refind-0.11.4/0000775000175000017500000000000013372357235013324 5ustar rodsmithrodsmithrefind-0.11.4/gptsync/0000775000175000017500000000000013372355001015000 5ustar rodsmithrodsmithrefind-0.11.4/gptsync/os_efi.c0000664000175000017500000002120213111633624016406 0ustar rodsmithrodsmith/* * gptsync/os_efi.c * EFI glue for gptsync * * Copyright (c) 2006 Christoph Pfisterer * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * * Neither the name of Christoph Pfisterer nor the names of the * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "gptsync.h" #include "../include/refit_call_wrapper.h" #ifdef __MAKEWITH_TIANO //#include "tiano_includes.h" #include "AutoGen.h" #endif // variables EFI_BLOCK_IO *BlockIO = NULL; // // sector I/O functions // // Returns size of disk in blocks UINT64 disk_size(VOID) { return (UINT64) (BlockIO->Media->LastBlock + 1); } // UINT64 disk_size() UINTN read_sector(UINT64 lba, UINT8 *buffer) { EFI_STATUS Status; Status = refit_call5_wrapper(BlockIO->ReadBlocks, BlockIO, BlockIO->Media->MediaId, lba, 512, buffer); if (EFI_ERROR(Status)) { // TODO: report error return 1; } return 0; } UINTN write_sector(UINT64 lba, UINT8 *buffer) { EFI_STATUS Status; Status = refit_call5_wrapper(BlockIO->WriteBlocks, BlockIO, BlockIO->Media->MediaId, lba, 512, buffer); if (EFI_ERROR(Status)) { // TODO: report error return 1; } return 0; } // // Keyboard input // static BOOLEAN ReadAllKeyStrokes(VOID) { EFI_STATUS Status; BOOLEAN GotKeyStrokes; EFI_INPUT_KEY Key; GotKeyStrokes = FALSE; for (;;) { Status = refit_call2_wrapper(ST->ConIn->ReadKeyStroke, ST->ConIn, &Key); if (Status == EFI_SUCCESS) { GotKeyStrokes = TRUE; continue; } break; } return GotKeyStrokes; } static VOID PauseForKey(VOID) { UINTN Index; Print(L"\n* Hit any key to continue *"); if (ReadAllKeyStrokes()) { // remove buffered key strokes refit_call1_wrapper(BS->Stall, 5000000); // 5 seconds delay ReadAllKeyStrokes(); // empty the buffer again } refit_call3_wrapper(BS->WaitForEvent, 1, &ST->ConIn->WaitForKey, &Index); ReadAllKeyStrokes(); // empty the buffer to protect the menu Print(L"\n"); } UINTN input_boolean(CHARN *prompt, BOOLEAN *bool_out) { EFI_STATUS Status; UINTN Index; EFI_INPUT_KEY Key; Print(prompt); ReadAllKeyStrokes(); // Remove buffered key strokes do { refit_call3_wrapper(BS->WaitForEvent, 1, &ST->ConIn->WaitForKey, &Index); Status = refit_call2_wrapper(ST->ConIn->ReadKeyStroke, ST->ConIn, &Key); if (EFI_ERROR(Status) && Status != EFI_NOT_READY) return 1; } while (Status == EFI_NOT_READY); if (Key.UnicodeChar == 'y' || Key.UnicodeChar == 'Y') { Print(L"Yes\n"); *bool_out = TRUE; } else { Print(L"No\n"); *bool_out = FALSE; } ReadAllKeyStrokes(); return 0; } #ifdef __MAKEWITH_TIANO // EFI_GUID gEfiDxeServicesTableGuid = { 0x05AD34BA, 0x6F02, 0x4214, { 0x95, 0x2E, 0x4D, 0xA0, 0x39, 0x8E, 0x2B, 0xB9 }}; // Minimal initialization function static VOID InitializeLib(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable) { gST = SystemTable; // gImageHandle = ImageHandle; gBS = SystemTable->BootServices; // gRS = SystemTable->RuntimeServices; gRT = SystemTable->RuntimeServices; // Some BDS functions need gRT to be set // InitializeConsoleSim(); } // EFI_GUID gEfiBlockIoProtocolGuid = { 0x964E5B21, 0x6459, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; #define LibLocateHandle gBS->LocateHandleBuffer #define BlockIoProtocol gEfiBlockIoProtocolGuid #endif // Performs a case-insensitive string comparison. This function is necesary // because some EFIs have buggy StriCmp() functions that actually perform // case-sensitive comparisons. // Returns TRUE if strings are identical, FALSE otherwise. static BOOLEAN MyStriCmp(IN CHAR16 *FirstString, IN CHAR16 *SecondString) { if (FirstString && SecondString) { while ((*FirstString != L'\0') && ((*FirstString & ~0x20) == (*SecondString & ~0x20))) { FirstString++; SecondString++; } return (*FirstString == *SecondString); } else { return FALSE; } } // BOOLEAN MyStriCmp() // Check firmware vendor; get verification to continue if it's not Apple. // Returns TRUE if Apple firmware or if user assents to use, FALSE otherwise. static BOOLEAN VerifyGoOn(VOID) { BOOLEAN GoOn = TRUE; UINTN invalid; if (!MyStriCmp(L"Apple", ST->FirmwareVendor)) { Print(L"Your firmware is made by %s.\n", ST->FirmwareVendor); Print(L"Ordinarily, a hybrid MBR (which this program creates) should be used ONLY on\n"); Print(L"Apple Macs that dual-boot with Windows or some other BIOS-mode OS. Are you\n"); invalid = input_boolean(STR("SURE you want to continue? [y/N] "), &GoOn); if (invalid) GoOn = FALSE; } return GoOn; } // BOOLEAN VerifyGoOn() // // main entry point // EFI_STATUS EFIAPI efi_main (IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable) { EFI_STATUS Status; UINTN SyncStatus; UINTN Index; UINTN HandleCount; EFI_HANDLE *HandleBuffer; EFI_HANDLE DeviceHandle; EFI_DEVICE_PATH *DevicePath, *NextDevicePath; BOOLEAN Usable; InitializeLib(ImageHandle, SystemTable); Status = refit_call5_wrapper(BS->LocateHandleBuffer, ByProtocol, &BlockIoProtocol, NULL, &HandleCount, &HandleBuffer); if (EFI_ERROR (Status)) { Status = EFI_NOT_FOUND; return Status; } if (!VerifyGoOn()) return EFI_ABORTED; for (Index = 0; Index < HandleCount; Index++) { DeviceHandle = HandleBuffer[Index]; // check device path DevicePath = DevicePathFromHandle(DeviceHandle); Usable = TRUE; while (DevicePath != NULL && !IsDevicePathEndType(DevicePath)) { NextDevicePath = NextDevicePathNode(DevicePath); if (DevicePathType(DevicePath) == MESSAGING_DEVICE_PATH && (DevicePathSubType(DevicePath) == MSG_USB_DP || DevicePathSubType(DevicePath) == MSG_USB_CLASS_DP || DevicePathSubType(DevicePath) == MSG_1394_DP || DevicePathSubType(DevicePath) == MSG_FIBRECHANNEL_DP)) Usable = FALSE; // USB/FireWire/FC device if (DevicePathType(DevicePath) == MEDIA_DEVICE_PATH) Usable = FALSE; // partition, El Torito entry, legacy BIOS device DevicePath = NextDevicePath; } if (!Usable) continue; Status = refit_call3_wrapper(BS->HandleProtocol, DeviceHandle, &BlockIoProtocol, (VOID **) &BlockIO); if (EFI_ERROR(Status)) { // TODO: report error BlockIO = NULL; } else { if (BlockIO->Media->BlockSize != 512) BlockIO = NULL; // optical media else break; } } FreePool (HandleBuffer); if (BlockIO == NULL) { Print(L"Internal hard disk device not found!\n"); return EFI_NOT_FOUND; } SyncStatus = gptsync(); if (SyncStatus == 0) PauseForKey(); if (SyncStatus) return EFI_NOT_FOUND; return EFI_SUCCESS; } refind-0.11.4/gptsync/os_unix.c0000664000175000017500000001425012626644770016651 0ustar rodsmithrodsmith/* * gptsync/os_unix.c * Unix OS glue for gptsync * * Copyright (c) 2006 Christoph Pfisterer * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * * Neither the name of Christoph Pfisterer nor the names of the * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "gptsync.h" #include #define STRINGIFY(s) #s #define STRINGIFY2(s) STRINGIFY(s) #define PROGNAME_S STRINGIFY2(PROGNAME) // variables static int fd; // // error functions // void error(const char *msg, ...) { va_list par; char buf[4096]; va_start(par, msg); vsnprintf(buf, 4096, msg, par); va_end(par); fprintf(stderr, PROGNAME_S ": %s\n", buf); } void errore(const char *msg, ...) { va_list par; char buf[4096]; va_start(par, msg); vsnprintf(buf, 4096, msg, par); va_end(par); fprintf(stderr, PROGNAME_S ": %s: %s\n", buf, strerror(errno)); } // // sector I/O functions // // Returns size of disk in blocks (currently bogus) UINT64 disk_size(VOID) { return (UINT64) 0xFFFFFFFF; } // UINT64 disk_size() UINTN read_sector(UINT64 lba, UINT8 *buffer) { off_t offset; off_t result_seek; ssize_t result_read; offset = lba * 512; result_seek = lseek(fd, offset, SEEK_SET); if (result_seek != offset) { errore("Seek to %llu failed", offset); return 1; } result_read = read(fd, buffer, 512); if (result_read < 0) { errore("Data read failed at position %llu", offset); return 1; } if (result_read != 512) { errore("Data read fell short at position %llu", offset); return 1; } return 0; } UINTN write_sector(UINT64 lba, UINT8 *buffer) { off_t offset; off_t result_seek; ssize_t result_write; offset = lba * 512; result_seek = lseek(fd, offset, SEEK_SET); if (result_seek != offset) { errore("Seek to %llu failed", offset); return 1; } result_write = write(fd, buffer, 512); if (result_write < 0) { errore("Data write failed at position %llu", offset); return 1; } if (result_write != 512) { errore("Data write fell short at position %llu", offset); return 1; } return 0; } // // keyboard input // UINTN input_boolean(CHARN *prompt, BOOLEAN *bool_out) { int c; printf("%s", prompt); fflush(NULL); c = getchar(); if (c == EOF) return 1; if (c == 'y' || c == 'Y') { printf("Yes\n"); *bool_out = TRUE; } else { printf("No\n"); *bool_out = FALSE; } return 0; } // // EFI-style print function // void Print(wchar_t *format, ...) { va_list par; char formatbuf[256]; char buf[4096]; int i; for (i = 0; format[i]; i++) formatbuf[i] = (format[i] > 255) ? '?' : (char)(format[i] & 0xff); formatbuf[i] = 0; va_start(par, format); vsnprintf(buf, 4096, formatbuf, par); va_end(par); printf("%s", buf); } // // main entry point // int main(int argc, char *argv[]) { char *filename; struct stat sb; int filekind; UINT64 filesize; char *reason; int status; // argument check if (argc != 2) { fprintf(stderr, "Usage: " PROGNAME_S " \n"); return 1; } filename = argv[1]; // set input to unbuffered fflush(NULL); setvbuf(stdin, NULL, _IONBF, 0); // stat check if (stat(filename, &sb) < 0) { errore("Can't stat %.300s", filename); return 1; } filekind = 0; filesize = 0; reason = NULL; if (S_ISREG(sb.st_mode)) filesize = sb.st_size; else if (S_ISBLK(sb.st_mode)) filekind = 1; else if (S_ISCHR(sb.st_mode)) filekind = 2; else if (S_ISDIR(sb.st_mode)) reason = "Is a directory"; else if (S_ISFIFO(sb.st_mode)) reason = "Is a FIFO"; #ifdef S_ISSOCK else if (S_ISSOCK(sb.st_mode)) reason = "Is a socket"; #endif else reason = "Is an unknown kind of special file"; if (reason != NULL) { error("%.300s: %s", filename, reason); return 1; } // open file fd = open(filename, O_RDWR); if (fd < 0 && errno == EBUSY) { fd = open(filename, O_RDONLY); #ifndef NOREADONLYWARN if (fd >= 0) printf("Warning: %.300s opened read-only\n", filename); #endif } if (fd < 0) { errore("Can't open %.300s", filename); return 1; } // (try to) guard against TTY character devices if (filekind == 2) { if (isatty(fd)) { error("%.300s: Is a TTY device", filename); return 1; } } // run sync algorithm status = PROGNAME(); printf("\n"); // close file if (close(fd) != 0) { errore("Error while closing %.300s", filename); return 1; } return status; } refind-0.11.4/gptsync/AutoGen.h0000664000175000017500000000215712626644770016537 0ustar rodsmithrodsmith/** DO NOT EDIT FILE auto-generated Module name: AutoGen.h Abstract: Auto-generated AutoGen.h for building module or library. **/ #ifndef _AUTOGENH_B8448DD1_B146_41B7_9D66_98B3A0A404D3 #define _AUTOGENH_B8448DD1_B146_41B7_9D66_98B3A0A404D3 #ifdef __cplusplus extern "C" { #endif #include #include #include extern GUID gEfiCallerIdGuid; #define EFI_CALLER_ID_GUID \ {0xB8448DD1, 0xB146, 0x41B7, {0x9D, 0x66, 0x98, 0xB3, 0xA0, 0xA4, 0x04, 0xD3}} // Definition of PCDs used in this module #define _PCD_TOKEN_PcdUgaConsumeSupport 16U #define _PCD_VALUE_PcdUgaConsumeSupport ((BOOLEAN)1U) extern const BOOLEAN _gPcd_FixedAtBuild_PcdUgaConsumeSupport; #define _PCD_GET_MODE_BOOL_PcdUgaConsumeSupport _gPcd_FixedAtBuild_PcdUgaConsumeSupport //#define _PCD_SET_MODE_BOOL_PcdUgaConsumeSupport ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD // Definition of PCDs used in libraries is in AutoGen.c EFI_STATUS EFIAPI efi_main ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ); #ifdef __cplusplus } #endif #endif refind-0.11.4/gptsync/Makefile0000664000175000017500000000112112631123302016425 0ustar rodsmithrodsmith# meta-Makefile for gptsync program; controls use of EFI build using # GNU-EFI vs. TianoCore EDK2 or build for Unix/Linux. # # Most of the functionality is in Make.tiano, Make.gnuefi, and # Make.unix; this Makefile just dispatches based on options # passed to it.... TEXTFILES = gptsync.txt TARGET = tiano all: $(TARGET) gnuefi: +make -f Make.gnuefi tiano: +make -f Make.tiano # TODO: Fix Make.unix; currently broken.... unix: +make -f Make.unix # utility rules clean: rm -f *~ *.bak *.o *.obj *.so *.efi *.dll err.txt gptsync_*.txt gptsync showpart $(TEXTFILES) # DO NOT DELETE refind-0.11.4/gptsync/gptsync.h0000664000175000017500000001260712630713102016642 0ustar rodsmithrodsmith/* * gptsync/gptsync.h * Common header for gptsync and showpart * * Copyright (c) 2006 Christoph Pfisterer * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * * Neither the name of Christoph Pfisterer nor the names of the * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* Changes copyright (c) 2013 Roderick W. Smith */ //#define VERSION L"0.9.1" // // config // #if defined(EFI32) || defined(EFIX64) || defined(EFIAARCH64) #define CONFIG_EFI #endif // // platform-dependent types // #ifdef CONFIG_EFI #ifdef __MAKEWITH_GNUEFI #include "efi.h" #include "efilib.h" #else #include "../include/tiano_includes.h" #endif #define copy_guid(destguid, srcguid) (CopyMem(destguid, srcguid, 16)) #define guids_are_equal(guid1, guid2) (CompareMem(guid1, guid2, 16) == 0) typedef CHAR16 CHARN; #define STR(x) L##x #endif #ifndef CONFIG_EFI #include #include #include #include #include #include #include #include #include /* typedef int INTN; typedef unsigned int UINTN; typedef unsigned char UINT8; typedef unsigned short UINT16; typedef unsigned long UINT32; typedef unsigned long long UINT64; typedef void VOID; */ typedef int BOOLEAN; #ifndef FALSE #define FALSE (0) #endif #ifndef TRUE #define TRUE (1) #endif typedef unsigned short CHAR16; typedef char CHARN; #define STR(x) x void Print(wchar_t *format, ...); // FUTURE: use STR(), #define Print printf #define copy_guid(destguid, srcguid) (CopyMem(destguid, srcguid, 16)) #define guids_are_equal(guid1, guid2) (memcmp(guid1, guid2, 16) == 0) #define EFI_UNSUPPORTED 1 #define EFI_ABORTED 2 #endif #define GPT_KIND_SYSTEM (0) #define GPT_KIND_DATA (1) #define GPT_KIND_BASIC_DATA (2) #define GPT_KIND_FATAL (3) #define MAX_MBR_LBA 0xFFFFFFFF // // platform-independent types // typedef struct { UINT8 flags; UINT8 start_chs[3]; UINT8 type; UINT8 end_chs[3]; UINT32 start_lba; UINT32 size; } MBR_PART_INFO; typedef struct { UINT8 type; CHARN *name; } MBR_PARTTYPE; typedef struct { UINT64 signature; UINT32 spec_revision; UINT32 header_size; UINT32 header_crc32; UINT32 reserved; UINT64 header_lba; UINT64 alternate_header_lba; UINT64 first_usable_lba; UINT64 last_usable_lba; UINT8 disk_guid[16]; UINT64 entry_lba; UINT32 entry_count; UINT32 entry_size; UINT32 entry_crc32; } GPT_HEADER; typedef struct { UINT8 type_guid[16]; UINT8 partition_guid[16]; UINT64 start_lba; UINT64 end_lba; UINT64 attributes; CHAR16 name[36]; } GPT_ENTRY; typedef struct { UINT8 guid[16]; UINT8 mbr_type; CHARN *name; UINTN kind; } GPT_PARTTYPE; typedef struct { UINTN index; UINT64 start_lba; UINT64 end_lba; UINTN mbr_type; UINT8 gpt_type[16]; GPT_PARTTYPE *gpt_parttype; BOOLEAN active; } PARTITION_INFO; // // functions provided by the OS-specific module // UINT64 disk_size(VOID); UINTN read_sector(UINT64 lba, UINT8 *buffer); UINTN write_sector(UINT64 lba, UINT8 *buffer); UINTN input_boolean(CHARN *prompt, BOOLEAN *bool_out); // // vars and functions provided by the common lib module // extern UINT8 empty_guid[16]; extern PARTITION_INFO mbr_parts[4]; extern UINTN mbr_part_count; extern PARTITION_INFO gpt_parts[128]; extern UINTN gpt_part_count; extern PARTITION_INFO new_mbr_parts[4]; extern UINTN new_mbr_part_count; extern UINT8 sector[512]; extern MBR_PARTTYPE mbr_types[]; extern GPT_PARTTYPE gpt_types[]; extern GPT_PARTTYPE gpt_dummy_type; CHARN * mbr_parttype_name(UINT8 type); UINTN read_mbr(VOID); GPT_PARTTYPE * gpt_parttype(UINT8 *type_guid); UINTN read_gpt(VOID); UINTN detect_mbrtype_fs(UINT64 partlba, UINTN *parttype, CHARN **fsname); // // actual platform-independent programs // UINTN gptsync(VOID); UINTN showpart(VOID); /* EOF */ refind-0.11.4/gptsync/AutoGen.c0000664000175000017500000004473412626644770016541 0ustar rodsmithrodsmith/** DO NOT EDIT FILE auto-generated Module name: AutoGen.c Abstract: Auto-generated AutoGen.c for building module or library. **/ #include #include #include #include #include #include "AutoGen.h" GLOBAL_REMOVE_IF_UNREFERENCED GUID gEfiCallerIdGuid = {0xB8448DD1, 0xB146, 0x41B7, {0x9D, 0x66, 0x98, 0xB3, 0xA0, 0xA4, 0x04, 0xD3}}; // Guids GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiAcpiTableGuid = { 0x8868E871, 0xE4F1, 0x11D3, { 0xBC, 0x22, 0x00, 0x80, 0xC7, 0x3C, 0x88, 0x81 }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiAcpi10TableGuid = { 0xEB9D2D30, 0x2D88, 0x11D3, { 0x9A, 0x16, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiAcpi20TableGuid = { 0x8868E871, 0xE4F1, 0x11D3, { 0xBC, 0x22, 0x00, 0x80, 0xC7, 0x3C, 0x88, 0x81 }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDxeServicesTableGuid = { 0x05AD34BA, 0x6F02, 0x4214, { 0x95, 0x2E, 0x4D, 0xA0, 0x39, 0x8E, 0x2B, 0xB9 }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiEventReadyToBootGuid = { 0x7CE88FB3, 0x4BD7, 0x4679, { 0x87, 0xA8, 0xA8, 0xD8, 0xDE, 0xE5, 0x0D, 0x2B }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiEventVirtualAddressChangeGuid = { 0x13FA7698, 0xC831, 0x49C7, { 0x87, 0xEA, 0x8F, 0x43, 0xFC, 0xC2, 0x51, 0x96 }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiEventExitBootServicesGuid = { 0x27ABF055, 0xB1B8, 0x4C26, { 0x80, 0x48, 0x74, 0x8F, 0x37, 0xBA, 0xA2, 0xDF }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiFileInfoGuid = { 0x09576E92, 0x6D3F, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiFileSystemInfoGuid = { 0x09576E93, 0x6D3F, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiFileSystemVolumeLabelInfoIdGuid = { 0xDB47D7D3, 0xFE81, 0x11D3, { 0x9A, 0x35, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiGlobalVariableGuid = { 0x8BE4DF61, 0x93CA, 0x11D2, { 0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiPartTypeLegacyMbrGuid = { 0x024DEE41, 0x33E7, 0x11D3, { 0x9D, 0x69, 0x00, 0x08, 0xC7, 0x81, 0xF3, 0x9F }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiPartTypeSystemPartGuid = { 0xC12A7328, 0xF81F, 0x11D2, { 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSmbiosTableGuid = { 0xEB9D2D31, 0x2D88, 0x11D3, { 0x9A, 0x16, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSasDevicePathGuid = { 0xd487ddb4, 0x008b, 0x11d9, { 0xaf, 0xdc, 0x00, 0x10, 0x83, 0xff, 0xca, 0x4d }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiMdePkgTokenSpaceGuid = { 0x914AEBE7, 0x4635, 0x459b, { 0xAA, 0x1C, 0x11, 0xE2, 0x19, 0xB0, 0x3A, 0x10 }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiEventLegacyBootGuid = { 0x2A571201, 0x4966, 0x47F6, { 0x8B, 0x86, 0xF3, 0x1E, 0x41, 0xF3, 0x2F, 0x10 }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiHobListGuid = { 0x7739F24C, 0x93D7, 0x11D4, { 0x9A, 0x3A, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; // Protocols GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiComponentName2ProtocolGuid = { 0x6A7A5CFF, 0xE8D9, 0x4F70, { 0xBA, 0xDA, 0x75, 0xAB, 0x30, 0x25, 0xCE, 0x14 }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDevicePathToTextProtocolGuid = { 0x8B843E20, 0x8132, 0x4852, { 0x90, 0xCC, 0x55, 0x1A, 0x4E, 0x4A, 0x7F, 0x1C }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSimpleFileSystemProtocolGuid = { 0x964E5B22, 0x6459, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSimpleTextInProtocolGuid = { 0x387477C1, 0x69C7, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSimpleTextInputExProtocolGuid = {0xdd9e7534, 0x7762, 0x4698, { 0x8c, 0x14, 0xf5, 0x85, 0x17, 0xa6, 0x25, 0xaa } }; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSimpleTextOutProtocolGuid = { 0x387477C2, 0x69C7, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiUnicodeCollationProtocolGuid = { 0x1D85CD7F, 0xF43D, 0x11D2, { 0x9A, 0x0C, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiUnicodeCollation2ProtocolGuid = {0xa4c751fc, 0x23ae, 0x4c3e, { 0x92, 0xe9, 0x49, 0x64, 0xcf, 0x63, 0xf3, 0x49 }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiAcpiS3SaveProtocolGuid = { 0x125F2DE1, 0xFB85, 0x440C, { 0xA5, 0x4C, 0x4D, 0x99, 0x35, 0x8A, 0x8D, 0x38 }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiBlockIoProtocolGuid = { 0x964E5B21, 0x6459, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiCpuArchProtocolGuid = { 0x26BACCB1, 0x6F42, 0x11D4, { 0xBC, 0xE7, 0x00, 0x80, 0xC7, 0x3C, 0x88, 0x81 }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDebugPortProtocolGuid = { 0xEBA4E8D2, 0x3858, 0x41EC, { 0xA2, 0x81, 0x26, 0x47, 0xBA, 0x96, 0x60, 0xD0 }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDevicePathProtocolGuid = { 0x09576E91, 0x6D3F, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDiskIoProtocolGuid = { 0xCE345171, 0xBA0B, 0x11D2, { 0x8E, 0x4F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiExtScsiPassThruProtocolGuid = { 0x143b7632, 0xb81b, 0x4cb7, {0xab, 0xd3, 0xb6, 0x25, 0xa5, 0xb9, 0xbf, 0xfe }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiFirmwareVolume2ProtocolGuid = { 0x220e73b6, 0x6bdb, 0x4413, { 0x84, 0x5, 0xb9, 0x74, 0xb1, 0x8, 0x61, 0x9a } }; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiGraphicsOutputProtocolGuid = { 0x9042A9DE, 0x23DC, 0x4A38, { 0x96, 0xFB, 0x7A, 0xDE, 0xD0, 0x80, 0x51, 0x6A }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiHiiFontProtocolGuid = {0xe9ca4775, 0x8657, 0x47fc, {0x97, 0xe7, 0x7e, 0xd6, 0x5a, 0x08, 0x43, 0x24}}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiLegacy8259ProtocolGuid = { 0x38321dba, 0x4fe0, 0x4e17, { 0x8a, 0xec, 0x41, 0x30, 0x55, 0xea, 0xed, 0xc1 }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiLoadedImageProtocolGuid = { 0x5B1B31A1, 0x9562, 0x11D2, { 0x8E, 0x3F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiOEMBadgingProtocolGuid = { 0x170E13C0, 0xBF1B, 0x4218, { 0x87, 0x1D, 0x2A, 0xBD, 0xC6, 0xF8, 0x87, 0xBC }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiPciIoProtocolGuid = { 0x4CF5B200, 0x68B8, 0x4CA5, { 0x9E, 0xEC, 0xB2, 0x3E, 0x3F, 0x50, 0x02, 0x9A }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiScsiIoProtocolGuid = { 0x932F47e6, 0x2362, 0x4002, { 0x80, 0x3E, 0x3C, 0xD5, 0x4B, 0x13, 0x8F, 0x85 }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiScsiPassThruProtocolGuid = { 0xA59E8FCF, 0xBDA0, 0x43BB, { 0x90, 0xB1, 0xD3, 0x73, 0x2E, 0xCA, 0xA8, 0x77 }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSimpleNetworkProtocolGuid = { 0xA19832B9, 0xAC25, 0x11D3, { 0x9A, 0x2D, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; //GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiUgaDrawProtocolGuid = { 0x982C298B, 0xF4FA, 0x41CB, { 0xB8, 0x38, 0x77, 0xAA, 0x68, 0x8F, 0xB8, 0x39 }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiAbsolutePointerProtocolGuid = { 0x8D59D32B, 0xC655, 0x4AE9, { 0x9B, 0x15, 0xF2, 0x59, 0x04, 0x99, 0x2A, 0x43 } }; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiAcpiTableProtocolGuid = { 0xFFE06BDD, 0x6107, 0x46A6, { 0x7B, 0xB2, 0x5A, 0x9C, 0x7E, 0xC5, 0x27, 0x5C }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiEdidActiveProtocolGuid = { 0xBD8C1056, 0x9F36, 0x44EC, { 0x92, 0xA8, 0xA6, 0x33, 0x7F, 0x81, 0x79, 0x86 }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiEdidDiscoveredProtocolGuid = { 0x1C0C34F6, 0xD380, 0x41FA, { 0xA0, 0x49, 0x8A, 0xD0, 0x6C, 0x1A, 0x66, 0xAA }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiHiiDatabaseProtocolGuid = {0xef9fc172, 0xa1b2, 0x4693, {0xb3, 0x27, 0x6d, 0x32, 0xfc, 0x41, 0x60, 0x42}}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiHiiImageProtocolGuid = {0x31a6406a, 0x6bdf, 0x4e46, {0xb2, 0xa2, 0xeb, 0xaa, 0x89, 0xc4, 0x09, 0x20}}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiHiiProtocolGuid = { 0xd7ad636e, 0xb997, 0x459b, { 0xbf, 0x3f, 0x88, 0x46, 0x89, 0x79, 0x80, 0xe1 }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSimplePointerProtocolGuid = { 0x31878C87, 0x0B75, 0x11D5, { 0x9A, 0x4F, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSmbiosProtocolGuid = {0x3583ff6, 0xcb36, 0x4940, { 0x94, 0x7e, 0xb9, 0xb3, 0x9f, 0x4a, 0xfa, 0xf7}}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSecurityArchProtocolGuid = { 0xA46423E3, 0x4617, 0x49F1, { 0xB9, 0xFF, 0xD1, 0xBF, 0xA9, 0x11, 0x58, 0x39 }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiLegacyBiosProtocolGuid = { 0xdb9a1e3d, 0x45cb, 0x4abb, { 0x85, 0x3b, 0xe5, 0x38, 0x7f, 0xdb, 0x2e, 0x2d }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiLoadFile2ProtocolGuid = { 0x4006c0c1, 0xfcb3, 0x403e, {0x99, 0x6d, 0x4a, 0x6c, 0x87, 0x24, 0xe0, 0x6d }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiLoadFileProtocolGuid = { 0x56EC3091, 0x954C, 0x11D2, { 0x8E, 0x3F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiHiiPackageListProtocolGuid = { 0x6a1ee763, 0xd47a, 0x43b4, {0xaa, 0xbe, 0xef, 0x1d, 0xe2, 0xab, 0x56, 0xfc}}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverBindingProtocolGuid = { 0x18A031AB, 0xB443, 0x4D1A, { 0xA5, 0xC0, 0x0C, 0x09, 0x26, 0x1E, 0x9F, 0x71 }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiComponentNameProtocolGuid = { 0x107A772C, 0xD5E1, 0x11D4, { 0x9A, 0x46, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverConfigurationProtocolGuid = { 0x107A772B, 0xD5E1, 0x11D4, { 0x9A, 0x46, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverConfiguration2ProtocolGuid = { 0xBFD7DC1D, 0x24F1, 0x40D9, { 0x82, 0xE7, 0x2E, 0x09, 0xBB, 0x6B, 0x4E, 0xBE }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverDiagnosticsProtocolGuid = { 0x0784924F, 0xE296, 0x11D4, { 0x9A, 0x49, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverDiagnostics2ProtocolGuid = { 0x4D330321, 0x025F, 0x4AAC, { 0x90, 0xD8, 0x5E, 0xD9, 0x00, 0x17, 0x3B, 0x63 }}; // Definition of PCDs used in this module //GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdUgaConsumeSupport = _PCD_VALUE_PcdUgaConsumeSupport; // Definition of PCDs used in libraries #define _PCD_TOKEN_PcdMaximumLinkedListLength 2U #define _PCD_VALUE_PcdMaximumLinkedListLength 1000000U GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdMaximumLinkedListLength = _PCD_VALUE_PcdMaximumLinkedListLength; extern const UINT32 _gPcd_FixedAtBuild_PcdMaximumLinkedListLength; #define _PCD_GET_MODE_32_PcdMaximumLinkedListLength _gPcd_FixedAtBuild_PcdMaximumLinkedListLength #define _PCD_SET_MODE_32_PcdMaximumLinkedListLength ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD #define _PCD_TOKEN_PcdMaximumAsciiStringLength 3U #define _PCD_VALUE_PcdMaximumAsciiStringLength 1000000U GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdMaximumAsciiStringLength = _PCD_VALUE_PcdMaximumAsciiStringLength; extern const UINT32 _gPcd_FixedAtBuild_PcdMaximumAsciiStringLength; #define _PCD_GET_MODE_32_PcdMaximumAsciiStringLength _gPcd_FixedAtBuild_PcdMaximumAsciiStringLength #define _PCD_SET_MODE_32_PcdMaximumAsciiStringLength ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD #define _PCD_TOKEN_PcdMaximumUnicodeStringLength 4U #define _PCD_VALUE_PcdMaximumUnicodeStringLength 1000000U GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdMaximumUnicodeStringLength = _PCD_VALUE_PcdMaximumUnicodeStringLength; extern const UINT32 _gPcd_FixedAtBuild_PcdMaximumUnicodeStringLength; #define _PCD_GET_MODE_32_PcdMaximumUnicodeStringLength _gPcd_FixedAtBuild_PcdMaximumUnicodeStringLength #define _PCD_SET_MODE_32_PcdMaximumUnicodeStringLength ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD #define _PCD_TOKEN_PcdVerifyNodeInList 5U #define _PCD_VALUE_PcdVerifyNodeInList ((BOOLEAN)0U) GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdVerifyNodeInList = _PCD_VALUE_PcdVerifyNodeInList; extern const BOOLEAN _gPcd_FixedAtBuild_PcdVerifyNodeInList; #define _PCD_GET_MODE_BOOL_PcdVerifyNodeInList _gPcd_FixedAtBuild_PcdVerifyNodeInList #define _PCD_SET_MODE_BOOL_PcdVerifyNodeInList ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD #define _PCD_TOKEN_PcdDriverDiagnosticsDisable 6U #define _PCD_VALUE_PcdDriverDiagnosticsDisable ((BOOLEAN)0U) GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdDriverDiagnosticsDisable = _PCD_VALUE_PcdDriverDiagnosticsDisable; extern const BOOLEAN _gPcd_FixedAtBuild_PcdDriverDiagnosticsDisable; #define _PCD_GET_MODE_BOOL_PcdDriverDiagnosticsDisable _gPcd_FixedAtBuild_PcdDriverDiagnosticsDisable #define _PCD_SET_MODE_BOOL_PcdDriverDiagnosticsDisable ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD #define _PCD_TOKEN_PcdComponentNameDisable 7U #define _PCD_VALUE_PcdComponentNameDisable ((BOOLEAN)0U) GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdComponentNameDisable = _PCD_VALUE_PcdComponentNameDisable; extern const BOOLEAN _gPcd_FixedAtBuild_PcdComponentNameDisable; #define _PCD_GET_MODE_BOOL_PcdComponentNameDisable _gPcd_FixedAtBuild_PcdComponentNameDisable #define _PCD_SET_MODE_BOOL_PcdComponentNameDisable ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD #define _PCD_TOKEN_PcdDriverDiagnostics2Disable 8U #define _PCD_VALUE_PcdDriverDiagnostics2Disable ((BOOLEAN)0U) GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdDriverDiagnostics2Disable = _PCD_VALUE_PcdDriverDiagnostics2Disable; extern const BOOLEAN _gPcd_FixedAtBuild_PcdDriverDiagnostics2Disable; #define _PCD_GET_MODE_BOOL_PcdDriverDiagnostics2Disable _gPcd_FixedAtBuild_PcdDriverDiagnostics2Disable #define _PCD_SET_MODE_BOOL_PcdDriverDiagnostics2Disable ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD #define _PCD_TOKEN_PcdComponentName2Disable 9U #define _PCD_VALUE_PcdComponentName2Disable ((BOOLEAN)0U) GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdComponentName2Disable = _PCD_VALUE_PcdComponentName2Disable; extern const BOOLEAN _gPcd_FixedAtBuild_PcdComponentName2Disable; #define _PCD_GET_MODE_BOOL_PcdComponentName2Disable _gPcd_FixedAtBuild_PcdComponentName2Disable #define _PCD_SET_MODE_BOOL_PcdComponentName2Disable ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD #define _PCD_TOKEN_PcdUefiLibMaxPrintBufferSize 10U #define _PCD_VALUE_PcdUefiLibMaxPrintBufferSize 320U GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdUefiLibMaxPrintBufferSize = _PCD_VALUE_PcdUefiLibMaxPrintBufferSize; extern const UINT32 _gPcd_FixedAtBuild_PcdUefiLibMaxPrintBufferSize; #define _PCD_GET_MODE_32_PcdUefiLibMaxPrintBufferSize _gPcd_FixedAtBuild_PcdUefiLibMaxPrintBufferSize #define _PCD_SET_MODE_32_PcdUefiLibMaxPrintBufferSize ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD EFI_STATUS EFIAPI UefiBootServicesTableLibConstructor ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ); EFI_STATUS EFIAPI UefiRuntimeServicesTableLibConstructor ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ); EFI_STATUS EFIAPI UefiLibConstructor ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ); EFI_STATUS EFIAPI DxeServicesTableLibConstructor ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ); EFI_STATUS EFIAPI HobLibConstructor ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ); // VOID // EFIAPI // ProcessLibraryConstructorList ( // IN EFI_HANDLE ImageHandle, // IN EFI_SYSTEM_TABLE *SystemTable // ) // { // EFI_STATUS Status; // // Status = UefiBootServicesTableLibConstructor (ImageHandle, SystemTable); // ASSERT_EFI_ERROR (Status); // // Status = UefiRuntimeServicesTableLibConstructor (ImageHandle, SystemTable); // ASSERT_EFI_ERROR (Status); // // Status = UefiLibConstructor (ImageHandle, SystemTable); // ASSERT_EFI_ERROR (Status); // // Status = DxeServicesTableLibConstructor (ImageHandle, SystemTable); // ASSERT_EFI_ERROR (Status); // // Status = HobLibConstructor (ImageHandle, SystemTable); // ASSERT_EFI_ERROR (Status); // // } // VOID // EFIAPI // ProcessLibraryDestructorList ( // IN EFI_HANDLE ImageHandle, // IN EFI_SYSTEM_TABLE *SystemTable // ) // { // // } const UINT32 _gUefiDriverRevision = 0x00010000U; // EFI_STATUS // EFIAPI // ProcessModuleEntryPointList ( // IN EFI_HANDLE ImageHandle, // IN EFI_SYSTEM_TABLE *SystemTable // ) // // { // return efi_main (ImageHandle, SystemTable); // } VOID EFIAPI ExitDriver ( IN EFI_STATUS Status ) { if (EFI_ERROR (Status)) { ProcessLibraryDestructorList (gImageHandle, gST); } gBS->Exit (gImageHandle, Status, 0, NULL); } //GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gDriverUnloadImageCount = 0U; // EFI_STATUS // EFIAPI // ProcessModuleUnloadList ( // IN EFI_HANDLE ImageHandle // ) // { // return EFI_SUCCESS; // } // Stuff added in effort to get Secure Boot working.... #define _PCD_TOKEN_PcdDebugPropertyMask 11U #define _PCD_VALUE_PcdDebugPropertyMask 0x0fU GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdDebugPropertyMask = _PCD_VALUE_PcdDebugPropertyMask; extern const UINT8 _gPcd_FixedAtBuild_PcdDebugPropertyMask; #define _PCD_GET_MODE_8_PcdDebugPropertyMask _gPcd_FixedAtBuild_PcdDebugPropertyMask //#define _PCD_SET_MODE_8_PcdDebugPropertyMask ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD #define _PCD_TOKEN_PcdDebugClearMemoryValue 10U #define _PCD_VALUE_PcdDebugClearMemoryValue 0xAFU GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdDebugClearMemoryValue = _PCD_VALUE_PcdDebugClearMemoryValue; extern const UINT8 _gPcd_FixedAtBuild_PcdDebugClearMemoryValue; #define _PCD_GET_MODE_8_PcdDebugClearMemoryValue _gPcd_FixedAtBuild_PcdDebugClearMemoryValue //#define _PCD_SET_MODE_8_PcdDebugClearMemoryValue ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD #define _PCD_TOKEN_PcdDebugPrintErrorLevel 5U #define _PCD_VALUE_PcdDebugPrintErrorLevel 0x80000000U GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdDebugPrintErrorLevel = _PCD_VALUE_PcdDebugPrintErrorLevel; extern const UINT32 _gPcd_FixedAtBuild_PcdDebugPrintErrorLevel; #define _PCD_GET_MODE_32_PcdDebugPrintErrorLevel _gPcd_FixedAtBuild_PcdDebugPrintErrorLevel //#define _PCD_SET_MODE_32_PcdDebugPrintErrorLevel ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD refind-0.11.4/gptsync/showpart.c0000664000175000017500000001741212626644770017037 0ustar rodsmithrodsmith/* * gptsync/showpart.c * Platform-independent code for analyzing hard disk partitioning * * Copyright (c) 2006 Christoph Pfisterer * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * * Neither the name of Christoph Pfisterer nor the names of the * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "gptsync.h" // // memory string search // static INTN FindMem(VOID *Buffer, UINTN BufferLength, VOID *SearchString, UINTN SearchStringLength) { UINT8 *BufferPtr; UINTN Offset; BufferPtr = Buffer; BufferLength -= SearchStringLength; for (Offset = 0; Offset < BufferLength; Offset++, BufferPtr++) { if (CompareMem(BufferPtr, SearchString, SearchStringLength) == 0) return (INTN)Offset; } return -1; } // // detect boot code // static UINTN detect_bootcode(UINT64 partlba, CHARN **bootcodename) { UINTN status; BOOLEAN bootable; // read MBR data status = read_sector(partlba, sector); if (status != 0) return status; // check bootable signature if (*((UINT16 *)(sector + 510)) == 0xaa55 && sector[0] != 0) bootable = TRUE; else bootable = FALSE; *bootcodename = NULL; // detect specific boot codes if (CompareMem(sector + 2, "LILO", 4) == 0 || CompareMem(sector + 6, "LILO", 4) == 0) { *bootcodename = STR("LILO"); } else if (CompareMem(sector + 3, "SYSLINUX", 8) == 0) { *bootcodename = STR("SYSLINUX"); } else if (FindMem(sector, 512, "ISOLINUX", 8) >= 0) { *bootcodename = STR("ISOLINUX"); } else if (FindMem(sector, 512, "Geom\0Hard Disk\0Read\0 Error", 26) >= 0) { *bootcodename = STR("GRUB"); } else if ((*((UINT32 *)(sector + 502)) == 0 && *((UINT32 *)(sector + 506)) == 50000 && *((UINT16 *)(sector + 510)) == 0xaa55) || FindMem(sector, 512, "Starting the BTX loader", 23) >= 0) { *bootcodename = STR("FreeBSD"); } else if (FindMem(sector, 512, "!Loading", 8) >= 0 || FindMem(sector, 512, "/cdboot\0/CDBOOT\0", 16) >= 0) { *bootcodename = STR("OpenBSD"); } else if (FindMem(sector, 512, "Not a bootxx image", 18) >= 0) { *bootcodename = STR("NetBSD"); } else if (FindMem(sector, 512, "NTLDR", 5) >= 0) { *bootcodename = STR("Windows NTLDR"); } else if (FindMem(sector, 512, "BOOTMGR", 7) >= 0) { *bootcodename = STR("Windows BOOTMGR (Vista)"); } else if (FindMem(sector, 512, "CPUBOOT SYS", 11) >= 0 || FindMem(sector, 512, "KERNEL SYS", 11) >= 0) { *bootcodename = STR("FreeDOS"); } else if (FindMem(sector, 512, "OS2LDR", 6) >= 0 || FindMem(sector, 512, "OS2BOOT", 7) >= 0) { *bootcodename = STR("eComStation"); } else if (FindMem(sector, 512, "Be Boot Loader", 14) >= 0) { *bootcodename = STR("BeOS"); } else if (FindMem(sector, 512, "yT Boot Loader", 14) >= 0) { *bootcodename = STR("ZETA"); } else if (FindMem(sector, 512, "\x04" "beos\x06" "system\x05" "zbeos", 18) >= 0) { *bootcodename = STR("Haiku"); } if (FindMem(sector, 512, "Non-system disk", 15) >= 0) // dummy FAT boot sector *bootcodename = STR("None (Non-system disk message)"); // TODO: Add a note if a specific code was detected, but the sector is not bootable? if (*bootcodename == NULL) { if (bootable) *bootcodename = STR("Unknown, but bootable"); else *bootcodename = STR("None"); } return 0; } // // check one partition // static UINTN analyze_part(UINT64 partlba) { UINTN status; UINTN i; CHARN *bootcodename; UINTN parttype; CHARN *fsname; if (partlba == 0) Print(L"\nMBR contents:\n"); else Print(L"\nPartition at LBA %lld:\n", partlba); // detect boot code status = detect_bootcode(partlba, &bootcodename); if (status) return status; Print(L" Boot Code: %s\n", bootcodename); if (partlba == 0) return 0; // short-circuit MBR analysis // detect file system status = detect_mbrtype_fs(partlba, &parttype, &fsname); if (status) return status; Print(L" File System: %s\n", fsname); // cross-reference with partition table for (i = 0; i < gpt_part_count; i++) { if (gpt_parts[i].start_lba == partlba) { Print(L" Listed in GPT as partition %d, type %s\n", i+1, gpt_parts[i].gpt_parttype->name); } } for (i = 0; i < mbr_part_count; i++) { if (mbr_parts[i].start_lba == partlba) { Print(L" Listed in MBR as partition %d, type %02x %s%s\n", i+1, mbr_parts[i].mbr_type, mbr_parttype_name(mbr_parts[i].mbr_type), mbr_parts[i].active ? STR(", active") : STR("")); } } return 0; } // // check all partitions // static UINTN analyze_parts(VOID) { UINTN i, k; UINTN status; BOOLEAN is_dupe; // check MBR (bootcode only) status = analyze_part(0); if (status) return status; // check partitions listed in GPT for (i = 0; i < gpt_part_count; i++) { status = analyze_part(gpt_parts[i].start_lba); if (status) return status; } // check partitions listed in MBR, but not in GPT for (i = 0; i < mbr_part_count; i++) { if (mbr_parts[i].start_lba == 1 && mbr_parts[i].mbr_type == 0xee) continue; // skip EFI Protective entry is_dupe = FALSE; for (k = 0; k < gpt_part_count; k++) if (gpt_parts[k].start_lba == mbr_parts[i].start_lba) is_dupe = TRUE; if (!is_dupe) { status = analyze_part(mbr_parts[i].start_lba); if (status) return status; } } return 0; } // // display algorithm entry point // UINTN showpart(VOID) { UINTN status = 0; UINTN status_gpt, status_mbr; // get full information from disk status_gpt = read_gpt(); status_mbr = read_mbr(); if (status_gpt != 0 || status_mbr != 0) return (status_gpt || status_mbr); // analyze all partitions status = analyze_parts(); if (status != 0) return status; return status; } refind-0.11.4/gptsync/Make.gnuefi0000664000175000017500000000145712630656644017100 0ustar rodsmithrodsmith# # gptsync/Make.gnuefi # Build control file for the gptsync tool, built with GNU-EFI # #LOCAL_GNUEFI_CFLAGS = -I. -I../include LOCAL_LIBS = OBJS = gptsync.o lib.o os_efi.o #TARGET = gptsync.efi include ../Make.common ifeq ($(ARCH),ia32) TARGET = gptsync_ia32.efi endif ifeq ($(ARCH),x86_64) TARGET = gptsync_x64.efi endif ifeq ($(ARCH),aarch64) TARGET = gptsync_aa64.efi endif all: $(TARGET) SHLIB_TARGET = $(subst .efi,.so,$(TARGET)) $(SHLIB_TARGET): $(OBJS) $(LD) $(GNUEFI_LDFLAGS) $(SUBSYSTEM_LDFLAG) $(OBJS) -o $@ $(LOCAL_LIBS) $(GNUEFI_LIBS) $(TARGET): $(SHLIB_TARGET) $(OBJCOPY) -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel \ -j .rela -j .rel.* -j .rela.* -j .rel* -j .rela* \ -j .reloc $(FORMAT) $< $@ chmod a-x $(TARGET) # EOF refind-0.11.4/gptsync/gptsync.80000664000175000017500000000115512626644770016601 0ustar rodsmithrodsmith.TH "gptsync" 8 "2006 Jul 2" "Debian" "rEFIt" .SH NAME gptsync \- GPT partition table to MBR partition table synchronisation .SH "SYNOPSIS" .BI "gptsync " "device" .SH "DESCRIPTION" Reads the GPT partition table on the device and synchronise content of MBR partition table on the device. Useful for situations (as in mactel linux) where legacy operating systems require MBR partition table to function properly, while most other operating systems can work with GPT. .SH "Author" Written by Christoph Pfisterer. This manual page contributed for Debian by Junichi Uekawa , but may be used for others. refind-0.11.4/gptsync/Make.unix0000664000175000017500000000332412630417734016574 0ustar rodsmithrodsmith# # Makefile for gptsync on Unix platforms # RM = rm -f CC = gcc GPTSYNC_TARGET = gptsync GPTSYNC_OBJS = gptsync.unix.o lib.unix.o os_unix.gptsync.o SHOWPART_TARGET = showpart SHOWPART_OBJS = showpart.unix.o lib.unix.o os_unix.showpart.o CPPFLAGS = -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -I../include CFLAGS = -Wall LDFLAGS = LIBS = # system-dependent additions system = $(shell uname) ifeq ($(system),Darwin) CC = gcc-4.0 # TODO: re-enable this once the code is no longer little-endian specific #CFLAGS += -arch i386 -arch ppc #LDFLAGS += -arch i386 -arch ppc ifeq (/Developer/SDKs/MacOSX10.4u.sdk,$(wildcard /Developer/SDKs/MacOSX10.4u.sdk)) CPPFLAGS += -isysroot /Developer/SDKs/MacOSX10.4u.sdk LDFLAGS += -Wl,-syslibroot,/Developer/SDKs/MacOSX10.4u.sdk endif endif # real making all: $(GPTSYNC_TARGET) $(SHOWPART_TARGET) $(GPTSYNC_TARGET): $(GPTSYNC_OBJS) $(CC) $(LDFLAGS) -o $@ $(GPTSYNC_OBJS) $(LIBS) gptsync.unix.o: gptsync.c $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ os_unix.gptsync.o: os_unix.c $(CC) $(CPPFLAGS) -DPROGNAME=gptsync $(CFLAGS) -c $< -o $@ $(SHOWPART_TARGET): $(SHOWPART_OBJS) $(CC) $(LDFLAGS) -o $@ $(SHOWPART_OBJS) $(LIBS) showpart.unix.o: showpart.c $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ os_unix.showpart.o: os_unix.c $(CC) $(CPPFLAGS) -DPROGNAME=showpart -DNOREADONLYWARN $(CFLAGS) -c $< -o $@ lib.unix.o: lib.c $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ # additional dependencies gptsync.unix.o: gptsync.h ../include/syslinux_mbr.h os_unix.gptsync.o: gptsync.h showpart.unix.o: gptsync.h os_unix.showpart.o: gptsync.h lib.unix.o: gptsync.h # cleanup clean: $(RM) *.o *~ *% $(GPTSYNC_TARGET) $(SHOWPART_TARGET) distclean: clean $(RM) .depend # eof refind-0.11.4/gptsync/lib.c0000664000175000017500000004701313075420160015716 0ustar rodsmithrodsmith/* * gptsync/lib.c * Platform-independent code common to gptsync and showpart * * Copyright (c) 2006-2007 Christoph Pfisterer * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * * Neither the name of Christoph Pfisterer nor the names of the * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "gptsync.h" // variables UINT8 empty_guid[16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; PARTITION_INFO mbr_parts[4]; UINTN mbr_part_count = 0; PARTITION_INFO gpt_parts[128]; UINTN gpt_part_count = 0; PARTITION_INFO new_mbr_parts[4]; UINTN new_mbr_part_count = 0; UINT8 sector[512]; MBR_PARTTYPE mbr_types[] = { { 0x01, STR("FAT12 (CHS)") }, { 0x04, STR("FAT16 <32M (CHS)") }, { 0x05, STR("Extended (CHS)") }, { 0x06, STR("FAT16 (CHS)") }, { 0x07, STR("NTFS/HPFS") }, { 0x0b, STR("FAT32 (CHS)") }, { 0x0c, STR("FAT32 (LBA)") }, { 0x0e, STR("FAT16 (LBA)") }, { 0x0f, STR("Extended (LBA)") }, { 0x11, STR("Hidden FAT12 (CHS)") }, { 0x14, STR("Hidden FAT16 <32M (CHS)") }, { 0x16, STR("Hidden FAT16 (CHS)") }, { 0x17, STR("Hidden NTFS/HPFS") }, { 0x1b, STR("Hidden FAT32 (CHS)") }, { 0x1c, STR("Hidden FAT32 (LBA)") }, { 0x1e, STR("Hidden FAT16 (LBA)") }, { 0x82, STR("Linux swap / Solaris") }, { 0x83, STR("Linux") }, { 0x85, STR("Linux Extended") }, { 0x86, STR("NT FAT volume set") }, { 0x87, STR("NTFS volume set") }, { 0x8e, STR("Linux LVM") }, { 0xa5, STR("FreeBSD") }, { 0xa6, STR("OpenBSD") }, { 0xa7, STR("NeXTSTEP") }, { 0xa8, STR("MacOS UFS") }, { 0xa9, STR("NetBSD") }, { 0xab, STR("MacOS Boot") }, { 0xac, STR("Apple RAID") }, { 0xaf, STR("MacOS HFS+") }, { 0xbe, STR("Solaris Boot") }, { 0xbf, STR("Solaris") }, { 0xeb, STR("BeOS") }, { 0xee, STR("EFI Protective") }, { 0xef, STR("EFI System (FAT)") }, { 0xfd, STR("Linux RAID") }, { 0, NULL }, }; GPT_PARTTYPE gpt_types[] = { // Sony uses this one { "\x32\x97\x01\xF4\x6E\x06\x12\x4E\x82\x73\x34\x6C\x56\x41\x49\x4F", 0x00, STR("Sony System (FAT)"), GPT_KIND_FATAL }, // Defined by EFI/UEFI specification { "\x28\x73\x2A\xC1\x1F\xF8\xD2\x11\xBA\x4B\x00\xA0\xC9\x3E\xC9\x3B", 0xef, STR("EFI System (FAT)"), GPT_KIND_SYSTEM }, { "\x41\xEE\x4D\x02\xE7\x33\xD3\x11\x9D\x69\x00\x08\xC7\x81\xF3\x9F", 0x00, STR("MBR partition scheme"), GPT_KIND_FATAL }, // Generally well-known { "\x16\xE3\xC9\xE3\x5C\x0B\xB8\x4D\x81\x7D\xF9\x2D\xF0\x02\x15\xAE", 0x00, STR("MS Reserved"), GPT_KIND_SYSTEM }, { "\xA2\xA0\xD0\xEB\xE5\xB9\x33\x44\x87\xC0\x68\xB6\xB7\x26\x99\xC7", 0x00, STR("Basic Data"), GPT_KIND_BASIC_DATA }, // From Wikipedia { "\xAA\xC8\x08\x58\x8F\x7E\xE0\x42\x85\xD2\xE1\xE9\x04\x34\xCF\xB3", 0x00, STR("MS LDM Metadata"), GPT_KIND_FATAL }, { "\xA0\x60\x9B\xAF\x31\x14\x62\x4F\xBC\x68\x33\x11\x71\x4A\x69\xAD", 0x00, STR("MS LDM Data"), GPT_KIND_FATAL }, { "\x1E\x4C\x89\x75\xEB\x3A\xD3\x11\xB7\xC1\x7B\x03\xA0\x00\x00\x00", 0x00, STR("HP/UX Data"), GPT_KIND_DATA }, { "\x28\xE7\xA1\xE2\xE3\x32\xD6\x11\xA6\x82\x7B\x03\xA0\x00\x00\x00", 0x00, STR("HP/UX Service"), GPT_KIND_SYSTEM }, // From Linux repository, fs/partitions/efi.h { "\x0F\x88\x9D\xA1\xFC\x05\x3B\x4D\xA0\x06\x74\x3F\x0F\x84\x91\x1E", 0xfd, STR("Linux RAID"), GPT_KIND_DATA }, { "\x6D\xFD\x57\x06\xAB\xA4\xC4\x43\x84\xE5\x09\x33\xC8\x4B\x4F\x4F", 0x82, STR("Linux Swap"), GPT_KIND_SYSTEM }, { "\x79\xD3\xD6\xE6\x07\xF5\xC2\x44\xA2\x3C\x23\x8F\x2A\x3D\xF9\x28", 0x8e, STR("Linux LVM"), GPT_KIND_DATA }, { "\xAF\x3D\xC6\x0F\x83\x84\x72\x47\x8E\x79\x3D\x69\xD8\x47\x7D\xE4", 0x83, STR("Linux Filesystem"), GPT_KIND_DATA }, // From Wikipedia { "\x39\x33\xA6\x8D\x07\x00\xC0\x60\xC4\x36\x08\x3A\xC8\x23\x09\x08", 0x00, STR("Linux Reserved"), GPT_KIND_SYSTEM }, // From grub2 repository, grub/include/grub/gpt_partition.h { "\x48\x61\x68\x21\x49\x64\x6F\x6E\x74\x4E\x65\x65\x64\x45\x46\x49", 0x00, STR("GRUB2 BIOS Boot"), GPT_KIND_SYSTEM }, // From FreeBSD repository, sys/sys/gpt.h { "\xB4\x7C\x6E\x51\xCF\x6E\xD6\x11\x8F\xF8\x00\x02\x2D\x09\x71\x2B", 0xa5, STR("FreeBSD Data"), GPT_KIND_DATA }, { "\xB5\x7C\x6E\x51\xCF\x6E\xD6\x11\x8F\xF8\x00\x02\x2D\x09\x71\x2B", 0x00, STR("FreeBSD Swap"), GPT_KIND_SYSTEM }, { "\xB6\x7C\x6E\x51\xCF\x6E\xD6\x11\x8F\xF8\x00\x02\x2D\x09\x71\x2B", 0xa5, STR("FreeBSD UFS"), GPT_KIND_DATA }, { "\xB8\x7C\x6E\x51\xCF\x6E\xD6\x11\x8F\xF8\x00\x02\x2D\x09\x71\x2B", 0x00, STR("FreeBSD Vinum"), GPT_KIND_DATA }, { "\xBA\x7C\x6E\x51\xCF\x6E\xD6\x11\x8F\xF8\x00\x02\x2D\x09\x71\x2B", 0xa5, STR("FreeBSD ZFS"), GPT_KIND_DATA }, { "\x9D\x6B\xBD\x83\x41\x7F\xDC\x11\xBE\x0B\x00\x15\x60\xB8\x4F\x0F", 0xa5, STR("FreeBSD Boot"), GPT_KIND_DATA }, // From NetBSD repository, sys/sys/disklabel_gpt.h { "\x32\x8D\xF4\x49\x0E\xB1\xDC\x11\xB9\x9B\x00\x19\xD1\x87\x96\x48", 0x00, STR("NetBSD Swap"), GPT_KIND_SYSTEM }, { "\x5A\x8D\xF4\x49\x0E\xB1\xDC\x11\xB9\x9B\x00\x19\xD1\x87\x96\x48", 0xa9, STR("NetBSD FFS"), GPT_KIND_DATA }, { "\x82\x8D\xF4\x49\x0E\xB1\xDC\x11\xB9\x9B\x00\x19\xD1\x87\x96\x48", 0xa9, STR("NetBSD LFS"), GPT_KIND_DATA }, { "\xAA\x8D\xF4\x49\x0E\xB1\xDC\x11\xB9\x9B\x00\x19\xD1\x87\x96\x48", 0xa9, STR("NetBSD RAID"), GPT_KIND_DATA }, { "\xC4\x19\xB5\x2D\x0E\xB1\xDC\x11\xB9\x9B\x00\x19\xD1\x87\x96\x48", 0xa9, STR("NetBSD CCD"), GPT_KIND_DATA }, { "\xEC\x19\xB5\x2D\x0E\xB1\xDC\x11\xB9\x9B\x00\x19\xD1\x87\x96\x48", 0xa9, STR("NetBSD CGD"), GPT_KIND_DATA }, // From http://developer.apple.com/mac/library/technotes/tn2006/tn2166.html // { "\x00\x53\x46\x48\x00\x00\xAA\x11\xAA\x11\x00\x30\x65\x43\xEC\xAC", 0x00, STR("MacOS HFS+"), GPT_KIND_SYSTEM }, { "\x00\x53\x46\x48\x00\x00\xAA\x11\xAA\x11\x00\x30\x65\x43\xEC\xAC", 0xaf, STR("MacOS HFS+"), GPT_KIND_DATA }, { "\x72\x6F\x74\x53\x67\x61\xAA\x11\xAA\x11\x00\x30\x65\x43\xEC\xAC", 0xaf, STR("MacOS Core Storage"), GPT_KIND_DATA }, { "\x00\x53\x46\x55\x00\x00\xAA\x11\xAA\x11\x00\x30\x65\x43\xEC\xAC", 0xa8, STR("MacOS UFS"), GPT_KIND_DATA }, { "\x74\x6F\x6F\x42\x00\x00\xAA\x11\xAA\x11\x00\x30\x65\x43\xEC\xAC", 0xab, STR("MacOS Boot"), GPT_KIND_DATA }, { "\x44\x49\x41\x52\x00\x00\xAA\x11\xAA\x11\x00\x30\x65\x43\xEC\xAC", 0xac, STR("Apple RAID"), GPT_KIND_DATA }, { "\x44\x49\x41\x52\x4F\x5F\xAA\x11\xAA\x11\x00\x30\x65\x43\xEC\xAC", 0xac, STR("Apple RAID (Offline)"), GPT_KIND_DATA }, { "\x65\x62\x61\x4C\x00\x6C\xAA\x11\xAA\x11\x00\x30\x65\x43\xEC\xAC", 0x00, STR("Apple Label"), GPT_KIND_SYSTEM }, // From Wikipedia { "\x6F\x63\x65\x52\x65\x76\xAA\x11\xAA\x11\x00\x30\x65\x43\xEC\xAC", 0x00, STR("Apple TV Recovery"), GPT_KIND_DATA }, // From OpenSolaris repository, usr/src/uts/common/sys/efi_partition.h { "\x7f\x23\x96\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0x00, STR("Solaris Reserved"), GPT_KIND_SYSTEM }, { "\x45\xCB\x82\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0xbf, STR("Solaris Boot"), GPT_KIND_DATA }, { "\x4D\xCF\x85\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0xbf, STR("Solaris Root"), GPT_KIND_DATA }, { "\x6F\xC4\x87\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0x00, STR("Solaris Swap"), GPT_KIND_SYSTEM }, { "\xC3\x8C\x89\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0xbf, STR("Solaris Usr / Apple ZFS"), GPT_KIND_DATA }, { "\x2B\x64\x8B\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0x00, STR("Solaris Backup"), GPT_KIND_SYSTEM }, { "\xC7\x2A\x8D\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0x00, STR("Solaris Reserved (Stand)"), GPT_KIND_SYSTEM }, { "\xE9\xF2\x8E\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0xbf, STR("Solaris Var"), GPT_KIND_DATA }, { "\x39\xBA\x90\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0xbf, STR("Solaris Home"), GPT_KIND_DATA }, { "\xA5\x83\x92\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0x00, STR("Solaris Alternate Sector"), GPT_KIND_SYSTEM }, { "\x3B\x5A\x94\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0x00, STR("Solaris Reserved (Cache)"), GPT_KIND_SYSTEM }, { "\xD1\x30\x96\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0x00, STR("Solaris Reserved"), GPT_KIND_SYSTEM }, { "\x67\x07\x98\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0x00, STR("Solaris Reserved"), GPT_KIND_SYSTEM }, // List sentinel { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, 0, NULL, 0 }, }; GPT_PARTTYPE gpt_dummy_type = { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, 0, STR("Unknown"), GPT_KIND_FATAL }; // // MBR functions // CHARN * mbr_parttype_name(UINT8 type) { int i; for (i = 0; mbr_types[i].name; i++) if (mbr_types[i].type == type) return mbr_types[i].name; return STR("Unknown"); } UINTN read_mbr(VOID) { UINTN status; UINTN i; BOOLEAN used; MBR_PART_INFO *table; Print(L"\nCurrent MBR partition table:\n"); // read MBR data status = read_sector(0, sector); if (status != 0) return status; // check for validity if (*((UINT16 *)(sector + 510)) != 0xaa55) { Print(L" No MBR partition table present!\n"); return 1; } table = (MBR_PART_INFO *)(sector + 446); for (i = 0; i < 4; i++) { if (table[i].flags != 0x00 && table[i].flags != 0x80) { Print(L" MBR partition table is invalid!\n"); return 1; } } // check if used used = FALSE; for (i = 0; i < 4; i++) { if (table[i].start_lba > 0 && table[i].size > 0) { used = TRUE; break; } } if (!used) { Print(L" No partitions defined\n"); return 0; } // dump current state & fill internal structures Print(L" # A Start LBA End LBA Type\n"); for (i = 0; i < 4; i++) { if (table[i].start_lba == 0 || table[i].size == 0) continue; mbr_parts[mbr_part_count].index = i; mbr_parts[mbr_part_count].start_lba = (UINT64)table[i].start_lba; mbr_parts[mbr_part_count].end_lba = (UINT64)table[i].start_lba + (UINT64)table[i].size - 1; mbr_parts[mbr_part_count].mbr_type = table[i].type; mbr_parts[mbr_part_count].active = (table[i].flags == 0x80) ? TRUE : FALSE; Print(L" %d %s %12lld %12lld %02x %s\n", mbr_parts[mbr_part_count].index + 1, mbr_parts[mbr_part_count].active ? STR("*") : STR(" "), mbr_parts[mbr_part_count].start_lba, mbr_parts[mbr_part_count].end_lba, mbr_parts[mbr_part_count].mbr_type, mbr_parttype_name(mbr_parts[mbr_part_count].mbr_type)); mbr_part_count++; } return 0; } // // GPT functions // GPT_PARTTYPE * gpt_parttype(UINT8 *type_guid) { int i; for (i = 0; gpt_types[i].name; i++) if (guids_are_equal(gpt_types[i].guid, type_guid)) return &(gpt_types[i]); return &gpt_dummy_type; } UINTN read_gpt(VOID) { UINTN status; GPT_HEADER *header; GPT_ENTRY *entry; UINT64 entry_lba; UINTN entry_count, entry_size, i; Print(L"\nCurrent GUID partition table:\n"); // read GPT header status = read_sector(1, sector); if (status != 0) return status; // check signature header = (GPT_HEADER *)sector; if (header->signature != 0x5452415020494645ULL) { Print(L" No GPT partition table present!\n"); return 0; } if (header->spec_revision != 0x00010000UL) { Print(L" Warning: Unknown GPT spec revision 0x%08x\n", header->spec_revision); } if ((512 % header->entry_size) > 0 || header->entry_size > 512) { Print(L" Error: Invalid GPT entry size (misaligned or more than 512 bytes)\n"); return 0; } // read entries entry_lba = header->entry_lba; entry_size = header->entry_size; entry_count = header->entry_count; for (i = 0; i < entry_count; i++) { if (((i * entry_size) % 512) == 0) { status = read_sector(entry_lba, sector); if (status != 0) return status; entry_lba++; } entry = (GPT_ENTRY *)(sector + ((i * entry_size) % 512)); if (guids_are_equal(entry->type_guid, empty_guid)) continue; if (gpt_part_count == 0) { Print(L" # Start LBA End LBA Type\n"); } gpt_parts[gpt_part_count].index = i; gpt_parts[gpt_part_count].start_lba = entry->start_lba; gpt_parts[gpt_part_count].end_lba = entry->end_lba; gpt_parts[gpt_part_count].mbr_type = 0; copy_guid(gpt_parts[gpt_part_count].gpt_type, entry->type_guid); gpt_parts[gpt_part_count].gpt_parttype = gpt_parttype(gpt_parts[gpt_part_count].gpt_type); gpt_parts[gpt_part_count].active = FALSE; Print(L" %d %12lld %12lld %s\n", gpt_parts[gpt_part_count].index + 1, gpt_parts[gpt_part_count].start_lba, gpt_parts[gpt_part_count].end_lba, gpt_parts[gpt_part_count].gpt_parttype->name); gpt_part_count++; } if (gpt_part_count == 0) { Print(L" No partitions defined\n"); return 0; } return 0; } // // detect file system type // UINTN detect_mbrtype_fs(UINT64 partlba, UINTN *parttype, CHARN **fsname) { UINTN status; UINTN signature, score; UINTN sectsize, clustersize, reserved, fatcount, dirsize, sectcount, fatsize, clustercount; *fsname = STR("Unknown"); *parttype = 0; // READ sector 0 / offset 0K status = read_sector(partlba, sector); if (status != 0) return status; // detect XFS signature = *((UINT32 *)(sector)); if (signature == 0x42534658) { *parttype = 0x83; *fsname = STR("XFS"); return 0; } // detect FAT and NTFS sectsize = *((UINT16 *)(sector + 11)); clustersize = sector[13]; if (sectsize >= 512 && (sectsize & (sectsize - 1)) == 0 && clustersize > 0 && (clustersize & (clustersize - 1)) == 0) { // preconditions for both FAT and NTFS are now met if (CompareMem(sector + 3, "NTFS ", 8) == 0) { *parttype = 0x07; *fsname = STR("NTFS"); return 0; } score = 0; // boot jump if ((sector[0] == 0xEB && sector[2] == 0x90) || sector[0] == 0xE9) score++; // boot signature if (sector[510] == 0x55 && sector[511] == 0xAA) score++; // reserved sectors reserved = *((UINT16 *)(sector + 14)); if (reserved == 1 || reserved == 32) score++; // number of FATs fatcount = sector[16]; if (fatcount == 2) score++; // number of root dir entries dirsize = *((UINT16 *)(sector + 17)); // sector count (16-bit and 32-bit versions) sectcount = *((UINT16 *)(sector + 19)); if (sectcount == 0) sectcount = *((UINT32 *)(sector + 32)); // media byte if (sector[21] == 0xF0 || sector[21] >= 0xF8) score++; // FAT size in sectors fatsize = *((UINT16 *)(sector + 22)); if (fatsize == 0) fatsize = *((UINT32 *)(sector + 36)); // determine FAT type dirsize = ((dirsize * 32) + (sectsize - 1)) / sectsize; clustercount = sectcount - (reserved + (fatcount * fatsize) + dirsize); clustercount /= clustersize; if (score >= 3) { if (clustercount < 4085) { *parttype = 0x01; *fsname = STR("FAT12"); } else if (clustercount < 65525) { *parttype = 0x0e; *fsname = STR("FAT16"); } else { *parttype = 0x0c; *fsname = STR("FAT32"); } // TODO: check if 0e and 0c are okay to use, maybe we should use 06 and 0b instead... return 0; } } // READ sector 2 / offset 1K status = read_sector(partlba + 2, sector); if (status != 0) return status; // detect HFS+ signature = *((UINT16 *)(sector)); if (signature == 0x4442) { *parttype = 0xaf; if (*((UINT16 *)(sector + 0x7c)) == 0x2B48) *fsname = STR("HFS Extended (HFS+)"); else *fsname = STR("HFS Standard"); return 0; } else if (signature == 0x2B48) { *parttype = 0xaf; *fsname = STR("HFS Extended (HFS+)"); return 0; } // detect ext2/ext3/ext4 signature = *((UINT16 *)(sector + 56)); if (signature == 0xEF53) { *parttype = 0x83; if (*((UINT16 *)(sector + 96)) & 0x02C0 || *((UINT16 *)(sector + 100)) & 0x0078) *fsname = STR("ext4"); else if (*((UINT16 *)(sector + 92)) & 0x0004) *fsname = STR("ext3"); else *fsname = STR("ext2"); return 0; } // READ sector 128 / offset 64K status = read_sector(partlba + 128, sector); if (status != 0) return status; // detect btrfs if (CompareMem(sector + 64, "_BHRfS_M", 8) == 0) { *parttype = 0x83; *fsname = STR("btrfs"); return 0; } // detect ReiserFS if (CompareMem(sector + 52, "ReIsErFs", 8) == 0 || CompareMem(sector + 52, "ReIsEr2Fs", 9) == 0 || CompareMem(sector + 52, "ReIsEr3Fs", 9) == 0) { *parttype = 0x83; *fsname = STR("ReiserFS"); return 0; } // detect Reiser4 if (CompareMem(sector, "ReIsEr4", 7) == 0) { *parttype = 0x83; *fsname = STR("Reiser4"); return 0; } // READ sector 64 / offset 32K status = read_sector(partlba + 64, sector); if (status != 0) return status; // detect JFS if (CompareMem(sector, "JFS1", 4) == 0) { *parttype = 0x83; *fsname = STR("JFS"); return 0; } // READ sector 16 / offset 8K status = read_sector(partlba + 16, sector); if (status != 0) return status; // detect ReiserFS if (CompareMem(sector + 52, "ReIsErFs", 8) == 0 || CompareMem(sector + 52, "ReIsEr2Fs", 9) == 0 || CompareMem(sector + 52, "ReIsEr3Fs", 9) == 0) { *parttype = 0x83; *fsname = STR("ReiserFS"); return 0; } return 0; } refind-0.11.4/gptsync/README.txt0000664000175000017500000000526612626644770016526 0ustar rodsmithrodsmithThis directory contains the source code for gptsync, which is a program for creating hybrid MBRs (http://www.rodsbooks.com/gdisk/hybrid.html). HYBRID MBRS ARE UGLY AND DANGEROUS HACKS, AND SHOULD NOT BE USED UNLESS ABSOLUTELY NECESSARY! Despite their dangers, hybrid MBRs are useful because Windows interprets hybrid MBR disks as having an MBR partition table, whereas OS X and Linux interpret such disks as having a GUID partition table (GPT). Since Windows ties its boot mode to the firmware type (MBR/BIOS and GPT/EFI), a hybrid MBR enables Windows to boot in BIOS mode from a disk that's primarily a GPT disk, such as a Macintosh OS X disk. Unfortunately, Apple uses hybrid MBRs as part of its workaround to enable Macs to boot Windows in BIOS mode while also supporting a standard EFI-mode boot of OS X. Many Linux distributions also install in BIOS mode on Macs, and so use hybrid MBRs; but it's usually possible to add an EFI-mode boot loader to get Macs to boot Linux in EFI mode, thus obviating the need for a hybrid MBR. Some Hackintosh installations rely on a hybrid MBR for reasons similar to those of OS X on a real Mac. Thus, you should use a hybrid MBR *ONLY* on a Mac that dual-boots with Windows or some other OS in BIOS mode or in very rare circumstances on other computers. The version of gptsync provided with rEFInd is heavily modified from the original rEFIt version of the program. Most notably, it's "smarter" about creating a hybrid MBR: It prioritizes placement of Windows (FAT and NTFS) partitions in the MBR side, followed by Linux partitions. Other partitions, such as OS X's HFS+ partitions, might not appear at all in the hybrid MBR, whereas they generally do appear in hybrid MBRs created by rEFIt's version of gptsync. In the rEFIt version of gptsync, OS X partitions can crowd out FAT or NTFS partitions, particularly on computers with shared FAT or NTFS partitions, multiple Windows installations, or triple-boots with OS X, Windows, and Linux. The rEFInd version of gptsync also checks the firmware's author and warns if you're trying to run the program on anything but Apple firmware, since in most such cases creating a hybrid MBR is *NOT* desirable. Although the Makefile supports building for both EFI (via the "gnuefi" and "tiano" targets) and Unix/Linux (via the "unix" target), the Unix build is currently broken; it returns a bogus error about an unknown GPT spec revision. If you want to create a hybrid MBR in an OS, you're better off using gdisk (http://www.rodsbooks.com/gdisk/), which provides much better control of the hybrid MBR creation process. gdisk may also be preferable if you have an unusual partition layout, many partitions, or specific requirements that you understand well. refind-0.11.4/gptsync/gptsync.c0000664000175000017500000004641713111705311016641 0ustar rodsmithrodsmith/* * gptsync/gptsync.c * Platform-independent code for syncing GPT and MBR * * Copyright (c) 2006-2007 Christoph Pfisterer * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * * Neither the name of Christoph Pfisterer nor the names of the * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* Changes copyright (c) 2013 Roderick W. Smith */ #include "gptsync.h" #include "../include/version.h" #include "../include/syslinux_mbr.h" #define memcpy(a, b, c) CopyMem(a, b, c) // // MBR functions // static UINTN check_mbr(VOID) { UINTN i, k; BOOLEAN found = FALSE; // check each entry for (i = 0; i < mbr_part_count; i++) { // check for overlap for (k = 0; k < mbr_part_count; k++) { if (k != i && !(mbr_parts[i].start_lba > mbr_parts[k].end_lba || mbr_parts[k].start_lba > mbr_parts[i].end_lba)) { Print(L"Status: MBR partition table is invalid, partitions overlap.\n"); return EFI_UNSUPPORTED; } } // check for extended partitions if (mbr_parts[i].mbr_type == 0x05 || mbr_parts[i].mbr_type == 0x0f || mbr_parts[i].mbr_type == 0x85) { Print(L"Status: Extended partition found in MBR table, will not touch this disk.\n", gpt_parts[i].gpt_parttype->name); return EFI_UNSUPPORTED; } // Check for matching GPT partitition; if not found, flag error if ((mbr_parts[i].mbr_type != 0xEE) && (mbr_parts[i].mbr_type != 0x00)) { found = FALSE; for (k = 0; (k < gpt_part_count) && !found; k++) { if ((mbr_parts[i].start_lba == gpt_parts[k].start_lba) && (mbr_parts[i].end_lba == gpt_parts[k].end_lba)) { found = TRUE; } // if } // for if (!found) { Print(L"Status: Found MBR partition with no matching GPT partition. Re-syncing could\n"); Print(L"destroy data; will not touch this disk.\n"); return EFI_UNSUPPORTED; } // if } // if } // for return 0; } // UINTN check_mbr() static UINTN write_mbr(VOID) { UINTN status; UINTN i, k; UINT8 active; UINT64 lba; MBR_PART_INFO *table; BOOLEAN have_bootcode; Print(L"\nWriting new MBR...\n"); // read MBR data status = read_sector(0, sector); if (status != 0) return status; // write partition table *((UINT16 *)(sector + 510)) = 0xaa55; table = (MBR_PART_INFO *)(sector + 446); active = 0x80; for (i = 0; i < 4; i++) { for (k = 0; k < new_mbr_part_count; k++) { if (new_mbr_parts[k].index == i) break; } if (k >= new_mbr_part_count) { // unused entry table[i].flags = 0; table[i].start_chs[0] = 0; table[i].start_chs[1] = 0; table[i].start_chs[2] = 0; table[i].type = 0; table[i].end_chs[0] = 0; table[i].end_chs[1] = 0; table[i].end_chs[2] = 0; table[i].start_lba = 0; table[i].size = 0; } else { if (new_mbr_parts[k].active) { table[i].flags = active; active = 0x00; } else table[i].flags = 0x00; table[i].start_chs[0] = 0xfe; table[i].start_chs[1] = 0xff; table[i].start_chs[2] = 0xff; table[i].type = new_mbr_parts[k].mbr_type; table[i].end_chs[0] = 0xfe; table[i].end_chs[1] = 0xff; table[i].end_chs[2] = 0xff; lba = new_mbr_parts[k].start_lba; if (lba > MAX_MBR_LBA) { Print(L"Warning: Partition %d starts beyond 2 TiB limit\n", i+1); lba = MAX_MBR_LBA; } table[i].start_lba = (UINT32)lba; lba = new_mbr_parts[k].end_lba + 1 - new_mbr_parts[k].start_lba; if (lba > MAX_MBR_LBA) { Print(L"Warning: Partition %d extends beyond 2 TiB limit\n", i+1); lba = MAX_MBR_LBA; } table[i].size = (UINT32)lba; } } // add boot code if necessary have_bootcode = FALSE; for (i = 0; i < MBR_BOOTCODE_SIZE; i++) { if (sector[i] != 0) { have_bootcode = TRUE; break; } } if (!have_bootcode) { // no boot code found in the MBR, add the syslinux MBR code SetMem(sector, MBR_BOOTCODE_SIZE, 0); CopyMem(sector, syslinux_mbr, SYSLINUX_MBR_SIZE); } // write MBR data status = write_sector(0, sector); if (status != 0) return status; Print(L"MBR updated successfully!\n"); return 0; } // // GPT functions // static UINTN check_gpt(VOID) { UINTN i, k; if (gpt_part_count == 0) { Print(L"Status: No GPT partition table, no need to sync.\n"); return EFI_UNSUPPORTED; } // check each entry for (i = 0; i < gpt_part_count; i++) { // check sanity if (gpt_parts[i].end_lba < gpt_parts[i].start_lba) { Print(L"Status: GPT partition table is invalid.\n"); return EFI_UNSUPPORTED; } // check for overlap for (k = 0; k < gpt_part_count; k++) { if (k != i && !(gpt_parts[i].start_lba > gpt_parts[k].end_lba || gpt_parts[k].start_lba > gpt_parts[i].end_lba)) { Print(L"Status: GPT partition table is invalid, partitions overlap.\n"); return EFI_UNSUPPORTED; } } // check for partitions kind if (gpt_parts[i].gpt_parttype->kind == GPT_KIND_FATAL) { Print(L"Status: GPT partition of type '%s' found, will not touch this disk.\n", gpt_parts[i].gpt_parttype->name); return EFI_UNSUPPORTED; } } return 0; } // VOID check_gpt() // // compare GPT and MBR tables // #define ACTION_NONE (0) #define ACTION_NOP (1) #define ACTION_REWRITE (2) // Copy a single GPT entry to the new_mbr_parts array. static VOID copy_gpt_to_new_mbr(UINTN gpt_num, UINTN mbr_num) { new_mbr_parts[mbr_num].index = mbr_num; new_mbr_parts[mbr_num].start_lba = gpt_parts[gpt_num].start_lba; new_mbr_parts[mbr_num].end_lba = gpt_parts[gpt_num].end_lba; new_mbr_parts[mbr_num].mbr_type = gpt_parts[gpt_num].mbr_type; new_mbr_parts[mbr_num].active = FALSE; } // VOID copy_gpt_to_new_mbr() // A simple bubble sort for the MBR partitions. static VOID sort_mbr(PARTITION_INFO *parts) { PARTITION_INFO one_part; int c, d; if (parts == NULL) return; for (c = 0 ; c < 3; c++) { for (d = 1 ; d < 3 - c; d++) { if ((parts[d].start_lba > parts[d + 1].start_lba) && (parts[d].start_lba > 0) && (parts[d + 1].start_lba > 0)) { one_part = parts[d]; parts[d] = parts[d + 1]; parts[d + 1] = one_part; parts[d].index = d; parts[d + 1].index = d + 1; } // if } // for } // for } // VOID sort_mbr() // Generate a hybrid MBR based on the current GPT. Stores the result in the // new_mbr_parts[] array. static VOID generate_hybrid_mbr(VOID) { UINTN i, k, iter, count_active; UINT64 first_used_lba; new_mbr_part_count = 1; first_used_lba = (UINT64) MAX_MBR_LBA + (UINT64) 1; // Copy partitions in three passes.... // First, do FAT and NTFS partitions.... i = 0; do { if ((gpt_parts[i].start_lba > 0) && (gpt_parts[i].end_lba > 0) && (gpt_parts[i].end_lba <= MAX_MBR_LBA) && /* Within MBR limits */ (gpt_parts[i].gpt_parttype->kind == GPT_KIND_BASIC_DATA) && /* MS Basic Data GPT type code */ (gpt_parts[i].mbr_type != 0x83)) { /* Not containing Linux filesystem */ copy_gpt_to_new_mbr(i, new_mbr_part_count); if (new_mbr_parts[new_mbr_part_count].start_lba < first_used_lba) first_used_lba = new_mbr_parts[new_mbr_part_count].start_lba; new_mbr_part_count++; } i++; } while (i < gpt_part_count && new_mbr_part_count <= 3); // Second, do Linux partitions. Note that we start from the END of the // partition list, so as to maximize the space covered by the 0xEE // partition if there are several Linux partitions before other hybridized // partitions. i = gpt_part_count - 1; // Note that gpt_part_count can't be 0; filtered by check_gpt() while (i < gpt_part_count && new_mbr_part_count <= 3) { // if too few GPT partitions, i loops around to a huge value if ((gpt_parts[i].start_lba > 0) && (gpt_parts[i].end_lba > 0) && (gpt_parts[i].end_lba <= MAX_MBR_LBA) && ((gpt_parts[i].gpt_parttype->kind == GPT_KIND_DATA) || (gpt_parts[i].gpt_parttype->kind == GPT_KIND_BASIC_DATA)) && (gpt_parts[i].mbr_type == 0x83)) { copy_gpt_to_new_mbr(i, new_mbr_part_count); if (new_mbr_parts[new_mbr_part_count].start_lba < first_used_lba) first_used_lba = new_mbr_parts[new_mbr_part_count].start_lba; new_mbr_part_count++; } i--; } // while // Third, do anything that's left to cover uncovered spaces; but this requires // first creating the EFI protective entry, since we don't want to bother with // anything already covered by this entry.... new_mbr_parts[0].index = 0; new_mbr_parts[0].start_lba = 1; new_mbr_parts[0].end_lba = (disk_size() > first_used_lba) ? (first_used_lba - 1) : disk_size() - 1; if (new_mbr_parts[0].end_lba > MAX_MBR_LBA) new_mbr_parts[0].end_lba = MAX_MBR_LBA; new_mbr_parts[0].mbr_type = 0xEE; i = 0; while (i < gpt_part_count && new_mbr_part_count <= 3) { if ((gpt_parts[i].start_lba > new_mbr_parts[0].end_lba) && (gpt_parts[i].end_lba > 0) && (gpt_parts[i].end_lba <= MAX_MBR_LBA) && (gpt_parts[i].gpt_parttype->kind != GPT_KIND_BASIC_DATA) && (gpt_parts[i].mbr_type != 0x83)) { copy_gpt_to_new_mbr(i, new_mbr_part_count); new_mbr_part_count++; } i++; } // while // find matching partitions in the old MBR table, copy undetected details.... for (i = 1; i < new_mbr_part_count; i++) { for (k = 0; k < mbr_part_count; k++) { if (mbr_parts[k].start_lba == new_mbr_parts[i].start_lba) { // keep type if not detected if (new_mbr_parts[i].mbr_type == 0) new_mbr_parts[i].mbr_type = mbr_parts[k].mbr_type; // keep active flag new_mbr_parts[i].active = mbr_parts[k].active; break; } // if } // for (k...) if (new_mbr_parts[i].mbr_type == 0) { // final fallback: set to a (hopefully) unused type new_mbr_parts[i].mbr_type = 0xc0; } // if } // for (i...) sort_mbr(new_mbr_parts); // make sure there's exactly one active partition for (iter = 0; iter < 3; iter++) { // check count_active = 0; for (i = 0; i < new_mbr_part_count; i++) if (new_mbr_parts[i].active) count_active++; if (count_active == 1) break; // set active on the first matching partition if (count_active == 0) { for (i = 0; i < new_mbr_part_count; i++) { if (((new_mbr_parts[i].mbr_type == 0x07 || // NTFS new_mbr_parts[i].mbr_type == 0x0b || // FAT32 new_mbr_parts[i].mbr_type == 0x0c)) || // FAT32 (LBA) (iter >= 1 && (new_mbr_parts[i].mbr_type == 0x83)) || // Linux (iter >= 2 && i > 0)) { new_mbr_parts[i].active = TRUE; break; } } } else if (count_active > 1 && iter == 0) { // too many active partitions, try deactivating the ESP / EFI Protective entry if ((new_mbr_parts[0].mbr_type == 0xee || new_mbr_parts[0].mbr_type == 0xef) && new_mbr_parts[0].active) { new_mbr_parts[0].active = FALSE; } } else if (count_active > 1 && iter > 0) { // too many active partitions, deactivate all but the first one count_active = 0; for (i = 0; i < new_mbr_part_count; i++) if (new_mbr_parts[i].active) { if (count_active > 0) new_mbr_parts[i].active = FALSE; count_active++; } } } // for } // VOID generate_hybrid_mbr() // Examine partitions and decide whether a rewrite is in order. // Note that this function MAY ask user for advice. // Note that this function assumes the new hybrid MBR has already // been computed and stored in new_mbr_parts[]. static BOOLEAN should_rewrite(VOID) { BOOLEAN retval = TRUE, all_identical = TRUE, invalid; UINTN i, num_existing_hybrid = 0, num_new_hybrid = 0; // Check to see if the proposed table is identical to the current one; // if so, synchronizing is pointless.... for (i = 0; i < 4; i++) { if ((new_mbr_parts[i].mbr_type != 0xEE) && (mbr_parts[i].mbr_type != 0xEE) && ((new_mbr_parts[i].active != mbr_parts[i].active) || (new_mbr_parts[i].start_lba != mbr_parts[i].start_lba) || (new_mbr_parts[i].end_lba != mbr_parts[i].end_lba) || (new_mbr_parts[i].mbr_type != mbr_parts[i].mbr_type))) all_identical = FALSE; // while we're looping, count the number of old & new hybrid partitions.... if ((mbr_parts[i].mbr_type != 0x00) && (mbr_parts[i].mbr_type != 0xEE)) num_existing_hybrid++; if ((new_mbr_parts[i].mbr_type != 0x00) && (new_mbr_parts[i].mbr_type != 0xEE)) num_new_hybrid++; } // for if (all_identical) { Print(L"Tables are synchronized, no need to sync.\n"); return FALSE; } // If there's nothing to hybridize, but an existing hybrid MBR exists, offer to replace // the hybrid MBR with a protective MBR. if ((num_new_hybrid == 0) && (num_existing_hybrid > 0)) { Print(L"Found no partitions that could be hybridized, but an existing hybrid MBR exists.\n"); Print(L"If you proceed, a fresh protective MBR will be created. Do you want to create\n"); invalid = input_boolean(STR("this new protective MBR, erasing the hybrid MBR? [y/N] "), &retval); if (invalid) retval = FALSE; } // if // If existing hybrid MBR that's NOT identical to the new one, ask the user // before overwriting the old one. if ((num_new_hybrid > 0) && (num_existing_hybrid > 0)) { Print(L"Existing hybrid MBR detected, but it's not identical to what this program\n"); Print(L"would generate. Do you want to see the hybrid MBR that this program would\n"); invalid = input_boolean(STR("generate? [y/N] "), &retval); if (invalid) retval = FALSE; } // if return retval; } // BOOLEAN should_rewrite() static UINTN analyze(VOID) { UINTN i, detected_parttype; CHARN *fsname; UINTN status; new_mbr_part_count = 0; // determine correct MBR types for GPT partitions if (gpt_part_count == 0) { Print(L"Status: No GPT partitions defined, nothing to sync.\n"); return 0; } for (i = 0; i < gpt_part_count; i++) { gpt_parts[i].mbr_type = gpt_parts[i].gpt_parttype->mbr_type; if (gpt_parts[i].gpt_parttype->kind == GPT_KIND_BASIC_DATA) { // Basic Data: need to look at data in the partition status = detect_mbrtype_fs(gpt_parts[i].start_lba, &detected_parttype, &fsname); if (status != 0) Print(L"Warning: Error %d when detecting filesystem type!\n", status); if (detected_parttype) gpt_parts[i].mbr_type = detected_parttype; else gpt_parts[i].mbr_type = 0x0b; // fallback: FAT32 } // NOTE: mbr_type may still be 0 if content detection fails for exotic GPT types or file systems } // for // generate the new table generate_hybrid_mbr(); if (!should_rewrite()) return EFI_ABORTED; // display table Print(L"\nProposed new MBR partition table:\n"); Print(L" # A Start LBA End LBA Type\n"); for (i = 0; i < new_mbr_part_count; i++) { Print(L" %d %s %12lld %12lld %02x %s\n", new_mbr_parts[i].index + 1, new_mbr_parts[i].active ? STR("*") : STR(" "), new_mbr_parts[i].start_lba, new_mbr_parts[i].end_lba, new_mbr_parts[i].mbr_type, mbr_parttype_name(new_mbr_parts[i].mbr_type)); } return 0; } // UINTN analyze() // // sync algorithm entry point // UINTN gptsync(VOID) { UINTN status = 0; UINTN status_gpt, status_mbr; BOOLEAN proceed = FALSE; Print(L"gptsync version %s\ncopyright (c) 2006-2007 Christoph Pfisterer & 2013 Roderick W. Smith\n", REFIND_VERSION); // get full information from disk status_gpt = read_gpt(); status_mbr = read_mbr(); if (status_gpt != 0 || status_mbr != 0) return (status_gpt || status_mbr); // cross-check current situation Print(L"\n"); status = check_gpt(); // check GPT for consistency if (status != 0) return status; status = check_mbr(); // check MBR for consistency if (status != 0) return status; status = analyze(); // analyze the situation & compose new MBR table if (status != 0) return status; if (new_mbr_part_count == 0) return status; // offer user the choice what to do status = input_boolean(STR("\nMay I update the MBR as printed above? [y/N] "), &proceed); if (status != 0 || proceed != TRUE) return status; // adjust the MBR and write it back status = write_mbr(); if (status != 0) return status; return status; } refind-0.11.4/gptsync/Make.tiano0000664000175000017500000000507213137426666016734 0ustar rodsmithrodsmith# # gptsync/Make.tiano # Build control file for gptsync utility, built with TianoCore EDK2 # include ../Make.common # Below file defines TARGET (RELEASE or DEBUG) and TOOL_CHAIN_TAG (GCC44, GCC45, or GCC46) #include $(TIANOBASE)/Conf/target.txt EFILIB = $(TIANOBASE)/Build/Mde/$(TARGET)_$(TOOL_CHAIN_TAG)/$(UC_ARCH)/MdePkg/Library ALL_EFILIBS = $(EFILIB)/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib/OUTPUT/BaseDebugPrintErrorLevelLib.lib \ $(EFILIB)/BasePrintLib/BasePrintLib/OUTPUT/BasePrintLib.lib \ $(EFILIB)/BasePcdLibNull/BasePcdLibNull/OUTPUT/BasePcdLibNull.lib \ $(EFILIB)/UefiDebugLibConOut/UefiDebugLibConOut/OUTPUT/UefiDebugLibConOut.lib \ $(EFILIB)/BaseLib/BaseLib/OUTPUT/BaseLib.lib \ $(EFILIB)/BaseMemoryLib/BaseMemoryLib/OUTPUT/BaseMemoryLib.lib \ $(EFILIB)/UefiBootServicesTableLib/UefiBootServicesTableLib/OUTPUT/UefiBootServicesTableLib.lib \ $(EFILIB)/UefiMemoryAllocationLib/UefiMemoryAllocationLib/OUTPUT/UefiMemoryAllocationLib.lib \ $(EFILIB)/UefiDevicePathLib/UefiDevicePathLib/OUTPUT/UefiDevicePathLib.lib \ $(EFILIB)/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib/OUTPUT/UefiRuntimeServicesTableLib.lib \ $(EFILIB)/UefiLib/UefiLib/OUTPUT/UefiLib.lib \ $(EFILIB)/UefiApplicationEntryPoint/UefiApplicationEntryPoint/OUTPUT/UefiApplicationEntryPoint.lib ifeq ($(ARCH),aarch64) ALL_EFILIBS += $(EFILIB)/BaseStackCheckLib/BaseStackCheckLib/OUTPUT/BaseStackCheckLib.lib endif TIANO_INCLUDE_DIRS = -I $(TIANOBASE)/MdePkg \ -I $(TIANOBASE)/MdePkg/Include \ -I $(TIANOBASE)/MdePkg/Include/$(ARCHDIR) \ -I $(TIANOBASE)/EdkCompatibilityPkg/Foundation/Framework/Include \ -I $(TIANOBASE)/EdkCompatibilityPkg/Foundation/Library/Dxe/Include \ -I $(TIANOBASE)/MdeModulePkg/ \ -I $(TIANOBASE)/MdeModulePkg/Include \ -I $(TIANOBASE)/IntelFrameworkPkg/Include \ -I $(TIANOBASE)/MdePkg/Include/$(ARCHDIR) \ -I ../libeg \ -I ../include \ -I .. GPTSYNC_NAMES = gptsync lib os_efi AutoGen ../EfiLib/BmLib OBJS = $(GPTSYNC_NAMES:=.obj) BUILDME = gptsync_$(FILENAME_CODE).efi ifneq (,$(filter %.efi,$(BUILDME))) DLL_TARGET = $(subst .efi,.dll,$(BUILDME)) all: $(BUILDME) $(DLL_TARGET): $(OBJS) $(LD) -o gptsync_$(FILENAME_CODE).dll $(TIANO_LDFLAGS) --start-group $(ALL_EFILIBS) $(OBJS) --end-group $(BUILDME): $(DLL_TARGET) $(OBJCOPY) --strip-unneeded -R .eh_frame $(DLL_TARGET) $(GENFW) -e UEFI_APPLICATION -o $(BUILDME) $(DLL_TARGET) endif refind-0.11.4/RefindPkg.dec0000664000175000017500000000036313112113643015635 0ustar rodsmithrodsmith[Defines] DEC_SPECIFICATION = 0x00010005 PACKAGE_NAME = RefindPkg PACKAGE_GUID = 0eae8e1b-55be-4c3c-852a-f0273e22ca3c PACKAGE_VERSION = 4.5.0 [Includes] StdLib/Include refind-0.11.4/mok/0000775000175000017500000000000013372347460014111 5ustar rodsmithrodsmithrefind-0.11.4/mok/guid.c0000664000175000017500000000377312626644770015224 0ustar rodsmithrodsmith/* * Copyright 2012 * * see COPYING file */ #include "global.h" #include "guid.h" // #ifndef BUILD_EFI // /* EFI has %g for this, so it's only needed in platform c */ // const char *guid_to_str(EFI_GUID *guid) // { // static char str[256]; // // sprintf(str, "%08x-%04hx-%04hx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx", // guid->Data1, guid->Data2, guid->Data3, // guid->Data4[0], guid->Data4[1], guid->Data4[2], // guid->Data4[3], guid->Data4[4], guid->Data4[5], // guid->Data4[6], guid->Data4[7]); // // return str; // } // // void str_to_guid(const char *str, EFI_GUID *guid) // { // sscanf(str, "%8x-%4hx-%4hx-%2hhx%2hhx-%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx", // &guid->Data1, &guid->Data2, &guid->Data3, // guid->Data4, guid->Data4 + 1, guid->Data4 + 2, // guid->Data4 + 3, guid->Data4 + 4, guid->Data4 + 5, // guid->Data4 + 6, guid->Data4 + 7); // } // #endif /* all the necessary guids */ EFI_GUID GV_GUID = EFI_GLOBAL_VARIABLE; EFI_GUID SIG_DB = { 0xd719b2cb, 0x3d3a, 0x4596, {0xa3, 0xbc, 0xda, 0xd0, 0xe, 0x67, 0x65, 0x6f }}; EFI_GUID X509_GUID = { 0xa5c059a1, 0x94e4, 0x4aa7, {0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72} }; EFI_GUID RSA2048_GUID = { 0x3c5766e8, 0x269c, 0x4e34, {0xaa, 0x14, 0xed, 0x77, 0x6e, 0x85, 0xb3, 0xb6} }; EFI_GUID PKCS7_GUID = { 0x4aafd29d, 0x68df, 0x49ee, {0x8a, 0xa9, 0x34, 0x7d, 0x37, 0x56, 0x65, 0xa7} }; EFI_GUID IMAGE_PROTOCOL = LOADED_IMAGE_PROTOCOL; EFI_GUID SIMPLE_FS_PROTOCOL = SIMPLE_FILE_SYSTEM_PROTOCOL; EFI_GUID EFI_CERT_SHA256_GUID = { 0xc1c41626, 0x504c, 0x4092, { 0xac, 0xa9, 0x41, 0xf9, 0x36, 0x93, 0x43, 0x28 } }; EFI_GUID MOK_OWNER = { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} }; EFI_GUID SECURITY_PROTOCOL_GUID = { 0xA46423E3, 0x4617, 0x49f1, {0xB9, 0xFF, 0xD1, 0xBF, 0xA9, 0x11, 0x58, 0x39 } }; EFI_GUID SECURITY2_PROTOCOL_GUID = { 0x94ab2f58, 0x1438, 0x4ef1, {0x91, 0x52, 0x18, 0x94, 0x1a, 0x3a, 0x0e, 0x68 } }; refind-0.11.4/mok/COPYING0000664000175000017500000013145412631672603015151 0ustar rodsmithrodsmithBelow file was part of the efitools package by James Bottomley, from which most of the source files in this directory were taken. The files in this directory originated in the "lib" directory of the efitools package, and so fall under the LGPLv2.1. The mok.c and mok.h files, however, are based on Matthew J. Garrett's shim program; see the copyright notices in those files for details.... ------------------------------------------------------------------------ efitools - useful tools for manipulating UEFI secure boot platforms (c) 2012 James Bottomley All of these programs are made available under version 2 of the GNU General Public Licence. The library routines in lib/ are made available under the GNU Lesser General Public Licence version 2.1. Additionally for linking the programme files with openSSL, there is an additional permission that compiling, linking, and/or using OpenSSL is allowed. Contributing Authors agree that their code is submitted under the licence appropriate for its location within the source tree (GPL except for LGPL in lib/) and agree that any future patches, provided they are accepted into the project, may change the licence of their code from GPL to LGPL by moving pieces of it into lib/ or LGPL to GPL by moving pieces of it out of lib/ GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. --------------------------------------- GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! refind-0.11.4/mok/guid.h0000664000175000017500000000076212626644770015224 0ustar rodsmithrodsmith//#include // #ifndef BUILD_EFI // const char *guid_to_str(EFI_GUID *guid); // void str_to_guid(const char *str, EFI_GUID *guid); // #endif extern EFI_GUID GV_GUID; extern EFI_GUID SIG_DB; extern EFI_GUID X509_GUID; extern EFI_GUID RSA2048_GUID; extern EFI_GUID PKCS7_GUID; extern EFI_GUID IMAGE_PROTOCOL; extern EFI_GUID SIMPLE_FS_PROTOCOL; extern EFI_GUID EFI_CERT_SHA256_GUID; extern EFI_GUID MOK_OWNER; extern EFI_GUID SECURITY_PROTOCOL_GUID; extern EFI_GUID SECURITY2_PROTOCOL_GUID; refind-0.11.4/mok/Makefile0000664000175000017500000000117412631122041015533 0ustar rodsmithrodsmith# # mok/Makefile # Build control file for the libeg library # # This program is licensed under the terms of the GNU GPL, version 3, # or (at your option) any later version. # You should have received a copy of the GNU General Public License # along with this program. If not, see . SRCDIR = . VPATH = $(SRCDIR) LOCAL_GNUEFI_CFLAGS = -I$(SRCDIR) -I$(SRCDIR)/../include OBJS = guid.o mok.o security_policy.o simple_file.o TARGET = libmok.a all: $(TARGET) include $(SRCDIR)/../Make.common clean: rm -f $(TARGET) *~ *.so $(OBJS) *.efi *.obj refind_*.txt refind_*.dll *.lib # EOF refind-0.11.4/mok/security_policy.c0000664000175000017500000001457212626644770017521 0ustar rodsmithrodsmith/* * Copyright 2012 * * see COPYING file * * Install and remove a platform security2 override policy */ #include #include "guid.h" #include "../refind/lib.h" #include "simple_file.h" #include "../include/refit_call_wrapper.h" #include "mok.h" #include /* * See the UEFI Platform Initialization manual (Vol2: DXE) for this */ struct _EFI_SECURITY2_PROTOCOL; struct _EFI_SECURITY_PROTOCOL; struct _EFI_DEVICE_PATH_PROTOCOL; typedef struct _EFI_SECURITY2_PROTOCOL EFI_SECURITY2_PROTOCOL; typedef struct _EFI_SECURITY_PROTOCOL EFI_SECURITY_PROTOCOL; #if defined(EFIX64) #define MSABI __attribute__((ms_abi)) #else #define MSABI #endif typedef EFI_STATUS (MSABI *EFI_SECURITY_FILE_AUTHENTICATION_STATE) ( const EFI_SECURITY_PROTOCOL *This, UINT32 AuthenticationStatus, const EFI_DEVICE_PATH_PROTOCOL *File ); typedef EFI_STATUS (MSABI *EFI_SECURITY2_FILE_AUTHENTICATION) ( const EFI_SECURITY2_PROTOCOL *This, const EFI_DEVICE_PATH_PROTOCOL *DevicePath, VOID *FileBuffer, UINTN FileSize, BOOLEAN BootPolicy ); struct _EFI_SECURITY2_PROTOCOL { EFI_SECURITY2_FILE_AUTHENTICATION FileAuthentication; }; struct _EFI_SECURITY_PROTOCOL { EFI_SECURITY_FILE_AUTHENTICATION_STATE FileAuthenticationState; }; static EFI_SECURITY_FILE_AUTHENTICATION_STATE esfas = NULL; static EFI_SECURITY2_FILE_AUTHENTICATION es2fa = NULL; // Perform shim/MOK and Secure Boot authentication on a binary that's already been // loaded into memory. This function does the platform SB authentication first // but preserves its return value in case of its failure, so that it can be // returned in case of a shim/MOK authentication failure. This is done because // the SB failure code seems to vary from one implementation to another, and I // don't want to interfere with that at this time. static MSABI EFI_STATUS security2_policy_authentication ( const EFI_SECURITY2_PROTOCOL *This, const EFI_DEVICE_PATH_PROTOCOL *DevicePath, VOID *FileBuffer, UINTN FileSize, BOOLEAN BootPolicy ) { EFI_STATUS Status; /* Chain original security policy */ Status = uefi_call_wrapper(es2fa, 5, This, DevicePath, FileBuffer, FileSize, BootPolicy); /* if OK, don't bother with MOK check */ if (Status == EFI_SUCCESS) return Status; if (ShimValidate(FileBuffer, FileSize)) { return EFI_SUCCESS; } else { return Status; } } // EFI_STATUS security2_policy_authentication() // Perform both shim/MOK and platform Secure Boot authentication. This function loads // the file and performs shim/MOK authentication first simply to avoid double loads // of Linux kernels, which are much more likely to be shim/MOK-signed than platform-signed, // since kernels are big and can take several seconds to load on some computers and // filesystems. This also has the effect of returning whatever the platform code is for // authentication failure, be it EFI_ACCESS_DENIED, EFI_SECURITY_VIOLATION, or something // else. (This seems to vary between implementations.) static MSABI EFI_STATUS security_policy_authentication ( const EFI_SECURITY_PROTOCOL *This, UINT32 AuthenticationStatus, const EFI_DEVICE_PATH_PROTOCOL *DevicePathConst ) { EFI_STATUS Status; EFI_DEVICE_PATH *DevPath, *OrigDevPath; EFI_HANDLE h; EFI_FILE *f; VOID *FileBuffer; UINTN FileSize; CHAR16 *DevPathStr; if (DevicePathConst == NULL) { return EFI_INVALID_PARAMETER; } else { DevPath = OrigDevPath = DuplicateDevicePath((EFI_DEVICE_PATH *)DevicePathConst); } Status = refit_call3_wrapper(BS->LocateDevicePath, &SIMPLE_FS_PROTOCOL, &DevPath, &h); if (Status != EFI_SUCCESS) goto out; DevPathStr = DevicePathToStr(DevPath); Status = simple_file_open_by_handle(h, DevPathStr, &f, EFI_FILE_MODE_READ); MyFreePool(DevPathStr); if (Status != EFI_SUCCESS) goto out; Status = simple_file_read_all(f, &FileSize, &FileBuffer); simple_file_close(f); if (Status != EFI_SUCCESS) goto out; if (ShimValidate(FileBuffer, FileSize)) { Status = EFI_SUCCESS; } else { // Try using the platform's native policy.... Status = uefi_call_wrapper(esfas, 3, This, AuthenticationStatus, DevicePathConst); } FreePool(FileBuffer); out: MyFreePool(OrigDevPath); return Status; } // EFI_STATUS security_policy_authentication() EFI_STATUS security_policy_install(void) { EFI_SECURITY_PROTOCOL *security_protocol; EFI_SECURITY2_PROTOCOL *security2_protocol = NULL; EFI_STATUS status; if (esfas) { /* Already Installed */ return EFI_ALREADY_STARTED; } /* Don't bother with status here. The call is allowed * to fail, since SECURITY2 was introduced in PI 1.2.1 * If it fails, use security2_protocol == NULL as indicator */ uefi_call_wrapper(BS->LocateProtocol, 3, &SECURITY2_PROTOCOL_GUID, NULL, (VOID**) &security2_protocol); status = uefi_call_wrapper(BS->LocateProtocol, 3, &SECURITY_PROTOCOL_GUID, NULL, (VOID**) &security_protocol); if (status != EFI_SUCCESS) /* This one is mandatory, so there's a serious problem */ return status; if (security2_protocol) { es2fa = security2_protocol->FileAuthentication; security2_protocol->FileAuthentication = security2_policy_authentication; } esfas = security_protocol->FileAuthenticationState; security_protocol->FileAuthenticationState = security_policy_authentication; return EFI_SUCCESS; } EFI_STATUS security_policy_uninstall(void) { EFI_STATUS status; if (esfas) { EFI_SECURITY_PROTOCOL *security_protocol; status = uefi_call_wrapper(BS->LocateProtocol, 3, &SECURITY_PROTOCOL_GUID, NULL, (VOID**) &security_protocol); if (status != EFI_SUCCESS) return status; security_protocol->FileAuthenticationState = esfas; esfas = NULL; } else { /* nothing installed */ return EFI_NOT_STARTED; } if (es2fa) { EFI_SECURITY2_PROTOCOL *security2_protocol; status = uefi_call_wrapper(BS->LocateProtocol, 3, &SECURITY2_PROTOCOL_GUID, NULL, (VOID**) &security2_protocol); if (status != EFI_SUCCESS) return status; security2_protocol->FileAuthentication = es2fa; es2fa = NULL; } return EFI_SUCCESS; } refind-0.11.4/mok/mok.c0000664000175000017500000000704412626644770015055 0ustar rodsmithrodsmith/* mok/mok.c * * Based mostly on shim.c by Matthew J. Garrett/Red Hat (see below * copyright notice). * * Code to perform Secure Boot verification of boot loader programs * using the Shim program and its Machine Owner Keys (MOKs), to * supplement standard Secure Boot checks performed by the firmware. * */ /* * shim - trivial UEFI first-stage bootloader * * Copyright 2012 Red Hat, Inc * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * * Significant portions of this code are derived from Tianocore * (http://tianocore.sf.net) and are Copyright 2009-2012 Intel * Corporation. */ #include "global.h" #include "mok.h" #include "../include/refit_call_wrapper.h" #include "../refind/lib.h" #include "../refind/screen.h" /* * Check whether we're in Secure Boot and user mode */ BOOLEAN secure_mode (VOID) { EFI_STATUS status; EFI_GUID global_var = EFI_GLOBAL_VARIABLE; UINTN charsize = sizeof(char); UINT8 *sb = NULL, *setupmode = NULL; status = EfivarGetRaw(&global_var, L"SecureBoot", (CHAR8 **) &sb, &charsize); /* FIXME - more paranoia here? */ if (status != EFI_SUCCESS || charsize != sizeof(CHAR8) || *sb != 1) { return FALSE; } status = EfivarGetRaw(&global_var, L"SetupMode", (CHAR8 **) &setupmode, &charsize); if (status == EFI_SUCCESS && charsize == sizeof(CHAR8) && *setupmode == 1) { return FALSE; } return TRUE; } // secure_mode() // Returns TRUE if the shim program is available to verify binaries, // FALSE if not BOOLEAN ShimLoaded(void) { SHIM_LOCK *shim_lock; EFI_GUID ShimLockGuid = SHIM_LOCK_GUID; return (refit_call3_wrapper(BS->LocateProtocol, &ShimLockGuid, NULL, (VOID**) &shim_lock) == EFI_SUCCESS); } // ShimLoaded() // The following is based on the grub_linuxefi_secure_validate() function in Fedora's // version of GRUB 2. // Returns TRUE if the specified data is validated by Shim's MOK, FALSE otherwise BOOLEAN ShimValidate (VOID *data, UINT32 size) { SHIM_LOCK *shim_lock; EFI_GUID ShimLockGuid = SHIM_LOCK_GUID; if ((data != NULL) && (refit_call3_wrapper(BS->LocateProtocol, &ShimLockGuid, NULL, (VOID**) &shim_lock) == EFI_SUCCESS)) { if (!shim_lock) return FALSE; if (shim_lock->shim_verify(data, size) == EFI_SUCCESS) return TRUE; } return FALSE; } // BOOLEAN ShimValidate()refind-0.11.4/mok/security_policy.h0000664000175000017500000000023412626644770017514 0ustar rodsmithrodsmithEFI_STATUS security_policy_install(void); EFI_STATUS security_policy_uninstall(void); // void // security_protocol_set_hashes(unsigned char *esl, int len); refind-0.11.4/mok/simple_file.c0000664000175000017500000001006012626644770016547 0ustar rodsmithrodsmith/* * Copyright 2012 * * see COPYING file */ #include #include "../include/refit_call_wrapper.h" #include "simple_file.h" //#include "execute.h" /* for generate_path() */ static EFI_GUID IMAGE_PROTOCOL = LOADED_IMAGE_PROTOCOL; static EFI_GUID SIMPLE_FS_PROTOCOL = SIMPLE_FILE_SYSTEM_PROTOCOL; static EFI_GUID FILE_INFO = EFI_FILE_INFO_ID; EFI_STATUS simple_file_open_by_handle(EFI_HANDLE device, CHAR16 *name, EFI_FILE **file, UINT64 mode) { EFI_STATUS efi_status; EFI_FILE_IO_INTERFACE *drive; EFI_FILE *root; efi_status = uefi_call_wrapper(BS->HandleProtocol, 3, device, &SIMPLE_FS_PROTOCOL, (VOID**) &drive); if (efi_status != EFI_SUCCESS) { Print(L"Unable to find simple file protocol\n"); goto error; } efi_status = uefi_call_wrapper(drive->OpenVolume, 2, drive, &root); if (efi_status != EFI_SUCCESS) { Print(L"Failed to open drive volume\n"); goto error; } efi_status = uefi_call_wrapper(root->Open, 5, root, file, name, mode, 0); error: return efi_status; } // generate_path() from shim by Matthew J. Garrett static EFI_STATUS generate_path(CHAR16* name, EFI_LOADED_IMAGE *li, EFI_DEVICE_PATH **path, CHAR16 **PathName) { unsigned int pathlen; EFI_STATUS efi_status = EFI_SUCCESS; CHAR16 *devpathstr = DevicePathToStr(li->FilePath), *found = NULL; int i; for (i = 0; i < StrLen(devpathstr); i++) { if (devpathstr[i] == '/') devpathstr[i] = '\\'; if (devpathstr[i] == '\\') found = &devpathstr[i]; } if (!found) { pathlen = 0; } else { while (*(found - 1) == '\\') --found; *found = '\0'; pathlen = StrLen(devpathstr); } if (name[0] != '\\') pathlen++; *PathName = AllocatePool((pathlen + 1 + StrLen(name))*sizeof(CHAR16)); if (!*PathName) { Print(L"Failed to allocate path buffer\n"); efi_status = EFI_OUT_OF_RESOURCES; goto error; } StrCpy(*PathName, devpathstr); if (name[0] != '\\') StrCat(*PathName, L"\\"); StrCat(*PathName, name); *path = FileDevicePath(li->DeviceHandle, *PathName); error: FreePool(devpathstr); return efi_status; } // generate_path() EFI_STATUS simple_file_open(EFI_HANDLE image, CHAR16 *name, EFI_FILE **file, UINT64 mode) { EFI_STATUS efi_status; EFI_HANDLE device; EFI_LOADED_IMAGE *li; EFI_DEVICE_PATH *loadpath = NULL; CHAR16 *PathName = NULL; efi_status = uefi_call_wrapper(BS->HandleProtocol, 3, image, &IMAGE_PROTOCOL, (VOID**) &li); if (efi_status != EFI_SUCCESS) return simple_file_open_by_handle(image, name, file, mode); efi_status = generate_path(name, li, &loadpath, &PathName); if (efi_status != EFI_SUCCESS) { Print(L"Unable to generate load path for %s\n", name); return efi_status; } device = li->DeviceHandle; efi_status = simple_file_open_by_handle(device, PathName, file, mode); FreePool(PathName); FreePool(loadpath); return efi_status; } EFI_STATUS simple_file_read_all(EFI_FILE *file, UINTN *size, void **buffer) { EFI_STATUS efi_status; EFI_FILE_INFO *fi; char buf[1024]; *size = sizeof(buf); fi = (void *)buf; efi_status = uefi_call_wrapper(file->GetInfo, 4, file, &FILE_INFO, size, fi); if (efi_status != EFI_SUCCESS) { Print(L"Failed to get file info\n"); return efi_status; } *size = fi->FileSize; *buffer = AllocatePool(*size); if (!*buffer) { Print(L"Failed to allocate buffer of size %d\n", *size); return EFI_OUT_OF_RESOURCES; } efi_status = uefi_call_wrapper(file->Read, 3, file, size, *buffer); return efi_status; } void simple_file_close(EFI_FILE *file) { uefi_call_wrapper(file->Close, 1, file); } refind-0.11.4/mok/simple_file.h0000664000175000017500000000047012626644770016560 0ustar rodsmithrodsmithEFI_STATUS simple_file_open (EFI_HANDLE image, CHAR16 *name, EFI_FILE **file, UINT64 mode); EFI_STATUS simple_file_open_by_handle(EFI_HANDLE device, CHAR16 *name, EFI_FILE **file, UINT64 mode); EFI_STATUS simple_file_read_all(EFI_FILE *file, UINTN *size, void **buffer); void simple_file_close(EFI_FILE *file); refind-0.11.4/mok/mok.h0000664000175000017500000000257412626644770015065 0ustar rodsmithrodsmith#include "../include/PeImage.h" #include "../include/PeImage2.h" #define SHIM_LOCK_GUID \ { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} } #if defined (EFIX64) typedef struct _SHIM_LOCK { EFI_STATUS __attribute__((sysv_abi)) (*shim_verify) (VOID *buffer, UINT32 size); EFI_STATUS __attribute__((sysv_abi)) (*generate_hash) (char *data, int datasize, GNUEFI_PE_COFF_LOADER_IMAGE_CONTEXT *context, UINT8 *sha256hash, UINT8 *sha1hash); EFI_STATUS __attribute__((sysv_abi)) (*read_header) (void *data, unsigned int datasize, GNUEFI_PE_COFF_LOADER_IMAGE_CONTEXT *context); } SHIM_LOCK; #else typedef struct _SHIM_LOCK { EFI_STATUS (*shim_verify) (VOID *buffer, UINT32 size); EFI_STATUS (*generate_hash) (char *data, int datasize, GNUEFI_PE_COFF_LOADER_IMAGE_CONTEXT *context, UINT8 *sha256hash, UINT8 *sha1hash); EFI_STATUS (*read_header) (void *data, unsigned int datasize, GNUEFI_PE_COFF_LOADER_IMAGE_CONTEXT *context); } SHIM_LOCK; #endif //EFI_STATUS get_variable (CHAR16 *name, EFI_GUID guid, UINT32 *attributes, UINTN *size, VOID **buffer); BOOLEAN ShimLoaded(void); BOOLEAN ShimValidate (VOID *data, UINT32 size); BOOLEAN secure_mode (VOID); refind-0.11.4/mok/Make.tiano0000664000175000017500000000107312631122035016005 0ustar rodsmithrodsmith# # mok/Make.tiano # Build control file for Secure Boot components of rEFInd, using TianoCore EDK2 # # This program is licensed under the terms of the GNU GPL, version 3, # or (at your option) any later version. # You should have received a copy of the GNU General Public License # along with this program. If not, see . include ../Make.common SOURCE_NAMES = guid mok security_policy simple_file OBJS = $(SOURCE_NAMES:=.obj) all: $(AR_TARGET) $(AR_TARGET): $(OBJS) $(AR) -cr $(AR_TARGET).lib $(OBJS) clean: make clean refind-0.11.4/debian/0000775000175000017500000000000013372347233014543 5ustar rodsmithrodsmithrefind-0.11.4/debian/compat0000644000175000017500000000000212626644360015741 0ustar rodsmithrodsmith9 refind-0.11.4/debian/rules0000775000175000017500000000163012627157435015630 0ustar rodsmithrodsmith#!/usr/bin/make -f export DH_VERBOSE := 1 DEB_HOST_ARCH_CPU := $(shell dpkg-architecture -qDEB_HOST_ARCH_CPU 2>/dev/null) ifeq (amd64, $(DEB_HOST_ARCH_CPU)) EFI_ARCH := x64 else ifeq (i386, $(DEB_HOST_ARCH_CPU)) EFI_ARCH := ia32 else ifeq (arm64, $(DEB_HOST_ARCH_CPU)) EFI_ARCH := aa64 else $(warning EFI architecture for $(DEB_HOST_ARCH_CPU) is unknown) EFI_ARCH := $(DEB_HOST_ARCH_CPU) endif endif endif %: dh $@ override_dh_auto_clean: dh_auto_clean rm -rf drivers_*/ override_dh_auto_build: $(MAKE) gnuefi $(MAKE) fs_gnuefi override_dh_auto_install: # "make install" actually runs "efi-install" for the current system, so let's not do that :) override_dh_install: dh_install mkdir -p debian/refind/usr/share/refind/refind/tools_$(EFI_ARCH) cp gptsync/gptsync_$(EFI_ARCH).efi debian/refind/usr/share/refind/refind/tools_$(EFI_ARCH)/ override_dh_installchangelogs: dh_installchangelogs NEWS.txt refind-0.11.4/debian/po/0000775000175000017500000000000013325161537015160 5ustar rodsmithrodsmithrefind-0.11.4/debian/po/pt_BR.po0000664000175000017500000000347313010637654016534 0ustar rodsmithrodsmith# Debconf translations for refind. # Copyright (C) 2016 THE refind'S COPYRIGHT HOLDER # This file is distributed under the same license as the refind package. # Adriano Rafael Gomes , 2016. # msgid "" msgstr "" "Project-Id-Version: refind\n" "Report-Msgid-Bugs-To: refind@packages.debian.org\n" "POT-Creation-Date: 2015-12-12 18:35-0500\n" "PO-Revision-Date: 2016-07-23 19:51-0300\n" "Last-Translator: Adriano Rafael Gomes \n" "Language-Team: Brazilian Portuguese \n" "Language: pt_BR\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #. Type: boolean #. Description #: ../templates:1001 msgid "Automatically install rEFInd to the ESP?" msgstr "Instalar automaticamente o rEFInd na ESP?" #. Type: boolean #. Description #: ../templates:1001 msgid "" "It is necessary to install rEFInd to the EFI System Partition (ESP) for it " "to control the boot process." msgstr "" "É necessário instalar o rEFInd na Partição de Sistema EFI (ESP) para ele " "controlar o processo de inicialização." #. Type: boolean #. Description #: ../templates:1001 msgid "" "Not installing the new rEFInd binary on the ESP may leave the system in an " "unbootable state. Alternatives to automatically installing rEFInd include " "running /usr/sbin/refind-install by hand or installing the rEFInd binaries " "manually by copying them from subdirectories of /usr/share/refind-{version}." msgstr "" "Não instalar o novo binário do rEFInd na ESP pode deixar o sistema em um " "estado não inicializável. Alternativas a instalar automaticamente o rEFInd " "incluem executar /usr/sbin/refind-install manualmente ou instalar os " "binários do rEFInd manualmente copiando-os de subdiretórios de /usr/share/" "refind-{version}." refind-0.11.4/debian/po/es.po0000664000175000017500000000513513325160756016135 0ustar rodsmithrodsmith# refind po-debconf translation to Spanish. # Copyright (C) 2018 Software in the Public Interest # This file is distributed under the same license as the refind package. # # - Initial translation # Jonathan Bustillos , 2018. # # Traductores, si no conocen el formato PO, merece la pena leer la # documentación de gettext, especialmente las secciones dedicadas a este # formato, por ejemplo ejecutando: # info -n '(gettext)PO Files' # info -n '(gettext)Header Entry' # # Equipo de traducción al español, por favor lean antes de traducir # los siguientes documentos: # # - El proyecto de traducción de Debian al español # http://www.debian.org/intl/spanish/ # especialmente las notas y normas de traducción en # http://www.debian.org/intl/spanish/notas # # - La guía de traducción de po's de debconf: # /usr/share/doc/po-debconf/README-trans # o http://www.debian.org/intl/l10n/po-debconf/README-trans # msgid "" msgstr "" "Project-Id-Version: refind\n" "Report-Msgid-Bugs-To: refind@packages.debian.org\n" "POT-Creation-Date: 2015-12-12 18:35-0500\n" "PO-Revision-Date: 2018-05-27 10:17+0200\n" "Last-Translator: Jonathan Bustillos \n" "Language-Team: Debian Spanish \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Gtranslator 2.91.7\n" #. Type: boolean #. Description #: ../templates:1001 msgid "Automatically install rEFInd to the ESP?" msgstr "¿Instalar automáticamente REFInd en el ESP?" #. Type: boolean #. Description #: ../templates:1001 msgid "" "It is necessary to install rEFInd to the EFI System Partition (ESP) for it " "to control the boot process." msgstr "" "Es necesario instalar rEFInd en la partición del sistema EFI (ESP) para que " "controle el proceso de arranque." #. Type: boolean #. Description #: ../templates:1001 msgid "" "Not installing the new rEFInd binary on the ESP may leave the system in an " "unbootable state. Alternatives to automatically installing rEFInd include " "running /usr/sbin/refind-install by hand or installing the rEFInd binaries " "manually by copying them from subdirectories of /usr/share/refind-{version}." msgstr "" "No instalar el nuevo binario de rEFInd en el ESP puede dejar el sistema en " "un estado no arrancable. Alternativas para la instalación automática de " "rEFInd incluyen ejecutar /usr/sbin/refind-install a mano o instalar los " "binarios de rEFInd manualmente copiándolos de los subdirectorios de /usr/" "share/refind-{version}." refind-0.11.4/debian/po/pt.po0000664000175000017500000000351513325161166016145 0ustar rodsmithrodsmith# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # Rui Branco - DebianPT , 2018. msgid "" msgstr "" "Project-Id-Version: refind\n" "Report-Msgid-Bugs-To: refind@packages.debian.org\n" "POT-Creation-Date: 2015-12-12 18:35-0500\n" "PO-Revision-Date: 2018-05-09 19:36+0000\n" "Last-Translator: Rui Branco - DebianPT \n" "Language-Team: Portuguese \n" "Language: pt\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #. Type: boolean #. Description #: ../templates:1001 msgid "Automatically install rEFInd to the ESP?" msgstr "Instalar automaticamente o rEFInd na partição ESP?" #. Type: boolean #. Description #: ../templates:1001 msgid "" "It is necessary to install rEFInd to the EFI System Partition (ESP) for it " "to control the boot process." msgstr "" "É necessário instalar o rEFInd na partição de sistema EFI (ESP) para que o " "mesmo possa controlar o processo de arranque." #. Type: boolean #. Description #: ../templates:1001 msgid "" "Not installing the new rEFInd binary on the ESP may leave the system in an " "unbootable state. Alternatives to automatically installing rEFInd include " "running /usr/sbin/refind-install by hand or installing the rEFInd binaries " "manually by copying them from subdirectories of /usr/share/refind-{version}." msgstr "" "A não instalação do novo binário rEFInd na partição ESP pode deixar o " "sistema num estado de não arranque. Alternativas à instalação automática do " "rEFInd incluem correr o comando /usr/sbin/refind-install manualmente ou " "instalar manualmente os binários rEFInd copiando-os a partir das sub-pastas " "em /usr/share/refind-{version}." refind-0.11.4/debian/po/de.po0000664000175000017500000000361013010622206016072 0ustar rodsmithrodsmith# refind debconf translation # Copyright (C) 2006 Christoph Pfisterer, 2012-2016 Roderick W. Smith. # This file is distributed under the same license as the refind package. # Copyright (C) of this file Chris Leick 2016. # msgid "" msgstr "" "Project-Id-Version: refind 0.10.4-1\n" "Report-Msgid-Bugs-To: refind@packages.debian.org\n" "POT-Creation-Date: 2015-12-12 18:35-0500\n" "PO-Revision-Date: 2016-11-01 10:42+0100\n" "Last-Translator: Chris Leick \n" "Language-Team: de \n" "Language: de\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #. Type: boolean #. Description #: ../templates:1001 msgid "Automatically install rEFInd to the ESP?" msgstr "rEFInd automatisch auf der ESP installieren?" #. Type: boolean #. Description #: ../templates:1001 msgid "" "It is necessary to install rEFInd to the EFI System Partition (ESP) for it " "to control the boot process." msgstr "" "Es ist notwendig, rEFInd auf die EFI-Systempartition (ESP) zu installieren, " "damit es den Systemstart steuern kann." #. Type: boolean #. Description #: ../templates:1001 msgid "" "Not installing the new rEFInd binary on the ESP may leave the system in an " "unbootable state. Alternatives to automatically installing rEFInd include " "running /usr/sbin/refind-install by hand or installing the rEFInd binaries " "manually by copying them from subdirectories of /usr/share/refind-{version}." msgstr "" "Wenn das neue rEFInd-Programm nicht auf der ESP installiert wird, wird das " "System möglicherweise in einem nicht mehr startbaren Zustand verbleiben. " "Alternaitiv zur automatischen Installation können Sie " "/usr/sbin/refind-install von Hand ausführen oder die rEFInd-Programme manuell " "installieren, indem Sie sie manuell aus den Unterverzeichnissen von " "/usr/share/refind-{Version} kopieren." refind-0.11.4/debian/po/POTFILES.in0000664000175000017500000000004412632067216016732 0ustar rodsmithrodsmith[type: gettext/rfc822deb] templates refind-0.11.4/debian/po/templates.pot0000664000175000017500000000237712633127516017713 0ustar rodsmithrodsmith# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: refind\n" "Report-Msgid-Bugs-To: refind@packages.debian.org\n" "POT-Creation-Date: 2015-12-12 18:35-0500\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #. Type: boolean #. Description #: ../templates:1001 msgid "Automatically install rEFInd to the ESP?" msgstr "" #. Type: boolean #. Description #: ../templates:1001 msgid "" "It is necessary to install rEFInd to the EFI System Partition (ESP) for it " "to control the boot process." msgstr "" #. Type: boolean #. Description #: ../templates:1001 msgid "" "Not installing the new rEFInd binary on the ESP may leave the system in an " "unbootable state. Alternatives to automatically installing rEFInd include " "running /usr/sbin/refind-install by hand or installing the rEFInd binaries " "manually by copying them from subdirectories of /usr/share/refind-{version}." msgstr "" refind-0.11.4/debian/po/ru.po0000664000175000017500000000423413325161537016151 0ustar rodsmithrodsmith# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: refind\n" "Report-Msgid-Bugs-To: refind@packages.debian.org\n" "POT-Creation-Date: 2015-12-12 18:35-0500\n" "PO-Revision-Date: 2017-11-30 11:21+0500\n" "Last-Translator: Lev Lamberov \n" "Language-Team: \n" "Language: ru\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 2.0.4\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" #. Type: boolean #. Description #: ../templates:1001 msgid "Automatically install rEFInd to the ESP?" msgstr "Автоматически установить rEFInd в ESP?" #. Type: boolean #. Description #: ../templates:1001 msgid "" "It is necessary to install rEFInd to the EFI System Partition (ESP) for it " "to control the boot process." msgstr "" "Для управления процессом загрузки требуется установить rEFInd в системный " "раздел EFI (ESP)." #. Type: boolean #. Description #: ../templates:1001 msgid "" "Not installing the new rEFInd binary on the ESP may leave the system in an " "unbootable state. Alternatives to automatically installing rEFInd include " "running /usr/sbin/refind-install by hand or installing the rEFInd binaries " "manually by copying them from subdirectories of /usr/share/refind-{version}." msgstr "" "Если новые двоичные файлы rEFInd не будут установлены в раздел ESP, то это " "может привести к невозможности загрузить систему. В качестве альтернатив " "установке rEFInd можно вручную запустить /usr/sbin/refind-install или " "установить двоичные файлы rEFInd самостоятельно путём их копирования из " "подкаталогов /usr/share/refind-{версия}." refind-0.11.4/debian/source/0000775000175000017500000000000012626644360016045 5ustar rodsmithrodsmithrefind-0.11.4/debian/source/format0000664000175000017500000000001412626644360017253 0ustar rodsmithrodsmith3.0 (quilt) refind-0.11.4/debian/gbp.conf0000664000175000017500000000005412626645002016155 0ustar rodsmithrodsmith[DEFAULT] pristine-tar = True merge = False refind-0.11.4/debian/copyright0000664000175000017500000013773613363400634016512 0ustar rodsmithrodsmithFormat: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: rEFInd Upstream-Contact: Roderick W. Smith Source: http://www.rodsbooks.com/refind Files: * Copyright: 2006 Christoph Pfisterer 2012-2018 Roderick W. Smith License: BSD-3-clause and GPL-3+ Files: debian/* Copyright: 2014-2016 Roderick W. Smith 2015 Tianon Gravi License: GPL-3+ Files: */Make* Copyright: 2012-2015 Roderick W. Smith License: GPL-3+ Comment: Except for gptsync/Make.unix and net/Makefile; see below Files: */AutoGen.[ch] Copyright: 2004-2011 Intel Corporation License: BSD-2-clause Comment: Files auto-generated by the TianoCore toolkit. Copyright assignment in this document is based on the assumption that the AutoGen.[ch] files constitute derivative works of the TianoCore toolkit. Files: mkrlconf refind-install Copyright: 2012-2015 Roderick W. Smith License: GPL-3+ Files: refind-mkdefault Copyright: 2016 Roderick W. Smith License: GPL-3+ Files: mountesp Copyright: 2015 Roderick W. Smith License: GPL-3+ Files: mvrefind Copyright: 2013-2015 Roderick W. Smith License: GPL-3+ Files: refind.conf-sample Copyright: 2006-2010 Christoph Pfisterer 2012-2018 Roderick W. Smith License: BSD-3-clause Files: refind.inf Copyright: 2012-2018 Roderick W. Smith License: GPL-3+ Files: refind/* libeg/image.c libeg/screen.c Copyright: 2006-2010 Christoph Pfisterer 2012-2018 Roderick W. Smith License: BSD-3-clause and GPL-3+ Files: refind/icns.c libeg/* Copyright: 2006-2007 Christoph Pfisterer License: BSD-3-clause Files: refind/gpt.[ch] libeg/lodepng_xtra.c libeg/nanojpeg_xtra.c Copyright: 2014-2018 Roderick W. Smith License: GPL-3+ Files: refind/pointer.[ch] Copyright: 2017 CJ Vaughter License: GPL-3+ Files: refind/crc32.[ch] Copyright: 1986 Gary S. Brown License: unrestricted-crc32 You may use this program, or code or tables extracted from it, as desired without restriction. Files: refind/driver_support.[ch] Copyright: 2006-2011 Intel Corporation 2006-2010 Christoph Pfisterer 2012-2016 Roderick W. Smith License: BSD-2-clause and BSD-3-clause and GPL-3+ Files: libeg/efiConsoleControl.h libeg/efiUgaDraw.h Copyright: 2006-2011 Intel Corporation License: BSD-2-clause Files: refind/line_edit.[ch] Copyright: 2012 Harald Hoyer 2012-2013 Kay Sievers License: LGPL-2.1+ Files: EfiLib/* Copyright: 2004-2014 Intel Corp. License: BSD-2-clause Files: EfiLib/Make* Copyright: 2012-2015 Roderick W. Smith License: GPL-3+ Files: libeg/lodepng.[ch] Copyright: 2005-2015 Lode Vandevenne License: zlib Files: libeg/nanojpeg.c Copyright: 2009-2016 Martin J. Fiedler License: Expat Files: mok/* Copyright: 2012 James Bottomley License: LGPL-2.1 Files: mok/mok.[ch] Copyright: 2012 Red Hat, Inc. 2009-2012 Intel Corporation License: BSD-2-clause Files: include/* Copyright: 2006-2010 Intel Corporation License: BSD-2-clause Files: include/syslinux_mbr.h Copyright: 2003-2004 H. Peter Anvin License: Expat Files: include/egemb_* Copyright: 2012-2015 Roderick W. Smith License: LGPL-3+ or CC-BY-SA-3.0 Comment: Header-file transformations of files from "images" directory. Files: include/refit_call_wrapper.h Copyright: 2006 Christoph Pfisterer 2012 Roderick W. Smith License: BSD-3-clause Files: include/tiano_includes.h include/version.h Copyright: 2012 Roderick W. Smith License: GPL-3+ Files: include/RemovableMedia.h Copyright: 2005 Apple Computer, Inc. License: Apple-BSD Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. ("Apple") in consideration of your agreement to the following terms, and your use, installation, modification or redistribution of this Apple software constitutes acceptance of these terms. If you do not agree with these terms, please do not use, install, modify or redistribute this Apple software. . In consideration of your agreement to abide by the following terms, and subject to these terms, Apple grants you a personal, non-exclusive license, under Apple's copyrights in this original Apple software (the "Apple Software"), to use, reproduce, modify and redistribute the Apple Software, with or without modifications, in source and/or binary forms; provided that if you redistribute the Apple Software in its entirety and without modifications, you must retain this notice and the following text and disclaimers in all such redistributions of the Apple Software. Neither the name, trademarks, service marks or logos of Apple Computer, Inc. may be used to endorse or promote products derived from the Apple Software without specific prior written permission from Apple. Except as expressly stated in this notice, no other rights or licenses, express or implied, are granted by Apple herein, including but not limited to any patent rights that may be infringed by your derivative works or by other works in which the Apple Software may be incorporated. . The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. . IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Files: gptsync/* gptsync/Make.unix Copyright: 2006-2007 Christoph Pfisterer License: BSD-3-clause Files: gptsync/gptsync.c Copyright: 2006 Christoph Pfisterer 2013 Roderick W. Smith License: BSD-3-clause Files: gptsync/gptsync.8 Copyright: 2006 Christoph Pfisterer & Junichi Uekawa License: BSD-3-clause Files: filesystems/fsw_base.h filesystems/fsw_core.[ch] filesystems/fsw_efi.[ch] filesystems/fsw_efi_lib.c filesystems/fsw_efi_base.h filesystems/fsw_lib.c filesystems/fsw_strfunc.h filesystems/mk_fsw_strfunc.py filesystems/design.dox Copyright: 2006 Christoph Pfisterer License: BSD-3-clause Files: filesystems/fsw_efi_edk2_base.h Copyright: 2012 Stefan Agner License: BSD-3-clause Files: filesystems/fsw_ext2.[ch] filesystems/fsw_ext2_disk.h filesystems/fsw_reiserfs.[ch] filesystems/fsw_reiserfs_disk.h Copyright: 2006 Christoph Pfisterer License: GPL-2+ Files: filesystems/fsw_ext4.c Copyright: 2012 Stefan Agner License: GPL-2+ Files: filesystems/fsw_ext4.h Copyright: 2006 Christoph Pfisterer 2012 Stefan Agner License: GPL-2+ Files: filesystems/fsw_ext4_disk.h Copyright: 2006 Christoph Pfisterer 2012 Stefan Agner 1991-2012 by various Linux kernel contributors License: GPL-2+ Files: filesystems/fsw_ntfs.c Copyright: Samuel Liao License: GPL-2+ Files: filesystems/crc32c.c filesystems/gzio.c Copyright: 2008 Free Software Foundation, Inc. License: GPL-3+ Files: filesystems/fsw_btrfs.c Copyright: 2010 Free Software Foundation, Inc. 2013 Tencent, Inc. (Samuel Liao) License: GPL-3+ Files: filesystems/fsw_btrfs_zstd.h Copyright: 2016 Facebook, Inc. License: GPL-2 Files: filesystems/minilzo.[ch] Copyright: 1996-2011 Markus Franz Xaver Johannes Oberhumer License: GPL-2+ Files: filesystems/scandisk.c Copyright: 2013 Tencent, Inc. (Samuel Liao) License: GPL-3+ Files: filesystems/fsw_hfs.[ch] filesystems/fsw_format.h Copyright: 2010 Oracle Corporation License: GPL-2 Files: filesystems/fsw_iso9660.[ch] Copyright: 2006 Christoph Pfisterer 2010 Oracle Corporation License: BSD-3-clause and GPL-2 Files: filesystems/lzoconf.h Copyright: 1996-2011 Markus Franz Xaver Johannes Oberhumer License: GPL-2+ Files: filesystems/edk2/ComponentName.h filesystems/edk2/DriverBinding.h Copyright: 2004-2011 Intel Corporation License: BSD-2-clause Files: filesystems/test/* Copyright: 2006 Christoph Pfisterer License: BSD-3-clause Files: filesystems/test/lslr.c Copyright: 2006 Christoph Pfisterer 2012 Stefan Agner License: BSD-3-clause Files: net/* Copyright: 2009 Michael Brown License: GPL-2+ Files: icons/arrow_left.png icons/arrow_right.png icons/boot_linux.png icons/func_about.png icons/func_exit.png icons/func_firmware.png icons/func_reset.png icons/func_shutdown.png icons/os_arch.png icons/os_centos.png icons/os_chakra.png icons/os_chrome.png icons/os_crunchbang.png icons/os_fedora.png icons/os_frugalware.png icons/os_gentoo.png icons/os_hwtest.png icons/os_kubuntu.png icons/os_linux.png icons/os_linuxmint.png icons/os_lubuntu.png icons/os_mageia.png icons/os_mandriva.png icons/os_network.png icons/os_opensuse.png icons/os_slackware.png icons/os_suse.png icons/os_ubuntu.png icons/os_unknown.png icons/os_win8.png icons/os_xubuntu.png icons/tool_mok_tool.png icons/tool_netboot.png icons/tool_shell.png icons/tool_windows_rescue.png icons/vol_external.png icons/vol_internal.png icons/vol_net.png icons/vol_optical.png Copyright: 2013 by Alessandro Roncone (aka alecive on DeviantArt) License: CC-BY-SA-3.0 Comment: tool_windows_rescue is combination of os_win8.png with tool_rescue.png. Files: icons/boot_win.png icons/func_csr_rotate.png icons/mouse.png icons/os_clover.png icons/os_freebsd.png icons/os_gummiboot.png icons/os_haiku.png icons/os_legacy.png icons/os_mac.png icons/os_netbsd.png icons/os_redhat.png icons/os_refind.png icons/os_refit.png icons/os_systemd.png icons/os_win.png icons/tool_apple_rescue.png icons/tool_fwupdate.png icons/tool_memtest.png icons/tool_rescue.png icons/transparent.png icons/README Copyright: 2015-2017 by Roderick W. Smith License: LGPL-3+ or CC-BY-SA-3.0 Files: icons/os_trusty.png icons/os_xenial.png icons/os_zesty.png icons/svg/os_xenial.png icons/svg/os_zesty.png Copyright: 2014-2017 by Canonical Ltd. License: CC-BY-SA-3.0 Files: icons/os_artful.png icons/os_bionic.png Copyright: 2017-2018 by Canonical Ltd. License: CC-BY-SA-3.0 Files: icons/os_debian.png Copyright: 1999 by Debian Project License: LGPL-3+ or CC-BY-SA-3.0 Files: icons/os_devuan.png Copyright: 2017 by Dyne.org foundation License: CC-BY-SA-4.0 Files: icons/os_elementary.png Copyright: 2008 Dan Rabbit License: GPL-2 Files: icons/os_void.png License: public-domain Claimed as public domain by source (https://commons.wikimedia.org/wiki/File:Void_Linux_logo.svg) Files: icons/svg/* Copyright: 2015 by Roderick W. Smith License: LGPL-3+ or CC-BY-SA-3.0 Files: icons/svg/os_debian.svg Copyright: 1999 by Debian Project License: LGPL-3+ or CC-BY-SA-3.0 Files: icons/svg/os_devuan.svg Copyright: 2017 by Dyne.org foundation License: CC-BY-SA-4.0 Files: icons/svg/os_elementary.svg Copyright: 2008 Dan Rabbit License: GPL-2 Files: banners/* Copyright: 2015 Roderick W. Smith License: LGPL-3+ or CC-BY-SA-3.0 Files: images/arrow_left.png images/arrow_right.png images/back-selected-big.png images/back-selected-small.png images/refind-banner* Copyright: 2015 Roderick W. Smith License: LGPL-3+ or CC-BY-SA-3.0 Comment: Some of these are incorporated into the rEFInd binary via header files in the "include" directory. Files: images/*.py images/txt.pl Copyright: 2006-2010 Christoph Pfisterer License: BSD-3-clause Files: fonts/liberation* libeg/egemb_font.h Copyright: 2010 Google & 2012 Red Hat License: OFL-1.1 Comment: PNG bitmaps derived from TrueType font; liberation-mono-regular-14.png embedded in rEFInd binary via the libeg/egemb_font.h file Files: fonts/mkfont.sh Copyright: 2013 Roderick W. Smith License: GPL-3+ Files: fonts/nimbus* Copyright: 1984, 1996, 2009 URW Studio License: GPL-2 Comment: PNG bitmap derived from PostScript font Files: fonts/ubuntu* Copyright: 2010,2011 Canonical Ltd. License: UFL-1 Comment: PNG bitmap derived from TrueType font Files: docs/* */README* Copyright: 2012-2017 Roderick W. Smith License: GFDL-1.3 License: BSD-2-clause Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: . 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. . THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. . The views and conclusions contained in the software and documentation are those of the authors and should not be interpreted as representing official policies, either expressed or implied, of . License: BSD-3-clause Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. . THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. License: CC-BY-SA-3.0 THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. . BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS. . 1. Definitions . a. "Adaptation" means a work based upon the Work, or upon the Work and other pre-existing works, such as a translation, adaptation, derivative work, arrangement of music or other alterations of a literary or artistic work, or phonogram or performance and includes cinematographic adaptations or any other form in which the Work may be recast, transformed, or adapted including in any form recognizably derived from the original, except that a work that constitutes a Collection will not be considered an Adaptation for the purpose of this License. For the avoidance of doubt, where the Work is a musical work, performance or phonogram, the synchronization of the Work in timed-relation with a moving image ("synching") will be considered an Adaptation for the purpose of this License. b. "Collection" means a collection of literary or artistic works, such as encyclopedias and anthologies, or performances, phonograms or broadcasts, or other works or subject matter other than works listed in Section 1(f) below, which, by reason of the selection and arrangement of their contents, constitute intellectual creations, in which the Work is included in its entirety in unmodified form along with one or more other contributions, each constituting separate and independent works in themselves, which together are assembled into a collective whole. A work that constitutes a Collection will not be considered an Adaptation (as defined below) for the purposes of this License. c. "Creative Commons Compatible License" means a license that is listed at https://creativecommons.org/compatiblelicenses that has been approved by Creative Commons as being essentially equivalent to this License, including, at a minimum, because that license: (i) contains terms that have the same purpose, meaning and effect as the License Elements of this License; and, (ii) explicitly permits the relicensing of adaptations of works made available under that license under this License or a Creative Commons jurisdiction license with the same License Elements as this License. d. "Distribute" means to make available to the public the original and copies of the Work or Adaptation, as appropriate, through sale or other transfer of ownership. e. "License Elements" means the following high-level license attributes as selected by Licensor and indicated in the title of this License: Attribution, ShareAlike. f. "Licensor" means the individual, individuals, entity or entities that offer(s) the Work under the terms of this License. g. "Original Author" means, in the case of a literary or artistic work, the individual, individuals, entity or entities who created the Work or if no individual or entity can be identified, the publisher; and in addition (i) in the case of a performance the actors, singers, musicians, dancers, and other persons who act, sing, deliver, declaim, play in, interpret or otherwise perform literary or artistic works or expressions of folklore; (ii) in the case of a phonogram the producer being the person or legal entity who first fixes the sounds of a performance or other sounds; and, (iii) in the case of broadcasts, the organization that transmits the broadcast. h. "Work" means the literary and/or artistic work offered under the terms of this License including without limitation any production in the literary, scientific and artistic domain, whatever may be the mode or form of its expression including digital form, such as a book, pamphlet and other writing; a lecture, address, sermon or other work of the same nature; a dramatic or dramatico-musical work; a choreographic work or entertainment in dumb show; a musical composition with or without words; a cinematographic work to which are assimilated works expressed by a process analogous to cinematography; a work of drawing, painting, architecture, sculpture, engraving or lithography; a photographic work to which are assimilated works expressed by a process analogous to photography; a work of applied art; an illustration, map, plan, sketch or three-dimensional work relative to geography, topography, architecture or science; a performance; a broadcast; a phonogram; a compilation of data to the extent it is protected as a copyrightable work; or a work performed by a variety or circus performer to the extent it is not otherwise considered a literary or artistic work. i. "You" means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation. j. "Publicly Perform" means to perform public recitations of the Work and to communicate to the public those public recitations, by any means or process, including by wire or wireless means or public digital performances; to make available to the public Works in such a way that members of the public may access these Works from a place and at a place individually chosen by them; to perform the Work to the public by any means or process and the communication to the public of the performances of the Work, including by public digital performance; to broadcast and rebroadcast the Work by any means including signs, sounds or images. k. "Reproduce" means to make copies of the Work by any means including without limitation by sound or visual recordings and the right of fixation and reproducing fixations of the Work, including storage of a protected performance or phonogram in digital form or other electronic medium. . 2. Fair Dealing Rights. Nothing in this License is intended to reduce, limit, or restrict any uses free from copyright or rights arising from limitations or exceptions that are provided for in connection with the copyright protection under copyright law or other applicable laws. . 3. License Grant. Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below: . a. to Reproduce the Work, to incorporate the Work into one or more Collections, and to Reproduce the Work as incorporated in the Collections; b. to create and Reproduce Adaptations provided that any such Adaptation, including any translation in any medium, takes reasonable steps to clearly label, demarcate or otherwise identify that changes were made to the original Work. For example, a translation could be marked "The original work was translated from English to Spanish," or a modification could indicate "The original work has been modified."; c. to Distribute and Publicly Perform the Work including as incorporated in Collections; and, d. to Distribute and Publicly Perform Adaptations. e. For the avoidance of doubt: . i. Non-waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme cannot be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; ii. Waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme can be waived, the Licensor waives the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; and, iii. Voluntary License Schemes. The Licensor waives the right to collect royalties, whether individually or, in the event that the Licensor is a member of a collecting society that administers voluntary licensing schemes, via that society, from any exercise by You of the rights granted under this License. . The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats. Subject to Section 8(f), all rights not expressly granted by Licensor are hereby reserved. . 4. Restrictions. The license granted in Section 3 above is expressly made subject to and limited by the following restrictions: . a. You may Distribute or Publicly Perform the Work only under the terms of this License. You must include a copy of, or the Uniform Resource Identifier (URI) for, this License with every copy of the Work You Distribute or Publicly Perform. You may not offer or impose any terms on the Work that restrict the terms of this License or the ability of the recipient of the Work to exercise the rights granted to that recipient under the terms of the License. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties with every copy of the Work You Distribute or Publicly Perform. When You Distribute or Publicly Perform the Work, You may not impose any effective technological measures on the Work that restrict the ability of a recipient of the Work from You to exercise the rights granted to that recipient under the terms of the License. This Section 4(a) applies to the Work as incorporated in a Collection, but this does not require the Collection apart from the Work itself to be made subject to the terms of this License. If You create a Collection, upon notice from any Licensor You must, to the extent practicable, remove from the Collection any credit as required by Section 4(c), as requested. If You create an Adaptation, upon notice from any Licensor You must, to the extent practicable, remove from the Adaptation any credit as required by Section 4(c), as requested. b. You may Distribute or Publicly Perform an Adaptation only under the terms of: (i) this License; (ii) a later version of this License with the same License Elements as this License; (iii) a Creative Commons jurisdiction license (either this or a later license version) that contains the same License Elements as this License (e.g., Attribution-ShareAlike 3.0 US)); (iv) a Creative Commons Compatible License. If you license the Adaptation under one of the licenses mentioned in (iv), you must comply with the terms of that license. If you license the Adaptation under the terms of any of the licenses mentioned in (i), (ii) or (iii) (the "Applicable License"), you must comply with the terms of the Applicable License generally and the following provisions: (I) You must include a copy of, or the URI for, the Applicable License with every copy of each Adaptation You Distribute or Publicly Perform; (II) You may not offer or impose any terms on the Adaptation that restrict the terms of the Applicable License or the ability of the recipient of the Adaptation to exercise the rights granted to that recipient under the terms of the Applicable License; (III) You must keep intact all notices that refer to the Applicable License and to the disclaimer of warranties with every copy of the Work as included in the Adaptation You Distribute or Publicly Perform; (IV) when You Distribute or Publicly Perform the Adaptation, You may not impose any effective technological measures on the Adaptation that restrict the ability of a recipient of the Adaptation from You to exercise the rights granted to that recipient under the terms of the Applicable License. This Section 4(b) applies to the Adaptation as incorporated in a Collection, but this does not require the Collection apart from the Adaptation itself to be made subject to the terms of the Applicable License. c. If You Distribute, or Publicly Perform the Work or any Adaptations or Collections, You must, unless a request has been made pursuant to Section 4(a), keep intact all copyright notices for the Work and provide, reasonable to the medium or means You are utilizing: (i) the name of the Original Author (or pseudonym, if applicable) if supplied, and/or if the Original Author and/or Licensor designate another party or parties (e.g., a sponsor institute, publishing entity, journal) for attribution ("Attribution Parties") in Licensor's copyright notice, terms of service or by other reasonable means, the name of such party or parties; (ii) the title of the Work if supplied; (iii) to the extent reasonably practicable, the URI, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work; and (iv) , consistent with Ssection 3(b), in the case of an Adaptation, a credit identifying the use of the Work in the Adaptation (e.g., "French translation of the Work by Original Author," or "Screenplay based on original Work by Original Author"). The credit required by this Section 4(c) may be implemented in any reasonable manner; provided, however, that in the case of a Adaptation or Collection, at a minimum such credit will appear, if a credit for all contributing authors of the Adaptation or Collection appears, then as part of these credits and in a manner at least as prominent as the credits for the other contributing authors. For the avoidance of doubt, You may only use the credit required by this Section for the purpose of attribution in the manner set out above and, by exercising Your rights under this License, You may not implicitly or explicitly assert or imply any connection with, sponsorship or endorsement by the Original Author, Licensor and/or Attribution Parties, as appropriate, of You or Your use of the Work, without the separate, express prior written permission of the Original Author, Licensor and/or Attribution Parties. d. Except as otherwise agreed in writing by the Licensor or as may be otherwise permitted by applicable law, if You Reproduce, Distribute or Publicly Perform the Work either by itself or as part of any Adaptations or Collections, You must not distort, mutilate, modify or take other derogatory action in relation to the Work which would be prejudicial to the Original Author's honor or reputation. Licensor agrees that in those jurisdictions (e.g. Japan), in which any exercise of the right granted in Section 3(b) of this License (the right to make Adaptations) would be deemed to be a distortion, mutilation, modification or other derogatory action prejudicial to the Original Author's honor and reputation, the Licensor will waive or not assert, as appropriate, this Section, to the fullest extent permitted by the applicable national law, to enable You to reasonably exercise Your right under Section 3(b) of this License (right to make Adaptations) but not otherwise. . 5. Representations, Warranties and Disclaimer . UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU. . 6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. . 7. Termination . a. This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Adaptations or Collections from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License. b. Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above. . 8. Miscellaneous . a. Each time You Distribute or Publicly Perform the Work or a Collection, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License. b. Each time You Distribute or Publicly Perform an Adaptation, Licensor offers to the recipient a license to the original Work on the same terms and conditions as the license granted to You under this License. c. If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. d. No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent. e. This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You. f. The rights granted under, and the subject matter referenced, in this License were drafted utilizing the terminology of the Berne Convention for the Protection of Literary and Artistic Works (as amended on September 28, 1979), the Rome Convention of 1961, the WIPO Copyright Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 and the Universal Copyright Convention (as revised on July 24, 1971). These rights and subject matter take effect in the relevant jurisdiction in which the License terms are sought to be enforced according to the corresponding provisions of the implementation of those treaty provisions in the applicable national law. If the standard suite of rights granted under applicable copyright law includes additional rights not granted under this License, such additional rights are deemed to be included in the License; this License is not intended to restrict the license of any rights under applicable law. License: Expat Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: . The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. . THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. License: GFDL-1.3 On Debian systems, the complete text of the GNU Free Documentation License Version 1.3 can be found in the file `/usr/share/common-licenses/GFDL-1.3'. License: GPL-2 and GPL-2+ On Debian systems, the complete text of the GNU General Public License Version 2 can be found in the file `/usr/share/common-licenses/GPL-2'. License: GPL-3+ On Debian systems, the complete text of the GNU General Public License Version 3 can be found in the file `/usr/share/common-licenses/GPL-3'. License: LGPL-2.1 and LGPL-2.1+ On Debian systems, the complete text of the GNU Lesser General Public License Version 2.1 can be found in the file `/usr/share/common-licenses/LGPL-2.1'. License: LGPL-3+ On Debian systems, the complete text of the GNU Lesser General Public License Version 3 can be found in the file `/usr/share/common-licenses/LGPL-3'. License: OFL-1.1 Copyright (c) , (), with Reserved Font Name . Copyright (c) , (), with Reserved Font Name . Copyright (c) , (). . This Font Software is licensed under the SIL Open Font License, Version 1.1. This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL . . ----------------------------------------------------------- SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ----------------------------------------------------------- . PREAMBLE The goals of the Open Font License (OFL) are to stimulate worldwide development of collaborative font projects, to support the font creation efforts of academic and linguistic communities, and to provide a free and open framework in which fonts may be shared and improved in partnership with others. . The OFL allows the licensed fonts to be used, studied, modified and redistributed freely as long as they are not sold by themselves. The fonts, including any derivative works, can be bundled, embedded, redistributed and/or sold with any software provided that any reserved names are not used by derivative works. The fonts and derivatives, however, cannot be released under any other type of license. The requirement for fonts to remain under this license does not apply to any document created using the fonts or their derivatives. . DEFINITIONS "Font Software" refers to the set of files released by the Copyright Holder(s) under this license and clearly marked as such. This may include source files, build scripts and documentation. . "Reserved Font Name" refers to any names specified as such after the copyright statement(s). . "Original Version" refers to the collection of Font Software components as distributed by the Copyright Holder(s). . "Modified Version" refers to any derivative made by adding to, deleting, or substituting -- in part or in whole -- any of the components of the Original Version, by changing formats or by porting the Font Software to a new environment. . "Author" refers to any designer, engineer, programmer, technical writer or other person who contributed to the Font Software. . PERMISSION & CONDITIONS Permission is hereby granted, free of charge, to any person obtaining a copy of the Font Software, to use, study, copy, merge, embed, modify, redistribute, and sell modified and unmodified copies of the Font Software, subject to the following conditions: . 1) Neither the Font Software nor any of its individual components, in Original or Modified Versions, may be sold by itself. . 2) Original or Modified Versions of the Font Software may be bundled, redistributed and/or sold with any software, provided that each copy contains the above copyright notice and this license. These can be included either as stand-alone text files, human-readable headers or in the appropriate machine-readable metadata fields within text or binary files as long as those fields can be easily viewed by the user. . 3) No Modified Version of the Font Software may use the Reserved Font Name(s) unless explicit written permission is granted by the corresponding Copyright Holder. This restriction only applies to the primary font name as presented to the users. . 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font Software shall not be used to promote, endorse or advertise any Modified Version, except to acknowledge the contribution(s) of the Copyright Holder(s) and the Author(s) or with their explicit written permission. . 5) The Font Software, modified or unmodified, in part or in whole, must be distributed entirely under this license, and must not be distributed under any other license. The requirement for fonts to remain under this license does not apply to any document created using the Font Software. . TERMINATION This license becomes null and void if any of the above conditions are not met. . DISCLAIMER THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. License: UFL-1 ------------------------------- UBUNTU FONT LICENCE Version 1.0 ------------------------------- . PREAMBLE This licence allows the licensed fonts to be used, studied, modified and redistributed freely. The fonts, including any derivative works, can be bundled, embedded, and redistributed provided the terms of this licence are met. The fonts and derivatives, however, cannot be released under any other licence. The requirement for fonts to remain under this licence does not require any document created using the fonts or their derivatives to be published under this licence, as long as the primary purpose of the document is not to be a vehicle for the distribution of the fonts. . DEFINITIONS "Font Software" refers to the set of files released by the Copyright Holder(s) under this licence and clearly marked as such. This may include source files, build scripts and documentation. . "Original Version" refers to the collection of Font Software components as received under this licence. . "Modified Version" refers to any derivative made by adding to, deleting, or substituting -- in part or in whole -- any of the components of the Original Version, by changing formats or by porting the Font Software to a new environment. . "Copyright Holder(s)" refers to all individuals and companies who have a copyright ownership of the Font Software. . "Substantially Changed" refers to Modified Versions which can be easily identified as dissimilar to the Font Software by users of the Font Software comparing the Original Version with the Modified Version. . To "Propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification and with or without charging a redistribution fee), making available to the public, and in some countries other activities as well. . PERMISSION & CONDITIONS This licence does not grant any rights under trademark law and all such rights are reserved. . Permission is hereby granted, free of charge, to any person obtaining a copy of the Font Software, to propagate the Font Software, subject to the below conditions: . 1) Each copy of the Font Software must contain the above copyright notice and this licence. These can be included either as stand-alone text files, human-readable headers or in the appropriate machine- readable metadata fields within text or binary files as long as those fields can be easily viewed by the user. . 2) The font name complies with the following: (a) The Original Version must retain its name, unmodified. (b) Modified Versions which are Substantially Changed must be renamed to avoid use of the name of the Original Version or similar names entirely. (c) Modified Versions which are not Substantially Changed must be renamed to both (i) retain the name of the Original Version and (ii) add additional naming elements to distinguish the Modified Version from the Original Version. The name of such Modified Versions must be the name of the Original Version, with "derivative X" where X represents the name of the new work, appended to that name. . 3) The name(s) of the Copyright Holder(s) and any contributor to the Font Software shall not be used to promote, endorse or advertise any Modified Version, except (i) as required by this licence, (ii) to acknowledge the contribution(s) of the Copyright Holder(s) or (iii) with their explicit written permission. . 4) The Font Software, modified or unmodified, in part or in whole, must be distributed entirely under this licence, and must not be distributed under any other licence. The requirement for fonts to remain under this licence does not affect any document created using the Font Software, except any version of the Font Software extracted from a document created using the Font Software may only be distributed under this licence. . TERMINATION This licence becomes null and void if any of the above conditions are not met. . DISCLAIMER THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. License: zlib This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. . Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: . 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. . 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. . 3. This notice may not be removed or altered from any source distribution. refind-0.11.4/debian/refind.docs0000664000175000017500000000005712626645002016662 0ustar rodsmithrodsmithCREDITS.txt README.txt docs/Styles docs/refind refind-0.11.4/debian/refind.links0000664000175000017500000000007012626645002017045 0ustar rodsmithrodsmithusr/share/refind/refind-install usr/sbin/refind-install refind-0.11.4/debian/refind.doc-base0000664000175000017500000000033012627715103017402 0ustar rodsmithrodsmithDocument: refind Title: The rEFInd Boot Manager Manual Author: Roderick W. Smith Section: System/Administration Format: HTML Index: /usr/share/doc/refind/refind/index.html Files: /usr/share/doc/refind/refind/*.html refind-0.11.4/debian/config0000664000175000017500000000015712632064131015725 0ustar rodsmithrodsmith#!/bin/sh set -e . /usr/share/debconf/confmodule db_input high refind/install_to_esp || true db_go || true refind-0.11.4/debian/templates0000664000175000017500000000102112632072210016442 0ustar rodsmithrodsmithTemplate: refind/install_to_esp Type: boolean Default: true _Description: Automatically install rEFInd to the ESP? It is necessary to install rEFInd to the EFI System Partition (ESP) for it to control the boot process. . Not installing the new rEFInd binary on the ESP may leave the system in an unbootable state. Alternatives to automatically installing rEFInd include running /usr/sbin/refind-install by hand or installing the rEFInd binaries manually by copying them from subdirectories of /usr/share/refind-{version}. refind-0.11.4/debian/changelog0000664000175000017500000001057413372347233016424 0ustar rodsmithrodsmithrefind (0.11.4-0ppa1) bionic; urgency=medium * Version bump -- Roderick Smith Mon, 12 Nov 2018 14:03:50 -0500 refind (0.11.3-0ppa1) bionic; urgency=medium * Version bump -- Roderick Smith Sun, 22 Jul 2018 16:05:12 -0400 refind (0.11.2-0ppa1) xenial; urgency=medium * Version bump -- Roderick Smith Sun, 22 Oct 2017 16:37:13 -0400 refind (0.11.1.1-0ppa1) xenial; urgency=medium * Fix to problem with setting volumes in manual boot stanzas -- Roderick Smith Tue, 10 Oct 2017 18:47:43 -0400 refind (0.11.1-0ppa1) xenial; urgency=medium * Version bump -- Roderick Smith Mon, 09 Oct 2017 18:22:58 -0400 refind (0.11.0-0ppa1) xenial; urgency=medium * Version bump -- Roderick Smith Sun, 13 Aug 2017 14:18:20 -0400 refind (0.10.9-0ppa1) xenial; urgency=medium * Version bump -- Roderick Smith Sun, 30 Jul 2017 19:56:25 -0400 refind (0.10.8-0ppa1) xenial; urgency=medium * Version bump -- Roderick Smith Sun, 21 May 2017 13:53:08 -0400 refind (0.10.7-0ppa1) xenial; urgency=medium * Version bump -- Roderick Smith Mon, 17 Apr 2017 22:15:16 -0400 refind (0.10.6-0ppa1) xenial; urgency=medium * Version bump -- Roderick Smith Sun, 16 Apr 2017 14:31:48 -0400 refind (0.10.5-0ppa1) xenial; urgency=medium * Version bump -- Roderick Smith Sat, 04 Mar 2017 18:18:50 -0500 refind (0.10.4.2-0ppa1) xenial; urgency=medium * Version bump -- Roderick Smith Wed, 22 Feb 2017 09:25:33 -0400 refind (0.10.4-0ppa1) xenial; urgency=medium * Version bump -- Roderick Smith Sun, 09 Oct 2016 19:10:59 -0400 refind (0.10.3-0ppa1) wily; urgency=medium * Version bump -- Roderick Smith Sun, 24 Apr 2016 11:51:14 -0400 refind (0.10.2-0ppa1) wily; urgency=medium * Version bump -- Roderick Smith Tue, 26 Jan 2016 21:21:44 -0500 refind (0.10.1-0ppa1) wily; urgency=medium * Version bump -- Roderick Smith Sat, 12 Dec 2015 20:14:57 -0500 refind (0.10.0-0ppa1) trusty; urgency=medium * Version bump -- Roderick Smith Sun, 08 Nov 2015 16:53:35 -0500 refind (0.9.2-0ppa1) trusty; urgency=medium * Version bump -- Roderick Smith Sat, 19 Sep 2015 10:42:58 -0400 refind (0.9.1-0ppa1) trusty; urgency=medium * Version bump -- Roderick Smith Sun, 13 Sep 2015 17:14:29 -0400 refind (0.9.0-0ppa1) trusty; urgency=medium * Version bump -- Roderick Smith Sun, 26 Jul 2015 12:36:11 -0400 refind (0.8.7-0ppa2) trusty; urgency=medium * Fix Debian packaging error affecting IA32 platforms -- Roderick Smith Thu, 19 Mar 2015 20:25:03 -0400 refind (0.8.7-0ppa1) trusty; urgency=medium * Version bump -- Roderick Smith Sun, 01 Mar 2015 18:32:25 -0500 refind (0.8.6-0ppa1) trusty; urgency=medium * Version bump -- Roderick Smith Sun, 08 Feb 2015 09:38:43 -0500 refind (0.8.4-0ppa1) trusty; urgency=medium * Version bump -- Rod Smith Mon, 08 Dec 2014 12:28:56 -0400 refind (0.8.3-0ppa1) trusty; urgency=medium * Version bump -- Rod Smith Sun, 06 Jul 2014 12:28:56 -0400 refind (0.8.2-0ppa3) trusty; urgency=medium * Removed stray debugging code that caused pause during startup -- Rod Smith Sun, 08 Jun 2014 16:48:48 -0400 refind (0.8.2-0ppa2) trusty; urgency=medium * Version bump -- Rod Smith Sun, 08 Jun 2014 12:32:48 -0400 refind (0.8.1-0ppa2) trusty; urgency=medium * Revised Debian package to not use version numbers in /usr/share directory names -- Rod Smith Fri, 16 May 2014 14:57:11 -0400 refind (0.8.0-0ppa1) trusty; urgency=medium * Updated for version 0.8.0 -- Rod Smith Fri, 16 May 2014 09:01:45 -0400 refind (0.7.8-0ppa1) trusty; urgency=low [ Roderick W. Smith ] * Initial release. (Closes: #1136112) -- Rod Smith Sun, 9 Mar 2014 07:59:50 -0500 refind-0.11.4/debian/control0000664000175000017500000000252413140126361016137 0ustar rodsmithrodsmithSource: refind Maintainer: Rod Smith Section: admin Priority: optional Standards-Version: 3.9.6 Build-Depends: debhelper (>= 9), gnu-efi Homepage: http://www.rodsbooks.com/refind Vcs-Browser: https://anonscm.debian.org/cgit/collab-maint/refind.git Vcs-Git: git://anonscm.debian.org/collab-maint/refind.git Package: refind Architecture: amd64 i386 arm64 Depends: debconf, efibootmgr, openssl, sbsigntool, parted, util-linux, ${misc:Depends} Description: boot manager for EFI-based computers A graphical boot manager for EFI- and UEFI-based computers, such as all Intel-based Macs and recent (most 2011 and later) PCs. rEFInd presents a boot menu showing all the EFI boot loaders on the EFI-accessible partitions, and optionally BIOS-bootable partitions on Macs and BIOS boot entries on UEFI PCs with CSMs. EFI-compatible OSes, including Linux, provide boot loaders that rEFInd can detect and launch. rEFInd can launch Linux EFI boot loaders such as ELILO, GRUB Legacy, GRUB 2, and 3.3.0 and later kernels with EFI stub support. EFI filesystem drivers for ext2/3/4fs, ReiserFS, Btrfs, NTFS, HFS+, and ISO-9660 enable rEFInd to read boot loaders from these filesystems, too. rEFInd's ability to detect boot loaders at runtime makes it very easy to use, particularly when paired with Linux kernels that provide EFI stub support. refind-0.11.4/debian/postinst0000775000175000017500000000653313073177130016356 0ustar rodsmithrodsmith#!/bin/bash # Post-installation script (run on USER'S system after installing the # main rEFInd package) set -e if [ -f /usr/share/debconf/confmodule ] ; then . /usr/share/debconf/confmodule fi install_to_esp() { # Remove any existing NVRAM entry for rEFInd, to avoid creating a duplicate. ExistingEntry=`efibootmgr | grep "rEFInd Boot Manager" | cut -c 5-8` if [[ -n $ExistingEntry ]] ; then efibootmgr --bootnum $ExistingEntry --delete-bootnum &> /dev/null fi cd /usr/share/refind if [[ -f /sys/firmware/efi/vars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c/data ]] ; then IsSecureBoot=`od -An -t u1 /sys/firmware/efi/vars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c/data | tr -d '[[:space:]]'` else IsSecureBoot="0" fi # Note: Two find operations for ShimFile favors shim over PreLoader -- if both are # present, the script uses shim rather than PreLoader. declare ShimFile=`find /boot -name shim\.efi -o -name shimx64\.efi -o -name PreLoader\.efi 2> /dev/null | head -n 1` if [[ ! -n $ShimFile ]] ; then declare ShimFile=`find /boot -name PreLoader\.efi 2> /dev/null | head -n 1` fi declare SBSign=`which sbsign 2> /dev/null` declare OpenSSL=`which openssl 2> /dev/null` # Run the rEFInd installation script. Do so with the --shim option # if Secure Boot mode is suspected and if a shim program can be # found, or without it if not. If a shim installation is attempted # and the sbsign and openssl programs can be found, do the install # using a local signing key. Note that this option is undesirable # for a distribution, since it would then require the user to # enroll an extra MOK. I'm including it here because I'm NOT a # distribution maintainer, and I want to encourage users to use # their own local keys. if [[ $IsSecureBoot == "1" && -n $ShimFile ]] ; then if [[ -n $SBSign && -n $OpenSSL ]] ; then ./refind-install --shim $ShimFile --localkeys --yes > /dev/null else ./refind-install --shim $ShimFile --yes > /dev/null fi else if [[ -n $SBSign && -n $OpenSSL ]] ; then ./refind-install --localkeys --yes > /dev/null else ./refind-install --yes > /dev/null fi fi } # install_to_esp() # # Main part of script begins # case "$1" in configure) db_get refind/install_to_esp || true; if [ x"$RET" = x"true" ]; then echo "Installing rEFInd to the ESP..." install_to_esp else echo "** Not installing rEFInd to the ESP! **" echo "If you want rEFInd to control the boot process, you can do so by runing:" echo "" echo "dpkg-reconfigure refind" echo "" fi ;; reconfigure) db_get refind/install_to_esp || true; if [ x"$RET" = x"true" ]; then echo "Installing rEFInd to the ESP..." install_to_esp else echo "If rEFInd was previously configured to be your primary boot manager, you must" echo "use efibootmgr to set the computer to boot with something else." fi ;; abort-upgrade|abort-remove|abort-deconfigure) exit 0 ;; *) echo "postinst called with unknown argument \`$1'" >&2 exit 0 ;; esac #DEBHELPER# refind-0.11.4/debian/refind.install0000664000175000017500000000066612652500412017400 0ustar rodsmithrodsmith# refind-install symlink is added to usr/sbin as well (see refind.links) banners usr/share/refind drivers_* usr/share/refind/refind fonts usr/share/refind icons/*.png usr/share/refind/refind/icons icons/README usr/share/refind/refind/icons keys etc/refind.d mkrlconf usr/sbin mvrefind usr/sbin refind-mkdefault usr/sbin refind-install usr/share/refind refind.conf-sample usr/share/refind/refind refind/refind*.efi usr/share/refind/refind refind-0.11.4/debian/watch0000664000175000017500000000013612626645002015570 0ustar rodsmithrodsmithversion=3 http://sf.net/refind/refind-src-(\d\S*)\.(?:zip|tgz|tbz|txz|(?:tar\.(?:gz|bz2|xz))) refind-0.11.4/debian/refind.manpages0000664000175000017500000000001312626645002017515 0ustar rodsmithrodsmithdocs/man/* refind-0.11.4/gptsync.inf0000664000175000017500000001166313317563350015514 0ustar rodsmithrodsmith## @file # # gptsync.inf file to build gptsync using the EDK2/UDK201# development # kit. # # Copyright (c) 2012-2017 by Roderick W. Smith # Released under the terms of the GPLv3 (or, at your discretion, any later # version), a copy of which should come with this file. # ## [Defines] INF_VERSION = 0x00010005 BASE_NAME = gptsync FILE_GUID = 2767A966-477A-4EC0-8E95-EFFC2C29583D MODULE_TYPE = UEFI_APPLICATION EDK_RELEASE_VERSION = 0x00020000 EFI_SPECIFICATION_VERSION = 0x00010000 VERSION_STRING = 1.0 ENTRY_POINT = efi_main # # The following information is for reference only and not required by the build tools. # # VALID_ARCHITECTURES = IA32 X64 IPF EBC # [Sources] gptsync/lib.c gptsync/gptsync.c gptsync/os_efi.c gptsync/showpart.c [Packages] MdePkg/MdePkg.dec MdeModulePkg/MdeModulePkg.dec IntelFrameworkPkg/IntelFrameworkPkg.dec IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec [LibraryClasses] BaseLib BaseMemoryLib UefiBootServicesTableLib UefiRuntimeServicesTableLib UefiLib UefiApplicationEntryPoint [LibraryClasses.AARCH64] BaseStackCheckLib # Comment out CompilerIntrinsicsLib when compiling for AARCH64 using UDK2014 CompilerIntrinsicsLib [Guids] gEfiAcpiTableGuid gEfiAcpi10TableGuid gEfiAcpi20TableGuid gEfiDxeServicesTableGuid gEfiEventReadyToBootGuid gEfiEventVirtualAddressChangeGuid gEfiEventExitBootServicesGuid gEfiFileInfoGuid ## CONSUMES ## GUID gEfiFileSystemInfoGuid ## CONSUMES ## GUID gEfiFileSystemVolumeLabelInfoIdGuid gEfiGlobalVariableGuid gEfiPartTypeLegacyMbrGuid gEfiPartTypeSystemPartGuid gEfiSmbiosTableGuid gEfiSasDevicePathGuid [Ppis] [Protocols] gEfiComponentName2ProtocolGuid # ALWAYS_CONSUMED gEfiDevicePathToTextProtocolGuid # ALWAYS_CONSUMED gEfiSimpleFileSystemProtocolGuid # ALWAYS_CONSUMED gEfiSimpleTextInProtocolGuid # ALWAYS_CONSUMED gEfiSimpleTextInputExProtocolGuid # ALWAYS_CONSUMED gEfiSimpleTextOutProtocolGuid # ALWAYS_CONSUMED gEfiUnicodeCollationProtocolGuid # ALWAYS_CONSUMED gEfiUnicodeCollation2ProtocolGuid # ALWAYS_CONSUMED gEfiAcpiS3SaveProtocolGuid # PROTOCOL CONSUMES gEfiBlockIoProtocolGuid # PROTOCOL CONSUMES gEfiCpuArchProtocolGuid # PROTOCOL CONSUMES gEfiDebugPortProtocolGuid # PROTOCOL CONSUMES gEfiDevicePathProtocolGuid # PROTOCOL CONSUMES gEfiDiskIoProtocolGuid # PROTOCOL CONSUMES gEfiExtScsiPassThruProtocolGuid ## PROTOCOL SOMETIMES_CONSUMES gEfiFirmwareVolume2ProtocolGuid # PROTOCOL CONSUMES gEfiGraphicsOutputProtocolGuid # PROTOCOL SOMETIMES_CONSUMES gEfiHiiFontProtocolGuid # PROTOCOL CONSUMES gEfiLegacy8259ProtocolGuid ## PROTOCOL SOMETIMES_CONSUMES gEfiLoadedImageProtocolGuid # PROTOCOL CONSUMES gEfiOEMBadgingProtocolGuid # PROTOCOL CONSUMES gEfiPciIoProtocolGuid # PROTOCOL CONSUMES gEfiScsiIoProtocolGuid ## PROTOCOL SOMETIMES_CONSUMES gEfiScsiPassThruProtocolGuid ## PROTOCOL SOMETIMES_CONSUMES gEfiSimpleNetworkProtocolGuid # PROTOCOL CONSUMES gEfiUgaDrawProtocolGuid |PcdUgaConsumeSupport # PROTOCOL SOMETIMES_CONSUMES gEfiAbsolutePointerProtocolGuid gEfiAcpiTableProtocolGuid gEfiEdidActiveProtocolGuid gEfiEdidDiscoveredProtocolGuid gEfiHiiDatabaseProtocolGuid gEfiHiiImageProtocolGuid gEfiHiiProtocolGuid gEfiSimplePointerProtocolGuid gEfiSmbiosProtocolGuid gEfiSecurityArchProtocolGuid gEfiScsiIoProtocolGuid ## PROTOCOL SOMETIMES_CONSUMES gEfiScsiPassThruProtocolGuid ## PROTOCOL SOMETIMES_CONSUMES gEfiExtScsiPassThruProtocolGuid ## PROTOCOL SOMETIMES_CONSUMES gEfiLegacyBiosProtocolGuid # PROTOCOL TO_START gEfiLoadFile2ProtocolGuid gEfiLoadFileProtocolGuid gEfiHiiPackageListProtocolGuid [FeaturePcd] gEfiMdePkgTokenSpaceGuid.PcdUgaConsumeSupport [Pcd] [BuildOptions.IA32] XCODE:*_*_*_CC_FLAGS = -Os -DEFI32 -D__MAKEWITH_TIANO GCC:*_*_*_CC_FLAGS = -Os -DEFI32 -D__MAKEWITH_TIANO [BuildOptions.X64] XCODE:*_*_*_CC_FLAGS = -Os -DEFIX64 -D__MAKEWITH_TIANO GCC:*_*_*_CC_FLAGS = -Os -DEFIX64 -D__MAKEWITH_TIANO [BuildOptions.AARCH64] XCODE:*_*_*_CC_FLAGS = -Os -DEFIAARCH64 -D__MAKEWITH_TIANO GCC:*_*_*_CC_FLAGS = -Os -DEFIAARCH64 -D__MAKEWITH_TIANO refind-0.11.4/RefindPkg.dsc0000664000175000017500000001100413371575637015673 0ustar rodsmithrodsmith[Defines] PLATFORM_NAME = Refind PLATFORM_GUID = d6365e1c-b895-426d-a012-46769b2d02a3 PLATFORM_VERSION = 4.5.0 DSC_SPECIFICATION = 0x00010006 SUPPORTED_ARCHITECTURES = IA32|IPF|X64|EBC|ARM|AARCH64 BUILD_TARGETS = DEBUG|RELEASE SKUID_IDENTIFIER = DEFAULT [LibraryClasses] # # Entry point # UefiApplicationEntryPoint|MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf BaseLib|MdePkg/Library/BaseLib/BaseLib.inf BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf SynchronizationLib|MdePkg/Library/BaseSynchronizationLib/BaseSynchronizationLib.inf PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf PciLib|MdePkg/Library/BasePciLibCf8/BasePciLibCf8.inf PciCf8Lib|MdePkg/Library/BasePciCf8Lib/BasePciCf8Lib.inf CacheMaintenanceLib|MdePkg/Library/BaseCacheMaintenanceLib/BaseCacheMaintenanceLib.inf PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf # # UEFI & PI # UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf UefiRuntimeLib|MdePkg/Library/UefiRuntimeLib/UefiRuntimeLib.inf UefiLib|MdePkg/Library/UefiLib/UefiLib.inf UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf HiiLib|MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf UefiDecompressLib|MdePkg/Library/BaseUefiDecompressLib/BaseUefiDecompressLib.inf PeiServicesTablePointerLib|MdePkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.inf PeiServicesLib|MdePkg/Library/PeiServicesLib/PeiServicesLib.inf DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf DxeServicesTableLib|MdePkg/Library/DxeServicesTableLib/DxeServicesTableLib.inf # # Generic Modules # UefiUsbLib|MdePkg/Library/UefiUsbLib/UefiUsbLib.inf UefiScsiLib|MdePkg/Library/UefiScsiLib/UefiScsiLib.inf NetLib|MdeModulePkg/Library/DxeNetLib/DxeNetLib.inf IpIoLib|MdeModulePkg/Library/DxeIpIoLib/DxeIpIoLib.inf UdpIoLib|MdeModulePkg/Library/DxeUdpIoLib/DxeUdpIoLib.inf TcpIoLib|MdeModulePkg/Library/DxeTcpIoLib/DxeTcpIoLib.inf DpcLib|MdeModulePkg/Library/DxeDpcLib/DxeDpcLib.inf SecurityManagementLib|MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.inf TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf SerialPortLib|MdePkg/Library/BaseSerialPortLibNull/BaseSerialPortLibNull.inf CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf # # Misc # DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf ReportStatusCodeLib|MdePkg/Library/BaseReportStatusCodeLibNull/BaseReportStatusCodeLibNull.inf PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf DebugAgentLib|MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf PlatformHookLib|MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.inf ResetSystemLib|MdeModulePkg/Library/BaseResetSystemLibNull/BaseResetSystemLibNull.inf SmbusLib|MdePkg/Library/DxeSmbusLib/DxeSmbusLib.inf S3BootScriptLib|MdeModulePkg/Library/PiDxeS3BootScriptLib/DxeS3BootScriptLib.inf CpuExceptionHandlerLib|MdeModulePkg/Library/CpuExceptionHandlerLibNull/CpuExceptionHandlerLibNull.inf MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf BaseStackCheckLib|MdePkg/Library/BaseStackCheckLib/BaseStackCheckLib.inf [LibraryClasses.AARCH64] CompilerIntrinsicsLib|ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf [Components] RefindPkg/refind.inf RefindPkg/gptsync.inf RefindPkg/filesystems/ext2.inf RefindPkg/filesystems/ext4.inf RefindPkg/filesystems/btrfs.inf RefindPkg/filesystems/reiserfs.inf RefindPkg/filesystems/hfs.inf RefindPkg/filesystems/iso9660.inf RefindPkg/filesystems/ntfs.inf refind-0.11.4/banners/0000755000175000017500000000000012626673562014757 5ustar rodsmithrodsmithrefind-0.11.4/banners/refind_banner-alpha.png0000664000175000017500000002601212626644767021354 0ustar rodsmithrodsmithPNG  IHDR@o7) sBIT|d pHYsu85tEXtSoftwarewww.inkscape.org< IDATxyU?wUH:+"6 ₌( "88/ *̈@ؕA@-! ٷNNqSNu'~׫hRussnn^,jkk!ɗ|0P)dfϞ]x* B[H-H K jçoό4Li\a=|/0+r*He3fr ;]ɏxt6w/tcPEa.^W襡"Hu?q0`rM:˚G~v[NAzt||^R-TF~~|I[9_g3y{\t=`=zo= + RJ5h4܅aSF[Ԡ]_b커֤/ƥЁ~~L'NJ9L̀eO!󷬶-ἣZws/~ex[#iψ-[ԿjD̆E]˸R~f|B ?9?XٳgL%{^~AL̂-I2bʶ#ѱ&KAy[ %1;ExDtnb]s>ۜCa،FL,}֝}%\XٳgEbm}Lvޛh?? V,ÏfztI ݛ6=3{OnsX!w$c=ϼ]6~87)'^2v*7 }w7F`l4La)3ATƟGz=,Yv iif$[C7m?nr/}ĕQ)7󟳅/$ϩxu42pXWnNw&?8O[W'^ož5 ˒2A=3?w2?,A*e/V7A.yv>>Ś5R-Yagݛ=c{(i/e"FQj޼T)Y ZN:, s*P;1r!_ OBiVhT 0S2퍻m=H9S՗;t]~.UAyjn q4QcR~=r4mf4Ajݩx˽a*@B[I_Qiٚ hMʮ%ݓn%0GJ-Ɗ˭Rs1rw\zO[3``D! 3(Mt[ }7>^ƞPA]={Lg>HyZhze#Z>j顿)vᠽWz/U eZUJ#x=4V@Uw`qY.<2FaMʶ:XU_ftJ̹,57qn^ZAK~K}\y>n3`>>{IͻZFjD*o.)(Z&୏[}ҧD[+\ @ Te) >YjӉ'^8^}>a#zmfޔDDƿ6DLWhQyͽYF#%+7W L&iǰ&SqԶP@c# {fڅ랐 RՔF܄~+>%̮: Rp/ ,#l:{ ~ڦϮ^Cs< {jsg l RO]k t+> f3S0IOGA*n?z Ο2K-zAHU,{kE2."7 )H1$'ҕ^a-Z\/ dLf n3mݖp(HuVF# ccBDӄ RnZScjiQ?QE=*sW  6Ͽ=q|mv? j>7hi4'*"xi> Zag#\AvͣhzlSq2fnݛP93uXTFJeEf?(8#0 ZXo Ϊ4 {3Cwf=2 clbY N=(SdN8ruړvd},HcL.'àQ;F 'PA,W#2g˪GPPN q:_0ˋi`)H2 ꬑs#nQ]Be F=7%e6(> NEp!# 13fUFJu-7W `@/j3fgLJxѕ'^N0!#99R؛* LB4A0:Yˢbi= Ծg#2^a%~ 9-ōRנ^SK?^0' :y;0KOt;}tA@P0h|ŮU xbTi(Z.GV&ew4y9OXVK-BLǯTVzTlT*BCcpM(y6 G Tmx׎u|dmjEZ* ֙|*ldLk$ԾE t.RɸC쪥Vd0Yd2a1}<MX> f IgZJтsPn?#(> xCYzA~LrݰJԮvPlXcI|̯.͠05yZλZW 6D`X_ pwTHԂuQE\%]`Q.k 92sI;_v Y$[%,l-ح\]r #"y $2ET/Ջ1[:FI&Tx&?񾾚=R.5)tՄh3u4Jwf391zH?_E*A*;V'"Q`{)is ʕΏ^!5E+x餎{{"ޓ!Tǁ4)'^^~3܌@C9@*НdV.NApC v==IRB+V'(2U)Dyk ʵ2?kvUBVz1)^$ QɔNxiq͚[S铠;W.Ǟ"ݗlmJ:~[byvߜpr$Dȷ$-j5R6??conty3]v^w[[۰J24cC:v2_Nِƕ<|/Fcu/+3>PnC{x.S#4"bWF3w0'" vC?2 E|6Q&q` ^ѣ wjlH_X.нo7y҃j7cW !H²avʟA۞r6yDjbg"Yn8C#0b9A*F ^)V9jURP~Wdt22sG.:+)> /'u[O8+=ސfU\~Ⳅ͚u%fFձL*RX̡EwKNsC9)J\EM%dre#'a-*%v7B~v!V6nrُT1tY b6G[7ѵH8 /JRer}]JOI0p Y/o&qH'm)4f̳EU R _g!3k7ȽU1<{\_sͽ y2TwrRÅ)w(`l?ao3so"4KKpJ$6ТET)^0(a e/|:M1h>A#oݚme֩yH:Aٳ 9h?2vo>7sC/l\QLN3V%Bl0+9BCYXf{d9y6;$y_m<+Ytr|2cvar}y4oDz2QHu`Z'dSZ.RN`I}xZ &7 3G1M>͘P~zH*tӡm ~wb 3P=cFS %z`vNV&/iVGCcbg4){ a1ac̬TP Dw0qGdj,,A_36jiHz%٤bqBOJۓyv>5 ?㻲Q{Raf1xsѕ|*3n {?S0M:'1ƪK=+lrCNa<%xi8ZKW⯸ߖ'ulL~[Qlc4Q NQLxD2zٜ-x&ےME7eV#q_/v r1;|)3.d4rĝRǿg[J[WC[VVnǹc#iVCz!oc n ]ij Gj$yV#֚iI&&Ų+s[_adH[$Hҁn|A+l{d}~'Z m%+9vz8_8WX.njФɣv)gN /|śH%JD d ~7yz`@7sƄ //g*s{ŠaHJlhG[:o}5_($۱!pM} R`jҵ{qɕE|ZMD휣~#kԷa|t~?(aKLȚ̇c9vEH'ts=urH .YxedVQ [X(JYt]'yyx@WiYj_0Tc3~?yAw5IOͫX=7 ҢKI_i,f̳,\ĸ L< !?apVbfHGOO6_R+*WnA[ʖ\Pͽ ~9\6ߡ_ش+L} (MD|2+x}y|_ #+6aZn~{ql |O?]{qlD3zT{}3cI4/Ks,bv!<͑GPu%+Nw5#)Xڞrm)[M9ʘVʯE&ZIr%/s-|h~',|VHYʘ& yٲ~Y ~k \n^u\k(%^FfzdžGl&wR ^bMvF7 #ǶƳs~ I~h&>7=Ѻ0>݇a53y3BK'n({W,ԥP~v"˔)컲=w M!S>rdMw3߫ΠK/oVHi&_(*80_{2B¸|ÜRar;' :G3  wKNڙkOνÁ;Zsͬw0#9i0`nsT=n^x;2sɻn oe ;?Zno,Fisy1Syr,Hg+M)x=ﮧq+Yiceޱ q{ ePʪE,emAt'ဏӷ/wpʾ9!0;\Ƨ.a_'o ]s9c&58}oo זؑ`\ndu&7Z8,. CnhY3x>:'KNv~{MmXS 1ft }tNN?]a^WOB8w 7{9y<{㽼 .Q;@Dj}pݬĩu"}}t'8g|n}Fm?x+<5P]p_9>8'9f~0e?t5 {IDATH#={v'.6?aͳ9C,j$=\Q;/o^u>+{^́ q>35eW8h&˺G9oKYs,>ڗhL؆;Yu)$ANdvnO~]ӂ _fp*7>1E Ln=@ӚPt~ӳ-GMgrz+'-澳xNo6]kh^?rD޹?~M`8^}tgql~3Lԩyf}6=y7|!_(P8SZQq~7aǶ5I ?sǸ9ϑ?w/mc5vCo[$T%E[767Q|mMu%LYoD3̽ '\SCtf9>G=x-/ u,׍@C<q{?˜NVNcƅ.܌'ӮI _dFgGDƍKm~zËy& 槗rǢmq0ɶٝc Oq 7,,VCZ֞DLhdzVOǂ 0ȺF}ź=y퍜 zޖ&2m], h`BM ^ͪ9/JdKSzUE/[A*J>V=Pzx Ԥ9!m붰0 XX&1 ؐ { \˘dr&wA@!)S?o:m..|'l%<췈$tlذGj؆}t3x}D'ڎB3B &k C@~aS?,%#: 9TNcD&,Csװ?&Cjl`znE/vS17q- U/OML:IR|6e`z |t-6S7F!D O7:,DN 8ܲdVB3q9syv4ƭMmc*xDjvma<~]]XWpKfEKjlgM- qB M9%I@n͌RXG&/0&m0?lwlǘדZ&eŕoq㛹l/.kcl\27cRp;|u?s/{]\{W7vH"wWW謝d;Zڽ+1wD+a (<2ofpR^=J1d}%~i;``M356\͇x*v 0:hɑ[*MRsT'Ń?r9o bލ,lbn?}'pvڤ=χI7 'JDz$빍[󸷑L@Smw7k h" '`_Yg^x/oً=WkY;?8ɤ:>jeRCFcC,'?)XyKX3]|zY<ƞeѮiIx_‚zYk$L$Snn'Vy)1L?y槯[X}-]%lez3ܓae[} OևUzQL^³'dU\4|npM t_¸c쎯FV_sk\d `F}~!6gaq -LL3>GMGny{pԫ8]rYx qg-u{e!wm/=$Kme촚E_滋YGwGXu+m?1WUP wa)W;$蚐}ML78[&ǻk]&[38ێ$&`@ `06a$[s}􌤑$ThsΡnM4M?B$IA$F_'B0UUUUUE1mtTMT ,zH Iƍ(!p5EQdYR~#E!H ˪ZشI[fXh\CyوyY,IeYdC'shQ鴶lp-ҦMvjXa vf&({?LR#=Pvftv@N)E_f丳L_[jV`:,˓^~TWbYDyEWD#3V,HmVR3cMXShr$8Qxi}pGO\o<ܵˆ~\jr;Iz -FBǛSuEQ̕'`6洺7AdYl6V+Xˆ^@t#_"|{7H[E!;B,&va(٘>2"vuI*kaAMMnl0x$ItZ器tX fzU*NZm- vH'OjNe*]Hwo琪F|8g 4TRR>+VË|v]qۭ(js0'SOUDh;jտu,dRۿΟGQUghZWRwa:Qzz=&RBwK=de`uWT?= <}ÇnpU%*$ٳo{&ych$K]ek`|99&]PU]Q~TR,%IR]'v,ۇBJ{^_X,,ϟ4Pr^lY(Lg9⌢gDb׮]?vwwp\־U;EQFFħRs{f+Z~Kˠt:,[b(ʂRkk)xmĉck0*hA$I]YQdKmrf.eY$Az! "lVOR<8ݎJګ:MӚϲI$Is*L7ciZOf…g6l8éhfZ|(EQ;d}MMq1ۘ˲4-roV:ghnGZ\!hEQz{{8Ncz(o}uqd$\.qp$b>m` 'Xo~zMf 4[* 8'nguw?Mf)xT*=#m۶YÇ˓xp8zM'+dY$w9x`2L$Tyh>I E9p@uWx=\5ܕ #6o&d2d892&'ݥ# tTUKgg;Elvo&`ݻwwwwT`UU}!icl]AG۶Y8h۫+jeᬪjo^j `wLZ{{7l؀}x2??;vlNS+כiڥKL '* $2D'Oj4p80CYjf `&_#Dn]xXIޢ츕`juB  0Mn(\K-[=!EQofM˲,3FC>_Aw3 r1nƭ6EQ(RގZ^]5VUT__vm6˲~mZτBɶQw@<\BxRp{Fv?= XqG4 oׯZ n$ /0::j|lxx8ϋw _*be˗P(IJl2O~2{t;I+1,V2~c|Tw7GFG>VڶMpsܾe˖P(ȳ6MQ!mSfhB&,+eN!']tȷC*Zh n:[lY8b@ 1(L~tQB!Q}B 9lX;` @K48!HӴ(== BkAgXqZjѢEh4B tr* 8+y5{bA[oUћxEUdEd`_OYQgk@J&t5}>a]1|%IF&L{^ DQ,7?D">Iӫ44R֬Yau"W? /|.6EѤQnNfL#aJ +Jzɲ<1Q'Y.Ĭw ځ bBg9].vnO4HrA[n3NNyT3G8E1@x< : اeڹ6igΜ1;שּׂbH0\UUw#y&+ %D W jN;M B<7=WfЀ== \0*F)i2ˣ`y! 0lfiO)Y`Ujkk!(`k|qP]v涡aҥ@tDP!Aiia2x$b;]r t#"%AAoEl_ŊݩSzE?֟fXHbB!V12f3I=^ʣnw L*J4e2c]= H7jt5PMM 0NWڀ=1Rrj]B[( :E픃P:v)nffl ]p02>n2cv;5ߐiW*N$UR "Xa ,].bh2&^/:,tk`Z؁kXZ[+np0v,A_\kR<^'v3/[q%Xir$cQFQIM9`I]nx>^*L'˝pug>8oTrwnT6GD*]O fhHx p8+V$f)34[?#J5526T tE)1S7¥"2J.IR<7X,&5q~M yR޽;I#&xDQwdB7,y`%cbѤL{?]W\4RdJ5Z.6g0XZ8Ja]n0cazMz3)Xx?kf[,zSLl޽hr4 `ƖJol̝:Z} -0Ȑ_ JX<~^,[rEɭc3k qaPAHD_Foi T2<uNhgSet4Ld@ 0u}ѢE&إXhQSSu:!Q)0ca7oN+&b߾:غ58Θ9S}cG{/?en7])3(c2îB۹},y<ɤ͚ J! ]8x&Fi5M3Ebbnjmm=p@yg9vp8>I=)?(//яL&S(DQQ1 _ZqʘsmmÐ$,P6i輘Zt(H$ XTю t+_ؽ;cґ#1GwB^Ҩ&{Yl6krCa0ag!w6(GrDGڂQtؚ$TTvjm/^ s۱,OuNg(§5@?;, qV9}tf+>90kΉd2N,rl6{\?~ҿ=::׭;D`uUf/n:8ա0n9Ro %be5ll jV]VF dCڌimmyԤ#mذ=}_ݴiOBKKJY[y8,pӴ`,Лo*#_I=G },e޿H$DoYK4כdx0;֬Y ^/bT˗9.p$)D*0,suu#[_ p$BϗMA֭ӜcBT"!˲ŷl\W1#Fwy+0N\0Fl>oll{ i2J ^eK.mkkFPZ n nU޹OE|>Hng7obX, B׬kIcB!H$|>O~@ 0BL&ST&ccf[q.n!@!Jɲ0,q¦}:LӒ$AGq$IBz xPx2cmENBT*=Ʈh-d#J1ZEuxR F!+vh8`V``bF l6+A^n{<).q8Hy^UUXlW@:N"XU.P܊D`8hzwpj1Vp)8o`~srh&Py4 1x*@g)<ħUz(I#h*'/ɼZ'yA47[kj&OH:tp(Ze,Ys*}j,Dd C<"{ 05Hw,>d.ja\ (inْZ>=Z,2sp%E*h+ulf9s2ȱ B|FI )WD*]׍KX6Y,jlv;d:qK%Z-Oc(NFCJJ։ 9G|_ł矯{%ߡCYMKb23d/vZc[S').|oCJY1ܮ\x 36 quxI$Hp:55iC4Mwvfo.?nps˕PЃye@O3n,V~BALt=ݻ)A~;}. :c`@QxGq\p; T=ÁCDQ|SO٬Ywp83*TUOL v=uO=e)5&eGU~O\?Zs{p!ĉm@, '㬖[ŞLh…YOcFGBV>~=#I 6>G{h]cG>eX0?/%pܲe(С%_xZ^ߏ>%>-<8G_k8a"!_:-˲ԩ%/4x?^SSٹg,4NLLDBԧ'?;}>9nիߺD {[o't=tSjX&'Onڽ!4β˗}VfW17޸7^~܃ZB6~˗yԴߤK_ ?lų|I޳]˖zؒ/>ȗz`OsoVc>ϲFG]ǎT a:6FsXooڄjx[o!]?qիGc#݇ uuioz~2A{{Ӣf2*EC!5|aZ/_oZ嚚S32a7niZFBLFcBol:"^sjPmZҥCuuVQ'  }ҳn]EIfoā U#uuI9C+J(!\& foq8B2MJ%vl !AUteٕNgN;r6r "KEti0YͲ˥;$=6&1`$b%³BIWK&BirlD <)7qbY!Y,D" BvInl Xr櫻Q8UL$!~f3Xى Dqc1stz BLBx ⷀ<^[KMs#e˺WJG"9sljK^ 3*bƍm=ujAo/x\߼n_Hz~DUUC#.v8sվ{ LsK._~`ǎ+Ω 2.EQt:nXѺ:^[[d]k2x,jwݱ?u[hvJUP'N?縅 ſ@pf;(J6or! #מ{n4\#Z}b!T]O&ޱ1Pa\rN(v=^SS*Fo{I*29I'MN"]Fwߞv:zSӾ?z].p_Nqw"1TW@ <%=9|Xa6Ywzccy{>MR Bbq(Kӹs+ND./[t:?w6Kj>v8W6o~{6JW>̙ŋBPplxOVuGoz5v'hԗ#h8B LscgԸȝNN~;~A0s_/oiF"nON'&&2,E ǐiccEPm6NiQ٬2:*dTpwϲ|L&P*$$p8 1,gY9u]$Xjl69, '[,I"85MEH-x ("B6]/ٟ~!˲J,, `a, 49NĂuX,Exre ![cNHK\il:a > G;ϳL,9$v+0Lဟ2fyi 8A:h,2'n7tKHfb8&5|щ|šx(J j G#RqBL0@Mo)Rc@Pr p GpˤE#Wo>ys}7OvX}>y^U>" b '6 |G.6cySfkhgϲ0x>paө@N {Gafc\pD/%7f IS΋7P1 T,[vp?x1o,^ܳv@4rBgpƼ\"\Y' EitihkfD2i3$n6]Q-|^p?TBkO3L&l<|9{͖khy<\( p>lo}脩>aƜ$Q僒L|뇘h4UVIENDB`refind-0.11.4/banners/refind_banner.svg0000664000175000017500000003422312626644767020307 0ustar rodsmithrodsmith image/svg+xml Boot Management refind-0.11.4/CREDITS.txt0000664000175000017500000001143313142210427015146 0ustar rodsmithrodsmithAlthough I (Roderick W. Smith) am releasing rEFInd in its current form, the program is not the work of a single person. Others have contributed to the program, both in its original version (rEFIt) and by providing features I've incorporated into the current version. Specifically: Program (C source code and script) files: ----------------------------------------- * Christoph Pfisterer was the original author of rEFIt. See its Web page, http://refit.sourceforge.net, for this version of the program. Christoph has therefore contributed more to rEFInd than anybody else, myself included; my changes are comparatively small additions to the original rEFIt base. * The Debian project has made a version of rEFIt available that incorporates a number of patches, all attributed to Julien BLACHE (jblache@debian.org), to enable it to build properly on a Linux system. It was this version of rEFIt that I used as a starting point for creating rEFInd. See http://packages.debian.org/sid/refit for this version of the program. * The filesystem drivers released with version 0.4.0 rely on a filesystem wrapper created by Christoph Phisterer. They then passed through Oracle's VirtualBox (https://www.virtualbox.org) and the Clover boot loader project (https://sourceforge.net/projects/cloverefiboot/). The filesystem-specific code comes from various sources, including Apple, the Linux kernel, and Christoph Pfisterer. * Assorted support code is borrowed from the TianoCore EDK2 (https://sourceforge.net/projects/tianocore/), which is the reference implementation for EFI. * Dave Vasilevsky (dave@vasilevsky.ca) contributed the disk-ejection code. * John Bressler (jrb1327@gmail.com) contributed the code to boot BIOS-based OSes on UEFI-based PCs. * CJ Vaughter contributed the code for support of touch displays and mice, with some improvements to the former by Tom Briden. * The code for editing boot options (cursor_left(), cursor_right(), and line_edit() in screen.c) is taken from gummiboot (http://freedesktop.org/wiki/Software/gummiboot). * Stefan Agner (stefan@agner.ch) turned the original ext2fs/ext3fs driver into one that can read ext4fs. * Samuel Liao ported the GRUB 2 Btrfs and NTFS code into EFI drivers and contributed them to this project, along with several miscellaneous improvements. * Martin Whitaker (other@martin-whitaker.me.uk) added 64-bit support to the ext4fs driver. * Emerson Barcelos (emerson_freitas@yahoo.com.br) wrote the code for enabling Intel VMX support (the enable_and_lock_vmx token in refind.conf). * Rohan Sehgal (rohan.sehgal.su@gmail.com) wrote code to help rEFInd detect network boot options and launch them, with the help of the external ipxe.efi and ipxe_discover.efi programs. * Matthew J. Garrett (mjg@redhat.com) wrote the shim boot loader upon which rEFInd relies for its Secure Boot functionality. I took a few shim functions to help out on the rEFInd side, too; see the mok/mok.c source code file. * James Bottomley (James.Bottomley@HansenPartnership.com) wrote the Linux Foundation's PreBootloader, which is an alternative to shim. I've found that much of its code is also useful in implementing Secure Boot functionality in rEFInd. Most of the files in the mok subdirectory are based on Bottomley's PreBootloader code. * The PNG support, in the files libeg/lodepng.c and libeg/lodepng.h, is a slightly modified version of LodePNG (http://lodev.org/lodepng/) by Lode Vandevenne. (The libeg/lodepng_xtra.c file provides some necessary ancillary and interface functions written by me.) * Pavel Penev contributed the code to enable encrypting rEFInd's locally generated signing keys in refind-install. * The RefindPkg.dec and RefindPkg.dsc files, used to enable compiling rEFInd in the traditional TianoCore way, come from https://github.com/snarez/refind-edk2. Icons and graphics: ------------------- * Most icons are derived from the AwOken icon set, version 2.5, by Alessandro Roncone (aka alecive); see http://alecive.deviantart.com/art/AwOken-163570862. Many of these icons have been scaled or altered in color from their original forms. * The Debian icon is based on the SVG available from https://commons.wikimedia.org/wiki/File:Debian-OpenLogo.svg. I modified it to fit the general style set by the AwOken icons. * The Elementary OS icon is based on the SVG available from https://commons.wikimedia.org/wiki/File:Elementary_logo.svg. I modified it to fit the general style set by the AwOken icons. * Erik Kemperman provided the original (pre-0.9.3) rEFInd icon, which is a combination of the common refresh/reload icon and the search/find icon. For version 0.9.3, I created a new icon from Erik's basic design concept, but to match the AwOken flat-with-drop-shadow style. * Additional icons were created by me. refind-0.11.4/Makefile0000664000175000017500000001606313320416625014762 0ustar rodsmithrodsmith# Makefile for rEFInd # This program is licensed under the terms of the GNU GPL, version 3, # or (at your option) any later version. # You should have received a copy of the GNU General Public License # along with this program. If not, see . include Make.common SHELL=/bin/bash LOADER_DIR=refind FS_DIR=filesystems LIBEG_DIR=libeg MOK_DIR=mok GPTSYNC_DIR=gptsync EFILIB_DIR=EfiLib # Two possible locations for TianoCore toolkit: # TIANOBASE is used with "tiano" targets and # EDK2BASE is used with "edk2" targets export TIANOBASE=/usr/local/UDK2014/MyWorkSpace export EDK2BASE=/usr/local/edk2-vUDK2018 # NOTE: Below is overridden for "tiano" targets -include $(EDK2BASE)/Conf/target.txt THISDIR=$(shell pwd) EDK2_BUILDLOC=$(EDK2BASE)/Build/Refind/$(TARGET)_$(TOOL_CHAIN_TAG)/$(UC_ARCH) EDK2_PROGRAM_BASENAMES=refind gptsync EDK2_PROGRAMS=$(EDK2_PROGRAM_BASENAMES:=.efi) EDK2_DRIVER_BASENAMES=btrfs ext4 ext2 hfs iso9660 ntfs reiserfs EDK2_DRIVERS=$(EDK2_DRIVER_BASENAMES:=.efi) EDK2_ALL_BASENAMES=$(EDK2_PROGRAM_BASENAMES) $(EDK2_DRIVER_BASENAMES) EDK2_ALL_FILES=$(EDK2_ALL_BASENAMES:=.efi) # The "all" target builds with the TianoCore library if possible, but falls # back on the more easily-installed GNU-EFI library if TianoCore isn't # installed at $(EDK2BASE) or $(TIANOBASE) all: ifneq ($(wildcard $(EDK2BASE)/*),) @echo "Found $(EDK2BASE); building with TianoCore EDK2" +make edk2 else ifneq ($(wildcard $(TIANOBASE)/*),) @echo "Found $(TIANOBASE); building with TianoCore UDK2014" +make tiano else @echo "Did not find $(EDK2BASE) or $(TIANOBASE); building with GNU-EFI" +make gnuefi endif # The "fs" target, like "all," attempts to build with TianoCore but falls # back to GNU-EFI. fs: ifneq ($(wildcard $(EDK2BASE)/*),) @echo "Found $(EDK2BASE); building with TianoCore EDK2" +make fs_edk2 else ifneq ($(wildcard $(TIANOBASE)/*),) @echo "Found $(TIANOBASE); building with TianoCore UDK2014" +make fs_tiano else @echo "Did not find $(EDK2BASE) or $(TIANOBASE); building with GNU-EFI" +make fs_gnuefi endif # Likewise for GPTsync.... gptsync: ifneq ($(wildcard $(EDK2BASE)/*),) @echo "Found $(EDK2BASE); building with TianoCore EDK2" +make gptsync_edk2 else ifneq ($(wildcard $(TIANOBASE)/*),) @echo "Found $(TIANOBASE); building with TianoCore UDK2014" +make gptsync_tiano else @echo "Did not find $(EDK2BASE) or $(TIANOBASE); building with GNU-EFI" +make gptsync_gnuefi endif ########################################################################### # # GNU-EFI build rules; should work with any CPU architecture and GNU-EFI # version 3.0u or later, but cross-compiling requires adding odd # components and is untested.... # ########################################################################### gnuefi: +make MAKEWITH=GNUEFI -C $(LIBEG_DIR) +make MAKEWITH=GNUEFI -C $(MOK_DIR) +make MAKEWITH=GNUEFI -C $(EFILIB_DIR) +make MAKEWITH=GNUEFI -C $(LOADER_DIR) +make MAKEWITH=GNUEFI -C $(GPTSYNC_DIR) gnuefi all_gnuefi: gnuefi fs_gnuefi gptsync_gnuefi: +make MAKEWITH=GNUEFI -C $(GPTSYNC_DIR) gnuefi fs_gnuefi: +make MAKEWITH=GNUEFI -C $(FS_DIR) all_gnuefi ########################################################################### # # Old-style TianoCore build rules; useful only with UDK2014 development # kit.... # ########################################################################### # Don't build gptsync under TianoCore/AARCH64 by default because it errors out # when using a cross-compiler on an x86-64 system. Because gptsync is pretty # useless on ARM64, skipping it is no big deal.... tiano: -include $(TIANOBASE)/Conf/target.txt +make MAKEWITH=TIANO AR_TARGET=EfiLib -C $(EFILIB_DIR) -f Make.tiano +make MAKEWITH=TIANO AR_TARGET=libeg -C $(LIBEG_DIR) -f Make.tiano +make MAKEWITH=TIANO AR_TARGET=mok -C $(MOK_DIR) -f Make.tiano +make MAKEWITH=TIANO BUILDME=refind DLL_TARGET=refind -C $(LOADER_DIR) -f Make.tiano ifneq ($(ARCH),aarch64) +make MAKEWITH=TIANO -C $(GPTSYNC_DIR) -f Make.tiano endif # +make MAKEWITH=TIANO -C $(FS_DIR) all_tiano: tiano fs_tiano gptsync_tiano: -include $(TIANOBASE)/Conf/target.txt +make MAKEWITH=TIANO -C $(GPTSYNC_DIR) -f Make.tiano fs_tiano: -include $(TIANOBASE)/Conf/target.txt +make MAKEWITH=TIANO -C $(FS_DIR) ########################################################################### # # New-style build rules for use with TianoCore via its own "build" tool. # Works with UDK2014 and late-March EDK2; but UDK2014 builds fail with # AARCH64 unless .inf files are modified to eliminate references to # CompilerIntrinsicsLib.... # # NOTE: Unlike other build rules, these build everything (rEFInd, gptsync, # and filesystem drivers), even if only one component is requested; but # only the requested components are copied to their final destinations. # This is done because of the heavy overhead in building just one # component in the TianoCore "build" tool. # ########################################################################### # Build process for TianoCore using TianoCore-standard build process rather # than my own custom Makefiles (except this top-level one) edk2: build_edk2 cp $(EDK2_BUILDLOC)/refind.efi ./refind/refind_$(FILENAME_CODE).efi cp $(EDK2_BUILDLOC)/gptsync.efi ./gptsync/gptsync_$(FILENAME_CODE).efi all_edk2: build_edk2 fs_edk2 cp $(EDK2_BUILDLOC)/refind.efi ./refind/refind_$(FILENAME_CODE).efi cp $(EDK2_BUILDLOC)/gptsync.efi ./gptsync/gptsync_$(FILENAME_CODE).efi gptsync_edk2: build_edk2 cp $(EDK2_BUILDLOC)/gptsync.efi ./gptsync/gptsync_$(FILENAME_CODE).efi fs_edk2: build_edk2 for BASENAME in $(EDK2_DRIVER_BASENAMES) ; do \ echo "Copying $$BASENAME""_$(FILENAME_CODE).efi" ; \ cp "$(EDK2_BUILDLOC)/$$BASENAME.efi" ./drivers_$(FILENAME_CODE)/$$BASENAME\_$(FILENAME_CODE).efi ; \ done build_edk2: $(EDK2BASE)/RefindPkg cd $(EDK2BASE) && \ . ./edksetup.sh BaseTools && \ build -a $(UC_ARCH) -p RefindPkg/RefindPkg.dsc mkdir -p ./drivers_$(FILENAME_CODE) $(EDK2BASE)/RefindPkg: ln -s $(THISDIR) $(EDK2BASE)/RefindPkg ########################################################################### # # Build rules that are not dependent on the toolkit.... # ########################################################################### # NOTE: This "clean" rule cleans intermediate components for all three # build styles (tiano, edk2, and gnuefi). clean: make -C $(LIBEG_DIR) clean make -C $(MOK_DIR) clean make -C $(LOADER_DIR) clean make -C $(EFILIB_DIR) clean make -C $(FS_DIR) clean make -C $(GPTSYNC_DIR) clean rm -f include/*~ rm -rf $(EDK2BASE)/Build/Refind rm -rf drivers_$(FILENAME_CODE)/* [ ! -L $(EDK2BASE)/RefindPkg ] || rm -v $(EDK2BASE)/RefindPkg # NOTE TO DISTRIBUTION MAINTAINERS: # The "install" target installs the program directly to the ESP # and it modifies the *CURRENT COMPUTER's* NVRAM. Thus, you should # *NOT* use this target as part of the build process for your # binary packages (RPMs, Debian packages, etc.). (Gentoo could # use it in an ebuild, though....) You COULD, however, copy the # files to a directory somewhere (/usr/share/refind or whatever) # and then call refind-install as part of the binary package # installation process. install: ./refind-install # DO NOT DELETE refind-0.11.4/docs/0000755000175000017500000000000013363352576014255 5ustar rodsmithrodsmithrefind-0.11.4/docs/Styles/0000775000175000017500000000000012626644767015551 5ustar rodsmithrodsmithrefind-0.11.4/docs/Styles/styles.css0000664000175000017500000000245213364101564017570 0ustar rodsmithrodsmithbody { color:black; background-color:white; text-align:left; /* font-family:"Georgia",serif; */ } p { /* text-indent:50px; */ } li { margin-top: 1em; margin-bottom: 1em; } h1,h2,h3,h4 { text-align:center; font-family:"Bitstream Vera Sans", "Verdana", "Helvetica", "Arial", sans-serif; } .userinput { font-weight:bold; font-family:monospace; } .variable { font-style: italic; } .listing { font-family:monospace; margin: 0px; padding: 6px; border: 1px solid; max-width:100%; width: 50em; overflow-x:auto; text-align: left; background-color:#EEE; white-space:pre; } .quote { width: 90%; float: center; padding: 2px; margin: 10px; background-color: #EEEEEE; } .highlight { background: #888888; } .sidebar { width: 45%; float: right; padding: 5px; border:5px solid gray; margin:10px; background-color:#EEE; } .navbar { width: 40%; float: left; padding: 5px; border: 5px solid gray; margin: 10px; background-color:#EEE; } .subhead { font-family:"Verdana", "Trebuchet", "Helvetica", sans-serif; font-size:150%; font-weight:bold; text-align:center; } .left { text-align:left; } .tight { margin-top: 0.25em; margin-bottom: 0.5em; } refind-0.11.4/docs/refind/0000755000175000017500000000000013372351117015512 5ustar rodsmithrodsmithrefind-0.11.4/docs/refind/rEFInd-Metro.png0000664000175000017500000005044413074725144020430 0ustar rodsmithrodsmithPNG  IHDRG) pHYs+tIMEy\DetEXtCommentCreated with GIMPW IDATxw|e?ϔ={o*J{9{YNϻΎ;bEE"]t m{n6fڗgywAAt,A$w NA ;AAr' A$w NA ;Aɝ  A$w NA ;Aɝ  A$w NA HAɝ  A$w NA HAɝ  A$w NAr' HAɝ  A$w NAr' HAɝ  A$w vA%& SY#XӪeoNM:iDܣбCr'vL{50duY/T .{ƀ@ 76~!|;?Xwu ,KCr'{ cpYYIrj^wi`X_ A:BB t c{C/GTTRޔ2,֑{2VAPNt@8 ol~xdLH e(";Ѯp^8e* BELH6lBI N+zpƍjP xCT/ K0bF ɝ8ơv*Dsz()y`X9Y ɝh{Cǎ2J}pqh-R ;J, FAr'B;J(RZhؼp8PDd iɝh=s\(tLCv<#e ;DzUkpD? 9R HD l(¡.mvz`OC$d XA=T-JP}$A (r'5;l(9f; Nt{";+A1!( A܉ !נ7 HDj84 nԠPk.TA;9qh9QўTSNm=P=vێzPbA* 1֊h*4h״`>EcL L!$w]?w5j[݁dt2 qTgo`c}, Y(Nr(%C{|v{lsw *L$.V ol8@2 2wfl26Ya'19RB2 Yy#[~εWiܮ@O܉c}fsCu"]$$$P^?J( ȥ(~|k90Y 㦈kS`!aѓ4þv}w;"zGr';Q[ LI2U*2D F}ʽ/TJH`$7gvuP0'$O>;yٮVea3nHıq{ roa;3"ɈX}ԣqhVvVz>8 )F;]k?\0Zrq~'Y]/ F p;q ΡiP=n$#dBA Ưk8TU`0AiՆ7*|nԘBuMro?mZa53C[7 0Jѐ܉ۃzQRTfI 33APT fEY)z10aAՠՍ^f{\;wesm:f0wy#OުVA$܉rQWjU$@!1PwmiL_dO $ 6 EOWўJ < M߰{Щk[wH-z۩ ɝhT/j I"d Ó!EB00LfpGK0a`baz 2~}pN(y`7J5먉n{Tn񺕊JJL5v%+`ϕ}'ϐ܉6qh ̈,AK,po-C7KA0l6iP erA(B;WE53+ıso{5޵g;7j.`I ~͖:eHwnI 9A1ل$=XY d%gdł4:! eaЯ"zz%j=xq"G6yNw[i5蹻][~ X87T 99?i;+~]HDk;^SGo(B`U !RZ,/ 0;q wVz #,`L͓t&&uRJZk;onf0b1QX2}rZsdh4'eVۃ ddX$yvuS ̏7by&'ܺ٫K2ybƔ,QV7T A Q9A'v \\)-5 C8 gv`0rY G܉Vh{Ƚ4R#^׋w*CR3Rr IW;6~y\EK[ \*'v*z`3"~ %,6㳪æ:;7wlV*K5`bbi:1tioDI0ghnd ܉܃c7G 6xZM=wVޝO:OMKo87S؉ùza~Xk@z&EH5kvѩ.abOLeK>u_9$C!~,V+ذ}[tO_¤`ibjeX(%ϼ/]q܏/)wjƾK1 iMN:637 @V3/2xxcßʆ-/jSĄٗYMh`MdFd&E&ɂŪ:jj}n/;lNj73.2ht#`ZVkbc A;<4(Xy{ΡZ]䱰 Xy7}wlR?Eh56{8K8 W 2pcֵw9֭P5B9|ދ.νsc*i-qTSA13lro[K?ɝȟ޳4B35hLbP(g&)r 9DOI!Yc^8T2 -)ScorJ.N6vqMů=4L3 UMɆʽ(-Ck*1ժ=Ce:|^M8uCXXFH>΍VZ ҳSN;+Šz_.LYK*i\-wMcDI,X$3Q 2eLsJ_{l5gRө. gȭ{xsjڥU[5Ef&0A8y|I05oԋ*{(r'Z>;UٺqIQ󮜵sj.{mYg:HOi8L?h`)SϏwnEҊ/>u}2p0vvݞ0[GNdF&D׶_uSJ>y(r";5M |3Oei+*T|} ]ؤ E`O#?BrUIwOauU/ƂqUҲLCh<{x4+xwU6ᮩ?I12xl)!V4&Ar'"f=h1BU|dzUwtǍ)(,yg2y+H;j ͍E[ʟ~?e\o)Ub(p\$d^ugKX|ӟ fk7 e<}@vEz ̍Oʚx K@r'-bXHݨNBcLo2ؠ~B^'qذn=ɩZEУ+j֭ ʎ(-kt[Jw?i¨_+dԙ;ikԳU!@dm´s{pXGM\;ɝh)MeoӅ$dIӧzD I>ͤd@LfܹC];OdC Ս~/*1;Ar2^Ą8jgu κ:[\~^^j8?_0)3QPcy.TPIoĝsB7x4c ߮X~wR4:Г??W\Ӽ{A1)FkEB?{y}6j`8eqCn)@r"đY'*%|6ࢹe}@+r&/nH9j|`Wo;4a&BwrPQCk"'܉۹p)A.KDf"MH k&q֫7;%4ÎՁǼ#4(nTD`WZ:m K)ibbA/]|d& Ar'ʼn̊d0 {sScR&f~E^󰁈#&z^#FX8!w ,,- a㪟qB39Χ }X9ST)Nr'6lלt4@lEQ~0` ~ӕЭ%+l=q8 b@@|f-Ζ3*|5(`4! \uFdRM.`Cvg_T{h4C*R3rC\Nj~Ps9֎AFq7Da&$Z*@bv00,)+mBns5ɘXp_}&&% H.TP!q:ܡ_soK/i犟+~Ҳ;V/\f {_{obyR^)q y4?"EDQ=_hF& r(@ <_ g }K R`.lG d5$x`=k;J%Sʘ/=RMCNnQKXMzkwI%KO= p=3S K@N4+!_B*7)2d=3e#8 @([}E+=+/=3ָ`UW K^İj~׫V1 .s7e^x"E_YQ{ &k`HeQ4f`lcUis_†~ux\-,@cPZh3.UE~!#حoWT|K0SJꊒןP+ZEIٻO;5UM?-*es'M0J7 2,L!Ja{_}SPQg[s:o}vKq\wMhspvP6׮v_s܇[ukTmU=޶.K9r)#'WOICtt͍J;PѤF$X.(RpX#`Qѫ׫ ̿zu忞]zo{ٷCk Vgм+0I0VwL(lwݿ~WZ~U_Qvڢ]bޚ4a&OyNL9jU9`w{fgojŤssij]F' Hdvݎb{z* MHju. ;S "8g\ ig]%guRK?xA0kZ5 L(AS圮c,Clj )B(MqnR^XN^;+sf dBb0.iI~\*4BAި&ud~ &@mv𮣏X:^weg??$gW~ 3z(1Yf9b} f^Wc޾jM!wS&a|>w&1̮a![3"v $Q0A"j M4{4;}b5 "e:߹w;"c^ͼfˠQLEks/+bOWUx_G tIĄ$SWEJlt$wkmbY8:,ќjwBl%8=|o C{8ڿ9:dGWU{5e&D99ϗ}Ӄ9`J.WmUl ,Y;LSy10;o 0"A{i'; |]jCD& ʪQ،] Uw֌vyർwWZ`ܹڹ^8W|L:֯rnX A -1{^goeȝ<Tjp(ͮd$ď^/A.0H0?US4`MFnb jUyق:񄘘Ҵ0MS]2¹']br"ez $#먶*O^Wk*.܉נP'a\ >bWK7g-]B72>8Q ݮ_|܎M5ɾf)ɓ䳢Bo b%P IDAT߈ It"SZhs j ēRЇ`f.Oi [zD#2hVffLl(V`{ Ie_\4귎59RL[W-ꋷ$w"7pQg3#łT# C3j{]2]e0!Ɍd RHNjDyp֎L|n02eUsU~_ILl旿, Ii"JAuw2FTDGDJyQka{mnFR $" ߻%4(~xphvZ.ԡ1ƽ^R3Nuˆ[o>PʎI=늤΍oe>.NDv;;f׺ca r`Qo.I%89&{l(]/HS1t0Wk*^}gpǚvUig]D,f[U雏kN;!vCSUu)$>}?M1.@xv\-lwa 6 4]'CGãFPps8chοtT&Zk_GJȐ܉a.).@u.@G!b=AQb,B3_'{G,#@a֠ 4~([GVɰawt / jNnɸO\mǖE,O FDr'b큧 V{P ,zF! M%口uy(ᖋHЯ[$5(TVxȂ?aa 9&( P>%).M>yZ+&I8z|UB/ɝG&$0iAڦ<kPe=G)m?|jmÙ84ps@5 aYw0dqlѽ{e)gWx⓹u+UG N45)!8{䇙=a,аD8q׆͎<.>vqkQA_X]Mh$尭ڱ~U ҤciH~~n;4aUNֺih]0 V,8W*O_6 |ΉA˫} 1~;Ղsif׉㧤sufں.gL@`ujCr' W(XhBQ[,w0o  F_~OMf&6aӆZ\؂H}g{EGA[%L0:b!`02IfȘȖsMr+~pmwނ<;ѬX5 ,Xa_ax1qi$N[~C du2'\Dp^.}Y9#йՐYJJc&:<.q+*_IRrWxP)/a %HD#ど0Ç!oi8Z:$XgPdzH&v%$ OTE&a2kn{V-дچZl  $11Dɽoy0;E*.euv` (a$"ެX]hw܉V{^H=%ȽCD#BS0AwNm4Me;v?&qx HD.Gb qc8X %kXu)`Dp܌`L$w(b`NF$ !p G&/kF!ޱ^f]C=RMHeHɽ>45> 2x=MC IM A;|^gQAьT}D42Lf$ S u vgaJH3Dp~\ XCЏN-ubjzQ". x a΃C/PH0!@! b`Q`DdPSIOx#eN8*|~x.ag) }&`NR ~qn]qH b]RNm&WamnGSՖWĺ4eGX;w5deI]r9߻v+tfe s˜д ޅ4>b,*1/mǑMp7MB,zcjZzژKd_= pf|pqT"#Zfa9{퉐͞}n[iڏ{^~6)Dr5f]?iI|y$a&cs ŗQ,#vE^IIbjfWuFW ў֧o@ k^w7 Nm!i-ֶ;Z 2N)%{Gq;кuVλ(;#C5x4_[>qāp^РܷuG6rJ2ɽC\6pԫ1]Z?g1cyЫ tv.׸!u_Ӱ{3$ *d/ ޱfg$bCT]9W=.YR$}#JSoq6%~J -P7D݆Ag%;t=̼3{mCxNC%5;.l$-5EG~'Yi?n}&"sY㇍{Ǿ Yi;q ܮLcEMOeɓh Dc|28Dj9Lvh//,Ք1hF!mzrrh5Ź (*t1 4ْωJ'2uQUCq{?fLs{2|̠Вacy};ˏTS~NeST~Ypc88y=^@n4,]|J%ucN%7SvhQzfIvyӯV|&g1Ir'O-h׶˖ysur: lMIoْ(c3`b5N:rPeEաݿԴn=v9rS~NM0`!nq~FvRFvJ(UPaEAqAltn=K;Rlۣm`ZO1QJN9˰13Ҏjݖ+J"ɩC :))ICF p<{(ϐ܉;JmggVBBf P + 9z%_sy0{zNJzjkeG88MƿcG_fB!"]Fv״3 ;kΙYmھVoյ&<_箹'O7ѹsm}?Qi܉4t}T}:y_?[Rh0f/.L{% 'F`&1GJ9o~zX0p&0AdRM,A ڹUI1' yօ3 cnݴcGlN*s[7ڣKfVz>=Yr܉-ӵ.@ևUzGk!Vt} H$}j=ZaKEHg`nvVIPSH1ALL5렑RҒ foveorZceG}ŃFs̬A۪{,yl TɝhwQu2-TL>\*y ahz]$1wQ2q1CFѫ[zfچ_6?l.s(^ ZX2]cG*vWvnf>=Ɯ<"#+mݫ=HyHDfui5h@F] =aI5<1 .6 G8ub^y]:^Nfݻ(/k @T={s5t#N/Fr'ZD!9Që2!zr2RHʈ*w=/ a؈iǖ]7.-j~*-.8qh܉I΀A`I[çRYi .xL=P ބmC]aen6!m;TWUWRSDNSV4{=f]f /6!ɶF٘p{=ފ=;6HHbJs}v\q;Jhv{2?1ݞ6 Jz~C{V}Ug\lTsԥOvn읛p/z$w ş-h> Eh@$M6 Q8W;t&3."ՇlgDQxаA$w NA ;AAr' A$w NA ;AɝvAɝ  A$w NA HAɝ  A$w NAr' HAɝ  A$w NAr' HAɝ  AMA]@sΙ ʜv ǽo!u:>uhE{ oCAr':F}[tfNFɩMG:G\K&$wCͿ{.x=oqcc?-r~+=RAAr'Wuscs؝z߸h91 3Ƽ?{=u͙2y# ZKyzwHɝ8.v3i,g͇\cӺF7{^֨|qyZ߉rDkң_5Zw qϟ9̍.duJ`sdvlb~?B3"$(@bh?[7Wf O]'i醘߄-Ǐ"v=p %g;^y (Njͮ E ]c6 ;/;.Q`٢U^YXt,F1MՎ(>zҲf\0N܉vӆ4]knsVGkW3q1-]pٺW[5xq1m߰cµubv#Qo54M*wo=Nch*Νh9LHU|OP?? @YcNwh~pEޟyJkP94 ouU O>'7\q:S&N3>%j}ߎo'& ,p vm:{ pE?5dLW޹0E(uOP3L$(BЕ,߸v{D4vҰ0 ->y֘˴a B Y]hSl;gŘ I/# BYq5Cɝhjg̜j3A81.QDR%m4F܉cVmlƖqQy"F>SS>' cm/;/--Eɝ8Ĉw:x#ֻlE!='}>'Nq~?Q{?m5X蠑}~*>\J_M%s J ˢ?%;zwT5qѯwk{.y䉳N΋ݚh離-}4+45ÄZd-9]O<+ַc[N9;cMٺ=uI7\Yt8sf2u|h~ӦN1EFm3qI##.*.hǶɝ sDݚ++_>29w\wa_+z,:T eeyut:;q,a`j7]l؁ң_:R7S &=?̼EiͫGPN?ݓ#NOaU&;֯yM&@*W6_{s?~Ň(!CPN?rfiv*{4C.:+w0S_]heK}O8NPNK.˘ @tU-X1dS?rVǰIDATPߋV>pvK<:wnŋ?8QE܉^j>-%E&4kk۹aR6tx_3gA>{jk[ػE+EHdvN_ ccSh0qV7>\ɪ8*"$b;"WzeN>I,x][/^`F$Zɴc%|xu٪GW=9*=d2.7s |y2Ϲ|5ќbs"LBRU^fٚJ[IYn "% ;!xpkQ(@ 8T E[N^v Νs|1oQ#"$N܉wCq߃^Z< vq܉vh@u#Θ~';AW+r9qFWA$w NA ;AAr' A$w NA ;AɝvAɝ  A$w NA HAɝ  A$w NAr' HDc7_&CgWdюꐴ{Sv-oc]̭^>( z˧$7 tcnL=wB}9Op.mdK;FK&&{=9zyWM㒇z]Ei܅ QOSG[2vYC㜿}u}{"Ҝ9`qeYu=.hN?w՜4ޞjGqAszWĮHǯ_q뫾zo} G{[f\0QxꝻcq%o|l ygӧyһK_˿<~Nko?Xݷ|ͺhrᤔ|ߡz%讻|ӑCKn<+s9_3_Vl:ګӨ Cb;ら/ }S#Nk@$&[|І꯿Ψ Cvi<{/o3V~i#~)<5#yǶ8ݥ-;/+J_a͑O~s}/wd? 1bq OX/~z|3.l58o*ꘉC_yo.zv޿;1Zp3O zG'=]A31@:@:83y=6K oij{%̺[[ In~uOӳgE壭1&˒YU^r };|u3~W34Upݗ4q7}ޏ׽ݿMfc2S_qƠkpi.yfsrOg_g\>_?>g|x7şo|VSgλxDoוs|'>/vH-=޼mo粻|asƳ_]9c4aqc^ۏWuT;UQ%/ڲvg₲1kGJ׬~ ,dkN*M"s?O9?{q&#najF2 com7_{6-39Z%M-mmR&í\m4cs̱^YX\PvPs> ٟ~ WaB0*᜗T}>?{mć;6q\?5[^%1!CF;Λz|`].XYSi8GܟM:϶UٿFUS ?\jF2x''~^)=+e|-:\ڥW%fw[bfNZYq9WNfr=ZS]_ rW0[L~dq |'Cšr?Uo/orѡ߷C'ΛY>vF??-|/ ηde{\cfn?$sUU4|O1K937}á }߼qю)h㹩iyCPL팶Z$Vxݗ|SCx\~l\#/9O22 {hUuy{yݿY-%Uד~?r +jx{eTV5|AqAeo$ڕW\Pc?Gk_=寿]@Yqe.-u4qޤSQTι$KU5v_iuE>5QxVyI/~l-bogk2-cepT-Ɯ.Y{ ߼yᤙM>; zP3ܮYgK>[G Kvo;3sa]z~_˿˞{PTUMED|HMGFeffV(E¨ $#ԑq42&#0'EhxK\geZ4={s{%#??\.Wze|W1.|xЀچόR:|Q;MMMݸi[ײk0_|*ȿH;RS][YmiĬ~nkȏs'. lTTueeViܻdJұtvl;zoȾCj?ݿЈYavBlI3?^vJ LRQ'oﮝvz^gl|.b=5ZR SkT B*w+wr]TJRj'>WWStR!d;;%l@*t=51w* *lzhjtzZҹ{CFN{ǒnߎ|}{;LJM~n/[7ȴSxxxzWamڝѱ/KTL&㛹&g)ڶ #_-gɌs)֤ kTڮZBF RDEߝ2ZXG2@w ;@w;w ;p@w p@w;p@ ;cNwIENDB`refind-0.11.4/docs/refind/MokManager2.png0000664000175000017500000006615612626644767020364 0ustar rodsmithrodsmithPNG  IHDR Y`KHbKGD pHYs+tIME -tEXtCommentCreated with GIMPW IDATxy\U7" llijnW2mT3Kq(8"J_LV4̲A[IY  qgggZ;[ FPުp  ze>B"IR߾(WT)X @ @ @Zvrrp饗|w!u$H='=|og%ۮ_ ,^~ai8DB cwm^@giXwY˂zryGrk i pRJ33xS|n]f5*V|@(3E=D!DzNd 'o`7e$Z[,:hƦuWi99OeŊk=iΖߴ) hJw-SOy;\6 $<\zI:xgeIo=8HSNp0;Z6![7[… {}=Eҫ:uTܹ{'2?*o-RAԷ/p|9 Pdfڿ3$Rc,q}{{S >r@F@鑂  @ @ @ @ @rp}*H|"Y}gO;7VO>lv9&md+|4ny-5n,tK0AڲE_jP Ə>Y3)%Eں5m8ʠP[矗l_FV5P RRX7\sB NhvIÇE2+ W^>˯[W6L.2lEI'X0Uُ$5m*-_.uRxڻZQkH|?zKZ8>GgË:@pdg>+/%1QGFҠA円JkZJSƶUmuICX? 믷W^{kW@}3wu$l)oէ3gˈn՛>rYk߮ݥnyMP̘!_ i/~6ش޽1e޻~.WZ?5hTrY߿mZ\[g3^% Աϸ\_? ?b7t f׀'%Ykd+w lsrhtЧytp\z'VIqqCqv8Ѧ_~u/>].KޕWDmySzѣӦYn] >F<3-85h`7ߴVtb˳`-p:7jdÛoz.eߩp+ 詧ڷU/J$vUr⃐oEEo.== Yn;mΫrl% > op=VrnHV榤X}w08;җ_[besR݄-:ԎwzsV>fAȰaV~&&zmիgܹӦa7BpbNH]˿ViȨşnwtM;Y5b{$,_իζ`Zb"\lV>ҝY;gg[E^M ;Oԯ4ᇥ,)2NvXGf=a}oVJwCSV$)?ZBJ; Fz߻쏳 "!R^笣qcX}, Ewa_rr%m[}B޽{8Wwae 7)/K7)K7˹8֐ç`eg߾J pr`7XU-I* h,_W^yjiN  Z{YofEuHoܘ`f`o""w`jߞ8.R:)X'AƨQ_X,?-Qx1l+LLs`8`ߏo @'\{V|+GVt -V"P^jURq63eI]yu߿t:6}/nwׯo6+4ZrӭunE>0h֬f!ߪ}kgߴiKζ1˗K^[N ~ezDwO>)w^: fג. |#l .Z- 8ժee}r7 ,lpuLL)Bp=q7ўdFoTRZ;G_ +gXg#ln''{ 0G:|] }6a,OIc;oJر6"ﶌhNHjiJTBCmt#g( h`nb4x0!x%0fCPfl$~҂7h9YY. >t+,JkWop w*N}@m۟>m x풼Cv`=I2pXc}8lIzUWVmd,?S'o;7Q-پ,HXWvaxl0;o / c4O|j; n :.1>g4=,*q7&? o#`eCq;?δrʰ!C};nX;YjX~HXqqv] ltx+l=w$C>\-h r[7oߏILs-=3r0AW۷\Q{LP9 b978n{` )X*ƍ-I #Ɇ C)X@@$W@*Uݻm3ϴYJjcQ}yyҦMU|{G )K[ٰ|ٳI^~)?=%8؞AfΝ0w l]J7l5KIJ~{كSCCs?Ø1/<1ĉv'5JmCQm1zٿl޽+l̶sY`Yw﹧6m,+m@ʇ-y`mm;7/߉(6VZnj@{0Bǔ)ҧSSBTv?9cOwXT}6*@P'o4*6w)X',).N: o@m% z<ۺrW>:twO9*s٫,[f/TI̒9 A8xdfZ/҈g-Md}E~ٿ: r~I5w4~-3ٳ/RR3jIKMKCɱi~+g.Жi4oiG3_,}^ժW_:qeĝm~JWv~L`m4y5H[~$]y-o:KAD~tURh}E6nfδ47-h[ֆ =H5H҇Jsشk ^{Mz=;/m}ԻF-?_ZV7;a?. 4i"EGXY3OKQxMKqxe^|νC-mgNw4x8[nwժI\ nRږ.V[z,޻N顇3xYnmI99vM b_9rrWD+g)XAA]nm+{^eeIM'xv`}ṮT }{;zюKpsll[7{\AwnɦϘaeBqzs`H-,$ʍ?E +6ns[3)$+Cӿ>RS-UJjfVmjZ9jemW[gb\V~sn\A,Ir++O+Z2ʢ$^].;|Sfehlԣ;)ʉ$+{˭> E+Ѷ m{խk\ckזc|vN;WJ{waw?RS5mx(uL,5mj+֭V ^-[lo*5onv*"Mfjn'ϭZYE&2*Oj\r]=Ϟm:w*>*L > ʬ3yVm{] q=UwJs7 ~HǬ"}1ndyL[߸qv.!Ul[?6m*ܗc4 ?S7|T RRTl{ߦM+ODŽ !v-'22CoۿefmV^x׭[XĦonQ:ul_5ӋcyyvK+3εa׀5-@`zu ht> 短k1iUT]oN`XD''|0HNJw=pZ2ƏdTo(7kݺKz}{U},0u+-""[;^RGN?{c/t8J'_~y&]' 4)w8vwh,w do M dw]c?xᛂUk-!{ζ&>s+&{G$)Xkڿ*h Vyb/+u~ܽ+rr,꧟w$m-J-zN:[]\ Jg-œ&YYVHbN K5kZ1! ?P\`gy;E;tK.⃐.f?f/u<˳>܆3ǂv=aa5~ׯ~',8,pKmzZ8ٹ\vc:q`>$ُwNC {_(N+:\sXu,u6RY.KڲP9\wW]eѣtjmhjL}w٥b['%K{NwܾbԲeEDXk+8@:W.w飑mF˖Y'flK/=1oVmsZE t6,cNUҼi4giXw7;RRS|ѧ_ЌCY~p `4ou$);> 6d[Ϙ1Bu4e4xZLNRҊFpwaC1:P;ii/]gC:5/F܉^;Q#K{7 $6l}@lVg(ܢy饢7^P`5klzTUZ5K=> ժYLAIv~#c*ڶW/`w^; 3ԭW1ɶFZ҂8WVԩ +hXAAvu #a9C?ew^; oVXև&+;zK v}1zrUl}ȰQ>;|s>ax68F'#sxXjaüC3C:WWûg]{|lqhV֯_ zO:d4u]Æyݿ/g(^ʠCmar ~keeΝK.;dםd_ax ch'u'p揋`Fw2y?= ov{qq% QZy_P@ &[ -I33ۗTFynsY,D{DZ6z=o*>^*XYLfN Tg~,R6GerZܵq%38(,޴jh` + ʨQ'r^K#KH8 II)X~,,Qj֔&N2sps IDATq+X칹W_RԶ^Y\}I/}4gjeB,X(:u"m}خgO{FMժ̋?,gٳ*&O>99._|ql#! 2 ń ܓwʁT l6:m>G²w0yztY8t4bf{0Ź|M6$ּUk–߾=Ǻ(qx,,YbD }^]>3 ~=k+;6ʘOʳm=Nb~wsF O=ZU0@T*҃V| HQN' @" @ip魷C _{ի텢=*Z={)cVm\P eD;kVNO>|c}fδfzÐ|[{0ԅڴ> X.-#xKB]K/mqkVof._/=w͵4}Mڳ^:#S͛Tz,u /϶XYcQ4l)4TڰA=+(|\{ݾP{⣏7nlaav`IkI޿_}UZrဟ~j4|u0U"l\˖%|y5iٲߢԵ=饗+-[J;<\zg[wJ=dK<#bv]HAAṽ-gBW2ޮo}>"~ *w1![Β%v.mk͛gǵ];cGi\K}ro/}@C۶ɓsαUb[;oϗydTv#2қrs˟=[Z־6m췼vMMjڶyݺݳ\.[ 6wo;2EvwIMwӼkha o|RÆ~.[&$y,{ KoeMh۷oi~cX.ټuXlߨQҎo[b}aawaXGK-VIIvm -sw l#Gڵ,,L:T'{(8`#=~gCX3Pcc>{$2FV E ƌc$X "\)}UJ֕*PX};lEnT'$|by][oI7J.zU}[Vۼ.6+WZES'{ʕ.]oԹG>6YYVy޾Y+v[>isub=p:U(9G" J~ŶaJ(;tx=\}U?6*sc2޶3,.HH %Gۆ0|}7>7mjΝvζ /V:qljjxj5wv˶W774&M3oeAĉ99H۶쯾~V ]wٺ,JgV >"#ŋһrwjdJeb'(*QUXܼ*],Z+N[ZPҫSXkWn7d< WkW;O\}Vl9slb ԭkgyV6]koq5e̜iٙgyy϶_m|mo>-nž lsϵھ>Η.uԪe?o .۶o8ny~[ڽۦ}U{qB+W;wʕ'G;6=frNv>eJJpXΝE!޿~$aaV_xÿ?{+!ZYzy]""岛o}t8ma\TTeÆff,>ݱTn}2Jv0<'cs䲿 8a}%LZ5)tʅZ p.FIH(e[:ٲePRBCCsZu\u:~aC#U27/΢JӦNVoe {jҖծ^V*=m_%^|RT.]c 刊7jT17&~n-8(^NxT&,T5m*Ul4xKorRzmq㎜l$$Xw[C)Xûi36U#3 1W^iC'8mndج[2zcCBu P|󍥮%$H-w0쟗gF4BC O>X^z!vKϦ73I> 6"ky6jXxZԹ-\ ^wʲ$m"0:q/*pfwf{8-<09t lmlM_tFw6#)S ?-Ͷ=:~N9;- 7%%ax @m <|og^K[9Ldװa&%`-_$0iPG:m]#GZ y$FSeJߡxk?2,cEE jւ+j񼑙i}rpnh;JF|K: /P973n{`J宻,MEY'$k)-P )XR94+"RhL׮>ߧgdx4۸q)X~ߧ"p?n/Ap2"  @ @ @@ @@  @  @  @ @ @ @ @ @ @ @@ @@  @  @  @ @ @ @ @ @@ @@ @@  P.-  @ p+V"efJr`˓9,3{`8f@  @ DxPRO<)i{NNΓB1CZ6jU͘1C}VfϞ?C7o<Ӄ+""BfK\.fΜ,%&&j޼yR||SN9EӧOW^^O 2vviJMMUlllӦM\JLLL;5uTuV, 6,crg*##C_4bIYg)SoUrrr@˪Y&O/R5krrr<Ӄ?h^x?~nݪqy޿袋O?TiiiK͛7+==K/Tiiiڸq&L I4n8}ǚ8qb@C5ydS۶mZ| 4=OQ~}%''kz7lPmذAg> nA Ћ/ŋK5kX ZdIu֪Y.\Xf˼ջwo-]T=\ѽ{w͝;WWtt-Z^zIԦMuM֤ޥK۷OzJ/asΚ1c{wde]v]?^y"wQڵ̙3;N:e˖r)33S^n=ԪU+M4Iׯ߳gO5ksq\6m6lL޽դIriʔ)~7g'O'|yo߾曕M6}>::Z7,„ ڲe﯆ *??ӵuV{k4m۶c2h կ_姦j튋Sݺu~ϴ1c諯R||ԩL5jv!IJHHPڵ9r}Çץ^jժ)))I$)))I\r89]v͟.HaaaJLLԏ?#G /:t~bk̘1:tAϼ_s=38޽رcuk򼟖:˳p 4H[.==]5jPAAU?L0aN;4X矞'Nԩ)&&F{L4iN9]$)##C5jP~+r\*((\WIԩSuꩧ*::SVL6Maaa7$$D}.OPO=9::7;c x71sLUZS۷9/IfRppT}={V*]( jժ3g4srYGXX,XiӦ|4h8~)44TUF edd(//Or\[VPP߯ZjΖV\\:,M4ITzu͘1Cbbbtgz꩞թӧOO?XժUSA>5}tСCuG 8:u{ 8P_|Ǝ+Iڽ{ K.Þ|U诿Ґ!CTzu6&''FUZd#ƍ+TK/-TQ;v())I5*2 TڵK.D *4N:JJJ*|YFs7| &FڲenN͛+:d6lzJ}9\vmz԰aCTnuCZJ?￿LիWkŊ:3|r-ZHݺuS֭|_s=37nT54sLnmݺKkʔ)Ou+##Cn[۷oWHHݫX]wu?~lڴI+4i$}:4qDnm޼YƍS͚55x`5lPiiiT^zQoRRիo߮ & .(vܹSrƌ#ۭ~I̘1˕Y~ U^]TDD_UUWǎs9P%uܸq ~ԩSUFZj)!!An[ݺu+|ԬYSC /3fSNg}vս{BYg8Cɓ'%Yf)<﯂r BrssճgO 0龭AMhh':t'@Y+Essa|.lcvvsj̙E6W1qR(((PxxҊL^J%~AU^]G>fSiI&i3f$VZ8qF B9̉,$$DvRddԩѣG>ԩS>m6EFFJ*9R: _4 >\5\ÇK'ٸq222JUӦMUPPkÆ < h4iHOБ͛7q Ӌ/]vvڲe~YFk֬$tMrjҥj޼g}VO>$oV~TPPzJonEGGkŊ >n/_+VHn6O?~Ze˖K.Je߾}jӦڴiyɳ>ُv)**JoxРAzGյkW=rm˗kСx͞=LC K}ѣ>w}3-$u]~wUmڴє)SvZORNߙ &h۶m޽{{ N辕wr\Zzu*|;r\e> r\E].W_+.KIII矕 >h97n4rHN % rrr<刈SF1c(55կ/|jjoIJJRZZRJrw~߾}~ oC;z:Ӌ)SN+n$K QtttST,:WJTZ~@ի1peff*((3UDD'q:Ϝ9P.Gęݞׁz)i՞={ԭ[7IR54m4=#% Bcǎ"sUff_*55Uw^ԩ L\qJII)#??_kuP^^4hLw9(X6m҃>X7iDM4tֺuԡCI__&kjڵj֬Q-o]nժUjժ~,^PGxxVXQh_"""4cŊ`XqZ=:wX(Xٳ'D{WT+˥Sz~iĈ;v'^m-;&&FM6UJJ;~!ꫯ\.;V_|︸8EFF 25>>^~A҈#_kȐ!`ǎnj :T^{D]qF4hz (11Qw.gtB:tv)R&L~vN:JHH~<}g䪟~IǏѣuթ"""ԯ_?  'N̙3ջwoQdɚ5kWli2qMٳg{hp̜9SsQTTfΜP 6q*N0rhUeo߾R;$qqqxFo*!!ASqO/}RݫxuY6,$$D۷ovWzZᛂU%44T|f͚U7|S7nTf/7"`}pz`ZhB-Z𫰟H"""t"`9ǣrRű BѰ >J#Ҩ^z"ߋo={4|pPG@ۑJqiT_)==3ƑnU6e~銎SQ8w]?x̙@N9999F38CӦMΝ; ݵ8N jÆ e~[Fkjڴi~)X]^^֭p)XeiӦ8pV\I9[5Rlly-Y/7}ġ)Xq|]}֏^xRm۶C=yiժUj׮:vX!t>}'2p'uqz#2f̘R:U~}%&&*++#\B;A Rdc/## >T~7k,3H;xz EttN=By8:K%zaEصkz)))阭.رcK0ŠuVoFwwW^%zayxxbCwy ql;u˗uZ^YE [Y%&&1d]uUORӧOWXXXuF<3gTrsWae{r<ڻwﯳ>[&L <HAAA~{zGӧTbbN?t-ZMYYY8p."*""BSLw}yGGZdɒ5i裏ʤ#??_^x-[nM͵b =C+V.۴b oUVeo>vmҥk*46d k[lJڵKVR@BBB !% )ȍҥUꮸR*B4@Kw)^p1LB|8֯_;㢽0p L:z@qQgu]}+ +cԩ9}";;Ɗ+Y|_%zv^tt;U\\DEE!55Wx^0XTg$b޷k-'WTImEfDEE\%9** : kzYY4ZMk;v x'z+gGii/('|җĉ ή]^Ǐt%%%8|p@ ȡC|ݺuCQQQSScπeSuu.Caa!8/G~~>'GϞ=QPPǙH^tR!**  Y % Okx+Dw}ױާOaϞ=Aatt4y[-~=^?Ϛj^7h^׋*KXx1?W^y\.v0`Ok7P^^O|Τ4h/Ā+؈͛7cǎ7o6n܈;wb̙[⩧r|СC n7lKےխފ4lܸm!556lu|1 Oƍ~dee2_׎IRѣGqqqظq#y>MFV?^EG>A, ]t"55WpҥHHHmkٲeڵݞ+X!B˅D,Y$ht FV0&&'OƩSPTT `Htt4ϣ]tDGG; )X,{1H$&&uÌ.@ uuu!ž! &@"d:tć4;= !`ܯ\.fȐ!t-!: >LLLرc}nPZBHtrWQB!D秲]8"DX!2*l'B!tp!B!8'H!B!*$:X"Cl,PV;dfO> 9ED@F55| PRTWޞ="8q6t {([7` X}n@Qk(,LH r ? ((>hk^ˁ,-(qʁ|Xxm`B~Xx- //p>}=?\]%K׿عhku~ 'C-nWW^np*>#; 7_mܰX.|u|6֬ >8/A~`8hlk/ʀ})`}h ~'?a_<򈵽Ǻu_9f8a>ȑZZ|Q䌌}s V$,{ux_FGs&N 0}Ν@b"0t-?}$%;ۗ-vdছܜ9^Pc f+OsEy$rn>**ɓRY0A-ڙGy9󒒎XLq>(O\$S=xxLm'";%Ӧp7ut駼A"XMHqݖqklRS v;)ӗ jQ|Ü:Oxi0nd1}:ρ9ٳiϝe. …NC;&P8͚ \T}9{ζ[}}o=zoSX~;PF?%B끻z?u pp42]~&ӏ<<@xG~=瞣PyQSOF x0aS1d:=6`&M@PZj֭K 3^Yig72J^˖[Ш8)(ʬc|}.n_R¶_ܧ_r 'Z̶UU;>mpwXջ7dzo}ci߳cA^4oȴ k Ͻ9k޽s4,`kݽ%X̶II'&o7+t^qqJ?v,pC]9Z6TAm ?%>ʴ}Řnn=)\c#s~&#mGy2\.6[|L 3vmC3iil7|e{j*ۍ؏{ )l 7"}HteS[y$'F}S=ʁϾ" v1{6;t +9zFGQ=[ۗ7!Eg}q/ 7eҙxY -[:|StfDH~+pmf%FWD7}_EWySz:`Wg~TEܬ*|ED|<ǭQQ&>BxqRU|\u횏?/B:+#fu-юnDGKS8KJhSOR!#^EHGrHT%>RR*!Bao~L9De,K33g$<θcs./b>_8ǎ= vbܹ#BV?:b`.8\yNwՏpRt4/q `_ڵ\g,{8ٳ3 VQ_Oa|EtDII(&⣹6!N_t*Q$&'@CܴQ4e+vS\44$BDq\ uwo%*E[1.eSb?Zg?Q|(]Vq5׏Zm-ݻف-^/gA8?64P0U2qx#EjC]>4BWV cnOo蟞x+}tYBm4<46@8/|kk9ic. NW#\bc/g,׫:e}\9x%>ƥL~tILo=v7 wwg~ Ƽt|Iя(j CXs׫Sx~~{8c31@fӟ+d cZ~;wضd xA[W/eӭ]73g򚦦r&?eeFMں(/VI:;^')8d SXȁb{q50[ wnҳ(JJB_6K/VI^^pw+{ zd$gC BojbƼyuK˖/67_uӜ91?>b&&٣GSx̛llgy^\yy8.g@,kg[\̙*oz>VY"1R_O!v4ԛo:֭(l_#%bWg?8MNf<F|$%]wYq45ML3 <B!8y^c`Z7~ PߟNQ;v,E{9Z#G҈-)i{u&LuYBڵ_ر<mVL~>c nc˸qۭݼ1=:<oi|LVTNde9gϦ;Oa!3V\%uuVlc|<`nWs粏l[ܹ< 8]Bq:yɦssnNrL2K9FWKqM\z3 IDAT_ϓ^>qqx3[BJC5a|}g$@Z;h猩8xV֫xK@ibD}f_E\$$8OWGrp{YTęPD`V?{/ij%ƨ(ڙ@A>V^A9GC?n@^/lUT[΂{7gCa3+'@1n۶1ٰeKlĿP0qq?Ym`=) f'?,Xfܨi`ΛdZm-wsyKfg1Vr?y2]Nx!]?- t3yd!xiifϝI(Ϟ1[4>˃Y'1]~3;c~{})qJiI|̛GLZӧӵ0nWU%hvt.էO[A藬1ƻ9.W'woVIMkeg۵k`+(3wo,Vf&3xuԻ211\230jP[`W\]툎f]47ov]·:v,3 VV% V[;`QԻv,s>!bf x"Rra+efunPd7DEY5+ i6.:$hD'@RSy]Pc\h]2:m'XDE=cO8pTŞKK]O4DgLx.*b|<[GX\{-g䪪 qk6^[ VgϘa`[nQ[.3qgJSS8v,.Xg|gV-W?6l\?16mH9Gk+S&rfò<}Gwg9a.f^`/@td1 Rp6 B]q}M]S5_Ǘ3t}Y92qkTWsV_qY=?qUmVSǎYhh`gR^l~;W.~O m__b~tw[8y6f LW Ç r,љ҅嗹*o2 =p,_C3RLw˱/ l11Cr2W o >ۂ5˪n^ = rgbUS\c?22+'-n&XiS+Sh4n 0aJU  L_ܺ[E/t: R^ µg2\gjk[Nv%X*^ RVFC;3c^e|5ʱ/BLeG(n&ǎ9@Ts, e3ܯggO~N(7ogy/?* ٳC"sYYq^R-^1vVqFo:W?yLm۬`\^իe~ss-+@e38X|[tǁ SSC(3;I[ScE#j=R_:e pWn֙0TV<ݘX;%&2wF۬,_?W&3Ӹqe}WT0[& |Fg[瞎[0)=1}O,>? .nMVb {~5jWobnzPinf]LfI1s?#G:]L_Xt2ix'Lm& #VNm۬4Љƀ3|k3/[fe2)ORVUU8QRD>&i3#)BϹC{5; 8Sz1ۛq|K>`edXvپ,XL+_CC`FK46r5]}{nգVTXFDFrƶ˄ '.#B;"Dݾ]Cqq`&Mt@1 BKC%>DaX s!`p+!BK!CEnyw2!䜯BOeUM*B$rB!BH!B!$@B!BD!B!"B! B!B !B!B!BH!B!. :zd$PQ+B!@$& !B!#,!B!B!BD!B!$@B! B!B!"B!B!BH!B!B!RQ? !B!yAD!B!"B!B!B !B!B!BH!B!$@B! B!B!"B!B!B !B!B!BD!B!$@B! B!B!"B!B!BH!B!B!BD!B!$@B! B!B !B!Pbt?HE8p" ".:DpM!5gЏjj20yJ'͜~¹"r-ڿH5" "" GDpy  HUrVB>JCQ~@P E@Ĺ$HW 'k"E}@>OW}9D` <苄ѳ}xd?Bpafj̾G0,0J@ȸńesM6#"!W"s- &44@m3̈́"xU"/YQv5!19\E;\`'!c@䩃\0'd@s>UT$IHO6 "G@-ƑUΐחSAz@ϠX Hht2 j!T:Hx#|b8] (* W@..(je9:Dע̨!yC? T%i_y!+OZD_!_D! Z1]+ץ琫jma~ʢqDV S.""r@?ջROi8_-|YHu)Cbd4Qiܐ&"7=Jַ ѧIQvS@=d+Ah2 sL 9CM"0)JFy$q=N1Ñ!8q@`.Ӈ**'Dp!jT9g1%G"%t9<(=ID)[!`0`DcԊHj DHjS@\}?4PYti1=O߾%ˤz6})jB0AL@>E5Ȝ/} +OM}Wͣ&! 1ɹI*.$19Q0usA d7YdJ^zHJ1/h8AUC-P:zȜ$x8_a%XT*73ӣ^ D߯HNf%y+.DR N;@{#r!9'N(!TZʲQ%~(YPȏ"IkzlEZC4NFXBR D\XX3/jCv,ʹjҷi =y#Uo)~ ?;B]5H8 cF3+PE$O;7cMC>\d031m` ńK,'p%SO4֥Zʍ Ԃ(RlˮBB2Q \An^'Мz&)*~JPʩ2hSQOa&TOB/bb"D!✹="ΐs<S9CNm< V*T6SE㈸!"0& 0se (REhY4L }v!J^@S p8ER$>I;StRTd/,d7gAE1g\5}GĥՀY_#aJS"%FǪ =fr 8e 1d UW!Nhzp2歔RʵnDQ9cU>hMw- 賛XE0CMX-%ªՇ6+k/%Pѭ ԗ+@@Dxq Ljϐ"JǹX@jU iCڋŐ?ۋ5 NiuBRXP4-G * )R߆)mzFqjV"(3S'0j L`NLBv,$)v#QL@J 0)Qj!Bdcjqx_VB E'4bi@9Q̬SB` zrC[A=3a-1fmivӼ6/V()b`h ߴF.C`uusP0AfJ Sqv3\1<˙"^T׿ٳk|eѧ1BߥGتtS`JG\+謢G3pM9i:ҤK!RCBF@!1N 9"InÀy2!Xx5O4M(I8pdA.8Da\hav%[Ph_x [n>R=AH阈(T9z9(N[oPϺȀJ TBF1p>co'mE&pnZB$-a/Bsc1Ǎ917uWu3xAC~pC`퐢>>zz"qZKX'U?~Qy'^+pSf=C&crϯFpRM1?:=瑻~];r;;2Dq+ճcv?ݟ*0γe{^Xos ~۽.xm|}Oا}ymeּNJ\~r C.\>;+a[}'{I^v>tyJ8ً4-z1d 0p@qt=')2'3t鍡(Ȑ G13iL ,Đqq}rzP3_X ty>@&iRGd*D n&3/)`(1#;e ]1{ϥ "Cʏx,c aw+_&jDI@L;V=P6siP8p!\#DƆ?ï=(̇P6 SK:x)e54j1*v=` 0ߚ˗d, 8~MbdNiMLk~ |S+}ֺBu+}vmNMR/5{cs qsX܉Ș ,mdM?tq*ĩu+aʿA/OD}λ"9=RMQova g.z{YsHټ> ^}?T}\=uI՘_]_ O;t2 Sg#]U^L:hx`U<8Ww{VwJA YWP^XNS|tN^!qQ1a[EB߫=8zVA9ᯫV}*[JBzFGUo|o&/9Y0Yo\%%Iaq})"cEuIQg! Ӝ4E3-`1%ęVBZXj@"" .DpDnLGXH0M+KALoݠ}d,H j)({r-4), {Z7K^}wߚ R^x3'즶(M_ɔ⡐bQ2N 5ce? s0 2 q#|b#n֔ІKxz#.yp1^s=dis~/UYuow bE ûC|{dqmXï:k~#U8b$X-:jJx};{-#+)(Q:;^> m9" ӊ^mgwN(r W/?\w~o>~>n?a=>qq=}~q..^:lݛlcwzۣե}^zɵ\wĽ5⧏wMyLT%d_zf )D4%flbAKt14YTGġ6U}0B ތsW$&WF2i 2/YAQo0i($1c+]J;ҫA!X)5AXh0-_zԵ_"ve}|[?L&d|';pȜD|WT.o:aPmdLh?)w!Juinl8)y,`%? g{O{*Ž>^TWK</%o4=v梉0gUgN=(8[pBK Nj/Fb;mGzCzV1>'`ŧC)@WOk_n{=}82y"P- 1r Gl)\z C/H"hfjeO C a_N9)}]}Aoܐ^sWG:WHzr*ɟ*4)r/4kLr`9Tݘ L“kז95]/JfMz'݋Eb:rR L]E%]~T bANLFq?z˻SمL*>Koke1ַ~[w}{Yuޕc_8iMzo#>o/> (ɢæo5+Êcoگi9~`Q{ΞvA' ur^z}?SD2a=/mw|}_?*8sK-'=ŖWTrj'bY'_Kup1שz:|M#‘-[B݋wzk-_J"@b !~]6]#ɡbf?iQY9k'.BQ){}ԾwP;Q<òv/0JϲvR nO`M-for悱,RD ICr6\sAf`w;zQӿttPs(]oRdbb H^EvFonDl>;6~3g#Wͺ^<vQDU\;< J54Q[ky`A;/\\#pT52Y|t~E"G1%/s$ =p1'(ʐ0zbR)LX 3 @bUZ BPW]F*lNpgDPK2BQ8DMY{MsOl]2W9dc ^Drv8̅Y%"8^iB1EoRq\͊ w&CA1!!^X(&]#\"pFSF ?yi bH|7ip_w_WCb+]01_|C͇ͅM%XqXԶhٓo/{ew^^U@xuiz[v)E8 9vczY8`)[a޻oW7Ap: =:-G;h-=I(Iq=Log1_p#:k^,u\mp.;E_n-OΥNj~uZ*P< 1$M\h9H8~"pC+K۞q>Zh<bH."8 WZbt<|=0r\^g\;];,`aqqq],t1B1,tYPB *p (p @ˠQ)ΨQ )<88qqob8T(P̡Cqc(s¿1WCxy Z3#(K.ī! "ƠA( b ,0D5b ⣃u@.ʚgX0@_߁8B,ˆ}OCO517'ǘ 1 1F.8RM|'_?ǘ+W]\G@bcT[AKS*l{MZvdRYOߴb%1)E?wQ.PwAbq)˞kz8EC?UY IDATapzH` cp7|&<|pKeykۯO\B˞:9I`IsGN?QM=5O}o2kOQ] 's\q/T\U[c@P՟U!M杏g/r YQt1 C_j}d@0zǐ'q;D nQf:`Y ̐WKwFB F=c6MP_~s{D\sG1ĉ^dȔ: iθm=N' R[tF"5Nˊ5. 9wэCW/]cʔm/d /9';[oK /܏#;BtHPqH0**@\y٫d9iNw2 ;ED'BEO!vc)Fqr tH e1܏mǃ t52Vh֬ϵ+CtvPC"nb  ]ͅ#"mB["~ll) o15B73.;2,RR@x>j < D$:9c-~J=Òi8(H\"8\.(Yr=35hP\ p?SpDQH8dr\C`,Z_ )qH(IɘKJtU- i?Ak \Ǎ,x`:MGme71 v.c&sO :/@)o 740[C ݅& 01dG)-}ՙs?=֍Ĥ?A$p1TQY6.&axgqVFM#-zóQXYh(k$]=P8Yn#V]1r'aTza.s.s+pBN/Ƣio-LLHjrJvb3e(:tzp)%0d$83R*01D&n\P7" R NeBs3.*pFHf" sea_:+ݒ*2; 55n#=Eag@G1?XM0hbus+p XGdss,CeG g@ᴝA3h& BJry :j[^-R,772☟[EosFNSf7଺ķI 7nQY\P>Yq 8;hNh5DDqQ#&c6 o&c>s8l4@ NYd. fj>8DS'L^Cp(ac*4VdMUaō%CruʶJY8 V܁F;!kv^TAd ݀HKJ4f-Onn?/&4K H!]IKԽ+\T CWAVkXc%'BԤNFsv?( nR'@"5#u[_ܔ[@$dJGMTe@^p;Pue]rFto I u9y]}<6p]s9Pn[+ȲQnYf(cJpfbfrq=XxZCGhG#͚N>9{u[Yovx,17J9|?JʸFx͂bt㘣%'3$;;_Qն,,,F9ngxtƉq"WX=Vp)<3w&9Ԧ[XXXzjN`0Jss+Z,,,,F'.@nJm\@ -YXXp 9HyEDDrl/!"o-W:Cϵȍ{̋rV_, ~w(/-ηd1f)Nܱ*XF Wm! \t^My[FODaF?b[*_b$5ˏJ@nEttݺuƏ?ڊuŶyw1InّGmU!vsOcY mi)f'?#CK9Bx5Nz:%9{)~v^p33*UId=-P9#N WW#Z3[c"J,LPTⵝΦ svalFmțyEDS#K&Q[44Ɉ׆rj}OcYYuu"bYc{|ӣ[Uۜu-;ea#mam5@BF*=0dAmb3],ۦn[%{<Y{'{=.%OE6A6l=kKڈR ]Y:ěiR""Teh'.jy\1w}o\t]W=tKe}p[=0 :  /utRB8봽#' LK;kgsS[;}ҤILy2͇' '>{>?}^"gkI4@ÜrUiRlOkKggm-= IJT>L-T{'|!&M>wt}{vR[;>{v2[J]'uƀ!\sYe " \1cc";аwNy/zuٲe˖z^KU#,9$Zl٭޺LBTs^;JϺ}ެ>gfp'aqa?_;e^;#}dlUm;j"$`r`v$x'jW}.r?KDO?+/g i{C8K!1ֱLSc c_11W?Hu5ȵ2L__yk#>_cѓY>ޡs/8`mAsN?qoo] kL0!H;t~k/ǼEǞ~cow ƷG^|xc%]0kC>h, m[rAB~Jki*֖Β,HL-\H@^irƲdw]>RiJ5tKa*Po/z=q~o`'=yQS]vY;/O{Ll}wAX,jӛaL|& enfr+ÓϽT?Ix>/>Ź'?Yleo{vNVq}yĿ{o%/M_WCr[m`6D͂$"6:ʡg9 0BmhKR H6$X+>'|w^7{PW=o[>XFv ق{c6d \⌈ qN@==9\7|Թ/O/=7 `yYqN}Qթ݋>}S+TsOr>xbo^<sN}t|?8dlJ\:jGJ5 0utt-3xʛȼDRHusn o:nf*?i/iByMoֱ,"C&_L&v9y:FcHܠ+^n8kO9a}k~;H09_;krah2fuz,qEq{Ae) *ߝm%m,>9 )e!\Woo7|U5 'g}LΖʾ{D陷Nݿrt ?jncϥC Ϛ5[a&l7Gus#/tσ]r|0i()ғOA8mm1'7iD&lmn̽r9D<2".ZY(D,Fq]ٖAxy^z`$1ƹ t:wNCPCCj1f-<@c^sEO#2JDj6+ٖ HәLfݺu:t2RD 9FCoZ0J?t"tm#-%nD5{ժUL&ɬ_^S2碂pa\b t < == &y.c @d2L <'N= @auC-YXXX "Cw":c2DdlmYXX~0c "&8aXL+YXXa+Hu1q+:@;lYXX~0'mcR8 RilUfaa/R[ lmcsAB` ω`"/At\E Cd\=$ɒE^Pu0pD$?bCT8  'D.p@-lN9xL܇D9p%!p)"qD2qN'e6 8 3j(rN.4"Kmy"ysnPkq@fh^гrF2ɨ899 n҆9PmmM)WRs$@Ür/$fTF1v IJTn tQ˛zA@qdq)Oި2亩0=P;kX\U>EC *xČ?OԒ/jhkZn6*!ƻDrr:~EԟQ ` .QADTם sꤖJ7Hɭirۨg>-ZsʶUZܘϬZܸrFԒ틻JZfpCܘ1Ǎ EL<ĉP[Q+-1R)B=-Rݝu;e+oJ5rq/idw u)Y1ex@BY$jDZr<-^P]:\w%]3P>dfQ)9C:n,nucLD519Up _eD͂$>g\PK@%Z9y&TQM 姖tV$"@iF@C!0\w^# :?8L-~!Z<^ YS]\歲~XYZ,W4d/X!e1'C`"8:»3zՎۻ?oAM 6P<ː"HND&w˃^F 򚅅E #EWR! "/5 F@ IC,,,LnSV6"v57H.8lx[?hMp\vI)lYXXXlȆRpw+V `6(jsQREImH m(RZ#f`B5 <6`6Dp] pyl |77W8{" t6btTZx"ԁ@U2GJmylD*p a(=w"/se2>q33$?q=ee=zŶW*L y^&fb9LD [ڐiSXnYl0"X%j誷bO֮Y^}FX#M,h(QabtTldf@dc^H?߰Æ>[֯g"cȘ %&tvp^jjX%-*-NҮVlK]fݺu˖.]tx_~5. >dqiTijKڨ,9}F~)");7Qm-Pc W^n'| D~kVsi^# wHuw l.mHuP 4w&?[}k֬O@[vՌ8'"O!es>f? "NŹ6J5tUXtUPd}vj"_-YҥK,tɧ_~͚,<[a 3L&8&>aYc7JJY`m+Vo` E~Aʕ+/_ي+W~u,Ng2k׮]vݺu֭d2tzY~S:jҦD͂M"brAMK kR*tLMHM)OvL Yq2R;!*}:X!h]{Fd@R[**]Pڐ(j¡A{5.im4W`VM I5 ZIlm^j#+[=ͧ6"Nĉ{ ɏ/lV.DP*% .ǢL/cs4FL@ÁÖE^ͥ );,,,FtzBjCDFx/ٰ~EqVF# x߯Ӿxn&x #2u9l}YXX 5dL_f*͍`aag e+ yHDkEnrY)"2gaagq)(#29Cjaao6!W:8Av-YXX**?D9Cd1!ʲ#^ sݘq1Dd f"630VPPD&y8lDȽd$0T/s2UAđXFG쪨ndqQÀ*[VXmU|c(PƐ9 Lr]*>8$j:lBc}WCJUfO~DMUl("8|2$fTB$qvmgg2L)C$gr˶ર B"nREF~Zh 0( e{sĠ;M>d&4 9 ڡ$1^#-*-NLİi_ZdEd9 je:Lc^{5$>ʴ6M0dCjyeQ$M檙=ê7ԹLm۩l\:̴/sY`zg/2x,'fSեj4 +gg?ɓ2zoƝ,ΎZ4Zyf ^3g#&zzꍩ2mFrefKRoQ]>;KpQ3TnYNrIU5/lWӸrf?Cš,9/|kZ~F̮짶Ksj[U؈l/hJS>ya{P2<~R nPB [6ցՈbLJFVH}hrd{fT=-٢FToI:0I WƳ(,PMkK[Ɇk|kڈRm3]Q F-ݍ5B06;e#$j_&[*S5 6 'gVԩDMGT`ң;;}y"#MyS7JAq4Fܺ9V91(ZoאwmbbD-+E hy Yk4g5 4U߻4`NlԎhu}8r|A>V }ug^=@&/bTQ!Ǎ-W#nZNFn$|m۫+ڨdzShs)=ΦF1"ZMmhjMj&mLCw YjTlGS'u"TR`ky Gfaa1fg8KmyhD2HEj"Ll[-ș[L-,,,F71`96|XM#(Qӱ-C-oRUI?NfRDl숎X>*;oBeeꆪ@[xN;ƞpm1 APuVSW(LSg"Ce0q8 ӄwF+6rAfW<k #Ve$nF/kۆJm.La(T0I^Nr_i0biȩOScL. XEaD ,Ycm!eAͩ R kcUE0'6:"(tq1 DeRRI!TRV T0IJv(O10H6R>J Kx^SHH) oazP5߸0Xkbo5^R/߱hw,ZtGe@um535ms\.:ύ>b,a5^fjޱhZdh,|]YfR&XT|.z1cimtxYW~|*@voq\hBČ<%~=ܫgޑ/B-v9>sW< 8͞=N8餓&Nxw|Zk_9z{{{|zYm0~. sD:H4Z߰8N%NlB'V=+ytTGܷ^G| IDAT#7TOmً{y"hm߰&W\lٲ.hܹ'p‚ zꩃҹDVk]#i~>)=>)O9siswwQ}! pLnMK /<>3'>>DXkà1ξwJ>;u^} sҧ޵"+W??qzp}6PFEZc̺u,TXm|r|`k(ʩzAc*l!yNhow eu_co˞M?ܲ3t23[V!z:#ލԎW{ ν; ?{}?zчyg7rc&Kw"Oj}}k߷E9uɅG7p c~\!W>O6Skc@+B~>r\|?WgN:qW}G~_<-H Y4 Sν~? ;є ]e7`Ӧ8Wtʴ㷼uȾ%VLLp}?zԭy%)} RztGiSNĞGnH*b:}o/:wJ!xk!(7OAy0Ԏ3?q5u?9o?z\.sV|I̟?f 3_b Sox7̧׏nu6D-̿`o1XQNn/z`oΆs(nf$A (y%i&(af'}K 7eO~ @˟]^;7?Z4gٗ LM`J]JDsz=+ש$"xo^) x!wRd:I%k9 Swq{E``0omw4DRJ)Oe2'mR5b1冟>~9}w7nkʮ]*ۏ9yoցVRJ1c<ϫU(Jbi+̟?5nbyk\*=coq@AKK-PR)T:@FQ)dmR)-6G믿tqAo?o1mr޽1v&O&%TJJ00@J%9 0{\6bZk6\ޚD7Dd?0Nܮ B("j!}C1#cԩ5jC ҐuP񂀰<ӧO4сѧGB]n:}HnĹr~h[&{U3c1 K[ͺd t0 S;i#5ҹ~mؚdwEAXKGQZk{{{CT:d!k,p5YmAݾ>]P UbkI]lfvBąѢ71EwٵXcBWci6 aF#շlA+!ze+!$,Xm{: qfѲ7's^}e#Z `ZIHHH 6@uC`BQFvSO=4;^mmW_1]`vn$)8"ɜP"T2d2LKyu EOtŋ?xWcQoݾmim lٍDf҆TI)4S0%"TBQXrU)[܆4ٶ98 ;}ua.k7Q䈥 7 :)e(=jiz:DўdNgi]or#(JCQ2 `|3YmΈrAbaR]:Ku0 S/(*ZkLY(JY(JaC뜆iu(LCQ2 (@qr(JaA! P 4tx(J_9% PÙ*k-qQ6a bXs(JEd zDDD;-; Nܲ:;М8AJ7Ǘ]6M;R2 E(q(J1TK-X= P8\FK}?@^ln#< V z68+3Lpn{|;_=K/~c7l[v={fpU )) Ea3vt@YLa*kj)Xf>4-~َni_ ^ѽFa]´fHRHP&S)$dZupJWy1.GKHda}ʹ9ZupJWyqSJ)ii)Tda)ۆ{ *kdz+Sr2/<4BQ*eZ2Q(Jq(Jơ*+mѢEn㏟>}u]WngP"H!9%0u3\qLfҤIgϞ4iҼyj۝V`O)< }_a$mƘuֽmo;餓f̘tmă ѴSWa3ZoRΚ5`t-6TUnX֚Pġ(-RʸXkqɒ%N-#0A(|DΘP Cڄq劚D#յL6a(J7BCQ2 Ss*t N7蝈?Z} dHAXjFNb\(Ju___dCQay(֌`1 y"@@B4uE cԍ1BÍ%Ns'WCvVg;V@՜ eG;(DˮDk;n.[tGجP"I,Y"k|c EY(*̟?Ѣ2(duO;6x͚LU)~u~uOïMWcǎ.\[Te=(XV?БRW_}Wx {5:z~`$ b„ {; y7n\] „/.+ rB'B a(Jx,W_=Ə_p ?ϧLR+isx7]'?(PAa0KxDAj CQz3ak] 05ڈZ3f^@ ;9n6 @DQJH)JDDTP麱8ɓRc|߯ѹjÍ-у]bkmiXKZ[gJ)!T@!RHR!P (e m)edI)ZڢW1-S ygp sΊOj6XS>>i)O+@&DTD@@@l e˘1yu E׵N:iٲeCΖm{73g\hQĉ'HD|FYk|[38#QJ5:_X)<%N31y'LwE46K,|Y&Yj7{Zݨ*!rmT*XS'RjѢEGuI'4a„!r\Xy4hfܸRoo_޽FZg2lMJ9iҤN:nN-Aj>K"Fj=@kO_'NLC{:Xc ׌fCLf6rmmmgϞ:u vun)['i5k|k_hmjf3b"Nnt_;k6D?~ҤI3g4D!;KQ5._gٯզc;cVLd2h4_;=zL>}ܹ.XyJS٢_t'*%m=[p-ZhvbmL.z0`߾ޙf6Q,F1^{Q k4H(JM>G =ϫw({X;s jQ/6J@tN)t&k$mm]aaaG__2aaE8Ck1uC}h65jlE/|1L]I$Gu~WeɃ@ic1b ԗRMuG}Gm0b8Q"jnc}mZ5KwG}0!P U. 5AMߏ[.qaa!Opq3 spP)%BpGad׵Ҧ2LLZQBry1 VR2NQJ%%K0dU-Sy˴dJ*0L#9JyJ*B nvJ*0%pnSRJ%U*RC0LZ|B !P`\!0L왽5Gv!ĸc8uQ]Ji Z s~L:}ƩZ2&8_8C`Ci"KPN0|pyt*7dwkO!uH] D.ǍE! Gge25( LV1牬js3k [a箶;Tvo}M. ,iw^@! Ԋ5/m;/m߽d獖Zx>7,DoTLfnEh۾{7ܜg^o۾sPڲg?0 Ukֶm.shsKiBSD J)K4&T6޺}T5^9 k͊ G2J&ST:VJy5b}<%\[[`>m@ڔbkk@[wCڽ{4RJI%ә`y Ӹ6E8{+P4`ޥoh['|_lbVh] +FI%T KÌ~:ly*ԾsIkK\s͏:iRJs#0 ڤTH%2Lӛx͎p1.gGe"dsN2OUܲdXH(b民Jtb:jz[*uHEc1ł/+dYq{'1L.[MkcnRRJr C)}\.'RJ#F`4JZTs!Źi\B< @@ಿp0 Ӡ)(c5E w8%0KA*Rk\LJ"bic񌵘(mfXyaRI!ca6ܔR HxR B @aFTRT*N 7Q )bbfiYyRL&! $G`2{TҍE 0 !jZcLJT,`icAp.5"R.@Rr>?L3ǟ??5/3_ZsYѷ֜uZR~iYCVvG\V2vMי]D=_?Cp:ɧ9k׼#sg\@k'GD" -ǽ{4+rV;cs̘ (=9 };K`}VAm Q=؜9=t3: Ki4A`K\]۟ܗH@*4p]LhmW}ww_)4kۧo{W0> G޻S$:S{yܕ==+un[~{mOpӟo,'0;>squw.0iiijR 8s3U> {w_" P,jn!ehs k(ms=/Y[2KہXûz0o\yGX8J-k{eݲ3+7}:Wj O7oss/8^Y~u[Mӗ 9n,|ܠo|^>kcJjɱw>uN^XS;3=򱋗'*/ic//>'cb/?^)SZ[cl 5[g IDAT5c3Tf5L_> O/W+O1Kn%yҍ^aH2Tɧv>7M~ӓ`q־J {2ՇS;Ncn>4'~uW݈T@Dr#14A4!Sn~ޕgLwg?OL`L˟qMǽꔚ:iFu2>B3벵xs_?wг\`;﮽`ekwdҜ?wO&%"R)n('Wf,uho~RI}wsHefPi0#1?e Y>“:pz?ߗF]A8!Hb,BHɤH$P)L$@J!+8q (gTRcx--jҤ1JA2^:S4w!ڴ5#&k`!vk]fw1XƆ &\)[5hNڼzzӉL&O|p{[S&Kj̘DKwD@)dL&ɏ0 !TKK"I_)1JR2 Xv3݂/*R)u-( b2I6afPɤH# (߽?6]x\cuE(QGBmW^ Va-YBƎ(\GR4=Ⱥ.Y6;&,2 C lwpWaY.)PpJW.|? #|W=”)\eDt7ҥK.]BYC/3*VD _8#խ0x@cF!]!_( o|׾1J)SRJ.Jy^ H KdZH&Lx^$";݊Q'/~%N/2|cpzX=QN p页rd [`>a]7B9n<ֺu7ZC(PwdC̴^(4Fqk@" IkF/B!rJ*%R-RF)TFJe-u <5d#- ù%KFkXpHn7`"L$DiR)%ҧ2KRrfثPT ?6tYc%w𼄧RSS26/ E_o"YC!yks\xB@䆷'4 !J!0h*wwƍ/͛X/ݾ|h҆PP\Ys26~X,bQ #HRX#U"T:2I eQWK~@\Zku"!FKZ_X.ɉ6ވ\@D#:QL=/S ϐd_ b ~/} E?K)( ) ȳB r@(3 ȭ=fL7٦9sz;g͚50w\ugoF[g:T*WVV7h1=/]BT[VaKC`Z0J(%'=/aoT!oz2d > (,;n %Af*0"9K9ܛZhDX/1:A*oi"}꾜B"~YRA P`fR5s R H#aK*A *!s6jӾZ9a5F[l1vU3B[9 X.l|j1à hג[xBjz?r|Ԑ#U2&¶R{`-ϟw3{Yg_ٳs۷oݺ5:9XJ[EBt oٞ>*U} vmtkES{Ԣ`Bk}E!^pUQиaȚMm Qb m:HaWUMɸkMl{$h@]sLJ CbOFmRH|icDVhtmΚs L<'m.v=Dd9cNk>!gOIENDB`refind-0.11.4/docs/refind/MokManager1.png0000664000175000017500000000366712626644767020361 0ustar rodsmithrodsmithPNG  IHDRkgAMA a PLTE}2tEXtSoftwareXV version 3.10a-jumboFix+Enh of 200705202IDATx홱:ETJPW8qN`ǵ|v lo-KB"./m)^">~z1 `{u--HXoVI K=YI(i 6!_f]k mI:䨤:CmsD.lz*uuH|^@.ண3~Is#1#MYuI~8F)iD~z^'tmO:7U 潶Bj [z̝}GG2W2'HO8}-4<2wzvT |XCKr}اeyS L@bS&ސJ!y!"1clH뜔*fٔgR`0Ҭ6%HeNiSTIY'<2e"-FPOoI ?aD g$1hh|blO!MoIUHo#MZ?nF#~4IoO_˞:<"ն`W"#Mc%i2ҠeQ ޅ%oM4{kW$Go<>!輈Φ{t$1 ={C Qx[9?"C5}L?ZZs4d;ZSхX: doעXBv+hAj"3-:nӤZ+O9$Ld3Z@J>^"Z@nŒtSw)ԒtKQJ~Y9`ۋ*'Q_gSھs'%"cl wk4G mEr'ӎNIՅ1w kNdڻ/:4w¢e$Ɖ|IkI*JM9j0NA7tvW<'NҘ;oKHu40fzD=?w 4SUDs'jS޵Sr'꿺{o9ANHLe7>%wQJFbIZ Oɝh$4jEJĮJƔzz;inIll=4z=wr\.r\.rS +TtIME *6IENDB`refind-0.11.4/docs/refind/tux-refind-theme.png0000664000175000017500000005011413363352556021420 0ustar rodsmithrodsmithPNG  IHDRH`k> pHYs+tIME4-WDtEXtCommentCreated with GIMPW IDATxypy `M ޢ)%JLJl:Nl+()|0%d;UEvN\)U);cK,[)")Abݙ;X*z$IӴ9rرc5cuI MԢ2]2Z;jKvm?,Zǎ;Ξ=[K:<~Yϯс %E|>h4Z3usl {;x`c2]_ O[_J|"eYqrms=$I{$40lͿ^ /,Y e t]_Y*ۑeԎ;#t\uuZcq5{٬,,SI*YñhnV5NVd2۶m+\ cǎqpp1\U{رvBYQ4-e+('D'IRmWXL&3<<{FQƘommnkkSU:.͛ԧ5 ö:0vt:SUT&y.ȰU|ϴ p8jA\I_zǏ[]4xo׷{n:.-SǶ p+rup:[n.@$umfW~2 *Ld`ePOc}}}qA:NMM?}70Μ9gϞ-? :p ֧6 9.QJ`*kP*7B]B~f͘`Kmڴ :Vc:~{F_|QP:;Y~pEVmviK_*2oK-~k=y6'QCD]]]$]+S*zz<Xrckk+eت n:rh][͡K> +l,6+^JX/)Lsg~~o̶2:f2aN_<;RY رux~x,klllkkx(r[[ӧDð-P4_Nx<>33D隙bl$˲8U}bV0Y|:ԑb--t 3gyV]].c,^t) Z-eޥNtwvv566AGIS0ö֭|EoΛ?ْUQy9J-+Aԑ*Fmv(NP(t]ᜇᩩ)ɜ)ԕ=QöH6oެ(r&$wD&ɥX5k mթB1x.:ښx-O7o޼{nl^0۷oٲ%J?~gfL׭@Gc[[Lh#%q\7nv*oЬK1BU]+>g3eRjz`%X8QAeYy{{{0 "]ׅ; X4n](BGJð-NV_nPXyXUP4Me1bJd29:::66mt2,uR~zӱ:o塕+rtuu755J[0rۡN|JĥX\8y֭{{Ngff B,={6W8>>>>>.#)I*~tlmmkll[`Uʆ DZ^z{\o1lTplذp,byx Xa3EQG<u]WEt8tizzzjjs?> 9NZzб:Zu{饗jfWtplݺU׍ C %OT*VP(tҥұ0Wuz$x<۶m)TU%t:=11!rWW+Vi|||jjJHRdeY @ 0==̱' rnT/ghG1u$ E()n:EQaE[?:2<֭[cv_yd`VP(g;U&ThѪhՊz𭵋b׌7UX~䤘|MMMeD"QU[,٩u{zzcQ^$m"'JG_P0UaTo(ή'ұ~2|Ŷy,+RyU'^oSS)b @pX\u Á@:qh1b!]74M/~.eV[% ]Of,ұT0 .?'Beu,˽X,Hxl6+v4mddD&nuKޮjunaA\.׶m9mN/|,/.p\<ɲL d W>hco5M9UU$tVlRaRz7Vp'KV+IPE uc/PnѐuttTa8tc, 9@@ttʌjUG1v{{{cʲxq::: CLXX. [pZn#ةTZբTzê ͛79sNtj ØFpXN11H_2lhh|,mxrhl6f%IS2hBב1&IҞ=@:644Ȳ fsx<72&قq "cqY76,DRoorXEgqҥH$(J*2GE#+ɥ$IH/>7xLQU 6@:JxzcV+E{ؼK=-Gv潝B'E" ZQ,{Dت^3wJ$IKNS岕QD8n8}}}opiEE\m`*NMSeW^h)䰺:GGGE }*D|n1&JQV2ϐJG`ֱ:Vckk uJҞ=f-80t]/4]o+KC|y6ѦQMS #$yXxL<?{8ibO,TLaClFe2sK4[E\: k.X`P$ VӹeIbq^T8Z>FE*z^ÑJj^-Lx<Q9ODB]fE?Zұ5,6lv͜-ٴik6ytE0¼kIG3Ά c: Ljm(П7A5\h= iG]A˗/RgϾ6l0: u}zzZE{||\4ӧ$_p(бBN>f߹s^i"*;9`)GGTeU,^pazzzǎ0N8ooڴPa&xVl\.WKKL$^׏Dlݺбrn(dY޹saelŦيVn՛oب(:Ӧy1 ---drxxX̸+a;Xh,pw=qzzsAG" Qc$֭LDQgYvmnwR/wt/̼@Q4Rb2Ed2lך>ZNğ(tT*555eKQc:'ئMBu49 [d.ZJU-$IZZ,]-Pu@ژ~xZ[[E9>,H$ `ؾHi(j[G 5AE(6(@W{$fO-,5_9hoo7O2L$d2JRt:N:l3Urϛ kgz:SYٖ_ [ZZy?JFGG3gUHS 099)c#缷:.NGA`؈1q㼒Hycsm~1xnz6v.HtZmECJͽ96(Z#WCGMRTkkkߚOp቉[g'fggǓɤ2.hkXGyt\@V -  mIMgPaSɲ,I KDdSd2hy5\dgD~MMM5aиyseR}00!y˯u=dY֪"oMqq::@ FaUUT)\P )Ilӣ͓#TfRe ւa[GFF ,=uUUU4yb8J9Fs7X)TDh4JE Ԥfc q s:f51cs[#hnl+̃'-4{J.Mh W q.L6ock$k9tT%477K(힜L "D5Xu=qYױ:.EG҉[!Gd5WEo _f[L83m%[`ٷ׼~۞Rm~4 IDAT<zeұw}=O0x!SEu@p, jNgggEÚIN|ٮm kNG ksXEnbZy+]YtqIR )O;POU*aAtEcz?B6"[ן)#\HHb t,Kh4HkjjISSSf=Q,f%UU].%Im1JE"xCQ\,===q:~zt@%-Y c.[Qd@%Q6Ϥ{7p㩊%$$544Q\ qP(dz5,J Ds:NSP($fDX,699zfb/hطf"^\9SuEA8c9BFD^˗!ԟ1aoO}#fAG*+kJuƋKe:[֊թLPb bʈ\ cJ7ߊn4-LΎk{+QDizr8 fC]ht^/תQ__,++n}-"rI ne(gpN L/{%Kߨ k Vf W;455y!_YΝ/d6A'2v pNJ&[}S+[m1&֢XCj:tw77ntDWW"F\('ҭ^ :2FsjrC0tbmFsUV|zO9_GL%`*b ^t4U|qq.(Ԫ L E6mJsND3cN#b&+*t\vy~Ɣ~X]Ş0l3h#"Iuйkdp{2sfg [TR =sT᢫ʩhd#˙gc<f]2Q3 ^‚RHFm6.Fk_~Hsf013qt8qN̜3Lw%ϻHw ,7*"y&Y6s C(ȍgADW974gL6+27UQ4F֟+2?Eɔ3t287t93 2 s@f#ƹaA` _3RЏ?o&,"b[\Q"K&R~ʹAd%2rѫ<7EC뻈ivW,ύĠ Qx"ձOHnO$.^DO7n%Mt1fL$#I"8q&֌ܿ%DIKm2y}9H%V, IJr ]ãgg#>_H'iubLRcdH#0I dO $Te=떆?M1E 3GP쑑Jfff<M_gҩ3OB5Ie$H\($C֘Bap)'9gz,/Rn 10tP,,#pN1ʤб:NOO;N1p/2{qI܍:wjYM6 &IKviNpI2#Ƙ$1F1#FLbI2ʘ->C!c\$FH\Mfrfҭ[q.Ikb^|ʆ\J=au[6 7,9 sCL(N$. H\4zy" +3v?7.E6,-Fdp8I:9 rI $1pS="&cgL+Š]prcuuxMePȡr̡JJ%ᖔ#$FdI2rƌ$Ƙ$)W#Ƥ[Y̊t_!o"X~#,Oax)]$IoC>i~h K\E[#0dYx?#0/_ [0ҕ^'+s6Ge2t:m~555eFm-؆XdWhcCvEFNvyE1t2COއv;iDLVMd`@:yicyj:VYT*Ufظe].Uur#-1IV.NNᅮ& -Z`YJ0X{b{{k3+,˱X,.^ò,˲,Ia!Tt3Ir(,2SIwx)on~8F%Piv8^WdXEv亹M*~T*anP21i]\ɼ~w_u"cDq n%(E=Dž7欵a(>,˪z^_sWoDn[ATN^ѣG"I96d[*ܴi']&USӡk:w;b|cok,DfI7ܴ-=}~IٕΦJsAǪ}]rmY1b[;H3Su'2tN/cg$I* Q(C\kDcÞAX}YX[w+s> BdYN$UUtZ$2 :Ά7xc?FD$\x0bIxESR<$3,ۜ($ 6c9g3/ۆ]f|ff6AjxL&S" {eyׯq4՜'vf2Lt"MW"'$)(ØN31 <•q".V|DÕnby+is+s\'hC.ZYOso f<<$I,dY,)pCĆá;ӧ}-\eR.7w}SJ8XQF5M'MWi%VR%y>I! t\ uH,u]4]bnlKQU'O322"˲rnuEװQn5D$oٺo&CwkC7ܜ+$I⊤9C:YYKH"1D\bLDLD$I$f`3rkl}_R$5 C7sbR˷"0܆X^!sWISS?+W+G,#ڽc TUSeYu.醒Pss9I$.FK2fx+f1o:bo9aRԳ=O6'ݶq*֪ڭ!tj+=hY8^d%&7t$[F`Ϲf~%zYHc)ðE*4Hv1[=[!I%ʜnsW`-5H\X#Yz9+Y9, [=׬c/;yٖicܶ*WbI8gf̴ԭ<_͍CzĢqdjSjemJ*혛*;''bTlh`qKuTǢAG: %x%,>FњQ必#jeu$0b@V2NxEEV !#t0l5gJ:q,D[U*nkIA#zÁZÁUDuEQ# P#dY<R!y5P{˰ipUPcJh49Ǡm8hnJ0TU%d_Vx"ad2$9mM4ajlXvt6UE480relvvv6:;;r8l6JE"񑑑X,v5ޗ{y晩)Wf2z: MNNF#Hkku]e˖t:=::zcǎ=zԩSLi׮]D"_Eյe˖Ʈmܸq#|vvvm^}x2 oh4`@ v'OK###H$NNDH$rœ'Orw:>>i{{/Zw޾aÆx pmxx[o{aս0Μ9S%&311PUuΝϟ/cUUGFF*ՊOJFlDtiUxΞ=[s={sر .vm[|M{j g*$͎utt}t9==-IR0\RccczkEQn喉_eҥKU?KZZZV񾚚*q.5믿>11q-Xמ˲|7G"^{ 'T333; ˑwrrr)kW^{-r-"a,O$ J;au[Էhtq ^ZslV^yX,~qM7e2^zi aW b'6.4Uk9vd2{_9կ~fs_|EX5_$;30lݡ2 +GȀ[r1w^UU1Ʈ5 \bȦWwst:r~Z۝N׸{|=\6}NLt `X"HcccO "*W"X^`p n=je`ȑ#ư=۳gJ;au˗[[[~XF -xJW`gΝpȑ#u]?rH0ܽ{7 lkkmP q~1IDATj,VUuӦMo˗/wwwW+:_˗/.`___f>gy{hh ضTUg```˖-?*4mddk!H kP(tDB6ٿR߿ӦMkM,.'=p@uV`~\ttt}{>sKP3 XMZZZFFF"H"u]e [[[;;;gff;IF*v_3.\py뷭7p4-:uPf߾}ov>n_|q9R -|>_GGGKKK p\"g*|ŋW7͜{v{miiyWBey||cl[~ `ep:=s=7pC2^I~w~ҥKXZWzxK_=ctzddd򗿬(ʻ[|3Ǐo|/\0==]ꇕY?뮻ٳHdhC} ~y>90FFF_=/ժ:>>>99v. T `%yG>~=tPCCBYyySN~oرc+L[cKn;g???|FU*®]ɓ'%j0'N񦦦~ l駟~뭷臏>hWW#44O;w8~|祗^~k_{w9D+_|2>|×/_HQ`0Ce2RO7,o~^zg5m;0=z}_ĉ?Ȣ!g??{oww^ :DD/7O~c t}E{%If~}&''j?e/r?vu]߱c=SN?TXoR)o~7;G=\T)E^G/I2T @ "|I۱cW{GOD]]]_׼^oI>Vyo~󛍍>|x{$Iz'O~;w㮻:?~P7ż69N?)ӸɟI(Ї>ogx}}0-EO}SrK)YEP07)I9Ɨݻwko~| _[+|EܻwCcK4?7'eӟ8ؤ-˒͂>}sjO|o|~TY*VEnӟKZ M/_?#644 GK֯__D<?v؞={hpp0N OȈadrtt4r`jj*NxmmmO?tyoo199'i@'fNsG%y睲,_wuMMMfj񴶶Dʲ,|bpܹqSM,ud",s^?'K.ٟBl*U^~_pGGGGFFU*p}~P撖n"kD" }򓟔eܹsx0 m,@_|ݻP4|(TJ0 _Wu]7_^CC5\{tre2g}vjjvYxI??:t;|ϝ;H$R)!\&~_2>RGrKݝI0q uPXyY~3r45]UmvqvIE}u,/m|M+I*>ovvvvvѣjoo߹s痾0̖r/|f2(b6oկ~Usrʏ\|s}Ox~-K*ťKoE9|g-y*RUUt:=iFZ֡a#VlѨi*@ PbC͒va$,ZXK Sbb YݻGGGoF"iii9ydkKK c|Diϟ?8G_"ھ}mqСW_}9#q/~GyGy˴j~Û6m*7;u]w%^(ӧԑTG}tݒ$?w0؅?bHd֭Do>њYO}T[Ex}G]𜥊b%Dщ+}FsQ޽{]28[Ew}K/433cvIT7Fl5`D"?詧:twߝN|I.!'> Y/^(:eOOey衇D#G~_=#Í7~/Yj wqɱ1I={"M7d.'(c,X ŸSUU"_w߽뮻ǟ|I8~NDQ}{;t?g?c+wD"!^ַ:t]wӟ(#[ZZjSO}{4M{ꩧҧ)U+m~ߘַ%x,,Ke\X*y0/^2MZ׿nNG>BD[nE VG@hll'?ؘN͛$ PVFlIENDB`refind-0.11.4/docs/refind/secureboot.html0000664000175000017500000012050713372346574020574 0ustar rodsmithrodsmith The rEFInd Boot Manager: Managing Secure Boot

The rEFInd Boot Manager:
Managing Secure Boot

by Roderick W. Smith, rodsmith@rodsbooks.com

Originally written: 11/13/2012; last Web page update: 11/12/2018, referencing rEFInd 0.11.4

This Web page is provided free of charge and with no annoying outside ads; however, I did take time to prepare it, and Web hosting does cost money. If you find this Web page useful, please consider making a small donation to help keep this site up and running. Thanks!

Donate $1.00 Donate $2.50 Donate $5.00 Donate $10.00 Donate $20.00 Donate another value

This page is part of the documentation for the rEFInd boot manager. If a Web search has brought you here, you may want to start at the main page.


If you're using a computer that supports Secure Boot, you may run into extra complications. This feature is intended to make it difficult for malware to insert itself early into the computer's boot process. Unfortunately, it also complicates multi-boot configurations such as those that rEFInd is intended to manage. This page describes some Secure Boot basics and two specific ways of using rEFInd with Secure Boot: Using the Shim program and using the PreLoader program. (My separate EFI Boot Loaders for Linux page on Secure Boot covers the additional topics of disabling Secure Boot and adding keys to the firmware's own set of keys.) This page concludes with a look at known bugs and limitations in rEFInd's Secure Boot features.

Basic Issues

Through 2012, it became obvious that Secure Boot would be a feature that was controlled, to a large extent, by Microsoft. This is because Microsoft requires that non-server computers that display Windows 8 logos ship with Secure Boot enabled. As a practical matter, this also means that such computers ship with Microsoft's keys in their firmware. In the absence of an industry-standard body to manage the signing of Secure Boot keys, this means that Microsoft's key is the only one that's more-or-less guaranteed to be installed on the computer, thus blocking the ability to boot any OS that lacks a boot path through Microsoft's signing key.

Fortunately, Microsoft will sign third-party binaries with their key—or more precisely, with a key that Microsoft uses to sign third-party binaries. (Microsoft uses another key to sign its own binaries, and some devices, such as the Microsoft Surface tablet, lack the third-party Microsoft key.) A payment of $99 to Verisign enables a software distributor to sign as many binaries as desired. Red Hat (Fedora), Novell (SUSE), and Canonical (Ubuntu) are all using this system to enable their boot loaders to run. Unfortunately, using a third-party signing service is an awkward solution for open source software. In fact, for this very reason two separate programs exist that shift the Secure Boot "train" from Microsoft's proprietary "track" to one that's more friendly to open source authors. Both of these programs (Shim and PreLoader) are available in binary form signed by Microsoft's key. Shim enables the computer to launch binaries that are signed by a key that's built into it or that the user adds to a list known as the Machine Owner Key (MOK) list. PreLoader enables the computer to launch binaries that the user has explicitly identified as being OK. Distributions beginning with Ubuntu 12.10 (and 12.04.2), Fedora 18, and OpenSUSE 12.3 use Shim, although the Ubuntu initially shipped with an early version of Shim that's useless for launching rEFInd. (Current versions of Ubuntu ship with more flexible versions of Shim.) PreLoader is used by some smaller and more specialized distributions, such as Arch Linux. You can switch from one to the other if you like, no matter what your distribution uses by default.

There are three ways to sign a binary that will get it launched on a computer that uses Shim:

  • Secure Boot keys—These keys are managed by the EFI firmware. In a default configuration, Microsoft is the only party that's more-or-less guaranteed to be able to sign boot loaders with these keys; however, it's possible to replace Microsoft's keys with your own, in order to take full control of Secure Boot on your computer. The trouble is that this process is tedious and varies in details from one computer to another. It's worth noting that many, but not all, computers ship with Canonical's key, which can help slightly when booting Ubuntu; if your computer is so equipped, you can use any Shim you like and not worry about adding Canonical's key to your MOK list, although you must still add a MOK key for rEFInd itself.
  • Shim's built-in keys—It's possible, but not necessary, to compile Shim with a built-in public key. Its private counterpart can then be used to sign binaries. In practice, this key type is limited in utility; it's likely to be used by distribution maintainers to sign their own version of GRUB and the Linux kernels that it launches, nothing more. On the plus side, Shim's keys require little or no maintenance by users. One potential complication is that if you swap out one Shim binary for another, its built-in key may change, which means that the replacement Shim might no longer launch its follow-on boot loader or kernels linked to the first Shim.
  • MOKs—Versions 0.2 and later of Shim support MOKs, which give you the ability to add your own keys to the computer. If you want to install multiple Linux distributions in Secure Boot mode, MOKs are likely to be helpful. They're vital if you want to launch kernels you compile yourself or use boot managers or boot loaders other than those provided by your distribution.

All three key types are the same in form—Shim's built-in keys and MOKs are both generated using the same tools used to generate Secure Boot keys. The keys can be generated with the common openssl program, but signing EFI binaries requires either of two rarer programs: sbsign or pesign. If you use Shim with a distribution that doesn't support Secure Boot, you'll need to either sign the kernels yourself, which can be a hassle, or launch the kernels by way of a boot loader that doesn't check for signatures, such as ELILO.

PreLoader is easier to set up on a distribution that doesn't support Shim because PreLoader doesn't rely on keys; instead, you tell it which binaries you trust and it will let you launch them. This works well on a system with boot managers, boot loaders, and kernels that seldom change. It's not a good solution for distribution maintainers, though, because it requires that users manually add binaries to PreLoader's list of approved binaries when the OS is installed and every time those binaries change. Also, PreLoader relies on a helper program, HashTool, to enroll hashes. (This is Geek for "tell the computer that a binary is OK.") Unfortunately, the initial (and, as far as I know, only signed) HashTool can enroll hashes only from the partition from which it was launched, so if you want to use rEFInd to launch Linux kernels directly, it's easiest if you mount your EFI System Partition (ESP) at /boot in Linux or copy your kernels to the ESP. Another approach is to copy HashTool.efi to the partition that holds your kernel and rename it to almost anything else. rEFInd will then treat it like an OS boot loader and create a menu entry for it, enabling you to launch it as needed.

Beginning with version 0.5.0, rEFInd can communicate with the Shim system to authenticate boot loaders. If a boot loader has been signed by a valid UEFI Secure Boot key, a valid Shim key, or a valid MOK, rEFInd will launch it. rEFInd will also launch unsigned boot loaders or those with invalid signatures if Secure Boot is disabled in or unsupported by the firmware. (If that's your situation, you needn't bother reading this page.) PreLoader is designed in such a way that it requires no explicit support in rEFInd to work.

My binary builds of rEFInd version 0.5.0 and later ship signed with my own keys, and I provide the public version of this key with the rEFInd package. This can help simplify setup, since you needn't generate your own keys to get rEFInd working. The rEFInd PPA for Ubuntu ships unsigned binaries, but the installation script that runs automatically when the package is installed signs the binaries with a local key as it installs them. In either case, if you lack public keys for the boot loaders that rEFInd launches, you'll need to sign your boot loaders, as described in the Managing Your MOKs section.

Using rEFInd with Shim

Because several major distributions support Shim, I describe it first. You may need to adjust the rEFInd installation process to get it working with Shim, especially if you're not using a distribution that uses this software. In addition to installing Shim, you should know how to manage your MOKs, so I describe this topic, too. If you don't want to use Shim, you can skip ahead to the section on PreLoader.

Installing Shim and rEFInd

A working Secure Boot installation of rEFInd involves at least three programs, and probably four or more, each of which must be installed in a specific way:

  • Shim—You can use any version of Shim you like. In many cases, one will already be installed on your computer from your distribution, called shim.efi or shimx64.efi in the distribution's directory on the ESP. If so, it's probably best to use that version, since its built-in key will handle your distribution's kernels. If you don't currently have a Shim installed, you can copy one from another computer, copy the file from a distribution installation disc, or download a version of Shim 0.2 (old, but still usable) signed with Microsoft's Secure Boot key here. This version (created by Shim's developer, former Red Hat employee Matthew J. Garrett) includes a Shim key that's used by nothing but the MokManager.efi program that also ships with the program. No matter what version of Shim you use, you must enroll rEFInd's MOK. Ubuntu 12.10 and 13.04 ship with an earlier version of Shim (0.1) that doesn't support MOKs; avoid Shim 0.1 for use with rEFInd. You should install Shim just as you would install other EFI boot loaders, as described here. For use in launching rEFInd, it makes sense to install shim.efi in EFI/refind on your ESP, although of course this detail is up to you.
  • MokManager—This program is included with Shim 0.2 and later. It presents a user interface for managing MOKs, and it's launched by Shim if Shim can't find its default boot loader (generally grubx64.efi) or if that program isn't properly signed. In principle, this program could be signed with a Secure Boot key or a MOK, but such binaries are usually signed by Shim keys. This program should reside in the same directory as shim.efi, under the name MokManager.efi. Although you could theoretically do without MokManager, in practice you'll need it at least temporarily to install the MOK with which rEFInd is signed.
  • rEFInd—Naturally, you need rEFInd. Because Shim is hard-coded to launch a program called grubx64.efi, you must install rEFInd using that name and to the same directory in which shim.efi resides. In theory, rEFInd could be signed with a Secure Boot key, a Shim key, or a MOK; however, because Microsoft won't sign binaries distributed under the GPLv3, I can't distribute a version of rEFInd signed with Microsoft's Secure Boot key; and as I don't have access to the private Shim keys used by any distribution, I can't distribute a rEFInd binary signed by them. (If distributions begin including rEFInd in their package sets, though, such distribution-provided binaries could be signed with the distributions' Shim keys.) Thus, rEFInd will normally be signed by a MOK. Beginning with version 0.5.0, rEFInd binaries that I provide are signed by me. Beginning with version 0.5.1, the installation script provides an option to sign the rEFInd binary with your own key, provided the necessary support software is installed.
  • Your boot loaders and kernels—Your OS boot loaders, and perhaps your Linux kernels, must be signed. They can be signed with any of the three key types. Indeed, your system may have a mix of all three types—a Windows 8 boot loader will most likely be signed with Microsoft's Secure Boot key, GRUB and kernels provided by most distributions will be signed with their own Shim keys, and if you use your own locally-compiled kernel or a boot loader from an unusual source you may need to sign it with a MOK. Aside from signing, these files can be installed in exactly the same way as if your computer were not using Secure Boot.

If you've installed a distribution that provides Shim and can boot it with Secure Boot active, and if you then install rEFInd using the RPM file that I provide or by running refind-install, chances are you'll end up with a working rEFInd that will start up the first time, with one caveat: You'll have to use MokManager to add rEFInd's MOK to your MOK list, as described shortly. If you don't already have a working copy of Shim on your ESP, your task is more complex. Broadly speaking, the procedure should be something like this:

  1. Boot the computer. This can be a challenge in and of itself. You may need to use a Secure Boot–enabled Linux emergency disc, temporarily disable Secure Boot, or do the work from Windows.
  2. Download rEFInd in binary form (the binary zip or CD-R image file). If you download the binary zip file, unzip it; if you get the CD-R image file, burn it to a CD-R and mount it.
  3. Download Shim from Matthew J. Garrett's download site or from your distribution. (Don't use an early 0.1 version, though; as noted earlier, it's inadequate for use with rEFInd.)
  4. Copy the shim.efi and MokManager.efi binaries to the directory you intend to use for rEFInd—for instance, EFI/refind on the ESP.
  5. Follow the installation instructions for rEFInd on the Installing rEFInd page; however, you should normally give rEFInd the filename grubx64.efi and register shim.efi with the EFI by using efibootmgr in Linux or bcdedit in Windows. Be sure that rEFInd (as grubx64.efi), shim.efi, and MokManager.efi all reside in the same directory. If you're using Shim 0.7 or later and installing it under Linux, you may optionally keep rEFInd's refind_x64.efi name; but you must then tell Shim to use rEFInd by passing an additional -u "shim.efi refind_x64.efi" option to efibootmgr. Change the filenames to the actual filenames used by Shim and rEFInd, respectively.
  6. Copy the refind.cer file from the rEFInd package to your ESP, ideally to a location with few other files. (The rEFInd installation directory should work fine.)
  7. Reboot. With any luck, you'll see a simple text-mode user interface with a label of Shim UEFI key management. This is the MokManager program, which Shim launched when rEFInd failed verification because its key is not yet enrolled.
  8. Press your down arrow key and press Enter to select Enroll key from disk. The screen will clear and prompt you to select a key, as shown here:
    MokManager's user interface is crude but effective.
    This user interface was used in early versions of MokManager, but somewhere between versions 0.4 and 0.7, the user interface received an upgrade. If you've got a more recent version, it will look more like this:
    Recent versions of MokManager provide a somewhat more
    user-friendly user interface.
  9. Each of the lines with a long awkward string represents a disk partition. Select one and you'll see a list of files. Continue selecting subdirectories until you find the refind.cer file you copied to the ESP earlier. (Note that in the early user interface the long lines can wrap and hide valid entries on the next line, so you may need to select a disk whose entry is masked by another one!)
  10. Select refind.cer. You can type 1 to view the certificate's details if you like, or skip that and type 0 to enroll the key.
  11. Back out of any directories you entered and return to the MokManager main menu.
  12. Select Continue boot at the main menu.

At this point the computer may boot into its default OS, reboot, or perhaps even hang. When you reboot it, though, rEFInd should start up in Secure Boot mode. (You can verify this by selecting the About rEFInd tool in the main menu. Check the Platform item in the resulting screen; it should verify that Secure Boot is active.) You should now be able to launch any boot loader signed with a key recognized by the firmware or by Shim (including any MOKs you've enrolled). If you want to manage keys in the future, rEFInd displays a new icon in the second (tools) row you can use to launch MokManager. (This icon appears by default if MokManager is installed, but if you edit showtools in refind.conf, you must be sure to include mok_tool as an option in order to gain access to it.)

If you're using rEFInd to boot multiple Linux versions, chances are you'll need to add the keys for the distributions whose Shim you're not using as MOKs. rEFInd ships with a selection of such keys and copies them to the keys subdirectory of the rEFInd installation directory on the ESP as a convenience. Note that you must enroll keys with .cer or .der filename extensions. Although .crt files contain the same information, their format is different and they cannot be used by MokManager.

Managing Your MOKs

The preceding instructions provided the basics of getting rEFInd up and running, including using MokManager to enroll a MOK on your computer. If you need to sign binaries, though, you'll have to use additional tools. The OpenSSL package provides the cryptographic tools necessary, but actually signing EFI binaries requires additional software. Two packages for this are available: sbsigntool and pesign. Both are available in binary form from this OpenSUSE Build Service (OBS) repository, and many distributions ship with at least one of them. The following procedure uses sbsigntool. To sign your own binaries, follow these steps (you can skip the first five steps if you've successfully used refind-install's --localkeys option):

  1. If it's not already installed, install OpenSSL on your computer. (It normally comes in a package called openssl.)
  2. If you did not re-sign your rEFInd binaries with refind-install's --localkeys option, type the following two commands to generate your public and private keys:
    $ openssl req -new -x509 -newkey rsa:2048 -keyout refind_local.key \
      -out refind_local.crt -nodes -days 3650 -subj "/CN=Your Name/"
    $ openssl x509 -in refind_local.crt -out refind_local.cer -outform DER
    
    Change Your Name to your own name or other identifying characteristics, and adjust the certificate's time span (set via -days) as you see fit. If you omit the -nodes option, the program will prompt you for a passphrase for added security. Remember this, since you'll need it to sign your binaries. The result is a private key file (refind_local.key), which is highly sensitive since it's required to sign binaries, and two public keys (refind_local.crt and refind_local.cer), which can be used to verify signed binaries' authenticity. The two public key files are equivalent, but are used by different tools—sbsigntool uses refind_local.crt to sign binaries, but MokManager uses refind_local.cer to enroll the key. If you used refind-install's --localkeys option, this step is unnecessary, since these keys have already been created and are stored in /etc/refind.d/keys/.
  3. Copy the three key files to a secure location and adjust permissions such that only you can read refind_local.key. You'll need these keys to sign future binaries, so don't discard them.
  4. Copy the refind_local.cer file to your ESP, ideally to a location with few other files. (MokManager's user interface becomes unreliable when browsing directories with lots of files.)
  5. Download and install the sbsigntool package. Binary links for various distributions are available from the OpenSUSE Build Service, or you can obtain the source code by typing git clone git://kernel.ubuntu.com/jk/sbsigntool.
  6. Sign your binary by typing sbsign --key refind_local.key --cert refind_local.crt --output binary-signed.efi binary.efi, adjusting the paths to the keys and the binary names.
  7. Copy your signed binary to a suitable location on the ESP for rEFInd to locate it. Be sure to include any support files that it needs, too.
  8. Check your refind.conf file to ensure that the showtools option is either commented out or includes mok_tool among its options.
  9. Reboot. You can try launching the boot loader you just installed, but chances are it will generate an Access Denied message. For it to work, you must launch MokManager using the tool that rEFInd presents on its second row. You can then enroll your refind_local.cer key just as you enrolled the refind.cer key.

At this point you should be able to launch the binaries you've signed. Unfortunately, there can still be problems; see the upcoming section, Secure Boot Caveats, for information on them. Alternatively, you can try using PreLoader rather than Shim.

Using rEFInd with PreLoader

If you want to use Secure Boot with a distribution that doesn't come with Shim but the preceding description exhausts you, take heart: PreLoader is easier to set up and use for your situation! Unfortunately, it's still not as easy to use as not using Secure Boot at all, and it's got some drawbacks, but it may represent an acceptable middle ground. To get started, proceed as follows:

  1. Boot the computer. As with Shim, this can be a challenge; you may need to boot with Secure Boot disabled, use a Secure Boot–enabled live CD, or do the installation from Windows.
  2. Download rEFInd in binary form (the binary zip or CD-R image file). If you download the binary zip file, unzip it; if you get the CD-R image file, burn it to a CD-R and mount it.
  3. Download PreLoader from its release page or by clicking the following links. Be sure to get both the PreLoader.efi and HashTool.efi files.
  4. Copy the PreLoader.efi and HashTool.efi binaries to the directory you intend to use for rEFInd—for instance, EFI/refind on the ESP.
  5. Follow the installation instructions for rEFInd on the Installing rEFInd page; however, give rEFInd the filename loader.efi and register PreLoader.efi with the EFI by using efibootmgr in Linux or bcdedit in Windows. Be sure that rEFInd (as loader.efi), PreLoader.efi, and HashTool.efi all reside in the same directory.
  6. Reboot. With any luck, you'll see HashTool appear with a warning message stating that it was unable to launch loader.efi and declaring that it will launch HashTool.efi. Press the Enter key to continue.
  7. HashTool should now appear. It should give you three or four options, including Enroll Hash, as shown here. Select this option

  8. HashTool provide a somewhat nicer user interface than
    MokManager's.
  9. You can now select the binary you want to authorize. You should first select loader.efi, since that's rEFInd. The program presents the hash (a very long number) and asks for confirmation. Be sure to select Yes.

  10. Be sure to select the right binary when you enroll its hash.
  11. Repeat the preceding two steps for any additional binaries you might want to enroll. These include any EFI filesystem drivers you're using, any boot loaders you're launching from rEFInd (other than those that are already signed, such as Microsoft's boot loader), and possibly your Linux kernel.
  12. At the HashTool main menu, select Exit. rEFInd should launch.

If you did everything right, rEFInd should now launch follow-on boot loaders and kernels, including both programs signed with the platform's Secure Boot keys and binaries that you've authorized with HashTool. If you need to authorize additional programs, you can do so from rEFInd by using the MOK utility tool icon that launches HashTool.efi from the second row of icons. (This icon should appear by default, but if you uncomment the showtools token in refind.conf, be sure that mok_tool is present among the options.)

Although PreLoader is easier to set up than Shim, particularly if you need to launch programs or kernels that aren't already signed, it suffers from the problem that you must register every new program you install, including Linux kernels if you launch them directly from rEFInd. This need can be a hassle if you update your kernels frequently, and every new registration chews up a little space in your NVRAM. Nonetheless, PreLoader can be a good Secure Boot solution for many users or if you want to build a portable Linux installation that you can use on any computer with minimal fuss.

Secure Boot Caveats

rEFInd's Secure Boot originated with version 0.5.0 of the program, and was revamped for version 0.6.2, both released in late 2012. It's worked well for myself and several others with whom I've corresponded; but you might still run into problems. Some issues you might encounter include the following:

  • rEFInd uses the same EFI "hooks" as PreLoader. This method, however, is part of an optional EFI subsystem, so in theory some EFIs might not support it. For months, I knew of no such implementation, but this SuperUser question indicates that at least one such implementation exists. Subsequent discussions on the site imply that the computer doesn't support Secure Boot at all. The bottom line: If you encounter the error message Failed to install override security policy, try removing PreLoader from your boot path.
  • Under certain circumstances, the time required to launch a boot loader can increase. This is unlikely to be noticeable for the average small boot loader, but could be significant for larger boot loaders on slow filesystems, such as Linux kernels on ext2fs, ext3fs, or ReiserFS partitions.
  • rEFInd's own Secure Boot support is theoretically able to work on non-x86-64 platforms; however, to the best of my knowledge, Shim and PreLoader both work only on x86-64, and rEFInd is dependent upon these tools. In principle, you should be able to replace your computer's standard Secure Boot keys to use Secure Boot on these platforms with rEFInd, but this approach will require either built-in key-modification tools in the computer's setup utility or a build of LockDown.efi for your platform. I've not tested this approach on x86 or ARM, so I can't say whether it would actually work.
  • In theory, signing Microsoft's boot loader with a MOK should work. This might be handy if you want to replace your computer's built-in keys with your own but still boot Windows—but be aware that if Windows replaces its boot loader, it will then stop working.

If you launch a boot loader or other program from rEFInd that relies on the EFI's standard program-launching code, that program should take advantage of Shim and its MOKs. For instance, if you launch gummiboot from rEFInd (and rEFInd from Shim), gummiboot should be able to launch Shim/MOK-signed Linux kernels. This is not currently true if you launch gummiboot directly from Shim. (You can launch gummiboot from PreLoader and it should work, though, because of technical differences between how Shim and PreLoader work.)

My focus in testing rEFInd's Secure Boot capabilities has been on getting Linux kernels with EFI stub loaders to launch correctly. I've done some minimal testing with GRUB 2, though. I've also tested some self-signed binaries, such as an EFI shell and MokManager. (The EFI shell launches, but will not itself launch anything that's not been signed with a UEFI Secure Boot key. This of course limits its utility.)

Some of the awkwardness of using rEFInd with Secure Boot is due to the need to manage MOKs (either keys with Shim or hashes with PreLoader). Such problems would evaporate if you could get a copy of rEFInd signed with your distribution's Secure Boot key. Thus, if you're annoyed by such problems, try filing a feature request with your distribution maintainer to have them include rEFInd (and sign it!) with their official package set.


copyright © 2012–2018 by Roderick W. Smith

This document is licensed under the terms of the GNU Free Documentation License (FDL), version 1.3.

If you have problems with or comments about this Web page, please e-mail me at rodsmith@rodsbooks.com. Thanks.

Go to the main rEFInd page

Learn about rEFInd's history

Return to my main Web page.

refind-0.11.4/docs/refind/refind.png0000664000175000017500000024702612626644770017517 0ustar rodsmithrodsmithPNG  IHDR.~bKGD pHYs+tIME /,/tEXtCommentCreated with GIMPW IDATxy}'o]}3=F Љ9026;$>?&Ov>Yn'ds9`sƉ! ,!"!$t2:\=}UuGwgG3@yyVϷWسg """""Py ܉܉܉܉܉܉܉#чmS,˂eYu(By;E pn&Lӄa2- 71>*ho*!g$I$InODD DDڝu0P.10cV*qP}@UMReYU(/YFko>={ؼ DAv'ed2:nհs={dhyD-+cӱ~dRqGkmXZCDD DDӄv˲`&4M3ϔhalLhLjt| Yl #4MkH?gy#2|nt];]4Me :ma_w"A֭KK_*;UU!I~?\Qy.k?8P=ݧ 3ctǨJ fOkj˰.%ָeԲ뺎;xAN]!^=GGp-YlOسg˗![ Aښ4:̆X]wjolۆauB?s:_iayr\aA$x^wB4;1U r x1@/Oi訂vb'NxQ(T%tvP$}4_:MJlۚEh,]*uGpd鴅ryfWU; (5c ]kar40veYXr%Op~>!"w" g ӜyeB,AeI(Xh^4>~( ÀuK:>ki:6oa".dOmHY2CD DtŇv 뿞Yh9, ԍڶr0NСDI,4mF}P(@*Gش .<꺀m̛7KǃrO< Cij˖@?ڼYʕ#n$I؍LYQcb/XneY8|XO}`RZ_k F@D DD GxCu/cQxPu/=i0Mpet>HeW2#uOJ~;5h(˗-LN9pǩS4$YG:3XֆBX#GLo$b ֬t@Q4kѧX Rm;Kos~;8ΧgGv͆o--y$I 獮s-<|RA\u88`vthhmmE2D0ߙl:Nl|[ZJz#nSLmwe߹T%2r|}}}S~6qNDNDW'iGc!~VFړ$᰻Lj2v3oŢ:4\fiwy ݻ7p,}]{hmmŚ5kL&j&Nl|(ZZZŚ׆kS%I{cqԐ)IeR&bR;ytr ufH o +~?={`7o3gx ݍnD"wҲsz8F]wN100tbj,sJDNDnxwm>ھ|a$ w7 */~U-B.gP2t nRIɓ,XpvlwU > 8yl޼n4_$|%,>U<,+ӔP. 8x<(\'gL}NB,l[e0 0 @QI}׮j62Sg(^}XW9rwwqb۶mx'0<<׃`0l˲p9I?{ 5<@k g7ӏF^N5 [n uVD"˿ N<\4MÓO>;wOO۶݅&N3<{~'ɺu܉ aD,uCS~#$AQDQx<ah9s*VD4MӐN8qBEoo FFr]tJz)Ҩy r9 q09i _ߏצ2ּBA޽~zzF![}6OHgf׭W5ahh=oS;y֡=sOZkiiqKtfRCDNDnY 72`cqBmԺ4[$E[QVٙdETB%KthZ(cN֡;oxMgkػw/nƺnDQ&ٟaǎ؝ӵ DNDW$˲pl fwq.# MNqr';i)2@ݨLd,B6UQtvvbڵ?ޱkD20X]7i*OfcSլLkk^o >JiǑH$Fi;8p˖-Ja`ppG4,UU 0444{:0;]Qjr.|g4(+GmYDsrF]+́ݻÐvVe7i65v$I,]C4烪H&Fz8u<P֭@(pE bqqu#ۆaFeʈuVjM{vZ\wuQQ(ca```!AӴR~ӆvUU|r!JAUU'?ɔmu!"bp'+6zrp8[W|1G,'gr[ /l A!S*{m7;:' q]w!J+|>7~|j  @gdQlRUuBG8v;&FGu|M7mo(D4""xKz(޺F/aÆ Xx1Z[[!"4Mç>)<#S~.ϻ.C᭷jKPqb͚5s+N7z DNDW~hm|Q# v6 '\ 8y҇'.ҥ\# 4 ˖-C[[:;;NunILSu0AWT*x<:7[ʙj &6(a\dqy, /B! Yaz{ O9nx:,\hkksGT*aɒ% vn7ģ>pqD2t+Mnr?z""w"bû$5/u/u72.P}ضMD[[j$pR#oiiqCn퍁58 ӈbhkkCkkkv}kGZ9I&sbhooG"pG'px;jL?1nZ?I믿dҽn*m6ngr=Xɮ>'ݍvly욦5o$qgG"bp'+^eAFӼu|6e9|rBA3ٯeY8}b1$ asS<4`BD" NE.P:e#͂ukkHhDh~f=E ԭjlbE%;L#hԽ, }}}x7>n sAgg'|:afs>ND DtE8 J^wyٮTz>4MJeJl,\x9gV=-B>Ȕﷵ}>;:[ۢ スo~J=|@\FvX'T/UUIÓK@v2pebҫ]kPO5gB! FقID Ӷm駟n|`ɒ%hiiqk蝒"ga(˲e.d##qd2 3]|eYx],Tp\W3s_?0{қJm<ڑ<~4(#:b1íwlM_ ,p_$Ygjömj҂ŭ7Mov̙H$D"H$$uض©wgh'ˉj袇vA!Uoax Bu.o2u53pYMR|Ӯ{zdnRR;dLO=N4:vH9mg&Dk{nm$UUXհFQ}NP(L!m?5s~1ΙxfM~T'~[J'&e:FF͙s.46`8]讔ɘ0Ma-_ jtw|M-i65֍Owb{.bßf=-r;L~^frCH$<u'"w"û$IEDzl>㘘n i~ou@\3v/inN`lvch4㞋P P}:(=|WoFӉRLӍOa]12297zraQR,FD4JD=;C!V* b4)|jêi)cl[ܹ' TƲ, usLע1I!bѽjs͜N񥵵7j< :]ǚּQyNNL$ koB;՝x0o<=ztʶ>,:::D 2~;׻Q9;;]uM̆ +E"qE 8^,KիO iwW5鈻SN`q>rdFF/ XʃPl3RT/%b~Ajnu ߓoܜ4[*JՍ۶ 6 t bҥM0::RƂex0g63&OMPՓJ?`0;n&EjM<*o/߇hH22uF9Ƴe?4iSO[c犈bnؘlvj*twfgaf.Q0Z˯q5k`Mȑ#8rȌsc2Dn% x<_^haHx≹?L&|>Mp&mNtj5M`n<2}hFGn]gZ&QpednѥF<z/ FGG 'N4[u|Fhޛ?߿}Qs~9׫Y P-InF\ڶa 1UERJo "^z)?x Μ9t:]2\.M(,4 R \7foxC,pmJőL&g]&l6;{zzUNg22(E~\77߬]k.I&np1A PQa̟o! xRn3+VRSauwkݺuSŚ5k ۔_Xoqҍ+Wt[p:ݙcى|;X~=By_UV!  κm(w"t#,󱏕NG:aҴ?߯?W_؈F JixD:P,8uJƖ-ۇnEkkZZZ܅{fڝ/7x#~~ vB(Š+l2s;wu 8t>/i9~x瞓04A2wnáCk!H`ŊX`'D8C[[V\T*X,6g^/0{{?}a@P@\v?i$`ɒ%XnBЌB]A={ؼ Dt8ɺ#attO>}Y}l,_66l8Ntvv b), a cttrPdX BsM<0>>L&b͔S FL&D!J2 1>>r EQmg[*ϭqot.kHUU$I ]>쪪6ĹqrDi;0 rʽuu;畈.I^/ l??ky/Qr>Q=''(sheeq<Op\繝Nqj?]8stn܉fzgEQp]ش)ݻ;P((&0 Lөuqh7uίvrLΖu8s\7eNxgT4M7^9DDo|㻼 Dt9{ȩ߯`֬9PhXQ.{4HTF4:0Mb5uLB׽8sFʕYBZ :3V|ϐغYhg8/Ff%zOo|GfDEضMpꦛ`vy7M>u#ˁ#D2'DQf~}|L)ұ`Atu VFWB:޽ÈD2T.r )B(\FI{Al70_S];J>9lviٸRW&D"'e 'O0M \ThyڮAnDNDWmxr»B((J(kt \u{wwux64M'%N$p{P-(LӄaWkoܝsCl~@plҺsFGG!Iە9L>},Ͷv\y9ݷk8;t':5DD DtUxgة w.cuH툧iWTd'J9c3PU09 `"ϟ^z bb螻}}6*0M‰=1>>p8<éoٴԁؙɸcw#[`Q ܛN4k5yҬ3ٮvǚ|4 sY3F]uB4dYB!R#"bp'Dxh_DF}'%]ױd+sر#X)[}Ϸݶm+ mc;NuwM-u^ɮcua8QUdYsAeY(׋AiQ(~3p"Q7~jOGԵRmXab~jo(;:7/6+osEqʹՖn+S%:P2y`"bp'd0h6}˖Ur"꫐Ɛ;K^eض e>"<##Ι "|ڟy?|~sPQrgD?PΪU5 kG[o/mmZKt(aiۇ]GG1ՅoG#84c_"|<:7nEs9Dصb~FlnH4ozݺ^o [Yd{zwyYX|("h}%xFFAwC>o_Gw1hwÒ$Zz<瞃\.ch:L\=<œ<HW>\{; H&!2Z^xq[ѶclA PjmEH?v #;]5!67G"§>5La4^ȑ8<`0 7h Yױ! {{qNut]Gǣb㏣v_'bM9ͼsvt X{9tx!MsW0wVkGcx/z+'OVn2 &J>?`~xEyixJ%Ⱥcc 71_maϷ ߏCwى  g=Qնm(wWk:b>χo`h u:>_2RX-N|lV,޿{ ?9xǒw_~k0ڐ˲`h۵ D{z Ǽ'ٻ'zzpR HQ.y5,0h^~ uu!C:;:ptTKvJg~7gt:o}^t?>b.4~dJ LG&:;1t)l؀Wׯ:^ymvxc tvF:F!&޾f۪Uloǿ? h;v iM$S)ȱ|>Eqd @|6ȚkՅl,~ܺm`x[!2JpdP.1o܃$kph h8\..%Kp^MCntso-r}L&!x<]'. f˰mm0ݰݕTo0`.ܲi(zǾ}d2PGFF?Smm8h_o]]81o b"42\0q/() >089o~~=Nwt͏} e2iBHV8 O$R5R;]U]E\sMwGnoюuN  uw[V;LnMC0K@YQ,VoNTm|:l$UFidaU`|+@- 5nXKvuT{;z,@TUaG"ѱ1躎 tEvxE~rSƪgcct2 EQ( |[Ć0c$Df,O\Fxt#@QI ^˲"^O2YYKQ/0LB>_z<%ITg' <06Fc1Ȳ\iMZ}i@&Z}&ϑ "bp'": կc>(  㩧"EE9gx h +8~׿ dW;zA?2/8۶V/ڿ/`K/AmlMLyP~߭R_}8BdI~kj}tEA0C>Ch|##ߏ9a "|%oQ DQDd| H]y|`("}`hA{DE:OBdl F QfS?? ih?^x^,8scA$Y'"Z-*R:DD>h,Vɑ$CVtNLŰ1@`0H >_ADND4)˲\-_z`Sm[=m8~ ~\!g~3XjpEQbXk{dDld%/H ld^mgTu2uO2V?1ΤR8bB^/ccHdسf <G bo[}DGF`I--|H WiiPO90hmŒ^h^/~dȷU?1ɶ ^ HL^+DD k܉ _bK%׋1>>|>?ZwP06>^ l>a(4111|>Q !r,JEtA^|>w|uP(,w'P@ZgR l~qx<<{d2@ r s|f\i5W;@4J%2J4\jِsgPmP(P(?xDz]j,!sT=d 7eK&G|2Pti׭hNpmiinpwF0(2LD @1Z.WAC$EQPm',;ٙte$R'[~^m# Besh(dDĝlkӽGjwV&uhaSzXh}e^o\h:OT}]w]<A8 (E0 ý.ò,Ȳ쮤Z{%U':_hKpeou;_uq&g\mۆ/bw"bp'" 񵯝qY;:*Ia^.w$ $I$Inp,aw@ P$ISFsZslgٟqGʝ|ި薅89FeE΢Dc66lM籲`5- QT!+:I9L~.ܜVsU1:s""w" T;ʕ9 Ӭ &`A]!ۮrrky6;yr¢fio==łHRhmmE4ukΈÂ2DtsJ[u D"n&"3}q:<;11;11;11;;1;;1;;1;;11;11;11;;1;;1;;1;;11;11;11;;1;;1;;1;;11;11;11;;1;;1;;1;;11;11;11;;1;;1;;1;;11;11;11;;1;;1;;]2/чeY ާ(P|>HEeÀiJ%46q""w"`qJ‘H]Xme,ض] ͋u5_Iexd>Ejf20L׊>hUE  \0 a0Mض]x2A,Id,#ˈ hDD DA PU`&J"4MCTinلmYY ]Yr(AQ~Ȓ`0Q11Ю( jTBX; :NW>A PqD,!0M~Uな(J/;].   dYLrr(Jer%WG-u2.=J%|>ev1ЛLX%""w"Z*Q,0abb|be]wۭQwTG۝ $0 &MEP0IUkGDND(]סi " Ma6ʆ]Ӡk4]GYס˕2TF7M-,CuQ6 ضŗ#_? DN!  ӄen/CG't Ӳ 6LӬ{=4aZdIkٿn(; <1}YY +V DdfYG8Ӕ5sAy&QvȚgx"bp'('XT=ږtiyw޲- z.zݟ'5ߟIvBzFg'"wU dC@ʪ3 εOf^,Cex<w:, rbt*:]w͂:<1%7"ɸ tM IDATۇӧO ^{yφx 4QUh'( <<E9RbbXYɸT( $I(kj=C<1%eiWkhpQ۷eGuzuFXb͛np8nk.$G\B`M, `X "!\ >>X;0d0>>LLL@)_C|@ cd'"wuXCgpGٛuu788BEqR)^V’%KJ8ODڠnY"$~veYF"@"@OO4088L&8^冣 DNxyf3ϔeYߏ7w}7x"RW;n6RbBЇB$7/XLCCC'N$493Ӈ&6 N``, կ~[/dؼy3>O;D*/+j 5tuuv<&Qى>>|uG-<]Xۮs YKCPY€SDlP .w`m\=y9rrin߶m~}tY$ۄb:*gj$ˀlW " (24 M(VʒeQ%pg͂4ߟGx[F{*ShAPU]STOLMX?5v}w̺ 4D B=Ԛ!uE))S,,Rʌpw+Bww7LfݒK7+;wt4 UUQUu j}ݏ$?,ǡHĄ`Ɣ6 S̤ Ȕl0 <QEgeY\r_g~~~SK4N8 9XD3GV'ϑraKCu,,kT.#IXRM RWLi $JSQq~TRc6mmm444lhf9wﵪ\]~y-`ILY S„%3m2d&,KaҖ1U:YR0C1|dž?—>b{UL133ë<_+o-0N>O6E>M>K,pLnɏK+~9 cCZvXLAV &J3熚!H~&eE{"رc͜:uQBP}`}`:%f,Y; SᆱȚ2"k>k)X7fGv0M;(q>pcBLak/rƍmp58HI>Gw:q9"FII6IDR+Y9`p=M )#D.u˲D"NVz*'ի?~] èJ(¶m_Bҏ tD&oI, ̜-3jdF Š%SDȘJ\Z30ya`JY?|: u Wy <,#GuL:!HWiQ:K7Mo$ĦgUni.E[me"Y{ ڽ,{}}=lEQ%rID"XU+wo$Q oKl Sa 0ba)L ӶLr$tX=0,~Cݲ2>>>^3044߸ݟŌ<G^4I[ *liZiX̥X+vF ز{/@e-:Rtww?,{ꩧr Ǐ0 Lt%4 I|Lm} (7Z1Cf p0i)L[ k2Ml[ ݏ횦~~h1<<2?*cQȎ ; ô(@.K <<706: 7/.XP(Dww7do O(B__lG2;;eYea[C-j22 yG^9[c]uǬCCC$_e0AK5+C$v} -r6əx7S[E}}=mmm+:ƈK{UF4 dYv{5-&gO>add4,p88AuDEVmfX O0|: 2B>00~z_ oٻw/@}4U/ :[G*\?qN%q6ލ <1[EGGǪUGFFx)J%t]0 yg[u8=o6 [F BqR_kZZZ|O<穧?u]~@Hmm7f- K!(cDfap)b@W|{w?a4 Y^}UΝ;e?Wiڄ~05_a_*ܖlIhgh:N6Dc%hꢱq>F__om땅{ta}Q~(ZYٳ,hyljF|ge;IqqUwd„0ai8n[ sbBh^te2MW*koV,,I qA>0۶yٱc_K_~84j<< C[`UYHq&O^CMcc>SOqA"@5̵x->j*Z~;Pp8L8& ^xUUyꩧn=IX0qTjZͶmLӤX,r!.]e̙3:tGoPr,Gx<U,Jt,@(iz'7Yϭڅ{۶mkx8tJ8& .85McǎE4/+b18DH$B8vǪt:ݻo<3:thE.'Ov`Ą0g+R!#Ȕ(s):󖌁[~&.a2 RDQ$~ݏUXE722‡~a]Dl6qP`zzMӪK@KKվ&%_ _ycgaijע-~D,A;@,G?7:B!Ѩ\i\|={lj;v . {,#HH$bB!|Ig׮]y>ӯ2jmiAX1E-ȼ#3n1o&*L4MWuO2 u~ݏ:*ȑ#\zu͟$D"AKK mmmd2w&NLL044Ąkuχ~C ۶MX<\EM :*m_$I&:_~ckk+lG… Ȳ캲]0`/RԦ/F2,JkkK$z!8xR)t#V]H¼%'$?K:r5@ @KK ;w,;I$.]&Ez-o4aF<ߚoOq|aƹ`ETLbA\`I.cdde+_ 4|KFugv ]V^~ݏ%֚qYYٱcdP(D0,ӌu]QUm۶d8uԦ_vK.e}~wfT9.\y= vyn`jDuⲮQ@Dh0n5s se&IZE(sN~9rĕ%0$T900@ggk+nܸ/~ TU% @.d2ݤu9n46'˭k] rś vc;+vw?4+m{Pr5}]v@$)K`?4MX,R(((BOO\nۈ/G%]vUs+\y86Q"qo2vmsss$G7Azp[ǩ<1{SRf*u$ӳbE;o|;vRD$0 B˶ E˲_6Gg#ޣT*]]N @Uջ,tg}W^y|>]S'Gpd)@(>@~6C!ؚ-o~v8xum.( r9Pm۶a'Ne"N$>ϣii?sikkV펩Dn ׶<4p4G]l6K"p5^>338_LNKpۃbshrIjݶmz{{W|&2 y)B! p2$}tt:;;I;\rW_}m2^"wCó\}yj¥ŵRw?ns,˕055uωIt:M" L 7[)˹abadddYy$I.@4]<&SSS\~iW7~: e\~[ y< y 4™XѦd2e ljF"@UUdY>mEsắ xm|ɨǙ&; `,gΜ9CSSӺ3]o$In%ΥKE!HlgΝ\xk׮7_RFXR,ьPw?w4i 7~n :yd2d2RXH$RʽB!B{qN&&&0MlbhnnU&e .@GG\tB-ȉ N:Eoo.>x_[߱, C c`a*XT*իW%xmk׮-J>|m8_"fk[f-ibزV äR)t]g~~zÔ ݡoUmEFڗ>ٳg]%뮪*OeC;a~xiE&6}ygy7[/fL%x[|7nܸ2 > dd2vzܠ.=4 Mhnnfbbqw[^ݻ5bbRD{{;h4~-ӧq\f eY"jU(,$LL9pSI*!9Hm@v% \`W@p8L" NcE8wV@$t D]U3֏L[$or W.Xm! I|˗/nȹ8qO>dY+e{vW^-#LKXmZ'a[ ÷L<d2$!u9- ڋ"shii ͺ/+e8YB@>w_B?77GtU/Yd Ѫ8/KwTn2bpTf s.)X8dV%YYi@ $I<Հ ,BUdcojPfˁwv{z}|s~D~zJyWbK+wI"L޳ <\||>O0,IvɌ8'?[2ZZfP{pmۨJ__>($1::o[x ~i:::b]˸{_k, gϞ]u@ P}en&1Qd3!ߎ3`FbBRIH9K(a4M$$OPe ' I# YܭYD6Ń 8܇E T{~> ǎP(i8Zw0n]ǎc``X,V$SɶoZ~{la#;~ݏ{ „d``[~.J,7k-4661dwz!dҮJUY X%Uƍ>};w-KH/HiUܔ/N/$3R`xQ'yʤRq\yiJ% sq1mѩOX#I{rWQ8V ҳ= njH$xgG7aޛh,XwUUv˱կ~:,*Σp8)msN~ߓ]SI?|OVRb{Whڽҕ[OH,dc8Ǐ*]AL$ rʕ2WJ.$3f466ra, ۶}*KColZ\ Ӎ\WH$Ⲩvvb ڧq4c!GNq>@`E\ٯfΏu_c(@.RN{{;nڹرm۶122R&JB rGarr͂^[Rd2ICCæO&g)EEΧ?N`45md/@^ p/.[D$]z,Nill$-H///huݵ\+y ,{*Y԰+n:tHHj&LňFeݫ]BT\9&˜mc1Ighv=[ [45Jĭ^{gi d%.=KH]xgx8̈v]###\Rl ǵĮ]xwD^35 Yw?okVy*C$8Pְ`r\zvlQYP("ae 2 lYeMss]CyזlC1vvvVО={mRT>K>^288f~ɨꬥRi޶mffgb+NKV7';޽,Z]KHBXcd=a/vgC2QRǶA#Mh{wET*E>g\Hqi|B0-Dl lX[Hюc+Ǜ"H՜_6uyYw ]UUΞ=KkkmCZo:x{ePww=U#G֕BTK}?35:7":qgΜY16Q*T*ܤ[J]L0kl{y%{293e8Eww7]]]455q"RWD3d>KO$"b1Z s8oIrs͎r,m7N`̘yFju2jbEٳ K.pw kKD||+UUgǎn~Gϸ00 uWNVu, M'H8ə3gbeYr9.^$ɬ L LNN2::s4,RZ`~NJs0l4$uO!ϓrtd Z}|KlWDeP(D:vYęj2H)D֐#1e+If -)w&F:VKXVvŻgH:ZZZhmm`(Ĝ᪒⤜R@ D .n6F<5pN2E__{X,R,ݱIHĮL8̙3+TƱcǸpŠ s<i% B?f^G5w[H?iR1yL~38s)J,jJ.VO<s }]u^NsVk~C7D lvmmm444 dYLk~i6{iuWxc-7MYD)Lh%ddX =QO!рiN7,@p8L2$˹ye6xm x/vxZ߰>#KSΩX)eYUɶm+<䓜9sƵ?un3sss\vo_vJ]媰\-:;;$?|FO^k6eq1y neYdG@*2OPP$dAi=M̠KIJV_r_|Ԛoffk=U L̩ } ddz RH$B:&r-,?$>aLI >@laSCre$,9@)`v#D`0H$!L`eYƶm p~?Dә۰jקiҦVTCaџeϫ)Z[[wÇUE%SoQSNܼj"ѣGY1 vZ[[sH$~IU0÷˗/}-w"\1t}չȬ,~:!Qb8Qva9'ԩSk;vl ܶmΞ=\UjMel{,͞cW[82uqu?5Z`3@ˍ~3z\ҳ $ `q M_2dz&se9!zXbVH7"NWipcMg2>ȧ~JX,*w3 ˗/C-=t  ]{eB$ItttTF< o>8ebֲ,7_?55Enܸq[ :CCCL[Xɑ&\A*h_fGq;H[F!_vL/hwO}ffggwA׍yLJfH; ;X0ũd/fd;,:{aRl;椒u]d FuǦ~*#/zHX &6 Fd2466@#Zuo$IK$di5?Ef7R=Bvu,e8šCɇ \-zzz0 ^3~QpɅ V՝̮1PV)dff涿/W^]vZ[QK$<1(sW^ʱcx8y$|144Ooo{cts(lL;p;.:njC #T1Bczh;Kd:ƙlr8:WdNm6<׃GmDjܹn܅r{0l6[V'^Lv]׹x⚫&my~2vZ>]Iͣ]E}]k裏OѣG2"!fsv+.@** Yi{>atqm's J|9x_,*XzE2|lg(%bi՟!-JՔ]<3J%eFTqMx022~ֲ,{=0hh4J,+ }}}j;v1*~W("4x]FZ(h7 aΜ9sl4?O8t AMPyd>ڱ_e'd/ ,7 {|;߹p``w}ם.ݻc&v,# vEv\¥_ctF7\3:=gߦU*4l.;#%h1- ܳ?dXb),r/_̹s\.@WL&㎹~Wui&'o_}_%t}PgX=ztM+|Y&J 7aܬaK +|ٱ)iͮR4"`{??+08|0ccc_+^oounJQ6 F3d2bUA(hg:g%vв˼{oxJkO@ԪZPG(a>J.cpp]㏉$ #ȒbKlRd2}~ `EU GGm(12k(kiCCC|w<˲}۷LEݸĖ"hN;i6,~GHRw|/[o׎q, 2is\dJ ˲( ^8Lۍs]NPέx=3 L ,SV:}X$F}}=V,$U0gϞիϓL&I$moiibTbJe|~|Bx\/9^(q-v}^c4M<>cccw ڟ|I{9Z[[R?/ivݺt"lt'D8۷;Tʇ~uQPFicd2@tTH$(+z;i$sY 'ip[9Iq4H6F.bPo j5x٬+ݶmXx~..{%ۮ(JM?H_{HI*C>K%26|^c]u>8pG,,۷gy-T:LJ[ |mdvoA@[PX.~aMMMgnDUQD>QLQW$׾ biNMH^}nx+F .)it!;ufjyIRe+H??\u,=v!R$Sk+ۗd|}}q{!Iz`eoOZ ky }ۮvA={x'H$WlT4&p,-XJMJ0XlA&a0;;{=rl۶h4eJ$:Q'cہYTPŠD 4p5& -˶{lX$1t髛Fm9{eYS/J>Sǜ⺞$Iԙ9$U۟"H?w{e``-$|X]y=(܇ZZZj=ZZZ8sLh&]%aYbvF9W5ZSFX.!sXXXaHzH$$988 oi01/J,vokdi|MΜ9sGľ}feLReYp Äa^4Gqp O'+&hhjbY$"ȲE$I;wrn8@KK ? [Wʍ2nqc3+ΌD7m!@'@{:+J\m<=c*);q/!˲ м(L4Ÿ,L5KqNaOr ’G;*R)>+xoooMˆDb1w&ƽҦea#q~,997@PG搤Ԋ)F>gqn5ǵ˲D,=LJՁ'l&|Y Ӭɦ~ӎ344lB5Ldff7GjhhGT*E2$݉KLP"a+Eit]odp_Ge&d7Q_X,XJ_ ޢ(T__eq t|s??)kݶm2HEa;>M..b14K%.XY >B f0=l[$geri'H_?hq WUEH(ocR♼Vܕ{ @ tIoPUVɻx)Yef=*("/QL3"XKm̾t(ldI$(2PXVZ>C;vBJfDT/wD_f?P(D$! bqnȽ>?EQ9!Nh(ʨ*/q pX8DpK/+6,]v{n.NljD"K4|UU0IL^OpϰsP2ӼNDui N^i^ګ޾};v[y^|EdY%w"$㐔m$6HYt]S`Rcjjy]X cj )K`t0( t_GrvQf'pD",?prMvS+#Nk@q_l?.j^(D"iMfׁ(/&Gef pD"a7G;eQ*U7#e6s _.s*<x饗}Gu=lT*E*rArZsLuӂyxenmSe­]tdFeN1㔕|*4Hc1H|L/*NW]IJ*0u1ŐDuőcVuԭ"k.>s(JaCb8[jAUկ fjBb1g,sn&.Ee8e!2htӯn=2!qB*fs?g,C4ok >bW)h?}4믿~GP(#_|'NCm6&ފiDsA]e^|S|a9a|6?~B8ZG&YÿxrEr4ctt|>Gm#$HW^//ٻwo͂%c#;v)B8F2WWms,HaZ'?e}4Aۨ$g达vw&yC&ٱˀrL✶T`bb7xY[ n6z*drn``+_\F0p%of[eݑJF{ Zaݽ9h"{W/`^>Ν3xf*]mS(xyyΝdYW_&o- j+qEQ?ѳiBjp$F*rJka7(aiitttp;- ''ٟYM3_162^ٲJ$*sZ&I˅PCVPlԗhMu$]66K,0qo"ɔyvy_N{{hEQݫ&\Wˮ8\^Vej]T>Y*odbj"[*ZirϛoyGŕ*CLp LJr]UUJml2,sYbWk/S244tǬ.]'? ?JЗf;&TV~^&) *bq͆eضik:K,@r }+U7 XlUy~27wj={%s]ȨEJӾk9f#nun[$ 8C }W=+C8lz;ݻmD4 ۶ DQ{|oBk/^Mʹs…gffWEooo 3`˷8D< m_D_sJ$%5F)-3r(rj$NکKV&nl&-P ^_®ry֝$WckmK,gy$I v28h{cwIKiqtM{,ݴyo pV=">$x`}a o%XSNӟt@;,޽{˴ |2JΌFh8.+yX $B ]xwp3۶m9ݻ88HҭjjO^br IDATg-8MupM,qϕ$"2 5$qQpVάE `JJUpe/ѣqW,xOSSuuu5뱣cg`.G3vuZdb%0^\Q^(\#fHtM/+l1{C(Z&v08y$/},.!wyg55E=Npf>*nȑ#Up;b7{߽ϵk蠵fۣT*=բW|BQ#P13LU? ЮC [7ΖLvrm}`Tj8Ν}F?v/'1$Ibǎ.+Yk0{rhh4J$d2N"d[ !IpX`n9 ocBe]b ?LS 9A / 8qZSZq55fWbT ű׽&Ф.V}pp@UU}$qbu} .O={ƚ4ml [,),1nbH`QN'wib]kIvill$o{$LNN_zA{zzsy{*ٚղxSH$B]]MMM E~[m}m$ffu'V KRl 2L~5N:iYA? CWX )XXSrѤ@U!q X&ʋ1b7Rl߾UU9ydmOOO388ȶmjW&nM4r_Ÿ ^#ϓ˙ނńoKUnx(b.l;x-XX| ?\wlvC<܂k|Grp8Lkk+pe#z`"UdF,sҥuӟ@ ɟq$1eʘ!u.$.L<{ h,ĠZhLMX`E"H3 v3M eL$iXijsr. RjaI>q8uo˰{P&2 $oϩShnn&\jO}]) Kb(\i|b Qf2el:*lJuI_,YXlGVeA@oomvJV͝{ tn*/+0㌏ʀ555Y&fyg+&O/L8&˭j3==MX\.~rrORYxO[ E5wtK4U0WoDc:E*X[[$ =?ys62BNQo+AWl$܆ R`U2Z(B ~_ɨ^˶+B{{\t7Wûk)z W^e5.R'Nө9R*Sҫ?[K)1RDIcK[\W,ItvvJu}]Dz,&''9vLf5.0.k9id2yOJ߃m׮]kr?e-4^KDoo/ Kleup8L" ɬ ٹs'P(dhh\.ZZϟw%3ՔZw IsNY'HJ2xM ͒Fr>( HT*dcCu6Oz1jZj]r7PU?$iBD"QSħ~ʹsv1Şȑ#spϖӧOJ:vgffT*U7{<siBPiۖ;'{d4jrk]͌@ @&!JAa(D2iXľHLS >8477s ĶYPchhh(BCC]]]455D* $I&&&V|2,ӶL NnOpfŝL&CKK 1>>NTZv 4z~e+V e0fڀ昙enig]c4gϝ;ERwY"ǎǥ$uK%TwMj0@ 3=`̠]Uqt%];vKlٖL-DIIv.g"[<<:g^]z; qJmmmZf_)q뾴یTiN['\nͨ$4}Kr>fpS6HٶJJ/qg]Ee伙;Loo/LNN8NLfUj}ҥK|6ms֭B= mQeTDN&I3SwL^9~>\PX20>5ѣ80BOOφ%*~ כ_^U-uvb``bKaĽP(0<<@ڷ!rLں ͚mJR<A? LLL4]OLLp%z{{\4It]'@g<𸹀~OSng$Ym ۙ留>:GMm7sվUuũݹ 99掖iZ~/iT*m5>`aaä́T0طo|x|aΟ?1)vmK.k.zzzq[mH@ܓ&2xS9NF.w 4F#رyյI߇hj5j:A288Ȯ]⤆"\^3J}73q~T5zrܪrl6KGGZp]d2ƍ7}v4iaak׮գ%h `(u]jZZVaYfddk׮qx544ľ}-­q7 d~ 8"cna5b.*~T}SG,n8i#tuw'Ӯm\g_1zF0}OqVF?Dvsㄮݻw䚦q1N<ِLr7or5tӧ|cIQ:8p!J}㠈-TGG_yw ÐnFFFJ~jrڲ, Xshv}5Rzc5pСUe*JXpv>LZT*1<& ~9m̂fǯ褫|>F5?b;S5aoX`oEw1~ʕ+LMMŤC;YVI[=twx8rd/~(⾁=iuaz{{q]7y>ox\EJAΜ9rB$2&'`}}} ;Z|>O\&^H+ζ6:;;TBZmbB78.饷b8v9Xj5'NҿpuîӔrbVw}c& |[jLJdN[###뎖;v7xJ$XI28p`˶х 2ةAuJ%GñaVVol6;nȉEiA Vav\$d5b?Qj߹3r~\.GZ'VFV+ڳUZΨkh[Hk,^8d[V&󒉪r!kL6 bi'Guh}EOZv(\;بYEH|Bvea\v-K^{5_jB什}O?͋/''{mI xBسg===J%Z[[W ( ˲BU%rR"ָ'&Nv]N4#deMFђ|>(,|>ߐ{dBs}v7pU+j8Ej#GEv:B#VtXl+ IKK˚=Y0%7h6.qLQDOXmewٟc˝yg89&ݦi288IѣGyשT*q`%YNf2/_رc[8K=ضJ"Ti.*:oWL>[ tZ Szs,x^輥uJT0=] ݺObG@שHgRdN)=p5˒6|i]KLRfk욾_g,oiLOOo9.^ 8ڞ$H-\~B@+P$g288ŋq i5B#ڪP}&;I%1Ҙ0 A>hfɕ&`6*O&=()lRľ}Vק-dzI!&c+ew4yj3ϰ˨mgwVϹbg7\?S.Lr}`vq13Bg==8hQXc6\Bz^PU:9&~T(%I1PeqUٳffctt'1IOJdA۶ğs!FFFyfܷ-.r7!x',q]PHb;3==e[oř3gb-{Z"#D>'w^~aΝ;אLrgݽ%v'FGGvyvEqWX6h6qr-J)NdYOw#Kk]V%rr>_yb󕜻1xs罐|Z~Ki7G6e8׺Z[[qA@+*6BZ /i[AT Qθ*1E)tAp*j vGIe&&&ؽ{7l47fN22ھ{{⯮:O<NZ6,;e133K'nݺGr1PPPP]VH`>) JRd̙3An$rpGo>.N.8<ъuenwv?;7 ?D}e)*Q Pk(p_d/..f{n[N]ae# 8wD Dlc+fr4j\z7XJ'$i_ob``/| XG)ݑEr}k~jd$iO:=u?vz&^FNeqQ z4={P*VZr˲jr]Q9='_30a1mioo-KRR*) Cj ˯gi!~X<{V3z%L歨oFCgxr>y¡_MeGO3-hL&TrEQ T tn\e+O]c'EWB3EI4K*(t]w+9Yv"{wΟ?߯ہ0%2i.nJ>/܅x'NݪY g.F&Er(ԑ 4cmqWX%={!ǹz^ܹsnɪ}^?[o zvQd0-CqF; dBy M:uwqazrlDj݅yv$xptyIܣ(ٰ Y\%[_ai&(yuGQ w^m_ٗΞ=@PYxxW{Bv lX2I̽myG4.]n__ouwwgϞ8ڞ'}Y*,pK5poW;ovU]aUғآN&`w^&'' ÐY*VP?_MK1DdCu L q2Nv>wfg"RX#ɨ|I)'˧}9`ާe*nV^XȰ3$͐|^c7Xb>A("tif]纸La. DvwKqA@F\uk\* H,io|JEKS71-j<{կ~0 cw nfgg&??W#$x׹rJLd5z衇x뭷md]d[]pXo/68q"e[[¯!|KD _G3jcE֚8 Au]xǙ\.;PM&:pt ҉"n蘦mض\V7 w 3quR{a[Ga<,ղ`&f-:sҫT3m,P)toworwkB"t4Gir!d| ۾ߤT}ߏAs6#NX~va/ݢe tik&n 4ݨw%ȆGib'j'8EJb!A$(baa!R /XEIK/M~/HVkR.ɨa {jx78pC166֐.8twwǞ6{ٿzzzVm'y~B ;DUk CwuELӌ|>OEǙd||rL{{5"ۍ>!Nm^nY+^B#]GӗltMG다nnݢcGw)F jcУ[M.*޲da=2E! Dr$MɭD=ݜU?JVNwxw(9w?яb ^횦{nl޴1 'xg6eJjeZXX`bbN2ɾr/W[[[ݴLf; @3Ke4|*7Bw5! $[[G?ŋaR՚N zs'tϫ[ݹsׯ7}tsJ=_|oHˡCoS P7AKetC'QbAHD @ǭ2Y=qÐKn+˿j6Ѧ}g;,C,TD `ipFrҒѨ$\I:996%ԟd].8}4N?hdT䮮.::6{n{1N:"-;GGGٿ |a#wcU}gS#ĆZjlE"Iw5ѰOAylm] t{v{*Y",j"h#<&gg$[&hA e]2#0"U%\9D!70%{>5<'159ͮ=۾H !߁.4Ms*˳uFc.>)9y}JF]rb9 vyGal'9b b\^kw]0 (w2lYֆqX-WgLMM144I/rĉ8P(Z|>o˲8p@y;趑ʧ Ð _B)I<*+jT*iq;K^-@7 A܇!,3̈́ j%Z#6߿>mY̓lCޖC!V?= Y,%m,㉶_Cidh"m?9[9VBMKoH;:37蚿Ïb`xӼrދ^DDLd~qgR+!m7 rPV,FsҶ-" <L&Ñ#G>x /EQ, L&ڎlJѣMfdP(lZrq[m*II_&P(PՈۮ>Ǭ2"Q4)D=ɷxvک::psmxV/Bv/m@#dM_HBAwp霡  %Et4>Y3^,Y7(hƂ#"(Gh:s3(@ae >wjQĠR~|,Nm 4kwNj=9X !P(\u[w'ST"S=^Lu;K&V^ӆ{3f-dWEvGNF70OTԩSK+Rv޳gLf˴MPK_?WT*_0mty'[q!(sr\8CZmb'w ȟ'rM3x˔psԲ-rT]x66LȰL>͕J@F ɧʦr" MHyt.Q`oiZ_5{f/7h#MQO ? ,>_a%eyLܬ?b\!fD 0LD%]fU ,t|5M = TfC{8o*njemvbB.ꫯ:X{V*{DddT*ٹüLOO78HeY _JJV]K,V(,|>ߐHӤ^A.g#a$g xvZZ7N5׆oq-Ӯ /sc$H<:^揾frybr;4Hgg&?Pd>.B 'E"_sg"I{'5M<\|U75hY;OͶXR+ֈ6Ӌ6ToW$YCA&i?O=V},,,G%M2c^?(J%&|~\LܷKɼҵ(ݒ;^监fe\.GX$8NCA+yrlŗhq\l+Lz߳D٣f^EqK-X+Q^őekp>|բ,.ml=X/L;eXX؎m[XE,b;+vND|AmZ5"3FQ$){:,./\\)|էUw\w퉝\2ڔLJNxҩDnQ2ܶ2D: //~p:55͛7ԧ>$Ɉf[Mv?yFGG1=nzV0fҾdJ܌ԧ͎f=i}(4M,bB`Kڬ8m۴jyky km>kgix)mpY\:}^qm 2h@RDib;3nL#<vD -mkIPvl)B^2MNH !k&_.jfk^}gn91oWB_V-JG[эjC@c~a}:am뾖ֻǵ$FGG~:›!N|lk) ZYLuZ(qL?kzznEqH{R&QK-v j܏533#zI}V:zHw%dfy}W$ʀ]Z$"QmlA }_+@wyU4:aă뺸mODܓIfד8+"t nEN2߭t r!(&:+'б#:55BZ3I{CNBWj!U1xuKE/A09:(ۼ6?kz<5KJNh֌&2Zt Q\.8Ύ"E?<WZ8AtM# BB?$ (B,h2[d}7uL+i W9~䁉FV2I0I- |\*\Xy!dR!' #-#S:x]ɨ&l\Ro?Gh-DU4k{;vTJSQ2jo3>>ΓO>ȎMt+J>rOծMy)z4NfkܬfyiY}_ڧ:"&y7`=C2ƯWktb0 P_Np9+~iZsܗC M#'REABg&fTxTLLKfEtD |o& ͆ 5}!f! Β;e5З%VYˊ,--ŒǷn(b2!ڎ|=CY&.%?e8ڌ[մOɝ;wÇyGw/m);bK)4nH;Hr&7̧pf\x꼦ºȻY?|5~Lي7F%hV4[`Pݸ3u%CwWԉA]*#UMC`9Q_YBǭ­t–.척UL2M۶q]7vLHnV_Ec^yfggE!lVAim[Eľv9BZ_Tzj;kr5 ê)"u,I_i[?&0-'AW67<&~sFStuFeO)3Ac7; n-sȌҶ>L iTK4nX<صkJ,Y5]>& |RY"\cyàhDt9&-Z@0E."4!5H3 9f\EfڍXufT1NdetxkĊCuBlN.`&J^˲T*⋼fc{EIM(GzR#}U7qu`hf'BPWrR(%Ͽ[P}䘏ЀG[(FX. f pHMZ2$OrrI{)6hrl4ߚI_!򞼖͈w};}(O&i DQWAt]7"fyZZZ(+"jia?ڶt z{3[ft7IOu6xEl GZҔdjcV_9vMuB0==י˜8q"&NBa񑌤'z:® EWnGzUc"[$Q)9YIWDnX$7d8Bu*.|BаJP60oEH 4sBX7VxEC:qV^4OW<.f}a;G-w쒁$qO]I]u].\ӧ<۶9|0Ggg=k'qFLϜ9Ù3gb.oFdKE6bHJNqW࣪krb,+'"˭fkq$Ae[9YJ-3%`LkefZʵqOd$(MӯݶK(<@ޓwS;xQZO@lH4s/}L&yrd[TҋŻ!Ҳb''?$'d=9FYR*" k(ܲ$J*f Id-WLVXlS]8(EC?N[TyՈN!?Qu0~K%R>ӌA8O6]aC$X4֓Sь7K~N&&OfD+((( '1IّHo: ^2m'E]F4 C.0 0 y_?5KZ+Ak;x>b;Ȏ-<#ɬ Iޛ%@'zoYNƎtmڵh5hZµ",jɓd pIOa`:rrGv"ɉw$='dcYӾwGIIdtj9Ʌj:Hy:=fd}.8q :E膁e؎88k8 7!]&(V!Ohmv(#cwb[u'҂TzP'ӮF׬F簖Qڭ(MכIEbUʳ6u0HasHimY8 T۶ ,fUPPP]AAaKu]2]FuR(ӘGZImf \T"" oH,-oC=j&a!)⾣=.' /( q10 \w+(((((⮠ RLKedJoJKgD=Zʨiu.!Kl!ˑf) ds9,>|/DB4eRPPPPP]AAacQհL\.mYBmBb\QGǿ½A잲o$3 !b.[@V*jj8E aB!&nAG:e7qR򘆁aQwz+j4E'2nFq,*axJNqBH}CAfqaaG;((((((⮠!d2ljeapwHyJ7yRX(((((<sjEqWPPPPPPPPPP]AAAAAAAAAAAwEqWPPPPPPPPPPP]AAAAAAAAAAAwEqWPPPPPPPPPP]AAAAAAAAAAAwEqWPPPPPPPPPPP]AAAAAAAAAAAwEqWPPPPPPPPPPP]AAAAAAAAAAwEqWPPPPPPPPPPP]AAAAAAAAAAa0U(((K!4M5ª}DcGQi3 cGX" pnPqFEj5W/K>ö혘)<d@]d_AwHp:i!0 ($H?EQ10~. C| ߿/&y}p^`fѴ!2 RISN1??O\&/۶ ðទV[[BzzzxGpȁ8|0iN2LNfv( ~vD._ۑX]_.!Cz@kHm ~Hyb~0Y\' qL|LZcsMH}r!`iAG|M}1鈢%Ξ>7n| =2q|~ۓw]"0V72* ==wƲ]heYx Ћ-uٻw/tuuQVw׾5"a LH;f'wxN}LS`Y]]5|rOznGKY4-X'hW#ZMׯ'α=48_"Ѽx6={Ex-I<$ImFvw;im[:t!\v!z.ɺkat4M,|"?D__ߊ,'l6K1y$3A <Dž kD&AffQ(d, qMhX4-/iͼBָP>ŢBъx̹0ڵk d *?{oqWtck+-%Jl˖&ck2Fg&LnνLdbljZb9DKDQA؁RG/B$4|ӧOWשz{3 }D”p@ >F1YKEE?<7|3P((ό?R$Çryg]WrWC|347O`\Rvw_$BbDMsqܪcÇ})1y$5ѣ=U],QKP nj-(p`a峡Xo~twwvb!|i0Cu)+++_ /vw}4=WNyd~Bfb ybH G%ħ VkEEeBzRsKtY/۸nVXA8N1Jyכ;g@[t|0x ۃiج6$)=żÑ#GNΜ9ӧ1M3(Je2yMk\ _ ?H(9p?೟MlG`#cc=-܂#p8v?–y8=1\@Yml؃0GoqNίx>G"fj_[uk]u\Hy4ZDZ:=wÆ #DZhhxudd2L[9qy2ϯ$pz΋v_g'O?͙~̸ыvc=$x-E^F`ݺuYH$8r##3P;Z[[ ZwMӨBӴlW`GޜhD}?xwւdO!D###+ K)Q{{Y5Ke/Ķ. aL;'$p|#3&`@iGNf'XT/sx |,5#I(8^d: `ZBp8B-[ʲL|Ռ-X=O]RR$8gg3R U8lVPi pyuSO`fGG\R3[8.\XbK sYBqɀbDwYОYdtg= 32khg ϼ's\ MBHdS}Se3Rы~_xǷ3>$Ӊu捆n#kXz֭k7QYQ /鴜"`#3%I:::X~=RJ1Μ@&L;# M3b䝟3qj/Zd 4hËH=7cNFioogǎadVVc6z+t(- QRRuбX,x^(++$sU?(Q[%:EVC(l6duYׯ[rf;tyo9 A}lV Q#v>V[r]wjV.X e)%[;u@{Д{IIv })Py OuNY@vdYDYYcqs0cǾQ#eeiM?t>}ߟ\T^YʜXK1O&'l|_ Ü;wzG}.UhpL&IZ2S-a"Pc?gtiHD`Hڵ6Jo Ecs\kH9NDBH_Z˻ѴYODmN[|) (RN2k;rE2#$BH-z`07i9lJ@YUơ%I5=8qkf)zScvEJQ:/Dbn+S 'ٗQNAq>P'xwmQd IDATH.+c9KFE0d͚5;vlb{\y~8˖Er#c9a?Nii,: HD>Ƭh o+)..Jdz C h').~[ b|lB!.x?ܑnNzoOΝ(3Eᅺ:Z[iP<ݗR\7۞Bn7---|_:/x衇$(wݞX4-k uiM0%Ґ(I`| 3Tт!,#keS8k ! #D˝JOO5\w <-**Vp IYY!̬ {?~ .`q: H)IF<VQCEE3_}xx~h-;cBߔT)x)Ơ)i6®ī9/~K4У`0 <*?^Ͷ0D՚`]gt4ƛoJĤC|c( ۷Hb5--GpAJJN^+<&JJJUw?#*_>Blk1M_R\\L[[ΞA7 wWcEakm-׬ /"ܗCd2ɏc&&&شiY￟}s8p7^-naǎ)|"RTTi1IP-0#cw?.!wiH!)?{_7mn/I-Ž32 npq b=/n;xq!0 .1 Xt7hbEQp\\csmkzիYv-;w덟`S ^k?!㥪;꿙u$! bÆ#SKt 92JsvUTTT`ۉF x\J烷*孷J/jĢMpϡC . %~S6?~Bd}=j% Z#C~|yp60kD HĒ{F|_׸{;0RJ8|~zoDQCUTEAQԄ'R[bShauYYUgdϞ~LBj6Y5;x LL f`fzs]{{ D^bjQK/'ɯB>@<!\g,(ӘE]wٚ..X~w1@,V|?crB?둿"#dj:E9')Dw9s`0H$a]k3y3U:{ ?+ovqGA:[.'ŰX,YvWFGcW^pߎewee]i+V@x+rU|H!xUhnn& .k$kd"5c޽ݻo}[|{{rHٓ)9[_Rs'BJ).)= xFnF4Ǥn9@x/N릙eIfLK1S|%\h\皦i|󿁦YI--oGGwx.!2:;e''hbÆjɞ~(q8HUU 'I!T**`0=>C{{a$I+.zW '?=}mh*{utnmm*dCrxRT]5J3v" c!T4+YZ96D:vMIII*oemi 9ɯSK0YDUuLSGQ,JI(cL,o l|܈[M]]N˅a8롡ahZx<'F[ 枳lYuχHd1ܼĴ/h՝ 0\MnbMtMTUrG(>PdzHBYS"BINu=;QK)Ij+Aj.BY.Ӏ]1$L[3 t} 7$T(?`Ǜ:GL"+  Μyӧ>:\YNv:ŢLcN8A(1Bg1h{D)fgʯs]K.vq|ILӤ l6ۂi$I$*|Mlp2 ,NM,׫͙5Nh״ٽ{7Vx'n8nʄWs6?=4 2 9;Sf̲ udӞʙ:X-=G~?5LL܄iV\6O$Tzzdlar_2bˉی IUUc~aTuIP\AA V~ _3>Ӡ}IܗCg X\EpX,DfX8?>(܆nrO Rd1)R.rbEn{d;S]_2Nɹ֬i0N0L%y{(4MnZXd4A=tm%ph4iLg1~iFPU㌍-L>9u4bQSv8~ h{Mss[;ϼB!jjj(++,t(fXq;{L_oA3$("1<"31AS"*B, 6ǹ}" ijQtCnqE:ܦSVހ1՜C-aqpH$B4Vo6 cAǟx\߇iίz<]Oaw"pvq8"`ll/L~!pi/?;$QĬ}b|<,p8V|LyMM5N Τ\0 UԽtH4M﹓n hYzi_KaLSYo!voqeBJ022¶m?{Z,+  @ `OKel@aNrAbf;O- %%Dh bh)4eѐ`H^Xﭡ MyIΌ)ʹUۃLđmL;dm, Dbѵ)QO :;D3:1ixcユpx{xbt%9|ˁIO}16$Xv}|S7]~ښ{fT'8=Dظ{Μ9 8Nuܱ5*XV!HQ1RB 8DML Db466r*++E4`ll~Wp8PWd=R;65}oirNQ2FG-,-&HRJ^+2+*EEE8egTu (Z.0nHmFΫxfIܗb!ifpTl6:::xx{;{ X6NGz.i^WR(<!."$iaZwӔd29109eXX[m\]Yɻ{Qw(˅4aa&/JgZQfv;8ǣߢ,qDv! =},[Iy{#Gz$P-7GW0B1OzW@{$&PSSCII cQ2s@jJ|E͔p~^%J/~kfI&Y/g |gzqW0v,b{1Ů6 4`&IPPF fZOYE4]I Ѷ dLn 6 el6JJJС˟5-88AӴnabù6ł!7MG"I& 7%üAMC= Ѫ%Mp_YH !رco66[J#X[} vLbrv!%%+IS3=!iz ͖gK[4 d<n5.tN &FNRHE _gdf`i\?$i-FDQ;o}~LSRl:̽B4Vxի Eim-gS$p8V|al&֭' rI}QmmmTUU,{!Lz,G/}?B(ՒiO>u5skaok ÏtuX+q̰dUjMPִ(hdE5Zz+ԭ3GrZV8X* N"d$ha^aΕIh].'VzE׸R=EQ҄mFHG~cIcF߇6S+ᐒqZK})g5De>Nii)ՓFӏs)Հ~U,Ó}eO1UYN? 6H8RJưl2qU*$_J CZ^l6Jinכ)ЮAmc^OUGPc\"L\gϲ1\.b /Ň|YAAy<- ay vi *IȔ bB'@A̸XB08RasY h2c/)(O} NkճEi)躆"uz Zѽ՘6Ql9Ͱ6FªTW dhhmUU)+[݌=iJ,s@Q'+Bww55k(.>LbDLdݺoO=͖:zN:B/_NYY@Ͷh s܃ -&񉷯4PMNqǝ &&&(--t :!ⳂD0I&q\Î92X8fkb0<g?<,hblٲ'NhhhEu3۩]'jyA,n){q?TWWsfz/9q`c7|5P9#Sz:ϩSW/0U\+T55iTJ=]NaLQe!{1M٪VVԾze2æW!6h?t:}J?bR,6Mdp-P2]EQR_UT@*J+B׳ REdSqȂ X4- McQn80M։eI~sx*vzΝdL)C554=k(L%. .2 h[V(/K(ݧrAə##ڀ^Xۿ8kL{{{ BPTT)pr:444z*N ?i' U_2!A5S'%M?%`y`6_/t㌬U,ϢFχba+,xb EnWp8z<%% DWJI2̙fUUEe,vp9}&8+p|qgPYK**'Sy Áy ~ ?j?C?0j$R|X=c"ϼ̼*5W3 yS6r-t{DѬL7}j\/(zD--tD?C!e'% O0>>n$@{I:I)p"TѴIjg" )par9^&tݘvƍmo!H٨9+'?&dw]"mmm444Z3vr465~zʪ7?'1 )HK2:oDż Io)D0 g8U\tPǕ*JKKinnǏ/Jq8b'jk/1.sLe2E)+Y4p8x,FJuElihAC?RR6R1/ 8>{XU-Lz %p@{w%%S#\WPr;9I~=W. b2O͌d@SNzOt]'KaPW͞l 虜I(~TЮ:a GNS,~^&!65hyUr7.xVUC,vx|7%%SS0MIII+WJJK 65kf˖-ݻljا1Euu5~ <Zt` )MMnϫZHG3=(g4K})hO`tJ˴O&*b5GI'A]7hY̲LHtg@۷iY.as\rB3 6Qc~ MXS코A; 1*VLc3jL6DlU`XV**D IDAT~.tWmm,_~!:I$tn6دpLGᩧ0 ڨP/pn7UUULLLr.@4Μ97pm*Pʭ|ePқ涴NGoMǎ#$ o;^{kRbv/ańՍ7]j P-j2f=6 ,G<)ٖqF,сi4 dd }>;I[')*bz|]9ye2BeݸE[H+-aZl'y[47##IilB{30:UCMMYRJ|{P䓓LžΡ(|$پx =pY%Wf uXu(2-+<) PR ߟ{b"Wݻ7S2lŢNcڧz)%.9#X41͔&gTRW[Nϭޚ[AUQώ,06kkD~#eU}j}xŝw%mqmƫJUUՔev͖es3-wl>cϼmGq i')/ p?z ^b} 2 Rz9WqzGr,Q`s\ov@PTTpt$F(-Aoc2¾ztO gh4`_Oo7p7ݴ"4M!.+냾<忠{4K/)*rLӷb.RP+`.[{3B!M2/6!p%6_y$ǎA|2?u@Jgۍ^/\58/!%ܗJ{af2dQ1)c36JO !H ~ Υtt:k<_4-B0>>ΝnAUS "e@:NҲqnqdch,&TQ=yEӳg蠽}9v- Lb-*n[D> ݆ahRX ܹsRUUE V@(ԝrv;E csDr@{>u?TO1qwlz؋8p?4L:dꩮf!`k_N4e||QFO(r9W29+ $ΊɺJYVib]`aX8Cqnk^2M^ O"(Y}JJJ㡇|kQމq:lbv9xp9<Cjζb322F"A,Fؼwog'M*S蜴=+UD:4]|kI0Ms!DB,T~ OҒA8LDmKªU W}>"LaEdl t[hm].X5fwHYp0tftߩIV_+*T0fjL͍Db-fHv;MD",wNzf+g _"hI~~^!IO4rLxoWN%NBVbO?4_RrpKi{ }Ac{#<9p bAi1#`q41q#eee466ri6oތi\.Ghj 8<|d $:Mޣ:a2(IKTVt: H%hnnf?i_\͝[Wo?Яp8.gѨÇWPS(]4]Oz\+RklwFZ)Jy8N, R(_y_ܹ} /d̎ڦbqAf;*#җduA2 e='}sڿ3lyaIvӊ@) $:Rjhb,e++ }O|7p:cNj/iZP(DQQѢk1v;Pݎa||H$pGyAYyYM lSN'FT,}ڊrۡ=5 -vTսB^;ϵ 7 Q[[ kˀl#K]]>ɍ7A uK҃1DfSmz_ V QTPPjFr¡CяZ=>O@b(VnIH n8EE8΂ 4MarQY"Zo֦&e)++ә͌K6]Wb /|tUU(//$5-e ){ZƢd39(٤ OIR 4A<a066Ʊcv󂃡>9g7Y1A8.jQJ7En>Pqɹ[&*p PMMM~ NݞG4 1>D~px%@nL7Nn402C,_.P+v!NZt]c͚#9>%Fhn6U%HR ^ye- &)U>}/)ksoDОKd{R`w7 s9nVsR, Z180tƤF#Y=@L`ӻs-4t~=#q8lڼ dzhib1>躞}LjX ?(;^ pH/ ŨP(C`G2hj+JI~/%Lf7d͚5% 9ZX,*++g8>yj, e?9w}wa[,#^lN@l.p5?3n&*++ٱc~;cZlb/*x<D"hCtw]JY~e"y2D 8Ǐg5).9ƍ[ihh=( 6~`än4$㌔_j9hm\\"3w8E s^w4}sa|?IIC:2qzr}wiZ%Y"1".,rX,qp]u Jd\A #E(hfxHj&(NUUq:8Nmۆa\P(/: FII `0/0: 9IyR`jQ*vx}Y6oތ녚e>G]<`w0`شDx{쫩Ǟ={ԧ>t: *BQQ---i00 6IfnmMq4@EUˑ#G*9xЏiL|K  lfg;3f嚑(RdΎl[PUU).. 4{?F)A"1sd3v;R>>ی©5kXԄYR\DL&9uy2i,V:Z2cZ(zI$kdsOLĠ`KrV]&eXAù3ijjjal<ߙf 3ԝF83^"ӟ4;va, /'XnDM9> S]#z {Jx+h)+~4Mcyp+s?rvw B\o2^7JyRv3 rAӕJy gPUVꦩiy֖#%G<}T1\/R!"=뤲q) ܙ?"D#MME -RN_!ுϞs1Lcf\SQ+9Kc_8^nku475p){F*g;v҂"UV-fjƹs0M&;SS%1SLIĝ]oAH;H*Aĭ;@\{?D ^8$HV*By L>3kYk=kRL \swOo:ԹaR Aӎ{at RjR08Uf#}"yի'N >>0())aA?NkBkJ6D֭peW`n9sC,CbnIFiդ ͚5ӓH&M(//&3gD H1#/.=89:%%s3? pӟ;Ҷ֩:뢊_FLBBrs/2JWwy'-[ 3STba׮@oD˖hOFuaK_]=&--*"bXF>ԉnh_ͤ]͚5Xx3b0Щ3?_)io֢0-eee?GrGrjԨZu4l=l6S\\Lqq1WzZhկ_}kEzzObvSeeff, Cy׌&δnݲO"%%%8qlTՕm[:*//R.]Dbb"ri0LҴi_n..^y)F85n䄋 P8̡CqrrӑOIҥK9sǏsi,zdf )-ukG+88yM{燯/X䒒Ξ=筿Jf]\\hѢ0' gOBi#Ŏ=?鏗WcZje}p̭xp_vv6=O OX2N;.. lDiҤI=%/|JJJD^1޵aÆxxxРA_W֯~BouF*N*[ŕ\.^HyyIJ"Isr>ޒCq):Di۶-~);w/QQ_zիgyYi۶-MzS.'.^HVVO&''K(.nAAAkZqrC\]]pt~ .q GSxxIxz6yhтƍ6O/xFŐF{FO={ X(,4Wɓdd4ԯZhmyʕ+䐕dZH\Bnnb>>>xzzJw̓ޭ]}HD+Y v0;SōWOQzI_]3ǣB|}}iժk'''1LL&)))aÆo߾*vGGGӤKHMh`ܴprraÆ} {ŕ?{uVdvyDá4ؾxUܘ|k"JEDDjVSjȿw wQ.""""]DDDDDw%"""""]DDDDD(q%"""""JEDDDDD(qQ."""""JEDDDDDwQ."""""JEDDDDw%"""""RW8*"uYjyyy4oޜ2?~<Æ Gnn.M6h4pE}ʈ!77ш'f___}q(,,f͚;GyDݫ}/f͚51k֬:׾gΜQjⓛow}lSNf̘Au 芻H1rHf̘G}ħ~ʠA={6ΝHaaaﭷ> 11D@@@u]YoڴR2Ș1ch֬==zLJ lrSz֭-o_MWS .0rH\]]ٴi7n$;;SNUz_NN֭ѱ 3p@>s6n_|Q=7K.ԫW[*d֯_ϧ~ԩSٵkd̜9$-[Fbb"׿tQ."5էOf3'OآE oёN:U֨Q?Iyy=oh42uT\\\pss{AoSOTpyJKK h4Ν;+'44uuKʯ_zz:ݺuuVN:ÇuQ."5gr(--eDDD0`׿VJZ~wĉx޽;5g}mp+/]euڕƍg]lժUtޝk#003gTz}xׯjȔ)SHIIG'11Ѯٳ}U ;;ɓ'ӯ_?z!{1?~<˖-#00@fΜIrr2C%,,W_{t֍;vL= `۶m<88Wĉ+]߿?'Ov_X,ر{l]޳gO O?M޽;_5aaa 0>}Xʷ[۷/1 `ݬYJu7|c=n8;;[FF# 6 IDATVDDvv6+V`ذaO`…$%%Gbb"<\޾}{Xhw&--ԛW<==$3 =fٸqѣG,Xp=ƍ4iC addd|TTAAAdddqFONϞ=7offپK/Q\\LBBW&//~W^yj*:vȡCXf QQQtŮيٳYq?m۶eΝ\rl6moA>|8 NϟJɽYd , ))hLBVV_~uQ\\iiiqwk.>}Mʷ[ѣ)..fdN>M׮]ox"WoܸqF~a1rN_{5Naa!֭[4Hոqc^{5>mF>}j|R2nZ򰰰*722rY7o^m,))ãۧ&^ݹXv-:u"''>ZIymёJ'8;;_3cӦMp_|gϞ%<<ܺd21az… 2 KtttVщXm}]t},_0 qfΜYu芻HV~}(((GGGN8a]~eiݺ<6~wijlܸX>x`M}z_端bСLsY233+/)))jWۮ+-Ņƍ`*]Dn%Bbb"yyytΆ l6b x衇l.P1c߾}deeyfL&Mog^^?sȑWڶ֭[sa HII9sLΝT; 8M6uٳgǏgرDFFһwobbb8f>cX,߿ÇIÆ //ke8q"ל<޽Kr)233'==[RRRlfԯ_ PE~' ~Ea[l߾|)))Ņ~qa0(--#))2ڵkGLLu'3f )) WWWzʹil>fʕ,_2 eyy9#Fdʔ)QQQ<2}Q|2&ɚ͚5Q׿Á_n|9vDDD3Irr2&L`/7v֍iӦYTuV 111 6#F?ФIU٪?Y=nݺJXzu֡'66S~}ɓ'?`޽,]sË/H׮]+m9wDFFV>|p9rݧb =#L<֭[Fii)xzzR^=vj=',, Lqq1x{{c0d6_nW=S3k,L&cѢE>|+Vp o?ɓ8;;Ӷm[&OLvرc .$''?AΝuQ."Rsc޼ylٲ妦WXXO? /@PPSN1bF_u?8 :gϞ5/--GҨQ#f3EEEdddpNuw8Kѣo&)))L&;xGPG%""""" Q."""""JEDDDD\ߜ9sٳg'_ș3gjŋs2}?d>x ۷/='O]PACDȯbo>oꉖRXXl=oܸ1]tPx֭[-֭[)((or?ٰa-CDoiӦchh(֭>VտiӦo:t(\;T8s L2UVb ~ϟ@~aΝ\tQFYxK,_?e˖ >\^~e~mNJff&qqq̜9P9ڵko(,,ё~#G\XXfb 1Ƛ̪U8{, 4s̝;Z1ܷo-/!22fm-~TUXV^M~2d/nWÆ ŋ&7oAzz:WWWzԩS_~ JHH`Ftt4v_Uf8oٳgqssآ+"R-)))Ջ ?n=n8zQ ,IKKؽ{7iiiʅ D\\ORTTѣ)..fdN>M׮]Ϭ qzX~= 4X,]ߵkIII7?ѣOxwINNV=ƍ4iC adddجϖEPPlܸӧӳgO͛lV ٿ?k׮%::RZZʎ;سg'11Ѻ<>>%K`fʔ)dee~Uמ\ 60uTvI""JE֘L&;F޽;Z7mȑ#h42~x HHHՕ˗/3vX:vHff&'NC;wH^z%5jh{磻T+Gpp0> ???UFqqgywww>SVsuuٙBfϞM@@瓓cw9=zb„ ۗsQTT`Ν;3j(K.eԨQ quue޽6ϞWUKKKYv-cƌ!((ooo~%"R֭xxxбcZK333)++UV\\\h֬ǎ~ie˖֤''JYpf̘QȠCֿ ˗/V;waÆF7oNvv_C`` 1ՙ]h۷xN8SO=ŕ+WO>ɓ'0` w&** ނ?Ε+W=b CgΜɡC?>:u"%%'(++՘Qmu3888ЦMMСC/ӧٓvŞ={x嗹;XrEGG_3V_/TTEO@D쑝͗_~ILL$11+Wb2B:;;SPP`o|WzGGGN8a}dggӺukq߾}DDDйsg;FG9p@%ŅdeeoƧ&fΜٳg;:r1sl6? eN8޽{qww׷ʙjf͚pqkG{EDH)**E[_ر#M6iݺ5lrM9WGVV7od2ٰa999fVX=]شiSj ̙3dff2w\߿V;s ~-fK.pB믿f۶mdggcXtڵg,]SNI||IJik֬ݻW_}uM""[ "<ODEE1n8^xRRR0 q^|E;Fpp0<3xzzZgX,̘1$txӦM^z{DYYڵ#&&???z)ә5k&yh">̊+8pѦMywaΝ6!z{{c0d8pŋO?D`` ,kЄ ؿ?͞ݺucڴi4o۳Vl999lݺ@LL Æ cĈ4i:OUyCQQf.]0i$ڴicWܰa ӧO'00޽{[ww}[޽;'N{ֲmǖÇӷo_>c ݻYf !!!:VUmֿ 99QFѯ_?"""xWXjݻw'&&~ș3g_ڧSձ 5ާ}YڶmKll,L2y~?UOu[߫۷{~ZnߊQ.Kii);v`Ϟ=̟?ϒ%KX`IIIDGG3e¬Wׯ'99AbaZ;r!֬YCTT]t!##$<))8'~vqwСC1L<Ӵo߾ڱSNܹG}f|fΜ7 6 exC߾}ɟW}h"vMZZNRn[FMqq1'88%Kpivg}f^z?~yF'|»kM,ǍG=*joO"QQQƍ>}:={d޼yfOUS[ѣlܸI&1dfϞmr{_DԪsQTT`Ν;3j(նK2j(|}} Օ{U~dd$/5h4rRRRdLJ{wwwyw4h rĦM9r$FƏOAA iӆcǎa6ٿ?'NnݺZqھ};[laɒ%xxx Ν;)--d27d35e+>reƎKǎdĉtЁs,FOOO'((VW\\< 볶U{ʯh"oT[;pmV),,dN~~>9996˴>թo+3gz3<;~kkѾ"g / O>$* O>ߟ(aʕ[̅ ^ߚ5k/d2]=zBBBl.?reeej>5kƱc۷/&lO=Ctt4ϟ;>?ȑ#ҡC벪_:??Z^/^h=վ}{8päٙս9={Lw߱yh fFWDؠA8~8vbuVwnٶmX,.]@vxٽ{7K.ԩSdffOzz]oڴ)'Ousqqalذf3+V͍z6mӭ[7ZlI HOO;ށsĉC~Oîbbb8p`ضo+#++͛7c2ϭ?[5a{Ν9}4~5Ajݺ5lR:V>߉'?Xvq 7??3gΐܹs6˷wUVoU"Wٹs'˖-nݺꫯZ|nذN*S^=vN2>]vѬY3:쉿-3f+{fڴiԫWf|SOάY0L̛7EqaVX.ʔ)޽kդ8pŋO?D`` ,^z\p_|cǎLDD< DEE_ڧ+ >#Gyfʕ+Y|9eee899YO1blݺ@LL Æ cĈ4i:3PUIII~E8ۿ?ͺݺucڴi1ʷgw+]D7r!-ZtS7N_aa!!!!ݻ ТPsvYDzl2"##ԩ}Ep4gϞ' //777vZ7tjMQ*j_ ?N^^YW橒R!77hl6O||< deea2h׮SLVoҥK)((͍NF믳sN|||nm^~=qqqҴiSF#/^ߧSNjpZj+VO>[jPlذDƌCfHLL$11N%RXXXb@bb"wuaaamڴk2p@v]psscĉ՚_石qF u_5nܘ.]T9r5!_~5n8zPD+]۷/8;;3f駟.󔖖hÃ;w*пP֭[W^E-ZYKNUDիׯC !66^~e7 ==bgfBBBׯ'77777 eٲe,[ egHHL&ƏOΝ5j< HMM,_?e˖6Otuu_୷ݽRdƞ={ZO˵Krw >\^~e~mNJff&qqq̜9Q;w.6m"""h"Ο?_"##9rlk[믍8rk׮% F>k{̪֟U8{, 4s̝;zoU6WUׁj\훒r!".b(`ƍL>={2o<Nccc)--eǎٳ瓘h-#>>%K`fʔ)dee1x`VZEǎ9tk֬!**.]AIKKcѢE޽4v D\\ORTTds7#==$ڵ&;v燯]}ևőFZZw}-ѣ)..fdN>M׮]s|tUI֭G壏>bƌ<̞=k.>}z_Om?5'U?%%ѣG'l׺oU6WUWmoOV?DDH;;;SXXٳ  <<|rrr8wEEE W+եK2j(k+{LJ{wwwyw4h tfL&6mȑ#h42~x HHHڵp^x;vlذ Vz:j]+/_fرtؑL&NH8w\oԴ...899Q\\kFǎ5j|駷<5h"o^훚+;pmVu[돋#88|_?[nuiߪhHZgL[qsO>ɫʀӧ'** 999\uY3\p:ze]GHH!!!5Lhժ55kvMr]kk׮>N>bժU,Y'~օ5nܘ-[~puuɩVGM߹sg4h˕5kFvvV$ϛÐ!C*nkDFFZ6 [nEiߪ(qU={$!!]vg^~eV\i#::Nj_b3]ZBB .dojecGZ2L׽_U?Fح[VkNNN1{=+{2"hΜ9f?pBl‰'ػw/R+c~~~>닣#'Nvek-?saٲek?nfdee_'WUΞ=Kfff\ؼy]o߾=Q}[[ǟoow__Ͷmbp%2yvҥK9uǓn:*L۷,6oތd9Ά l6b x衇nylJJJ2e ]tt[ׯ6_a9s ̝;ooo_'ĉqYsZ ;w.Ǐ|:Q|[ǟooH'zryG˘L&Yغu+ ƈ#hҤ }6l !!'Ob4b̘1DDDXבʊ+8z(0ydRRRXnyyy888X/^?O[,f̘ARRu:iӦ0R{=(++]vǺuZKz++\GXXIzڵ+ ,{ꩧHOOg֬YL&͛ǢE8|0+V{Vqttnݺ1mڴJcƫ_97HƏ_̙S+t7okAUV\)++z廼#FK/ٵxb~' dv?jFjoœS"]Dc„ 4mڔYf(,,$$${ҰaC5ahV-[FddvѬ2""K,!==W_}Ō3 -2tPڴiF?  hwQ.""""]DDDDD?W'C IENDB`refind-0.11.4/docs/refind/using.html0000664000175000017500000007300113372346574017543 0ustar rodsmithrodsmith The rEFInd Boot Manager: Using rEFInd

The rEFInd Boot Manager:
Using rEFInd

by Roderick W. Smith, rodsmith@rodsbooks.com

Originally written: 3/14/2012; last Web page update: 11/12/2018, referencing rEFInd 0.11.4

This Web page is provided free of charge and with no annoying outside ads; however, I did take time to prepare it, and Web hosting does cost money. If you find this Web page useful, please consider making a small donation to help keep this site up and running. Thanks!

Donate $1.00 Donate $2.50 Donate $5.00 Donate $10.00 Donate $20.00 Donate another value

This page is part of the documentation for the rEFInd boot manager. If a Web search has brought you here, you may want to start at the main page.


For the most part, rEFInd is easy to use; just use your keyboard's arrow keys to select the OS you want to boot or the utility you want to launch and press the Enter key. A few details aren't entirely intuitive, though, so this page describes them.

Using Basic rEFInd Features

With rEFInd in place and added to your firmware's list of boot utilities, you can reboot your computer. Depending on your configuration, rEFInd may come up immediately or you may need to select it from your firmware's boot options or reconfigure your firmware to present rEFInd automatically. Unfortunately, I can't offer much specific advice on this score, since EFI implementations differ so much in their user interfaces.

Assuming rEFInd starts up correctly, you should see its main screen, which resembles the following:


rEFInd presents a GUI menu for selecting your boot
    OS.

If you don't press a key before the timeout expires, the default boot loader will launch. (The timeout is shown beneath the description line until you press a key.) This is normally the item that you launched the last time rEFInd ran, but you can adjust the default by editing the configuration file. (In this example, it's the Ubuntu Linux loader, which is further identified by text as EFI\ubuntu\grubx64.efi from ESP.)

This display is dominated by the central set of OS tags (icons), which in this example includes tags for an unknown Linux distribution, Ubuntu, OS X, and Windows. All but the first of these are on hard disks, but the unknown Linux boot loader is on an optical disc, as revealed by the small icons (known as badges) in the lower-right corner of the OS icons.

In this example, the Ubuntu tag is selected. You can move the selection left by pressing the left arrow key and right by pressing the right arrow key. If your system has many boot loaders, an arrow icon will appear to the right and/or left of the boot loader list, indicating that the boot loader list will scroll when you move off the edge. (Such an arrow is visible to the right in the sample screen.) You can scroll the list by one line full of icons by using the Page Up or Page Down keys to move left and right, respectively. Moving past the final selection or using the down arrow key moves the selection to the second row of small tags, which launch ancillary programs or perform special actions. If you've moved the selection cursor to the second row, pressing the up arrow key or scrolling past the left edge of the second row moves the cursor to the top row. In this figure, these eight tags are present:

  • Launch the EFI shell
  • Launch the tool to partition a disk (gptsync or gdisk)
  • Launch a memory-testing utility
  • Launch a tool to edit Secure Boot keys (MokManager, HashTool, or KeyTool)
  • Launch a Windows recovery utility
  • Produce an information page
  • Reboot the computer
  • Exit from rEFInd

By default, the options to display an information page, shutdown the computer, and reboot the computer are present. Options to launch a shell, launch gdisk, launch a memory test utility, launch the Apple recovery utility, launch the Windows recovery utility, and launch a Secure Boot key management utility will also appear automatically if these utilities are installed. A tag to reboot into the firmware appears if your firmware supports this feature. Options to launch the hybrid MBR tool (gptsync) and to exit from rEFInd are not displayed by default; you must edit the configuration file to enable these features, or to disable those that are displayed by default if you don't want them.

To launch an OS or utility, you should select its tag and then press the Enter key or the space bar.

Ordinarily, rEFInd displays tags for OSes it finds on internal hard disks, external hard disks (including USB flash drives, CF disks, and so on), and optical discs. Sometimes, though, the firmware hasn't had time to fully examine these devices by the time rEFInd starts; or you might only insert or plug in the media after rEFInd appears. In these cases, you can press the Esc or Backspace (Delete on Macs) key to have rEFInd re-read its configuration file and re-scan your media for boot loaders. This action can take a few seconds to complete, so be patient. You can also use this feature to detect OSes if you launch a shell and use it to load a driver or edit the refind.conf file. If you regularly need to press Esc/Backspace, you might look into the scan_delay configuration file option, described on the Configuring the Boot Manager page.

On some computers, the firmware doesn't mount external USB media unless you adjust a firmware option or use the EFI's own boot manager prior to launching rEFInd. If you don't see external media appear in rEFInd's list, consult your computer's manual or examine its firmware to locate a relevant option. This option is often called fast boot or something similar; when enabled, the computer doesn't activate most USB devices because doing so takes a second or two.

Adjusting Boot Options

If you press the Insert, F2, Tab, or + key, rEFInd will show a menu that may hold additional options, depending on the OS type. (OS X and Linux are most likely to hold interesting options on their submenus.) The following figure shows the submenu for Mac OS X. You can use this menu much like the main menu; move the cursor to select the option you want to use, then press the Enter key to launch the boot loader with the selected options. Press the Esc or Backspace (Delete on Macs) key or select Return to Main Menu to return to the main menu. (See the Methods of Booting Linux page for information on what you might see on a Linux submenu page.)


rEFInd submenus enable you to set session-specific
    options.

From the options submenu, you can press the Insert, F2, Tab, or + key again to edit your boot loader options. You're most likely to want to do this when booting Linux via its EFI stub loader, since you can then enter arbitrary kernel options. A simple text-mode line editor opens (shown below), enabling you to move a cursor back and forth in the line with your arrow keys, delete text, and type in new text. If you want to boot with your edited options, press the Enter key. If you decide you picked the wrong entry, press the Esc or Backspace key. Note that long option lists, as shown in the figure, scroll off the edge of the screen. Moving the cursor past the screen edge scrolls the entire line of text.


You can edit options passed to the boot loader on a
    single-boot basis.

If your computer supports Secure Boot, you may find that some of your OSes and tools won't work; they'll produce Secure Boot validation failure error messages. You can overcome this problem by creating a signing key, signing your binaries with it, and adding the public version of that key to your machine owner key (MOK) list. This process is described on the Managing Secure Boot page.

Using Keyboard Shortcuts

Although most rEFInd features can be activated via fairly obvious keyboard actions, some are not obvious. Table 1 summarizes the keystrokes that rEFInd accepts, and the action that each keystroke invokes.

Table 1: rEFInd Keyboard Shortcuts
Keystroke Explanation
left arrow Moves the selection one icon to the left (or up the list in text mode)
right arrow Moves the selection one icon to the right (or down the list in text mode)
up arrow Moves the selection from the utilities row to the OS row (in text mode, moves up one entry)
down arrow Moves the selection from the OS row to the utilities row (in text mode, moves down one entry)
Page Up Scrolls the visible set of tags to the left (or up in text mode)
Page Down Scrolls the visible set of tags to the right (or down in text mode)
Home Moves the selection to the first item on the OS row
End Moves the selection to the last item on the utilities row
Esc or Backspace (Delete on Mac keyboards) Returns from a sub-menu; on the main screen, re-reads the configuration file and re-scans for boot loaders
Delete (on PCs) or minus (-) (Delete on Mac keyboards is Backspace on PC keyboards, and will not work for this) Hides a menu tag. The tag is remembered via the computer's on-board NVRAM.
Insert, F2, Tab, or + From the main menu, opens the selection's submenu, which is most useful with Mac OS X, ELILO, and Linux kernels with EFI stub loader support; in a submenu, opens a line editor enabling editing of boot options
F10 Saves an image of the current screen in the file screenshot_###.bmp, where ### is a sequence number starting with 001, in the EFI System Partition's (ESP's) root directory
F12 or (on some keyboards) Eject Ejects removable media. This feature only works on some Macs, not on UEFI-based PCs.
Enter or spacebar Launches the currently-selected OS, utility, or built-in feature
1 through 9 Launches the specified boot loader by number
A Displays the "About rEFInd" information
E Launches the first instance of ELILO in the boot list
G Launches the first instance of GRUB in the boot list
L Launches the first Linux kernel in the boot list
M Launches the first Mac OS boot loader in the boot list
P Launches gptsync
S Launches an EFI shell, if available
U Shuts down the computer (but note that this is buggy and reboots most UEFI-based PCs)
W Launches the first Windows boot loader
Other letters Launch OSes whose names begin with those letters, as described below

rEFInd assigns shortcut letters to most OS entries based on the first letter of the directory in which the OS's boot loader is stored. For instance, if you have a boot loader called /EFI/debian/elilo.efi, rEFInd attempts to assign it a shortcut letter of D. rEFInd overrides this default for Mac OS X, Windows, and for Linux's GRUB, ELILO, and EFI stub boot loaders if the distribution can't be more precisely identified, as noted in the preceding table. This method works well for many installations, but it can produce conflicts. For instance, if you have a Macintosh that holds both Mac OS X and Mandriva, both OSes would normally use the M shortcut key. In practice, which works depends on the order in which rEFInd detects the OSes.

Booting Legacy OSes

Sometimes it's necessary to boot a legacy (BIOS-based) OS on an EFI computer. This is especially true on Macs, since this has been the usual method of dual-booting OS X and Windows. (Since the release of Windows 8, though, booting Windows in EFI mode on Macs has become both more practical and more common.) In the past, many Linux distributions installed more easily in BIOS mode on Macs, but many Linux distributions now favor native EFI-mode installation on Macs. (See my EFI-Booting Ubuntu on a Mac page for an in-depth look at this topic.)

On UEFI-based PCs, booting some OSes in EFI mode and others in BIOS mode is less often necessary, since it's usually easy to install all your OSes in BIOS mode. If you have a working EFI-mode OS installation, though, and if you want to install an OS that lacks EFI-mode boot support, you may need to boot in both modes. Most of the BSDs (FreeBSD being a notable exception), Haiku, DOS, Windows XP and earlier, and many more obscure OSes still lack EFI support and so must be booted in BIOS mode. You might also want to boot a BIOS-mode emergency recovery CD, such as Parted Magic or System Rescue CD. Note, however, that EFI-mode support is being added to OSes. It's possible that some of those I've mentioned here will support EFI-mode booting by the time you read this!

To help out when you need to boot in BIOS mode, rEFInd supports booting legacy OSes; however, the details vary between Macs and UEFI PCs. Also, be aware that some UEFI PCs lack the Compatibility Support Module (CSM) that's required for this feature to work. This is true even of some computers that can boot BIOS-based OSes natively. This can happen because the firmware is basically a BIOS with a UEFI implementation tacked on top of it; such systems rely on the native BIOS to boot, and may not provide a way for EFI applications to access the BIOS features via CSM mechanisms. If you have such a computer and if you enable a legacy boot option in the configuration file, rEFInd notifies you of its inability to present legacy boot options when it starts up.

The scanfor option, described on the Configuring the Boot Manager page, controls rEFInd's detection of legacy OSes. On Macs, the default is to scan for such OSes, since a common boot scenario on Macs is dual-booting OS X and Windows, and of course BIOS support is required for this. On UEFI PCs, rEFInd defaults to not scanning for legacy OSes; thus, you must edit the scanfor item in the configuration file if you want to boot a legacy OS on a UEFI PC.

The legacy OS icon is identical for all OSes on UEFI-based PCs.

On Macs, rEFInd uses a flexible scanning algorithm inherited from rEFIt. This procedure detects most legacy OSes on most disks, although it can sometimes miss an OS. This scanning algorithm can often identify the legacy OS you've installed and present a suitable icon. On UEFI PCs, rEFInd relies on the computer's NVRAM settings to determine which legacy boot loaders to scan, but rEFInd does tell the firmware to find every BIOS-mode boot option and add it to its NVRAM list. On most UEFI PCs, at least one hard disk and your optical drive appear as options. On one computer I tested (a Lenovo laptop), the internal hard disk appears in the rEFInd menu as a removable disk. If you have multiple hard disks, you may need to uncomment the uefi_deep_legacy_scan option to get entries for booting all of your disks. If you opt to scan for BIOS-mode optical disks (scanfor cd) on UEFI-based PCs, an icon will appear whether or not your drive holds a CD. The UEFI scanning procedure is also incapable of detecting the OS type, so you'll see a generic legacy OS icon, as shown at the right.

On both PCs and Macs, if you see non-functional legacy boot options, you can remove them by using the dont_scan_volumes token in refind.conf: Add any substring from the description that appears when you highlight the non-functional option to the set of options to have rEFInd ignore that entry. (Note that you must provide a complete volume name when excluding EFI volumes from scanning. The legacy-mode exclusion operation is more flexible in this regard.)

Reducing Startup Delays

You may discover that rEFInd takes a while to appear on the screen compared to other boot managers and boot loaders. Ultimately, the reason is that rEFInd is doing more—it's reading more filesystems, scanning for bootable files, and so on. In most cases, rEFInd takes just a second or two longer than other boot loaders, but I've heard of (and seen) much longer delays on computers that are configured sub-optimally. Some things you can do to reduce these delays include:

  • Remove unnecessary drivers—Simply loading a driver takes a certain amount of time, and if a filesystem driver finds a filesystem to read, rEFInd will spend time scanning that filesystem for bootable files. If there are no such files, or if you're not using them, then this is wasted time. Thus, you should check the drivers, drivers_x64, or other architecture-specific drivers subdirectory to be sure it doesn't hold unnecessary drivers.
  • Use FAT for /boot—This tip is a corollary of the preceding one. If you use rEFInd to boot the Linux kernel directly, and if you rely on a driver to read the Linux kernel, then you'll have to live with the time to load the driver and to scan at least one extra filesystem. If you mount your ESP at /boot, or even if you create a separate FAT /boot partition, you'll save a little time. Note, however, that most Linux distributions don't allow you to install to a system with a FAT /boot partition, so you may need to set this up after doing your initial installation. If you see symbolic links in /boot, be wary; your distribution may rely upon them, and because FAT doesn't support symbolic links, this action may cause problems when upgrading kernels. On Macs, you can use HFS+ for this purpose, since Apple's EFI implementation includes an HFS+ driver.
  • Minimize the number of scanned filesystems—There's overhead associated with every additional filesystem rEFInd scans. Thus, if you have, say, separate ext4fs root (/), /boot, /usr, /home, and /var filesystems, and if you install rEFInd's ext4fs driver, rEFInd will end up scanning at least six filesystems (counting the FAT ESP), although only one of those has Linux kernels. You can use FAT for /boot and remove the ext4fs driver to speed up the boot process, as just described; but if you prefer to avoid the downsides of that action, you can switch /boot to some other filesystem, such as ext2fs or ReiserFS. This plan will reduce the number of filesystems to be scanned and improve boot time. Alternatively, if you re-install Linux, you can reduce the number of partitions or use LVM (which rEFInd can't read) for all of your filesystems except for /boot.
  • Use a speedier filesystem—In my tests, rEFInd's ReiserFS driver is the fastest and ext2fs is the slowest, with Btrfs and ext4fs falling in-between these two. The difference is trivial on some computers but it's noticeable on others. Filesystem speed differences are more likely to be noticeable in the time it takes to boot the OS; rEFInd's own startup time is less likely to be affected by a filesystem change.
  • Use a speedier driver—rEFInd 0.7.0 introduced a read-ahead cache in its filesystem drivers, which greatly improved their speed on some systems. If you're using an older driver, try using a newer one. Pete Batard's efifs drivers are an alternative to rEFInd's drivers. The efifs drivers are still very new and rapidly changing. My initial impression is that some of them are quite speedy, but others are very slow.
  • Delete or move files and directories—By default, rEFInd scans the root (/) directory, /boot, and most subdirectories of /EFI on every partition that it scans. If these locations exist but contain no bootable files, they'll just slow rEFInd down. Likewise, if you use dont_scan_files to keep unused boot loaders out of the menu, rEFInd will still do much of the work of scanning those files. In all of these cases, deleting or moving the directories or files that are being scanned but that don't contain bootable options you want to see can speed things up.
  • Use the also_scan_dirs option sparingly—Using also_scan_dirs is useful in some situations, but it does add to rEFInd's task list. Use it only if you must.
  • Reduce the scanfor list—Removing items from the scanfor list in refind.conf can speed things up a bit. This is especially true on Macs, which scan for BIOS-mode boot loaders by default. If you never boot a Mac in BIOS mode, try uncommending scanfor and ensure that the hdbios, biosexternal, and cd options are not present. The external and optical items won't add delays unless the relevant media are inserted, which brings us to....
  • Don't boot with removable media attached (unless you intend to boot from them)—If you insert an optical disc into your drive or plug in a removable device like a USB flash drive, rEFInd will attempt to scan it. This will slow down rEFInd's startup process, so you shouldn't make a habit of booting with such media inserted. In fact, there's another reason not to boot with external media attached: If such a medium is infected with malware, and if your firmware is configured to boot from external media first, you'll end up running the malware, possibly infecting your computer.

I hope these tips will help you to overcome any speed problems you're experiencing. As I said, rEFInd is reasonably fast on many computers, so you might not run into problems in the first place. If you do, though, reducing rEFInd's workload can help.


copyright © 2012–2018 by Roderick W. Smith

This document is licensed under the terms of the GNU Free Documentation License (FDL), version 1.3.

If you have problems with or comments about this Web page, please e-mail me at rodsmith@rodsbooks.com. Thanks.

Go to the main rEFInd page

Learn how to Configure rEFInd

Return to my main Web page.

refind-0.11.4/docs/refind/about.svg0000664000175000017500000021345712626655722017375 0ustar rodsmithrodsmith image/svg+xml refind-0.11.4/docs/refind/mkrlconf.html0000664000175000017500000000564513372357235020236 0ustar rodsmithrodsmithContent-type: text/html; charset=UTF-8 Man page of MKRLCONF

MKRLCONF

Section: rEFInd Manual (8)
Updated: 0.11.4
Index Return to Main Contents
 

NAME

mkrlconf - Create a Linux kernel configuration file for rEFInd  

SYNOPSIS

mkrlconf [ --force ]

 

DESCRIPTION

To boot a Linux kernel directly, rEFInd must normally pass system-specific parameters to help the kernel locate its initial RAM disk (initrd) file, the installation's root filesystem, and so on. rEFInd stores this information in a file called refind_linux.conf, which is stored in the same directory as the kernel(s) to which it applies. The mkrlconf script creates this configuration file in /boot, using the current boot options (from /proc/cmdline) to populate /boot/refind_linux.conf with boot options that are probably (but not certainly) correct.

The file created in this way has three lines, which correspond to three entries on the rEFInd suboptions menu. The first entry boots using the options found in /proc/cmdline. The second entry boots using the same options as the first, but with single added. The third entry boots with minimal options of ro root={CURRENT_ROOT_DEVICE}, where {CURRENT_ROOT_DEVICE} identifies the current root (/) filesystem. Users may manually edit the refind_linux.conf file to suit their needs, of course.

 

OPTIONS

--force
Ordinarily, if mkrlconf finds an existing /boot/refind_linux.conf file, it refuses to replace it. The --force option causes mkrlconf to replace the existing file in favor of one it generates.

 

AUTHORS

Primary author: Roderick W. Smith (rodsmith@rodsbooks.com)

 

SEE ALSO

mvrefind (8), refind-install (8)

http://www.rodsbooks.com/refind/

 

AVAILABILITY

The mkrlconf command is part of the rEFInd package and is available from Roderick W. Smith.


 

Index

NAME
SYNOPSIS
DESCRIPTION
OPTIONS
AUTHORS
SEE ALSO
AVAILABILITY

This document was created by man2html, using the manual pages.
Time: 20:12:13 GMT, November 12, 2018 refind-0.11.4/docs/refind/editor.png0000664000175000017500000000320312626644767017527 0ustar rodsmithrodsmithPNG  IHDR-gAMA a PLTEk2tEXtSoftwareXV version 3.10a-jumboFix+Enh of 200705202IDATx1n8@ SfO N!x  R䱜͎x<E~z槨fBzo(k(k({я^<9X7v+LjF~x>D;~1U< QT)8)o{{^wO؛jmSv*N|SW-_F۷%z**&u~* gbnqEoEaT|0ţ+򵊻W}WE߳fW k(k(k߾?2Tm&*)PP%hK ەa[kM7ak[qqrV|I$TѺ^MՊ3J/uTMk%W|Ub]Q%]1U_VdT1Wb(r sEsIqGQG~UgcM%EmSV~Z[CSӠgN뽴>^RMcl|uV1Z=66<6wد%RWE(z5}\jX%nZ\R=x MWQI6<֗XT*YوbQY]JR*ZU6%mbgkIG_Aq4Ζo*y]]YE_Uz=szhK8=m)\Dm-ݿ(3O꣢;֓[:?t:mN_{>G,/fFM*:kz{߾) Ith^O(ߥW#[Sw[++V{OKH/J%y$"8P\{|Fq C&#a<Ыԇd[-8TqYV px T%,ȦkRZjWzI~ cD6Rf>csyiuL譬҂bh:u+XC{ģM;c#4C4;WDO# [me{1ɖ Z ~U犞)?`!9C%S(ư؜rh;,7J]DDzD1b8*)6KZY6+1uZebyl\^R?e%ʠSQv!6.+>ϐ=$jN{Qcu% ^Ώ͍E76|=15D"MN*Zk)vZ %n.]7_O}O_A",ӒtIMEWbIENDB`refind-0.11.4/docs/refind/bootmode.html0000664000175000017500000004352213372346574020233 0ustar rodsmithrodsmith The rEFInd Boot Manager: What's Your Boot Mode?

The rEFInd Boot Manager:
What's Your Boot Mode?

by Roderick W. Smith, rodsmith@rodsbooks.com

Originally written: 3/14/2012; last Web page update: 11/12/2018, referencing rEFInd 0.11.4

This Web page is provided free of charge and with no annoying outside ads; however, I did take time to prepare it, and Web hosting does cost money. If you find this Web page useful, please consider making a small donation to help keep this site up and running. Thanks!

Donate $1.00 Donate $2.50 Donate $5.00 Donate $10.00 Donate $20.00 Donate another value

This page is part of the documentation for the rEFInd boot manager. If a Web search has brought you here, you may want to start at the main page.


Before you invest time in downloading and trying to install rEFInd, you may want to verify that you can actually use the program at all. rEFInd is useful only on EFI-based computers, not older BIOS-based computers. In fact, most EFI-based x86-64 computers provide a Compatibility Support Module (CSM), which is essentially a BIOS emulation mode. Some EFI implementations are in fact built atop a conventional BIOS, and retain BIOS's boot abilities via this underlying code. Thus, it's possible that you're currently booting a modern EFI-capable computer in BIOS mode.

Unfortunately, determining which mode you're using can be tricky; the clues are subtle or hidden in ways that require specialized knowledge to extract. This page will help you figure it out. I first present general information on identifying your hardware's capabilities. I then describe ways to identify your current boot mode in both Linux and Windows.

Identifying Your Hardware's Capabilities

Let's get the easy case out of the way: If you have a Macintosh with an Intel CPU, it's got EFI capabilities, and you'll be able to use rEFInd. Earlier Macs with PowerPC CPUs use OpenFirmware, and rEFInd can't be used with them. If your computer shipped new with Windows 8 or later, it almost certainly supports EFI; Microsoft requires that computers that bear a Windows 8 logo support EFI, and boot in EFI mode.

For everything else, it can be harder to tell. Your best bet is to locate a PDF version of your computer's or motherboard's manual and search it for the string EFI. Checking your firmware's options via the firmware setup utility (typically access by pressing Del, F2, F10, or F12 at boot time) is also worth doing, but you'll need to check every option yourself. Most EFI-enabled PCs include at least one reference to an option you can set; however, manuals and firmware setup tools often don't make a big deal of this feature, particularly on boards with relatively primitive EFI support. For instance, the manual for a Gigabyte GA-78LMT-S2P motherboard includes the following paragraph, on p. 28:

  • EFI CD/DVD Boot Option
    Set this item to EFI if you want to install the operating system to a hard drive larger than 2.2 TB. Make sure the operating system to be installed supports booting from a GPT partition, such as Windows 7 64-bit and Windows Server 2003 64-bit. Auto lets the BIOS automatically configure this setting depending on the hard drive you install. (Default: Auto)

A casual reader might easily overlook this option, or misinterpret it to mean that the feature is much less important than it is. In fact, this particular motherboard offers very poor control over its EFI vs. BIOS booting features. (See my Web page on this EFI implementation for details.)

Some manuals omit even mention of EFI, and instead refer to "legacy boot" or some similar term, referring to BIOS-style booting. The firmware for my ASUS P8H77-I motherboard uses the technical term CSM, which of course will be baffling to the uninitiated. (I referred to it earlier. It's the Compatibility Support Module—in other words, the BIOS support code.) Such references may imply that the firmware supports EFI booting if the "legacy boot" mode is disabled or restricted in some way.

Understated EFI features often indicate a slapdash approach to EFI. Such systems sometimes implement EFI as a layer atop a conventional BIOS. More modern EFIs, though, completely replace the BIOS. Some manufacturers, such as ASUS and its sibling ASRock, are now actively promoting their more advanced EFI implementations. Such products often come with flashy new GUIs in their firmware.

Positive identification of EFI support in your firmware does not guarantee that your current OSes are booting in EFI mode. (Mac OS X booting on a Mac is an exception to this rule, though.) For that, you'll need to run some tests in your running OSes.

Identifying Your Linux Boot Mode

Identifying your boot mode in Linux is relatively straightforward. The simplest way is to check for the presence of a /sys/firmware/efi directory. The mere existence of this directory indicates that the computer has booted in EFI mode. Its absence suggests a BIOS-mode boot—but see below for an important caveat.

Another test, which produces more detailed information about the EFI implementation, is to check the kernel ring buffer for references to EFI. You can do this as follows:

  1. Launch a terminal program in GUI mode, or log in using text mode.
  2. Type dmesg | grep -i EFI.

The result on a BIOS-based computer should be few or no lines of output. On an EFI-based computer, though, the output will be extensive:

[    0.000000] efi: EFI v2.31 by INSYDE Corp.
[    0.000000] efi:  ACPI=0x9cffe000  ACPI 2.0=0x9cffe014  SMBIOS=0x9cebef98 
[    0.000000] efi: mem00: type=3, attr=0xf, range=[0x0000000000000000-0x0000000000001000) (0MB)
[    0.000000] efi: mem01: type=2, attr=0xf, range=[0x0000000000001000-0x0000000000008000) (0MB)
...
[    0.000000] efi: mem62: type=11, attr=0x8000000000000001, range=[0x00000000ff980000-0x0000000100000000) (6MB)
[    0.000000] ACPI: UEFI 000000009cffc000 00236 (v01 LENOVO CB-01    00000001 ACPI 00040000)
[    0.632723] efifb: probing for efifb
[    0.634127] efifb: framebuffer at 0xa0000000, mapped to 0xffffc90021780000, using 8100k, total 8100k
[    0.634129] efifb: mode is 1920x1080x32, linelength=7680, pages=1
[    0.634130] efifb: scrolling: redraw
[    0.634132] efifb: Truecolor: size=8:8:8:8, shift=24:16:8:0
[    0.644648] fb0: EFI VGA frame buffer device
[    0.754748] EFI Variables Facility v0.08 2004-May-17
[    1.305636] fb: conflicting fb hw usage inteldrmfb vs EFI VGA - removing generic driver

I've actually cut quite a few lines from this output; there are a total of 62 EFI: mem## lines on this computer. (Another of my computers has 148 such lines!) A BIOS-based computer will lack most or all of these lines, and certainly the EFI: mem## lines. I've heard of some BIOS-based computers that produce the EFI Variables Facility line, though.

One caveat exists to these tests: It's possible to boot Linux in EFI mode but disable the EFI features that create the /sys/firmware/efi directory and the copious EFI output in dmesg. This can happen because your kernel was compiled without EFI support or because you've added the noefi line to your existing BIOS boot loader configuration. Some of these features will also be absent if the efivars driver is not built into the kernel and is not loaded as a module. Typing modprobe efivars should load this module, so you might try that before concluding you've booted in BIOS mode. To the best of my knowledge, no major Linux distribution ships with EFI support disabled in any of these ways, so chances are your tests won't mislead you to thinking you're using BIOS mode unless you've recompiled your kernel or deliberately added a noefi parameter to your boot loader configuration.

Identifying Your Windows Boot Mode

Depending on your Windows version, at least two ways of identifying your boot mode exist. The first method, using the Windows msinfo32 tool, works in Windows 8 and later, and is likely to be more reliable. The second method, checking your partition table, works in any version of Windows but can be tricky or misleading, particularly if your computer has multiple hard disks.

Using System Information

To use System Information to identify your boot mode, follow these steps:

  1. Press Win+R to open the Run dialog box.
  2. Type msinfo32 into the Open field in this box and click OK. The System Information dialog box appears, as shown here:

  3. The msinfo32 program provides information about your computer,
    including its boot mode.
  4. Locate the BIOS Mode line in the list of information. (This line is highlighted in the above figure.)
  5. If the BIOS Mode is identified as UEFI, you've booted in EFI mode; if it reads Legacy, you've booted in BIOS/CSM/legacy mode.
  6. Close the System Information dialog box.

Note that there are other ways to launch the System Information tool, so feel free to use one of them if you prefer it. Unfortunately, although Windows 7 provides the System Information utility, that version of the tool does not provide the boot mode information, so if you're using Windows 7, you must use another method to determine your boot mode.

Using Your Partition Table Type

If you can't use System Information to determine your boot mode, you can examine your partitions to identify your boot mode. Microsoft has tied use of the GUID Partition Table (GPT) to EFI booting. If you've booted from a GPT disk, then you must be using EFI, and if you've booted from a Master Boot Record (MBR) disk, you have almost certainly booted in BIOS mode. (I've heard of some exceptions to this rule, but they're exceedingly rare.) Therefore, you can check your partition table type as a proxy for your boot mode. To do this in Windows 7, follow these steps:

  1. Open the Control Panel.
  2. Click System and Security.
  3. Click Create and Format Hard Disk Partitions under Administrative Tools. The Disk Management window should open.
  4. Right-click on Disk 0 on the left side of the bottom pane of the window. A context menu should appear.
  5. Click Properties in the context menu. A Properties dialog box should open.
  6. Select the Volumes tab. The result should resemble the below figure. The Partition Style item identifies the partition table type—GPT in this example.

Under Windows, you can use the disk's partition table
    type to determine your boot mode.

An important caveat with this method is that you must examine your boot disk. It's possible to use GPT on a data disk even on a BIOS-based computer, or to use an MBR data disk even on an EFI-based computer. Thus, if you examine the wrong disk, you can be led to an incorrect conclusion about your computer's boot mode.

Another caveat relates to the use of a hybrid MBR, which is a variant on a GPT disk that's most often used on Macs to permit booting Windows in BIOS mode and OS X in EFI mode. Most Windows tools will identify a hybrid MBR disk as an MBR disk, but most non-Windows tools will identify it as a GPT disk. Of course, as hybrid MBRs are generally used to enable dual-booting Windows and OS X, and as OS X boots in EFI mode, you should be able to install rEFInd from OS X to help manage such a dual-boot configuration.


copyright © 2012–2018 by Roderick W. Smith

This document is licensed under the terms of the GNU Free Documentation License (FDL), version 1.3.

If you have problems with or comments about this Web page, please e-mail me at rodsmith@rodsbooks.com. Thanks.

Go to the main rEFInd page

Learn how to use rEFInd

Return to my main Web page.

refind-0.11.4/docs/refind/HashTool2.png0000664000175000017500000000510512626644767020047 0ustar rodsmithrodsmithPNG  IHDR~\gAMA a PLTEOҧ2tEXtSoftwareXV version 3.10a-jumboFix+Enh of 200705202 IDATxAr8E=+EU2MdQe 0}ϽI' ŵ?_> " * д"g/ kѹA_:ɻz؍>җ}u5рA{aYC>6wgm3t6NS)~DXC\w|)Mߝg[']2g*RFh'\~]>?[4g.1 `5J@98]S>{C 䎬``qTy.s6:β]ڊΑ(\!`M.8q;N}P IS|'?+-nksW.g/F?`sU?V*c~E@Tkk]sڏy(/% ~)2C{ZZ>Ào?hy?3M)~4|^~.b7l.f-urx9i\.UAv7hVN9]죵%K\m4Y]3czet׀Yk@}*b0첊 pNa4SA!![@'v~?tRC}t#W_\ O"5F.'@1bxb3$;y=$HhӮGhÆ׽V5 _} vOsY_n`" p/|1vYw&ewֳYy~=#=ˤi \g6ZWYW_ `u],[@fnVk+ |EĉـC@Yҍ,!m<4WV+_/S`Lr2gņOj'x'?b|} ғ..?p8Eͽ4\9 hXpw6YGƂ)-#ثKKGvv[cmx#'Nb>8̀s?>m$3u>eWـ#@ W+.\N8Ls_sl@ȭ\lg0bs6x " g{ZwL{ @lS%xӴ/`" *" *" *" *" *" *" *" *" *" *" *" q?,/& !Bk,/r_~#/1! C -~?n2w D@>cvn ^ByiEt]ۀy^ pq~;حNn{f-C;U@1EGi:1WmxNc48:?{^u4j`wdĩk6Bk,/&`tΧ1l$yv h7xWy$̖7&^ 0̣H뤏Jۣo Q<XLYU}Qm-o?`(Z~mwy0WS[$`9X^hM@C$`9X^h]A:+" *" *" *" *" *" *" *" *" *" *" *" *" *" *" *" *" *" *" *" *" *" *" *" *" *" *" *" *" *" *" *" *" *" *" *" *" *Ҹ?_>{D@TDE@T(stIMEVIENDB`refind-0.11.4/docs/refind/func_csr_rotate.png0000664000175000017500000000330212626644767021421 0ustar rodsmithrodsmithPNG  IHDR00`nbKGD{# pHYs B(xtIME $5hX[OIDATX͙OSY߻?}?ZBX?"#!Q 16L wY%э+c&qL&N H)};>JXx)|9idg&_!Իz!ൺV O#:1 gŠ!u)eLd4RJ!ķ>lRJcQ!r??}΄ᜯv^nyYһw(͞ !ITTB!Vfg--f|8Z{RSX\ɝ˒,px]]I]|4HD ?D55ŋ˗-1M1F)%BbCl"ŋW2 ?%Q<8~vp0Դ PT+48RJ9w]u>69qmvꌙ]]N{{СN(ԃ/xPG*$P21RHB`0Jl6.JbXV&rz/J{mC׃/vkL$(ﺁdYlhRl(F$}x!1AWOeiFRSH8@N!S r(!!'wfq8!EH7wh hc75(D]a\b %ZZ czSJ=='n Sꗇ1e@\[:pPB,_@$KR']T^Bg'8,˲, RV:aô*:|86V!X' ðf&-9hl۶,  DFG[/0LӴ}hF_$XsVi;`[alvڐ/BfbOw#fc4 O$BW-0ٶ~옆#4ݝ:p8NG4y0?7o⎎溺R--Ji mxP*ݖe%Z16k @   Ѐ{L@ áDcVaqz{siZEYyDl5fK)))vL!;6oԛ> ZAFSGd0m靝kw>0!_[[(mQgVX_cJdn}VLLD"_W_ࡐE)cQ^Vy+B!B;'63FǎeaC0ƪd@Q!J~,x  eΟs9uM!4MuPB@QOSDҪB_ąiœ@oPsSbl6 |: hgRVmR. .z)n5 IENDB`refind-0.11.4/docs/refind/startup-disk.png0000644000175000017500000015062112662431222020654 0ustar rodsmithrodsmithPNG  IHDRkzv9iCCPICC ProfilexڭyWTmuu!眓 sQrr`B *" bF1  TT@s~7g\tڽjWUcQvd8inaZhR#@(c8I+% pDF2Ғ 2wĊ- !+p3<-L@uЈdj"3>,*;hI 5qq a3 q"+fߘ4Z_{`JJeMC( [w@$8qvNnT"2k?d(,@M2[5h >lj0W㣩Ύq#v$+?(k;`@/dFzD;S &x8gFZ80Rܽ@ gXp0?ua*4+L#=mW|1_z atK X=kUlꛗcmWIJ8sl,fﺢOLv\ц`   Q=m zh*hxdG:$30+Ge0 1 Ƹ!㦸1d%Z-Dk_ ` tH!O ##s7?m)'ծ!a5pm7q}yqAPƵp= 7 qm\O/U*NUj;GA8c.v@c?7܁vBmRmN[U:$$ӓ,3QftqP5j:~+o>,z/@m0uk>Ma`8  ` V`. ~ q4ِEa8A܀;z^)yXD"\" J#V#!H )E uH#r@!}sdD"?Q ܨ*zzt梻h=zmEo~tB0X0^LS0 1+*zuaOl[8.+ㆸ-N~o;'(>& JAH#* mB?-aH$刺D[1EI!&^'ljs$ID2"hdRtt􃉅IIɚɟ)iSSULٙe ]Ø30_b~yA#=l~r36yEEō%e+~3,wYFY(E%BM9FNyN*jϚ̺0*UjG nVQ[ؘd2*γ=bfgfe`ofb>>šDZ'Sӊ330-q.K˂++mDn9n;h"S=3<A\~A9φʆ1MkY;n$iD33176>d'~@IRN{[ f˃UhU#K7q{tʥ̫NW WT y|`sHmQCQԵW&N=zG~?6rxgnccpS Dʉɓ'{OYjoVn;{ I9lفsn;|ABu WKa+Қ:6wKZ.\>!QuJUܫ2]O>}#͠/ozs;wnuu]kt=yڭPaKNO#G]}l'w=}75l0`pYسϿH}raa O\{9:>&w*ދoИ蘴۩ĩ鼏?s//_w~vlVk|?/-t~1m¯K~--/'4 z L]Z]7baz8?Ld"11琯Q4j;#>6O53/"K(+(~QR9FHUin.joq}׬n`fH6|(xW6ӍfW-jKl6L8t;6;8׹t<<ؽ1%E?g^G `]  N;ZVH4ҊVcg{7\fIڝ%%/%Ϡg^d7lۺ.;eܬZwBcnb=>%{}˼=+9w9`^e\_yPVZC}ᑣv 'M5r4ɜP?ixʲϙϧ]ܲu{[~{K嗫;\z7O {NZW|=pyhhCOX[ Z={.bгW7swz{ ZFOg~_ҿ~suc϶_˫Wpl!g0fr$K5eȖ~S+)6WBy½b%CRs2dg(+2)>U][n5u1͚ZFڈmB]=.Ju"CkM35[48kӊnֆm]}1)9%5CSȋz߼*p}f`To%M5? O ohʍN5gMM0$Rz#YxtFM巈o%n}ݲ8+wGT~NAMᩢ.>[|jOcC{ˋ+ m۟Qp *zk͵ZCyrt`T -O;;{. W[Z&ڿ].u(]1jzM ͮ[-nWӵn==6z,g=}9q8ˣdžL#ןȞVI33 ~lܖyrt,d4\,Y\ 2`DB$}`cBȰQٲOrq.sXFm x[ˢub?%H:HNIKIߔ Y-S/@R8h^)oʡ*RVZ:i G -Qvmwibmzz[ x N>^Q1ɸDd4LԬEŲe5-Z˝<ٜκvxY[O_:u*;, l",2,niEŚı MKN\pQ̓265,M6] ,'/os˭U&l_gC1пHhqȮ/ڳd]^ e*۵;j>\.,/ 2(#x*(ѿ0  p?X C8$A6AhFa!!ˆ:b!iH rC<&5tRoߋ4 Db%qD#ge:,\Bf!YP)XX;FKlzlm_r$ssqy߈X`%@afTQ-obK]Rґ2ke#rB͔dP,*Ryگ֢1Y]T7C/L@͐o-HŸTl=VL<6vZΎ;w|urXu Y&H!̅ `t*~6,S$JiY 7Wm.!fo?UX3nwK ^V쪵94W_|h~Ư':q˹w&Z_rŭ]L>Tx y5շԉSfO^3k=Oo/]wȲI@N PM0[`,(Jh^ B@5 B22 ҃|DPMAϡo11,;M:x.OP d*"ILVL̪MdI-kW8k:Z&v݂%G'/g7GM͐({m_䶨1!q ^%'7%?ȔJػY{ˑlmeYy]jWgR+}<[Rcp硆z5G7<~D)g*i._r+Yr}Ç)OǾ<ؘwW'|yl~ݢ_o~Y? J ܅aE(,bG* 22( -G{1]!тxdD9F>M(ml+9R8yxt2EBD=Ŝŝ$$edv7)U\êz@m@CP3LC~=K9 Vm6Wm{[U\NzZx Oxr0,zx:DrVhpƝjxm.;OlL‹mJJ˩8P_S6>wXJPݓ[mΨ_ߕkU7n:|`wzj/7do܋_Y ~065~;1&~0M(Iװoss盾?}ϏBOӟ?-R=-.1-./]%W~V{//ӗ/w//$kjB1 // *Y^^_^u@dxsX< ? pHYs  tIME8! IDATxy|TYf$!+@ \p U%X mUmUl.kKVo[@kmA{m TT } d̜Ǚ [$y>jCf&|=|! bŊ_}ɧ!B!1-suu[G^2$ , ۲q]WK!B(h7nxNvFZB!'?`WiujB!'u|9.B!:*ۖ- !Ba[rB!0)Nav^`ws:sGW!d$7NqN@4EuN8-}Q mw^8pt},B~I3c߬Cvl۱VGmo@T?G7nFӴS6ھsGW!d$ęoVSS"K.txئivt~(B~I3gD2-ס+?im98e9B/ q웽^zCS:֖SQY^!gξY3^Ww·5|o/C[ yŘֽ]sc-F6ԯ^)V(M0 ihh   33ԍ 4 osWo۶X,9眃q!iIp$}*@%ި˖]#4=v-'y _K{ s[TXUoYm^cc#:_$!OZZZK{7 ر#Go3tKeeeKcS3f#'B|ިIehaPVV|8 4vL!Qu҂3u]Cv.4Yo[7z";omn"gpiY :gϟbwv voC`7{/ |Э5vmq1 n1G  X  BDQU{>jO5v|ׯ7ofƍ 0-Ϥ'>vmK.gkA8܄]k>*'@8^!o>WoɿUǜ^Ͳ̷厱y`3r}O>IAAwy'p0Xb[ju:7|y%5ɗE7;ÿCa7o.~ddt['ө/~ 8 .%w6,~oz^!i8CCI{^gヒzrס( p#JiZmoo tJ}L4mςO<2vnl'^V@& ٵ]֯ySfpywZ\zzN4͢uެ?b\vt.~ [ofw\m'0ME.QPPĉSGQQ` o}Ɲ,Y^޽/bT -]A/!tpÇJGH[/;8[l ]o ]2KЩUKo8B {m-tF"i/x%(D"65k6qmO!4b7_mWGby2."h-ơS.V}Ǎ &$] %O.?>M~@?=ϥ| >஻:{#Fsm4PB=sX6Q˨˩:4z PS.]E]G3z`7ƝY>l?{c\l:_p\ )Ԁ]Wӝ 1B ^x- |XJ^U +֏@~zxMXB5N/sMn~<#}ٶm&Mb'ttsrrP*6oL?|Seo5k7OwyEv?Ѫ𫿇dtp7G3麫鏷_=[>;e|{Ed,4gk'hh w;Vsrr! #y5 ϡWws38aU٫TubQPU FI㣷WQWzJ֮ZF_3q#F珺]2l!Uui -􆭼#\6*K.%k mO`H,'+tHAHs]n( FDo)ٖc;r66loYγeQ8<7h.5:ө Fv6ya]qޛWVO^Z˫^WhhJx lu]47+Xy 1\':?O.>⽍7FNZN(_8Tz*>Y>]' \]_W7 ņoAfS r\(Dv.(3`4|dgxYUT8[ϭwXOgb0E<<%ɟ{IL`\YS/o\zЩ>ia8PuM3N P=Bqq1/ywsDÇӛ6moW]uUߧq&>gC( Y] xTXRE}^p;L*>bYSu#2_,zCLQJuu0{ FϰwdXdϚظ(|Ԇ\ůO{+~zzQ"~VYȽ}5ѣCW7ωP Dv!H4=IF8:h}>^{-/"*0|>gFF{FӴ6ϧy,<> ~2+j+Jy #\@ޣ敕k췾D..q@յmL>/jOS-ZN> + OۺNjGǥxu8\q-q;EI"?_>},Bu"0|p=,|N,,g{m333yy뭷ɡP(UW]?Oٳ1a[vmH j79tLT}^9#I䝷?@war,&8Z>Y5lyj*f"=7Y`_"OjϾYOvv#r?6JdsmS}~/"~kǙ}+;A=ox7o;z8q޷BtԤN7I$q!;;;mMzy饗xu=9p  M2vh=<',\rqy5n]:_I75wbv]o$sݴWAnȋzS-&]NwvŸW-op@?q9q*6cRy5 p!h>ۅ=gP<)\H\rM`{c}߹(ǐ2;1)D"HOOOR믧gόsAa+uW6vZ_*"ϥS/twǯ:vOgKBYy Kyt0fXOQ,S1++Nt_+#P`; _9.N9b\p7=4FD~?0pUSSùCmXŋIKKcmm|v܉m ZOvvI-_!k'Uy$]w f{/%!x v;,Lv cl |-_?md6iw\LvG{֓Mkົof`bK o\X2":-ß'O}-). 53T[ ;.Sl/y,7\ǰl.-luwL/ΤmɲsNynw?cXGIK 1Ҳ,@E#rqGhӾY.\+C:|>>^wӖy*r+xF▉ =F_s-w[+Mõo>ßE6<i dW|hii&$Y.v]-ZRq!a( 2aGN[~s=і}(?&RmD"mÉjll^T݉F֐'N^UU dgeO|Nw !엄8f9!n.j>;wDyBKB}N!BTIB!IOB!8%S)B!:^B!NO?TjB!BtlK&B!DB!┄N!B!:SºZTWL Fe$B!ĉMRL/€a#1bh){Y>{3Fg.UE^EJYWoV;q4J?9c-MZ,+-t翞;G+WB/B/F-~1ZU l?o--*3; 9)Ls[P2dܖlw)S2e&;e=ںa.d"y\z%«᥍L3fv'{5/+IE7YFTQq!O}6o Sa]?bZ3A-R~2P=0 >M4G7'+x忦sR"ʱc _G^^fa-oqc&MG-dʖo$>eb8S\|?ʞiUžrvU( 1⩳(-{dg<-bj)3eaOu]k93_lR3 SaCMdCȆ&?N#{%7ߩ4}"Z|h3-[JgQ\<'7f EEjok fv斵9n=,azybQ{,Eqq1lH=1iBAQcs{cgJwѤۙ[˪ba-?[GIu]* V:yhZ|Sd"iY- %EL-.fڬR͖L/*64Y9nul4[uL{ExӘܑ3s3~JgŞ\:`”PeU׾zK\+J6 M'oQQ|q .i1cK(x 5+jn;B,~l'R^w7B-1W ʙo(]{a+9_nN2[\c&5 (ٳ/̙̣/U_9w]sPJR*Ø1ausKP:.8g8o>;nY{>}vbd&gP.X kJCIEPޒr`=6r02wKCE$K`}75›oҭ N37~JguM4R**CX ++[_asIEj ~^@X<f}ݩP2yV0ol}RQQAԁ *Ƞt1N1#xj/O!ߘR dUX#̾3o% 5dm]Q̟4{*a7J~9w9jz~zxga5|ܿVQ^k>c}?CTQX_>>~9_g/][>#ipYp)O Ypa.0_u㖵񽿧iK3+OzJok1-_CQҏ eQuujn F}k?W͜#zbxۃ!#&r}1JId5KyỹϫVoajݧ IDATg3*zoW6FWm.Ϟ5{mP'VUoQ9v+0paQټZ+{ճ'n!Rߒ5/óYL:zwai8@YZNYY9 >tsUx#{qZ$h卦=K$ uxyZ2f]^.W+Vbi9/?@)m @3x `MP \<>},PcM0^Q.kS;sElq>#'yrE-sN.,oapuי0~,ŝU@}\G_1c^owa}Ga3QFBh^Jdml4GVY8b$k7RǞE8N;׵cY;ZY}=T7GLUqā%z \FY|<}]ٽd.0WWw2oC{g17{ڵ~.Q-QnG6>Gÿ Ø;yϥd[udnb% P-5^^V¬Yxn?FQQMd40ݾܒ@q z:+)ao'>78nor `s~qw;GlVNλ<3hǏcC,7ޖwg<<8?5 Gk&qޕݴaX~1z4O.ٕIlo8t .Bs]0e?j:v)Q[պUּsi=\} vߝkCI=4ys&C'δ̨8rkD24jtm6/{ܝޙ6Ib)kdgLΘARѬxgmvԲ2>{< ;E:ci,~FbɜR'ϗ-.W?w0r꽩/q70}.2\lLxm}\/tdy+SQ o [[XLL㚯L'b5Ә9s&|?c7Vp1L>aɱcI6c"پkkJNѕz'N?@~eѬۀ fy'?oC;xQ4psp"qy_7^7AUةlΝonU,U]B f s*auT،{x/%/$'2/q1[p8жnܦm)+HD,jk8w@q,tAԮMVhV&%bG_m]֎WG ۆ`:a=)u-'};PӀ7{=ʳSpbx|7#10ys SLguO^utmqןȴ)8;݈P|Gn Nt}]W#+/I yzpػQ}Z'h[ӳ~Iӌ`t'u@}@ &8v;ev҃AӲ6 qVv쭴Y[=iuwDw]ٜ\.n; PTT$%B9tғ>M9.B!:N!B!S!BHB!BBB!)B!$t !B!S!BHB!BBB!8tcs]'(-gF{۶d(h躎ʱB Y1M=X 4ECR4*']E2->,TUy+4Ui^UPT{k]QfA;r4M*]!Nᅐak>lҔ&CIEzL$ܸ m[z;mȎZ^5W~ܮpCU IUmjqT) $z o:=uWOLӔ !:8q~}1#a|i( q4M{֢:M(WP@B!SߧjSBvv6驠iYUc׮]1Mz233 4D"驊 ,`9n=qz90^{ K.] |(a񙊢`6UUUYna***:WutE, $M\!N:7y̌t.jL 7PSU .p&1-.A]?:9.j( ) e.RB!$tJ.,qLץ0l'/.r]\d,223Q/((mYq\%fDZmM}ٸaia'/6W>)jr wݱ-tB} B88h$i8TB "z(*^ϧjePT%u\! Sɔ(`)m;umXa8BV^Y^T]Q]TLQE騚mY8Q0,B!S$yб^OvGTtEKuq\k:yYSur$t mm6qLu4]tU!u槩mv!kgv]\J޹Aq5A? Tn !yul UPUK°0\; M2€Cum-ア5 6,EEKhbVSl<B! Ml0(@Za[4HDžCQp"Ӥ.J4۶ %Hma Q[_O0TO#{ 6{:zղLX4Oq]GN !)bD ~"QRckT44ջX,I"HGg: du) KTm4 eZLn:ɕkt`0ݻ3ab.:d'$ +Wr𡩇!:86Yy(K]]ֽ.eC NpD?B!ߟZ3$fmc[]{Sf&`6ik F,F0'joMS14bBa>EqˋwN٥TK4Ŷmt!:ɆnoV竻 LӻH(yB]54á1HHURYUӱMS*4s0 Tl&a=EJQQFq&ݺcaz7^UUH}=P]T40B!$t pَ aĽus deem5EVH91d#E?XMӲByQHc<Ģ $%u\QvE^n.u^l˦Sv6۶n%+;Pz[UP\{>▅e{:)BH< 8㺘r.GGml$RWedvꄮ{<~MHXs{iZ ׻c^mۦ#U4"k@Np`^lJ^|2;ehFc#a k$g)eXiYD1-B!8qrl⅕?@]] D۴}>|*A %3wjs O`&aʩDB\!N !.FH\S'}t"m$n$ppQ5?)SNjJ$LcֶۘmF1 էaZ1h`+h(>E큃b@ I*yyyC!Ĉh(|~j %aģXu!:%80]EUGQ+§h餑< =[EAi6.M>AAmPiFjԳmƆF̄~oe$/rFv^Y(hiluŲ-GR\ Fqlb(a)BH4M#*n'mDQ `p5 U ~~ab6 (*c-'zTBاSkFp5yEuH !yvF>ڮ R"n i:cZ{|ޥ( ^@501U0{67N:-"^Pp46pA Q8 $]AEWbXAMC״#U\I]`&.BBY.H) :eQSsP0 PDgfj}>|>Ӵ0, 3aFbtAGEq]3UE!=3XLnxci;ރ556ljFNu> vBZ(H(F8cDc4F9=w!S .У[7,K*]!γ*fgkߏm5ݣE񞯎K8=OP**nCxM@ HNjr̦wjr_[Cvv69T8lf99p۶biX\b7ؾ WSx=۪mit߇؎*lREuu'tAÕ !)|`HPL=ܝduSQ1juݠ*~]'##thq~Zuuv:*hZ[U !Ԧ)4ad"B!$t\ץ>J9::ۂR{y2iTnawl ;wIJt]V?!:jhFFٹs{=G0"}:㲥j+]tf-ÖW[߯-U[9r$b[6 Ny([!;XC45MVz~:uSV' (XJYCĺ0lع|: ;5kr饗ңgOe玝~t1c%օBH<멪B8!|>P( ]!H`&~pF8 ɟ5]l:m2do>mqiFvF1BG~~>@צm0L8'?/ϻRWee.Dxc\XUusׅBH<؈ؤ M\0L={Ĵ,z8vу5^Yӽ@ #A)&N-EQua=4F Ӳ4CTi4 {. aüC^o5i˖ml!saddfHB!lٳ'X!STM|5qzBg0䢋.z<ɏTGFFtYt !y0:mwUMRUUzNc{~rrrb%Ot@*@p8L8Fuis!:]GӴMiu9~\4yԾB!S0x6 wB!' B!N!B! iOGlu\lCD~Bq\XQWn*rnz9 V0r;ΩX۬ q.ډ>ƻ ^87839\oS:o)˿XS:xO:a=$ xZdZkiw*`ϲ-՛)Wt7RB'B gR7f8.M%2+> nHWR>_ZKu쟤wi!|obMjX c$蟅͒ů:td!o8ЛI7]Fc3c>8a'`Z휏@Z]F!K齝G3`@d +->k,؀ rR|UtQK> _ˈ!Ui0G=/{`7Miux7{\֖-3R5?`pe_A~Þ%n %ֲ>OEь x*H* d8&LA~9b\r3w3r8D wfP6yF6nY7>cF=)=e +g9Q承dC~ظ7aFTړ~\\D"ÞԾ\gkԳG~fs(fYC"yv(HB!I-6XPǜi6|IÀ.wS9Ry4#"Og4.t7ѣӴ\@_𽸫쩞;*T7RIz/5hx8g &[T>SӓwJfs&&s&,w:닟)תvfJ8M?n⧟~bcvJkУצ~u'GrV?FK`hZ-B!얟lq[X/6!Ȼl9ntmâ 9FS *#n(HܔKUtQAY*]z2dhv`v>^OPH;7USt­:epwp\m 0Q+Cv2PXXFXZ-c^^XP5^78 *jĥV62!S&Yд5=· cnG.19R4h6n; @U̟5V)3TWա)'~ʡhj,&{Vxlzzlt5F*kJTQNel\73!p u4mn>]'FIB>w|5X|;1>Z׺ gU?ez. `ʔIRj:_qzz81]Jj20)+T:]-ׅBQ𒒒Yh~~>7UEJݙTh\ȓjjWW:ۯĥƽNcҊ i&jw̭e. ~ѻહz M <\꜌!w y B!S!BHyVb01jp@C,g b_YKgB!붺dL 2,vΣ۾_&/}:lOkOnf7b ='5>x40mM*Y+pxǺQSCkA}qYJ=Z7n%l*קG$CuxBqӹmF:7} FO[ǧnOmgm^ 'L`qt|w͎/ pshz߀ $VvϚc>!dTxƏ|ez?[w0ɗCe 5?!}z-k1<ʸ={ɗB!Z$?CG ~ yٟ-l fT4_"ſy_g A#|C>{6*\hu#eHq??]c%l;wH8.4 AݽFiGF0*+T82A2n̟hZS\+րJQ!7r#tj;U vg?ON=@tהaaʷ##^p<0`$\_&#Z7sݾHgZEՒKE wƯ]t GЙِ9O!l#7ǃfxy\]qU6_vNStVF:B!I5*=4pɚ/W jƳf„ry');У >Ovُ,TeUf\3i׏dž9MSḭG:q$5GYK MVHPu'`2+@ހ;ߗ^~EUMb/{ydBwd7I:BqQKJJRfޘY+1M m}Ia&3Mh/9؆,\AGp%h0`ť}"Κ@Fq-B+i&j.J.h$_^~g'; 7mlL\Zh0HB!t<=جI?吞,> V5H3wMpU.?KM4 J)^!wP҉ҏ$΢Z 1 % t:t::]EṂI-s`b(S)XGq31 E9qruϠ\`blwnr2֟U|:QR)שQN6̤I5I+!OKQ@_8*B!Ny1|ƃ5!@DY|Z E8[iO,VdQFDN2,=99c_0 d)d&Ѥ.C}Ob8iziЉUO~\8.5r ԩ]De!^ K>W'S^#imxCW9s3`c@`9OXSGvu0AvEn=0e.%B!ĝtAVOO lKC{ÞgirxѥZ ~< ~}EL?SIM˰-xvDr !:o<%j}?} áI|=e:(O%\ۜgIfB!An]~f$7pGP͆BBk:!m6\siiv'`*(LːL7aXb~璈xo -W xEv1uxMZc֩L̍Nȇ(ľn_@WDzciecݞ@k"(XYN@B*0ȷ^hV^/#Labp<4cL$Y0lMm!Vާu`Tg?2~ͪW[I)mO+ޥ 'Ok@7"y2Fr_SHcJ!nf'OP(K"Hii)h4ҲeK\]]oSg ݌ a=c^]l`4{`(Chzq_v>.^Xތ,ee 191 T;u3M%sP(݌y G=KqvֵuG`{{ccU}_tO`͸hoiȞcY J5pO=1/F. !m`0ФIw.W^^^ڵ U-_ /))I*PX1(4\j]*8W^㲧VLF9PR&V[bXjuFsׅB:-Z`ԩSu5ݔ37l.(.POqew'*zml}ec[bXRE! FI85ѢE z2]Bq Z|'1Ww.ރ*E%IBq ~^R-/x_礿ygVb/?2Ui"B!n H]RPEᇙ=-IBap?g,נf+cك#q~It5&Te|$C^cKu>KL(j-b򒢈Jʽ:`ă(1|~i:iE%tL"Si@Nv+._?Ws۰H2ՌaL>K|N^1_D@Kdڒ ^Tg%J#=`RSoܲto ih63faQ)A<ϣll0 = ߾ο5% gŌ ;a _TTA.OKB_[,qlk[i0l!B!}gZzx`O; <٫~H6P?Oo~odwJ&  &cAtԉyL[?=`Scbϋzvs@o| Ayˠ:e+sF:2s~.n>E&kbHQe )95.+嬌`vx>f:Gg9Ls>3-Kʆ=u?LLO_^?ǼP(ccuS˼48de20z{ù0W{g}'͜fLʵOx؎Z֧->>>ifO+;ѢE|||i3羕 $ä>&Pl׷@Cbr&ttܼ=ױ 1?Bq=9'MN+Ywe>AP}Pb‹?{G3 7]! ;W,8'-ar?s( z>=4_l|Bq|.^cHB'rִ1](h?cS`^APϞ6Y< `1srY6M+.Divϧldp0M 79{5Qwo!K+[iF(4O2W:¶w-Z*C?]i-䙛Qa6jz7mklh8>sww gِǙ:И,o#! sϹh"}TSKs9>B\s Ň?fү{f6b(l&eT=;8]SF 3:r2V&ij%x*?̍n7}7oJJOΗ! ܛ&34-nnm!}G*mpjtr_7*4xB3]KJ{w< /=8:~ΚLz +X.t(T2byih/kx")]Ð69S)tD?!4<\7]shltPD01j<7@Y/zBڊ[ŋ`Mn+O_sԺ`FƇՌy/8*1W)նGZ9:B\f&Z? = /ΧhƻsSwC|GLP{ks#rU7dճ%hvSvNA%qsBy]]Ym63:3`UwѮ]kfxz:iӡfT5:ͦu#=rZec`FzF v>gB*G^%FҸgk]:/rZA `jjkj98@/B@U߿ ! syx$eqYȸS>c4*^#'$lL:E+Q/EǤi-`ܹ|7(,><-ǫvë.c8(s[J^X8q`'lTc0GIg.!0j>@_>1t񄟪-d=l63o%FUs=7{EPU#%a6ڑo\=>ADgy/);8@Βg&HoOfp4_sa_ o.]Or̈ńPi<:sf\Ɠv v~,|/h9qy$/ N hy l)|w((XVEƳJl7eFPT[*i)|Zɾ|QFZ4*3f8pK[F 1ο:BFJ6\^F C:Ӣu{|֍wPڋ9}ent N8b. ҽu Zο{лg;wsByFJlXgheOq}tt;sTs9'"H|H˖-quuu!d0hҤ s${I& ^$B!-mJ U׶m[zuut՝?b4iѢ zEZhhuNŹb2&2i$&MK$5#7Xg@(gYt{ŦV-o!/.\t ٽ$zYIH?(P?y˻㲱vy!nA*La]r2+V/9yGYolF~˝w9:eu=,ijvF`Kؓ|2V|le*!D$p[ڮ9e@DXZE8t{9fJMMzq3Jv!/)ѦǦ/\bۅP7feԮlx*=;bSw-?fl.?A_CR:L/jಎt. m13UF>n.ץ>~ϽozԷd͟j/ Pҩ7g#'6|*)>lWa5'g eRYZ̄pN,#7}à-0$tD#SzW__M {~J(U7 ťځ<ד'Ey5J }*Vl..Ty EۅqkoYC#Vky?~UV,dJ/~7g)3lae 刅>צPV*?~ ERygM#t/IYC-q$vƜ0{N&!b9DR]RjGޮ,y'CW6hM-ߠU}jxB?Y1+&]IGC^&!b=w#d51ؿ~o:f*naޏs<~^ۮbb|f ]ўA'ۋ{"wSVOOwV ,C45rNsAotO? ގϪ#IE2F:0k-i3KH~:#y(`;Yl3=Oēf+9b|1yᣮ12OX06-$#sj1.%ddL$OoCBtꩅSL¼X<eRzߜldFl=(b/#fPf0vd+Ⱥl//ٍBap03`L2%tm٩NZ#qWᦥ%x9997L6ZP(Y0"{W>O'iSl/۶h_^@,{FBL(kLY 4=u \64XϦ/cȿ~Pd'.۔>y:wc[~(>[-ѩvSnvkzںy|=͘ l3=2%fhgUfwe7 ,EL'Y }t^䅕v|Usb0`us[x"f-`Sr ɯGT!$!-Ϣ;fAVlTFIDadd0>1okne1tǪPp&7И3c27eYM,}6B4$/M-y|OzƏXH*ٻ Ky^{~R~뼌#ז)l.[3R^wYSh.yux;lw PZPJJl2Rf5cX>㫅hSmynNmOi(FU*Б'#;1kG::j(Pa5q9ƹՏ| V|0u:l/SOU ץ R(ǂw 3F׋׿&9~p~W#VǛ3o0H`3`eRݖoF$СoC#>?· } wWp6:e:kP l[@YK6cxKvS:u1X4i۴c/OEķ ^^˔`7`Lԋp#`jgy1 jUχoi_kzЋ_lpY3i=I#uɯ7ȏl ,>KHG_zF"9Ҿ&ޡ GWNS.We26i@3z2,X}m(A o /ύQ  c[{gH[a Y s3fNB?=yпScb4_OWbzW}uAt$3V<oCLz/ePpFI~|.BI;|gr}@&8 o}:&7}HOkItu =/VrQٙt =^|[] xe z LO !C5{%cn,>h5O:JW '/cDb \5魭?}iR%"`Q5 6gQB5]5T933l*nMvmh9t`#жy$=ߟڠEWu9ѮMڴkGv]Kaĥz/+! sUV;3䃏/hݢZQcÑ;Xby+<ඦoΥVumUWTN3Πs3nFۮN[_XXfU*᭯?_Q۫\T wupqi׎- (6`,T_,R1Yei͂4ՙ?iqr/{F8~Ht6B/_L zУG\c+yVjPcs?!(=t^Mb7?R'iIE h T]:U+&73>F~9CK { _=zsA/ο#6%%89pFjz źy~w/wW="albfr)JJ05,u8wqm %ö); ɭ{ Ո᡼<6_mCa dpڭGoFfH7vh{[8,?Y^%Ň9<-}z9nSP81@,qd,~Zffj:;seyө/fuؽVjōms!na6[+<o>*>FJ% r ._̕Α&耡|Iaa/s*=[9V7BY5:Ah`+Sq5G$ X}/ZHNG[k8ٴ9_ucp5WfRb0mۗF{yglYC(Ni(w1]tcEټP-ikJ޳SbgHI) -s.O$ Seצ7VŶm768<(9#Ⱥ>bZ!8| kߎ`ntOR,NI;V¡<= 训֦ٜ̥29 cF 4>MᎯx}|2^`ƏQ^dƌOfW0n JaCoz>Δ wD f"X{lz޽m۲Ig<tÔ41ߟS>f^6wVYnR--b;n\{;X_ЃY!u|$Pm'n)N܉@lxE\"D5U B_A ~d1lI6W͔bX&?gH2yeTL}s6 tLcOgQyd,: ?m\r9;dv`蔹Lw&lu?ڜ9y&agڿ"_╨(~߅;fTv~?fؑzԡQ)hěcXv^|c4smgIk?(a{ |4 Qoå-ьb=\0>Y斲~Zɑ_f%T9L)0Tܟg `xIIIuعrJˌXPFg& <<jh6RrRpsV\<߱L^& 4K5k+ PX1L 0ƕAuEYZr55B\yyy_fk4zi3U}]$((񠹛KQM B:)e1Pt|}[7:[7nbb*%m`Z'!Ӳe˛h,_6o7Ju_22sŠF[.\/ñ"J=}*>STPO@[!MۏILp[1YPTqӻnt*2IH3[Х'!oKBAIny%m/~&rzrK,,f+cك#Q {$:EmwX,\fa.S4Uo닩/)<xpep` +q1|pI5BqS&'^2`G?0=8MWoۀ_I~#*YXGP<VyXNd2*:ugcm]faQ)/^fq"jw7^JǙxdԥ|!Mt[Ьd?۴ upt䦽Dtq+2tf:ξMIait:rklmbm{I 1KP4^NGؔ$] SQQ5cQCb2EMK}~ iԯ@?>BͣD=fe#$;4~WJk#}QD.Su;ǼP:Qn=Vo3(3ɹﺸ5=qcY,kfc| %'Gٱ.HT&Nbiz?`ߚ&ʹ/T-`baR%Pli;A5@O=:]Ez[a=Śb%%$aE⟖[BQh[}۱#3aDvt}9Tk@kߚbr/QMvrߧDgIL΄~ 9L˽ %)L1,54}SA*1)U4mqKs/o+ygN|hU,10Rr^hߤ~P7_y%8 BqcΒ-LLcCz#f=pﰷ4M9&}NY9~%edPVrP(Y9EO;s05$߹;3h1#qɿf(?=MVzN@V2Ged9OXSGvu0Avۻizš[_V%ۼnY涙Ry-D])4u*)SҼ"jb2#31rDw}?2gsޟ{>( %={MegyD<0;H_smazߦ)MXg%x'>&)LɃl?TT/*b˒0Ō"xfG2sT]FQq>EFQB+NJvgQqzBdX+㘖pߚ|doT; Ͼd/o@ ̎$$f4ZnɇSy|a2sߧ,]AQ[gsYrLqL~& yqh"ƥ&y$8eYVW̶mysd㏄ջqLk#ۖ27qCQ\|}1e $'s:"Ygqc&eiE{ΞNQcVP|Dh=T#;ӁUߺyh=/g]Ҿ]^ɚ]ؖo\ Y =T&1+_2?#X>uTez?6}~v,%ǩT Wu1<RNc˒v$Dpk4Auł %}@=z=Jkm' H>A%r7_ؠ1Lcx/X4֑4Vc`'?_DO qw+ӟ@ o?OeF[ˤt^Jk&;º JEw|Ҏ^a_ <ZwKPskɷGjE \A֎֜a7z̧3Ln龖muku@7BXdEWTyJN:o'*ABT}$l;g9k@ t uկ0- =zbٗ9<;q6<^6>Z FhǺmlVz5H[3 Ivˤ_YM@˨x+fc@`,3(PQYKGo Ssy<JBojDZ?UJc{K`2?ʿ9Z5Z_WJ9Bt>cVn<;mdlذ-/3cծFۏ]< Іu',,~=_!򥛈Q0{4R=?! -BֿC0:0,;nIg[SHͥm9LLh3>]~L{˗m9Fu>| Mǘ'uSpi!)@Lo᝴ugkCA5w&,˜p=)5H fR4bUZ3:PyIe-38"]uuũS^gܡ)k)q*5Iny9fEJvfb<Ͳ-ݰV=jŬ`c q^%Jk[i߾#aajTCi3xw+53uGFݸ?>>>kJlfuց-?N[{y]jt68j8l&z;MSkڳ9zEW(ZqY% P+Xu=;\qiC'k)y㒲vNExު^[(&:qcZƭBG%ՍmfECe8-dm^卑aiedDQg8x$9ә\ =,H k2L8 ag؀g۔[STByܬ429Jyuٿg_q 9Ga)('dz6s$wa-'3qdRҦa_>޹FQq>EFQB+kP;2D<0?_ 8G&pkJlU&kS L֚_8UʆaΞ=ͦGβ |$:cgϒccRd@i(%cš&#ڳEQUáUAFa]'xeo)Nd#p!zm=M&lhtf%L'FÙk\ʾ"< Mtɢ^%Nc,'q/;O$C}ryT M#y5Iޖٜslƾw㸿q+IѼ{8e2219doA72dl6 V>GGdz& 9ێhk vc$Ǝ^HT8FR i;?~?;X=]ˌ1J-~0N'p1 `4VNb`';k0-ĩS(#ޅHE$1vAT9$_Hddbͩ/wiO^-o;i'v9d {@3bwY\W{:qh?}czիE_o5&4>n:)`,1${'3=|6:FM&@<2-=뻓4x&~ }l2a]0:25cN4˵g/Ѡ1pO2 W븒g2W\WhVXu1-A1! )l\/ʀ,vZ Hݤ:6/rp䘟ڱԏ&a2xf@ "[ñcShTN~=g-b/زn|:E5upq?݆&4ey ߎ@^_?嵌?KokVۏTMk&Ƿn@qV!nti6&sҟn=sgbD[toZ?#]%kRbQ?{G%:BHHnĒ|@H/UxZZ K5hw.v&QU ޵QJHHadi]5=Sf[}%f} 8{|o7NP57YȇR¼yel^dFG¯dkCAl|}D4mX/bYBIi-Iҫθۛ50CG,vþ|9:m)8)/4+Tv[D(8l dȑߏ\EU;kZQDlN#+6ԎKc|Mڡ3bY{&%ނ))YԞ:]zzI/Nahn"UC IpUtQFzhTDugZ|TMr}3D O to*6>Eݗn_U|yOi0K&fTP iqMz]û3 XVuL}"0_9^uyG=@j|";."^V!P|}jiÆ=׳fÁmlmXnu-:ٛEkhdV+~yFQ,gE|Gq: >8,f_}<} R+6378jZ͆թ`\U.zԷ*{͵>RJSܯwtniN{^6 dž`04xYaŮ14F#q˳R6Xi,yݡߵjGM6F⦯f 2ol^0yBzB!O"f-LY~  ̎$$f`ai{wdzHz |=BvJ}%ٚڮ.[6&bbΞ=HEkeCe5̌"B)aa$ƎCa['֭ۏPU8 ?,4Vc`@`O/!l,mlov6&J[ ԂE!kvA&̏!BBZQ?pA0cw0Png** -r~4#N{ =F~=;|`%E8Z!O !BtN@цJjYDvHIc#\i;=;w]o߅$pFG2)~+3x[B!5߼tRWak;F࣑^ Bk VVoV]s%B!.B!$B!t !B!IB!S!BH)B!$B!BN!B!$B!t !BI:B!S!BH)B!$B!BN!B!IB!t !BI:B!$B!BH)B!$B!t !B!IB!S!BI:B!$B!BN!B!$B!t !BI:B!S!BH)B!$B!BN!B!IB!t !BI:B!$B!BH)B!~BB/\Ph48(B!$R*;à# .YPVBvmj2B!t^ԹA+Ex >>>D-(@Nx{)J!BH|`tV?2ڱ֋X.Y9c>CqϺWȹ i׶B!$Wv8=cUjGT\ȸܩf_f-A{{}B!t6ҥK8:϶0volݿKhg}AXh'ûsnYZI!'U2D 7wS筘ѿ{E0>|6z*i!!BI:Vrڷ<=tn֥FRr4e8sB!O\^^\*GK6m͉RuJ+ !BĵLb 4:UOӢ( ;CZI!'u^Ңxh>E^^WͪEB!B:TU… ;]H#?o[qTV6^o%(;H*::oB!O1k[jNofҷEDuz=Ur!YAUU 촋[@?B! jҒbNlNF۱+*TU P]U~]EA@Fީ;u'R3*h| B!nH̪6ԜͨM)܁h'hE[m~4)څ懯}A_~+¦m\uG1È/f$XRCJCX,fŔ6m.}d|)vrMo:(28]-TkW!צg:6[9f6ӫ T'**RܗUESxW.eΊkwgE f/a;ONe|dTY]&5U%@Q\3f*8N`oԺsv80$:zxhG!BX->g">\kOʜ8nrF~;UĞ쭔wsq.3{ >6fbNf-q~5yh?_ gc krkexEx~'[@Rz3Ha<;]NJՠxW:cvۖ|7q S8]ToqOoou4ZKb/_1iύ72G1ܻ^)|v58O)fO0WaM)^^-NliqVO<ܻ;@Qh>z{ kQ_]Und^ZM,y7Ovm|Ȥ9)ECs "GYvS &n;<PJڸx#uJfܤh:SsSd_=g&|IRh_ϫ?9kE۽o 2=gLe,\8CioQ+`a,+ׯg#7"%,aѨgXp֜|Bu䦱 /L?ٌψag?;82ߴz~z'Er!&pz_$prצ 5_=OwC$Q*^Ɇ9|W>s]ĥn )#=}ފ #f2h4iYb&g̷mrp;&oe߾@Ew2ki/BΖTihDӡ+ʕ8BS]UrUF(;rЦ!앶ke*/8/5xtCX{k6 u{Y} RNl఻~tC#S+=t^'tq9qppbk:WV 4|%[uSQt8."jݾ٧V;i7@)v|@Q @:ߙ^lꪘX9I)yN׃D01v/Y}ԺK@p;+ʨ.[Mܵշ{X y VL`Z6Ù<~3Lf O}~rB!Ig %U`))}_EE)^ziE%8T\*k\;$պ^m sW|K ˸0x fyߞ$~,LksP5)"uG pwFMH(0ڙH8٩q5ysSQv4WL4 Ǡf3fk+V~ 7q_hf'‰~ߝg6TU+'';|?8y!mUnj`cK޵تt'k}q9i1391aT8ʏR:#<'뿧2;ܙ'j#KөxihPpS(n~*PP(+8QPR+Q6ŁRw^ (kf|7x{>k]iĥlurXF:6g3jNصYKbv J~HUMfjw' ~¸)dxggGKQ+yb}[#b7iTJv;fż~VB;aМR\0{)U'g=A%2#euW?R|Nꓮ;:Bjw-1j)Z}*;LXԆ)wɤ|tĄ{Ah6_MKTB!oqTTW1KNx(jT9\53^x':pVBnEz52Ċ5؞=s'?\_{?s BďX~Nhwwo_n{0ms%efߏ?}1ןOeAfTK3gwdP!x#$X oIya}6 bEtԽStf|9A1,t렫-CiGał [ "!S.afvgبy󤌻9@ |w\w㡑]oY}0}Ċ- oLa_IH!_h<8@#^^ ^BjU ^xior* Ϊ*PU{";RQ*Mo'_W,fN4>m1f  \QW~RaԆm˱=rN0IZK)gW]j6c׸au04}ۄB۶i*R36^iVj |̇`{ػ̻^㾩dz:]YϞ\Eh6B!['`$(#7jԪZوkSu/Yk+}J h{ hꞁhdKU5V@Hoh~0Jm:k iBUUC!vЌާ4oٯ`04Z澴O̽7?eDʚ_m%BHbP5^OK^a FNVPSU$J,p Mf~|u?I^o ! ZAt5kV:l(N;(*xU9A‰KAhy\V{E+J!B'$oB{DzzOԾjY𪃪J'^^ Λ*vY y=ZB!?Q- Q5Áf{9+lxi4xzOZJ!'hh=?$B!+hB!-t !B!IB!S!BI:B!$B! 锧ׅB!D'B!BH)B!$B!I)B!Z=B!ՓNB!t !B~0!BN:VB!Bz V!B!ZCNNη M6zo!BRRRrd -Hs_IENDB`refind-0.11.4/docs/refind/index.html0000664000175000017500000004401113372346574017524 0ustar rodsmithrodsmith The rEFInd Boot Manager

The rEFInd Boot Manager

by Roderick W. Smith, rodsmith@rodsbooks.com

Originally written: 3/14/2012; last Web page update: 11/12/2018, referencing rEFInd 0.11.4

This Web page is provided free of charge and with no annoying outside ads; however, I did take time to prepare it, and Web hosting does cost money. If you find this Web page useful, please consider making a small donation to help keep this site up and running. Thanks!

Donate $1.00 Donate $2.50 Donate $5.00 Donate $10.00 Donate $20.00 Donate another value

Introduction

This page describes rEFInd, my fork of the rEFIt boot manager for computers based on the Extensible Firmware Interface (EFI) and Unified EFI (UEFI). Like rEFIt, rEFInd is a boot manager, meaning that it presents a menu of options to the user when the computer first starts up, as shown below. rEFInd is not a boot loader, which is a program that loads an OS kernel and hands off control to it. (Since version 3.3.0, the Linux kernel has included a built-in boot loader, though, so this distinction is rather artificial these days, at least for Linux.) Many popular boot managers, such as the Grand Unified Bootloader (GRUB), are also boot loaders, which can blur the distinction in many users' minds. All EFI-capable OSes include boot loaders, so this limitation isn't a problem. If you're using Linux, you should be aware that several EFI boot loaders are available, so choosing between them can be a challenge. In fact, the Linux kernel can function as an EFI boot loader for itself, which gives rEFInd characteristics similar to a boot loader for Linux. See my Web page on this topic for more information.


rEFInd presents a graphical menu for selecting your
    boot OS.

In theory, EFI implementations should provide boot managers. Unfortunately, in practice these boot managers are often so poor as to be useless. The worst I've personally encountered is on Gigabyte's Hybrid EFI, which provides you with no boot options whatsoever, beyond choosing the boot device (hard disk vs. optical disc, for instance). I've heard of others that are just as bad. For this reason, a good EFI boot manager—either standalone or as part of a boot loader—is a practical necessity for multi-booting on an EFI computer. That's where rEFInd comes into play.

I decided to fork the earlier rEFIt project because, although rEFIt is a useful program, it's got several important limitations, such as poor control over the boot loader detection process and an ability to display at most a handful of boot loader entries on its main screen. Christoph Pfisterer, rEFIt's author, stopped updating rEFIt with version 0.14, which was released in March of 2010. Since I forked rEFIt to rEFInd, Christoph has begun pointing rEFIt users to rEFInd as a successor project.

As already noted, rEFInd is a boot manager for EFI and UEFI computers. (I use "EFI" to refer to either version unless the distinction is important.) You're likely to benefit from it on computers that boot multiple OSes, such as two or more of Linux, Mac OS X, and Windows. You will not find rEFInd useful on older BIOS-based computers or on systems with other types of firmware, such as older PowerPC-based Macs. Prior to mid-2011, few computers outside of Intel-based Macs used EFI; but starting in 2011, computer manufacturers began adopting UEFI in droves, so most computers bought since then use EFI. Even so, many modern PCs support both EFI-style booting and BIOS-style booting, the latter via a BIOS compatibility mode that's known as the Compatibility Support Module (CSM). Thus, you may be using BIOS-style booting on an EFI-based computer. If you're unsure which boot method your computer uses, check the first of the subsections, What's Your Boot Mode.

Subsequent sections of this document are on separate pages. Be aware that you probably don't need to read them all; just skip to the sections that interest you:

Note: I consider rEFInd to be beta-quality software! That said, rEFInd is a usable program in its current form on many systems. If you have problems, feel free to drop me a line.

References and Additional Information

  • Informational Web pages
    • The EFI Boot Process describes, in broad strokes, how EFI systems boot.
    • The EFI System Partition and the Default Boot Behavior covers the EFI boot process in more technical terms and in greater detail, as well as how Fedora's fallback.efi program works.
    • A Linux kernel mailing list thread describing the new EFI stub loader that was introduced in the Linux 3.3 kernel series.
    • The Arch Linux UEFI wiki page has a great deal of information on UEFI and Linux.
    • My own EFI Boot Loaders for Linux page provides information on installing and configuring several common Linux EFI boot loaders and boot managers.
    • My Linux on UEFI: A Quick Installation Guide page provides helpful tips on how to install Linux on EFI-based systems.
    • Phoenix Technologies maintains a wiki on EFI topics, including information on many EFI system calls useful to programmers.
    • Matthew J. Garrett, the developer of the shim boot loader to manage Secure Boot, maintains a blog in which he often writes about EFI issues.
    • Adam Williamson has written a good summary of what EFI is and how it works.
    • J. A. Watson has a review of rEFInd on an HP laptop on ZDNet. He had serious problems because of the HP's UEFI bugs, but finally got it to work.
    • James Jesudason has a tutorial on installing Ubuntu 13.04 beta on a Macbook Retina Pro on this blog page. I'd recommend using a Linux filesystem driver to read the kernel directly from a Linux filesystem rather than copy the kernel to the OS X partition as in the tutorial, but either method will work.
    • The Windows MBR2GPT utility, part of Windows 10 Creator's Update, can convert a Windows computer that boots in BIOS mode from an MBR disk to one that boots in EFI mode from a GPT disk. Note that I've never used this tool, and I have no idea how it would cope with a multi-boot configuration.
    • If you're interested in developing EFI software yourself, my Programming for EFI can help you get started.
    • This page describes how to set up a multi-boot of five Linux distributions and Windows using rEFInd. The method described was sub-optimal in a few ways (such as re-installing rEFInd in each distribution rather than using refind-mkdefault to adjust the boot order), but it does work.
  • Additional programs
  • Communications
    • The rEFInd discussion forum on Sourceforge provides a way to discuss rEFInd with other users or with me.
    • You can e-mail me with queries or bug reports.
    • This thread on MacRumors details efforts to boot Windows 7 and Windows 8 in EFI mode, rather than using Boot Camp, on 64-bit Macs. It can be done with some models, but is difficult, particularly for Windows 7. Be aware that the thread is long and has many false leads.

copyright © 2012–2018 by Roderick W. Smith

This document is licensed under the terms of the GNU Free Documentation License (FDL), version 1.3.

If you have problems with or comments about this Web page, please e-mail me at rodsmith@rodsbooks.com. Thanks.

Return to my main Web page.

refind-0.11.4/docs/refind/refind-mkdefault.html0000664000175000017500000001366713372357235021647 0ustar rodsmithrodsmithContent-type: text/html; charset=UTF-8 Man page of REFIND-MKDEFAULT

REFIND-MKDEFAULT

Section: rEFInd Manual (8)
Updated: 0.11.4
Index Return to Main Contents
 

NAME

refind-mkdefault - Set rEFInd as the default EFI boot option  

SYNOPSIS

refind-mkdefault [ -L|--label <name> ]

 

DESCRIPTION

EFI booting normally relies on boot manager entries stored in NVRAM, which describe the locations of EFI boot programs and the order in which the firmware will attempt to launch them. In Linux, these entries can be created, deleted, and manipulated with the efibootmgr utility.

Many OSes and Linux packages assume that they should control the boot process, and so both create NVRAM boot entries for themselves and set these entries first in the boot order. If you intend rEFInd to control the boot process, though, such changes are undesirable and require adjustment via efibootmgr. Such adjustments are annoying to make and can be intimidating to non-experts.

The refind-mkdefault script simplifies matters: Running this script with no options sets rEFInd as the default boot program. The details of what the script does depends on the current state of the boot order list and existing boot entries:

*
If a rEFInd entry already exists in the boot order and is already first in the list, no changes are made.

*
If a rEFInd entry already exists in the boot order but is not first in the list, that entry is moved to the first position in the boot order.

*
If more than one rEFInd entry exists in the boot order, refind-mkdefault moves the one that comes earliest to the front of the boot order list.

*
If no rEFInd entry exists in the boot order but a rEFInd boot entry can be found in the list of Boot#### entries, it is added to the boot order and placed at the front of the list.

*
If multiple rEFInd boot entries exist but none is in the boot order, all the entries are added to the boot order, but which one is first is uncontrolled.

A rEFInd entry is defined as one that contains the string refind (case-insensitive). This string could exist in the description or in the filename. The string used to define the rEFInd entry can be changed via the --label (-L) option.

The intent is that refind-mkdefault can be called after booting via GRUB or some other means to restore rEFInd as the default boot program. It can also be placed in a startup and/or shutdown script to restore rEFInd to its default position automatically. Because it does not re-write the boot order if rEFInd is listed as the first boot entry, this practice should be low in risk.

 

OPTIONS

-L | --label <name>
Instead of searching for the string refind in efibootmgr output as a way to identify rEFInd, search for the string name.

 

RETURN VALUES

refind-mkdefault returns the following values:

0
The script completed successfully, which can mean either that no change was necessary or that the call to efibootmgr returned a success code.

1
EFI boot order variables are available, and a rEFInd entry was found, but the call to efibootmgr returned a failure code.

2
EFI boot entries are not available. This condition is often an indication of a buggy EFI or badly damaged NVRAM contents.

3
No rEFInd entry could be found in the list of boot options, and so no changes were made to the boot order list.

4
The script could not run because of OS issues -- the OS was not Linux, the efibootmgr utility was not available, or the script was not run as root.

 

LIMITATIONS

*
refind-mkdefault does not work when booted in BIOS mode (including via a Compatibility Support Module, or CSM, on an EFI-based computer). Similarly, it does not work if efibootmgr is not installed or fails to work for any reason.

*
The script uses a very simple algorithm to determine what to move to the start of the boot order list. This algorithm may fail if the system has redundant or non-functional rEFInd boot entries or if those entries are not named in an expected fashion. Cleaning up the boot entries by manual use of efibootmgr may be necessary in such cases.

 

AUTHORS

Primary author: Roderick W. Smith (rodsmith@rodsbooks.com)

 

SEE ALSO

mvrefind (8), mkrlconf (8), refind-install (8), efibootmgr (8)

http://www.rodsbooks.com/refind/

 

AVAILABILITY

The refind-mkdefault command is part of the rEFInd package and is available from Roderick W. Smith.


 

Index

NAME
SYNOPSIS
DESCRIPTION
OPTIONS
RETURN VALUES
LIMITATIONS
AUTHORS
SEE ALSO
AVAILABILITY

This document was created by man2html, using the manual pages.
Time: 20:12:13 GMT, November 12, 2018 refind-0.11.4/docs/refind/mac-theme.png0000664000175000017500000010744513117302434020070 0ustar rodsmithrodsmithPNG  IHDR X' pHYs  tIME ;8@َ IDATxS[Y';`0+tvt㌘~ΟSvNWȉӕMNMrflW9I4-& I[ҾyXFݕݶWoѯ@XXXXXXXXXXXXXXXXXXXXXXXXXXX ŋ/^o\nvv>|0J՝;wܹmÛB    N;&&&L< S@ۋBv, `5>>~|@,+ i(GU*/^rJr^TT !iNLL,..r|>ϯJm{yyݻw|޶mBH<OR7o/_uֽ{&,8x<(mA+7><*MxzeS@cT*Ϟ=?OLLbx<~Z9xP_T*6 \.;s͛7JUR1rA2Mrܳg<@xmx|ff=|޽3E9dt>y͛]tPX|0x# ,=D0wSFa4Eur?2d'<7@8yeYzz CX]ԥ9h4 X ^5oh>Xpr5$w莃!s_|IT*bmK@PA| `@ݻm{vvRꫠ]0D@϶m?{*JT 1 : !LLL4.nmv.k\:J}Q TqN[(j]㏼U+-“J=z|>g\JFFFB0p_c/t   :F'mll42 (rFZT8ojuu5OLL{6669&xc>?ζr `[/^(xA k]sΝ;sss=:=r9L[,///OLL4~yyYCnЛP#ܼyTTBȭWH>V*yׯ[7o6GI\.׶/ji+k{p)GT*'۶766mەJ/^x"JrΝ;w_Bfgg !oZbbbٳg/ٳg7|>x{MLLrGͅB!۶[ݻ!$ ƙx<7Nܹ`MgϞ|2Jٶmg}Ɵb.KR>ěVWW_xg*|ȳgVVV=zij 5ܻwΝ;>|ȳW+EQ&&&y$'&&?{Lїx7??_/sss<󳳳LZ]]m,BLiee%a1l֙aX)^ZTYS(!lllB֛B+Xd;Xm|>(i*)瓵p'?>eY{x.,;t)?4Ͷٶy BK+4 _|ÂSE9v<a\.QӨO0VM*ࠉm꾼:ߺuś7o6nCp 6nY o@.x8###Mx"y͛7x*B oJLV|{ۦ,or~YT*7o pnnn|m?}C"x炦zÇ8< _|7|W_CP0̗J>}xNZfB&&&^~qg7:d;wfgggggx޽{|={ŋP(/ ?x`nnqgee%J58믱RTZ BMe۶wNk3BZo擟F ySЦ!<۶6qEQeڵki6M̅:c&yϴiV S@yb/򃥫@29L/NW@(G^٪<()L' 6i~[,)_Ot8N&d2NًO`b# OűoEo~߿+R!:s( Baaa!N߾}ؘ8ϟ?KX] nw2EA:իG{d2lvjj6l/tt:nUVNO-?BㅅƘ0;;{PO6 =]ׯ_kkk{'sBL&,P(bTw5:S`9paEQ>֮!;;;mcam/z8~P yW6TAeQEQ!U y.0St D"ǽXd1]5>!8[EQ4EQE$i)Fa(0Bٶ]m<Ei 4.7bɓh4LF!z $j5J)9@<,5Αe9N'ɶkB6774 _(]PE>J8k "" T;lkvd2u&j5LjXũp8(aY%I q\-rYuKg9(eY|1fvR9䠬(J(p8lOCq^EQ;نu{8Nc\ZZj}"+l^Mkو(tEcODD53|~{*22 `; $I|XY(|1M&+JrP(ڶzexƲS=˲(4~5[?=bq,+>*Z8]d2PK@˲ףhE[[[<~u>:7zao1Fڎƕ.("'V LPE5QʋcO/Y6֧GD"DQlt<<_[h4m{}}',uȈ4H188($/ՃZ-˕|>kZWYXXXZZjO03cʲѣ.A [#lێFJѰU©Uc&нHP񗏇okطATe۶1 yFt"JP4lllJ iFdW64 Y__ٹ1nRBo=侦kr8NR1M煱d2-:2]|=0Z<)E*vT&iI=4^煵Ff/1B(凑Z7 nH$FFFx׏$ q^O _iX0T*%I*L$h4gٝv?hQB077wdffffZ3eYO`TK?xgcI#A 4mpp0JivYoܸk(Mn$ba\n}}r68ߞnT(޽L&-o߾} q ]B4z=o{YV嫽ŘJjB5ͷbˆ7^ROF4,@+-vqHHx<~O0ׯBL&sum`[KKKBg2'Otr?dM5Mk,L$M 0 YwW N\o}kQs%I(!(MMM}t;=L~']ڦ˲j\ýP(t+?~X=E1t+XmzyMRH$B@)JVIlwX Jy8uT*u֭36כEu@rn*4 IDAT~`ӧOuCq53io10* T ĒD*RF!\ Phll Z:ɃU+vzzѣGG6yoNW6c1k?_1|dQ"l>!@dI%M k? "]\7 ೪IRYZZZZZj Ѷ#qN ?Ϗ5e*9۝/tdZVTD#39>`ј%-dXpRT*4Mjuuݻw#RVnA6N;\t{mLZ>mnc$F้$!Yc#0 ]GFF7or49Lu9mA:j5`q'jĈ#ƄHV0qEJ`QTz֥h;CoN^mu2^# _RZ,[gǝj+"a1h^dNU+r ޮskΨNTkb(IRGtSk#+kkkkmmKEYEQP(rQRFFC;Tf0Ugjw|`-w1Yy  z[ vt,ʹRtu}է}#;qŧaリjF)}-_poeBF#+Nl^ݝ3|ᝁ)F0],EeYEAg `%ƗHT*Zsɲ|d+7~{qz2<2<ku+ms,M4M[]]]YYiYUb7͊ޭ?8;S1[_,KUUP!BQ5M~ xX'޾}{kk렵]2Q̲ft߿'uaQJcAKu]+?zAGp^^{mSN Ut'd= ,JHX4 CUU>Ax_BwDQ]ױ!RiggJ=婩N&!6 ø~:;ztEЩaŇ 4-.--v7F>~3-NS V޻k_auuu]WЃP8+|t,;nv0fff>}Zjlɓ'h4baׯ_XpS9]pr8Zݽ{dDZmK-˒e_~߶^lxyuVV0@iYVc ,˲,x;V‚_ZZzՕ]aB!˲l~ŧ~ۼt#;2g7wCO\ˆb]sh;6]moo}VP(뺢(LodƵkp#fضy^OLLɛmnnO*]!aQ-lN:vq[,O---4~Xd2e%<Q$ 7zܸ09뺮YVAG+ƆQˮ$"艢+ʎdZNڵRL|]z<bPH4ޠmܡ7] E/3b333\_2hZݾ};,--I70>3~Bp)M[R,OdYdċ'3 }>#1(i_~?X!vܧ+{u/W`ȁS766jZ___8uCE< Ӥp8s8@ *4*Xy FL*X,]B, X(r9˲JR|X,ff,iqkZ'SrܵkNMLR~'o+Nyg۶뺶m88yGTe4xɓ''Bᔳ4MK$B흀۶yͫ(۶]۵ZMӵ\ujb^k׮C!Aj]CKj{?5|]<1  .X{+We/<}d2ǺI0~'Bm 8_}P~8>z8iRJO9C`@_AD"jiډ' ضnuZdQuJ*`̵x|L 'l_.A>~x]ՖSid絾Ǚ;e{ 3%LnmmYqVJ]Ji8assիWm˲,IRi~Ū,/^^^Vepp( ٵy1Bl-& b5ExIx#]'Xk :8wޝ=ěP(Ny_-|'6ή-p8y_QST8D"H\oLV-[[[P֭[}"ڼC<+QBMU%9ueYƆX._o++NONNvN_?f߿\9W(N&cR/W6mWle0&EWCuYu}AUUAL ]׭jߤ[nRcj;ZP*XrNej0x4gjaX\,`QSX)SSS76}|#R㽻z3OWB^?G nv}0&0>#:\G|7+>nqq\.SҠ[(=88'6]y]X*'+ (^{U~Dd4Jkej5Ƙa|)C(4 t1y{'6YXXx۷ Bw EBall+tjjN璮z^[$;mퟶ+ő ɈK1MUALg5VjJni}UX5GO%?S͛7b(VP@Fׯ_um6[T-ˡlDE(P{^fWJb}w}:{}XnWb'2 `AB w\ЌL&5mjYV WٸɞZ)]w<E?1ƶ_m,KvT9Cd*" (;Sl˫TJ)nvvVv.-) hR)Q7662;x᱆1&`4mMW}nf(jX_ PX AA|9y[إbS*lZ]l<}/6cQJXX+ E`bOz6.*SEyWzuݠgpˆ[s7Y|Vt,=ո)*"Poo{;cb[gז_^5a?\U!|B^. 6BP8fM3 ldֿ/́kɡ-1 ’ DR Lbn}*J[/,n[eYR> `0`E Xccc:s854}E/QBpoXݥ瘮U^gTTGs$FQ(0]5,*PJ,!%4lLEC字[:?`nr%tmHfHd";]5, TDEXtlj[ԟ=?8r_> `Ap' b7ѱFX酀u^o`zSV㭧/ǤHH )LɱUsXfL߈N Ќz5^vWOR#J($Hr'ÂGQJ ȪMG_^me!; 1@ X4l D dNnd3ΥԴvWA)F#a%P9cɡthx<2.Ʌ|kvVVPB.X;)J +EEUSc}Bbǭbv~UQ,!`?鴦i˲5jX/Yw+LMMK'W{~"wt\JiUcR%pL;onSBje"gTRi5ڻ7RAuKFc뮴V!X+Zz^u FʲNJ_}l|} N teƑ)!^P$|_SD.@)TASƐ_V lZMBS)~Aj>QWpEwJ(+ޟwzS㣫z+@KF{y#!SǙoU~e];ywbχ% {?/aL+BHKT3xEH%]nMsx+|-&{>9L^j*(Ȳ}.̳m< zvZ~ᱱ1EQz9`tQPꫯ&w8o"yHf&$c8= k~9 w|_J(U9Ēz?Ss#7oaQBQA9. E,IM%(Q`Uw\B@ho8d|0ζ$;KxpGbNd2~Cg`gjӈĴBT<^"D&q%&[g{Ƙy'SȮlJ)2!gUBJERjvV `Au&tzo=^rPzA˲:t4 xlO<9wF=3 0,JpƇ}J,(lʜc 뺾ﷶHkYv*e>Iƴr"1E䪦|.R*ri=A_ X  &\vRݻXe LE..V+|iXsEOT"R^!D$$Uvf (=(Yt_aAy zeYߞ\2Ȉ &=:OU XQ|tE}W_,J$Jg[j0 eAD;>D= XG,"2#n݈ 5e쇃2G} .p|i|g6s%O?棅 ,K:AR"߼   T__}kkkG^碬 XsLWSX qPmKzjssͭ!,$QlD+ B7eu/kUs?OiOB_d2iZRlnnNOO_QQt:AcRl|k!tkk}_Eag#|WvVJӍ%ߓݺ|Bi/FL1!Dx?\>u}r6J*? 611![[[KKˆ ʲ̧`2{K ooo۶W/ wC2Mb~HT:uL}WVVzxM"وnYx/qbپjB yi FPXe>!'ӰXϯEtj|_aG<.j LNNƿ˿b1Ƙ()Η_~_>`O}6w"އ`~zRIN: y"vMe3=BDB3B|sja{-x]Ȳz(*| IDAT|J Y-%zּ,w&r}Agツz.!~#1$AdZEJ__׼|v]"yJƆa|N:Fӿ| ýRhtBXk8=0\Vl(WU*RdY(PyGJjГel\rN:BXsX[[[Xrw꣔VUd2A/"7+yO)jJc|=#L&/ĢP(tQs XAJQEQje"Q,n7gW/FXu&SXbJK*1BZۉQA>&}4 et zE> zp]~N . (CyЬub=B`Yccceh4zױ"OW$IT*ժbͥҨNtrgVE2_jJ"rX|#ha$dӰ.!wQQUVc9qKC8<* ~V !/#'û 8x+D5,ubkw~nY`wzR!hV.rӥZl5cY'|_GUUEQ 1rqYi~tv]m?nvOvg\O>zy+NEYE$X,vusb(a|BzwWswɬ+^a BsY+oƎJ^Gu9 `AϩV\?z[6~e~?_mO׉bo':y4IdYVUUUjb#93cKl,B|Y4vb5]Yy^(2MSbX;Ļ[;nnc8 `Az%.beQ"Bp #m?) _8{|Pn9xRE4MAn|;1?kSǘk^}o13iMW<anwZ_[[Y8@aU:~ (_鉿o,xj8nuuuݿj0a6X 'rE9XƄUܼ9Yz,ؙYyg#>镕mJ:fK'UUuF~qX, 2C|yX|o[Ikӎ1̯R?bUe9DxY.y9hmWVk~G1a>vvv@Z-8(8X4<|z'"cVV:#druu WXc^?AJi hL8mzݲP($Irӓ'-z&i'a'i|^Cb@Z5M3KJeDV)0Jk$Qrxk,RLuu$v@b۶H2=)6oEx7eٛʃWjY,qt'Cs| Èbi(JV3:RJ+`5?xm!x[jb-jG5_vvy;R]H.cߢ RD)bp] A[@pf~n=鰌ؘ[qw{&dh(4ψRA hM4 ~,"n6ZeYf'sN 'X,vЇ܋SYT,m{_((v?;2Zdy|ݛP{zYzU)z=L$ȫMj^r9Y2B(%0¨kR-߲F|B%mcQrʞױZ XxOtb 4_-8d?{65.q;5Bݻw;OJ[EӦRH${^q̒$)B*']~Y#K(˲墮\.̈X`#h9Ԙ >Ys*'LO,ȑ9sfA^( EKD"(u\,;cS艟c$q?TUtöTö/XpQ|2|G@WOPxɮݻVv& XF_Zk|R;x,ߒ%z~O [pddk(UU> ]D8~35:Xl;XCQc Xv Œ<3#/CwyU`Θδs,x"&IY}>1háj.b1HLLL0=9 }>,?,[s5#.o~s|P(Ic&x<;  .˲F4-?}467'",r"W̰LLUtH<w\>Ϩ$Q#t֓X9P>zAy}gq  MA ^Qn&faaƌ6>FZ㣜:X>_*mO|>?::DlQ%LI?~ҥj2Ç;::Vfffjq3̆GcEQ[hx&ijjōrLfii)Lz^OW8FulF'gccl6J׊.# `+-͎{<۝1>52M5>ߩb[nWJ^z>r*l>|… REQqLR~\ {Mm}?rhMӢ(`~]]AQCww;ORD4 4gʲlNQ6Nyg8MgƬg] sW]5z4rAEQeM`?66655U!7۳g C3UO3gD" e^O߿9PXC#Xf6T盚\.^ h\rGGG53 `ͽFBwMϏFsssHde5[Fҗ`(+̍ s`S/,,h^dg~~~ii)/D$I 866VZUr('$?~N]YP(d3*YIh':Ugת,Aps'a /}v۶mMMM߂L&gggrHNLL0335NMOOs^UU5 B|>O-qTKTyi{LWh4jRZnުf]4x}@߲= ^Qlɓ'XBUAPX\\FSX,X,ٳFirh4:99r~a$IaHSkI!"K9 sss^hNxxl1G٦&I~?kiMfffhh5\5M<999;;p8|>_}}=quuuk'b*4XD"mUUf5Yu7nm,痖$IF?t7rf=,ЈV>OQ5iͼv̋u[}*W699YMZg` pGA'Nϯx|>l]Ü8 X522*m|Vm600)KKK[;(nH ^B4 淅&,`. ;a`,,JDQu/%X <l1dӦ+۽o]s݂ Rsz ] `(,t:;|sQoht: `yr\B@{aG(<1Ec'7[,,,@@@,,,@@@@,,,@@@,,,@@*D5iq1EQEQu|^4]u]yBjDusArqi4@ؼ4UUE8/$IJ$bqqqxtt_ަ*Wi26Vr\1ۍV5X˦zU DUY'].W<_˛ma<Q4cU 2vDQܽ{ӧOsRR, )cb0?RM*-ŨH$@Ze]Zq<駟sϑ#GvY: +%ض\h5>>fpظ<M(ϑe6cmx 4MQrAhoorUztZi#JP(NTtk?#әx eKQy@UME].`ݻw/ P,ݻk.^i,EQr:3o[.#]MOOǏ'IwUZ^秦fff&&&c@RHkkmFr $Sz׳\$ɲ~9\{Ǐ777\ʋ8.?~8HiEQ߿o>``<&>Xcܕ=~UU,Ţ(˸JW333\z;==mE tzxxXgnT,kvv+W#b0t\Zsn=E70y{Ԕ  @ TR?@CC SSSwܱ( (@au/sxZʁ|׿\t5<rռСCFeáCRUUk]y`8H=޽rN'ikkm4СC>bS2V׳\tٳx'^ڀBVa@QݱcGwwwgg,W#bYݿ<jP,޽+2]}c,<333~hiiA;X\\;b$y[z|D$8bQH=uttHCVj墩-! j^)}ll,466RfCCC`_z$I---@_W A( mv M 5X*Usu=ͦRd2Jr7n֡\dvvvrr*B~+jp~"8nԮTu+b8??r'Up׮]4A!cpx=z;r2iZKe˒)5rq*񥥥!)IRcccWWfZ  Ud4$U`fny, ԩٸjֺ\hT$Ahf@ @uW(AB lq\PD"FM@R|Cerl7ljjٳg %X 0YE4@BYaEvbX,4@ E#22 AjT.,W"b ` seRbX mNÇ=Hd2 (b\.<==M U T38*o0p8 mmmtexwc r$I*zڕS[gg(SSSz,I^/5z^HW---۷o7+f HШXXk|a[Y22`!it:Ng&Y6U|rrRAeB/B$1: 3v}>#I*(XFYr*,34Nimm8njj2ipyeLD  `-lAWy,˖EQʶ9reܔ`d*UԲVaRUQt:];jZ.R[^KK ol^M+D-|O">jra[q+Vw,U m\m3ug'iZ6e٘fcEwif&/Ieu+gN#FܹCw|yQ_f{{{Y(Qoj+?,1,Դ\1ctou.S|򸩶5In{=e3zݻw^.7/5 N4b 0Tn5pq5sssӶMlv!4;][ZZJ3zeQ捄Dh4*Q0utڕtFvc{x{;w}>k5Mkkkkkk3B(޽{nݢE{[ N# `lli5Ѷ\uuueQˌu/dy355E*~riV__on033c:Z$iY]e* <ߺuΝ;4m۶uwwwwwo۶͜2=O u`#"` `FuU^Vkri匉hPt533344dlYWWq\i,eEQ|>MMMU̹x<>==m3 ڕ=*Wtƍ@ `IWݙL&twwXV >|x5#cVr6]r,N|9f5B- aCWVY?~i \&15M47\b]yORϞ=ܻhnn.J=~7 -)rd&~755y<c#5Mkii B4jP;v0FFFʼڕ 僻.85UF;SܩQ3˼`0N~4rݸqc޽(P4,˓>BYTU.ivv$IH$G" K655&''EQe84---ZjZ.EΖG577\.sjnn4 1e!c, n4Rb=~XЩn)@Xcb1H2VjUXd256-W&q:;wJ,]޽q\__u1rM{G3-^|:`Q(4e*Í*m۶%AE۝NGFF2  |>S,hԬ1KӴd2z)LmDF)0pqӨ4-JQ2XסU=K(~FY,{7+6l6kuF~0 P~'_Q2L&,Q|I&Цi @ȑ#Dz ,5 ,T=Jhl6KwT< 3aYwQWW7[a͛7ij:^MMMQ>|H=,8`1b@? U+y,j֓'O>|> U)lid2p4&P(4;;i nccc ltnIS \\\lllaE)B24¨: ,+(E薤(Jww7MeH/72ͺK4EQᩨ۶m[\\hte,1ؘNiJo~9躕  qp\|EsϞ=Om$P(`$3̏ Dch,EQTUu\.KQJ'{ikk8NUUKf(ԕr% RXPԿp444P4:Ciզ*e#+fمL&H$<(i4ܹDyN ,(>*l) i*Jj ƫwsu=q `hp8цV4ZD:^14MevkzaU4eGۊMX.cbTQEA-1jP4&U YmTKr܃r2VӨk&I`VOR\q,qȌ~tP#PNX4W=Z]mrXZҌe.IHb4)Xe4VJ/lӐK\O\p3QS6UXFsy2sY Yvb0+;^,W,K\ی;SԦ-ʢV)m8.=R\9NUU)GGp`Dz{Te k,uy[VKZ:ޜ7j\[\4v'ni:ISnX*`m躞N, wpz0f2|IC\Rt$2UeٶGWF,j G4޷ &ӭvƀC[1ʵŞO#I&iUn irʠ `j|>OUd Qv\[h]XXXXXXXXXXXX[]P(|'<<޽{K.ݻpEGN<~D"a{뭷< իWGGGEQpXd~̙3?wߥˀ(0?3 B:~(kʭ}ܻw/L~tkkk}zܼysűÇo6q+u^V|4~x7`,ꫯ`}}} ;dJf@XͲ,R)UUc }?x`kk+cH$_szرmޞ={ܹtV~H.;vu/D8J sҹs|MQSN|l6ۮ}vvvppP;vzou]r?.tEH> TUVG@(K c/^ áP(|7}̙3Ν;}Z5p8zzzn߾}ȑܿ/\`~X,vԩd2矇aAl+:tʕ7|ڵk===tU]}:::ݻJ"ܾ}; ={v{/ٮX,&~A}!~'߿_y-/^ܱcG8^\\8{/^ p]Wm^zб8ş~+2>>nKQܹ3 uV6e16::_Ν;;::k(|؞;y,t. ݻcxxƍN*m7hVL{#,iG!Jb1R^l}}}郖nO/t9\vܹ?[*EWG%b:vݶOkkkxb:>~xrx< 7o4`:>tP5.^_\\lmm-]{> {oqqᆱw\>ܶm媼t:DOO}}힛knnQ\9$&Isߩ5?m,8;}_L&{zzzh'؊8zW>@`gϞu8dŋWU,l6ɔ>Q/˃~[oEm7Aػwkb}8u3wk{Y֞$I'h^1H6ŸjӲvIt]ߵk󍍍sss<Ϗ>}d2?, +8pgK˝68ᅇcm:H${@`911ښt]l6t:NgkرkҢdB k׮ .IRPR(r4ufEƫr5N]EQrqqSSShBpA 'ٳg,d2|ژE"D"A1~-2ƚ~;#LQ@ `[eh:}H&/_~w~ܥK*`kvwu,.#N~UU}>Ǐcx< >h\TqUR%1&&&"=x}Y~rkeYQIVٮ1SX<F uM`wwG}~;vسgsfff+]xGf˗//,,0R$yXww7TU5ROAx^Ql9k#s.U۰gn,J&G[[u8q('OZcwt钮>ﭷު>СCO/t]/cmoov8vyׯwwwV0455y<]yؾ}'&&mV#G\z֭[PܞR͊c\СC,[{oo˗?3yر뺞d4M31qv*7C<~UiS59m @VP(d4uuuݾ}ѣƓCЅ 4M8n߾}ƞ/=իkiiWwnnʕ+mlRY3W6G>䓳g| Ͽ&B-֭[W^eMNN:NΝ;HW/`laTLR(>|T.]w,MXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX? D"ϟ߻w/7o=jgf{p.+K.҄>#ñQ{~c&%@xE+Wr9W\IӒ$r/駟8vUݾ}[uA(WSYvHbھ1&|xܹ??O)ҹ\.Q rG1q/_2uD8}tvvf2]ϟ?OO( lb>|zXuXEѲ306Ll6z'''Ԕ|ѷw몪˴;v re~n|'%8A8u;;;wmlgò=l`/_?t %I268JiCVI:1EQfm_e `lI, MӨ "8N-,,|w@@QAΞ=e&˗/;~nnҥKƿl[:,R]tfNSUd2_  KΜ9#bonnccc˹|,l7Q۷oF.]˫<e& Y%I2BP ܨƬ ;dśܣ_dY}*%t:nȈiT1SӞEyGFFp|>_2#IuѣGw5TU|?f-..`0zt>WUUn"t:۶mklly&Yn㻻oܸJ^aE$q]ST_e)"ݺuAˤgb~b1DXU;dr~GԵwHӧOcx<644ؾ2-kݮ@ z8~իWo޼'& ]pA4Gm'N8n׮]FÍE]]]KKK(sssW\9zhdHœ'O+>RO>DH:_555۷o7϶޽ҥK|zƯ]]]|qsY1kO<Ͽk455yw}֟z+Wկ~+'|;loÿ-c*^tӳQÇ~r{ʝ Ǐ%vCpАZMMMƠh/q_s`:lN+7OjNS޲槫mmm% H>3~|gϞ1^{lR[f./޽{t8a{2 rcǎ5XYV72mgE,2M4d{W$t%=Fկ3dS%Vy~{Uz;.\f{{{ѫ `%lN~j?۩S2Ԫ_槫rgٳ~_XXu\+/^ ͹p5Tt喹Kq\*:uT&_:'…jYV7^sY\u}bb㸺r|MLgi["cT?CV9UbgQwsiiiwߍF_}U(`U:uZSfe.̧V;?ݲR/.w!ߤ* ]沦 ,7?#V_*O9mg0rV59}'?þ}|MLgYa/*W=uK\P(qE<*j`JN~jV%Y|j/pMozFX"?k׮v^&U?]+.?r{ط&,D[ ZS~k2?]i't:c߾}˽l6i\te#ͮ\,7+bM윘hii)=+le: {rl\+ Y!^\aV3U:Oٕ+WlO-UUNWΏ?WjI/s.ɓ't8bq8lOՔ􋫙 "鱱1o{W$tUU~r/rr/_T{_~Ғ>?{j#`Mh;Z+Z4|0=rȑe更eV-SUU:}}}ᰜ x믿<433sV_\˴qs1G[[[oo |M2OgYn/Y,կhk5fo} h6T*W_={mEPZ~r٭LK\fggwܹgV6;0&%&B\mFuz6LMk #XXXXXXPc?!AIENDB`refind-0.11.4/docs/refind/about.png0000664000175000017500000020165212626644767017363 0ustar rodsmithrodsmithPNG  IHDR /|sBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org< IDATxyTՙo]w*#nwfhcbb&N։ɓ8q2_6wD@QDA@TE6Yizn-GTuW7Հl's*cذaB!aO ! AB!J"AB!J"AB!J"AB!J"AB!J"AB!J"AB!J"AB!J"AB!J"AB!J"AB!J"AB!J"AB!J"AB!J"AB!J"AB!Jb>' DTUffF FQB!FqRӂ-0d2d24,--2tu eejjTVZ͇͘L&&I( D4V~KB:&JҢKixFb1qW`3CUUӣ̙ep6[b`6 Z"c#Bh 6lPO~C*"Vx$+WfٰL292,&$89sNVŢ:wqHwBAT`!ɐL&Y0d4c _B/6zq8zdX&͌L&TljAPq ? N4Jhks ˖9zqP̜K_3lӉd'*Z:R===iv;& ժ'ߞ*#H N8I&̛@QOw@G?W_ gX,wܷNPWp8lLǮ{H47'ٶM+C"EU%c48Vv^iтݛ"ʒJvPNUO<Ղ:$k$ٵ+͌Y'Kv8ڽjkkXz5l)Spzq:'UKGKqBi(<|LWY'`&5[*#wT՚aN[ؙ;O:jǛvI;dJ&chfZU~NMsyZٙG?Jq#oh,?a\ˇܓΝ1-.`0qm]\zMhOꡇb{k׮eٲe|Ї AA0#$֯q} eek&ˆa<KRػ֭lRGwhYfsLF%. 0,b1E9.cI y&΢EG_(S1C, T7]KO:ma„vL&SA? ,YbdʔvYd2 Tl,X۷3uTnޒs_A0Zyss;=嬳g&|>oS btOo7ܬ\9hP`6'@8yc#5r2 ۶)tw|c$kfYmSPvI$d6~! ~83x0sLAee%xp:X,,chSN{V +DE~;3PˀM$3RV LhjJL]en2e)+k#̘t`Z1 dYop&SF 3}z͆` ɰsgb%@ڏ48Q>;w{d2QVV'?CI(FqBdY _|If55TWWS^^p$MSUL6ՇʼyNt(U$(rɐT{}ӺZrɃYUFŬY{2X[`Zq\~q\L&4wfXnl6[ľN'@@/l6Jص0fh7}h{Xl[6T4Nk׮~{~SK N4N[K470f{\p~jjj\A.6@>5zEzVVH$ 9L&i=wh'h3ZQ% RQQ[ ^X,UA(SrMRYYI0vcX8\Zb([WT$Z}EΟA7?wqT&HRDQo_߯'~jA qRA[VLee! zsJw()2ÿkuL(JGӧ kd2[1~?[4FRg2g2Vg2PnAɔ&L r 60qDFWZٶm;v0l0 d=&UU휵VC---&A}RB*$hǕ6᭷ 'n#,ןn=ϐE*sdq:ܙ'K,fDQ(U-^V"ac^FJjw]֭[^xGXdIA+d9r$.۠Xk xQYTzSFV'}Js`㉠fY3鴑T L&^vlg_ff87|3۷o׷WUW]jeٲe̟?~el6j>p\ߟ>Efҥ455IGGt`0*28H G9NdIU-l3iR@nD~0Ԧ^m⋍Lp8LOOV#6'LI$쨪L֭\xa`\ ZF)g}{x.d~+W_zTU'7… yhnn>u  t"A8͛ne;v _#}b3Ll6~?K2!4LI$H&B*{8ٹv/Ѩ 1{y 0-k ǏgĈ~v;NM0cZij: SU̙-x<.M u-C@]Ԍ,xOWlDThl63fଳ]F#X{~߿dAH$; N''N*N'<-6rBӉ RUEo'#H*V Z#]窫T=xКwNZ0{qSUUpip`{+b#'\|r1-t:<p8rNj-hO::lhe8'2|I#. `R'pX٬@&A/fرTVV:$]v;SXf3<ӧ럑vP(Tt`0jA$hǍV&oc4rZаzu Tb1b3wѣ[?ޠg! &P]]M]]z§h p--jOSU墬Lh+- Pvr ;>HeOo{-ol6:i|f4;wv!=iP2,:묳=z4TWWODq/?Eo裏ݾ.:4h iZj7!Dq\4p~M Q51o^Xeg2#!}5R s2O9r$zZ(P, ੾y'^2 ?`@ @MM zkC>s҂>}5g$H=ЛL&>l~ߴ)UUg,&Lm{hbnK.aذa]Eڵ'ɢ &Ioit%A8r #L~ >JZoJň (RtZ}ɠ-uG?kM<YMƔ?m,Xȸq㨨s&nmҩl6[82rB|H s2a #]Yptwov:cx.R%7SMM^ݑl_QfoA(Ub#'f@ oơG 4O&?K&@eewЦTTTyLݮGyy9>`u~ h0ӑd"?G@ee~i+6bu7E~>Ú5 rJIn򫪪n:塹u#;׎1К~>H2BBzA@Im Ӊҏf$ZD~ `A$H9!Ng4d2aZ5jizm+#H$m՞i&ВYUZDb#'"8c2,5ͲcGTGrCSK9aUN?|X+" mg)++plѾ3 vB2!NfǍ$gX>}ࠡtwwH$ >T*>?AC@#^^) V&2d2&q8:_0pDȆT]%Yݷ@ @ykk+x 4B6G\J } N74JF] ˗nEѻ)߾O=5?+gtr7K+2/ Ο_ZU8`#?qp2 O&k۲S___t(ZJMȚB!q?3ujW^ݶsυҗ:UG_Q&I~>|[WHlX,V߼4=x<bM;bldCeeLy$`#3*+ 3ݿ$@ ڵ[,FQtZ|ZWȉx<^ DFN qU^vkf͚LIVNyn>lCnͯ8lqMۃW3幵&b-#& ho7>قјjjT>[eT ϡzȆ@樚 ?ȉoШg ZTUeEP(]wѣ?~J-_ti.X6ڿ@#`,Yds߾};۷o/ze q!9 ҞV- .}N&&61pxDssph4J2'O'Ir1yd`ltMh-4f`NV~N6 C^/UUU2rB$h]KYgy7ڰSw?#tuA:;; BD"须H$† az(Wߘii9ܓʴi?HEEʐ_j^6m>ejsYtL 瞻6tTT1rdV_VL6[aPUFcZPv^3g,`00}t<O}h42k֬SLчjASSWWOS̙iNvyhi'ïMs9)BytxbSO9T4)X,Fq#MMf{„=z***I0h#f͚'?IV^aҤIL0A_\j m7[So%r mةáPVf&Fv NETD䒭ʎGR F<+f'/`B0⢋+_6 ٺu+k֬I&1j( րޅdnߧ)SPUUojR__M75\ϦM&JVb|>ƍc̙KgNtfذaGE~:V7hGp&L/n:*++J`(]lt:M4zzz0 x< @@,U0=FtvvE8&/Қn7~`0p`0H$a"Ja(++ӷj  B PEy1|mHcf46 owI&ѿCtvvH$X,xނkΟyRubzKU4%][ushkU68ӕ4&r*LKH$/"u,L gBuu=dkOZhH$rC"v{菁IZNgok@ WdUbцl6\..KPKOUC&+#mi/Z~}$ F#v`}N'`Ӊ(< }Ղ6>d2'٦i=;#v_ q:APZeaZqݨ+G IDATu׵s;xY?[Tdfs-ƤI; jЛ-=Z%f4Zz?`ekr-6Mglb*e_Zr4shL&=Af * l ihAvZKK_@M` fl n}d8I N``+m\K/=`4fHmd2*E,#I|,v=Z.ʯ`5H ?b)xXL٭-e{q[U!+Ǒ+'[߶X,l6.ɓhujlG| 9Hd2Z߶?F$)hO&WUZ+{,L7kM 4zkF&YJˈ(rq:2}[ߺDjbq8l`}x< Iq3dJwR[LLց}HÔH`z Bgnҥ%ގ[#d¢@uE収&N4N~kZq:x<8D8gZ *& ůͯWo=f"acz&Nl*8ҊRͽK<җW^+רy 6y>-d*vLLOu:<oMo;r&kMpƏ/8JGGn0m@|Zڶ2pi}j}7i҂28]H NZMZ.6t0hKhZkE^2CyHxR>,8΂G2GA:<F#G^s׶Ͽ@ LÞ=?֑# xE}6ofe8-X_*tls3qGG\˟?Vm@])[v1P_v}}Q֭w LDxѺllasQt"fqJD'U&}-[ⴶ:_[oFDdgGk|O;SR[R)G70wv>+;WlFUUlOūbio'+@unL…mƄb@[ ڵ8xwTd6Qs'jKM?}s::wv;Q2^zϝKڵ[[uأQ{1c0۲3Ϥsׯ'nPȑ3/IQ/[HHc#Υ:|SF;vPkX 76|{?7ڵ{1c[Gdi2_xs*E̙t}6މ,--"}詩aC0lWp;ϧz T}_L ^{]sG=A' )o&9w8{nt~o/c˖mݡ~Xj9xbV&lݪ?zN~M\~9PL|qgsAO3O˜ׅ1b-_Nݺune?'gH-^ S`onfƦM ۵'Of3],5!H0~|Οp`iXK"YQX{m#``·^Ȇnpp =1'BOy9.{WȚL3^x?yD6̚^cڃbdȘL dyh+Vh0`?t]t3ϰ[9pEnʴ;51 9^OI?ʶnv>$o3{[f\Uz׎6Ӆ|)pOY*Νb~QpCNTU[K M3) `ڵ\<6r$&>8=~?/t)[2GQ?/g_]c7mbck͸ 2W\w@6zjklŌسvqF46o0,SBR)|k0/1OZ_O֭\X [lȰŋ;i F.W>U륽k+4W\AgYWfst߲)摲x_@Y**gõbٿMSn,[[X7c6hwߍ9繯~-F1aF>׿rƼy,63]?}:&L`ݴexwu8×~S8Ȫ*cA뛶Zx<΁nib.}y}'Y`m-uut/9sh|]jWUe֤IWPmPW_ŘɰsysT? ջvJ&qdL&BUUv>Pld3f`ZI one@Uy1$kk(IRXW}`23:i^/===z6z4Ǿað&tt0|rTW_́`i3z4mn7Hj0ӟƋ/yذvN'o9&0jj[soAqykhf1|쬯gψn8NMŦMܽFömDpuww^3}}9azI!׋w!.md ii Zk6ts$gc:_i +V0sn_p}]ȉ2n>[I0Q L<|ncUT m2ZB!^/ޅ7w-ij.ӧAEь[6oFw:Q}>Tg'?pfkZFnwP0ffaOQ "VhwqN1Jvt^UE˅l{Ob~?K˰f >`ȑ$n2p=#F`R\9`n0 G,F[0Rzd2a𶴀苉yz o(@L_oN F~vkSS{y_Z>6`@~1 XFjwU[_Z߲#Gb*QU?7ĘMh;00*MÆaVU<1͆0 C?}n6oyh" ޕ8q/ϞfWkx0( afnuܢP¸ `4uu zW 8Qbn7KMK --$nj`0rF˩kjIʭ;Dχ;硫j2A:kjȺ# Jwoˋ풨vS Q@b1luwu8 kn7s{2}e͡q*A|hE9jkw^US6lf͸n}5UhmS Yww7Jkۄ l?,B55~-.X;vH$vuxX;w.6ό˙f wœho'p'>Ay,AU ZPKI|a1oz½FzC!z<Lf 2lwgΤʟ̶ɓe\^OR XV'{n:ml1aM tWUqʕLھ<(=n7#*q{[v;v& v;mmm**hmldM u--ôTV2nNV+{c1zyޖHEe-rsU/HrJֆ/|A>>KWWhgoUNʁZ]}5 %^/,"U--xB!46حb,+MK`V6GnLEyMV Pli=3gp8p\#G x+(+/QXS?Oba r%kj2aHG.h;$1Ň_W]IU9kZƾ{ƌawc#*\.ϊ/~s:ʹ9s TW$^L,VZbTSmUU,ze==ϯJo}vĪq|oxzzca>YZ{SjkP󮫣<-8^~Æ ~ \!N!ZA2$ lY'}DxÛ͖;ySkv}Q Bs^Y,$DB?T*E"Cn,{UUbb1}ł B'NLŹX4ΦM>[ (f6o1~| EQ f ,VViVTTt:Ak*"L&rxpRJp`2Hl6b.|hVYk ٌ7aQ@m0p8qV+v1ͤzH3ӧ t_NGԂ#/K+f\c:) NG4Nc)SzXI&SfԨLa۴W -wWk#hO6Zy@:ekר#?Ecfou רzvɓzE?vޓbז_f$8]INXٺI,fdts:ɰaèi7c)g)QlY\7V~9ZАL&$h*W&H~z|;L:#?U!ǐ B"VZٳ9sXjUmV^_%\7T*}5\e]??w^xfΜ߮o%0ydٶm3g袋9s&wGxB B"V\ɹٳٵk̟?~|3W;v_d޼y,^1cpM7׿άY ʺ뮻;v,o&xWx7 \/ 8qv9s&_H$D[o˲eˈ1?UUyBS4qkmme͚5,\ŋxb~x|ݴ0f1ٳG?Jcc#6H$q~e H$ʕ+ygG0r#4ZZZ_J<^q2As6n<.ϟkO~믿͛b>s_2W\q۷o硇s zF5\ /?f~r7i&L&BaÆ A)BÒ!BD!BD!BD!BD!BD!BD!BD!BD!BD!BD!BD!BD!BD!BD!BD!BD!BD!BD!BD!BD!BD!BD!BD!B|O'`޼ytttPYYd  Nd2f/~.bTUUpw0k֬!E B,\Ayf/ڵkgy_ ,X'|Mƿt:K޿W_}˗}?v!8ҐH(J/6N|n~ŋxb.&Mŋ2e W\qSO=OxbPUUo3ԀA+w]q+Z~sG: z\xb.N}Y(PU655/n_~UVNYb!(qmi8xNsvᰅhD:[,Ng_"ImmrxqWSSf}ĉ@CC+Ws_X3 IDAT_jW^yq=s2wzLUU7o^{-G>\s |gqƠ{^~_0bmիiGB#Y.g ]]VH&3x٬bdHpLO#g3gsx[n}sE=hn==C=%\g>WlypB85ZG@Z~=oEOсncܹ%ݟv~_~zTUvs+l6K" o<T?O,]d2ɘ1c6lXIg0l߾k TUU|V> !D>d~~3y 鴁x޽.o;-['gŧ>)x&LMxG9묳رcG}~ ZyK:7ٳٱcg?sI6''? ?;r-vJ`jOaG7.ePS8g|tjkk{n?x h/~@WWl΂r?7te]ƅ^ȥ^7\ҹ555N1b餪;w tG'FQ,GhO!4,hP,/\ i?_|B&!{QLya$&fnx4`A߿+ٱ'ѣqpyq} Mnm9sXhK,a?_Oj;vzg*FT6sA"\4Cr!ťoļi_su+PBOf[=Ԓ%ADDv#0Z_y<D"aԩݻtJJJX~=^^^նΙ3^7$1H.^Xo/*~k7t&MJյйf.LRSSYYmcn^ɬYtqdTTQQQ!JujՊm۶uV***H3|RYYɄ xY`V Ə/1~x(,,X_|9GH$5j&L~E9rBRd=^WZHMM%,, `Y?Pp*>>7o"ɰ#00K{{{$ cƌa̙W_DEEӶm[VZ~a߾}ܹ"zUqƑƎ;ҥK̟?Gͅi.o|""""PoAVau"+˲ СO %%$'WpXZRA.uD"""""" F'0`HIv&=]{kDo[קT\b뿽SDDDDDDp7WsseFܺ#!DJEvv;**(C6%bK A*bn.qFjgWJZj5eee\XQ LuADDDDD0hhܸ1-Z k$M8vcq#_oQ|jJ+pp*!^ U*!\e4TVViGiiwNXYX$ """""" @kks5I=ؔak[\.llUQ77M6VBDDDDDDx rlllj?JlmW[P\\͛m0HXmCDDDDDD4l4ѬY34Ai%przHӦvJf/;VVz^_X\4oS j,-eh SY)AB ~FEǎpvnA&W """"""": Jm۶t zV:ɤY4nD*-A*-A")D"͏?V/t떋8 """""Ҁ{AFprrw+ xȽ4 [z.:.hb/½{MQ+).FZɽ{VpNN"=w\"`iiIvpskOXZ^9Eq=n9tzYnDrs֚OгQڷo̝͛;___5kIIIZ,-bbbmzł P?8|8}7nxj)JᅬBVMM?߆KHHOOO СCyWXx1%%%ZG6lk֬:<֏_ R[[[:vHǎ.l.>Iٸѕ}}1((hLZoM$>TV$ WKH.i޼y5Bĉqpp &&ӹsg~g-͛7[n4jH4ӧO_~:KMMӓzwfϞyN/o>\Š+ .wǎǡCbΜ9ȺuXj藺s碉Ԫ8q"DGG{nrrrjp SLaĉ9rjjuɯ__чSgM{~~~ٳe˖Ė-[HLLd޽u|gq v?X?"-ښaggG.]033C؈DÇ).@"Gs=UB +B`h@XZ0ݺ)СʹDdd$666,ZHѣW\yƒiハϳF*++Yt)o{68}&MXr%;Ν;~bN`` ӵkW""";v,̛7\B.]<ߵkWd2~ٓ&M4|...,[vڑɓ'U:YMI.]pssӪ{Q^^72 ԏȳ$]t\2?1%~!/,5o Rф'/HLZ֭С+-Z5P>|cjM 0P^^֭[(--͍`ڴiի???6mĽ{xw3f K,!66+++͛ǨQعs'j&O̖-[9r$dƍ3sLF/*>|pٝڵk177ښ<ڴiCXXp]JJ 7nDTpB FZZ&MW_}D\.'55U:LNN&++1cxㄇM&MpwwgZ״jՊʦM./i{`cc۷IOOg޼y֭[ȱcǰ|׮]o>|~̙3`ccSk޺c4 5ϖ-[_Rʕ+pjKKK EOcO]W_d2M6O>Ќ3z G ^?jxvInn.VVV̞=EL6/iѢvn}CP(&AG$ƔaYRi iEcmmC۶n`mm\LIh(,,ZٰaDDDмys6oԩS?$== <ҥK9{,+V_fٲe:u^{Mx&NHZZC Cٓ\|ׯĉ'СC@UGU>Ғx2e GfȐ!5޽%K7߰f^u:vș3gHMMѣXYվ6._Lvhٲes)))̝;k2tPnܸ[oUc>^^^VaCUG۶mqqq^+999dggyXr%'O‚@BGv 0Z7nHyy9qqqXXXp}-Z~~vСzRn޼)NBPODDZ7t0\\\8~8 , 66Vglz~ye2֘ӬY3Zlɭ[h葜<|؞v63тR=*ffYܠEllm"-[y4nX8<7W\\Ltt4}0Ϝ9;wرc駟ҤI^|E"""5k#F`̛7\Nqq1?#K, ggg~:aaabeeoS?uVqpp g2c ẂVX-< 11R j_^k^x{{жmj GGG >-Z0X]vq9H$󵰰кiӦÇsnnn±N8AZZtdg;w#G2|y|M<']=hӦM;vٳgjׇܹtVZŖ-[>Peh}5deeàAtH$ׯ_w fɟOƦij*T*o6l`ܸqdT1cmm )))*"Omqf.LkDJY077G.i ǙS?sѣB && .UE$/^4X/ŋδiի|W$%%QQQ+BOs֬Y\t 333*++޽;/ɉ[n C ,ȑ#:tHo"**3c ͛G߾}Qdee1a&OHm IDAT̻ktʹi5jSNk_9s0c ƍ׀R)"Wڻ(ށ)8s 4k JEQQǔ899_sU,YwӧO H!4<_#ɰeҥVggg3e򰲲bn$矓Bqq1fffnݚǛ@126ʄ6""DSDh qzBDDDDDDD/DADDDDDDD/DADDDDDDD/Dܼys닟f?/YŚˋ 4dpyjcWJ2̘cРA̘10n8Xd EEEZJ%{GPxzzV:!!ooozɰa0`GzYMNcGEEѻwofϞ]2|M[͑ц ѣG|r֭[2d#F`ƍghD-`" 'NOΝ駟hZ4oޜnݺpiOuxzzRPPPo.\ٳY|9^|EǕ+WXbر???8tVVV̙3G8ȺuXj藺sVQ(L2'rRSSЕFFFjj S$~~~7^xD?NǎYp!zڵM6N'Oǧe=/+t$} Yưk.?Ν;Yh.ꪟo}`""##aѢEXXX`nnN=~֢iCTTT 5,]z޽{I&\믿~B@rrrHOOGVرcquuܜyq\5˖-СC̝;rV<_~ƍT2_| Nߐ< wrra:uEQVVݻw".\{B^z+}y>qaTG0@Y^^Η_~?C͛^OOO,Yɓ'y뭷2d{`ɒ%xzz2`bbbعs'ۛ-[˖-9___z___!,g0999̟?!C0|pz-|}}9su)));A@ZZ^^^̙3W_}/// djpq&MĐ!C'?NV0`_hxL޾}tx[ёcǎaccCQWσ|&//M ԭP&9<<7x޽{ n5jx뭷:t(G&OիDGG '''xJKKڵkdgg Fʊ<*Ǎ:t(Ge 8PúǐA䯅h4B pqq 6DDD1uT޽;}Xf *JR>z(gΜ!55ՠz|2ڵqH<%%s2yd>͛I8A!]]]Oj۶-...BoooNA TEnS:w̤IG*2b9b~G틳3={ښ|֯_ψ#1b^#&00sssٳZ Xb 6|J jׯP㹈yבH$muttK]vq96l؀D"6m*잤.lll8s L2m۶tR:t(FSN;vH߾}Eid eҤIュ%F?_߿G7oT*޽{ӳgOM:жm[vލ/fƌhiiIaa!;wFP0g:uݻwMR>4| |  &@3dz EO8:: ݅ށT*Qxx`=zW^yET_~¼鑺x^5}<==5B>}P*XYYx.33N:iW[.pA  &M~ZҬY3gտjا"D"A"`nnYp! \~]{{8|0&Lٳn;wPXXHΝk7//Rɶm6lST ?_|駌3M/.aeeES PUK.%::\ƍGVVPeiF0,--&+}y>0}.iѢ^ Xʹoߞ]Նp답5gǎtRnpĐiqvv֭[5zkCdzanJǎ㚆޽{ZǕJe1j%xo{Mk׮ҤIDGGѣu^)mGƘ={0=gjѯ:ҥKiӦMgXNNN憫+H$ ݺun݊/?-[4z" đ1bk]\\033ƍ±BrrrzCܹp, 'NFnnVX>3Ν;ȑ#?>oAyhF\tѦMZwؑg`ݹszZ-[T8;; aРAF)Z4kiժCeT*Ņe}ޣgϞ̞=[XNNNB^^4dggP( ?C 7onP>ua-@4Lɓd̟?7oRZZӧ ‚qƱk.J%*0>|G~~>oFPzjyׄ󾾾g#:: _3$yIܹÞ={(..;A{..]vn֬Y믬^k׮q-Wcza(--et֍".\  Sw^)))axyyѥKA*>>Jrssٰa޸Iy&GթxxxJܹs߿_+srQBCCBPSaR}WR)W‚9s-[$;;[Xھ}{mi3g9HJEdd$76i4NcobKr= .^HQQL6^zQ^^W_}ERR,,5k.]̌Jwŋqrr֭[P 8rz)QQQDEET*###tT*JJJx!H$ƌ̙3Yvm!r6ȏ#G C"̨Q0a-ZV`j.]JRR 0ŋHgѢEYڹg_\.ӓuiEONtt4:tЫT ;HΝ;)**W^|XXXp%a`yy9yyy4o\V_z^?+駟_k&..UVQZZ˗/t~ԩS:_PT*0`aooÇ*Baaaddd`ff'%%h+::/Z͊+:t(cp uw^V\ɩS077O>!==ږqƑƎ;j]$+?#}7oܜ:0|\]]6m.\`f6mĕ+W ٳzOm;jDFs¬Ypppڸ|26mu`}gƌ̛7}Vb„ L},\P42*""Cix 믿F&akkҥKEfgg3e򰲲bn$矓Bqq1fffnݚǛ@126ʐO롈 """"""􄈈^F^F^F HHHOOO $]x1%%%OU<==k,y&s???f͚ERRҳK_xx8^^^,X%3tPBBBNsUyfذaߟݻ N>mp^Aֺ3_C<oョ^ьi;`سg˖-#))-[޽{MVNjj*zM֭A '@LL sOZ4-SӧO_~:… ̞=˗{_d߾}\r+V\]HLL$00GGGILLwza m?ß}0]v aMIm߂ҥ nnn\r婖ハS-S"##aѢEHUj=zy?J.][oeZC&MXr%;֨E,<-@4L&-//g֭|wFpp0mڴa˖-lٲ#G2p@6nHqq13gݝI& C*\.~ 絼)UƍdȐ!lܸR… 6lP1qʕ\pZ-ո}Ç;v` 0oDGG6m޽{3%KcԨQܹPj5'O~GrrrXv-?3X[[G6m KIIViii:>$''Ř1cj<qΦI&zjkZjŀ 5YoMsjxvInn.VVV̞=d8cOy:G%)((̌3foU >._RAll,XYY?CϚo[yƶOqz(--͛BD 6DDD1uT <<Ν;seoNPPݺu#33S`i=ʙ3gZm]ѷo_233ٽ{7K,O>YF޸q#q1֮]. )((3bb]}tޝ <ҥK2e +V 33e˖aoo:yĉ <5k_}>x"##cZq#j?}>\|vѲejRRR;w.'Ol޼Ǐטϟ7Yc]ºuHJJb,X;w-Kt駱CUFsN?Έ#ظq#jhtQm6vŢE?ԫ\}O._}1F4b֯_5ĉG&1sL>|H||<kkkY~=#F`ĈX[[DʷܜVXÆ #??R ݻw)**B" J}xHP,,,唔駟ҹsg&M-=R#F@yy?H߾}?9pYu՟)~:5ۛ_DB۶mk xHaa??uV eҤI‡KKKXӥ?1c裏h֬2^zQZZj(htQ///gǎҷo_@g?}M>]5}}ڈ&O?077'-- ڵk'\gaa#V~akk 8p2) քՄ:u*|򉰂^5h7J>www4iT(vtt$''"##IMMLJG+5ԧ~5ymD,[W^yA0հ!Ӈx:ıcXp![f۶m Thтk׮Tbؾ}{vJll,>>>B͓1fϞ-L/?]<Ʋl2._ڵkҥ )))̙3kE CHahBi_6S333nܸ!+,,$''Gkx[mm=,ժUT*x 6lq#F >>ƞI}{!wM8'HKK#77N:%>|g;w#G2|y|MЦMZwؑgݹsaӢŅ+h:twǏ'//Bv9rDs̟?gggx:>Wџ/\g}F^^/l޼gggtoCK_PT*0`aooÇu}vء]|h_ `֬Y888|:|26mu`}gƌ̛7}Vb„ LsRRR(..֭̌[3~g:|XVVFYYrܤ38qw~;|>Yt)AAA:tH_Rd˄ GƍG=Xv-/2C a@U=zat~~~ٳ1Ė-[HLLd޽H=2doUds>|w hh/(..fΝZ|||zfAHu""ϊ{Q^^72 Jii);TJ-x嗑u >K.q@ǎJXYY1rH._\A}G݈Q.kkk9u~57ϟT*Yr%.\@V nL-ZDZZ&M^W_}D\.'55-[eFٸq#̜9QF,_ɓ'ٴiwe̘1ƠAXv-C ATG\dzsNrssbUad#""%;;+++Z|{!22!CoqFJ% .dذaz_]zRݻw… ?EP(DDDl2|||}(//g֭|wFpp0mڴjz3f@*/ңGGCC<ϓСC'Zߟ0F|ED&Mʊy1j(vIhh(jjЃ1#j]>?~piҤ ^nܸQgKS#44 -[Ν;ᱍ7R^^N\\ǎcڵ$&&U Ϝ9# =z3g V@@tܙ˗/}v֭zUv͇~țoɊ+d[u  CBBXnIII̞= m6vŢE3(.۷/޽%KЧO֬Y#DU~]SuOuʯ~-ߘ}oooBBBu/෿.ׇ 6DDD1uT8u(""3gp |.fΜInn0U`*-q4:vڏ>{{{`ĉ $>>חz>yyyѤI:svvf_$dHY~=^*2b(//p႖g>~1k,_nDDD믿D"m۶xxx]ԭ ~8=р}mbii5n+ ***h׮pGGG~w#0QQQAaa!M6QPP@pp+3fpvڥ3_Z?g駟biiQQQzOIjj*>>>=zjM|嗨T*_ի6m_SYɘ1c%O[~@﷡FCP(9U]Ӈx:ıcXp![f۶mKii̬JfϞ]? V,kvV.MAW CY󴟏&|7ҥ $&&%51ao߮5Zfcc#Lh(,,k-[+3}tڷoO׮]LJXϟ_zT /ŋ9r$N2"˅51Ob.״KOх8=@(JN:oVBRoaύ74 o~~~8ܹs777yp^䳶ŅҌ\vM8aW%5|}~@ ̸qpڷoo2YXiӦV|!8;; J"//O|Cĉ˖-Vj͚cǎ={FG]}̛7ϟ?Ϸ~KgrǏ?"%r>ksDMri) #sX9cڜj#E#Z&r("":)owu)vszޯ>]z+=FÇhٲN/8n޼7|# 9߿ύ7HMMeXXX[oЬY3"&& 7uTڵkJBBVVVtЁ'NV_%'S~iJEί.+9MHHjnJ͚5ׯN⃪;?L2P}aX˗9t}aoo/kӲ_^M=unܸZÇ] /#DŽ 8w˗/\~N^,:l2{4 FFFѽ{wONՁ_鱴DP T*`ԨQ% 5 , 22Rz%gܹٳ 233ӓv)5-j+„  ~~~ 4CRN=*k.nZjڎoEv{GBB/&77+V~zغu+Nu7Iaa!-[Ojwss;wPV- رcl^ǎ;?144? klllصk>_~|l޼|lmm7oW"/vZ222033АիWӮ];n)((@PHu)񖀯/QQQDFFZf ǎ#''ZM2e ͛7w~~> (O#Sذa.\ZjT*_}9E]AAd  "*  "*  "*  "*  "*  "*  "*  "*  "*  "*  "*  "*  "*  "*  "*  "*  "*  "*  "*  "*  "*  "*  "*  "* :#]tݝ=z0x`N}>iiiZAAAXXXTj ¿4 cmm۱OJwqq֭[Jח 3ZpuugϞT*?~,ɟqqq_~ 6 777Ə/k ذa"bިT*vANTtLpe?~5wӳA^  ,{BAYDAAYDAAY"TTpp0;vΝ;ԭ[R {),,Ϗ;wT*j5 6??BBBx!;wfΜ9rA^(QiÇ^c̘1|җa4:t "" &`mm… JŌ3 `۶m!}rbccy1c֬Y9rjժl_i߾=U} EMK.%!!F =z`Ze>L~~>ZϏƍn:v܉ dݺuddd0k,Y3uaffVc-7pӦM5j+++;&* c!ʕ+KMOHH 22Rj4._L`` ǏCCCٴiDFF2i$|}}y&3gOOO u[ڏC)uݺu((( ,,cǎr],]HvADDZb̘1ッ޽ӵkWVX!2Z,‚I\D=wwwCδiӸtN˾t 4m2j("#hذ!PM`bb‰'Ãp %!!Yeߺu zzzk׎#Fʛ˞={>|8(JƏOVVCCCPUmpwwji^s=bccW^%J3fRRRpuueΜ9DEE#+ojj*4mTZfddUJ<*ǔ]byvv6k׮AE]v]v:tcǎ1k,5jĶmۤ/.[ի۷iݺ<##CvK @4TomРV155aÆĔ㏜?{fٲej ڵkٻw/W^ĉZ6l}}}^*-&==f͚ɎAHMM-S 5[&>>^Zv5qvv~a P233rJ=j(RRR`ԩDEEkHMM%44)Oq뇟+SyOfhx! bi&$$ j5[nf͚e&O'< 1crXf /ZAErY mƖ-[(,,Zj`>?fС___233 yidgg+5/^X먎aaa,[|ŋ0a?3lݺ/O>}z_󾾾DEEY[LZZZP(b񄄄pARRRP*XXX0j(imm ظq#ҲeKhҤ ˖-c߾}( 4hC?N:=zH]-dffbnn.u<7ϟg׮]tСL;N)?4  x! !* ssAAAAdAAdAAdAAdJ* ggg\]]ٳ's%//(xJ/$зo_w;+Vx!T6F_| >_~:waܹxzzү_?fΜYbIm ARX}9}4lڴR߰avvvϝaIT*nܸ!og_E߾}Yj y뇋 [NT`QTₛUS{}T=Qi}^hl޼[@rƢRx3۷/?#w.eٶmӓ)SHw2|pLLLسgw&==k׮ھI;UBB&Mb|RG}ui߾=Oviӆ$,Y";6BBB&88#G0{l:rY`=GÃ%Kp-CҮMNU߿4T^{VZTie޾}Q*^iH?3:GPУG}6_}JٳgcddD͚5ҥ 5jԐ}?S{=UV}x1 ,`ذaOYDPPP&QK.e߾};wNq%$$`kk+(jgglzZ&%%C)"Gex'*T*1667o}G8;;"3yd|Mqttwڕ0n8@Q Օ?P@ڼy3* JŢEߖHݻ7Օ(ի%ۻM[[[7ޠW^@/HiH#GШQ#4hӧzz)))g`>[F#͠~z'66V?w^vA||LR;vS-?k?_lݺAI_me=Rッ޽ӵkWVX!=R~~_Z|3gOOO u [*˚5k055xyy1sLj׮RΎ|rssuϞ={>|8(JƏOVVښ.]`jjYf xxx`jj ٌ=RSSX`Ce֬Yx{{l۶ i}Z-U\Kt ) lRuܽ{Wkr?Æ #$${z~T*tl)ϗK|ysNbccqrr"**^zT*uz D-Z={+ٳgYr%111RW_4}}}rrrJKxx8WFOOm;fҤI۪[ԴǏ'-- ww1M07xk7kkk_^e]~~>fffeΧsԴ ;۷lقǏI&IWZ5 uϓ[J+,Yp!ݻwg<)MU|~h|+)O͚5_899qi{]:='ڵCOO޿Lnذ!%&==f͚U,IKK#55/ >Sz-|}}Yz5kAAիWֵ‚l ݺu/v֭E[~OOO8_-344dҥ̛7O5nWVOz7oޤUVȽn޼IݺupyI&###155aÆ<7֭9usp ʒ.˃r/իSfM޿r~~肶7m*9<ݓ7{LT!֭Kbb)n򋋋͛|71&$$ j5[nf͚O1yd<==رc\|ѣGE=#77 :u͛w233quu`ԨQ>|h4 'O$))o*('֭[X[[3c :v(-[JƲuV.^>:t`үSNa.\@jPTc``ݻw1c.]OOO&NHZ)[|'8pciiI~~>FFF 2ȑ#ɣ^ǏLFF#lmmy4?ˮ*oe?k,nݺŃظqc4^D!!!|t1M0ZͣGx!_u_-mHJJb͚5ݛCGNNNƍ+1ki7%Kњ~V\GBJrAYj۷ogر:?!!ʱj*6òS7ofe0Tehժ3'zQٓիWm6,X'Y9/~iǷ2TFVz+/?Zg7ݲe ۶m߯py6ΝcҥL4Dĉܹ)Sn:i8H7e޴iS֬YCrrN'7- ܹskԬY@ RxaggWaТE 4iRV>zUlذ}1hػw/}q9?z>߇% bҨҡh>ɓ'GѧO7o^}7Jbll,]ojj4g}Ftt4ƌ9سg/Lnʹsh4ѹsgƎ˕+W={6?CPϗ_~ ݘǏ',,{allñcƌܻw{/cǒFhh(}Q?K݋o?=zpP4sV&&&deeQ~}lllݻ7vvvϐ!Cpqq)V[|r_yQF ٣5BkbccyM4LJB0}ҪU+N*kښK_#KPݻh222Ͳ_rs9Q*xyy=5Go&oooimm'Ǚ3gHOO*[nqUF)-Wu!>>p~'?~G}D^8uWۻz*NO>yf[YYakk˞={3gNU * d_L:1c(}ot <<L'գGy&...tIkAAA>}ŋcffFHHcƍ:9gΜaŊL>nݺq fΜ)h;vV~i~-bʔ)4jԈD>3oQZ5V\1AAA|W0+%%pFٳgٲe 6664jHkοŋX[[K]ŊJ]vkΝ;L<]/=+ոqc5jĢEy, 93oߞݻwhF*4Tkkk>Xn .n===8~4g|^^IIIT*޽K^^ ===Zj5 {+++ȈӧOcddDnn.y椥1b5kݻw+FFFɓiݺ5ݻwÇܻw߿3` 077ٙ? Rn]^uLLLx~~~ '''o E^^vggg(J ÇݻN:Bښ6mڔyߞ_G_߿бcG<]]]3f (JڵkǣGJ򘟟ԩSر#&&&i-[\~]RFR=ok׮%33 60qDjԨQ"υ qFʒPNrssdPWĉqwwgL>UVaee{%!!;;;ҥԄ9p@>3ƍG.]ppp`РA"33oH5 333ׯObb"|mJtxQ/>FO_*JK.tҥ|;7Ο\7nȈ֭[|~ =++WիWN:\vMkڎ/}YYPp2󤥥Ɋ׏n߾Mnnnsi{jZDJ%h;?{QV<5unnnJѣ?>}:^^^Ϝ]rݸ?I[a8;;"U^777DV7`llL'fҥKl۶k׮?P{@h/yԩC֭9}4jgronndÇuiiil߾ڵkӭ[7YvuP\ݻwpB իWg׮]oߞ-ZE_ׯ_gҹsgV^]JBі^,..ۗy^bjlu "9/]DRRܼy5jĨQhܸ1RS'|?̖-[J>>˗Uyoذ!9%bbܹ$$$~( ڵkP(puueȐ!w]4?#AAAdffbbbf͒85B+~' iܸ1>>>%? իӶm[|}}m_--[ʺ~J|9WiҤ:wLݙ?>kf.ܹsEFԩԭ[-ZDbb"Pq+QQQҫW/ywx78}t׮]+cpy͛G߾}ѣ΄*6l <J% y[888еkWbcc˗/GR1|6l...|吻bffFf7n… %&iԨVVV;v\e <4T"##Kk߿?۷oƆg۷'99w}x9u&}ѫW/zűc077qƜؼysrssIOO'11޽{sKL$77Wvw%##m۶WVs;r||ִnݚ'v8;;0AxEJ+yҸqcjԨABB4@PݺuILL$??֭[WO:(v>>yd<==믿do;''cjj*-nݺ%ޢ>7n 55˗cii[o%;]WQ9> 1crXf O+P{$&&Kff&+;H<9"a ///jԨAPPP;wAq]HNN9s PTiPt BANr>o<>cC>ˋaÆZ> 7nd֭|ӡC:uTpB.\;v,ӧO'33ݻw3}tN>Ͱax1رCz| ?~ !X<qc[4NNN~~~`ggŋT FZW0aueJA  "* ?ަMHHHȑ#?5̲tAA=! ,AAYDAAYDAAYDO~pqqf7o߾%++CT3WWWό38_۷coouCCCQT߽*ӧquueӦM@у888}vy7pss#88޽{RpuuwwwHJJ"11wwwi}?ӽ{wlmmuN< _E߾}YjUF{- [>CRSS^HH*2۷O~ϟONNLۯH&PIBBB&88#G0{l:TaLpp0;v`͚5۷cccƎ+ F$Gll,*_k,XbΝ\r wcǎ[n577}ϝEyU&Mŋԩ...d3gΤsرÇ'_HCСC"""ԩnnnR={rCBB`ԨQXYYIiӆ$,YR{TF9z(O}! ((HLnzDD,[{ԩSehѣG۷]vq̙ch~EJ4#]G;lٲ> ```̙3q^|=z4ݻwGOO:uЩS#R  ¢|UǏ` &}YWD144|n~ QK.e߾};w355eѢE:tS~{Y;v0dZl!ӦM#>>$]r~ J%ua֬Y8p[ni~EJRfMΜ9Cff&X'::#F₧'s`ͨT*T*-"::~777i0 +&::Zvi֭CRKLL C ٙYCVV={UV ¤s???)Ej&?<Ҭo&8::|rT*'..aÆ·~ P?ۻԦg9}4X>o4'Nڵkxyy)|h&&&̘1LlР=z Ih֬!OIb̙Ԯ]R?(u999( h׮#FQ+WPn mcѸg:twwwMƥKUܽ{"]vaggݻ'K-xyy1g222X` ,7oζm;8!BPcP^D\Ѡr\SsI k/\n \Lp5oh*;^Rf2"_̍æ%s| ׯ|r7}%?M$ix;w.6m _^hٲ~,tR^333{Yjk׮jqqq?mLC2iҤ2ceeE ď?X7,\\\HHHRyuu [[[>D?_~y Ku޽{tZhQۿy&iiiolٲE:H`` KWpBZ-}elٲWyƇ!7/t钾Z-jZ- y嗹u?e\|]vغu+;v4xǁZʕ+WjϞ=ec}Y311;;;*1cSPPW_}Eǎs ˗=z4 {̘1CRSSIIIAr!"""x0333}%?M)/‰'ؽ{7XXXЬY3NZMdժU?sssXt)6m"22Zuʜbj777Yr%ܹ` 5jp]QT 4u!::XRSS155ΎQFaL\nGݹs'k֬vڵk)..\H0tPzʹiʌ !CPh g}VΑ'O2vX6mT휥͊bL:ZA˦c\r[nQ^= Tf.(Сfʊ`СC;RSSZÇsm\]]9r$eQ?-$i &L̯=M͛7y0`cƌ{ 'Ofܸq „ܠA$a3 7|)cܹOլ姽|8s~  p֭JmAnݚ:uy}׮]3gΜ =r^^^VՌPcǎk׮ժwѢE1f숋#..N<(61|pa˖-QÇ듵oFw=z`̙бcGˆ sC Ν; >???ڶmK~ˋO>???6l@>}رcvnݺLx3y "##oΝ;dž 8q1n8 Fpp0֭GׯXv-w聆-Z0c 7n ={x701_޽{wwnt5kְfh4%.NGll,QQQܾ}u2i$|}}_Ey lllѣsrrXjT*˖-+ eff`kk[9P 222 e<;N:YfҥeVr"-[$))+Vo>% yoߞ$Faܸqlh|Jx"7ndΜ9tܙŋj+DԩCTT `t:AAAt`|˗/'>>hѢcƌ!??C넇ӧY~=AAAnݚ/jtR4iӦM#==JUҰal2Fe͛&Nǎ;puu5'B?IjX@@{'>pqssҥKhZ;իW9u/_iӦ5VOnn. ,rrrʪ2h >#ׯ):tF5ƧhشiÇSSSƏݻwΝ;@ߪ̋/ 999|W :իW3b/>|R0zhٶme֭F˜M)Ott4?˗//s6B''j؎;cҥDGG2 FCFF)))ꫜ8qgggj///9s9tjܹ̇Cqq1M4/kee#.]_/OZZk׮|||!;;,cZ-ٕoggggt;w9舷7K,]vK3NHHH&Bǃ$ A̛7nݺm6ƎPtZ~rYJJJfΝh4ڴiS? ~)Ofɒ%jՊs%*‚{˗/tI*} oEnjtɓ'ĬYX~} ,_k/k !,ryXZZRn]޽ `)?@JJJYz*ok֬۶m+m۶%%%_RZÐH`` Tj. fff\zUZ^^  663'J7ǬĩSؼyseYYY=z}y‚ŋsyV^,\5kH LZ鈋CV뿩7mڔ3gp]زeK[zJ=11t6o\i򸹹qAigyd5jPmPXXHjj*׵bDGGV%44uk0rHLMM>gU IDAT:u*r1BBBoϾ}Xz5׮]#--p+W<7f͚1uT"""8~8L6֭[Orr_ZZZB<~T'O|%,[۷=XYY1p@ƎJ";;?K.M`` 'N^z8p[QT 4QFѷo ǏOVΝK||> BBB *!C0k,W IB!B!PD!B("IB!A!H BE$iB!"4!BIB$ B!PD!B("IB!A!H BE$iB!"4!BIB$ B!PD!B("IB!A!H BE$iB!"4!BIB$ 5 %%:vH.]ߟ޽{{ō7ӧݺuߟŋpӱcGMHꏊW_ˋ^z.]pEa[nkṈc*ϰaˋ4׏.]\˗Ӿ}{Z:0gΜJZYr|<$iѶm[#..M6=; 4uԩS2|ٸq#(ȑ#xyy[2i;v,]v}DQYl|ѣ&..QF_SN'::+V(^~t֍mrmxwiҤ{=ڵkW8Q$333UV:NJ/UZ733"155֖;wl: baaQar;99g=ʜ9s%33GGG]Yr|<$iE|vZvMaa!-Z`ƌ4nܘ5kְfh4Əπ 3x`n߾/9s&iiiDDD駟[u:DEEqm֭ˤI~~~hZ {.Ǐ`֭[G=ׯdee1}tܹ37'V^Mվ7sαaN8Ann.fff7aÆq9FAII * sss9bƇ,>stX[[ӽ{wfΜ `tWg|(R 嶿:W{w nǿ!JV%""۷sM֭kty&p._oYbocРAb06 JƇ?===}%KЪU+}:5",,L?]U{s֭ks@qrr"!!-Zмys.\JɩWXXe I?q"'̸z<222hڴc_ ...$$$fU0711@<<<011)w.Ai⑓Smd7o$--g .\Vo߾,_-[pU>ltj=y)6o\;| .TjNNN:t͛Z8::VrssIOOE74h|T&$ix|VO?TÆ y&͛7ĄMh_NN7n --EaggGϞ=ol|)ah|(U=>N<;IIIaڴijLLL%((!C)**믿&>>b7oΌ3puu%222[ho6|gh4/^̊+8s 5R#G … ԩS}-UT* DVV[nER1c  СC9{,={Ϗ"n߾MzSmڴaҥ_%Qոʕ+qvvVNcܹo)={6u1…FT-e7oV-`Pll,bggǨQ T3> ߆  5ol|vZ177-))aС?dj5yyyh4g}޽{ߴ4f͚EVVݻwϏ `ȿo>s=1ϟ/To„ _]v̞=[cah|^QꓤA'Hnn.>>>>|X?iM!j\ f $ VB"##ԩ&M?*1~oN>}֭,^LyLL ^^^ܸqu(O!!4ԀcҵkW9r///rssT^ٳgCRYtt1J{k׮9r$G6Oaa!ϧO>>>k*c+(:t耷g~gȁ1b=z 00Yf)o޽^zo>֯_x?%Oӱc|MzlsQ7;ұcG?vˋxyy1mڴrO0>> O$ 5ŋlܸ9sйsg/^Ve˖$%%Oy۷$9`|ʔ)k׎ .3w\z-,Xŋ+ݻiҤ Hi߾=IIIFøqhٲeˍy ݝӧO~zhݺ˗/'>>hѢcƌ!??09s&;v`ʔ)e;v~,YRC?YpƍL2~c+=;;;ZjΝ;/P! 9={r2ʆ9r$;v oooBBB~:mڴ)܋R?J_LL !!!,]x&MĴiHOOѣ4EDDDRR>ܵk; K.`||jOIjPnn. ,rrrʪv077yΈ#W?CeWX_Rt:~K*͍K.j9vW^ԩS\|MVggg^|Elll᫯" lllh4lڴÇcoo)ǏݻRTTĆ 5j]tWW2uܺu|T*&&&xxx0bĈ2pB:wĉ~0Z۾};[l!$$D$7{FR`cѸɓyuVz?NcՌ1ekkJ=:"XXXTx|*'D4 ///ի15vyLLLptt$##2ƞ:O?Wuh4ddd«ʉ'pvvͭѵkW}ùs(..I&嬬pttҥKg1c{IPPPe<<FVdJ!͚5O>̝;ƍtS~ܜ*V8hc4i R|աd|JxJxsrrT{w%==-Zy͛{#--Ǐ')-WT4k֌m۶׿mے¯JӦM]4`ffիW呑AӦMqtt .… jۗ˗e^Z\}X;L4JWQlْ܄2bl|U*^MQ2>I"ICT011t6oތFQ\Í7HKKcѢEӳg2uL<@~ꏎo߾>6P]v4nܘgyd5jT#J⯈&::,Z-ԭ[^{ GGG<==9|0Z~I?ٶmt:~7vvvhĄEaeeɓ_I|o„ /,Z˗/su; +!Ɨ!>c\v4bbbHNN*KO'\?ARÀ?>G0oѢ|嗬]ݻӷo_v?~7|ڵkGDDDו˓U VK۶mQTmۖ+WO-WܐH"##Q՜}޽;>AAAٳm6VZ)vvv|駴nZǡC8t GFFrt:Ջ#FggH6m eժU >sss T_vv6;vϏ('N0:~=z_?Om۶[*Q:uhӦ K.՗kZ T* DVV0v|P*~zRRR/T.!Oy'Rry)PRR¿ o3V.!Oy'DeoQ! a׮]\rf͚=0Ly=-'}<2B!B!PD!B("IB!A!H BE$iB!"4!BIB$ B!PD!B("IB!A!H BE$iB!"4!BIB$ B!PD!B("IB!1{iQ BTݞiB!"4Ԁ(lmmSM4~xxxwGڟK/Jz|||xg+pT*W\y,B?3IjÙ8q"Zʕ+dffɐ!Cwڵ Jŝ;wj1ڪϟݻWj[t 2>!31dn߾MZZڣO+?R*}rQ6lXX|Bg&IC-WWWt:o<<<U,-- KKKlmmXp! :T O'T*T*cǎWWWÙ9s&*AsN<==qpp ::ZQ[p=-Z₿?ϟW_>>>>}t޽{z-6mJqpp`ŊrWWW\\\hР*b}Yuۯ$>CXB<.$ia:gϲtR̙T˜;w.7oڵk,\7xWҦM ؾ};ٳѣGz6oެѣٿ?ڵ㧟~bٲe̞=N:?3k,zř3gYv-={dҤImO͛9x W\ӓݻo)ӡCكNe>ك%IIIdff2rHfΜNի\v]+5V+ IjЙ3gpqqUVmۖiӦy믿-ծI&R~}n߾͖-[9r$#GA3ϠVY~=]t7$;;7oVc_!IjPV~:易Ln޼ɂ hҤ_II 5C޽ 00s˼eNNNh4jyExY[[™3goW^ٳ;wҧOʗ.]JhҤ cƌtmE)ݿBHP >233ٰa|\rE/;;y=~)㫩x;vHAA+V߿Lرcٰa_5/^dݺu5RgMW+V4ԂM2x`-[FII ͍8~Z;11fV5k9Νӿ˵kpwwW}sss^ylmmiҤIkIDATxz-:v숩)Z S yB#IC-裏8<[n/`˖-̛7K.qEHHHЯSz`||0Hy 6lׯgϞ?ڵ>SNQN:w̲est:cƌoƆ^{,,,u_~ϏzK?a֬Y'33SSS4hÇiڴ)T*V\رci׮8::*g({1g[`ŊlvuƉ'HLL, 6$''|7nYYYٳiҤ /_ՕQ8;;R0aj +Vy/BGM?{BUB!U[n=BZ'IC pppx!!N!B("IB!1{D!H4!BIB$ B!PD!B("IB!A!H BE$iB!"4!BIB$ B!PD!B("IB!A!H BE$iB!"4!BoOa IENDB`refind-0.11.4/docs/refind/getting.html0000664000175000017500000004342213372347051020052 0ustar rodsmithrodsmith The rEFInd Boot Manager: Getting rEFInd

The rEFInd Boot Manager:
Getting rEFInd

by Roderick W. Smith, rodsmith@rodsbooks.com

Originally written: 3/14/2012; last Web page update: 11/12/2018, referencing rEFInd 0.11.4

This Web page is provided free of charge and with no annoying outside ads; however, I did take time to prepare it, and Web hosting does cost money. If you find this Web page useful, please consider making a small donation to help keep this site up and running. Thanks!

Donate $1.00 Donate $2.50 Donate $5.00 Donate $10.00 Donate $20.00 Donate another value

This page is part of the documentation for the rEFInd boot manager. If a Web search has brought you here, you may want to start at the main page.


Note: I consider rEFInd to be beta-quality software! I'm discovering bugs (old and new) and fixing them every few days. That said, rEFInd is a usable program in its current form on many systems. If you have problems, feel free to drop me a line.

Getting rEFInd from Sourceforge

You can find the rEFInd source code and binary packages at its SourceForge page. Note that rEFInd is OS-independent—it runs before the OS, so you download the same binary package for any OS. You can obtain rEFInd in several different forms:

  • A binary zip file—Download this if you want to install rEFInd and/or its filesystem drivers on an x86, x86-64, or ARM64 computer and have no need to test rEFInd first by booting it on an optical disc. This zip file package includes x86 (aka IA32), x86-64 (aka x64, AMD64, or EM64T), and ARM64 (aka AARCH64 or AA64) versions of rEFInd. Which you install depends on your architecture, as described on the Installing rEFInd page. Some users of Arch Linux have reported problems booting some specific Arch Linux kernels with rEFInd and some other tools. For them, a variant package exists in which the x86-64 binary was compiled with GNU-EFI rather than the usual TianoCore EDK2. This change helps some users with this problem.
  • A binary RPM file—If you use an RPM-based x86-64 Linux system such as Fedora or openSUSE, you can install the binary RPM package rather than use the binary zip file. (I don't provide equivalent 32-bit [x86] or ARM64 packages.) This package runs the refind-install script (described on the Installing rEFInd page) as part of the installation process. Distribution maintainers can examine the refind.spec file in the source package and tweak it to their needs. The source RPM file might or might not build on your system as-is; it relies on assumptions about the locations of the GNU-EFI development files.
  • A binary Debian package—If you use an x86-64 version of Debian, Ubuntu, Mint, or another Debian-based distribution, you can install from this package, which was converted from the binary RPM package using alien. Note that an Ubuntu PPA is available, which may install more smoothly and will cause rEFInd to automatically update with other packages.
  • A CD-R image file—This download contains the same files as the binary zip file, but you can burn it to a CD-R to test rEFInd (and its filesystem drivers) without installing it first. (It boots on UEFI PCs, but fails on some older Macs.) If you like it, you can then copy the files from the CD-R to your hard disk. The files are named in such a way that the disc should boot on either 64-bit (x86-64) or 32-bit (x86) EFI computers. I've included an open source EFI shell program on this disc that's not included in the binary zip file, so that you can access an EFI shell from a bootable disc even if you don't have an EFI shell available from your regular hard disk. This can be an extremely valuable diagnostic tool if you know how to use an EFI shell.
  • A USB flash drive image file—Although you can create your own rEFInd USB flash drive, you may find it easier to download this version and copy it to your USB drive with dd or some other low-level disk copying utility.
  • A source code tarball—This is useful if you want to compile the software locally. Note that I use Linux with the TianoCore EFI Development Kit 2 (EDK2) to build my binary packages (above), although the GNU-EFI development tools are also supported, and are used in building the Ubuntu PPA.
  • Source code via git—If you want to peruse the source code in your Web browser or get the very latest version (including pre-release bug fixes and updates), you can use the GitHub git repository. This access method is most useful to programmers, or at least to those who are familiar with programming tools. If you need to ask "what's git?", this is probably not the best way for you to obtain rEFInd.

If you're using a platform other than x86 or x86-64, you can give rEFInd a try; however, you'll need to build it from source code yourself or track down a binary from another source. (Perhaps by the time you read this it will be included in Linux distributions built for unusual CPUs.)

To extract the files from the zip file images I've provided, you'll need a tool such as unzip, which is included with Linux and Mac OS X. Numerous Windows utilities also support this format, such as PKZIP and 7-Zip. The source files come in tarball format, for which a tool such as the Unix/Linux tar utility is appropriate.

You should be able to create a bootable USB flash drive from either the binary zip file or the CD-R image file; just treat the flash drive as if it were a hard disk and install rEFInd as described on the installation page. Using the fallback boot loader name of EFI/boot/bootx64.efi is likely to be the most useful way to install rEFInd to a removable medium.

Getting rEFInd from Your OS's Repositories

I know of a small number of pre-packaged versions of rEFInd, either in official OS repositories or in ancillary repositories:

  • Debian—Debian added rEFInd 0.10.3 to its "sid" (unstable") repository in June of 2016. Because most people don't use this "bleeding-edge" version of the distribution, it is not yet a practical option for most users; but it is on the way. You can download and install it as a separate package here. Debian's inclusion of rEFInd means that derivative distributions, such as Ubuntu and Mint, will eventually receive rEFInd packages, too. Be aware that Debian's package is not signed with a Secure Boot key, although if the sbsigntool package is installed, the installation scripts will generate and use their own Secure Boot keys and sign the binary with them.
  • Ubuntu—Two Ubuntu-specific methods of installing rEFInd in this distribution exist:
  • Arch Linux—You can obtain rEFInd from the Arch repositories, in both a stable version (the refind-efi package installable via pacman) and an experimental release built from rEFInd's git repository in the Arch User Repository (AUR), under the name refind-efi-git. The git release is likely to include pre-release bug fixes and new features, but those features may be poorly tested or undocumented.
  • ALT Linux—This RPM-based distribution uses rEFInd by default on EFI-based computers. If I understand correctly, ALT's optical disc installer boots with a combination of rEFInd and ELILO. The distribution provides an RPM of rEFInd; see this page for details.
  • Gentoo Linux—An official ebuild of rEFInd is available; see here for details and here for Gentoo's official rEFInd documentation. Because Gentoo packages are compiled locally, there is no version that's pre-signed with Secure Boot keys; but as with any rEFInd binary, you can sign it yourself, and the installer script should do so automatically if sbsign is available.
  • Slackware—As far as I know, an official rEFInd package is not available as part of Slackware; however, a Slackware package from SlackBuilds is available.
  • Fat Dog—This variant of Puppy Linux uses a combination of rEFInd and GRUB 2 to boot its installation medium in EFI mode and provides a rEFInd package in its repository set.
  • The Nix Packages collection—This site creates packages for a number of OSes using its own packaging system.

If you hear of rEFInd being included in another OS's official package set, feel free to drop me a line.


copyright © 2012–2018 by Roderick W. Smith

This document is licensed under the terms of the GNU Free Documentation License (FDL), version 1.3.

If you have problems with or comments about this Web page, please e-mail me at rodsmith@rodsbooks.com. Thanks.

Go to the main rEFInd page

Learn how to install rEFInd

Return to my main Web page.

refind-0.11.4/docs/refind/mvrefind.html0000664000175000017500000001120013372357235020215 0ustar rodsmithrodsmithContent-type: text/html; charset=UTF-8 Man page of MVREFIND

MVREFIND

Section: rEFInd Manual (8)
Updated: 0.11.4
Index Return to Main Contents
 

NAME

mvrefind - Move a rEFInd installation from one location to another  

SYNOPSIS

mvrefind SOURCE DEST

 

DESCRIPTION

Move a rEFInd installation from SOURCE to DEST, where both SOURCE and DEST are directories on the EFI System Partition (ESP), with SOURCE containing a working rEFInd installation. This operation entails taking several actions:

*
Renaming the SOURCE directory to DEST.

*
Renaming the rEFInd binary to a suitable value given the new destination. For instance, if DEST is EFI/BOOT on the EFI System Partition (ESP), the rEFInd binary should be bootx64.efi (or something similar but with a different architecture code).

*
Altering the computer's NVRAM entries to point to rEFInd at its new location.

*
If Shim is detected, renaming operations and NVRAM entry pointers are adjusted appropriately.

*
If the DEST exists, its contents are preserved.

Broadly speaking, mvrefind understands three types of locations for both SOURCE and DEST, relative to the root of the ESP:

*
EFI/BOOT -- The bootx64.efi (or similar for other architectures) filename in this location is the "fallback filename," which is used by removable boot media and as a boot loader of last resort on hard disks. Some EFIs can't remember their normal boot entries, and on them, rEFInd must be installed here (or as the Windows boot loader). When this directory is the DEST and it already exists, the existing EFI/BOOT is backed up to EFI/BOOT-rEFIndBackup; and if the SOURCE is EFI/BOOT and EFI/BOOT-rEFIndBackup exists, it is renamed to EFI/BOOT after rEFInd is moved to its destination.

*
EFI/Microsoft/boot -- The bootmgfw.efi file in this location normally holds the Windows boot loader. Machines with broken EFIs may refuse to accept or remember proper boot entries and will instead boot this entry in preference to all others. In such cases, using rEFInd requires moving the Microsoft boot loader elsewhere and replacing it with rEFInd. When this directory is the DEST, mvrefind moves the original bootmgfw.efi file down one level (to EFI/Microsoft) and stores refind_x64.efi (or Shim) in that location. When moving from EFI/Microsoft/boot, this process is reversed.

*
Anything else -- Any other SOURCE or DEST location is treated as a regular rEFInd installation, with a proper NVRAM entry created by efibootmgr.

mvrefind attempts to identify the ESP and refuses to move between the ESP and any other partition. When it does move files, it moves the main rEFInd binary, the refind.conf file, any identified Shim binary, and the icons, icons-backup, drivers_*, and keys subdirectories. If other rEFInd files or directories are present in SOURCE (such as a custom theme/icons directory), they will not be moved. If SOURCE is empty after the specified files and subdirectories are moved, SOURCE will be deleted.

 

AUTHORS

Primary author: Roderick W. Smith (rodsmith@rodsbooks.com)

 

SEE ALSO

mkrlconf (8), refind-install (8)

http://www.rodsbooks.com/refind/

 

AVAILABILITY

The mvrefind command is part of the rEFInd package and is available from Roderick W. Smith.


 

Index

NAME
SYNOPSIS
DESCRIPTION
AUTHORS
SEE ALSO
AVAILABILITY

This document was created by man2html, using the manual pages.
Time: 20:12:13 GMT, November 12, 2018 refind-0.11.4/docs/refind/refind-install.html0000664000175000017500000003622313372357235021332 0ustar rodsmithrodsmithContent-type: text/html; charset=UTF-8 Man page of REFIND-INSTALL

REFIND-INSTALL

Section: rEFInd Manual (8)
Updated: 0.11.4
Index Return to Main Contents
 

NAME

refind-install - Install rEFInd to the ESP and create an NVRAM entry  

SYNOPSIS

refind-install [--notesp | --usedefault device-file | --root mount-point | --ownhfs device-file ] [--keepname] [--nodrivers | --alldrivers] [--shim shim-filename] [--localkeys] [--encryptkeys] [--yes]

 

DESCRIPTION

To be useful, the rEFInd boot manager must be installed to the computer's EFI System Partition (ESP) or other EFI-accessible location. In most cases, an NVRAM entry describing rEFInd's location must also be created. These steps can be performed manually; however, the refind-install command provides an automated way to perform these tasks under both Linux and OS X. The exact behavior and options vary depending on the OS, however.

Some details that can affect how the script runs include the following:

*
If you run the script as an ordinary user, it attempts to acquire root privileges by using the sudo command. This works on Mac OS X and some Linux installations (such as under Ubuntu or if you've added yourself to the sudo users list), but on some Linux installations this will fail. On such systems, you should run refind-install as root.

*
Under OS X, you can run the script with a mouse by opening a Terminal session and then dragging-and-dropping the refind-install file to the Terminal window. You'll need to press the Return or Enter key to run the script.

*
If you're using OS X 10.7's Whole Disk Encryption (WDE) feature, or the loogical volumes feature in OS X 10.10, you must install rEFInd to the ESP or to a separate HFS+ partition. The default in rEFInd 0.8.4 and later is to install to the ESP. If you prefer to use a separate HFS+ volume, the --ownhfs device-file option to refind-install is required.

*
If you're not using WDE or logical volumes, you can install rEFInd to the OS X root (/) partition by using the --notesp option to refind-install. Using this option is recommended when upgrading from a working rEFInd installation in this location.

*
If you're replacing rEFIt with rEFInd on a Mac, there's a chance that refind-install will warn you about the presence of a program called /Library/StartupItems/rEFItBlesser and ask if you want to delete it. This program is designed to keep rEFIt set as the boot manager by automatically re-blessing it if the default boot manager changes. This is obviously undesirable if you install rEFInd as your primary boot manager, so it's generally best to remove this program. If you prefer to keep your options open, you can answer N when refind-install asks if you want to delete rEFItBlesser, and instead manually copy it elsewhere. If you subsequently decide to go back to using rEFIt as your primary boot manager, you can restore rEFItBlesser to its place.

*
If you intend to boot BIOS-based OSes on a UEFI-based PC, you must edit the refind.conf file's scanfor line to enable the relevant searches. This is not necessary on Macs, though; because of the popularity of dual boots with Windows on Macs, the BIOS/legacy scans are enabled by default on Macs.

*
On Linux, refind-install checks the filesystem type of the /boot directory and, if a matching filesystem driver is available, installs it. Note that the "/boot directory" may be on a separate partition or it may be part of your root (/) filesystem, in which case the driver for your root filesystem is installed. This feature is unlikely to work properly from an emergency system, although it might if you have a separate /boot partition and if you mount that partition at /boot in your emergency system, and the ESP at /boot/efi.

*
On OS X, refind-install checks your partition tables for signs of a Linux installation. If such a sign is found, the script installs the EFI filesystem driver for the Linux ext4 filesystem. This will enable rEFInd to read your Linux kernel if it's on an ext2, ext3, or ext4 filesystem. Note that some configurations will require a /boot/refind_linux.conf file, which can be reliably generated only under Linux. (The mkrlconf script that comes with rEFInd will do this job once you've booted Linux.) In the meantime, you can launch GRUB from rEFInd or press F2 or Insert twice after highlighting the Linux option in rEFInd. This will enable you to enter a root=/dev/whatever specification, where /dev/whatever is the device identifier of your Linux root (/) filesystem.

*
If you run refind-install on Linux and if /boot/refind_linux.conf doesn't already exist, refind-install creates this file and populates it with a few sample entries. If /boot is on a FAT partition (or HFS+ on a Mac), or if it's on an ext2fs, ext3fs, ext4fs, ReiserFS, Btrfs, or HFS+ partition and you install an appropriate driver, the result is that rEFInd will detect your kernel and will probably boot it correctly. Some systems will require manual tweaking to refind_linux.conf, though -- for instance, to add dolvm to the boot options on Gentoo systems that use LVM.

*
If you pass the --shim option to the script (along with a filename for a Shim binary), the script sets up for a Secure Boot configuration via Shim. By default, this causes the rEFInd binary to be renamed as grubx64.efi. Recent versions of Shim support passing the name of the follow-on program to Shim via a parameter, though. If you want to use this feature, you can pass the --keepname option to refind-install.

After you run refind-install, you should peruse the script's output to ensure that everything looks OK. refind-install displays error messages when it encounters errors, such as if the ESP is mounted read-only or if you run out of disk space. You may need to correct such problems manually and re-run the script. In some cases you may need to fall back on manual installation, which gives you better control over details such as which partition to use for installation.

 

OPTIONS

--notesp
This option, which is valid only under OS X, tells refind-install to install rEFInd to the OS X root partition rather than to the ESP. This behavior was the default in rEFInd 0.8.3 and earlier, so you may want to use it when upgrading installations of that version, unless you used --esp (which is now the default behavior, although the --esp option no longer exists) or --ownhfs. You may also want to use --notesp on new installations if you're sure you're not using whole-disk encryption or logical volumes.

--usedefault device-file
You can install rEFInd to a disk using the default/fallback filename of EFI/BOOT/bootx64.efi (as well as EFI/BOOT/bootia32.efi and EFI/BOOT/bootaa64.efi, if the IA-32 and ARM64 builds are available) using this option. The device-file should be an unmounted ESP, or at least a FAT partition, as in --usedefault /dev/sdc1. Your computer's NVRAM entries will not be modified when installing in this way. The intent is that you can create a bootable USB flash drive or install rEFInd on a computer that tends to "forget" its NVRAM settings with this option. This option is mutually exclusive with --notesp and --root.

--ownhfs device-file
This option should be used only under OS X. It's used to install rEFInd to an HFS+ volume other than a standard Mac boot volume. The result should be that rEFInd will show up in the Mac's own boot manager. More importantly, suspend-to-RAM operations may work correctly. Note that this option requires an HFS+ volume that is not currently an OS X boot volume. This can be a data volume or a dedicated rEFInd partition. The ESP might also work, if it's converted to use HFS+; however, HFS+ is a non-standard filesystem for an ESP, and so is not recommended.

--root mount-point
This option is intended to help install rEFInd from a "live CD" or other emergency system. To use it, you should mount your regular installation at /mount-point, including your /boot directory (if it's separate) at /mount-point/boot and (on Linux) your ESP at that location or at /mount-point/boot/efi. The refind-install script then installs rEFInd to the appropriate location -- on Linux, /mount-point/boot/EFI/refind or /mount-point/boot/efi/EFI/refind, depending on where you've mounted your ESP. Under OS X, this option is useful only in conjunction with --notesp, in which case rEFInd will install to /mount-point/EFI/refind. The script also adds an entry to your NVRAM for rEFInd at this location. You cannot use this option with --usedefault. Note that this option is not needed when doing a dual-boot Linux/OS X installation; just install normally in OS X.

--nodrivers
Ordinarily refind-install attempts to install the driver required to read /boot on Linux. This attempt works only if you're using ext2fs, ext3fs, ext4fs, ReiserFS, or Btrfs on the relevant partition. If you want to forego this driver installation, pass the --nodrivers option. This option is implicit when you use --usedefault.

--alldrivers
When you specify this option, refind-install copies all the driver files for your architecture. You may want to remove unused driver files after you use this option. Note that some computers hang or fail to work with any drivers if you use this option, so use it with caution.

--shim shim-filename or --preloader preloader-filename
If you pass this option to refind-install, the script will copy the specified shim program file to the target directory, copy the MokManager.efi file from the shim program file's directory to the target directory, copy the 64-bit version of rEFInd as grubx64.efi, and register shim with the firmware. (If you also specify --usedefault, the NVRAM registration is skipped. If you also use --keepname, the renaming to grubx64.efi is skipped.) When the target file is identified as PreLoader, much the same thing happens, but refind-install copies HashTool.efi instead of MokManager.efi and copies rEFInd as loader.efi rather than as grubx64.efi. The intent is to simplify rEFInd installation on a computer that uses Secure Boot; when so set up, rEFInd will boot in Secure Boot mode, with one caveat: The first time you boot, MokManager/HashTool will launch, and you must use it to locate and install a public key or register rEFInd as a trusted application. The rEFInd public key file will be located in the rEFInd directory's keys subdirectory under the name refind.cer.

--localkeys
This option tells refind-install to generate a new Machine Owner Key (MOK), store it in /etc/refind.d/keys as refind_local.*, and re-sign all the 64-bit rEFInd binaries with this key before installing them. This is the preferable way to install rEFInd in Secure Boot mode, since it means your binaries will be signed locally rather than with my own key, which is used to sign many other users' binaries; however, this method requires that both the openssl and sbsign binaries be installed. The former is readily available in most distributions' repositories, but the latter is not, so this option is not the default.

--encryptkeys
Ordinarily, if you use the --localkeys option, refind-install stores the local key files on your hard disk in an unencrypted form. Thus, should your computer be compromised, the intruder could use your own key to sign a modified boot loader, eliminating the benefits of Secure Boot. If you use this option, then the private key is stored in an encrypted form, secured via an encryption password. You must enter this password before the key can be used to sign any binary, thus reducing the risk that an intruder could hijack your boot process. This is obviously a highly desirable option, but the downside is that you must remember the password and enter it whenever you update rEFInd or any other program signed with your private key. This also makes a fully automated update of rEFInd impossible.

--keepname
This option is useful only in conjunction with --shim. It tells refind-install to keep rEFInd's regular filename (typically refind_x64.efi) when used with shim, rather than rename the binary to grubx64.efi. This change cuts down on the chance of confusion because of filename issues; however, this feature requires that shim be launched with a command-line parameter that points to the rEFInd binary under its real name. versions of shim prior to 0.7 do not properly support this feature. (Version 0.4 supports it but with a buggy interpretation of the follow-on loader specification.) If your NVRAM variables become corrupted or are forgotten, this feature may make rEFInd harder to launch. This option is incompatible with --usedefault and is unavailable when run under OS X or without the --shim option. If the script discovers an existing rEFInd installation under EFI/BOOT or EFI/Microsoft/Boot and no other rEFInd installation when this option is used, it will abort.

--yes
This option causes the script to assume a Y input to every yes/no prompt that can be generated under certain conditions, such as if you specify --shim but refind-install detects no evidence of a Secure Boot installation. This option is intended mainly for use by scripts such as those that might be used as part of an installation via an RPM or Debian package.

 

AUTHORS

Primary author: Roderick W. Smith (rodsmith@rodsbooks.com)

 

SEE ALSO

mkrlconf (8), mvrefind (8)

http://www.rodsbooks.com/refind/

 

AVAILABILITY

The refind-install command is part of the rEFInd package and is available from Roderick W. Smith.


 

Index

NAME
SYNOPSIS
DESCRIPTION
OPTIONS
AUTHORS
SEE ALSO
AVAILABILITY

This document was created by man2html, using the manual pages.
Time: 20:12:13 GMT, November 12, 2018 refind-0.11.4/docs/refind/os_legacy.png0000664000175000017500000001002212626644767020203 0ustar rodsmithrodsmithPNG  IHDRL\ pHYs茦btIME "PIDATxOU̜,@6&iA[gwhL|w}ibQ4bko.W^fYy`ٹ Phf~s?|ܾ}<*Gt~FEQ H_@{#@Q#Oy(*B 2;H c^///ceXh;s{zz!E h*y;mG1?^gggUU[EuM!;mG1 dq___Va\uC0!hO R 裃3gθ;==gf(`MOOrtGsFA)Os=h4ݻSI5}F<_ݗݯw@=:8@- 185BW^Ed_$^C聢8-U#h4|'r9}q;E.QP\u]wuuΝ;1y>hvvk=~!ιdu]w~~~ii7|#OcP]_ @>cP(,--ŕVq]X,~:~P{]O8CZ?*D51ч F8g}{ 0t]7 RjY֙3g`KСCZVVk 5>BaeeEKzRj67n$b4M4-2 # ciGq\.onnbށ}sWVJqBp$x[d,.\0 CᨪzQpP.+JZdžt&I<Юǁ;, CCC8z۶mxa馦i'NRT*`qƁ0}(mB& ~&ti§zqR hxW jWWWwEQ-v.]dYkCEQ(gϞemll`#5rp)EQ4Ma|<~f ]WpϟgJ%;PSM)4>Pmnga(5-9-;p^Ԥ5E 8Ӈ9Okq MoӏA`W jcrh2Џ܁gio:̋taF0fͣ~$I;Pv<@4͘"<`"U6-;yv8?PwE<l6k6|&O֌3bh~LPeYeYphmm1a<ӠG Ν;r]X,.//KEoKuHIingJR=Ο?OBr0Ns0Va 8d2P$4"`еn?|X}T"0777%l?@P fq'''K`b$\YY)R9p]wqq?>w Ā![>%q9!N 1\ Uw}5j}oo>;00`6T.Yj k׮AW)#^bqU]-i o-J&ǎx"Ν;g&v7tii)E@իWa𰖋źlfVK/pP?/tSӴ0`?q?SM,Y˲Lӄ _|҇?V ;`YVCPp!B!a@իwĭ4\!@u=v>:x뭷:;;q0A \.?cN-v-;(r!铝RtovAJ_UEXt] ۢi~0牃~DN- * dψEFq}S~{rοTOW"u s>>>^Tpd2ONWu݅k׮<]T !;Ɓg*~9T*{N* fW\I>:ujffR֯(b½!Hd6> 5Q̨ݜ]Qj sssl1/_N>~TacBGFF2 M6g$Iȴox_ys^y:W_e2fG'x[(D}@;H!ypRO0u< jJ˜_:thcc@\?8чOwu]xȫX,B>Ncltttjj*4A bD \I<'&8>?W<77h4>,uGFFn߾. THKF4O|y$dAIX& nmA?e93&\R<2 ցle߿uVЗH@xp,?}qIY2/&LMMc###ccclŁWf2 hƁ(SSS+2:::>>qB+c$%v/tvvB r1EO; *`goU*|>_C_j:zy*%җ]v% sc IH :@Y5AƵrod_Lȱ_c%6/eijD$,>҅' /{IENDB`refind-0.11.4/docs/refind/ucs2.txt0000664000175000017500000000001013140133734017114 0ustar rodsmithrodsmithfoo refind-0.11.4/docs/refind/sip.html0000664000175000017500000006634213372346574017223 0ustar rodsmithrodsmith The rEFInd Boot Manager: rEFInd and System Integrity Protection

The rEFInd Boot Manager:
rEFInd and System Integrity Protection

by Roderick W. Smith, rodsmith@rodsbooks.com

Originally written: 11/8/2015; last Web page update: 11/12/2018, referencing rEFInd 0.11.4

This Web page is provided free of charge and with no annoying outside ads; however, I did take time to prepare it, and Web hosting does cost money. If you find this Web page useful, please consider making a small donation to help keep this site up and running. Thanks!

Donate $1.00 Donate $2.50 Donate $5.00 Donate $10.00 Donate $20.00 Donate another value

This page is part of the documentation for the rEFInd boot manager. If a Web search has brought you here, you may want to start at the main page.


Apple's OS X 10.11 (aka El Capitan) added a new feature, known as System Integrity Protection (SIP), aka "rootless" mode. This feature causes some consternation for advanced users, because it restricts what you can do with your computer, even as root. This page is dedicated to this new feature, including basic information on why SIP exists, how to install rEFInd on a computer with SIP enabled, and how to use rEFInd to manage SIP. Note that if you've come here for help installing rEFInd on a Mac with SIP enabled, you can click to one of the methods in the "Contents" box to the left of this paragraph. I recommend trying Recovery mode first; but if you have reason to try another method, you can do so.

What Is SIP?

To understand SIP, you should first know that Unix-like systems, including OS X, have traditionally provided a model of security in which ordinary users can read and write their own files (word processor documents, their own digital photos, etc.), but cannot write to system files (programs, system configuration files, etc.)—and users cannot even read some system files. This system security model has worked well for decades on traditional Unix systems, which have been administered by computer professionals and used by individuals with less experience. For administrative tasks, the root account is used. On Macs, this access is generally granted by the sudo command or by various GUI tools. Most Macs, in contrast to traditional Unix mainframes and minicomputers from the 20th century, are single-user computers that are administered by their users. Such people often lack the knowledge of the professional system administrators who have traditionally managed Unix systems; but they must still perform system administration tasks such as installing new software and configuring network settings. OS X has always provided some measure of security by requiring users to enter their passwords before performing these dangerous tasks, and by providing GUI tools to help guide users through these tasks in a way that minimizes the risk of damage.

Apple has apparently decided that these safeguards are no longer sufficient, at least for certain tasks, such as writing files to certain system directories and installing boot loaders. I won't try to speak for Apple or explain their motivations, but the result of Apple's decisions is SIP. With SIP active, as is the default, OS X 10.11 and later limits your ability to perform some of these administrative tasks. You can still install and remove most third-party programs, configure your network, and so on; but some critical directories can no longer be written, even as root, and some utilities cannot be used in certain ways, even as root. These restrictions impact rEFInd because one of the affected tools, a command called bless, is required to tell the Mac to boot rEFInd rather than to boot OS X directly.

Installing rEFInd with SIP Enabled

The end result of SIP is that rEFInd cannot be installed under OS X 10.11 and later in the way described on the Installing rEFInd page—at least, not without first booting into Recovery mode, in which SIP restrictions are ignored; or disabling SIP (either temporarily or permanently). This page covers these two options in more detail, as well as a third: Using another OS to install rEFInd.

Using Recovery Mode

Unless you've deleted it, the Recovery HD partition should be present on your Mac as a way to perform emergency recovery operations. The nature of this tool means that SIP cannot be enabled when using it, so you can install rEFInd from a boot to this partition. The trouble is that this installation is not a full-fledged OS X system, so you may have trouble using it if you're not comfortable with such a bare-bones environment. Nontheless, it is arguably the best way to install rEFInd on a Mac that runs OS X 10.11 or later. To do so, follow these steps:

  1. Download the rEFInd binary .zip file and unpack it. You can unpack it on your regular hard disk or on a USB flash drive. Pay attention to where it's located, though; you'll need to find it later. Pay attention to both the name of the volume and the complete path to the directory in which it's stored. (Your home directory is normally /Users/yourname, where yourname is your username. Your Desktop is normally /Users/yourname/Desktop.
  2. Reboot the computer.
  3. At the startup chime, hold down the Command+R key combination. The computer should launch into the Recovery system. This is a very bare system, with only a window providing a way to launch a handful of utilities and a menu bar. You must use the latter.
  4. Select Utilities -> Terminal from the menu bar. A Terminal window should open.
  5. If you unpacked rEFInd on a USB flash drive, insert it and wait for its access light (if it has one) to stop blinking.
  6. Increase the size of the Terminal a bit. (This just makes its output more legible, since the next step produces long lines.)
  7. Type df -h in the Terminal. This produces a list of partitions that are mounted. Locate the one on which you unpacked the rEFInd files. It will normally be /Volumes/Somename, where Somename is the volume's name.
  8. In the Terminal, use cd to change to the directory where the rEFInd files you unpacked earlier are stored. For instance, on my MacBook, I would type cd /Volumes/Macintosh\ HD/Users/rodsmith/Desktop/refind-0.10.2. Note that if any element of this path includes a space, you must either enclose the entire path in quotes or precede the space with a backslash (\), as in this example's Macintosh\ HD volume name.
  9. Type ls to verify that refind-install is present in this directory.
  10. Type ./refind-install to run the installation script. It should run normally, as described on the Installing rEFInd page. You can add options, if you like, as described on that page. Alternatively, you can perform a manual installation, also as described on that page.
  11. Reboot.

At this point, rEFInd should come up and enable you to boot into OS X and any other OS(es) that are already installed. You should not need to perform these steps again unless OS X re-installs its own boot loader or a subsequent OS installation overrides the default boot option. You can install an updated rEFInd and it should install correctly, provided you're installing it to the EFI System Partition (ESP). The refind-install script may complain about a failure, but because you're overwriting one rEFInd binary with another one, it should continue to boot. (If you installed rEFInd to an HFS+ partition, though, replacing the original file will require using bless to tell the firmware about the change, so updating such an installation probably won't work with SIP active.)

Disabling SIP

Another option is to disable SIP for your regular boot. This is a viable option if you're an expert who needs regular access to tools with which SIP interferes, such as low-level disk utilities. Regular users should probably avoid this option unless the preceding procedure does not work—and in that case, you should disable SIP temporarily and then re-enable it when you've finished installing rEFInd. On this page, I describe two methods of disabling SIP: using OS X's Recovery HD system and using rEFInd on CD-R or USB flash drive.

Disabling SIP with Recovery HD

You can use the Recovery HD, as in the previous procedure, to disable SIP. To do so, boot it and launch a Terminal window, as described in the previous section. Instead of locating and running the refind-install script, though, you should type:

# csrutil disable

This command will disable SIP for all OSes that honor this setting. (In theory, multiple versions of OS X might be installed on a single computer, and all of them that support SIP should honor the SIP settings. To the best of my knowledge, no non-Apple OS honors SIP settings, although that could change.)

Once you've typed this command, you can reboot the computer. When you return to your regular OS X installation, SIP should be disabled and rEFInd should install normally, as described on the Installing rEFInd page. You will also be able to use disk partitioning tools like my GPT fdisk, write to directories that are normally off-limits, and so on. Note that disabling SIP does not disable normal Unix-style protections—you'll still need to use sudo (or enter your password in a GUI dialog box) to acquire root privileges to perform these system-administration tasks. You'll be no less safe with SIP disabled under OS X 10.11 or later than you would be with OS X 10.10 or earlier; you simply won't have its added protections against user error or malicious software.

If you want to re-enable SIP, you can do so in exactly the way you disabled it, except that you should type csrutil enable rather than csrutil disable in the Recovery environment.

Disabling SIP with rEFInd

As described later on this page, rEFInd 0.10.0 and later provide SIP control features, but they're disabled by default—except on the USB flash drive and CD-R images available from the rEFInd downloads page. On these images, the SIP control features are enabled, and can toggle between the two main modes you can set via csrutil enable and csrutil disable in the Recovery HD system. Thus, to disable SIP to install rEFInd, you can:

  1. Download the USB flash drive or CD-R version of rEFInd, as suitable for your computer.
  2. Prepare a boot medium. With the CD-R image, you can use your favorite disc-burning software. With the USB flash drive image, you can use dd to copy the image to a blank disk, as in dd if=refind-flashdrive-0.10.2.img of=/dev/disk3 to write the image to /dev/disk3. Any existing data on the target disk will be destroyed! For this reason, it's imperative that you specify the correct target (of=) disk; if you accidentally point this command to your regular hard disk, recovery will be difficult!
  3. Reboot and hold down the Option (or Alt) key to see the Mac's built-in boot manager.
  4. Select your external boot medium to boot to rEFInd.
  5. Use the SIP "shield" icon on the second row to toggle between SIP settings, as described in more detail in Using rEFInd to Manage SIP.

Once you install rEFInd, you can leave SIP enabled, enable your newly-installed rEFInd's SIP features and use them to disable SIP, or boot again from your external rEFInd to disable SIP.

This procedure has the advantage of being a bit quicker than using the Recovery HD—at least, if you've already got rEFInd 0.10.0 or later on an external medium. It will also work if your Recovery HD installation is missing or broken. On the other hand, it's probably easier to boot to the Recovery HD once or twice than to download and prepare a rEFInd boot medium. Also, some Macs are a little flaky when it comes to booting from external media, so you may have trouble booting in this way. Finally, if you don't already have rEFInd on an external medium and if you don't have an optical drive, writing a USB flash drive with dd carries a small risk of accidentally trashing your hard disk, particularly if you're unfamiliar with disk devices and dd.

Using Another OS

A final option for installing rEFInd on a Mac that runs with SIP enabled is to do the installation using another OS. This other OS could be an OS that's already installed or an emergency boot disk, such as an Ubuntu installation/recovery system.

If you follow this path, you'll need to know something about how to boot and use your non-Apple OS. The options are quite varied, so I can't provide every detail; however, I do have a few tips:

  • If you've already installed another OS but can't boot it because of an upgrade to OS X 10.11 or later, you can use rEFInd on CD-R or USB flash drive to boot to your other OS. You can download images for both media from the rEFInd downloads page. Prepare a boot medium, insert it in your computer, reboot, and hold down the Option (or Alt) key. The Mac's built-in boot menu should appear, enabling you to boot rEFInd from the removable disk. It should then let you boot your already-installed OS, whereupon you can follow the regular rEFInd installation instructions for that OS.
  • It's imperative that your rEFInd installation occur in an EFI-mode boot! Many Windows installations on Macs, in particular, are done in BIOS/CSM/legacy mode, and so cannot be used for installing rEFInd. rEFInd can boot most Linux installations in EFI mode (as above), but if a BIOS-mode GRUB is installed, you might accidentally boot it. See the What's Your Boot Mode? page for information on how to determine your boot mode.
  • You can use many Linux distributions' installers to run a minimal Linux system that you can use for installing rEFInd. This can be a useful trick even if you don't intend to run Linux normally. An Ubuntu image can be useful for this. You should insert the boot medium and hold down Option (or Alt) while booting to launch the installer, but be sure to pick the option to "try Ubuntu before installing" (or a similar option for other Linux distributions). You may need to install the efibootmgr package to install rEFInd. (Typing sudo apt-get install efibootmgr should do this in Ubuntu.)

I've tested this method of installing rEFInd on my MacBook Air (purchased in late 2014) and on my first-generation 32-bit Mac Mini, but I can't promise it will work on all Macs—or even on a Mac that's identical to one of mine but with a configuration that's different from mine. My preference is to install rEFInd under OS X on Macs, because Apple likes to do things differently from everybody else, and so a Mac's firmware might not react in the usual way to tools like efibootmgr in Linux or bcdedit in Windows.

Using rEFInd to Manage SIP

Once rEFInd is installed, you can use it to manage SIP features; however, the rEFInd features needed to do this are disabled by default. You must uncomment or add two lines to your refind.conf file:

  • showtools—This line specifies tools that appear on the second row of icons in rEFInd. The new tool for managing SIP is called csr_rotate, so you must uncomment showtools and add this option, or create a new showtools line.
  • csr_values—This line lists the hexadecimal values through which you can rotate once csr_rotate is active on the showtools line. The trick to this token is selecting appropriate options. Several sites, such as this one and this one, describe the meanings of the various options, but often not in much detail. Apple's own csrutil command sets values of 77 (disabled) or 10 (enabled). Note also that you specify hexadecimal values on this line, but without a leading 0x or other hexadecimal-notation indicator. If you specify gibberish values, or hexadecimal values higher than those used by SIP, rEFInd ignores the bad entries. Thus, if some of your values are being ignored, you should check your csr_values line for typos.

Note that both of these options must be set appropriately. If either of them is missing or misconfigured, rEFInd will not display the SIP tool. A typical configuration using these features might look like this:

showtools shell,memtest,gdisk,csr_rotate,apple_recovery,windows_recovery,about,shutdown,reboot
csr_values 10,77
The SIP rotation tool rotates through all the CSR values you set

Once these options are set and you reboot into rEFInd, you should see a new shield icon on the second row, as shown at the right. When you select this tool, rEFInd identifies the next available CSR value from the list you specified and switches to that mode, rotating back to the start of the list once the end is reached. To confirm that the SIP mode has changed, rEFInd displays, for three seconds, a message identifying the new mode.

Whether or not you've enabled these SIP features in refind.conf, rEFInd displays the current SIP status on its "About" page:


rEFInd presents a graphical menu for selecting your
    boot OS.

Note the line that reads "System Integrity Protection is disabled (0x77)" (highlighted in this screen shot). This line will be updated whenever you use the CSR rotation tool, so if you've specified a large number of values and have forgotten where you are in your rotation, you can use the About screen to figure it out.

If your Mac doesn't yet run OS X 10.11, rEFInd claims that SIP is enabled in the "About" screen. If you set the showtools and csr_values options as described earlier, you can adjust the SIP settings on such a Mac, but this will have no effect because neither pre-10.11 version of OS X nor any other OS honors these settings. On UEFI-based PCs, rEFInd won't display SIP status unless you store the csr-active-config NVRAM variable in some way. If you do, rEFInd will enable you to adjust it, but it won't have any effect on the OSes most commonly found on UEFI-based PCs.

I provide these features in rEFInd as a convenience for developers and other advanced users who have a need to adjust their SIP settings. Using rEFInd for this purpose is much faster than booting into the OS X Recovery system to make these adjustments. I discourage others from playing with these settings, since changing them inappropriately could cause problems; that's why they're not enabled by default.

Conclusion

Although the goal of increased security is a good one, SIP is causing problems for intermediate and advanced users. The good news is that the process to install rEFInd on a system that runs OS X 10.11 or later, although more complex than it used to be, is not an impossible one. Furthermore, once you've done it, you shouldn't have to do it again for a while. (An update to OS X's boot loader is entirely possible, though. If nothing else, the next major OS X update may require re-installing rEFInd.) For advanced users, rEFInd can adjust SIP settings, which can be helpful if you occasionally want to do something that require greater-than-typical privileges.


copyright © 2015–2018 by Roderick W. Smith

This document is licensed under the terms of the GNU Free Documentation License (FDL), version 1.3.

If you have problems with or comments about this Web page, please e-mail me at rodsmith@rodsbooks.com. Thanks.

Go to the main rEFInd page

Learn how to use rEFInd

Return to my main Web page.

refind-0.11.4/docs/refind/submenu.png0000664000175000017500000005666712626644770017737 0ustar rodsmithrodsmithPNG  IHDRZ pHYs  tIME 68 IDATxg\gtQ bLQEXbPcAnTX(D*`4(U}>/Γv^qfߜ9s#=~C {M@ eG Rv@ eG Rv@ eG @ʎ@ @ʎ@ @ H@ H@ N2q龾ӧOtR۶mknnP.]rtt|M?O`BBB@@?aWX蘕oYrK?̿H$ڿ3|}}qFGGGww/^`6eʔdwwwgggI&͝;8W.G7nW0 [z?2qDӧoڴ 5Rv,Zhǎ]rہ;wh鎎---JT~xuuUVD;zh:ޟ' ǀw={޽{/0쯿mmm}jo2?...55566[l~Aghhhmmaشi,--z]jkkiӦ.?/bVVVm߾ðlٲs„ gtttcc'|؈)RLϫ@PMTYY!H 8ccc^+C> Æ OǏqP(6l͛mŋb1a$FQZZZssɓi4kbbӧOϝ;p>l޼y Ɵ>}D" *t>'O~Gᵵ6m0v׮]RTCCcҤI[lQ0W...d Î=:n8=vرc0 ={gxx8 3g񝝝ܹS[[_xBRCBB.\YYYfoogϞ`` ihha0]f?裣Gz{{_x122R{]ުs8 äRiRRRlll]]^vy<{=s o̙{QT.s|y7777!!A8jjjgff~HQUUUs1110,,,͛QQQ׮]6ly<<8x a)))m4dnnЃٳ^^^[n QMT~]+??9s1bҥ G]x)444߿/o~L LNN=uuu7yWWWu+V ͆@ʮĔ++ TWW[XX߲X,##W^鵶p\Φb55 .(֭[!|ĉ"H͏9sfcc#<xzzR(˻ƙiӦsv35mmmqqqDenݚ?i4A?}?~˚e˖}駧N"?,^^h]ڿܻw>`fii9jԨ 8*9벲2x@5L&f777RԒ< rGZZZaX,onn~aú;ݻ%ɬY._\RR` RǏgnϳۓdb&ÇJڵkX,]]]C-YB?ҥKKKKSRR0 SRR=Z^^^VVvҥ\yxOa͛G(o|z͛7|󍃃'k!=~9$$$455}ܹV"H"~yf{{͛1  ;vy&T nݺUҡsΝ?999mٲf/Rbi֭ 'V=Hy慆<ݻwǓH͛7ϙ3gϞ=?⒒JKK)ҥK\U$ikk1c߿_444dH.d33'N $H} ggg.?miimaavTWWD"8@CAH$bX,7VʿW믿0o߾O?󊊊vuwl``0qDwxQBB2!!! .ILLJJJ*|*\U蠹X"C$\MPPݻ MLLΚ5k֬Y`޼yORuuu_~Hg+[$D"XLutt̬G`ooooo?rH;;Ç>F >@  Bw!//|MM 0 kkk۶m۰aLMM 32L&3((0###&`Gwf2χ2d_YY9{l===+++X___KKKGGGWWW__ؘᘛ1cܸqvvv搃x T=~iժUmڴ… w-..vpp4iRkkcƌĨMMM uV___/\y˖-B˗gϞ=s挂ŷ~痟o?~|ԩk׮xֆo iΝpiWW WVVVWWgddlܸK.s_~eƍ~~~}|󍕕a3gJJJRpHW_ T)S|>'hhht>7_w:"gLX4MR,--DRT*BP(T*/$L&cF"߉|QQQss7|3nܸGՉD"\ 544LMM󋊊dnWlڴiҥAAAۺuk]__0ccc |>0 wy JJJ:*++wE,CJOJJM/2auuu diYYj<="f'/V1447ݤP(zzzÆ swwwww\.xߡu}ahhxĉӧO;feΥ;uW^sO>dԨQo߾ :::rEEE'O\paֹ v*^PV`*oT2\.WOOJ#R9kJ*jjj`aaq3bOOOPgiBa[[\bikk[[[h/^r;;;yۉq}}YsFF/˗//,,LNNU]G{4D"YXXs8553Ml6{ĈSLmkkkmmx}'.Jjjj444>JX?jkk/^XvaȐ! m%%%ǎS{QCCõk~޽SNKf {Ypann{-[%))I"g߾}/__zUTTtĉ4Cdff ͛7wy P~>_/_~?V2QuDǏ0a.`rt:ND<1B|?1ׯ?}t}}=l6;$$d۶m$;H$?x Wϟ?9cƌ#G(ps-((>}%KM_SSsJoܸqɒ%bpH$ի߾}E":j*''\##u:tߝUbb0˗- X`'ÁE[ׯ_駟>}J]\\80bsssPXUU`0\]]%---$$֭_yeeeÇ|^}]wSu}Fœ&M:rСC\/w/7#o({D"522bhjjz7o h+V⺧+J^rrrZ~{S>"eژX,J5mmL ---WW춶6&I D"1b/?>}j`` H\n^^@ pvvF3?e뛚wt(ޓ'Ob1.T*U*XHe˖x<fmm}ĉ3f|hcǎ4*燾2!:[%؉ׯ_gggH$&g 3CP33#.R6u {s1(^FFFcc#P%gޥR);e],뛘t~<#hO@E#d2YYYjjjjjj|hx@ nCuŊXhp'G 4D޽{EEE9/Ϟ=rJ[[*]]ѣGw"vUV饯_hƹsΞ=[UUU^^mmmmLL 5k:QO?~͛7ܴwubiiihh}RBtSPRmmm e*UǏ322 :~:::ZZZf͂w HÇTNdOTm&?~|͚5&&&t:}ƍo޼qaNNN?ˡ˒p»r劗W& 򊉉Q=Μ9CPlbl3u/bŊ"N%{„ wܩ,3LF&Ri{{Ç͡kk/\Ǡfu(J%H#GTf( ɓ'߹sGCzgee$D"oܸ! yf333y_xxbx&H4-==]맧ߋ/srrZZZTqC% IDAT*_FFFVVVٳGiii`|l6;''AGG`t}277裏=}HO92n8=}tD") yKKK ݴi]+7\zuƌx"tݺu_eeeڵ ]%ٌ͛⇰0:nݺO>D*&%%ձkzyy;vرc͞=3<<燆02y_rY?@FyY0L]]}޼yF1 9MMMMMͶW^<|ŋ!)fܘLM0DB ѡ aUUUs԰7oFEE]vmذa˗/x>xRRR##C*ʞAcccSSS!S_駷n:tPjj+**X,ZB̝;ڵkDs!!!AAAcs،7g!!!пEӽy+**:{w}?;GV&*CC]vv""h޽۶mS~˗/Ϟ=W_}G;w_=8_9299O>0ҥKGٿ͛7׮]aÆoΜ9322.//+W=ztQQʕ+]]]eΧq++x#KF,$g444?~ܥXohjj}bvŲp8H"; 6mZ{{(Ν[hB mnnNJJg;uuu믿 Ty6nܨCPƏ/ !**}ڴi$Auuu5fkkk!?{֭[CBB>>`: ,,Ї{aaYd{^ JKwaX^^^ `ف/r=<<^g{|{{hF~ۻwȑ#/FkooWrdSSS(EvVWW|?}'lmm?>}{)NIGEE-[קNAwϞ=|>_|D7oRaаbhhX__޽J3FRǏfsdooO&e[[ۇ*9ZZZcX, 110\U0TMMMnnߒ%K(b<dmm}QF;ɓ'ϟ?2yg9os|KuuyPPPBBa0vھ};aNtwA۷Æ S~k׮ZMMMSSS(ʠq> eҲuttM&`;|K@߼yTׯ/^x%1d2ںe9^^^--- `Ƅ/U.J]0fW[[+H"""l3m!7##۷.\2'a'|BbhhPXZZJ\Fzꂂ={~?P`2*++kkk 366N</>>^(J$'O2LWWWGJ&W\yVVVwurr233SSSŝ.уy댼yҥKoܸ*J͛Nn2eCSSӛ7o٣?uT/L޳gZn|믿NII9zhyyyYY٥Krss{0o@}cy###(% ::^GGފ‚5c2ު2`J:T )E455{_+KJJFCCCMM -gJ8p !!@(XsZD"D~͛6667owyavqM I&mݺU^ce˖~L---YYY?cCCC8Xh>|Å4q;w<i˖-l6 ''ƍ z666Fؽ{ŋ +++llqqqKMM^~}qq1VyBCCe[tttDDDڼy9sϟ3==?S~̛<߿j5 -..֞7oޚ5k zjXKuVccsaTsN???㧟~Һ{.a/_RׯOKKihh ɐ:y򤉉ݻgq8άYEId2yԨQRЊK, 舋E/߾};Q_xNPT:::`hiilx2; g| ]LmllƎ eV-+G'$$2NHq~SNrp A HaQGGGO$H$e_tXKwVV^;Ouh;tP՚9/o';>諉@ 2f=2dʽL}|||>}#Nٳgtt ˽x"zge2*7 h&MN;4ba*@_СC544ƌ9mVR. BQFFF&Mxpj H#Qvb;FnaSNvmA!'SRRgϞ54VELw1bwDa;Ș]" 2O+a;ax㰼<.鵵2&Q(MMM;/ɓ'|bb`dվ8 FwXO[n-Yg͚5xSK.\2 `ʔ)!!!uAJJ6C Qa<:J0 >3T@޾}[$uteWm|_%="O%yJĀ&+++::e抛cS}UvbmUX|||7&.\*--ǃIĞx݅ᘘ{Q䩤S ϒ^ǧ=z(,,Dfcp}،=jZ (2#344TRlNA͉yXוI6NR*TR0>|X"ٳgŊNW\l 1rgʔ) HbHSsC& wcc~~s@'#RS3不 *++pǎ !O.ώ뻞3f *o&#Hd& ޼ysE nPyOGhcǎYv>ّLWO7o<~X";99 6=KYY⡐һB77p$H4jԨ~ ɓ'O._ E}9;`&''C DO++'IU«W:NRL&SUs믿޹sI$ѣGWVVV+W|o千emBlEkmm---mkk` _4 Ӄhd] xG__חX$J=??YSS/Ā}Ȑ!JCN1ocv èTQv dt ;;1`P(X]]]uuv(fG } jjjl;uޚC*1jjj[ZZlfs6l1bvʮdü~\a;p`@n]CCV'A`0bȐ!DYWa̎T%ty46Tv\Fip8OOO(Lw88_t:hzCT<:3O%%x'CaQ# n "HˀWW‡ à ÇK\enń  ˗s&M4eʔ8.^7((HzwLaaTjiixE^3rxx >)S\vM {utt4i^llL)b,Xoܹ@r1GGGGG~!55uk ,xaXmm7|9cƌwޯ<}||nܸ痒riOOO'+H"##g͚5qF"TKAԩSqTy4}pfc;;;SSSvxL&Ot:TU.T(ϣ 1\ LԹ.DJmmmGJ)))VVV ,睤rO̴4ӧO/\EEE#F/Y=Ν;WWW\^^8J *4sFxIIIP((Zz5ly:._oMII֏]3fffpЀ<}uNvwtS Tffc0 IJJ"iDq?kjjى^X<:{)W^Jgxۯ%ɣG7E tOۅB@*@$|sA$i0(;we8P(666:R(#GvP'/_*B;>T Tz;vX`ĉgΜP([laXl6ؚٙ_~YbEwuv_PP01x>/Q_|ybR1t:JX,CCɀ5h}wʎ<:<`;ty7^zuڴiogݺuW.++tܹR:ϧdҤIG-~Jd2X,HC^ښ`<1c@_a;w!>}Ag2TT)O< P*CC]vv1"h޽۶mS>`922 &dggϺ);Tk@;R ;duuu166vqq|pTGIBQ\\\]] ybv䩤ny*wx@rqq_vsrr0 ?~ȑ#7?=###.?v"Z%w>IDATvzb%㕎x_daaȘ1c233y<N wr%%%xWŋ w(11߿qqqtaÆyxx-N>}޽bV7m !ҪUz'N ;sLae[+'d(JkkkWTTDGGCtȰCJ*#GԄl;qBǑiywݽy*uy*sJfff*I$-AAA `ڵkp{@q>]}аB* uHdE ۯ&)by{{|x - ^PPw~dv|С ACl: HbX N<2b~-͆eԄVwćLee+̙|$֭ =vaOh~KumϜm۶AuVUxy B)--TfHo=u^2&uqO#]\\ P7C[B)'AL<{zܹs[K{\;v,t!Ban\Qvѯ _X,r dzkp8^.ӛ2e e}ݺѣGMMM|s%S @wHȀ^'Z&@LLLz}G #.\"x%;xbv1%*5..h8ܜǰl|Dx.E:ai_$ّTlҭ[,Yf>y۶m=::: 11l6{ݺu 6J $jAFӧO[v2lee%>>`tҪT Ą N/,,TݸqC t0[hhhQ#F_K3[oii9~xU*Qx:C";P$CE"Q/.^zC#~SRR,XP]]-FJiiiO^p?FOB=Ν;WWWܥ-S7]OFpO%c_x*^6vSoMII$oO% SIBBIIÇ322.]TRRb b+WDFF9r"$$$ț|+pO~Pvj/w۳{oll3<\;ᙘK :.A * qnIYYyvbc_>EJ@Jﺧaj֭ḡyRRRXXljSIFeee y/N4J%: H$J]`E}}}DDDuu5b_!W'i<:<O%*++7 v޽رck!Qnjjy|)W=qܽ^zoD zTy*y*Jo޼yD"imm wrr 6l=z4.WHJ 4\,|.!-C̶C"ЅC1<ٳ&>kjj#G«9p\KZ+p)77~ A ;$i:LD"dT z$X,H$w! 1 |9$q3af 0 3g@ x9Fkii)))* xd|q@ O>pT۷o+*SSS /`q bCC>Z[[ۑ#G}SdqR4%%e׮]`D$TRc:Rz_~]۷o777ʎ;X,6118 2aPP(QH$]|t:dWvHC dać>Sp OD 2]]]8uҚ hkk x} y'"_\3g.]ut(c& @ z+Ž鐅B]$A$kmmmii0aBZ}Dk 7=7-3 644DGGgff#C#YG @6cP._yLU x/c lN+Pdeecrss}!Z0i} TzG=z?̮lB_,|oSqqojj:{gާy,**:~84PIuH[Sz*~|]g?Tل]oSRd FbbbZZ,u!Fx_3)TTBM@q YŻ?z]L4D˗/766 ^ Xb*ItT:~7Ba6o oenŋn)6pvvsNmm~O蜜*7bLMMTSS߳gy*J:::TxbdddY|yvv6|Oy`hjj644EDDۯT*MJJck׮Ȉ)S+ommmrr2Ñw2?vرc0 ={gxx8 188nӦM˖-[ʢ~///y[D!zv(fW*r=i]p!))KFIIɩS""":T@Ou$T{uw7 'O644̝;W`M9>hey*)=09Fɓ'K.e03g|vZ=0R{ %|г ecNKA:dST>#OOQF)^?W^-// <~Ύ1yD. 566 A@:}{Npbx*͟?v*$z*ZǓ-O˗o߾WNڹ%2CTh 0-x)]OT0>x6eeeij狔%#wPvXznܸѣ[XX HSMIIɓ'O%: ;X<SIQw_jjjzxxDGG9ʕ+_~=ePg(um-!!N쀈 $%%#wz1 |'O ){wxAܵX,VNNɓ'޽w+Ad͛ׯo۶m߾}L&OCx4a?LH \85DZkQB +oB.,,eD؍bPP+F] "tA *m#yt]|<,<9ϫo>T N%ISIH6YSS׷@ D^ iA䤦iRt9 ;Nע: :cbb&&&Œ͛7%˗P( ߼yClҟѲ-u: mw*ѩJrFJ*,kްaM:u666AR]]`0<nPyg],=ܩoEXhɨ,螙e˖b1TYYYY@```xDg=J'l#_X#ْxKKia#4E<zUĒ]# tqLd{s3Ve{ӣ8Ż1l/mz^Fd: Mu=x𠣣clllڵSSSZ6ѩ*{ݽ{INspp8JOOϓ'O~cǎ&:a[ny<:Ve߾}“ftϳ__|xhL٦=\M'OB_~?WZ)X"ЩH;$EfիǏ~:/"$;5t*g߿m6k448_q%Yr. AB<:{,Ivu'9sfΝjĒ[\.ӹ}aC :~(rR#In\y< a`0hZ>e˖ZNNכLp8VUUUUUDǐ:u9IJ+7j7gϞEQ^z'ݻN^T1$)'E]N (&};uTwww__K'ܻT8u9H<.1Vb;q$z}$ M$rQI4nC)g@CF/8I@ x^a&xJ`]N{( KE___KKK4׮]8ܹs>|||'dwhccc0X, t޿lllT ՕҢcHnObIt9ґ`\y~%@`72|nw$;իWcd$; d$; Hv$; Hv@ i?IENDB`refind-0.11.4/docs/refind/donate.svg0000664000175000017500000001003012630127607017502 0ustar rodsmithrodsmith image/svg+xml Donate refind-0.11.4/docs/refind/asus-bootmanager.jpg0000664000175000017500000007267012663063045021503 0ustar rodsmithrodsmithJFIF``Created with GIMPC  !"$"$C  VS PP€(yfP/&B3\f Ej0CSD4@н7˹v$\y.ju(zjnP2ܼ8`7@ t 1Y `Ƀ ֶ[ HR) @tu @jλIsgpk3g;;|0GWӛ  Y,Q\=㰍Q̒S>;h,W:<_}'_'/FKC.o'J;Μ=7u7O7WzR*^.eκXZ6u[x(hzYJ_XNMM5˃[3,W2Ti$ٴq̓BYYdW2r7X.e;$\Y`!y= &yo "L{c4%mϲ_1r. ⥜wܚuUl]ͳ5]*YɹI crQ8&Z^} u5&(Y˹YEd%$굪YR.t97沒 4N K(MMRhjYY,҄yb{3BslKʹy6-I=$ߛ5d ԚQ\{+BHTJ2P6ACSfF^\w]!;t|vl˟C:heDkQɹAJY4T)U8ϠJ-j\qqmzq*e ɱК؆j3f񱒕 ufI)[iK֗vzw%ťk屮1',/Rk% -F5J{M|;ѿoӗ~5˿Xɣn+zH g2NG3ʾ8Z4 g3 x_xe [?M!y 2~)/fC ,Q]o|Ӽ uP[P/kn|f|jҼHRetN[u`'ǂ3̗S屍ҩZ,c5. fX\?N)am{%*( cj~hg 9rTQ[ fj.|f|Ål ,+1;;dpˆȋwMwM˦ț_> M,YgQ0y'86aI^as8wIWL0ĭr&N9+1+RpVA6Gq /;r;1edM7 ύcߡ$)-q#O>r(#23 :z)e% :*ogO4󅞟|KT+4`D+$G-6'5}d@w59z`L9P le xvꛟa.Ȯ~'P+7A-R||K.<],E86#j"՛RʆJYp6[_ŵyߜf8coPcOPu!+*htګ e|~^$Tթet -::`(XPk`7tXK@Z  * -•PݬՐ( YVj)ZҊ QhYz/Q* a_eV eo`l5caù`(; k>ߌ|gijPH,S4bxClQpLŃ#~mWenN[fٸ5[Z.A[Ae)ruY~m[_?i611_iL\cvD 1^ lAI!A3b"?2,b&7Tw8\M$f(b>~m[ڒ%ܛ$9&R9䝉03y%Ҝ#La,OgG$G3 eg@Qd7>5Y18N1?a0a!D8̲D HfHra3ii!V/όrTJ$}`fC#%EE m8!/_DeZsSb \.tGQ98#Fq%6 sey߲_ǿsQ910EH"("wș{N2S 3"f3g"yƱ_ǿ}ߋc:r.:d쟝~vO?;'d쟝~vO?;'d쟝~vO?;'d쟝~vO?;'d쟝~vO?;'d쟝~vO;y3!1A2Q 0Paq"#3@BC?KQEQEQEJ((((((((("]gYQYy^~|gE>袲k*(诚ʲ袊(+7UO[{1=otGV/s1RM4k~~' ~~'ٳ<,W,r#ab˶~Dq%?2X8lxXdp$=FIq͚M$J8Ѥ8V]"^ItlwWKv?'\dQoY9햳QnjfIc|Vv9j5+Faj5 Qi!+ĦS$C"ES+*qY"$FcHFIHB4i\Iz+ Vq.II&~I #mrq']o藃UC%v] 9,m=Ydzjj4VzXL~Jh 4S+-,8QEbzػi64ir>?J&%/y%~~OrG\vObzZ53S52yXݗye-٩52VXݚ454tQ<5!$䤗CvZoGO[{1=oG4iY5R憄hFiYP<#J+R~{1=OZCyY-FPZ5,jұ"TI$J54c\"UifIVN<YEYOdz$J&V\hli GLEQ&odzVi4::+9%c+Q."]K\61tt%Bh}vȔ/Q~dql^vMl^JUlYlYoG(EQEQEQEQEQEQEQEQEQEQEErbzf'=ʹmmhF6ѶmmhF6ѶmmhF6ѶmmhF6ѶmmhF6ѶmmhF4!A+1A !0PQ2@"#Baq`?\|/ؼ/7Pk>= v".Mcz8888:q:qbt8888888Z>T%ӈ}*BыAh G؊AhTo'|Pb_aF/Jd;vGhRi&z5x^?6LWש>2-FMS6ߡzFd6.X븽!.bCHBH%Wx}̋j(kSK8BMv8.ԈSGR'fubo/( GU q\#xv:GR(&6u"PS:F]8.]G*,YeX",B4$"#Xb(E(("+EQBB/—eeYbbe,V^S\xBr(Y\g(B,q_Y,x_1p2,E㸅C>\ ;xB.1EQEyQEQE䢊+X,LbeqQE $QD~.>A.>Eq+o,;,ee\{WEE{q^Ǻ/b,\{o b^;bq \|\|ڍ͍͍͍#ccccb666666666666fE!1"2AQ4aq#r0BP3bs $@CRtS?uqo!Rd*؟Pnv'5۱>݉ vOkb}C]؟Pnv'5۱>݉ vOkb}C]؟Pnv'5۱>݉ vOkb}C]؟Pnv'5۱>݉ vOkb}C]؟Pnv'5۱>݉ vOkb}C]؟Pnv'5۱>݉ vOkb}CJt+~T⓳3ΎNGC`W c_qu+>6Um&)mcz<`}+uj^7z% 9rʖхiKB;dOzxw#mI_ONp)[ (6ӊYT+)6iNÝc*XBڇFeXT(?{: Ǩq.#ftoZ6ip_ly }Zy/\kZ$_֋j.gAPJI1Q|6QvK.'e6#fdШ3COR*ë`a•7bӁnJ)EKqan#LEKqan#LiK6m+å9k%6 reN>1KͱԢ[% ̑Ӧtv {zn,0tGL2(NZxU%fO#f3T+TT$)rdgXXœ'-h=>#A)NP[1|)M;KvBS e.:Ү[KJf$'RV\=h]$sV̹8{87Oʮq:$Pd4!hDCҚmS XFϼeIJq%\ W3SΆե:\{.&32 L AiiLĔ' 2l˓tn6']((CTbʞB%P7&u>tmp%{wM:pD) m ɎSíWBR>t0U3<].̹ܦ7}Q@fFj~rks]kEbcjdeM1zfBKؼP7bXC%3tSeza6."tL}Q˗zERQBJ*zT!W66j)ψ8t;o qCm1NfLJiJw~U!mRkXҧ[(R24mDlE9s7h #\V-nBj¤_<qplX3<^oqw>T$L_H%Ŋu1o)Zئ.LIֱOŖs sAe orG]kjV? */bҗ;*^~9~T[p'r^P+"bBӈmKFys"RbM5qI U'3S>CO~6-A`i)aa@%ԕ94y.%R BΞqo%ĸKaMWgX_6!*]v}5X]mg[c3җ۴[BJ[q.:AhU(+ڃ+L!9C0]2JY?,_-KAB6dV'f Ba)6"ƽ˄t)y| tʱu9{`6Q![ >{WN|G^-:V5ԕp$ Ex@njSn-)sI: x$҂d0dҔAB). Fyq)N@ I.7hQ׿Άջd5UxAnR|%m+xJR0X6NTXI-)o6Djq mŠ.pԸ{JIV'9QmĔj?/œ2 J󧖄B-SkdH'z`gNF,I<=+k]x<}ښL-'NB!Iv=K4w^Sc"-',+qJRd^H9t;sS]p)%u33ivΛMκ6OtaOMcmwO]m]=o5U۟ʱ?XEjk[foOk IwfsҒN<Ի#¾Q9V2`ᑗ}[S?)zV%3*_Uy7lBeLO6 u >#AI0FR$"_79 iJJԘQ5Nbq-3%jI 2w|}Ei[GH*Pi{;6%D: ҂H#B)IR 2P1MJMpBXV :~~=h!.? _  3=iiZEۀLPC\֒29g֔)0*])mJBDZʒ 'jRlH|(%'-G|&Uq(HI'FTrzq\ s4Yu{2[pDDN\wgCXDPTӐyӇlҶJȝʖW 拳(:S,aR#ӇlҶJȝʰmq̟)jZRIRȋ:N9N|F:y, H?cmJXglsjP܍9BxR'?ʔW£RJrg1:ӻJT" &F-WB@3XglwjP܍:Aҧڧsbڇ/~S9>#sœ0N|G^˳)#c{)cI4\N:6JEjim+< 3[LJ2:DLA#{#HdIΗnW<)ψO!H ffr(gNC29+ .ցGLNCAHa%3Ҏs*mH33Gu"j4[(@kJ{\>#v$ARNTQֈ&i{Guƚ:l#w9LD(d+i)Y><1Sy*!FA)P&τD"iJd$ݘLGJ)f@NM*I0)Q!`L'9U|':ޘ ~ s?fUpT&:Ѻs4ciT9 ţ3:ekP|=~Do&S:P_9R<]w1J*wJ)HJ)HN[ҳi9Rc{[f!>T($+Ƃ;▣4v 1Qփ_3KӄrH3F_/sœ>u7+Φ>+%(G>D|dϳ"jnWH&hs֤OD7+βQΎZɚG>#sœxV)Oq*oʸ*oʸ[*oʸ[*oʸ[*oʸ[*oʸ[*oʸ[*oʸ[*oʸ[*oʸ[*oʸ*oʊ Q*!1AQaq0P @?!~j^^^^^^^^^^^^^^^^^^F5>5>5>5>5>>>U>U>>U>U>U>U>U>>U>>U>>E>%>%>5>5>5>%>5T)3 WrΧ(&`lLJGG&_շ/;zqe { xr&Ci,SK$i?}6]L:Z^(ߜ(n>[6=rMIrel[-el[-Kel[-KKeil[-Ke=\r˗/r˗/rܹr2F\K.\K._=^|W_OW ~amk,XYbaυ.|>ǁVel|vM~ հS!Zy0||>5ωbBGjԺ>`[Y5MzCU9ac)Kh^z\J-P1"4 -ݏƯU0 %fzpSFaT4?^q'hR| LKk&ץ Я9~ UMRN8$U _6+;QVY`TUzpO__9"YV+Ղ{L.`:V4:jWTY 2; aʙl.n6>q( m|5þ3W`0065b]agVm)<&TqSMa<hVc1`.T4yF=QklYFcΖoJizH6ɵJ@I]LUSP4ڟj<=rzv/%bj}%%(5Yf%̰C7Y^lXӶXvwwo` K?Dd,Ƽ_B9/%*ȵyҁ0Hy4GFs@7BCƩy+~^ x;'c\ sЭ`}"dOo9qx,v2KX1QGD_jFy*:o )b[+ b(a6ucfGSH?G[,JJh1 Pbh}cgu蚄a 7vm"M;㎉ULt=R]09;跃 v_wYb\<`y4H^5`%,>kWWMex=!4+(wqX6=3u8Y{tnʧg"iAY+:}1Xs 6t:B͖[渚TV+Jxs*qMeb7(P#x8CYocn+}y0ݔ>MΡ5"؍"RQ`>`ap+̰lXSc hYtlG#:G ( J 9U׵\?֌t%IA8(oU:0 U 8Q$<\mbK+c9kK+c9J6յW|4qgR8QqkY&.v)-X4yc0KE ^sNU* `8 ])lϓrV;Bέ̗/&KTOIy]ei]Xd¶Xf.VT!U*py3Mgq@͔{fp'7SkK7F3KocXUe̵nmzHT@r Zq[<=1(c )loѫӜf/"؉ɶ)s8 n"kE#.M55,[dX Q%%p U_R\ :+hS Yh^"U-UhڍPbeh2Fk0= -+iۤ!2lT Zt>/ϚܕO)̜4s>2=Υ_* [yIfO 5MaHu9@)/:o"\h;:zZOxuv[#vd{g?K-?hS,4cB b3;80DW P59/DYBpm}k+RBeoy(3 6= a!'c~ =n|W_ϚB]>kTai}t!7Jz>k)Y0h` }D`-pV־: fy07wDі5zQEPFeES\J>ƁOꇬj{(}ٟci3/:ȣSu40#dr{@-8FlѰ㥭/.ի4]ϼIqv՜Va _%Z}cCDQg1gāh b fBitSu# =3 :$8Tm81c#:eQmop-4)UP.TCO\P59ƹ̴ښhi60ERVJn}~ )ea%d~&fjDPi(PD|*M6|>+M>yP"5|Ct=Sn @`qiN%%yjj5Xv-P) EPh=n07`,:9# yv[*u}%ykU5ߖM!.tGZށx}LtV~᳏Y*bL6 @ށxetZs&UuJRMv%$VWF4#(|ijd=\ijf˙ngX*e&t*;xviV-$;̅ *",h,(!v0FP"ތi꧅:F|3u3Ԁ KBAmUVXE.*Qbj,;MuU*d% )mqlEb3r9ѨyE+ 6s&lyWwN⪫kgϊ//_ ]绞>+X ?s/?so?m?sos/?^?m~߹m~߹m;5~wb_m~߹e?q~_7m~ލ47 IdHoMfKm $ Z%nb16$I$I$m$i&rI o-@QSet0ݓimumm mmr/e I 2E4!¼w,">T}hZD4UM͌\,tq4'b Nܢx1C3 ÔvA6sjIjc3.FYnڧKOsB4p3hԤOOB@Z2]Eڂ+쫞{o}e;[;w~)m[mmmu5҇m}mmmmmmme}}}}}}Om-mO}۾oJl' ;)&mg3qE{lݎri۳ hv-̚Ri-8I[mlTⴧ-;ohmN~IQ3e: -^Sh[tQmA$IHH6mm'}jO??7m٦ڻ]𸧶 TE6S*!1AQaq0 P@?ny|_9|_9|_9|)|_)|_)|_9|_9|_9|_9|_(甾RƲӘ5T!~/[ }+wRCg1/ ̨j&*T yJRuf} {SO||Yx=Pjpe)(- n+?%LiM@YQ//K*+ʼnu'Jj%ϙfwTPfJ3sq Х(O7 ᶾJ>iep!F9?H h2s\gd1Ewݐ#v(] 0)o-kC)veǧΰ X L)X&g2f0 f}ؿg0@f> iaM,sdA)ov!3[^Y=[_NU4xl^ =+!Uw^2@Z>Ԅ9g,6L9ߒbym} 6m}`@|pM(os{!uf2ml^޹swX%^wX}[*Ke_`yXe^wV)~[_e~\5}ez˞.)ȮjV]_Cr%wbs~M fUucjiwX(eǴ4, 2/WLFFò,, 2!ei =r)c\2yaye6Z-KCI04f ?`HT&?a `h3t/:@b((.Rs] .)^z8kx=+f #Jwʳ/VN_Lʲ<"vZo Ee/Rˁ*:A{ 7*P@AԵ{DosCY`*5uJFVJ5(k^Ҏ11 t5iʃMkHXx`5gcX**< u zbVBi feО,e#ɘg$k2hRahK!jEFCR(tfh`\ҥ50*ٲUeV˭J6jXh-1 j6uj\B{:mqmYg~*@JFZ ʌ9l f,8c]K[+kua/]"7kRW_E? e~[͞&%EVmҢ{"&DDP[XMPG!3(ĵ"=iŚ?@x"{1=ڠJA8'P9,qcvc75|[>c/WyKWicoxC 1I_u%bk.NW~=&GU2pW1hzD",:`#:Ʀz FYs4,4D !:y MTi.EY`lRiE◲=Ӱ, 5"L"M;N&TIw ( &Xp]bDW΄F*ڣ7ig;2#i訩qsT'4M(1Mi`ofyfr6(Z55pRбdq{/Nq{.2< 2߱(l.:)݉7 q <^`$b`G60k955rzj=2sfSG4TC!eBG&*-֍MCED I{9ܤ7 a[I4gXSEt:â4-t#akhD$BDA.&hHIZN! - hH$BE"q3DБi L/hh)$c'ߋ#F$C´NlGAQB#i?45~Ƣ~5~_˅Lx'NUCqqp_Yy.X'Ó<$AxM@Ju]B!!(D~\/1V3}D Ү*LO,, ;Ŭ*bk$&QX5yBN#Б-2B$DuӃO 2 xz62 F9ongz66xm$6GjFtu!i^/UTov!Cބ45xm&DE\JB'DDA q hjRxM~c//hj \ZoZL6)^E LE 4YSE&Abb(Mt6QE)WCbjݣ(!1AQaq 0?jHI4ã1- Gǧ^*2ꉉF*oM5O' (֜іkV]F6)Uj||ȱ# 5" P10wea~p SEv[G05= ޙSHGz+1w,/.}8:?S. b2&tEbQ0^c-}|4|> ]tE9(-UW(A=Hc8Ͳ+C-Y W"[y*ҕ7m*jTwq?\Bݮ^;:B.4(HRi;!#1 <#DJބ9 1{R7n[{j#Nm$rup"3xw忒D2$59oLݕ ÊpS{j"{)TdT&D$fh@Xj+Gʚp\J@,l] H:>st$p:{s` ޶կtTWpta/v2%=n=wɚ͞{9sݝW=ye{ݞCUΫEv{=ygETA 74h/p9]8EC!^fP;k&bT49A~p\8N^q۷^rُv>|\Kk n7*ߜSx_*Eʜ^pX"O.]'T;,?a{qϾF,iA0@/:"ыB벝eN Hcybl$^Osk?nsinso.= ^to.띔}U)_DD ζb$r.m2\ksL&ho8 l(k4ƨQrRVxƭc7~skf!D @ҺbDv}L4\ >c5/ЀxʄgjD5unlFvCWX²1$U,*;DAJ': wL gjj$cT, ͐l~; JGݴ" ˁB٘?`Uu9"9[CbOsXN`X:`9%QFiM7c]+r1JPD|";ߐ;\Py,J8^ 6 ON!j#$ݵ 66P!#X3`60"R+ڡ`&iݜI]5VVSI r# X6w. ~9E"ժ>,mUj i9s*Kځ C,ƈLzRl٪^B@͑NJLaIE|H!g|V4ZSG +e^Esᥑ;mkE qq!*a}a\Z6 WFH-m=\U @O,b -2HV K[8P'e(7'e(\2٠v_8.8Kb7I0"b ]ߨuxǩ ~Rd9vƈGF4i>+/2,>6V#l{ɍp4?/o ,_Xr.6P/J"QA# j@ 3uOR8xEަFo~JdJ0[G 0 thH SŌ]; [*"%Uk' eRd4QCJXÄR| ttt;Un\etO~m7(3k4}1dSn]XxXigDZ;*Qcûh*b*j'Xe'ˀQ͋&0 &{2-jH ڹAAZ4ui"v`kebĕ8w.j& 7>ʰʄL;At$}geA"J*CK&=&LCxo5PeulLrЇ𖩱٥]"YUUUy4>-]!8yHآ1q7Ҁ ljϋC9cԄJyW!"Um#ʸ(9G{ڸmP%A`)aB4*jm^qUP"ԄKdy+ S&*B +`lbtBZ5$) @] ģRyT(b28QHH 4tRRmت܂Ѯ#.@,'y ]r0!Zj1ArY,Dj;;W'5ioZ]#)_ M 4-# +3wh3PCP2n詤 t6<a gh2vdjh(VR' - 9X@PidJ刘HҤ F^nֳh .^b7P #7LQ J`8Y Z4ou:`, "hn'Vn#c؍0<)@g ;mQ װf@ 0%'8KU&^&Ie8-f e@Q_0 b(UQ-L%&Qbt6<C()I8"HN5#GOczӨ 0 e p + b#ΐv*Y[hFl`jB" U4壇 ы"NMTûP@0FĄ>0oLHZX1{H@CB 3Ì5Aݩuhԛg -6 S@(KC@ % X 5Rrf@BTȞؐrGÝֽ,qT4 tS:ˠہȞQ!{mXиBڜnKXY&‹L%XPN90MI 1ᣄRl,6v+81 X7%Tۍ+f Rrh섚6 pE Y7f ۃ_*EM&bxy=)eڛ G =NHY cT-KsF`!Jh+tuAIQ]) Rr#U)U>ퟨ葍+ =+ID"n(cR "8Sjp!/J-d 2`8{@M(QY,wo5-wcvC(dQS@r*" 8P ]w ) 5E`[`ɳ*N˧z)o;C ^ي5uP#D2ŀlsظ6#1iWDRѾS{PiK]Ika7fLN ǝUj%Hc@&ե2v.7e>$$\lPٚ\2:(TYnE%gJF{; 7YP@8b]b ST;+Fb:08@\ )6W7k*zK;ry3": ^[Q291TϾo[$K%@ p95jYB9RG^YND,,mCu=s]hiOI0گY3ԗW MQ$J(z +uBa&VBAp@")+B4` Q إjf㸏 11UFu VVx"M "(` yAun;rJvxMlP]lE 4rZwR0h$Ŧ1HOgˌ\53q)SxS9<ފJDvw.AS @%ۺ48NV >HSVbH<x^]Jvthr⬂z0ٺsفX ۽5fr7!t]ij{Nq0zxԵq5߷DzWE&rgӺ-wL^ٙ$ ko~w㮛]{L"6\Z]\(Iy4M`iZ fp(AqU1P-ӂB t-HJ]:oDο?8|q5kb;ExTL *w*'wE^,UJfLxO/wJ! BSE^,UJ|DxPfM5W4,5]8  B{ͬmM֍SsLh_Ī(V'{5o BiP޶<`Y$"Vw\a`"Vw0"AN` ZpaZ~^V $UdNp"[چ $%jrC݉{']CY+.m 1hT^p*|k2fWfy?kyq3_Õg~chY> xWBCP:Ky^j_swPAVR@hR޲G#: MRj x[/Nw !۾b䗚 ^! +b*M B gbLv'@MML^5eӞ|W?>}s~0^/.~{} ϖx3:>=g_us?=8/:K%?/wyηs>{=5\qֳYzW Qz1^|^:z+4cj )Z9O9zOqp\hsTqGk5sZk'~q8YI֡a&NJv4 v7@y7IB ? `^DY@0^F8t{T<-#x6<|MN03G`!bBlt.,M1GsP))NZ߿#9Rqp aF>CēIM:x0s|}ol=e\ߜ#CU'ђX2+<5VRWwVΝg):4碳ye^m Tnl 2W=dNVozk'  ۏF,ʝsƀ~VT &mmҙSVڣK 07TɞbsƛI^zo!+mmSBiEa]&󮵛t|{l)xk5ŀ\>rٸ"=Qicnw@V?";8>^1JFN Ͼr WBEޱU>gcMIM%7|HOJPv͊k\%V>W%]R[.)"JoXrXWv1혪:lJT 1Pxŕo[˽t~=$%QMpc}sgg<ι|a ,ctyTbHk03f5^5-,wc G[ug?Uh[U+x98@\j=ǼKCd)(8m"#J^r`F\yjKLPk޺9f` [@P'CߍZǞx2CɉZ|vP\>'*Ţ#J c` }0u.d\>`C_ na-.9HE% d>2WEϾ@g5γAAu{7@ exqruFcJTUdӿ.O(3sCb7L޳$Ox9(O&"DH#ʔЄ &Pr\c^mC pPI8ӧ$hX gB!ZR48ߧ_TV!$X^0ykc (fTq\":upU '#@>744:z*őmFA0V/v~0h`'X?cycβ"N * ꊵ3dUZ"}j+ߜfT_9~1ץh+ߜX9Byn3r*W €<>r"N *G*yX 15> `U~2'N ~~y|lLWiY[<֢lUn\?xb)))y2rܧdy2LG~r<<yO9Ky?9L)9?9O?R~rL9O))y?9O')y?9O&G~r)y2L9O&G}#_L}sγW78kZu~?γsgǬ^&Q_L$_O80.9^2<ޤu1 g8.~~A? g.oswss>3~3ƵXY13?oֱz9Ӭ?Mz>!26f2c˸yǵ58nM96s16=M3}>oy=1۾h|6mC'siL7;hltC?fX=˦MVPrefind-0.11.4/docs/refind/utf16.txt0000664000175000017500000000001213140133747017213 0ustar rodsmithrodsmithfoo refind-0.11.4/docs/refind/automatic-submenu.png0000664000175000017500000007064712626644767021723 0ustar rodsmithrodsmithPNG  IHDRn|]c pHYs  tIME  IDATxy\Sd!6 XDwT*[*(*;VŝVP+\PMAJE@ !$6ͅ,~~̜gNw93ȋ/@ B.@ J)@ PJ!R @ R@ PJ!R @ R@B R @ R@B @ R@B @ (@B @ (@)@ J)@ (@)@ J)@ PJ!@)@ J)@ Jߙ xH$ \O??777O0OCCǦbcc8d``1&>>>$$3L^1{˗/DZCQ俷]޽Y[[fbb;d?r>LMMDۺus.]D&=<<<==??kkk'''+^WW{?رc޽{ɒ%~mon޼pv"~[ݻpСYȰhjjꢊ:u͛ꞞbuttLMMUTT>fÈD,XѣG׮]{qoY޼yeoY7kk7nu)))Soě7o 3^z322$zWWWs5SQQA`f0_|A+W,X !!!99dnٲE$av+W<RѧOh-AwQAwnè{''' &̝;3qpe]]]O8t۷o߾=w܏K^^h}}ݻw/_=z/RPPpС~X~̙(uAB… 7o4hOee;wzl622RWWc6LmmX,6mLLJJ:ܮ^*J.zzzF"HL&רm۶v_]zL&t&9i$555rgQTT>p@Ι3D"h4wwwSTTTZZ2<`__?~O/_|F^J_bŔ)Sf~Ydn55Ç߼y~WDh%xa1cq Ĭ_hL8Qaϟ?<&88X(v%)^lsssW^d2oaؠA|}}O|>|غueqq[߿zCWhRXOkk뒒k׮۷رc(⽼X,NHHHMM }6>}Hó'NE~xI@qqk׶nݺd.Z|>>>,$WW9sZ5++kڴiΝჹTOOO'Ǐd2HIIIIIq㆞ޔ)Sƍוꬬ+Wx{{p>lٲ.mppM:j1W2  |\Y߿v.^uVYzlls?k׮*633SEE%**Ç)ketWe!(ӓL&/]((@!CU6OqΝCK>>d2/DB#f;D522v횭={֯_O|i5kQouSZZ+}}}@P__xWX HK߽{fw477˧Y}CDq=-,,9 DHXv޽{꫙3gΛ7ãn?SNŋ!6~x p8]T?/Z("""##666xTGGgȐ!YYYFFF JfSV@TTԃ"""tv~~~x ٳ(=ztݺu.]'s̘1"!!ӵ`!!!˗/{znݺv9cccϜ9sEy{{YF___sss@qd\ŋ###eqN{˗/?~}Wb(+N߿徾˖-•XqK.,Yjo}Og~#S\?}8٬CP(666fjjj:ޗsk٬> XYY%&&&''<ŋy"H٬_i TWW7.>>6>>~ǎu?Þ={H^qS~x=lذ={899=}E4M==NOl pV_͛7?b``_EEE\Ra|?/* Lvp8cccemcccM>]SSSqJ#Gv>q=rE/^tƍ2Xop?zhjj۷[#hѢG}ASh4??.\pҥw|(P]]-(sll6x{lԩyeUh'55ظ]e,**:ryxÆ ߾}[__ThSb٣azzz8~x$1eB콾JOX,:˻wp}BQ2e;*{gȐ! c ʆUUUzzzퟗbvmgnnNӗ-[rQ e2 .T[pUUUׯ_'zyy9sf 8Pf=zb͛7lp0 ÃE#F{P.~՝7o^_kll|?q{qAAOOO*H|||tttQJzee/Pmnn ՕnٲQ^#~ΝbUPP Q1ct1ưk.SSӖ?`|E?~yf-PɑQx۶m< `ٱyyyUDBLN{?ZZZn޼)PPUU888>99ð7oN<W,e;KKK{g֬Y555^jxbebyɓ'~ ŋ>2}ĉF%tҥK===?cJJD"1bT,/ٳx*&&槟~jiiǗoذիW E*ZZZٳGоK, A///|;dIIIϟD{UWWx $ JW*._G/;vL>BfoozⅧgLL?/)lذAOO6̃( ;vƍv/'u9;;]_~x'OvomٲecbeeE&|8pK ĥRիW(wk|FRZZZW8 ={}ZTTשZYY%&&(?zˎBۥxӦM]ﮟ!(O;vxxxÎ޽Ǐ_x˗/ҘL&A:}ΝSLyB!RT:}tAOnll,2?rHrrrbb" WӧO'(˦zzzSL!zj<۷~>(?EGG2; hGM8qҤIMMM?VQQ!^eWh~@>m/^@/|?[Νkhhx% =@ ('C@@ d^!x!ݎ@@ 8*|4x<% Brvvd.066III=`gghkk+%ɟɽrʆ GŸ߿p֭{988:tg222,,,(155mJSRRJ)̜9EOlmm###sK #;<5X,p;wD"ȑ# ,۷nnnϳgFJfdd(+ rr>a1c?P ;w%K\=h4 7dȐ'`0,111**dz{{*:k,sr\<쬬 ?'''`PH_lY]]ɓ'lvxxx@@2?(_]]-z Q)3ᄆ:;;4~#G]EYQx t@_Y of=<9d"~ IDAT++cǎ&&&FDDxK޽s?~<%%{׮]yzz@{NELLL^~}eSSӒeZ5++kڴiΝჹ |h[z!(K$7BaLL+"^^^|>?11QYzoUkjjZZZ!HǏ'>`hC766r|wwwhѢgϞ ICBBlmm FZZZ.Ya7004iFccS444W YĄfoٲe̘1555,\nmmbzz!O|IHHǏ_bEtttCCD":t(-NV[kݻ9syns"HUU ;?ȓr/^(icce9::vqN_ 1:::C 222b0;\UU%tJ\{O>=..n̙=aXo~grrrjj/^uFӧOrرc\[6l@SP')^.ESSǗ+]:},q3B v玪* OXY|ح^^>?}9rEŋݸqg899رc͚5K,!^CC_t@]]@'+(󳾾>@vfjqqq @BgtxmgnnNӗ-[rQ e2 .T[ǂUUUׯ_ %vOl_!qqqðf#zpNZ`ALLLxxE:m۶!!!l6;666// qAAOOOqFnfffiii(׳O|Ja>;N8bD"N_t' bLIIH$#F(Kx)))K{!Aa~ NLL,//'ɺĤ0, A.{MA/_͛ܿ?00P>6khhxŋw -..P(fff;v @ܹݻwӦMsttܸqÇ_HG"qDDZ!֭;xP(S! $DI>uuuݿ?֭[spp8tPMMMϬeddXXX455蘚ᡣ}OOϩSCۋ;0ޅ]z!H;'ROBWZ&F0UV`-F Ԥ#U#2BFGA(@H1Hp-3g +//{kbkk,rz @)/LI۪%-ҖI@ kXR,7<'H4!T T *_ =Z 8i }}2B; X,p;wD"ȑ# ,۷nnnx|rPTӿsM8O ͕/77L&:r}}}핕lٲ:__ߓ'O[[[GDD̝;wɒ%+O`۷W\yySSBY~ʕ+{F јGG >}oqqq!+O.{Ἴ< ag T۪٭r &iE[) QE2V3 kS bR ibzLFTJA(4C ڠAAm&[?^MMMݾ}{VVVCCÎ;F|?GGG̙3t:]Y: ##cӦMiiiL&П~֭[QQQGFQS ݻw}||xemVVV6h //W>y$55DRرcKKKjMM̓*,ǧZv _|[CC#((觟~zl|׫l޼Y(?{~_N.UhEQe~طo;vN/((شiӣG`g & PcIÓ'kGUGԧ }\̟k~o\h(n-<T_IoZ7߭Y͉ܩZQ($gFadƍPbdOLLT ;E^|t!333{{F.,'k֬111a[l3f 0hbG[[L&"ӓs:t:J~&&&nnnZZZ-~iiiAD"? P qYkYaKayk9#$g&BE" z-x- ,*Ea5I XI>>|}@UO5Tm`@ͽNBB@ 8~+$СCotwlHP(p8syazVy ---ǩm" ΐ!C Jh/_c!$I__}~Xv޽{E=)Ji?Q&\T^*,}%x% 0п֊11чJQW_'ֆU**D-$!C  1FAO7s̿D7oRiӒByo'=~@@ׯǎe˖>P(Oa-)*11199955w/^ĵ<^_UU5r9r/ qFYYYZZL!PJ~mE[m_} ~mQKѝ;ZZ?bvmgnnNӗ-[rQ e2 .T["UUUׯ_'c6ѣGC QSS.Dd)ߤn2Ǐ1ۖբrF9*@'N:88D":iӦٳgo߮zjD2bĈuuutȑ#OUf޽?aΜ9rƍŋ+^?77wŊR2<<\6M]Y#G(ҥKΞ=K&uuuLMMag {^DQg5ej~$iϱ܏pd9G]a===[=s5-[ߣ [YڜѐGӣꁾ_)@ "*JeyMyÜhaߴev>rܹ<2~kkk#xe]&okʫn# 1._62y!J Fu9M9Y,8UFZThd(wEQT"32Zˤ Ae0[ __[qqR.TߜoD3R1 j @ VbqÆ”?6?rȇu?RT mPC`@ Q *y&O+d W-,,kaaQYYsիWϙ3g 7mfpB٦? @^^AX ̚5k2DGG[XXwW\ikkkaa*`ӧ;v/5k, ;;ssXXɓwn'N_Rh^ýDn]o5$''۷O:::***>%%%6667o}Af6zjWWgddH$׻2k׮q8 Sr>|`*ʕ+ ,HHHHNNf2[lFFFTtӧOw%H$:p =ztڵǏngddXXX455]]]nݺu=CC_ѾԩS{w>8vu?RD"t~'M&鎔VU|T;W622cf7j(d2^~M0fHNN޶m[^J&t:ɜ4i~ʊ2fQTT>p@Ι3D"h4wwwSTT$ɓ֭15=V,O6L&kjj&%%h̙(v%ϐO.\sH$9rߐ!CwZv|ץΝ8q"~~zz}Np\.yyy13fW^~_B;ϟ?<&88X(zyy9;;+ rјGG >}oqqq!^Wf Oh(#DP{*$2 ^7bqAruu3gN``UZ[[Mvܹ>+ؖ amm]RRrڵ}YYY;v EQOO)SȲ?~@& FJJJJJʍ7L2nܸN/D*fee]rۻ~hkkp8zzzvppXlY3޴iF#6b\0 KHH022244ĻN\x1::?!!a֭s?~<%%{׮]UUUO޸qFffJTTÇ1 S.5jTvv6{Avv6nu>>d2/D}qӧGϗH$7noȘWWWE&|~bbVoذa޽CQ4++˗߿?et>iiiAD"?͍ظRRv(c``0i$ SN988888hhhQvT*711qssҺw^w=>A?]?/^W,_:W`|_SSEѾDpѢE鮇+_Tmkk{M_,1Ƚm%0L ǣ>cjll9sfF4M[OOS)z'O]gbbbPPЅ "ղI5PaÆ)S):>(Kg xu``رcӻ>7ܩ3":::؎=7oRiӒBG^++T___xQ~}M;jI/vH&:s? tT$ůRuP"a0a9(o߄YhѣG޾} /SK.\tR@AAANNP2 Z^Q稪l6n:u555ʪNjjqz9rvtth4Çݫ̎> ӻLGGǓH$y)kb;~ECUUd|CCC "{W p8ccce֧c͇7nܸ &v}9ŋnܸQVV& +>E; !n|>jȑgw]J)R@//kj{]… ?Et|] @"(*J ;/^(+ݲec:~ΝbUPPBl'33s̘1]XHk.SSӖ?`bI"tuu Pɑ m۶TTTX-#E"Qyyypp0qW833aî_}6377˖-r(2̅ *K> c=2dZ^^{| q8 Ú#F {Kcccee%>z(Ś7o^wIl~_<Ѷggn. s\DѸ@0D׿Ƌɂ'md}ld6TSSP(]\]v^n]^^BcN>]PPxb"u uY:˽y& ~~~˗/̀߿___swM6qƍZZZNNNe˖u)SRSS[ZZP555ݺu\W1^zGb1)));w:[f IDATmllvٕ~$_{nWiiiMM͛bٻwr3f̰`XwdddS(33;vى⺺:---sss|]n^^ށx<ްaæMv$reߟlgYH/Ü8q">>bD":tROOOAb?"HFG ק#>|cǎR|%rJhhr2.PWX5}te/eB;+Vx$ FDD+ 7(k 6zBHRKK={9 W?r2?JlrqݦUNu(R2 F?-Y6  Y9?(ԁTQQ}'wlذAOOeGT"R#b|̊dUc4 08f.E$Ҁ11].D"!ERH@i(l)bRL 4Ӝ[u3tӊ[[[Td0 \.~#'DFe"_#^Cdq ӟh#..W(QܹsyyyݳB=+DD"QSSooM6*O6+3p8T*UEEB0 <T*bX,H$5^^LS d@Vf`싋 k*eB H^|/8jmm@LG T񵴴TUU$7țWl=>TPkQ3EV㬞>mSm !UB _V^t*J" @ :K)@+l)bWZ4Fmmm555p7ZV(vh6f:W ~? ©_dǦ?Ap,M!`@a.ƐZ^"gC(( H bEPwADERsX,~@ ȦfL&SCCCKK`RGB '(-"Iœ*@IU+mmm:^EM)RV'*b`.RT0̡5W2\XX8>0]NM1oON 2Fڊ! P=EBҢ9=x@~71b8D5770BPTMMM`0L&TWW w!DOJqmkk<9%7G{ːDwT(\*j-ŵ.tIIsZZZFnަ"H@(b 1aXeeI$җ_~IP41*R܍MTP9s~W$*\f%SPL&H$ B&T*>gFt>$RgH#ܽ{722?.TN>]CBB|>ɴ9S xH$ ?[Oߟ} P6?կTqL Q6BT$Kw9),,4՝#lLH$*,,|FzNGQŋRH1 IIo+&jjj#\P?9d2L***T*FCRUUULD)J &''ۏ}IIڵkM;ٖa}6lXff&~'N}}̙3cbbRM***ԩS---GTƕ+WVZ$w޽e˖8l\.722/DGG^Ӝ"7nlnn^bE3226mڔ֕,j``}[nhg:thzzz=w_]>a~T:[ EpC!5״tfw<+a*@!V `ڧx`VS,%@5|iXUhjj^,HRYbq Dr}}1U& , _+ vQh4\Se ^YSǃzzz,D"1L''JReC}mEW^%SѤIS,1k,砠 wwNOA3gDhEEEǏǿ:yurwӦM#ɚIII.9sfXXXyyyϤ. 0)x_ߜ`4J7=$apPN=YU5jh4Z ?a"vaVѿB4VFnSVCU)}mmh_C"d;D"|p\kGڏ\Pe 0@]]7 LJe:*SS+g}7~Ztttܻwo͠1u~L^=e0|b [VJR)d4!!ӦM@LLݻwM&[VVt!???¨5iZ|Je?~޽{ObŊi_t)Bb SNaDވȟE;t:T*JJJ|~\\SRR֮]KjA&I2//o8M^߷o߮],;rȉ'JKK?#|<''_WZZڀ.^i&XܿRDN׳eooh"sb^{H@*JΝc&''_r%==/XtX,&>7w] @kb)sd2A~~BXdɼyNjɓ-,?22rر~۷kjj/_~%$/6>1=/2{'XMqBdcਜ਼` ?ؘ3!FP`l/oggNʴe@ x]$vrrׯ+ l>SA(_A6h$A?A*l?oggt85sL&3<<@#4Meee@@@ PTo% `0Y'NĸXUV)|sڽ(IVcȑ#ccc{\ܼy3..Dȟ~B^{o|wwc+?<<<<<<2_s܇'<HFl#NlcS5Ft%5L&iZ;wد Gv ;owS=KMSZ~kWiWq! Bpf׃͵OtT/YȸzjHHHQQQpp0n"ggA FdwV:xd[\_/vF3m%KVC2/p677Ҧ-ӶO|>ݺK7zjBW.U*F<;wvC}}o[oIݦ/w)!!!b k+v>l۶m%Ǐw]O===m6gΜI&hVjoor"G׮]۱cz'''>|}FH'CW?~|rrr <@x}1nqvv'Lke?I}gϞp|0p#GXH=k{{ &dff1B&>}zՖ^beHѸ-}5_&/DT'AvѨP(8zNdr$/#˾|WAVԱqFҠ|{waγ"Mx,lDŞe'YU(:999?A tcĄx}hrIwvW/BGFF^tݻ[yrJ%LO]0f͚5oRR[.$w&"***99ɓ3<ܹbΜ9o={lk͍CskW=\;8ik86bD-$QXU'clưHQJ~uGP54Hd `B$*4vBĐ Ġw: ނZtttfkgg؝ 7ƚfF3۵ebv3JG WUU)'O!!!y˖-/􆆆 dUvt4G\\ܹs.^HdYYYUUUttrJJJŴVݴiӨQju$ed2]\\,LeF} ***vCmذ(55^"TVVZH$yVKII/.))yO7[_gΜ>>>|>2 4P8k,sǻ\9SJnnT*%Izvĉn_=wsk=-Gk> =vD%VkkkdRVNb}-@ JJAID< x` b@#^*#ؗ$ܶLޒn3L ;3p`!H iU(uURM<;w})1L<r7mTTTTXX_+˖-O4޽{7(=z o w(+Wnܸ1 $ .^wށy襁 fه v׭)j!zaccsΝPy($oIepsF QyW=Gi llAk ˗~QE\-3V*6pxd2;:: Nhj sppxWB!)SPժ궶6BP(pFNp8 Žhlrcl.Yi/-T#Ν;.N-,HIDfj4?PrBaSyFccBxLPWٯx<*-VMT2rQAAvM}1f$Ilg 2DJjͯhg"aH9+336@KJJ,fIVp( "IDATQ(z0Hrq#*'%xԴwg5GD‚M={y ggQF4P]])RZ8Y",Y$&&z*Niii'NRi}}>$,gz ;{P(\~==L&;v}]v"Q_xZ+pT9zs'X?\a/):`0QZZ:5ɻcE$rֺH[/R[(c,5)Yn*9`nT Vəxq<&) ̙'l''&&2ݻ%%%?blقرcy޽AXbi8*," O<)ƏoMXVVߋvtRT$%%%ϟ?<)))k׮rO#$ɼz~߾}~ G޲eK^^޻K9t 7m#Pii)^^^^^^edee]x1<<<%%$Isb^{ۙ-薕HҴs☮ɅgΜ:tҥKj=ϼy󼼼x9sh4+W=&dzss׵|92wM{/d~~~?};,Yk׮j fΰl| 퐒.\o߾3ggRjbJsvvׯT;;;&5\L;;ul?r&nS?}X)ܿJH/E֗n /((!FSYY`.}Ov5z3g* LfO6l؀&11QVݻ[Yn]``իCCCzn%ԩ۷߸qnݺU[[;e/]QQLffqFaT 333... Օ=55566sHH@ +:::!!ɉb7N>ů燇O>`0Y'NĸXUV)|s{Z=OOQVVV[[{֭~ױѭ=}zY(O\hcccϟ?W[h&Z#G}) tk*NhgꎎNw]B89R__Qtp;|>ݍ=}pQ/W ȌW1w:::'٬,gfɬ '''|<88c͛q/ ={,[oN8qo^^=_IRSS.\H{ D>}ѣ놆aTÇwd#G;vwo|\."vyyy*j-nmm5 C |77H${!F*޼y344ƍBo-ȑ#tssJ}[vXt۱iӺ&bzRHE k4x1i'o-\p[,bp>l۶m%Rz) }Փdzzzn۶mΜ9&MѬޞҳhDn׮]î3???99T˗/766RjfǏONN6YNuu5BW-x}1nqvv'Lke?>`믿ƠFCOy?_~v~;9?{ >9rB]JmєkJhz5.Th!j߂u=޽J7\.W=}3%v%5kּyBUUUjzر<_W^g?XQkTz^$Y^d0MMMtO\pã\=ݻ{tz GDDbΜ9III&qssCoS? P\\l`bzn iwV(*ZRR֧kz{{3&̞=c{P*=:thO޽{ƍQQQQQQ$**ʕ+]9ٶHj7xU$Q(RDAG3f`YpUUR,..~1!eΝ;_ ?3A...t#""CJ\\ܹs.^HdYYYUUUttrJJJ fjM65JVW>A"ٹ`2...~J=ʕ+ATTTPڰaCQQQjjj}}D"ɱ2B$ݼySեX GXnB HJe,oΔ+JIlooGyyyN?ܰw+kr8[wz`09+˫P^jGPJY;Ғv7njQQQyk0^jN?.ɮ]`0rrrΝsNo?.Z""""((hk֬y뭷222_*?lذC8p QFY/` 6vZr%8p 55u׮]iii_JT꺵 lݺ^jUMMFY~}ttuuְ'nذa˖-NW_f٣G3f |ׯp8>>>/w;w>}gxx_|]PP`_Ν;gBCO>Q(<$AAp8<Tv3 Qo-K("*i'>]tѥ1x9tPee%ŪرcG@@߳+ihW^Y)%7 M R R H)H)R R H)H) R R H)H) R R H)H)R R R @o{SvIENDB`refind-0.11.4/docs/refind/bootcoup.html0000664000175000017500000015222613372346574020257 0ustar rodsmithrodsmith The rEFInd Boot Manager: Keeping rEFInd Booting

The rEFInd Boot Manager:
Keeping rEFInd Booting

by Roderick W. Smith, rodsmith@rodsbooks.com

Originally written: 4/24/2016; last Web page update: 11/12/2018, referencing rEFInd 0.11.4

This Web page is provided free of charge and with no annoying outside ads; however, I did take time to prepare it, and Web hosting does cost money. If you find this Web page useful, please consider making a small donation to help keep this site up and running. Thanks!

Donate $1.00 Donate $2.50 Donate $5.00 Donate $10.00 Donate $20.00 Donate another value

This page is part of the documentation for the rEFInd boot manager. If a Web search has brought you here, you may want to start at the main page.


Once you've installed rEFInd, you may face a new challenge: Keeping it set as your default boot manager. Users of multi-boot computers have long faced similar challenges, because most OSes provide mechanisms to keep themselves booting, even at the cost of disrupting other OSes—or overriding your own choices. On this page, I refer to such unwanted changes as boot coups. Experienced multi-booters know the tools and techniques to avoid or recover from boot coups. If you're new to the EFI world, though, most of the techniques you may know for helping with BIOS-mode booting don't apply to EFI-mode booting.

This page describes tools and techniques you can use to keep rEFInd set as your default boot manager, or at least to recover it as the default boot option if something else takes over. This page is organized by OS, describing the tools and techniques you can use in each OS to recover from a boot coup—or in some cases, to prevent one from occurring. I begin and end with information on firmware-based tools, though. Chances are you should not read this page straight through; instead, peruse the Contents to the left and pick an OS and, perhaps, a recovery tool or technique you wish to pursue and read the relevant section. In most cases, the recovery technique is fairly quick and painless, once you understand how to do it. Note also that, in extreme cases, a full rEFInd re-installation may be required. This will be true if something has completely deleted rEFInd's NVRAM entry. It may also be easier to re-run refind-install than to learn about esoteric commands such as efibootmgr, bless, or bcdedit.

Evading the Guards: Performing a One-Time Boot to Your Desired OS

Most EFIs provide their own built-in boot managers. These tools are primitive, and in some cases they can be difficult to reach, but they can be useful if you need to bypass a new system default in order to boot an OS that has the tools you need to control the boot process.

On Macs, holding the Option key (or Alt with a PC keyboard) brings up the Mac's boot manager. Typically, the Esc key, Enter key, or a function key (usually F8 or above) does the job on UEFI-based PCs. Some computers provide a prompt for what key to use to access the boot menu, but this isn't always true. Sometimes the keyboard is disabled in the early stages of the boot process by default—part of a strategy to speed up system boots. Disabling a "fast start" feature in the firmware may work around this problem. Getting into the firmware can be a challenge on such computers, though. Microsoft provides a way to do this in Windows 8 and later; see this How-To Geek article for documentation on how to use this feature. If a Linux distribution uses the popular systemd initialization system, you can type systemctl reboot --firmware as root (or using sudo) to do the same from Linux.

Once you've found the built-in boot manager, you'll see its display, which is typically a text-mode listing of boot options. On UEFI-based PCs, the user interface is typically similar to the one used in years past on BIOS-based computers to select the boot device; it's simply been upgraded to include the descriptions held in NVRAM for specific boot loaders. (In fact, prompts are often outdated and misleading; as in the below example, they may refer to "boot devices," when in fact most of the options are EFI boot loader programs, not hardware devices.) As an example, an ASUS P8 H77-I's boot manager looks like this:


A typical EFI boot manager display is very
    rudimentary.

You typically select the option you want to boot by using the arrow keys, then hit the Enter key to boot it. If rEFInd is working but has been overridden as the default, you can select it; or if your preferred OS has its own option, you may be able to launch it directly.

Keep in mind, though, that some of the options on the built-in boot manager's menu may not work, or may work in unexpected ways. For instance, you might see options to boot hard disks in BIOS/CSM/legacy mode. These options might not work; and even if they do, they'll boot the computer in BIOS mode, so you won't be able to use the tools described on this page to correct your boot problems.

Staging a Counter-Revolution: Re-Installing rEFInd

The most general, and in some cases the easiest, solution to a boot coup is to re-install rEFInd. If you haven't updated rEFInd in a while, this approach has the advantage of providing an update to rEFInd (assuming you first download the latest version). The Installing rEFInd page describes how to install rEFInd from Linux, macOS, Windows, or an EFI shell. The refind-install script preserves your existing refind.conf configuration file, so an upgrade should not affect your customizations. (The rEFInd icons will be updated to the latest versions, but refind-install moves the original icons to a backup directory, so you can restore them if you've customized them or if they've changed and you don't like the new icons.)

One possible complication to this approach is if you're stuck booting in an unfamiliar OS. In such a case, you may be able to boot into your preferred OS on a one-time basis by using your computer's built-in boot manager, as described in the previous section. The trouble is that how you do this varies greatly from one computer to another.

Recovering from a Coup Using Linux

Linux's primary tool for adjusting the EFI boot order is efibootmgr. If you installed rEFInd from Linux, chances are you used this tool, even if you don't realize it. (The refind-install script calls efibootmgr, and this script is called automatically by the rEFInd RPM and Debian packages). The easiest way to do this is to use the refind-mkdefault script. A more complex but flexible approach is to use efibootmgr directly. I also describe some steps you can take to make it less likely that Linux will stage a boot coup to begin with, thus obviating the need to perform a repair.

Using refind-mkdefault to Adjust Your Boot Priority

Since version 0.10.3, rEFInd has shipped with a script called refind-mkdefault, which uses efibootmgr to identify rEFInd and set it as the default (first) boot option. Use of this script is quite simple: Launch it as root (or via sudo):

$ sudo refind-mkdefault
rEFInd is not the first boot entry; adjusting....
Setting a boot order of 0000,0002,0085,0003

The exact output of the script depends on the current state of the system; it might also respond that rEFInd is already the default boot entry or that it could not identify a rEFInd entry, for instance. The boot order shown in this example is meaningless by itself; it's the boot order as identified by efibootmgr; for details, see the next section.

Instead of using refind-mkdefault manually, you might consider running it automatically at every boot or shutdown. You can, for instance, call it from /etc/rc.local or create a script in /etc/rc6.d that calls it to have it run when you start up or shut down the computer, respectively. Details, however, vary from one distribution to another, so you should consult your distribution's documentation for details. If you use it in this way, rEFInd should correct a boot coup caused by an update to GRUB; however, this repair will happen only after a reboot if you call refind-mkdefault in a startup script. If you call it from a shutdown script, rEFInd should correct such a coup before it has a chance to cause problems; but then it won't run if the computer crashes. Note that refind-mkdefault does not touch the NVRAM variables if rEFInd is already the default boot option. Thus, calling this script as a regular part of your startup or shutdown procedure poses little risk of causing problems. If you decide to stop using rEFInd, though, you'll have to remember to remove the call to refind-mkdefault from your startup and shutdown scripts.

If you've given the rEFInd entry an unusual name, you can pass the script the -L name or --label name option, as in:

$ sudo refind-mkdefault -L ubuntu

This example moves an entry that contains the string ubuntu (case-insensitive) to the top of the boot order. Thus, refind-mkdefault can set any boot program as the default, so long as it's already registered with the firmware. The script searches the entirety of output lines created by efibootmgr -v (as described shortly), and so it matches on descriptions, filenames, and even the obscure EFI codes that identify devices.

Using efibootmgr to Adjust Your Boot Priority

Adjusting your boot order using efibootmgr is a two-step process: First you must identify the existing boot entries. With that done, you specify a new boot order. You can identify boot entries by typing efibootmgr alone (as root or via sudo):

$ sudo efibootmgr
BootCurrent: 0000
Timeout: 0 seconds
BootOrder: 0002,0000,0085,0003
Boot0000* rEFInd Boot Manager
Boot0002* Windows Boot Manager
Boot0003* Windows Boot Manager
Boot0085* ubuntu

In this example, labels were clear and accurate; you can see that the BootOrder line identifies a boot order of Boot0002 (Windows) followed by Boot0000 (rEFInd), then various others. If you're in doubt about your entries, you can examine more complete output with efibootmgr -v:

sudo efibootmgr -v
BootCurrent: 0000
Timeout: 0 seconds
BootOrder: 0002,0000,0085,0003
Boot0000* rEFInd Boot Manager	HD(1,800,113000,2491a00e-2a89-4dc4-af21-34c436c8f88a)File(\EFI\refind\shimx64.efi)
Boot0002* Windows Boot Manager	HD(2,113800,113000,8b0b6d94-06af-4894-b9de-13ca354714a5)File(\EFI\Microsoft\Boot\bootmgfw.efi)WINDOWS.........x...B.C.D.O.B.J.E.C.T.=.{.9.d.e.a.8.6.2.c.-.5.c.d.d.-.4.e.7.0.-.a.c.c.1.-.f.3.2.b.3.4.4.d.4.7.9.5.}....................
Boot0003* Windows Boot Manager	HD(1,800,113000,2491a00e-2a89-4dc4-af21-34c436c8f88a)File(\EFI\Microsoft\Boot\bootmgfw.efi)WINDOWS.........x...B.C.D.O.B.J.E.C.T.=.{.9.d.e.a.8.6.2.c.-.5.c.d.d.-.4.e.7.0.-.a.c.c.1.-.f.3.2.b.3.4.4.d.4.7.9.5.}....................
Boot0085* ubuntu	HD(1,800,113000,2491a00e-2a89-4dc4-af21-34c436c8f88a)File(EFI\Ubuntu\grubx64.efi)

Much of this output looks like gibberish, and is useful only for very advanced diagnostics. Note, however, the part of most lines that specifies a filename, in parentheses after File—this information can help disambiguate a misleading or duplicate name. In this example, for instance, there are two Windows Boot Manager entries on two different partitions; each boots a different version of Windows.

To adjust the boot order, you must identify the rEFInd entry and then use the -o option to efibootmgr to adjust the order:

$ sudo efibootmgr -o 0000,0085,0002,0003
BootCurrent: 0000
Timeout: 0 seconds
BootOrder: 0000,0085,0002,0003
Boot0000* rEFInd Boot Manager
Boot0002* Windows Boot Manager
Boot0003* Windows Boot Manager
Boot0085* ubuntu

In this example, I moved rEFInd to the top of the list, followed by ubuntu (GRUB) and then the two Windows installations. You can adjust the order in any way you want. You can also omit items you don't want to include—but be aware that if you omit Windows entirely from the boot list, it's likely to add itself back (at the top of the list) the next time you boot it.

Preventing a Linux Coup by Disabling GRUB Updates

Once Linux is installed, the usual cause of a Linux boot coup is an update of GRUB. Such updates are relatively rare, but they can happen at any time when the distribution maintainer pushes out a version of GRUB with a bug fix. Therefore, one way to prevent a Linux boot coup is to disable such updates. Unfortunately, the details of how to do this vary from one distribution to another. Furthermore, disabling such updates has its drawbacks.

One problem with disabling GRUB updates is that you'll be cut off from the benefits they bring—GRUB updates are normally distributed because they contain important bug fixes. These updates might even be security-related. Of course, if you're booting via rEFInd without involving GRUB, you may not care about such updates. This possibility suggests the first way to disable GRUB updates: Remove GRUB entirely.

To remove GRUB, you must employ your package management system. For instance, on an RPM-based system, you might type:

# rpm -e grub2 grub2-efi grub2-tools

On a system that uses Debian packages, a similar command is:

# dpkg -P grub-efi-amd64 grub-efi-amd64-signed grub-common grub-efi-amd64-bin \
  grub-common grub2-common shim-signed

The details of what packages you must remove vary from one distribution to another, though. (The preceding examples are from Fedora and Ubuntu installations.) If you're unsure what packages to remove, you may need to use your package management tools to track down all GRUB-related packages. GUI tools, such as Yumex for Fedora and Synaptic for Debian-based systems, can be very helpful in this task. Unfortunately, you must sometimes remove packages that you might not want to remove—for instance, the preceding example removes shim-signed from Ubuntu because shim-signed contains a dependency on GRUB, but rEFInd can use Shim for its Secure Boot support. Fortunately, if rEFInd is already booting via Shim, removing the shim-signed package will not remove the shimx64.efi binary from rEFInd's directory, so the system will continue to boot—but you also won't receive any Shim updates that might roll along.

Note also that removing the GRUB packages will not remove the files installed to the EFI System Partition (ESP), so rEFInd will continue to show a GRUB option, normally with an icon for your distribution, in its main menu. If you want to remove that menu entry, you can delete the relevant files, normally from /boot/efi/EFI/distribution_name.

An added bonus to removing the GRUB packages is that you will no longer have to wait while GRUB's scripts scan your system every time your kernel updates. (Such scans can take well over a minute on a system with lots of installed OSes, which can be quite annoying.) Of course, these scans keep the GRUB menu up-to-date, so if they stop, GRUB will eventually stop working, even if you leave its binaries installed on your ESP.

One limitation to removing GRUB packages is that your distribution may try to re-install GRUB. As a workaround for Ubuntu systems, I use this dummy package, which claims to be "GRUB 3"—a version high enough that no GRUB 2 update should ever try to displace it. My "GRUB 3" dummy package contains nothing but a few empty directories.

A less radical approach to preventing boot coups related to GRUB updates is to use your packaging system to lock the current version in place. You can do this with Debian-based installations with the apt-mark hold command, as in:

# apt-mark hold grub-efi-amd64 grub-efi-amd64-signed grub-common grub-efi-amd64-bin \
  grub-common grub2-common

You can achieve a similar result in Fedora by installing the yum-plugin-versionlock package, ensuring that enabled = 1 is set in /etc/yum/pluginconf.d/versionlock.conf, and editing /etc/yum/pluginconf.d/versionlock.list to include the names and versions of packages you want to lock at a particular version.

Recovering from a Coup Using MacOS

A boot coup that leaves a computer booting straight to macOS was most likely caused by an update to macOS—either a software update that installed a fresh copy of the macOS boot loader or a complete re-installation of the OS. In either event, the solution is conceptually similar to the Linux solution, but the tools you use to correct the problem differ. In macOS, you would either use Startup Disk to set rEFInd as the default or use bless to do the same.

Using Startup Disk to Adjust Your Boot Priority

The Startup Disk utility appears in the System Preferences tool. Unfortunately, it will likely be useless if you installed rEFInd using refind-install and its default options, since Startup Disk is designed to switch between macOS installations; it's not smart enough to detect a rEFInd installation and re-activate it.

If, however, you installed rEFInd by using the --ownhfs option to refind-install, your rEFInd installation volume should show up as an option in the Startup Disk utility. You should be able to click on it and then click Restart. Note that the name of the rEFInd volume may not be rEFInd, as it is in this screen shot; the name will match whatever volume holds rEFInd on your computer.


Startup Disk may enable you to reset rEFInd to being
    the default boot program.

As with most of the fixes described on this page, this method of recovering from a boot coup will not protect you from future boot coups. Fortunately, macOS updates that create boot coups are fairly rare, but you'll have to resign yourself to the fact that the problem may recur in the future.

Using bless to Adjust Your Boot Priority

The more general solution to resetting rEFInd as the default boot manager from macOS is to follow a subset of the manual macOS installation instructions. Unfortunately, some details depend on where rEFInd is installed—on the ESP, on the main macOS root (/) partition, or on a separate HFS+ volume. If rEFInd is installed on its own HFS+ partition, using Startup Disk, as described in the previous section, is likely to be the easier solution. For the other two options, you should first figure out where rEFInd is installed and then follow this procedure:

  1. Open a Terminal window in which you'll type the following commands.
  2. If rEFInd is installed on your ESP, you must first mount it. The easy way to do this is to use the mountesp script that comes with rEFInd. When you run it, the script should tell you where the ESP was mounted. You can do the job manually by typing mkdir /Volumes/ESP followed by sudo mount -t msdos /dev/disk0s1 /Volumes/ESP. Note that you may need to change /dev/disk0s1 to something else if your ESP is at an unusual location. Type diskutil list or use a tool such as my GPT fdisk (gdisk) to examine your partition table to find your ESP if necessary.
  3. "Bless" rEFInd by typing one of the following two commands:
    • If rEFInd is installed on the ESP, type sudo bless --mount /Volumes/ESP --setBoot --file /Volumes/ESP/efi/refind/refind_x64.efi --shortform, adjusting the mount point and exact path to the file as appropriate for your installation.
    • If rEFInd is installed on an ordinary HFS+ volume, type sudo bless --setBoot --folder /efi/refind --file /efi/refind/refind_x64.efi. (Adjust the path and filename as necessary if you're placing rEFInd somewhere else or using the 32-bit version.)

One major caveat is that the bless command will fail if System Integrity Protection (SIP) is active. This feature is part of OS X 10.11 (El Capitan) and later, and you will have dealt with it during rEFInd installation if it's active. See this page of the rEFInd documentation for more on this subject. You can use any of the procedures outlined there with reference to installing rEFInd for dealing with a boot coup, as well.

As with most of the fixes described on this page, this method of recovering from a boot coup will not protect you from future boot coups. Fortunately, macOS updates that create boot coups are fairly rare, but you'll have to resign yourself to the fact that the problem may recur in the future.

Recovering from a Coup Using Windows

A couple of tools exist to help you manage the boot order in Windows. The easiest of these to use is the third-party EasyUEFI. Microsoft's bcdedit, though, has the advantage of working around a problem in which Windows keeps setting its own boot manager as the default. (This problem is rare, but crops up from time to time.)

Using EasyUEFI to Adjust Your Boot Priority

The third-party EasyUEFI program is a user-friendly GUI tool for managing EFI boot entries. If a Windows update resets Windows as the default boot program, you can use EasyUEFI to restore rEFInd as the default. Doing so is pretty straightforward:

  1. Download and install EasyUEFI.
  2. Launch EasyUEFI. The resulting display will look something like this:

  3. The Windows EasyUEFI tool enables adjusting the EFI
    boot entries in a GUI environment.

  4. Click the rEFInd entry.
  5. Click the green up-arrow button (at the top of the column of icons between the Boot order and Detailed information panes) as many times as needed to bring rEFInd to the top of the list.
  6. Exit from EasyUEFI. Alternatively, you can select the Power -> Reboot menu entry to reboot and test the change immediately.

Note that EasyUEFI's menu shows the names of the boot entries. In some cases, rEFInd may be registered under another name. This is particularly likely if you used macOS's bless or Windows' bcdedit tools to register rEFInd with the firmware. You may be able to locate the rEFInd binary by examining the File path entry in the Detailed information pane, after selecting a "candidate" entry.

Like most of the remedies described on this page, this one makes an immediate change to the boot order but does not guarantee that the problem will not recur. In most cases, rEFInd will remain the primary boot program until it's changed again by another OS update, but all bets are off when that happens.

Using bcdedit to Adjust Your Boot Priority

You can use a truncated version of the Windows installation instructions to restore rEFInd as the default boot manager:

  1. Locate Command Prompt in the Start menu, right-click it, and select Run as Administrator. This action opens a Command Prompt window with administrative privileges.
  2. Type bcdedit /set "{bootmgr}" path \EFI\refind\refind_x64.efi to set rEFInd as the default EFI boot program. Note that "{bootmgr}" is entered as such; that's not a notation for a variable. Also, change refind_x64.efi to refind_ia32.efi on systems with 32-bit EFIs. Such computers are rare, and most of them are tablets. Check your Windows bit depth to determine which binary you should use. If you use Shim or PreLoader to boot with Secure Boot active, you should change the name of the binary appropriately.
  3. If you like, type bcdedit /set "{bootmgr}" description "rEFInd description" to set a description (change rEFInd description as you see fit).

This procedure, unlike the EasyUEFI one, creates a new boot menu item. It requires that you know the exact path to the rEFInd binary. (If you don't know this detail, you can mount your ESP, as described in the Windows installation instructions, and try to find it.) Overall, it's likely to be easier to use EasyUEFI; however, this procedure has one potential advantage: I've seen reports of cases in which Windows changes the default boot program on every boot. This procedure sometimes puts an end to such shenanigans. Thus, it can serve as a preventive measure against at least some future boot coups. I can't promise that it will work in all such cases, though. In particular, some EFIs, especially older ones, are buggy and ignore or forget their entries. Using bcdedit will not help protect against this problem.

Using Your Firmware to Repair a Boot Coup

If a boot coup has left your computer unbootable, or if the OS to which you're booting provides poor or non-functional tools for repairing a boot coup, you may be able to use your firmware to fix the problem. There are two basic approaches to doing so: using built-in firmware features (which may or may not be present, depending on your computer) and using an EFI shell (which may or may not be installed on your computer).

Using Built-in Firmware Features to Adjust Your Boot Priority

Some, but not all, EFIs provide the means to adjust the boot order themselves. The details of how this works vary greatly from one implementation to another, so I can provide only fairly broad guidance on this point. As an example, consider how to adjust the boot order with the ASUS P8 H77-I motherboard:

  1. Turn on the computer.
  2. As the computer begins its Power-On Self-Test (POST), there will be a brief window in which you can hit the F2 or Del key to enter the firmware setup utility. Do so.
  3. In the "EZ-Mode" menu shown below, the boot order is shown graphically near the bottom of the screen. As you move the mouse over the entries, you'll see an expansion of each one. In the screen shot below, the second item is highlighted, and you can see it's rEFInd.

  4. Some EFIs provide a way to adjust the boot order.

  5. Click and drag the rEFInd entry to move it to the front of the list (all the way to the left).
  6. Hit F10 to save your changes. A dialog box will ask for confirmation; click Save Changes & Reset.

This procedure is only an example for one EFI. In fact, some EFIs, including the one in the ASUS P8 H77-I, feature multiple user interface modes. The ASUS has an "Advanced" mode, for instance, in which the procedure would be slightly different. They key point, though, is to locate whatever menu displays the boot order and use that menu to adjust it. Such a menu may be shown on the main screen, as in the case of the ASUS' "EZ-Mode," or on a menu you must select—often called "Boot" or something similar. Some EFIs, particularly for low-end fully-assembled desktop and laptop computers, lack this functionality altogether.

As with most other fixes described on this page, this one won't protect you from future boot coups. Most boot coups are caused by actions of an OS, so prevention must be handled on an OS-by-OS basis.

Using an EFI Shell to Adjust Your Boot Priority

Version 2 of the EFI shell provides a command, bcfg, which can adjust the EFI boot order. Unfortunately, this tool is not present in version 1 of the EFI shell, and version 2 is reliable only with EFI version 2.3 and later. To date (mid-2017), all Intel-based Macs use EFI 1.1, and many PCs sold prior to Windows 8's release use UEFI (EFI 2.x) versions prior to 2.3. Thus, this approach may not work for you.

Even if your computer works with a version 2 shell, it may not have one built in. In fact, most EFIs I've seen lack a built-in shell. If a shell is available, it should appear on the EFI's built-in boot manager, as described earlier, in Evading the Guards: Performing a One-Time Boot to Your Desired OS. If a shell is not built into your firmware, you can add one; here are a few links that may be helpful:

If you need to use the shell to overcome a boot coup, your best bet is to install it to a USB flash drive and boot from it. You can do so as follows in Linux:

  1. Prepare a USB flash drive with a FAT filesystem. Depending on your firmware, it may need to use GPT and the partition may need to be marked as an EFI System Partition (ESP)—that is, with a type code of EF00 in gdisk or with its "boot flag" set in parted or GParted.
  2. Mount the USB flash drive. In this procedure, I assume it's mounted at /mnt. If you mount it elsewhere, adjust the following commands appropriately.
  3. Type mkdir -p /mnt/EFI/BOOT to create the EFI/BOOT directory on the USB drive.
  4. Copy the shell binary you downloaded to /mnt/EFI/BOOT/bootx64.efi (for a system with a 64-bit EFI) or to /mnt/EFI/BOOT/bootia32.efi (for a system with a 32-bit EFI).
  5. Unmount the USB drive.

At this point, you should have a working USB flash drive with an EFI shell. It should show up in your computer's built-in boot manager, as described earlier, in Evading the Guards: Performing a One-Time Boot to Your Desired OS. It will probably appear there under the brand name of the USB drive, perhaps with "UEFI" in the description. (If the boot medium shows up twice, select the option that includes "UEFI" in the description.) One major caveat is that the EFI shell is not signed with a Secure Boot key, so to use it on a computer with Secure Boot active, you must disable Secure Boot.

Once you've booted the EFI shell, you can follow a subset of the EFI shell rEFInd installation instructions to repair the boot coup:

  1. Type bcfg boot dump -b to see a list of existing NVRAM entries. Pay attention to their numbers (labelled Option: and Variable:, with the latter number preceded by the string Boot, as in Boot0007). Look for the existing rEFInd entry.
  2. Type bcfg boot mv # 0, substituting the option number for the rEFInd entry you identified for #. This moves rEFInd to the top of the boot order.
  3. Type reset to reboot the computer.

With any luck, rEFInd will be restored as the default boot manager at this point. As with most of the methods described on this page, this procedure will do nothing to prevent future boot coups, so you may need to repeat the process in the future.

Because of the complexity of the procedure for starting an EFI shell if one is not already prepared, this procedure works best if one is built into your EFI or if you already have one ready.

The Unstable State: Dealing With Persistent Boot Coups

If your computer simply refuses to boot into rEFInd, chances are your firmware is either ignoring its boot entries or forgetting them. For the most part, which is the case doesn't really matter, since the solutions are similar for both cases. There are a few obscure exceptions, though; for instance, an entry will be ignored if it's malformed—such as if the filename specification includes a typo. Also, there is at least one known bug that causes the computer to ignore boot loader entries except for those named "Windows Boot Manager" or "Red Hat Enterprise Linux." Such problems can be fixed by creating a fresh NVRAM entry for rEFInd that fix the typo or give the entry the name that the EFI expects (even if it's a misleading name).

More common are problems in which the firmware ignores or forgets its boot entries. Such problems used to be quite common, but are becoming rarer as manufacturers (slowly) improve their products. My general advice for fixing such problems is to attempt each of the following, in more-or-less the stated order:

  1. Upgrade your firmware. Go to the manufacturer's Web page and search for a firmware update. (Most manufacturers call these "BIOS updates.") After you apply the update, you may need to add the rEFInd entry back (re-installing it will do so).
  2. Reset your firmware settings to their default values. Most EFIs provide an option to do this. The idea is that corrupted settings may be causing the firmware to misbehave, so resetting everything to factory defaults may work around the problem. You may need to re-install rEFInd, or at least re-create its NVRAM entry.
  3. Use another tool. The Linux efibootmgr tool sometimes doesn't work correctly even when another tool does work. As noted earlier, the Windows bcdedit program can overcome some persistent problems related to Windows; and the EFI shell's bcfg works better than efibootmgr on a small number of EFIs.
  4. Return the computer for a refund. If none of the preceding steps works, chances are your firmware is just plain defective. Note that by "defective" I mean "defective by design," not a sample defect, so you should not exchange the computer for another of the same model. (Indeed, even another model of the same brand may suffer from the same problem.) Your best bet in this case is to return the product to the store for a refund and write to the manufacturer about the problem. Manufacturers will not fix problems that they don't know exist, so informing them of the problem is important. Unfortunately, many people learn of such problems only after having owned a computer for months, so a return is not always practical....
  5. Use the fallback.efi program. This approach is described shortly, in Managing Boot Coups with fallback.efi/fbx86.efi.
  6. Use a fallback filename. You can use mvrefind in Linux to rename rEFInd to use either of two fallback filenames:
    • Type mvrefind /boot/efi/EFI/refind /boot/efi/EFI/BOOT to rename rEFInd to use the official EFI fallback filename of EFI/BOOT/bootx64.efi. (Change /boot/efi to the ESP's mount point if it's something else.) This location works well if you're single-booting Linux, or booting multiple Linux distributions.
    • Type mvrefind /boot/efi/EFI/refind /boot/efi/EFI/Microsoft/Boot to rename the Microsoft boot loader as a backup filename and to rename rEFInd as the Microsoft boot loader (EFI/Microsoft/Boot/bootmgfw.efi). This is a somewhat confusing hack, but it's necessary on some very badly broken EFIs, particularly if you're dual-booting Windows and another OS. Unfortunately, Windows might, quite reasonably, replace rEFInd with a fresh copy of its own boot loader if a system update provides a new boot loader, or even for other reasons. Thus, you might need to re-install rEFInd and repeat this hack at some point in the future.
    You can perform these actions in another OS, too, but you'll need to do so manually. See the Renaming Files Manually section of the rEFInd installation page for details. If you upgrade rEFInd in the future, the refind-install script should detect rEFInd at its altered location and upgrade it there, so you should not need to repeat this step after a future rEFInd upgrade.

Persistent boot coups may also be related to OS actions. As noted earlier, Windows will sometimes cause repeated problems, which can usually be fixed via bcdedit. Repeated problems in Linux can be caused by by frequent GRUB updates or by a combination of bad NVRAM handling and the fallback.efi program. If GRUB is updating so frequently that's it's causing annoyance, it can be dealt with by use of refind-mkdefault in a startup or shutdown script or by disabling GRUB updates. If fallback.efi is causing you grief, read the following section for information on how to reconfigure it.

Another thing that can produce symptoms similar to a persistent boot coup is Secure Boot. If Secure Boot is enabled on your computer and you install rEFInd without a Shim or PreLoader program, your computer will probably refuse to launch rEFInd. In this case, inserting Shim or PreLoader into the boot process, as described on the rEFInd Secure Boot page, normally overcomes this problem. On rare occasions, though, Shim or PreLoader won't work with a particular computer. In such a case, you may need to disable Secure Boot. Note that this level of Secure Boot malfunction is quite rare. I see many posts in online forums that jump to the conclusion that Secure Boot is causing a problem, when in fact there's another more likely cause. Thus, I urge you to investigate other possibilities before concluding that Secure Boot is causing an inability to boot rEFInd.

Managing Boot Coups with fallback.efi/fbx86.efi

One type of boot problem is similar to a boot coup, but has a unique cause: Some EFIs, especially older ones (mostly from 2012 or earlier) have a tendency to forget their NVRAM entries. Such computers boot from the fallback boot loader (EFI/BOOT/bootx64.efi) or from the Microsoft boot loader (EFI/Microsoft/Boot/bootmgfw.efi), but that's about it. A similar problem is that some computers remove invalid boot entries from their boot lists. This is helpful if you delete a boot loader, but it's less than helpful if you temporarily unplug your boot disk and then plug it back in.

In either of these cases, your computer may boot to an unwanted OS or completely fail to boot. One solution to this problem is to install rEFInd to the fallback filename, as described earlier, in The Unstable State: Dealing With Persistent Boot Coups. Another is to use an EFI program called fallback.efi, fbx64.efi, or an equivalent filename on other platforms. To use this program, you would install it to EFI/BOOT on the ESP, either renaming it to bootx64.efi (that is, fallback.efi uses the fallback filename) or installing Shim as bootx64.efi. Shim will try to launch fallback.efi or fbx64.efi when it boots, so either way, this program will launch. (Be sure to match your Shim and fallback.efi/fbx864.efi binaries, so that Shim launches the correct program!) For simplicity, I call this program fallback.efi hereafter.

When fallback.efi launches, it reads every subdirectory of EFI on the ESP except for EFI/BOOT and looks for a file called BOOT.CSV. If this file exists and contains a UCS-2 (UTF-16 also seems to work) text file, that file is read and used to create a new NVRAM boot variable. The format of BOOT.CSV is simple; it consists of one or more lines, each of which consists of four comma-separated fields:

  • filename—This is the filename of the file, in the same directory as BOOT.CSV, to be added to the NVRAM-based boot list.
  • label—This is the label to be associated with the file. This label is displayed by the firmware's own built-in boot manager.
  • options—If the boot loader requires options, you'd specify them here. rEFInd doesn't normally take options, so this field is likely to be empty.
  • description—This field describes the entry. It's not used by fallback.efi; it exists solely for human consumption.

An example BOOT.CSV file for rEFInd might look like this:

refind_x64.efi,rEFInd,,This is the boot entry for rEFInd

This example is suitable for use with rEFInd if Secure Boot is not in use. (If you're using Secure Boot with Shim, you'd probably specify shimx64.efi rather than refind_x64.efi in this file and give rEFInd the filename grubx64.efi.) This example adds an entry for refind_x64.efi, with a label of rEFInd, to the NVRAM-based boot order list.

One key point is that this file must be a UCS-2 or UTF-16 file. Most Linux (and Windows and macOS) text editors create ASCII files by default. You can use iconv to convert to an appropriate format. For instance, suppose you have an ASCII file called boot.csv in your home directory and you want to write it to /boot/efi/EFI/refind as a UCS-2 file. You could do so in two steps as follows:

$ iconv -t UCS-2 < ~/boot.csv > ~/BOOT.CSV
$ sudo cp ~/BOOT.CSV /boot/efi/EFI/refind/

Depending on permissions on your ESP and the account you use, you could do the same thing in a single step by writing directly to the ESP.

Note that fallback.efi can create boot coups, in addition to fixing them. If it's run inappropriately, this program can modify your NVRAM-based boot list, causing something you don't want to run to become the default boot loader. Thus, if you're experiencing boot coups, you may want to check for the presence of this program and either delete it or adjust the BOOT.CSV files on your ESP. You can find all the BOOT.CSV files as follows, assuming the ESP is mounted at /boot/efi:

$ find /boot/efi -iname BOOT.CSV

By default, Fedora and its relatives install fallback.efi in the fallback position (typically launched by Shim, actually) and set up a BOOT.CSV file in the directory that holds the distribution's GRUB. This is good for keeping Fedora booting, but if you want to boot with rEFInd, this configuration can result in a boot coup should the fallback boot loader run for any reason. One way to fix such a problem is to delete or rename BOOT.CSV in the GRUB boot loader's directory and create a suitable BOOT.CSV in the rEFInd directory on the ESP. The refind-install and mvrefind scripts in rEFInd 0.11.0 and later create such a file automatically. This file is harmless if fallback.efi never runs.

Note that fallback.efi does not guarantee the order in which boot entries are created, nor does it provide any mechanism for controlling the boot order when the program runs. These details are determined by the order in which the program locates BOOT.CSV files. Thus, if you have multiple boot loaders with BOOT.CSV files, you'll end up with an essentially random boot loader selected as the default. With any luck, you'll be able to adjust the boot order with efibootmgr, EasyUEFI, or some other program once the system has booted. If your computer completely forgets its boot entries on every boot, though, your best bet is likely to be to delete all the BOOT.CSV files except for the one associated with the boot program you want to control the computer.


copyright © 2016–2018 by Roderick W. Smith

This document is licensed under the terms of the GNU Free Documentation License (FDL), version 1.3.

If you have problems with or comments about this Web page, please e-mail me at rodsmith@rodsbooks.com. Thanks.

Go to the main rEFInd page

Comments on rEFInd and OS X 10.10 (Yosemite)

Return to my main Web page.

refind-0.11.4/docs/refind/themes.html0000664000175000017500000007626313372346574017720 0ustar rodsmithrodsmith The rEFInd Boot Manager: Theming rEFInd

The rEFInd Boot Manager:
Theming rEFInd

by Roderick W. Smith, rodsmith@rodsbooks.com

Originally written: 4/19/2012; last Web page update: 11/12/2018, referencing rEFInd 0.11.4

This Web page is provided free of charge and with no annoying outside ads; however, I did take time to prepare it, and Web hosting does cost money. If you find this Web page useful, please consider making a small donation to help keep this site up and running. Thanks!

Donate $1.00 Donate $2.50 Donate $5.00 Donate $10.00 Donate $20.00 Donate another value

This page is part of the documentation for the rEFInd boot manager. If a Web search has brought you here, you may want to start at the main page.


rEFInd relies on both built-in and external graphical elements in its user interface, and all of these elements can be replaced by user-specified files. This fact makes rEFInd's "look and feel" highly adjustable even by non-programmers. This page will help you get started in making such changes to each of the major sets of features: banners and backgrounds, icons, icon selection backgrounds, and fonts. I conclude this page with pointers to a few themes that users have created for rEFInd.

Theming Basics

Broadly speaking, rEFInd's graphical elements fall into four categories:

  • Banners and backgrounds—A banner is a logo or small graphical element that rEFInd displays horizontally centered in the top half of the screen. The rest of the screen is filled with a solid color derived from the color used in the top-left pixel of the banner image. rEFInd includes a built-in banner image that's used if you don't specify another image with the banner token in refind.conf. A background is simply a banner image that fills the screen. As a general rule, PNG and JPEG files work best for this element.
  • Icons—rEFInd uses icons for its OSes and utilities. The vast majority of these icons are loaded from disk files and so are easily replaced without adjusting the refind.conf file. Alternatively, you can specify a new icons directory with the icons_dir token in refind.conf. Icons are generally PNG or ICNS files, with the latter being a Mac-centric format and so less common.
  • Icon selection backgrounds—When an icon is selected, it's merged with a slightly larger selection icon, which you can change by specifying a new file with the selection_big and selection_small tokens in refind.conf. These elements are generally best done as PNG files.
  • fonts—rEFInd uses a 14-point monospaced sans serif font by default. If you don't like this font, you can change it to another monospaced font by using the font token in refind.conf; however, the font file is a simple image of the font's characters, which limits rEFInd's font capabilities. The PNG format works best for a font.

Of course, not all of these elements are likely to be included in all themes. You might want to change just one or two elements—say, to add an icon for your OS or to change the banner or background.

As noted in the Setting OS Icons section of the Configuring the Boot Manager page, rEFInd supports four image file formats: Apple's ICNS format, Portable Network Graphics (PNG) format, bitmap image file (BMP) format, and Joint Photographic Experts Group (JPEG) format. The demands of each type of image mean that certain file formats work best for it, as noted above; however, you can in principle use any file format for any purpose. Specific file format limitations include:

  • rEFInd's BMP and JPEG implementations lack support for transparency, which is highly desirable in icons, icon backgrounds, and fonts.
  • Apple's ICNS format supports a limited range of sizes, all of which are square, not rectangular.
  • rEFInd's BMP implementation does not support compression, so full-screen BMP images will be quite large.

rEFInd relies on the LodePNG and NanoJPEG libraries for PNG and JPEG support, respectively. These libraries have certain limitations; for instance, NanoJPEG, and therefore rEFInd, does not support progressive JPEGs. If you have problems with a specific icon or banner image, check the libraries' pages and re-save or convert the image into a more generic form, or even to a different format.

Banners and Backgrounds

You can create a new background image and logo by placing an image file in rEFInd's main directory and passing its filename to rEFInd with the banner option in refind.conf. If the image is smaller than the screen, the color in the top-left pixel of the image will be used for the rest of the display. This pixel's color is also used as the background color for submenu text, even for full-screen backgrounds. Using a full-screen background image can produce a dramatically different "look" for rEFInd:


rEFInd provides extensive theming
    options.

Note that in this example, the text immediately below the icons is white, whereas the hint text at the bottom of the screen is black. The text color is determined by the brightness of the background; rEFInd uses black text against light backgrounds and white text against dark backgrounds. This adjustment is done on a line-by-line basis, so it copes better with horizontal lines than with vertical lines.

If you want to use a full-screen background but also include the rEFInd logo, you can merge the two in a graphics editor by including the refind_banner-alpha.png or refind-banner.svg image from the banners subdirectory of the rEFInd package in your background.

It's possible to stretch or shrink any image to fill the screen. To do so, you should use the banner_scale option in refind.conf: Set it to noscale (the default) to use small banners as such or to crop larger images; or set it to fillscreen to adjust your banner's size to exactly fill the screen. This should be particularly handy for theme developers who want to use a full-screen background image, since you can now do this with just one image file.

Icons

The core icons in rEFInd 0.10.0 and later come from the AwOken 2.5 icon set, with additional icons created by me, and a few others taken from other sources. (The details are documented in the README file in the icons subdirectory.) These icons have a "flat" appearance, but with drop shadows to provide a type of depth. Most of the individual icons use just one color, aside from the drop shadow. Of course, the point of themes is that you might get bored with, or simply not like, the default graphics, so you can change them.

As described on various other pages of this document, rEFInd relies on icon files located in its icons subdirectory, and occasionally elsewhere, to define its overall appearance. You can adjust rEFInd's icons in a few ways:

  • You can create new icons, place them in a subdirectory of rEFInd's main directory, and tell the program to use the new icons by setting the icons_dir token in refind.conf. This will affect the appearance of the OS tags, the utility tags, and so on. The names of these icons should match those in the icons subdirectory (although you can substitute file formats, with a suitable filename change), and are fairly self-explanatory. The default size for OS tags is 128x128 pixels, tags for 2nd-row utilities are ordinarily 48x48 pixels, and drive-type badges are 32x32 pixels by default. If an icon is missing from the directory specified by icons_dir, rEFInd falls back to the icon from the standard icons subdirectory; thus, you can replace just a subset of the standard icons. rEFInd can use icons in any of several formats, as described earlier, in Theming Basics. PNG files are the easiest to generate on most platforms. You can generate ICNS files in various Apple programs or by using the libicns library (and in particular its png2icns program) in Linux.
  • You can do as above, but place your new icons in the default icons subdirectory. This method is discouraged because using the refind-install script to upgrade rEFInd will replace your customized icons.
  • You can customize the appearance of an individual boot loader by placing an ICNS or PNG file in its directory with the same name as the boot loader but with a suitable image file extension, such as .icns or .png. For instance, if your boot loader program is elilo.efi, you can create a custom icon by naming it elilo.png.
  • You can provide an icon for boot loaders stored in the root directory of a filesystem by placing a file called .VolumeIcon.icns, .VolumeIcon.png, .VolumeIcon.bmp, .VolumeIcon.jpg, or .VolumeIcon.jpeg in that volume's root.
  • You can set a custom badge (the icon that identifies the disk type) by creating a file called .VolumeBadge.icns, .VolumeBadge.png, .VolumeBadge.bmp, .VolumeBadge.jpg, or .VolumeBadge.jpeg in that volume's root. This setting applies to all the boot loaders found on this volume, even if they're in subdirectories.
  • You can adjust the sizes of icons by using the big_icon_size and small_icon_size tokens in refind.conf. These tokens adjust the size of the first-row OS and second-row tool icons, respectively. The big_icon_size option also indirectly sets the disk-type badge size; badges have sides that 1/4 the size of OS icons. The icons provided with rEFInd are 128x128 for OS icons, 48x48 for tools, and 32x32 for badges. The big_icon_size and small_icon_size tokens cause these icons to be scaled to the desired value; however, for best results you should replace your the default icons with ones generated natively in the desired size. (All the image file formats supported by rEFInd are bitmap formats, and so the images will be degraded by scaling operations.)

As an example of what the combination of icons and backgrounds can do, consider my own Snowy theme, showing the same boot options as the preceding image:


The Snowy theme uses predominantly white
    icons and a background image to match its name

Icon Selection Backgrounds

rEFInd identifies the current selection by displaying a partially-transparent icon "between" the OS or tool icon and the background image. The default icon works reasonably well on both solid and image backgrounds, but if you like, you can customize it by creating new icons. You should create both 144x144 and 64x64 images and tell rEFInd about them by using the selection_big and selection_small tokens, respectively, in refind.conf. (If you scale your icons, you may want to adjust the selection tile images appropriately. The big image is 9/8 the size of its matching icons, while the small tile is 4/3 the size of its icons.) If you omit the large icon, rEFInd will stretch the small icon to fit the larger space; if you omit the small icon, rEFInd will use the default small icon. Because PNG supports both transparency and the unusual sizes of the selection icon, PNG is best if you want your selection background to show the underlying image beneath it. (You can create the illusion of transparency on a solid background by matching the colors, though.)

Fonts

rEFInd's default font is a 14-point (12-point in 0.6.5 and earlier) serif monospaced font. I also include a handful of alternatives in the fonts subdirectory. rEFInd's font support is extremely rudimentary, though; it reads an image file that holds the glyphs from ASCII 32 (space) through ASCII 126 (tilde, ~), plus a glyph that's displayed for all characters outside of this range. Thus, rEFInd can't currently display non-ASCII characters or use proportional (variable-width) fonts. You can change the font from one monospaced font to another and change the font size, though.

If you want to create your own fonts, you can do so. If you're using Linux, the mkfont.sh script in the fonts subdirectory will convert an installed monospace font into a suitable format. (This script works properly for most fonts, but if a font is unusually thin or wide, you will have to adjust the let CellWidth= line near the end of the file.) You can use it like this:

$ ./mkfont.sh Liberation-Mono-Italic 14 -1 liberation-mono-italic-14.png

The result is a PNG file, liberation-mono-italic-14.png, that you can copy to your rEFInd directory and load with the font token in refind.conf, as in:

font liberation-mono-italic-14.png

The mkfont.sh script takes four arguments:

  • The font name—Type convert -list font | less to obtain a list of fonts available on your computer. Note, however, that rEFInd requires monospaced (fixed-width) fonts, and most of the fonts installed on most computers are variable-width.
  • The font size in points
  • A y offset—Many fonts require an adjustment up (negative values), or occasionally down (positive values) to fit in the PNG image area. You'll have to use trial and error to get this to work.
  • The output filename

I recommend checking the PNG file in a graphics program like eog before using it. Note that the font files should have an alpha layer, which many graphics programs display as a gray-and-white checkered background. This requirement, combined with ICNS's limited set of supported sizes, makes PNG the only practical file format for rEFInd fonts.

If you're not using Linux, or if you want to use some other method of generating fonts, you can do so. The font files must contain glyphs for the 95 characters between ASCII 32 (space) and ASCII 126 (tilde, ~), inclusive, plus a 96th glyph that rEFInd displays for out-of-range characters. To work properly, the characters must be evenly spaced and the PNG image must be a multiple of 96 pixels wide, with divisions at appropriate points. In theory, you should be able to take a screen shot of a program displaying the relevant characters and then crop it to suit your needs and convert the background color to transparency. In practice, this is likely to be tedious.

Known Themes

In addition to this default icon set, I've received word of a few other rEFInd themes:

  • Snowy is my own theme. It's built from (mostly) white variants of rEFInd's standard icons and includes a photo of a snowy field as a background image. It's shown earlier on this page.
  • ecto-plazm's theme was one of the first independent themes to be created for rEFInd.
  • The Mac theme was created by Wesley Turner-Harris, and is a theme with relatively few icons intended for use on Macs. See Wesley's Web site if you want to contact the creator of this theme.

  • The Mac theme is designed for use on
    Macs

  • Evan Purkhiser's Minimal theme uses black icons on a gray background of varied brightness, as shown here:

  • Minimal uses flat icons and a subtly-graded background

  • John Trenton Cary's rEFInd Metro theme is another minimal theme. It uses a solid background color and a number of OS icons.

  • rEFInd Next uses simple white icons against green artwork

  • Sean Gibbons' rEFInd Next theme is "inspired by both iOS 7 and Windows 8 interfaces." It includes both a background image and a number of OS icons.

  • rEFInd Next uses simple white icons against green artwork

  • Zhu Qunying has created a Slackware-themed banner logo for rEFInd. Although it's not a full theme, I thought I'd mention it.
  • naymlezwun has created an OS X theme for rEFInd.

  • the rEFInd OS X theme uses Mac-like icons

  • jamaladdeen on deviantART has created another OS X theme that resembles the OS X environment.

  • Another OS X-like theme

  • Brian Lechthaler has created an alternative rEFInd banner:
    An alternative simple banner for rEFInd

  • User munlik has created a theme called Regular-theme on Deviantart. The original developer of this theme seems to have abandoned it, but bobafetthotmail provides a variant with additional icons hosted on github.

  • A clean theme with a purple background

  • Despite its name, the Tux Boot Loader Theme for Ubuntu can be used with any Linux distribution (or on a system without Linux installed at all).

  • A theme with
    a dark background and icons with a disk-icon theme

  • The rEFInd Ambience Theme is another one with minimalistic icons against a shaded background.

  • A theme with
    a shaded background and simple icons

  • The rEFInd-Chalkboard theme by AliciaTransmuted emulates the appearance of writing on a chalkboard. See here for all of AliciaTransmuted's rEFInd themes.

  • A theme that emulates the look of
    writing on a chalkboard

  • The rEFInd-Details theme by AliciaTransmuted implements many unique and colorful icons. See here for all of AliciaTransmuted's rEFInd themes.

  • A theme that emulates the look of
    writing on a chalkboard

  • The rEFInd-Indulgence theme by AliciaTransmuted uses a background that resembles soft leather. See here for all of AliciaTransmuted's rEFInd themes.

  • A theme that emulates the look of
    writing on a chalkboard

  • The rEFInd-Wildside theme by AliciaTransmuted uses a dark background and dark red icons. See here for all of AliciaTransmuted's rEFInd themes.

  • A theme that emulates the look of
    writing on a chalkboard

  • The rEFInd-splash theme by AliciaTransmuted provides a swimming pool theme to the rEFInd main screen. See here for all of AliciaTransmuted's rEFInd themes.

  • A theme that emulates the look of
    writing on a chalkboard

If you've created or discovered another rEFInd theme, please tell me about it so that I can provide a link to it from this page.


copyright © 2012–2018 by Roderick W. Smith

This document is licensed under the terms of the GNU Free Documentation License (FDL), version 1.3.

If you have problems with or comments about this Web page, please e-mail me at rodsmith@rodsbooks.com. Thanks.

Go to the main rEFInd page

Learn about methods of booting Linux with rEFInd

Return to my main Web page.

refind-0.11.4/docs/refind/linux.html0000664000175000017500000011475213372346574017566 0ustar rodsmithrodsmith The rEFInd Boot Manager: Methods of Booting Linux

The rEFInd Boot Manager:
Methods of Booting Linux

by Roderick W. Smith, rodsmith@rodsbooks.com

Originally written: 3/19/2012; last Web page update: 11/12/2018, referencing rEFInd 0.11.4

This Web page is provided free of charge and with no annoying outside ads; however, I did take time to prepare it, and Web hosting does cost money. If you find this Web page useful, please consider making a small donation to help keep this site up and running. Thanks!

Donate $1.00 Donate $2.50 Donate $5.00 Donate $10.00 Donate $20.00 Donate another value

This page is part of the documentation for the rEFInd boot manager. If a Web search has brought you here, you may want to start at the main page.


Windows and Mac OS X both provide relatively simple EFI boot loader programs. Launch them, and they'll boot their respective OSes. This makes rEFInd's job easy; it just locates the boot loader program files and runs them.

Under Linux, by contrast, things can get complicated. As detailed on my Managing EFI Boot Loaders for Linux page, several different EFI boot loaders for Linux exist, and all of them require configuration. If you're lucky, your distribution will have set up a Linux boot loader in a sensible way, in which case rEFInd should detect it and it will work as easily as a Windows or Mac OS X boot loader. If you're not lucky, though, you may need to configure it further. rEFInd offers options to help out with this task. Naturally, rEFInd supports traditional Linux boot loaders. It works even better with the Linux EFI stub loader, so I provide instructions on starting with it. For those interested in manual configuration, I also provide detailed instructions on how the EFI stub support works and how to configure it.

Using a Traditional Linux Boot Loader

I consider ELILO, GRUB Legacy, GRUB 2, and SYSLINUX to be traditional Linux boot loaders. These programs all exist independent of the Linux kernel, but they can load a kernel and hand off control to it. All four programs have their own configuration files that reside in the same directory as the boot loader itself (or optionally elsewhere, in the case of GRUB 2).

Ordinarily, rEFInd will detect these traditional boot loaders and provide main menu entries for them. If the boot loader exists in a directory with a name that matches a Linux distribution's icon filename, you'll automatically get a distribution-specific icon to refer to the boot loader.

If you prefer, you can disable automatic scanning and create an entry in refind.conf for your distribution, as described on the Configuring the Boot Manager page. This method is harder to set up but can be preferable if you want to customize your options.

Using the EFI Stub Loader: Three Configuration Options

The EFI stub loader is basic and reliable, but it requires some setup to use it on some computers. It also requires that you run a kernel with the same bit width as your EFI. In most cases, this means running a 64-bit kernel, since 32-bit EFI-based computers are so rare. I describe three methods of using the EFI stub loader: an easiest method for those with compatible partition and filesystem layouts, a quick test configuration for those without such a layout, and a long-term setup for those without the ideal setup. In most cases, the first (easiest) method works fine, thanks to rEFInd's filesystem drivers and rEFInd features intended to help launch a kernel with minimal user configuration.

For Those With Foresight or Luck: The Easiest Method

This method requires that your /boot directory, whether it's on a separate partition or is a regular directory in your root (/) filesystem, be readable by the EFI. At the moment, all EFI implementations can read FAT and Macs can read HFS+. By using drivers, you can make any EFI read HFS+, ISO-9660, ReiserFS, ext2fs, ext3fs, ext4fs, Btrfs, or other filesystems. Thus, if you use any of these filesystems on a regular partition (not an LVM or RAID configuration) that holds your kernels in /boot, you qualify for this easy method. The default partition layouts used by Ubuntu, Fedora, and many other distributions qualify, because they use one of these filesystems (usually ext4fs) in a normal partition or on a separate /boot partition. You must also have a 3.3.0 or later Linux kernel with EFI stub support, of course.

If you installed rEFInd 0.6.0 or later with its refind-install (formerly install.sh) script from your regular Linux installation, chances are everything's set up; you should be able to reboot and see your Linux kernels as boot options. If you installed manually, from OS X, or from an emergency system, though, you may need to do a couple of things manually:

  • Copy the relevant driver file for your filesystem and architecture to the drivers or drivers_arch subdirectory of the rEFInd installation directory on the EFI System Partition (ESP). You may need to create this subdirectory, too.
  • Create a refind_linux.conf file in your /boot directory. The mkrlconf script that comes with rEFInd should do this job, or you can do it manually as described later. Starting with version 0.6.12, rEFInd can create minimal boot options from /etc/fstab, if /boot is not a separate partition, so a refind_linux.conf file may not be strictly necessary. Version 0.9.0 also adds the ability to identify the root (/) partition via the Discoverable Partitions Spec, if your disk uses the appropriate type codes. A refind_linux.conf file remains desirable, though, and is necessary in some situations.

When you reboot, you should see rEFInd options for your Linux kernels. If they work, your job is done, although you might want to apply some of the tweaks described in the maintenance-free setup section. If you have problems, you may need to adjust the refind_linux.conf file, as described in the detailed configuration section.

Preparing a Test Configuration

If you're not sure you want to use the EFI stub loader in the long term, you can perform a fairly quick initial test of it. This procedure assumes that you have access to a 3.3.0 or later Linux kernel with EFI stub support compiled into it. (Most distributions ship with such kernels.) Creating this configuration poses no risk to your current boot options, provided you don't accidentally delete existing files. The procedure for a quick test is:

  1. Copy your kernel file (vmlinuz-*) and matching initial RAM disk file (init*) from /boot to a subdirectory of EFI on your ESP. Your distribution's directory there should work fine. For instance, typing cp /boot/vmlinuz-4.2.5-300.fc23.x86_64 /boot/initramfs-4.2.5-300.fc23.x86_64.img /boot/efi/EFI/fedora might do the trick on a Fedora system, although you'll probably have to adjust the version numbers. Note that the filename forms vary from one distribution to another, so don't worry if yours look different from these. Be sure that you match up the correct files by version number, though.
  2. Copy the /boot/refind_linux.conf file to the same directory to which you copied your kernel. If this file doesn't exist, create it by running (as root) the mkrlconf script that came with rEFInd. This step may not be strictly necessary if /boot is an ordinary directory on your root (/) partition.
  3. Reboot. You should now see a new entry for launching the Linux kernel that you copied. Try the option. If it works, great. If not, you may need to adjust your refind_linux.conf file. See the detailed configuration section for a description of this file's format. If the kernel begins to boot but complains that it couldn't find its root filesystem, double-check the version numbers on your kernel and initial RAM disk file, and check the root= option in refind_linux.conf.

You can continue to boot your computer with this type of configuration; however, the drawback is that you'll need to copy your kernel whenever it's updated. This can be a hassle. A better way is to configure you system so that the EFI, and therefore rEFInd, can read your Linux /boot directory, where most Linux distributions place their kernels. You do this by installing the appropriate EFI filesystem driver for the /boot (or root, /) filesystem.

If You Need to Reconfigure Your Partitions....

If your /boot directory happens to be on an XFS or JFS partition that the EFI can't read, or it's tucked away in an LVM or RAID configuration that the EFI can't read, you won't be able to use the easiest solution. Fortunately, this problem can be overcome with relatively little fuss. Several variant procedures are possible, but I begin by describing one that will almost always work, although it's got some important caveats (described at the end). You should perform the following steps as root, or precede each of these commands with sudo:

  1. Begin with your ESP mounted at /boot/efi, which is the most common location. If it's not mounted there, type mount /dev/sda1 /boot/efi to do so (adjusting /dev/sda1, if necessary), or mount it elsewhere and adjust the paths in the following procedure as necessary.
  2. Check the size of the ESP by typing df -h /boot/efi. The ESP must be large enough to hold several Linux kernels and initial RAM disk files—100MiB at a bare minimum, and preferably 200–500MiB.
  3. Check your /boot directory to be sure it contains no links or other files that rely on Unix/Linux-style permissions or ownership. If it does, don't proceed, or at least research these files further to determine if you can work around the need for such permissions and ownership.
  4. Type cp -r /boot/* /boot/efi. You'll see an error message about being unable to copy /boot/efi into itself. Ignore this.
  5. Type umount /boot/efi.
  6. Edit /etc/fstab and change the mount point for /boot/efi to /boot. If the ESP isn't present in /etc/fstab, you must create an entry for it, with a mount point of /boot.
  7. Type mount -a to re-mount everything, including /boot. Check that your normal /boot files are all present, along with the new /boot/EFI directory, which holds what used to be /boot/efi/EFI. If something seems to be missing (other than /boot/efi with a lowercase efi), then you should try to correct the problem.
  8. If it doesn't already exist, create a file called /boot/refind_linux.conf and populate it with kernel options, as described later. If this file doesn't already exist, the easiest way to create it is to run the mkrlconf script that comes with rEFInd 0.5.1 and later.
  9. Check your refind.conf file (presumably in /boot/EFI/refind) to be sure that the scan_all_linux_kernels line is uncommented. If it's not, uncomment that line.
  10. Optionally, type cp /boot/EFI/refind/icons/os_name.icns /boot/.VolumeIcon.icns to give loaders in /boot an icon for your distribution.
  11. Reboot to test that this configuration works.

Recall that in step #4, you copied the contents of /boot (as a safety measure), but you did not move them. Therefore, you ended up with two copies of your kernels and other /boot directory contents, with one copy hiding the other when you mounted the ESP at /boot. Once you've booted successfully and are sure all is working well, you can recover some disk space by unmounting /boot and deleting the contents of the underlying /boot directory on your root (/) filesystem. Be sure that the /boot partition is unmounted before you do this, though! Also, be sure to leave the /boot directory itself in place, even if it has no contents; the directory is needed as a mount point for the /boot partition. Note that GRUB 2 may stop working if you delete its files from the root filesystem's /boot/grub directory, so if you want to keep GRUB around, you should re-install it with the separate /boot partition mounted.

Once this task is done, updates to your kernel will automatically be stored in the root directory of your ESP, where rEFInd will automatically detect them. Thus, the boot configuration becomes maintenance-free. The procedure as just described has some drawbacks, though. By placing your kernels in the root directory of your ESP, you render them vulnerable to any other OS with which you might be dual-booting. Your ESP must also be large enough to hold all your kernels. If you dual-boot with multiple Linux distributions, they might conceivably overwrite each others' kernels, and distinguishing one from another becomes more difficult.

For these reasons, a variant of this procedure is desirable on some systems. Most of the steps are similar, but in this variant, you create a separate /boot partition that's independent of the ESP. This partition can use FAT, HFS+, ReiserFS, ext2fs, ext3fs, ext4fs, or Btrfs; but if you use any of the last six filesystems (five on Macs), you must install the matching EFI filesystem driver that ships with rEFInd. Creating the filesystem will normally require you to shrink an existing partition by a suitable amount (200–500MiB). Mount your new /boot partition at a temporary location, copy or move the current /boot files into it, unmount it, and add it to /etc/fstab as /boot.

If your distribution already uses a separate /boot partition, but if it uses XFS or some other unsuitable filesystem, you can back it up, create a fresh FAT, HFS+, ReiserFS, Btrfs, ext2, ext3, or ext4 filesystem on it, and restore the original files. You'll probably need to adjust the UUID value in /etc/fstab to ensure that the computer mounts the new filesystem when you boot. If you use a separate non-ESP /boot partition, you'll probably want to continue mounting the ESP at /boot/efi.

EFI Stub Loader Support Technical Details

The Linux EFI stub loader is a way to turn a Linux kernel into an EFI application. In a sense, the kernel becomes its own boot loader. This approach to booting Linux is very elegant in some ways, but as described on the page to which I just linked, it has its disadvantages, too. One challenge to booting in this way is that modern Linux installations typically require that the kernel be passed a number of options at boot time. These tell the kernel where the Linux root (/) filesystem is, where the initial RAM disk is, and so on. Without these options, Linux won't boot. These options are impossible for a generic boot loader to guess without a little help. It's possible to build a kernel with a default set of options, but this is rather limiting. Thus, rEFInd provides configuration options to help.

With all versions of rEFInd, you can create manual boot loader stanzas in the refind.conf file to identify a Linux kernel and to pass it all the options it needs. This approach is effective and flexible, but it requires editing a single configuration file for all the OSes you want to define in this way. If a computer boots two different Linux distributions, and if both were to support rEFInd, problems might arise as each one tries to modify its own rEFInd configuration; or the one that controls rEFInd might set inappropriate options for another distribution. This is a problem that's been a minor annoyance for years under BIOS, since the same potential for poor configuration applies to LILO, GRUB Legacy, and GRUB 2 on BIOS. The most reliable solution under BIOS is to chainload one boot loader to another. The same solution is possible under EFI, but rEFInd offers another possibility.

rEFInd supports semi-automatic Linux EFI stub loader detection. This feature works as part of the standard boot loader scan operation, but it extends it as follows:

  1. rEFInd looks for boot loaders whose names include the strings bzImage or vmlinuz. For instance, bzImage-3.19.0.efi or vmlinuz-4.2.0 would match, and trigger subsequent steps in this procedure. The scan_all_linux_kernels option in refind.conf controls the scanning for kernels whose names do not end in .efi; if this option is set to false, kernel filenames must end in .efi to be picked up by rEFInd. This option is set to true by default, but you can change it if you don't want to scan all Linux kernels.
  2. If a file's name ends in .efi.signed, any other file with an otherwise-identical name that lacks this extension is excluded. This peculiar rule exists because Ubuntu delivers two copies of every kernel, one with and one without this extension. The one with the extension is signed with a Secure Boot key; the one without it is not so signed. Thus, if both files are present, the one without the key won't boot on a computer with Secure Boot active, and either will boot if Secure Boot is inactive. Thus, rEFInd excludes the redundant (unsigned) file in order to help keep the list of boot options manageable.
  3. rEFInd looks for an initial RAM disk in the same directory as the kernel file. A matching initial RAM disk has a name that begins with init and that includes the same version string as the kernel. The version string is defined as the part of the filename from the first digit to the last digit, inclusive. Note that the version string can include non-digits. For instance, the version string for bzImage-3.19.0.efi is 3.19.0, which matches initramfs-3.19.0.bz; and vmlinuz-4.2.5-300.fc23.x86_64's version string is 4.2.5-300.fc23.x86_64, which matches initrd-4.2.5-300.fc23.x86_64.img. Many other matches are possible. If an initial RAM disk is identified, rEFInd passes a suitable initrd= option to the kernel when it boots. There are two variants on this rule:
    • As an extension to the preceding point, if multiple initial RAM disk files match one kernel, the one whose filename matches the most characters after the version string is used. For instance, suppose the kernel filename is vmlinuz-4.8.0-32-standard, and two initial RAM disk files are initrd-4.8.0-32-standard and initrd-4.8.0-32-debug. The first of those files has nine matching characters after the version string (-standard), vs. just one matching character (-) for the second. Thus, the first file will be used.
    • If the refind_linux.conf file (described next) is present, and if an initrd= specification is present for the option you're using, rEFInd will not add a pointer to the initial RAM disk file that it discovers. This feature enables you to override rEFInd's initial RAM disk discovery. This is most useful in Arch Linux, which can be configured with two different initial RAM disk files, one to be used for normal booting and one for recovery situations. You can specify each initial RAM disk file on its own line, which gives you the ability to control which to use at boot time.
  4. rEFInd looks for a file called refind_linux.conf in the same directory as the kernel file. It consists of a series of lines, each of which consists of a label followed by a series of kernel options. The first line sets default options, and subsequent lines set options that are accessible from the main menu tag's submenu screen. If you installed rEFInd with the refind-install script, that script created a sample refind_linux.conf file, customized for your computer, in /boot. This file will work without changes on many installations, but you may need to tweak it for some. If the kernel options string includes the substring %v, rEFInd substitutes the kernel version number for that string. (If you need the actual string %v in your kernel options, use %%v instead; rEFInd will change this to %v.) This feature can be used to match an initial RAM disk file that requires special treatment, such as if you have multiple numbered kernels, each of which has two initial RAM disk files.
  5. If rEFInd can't find a refind_linux.conf file in the directory that holds the kernel, the program looks for a file called /etc/fstab on the partition that holds the kernel. If this standard Linux file is present, rEFInd uses it to identify the root (/) filesystem and creates two sets of Linux kernel boot options: One set launches the kernel normally, but with minimal options, and the other set launches the kernel into single-user mode. This step can get a computer to boot without any rEFInd-specific configuration files, aside from refind.conf in rEFInd's own directory, but only if /boot is not a separate partition. The intent is to facilitate the use of rEFInd as an emergency boot manager or to help users who must install rEFInd from OS X or Windows. Note that rEFInd uses /etc/fstab only if refind_linux.conf is not found.
  6. If rEFInd can't find a refind_linux.conf file or an /etc/fstab file, it tries to identify the Linux root (/) filesystem by looking for a partition with a GUID type code matching that specified for the root (/) filesystem in the Freedesktop.org Discoverable Partitions Specification. These type codes are as yet seldom used, but if and when they become common, they should help a lot for situations similar to those of the preceding case, but when a separate /boot partition is used.

The intent of this system is that distribution maintainers can place their kernels, initial RAM disks, and a refind_linux.conf file in their own subdirectories on the ESP, on EFI-accessible /boot partitions, or in /boot directories on EFI-accessible Linux root (/) partitions. rEFInd will detect these kernels and create one main menu entry for each directory that holds kernels; or if fold_linux_kernels is set to false, one menu entry for each kernel. Each entry will implement as many options as there are lines in the refind_linux.conf file (multiplied by the number of kernels, if fold_linux_kernels is true). In this way, two or more distributions can each maintain their boot loader entries, without being too concerned about who maintains rEFInd as a whole.

As an example, consider the following (partial) file listing:

$ ls -l /boot/vmlin*
total 17943
-rw-r--r-- 1 root root 5271984 Aug  7 10:18 /boot/vmlinuz-3.16.7-24-default
-rw-r--r-- 1 root root 5271536 Oct 23 17:25 /boot/vmlinuz-3.16.7-29-default

When rEFInd scans this directory, it will discover two kernels in /boot. Assuming fold_linux_kernels is its default of true, rEFInd will create one main-menu tag for these two kernels. A refind_linux.conf file in this directory should contain a list of labels and options:

"Boot with standard options"  "ro root=UUID=084f544a-7559-4d4b-938a-b920f59edc7e splash=silent quiet showopts "
"Boot to single-user mode"    "ro root=UUID=084f544a-7559-4d4b-938a-b920f59edc7e splash=silent quiet showopts single"
"Boot with minimal options"   "ro root=UUID=084f544a-7559-4d4b-938a-b920f59edc7e"
# This line is a comment

Ordinarily, both fields in this file must be enclosed in quotes. If you have to pass an option that includes quotes, you can do so by doubling up on them, as in "root=/dev/sdb9 my_opt=""this is it""", which passes root=/dev/sdb9 my_opt="this is it" to the shell. You can include as much white space as you like between options. You can also place comments in the file, or remove an option by commenting it out with a leading hash mark (#), as in the fourth line in this example.

In the preceding example, the first line sets the options that rEFInd passes to the kernel by default (along with the name of the discovered initrd file, since its version string matches that of the kernel). The next two lines set options that you can obtain by pressing Insert, F2, or + on the main menu, as shown here:


rEFInd can load Linux boot options from
    a refind_linux.conf file in the Linux kernel's directory.

Note that in this example, the default kernel (the one with the most recent time stamp) appears first on the list, with the labels specified in refind_linux.conf. Subsequent kernels (just one in this example) appear below it, with the same labels preceded by the kernel filename. If you were to set fold_linux_kernels false, each kernel would get its own entry on the main menu, and each one's submenu would enable options for launching it alone.

To assist in initial configuration, rEFInd's refind-install script creates a sample refind_linux.conf file in /boot. This sample file defines three entries, the first two of which use the default GRUB options defined in /etc/default/grub and the last of which uses minimal options. The first entry boots normally and the second boots into single-user mode. If you want to create a new file, you can use the mkrlconf script that comes with rEFInd. If you pass it the --force option, it will overwrite the existing /boot/refind_linux.conf file; otherwise it will create the file only if one doesn't already exist.

From a user's perspective, the submenus defined in this way work just like submenus defined via the submenuentry options in refind.conf, or like the submenus that rEFInd creates automatically for Mac OS X or ELILO. There are, however, limitations in what you can accomplish with this method:

  • Your kernels must be compiled with EFI stub loader support. (This is almost always true of distribution-provided kernels these days.)
  • You can't set a submenu option to boot via a different boot loader, such as ELILO or GRUB; all the submenu options apply to a single boot loader—that is, a single kernel. (rEFInd will still detect other boot loaders and provide separate main-menu tags for them, though.) Folded kernel entries are an exception to this rule.
  • All the kernels in a given directory use the same refind_linux.conf file. If you need to set different options for different kernels, you'll need to place those kernels in different directories. (A partial exception is the kernel version string, which can be passed via the %v variable, as noted earlier.)
  • You must place your kernels in a directory other than the one that holds the main rEFInd .efi file. This is because rEFInd does not scan its own directory for boot loaders.

Ordinarily, a kernel booted in this way must reside on the ESP, or at least on another FAT partition. On a Macintosh, though, you can use HFS+ to house your kernel files. In fact, that may be necessary; my Mac Mini hangs when I try to boot a Linux kernel via an EFI stub loader from the computer's ESP, but it works fine when booting from an HFS+ partition. If you use EFI drivers, though, you can place your kernel on any filesystem for which an EFI driver exists. This list is currently good (ext2fs/ext3fs, ext4fs, ReiserFS, Btrfs, ISO-9660, HFS+, and NTFS in rEFInd, plus more from other sources), so chances are you'll be able to use this method to boot your kernel from your root (/) partition or from a /boot partition.

rEFInd sorts boot loader entries within each directory by time stamp, so that the most recent entry comes first. Thus, if you specify a directory name (or a volume label, for loaders stored in a volume's root directory) as the default_selection, rEFInd will make the most recent loader in the directory the default. This can obviate the need to adjust this configuration parameter when you add a new kernel; chances are you want the most recently-added kernel to be the default, and rEFInd makes it so when you set the default_selection in this way. If you don't want the latest kernel to become the default, you can use touch to give the desired kernel (or other boot loader) in the directory a more recent time stamp, or you can set default_selection to a value that uniquely identifies your desired default loader. One caveat you should keep in mind is that the EFI and Windows interpret the hardware clock as local time, whereas Mac OS X uses Coordinated Universal Time (UTC). Linux can work either way. Thus, time stamps for boot loaders can be skewed by several hours depending on the environment in which they were created or last modified.

On the whole, auto-detecting kernels and passing boot options using refind_linux.conf has a lot going for it. For distribution maintainers, if you place your Linux kernel files (with EFI stub support) on the ESP, with suitable filenames, matching initial RAM disk files, and a refind_linux.conf file, then rEFInd should detect your files, even if the user installs another distribution with another rEFInd that takes over from yours. (If the user, or this other rEFInd installation, disables auto-detection, this won't work.)

For end users, this method is simpler than maintaining manual configurations in refind.conf (or equivalents for ELILO or GRUB). To install a new kernel, you need only copy it and its initial RAM disk, under suitable names, to a scanned directory on the ESP. There's no need to touch any configuration file, provided you've already set up refind_linux.conf in your kernel's directory. You will, however, have to adjust refind_linux.conf if you make certain changes, such as if your root directory identifier changes.


copyright © 2012–2018 by Roderick W. Smith

This document is licensed under the terms of the GNU Free Documentation License (FDL), version 1.3.

If you have problems with or comments about this Web page, please e-mail me at rodsmith@rodsbooks.com. Thanks.

Go to the main rEFInd page

Learn how to manage Secure Boot

Return to my main Web page.

refind-0.11.4/docs/refind/features.html0000664000175000017500000004153113372346574020237 0ustar rodsmithrodsmith The rEFInd Boot Manager: rEFInd Features

The rEFInd Boot Manager:
rEFInd Features

by Roderick W. Smith, rodsmith@rodsbooks.com

Originally written: 3/14/2012; last Web page update: 11/12/2018, referencing rEFInd 0.11.4

This Web page is provided free of charge and with no annoying outside ads; however, I did take time to prepare it, and Web hosting does cost money. If you find this Web page useful, please consider making a small donation to help keep this site up and running. Thanks!

Donate $1.00 Donate $2.50 Donate $5.00 Donate $10.00 Donate $20.00 Donate another value

This page is part of the documentation for the rEFInd boot manager. If a Web search has brought you here, you may want to start at the main page.


rEFInd is a fork of the rEFIt boot manager. As such, it has many features in common with rEFIt. These include the following:

  • Support for both text-mode and graphical operation.
  • Auto-detection of EFI and BIOS boot loaders.
  • User-configurable graphics and icons—you can set your own background, set new icons, and so on.
  • Launch EFI boot loaders.
  • Launch legacy (BIOS) boot loaders on Macs. (rEFInd also supports legacy boots on some UEFI PCs; see below.)
  • Launch options for an external EFI shell or disk partitioner. (See the Installing rEFInd section for information on how to obtain and install these components.)
  • Provide the gptsync utility for creating hybrid MBRs. Note that rEFInd's version of gptsync is significantly updated compared to rEFIt's. Also, this tool should be used only on Macs that dual-boot with a BIOS-based OS, such as Windows; or very rarely on other computers.
  • Set OS-specific boot options, such as to launch Mac OS X with verbose text-mode debug messages.
  • Load EFI drivers for filesystems or hardware devices not supported natively by your firmware. (This feature is absent in some builds of rEFIt and in rEFInd prior to version 0.2.7.)
  • Inclusion of drivers for the Linux ReiserFS and ext2 filesystems in the main package. (These drivers are absent from rEFInd prior to version 0.4.0. See below concerning drivers for additional filesystems.)

rEFInd expands on rEFIt by providing features that improve on or go beyond those of rEFIt, such as:

  • Bug fixes, focusing on those that have bothered me personally.
  • The ability to specify a configuration file to use at program launch time via the -c filename command-line option.
  • User-configurable methods of detecting boot loaders:
    • Auto-detection of EFI boot loaders, independently on internal hard disks, external hard disks, optical discs, and network boot loaders.
    • Auto-detection of legacy BIOS boot loaders, independently on internal hard disks, external hard disks, and optical discs.
    • Manually via the configuration file
    You can select which of these methods to use to construct the rEFInd main boot menu. Although rEFIt supports auto-detection, it does not support manual configuration; and rEFIt's options to enable, disable, and prioritize individual boot loader detection methods are primitive compared to those in rEFInd.
  • Beginning with rEFInd 0.8.4, experimental network boot loader support via the iPXE EFI binaries. When activated, rEFInd should add a network-boot option to its menu when a suitable network boot server is available.
  • Support for launching legacy BIOS boot loaders on UEFI PCs with suitable CSM support (as of version 0.4.6, with significant improvements in version 0.8.0). Note that some UEFI PCs, such as those with Gigabyte's Hybrid EFI, lack a usable CSM.
  • Improved flexibility in setting the default OS to boot. rEFInd enables specifying the default by any substring in the description. You can also specify multiple defaults, so that if the first isn't available, another will take its place (which is useful when using removable disks). You can also add time specifications to set a default to be used only during certain hours of the day. If no default loader is set, rEFInd defaults to the last-booted loader.
  • Support for partition names or GUID values as fallbacks for filesystem labels in certain configuration file settings. Partition names may be shown as values to be displayed as part of the descriptive text for boot tags on the main menu, too, if a filesystem has no label.
  • The ability to fine-tune options passed to EFI boot loaders, via manual configuration.
  • An option editor to enable you to edit the options passed to an EFI boot loader on a per-boot basis.
  • The ability to specify additional directories to scan for boot loaders and drivers (as of version 0.2.7).
  • The ability to specify volumes and directories to not be scanned for boot loaders, even if they would ordinarily be scanned (as of version 0.6.0 for volumes and 0.4.2 for directories).
  • The ability to specify boot loader files to be ignored. This can be set either in the configuration file or dynamically as you're using rEFInd.
  • The ability to re-scan boot loaders, to assist when changing removable media or after making a change to the configuration file with an EFI shell (as of version 0.3.5).
  • A configurable delay before scanning for boot loaders, for systems on which there's a delay before disks become available (as of version 0.4.6).
  • The ability to specify an additional icon storage directory, to assist in efforts to customize rEFInd's appearance (as of version 0.3.4).
  • Support for icons, selection backgrounds, and banner graphics in PNG and JPEG formats, in addition to the ICNS and BMP formats supported by rEFIt.
  • Support for full-screen banner images.
  • Support for scaling icons, to adjust icon size for users with high-resolution displays, poor eyesight, or simply for personal preference reasons.
  • The ability to set the screen's graphics resolution, within limits imposed by the EFI (as of rEFInd 0.3.0). Similarly, as of version 0.6.0, you can specify the text-mode resolution.
  • Proper handling of more OS options than can fit on the screen. (rEFIt displays an empty list in graphical mode when it detects too many OSes.)
  • The ability to handle some (but not all) touch-screen displays, as used on tablet computers.
  • On some (but not all) computers, the ability to handle mouse input to select the boot loader to run.
  • Additional OS icons (most of which are Linux distributions, at least so far). This can make it easier to find a specific distribution in the boot list if you've installed multiple Linux distributions.
  • Support for loading user-defined fonts, in the form of PNG files containing ASCII characters 32 through 126 plus a glyph to be used for values outside that range.
  • The ability to auto-detect Linux initial RAM disk files and to read Linux kernel options from a refind_linux.conf file. These features support (nearly) automatic handling of Linux kernels with embedded EFI stub loader support (a new feature with Linux 3.3.0).
  • The ability to "fold" multiple Linux kernels into a single entry in the main menu. Additional kernels appear as options in the submenu. This feature is enabled by default, but can be disabled by setting fold_linux_kernels false in refind.conf.
  • In the absence of a refind_linux.conf file, the ability to pass minimal Linux boot options to a kernel based on the contents of /etc/fstab. This is limited to cases in which the kernel resides on the Linux root (/) filesystem, though, and it won't work if the installation requires any unusual options.
  • As of rEFInd 0.9.0, if a Linux root (/) filesystem is identified by the type code specified by the Discoverable Partitions Specification (DPS) and the root filesystem cannot be identified via refind_linux.conf or /etc/fstab, rEFInd passes a kernel root= identifier based on the identified DPS root (/) type code.
  • Fixes to display problems on many UEFI-based PCs.
  • Beginning with version 0.6.10, a screen saver feature, activated by the screensaver seconds token in refind.conf: Set seconds to the number of seconds before the screen will blank to prevent burn-in.
  • Workarounds to file detection bugs in at least one type of UEFI firmware.
  • Improved detection of itself, to keep rEFInd out of its own boot menu.
  • Detection of a fallback boot loader (EFI/BOOT/bootx64.efi or EFI/BOOT/bootia32.efi) that's redundant with another boot loader, to keep the fallback boot loader out of menus when it's unnecessary.
  • An "exit" option (disabled by default), so that you can return to whatever shell or boot manager you used to launch rEFInd, should this ability be desirable. (This feature first appeared in rEFInd 0.2.4.)
  • Drivers for ISO-9660, NTFS, HFS+, ext4fs, and Btrfs, which are not included in rEFIt. The ISO-9660 driver is based on code from the rEFIt project, but was never completed by its original author. It was completed by Oracle for VirtualBox. The ext4fs driver is derived from the rEFIt ext2fs driver, and the Btrfs and NTFS drivers are derived from the rEFIt and GRUB 2.0 driver code.
  • Beginning with version 0.5.0, the ability to "talk" to the shim boot loader to validate binaries supported by shim or its machine owner key (MOK) list when booting with Secure Boot active.
  • The gptsync utility, included with rEFInd 0.6.9 and later, has safety checks to prevent creating a fresh hybrid MBR if the MBR side has been adjusted without adjusting the GPT side—a common source of problems. This update also prioritizes partition inclusion in the hybrid MBR, which can help on disks that have many partitions. OTOH, as of rEFInd 0.6.9, this version of gptsync is relatively untested.
  • The ability to set the VMX bit on certain Intel CPUs. This feature is necessary for certain virtualization tools, such as Hyper-V, and not all EFIs enable users to set it.
  • Beginning with version 0.10.0, the ability to spoof the booting of OS X when booting non-Apple OSes. This changes the way a Mac's EFI initializes hardware, which can get secondary video chipsets working on some Macs. This feature is controlled via the spoof_osx_version token in refind.conf.
  • Beginning with version 0.10.0, the ability to adjust Apple System Integrity Protection (SIP; aka "rootless" or "CSR") settings. These settings control what features are off-limits even to root in OS X 10.11 (El Capitan) and later. To use this feature, you must set specific CSR values on refind.conf's csr_values line and add csr_rotate to the showtools line.
  • Beginning with version 0.10.1, support for ARM64 (aka AARCH64 or AA64) CPUs. Such systems that boot using UEFI are quite rare, at least in December of 2015.

On the flip side, at least for Mac users, rEFInd comes with less sophisticated Mac installation tools than does rEFIt, in favor of more OS-agnostic packaging.

If these features sound useful, then read on and try rEFInd. If not, you may need to look elsewhere. My Managing EFI Boot Loaders for Linux page may be useful to you in this case.


copyright © 2012–2018 by Roderick W. Smith

This document is licensed under the terms of the GNU Free Documentation License (FDL), version 1.3.

If you have problems with or comments about this Web page, please e-mail me at rodsmith@rodsbooks.com. Thanks.

Go to the main rEFInd page

Learn how to obtain rEFInd

Return to my main Web page.

refind-0.11.4/docs/refind/msinfo32.png0000644000175000017500000007243713002476242017672 0ustar rodsmithrodsmithPNG  IHDRBoU pHYs  tIME %5RF IDATx_l$}y&)NxgG;ja]u&Z2z y*vc@ƪ_J0c4Ӣe؝ŨKJ!Xu:#r*I12q8_K3!MNU͐h3F8.W_<;}Wn(+楦{mJϺ`o T" |g۟/#oߞ|}g[w;~ٿv~??@iJO|v>7?'MP^ sS93'@GMe0-w|%t֭[?OlI(dc?'۷?o7|~ou[7;By =v.ͭ %ZgԐWx1@ZA,w_u/wnݺwBft/#G#V~|s7~a^¯o㻷F~~?O|$KH?@y'JάMc^M! yJuY;oS8չMiv>~1jٹ7o$۱^inYgy+m[7[ 7N'y`N!̷ً?_~~m|@嶿[dc28W7ͭΟ'lmtvg NG*o kW[z,![%l\?mI:zܙ$%[7;[qKR7wf%17cRv^Y[o$%dk_l>x(Ou2~ŗ~ _`cˁ-{EMǿ=wngg'Ξ%YgϞ%mm٪en>Ȃ/tHpp}o122e?sΝ?駟s8ٝfi}~ YTggg6; YR',!g?8{+"鱃V) +4os

G''~~K ݥtwݻwΝG˕3766~_w}SSSҏ>?կ~us=;355~+BH⥗^d2Lfqo|~ݻw/BFFF~{jjK_RJCvw t0tuGy֭[o8O?/˄Jix*N欽rsܷǓF8BZr̙~N.:::::߯]Jݻwww޹m4 N?pRuuuΣT \A5!G-&2' s&P{yyntʼgCC5)? -TWZo bI. Bs&]{Nk-'f4$h6S--C',TWFary;U$hEiQ~-+\ApZ[MɠR&g7+{]*6H)6h[&Aic ?/{&aGu%VFz'&!ļ$YaMqT-֭*ԨpZ'_F8anAu7%BrURy4Ê%jIUM"{n:KȩZ,__-voNZ8{a,)2[=i^Ȇ737{Xk~&GڰZ\BִJP, y4j=i'k-o SijF.Q\aIM=xZ IhZ8nH5,$7/yg)D神jT'8k7 u(h#^~@8KcccL&8@$3&8ڈ -:>|V:hT_:::Gg_z t r1u!էє+pnڻsmLMM_G;1Rد uuuyʯ>ǯ3 =:\}>ycƌyoT1pŠv }ʝ}u}O?>xPղuy{17,jW__r`Gm"f ۑmrzUf F1䀃CS$tKqgo}O$K^./mt<܍m"!#?}i{{{Ɠ?~Lj{{K׾{Ol۟#jeF<}MN՗g˗-$k[\2Z>Ξ:^^۾OGd.>q˖,0/-]u3VGrQ-?OvGZ''.1bKl+N4NYɷr8=]XÊNpgĎ#ua?uE1:9dmKjXAg?t K)K$φeAk$8ѶL AiC$PkSJ!5rNY"-kEkj0γ譛H֬̕A@nc&tU8R㯞{ԎfXC}pnoooD یGfsu\lc[) Pn{;K%M̗DzTg u.^6X :5ok@>O^$\qúZۀOb׌//]ƾG4r mN!^lLH񤎮Mq W ^O|.Ԥ3 .}g?˗e7A,F8uS\,. <8'vZ^&Dz1P̕g5B0[4_6y߷pEͰkNsLT9,am?/`bG枱1q"q~Z WX1W{nZsZ@lPj^23AПa;b+4ov@0֫Nhਁ$3p\gjj*+W hSׁI:W\Ajup:|_G#ֹq]o ΫoFgg'N5黎9JuSu6=(F_|FW8AyE;QgkXbY +mTVr[̕ Tٚ+R8G,[v2։^Nc^B9@:eR1WZRږ;`wϒ)-+7U+ً9CkbE I1_nY!e"ڔRjHͧsYMJ:QWm~fB5We㙇(É<??{ߴ>ǭ'"gu۸`ņ&8)/{c2qi,neZFȺA1։2ۖVPDB,[bęyёq'0mGWe^ԅpRѕÌ^Zӂjͺ:^^|ݿ>|sz2+|VoP'K.DP!|9WZ|hNkDoivtٺRF(wbZQ (63Bh1)d@$Z唅8`M% c@t%ΉuqxKSirNQS-T{#3oSu>=}BS2"(S%u c}$$|K\֯_ .B1OR&Ew?Mlb) =Qy+gԐ3HjFv-t L>߫ETk|16B,u^zɆvl-8ǜukW'ii:.k/Vv7<*؋ӈ%ޜ!bi\,ϕĽeіgW̾' κ${h\,FY'H6SԅpB7U˝T^o"YcvT)ƗMˑJMu)I.#HIR(ܒnEB~X16$UjYwksčMQ0?r|q7IZ'R=ΗKw}',{e)"ɱ:PoUi\ڠC0[ Yal۲V>eej'Дl) 6h{6xSul-G"-٥O5ۺZaF)=;P :Ic)mVH鸟7uI۴E{PU穋OclN?hƾ~r>G/taBGZ91oOs"ٍ̎ʗ\6-ǵI[u礹[xcCV|7|w}߿u۷?c ~&Gkh!;m<1Q嬉kE:UvC;r]bIt ,Ly4%ʥQָ77sL~JɬZ[[ Ey"wPɵ;e~a{OB6ۑkaN_Q?q@\ʲn5M_ʾj(;{ݥָŎ~ZVimʊZs/{g%8.ZqS7^p^}BtUFTk:bIVK$vBRPŭ j䱀d0Ҥi֬3vZKVu}O]Z%^ZOc*JEUV` {o@Gu,^]k"m7".IME8R؋Q y$IIRP }sy2" X]Lu{EUb)f/dUU{xL/:Ycз7p}kէSu wNW\4ƍOOOOMM鉉񱱱L&dIuup:8Zq5FyoFgg'rA(wrgu{vHz:NX~~x+\jxKD1VHLW7U_`_\=yӸpV z'3~+U64\5)?&W'TRj'uZ k\PZo\iϕ}蔟%/RJ_mM$Po.C6T+)h[&հ +E? PCy{?~{?~i}p[Of2ߺD}Ab-{/,ŒL f$oȝf L?!+f̃8AZ烝۫?Ëևvn[_YOfi!~2B--N~}i/b>.`k v+Q|'Z  iRIqO(ÂE)R&EoCqhf* )no|MwyJ{v?ȕk+)RZww++:!D,ɝQFW\J}wFeā2Kκq\G,!Ѫh`ke1gs\;WBcv3ԗ7tǨlL.BHn8 Q8Z';OXdgN͢3x( Cm>ДrSlf3{`_+L8Vu.'f`lp5TA=&L w~ٟ.SKbN DWJM;"1‚:߱VjA)oGHR1fZ Z NPfpE%S͕ܟɑ!pS]hJ%כDZhAjA Vj8]q?x);u7k=i'Doiy{nK|}lvBܔĒ{:8|VJoi]R}ӕحv7prw_h!U Su>'vꖚ174x*]i Z݈}~-7+] IDATF ]smJ)5S7989%n|*Q(l#9U ( E@''dV,~5jHM!X.EۭYo$nBu"=/6'$oe-Y~BRD𐛉'&?^ _H჎^*0u;Wxqyܶ̊>/f#|{(i{t7_nΕZ:[q qMe˄#vV77 Ru>/7C |CsuX+D,7ߺiI ].dKN TǾ O[O~x]dx>@븬XIu긏Y%S~j%ۭŒ|go'ϕʳZٝ$k>՜'ucܖP +S-DW'&qg[M&>"r}S{L@}',tK^]v@Bl&Sn-.{H,uX-t'qOſI8.nX:ɝX;%EVnT \RpUP3Ղ/gd7YVn$a!QSdݏ|Nϩi-Qϻ&m7{̗2u|qVN}Z_ۑc1P_tfDW[ǼL< N>V˴@+ܶa,H8; ^S#6HrX> loofo֭۷o#P{`k --/ WwWJRJr>6_9{x'ȩ,K" 0%ngx!$Z(qʨ$[Ԩdr\c^~`.f4W|Zg\oi%b_pq|e,*"峓Exx㰆N/ff{{&kh< o%[Zn?6ܔǗ;o 'ΒPE qlEOw/W]Q,ݗmvK4$4WZR'xqQ-Fsq ,Ze{<`*&݊|;rg]CQKnZGS OW$qgr[~-·=*$c^AB6W--M3ƅNNq|y;'Z= ǴDlPJixc,BMQPijgҗ+]pP_^*R%c^Ь۷DWb/fM'X8]u>T Bk },ykk?ɪ˰ %{h?Fp\Ep#(6[ O%Y-4sM,,hptfFW/(T'gͧdP\ fwz MͭY#4% $IVtze[ӫ;/na=J ҷmK~Rɀ㸅OƼvභSpZEԩʕ˗{EWZ: ƍ7'XkkkcccL&  N2hؠsGuhN$[x]^t$ hpB땆Zpatt2Tkܦt7S Q>!6(=w(=x7ka6:aHƐǛjAhJMvZd0Z/}F7pEx8n |/wڲRyiw)3g,m)In`) WPu{ 8h? WH"8Y8%gtKw6LHc+TMf{W9;DRP(<*t>g22ҡSmS~b @[OX%aByT~#}vG|ggmY+pR#!m$_7=;+S-{uRJji8%N'DWJmܪҀA~ 仂3%\ExIbRӉwU֥)=!Ο^ѹqҝmgj )ui {mVZJmKuoo_bIs&e>|0fVrY^StG՗Db˻u3dW0p| hZK8*3P4{>gC?rUZdO pONO媬;1՚NxKO 䮳Pb9x=c$_A'I%1r74)Z EdSGui:FWt6%kErC\It..Չ@@$`c-&Sd%6 -{vmY+2` #r@`4mK_ O# M>F%YAOEmqdNg6pභSpZEԩʕ˗ ղ@ 7nHxzzzjj?`MOOOLLLNNe2L&N2:8Ɍ "6(p hhhhhh@@T λoCEWL]atsE$zGt%oS9??xBY0H]R2@! )nИne=qZO{~;I۹/MIIlHM/*|:9ẎSC2hGiy33_.97TtS-pEt+;IuCɷnVt/<_7{zI&UhHM"--IZ #dیI/WHh/i˝ErUۼn?>ZyTKrwðy+ޜ!m|!BtE|ڛ7w+5J)mZZ%j S@>XԙyG\LDe-ul?%1~̇U)a:ċrNJbbI֬0sބ%OnGy{$H +0|ӓ ݊߉Rƒ~e@Vi#ff!iZt:)rf@z3WDV7(*}SaQƐ9p_XȠB l݄tL-]d{Pɵ;n$]Nߺħ@Zdx%vO3 V|:X{e *MbIN3`Gls1ZЭCq>N:AWb^$|uIrf@bdձK9MД]ĥ:qò6'BĆq8nH@y *0EK\a].,=Iɗ;FW`<.Q{G%1e_3moo'xӋhSE+/tkQ`ܸq#}驩)6===111999>>>66d2 :`ؘjMK::`o 8 6 ZZZZZZ:zXN8]jya"7;ueĕ+CILm:![Gks8:X HBS2ݼw/X{`^>?n>+6:PT@cA^w|,&Vޚj+j[);wOaErrG̅$庾)q8R)%J`FVE 1gtv8U#W)é'~^"!]%a}jKK<ѕ"i۳ȗ;-|ݠ!BtEڔRjH7nFV)mY+r\Dl]ʚ?/W4?)V֎2F`vVZ(R18w|v`~5,JN ZAܡD$k-k$U/m/ ׼nW˼!q%96+qvL[6KI02XkFVrY^S Ni~u*91 hpz%jLd\I !a[0P7/W{wkQ_cwN;=T@S52!(mRdnםۡHP]vmjlV)g3PN8o=T"^k?$ټ(%V*kE! NkSp!Z~) 0uԔZ[[d2Lq0lL% H~8@!ϼ%W#( AiW#:JK8yjyI{J\麂¯W浙q-RD1=:P$)n̔|WtZNUݠRN* GFNt-u~i?cx3dE7WH"Svw+\AÊ7HeY MIuY4=^P7YLO_96Tnu#\';D*_\E` E9 Tu%RݣX˶4])=Ko|C۲5cn]*6Rӛv+5J)mZZ%jfw٥C;rH3سf?VL+v\ʡSHبB 6j+k TuHv!5P,ZK's'WᷥK3YgBHZ @,ɱYKu/c5-ܑ>vXa8Ηri+ǝPSum/1/|FW Gar1,P*i%jL4\V!$t+B*Xv oL`qG![_9\S ULҴjtoKwQpu@7oOiAaR&E{(C;a%nB?,+7bҞ*M&)`;W;ݖRM: Fc zed#d Onh[>ƪFPG,+R)]W0ݯ~%d&gSGlse pu@\SảK9M$) 8X;-;&R=OA"6h;gꋽLԭV᭒7UUȯrUVs67"|"}Ԏ}b[bltYbZKaNݭ,7Íy)/Wr "pA:=q\ݐXi'uܧd4DBT'sXb~|kfFv"y厯<gBy)ɤiZ,묲a+B_.9ðX{|r$d.4%)uo5nD3T,ɱ+#pT ?/a$FߕmH1;\6D m瘪)XߚכdyoTidjb У+j[l~{>LjnFV={{_WF)5%v-^>|$%R[֊Η;n,!o34jezK8˰X{d柈[iK6 Z\făZ1aI"|[nZT')ogrZDt/r)Fm˺e}O}f/8˜j!o}B?F[v&K(VbORy뽢zH\!KqĹ^$&ԓ2}v+=\ ?F$^̐٘G\yM,`ˆJn-#PF(Dڡbz+Yl^>+blt  ud}fW-8+jѠFr42mlQwY |f8n8NڱPK~8JT=P8-uN|p5FN;[İ= Qw"/WUԁGZg@eq=蘺$^#)nkEg%-n@cܷ!dh^d cd:ţdX*øuvIYNxԹZ}C=H\x`d2fϗ;9sfJg7CDl~%ӘjaZy1 1l>he kEeQnZ]r;l^a_Hl98G~ZĒuJYK0!u3xyτzH\txWϰ'b-rU֊ǬU=1 K)^H=>~iᏙT61y_@\:/53>>66d2(CɄ/JA'bOp > JO*z1l~BM7=z\c:"쿧`N2:']_ ) {x7: J`(a!bnHcC)t?̱ W$-wH*٧3L;uCwE{;- ݦ=]47;ML /658 vMIRSpn{S-Mpnz$k;dWT֪. 1ZO{|Z/DžVwT N'F+b'6y}/B%gAabaȴ]5 4\{hpr]_͡r-kyrXńŎ8?TPuvvG{_99'aZ՗DFꯋo6L VBBM"--I~LN.Y_`;}(tG.G*!YhJR`X3;E>ֱqMV8$AG3ֹr|߃&qn8qz#mJuMbIn4ٶ:A] N4χ!1g%R}DoY=g+JEYv</^0B煢vrh˚Ȫ.&!T[Y;cΗ;-[qHb}ƌq ^t:úɾ#T{`U\SF}j3;Ĥ[&HrV3cq'A3q$Ż#Sb׶Y-nǟnE8j9C=쓬)_XZAOKSyOv@q>}Bܔb 99%w\U:VpO>٠v729MyJ:/|udF[^hTkZ`iXrUNN}bJLebei5f/e"RVCa厑qq/̺}%-ctZS-,Ս~&@}3r''2|4ɖ8Nt٣NV7p|H~%w}ٹ1DQo6` ՆsX YdP nFZ3KLenkJHjg ddEJP EN;P:: |7!l;O_p761~P`lRKԈlgbS1Mhr a3#}eЌ{<޿.DF5!"u2?/vӯ,i:e"1g]ny+x⒵W"+%i%taJMx}(DhJaĆxɾ1Kэ5pBS2|u"~y+7RAYl)sÏ9'3kN ws%&2)<،/:u+VT 1=@8zrM'Y"6pLභSpZEԩʕ˗N * GT F7-Z\J7˸ߏo(ԔZ[[d2LqS{˅*J7-ڋ[C^~EAlP|GkFTa[#^`5m8 hhhhhh@ Du)T lQ+\@z*ԕi4qN cJؠ1{V R@뀃dP # K|L?uvH[M z:$މW7卪}}bH bļUu{oeWPrBSrHB6*nxi˚+b ;qHRA7YޗcNXbùmk#?/ZB.U}V/L4zV|XFb~㕭z%]*%"IJRJ;eK Z(P'vͰ6Z.-@뀃;厵4!.սЎִRC"p Mi5ans|& tQ錇./WRl}#'$Z(%|w;jnhG_ٯSH[4x(Pj^7CQ#[]qP2"6huC[ /Ț9Y4@CU<|hOau!ﺁohgXd#w(mRBFƭ{6u+>E`ltb/We(0:A+j WKE eO%.[>/+E t6'dm8㊤K;+JŞ+Wtz۝/;mY+&$Д6 % uj|ⅫתO/NW\pܾ}{SSSkmmmzzzbbbrrr|||ll,d2upuuuH !;P1Z(X+pQ1S-àD eJؠ(w{ypui&_7C+ǏtS#y<$kzKK5Fվ^ѧE<8|:onb:=@37 ͭI=4(/J'5#$xՅ1[BUxQ!TuAEUs3FU4))ŨQ}>&l(B9<~;yȪYcr_Gk>}ԕ^ɭJL,Oy-J5U8|+Г~ڳ)=oRGѣJR^˼ޚ6p_syE%禮ծY[bm\pQ 2ԱP,~0YV'fe.cUb u2?wc(bȆSw IeKb ¥q.Sf ;cF_$;# S~z꣥v|3=.ٵp@n52TXsr8Ȣ]YSɥy%mhN ecmH*ؾ<ύM/&Q̧q%q.)j %[}WzyՓOwȂbŢ#nU=:ؕu6!rә"C-WyEhٞ=-6<9}V.>xMeT7s2֩©I#*b=:.te+fZl-<ԍ%DXj&Nzwa@*44Ɗ@عQ@OrXGGY~='LLQJ"G;nh$?u1x< [&_ɣSz'Wbfgbӫj1#U^A%9c@_bjBzubxRaTSv2cuJZEé䬫mђ~ -ZXzԿ@P(ŕѿU>`NO>h\. ZZZ  :uY@A~ p*W|k5nݰNeh!@K9,Ԍ4^uPE@Ab^@A#c^@A#yrE^7إ>qRh_ʕ¿e)g8yQc9PθKHa 5sInN~0o|yrSN?)o]^yUedrE{|R~,"^1 jrYجykMgpSW)HN~4O~r4ʫi/Qy䏦@R\[`a*\JH=~Df-Zۭ"啒;z>bYjGmS^D [,XCJS9 ?B츇I{ՠ?%8κթWssM~Nn'U;2gmF٥"n?knr:9Ɲ^\{,g0OxlP1z엎g|Z`ܨZ{ǩn,3Œy gZ](ϓ"~K/o˽Z#FI-ԎZ彤low!o4}:}[G-?˅{%WJɽ;9E+~KkZrd429FƼF|+_Zݯ[$P(;WfF]eO.&ӊ?xyrPeMMM`0 2Yu:dP}ف@W:C{vj@gWTezw:x*Oe TcYMu/OwD}PKw4kz1~s̕j:z|MluYsrX, CU^v.9vO-wvVGKG# r2<5=գ+r58(?-$V6f=]v vLtWGZy|.b~zxRIi?ZT1)PJSh>jeťBWJt6eRߪ+u24|n{D} W=;]CJ7kqJ=sFa̖ FY\d4#}AibOƘ}ݵs#CK*ȡn;rru\FR;;ŴkU~fnϺdճ;%׳;<]%.ߌ?Ա99z=+: f N aSbŅڰX,ĸxV8 lwBvbhɜ>lk[Sߋ4V1m_Q)^))rԽQggӽL YlܜvN Qe3|z,6 eD?ͼn eںdC@A.{ϝĆ'E-xxWSOW9*Tv8w|{^\V2LlxS9oQ8#6ȖSJg}Fp_33ذFQ>cz+n:uĭQcE3'$1ݣZq=Ӳ|8i˯'P(Joqejfv?<ӧO++˅B777755`0ȼhdd@ u:d u:@mJX~&b/ImE:a PͿ6Y }f T;կ _64@,MMd4bX,.t W%TB_;\s,[%!KU}dry>Kd`"G; B(.)sguQv ЕΦL[[uWC&.X*w <; CkOwz24q_p܈Y ڽuok>D:gs +oGB2ӣgzdA)nd"C bs\›*|g٘@И;28ãɌyj';1$v0v >;Rʤ '72w]y-bKVk> {(Kwbqur% %P$"sٔL©i;Kc/1RavbH&b Ɍr'kGƶSIuxҘɧ2QcPYq ^$n ;ڋ8^=ʦ| FK.uP5"}EdQ8(bWcM Z*UHG{ؼSutqۑ)}j';1$Y>yzvL85;)΅;^Ev乘Q~6ނKd4%vB|^, b\kpre0hؑM9>R<;O;wԽ^ Wى%sXҦ_YVkGKΣKdԵ|1c]eD\rɶأع@~^rGzb2(uMD\&urgJrBPڶ%#3FquS;̌u8ݣJlf Kd+킹gyru:M(eׯh\ŕԥO69*M:;r^ϕѧv:eR8;l6$˾Z.)/n;KKzף7<:pK5 P(Joqejfv?<ӧO++˅B777755`0ȼ9TlOdPqgAj=#V{ic>ywTg>k3D{37EDrZ}."__λ#WnSKʎs e©n4"gb Ryz7o"omݾN7{Uu0ͩXtM/0."WFD-iN8 ~_W&"k+rmu gF%>H-?fwoG{%ʻouICG>٤ߖ5rggg\q]gc9cұ__;;>6scQo̔zֺzS ҳռb_5+gLq4#m侸S,O>XQcfMM"F2Ѩn~7}ߪti|1s鋄?_s֩svJ70Qkqjhn4%"ÿey*~+j:;>s鋜6-6|wଈߞ׼TrZeׇ]u2Ŕ4L7pba{HDF.5e>51㚆X 5XoIcUO ߨaJ9;lE2kUzKm-YG/*7nzLD{Oiu]ƗE]2'9o G#D?ΎolllHB_cD*-> %߷ hj-ipptOc@y_~ S/OxO9U,KdFhyg˓v_J$<,rk$ťq{Z~ݗ[oVC o$g֩V vQȷYyđ(7\x!Ǔ~Cz_{T[|(XΎ\:8d>oՎ̥/Z.@>>lwy߶>x4ζyǝ7oӟlg??_Cזp)ӲΫ j19NP*kmm.&ⶍFh_rLy#~UIu6|٩^=9A|W `bfrt{Hyp]l_MxO\_\hV޻룥[)rT-UG#ThoȟUgW}WRA j{{]<uJ+OY'zYYLMU+V> <.l|sC'n}#'Ttٻe.:njSZo_ګuo+.\=Vxť۸J*1|ot~|+Ov@ `/) ~_S'V ޔS7z+|NԹ֣vVШr\8niiy7TYE>.Z[~YjפfzT>;u^x%A%ۢkXlXZL^9=~?TΆWS,֣j5@=1ҿJ@ro{X4@ `Lhߐu@Ces!;J! : h{ѧsXhr6q߾}{ݳgzYlCmEqjϞ{۷q-:`K477oQݻw޽`0 ڦv:`K [Q9ئveVKKvfz:.R9(%zE7=0PSSU:}TWIENDB`refind-0.11.4/docs/refind/easyuefi.png0000664000175000017500000011754512707211603020045 0ustar rodsmithrodsmithPNG  IHDR$u(4bKGDC pHYs  tIME* ] , IDATx}lirj<]0;BCi{ĊlV̀yҬDxwMmf- Ff3d Fz(#"4),=0GI#fH-t=MRJOIl~oMZ/`o=,ˊ-..D,cii)=HB!B\|_dž 7lƍ)F,..FbDD!B+D$CQsB!T$ovo3CZ~B!B _ lX\\To!B!֝E6,--'B!$B!BLh,!B!e?0 Pf`GmniXme`zU!BQ eff ]vYjbP*6DnXQ!B!Db3$s7 \#Y`Tl11,``b[vyE}Hwax?9ͱ'Kє>U?۱\egqd1d68B!.]**ݻz|>.^^.]'(&M ",GxsD"```lp¿"wp$E4'vӻ B!^(V'/^~QK._ŋ%-3 mPfs7[&ּܜce}"c0t !Bq(CH6R AsSaC6.iTl"7"ss6SS+ȇݵֺݣss yCD0=@wjk`?B!w(tҚpL.[[S~Ş',*DmpfJ, \¹DK`cLOO3=}g;sv=>ͱ'<938vi`>S|RxnumIӨDžB!DZpME33{QȜa}{("`\h+Ň>*v9́*M?<ƇǞI>d#,o>8RˉxB!Ȃ+z`+= 0۲̙4?ms 5Ui*;Z̽Áprz'/;s̽s)wU' >/3W>JU(s h9Jܧُ !B $y5oiTCE-&5~;j#ɿ7ze54Ԏ* 0F=F9˟~hZ߈ ?_69&\`jg*8 w*%q!B!21 MD"^},&ba6633%MÑG#oLG~NN ?VaN2?yl#|}eթ|cG8B:?DžB!^}TbOx5y#Ǟ-&ib;#QnZ+Y!v2TMB!(=E ϼOd+u1Zߙ99‰)g+u!B!y$.ޛ93!B!6 B!$B!B !B! B!BH!B!ZXe֭[ !B!ĺ!B!B!BD!B!$HB!$B!B!A"B! B!B !B!ɺYB!>l |(H{(71 o,ly ; Dm6f=!B!$H2މbEućײ,"X;ÞmWXi !B!AKd8b$r"l,m;IciPQa`P ;bdl['N!B t  1W@$ߎ:,OƳmR%җ93%B!B k5m"r3\ cs %|7 gF,"rӉd͗V=TNμ7V!B|qF79"V 0Lm˚L(3 _,7a& Qy剒0sμC|~eĉ+f8ow_~=qWGtx㤥ޮaaxʩoj5!^b,hrp xˌ\il<Ɗ(AծؚNXuҲᬎe ^B۶8Q9=;ʕv>ncW@y;klv)J[667͢ut-(17_릑Uu(B!;i YXez]vGɺ^>ݝ'~/'9>AqNyMkR V"7 h!:^#6h W.qe&8 59Y\Ğ7U_FSf;e~9I>HČ%#of;fb$HOB!>*Bރ3%^g^g{ | 336>p|J=(s;m*=h2 aDnXkNOb_H7C>JWΔʹ=2O7pvIO#s-!>ILNJ KFdS8S籠ق'i2 6y=+lgf\K֥;gA&ebD ,G0m[*z&q-gys:s^xUxO =}/5_Ğe?r({.ZE2-# )H!cwukuS|a,ޢ{i,"Md8i_g:x?Ng>9+qضM9u'5Զ>,+DIq,gp]~gy&>}n;\^ߧDkWSY{-(mB ( <Ν牝= LwMAs[ z߳RމـXie[4B!>V敎n޿'~uiv~)Λn:8mvWۨ:M\{\?TUL1@"oK=K\Jî8 s۵_GԇĿډpȞmB"{9 »49LƲ_ I1aH϶0| 8+`%GN{&Fx9O{+h{dV9<fH jfH.BTf̲裳&[Ig,c?f ׼3 c%fua'ޕ0=0{PF AMDm*Lعs;jg#B&ss4?~gh DDCEx op?mFVqpm~=#t?I@GjP‟ws ,>~$"ԤkWZ`|HG<34%YA(fQӭ]!X'1Q[9q$:x@XV]2cL^B)g.53يޙb3)sM5~+MfȜŻ?z0p%«Z|Ϲq `M$²}HI_d3?kKZQA#NX䆝h7Qn{¹szX?,y72(fh{)(=Ig""λwI}H*m,:K574fc&=Buc42q^:}4 N:8mU~uq>gOuaʴ06[B#ᅵfaUIzs}mI'9V*+9JA"tx晎eq3?k&H*4-Z Q >m8[*8=?oGʌL"su3e&URyڎU>{.Œ2wx,l ;%l ?%/o_sn.Yǚg ۇ$1172`}.FyҔ·dCr~LB=B[YgO3̓Weԣ\u]I͑>omAX~PhmlJPj%?k%H jVlqQkf>|Þ70ͱwaT2EYŹs`X7%g!Zki{bg;7;}78[ }f`N,-󏔳ss/ɰGxD.X̑]z{w3$qP`b(݇$HJN r!Lzdۂw^'Ȯ tE1nد;y!hrَϰB i/l !i +֚Eu.mv EUNӬ U>̌;}{D /2z/Ef07;7RY'r71f^kڹA]ᬻJLDnF8wä8w.)~짍4ɜx> lB`}m<+eMSK=楄ivn3[ vmJ7N: C4 ^9‘ Br |:ߏmX'A*rk>9lgs dCaTT ⯰033%ᛒYt&3[*ξ\mJ[4o0؟{*hr9w=Is-5I(M#Y*tJ+_>ZɊYk1C2~\Tl{ףeXH.i|]_`cz8Uȸbc3K\? H#…B!]$H+EyӶ9f 5~-` gYcX{{_ZuY^F7ϞxUHrOs sTus;9wow 3{lW]if ~ȅl )+XɊY¯M?~N=~'vw6M3,k!!fN6} 8=̮ Pˡ'3_B!k;~_V~ߤbꖻsrwa4yOy#OS7({ zgGo# ߎ z7IED08;)sVbf jLs[_ej9ugx6ٖJVJ/˜7Ww]Hܟ0hZbFtg6e 1OJr䎰…B!]&H܍ cݽcJyH$u+xW][|,«mwޮ-eIP ̰oUrudOov{݁zs\\dMqUNs34(JeϬt eݜ 5)"h=rvSjVo3Ƶ:e$2fV !BL̅07DnDm kƶm4@䦻_EufBrPDKg[8&{gty{Ӈ‟3{F{+\_Y^׹q7ػ+JN[ni(Sh!VĘA/; ,G n[6x `,ү| !Bᛚ= ɗץace#{¯3ߝvJY>သL/xmv~qIsa'8 B!ˡ3O[h0Mٙ"3!,nY.oc]ۗ:ƃK{ʶ,>kҥ:ܲN{fiE>*3fqU.:18mar6֪?$o`Y !D6}†m,zY8f)6^D1giS=۶ !TA2>$߄\?IS.sac̓ 0A.3y:oe&Lӝm:9'NZcc[f fOŬ\1͙g;6%əw{٦W+-ͤ*k_ehp1Uk:ۦI/zmSc~s'׽ig벲?4~%Aϝ*Ȓd0, Snc1~)y[fSZKfpL,B$?41PS沫\iְ&Bi:顦rImϯ9s'ٞ[>BI̹r=w= <{?yͫ#:vrM7;pФr?3$ ) 6߄\eߏ*J\+\[Q_#%`"'d+L%X|lLl\?˦e׳d;K6Y6cwLZ -ar7Cb{<~kzYbqi}n9ꓳgX,aFtO]w\3χum""WUk#r|^3t<YNK6Y,/BXtpڊ&G0>VϦLG*fVaye]B}aq78enƩAu2Ot7e?`ϝ_!C\?˙ -Se5;H=>wt歱x78n> -"U!JIu:3Ҷ@)Ue3 Y%`{?iQ 6MQB IDAT5~c "²OCϲi8=R]D7۞ '?&[q3"dõOij,}YUmڿY,Ia$yMzt;睟vO:tx:orINo>5GĈWRgB!Bϐ\oܾ};mox6Kk3طop6 Q3!1>h>/rj5Jχi ׶#!},[E_tQ:}lU7G!P#5o!ϐ|_>{0X |߲[3!ƍ_\\Tǔb;7;{`U|ZozX_tBU`ju+:]ٵ-?X+?i}BᖴQNt q B?dR,cɍ<42q+Ԕv8.qR'Q{~bCO/>XOM{?ɕW0 #$`6ɿ6OuY }LV1BNGvjZ֮:*!:BkԾs'E|>c1b@[J|_ROQOAc:YBOYXdaq%,83#7nLdIi²,ۘhjxb8ٳw{_K޽}z/Oao^>y F{C?CqKpƄQD)L1iQ㎉Rggk~M4jqfEiN)4C"Lz@)Ή)tݝY,B7m83Aq, 4ω{\1Fp_v9 e!DI__ܾ"w};[XNt;ygNYfG$4NA=.[ {Cx9{oC)vRQnb P-/XaW-̶V~qoo/_,'Rтhzc)9VҊw$d"ޜ !E[,~ ?%܉.q'4ٺ] "b/yՔEaN10ca]B7bO'wnAt6NtlBtM1|%?ɶYvoo"dY1B' !3M!,ʴdO ^.<[54;c4#;q,ݕC 0˲$[·G Y8R,F\ߑ_Lq&vg %n(,,7o ,F_W@潿|(o=Dg 6ûh~1z~Wy>_Vm6,g'c:~D78,7XgaFZe`E}&$3 "e|>|xy跿??ҙ>+x-XGWe]b>l2Zɾ}[G9=E!;!Nt9S7;"~(=="+k~ջMfyۖNnt9۞KbU8D飞Oh|sCvf`U~+pSe{L ,_Qs3飧v[NsrϗOswDn3 *}Ap̵l;t2ʌY7LPu#|K_0G t0|`EZ^-wS!FZlXvmH#@o/ Ã{*A NtgާÃ~#JwFCx۞r -WWlh爻y@+C@j>W"EhU6 [D;oqzZ[lv*g^NUe-'ǹϹ\[g$?BĽ)T 8 ]v.ƁLh~7j`X_K" e!ևQ[i hvupzT[u룪6N|=̞/ ,!M4UQE;&t:ICd1>4KWNZԉ69 Q.E\Uq],im%?UQp -gt:s~ _\ϗj: V!Ľ+T=҅CTwp5 -UUBj>bٛif Mۓ39!Oq R[m;)U@OkYq2D[ʌWd`!X̽|t/W۳] "s#/p~ˡ<\oCyچJڝ @h]-B[rr<]չ)|N?*A"B1}oP:q aB>ypP3a8٫4:!e~NŜp958<5j1{݁V!%g"a !ׄ*qrW9 fTpS(}--۞Q(9o{s1j)/%>o){O#CL]QN+'],x}1b;Hm| 0KcϩUBх3rڶu^p߇iM3"/۹iK؆CFo}~[VߏzQW;k983=z k)пE[A9)8~;BD!KU<hMdF4P7};k9B/]T|MSא[ 8cKem[ }Zfhe6[W_5]u#>WNsY8s|SSS~? o;M`7 Ckܩ,ytL\֤t0nu$bͮ~[nݓҵw7GoBݿ!b}z>si3$-)|IT5qټiMl0uӜ|6АuSel.$]ilͻ3BQ9b 52{d9dɫ [ u0=h _9j;uLr5Ց"=2D PĮBe'DX]!X#7xXl&fB5u<+&HhgpR|Զm.8lwJOC!փ|IN#PڬD8Dc稫2dt~l7eP{(u]'ZH!Om8"LN[U ;etMsLF'ɍbt9&U@:|ltɆCxxjF+d 8uH"Rs9Xf`9QZlN>_`ijJC̕P7[DAL֞,{(7B]ס&?ٮqzc##8k\|<%P! 3 !ST:b ? \dCrɺѤْӾM\A1h; UZ`UI-=|e +$]FOtQw4*\i W3hHýk~'K7RG׉k˳\>bqqWp֭U~#B:鮥 Um0=# Q&ikiif UAbPq&[Um7,OX!z!PYZ -IJl;e+XCARF;]v9VQαwѕYN~۩"5I̻铳&ۨINLCU60Y[=<฻MKUutveXنZ={+)- EܚN }͸힛XMa<9+Sddrf4]UѬO Rʾ){!^EoUL}LW*n ANLWfö.:s ~JRdSK\ {l=.ӣ 5{Aq>FoBdjj*V3,kYO5'YX²D:-5ЛHSݕ掦4,8H_-ah(xYҥ\7Imu|GXfC|* RVlhBf3$}|- VBpYw9#cZ`-]6#v%$Z27uyy6ʿ%#n_D^))mΖ>b[û755{//+vA!xswuֲ?ܺu "6 M҇0vnvx3c⊒裏x7]!m=bX3O[wj?Bܿ>߳%Ycvs#\ze#,+6ْBҙme3rf@vpyVO$1"$yHp 7f?_+ Ŧa5NS\7?MVZ|!RvKK\ر['B!$HV:"kُ52Q{jeg9V? ֏:;#=5ڱݮVT?HX@'B!$H!5~K: ؛> _Fלx@8w F]q_P_{'~_ KoM×4Zfvq/u%g3y~<-{/(U;? ׿ rg~w/Wsd节<3k N7uЧXAr 8m0{i7_Mkk{\i2`=xmyߩWA_;c9f@үo`aSNkh9*J|ht4Fc~Ï_ ?\%wj>-cBnUAǂEP;̒㮑+l[غ/2JFlXOtCC{>Ɯ&H=Vro0iSĀCVTrgGߌ[<<⃣~ s} ~~)|c+ ?'ecd_yjw4p.^߭D 9bk|~q[oDry6Va8Ԡ~{~oz9:D`\\ Gz{84&FzdC;GZZt$C\8c~Sqok7O%ͭtL8)@{މΧrVf<4\άLz$w gP#͗Ǘ|#4|nx;S¿oM][oDΐdߐϛN6w?-=OF?tuKzF=DMݙ: 4r>C% 5V5O?eAxK]`YmM#k[>tW215x <#Wi 69 Q.B·Zon~ _?<"\Ix'e"֙kpjWtN[.=q&kO%hw6Kyr.F2f{lmL)kz6`]u#ԳvOj;N1HI>ozBl-ж}/𣝭L)c|СAڏǪ"xj>_+hy!>7A<~s&NMQ`e8ܿ5W' -.O̎|qsU\iۖuϏ>pVK.W+q|ZtU;N]uxߠ'[ .'|I싏` 3=,7>nGILWZؙ$QU&zUu-lu _e~Ƨg! sż͓&_|=<4~y~c+f%+q|Z7XpF9.zU8ϗc0|#g]nOz1 9J"ETmsQBLP{]wU;.CB{[B ?$E"J(wjayOxߦN, u-T[t|Y QL'?ߖʙ]ٮ xbXJ~#WG)VٺfjpC{I۩>Z\_GWP<,&fh=1ʉ KG@oQuu'tCU YG;}HFOUwXzյ41B GQ{/Ul)*DA7R -5TQ5)޷4W)rK-=7H hmb"5)1&T9@`?vvwv߻ټJkkgg3ׯ*ՙU*ljWŲMԼ49C2H(15[$T$ߣUben,khvԧ"{u5j0+53>90&NAL~D,(5Uo\Un&u5vv4شܓd٧Tig 4*ٝlugo <{ԤaݥjɎb|6rӠ69')͔w\ScYGmkQ!ʰr|7 Դ dөuXJ*Jy&9Y߯KU7wr/P %*֨aYʫs? OEE+W5Je/Tq׹.S=FsN]{oBZuF){:U֎r&hj}mQuRu> *x~&-(jPe[; %5-Д.WEJݮ)*TD\G#.n{GyTyRNw!ʰr}7MѴB5$j}YT-6.mP B.7U9KbpKr IpENS(҅{J'jP)j͍nq ;܆~;0Xre+W$=q XTT]yBiJU9#Ȯw**- hS{7gʮVj[*[A]卑F޷ *b hJ+jVkZ7[|My;y ⩱Y6S;ՔzL|4W Mj(^*Zk$ZT!{zF,}W]-ՏxdvH6u:}AmZ+Z:aܾMF+,A6Qx m"4RעEڽө^]R: SӮz=Rݢ"OUTjM!umjPL_4$Yoυ3TYžRn!izD!j. /,VK&:*pVgJKkԹcv\ҦiB ڻN+_1=IWT{36*))QkFJvv]%]%~ΠըZE,sU\>it{u5j0.5.Ǝ͞u>f3j-RW@E|EQPU;UlZٕ2LFEq*yU'dJmT^qaB5(1F NEPj<,PZ԰KUUѤK_hJQZT=^bUTrcz%O+ݒnh7n-՗nK<ܨCuHa~?{&MUQ+B>ì#b:OGu+~]R]7ۉjݪ볚2Է•eª ~oG4#BU-?5;QR7zj.'S@jc*HSΨj#cJ6έoW ?8X!:͛7A'4ZhoNw{"Y.I]^{MV9\KSxܮFwh0񏴱9'F (Qe%RnTb/nD*Q{7%E!F'801" $cCIZaaJւYd%[%R')1^7;r8!?5Ԕ.Ug/JӘ[[%:| ]C-@Z8ruNby&á)St]wj;49+4oh׮ZMx'l˔4O6@MQg0[OŒmc) (x=D(i7ew]Sb$) lԐRnYRt/ܰ @iB|DR SQ/}-뉕a1&lZ`Ѳ r C#-Rie  xFB?h#MJ=+M޿d 5v.jjTڐr"lt N&SSTӊ}g5iB 1{gu4-7 *ekr}Y`A>5{]\oN}tvJps*fA* g}ʼɡv=wsӬZm_7rH@ n`ApҲw-^&wn0C6^L]s7ʮRt1ѮGB?ZZM]4:a1o2( ؇!۝}Ƽ?MZPTF֫A􈪋}C+ j}P UQՏx qG %U}o,\o3AxDSn 9Z7ji la[t()ZN:7{ :Qhf 4k>Nu F5QB>DP4AN]T\S#]u65_=: /F᪁X}69ToVeYriZ8?UY#y.Uq\bo{TjY,mWq3!:G}m WdJ7;G[1їbh*^iw/.Ҕ"o7n. $F{,{u_uuvL ͛G 梮ZM)jR:'4fY,YW^ye{N3kiժU1daicSy5=RQ 8@ .$g"'bT/HmD6-@@RnUQl̫YMk׮RCv7KN䈦bWC2mZ`@@@RD! U3  iՐ׌HHP5$E`YӦM _C @1  j flRtby !l;$$lV!  $@@)x IDATH xLHkL$Ħ'u8 HH-۴=Љ^:Knjҽ7}Rƭλp:_E>w}:zG?ܥ{gߨ =GyCj$NO_}}GRhe Vt>*:l / / հy6t=[t֭Ľѥ^w2ĢC,:d u_NE-@ڬظI hWo]ho4~[t}Tri_oZ|58Tr 5$ѩqcvvuǿzRx9g^?uSnisg H Y0L'ݧ{Nq\B~WNxo8{(8Q4EkOWб':qB胯>9?O>;~L?6lݮq'~Ufu>;~L?fz}c%~yPphHT ꟟mԤsWg!IrRǁC*)G0$$c n$-kpޛV|ϲ%:A*.(H) 3VZE!Bb-$H  a@'m]g^  6=== pPch c!]۟dZ=+\Q$\.{ΣNͨA aͳfvd=2})0  5Y}βQHCH;x( e$,+ k%"m-0MA; 7ч~FukU.|W#oql6PK$K@ĚgU~vUDr~ko7/a_  +9a~vuh7gtz>{~h+(8A!? q<p?I[Ft;B.MqMErY5b`>EԐ2f8m6گg1u.&5MʓFFJWIԐүSK3l!;kSkzkƏ/ɪ(7AԐ +*8,I- IxC-@9A@Ƃۧ<ϥ!?  }ߐj՛o'(9rc!1t.)4A4dĤI]r\*)) xȑM?$ަX'N$}z=>%f ^.Qϡ(l=wj?gzƙ~t(#m+!HYGG,V}lg|I^1# #9p@ }DuIU]LeyRG!l8jH JνUt_$=VڷkgZ/!Is\*v$$Ok떙yI$AeݺuI ۇ$9qwg$-d,{u_uuvQ`p^"[]ׇekH =  $@@H AlQ&5}>Vkm̋-UUm ~E#R;ҭٌt*ۙ &cʆ<, zMNgtˌBҸ;ŹEw;b{}Ғ[@}VMw4^uK[( H̦͇5yJ%mxQȠ`ܝtۮz D]4]Ljo&]s:qizqXO\UX&Y7Q_ݑԜ˷ݤڥ%Lk- 735*VWmJ i}AwP[}VMsUms&QUUgf;=u>kZ>}5U4F3է3}ۙzht֗G$l\ѴjVOIz)-zla}WjYΨ=^o6vڕ6r:{f_ڰAeKt36|X{o%^y۴kc KL>þ9LUyjP9<7ohG0zX3CNô4m.yv- OFU~. ɺ [?M^{S`wi7-/j PfeK.3[5ז*S-H`^f]`G}ګѸ;]z=6|\_۴W$MӜG߮!z/}P합eKnbϋs4SS^ ђˌڎi׻C='vrܝ._c/V $Ec!}:MmjZ-~¥o;GP`$ͶR?tsn7ZmL}S6^&CgvOzXKt&ۂwuq6s߫}a6j֛b``gF<$ K ՚߻lfHij-9ӟax&-_ t*\~v}% F$ɲw^5 Q]ggEU;Y5!Z,g#m,s*/KCXnӖNӮ" ;L_?zH;;A  @@$H hMp8(= G̛7O===qjժ$L1}~ݺu m/"`oMI|Xv]>z{{Utᅾf\'s +>>rDytAs9z_R&]ɓ'G?z 6L}$_>H;Li@2lPts__:~rYzuzwp8駟ְat ;vL.c8`Q~~~\f]@"IbK_ߏ]====zNZ_9"4ʹWސ4xʷɓ裏ju.oj ?$=!'>]~ri!Sй~ZiS8k{/X0 a3؟Dc0~[erLԐSez^n_+_5=7*.-'0)5QNY=lPcc}]:Kzt<_R|S:Л=AU&Zjhv2H$}:}Ү8cx1I;=FFCCO׉CƺΒ[Pk?,:!}l~T>铽?` 2bԐda@bv~~]԰Yo$k7kuc7/?.T8vZ0g FKL~{TY%}t4`KF[S=.= m.)?OGJ7I[8S*/8MA,e2G>ɕ:cy*o d\It?gQ&w˱ tR`lӮG'4ykW kEq}NRMݵZ)/*iq!ǘ.r0OO- g}m+7Im_C8(ABwmOAMerIk{mƖEW|1D͍O[Wdu I~A,ӿ sQ2Du&dK^~2QC/zzyU!ܯϞ+SM?rD4K ^VoAjZh4 ~0s.8(L*(M l^fJto{GDg`cm{$/XcRSm}bnO%i#MedZZyY,~q|߇yo>#ˮOc0~[er3X4otfrlL wt.jmgSzh ݩ#y垶|pI#2tJgI [co搬IyXYE0p< )ݻӎMAD-IU=i>rk?xyh }Lí??|?Q4~%{?gQ&7L>oն=4*#;xA-Ol)鲰Ͱh7:52̯[ySԸ\R&}=9+R5p< g˯`T91uD-RCӹwD= fK5 ;=2̵)˯is|ZnǏ=G_%_J;P[f}{}~>v[˧Ecm򫮤L!yU^֯0:0=/Sƒt/r =BS'WҕWɮcmj}$rW!b J4Kp x:nE1>C@=tԮ IM[%~WbEVZ8}6^?Gvkyu0?I.To>wz,{w?,~Zj~>]k#MzZoiƿPnWOR%Cu<|Tl|_u/t([okk5jA4T+\"sWLЭAͶv]T]3I}`~cz^wyf\>az'!zH8Fݨ v4ybPROoG?zLDFfYЉ$xLie\(~T6G >φe)*%;m^ԼI#|I=gu h>S{\=~?I.To>ONjW7h֜Fb2IDAT@Fuz[ҁ-jzkaV9+H|opׁx'/ u7Ae|2J汙>-??Էԭu]S\LۘVоJn!Aj̖&o<{ҧsO(>u +cƎ߭>c3~ҜYF<6.P%Ϗ.zZ[ F*iU0'B]Zcljdk0?Kwtm֝|:]~v>]usQ2͸yڏucFK\_4?[ռ{cJ"Ͻ]^I77/Bvl-j؟\~r' y:`h*Ҳ?}m嗤sSMK{HZnZ&Cݧ>sw1-3NkX{C_mY4C:?@*dolSVy?~]nOY^_tԩ=6L:ĺM˧-|˭]׾+7㣼b} \IefOG}GsJ7ܡ?xP/? Zj5js;G+<$l=fIO*tc %M *sRgn)qy2(}tIl.5_dMMUIma:GיU P ~gjlW_0Ϋ{^PNy{4yGb#&ƨG)4/.m>OJV7TI/lumHܙڶTT#ҋԎHIX*洒js0U1#607'͑ M527>!u#8r97{m 3,m&s+8L*u eێ1͋'Ss;L3m/#gD*W{B$&!P 4qwQnC2hiWuzq *M^!i^l*SC B ޔV2v/wѕ W*}&]SZ8KjxM*iN~x'13&I{Jz̸Qtnm'oo5M_~C_Bƭѷ)zg]o]iO9:nc2 3@ʶM>?(p -grd~2hn]h/ x:1ɾψP\rV{@?|GCm^ZIK4"Wr@n1Olweu@[3Mdxrz]ĉsWL wi顝{^FT$ Vf60*bkKگ'q4c[~IL5fKS<,S6 1\.΍%mDϺ.9~ORiaQ:=juG5o3_OͶuB]sLͰv<_0RWfل+pi]zxe-g@Ԑ:_cծ# L?|P/ |-M 7jNbI6MBu>_R ImOE4Q`_ ktL8UҁH1/scC}[1AInߙ`ě9FL3c'Y|ԭޚ|%5#e5kKjߥ5O5wԎD_,!J7/vXmT>JߨלĒVcO~п[kW5n"wCsYVUN!9wz^7\u/2orڨ._s1J?)?|7ʙ(\gW2$i|u|yJǓ}2QCbٻw熨㮳cJp84o޼e֭ӼyJ} Vap/EVIm##vʏ}:3yHr>:?4-|E?ʺ ō{NzL3ms۞VF)8=\_ݠ5^0&/ 't9M~>F7jY{N?DP2񏴱̙2 -I`g+Q^ %:lӮS&[{Z6UV&+yTMBZ/OKd˭2vioj4ii?M[>vi9[?K\/t˴s\f?i⽷&,2v_PǸE'#rL H/5viyu7o>3ިzbSm':CARw];:v{G,-_-&zg3~&hҶha" cHto;ƓϜ ttliuHZ~߁~8bw~hu _.Sy8.*-kH@pD{HEՁ7?L{Nv>CF?0h~mUc)塎pʹ߈v'ei+ѽr\s$.~#Q{~7U=:'U{j <ϴ'K =LCXӵKHѬ7G6rw !J7‘ }+ CTl.)ݪ(u_.Z:uśnhƖv #g_ׁ5RYP9]9O*;Mv7g?+ՏJC$D ^C>$c 7#Ufz'x\!guBV^n߬+5p^>گA>`į?\(nA,?XmaJ=Ӊ}(ۇ[oiIkj#xݺQڕ&٦Nrq vĜP#OJUq\CFJn2l5yTtloo*o|)e*6 *aGwV[32LWo! 7A]wOfyx}]玛?jcI|rpѡ6>䇝"-zpM/xpˣH{S:Qf2grn=]C!"p9Q~9OI#--=IGwHDsmIzoޣyȪaTGr(l=o%Ԏ$U&!Is1/o]מ' 05jAl4ZL}GsW)U^lL*5o%'UT7W%kTUwyjT)i1h#v6SExjmSU6չT~9O#ӞԶUFgr 6WFL)ek/ƚ`"́6C w^t>5pKgyf'^ mRÍj`tm S9YT>_#_Vfrv!9wډ7d~PU!][)P7h's@JK+<'FZnڏpiJ\)m(C =`U60]ΉrZ;;AWHn~׷D덡~S^#u_k&3Ѽ83OGkW;UUzyidޡ%C,:li  䶣]oAiH#LIҫ`?C"wJ7l_.%kj7t7@'"DhqRr,~v?ˣNSTzhZO5*[}Vt+2QCbٻw熨㮳cJp84o޼e֭ӼyJǡA]=$I4>$y|={'NS }Hd }HdL&jHdkݺu ;1 H IAIRHcd7jHd 5$2C @PC c!1ԐjHd 5$2C @PC c!1ԐjHd 5$2C @PC c!1ԐjHd 5$2C @PC c!1ԐjHd 5$2wMk&E:ۻ"tW'8' kA҅p!.B].!ЕuyRGzMlZ4ikm&3ϼ< H#!HH4 H#!HH4 H#!HH4 H#!HH4 H#!HH4 H#!HH4 H#!HH4 H#!HH4 H#!HH4 H#!HH4 H#!HH4 H#!HH4 H#!HH4 H#!HH4 H#!HH4 H#!HH4 H#!HH4 H#!HH4 H#!HH4 H#!HH4 H#!HH4 H#!HH4 H#!HH4 H#!HH4 H#!HH4ݤc?wn|{T,w/;jz/*\܈(\Ͼk5|,#k:~gZNUϻ9x4b4XOe9s*d+#^v%ba1w=f7wڍQc5fVS"zVS,WGsXl\)V޷;iJbgΗh,\8cMB^|ۃo+3{=c)b?Fk=t.:>s 9X_X#k=l~vN6Gouz~5V4$Cdzם?ӥRr4}c-h쾌\86Fb*Jl/߿ǝ Z;6۷^g#~{?hFDM9#E3Jv+w?>3ߐQkRoG=gZZ gO>4׉yԱ׼Z"&d/f]TŽ=ϟ7Z5jݨE)j7Gܰ\Mo{юǫ_#WCZlE;^_ |ƭkaZ7/}j pFHH߳Xyx__^vZ#6Ѽ[۝;{1}=^v9iU<q݋!cLlT<:4JqaS|{z?.Dl=FckL~](Ǜ'MC>u|絏cːpZ{13ߓ@+I:z>_4 IDmxcbKy6~?f}}xv4jǽ}d>s֨8N3z?==o&FxjpG[85z&Ʒ(sE5fvF= jJjh/Ϋ{kwHbj/Mʈc.:/RhZ]E.o߾EаX݊ ?K*HBp޽VΫo_ ѐ211 RHH@CzJ111Rk$+J G\ɈhǝWU0?˻JIENDB`refind-0.11.4/docs/refind/refind-background-snowy.png0000664000175000017500000132216612626644767023017 0ustar rodsmithrodsmithPNG  IHDR3 l pHYs  tIME 6;! IDATxڬY癖a=\.qVC>_n"w>߂@ Z&!"utNx.WkO?/ÿ,Z;<^\\,bիW^moo޾zj}}}>쬭󽽽ۛ˕s?fmmmcczeejkkkeeemmmuuׯ^zů^^^nmmܬłoӮ׷f6իKruuueeq{{{qq1N9;xbkkkmmmss_YY\]]cY ?&O 󐷷kkk5+~`mmrM=}:6oظsx)ޗ磮@~jggںb)9,Ê,Ŀ8|cczww㴺//,7lmm +l4Úp677g:G˲L&^`C9~Ɨ_~ypp*-7|/pWCٳ}WceŹM|/OΛ ݹ>|̤TO]aI{ |\v@M36K1am\='ZՎaM9Ѡkk P&g .Ⱦ$bSɚWw0;6Йq3vFڇ?&^諒dZ+x-p_Bc6X%S \Ĝ3C:Be]0\7})8^ ifYLj\O>-e45X~•MS24jsd-i5l5H2"z=]>tOxB yZ8$;F{a=<;%486%4k.X(֛bqp j.DB j /ؗObr/; B9 @y5LђPOڲn;ȓ4Zs = ߍ`x|uul Ɨv{uᮿ0&ee vX/v}}}qqfY Ѧөޜրsx#V[<#ïyn9s3~+;YЋzU^^~[r=F 69\$Uz֋`cjyŝa .XmS臘B۟40.,deNof|OЈ{bDbbVUYkݤ5,nWaj{Y-exAA:i 4㺘MԴ>a !60 ϸq~1TD|њEzAxӻ[&*/qu;>'7|l'n ˜bm>1+)?6Q4U6蕽1i-zeG5kHюFly] K|]YF1oj9D熃":X̻/~xHj ~slĐVK[v uPHK&SW~cXl(&Ԟ7n HX+|:8 o\__FC T2TI]d$ b,bU巶xgvpXA§q[ *K"B*t]/fD9uEF$$7K2]WpXMyOhg2/}LbOÔfB.`+#q.c;$JVKso첐31)bMkUhP/M^[ 6݃Z"7jն2Xm:>qRhkbM}첈 o+ì-҄^Zfq&̺rM+қDzta+';AM, 7q9Cɯfގc}vx )4<0)#L&o~lj 9O&NfS{iC)ԇ żJc6r!DdcJLqۂ ZlעBWje+4O:WKO8Y"cme4ڳAflwQ tf'ZtH -/vRrxe9xx1a._olk^%4&3i -~<+jѺCSv̏1oܦYt0/M/ʺR(;;;BR+ܒ㩶7:T/6ЭAkE.]b $bW (eUbݼMit.#c}Re |IK [yAݶMmuRIu8]6ܚ q[k[Ίf(nca.Z~%6 Ke}`S+9 L_]]a(ҵe"Ԋ.lڥA( d[0VK&Ҥ lDIq4S Nl@wA͋2rXxtha&J L ТPewmm {~~]hgBV>@[a^ %Kwʡ͊W)E>!ۦktaf՟.hPl" mgmSբmdrdeP8U}I⥍ZSâOhn ˍj%OcQ<ޭqwdF&qs8Ӭa26>cǀFV* ˩j_ Qɟ[M3].!}|j.ayԽT{* VTy.ʱQ-e!FۡAYieި:BMxܴE6Gmd7<=Drڷ m{{H6l[c?Gaōk7@\{*%7]PEv}35ƭ212*|Q^^0J9}$Bۢx`  3ZZl<~!JZ,6! /Ufu4ualo6\EEA92<_[fT?wc,1UvV"k ,V\ `U3b6],l: )K*XoVjB}壔 WO-`Rj߃&2楊Wrd-սԮM8!Š䐽[]cEA>OS+j7bPm=-n25-{(qkJ!K{ydwUŠR"DaTƪe.TrB>|k-SegID@f8%oJl&AQm>۩%e03 q QVك#mmwmkd>Du̒KidSz6r|M}ZChzmH1߭[0[:A3mhۑ4[[q-WWSZtSVRe0yRtm"tYNu-7Ϫji8A&*UJc=Cy{8\&7LFrU^/"),(‡Je/gMet<Fi $ ;;;Dop,6L"M &bb2YqU <IqMox񶊨@Bo{zt +$)fGOC7^oIkr[ 2d}鞟[oAa6۔h+m*щii q\EY;u~~9LD<]bQ&?K4SpXv`qM|R.X9@%t zUp8i_JN]z] P <|d'Y4QFGww+ah`%YKu &^.jK { ~KҴ́d?\"jI@D+n=L;h3]i~4a%7AW B6:~urzUqvlbLbTbX}0PU=[%zJhOԧI] P|P3pj>:n%wPZYe=Z!j!f2lp.M&yv=E+[6x)٦?P'hDUh~:GpAPnh)06T^5ۣ`B-QƳgsT@tGې6v¼Q {{<*{XӪYۤg6RKe$yD{,'u!MaɎk rS=.`I\NlCWC~ SdXʱESe3@.>WKj`&~:%3&*vBhUTd7 \v)Јi%qEڞm?]lQ56xqxx}wS)t{GEj6ѯuJk3S6ېq,V"aJ'[&1:ūdTRڰLb|~RLF:ۦv5ެ|x =Q\ mNOR~%z&.QKBJ@qM0!q8K[1dKװ^1\#T䡒n+ ѭ@%ݵqrچCKC$ڷ<&F;倕d}Ly5%5 7&p_ւLT"X|΀d2Y_FU6wz۰(ۣ`ёURlhGpPaVk G:Mel!ʤ)q\/Ujep"/ (c Dtu5aHX#M~s6_J ۜvr,59!Nj}tC(PsC_D5iP@eƯُU`G 6@AoCJ C1'\)O@)ɷO2v[Ҍf9up.E^W/l7d|"7\&-T4L( >©fh XvVb%klݦ=ZmleM΂dpy}L IDATqsʊ\2{knN%˭=8F-HMR>0z֊i.:L:8ca+)eyyX$vTٙG S{O:IS9FPZF`km.h)L1eVK\!Km%[K:ߒ֪ScT28Li[FG7Zj$VI+NfG/wxxO84ct[+:6o ɻa,[drV#q~-ܡ~n\vQT:u(Ҷ2ӕazaCunE,KuDG:杭^2S'y)O2hLA T<σh_awq%V~We}2['4uLACզIc[;꫽CGuL&v':Q hN%X,th/YerdLDKw'e]u^0ksRb@y\(dJOi:Xݣ"}māP zfskeDK2  ZϮQGpu>0Pdp݉b;~iXfB53TgXh*Ŭ t n /"|WM<~eY*(zaiIENF92['IٻyLbn/F -mN;նX=Ϋֳa*VS#>Pjъ;*PfvU:BCΎXS;:P8UO 4;r|{h6πX  bơ'l6k[` ["5+ jf9h6So:=B'mVGŘ21pf:AGqyNv51 dK\yT_.Bsxt6ͨhPUk. F?жl307jvX'h.m@X8v_]qjّVKylYxfVPs+9 ɳkfăs%tMz5"ڴ0mC7V:;]ͬACvڰ6y_i Py>@`[dy`g,B@P=0inPO5&^OKKmI?o}[v CmUFtr!B5mW=)}0eU[͜fC@ʪo#UGZA`8ivY{,X];Xbdw0Cl)¯U1%;xMJ#`Pw0+^Q+%U+[13%ekRn([J}^нc7ѶJϫ^9byPG[Uaj z˪smf5߶,G?$xP:SUu^{gP֮c)/ULdC`o8N6+w}v^΃ 0p1Ÿr_*jOZJvvt9ڰFz~IB2(Vf^n2WZZ]E@G  6gۉFuFP1B-g9^%V Y-v~Sޑ5oR55n zTeu>|<]U c{*:Raښ(smK1Q:>FQr+ocGg+"|<=b_!LWɵΑ*pǁB`HK*6e|[ Od[}$1cDr1dXCkwvCHiw&T$F*UJb0g6&+%nPh٭H<Ŵ7_fR3V6oASL@mv947)W3Xtf=Lʒ1ڃ]Yo̓e_rj81meeAG:k.h5RH62լGȈjioz]۹}0MQL c٥7#ӏv`r![HmɌŬ?T]b(QU*8ZE"s6Yo*~#gPq/X⅑A5mU{9'S([{{rtabx-Iqw e0iϟN}VUoei`15LUńk4:T @u4@)ϴ&S3;mtsjVVdY, *'KqTGʖ" PGs뎕/]Krj'}A[Ӂ n[D{'M51+lv 4Ub_^J5좙];R]P *hju' 㶏`u LCԂ@x_]]M&sCU%VK[woŤ=UOfZ[eْT;OP븀f Cc^n59+V@\z mVQ+CM 8W[wl,<̽u%|>۫ -P0Xo?WWWU,|(,Q)Z~CUyKpKep__6+\&6TWףJ[ 'mN+Ru2뵶gq/w;Lڐ0#^0M<>c0777nzj( t 0,5FTS 1m *Q]pt'9AGw;Z0.8oll0~J3on3O5f Ag%KEK1I-(B(*~_:FT4bG"*#T#%Іs]ƴh.:;pmǡ3u+B"СЩ6]/ƪW^X.K2ɶ4uIp.q*%`R]l>9`m`QLc]Mj .mZ;(Ƕ:o D_N>v}OPBO<]R`oZ *mжR7bcgZ:!F,*G١+DZfJG@FkGű2D*euHH_aR< C'oNRPhGcwtpe|AZϝo?8/_~''':ȓF;$΋vךEwQ_lc3NETldAX^Ri-f"DD[Cu&+HX]uW"IWps(ۉ"mF["xT$ oL +e  E%qzKKM&jXenyK$Jnӛ%K-gt1F)aoAl)_'y*f bu/CSD\}5^Wh,ӃOO];xJ6v_Jv mU[wd)j2/حOͅrrr炖ױc|_ K ^O@c3>ʲfQ&I%t*(eKjkk'q=c9LXڄ{[.f:H%jRkX]D**c@ӳ; a 3 QkC7E4HGZ#<' RUM%MlWs |ɤ_f˗ѣG%ۊ.dHX-z*tꞇ QU+]LypTRVtXu4eM}h<Qz`ȍĝVQ ;6+ʢyx;' ړzPիekک0 Kv9axN͈E[<% a{?}b<;;;===99Adoo \Ne RhGɄ6:Mw"-0ġ^^ݻϳb57\Dd$otL&swoSҜU=&FX*6 dS  }"vvq*"s֥H;0r=!Te߬A^ [ u*i;Ad P7iM2Au+(R-ޮ!)DژcLTe|\$0fY__?>>s|>2wE)f5oK]g'o_jZ+t`8nV LpK[ܽqr3LmdIg7DŇd GdzV9Rm{,!GzUMmfBVwA(RJgp zX KrTJɕV_WRMq[YVշ̏+,iUAn %T2rGzt:Uv'֑[-Toh{a [ Wh&K_Sa3H&߈x,YFxzsss6 mycM>ԉf*8FO |LƗ'`]5F&Gu,nZ{(FvDo Ѷ4aՓOr7Ae9vtXO̐kX&=Ý^ݰbմД-ʑ7*3É]P%NCVmВ$+I*szzzuuj666޽f}k?O;%=3gtA}UJ;ݷrZ!vb+O"dH/P+0@Y@BM?Do>rooϜȯSDI0///_x|KagqnkZ/>(񛃉W6uj=^ov}qU,;Jd%OZS6:m_-ϯҩ,*dۙS0m TB#-)TlVZIsA{(U]Cg; @Xɠ= q3;EABv&՛(y B>XR!6LzlnCZ,P[Z,hs#rL5\ -lՑoI&ł 9K'jˆ п MEYH z,4t}&V]MZy!O^(~_[V иN?pwRT%p:x|&-U ,% 0f>zH7|}a˥7$3A]9 -m-pwV0*wH8N,v3ԉYZYvgTwu- ᵻT< uNDb!;U\`;9m P3r+5/G` -2eЀvYo;VVV~>KU] Gɔn[A^6p vwwT`M5DfHb^! J LAKŤxt`1R lPe{J2!h1`I==\ +滭W&طF2s$ q%5ŷHꄎR8e3'5߭o ˉ.Ljf3C^M64L!B"u*fۇ͋/꫏?}zzG=~k:׿oxPHULsjWIln t׭=><::b=?ݻw|~駟[oegb6Kr;` ' 2Ppa^*⠘r=b6}?<<|qPh4DY!:/]8stģy<*R*PhLu:]J%̆BU4 '@' +Iz eq:sB2Ht@76%SY9F8:==%Ai3yه~|ݻ>?>)ly(6k&`S|{j]󍍍;wׅ?tzuuuok~G}Ds;ܲ#n򃃃g{{{]*۔{Zdmk:þٟKla˅\ _/ZMVDk,tЩP~ZZO`[XuKwQE`Q`n⚷Ttce> '@*:"N-swww pJ`HNh6tч?wXD<^2)90o4*/؀W eVEkku5JkUTذ=&gW'{& 2:|臚"׵1)9ŋvPR<OMNV¢%* h8\y22q/JL]F 4G!%"-xUDՉATHb\"7y?)$+VT-WQ)gR!2C4I:m<-tvv_ƏfG_[[{oɓ'OܻwΝ;wy/-s6O~rsss&\,HaBZnnnܹsWj9<<$3;::>p{{.FVztt4zpwo:\L_yUvJB׈ㅇ,&ӣ~wwwΝ;iqR*hEvW-JZoJIOx`:v ST# %QPj2ӘeiJ majQeK=FW8Fws#S9e:K< ċ%9Uݯ͔!%j9tvP+6t*ֲqy t,A,FAk Pf!ĢGJޡ<O8Mƺf[4ʃl*ڣedNqe3@falfq}N*аjJ\h>}?,9bI֋ };v(vY1QA1q09Љ`Y:RQx'Xֳ"Nãݠt:e%>o|ÇPɾsӧO|'Ӧ?;;;/^%ʺS& _a!6eٖNǬ@aQ7C;S/unU0KIS> ILL΍Q KKi] ֆg&fv(r( *IR`jnTN)r~V:5 9A|IM;w|22/>Ͱ6ړ~Q$lנyy6LBT2~U"6خ0q'j{QtmU+8f{5_[ RYΠzst]֡!r&:Ny1q 2_JbW '$W K=Gz =;cccl2t]|{R&?_-U6@IݨvAm3 3ix9n8k^bVe"@e,oۻo֣GU1N< Zmmkz^b!kaX_cSvvv=m1կo k_~ _ţGJaʔ £j6$0E ,mSV2v)}|vﳳ3 Ai0!$yhŒ3}֝[Y< ,4Ӟ9"˭hgFjyC濺A8<o-KO~뷞 8}֓z\+KU y5/.1;nk0B7 l3sJƄ(S5GjMŬM3%+LtP# >xU$&d}ف3$0Bv6 j7sꂈV}qe$vI56Jk-[PlUUẍ́=Ƭqflu*o7A￶YPi,!X+qa֒aWMC~7yY4 biTYf llBIYإ pf*d10ggg1A`Lr'|jV˓;|oop`ȕ&!ZiI+6bC.-fzP*VϾK+qsd.{Ћ%)Z9 9*`+52amT9y,<k@2N(*I[‘pҩ,I/7m{X#!cԦrmX:CN#$=kC(_9)WC`RNj:o18<Ho$dN8v7xu/777T^K?΃߿ITFyܻw#E.H0-q<^xrĴ_/x]BjE |yn9/eth$̜-Y |hvF(iaL<=ml+@"龭C=EѧuY%D{* ͺ-vWڱ%IlZ(5VHũl6{rӟ//yGQ!0-pw-ףG>/Ue"wss'mll~{{S| >ٟ{pB22s>wwwI=aB|?|wwwܑE.P1߷jlooȂ{{{lS Kw@ス=M23`kQp{{{rrAݻ˱ 9z2~/M1TI`p>ĭA(v$Z{h^R- -^pl]68뫯>umۑ2nh%3'l]m[=Ga7'X1Z;ub#@JzTJQ8#Ų+e3䄏r2omj留k*}nWqm9R8f1OcB;-8kkkG?rE u*S/i%doyt@Bǽ|0ٔz0#7KI3K{qt]kvu/g!madbJ:,ֲpTwH=*EyRv]7l:e! j,,i܃SƒقΗ?;eSlV!1"dJ<7S(:|7/}__2Kr2w~9@1l_| # eo꒣6Vf}}7x7"{{{ݻw=BCܹsttdol׆|_QslX;w8>>xwrrze|O?}b_ؔ#619Lݻ|*?@8JUjCV'#T&+ dlMgfX*0 ݈P{*Zdٱp7qT8:0q M޽Ws$EOrmpG5 GixtƋł#}4z~nM[١Q_-`AlɐBd/;ý]k+ ssR 3 ޴"miWELt\˗/m8[ @2h*?SbbssPc87H ugEt9Vv;OJhДY5!dbG裟g\ss}?~ΝrNb :Kw "k5aTjvzzJ$a~JюդseOr1% mˀyfܴ,Z$¸ lh ׈Jˆ"$YS۳Wc TI\##a\x) *k 0VYa z-;O~{{'= IDAT7>24~F􎏏C_k F54t:}7X.=~O?$0Ǐkٟ?[oH&-*mEX:Mj=]8s=d)plsJd̲#S:A狨M@Zޅ&:)P-'V%3H,xH $(B0O%jK0$V؉Ie.^_ 꼫RWkyVfҹN,VVV6,n)+Uf & *_y2h[,SEdC8QlhoU†#O!ub_#E0Z۶h Yc;DAݺu;(5DIR8Z6.VCH)%9TDhpu{)M [hQnu )`ƊV+2Z3|ԕprjy;+v:Z$oR,([,c:GNyGylZp$uпr rrg|oѣGb\UHl >SbBH㳈dXi$,[+R&@#dDuuu6~F1(]Nǰ}FF6UW]G},Y9/"BZX;QPaxLآ#v֔n۽&U 89H;ˎجEh,!ARZۺ:')8Rht+\dͺ+KTf쾗WHlޫqX;˄]z:&PgݖxQVM6q*ݻ}M9 ):JB;]o/$Q'Vֺ_ &?P3?<~e^Ç'W,~9BHbNiAqvX<-|I \Xۺ-B-ֶJ3yD^ W KUїVo#뼟r<ԹBĉ*i|C(f9`Ǭ _!̖ B0!z_-yʸD>vqT#?}Ug+Whqq* r5{"dVfZ-z(쒦.fS=:VT()ea ҆fW]Ys*Dx.b\/EܵG%7{?~% ww-qB 8<-LS͗/_PL V:PPU9S-S:/a5JR2"wrˆxT'/:B8@Aŋu)!8YQv'kTa+ivYU[:\:7@6a7 ZpD:l*A,őSQ>l[,0B4Yk"2j_2 rO'|ZC{r0a߅,E“`=H&tl"9KVs1U"F7mB|֓-qG:J1j L*g ձ;3?d>C/-YbAxdB;k~3mp6=իWg^f=}tkk j $|~m?[keb?~mx? {{{?->ZI|^mN%.RȲԉTç:#ӂ8 ,%Q E8o˩ ދiY󖱌؇%و5EkL ="坪̇)$*eVys%GTU#qrJʴ*+ eDs'yVY;F¤lKuwb[gr\;ŝe ...6G5}P &i5ܦLa 0 CXh6츎2B*NEq'@qiDRWd_(ΐr6uw*qtī`D,:E%\a"gt!iU5N{H QVGNOn26Rc>p'c2Jiө_\\V MkJRVh2)Hj8yg,ktJo|wݻw.G4Hp?X,oǏ;.N}ѣGNT/'L&|kg ɟl6;>>fRUvbqb#څ\ZF~ss oo;ڰfk|"\^^&^cϬ[o3p`<'c&q1o4-麼P'13uU+D ^!i. UU~x?('ڰҁd& s䍵JgzZF pm}d^-xw8ڸA: =ǩxu[WMTÇ8l,*R::~:  Am0 |gMH VJ%!x!J_#_3NF3בv] 0Av޽ oyW_}%3;y뭷^@ٳg|S'8LZ«>\\\ Cҕv1|xjpֶ&|mGȂ83 )8!|0?IcH *C+9)%_7b(gCsIwRA˄Y,ɤLتmm^'ɻ*Aʫ11t:C,/J$Ist`ŪҫTW1ꡕ;m>E ٘[:=/hw)/,De e9Zj[6Lё-|4ydq˄8U2AX %ԋWЪbʜ'GZ%b+^^ 7'Gmif N$m$uZܨl8$$OiD|&('Gl=-iy_;iV {tw.gggbvk:K7)[-7zO>L&*؅%eܵk}ph)`q ^ᕉ)[X@WU]w0N{Mxk@ef۝КيW  I 7nj)ff݇rVE {VD$vҩI` Tk!yQn1lbe j߿jc9JJ-3`rv^ٌ>nlK6e`Pbs[eC8jawv kd ݯzYk9* IŚcggQs vif`VVLI(尳U[-,@'Iyeal,"%) p(gT CRCrh g9vT)~KߩsT9tGFꫯ^\yϕ?7aZp @+SU:zU+ű}z}*#GzDF.1X. z̔ >2,=`QbKbFgCm[%R+ {(=t3LuL U?xlw;=%& @b[Ă=2@/`ǂUX"$iH:sݞ욫\v.N瓣o9/^Ds{=g!KJZnC|u%0 >h2cׅnb30cdr]TgGIN͑7)U7&]DZ$u|0gs^L Z3)l ߟđPR 'dضu ;Peow’Q(Yj7V^Ś|_0ӄiZ|sS2ͼϛN#9F}Ef̵Xa;BpS>zk/ kxce# iTT FTagoo/5Te[!ZC-NJL6Ԋe`0E= 1K0ř(W?88 0cܽ@($DtSwcD9iClۻV910#Q'^|kvE~e}}=;o-ُc;;델HtAl?Kvblك9Qvvv̳YT|{U@||Ȃ魴:6n,&]-K+/krr{8ԖKHإ*y}mCSp>f$m@AYNVbLl@+ stx-J`+=#(Ԓ3mڢo356667mȔ0G/aRLi4Oltn)g]Kgxu[XC9(<2%HI> 23\jmK:hF!p0BG_vV6 c y/(ƪT[Yf5e>9 ij C_j5ˉ0C3mD06'ܴm0I*\0Sî:=iVINF l[{΍v鰄nrS.Aɓf۷oooo ZZM92nS?:0oNI/(;zggtkmU@^-6 Hi>`kCst܎fEE8>ToccKT>8ܭ[U[t'7 hlbb6U'z_X*ëfG0dvB`] ozHĴv{W"5>>>>;; GCHߤ/ؙ0':KJnХCuv9P,-uh` 0hh߹sgww7ϓQEW.PXL=,yP|%jM**P|@kW,U|V}%8x* J 8ӣ2MְyTf#q9)lkن6_Dv SO7>)plllkkEv5n=i`}B?k{,'[^]+o^@D{th)jFG8YkСNO6I6Pfg/c#W\y yǏ///AFB U q?qk\cۋDMr=h#i~.DLKeef%=7n#Ύ?{{kkkt /0k2 wĉMzZUB 6?@Ǩ-C :jtmp7|ݻw#˖ׁAWH֖|y=A@ez$ z5-J+01"VO^[O'4Zw#?0P[?mt YrdGÿd&&籯Ǭmss3b M4BЋc3.XCA=wxxrb_tEdrzmU'EiP,sHsv\}!}_i(-#كc,/I39|dÉy )TF,) x.vwwxfU SWR҉-6<2>7[+1ZNJ2fj" 5\ܠ;sR4dhI&^Ne;ngggIgvBfZrYÓ7o\[[[\\<|#FVf27EZ`,ږR(ƭخSƙ.GL#UʛI3NS`C%& '%fnwtlZ{͵N4Pr)xiQR# q|iilPZj_u4CwWmf$?%b;NnZږTt4|M0YM t-yV CU|`eSA266w3QvCU[FFF}{nww߿zFtIfrkk+O~COxYOUn_S)7{{-gPypn)xR(4FRJ%9Y^3xY8,LT~<)+inwau{QC=ؼл~zNa%A{q4흾pOptfe3Ν'?qڵ! dmmmnncvwwo\pa~~>Y-؉oVѳ?2BX9s:mܑGΎF}C5S\&ăݥ'NuSgr\?<<|~Oڸ>HS>Ny+o=ouXBD3Ew+r˖̴XB$'BJ6o˳i4Er537Hd*ljs|:7:"1.6sf9g L)97ӌ^ qk /ei5h֪wUy>Ʊz0رcW^=<<nǚ-PLD|X; SG=zw=gнtH71<2P &gsIidQ7B;jFZ{e0dkkF#1FO-!*>3ˌd:%{aM 4rl0v֞/--ZJ$x җ<>h{4I[;g??ONN.//OOOOOOLiK.}+_]\\ϩ|V׾0...g߃J)]uu}k|><99YƼۿBld"w充h&MY___{=LǏ/--={6P /9SI z`fU\Ox :34gP+e:c0!a\(جJ(Gwh"FPH ¨\r%b8>>ޢ\z58h1[G-..={vjj*C›+++d¹stbHΕhׯ_qF'NX\\<|2rͼ+W8qٳΝD*,E%(d$XgϞOP[[[n^__ ` fOMMϟ?>#ezRz]=ؘyp,Zn{ k=vC>K,%,BM HR/ID*!Lpk=Ω[:=J=ǐ8&r Ğ"G.[&L̿$tܜYՉ?eWβRȩDv-{h&(< J P+`rOrkdrxQ=8lha/7&碪ꕬuP|nnV``y:ѣNQÛT|-0]Qw6{SiLߓ|Nc*RUϜ ۺ 'v/ ӨGC-qt [{-jAΜ-gXWH 6 ll|"kkk=C]^y啧~:4mgUy-//ollc d"}||=?s677#rə$1iYc'.8??)'xDv}}}ggGM//Z)] o͊N>wMP{MMMMMMMLLhĽ/X*c@f*8}H+5InB+/y;'Y]{& M1~ gNԢ$Ј&I˲\=UdD\喳gK[aKZJiF[g˨'r&R|qr9iu$4ugG"E0O&o}[ŋy䑸 :=lw:D $TP @QI0˕=_EH!azpv-bTɺYؓY8C{mP^m`ٲ'fh"@@x5ڙ([.PRW/eНnooΚ$ݙ61* ^(HiS4 i,F8~*u[&B؈k'`6 ,R 1SdnzpJN[Wܹ\07>66rT²_LT9sfss3 ._̚ͱ=s _ UafYx?͓9(2N(.:ƅطlG?k"IrLbA-dc$59Fц͔3(D[)iyOaz7u=ȅ5ɖmr37'tjSsNG4mMx3I)nĎBJzdx)q5i~i y聺lkgWKVpz='v)0&UOaje ztr6xJMDuzQӄ?AՎu$>>33鹹n6͐ϙ;QgF [Z\U{9+N6bCZ4<,@u6k= ܍ќV&Xs%)"H|4Dp OdqM4>{R<[|Xm6 6?]eUu76P^څM?aX5gÀL0|29RCX#AДma$l13GMlUe꥕=qOŧ[2.Hjcv -gQv1O!g?d%xsRKJ,  u]ns{ۖ= O&AH e3-9>ET. YK`<^ &#Z]vWk c{t= ̔<5:iMw\#1,B`7=P#+?ը8dL؈|/‚,qﯬLNN8 gf1ZohUWs"֧y>,NWϢJ~Il@Yr90r,2/ҿz|, ;HEhP-kȕAI0"hQGmI2=w#"% 019g# (")ⵑu A Qڹ%$9OcP][>6䈂u:D|WG"!)4['ZB[+Εv.>XK&*<᣹c5HQ'bZ@rNϖ@|ߘdN/_z*X-1YWМ<,=Eyzz;ftB芳 _?՜ӱ@~JY?z~2qm_F@B#w==N XQ`Nhx: +D;cKzCOO/qNJ6Ak:GwIcXxĉZvwwWVV~ꫡ޼yҥKow~pfՓ]^^~뭷"ҽ5 i=GwpֶmZrHRv|st4A՛:zRP{/iZqR$ﴶ:v IDAT>ۮAwOuLR5ukXPf8,eK|yzd_m}hi>驥VQB qK) a_^F̌܂9x \˕x5U֛M#Jin8cI$/SU9Y`MQ]'+N&ΑVdo7J*Icf{HӇkgD!{MZTq0199G Z\#nh wdAjͧkI#O>цT0|͙|c9Z$(j>Ɍ6#jbD1Z5MPV3 A݌uI-k+r{Zf7gd\m;7=P慪1ÌБ>;]k/۰ww{(C*jq&/RT5{\dZ5#sץA<鶖jqz/ά^ޟQ05ΥTpXSy&vüL;ڇyr_{ 햪J֌VI&c9[{&ϻ,0DH)n]V'ġ9Um>V@p0z$,lo !zkW]gZ;y=ܩw-hzl˫fd4n0Z'- `52)n6w0VABC@՞xRiy>3ɖB=Mg o&؃ (P[ j ZzyDZL~1CLDdiiijj`}}ܹsG;PSSS[[[PiX SZs)ciZu?Ժ%|^RѶR)༑U\r J SGWS~OGdy ej"hB {!9`8'2Zmj4}LeWz}W:w-|0BcI.=]|5K=$FXڥ NDZ- _c΃ok+t^JN- ?`ʈ :ߍѣzC0&pؒ#=Ow`|^vD"[fh@|!'ay[ttԪ Ji>,[ڊS`J!5xF$_4AX9+X]Ԗ..ɡWM4]&K+;@mq XrB5]!4WsTO6\׷~;)H pQ ,L,E_~hQEzR\2݁VܹsssF}?1[{g IJAɃF]mwgDiR-&0?iT PUm $,3!SZ]Ne5cp|O^f[ieƢ;5Y#i`CI\qRGF`a8p\I?9$@*:xHkY"kHB 9 ]΋|_Ѳ׫a p1PZ6fKe{9%)b$ v><<ޞ5R /|cG.R `\ٷFc4WBŰ8m@(y߱W~kSyj2T{5>b_Ҩ(hSg#X2^t@2p7oIJ!;U`jA \(Iì@pX xa(u"+5鍙|Vz|Lǎ;K/dVhN;wfgg߿K/ݸqcvv޻-l-T8x^__Ϥ+W\,Xf ;W_>l"^{|c.lwwwcc@@C⧸]ļ;wg}fs9-QQ(?n&OS&!aܻw/Y [[[&v{mIjHmf4$b@oe`ip`嬵"$K62AXk>4uQ`=&%Ukr`mmmMLL`@V $CtGѝv0Ln?=Wл,DccDcM^tmx|RR'Rav7!@Z>7ݕȨ",jQ'ɖalIΊ >D&hs28G;f (gSv2q @Ņ,d<_o-Ԟmcִxh F LL+]$[Q&֘ .6& 'T>5,8'7þSk2U̸8]$ݺ~'fiIsn(`eV[(hdɡr͛7%֝Ͽۑʵ v\ǟ}O}SNڵHD"en;VWW3@tss3A.,,8>{'xTk#6VR۷oaM(}ooo'Hmwwwkk+^Wo$Wǎ؈p ҽMNeLrqyvVQHkkkӳJRY,驩8. ʲ`NvAnu"U}T&[IO{M#UTMY='.Q&2J _vFFEis&L.E8y6wM|kI$:LV˖bՠ8[\Xn!1 nhՂmޅQNzasI[Kj± N;z2;=[2W)ea9* _DţZӵۃE`ZtA~У.CO^ Ѡz’":e zyN+#Br4ؗfkBQ{yY q`$%X;W͠(ShGtCR[h`iNNN޼y3^7R}ppr_|qww駟> Ƹ^~=1ի?xCy7[ō.\}W7oMOO߸qc}}}aaᩧ m(29 ccc/c.^믿~ܹ'|2xXXX8<<|W3x㍉z]>hɉhǏϟ&&&&&&/]cavvvjj*w}7IRg؎7z+ozQiښtmd^V^M5r7Pm8k 50[zD20t`  ov F'kG^3;g||<@WI~|B.TjcIR;P^QTFZH$6QTƆ鱡w3w 㝯N-3TM},P&-3j dVRpQ[[[23m=zpKZ W f£ ස!3C i0:=ƘmN4jpT,/kbb"L5A(ni\OG =6BjZ%W=$]k%<^̉(lS xuOZvOXD:'IRi]|שScb\y5΢^YYqQ`ŋ;;;G0 j 1s~W\9y/--=Ǐ^zѥ'NDo{{vߞys}k=Xرc׮]{FFFy䑩|####_W677yxxW^U?'Nv7Ǐ///Ӫi,-hMnlloxnA?|WYI8T Ő \.lO'ax,Xޠ1,%&٭HxJ T D8g19` 4=,Z7Id&Y6Q̜/*y9L~KLųz?[Ȟ)4q3+|ss3vL =B6O(=_}lk%BCX:9{Q4{vK`Zm )$|:> V)ch 22b<,ػwNMMџ!B%]9nA/uQ`_O/р#yDͧ,i֡E 1([u ?1ۯ7 gCSSSkkk9)y0\ /[o=ssskkk[o:uGٹ|G?ё/oƫ ;wvvv>ݕ+W~o~=|ׯ_\ɓ'_z/+++?яK.]|߿/}wy'''666|{|c}CwySԃ/;Kv(D>%ՓGpdpxP Z4,N녒 0n[ Y0x;Q`Z&m yMQ+J{C*OO9 ϐӛ"t0K?j39DmS`n&zk]t AsssȧGI ̭$f A0&ZkD6KUm .cND###ar }XB$@BC+I,i>3aU,,zQ:5Dt^fe1ʱJV& P]Iܴ̚d vzGhGv/,C&M6_^nQ f`}uěɡnEj%Hmj47`F='O<{{qχ\3ό\|9:66g|M!ycnܸ-ʕ+jH2,--{֭st֭񭭭/^;}'?ɼ۷oonnӖW~%}}}=W^wsҥ}{6ꖖvD'wkݿ7x뭷S;.,,ˌqԩ}.VLs8=ږQrs$%ڤ[퓚!O=.'$A]MKtf8Mɵד =w&a&&N-ZHɓ''''wZrd4/Z(&9j@bSzJVWWQ}M@_O1"b.=9I!vسiްlռ֠n?tԶ33)*677^daa7~7p?#yTX)=/]455e>رcZSSSo߾oob5{8/oo|Sz皀[[yIGݻh\\\k=s̷}c,fff8Ѕ//qww_'?Ĩ,@2'9^g$ ^ 9q[JQ%x ٲs%Uc'1a1Zxԉ{Vz2 T5!<*1a; `C*=jKkzf IDAT&&&R%_iCֿizH3E8RZ<xbYQ+ȣJYtxG}j\tkq&V7&J?GLHKʶkh+b:@rڣtfF P3$#d,Nf{H/fҡﵐJ΁-7ǤZ)& fӚ;8!5@tBUzLZ/o m.Gak_*iP{ZXi,Qck*,5@(uvAF5xn-Yi27oބ ,,,lnn:c%֜9sfzz: o׿Pe>^.5-9888wٳgO<o9s{[XXsS꿰dϟ?[o}R$dq>Qm. '<݋KCiGc¤G഼[H>!' ܔ<8ŶKlmkD{ YL3(r@7_W>11'=lmZ{Á(Bj+$#mҠ`B$m#?aL(A$ 1αt+zH~"T)UhxL=ߦ_􊉐N0"433CYQnGnr;ӧRɗt6{c U+GG8V-TclR)L~=5JN5%=ƪ{$ ڨNb1D-z,MT[ˣ >$ʔPm!)$k2 )@T wMBY!=;;kkDvrJ@kdND*Li5m"I%*2VĕiYCw^@J6cNz1Ht_"cOp ~g_gNV-M$y/'V.k)-"ye4K'.Q)4&8IpB֭[O.jG8JT D ;7*9Cwn}"K H:Y}ӄz:B@ګy0V*.:rZ Wƹ 8ф!hn*MIqh< 4"9x o7(bzXhr@#op[=_&(LLVBv0"\$aYf9_e&]1&ն/w5/ڀn)S@'a^]]=88r׻_O>}ň:K~O>P %iz(L)UI)5U#|Kk%Z+m"ײTYO>&7ӧOG&je6Տ4;>0"En<+Ga.'sA| $I]za7-FKx Ea!=99[n@@n$דL4 DV(%Bk2*);93r xݤhNuɻcZkmkͣ:e米^RNw/`rw=2RZ<|~Lڷ~G4}0tբ"c:8UݷxbxU*|Im:a}vx39ZZvd&UmMwo3Q'J3 9N1 <y%X&{8[RЄV{f4L5ln~g=B<.m#bXSSЧ;c8!I ӄAnlITKG 4m1W9HTOۧJWus#HjTvw *`2,Wݑ O@+_䋨x>Vl&OtT72&{fr}v|cE |RfDrX<,&rj&[ieGEkϚPQ7 U!8Ƴb4Y>, ')ۚ:F5:h~IDvk!PKKPpǛΡĘ /FM':~`[;'#W1 $2A'. LkE<ׯWjܕ{,.@ׯO_Fu`D7d%euv L 26hIrwbQsR{Z<. eFzmsa`;i`7(]DЖl $l Y^0$)8c($Qb̯`@Ҥd۽r|QFB?ɉQBƮ+1Dv}D$ _Ҳo/:leV2CD=ۖƴ{ M)<̘nK#fwuw$!]C-l%X6X>;lrHfLɝm;[h0M5i]35gbfL,a>C7灄"yyw\g2RÜ+DJ ZzIJ% C= 2h y@f͝={vnnn~~]C췼/A͂'QYf- dYVJ+sg7KG@6H>H`f=ȑ"鉨$F4;Ʈ_-G!l^gFSy@~)l  $<Ƒ੮D-Y)WV.aPZKvfff_2l͔N/49kzc$P4i 貌SHt>FHUmt{C֦vcY+SAvS>Y B; Mgy8X;?,>iVGeoe>qAV!`$A4㵽vwws4v&xJb}`BkePi!g$ C,eض졵d3Gݓ_-0;94_f1Tȟ aX&&Pd{yߝRD{NT R,T`˔ek(ǶK[ՂigV{gqn),fpj諡8 Tz-V՛w!$Tc9iQ*ٙiXQS :LZLV  Hº1-Khұm*(1I0b1U_>VST- "$mNd ^F= w Zɪo3WLL K|g>~H2(͌oX\KR!١3q^i"LF0UB;a-Xj0kc>8DI*8$}b;:EFphIv?yd\؟mKj@?) sN(ram4@q܎ 6KRWlKF^gUovKVxvvv;~ P'^Վh B7#/x 1 ;qBQ#wRn%k>ỽ| IEa;E88u<1zvrVyo0hx-ʻ|t]zr7틆<] q{Z+0Z"Hң<8un f50}k~^/:Oi5 GHeTnGvh, rۍ6ߡ>/YT8!){vDVN1%i QKɏ5-ּm7|8]hV{Pd5c6p`l'id YSN~;ȧDW=/)vҁ X79a$[A/W cw'v Q=R8-/Ѳٜ[[ >4&4,=BPev}t&rꬨ E8uOEh?,-_VRI"Mq{?y4Zxnh}q=دr0c E)”>ܚ.™>_)Q/g_\hZީU[sVʕE|{HD|{'[v-Z 6B P6,], v)-.`NTVo\Q]a~Tc=w%Rh@0z;jgZ"zHFY4'坜:ȋhlQS`N\Ð18 p ; J=X5T&[g)zfίQM#Q'ɰ%:]I[eH6p?]kt?8:J9\sSKB-!'І*cKnHfWLNN2iw,. #pB#vqv A$Q7T)oѲ4r&Z^)R=NCɤy&@1DZ!_ÁP%4MZNyn5fRQ옡%-6k@=vX~=dgVl$MA#$Яӧߟ3&WVVfffzH!SjmqqA@.Μ9j2̟` 52 BV}[8й%)HYkZ7jXwX}Fm2@/wў )޽{qEhgp*`w*0mm^'YTg;X]Z5jEү1xRh1k5ҋpkgdmGRh¹Q5uT &LצBf΂=?x0LMMV%^~8 q\d< +d[,tۋX =J}KreϨ[.J6Wvm3Ԣ;'f!z.e !҈ZDvzd$!ާ{嘷߯[9-0l L\mњO G=8L.G?,3s/gb\V:iTIv ׹Ųfؒ6L]+9m6W>psԚa"JmKOB{򼛼dn l(F_'ugie{:km\[ 5T4j~FuWkj5!q)J^~@yIu @ad>9yqíOkWτK @LR`Ps&;!pYwkaܬe&׶?Լڹ sԹ?&Riu;챝HnΊ0ȣ,hWT'pfǁL yAMYV&w#L%^`dp I:1T ܫuc'4kNu'P@nu&ju_r^JЬ ( ;LyT>+-S-hB@M| J*f)PV̔ŒHlFGEdvJ3D`5{g]Mkl&bIӲIi{C++(J;v-n$s IDATwc6(K'᣼zFm+X+mМ@=HΨZjc,(H9a)ǀsÀ!+ >;8sp,oHQ)lɬ1W'.7AII@{@ HetPR^I}3oƛQٮOJټ?6]+Xw"wO`-=z](kjuvN;| -GElet{k`{Dǝ C+SsSѹJί@CtE`k}PvT> k'^]L{)b 0QLfGñ@ B iѶ\wv1Mz/O&Fs:AZ]X UwQU賿U'`R[Bcίf#6bOL5+aleSijtfju0ؓYsL(TkIAx[ClT K'!iZ^)ޒtt,mEloǃ s랦}تV,uP+}MIJ+k "]SX}֊nyʢ'`rRR88z% m^kV%KEz?xCm#~9́SHe$tfV:8qJxK4Y~PO1Bw/Ԓh&s2S4ZDnz86:R딫[oY@໚;j |ރ='';D$-m=$mq5ZYjʼn) To=U޸*`jQtN:Nk xA}nߝzA1 |6 j-ʁڷ J0de5Cl'ў 98ƒ'n;Z3I 3ibZWH;j? z;}`ɭԺ\=ETq 8O988?&h+ [zV.=EEYBGl aStAj2K۹u9۽hd^tKNWK18Eq6Uy܈L2Y^dm ֡o<ݨ!p~ P'ϝj28fn:c^yl 3@2]-Z70Go Ŕ7q_cjlA "p(ZO5/2pu\e)wN}/l00 ؠcY?yLJnK+0Af&zш:n˶>tɵT)[]mT J[-,vm].LQd%9Cbf_-rce]Z$dY.p74Ԭl> jFR۹1FseЫjlnL#Tۅ,'w!Nb-k=SY"x?nVN&R6FJȀL \aRɜ>$gxHՒ8Bݩio&vT NOOLU+;z5a,PmK=m Dɓ'3Poid1'\s9e9\s`/t—221:M-ZX 5 nA8n~_TN%J(Rbߪʻoj>4ո(vJ"דJ(yFO$[K5ie, dөWkfHG@R=XM}i`-Xp Y9L9u m2ӡCi@S7RG$+B۵gFQ{1mxٓ|Lqtͩ`W& W-"c3)rS4c ֌boo/ӡmI;ieEp]bwu6mz~3XZN ᯕ!Kg[DG+az&7KZd@ 1bQ###x?8ț14tn櫀D zs3 SCn|jK7ݻA ׃~ם/o(_Mڠt:'U%ZYuDC ]r0e;"h!;U 'ݚr6e]n{uG^i 'Qҏ΢ 4Ʋ#F/vRhm5_BsxC L7s|}ȚѠWɑCC[X3heu%ﺒ'i\;4ңՕϿGSkY935FHv+ȈX5xk fǎ4$%G@Ǣ%{MIVa&7Zd98 dM:܀ `9+_hk ZD{ymwC(@\;m@ ! . !5jS; xvֽ8#ZIDfUh&z9^$@}߻( /`=yVQ:]Hhꚡ [AP*}ѧyݑ ;s?0&(4q0AG4L&P!BJSaލUn54_Ҭ }EURg''iEFyL $70G/,AcJ9xL5W/{2HçKğfw)U2v*vwWЃL4kٛoU]߆}ԹTԎBL.%0ҁ]C#XTӨ+cAak[eri&믉MY4Ѕ\FbG}ȁw쟪T5U0eʣ,TGr$dh)"׬Aq5Ѷ Pôq{{`xH,_BY)"jOOi6Y%]ـ6O6m4lJy{/^_p Nxft;7/d~i7o+IKq+9j߉!ZxT[f:\DѯWijbk{}ž1ViH/̹r?ATJ\|6R @Q?ݯN )wr;L,#\+h)+z>b|NYMMt6F@z! @mݨ%+-W%ͯǼY\q W׎ήa@Av8^Gli˶"5l l:wG󛖯,fA*҂wZ6/f; 1 Bh뙜-W&ZjNJj"Qh-*4R.(f6(|Բa||ȋiBzA5 sUYbn>5EoCB&Рx LY{)@A\#6˖_r^6PalsFC\|" ʬHWw3Nʻ|ҍԔvivgꖈB5##x 큎;?lQZkCFJ;y懭@\sZZL걽67\:1:{ے, ZŋW=m#R:^&o6.痴&\sx=d6X҉t[0;KhD70W}힡W^){++zyhoT] $YZ?(bS#sFK(q" tvK# xLWp= 遶^[[ ;#.?QąawXNwu6%TDvEOU:kH׆޽_wD٧ߋhQyrr8kb>A" aa0s-UnkiwWvϚDU4^Pw, U2i HRN"K NԖt!æ~BNNʶ DLeHED`)͂r*wP$YV:75zG/ՍpN ;www=]]a8u4:|QU{S|:9֎1&(|8kVUJEp'1WZ3OU#;;vjLV"Sq9qtuLw_?.T嚠MB`Yu΢{ty'(MK!W]O?RrKިG\£*l'K8R6m_Iܼmrj;\FN6SZЄ> EMma *Zx,VRS[@k6vMg諏tA*`9iN[c_ݫW :GqxeZѠ6F{Th2SzX4۹ xwi\;hOՐ܇HBKF *0miCX$1hG IDAT)Z:B׸Ad㹼1Ր]eU扖]H:Q.y>Bd.ݞ4[XZiSdkn0Y!ٕÖ E3}U7dK(m[#18[-1H:?["ve;*ضe] $YDlPu=/oUnrSqz o? ]Bk^FǟLYry;܏եO]ytu͑c5zڍbJh^VIILS +]r2+]^AauaaT3Uerp@1҂fʜ\I hk U utBGg7VW(=- Ȣ>\aF-G0?v&xp\<~g/<= &کI?Ҏm핅NfyA >ўWB,m)2=RahGkUΊ7;sX&Y]JTA7\v<;QL"FG h>Vh@ؔX/Z X6P#254꘩Rx,lsZ$-dwh귡>L ({b>|sr5U-u)0s9;]h1 5.Эx?ÎiQsmWeKeR8WGQgxa*/ީIl J\}ogEI <c‹xmU* )8q|䲝ܝrb _ p(y\uV.6Ŧ}TW^Ã$^R/wC:Y~9:*`IN&V ̤چbS170 b#_9Hbph}-0Pko' j{gH8U^AWС|8N,hvfjlLU{\v[˽&(NJhS"s\ :r;65%;A)Nws=zRu zD8/ ӭ[$F +M`mùq5Pp{+Y~YȐtayNPs֎<b3%|<إtJ?Jf95SdeJT+)}$6(.io+2축bٗ]b|^Ʉpv`l;4*7rS>F^ $@ .M[h݂~lye&6\>sI qywd9^,goQkК'~" o/b%o)aS`{AFeh,[~6J/ְDr޼yJ8|%-l<avHˤ>>>n3/(,\ [;qMu4 m}*Q4qW#V.e_qI"Tͯ[b4J opXZwkux)Y"j%t Vdˀ۴\."$.'T`TP|\rNT$EhB®#֒RBe:i :8U{2s1{m ۓF{s:GՉM' mk>%JyȔ~eƄH>$PnX(W*X` rAG^icXV~wY^`2h`>*wWU߻^+",.aǾ6xѮ.M%]9F+:sT1 [Z?Vq9P?6v8f'QmJ%4ؾ^!ZwJ笨kH9uGr|ѕVdfOvJvmZ(NY@K}zcؓ3eIJfiN#  U _Y|fv>Ae#'F@<kK洤x8͉=3E P W\6^rNt)fU]ul%Ŋg;B-bf_ h;6t:酳V\G&޾}L+ECT85HJ,8)hQԮy.ڠ}=?֘}=I?^+qҠr@ ҵuZ; M֎CvsG;uV~R)[]ea;·ۉstcv+2N ,jine]LQ:w Hb,-9K/?ޗ 1:7[xK T^W\v:7'@6=颕߄p3r|{n`L n`uQGssW!48X04G@q}} %u??h_Jl^ǏsqRfJk)9 hB To߾_rKp^']4E iBU|a (buq141ɺh1{иJ9w:̾`|Ivg:D\@UL+ ZK /t"\Gծ֜n!->ޖO@$j ivx9/!j BTz>2v6{b҈8r9DB>$-A{Ԡ뀰tW}NNhؚt6Z>$lժKe&o G J8J(9PH@ͺowϧi euVπe!حb Wc(/ 5΄1v!PVF'(e99)yPR;Ef';[o }m`I(o@Y&$@LKl*fZIz!0Г3x tDǼc.UQl6T; Zg1m(u;U1}Ūm+ з:#3 8Se s+/Z'%ehAMǍ'a&XK(c/* "| q"jJQh=N}2R;ՅXlIuToVGj]U'1}Sj_d2 z]/ =AU{KwA(Vs =\&oW=0J1z"jcxm]?TWI֕bh6_&-BLZ!/%Ur\U48VZ\s7nh/I}va~ۄ+ۖ~8AΫIJc`Ή*H o 30uԾ ʛ˩1c !4ĤxWo޼Y߉ iWj,-jza.&p6HlV͠wm}KݰU%*8$7^z5r"o4dAHʏT CCkԽ_׿Ǐ~w|R]ڄJ1_vN{\cHq0z {h.Jer `8S"n%4ӮW}"<uB*8HkC rqpiѼڎb "{{{;}ƒ;?J V98l(r27h~ƪn"BD;ְTQoG{@וh&=uoYݏP > qH-8&"܃2ej7(6W}#at2ui!baahbeޮJ$ yHb:Z" -O?i qɐ|4NB0؎Tƣxzz"P#c_:ii]!oooN8u`rgU0oA6*Ko˻,=pp֘w"5fŋ/{1CiOi9o5a{֋)1P3zx*1"57"x0ZE,oF\ȞMT~tal}\{A1,Яs8fz9(C(Wۇ|en'6Cٳz0(=qUP" G啗#R5VHW֯G݁}T? ot(ܚ#{ίp);FhSV-IXtK@5C{4KU!hU [qw)-Oi V!Z!v؞%ql"[Q^V xe7 g!'++NٕV~5*,slˤqkT -0W'+"|7ᯇal$ݾ}mqd]jRō]y24{AIxIg!p 4 zmnMh$m5p===lҺ:vV{tڟV\&2f}\>DIOtطqob_э$V[?wV,\ ./gٹܑ 8vg/5dn)Yf.Mb0?/KpAYwiF̡%t![:\k3m(lWv#=4vJv4&c#hh>,o}X1,(٘(ra7ywwG[:ZT/#mcK(X#j+MҦWک@h鷃`TcfAJ/aF+KuI"i]sJoݑ MIQ\0(HO7ϲ?2ʔg؁VU 8PNW*(]?ª yLf5[{WR*4U:oC-]fڬ2|7zaäiUcVz2^wm߿߬qPac?t-:咦{ePpFnCY2+r!WCђ%rrԂ2YY"@5-ݲF͠#(!UfsaVc¾NiwI%Flq`̻'F('/UBV@WAg2C?/E+ QB{vdCCzҙv qb[L}+qg?GdF_bZՅ_#*P&~~Isͨd0g!l(Iwal0Wa`(AB|hp,[W#l|x|#@?&DE^+A. l˫yÈzoLsh%^4V<.SEUvk,1- x9mu Ҏ8L$Hlox\l .i]d`;t:(WJN2^VI{+ k}оkQeV~G1mʮ(hY.z[R>6dQ$ë$FJMx]3ԚǾ1\"ᩓb&Q,$ticnr;t]!JcMLJ;4x< P`` Pqn3VJ@bFXkh ˨x5|+x1lkVN,\.aC6 ֫`akT[zV`VT ɐ>~8pX=.J[6&uReZ*|huKiQKT=B Mm ]eU>RkW%xmmx b~G1~3%N5MJ<&ꔉsJb%cmv|}IWfr$K1b{^Bk tZs<9Jp1 T2҂#Ϫ[;-!^'&7yWZBl1ʅ"@7G9Q,5 uCJt8ۄ>eP(aH*0)~{o44Mu3dd˓ʘ bsXM3PmclVYXa]F&7n D:k{5v2d]USljm L-R)kS\]DEw8y[<*Y1s@*br㖍HaoeXإPhcy{*22wј b&0.tߩ^cՑ`nGk}qbB/}HZ LHK_ʽ;'\Xny@X@z+h]L(猯H1mgew ^@8@YOTbtB ݵb&^vX,Zy:ΫWR/UPRk kӴhquX+DokШ{ivTj8'CALV+WϭrN| #ZEvv8BTV/ ކZO.6i]E e?OU~Ct>ù 1\Wxx#;6-j3U;wx qp7n%UTvlWae4AVPNM Uȅp:^*3{%: ;sV7Wl IDAT\lۥj5RvU,jߵ ԚҴF@o3 M~~IoH+9YCP.>mp|`XEGjR}2;g\@:]T-SZ 1;ӤIQyaj{<, j]ܧiIv\ZCTSǯJ#57*5hAbq1/QAZ!荼[F =~ך5+>6 ο,4"=lAzZ(2F1yp݆ QI`yM qka]: GS,=2n /{mG &*O c@ ao ݪGGG, V8?G_j%}渀NZO߶TY2%$jmRGWK+[E^Yj"{\m+юd9¬݃/=Ɩ!4 &9vr5r8p.S)fG"UuaOjˡw|~,JW_}V~ٙrmr.*f!ۜ>aNG4ƓUTj^ܠ=}dNEd/ l/ˇ֝%ˌb EJ{g[c " tuz\ Ojw#8=UU!)=yaWS%PVcGXwepCs]Mfflj; l[``f{R+ J`ZrV:< <ݷoOٶcn"DH\g%1] ꣃֲ7^=,܌wBhE.2'eSq,(€_Om(b;rmmxabH ){qW pI'Txb1[gDR~9,p=\2K؞ d'@b,Yᱠ>st;qgpoM }{Ç뿌C9bov.2 k\k"BDwZ{Cnnn5#vFγͲVLvDSڵ,[>Zy:{RGEvtT@F`kV% ˞[}wَ\.Ԙ *qzu&m͘ VQ+7fhg U\l~w*9JVL^eUbm}k;;`xQ8VQǕXjAv¯ ÂJוBJXKnAi*XI.a9EhdتqI-@-^Wb\vtöC$Sm.*pn ٿgnõBmZl-9_+EmRZv379̱5aF㽂F=$dn=eMK`KaH߻֪>,cT|>4l-d8)A,4sO?oB (uoCYlWF/lЍgɘzyr0Hک0ܴ4E:wQɅ{ʁ(՗OUΐ4 \[wO~$ !nuZ> 7Y)9# -Hpۯcqɦl|ospZOR[} e:?,NC_}h5f5\__w :X\!- r!+W]E* s6'sL]{ j= f/fvtחv67775la j /?I~ܒ{ hBVP0bQr6ֽ٣_/>1 3[st~8Cg {?C"JͰNU;&8IV)8ùek#5ΉLBs L޽Ԃ4b-Z5wZV9MfvTVW#;,:7ܫhEMɯێEj4'_cе/mcm87iP|\>۔eIpdUŪ-rr34`r^$B퇢y%ۺ,SIX R"yMT>-*Z/^F3nRLv K]{XC΁xP hfɣrEԤT=O Ga}@  *SK6pJ me!vyd|||481r˽,Ů XF+[>Y\ٗImSEBT zPX\%Sl pԵ; I=XL oGHàVRRLi3( `$L!pnD7`(-k o@41TˑM*? @UtM$;,oFqÛ{ tashYRkZ&X3J/I!ho`޺2Er"\"^9,eU҅lW%ț7o`ն)$Kљء)ph5o68G3sgՀI~SK6ι(A٣LO1\T`yºV] ltRb_45XYx9*RX~mlAUu[KN&]NՖ΅ӷg!H un:%s}5=^"Brz]OG]'jAA%8 p^Ln@^CƒmW!kpXUzYkuΪf~c-~q ՛[:RF/s9"aeJ8oR[ 1]k R&V੒ 7nsT⦀XbSq@.Q,v;% g9*v =U˶ztđ0 "X8.M_V<=OP`^T;Y혽g'v\<]+vtVQ42-ۖ!%nv. سM%Wiy~_|קuaj Xep໶% ׆W+s^e,JN5ZΆBlKh ˽LK`\ $:8P*k`>֛%b㍕V?o8%]yav0IUExdf ;bRQ%y}zzrW bB R'$\Sm(l)EʃL%{yM}jT

@{eO*0}l5%K-O}%N #!ݻwYK#ˈbUz8뀢b'PUN"*U{+txU͟V-Yfۈ I'VYW^-v6oز_-)]GRS>-U%ۍEzwOJcpM4XEawKهTvCDǏ):hY(=^a{nZan\WiS\C"Xaa=sB)at$XW3Q^ؿ߂a:Pi9 aV5TW+^o80Aӽ K"4  MvhSjTF̴õ?*^-E$Ŕ#0mUA5[Qw}YĝA]Z"LN>XF_N'*ڇow*P' S!ES&^zd8Eǩ/M1pNMmQh;{X.ީXmjb݅yvC[dpLjP< (XmtZ`2L Uzbi"mTtAeH)42_>ZTr7F;zy_6/ӗ$/Rv^|g&o}ā{U;}Gb4uȕ=UHkOkDvOPy$S6gD8nJmN9Al+ޔi:;G9DIoi휘^0ܮgr-ӕVV.B= pҍ]ڐt p=c '8쪴8sZwK+7V+P&2Mm1ۋ.7 }X 8|qvJw*Օ>8Kh dU裀Ccc")nmw[N,T:jT x~v߀FсlC0/^G7z<6kԺa{^kO/.LGSCʻc C%sh{B6VOb[$Lܰb쌣Q ۾1f?nG eGnwk6\A]pI~Meaor8_ޡtN mjV |Ŋ$s=GݓoY#fhYl0B?t(dȧi?swwвqƜn6̖cWmҵ{Vz.^[)_]YD?~d \B\ȕtmy( "Hkϟ?O䴵޾Li"[b7wْKw tbmM/_><<;"Roo}#nD;gYu88ܸMC{ 97GlpYϋ/#1MV.|t~_.E|2r!t) Sabi.ԥR[VA }xx؂֪Wh..ܕr8:#ں:Gzj|$x~wwZrA azFìjݠonn$( HC!QS;= N!lbca]p/nlw۪3vDȚmG*%"@9 qD/>g[>>>-ڲ@e9&{e6Çfzr}/fU}\noo]z~۞̻w,Kmu=crȀmqUTAͿ^:ܳ6̄Q Է43;{Ԕ,ǝ"(Watq5[O"q{(T__VBg^,"l"RJˬLdEȴ!WqFxC'%u~6AW)~w(X>[V#!YŽxnVHG)w= M O^K;|St<g$nZK,~_aZ*&iR-/!uLW̮4"WD.E"4~x~xxpKuwMN%sR@>螕Ht9ӹQOmW&Sj&AkunSy{V؋v#vĈ(*|Lsx?zޘZlkV%Ț-HiO[*ƺҮ ;<#+b\.C|sNNPq/pi<-ak+Dn 2>*Bw6K"Q^;zk2pB%0N'P~=țca$Ig.PuB+ֲD5UvQ:*z”u['b-FTa G_GOIźRt)lp`Qr5͈phy%nˉ* etrGTv;WykЌF([ݹEM \T;͛7yߙZ R߂Bž4iב0AE Z-j'e'^P3# c4kxEbΉ`k#cFQxj-[ֹuZj8n3k-۩[:Z;qI,Ś;RtjWtެvK2D{`ᘞ~_v/VnPʃl!q+jڰ_FTȯ4- FfDq_mRoۈ0}FHwᑪ3oUe[m 2V5*c_g=ɍڈWSq9@tW)X aCQ4v ]O!c- P^HUQZTWG(%VVfz2v8xZs1q/ O^MJd9sn>Ƣ1xx*1jP]ۿ[v绽.&ꢦ}PD|N+Sf,L~AwJ7܈z-nnnF6EÇf5O8kƴ'﵏8q2k?9r>a}9 $~uaᐎ_=X lf.up@_⏖8⪯3Ҍ@|ۏ뽀uh2)[Ըcjo(:P-NvL֌  ZߊPd1Ghu7,i೵3הfp#/pAFo 2nug`qΖ%՝`_#eQ,Q;T`dTowh@Z:Q7*JPݔjTs6k}fAvKDz~8"ߧO6 ]f*ܷO>]=TDj'ND(fbl6ʖH+Zm=WkeP$!̶=IP; @#S]svM(Q^N|M0v\(Co_NUVTԮ)$l D5wt^S}8ف:K9%XlFEV \N=eqH}/w8 {u7bISkŬ+*ԶT-j lIC 5z,&\01 9VmsV][ގ4Ҽ JqK ZLr 8W=80#2Sl1U"#F|֬(ح+&E9$qj\o {khx>ѣc_nZ!Q\a~\)m*ѰqcUU]ȩRj1DhJg$k6F8B'DTS9u[aT6KRY?K[Bz TCv؋G<8oyQm kؠ8k֡믿n!gf\ܢPÔ5"_ 2b=]޾}jy2,Hٰ dK14'b/L ݺo'Ԃ[\[7g~$gas@]|B. ^ RsYkOg 5v#ȍ+" "ߢ!W0jn uYb؍.,>׶pknN9\;6r ;T8XֆnЂr ]c;/zu WOiJɶ*kႎT71D KZv-}!uHhjNr\XOﶛa!ɵaZ@q0`uZTi}u !#[B,R2 ׯ_<6z Wra cTWgT܋YK bP&s<|-6[WZ7ऑzDPDI并v"v.;2ipu)Fo:0j;AWEJۢ%9D],PX e RoU}<^ye+hTPښ*ޔ裁HB`[ke˪vSM쵻թBJ99" CHihւGzLġ#3i9Ww#!~Eٍ <(U|Yf LLaVAy"@JlȦMٱ:%9HA8{+P\ATRLB8jWiޓڊ9Q2R9l^DC٥Ew.6#\Fv2W pkʹr„ ٱd9&+8T?UaE;ҫ?[JBh/7q+lV^ug8^dKs0IE0mG Y[+<%UҟQ5J^f(ӑ=U_Z%"K*-U4'5 Toee͸5\k^#I4NAHhLdtju_" Cbƈ;2 C똈>\=WhV7r]To30Rm|}H=q!)-5V; }V/Dn4EKHRxq_:ԾqE5<^۷oٱ_ ^x{o&sY/cꪭMg%6;*f @@DօB%DfM^|y{{s{=%mԑvu u"ºd:{wkmy/ZbH;si$_teLf꾭O$Ut+~*8n`7fn=̆yVn:(恁g'1VlMxE57[&V _'= M;}cn WىM.zT6T|fvnjv+Q$zSSo{~{k2TSU,(P=+f#5q{l3_ Ew~rBu)͆T:$IN/d=Ÿ*:*TO9SGK4eUڠ3X EKn$~XidB22 m ݷur4r}+GF*>TF/@:O[Z74d%̈́ GFW 0KOvNRמ"^]:2@{q.ic-8{;%({J}ݦ8f1Vjw;DAټIIK;,5.$LIkie' mj͛7HҰ".,/P&)GyR@A+eWZ#3[,W3ҖF\ (va5LY)4ўjr^T٩&}LȒt|qhx}WEANҋ\ͳ7Xxo,$c" #.7ڱz5ۛm!{j*MkQ](Щۡ +̇y!b[6.a׶@yyi|.-Am& ގU]諾յc*'=1+#]@*p{ݒ*Eҹ%|TDIyH-Ew#0!u#bץ0êxpE A^eãe0jeWlP5d?X-Qcgc;~$4!U Z:Bk IDATԻc]$ЁK<[hTW<;_kQar?>X/rkV-Łj]pO;_3l;8wŗDj+pt%AkRW ZXTO~Wn@YvUmF Zu5u7c;j]*nu1g45w`jUEG{8$k߂?( `|q*^_WPk+ge-"[;q@=F~}9ʢXmGs եD&ܩsR\*sAPUIʹjJIV '5+l_Ga0N_vs{{/X⩞a(Yi<6+5r9*p%M͗;ZK LU;LErm3bb,mlBɕxksvb-]k>TQ^Q-K eӧF\æmd|oX`H~XcڱpEj+N-27\ɦ"LT~lSI 屃gͪvHFʍ.JhВԇsՄbDFi FQ8>ߐ'E3GX"K=fۨ~>DsUwtyK:YKެ"YWk-C͑JF3"!,#15Z~̠-L5Jn`GCݕ,T;XӖ*5z!aXج࢝=k3*=+>t(^RYOgt^lVb*Ԛ:ɳPS V΍\]Ӗ{+XUgS <]VPZ٢mp3& Z:bEw;J-!e:Ckl!CHCij^`GqP<+]<vKV; %馗x:bB]55qS?%-~0; 8/>xӵh~]Os/ x+z#pYd#3]F|U;;njB­+F(FhItӯV#o++jwI{ C9taN$<<<,Đ=F9CM8eKmїi3fS ;3#aWC RM+ Ably 9 9nnn>|]CCӭE4"4PC G]%X}7ҤSs2w:Qe˳jD/_+=2-FKKY@w=i+Sp4* K>*iaKj!pVA,R*馟rutLD!W+]%fGT!UTW%,_Rt2`H׌P3CPk!ûON p/*`f"*lJǔn(nFEovP ?ÿww,BV)UG8;|$;.DJ^p{ݘ`]쪺爃qE jmJf5hxw C(Ԑ^L)ҼD*ĦE+VDj]`?;m*cMXTȍ)>m4 8Z穧zl{Ɓc aCݭ)Pj;}jϛ֒j%k1as,Qrϵ m4S6_~QَcKT [af`teg !nZHOv&V3gNI7=7G̋!#xվ]6 - BZ)?V@,Zϵ>CM~BL"̢.,yDK(B#cYe""@XT>BRDE=se4lۇLcde)1IZSuŋ蠀с(KvO 䰥J! xlnhXM  S=vA6mO9bJjN4syU79@1BB₼Wqʈ`l Mn~yF"0eZ*xi+NH(˩gVB Bltd|]] D+_&7,skE;5]5Umw =Rk!2hϡRmWiI+pNœXmT޻[ i]EFavlTs/pJ,~|D$|1fRMѨ%s{8 alO #߱ˬWթ`L~YY^>i;zBt]bTFQ]0¥({S5og Q%j)Ļ'kdcbn`'(1!G)H[Ulr<9Ȅ$T2ZO:ݲ7=Ј{un :&]S^'xW%RA'rw`^DPZ(ԌV>݂Q2)j6u{i3'#4yE|buxd9x^+IQ*(K_*VݔiVn4z874[(Fäfԫ7oleF=PG%2=ժG%|8;2 gZ= Tϊ u`ՙFe jA^|3E}qqځaܭ6rI( rD͢v@\duNNK:~J|=& 5VZb⦂_[Bno. PI@m1c*ݮ]j ҮıL,bٽ=5ܢMU1yVBejS1dj6,TO̕F:ҮaP=Ő0OFwlzXf|IF1yVcGi;e07n0[W֛$aVk~O@EX5aҲUUE. XaM.www3vܸ"a F:+?+~R2SW_V/EC Z[գ[dQ bVT$vGjen.Ynk.jCQJ( v{U6dm%*J.}D~} Ϧ ,"%uH aj98*PKas\ԍBTHXYӱ>5D\(AwVWwp .T5 8ʦZ鉬8ȫ T>Z;=}vo+!ǣ^ɼEnoo1⍢ՆSAGҌ'y}ьL^ /'ײD<giDZ뮮ڵkJe H'wvRs([dX>= =K^A 0vŠֶo!+۲L=ZrP&gjq VY5}8V?[[bxI$6$b&jxOq#Et: vi+4ؼ&C%psd~O G%@/՗2” e+,s/w# xu~kw-I\ *^x یfy/%Ftv5iِD94͑k#eIO?! τɶ 5DV9ֱoW(Zr ]=`,1一~moS@/X?z6==F]"3yt|T]UZ s6@T%.A ҡ Su3N6`_2*TC R%(]ލ6m˾piZ:ujTh͉ϲ4L{mw(Z#{ϟOWc +]lg]67u^xMmbsd 1ZO[a*x^̡͢sqx' DQk緕O';ƅbonhC|;xwG;%wv8:(J&z*Vq)?`#@vۖwi/E2?}_g>ui;FF_d˅U0_|HzsX 6go?>3b'Sp=D$cE #_AqS&.ڱGyQR?;XT_-}w>an֝}hqe?Zttb*6#BN"zX:ˆ.INYkCqxXzS:4Ȟ0uc$r[l%:7S)m[Ҫb(S: TEJ!P^[]c;O"б"dǭh5U ckIwMڤP%q7TsRUFhV_PDlz Flߪ]iV&#hAk5< mXb\ =Gҽpݤzh]v]m N햶Da@%jj#wVjd#-r,mk~9VM6\`UYRo˗_IEpzBGTZcZ6m}jm'ocu]uk&P3Y;˞42VA20rnP-9,c5^< f(o=(xYQ[\}:*)ΡVґ C"nڸ5+Po)AZ:<)S^v|'\Wd`=E: )OuPD%$hX~vqKŜ yuq:,$[;bj( cLxd(54Z X5 zIjdCi{9> ^xYVަSl щ<;hBJ:KêEA .K0ݾbOvJ\OCZ{aXݡ- m! }6X!t^˯rSp+s%e?I)Qqi^iMC|knSh^C3I[$٪#:&_]Zٷ}?,Wz*`v|jJ߫={%@.0I,FVǏs/۫,7m)0;+OI'Dg_Am}*SMn10ukRīܯ_)ކo^p}=u6gLQhYNmk@XUu]g34љqV]RJ HKLt\e!̲ nʻPѥښTIW^{Tʹ:NxM]98+SJ۷o1u6WXv~PR5!LJ9JƙbCuz(tI'Q+(`†R km4Q@$2)GCno}^5#qB^<+sf+oMX zpk+hԫV"BQz?8mA$,kK ĩ>aJdvyI\f*]!3O5C'ߴ}鋪;rdVp,Y-P3زBDW>A/^~BMo*kr.Nv؈ J*dόRO|YAŋu`i2s{k ^2%:<\nZAXqc54[^t8:F+Ա:ʙIvjrVs4)]X,-O_f#dRNԖhi+@`#Qy%ȫŨ=|#TUXֈP,*QdҚUP/ ث^xF:TnA$s'a2^W{N&v|݆ ת9̨_> A2}9by TVWQNGpap;cVZ:$8s_z7uiw~6f?Ӓ=Ix7,MPL/d{j0GmX\m}Fml'A`aծ:jl W$HLJ[Oy-DmmNdB3䬗a+&:PqqXe5nx i [T4+^] Q2qk Z ~+ TZPws{-U M;v蟖[첥zx.v*U'`2<ۭ(uTfۖ$M.e{H.+KXn`EIl7]m X*㺂KiEBp\r8 %v1JT/_K/pV E OP3K1&,TH=՟PK*VA٘Rv7[*u{|-m}a(xo.,YWFJbZo{0up"R?SFC @X+ΪK RQ7h|soQ0VEP ɍklCP^RNު@j}V .:ئLEpѭG'QG:x{Tթ|v1`ik+M5P,=ĺcuG?)i}Y4SExI1-a~}*YߞԞ~:Kf$ q7Is!E\{5vU׎re^RI Df*vzzZC8=퍶mJ(FGrʮ.'\cza,kW2!ƪ$?}tZ-5څ.2c6^v3W-7+ø[wЌ.ĵ$PmlaU5L(fv)9M IDAT/>auʸe|1XrXl$& 3Ç:nnyV Vnsb64yάV׫P.]'8i.' Jn+)ݬ~ vV #*v\U+Jn7щfxTC;u0Ev *Ơ܂SmLRz {6Tfz+d[tI-A!XL,7y%HUĻUU+~_y2ET:R $fLrSKwuovˈ~ɈHMqYa5Q}q;(5FtMZ`k}pti&_8Cm%M„-T}TstK /KWj#<#d00nrە,¦!!uЍr oѴNl_5aJie *mGv\WmbQ])*+ĆU6z0 :=WMĶbv v rK9"/;f;Фtq^nYY1;ucSE']v{ܩCBI>yѲ)A&_'6GOyBX+alLLH}Zp6^MqG3r*Q^آesrYt>d\eЫљ@JWYGmlG5ϫmk--UѡFߒw GxVۼwG5G⎿RZ\j {5յ DEíu=h\rî 1z$UPR;4>|O?W/^~CxLW<}'n,h1+}=D-Y/)C_wCqϸ([?0bS5H\~ȇ' \/*W%uQҖЭBTnZ *' E;kRre+KpD@G_iu{ɈBqJLyK5HG>bcKvI[|؎~#_pH+:MOEX{VF ou]ER+^~] U"6(-(S0]]dACu͛7O񶈇}? qҡ|%A ] De} < I:lP W{г20V&dz~:|{ _r)ͬcզA(ء`"̰zy03_zwӤ;.Z>Ni cTJemm Cm{ ;|*Yێ1tՌd3  h |HkYm0 #:,PsWZTdJӕ0_Bdk`/S Я_7Wd&"*hQhA'%`,l%vl{˵퀪Yvʲ޽znzBˮ$) q6mjR.J%6Ruj}-uHI8ɚvhr: ?·ݤ| 񼾾.Cn B=)K<.vѐVA[8Cm nۦzx5: [b$ifjx +aNY!e\!]>}tր۷oeF޽[X@3 m9%j5IoSvs'u%ErhPZ%Ů{y~u)@b?t30 u\ܶxM"F65ՌBh%P'Cvu+*qFܓze)KA tD޶e_z-nڳ;.64/ڻ-P>DEqH25zhkP9J`h؆Jc=˔SO<`,8 YGkMhU ́:i*Sj;&->ᚰH.%pZ#iMlQAKWY쏟u!ֻslso׻t}~mSESJ?8垔ԼhXm4 df06- z*{~SQ:xj $8wN#b톽1RMTMG|w偕V(/؜+&)]T"csբֻ2aZI[?Um\Cuj+!k!?U#]pp-]:1޹Ha&0]*HYSW}A˾5ܛX󠃒Y&ү&nF5)SB D1xj})9hn!^w\^MNQl?V i^8UP>iq !mTBz߽AC$":{:56>z7HQC\+r0S?_l9I`bZT PQRuN*RR[tdrNPF0Hr]RRhj_-v[ + B%\ޫ xmQ\Dd4b ڎn5:&p6vU_}% |0S#YqEȯ{g)/x$/_$GPƝ <|r Yqn[GE0(EH,vֈUմr/l`NS]Akp;6yi[mv5,Ш; D'ibvr[Js҆AEi]1r㗡r8r`MM+X՞^zF PrzCIu-_Y$1.Bb-ʢse:".*k58: 8 8%T@buO&Ёªɱ֝qb3doj<}7Ӵ3:6#DӂwJ1eX777www>}k yaC&GNApOq@.//'Cg0.fa"_Q[O{_T/[~@c(] ukB~5w*4<txBvq{ HqR~N8`gJ9԰dne}_| 5&n9UH Nˆ7螮Dul>$F[щ#u.,8h.wss2JhzɤE,t F$Gm j1#A'2G:k=k1:*϶`Kqaw+uM")6ɲ7bMK_~K,U´ŻXW{リKYAׁ{)UK;I9ƂpK nVi/ 6txt ) ֦DT+:BlhTU_DўZ%uҩ eWj(ㆍdj;A'tHu:pww[ږYHZ,/&|x;U@kϮMzAh2Pqaի _A}gL\;*ZIA;|U׬KRa!OKLDVuO]'MŵCdʦpʔڦQhؙG.gÚ_`ܥ֖:h{٫Qa3_Y_y9jQLjQyUiZtA Q.uLsZW`7`ٲ@ ̹(%CU$Ta @9 It@Jbݑ(o+;e DP"F)BI)awޗh$TshCF#t K%> 4e>bů֚FIB_h{|GC^ po 2t4+?իJ-ǬoW6e)P-J1AoNS͒Ջ wjhLT/5?T;sNڙ1Dz(( -۵ͽ}hab_`ݣ"MDdGG^Lc=L4A52yBR[gD]ZG}s4nnnjB" &+V8Q瘔l<*m3.{EĽXK|v-ma/Xd8F Ũ}m?}tr˿;zpcPoǹvuTߤOŋkuZtAF T~IP8X͘Ulr1ocfP15~Y*{S1V!>woH2 U0M\Sǯ=;3/G{ M+~UV*An yU%ִԆwGȀ-)P4 Y`Z-Ke\i2m:cij4eٳg;\*߷.0md # L+cm, f GPۖ"!ۦ"4!b[Xf|fKW L` ԚqzRUH:4vU'W^ ZNmSqhwgJmQ€vd=u-!WQ*WCP~}*Db~2T-9ۅj׬C&a\U:Yܤ,ڪ{zƮd(ow?? mYOW V&TZ)"#JۼoSAm<صsx]j9f[VoD[HAqݧI:ۛ&^w=ZFFNT3TΓ:t+hJ 2= +-vZ;龔U6#UC2 }=n;U0nV6k7m޴~}ŋ&'W'E5vuTň:?.SPWz}|6|2ءz8&:Rݼo:Cp,pK״̸1a@a #!a#VT=ϫ.ʼDډF&FcWi0a'KȒfXuTxvg3Wwܪ/Eҙ%V.D7b_={\v'|$LSJB=uO?OȵTzwÇwwwaKN^L\8⫉Բ,0hUQ6."hEd~-5z: .5`6(om gm wJCdZFJ~>_jYrHqUsXaTOٵ#qle@kq~A{[͒}Ko+!LwfK2_USU7U9bB?}Ue%]2_0y+)=JFWgb)5BgVruD˴rOI.QGb04wj(,dɜRl%^>0 IDATt7Aqs^0OcHBͭHVNj\ 8jd_YG^'Wg;-ʭ6)s &onmMTMPM+ ^ ΅DF([q`# >Hv5r= Y4TITAE+H? $vǥx~t,l9CDn:v˴Fj8t UUNj|H~[s>;iCz6eR2ftFPf:EE“H9#(P?<.h[ ~"c`M,y.ttbpB6V۷Xk>=`Vs[f|URΑwV6@/eTP[i}RrKUS@H{j|fSEP+3H*SoQ6R;UEB|j#{j/5l[1BWu A1ΧM\l ։hX=YĨ>BXAfV8zKw(MBbK^>nx2Tz&4w/U5j/ ( @,'!Ŭ=Y[1lbpBr1pђ'aS 5=Gꦏ?_*@nkQf)K GcQ*fDݎ)7pcXVOV۷o$[UXz*ܓރrXPd+f[TuKЫVsBHrمxe$)Ϲ!־] ]Ȥl4wJК7jM X{ZpĞ>}:gy[žoO>6`وlq5zχZi8EOZgKZ RN=Lϒr^)_}:=t{e4{޽S똧Mq)DHON)&:;=x~9eU iʇS W zo$++,^ILMxZY|%Hw[J9;R `l)v\ B~Ym-|EO>_߼y{\vfь﯊4=BjHpǑ`"SЪNٺ lGu7ck$vN'yzZ]z 0su?8)tN( t՛?9|?զ\v{{[&>&=ÚoL:$TŔeۓYyu}wFquywJ=nmES~^mDE!ӘP(&,Viۯy85v$cѪK?: Qh+ uadaU] ]zej*k-^_g~m91Y1D]}.nzG.OeV-,sk՝PCwG@\4©1{7wd{U'rZWuNE/3vBe.|}UjZ al*r>CMHA\E3jCWbҡtsmPe*J)iyƀ(kAӼq @ybB*4 G:D: X `ګ/B2<Qׇ\Y-r;4[j& NwItϱ6ՙ݉ pP0wwpC)ғHafiV:mMhp|?E\!FTh-}K'*|+E)93ڮqvȗ!U|^ҒDW[^W؞d"{#5vUeOunqp(ٍ-tWM90B/kX֕|CիW. )8`rX~POSe.λ|Uuqc" 4-Z BScf_y\[G Lz=m Ĺщ[,@{UjshU J޽hoo;xD2w$z+tqP|;Z*RSg`U;@܉>or_ު"fNjrUe /}.PN);{ۓF^wܯl6k TYz wm^j:CgC!۱37ڣ\Ey4]w!Z\2T+hI bvx`zk6pV9xknVtEyG` K@ h>r.⢢!ׯ_W"ǘ>҂l ]JB =оᅾ`= j$,<;/nK!$ܤ1+]`)xSc}2B}H§  t3Gsɓ'{mQeٳ;Pre/7Zī/!VԑfleGxBf廊J*j/-N䝦:ґk'OYPS4tRCLޖ+QdgjB9jz <=b*P}V#VL1/v(tsjO.(6\U>Æ3{PL24;+I6L%p9Ez[X !{v)4&W/UAH3˯_-ɲcH"}-jAm:fR)D%;iL:ANse:WFC}ą*P|Lwi ƢWNke>3E|La}UPT`eZyZ__7ׇrq" ]:nSSCk~iV&2-s+$o|?&QG^DGGu%W„ MPAC!ZITkWOf5L1s?ʌoFӱXeRjA}강ew)v ];x|JJ8bg]taڭRh#3+o%a/e aWդ6YoD#UԇM;9AzulslYkdL4ؽPSc3;I"uU='nф0iFHedEsϟ??Eber=Q{&Wۨ]rnxpN7#ӱDm5n;95bF8;9Cԁhѹu^=Lߢ(ԪuzD#OkLrhRP;&\_OSבv,( R{T 9-ұ4fe%MjzP1GEIݎ4te$c?a+W>+ݺK>6y׎9ioA* 6C̎}f Tn,$xXʸ~k'ܻ{w7C{Oz2dUPutnEYz9QA5ԗsp#AR5S&lk/ hTvh+Kq%,[Uc',J15 [QY,|c [)5gښVy qC+UWͯӉ/lev$euSUyVCgJa>=}t~wmLlNiN۷ooܛ:^ZN-kc_YPA[cS+ 7v?8S} 9BcD]JF>zmWce#5{_dUCu%mBOCpɺn)Ӡ4<6w__?N0XR@Y:*kG9:38TɀCT~ݼREeܬ및.E| d^na#r0* e"U{@F3\v`ŦjweZ9*lt1zЊH?uT#!q?3" 2Xlehp]݊Iu7gwp8׸܈P!. 7VH4kU!˭n.^dװY 14`]PjY6vMGgښ|kUSĺ_P(@K*GTLbBuʃ>{5a)hw+@ReԪPsAEȀ vٻ*Tԡ˒ zHjJ82xMxLrzС,'rb`|14W-VH{VTT\5J2elSq)⪐"%7WA}=T1#.ֲgSXl,}~a^f! ]vCv +[OI7H PjҢP*WKJFxz6 2bv*l1_f_CB YIlH~UPޏ:yiľM)_oI$%C}r STV섨=US}x4v%` p&G,drlVpoN^z%5^ H{1ggEntc-i(=v]N̫@XZxl#gr v|A=}|Z7Aw =6;x0] FY=>fab50il瘽^fґa[DWX2/ZYEx'6n75N[\C;,İwKC^9ҭ3]ERUǗ?Ű2! iI܀;1@mA-x>;z{}]lV`tWN[# }5R勉 :r^ auCWQKG+k097,J`5j"م=cݝjZ,W@CP3+Vv1mTXV lDRbW岨l t,2P픖n~yϗhBM(o΄ b9SECkJgTyx_jȍ'QxdQu3(>b"!R!.Q%HcWԦP@kqLs<](&5HYjm=|Ӣ"U1H 2E.Pve(TVSޔcexbPm2q;QnjhOS\**ôx?W]/y)ڣj IDAT>^aԊ"Mz+`Sg,i44̩^jB\0\-Rb(uf+T'aB:57o\%:lQi⁝3MC/3KQY yR A[͡wqq1Dnu6,E I} bbS}Dg[bu\kKd^b0FuMq{1:GD+a=S .(Qg}S6Qg+z7qp&u]0}n# yY?QX^XGwiC'kK]Y5-:C:ڪ0^QA)!ͭ0raF;źD>̺GrTeڏ$ʧs-*mU9:6$\Wq.{eQm>xc>'1Wp1> Uq/SF4J w,|_aw}W𫶗rq~ᇎw0Fr+B!r6K!NM˚vXKw۷׆q$()= {%{[#p4Ð/ի/^n/<Way62eڶ}Z V$8wO IY^ pkzUUw GcJs:CDuM|v={Fa; 'c#fjtBԗ疺q=8KB 5v9id% ^2 GuE2Ut$_,m9g>ΣaVآmݫWH@E+;뷩l8wQqg֎y[ʡ} 4K] '(NhI~X$`Tr!@b=mEy}}=rx  >0R4WkA.mey(jW~̩)޴Y_`#$v(@4m2n I_ 0T? +4:1tPSԅ+sonnh(+łeģGnoo\6P+|}}M` ]$H>V)ǹD.\}T~R-TA%m]uTeؙ_:>M!*=N.: }_15.stooow(ogcY *m!`pm*Uh>|a*v-ϔpqrs0-Y1Y<լÅQKjyǰ"!]ӇW+8k-}tmq^G6t%FI %b;X0{SP.K݈Gۂ^ iFjE9vQLG ;J`m%;tm0\' .Ԃ:Հougo` چFT[?޺ņ+D fR AZ2n` : I_(y5;.JI`Ֆ{, RBV}Ca__a Kư (6F5%+/鲻VuWW^}v c9N> ՔXL.hQ!Ud7뫘l]]nGJ1>{yq=}V[v}Vt+‘-|??Vޒ־v7 G4k /lt_Up9I/$;*eUbr ^M*tw67!*3=Ft-jKdطSq-@nuX,gkZ/NDamMp b] \P׻[-yiNBTnS#$ei ]2ŁwRҬPݷ́:xq (HJ5є, !bHY{Yط^B儾z#hR/".]P}z:*_z˗/zgDunz,ްJjt_Q+vZYǁk(GJ]F[#z^ Cz Wvѳs܈w@/ {9TLv6!% m:1[B2@D(- 30 W~(m{ S|9#w;kò.-\[jVRNԋ-h*;Sluwd\1\qg!ho5vyCK{| M n>ua6g>iϺX2g\QI&Wy2)H:ICӠի4Pd&{}LՄ%hLtc ʄ:IJ6lw<Ƚ3Sy#ؚ_vʦc +,^q"s~7OoD?Yv<{l0LNȸ)WwwmU/?~dX׉w ut{HVn)GȀF$FbAMW7,0W-4ᝐ6._omGcwJRn{Z)t\T쁈K*B=^̎ >5t-e%ra܎DfO2fi6I=Q[УAM-UVK#2͕wv,t1iK9 Zf'-oڬ|SXY;68{wFn{CZ38-6[ SLMua6udZ^L;i3{0& %ǑܗgYs#¡Gм, ?Ṛuk[QEB ;5/YH~ ͕E7J>tLz ?yA{mDڿ6^ 貦$^iKWmˇKk ڃTHPkذm0RvHi`j^# X rVV48/[6lDW}/軮E5Pix:Y)wXU5e5~#R\P*q5}&tvڞ{{U변*' իʷr;aV*rcRX?`y NzBn)"b!hh ^l@PzkoTiV5 ] &0( Z"ҐIydm'cL-dm_;ףnkT4 :ay `6 6iw`!Uǖ-2-<t,u@lbR$ YAr2ĥRODU>|K3VyEwX]r.TQvs\d^_b*/j-O&燲v p{r<䣥UYa(K9@z +f$c_xqχle:vQ~gUu:_ȅ`P9iTK%TkgyzV4ma5m,|A.yn^aw#TUGo1Fp@L#.vn/ZHUDi{Jqwkin9;{O3+]/;C^_;ZIF_С9 h )͇yj %cŽt<+ǯ2xFȪ ~={vwwW #ck޺bKbSn5ۗ>6K3<]{ V|zJwC;q1{e JjmU/ɦdv0h~1n Ah"DW]m^E3mxs' պ]߽{ijh\#dȬ= F,D^c[ak+7mň CETn7{iTm2VmGުzG?SS9]p[rD<#t{\* (p$vf @v>fџMWNaֆ޴jd+@2ڃ cHj=ݮjjeHrz/QksAwaΓU$1t2u=ݯEZXk2ppsEb}i~\KCN+$@g4uF&8ܩ1 lpPqZkj[Qv"x+@ V>l3{H{L(6ZҨ~KTNtHִݔѦ>YbՕ,+P5 wĢ^$mV]KZi2uM߾}+P9 \󒥧; jpf;UmJ"~Ke$!sux$Y-vn"x jGJ!XB*I8J=O=z~xRnȞ '["nѫnjpoRo3~B*Fჭ wlSPz-(YGw|ytАVr,NNyLUv!->b2m#pޗ\}$o3BkX[ѣNy Y}/{@Ï{]okrhNvpf/eMS Z!6TvV%fnp*Bшk`YAzPN wȿj]K:_U_AVBHԔg JC,]`ʽWJIj>@5,lVS>دg`MscFRǕ>)\˦ϟ/X;y^Rٱ/%;':Vgvx {٠}ОBѪ&k֝^z5jF% IDATPB6(~Oývحboq\l# j6 )ձjV#~33Dq jC` 5XU"(VmJīron5U(-#H i磙wZUѪ{aWmj>^ `(%h3|QU% !Կɤ^\| rʥ[E2N.lj7W%L6wW\\\<[:삹zE7{I3yש̫/??iA\lS290uvvm}UI'ho#֚Q&,VWQ;t=DyT+Ϻ|) 9+dh XeEɁ31+NX[KRRQmBxAǰgI<~-_fkp;X^CȦ4N/+*¯޾};·dE1mѫT[C̣.TT Iu;>zܗThIJ:Z5=+L6;S)qB'`5|FL3:u^zњct[p j]# <~Wa d"ISMS<'Q[(T>&@J\"jϵHLiKPUfqjڶ9-7XNf[;vºרJ-΢ڧϞ=}ӧK.o]\\<~H/_..V ~[Yǫ{x_>~ӧGWO<#< !O;q3Qyѣ/_&y)͟^^ޯXv~qNG.|b$=w-qr0$x@,~!qư*QZb(:>,i]A>RJZ!Q r1wwhh%|ze׿b8! rE2\&^8NC8lmOX{:ѡIR~jUnM wwwUNW9 6֧뼳Ֆ 6bvQa*+cX_^U[5c@>*ucи|c_(Y&Gѥ5]DZgj8ɷ/{6LQ 4tpVi1$[LI7u #6*=%3-'Adokeۗ/_.Mr5}о}ɓO?哧O?ŋ/_[.|/_FORyœoDu} 0s@Aȭm3<ɓǗ+#ÇWjTMd_߾yeu7^Hrψ'c\y o0:A;^5Q򗜡!'mOROA)nQBb&ft1̐SM$|(kYl^uPMd#cvA HM]]_dL~Ӗ[xſ뿚,ЫQ=z1TPH_ċ/(UsNP.a-EiG&qE‹Ʊ{&MNSU e/b`$iYyoGe˗/1*:T=M@%%{YY>̛7o\޽{Q]yu- hjRJtT PAnr m+( e0ud>:inTVH>kEvՕGF~]mjJp3%P|aVR]毇ѣuo߾}www?˗ǗW޿ruh+Igz~E[|zd~o_?zQd$ˋ x~[N~Jɓ=B|o񣋋}K}%O|i.ZnYn_}2ўCQU^-S*UY$4LL׉6  ͬ>Xڑ (32Ѧz. ڎ&4f&m%R+sn2~s'$gz;A& ]jr=kiJz}1aXs_A3zAE#Drjc H+]*8ĺQ[:׼\ހb`CvޫW~CZ*{v4(al#unМK >5eZA#~^29dBFKE 0[BGHQ)%D-&Ȳ~tF;h&\wX7qd!qzգ9pLj{6R&=۷TO>})o劋k7S`I?}w#OUljB)t6USr+cζg}k[zޥ%2“JǛc^__ڹY؞WT\gl^(# C]$fQ)& ̫YJѱmzgiTzP'8Pu~58TjpqӧӧOo߾:IˀO?+xǟ|yruu/_V#/]^^~x6y|=rqqٳ>}I ޑ |U>}8fPGvQ_^Ce"j巫}ss}~Dwr!ncH뤱+@L1o{Bu+Į]D!y͛hU֮$+liZ*]5k"}Jٽ CwɶϰBf7.1Aq(UߺkUG՛7oER˿ ?ӖA} ;VuK>v-KTW'AvE/2v:<8>F/KߺYZZGC@~qb?5!cp.-Jŭw*J xQrh]Wuu~x޼y|&h NIg|n@w_STjHF+4ąRvPbK]gmmJv4: {eJD)?Pگu2BŨd{ șVlxen%vm!JpVFdmqmi4__ۻ?~iV=yru?<.|aQo2N R4d|x}-eYs l|ϟ/?-WߠѣOC˾Q]\]GalB8~&*![n3LjǏFRlPml0oХi?) Y~+XE9Fy^nVD†Ia빀DɫSZQ'f=%m/0c@& ?bפ%sh8_3+[7_kBnB(& Nj3kAڑ~V[ ֢vLzH}XbM0`CG,pԌ%κp肂\h%ǿL y \d4cͶY E62v]}3Sjp@sΝ;w߿kkk˫;wܳgϾ}8gŶ'.G5{Yf?n:R2reoQ|0_>oқZsB  +*K;KfEӆ1b'k(Ϭ>, ÚCǵTȒ&3Tn+R& Xk\8mdÚV  =H Wd1ýk.(~?HH2¹џ_gZ(T*jv`06ϑVUxX4_l*\P N "bkqk[]ea27r=6Ɗm,DmyMa AlZh0 fVcݒljumqj7lCe]k֛ ËFF sX-RpB|:.\|!q戲{*ʹ:t:8 Lc)cߘMifOdcc^XĘʝ2dB 1dչֻZRޑ.|Lg`,ˆza}?mz}n6C5nN~us}T镭`ZnBdv~+p 7Z-{ _*z0Iz_zF1UPFjFڦ͎xX1j{MM5{C >ƈ?[}-/E#v%QRq\Vazѷ@2"`He5=]V!hk%$MSAyfii_P^ $3eШ 4(˲@_T :î($ }R03di:N1` QSg+?F6ZkVfRb%5r4?^W!X`,6Nlpa J , 4a5x륌㵁zȝΉtxNşaꗼt=zs6r4]u)=}دZ?Sk+ME$'Z[ h`p```]AestXu ̌ ֏FH 2M:^E5a-MsbZc? 9$iPQ6F   bD]C}3 1gG/!~dKNC;v:tV$]֗.`E<}tۥLץ GEo-8Dū\+%#4be"ʐ $-l{:@qnYNֆ=O"o\ L2|?s4ySܢgYVTrZ-:l,ަ& źMG4nw8gHg% fS *'/Жɪy k K@6*Js;K׽XZg!f-Ѭӻ3`[7[Z$=o1пL #_`} ht ] m#p@uc (WVVh4wKNdr9x&VY01jXol766.JCZ_Dv뎍rǮ% R>M]IjJR#igmo^ho)˕JZJX#V‚Pvai. J>f7psc? d"%j mT6tb9xdaJO㹸*D!EW*IS' |.Dw|s Zl4cYy,BJgT "Jq\VkjZ-@tXY]MlKo:04V M2#:[/ʵHc8= 4g ;v`wk C/5V8_^aNC)ֺ57I)ֳ -Zgpn2C̟ٟUc*!$K ~NQZyސ]71@;}F/׍ZħABVƻ?`jNjmUp2So;l`CS^,֨htb-8V?6vD6t|Dt pQVbq& +68n>U5[?V؄, J]^^޽{2jkkkA|[߲z"N>>[ IDAT#9AK(TCc^iDžK@=j3Șؤ`C{J մTֻV uUϬW+e}=N(Q`B׭!U( 3CR,<#pA)$46 ƾՑ`CŭלRvYXBDoiiiiuuj1KLW^yE} 0B>2]\ Nt ʴ]͋X^˰Sل-ɘq _DӪA9?qxjvr^jz^kF^T -p(h|a@46&?DHKMcQ=N֖5j4jW^A q2"  A-iGv$H0 ^NEN+bU% ` VȊc>V˵/ IQX '6=,VĦcϒ|O&~hp1/_i9r Q9r,0*M|_j}jZvݭnmnd{^0H4/fB}4 &N|aM@<Hy~1e j5Fl®}цi;́m'ήv!d89 /-;/湰spV `XLgplb@!2F;1Wt.G( *fc2cee-$E;Z 7LQ2 >OZ:nxc:QŁ6kP5}i=֮1J( vt'(QZ5tT}$NE/@%9"4Z3#*n{,&kd ukTljjժ|(OJZ`\: gA` S;¸u" ,n~1Loc֚QBʊdJKǎSaVm :1%Qy .L)zZCMŻ/l% % N*A\U> .H'a(=V7n*M\56 !ڦ1Ī {~`0zx4]eJp.8(=2_NȢ$y2Tɲ/&MY~]V??;w뭷:uoVVV>xϟGtj*J KVe}}NM^BHwtӱ.a@xYŀ-zjmРYEz):GommI$~%%V xhTУE{5JS AR9x {wq>|GM A`3f2y9yZ`8BΙ)a33eu+Zcǎ;&1|h`+z9jrRN4X)94!N0i+'''D.v3`jukkzhs`.gv&DC5r[/%*۬6" P'vzrU*)𫄁2d$s2ZWCK*yA foY^`_@lACgr^>q 9T7IM/[h'rVC0UMcۊM(bІO\.fU-;< <ϋVZ-XzWpǗ 'PD4۶Yzp$/eΟ?aiEhi6N3eEڪָVc[:a3BȭDl-=Oݖ? ILJQiVM2Ц͐ hFD,b 5Xã8(nH f Oed<Gɟ|޷v(u]|;A?9sFfP0硓!.>xjFQrH;ЍNϖd!8. b"ӧ(YKx$1IB"av~ dDkky;4r֌ J̅EI%&|y. 3$'f$wy^3}Z,t֭ۊH7VcCL,zx<]*>fͦ49ŀFYa,L&h~l^]Twx7N>=1+XH39`3l<"? +岄zT.ѲRmX^JeIv@)~j4 / ,Jz36s@? +9 o=6QX.`y"_(/X8E9 =0f^ ӿY6HR{ĶZ" [؊l/[lNd A<\AVjgu~*ѫ+G TQp<}Ry4pTֱgq6'Dx.677yBeˣTK: qTފ-+k.'(ZV\*}'+:l*V[c'%Z~LI%SAx,Uu;z܎;=uz ul-`la#y*~h4ݫҿnmmu=fRNU(e"p|mI81.Jz$ڋ;%O Fջ@~߭y%"+?~r+-@zOZFSKd;ҫ4ɞQX8˅XɞĞE) ,M+']={~N<ߊhgB[*Jy9Hv :P>+{7i Qq -h+) ́ "oT% @~,k.ҹF'U"Cr`1]4jMmSqx d6BgU1ƅl-*5^'stu+>+[H* Y#+l `.@ aG4=݋&Vjt@:%^CEzUm%i]t:=q℠)$]K˟NfSlOkGhZȚdp+rv)ؔ%={uԱmŜ"?iUt]ջ)^2p]Xl~:{{9sF6Yv[ek<LUHQ߿j:r0+|0*@0Ll.&Cp8NݻpI~tד/a.ss΍ߝ.Y|^w ®tgYS r:{_V{R^vMB;[[~Vp81@vKQjD KU3_~@4wd3gΟ?Ym%3OUh!*']gϪݱcGݞm[`D}1G!L5Ahrrx)i8(v}OKy2y|(U.Z=r( e{y}S ѦNKK!zR2Aqn|gYKiAEyͲ4scY`Axy>L4-J?u;q?|'OV+0t=N)9WTmo{;q}A{ryTֆYFQeQE'kİX)$i[ưZNғyBEqx6*h= T0sJ̬PCŻⳬS. ~U6 ڹB@PDHԿҏj12+0^v|IU\) 61 (}: z.$O _zx,U^l6N#aIl2 EH"wav]/ߜd|?~t|O}o}_)}zlfNNK">h<_+,o\#Q!M= $W )γymOӟg| 70YnCgRI#ؖzfiEgiDH2!jgKNKU. :k؄zDZx΅m3 ju  `0x 3. jP!P޸"EkC'l 'gvLc#Nr m(Nw^чG D 9.5Y0,]2j^wb 1ZF`[BTl-m\)q*k+D.:CZV,,_Kǎp.BG;ţB˃VW<7txWE~3z9˯?mbjA5B\ƠU07λ^$6mEq3/yIiDQ}lǎoy'ӧzO}S_*$ZZq\(+J)RITKPGGZZZ'xB0kjAXƹ"~\*aبכf^^t֯ U0xlٸ[ZP %~XXXX[[_GҒݟ!6j`[3aaamU+bL RjLT7[:m"G1Lv9/4׶Rj4_6ҒsM%N%1V3\*B:}mBhY(AM|YOR*1e=$y!%Mz1;QnxS=ATX%n=Q-./Gaeׂy^{Qsݵk޽r޻񃠽.[ IDATomu{=]pKH><2dS#3^HeRKKK]lA/o^ncvZ~;Q4)ťn&IJt2&_y! . Fs\ewˋyT=Mٳg}-.,(ax4u]TP3uQppbΠk r\0 ]4I9'UI)7c|?yg$IZvT**V8$/ȠXIEQ駟]䯻o_~~]j'48$3gzy7|BkLJV:h`u d/HAY[[Xtϟ;wj5 $Mbj#0@^X]]=r#<}hXb^hX>KsQ%%A ֊F#͡QyH~`^4l1G%)&;ᨢEc+ ѪgO/#φ0e3+ƙxg:Ѩhaļgtv"h!xh4l9-.% Č2PS(UJa9Pǵriyǎk^(Vkaql˕Wj1R< =9&5{ujH>ޱ$g覿\[[O?h4 h6opɋF|{nssjάS/6ZWcǍg,\1PYKKKv*,_x& Q^l./_f9r]z;j5fRUi8c:d:vNG"dIxerXɩTxTTPE[Hi!yw~.?+^/M)કJTQYc(*Jafa\vEa0=/y] kkkGm2<)(WqZjKp]aŲ[8(xB7VqJ[ХRi׮]5^*T{_X+J駟msE`5V K0ڑƜ9 2kDs6q(-,!nE(U4M솅X0R3%"(b"s([Y+<=Hՠ7C% cPƐCFCFzZVR\.8` $wE˹6("fEʼ|GK"7p_x2ۯ4Ur y [°\*+f(ʈt[؊F Vvp0[!-M~nh^_t.%j4M__uև?XʋW6pTVj|:b͉gqA 2$p i,ɽo(Jjk#l+z0IUcD')p~gkY8dy›f0FáɕL|mMj!pC(mU_RܹsO=T٬T*Zn׿s5FL*9{ 3vCF;vu,d<ַOB"0%s=wѿ-rFo2X_(Mue(lcǎ---޽۾*NRnbi6TW¤V3 t:&bg@TU¶)b 䨘&G?Lx__yDz,V*V*DQ̉D13RG&WVi؇/ZTn)Ja;\kOgqFQ)kzѰn T u5l6me G깰+CZW@s)眭-JLlXWF'6š$m}3^#!ܽ{ k }l T !Z Y84$p0,ZM"]0@`l$Da؄ A *UhW%D2@A R麓|D>=YӔJz됮S $QߦO?ХԺ`LzH5"Ќ8j߷\\cUNm)t1KRјLƕ7tql5O:b3Bi Nr#`5K6!̩߭+kLh4jڬ- ]^ 55>"h4ڵkՋ&HǓ4+Cq?^x) }Y9grj]>\jL&zm)R׵Xr o^ e~ergI+HLL 3$N,[/.#$̧?{K9IQ0|iDLK) DhT ]CZx Ro[V&ls9X}ưVQEb4 U6") mnmX^j=n4ǃ^o `0fa%U)cO|Xs9΄H@~ہ|^v]T})ϟ?jɐɆh=텵HQ//_E3<$`8MwhS|8ɷW_V]v;=~zL=yr&?+mnnoٟ5uMDIR)RqؾTKE3]1dPxyϝ;w{璷lqq _YqXLyY1IQ.Wk:bl왊` [4^ GZA0wM[|o,Ο?ogXLiy(^H2l4&'nzJaQ` _d3 Q$o˕@ Lul %h&^ੁ gy\_ZdKǶfCatHZV@:P2v:W?Me&*ztFe'JބH6e> &&YҲjbqAC 8c) 6URB?b/Ƣ> *wߣ'O'}dy&i2*Qt.,y~0(<·}\דp[+R}iWbSk "vv]g6Euj3e[X;dcǎgYϚ $ȝL`,3'S犟{HsѥqnR34|[ru_ד$Q4O<|^n/,,(o; UUL#q+􅲀.7!b3/JٞS ;VV$Nz;?%JERj+0/?;26D׌=VSO}[oݩHțLk3;A6HnUr #  )-\A8:?Fo@F0 `L&xEDž37`pǏRE9ƹӧ;jV9˷N>ul< $Vo (|qJSY9Gq-s$QAuhI~_e9G"aX3bRռ \gJ~Y"??= BvEOZsPZ 2~pFsW `ss}Z5j>^p puuҨVY E[$(*łu$et:U[EE#C"YRsٟhmH__;kjU2r #Ҷ8",F`-Oisoa$lu|!Z, :nF&IH@$&,9I 1~4gl{bI"]a-.@PARWjyqqNX"!\.n;(RTei;)F>(f8Lɨ420 $tNiҚ+ï 61ڒڵ [&[n6uyFqa4GPg MݾWH4kjsPC^;@n^\[1 gAX}bR^4VJZliIuTx):زʌ̀W 'oiZa: =DL6H_0tLjЎs'ӭ ^_I$@{3>c 4 H_77&jϛm0K'Fyp s~ܵ{ݦȣ.LOm:([HӴZg>z{R)]zv{Cj5.^i2F0qIT 3cۯf6p4I8[6yu]-}' TaΔ|_d1ڀPJu2 H$#+zZZZðh =iYA+RN͙bJ}sKK0&/ͳg;ͷݶ~~aioS{P[lȸwJ+Niv_agzBqsv6(Bra Bȹ\1wNoVJMn/j)Lm|!ݳ5e >LT] xMklRj1I@hD2揢HEآ%ufI )+WG:ANltH-C Oӑj2`3gt?hMI [pXT+1ym'ύDn/rX5h 5?ulԉ(sRzReATzl)X\qBOeD^(4@\$rG_dq,TT IDAT 0!<& q:A-^7 N~\* aԓ8gTV=JuRtjh a4Ɖ?֢RcRƌҀ%P 汦eRGQF@;5ಌcwYW\:@сF#j2!XG{ڂΝ;Hb7u:\R!ւ߱FrvK-5'NDz"QRR%NIJƜ@Z?D(-3n3Wj#l@̤@Rtt#Qf2AnB%6YW:p <777̵Z-N~~qem'.FQN V҅Gi qV'y[o+@ʕ5+Qɐ$? p,k7]/kSdNwg+v W{v2&w.bKO 1V兴8;7:])R!W!vӘkLF_HҙkYCiAjb=RfBYkjWw~wrwlll/| rY*ϼ۵kםw#|(ip}cþ??ZYY Fc֝CCj{y幗.˜4E>θkE]Bnk/d0O"b|97pa2a&$ϳ0ZړdJu,%G ;] ԕ*)btk;lO.+P4EC8L nw45zيKVeAPeidi&¿zS{myX̛=Q7i)@*^{ur&%"MklU{^'Ov:n vرcǎ7v'\L`_#E!5L0{\e ^=ɛиxK's,ny/5ܡYCq&TfsB':eOb)}RS#4u7-lWβɓ'xj2h)0O$tn:ywqdz9r [th'Ix}(FVlIkmF6?-mpt0\LtR+2"qQ@rՂQ&-Z$I|+9'%4IԂE&1}?sM ooGR\*Xa-tG^h2[,;w'~~/I($Q$T&Ѣ1*D 3. N/޽{瞗^zi̲̗o$3JPB: &qr DX.'%>Jk>&y Xp/aa69 <ϟ?o :+!b4XαYZ-48s _#FV]ۉԦd8c! +8Fg`0nDL1 3 3#TD8dW<ϛ#z,,a̚0SÑ@J"C§^bn,P 5G騩$ĊjA,3)̭ ҭ(Ժnm.)~ =UZzc˳4}ʣ5Χ,--={Z_\\.{Z󭱁l&-'jPKIկ~׿uvj}O(u-y|eee߾}vۍ7F`5ύm+8A"v9jh\R큼׬]IA_wye,n8BlRPhm@| (DKϯpKY2k 3<<_\XXYYmF'|2}yrj$M fqy$Y\\|?L>6T+a;W $,Dygm6*tT^Oa)"t+BN(+ X Yt56VD)B`-~h=|K_,]VakE*Vg fvCA*TAǏߵk]~]l6!i0Xu:=:0짥AcYu,pa{&A/"FèaC13\ :EII5 K1 i:$J]bx@ UCAgϞ>}_T*ݻZJ A} K4M=~~ǰȴks޿F-tdσ)[;xn79Sbu :{0v;}L^ SRlllɠ}u5ZaxE y-͠ Ͳ,‚fy:~#G; =_i)I"x"o;__} =aÞ|0D pu4I~AG鏞]ܺ,..d%Q_(:yg@̙36Z6 0a\aX Ӱ®'OԢRIN MfS߃֧l4i茯7LDI<t7iv:y S0Þ :Yi+n 1 WקTG=^O"AS|٤: DD@`SPma;v nK-F EaOQ匏i!YIYjF d&zÚI SdC N~iq2-ϣR%+CyDZ%Wb' ӧN4[-?/5]Vt{QxniҳMQ}mnn~+_g>S*kHkZMOm6=OBy:ϧ % LeQ+` { ¦^7 J-+Nl6O~ۍVmll\ ɉ;Io~"}a_XY p v,]QQ\P?OVm%0`~V`@Uoה67B ZIi'.͊@Q7Ӆy0=s67s2BtL4nXXX GZ|$^L[pz=FYh4jmh3T'L񂳹4|4Lʕ_Fyx4⋼ܕ~Y@- ZzY/E=N̼LU 2Kҙ;{MTιzoo;\BAjZUp^׳FjC[g'U73g #BEr@0Sp elt.1y2U0s˜P} 'Nعs'zkFsIx.8e۶n!ͳ,EY2#d,6o8(kov GL25ؚm|ǎKKK=t: (,`r$xW QWpn2$!aq;vK Oߖe겒T5BFgyb=v)&p%>̚ Vcր+ e57rV˿}$HXB:pjCS՚i;кDKy:J0_j`im4&bu YhS@}tU+vAzzlŴQ4qE;*FHF6xs XT*w>t l1W_}W o}}?(\l5`bwf5q&EZMKU@B9U. gVrZLXܹs_җ67˲7:E|=6.8 p4€_f*:΃*B~Asy@EɢήVK4 ~A2*TA //4d#O p4~ө i6_0^JEDLh +Y h-]YUW:8uHfGK2%T~cJQ(cEa`s9A| [f.?~}zd2))-sS . =ͬرc\YY\+oMy׍FoۇѣG?-r}LCkE;U`qsk۶\~bG ~$ڛ4,m,a*#h)NSxzai 5(\)6+_zP^5؞qyv 𕀝Q&S*˲ȹr}-éf,)9nR'Msѵ7yQ=Ȳ,3؁@8"n©ʩ{*pΏTR9@ $Nǀؖm95KVKVO{߰|-ٖmuQBnu[ûx\@E󐠩vVS +)t<ܻyrO+}e:_kfffzzڥ莌G9&4-^ ^{-a7]/FqžMa<;{[@eNJ9*v?3ф&@ {1B<ebDP2Y1a').Q&Ҵᒧ/7%0I0}Nhd0W*$epCaGε56\5 qVF䑝nB o`n:yQ.nm(cb b\&I@,-4^]9wvq%R\UvvloΊHHXg b[\+fGS3ۻafąm\X#755u-_[(nkf~~^ĉJbR6߶/<@'v١``'WIl 61t%#.&ǖjVgϞX(G34/K˱<5{ k@lkNN#}@BB/l  j#e;ѲRJmL$i>o}w~w*M)h4&-a 9`wh;v^k1H1CL2e oT k'Y&`^ IuUNbE=0c"rr;ٷNM\=fL?Ih/qFDcX1\2pJfBovp,Q7 f1tqwѵTj;58KqphZ2ѬYFc$~c?=wb+r>^zuA0:+z|[7X}fdou(<}nvlF, bnARcǎ]v=RfHũk%s.\}BW5Z.2%7OA-EkCȾYKh0޽gݲeK٤ ~֭oYI!fvb-X,Qo٩Mؑ6fPvd x6FI4B0b==0E_,He,!'C dC??L3,#)426< 9\SwQ%3a}|glllZZ\ `0PR!PJ#%tǎPf`qŊ`K$ɩSsZ˰8jL)8v*Ipċhg SuW-;wȑ#NgffftthKܴNOOEln,ʾ!%,D`i3+%;BGA%WZxt樝()c`j];wΟ:/@dI|_[t|[Ɛ;@*>,& :[x^ott!M>rc|'mXBIm h7ٵ6!Ec}_8+tGt IDATӰJ0g?١x,/Ђ`R$q>\i;4SgϞ}Grpǎ]F\ oJ l n&ܰ9U] ,d(ǎn nEv\N= 4Kp 2y|7X1 U0Ԋ#Jr٥˶kƋRj3--x\P#/[-4LCO  `?Xdq3҂[<\(mǍ`ϒ Ra`Ë?a%tsSs zZ-^(xv;^S,iKS0H6C_$B;FZ>|v^OW) jyWl13 {8s"pu!Mڶm[|q.:q=2v2]T\*1.xrARP_NӴ3ώ(I+%x# (>b5!({}~eLƎ;8LSfa7c36feΧq]q2.'9YGW}UI-| cva6&,Munxѱ+%X)P e1RR``3g QN(QV-SSG4v:W 4'ߌj$h[eVFN tt:gS&rd]"zȹFo8:RN+^/ESPQK3EЕR>i+RԀ).L(+%c>S0"IHsaýω;`h^Q"j&bFA΄rbdזB+BaH>q-K,14 +=@DY?Si+_!LT6FKy9zZ&]&A bvIrlHanxKUV?<8 A*uĉ>j1ǎ׾666l6*\gw"Ƥ&l6 *#e+++3 gŢRJ>[uz*)D_b!Dz\0 k0v۷o> = T :f-2`uƨ"Xk4Twt7 N%#)eq&{NSY\XDe!D0k$A>*"n3K!$ k3%#yO Ӥ|AR¢{SPٱcG_\\LӴh*!Kd9o8λz$I՚^o Xyt'D= ;qgjaq+9Н0=(^-@db%=^8'A'۾ed2S/kV"$'Pk vǐJ Ze[)<ՁZWv Mc.Pྒྷˍbk@(M OՍuUqRr R4HA˧n^qK.Q6PiULqcR2X^ `0c_ U$vϞ+Me;:Vd{Eph>_]]k׮oȔ=?>22RKRTs,dA26RtԾT8h4Um1[vA_ }sH洸^-KnOϳNƚN3PiF>ϯzNHi=m/F9TkeE7ƘFuL5}! F9B[o ů$ L6qqHya]Q+]w݅۳gȠ'ȍvR$ZqMB攧T]Ѳa@{XcK_.)ar|Y;`K)HS^٤b-P(jĠjn8#WdAMLL enJ??Vu?ohv`[muuZ@xg2Tauu쥒KjQ`f Yd6m%F]:`6] 5ȩ  Nh  erj涔@xhڻ2#ili'N`o{zz+F㊽g7gώTU 1vT*V^a\ rر>/ƘzG-˓&&2'n>1R mEYRV ޞۓʷRtXP !PM_a=%0  :8gVVH(S MP`ŕۦV;UaTj= yϥ-rc1777???==}w?é5"EiXlRٳkkkFahıKjMt߾}+++I V,f- M;6 BrAGAqic1g,&Ey.|[neddÛ6cZ?fyɂ0I 1!1b%dk&R)E6XY,  )TFaa*lUx@,kP7PyJD^):QZ=T=Oudh B#$rQ e2s>ʖլy],LbeJJMz " ֩N8f0Q%^)OJ!xes3l?Ǔ}8TPRMD9T8\R=&p8zc9t:X.;K|/...,,r[*B~7tQT㊆&$ԐK~<cccH`zAMv"!u!RE*@XH)H+r\V͇!֝ ֺo~'O,J " <8+LX#<:3&IS2NbT.=\a- y  >GPʷZsεm]J:11Qj I)|zםNiBv=|s<̰6kezz^c)l[;y͜)L~ CFZ1k\oXjxcq]NٶfdqmaYކ51<H$_<!1ȉ$+d쇱5./Eš`uu֡n˓75oEhREcx`MD5&!hqFhipPtItoƈ8#RAf&eȣ/Gt_n' +TrXY8*?8 q)C\XV{sΝ>}駟64 0]&''lVx!pfffHB|`jj CsYtbJBȎ`7=GW^ٵkdXkk4~Z|6ɘ62E^slR[0rHyQlс֫W-F{=B8Bv!eJOVĔ9hR:m'M7DR9,qяRizWv\w{oSs=U(N] c] -X`W*}K_ȑɹTB\8e=)FF'Dihc@A+cfb  $XQ r92_AqQV3|KBU 9?f+\L=%Š/#pܖQDS˽.r  )x 4f2krG)eqbx=hЏ$ s@$i` _ZE gwy[v(HͰ]_6U B<\oo޽{eei&n8m?uѣGn,BsH۷OOOC?&sE*5d2Rʹ^xazzzbbhRq6,M"\f~HaX]MHƱ'hZyUp!+KI-B .Eu\{@rIA]Mkek?\lY_X wR=STg?\o_W??^\\D!so-px5}4l۶7>y1ǎۿ,GA}_Z7 ]~ vT<tz wjeZ{T-/J AWIbT֬koCc~reH&I|X>6PRIQ7kCff\AEp?cJqr<&v-7b1H#y]liCt'I{@.&q|m(k}$A%@Nff]TCciOw}+kkkbl0aibr1_^xnnXG!OF xCv1!)eTyʏS%SlfܪZdӓ#Y~~s&PQ1hBi@7oت!=jHoO~ (2ٟ CTɕV(؟Xjr(*JXIr{[j3KxCQPg_N_. [uUKjcccǎ;~}W(P )Kg#8;&[`NͅanvvM3(B׸bXϜ9]vuvRgDXhSH"Wd"|/ҕ\\M&~ 0}PIyǤF/a<0/T*LB-D2evch7uWLg2+m0]ȸG GRaGj6L?p2QCaL@Q'-VNCNo 7F[ 3Z=u:^/so.$(YT.*peiP.~p>Y˻y\BQ쇡rP^nBBĽXWc)LsX0ݒふ6UmVWWyVų&xH)@}qyޮ]nz[zNyV>tq3L6(n#(bT$iϖJZK*9;&&&oN:('B##cTpwJÅuB#.kU4Ѓ : І*! 1Ui'v#I8^^^#^ZZh-X 0Z x^(SO=5>1q{k_ڗj/~[s%e4RQ/2UJ${xZ8X?@ IxRjoM(Y""RI&Sd֣Ca~СC@ 8LOEjG>w}w.۷W'&&;$3gKI٤#rURivvvyyy޽UcfbRve"lٲtҹkZ.k.yj'FZAcQL{ B '1eK3uA8|{.QXgϞZ<7 L( ;và]+-s\V曯z ^EDyMBKjDȲ6d0;wntttlllΝ;/NNNjZVq$C$xA7c%`&co>.#nƘT(@2B*6xN[sbj±K d=YwӧOqࡇB[n;zje~F\[o3w܁y̙|;3<}310Jm\5{Y23,ąZ,.hVj_{ qwByZw^nE zBHb0dNc 0Y_2s]rS.Jy{,\. XΈ&OKaߝ9R2mH)Nf-U q9Fyќ -2e߻lsl6ʹc2ϏB! C2"8vp$I>nzZ 5Lbsa4 $I^~饝vqwW۝=7|d̼um7Aru(DB Wr= N:I0avK;\h"2|tp΢(z|Ǐ/ :jܤh7NGQ(G&q+zEQhi\.T*pۢ51䠆H$sss;wA)Up5(Q` #͟"L%CEg#Sg f*vyC ?B + ψ$diZՆ-`pP)NmoPf('T3Mn ]q[qLm.:<:?~Vs (0ɒ=%iˆhyyy||5N߄ L4 fm R2 B! GxNͱ^B̳FQDRz%Őgћ$Iݻo|czjj|bVZ`'Ço:u*Ds\P [0H1 oF qt]lD :F#}QTB`[^WC+g!V3=!-uGLYV}҄/+]Y㵔jIƧB=:wE RHpYᡒP v\~5DXJ [>~8ژWUApȌB)SmK`P~RzYl)E=orʢ( @J|ţG_վ;vl֭۷oD)nOc^;~0ᒔa.a~!vl"({`(+fn6@c04. JS(sQ&[8(FYZ.Μ920l49RTŅb1YɢN1$[=#yxs.\nllēgMG|`L$HӔqȒRCY2H;`"4\[E#dRoCp i'35qD[ŘILO2xyx0tz"JjU*vM oKv}}܄:\*7 "1 K9T]DwxhE%(Gm=w&V @Ƈ#pYƿj^?}zei}9<4% !^?q]es˜4fR2=1GQv|jzbHz/"B)(d@2*׀)1XH~?&lb2.zԩSbtGQiuM~]1҈;ܳ$߶9A_Q 0ٴ gÎO:Q:Q}FI룰Zv4BA 6qcR X蕊$(Bq;v6GMZRM%ql0z>?~ׇ>;g!g,'c ^~~o'< <.ݢw Q-1 9V\,s ؚbwg>}S'?}*;qVmHD2Gn{nݺڋ/xz~>;eI .T0܊(3^[df =t&J!keJ.88(9A(ADG0;ZDb]A1> NVk1X,wRqc i1wdyyIF~Γ8C3J1$ ǫ--gQX컑&HJͫ82oǎ9 ˸T|^bxviqJ5._Tw?nd #P'ukG`mENjɤZ )]K=6θg>;@j{_wG~ ssB*OuIB]E{TBjN6>Ro4|}hăFWTFUT;R*/Ss9kA4y}>Y)$36N z9) 2]c:~&bkɘRVq*@뾰 si{[ٞ-X he ie+m>RnTYX=!`kT*ai X+`f⾛"Y=655󼪣 rlV2/9_#v迴Ȩk@O DiK8DbK?*xʱ%B#&5cXl!&Ө_щ(6RPfU6\H >H*l(fʥylOriAd97rmQċؗ3t KW~jq D&Ÿ >Z 7TH`a(:՛o l-\ByR~+WחZ(*Ry2MZZop 2~\^vO.fǀu.UW㣡-!vb`(LzK?xUh'Hf1㓶,}__;R^aR&-1:5VJj5$I;V.I zmc#íQٍʵvf^뮻F^Czꩧ< v{v9 Cm1 Vi\X'CI^6.BRiJcOBDB)Ǚ=.lO*嘕M"?BuE܊-MMM 넣hIfkqsuLZ}GdrdJv0$p'w 񰖎,SnܡSAIA暜 ]!6jsYVP)-as',Lw $nw:A?ɸoEQl6Qaam ommnn\FwȄF !qEn&ԩg zFOaXfN&Á嚿$Fz`]@ 0 PŢ/wíy3H)0JyiBIE#ccLr |tQfpFQ$l^J)x{.X65;#"Ġx7Wp8"&M4ƠLHS* cg2ey'O\ZZ" [/P6=v Z3~BF͝:KB(ϗ8}7%2]l*ajYVFZ-Jf/ӳ"pf!M@H58*[ӋKJmH[t#z'-yJsj@Q0Q#|0X皆_+++CC$Sqk!yS4Bk4Jk.vRϞ=1gY)c Ǚ76``!tR ~^Ov 7x`)tc9Q-MhBv<dE|R_N`Ut mET M$IC7쮏f!'S٤Jaݖ&V{f]+Mg01A:cؤЙWH')_um)9i%?IclY\u)l362&,%ҮEt [Xc#3na^m>7hnŚv|#pkMGIZp3ġTYp#Br?:5nH@xqcc`ԤEð\.cEVVVK9EQw-[g#%"}8cPIb`bO+EՍX΄Fx)r1p#!cR^[YZYY]]^nD]k^KS 'aLAE6!)UB'EeWK$s bn  6cn3o _eW~ Rʤ #D*LbLvusɬͽ0SRƁP^ F +,̈́Kbmțf"Ҏ9I(DBA4 |T*G?_W*j$JJ=W CqYKTJ 0 |.= (QT-iŠ3Y=WNbJ%mJ!e$1JXɼyyd(8 4"uh9E0ܝ\_X  RJS%l+ntHٱ~ᛂ!q(k ք y P.a * j B\}s[+6UV6M7/dҝr'ˀEg8F/FaƳr9܂vQjaᚦFbRa}#R\(o==Ix˲)?%2"jRPN 9)"^.d4a8"pZm6?ϝ>MliF#"0hnڢJMR$ڬ6>3an9|$_,y'-x7,ƮaK/bHZp"Qi:8%D~ P*6MƔMxC9}/맣4BZhw%i-@򕵱)հhӠ#ItzJS>.cBP4\/!N*JK'`òb0|H__= ت5tvvOY_nPX |P]Z\0z ^~N'N8`0Vve]I\H6qwmc;d>2:eZ,aI3$U0ʼnĎK/ sDHh4DXfG8۰L9ѲS|/770/ah B+JT*!2h|b 3FT~DeK`@%>2ȸpOCHԮ/nYܽ؂6)QӬ1#4.Ն# +᫭e8ppO"(e'H&t.QP.kowK7Tn5ؾ0J$|RzH,6\4IZR)g_`xc|cP.q&\+~xOyKf,K`5z4!\9mp\Aiq s-n,6G&Yxn]Z_|=yϕ1ĜYHͅaBxRL4+{IQjՅ7SJo߾[obcif{ydrH}I5g²CBCǥr^zWo^u;v޽;#ZcUG.tZ i^yDK0#`B/?_mWˇra_zR$K)-Occ kȓ^W*sιjTt{OTOD@63aU*Xd:c+{IhNJ%,q mؙ޵k5s'Ol6A45a 'qa&Mel2a yFqzPY%M]1;~o4ӹVջ?_x3(<& 3ŰZv1snwmmTAS%g67`$Ib)OT,nR$6Z҇HCw4kPp.xRKޡʉ\)6,8rb?>my<&LZ P:R-XNw rL@ 1҈+H*:G/\!j~=a> _@d`cV+,`L5YšΑ%DkK\dPIN0 6YzP3+/u!29C666#P2]@ѕ !z.7cT .4j aԠP([&yP>'tLO0_& V-kuB_Q?6><(*!푈>o0c0-&,@u(J_lYnK jLpЩA?CkHt(`3K8GZ٤SA&ucm5}mH'6 Jѣǎ=_B_[0C*e;F*%4 ALχn&O*'`@JZz$l0zC&T!%r>]w%ĥH)c?Erf&*d)rS2'M5_{Yw'Ĉc\I,TF,Qغ LEY|(]MOO#fFM=~$I;h4Ǐ"3ٲ?p( DtԵ#뺉 g q(\YFi(cCD6k3ĂvXںv[JFb.06lm&gŶ 0jt6>>? z}$EBmE *!Ȫd3,K}bTQOz^*,A/:<^lqfi-A ݧ3=Ȉ[qJL~\'UgA#8sX2tQESSSҩS?o߾{kkk^mLNO>Y*@޹s? TtϠ#^[^^\.cL2U\8y/J299%1Fnlluez2UM {3]5~m4g%Wg(Zi[~b`_@y?EV<~wcyu(ͯYK ]ZFa} _gZm }VzAgvT8%} `tnFw%ɶ*։&φ[ɣ> )Nաy?RkkkˣN$\ZZe%3|SV «ss2dqy<<6qp@Jl:`ܚR?H'%5 OiBvvU'P6Sʣ ]KF駇q@c9<0Tv%-/|N- 譲s=c@Xq@Y9xsq]cG".[mcGTB('dAlELw~ctڝ/懝.=)\7DA`ꐉ[Z-/xu~,hM'LbC޲xO8jΜ94JRlٲe|||Ν۷o(W]B{3] L~^|% ;\ FN(ףdѕ1()fpc Щ9i4###666>я{0K #̳/uᡵNGl1[[v kN-[={w\"Wr G  BvZ$Dq4# o3!s4M_~gq [n_}{lLdR3Z'IyFk#`<Z(&I/;=zq4h4.wJ/LH1}2pe-L]}c}/J'O߶m[lGT LSd(=H͜ÕAjhR:u ԱcΡkT3 ˏ<?O]'J]as,0"Lv` C:`E7qp}hҐbW|% #>"zMphdpY0e!p/666c_^-+DbzedŅ .x`Xt9,aȁ%!HS)tXYct'/R\@>`x 8N[ow#,#Cet_sY@QRX7 c 6\db?FЖ= a E4 .xo8p>YԬC[1faaannnϞ=iw߅oEl{7I!`ݸ4Iܙ> !^|a'1h-*zV(`QKý0 ǁ#VfggGGGLא+Od<5d ;x8[]~.Lq޽{ӟ~_kranttT=::z]јn˯gXdȍ""LH6 $pPT6,1X/Y8C x%F M5,fYxQ*Fp>8X q8 ̳[䊓C4tt%GRZAL`ςaLjp @pAZ lG9!)zș![! sA(Ρ!w26w i>pn;wU*)\ZfyXy+ &R /eiv'iW@͙# úﻥ́g?kZ㓓fsdddddVU*|>Wձ10J/`ðVkov[,KRRٱcǕj+F/4r3 'O\^^n6jQ섺6U1 \/)ʼn wf3Fzxލk㽯y ݧ^>|ٗzOƃFQ[Ga1#5ZտNkV.HC#iFJkno feH8_9.a!Jij1A⋷~;7xvDQ. Qx;G ˭tDuJ4 5M6Eoo7Mf:-~f۶m{~: B ZZJ_.+j\.$(CC _~}CJFCl5;RXŕEI߽{(+++KKK7pÅyH@۶m+zfk׮?+>֐1RJMǀPaBʡqx1 p4Љ O,Zb=O%)E WZh_8wv%TcpfI4D@JK[`qD7x?O9Zl6lm\.ˈ|BjI\¦`z<77wܹk /J&l2y&WVVFGGkx""LV7K8U*^P8kk4=|Ui!$5IbVB h_޼(⛉lϡ՞%sfŭFQAvyI )XY9J g'cR)I 0`g?dC*?s$kZ{Ǫ:Aecnwƌ= 5h!PC 4AȡAhW/ױu|\ن3+fuUy羯Ff,.4ƠfV=΍eYLOzUU7{L5EՋ+Ben kkkc勉*Qi]~xGSBS=!$NV>9+O}j0\paܚfׯ_ظpT"?xo|c8"s`@_issdxI$D %v ޹s^8w\}g766?#z_w5Acwwwccw6=3A Ǻ_ՍŅ*Ecs\f]ܗk69s'$Io4?? 1t;ۊ%d ڍ6f/\4+^Yz)B n>k_wիW777!`;wvvr'.1~?쳛˗z|*d(PuZ\;d#BmU%7wB+so~ZǼTFU[tm:w󝝝k/TU;94V9X[۪db7z$M"m=3eYchp6=|~`׿s]t Ӊ~ܹsKLZe{Qfv^zwww_~/RbIhe#qhEӈ>Ml+ύ%`JB8yY[8:;ŽUǰMs" +(0n[[2`̩n fjJ<#% p9wϚ.OJDkcj,k*7Uj0עp,;r'4$ғyY~_Xo7.\Z`ſhn^KcY1wYJ#RhU a ~R#kaVWWO yPyM IDATA`<=ih\"IwC=-"'&TQ>+W@e_dI=<采׮]tM0`[Y6@sTfkMAo}ݻ?Gx-yƃ g{+W\|~1o~[[~assG?^whʟɟ={~;\xQEԸjc* @T+I%1mdg `,S;- 2$PAO>-ؼ;բV)HdgFm`&P.T?{:|ĺx9 cHVؔwdEd~XW~FO IMqexaa*I IzicjH&m[x[/|;_0!wG<RWUE/~P`rj8R2(0\.LBFzKԑA(>$4E>Vʊ]*&5 EfR? i%Zۤw2D=3F21`/LԨ*-/UUټ;]3O ErFp8#@ W(f|y-NL'"wXRM&Z6]_>V ǚ7S%|ުG`o|ݻ>(7o߸qǠbyY^ ^?c?6~ttt5Nl&ZU[^tVWV6WVWT ;#ibrZRA^~}{{̙3;śr׮]?{ճgpk$O~8::׿~=*tҕ/=fgZ˗/\0 .]tn7@B]>!SKِ"0] :-],j"ȰG6# XB7q3ɑUREG:ǯ4U[,'?JGpͮi3OhH2}S%dj)Cw>Q@q2ՕbS3!YBj'95A "+je 8ot:WzzpnV͔f]? o g\SK";v(һDySjM*=#FpVII$\ޅ/Eّ5B@~._6~|Ȕ~NH&?ñ$~n… W\eY^~_3g޼+\ӹ|۷?/7n\pNUU^xp25IR&(SY1i ùȌ(p~r9 PFx?c5q.$uHtft04,m27!x?Ja;y몪Zl+ӒRi-ԒXCb$L ވC-eO~[^ kzP I,W|GFM7}ku:[Íno埻x(dkyMY%EQ4+/]9|7_8GvDJB(e*nx޽Fo]'v]Y褲Gv-l\>CCtأؔ!YfL^e_o|ۃMf3x7ʫ_S=($Mi㲬xX[kV:ʼԓmr2I}Ld /\zOݾx;ֹ}zZMgy贋A/y瑫ֿc_~0ɍZ|^[N>QD3߸c޽{ttt4,ONQcߟm S}x; dk׮=c!}{/޽{l.m@DPk6:N81UdeUUFhFcuu'򭛷ϝ?rқ[FNLnn~t|,cђi>`)(Itzڵsl92`7㣣_|K_'>_zܹsgϞ侠s_6Hzo}[gzG}//O&ͭv([nWWZxQ_Bv=[?o7p&aGs@Xlǻ+s6)hT}=ҺaMWK]1L9K/dѓ8rAY-}h9nt5+_ SIdP!QWYgΦߙ99km2?bY$Iy٤ WL~FXyCL&w޽w޽{vwwFxn픍*7xg;w? :L䫲lvnuj~x:\p![5`N88f2ЌM%(:d|H'''x2ܾ}o}7y~+_y[hT''[,-91UUU4Z͢W4:Vs^Mٯ gΜ{^ RXh<"̫ϷZ__{_QE毾>}񭻳L'Geը:٭yRvہ ˗/_+/\KZjt:==톣=?3?ɧ?ߴZnp j6Y&ɕ uʯ'[Ud>ߚoll 76Μ=# 77ܹBv;puRU~x<hh4.\0^FCYQ!W^9>>yfV iHPwW_=88};wݻwpp0޾|2EP7ܹ{͛71V]`~ .]= nص5%^Bbùu~vƓ=28$>Q 0O MNC!K&SYo:-[L͛7www'=cKf@2qd¯+ϵVfu=뭬I`k'SP9 K"6^xׯKKT%ߋFcɨi K#i]~?J/byVRzjt;ݻWtKZ}ܹshttg1'h̫Q'2ei%՟$XHnYVf˺U}:;wW~W~'h믿'Yk?VTecՓܽ7Ε+WΝ?O*U$i]ي5Yf4޹sW]ڛwuz:gϞEp%l%۷x<&;!A,Z6ֽxT`0iZ/3{{ދ/ҁ0۷vK5{jj4|筿Ʒl76l*p,Rgz,0EMrq}sڮ2R>Znc{36 6b6v_|777K%7nmҬؕG777:mݕR)p eWĠ"SHFi015EѬVzf5+v1wuVeәN+i;uaZIhܾuϞ=?o۟|ɻw믽t6t>/QS 7YUe9gRnJe٨E_z|s_LvNŷ0Df>W [_n; SU7j^oss{J;R IX)i;wQf O(zxysP\̦erz2/xo>FϞ={ܹ ommcSFVE4)JY&LۈzrrrrrB3L: VG2ʚK{0Xj[p+QloolPNrtttppps]ržh4'F# II~a`p# -H"DIQ5J΀Jj- r&}Cnf؊a܇l ;^HʪEM>OOO rf*Um&a\@nzO"o777n{eXdΗNܒETDW1j5ɖnN:jp!J))=/aoo`6F#?S?S=y"kwwO?4GՍ ٳB|ԁL*g eۻqoܸ1~~|'C[_e0GK/SOf!NVxP )0OʹIcz[n޼yw*p Hd\$rѰ{.Rr  |e YaqY.ˢhu:{EцlZl4f+$z)5j6[fEk6Ԩ0lV٨fv/_|px=y`øM;dYOrP~p&VuFK5)yʈl>-'GɽĻXKp餹16)_ȹ2 vT#6rĘfRRu촀oQPMy#?1Aw࿪GuޅTfY2^M/Te2րIR~,\]a͋//}'~'y%1k e',^\%sxxxƍt>믿^%lf>;VcCuͰ]g긵P][)jMkm=a$WVUQU`!ͪVM!Ŷh4 @n:6Y@6#_)N_Q,28|FpffMnRUUB~Gz/So1@lS6UmasdmuT"|:8Jp</F@RHy9+ &"D1k)H籉lDuαkF3V0NёJ~ؙ4 c;e*ZORO.-$*|Hj:'~nllPϜ={ֳ7$C9AOA<OؾazCB јsRg4\ګY$:M4q֨N1/&sE,^&5ufIfEdyfnSt:٬9i@au3'ia fލTEm?$Fh4O? u28PîFQoVP@}eYF#~H"J H˷ V>.&"v!MS~ogrX:==c^n$\-\ Dv2/5sClCʁ𺷷;X>`8pQ/V|rH'ޞK}bl /8rrzr> M"(LjóQ$SxOWWW9vXC 3/`6vYe^V9ڭSV0( K\feCHA_!Ƞo_OK@ׂ+(xw]֝dק!h!/'Ds"+&>*^|hįȶgɌ'5 K\)b9 X"cuoIfȘ ){j==|ߒffʖI߇q3/bYIS9m3No>3Sr4.4FLu<2k'V/le(W_u25녧#ekU!Z$~iD^l¡I Eh {hTW4z>+  f 9L/Kf[UըхFc>UCEfueeu˗/oN&pK!jza4vð|KΩ$mBt%mQ ƍ.$"n[uk T4_7Gx}[gOGNip5g<vLI2Y:9UedM&04Fd8vꇑEY*8+Nh6O@YV4LJJDyc"T&V,~]p9]cfUe:%e]>88&$lQ@C aAtu`ϙ%,uJ!Z 4Ͳ(B[:  bNMR>ק?pSg6u},YmLY%&plne/*˷s\Ew3YK%vB:uNOOy2 Ma$SBcs㠭ĂU wZE8Wks(]1q2߼[BP #ϚҁTHO{%=e^*KpQMNqoOMnurrrz64FU Щc"yn%L/eYʲ'rrB@nh4 AU: ~fzzkw>WSf5N۝J7Y.uꡕfw`~ԬmxSB I3%AOK+STM֗EAx)䜲&ʎőOH3HpΎµ:&gprĘ*';?~_'ܨђlXSJOX`-E$Kp)˲(EVepezzuٚե  s^\AI-”((YK)vL ֣Y0Mf/OB$R? )p'Dq,Y'5גlR{ %RotyA3+\+-%Byg%o3&M0FozW&  R:LOO;Kw5XJ`} aSUOk}l֪uq(iQ8߭S20E.#|F%sE[K@Bax*SeUka : xe $ =vuR54e>oUY*\Ʉ ̙ &gւĻU沮".̹cyrաY:Frʚh}cdX__GmcӠ|ĐlaHr`W\?erDTE)'{Eq%k?pNi8s?AIM !A%]f:-ɹP~_+ P4G9(a),0A0I0r‰8 xªZfɶz(ZInEq|r2|vUw:vl;Nvju]%qE[Uv,Օ(ڰ;^n=yz<כEv۝NLYf]=dQtjfQzNFՙ2gd:Ԥ'[[j&!LV#N8JTWp5^-f ~~^ʺbiHXaoS(b&, %5\ 6*?)|T_~09"yXF3\+3X~hllmQ)uFA3*>z8sp%FRWVVY2d{2Qf/w:n[Y)nnڭjϗ9X[k;Ȱ$@VCF~_[\r)(O_]sψ-N nFQ9O&*%>F#o\>!5\ZԡȡA+]ʍ悬"E p[I$s[f8p@.7ݓ|#By{@P\ZzyC^L'> U:1öE3dFO23ii^YӚM7W@NN.df v{++UUM1|eYFpr=zCL^oV+P.fM6nY6u~ xF5=9ԗt6k Z4':Y%,yUy۝Q t*Z΢/fը*f?N;i|/UQ6 i4Nd<&IS5Kcv_渶I^B z~2c ^vJTRN isԙfsclw:WU5==U5el:4ʪ*Vݢ(uNNN^uL6^ަʻt"~( T t:COFu{IP7!h,$ΜӪqO }N\NikřԌn7yN-ydśC:㍊صZ'.@M1NwUmE/ "|_ղO+s.ght]`*DX P*]M<>V\4n ~;Q}Oh6G6Yb=>6³fla1w O@ȮeO!kJzd6YӞ~$G | [kֲJC I<ɜyuJ+m 0K|l2k _9r̈eEL |H8dT@OUJ)Xݨv-$us>#Ǟp:asp݅c9iؔl~lq)lwb4]p\#C9$N*yb ULSSw}@R9x8&ua{]eg98==-r̙V[n6٬ϏON8=9͙(:.l{FVWVf4Pg̺8Ҍj5㣣d-*j[p?=9>< 6e9EJ׫ogciB.b4M&F 9#Hʼ)?dDӎ>ơWӁyR+0ONl:%W+:ҥyrz 4H~)vӚoۚ~;ydV@ژa$uUdʘv?ks $ASRj6Ƣ v0SrK&Nןw r}6s9bLK7-՜?p&~}?A;B圭u=*ޞD'5:5]jց-K{n?R.;JrlGSdL%Z&m#$,LlΘY YXr %?J$6nD;}4&9u*U&c} x+c-i9Ԏ w=EڸoXTaIdibd|1 WWk 㶰;pjJDi<8eط)J{+כkI-5X" 5l6i0ՅlЕgaTIK] Fג"8ZYrL9 ˞ȥ}K>wJ5b<Q؊UC_mLf{[>)صԌ:88FݗrCUn8 E)=e*lDh`({XF Nj8˒!tg0 NEypN+L&&rSLiL^b9 Ҩ%uz؀PdooO#y龲T?*L, (Fil;S o&\,#t+\X4M v/)\|.V%1D(;LHcI)cB)4:q2Dz2PL]2J:(a!iLE#'\3yr` z ?ʌ`x4>?[RYF6 ٟiE IDATQqke9|}+N_-` }ѼRDE'T6Eq-@keCt®˂dfJ}J6kԒN4,;pyegԉHi8[BT>TP}vbi+4/6L5r5?m@ShA>z u$F2 < GCc7+J A3j+sUptYW,Wb~D˜$ɴ-D"ܺ{fp'1r,(я+l2󕍍wlmuR?Twb i^Uag(٢c{NYPZ7fk»$OaRknkHMGD @T߀~̚/;"7YM7r\:'L̜[lmvsҕ>:t2%[B"oV K +nĴt)XRj**NuY/f#kx#NP@kvQʤ[Z"b4FcD mV6Yͧ~nʧFjɬGGiJ@I9|.WNzX-!:(!ZBSnB@YvS-x5 F!HTJq*/)ꁵ0SsI94S#9_㰒{b8=r$۱p߅7(YPs9f.(ie~Nf҉)HCrZAS^{}q eQM2sFXSzV2(hXCqmJUUcu/it_cj)n!U˰e`$Yz/eVYr1#B&(5(, g$XlTSӇauh/id7x$=W[uַlY>T@17rKr,K\^ul>!ϣw0.{5j(ғQH#B#YkXNٸ1ॺ^l3D^q2MsYB|.IO9kH43K֋6zJNQ nw0h޷V w`d+HfJ=4;%r^خb f³)IN;j4!Y&${&*cANDAf}b1Dg1 |@{Ykc2I[K$##677a/t&V  ALQR{^kkk9U,i]Lk}&+hsԽU㏏5 K?~o.¡H-b"PXĦ?'^鸩fθa"_7<@5ye8 0maRhk,b:?kB)yR@k0RA݅OU@I_RM`7c7HON֘D]Ðo; JĔ]ʚnb<ɾvf'QZ"T-ZH]?hi|j麗$q9s J:e3{%@`ʅ/$8 8)`TK=SI9yTlͧJGƊ6jFƁ%GrFePymset(m&piȞlj8ds K.s*xE$k=?D<>tԞIu kB&!ZiěN)SW_MB}.3<*+ԻZٽEGI7gA^&R%l&ӔEXNkA/ؐ[9Q`̙3;|ci><l h4XJs' /@'<,OWq .e:[VWWU!njJPڏo?,uS"_P?9ũy iL6MdkMotFJN2[蹐@^  f.[/NWJ'TsGr"#S2MhSH tY\m?TsspqOSMŞ /e{ݦWNsZe8eI1q-Ƞ2˨Xw=mk19*ZEQZ**oaI o6nB 0M}F07ͱA7{}Bz,w>հoXXU{|#Q. {OÊ47є) Ŕl-`"F>]6xjb |Qd܁2D4Nx#[$6Y՘,cErx0M+m~M3Fʜf~㣑.JR*_vksbۣn$>¥8!?; I~HyV u7]$LJE<,ǬZKС5J΀v:txxK6z:U$+0>q>SN:0&w(o$ Vq xE,;Mcgx*yɾKS@7"|dW$/B,TIKw&UjS,T H~zvnh7]ҼsͪފL%T`7= LýMb+x=Z.]E~͜RaDF/ <[xXZ##-&2wTZ29VMh9\$ THӝJ\-nB??>QJ.WH + \P21av5kx~+ 68n{y$f8+9Ϗaw X-W"ToK33W4})Z%g0"&1 a'? Yt4gҌTYMy36tuOGBCY [K86M$-*|#3 5k4L1DeD^]p2˲)fp8yǐy6y(>O6SP2z9eiޠ@JNf2$aT;e=fy-1_X ;*b9eqm#tyދ@ؔQbޯr2֐ԁ,*K fOa=]>z^ͤn"T*cnIjEHhXXѠdط.M@H;S)a) I 5ՊmS.K.B9|<$a<]mlYN[3XfkNq0Η9$MO~^qAc WeQš+c9Kq0het]moCn&sI- ,6::ewφ&Iwiz~TǼ a)9՘/05oMΞ^XV:ñUTQHȅt3;hoF=ȜL[(aQڜr̥ӀXA(?6EgAJ!mi'ś#yEIA^C7]^t:xz [ك˼ʍa'Ă$MZِʾ3h"X&h+ 2HzHk# =IXH.uve'y 1lhnW,5rWX)O;\rJ,d1XdXDz8a1((E%*+' #UyWâ*-%R*]&31tצ~n^nbol$Ӥ,yf?9[fEHuQ=s/7*S0bMp:͘MБ{uysm- tSd+RzKx9~xNt 21& I*Z(م\u\9/5#Q .d" FZ;3 ~P;Bd.8s %KGx[?-UE5݈rB %V$[Iq!~N1@Wh}RuAgL3bHg*`t٪(~h )yNxLn0i<h:̜]ť,JS9ےX Fd\Kfrp *Yakऒ4et7 )L4q I֜pϾRB;Kya-  *45G( _c -ZH="2r]PJQ*h ; )BylV}^pʲKV|s9ar`׷3-oɱS>aiR0lYr7$**4Y1ҫK -{mB|;R XyZY]vj$%t"~h*}9)c,2g, ̫.%"# &pXز]e`Ϲ} I':Cܐ$Q<>9C)dKwOɡѴHz߆ Hse%x֎dNm%[<ژ0Vބ@abވ ?y{,:x9֠=O sy1|9*E2ϩlmZЇ^*r:^<%.jХʭ 0|r9&?ध$4 r#˘YOhI[Y+{1GJE;缌ATpR(NVa ^ogf.g7j$s'  S^Rd z<,:+)%f6HvK'B_J!p_9L^.ypR2aG;ͥ9H^NM::j``\,)5 KC'̙ HsRnŮ*Fv \;h#%rm ~L] = &tQlU6*\xe. ɨ*Ò%IM:5?vۆbuKaiݷuʏ}"rH. ""^MU42gH2rDPn B7Ȭ ^$c\$-i8vM]dvBEG],C fd ҪT.l&Aj0S/AiWbo].nK4)3ciI 憧l/h k"8i68qdS}v,! Y/J_-ӴrFc+F` k6gfLS/u-)7YʧsBCEe^mJFɉSR}Y5%ޥPgK'G7SdVOxXCiRNr2rkR|]oo#$J])U`X1SOwplnN3$ՇcSaܭSNi[?:_s-@-S$ \.0HRQ*3ş L2ճԼO@Љ6:"X*J䰳G%@[x̆ XT_̽r̗gxbR xW,`B⴩xflYFDP]'c$HN}ޔ5ĩU B,+ܓbSaeFjxD@r*wfҹ{'*;8vL7?_G8b#l`9}:S IDATMF\vlxidF⚤nKMA>`gN>PUɃd7"w\Nt\ "*ڧ0߲T$dccZv5HqHdc\Ro\Kt7=S\NH<SN8k DUIm&i/#SoDw0٫ aϨ'N%H`GmЇ &&>{Z&,)(Ί#|iS&If噊v:Կפʽ)A 41-)VYp nMvl)cSL"3Bhћ4'Ɩw4J # K52;4U%'EҪeuX /n&*'dC3tF>OTMџʨQ*~NGLbzt MUɹ-38)16CV>_j:(rN`K9}z W+Bf -I@%2 p풥)y_w~wRK.#vU;{WY=kCnUyHgq/Խ8%ѥA-1*J)l񷤧b؏qzzzܹ%Z`;cPxMW1YXŌ ZG魗1U>v7 yv`l!q*DFKFSg^ (rISեy^ZA}Vo(XI6r݄s<# e(mfliyVhyR|ҷ$6z%^US"@z%]X-KF[?)j%:Nݻם:N<V  \#i[+$:/#0m _FѬdVi>IclZ[x̩1~d#(e[)ScïiO@~^JdHTOo7zתw(Ls"ٚRMY֢)Nk9Βz뚾d%DL((RY4c:/]C̅'H5Mw݁9dY0gxEG`9Ț-brhI7$kTYr>4v;#vH3Qhw:x;ݻw˲|׻v+;kl69LeUeY8N qADnL{S[ĜcgbYfi  tT&uPO#AӲ*{,sjNԀO묻`IgssUlR6 ̯$9ЉB7KV ɦrI[Rcځ鳏_ܠUxɛmV,p;@OQ#5MPuQ,2LdKI =qosݦ%JT3˚1OR}Ό.EPqgggg4:dzw>Ǟus8VՉK$bQK]Vo営SN?~n`Ak@ ceX +\^,Nt|<VH$`paaAu6|5]Nzh:D97EgKd2N#'C` FBN d?/M['WtD)йS|p&#Z,]EPu")DQ|2hk{ZR8q8qF~.-D \u`/P4 "0u!n{r -i52Nڹtu$qYp7'kF}gcZ>R I+;q@'F Cu.ڲ_P]q_ar!:/FwZXh5~Ls/bάLv}x q5C!s@q p%eqHF]2GE闶"v?rjQS)NWmyy1lɜ"l~+?wtt>|XKl2Σm \OKf0ߟd2LRbT*R)9t[&H> x%d:LU*L&CKZnnnX,F6f+]pB(fD";rIU %Bw9 AV BF nh R\=sZuP(,//B酅YwqwZp=;7猨]ra-DE6*Qe6)DQR Ѫ18,(|0~>5EʒD"~)HgsiTY״dp D Q"}Lf0ݏ>6 =8_ASwlm0~~?m{{{\VD!8]TjsH©XD,r1tŽwPݠ ͝t'rֱ/gYeUjU-KrBC]XUPKG i/H y> m"y %:LoOdHOTm+5CƨOZJlj䷾ .>}ԩS333ǎ;u?fqlĜ;wNډn$qh*q{AE'm]l葏kqqo. Bb?L&;::P}҉DęWGw }q"SLe2'Ɇ)]d%=΂yNLFEV ccc/F+v[ 322J-eƙt[$M߱F ngDl`)OLLW+`(ڷo_ \!-GƵBi1EGb;Lw](vK8=љra7Aƒ+W } 9z%ç%(~oFb$EPMɶ'BTs G4 6 V)d3A+ h\EM*.7N:}Nqu6 5C"UWΠM6'b+8ΪXi"0DbzssS YįhȩnPGFp05Y ^L`:i۽F9 @{˥777S>Ӄ ,) #. GfBy_yE\z~ҥ^ |FeyGV__}_~Yl*d>9  8Sx V'.uҥh4:33Ҳ:88r0_ա!B-DXe`Z-,@VVV4<'qyyyaaazz{il^{oLy@Gu d~v8E"/_`0X*fgg]Z^wHfidt4H[sn'Gh4J7LyppP\( yǬ7>HItCa"P(TTAi7ąPAB14{FwP!;*=툸hnJH$ )6;58kkk0nçb;[ `  :T$Dr\PڸZVmk|3Rtd-KAQkA>;j]hCsX\WhS+=3J[#E};D!p0(՟K9aX'[JT"|>+p;AI`:npS>77h MĕZ|Q|1y~n}zbb"jʠ$MOOqL@V+-WHQ _t#L/]\(zꩻFg4D"hʧF[0`2:AYZZҗ}ɓÜۿ՛M#'>{,cpjResѼD$PhttcbrDN_ .DPp5s@j M{1VD/1?žӡԊXa# i,qd5TA:9R%<yTxA{=!4QnܵWcZ>]%N%xjptSU(eňIJ;oJєCJQhS/O)F-ú20MN ݔ),YATx5)DL0mEt(V"bNJB$ 7---ueBY@Ifgm8Ki6O8{ 4PFDugK:C2G__ݳ=WL{ۢwq=Aw -=\5LV^wQV*nvIIM- j걕jpkRptM휙Z 'pa`wb篿kd*< z!xD:m,o!`sX$Dj S޹#.zY8EtRfggSN'9̙3@C=NHlS1J`q)J-Ӽ޿?uF+++Dq)q kcsPؑ ~Bϟ7;;T,;÷,veԐAOq*!j@"|=l.s;I t0G" Ճ8<^m@=[]]馛ƤC.B6v@Ȭi]`c r&`rT[jxPZB4jWqPin+N nƀliޅYN"LjmbX,9=QٳSSS@ Hw|KKKRqՒj5C;UdNe8ԕNvHBs}%ʐ`U9)hg4"A=X˨YHff)h%Sʏ5 4xgVخW68hI\T*1](M~Eܱ|8CLM[C=F }4%!be&~FnxRL8UŻx&evP+`0D;a9Њz[9ՀhT |RTX~B+ vtʕ!FENJZR0`S=u$sf0J9V7O r`peyei(K2@w"rcccjjJ[oHO- Q>H;md0`E]S0wRխ;3\tioo/ɰ N<=T,3\4={e\ ktG0Q Өk鴢M\X6t$H&38 ,}U._~P(400XÆBajj^nE9~qAqUܪJRdK_ѣG%usͥwRgٱ1Un'\.@\J&j\/Bc t_y+vuu% 6tja}gP$FĆUY* Qbai & %M(\C(#+ lÛYj 9\RX'K",e'zZ@Vp3hĉl64@I\MNtyyz$y(b̋~ewww8~z{{ .G_uY\P@ ˯y]HA S gΜ)/^I$HdzzZKOXٛoH$zzz~tuuuuu;u~~^U"ST3ψj0=CrDŽB~}}}p DPs1:Vʏ~'N?~gv@KAT*N'D"L&!b¿˿˯:DCH1듋ntT뻁y$BF gi5AJZK:^.!E>1Bx擼.DBCn`CtAv 4C>y0(U0p)^ [X 9P!ʨ 3IVwDvztZVb1WL@\N3MD/U7kW##sdBc@lyjGwu Wseo\NQCa@ߓǭ-kn < 2_ݿ#BGQvy\ZRq龾hR#`cJb#<N$qh \٢zpab(Ul2́b Fgl|>_StSS^Ah潢y2 ꎷC!L넞&}NFWWWz{{2ٳg36L*z:O>}AAǎ;w jwjDh(e7Y٩V̒ @ ^GbĉyLЄJ&W8ޑ0$'% lR 4VWWVVVnx<. E͉ ~*Uׄ766b6MR?uG 򜠰dQ"჆7Uϊ^Z__^%Ac({׻kx:@Ɋ&x:Q%%h#h1D)p -ra E;`ЍҒC\0= vcZvN\Օvӟ4(;"O+8)]s!€N q צw$%n" CrVsUgH>zܡdMC) uǘ}_|ř. ~q%ؖ~uT {:gYׅ:sL>gjBP8:{T*pʞЂ\  L@nlkk677|qx7*c_u93I [8066 iW6RXx'֎dt|*؁9Юmt8].-M|xTյh6QѧI%HO%I6"> glJ~7O hi=MWqh=QE&UoN렶ֳ8G~\4elʋ]\ӘLa.aK6YIq2bQAkrrrrrѣj_};L*u9JeѨѴVp 5H{#X@_B_}W> []jleJ? +-mo !zLMM k%Ɏg^VWWuL& / ~r7xc>okk,WMO-)\J{뭷/,//Iqaa'?x}AB86.YS2tjRx xwS]9ϟ߿Ƶ_ɿy* %d~;Dr9)î^3D`Cݝ3Lww7HKKKXx /]wddsss.d2TyIj ) ѮߖNh@">(%jG ֱ e^t̥҉/BH階QW nP'c Cߣ_z &nal<J;k ^*WFxD{cAPzd1aPD8V{I?E ᣰ) %le+L0]BkV2'U'XCKxI>6Y潈g?#ņ !0zT6HVՄʔeU=(?я/Nz>NG*h5ѨAigj/^re :4p8ohV1JU*˥Riee)͡e8Aj~B kUb\C@B) qWECIO'LPϹ]~s(S 01> wZPY)Pz9&P]BvƯE,%H`.7t]1lKź8'hStI-5CIKى{o2 . AˣNF 'b0靔 /H)aǀۇipms26_H0ЯNtZ~}Wϝ;W,x<)'6|Ȯ}\KT' bV&DΝ;ww ]>]z.$)5@G&h),R__߇>J000<33 \Ђx< # `0xwb1qko3g_s[{ujøf_:)ݳDLSFd`ggGwOujQrz ,jՉ NqfPIC[B38=9uԑ#GZ,|GL—gu`0o<3br}&~h4ˉErV* &zǹ}CEw6uPKEP@(E5`㷠7# )E)F5)ѯ$G%dmm /J}@ϗO}R) Cq5'ߺu']Q-abJftZ[[-.jUص2X,VTlq`!:Jȁh`7k<]ٙ2* G.ڻ.666F-WaK~J=KE@ZF|R+!lLzqxWP,{њ{Q<\Ds7ޘH$۹@#͇(HEvFm0" hOOO-^YY?;|p8r*9_z8.-//z뭁@78z(Wؘc@__߉'&''K/]z3<cccRG-酟s{{{yY 櫵Dp>]>"InX j sq]LqQuJ[ hXt=00mGbρAxsgg&x2oC#‹h^nnn&fP1Eޚ_( o<*ip}j%( Ao?g(dJOr,c< dr}VSFpJܴ{E[g!u R3gWc<-$gUtJ!@OȕgB? -!KτY/`<0Mp_S (MC(xTGeG· JSD2I|. \Ќ.R c/,,p]) xTBR=1z7~7|3J}Vxw>>lowW'*ⳏ>AMV xs ߥ%RD3coqY + y3 \BRt=u B ΊTT:}# _x#G IKK 4Ѩ`j@drK 6\Bw_bFq2i ;om0钬ccc}}} Ѣ9 ΍$5_*RT:nmmJJgҗ޸J)j P.< )240.0iH;.>M!ʉcvݽ9= ᅰ .ΝWB+m (XZbĔRN-UJ Қ&^Ҕ$뀁 6o3uK l: x:YFZ2I 1)כSFupeaLF 0*XɆ"^_"୓KQM]©.JPC'IIQ&+3d$X R~qH!Qjk Esg2j ,GGE5Zkkk =@7G[)_xZgT M)Г>1!k̹sLx4v뭷|͕JX,4[hr---i8.[{{{\ɓTW^9tFŋ<{l2ܷoƭ''';::TSFǐ[ ((l.Kŋ3RteHtF*_K. {JB-r0ը%!&u6ە^:A1RwttRÿbh r#O!Glii魷Rfwwȑ#h,x0;=RW^1_Z7#l 2[ :; ]= B\ V 5'8G@bHiy l0v/Ha /M`^+W>qaID:촶Ńio FN(6JCl}}]ę4IЇs= t-y!R B'ZZZ7Ewr81occLw$%7bP m1ǻAsp=ĘYVӡ7#)7B'PŽ!^R))9[[[SIw(8̔i a 3$(th-!(@ ȝ%+7+;g-auPrpr\*'FFFRjYb[Wk=b]9$4M{@ pС'N4+ϟ?/㥗^ǏwwwGw'Qק ںؓW9%a˾֘3{/VLPHɞ>wi|Z-NW*QGG#7F ~goll PD9Ҿ*(In@=`rD,YƩ Vc[2@ "AVT*c=c=R) D"XHoۏۙpt&mX,6<<<223::R*(QHnPQL؋""U|>X%*#X![O)VBΒ 놫eW YfQc%k`GxGqhԅl>Bbۀ3=6qaN]}"U>;QJ,eQT.𲒂-Uҙ;l7<#Zk[\.EU@#J+ d+5; WD$ԓ VP!haa0vDGC)Ez4SQ?ԕ\."b2CN'ճx lZEx3p,1 나>I}mmMAgU{*, \ZivvvD[iHe~΋/y6OLLDMWĚ:%|… ===T\. \.7>>r…sss###2"VSuE2mք!>ͅ1EbMQzN \njj:qD.ӂR9ɖh^Y 6DNJg~:_5)p]-욛W IDATgsqaFѠFrIu贑H䥗^f#bee"8Ȩk:tH45Rbo8pHFFFnY `0TS~ygR]=E=awb'f:F.+|VUE_8jjjƒEuBE,A$ү3B`],d"rU*rP^~%/}=.DxA7Bi޹ -EEt B{w@2A %2E c"- =kkk1B`77 a%T9wR4,\E9W{!NdfO ׆Rc:e0!LVGTJ)h􂎊Ǯ?ZA,*/1O@(* )nmR fHzx^裶V[[ޞ,]nL Jx1򦦦z~u^  Gx(苹%rVVVz{{t.koo?sL{{s/lmm+Q <@(ΠZs'iQ1# `H$}[Vc;;;ȕ9u?;;;jP6xެ-uǽ-͹\ T(\r_*azT5͏2BeA4;>>~% ?>< k~3bQg 2jxJ-y onnd2mmmx<Bb3ÃBf鴏Xe(07)<'6A>Vu(BZtUNY&\lmw!FP·*x @b *421ɤzd:z$h!tgi1* e:SSx Lѯ2fAF) k bEOLcrZdRB%.VV٬FcHi/fDa].ݵi(K)H$#@E` [Z<*S[tI#\biicpY.IET95 d4THk(clIvY{\)UKR]pamm6T*'N~yv<>Gy3kkkK}>4q[jN|jr\ ig2xc80777c̋/xrN3L^|ɉX,8>( :<U%=Y6UK&wonnO~2>6 @nnn&I&( GSΠH;-91K ٱd1 &h/qOC +[pZi2`VkU˥,*Z+IW;ݤL> E/N[yIY l$d}t_hief'*z.e)&RLHA9#Z\W/^U(1d'0QkCWAqRM'^:a1葱w|P4Q(<W?BP(400(Z3wtZ[[/^+yU `0ҕjDj`3Nq,ٱXŋ\.J9oo5nMgAD 4()8ܔ1 Bsss{}}}񬁬677xMoV͂|hy`";V(ZmmmO< eWļ@\NgNzGG 1cwrfUPR|'s$yǓdOOO$ַuM75X9N&@G$=-=RFEͧk1J;LGٙdY3& '#6m鰀 j&'Q>4xD' 2-5@a;aEkk+r.QH@b;!eN ]jnO +!_,777;;;ž,9VA@tcC^+:D65{x^.T(eZi RIY[VB(h2h\9Ѩ֗Võ3ї9.5uP ZúuGP6^x68G5tE}#_^ "v)f Tu/;<A% ###711Ӄ].S---17KCOSV'ϓkC U} #Mp)4`(Zy&8t$7~EY BΝGvvvT0|-hq팬xooteiS^|O|Jt 6! +)Jiꨅcǎzy{NPKK3F4ڜitY75X)?VB M;_nȡ.? iYh_.)`<][;>/1OX Wde#yJژm? ʥM^=/ÉHU/\`m2!)\B d0땫펞,PȂl?G=w+ %a)Ye!jU!r:>T#' 1J ŒȂ*~^{Mẃ>O ￿N&Y\]K_ފ45IJA~!r<`o\ "H GpÉMQrjx訧'Ov 2 C+yN'7!J"J*Y5 VfYqvuМMt!]^B,BS䄷l#666R: H% Gi: V隡bQ.u+[.Yeݩdf.)3XiK5(7ۦiw6ZE1-˴iYg)(u 7#6a"ԫW͵t!j3 > ku7jȑ#L)!NJMȖdZ(|5uxv5Xo BȥF{K֔m 7;:tFR`zc6|^rj i× ̵@QwfԊ]w#8q{ﱫtE\ovwwx㍮`YEO 1 OS4#|\.7Tڄkkk.]z'af} ch KDICѬHCCCpf7xtskFGGt>?}rJ{{{]4616~: @5tQ1ꁓdKKP$YXXX^^Qڵeѳz/@"CE0d%=CnCgs+i3C*҆C鎈l!/9m/Y9n4tA;(2Ey/Yn :qE!p/RUi:ȦH$Vx{{[ҚZR{LOҤWk2Ove+s+xGQ[}id[T7:/O-=4ez\ \@UZtHMuLۻNPa)оtsS:PwajC(BauQ16j *moob1zЂ I1]edd^^^&I1/PfskxSSS>CW67}jL2ZA $ 45 jP)h wwZ(T;VbbP>Ep+{(; Ii<- )]RF`8?wvv>vk488o>!劊wvvF|>Z#؛gy8|"TT*uttd2 .p9rDkz%m'ϕh۷OUv6!6z$ܒy@["*Kͬ0ܨ.tml/"eA!MDfro|coOp./"JkpWU,+s bDTH.JU ?B&DLia@ԻS.fM W`P(,,,B!l=cPt1Rft1d_QąO5ф^X1MPD+<577{LvAM<_a d}k!i~à?ҡJ$ Oc8a1|S #GİIK#9W(Ych(CT-Ne`DMckkKЀgL3Ғf#n׊nT*6Pg(Uk %!Aa>.VFg̠^Kpu`Q܃%G$!}U/ .]Ss>AoN}PޟdΥӧO;vuu7|sssw||ȑ#:,DBX$QPtj qQ%H5TOMM"Gf2\Jŗ_~yzz^߿_d`UìωG63htppP t:^ 2? Rեy7=HsmUZZZTp2W+jgggaaABT*U,HRrjR+ lՃŽ:DTآyq:Aʕ] D9HT* 5!F.LnJi꓊iI]ZkȰ'xBΠv2gP}@UTDA] m=.%4Fk񚐖P]+,ḭ@ HdK|:pz4-0) o j;V⪣d}a0("g{ A-!6/j% ]E-VI |)C):#GAqh?Z st/]I1`hnɀN- ]aE^\)~Λ bp308l X \Bp5qnSGH[ЫH jZM'2lQg9cZ l$*ql`֚hZvkQi?IVH7%&r)-BTbmu#vwwi֪@vLqr:LcV'zߠz񙙙|>f5~/T-KTސukB/Hyс,r $ v,Qor2<:AxWɓ'Fǚ[ZϞ=DKKJ\]]];j5OW6>.Se'&\ jL4N":)%p@~B!Ye$ [7`7N.">&3N~Z$vCqil4A 4ZXY_,s}}=O}ʥAHsQplɸ7I)$ubc5 Z#nGI5o@uRP3*4ۥe>n½[YtGk" J%>~X._+KA$VHnz%-H_\]\[ݕX"ka-vD"*X[8N&*x Z,Z}]S79QphO+xhlv_uܔA$9& {g8MTyɉL& )a}I;a]3ڻޱIyp:4›HqVIBw'T*cH,zLp4IJaۻ,8ɠu;:wjHPPҥK H$ B9 $J(ЂBq{^Cn*C  5 `<*_n1pWpLb IDATHZGئ|CWiG\\-GWm-N χ Nz:}F$|@5i8:^GG' G` 3-8T)t)a6ԜFmxBa !-bN7>v#Gtx޴-=L;ogqPQ Q7GD4.0d⏲}%BORn XA2B]߅q6 g'PN" j(2*Z^$}D XlTDBFu!QA e `^g,ENR|@ܔpAPsՃ3cw])nt+^ApEV9MLLH kll,bx<ߟ`€dޘIxÅ'g::pJ`W+ӆa΃[I1r71cs/Oud9ڌar]j6T4|1) RM`(S}7Gp"h}ݤ#^&Ap0wŸ'q{"P$" B^6H \!b"ٺ7IP=A[ɐdE.ÓjJJI.; s/͠0Y47\L]vӅvì aRP  )17Bj0~jgq U*&+(5>d$+_:(?{*wt~zQq( *Ppp*IIw|Bg+ >]`TGF vMg USc|\:L꠮3#, hTJ eOR#r(8 \ 2^7HunA[ @a9$ 63!#cCvhI:0aP(}}kr2g[&%7*@o)UbT -F0Іw uc_XdBFժ\oͰ/\b0<󴎆ޫP@N SNo6uzY K}H[~XTt!7ɨE,޽.B^$$@еrYJq$(O0ČLMt9"Bwg5pOk. {3Cr0Փ-H K3>n <NH| ,!5-/ LsXAɇJXPYK^oD76Uj@> gu//L|/AdFoF;Ui0 %qq*{K L\hhHV#nz eQOVrRũ|0- 4kfhӅtBw Y:CCZ(90v,+q& `RDi} B〽^.2Dꪾ-0 e"̛RԈ}ɹ=j05pTT23D.NQ )ThIJ[t\.W,$BBSwҕǐV*h &ͪEYgSIM `bajT*X&>uU .Hbkk+|$ڦJaq9U^N.r] TmmmJyVK$Yk=.tڒ4r35c0z9^7+>K,2/o֡@w`b208N 4xȉ{C33FrE4 F?b^]5RN֔HZR%i yb뫫Z]]YZZZ]-mo_*; +l@n-rM aᲸ(=نqM`yB竑/ɩXdWC8!~4iu2'"NWέQH7 *J*N25CW΅C, N5pA@\S۞qHV ~+׶)TJkA_@Xy4i8}+Z0T5~6ϣ%R<&r2]=$aWX*L)7x'QqHX@zԺZj`'\ Ԗl30\X t}.Y?%9>pxj33&?X&hMi89sBV`vhkc13K$X,C{m4K \k3Stٓs EN1؈M8v A |g40Pd׻l%'ZQK5o3|dƛh忇#PMrmNN&LÖ@QZO!N hd΃z>C=ii<9n 2606j+n=7q8WF]T%Q*.U*fZ]]]j-@"76+IRhyٍNr|m4$?f @h^$83 X NQ G`D1RsSЯujW&!q֙EJA hČTp`wMgו&2c -ɩ.ILFQ3Ʉt4ώSB i}2TN3~4HAJvr8vtD#QȒ|@y6ҕuv_Al7B!dE+|HKȠ=.-&I=t`]r  X̅MH# R)]$FIGS\Dq%M_"N+!TPԔL-6 {{ÅhJ-]C1}}.Dֲ*{! Њd~3 CE[DE_1(|} ,VG`uuUP}ST+2+~mѤ1 iv6x7)|쒖$yZK:@˻z>LB.L'7gŮ!sRbjȄ7.fYhɨZݱ974Z41䢩8rnjDpg'9O%kB!no.6ڇ!RQY+^=ڣKoVYZbqiiRsY**f5:@: q_ `h@`&|y z 驮g,ۤ֘Z&|kZkEt!::a5f /6$1DYB#OGB/}sQEPQ4rY 0#Q֕uO*WPf~o)?D 8 Cke^%U.GhW8m"E4iPyI:;, 哠8P gS\]ib)T(TEF s ~Pl R 1x "㤁+u>6Z3q;XڦZ7Ʋ1TmF ??BWWC2&PFʂ)ylty]g%6Z^cpʌ@.jӶb> U U$^O(.:!h]@> чbDMgugBTv;>ɩoP<>C>/뻸 &-N#O,*]w---Tjmmͥ5|JӶ"GT9.^8 Ӂz$u`}o7 ­XG.4 >w&*Atq3-2(z<"ѹ^w ?T r)A4̧'rr8]זzTzCZ0a=tla SVQ(EQ8@守6ZIv,w91H5EsKw7fP6;%Ih.B^oj;]sdhoڨ@ia1vT^v %(gCou}Hz]i< D z/61Ր;N"tPvj󪃩R f=cqI9!duBv6Dns!a>B7s7vejݛng-Dzn.J$Fϸ>ibs 1>:h$p\Q¦reJ^UܐUC|HIN:@>oZpuMM8&QLGi:3=1""s^t(o4-5XjCsCУPӒڽ4CifP=ށ鴶ξU\9F㉞ɛGGɔ^P*|>kPW0(by{Ky( z JE1C}.!kف+h0!B$.pкr@G 2i['պ5r`)bqvd:C U 5M]imۀ-ASRSŁA[bX74X STG~M|ϻ8g30xH)H _ W~.' p{׃AGiY wv^8h]>%tt{b1Pt1/Tra a=E*d<j* P%=Lu X=Uyl؍<7aA/Fe@6r^WbWd) J?(w21ޞT xEX/H&/c:Z[l6SΡu))*n\4tiB[tWiYx)-w؃J:2lb>5흹C}7 O9bѶP(H[7G"6H'i{T*-p(xnC7\5 p+@k 7F-P)'$G! !%%,_ʒXb(( mqi(\"T V a zΜs^>ߑ? 9糼y~*id)gy,d2T˜qlFE>mV3D N(\ёX_9 BkEeG2Qcub@Wim@Rk;zvW餰:er@Gu *; @:e,,k {"\mA%DoRz,[aSi^6{Ӊ:Il6}-Mb釪ţͥkm@,V?CİNlUЍJFR@%$ 2enLx] &k;ҩvef3̯ǃZ"6زU=ehDV;ΪةFKDŠYԝ`a+h\4hs=vJ,r©3Qaf={;ƪN1ekv`aJEVĒa6@pc4:!}.5IWw烲;nltæ\.^oYF-`* RAˬͪM-˕[V=-UDuW53ׄŀ,)g "Tkj *L~E;g0aRPgBipv*o-l< % $̀F,{B=?n`[:÷ўOE`4mc-.~8CjdvVLeN8}Xuk&ҹ`Ne;Zh3vṈ"DO4od g hLDB'AκAn O}S` -N\go"L]ܜ(2!SlSY=0!H#ˆHwafd\i2b!#S[wjT9V NY{/+(F*,ֆ* &AFB/\.WZW6 BarrX,z\.FRw"M׻hcegd;әFKh'^ է=Cʎ߫d501^YLU.t^cWEK.XR0 @χVa#fX]G2-x\S(dil#"#$K&0bZN5X9$`d\J"wYZ5ˬ%6YWW_XGQ)sل*aǪ7Y5E,hXs*DZ|y#5vG%~A`)>+82S+=-WI0:Ubv.mvDmO?GzEmxaVH\ L7,WZD-d++Y(;[KF HIՁV} DbA\Fxgm,,3WIX4L :jnk r6ע$9?):vFB+v ZHaV]>.yl2>CڞFvN rl{~lq32Ɂd?-oW دZdr.džyw,{L' GV6=Ҿ!)6c6FS [q=wh2bk* +zR(W8G~LRxH- [(k YT?Q]bNOz2V)}gN]&d[c>[8 jVvTƲ 85DYeي ɂ+!'F/ې2_UP-X(VyK%s` ;^S51ywZ`QdAþZEhOS!.S="(PI/#Ӄ'aGme""pE1BqZS-=וJ\.g}^S|`ѨY@ϨUm[uTNz؂d~@M6z,HTt rt bacS%L*kNVdOg`?]2-A;kCe[$.2-4ku&1n[\of%/chfa`=6ubbt|TKHJ;f/Ce0ZbV[m[T]՚upڮ.^ ê *`씈gz4o-Ba{Vp,OAfL6B>RW IDATZ"Q}T{zu' #,@AvޛnI턡.ZZvVN! RR$ jٜɤ8H*] QR@‹$3t((3Wmwd`! M+x`X!N,8(P2 ܔvH+13b|rtLv0z8k?Xr$΂6mAWRo6Bq޷f_ GS>hiYzrG;Ko!sQ@ut+!2lewz?zsD mb년)\VqPll^9ϐ$ME2a\Q."X\݀CCCzPOOщQWW+7Ĕ|^:șmCGE)ϖ։Cʌ/<P xҲhdZ3A9.JPqV&')HHT֞$h"ۈgLOw'=\c (vbrYDဃvIGh4:DzS2ȏ> xVSz+.Kh쇣G8RCyc  c_Dl#ܙ=씻[up]DԫXU*[4C00M[R,\n2H<w(d[jhh=c-mZ4fe0V2{ ZJYO^YmP6 ϙTQz?w =[ Q 3~XYX t zvFZ)9EΎb8NVT*٥o"H |'-:`(bQj;O*nJ=?aHIfK\N;oK@[=[ WiFcj)C [9m; )HD>V:ll *N;GcǦMI X7nA"Ď(ae`q#>&tN!PZ 6-9#Vbaع$VeN[64gDhgZGe gv֬%;gfmNf|*hdXq<qXP^0hh5*/ĢȄRC6ln ,j-zKxEkRJ}i8zvN2+Tlj#,YG}~ 7;`v:.ZI4b"k788^!%s?V-G"ܑvO{GBcdP H#E08Z3,<&.Xl)h9ZjuwI]`_PoCϗ31ݠ=H|@nyTJ:}XCbG;zNRIeXLI3N;S,bZM։'w[;$WCV3_=0Џ7AB;:1) me\hVF0$?ntdy5:R`?c2^TkgےLCkeS8̠Ag]LR|; +,%Zh[ 랶s ptrfCFIuJ|VM%F[1.(遨Z@z>r} vB<^\&C,qj Hk5 "7oAi,2%Y%9i(ljM,N "L $0stkEdMrnȈZ$CebCdgXPCPO~ F-w&PG*#H`d2if)[5j A/Wt?CiE"HC?!Q*lmCh"`[ђѢL,JRlfq!PQl6{.7R{ٳg޽t+o j6gTڿ8VK%}ƙ瞰qnZKbUK$ן2 Q^{t:](jT*%8=\Y tZ3䈳iNV>9n;SQ={޽v/c[B$@+AC&nwzzzݎ㌌1ڵ+N B 󳳳###lppro1;;Kc;/̃HjffF夑/tzxxƓ|>?88Hzmilg &hđmcn/-jkk[^dN>!YIe;ePY8-<`Kt8GnZI$$KF aR(JZpt)]w[tTj ̸յZP4^Bh ``ڗ g#U#NM[E#b Ġ8YΗtJ3 fs}vb:W(*>Qeb;v옝iڑHTy38޹s^e˖}y睗_~9,W:j ÿ/9VqĚ5k:ꨣZJ&t:w[j rJڨEz_x-[( 7l@*Iǭگh <{FGGw//sOu]?ϲ'sM7&{sFz|5kykH/jd>j5;vT^zfFv ۻ裏r n{SC4zG_~͛7()AYG^9e4mDțZ\_aZʏݮ& K@+$:^G/k$0Xɡ rMH B8Nj49g)Rax,X&0>:*~]=؍"h*CچJR*p<$꠿z-͔2QP 8m{\~^Ko^Wvۇ?|Ī+n;oo:zNG>Bo[{wqWrW]uՊ+6mc]z饗\rɇ>.;ܺu8//N>Ǽe]jTժUV' G?+g믿#\ew1T*uݻP({+ʅ^(HJ]}n;n׿ 'O|{ߋ7v{FW_}~?&y/}K.nzoo>9_y啿>餓nP(T(nݚL&뮻wy饗ybby7X*֮];55x}gyF;б||w^xᅟ'o-[>x޷~vڴi7߼u 6]'k?яRj epwlL6kuxw$Ĭ5c!C$xh{),#ңUv3z;H~V.OLO]0`-,-& wi++|QJ)`uđp(AYPїH' {jANghhH}g\E"T Ee e.D2M;`!fH(<I ;e Dzj+O5o (qxR/N8yC0Zo<.jjfKRXNd^u hbnii)WFuT_fА- QH$.ٻ+_WMq-rs=O}}Z/-H)A\._y問='ƦssBuG}v Ԍ??ZmttO~r=p o͛7 Zv뭷z=S,/HC2 l*J^|7.'g&MB t:TQtO=ԧ?iIZ>*'Λoc=p͛Xbƍoƍ;#lٲ妛nz饗o6~K/U[oO~r6l[v?~}kN箻j{T*{k׮O;~8oڴWe]3իV Rh}ᇿo\|-[v?SW\q??I1o?c_zm۶}<_x|pƍW_줝Na Y `yI>adv ͘vaV@ʼC՗ A@Auw@ժ|uHk _ƔQ̃E:eȄ\.D>KԻFڕJkb\w',c!uXXĠ| m l83ãG8p)A׉ {e [FQ&QWOM#4 a)-Sk{Q\87M3mW1*D"DadddiiI?L&uG|>_T\sgu.+JuGիWc~UW{b#f2Ao5\ӫ^w}[lxM7Eh4q{lݺuJ.۳g]wݥȠ\r'x ~|>/ơƨG-[VXq饗{CPܽ{w2>gggׯ_/Mgo2-yFqw]v7߼}vnrdz>OTՍ7jCcTE=YAv֭җxo| _@Pܼ5k"yRҨϘAG{m~~~bb"?: y gq];__gu@ P(R6v ȇUډ h[B>Vt-@!ghA9TE0Ϣ62J4uB xWQ#?F[RUjp(魭=z88pq$U6H<ҩl%m)-!Y/EpP(Ft2!C/\. _`YDpOUÉ/׋U;;NbԷ}+IJ/LWP*H:%U,B@:4FTR"/Jʎ6`o[A('βMeZQ IDAThN˳&qZ:+ НХbHz"2`EyC9 _KM/]ϙZmhM'D覀3XuCejjj;wl.W'WjZ6W)*3w'/;xꩧ^E)aCz=r\sO?p[o^{m``3|7гPJ&U XLJ$Pw|{n͛! bҁQ*կ^~pxڵw}_&Ko^#SX/w}z8P"QOa=S;Jl*2 4i;ٮBFZ* sŤ6ov+ѹPa^ ^dhл4yC_xuTט,8Uj쒬 M)$1*Q#oJ|m % +R'bg2*$-rx3P>84:n>/4\EZX<5gp8x FzFH+;bY[aNU{+Z[A8z=PTBX6}(I=U-\RUmKa' *W!~Y!QT)~XPߗiג!{D7 0]PR˷[^}UJrV_XXxWN__}#q\?яu|Cz+oCRGyc'>[n+_ʵ^JG?Q=h@e۶m~_ʕ+A;~_io{}=CW^y&@T+k;m۶]uUZRԭ/x3 :Z[n}WN=ԭ[Y梋.j4Oj_E䝴O{u׭^K/x?o߾Oo}#z '0>>3H$}vCн޻w;#_}էrJ {/xtt[oj~pddGD"?~zo[n喳>K.~SSS>orr_j}gB1y*l@s$Xъ4ZoH$ ?Q`J3/r155n̐ Zײ8$b :Լ̓*ūYe6% z kRRc^O^rsv #t,8J6EMd Rn/CT)stB Y@Vу5鷐ƃRҠ/7|SNÐ1O畦e Kbni܁$yEhhmi"KϋD1N uvUdѻj={j IYӪ‹_[='Xv@I&BkZy{=:֠@lkFËӪE_ h$V+̏+Wnw N:vZ\Z(*ZUvj+ X{LX,&ZF<'^hU!G d<wG3hSr,tj9{O0 F#U&ؠn-cuL8-n__Š`0uӭ]\. VE~PI*}d28"z2: 8XG$:hbB+8 &5@SҵLPx*!D? |e a:Cq_*VZ`rt\BhtffU&hEs'o ԰"hR  W"kԀ)+G #Ҕ(ȸ#.ǟ[Wћv`Hp=Ȕ_}uv;ԏ{23-eTrsJ+h\(fV2#:Q FN Pɱ y\+ \'i lS]lm d$ zk@+nD,O#eG8-wɴa))c! I`?Idj}H:%U0|0m+ ZcbTa0܋n8RL^NpTT#]fKGPUfHy2dk'kC}G fZUį_fn(22e8նSBoSU@ʕW5H]t_Ge|nJlAK˲\.bG\jG=%Ii$ ]qj'{rYE;ДQRX4bҟ;a]PheL7PƱDwI'X پ>:NA2(tdȄY6v]U;n.۹]vMO|c?488B8֩ǡkW  A&J?bv8oPt5ݥǏ-)ʩA9?14,J\.W(U*Ni7}F94@J .~ttt||< HZCNkҶf'''gfgbR)LOXZ,[T?)~R)i*%Y8y3%آ9fa]sVz;]P©[buB&pA.H8@Y۞CM RO"8Z *©aL!hΙ*}Xj*VJe$ "Y H5D;[;iXL-[]"KBJUaZO+=+ #b 1p/JR 7 &`%5n=ÖJEX>o2/ [Ԡt:KKKDBp miA8-DصjX‴VC /u i,\[We4DOkT@nwѬժx\4 u{^X\J/z<`(jrx|\+;KnW CT2FcڴZ=!6@o*d;,( 4`Oe+8P*&&&Ơ(Sآje@O[ +jz>qUzαXTۍ?n9xDA1Xo BGH6*Y; jE$^, ܑhb9?0 NYDBT1 [j+@Q CpE+|teqُx(0VU*?>rpȡ8X R=jmBbjh-^q;3"NZ]%C &<|CM+%R φ{:a'*V,"#j˘p('r \\T,9E"=nxMpzb3 :Uqh eWC`gyi2h6vYd\f(FzVrGU)}HuӋG&{g`˚znw^ԾFF (X"`Mt:RQ/C\.C!]vϷZ}gIĉa.eжmy^th1pq4)TjV]M\hyd4>:AO4W'-s|X u>U*T*d BR6].g2J| Ut@JxOJG[] G, kk%YNb-#aAХ#i94j T.8xk ѥE xm{Z4CzzS:c7DY*d2Y*y`qo[X$l_XV Q\EF<]r&Tr{$h}X@k2Ғؘ~3~iO%:pRs 64րVgU Z-f6ĶNJ .`agL]4Q{yQ~8SՇΙ TnʲI&uJwZz:N8v 'QVqJYeCggT%AWFg?%=Q tr$dTѺBK:ne~o)Lb,Xpr*+F" Huѱc㫏ZРTZ$rDbeۭV2~^/dޚɯ 齡p K^tJǾ?MJ F|f.8џ-s{zR>;}h:wD$2bŪ~q>%JmSIUcD~5SM (7H% z⫯g&sGo!L0LiρPufx<l6ɴۭp$U;F<ӨɾHtR)vͼkY5-mNvQxL-ҫnz\NbqiiLGGXdIU$3$h81D$TXZ'W} %5 =vmD69ժ#̘ց\Dt[qư1Oп52 ! z`tVVXMdx@hU 7מٚ*'c(LfRk4_m8 k E"!Wf*xQz\# GS-(e~/LDr51K)JEqF2dB٤#`Zx[jÒpf]hw#U!2S2U BjVJJ|S]`v̑a^G1ĊiATHlS C6L@nneB3Ki:bӴP:"{zzZ:>[kmI@B&`'8ZYR" @G}T(}ћŸ] YZ.,h}>.k6Vsnv.Xȧ2|\)]nw=eSrv{^׫TjLUkě tF-l՜?_l1nOtl[ RVmptCT,:dDj >O_p\Ag͑'trZ9qa`-HdϮW߳n(:l٬eqQLG(r9V?[g/t\.YqMFFF<:' iDbہalvfuƕ5F$+҉޷9m|IcYbT-z<;ԠN#*[JL$Z@X٭ x]xs8ޔo>WV❵I) @ُ%ܚM 6j c[!z2BT$ cs7V&BufkHe(Tprla"9tK-'+ŀP%kbZOkh,``M"2c%ӑo8geP IDATQ>zt.(lg}CѠƗh X-jy1jlXt G6ǂXuY؍smʽ*0"$P1fhل fwx?5бux*94VI`\T*>ϩպV+j45caa\ 5} ɕN֛N׆"p?3J5;D϶rɁ;ݞ٣7I۫rC#i5KF^-F^"^oj~c>7%}nݪ׷??5v\A ޟ+2X\Z.+ #׼\\iiNZYbWUHcIVؕEMsRCCvj,.-6ݡחHĭ2GQΖ&0cnwXhxxryUH+WD"h`0X,Vx)0B J_R8TM!U*\.W(܊X=7=8;5u`rph8,-- GQev(FDZvx[Gg Q``g_#i Qr7j$9&3t`VT%WMŒ-ZH#"e ϓe X C*Jv:|Ѥ1\葖 Rй88nu8Gb)'Yì/ɟ~lUX,h40JՋ%-vXh} }~LE\GF3gDyޔ |K_$v:FC3>qlϗgW2j u<=v@E-U(PstHWZAR}7rɺ/q1 )*c2h *b$O9 T)2[GE VJ?6 z̀(D¸N$bQ7+@Clzd!H{qw]+S* \>e|mORrrSvx{`Q {z΄éuG}X\*{{JũS}G&y}nfrv>v]x4킳vʕ)_CռaOPp\LT̄ GfbŊ5kֈT*O~ $wbb"٪Vu^5٩6Dž#Q{,Jq6q\^  [Ї]߿ɤN#ɕN3<<,`0(L q)*)ij?Cq 5Nt&PVox~P\T*zh8Pf#R +'m(bzL:ء[mp s#x էe RUt&SPv]eZ8y[*02 J;­I8L$pt7ukѶz  D64GϙOkI٘4q϶UẐKٳZ9J%:.LZ?&K5% Cn'\>*hPUQ .pa|ChRi Ak@Xg@)ڒtQ-( %+:p 2FVP@} 0F eǼiO du@\.B|ZO A2KZ^Ǥ1UnjlY%"=#_nh%d'Q(p div 5.Zfzq.],rN:}pݬNff hȩ4:NP |r^79Hk ΙfJKxz! v[T"G=ApCcV^v;Guz=7Ra"97Jw/>_].W,X:V: zvJ"Cn{ddlwUtCnny><{<LMD:'b[.A B (s' lֺN(2XvN#B6`nk-^[RD8'xTL&{ BDFl4N};&ryrrR'2T*=lj*BalŸTGN3ADT %W⇈G=a|[1&N 0 b,/D5m PL/2K Njjh?F)1=%j1+5ChUS:L5ŀ0yw XA5slpïW3uAIfOi*wh'!|,9cl6#Ҕ"4 ВD"@Cީת/2E%dBL\݈0H>A@(|/FVCWRT1;H ٮWn3<;C.a^;őY'P-!E8ݨw2m4 bZIFeDZb#GQA8t(UtHgN.3RnҲϗˤp,>ƵS/@XzFR yY$j0Ϭ ӓQ§ u`VE ?tp&mgO"-`FJEŒ N+ [?`GFP.n@ʢlY2dd2EE?̚Z;Uc 9$'#󃙗(H$hc.L C@B 2ugNMlek&{) 1XUXD"Aj}]5h%`  &ϖ܃!l:k=j&ilLIݧ"mtE$f(i EAؐVɮeɃ2kuLZPF0 [+FF' )b4 V@QDi(6Iq*"#\u0+S,NR-KRviX,VSSTWkMǛ/V\.C;vF|.w/Yrtwj9syR\.Gn=9?\jw,rIǼ`0"nZH4jbxӞ|=Nfzʉ' ꋋJksl4/ߙ՛B'N;y)nG<O,9-|>SS.Xldd$b1iCaj5{hӭjnwVKWʙt: h䌰 /\uW*`0]r9f(JlǴJb>;xݞ쮗3XDF=)疕ݪX,^Գ1E+U*)%%Kмz>'\r Dv螕ep c\tnPӜj}*"  5 w,kҟ$}YU=~qނ!k FK/3`0 >CItBՍ@ m8aI# # s4ڱm,09DyM8b3b b/+U"fM-hϽk.< ʠ,TweVLPPW2Pt'jU(ٟR) ZlS~]UKŜ8fJD8rb>;LB~1vK9?/N8xr٪v&V+:][\؟L$SC3e^\=08Qouv+r>Fbzcaqn;oXs ^^pځJ .۷oWYT۝V0,;+zިW^լͧNhxxX|>^}򶾾JfwU,suZx"5 CqqUzr٩\FjALx<16r7d2 OC. [ JT;~@ 'r>WGcڰPFl8/pA'V}AKqAc&V$rS3Dsd+-X 󺸃YP4ew`3\<:Vxz}``lQ5K$ -+c_NiɈ ؗ@DB:)N,~ Hޅ- mrDTBe;J|I“ >>d%H55^.gєQCP9A)HD^vatZbv=66d>*#\ - Bޚ8zA txhq& /IE¸5XTĴTZc r MER(47rܹPe[!RFq,ISXjzc$ፒdj@(r㤗SLM/..+ft\#}?cx=e'=6qo5So ڭz)`1`06M:rhdlŘ]\\h8zM/Otյ<wƢsg֭v\9RZ*&_{N4hNFnuMrR\#7cdJ(|>}>А!5sgggNO5žXrhN)V)$S#מJҊd2 6̉(x|iiItȎvftŢ\ r8ӡj5V\Rl:v{Rzzzn <2w^W%~^u^Mz.nd:D|>M &}~NH YAtfff$}[fUS}Hn+iiզP3µ]{2Qۑ4۴kՊbgG++,+5wt[ jh D-J Szx)73-kЭ^ hi8ƴOx@J;llU a7ޥߤuzd\.Sy*Ě1u4:2MCLG)CB1')L@9(C)e&phSXyĨS+Txk)9a>Ud4=1*LQǖ `i1X,FR'8S] d-Ii]*lCDE;HҁNn#+B%ąQx-=4옆n:?57==],'j5<.WVܳ;8{9rqg^XὉZF#تUk @8 Zry2ԬȈj5gQ9xjzi6*nw( :Nr7}$|p}=* H䐣8i(L&LA20kq8#`7赪k=TTBve/{SZ%MͰݻg3߯MS'Ibq׿Ó;o95_럔JAjI}>_ܴZ- VD|x뫫v\:y0 FEU*yM˲J%RyU.~`VsWjk)_}gy7*Stx5$8fUDXEQ8kn%zlxh3FTu8ۘː" |&DS98O,Tѻ3=TZ Ow4F`" q\P÷gl:k!/" M#JLpefSgJ Esf÷7"˥|dSmqq6-ȕ^#UF֐{sI4:v,48O)MvS(^d՚8hh95Ua:se"A!nZ2N!4m!悅4XM`\!)=R9Jrec-1D7]&!d3 Jw1J0W[%R<%+']zfp& [\*q8hgr^,ŋfmJf=ַ?/,,WWliY7>o^Bg6jm/vn[i^4 ՠUէOppEQ!~oIR~U:co( [X}{nNM),WK^Zzg[zs6I??n7OS߯n㸢zy.X-l&":J(_?G_Gr2^~?o8<}}l8lϲ,pZw/vwP%P퐭Ăn>͢ZL W{mÇ:?uO&'/Kne6FyQ.,.Yy$Y^Ee5Vdwy6}o:mێ-"e>2dB=j>_Y֦?үX{{F`0il6k:[0z{U& hۦAW 9fv+-n[o(au z|Pb\gI%*Z*<'Unl:Oį//oVYVRln6NY~rUTɏ * -``a M(xiVNWnr)y\)P֌a&"~ !0$Tt 0L:X9@BbjL) G\F-0)d ~@]3QyTK;z{":pI&6@O^-9+$ߐ5"LQo\N5'w:04E@Yk@mqƌ4 eⱠ0}fOGV!F8r_yvnuWAÔ]Z.ApP^rPp8rzA88<޻wwb42uQdM4Luq׫Qj *yV!ij:A,Ghv>lӏ^noo7;wkn Vm4_/ǣqz38; /˶AP~ѨFQZdE_&I$Upqq1{UvwtzzJ/CRoEt<k`dYٽ֝㓷?xVƽ=<>=k*Pt~ FS~6E9%̣v$0EdޓE&18TfIZS$hKGa͡AD"07.S/)hl(è$c5jndY(sbCV  P?J`6r)T!#ϠÄs3SBz^q}ŜCDHΠ4 Ot)BQ!wMo1+dIj=F%e1-!^ J2ItD maW4s VS$ V$jDo ~c*>Ʉ̹KV#(cCG ujj$&OD6ܜyz|1n[<֓xty~>b"+t:|?x׶ -wXhHnRܿ__xvAڝwE\\z|{4nV~rKnKYv8M,5#ɶq|??DG͚OlNnWZcH#Gm,KvJbTig[]W!MJ`Ƴqʮ[r]uenN6\_}x[WUfnboo|_{F.kR^*MS$lpxxxppT0Peel. ިnq~7a>`>zZH2Ţ(&aѨz=uy/9F>Cό1X^ge+ PȀI)C'8:+lCo}4],!/E I$1WX<%xMV&v<+BPdH| !ˆ;ۙf%tbS\+_,2fjmFͪMcSf^QDn7Bzd'vs!u=̀/]=E8Aj:@L86Iib +lZpCxHhʰIakk,Qj3ӸyM@DV9"kB5]5,N%!$ER?L]xl"mXjLE 8hzLҗ2_ Q)#3;3id0 ӜgϟxZN+ȋx;7n>?yZy;7]4,;o{n9\'mۭVK'Z&=b!fHwAglie_~v:2 ۍtJݮ[~ZW|\T/ο/>_iy~׿ǯw߫՚J殮ػzJdB%I\.;l65 Stz~}T*W. J$MrJǫ|ڬn&k?"VU0 M+cS hhGIZm5? Ljf3+w"~GUoէ|$aX;(y*|uuإQVyMVuw8Zluڝ^`+̓Zx #^S:88F^k s $Z(oM?Kq,OPKcBW =S$%j؆&B 㻨qSZú*;HV̿az@\!&9`G-1tYţ &.%,A^(3L0LI2cv!":򌭡0 zֶ`'T-"dzT 0L"8y3(8j=hziAp`ٹAVm0dEsSIISll*IĂ!Y&YKHH-4(4 JV[-3%DY˶"م2kYNPi@S9۶KfSf? !q^7L6H4ӍϲV&q'eyo?>|ѻfzXTe&ȩvopݲj:N^pFQu{&ݫH,8 nfb1<.,(wfz57Z|>˲;xc,g(?OnfouJ^7趺wXVQ7*3bRk-KsFVjY/&IuPh_Y}N'SU<[\۶5Ƚ(E C2;0L#IbʨC6ALob(p@M| .E[I(6b& mv :(b/kњ?cFft1Yh+aDt )o}_s j^]]̲$vFs{?jio1ǫp[$ۑսf/Z;^Kw.L!Dl6.Fc%wJEV,"9jgj`am˟.5vwKQNdY_/W[˲Nۿ[?[XA䥻zUV^!G]:S.հlod~shfbQXPQV+z14Nwx8lVd|wpE( >K`i7FoJ$ˊ+8I|1^ zfԻ=[Z.Wx&f~dnp8o4*a}/I6hmjueqk9-8z4)9`j0:R5 )G;KH3O/U3_T0f[PƮLMx2qm;xSDKݲR0 qjr!Tј#vSn&[tx;5^vZ%aUյcەJVWm|dq{b}kKƯT*z ؤF 0cQ\э0W0` tT* DE,驚x?n8>}r\*;b<;Z6H b:iєAɡ< ]luvh4JӄD3 "` erDQA HP^ &,@z (9^#E6B6L+S&|L}ԍBfo7aYh(vMYb3Q( 3.2RnA-l-bqJVUX"`yxyIez`6]"ըWO BLmXqy˘gCy&DE+DiB0z!gfb+],5s"rluRO?_믯W"0*$S\ҷ-II@GWN EGe:h;AAL#?L<*=fQѨwWOms-%~UAKkeEL-SEo'^$*Id>?z?drxwkw)G*rY_dm4|TNˁHi>{uIpXh7f)Ytz=Z-v7GER9~rzZM֦N7{IðU kxW.M}?DŽOlөV^^<{ɉFZvͦhzÛ/*T(o[XiSTްLcjVA;{ų8Fp8Vfl!$ljotƭkAw:O)gwϋܲkE`4?8V,]˓"Ů?*aQnSIV9>xnų*^o(" }nF68jQpMmAuxajd ѣGJyo6l$i:LG`P Vag2M`'D3X24#q@ G$6` 4IE+كY‘BC`3OmU !^9$g~_yQhÜmK:CP@ˌ\OC١L362=Xlo#n5XA& 9-MexZuc pB4 |g!L\y7̡BnN&քT6Rub^㔹wiFDL3#2_(@JӂǸ"N{&EprKM0V -mA4ۜ,}zDQ4r|gyp_xoYv]lJv}۩Ea\}%m[E^JnA\n6T-Z,Fc_PMzOfqͦ7k$Utkthf^\;j/Lw|J.G+˭VKY)ateJ- 9nu<~ˢDLZ|_&6Dr (ͷQEѮ\'IX\;xvfu+WN+eU*Y0n8j8:::<|Xe;nmWzq1]dzb^ZHku 2lC,"oo0ŔT-@ 6 L~"g"[L]"֛9@/\ I*qgül>\v(/) GǴ0 ᆼJ 6w]̞\BQy9zn$ qx  HO4ec !Eb8cA>TLWpWis1IjY: `[-} n IDAT$L7"-Wre:љ%?U^lyfIV+ Ox=N/ ƘV\ rs@`E/:J#fwPPdl6BgGS@h哼\._x6~}o緽JaT,:Z~3pK^>-m~op+N]75ٚ|kwrzVVuu: o[I4vs9FUF{I/ZBnxr,-ɺT |jz-fuU 9iͤ}Jq( %aJfN89 % YltVJSRfvCV^TWWWBM9NeYY1ЕSNASzǏ/.../m4=HfwCXr< /^|x*/{C_mY^){-.gٶ:*A{t|-lSy~gL<w:RPVVǫ*]g%Nv*,;x]厞'5(!pZE/V.eeAr<ˋl^-~}W&Jӗ0J\լs21g _nbV ]PBAf\Tntjڧ&]00@ qGH`ҙ7#;dh hu9C{ ZcؠG@\{*;zxQ*H0̪.0}%i(93bX,Qً757ݣLb}0,K| L j.HSFs W;ɿSk' Xќ=R瘌;toҙz m3f La3' 3SZ4_ I8TрN 8g Dv0#za~#քLULv0qLAU\.hxŧΝ_V: mT ?98xp୽n<7na9h[3(kN'7fVoV+ƽHF96Jzv[y1"yWXdx' a(jaިEaj6)k$̊kFZX p^kJ4|,2rUOCWy|>wl_Y;NWVp8l>],fR O3\kV0M`NGQ!&4BG0SzdKQakHy7"3+t BQdǣuD@. ECF:06j!R)(tE@1g:uoA0gg_|?|Z (jIGNen_,vǯ|m4ZL_Jzq飯>z߾`\. ԩZ h4:1%B<4)[ޢ6Ǐ>}8!:ڷ$jowzzEi/TD9l 5k`[+^,"d" SON@VFCgp8|j☠gmͲl]]ݾً( ,lJ`iuZZ~t:Q waXm6]wfJz^vhkB;0Eu4H Hy{[')ө~fD!7R)M:!'r$QulvDZ>e&'&J]^*d: k-'33m_M\B`PNG!|a-o4`$ pIFNG+@tM-br(cStiiKF8(~^+ 8D&0 53 R`-#:Ϣ'Mju\2֤rSDyP,4);gyuz䠢039 cvPhk؜c])9'(C^B5]+tMhMbU֟_?~lo9`Vu]i_t~5l4^P7lNqdluat?VɃ_yRJGPMu@0 (ZVhM 9W/^9h\fY.b^O|.;V +*D;-| 2Lh(~hz[pdՐM{جr\\qiTr<@`,9|;]9gk1a'sٶr)rKXA~l:(MƷuÎth`A1i1R&$P:^U*+E$6 S=5uq@P#(/8ʋ#f+p TшNo#S <ETP5tL!`ZASbxT,ľ䆋܈Ϥ!i$>7SZ;LdudM#.(LN3mSېw&"Y.i|\3c2O3]kx*i]i>ʕ0PC-ףϧdi*P&F_k+d2ǤBz:ɟE'~ J XK=cZxg1;ӻw K%V[畻nWUnh6ͦbvfru[f?o6A#F!F3$K.r% _8.=ϻ{ivOEQOD:h-1jyA΅eYJ%Jyn7[lEaѨl\FQe/*8Y'AnbH_0㛛pxyqŋPT1gVm|gQ\|٬, ;ݥr6R5A$t5#|ȒbfY&[zB.=RJvM(yngvj0XPhp3:52bFS.n*ݬM8b17"q;fS⺎Yf>gz jR-[M-?(L{EoW09B /E^IF{{ = We(4`1 1`xLy15]6"2XVD5l`qN`fEN:[ti'y^TVT{˶qZyYq^hfDVqy&ccd, /?Ϟ\_?N6ݥ(yuI&tkn^X?Z 'Ͼr9Fڄp$Fmڊ0 7&9Fض=N=2ZiYgGe=y~W/?gO?|ˬ<{"⣁3A/Cg%)fEc}T*X_.J7MxfAY[\~9~Yg̶_?_\=<⇕WñͫC0LI 8@ݨ#aJNۤFKeT@GU ISBhW `WGiI7'i4!byLxZN9*RORASԑc2Z`JK4>}" գbQ$?GX:bs^7) x Wcz 8kOW m $K@{?wj)DЪh6z0V$J%؂n?p(E 6I2ͭQm%2ZdlX+G\"ٗ~+o3Is{^$`У*q,ۭD0l40`&dHUڝnn)᧿t;'Oݴ\ig'S2lyX,/JLE,uev&ʭ&&sPAGtNY)!aZݛO~Q[e/6Mv}$I-,_-n-y^&(zmyB+K^HH cO>}b1[-\/jxuqmy\.f: :fu}'/V[Uˎ|ٓOx󏾘>+{yu \Ad%&(My|V{_\uyv~~lFd<=r6^_|^?'&좰GĈNN4$ɩJdBTu`B v\`jz|||~~F0T ll_xA,05Ԛ^ƓlśO?qv͡ ~"!S;Ip1MjsR0 L ]740hȂ눧hGPA'3F"S0L׷-g,CJgJZuN:hzM0`݈.!NiKҌLmz437']${2/K^4AΤ3u>0Fy]*Z'.1=$i k[ntQ#=dft56}z@G1SK7b *txj^i\T(sOD$h6f60591u *k76Q<$yS#pEJe/yv>wnut|f5vtOTh3>D9køv U}Ltu5 5G5elP$;rv]<Úm{R|~WiyvYmWt=V7iܥ#ǩx^0?,m^,n|Lf]8Nxh2eX19~"DZ)AG RI@EfkGC`(d*l*OHoDZ*5 T2eMvTؚ26(S&AhꬁクŴn Lj!sY*D(TH/^|roeJ)a= &6 GsNj%"5,MSjдᣘtt$U/ %7T i%̉3> x N1m2PH0a dblt%:U]6u-!@W  }?Z7QJZ0j<# Lm>_t(S82CN4Mӛ]*u*vO&Vʡvy^zATaz** Q ]DTPEO!;|r3M#5@1VÏLDEYUo= ml;`0Ͼn%I*-mFjlAzyA٫Vyh1_r19fpl7ŶT*VnNz><<ԄZۭjJI_4'iYtʁ?˳qg|3ͷx4 hY-g-j5E*N2R uRގ_ժoj7<OJbϧ ۱/uG~g7||Ѭqb;NV9i^V+}zY=̐UJIyڥz~w'dkt7<%3Y-ЅP4(L.8E#0U%@Y }L yI2ta>p,ӡPk@5' p*PiC{$ IDAT69dWd$ <BAz@8s|4 0W/)!guC M?Yx,S.\E@xb.Y{{s~Po8zJFn4SEȤJ_DPqj3kFxji`L Jz ZWo޺2E~Бly|jkqŋJkͦ_)q~ѐ˾+L(""m!E_&4g|~E{^ilum,ʲbvKVޠnVapK^a;ATw]ۥx{O˛|1b1g"]i,Hz-QEh6vP\iw0TjYV Y+$ԛwJ6۶^6hq\*x)Ŏ(vNѨT*I$䲚ur~ʮ햫ywK}ۮ]J_|qu|zXl|pmu[:zX{&B gjVrn*l6N' Cq>$hۇ~Ȳ,/ ;y/fOܶi:VJ[;oj5n&m:)L6S,,^ءCnzYBÜ*ck) eL@ifiz!S aʹc fUG6-N*E2ouVcg&T3p$jk+g"T`7&DR(d\A4p6ձ$T8P JGVhwZ]_ʼ)Tc>^ ֏4-3`ر=RD!C.c*PLhRGLaݬt;xB$u&z"x:дZeʏi$Ʊ%D\" x/L` hjLla &h^-nL}o4:VoV*~- 5nUu8%E feG)]JRzZift:~,ˢ(NNNz& AYC0z,q=JOV1>%7YI$j5? R٭5zvl6x[n}oQkVnT_n;6dg6hf1_닋b*/=G=zq~qOnn&gOf]WQEMInɫrݠ\% T*eݾ* nhZEqt|HkCrlzz7_#'0vw |w~ ~="_-n FɠNzjVE W&ʼnFXՉI0 b!O% CƗ@CzVS.*Ji|8.K׳ ;O7*~: KO+~ً9"ځ((IM=_#%Fh߁՛@d'!b SnD>ن%cz4Lb~dN@ lo2@JJIi0KvDMfD\%+$56Ϙ!IC?VZMq:#hL̉c#B*0Fě SXԞ{oahPF~b6J"<06%86܋-8v\G<唜Y i#9JkB\If=A! L(0ƁK:/zWyi9+} @ vSBLR&t:B~)=^FȲFytth-Z=^Z r,_hz,fQ5cGGGa^]]o7ax;V[ia5htSSz9<<Ȟ`oofAv+J;ۣO[Iz3f8X. 'bMӏ>h\, qC.URTXB$f.˳eI<,DĶ *~X4T|[°Jitٌwɬ?ivF%hi:>}l[7A}ǿZɝ_=zzjǏjp:8<|oz}y^v`9£Z \uߩAe1y_h8IhV_SyZ^jo;t{h/UQX٬4-4YEUl&CC ^h@xJ; &v- ?l *Tm@mQ6AFB`4~yB*#bSzR'h“/PV\Ce>l v,Q6 MA:aM0ujQ v*VQ9ŭWFCǘ3ӊL&a)6zh:b }ƫ|3L˥_|\.wqD'{z\.'ʲioVَ+.]$qodRXn^x"vy°s嗾r)xsa٥r/ *z5|>ϳ {گVw}YVLyV*$iWo4GΉWA>88{1rֶYԧIdJj%y͋\.%If;As뺖YZkauKj-I8voDjض.M,.?)`\)nzJX$t{M?kwyJht `|x:s%Zu e3P?cJp?s/LDSNak67_SR榠"cxZgo$yHJa!OhF+KDxMG}*%jJW{^X!0@ l26 ةh:Ij2}%8*inLcyJ`MHQ9B+jpm< %\Dqd|&j(PL K㗾VJXX.㡧>/Ub'L&p\F|zss3ƣG/^|Zsͣi#.RZGےC;S 8k$ +UoB}$c3jmDZ2oniuZ4Zl$I̐JEVZ.]ǩVjEQV~͋,],YEIwME5F(uxP~J@ndȲzmݰrlvx;q.Y4wp$mZ֮u]Ɠ.M`%I╽H&GIHQnm6kit(WuHܽshm%n+OVw{֨ێUa=h~h4aX<}XXc,QblqGspF926Fc4[Uj*yxy J?_vhg7WO4;Nղ=e; kOaV7'6$@tpL#C4%?>]`|nþBܒJg~$mpWg_~6]ut(N)k%-S5(L5?t`]_&;܈A9hd ymtzy*oc hX=@B"#Ϋ胓 0 ?0K̩"2T>DE& 7,#yWt` |$sޕLdûwZeY6L|?Av=,;~4>{4HcO?T0M3InXl4yԶOG]W隭aᆭ?NgGGf:&S72Ɋɲ"R u,+}7uhm{Ȳ]ۛL&Ӷm_ܾ+y?hz~e禑mSKy^q2EQ~4&np{{۶$8F(JYVt OgǎmAÇP@+ s59kCzM٧&Q)@i>B,/$0qВ-ٶ n>J0c͌.>( "Eyw2!x'xRc-{1E#dcxT( OvHE?Qd&O@Arۙ];f9\nVH {|rk+~:Q̜a[SdӥDUq{S (M؂ x@D],> 0N;D 4)`Ϟ+ۢ` X\l3QU۷o߽{wuuuvvv{{{ssIM²lwZveۖ}>x e.d`8X\\Hr+;(8uL[2MiZqh46MsX|WUJF#fxh]BH>"eM h)<A.Dh(q ?X*A;HU J0,V瘛U`F-0𰁂"<AAE5a :x*'o`\jcŰ E+ $ݑ%k RԡF$ WŔFȣ^HCU‰X.苊fHD9G\bx4 /!K,;9LW!4]P`Od_J(<ԟ*M'Α#] )ld&&$An(wz<Ǎ$7`qIeئ=?ԗuV46]qEiJUCHݶ"A0ey4~?_=/<}%#A>xTD #^+DhQtb4,aYI F}*,jdx'$Iшmc8-`U `4jUׯU=04Y]ߟM&l@hɲ\Ud4UnhwjEhk͜u5S:}4mZަ]K}"K; _Yue^-kߵBmIl+ nwSdU="Nx5I:i9c!TjڶUAlUUT?`rHȽx>)J2ń]z qN^& qˊ60j~}//4_ف~Gk]lY0ȋ˽˖,+G6GQ,gJ((@lfH6@ 5$QAuD'S>RDM1B\X1! 9 ێJFP\)7]r?. rV0 ۚ| l$YS mLc#(Ťrjd*(J"#Iœ[ei($Z8 $Ikxع"D({{{iv]74MC(O"#"*FAx)!E룪*3Q"g 8mDl rmb;7v{; ~ĥ9Ēx6q3TD:WũjaQUa5M[/ۮu]隡?vpRDV]^(Wj]m26M̮뛦Ʋ{bivŰ"GY>k_^c߁5 mĮ狮8h']cQl'H $dzkejTidB"؜3(JǂMO\X1nBw ;:L9·n"$)J~Qib+ u^+Tfs~~0E#M,Ӵ,{2g9("fvMzUd$ YZmȕ,uƟ]yM9uu#/۲L]oU]/a\~* )u-,xp? "vtYQTU7-/rr'l[v4 2;_ȤɠlV^ `U$,6M{{{[UYrZoQAI $ IDAT"*x;w^*]6Y6MZ^z2y4َk{ٳgu]K]7E,IuR޵,i/0nq_"KD&P 7_A Z̛,10sg0EDdQׄ( [`a)GiD0D#t[L^ 5Dez\\^ uĆ#P~fs\^a;I0^F[V**eǖ?,Z4UyDܨB] D?5?"Wŝ@.I!Q"'T(@HbcXpĴRSo23 N-w3[)8"ٟ~O1谍\e?)f5YUd9[A i˲&j5MNF0h†da8adg̯9lw''ʦ@o]W,u]4N ]qџ>8d2᜹Xq戳gL#A*6wFri ꂔ} $%H#ڄKC䞓y"D!2Xs>H# g5=ɿ(h!l޽M pƛy(/ dN]DOCQT т3\[W0]A8Q$7 PD*2Ox}?"ԽLؽ"XD*zwԟ+H7G]% †hQFo埓k9;$( 4p&%۶4@ݳÄ9$Iδltq=Y*F-`x8,(Qq,۬\pEiD2P8P`ϋd q(~ڍOT$[E 8i\J *޶W_a!sƝNtZ~l@'^ æqX/RSNhuC,7Sɉ8]Eb9c~#8<0M3 # pKq!_<Ȯ  y<zs4N;//M@V2HʲvaW " R:^@Y5M}l=u ìj%"s +Cy^oNO_/njFA׶pqYueEQȊy^izQڦxYU&śWao~NucOռhlvtttpp.3.PUUWDD %j\ %Bn2 7jV IPYQ$M3)YѺA, BZj\7ܶͳUץirus6,W IEFw\EQ%$.v3 b^ua@LUQnLO 󢭳pܲ~Ieٲ-UUy\e(*1W6E`S$Z2Tw]ǟp/nLp"EZFz< 4D7l\*8çl vL.K$*%&XԘI $`4P)j2U[ .:t"'[b0q)BD )1Q1lMTsDDRX AB*=?L.mIxb%% w 1 G$V醭0E3:$\L%d'xbI8@Y;D7 A&VrVJhȠMFif<82\: ߱"(lI?I,0 qGQTtCzʇREҦz(ʲ ) BjۉFQ@lgY햯o\b$4DiQVSjq&Gn\_a4{zm4>{͋Sϟ4MY7M NFWGu#YV?~<=S72vdE-3>aTqlxL&MvIRi8en蚦^dEQYuYR6?{k9%96js{sm///^իIxfW,AV7 EYGeY& R֖3$u] dYVm.f0 -RmǘL\$I C:1#M 6bʁd65'.E07%ئ#*|M.ɧsyP͌6eض ݊#XZD/DoR6 YpKT-wq1[TdkkZ J1 Bнs#Ȅŕ" "M ăA1\v,4u-U0au((&4ly,E!l29쟆MHU)LuÈGl,TD,X#MV@. g-@<>zWwv甬(/f<Ӊo ╣vDqX'n\Mu\-~Q{oEn!4p*PĹE R۶U˳'ko( j]d۶]/DQy$ z&z7n9 q$ue].t]MNfE3M%tٶizfmxs~s}]ekMv 'tz ɟh&t:<4d6^8("AZrY@H^VTu= ]ߙWj4H]Sem[:FmE$Igh8۽BUw^2M+Iw^e?^,#|G4y_0S"(a#y״GYiz? }[YRdiOW.6M) Dӆ~ѱi3 iOInᬜhDfڎd/ b3^ pfE{XLT ]O$4w7#4|;| ȓ@ql#G h]ɰt( 1GgOόj,Y$cSF0ea+Zva,bcD Dמ?^@JYG)J<Z 5/jBU0 HP@'Jb#^yx Lшf}eY݄alꐁ4_\W{A 4Ե_q]3hWWWHěE C ~nh] o΢*iE]otF7¶iw]e_|6q=slv(_Rb uC/Rtv{Ed2<̐<"ڑ;&ٿm  ,Kh iUMkaY6Y0j$Ii[䞪jU]7u],&sMno(vY't5o{p6k[TLӴm7va꺡kZu}zAQղ^xY}{4A3dey1c By8&5n-: > fq3iI~Q؇D>h D:&J2q(STp 6? lv%`-X ;(\?UL Z̖bCO\%eHBFЋƄW4R{d4& .ț\HQX`Xn`Kh "_h0x<i)q OtnR)h 턥 "<@ F"t+FjL01"% `B`2PDԢYL m[~4JB" ~θSx0o%-uFIjajL{X`̊HUAA5L$yH`* A&@DH"5smuJQ%初f{DqICG)2\i^__,hX̷eUaI0PUjBT|9iq*oZ隦jZ4iK ÐZ?<#$E{fX,LtY|zצTU"˝aiQ} MO>Wapi"Ü4I(= u"D9&IB#fVcUA'4n,K(hOTlL)(]v}iM۸$I^w+ٷ Ðl6 U Iֳ ྪWg~wv7/N_|xeUeYʉP]kbًX.)$End4CQd{寗ϻM7a4CUT;=׳Sw+j,$@VE4WP "p^!"l[J#;_+Zq*8{YC,cDlwX"J ѕF@] BځOdQNԜ _@6 * _@3~bcaS@l!}d! D<ϩEA 䋥ļw 1T(DǪ3Eg88D=I{Hn*x 4 PqQ,q{:ԯJQI7әqA3O ל`;=Inh "f{G[>6Co(ō1/`XQb!z,)c|sL8}ty1w|$NnQYޮVrX,؈],{ÿ0̪n3MsYM}xxjuCM4ٮςp>\8jGMl6[MS w"ϛIӔI^h4%}޽ݬikw ެiRE6"7/[.^[QG\;!aaT <no駟?z=۶ S$|/Gq;3RR@7>H) I8J2$.r1K˲eyz۾NQuiuTU,6aOgf{'a4ь wm8-TEVd9=k$Y MpmӦ.6m/߭$IʲrlqeWU4s4"YA+YFPS(#ffOjNvm{,։b^dubԕ1A~Q o#A bqoꦩ{0#yntԕiMӂ`y8ooo{(q\nUUuu,KYyM0iOxz~Q7?gdcB{1l206qs~o!ayUdEtݠJutպ*Es=;OfViɏ~~bg\1R$yg"FXꝋs$␗5#*4MӶMRUr&m)j;xrwCY IDAT咤4MK]j2r\e^̴۶*śI:Qr^~,ׯ~Wl!D04Mm*l(oWx7=si]o5]:?};tix'Q,Lً1dn,5r E2@$ރC&˝y`\hl7`CCXQR'PV=#+!416#"Jˈl%ߊbD(lF'2Qt;uM 4;g8D NTÈEt}aԋ¸qWu"QszEN᱓~Äuσ^-Jd!~ >2;qӔ{'67D|q說@f؈D`?bSxNNz14eJc~__jzY%(ڟr?1<aD9DG?9#Q5߇YHF;CG @&^P`-{/t, 8keg,X,Wu'ie,KCQ\}++FYml7+IVn])ˋ"%YzzӲ4IӹHNF}Efɲī<ϻUTca? C.~)R]i# *&˦gG';lV6Mo8Lrl7]E]՝m ն$I?ǎNSp#K $t>yO>##h|cɢAaN峭K> +gsPm{yьiU=ʭ7m۶<d}z_ěI0zmeng:~]xGm率t)kOm.Nbkv{|1$4 ˲F+6 y^o aΊ [<$sb]Q =,N̽p k':aTUS&DAsYi;N5nlD jwJ1bˉ{`4Nƶa6Tᙳ<ı8`O΀8_-Ζ~Ta!\ZQlQ1'%E4<j'&GJCzV=5ʥ,13Do/v0.b N#bTR@l_X5 *Szm.K}2TLD9H$@LӦ:U71F~)tS1hHAe$cbDaA^t {,9%9*x'*IW^eY}Wwmi sjARͳeShλRTaPtݨvn~;U=(\b̌UU"߸#eS'AxyaٺʲVu_g]S Y1ZtUtƞG5\VU$I^RTUQe۶ Gv]9?~yEYcjVb, ]jU\o `E'(M&clС,zC;f<* r}_j_EQ,|9]'׫Ƴ/MkiE5ͩnD"WWYSmlHhtX׻v~WWko~Z]?|ȱ3 c٘i|nqàCY88|zUٮmn-OO`mX( ^ (h`6 &r֒$l6/_|/޾|l6uS(E2쒍8,ƛUE R5My6Zo.%/yUծ5;ן&˪t2y2HC]\:.γ,bh|c0Hֲ,oVWLEʲ< nx}%mM錷3 hL#CTۄȽc*ZgTMqVRf-K(@"O 6ٴbRXC1C qHJc@X0KRfvOS\+q>~N ғIhH$ԟё8+?J+a){X,]gcK (E$*ܺwָ|NV6깞lG}FpE/3'EE&2 Bs{F¤")DD;ΎT ` M q1R/V Aťckag]Aebl4%)^"׏ѝ.؎4-"Q;pUJx@#JXTDEQ(b'oo+MS2ipOq0_lBjN34"G۷^l7.$EϺuSodo봪ӺXnV$.m7M-zquqʲ:IIQUeo|]Wуh`^}7lqv޶,cjr2Q9iZ,/6].hRUޓ <TaFQ`5d^zuu]YR,+I2,+a;MO}UPA*plDz,(qP8Ode:˱5vE' )Y9͛74zve}]$;lWVeEeuhajU,g|}8{GnZnw}[E*_}\,fh&yU&[4MYmN7tE~$CQM]3W7UvCgEaQ}=ov(Y.le:Ir=>Z&Cץ䡬|ZE̵ :e"xbwdH8G&tx/Xa]PrPlLP_T-#_*7;\z9.;RY&NiNƸp- 9clr1=qˤ6Rqs<ԂԜk+p"OCTK7sf{qj o91rj4"= ߑ$-cy|?t&1fLd-˕a/#}ajasCy|  mPĐ)Qczǡ"1Zbk'Ң QU;!"|.TNlC7͋v{n*EPm/d͵,_̪\zh2dlV0rY/vicjzf'}ᱬ*~Kֺa[%t!ZnEl6쿊Tl#SR7jhٯeO& w0\]]z8ޮ7}WOq2q|:wX?7-ڲYSrqb]9:&mXvuE{Teyv/v]˲>8ԏެV..E-zuE]7YE:FBixEdMM|NO$i:u<m0ಠO!*a%FQ9$r ,1_1G)I+Q=,\z\ ,P jqEDg~^D2|0abY4+G^8%(=cË+?Y ^|)x#x5I$W:!;lUzIhB¼ U\+r9~E" ߦ|mbj v3?t n'K"G'H,WL2?%[q†F 0-aʲBj"Dr=$cNJ- 6x@`jA[Gkg?_g{SBBM2Zxݳˋ;B˙"&㦋!_rvĽFG }T 7 J\PRcO/~kuS} }ӴhHQͮkF\m}7ziNymM}rܑ47-k~ZV Kr׷nidumYWɽ_[uӽ,cb( ٌHy$yײ,ɒdYF4'+4rEYdiz}{0MөzooSQA& Ce'y-')F.QϛI'訬ذ] &,////ujZ{IZ;?٢mW82mwV7~7./7?(I}8:=0v{Ud^6KER|ϘêV,ߝMu}1rXl^jֲKLˋwM'%gvلaI`mHQT]]2yٷrAdi5H_Fј]tqG1y0q!%%D ˉ,́(BNQ%(N1F@7#=UΉhɎsrl9;CbcJY@)8ĕ0CSDX}oJF>6 x2eǎN=GQ2+W,Y&.MrT55E{E1tNt#K}IR,u,wruQdʊ}(.~X-鞢77~tOOdiˇO(d9˲$I9>>v] 4DZ)$Mp]6l}dlDzƜrlⶓL+ -bix,jVe7]vttyOS[? 10Lm\|f*{I '.q'ByA$Il޿\.,m$UUiMۼ{_6ws4q$vo_7m*?ѣ+rFM8zv6j~yE/O1mw~tDmULgY9ݤauxumWU4+ںjʼ~ze9:w/Eqda^ʳw߿|Zf$n@8Kch=99#$S]d,فy /H8$r?xGg&:L1AF1 6:@ےl ӟ 52E2hEAfQqBHay3dȿa=$EgDElzHwBJdWbh uH1Mb[p_r-/{{~ێ4.Yu)m}w%ZY^DNG&eQ$˒$}_m%I|qXF]']ߚ!+]Uۖ~rs/_+My_ 8,koor#FwM^u]$vIHn&7UQ?Ǐ{k40HE7N 0,>A؟@OAVE˲>話A}*\m#T:ƻNdZ~ -iڮ4k}6{-$)7‰ۻoOWU(kΡDm1VUmۙ4ŷ~{vmcMz}GrWU"C[,TYn^QheYkʃcESn}7mu ²ı0 QdyeyM]9 C]OSkϞwl\X/0!r*a1&qQlv^W՟x`H}X<VCwɭ!9%DDǒg#wj<0IQT&ģ"91-24Q_$n Gs#FHB8=%x ="lS3Fd׻MhtUgF\s>{ZL$#"krL /eu]Ǭ-XL9$Wr͸!L2{Ooi`ż PdYZ5"L4J L=Q@؁Q'ˏ>JVX/_}/W8~mfXQ䥢(Exj<^FnV 2lM%I8 ogiPy[WbrmrZb<^FkkxiEnY04urEڝ?::NYxh5-m\x0=JL*_/`6:˵a^s2i24rM85k}֘)$p,rGۂ\(`rҜ'pgQySKӤnܶt8?_.'?~aݘ/֪-ck~[wo~\Vjpv' CUQJjue>~^E~b*P*IU|Dq%i}o;˗S0dMk[VTtugvg0lmmQ aQ2׆n)Z Qʒ+]gв4on4JX0UHZ%qdQ FӨϟ#E؝hs1$5&,~f&E̕x((k-즸K:2 BUՂ#8 f"I$Al=EKQ8MJY@2=]D7O׃;^zWG_\^γjVjQיUUEUKxX5lG[R]Jry >x4Ȋdj]U]%EU c\*({ǽ~vXt:h#q4]v8NÀ#(…9jċ:$1EI$IFoI8jDU%ٶ*U'up)ju*zQ룢(i>"E?[4S%%-r@e%?U0Ql6CZUU]WZ$5^p{M4e ˲wfyXٯ?:2tm:YäU7n|h;m*|>e<'WãI.(,+,T=Y29&) MJ҉Sl%w5Pz}JEYQ,9;YU8G膇 j6yEQ`~;ڑ|q8|\DwѸg^$/=}&W۫JU8JNEQ%I٦aiml4$u_0u MUmӬjYӴ4 ׫pgϲ<̲E ;wWѴa~hHr»C0%do'},EE0 ,0XizuuXdEkγ`|Y\UG'uja}@r=xeyqqc,/r9y0]@z:&Ia^̦'O'Ϣr`wkcUwUuݡizp4-7?|W(ʒ4-:/KMU>z778yAhbk29}觏|qzJ8ʪ%i{^xbc،HFjwoٻ^c_<Q*J5rkV]І<$NQ4-60$8¶%A6 SHg9<:zG~,IRReۆiUZE|뚺\ݮie^YQVR' \Z$eY/UM6tvTWraNcX흽wvF8˺ȖX``ٞLgncGQ%T&W$)vl5:HAP;sFU!hp+d*X'IA10(Kjuvv6WEfi<PVLi]א?W_].$WlUmmǪR;NCeS7}Ϟ_W8+,hf>|pgJVUegcF/8m\uLoN<}njgyln\dN[|kZò}za:VbYaFMz&sPxJ+E0eONN}o./$U%F*04-p2^rkTy9Fq׵gt.rȪ$V2݆9zlzeYonX3DeȄ`_:EMl~̅"@'6)Pn,^L/>zęX,um; jLuUUEZFml Fz9aG !o6Bauprzvuu^QDU&/ c[iaxrr|y8\=ʊh F;Vs\_Qd˴%I,0t׶e/ׯWu]յ,˝{76Qj\n˲O='pdQR%u%uZ&Iwo>;Xi^uconmv,(eY -,R&H1[e3LTo>#1l/!ԁ0f 36I A=$@"ՆƝNmM,#-1oL"w8*F :(m3f";6;aNR]&ṗSc#0բu3+L\[늱/`5RkOC-p6-ٝVIEQ`R?+C" EME C~7hA02JtlP8 )}~lc䞠h ܈Ju\`tEib c!@J$'? uĹęvJ;(qZ`!T[x`튃 .KNfj"|"::u-D5](8&0Ft1[ga3Jzlxz}ZӴpeY_/tSO$+|m˲e08.pw\Eqq~jHuYsgw]pn[m#B3|R QB|Y_Pi>Db8pyYY=[CβD}]wT MSdj&4Mf)$="OkO&'oYiu)Ɋ몪)K:X,ϕ XaPw$IUժ^WMMej47:Oܲ8kIU:e0tI"{7/_j*r,wm6:F8^O_i׏_<ϋȖ߻?Te˲$)m}?/I7\+/G_󢼘,߽};weٓOsj;$MjIvVAnk AD%u8VW/_M677p^pjjјFoբYG a%1pdlf$b6 n^s|>IZLJSAU,jHq!@`1a܈c"C̃g bim @:1) ҍE<>9C\QL/I䙍\')E3v^Qd qidž#A5$<C2c"N5 R| ,i/fJA7udۢc9& ¢BgQ*|./wLBU-ˆDd\WEկymLV^ F',iƲG2K1uu8FZ.)ssk]i* "-%^Vj:==yuvt|f[f4Ofӊ̰U,^u(ʺÍ*MS[.2i6=ǶN:[۷Jmڶe뺮J#ka*o%e#(c5&'>͸L@0%I2ͦW"RCW۾ےEflZ~-I;;޶a6M!Cy ܈)'*7,/ @SntcTeYuQJum۶$u^.ΣN騪 jTEժ~W2˳|VוiǧO[aLiH4UU[/>8=[GYg",[m^heqVz{>Wgdyv@#IRUպf;IhpwmU%eQz`gm(X/="n]K^m"K$TН86T@Qt (M֎m|o;'nZvv/_|ג7!eڃǾ ($ap,ESmpa$$e.p&'ӸlTh_% o&ry~wDfxJRtkR"l7j:Sbb/aȟ@i'ъFs-YO4a65$ּ"^#^9HoXyN,<CE (9#{5D XhI"ڰqƄT/Xj`2RXi@'Eq \[/_:?}vyE%.°4lJ C/,{}odie6ΠWյaXאeŲLY6f!QU.oiKȒG(sE-ch]]L.$Ns9he(cۋQγ;7Z _(<#{<SLljefEPya6=J-Dk)M,]ϣڣImZI?n}ۿsvzyYO;~Nd})LTѶ$j IDAT>}???,ڲԽyQ8WYGa,˫Y$qtFp{0@_(fJ["48 js.wH\H%mAErQ( B ) Mt1F'`RH9P"kr@Uq`o qs bY\u5\jROK$RDH^d*4NIӿBfkA2}W1`HF KQ2vH@8Bz%(iC;&}J\{ ъ'V2*]g%CZ)X ^`aQ *fӫϞE)Z]y,)8Z흞^yn˝1ojUUaYfQUUR/ŗI%VqQJ _RS:: IseYZ`*,\ckkh}Uux4ݺ}=1,XN)?-B6&h6eK5c㸚FQ4YUvviYOn|EA;/5j/^QUUGQp~G۽[٤۬kݱ?~OtMw1GϞγ[7n}:bH4W/z;~=jTpKo $Nf>{7%Ev4odEv}Ɗ7ڵ$fO;Ng?7?,j@z.̫Vj(`0-ƶ~bݍNU4^ufT;ap1Bns]0 A-G 4JR+Q^B,ůcb&+]-fE˔=",-3cA;tNFs%ب#H)[0d ⦨|A 5+"rv,%8.N S1\ !(rq4!B@Z~|>6r/ 1QT.rqIQ԰m{6d!Mu])-49E P$Y@ln&+t?14M*Zl4v1!&;Y 7%Q|#۶auNOh,!%D3kٶ#WF҉㘝56l  j"zDJ"x@99EvfqZ^XlIp]F{$}9m qQ<)a?‰.z[prPtcC*g Ր/t:{{65-K^RQ0 KQvFK,{n]W꺚eYuğ\K9S/R(+1/OS(cФ28(KB$jyu~hFS7[V<[߼5:TZ-x>mFϟ@z^ǠDQ\.$...7`l^=[ǯhkj5NT݋4#:41-$I$c;L&6p^۶{y ~(47 ۖG߼c[[na Ir]zr8_9o{o|xo:~mvjyaۍaJۛqɲѻݍ}Y4ɒbukA3 $xD ^J%}1fprv7nem`lNNWCV1 @ks1SAL+rSȷI{%d2D,OG)Ov 8:r lO.TG;_:Ư恊`1c c~Hf(5M"wLns"aLGhH7T\c^=N聊z40AL@Dr]7 CTϟO8^.@N߅Áb58O !=0a$L`Bu!*&Z)΅H2E\vK^gͺ̜Kb#س,i+G %6.PT-xjf=" u' u]o6G]]VbHbH鰊N ﲶyNI8/DB EO;N46/Db;YP.UԮ_ę.:mVoN,ty>NEqUl D<7x$'C tƘ=?J Cs%b2*]"!Af~'JTm)izlQW"ǥ: B0G2W_Ri;~q^s?3e#Ϟ(?l1e9ǂǚOc߈<1Hϟ=ydkoWj,˖~{ν[[v86,CfъH94q"O$ieU8A_YTMn ?C$KoyrQIIN$oܐ$),Kjʲ\ٳ+6noےler,+UU}O,304oɬrpCRhijUUI:zaqCQ44UjweTk>~qbdISNwTUgÍNM979@?,N0f(Z0鉦ۢx( EeDXoX̮಑Er-a)ѳdJbrʔyhu:mUUW'ǎ: fk߳6oX@$*fY<˲^*`^ӫbݛݮ~_nu=o˲vQi (UhVe_?yеv-G IeY߾͛[/p]ֽr{nO+5-KYib}zIY7.Y2Vj0._5aس$^i6"rUj$Ib@rAd'[%Ԍ>/Z$L,D'jqۜi6 !MtZ#꬈@>bc@$ 5+N1=&C.?+: ~y(rIKɇ`dZHF4=@8ԬAb Sz4"$Il"6AQ%rpm0[xSH'XB(c]%!=y cgJUhOL"̛%*| ]S\c?L7oJ:"jaOe)6?<a o(Gz' H`Z~v-" 8wn4Q&ćsȴDĈ5x"G!uK68+8X麎t+L8s5P=-*(s&.JG% Sc38<)0y!4L&-aњJ\.OOO+I;{{8 i4XӤL,E~^ՠX,677&奢(:V`y^A,W~\*7n} >eٵT˒fëjd)\O8L2d3XvڸqݻvʵyEEV;/$Ϟ:ţQ; Ҭ|l;w7^0o_wWbgA]e{]7Oˣ{w7fUzuS7Vn#pQф [V,h(u/SUrz;{k{yYq(m{4YZj4Z'P%#&Lߠ]t8Fלcȳw8ijQM5o8Z8B.8{Dc5l"7؏o%*1ǢiҎ[cBy6 H|g!KP!>j(M9PXӗĮp -ΘP EG lӮ-irDD9Qk4V҆%CE*A MRda"sr [ ˃{|%`E8X81rGQȻ*rX IMB 8m%SG!x^& cϲ nDw2~d*4?I )ZD%g@GD. rѳNuPΦ( G" H~6O&+l""%&s):r >YE_X|$i{ .2 66o~7F#tA)OA#`@S_bŤmpuąag"YWi8v,+ UQm~їU;ʲkU,4/>8Ɏ/_<<}H몊e)$M'gliZ&qda,dI<"ˊh.'Q/,) C[*4mݞn,w{7{EQӓ=uktyׯ$4iMnv*t$\.eFρwG$<K]Ԑx[;*,w~8ދ/gg,[,槫(i<=kRp\\,Uǖ婊⾝({d+iQJ٨rIuQ1E4S3rrbٳ%X$cV2XxԜgl8G:6'|DREl܋,tJ /QwG83 .*'x=$žL">yj _% aku81lV ݀XPl3t jBA~'x vЯl6);P2.CIN0 !يD)iCj IxcʲTJpWHj0 fDu!C=>7:>ܩOl\C&S^v$65n.7cfpZ#iGDTC8޺0(ΊZIx"k (dY)d\..vAN3ܧ `P#A!峟wyQsgoc렮( }ߏ(2C7/LJ S889_^Okt)Re'G?-f/4/JUUYb~Ndr*x6_>vrr24)GӻwAw͇i;֠nKN?Fgy&O_}^u;΍w]he<7uMm#yDDG[28^ $ VfG3:8OV*Oqx͡e5]kZpATBJ⛅,gZR Hi., G5j/(8KF41F\WE81G->|&lY wEhQGUv$މ+ ,6yERLh!aÔkc,q~(2@VJndܢ,l?& Q4W,-u"e+ITM7xel;ԉe-Amb":$Nq2Tꤠ&:XIRÐ.&|[cq{g$_&SN K!g6]NX͓F{RQ`PZHB#,9HD綧_9eH}Fi!T=cm⒄wһS[z8rsLT4pg뗡|1tq>`8 )z̢@!8///_|=ׯON_Ϟ>ы×O&XQ|A&,MUТd'WQ4)?de$(yEIe٬jX@l<Ӡ/ Fj8r\xq7qmnKumNUՒWY|'+۵tC{"K2:I"V=_\I;t^i4n״4dYhiZUU_^J)˓ ͳrocz[~v[w>$6MKb6?kv%IӍFEIN/YV5۷sr~d()`0|>6j$ EWWW뚦E`vwTk{\hbU#y򢰝T)B@6hmneHgr UjD*QbI42Ly8Qa["OpX HW95ͬlв]haamUBRdAcЄ bP$f0 ȸ&I4@"B3)4y'|#h!#><<<:z~q~=Xϫ*v,-< 㻺fÝ\[to㰲` IDAT5\$~EhЛs&"⋄|ӁS~?t#9.m)I59 0o©`b ِ[Xӌ4(Kc,*c@$lBLw؉>DCBGJSv!磢xV* B5^-m.//yst"6EGcQKp5% 4\H%ck /|l6O&ai~;M\c:]CsGDE,v؀#M~6z8s lг# F#ib!3Olgi}D+Bj`W B92F5ḤY-D Eg=S)i(N`+厝IJ2Lh0XOI>B ^1,79#ԏx@6rz\&x0$.)8ѨI: 1}^!,'#DZ8GY"†m۰Bb&F4/_/~nsd壋"|ċe˫`6Ӥ*lޭ vN-^ -#2B1bOa$z+̈?R [vcnllTUuqq1NE(˲kY @m!rUUU9i{f=I"p^4uep߿>ܺ9vuw^FqQT(=ѵ:W8JRVf~hS=N ibʼnQ#u]:}p8N Cm'"(eYjY6: i<̲.(k4 - ajmETVاhp1nd&p4Ka"ã 61L3>O@"!9/ 8ѯ008+̀?3oˉ ` ąz원B8x#OlD|?Z~ԸTQ&|;>CD3($ns xx{Լ > #~l2#GI3U|D 68J׸Hrb6Т>/6d}pps esMmN~1R4@tEUV]x_QAT4AAyoβ cŨ! e&tDkY8`8VMC B(l"`/m9cɎ&gm{dCvy!`gQ!\KpA{g`:]itv17M#+UEQUYacwqPN1}&ע#()8lǞ&Ij A''BP:>>}ɓpq\Q;cDD\1(*έ Y X9+L9 LXXgggg?<9 bXēiPUV$u}`Ѱˇ_ 1\(6lLQgdagf f #e咰A{$D 5("UJ5иv @%I*ˢ2ϼFzyQD.ʲ׿P7y8Z MӴiV*գlGf: ϋ4[FC,]cIJ$-r$o^oXp5Եijwoir|/?''GGlL64+l|}hfoɒ&nEYI.ɵExgN;{g:e="&^qMTUڶqcL.4Mt<`ZKeymm2F6P 09-PB8=jOYzg'M*܋ȋs{IA]J<(fYDe|X(eٲTˊtlXQLgǓI Iҷq{iUo,,S2I-I-s~qzu~49px||QaY$it&KM\׍̒hiq"*$jFjVQu8$^ΧO.NOrUJtpc0h^fUYU j6lMUܽ mʝzFo~=8{ǯOYn[o޼ɮynWI5w9Rxb/7$Pyo菨$UUe$ɪԒh%QUUIr%IZua.EJhy!$ #j%kE"̻RdL2/яHh_WDrd pxOZ f+~24pbȯ"DYج$cG[AU+DQ6tD JA /ʇƐ aQQFX=iFЅODYq뵋BZ,NQf^T5 Sw@$9AF?@FQl<&RUEjjYj@o6, /LyKqb- x%;E p0Qq&q1*!03 ]<\_Bg DEvq`GS d6p |z,D>fT?aNLrtI8tml*X=2 V<&@[ w͈W5C4iV@-cD9DZmO~ 90&gL("' &X1@v9Mx) ubR9d#QB vf,$Ԇ_!FxY'DW†,_.WWWuU|o~>9s᪊{cFC7tu;ahֶpHW0O4h䥲uNpH Žgh?߁ֵM'=1cauCu89ѨyqE/?݋T߾j$ID+UeYGLj~hͮa$N_,e.K: 'AYԦʒ(Yg)SRqUQԋ,Fu5 666o+6ZࠖNow0?o7ۊj*:e9jH&ju]YVU,+K(,{Q\^ RC"1x#Hck?j1MFꭽn1j>;LQ?n$,ȒiUax.t+mHU kgoFп`OAͫ)ĜH2x|F)FC5*R-2o7/(zlFTg-C8R-F(Rɔz/ܘ2mx; 4!H?e8&EW킟PIq%"VAo d98(yDiIRxb@ ÈB7. ӣ I QE9hB ȄYcP|9mas%+eY~#c*614nf=T_=ɤL$43ã*S]PRDCw@Ez)L28 ^yCob= Ja9EC2lu<^f<ܴ$r}@a|DWP?~ɋ`0{ufvh|sr<~pM85CF3ڣ0XV,8Nfɨhz=@{P $ Qg00f̌RAn&tz4=_O?`oʷF[ukY.u(%Y}Ep=&^eYy^-+VUeIJ|>={PO zF-)`kDIOatvwwmKIVi1ܾnY^?KMmTUp̦GőaʲRUu,%Y5؅%I?Gwʲm/` 4}1)q,;D:%IZ( 5M V$: Ugk"s]( г,4$2K"5-(rts S0} Q J6.;⸐(bsA.0Ia`!)$ёV@v)lIJE!K~a~` '-(>v $c3ac3( ٠@Q-h`@J]6EP 'r)GT*Kd Ǘq h3iĖ Zi"xnh0o_ȁf5V 5Ą'DZa=3hn/"*G?>L8V1"fg:DpL<㓓LyjItU577ۻw{uz7YA ?1'y!hwC#<3qӀ&8mEY-ʠ3AaAfúBYYE'íwQ])EeeXvUUYVukFUUᖕյko>}TK +5|~$&\}PjJ*Ħ4Q# *Ԉ (B(=}| 9[@qns1HP%h46=/#7;; A?X5}KKMg`(jڭJnԗ kY|>)@ 099L&d0ՌXt!~kh,n--9TQ*wMZvV0HH*J^jn;.{E `vLU;r`߳8Nk4 V=yP~d?qv }>7~S-:a8V9,F@0ྜ AxptrFDi2C*ʛ<"'ˋFpR ,AGO:`K$Y4^xRR,uAEysܷgj!` F|b$DD/{*O&plמou ȥdE2򇬻2ԥV\ t0YQmEx,;?0,WZ[U1V k3zS4P1dV"&Ta?`z UvzqP*@MoO1$IڑؿqVW%hp:3F!Xi;jSN|'N,..if=bMwg ET|-d* v(LR2+NR^W\ة_HlɅTrJ>- GYx3c3Br^Hn9kCnwք~/M Tn:v zPz}5xlzzp`JX 26?\8htn.:fj0o4zR9`4EXl||M.ޒ$3L&)Gl6;1195.˩/bdz՘w۫nrOGԯԋ[6gFPS\#a߫P8i/%c#BPVA"N)NCP(+nk5fˍtcrBh+Xd"`5D=X! lwΑKF3g$+ Ly*Bv# mm .RPTVu; >&u*v| ;<¯ag'ن'b if:Rpms> 2g5D"NqLzEʎA!Lf Akk5E? Ca6^_;YZ'kۏ%[пtE_/o5w_4 IDATuU0nxh! |Ζf#SVLGor@:."ٺ2AG8_H ~EwT¬}:.dPV\VC9??IR_Xs]wӆ`(x+^qf% F=A;uqv]̯FRԥ=܇t)Ly{*:VZ?ȘKӈ+]m4>?c<9~G'Vm]񼉱p$D`^ p8PpPC .-XZZt$v]_`=5[:ua֊DW$s|ŅF^j5Tf0zaKВP'_D"!B.@0G׬/N'Rk7~mH[)b RRq2 O hQMX"9H&_u]4BuP8T:XH#"䤹 Yr 3Z1' Fn /1Iy `$E*i5`sii,՗ {y].0[E%.o̱)Gb&2-UX"<۫C*rV>fE ioI.&E"R<p 4hWv61NXV^8C' wdv D^x v:@ î?w\ ^?L s#L k}wHe@KTqIC;Sc@ k$|c 6u>$_ˋmP(M;lP IPd5ivemU,dud^=MxknzrA?O?RpP[ O %1L om39_e$.0w~!iB!qȫ Q~hd)1go7,g\8BA'v̬dĠo4,UBILrZXWPлꪫz&c,.i%xLʺ->Ai75=k =tۡtHkϺqc_ۅr1^Lgstn٨j{GFW7vH8r'u]e0N,cQFm5UXY y8rӑ;Si+yG`=4&@ @2D"0HF&ũիWONNi4z|)tFp Eþ몍ttq^{8RjwD4_5nX_`tbS_ zOH*K'>8 4i[GP˳WM <բc/Ɵ=LFCM 5TPld 9;G @,esB!NOOh4"ϦANQ|>^[cdZ9ըp|Z?dr ;@[P~)fWZGbq~z#hzU ψ(qǹrsRhk ʐdE%6(nha}EKiWkb mD[ڃ I78zw;L<&8 Q{Q48n$-ª L^=` ,U`[7tmNF{X^HC&'@iV/OV ---lBĶcgT(`d܏AKQ'E`G ua886SdP9mܴ.ǟozn{ á}>7LeY4J![r`d\t5vfzTNȩKeC7䑰bt: L8N$V:G{ H$[)@ T㉢ ^;%{N*c"n׭p({gLDr#ScgsX"n,,Ԧ2O۔ʮ\R9njߜ;UCX(AЦ6ھ"Z VnryaAR : N%=H$Nf9`$! $`0XW:榃BH:&8vo d(úp Xm#ƁxV~µZ =hX{HI”NL :dADGY9nXZZ1  o2 CQl_^^)czCf 4'_t=1RoCs1‚J we-tlV䀵>'"'cnQ1Omv]$% q؋JP6>u v^ߕ+9Y[e"kA=|<4D5RIe+@F@8£zKj H5kO2+qaEkW5*UT?r0O]1CB%۔vPRjʬO2%#JrBrXZ?Upf0fT< ^y3_Ig 3j3t;KV\6lVm8w RL2<XWh0ݣmX T{hFt":.rZauQytqR2}k5;s,ի‘\4>>mn?~j-Tgn,.WRg8H=_.6'j/SStn-`:3;3G趗"7X48R)<iNkذXa1d%LؽdH'GkN2jjt:qv]n0~iaq|N65H9!T QE۪ORzj%/Z֣C:=.'qࣤg: [QQ-q N[o{i՘< 0)6_kH63p`HE%L KPT4õLg6$յ+1 1! c8>?0ɬ^T_@"߲}PIbҰÑͥnGȨlY'0@"b(T*(+;µ֢iqKjHin HQ;j^ʢ:zOXGBI􄬍o즺ݮht)qNi'R\^Vm`:BnVV(P8[5*\~Q  jczP82 NlΕN{qZmy[O;m4&‰/W<8Zە`\w%x=ٞN  ]s \j18GuDͦdA Cn^6An-^8ATxXXh.-kW,&jfTCgp;tx4e5ZѹC3`gW H$C+ε6 іWZVmrMĩ¹0Pr~./^\ ue-F^D>7Pnʟ0GOM`E!#Vi8`ܠD%mux Q-`br>50bY# ߎ+A[]X8Z_Lj_IRySX %C9Qӑ~V RpPE\ǧEJS!MEj0AmwTi;TtLmzLGmHȐ5ր,϶)53FnX*M4 uBB@&Ѷ ~Q_b=i/vn?7W/WáS.7N(Gji p$ظqu2=/n.#h67h,Q`S) CZ*vs* @}{e K&S a@Ol~VDN8v_!0@)^4kwvt ],;}@C W pl(Yr<{` ]d6nYXXh4Rʥ`w~4owzd,V*B^"3H( >ټu}at:z>W\f[P\3 0MӞ'{P9DEAO]K}zJw+ZQjw Wt5ҟj5vs熂Vq|>?Cnݪ4ssC˥bjuNު׻ X1EѬt86F}qyqny==U⚡//,6-1f2q vBv*!˗%jvd;N B.^5fc)<_Ng`>*D)(Aı$9PU8X0<؇Td*sgfFժ@k-I;T ރwDЪ2-ެБ p}^iD;%mJw (@d'`] 472cꨝ?`:AS J p_{X c$("Xו.)EЭ'E dqDa8 .Tb8+ب@^ {^*jáNJSkus=Vou{N?2dR|a]( "D^8phffTɱ&ȔnK =ήGV^#uʵ>0Xmdו =YXLp" ^ p!Nt.@38ݰ7xGS AZRcGoͭ/h5Wk9_(d]' Fh /=]*:S?R=DEN n GzQ #KBBP"9j2vM5 {).2K]g}4! XJM@8EOPT7쭥V$'NZR 7o3 KpIF B^JL(͹μBEV;z\s 'Gˬ# iG)hjX*-`܎G9[:q80K膐ڣ\LZp%[Y*4b. @? &gP[z:jUsqˋV{H4Ө֪jyrM.`s*s|p(uSK Ǐ<{:8}>P̅T:/LT*trG$=D&#:D%""5|}m0j_-S0Zj.dV(y o chCLC=tz JF+%u~1oBBt>zݚ?xx``\]eSk3ٱZxwt*Tks3{[6MWdWz})bD">/u*cU02#ᒽJV\ ==ek܈,QV(+0)sl6JDӦ%煹=һ@U[[FYӌ@XEnn% PbDU%G󏭮'N}hfM4頊͡"Ż[lZpZtqҵy&.&hB0W=\ 4 RX+U(5BHо͒t 0ڑL&BZ=!&$'Yj+ӂ|ó(5Fe,3x60YkfO OѹwGz(phQA׵$pȊ֤56ʣgI-۴u$fVPCs8VqX5B3@|ZB+/N%BWgL`ݖ[d8zKVi =;7_ߗl{F8uk7`qD&Z[=zlUdY$P0d>[\XX#?럕 ~6^Cq HrFB }LF, :0PstDOư`hlEnAht[iYED"J:pn8i׃H Qv;?6}akNTڠ zVmn8*չjP,>N9zGM`#[Vy" *1]*v;dMcS%-rCrAd͛2| &er@0tXcJbZD3dbJ7g[abǴ 1\jU3P%8fP%W'WeTWa,牯ɨ6eJ­XDx3YD"3s)#?,FQE_4MC>'NtLL5\IEN"f\܎Ohv!N5ІLcn֪:;sr0@0ܬ<39m* 4-H4>t& 8=i|bJS|0lk0/3>ߙZ9MǢL&NŜ|,= JwD i8CׯcEұ )[u])my5RXꍪ|Bu\o0FFm|`0tڭ~ fRj<TzpЩ4'ynw8:6}T2\ɩDSt>F(VNi2/"7+}t:mU(3r/j1mHRv_ GyV!׀:$)ZAOo4ܗHFy40'bnqs^@3& Gp$9 ,0X%]ꯐɎqJ}ȻXd[BTH I QȆGBH AT= Z&4 d69J5A iznSCZD7LD <`=#kJgZwkBF(Ό?S/Q\1MbBbIqXQqG%5!'V^v:bH3qL%-1V_OI6&j]X3 Y"VMZFd4PP#"n\r+aj3$Vu{vs:pݜ׫WlwgCp:NZ*:uravν[O(E‘BxN$gJ˥奓TWy||Z^BbPrH0&/מ~(D$jпBEEajjeB4˦-!R{e ∲~R}s{Atzݞ~z^v:x{~g|N4X.5~'rD*U5kWYj5d*3==dz cf-lpWTb{kTEl]i9nl|:LD"H$ڈbuhrՇIskMtrl^7+҄o;)b::*1㔄%-gdz}f+JyrhSrh ">7\_u_w@0Ju};s۔?KŪz&&'ׅB^xBĤRRTVnuL͊"p]GeFøaAr?M&+Ve'1 V(8kZrJR;H `$v qK_kKsp .tUS̃-;L8)RAnPBZyc$\ 040 _VQ(kaNi2Q^Kl??0U[FVKEUݴcVVdT|0xH (@u xw;(hهSl!⣭g- fU٣ljT§zUYd. umnLO~Gy0]v*"ERAJЊ.'nTRBUr<;;+.0yTj`[˃Av]jM@F}qati{`4M&әLZ*:`F,eA]+f6E ~A~Z.BdD(=l=A0\5HbuV@nJ   1ڭyga~;U=/2:OР|r,ΰ?H%bp  W=|8:sr:ԋ0K:+-0[ҀO;!`g),|;LH d *Ά'%p2y#[K,tY >V ^iI.<,y(yW^yJu X<2QR=%ӯ(鎴2DZkri[6`ћF4@/V>:V_ZHLu93X"}VW¾Ng||\?Hh08OA۩^I&—N?<X^o4ZNNۯU+-*?MC¶BAbX*I$|f;͠#/DVY3,,wAtTIh'!$uP*K 8lhX T*ds~qN3Bnzu߫^#ќS0_pD:~hji;'Ϥp$dD<r`Ȳdy(k)I,Ю#]ui= xp3=q|Tsx)`TCO.TL',MS9 VP_.z Ǻh4k| -s)BiջCh3&Yu(RY BQ~(J%}'S7*XVYn'N[n{qnv=_?7OD" 8 ʼnӪh4Gk;%\.>2l:5R=rJk|5 fD7TpOT[B|&n_81Hp}`A!$3XsM^q43F g\>j+itR +v6n(5& *$Ai( Ka@M~!&z6imO&+ % 0mNJX+!EKYw5PUaB/DDW+\-]J#?0ok2j tu+fȪS)9A92iND. >0]?e{ O (>CKb[+=+*%;-"H(a\˨KUyBmm!XB%#U00 4\\B$ |JfQ6IDɌO޾vتS%Eϫg~rk`vsi[|כV:_ X>6Z06=VW*H1r$-&mzzX~(ҥ> `"!Bn1 Vg:sD"J‘m,.ۍX߰jdP(i][5|##L6G'W{< o~d]0V0b˺,fBxCP^,`Bx#*VNpϽ:i20tؖoeNְxVdPxAWO7EIåʆǂ85HpVIh0 ()VK2q\iڷ2cdɹf( X&oǠ H}gJ5nq2M |;'A/NӊMFEWCt:+ s0hTI~MR_yh;.:}BRaRT=!{jjueulLkE\"B#y6Ev# \7 ]XYh[s[qٙ$Ϊ i^Z!a-2BBQ5tb㔫#=G21uAiҫ2Q"}_x0XLӶLZ( SQjPW!aF AY0ծePٖM wjMUn<G…B! \.뺞 D"xh4126Ϥ'vadlml^/,,8399zꥥ%V6.$n (EvuENqd Vښ+WͶ fd. +yVv#|Ʉ>Ha~~&J`>?4P8rHgl=3N?f׮_y۫VڐJ%dۉb###"PdPq""ago (Hǖٸߌ&Il^ |Ш݁M-6D'8S埢D 0BРd)Ͱ0dV"8sSeD! s$:HoBa;*(;Zk\=G=^В,K(0shk1B#ؾUn)êZ%z|Z=tvrh6?(+ZHKK*/ G`.b)e b ݻb>+ӭ1t*C^}'Z:@Rd<ZHz*FtYc<^D\XsȤ~dSN.5}wF )>8%ځCrp8\Vi+T@2 eZFz&St:[֭ۚΎnذuSl-d`>f݂H f},|Ѭ<~x\TDm +F6` F8x#r ť,e;?G~@h4bv=]שTf=/P(nN@-S[|T<*nmZDD2yiZ5B 7YŊ1ikdmV<g2R]z+,Sml& z8ttXrEHp@T̑E<zP6pUd&,fi:tT\4}F :Z^2:ّ1 lw%ؙ ej^(nSRg R=/2 iCOUǶ_ZMBO%q*B,̓UK֘Br0x8B5`LZGn "@Эb #tS[sJ;o[TM:YbyU+MOlj`V龺 I y(t/3b]}X/d2IrJbͤ ' LV'|[6&0LLO^gEg^:[MKPh3bl_$:nf_R;.JҬ j5 k먦Fj owB^빊J|܈x*f(.=dX8տ(A=KśG]$hLm!mBY8Y%=`|KaMwCI‡nf)el6S,#d0vigfrPhrj8jmdJ+NE'фGϚRAZv ֌AGRy pOC°qUvVߌ1"HNr у\bd'AtBS#0Fy,>:{tXXYkݽyiZ> ڱ݀E)/n=,-Hmgʙ+yQw{,.X-{/Aj'Y#Cmr+Ƿޣv0 dgYz93,O$L 1Lk!@w/VVrQFԮS1H;(%/-51zhP?KŠ,|nj;!G_qqVGNaR Y$p3żZG)N[%:u$ aVDId[\~@!&vf}$X m=PseȪZ䓉T u!';T%08*z|^q2ӖҷH$KqW0XGfKYSfxJ )RfAP(P >GOvL\OL#/NhC'8Sb,+Nnڼubbz h4ɌRcccrUdH;dITBj0#M )&V9GT8Ŭ/K~+)U# 2"@BLIGԶi 5$fcK pq2rX[(;LzttjBD/l`$茑rQDØĂB`!!t y8a>Ix St{덐ՠiIB&W, ߂ Q's=oqlBmI֢e 1 `0{*B`ɰkdO-,9?p//-`k`eO)7+"UFi]}q5 IqP-$ie-d5GX Y6( ~4:Ԕ#iM %Tj5ja@ڈs>DUvpM RŇG()@2\₎1h4hfDB|6M_Cz|S$H$":bp!N r mF^ IDATGݘi[HH9PIe>`mIx> ZK#NS:,H@7[+vd63|;3@X)CmK7 G-"@H@#@gЍrJ끅4`*KV L6 HZ'ߝL&UoT%Ze#,i_6Z!s 6fɆ,O:=d6mhZ5b؝~'m)N=@ňOG&հXъb[ Βm]b1 2hB64ԒDkhֲ@[VD"hUDp$}zv| \cD`yRA(0&? pSP[qqB/0t"2!k- )Xm%bxp;.W:_fϨ{۹}5J JB`!\f&0@ ȓШo4@QaILƜ'}HhcY-\qC⼵[oQņd0O8d;i;~rS4쐭#F 2Yn4RjVaBOSB!yA/Xj**0 Z#9fP/r"uBڍpN(ggI?\-{ih.v9mt=H$DEœJ<7 ʆW#Hd3uTm*Kz DEAnu*s '+|[ڲeW\^{Ӛ [b F˨ I.3:u&7RIRW_}Jt8f.FCHp!Zy&W(TZIpfggAH5dÇ75k8p`ǎwmfgg?w}x|rr,Jm~s?228·?B_SO=8G><ر6l{VuE}|ꩧo^(}ُ}c-d88qG}ӛ/~_iO~ӟ7o={}-r{K_ҳ>{YgY-f;}}.;w>C^x|3zի>| B=н޻~d2ywu]/BЪU\׾v=66??>t?Oa xGy3|'?ݻwddS-[0՞~oqnnnϞ=78?S~/M6Ivo#<}sӣpҗ.Hh׮]w}Yguԩɓ{w9r9\pM\NFک1kMMX(ɂa[CZKG*"uE VD'cEgߖ נU|Y>VTBi\fi,񬬢P!`U[㽀 l1Bn4e Cܳ+QI 3hvT1,!J`9p Lf;pYɗA- b83؝ǔ 5qUFʃ4{0x\2b脰@bor̅*nsFF^-s#X[]p̈́~:VhЛ2g:q5X'eiyd<>tH c23 @~8:`TR='mLȼzٟ}=|p\ZZ?l!}g?{^{SSSW\q3<6m:xz׻~_~>`0~0r-?яNsĉ׾gy̌P-om۶=]w-wK/ۍOMM5) k׮=۱c^pGw:]v]v}K_J&Z{{sUW_2MKĉw}mnn޵k7͝;w᷿}k}M6EK/tƍ\ _±cnvo|N谴+bժU;vz~ٳ' wyկ[v{qq]/~~mݖNo{ _޽{mڴ.Oz7y晏<(~G$IQ|/d<_nݿۿ=7n+\q\p}Cv{7os=o\f[|n:yJ:h;wt]+_7p8/p Їַ-o!ˆO?wm۶o|'ܹV]hn*Jwq?~]w/###;v׾&pQM+0no\a%[g,t+j5v )Sh>d8LišCQD1⭂: pGMVꯡne16ZbK^M , J8 Pn%F`BA`dT OQs}X,&0So&#>M,ؠ$XH(+qe "#-"$M zfj z:T{cǎ]y|ȑ#^~-[`?׿BK.G-JOJ;7J%R, ~|+^ӟ4:t( {~zӛ7 9s"O>_d2W2޽BUժjn7J}?|zo7́]ven ֫nwXֿˆ 4լ5sg3ԮܢHBі')ZZ & zVʑSZdI}YݚJk(#3.ʳ~^ch:֞vE]kl61 :C TT@ L r' 'Dw:eIuYu"94Té I-8~ J щ ?Ovf4TVc2QtwbjʔlCB$;\l6` \UuQӋ'G<q#ҕ>pfFYB[~**t[Y^}_ybڑf!OLe@&(Ew?-`,lRU[\.CҴ::mv,ƂhM}Ol]kg_ctI+Q#o0,//k4IOQo׿k4wq~P(8s7^rg_necPP(.H$ɤj@ fff֬YS.sG?ڼyN>& 'OׇBǏΣ  [q!5C_O\ .5$upnhf E?hpx-ׄnK S ”P1 A8֡i tٷZ-,OtRTVr*AE&.G|R^4t,"*2P2cA[VRWI Agڎ֒u]0zDUd MeH[9VK:̌(jdgvՏ'AG,U^ki{aR(κ."nyy^+`TRπ AJE2NSTH\ٸTezA 6 =Jb+ VT*2{o|7nJ֭[7o|g2Ⲯ@ p}^u֩}tZ3P޺u8ǏVsssRƫV_|í[6 55;gy&o޼y޽gqgm61_~gy7t{_WӘJ:S7nRRIӉDsGnݺ5NLL{ySSS`0::zȑ~: uƍ?Wsݲe H gQJ8̌ի_x]ܾ}⥐񟙙YXX8묳HHHؽ{Q:~lj{ 5kTWWĉnj`D>uTQQQQQѤIzƌ?W^駟n߾xiii ={#<2hРnݺk6mڻwmۆ>~x@|NŸofȐ!{޶mΝ;7n:w\IZZZ~ƍsrr| 666_^Q'O袋/^\ZZZRRR__?t8I~م VTTƍѣNJ+o߾e˖cǎ;mmmNJJZ~~gϞ۷sʔ)C]lYCCo=z\rƍIII1b1У>w IDATOvm Pɂ?{~{復n߾}---UUU[n8qbiiE 6o]dICC֭[/ҫjٲe;v/KKK322֮][\\ܥK#G}d?x۶m۶m(UTT|sZTT~cǎ-[lʔ)^{a^y֥Kx㍗^zi_ǏZꮻ۷orr_vڲ2=z^};3ʾYt0\a-:[]xk9+T5]ਘ{Lf LNW)}6H:yl3#_Q$q#!1TGh2Kn1B|l2^X uz|%)`0QVg2Į@G`ЗNLOl"SN!9Sn'A!"_briz 644"e%鑇F>j.uK2zaIҨ cc3WBR'`(!&S>(Q'%%555QXWu852XZ>` ,VUe~Ek*͞ټ [Ib+WmeX}6qZ 4,Jz{L4Ub;:@/Q-Бb:rM4e+oQssS۳1uuuө" ǏgO8IΎ2^>y'$$;v,333%%wާOVWWW'99&99o߾"gqyG}d.99O>q,-H^1tPPǏwttu,((039w\~[#G ĞRծNHHիUtsO%0`sjjj䛛覦&~kРA\&΅ÇѧO:NSĉ]G~'"wcǎ 9sɓXYYYY,8q֭[]]W Hqa ;Hs ho "%ο T-ޝ%(iEt_YHAY/9l\-v|~G)$}}=7"Qa'DWs(eINI %kl[-4QV\ ˻ۥ vkգ/kt'/'JɢaB-9>4JIҽlG׆+ro>RIvkb wѱ$i.f|s{{{FFʼoxkը{"0_aye>8BߡlXUzz9- PRMv,#J ,ΖgAaĘ3sXUV/a֭۶vWBP2_`[Bbe/?Q0{nzlLaG'58/BK;Fhۣ(egg`cV6Yq3ZtD}NbnbT =[bQ%]Mt{^-arT>UT) q*h@;tIIN|#Чx_W,~׮]ǎ{W(cWx;z'Gg!&s0!IJx9T /Hnȑƍ{w==c ˖-;wCF&&&[{8p7߬u; @^WXYT*2:eXv[݈FuBSRR>QFEdf@ N4G޽sONNG; uO.\'?:׶X aqƍn|w&HSIQղHRRҚ5k-'6XYsP[K&ĶtegKz.E(s$pf|b&`,8czO _}+G#YU3t3<&q":3XI(w6##^/:b4v&ryN-%GՓ8']srrQHxJŋ|<ЩSZ[[ڈ(l35 Uh#fO  (+&?8QkFғc>ӊ#HnJ ҝ4 ֙(*oνBgz^ɱQotV(IH4@x Sg8L^06YpH8 Lyvd81sK.?;w1clJHHEjͨ`Dq.x rvW_]p!.{23$!PY?~<,sΝ9sfqqҥKϝ;7k֬'Nr-h<gϦ ]nC9r: 8%N%BQ2hۚaVռ駟{&LvZl)0Tp67aƎa bpx d@ %.%_AA7c/'(߫X@ԿfZ=X;mYX M8T+4T`|x_^UU5tÇtPyyy}}=F{!R}mٲeݺu4xvttVVVO<.G=z߳gO]]]VVַ~gϞ.//>|xnƍk׮'NݻE݃۷%==\yyyuuuCCC^^ɓ'׭[7qĊgfr;,jIs{MG'׽QnǺGDtjf+XCu_w5I" A*Xr3$Iӷ"{il5.(pWIsRC." "#N1BD{cež`X>dFJ# ˦JƫEA8JCё$OS΄4qB VrpbsO;- Q^!3Qhcï_0+% ,"zc_Q$'W 'o'ۃF!Fj-EU`etj6BJX^q]qe[#L NZ'9LT¾Vi+5]iT$o4dQ&gVUU=裗^z??<̘1c񢢢{kmmm7oޒ%K⋗_~yĈ}ofϞ -YYYvY_|G^d*:n6`  hΝӦM/99yʕyyyƦNo^۷}Ȑ!K.ݳgW\x78~xaa!{.k:uà ڱcǭzWg?;7o_bÆ ^طoݻw?SK,4iҖ-[rrr8Ow{}m۶ Ǐӧϻᄏ|ÇwҥcyZjڴi7pCRRg}6;$//oƌO *A_~ƍǍ7qEY櫯%'JϤ<=={^JJ͛_|I&577g?ӟw޻{ʔ)iii={[Ù3gVUU/!!aO>|/SOǙ꘲[ٳ{u?|nƺzcMMMuuu[[[eeeFFFJJrʑ#Gӧ^(//_zW_iӦѣG|/BRRgΜI_OV^- !ĎBEح:|Tu(YMG(K8^4* kQXEí9$c=D5Nh9!'KX<TABBYzq j_9i&T>n D.$8/OGoVo-N<*joX2W< o8瀼8T_ՙ$;8?E!ɨG/{)EEm=;)')m*%WC++JBHWȠUQ5XP &8Jֺ" ɋ曕WUdJ1 GcoAEوaGGA-)yUuƸإk mzG4*^ȪjcHSf|饗"?jԨ-[֦VTT<<[QQѰanԥKرcΜ96l{/99{^CCCuuI bDX^W^ݺu[h?߭[oŊ4R58ҥK_{S^yX󪪪 2, tttL:رcYYY7tygffw[xqzz}o־[F{oqǎ;v4iɓN:xo/..ӟ=z;__}ƍ1c??9fՀwYzu^^^MMoۻٳ{UVVbŊGyٳ/6m /.ھ}-ͻMvu׍3~ZK.%%%7t 7pE;vxxo6Q"Ezz~+W0ioo_pa~o>ݻO>k:t([oo.>w\ 蘂裏xM6o^ziӦM&Lٳ_~9m4luM4W\>wŋ=zO=Ԕ)S6m4gΜ &ݻw&*))a@HHOOwܷ5 u)O[|꼩.&|򲼵D<H1ޅ ;: 2-:耊E3S#1d؞Z4my.6b4 "O&C7!+\\٢l/\Djz ND+ȶb,E1AoT纙6&+3Flq˰?/4S'2g[JAWy<({XR^)Tc)"jr/E)J秦!'%^6""')}D?%s !"0R)VU35;O.LUsӶLje;ۈa% ί Bud%muƯu7:R[;"?=qĨQn[ouРA^{m.]7lpȑ.]\ver#Y,*++Ҳi;v,=qwu??q&{_W 2 5Yf+++srrΞ=ۻwZxW\q3_U豭 ;O<ٷo߂ݻSe&@͡@u^.,8Vx)+-Ӫ pfej322.xNn&οbF'JϯR*"!!%fނk F8;;!/E3I3ڪ(6Jv'FIXK94w줎)QB¢A8a(Di6&K5q-_uޝa%st=$QyDhKfth*h F &+o(O껥8X0B0%ۅӤ9xdlfq2*ݞ|6KF5kojj`FTkV@\ea7n={sOGpWV,N~MbW3 ゠C$b:=eDWpT$---2:}AۍMƌ3mڴz=pW_}Б\h/ݻ7T!9DCCERF SrTn'xbر HƲMqpԩƜ kIpSGٳPadbqС')q ޽漼dff&BGUjjjnƵkvW^l޼yŊWyȸ1n?OXof{я~h?W^b655pԩkMMM?# ${ ݻw_|yIII>})>\pH+(ݗ_n߾}ѢE y.\k׮_g&$$[믿޽{w߾}G]\\;L>]Wd;(j?я͛{^zzD1---{駿⋒UV%''/[/8p`nnn~l2EL%';+nWHU4 [ZR%0jD E29E v3wׂ͒pՏ)Í f"$u:N{p4p>Νnݺoe#?JW{i8R^I솳ׂ]Ln3U^xSp<,-Dq'ٻ.Jۼ=2b]5T-F^P+b 8@g9rHaaaqqqffW_}եKm۶N6?/~\|SNqK/Cjj'>K.f˖-FGLv &l߾믟4i'|RRR_9qľ{W__ߖ9̙3GMLLܵkWEEž} {m"6'lذ!???//mSLO֯_߫W7\pRڲeKϞ=O>=pSN~ z7Ξ=_-ή޴i_ޭ[‹.hݺuv5jTaa!IGGĉׯ_aÆ3f9uʕMMM555?8}YYY}-))>|ڵk׬Y"J?\sMnn+rrr|m۶f;zh#G^r%yqq1t(.Fϙ3'Q999[n-..޻ww+r߾}~Ν;_+33s_|Ŗ-[ 0b Q|rȐ!_={.⬬oذ?>}e]貯ZѣL':thFFFvv7߼uM67nժU6mꫯh{{U^^g]uUA>+ ??ƍ%%%Æ 馛JJJ@ٳgee'M$-UZ ɆZo(Hՙ;]EuW?&9E OU`IְJcXHR8?p7 dAV)J\ V$LCx*:Y{{5 rr`e}yA c;KR] 4l2ĔDa獴Ȁa |AUY9̍q UP/h %©Z@$VѬBFeơLNg QڈZk#Cf+B SB,(xN}•Q}1h2) qΰ(T&E 8jpayl: sm@K6G2AJqT;O$Bm'\" ɢyޔB0UN \MMڋ$Ocʎ$ɨ=2G,HTElem"NLy}_qע7dGJd)'MBu01JXvmEnnSIW f֬Y`Fuq88n%n a . LlKΕCbQjnnÅFɐzgWK$` n1:\6vۯ'kZ;3miii69$e"wUcbL̪)*ƼwQ7 3L$) [7uǵ/h,?j,5'V) ;ҭ3X8 IjJWӡc3J<;hL^O9Ofi쩑ͶUEYlC%b*lo޼W_ꪫTate8&F4R }ӧON 3uv b9bQHdNpY ȅlِs?U222w\"-6ȗrd8HF*l(?@(â,0mXag+)噹}c5 &NPGN5QŹ+1"],+c|5)(+,`DC.lU鄦zҜL3,uX6a%"s\H3@mԒ"puΎwÝNKscCh?a>*4hDx6 u횛rʎR@VUTB'") .Ip^LQOq>jeFfq!ћv014!׈M@e:ibph;n;Kiԫd;aw(`FBGk|;ߜ9s8W :lU Kdh1>gqG0:LLfffޜgӇy%=#qA j#+^eP0 ÿNщA$eAZcȄxlO\ _ge gp+إi}CIsj11}yiyHhp%/{̙\';b } LI@lEwlo!a#r̐y/N;¬‘LJuPqn6\D ]QSfDvcV#GMž0:/\Rvv6@Bk_J'0^8iOHHdIc/,5Sg,qSz8LXEdZ/O" "h'l(! + VF#CI8Rg8.UyS|'XvʥU0 V.a;>@.4sSXj+6Kvvl] $<Ɉ|Qc"!KiAI`JLS8XU%iiIq]f7X΀1+jVe26^E7ϖ .\GPقZ׮E?ex̳;I\Hrf$wZ(RB֡LmÚu1.4o'cQ/eE%IەcM>CEl`GL 6;ȽæiDĔCf Q^\j "$ vcMw%mL8ߘsɣ18=@đgM;bYтIx "+pS=O9_6ޛUx j{ՂS 8,g[ I [dQ!"hcXhI,|8`Zꭋlspkdr, ē(]-ܨjeTlӶ5Z.yYgl1ϼ&KO]#1N/F)`:^'WPhXO(GFoW#LZnRMC8FkI_V@TϤ`Y?&MV |4MΕ@cDG;Μ'K٪f]B>308"6|99C.n0zg;w.?)XqDzu{1@B 1F6fTFF qgf#m^NFJg&UWءH/cyt?1IAL%M;Ʋ>^ϻ&cDZk[BcnvlA*%9ܒy}ClYtfr5ߑ׉rGMd l11ΏmiijVt RjhppR  tʽCm妧j%團hjhI gUQCwC+8,+#`rI U+ZE#8 Ln.cL7eb)Pv? q2!@t-:-=u+*L,ͣw2_E81Jɩ\^y;9 Y&0/UVXڶRODG9Q7DOx*q8s83N CP/e=ԩP4azQVVsFFFe1hQcѱqh۬ ;T",4llG9cN O E-sY?Q9ԃ;6 0*ܹsxT4d{J-ё) ۥa̡>!M7MϴݰGxj=oJg9K)#˘{mӓ"_JA8 N,^^s vB6 }!#lwmC>Hv iݔ64Zx:uKcޅ5@P!Wi4~56N0pGEZf $WEl*.^nay:X{#9X¨hKC7O>8g~/*C!?v[[%ТLr]/;`_dvE7l0,c^VJ*Ɏ{dԯ;N bQV |6k KYh)(yY\ UG2Q2ڐVjx #3cl8A5cQ} :nGd U]5.%@&rj-jNWDE@G·\t3l.S"[qi.}ep !)Ρ'BJZ1Q|8$[毸S8'H= $^-'[ Z]jMMMOR0Є[4[o$z-EX175#lr'f"`Ysjpϴ uu)I"#B`MGar)hքI!ъ^zlbsjۯ{`DMNQp5]=0^q13F]l^:ҏz4(\}/tXZ T^&IYf Z)0 4R #J y Xq w0fTZۙ6 ԫW9 [mOê\ qK"D0 ,xKc'V;eaXݳs#ĎRJ Ƣۊ{G>^Gr#HDիpT\.~8n-K4^|;6`WS hPB޽{lqT)3`=%r4ֶ:Wq\smBhİ&B&bb#7"Jŋ#~3c(EOZ1^G4/;R|q$-E5Becm7J_0W)oC+=45q8)v岎! `I,dh)=s> c![7ό3gBw)ñ !xfBV"hE^E!IlB(vnnDfQg3!Æ Ǝh& uDOdGqΜ9CW4Ԫrc^*!`7cW41JGR9<*Y b*U͙5ڔ555(_mf233{œ?,Ekl&A eYpmܘ8Z%(X,+FP3H4<%ReDn0'@8C,ۮokj*dZ2Sc"#^NV!8F (B2E< f514 RF8k n0+ H߃dUZko WFycԮ:J4v'jheF2IM6* B;N(`#-r9E"#oubAl%v ;- xPaa1싁zOuD{DU 4b*5'1VE|A'%=*|%cίU65 IDATfMYئ@-(:Ȧ-穜fB0mOckUQlBʖ;CŗX58vaH0!mJ DɈ[]@ti>ChLl巢ZltE=DA3Z:o̫"7*(zN_),ȬT R44hbf"'WW)Rʶȳ D]T/Gh#$A'k+ ,[W&4UՑ[yo9_xèB QI8wljKiMIwVL}Z!N9`x1avCҩJ'`\Qy,~FTj<1puTd~Фcl!< Dm YfA!";ƭIǮCۯC?ꢨD')KEcٗo rU$b(vRN18);qvR:>2ʬĂCF>IENDB`refind-0.11.4/docs/refind/FDL-1.3.txt0000664000175000017500000005466212626644767017217 0ustar rodsmithrodsmith GNU Free Documentation License Version 1.3, 3 November 2008 Copyright (C) 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. 0. PREAMBLE The purpose of this License is to make a manual, textbook, or other functional and useful document "free" in the sense of freedom: to assure everyone the effective freedom to copy and redistribute it, with or without modifying it, either commercially or noncommercially. Secondarily, this License preserves for the author and publisher a way to get credit for their work, while not being considered responsible for modifications made by others. This License is a kind of "copyleft", which means that derivative works of the document must themselves be free in the same sense. It complements the GNU General Public License, which is a copyleft license designed for free software. We have designed this License in order to use it for manuals for free software, because free software needs free documentation: a free program should come with manuals providing the same freedoms that the software does. But this License is not limited to software manuals; it can be used for any textual work, regardless of subject matter or whether it is published as a printed book. We recommend this License principally for works whose purpose is instruction or reference. 1. APPLICABILITY AND DEFINITIONS This License applies to any manual or other work, in any medium, that contains a notice placed by the copyright holder saying it can be distributed under the terms of this License. Such a notice grants a world-wide, royalty-free license, unlimited in duration, to use that work under the conditions stated herein. The "Document", below, refers to any such manual or work. Any member of the public is a licensee, and is addressed as "you". You accept the license if you copy, modify or distribute the work in a way requiring permission under copyright law. A "Modified Version" of the Document means any work containing the Document or a portion of it, either copied verbatim, or with modifications and/or translated into another language. A "Secondary Section" is a named appendix or a front-matter section of the Document that deals exclusively with the relationship of the publishers or authors of the Document to the Document's overall subject (or to related matters) and contains nothing that could fall directly within that overall subject. (Thus, if the Document is in part a textbook of mathematics, a Secondary Section may not explain any mathematics.) The relationship could be a matter of historical connection with the subject or with related matters, or of legal, commercial, philosophical, ethical or political position regarding them. The "Invariant Sections" are certain Secondary Sections whose titles are designated, as being those of Invariant Sections, in the notice that says that the Document is released under this License. If a section does not fit the above definition of Secondary then it is not allowed to be designated as Invariant. The Document may contain zero Invariant Sections. If the Document does not identify any Invariant Sections then there are none. The "Cover Texts" are certain short passages of text that are listed, as Front-Cover Texts or Back-Cover Texts, in the notice that says that the Document is released under this License. A Front-Cover Text may be at most 5 words, and a Back-Cover Text may be at most 25 words. A "Transparent" copy of the Document means a machine-readable copy, represented in a format whose specification is available to the general public, that is suitable for revising the document straightforwardly with generic text editors or (for images composed of pixels) generic paint programs or (for drawings) some widely available drawing editor, and that is suitable for input to text formatters or for automatic translation to a variety of formats suitable for input to text formatters. A copy made in an otherwise Transparent file format whose markup, or absence of markup, has been arranged to thwart or discourage subsequent modification by readers is not Transparent. An image format is not Transparent if used for any substantial amount of text. A copy that is not "Transparent" is called "Opaque". Examples of suitable formats for Transparent copies include plain ASCII without markup, Texinfo input format, LaTeX input format, SGML or XML using a publicly available DTD, and standard-conforming simple HTML, PostScript or PDF designed for human modification. Examples of transparent image formats include PNG, XCF and JPG. Opaque formats include proprietary formats that can be read and edited only by proprietary word processors, SGML or XML for which the DTD and/or processing tools are not generally available, and the machine-generated HTML, PostScript or PDF produced by some word processors for output purposes only. The "Title Page" means, for a printed book, the title page itself, plus such following pages as are needed to hold, legibly, the material this License requires to appear in the title page. For works in formats which do not have any title page as such, "Title Page" means the text near the most prominent appearance of the work's title, preceding the beginning of the body of the text. The "publisher" means any person or entity that distributes copies of the Document to the public. A section "Entitled XYZ" means a named subunit of the Document whose title either is precisely XYZ or contains XYZ in parentheses following text that translates XYZ in another language. (Here XYZ stands for a specific section name mentioned below, such as "Acknowledgements", "Dedications", "Endorsements", or "History".) To "Preserve the Title" of such a section when you modify the Document means that it remains a section "Entitled XYZ" according to this definition. The Document may include Warranty Disclaimers next to the notice which states that this License applies to the Document. These Warranty Disclaimers are considered to be included by reference in this License, but only as regards disclaiming warranties: any other implication that these Warranty Disclaimers may have is void and has no effect on the meaning of this License. 2. VERBATIM COPYING You may copy and distribute the Document in any medium, either commercially or noncommercially, provided that this License, the copyright notices, and the license notice saying this License applies to the Document are reproduced in all copies, and that you add no other conditions whatsoever to those of this License. You may not use technical measures to obstruct or control the reading or further copying of the copies you make or distribute. However, you may accept compensation in exchange for copies. If you distribute a large enough number of copies you must also follow the conditions in section 3. You may also lend copies, under the same conditions stated above, and you may publicly display copies. 3. COPYING IN QUANTITY If you publish printed copies (or copies in media that commonly have printed covers) of the Document, numbering more than 100, and the Document's license notice requires Cover Texts, you must enclose the copies in covers that carry, clearly and legibly, all these Cover Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on the back cover. Both covers must also clearly and legibly identify you as the publisher of these copies. The front cover must present the full title with all words of the title equally prominent and visible. You may add other material on the covers in addition. Copying with changes limited to the covers, as long as they preserve the title of the Document and satisfy these conditions, can be treated as verbatim copying in other respects. If the required texts for either cover are too voluminous to fit legibly, you should put the first ones listed (as many as fit reasonably) on the actual cover, and continue the rest onto adjacent pages. If you publish or distribute Opaque copies of the Document numbering more than 100, you must either include a machine-readable Transparent copy along with each Opaque copy, or state in or with each Opaque copy a computer-network location from which the general network-using public has access to download using public-standard network protocols a complete Transparent copy of the Document, free of added material. If you use the latter option, you must take reasonably prudent steps, when you begin distribution of Opaque copies in quantity, to ensure that this Transparent copy will remain thus accessible at the stated location until at least one year after the last time you distribute an Opaque copy (directly or through your agents or retailers) of that edition to the public. It is requested, but not required, that you contact the authors of the Document well before redistributing any large number of copies, to give them a chance to provide you with an updated version of the Document. 4. MODIFICATIONS You may copy and distribute a Modified Version of the Document under the conditions of sections 2 and 3 above, provided that you release the Modified Version under precisely this License, with the Modified Version filling the role of the Document, thus licensing distribution and modification of the Modified Version to whoever possesses a copy of it. In addition, you must do these things in the Modified Version: A. Use in the Title Page (and on the covers, if any) a title distinct from that of the Document, and from those of previous versions (which should, if there were any, be listed in the History section of the Document). You may use the same title as a previous version if the original publisher of that version gives permission. B. List on the Title Page, as authors, one or more persons or entities responsible for authorship of the modifications in the Modified Version, together with at least five of the principal authors of the Document (all of its principal authors, if it has fewer than five), unless they release you from this requirement. C. State on the Title page the name of the publisher of the Modified Version, as the publisher. D. Preserve all the copyright notices of the Document. E. Add an appropriate copyright notice for your modifications adjacent to the other copyright notices. F. Include, immediately after the copyright notices, a license notice giving the public permission to use the Modified Version under the terms of this License, in the form shown in the Addendum below. G. Preserve in that license notice the full lists of Invariant Sections and required Cover Texts given in the Document's license notice. H. Include an unaltered copy of this License. I. Preserve the section Entitled "History", Preserve its Title, and add to it an item stating at least the title, year, new authors, and publisher of the Modified Version as given on the Title Page. If there is no section Entitled "History" in the Document, create one stating the title, year, authors, and publisher of the Document as given on its Title Page, then add an item describing the Modified Version as stated in the previous sentence. J. Preserve the network location, if any, given in the Document for public access to a Transparent copy of the Document, and likewise the network locations given in the Document for previous versions it was based on. These may be placed in the "History" section. You may omit a network location for a work that was published at least four years before the Document itself, or if the original publisher of the version it refers to gives permission. K. For any section Entitled "Acknowledgements" or "Dedications", Preserve the Title of the section, and preserve in the section all the substance and tone of each of the contributor acknowledgements and/or dedications given therein. L. Preserve all the Invariant Sections of the Document, unaltered in their text and in their titles. Section numbers or the equivalent are not considered part of the section titles. M. Delete any section Entitled "Endorsements". Such a section may not be included in the Modified Version. N. Do not retitle any existing section to be Entitled "Endorsements" or to conflict in title with any Invariant Section. O. Preserve any Warranty Disclaimers. If the Modified Version includes new front-matter sections or appendices that qualify as Secondary Sections and contain no material copied from the Document, you may at your option designate some or all of these sections as invariant. To do this, add their titles to the list of Invariant Sections in the Modified Version's license notice. These titles must be distinct from any other section titles. You may add a section Entitled "Endorsements", provided it contains nothing but endorsements of your Modified Version by various parties--for example, statements of peer review or that the text has been approved by an organization as the authoritative definition of a standard. You may add a passage of up to five words as a Front-Cover Text, and a passage of up to 25 words as a Back-Cover Text, to the end of the list of Cover Texts in the Modified Version. Only one passage of Front-Cover Text and one of Back-Cover Text may be added by (or through arrangements made by) any one entity. If the Document already includes a cover text for the same cover, previously added by you or by arrangement made by the same entity you are acting on behalf of, you may not add another; but you may replace the old one, on explicit permission from the previous publisher that added the old one. The author(s) and publisher(s) of the Document do not by this License give permission to use their names for publicity for or to assert or imply endorsement of any Modified Version. 5. COMBINING DOCUMENTS You may combine the Document with other documents released under this License, under the terms defined in section 4 above for modified versions, provided that you include in the combination all of the Invariant Sections of all of the original documents, unmodified, and list them all as Invariant Sections of your combined work in its license notice, and that you preserve all their Warranty Disclaimers. The combined work need only contain one copy of this License, and multiple identical Invariant Sections may be replaced with a single copy. If there are multiple Invariant Sections with the same name but different contents, make the title of each such section unique by adding at the end of it, in parentheses, the name of the original author or publisher of that section if known, or else a unique number. Make the same adjustment to the section titles in the list of Invariant Sections in the license notice of the combined work. In the combination, you must combine any sections Entitled "History" in the various original documents, forming one section Entitled "History"; likewise combine any sections Entitled "Acknowledgements", and any sections Entitled "Dedications". You must delete all sections Entitled "Endorsements". 6. COLLECTIONS OF DOCUMENTS You may make a collection consisting of the Document and other documents released under this License, and replace the individual copies of this License in the various documents with a single copy that is included in the collection, provided that you follow the rules of this License for verbatim copying of each of the documents in all other respects. You may extract a single document from such a collection, and distribute it individually under this License, provided you insert a copy of this License into the extracted document, and follow this License in all other respects regarding verbatim copying of that document. 7. AGGREGATION WITH INDEPENDENT WORKS A compilation of the Document or its derivatives with other separate and independent documents or works, in or on a volume of a storage or distribution medium, is called an "aggregate" if the copyright resulting from the compilation is not used to limit the legal rights of the compilation's users beyond what the individual works permit. When the Document is included in an aggregate, this License does not apply to the other works in the aggregate which are not themselves derivative works of the Document. If the Cover Text requirement of section 3 is applicable to these copies of the Document, then if the Document is less than one half of the entire aggregate, the Document's Cover Texts may be placed on covers that bracket the Document within the aggregate, or the electronic equivalent of covers if the Document is in electronic form. Otherwise they must appear on printed covers that bracket the whole aggregate. 8. TRANSLATION Translation is considered a kind of modification, so you may distribute translations of the Document under the terms of section 4. Replacing Invariant Sections with translations requires special permission from their copyright holders, but you may include translations of some or all Invariant Sections in addition to the original versions of these Invariant Sections. You may include a translation of this License, and all the license notices in the Document, and any Warranty Disclaimers, provided that you also include the original English version of this License and the original versions of those notices and disclaimers. In case of a disagreement between the translation and the original version of this License or a notice or disclaimer, the original version will prevail. If a section in the Document is Entitled "Acknowledgements", "Dedications", or "History", the requirement (section 4) to Preserve its Title (section 1) will typically require changing the actual title. 9. TERMINATION You may not copy, modify, sublicense, or distribute the Document except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, or distribute it is void, and will automatically terminate your rights under this License. However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, receipt of a copy of some or all of the same material does not give you any rights to use it. 10. FUTURE REVISIONS OF THIS LICENSE The Free Software Foundation may publish new, revised versions of the GNU Free Documentation License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. See http://www.gnu.org/copyleft/. Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered version of this License "or any later version" applies to it, you have the option of following the terms and conditions either of that specified version or of any later version that has been published (not as a draft) by the Free Software Foundation. If the Document does not specify a version number of this License, you may choose any version ever published (not as a draft) by the Free Software Foundation. If the Document specifies that a proxy can decide which future versions of this License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Document. 11. RELICENSING "Massive Multiauthor Collaboration Site" (or "MMC Site") means any World Wide Web server that publishes copyrightable works and also provides prominent facilities for anybody to edit those works. A public wiki that anybody can edit is an example of such a server. A "Massive Multiauthor Collaboration" (or "MMC") contained in the site means any set of copyrightable works thus published on the MMC site. "CC-BY-SA" means the Creative Commons Attribution-Share Alike 3.0 license published by Creative Commons Corporation, a not-for-profit corporation with a principal place of business in San Francisco, California, as well as future copyleft versions of that license published by that same organization. "Incorporate" means to publish or republish a Document, in whole or in part, as part of another Document. An MMC is "eligible for relicensing" if it is licensed under this License, and if all works that were first published under this License somewhere other than this MMC, and subsequently incorporated in whole or in part into the MMC, (1) had no cover texts or invariant sections, and (2) were thus incorporated prior to November 1, 2008. The operator of an MMC Site may republish an MMC contained in the site under CC-BY-SA on the same site at any time before August 1, 2009, provided the MMC is eligible for relicensing. ADDENDUM: How to use this License for your documents To use this License in a document you have written, include a copy of the License in the document and put the following copyright and license notices just after the title page: Copyright (c) YEAR YOUR NAME. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License". If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, replace the "with...Texts." line with this: with the Invariant Sections being LIST THEIR TITLES, with the Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST. If you have Invariant Sections without Cover Texts, or some other combination of the three, merge those two alternatives to suit the situation. If your document contains nontrivial examples of program code, we recommend releasing these examples in parallel under your choice of free software license, such as the GNU General Public License, to permit their use in free software. refind-0.11.4/docs/refind/refind-background.png0000664000175000017500000250431112626644770021627 0ustar rodsmithrodsmithPNG  IHDR3 l pHYs  tIME 9 IDATxT˲m[vZc}G|( I`8슱J(0K8(Paa@IRJCq9g5{oXG]مk9FA$mDkUd-&aX*H†Lx#2!K"@-z8RRFZ rKz_1_~/~?yn_~/nWZ=/K3& 4 %-Ux2}!`cnWRưGI`x*I{7$VRԈ8 a,a&Sm8( X 9uyJۢc  &Nn8OfV'2Ϧ3 DCnJYg4\oE9,xD<#dJ۫N]: ܽۇm ,HE`zO*cm Ɠ$$n4DYdA,h&)a iD'0mN#3@)Iq$0B;QȐ!hI8qHWDH1xdGb!\p!R$A\..Tz۷_]߼o P}s{~v~{'?n>{׏o~v}}s$q#g6)@řS\!"H2Q.dF1AB:i.8}=Ɠ wb8gHd@eMnɠ!nf& )i=wLĸ[PXv4aGakCUº R^KȾx3ShYP41ngvQL s5mqcD"&fű7Z$3t wKߘ+;No%=`@#ӒdJ 81ZVp-&l6RATbeNB JE DnY%̙?W ̽$ T3g`q Nz&L /OU 1>OU qj ƵP@ܱ MM{Q^H'@(" lngH0AaVdTqңH6G:XEBBwTJ*Rn"%lP!8D`?TAU"dQb"q x/ W@NR&*P%R8XL" @ **$1SsC`,dBFi_UH@bC^qOpd4r/8GV-L1)%wV JPU29HvC`%k XF6`D 16p51LGuA݁g-x$c@`{}0iR 2dSǵ&sʨD* KejvYXm/KzYRLr:a( ,TZAD"O(4e{XkZaG/uAGOz~<[3/_?j7^sPux=]O wﮇw#p8'Z \vovG7oƷ^}oNS[+Ԍ:=e_}_ӄ7vعa<IL=PJȉ%;`~tDtÓL۰!"}_\x7" ,v 0  b2F@!dp8챑hz$&r' \TU H*TgT0vR1.PawxJs(4#d|LYP[_?o|㓏>'[??߼}nwB<}^p<qy˒(z,,#p6A>>~UtzWm#8̜$Ļǯk%8RwhL UF*;Z bd *E:B6RG#)4*a D=w =>sjNRv!i{Qx 6 ^/.Br ߄ [o Uh,vrbxQU[q\B(o$9qvnsV2rs& ̩3>%0q7^ܢ1;܏NȤdT: xn|o78Rl8ZXGP;*nagPB`B;#jیdJLIf1sHfE-U{/O^|?;?_|Wo6Ϲu\.{Ixzx>ǏAd=X/*<y\=5?ϯp<`.GPx˛oHq"wYp]<)ML  7H/aSiow<~gKmFc3`695#L\x !}.I8_0}ҰcT- r"nS=?R Ul<e:3$Dw;vQvGBfk 3f%$$']un7zZ,&19q7N"6Wy'"62}CϓUӳ `80uHō ,mH Ct3P `8V9M}!2 }^3HAc dʵXZӧ 't︐ck)8>jO_wl=ABVʹ8I-`&avQ1-:wwlJUx+_{я?]-ϾRKo3'ϟ.Io u9.>8=}xp('Nj:<~[|r`='___ k7lv&bLWZӧy(-R&$8.NDXsB*mUbd-9t'aӻAF+nԖv09ǭR Lgݽ\>O*> (9m_uNDW = RieK[?ZGUM:.gZ#,nj7"ϳTs;w+^p*$3@Bd&={ M 9}lG&8ndҎod fk!ߪp%nz?̝wٝdTo#᠓|.sv"O,@=fܞŻ/]>)uߪHvϦdT<9Io~lwx&LqZr@b˱67 pfǛCņQ@glOJ}sBW%y }gr[Th`'3Ζ#$vvd+ \,n-oݣBxdZlΨشV` ,M{wPĝy@P$zk X;o^ulюdň׮8"u=GUiy!l[Ti(, ͈5cTJZYm?@-cl4R߽=QjQ'rd wc+wa%VށB@) ,EU8v.q<Sv)UJ ANJuhjQwVccD>f-Rm@Įuw[LEz%7t%$" 3WՖ".t lY@:w,%xb0s׋$k>;!aOWo>糿_ŷowY~/ï7O?㗟}y{<]}!?y!zwoˢ|sᮥ]sim ķv*& X4҈A9$ɻ;=M >G]PO/E0p`$)sy-$Iz6Lwa?#* 2@zgx̢l0 Z&Pk퐃{mB|;z+dwpj/-}Q+(P@"j]bb+ iO 3VUڮJ >!-.;Q'z.p'{I[USؔ(u'<0=;QaY %]Z;zwyfE(89IrT>'GmO*RU[PPkP1JUAfIZAabdH$BqPI0JUZK!% fƩ^mjg!]"AVeQ.r˝DŭLlnF!.gFP= p"q7 <ԑ9>fNREyP$hx$0m*Mee]aVBsoNS=sbI2F|1+ьF$"p7]1z0dދgX Lz1[k~t|OL??2/ow?/G?{ת=v].8 =}:|u r?ړً'}}k>~;R>GfU]6hڥIzUU & lӰ!)="MHr-!ĥtR{fBU{p:#%@i>V %\SEB}6Um;Fb g$}ڤ{GADzHNwo=ԦDi˜ぷe>2D] 2\zFBd}MLnGGj[A?nO/ ϵs:ʜuf_gۅ‘$Q'!žl1 9͞*cs>iqhLOg=OHܐ U)J:gsVdgl}lsR Fit8bqk"<;XIL#qN;mUG9Oč Rgzښ9;/$;+`8}t)v' bϷ\FYStN6 =p,죷RQuPK4IiPv! ';]$F$lE+<oXjX`UHyWL1FBX.|[0) ZʽVs:XJP>5=&CnZU#D;=}`::N#(ֱ.܋h+<ڻ} u)(TyxrEK.'GQ8Cf[r=]G i@`Yܳs=XHZ@tZK8={.k<{R}q_ 1 jMU%m")qĶ7g6Tw9dK$Z#tM"(qzZ3w9`!9?۩ Nn ota}N `#  fú=B>'ijN"5}.YzF[c̪7>3޼ʟ^<^zi|W囟z}y?⳿/~_|e]<<<=f|㙤>^7H˗Ȝo >Cu_˷_<|>~1Ž3aOSLOzt~Rmk̤v{=H0\`Ҫ9{ֺ!O}C]tgu683#D*9=3) z]#;osYUYddRӶlA dú00 ,@~2aX2H խn&딕ךD _]eZs?c|sn-:Wi*q*-.Td ?HF/M!o"b RעV}l^-Dwc2)pL:ݱ9j-L!¹#GDBKyUF#"-QK ԑdJuQVT74@k]4!JSYj~]<]f^N_oSHi Q3j\]]'WNu>jޣtY 7Y 98 LGtQu_ԙhp5\+m@3ҺbHW/U8c9P)|vnRv8QBQkSl%3f=6mn6>vϞ=ٶ-@ݟ?O}t=nܭYCpߣ aD5q0b"Υչ`:cw1ˌmp,"ᄵp.4LJD~(#k b7`~Ͳ&0PнzhE b#0@3sww N.憆9e;ݭ`y]l[wMo۬}a a0͖uu]gne27dS=(IN 7qi5+uJ |ïe4=X 4h]0u3>$5o[t #1Q;S'@`+kF̗ͭ[(`iWͶ72 [ʰ^bu=ife$#0+-*wʄnuoe~39¾m`YP{S?~7?zɳO˿ww}ݽ\뺒y^yqceu<:{;,ݿbzuύs.׷O [}0++X[[U¢m5ia"'- UհV[A&ͣ@,i-ѹSa^Tj ?2j%5 q2** ]A&:CPjSu[އc`<A(J[8Ta2ʲ0Nvew9b.~pU\h٪^!MP !쐤ɣzC^;hA͔,jhBT3ifnti#Aq$[y=fZ*zce"q:!(Aw3Ewk4rp`f Y @-xOӢ!W4ѤJ_ [TG<ˏu苷~Xo#n=?PK(zKPܜ.yH5`~#7l)yZ xT-;gלel)|JsZI º< Z۶s&ulCOSZuQXឫ͌KJ:mK!6pX[ UY#m؅=/2z "s,GC0- C`@Z@iݡl~on"(4X ʸ҂▥naFjc1:Wl&z.:-<J' Tfj5G4t@:Vv<ݢ´fcIT $4ZRcwhЄ&Tt\ Vp F>y{W@O XA[-qgXUm9vF+k mde{ee]ݬªl#"%&݊7SVt]$,HPVȺRAn4n4stK~;/?ѷɇ/O/ٟٯO>~o|oO7xuaChCۻ`@SZ/ekO|6[]uo^<}fçO_؞>'>~ujefN aj/׍})sw-V.Su̚0-sضɐ{.7h%,X!<)r5F̵@T"v_kRv8TW&Rݷ9q2h,EWzf6㺦aZ"I:'׽2:ѹ:[k+B'%DTe8uwJe["Zb{Xf݃K.,Bu䦖Gt`f5g%uwuu]Šh&dP!Dw9`ȪC5bwfVfZ"ÜU 62ICY̝ ]P"E&ȫZ0\G%׸sv-3Jh)3 բ v#HUk @2\DVoZ(5Qm܄Hɻno=j\9Jn\ր3O&j PfA3TH|n~w=$3_yXK/?Gw>|?z{Pʺq5>-7/K["83н:48巆 Yef3~¢'nnk<lbTgijQB0UFجJ fE8N>ב!;;E(6I3@vz7`fېݍyD\UL#(½qЂ{43Kd96Gq1EZ7P2fNl\ -{ q8>}X[p5œ & q7ΜT;1ԏX3d.mxn]OYiݘMd:ڴ&Esօ/\Jd%LjĪv*#}%Re@}J75:5q.Չ:Ѓ^dɘh'Rn:zyqlm} 8Oſ_Zo>~'lOí#t{z7^߿2Pvs`5"L/u}x[͍Qryj;ҿ?gU] 9.4iTmW)U)ͭ8}N'Y.`X @O:0 -a,R -HmyZH21jK|T_&+ժ ePòIf>.:5sF'Uy8=rtVM5W.[ V^0oYCmQՍAM WT''YuJ3'5.N|7qfIN4~2J[V]Et8Aþmy>G~i<^<򽏟lg?yً7_ڎg77AfRG:cvL={"? CWBx68mo`N}rv56 &51a3 ] mę5Dzo>u,}ͅ{L YdAQˌ@+<{Kf[ÌG$J!607 l6SJLkX3dz*Z3'OۤG+%,0d|[&&ZSw0C @6[FLd6t4r 4Z@m|Z0iDsbnV>Vlg`o:]^V-Тe@'Y=t q4Jt)kYԓ:mz,.X7>q2fkQ-ŶOf;37nXa^7m >AAg+O?_Yg}m/_W?~O_OuSo<|u͋m{'O_~ .:-aOZǛ׿~knL vW_/>{e?۾qP,-NjnZ1\KlGM)٪4v0Q>]q{nP /bxvY*3[QPRAle=V2 cu]ycUb+a:%rq]吲K(Zov^1u;Yvkdx6Z$q# q4$=AKP3tİEgirG! mdfxMxe=VBm^ݛm'R\ꄓ2uY LT͍YMR16*9m̝C{j'].c), )8jO4K-# mC.3lC`*m鮊u-otWnL"nnl?o ֧Ay&lhuFQY@yݰm^}FZ-Lj߭N#?VZaSӓr2@C3s h 4NÜmIUɕrt=6*Hr iBjѝ bUJU3*[g2:'L>5كK<ؼIܽk4: O%9݃-b>||z}_~돾ח'? \^߿~}qu֢p)nzx{<im׷5 *Uur}Xn?y;Owo?ѷ?6yY* 0JPMQ5slM<!IL6&=)iZ9㵛ay]u3/q#H4JNR*ݝʥYOCu=+Jݽz:blvdU5>*kh`U7ixtjzO_%u@r0uLneсrWzy%e8<ѹv,UiGjd23\b G7f]F@@6\<Ь+6;_F,N9umz:q,`r[V%cF{N8e!!*kiN!;k$\mu)eT-0Oln>ɖʦ4K\ߜXW2P5oI?>E/:MM?y?!^w;>`3obLvwxy: :r#_?K9&vvES v([[Cs?2FDzi'b 6c2%lսm1w@e |80/H6,;h='v4 w|36fQw|f}a^mP"\Ͱ0դ8Ga|H&gC,4GT-[ÒaB¹߸ ɠ.bJL:8ª*o.v $PG:қhdæDFArc͜Ub:ig)iRi kJs r*u3Q:K_YUѴa(F|hу񮥰3m}rSR A ((U* IDATZǀ3 uUl"eo+׻k>ysW}[|>ɟ?/Zo^ݺ^z,zMwA{xûQV)+7~B60seN+y{/ǿ_*ZWعV 5gl@ L+K!Ϝn-Ț. ,PIy #ݽz.t-jш^e~ݗۋ'o_n㵜9Uxg]Zqܿ{Xmn̘84wlm88gYē1HJAOUYF An 0gթ46):Qnwq8> yV 6C)e=nCD#u<:Ѱ yh0F"M_̹ H:M^.hEޜPJECszTc|S<Մr*IS,21sYyBn6DgJ1p? ѱLkjZ%:dA\DDܸmV[wů~?mxO7_ͧ{uWݛެ}7G~%0v\=G.R^Mm*߷ٺ7̌Ozw7o/ >/Ҁcćio(ˮ1uٷfۭٻ\-uW*24,Fu9 a10+1qnaUlT%L0k 3d92r#V6bړ'ORdCt4sV-Bdӻ+4(BTUwVٜ5 ]E3cvOfz3kvS\Uj=#ЌN:NpLPT!:G:!K]&kWQ}k L&<˘+5? eT(%ʜ?rՕ>!@u"F둴̨Oa\ս͹RJB=L M[$ZPjI'ZvHMZ =VcqAYd' Mc%z2nhج>$.AS2r*7&Bl2}ۥFgBLF?&gˁ-Kx|[/_|rqx6/ݗ_|o_ׯ߯kXeOoܢ߼%_piq.<*Q R`h>m>C ~+atz\G(2@[-p4FӜRJF##qs5Vr >Al+o7D6~ M;Xپ9OA5AMikMfC"8\7l"NG/[iNhjT,K-hn~36suBv SI(:گYY@#wC׹tWD1] >Q-lڶAƱ8x-Nk ph x0֬iWfXv1qxӉSl Օg`Ƣ[YP A!xw'9֌)dƪ\BgAn9*<"Zu&칑'i} 81=t٭R׿g?엿۷\khݼ}Gn/>͇xg_?k{_}y/^.UɜeZ={zfZYI^!l[Po `m.蛶O;77DZ|öyZmtU&=qz4Mٻ0/r]E:OFnm5 XT;Z@i<ls"juWKYg,*(ufZ \E4jR<=ZiڀONfLB,*ǦsU>5&?jt(wQZ",U ,v轌rZO'QITJg6PA5ʢ Ԃô\fZc",B:!^dZ+4e WH]FV%\Ƭ̪EہX8DdTu5=WJ7'gz֥YT݈m@JUZh%TPNc9m[%2ZljfGVy4IIU&cNn Ԫ2̈)zaլ ZdkP 20R*!?MqC3At6cD [}O?oZ 37_}ׯ޿Oo߿}÷=<zZ~RFPmٲQњrf;AgB'.;b3 a 1a,(m6q D469b^4%y8Nn'dO2;r5V EVfA[ {/ahӈGFFFﱇs x'KTINkM7PQVC./D˚p0J`X}πCB-دu5]`AlMAl$@A7Œղɟ9)3tkoaY4GUwZ`Ax#j@jlS*O_7ܧSifii> g'GC6Uk0}yQb/1h[ҶVOĬUahͼhNi`Ѽתmۧ*Wi U0}W[Q<~xW_{:X{eօ7ɿOooWgn?}źظk嵎lmXcfanj0㚛~ğ ~woG}aח?_jXu4mQHQ(>fZMߌ'c7ɒ) `;mBdW\֍&ivZCU9Jz*)VWy\@U:cu$hY;VX#obOWlL Cc/I26չAעQI̴rLFC04HctN|Ud#H&x.=K FԡҬU+dy|ܾ6@ـp*N|>ݢ^f03+ˆxJJqfM,Z*k [ݢxHa]"wT8gV۩&6$]mۥ!kqvV94PvYcّze4](iu[' )OBp#PfQNi'IW;ʁ3{f']zp.u],ilPUc* &}9vi~<qsnÛ'˛]^ׯyx'Ofz̮VjuG7U89j6wt1]OۣH52~3zgzzO>xa&Ǿ+؜͜RqvGPՑ~[wq{7~O~ŋoWoKjyfѳ5I/#N>{|>W_}szͦy?պ~~uA){1Hؒx*iToN="m=nJyN_%a Q/iߜGNt\N 5N y<[y0Fώch̳۵ji4Sd$'xp߷رEy{{~ldp6ր۸v:"m3ڲi4 6׾c`52M#Ow?B aau 6aNfUejda4NzdFa M,Fȣ0 m{Z`:e[@3@D,GF&QِKAg\ }W%j]j@i^ŹR4ZC0:tk$-+ N4\т.Gzr(לDZLU4swsbl# {ƛv8<\xɇM<7`{8΂ߕˬ&fK]02Ao7Rl۾T۶Ek9+fniǎ}ךsUN2gh`{}?U ۰sh*!biæ8"U)}ԩ<gTՋxN Cu=Ee2U2Rd&R'7OȪ݁PeTTK*)SKB%i^"~g;^|礻om1; SVY~P4*{D(+ }*>ԭfU3KE`` &G"Cr76׼U, YK*cV/rJj.J 3XG ޱn>/>]ݛ7{>|x]T|?O~ӯaT~xo?M\7nϏQiթrh[د!T>.a׭>lrrdI;* M1qUh@%L6ls14SL9(#PcZA@t} 1Gixfn>5X6d2לqJ1F:>{(@ȗo/VV*e )ָ4\eMhuL/2Mc$5l(# 'Kʞ-Vc3] 8X_KbhB* h8"ˉ3l8[_aUs_4qz}4<0eV>>ZÎU1cݶ7y-Av!KYrMw;(6S̜8~yP@^j!t'J [Yՙ~L%8&q|vNU8+?3=߮o_7ʏ P|wb޳ۧOc=}|18Ǭ< fr}9P^<0_ c^.Oۼ᳇_ݝ~ZEVcLF"0T>[oRiO%!t#iqY*ZF-Te"0z-=p&KeBUYًB5o @WZ>WI3?|x_wrn'ӄ$PB4t BzyðT#V3?3HgUA+Xn{4EiwOpwF2NT%)HU&jhn< WƆ}.TJgE*sQj\ uZY4Y*0F {G2T>Ga mrI ڃ}~*+[tuqۙw/_ 8oO{6iJ:Tz:R#|=ǘox;wŷo=ǓOu%RU0VFOfdYhިPI*c'(nqFܾ[jVy8oLS691"+RRT`Ex2Ȍ$5=#Ь^T&2WF\164>qY-αfT!Ȭ6PP"v}KUt,2fBEHVWg}J2+S}!DFUAVV;]JM$+KVM%۶L٫r2Tx-5tMd'>E^ZMw٣蕂YJy{RbQKuI:YP6QinTfi AgXrϑ\tk_9"nUdPYVe]L.[mj\^;A- IDAT26հ+k9C2ߦ|)5 4JJB5nW_oꫯ{_|?싯_}LUYOO}+3ԫ)a_g?zoo~-[sn32ɑcvx Y:L&t׭)<}Z4Dv1w=>Tv4ѯ9F!$dJ( ٽV[y_ņ 6UsD7Ǯ;.>b0?1fh1e0s*4kgtq +-N@isdqnÌ>wp6Jn8_Po֩R@QS@k+>Vk 95B 44}3Eox@no d*v/~¢ _A˜h;3FRYUɝPk(YUFՊj%Ja^N 3e$e@Af 4Fʶi#*VA]eӺ@6NZd^H2݅rdo||sJ\n|g>CAǥO+ψd[^=znqƢ8/kmL,_ǸF,P⨉'__~'c>[j/IC9;*8G"s7۰!iW)DBHeEUh<$khU pϸ=BfFG;XRf3P\4SU,nFzb&UM*SeT @6]QlEvpnJ.wYX-2<8)KDEA*0kj}Vs[((߬]څ -Inu7H*HaUFAVUAD*yrB!p}0uJ5=0R O0"sܽ{50>\-|{{zBqa2'__FM/m\_}o}"@r GC}>tinRUNlo8YUMwǴ`*ZM_ÜrY Nq]8!%&܌?^̘;MF{ fUٲyhN9}|֘%/>&/`2+Qb{F 0p˦'h*1 O͞biwqzQ.N\$hY9wZ(]-:܌Q09l6zYQT!PUD3fn[P|)3#-]:tÊR1^0eD[g0jTqenvL29]Wc)RR˥H#̺% yF=d$Y+:sA3DAMY8ѷRޝc9`@*~~O}|JOx&yq"Y?ӟѾ_γȐ1s*ox)jǛ=OqZ^Jχc}f=| 7߼_2(kٸϊ:`͎ A0K2^2#Oe3x .$~QՔI+0\~i_~?}zpܿyH\dC&Ղ`F!^=F;UFM;>u1Ƽ?w󷯲So!ndyG?7hc8l-rw҆ Hﱆ7WWB2k\Yt^ mŗ4 3 4̽a-Hr܀wZ0s`a&+9`y 8Gc`Lǵy6ufa&Oyᘜӝ601Jŭ8 3asVeآq6.g@拝J,P=c. YbƈnmzY4Oc%)9=V/ 3 ܫs]~I-t/UŶ2)^(++3UYMɤ|}\4ˣ)Id5,C{cճUj)B4PFnY@Lmrk܄ 3M5G{}݀$k:??~tw[/毮vrCfp><=8[ Po~9~Ӈq>?nK<5:O\i3?n|b|$)3'e*,:@MUHff惬 7L1rBvWD$$8 ʴ^h*- 2XRD3Wr#%EAul9/F*)nK+}+J };O(ȔY~G)_0bObp*2g׸ū}jaY"pJ {̀2T^L %le 5ʌ= lT"+a-")!obNEa/z+%#deQgoh&A͇k1I}U1g%#mBӘA+s&j؈-'TB0eieJ9|* QK)eJVk}Xtѻה\lkܼP,dʼ7ȌX19.==]#2ate ;|r1Ūۏ.t'"#{7.RJw#d4CE.5|2XьE-F>))6,m)/ǰ2f`x r<hED&`K4hߗ P4F.qu-}Lx'|9066b>/cf>tQ2_p_pVspubl s{ׂͻ!᝭V*>Q><ϰ>U=d+WD%)ӁT$sB ]u+=Jy(3#:\W*Nxru'!Tb RsgyWIME{JL0S)"qؔJ؋h@{OO~r?O[>Q Xf:|^ϕ78"n )E^gO●~'zi0Ceᮇ|n;{U'~3zǻyY.P^ 9f(7fsHK&]u8:= *OQ$uߦߗ&2Cubl⼂*be @dZ~sA̺{{ͺ_%zKٽR\4$*#Q&G'͆'4Ufy͒ Z96A-0:Q"3+zFXREmZ"f@B#RT2\(%3ڍRJɵb*jذRQdX*s*`[f I" ۠dEU3_- K,+ JK QRæ#HBH!:A1ڵju d(%R/, "0C^,EXU_22VJ9<3{v—z~*7v+(u3^6%ˌD?th Dм]9e7-JCWֹn/:|z~~^|HUfF[Mq헗sx_oa~H)}ai! ~`Ѓ߱Gcxfrt#ZHXJy ;;[2I XyO17}p v;Na_ȄNmxabF参 BHpLDz)2OӇsqƔMw-UQǝgaU.R:Sl=r81<þ2 qcRTٿZکJ޻ZR7,ܭMDqpon{@N߼/  B]%B):e9 d.tPvQt0Rɕ]hmJKgɘdQ"Kľr*_RX;>1P_ojrΑ U[-: (tRFLs 4[Orj7񶤊+s!N`{KGI* ʈIr) b2zl}#/H,sP ZAPIL-#!cwfW;(ݵtnꜜWϾCAߒȪ=:ꥌuQ;LG)U$`JD-z# L Il.RgF  ꗬͳ!GnV ejOfц,@mtA*X}~d@uj=E5 hm8G0Q0]ְ}tZOEjY<2b n>< ٤Lﵢ he/2 'uD_Hi) tۍMǎSUi4+ }Y v{M552w 2 cV:i5Y~ʔV?P(VZ?W>:e$z\,4QP E (T"!`H4i ")@'--F):weVn@ZQfGUVbUB6`ƾjp\M?}z|3 ]~zqk{?n~J{t UYapZZpܭ%ǘ(>>UK9 :_#~8?{_G_ {oL bZf0&yȑ:[hCena QHh[#qFf[1 &dJ*9i^?>Woݎk]o7U9@1اbFb'ͷkCq7 ! XU&V;@de%$ܘn*K*݋(0 dҲ 0&cyҼ1sBmlS rsvԚr f&]Qt+z'8m{ \<}8-11,?C)^,ܜK\U5 \|&^p\L,x2y;aNov;M]?B.z\_ƧWVٺIyw__ʟ۫qX3 qg9rVd,Tw7Ͼ?+xNK_Ǟ3Edz'׌>D͌E N*L)Uiݩu IDATݮWG% q;R-4CDYV%V0֙.ZnLeZ"2ˁ֜R6s>)6'z`&vE !/Ull/j}O`, ڇZ}q~v|};1#cVU$PF su] +-TCo5xNbU(UPPeU*dYEH BA"MMC#K&S:@SB\Xi\˽65uC ٓUQT$hhPVe/+Yݷ/68Jeh ˌ)Tk~yעu"Zf>6;/-UֆVh8Ri2Q*6 l*V94uַlٲ1F nhyU ;MF؅fǨg2+9vx8E=៿O^ϸcU3F揿{u^g77hn]CY簛>2XiAѻL-}*A"t M͛àԘ#"@:adJu\X!V-&WE 2;4 Ui{+ 49 uc̚u\2r &lr9duot$9>]l\ƼK "Ï,An(@\BTޅVMLs;ELK4V%Gm)L:y ^UGiLkU lnXU:Bj;ϓm'*LkR4:, !*'HHTϭz|p\X3_DY\5XHIe2Qԙ4H8F % JCsSnZ 0+p$!}}b {]ĺ>ʳ&2??>GׇZ]}f^W;Yz>.Zy[7<:.jMt)?{_ _~wKU,84`ay^rDz-,`pڷi]Nz!)#}W\=\k5nGV%`;|K8$s1'I" t Ut9#* w|,X5qG$dC.[FE>wkOރ)@J+{90N\O_>mt >␚)8\ ,U$uٞp 1$}wH;J/o?=oOo;_7OO:_߿m=˹o<3}?8vW'ڳn^{_?՟Ϳ'?<>n[r4ƞhlD3 2# 7o#qDh,`%kza0Bf&Pda5xHo]XHrHֶŮk Ĥ] a+Gja._c'QmF:n<u23Q! aa ;fbH,[. yZRE"".WJzhVB0} \УA޹BJG9;=|ݯG@n ub>jE$ZPw NtG]* ̘MdX)CF٧qd#TԤ{!`[ :b=~AAeĮ1ZXv!w4ȀV RrW.BOW*N\RO/,#Pu.։Z0ܜ e"*YؔSXBļN<|%/fT#Q` {\LapNqb."Z*Bհ:2m - 1yH}rK8!ܗM\CWI:yAB v w(5﷗\G>֣jG7W:x}vtyպ5ݙ7^_hFsk5,]=lҪGf#'eR#2yiFA^I b=f?CWDΈX#U'`aG y\4{,MRP^?av\Dq_>d;Z3EC wiZE+Iqd.5W.sf<^eщn@*xѪnnmU8@b&oNE{y(3u8YU@4iDvMg{?⢹TGK*2Irj52dF0;zF+\gfgTA6Ԡ&DFҽ{e/1[3Iǒ5L yϚȅXqπ@{v|:X:ruK tx"د?x_^?#* W_}{7?!2ߪZo"sCyk, o7y 8?|~/˗}q܍U\bUu{rk&꒘@jr9'A2 9mw/l'Ac$ [Ř~NY n+Grvx[q L6zV` %\sw53Ю[Z@T梃P$%`RIK7~|>?W+sF"׎Lk\>duk]|ĚǬZ+Td3[,U] ܷ{ <0JjvHK po;*j,HjNA ꌨڀ##}UYnUH1Ajޑy`h79BH*捥Q"bXwUGD0Yd鴈*gLI3K"jVWaB}J^L%W2!M*Eˈ:Yk݄Hn0b^7o?wo?>?;әtu|mޡ~}ɹ?8V^_yܟW|eZgZVͪgvolb iwoPs+s3T/|~w%ۗa0B I8ۊL^}sd*J,SJ Ynke'3QjD*]T%6u6I"Ԩfv{!"<-dפziՀ#θ*L-vޭ9$q5s0$$n ȏAcI1M<]b4*#:O\m9 $h4t(XA Ŕ]K9D΍WCrNh0 STD,*s RcL22Br Mj;dPr|7vEDvnVݝ{Re$,Ɨ~Lgf3mu!hFGy+7i+s֬Hq{. na+W쪚׳pqhafTDg=+5- S&`W˵ePpw䛯޽Ʌ~r[w_}a * }܊>"du8uB仸z^nXo4lR<[f.;x̂uX-iĈ8^pa9d nOG;9ߘ?=E;,BFD4~Y=lc4LpGɪ8gK+\6J3`xkpC@CՓ\ՅYUeA*~8fNxüS*mגݏl[@DMhHi$੅WVϔ;vP0aHڟN/3P=Oۊ޽OOc?ɟկCxt?n>W_vv:ȈJw2 }i(qCoޯy|w~7~2#:3Ξ\fȕˁ+l=p#W1Gapit3iGHҨUpӌbN'˗Znz"a@^i"DXЋl98uwՑc VEz]By}P[eVM*L"z@]R%ٵiP:Gd9IluCw=mOrQuM8v6zu]Z/vL"le->Um.aH[j!X ;ys /Șk@%kO6{9#>3/`lKi+FgҨ/CRjkuʢ"3FL٭8fЪI~PiA0(I:xH J a'.[/6OaxP6dζzZIȸu۱"ۯ䛯˟?<8đ_^>mWD^GKg\aLg9> wu*5&\a \Z@{QAȵUdD-+q+c !8'zqV su:2#:̻\+#NHBn86G @kNJ;LY7v~ b=Cjdfy387Z8_@Yo}~=n_>y|Z^w?~;O?{{|SoUv0c%+W&"|Aaf viXZU&098 vD7$s$V!Wx"֮ -``lXdmrÍ&PT[:2i=uՓOy+vŊC*VP6j&W{{;ûWf[\g fs3@ZنQ'<: ;Y*39'cvIh8XhF+MߐʬfHh `:83kab^Tfd3>7<+ߕn/^S?߼9r+xuƧiZ?~~yzv{r8q:1[IXh ' IDATHtv۵]w%b r 6K׏ ɘ h[:U1VT5Վ^15$GU \*&45?ŬuRҰ&;OxRdc#0[3cwZr^\'A(-UJ+Бq\6qK<-u`8xOGvbi "J5~pRB6D@ef X<" AU`-HK:ix@X}sS]V YOqݓzdw wRe +r?"$mJ='B89υы  k!a8.SXMd1eA0!O1nO/M?|_|~)vJ GO}Ϳ|~y<܏]qd f]+Xu>Wno^ x?~_/~oh9!6`is +0ٱHnvh@(n1^M-R#ݍ\7u—"C1[tW2(^^Ҍ)<0+@"Dh%95kefDqxou3s 0رeļHs-)V*DDv:X_yM`7ٱ8nus%oGda1vxi"w C*a1&6oVL:9LbѨ.0>G9Hk]# +g;zɾ^NxE:ܐujLY>C7ڭHiWT4 n !Ln4L$5Zc)mz8٨m 4!ϑ. =LG24BakB^+Zbb-@K!\-7?>Zqǧ?ɇ_ 3ٯ^^v܎[|~:n_Avӹz 㸓x]7__{So|'8Щ}hֵ .+̥s`-1Vvz4?vϋ4h>Bly~3jg"j̊b^!cO|z;Qu D{y4߾]P2vZ(2`*Ҷ\˄DU.ε`g*2jQk[ *pTTޏ#R]9y @kS Acc+Ky_Q?a)HLwΜ uqWd:2ٗyE*\&d#pbcE[1#9DcYM/4fA22p}=C\ 9\7Wn<4,#ь B3aSw,"1APꕫ0YF&ER_ާ,cCo_6#Z NW~0> oO~/il\A2Pw@Qu.鷟Y坑^y,X];I΅jPLw "ndeJHF bPHzv;}#]g跿E|8Qy;Z/_<8n?tgzˋ__[ޞ>Hn7q:/~?w{>ɣ?vC]'9^BS]HZ$ޑ |RfK3 ~ A则;S1.k,)Pڥ^ICɦEv JZ=7K':mg[di:֢-@:r~ ~1۲DLSACZE[ry1o˚~F'Y]嚟GОLvaIYjT007^hHBr/PD6P{ \;lmdlqyO/EEpHyN{7ais2l̊,k }֐4 a.ig~)&΄bh\K`W'g|`0rqņw :xӤ{٤@[1Xc`;"b0k.]:5i$6 <0vE!LpSfz_LbKaD;#w6up'%tY#^̿W_`sKXD+f"alWzp PVtA-9wg rL:K15% ޖcKa9e L!q'ƨ -+i4ug3zraj=KŊGfF1`~0w7wOt,4g[d vs`¦܄fh؏}!{o1<8f#:vtY[,#m#fl %?7ٞ?K %eЭeC࿆Ti{YJu򽈴Yr*d Cd&xA JM2d2bfFh3sVfRhsdrVՂʜ8sfeJL 3.[:\%aʩ 469[5w(d`^ yWM]7Z^Rx+=ܽQ~}^}7<8kwteƞ|<~iFț#%I`Fd6Qrfg};sqg5-[/>ݳө wȗ1obY&YRݎLRJ$P;bVJ2$f 73 Fh5f&3;T$Y'dZr$fsDVs<쥸-.o]J:!lTJX@hӘa39;;.cJX]fԜ%UbbþH& MegH Ō ˹w(F&Ms  @2ʜ֦Wj5+Ӑu#'& elVU! P E p.]i5 3 8ϤRk#}4$oD9F9va>S-1)aIU:Hb|,]eEm\0A,j +QrhWL*UVj!'H/{f^I*"IGN7*s&!R -,g&nA^iXRjbD_`Sʖ,SJ!iL# Xf]2gsƜftNU@9 Vh>̉d8cZu*՛Į408 AYF23kUwj3uBV4y2fg9'm4=N)bjYWKOᰰ jRHOPdΜ[ ,AzBf̑w8{Ln嶕G 5 ;gås?=9 x扊mIH[6o1g"vi8mo>/n/w~|qZG}?>S'{ay<F>{ 7A 3{kĉjs\Ta큄h^' Mn#̌;2\LSRk2iԲXI" JΈ@=2hJ̐;CPީ٬GN%DÞmΚ%&9pע-P3G핉dto$DsJYd/Lsc[rf"gX LQY?158Kb&Z!yfTVVhSf  ͬPF8={*T4SafN7@xIQ 1Yca+V:cV@,FGM1W+v*RFM-s2XL `4…H%~&Ct,5%yAP&|VUMrEO)wzaE=:^[vT96FDFliij#11vL\b)`֓y'Ϯo%Z+ &Sd/F=4;}r=^m IDAT>tp̋6zݳ+py3.[~}?\[ξgrO]ϼoоp{n=[[F( Uh[P KpfO7bl&' > FQ9f JiL)K# ͈ھ0 YS$cI09'NɦІJ %Ѫ-݆2NXVg5#6#1co BuMe1HU+ί4S%-teۓO"9B,Vs+`ʌ0rv}}/$z]i`Uu DE B;YZ"S2gdqG;G%K=isN!R#'UR.(6Ƅf i_('=rV܏0TS*&E )_A+3IIjfvT7Eq謲\+Hd*̩ `C351ebUeV|rbH9 b""w(mbn~_'/1 kT%a趬Ͼ_]w!e&f[+Bq\ߘq6"zfs]^m(7N[aͪP`~-2`ٻ =1XjŬ2+ncDX#TM`9X2#f;ؘ,`6S䀬Ѵ,}f"/H5e$2d v)[-)lp9R3E$j<$(4]3PT y&^BɌMYKZ N93ff2[U DZZ;0C*.&=\j=}޺t<7< FϜ =gVs"#CRLq4opqgnl `3"V,qC+@Lt4Ϩ<{N9q'Fhq8 q23Zk.KWF&p-̂:ܚyޗ>8 ufKNeLPN1IbآÑ/G 8;IKO\3[wChƖ3KhNs1bs3J%^auySe7 kY6jH![s#bfKBfNF {FXiFD j!(uJ^9œ*EA}Z)NDT3F9"D"T86a$L!G9nil"]sDVPf{h˳/ /%tEYɘj6sI*#Qlb0R%vKc̭r#3==O~w?z壦qlX ~znO> [ξ~\7=tRvv-k^zpчZ_G84/gϯ.˫y詿t_D{4ǐ%,S1O5Dߴuk"WMŕtѿ;_o?~OЏ/Pf `HdA bFfbZw9.X54j 5'4F-Fȝ ߐL$C H}ߖ2@)aj8L셢贜JTVݔ̨v,&y}}uϼ]ߜUΉ7H یQO֚R1P?{~[9O޹gwgҪyq4N&gYhcC?띹(aiG>dzp|s|w~?qoٓ㫗.vvfŝMó77]Նtqڟ?q3_{ۿ3?#){\}qqr]LP D0D0Ϻg-`ESX"H/ضQww_'O]\4\3yn g=  Sp"34xf~;#`R0HfY׃_~+@_}9ݜ~ѷ~+VDHŴn%mf"^ΤDd) qJ,HaGb6a|oҼLȜa!9GbB2C ŬHXEE-mIĠ܆-5FldiRZLfhhP4SlRQB32 =3(Gr3TT$ժlU2+f](Ba׻G,˧|pXOq톃y"͙bcZ(3#ި]Mы`}$pD #VTk[2Ma'AcXm")sFj×Yfr#jeY;ož7S]- R/)1ggk&y9sLetV|Wk9뷢Y䉭^3%(o>ۡȜ;s-޺)sM%frz)U6[0YpsXZ5ʕQV2L5׊$rJƠI8zrι ZƄ{Ì,Ŕ;0IOE5A'"uӲR9&X븾7K&E8 tohdq-Q&R"`d޴)5\BLh_"sTeCR!lDxM P$>] d,w 7dɌA0Vl+/X;=#8992J% 360ft `Ԟ 0mr6.ͪe_?:z\{7֧qIr.nnxX7o.}}7Wy/q46s?r7yt=yuӞ?*|f"{1y^3z{lV$2 OY/ٗ_H'K&UًBs)dƣ_˫?ڿ SPT44 r_(QfffD1umtG%q1i|_][t?B,^4Dd"ܨP̴}8Rx1INʚ!qXG[*NPts>$745Ѭ2T_OE&+l7[v/c[a`ZpYS"0{#R3f}웻י`VS8n,6vHMi`dќfpdfª*&`%*!F1 JN"1;eFm6fL,d &Y$b4e;{]ހmIl9OP"-& qECnjEhLԘ|7S(5B*x!ٺFHN*>7(˩ Έ)YGG;`RF/#ܬ{c*6{yЬj)H j%d .1)u55G沠-lE)nF)}঩A~F,gtB !6dڜrfٛٚ~l$瀒J" i`8}[ahl%*S2)u=IF+#&h1; 3Ј(-"$ 3P0#@ªa`w*Dj8ZЀ aiHz r"KÈڇcUfl|;%!&˪Ԙc|fiV0"cS*nj&c&Slb;& ֺn[dj0ͬf Dfzf30 %"4p귓l 3D 3FX$dj}ESph* anߑ^'?N||y,>1NFzzq=~h@1.v~d/;Gt@ĸ8ӛhwn٫ʏ~?ڷ7}wږpnÏ~Sn}I~5=,XPiEgn H%>cTsg0#(B.nO ><;?_/?oeqf?1Lp fR9cR][Tל`J`Fag.5@}7 />i9' hs.Ϗ/~>$A^sLU_VL3?xQ`GΓ7"M{;bFhNlGNuse۹Euԋ(\}Y@ C24 adAFqteip ռfTUz\ھ215{AP.:r6ڶi΍!a7]`dT L8"&K5sZk vٽW.G|fZtBʨP+& !Ȕf* D"fNZ̲ Ųb٘h_My@t0E?$/-sJ(6ڡa֧w;D臖PV|&ށ}am:&, nt[WZ;:rr&g$V3IiN͑AMGaIFOiVKZjbHd@D XԦe h$ӊ_W" KdV4>K̘"EU-0]m5ͺRӽf2׌4&ęh8S̜f% KAm(43鮙efLTf trhR&]1 {^wۙhg 1ـmYɢ2RHz3c^wv+р.9"N䡷EϯKh->jy98ݗwٻ{ߟO6<}C\|Uێ}MĈ`SO:WWG{g`w?ny.xX~zz<_}{OoVSA6CzTD &}!""(D1c/½ #8 ܯO{St3!Dsw>g|W_I Ql]8gO>K㳟Oz~^k40FQ0U)/|㲞> ' XcیfN(Tܽ{ϝ}9fgy 6۷o7~u}K'qLP7^}m:A9$͉Pθ8;\zώ{9g!t6Udi%ZV+bfEcPed}igÇ|˘,MJ~:& P1)rrrc<ڙ^OEUzn=79wNݽ˛Wve3D.cmW0NhrO٧.4hmS'>#|e,m'A9N_{S`YnށP#Rt{Lڑы-=; :D؉w{: + 7+{_9ͷ^*P$K iQW|~KڿճuDY!=E6OUf-$tхZDDR_i~}xE7G~'j-ү=W=wn怛Y&(f|;k$E6W?s6mv Cg?Kw|ӛ;xĄGƫJfPTw/)\N"E|Ą3KQl6Mf(v}?zӛNk9RA򳟿/ɟ|C߻ԧ7:ypv_Ig_~Zp/~_U =jI%屧?{m}'~|#5' >\tTUD+u#v ف7ϮM7%ZF}s-6mۢ$hH3Aff|*Y\auG)^=]|t{;^gƙd!sB"#PtDGHJEeZjׄX9$l ~0Ҭ^%d{C5HaFn- 5𘤐о̆*QD3]慦UdY(E R{2c "nSѦi2lNVA3ːڕ(A*# ti߆h]eW@bF*Fh0T*0 &<,3q&HA)2:&[:%`ݪ 3=^ʀ#!A' ͣu"0G IPlLB2ºnguf>] 9g}2]:!0FF.2YncP4( #Ͳ7Cu68XkF!ZgRJ2JAd O7!UѴ02G@[Mn捵JS`0r4rh.FaQy^_/_6+1dqZ=e7'WKD`^T[_+olem~}ϟtiK9v4c :TqzzՆȞzɻJEns1ݥs^7݄ UgukuҐfGf9n RKyܾ O^ nٹW/~WYll,?OFn}m3O=c^w݉k'|gg/?xw~E?Y럈"2y~ ÇO]}]|3OgP8܂a/zhn.RF&YfM`cDu'776Tewwɧϴ^{:zۨg>C?|8}Qd畯|7c")' ?я;͍N]._~GyٷGpюx3_|+N^wؑݽ'z>yKzWfm$A餡O.}S) 5QʤhR(EB%`|Ad"*ua6hFd.VB͊A3y*%`og$U4d{RtQdY9l {ui ihKeϘae`&uFa&U%{#\KbTd˼Cp|)sh:Hhy e;bPwBT{>v9QT3]= RYBB EKX( 9W)j13 )ƈ nA0WT…e@DjZ0GAJx)UљՑs~XOٚygf0K=GzdJB}^mFUDk&-xb{*{)I)>&$"at(c*uTZ2BDLwIf=ƒpKw(J)moEߔHk`ƈbTeF&)VΰɅj@a!!((9τPVȨI3})4 SâǦ@cY5h% DXlwe,mmv*ri(uZNZ:8rFEjܫd)Űmph9w}ϝ=7-6[§lkG/wƩveo9MZIP2ZjQIT# )H+E"]D=2Cf'"&&#!}w8%w%+\kբnY/N?wpo}辯|>{C`U=~9r~r8! }~=^0Q,zN ""$"2ݯss~o]&6 3UeM_;D? {3gg>+=ϝ=k4}⣟xы_txZ7 3<3/^_/~_g>s-7o-Zs1$Lyx7vkd-n~3g8WEETZfq,WG^3 EDYTC|c^uc)=p4  =(NrBKםz@1q^ {D[n!O|gOU)1?7&1?_>}éSNr{ʻGKΞ?Zo-"A2!RxJ>1r^j2EK~顯ɟ?'?]By ^{,Z;Ǧf/ԩr33cp~ͨȄ}EWPD;cD( XP!1Л1lSLTq:cD1:pjA.4[`,DD+Xp$kDZ[P:"5}),-TycѴю1!8N|A{PϊIR!TVG=:Z ތ Ƭ#=A> F-*djt>geRTlTJᎪe`'eբ(8ĨA'Iw hՅf [ԅ6iI!KUdN1 po(ʒ>yH1h-1ga $2<<3<#a0LfMpf?LrF"Slfa}Ad\肘7'1 "FoF)|jF֘ >y󶧀q#\iSzsi 2c0ȌlLslHZ@IJ)%Id8Iw <åQ:הa}Y5fLF)k>Df H`U$RgH@(4d#XN=-Zw6._|oԭk/ovNuETZRU9yȋlu2jrʠOq1j#åf_xdguIPu(CKlw9)Gm^ W`Pܦ5r$ hR Ҩ1XD)̘Ηlx!jUh9eZͧ@1k[G<1kd|$e|{hz+nُ}gE=i[o/GOl @sSUGѢ"(UHKw qo.gO?{nkH!Z E(UtZm~jXjRX}>={x֛D ox3gLPk"}@Xacp`*Db(* @co}K_"IMo:|8O>q]o'~GAX3P7;")`r[$%"3ҭ+sS?]=d:3V"67W~;o&$27RjZj) y꙳O>4oMo֎5ݣ쎗o{,h|o| s(LkGV|~ޯ;QPzR2>k/nUY kom g4Q@ZNM֦֦0!P*6W"3pzZ3\qadX$UJ—*yudD_(șeVA3?d9g753!6͜IIa(I>q6C&Kd(LdMJ ݆2jf 'Z"2TfU5UP(X}1NnԕLw>#K[[((+ϖKi5n$X֒AKED5I64  #އəp.l5 3l.nDFi9"ݬE$}V};^qc"nHK6uX0-lF G|" iIkɬEDnp0:S4 @sDA@d2@5vwL^J2HR,XYשg=ʞBdߪH-B1M6CEE:4 dwt_7T2[!']p U qz˰crzL+8qe}Xnk.]&ášY6;)MZGJN6b9Zc 㖻-CrQSr˛o pHwtZfDhGyNi W9P 92א:8zk6?ra-83p/>v|gjS{/Oxշ"k4] ""J'zrțۜn@W'`挞 @RDJN=~86{_~W>G2)ݵRʠu2\6۾*"Z(r h,dtH exi } c߂fy C@CB29D;ë*i X4xja M]a]_-B4 jeFHU R1E3Lx!$5bJN9at ]LnIA@Q "2Lk(wvdtwtB%,! ݔY Ttx e)sc2!QA椲A茅 JdH[M!}\۸?O{m`Đ,*V\Z9yhsҙ3{{WGxruלX:ϝX 1nZV4*b٬;NdiXw__DuÛ?3+=>v\<7;7;;"AĬ¶u|nx⡧/sYZ*|"`SZ )RӷA"2)X- }@f=<h,Pd#aBLN CH[G4%& e0zud%X9[F3Gd Z<"E#ҝ}PP íðҚ1yhDd)%=Cega"@Keh(ejYa)i\]fݓ@P uLOD4c3(X́'l4s%7v0l x2pxe@IVMkE&zД!%wL<@ aLĹ%dtZ񵣭4"2TMR0 h-Zt;8)$3#^3`Ԛ7Q"bkuBb=պ|eŰvnT]HXjSMvY'mm[ԅ:ċ:z'Nzhyñͻ_}N?n#rll4{4qDZ%H IDePd7d`on"tJ@t 8;;o;Rʶ.9;_}.IztU=OTDDxP&R"D4j?ϟ S R2`Y&~e҅ W2#:3JURxM/KaKyz;nTڼ[V^wfrogo& e'rҦv~GZ\d.:|hQj]|_/겖KxD~h޴T&J!H%RHҝypf-\lZ.HNH [րIZǮr2+: Jfk>l(l=~Mc(&.-¬ Fg) Ml-қIMљ@0,;5T$=z>Kj0x.w94\C)SĽ& *#{0Cz(fH)E*KA^KE)Li it*搩Y:A)}9uh0, wJiEͳ;(BO>Js-5ؤ]1 fu7 *2:eSHI"E&0|KYLD9T%$\M0B8E2-A<{߽"#6P/t@&9h3m++df y,, zu%~TY`5qt k3G FW4E0*zŽNO2KaJi"Da29sYC49td /A:,6hej-%[ke][6Xn[,gYM 8e\ml]y ۾jM{1rz[Ën_q|W>y?"Zb=K;;|v]n7k~70"JJRg^m:Y<#HJaX? H}q-/z-]q/<>YO=އ߸ zmgѓG`'nhV#"q=FH ؋ p*KnET1T Qs  WAʴqxU+ywNɳ}^ﯿ?GQt u«ƑPVjlD)z = ;Y4;?NfsUͬ}2,33:J tjZMuGբv n/x1Y-WG;f%:Z>9GfF4*.(-@#{s:s ?0ZGѣ9[] .O_-nϘXE>!!`X d!U\ (&=DbP\2RTULS!ͤRJ'yDU-ü6UA49rtqrzmil 3m N%Hrudީ*#u>`F0{ STU5dEdDnGB"#(,>g)BEM) H7H $K_bhHVjPT) Z?IQe(j!ŜC,pSYdaX$-nEl ze u"mYX[o,fıS7mct5o8rsPuev. <۟_H Y2SY)ȃ<|,iƒfdL'rIɖ(@|_?f{{O9s/~|ZZNh}# WP BC!% ļrezZ-ͭaJ)/|ɂ`2}~$Ceaz8#"R`SI&",.;y 5:z;\  ,E>Uh"k tUuSAaU'DJL7"€{ Ef3BJHV#[ǯF0(r3ewo`Ps5U.5S^kO]mvbAkb){EFzАSPR%'52annYԲVE]0B(&Pu)b$k"`KD(*afTOFAs+QAmZI-롁)?Ϲl)Ȣ9!3h52۔p]i dLuNӬY2pH)iane aIt)P-BkMTvz# wD}}{b0@ez -IP)d)%(:EͲ"\´I2Y&ƌl4%d{?+ѲgyݜJ Ճ^( 9$ÄDataLk=7. ` g,if}+GAGhQi1'TA@d `: !!EbA `d HzK!n])!B1 nw\^|sOgɄ"X Xj].C矝vқXk XZ^}bVDŴq{pyeO==.xN>=EY'I.M{4-4cbB%Tݣ$~t3oҟAy>*) ںMz5{vU4ZEwKǯ-B h.eԮiSKi %1k2gw*~;1gpse:y^xˋ^paڻ\PZY8χ^:]jȠ&SuZÃBjR̓*U?}p){jLUEKA.8Z&* =CpG:ON]wop'cgϝ;w??Ha ?Y-1=,7]ku}c9S I"E$RIId[VÍF8H%y2A"cNimɒe(J$uXEɪ"Ys{90)p>^k1SzOѱ)8Iy/ş>O?轎ql6q1-Ld g@U@ExN3 H2p kڨ` P1SLwYp NJ̭s&Sef0wEˡۈ Ra )`FzjIO<}yI_`񍊪ZA&{SZjeMu:fޭZVEW;z`s潃ãq+^"U-VJM)EK [7(%Pc!R#R1n%%"*Ԋ#JUu3’)q̞!T3-KB3-Ąc3V5贀R-uS-D}#p̓ś6"4).M24HiU1>pՖV,EDL .15ŽȄE,A'q9n*=ӳVa Rr 2x/- ]H N8j4F&#ډb;R`,V"Hr)EK`CPCTmI"PA,:HD28~h㶩f:rC&펭#qqV)ۋ)ʶ11%e(E@Q k̤Dڱ6hcXxx1AIx,DzIPFbZgwqڻylC@wJZZt%sT&ﶸYPr9>Ko|N;-#7uQCw#{pg޴WV -&BhƼYiIEHR$3T||_:\N!*mn}7Hz~UDN=,FR2inKFZ fi{6  1i}9%!ub{TQX7Ut {!bcw.iΧ;:To` `iZT:2mw79>hP/^|yk__۷o<}:jLZ1oXQY9HL\ǟx~r84x}D (X&79T-o_p9#4Ϡs;NbZQ8KϘqHUwo`fc'{Ժ#Z#,U-jF cb R xfD*q&Q< JXKkGf AĤTψ&ܻ#)TU!} {nUS!E K20ŊHDQ!VjT@ift"QR„ZD %](ȔR`:ܻRD*TD ]d*;@PhJZi:5%27sh2faW6O>9n-IzP%S]2ZpuAvႡ " X`p%N⢮M$EpfC"#2\! dt=}:22="-$2Ø fh tAD<Ƣ 7:=f-=bN7 3*>#=F|{4#fmmn:]Q .1k̜I<(8C#uol@Ӓ =m[EHJ/Z J5"RZLf QO5R"%d- nEzd"$@-c#nj p VGW^Y]ۛtuXpR H޾u`?۝EIՎ6[Y[Toq8;qS͍-qp~W?敟]?tLXzT?-\g?*Cw̓Zi[goww7Wz ?g$aL(~L5#I z4zӟy֊Ɨ:uϪXc&ń*`F0{'V%[TC4䫗Y[sg긃|HNbm!w["r A)[BѤ{`@d"S pQzd-ݙj {sE5kP ȵfWIXH41+ah96-$UE A h)xO$|+MJ5TT(5v WM!)V ]UD4U 7M\ ɩHF)0AC0eZ;{ddh")2-)'ĪEҏ ~m0[Fds`OS[̊$="f}Ą(je\&8'},$ jf#A Dv'\Mz!뤓 s$Ȕm Y?o>g[FH#51Am)=sNvcFSjt-N` oHls0H4#;IF(nO'H'[nd+tctUR!8XK6N 8EB1Af&]nPu<`+1((ԨEU gh0=]tPwW!CZ@30z/bJ7yKvN<뾿9R}l#3 MCk]nY-"UAɾaYTLR9wi.;#O>?7/uSTDE ł-6ׯ՟Wxǯ杗7n};3"),9V$= T8OTeU1dbX+|A?{g3 ҋSp/*HĴ)?f'd-eR{GTܩ ]{[=W@AT2FATejZOɍTKֻo_zm {KyerVD+~r @Q#j.ajY>,R'Rf۽KS $9K#|)[y1*L{DD##-Y_e *dTz4vdXdlŲ=̽'Pd:wDd(h|L<8:ԩP!Nڵ|$bՎ`7o|ƍbڣ뾈_SN9}=23#z6`L)p]=wx& JD\{ YH%j8k͑Bl#Jy?3gALaE)[Vd@KlA8j Hx$1âS-NSsYeX-{ʦܺϑ3LjĢ$T,Qݓ3geo:\.'{UVB1R)HI5YL(J%2 - oek-,"RA&LpXQIP{LPX&XժItw(d&M'DDHtKBdd/*@%4Iii]c#ysZSV6O%ZJ֐ }m}}m鍑ҒsDNT$3asO=3~9؁[&dz`(TR S(9 "2)A$C.Ḃv|mu+o\k?{[ln<|ɇ>N˳^R˴Z;f)&uڹO?s;i=iZE)&>-N4YN=ЃxÏﱇN;Ұ2rę<~'>Ľ0: IDATƛ770)E[kl޽y+Wz֍7߼4X#-=T҅^DIaMuT+͛@}>ma:ftW7=ŏ7G".`}mrZ2r1MX.Vj\D>}/v)%Y,Wq|GLQX7'W2%a߻s>ԓcUdh].bX.ƥ} _yNaӲo=zjd0w̭׿!HXk#O䃋QqZ Ɉ`DRE7) 2h;\JYDz{Gf4"bDu` \0QB,]iWgN]+8; }fJ([`fj*HUpd-$@g,7cB5!A[.TWdj@)a CJI1`zGAb urVSi)LFxE$Ӈ*ǚ>c>ԶEC4fԤ@SIX޶q޽{o=Bፈ r@|a5\ӛ'c8Ĩ2Y& x( *ZJ HFs"'f%ZK HBa4UjoZDUA6m"H$Jg!߼!J1+5I6JΎ-l%GQ!AhM s- E͡ @ еv%3lU*G hXvo."|;3T4"j RUzRSRA!322C-BLTRkeRĴ0[|wwL4`_$B[Z,˥G73N,ĻKV;'*PN'۪Uf3p]R'ss˳Or'VgOa>wV}9xÏ]%Yg/cWoiT[u㝣v(`7BKr&Jr 7Q]Dw ʴ*tQS~YԨ) Ǻv_xg/r>CpBHhzZGAtG;8w䳗/>|^[7_^O=O#kQ򞃉 G&3u҉Pm{0!6"PRDT̳~V1XwwN@G Th9@дRe$f2*bb?]y_K.+ۻtW>\~~ӟ:Ͽ;8yԥ| XW&o7?1"_܅}k?$/ه.=q+K?O<|ͳbdQcDwooox;Ͽwx Ã$)m1 yk6SZlJ03(2RZ BwO-Μ=! s zݏ͌ɮLt*VG)|rE΍gr7WOԺӴ\zJ)&FFFDKR'pT.2LJDO!$P")6eƭ=.H&KRGh8)A"h &QIL&EjDJ0 jHT6)mFYYgO1dTMJ"LsC9遮4Z(%-]()*5 "fÝ>{ƥD:J }#VCP1nDL`Ɉ2:$*fwiS QxQFE!DD!+6(I 4`Iq(1:#2*+1<.E&.$ӛٱ=+S^IYRݎJ"+*B|,v T%bfۏ͊%[0h}"L%@S59jwR:}+[Zj[9{q֪uˠeϱbP3ʩ3ϟ]۷ovboc;GN|ě7L=pżp?3w~zm\aa1"EȹRŝ7ޱ;}sTRa@3Л7ZoNM1ٌH_ċx{ZՉ}2?C>l)!w+/_ëW~x_?]ߌe䷪rQ-j7~W_Wxm_r_?jܻ<1jֿjEZ֩d*PNTfཌྷif}bdXlf\|}ڵz}c˾-j2G.z3&J<7XL$pk]7^~dZ}OwO_y< ӳ|ɧ>gĠɏ8'>r嵷~v{?z}}y3+@”T$1P 0gxKzP袺ӪN}=Z+YZ#R5$3pf3Dtda^h=9gKZ,O@MI]-4SMDPP5HDRL(X03 T qL lcY&2< 5 )2*3IFz"J9[v+ҬpdTQ$S͈LaXQ(my1+̔D(fz$5R+iYU*LlT4C-s e;xbPdd=-z2i8fQ7ZL`>H1KZRcgN?;a?{76mirv vNg{Y佹=iaԂxڗǿ|b/^֢ᄦ¤SuMjAҊu"F E,7^{RO;~]<Pj)R$E2,Ŏ%,ľLӲ>(gQz. T0szO4!BؖMD=TC=tؔKIR"b'2Ap]vgz7M)v…}z"Ynl-4;5c9$Hݎ+)k":2~[/_^tOh r91}y{1W ^<7[0"b@*TjfVx"[%̙O>ԥKGj$= !ׯW*7>{ɣo/O>})ʹ~ PTZxؤ޽K(Z8ދɩDP*4={ݭus탛7ob9S51 iQ" -$ju]Lj>铧X.dqb1;6^zWHJzyF :p2,nG[R>"RJuZP,EU5gITC Z"DεTH0{Ln)R3U"iCJHBM̒Re08dXaiSZbRRmR@M&M̭NDRlnfuAVf1]V2iiGs X%GF/KNV˴,EŊIjo1-T" @3tO:$[Bg63 ` BD՚HQ2۰SݵZ$ {Qh,45j`$Q fEq 6iNم1>3 R* 餌m3LL/!H U1Ǜa12F@ Bbk`ReD+ EPӐ鳈$T8Z *A)R#DSX2RrdBL"bYDBk]|xt8o| rzp;R;]d4פd}~5.젮J.;Dm-v[Z\eS]x/GwThG&rpݓ+w/s=&Mg߹P娵Go;X.Vۤ\Բ;~L]ZjA9{ru\<~?*fL\0D"Ĝ!E?E5o7dQpGAŦ-̒D]COe1m+d1o:FPE,TZ${p:BZ˔[EHw!TL+6IM T4)"buJRR HabDM bžt*GyG+(5ѢK|3;@NCk;wfTԒJ)L Yt1HB[r1ooZm $JQAQ_w'o}y#=4)Q2U $P1bUWW[CHђ1HzǴX{aTIA_TIH#҉nP51&ci9p3EeRJ6.Lj(3hFfEZk-TL{OAf Sifb J %椦S[hP"h^η|wOYI1k)I-M]ɰ$=I`!!PZAlL#OR=TTU(4«* &LsMQL%$+zK{&@N3PD0ٛ+B{&5}? ] 93ME;"Sm$ GԥG 'NIJheaYbiF6fU1pUAMUg߰'1s<Llw-@!Tr)Ri0#ah<2߂` {g PtUn6d)6:qOFVDHdS%A&b9$OXsPE$).ELtJR *}pgDnS--e@*uXC>XfP F1%5cpbuĔ+w&=Wuدq)Jƴ~W1*7_;OםgǕ4H.pPm2Zꄩ&MJe{JlYvvϜ8w׸u=Xsg/_-97mLS8[iNLm*=Q.Ne_Gfo{;X\RcjGM0ÄBA81Qd"l{<@l>G)*IX1(IrҚF"! zE Gd0ݲhAiZT$\l;Ɉ͂A1OP @HwLp!QciEfg-ʘ3Dv&735:L5IOg*14)uH(234.UĊ@u1Fܓ:_e-j19e}n8nL;-$, (X6 <5< uO`#$FHgFfFĉs֜7 _a91zo=PȬȈrE*ArZa)9ʙJ1{Oò$((3A+"&)(i-s eDI$Mh9(ku)"FmYLUZHȅz? zUud)z\Uܸ_ f5=KYM6=;esh=3`\~wox8-]K6[Jṷ*:<{ki"H+nɵ.O\1' ]0\wէ/K/O>8Q.Wo"y#f+\o#9o/4/}mӷo~?|ya!?]m3b+wcĜC}#rmk8GͿyu\!ï߽k~|2sy=cZAFWE1Fd2v}0%-s:3+S>+È[\i,%mQ**N*vʨތ;M%+|[NfE8@|4 m U A8ŏQfMS5eӦ dU8P,rfe!a*"PJ0'93֚s_\ ZNC @n#agʠD_ZJV0BkR"3IrH0c:\9LD(T+CeԪȒZkzAL`Vȣ.^,RXsP}_f*PZ"6@ˬr})]* SifF(!سFM-i@i U)0eP( IDAT fW8t<(f{Dc T.|x/+i},P7C3_}Ora WuHW_쪜f.܊VD6:w˭*QoQ!ePhEYȎHkj8,3Lޤ)|%LL70wIA#J) a rm&/t(Bq\+Y\+<^hBGZL!EA L,6+a. hU8 pRDgg2(-s"I5_^?C*d} S5 o#ꢐNS samV%m[+h@Zʅ+aƫX 5̽a 32QC?]U 8ԑy5>UTt]6aE?iS(71 > VЅjUlCv&l@&1IB5`e2/NWt(q_~vZ%CR*ne5PM% vFU޾?|˯×?'/978˛}=Y O|Zطmop=|C<])o><^Vl] 2#KV'] }uMV}6Q]> d?,4U#cBIi 9JYNshgs 8 &L,+$R)NZ h2%A-_T>EIJؐUr}.PY,!dX2H@jaHm FQ5eрs;^1K(}:xA ۳OG2q$aV)e\&[!X2z9y5?y4?]'<|c!ҬL%ze.SCTa̸Nr8`6J+vR3)†B e&{'@= Gƽ x7(7sHUrEgVre>GFוש=+ ! bb1׮0?U%T8 2]u6+3O5y*= QC'T?LQpZ$ƽfb #Vin&5ӁhX1$%%[UrYE{e&aY3~Jb4K+k[Yf-"'݁K!y"4kH;zyoE.H'VVsMo12r @G±fY1m=O !32IfD5GAB{}J[ʧeݭKee+*F*PW`!^pQ 5Zy]µfDz7߸gW;/_<_^`xxr )}noߞk}q~^Ha7*IU*c*a+ 0޼mr&|=^v_ܼ_}xZs~:jy}R@W8_F߻I9'd-i82LB53p8,RdOll2UHT`]Q&*Ǚ>LX#@rm<0oe^ gDӈS4zIi=],}d1++D #Q E(#XU -"denhU*$ԊbyXcPq˰uAhF6Zfl;FҰz'kWfD$FsBT2Jf-4T 6b*AYOM%Da4\Ɩg_gF+{L;3{o]w7͇;Nvv g$wi-~ꐍᦕfi,>{NmzwQ<8IZd(~m쁁^͎٢p eFN̳J lN$`]/ "j 6X-Q҇`J4*9j]i~9䉸?O A e, J3P:GaٔL='h Zf7F֘O2lEHR$| (G&R+YpR6Hޗjy7M(sIP0Ȟ1bP>x|Ivl4f;Znt'%.tT¨Lƪtӄ&{n%"A]|q_ǵW4*v-q Տl(L%Jf?rǏ廟zןp˛}i?t'6 XsN0/]\sR{Rc]ּfN=^_çcӰ۳΃qkՔe.@AO 8 í)mdy!Ĵ,Ě4ώ`,aSL@ΎC(?Ɠ0 3Cbi2d"^%ӊ}8mM`1;]7CT1Iϒs{n\'Tg,:U$7\}5-{,wT n$%i sBlH"w?n#ĉW|o"iN44vrk!?ma=8j~]5xxl{F*o;h"VrN_tGl̤q6$bIT)'aar<h2u^,fp2݇/'_la }d sWu@qbLS1_ݾyq>ݘmctq),VɕeT l6i;o>}y篾||sNڼDiX~Y@* 29ls †a ӍWAi^%˭`_u`pd{v6D*Vf-'KdYaxd&\eH@B"X+낸~eE 0q;2 ifŲBA!* UOf9 0A4'r2et}U%(2T ,M=䆖 $-ˡr3T`ITan+`~@bhB; R~L!)vgx¼lTP` V ]f3wc*C0*2ߢ4JUVpc*t: boPY2؁$!* 4Ja$oNphaRm,ᢪO<f4n6#4,>g?7/YidVRy[2H3yYe頳Ҋ9st?dw>>/ϟz߿w{}|x8}yͣrsrD䊨W/5sfݜ}yZn7O?g?^sSǕ'>]sejFN&"±ۿ{ËK:nO/Ov/ۧ߾~#)#ijeL;5&YAcZdM&Рw0a7dI[cT9hY#3)eV:"tÌ)Ǣ fg6!q<62*T`1!dfc*tH)/Ge G)m5"PKJ%#Nv dUg`}d2>13S0<2bJyc#"3^}C"Fe4ҫ`0Ql1"Ī6<c98T}黉v0! Hdu2dP$9D tZuTR-0Mfs~NW?y{D!W:i@7Ơ`Y0IUѿ6ЛJjBWBo[瞵$|lϧm4ncyT^{23J,,iLA4a-PnXZ97~=Zay]OqjJ*fGD:r4[* [5%Fs6ht [Jc`` ַѭ8|2 4:YkT̬ ߺ*6XjU׌*YD&d6jCrPfEa!8TPY #cN&$/1N;pAwTV"@7"D\NkV!]. < ؗ~p[sdU$2`AC}# JV&CTzpTSTfRdRiGF2miƕuyrP ǧ5E"̥Lk36NmkJ0SYVyU%'ȝNӞGb\%ܐ,e+w퇧wՌQXu3a$jl)r@نmO7Wh̻Ww'mW+_w߯SSmQ2,i+tmit//'?{Kþ!Vhh.q+ [a}{>iW[In7~]ZpXE<}|GV,HsfUII5ϬqYC<ʐ+FHVuW4\O׳F H31=nt Aь *#Ǫ~Rfhrw YB0>{\ѪB8 / \Ce5rmԁUif B~j@R.9jǫ"o0 SQ7Y\Ū%`kށd U+WwUMPZy:kpߙ̏ a!.ML:$o]6(@ y|Vw:\G)vYJ+K8pG4x$l:u;յNZX1Ɩ+Jܴ b='N.0a1jBHZUšu˒e;vگ*+ƮfidIё -3@2U }3~$/VPQR}Dz=̠nn] s afꡀU hJT4㌐5FeΔLTX32ͩ=3+Ҿdz4NwsbgO4+ %U)ʒS8t,e&U`sXaޙ^Ȫ%@VEzaXٲȂ{UR阤*dVxjS1 \^5,R/1UY^Y,'P\QE' &KP`T铪t}ĎLo6Ǫ2iMEU` r ='?8}?5y~xQx4]uO<7>NMD+v37˻w_z4q{&xH}n \7_u^zE޽?uye\w'ۧZ= WnͷY^QeDd=#bɆ+\cti_ᜧMo1njUe"D涭%M2ȚsD16*L1 12)B[UlVCHF){AA4g? È#PE]Ja<$y✦tyrUGh,E1m&ҘZ`)5EFHX2G*4huCcNP~T^^y,"֊1:'T͊1pjiQzݝ~^jjh#WmթX D1%fO=*[c+C}w5:(f(5pIJ:m̪+7p p[d2K&k6Eτ4RYA]}u0{VA~mɨsjaN lgܢF%tæQy Čdɀܭ^4o|ݣy%wba 3D̚aQ6u}}xbvݞ0*+cx|MZq|rsU=?ǎ}lf\>Ns9*xm.yi=Ư~`LӇ/;P0/K./F|.w|ķ޽}5cY9%iKlC+M1S&ͪ\y+sXd>9"`Mk6d,L Y. #2,V(KnS,FuLݩ2(hӨ4+XP26 Aq%h}?E@ S3UVMGI訣e@0(KQCrSHմ1Z 10Gi|"Jm(ҙEs3s]]uf/{ t;UDu~$y!BnJNdYw:c4U2CP{¡Ex3oBGW FL^⥈׵`H*PYѲ`Vo$8eYQ㾟(l,S>(֞%Vþ%_XTDDsWD7`xȔ0Sd1 V-{B" jS\Cm>׽J=XkPmHNBZo1Aq.ׂ"S@)cTe|\)f֛ʍQ)Q>ұU{kl,ˆq 0[+K2uxі9X3[c. +ono`^D gUE zA(S80<4h}qBvwV]B%fTn+> IDAT%ஒ*wKSփ\0ܫv=9B4lK/GW/2sϸC+Q4* Zi\P)@mfUKi__dt%lf;Q<*? HՐ-[Cd?/Nwz}rBX8Ukik}ry^׾V͹mU뒏4onoo>/>ͺ[O5pO&ci #?| V?)>կ8m;tӗj<_NݾC}aH~x{;Oo?} Ɛ_O*oo^W=ŀ\5n p)zߓG7+XTrJgUMΐT6&eN{J.ussHELVeRF(Jy&hDk1!(Izy>aXA=N}UYIܘ`cYb&x$ᰁaB:?#ĈA Pl6\R/GtƞgeϿD EkzrVEDtDTѻccP2ҦUOd\' sZVtUkޫZ(ݳPߔKqa`G:8Ҩ޺ P߈1*A9L]u*! S z:_o>_UvyվbETje SY4ݵT <7G̰tkE|?.. ˴bE&S]i+sv4#VBRDs9eó*`BӏĶ2C Ucl"Y@ceP{}Wd)Ǣ(7vŧU{C^,ji^4Xi%RMHi 8xndaeQB֢Msk6ʲ@dP%tuH VJ8 H&Y1HӠ~$S4+1P[#H)(k:U2? eZC/⒳sxF@l$60-VÎTOQ# H& ;vgjuά2pz' arNaUEoJXؓ(ɌwC.WnȒGd|x?~z(gÌfUel:͡Fkr7�~7<[o?t&&ʀi Qq$a)4˻/+l֊a7mj=vܯ^mO_u~{W.iC y>\w[0یÍg~b˟n^ǯ_mv߽~KẰTKWߜw<fnx|`;|֯~oŧ_O Ӽ$%0@q5HbN**σK6MlJ@inR{&w14“K(|* $ussRY mFc8)!ۖףL stll;ʱ\L'njҰajHAkX** Z;=ŵF?|__NT]/ןg?C%Hxx$@RoN:m3SI mX 1e3]^ BnέӪ U}{ԉ̀VwivVW;S)iF3 ͽV&No>}ɍg?tƎ~L֨E R@[Iqq%6+9Pu23{ ;҃ LeHe2LL2=vyaQWc=߻z ɫX?UVaK\kM҇>u+"&RԬq7NB{a5{͋y9Z~hc&ԫ{m=L-L@f퓝 KUZ9/=~>~=܈HN.r8Y%d fDV5hj:u *ډ -*;J \K]u2NLsUEח,VX9j̉@j7xAr@D(Yn<`-`'ĬF,2ix]ݍXzSNN"n4IFD\"%Gxscwo.-Jw6dG H D$LGe<.+++'No; BYHݐ.JpGڂQi o3Fd:7:tM"R{MsXXՂy"(j>ȩS~8gfݽoH@L84 S'OK7\}S'9 " K A@1q֢`o?f. !6Qƻ+f5USU}_Rlߜpѵ fWg/3 kcX\F͐ Z;RavB vá-XJZ6r'0UsSsS5qrʤwfkhy6pLwvN4Zc꼑OHIsiawZɥufq'ko3s'vHmL+r{FΉ<;ȫjCI*NٕEȶn! J`+N A!\%UnT`JV2i"Tnd3Qr a$fD(A-<\BK&&w7kPEnL6g(N 95+Ȁ@4#+y^;8L7b1*FċkJ䌐SQpmGm]R"OPWwvC24FbTJ._auǾ~OPxZh&S@5nN`.863!N8|f/%]J ҩUIJ.FZ/dfJfMV"TACȜ01In\>n)DGϼv߾~/'ms:RCcʙ'MXav`|NI&*}?;ؚ 38Fg:!8[VZu?1߆+YKݜiATIYK< Pǧ#Onl%N,VFj& NX))T2uJ^CI;X*^I 2094 N-Ǹ|RFC))+X4pVɵpYbD?.3SG]U9h*DlVH+X'bu2|YFL`JZ͵M:&1qȭ 0a4ZnjL\ԅ,MplbV ؓ@cKV&!@mwg8RJŊPȋ;$ 1;XwL`t^ .ryŧ㡭6l F>y ˩i2k y{{g_~tqެv;&fAp";xK@܅P2oaQT[8>7Y/h0$I*BɹltڼhG;>y 9jFAROOӝt xoeOnyqri4Q&C8%NLaL5!J`oBQ!Wc@ )3#kmlcbLOSL;_I\0B3W4Ż)&i <tNk:k*a:%* CfP*C#,֠@L0قI$L`$1%X#pUU0c9B3D$3acުJV[A"A1J*1kHiqs'! jJqP`)jJU.c@%nJ @\dHZװL=͍#S4Ȋ933\o<:ܕ#6[{)3#Bhf4333ST4G5L]M Kw3bLXb"X0'i"l۷o?}4$jCyH)!3]yO-ny^~/{w-C]XL szޱ'&dQeP֓4?Rb/VU:pX߈";:,a7Xqױmvj]Lt lEs.."a$Y}'IDvݺJ 3z\jUʥxQwP@ȩݓTXn÷\k}Wgx%fzd˚mU4yS_w7]y¶7O~򶅙țBM+o:ft9rķ9t7~C'I[S,1A׶ ]Yb}ɝ"Da 3Ydsl48VSs8b"Eb1O (:9*Z0ÄNbq as&BwLvH@xvO5K4;WT*+pJ0V#3ZFSk;&(5>%ZP8qbq/ORJpCj@9J`npn(lbL>]URZ,|gI)QfDqTZaNńHB9$6&* %5D]'SF=U$)ipZh(Pj6۰4WwI^ձMtD42V.E_vז˴+1Hx DF,NR;Y8Q.T$!3Ome !@%u}tBw`s. yffv۱{W흝?z<ܝZW5 ZX WuG[e 洪J3{zJv,HNoARXz$ gbDUn(S"B?-uU5ߔ<ɝ^;3䷾_MF;Dxq8n#]{eFT|݁ؿGkwݢ0/D"Bz0^Oܲ0WyEf+.q奻յϽ/Z6>T6?kݝ+񙴰{Nع4{޹̉0I\ Rr 2%3g/Q~cE[#U#1g(R8*@s+Lp.U]ɃTUAʩD,z[qDXHA SJ,4fwAY##1p[Nl(f9yMU xgs2Xׁj1xhS Z2!qjM dDoS@] 93O*M"(6̎-vs"I#(%WLhE *d^eO 0PR3r'kv03s Zhc0̅)qrs'G ܴeG-N2 ĝL9qjM1Fv3Ys$NbgNNPzFaEZ_.hWi\+}632[iSLZsq2!IDSqnLSڙtj,GeҤ.TW/p] muoo}Tu%K>_t_|pgj0{8:@ۻk}W<1: _c.ڻ}iqV-0>!ot4S `hJ%<%2nS˫}8KZcPVQf0v9PA#Bym Hbj%ս\TM6(1BMݝلi!XHM:"*uhJT$ لAV'aI79B6u2PuUJJ@Ғ>T,U4DQIF f3#̍HCsX4kse`g W̰eU#lP7&+D[ 0JpdI8椖%%F(H. "RFLK+!3Dl+M001A=:I P,^[<|^.e^7j^߇=~`N˗RbU2FmT/t̹;>kYmq@iU]aW|˿k7Q:s+w]TJ!xaJ^hyyX]|mTMJv@9o/j5bC'?|;gN#O>Ʊ*sN87o<0{yb۫Z '_z]>KsǮt?/ʉƸI^# {7ׇ+,<z#i{1@J>V5 r"/=+Os͕ƨdni«ts1NEN]}7OrrLt݋\uɭw:=S:aؕ)</>vOvfwn}^=73IΙS+}מ{%7S3Ͽ{ޑ(HWw"R+uZ ,9Q:9+NN#ҁko޾sW]W%^?ǏY]ZJUU3swgf 3{,6Lg5L[Dz s:7K&f-=pBBܑ rHj"pxln`m|Q%pFm۶]qف4nˈ Dۇ#s(LBIJ}qԩӛW[2i/-w=| VS|f1G[,rcw50aZ I5Xmkxh3đ^Q%Œ3mWcW)ERdjqxQ5ÕaNN++g̬--.:IIkky4l /~X*_Y_K*SsSu=>GUkߐKe=1+nfw{G8sG?vKO~ճޏ_RC6G_O}+?;f+s+}fT9=8߶G3 NQ6FCw+C~坃L83|G}S?n4ap7cٿnϜ^{k.œH+o/plϜZ9!:)u wz3ߺ/FS6{;|ԛFm@FUꔦq ô8,ȉR'o45F3y{iǞUkmzf/d27O?Ow9Ҕ$2rZt,_c5 b L(xRo U$/aoDmYϦ Ǖ5 1LXH"NqK-zg'A],I2Na0!gawD`圥DL)&7Kۗ(rfmm9D@D"9QHnnl @YWKu$*EUٍH :*I]XwRqu55'JpήdPbhcp+2-Q#C\VP4|fmTZ)`sjrMSv=N.OZQoq; I[ un]Wi+uYJǹ!$0*Ĝ=u&:mC!LZ dUbïسsn׎R{ )p9„ FPP"-0vkp+-%R%H!!Sw&q L-BT5'+`RᙑDHB)*hy BQr+^%kŏ s",!Һā\wILrԥ1"&bfa/ {I߱sv[%^L5n94Z*\&DYF(a`Ub62$ fnlJEUֺ0$("NDed (" ˫PAPJN)܉`6:Y.0S|BwpH8g\}^wv#wDf'!7-.wݰ>ן7WqIc߼MmL;gDd9,)Y~瑵Ds Ϝ| ϽQ+?|t~i]Ts vxSZ/1>Qlei:9D4Uhڹ-AǞ}e/[gk:Ǐ?}6</]w|gO?󭅌;sZ2$m) lpOQq"Em5./x;\u䶻/:{r1xaiߎ?v΅xuTkl??oՃ=zhWɮɨ|?W?9߻}'5'U*P۷]pޛ?r vս#N~x륷q;sb5Md8Nuu}>}㱞9q橇{꩞zed$WGol[Xw6k~>wgy/oEw&$'H1K>*&Y$͗_~̪oCw&?z=~MNb䞛 `zfvǮ=_qv^_;;v8O|o-lS LtWr@x;iW 7WjĎ FNf-u㽫DBfeB%u7%irHs4!dfU;;Vr3! ;Lu8t:ӽ8s ݊Y`fUo!H̔3 W┭}a+ l(5IJC"U "lLdS`>a!"OTaJ$?3ZR[ K3g|!ħ]8ewh18)y)F\#ui!Vbx7KC{jK͞BQ )+s4jcJVr#L)M%/N)~(DB9,yvJ/92WYrBe/[ I&1Qឩ"ʅ1#ղ3KQe)JL"#y9D !TGT,! Yf iRR5wSusb(̂h &NnufU ְ̱*1w͉m!nTE[K- `" `g,Dl;p]k]s/'U:zl_صg[3fF^1//K!wG23<ٙ?߿cT%ڐRE_玿 O^ 7Ϻk=^?{5M10I57&¨i^?r|9+]卡f 5hBSi⩌?j;'W[}Sp^?~w7GOw?W^o-sʂ\F;/{_}2 VTؓ'o* 4"4୨ U_{扚_S?o]|Ӥ340%nl}fcDz3C+U'?wշύjn7_m}O{gd${~nsjqܿo>G<}˟fNN"G8|$1wߏߣf.- 7/>9\s/,L&V܋/{}=ط{7f4v 5ZPsMu93MM?}ѥypw%]|`}s0tU9_|啳f8r5s?gqÇ~_=)a* Iga+$*u2ʉȈ46fSPIU{'D8*&|hE'~n>s9ˮ(>2+>4@UUń)&R`8 /vPJn$[˽:yp4 R0 Rhȥw{݅{Ͻl a%dȹN<wf07w\Z7&n%]I g+ߋs?w]_rSXiRBRJY+\N%uUԚջʓf<Cz="ƃx9kJxgw [ۡ%'EGfnnD(oǟ?<N~/s͗\qι4շxЉ ) UaE,9G9K{q'$WObgm=#3a2{+)iq CsZ:6MR&$s WWhىɜ>MjZВ*3fFc2bb#d(sҸWOu7sL,n"bZ,.3¥׉[ =\fnq4d!dS-xR-:MɡJn1f 1=b&l*:1/цsS#+%{69L[Cي{c6,JQ+ť ;%N4$; `8#&9, b6sᩖ''X_y{WZgJ)Z͔HEf]y>'6nO={ݏz \:zw^;6xTk$'S3'm?qcL+v~q iJ"y8^N SE+R+V fM?ˮqdQX}ߏ`9yꡃVG"Db%ܕDa̮=N&-Y eh)n&)h 0m{N(" .nVY "r<3}^Id<?>ijUJH3'#%vZftꚙ;N=r;'Iqg!&n/2=՛uϿkalIfb-d ȡi 4 ^ %s& \n`4^o냱Dj;Xh:Ukz[0m9HǓaL23̴޽0}?{ȋ_4:{Z{s#fAJI$%l,),K;QdG\IUr\$TE1(%DJ$8 DDFpzc`*~\ts}{;= 2<4sFpNA TNUDڪdWUB|hIV/mQU&4# Xd@[ڤxQ$kKp"A$9, DGg& If9%2"HɔDR{,I BTM5gK-ח{5XXx"ZԴ))Bl &1_+K [@:A2  QEX'Z T]AЕҍ]D=`vg )(QD Tx DXEڽRv$ `0<hI#V5iuM)6@Y_]={qkw4nG,3[>x=|y>:AQhf3lA=nGupwY !C5ޟO (F|ysZz_vīh:!r^i}e gu}79׵[<|&utk|5s R7)EU B$= "&Tg!IYsC5do/{]uR'~39qLٰ;KGbl0;槟՗Wٻ92)ѩ˗!&_c8:3]ʆɔrq 3oּ[^gMcJqf \Ťىi?{8vyeŢ`^׀ IDAT_O=eCH⑯ ޟ6`]!9RkV=T,j.zpMz~>Ϧkk (1gz M6Dy9ZZH86D()$%ҊMϫuq/ {-Koh⩳}OF'bR),$ %6{.*@@nQ>x%n=s.sN2M /_ Q`fdRIoɆٰW^~] x%ZIZcSߨ5ro8$4BU(F$b, a QJmp"x+"Z&A B(Ee5q<ȍXyf:V;ܖY ¡hnJ/i)6 T Sd*")*ujhWT0"*\E)h>hcD hʦj5 + 0a* ` ͔`mftC $2$!bH2̂9BZz\Z^Aې"pp!A7U! 5`ļ9 ;id*v2Yk/q T#c_w]rqs^ZNVLk fc&+X VZ3wp<< ~-asdoڼpg0 HV^;3G&)r  *w}†E]EC4ÝWWHbe B*ޜjrpi12f#6Dw.Ree@f=f !sV&I7\stʗȬz9bILɜwk%x;nY_]֣O|ǽݨ{7ҥx}2X_D6KÇGKr_>GnofQLMP&IYTUC2a$ TH(M=,`އo/=t<y(.r~+?LP5%8T侻櫖 ~#O+ם7H$ds Ͻ+ j*CL(/UHyx  "Eԅ7 phfmz!WGHgIDڙ V6FMtH3R,%@-MJ; Pŝjl $91$e b4TU)b(s zפ *us !K6E +T%YTJ-0`DÈxhۂ*jJGphAz1!J#$RUL ahLP)` >YjiEp5k+[-KIER!%m aRjY*BeU%eqV?uiw6]2%|/E1{{7w\AgIM#h[z%HilnFi2)hLZxy>-^[QcTJͭ Ku4ɶeR,5!HKGe۷\マ2y|yhKg䅭޸%*fBݺoH`0 B-tEс0fEBr)ڦ{}rr ipMy #%i޻9}6o/0~Z()g}ۛۥ!D^wmoNG>]?&ͧӶ~wӿ;_lbcCz-@ OWp˝j.\7 "tԽwj)k Ph3o7C DDmᢖ55ymc;2"f Y!͢ T$jpAIc?ɓ|ӑxc?uꔚ]  WHj΋zHn]+-w K! RfIAEƛ뜦MXZLJ=1,7ſHPDYb@ؿkKGP!5U\$P(#^=rԙs;;PLG]޿omx}Ed&+ny~ߏ=S'Oz..NfXܳIo|+`AVCKKyc}.n>I5?{[9rigSd/%uJ\da JMU53@Q5< 4YD% ؒie$ D(hHQ[_\[eAEdIGM.Jӹz'^+Ej0$p\ƀCB j}IkI0HbfK3H5F+FxnWI*]5V$bax;#Vq (" (yq;th?Y37W?e *ҕFlL؈#)=@$T͵T (3(lY2ks"^tn-ˣLRn!j岘`Fooy^|w|g ݝh,ta)(*"3u# C1J60LT64H!{8IԤ^!:U%T 6RZ-#쏆[lY+g6qdcӋ́Y"?x @X O/~>?ʉ??s?wȡbxwZv^uIȣ쥶@D@4`bXZ]!cF@;`6T)ZjDJ?gO>Enee4^2Kmz9v=¬ ī \4:"Ĩ"*MRCz"7\D+ L!h_adn Œ&Na]Aġ;iJs:+$yM7_wU02|U#fڍI<3K9e^KsdR؝إh;%5q:^c&&KK :bܦh lSR .m7]wW={#GtV3ɠ7mŔ*h ĵW>ulƣѾյ,wj;ne5Vf>̦ՖG㵍kS6/ -Mt1a.0@G&nu˓de糖[] h"~/:ƅS}u~d4A 8wo|CMJ0t~}_9%!j,Eć=G?xCLΞHj{mdNHϖY"j!Mab䵸 dW1HNK"xRRGR3D Y\CT2y8,4e3$wXN[F5C<$0% $9D)-1*[Eu,y4U^U&wGl-2Mm ShGpYDɘ #$Ui8x3iGKh $*p5gbm[SsŒ@AY!\q95ޝ$%aŐ}cˆRmw"$4+FR  $NZդ Wn4djEUt 0K_U_˄.qQظ?6;덎=g-gj52rPCh("<𢋙XL{쁉H֖US9L&x9o[DmOj2^I-Z\uy=M:^sW'K q\^hqߏ26[Q%$kCg 6aH$~h+,$h62{?VZ@bfՌ ]|G~7?D :Z-r  ,Ń{c^}?:#luyoi˾F:zԯ‡>צ[ۧ_y?ӓ/4_'_y_'x4^a\(wZ&qP;F-N YSuBiʋ60̳0I1@m&Tɣ/>fum>g3EUKwwd sH+ қ;r_98 EVo+Z"lE2 ɧvw/S|9gF\wu?o/ʸZw>r7nV7 %%tkN'KlmBWZ)naU&]-ILEjcJ"[fae PD$m,jyj"e Èh2Y>ȡյYMZZ+S#D A.Whi te} @?X43JS0:+]G,*e!m,-Egw#HonǠKC}%RڙsɸC=~ڙK[cQt9 ws0Ss'wkMtA$ 9t.d+EJYQ D#}R#vfK- #&x3E)JRhi`;X](B69)f- 藞0YElIx)mdy2Z^:tõٟ~jϜ8Mw3d}my{}TEu Az U]q)vhvnN'_y;!u Pݩm֙TR+p{-M~wmPIxZym(ƀtpo'7&l_z8lL.jRRxi #P(jn3{ddtg-Vhw}} $9V !^ggwna{{qE߿_e ݝځXʹK[p}}ED kȚ&%m1.*nnW /)Sݼ|,顂]=5Sysg*ftnv;^&˓xr[:ڳ'pYް#=&qKݘ7cx[zNF ڒ=o$YmoKsPR@XΝK@@D #{8rZ*ꊽQK(FH}+.۾pfw{PR´kVVq60j$~ L-p+ٜ9urIn>o>箔OoHݑ$݉Nr" )ŒQk<|凿}?O5 LdpIYjՙx>;[q У 4K." ^9k$/\W0h@%L.oe˪u`!M]$H$!&ť>/;)*jbT9{o[Hڙ P{*J8A7h֋/9x4(hM9,)ÜAдe ZI\oQl5" ![D(Uw) ^%+q8qYJ55(,YrZH(I^*:wDo2H}qwB1ټtx4Ni4N-ԽXhNI Hk^ʼnl:lE::`%[aݧpUG69+g%(XqVޙPovKd/9+d(RNpfI^{h6EW· EbF[R-9cb $L0FSDղDvO03ElUb(;Crօ@в└C!)t>) IDATm)ew0 cCCs!%F9gZJO@1UtT{0eE%T7 5HP#ŽT/zDFd £2tKh0$/EH 4'`!] Fl;SJmQJ2H#)(&*fC J @H ϩ"S<(t@ zvk` "ꍴG(z_eİ (PD e\&f./N=R}_>r*[D-P5d||Oh+>Mwi뛟{fyu!D_o/< WW~K}{w./pڏ\vqӷK?dt/hp4VQ*ߘ/|c;NbIpteRnݿ4kta':qe)C;,.}2;88ʰ mtYJYʂwȁL= gz*8rǴЂ4nH+=gŔ^گj С K]vsH4 tso|EDD&%1ɫNy#Bk+wv.s]B6HS o=;%L YX:Qꖎ.]x_˹k8Hʹ hf /ҢxҍLi+Jī/meک"4xò4Д-oN6]+ZHlh!I@],&wQjn*0-k)0Q" E@t9cwy{;o;玷s=pzP=R+nxuʫ/:@ (CZsX[]=UwV;REb1g' 6"̠!AGK:keQ.RW&֔RXWJĉ2eWzy`oY_뼖~6_t3g^ʊf! @C\$Ն!H(ÑC;pM`g:'NOx[oL,%&3Jw Z#h}u~䑃kp Qsx*Un`{g>~:d@$=}4V h-Q%mUcw\e%]MZji ETEb4n&`$$dKYˣ.-euI-ԥlӪIkJ:RKk4zR}QRaȆ&5Ҁ&&ZC=w 64$hQ9,B%K.Q B[.u:D 5L{U%.N7zAiк6/'Q^U D[*H*-)GUau" ER*E"N#0jHS0*X(h0ĽŴէHWZ7 -aHH`mÌ[ / l(LQ и;0vdq"F}Eߗ>t~\-VkHZ}Z;UAQc 2D9yo"De[>GN>WsN8S|ƛZ9b;х̻p矺|u:qR ׾]9@ZF]Z^ovW7uE,Fk[bζl}/k`Sz.=a.FӰO?o~~n"@£B! C/|Ϩ/ŷۛ'ԧ5V.Bmu:? Ϝ"`!4[p(QyN{u<'#U ~K^:hV8J-Dv(B_AJ?퇟7rQLjXݰ{KMΖd?=?/_&vh )uhSљAT3 ǟ}xL4iRM%L ؛$22@Y 6LŐi6J{\t&&AUH(^ۜ&:iWUC`xQ(չ8q׈ZkeC>Rw3oqi58ȅϜ9{<]THh"U5lADE[Y`=kPYU>_ RZ`Y,!O={ylIE 'rfH) /<}#,[[C>z͝ ;;}?oo?݇rM1P~Ge0j@/,k:  :үof~?נ $ qak=`%}﹗@pvCZTsOL7iBAM&/vHIHkDJ@Q CT"hfb2C2XGT4!hMFF+K$R8Hu&BÒx !RTR\L1Ɂ`aJegIt#]FU3 LcV LT3Ks%@Ux%( 񘣭0P-\= J&AdHC!v&h8Km1Y` "=Q! * %.PJZo4Z^7c, /VgL{vSg?0g8|}& q49|K?oߜG!VRHu,op8rS7ȣ3zY{smD3n_pnڷ%hw^G^<ǣVV֖Kg/? }oze}b ݺs[8uU_uش{W/|灇gs7 LT_xO~덓'~emK++[>̧/2hy)cmon>of;G8r,^g>O?~n]1"svRUh&CBDW?wf;/@ݧ~K/]zꕫW^9:36/^y+W|W]Q$)hl"飰JqqG]͡4T>/xu_r̷,F3Ο_899y!]png{z|'|…?FʆWV~>՗/ҋW]y<7)O_xKW^ W֛0s C#B$?)w~O};'fڵ[O~k|o?g>-ܾb ._yY欛~w?͛`Ҳȴ}]O׆[d| ϜGhm4KRRbE!e8ֶ߲jw/O\ӫ^sc?NtŢ 1' u~~/~k_;\}P`Ǿ_z/3[g*3wsOXor3?7%r4}~.̛ /=ҽu*Gq4iN %?W/?ǟk/]_?>+0"nO7vέ7FrR?/~+"J1pH{ P]NJaRF(}t+" &!7_~_͔[]/ܦa|6hb'NPl'60GCBs=I|C O~[`?݈mx얕_?;GO~kc<7=~jBIIk,lݓyW'Ym#KPd~ '75D.L#o}/tn<_үjpzQR18w#YEڭ+x[pg` FŠS6CI f Q)bZ 4Zf7KvTV>ҼN!"Y=k)L-nG K۪F{ܗ*-dӀa6,ĴmmG4N)Hff*\9l>-2#GZC ^8?xW-e\}1[p[}ͺ݃k^wǖ^}_+G^~E;x|{Ï}c_w<:{={V3]<ܷ7ę>|v]\LWn|ozc7޹}:oUoyC7_>i+)yOz+=xp>qHGd>K_:y.1G$F0- XV?wGytt}2 ^G(#G ,_sp~zx̲hޢ+(]|CuzZŇοx  V u+w6y^cIs¹GOLŋx}9̌rRHkR_{^w̛fѢ̶=ۜz>={g]v4yQ0VZX2{Yo֧!y;{#ox녋CAAݜ̛>#??upx_G~@f;^޾FwnVKpOȁj=shƗ۷:2-O=8;?%ȡsH,3 M$㓍vs=m]zCݿ\-1,GaQt{yP~|#N)77@,+7k{͙ýÃgz9`P0q36ǸO=W_Gzi] n$ك7}୓/X.-T&0ޣK2ݝ}GnkTw)Ժ"2O/Fdd:_=tM}3Lox7g[GOO23Z>l֫ZOº"v}?]|cs刑%N {ڳV'-3Ǯ޳5 ݍ&rYwٙΞYa{-9ibQ-VD Hb)BKn.Jqf7̼xers"+b4bm|RӪېA)#rw(ut(&穹0.Z^ af Vl }K1hqqCiN~o ᄜJXEBʜ pctM@Lt0Z HY %榌qH5{܈IHЍ0ztx4)3%=Ip=#3,5n6A;-Ɠa0imIYq]ك|䑽˧owOK䊱,ןOwv?|nl4-գ Q.G-̨Yi@)lfe@+"Yzk<ȽS>pկSwJ<wn6rzG+.\Iәiup0}o9έ둧l;މW'}ݷ8yO~~xs%:n\99]7Vzx߮;%qr$ݷG~~r J /Jz5`? '|ݹus;s~gӚ3-̆JtS(dain8:D GX/Tut,{g\8 W;uCyzjك#i6dJ1[ܸz+72zJ{^vH2& e9 EL՗Hi݁Ռ *Ƿn߽s+W{;{-* }{F I*]GCz Ì qٜڦ͆l6`j= 4A!4 lu9Ƒ tCB~ Y{9x}9L;ug2 IDAT)j$!L:ݕ:f9L=蹍 # RʠR ͼYD^TKa#mX:EɋqOZMSʋi]`Q%w=99>mi3+wL [)U) 9:9l"`-uJ-AJ@Eu lzlT 9 EK9&]9$ݜ4. ewQV^9Hu[LGeavOt{o=ɂ1) QɒQHqUV;-*UhNw%zm͙9T{f/u^%3$yE)# .a1rk8e >C) 3,GޢlynkZ2GX2 -|(dXDl`,Xu;-hK-dQ9Luİ8<+@*N8'BJ:R-gg7VB*"HT# QtI=׊ӛu ZwÏg^/\-hfaHX轅ԻH+ jhm^a& rE˄ J-W\.'PݦoJ0Ӽ霧ӫtz=89EYg_9=ٜbqG<ϼʷV\oNչI9?3Ӽy빗aH"Y e!"׾8C|L+I` ] M3PJyg}@/Di#-'nSzqLd"2u aPiƔ܌TDJ3:bl6Mxցbm̽3ωEp̃VK[ӳ^ 3j @[o d0.F&$0a¹,{d޺-$RfiZ gEىͦRz(3HEAeiNOm/{D#-0#i6idle)fFγFoeA8x4B91轍V3 gCbH%ɑ:yEYIZCt A1N&zUh^@I8YZ&H6ڑJ{4nk?ydʢdZ/<45HB3u2֬(mWl;x`e͗n- ,lci}g,eL1g41ujlB _XqRzLvxȅ݋%0Tu"r|zX,Vrvºu)gt #=3KJM|0gwIne7ݍm5:n RKK򂞽*ƗR D(LV`&mz]iA5'(Yh@FHcVinȜ^u: dp2E80cR` 5/i)`)iiR ѴXZ4\Iʐ*y ie0"`+*dE6^gFw鴭a%!(nfHFd 1̤h5tzO9X\Q&(AlőQp:s̲7AMe}w\~nZEYßx{Xz}dG?y[n\}'Gn\/r-2YY =xf'9u\[؍ǯy{?wi,zw:AgSA%-V }"B2HfD2II6 TxfUQ Bl %QVy>tE i,2D@6d # 8R[[S޽ڬ=3I`%1`e1V4AR{0IF7S ܺ8я-{bZ,#yO-XFc.=H۰ojSXE2ꮩ4GocRi**N gSKZ,;*k^vf#ZRi"" ӞM@C/ xzh4=KMh= mn0B+}E#4P(lkT}} *zZ /[9Ԣhn=Q .lĞ!MťHzdd)QV+sYֺ^RYB0p籙b5LB]颻-dAG0Lu+ +r[f V33.1-X_๑ u(CIZB42[ǘGkfb0L@1F3kI81cB0FOLj%hX$#UE5JGqՑA9pAXibkm.HƸs<{niL$C4fvge5@! l_?= f3g2kK*0^[*ibkD鬙-ݪ44-;|艞Pb0- %-Φ*66nQw&k'Bx,2w,wncT}j}}?{ƋojrU#Hm;|b틹 &dS $<Re'2eh@ rᆱ{ݝ  [$a6Ml)3y u8,`,G&x >-&,K 2NoVb Y=3&erMSr9gʹFTj0 itT{dYX)1(i3X-;, K7u ^e3Ykt*۠ȰRa0R(2TGZB%n l0b439Z LJN[09q~ 84,=̞0c(q$<>P" G dt.sX6IYl4 `.8쎧Ɛ(¤Rmy. -9pTdfM1Khpڈh)9% D{2$"EFf 0x* -­7Xzª.ϼ+/ޜ\Mˊ۾W3JlhXlS ,6g~K7k⛎Zo]~TB4Y2Db$R50Dx)}N^hT*CJY-&Q})L^ja.En )M]P+e F vyo}2E7-"jSO)OaZ P̩DWH/,gGF )i}{(YtRR^+ufRK4*zJJzfmܪ; Gzk-C/3CX(ʔBAPHӜ.Tm:zXUV TJn6Q[6"V#k-Se$ );A}C I,%m=DB[ 36ޕm L( ͑,kh*@"5Bu@@qE0"2)0RV SeyDB 3#*̡mƌ0jVB}k(q̶TulH,ڝEaO3T{! ;XD=6u2i1K~ܫLQ S+u%1\E u`{feY C[콸up\,kpޣ{WKTer{)܌ ^̚ՆLLTEBd[9`=ATjF$az ѭ+ypcRjF7e}۴,W"9GeΩB2 Lm.,#[}g62"l+6WZ]azE9G"eD)Ŷ8 DPwyii%ͷFevͽH݌"-ats}䤤RjFt!{Fh5Eܴ楸Pܑ9p㚇R4pcMg8(2g훜0 |8FG. TyhuwuuܵOw矝XON!Tht6^sf=OɶU'FߞQR04֢Ù2Z"pr4K1>G EG l6wMLIZ!E>7PǓۢV'ɗ%KN/řwՏ|ʷ xK_ҕO7݊sx&T5# 3nLɨDdzQB@#-dfGN]}rtթEYNN w0aq-22 {Nh͂w [&X$GQ0f;ޏ+y%bLbkLEROҜ8 ʌۚq4mIVZGzOyfF@}`NQ`@ HliP] A 31y2TJ)DĐJ)2L%-#j]p(7N(Z ճ^I%h"#`9^BᑩH7yW;7c %"M&ǁqǕuG)DB "iG`cj J{5?7}m<1%YNuMQ RVP&s˜t^[ dBNo9shDRLӰ;7VSYqZ#S$Rs-}hz,\in$FHdFPF@W/2_f&)OTdnҦ%ǃqfBh, /1Ҙcȗ-jVgpKPP T6fըVhQ|/^bY`nՊ'Zo:ET%LK]14R 3.z S{E.%xY*0dXJ=Y:j eeH b6ɮӴ4x~B.LB1s)`Tv_;4V! c QEm-?Nq©p ~ot@3b:@f %àٖ@ =2Md`PϞcn%-# MXS"f{DAY4&$f9B[1*ZeF/HQ[ml2HhTQ fJwD'O<ҝT!€!CxdjTl;Fy۷uR^#{ok^meY LebRʴXb iQ\;}:e[ۜ\}qW N ss(S`)C P'CJt.hNBY9A(|a[Ej\K ōH2T`,/ lL"%̖L/KPލ޻Fl}au*Z޽cԧ\^7n&/OS1@5v n֞uc]kLEɶDlYec( (mҦEh\WMo4( sԊ8%ˎDR$Q${}朽/Il|{7\b.,ِF X0kkV0ͽyG T)!Yg7Gԫ2QT"3e}>H*[dC4n'Ve"3 tu_Ɣ*Q2WdЭzi.N3eTsBׂ=!4y!Շm)G2Ү+6L4{Y//>κo͟y{˿Gkvr`B̤y{'hedl@LY^ R+wWJ_]ݙ’gYșwwsb7r"21׼9r޶][H-zi;kGd>tӃ_?En"3j sJf3f^уˏ٨ҲIdLuFͤD6ڥAduQ;:̙ncݦ63Hd/V($93JPGüyd[d? 3lܦZ<G[5gJj}HzZ/,AA3'6rTTd2AWVtL9Y@enmLI.ۘ]'mBܪTVtU &bނ֚fFzp݇$ie*= }Xھdd6lnS.%dfBd4& jO;Ea}.XԷubﭽ]$c+(YT&hzWLv^.]."*3d@j d;hZrY̥`} c,40OG_ƘLzH̘l۬w IDATیSϧL.l]2jf>h739zѽpëO>9sE7Xϧm-U(I2i˒Dt4aȐ{4GuM FĶIʻQˊU&u5ęY&BZz "RK,a [[ RNTLrqԮ!ɉ*)"ۂ&B< K&vllZ#kbɍ,26䚇K[.4+Hg+{*ע>LN*U&V ,*.ؽθ7/$=PE+lq]~E]̔>QQ]Y 5/Ld*hG{>3f)#*rb"IQE&Lt!O,H(̘%*'UAbqջ/yJ|??|ut%<ŌhGz7`Kwp?l}8LG9^*tf s+Ҷ Doi[2./=Ԙװv\U~46Ob:P^gW^fӑw?W>|~|o}[p .Y*sKi٬KIG[ zՅL(,w% ̶J@ѦN^@TԬ6y=[1f )$3юY2bH@HH]/G|*H#%J--m"m(dcRxoH*Cvzh3*JEeC*vOPdP9DE҈̜-AUjs&w0BʈݧְcV3rh(Qd­U(=(٪TSSEY?YNl,S_lhW';LW .,+9{+,hZ ?t^-{T[&ӌ `*v@C=F*Y>@SToDbI2M{bGH/v1Wj1B]4P \Qˏh>?|q1d뺦n}޿̙yF)i{[5!E73ӆzO>oY[/<1Mmg90wŀ*J>^R^)*6*hҜ,ӖfT%K`AfHB@fu9 vPmѷ=VHB2"9+kquf neY1tCfc2"N.҆bAAH-ŒpJ8S.7ȱضYJ(Ϧ8C+Wj JGxd.PGk4RmKjfhU]~t 1m2۱Je(j>3>(02E `}d^ EDGlR̂ @*_Hs+@> +dLPL/T1Pag_wx?__֫Ql3дWZ7F%Y&}Ԍ "ʨvV){W2T r~|E|$9 28PݴHMŃO<^?\g(fmy>W6Ϗ>|k[W~ӟ{Wyf|ϞύJٜApB9Ou߿ESao<,Zd)C%5i0*MVkn] ݭޥF(FJ~{*KJT t2H(U5j\n*M`O\IZ|r2@I̲(ʠ1Mz H OPfi5UeBEz5wfEU ssB ebbv5j/V`eXFR̂hDKcy-d1l *V@}vyUvEZ=br7\.7PN&ݩD7 @aɚ6t[Ye/6@?@S0eviKN9E뢋jv7ºa[6)ҝmOػ)V! YgDR%X [-*wËai;o(u. 2!bjEHCf=CJAS[$/GwÑ#grJJ2HaӴXDUo%J ,Y[2:hT8z1A5꣐zeC~H~"hS~#)X= !f ~:'-DVa>V)W3IU" vg*PzHCTY#s%\Cؓ,eAMK_j (mQ}+wrϼ_~xT!Q3#n9UR?9}9Kj/{ƒAU7"(˪x%LdQ]Js}'w<50sΫY')F߽j۝;>N\> o^X7ݹw|9<bd,fWu71U76BVk|ڏڑCEL`)3&+g TnΨ2CfgtL&;$R *(k]'W Ҿر2q\~Njk?1l|qF>K}Cd2$ kN].Z"k*Gw QP"=? 2 k Vf2PnH'jﷁ/,K98>76ɍ!kB%Y%̞l7mI*$G$u>+Tɠvw3(Ln1[hVCTu Tۈ! w鲑Q@։(  \VtL#/am!'D0HS \@ʲ!֔ڎ\+Y2IBi2E;1Rrs"\oųiEr 34[݇Q7F%7[d;ز6ww49|yt[Ұƺ-ΒkUM(3[t3hF%Ͳ1![d;'*>ܑ5ld n/ b[-bq @f5[70o._G7z)~f=_7dȪ]GV[ 6^;+>W~o|ӟϯֹY}dw{?N7|xgקu<>W?|7}<׌lt4ki3~{o>O|QU)?ǟH0_DjbdvW%i湡{?{Qc("J Ӵa$)9mZ$ަ'kA[m+|zx ˨![|3 _iw ffŪ~\#Ӭ Qn: sK :p5Wl_?~e.Q=nAPd>KVk}pqy<ͬ-n-/F3KwXtCuŝ6O|^أ[[ ؚ{JՃ(DCJrNlۧJ%5[mv#Eoλ=~T*'5bUQhE?y~we& e,Xf(S2 rEN2urԦacaj5`@¥M7'?x|<9Fr9=SW7QZ݇C^Y3s"C 2pl1w;{Gw>|W?˃q pp[s9Sʀh-P)u]IJ23~HJYjS SVZn;ڧOf HA d454EʬL3Bs!OF徐l].XY]aKmsynqDvY- P7a/9#ѢYJ!d]pZ3}(ʳssj"86*U47N`^\٪{D#(7wAjl({eKm-jUF'ZJ3YU~sT~B21 kD%E">N]) Ҳܷ d29,klgFjlf{ [غ6}nqf)+寎=ڗ>c⭏< *5+fìb'9XAhbI&w"gZ;+*sۺ,KlQy3YQh 31G@\_~Owy' ^\Ų_|Yo֛^*TLwe<?'qyOǣG_>_]oxO|}W&۶Xr+ h`q7q8{>?;]od[k / ȳr:HvfGʣʴ[cWf-5ʜ.k@Ws9yax ]ӆ bDdR'ruGWpi!8xC4"Qb󴗶>cf1g$xk_\iB5@2h 0kX~~?LUXJ[BVbGTgCoRqUf(3%"HcVT z1)+h-mt`4huv[FVY5mNdN'fHJZ>m枆DDْYemP=9M"!ş|iԡn6ڼQ]ųvw~w1 HmnCURERɉJ9,3FfFVfNs3.XDY)V[VcoE&on7K_O?xKk^\3 nXsk4/ ) P9o*f_3973[ԅB fyt7cF\\ht79lZ|-z~{TAi23OcΨpyoYM4n3NsUq= rՍҌiEZŚ2Bndk;MPd{6fm6 Q[*DE@9eyĄD a-A&9P>ϼZx\:9.- K63<Ke$-4/ 6̘(^&k4pjg`.(OLT0iVP-+iۺj)⬩ ASRP aMR4R?IGAX``M4Ys7Ś:9= Z2&i^;iU 0ׁҪJζY82e-9nn^UE-̠a/Ɲ+; oxol؅\ș5D*rv`tV"Se>g[MmfwUΌQ3匩25I,20gEIU"mUH#TZD; %L>=|{n9?プ? 9]|q**/=>y GOç;!~{[ߙ+9o^<ٯ_s{_s/-[_y2'2XE9=Rl%[}3֩=3`my:gVavF(>j2sr]Vl=˞4H} cn.+Ѝ9C$ZIG]AzeLFشgi-l@eVǡiv(bN0FB1d8j  2AOt>esw- fZ{t,iZjv&q盫rY{u- \Nv%'HK4gBa3m*Dd@ Zgf4T3CfUfFkF07=ᒛvQ ;;17(\홵8ڂ{n(U6] Q<*(UcQZHMQ0R@e{pd AP&WfLhb~Qvf;os"lܬmF EiXJB#KZVʕݘ[qŒuŜ!rf3/LV˝ W< <;?rC:b!!cE6rg Hf(UTbUl&H樈KQJ4Y!A;Q%$> /Ǥesι(9y=(D@l3H:$+ U66HM֎+&wEa #BN$R(Ņ8?V3*2u@kq.z:8 0Dʩ^h1{Ĝkht3ރpszSHLVWJT5콳P VevV(#ZpU͕ 9bF6׋ád혠m] 3Pٺmt̤d`Lt$w_ǟKxɷt^?L?fMTerLdFX;j#mH%F6% hIBM晙X;HҶ-XYnBȉ=Z2ȵ׉#~7ڏ-\36庮ztFe*c./q9ʳqw;G>{3ytضާ^y(>8D Ooy2S=}H*.2̤,~HUbSv?*EgPb?:.`DR, P1} $ccB0 I@ˍ!Wc2H+3t2S ?}nMy/r)2/**rV.G^NjuEY"N72w.z>q~5g B-'讽ܱfզ=X=@%V1Kg[mۜ[0=1//~6DF䌢eQa5skcDo(3aK_,3԰]nu{|)\+N|QMqOtM[I*e.">~36=8N1\5g6jPPa2h¦` fhsn-6A#o.Rm1(̤_^ZjU׺֧xv!,rp*c&b-yCxR˻Bcy6xo#.)-O "gY1iQiM`S#`vbQH IDATw'DSA" ݌nBUȰMi|9)qhڢm6WeBO:ė@NeَYdaw ŗ"*0e\h崞`L?>zZwPw#xjD۞E/*ok%\c|5"g*oV3E[5ض.we2MB2g6*pTԈPiѝe<>~l ?.v %1P]y8>bMcQqu^+ eVlPRZT*Dň;Pq1lYfD'ƶUne.W 2},!LEK‪,gC"f#@U\ߜ lj|ˏ~t?x8 $ Dva{n@  Wm&?\B5BF&Pb=,CC*k=͊UɘYMXKL@eMmy;o=~q=Ź2W'kM?̜;xǃ7h<ßW/|~Ͽ|G7V?zӟ2~{:sTc﷜6ܒBl[FHTbb2VYHzPPN~\;@hݦD62mdv(\[A:Y[/sc91S,*1[8l?uQYivevhsnU3bo)~J 2jkKH?9^<\QZ.-Զm|Y) |6 FJ=-Ep'·?Cq\g͘4h7Q>9ٯnIϼy<|4Un}~oo;?;d3V*4"LvHH|T*a*}kӶsR,YuffeFl-ÁLJH,f]c Sʌ|ʼDSH9Eݬܶ0Q>H i <5sܶ/Q͘aDZ>Ȩ<ϰ.eͼڲ0ƭ88_ͻwǃm.^Xsf]Ea˳˥'FNV\*ᐕ\!D/Nl)c!9>txp𫛋 ]p1>|]T`r]х}@+BRǻ&u얕><a2pda;n'*&uFQC.&y)S!n" S, yEҒ{|}dYbtVZe8*PUJG6k.(*=3Y+m87C40;l!*Pۙ8t.trz?SyZ@ ˱Eķ^{ǣ=_7^~'"_/_~6~._!R~?~Oэ/} fc4fQܓgOh\fN(@e2:$܊˸~q?x[_/~g3gw{O)}G^_҃Īd}UIzzh˪?\{pc[9CeP"'HI([ ~ְ,^v~z~V˲lKPQ "T[u9{5|ֹ}wk{7sμW1QgXPliN sO#ƘZE]{͛RNy6$H Ξc)Ν}Kw`kӓ,`1K=0G?:~|ʕ7|3)JCn1őEK4x98082Bsuj%3G:yDon.aBlƎ{ݓםeffJJ )KT>}w@w;n,`zPu392:ttNu߽7="̉VR JSZGwff[Uy;4 y;ڭ+W]깠@By0,{wϫu6?kދi@0n!f38|Xg+"򕋖-_3sb3d'F$X('w`S/X8tٕg UrRDsRvY@s׳w;>>Srƙ.ݺVbo GHط=fgƆK.Z6/EP%6f] n`yx uEO>'K,} /n,F xI 2)#i( @v*C{5tCc)]b%6|EfnU۳Lo.䢵 !E5QaG:‘#}Wt".~ClnC D EQ8S1Kc:,`E"˓o,9HC9\թB5;U$IM 21V7Jt'Os$k>C%LE/Uq&ɣ0If9HidnuJ" K4D b&t'n`fKj5ȘN}9Qq +gbf暠CȓR1x2TݔP0FOܙȬãLL` Dqˮ]# j& b@Y 9Z}$֌jgԵG7E" ֌rHF$h ddPsPl)W:AW%4%ɝHpS蹩xٚV$:oRy[ |=zeH@&Dj&t}>ŋW?zbPgbݎэf)j1vpLPѹއ޳bt;zȑ7ƷȓO:ٶ?]_q+633'0x 6HPM246f__;Cݼ;?~LvD8Ee%ˉ?VNv8ؼC߽㧏kϺcCAG'~s+~Eݳ8|=;?On֝×+֭"sBhokǿOхKY v<+[~oe[k+֯ [_zox-C$aM Wo_ WjzZ?=;5w)3׾'>|gϋϿ?K# ƀUoX뮿)ժ)UCJ1QȜSwq.&:vb_ ^kɶ1vLEM{}?w.+?4q_\+W=Gצ&O13s27߱zujzΗ~}u_7 PQd˼vo|\uל}=7e^__QHOVU:V̧/9gӢ5:2A(7xJ <)().9T)J` 1"{֝!58 pEC-)3τKI Y8G l$mDHLr͟ 欩H֋9+ۼڧb xd#u IJk@@hb4p )UPfd/VQ5QXln%gq2iJ ɖ!#uf';3gizNF276˂9N&\94Cɡ̘9d2#vxK9zaN:kalp B̚**XUs9硉$xtb2B kU-pb|{̌g'~!oWm^xռX٫;Nz}#-1!ªV6x;v6jvSu8$0(䂜 t`eM9qxjS:1W(C-jڬV$HR iۑ6I~xrbrkV,?z{_??ۉS{b +/⼳7xa/>p|_MvONOMkb㯍8fٚ,j u>>qW#opdĹw*ս@@K#jd&e5"ljfI)wSRM]F+w?hlyc&e#V&EVnXz"#O>;7 Z8ô~gSn7oh4zpێ٤&( p˚vIoS\΋)BU%7?{c/:kRw䁃NmT[q]?}>78zFF{xNgۖ/~ Ow֑H 4^0{j^5м_t83 /ZF`MQ/{acY N<RJoa2rkDe8fW\yH0w?_yi%˗̦ ZU~z[J1p-[B-~џ+o 0D9Y|SAD8yF3~9 [^fQ/f㏾szml.l}Xw{vwg^~7O=#O?Kf2h㏼3./-cb{g߱u{ WeIc ~s IDATm?K_o#kNv:439}a+.@Ɖ(\u N8rb%% #6O9QRm OV48 ~a͊Wc+y ;YקG=ga\\u%WnȱǷ[lܳgܨhܻMK6o^Bb}m7v]uKg3\D[Z֭ks;;SϼL|eL7$X'OifjىUN7kRBl[c!j(XIJ¹!(T) 󚍈Ŭvw33&$V799)d5InD OfVH.E`$0PH(8w ,˝Pfk p6MDYr0R 9dx|*FBn<{BW5!]T=Wr99\`U\U}+=pc۸0hRBJQ!Dyh%\'ހW~RDdf@E#ymr.LBQHN!nq"Vٚ/~@]iÐt;6w报:㢵g_K/> 7 G $ljTb[%g{016=~t:SEz{-GR2K)uޕcun0֦ Д̷BǼ拗^Px"Lm[3/n#Z{o{ @Q[~6WU&C_w@n94d:-[/<3NW1k˹Vju\Uwy} kՍw},_{~+_i iUwKO>lnZnS&ţuLJnwvFNl=g~?Knefh( >vA;sSGp;aph^ew|Gxn_}/>\A˖/=51RB p)e.VkYDeYLNzn##WRg7>rb@}m>g)g[9)XWhG?~U(A GN=1grufeQd]k rVQ `dKCMQYj@Q * =*ԑ8QAFn᳁ x`S'v5rUwRX+I b"VH))R\(DKA,\K B̹ T݂+2P0 IL ;#FLZ==F5TŬpFN39 Hk@D|rlzzV  eѐ{ 7[r??ͿAy JI5LU(`560=Y z|7%f-P4P kZBر\xΚV!&e[M=?o w:NTHtnh5n\%%DL[<2uKJ Xttd*Ld $9b&S (8`)j#JRPyedHk+\`mɡ^ڻuJɓ+RâY h2E\<)AV0LɌ\ݻd%L̒imAxV˕*SBff SSCGSUSάPwJ5T p޻D!/ۦ:bODnp3)1}8=g1,DFSs?{ߠl`u 0zhL=31p\ЗV mF=wp%zf`d`J)pݡɘ2v #UgNN)I@ݒkjԩ|HV/SC pi솕X<{9k|logi~`S .ba$S"0JD cKpi45X‘ރfoȔzjdyUk@OLI $˻r!apMr+0;ks,gMKV_0^f!|*eAĎӡ̊e@+IDR21N{v5ko;14)իהeR3Fo4sb@:w磌)  p rrg] {w,8ĉ|bd7EK-0~b&I}cKV ZN dN .^?'^o[܏ [oJD{o*vv,*U2c7vk\s- 5"R526 yh`d~/cwtiB }%=nZmjM&qUFڭq S^qb&qw[X6B!BŋSTB64Xf2t'NdN+:5ĬĜ4RSTBD8Db/S+ g"@jfdd)%M;RV&vf)X""HXbZR5B'\ Zu +=y͆%BIe穈2MtWzJ assL6ׅ}XnQFkKb@ApO-dOy ɘ&9u=cE.:8 iaȽs#Lč S 5 D$F,dĐjYv,3'hNJ7 Yfr#NQ9pE MU)BUrrxdNU'5 s7-Ng$2]l  ˄2jT>wAg"S))R7ѣ{CѢ7(jA>KȷѝMilfNL۾cՁf`*{F;ev}-^ጬ8j:$Hg?)eV"X,hs @bscQv!\]$ղ FS/~ nQ,k.1Y6ԹQ?pG_; K.rjjvfb3QWS$e,^yLڻ^ւym9N5ΣpkQJ.DB>=3۱fv絚UtrddPaU*D2QD@{bOāNDnjD"9%51`EN\$rbmE$ a!K E^'C@b!zN< =; \R4&7rDb)@=2@kͣm*,Id(P0\-۳JEYy3KL u&d!bu(AhYyu(9ewfbZ8PA`ffęDan˚RBe|COl;Ӊu#D@3J@詃41Rլ{DMLb,T &I safvv%xH% k"«"5:e*K,>[l6ZUX)0qR$"pB-r]-W@FD$l=!-19@NbZ<T5pw;LsW8gQ IDATIU4;T2RX$ F)/DLEr2)`aVplSΗʴ*ܜ v7&먔 @ͳ [cb!S1y/ga1^V¤9%F\Gd{x 1!tC̓-o9~=Ѝ{~Hu VJQf]fNX/+&GK];//^| !DAB{ffm\6\ `gH(L7&,\ ZI[70*L𽝵ۻo㇎2c,B{oq7:umf sR"UvQHK+*ݬR#y4c1S~g"a|sg˘$z ٖ؝ dvQB-m֮roihZ-E "$`/~Po9{7^/^:{׏%3w!Y{SQpե1k4;>h%3K-9s*f1{`rk#Bqkn w ِNJ "P4CNF(21S2gg+TU=3l9#dN$BjNHDM!9f9籌]Φ4J@\ꄬb)Ɋ1LlݝJCZh fZz)R8gR ZrmMlQ=KS "U` "d*T9q0aaF"i$  G!Vs{of<8{< vng W\b*8Q!X7$'%nZ:P n[o5wf׮ٴ:ފSV$+W]vpv{z=oka=;ng]4ӥPoQU5ڼal0enԵ {o:g1ic섴e±O~wE4zljьX7r2>zq D`DzO.DFD gsR3& aLQUjwVscI3 up\9̋}\=#&&;u'мym CҨ\7x2w !fMY3lͣܚ3ԾWN Gu9 rpw2)ZJ-ŚZwM&0; ʈMd$ g9@ę^R :2/q) *eNL3:s JMZ!NNM8!fbs!GRJ$XUȑcgϜNt7n\"f/C" C`A/Ւ;3 , v9ŋh * g^BL6>(1`TN^.i;oܲzGo?Z~ŧFqhv]O1`N™rդLUN9SمcuZzy7j.1l2E6#  8IsgjךB"ER. >Z_/ۿwýP" "!2!pnRkWyOwm.]j&":VE՚Iƭz׵PC8t[-6Su7[]"̐H5չEN;J*wL 򁽎UIQ-N Lf&%] pƽc9%Քݙ1)q& s Q.3r6 ́*! rD(jݥ4"1 ޘb)%I[͔5 hdəP5$Fp'S3S41%sfF-9Fm؝͉S@ɠfpS20 c6C$259Si%Pz1[o3(<ᐹ*JMJly,9r`1،yfbTܡ\J߽јJlV[YU!g&gafP,+J*,,T`q#QAA}f$'X Z:۹WtzTYxL@9inyVk3`۴qu+y앋O=s/<7~ԓx7^zOhhΦLY\\XX_Fji[D㭌C'<6v:-Ƽkh.[}e"ϿvdNK/2w ͳޕLܥ-3 iY`b,\KL,[f2Uq8|yNfqc* UN=9 Xi4]:7`ŚəӰmnkk!M9qN*s7#-f_{!!ŠHBF)7+Y3}o~ْnW"\[ei+(D-m" LDDf 'vJ9@USq 9 !eōl\*LT7n],VQ(\|鵗^,5"4{_[{+K< I)&/􉌨4И|q 1ήpa+972_vm4j.*@ aa1T㹻޺d:p e׎2knBTf7ǵ$7ߺ\)W;Ϟ+P!x+׆OXf7Np->bYFQCͱW_z`GGJD]m~2ֱ'!@Q4\ZNI1 s,9Lى]Df&1x@˞a a+r?o(;GMcZm|N3C$Pw;O_YXؾuP8OH6d@Bu}*@[ll#0XK3LAj)%D'1- `,H=9e-%c ʼn=[kf@EH&Z,*pt,TC0>*"!LO &*sr!g607f9i1ށT"T 7UIg7h(n.܍ArW@2l,QNb ZQmo^Xy[H`59(gVS;Tb ꮶt9s).{e7+ËT~%\('98P)6YR`#2П1";)]ǯ(dKD9;;$ʎ[6,6gwh'e$vz̴ݚ`'Wq/xBA.(`8(235yöm7l5f6mp٧co4n{ *J h4..,sqWg[1Zstf†.7^>rRg5s ɟ|rxO ꌿ秏^f3~8cʝon`Z3sR6V8 q̘ V0Թq6Q !VtCgŏ(U>vEځnX:gCrd²Tl&"6*dYYeSW7MXYfwljhsV&r²YωY.&FL 6nKW29i!;eŪK.A3-G=hkf[v`{x_GOGDDҳ/o~xN#z &\l>1p`AJn!^5[ʼn/^`53Sc$ڎD_d=b쿢'.ݢG,!PꮝLRV8]tNMwYs׋_xx c"l<`݆-f$ nܺ}Ǯ;3ߩX24 `1֗rz`?{Ns`' e^y$]{fmJ;e\U(ӄ?MxWɫV#AB=hxkfS*k|U.x';wg^<}|<`rw/H0Ĉ'tb LP"f75Re3bcq#70IgtZ?׏`rMXY]a?iVJ ÅO/5YNS|QwkU73GÆAAiaA(7Y)/x `2P!!~ 6ϖ]wmerD\0uK$&uIK)=w^tc@pcZy૝h8˧ټfą:sgΐjdƤiիWvunvxcڸćw+ܳmʵ̋unXf;4ĥ;ƫgO]fK뷮ܲkG.\83;=rʥ-6AtȥT]NNKЪ۸ ݜ N*.spfԢ|1HIoÿcy6'l;olf^;~؅¤̴p_Iv޲}~ȹ}c;ߺ2 9O_ޟ_ܼw^5=WODZ\j"/*jī.)R|ĚMȯKL"4\=}w^x_,_1X̖jX=Le+7(z=o7Id%dn?o7>w~뽷];zSuqGidnb d1:9iʚgΜ?w董ϝ߻ɩ.}`,عsmnu]}>SJ?OvݰsێͩMoykfW2ѥKWPb@]9w:j̮=[֮[]8o >z+ۦ/BA<~7aM3HO쭹Cاwb {ȁg77yM!?CgOشe7w4tdupOl} x' f'Nu憐|bNnk-vۑYj4G ~GU#'?cV5?}3S7o^Qu7yk8عe5mxJ #Cb( P'8{{G=ևW>sχnVUw{~rvfw#&g~ç_Oާ?yÚg.g/G >z羻(1F>{Ҷ~ @hB̝Z-Y:]Kj9HE(æK7+1- #gNLBBu0 ig*3H8c9UD@hUaœ"܉B`ւW 0#*,"MdE6 x= 'XM̡h*II.cKb69rdQs&04mX&JKƇy&i2Yɽ8,%#f,EGj \̍!Hՙ\Ŷ)pdmDݝPtc8*uWU"1SpqՌ2RFe3N IDAT ɭ̪,2CqyCJ=st71iV UUPK"C\ dN LjJR{횚ā[guf֍{ؙy% ͪXYmD8^zUՙ=qjoPgsJ3Ko{ׯ#u얞Rr,ndĄ*zUܐZ.Ͷb/7spkwޱbu5ixe~LЗy7sjqnO?m{7|wxn鞪,%nF`0 f9_cLFn0XK9AA mr@hN&^ko}O蕫{ࢮ-'FĐ@OjNdjcTVȒzWcG?vk<}| K?| y3~s֕HoLT ' F@eUd߾{wް+E`䌍6~?rcrҖ-><ǖ$޽˗.\riʥ Np۶vr;~`M7Ͽ{/</|^S=K`j-WazO;[toj00߹z츍${RB%+1,sj.]{罓?x䍔{?}{?}SXyN/ ?yr0lg>諿ﮝY3 wLK3QӖ;LE5I @Ȟ][ȡSU<^]( Í-6iHdyvnЄ"+5qU\RRs!X:ųLbVSRx`c:xN`%'Uu`e iss$9E Rn)7,pl,ĕyo2ljL 55uR6y+9k bksbU,YN,; e&v"19Z7HGT@ܙe􀳳2[kj@0fFPW եdc8%"""1::sg޽tūYq{w֓u6 HRv0 qIBN&gz6m{onG(yNS(vV>;[;g΍XՓ+0Em PVq}UM+uu Ase5S릷Ф#s>oM[M[ND WN\6ly{o OFEoG֨p1ee+pKo@T&fUmBXqJt(ύ݈([fw3 U0q ).!6ʣ*b G"!l.st,n>u%fY#,NI*4 6=r1am[>UAfݙCFd pG$n^wj8[o]&M} "OLRJm@L)gvW'\"P p(\6&e36K_944f-&RQɉ~Rke˹]beJvfѪ fC3i5wß~W<<>ٛLapLL 18TF:TJew7gdr:v@h~ LH2lU7^ԩۦm߱ R.CbJb&=Ç̬\y7oڶ!DU U`PڪaCo;ysLY9{5jLHBq^/ LAğ}7 ͦm3m[RjF,KNj LLO? Ϝxao_߻)H3)ʈNR6!Y^Khۯ]XlfVtٷ8jZԎfJJz'ms{UB[na;:?9A;_Eb93}g&WܲusF*"H"Y~vաs>WȚ+xM7޺cנmr0̣j+/~O=?hՓi i:ə:  H Ul]Ф֙T7QW3:D΃a0hIY<4sG0ooF)\8%vWH9 A6Qc$lj*T)QP FE|BJ)JiWlٶ ުB"&g\6Wf&L:68qeACvKsPc9Jwg,_w| t Uwo ʠ@Αq7<qWvE! L|#32%c N[|L-=["B"RbHt!3/ʂ fER&cgAc9%P qȥVM]Pe 5r'/Wwmc(HB 8լbPfD=eqX ;ul3j َ4kVvc Wmىu+Ǡ~Z# 0̝֩k6O\?yy45=9rbL#yؤ}޹{jVxmk.͟?|Wv-)i )KQDT-62#&d6%bns27!CU`U8f."I W#@jDٝA )\|fXE/EJ#wcܥ0E(@M0sJy$2y8(1s 1cIb ,Rn۔)IJՙ!D0`1,0HpS#86Z籥Z-T@TR)ܜC$˪_-WZ.,AK3ǜ` ~znyࡏZ9ifm\  a=uS?_^~mns;l #hjQNٳ !X:&bd))2[D\6&JPUB)%%F!!(1U C@:L"vd)gWL AȌ@C&&D\!pDP t']Q{SM R%c9`2T8UH$3HLMfFG)!IH,F亲hS eQPԴ M7T\C4NUOa2y,44˄̜-܍bUŪ&"KZ;+ʕΕQ [wmSw/5h5&O]<}ʁwpjF&nͳ+WϤ?LM,K5e,nzۤ E ( aSR"&g?NV`XJdEf'B'E #)<# ^%V:mSN)nU-Ƣ%d0[c&aF1A7/T@̦hGmjZma L IL-FH5V0pBpM,39\ u= Bf2wR2ge#@ )2XӘC?Oodz\ާnk:% -Zk<Ğ;p'ɲD h<ܾꜽA6}٬[j }S@Le/|i3tWϾ~tu\WWWWW_nϿ/$yT8Cl(bAT^2@f ^BT͹Wb0 ! $-Qbjn37̴0Iި\lwdwf*s̜r~<TA(B Zdax'S%0' wwn^.elޱJwfrvýyC,XQwnߞo_^.l?o{[Uf|S3Y~6neCe1U7:S%3@W'>yts Wtr.{>s1<3uYK.UϹUvD-`X0yXƑ;=-\A.0n8+^)aH&'sZ`$PpOѫ=)j"Rq!օ:̌1@0s0;aBRb3 D)CUR2 ɟed!R t#\X B@@3,eaN}4+#Krh'%K/ܑ!jĜ̢M0TN:ҮB{zbB݈(I簪ɝ={(cޯ$cY̹'aGTZR2YmF &>1jHa368Uʎʛ4g #D2x\6`C̨L Uq]Gm *+EnP1'`ge9]2(#4F$}rҿ`쿾}˗W1ONd~/L_G߾</l~e}7|僱L_~~o_/›Km98?m'?}m?%O#^oyrn^]_fv3ɿJ3I4b#Bgt&+\ PBx{A:K+b%1B->2sOu'Lr4(2X*wW01EA6Sn#i0Ef[M1 !LГd,p͑N9`Βl@9Qx  N۱w=8s%)&qw[Cоf.cj61,mq2#Mo@)3{Ly=kψL7rKPV;QpDIJ[??Ϸoo_ۿW#jqt=jJPzb̍LjHi6}\̙V9i/afI&QR"!T1Dw.a#+(fXW9YVE3' h,1@T9!Hn**)6 h16Lp\SU%!escKOeAXq4Āv?9zzp.wnj57jV8D3ˤ@:vîyRrg1"Kv6 EtDIg|{>/)x5i4O#ݢTOw+5UAQ6%jje1!!;\|P2'MqqSʇ{G;'lb6eQgi/[T2ej˵JEj*1U=;,#V3N~ac4r, s;'lT( LPh'`2yn[rh ++cMʅ],O.B\knB6Vɽd)X`H¼_|n4{ӿ%a2;pFtuld֢F%xa&U2ћ ^f1Fm;h &dy LRi2NVǶf40WZDz:SRReRT? c9H}ƠNf=2t{:T%wт%IyFXKK{|Op|i5Y}_~'yޓf?}y9=/zͥr#Lh(,6:K`W :hXGh3cYY@27*ȏ|-Thda" )h?[tf1fsQ6%#[aJL0ҌFXj'h*FC% ˹ê|Tdٻv{ViʙZ_p 썓ye:Q99 wGBI)ZYy p 8*;Fn^?G?\Wwoom>$G|G?ctda-&5\X̙ܮyc:%[1.IW=&px/"Lh|: j8;P^e$$^gquI&r 〉5bd!3+Io欢X,VBڧbÜ̚#e;Ю ^\1}5mjY̚0Y͜>Xem}5[j3T8:9h,Y1FlPiZe\cyμd [ p*9ϗK֜S9k^5'!Q((2E= Xw3Ja3nUb~pN)FX}"Q Fsfz*}İ>^:*ݒdo&L C#˃ 2*+)M4s9Deߥ2>E5Qa4Qwt(-c]Q.`njqW>tntEA(Ë:UNr֑%kBvbM_8wy29͕(Un־ٜC.g& eS@+QnDВ2Z|BNڝQ}u8RAarG^.r+ڜ܃GFUf̼&9TV,#{y]mCطF&er%5 23hYH{{y IDAT^"Jꜩ1 (w:B,abz?2T3T2{5v Vt 1gM>J0bQef*s岵?(U{u$cPMu\#;TeD8A/DTbSTw)m8ղ,ƍV1(;VԔEyf2Wkk*iN:7ԌXcs֞ڙ ^.9S\`/jBIgeP0GUгvO<%tyzm*"IZB-,ֵ9{#>F[J We"ፂԜ<Yutэms`TLDIXcZkNg?X~K6fT.ZcQ e=G鷠 QfNgs/p |7 I߫zZVue=vsS̜8}\zJBw6$ |ںc*+[AҪS>/6nʡyOeI}mϙW}˥DMp7\v)NaNKG$YaB)dsV҄Fe# fane"f*  9X'{\iNr[V G1`$Il4wpDzz2ѣHL0`q7wmΉJo3e at0D'׋_ݬÇwPU`f VUQ̟$La-mdg 9;@os!|Lfu4 2HNNop:: BO) 8̖ nzKiJh LLDǻ&!"ɞs`hPU % `@6i*=ڲeNЭ * N(uZ4YrSՄDxGtxyDz'djNBVm}ɻgݳo~7_ix_귯_iyKau=|v;QQYĐb&+- YnwY<|~woί[SU_c!|uƸG\?xz€v\O?_˟լGď]>8Ͽ'Oӓ.rtڵ$H'yĦk4fQVe#`1"+ *HEM@LJ զfbRJ.~(#fGĦ0Uq?lѭ0xދ.gm.Je,w[l&g EˍRVofS YGhRD[eIT)UÒyRIy=m P~;=w2l3ȾJ3JUCق3V_e`d1 RlNo[П{ŖetH?u>TL$TKDGtH[TXPvZPƮ*aB"4'v6MҜ`evkfa5~Ny/̌[Ms;o]*v<*ױ,dwփӸuXNqs}ޥymˋma1sܻlwoۄ-Sn;5cW"WjM`Bf7A^hޞZ\J\;vS钺!2y'CF6#$|ؙ5 :X澄 K8lV rRi* !۽d@6R) j79nʙf~ЉAZ+0f^r*SfӪx<.#bNa*l!s"D0K7Q![QyV wچxĬH$@7cܡVWYm4,f 38aFsW%>%Fk$h,:ĸ2S:`avlin;}v+8P}K=,3pxkۯ옯AR@ G_ }c:{"MC`߽݉76Xd8"A`޻?7Ͽ|-9q߭Wz?Ώ[\VW̓GOxu}ڰQ1RDW:C/^e]_>9ۻ2ju3.y;F=Xz3nnu6>}?ˑ~ۗ/;Or=Ώ=w?=vQ*屔p 㛚'Ec+O6~D/[{J`bv] -T 3HwY+ŀ*)Su?.E%HlGj%x 'Phͬ9UB WlJnvp*o^aU RUվYUDhͪe{ќ9[~ hh% ^ŕ*[m=-+ڽK tM4*'3׈s;^>a5u)k^@Arsݜ! dƤz|6#u dόK-E0ay&&@[ i3w{2Z&Y`Ypj,F"7 tЕʀӦ=}̶>hd1;^W0*)@qao@Mړ7O\?|dO<^neuTo^wYS.:}ު%.k#i#RARXSY^rJ0|B6*d1Lu1($Cēa3ͷ"%>nLV3'Cf%Im CGAw 2EsCl@R6tEII_4ت$+rv7RE#2F/p0X"rͣm}=Uӿ̽}H,}8u#|wY^۶[U՞@I.n X8QUm,慎FxV9*2%hrn0)W s`r:ҩ,3 vd]* I>4J wY9bAQЂ]_eǩeρKZ*sW C0FF'Se w^Ot1kg73-oNWn oe\n,#\.va'v_Kc;vG|x:f>^ʗc}p|_+[oNyzp}^A/nwJyh^d﯀8Ry@_U ƧsNEHy0e92s ǁ=N1Ђ*A^{Se\T;欴OUҢ*9Ǧ  a dinPB&OZˢ`28 F:8U;h֫e D9͢fӀ@C=Y^9U WPotT3l1R{)43 mW,ILGydD|u$%Z #k'ͩ$*A  2,dVi0k#L(%={Nq, ge4Y{g6gsSf&f 2*lhW-VhV6KNv[f]\5 g^n?qi\T\ܕ(L]r±bM]snJQiVs*QжsWJ)MuȪt/ɭJf{n=pqdW'XLR( y/gs3cɝ>":^\SQ]O@MMZPFS 3oUFV-8f4U  eͻ*Hnp Ѷ)J[JA ' z2hC(!kf;Qad`fVm{Q>[d>RStGQګG?6{(Bn>[ؼrz$ ~O?l$FG|=1VW}< bZVEj.+p9ih\i⸐f^6_Q$PVn6 o :::p\Ff&e&lspdkP'u /koZ R R߇js匬4i}dQsf~AsHILuW̭2VČa{^}v-xݱ Mؒq:G V3;_7G6TU履3rR֫1Q;m'>!1c!2?B~7>/_O e~}}WǛ߾zvD (٬e^= ?Z<}r\yܴ}VL9_铏r__dzzio5|;vy{~7z=}:<_7[YuųW{WW/q_\?Z~o?|{}WꅾƷ?O~??}o~5Y8Nh-.QfnzpirY X8-brTP%{1 ֞B&=den/ATfޘ, #>=>@uui9#,܈˰xpJE$ գRY#ѭX\ݤ]X"pEpY,!7) p.}-B(ǴaHGHj.W+FiA 37'2w3і%HfAw1'̓$ˮ,̬^gg` 03H$- Y\lJaQ0mGXd^" aєYhQQtApiq0OU]K.ݳWY{9X4É*&VmbBB`H0H^[/EHaQ-B}IA7a'LgrdnabHhj:Ȣ)z*Fa`me)J Q b6kZ:"]27 IDATNNDW69vDI'hcݴf%qK6%/`L)櫕 <4 lh (&LB gND:ZHT LIDs,u22IS:pq0  ʔDFjfV d`HH3*Ff(+ful@D !gӉ0MDV,GHoDƔL$^yڤǢQ"$E1vnE LHbq -E:Mf523vL(ڱ UKQvl n."{X2͓%[ 3@LPFHFFr4oeDV`Dɞ2sl5s)`9&iGUό j}i'z|3dexFP@p[;Y'!nl@RJDѤL֟pa DJ+ J472Ri$7]))X2E ^34H$ň7$b (2+܅4d!P0"hF JnBdj29So]} GW75mwm<9wLy۫PR`Furt+.|;ىчQsC& e g[X]a{xk%aQ,}ڍ$xs9ݟaz˔xa5/q$0 17-lPCt\A4L|co'w'uoxO}va"k8S62>O,}oI{#P E $/\z23[o];BkP&1 [ "w/WD-%q嵷~h?ogUԦʶ+pvElk?\ mմ^WnL]) cm Q[Q(|S'^qMgo#s>@@F:Njϼ{uhm.:ݏ|=]zaqEk29XCOb`_^.?.Rn IJr LmƗ~ [{9O](IT ( feݨl4`V43{A Bd9iWPG2GPh ]kICB Erf +G6JEd(!b`dBő^S,V"0P!5\B\m,,vH ;t@Pu.r8nu^<9*e7UjP D0HD LCE[2ڨ!dHE$0jՆ&Z#\  DICEˤƨIaL5U2Ԋ$ 2S"&܋#* gRNo{*fPfiD*  ZDdt?2 c H7^ KaP"$ BVZR:xHPnpkBtƄD#@"GgĭM ـ B"Sw}Tc 7hk8X4,+IVE$9=] m6N8Z:#5mI⣗[G7).R b#ҙEUl*y@K:5>Ep8[-K/VN֣9Vޕ~ۦun\,ez0lMPb<@Us●X)]|ZOlD2;.\xyDGotts&9d{*Nۛu;Kn۞O{g#@4 0RD6Fdז-X8k>ٟ_7n˗Y<;'}i-q""<)BO޼;_}ՏCHI"ɔx+W-?{ZԘ/w2|w%1*,|߾|7oGO? *6jt]G{F<_[/ほ?h4IF;?:?b4'2Wϴ}}ۇ<)8YXD( 7 B@ ^y뚨 `/5y4!D5P\6A^{қO"A))c?}8G]ʼ"n=zSTC;aqD,L!E3,E@\XL~y Ͻ~c2(6`f^.7>Ͽ}5 al2tzx:<0EfpGR;Wv55<n}WDTxҭ{e~qk;W^Χ>o'[D e7q% GZ]R,0D4݉ .ȒڥhBR!\Ή$b &$De/$59!]D2B C p]w@!qEuY432%qfF&Ƞpҵ!gឞ%!u22 }J2pH*;!aQfO<81 -D.P*F1")a(EpD8Upeag۪I,FXC ]:N@HQ33س( ؀gcI,ˑ`"X( cJgʩV3PD4خL.ҘHl-oyՐ5 \#( 4\SSM"2< pcV̲&fyQl)_`3-"%=u#Fӵ9u}հ޲@HA6i# `@1$a)$K"v-u[~of)uv-ĝe{݉ӧi?pbgOth~1wLȌ2"ìWw]>|:{vϦ_V?>/98q+S7}j~wluN~Տ./՝+GG>{"dr7_Yko8a44 f nuэ#?Z-X/_ּws"-nxWo'_YZG67:2ln>i1roK/~_G&E=-mXn|֌8Z7 <];翺=>c(TkNòDtJ H2ݧɞN) IhѐWK& QQ#32FKL0JB6-PJԨVLT@Ғ ғL5L(,,ŢJSv&7Xy89=A%B9#H-uZ K$ucHB#*Ahh׶ra[82B: aaj"%TҭY) IAD%(",iu!dDgʆfg(#cH.ΉHYPXQ\d"|PL-IIh%&8NR*`Dk֠k2%8Ӫp2KƘж# Ob&wq Q AN\L|>qn瞺z}Xrp~ԹC /hjg/2dMI0,hɟwO߼v__*Kc7mϾ߽9sON$6m)go9^ x}r_Xν.= i^{ d6]Scؑ^Z gx3{o7,I-#R@q-w&-Ģ?_g|/}]$L.E(̹kSTGD1F!JTfsG-BJlN3Fc#Sr$'Se oK3lCcƄ 8I£R$f\TL4ICUĚfQ G)&KzI%E49$։@TX-3) 5n!!!C',Zh{S!iNPl-/1LRlc.,=E H=$bjwdEz7Jf.%TcgΤBc*dK@,!žfHuY@D(J 2Aj7s>5#2MZvwՒb&QOMnv3G뗇K/ƫwVu%y `ybӧ;ATq>,Vnn-}\GCXm5rmw{M*~z޳{ϟޠwN޳u{{ trS`sG9 [7m^vxX rԋe%[z˽/JKo]]ޤ?> `w?'W_.=[<Ϭ3'6g7rwe9/@U&9+U:u<{֥݀-3#r^tk׈#[dexp֙ LӍ/Z1-t|)*#@,7P dLo|k/Ju,DDdawf&oV#`iUX%JRP:gP߰(F 5Ӓ8˴LGX7)=54Y^c' x;iފ Yg CZ, 8  4$lTQ.SJKd1T1&"7X7 Te`Kvz\hQ':=2̭)'Gb봾1<tV;/ع|էDn`EDeI9epֱP)&L!CNqp<:O#/pk&^^}{.{sWÃb>a\ I!J4a֮4*?Hc 6pf9١͏VGսC Tֲ(BIavͭ *J]dՊV+bh0}>sLY1ƨ[;jFyNɌ@olaε LrjGO#rm5ׅ{(Jg-62i:rc20 *$@4HHbfk_)p Kj(H&0+$Yy-Il$7yXkUe-Vf)b&]wRE@c["3#hc n9ʒ` 0#3Y h t&o@B@!-a2)B&NL ~/tnJabwGfm#⸝ 7: "X4ђ6vslN(A*I&g ,"BXIࠖCI78k#QӴ7$kj-MTȠVbMֆsuf);gzae9ηtڜV|/?/W]߹vNh9.x_ɤ[nkoFe9U:K։BuuTE9ZŴNnGlmTu~nܸ|9!^&^︹~O}?zN曧c7yjXL6&'fB"-'q}/2ޚ~_k~;pav^&"%EDmlMNp*%2i7_8u~w*7_ 6pE-v:p(gz ?s=x0ѻ\9|]uB7Exino&w­zȠZLYFywc~쇿g0<#҅KR$QxcXя<2(Ƃ (%Cf SaUR-L$40lf:NE8``"bIWnG ڤxM,*Ha^uSRY\Lv "KʣTT}׿ݕV {AZF0Q"gQ0FN, Fe?x{4]Ee'zcwO]D~_?vi7jfNuvf^/yMlN9^ (z`gL^ts莖%vwǽ~םϾʋhG6rXGGG.P!h)Zfo nbAGfc:"PH@$%+H@&eİvIy=FcX2,FUG8Heh2wQ )]kQV!!t0b sD{"U#.-jc}gqa(kS1 < YE 2L L4=8]E'e#&`I02$r@)QI_ IDATnj|6W?_Zu6'E K*E RĄFR1<,hIxY١,IX $ԠNpd2@UL)Li1O(E D2Z#cyᦁ $dP b$, D}POb$ 3s/, mYn(u=$ Zpd Dd0SК.iF KGde"QLo!dNutKՇb5 r]mJM{%@ Kzky Tpq!s.8 N'RT  HZPRw $،=UXTE"3>Fقs8m1`ZO\fҘ)XIN  33% LĸFKfXRG`" JEz"=8#AP-MU $f4PAHY9SP_`e!H'+;*B RX<ՙ#`iJA$L)" rU$r"vEFо, X:]{a!oik ܓTE0dA(?czKo-3;7g 2:ESvf`SvJT!*":i<(upmRZ&NoOZ0.c"?,'|I)upU9r;0M"Ҁg!2,<Ve q13,gNbBLJ HAQN0{"ɮRIC"$6s%e>f*֑Ek' D%5 f& jR;M%PI6li$C !nGZ43(nl I6aF\z) :T1\f1g2 jI-YHX`TϵK!),D,"ƠM9ڊ(D-83yPt$uH\8IXTuoބ̏x-<(<DҒS)HmHم³5uɝ85Dc$<,/YږZE,֮"PHJzgFI I_"91krIB@)9ƐN#E3[% H6 ns  -Y"3x JNj"2@.ND|i*양R@^n[])N,"okK|}oW>+n%h2 \>SE=}ATҫ8.W1lmǤdB!NHVażA6Qr7^,0|1F]ml̸Lf[spP'|v/.rK 'M)Nm.wOv鍙[Z1d 3'a$^τ;waֽ O5zBnrFNtjAkh<{q&{'=^.e >ݾP.;W9quqȤHx+w?pq2 ]rS3mwZx[-^@ rMy'py}Mu]Ϝ/%D̓[e-*{mq}fKL릎B0=,DJ%٩[D8~t}6-`EC m$זTCh 5qbKxR!F  k+4 H(“̍H~tp<&.@vv2L3Kf2=B5j`҈Ē!zܖa" "3MaEHZq5 U֪7ef%Hq^(emi?͔b>&rZ=#"XB<&W _g~׾?Xpsf:jٱR)RHPtQÃzS̺[y+fW`^UpחY1zV7cXK4"BNY52ӃLH")Wa,"x:҅Y"Jš٬jf(DK%QQ"Q-da#ezաc.ĴS`$Edr28$2 ɔRDB5YQhTb/қU"щc%Y(t- WY-*)Y{e-]P U'4Vg Ndpdp4$EYcTB#$ (17  K&7K)̼HYhx5 K,A-2Y?,ֶ:1\ksnW-YUbSlNEL5dڲ(+;y?H  c vCM R[dٲ$$Ů(b5bumNZsasNj[}k5_M;"{iD- %ctZ, aU`6_+#PXr%z<ɽeӜea!O0rtSR+! m`Ձ648$6!'gϮaVϡy& ఻Y9EHfL}KrV)mU  2.2YT`YB&oS2"dw#?~=~aÇv;{|m[|ǯAˮޥ"qxpy<3by8m+EN4mh};m+a\XntҔŕpyLS8oxsm @Wrqǯ^/|z660!N:BQhu"0XO|A9۾/~uG8<񶭻W۷<~yWV_ߟOȼI`o=pxo~O\b{ڎrMWi$|4h0ro^?~oD6OO1P>3/¬$ T[ʖ&/3ҋÏ)I8YO%=`6̫jRW@ʣCmmvVF7X/]LJa9nspV_P>(809깋6@!$^F\>P 'i ,?s_OVN7fsZH !݅XQ+&I D}c4`N"KX IiV'ScR"/Sx;]-LeEug.}|k/yW^|Ï^*^RwwH!dd+P !p_YW㿵U2\xt(sgőAxٝޚ"@rS-iG` (mz,YRxb. V|buuЩzfC1:2`#O6@-cmٕoskʢ%T6d wjQGf*0΁6Pet(趬;cy`6s\IH[E(6ŷWЃ`Ȉu5T3/L8ۧk1ʮu]^+=;* )s dR'e8։U ŤJ|'@̒%,[o =DRGo"NP{T!3*CfSB*{4cg^º" :,T1˲w S[!,d G`)Ȫ1 Gh$E$5 0$4/pwᮅhsaDu?t7sҫ߄Ad,vSDmp4À3ةRz#NbPY c]+<<뇇Wʃ]y{?>yvM?/tf9D$GK\j3vp,y`]zէik=rw._txa{kD\{_ֳZ^;n/ԭZ^-旾ʗv LլɬxL=!ӕi?w#No0O'ikgn;m7+Wi ۷[GvkL%G7Olz4"tis4/?{^f/Ի3 if W9z]ײK0++ϿASEqf٭O}Ye[ƫ{?>ZYBfF$p2Lh+anii /v(-36RFCb@a;"CFr$L5z&nNu{~:b } O|ӟ責ؕ Lܳ߆{{ZK)i({Np@$D73CQ-^2R7Q4`gx7ܟ8Ygg^0M}JA#zx슋ו?_kO>QKbJRƱ\dE0f,obw/{ m U:#У̒ji43U͛Lūhra@E ̰JUH4E-æX ͓ͬ`rm~L`XNd u0de8eY),hnm4{7SqFLV..6UmBzȄ|-*7/9_V+fTOH> Zcm =etxJ=-7,sUeFŝ!$-,k1G3g$ɲU}ͺGǚ^$$FtC2ʡ9s]6s%rer#7˩ (rPGZo1;RjRs,GR{_ Tda,R\7bSZT\#>G^XpZbt=[5,٣8XuUkx2u$2e ]\@nF IHb508!^(˦AT9ġ,nbf2Z 0BeHt=w~_ݽz|?SČ+_>/nܺ/ƭ@ɜ6e:P)=E{狯Ӣ0dn~v7%e7o,(%3tQ&g'gVr|e_YW뻳3O鹂.H4sx@_77|@?xG`)d"GZ"H1,djpd~2 {3/HovIVjI+0" :li(ICq1.7O~?C8to|#x-Vj7XaAFJQ=2XҜYcx39o  C,խxo4NwsIד_~/?_?'^=TXdp% <.g~G~n}=?.؏.TtBg+_Yd@T6$|-ðݴ4]ŭ,\ӚM4+u4~ @pWsj)4VmySKu/Սd:z4,pašn0DeLNkanPT)ӵyv53H3#K5hf 6V)  L&\b}z%ӁPE,#23.h$ATm蚫r]tKDtsD=Ne5@Wuk64 $3gL;`h{ nj*%qOQQk%W@PALRl%LY,CTRi J-c#y鑍#*RL6%!- ]1k=PLH5<5i 5@Z2 *3;zKO=Bdql"[Se z;5-)s0e:Kf_,=P5QzG\p3y' "x!VLw >bP"x=q~éko=xu{7#wPzB{_Nz Դ’ix˴^s]ݐJKfNY{6Anܔ+5t{5s ,:R\Yרc 8<Erϥ.n=;>g 3/Y]0:rtic Z4]4 [R~a&+}I'B]c|qjj͵nw઒Hp\!p7UИr[7'~=l#tqA^` 7̟&oB?ݽu\l( O4](Zw/懝YPc]N~*uV[UKOT+'yr@D0BIbQy}ɞ9O+V|ع3-323w豲LIWSOu'[E{00FPJPl+* Ɂ*+K(pᾯ11GEK=6cdXHFO!Ty8!Nw̜FDw>I q, 3:QADҙ0щs:Ȟ{QӖm<{1;ܫ62e?~ɥkG8瞿y׏]\.mٍ4zv]_٬Lo|MAu==](C8;=AmD*x/>=?^/~U>4#wSo6.z,Qt7_=Gܯ?պJ)=BHIy_}z"֋>Ӈe|/ןꥯ[ħ1>r@,֬Lb5<;>txVCU@6Fd )w{JjEB6WLIJa Yn*ݠP`5=z_k~3a=9ٽ«OՃ'§OȞ0$ -12L%E-[ =DHՠAG WpGFFrS2Y}mLuVH!H_pe!uS=}oʗ:oy)3H)QG_I=Ͽxvo?O>z %bHη:4DF={P" #v:?BגGe-K_#f*oz2߹y2]:(uJW1fZG60dSXYz)u `p{bU[5MܳN[u8tQr/`i,+aqx/olw3Ǚ'W #/ D[PS8cW%NT1 fUztSbУ&6\_~nx8W_hkK7tq0_x"M R *3ώk"=? ?KWoz??}H (#bp::*D%D{tpuCN]xV.ЈL(wSXT6Ѫω u\w%{YsYDSvD3B٥jB=d48B 'qcpssHO0rvoj)+n!S2[[X]23؅x!NS:G}BvS$20쑥fAuȐ!IdPڔi:,~Ձ좥`hx+r2"-4Whd1R0"0z^<3827,)sH`l5h=̬3,ĠVld ,%{ &P@L>쒒28q:.3wҿlj'_x믟mϏߘ棜fZkdvէ+r=k-mYrԣhwRtÇQ) hS,0[-y#np6UuJSѦf0{VNhtNLҸ88Ȣӛo.59K|C?G^|믽KǗ?n\ϋ |_9Kgwpn^#oOv3/߹s֍s{<P<+c?rCWoA}\ov[|w>k3ێ H12|G>gҾ{Y0,Ŷ?. 33-|x ۷< g3M1lLg d>cPQj Boek {NX'03Y2Fk+Q#w_}0M &3,>7ww'-n2АaNBXtks"&4,X pwK"{60&XOUG hj1D0x Ӵ/Չn]~7%=Gb0{'g~o;uuXhPdG. pu};ʇYxg1H$ rkfb2!rqծ8=y3[m4Zu Mo.UKi[UGaQ,<: 0{ZN~]⓫vT2T➴ֱ_V٦$zrs HxWeXmh=[ZIsF»u\S})b==9Ml= lI$>8vVfAXvF)AW ԼadJ*zQ&s)QqȋHX yBfa:R ȎBjY6Ȣ(i#h)QStfsnso`9Ȥa5%FjؤK۾ *&& AF` =jjFyOKѐϷ=BY55 (sS¬*J:"h9أb uvhVYb,CD,>:ts0O !Vfݻ֭L|.TYDtcIndqyp.)hsO,KW/ݝɄb@7P!"LeY c ߣ#Aᵻ=>_~4l ?ԓt 4rU ]ps4,7^99u`:(W0ハ3g\eJI_:0lé쀱A|__3_~vX(d'')ʄQ@Fzд)t5OЇBFX=D@Z]Z/C}-C6Ks(E"qDNU hA=yO)AD/uH EnauRى[O7_]B]CI 4Zn{iG@ H֦ر,N}>u8Bʽ=zo! 43P- 7ѓ@;r(Mљ$v!(JCVOt~=X{Hej h AC2s.;v$2`=4q)[2[]gxU1\ߺ҃W{wwk6U!؊-ST/1e4jD!&dޫE)tjٮ$cR(V5#ٓ愒Xwvvv'ZVnZ7AG}se]Bv9w4QG8u7rLx UU 4zJA>d1EV`{Z|sQ9,n99n;'ȟ4]`Z1n3ˆjf NKGN50?(L6mAhy.73 }+4rh,L/E_Y[Kݾ~۞m1XϖЭLs‹d(Ky}i"G/tܫӍ&#-q%&gZjV2KĪ0D~ ș9HCD)641mRrO|FCq8H3&Zk4M 7t"uL3N@ h=C EF [KI9@&Z UjdgMwza XJ$6YyrV w`vLt:P7iɔ!0 *DhӦH %Ȗ0ٳ;Â5=Ӥ&-:{1sA$DKEIeǖc"A9+Zh^E M^EQ(ڠEP$q6qdWq[dђxOk97I^1yΪK ('X4_K%JP=`J1_s= vr{Ν./ucY)Ӧws;˧/|r_vWCg8$UHkV Lir^::^uLJҷ {ҹi CWnڇ-qWe[y[֮ͯp<~+ \Óo?0pv~ϿTܾbYwm]' 4)*zѸug}t=wY2(8sn|I<5>``k|wjRiCKuWos|xgIFUH1LC eVƼlAEUF ,ՁAqt.zctUsQβ5y '..WoHj6HBzy˯.rq2n_VV2Ll i` *OJ[o0ŗ(4 cjOOzdKV*%G9ݢaJ?g_LcɗߕAZYe9%>c+廉c4L#n׮kKe}]h^qٷnW>'?Oo}+?k_;~S}aв؅ܵ0]Rv^&rLNjXs IDATUJ#SAX+57w70[l/ ?xуO77G8L%ǪTǛ<pB\ЩcۖsɉAcL#w91[ y9i1&%X /4_p/dh}s[WV ڂp:UdMyŒyyp_[#+T!4$F-K)V[-YiVahͭ-wjf5 Q0"jzՈqTq1Ic eUU ml5% F;nJ9 0 U %Rz5l,h ab &~f'u~*>QE86_oڨF$ -Be.J2Иe^sI@o?1 *&` $E%IW7,}kw{0[#7OwN9PK֨}ϭVOYji` )'7mg$Oש[3H7;/8Վ;ncAi2oDX[W?,am1׾79}i-rvr=^ګn7u_O_/'^{vq|ͣw߾~tŻ?>۷adpkҫ/ XsS _yo>KTy틯 7JҜ'lOWQ__]gOpNhdRe/?sL|ߎ3S;8_OiEXYb+4X%:ULU\B \*ќU`6+CN&R<^۲ى-^w/w/?S|CΧ&MC7?Tnih"1f[ 5՜gJfeoWW^}+/}÷~W~޽czjlIzD+GkU$`as{;~მo>t>+ri+17)%`Y)ۈ6gszӼ%Fnl_O}QxNps"|Y,; 6S+=9iS1Z&,P LH|- y](0MmS*,p0efT\?M1u4P لiѳ(@#%|{ݑE@X洵̇yVlOpU`VJj&D2AeV*# %TZ6i-$n YTqV^@RUP:$>‡l~M[>Uu<܌v9*ecdag?r%;;=yD*$ 7`.;6T437w[`<{q]#4mP 6LRrk,d9څ괣?釫3/>ُ7/| ?Y|>yrs?s{DP4ZY=?+`g()-l3/Z 7O/~ @[CXA`y27 %g.nݹxk|e3m)Ie2?wz_WWOϡFsbb>wjK S5^ۧ_և>|O{Gɒ!1}kyy9}@=럿][9?Q\u㭻W?Zk:n1f8 ɎȭњG2cT3}!JC& jZ$2r,D30؍ lkΑ۲8eGvZԖӤD{$dy!65#K%AfdU9 }TtQvfgK5BnB+T#- (Mf#ˍz>?`UUN27>66!W$ZgΡ1sL^Vȕ1>QRsʙh_RYL DdRDa5I9F(٘*%OWO=w'o}ӣi܆gharTECmwxS-/6 JWE\vд\Ra4kup4EȂƆדvqѽK N6޾}o|s'^֏_^q{Чw7㛟y).Kݾ5mlO^حSyzܼo{EJpE%޿TXxs? . W8:4yz'ϼZ%ݺwYytm3Wf* M"T zVfqq>xݷiO}cOW;Tї9+13|^;enۯ%tL+[.ЫDrg{n{< Dȹt)Si&8q?ɉR ςB~ӥN}zB~43iabU5nTuOL}g>rν,UUaN:?#_7o|[(?kNPLʈGtrI֏'呌Hݹwj1L(D4^_׿Ǟ#]}?/‹)4ş4>PN"8){~{ nz]8% r5%w -?om7Ǟ[Tg~ïz_ 4>t Z }/?}і=h;^~[^مaT3Ҳh0w 7c:vk;.K2jH9Z'קS/,WLzTMe:~1ө]nɣcf|ۗ"nYM~зjܠm)!vBcppw7A Z-kt%ij޼m1X(nv$GlLIYrX."܍-¶a9ʣzʢ24"IBT&4`+h܆YHIBx&ݐTLΞuNuXiIJę8pn[/ ئu`4J8uYUnYU`^UbNq0,3W ge+ӰH'p+ 8őü& ,0sHZ%; TX:fQJ u=bD*U Ȫ23,>sΡ=I@rնiU&..pahfC5- RAp$T hrG/s0j`2sʌrfRTJg OWGo:=(ɜ16>uaKQ-o~ȼ4?;Γ|ɲQ$q^ˎ.ˋpmݞݽ/~v?[o;NGOSCee^)!y!!bTlݰݠ!)%Da"zB@(Int!Fe#Xf栲oHf1a[&fJFxeEi辠u`z 3!{M<Ț>8ۼ@s..Qa-5,!BmI22B֝@" HGd 3։α*qV 0pbcr,Xn <ALEh\y[Uu PoHW^p( Ҡ9m프mf-:/-'Ʋ*'zM&J0.}lr9p8_];3Z4Qjk%s85*fElw^Y.+Fێu<~;o|ӣSqTfVhPu%kjb<(!_mdџ&8^Gʼ=}XcK#9IJ3š68Ucۀ*T9dj,eiuE3=e'uszCwk8 *eCK=ĸ}wq\!/O78}J_?t}ގt̫3b͐U+_"_ַyvTnY(4ed'0P9_usx2Q6j4_I2$X5L>F̼2ͼ)UT%fpaTX$zTY&;oN[6̾ݾ9vH4kZAI":ͮJtO0f 4U }cpi3;Dҕz A39 n`Ө̐DXֈhk3#S4]uu@yڈ@íh* Y41Vl#O79JRҬ`Ȅ5|TLGAdmhDqi2Ƭ0iy ( F4jF(<ӍѶfɄ1$2ᾜ/LRf9]UM☧Ó-:V,X'c~2˖PY%[(w\=[9 q'-tLGa'⅍A]2:r\w@tH-!nn4FfA'6mC mtuq *mfX.j/c>;lh 4h(0|bRsF%v,:]0[yD -V>ē ssAkt$6TUUpT<۵)\[%6.JhnLu<<\'ץӺxH]֫덿5Z[>~/ IJ_Qv ҘLe6K< *aRF*af3Ĭ\֝+u*m5A,s0nOͬye Ikwը k *hc$|a$ʑ5D#!@ƔRiίb ʔ!ר"Y01SqUc) JfehR' /'8If& *J 'n04Ul>T\aȁdpLR648; S,5@](<ԉܢy)Ffٵ>DZJ'ͬJ [>gE#9*inU)s?g*Y,?|8\P Bއyf]F?*जY /vt FήܩL<7,K8uoyG!.z<ӃT} Gh h 1p4nPmASih$m Emթ/DgcT۶Zxlêp:v 9}(!GLGU;`mֶDZ1o٭Ya%Nu|:%w;Np7}j4T|ys\ "҂cE3Й=Q`!B K2fJsoVY-J^p7Ֆ)3[8Jb22 X6`Gҍyʂa4ՍȠJ+GxїܝNs[1j5mA37` rn2&*Os(GʬdrJ~ D,Q Y2 Q#<ʠjܾ*ax`9#F:g9n?A(R$,&M/%"T)1yHkuh2u&U dВIDηñNEԤN>II5a,MH[$w7#S"ՅC7 m+UJu^YV>: 롏d ܰ~i9m{K\/ [۵[>="g_'^pK!,xn*S,IIj]b6$ue9S%aFsyJe(72GFsh&JS,_U 1tW8T,bQ:s7 IDAT;hDGTtc1*g3k^ U&}$ɩ1Id"A8'FJF6&8 4L|) 9M.*y4,+LͫOL3cɀYNoAHuNJv&XDVhKtB["I#4F"f34Z?)IH1ka >TQ ]i$PD4W,s|1f!b6J97]4 , 9r8cJ(eF̮'7kXPǏn7כ]Q9Vf^.o_k[k-p'47E03ݱ0kO[X*;]aN9F,",G a[+$AJTvrW{jWclXKNy9X<45!G17AtD@]fmX :Jf5-f~0r1̧THi֢khٷ"ĪQt”+A/@J[Kx8b 14mGʳi7')H&  Kqs:h%x#Fk&XU>S륪IcBqJ͑)g43?rpsANqI?X%:iݯ\,A0IG1uN[$QζO6bTV2f{'hC4Ajl%08Üa~Ut2"gZeFy~ZUrNHy;&$$wV`Jb2H`$U$RIGNcNvv5~SϽxwy~gYdз[zIr: qe{_Go-GYm:]yM\j|K6 2G7Y#Wo?ԗSO0!+(%l]d6`GXlR2Fs3:Ri~]7Xz݋v tLg>F~ϰڽr9O7#3/;gw m^WH٨46H92 >Mlb&ZLQ@zn*<%+)<&ΗR0f>7BM#-6?e,\PBrƘX86W^~YCdł0JIsSE>y#PD#>TU8J` 1]IrF9/$-Vw f3M,PmY/+ϕxq'02Y̔D:mmeDew6:oa4+ʚNHkvuѾ癧_{qʯvZ\?N]yQв -oH@ƺk"Y =΅ 6uhPjWd%ܐͭwLk}sލtbts0--h5Ȧ7$A9ZT\Hjí`i&aǐ7;(dufKW C̴rpY"i PyUZPMdb/̓~]7-K2}ν&Lf&!*P 5\Qj AQTIdh{~li`Q9 $Z/^\G鴿4E rI5&~ ˿4"q\U劒P"LYeJm>q>|~]j B$ ݗ\Ŭ^3oY dz\ׇSzeo}o!Ӟ=|}O߼?hO3*A2oCI n^bvAid,b( Y/J cInʾQ L/ETYZ-P-z))D`(̹T+o~Cj`Th^Y"Ah)3Uv~1`e3*I7:5O?6t'8KN)s_>'yhLV$n5%NCۣ&2sտab" %̜}hLe#Q(!$8 ņa0s}5*B֡ޮbjA7Ew X=b $+ϽJwX?;P(Lf}jnĭ=pssxyx5U S\:4KYKFD)>x~</4o^c%<$|'g@5<†ڵ\Xi)~qnaF-R TNQ`#lR^t_<{9Ni], )>㺮4fLcÇpqpw:Nףj!+ )fX9qhb0\ e{+vF\YIy 6ni;6^9k5-ضrK@?!p +31%TxFZ! o<(69nk1­͇n0u9t3Rȁj~!PɤaZ3['Xٱ֘ku9DoP1 yyg F%\ ٢LpJj `D+P* UgL7tz4/H6[^&bnU#AÜW3wTپ9G\iIN/b̹B03cʖ-dMS}Y|}uĿ^=6>XױY>j>B\s{rüXlQ ^M4t$\k j#<*-񶋄)Zkm{dʬL,r-jR2kGiŬFugV T ;c~a wݪ1#Œ/b~6ǫK/^Xu-尜8Jv$PUh'>vPDFTc*lAepis8}ԜttfM)Z#&82ܨ GQfV.7ƶWÁD.k*rf^K*-c$dRjMFavw1N2~KA$tpH~%߬aT+Rn$ieyg 9@+ST^nR48r:)UU8+[tyc梛PNNЫ[rs *n'%Ŭt"͌lv&-qJ -U$o5䢄MD%tdp UoYt\[\h3tdVf!GE7f@(ئr[_}?ǟ'[^_|q y\ioO㜯8~78^'O_&yFa%LqȬd\yw_a6>_qTig"P/a~oy\rK%2V [pB g?__n'_?I,U wH [4Z;ReU2ZPA U Wm4_*V4bɍX;Z֕pS`4XW춚UT yUWrXTN4 D gr۪m'slZI%y&"B}JafD̚&9\YTE&T17Wy7-cNCiHsB:83BG*۵YTX rZ-*t-ejGڻ^uYӐn({(WY#lʆj\Ҫ'с7X4c|8V8v{wV-i1|yHIɀmi5kzk&2a14ce_1T(0 0Z&upDXT[w1..`ϒyL4s3rL۷~GN\ fNg1+lE\^*`a]יB,F拣F>:<" 8L0Weyq,sD_nZc ~g)v RzicZD9a(N.pTx$ֶJVj^F5fUY21= pj.-U+,2oSB^zN ۼ#FX=i|.#xAghfuUy @YOYr+ ,Fv=8n%U%r)ұa[TֵimU9G( -QPΩGk}lY+`X88fo1.qA *ݣnʒOLeioRn;x}t˯ԏ }g?O[UܕE*%\ʐCL@Vݷj2 reҎԪ\X: XO@U>??|w>}Ͼ|uIKڵu.}twyV;/?=׿X[B (D5 2`T2.sw-"1Gvm?E=q!"+MR r:d^X3NtڽFpKzJljga2̥ؗu9,sFXKtrDLF%gN#X5ԴbCFe*íż ޤc31[gRIZy z-"&vjh.2GWbUv`a1Uї>*/{avt(sUE'r^ST88e2#ƨ 2#D3C^=[6dGJǭB1Psm 6V\ yL5 Z Y 9%-ٶQ(58 b*tV=gj"JrKYQ$62m9ӾK2|x_= ۜƊ67ݟwӳgu›O~#(P9((c8,Fb3ki#爬.UqZ(UJ$)xDba>52q.kR|5ёҸ D]3f[qf$и3Wz,Ka%)r/7vUm'\mXSge ];)M{jsxo]4\2$o`ZZ[S7MH贂TE3 `)&ǹʻ!UXYGmf3L *2w!!tZ Q$Lc`ќ bUVILd&T"Z 3MJX ^n3o#cay/*atN2s!̲GUa^ d+rF%o4#jY̠JЇ27۲KrLTt7I =O9`b#I$iw}e[Eۈ*wHՉ>1"5"~|~7{tK<ݒv!⸖KŶ 9G|{⓼'>[5q|>?yoGkw?-. f d&FYdVc; < ]供%h*QJY7g9-}+'z8(`ܼV m8 bٽ?[_O (+a"$Z!H`4Yf %5'ج$`VKp*X/zRp\,jIIZٷX)a9vޒU=‘ H*Y/2h5j:|L.cedw }SZvs6Nrm]9WMkE16kjlJJd*&`B(‘I w3iR.UM0b4`%Nz睭4 ۘ3/Xq IDATJm݋\3Ld! !3 MBrUfrwT2PE2h`.* Z0Z ҐTUITɾt ҂ѣEK;,^e@51JI-n,CU\U5pb~ڼwXF++wi 1ךxҐ<~yYGNi)ʰ<5 dq}-̵蕨L0L\y|FoLa*IXU]wZ}Nȓfi6QY~0>̹GXa۸>eP%S`Ⱥ6EZ)CZ^VP0ͪXZqR&"ͷm\DelXI c9<)Q5!;5썏.sI +)^ZH|ݕnn(ҊRЦ+e+:8JXWY5Am_fת=CX Uf:VRьՆZyù%D AHUGm{ väL8UU7ffeS89=Fprdo"~d G+3 '+WOo'OF\/\5rf9ta+&tF^}*JņIʀ6[$wVò/_wܿ8/-ƥj5Dz+Ufx_~Yß7?|eFu?z>O?hPe\k@eS{ϧS+~7ۼu'~z㜋Ȭ\(\Rh%{_w~(ݮc)Sa{T;//?Uj蔲aJGٜƜvz4dU* 9@T 8R(4* ;deCYjHҧDF[=pDeIQ:93Ǭ1PXy9IP}`[T$0RX47z4%n $S,LcTV- L}p$+\Ykf '8*V/;UAQ sA},=R FqAD 6J!.KYGp-q)*QL<2m/)H/V5AFp" RnN^uv8V-{bV.#fP1cƒ hRBB#8UEuFPF̣i,T!>ޞؼԼA+Afje.yyUߍaE3y[lȱa/#x}:88FQipqMb]tYiXfY+`u* wpj1}a(ix 3J 2c#MK=YRwZvzq\ewc4OOmVb94i hÞ敾-);x8p2AkM#\1¼^тfjo'[n0&ܽHu?+h)QUi{2ClSǂ-<&þd>'7+mBsS[֐0Vi?)ca rʼMUJTCriYQ 8T@8{ 7*IPd4o 5J4'{κ$&-/NA" mW[/ NO.#TErl[S*k82 ws *AU@__3ǡ })ѓ`wtY1WͧYP\Tn,&K7#GVnVCɵ8*bT!Ǫ1v7 %ɇdg{Z_ nZŋo}w_9Ku8>ׯT\J2t҃6./i " Y0CS7e4-=gܲA*Y+M03IaV^(j_n&6; Uq[/in 8HiO$(kRLB-VӡA {tLBL-ۿi$ dd?kS=T (.(U[!e8rX IYA;Ig}MX`ĠQߎ.3鄰h`m2!ef],@ҋ̪$X%>5HsVA F򮺑nhZ5Iru 4*Y.T(V&(A(7c;?x޹eky̛ԓ.vxfrwgn_,#Z2iFиVnGNwniPLVxz,w :y̕R\%n5owac6wٳi{вQi7ǫœsqTE-34Z#bX`n0 ;0AL *GO轋i3GD(mp `LBq!KjբbX |c/e+ޝ2t Ea#d7u˝2GPB"h91w]sITלQ;eu8C$h18Ĕ0|+ 4%T2 BUE U}t,2)5 xnDG- *c,Yf'mt(ؚWMrf+s8Wzz=NXoYq zy-YǶwr?~ӘWaEdNNʞA}Xh~A7Q,C7W1U* +v|?<#q}W]<&x*%j|Ͼ'p_}1m?̆MC!~v rl{_G_|<{XAْXyfI`7t-3-d5-/AebJU ,RFa3{A%ܻIFߨ&&j;u-ޫ&:0Du"C*bysKts4ƪ+mn &Zo%#q_8TYj2xrsԙ@i[8XGTJy2Y]ߨۿ@mhN`UǼ\NϦLF+ܾm*)SI^)8U&%o%V"Wvd4:b0+$spSI~xoeC=d7moy'~ nWz~qwx==6r um$-䙤 urI9+uu*2fMeǕZODfީV  ` ZdSk$ӃdVhq A jSf9{/=x\v=א7+✽%be}?W"+v ǰ9Y5*Xy&jd,Ӟ462vj%c'kAn\U16Y J xYOX*6} A1+d+6G.W0r=6C͚(VD|uh夬}T0<hOif>~ uV:M3wh5+d %; ۲]L7qɬ˔=29 vQ~hnZ)Vt*ʚT)؄ЦHJ!fF߳ pY2oYBϥ= 6:# \Rêë`(\ XhF':ɪrZfJN.6sL>ͭv †G^}CRV4, *ݼF6XT($8[ẵs~ioy<5N#{8m?޿6>ecoG K%фZVW(6:J).wO'7?}J2?JYDow^IcXVڕdn] ?VD6O݌>ĄњHU$hWl{%?uVF'DfbF!--+< `SH&\DSGA2{f"IqU2=W-Ǻr+"Vfp4 K]s%3,wiL% ww:]K*S Ԉx~wt0n,l;T}Wo\*4TO6xn7p~qo>eEcˀcʲL JCn7g_RooZvL헕=>Yjq[eO8OO>:fSVr1~K * љN396Q6"pB Ar\:XL`J2\ͩ\ty ;#,*+gL~>V*ו\9I5{z6hU 9EʼnZ C%20wA3鴙b3wUX3>{X*юł)rjfZ$́RtmIsyƞǛ}}}<\1]žXJ4:|Z׮JWHwui ?8RG.Yȅzly ㋧w>tQ+fc;+B\%YҸ;,] ШJgNT h9Z wilǂ+\JL0eF̽r-*yX(ʁ0Sbu1 ; %Se8PIuH+;YtBܭFZۉ!gy*Z\/%+C upIhEZ2@dDT]QI{5h̀4zdDP+cM~y\NO_E@W X{ Uʶ\js8%EkI؄2˪9nXcU UQ}_pN*uyCu4Xf|h@/^WLHl{=]RI÷zOI(-de-Vh{*X<=}ѷ_Imǒ}e.Ӷ/_}u|r;?볗対|P%pAShhl'Dq[,-f<6z,{e9n9]Kݗ>΃ۊ}Xx8x,ay{yv+Noޮ_Z~~o7^Zr+<"|5xvnn^FS7i컜RZ*@Y5JЀc͈31-kVkNͨ(hض7Υe IDATiwy2M?R41gQʓ4x$uX X3e>ʐKMk<^X mbI8kKUcZ0Fb9)qs88!FM + OY9ⴖ4Ngh Mr;Ypq9D$T|o5yB(xUÐtG^̬Ǒ\1kNE lGy1 V*o:l0ae*Qes&xkZP +jfekra*5͒iea <:JVY ̊2ˈjpY\\CS4jA[)jbN'<1uT]ގ "Jµp].%vX\%UT&{?rWxwy|nm(Ǜq|fKi/ድB|׏O|ş|}Uzj2WSMաt[ϔI\8q7s(B<`nM|ş}!||lؾ~w9g>}o~/sͺ̠+iB~-`r 2YPwI.֩XZkY@(aY0*¸Q=13Ae\Fk/$ (vЉ!^ {̌f[f1ӧ:<> iD9+oxb̰J߲grsG#70ƶuEK s-04=\Gɣ -U5o5UNP+)C ̙)X8bjb nKA6"Zob.e N$8ڝqkSV^i>̎FQEE RIӬPS}uHH%BEpTt~径 l\uQZs[RJAVHZax: ;mӞ~wi̹'9; qcC>޿6||}ٿNɜ2,u \L(\*.cUe8hrVhD9GQGDLR(e!r]ΧDݓN_&["h>Z6UiksAa[&v{gU]5,yHX,8 JNjV.f\=XMgTq9fV Uh*Q[lK&udY䦘k"籬,*g9C,D|8@FUy,n6Ȥp9 ^(qB1Wz`M >8Bу,781Xs{S wP=]=ses#,ETˢeR[%Rn۳"T%ut/sPWHTŠ4J`L3\:`"9܅N+=5+$2:W9'Xv e$ȴyR5?ȺTi+?v3fTu5cw??gͯQ>fvo_}Ͼ?/x<۷?/?·o~źX SM ?,:3>ߨmZA7 efù<˻w~v&Ԉ{ͳ'7 =.?<\[7?gK Gb\xJD\o^6ˏ>}}?w՟[?yN[tw7 D+4 ,K[ pzsФj"YG"I!%U_@9} B^DKsD\KjI ȦBmwyU RZhSkhKqtfTAl3r#QnkX{WӀ,Vr }"kqrJM[Qd!kQ4(sͲQZ'm&+8q6KئT8Si\`$mVEJ!J9LH\E*TX@/s9cUIZ…"`p݄,:۠måPuk A Whh(O?$2H5Upkfe"+mdCpA?^Ѧ|?wyv0Pfs\tzl5==>yyPěsSeFQsymV3Z6ZwF*e1Eian3 󨵎7ZP>{[ -I<\a%b3 ۪|{$;JJl7a[* uܨ}fᲲ#Yc;׾6Sͻ*:ʵ\.%:<]X{!9kιַy8rqZs m6dMU"x,Zoֽ=*nӰ&HNˌͪB4)X<"傡N~3b΂ B-ͬ4h1bxc^h+eɣbf:Gi=2S nRd"*A+_#\L[$'m` S23KZj;qUu#ݘYpjH*U0H[KpKFkf&`oA (t7VѪ1vui qe}H@JD[Z"εzo;s -~m,PRkxys?wp~uv;|qᛯ_}ɸ=aUO?|_>9^Q?>[m!֒,k JQ{|xg~GO'~ū7.;%Q퐗jj͋odP̸Å>Cf_կެOybqKi?nOO|ig٧7o嗿{vv\+D[[U]UUkztZ9NpUyoR2(4[vw!3RH(35YHZvr^<0`h_͙-p [TwjjNÕrW2o"B& 8JtZ:q G~-6#40`0Qb+i*6R2K&YInZh-[#ڌ߉, D&PyHsUispgb9 %+ַ /X (OC4}Ub3lu-,cQ טwӻ:dtDQ?9cw2 ''\j،aeo~\Jr0fqm#-y yd2y78f39|]q{;#^9c!"檬,,?qw>} yy{yJJ7@iP&*ؖѯ]'ߣѤZ!$| +Y,/\Xqn1˞|zxo=OdxrջK`J_ߔ:q~rnϟӻ w?|mo}m}ի=rΒɌ!&%?( 4KI;"PLs֚6lX eJIveҮԃ+)%obS(q3@J7@oќt2 XMas$ePVEG5 ƫ{sNy;oCdnBhfs&h+9 ClPl "Xj9]\Ӊl:*U=߅f%9Ql5lnbt*; T@ٜ)e50|]5=/ql|EE…f90P'/X ._ɞ]e)EVqITiXTvcZr0WIGM%e*"tٞ>'1Nks*qsͅi+\8yn]|G~.c_8S(i[ᐗ[ze=^VD'k_Of;ߞNw.'ȍܜ}>Uj+"Bmctl'#E`|?|qECuUlDAP777(H5V1V20X4afF v6L'a Xl&J5ji^͸q8↨聊)/+yH# ,Gt:2KCS(6vnO󶍍gIXKoIˌ}\y̥sVj5uݴ6(PٶOtqZ?&m5 @U9Aϵ7* f.UMm6؆@Uu̫ҡkiݠD†XJ#aʜWW- pu7fD8J3Nʞ H(jPB9pxr_wFu Z ϣ<\nkB ޻&fT,UqXbG< %}/o'_~}}s eÖc5\?w_|vq|7/=䎛%˴ͤF0$D]nVYJ[llF?P1̶K p0ʼnplӛÓ|\Ώ/?Or}~C7t}ǧFwox?_|7ngRFђ0Ȫ Jܢ>9]0i5p IE8\Rc۲l3xH͜*3 UD!ӫ'Hyeڶ6tݝըf!g'{OUY],*OLIϬc*i` >t-Uvq2db\%5%' "VHJnnGX$W5l "Ž|1 TKݨ+4Geð)(м 4Mۃ21Ve:CE2/R*L5y2JihTPg>iZJG\}$-[fsåk.mtq^AQkiAt2|u;8nv2Dы:Ǻw#h´.c>@gGY+M}Çυv2wՁJ8m޺r,vs̃;dK<J'Vq\yt] r%Ymol8#c:xڌIe P*C1NgfʂUrR1PeH2Asj!g=t).ڙ%dt lM$M1jnὄZ-VLKPtqB6݆`B9|fFXv:4ԇa` ( {HAyDwXZB`6 ]cH2E)M;m 3 [1Ւ^+J֜QZiJFlnx@(2JE|~?zw֫_U.sojv;} G|叟?Gɳg׷8n:Y嫟}M]#vɂ`S+"| XUQt5߾UBI u+֟*+cTIkrºOc!4UQb&J%SZK9]'\V.H>4xE CRNV=(G4/UA]^6P `AFs3\#-⠦YdVf[QU˭B$BA4reJeBZlzu9AV KI#+KåȾ8 M*4 [&k{h&ӘUX0 .a&ѝ]JnW@,V5zj&^ÓT](wf@[YY@0BZ?F Cr=)~dbܜk-n&Σ&?Gr<9~w~<\ev# V|oe.*voǎS\pr%X1H{tu'7g_Qrk,Dzsj+a SF͈?g7_|q ܏ t&TUؖ/Dn'ʈ f:dLj:Xa(rmF5 `aNV%.{md7DVCeEqSl嶶YD!BꧧIFw w}~{z2twXpYl* )deN*ݲl9YFvVeBh;},FҪuU6Dkwr)եN,(mOhP-Lr9H ȬTy}2.yˀ0/_o  0u._aDjU@tu}hx<;?˿{)=dml<>_>/?y1?חo=~r]!g#^u%csc kߺ?_?߼zj= X TPnUɓ@vAݿ}?ٿ9a~=,>G J?N_ߟ~xzd[Nͳ'77_ܧ+fZzzsWCeipVi#Pջ' 6ץПs̀ 4\#.q+ 3jpp%]Z<hCc00\iἎJRiYժaHGvӹ`9 t vuM l-R,sh<͖mq7gD}Nf{VPH)REmC[nྟpǖ;e˦L!U'3{FVQ?Y5N{9f^Vm \f^-/`m헏der2GH4¼8MX !,s;wsYfts3!aΒ9?L ""ld3K &EySnHQʪ>oup.3f(IbRjnNUvYdlplNc#ɎBfSp[A3 BJ[G"Qv3H sPB$K-BP*Va>Z}ʣrJɇ՚0êmyq:j=*-R&Mݟ4N{6 1pww>_G<<DZŵV.KK2ia9sVKh# |㗟_-_^>pܝ_"/T*&d/~̟r8s'<_}Lf0nR| *-CB@;KDU5u"!m'(ul^m:b.j·.D`hM֜LjQ?;aß~omi㵿JLhuU r-/ ʥ@rc[Aȭ:m6D0:7sd;+ P*U}p7ƨ2fa}6> 8bDCBJD ͪCM&AaTiMU9WXYQ V4V|D)U`YǨޠ|++zXKf^j-Q', f4T61N? {Ij~@*j}` NiU%B@07~~thY%lZ[ҐxK^ʦ7Bն'Ai٪IB ȴM׺(*-P-X@r0XJUЍe*77\EARQr}I% \%1oE5tyu^UҰ0{fsk]ZŅ,Ze:168U҄&ͶV%ښ#6fcApc[Ǽd*ҭ+Uv(ї^ #\ʒKvc2sdJnYC]IdSUj7*vh?._Wc;ѯ`~Lbcz!۶&Ez_?\'?|a~w℗gґ:*^ 8LʆXkE8 ݎf~@RXmeUrrIʓeƜxRoϹ^ϧzp;V<>>{f~?bo~5A5n wYEQ6tCKP/8:VkXkIȬ&]T1ffn_7n[%33V&f2UA*݂sI&(#M``PMu+wM;I97f-&lfmaRUK RQI ""eF)KA4 wji. ԭpՏHR9 Q"~;lzxq*EUohrT[GV_d0yU)!@Μ',1@glUǑt (6G1Cݙo^VVy4к D^2X$rtKu (T2l᫼quB<i.o/OOw4NcyBc^x|8'/㐲<\cIdg3k kVBOF:KHm۞k.کҚvDZϕ8k70VJƪܯS=8]=>}-;s^|zzN*9p/L76絯+T;AJUTP#R# 2 )_Ғ fVtڬ&nf樰B6;~爬a"ggzOt%?Quq؏ IC%^ g@2oL2BUn4a&iJ .*7`ؿUΏu_~bEpɵR|*|8]y=|qu?;x>7o/yTW3!_HY؎}[`D:5IaO%_;ZxYفwqX^|Ow|y~/\]X&X JqYO~|!w~_=>=A:($ {LNs xP!bXrGp3;kmy32PḌRD<ΛtDS"yRr Ӄ`5"ZFtÆ *)oX@&!aMr>|rL .Mi^Fذ* ú4p>%6l\-^HA*g=Q@SͫgvJFnn**n SRnj W4#j{zt޾}wy!UP9SΟUKN=Z""} j\i"iMоV܍ 3¨<o/Fu9+/sa%⒃^O!.@%.|rټ^aߺ?}vK.Oj_N/yߏDTmwY_BWZn3 +$ySZT-eThIncj *ʬ}i Ta%@S~\gLDo>Fh^. >Zu콸LzB|q^?ۿy77'qN43 Q+/ar_O>~_z۾||:m??|8|`meoĂYMJ\bP7GQ:WK(3x~r3hWaÜQ aUc,6pqr:\UP1VsڜzQ&5VV5wZ;, 2oVA ͺ{7̫7\.$fa1M;? %R3 bVheH殺3fM^!W+St+)Zeek. R.0S,\"+"'Vy{ ;%+ӌYI!v>h~ɰZiUsKJ}S`Uh'A*fwa6Hd-gaʽ܌[@ 9s&f/+-s\p|pU:݆M&jaǥmlbhm':nx`-ӥAay}zߏ1]Ot) 6[UTd~_LJ?/?ÿxS)ykF$sse`3I8:[;ɄEN*@/&Ue \ɶmn|2ϟ|_ܷ5-blx-<=>৿՟\gEP+ R u<3X))k0*fBNEUQ{-4d[f9aU bȥU#<r'fFhVJe,6ϐ눰N>S֨B!P'r8s[l.hng 3*Pt8VZRHXHwGfVB*J0G 7@0Beo3ں#mZ۷wTu?IR4!T7!̓^5S3"Ey1ks˚ցKdگV)3] l템4g~y"7UcP% AGWmqhj4T۰j2Ȳ a b%8R(,eZ+:̉dygf0j4^6h ;mgsee.-%O1뮕Ԅ̆@1bAdTYdȐ kzШEXE̲̒ Jvv['ƩD,.,Dka:n%ӖdWB(15ӽrjUy_Jʪͣ* LճޚUAgfޫ[I UurtV)< #89QطSĈY9/l"㇯goyyJß}~_ӿ_X^8 ӡ) 0YXLrU .Șl׃.9rq_ Σ|<'/>e?W,߾6`{ۯOW7o\|0#W;3xiJ;fW^`CW8W1swЀLc͒XyʼpW-"DZgkV07fXZCz?rphկ\-`1G7x+˺JT5]a;G`{qb*&+Xlы՝ GJ<ˍ[([F*6 E Bx)QVM cPLUX>TPӚru! c)(!ˊ rUbpaZ&/b(se 9n\e{A rOZ4Vo֕(â`nD,Ce)[ NXƐH5rȲ 6SpV*+jt91گg3?2PYݰ8,s>N_s_$^YJcZqfYLH{)8̇dYZe[Yc؊̻zwiM9*ə䐊f=7whuNN;q'Χtyf^*ޯ=bl,Z6F,ʶV 3󠙢7vfXoU/|\L"6@!X2DeĚdvN+;[bx微>6 Dr=bac-j|le  7Lf04=tr}^% 4dMB\@ӁR#tLa%Qs|*8*aK2}=nPM{V4[ЭgU`UzB2KF{n:(W#ʽ]VU7{CdF)K0h)7P?gDUѽdӌX[2k%om#m& UӬ^ŰȞYi4O{keZ~\Ki/;jiǴgDdrC=>ŽY̞OݨWg3/~x?㯟]z'D]z^ӛ?J xkrZ;DHRPX5 q#(+}uuy5XpO|W~zGexlϏyd#pĩ86=ߏtN:>߼wO[Ǘ?~_OTQlv[tF,XT͈UvdYh7 {7.H@yGuZs`]oz[aŚ 0ɌẌ́#A)UeALMfmjZcpmE7"bZ4*MftAT*ݳt*8"DĪeoyf< wuMT#Xɘи3I,>a᷏SI4`Sn5\^P. ۧt_αt5 7Gn)t٬9R;($HVEGٽZNV#:ډbJ r jUSjf kI6:,,,Ҥ!!=+D`n8%qhok:Q QYIm!TQ0=?YHxOW. n8~.Z&U4DfG0_֋ZuJ1,Rpqi*}V;r|"g?l].9O|ZջPBPVFUZXZ9r(ކ8hdiMT^}lZyG$Oΐ5 Vͅє '1>u܃RUןƉqe5d9uu^m>`['H`s5q IDAT'I,py\뇜y>~"V!v_/y[s}W\wgTDK`}|BY:T ?lϫM\2E 'R5 sYf)r(?N%JYF5fM7bdz},*jYa2 7j:2 YMk ʍ::"MЖ+ҼJ٬E9XHPyGYAxqMڕT#63Uɋmenk=?_m#"HͲ1lU:^N/rIܾקOq揾\IW_;\(i'Ipy&qYx|^%$#Ԑ$-șEX>pz/wsϾò/~SU~{F?s|6Qv1[}݇z6łJ[X-7)U8g_x![2L vG\V9OsFsd斫Rщ*Tyc#˩n*;6+%'^kkS*qT0 {fi7pav ֛[~٦YdJ7aUDןQՆabޘ*jy-e&a/ђ2f"ƀ#쐳rZ~rՕL*Tń-BFrUv}R TRl0ΪlCaYr*"* pVU*j(}-n3m?8;[f5³[+Bf}z~tu[K0 RWSq܌^r(;{@,~au^ 'z} %KQx0ߟ[O]U{#ݠ: k.~,̵Fx,\R.UrRLk46[$d5 -.Gy_z>€QNq||DʪzEIXP\K9ʺ#Ick!PK,suu4q=\(=%dT.~K=̹l2%[2^0ƠѕVWw_s/6ϟxy7N5fnV^h0chC Bi↜aL8bפR3)T4vڣX LBtD[E~䬐 $(0&LhAifQ :9fnEf, 5f`sC \1̛fѩq Nr5c[7?+.>Ki_<˟__͏2%$-A5Gi̫#>fΙv=NιrVFV׈D [Phoo~uyO^?ooǿ%ޟgGy+(d9U,+Ρ{c@#Sf#GfO5,UM&Lj>`WN*Sit.dYXY@LUFu/MF8TF3)oE i. 5RLh!8ت4w$,2fZk:ɕp2hKnLyD*lF\kUυvg"hXTT ˩2K[A Sr>|5~2GYVe`SU8eMy05}6}>=㺞WO8,[ȓ4b1m8af N!JDؚVlP>j(NNƬCMV\k%!V+H}*_ckձdф)4 ?&!XJc\V0_ ZTNa"Owx6U'2F!'M$۲뼵>{DddԫT# )0fh"ML@D:ADu@W볋{{ipn4K˴t{k} p'/?oot{zя!/QZ۩V|@)a_y+?9J 3̬he5? ,16/jSA4PfSL_wqCt%v^lnǻK?~%ǽNˢq1TތR+!]HsJZL~fx$̯Tًk51H&%sjRؘl*9*:+cV.jzZOFLjT;LZf*]5c_XYWO0h'C缤dȄ*im^R-bS#rbs441rCr&tŇRsQzPEk`M2@Y'. Զw8)GH!mSpUBoePVÌbJUPHK2[/ٚL<_19"ά4QLcvGR^i8GMUM af` sDUo;$%2zzlDlK?_ݥRhڃۈbYGu}:ul an 8YഇB>sF3{KbZ[#a hMzts:V%#WU>&y n]7ׇ)B籜*ouXf(q{0eք, 7)H3'\_Z"f),36TX6&/{(j., ;fHk-#n cdYరf-g5#c4#m`Sҗ(˻eȌֲtybtvEbk0(.7gD&qehblo~7tXR"H ,7אO_RS (Yka"Pc I&8;稚6X٬5v(21}\ D͸ ,+>7]lvavZ'4'KU33!YP 6?[ 67(:bCKSo-$Y T*“lS1f>]}Dxxr1za5ĸ`ҲGjWjy]׿W}O?|o~uwn3\!'26JR&K蘺_ZyVTHJq -B\r9~w>yxyyɋp|(c6Gւ~#yٳ~|_&3BWz U̼F ;$*J;EТDg)%46'[Amlr_hQ,ЛWn-GUpb hh~h=ZRfQ6I{o:q1)y($YYzz1Ĵ%e̴j^UPfP$bҬ  :Ag%VW8EGL+DIC%!3YFH:Tgbܔ[>Ԟw%6XP6woc^tS*UrW)C2`HU2 ^y#,Ɔ~PkκTV `T # MyrQrUN('jfG/}̨T9BDeARˠ_F=n/_߿ɐ:e'L̨[[?q8PG{ ١*zH/BR]^>\Wv:5Rq1Rm{K׋olۋX.[m#.#** LWe;t$` ,2lI^F3sl5 *ثJ, lH$ؐ%TVQ"Z]Nʄ,6U#kF|4P}ΩK[" cs:벹Cx~{}\Zƞew H uEG'#bTz=c#E.9C55%TF۔Mc`78*ڌo!@;3ؖ g5pg,b:dOɸر*'aWUҴ- VHLR"m*&Y)f^Sm"Er^p(fԘB?jM0ab]1`1S̘'OBrpFa<_ү}a[u$Ƕdlӧݗ[_?V~+['hQІBΛbNɾC֊EYΑiCow'bVY5XM[{ gկ|O?g_|z{>⾐ӵb V-Am{{p}毞}5ֿ2{O<5eVܤIHӆhmzﵦ E*EcHw%S%  RyR6oreR 7j7+|@ &]sa++L6Ѥ nFQb5dD6>ĺ;Qh$3B263S.`3WRmرlgDT;j˰x5xbmJO ]T s4M}miUZ'o-yy;][;"LUn^. Jq&2PS Q[~du= 9κ?h\%slfL\͕:#{Hb2_evT]MEh68]dHi+)r 5Bc!gCagciT^U᣸TbIj U,5뒭͏%X^s:Ēb5SMi,6c %1cEDZ'2UĜBvA|k-a9Qsh;j!7ѵ &' ӾZ|T5oB} vU͕zík L3=^2k`Fl9sH.r" s¦@urHMV9meg[ `[G͖.MNڹ_2Q6;Ys!e`!1Z_q?kxݗvoW_|}_>xû'{,\6IҼg \ SN*k%L Ȓ+I .y™oQ66%LkĎo)k-2 *Ij'zJCH7"0+512Jn XV&pcڠe\GӹIy3)5]d4̲M@1rmNє!U H`*Rjln9`A1YIDlI*Hٜ9-00bΙ[R8гN2&TJCmD,gʩRQ9Fsܭ]1䆒ѩ :jIYeF͗ʪy(d9NPI,1273s[;SukpYm=36̜*PT^O}}X_7[W?+nwq ؖy0y6F͖\p_i|$j˹S퇃 bSif"UDNjF*~_w^_ ,בݹ,^~Xˉ4t^ݿ_oNOe='H|}Dɝ&.e`R鲖ŌD'ǫuy~X[0[1=3*\Q &ieןg٧c{u =zޞnw?p*/˲ҏjS,# #GzѨ~}?|GsmY+TD4T7N{*Obbr8xKP̹sr+ToCehbOP)P*) &nC1'JcMU,~w+Y2z  ,`E:*)>t hKIV)+լP SQ} %)O-^g2@&KsA22K !Лrjo}W~I~_|y ղ,˕/=r,+Xn/q ^~/7~??|pݯ>Ie*T{&`HXc̳i["*IUx֖KUay*k& zno~_џ}_:w;\8BXxQu2xꛏ=_Ļ~|zǷۏ?W\DFr :z[/M6*Xo7fkϑ fve5KE4 M^&exR h90MU Q.ZTSB*ߞ.k5ڊBo%0ÌLΏӻE9o 4*(csS#33kbȱI~iJs0%U2l~O?Q2LFMP HNv.dϞmnY;d'J`O ͇^P%b^<ņ b<;vŔ*Ū7GycrU\Û%x((s|}41Z[4Uj:Ƽ{erR0 00gE7ϨJ1Aoˈ +4.^;A fgM~:,hV#*~^/V/lc4Z൜zkm O\U\nўl<ıE<\__߿{pyxXw)KyXieۦ[DeZDQ#11ia@x8jק>Nnv8<^~anx\|Ҫ2m9&[w3L.wb hqXivbQK%zc^\Vʄ$EZTdS{APbC!m SȈRi*?mx<_S*2G/,ޯ'mkryU`{fnP7EnX+p !iq ﰲ5,aw VglA$f{dtXVNyVJI~MNֳ6'd8Y; (#(e)U[[8cT; #y+ |KW!3YSfTyJh84_Ё2دSty;%>;~[;~OFf(ʼr 禱Y3M+QeeB뇁#cI_3(fnf⨭8?|_7~_\gߪӭJX.۶֬i:!^>y?g>מ}_>}z~XfVlz[*P(0+*Tdaa4TrD) u`ZZR%fY|3DKL,eMua~[uʗ 29|Pvs&2fzH5rTAdL {y!KXUm,ip2IySԍH4`!B b04dvV)W&Znl[nu% .ϪYid)ˌ1U*T-he4+t(KB4J>b!oBeV5=s9ze!Ռ;mHQ"22Dj5deJ0z{ Co\Ȝqm1tFbmL0٘j j `E,Gy-TurqYa˪Oޔo>Ւ#^G;:i.K[@3yJ|ᐏ|{ E5zٵD˚d|$ݔi`"*MLhzJ̼"v1#M);+iU]E7ЛLz>2>KY1͌tl2ݧeל5.Ms7&_ 抢P0Bڣ&dD!U% wON 6C487?5>{VYJEV, )HJ(^^0﷿O?z?;rXcԈбԃ*sZܳ"ϴv?<Njw>n/GUn@V*VHػ":ƣk[s.Z5Zn~?E>S0dH`ĺ?~㻗ZM~Z?gK0zϬԗ\$ޏ۫|g_~巿v/wZQ\ ̕tp;4+7 Pt31n^zUay$Bf%sw3 ^=qʩVABI)ƘbZ&lKpJjˀ^A1h <%椛M%"*Z)Lop7_Р[7'ZŬlUeh0UZ"@Uм U@3@htrF'@06}ڥ»0h*,scʤ epIn0v`r.Y^ \&3#h)a4 M%-Ҽ]^1A(c{0}7UTQY#PRa3PX+uӖ-ǾKysрd28,CAy&|ޝ_^NՉpli&Yuw_z(0V<rt|woѩ2c2ݛ[e;OT)͜clf0[$T֜%yo% ]K[cdiU6kDJ9H60cX[#L ̥H9kiDbFn@YlY{;1_U˛/zK?||FL/ z[#:uynգ+_nܾ}{suu£?Ώ~GOow@Xy>9(p7!rz֞ s%IL5f d&& &0w65{k:lҰ9P_>*Cж1_ChVgN󽽲+l2dAJJwLod I&j|Lic* Bb5q~NXyP6p`t3>6mFGӒ=bI)oLLBDxOghvwqa6? 6/`d@W5j%`ނՒ ^65,׎ai[dt+ڛu>$!e)ܰ4ʘCMzS|{Ώm0 sӄOֈg3̻/hʹ,-L<;L6 ͨ$N ys`窄l}6'̛9mVoLVPiGNo͖݌z_ƲAڱTL跼z~mZ].mvii̠Vu;ڰq;]g'cY6iJl%딘4ZSsC>_^gX$~7wC)ᩳfFrRb@OAW3LF.i3uܛ@ KiY@i(eS u뤁iYXBV(+!QU}ݹ>BI|j+a(v w;FL4M???/Dz҈Ba-8ox<ۃ\˗F m]/o_=}űr|}K9fRF"fLuh ȅ?#kn߾~ħ7?l̛ CּrRfd9F6z{>o_#aDS\/򴬇zelϖWs/pӻ?%g?݋/~4'jaMުf,w"ݽFY+X=QT8fKFVk/`dួ(C03©ڴRLDd`Cj QjdID5YQLʲm߿:]N /lVK[LO&Ҳ(:)Ͻ9ICZ@[Dz5n̐ BZJCm+ edwUxV!-Em3yΒ,I%b̜;*G""=ep4+ĞnFϐ5P{PJx (s ZP,Tl@0ņȥ/O)`Ց4[UA,^tnvšJM|Dl1g̙1f^w6uBeY~}9Qay|O':ni8<=&w֖ein#N!r\ɇӦGё fmikJoW}W/?Íh9@=1yy޶c9C&9؛QiMp35imZkjMf @4K֛"HX#P|0yN\Pd0Lty7G_W]\7Lbޮr0knfFy-Vp1eyyc˶]N3G|zs)aWw/[kWƆ104H1'eXQ:#ɘ9$UC3 VOkJQy:LHIH ^pF5[&[Z +BdV_Dd2-4Cr7+T908f"]HCi?'a Q[T񛋙k#BIA3cYK'=$zX$ڐF5Ikԩ:ABePq4c}njO~'x~Fi"fJls<2{Lqڳ\xy<>C~ջor9=n#6340" zzŋگ>_w竟Oteݏ~?ԶlH%tZz]V֬lxȇo^僆X)NܑZnNXw:|}m{;_7-5/?7_~fv/06^`pLLzmPh)Ge|+  p.MI0B9Zt`H^Iibw "$E\ ps CLޑܜ }˔{F7v!G aٶZȰn-5{39Y ΢kNO Θ2yޙ99-AdfQ$Rh9,7c #achifJd=\ f-411Btb>(Q[)). 9-ЬT1k(Vc6%] 2K4"1w,\&4;f֭IO̘iNJͩ$ *jᏛ{JҬ:4I4L-~8-1o0 ļ![k=S)4\ ö́y~{7_ovӮ x%޿:ԛ7g1 YJhœjw>\^|:yL.?٥'uWoُ5v 'tV/uHZ?2w#[wk7.LD>9tqx/淿<Ky~.<fiP=$YpU3k (Yųh>-\b La MNM(S9ĪȰeԓ22 W 1gdx/Tk% uAuLG kS%aP*[ksYӾEʍ$lyt'{G(8,/`@if::,:LH%U(=L4ΔRjʓYO欉Ķ+e4 f)aLw3v!I_}-gRFH)ل!]0bJ*vP^ PHl%5Vc8%E5cV2Vʞ 3F^n1R)Y'#_guդ΄rqLDJD&"Ql3;"Ͳ% sSvF8.1s#Ч.a-SJrmsr믏ү찬]4Ooq;/-ǁK"* ker9<"G11hđ ks Iii eZ@$)D,˒[†4z.6խ(Lȩb4GbWt, pE:Vvv"L*?J> ͽ-CoKDLm9 04Gfom%3̄`ʘCve+Ma1gn5f$GkqꜹN B4.s$ O[@&6;af"p1[qCQ^I4S.\e{%C`}+UݬH!tP2EpwEbI0{e[gV ^bRL5BBDXT9qB\7*U22[HL"T1.Y/ũ2U^x3~q} t9qlW[:Ѯク>OOq5>y廭G?wjlW"y'K(I橼;,ׇɛo~qyJu{LSFʥn4CĖFgy;c꼽R>)pj-G,-/~:9ǯ+ܮzYmΙlf4kQwmP )gDԹdE X2P{ȴ6dYޖ 0PA*UN0oVnEMi]^P-ƹEe)#̥0CLUG&#eG:?%Q}SQ 72KYSf,q ]jL`cΩ̊UɪcNjs#0K18W#0!ȏ6)s,NH0cfʲҜaȳf-k1ɈeM V누~6Kw3ܜ#C4O3IE!] JkB Ve}{ҔcF!S^=(>6Vkts˸eeVO9G؅6'5syDbÒ9O @s&|D.X AA3n.$'ڂ理j.8Cdڛ}Q 2҈Ba7ǃ{L7&Y VjIۙ4)ed䮙$JfկB3;n7su{Sqѱ]wT=!Χ҅Rs$\0i-RȭnRV:>rp\dOJ}q7y?m% m{a?>}=,}>{ώ|z? $2FiZ~k7 7|o?oǻow\1CF5HDE5L9[F [ȄM2GN=yɷq~/nO|<αf*7c!NA`ѺeI֐7Ή92}%ۦ1fl1# =(̚wխ[fn xW}%ܧNˡ)Lݨ͑)@@Sivy9/Ms`2v[<>\ލ13S5J[V4K-}\Ѳei3LsFWL.#pq(n$"/̢eqx0k8HhV7&|z;Yo-L̴DEvi,=-j(f42:e!jAPyFXo):a&)@%E*S cSzUr%9)id}#t--rYE\ @iBHO @4t4qSScneb*`ǷWv:]ݲ,c|ֳZwqYolh~xu?x}._n_ϯ7 DZJ*4PǶǿy<W7w)N7??_?x~p?>_qLcMdaN@}oN>އ .>nXY>޿WWb,O~3HE7[fԜ[њ!Hl<^ӤH&@(%K0# 3Q8wGkuϭAhfV΃"hVd2Ad%` Xn}h}9@)eM#62Ȝ)6cgR!#ۂe1NiSQxILݝ#ue#dل ` [Z)I$ L}_$m.s 5^-.iLϨ)~S$5)!$M!9 hJ Xj^9b^7np-9ZW.g6nv<c{K.e OqּDihLsv1tj b]eB$e$H6x5T{!SSt?*TZڡr ia\>s_WN%z"[Ͻ^|9 K*; u+ *^9(t/DPNl"݄Dsq0pМn9+m[|2iuz)f^9ƀ lN۱yY2"#I3^5=ח OCo=<?|EoW} N֖run;<~y|`poοo_86ҲYQGȘD,)t'~պ◿ǧݴA|>~qehFr'ywټyMwhEqdMh\o7oOn(s̓+>}x뱵߼yٗ_>yC6֞2v*[-C}w5re! Lz`"DaL;Sլb*KRb(eZƬ1a+W @ faͪgW^RkYz9)Q*Q 2oaBj=S5DqoV=PAwOI+#n[<{)jZC 8v֔ E3ܖSJEHB2̗5f7$GӞ(42XS$cH6+yH$0){jRdYR56/aP4#" fl]"3LJnp`G40#E}ԐuD̠nQg+%(3Љ9"""LJ|9b\@7GJ >spkqY Lc/G.62#̍VWgcܲ8q^k\ZwZFh Qh&sХ^^־x_oɻ`x>qĶpQscd9`Upz0%6gfd81K.h[wk$46W[=ֺqY"7c7C˜S]ZV9 n.Iz;Q"Q(T֍״|Yr䉾sĔah1P&.ˌ]G4i{?4' fX<V·BwSJ\[]}9}AǺU|QuFq ;aol4v (>tf-wF }a'{dGI.uvXcicxJoW|=Nuž5'}q2k[.y͋D_Mq{~o~ӿz7/m}qq+ߞzw/_]%(#5+'snGk [={_}ywPn)q޶ݻ?==I^ctkt<ۊ+oMj眾Hf'\2̭>E?#NOԬY͈ (E8Z̬[4#ae1LCVx+5 ?n4Y_F<Ҫk,dSqBl|5OhVg[.4ʬ21nYCQ!cۥfhHU-h-C:ȻҌO<)]J %Yner\ӢHt +6e >9i3giɊA 3z(fb:P:dTk /D'NVNPEmYό ;%[2Vt'"g%s(̠x T}d8q"JgZT(h7]{.16ΚD]a5'Y2aTkXHk1zvu9.1 ,3k+no;fęWWE9qܴef!o72ӘnLc^`12_?n5Ǹz؇| >>n1.3s1F2aV#F3ʝYtWZ[s֛uc*瀕VpR2G:8ͺ)i5[4 ֝7K\fƖ !9F22s̚{g(rYqQanoh%yJ8ApZUxY}Zk8FfkFZU 9lUGǟ֑I}eگWQsz&zf %jO19$ &+Nfyz˴Mfn  Z`5D H>gJ>SèL[duVb%!RB!DDfƙPK&M.55P$ DgMP++R]/&R e= "wiy{쏾=_=fX.C3-wu}m}#B]|خ|囿rݮ]Ƒ)&JZomw?O_l;~iTחtp?67gYd_1l"70;-ݸz _ߏzXفE~rxŃqO쇯|2j~hYk簼Pp0FfR"n,)2TJ %Q?L"`JCQI\LE4QrՆ4uqt֐L:1"*f$$K,T;5sOȚE8|EHu&*5*Ll4Oؼ*}ք H"aY)Y T5~Uj,Hi?%>J,;vq^a>K_+E0g:)sK5 (~f |*ZS)efLܳU&xQ& U@,ūR[9Jfgd "@&A6pi_ ^4PAJ^ᨥpzfCYB34sEn@To3 IY{:a/tv4^^|l0=.**ӱ@^Q9-aYLԴg'qi8s-cKmnt5(ثnnvgZf4G8GqCYM{I,(#Ԗ4ҕ\ &FΤ"O1a0WxLs0[_@F`m5uwkKk{{kn̰n\d35&5iSXV\C|x|||t!"bD'2Rze]ܳi IDATkys1 M vB"͹_j+ыJ&ZlQv΁%)keRl\;NJa3@ᩋ#Vҙ^ hHȅ(YG?sL%W",hm͌s;gRhދEE% .AsfH^$fn2JbT [FҜLz4E'0?~}sx2[}?~lcĤ3B ޭgds8yӋ?oGwGQ_?f,!L61'ou⏺KWe㯏svl..v7r}ŷC5w85l!W>r<)ovZgvC~~񳾭r/~/?yÿ_yU_\+KRyAL>fYz%- )+&"h-Mfm 19={$#ܞ85 [ #FEؐuxj2gH1B~ >n;JXQє)Z+L5#w+HwHm-5SX)i:9̽% o\\<> gDd.t˩T[DִZtTMd3[C+vE*{@u8jORt͌ėT~RM%KWZHDto"NO%Ϲ5/,32quA- -0rle'|0@R!uVl)6#".yVI b9 k$X1[Xs&:W~cpX_o]>Hb헴6h޳qY10Lpo6Gxo{% m2={w;_{<o٬moA* BO"nIX[o2v:KC ft9t>Oԥf:Z*b{~X 4CҴ4+Jn.167iȲ{_@ 'DTUYFSc4ā4_@D#")dD {K?/e{ZߗR7=7C#&"Nn@b!-cfPd0SBXt/ielO^e'ͪ,hGc%EBp&"A$I Wś:pSƿgqGqpm9$du=l\x$WӠq%8 fLcFu#$)(,0Clj,m*cv4vnT9~#=L(GFLʈJ$a9#&U?oG`PI^\͟|?ko'/zq[ BE=3ξ޷.{KՅ@l6-[\.oxt{QJ ~uXxFFJ,}r13*u=wζO; [mz?2{z<ƛw~qwR鹰/XnQ j0Is_(Xn9Ƀ()5י^kmzPAKHd4+kAzuPUZ=9Q%:́0`wя16 Tc] s-sAxw%XȚ9Lڂ*T)Rc34!Q9"Ac2 T}1',*1ƽ$3WFhäJ2DWR}}zpSF((J\I0*`4,Q)Q`406JEsd!Dt f&mC9I97U,n9?yn~\[SeqʶNGS',dݛ֢!r`#4֎[Vowr[ c .6}Pl Iר}Zs2N8un!_AUG_!1]JbE/>U2$:0ݕ.FQիn0Kd $ >9@><C#ef,N#NHi fa fc!,HiJFl`wxbe3}W߾d:~уgg׷__o~QF'߸GE.=:+s ltst"(a-Nl0O5ZJ*1' Y6DSI_&j+V #tf:^1O kC""eRs]NX'A9"!3`9,@CR d0hdf5ԙae̔a}>L%Ҕj `Xo FI4L1J&YzU.#l.nb#4ap }I/3h?v h026,ob&sRdU@)18;Jḩ#@a)Pj`KEG 砟B0+"~o)Ywydt7MGtm Ȝe?~s%Ɉj MdY"o*V勧^ͽ^/Ƽ s6L6tȶlQ뙽KMNCsD,{eFQrj!ZN'ZXU+;v..CKײd,ATk.ؼz41DҊqCወTOjeɁ"Ft:ƪvJM])g)(Dhx5/0@teK-7a>4DY1z7R_'#%bϱd)lQ|+Kfy}]DP4wȩqMK^B6/!R9 KV'9JwᛰauWhw\KNJB@V\X9sс+,8:yaSqȼVKJґr4Js&[E։\tO^\> Efy ea<@', ٕkO'x%2n`dTwh7Ogg/9닫7>rtZS-)d_W/{/o'x}w֑Wg:xO??~D=>;=zz\3~i>M'<9}8vK'|J a*Y:8.Ώ?O۫C{Ow7'׽=E~ocZK}e8>Ϟ'm 5K#'"ґ @ौHpwB(636AEޅ#gsd ŴuJ@krUJ EFf!A!Z̕*nfYa67 x)`9K3:慫aDw[Z<"p g)t=5 yƜ6!fc!; ȝ4X 1zN }5$-IeT4="s6#FB”G2kDDd2NuSK!m96HD1 V(YK,Vr2"R^,%c65AcSРPZai 9v'},GGi<4T 7Bb(Dmlg_KhC1"` LvLo8itWA41RSǼ}9rgxj6lOkDl}Y~v}0ی9L D1TBr-ZY'~aoԖ.F}_dOX+,%glDujc)k)e @GrN/QWT{ ZrTmrK¶'_뛫,:͆1T x,ٙI+V'^&4 9-՞c.N vTtc5l^x,E#$ftinAVNK&l17MHTC.Hz %ܹ٫2m6e;q{ϥY3zkrP#Ji/2hON7= ukQ]-"uiƐ'Qu-Hs8e1:.eY0"Ѡ66Eu?GRpCF 0E,Hf46c#ep e0jz3F2YJ_͜4"Q( E#D 49d"A#ԄGY-Nc>}G߂ͦ@̺@o£g˴}{ǗGwfjHdfjn^oOmQy7Z>䳇G ^{mzwկـ^22i%"239.P[rI/ղ&`h: Ec$D)St"ܐ.Yӿ K-́$mo[#5jѬ?L4!K]&x0FfTqwY YX|2i1 ÜJqU%@%yuNXBGFWh ؖMo1)Z(1`y*禬B=2=>O4bFsȄH%A[?8?}h:س-m?z>$ g I'ȵKHlfbR !d4mArnFEN6k fW.;ecu(c b|֊{i̤ .xhonn_xv?.ǛefgӒϭ%ZkPg~(9r#0j咇1lRmrn':#Zt^x~i$iɢ1Ls +6q5-ݬFNS s3S^,b pwaFEʂP6jS]#&"CJ"-@K7I͋+ᣌ4&̈Zko/hczTjd4G>n*z 5 2ZOS dFt~+Buyn[\bog+^լK=6h>b~\8Ϟ=~q\xw,'Gۿ_m~X)_яz>C/<~K|,VC~׎N൯>$@7dʼnHo϶^}wh.'~ŋ,KS3β<=<{Լˇۣwpޫyd妫E4+#UDG $M&IZ0"%"M*H%&]"1!CX+Q(na*>֍%ջD2"TQ,RO%m'զd>,T nGvj<wS׳=bf,Mc),"0lI ЁǪ?lY~FZ*ծN?:&YynbanqXm٨h&pZ#YИ-kuUJhE+?1+ׇ_~ϯ/GzC2 R9zڮ:L0j`)W/_fݟ2QV\FPAKxVp٭4e2Y /ݪLR+Suey(Ank9o8!w9T,4z@5V6YU.I+ 6|yt[>77ٞ-uǰVy}qȜk[Ra_<_Q77v;__SQcfmrtľsh_c!Fe򸗣G?n?{~g_\մ,c1JT-D*EKa=|= KlϬf9&Y0HDa9X  [bP%5`>)SJ3hC+3Wèҋ;@wHr/ժYTX#̽f]5rAu`b(tRk'i{|aP"apͤ4HcAR #1QE!9& j Xzt*NP6,u 4mz4g$NPPG?揗O~ӏϡ1.#;G%+rdw&`q+5} E(Kt+r{\M ߎ&⊶Zu>Xz!22C'9b3Àn`RFn (ٳ>=͇?(^.duQ/[Gixsvq--:m7'GGG0cn IDATTefdw>g38N#wFJէ+nNUòX=[PIL{Q!\&^J-Zn7dOjQJLEwEx֭ RMf.U櫻n ۦi0VFyQ7f5i>0ٴ4>Bb lnhLc풒̌e Rt#E-)ƅ9QˍEP,Ei@Y ,@[e&Q0f' 7k$Х,V!?uS5iEbDD>*f>FB ̀@3b)LP-L,%H=N: aEP!*P6p5#RKQ4*%e4R1C$5M;<;7޻}e5[|eXF3ϾZOn==O\@q~v~|Z V/}"6U,#[Y6HݧBsDVf][-=shHd"[ we#0ʤpŕɖ6:k)tMQܚ-3iAxQ`.T bTiK1jEJ@𚦅0s0+AYʤ6HX†BL%[KCT(@! 湹K~DZ#Z13O<Ʃ5g4⥲ʎاDO&zDaMÌ-MV̋I*~}v0bmRMe eR%pz\}Hc4k Y kgY0B %[wC>]eirb׶a/}Ă%¡bI3:@P# 줷@q7A  ) sH9/ ,iu3H3GRq#5\)2m*Gb#,53+2!jY bQ}p)Se^rk{~r|z|}<=QNwɿ>,”1ev)qڿ/rz\i'n UiyӖH-ef^"vYM(KX l K;IJ =y5T[ɐ՞#BpsXF:)AEЂR "3 @T ̪BH60*^4SFPahHߡKsDs(tÊ͌dFʦ6?b"o|֤ f.jSyi$!d(hEFNaq 84VD7'n?O{{z_6[ov: l6#>J&Em5k}l+mO6jq6j}QK#F-Yalbgۮ5J|BҲ^Jx-@go {_q+'[V6«Z;콅e5T \Mk^s(+HTSofMej1׍RFLB(ryqHš;ʖhO0L22 ٗƑ"R69$í)9#(SQ# {A%{]V s2턲oN=5$D, e,VJuB0ЗGvmHu+nmSѩVҙ,Z-LdYWGfʸ_%p FD^}es1Y #25nQ,P/=@]Άk%R9tN@=';2"L&ܵyMHYbȇ-7_7b~)M;O`Tpa_aÿ(kਪ#s}S͝"%78.__7_r˫'7/__>||zϮ<;}o=<7cW㨜\<;s_n|g܎tiSuO==ׇsd,x?ޛ~rsy~G;lp&1m./ovMDz;ކ O6";Qg?{~WN[lvO^>[&v{-򕺁ĽC|ڮh*}7'W9:_;}s.*YJSCN2i;q šn}8 +c29!R #1ÞR2TE$)X1PѡtX6{[UaV2T *1xtZw|iKD.DiRu*aeLd02`@KCGqлC ՌlZu&fbC湕Z2UzO<$ A snn_~v9-mZ1BBCۻd2GDGQ9*c6GfvK&A,Ut 8YE F]?̠b$ 9uF v{@Α 4rq@ZpX9Ȥd!ɀY9)ͮ>W_.]/ZLحtz)z<|ޔӭԼ\·e=Mυ,tz -&߁-H;Rei)Hij5ֶuD"T VI↢D,rSy=MGNKɶ}w~֌ۛ#o;+P0cfǶḃe-:p2mT ,CcbT)۔t2Z쎏rm`inٖ0ZkzL cM5Tc'sPwLS99̹onZ,Q_:U5\"S=r+^}3 uT1:V01b1WIқd>:ʐ1cD%9΅V!ZNzٺPTLrz/~oeFVkϟ'򫯞^!.fHԁޭ mrX3i]\i9߽:!-3elc[WjF<2LbޠsDkGi>\(>zXuBV ŲkZOFU$3j2mGy爲AW&:zFK*9 ƒe,@ZK1 )HsHF:48C݇Qn0)4 CԥT59hc3&wuγqι׳ϽǮ.|S&EHРhDi"$ZHZ@@VXJCD|Tչ}]{5/cE2^gZ7>]3kHNi`WZJ-Ȋ V ~x~8N\ce@#t$!@PXnCep$JE CX'm%VpqR_x![d+Cͳ5 ͉.,QAEfYí{=We0ؒ*{샯Ob8X ~uzkn:b`euըGS&"'cS6 ގN=,Y˱CHs0VjIRuꪫyfG237~L!0eU.OeȤ9vν2l;{fԩv˓'O 7):7)"a[^ybXis U@zh 3Gtf8*Ja "0S˥?ɷ۸“g?8o0_W6ۃ9{޺bo}i:e+'n?IjalzGq{`<ʹݻ>{|J ,瘽 km3j7:ͷ^7>z_rŗw[ 4l_O7tީg\uv>`N9y ~?<#NR?/}~wg7](X!ƈ:XW3Ҋtip &BTfu2XHUU4њCdds%18 hIjH7 `vUdB-&*DT} 1EjJ7 81dcXn9r(E0 >)j z2E!Ph@eJy3cc z}eN4S!ijKnh:LUvyc@nb뺸2&^\=˒}!(/P*-&XfΌb6H! ]nDTuD*dn dJj&|LVvHl*")y**!Rᷤ@3RMMLp3Peu1@{eb@zfYM&FZ< 0D32gK?;klC6vh<<]|ٗ%MLCB& -UӤHUoI6XZ]d[&rK)dvRܪ C/66 }-mDF4ۥR,c흦mR骧`*`0۸ iiiL %-O80O墟r<upCfOt"8O̱?j*)ŝťԻX&MUdtrզ]h9Wnab o9\ %.W#o-[ *B R颵C5%D$M3JQ fxYb ƭ rPEmTbD2]10. q-F$t k}>rbOd@mKEN*"1,ӘBW+F\nlYogvwVzqzyu/OogǛN:yx?r?|g~A9ӷ?\݂bB>]ώq9_ME;;zqA |j^G;sw_}׎Ǘr>-/,%Seѷ ?;oΣ/<ɋ'O~|Ko=;_i?[9ߨ.S_q]zW;ͦW.0˓_|_+?}﾿v{ޏ$咉iZ2]%E"L)YaLF6`FleZQ3(U +v #SnG?ں #ku1qS@I'(yɼ)0(܈%/h.8z@ԨԀVAEB5u/B94UӑATf1>DE&вX&!C̬6;HJf kDQ='f:5A 1DD02I3HKz1r$QmHr˸-\D= oks#6TJ&nU/|@ҽsSLUuՊ, o ĶܶZf'Na+m ͈ꛪV"?#S2Sckir BɓL&1dJBk$%|:Kj9y2;i'=N̓8쓨w!wfjTxp2vusYW1ԬMm,hXU9&P컋퐚zGei;mұ6 rB7Wޜh vEgʀhFxkD`,?kj"*n ksi@j* S`2,<P }"RtkvY##H5`! ,&:lbbS"#dYr]$:L LlHlwru+d벟Z٦6:Ĉn̦xϚuR)w5Ag:а7#PD P6 n]h kX Hz M*B2ĵIIS afv>Le uAC' ʭIbdflHqnrT"$Xx¬2XGJ"4II ʜ:$p5l643fFCXu5]%Qp&>xWؕStZ뗱[_yfL }k..|W9۵7_NUWwt/_Ӹϯ9.?rl/߹۰[oΗӗWs<&O_ /z;EwvS >'3xW8ǫ_?{t唦Ȩ]4kf4 Ȇ"5r q IDATW&^!rX@L< bR@ZA$D3M2VE$`df#!T XpCL 1(Tc`7P8KF&"=S"PFF Y9꒓%HȖਰpyt-Y*t1ɤZM+O"K7M ]CQ" +RCE,}XJE D`([*BZD$"P`HzoeW*ւmU.tRԧ` m[jkncޮEk5ꟉlSnOEu cnoF)u #b@;1+&4Y&1{ۑ Uc}nh?a8Ἷ{v?k!_?^?WxݱO9|Odu={ OyN{G/x8ٳ?x_^_>͋O>Y.F-Ti^^W_vȇ||v/;azZ>|m9]g7x*nW`¦N!!"U$Aĉ0 0}abUIjXAt Qy-2fMH9 M43h:%ScUҫf@7خi)).Le08-3hL c,=1PM(Ʉi$&,[R\FDPPdLڣ%e)~8 Q VHiTHKpPvKѨ-ʼ78wklZdv"fZ Yl"2ZWI;)Zbl,ɤ ݎ^Q>@;tPɚ eWmonw"Ɍ%I=gϔq0B d@SU X&HWu.YՆt63Dmj̕95s?y Ä)>YbWsxCρX[sUüY1*Rv ju_\?Ywg6lQ5-!k,0mzvdz=1S溄 sq5A, i]3#mr`&I=o& 1fZw@T ȨeHk;"yR\3O:,`)fTuʧKẗ́tȎ׾="WN{]ajU|~ܛ};r,j/u"Gh.Pce,H pH6M$2h" D0T%Ɩu4g(0hȚ&L:i0Xf2g7Ih- UdV ;#\,`Cy"F4m9 23M<*""ҤlQ6QgMnbZޫݜz+6j s&2HZ NRp<|hW7soθqxw?|q[S6~sݗ>?!s~,9M?outD:5^{x7Ǘ~9?}>˧ǧWO{ŠRz#~o?'=>[}ܽ95'!j&X=9 U6xirY]sKfHD`1zIFuτd'kQ+"]Rʬm(T!PPV3W n %RȀ(9t;WfPYDD5Ê%+3T=EEƨB:ERBPմj#rPXT`GJ #VQ0ʛ6)]C4EU{Ln lGX3Zl.rmBg#B$sSn#hn'$tRߦwo"@F QS Qd5k^&t1RY1",o9YKy*K5J@d|3WkdfĦE]Y9TtTQ-M%1Qti{*, -\hz v,$viԀQwSeh2(K 7Ǜч((3"9Z:\-G"f!rw-~}ʼ~O{!O6D5FM8U&zͨoL0'z+\ wv^gN;ox,9I蓉pq}sa_+v>1ArZ?~31_?9O?}#vӷ駧>V齏{w<>/G>n1?_޸k5"EX2L7SDPֵ7WW. ,aHH3:f9J{&I )Z9٦E@ :fB3Y[g"b Ih C"Civ o.)cT͚p!q{ kTK1pP tIkYZ!wJhDYWH UDAX#l#LuFXL GntN3HI!'M)#' &3Etsḙ]MRXQk2%!0%%7ۖ-6ڨ el%b54hDͭ1lVH)DԌ h!PDG#$ĐHS f=WZơ&*nn??6< M&ԮĈ2)9V2zD35k Z-cIi\Ǖ!9c0]?& ]G$G+*-,9fTީkTkWivZrLi85|G;h[kinä&-ҬK b)a&QGN7`9 6Kq]@D8$'ӂ6OcG1MƑ[i04=**P44N;6R($i=hv룞VJ?1:%FF&39܅uz35M1:/+wy:3FBt1YN`~2J M^3@?JUM$$5᭏e]9T`/K6Lb0u*0x+" a2z%)E^.kgnXDjgJd9 "t_B- V{2B3j @)jO "" oTf2t2L L$ WߔM?D).܉1]愱 rݖ6U!U,hSwr,x^LpwW_}o5ZwަùH,D0ݎϯ_Fv~2ӑjzq׫ORS?^.ٝ?|o?_v4T_ ܹY_׾xY_|Y_WJ Lmԫ#gՎ@jY& VkxZF [ LN<9m딊HE GP!VY&!Vʘ&I"B HQՈ.CITQ'TlҨy (>Uuੑh2y7:"2Iv֧E Wzs*S&&&BɆ9V6 Y ܎Ia0}i!f (榨DTѓ:X譂5#Bn% ׹:1#b$"s9$aVPDS. aeh"UDZHz,$T^xA hT4^zxe]طϏ4!TlLf-DEqOZvn!52u^wTx{ S3Wkn+*!ԄSV7Se 4 FPVKfELեDzc-hɈk͛79O'Y "V,P(!BPcF2ec|o똵I/0p;C[ mL9N;SsK__Ӄ}2ǯqso7?g^G;> >w_>}Ǹ8>?ǕJ ϳ{fOnnr O^Wc?5Oֿnݜƪc l2"ffc1PTꆷ'窦N0 gT;FPL+!YevgfV %s-qe&>P" j+RFtW5ť g2xF(_ҀT F&Un 8wWƣTOyT3 ѓ}[P+B8))1E&(T)Vzd@@oܶ3(PDnI;Wz^cbń r%m%Ѻ Yo ̴33q_޿Q¿+J|[~ѧO:/?kGώ:H uArsGT)) ?s;PaEl۴ہ.3p?vwf>QmӤ>beRba0{ SZg@HL&EO150lK޻*\'7mQ`NޓU+A8=OBxc'לiowpJq@bf>#%S*@7n8k1v53P !j00L]f JW&6bT-D ДH!MSi*<q5SdfUI#S$ թ;ݍ0UĚǤ(Z>5XβQ^ Xe3V#N3tfR@Ik(Zk3qU瑧4M5-S2{3Tm]VinFRUMN&+/-bH}}@/VRLvaY@b J`PLes ={B)`[U2ك5nK]9McDs=ŪZI'D…@]DzF4*ѳ,:̀Ë/?x~9>{yg~;>h>6>ƹU"ݗ/kg[RsI8?ӫ;]?ߜ}?|r=>?O>wÇ>{~qѮ7I_ hp'O~8^_cxԼKIyvB\o|Gv8燻~ok/?:=rȦQ/rdK#;/q%%$cmmQSCGY_R#wGf& E&|.!C)4^yS*V*QgLYI$DevԲ6 %j8\SLͪ4% D)!BB""죛7,rO~{xqS틯okw]6=JhB1̺EpKº%I \6ܭ Wl nin"H֒kSުT t~ [s [(R)Y$D0WW^yz/zե,?G?;G 72+ IDAT᛿{o<|w^>ۍ6J1UVѺq;Wh9Օ/%EMfޒ>Miͻp1/|:S}vȲܛH,d^N2;IW67Kb P5h McmK:3kp[S "DgXbFR6H&QbPn/)HTST8fD ̔ ΜM<ނT2)M?i&4یfז Zjd)$Iw*E5Q s0N22K2z7A3dIq ?vzkzx4eFm).>z_~e~}GS_}rV~۶$ j\V{b~`{[>eUxqx慗X[פmkj/6OvďŇo.N@vvYa˻=Wv5'ݹyXЎKV`u}sN;>[;gl{:|r!uȟ*abU#mR!jA&">3E!l9jף+q"iM&{ND=JG2!!nLhoMR0)5#z[P}MQѨ)H7Ϸ$A*sStit/@% TXYDD_f̈>~/WY^ ^o|h^?G.x'%At|pչFX%{n%3<:3mZ̔RkH4:*ϐ5f q3%4A!T$[xg.j'Q ;>ܾ^ꓧ勹k^}ֺ(ܐC*TEH>И$5bPEq[,VfEEq^\/vRm2Ҫ ai*XNm1Ȧ4Q3!9HȨH--20@65 6wNj̓J$v8{ g޹Z7[A:3uk_4USjh殒Zk=<99>H:5A`hl9L"ے&2=D,=AEo4=*35(*a"9]j >[^Hh*ĆL0hDKg&חՙ)2QX$:CqYeftsk5 s5d]!Y "S 3,{-/jY!`"0@3͔9,-Dٺj!!*Wi״0Fq)}=o 4`nmQ̌SëM̼jO hfd,@scif ף*ejib(#"-&n2Ʀ G*|mRi*aˆmo~C箧r/^Wo,eosɟb{d~p=3\pgΞ#c"H3@2r`>QN㜝zVs`A<?3~DwNx_}}uyJ큏]9_zWV;*p5$Mĕ윹cӼ89X,V9uZ29%t32{us疾Xbrξ5iMTJ lW™-T-#}roiZK3$02@30sDVkj36a I6YR']E$Hwl8[O<J_gO,>w`stn(ZDjffFf7Ox(a*FFq]3{]mIf$*!ӄf 1j@7`^ffF,,W/k:[|p_x_W.}GiDE7ݒFTV@]GR]"C4CBd29U9 GGk*m t֣㨑fl1A*7.jR5bbb+DmnԔj95Fc\;?rϝ?PNޖ"KxSr3Ws6WM_ZI97֬<IC@&q ?vi[NYD6tUOŬ&FQL6@tFuJ$Vsqd&sB0͝FSQyE/̕Ajm3܅Z fҤe6S%p c`qzUa6m1Oj`kug{GoH") 빻WPdaq+ma{>}~!"9@wMLSavT4 ևV#^O~6,O5TB)"yCM"T2N'{Æ xŀA*ĝ5M$TE,IQ1V$1 4%-D-z<"*!p&3BQ||?Zen=a,!Ch_;jMjǁ'R=lEx쁶h}k* ;ť%i"I.<)=ŌL2r񣯞y#7O )9FM^n6orSՋr?DΦ%[HZ3dY -AvRZHha%V0ܕ`K? R-UwdUd+j&'5SNt4m*Kh1zFmŋ ֩ 1.EӋaqRE AgDS-[cd*7V&e6 ?IEQoif>>XfReF)wY'"%Dt14͙M&HTmUIfU@ MH22T jDFSr;2iMᑡ.t\D ww?{۵ӫ/Roыr'{$ On 2GۭU>/?sgZ5-#<kߙ@X<G?3p~>{q}kyP>S?U]yk<׮/n:oj`+ޭ8uS6O;gT;p<ڥ//71+/}_]o580ﺂu%Dk wF ( %frL&qg3Ζ'3$5=s}#rͯW(C{۩oZXZFO z.CaEmZ'piCI5kҘԕl] "ݒF dH./xocҫk~=z~ӣUfmnŜdIU͆|k-7j}w2ooNOdJm\"^=^S)ߜZ/{' r ~[<8oav*Hovʻvw|S'Pgetrj9w'k"#}ȔZXHjIr㈑㛛LQ#cRC68^o`:xD3(RҐtti1& krxѿУ?1nsGwxoh :sv:}z9,;+w?w2b5 00RԋdŇ %k Q(ȃT7)Ԧf[v\nѤ[EdС1k S:VZ6̪;zծ I6w'%YSfYdK0 ͐5 CdLZ%P[6iI6Ȥ֘'<63b\tT7KSeź!$*\Q|0H1 LUlmi}BԹMqM#5x<)T}hBuf#EuIRR{8zSE7 nMuf 5cSQZ M=[ Hf%$D (9+AѠ*)] J*TTt#EАT+/y~<];O_^_Z7ޥOǼܸ;<{mS/Έz8 e{Ν=XݿGks|+wrw/|z|~O7O;~kcԭaJ[jzgpf,XO-}{7M*KNrl|sɼmwWW \>d|Q_h+)g__ ~y`ܩFUN^b[ͺThN1K<מ~ZˣlA3a/* ݗHt&Ca+PUmm ~GX-C%èMȒ5BZ6޻wM` 5U]_a(scݏ=Z'7Odž_9~f\w^ ?0RuY{=3 E3Ք0&V!SW7HH=LQHOO} Pz:o\:_ 2(T˟\^}n8mءq*!Lf!.]';9:@]͒ox*GܙU (!dOM"tVd*XF2yK C0jLfzNAel̜^5Z >sa@5i D{8$":XCZ2bp=?~u5jWg>n^X Lս?8semj/㼖-EU2`Z|B eJqiMJ?臨N* baiCgl'GuoK]2bahwogn_|_<4G@cvTdL빥aS]i{Kw?x;/|o0}#USo;~m.?v𙏽~;ăn.tT h TU$*ab1K20[BĿ+#?q<-JzpqP G$XLFn*C$ˠ@؜>4JKO E5KF+ENfuNs+TDku126- wϬ#ѻ>g_J2@fj7Au} s nN8P/k#vղnNUmSV ݾ*6 ̌)a[_?~WϜz|Z42vXI64%Ԛ :_k8ݺlALtB]79}_8ꡯS[3-WG$Iʖiڞ=صguur1Б-+L>So?n}h]Q2cs@h(uFtlkmM9ɄGFmmE"TȐj _~oo^V+.?K7xsϞ?v{幷_g/^rj|qy[e 邐!m8xHsXTL\2&`l-ӎ3&I9lMuE Gd ekF޽bӑ?yK[{C+f*=HFSՋW}׻$__C  ݘ'3gή;,S_;3T.قJ؄Hx!ۜpib%DPŐ-դcAi)9] Rt3TS\4 I,Kw/e5n_c3>vn}/e~䀢F|i&lu: ̜#ltLAz8`Cy  4IA#LבI[e(tz D?% hnn*Y3]EJWẻ)LN&P7h &Q8dM( 6Zd0+*A9C snM24FKDR$#τ6tmS%E1 [n 2~<}o.ZJDYdXH0QRRh Қj7 "ډ pDlJzZVW֓kq۷d/!=y=^Se~Cݸ˻=2|_ŷ%b૶gvKmqޒ kއ>sԥ_F81#`\᩻JXZ-}L QjZRg$3sfrQEI+ǑZk53#)b]X֙p?v/{tXjq9ٮGza4n[O2JFv3 UD2n=^()ji:n U 21Յ!ho$ 7ASZF2)`n} B#2[~=u5~q؋>+_nh".]t/wL c_oj d*sv/ j-0}O|-\m_ŭC˹QUin"PsUTD<%32u;v='W[q^}?BEc/1{"ЍWcd`Ȇj7QhE dYfY:b!e:O!` k ;g s؅f p:uUބ 6˟߹ w⻿bCEG8Xݽ}Sү?Z囗]sWEE{)l]U11 ѵx^|`(HP5U"rT㠉T9ǰz<{ʼnTAͽ>rYEmRJia U BDEfT-xtG RRMn-`4AXͥB)f*+N2hbhUb&DT)Ȯ_׫mkEIИ-2Z0-ь adH2+*UZ6a-#dh.Is5P*R4CkJi0B rcUaRɅyΑ%n B5Ն9+DUWqLar3dQ[t}KUh:JvUlX'hSTn: ywY HNav_nb.[~8w^}w;yTVGMg)]+=Xw{1,]?]_~#x䊗+|府4g2Gk>51gn--\Erg紝dŗ.}b;q|T]{NS=~U)\<l2$ UcסeKp6udB=nd~[| lh(S,1 )45hC$3( `rg}oz./>׮[ Dj8Zxw59}`RȇOǥKLhITq 2 0$u˚N'359hv? *}> N ^ϠJd)E38uDNOx7 d̗fTu3ō\eS5麗i m8cV37/>w{jK!FPӐ;QM̍^O S%JBESTBdƄ̢0\૕9[eXx)eYJ[k^?8fZ7xfezUL P1!Ԍ͗C=w71"> o'ΞzhvFl~^JKσm_;_'̛o~A4ܝhQ Yʦ^&A Vb-cƒ,5JhPM DdXmZՐ!kH &lK@33H1@ vd[KWYZ HTAeTSZ|A"4Z$bL)#pdɒbuV %ksM/Sk2etehq%[Q3l1Oռ47'`+r-DUG9HZT|ιH-\ Ț["$M`׀cmD4X@UZ3S&'f^– S.V_3& taL!$F^ QJɰ֘tJ8o36Q̙ahfp0l TlM)I%k7<=7ʸ:^ȯ4rr0ߤa޿w!D\O~n}ᗿm;>=vLN[vg^'Cu,>%-U*%2zsazϽ/ Z{Ѝ{/lmm>vtP[n- ^ƭ;~g2#SߩuhYɒ`مITdUui4RwlͮƘs{v`rD(" gyC"!J8"BHl'vvw>Smﵾo÷ܱO9/wZk~s! /#0f0RLmMZ{va낑aՀА&@WNs<8Cr _nGӯn}?ΏH[ޖ.uYWw-?<6A5wo Ƙ:L)⌛"5Wʩ Ws  >uC Gi7^ti]`*k?W-@}?Ǜ>RXJk=JF3cm[ pA%RPtj釟]ɿ'k )SJNF &sSNHz8 ޼u/ NiMޞ<>:9>p_-1m#c6g^N޼5?~yu-R'1{`ftff/\}]ʐD{{8&JGN?sDq谶AIKc,uk#jFxjlQ6_ `R%Ucg- j%a#HzCzi2EfHҼ$3"#KˁvR`p=Spc4FBSN2 <5Y5mܾaɌI~s_zWٴRhJ9~Swz?_{dsx[k{{oOnݞ >Me[+ҿgF}%`'Rz']kI |8?Vl:;:8}=o|;>x1xU=?n(%Z5Cyӧ=^OW?H˫S܀'/܏bURt}P&Jɢ@(^A轙KF^ ј[O;`i52TCʭ$ҁ0AYd,>|7_ɿ3o<-h;׺f:=Z׾rnO/8T}*XU "KXI/p8}Uh Ш̐)c<g_]87 5۟g7~U^go|7W56Rܽ %‡./$e 30ʬ~h,{|٩0+QF{xT CS`FW,ͮmrb\4nIm꫷n:nHC_bw {BK: t7.9**euۧ'orx׷?y7|^1<£?Y aAq uRb>GAek _E;+֡e䉉JM笶yɧǒcU bG%\FXhWTzD¡.K\KĹD6 *sN ].oh<ӔM{ -̭2raь+>!.4֋n)l)ˎsTm// D$(tDؤb0aMwD%Ɉ5*0LȷnO{q{re5폫ٮ5ԪƛO8:~hվ 35wN_yd;z_/a.AiukWGRg>_s?֠^myT.^)?k߻./iޟ 0oƧ|to3qt??۳ӛ>2F䢶 +isHQA0Wj´U ic`"3~LG]0(WFdGJSn5} в;Gɱ`)4U6H^zi2#ɧӓv3ok'Xv([k22M^wm>:}_yWm_- a1f¬S\SV7ѥꂼE 8G`x'db([菽Wڀw})'W݋/F+ZZPcqFERi)X҄ʃ}g8?kłGkjAR:2]AKDxn@Gᵚ&4dʣlJ _;ݹ}6Vju?Z>!fxaDg("zW y~־|vTh}u8|csn|K8,s'|czeCkBPEfvTNq<+ r(ʹ5i<Yq1kz@ GXM̾C҃eufߥ/,lͦii%gE5[v+ݫ@nec;B&0x`'9݊EOpSnI\f ͘Z݉6YnL[d.2,t圻Y8ڸlhR/6v%\,=Ȥ kbksd'C7bGLZo`Tn%#hGve8;5Xmb!3ZO=͐kGD!M*}b5`fVP+zTzv* D& =h]`FX䡁dlҕ,#Nإ[G/|ns'_u+zt6ޖqy#7u31&gWnulcv3un'gesd[̴֛ۣi^|K2w緮tÎOqy+V;W޸x;w铫CrݭsfySy5 k2nܼy\oCz|JCFF 3a@f,=āxk}4fM Ds܌ 蠧p2r$H(2 6M '`g|L?ϝ;eR?>|rݳf݋ a,V&X\.vx%P>Ě;MvAwB*"0v"< ")zf`9Pm 9ur .CBQ( S=n[_jŊøŒa~R"au:M,d}˯|}7nLý(#B;MBnnuB{J6`l(EM9~-G[d/NL7iv;cn 6u-Z?=J_6iq"?]K6XB)J*j ;{1ʸ@H{=qt#K>xSLRҷ]#| Wӿb$G7.b42^+WTOї @C%zfP6Kfdqp#a]C Y/K"sLn!WImY| /0!MqD(̀yMN&4ɠ}A* d \WWVIGveuJr)m.ЫrE46ZwrS \%eHdbϠ4kk2y,K-y}}̎u]J;AaR ΒeLd iiFG١Bq;P2 H"=Burp3;, c JEp 0N0br_ 'TI)(-C`!K$ɤslP#!Kth9- ~꽇uxz~ٞ>X珏k|.'OsA =zx5 IDATTR7Fv~:?Z6[jz]c$svԹ?iw}':fXs9M<_vOֶ,^ɵZ?Gm[]-? K;GVȏgК,ybvqQ9it+ĀXp$Ćt̠0 MH@!` 2B!UFRR#4%c,7H@D[۽;#=9d4!) e4<ЊP+H+aNU8Ռ](PObh2 H&҈"Շ8ʇ&] J "vmeDn/i\om9ӯaWZs6 HCFA&Pa>3 HϷyfF|77ޯ9J)}r!&a&hCFN-MR{GNˌUrLKuǶY*ef99S.BS=t0.1P1maID15&jn#4(nHgnպMRȝmٷ{d7  dP'2hc,]r84[Y3etA3әqs`:Y$DI"%Y]J, 23]i@kd;>}F@!M(d?|Uԓ1 [dz& P`V1no>1'0g^}Qn'woZ<ۗϮ;Jyz|~w U=}&"Ѝ+ٝg8J-ٕlg>8óˇy.X=? Gi߸߽kyG&eulo7_{7o=zp˞,Y״./R*lYK-^#RLT2Ҽضols2M|6O]¼Dy\sN®טot<%_z~yy}@Nd_SlgEW׻ooK?vtt @3;}pt 9k8μ[޿||嗨~+ Hz_ZY𶪸Vz53Kw^,V(OS@%BuZ po@:#iBj ,;h:.GXW $7diHRĶ7@AG-,9?vC5KYNew Pe{S3{&L'2Ae̫YBB9bֳMZyLxJkKnHDfWA)uк a5:,Z: +<54d1FE8 (,#1X0ލMFiٍ# L@ρֆayLVpCE dF{FuNS3$ǒhL{jg4 P$uY}v{vy)x{~;n闿ѓwޫh7r {v۟ܛ7^ĽW^y([F(j['ݣ˫/Wާ~+?[UuQ,[x~́WN7 d݋F!'Gw\O~<9)'yxtD/˦dz;:ur.x2ˢu4}\!%I?u! Hf%"%2SY=O NTюlFP-Pd"jz^J "Av W*NodG{~ޟySXI!(1́N+Ѧ-+فJcZt-넔R] GJ!` @óo,bXJX;W_JK:ŦViNCT HR?A fF z2G@PߺCDuk'('F9݌n^-MF31>,$ݜ2dG֪zcs|-y )3jYk"=)Y¢G=~zїpC3p]6ĔjCdǒ6w DNʬ! 1p8#O 9Y/:Ug5ZֲI2rU u>jpK,EEnn6 U6KN5ܸ#*Y F&ԚD*sE'E]i,pC-aJcR@ѽz^q < :%/FAF "f+"B]{ߔ*[d!X$ӔI%|@@3rbt\{)L"ĭwk_;x+Kv{^.N׳r|ǣ'?u_1xhԣ-'Swnݻe+\}Q]|w/o~n;(o'_~z /_y^I|{7/ŵמ]\4/'h>̶$av>eH]/U:ۍ &=~~?./2>&='~tye Jy'F/0{.K͙]nV<_%w)( 6$tsf 4ҰǧށO#wV0i Hҍ=Wj[~Z&l+"@nbQ,KvR4zt] Hc0@bR}9*#2^JKE͓?{6Y)f8*PH&A 8yPtY7H26m,OC+r}O<%IwL56[rdwgJdB"a@3hiز,omE}6MPdeYίNnasg'狿Kޝ˿͇Ot:]/c|ʫk_o/ݽ_[>y~S-wxŃwUoZE+sqEfdsѦ=yk4?/8$OoO~ɇcʌ>Ȥ.eiE>)q"eiE)fT+q㦔f`Xg1Ũ9,$ h*E@Owd,tֻD&3es/IT Ȑa,/ΦXhR!jfy.-% nmNFDq)2YF S6w(iԡ{@K@pc1HV^G?}e`;? K-&Ⰱa-bvh IPѕϏ>y8ԞMgn^~ܼ-P4kїO/9JO/_LB)z0o܋i]%ARk|cDTx,}^N2&FU¤d[WzaOcm ztZD _Pq/``F5C1KsX#U٠`f*hړkTX@8arO7N#"SiJ}Z>Bڐt|A3!ÐJscԚ3`LJݠŬ7UN`VYl'0el,h4fK2bml's0rO65ϛ5F,ߤ̖N0.-@UH)E`:{QC]eÖbvbtȥ GZD-KXFà )= RRAD9p^@UXF_0g*MP6y#[M8x RDGGA׿mvW=ົ#/戸ڙoo|SG7iy>o|/\{c*e=!uY~9O*\g?yrc7;&)uǻ͠Wo߾Sn>z3uvmP-X3br)2a*~> }_OәII@01݊EJ[n<RTۋzG{̌L=EyJ4P!iH8 C3"=@|53 B0Q[LS@/̩PҍZ;3D7F\ ా^Ha8Q*W!(VagFZpɅTJL!XV|J{A1_ nVkq3w>V.p<70T͟z_lﮓ_=KA"[)Kb5C6/%goWR^H4&ҹr i2!z岙ϵ߱xXhKB" jB/- ͢[tXi֫̒RV:m4'CR<sa-z05yXTf<FsC}H8 8EI +(k$+O*B"RD)nJH+t1$h&IXZf{R4֙}ܳ[{dN&Y\ /:K2P LV9`nf133A[;Hケ$3eiX1fgFp&?H6ɤH. &YtKxrVʄOrWײL4g.݆_|T 1t4 kHZ"ERtٙr/l" f+I)С)LdO0&SR{D \SJH]r(:|8e@d8S# 3n^L7n>{s|~suz[Onڎ<_DN|{`3Τ;^󓫯;WODytگg'VW֣}DYܯڣg 0"7^)/׎wȧts_]"R"vKscܝ.fW}ޯ sbcZʱ|^|m+c|tt5./w>A-( !V %xYdЕ}Kid)ZD6HǓNx뀏Mf&#"%QS*liͫR*9:?JKAnr lD;jvuY6^7`qEujvdFWQ盇JBʈQpm6:,#an/j#=Tɏ8ާǷZ}"s͊[a" |eVC@S& |}bv^{ǵہ:L ?ڍ݋gJ>8YVŇ7i5D{L.q]@(RjSZ7e`!*;ޢwڳGjRVe&Jc|\4zwR[Me#|ѷ_l:C!_^2P#^[a'#AhX2oDfHu\,us2h%3Q#d+ CZ!Y2Q]u%z 뺸SaY YjB'*mMs$Zf VEzH@XZT4$V,TW)[f9fh ;cȵ*)/pWȝfWvZ{眈;9TfMQnvdIYЖ fz4` ?0 [KO]^8z~7޺WӃGXRle͜Q ~e;s㽷(Fl> "r`UU{Gkڞ ~كGKh sd/\Mj}q=, #MX Ҕ^ZU#:7{hAG'w>ZDsGFC&;k ܳ8CfmMzD?IP`f*J`Ne b66e?|Q"A5I*XOe17$ &VjFJ $Q'!$$ȈfdCsJ_wrJ{i LLEd 9J3Zq(yDRDl-~Qە~{8Ĝ=v^ź"mU kI65>/vX-fZj1ь) M!๚DZ8)(,ѕ+kq,g#%+:J-Τ dF2QPMHd)ĒO(.R&HGSo;"WQ ZNqPk>1T#J?`m,F%N. 3XtnO3DsPr1 }Ǜk{w˗#ώes;gvQ@S.۫zrkv~zGԺzn\v_|xݹۏ~W>o_xO^^W|y۷=_?+Σfai)qk^:ݲgO>? JsTOk9g+®H%Ki Aa=;3 %;w& !3Hein" 楷 Rpw& h!S??x+0.39Pq-ZhM᫉H'3U, 0uH9#gKL)LNF_VI"P29_ܻs:ev/in\\HV· WB9Љ0{Q}*I1]^`4fL_rF/RƙDKYۉBK̙fjFѫ5J"-*N1̅Dy(nrޚH6Xzw}IȐ*Ґp0q$<ʺNT\*zrl)?滃}+[)E$3Y)vҵ5=,)dZz`2(4EhZ ت*݊DiJE@*c(9Y eeCŶЗ5;zN)%4/hlfbu/oeuRXml9PT kmV&52%օr>rh@zYZk˖OR&2= 6,PXG|Xjd0~ɓYgJemHΒdH0XoMm ,nl!v%V"5PKTD{32*XpS)h%%KP4e VCd/ds@L-4hy5D/ާb܉$LWJ>2~8]ц/]w9-#w>(6v#񕃧?[tsxtx֍ڞzɳ_@փvŝo/^#/_Ͳӳko<%|_/߶wN'NKGݯֺֽoq: {Wys^2Z#mo sSz/Om[_ލi ;x~Ejt|t≣mCF%( bʰPm](Fu)s o:`fn&/CE&78K)SJ(n]gr"&ff]¼12 UJjףTC:<;DD;I쫥>HIYh8W~XǢ'nnRkB/2XS4 f*FF/2Ӹ[%A4cd(xkeՆW6%vEK9xgB1+2AHq}o:f;ƿ7tpZ%f%jfp2N>wt{2{lD݉M@-kc^@*kn-.H@m9{d$Q(J-MEWƌtiB%Yg4 ;ol6r*[7}}⼔: y 1t{ wKFui 5zJ+1 '0s Se!B.MLQjd0TՋg6_ Pg\x)Vk+6*v^|D%|CV!uifUCAkGafw~X ˌulڜ>BnGC9V|]6Y`YXF`B"90HPeii6VXlԺj0bKaLD_؎Լ(e 0;؈]h 0 Ksdr@Pt2Ef?Gu+M-7_Q$ziȔёظ yQELI7`2fi!R޴[PI^&1 hv|'?+^{7n;޺s`qmY7j|)ϯ}|[O?=Nk 2 ׮߿'mE$羽yY"ӥ\T_]_/t_M{`g;ܮV|*76 e01?˵׮>]K6/>?___ si5`7qE:HM-FEV 'ǘI_~Wt3d̀/v*ãwuҾo۟KJ6%v*RBz'N#ri9$"=8 $!ZW$!( C mvY ɊL44ˆqOץ nR`+Y@a3 [h(Pz|w7G>3-j(|'޺vӹ_#0Qٕ+MOexxQ뤏D8ֆB(kXCQ@7fh iU V RBM(Hi=3f3QC11hnRt$5s~eհa/8h>}n~ns37,b_[|䩢XEy9jۤ\go8WD%NѶ_Ƨ=x\[|گpesaSX7ڕa^ۭMC=rk6~s`50=VêƆVZt"" 1#dtDHfĮBF\JTZ뜍ڍS38"ӌj(LEBB`#rK3ՔK968"~؇ ʽ\T0 5ŋ;_Jӕ u]޶ۇJj?Fe^oޛn,v)tqW$);/onOshKDu"oDŽ#B׍oEQM#vd{(dS=4u Y؁y2n EL eȼAl;={/o%ͽ;%w6]wuh`B>|{߭;z*`b8MB3!Ҫ$K'hMI1 SD/J?_$4fF- D]bXE%Edu!8zj2nxVԨ1)L(feЇdhhfDm܋B-&hT{TfKy3X-j%%$h(+C4"%\ TPLp`W^ll.e1X K[Hc=L+H&JO1D\Sc/~5P0sfS(ЖB—Wb1e7>o#XWN;?jB6-4gӓy_NGN3I7Gf֙GG)B6*"siq6Smn3?8~t╫_ɟWc-dP`:oe 73. KD79\.42IDa0n(;=J R!%T `f=ZJ-KL/v`J)Yw=Uԛd T7 ?/4d^/C)ťґ,7W0A*BU4Jki vCLZ4=1w'Y0R7kyMN/`L^z-Dl:ikf{o W>h("NI}e4.'KD\2r!2{{ABEURu#d@ 43 ^@!週IFd dafe%ibl&Mbo7hw[}>ѝnkvE_-_{[lSF^o|ݷp@׮{ "nEPų13e4\n Zrm&D"܄%(D\DZ;j4Q^Ds haF8c̀FC㤽 )feSg*s[Ma6쉺lܦ#I˙ZͥY?HNwݐqMʴZMӪF^,zm٢4&E 0)gK"e\̢T iS۲#4L3@(( `$Wk҇GAhYrV/!ȹXbNڐ3+j&ܛUeqC҄ g4Etu8(hi<>~~7xݓr],N|눊?k~[C^ͧF P߳]ð_v?k% 6>];SsrO<:]:SWyw{4px= eksĴ9;_=y̲l㼷դçnXzg^}ӷԯ];/_՛+c:{%Wqx*̃kgb1d-o<.ճ3,uXPW_w?W~M6qN>1"Dv&A9v௖Ս"Rr3DLV͇lMȃ٩`%;t$"B!2&IʔM1J);٬ s d?~}, Qs]s\+|c :ZV;?/ 3%v\o@WTT.X@ xIYC[Ցv){dUݰM;. |O=ro:;mD%☂zxIO4T-% 13-(U`-a K^ ѢkN3[op>Y2zH V4Kɞ.\!"HkKEcze 8s-ffZԔi>B '4Z/r4imnry[09eeeearKI$PC^iNs̔^K!f%œpcY&U%"H"i13KX2Id#958/0hQ(/.d1Ұa,La2dyN t*7e> /ch|to{nb99>0LGu^qul ȖWʭi5ErM[ٯoQ.G{g/~\Ƿ"dMӍo|ݟM~gexәff {OzwO=ά>p6ڣo-]Ƙ뛋]<>>|_[?={cݮ^/WQejJkO>W7=m^><{;qf&Ͳ%ͨz^_ٿoOSphfʝih١ޔRZ_l)`L@t;VܣӋC1ler`˺Z@f4d0/8|t[׿ϼ]҃fWc $2ϝƭ].R֝7g4oN_rWֺ` J`8:Pjb:[sH|Z3έ夌j5DƁ\&q5-KkXdFs6 h 0 fs3HeLCd u 4GQKe= :Ѧ(K˒Y l:Ʊ. &Ls 93K*5 2k(ŢR͈9EޘV{EłfJ }3-8*^ش3E"1 *fl[ b&.) fB@k%}]5L)ei5*EfTܗzZeb0vK5U)aM(ɢB-T .8F9[Gj^r_}o^O2 Z*}GӡD|~o|is|[? D eq;ztw^3Z'r<}G^ዏF󋓻 MbXRwq:\Rck}A IDAT7ô:rY߿ۯ|w70sÛ^CǾїt7o=#&?ڛʸ^!C˖Hshi.fnTT dNKTsXDD3눏0󝭿Uf,$Mx;/h.Fd璴_Oa^#(`fk˭Fx7/_v=}3|ώնw_?t~ϳjl9 a6>֍3@h}4յ`qiF;$"xRmR:<_S43j6ꫫ't['zQ:!ܽ>!U%tx @@/0l(tn^ʂpc ˖H(-/b|4=~|_d>4'n:v]ڍ}hL~@ _yϼ){o~9o^rX镢J,!j"UA4)@K@TF[FTCY&)TYJI D]84YeJfI3 ͇ uFZRD@=4x2ֲUS &&jmiZQCN&h{*@bVJKzmZ9GS4pBέ"SR #2H馊zz%}RTKHhĶ-24w0}+=b`JJ)T=cK&iDTf;@L$rSOv6uŏMhjEMx) ј \q`E5(JeXg)wzni,3IH˄!n BN;pZ9 Xm8_}p~~b~1>u`nrK"3̷^oN/BnqX_?:x{}|ʏl!y==͹|w4Nwu>#F,U(}Te(|66N~6N_|O.}M룍rO~}_{_{W~h ^nmooz]É0g3VXoC̜-I.E$3tXof8fF_scK;Ie,[`:@2ٿÏ,z&qt]tC/~jFyd;uEOWɻ4 JR&ki%wsA!\jg}eKŮŧu%+M~N ܭaٷdw U8^nL4Nv|.'<ubal/+^RחMߛ6f)/{tڕ-+lP[HD+ `&֫cI>i=-B-ﭏɩ9^[m]vy)yU=:?s},gLx[%=.x{ڿ|>(ý@ Re $Ss958YLlܔ2f~,jhd3G樚>`V͈2pa(E`E :PkGeҐ"H"bLh֊Qm 2rYȁ^VR eϸIF2[UY0"; d%E| 1DVYJ<^Z:1 WO϶0a h" PdeRxkME^! A/̆T!в7=CH"8](JX#@QM1y% VȬnlxɴ"* ͜SnD]S4 p ]aHW֍ele+;CʩeYqX=xsD;gl5;vb;?I'WW{߹8O~4Lev\{僅оsw_{ܐ-!2k}txGW$eWC޽ۍM7u8mKlY`pdgtӃl9o juŻg'W>hӿp׿7iXxxq.f3KLN:,ݟhVE(k-t%w֡fч}a #H%X Rf9|/Є˳T~lǞ]]bO$}a}1;/ONK3ϼ/y}mjsG$BϿKPrP/<ݽ?᢬4 3ǁbqXSiiM92q(͹FZ*Hd8̛ؑmC+@B-+%Zj'\CqK1a4pQF2 ӔW{D 3A͌KKR,HiA[rBVCܛ\z}v?syeVr;%R6["KñځQ# :iTpѠ(HZAҦu\vܤDNb[lٲ6S( 9ng{?R$--Grf9׹ f1%q7Dы6cIHEEEĐR,";(5"b˩- #>4;L}D.„HF@e4/=$H2;lK aAF$EHjaё={F)݁Y.X ̖짷Yn/dm]M6w?w \rR5w!g(m /3qFmiO18O.tkŕE,NFcY\Xp=JeR4ydeϻitxO;ԕѯտS0 p|pRɭI7kyxzI*PU.n j *(*rFɣBpb.\pٽX2/U\M<Ƈt0 .k7 Jه{Xxi>]o:$ $`:>Du;kM#m#NE!!VjU Y}EE @B WJ8b)+* de.UID0>t;7*qk]{L $i? TZtą[!1 igP-r^ŏ ؈X4j8ZJ ;=DDJ %H D]6 )0sGLGkqbs+OeI|D!axgNF'kGt>WGic1ؘn$OEz"z㵫;.]:r{l- !$ ULhE#ĕݩx h8S/e1p_bx ürΌAJŃIU#Bڈ gj$C&&68LŬ8TEBXI%$P$B\b(jI6I4Y1"oY80N#{)bm(&S"/,(J#H8{AYH6n>%{?`>dxt?aA 'z:A!QZx&nTWPHHL3̀>+5"dǐLF IB쫡b)ÝbphW)0Р %QL4E G4R TrSc\QPpeyR KǞzkK H7pG7acN/=gL6%f6޺{ =~<6Pg3w TEK$[b(%m'<#|:l׶7^b>܌.vfmDck(sPy|­.<4\/~wDYHK7~b?nte^?s'߶9/m>K{)VޱBE)@FNd9C%8ؘTsC*,5x:e%pV-pL aw;x0ӄ }T\Onⵓ7m^_Hg|[YjjGjS`.&6dg#G$e%p)u7 FbgbYXj(*%B(}1rZ+b(N'6 r57ٝ!r?I(y%>׮^Y,J3-\^_?_3yA"JQXt%K̎q=LNneg.MO Oƶ3<'c㻳;kX<&:iz"џC`:vCeα֖M黗N soMgSMQSx죈ޤ e %TEbE'0XO @`&n8@h׻#--1oD*b*woL݀)GweZSˏΞ}yյ[D<:[Uk8w3)MK'UaN:RBf"iKNVp CA!fq3IY n!p8 "P(i8N 2mX䔑,yR%$%5Mcc2I4%v$42ne)`~V,‹Ŕ^6e-PTsjM)ԨK_l2[Ol<LgD}5&MCAOJBq@"L*bGx*WB"+2p1isD$0uHT@uS#Ts9 Wf :BJpo֠1!Ve< Ijۆz ڥ @l=`;V%*UT/~3;kono=ݞlٝf=;w_]܁ћL./=vc]!3h19ʙs~I<ʽioUUދ >:}JEfS YR*0Ԉ5)NB-Y$u `FOˁ:oIpVS0ǩ]W Cz f;(@2TP$b-R7YdIЁͳp׋)D9LR\R5G!(6!)[8qvrr%Q 3\B!$Eh`Rq.T SGN΢6߂dDJZ8ń3X9垘̝CH(MJ z(. F=$ ׷X ML<$MU>%!m!R!19G筗o}]7{s~H/gTKBM5;\,z&o~ִnM/\<9Bk&}GBÓʙ)C dzh䣏}#||v0DYT'rʳyq/K j~^ѻosN83b'x}s,<SȤϞdԥF7vԈ"RŠ,&i5 R2AR+UHLq[I&/ )Vo NϽI ,B捔oyx0 |7]>Jx[[68l+0VշD= ɹgaK!V)Km JxB1|W*ԋnhR*D+6۪әDL h7ZL+~MUPaDwO\Va9e0Ƿ_#%bj`{ȚUBR b^\j:0)P4@B<' MYJ^@!g0X@Pn#K*Ofaa4F_OޣwoX1˰}_N?=f.^!ʯ{V00;5ShͦWt#1jfgw/DD9Q IDATX0g5%3f6N*'2X#T29Q"-@P ( H\!0ȃ"Rƒ&aS3|>`m6FvvkLP)d+8];mϴ}{}/~{b~a4۰njJgla`pEV`}g"&rf$U[!N+SPɵ8OPeÂP <ʗNbOs}jȞ]@fZ +!jf_çz;ZΒOLqM !(@q Q YEC)4Uu *:ٜVSNB@ýB縚U2TD*Yo\^t/ AA&¼Y/ixqpaT|m]Ԙ$ȟ8^DjUD`yUbaӆyJ Og5RQt /^yCєekydWI$R̤q ؼwt},6g^O8`eQǼ=t>ć~ޙ˻dyJ7nܸw_4bC&5f(Žr^CGiĬ)19QQC20 ×%[&4`M#*xύRt&Zs"`6x0g&V9\88xpD*9{&H%Hb"Dmv'ma ~3$Wj8Yi%5B0a":%K^h\b 쥞x%(<`1xq@>PԗejHvҰgbK"Jc$,Bڒ& f(:ER)N q+k)Iƒdv3)FXMQRYQRUf{1✅@*- )t 7*q`P4l*R&b£#X&"|uQN!H,ndILdQr ^ʲҨmDc ã%YFrqt#L NwK衇?ݟ3]q#yߓ<{n\9w'/OnǺOXenǮ8CR_݉0y=A%~-#U*8DPS)qm߶Vђ-~~Ә~c ' DDyYoI /ޫa7d ^dx֎׻Ѩ55U] f%;@Uɩ􃊆«?#8EfhDJ̱݃Oy`*gQ.(P9 .Mu@+geVe ?4$ f·7/yg>5pI@h!gYwѡ!P}V?`4_ٿO &VR3($TpQ=WOHI sZ%MAxݫw U);[ݽTŹ}ŚehH@)  %w5u_RQarb:AA" aFf©)( r3 h 1 ȕ(&L, \LdYsHY9"iF!qhOҘ)u6"i w/$2 iqG Pܡ.Ίh!p Ų aw%qKVtSDHjK(M5ͬ ^, 9KA=-P);7QBMmNhr C@7wfC8X% Ƀ5SX!EvVbE&v2ʌjb&R*=' DTCDAĦXI\'t!]u7%&bQl1'~|םm:t呿6#px8#p<ڃAы=JX+X7Y0UKDe>(O=ȃ0+{7\!hf@OO&dfҶI[mZ~/m/(fZccǑsYȉVW "Xbz)JJs`Bx4Xf;'Curcqc0^8zR J]{}aT"Ε>{`:Pϳ;<&*[nmvMxmZS$Ju&4V HJ1rBQA"^#'kZ;$0%VA"jrjz2f^%M`s݌O'?D S@Tg['1E/7/=Su#!Z! L3אIŸA$?~3,˓ÎF" UQ `a'c'0@-"DL&*Uk髨Ta&ShJZ%B! mbھ|OӮЩQO_ś2vւ?\˲?x?Doֹ.O|y?]RpqPFmc2Z76x#TգWgCh"(0=;>u\;ƃho [Ņ!A8K!![#!3 H!S 0|t} S$J}9@E`A.쵞ĪK,4408 1G]8UѨƄH͒2EޓJ[ta yp dQ+VuƉ=*d!; %w&gb7 f!uzg1̎} 74'7( >@|kBXh_OϘ=dbQ~~g UU8L13 1KOaRcԴvM۵MGk5 P-(g" Ă!8AjkꇃUA VN!%XW,: ֡tjT7 E@I2=哳zNDU9H<65 ^>} _޽޺Cӭ|p;J@84r0Z#cUgawg\և#W/Ku U136SXVp/a_ca` 3.^J-ф08¥dw?ۨh:"G)7pskwF9.ICü̧Nٵ_}c>w+/''ii{kmocɹ{Q)/ܙ}{MkֶB߇{ξ-f^qgҹ>x_ezࠔ&LDm(Y1%)!$ܢ!AE!"0 ԓaj/Ї(P>]™'j-Y< l6@:rQԛ(̙@.*#Dlv"&:ۑ%I)ឱ\.sJbn $2R¢<0E Qҏ[L$(,N"Ǩ˔P2) pS0McN+$šz_rŢs  tdY,5lo|В-_r!z=|79ߙ׼) {cwz_N0@f) w gcVUY! EJ(yE'>m6pRTpjZ}6'v[δY7p"'kB`fNMu_;/dnkCgǣ"("@9${ğuىSX{ׯ͛]ĉH IǓ~y4ڊKΒW@MWvg /`_i~b_q}!}`/߷nw%M\TaQ?ȵkՓ\ WzwᵯnL֛f$o\{bt+S^?1m^nﭝo/}S/~ 0WX,! PCBHM ԘZ,Bm%26,F<J"B^tqjČ(EhP R*IZ5u`d9 j{ EHa$ ŗ=國yv}<x""`c"8BR\22LCH$JmĄ,`&( YU[q H LL $rZ4!#N{G?\ӦWo?ݛTO'>p D(;%H$&8 ybBM^Ւ2'ZFRvF"@TI5> px(KbKdc.IAIrDCa/l|6o 4z3ǯNv~pC'|o>-1IGR7QmWxs{sw}zfxz<_NIR{:Dc~ѝkk|xrƲ&6voru}#sTQjdʢwSuw|G>WƧ9^oh֌GbE6{PhR2jĂ8DYee'u?N+E ' >ܘKV U'#QU$B\YBJ w 1ԏ^ýaӳ:y+gtˣؒ$ ^/sDitX@յNUQRh )jDVLT& v򂢋N'Ĺ8Q0A-4,! kEh-ݮL,o8;N}LDxOǒ# A@PH5PWk0~swz=5Khg7TTw -%CiSW/^+?W^행HDLDܔERH(EY5UAQHɥȩЪRSC" 1"bN!a4@1 Æ!dg߷} Zr7ϼ{ΎF:Rי Vĩn&;g%Drj#k#dmdrDCΟvhcOwh2i]ʝNE&6Ffcz_/}G=V lMcYEIIP6$$DTH<@<F Q!j("n6&F2 ijPeg'1'֢DJZۄR\T!m]X٘9I`I$ز:>}SmVV " "#@ TP-M4=a#O*¦CaO(JH  Uj*̗9{@9ĊFJ4{qgMJQ>H;qn 'r2dOd?ߩDc(e+>y,7~#=e>ϢhFrv/s7c/~« )$7dzOzcٛ[n|p'٫WT{o!'﾿ Θej#>: aDNk˯hɶiu:yX͕t?J\=z^~G£,k<ԕ|ouhQcT ` 1l$37DDHAa<-Uu.Vd]d P{~>kҔ%u*F'o|y#Sh]ҝ-TT i]" V!"YTN#"i՛jQ"PfFR(nJ$`Tc;[yCCN k1`+$Wk݉6N2 tkx@Dś'9^?9m{g=L]|zӿ{WoV<&IP؟.~`RH s UPT WD#Dm.DB)$L dMYnT־ ( FaUC^ v.S:O.w^=ӟɒٲg IDAT^&j1<#yul&o~yg.ŗ˭-!uzls#"ݽ"1w\+~iA_&Ng477~g!m=RݨRk %Q,D"vT$W!͂ IA=,p¨ LepDwXEPM3ƨK <ԇq҉D(C'*KDn!pTݢ  VJZu3Z`!!y:*J2wq\EVȜP5 *e}Ye7GjpwG9f1 llPC$ %p/ f50M-#.S/\|qo~w~'.|9}΍٧~?d?Kgs\Oܪ.(9˨2Â(dŅ Mc/(E{)-nlmv>;B yVTe ж ;n|ŗ~і?nyN'S3j*>Xw+ml!% D?9Wwҿ`Q$?3=waMjaeG}d,%0];8.wog^Bdi,WP=dG?8899]+H5{8_$6j9s¿ /|p|n_;{ dѯV3`l98wfy~&[./%^~۷wrd&5jY{[DDdIt1 T3R\(XW#?15xot|#/oLw'n2n Axm "|8# JkzXkʌu^kL~}Sr+TAGhJr@kcD;C) p dT1u .f֒9"TGD,%1s.I",NY{IqdyeHzV-uP5 --$3|pᄡ.~܉moLa§VOmMM7v.n/޾9(H!%"h/Q@ڒ%)[t]ά^:qah@a+kLqJRMfUT&5n{ys?2̑\|roO+$̓Ob~b5Za+ݜowg^|IG \YBRu;^tQ7w$iZѕj4 H,.#@m=0H9jFg>s<[q٤L|i{sڟw_褚-ŭL8l^b!'4AGz&at *h.h1S{^D4J=jx)ҫ ܭ LN-VOŻo,;7?0^>&y~0<X+|.}tۖkgbڥE͚767/]8o |i@_շ_qg;w]Kfn.Oz~o;嘾H{wxk<8^a<!b:r8RhpcANDZ_jǸkjDڬ[3O/dx; 46~g;;oݸבZ$֙DՌ"BUɶ >BaS(̬j?*H Lptnuzv)%\@SvS=xNZRS=XMᏽ8-c2!h95:fsJHpJҪ4SxFKo|PԔFZ;-CczUQ`,t7U i۠Ckd"f$n( ZY3upѕ/o=E؎bY>'^C?ʷf|[y6M{_&3RgS}OܙBUA2hUUINiSge8r&94AS"$F%mD$$ {$ꌀ = ;VK[/ xuSO= E+86Ue})m_Xٟ#վڋ>s-< O~ycs?;b2fKewDL(sO EZw8k s(e x_xn 5R0;p#! j'o|/{xj=]?b1Q:Vp8\,SI,f~:sʯPeMt+~˟zPom}՟yʖl]picysX6[ܻ'TD‘,aX hE)c2OA늶G1#S-$^Ahп d]֪ebd^{d'CD2P4DjDCܤ0ȩl:Uģ+2H+Ф %! @h&ɭ$AHF3Ҷ܉FTF0RLhD{Mx_4ƧV//g?-R;D<"DzA%py_|vfUfϏ3W<MoMo'Kul QDN$BW%% QG( tPtwrm06#^ET$IT:RA!4d:,YZtr~g7DJNy~y,حԮbtD$G>rw8ܽ(6\>|ۛg:7B-3_bǽL=}=zfģ8n{gw{ h ؈C 5:!#+0dL"DRc -Ri C;B#8t).E]l7c k8fϭ0g아EǤ&Ȍ:ejHa076FG5rjv0WX=::[BwA9HY*B:pjJXsM}WrOF J(p8C2REFZJQIaubq8|uovmg$'gwξ>xɛw/]dQW/ssR;g/NZS PvVF0GZ; tpt*1(-U F՟ySO?{7n!8>''gyp|F9|ٗISW{tȭ .ֱ~&OY^{g\9"/GS8s޹57LJIwvVWH70i3إpG%Isg\GlUԿ<,m0<5O^~g_}>߼uttf#j!2%r0jX̙*&80ll[;fڝJ e"SZ @ιT)ްYdۙ4GxkBt=0S 4&UNFX:<jNZ W04뺧^s*tϡHq|C#"<;svԳ7}SX'ۛauPj)5n҈B)e+U{E[y&{`\SMcĔ̀feeS(pWB4RXఒZ;FI|6Lh3 #1UӪi-2բe D!je^`RՊ! .*BXȩӎ$:aR@+XCRFN%$$a.S`Wye3aJpҴ@+ũ6ieLV(~x@YGC]']__4ݟ7Wv{nN^eVז5@tY3@&j]N1lA%JV(I(>xi/T˙*2:Ij%"Q!P g/vK/jậym|;}ٽ&GX8Vxݿx=GH~wrsu|~ vo렺:>0tonl. tCdVPlLlfOKH)M76r#tw}_lKgҪV:0bN T3 -dj SN\4[wOREhպZ `4/}?jNrݿpJbnb) ٣y 6a)em"RMUNJм)+LD$h+&뫸%"-%@#Z%r+%) dnjD'i0#C{yް 6Svxl~o/FۑK !" TP3yk,qHw](BjͱDP<܈uLY]OIkpQi;0!{A(h"V **fͽxjce\ZO6Rd>I=nn1<{{4#D "YZ$ DT$(Dh5 n)͘5Ìd@:t mN$+D5W(! ]?wJigaG3L~o;2F#7(H?|e2=S/~ Ì=dR4e&/>|V9zeXCCA7k} { CR57^-?u.u]שtE2)Qq4@GKp'+9`E0/*Bf:H _[a=,LnDZQk j]c>uWYE8I06#h'![Q[tKק'8ܰk!~d:]܀Vx6k": [Sĺk7 MȂ ( e*n!"`4FM#t. IkZpsmy:E &^C؋!,"6E H*mBbTcLt#ݞ Ot=rm]%|dǝd' Oqųgwr8ˆ$@u1=CsjIȔU3xuHhn@'A+4`{꺉w?>Us{Dx:HrwDgsP Cap4{fSq :NNRD"܍l LAG[1(-rNMD: !d=+!>s%N5FD{A{ը# u/ pP!Qց֐HqC3  퓢@?cB 7rh.hu5D=D0>m8pnԼlQT[ P#LԠITnOǧ7+,dSHBj(f^K'Np:"ױ/ձ:06E:XPAZ}Eɤ s֔$Ikc ]V]yJ*N=hBGLIIBCq~o?{&{{ss w~:j]q$9ů'/]sX k@ +ӬT"zXeʄ#4I hWځ@er2c FEJqSWti2M}S?/ݷPoጀ09 -`8AzFTaKBGx۟oNRj"{ҷ5XZ l6mLǐ5(+%40y`V1PQ132tWݮoY7n`Оiԣu˲ՙ bwֻXu P" iuY 91c٩8ǿ3Q>Ў"XCpd@P_xd*y%i.LFБaBD'IEc2rlTShL ld-LvĈ{`{H(:( 2/ $fSU $&F(!0hI%%U&fI"tNiUsJL@!6UV I4gcNjAFb2B5"c z T5,P5HaQ K^Z]==* 73 燴~pG;,ڽFs#im `wp~kDH=$heQIٱR@)09N(f"]r, 1)h.?0nLJЙD#[ܾ{NvFk߿s?ZQq2y'Ϝ/۷&Hf!=ѾgWWv!!`n D0&K7_|7zO=$x:Ӂg;ۛ{'O1FSQ(SIR7Ml{{ow^֣A]މfE Hрةh-Wa/jX5Lގx 9& _k/BxFAyŸ473ss+ٰcfYKMӤ$1FU߫L]T+P\> v" '>"oܽWvdc,24.0%B 5q$\4:f&FR=Mj~7MF(vJQ7;3DA򝕹voӶp| &KFRb0UPT "*tnlI~-p)]&dИAS"҄gIH]ּ%D͙hlHL`$`& HI48%$"LjaJhR7{) ۊ0;fBh )t/Rc3СCEe $^Ihb9JfRrQ5Cq M`NXD[` !P9!Wʌ`&GBh2PE@Q(KO K9Q4 Z Qj9IUJ Yc@б6LAJ_nBDA2F)M #kR <=XԙDGfd̦*jѨdv!BL^}:[bI:báx7Hv-մz/~ٟ9}jfӳk/ׁ'HT3E Yo5 SS EMw+}i] xdTH  Ĉ Ũ"%!4TS5FKdQ3z1盘sRQ0bDD>G0 w  #`3o j} F$"1բBHkJ(JQ-Ub TUTPE :5{҆ 0I ^H&$`sq+ƍ*gώ)JHr"$SGNHf倆K3լ.,/ڽÃf cXq0rR@EzVr;/s>/PI y`QB$tlu-,)s2 ,:S#d{K@' @R3V2"dҘy!#"5%5fPݙj'bN{nC GC 9t8 s")kLAS5,dbYb1sR@DK65AeF*ʙ o^}X qfAsU҇~5 [\->ĩv?\}Y/7zcL$539Ff hTp⽂0CMS6g". GMf”;aleix{O>W%Vؔ~Lµ^O;;.'f$%(XU:sw߇ă`o!czUџhZ9pηڝy`g$ʏ}/<זgmoJwڮZx~g4;}?]fz=7Jses8{!LEmʕqmtJ)ZCM39wѥ[ZK! FP;jBݭl.;wpNUd;&Cd 3L{ 1(:$t` O%DxG(ͭN I<8eYi~gµ6(Zb([IQhH@lf !`_D6F=^o4I!a/k.5DZ$b0" gdȋ O>m343.:'*>=߀Ymg-eQM9C%BHΑ&OCg f?iFDeztJtҗWbN6!6URMHdȒQ6@4uzD5`#;Jg42}ԃoTP+xs=;gJo1LSZLҭ̄(vׯ ݼ5V~;}HClSa1!X2s]7K<' }{f[tfwk;3zDV d(%C@1c ɗb W{1ec̡S3@#(4SA/DZ(0!)SD*8%5zW 4L$1; I@4$C)FKI%d!qTȋR5( bQ H"S2J(,ISH$N5AIVz rfEEXPIA.E5 D$Jɒ!0CŅՋ?Gɕp7!"%~ZzҖEN<~{>(Ϝ87?zAjH64⼲C5(h57͓P 3}{$PDȌhF`U !s&PK +T7^ SN34vyC7N<1>N%r d- "ǟ:oɩ)2Q!9m@ $$DR$"2W蜏QZܽy3GDW^]-uRgX sCzt2UQվ;vؑzvoeܾs}M\uep2ht G׮t5TzW6w>;=ᕙ }~t*ACQ!9bBĦě d2)Uf5ڄۡ,C $ *&^M{h̘'L0qlgjQsi,H V%#MMjIӈ&c(V7 C!)&%@DKJ৥ 27 N `sH%9uφ޺-rnq__{cu=k@?B"0S$O3`g_L&Gry>rʕ|S0g.\d ^gh;ӮmqbBcFKVgպMQ`F,VVPkUhUzcL؏%j}s% !rZ3n1\Y7t5~ Y] {ҨdHHL`,(@F*˛W^|1͙R~>џ\+A#dd)h K10yCLd) 3sJ[ΩY&؁C}4#4" < W7/TJC̝f0̪DC ˣ\ rY#Svdu̔oHM)2)W?_95/'x|Ĺ{j*4$DF04n*9Yh ,PLI`E+G-Ҵ!*6ms^{7Jۑb;/]x%m-'}KrM˯}S 8 ̮]CX0Zl~K_g]+<#T9_#쬭ܺysF)\mvU AC(R":$RD%jbLGD@MTՐ-s f?;hΕ$rd(09& G j6QŌBj<9jꆨ %R(*0}^I֗ Ќ(g#)G5(.Ы_ZUq6V$ԤC)8"PB #iBA&JRUG@(H'W,v~l4HvUpka֋$M ./,_~k,06ͽg@I#3Z`B F ؀IN*:HfT̔ ..|OwN]|u|6vc d2#!Q*dwT^٨qM ~k`8. _skOYP!׻s  M Xu냛/x$;;{{3G|>أu]oƳZηi,~CYlݺ7z;cG{կm3?_է7.·On/on}l?n|3qfSi* ޣjՙ>O;Oݼ7w{(9{ 7ovv'h`/ҙ]m9Ͻyw A dnk ij!{j샏 {۷33b2:i&KƩc_pQ/ ^:c[Q3i/ XriS)Cf&CL&y{fD*,C1X dvjbUO .ܺuk2ǣtFNxfHQ,eQ)#%agj QIP!) 2z$F5] @@G'Bp]LR(Z$rjȞ@Y-9uI0h6L#C'dNcȥ2D"j'S:h2MBD TcjD#fB9orbTbhN N̈́pT'`1+5LLpˎ-%`D& ajjVcg\8 BYZ`|UTb74:~nnN˿Ԍo|Uˣo{n|='q.")i"(P J*XU16d% `D lgHI11+) gRp_;b`"%D`W[X*+-XKD%GlPa K 꺭ΟB\ݟK)^̷WPj J1?c,Fo4MRQe/X<}SK\~';i}z7œ7pg2}R]h+$@ <~}Ļ}jg]H؀K_G9Vnan_,WZn=-t['˝{x'm0j'com='2k2DҌÂÝ;6֣OZ%yIWoSjCDS#"1$4r}e勖񨛮ِ&_qƤ ə Cz PaCb!9s2]qndNoL%o<5#4CC|T3 M(079$PrQUl6nݸyK&z%7ެygB_sN±=<8Xڷv[4|_^媢,,`oxn5fIػ=N7a +kK~pyox󻏜\~ww??C̓kv=4d>ApL")s"A4"A{XQ1jɬ e$b&Sseo00 !=+*31bơ$ )1"'(&ed9.4Eh jb plj"FDŽwoB*l`SA$!*!6I xV 2yG$Ajb3\b&Q2sB 8e)83I3[CI7vP aL\Y]׷^ΝF؆qH:/quMR0+,AbьsJCAK([TJGb9``FDb81g-&TB4$62L\ov~RTkv^r`8lPדƣ`'< ɉJ3n!BR, ) UWd =ޘ<?q?qoo]>с ;RK)W1߯ r?ւH|w0z2ޛ&N+_xW6 ?ӓa^\g>~mdֈN.?φS/~}r]MU8_z%EYUVѫ| *l5jBϟ9?ӟmunnѤ.# >gz?JXR1$͛2_RGK+~ϟgk6Bd[__ȥq0& tQrwW6w&&Ca##T@=*XJ``"1xSÔ9ůd"ѷ^0HmMIM^{ic^ߪ{b&fILDHf4!)X^8}eSQy|s}2ݫ"{Yb )1"R2)V/^|[)Ŕ4Dz;3{7M4CiL9aLfJF- wgﴛDMgT{6MAʑ99A!):ddzC(>ӟ!Lh-:5"#W%-8c-[E T2 ;34R"ܾyy{='Lvԗk01`qbN6}zp{i;UvYL fZ[;Bj=#Q;b ʢ-nS|nns[\\|9ng+]+KʈZ@0SX QFd`FGi$#U!3c` cG'TG DZtJȄ9*2)#DPIƞUۛڕe}k{wǹ8Z-5Hݒl+H2  H`H+,GHPmAzkdxΰZ+kvuZXH\sk? %5 h"4h8ɼ>I^餏C!RN@0ԤxtfŽcJjB{2D*`3CAfhY$S0PS!K8I -'Ԛ019Yc]XQo}t7q~4M2v:vGpv7uqoX{7&!7 ϛ^W~.@:*e &Մ؁0%T#H&p&d͔A=TG@^c@Db'@FJ Jj7B IDATA}뽏Nb[w{{f޼;nͺfq P#]#QyruIU 81nlo;|ah#IЈXXbm!<_9_~[`/<6ӽ~fvpwwWm._+xoTί\X=w{hT<:ڟUt - 7ή}.&w/|?vR=X.0$b+H~B ?wNUeJٕ'^+en}y1>t?"i],@WZu`jnd>d]E "<0'@ol y $%&gl Q^Uj =i<&Y>Oȏw{`*Y2 ؙ(GdK j(׮upQ,%fYVo!3^j0TEvH3gDL2I∘ 2ٸ4_]$@[zM%#Qd2"!f/!?Tw:ٺ5̨1P `DPPn9&8:/}η00.E1e#,%y_hľOm?z8X I4ʝP Is)$swWo}vSP>\xw'\˪tUYzm81Ʒ8b$^׽_X+۷Dܢ(Ol~`|_{-ȧΒ)HJ}" ؐ &uf@6D0F(#FbX(G;0t( 悑 ="1GUD0R"Qdd&Q,ZBA,k{?Kt]ۥvnMͻb3 Y! LIԌP7%̈́=wH`N-grF`0$Fd EM `B( 䈜bH ,.!ɕ ylvggRxSVvzrpA?u; >Y~3kVJ_گtOG?J{+K =QbBb""RRЫNɓ#ȌG$FC ѫtH`=i*_}?7Yd:RL":^ %|`hwcQrjNXzԫG3ϚNdzxr=;fu 8f\QJ|w_Z]Z=DWodٰm}߷=Ҫmf}r֫`'UUkc=KEX8K'N#7Ɉ٣d(s"! ee02y뢛0Eifw+_d2OL=r J ~/PϞ'-2q>4Hoxν+UPyKDE20$^=!1S`"`WRIғ. >"eCU#0%l&@E" JE *;LDڴQ:F`03 Ĉy/߽=hьo]{yn 숏ٲ9s-Dq@+Ybfk>حw"@}XBxUcoT}Sr d#+@ALɛ"G3΋ľwx#=R?xUme,K-!Q1mi})q᭷_[*UkF8v`lx͕S/|O1Tfz/ONSDm~RU@!bP9 %DQ"UHMr09c1@I@fŠhJ@Ne9ǁ&+ٗ.!*de173O??.}O/4umcq2uY#vz$e%W)x~sѣtwhώ6,կ}`޵+, DM@ ̆Doh UcR@d$@i )``A!&>xxܜ?;}h;iRibl gA(\pKL,*7 p"38nWOӝVW<7"3ܒĻ/d\nOΎ{_si C0=\p0Žɣ^.<'g6T'ppizkߺyhP%W__xbr.V!{bfC(<3ze( A}gז&bg؃KX%<ş>'h0= ?qu:u [?x=4R;KҰ BzڙXnև}Lrl(;dA4e|}N $PS&TS6@318\MJҚsC0?Z^p𴝼{[w>rKU(#9dfLLًtgI[kU:AƦi|td9F+^[S7wupAqbuTUQ;_Tg疗AͦfM'{*j;ܺ|ʝW>zg[Ѿ׸ 3bw1ǽ/bD55IM3Y.Y`rG)qpy2Bz23V6PQS$D-%e쒴mj#DޠڵuٴIm@d>3v1%*"A24 iDl h;o9WR ZV@*)0ILAP#tL矿0zBfs3wnG]^?u^htDlc? CϦ&DmXԱ c=j ԵG3`e^X=c ٥ ( '%ohޙx-=@%F]8Qɩ$ Y5SL-"P횹G^vww݄]%4ra9p u1<]щXek-toW_3n]rsk>[؟U)R~Up<sbS;="P̚8KOSePfL7~Ɋ׾J3`cU,O??+*N=,4If ,P*ŀFOKOިXn: &g"IJzX8uٷy緷c,|rўԨ~l Du<3ʪ^GQY 8{G[}߁Q,E5sE!9"$@lU3# 3{wpKmOK\ܾx"0Isoe.׃aJGD;Pei WBf$~1s۶??N1Efб3Aa.y=*h`H"WupH”?#3d@|^`@]``r|&#!3y&B<'DJ` ;&yD58ZkÙ4f!CF~B@@dppFQ "B$Kg~sɕw1B#Cc"']~THUW>b0U$bԌ| S:/Ʊoh>փaUqWx_9w~;7W.LHXT[UkڡEfsfĿt[!9_}^zᝣΜ^X尲WM 7`L)g$&, X0urYEQ[TD*2)N}ER;<30* ppI!bh C4-NfIkŶX"&UhIJNPz2#1tGi>e>?./=EOz7RM-{$3#ϢA)}/|x''ڱ8G=oΥ\ H3n6|i}ߪ5Gv̵3#=}zes鳻7o__k?a*ovkO]\{^u42OSP/kg0uE 6D%+V'F2ݽS;1̢2NWGsSl'aL^˗/>)>xr1Nj)bL_+W]߽8f4D}uxxwh(`@LUZ#&$)6!dM沛H7 4GӰVѰll֎xB7\ԃPDFEؚ*#fu "fj˟?_TF2>٘9^' <1(PWmvabB$` sʕv;:$[|  {3/?^rx1"Cb`DE&Z;DF h7GSqL>ƊBzX$2Bb4&"2e@=dʊǔDN@'~ׯ_;};^|o:h2FPP8x8wS$0HI |'q$ J^SR#DF&*9TrP޽aq[Txu6x,.Mx7 H+CT ĤBf`Lt+KhP3Q$l"q]P_G/ɓW ~D& , *|(b1 2XRAPG 5a13 @ јcB'W2{bC &@$(FP^MJHb!E#u 8IzjH 9%6̋s(3%I2Y9U"A|'3"bQAD, "0)(hŒd 䋟,2d" ͋*n~4mvǓ~Ԧoy (͛;<<ӗUIpLP=z,f=Ohٸl!%|,By+yRM޽,F%M@,,!Y3UBD:$Y ƈ4Nv :od4( G,t}?޽uƛq8>(~0,E銂51;] [j$"B`R+WҬ]Oj%fƌfJwp@ U"!{P07L$v;Yecb=?ƽdcD` @g$$r,ÁQ ^퍶8ч:G/.o+f0"sV RN^S}y---u'* Om74Ͳ}BM P'*~vmz36H 0)( $4 Z"Е0"cFvHћiֽl3%%4 hwˣ**Dl*&c<|hm"o{|huͶ_+/|k8^BxZՒ$&< +qD5M'怘"H#0b$$&$rt#Lfe` ̐ bT(IAyAФ,bQġ"[;)L4u`=(FĔʎ,I<5P0bD(&# =@@a 9q `IfBd`#ThS CddpRI9 @@w^:n^P`|S# ]?E7XYx~yn߿1 '  uؓ!ch- <2br)R24"BFIR(uI"j BhJܨMR4tO.mƱyoIE@ZJNNtb?sʹ8|:*%&6}ceK'7Yc@7O?^~1'?q^HB7rwN&NR?I3huՇw#|0P6CΛa B2bWNn\_=[z0ՓMI:\E.sl] T;d n/h]|w ZGrZm Lh J|O̽{oN)7U.v?[oEmZ;u pqeAhc7m䍭6Fz$Q$$e&Hk/فƆ D HO\vth|뛇+'VVW7<](JSm{{DM}KrPeP@Ȉe!Xb)-4{ t}'Sw\< 9Mw  CMۏ\83UF(_$dBX )a~'"-hhjdBBQ#D%t Gf@diS*ELAE$~l{޽hH=5("*S` .3&D^'gF;]L{w:{xt`4@q.O-`dN ͥE]Ln IDATر q) *}(UЗ,gboν?hTr #}?ﻦAaP:YtjJl 'r$BfQ'PMy4&bQ#StRq S@E 514}$bC13"Y?~_!*25jA%px4TX GySvo?= МIr#Ɓ$&*J(:"E%GSDT]`0P"BE7D`uw חN~}f Fu;ƚivTWW\N+1u@!sV޼VֹG^ƽy""`.j·仇foY Mbw/=J&rEu7|޶mޮ O곷o~AohIlH@HҨܠ~WB ~gꖋs/8ڭ?,o~,ɥkgfm~0l.!"j 9F,90n!BSBOb:hASVLRIE}zȧNu7We;3{Ya6;mf?v1ͳϧzP9)E6xpns߲޼h ")="('QfTITRtȆj@ !}DGwj4&y|䮕J;;hrU2HŔsHXU/Y冏K#FPPUVSΙezAW_|~٩ۍ'=uTyۿKG"9dhc4bE4CGr3ǟ\CiTa˹4D(@TrTETBBSRT FbjJxw|?s6_o~oI(&ʄ cy'Ao +/,_?@LT  C $fI "GP2B!X*E(8- \m׹^;k&/+/؇]aU/W|KhP:*5KZ0t2km6R,,:#w̛.vqw0>S&2A\n0tu4Q5,p:?mݻޟ}?[/]^UˢI(CJ>b1a!@BǜGAHe&䜇dm?S\xj>[~bsd=j"b{ríH}GGf:lցewnJW-,mMOas0i(~&:GNf~NgF++|m' 9,OXf Zqh7g86N7f &w?pi ItɖLTU ,w+É_q:AzIDBS˂{; qx;x2M.)˰}"8XyeKkm2K[0ZĪwTTH9X3Y5oLFa0CSOJ7P:ehL_{܃W>믿~vN)㘓ńz*z 2S! :ej'-w`ڴ bfwB( FG$ Z >$)@j\!@bb@o }]ܝp2:)w7Ӝ׭5FฬM68n䜺F WI=Ԍ$&,#f7r~fY YDD -«֣91(00RvfޫS6#c_v^}fgom]F 6y3B4S|&2@,|~3}$S[9ّn"j`5 w[WGz0˅r.b%S0ӲH A%}k UX~TbPQUjHT о-R_Zr\HU*/ʰbcCFǫGyN?Tf4Q&4A?]SO*@HE<]]R(KWHsw?K^Csg >iDEH&̄Ј;C&$BHE3PK19sbȈTif89-cRL=i(8TBr`ZeR Q5UuI;qmP$caA(uF%F;qEO@䦋B2"d2%(B$C61EM yMy&$,%`j=JgLf3ER6ycR"s@ "v=KĆ@ '܏=KoOoG?V{Ѩ7Q[JZM&swFC_u~:|o߸@3h(bB"A}oA}ј-E(k45NRy6"̀43ҁATLz@L _y՗>^MZDaA,ftd9. "~w){;>Y'卙N9QcJDHypDJ y:J>t9M)sW'/֤Ԉ `H$9MQyע{t4A)1`!ScO& PˠJBB3LήqL:ą@,f^) d*1!1ԉ [ocWeݜ{{h4="ȌHY UMFA A*( ʨ*!3"NҚ{{ip&4w{ͽݯح6_W]Gp+ȰEӳhSTB|UJiKjX@尟jkͭau(PDnv0|8\"&Q$ՊBqOɐs]LBRE ǜBa YTuٺ_pNjq[gNԵ1D[)nXݹX'a5=VkfjԦ1P_GIH>qypZNn"Mw1~njuKJCMYT ;&$wڷ(}_gq!#Rj%QL5T: );<~ kIK+E{yy~ٌg'VsU5tܗOVW_<u||fVkSkVTS2lNN/t1\ֈ=fܺ:>9Pk#)S6^ z襬):wKz8/߾݊cO@*>~u;1OzлL({`c'7-_ohКHhQ"`` }!,74rQޓ\`STF͐K"e5)Q*#`"MS/qȴEhj uT! PZ-.Z4LnIad`'؂bTYӱP1UEbHs%,9xYD0+ aX,A,̞!&)js!̄#(NSiTFq-%㰉HQ%g3dQ%_I=,>=C8I*V!]x'5BPHvlrcA9gBL %DE兲hm4`9sZԔi.Н$:<v[ޥbe}5z&r)s٠Z 1FnAKr`uvZЙNSFB5ke%[I󸐄~+GdDU5f: 똬 7H2 (Ul) o-zwYWLZ6?tڋI R[ݽ0TQd qђnES)r&tDFm!i>riԊ1rY[ -#3XO E* 1-vȱPu[ dul2HqdJSP@GZdSJD8ɮSZ9 7"R4[jQ\MIgfG[ru=Wt實yo~nN^?oۋϟWwj{~ ׯm9wGoɟyOP=?_rڑ \wev27<@Ηz=5[͋}x_2Gh&E˄`[ ) YB GMYfTj'\VԨAJ.*oTPUL2BfPT30UDA&t'AhMRBȠXla 3.XjaH03"#B!Ju{Ih"M@3h"BA2P_n}%-.U# BQ@IR%#5L4,YHҐlmD٩UrZ/PxF.nI RWjs<ͭ+6K|w.*گѦ Ffm% L_zD"]IZH@U#2Uᕈ2"SfUVR%G\GQr/ܫTEXzbxQѢea.I⍡j}-"R;պӴuB-8UwGf.N0RI@t]a9}n4 {-soa-.WZJι"23 ?Uq^\ 9׃[-^J߱UNNIL{[5O,WҤh[ `XTWYQI\t& a-r?2>PGjE[rP:kuyNlzPj0Ӗ K3 k-wQ̅LSqSDB w5JbyY`KJV.usQ^G\s|__Mu'w5 ؜nwu8޸ߩckŀ=ywnwg.07{OZ'_ SR]Tdga`Kn3@4SA"fEbaprv}17zl]c>vu:Yw۵ZnqNi>M?|ɇܺZl^_+ubx_I7.~}|O=kg7?gR^G/plT'<:Gv!!2.d76=}q緻^G7(,Ūs7߼76w˝{Sx4$22M  * IEiQ$3DHlPHj°\Ad?LAww2@T)Lr"b&U,$DGRa,DXGF)[sh)"Wid BFMAg !.QEE)=#$d2L 23GMA!G{A26 JA*S-Ŗ30L$moy .f]KG<OD)Ee* PRs$(@*4;)=]熚9֮̚))u<ըQ3%HU&8Y( ]Idk IDATv"vYsIj1HrfR1/ 00:tbDZu܌~6)R%ÊiAi}X֥T@V,V瓶Ϭ{V8V4"'T#C -P3o hm$EZHW F-"9S u,RӖf})R fu)BQzGKF,A{+RbhuQ5$՜#k\94HM”|V6R\EK{?蹓LuzO|>-m,Go gð gls<|h6ft[gG hZ,/Y2btlJ+(D1imZtꚀEIe^R(4%ʝW^ߓ7WU/-S*J2Rk)4oOU/Wϟ`EBaIu'\V|vMϷ_oin/f#{a2;i `P" jXd|XD0N.z,(ܝ0LeXI1;;D@D@7g gGhys^?{_WO0mkB#AWqYƜu=}Q7W Y.џVYWnnaғ9"+ULY)b&u &X7ArꆮuڕMn,+k]W郧O~h_k h5(XB 51M`x5`rhcVE6UU@]d@HQtlTdg }MEhQ4BH' K]J0sKBȥ3hf2! 3DzX$`jźVS۩AJ.H.it`!d ="nUZBҖ&`b>kQ7'ZFD*P@@]&) .@  e0-% !Z0vyyc6:<5AkɍeXPzCm8sE 2PthbKĈ$D."Hd0eMyP0N:WqQDDeaCqFUfN-(Ih$(-[*\PwdAP0M-QEMđQd##MZ/ *FTG#妡 G"r?^?ݍlor(7m?rav>,&V.}VzauPMWOf0s#d (Ռ Wk3(@,?(c-.n0IM3 L$Z3/._lKnCoV͋&Izk{n{wn[guYwQir㭻2['ÏGW7J:~?gVD$9U.$2iJM]ZBPUFT˅NJd/:]4PX_W%mkx'_?0?fR_ukWghm?ջ{nO jwro7?Vӏɷ5+)wd ڕǥ~Щ yMpJe[wr|g7aun_0z-p@o֕.^gRW~^*u8/eme(Z]?+>x3`2CUÌyMIw//~uK0`A  ;Jf@"f!XZ[PT&\,M/oJMd TGC6v2#))G#I&b&q,"2;mRl-6!L ;DGtQd[ThآŽ"+=!BBM?T_Xhc56ƅ0P` `1DTKGb\r>]}y\eiPW׭'덗Ty3MSԲR;VZ05w}[ͭML +H]шKɓ HJ]DoFl9ƶ݃⛷uzٴ?Wm?_v7=ڞ /,êJ?A9G C?ձEቹYXimsv}{}c`%tdn?Mо}y#i\}xEhdҨ5DTW dF'3[$b?$SRU-Zҋ*PH@CfI%yfF&Dg8CehDk߻-ZsA!hABQbY)r(`d6S[FXbIf4E6MR%jjLх!v}OM5(ˤ-E#T-[ZPE[ }:ITMU"X7j Rl*APdKO4@!l:皪VJwlhevh мLS+3uksm5I3jk*…x=h*hT7ޕ~ $LRifd.8 .STJU:!6MWԵu5kThS)lAFb>Ju+wsW"fj,+vlG!\IыNps7æ둶?ZYgkf2kJIX5&rA d6EULg2MB ;E5ELDaFFy'f1tѫi0d7xfvT0bٻyQ$:QC-hh 6YU,U*ԸezNzhXHe*UT,kf2 4MOdJSϵ0U5$2kdJz_'aUi*]amXDCߥ*U<EZĒ/)9OTsvѬϤ4::/?~x=4{"Vo\ Op~YYQ T30HAd&7_b$ sf*Bҭf\hHH:d2(!Pe80/1oFpů?{Po%r7h3/~S~sn_U{vs5bT6M D;47 D< 횀,MXf~D[X΄JnBR50B8am|^=ve}[km/r^1-cmvojvvZqJϦy!yu}u-ܪ|1N/>yTGQd1h$^bd gn[TJ5m|<~D7__s~onw*㼯٬λh޷"cgjڷOdID 1*uqkuߝ}Ȯj~oc4)- ~|e'nlgɯ%y,0u1wAv,J2p0Xfj,,LHhIE2 e O F./ŌЎrc""Q,*!#0_kBLjs\ԶYˇZ̳dd-a($ d3,}Nz(eP I1rK!i<麾My+"AYHH]8Gq6R5ce=3L%s9-B$s7X7 \fGA6ԑAR͢DLʩꍙ4M)FJPZUÁ!nU˘bgO}(%=B͵Ef$]`bjgQTwSd%ZED&0zb"̥RLJGj"餈Xb&Hb" i8uW~aФgġi&-Ӧ_u#u~EӢ*;l:ޟ~'W]1a r!HEQ(AŠ-QFqxk_0b QUTc)2]O6gn׮7g*ݝ:Lg~ؐ%?j3K)4HQW?_Ͱ?}tb?};?[>ng!)" 2EWJf["/+Y֖TPRՠ ,^Z`q-Ffzs7^okO=8bc~ Ʉkt:võs޼[͓_~XwXC5ְ9i^;W(~r,YeCjgm.{7ޅpYf>|vU[Oo-qoye uXo^Uv01KVq– b&B27!2ՃpH)9W僛Ó{{z0]Ɯ||on^_ 'Ojasƺ1M.5me&1C:1AKQUl&̭j+&_*mY VC0AbDgI.*C S*k"D%h)@1SLtD[BՖ0 u1@+c=sD.M\^*,$LZ% E&jwӓjSǹt`r)IYF
R͒dpRJ"K:8~QBM%e`z (Y.'PXR,*JH 7ףYɅ"e.tS)]EuZʜZtYEEԋ-v;l}8dKZkMKk9 ) d{ݰ:9)}pVFvlӄfRJ*؄ uNDьuƽy24ZkL 0I ]i.)N$#m7ϗ*07ELI֒|CKX=) hIG  ED4EUaMpAڗA2Š0Q\@QQѠuFuX/EZM5Lj!T&aaJg--,NIm9NaqnOc~ ژڈQTjr&݄ m².-'4"ԊLH,dMBUUy2ADS&#CŽ TܣSut&jh:S碮K$R2uAgϿl;ܽ_4h[ֶϟ4Jiېg\owߛ/NA^?߿?y2ϿӒY1JU%A `M*&lB"-Ӭlҕf.ڒL~IM$K,ş#32rH7%7M E( UKЬFar|6{P..n}OKc38XvWPKeV : Н%5mh=~~:Oyg`=z:?>|{3}q=` &I,VÙVKc Q[>Pe(I^dJ =sDWlwq:Xo9uzsz|]Lս! ]!@Aۯ*xt?$a>~~ݕDot=8qYKط~γO}{Q=AG&NTcsZX<ӻ3 6a:\K囝[yуM3n_8!IHDgQvFDˆb7!JF^/ .B3GoZ(͙-ADy<< AZgfvi63g $n1),f<U",(+)ffwo΢RJ%v z o𔅂j5bP0W8P$o_OmG`&s2EU$ xHA5+4ib!n gV`!f7?e*̿ۺՈJug5,umڠ,X;sZ+'%ֈE,ή 2BrrokWgA%7k@eWxW91B9y9̫6ٌ!DoFLTJi-G gG[Sݲ{e"oe!.sD؈[us*8J3h%(;F=YZsph#b&@2s~jA*iEœMSx3(-3i0! B.Iz}#1ʪvɑ`ȫ%.j!\jhY@֨1/x<{z˞VK\[mJ15F0FإqfwW U NWH;y#AkPsNbweV0'VCեrQ }ku*¬3+bHJ\3fF$fV;$4“ IDATvp+lw7׋i-tcS[.VW265Y5?oG-۳6G}0;*kʻAg iR@~ w#M/dBAI<+Xz}7_˳y-mx~r$;LRi..ؕX4S-$^=M!f&a{˪u^ܚPk nմSDZ8qo8JJyUso-FLp #0WR<#BACLbOYVIMe3)SDWÙO4Ӌ@YZ$hUGi8J<.~;] mxݵ>~'kk_]QoRgs}o佫[e~׬E9.F1\:ʖ8`^)R7!wZH=Aᖉ-PՅDLۜ Z@[. "@kL,IڷE f ee.Ej<>?ij.FApiPf%J%'bLv@&teOQ++)rA3T8X#͠`pFC-fTII$4LAkZ%@Dr@(p5 i\[5>6V'{noSNQB|&tt`D#ITU<,8L@!V;v]",r*j0Ê 5yzX;ٜ9F؝9:rTnKHDm$A ͛ KT [vPp]J"]kG$chK-9>Jl9 @H9y  !&FDYI8%hH TPkbF#XҼcm fTLRvҖm]*v/ŤZ fUU"W@5&^ȕrkDbjHR*kJ\ ,` .&@aEPHKTK,"9ZI}n! Y5!椱JdH,:ʣ9K 7#ֈE9~?ݧ_.\n̦C>!fk>9~tݮ՘FZ'>}:"Iw߽x?t8- Om  hp{V1 9b܇s+կ^Nߵ# "p h2ȭ[x!VKYݜؙy(X;DC:e]DisZ]=1) çu;uQ,m; GOk?NÑzQ>?wq"描=Wוw&%~ֶhc GQRx.YjQf˥]"gOSܥrF ]o[KX|øXW+\ 'B0bJN - f,,շ1']l4ֱWv5zo̷6ys6O1lrxmyMRJt=aih. 娦hfC"  V)XLd̞л֙n <$:< \:ϥ{wp ܁ "͡fmHO-͘WV' g"/]" 1R2w&BLW6'8;Ï?z~ys>vw̬)L% 8$Y6[*I;E$R o"32 A0xaOIuZRHe2ZWbӂb.s]ȄƒaYml= CPFz06Q L bb @g%Ee|x8nVw?n\ʝO2G5oKi\GiY24u,zv5p_?_|pu..b9˛))Z2w)GJxHrXZr~dƚ+N(%5u#֘=H8&@1]跿٤/{o\YR2{ub>X!1~n~*ŋ?Ys&{YxcKuթ> ӛՋWřb A0%֫̆2[Hx\8=ׁϗWG=n/u2cg^kv!\<4sZ͜ 13,v"Q="n.˞I.Lhޱ㟞ߴζ۹rN6pRik[jc^m1OQ~xrwwn3P&ptJY M;5팃15f"6ݧ6?Yݨ #@=i^ 9ptr1o/V">L{U#|X"<ܜc)gAt*qoA=nQ X# 8So_wOωż[eUe&P %'#\Ts`naA`a㶗t+% G8}:̽ 4wdrw7D$!4!'Vey@rJ9e%>Ze.!IfєZ_=$Q(9ABF<8; DYI(P IYd,<2l'4Y0L B,AjGsV"ְŭ4 aE6fт,DD9 *sΫ@Ni}xh<)VYH%I37oU6=DS{(Τh#!$3YX3Mn"JRutj1Kr'F3rba0j5HB5(* dqkK^--2ߔEq>D6U5t{yX=<=sr<ɊD+:_rȽ3丼~/_zS}pb*$QCw)%  ‰ >6~q ߺ)'CzHuӡ?}tӲlrz]Jm>s9MD[ZR~XQ+ץnͻ} b jC^^WG_~|ӊ}ǿ~F>RwG? %]%C[;n507DrsQ #QB:u!v9QHs;8('AWyxM:E+'XT~m0ʫ2O߯.?N?|h_Dzzs.[Oӣ|z`;z|\X@!܅بE/*%Gyv:#Io.v؏jJme77zks)@L kM.KsZ듽$h] 9 V[dBnWu?w~Xͧ C\їagmŪFP+n4OSl?7|!rʎN( <EX;[$J %tjY@~:Bج3Q3Z1[YDT:',ժy&y5 35\([0װv &op33=w33Ua~kfMTX&ja3$fj?w_0ga"2ͬ P E$hIjV%:3KkDG'RPRΈAH8Tfe4smŒ`aH¡VK8 BHy{:0qj9-QoV8z=_HLfM$`CY1Ep N JMufLbNNR0rw"\kZo`;iPVQ¼efs<$$sz0R?&i;z9ۧ7TCBDv01[k(Sױpp Q?wHN@bW#$Ё铣{O߾w*Oybo^˳/ዦ 2|oõӮ)4I2զ}⷟^Gvph.ht/@-DUŦETAS eh[HnL a07/#XHXlփЈ[+]颺peD(8EpSܻ6#CitX-T,v;Fm7K۲oX><<4ǧ?uyG~ ӟ/9ьz~(xgXˣ+*?{a#=<gGY V/3i)xnI9 ՈDi1k0̂y@ 'g7P="K͵XնisL%`޹1荻?{?{擋W?Ҫϕ9qz7 ؃Uj>vH !3fg pfPSc62&p3!JV~kieiYqcxb27Np7"2yY{V;Z0Py305*(ܧP+p5ͶB(6EXxCbB՘ 6xD@$R)"̻_ơ:xb`OάzDB~~D(@z83/Q@ˆɃ c`3FKmm?/m`YLN54$VBIW$öy)L&UoɬBjc #3uip EV"FbeMZhoYqX*Yr(38$@j!: 0 ]kkJ b0҆׺',cVjhjCL z#ևy`y+CÛ0j+"$*TKx B'U*qi+Z96u7Al졁 Ai`%!򀔲$"1P# f%63 @mRh mk-ۗTJ+@jD! KIH#$aLuWT4XSs&jH”&HfU(ji$%osܨ1c֚C3%u⤢*25QpmqhfR0k3Ppkx*Rz^vSonoշ4Mmu_>MBFXt`oqu3a}y`[$:{fHJ s)К33vA~}qsy Y$q U M+!,Ȃ(,O IDATDF6lf A!:K/䙤kc:MKJPѠt:L2MnI TA4 ^!ֶ-<a|ο1ٲWlw'2oW<=r @҈(xq % W>xp n8|)\&G-cXhY۲erJȵA: b.̓! vU#RkdLLd*^N"KͪG<- ;>J1*ɰzHSZ/]pWtxt|,#H3ޚHrCX#GvJ׹H}}-ohAa'u‰5E:KK=g㦮}KBz љ) ]DX(y#oY8,<0!0[Nf1N QLED JbNL$SmP)2+kh-0&rnjZA"nnLuff`v%8 ci2kKÛ5, UּyhZyhf;Ɯ.8ܭXIid8+@Jz0~H^֢63$1bf6pKDr3 Ye 3Ai[poNda1BAJ#"`aId,9AĕHFX 裡TuJK+Q=ZHCsֲ‘PkDXGH5W:NsF#Y@N :Wh~f(*-7*iN\TW&S87&T ;{i̔SALIC9*ST!bFp<&`6#D !Q>98lʜZ*~X_w/rqyո.RHΧi?\;Sa<[aٍ˜GO7tsy̻8֥j+t<)™H"nۧB1 i5^g~g?{UD]2Ȗa64M770|1el_w,~OiK!|}*j}OߙoڎQ6͘5Kqʗ_eoCVT#I%D,hLܑ'N]NAD'$4KX빈ں͚H" j , F|<^p:Ei$E.$IsD Ve VE43ygQ rġǧ^Zi<^GX,MW_ƻ|6Sp #gjcC| =>HPPpjn:o1~$˲[k}NDdfeUW/sirf$JCQ-|1 Ob6` 9 K眽Z~z*DF>}Hk)ѳ`02h"=Yx N9)1rHT dR$FA€5$L$@NjIF2G?! 2.L"2L%lRj2̾NE,[z2ݽ{4V\DHA7PY}۔t_s1XkMNUM%x i!HoF@D!ӷ֊eԭ9D{UU 3=#"`+jM1WkPMgLSeZNEiJJiB)R+pNM&Ap h H;^Dg^\.tz]2]2v޶cxZu'-!={o^OW T;.[zf߼ѐ=) ͤmDs$6\D*!Z$ZE_NmӺߪJT/mhf6_UE,Zt04 ck0kݥ dmBZEJ1{ŊJfz/s&NM(!b6 ":k;u 5YL4JuؔH-7!2y PgZg )DWIFUtL;̖1PG'!D~Gyx~{7cNUԼWc]7toZ,O>RǻZ^cWy}rXAbݎw@tɌ10V2mXيTs*h( >Hi4#C18ȩ̿ʗU6x |P/uCi^7ψޓRi^ɞ;u=mo_|fUXL $K[)'d Tˀ xL41DY *@M!!(B`BԸ3}ɓn_(ֺo H]&_zjmd|缌|?67/Mಢ_Ų_1A\̸/e~(Tc.R;cѷ̞!1Je::S{SjKǭ/$- "u9D;064]L[`lfO7A]e+p`Ȉ _F"[˄xv.c(^ Msb&inu:)ZuDIo2=SXZʜaHyOX)E^l'U$Iza g`n]MJܸul---xv0sLa-="3pwm,7\Ž*䭧y<]yF;[²֢?׽; G@Hmd'(MYA4C25Ce[sS2]߶VPMeDȪ;αt'] ={%lQ{NKSNbYVm.6s>Z׆tϤRe*fIFEekH Q #T&SRdUMHvNHwÃeK P1ҧ۬6fcv UߖزPc0dYuzLQg *m+B1&${H?銠`HU R]?!Ƒ-2qUqBH#L(o33PDU3]\οye~|ի}^wMmEᆻy'ByuxVQGH\l蛕N EDȺ4u|KS6JyZހ Z -S&RP 4aͷFqmSGH DuT:EE)T}#;b(J sHȔhsZ=KWg-EwxS&4dBpe0T/X9USevSbkර`Q[8gc7Gq2uܿ_ǻ?S|juJ!Y:*eE$ ;!cr=5Ña**nHj(YzwQEi$h=@HH,+n jTazOI*-TdMf6."F4E}X |r#PK A'fhnZ%3F3SZL"~q*)*E*ں2h1ĸllܝI LU͌Z Xt ƒPOQ$7OO{ :9h%e j왩iZ$%#A7G7*jomu$ R D0 &y4`TQ) -r6Pҽ)T G_VfwCO  rLlkIriwǵs=JOm|ڣ^죰8_==y>>:LbCԣ'H-EZ(Dtj"JJ){Rkɣ蘓^D Nplj#vP-Y T0sZzdarźsimiXA,mpdʎ5)TidXRB.!Y-BJ_NbI% eR ;xk!\}ҋJPUƲuPZZAQB)6xCS4CF{@Pbɕc1]+=rʾswyҏoSfEK}U^hQ\M+_,[7vϿfxNTeDcH$h%S$ ڼf֤3)6SF #H d ɏ{|U;ᄈ/!k h_kX'6v(27o鰝џyοov{vly|ճ_ϿX}sftQ7Q; 9(LaTa0CDDD2T m33"",'h$e;ԏՏO_g H9myvF4 , S{|sn߲{ݕ>?N_~^z~ 7˩&. hdjaYL,;VX;F?;]H^v#0J+ ej"Y%b1KjN0 HU 켢:=axƨ4]fDDTz1R3`QDZF?qES88N +s IDAT "BO!JFOzyC C!&p!Fi_UP4Tm6LJF!, +&u 4wjsȮ2DVLMTRjd Y?E4OUg^|kZKn*E@֩ʹl>+Kwlq obiNw>G"&D*A+)5" ylݣoy>$Nke!8'<÷\'%h分9}#$%E޷^,; AhMoumgR%ߺ*I.$w Iyk2%=S ixKs61+UWU0HU6.S7CEE$)a2[2t0BT!7NpLDUgX@b#8,rZbso=#$=y\{LiU)2Gl"N]Ji}֊q@D*;lT0z:C(2uQZ \f>D AjH챛4'zsb#T E* 101%7#*مUAMB D IPblI3)oG^á2w/JL<ڦ }|n}]p|6/?ɧ/X7 U~ *+B [!*bve4ײ̂O>}p:NӶ^և- Ջj Ǐޱ%WDueCQ%")Sa;>F*d7)$&ֲ҅5[(yyyj>~4wїFfB0X"9GPXD R`hd@hV"$Ml (RUļsd4UF HRHqj 8#'=2զ̌hHS葮HQXDWC˄1+1K#!0JA Ɏa4 3 04A("bTT -+yfmBYJJ!dZ"5EJ P(r )SbS0dR34F+z8%&+W:YK ~_N[# e(S"itp^\eglx<  M-L2dĮb4" Y}Rh)TctpSQj*꽻]ʴ-&c_sϦi@XdQEx T[e{l/]Ֆ7ZT({ML|Wۛoz-z?xsoһC@oҿ |s8ܛ)JC=RIJ!`?QV cCS[7іۍa[kܦ<$bes?z].?a{/O~x˿{~x7*V[k)3dGY Ce"Yeψ`ٺYGov.?9n!bֲ|)ǓȆrx篎FSŖɤ8!#<zN%Ăxs>Ziݷ=NϩNkzi_m=[<t{ZUR)4J0H:DI wP-]*ݕ"ThYjBZifB {X1A&LE:ÙBQӱr%YCG1SLhR68dWP("̰JQ6b23a0Y"/!eD֥u0a( #uhC2ď,0HT8XjG+iPM9^좔 YM|9~wE \_-Gn &2{I\muGQ+u(.봚52(#THZ :QLrp3:Ր5zהIЅThK _9N9x"B1Q d7ֶ垭k1Ogo-.b5pa`D1<$ rx(2F5#9ƥ%4<M! Y#㿺Dbj}6ВVUE"V sC$f.jB{䲵-lm{\;֭{m"0*M؊aN1YkNjՌt*\@P DF.ZqغKQ,4څg i eCZ+ݼVK0U!E8)l*PPL(Ԑh"L@1x&CGǓ?я>7ݽN2tD^:ݲ3}9'"شH2~OP'37__(&) OҒ0@=8N=.S#"iNfJpW;=! =/@s~p=o?~o/N^鵲6l6%Uq#snQoONjt?q/Pvo>+_#^@#VLH0 05xICJ=TEǵB3d"*3I  LTA޼7' Z a|񴭧/c;o--\"BV|?o?>\//>M'?_f"u g E!HDwSq>>: GXD_sfWjLkhismq}vl\O.|ǃ^{,*>r~+[c/UeK-y8e\`2`Hc¤\cibt'}dMAD"&B (Fª"SPȑN1I7!b#1Hl rRuRԣwiT!g]>Vgb) 2'd #^i*uQZ:XJ9"35ћTSe]J';)s=t>G?*)&itD`fQ)d5RD#R*ȀXKLŔZ<^k qK+I19|nENb$6Y%&}]zmqlh*T´b*hkܝhG(mOȵ%sQPj P'D"t*,VQ&1wWSA49SY ̩Z,TC15KQ?OkGdef{ y$^VW[i ҋ_A03}Q2+od<׽wD<;>ZŒi-:XLSPrl\o[a{x%% [GZc7yԪe%iW)SOi8\+2m!ѻ!Ile9 ÈFn #>3VqL O1u? DBHєH%M 5P:cXS"#RS0gwqաUH3jX>ǿ?? Ti݆wGp~|p}v3]-ߵv9߽R任7 }j]Ů>xE_{ʇ';Po?>}/Z Owzs))Zzo{XYL&=fd)" gg v^!vY.ݻ#Ca;Gv{}_=_=_>޿7_!ϯWWO3h"Ơ+2st#z>"I" ( Y=("'Mi#&%3h |6\vO>(<w]K.vPpBm^ߞ{?ӫXwyփ:H( +(}Td)ql}m>yOv-m~-,Q_}}7io>2}Aod.%o=KFĨѽ$,|snP %!b$mbP8ydJ%30 "PV}HIg A K"tAfH(+FEs)Ui"P zo`' 28LwQ"=U+p=\`÷͌DL!JUdDvSgKwb,HBb!hUf"IώrT F[> b)`Rh'Xn$Tv"ɐ*󮖉DžEgrwʶu[};y2aLf6>:?߱RdgȘJ=v!"ZbCIB؇T2mj)']fuG10d"f1E"v$MUM4In^6ժ;JeENYa&C$A#ܣ9hU4Ho>n@J#kER֫ zfǍDU5)tINeёZZ %Z4P0xPEo͖m.%Kk n#Fȃ!π٦b5l~'^&SD5n /хf&J̭'i-o-!,uޘ(T4B" !u'5BD$MQf8fh.ofU̾dh0a#&EhfVޞ߼rs#Z;xw{Dso߬77w7]_گuE(r#2!UvmO2G g$B(a$jY`c*6v%OH/QJl{|~yMuَtt27Njy~ |}͗^\=<˟rӿ_)ϧ:Z[siM?Pqbr̸9^>r\[lIuNyem9#nK?yoٖvBy8TOr>O;K_ÞQvMtraѦ(/_4{$~g]w5El-b~/~K9r;wo.P?%&mmc='ʸex?Z#"Ec6V1Ef SJfFO5=R*^dH.; @Puy(.puJ>~"mqH =NAh0`ǒ9c,43? 2d*%IDKeNqdҷdRE DOQPo$~v>5fԲPTKP4lG217,F ɔ:<"sKGQCG@YTT \J*$7Ў(#P)Eh)ZkvӼ7jɦ\ޏt:&rScSS2L9l}7rL#%:4,&SUH",FS\3)"RFXXƘ&FBU^f-T-^J7J5hJ+cGuoK%tGbu8xZdd$! eE)I oA^T >.Jh߿}  IDAT88|>Eydo{*;lO>rA[dwl,yw=ޙ,ȟw"p"?́h2Ԡ7 B'1͝,Dw)2gfdㆆ ~0 '\n-Um[e띕ّJbIl>ׇ /K|r{uY~~u5^20TEf!LF]!e 6Œ.#{?# #>t&`C[ 5^S9ly|[:HvzZ{qS<<;^夰hG#xuq8=-z.kʒ-D&~]O57׳F}$䖱K>ytG0C`"D]ч'$R*.*ޤ6/.ʗϾ0 }(]F,}}U2ηoN}v{M8׼?e.̴pQ&$B(Bikh"% h %E,$HD2=<( _>rJA4DZkcFB( #9TU9h[B(%5d S31oQef80"ׂ>d` I"cƱBxN8y_s]3=bML@"="G*b"J ,s hHȠ7P{d/;HE lJΏzjucm=m82Zv eY rX.-~o~fMwg4vo2x [T:g@U2JEl".M$*Yj5y?(4- -Pnq)T:)3%Jdu4Z N弔N&}fw^`Π%Ʉ#}X *H0ŻJp8TE=(FsvMH*TLefpvԴ5:Q"ʔ.*) PQOrUF: w׶86gVYjd&/jiپ(@I"c 1 f[FܠjBa$zY[ U$Iyo*Jժ+ңG%x"Z"B#)b7U)Tfv_*8ݑj9Z 9vNjogMSc>by?;i9]\΅.~MExqr?׻~_lya-E $hG"̠̑>p*DxW'd4F#Y§ە_{Xt>lC tfƺ&Gmww߾G+w }v?틷IL@7db;$Ed2J㭑J`fi$83#MGD( @GBf&1r6 ݿWT\) ~05J*[3b0aDi4;2@w!>L` JUpfGQa"=Eғ4%q!ǬX Q:a%scFIOTuT Lt#&XG^5TpϑǑ7u[UP%Hrj鞾."uG0)!] H!L8!G:(F0Jv8|]6]*z!^ ~ %w7gOgQv<ƖM Nh}Zg>=]E:s7֣zHENNtlL D[QGŏKiWg7?R")pE#CMAJJi*BlCEɇwǷnYo}}ܐob'\]Y/_>?wo,whAfx1D @p3(84Ӆl&JS=kh2TD\C%C,!GG4hz|D{٩0w鱪Hc`9|m](>"u]{-Smlcl} ف(&wX3u[{, zOshQyyPJ JQ+@J 2g ֛ +E3$*ܥPj~׻y(4GSN@ET!E=cYZ\[/LMrغR,Q5N!EST"8~ mH==/b:]̓Z$֑r[dN-%: ڸ2f}վvD_ޣC)YbKzZfJQ1I':,KGfz2 V51(J:p$ۇW~^WmǬ|hWnN߭[71*[5ORg>XS]<ɹ|;{ݥyˏ_/љL3KNfYoUh9lwR%r'GYz:.oc/~z_w<~ݎޚp_#aDGcGeH~G>L":̋F{pDugљQSC= w0edo"JCd<򵆚cT]M %!h&1n5ɱv}F")e_(Z$f9/|e]k+0}[Z_"Z$%@:ͪ!|mw7gef"|qZ:PXf/UJxX=b#,HES>̝i1cψ^Mbٷ7wI=)Zi pGc-[l~hqjx2{jJEB}="Hf۝qj VYrZ\ZJoTȊ=ipcj&1QC 9*\K>MĂR-Dza* !lS$ fe={.ݏGn'.=#Z)3@3IJ%4;%)^̘BZųQvZkHF$ZztbfENtp:C:y/N)ɖ6F9eKS3N"YgzUX$a=&hXQ!4(w2 Jh21N&qQmW_5mY~d_]Kxwq:NOoq8ޟ<~rncԗt.了 ,O~v>~wl~n]=zP"!D311ocNt'"EՍt ,3%D?0Zs_|/h:oC;/^>Oo^C S{4 )W]<{"]>z:uo7כ"ݙ@FCH]D9Cr7σ$2ȔQQ x ) .SYSC9*9D*u̒Y>ՋW_}}wz3<egÖwuWɦ3??>7{oR@jt-Kmټ 3 Etv+クGX,a16T(`"Uq\I"H }$22:.P.By{ʏ???{g?Oyy-q6˩OOkr:ӗ߽! Yd]է򣞷jq%wbbk巵/??r"%4FFdG*A"lJI% fdH'Ɂ$զMɤ8QIEPZ{ љH)>aݱd4(z {d.7LEb調z_^||/dzbHkwRb`fo\3V=YOZxE-uY{PsπeH_q:zF`f43C)r^0ۉxqSRy}?W+{-yV|Qd0s:rYuU5R`gOϋɛ}ƒbzMyEd,gdҶ⺯EFD# aLEo i/p~*j?iok[vc9o[n̪D(T$EB"$8A@I6p Hg$V&V(EeEIK");4Yk9A{eURR0ȀqAOl̖TK% .%F5! ! 8#+##yf9OcBIc 2(8b ÅH9l.{Af@dSL҉qP#$@.$@Ef;˹]1]K0q!'4Qy<p6TjTWԚ֛\'،f#m0U `>r5 T B&"e^I\5F'V*(DH&2QF/ EZHbBUHR"K&HFNzʙsLD}r KDPIBr$y64P(p|]  Us 'H d98< .}^Խ~wn?i{>zyxe#~tVVqطAtu;ݏ=Xۇ;~® E G0ܣD_5ڔ̒IkVS0PL>wo|?;mWχtXZ{Wɽr渞t2Y wќktJymOOM͔M?W+o}o0_xd"(H(D|~G M 4k!3‚ۊd0{p`PD̃J1@` 3!uBlH -lxVl} WwR ܶ6h5t4#̏>>}o7[P 5-U](J~65\ڑ+gȳx|~nkۋ"$9w"M܋9)hoo_Oס IDATѕ7o> kp74`f;ubfRYߺ4[;ݪ[n\+ww pܙYԢduxs>}NA!HW:fJFu_Ңjn)Jf"(5,G ]V]L! 4q7꤃Cgk/ TD'ԫwBg5jiWF%˝j@H9L$Y!.2'& @JԴULNA pc!wY\O^˽: ۷qrxN~=b)WᣣYo{S0,k}YC<777ǫfg=zꇺ^;G{O\>Z7}CwzhG؝UҧȻ&UvlIENzs:ZW̴V0pG C8S^$&f^q}yp +Nw `"{8O>ewgUb;77m;wvon;{|L[Jt2lk}\}*Tc' Ίv{i͝DnQ`R^cn<=녓Nv91YNH7d­ ƔX;ŸYAS/Lͻ~.ڇǝ%͢NL,7.U.̪&`IZa&`70Ŭoݹ=U1sp~W*kaNKbfbDpw 0:;rӰDY`hN'N0BAXp7}KmƜE^Ąs㯝<)+e^ O-bzn9HkRg3Zr0'f%#Ј Ԏ|Lu>,r&ӳUTWf[u6CiVĒKDJ"DՔn$J֡'fJ$ENm"qL£LB&ȉDbGS;D!lIܪ{P̻TZgF J!0uJP7թkꖳU "I!Y(D8(sJ3&\(4gfQ {XJ .:[IP Wj\w:880vv(ۍZ-2y]4!PDb-#Y6hni=9d}m3*)<˒\<'QWZX\s4֭zT!IœR&&I k0!G-pRf9Yj'4&8.#ջoau`?,~F˸ u[+Lv:w?X 3==?}VpRng XNE͕(Rh&2޾IF FġLfFHJ_[xt__~7OAe}O۳:VO(Jw <{g?WDwcU-xΑ;ߠl;t~M ϺݣN!\-`); PJ("l;XecON$a mc& 3hodzl"H`n(02'7rS(LWi=mN7v6i' 50&{W ܆0ѷ_|ONOovv 'n-vDɄKzvWJ!؛V\e "]fs0 [//|_˗/_3ݽY$¹j9}e_]T:ٱ1(s%)Z8oCH7\Oٶ˳nw׫{Ή}ݽj,D>>=_}zE"@] \Ej$9$##&:A Kp4ƿuǘO5@d(GzW7xwjvU-! F C"-d kTC&6 rM.M^Nw26m[ʘ~t i mA&$ R,SoPbVB 0u$$Z6ڝR՟;yfd%PW=}ņﮅnGCls Ť%EJT*E Dsf0;;Y71j>[ \[Q=8Epa>[#_ȈkVlK w$lZ%u)~^ɜkX|,`k8mA٨vLBA'"%q(NN"^R5^PEN[eݹ+rE fi/%hzӪ%Ij}a7Z6ZNwq,}?sIf!2lyzm2W>p}O~MѺohIR5`م[ YqGb7K&j+Gӕֿ6bōfٽA BUbgh D s :p֫~h=u ,;mƷ=gJ37rrFcp(~"H$"y韹W/RP}uF%<⑛sa0n+)t61V&8,UIZ54"D2e޿7n'ؗԟ[q?OP#@f?g^9c.\ziG"9S #^MLQGt{QEz`Ds s];I˟\+S{ N5dW?s/Q?k>~gcgۧч•¹)w}9嶀`H^:ch:Pq*EzdD <3NDH@SNi ';gZ|9yJDP DΒcSwKUc&T1wB ܛ]H)I\9Èd ,8GZBNF w**#h"'fUYŤwYLT1 BSbv!j S6]jR DTJeTBT9n]ɗ^xђg;qCR\{̗xޜn?1t\v=QY ~4uOCGL'|`WR+F[ɚ`.o1Q C;;kd)+ *;gG3;2_tU I/vޓ*NFI^A"~6Ihg>t#ƻܹ!lA 2( -X.™h:UZ&ȵ4Px ؝Lޓ(ݕ3CAGx;h;PoakTNdn~+_ /ߗ}s?ɺr^vU0W1B@gDu^)F+Z9+g;+ V۟l'q "BN+kO8 ީw&T0Na9ZPs(0$26hZK泽XU{x饷)"ßtkn~Ou)_tZZY98 D̰.хáD"m}?3[_or~}{_9kSl#O;g!  bbrRekKA8ȣaf~sw|h~;/Xo{|<[NIɌpj]"f&N+k̨) Ip[ (.o|\/v>jsZY28>g^=H#ߑ|ɲ 0㎳Hm'I9<@v)7r",-&pn[jި_H7@B9%9d-t,}f" 9jJi* .8szjV:ЖaA:B!9$EXJ28͈;{rt["]L+ xxmzyÏO퍻hSs&9!33+9ڶe@RkR˒(<2"al@`x8~eDn|ppLwŗ|0l)u"PvO]4RNDdO>ug9??ܻwkKĂ?п;Ա{/"hnp/DmfGfc :GJDC 2"0B8x ;?zM6 J)/ a`v&ve!]P$[ spDPN@Y+~ 4>z1C&ԀHړ)( ?s\ pi6w)v;̘39MզuTP<-*Py&bIH,m<텃R$9{!@iv2StDf^cp#3[óPQJXl1ZM""u}%V洄NbC)9auT)qQWb P f'd]<|e0KRqQ*UX&Uum}q( S" 2NfRrs\UBX)60bDFp{-'ꜤzY+%Zbr랉i"6=b1et]q)ypphf|ue/жq9=|>xe{z뷾ݹnEUC\9Xt$BdPd!n-A&0\?x橏 یs-֭ͩ6lGsExwww̘Z'ۢVʘB{wTfl @1iNrqGFqtmopu~*"jIR¬u뭏ӥX:Mӫxsgqߎkw}UsҐKG7w>0n5hgf)KyHugqzng/~+_xf~7_:3??8~q~vvK"2C0+ oYc,Ұ.NG. :n#t}wh@x޾w|JpvocĒ _q>Ω1:Uݺ$ir7&$ 4H8w~|. c&h0~x IDAToʍIa)wZHVS @$6 CY/(ќ0/4L\>[ y_Y^<|*~Lيa,EզiV0D9.*)wn)҄pp͝MMfFH3Y\Xfi#i OR-PejuVT|M ʳy , !!>453:7(*|ؘ9j9%7O^gGױ{Hm[R'j|o3Uf~Co~߹R vٙz 7NkbPJ54Uk(E@-%-`sh#iM䔉˜a&ƌa[xr҇/ç'STZW[Xf^VU$K ԔL82#ۮSM:lK"T t4SDeHU 64(k4b dsʡ׍x"Y<L}pCJ^]Ka*Sх UZRE6mѡi0aRV&nAg",B` CHM%w9Pfٝݝs6ZVKĴ©l-p$DvK”#,z;}a0rA]0N`J).a J^k%Rǒ" hm wġV7q$Y# ()޻;3t#fh[g'pn6sj}u4[Q 'zx[tzۆK#7rS6cmK#h w IMLTD3Ղݵ9œKV'#=eJ=,FY`6[׭ ce j.垻<c5[wI2{v^}7n^~ovvf^;]?>Y; 6F^}en() IBIT#X d/ek[vǜsyU.c6$48r@!jDtBn!ADF<:B Ƹ e׻uo{{֜c>SUl鞏gﻴZcgBhz1uld 1 E8X9|T>lUXǥv+斋% O}Xyc{?5_5?3?'_>Nt6۸bxr1?^-c]Y0e 8,Q)caaS 7o={OImplMٕ;z'J&k?^~nԵeN=D4񔸈SH74[4Ԇ;.{u};p`݆O ܼl6o}w>q"9wߝRZ˕+>>?+ox(GkYU &!&L`(Mo`: K>埰opukVwoK_Ͽv ڮe* #F89`ea9 4íqײtrŝ> -T'TDn7~OW[tܿↃ,Č)wkpJ ÅMTT0(c>yK;G"SWp6ڇEi_g/̶ﺘS>i5̠stz:q͢jױT+G7Gִ|}nVt8v6>2(XL08rBt*`]|k"JZe܂d6/VqP9y8D#QWa81OVylVNY"fLXdP\ JhL"s@)NBbFFH;j)(I0IDЕ2묕TD ^-@3:H1| 6jV#+h"3 8iH* `3xJh%"ri)I鋟=0xR$XT;T08\Lj9uĩ&Wf<9Nn6uY6U,L;eM]Zs&حg(\ `4V!rApI}4"'?! AYm*UcA`ERFD gR_8f`,ww\p47nrnKg?]_\Ճ7_6UNyrG50s]8X5?1Gp `FʀM1 "8-S x0R4IaqqRw? w{j^eO;Vvbut_$J甆fk'IS=߸Нh9`yNzػ?>xޝ٧?t^ #zD< )Xa-@J,̪SJ$HYL9GLmh $ޚ R W֝n:~t81?6FQI8KKsZVO6???裏~w;o?Gg)v6 ׃c6fYj6@ bIN$Da J*y{sS݉ {/~­aьa 0g۷=!43nX|c;ʳ}S/<<:P RcJ%[PÙMZcv:-nnK[[o=~ol=?~W^'?}U\~ۏ<˳٧oЇ7}ۿ^O)M8,\$LKN4@ݛASVzI93LO7kuvI&S  .ᢢJBFD]l|:88D: nmO6G}3/_^߼ 'A &7uC(1R*Ea"D ik}_yi_ƙGi2l?sb-yNr? jPͬ&)dL)pO/t‡޻G9b1he[n>zS$xb{0CT'n31~󙍔xwkq{KϞKlpRV=],BzQY) Zd4*UB9or䞅G8tf2 IđGPh @DgжR؂ #eI`U*>fRg*EPY!p XJN]Jab\SIlKנq]:Qkk46Zn2S =J Ldl0XV#"4i2zc2ɬQE>,0 :ST "NJ0s"Aa<1K3NeYE2[[V[=HjS7RtVRsKžf墒 ^|$$B`kr= -)Z, [G5l1s,`p 8zI %"u4icV;\][';lmIU>3"&MpJL1t9$`\TV M-̢P q&TJr#x#VGhǫS-$eA&-Ԫ7]J!SX|񝞞>?}|Ϗȏ}3O]7'LğLnQ<:9><\fYc jq6e,u9d.D,ןt dq6ʹp{O6Ν\[pxxcmg+%f?x<8WE+e3`'Zt#ڭ]-}"$·n]|&bU~zܹOQx/OvwV߿{r~H`ܛMEbQ؄] 1YM7;]oۤ\@S]#xAT\Cdylj; '&lZd jcUL$L$ck_^=']X3ik.'* ޵+Lz=_|6C~ CňMWPO؃Rѱ O9W-WwL"-W9Q G&YY0sE eh@|Ind_>|j!;S~al1QV):]I&$rV$""h`huQ PPHJLNř&.!fYL*`!qu P 'ia#Mu@Bɉ(,\7 EPcj]{#i9sIJlfIIsL );F(- " ܂(} V˵+XT[97kZљ:5;<qCd]U f"h$AUx<\TJ䉹X-V[R^c&j]ʨLdD@jDIy})b4ɒ9a-$!qI\[ TtA wq&؀`R7 XJ4R=hIa1ov|;;:r3 GϞa5twЋ/WKgwJ?7N$jܧ_qqcWƭn>/e}eTt6%w"sώ|zl6u.O9i1u %!4:mb 2g4#;rIa.p# lJA-B1OG|p?^s]eZ͓!H\iBptGS3M|~>~}]ץzꩧzZ%M׳ޘ<L<ŢϘNnh~t3FR 8p'fI]D0[mXmQӇC8C?B_,\JdQ>-NvRta~8O,b_MRc POA}]9=?Y[tW~~hOWkDϿ껯]=Ƕ>D&"~|f{|7OO K"P@MU0B5"BYYͫE,Wi;}s}Z}ϺfKߺoF\;k&SW´I% N1SԚ@Ղم[sou!9@ 'xJ᳾9;X/n^y?ݔsxcx!D4hh 7D!T$nN<4Ye/ޛfZJi"̺޹˧7G< +8,<4ĒFVrQ:\67iu3Tķ|3_9 ~˿sq ~챇kfK>BD?O~޹˗KUkM9ɪ}byR]qTѨ&ݐ15j>s咅/w6(y֯khmƋuMnrJ.fg7tY5ʵWWз2қ+n&@D%`­2A2NPu AaBߨǐ&s̫5MՁ IDAT~DQMU;JH qzf7gdLRb #ʍ ~XI($݆zTvNAom.-ʰ:r.ԛ`"*nњ'Q5KzVKʢٕU)pu](QsPac5{p hZ@V-5LbEapuCR8!椓<P8&Hf1S.RDSl̷r%+j(-kJX0M,"$#,qufhѹSm~bV !](D"j)gYFYr )pXRoLH$!@4'DL BxG< \ۊEh5m)аNbʵe"Z.u㋻\݃i9+w,h6;ċؚQeJTӈ\D) +3ZH"ʌDL]: O^Yd"F0D2l0bgkJϮ-$ "8] Nefu]j."‰ZS/xm8., C뷞YSE(@.@pg%L pO` Oh!ZXNP 0TRp*CAJ*2 `RV1 ^ȇۯ_]p6:^.66/\OrqTOU*)g-DOگoz徛Tu1v2gu$D䈐jI6OFͭ&W2) i 8#zR[;o1k1ش}查YGO\GmUf͓-& Zق)} 'G'qIe&x[c {0屈jk8h*kO2w޽PΟӏFJl6|y h_mO^ts~p8=zb`F*!fUUbwX4)o31Oj4 khW/W72iI;7U ?#ŝb#'vu0$ܕ9Z )6kbK/o88>Q܌#I"<|uf)%37F(m>{\}}3Ԙ)Zؓ`C 4k, IcIL:+ jMLt_{akg͔/ml{ 䯲8w}J̪f&N!BS&a\&cq8?%uC|>ݘr _;Yq~CWw\[&& $vii#b#z4+) ERY#N )9ɹrFp+g.V (0$ R,((ԌӢdT}fsA(h&2ҺZ' 0ez UJ!,i酨:;6-jk8 dI9jMK2 %IL!ת00iNu-sQj Ҙ"F NdA5Nަ}@ԵE[)d*GdIUB9ÃGNN2 Ve'sg HZ%ެn?Y0XsF`Wm}Ww. ʩ[̃}}Б2)v^_ƹ.m]6HԊEs;{W6un9|Z!XgNXwC F\I`̳Hɷ-mh%oM S!TEN9 yx mY"gtr~[_rsXw5~~ڥgڲ8.I?/TΙ>WFyCM:C4D8zymtk @91A)XISֲ;[,&[m8=fOcݏ\wYDw];w="NN=Z5wyc#?ŗNob&F LxV2qC}s^zHDϛѥK'nqǹf) r7dK.DS?+ r%CqSɸDScrafHI`ƔDLt&~󹃉 >]{[8(0_<} VIXfD 05`2 JAFՁI{i?DLG( 0.HSLD !q_+)I7bfrdsU*0xV z%`Q]6mr>C)$K{Tr*}4u[ZujN fZs2".ֽ fndRs]I2I$hpb"-I-R$'IxiMhç;Sr*90ýA#bMS9I.UM RΥ4qM9M|TjFKWd6zЬJL"mbY&TDRIye)0eG8GDa anFcĚ-T43KC[s`5 fN- MK`#w G y2#Hr X!L$tfRQ. J 35ב, *3&F $[ps'U3#v` “-tZ6jNL2A 'j{zw~Ódޥ&ٹ~+6w\qC\dv>*}Ie{~X\8=mw|n(n0Q DW&b0Z3 AR C({7b !IKCHF@0N}b}$J ;!ZǍErmRM~5mΣlJrj;y0\TYcj%1Svzs"YJ!L3{ J*%b+rQ ;˱AND`%'gbDVTGBdak[=ۼ^~L6sHNCN|^7 v;ˎLӣ`fUu3\ Fi.@ ULP, 3a`>YxL$*G>"%"EVI= ye}|q{G.=x13loyWɫ^:̌w҇?hg?WS !0 YE,FcMCsk"*gyq6i{Wyof'… ]q|}g>\?w¹łEDS DܙHX]$)yS$"Kt]@0|">MVA=S(*Llb'I&{b}r[{?U#, d1&om j +h%&,DI%ù-!f̈=H#Z$3}ח(}s({ wls LT4sEq4E8- pI2yP;w' i% >9čo+0`j'!P wFn!j^4/E%©lNRhkOKfHSILpskRRgIEdLE|N)pn!\aXc(B̌3O^R7iG\8mv 1X&a,FrpF84iDr:H[I1n k0{8WoY8  ;x:A7'rHr` o'MS9%Hߪ\7q.67ha@aa1:Z:YSBgeLa"'[y4DZr gNP #bI]D}`K"8ZSUx)uJJ)ItV.yԡ `qttؚEztkTgwĭ{M&T=G{uҥxO;]^:JY d-( "J͉BrN up K1XQ$h]fկݰ.s fqv:-VomM$n&38Nd< rG_{ɧnSBΒzA81TY1HzR_T5<q  "LTP*C83 #@" a]'z?y'n $s=wRO?{\xdOԧ·v 1W͒o<3*ڰph&*<4exB0mͮɤXuQV%@ƕHý"BgNNgixS0mV,[zG_}{75>h˻xC[Zҽ {!LI!XD1lK)ʌU)Q,2TR)'d٬XqIJ(%Ej(* $@zx{ c@qpuWuu}/}$}*5ʹg+ȇEmT;)7nRt p bh4wWZO,׷OOKꒅ2Mt"%ftMqyjE=?믾=ycڸfFM܅A ixhNDF1SJ1UfT u}xP8Ca93YHĨzOՔ$iңlm)6+c j)Z-2*X7m6z`%y8!77|G󝸫|ʆ V½"] a LjCѮ70qO>T KٜzZXrWrVSω#M&F%< "f"bj $j}'}HD`gkݖFаbիc"vSgo,zUcadJ`SeUHx83m Ͽ[/TVuD# l<>L'/oW[Mu)]Vrm}QJmr~3^r}ׯƍB1G?w> S2|?RɚƂo(= Q̅?x~G$~rp(B,}vN#$K(tKND$M(ugAMfp#0f%tSLpQX5'Jr۬F ¼U+e>NI,k@ۆYqjnaӔI8մZF-RFSfaRC=B0D 8Lf&)H]6֜{')%FBG!u22̇>y!fr$D 2Ld: T&b"G.Qtu8%)iYTa6Qg4@r/EhazX"&"S$f%2kܬͺg".#tZ+Wy|Zuxb;j/]|a~h˔"k)1ECX??x~upaN59;yfXr2P !: 2n+{䓲084`F$'!s2*'I]Wu?|UGS]3f4nV}g۷۳l GBMa0i:V"APJVgœ%!ֵH2 f>Q  =4MO<2z)NO7崠G@)S~gѲLgiqW+y"L '|cSqEɌ BDXmUjx4&:J Ȭj ]W:Kl/>~/FuKG-֩q/ګR 3϶wS'V}zk{ o=ypp>MJsSz:䬫[m{+qgD_|;ao͆.̇8?""s2`@X2I g"t#q0"͌)|*ѲwMw"]׹:rBT,XkmUiRQHD/V|ki/>@]?y"t]Yj)B,"j r@HK}nj[ݨEoazQ]{eqb7C]tϠ r '$3ɭ@_A$Z=|KFy=]#VQuѨw=sJIDȑAίHrG˲.߀K`"Y5wSyΘCaˑmZkZRI; &)TG)7\^stizd)ա8tɵ٬ZlbW{\~{ W<_''_8#1b1) 8 $p;-SaT\B Dlꜚ%=SRc:ڕݘ k Tm@0YgfNµxzw's Xh5 5! wzlD Wf2s{Iz%@iᦜ%A$BSa 8H"  bPnw_z`𚺎X8Hjid{g6j-Ԍ1tȜ1ŒنΫ;Ok /wƍڂ 40_y{Dz\XJ](R4"jđ@^+ͽ: zs+/Ĥs͸NO n6ĴtR<0ޅoxrò<^ͫJ7xڜ20! :h',uOc߿X{n_W<cプ}>]B<<f- UH y~2$6wxe[m(D"LjTx )"p'859<.^Xߚ_şoU'aʗ~yYӓ`I)"R&SgrcFI"IYB(l2 T/}8}R']6"?<ہĎooy澚p$ $f잚8I$RD2G?um~hl`Lrq;=sK~C{ir>Lю ѝ[gk90'Z`a㘐 ̒30^+5N^hR6B;xf$5l,5XkafRܵR")ࠨ]7" (喏#(&=Du]8{KX<O)=8Hd :bYb]6},3棔KWãJ—m?<;=] ٞ/fuk6sn?ܥ/8'_v8>ɑE5eZԈAl$3F cc޻`w ( 'Zl`!&T!e rfuKbWr(adaFSݛm_ٜ׫I|7Of%7L0 DxqRKnN"DRP "S 3 AIܝ&Ρ,h"!%i?WVg-C C^^5k8:\mxAM6_fl⑇E+9ޞχV5"bR8qN]@ÜL{YNAUqo[E^տs]6tOoWټ>uL^kɳ7uSsRLxCxH`3UlOlfiYSزiyZy7~HJZk~]Wv^v"3Dau-Sղ1il$vl›rN暂&V8;#J&߰Y`c<}6ts*p ei jw !R%ye!œI*HrJ$m99f|]幈03 B|nvrngW/2w) UX<$#B5]DR &&, frG3MXuо(] JpGG0^vioXi֛#0r˟~Go{__z=N蘋 T44bDQ+16'jLjz8ywa^!C̫xS<U8@"#*glWYrγV,Sx7w5qx޹raXGgӴ*KRq3SUk2A><J_vf{ox=7NweL׮3}ŕ>}cNk=ی]>nU3b3"yXpJi)݅.o7䣏~+g}/b6NTtrUe (s(̙9@fn "l@+b3/I}}W< i$"M_a!Ӌ1;H G%f@Vjo#bubrw w7%r#rHg}y1.\ q."y[0+KGS gRO'WBJ)EP "upˆzI~_3O޼ׯm3v@^lt QSש[%B$) z0FJ2Vu t9kWdf"Gb`27ZiLUǢLK3`" 3_rQb.I0s6) sX0 0 5MqjH H܃"%M I{NJk% 3L4WZCI< NL,,! } "J))'V%JB(AΓގ^wǿU=w<>iMZ0FS+QWxΨ} |6m,6g'6_h{{~~OսHƓvAko|3%A"uk9;3L$ 0YPL.P adkʑ́&5s Sb;-. HfF†qcQ>Ba6x@XU#IB(L*f6RpÅ;17L1,%'QWq?+*\ٻ+Mpi4Nj`oBs4su ?Eo nn~&;ONFDTР,=MLF2@㼚\.w.\6RJ[tiʵwoo-`w,2!LZ)DZwۇonKjAYk=W|nφ0}[\OMx``G&^׺my7iu:Y'BO,L"N$!uQs:A\!`M b30[rONO϶/>,fgG7ƳC.ExtҢ+a,oνg/!M=2],|ؿO.On导 g}b굝{}ˣgof ex'f#qX*u$TMmEzf DjFuQٽtd|~'(~.0sC#Aq4HGѴ9Y+=A$u Hj:<=͗+^{zzrxzc9 gM1~4t`I4'Oa1$UE{{4M__k]BŦ<+&Ju%pI䮔Ƀ5,B^(`8:3z yU@24_W `uY3\Zz~ۼ/6ij1 5]U8̵벩;)03bjfa K[+{py[mo]Z#EȔ 5\Rv:UP0l7\W9`ncYKW9[-&e]~~[_5=\Z[vs6eásʄQ' 3r`}7̺ݝ.e.?/ߺzr>^z" ykej/{ǴڢKĂ.3NZMD J egېHV`v7EJ"q+@P9!a0LtZA&yƎP03S *eKnCf@"T̈́w)@"C\'Tx4l!X8<@9k ߉D#JH( ,?ԳϯR/u d3uH[ƚKnB=lSNٕ(FQN9nrn~~]_%_qU_/uGw[c;_ey\ 9Vf,Pd`"Hu0*);"1$F*!̑LF4u.20n"KӂrwK߿;${Y+0IcmdͲ7HORm'5^J!_L 8.s@HsIaSJc'n,>[{Cvԟ#e_c .<ӕo?;WY_;=qvm2yEZ?zs\|0츿|-DHI@.TG84 f1&jZ"B؝ 0sW +( y;H,;pj:FS՚h=N~B$rd ה$NPAD@ZUs`@RC׫w,δ?ƘsEĉKUfeV]t-K@KXBH!B-Hx!-V-|kcWeV*32n'{ys{9i]5!%M3SkE) S'c2@ʚ^ח%YfDDQ;`+Pe wuNZ[j,i;(_$.Z @B*)A|l{gnD2 ܛ2ݖFȤZ=PJ)}0"'iA@1dy$O؞|}'ߞSX*m~lI|ėgU=^Mvlh {yC9.eWܻca}kho~<{;󃏯>/z11z2 t eDOv8 t%h,k_0BݳE s IzD!JЈ ( =3;8%9%%+М06ܮDӲٕv_zGxtu*ɔDDF tgN"Yݮ @FKd%bͣBn!CXS33A'(ND*ʙFk7?ݦq Q\1lJ- n+ab@D=?;X&!%0zTqÄ23Zfe>zt7oD! r- rP#+gBLԣLU)+{N`KD"USK x'@gB(@ S)#g_pCvK@8@CIjhY_[."XQ.fݒ1ddD8 F'xxe(E\v>ey^2[LktV;\bpi_?Η{F^4t*.'=m{>EO.Ӎ0"}|P=Z/<>瘞˼p$sRE &" 0@Ƥ9}͌A>Xfi>Swx0ZJ1)J:!$2 ۲Cx{o}^x229̕X-z1%LF"ݡ5%hcQ{1O"=+ ':A&R[n(sB{-5#6Z#E)j|0lsx|8x6ŎK?曏RD"ɵ\9Y|{G ķ-8,ʀ.EX, !*LKxXEG\D9r=U˃//n8[o|WZ_7?{d9(ᷕ>pPSP7nZ"<<2kaAIAk_HU:R{gۯy"Cua^ww ȎPO@ .MuMe̷RGOK/[/Ŧ g CRtDFFGqO6_S8THK2" !Qj!Fm7f}^fqsǂryu鴩(r[ݍRζLxXn{29m L\;xeN%A}G 1X&bAԝ(wk۫;Ҋ7MnhYѺa_Z3TaZ$ϒ/1\9hLd*|gmП|fywz|S[&xۜl%ӏ^u_WJiϟ_Tӛ٭n~wGtxk׾[? Y<=I,8( C P{Ǐ>xzܓxV7 qm߸w4ZLL1p0eT $H];f(;Vn;o{WϗqulMpSveb&TO$*A 鳋KًmJBm󩞳Ko_M+CQș}ߚJF6RtSquJ֎Ks))tO/Γۜ}%9ٻ{4pA!D) GtE\${Zx@>yZ=Y"pOKa)$I2K+srb[90\ 8nv?^?99Rzo+3[;ۂ7j)~Z/rl̺ ܥpqaPfoZK|DT*t\i7 2߿8=?2RPfTExjTDDywm7~y""ƒEh' JD#.C4DdF8D)A(\,F!a~ϯz;n7i-(DfqUیo;W8N6"%Y@JJKJTLMbP*y/U PZOPj O2*Bsˁ r's`.N^8@Pq.=2/ NaږdI{: F"ov/;N{>s<{ļ?|7^]/C>gry,6NFp'Kl[w7_ q8N/O>'߻:d9lD H2@ I,iQx(##̙I ' I&Ll-C3=DU))$ dQ{ 1'B]ie|9wTY#+xu`D ƢIN؆ j}Y`A hQgkB eJ/E".y:5|M^*n7IyxrYE1{{lb{Zlǥ-ͺ4v( =laK9eҪ+G"i5Ng7ӷx棃 PJ sq2Y&B J)'|uےk^DZYX5rm4͇oaI{%`^yI:v(ns65BE0  [$ЉPZ J.38#T,.L0 ^j2XA 3lD?illO~K,@ ͻ{EU#AF{JĬ DL;s"9 j% E0<=,e xp J"bF)m="-^o$`ǛiQގ9{ fUf E,CZhTk00Tv'7s}{.8?9^~qç3zچ>?{MݽS O 7#9ZZMke# ȉ"=2eV\elt#9]ٝZs_A0sբ=`~7UfᡔÐ8 %e8Xg0YX(+@* 7Zn$ʅ#{έٲFAjHgReQ>l>SN"$]SgIL0uo~k*..tϮnw'fWvPWol]p|f{8^v~_^8{ֺ݇??}uxsHO5fe5>㞅ܪEDղ*)6J&-@`cgN!ϙ$%%l1hX%)AFl X6bW;[nS/_즫0 Ȉ[I"$f(3 N*GXjKQ AW)$PA;)wdq A .kS)P >{Owwat Cz7ljzv\9P޼3WۯyR t8^m'>9پv1Ϣi\g6yRiKtkDBJUs*CRJHQG;8Ͷ~?yƒ'chLQ, )ZBĺ{4sn˕q⬱L'j⊒}܏lF89<瓓3˛owF?~G׾X\zQ!t3 =}c3~?A ['Lƭ\(t4L>E J J^qlIHXBQ,9 "}1@ D:JlSoFr>B0eܦb\sxQ*kFGHN$D {s".+ X#WtKJf5蟈p3#<^ sx0 ',!,X.EZw.\[)U={\DHdNcX.hylZf̚L92-95|P{+z_‚(-fݫ '^A^3({Tg"n}fNm`pNd 75E>#;RZzfJ_YD!3t=+I EOy;/;JzB(B!"tHB`bLe \292𚻂k X2 8#x,<1ޭӫtP JN+~N!BP ȲŃP@a$"k1$Y8+G[33jn_L?G]a IUJ*)ʛo ?{?]_Nrsu=}x}~|=* So>e_ z}7C;/oT9-t;޽3\_Rc!y陽EDB)FZ&ntDAI%ޙ"3ˆi?fP2s$3SYf0kXוuJpB[9*k‚,@ ΌД`N!A*(# "ADҊXJ=IHObςְ\fpxxvI,SHIHEiݪl=(9XYq0S'&qFY$Dxd$H2Oܙ·laQXOw.va:MMeLϔRo;e(tjfw:1q3  . n0u gFS"`0qʺm撨)^;A)]:rDp2nFDD!B"eO"f`hTK*YhZjRU "FXB,B%r ̡7/ >YgTA*@UK)Z e$̽II,@%H(RR2%X*TeaDj @ D'VMJem$(陜3 +j\ TuIfnݖLg()[zHbΒH ӠerDqF%!LOo#ɕw~gfeB2$EVM-H30 hԛh@`ZREٽg{FF=[~R֤x$Č]T@'{矿Z.NK[a^Up}í޼98B-0 (gߔEcY+11TYk{6\>ӓq~0EHUxŷjX9R[}$niƙ@D ADr~D ՜E!2eo\왽c\TڗB %V%>o?/__=a%ۓ $_ӖLV7 N6 8MiuLOٻo>&a__ŕTF)nW󛯏YU40Z8h&xX<&+Cehz5%pLyh=aTk%ܼ#m_\/0 i}6g . R-\~~yQORNˣ~jyfRrXӽشDI 0)3*MFȒlMϞOfŷo;hBBLH;~'+Ae>3, PFzf/5s- :=:聓"M5ALG*psN&`L$S"FHRdU =eB]K0szSƒD5F]D*n53= ;^G!" ^,g[dDglѰ;0]`"@ld4 Dk-`tx&E/64$?4YT..O;mvc7MIX<[FB=IhJ6t=])XN[ IN"6$0(eږ-뀌ҙH51 TDɐk%⍬j:3#JH\ֱ˒ƒW*eƒ E)EYH@$6 AR$9M4T \& aC$!3#e#]ݩ:P%xfQ+l#0W[m>Ѱ`dI$aܖ28f5ai٬5o4$Qr$|!.+q(å//tb4u Y4H1zBsO0uKe*Ĝd܌,TF%LD&ZHDqPq*L@<`|ygf5a,E89-^T&4jIDmЁ*(=&tW3;!w~h+BUf^Ǒ?Ik3!n^e,Qj $)8͗׃O_k "BS\"#%I*QdhZA͚*ȌL {ewpcF231TDn)B-?ɃIl!܇3ΤpatJD_ Oɿjk˫W/~ڑݹf6rNov{"ilw+eܛp/O~~{Syo\SSٰs! a˺MȞ˞t ZEdWEK+';YJtrqZ(^~fnYoojRR't4o`A,A,‰T5'[~f-ܼuu{b XoPLj.Ny#[; eF D{wÌ/^޼jO>?d00UQP8ɈLBRX3!D22 $"0#͙%A&3RӜΒ,R23A)DB,A$ ab.;]` Zrn,#I ?QaNK\ FJYx~Ցddd A \{aXD[ש~|isfyỏp^3 @`P-Bw2.D"}L"A>]b"3<LP zi3q2ݤ*MQPY%Uu8E YYSHfe%cJj?B rWr_Bc YZH&.!(uPLOS :? BZ2@O'otgNrT7^%H~''@)%` QӓC&MRd=-vg;)"NG2ˁ"BLfT $ cP 3qLc#2.ճ"9tt䦓P(g AQAF)YPz-3A." d'2N5Xd~LRd:Sd:2-Zlc + Zt !e!HɒlAʔjD/T5זASζfY+<}~afO(@ADݠtŒ X μ""HPaJ/Lw Bhvu"PuېgF`iڿN}Y $aJekd *$ݸAdi93n2K)EpH0[L Gx(R(p ¡G8HJ%3Lv\Lƅ`׸1~08sL`gܼZ^nūׯ=ۜ>ʯ^\vydyipkve)h?~u9>_On-֊A)6,%$308!$qdyy=3 Zľm $ez) ƻx(7E&EQڝ{2y?Ç;?|x$Zo LcLeQ${py|)"!L)aerN,ɾ@tL*`ݧE9 9J`V ҝDwNWߺϫmootyk;ZT[6\ka{r*é0oFXa3$(u:wٝd:1{<^ߟnn:?zve=_?M't0yՋ޻'xᣧܻvs'Z[Ü4h+S8 AfÄ!9x2ک` pb4.[xIrkϥH"P&n?2{7ts~^<Àiwox|eD(3Y;-ao{\K$Hwjb0z#% Ra |g,0'0v՜D"]r(ӳ˷ۿ{T)ˏbXn:Z{랰5ݶu^݂alW+\?WWO>g} y\WC6'xr:=\-/n~^[XLUA¤BPM2IaLRFeSN˩[7hǹ @' D\++`?ҧO|~uՆGG۽>.eY7KjnAD'ZaQ97ʆn?}-6rst}΋ɓ/~7ZueEDFܹaߌ=x\ǭD<`ԍ5AJBtDL;Q!L %zזv1HC]{{xnJOd_$1TN~\&H 0GDG "LHw!̝",:߹E đ DhÒ^`8U;1R{L]-d $)Ɓ3qIT`H3,m6[Є©slvXL0ʨjmu[3Vku.nq]ͼe#f'ÖXl NNmU"AR O #x(em6-ҼU7@“NlY% }|8ߡlK:dʩv#z(ㆅs<~;ի zx7J<{D[w~Z=*~r۩̓-H:H:3NoFD]nGԦp~ ľYNaݿ7g9Ͼh83=v>~=, L.rޱmKhV^kqG.i,ƌ@ TrcT6P#Pmo˲q<$!Mrxuhl\Nwc}u3cz54VOtݦii wO7E~|t?:?}寮ڶǫ?^J@o-s"ܙHМL<,&;%/)gbX_ڰ=jʣٶ{'˒EyPf\jly{><>zg/o3).a= 鑒DLqP>;(T`Y3 C {8$ HWhp[(;9K ݌Wo}uu&!m/yqt4#~I#Ȼ79s.ńrOb"a6E,tD8ښQ32Rzc5N4LĈ9aXLiojϰ eg`ݜe c+Q`nHـ-㸳` b-xƁYfʁLE@l c I $ތkJY#)BhL\U rN, 3%gG )2f qgO+C S ~^{+9?8Ӌr;;LĞNmH4M_Rש)u~TF75,~zyx;gO.-!iߟ6eY|Y'B5o&77W 7O.q{UO힬Sqywsˡxy{=^?xTVq! <}jz]Q*YQderR"FPurC%ALD dD@$C D⤜Ž?,Qa1l7uŻlXŚY;xMYW*?a).';|u0-g_1Fsn˺P!IƳ}M1[goQ6}g@@ںjm=1#a.{XVo:eͨPZֻEY{2*" uwxto뛗WfG^SY)dls˔Q4Ngӛږ]}h\k}Tխ*VI)jeQ @@dCJ$Pq?<&c lKN =*ֽUZs&0/<{Zs}Yyvt}7Q9 %E'AnPY" S",t$D8ÉA@EaRKҜXt*d9PqZW$PE0 /#E8tk7.\< b7ȣPySqd D$;ߜRB,*UND EPXfGxmqSP%dB@r";K%[37@sI-d$(Xh UPX2+ ZP<2=jIޓ↳NDp"2ͪ ZuwM܅>+qZ#lu@74)Be ] caՊ ՘Щ[nHRGP@z3J%`Y83,(H )Ilfrfd%UZj*\ A0#] p]#LPXC4{;uB*hӷ}ޚ!ZOB%tO4 EUHja޷; їY?d yBԤ!13wdWa@Rz2AS9\ SU3k(Z[R%G,DYT y [vOREG k@fB3 =yP+RUSb%&Ąd.:0ER]7W>_߿)%!L/㧧G")m\qڀӳfjܽ:xŎ[p&W~3Ӄ%iNUԖTEEGjϺgPw`t8Z?xLR/׵уǿ/=On8̝npO^LjJvqx|u'[W"۩arB{r&TC]EW*W 1n-pϧ\{rRPK+tD-9ͳN,L [ffjGE[J si 媎z woAxeS ;֣dDRM%/ŪE30{$0K@D${rd0kRz&NI D#0P.ğ5X[ dB)2(kHW院522n@7 g@"(8(, Y>%VCEa2-uϘrLZ"’pʒ{e/nƅ" HU@ &J!μAb%Yzus4RXfK^T部'LZky3Zd>l60xdZ0'ܱOdpnDubW&@*JyS*0n>O1_K&<@b$cr|ZO"krRN.1T35,,#Ape CK"Fdd'1R6KqrD巎$BIvB1!B,% ZH TH[2n 6"IS[BեSZa:dS4/b@Xg &!A iqV/MqVJExՒrhwaA$slP+ܐaFf{.1.3 $ EΚä IDATR܍*":0DKVaZ[i2!X9 CF: 8"Sh¥=an@GFf$/JT=uXNr(i6&9Ô[eYG%PJO}y lwr:^obBiWa89l"Ch(d@\ J|?σW_:V#G{xFI !3)9.Z<~ڮYϖCYNf'+e/w>|zٔ}3q4!bxᅮ/=*{Rh.~»n&-WCA0t4XWɽЄ)#K$"L8`$,@;xٽSZKb)bgIR90 `)]Rd8PHLR*qwJ"?{ړG=}b{A[Ү8M;mv:HHeXӝ^O|tK'/g7Ӈ^KWeD'3vL) FrQ7лkLcwݸg*yvKn7ui׵dpdyzm -Pz6Q;2YR-kp[I2Xu 0aDE1cSkY8" .1rfɺ^6#n?>|^\ן_۸އ9s0UtUg&aҽ9=8XL PqrFx৻[$A[ ,DxHW(" L`8d!,JDd[]F TLtӬft@ ##:ݜTPka%GLDCqKMR'@T cEB.N  Ñ`pf""i=Q&g8,MFI!s2P0 zDqf[dd̹ezPD߽t*ޑ+YP3BƲ:Zv0d+0% AePs!b<S e eQ2EdJ~k",&KIIEQө7G-ȫ35p/$aW=„[r \r?ev#S H;a6{HP&fRqхSj- `٭WydDBLN,єnHݜ+[l=e%1[i`*HXTeE+"%нe5:ƺYs"#IJF–I\ Ó"PeS_ާә9 YnF=#An**dGpb0̀rȔ6IFD@:QfHl1bԸԳѷ>u勋o}iyn}&]]۸&{6ǵ6k\yo-χ|=x /}b_k__ow_0έ3Ng%g)dTMNBy踼G^F'NNᚄ#0wcJB0X/'|7/ݙw;)m&-zu/>?#qO?`tz}vm5&d3t eIΈPsD0dFR0 +I#`-z3cɌ^KMM!5,;Gj< zg/.}kr=M fhS915ϼZZfn6a8R֫ռkn˾=]vm'}Pכ;bU%SF4I7:һ  p /x13K"X.rkG38D4K@jQ`PJB% tbJRKfpk%r,^aJIf82L 68DU̅S.$iyʾ)-J51wF z(JX:Rއ1j8y7'eNDь)Hb@qR kQ08 [j7PDΜ FBL>5/ET׈G NC<qaMEE3Q [__{g>^gaNߕmŶztxyD; =Jly%X˨zhݳqw!}/_g|խas& 38{ *A]œ XTb:l$ڮmډ[s札M$9 y!#}ӯ^~v<\q_j0Ws/-lzois"ڔky_l_zѭzy1+PNN伉.r. hEDd{B7b>@B M05W(R4 pe=?:|xw^lyp!>S28p-#Oi7޾*JZQj xl'm?궞K{݇?Gtx[)% zs^vlr$KVfY(Qmq}ݹOvmP+XΜGڳmvh1lܚ +ݮ`%yS)I-dȜHjb]'"ZSw"1'W;QfKs|yX׹нlr*j2q[Glr;;}f8{Rh-A)RA~VX VS#ADa@U" aY #ID֡6 ȑBȪaR$"s fZ) %% ȄOgAD>ް8۲&A날L KO6${o ,D29Y"HP .嘘lp Ru`d;21Ҙ"ź3밤.JPTTS6CY5mNǓӳcP64FmRIbvp>H7LmuuRI` kX v[e1[ r2b9S}6 Fٻ 52N[^I b`fDJ! 6Rӌc!aT!B{T9z8!g){,~ll =Ur۹5H.5R<#2LrEAmUUj\VK&Y `eu{N" 'f"kC*3'Y /z4|s Zr@AYx;ֽs٬(RҚc"y]M{X7VF'XAi H!=+o(׫s/ErRd7=Ǵ5<[2{bu|x4w.Do˅ <\(EHރ ˄'g7Yf/$Y\ZݼwzwdUpD8ŒG& fFx" D~#W Xl\ ܓ1XZG2JuS#SÓ+@BN*UD)}ɪTdUeiQ (["QIܣhh;B7k)E8SujvKƎQ( _&F…"L lfh]pLKͧ?*~gI79pry}8 [esk+F}s˫8u( q?|E)q=ZO6 {sj`v G:Έ,qY3ҜD I߯ݜ>ޛ[gv=pxlM;\8eK~tvWdD&LDVH5 8($J7ITɠpû%bLɴ:HϗIؿ'+gެk2ε>Eӗ|:nF հd8IC2ZW_I5DJ(Ҩ,uwџHQZը\}Hh-#$ $DGRu.6o>fN&15|gCǡ he)nm/6G?ݨv7BIN,iJl݉AS@}ܙl pbyب);a e@-r"bp"9 ĉHIaL9ECEvU8)4"A!L"D "LaGZAl%JZ)EWc:YZ2X@(\'%"\HBHf1wSa!ITiAAĊyq(J @ZB 8,9a^?AܧYthN#F7*[Dݯ~j>G%r v$ȅPQ#6q4Vgj-Y }Pj7:T*W%"-2L08,,-Pgtg‰ (P sX,${rIpc B؝A< $T8X9 s$4dx 9R;-.%k=mZy:$&2Gw;eQwcZ70ZM$4aڽYkVgwxE%(fR0[b, c֒IAXR>K:,O- I;jJTXgIK-úʠ*0DYzw%vNoʷ_g?n~DVUV6O7qu̺΁u܆eGn;W^꯼J\/w52D#C*J|q}~ R5ٙ8vm>|؅ǎs'e(1`ZPK!lþh;~InqMCGg혱tz-AVC!Wע-+PeV Y=֧}Q=\͏Ӈ⚲OAv\W: GwVͫSWǛ+ol=i//+$T8#)v,EUJFq|vvTG_nm6o?!"yP?;s֦m7ݘBZn~Gs n|a 5&434IXf5JfF$,.7>&y7'WGiw}W쳇'eBËV(0}2f/5 J`,\䥽NDq g8W? V_]; 3n~7~ `AI8_ ;Kx2#((}QdȂitd63Ճ3HZ(ZRqOi>췭JNT#"-Vݺq!˰()C<;!ވq=xVǫz4Rl 2lTs1ZJͳ[o9#% F*n <#tCd&Tn~ )~{8t3M!2#={zZ;0U"Y28ռ|ر"bSl\4OF)j sFKm}^$w,1SX;R@Jx Y%{RrJԨrea`٬CYaLٚuR=mbs0PzYc^;)1"Z%1E,TponЂRܒarXz&`Rn8KOq2 " ǧ;߾>xmwWm;=~W-zzxRǗ{ gz֓ÌlۜNO>zJޏeD_ko|Ͽ{׾ޓHdfFPHJea6ʴwĜ=,-Yũ81Rh#uƣ1: IDATúKnDt&)RLʖA5WT6Dڥs|ϦŇ"yyn pQ@#4 Kw֟}tȸ\l"A/|0v-{ee]7! ZX$@$ɸ1%!zK{+Y$yhq09ܮwsvW;K&Y;JXNn?u_/_D~ݽ}.ҫكy{@ eXWUD ˘|9wtK y"h,(Ai9?w>~K?QC3(,"L2\jR8˿ rdY6e뽍'ǕrOߋSSo{oRO6|+G/OɃo^>bR%̌4 @O⯼Wv>,.$99o~_k_[ PO_"$A7|wS&L!.#NtE;_;'/7+>?GYX,3Z\_^{eYf鯿[QY\P)̃p0 /^] Pd&ofaw84~v~EHtDRϜpDgGNWܺGJ49dV5?4첫󾧵>S]Sigag2(Ӟ3ΨnH\ YfOr/m"73d (zaTFDEfZBP $€Ȭ;R(ׂdm)cW`xd<I&x M PdT=O2*jAЬEsW HI{ &P$r+Z4NS7Z5k6d=N2݉DQO63T0p0$餵>0F&F1 JA𰪫P!Z-m\@5 zQ4pT ##cF $r)I *UPt%'^d Qb$"8pD S?rĜ9!KF'a$M\qzmx|]˚ E5310,UG+SZb7&2\a8!bc- %oوҶcs{>uMwUʫsC%e.Hd(Es $znb*- 1:i,j;ib.(Х+.XQ)}Qt<(f><UXJ8!Fj{dd)bZ g'ޓ= CAbD $`F@`,Lƈaf=z]8Z)N*M(y1cP߸p˷,a ʎ@-[얻4yVu؉LJg1pZ:-e wK==K_ri0]k2"2T 08T39R6 q8"x q3i0gmAthúiR״X&wZIQsk#{S[N|wnyE|.@QVqanHև3ˮbEsg7&&î8t-uӸtDEKp)6>|irIIGoprկJ!Ttw.g\rW\öj0yœe@ ɼږSw>OEsܭsT5SC=`߸:>k3h0ʤcP` W0f7VC&,j~ȬʊZW+fLuhT W+;n ~ϹE ֳ(̐L!D- Hf+& { Bq$C'Pt@%`ijFL 3)+NQ+{%|If@Hx4DlnVZ07kk/,Hsoda"fA ܑ32;e@At'UU)C=ѫxYՏ=tXT1V9g7;8Y !@&Vډv-p8rGa0&Y4M#_w֕.8wmE7?ip5suD%O&݁p5I**0H d4Z; "bI}H4Xx*Jpt]m%ef-v<'ϋ|/|/}u?uږs++.} ]sM,;? 3pEذiqؑ~O=w=V咻\Ӭyym嵦uck'jUuo í]x۰ys_89r+^F_rM?~C>+_w{7ƒӖ]t_[{3[Eb<]>D4WVWfN֌F< lۺeaׅ=o#Iw]*&Guw~,`)=%_~hH fJP .@[|O=-ef~{<ҫo뿼?u2?K._ذ;6,s+^GylFiw 9>n|CjGϽ'?7^Ͻ\':c;Ϲx_'^~?{׾Bl'}IK>o|/!|v>s.uY|sx^W`vv(`/}[wz0~'~ɛ~񂫮}-g]tE3^G,r4{ڢ dܦHyش*)A 1) v(TfV$ֵ:@sbp,~!ڤnfWH 2[RBn{2?(MGH xi \;rpcCt-hD R ̬_?wƶu<. m`~I锏pYQbP֬Y5;FW1"Avأ. HOKf]X.to:HjI[R5c&4FAbURqFhjOQh@@R"et@MfU8X Ud \@-Iaq$/ M$DFB2%bUc& 8ԁ͓k'R X4֦LeKm:S0Bh ``L &rw d #dҗ!cZOѸQmXDž#{WUd4 p2Z:psp'Ńİήp]w>麵i㋫z| \G\ `=95)V8l(<& "a<8wxaaҡ}k]7]/}0,Ĺ-9*g$#"b@^-jP\A5#*84R@e%8%<O;`%'3A,AL;2FG@"^X2!"#!D=DA]P0E$28#r&gN}vF <7Gb`ΎWveiq~JV0!rFFy/ Y/LF @ ) S?p_i޻y۩}.Gw~+_/|_o;_Lj`0=+=K~o޸MO?{@D}#!Ԇr'>tMo9qC|齏'yp]_q/z?{շ{E<»/_;67iN w|}cD W[m]$2 Gw+]ۿ?h&ܩ'9Qns%WdV3 lCŀ а(Ji}kZ##lmVF/dw>mMb Uw6p|ɳy_L H 3襥=þ8CfHqL] -[6W!(9sb*qfPkRi3ݺ"3l\+*dT8:d0m˥+%*@2XjDda#J3q>aN V#T*tE!iB cbg=6HIGl”5F)(\{ +OD"8ƍKr`meeXzf*TM͓18 8IC gfӬVA, THԹA@([OelNV̒Av@lMA; VL /n| _#FZմ<˃rSfɱM-&٪NVhPť  PtMkCן6jҮ4m]#疻GhNM0D4`BNQMU "%yswrBjjF0QՍxAbk3s CUHpqGsu~굓*fYH֦S[[7!$:ٵ3!tb΁{(UbN`GWFD ǟ9 2鯾\ȽS't4 \3vI>4/-DΡkѠhv4wi9YIWRK)DƖK]n:YNl+R'zvcI o[ud- LSvڎ<u`TYJkm5F&EPVA@aÂ! `@[Ox 4>]GY<~YLdgv_u "DL̬.$o7۶u={)ZnetCOs_(F#źbӕ<6YMx')+yd7x~塻n{gw?|}B7Q{e>jt>H,fi:Y[}=/} jD>ڵMUj[KK}=K?z;~#Y,?z}fGwLMmܴv#+Ǐ!)qpϓ9%*wgr=z/uKy7ba" fUNhiX9\JC{QWҧ .m\=x/:q}-|edv@\ Q6;zd3l?~-/ס=?~LN;.cR+BYyOoέ߰y <Ƒr fˉDPͭtL #BQ\պ%cZ@G2 wP2$ӄ2O@LM V xP*rxDCaVJKqdCVYEMbVLc`HH; ,*#BZE 2Bb@/dav8_7So^7ڸ};m<ի!zL-R\,".q2 @wmϷRJ27lR)L.)ﺲPB4[ʞrᤆU,3v-^:fjjȽ Q5YaQc]Eᰖ*DiL0iM5r@BGq~q CS<013RF`@dC7W3W%Bd dZK[$diۘĂPS3$D 8=#FUSFs+h`N.LnSqHB Trt=.K!Y{I8'\TL ݡ0S>^T0O0=ek`iZ9Z`@Pt& Z?0+Z`iS~Ѷ_SzZ=q+{gy݀I0bg H`h5I;UDP\<EODMTS,Dx]^p8'QEi,1FsϣYX:xpi&՘j*L[6 VVtcGtD؁T@( 0!I** 2wj䑝j$w"N¡l{Tu1i7mF(W[KS%R Fe0y ,Գ}v睻3^uyKoK7 F1ӕ%6ͤ``5j$^00:R)P Bjd^a4ؑ)椓65Xf< `Dh!TĻ~P EI.`ڤ VVbnrlܙ];/[n}9t8sP:v00TT )k!ʁz2 "z@3W 2W!3vM?7o}t0Zg*± IDAT@!#')sO<3?~}RգژHz Ľ xmxܬJ !: b8ɅS?qw>(S8~yP֭؏UIBxѫ_/ZV{˯ۇE>~HNEXV$Ff )wم^7i==?ێx,;B>HdEh/`FbD!HYtX*D!&d93(DUV 6pwD@R:o5nR*pc BF ??~?#LBcj6p}Ɲ4kӍs_N%wEM38C9,kAZk!v*"cUBPQ@l`Ժb@Q0qAQ qy_VP 8:6f-nq@s$+fl=;]/NFLt!Q1CTfd<6c M':m-3H s\PD cZBF0ZW3ƺݐ{F9 @7WHXTUj901SyF"MNm;ݍTz+2ĬdI!#An{>&Th "v^ )n\˰ K(d:0g3ug%@M(TP`P9y8U)ܚ{A{E!P @n w*&;`Ӓ :Y 5<0`3Ӎ0P^i un'ı 64F3uf1H t֞^ dq03ɑ 族r7z|iC ny\}+{~u}wFE )hg%X)v1#* i ,AR)gbJHHfj04;iB_SDd NF, Fq8+j8n\\正'{Xn]1C ]ѕƍ:;_f@'٭T"cЍ%0a? Dܝ{k9p'ޓF !8PV-Nwic5Ԯe(#!U0uYTb cadhv]2Շ6͜J#z"Y@ls0\ٰ9y f }:7;? hl83꒦5@ rnƮM"vKN%w)񫮺jiqiر#|?xu d^y֮_ l6u/ T QQz斛=w휻 <p`$K;"|:&7Sf6 D6ng]^xKѻt5d鵯iiuG|û~3/7?>1Di sh&kk\qͽ߹kt=|dryK~cOUʑ?c1_]>z>N1NW7or ^ݷkQS@W5w]sKolO6ksɗ?YVM_>$F$B.9bIr5S#EM[=W|/deמjO6QmIUKשygeiG~׎:x .~;`8׼]{{HmIw2£O.={tО8||w*˓_irt07dKa$JKN{b9inX"Y:wt C5-ZBEMfvPGB5b319:79u}s(ƃG vG Z\-%uB#PBPb(icN])Bu";b(զtm׶,h fu~^mW3xG|ok֭Wss`ozo_y˾9~p^Y^yO x].}097]~뛟=zlr3gm<ԧ^s[ruoͣN<{o-|# D( Hnm:eӯU˹]G5eĞ\Uđ|˻vu_;3^?r]ػwו~3\q+]O?XU}O=7Wd7YvꗿXŽv=|pس0H uno?Zxʶ^|勞=|hRG׼g=片vپ'ɷ/zm{+N6^9|]W/K !چ[_o^ذ_x_A3Ɵ^O>.y7\~Ɐ?X)'^m;|{K__ؼ'}՛6n~ymDg]rY^HO"iAE]BhsVۜ@QX;F%,2sPCb ǡPxVL+s#⊹&JU T.".@Apf%FLT(#CAcpNDN(C Csfy0WL=b D+t#:j.QTIGMnSIOB)yJX*NM޶vSf RRa` AH 9tVN]" !8fD qnn91jDĞXIЇ oDVK8"AeN)WB9+e$BbA  :\@B!RD#BJC,ŝ8:Pʞ%+(lL=''(2AA H@b8Qb jC c!V#K)#0Z--9>eo <4l!~o>[m9̝O?9S7~}^EM uЦ-7gF,6HNv\~T+u;֍N[Wi=w ^pG~xiakvqw oJ+}w.cb@-9 [kB?+"*;QX"Y @3gT~ N'WH~"8"zٰ:ٝgmݶ1J<أ{ ?>wtsY( ?fJ։1^__ 0#!X/` " ڷSn=i] q2KnVʶyy8?>zb<6'kKyڕ)n,V2h7fby1N]6'bCd BA%LVT EԕhBjuQ\agZ̽D3ygk)2*jy<Թfۦ#auS,{$:^E0mZCV(Y6GDN]*%@X͖%2Tr.jbo% `8DESLX(T* [QSB @XFe3&-O$bJ0t7RrJ2-%m380AC!&\ 7n9v0a]ӎֲyƹ2f[[^[[f2I(eXT&LFkT j"!R$3dvMtm48}f˾+<5z_Vss9X+2 oUHmF`M qr_JlHJMX/3ZX79aև/(4S4gI f;x\Hfo#reӧ\9l84U}6,JnB+h-О_N,cMFŻs!L`Cu嶔r\mjJ$9yH\tΜ5/k]ϗp.cWgMNҟ-Kramֶ>\.qm"ّBŬ]-7W/G ,,5ב7zÇ==瞸P~l}~z^s`*}9r*7Q$("W.c^*'j&޴Z;\lǃj*GVy}x:R-{ ʙ5gd3жul:F 8x8Gߜ_Q6xTq`Zmϼ˰0"Z (Ww?|g}\a{yxԩY븶u}x#Z^,eՆW/?1ܾ޼x_}7x;)eN=9fCpE/= Lđ5*`v%Iv@ (rHBKI8Yu<|;?G'~]= o>Oq)@*˼}>ɍWapj7^q5F*J2q@g|~ūOlo+iY8]-(i!aʈXh= BP3f`:ÔZ?"RhYBYPDf [1ZpϞݔ,]Z`lܖ~ #@7͖Jfbs3%YTs.N@/;/'kӊNѬYHOCaY`9P co̗kǫnU 1~7#"ZS$+hA*T&Q)ExU6gh0udS&zҶ(ᶇz8f,Fk~ E;7]&8/&k Rjȍ=gp\Q8|,EIyŜzӈE<ʴLYcQ5fHE[mS"fq$9g[ږU J@߭2itoy_۹ǚ՜#73* (3Q%Zpu .+_|9Qxǯ>9d% 4i0,Q k]9ٺk-g3 sDLr@a cs<2kҭ̲BN.Q&TUNUʷNrQmF54&5lR 5yjEkthC d z1).gkGSGbY:P)5Qz>G{//g_ڗ<޿9G^]_=^r}!,|u]'?iܮo6b~31Gǟow?m҉J@+ Epnܦ-*APXy /&1k2ijʪٿ䒻Ue|:CEeH{C4>`U}#74=T7Zzw/~GgVf_W?\U N3z nmŢl$YUo LTi]jϘHNa2 "omgZ^#m4G]snV[$v7֦p {n_{G?A(t;?p]>{v`=t/n'7#iOS\x?\>ko5Q E9jҌY5 rЗY5C;z(kh@9/:1ŵauL]zāIX 4ZczLg%Qc Fzh,$ { ?Y9[SՖͪe$'28l!îmϨ2ߦ2‚<\͌hGDR hJ Uhݚ^10>0a473f:MUnˊ]UDj,44(PA5&B "D/T ZcIdiNH(ܽm7}zkRB%6Ppͯ;L FGCN+p8ZԤV{gQm1=ق1mm&6sb 3 ,@9RdmP TYd3ёaāf,TӜ9мl:k3<_xXǫ ќ]25SCc]09Ke+4.kcH0#jU&e",2i(ښs)MK0vf,Y6IUY:.ʻj;.S[s<=f hѣjˌpuySk cyZÁZk}z"r*Xt1=o, d[ɦi2[ ɕTmY2E%,U I.:+C>iy\.Yf4NϠ'|U#f]`fkqZ/ꮙPD9~ϗ{ɧ7??}hޜ<Ӗk|qlwW7|s4z}7{חׯhՋ+UKkem~o6K%Y ,pW:297/Z|L 9戉J{4F;mЊ;@8OF;mJa|wXׇz|_|m}χwWJ IDAT՛? {P)kR *,('iP0 #,->;r Mp@V4J(S<@cмӬG7m"7yc]?}>!Xs}9ϱnw%k^=7ޟųJ~c5^,Chc8J5';F)i7WW_}h=b9~9\lU5eɑ@0Qf 0` 2WMeLF]f$dHchV`0`_$fploevwxFXACU4 !Hܳ6eҢPF"(SZ=|TҩD=d]rz=j #/R4)HI1̶8^vDP]rN(b4\V2zZ3LY%  `ofɚ i/F;3nEDB` q1 dCگޘ3jR@5 rX@4+J N v^4t_ܚ›%ganF fEH,BڙFD!++3U{CCsړ ʳlҞnS*Y} fg0ߩ19M2S*`֋1 ,uJǔ$ȃrkuUp(ajcQ*ۘȵ~:ijq8zwy18 |յty4[N9 o3Yl99F٥xzR>R,ɛ{1df2mJ9kN1RY@%\,mx|oŎy oBrmV&9Q9hle( z()8U,8DiѦ3"(cZ/g_qɗ'~kuLJ/<_,˃'[޳1M\/\_9ysC[o߿|4~W?7U*;Ys;*Õ;/ -bwnC*7e`5hT Fv$cz~77Gn\|q\>\]z㇇x{㻵?vu(__>|4yr|"r R!kNL9l9?=xN?lZmrLq LV.hQ&ﱤ1E*)%Xi@+$=lVEs$3/=ZFLoM6A fyhu/2-:MiDT4 ؤ"T*Fk) n vH`ݜasNSfFkQpJ0%FS[{eƾz C$rv(,e7H, ̭,j ̬?l+kslH u*(l &icқ(G9S26tr՝0fbYp`҂s.-O\f s*`,T^ k 1ʜ4+M2[*)/4G׮t.J%I׺4.z7ټ=VQB}nSǹCuëi J<YHрSФa`>?hzhS݇ZΝ-bi2q{G)"@4u] kS6qp!?zַ;P+iʶ:&!w$ғLATDr ˇgĀYYY gs{XLn)x`YyF~oLq+MJXSe,"!g Qhh`n떗fee*I@ 2}PhöZ])U0()!UK8Fv{†KDIP&TGe'w^ۯggN06>x.o~#+_u[7y9?;O{7n !/? 7RZeVJrJ*Y*3gۓhRu%^TVCuﳐ$ZhtOq:ʧ ьEw"ɲq[wv~rooٸ+ͻGgK^VYs(iM$fhpd&-1YnN H]d'"P&4il@UhDAxH/WgW/ͬY)]nn^>>]>|~q9w;<xDZ}-S_#NwG?I:p;/㠬D9Yuu@Yf7'|O~|Aiޜf=e~܇_'6Y`#a/h)+[NTm1d{Rfpu<`^ uNĸzN0M,vu\p~8kWʠI7%:Ȣ@'Prge? 2FYϡ`YpǐI:|} ,z~YPԁElX"f^.GP%ړ&{X@\p %m/Ы۾iG*JiI4.T,J\.i2Ywr5kE}]5cƖXLp{ei%j2"p;Rn%<ʹgsFp  2\0 dE!vXUmBn]0T"<`fTZsYji8HnfM w%TcCg ZTwGI f)]c3TF*TV>I; X"S)zr[#ƨ[-9j! 94KKU[fVU`Nc':??_Tikv8ߞo~{kݻ_?w_^a{-.oxgM:g_?\^~z{8LGI0:(7Y5*DTfYGhQQ.g ﻀvT@.nPAL:`aE: fUef3s{_ڸ&W4}e^|,iO9T$Khν2' eRrcFN9!]L5hxD7u?Wǿ/__> u Y/޶C,ͼ?5xS8-7'zegXϟG>jE}5 c*@ZJJeŻ<,g/p~|DV܈Gw0 (rfւ4#Z~8D<9ÄDD!Aj萕"iFzHWeV)=j_4ٞ G eHWrВI xkOW) zzƽG9̘HԤYN;L,(ȌYnvUdtPXUynlKs&R個%͔`̝g!07SMP*dw~!lD*e=}bGyXF#ӝ,Yҕ. G05Ya䘴.%@ Ƃ92PJso?1V}p^w||/pw}dӚfs-Ǥ9&Qi,FҨ,CfFJnPg7#Fоsk̔S^X T|{n5]콗gEvm>~|춽3a5g{Js+lZʕNV-Κl*)E9J\8J}+Ns/ҟ]7WO㸴xy[ۛmMVFm0{;,Q\|{c9UOg7|x./֟<}]^.EVEWդJ^:|;7>>خѯrvSF9y;?|O{=Ľor*鬊ˢն6߯wmKifhLt+ k;JfRuuSu6rzk,ڞ7qUE=)*A,d8S2LeH,,ZEA0w*!&AX.UxҶ?~9̛_]3lͭ$cY),i>l2B瘻zWs׺X[1ؚp@F6k-3[_b7^ȑ[g(|&V%jܔe@33{@ǵ4-HιG1͎ilmaI0-"ASK3֪6s1t3 ,UBmd. X#bG̱tˬ11Z>;oQT-%J= )/q8>{we;\7_W'?ͯ5~Y/|8<]mZ=\ݬ^.㗿N9o͇o=?>֊tKݳ/ڱ )}:uCIRJhƧDR;w< ĽXe UDFɝj{Qa?T؍Oñs\ϗu$j6ͫcH4m/ 4P6,]F]%UY8j<(edUr("K{'(-駿?s_j;6.ƥo>خ߼<\}<7>??^>,?>y;OB-|xlkAY|h S]r}uüAN\?@cx75ϛ֝ѱ#TO,#liֵ}ðT9%g:̪ p@$ri*w;˰~5KޥJ>ϚVΆW* cQ4th3i}?|&}s젺'=g&snSʬ h^F_|?C;7sf&SDHS-e4K>]{2J L ky~,wVZ#k1A"R*XG*3ýAr|Z_ 9#k{DX--wFrNsyhUS'(ek{ !sm'/IU(dK9ڔ̳&蘓I3i\ h FdP;lX59),ژLs,Y'AU(ƹ*IRP!M*Ta)oB2%5fN>,[iv4nDQts[\˪1[Uim b'Rn[e2H+8iG&"Ռ5DIavXJ̝,nk"LT$ʂw,{{x;I)f[$aðၧ/ o~}vC~~gCp[: A/Qr~*UBt@H+r 4ʝXZ SoUS$+y9 0%`Q,un߼8Q\I'8>"l(E&۰|rZn??M#]5X252:}:xD'`2Po* cpYe2*,qfVAYK@y&pu!7Q,@Zsd(TL 3UVUv=FDܪjRʬQtc e {3{v9rTl 2.cYև}b0a 2$)P0O 4,Q!=X@ .jƊ)&džjNsM`Rm 3EbYlԁV,g-$V9}c[蠜V9T$8hCiKk9>IZ3G'ꡛ!s?:C,k)pQXL58C hf]]`  6P#HMBZO$W@ "O#[G+!s\3M"U߳5vGs9HY9d 7,Olb8L֪{#!,E 92?i NDc շ-TQ낾+eGq4{1bi  tfR!Zwss- ̞nieʜi^,nj؜8n IDAT/ñZkLFUmasW}dpL΅9ۂ--j6]fNYu'4Z:`gUCn驎%I,U{%jlh,vm 9s,<^Ju[(^jWRȽC,NqH>E+\,VHi+ 2,h\UU>̳_ϯ/^9k\.wͲyi;k#ڣq7޾:~]'WOr/n};?꫋z?wv]3rZ"U0~bVFpd`RrK9&0ߖ*6' *6% "'iL7֘ 1JhI48@2Y7四~pשtsRi˜I!IRY % =$ 7*W2QXHXF7JN+um;ѓN'+k[Vxw~>x|EG0ngI߾3DJEzmP}o̐Y~w;>{]>z_͛]]>TO]lwwo?0)]i]&7fs3(BXZY}4@5 3W}7T ;#4B~M4 9{T={e  lKh2)KIcPjS4-³r kbTN. %6-k_&i̱֜T"hdQ2-`& $62J]Mx17¬d>R4(fF TdfK˽`dETʪ^> Ʈ#PZ4:q+#YK2OX\ʝ’ڵqKŦDid+^UTܭQ X^I/!6|"AbHcֲ[bVDzlEe:MK' Pl,hmu[G;e2GOp;n9h ֨ %/K`3[[8}Rb[6>2OK( k%FPU\5 r9{i?{`cw>>?׿su"nUbx^~ᑾ~믟=~}|=S>܏nUjyiH4}9bphPrlI9i\SR sEe4Esal4PfMf.O2z5wj".qϭn;JTcIW(߃ ) Hw#&3w O,r!;>Z֥xs٣o裝 ޘܿypy_}Oooގe?ׯo_7~H37/py B- 5Xy͵ =_w8/q8[ƂͭD{2F[TZy͠MO LtʌfJ`C >Rlm(TvXy mYZSeK,+&Yx6JaK+cu3ZG,z¢JAx"f30BnN~t{>g%?/ǧ_v[7c8\Nc\{Ut f $J, @VӜ2]K'cfhr *ws "a-ba/BIdpC0'S!wL9uL}RAS T`ESPSH gW5?~s~~Fj?|y]Q,U֠^`XH* FTplM u3 E)wFU¬ !֫P6&nK[~- F8 _ !3BAER~X.rooz͇/[muR BKiPELv0-@̣zG Q)u߽ݛSY<|ݫӾ78vss:xxӛ/^~rsQ>iw~`oo \,}O H/TNIכN2VM/Gts}nڃc9UvQtޞyg%UB / H. ْLH ŲpX,.JiYJ^v38=;V5kD\YDF0 "PȝMX(5DxF{AN]f^m1jgVY+ib}WS,}ó 8c9{߿3nͥNoQc $!aEPk`QtB Sy mfp.! (+[]\tdy&a4=, 9J$̮FFjTpi5Ja. hf7F,8 55,Xe95nYԃpנĴZJ :5ڜF^5˲{`TO!(G`[맑9;D̆qtmFy t# EZe 1GqTPOhbX.Yc7׃l:g 컹-{,kf"l8?P/`sKG@\v(W퓔n!5oAc;hP <$72hVMuWsamXl5.axھ=# ۱$ ^F$֪n.Łq֬T[h\BV+.wvNz'аqc64!p*JVڳBW?iTF rT˜#Q6ʈN؝;y! > UURs:evDq첍 5:1 c.% =T͉D6Rh}{}|xoe?X|ٗ)_⢝]խzG˧v K/B=^}ssa+_ç/.+"VFl =Iݖ16viYi '[=dkTOc5esNt.-k >|ldZ-Y|;~˯gǽ1~4fCYn675?,(BnN"bh0CYSF|/;pWo-`q~>XN'z}⛛v˱F]]߽{ow?~޿7i;/hu0H1P2xMf?7:oNvsק^o!) A(VíY`a(- D 2= ΒZkŐ3!7ǴVmpk;E<;8Zd.fU2cbJCA@t `Uz;a.2%>\N`m" RS7C9=UU"SnTD(0A0W3_=x{Wp{uo~,'nn!@}@IR3 N@K!CJF 1K*KDo** i]4_HIQfr 4N#s 68nfNЄP~iIKa1 [ֹoV8)֠; ,QBڲMd?Ӿu 9Bl񸸌Uq4kb=j[ԦDYݔ jƦ! J6Yu䬀96VIJVdpr$d syhY([v36Y3 j 8m9bd(8 3ŭJ Ec[#gݴKBd%pu3kRu4,K/fWsXflMVj AlA =vFX#P$!%VYw$*26 l=%ỉzr~v8kx$0%3203c&L4E `lR94c<@3i΀(a .T6_u~q~[ܕwSp Kw#,nnjQ2(`P"5HH0(9G|0z3 Ս.DQm^<K}˿/\},ۣg|<|x}$jF#DR- bː:ڀnLyeN:T giՠ- ':M}=N$0"7`fi$ZXTFl87T9YY*de# CQIIL0RB5$n9e\8\E-:%3F $VѰSCEY'XMU,ڷgrsW73 giVݯō~X. f.\[P01)8zD4W)aJYU-wUk^X*,3#5bl JŠSVyAJܫaV{w5ͭ[ok ,񡝭YNOiQNm Vk8%ܖ) Pua8U@! RiSeӟP־L]Ѭ*gQ7`U[i>h{pt>R OO,/`Q!T Ъ< bZٶ姏__y۳}x{6-8?hyuNۻfkϯCȺ;yGӲ}/gq;Yu1Ӈt}q7LvY!<d#lfxl " >)LM`.VA-dk$S?wo< @3_|"O DzkR2ۼ & &JF9U <o7w7}LPJsD@"(p&fbG H*qƆI E4*gNc&2ªA:eC n?zΏ>^ؚ&GQ6}7\mXO??ӼX"ׯums/6=8Mu&bi91|ظUŭǂpP^ꇾ/:uX0׋pT"4K=6ae!1([ !TCiF ՀG[㔵{f]tECC^(NԌ2ڪ1Ee$ܥSݜILgncLUݯ 8aW/_?s&9c]"g<^}~-χx^|ɓCZۋ/O'77Oo~?/j]~_/owRd/'iRm%{&̬{i"0L1A608QMb`~}u Sc27af0:@ oRJR:z~~vy}>/wjF<( CV/U짪!YcѸńʠ{F1"0@PtgyIuQ"KRfbvpou{zpfuniJ # --ruYk(ׂ^Yi.X hFccnRHons'"II"!16͎w7/^}t8{9i\^~o>/̟xrУ1TWH0UNK4$r dQ1f`9((!@SwjDL IDAT*j8pUh-HE!hKEokЌ̡.6s2webksl4 sK(MF'fd4Xp@[nfJNsRifX"2Z&aX'૥nGzceYLϮslfyb9(‚pP.R,+au-m֪-~hX ve;,l!~J,V2jnQq5㨴#Ϊ-t8G#b_- (jf""l];6sV.=k({Ux=U,Ы܂U;y, Эbuh&ih;kwim^KAE"{[&WT$|Yle7Yߌr5]S7Ȳ.c$ХBrU|ӎY&(}J{"C8|H}VQQPRF[\zL.ʎ,"+H5 2L+_7edʱ>8oW|n{{:dEuݎ ۶\oXߞ_^<=G`q|']W-m}zyYw_O~Q8Rf*mc&OvI"Ehf 9ݽƠ9$zh^#݋,CT+\eD6mEVU9v?;kWՓgoߎm&n?hnd5yW4#l*f(†LhYjRaQEIp¯2mY89nwmݖ&nÿ~T vkl7[\UP7ne@Uie[4?i 7FXX/q[Ehm1,vg>Fz'ےowUэAh[d(l lG(3ɞy"tH ='sA'Oz_̽VZjRe`nd4s .R+i+8EэE82x}O/;wS|)+-02"ICHʤi |k(sڠpYO5bq l/$`+H3Jy جOw~c?ߌ6ۇ_oç㛏>=h r*/Ch]_m)kp)-o@MP.ש̕gA0VY4V,V}ɵpp#.0 \h2h2Z ƘF3SrSXRdyBD&n3 srV_KM3:( aIB{fVhUʲ*a%F4 8ʄ녙Y$>ӈB]]UE<+DMS΢đ%dܲ82#ⲟ(#n0ڐ\qA+"kZ47) SٜZ)%vw藷xy{ ={0 ~W|1F T{i0kWJ!EPJej"IChffn\[]1y̢z7߽w^~~m?o}/.cqeZ_>_~x?~_1Y^4Uc1z'w[X^~S7a#q itPэ-sJOH-r>`"Ƭfq{ߎޣyw[-/8NoO`m- 1W2oznoEoÛq^{] i7=F1-h S40ܚatUEsS.V<q@C@Bo>UPifl6kmVrcȩ#a 2XXh&'nH9 ]}^㞙*vS7ıM,]V&PKESygbf9h(3 ,רL&jjL-Sk *-'%=j]gBNr;RZt'o7I??vr|S;}EM=YO?䳟̨9???e#$Q ]5ƌJSPifLg=Ă:Ra`O2g落 y,NC%ht@ˡ@5CtF 9rqTfzfZǗfC˅(d0(\:feyjad/ UU6Ynm9w%ϋ=$)9`PNE#͗c053ڬSM-7:m -J$+nn3}LZˌ893#⮪IuYݡ҄42nȮ$@1fm媒q9k cqJJ`` *kcˢE-k\pF{;fauj :$O#3i 4LVPH%3kj}NiUs!kNk E CZ,>[2 Rayj W5n`NͧYԜE d$EfCMR@5J%]7pP.՗:Ϻw'Q٘m:s74mCl'v;>A˗}rO1ů1Džs͟Y^2ڔ`pD*(I^NSpZAr.E֎̯v0ZAPD:[gRt萉0H'/ o޿/>Jp0ۢ1܌E pfn[YKoi}ܾo>o[ywz8?xx(헇oU_ӟ6t/B~iU ,&` E7-_ẍ́9'Hj,>3bB:WݣVxIrXfmW%56@A]`~(uT̓Ut+`xDS3g?mB>Y`ֶS+`sN\,.g&MrU1jPvk⡈ƱUJjEr$R9sCTN(t\Ÿ@,rԪx\[.N1!/ַmݴ\% Do[ԭb`oݖ^ݛ̛嘢c\A*.S6GEΒ{MG~xgzͷn~?~'{|q7o_"S}=(X$UJsT3"A֮;a3 WKI*`ܛ{?%#s.enތ ?s/|~WGnoK(J1޺T&ef`B1(s%B!ܐfl@ c?(+U' UFJ7L#HYIy:À9x{L1nyHw[#>h;&QfQ9-, ZABMsNM5a%rH)-etUqy9%ʇ^JDSt HPԪ_5bihF'jErPۇrkQ]T[͂5P9r9:ױc o~[gxvsUK1tgoJb{zȱ(sOVXBT.8 Z,tAcFK~3*ַVp+ 7٢2i}+D]E)TZLᅣk-dΜы 3RYא'6'`([w)h~12@`Nea@m07E bA" d $ѠJFAV%W酔E DjZNs(9 -2ݝKp7ͪuGkG)dP X1[Gi.3R}:*zg[\Y W'2H*d+9|=lCC 4!MI.+YZ@De MM?tymUGi9RbSuMHȌZwl&#p8=0)dWh6<>U<ӭ͡0d+xd0dPͶ~Dl&C -߻ofTNjHZ 8m-]1d/0n5y(eQUDUS5mUNjkR&K|*:i<+ih*p$N8O_ {~gu>1]O?8=쩵O/zzk'7O~PbPL" X4Hw_˗+@cfTͯ8VYa95s5 }eT1UD5;d Ypf{~~o޽>?~\s4?-W)A0Ibaf-gAV$B,FZ~1ӑs;0UA%`-1@χ5Mٟ~7m'o3[AN̺S}tH>GT0VeE13,ETCd̚w_3\4F\˜IG:4%jkP`9g$O3zџZYA4 yb2ۜ=Yy;gГ'V‚2&. dGwfU&UՅ,k-[ P.n  IDAT5ѮS%=˘s1}\2Oٗoa~{{td{b>m;N8ƞg8m/>߾}‚GΫ6\[>JL`d2ʄ2{ ͙@09,iF/s&[ xxzb5bI|5&ĂDϣ2rX`U'C*ZDHu9$[x fշSRJl|(M9&|&2ƞ:öGD&VlfyޗZ\2-kp{/#!׷IfպmzֶVcZ?U vlT;X)RmܲG^qH7m4n>7 y7&s\1 ;||nw̹>,f bR1kҺ鶕FV!%CvnMm}-Vx=QYJƸ6`*);(hSr  R\ Y31goo7vQ{5ڻwx}vO/>?%ֳ zzXd. jGҘ£T.h&pT LI+ͣ5Uue# C,2nJZnj1g_ ;̳RJ,؀PTJC 6{n|"1KVj {dm VC5Bb XfzB½W!U2zsAUIo&]Vw ~z t u˹?ƫO~_y_?y!k?N>ًo^&4r}Kj'y CtEws&yQoU.#c̩ jƬ0P)G,%Q0EcN3hIWUNt2\u\0dC%y\j[ӊ#"E(iDF8o8Rf+TN$f҆U",Ƒz!1AR1W6O7T;!.˕!*Xp:κ" 0[ȑSEn,\s͝ qjb?n`[4b/{>>~yjLg uقqd NieYUU%.@U4dt:,qQ@2 0"(t!xrnf葠Tgv禸Y*ضfDe Od)T<(0xq{FG0"y}γi씙09ʆȬlQ厔3 `7,NuMtūO?z5O?Fp!zn7+˜sWwx|᧷Pg7_lEciYZ "i\< Lw f2zX}ʪ5]J]\ahI:(R0c8&^ q:bu_UV w<7_}Gݿޓ7ߘPsdZ/2J,3E&Ԕ\UeY Se-F?D95)tMvvbiӟŭ2G?߾ŜNoFlZBAXT o7]IJrEYoAc1dY0El\H Н5#4 R4ۤwZ rsfk`^ebKq5{yX^¬h@i'@bfTXPhtTѹުPJ3qRh~*JacdqO7ߟ߽qжB]YqO>>dwۛwxrz0eYa28g2VǘiڄxKd SMiW$ʱܚc۫@" dPqlL0aI3RBJMcu j'횁1Re@kʿ[ʲ T,)*,)[v@՜xpZLQrup}CVBmܻ߄SvSǠӉ.rNatbgs~ ei0_,U!"PcI͆ >a3òfwg r\\;(np6Hc aSQ0 &s7~3Ѓt(͝lW˗2Xs'q{{>N˻/c6/[oh]wwO[~yya?_G/g=>v<}pLIgC2Ueftcbŗ7/T,DRƆe夷*7rwa,Hs Yf +)Z KZA+]/>3C{xXi{uwo|r;=XǠj?@bu @^(\S+yylc9w〙E뛌M3cJpھc_|t#}/>06 fs=>鄚YF}ζ`3{zڞukᘓD8`#bTH8ŶɃ孋~}nvcܛO 4SQ&(|!yā,ֻų-q 1,</Y FKå6P P+|nGqL%^ xˤVB5T&z*2'0hA䳛G'??ݛo??sڶ×4سgre?_e=z} Ղeo71 ]f|@N/8:.,4vZlp5El]e0VbVRio d߮teMn%!wO?nΧJ ,A Л&{mw&PC4৤y3F!s ArT3R9d՝-vﯾYf0k?*]}}{mC][@rC|q.2SrD5}E,ڥ'W̑q9[91U9kgG3d"UD1usvA S:+‡{81m91*t `CX9I 1uB%PݦX`kܴ*Ff+H(r\A͵'EuO?~"M jXߜNo<[\߾_pÎOߏ~>/oGab0ᚿvgǪ ZQ3x6j3NMJ cIýȪ+b JTd_"l؅ٌV3sff9B?RE fS nF^fޓb4'HX`c* !#tw]]&Hb0 UkL`Dz]YtI,6Fb7#i@k0d19ȶ4hiYZ퀸,T8tgRcGJ~ٷyl6önm/dvj,yN(CRb9crO҇5%mPjؽLA*E5| 0e民 np.=ߺEϳ{+Bjpdv i]5{Ud|O5[٪x05K 495{ bB `FoAN$,|!OcCc;܏m)Dj%rhV7FefzGqYJeL fոK;m -4&'{?קٓX]|^>`_`ce_o |^erb_~f=_^⛷\oӿxW_Dyju$WqUd&B܉si7w4QFaf"&p+ E1f[.҄1 K;Wem1rqLJxr>}ק|G/|uW5j>&ۙˉQ F D"yfXDc}nb R `#XU2_KL؂U*.;nKV!h.ehI!X͔,Ȱp l)ȥ|i0"莶tLFhɲh͐[̥oeoCy/eg.V5̑L3eFidWSyMo>1f9/kmq,z۞ťd- ʉPѽЖ2CG&JOow& l)mVhʾk!C 9r _ ,I*͹lۥkb,EDjͰ c5βUdM#914׹QZ`"c -m>=Ïу=Z_›|wĶ-n.Oߏ8LE청|sWc__'W?߿_ޱ0\qM"`)O[% SR mB0#x5;a M\Hy(NJ 9TatjIIqh21ysXʍW\T=1'7{o/߽z/pFZSjcЦjd3 A"100O%vf_ٛfYLLΐ&cd4>*non,k+|Ώ_'ɻcKsNYD0eBge<έEor8,4weyct|tl? KK?qi 4bbg`LYJ 8&,iy r&41P)40FáGcQeUՄj_rY뺃` Tj`nwg-b<X[X#iެAc 㼬W-ч?t_?~^zۻ8+^V}{WjQ/>{oZw핇/7?_g7ޝN$rbu9gΌٔ~8*Xو0@$r=A$< 5%TdHxfXTDі1nbas?尥*[QL_ ifF%f\]Q֖`ܬ%greghq~s;mO?'|G'G9T:-]20 H;bІ͚Q XxP[gKRѕdqCT]4+MSTe 懅iBG@@ iuǏMn>14߁LE%|eN$ZO 0rf0aE#͜ ̌3V7fCp0~vnvq闇_}݋qzN}(¬4"rғ jm aC4R0=IRPY,<<rk̈j֥A4pI,sY 3DK ]Gsܳ4r9mplyuܪNe{{Uc Gn{FkF{oNz-4V!ǠuW}/;5r/!4/[%60ŭ킖S{`Z1ZPm<@.'YbfNӖE,P,%᭸씌.J+kU}oonN[__}þIZlaaet[ fQiQv"Xf]h)qgE* >"!T*029cnLu5Xln s r9(Ó7/^|om2HJq %5Sg9[NkOjF7b܁,3}D,X 9&v1]mkͳ~Uϟ?doc]^k?os8g $ac׆/c(,ĺ&ˉA>t2/e ---qg/HNljF5&54GEsP_`Œ5`b-]8a9v{%\}ưVRPMJO 4}fc 0wW3XD]#wsUL_[@AN.͍p'n\ӻg}ŧ!#Je`c*v.<[>~||Ϟ|wwOϢO}U2 31HU:<%"\#UEXe8JBFU0j)1NF5@C4p@REe 3ԔlpG)D:K&KΙ  5YV*ҡ=E.FFPcTL9)r&hdDTe&—} / @1,L}=|j|gIe1V3r%iGS D3a< Qxf論C >-pPK4~ٷsmѷr 6{10 Rn6JuJ܉w-,#,dX#idB J8,!'FFKi4P8 $Kpާv*BR# GX^qtOp^hb`ƀ\<GMEּ׎j2tweGNw^%[B{Ţkគku `c%,]Pf-1`lY$W.SF 6"` `i (p6TBE 5V-[vs+˿[0pY~u_~7}/z׆}|{_ċ1Z8>ŋGoO~n{3X,\J95Ƙ* 3h7"*9j45itTpI26*FWi/ 5-g*􉘉$r*@t,qM$@3*a0wQ|]2)Pz&=:߿?x]fv9G>" @"K/l&j.AHDc (FUg3{?3e-_|}œs/|Wi[v{X7~_#}f:.ń{LEel3ӳ̼C53zG ׆1[!9!5 PܥN2 df=$L `]Zsc?蕼[n+h9wYmJQ% ,4ewEs6VZ@BƄ9E 1zO2E\ZkY~:xo%rYL;,w۸ q)ˇ7ۓ>㏿G/^m}R]_4HڌƔ-t8DLCeVj"D>(5|*]U S0*MxFD/}xIjv0f jZe\cTD[-hl ̳uKVlT%eEZ˔CαZ4}E.R% sOm+&۾q=X 9*G[aVw^K` 1qȔ<" [*:4^Ol ` Gg-u\*`@ QU ,9tEnX#o}K.[fF,uĊ"dw!×j-{\ &Q7vqK1ީߎ38!OޔgA˶ؑ}yT,`#Fv3}Z\lb^XM5ifhvMPlx-b #j0|RHVuUXP My)CNKޠ8ܜB&cj ${nэY<KԷejv *RLP([TgUq u*8~z8?kj*ThMx,g7 $ef"!89l#J"سI! $lFcb@Nph576XEFT\џ|z\~Kd%EpDZ2eYo?}(\>\=o~t_1Rpp-kteLƸ%RBV_s߂6S[MmNݬנʗY,:4rL8ÌAUn*Yf"p76x^` 5AE6wFsܗh}$" "0LE۶f-aPPUXݘ\nYn @Y+3W%b{U4*Qq3 erU@K 7, ׅ`eo Ҭfo06~Oۛ]}Իsm>j7h\eY ;{,m><,]<zdu;T5ʼm[P3u Wm灇J=k7,}^mvo藑 BNFט{lؠC-5wgyzxqq`w?Gzw9DžoZכӏ>6fDN,:1c)Y´{L44$2r#EUU%b2'W,$Itڨ%дSh)|0;iFβDY9oóG.lpf?ǏnUaD UUu)[nPW_ZR$`݄ 26z>z0zGsC) if,c>xٲɿvӽݜlwkmga?yr͋ZP,cmߎ7CU"%|q-jumN"']bwwwwxnUcvըSY5ʝb"UQДCє,fB¡49F[뷙$МMc7#,K{v\F/-V3U ( Q*WUUɀk݂1zQR,I[TUnwA7F|@YrKxkkx<|{gԖ~z t};ךEqrC!ϧ=:=}}5}gnrCUi2(STb\-5BPuA%B];ÖV}^ͼ1i 34[)ibSZ4 T yyh;z Z lҊhJطvF,B,Ww.mL4m243Iǡ\|RSC5̥=ե~CLx9]J/.>rNuģţ݋^=.yyz۶:ok3dQU$ee`@mGnXvÀ[=H YEYŪ>|֜ÍWid+ȓ{9#?_}-f 0?<;,z8"r #O9 lQr1u =ù^Ү2x3S xn |F 7w)QTiN|mwA˶adOE-RJa( mtb>k2w߶ap3Ϝs H+k e#ݝ\ ʪŽQP3G#nzqP5R=;}WϏmiQfm.g-˶իuiQ[3^{/mT?poRF *jN cႫ \wEzp KͥJ5oՕ,zM}+Y죧uuJĶPc',ڻQ[)~f c^x7fc^)NT8ۄ= 7p- /Go-3<ɵGh96AR-tΨ@᫸ ^c)T4,=[#Hq)S3TdPCDWx/8a`l5 \i :`Z㔲hn}?_.[Ur3I `-#֢'hrkVGIX|&pFR wL&!IVS݇>R㩡_cv{/~{k럽~Qwe^?|xx+08,Q=YCU44i]xs@P**m<T\|蹘3${Y>&Vc(13n ?95!ZgU)̫DXCM%J2?֗qy~oN'T *ɬϼTXJfH9- 0uYKz AQC#U hY*rG[?ڿoj,>}U*7zywn/_|SBOz[ڡ9rюǏ7{i4]u}+U^4[SFXz~WVQyle d(1QcSe={9PPNJ.;; Xqp8Hm nJ%:ixb p_R9odbCAL4S \@)s$ڂҮr:~?yIm0^PO\!è'e8$vjWm//?᜹9'o|؋9ʼeUωVr lAT`]rd91P 34 spO)/dLd\m%(LUc洟!'0jK @Wyf<f.$L6Vras?h$4>qP5nLd 5P8ITGTJKBM`9҆-Tf g,*LDY\􈜁E#}~{3laʞS5 68v޹!H@0欔 Y{&"Lԉ*!/꥽; Noe_??/c>7BtcQUyZ/op^t 8ֻUxЛWW?Go^yz|}x|zie4i6O &W2 5XQ123A%|իzӘJ.j0FpKPLO[,-{'\,t-vax:Q!+HQH%Hw-rY9/Lg?-_/g_/ǏN}~˿Çϳ?m1@[/2/kbїsw_$JqqWCh/>ۻ[\N8\n)6 }Xfsb jH\ۼ9s/Xm<4'Fzք"ӨXM)t4|^nVɻiAʗT=EAdPF(bi,R7sHZR=k=.& TaR%kc"TSJ =4N:JxpREmc;BCizte9(t"`1͐#GyxX͠v%\ږJ*wYӕNsYܬ!qW^aKsdȥvC`SeMJu-4?F`JF l`1pxSf\13A141557BYFqp٢<547-Ѯ^W˦5ZPU)fl& < CFP\9Sn%6rv(2m>rou=>SY,üR1r^}\IK?1,4ݦz. hmA/ADUyTʫ@fVC*p72ͦNJ5pӁ겠eGqYwãގwW񰞮O7o}xovG,.)~-ܯWOW/W^V_pݯZ 2΁c 1aYLY}#rk4VlKC0=۾WLJxdebj'5U‚n`џGB"΀e`h*0xDs("61@9O UJ (- %,}/IRskG]2mU-ki0zU]&), 0^66Ec1,jDT5;t ZZkY Hۢg]Z*K\K| }}.}߇m}`f5P l}xWkjUU5eAJ>ƑM3Fa^,7zf=y-snn5bp؝,hK䲠-^U Z:av"2 Q86kQ8م*]fnB(+s)A؜YF&c vP%!WCIb!YI1 鵥v"]te8K[ٟZJtOQ(h.`6{$;THsq'vy1)u{οFKQ(sry4׏~O>o_S|nD&xwQ4 = <<T B- ilܛ$ ML#QNW7}ھ='\ko]6WDl/&7"1ΩѢc[{}S`TV5O%l>A@Y#02RىI5Hxz<1ĺ›[惤gz |)Yp\._~޿~tzeh1ħGlv{/N_+plFpo6'm6n>g+_W`Vںñ2y2=Ȭlhi,s yq|7Meqx氬o|gH2D8<)a*`JQi&xMΉs̐ܗCvnpd5+2{?~Uݼ}>n~oߎuYhoO؟uŋtړo? OpPoϕ;g eD+d5Pn9ү1OĶyY<=zMHtyl*W)9eZY$fh6= j3+ȔeQN,BVCLZ_ 'PamXTI c{Ee"٬"qQ)XՊ#tswś};c <]ݺf$l󴃤M'*BX f2S*ܖhniS6%;aC ͥX :oo~z? +ޝ.sg?\aтDzu/ݷ Tm[zCb?<-O_i/nzQ8,2U:1 jq#cfC 1#kꐅ5; seùVyޥLbߤ\}G..+aLWr|P;Tffpg*Umt i\%5W_>꓾vzW=o0}z5hˎ6ahW1w|s޷픹VbtFRZ:r$ϹUNAf!jFkgFy^+4tl(<{GFą@XYsC,Mnçid`Ki* 0W/eNcm TZd4' PUX܈Q3Ic--wFL:@1Br-z:0YgeU戊\ڄ\}/J`8Lj"I;4ݭeYdkdEn. 2kPmAmRCUCx[b~~>_.=w,Ghhb]a{Xds7nG{u±Ch~9`c"t+Yz@.-leNh-ޢ֎.-+84iEz<%j=[Z3{ʺZAGP2Qm&ʣGk![l^/5|Ġʽ1V 潆RM$wuX%a#H4Tg*SS9#C C0GZSB\^$u7<]qC5dɑFJl LdD䳞4(Uk)ZԀf BųoLY=̦n6y[H+|qhv\ګW_~m mBa/tBX1$`#ip&Vh=%6΀Bڹ6+d99ޮ?}%YMmN{mafZk<7:vXPnf13+(۞jyz^?}{ Cptg;Di+Wn1J*'A{fq1"jԶzlx-2idbn 4d$2 %I֊61Γ}Y@W>TO5sQNh&Sn"p6ݍꏾJjq|ۿ}dHzo{"V,~|spU=ݟN}60`32mB9Y]}8FT tyFhUrStTɆ&qHӈpB ;L>5f]E  c Fq2eXc+On4U[h͠2:5y4/K*; 7c,4qlbjn3[OCo\.UQSc=Dd0*AO \&kV箁R5h|a9ҚKc j¸l6/C}}z1!fުjz HPHMZQf"^h@v0IAVIZ8TkbPՎB#dL_PM5 ÌXC3*LB:,1ESQVY|߱ JDS3j^{~{p|rs[\9 *Uz;;GE.i;`%(Η`Y`&]kٞ uU.aOַD zzfߵ㾏oׇ84"ǂS2"VPj]u)dpBB,[B?b˼ƫ /}o-Ap:u>@$%3 P Pp Ho!hf걬8jhO4`h%OpN0U-KsKfBUB5jvaw%d͞(N*Z/kZ3ZU- zc(sBaE>e/lg??(?.e`座CfIקrC˫^xǖO~ݯ.,feYyR#WJu]n%auSă³#xgRMe!r  ]6D> d8`5|>QU"SSArDUAX[2a ն^ %Ә5BCUY2 sJ2Fc[$$g`&Xy)hY#Jum-Hk[cSq IDAT{KsJ8E3YaQRȂs}(-ԩj.})VOzi+&t.a7Z }[BWni132f~ʘG-&)DѬ 95\Ftu8fRvTHj,CsZ- |rr=Nc9jSlMDxpoTF٨, ~ԩ8=t{!rrc\F鞷291i<:%9 cg B ̌QIP/mDV:]% ֐BIBΖ ɍG㫷ŗO?Ae߿;on"P]/^[+2+_BZX$[t>V M-'݅mX)s+̛^cg_iNÌZ#a j, 0&-0O[X Axy}?w~o?;޽ӔkŇͼB =zXCE/65PKi+턕 oĂ@Qi#śr+88|t$=vև|PGs>__gwYɝP8hePJ"v͂cll/].a,Ql|毾Նoe0s "X7rI@!qYG2"wGujk}sE#6t49 =<2` F6t몗YzkvvG@`%_Z.xCfGa-"0!48Dؠv3; {Іr=.T*;n"+Zip|VST}>햼nJ'Y)UmC@9s3kNW)K&cꮞ1TUy 7oi[wgC*,:bMHK Q@mf;,zcb7ٵstdgmU U:)V}2p3X(v/%ڧ9\1S;|iP~y;SNR/NHA5޳0UsMz3"ث>ieY>և;n☊97QaYvJA2q^M p5ѲPfU YuI2.!B;$-7EUe;X5}YS{>^ fA((/ -Ո◿>|x>!ۉn]pg 2;7FE3M3U| =.B*PjUUV2SPKlF76WKzN#iVbx<+X4 @\EZYhЂ& ͳ0^_}ǯ>5xE<2T5DD=K]Cb٥OlĸqMOׇIs2uunu<,nœUsYTTg`lMk ibxo<8Rt6Ʊ]n}u"lu\um@n/{8qaGǘyLۙk2r9Uԝ}'9Oԧlq~(Z{ЪU]5')}wټQ 2_vN*mn HQYCc p3mَH8՜=uCm^BU^5]L-i^'lcl.9],΢Q^mf`c֩ՄʤMbB`[<fU!@dg:NfYn*$pl\͍ . ~ؑ2vAIv\'%@`&V;-rQaTnU~O +dUcM%H6I.H_||w׿Uў/eq +lVMCV- ! U QxQ 5XIce.{w "% #Nha2Bkt#REmaMa.ne V QD@RVz/Z*w+]wky/|ϟ\uD C0ڌYK`IkJބ(x8F.v\/}<$Bܲ9"i@-`㓎5x*ݰ'Hhγ_Lã-naRle C$fOŏx|xǏ}y{?8 2X@^Pl\^,ܟ3h?0u+ȚˎҪ*>(kOɕɞFa&&Qb1ٵFa1|XuQڧS1Wo>_ wg??ߟMmM,GvTӧqCYqٿ> '{}O~O?|_~yr@ âݹݧ9(` +bW(R%;77g K1, *9Ю:@u4b)j/gZŏ5J]+eL39Up7cga% ԍFSMn2.A bz քH[ j&&=w1Ca&q̀@[O; dUZ8 A^6Sq~O8g087wxݎ#<+U"fafY÷%28x\ʬG:g0bA-4A[\,o͹Dafxt$;3k%A ؙ v13<˷q4={vdhSC-l >**X|sCM5 )/?$L)xmhVAi <TyV8]2Vn3ʺJ}gUNܢ1 a)+yܯ׫4Лn:SDyheP4(֜Ljf0 `yde3#|cF2lCN6&T[:'prM] h{UU3U%Ar~ ^ĔypgӺ/>kgl-G- hFY97Lm<)Aa :1°~ݼY)z u!Fi!{wR֢1TZJf@թ)LFB$Ky6rsӇR)T—F W`p}ڙ7g%09,%RڝkOcYRJ4D- !4CVF(tI`)PM 4HAS) K0j ~Ӈ?o~~j$Ir$_\v7\V:l$@5,/`uuiV~ѱ9JMfX3 NG+}TwknP$ :f;WH :fp/u4W>ḞMrrՔ(uN2j iT񊗣?!ɟr3뜖nvQ=muziV)QIFYKmlq߼b?fT4,V°6ZUZX5vk0ѝɺ= JU۠haFCjVҾ`}nݘcd-$G׿~QO~˧~>>}zߵ|/5?gG{ܮ0!?}8-lcT Y {U6Qʄw=q!SL1baj$L%F\꬜g韃śd?~}~w^\oWoyVu96CJ96?#ks@;Dw-ĜveKz0v,%{1)3:K4ڤ9&\կƫ_?~}co>WϷ~>>|ؐ^YI8ЦۡX-mDi ar"4(~.4FUhɨ|9HKDS+Z*CIn\cyX/  mnwN687^-Ym9Knn*Ztb T͎Rs'))ӵ ip4٭T9gEB/lXl[E:v=M(B]%}j-kgF6\Dlѻ3|-l`Yo}1+{27jҕd{E%0r1., LG5VjvSYm4 ha&ԊC0̫}ՆXjy:0GxeFu[bּgp?ӏ__xw'96 vU\M l5r#c~zkU lthi=_A륈XjN}[XU63k)롪hj/o2ǰnC5 zǷ̹|]U/ Q` tq֋־0j+f"N)û}*~='qFli1c>xBty|f}|qM`&ؤ<a+RضV\|U3on5ݹMܞ{ǽ>}[\WOoC˃_|j WַqB(>Ǭ総ݐ3ݢ!Ugw2Yq7Ţ6ty5`ʀjYV$Z h*h B]bJ 3 o2`(Q~t{:s;[|?o?{g?oXn,x.E@ 6aAV+ tK۰Q|l̢fnKWuU^[UeYJX[:;»Jq}U IDATIB_f5܆5v:?R M) + U:\t\1܆Q`jrs1eWNIAaDV=\V9]#lLF#i ssmdsvq?o~󘪬.k6#3N@Cէy½1LU P =fRILu|ڰ3",,l q~.i˅q`$e,\=,6T^w?1u\? f}u: f L!;+k̚K۔T a,fCbPhsN`pfo=Lc߅Yt% 颹YuwREMAv[5qWrT0,`E0ѢֳMlQd;hSew)@L%ƺ̗sHËVz겡\{V dEsXdH_|Wǟx[C(jp<{j. .2PM$!AGUU5^} ɎJnK)WkeFHtw UE\sc 녥GiVAR˜݋}Lʝ^zu</~s}=`[M:poԲR8Qf5>zj0\/[>3(C}[a4s8|~>^FqGgω&ps e,nImm?'䭵Ꙇ0 S9Fxr~QΧSǯ޼}G%M]uAȧ}yVUb&\[J7dT!%Arc @FUYplP3L[Qˉ@ X8ܺìHf 0۷M!t͌BIFμYf *n01_tdVJ7 L"-*y ufu3o3Ei\ ^%b489~?ݲnu[KYA6: ha8"<`[,+ф7L{#Oۘa ԄC0S֖XzҢlpt ة@1hB¦ϭ5x5' kH`l 0futsL&B^\wn_C$k o aa,lխ0 Uoc9# le!Va߿{'”0W%ܫ" S`afjp#;'blOFa*6|u}?/۱o|x1n=c#?^PRn-nu?.z&6Rb۶&B*G44˂V6킁Vջ7(3#qy/>{y{'/ׇ/w׷_ʞoǟ߅-[2dU&ͺBaN‚cħu,fX]JR[ r Ύz,ת\9R3W-3 ˰} ؆C5afl ){c=/Y·)Tow҂ys]=g.Dao|?z}?K[, A b4=WluUn4UU~wבsAj8oYU?5U~h`X>F3\Cp<>M;fv{bZeԘYhN&d1c&iz=;vkMY-lD#LGFCnVe6uvk|Ke0KBQ}<ܡIC޶r'*rd|&# *u7V' +z9bNdWF$j Ryzȓc8u2iG]Ƙ,FN2iMcbv5Z"H`:w!E{l!lL*23 ݥ>YȺÖNY&5O N Ҝ>Vq.%# Y4j+5jF٤Ѝa٧YnZŊ3hwPhhRO}??/עOeN' 8rWn7^GELH-Ei8pu X` z pV[|O*c8i{LW]ڷ%r䚻@V׷/_㟾>|UQZ,J7@WO]hM/ 45H¸ݵTKx4ڻ=,=nݼ2}xInZBQja aY3Nw6<N3cǶn_~嗷udۙ wۻ.ӗϷ؟/mi99 #u яҗyk2ʉՉrr:ke,lAUЈuXAk޳Hbc4b#biÛKKhnb:Jsӳ??_x;ǽ[~;*8ןt~>OUJlUMhOk!@e{I!F_(<mUV2֏_ t1T[A.xRDHz0ǰ.q D]Z%x !9P->BA=Ѣrl<fN=%5)DRhn!Vb 33cp 4_ߎ׼V} O7qֳUfc*Q&tf"p,lv{IhfGMg h@Κu1|-kvphGU RdՄυvZѕu$.qTZyۜhԪgsVʣybN^9*kڪ 6ԒJ&ld6d,%e#6$lLɚgv]na j؟:jC9(6 +T-01i0BN0*\Iݧa좻d\ DgKM\6 _W2cۃPQ\#Oӻ}/?opTʝm-ղ"WzU7okp0;1_y8dnUePŰL댰.kNPBd{ZCՂvlY@-n ZhZhe~>O?ÔcU`oa,S SZ yVܞZnm_/Wۯo쵹ms{c.ۥr̗˾M&ߎrZX^4PvτF;ݍS?V]= j Ei*?T u-kud}͏q??}a~W_ˋˁɺ;ilՠa@-4ej2A׈$(lKUh:BMI ٴc47o K̗7c^uafև)e$z !iyr|?~i"QY"(*[t4YF$x2qж׎K[>=%cao/盿傫׾_z:mmWU2X}6[Swc.ehGsBoeur@ĥ׃rg_^|

\}˝Yf= )|#-}@mf܂{F*U7AÂ_4Q+lYh+<\Tml$ZQ*`]N;Oy ]ⲽ}>_? oΚJog_^o} ?\G59Qtk-Rg9I9ti!r)dy Ղ##8,9xkjw'-fbe?_[$Dˀ]]=zi9D!GU2Zeѭ"U"mi[H^h6-`n\84 \87цeS}sUUyTV3 RY]Ē;l vO)4ԝ1`f<+caYci6\jF2]=9x.;>>m.ϗ~^o؇'ۙՐ |9iF @U2 ꂵ` sV]6GG4V!%@!V[ t,}APýt@eTy[SoB}5:22'yvCܹ9Σ̀ȶd\.%i3_7}N1 nv>"#ilƮ eKF` u0>ϬJ 44Vv{=g˝`)8ɠZp )5ȒZ(e@oON=۫Q7I̲,Xgg82r9 FcXgjC~0LOߨP/_A~g7Mys~T=gosTﳛ5u /io:|\my,3'Ȃ)CwKh`ιL )!,vZ Muǰjzca--ZFU-5LUӅAӊH _~oryoeL,^U\~zJ\`uPf,)mX g}? Ĉ)p`V֕ZnTIr7 @: 43(`qAvy׉u IDATMy{9w:yijm~yP( QـQiDŽ8,ݯdGIIz,n:F pPZsuWw`7A3 bmacTGS,tJb;j8;jETk],?;4-L<%_]Mێᶾtөug-m$ëڷrecöm6 cz&trlmN[+PJ@nkK7tݷgPYӃn2i"d_2KcJVen݀ETW5Нq?uQ0: [s9gd=JYy/p1 LѾL(n>5- fBr%z:O;aX M֖`-,벻 Ӿc%zVwyJރ2WZlܭay0c  !|"e0A31:hKCfDZ^i#i^hTA̢}tٮ_|djԝcivfՊ͎ `\\Z!*WRTeCK8DA{JreS-rI2!r2 HH~# `f@:}?m~_W~OꦁUǺ{cG* MBeF=,\ j §w(?mRLY'0-pdo~vpreϟxe#-G4C/ fd//= #s ѱtWj_ʥ2vCVdpVS0*uC rDJPg6YZ>>ԨEBooh:ǘuD.2R#{F|?7 Y>\9(½kk2`۪6i]~7`[X^.MU$αmYf4hESUBw,LT>>Ƨ iۈo@^/u|7zx 9-V]YeTwqhQ9& ( "RX?{ a =hFiW%1LzHZ M p`u@96-3#z9 Di TPaF7vηS7aGAU[^/vNoif㞜#{jTe>a6v-+rG9,hY5n8(떔ppT;6Tu 'Ð%uhhжj K-1z3%Ij6 #g&:ىŢϙ\RFIo4NVZЭD_}>{o9nv(zͬ4ߏYdн:Í6ܴ@<%u fVvȌ*R:Ҥ=3it>k,^*O[QZ2_::v});T !=6nWNTǽp'(k,6h3 hs{x̺3G3ͭ{bBMmDKj .b 6t0/vS?=PDj*FnnMT,jB.ryru v4 u?#j)T1W̪U-#LPajvVItYAn M ZGnTÜFc/R 0޽VIU%Mm,s0ѐeRݒy*e j 'L cO>۵P7O!cYݾ]\A$5)uFE#Y2¬sK':Bnn0Հs t/_<_~#:"DY4.8]mF|DebϻPmU?nZ]=BQn_OnA4&͠G%}iբ*!ìm`\dk7Y,na(b//RZpc+÷ nn1!#roR$M]1L] ^ޞ^~C~^9>3T=']2P5SGQɱ ۭ/\`p8xW:`D6S je޷u/q~G 6.ݹx~o//w"np5( [mXxs7gm6r⇬iJ(WOcҦ΂]ȸzr ,*&ec}hƹ@P, %ʌY]22A0k2&,yo~zlx<]v==o}9>7kuhlhRmMLE.0NUJzZEJNe&Ia.60nDnGTu6Pap <ٍ@2 rAp-SqAYK(O zl]B|x y{-,gսAc[-f [ PRa;9$ Z*AhyNrkvc91ܷ/s,6 z:ηaD qGȱlޫ.]lQ<.鑙/o۩ss%ݰ}CUg"~]|7Ǣ:l+ԬyhJSa|}p.a(I-%n݇#ݛ04sPQ4t,WeO֘~NĮΙ+]h:ɳ6鉐0gu.3.3u=!vT 9GudzJ:l\1ԔF?h.R&"֍Y[ྪJPh54k-| F09m-Y2r$Ηcro=٭v(&Em3c8dnrɔHD zRǢ`@T@ZBb.I;:60Q7&(w-f*dA2 3ײٕϷ?|_p.̰:a$2sbxݭriNYU:{bЌ6ᡕ!psMmJA[PjRHD RCp%+g:=R@U}a:~U}SuwG~姟n}oOٴ28z+pufecc2h'bz􇳲o﷍~]90OHzM.s!utlDٙ)L=vCz=tfڂ04Xu8h<.O>~_Nc־=x_lU]w91/oSo ayTuats޾}y9r̬ݬ+t_;coyp.:~[;ɥ0Q5y.Пw*b [|l,!4J4} l8> D/x4Ks%[r _֭Y(H@24DOHIIEVxߙHDlw_l4--@k}z囗o?OtT}>=}Dqǻw_/LJow_gzyM]7c=}//v̜' aZ@[^RN,v҇4Zm StcaܜajwTel]7gOْyT #fYOO/Pch=ƞ@u}d}(xm^?ףwbXeUEU"ܰ@w.)4U9R-A8$AM̈tQN# ÷pHͮv Ja ~N[UpsY3;z>dϼ`Ax\O;oa?Sϧ/̮DUwZڂm9KW/Rz̗=M4d:s%Vl^]:&jNVscXYR 6]M s>c TujUe;ktyE$os>;ƹJ-n[ˣj"g-UZҶKޗz2 wo艵!`n,a1D8us'ps%y˳Zu3_s3VYiw8"K?D6 ''lV \?k Q:tJY]%s%lkKRm dQ2]GԲѬA[Y&JvB{ͲVlݛ?9?~~_᧗> Z1A[-3im2kZnK25E!N3Uz-p׃LEi2S "S݊2@FoA8O!ɩ4RځAJ<%o~S6aԔ1N6`VV3Vannò<ϫ?>7=o@a{3ny.6DتӏvmqAP[vvC]mA*ԭ@F3paww5}ӧOncÏOŦ7!8o1s|~/l?{oՙS  4o.mͰ* Bjzz TFU]A d[fW')am*zrpkW6JK2ۻVg¶ +"#i[M1%ms٬U}/yN<㌇feKJ_O;Ħ gkY6H E3DiXm=>|3i( ^<Pl]E.4dmtDk*y%zz|>v>\xwHO7CǀUx#$l}~|fTtܺk8f&o0Ոaݜ Re`ls։&x.PӻDÜ;,}\OmW3]FnPI*Ao!CS..V&pW-m4:}XQ=x]p}6ܗW,A VbR0flhsVwuh1jSHE1ZI#>+-×zeRswll 8ĵQYfM_gWí)ͮsKEa_.ᄚ_wP{4zVHaQ|U-XD$6z>KʁdվWAFnhyK&`&nIزa]TE(hbi "܄:\3~Ab؛{~|}uZ'P˞!wa !ZF†e]^x[_w~Du.ybmrӶB]0tX6_l7x{?=|nV Y)Ȑ;sإcJG J5 [Vxe~ǧzPqEeCz۾w/GoOv*9@*xϷsg9rx]%$,J[Nl^A:kVHhEEX5NQDu9]n$,WXHd%\- Pjl[ex@ms swǯY~'SڰY~3| +] Ŭ;>M'[A=hmm@#AawW6n x _"XsfaV;%Kh2OLz _o2Glzܞ>~~py o5CEĂZ-E9iUp5ܰ\Q=lh 'C(r:[F:` a=a^3t;VJ-tЬ&t2%7>809o(lyL܈6QWcLv8[=%ƭY'yr} m*^odYz)jTy<20VƚvgeYf-pfp۝ >ec,#]G4&21[wNѝ0y56_|̕ .t;'EwZ.rKzcΩ^[T \$ZqC \u{M9̒;G[ϋ>ы@䫌2ö_jyyU[ r傐-CLfJ +l!ΜZY334rs\6 U{,{x70u(ckr΅uoFHHRalaGbMn+˿~7zR H |Mvn>CV!GR$,A!p['D+vՙ(]E눶:`z80sEc&bX 'NIILaN.;0x;><>?}?? ֨Z,I=€,pFXk4Ja켻CyFv{g?CMJujͱ=1F=aؒm>~:nnxyv iK\M%0 ޑ^qvζ"9OUu)igDwת02Ww|E`8Z<7Rv3ZCtt"!B(\ysv!DHj{=I1 akr0"‡Ά`Au{VbUGKH%͂UwlV[͈nz/y>j>`yE.˥[ IDAT_|}<}W߽At7QEa˕.$Jah3Fc;Z'aA ]0,Y\*6٠Z6H|xgtV/:H¬ΐUVJVȔz}y{^mg?>]קWc#4"C&e̮n绳 F36L%Kh3BݽԶ#Zꘆ]'E:F#\ZAjkMm0e Skf1-SyeۼMw{i:n<Ϛ7P>Om69ϪIeYgѪ|bhZNC f 0PYm]q5e ƲLY?%[̺]-B_qsZFbl! ƶ:3sfn< P2rfd8͹gEԅ f ]YgChLYyV>wUh4J@<%*AqT!Zh?mJQmPy@AaDݚ9o/댜m[Jcx 0mauLH `Wcl7Yp 68F@M*('`֨:aNK-Lt#[afٽJ ^»eMC mj٠4 E e}oO*apD  `D[UD);+Ü`PG{DcrA*!Xn.-:h* :6E[ m~aNQ h"1Z }arz_/ɇחkw2,jmЍL m";=.7hߞ#`}luۿRsv[.}X^va=n~6nSuT լQGLfy4 Y{}NR;>?r{Χ<)'+t01|._ǯ_;8qװ>a]Y//<_x{f Ѝ"=bt:.@tsza$W,qRkZJ9I&=}aϲA`10In8 %ׄA2r'&j2 e[?gW7uON,켍Rvg/~2۩ Jy}%iͺ"UnC+vUl[j{I:!sF)!)m0boXJx#6t2c5N[sNV]KZ]0 C}Rs 1|jTs5!!Ywf9cwW2QۥIV_ܿﯳfbЃf"Nkd{˖={w:޸kæIX*jnQ􀔕1FֶBF4v{_6φ(V*|/1z8?[{wذM3o/oQܘoz?>}.L-T1Y5ls&Va:=:MߋxuU^P89p5u6-tYl-=QksZEFCIr&XnK&&c6m gs䘷O}~j29Oh%KZGo~qrR5o).ʖsZ[H Sn)4ȔZS#82t( ͽ,¬ v 0+І eέsI9krW< )(9dFlvq4SFjkăp/kɺ%7+QI*d9rsr 6eW|663%Ap7_~zz7w?|1/\!5RؤAH(|%ںPWSTHɍ΢@wf]h+.DŪ^&~P[.VZ~D?yj+{3Lp:a@/Xaæ˻xO93aF1lVդGm exٯ;xnO_|z܆šCdzz2͝3+1Dެb!H-J K3̛0vES9<`{, Zl܌OY/qt#4g*x;~ݟ/߽gcf.Y58`m/תyDXCEhea _30G5E7542@hʤ 8 ؄ю?D4ˮwptwʏUmWVl#2e}<?dl[{Om \t2g3UkBI(xm_0|CfRW8CoU WKj&}b].ƙV¬9iAZFw2d:Yg`CqDYny 3Ě 4bH ۳5\b _DeR}Y+ Y>ז#"UbkcR voT1iXFZ_M1HK1sQQf^)1uu6C /4QEa@i3רsυvF;ַXʪ4Tfeo^_?U(CR=EW2Ж Z fUmf-mH܌ pVӤ*_8KWyE؂4 cAKbk5D!N67jC0Y aQ(̘u+j?}݇ӏz9 U͋$r!pߺMۮدǙ]^v=?͛gklUܻFmCi5̙ovB]n>;z_ZS>PnpX ȻrQ=sc Yy7C߾۶{[ݲf"i}"GJw']qRk~طϽa=at .F,$䒪e f 0")CDi+ufɁ50vc?|wd/x'??tQEI( d ضu\\Vfmkt*_]fä$AՋ 2{f5 aa ˈKEҶm{sot۶;#ghdftF ֙|~phVuӑ8.=F;\k-hd5;ohsm[fLgXXYEݼn΀dv( aPkbS5f0߲}=tsT6tz>nOoAۂ@i=d]g_yܶ)p|N}:j2w,|]澛ض೹M޺JQrƻYdlY%XRBs+NJ,8W0^̙݀&rDN `-u,/\!U$c0R¨Vw `URwB!ukž(&бuM~@H%Z "atfKαNo33ĔZb[TC6*ż>%:GQ٨v:mlueED)>jNVS ^T&,:Q,nFJDYV`ѷQH]i4D٥"f2E5 ov5T cwM%ׇ f+)XȖܶ ?0vSFZjuݍ@۾_]>yOinwXEWD@PCR FЅN] t0^])NADU'@ݍM\d8XNZkzPGuA=̲B@ ``Y+Q p$&uE4ENv|>>}?wb~BԔo[eͼ֛q(""ϻ<7Ou6ߞ}//ŹpT`$vob;HWbNxhsZzI E"@*xzy>hˎqݎLeW\t⸧?p-Ohc޽O=JYk \?}([l^ޔCj٤;ڻvycN6YJ`6ߺSfUrJsfQ%cwl-tuwoN1gz 1p[lz9>{xc['}-=>vmz},̴>ͻ;Ǘ?$SBUޤ_7$Qi09:K rcV5lg2t-EgaihZTłulpZ4Ⱥ`pk.kd{K4K{]ݐ& yG{ wU⎵~~.RI/W~Os?({0v4z%\J7> ޱs.%Y(]&3CFZ+ Df(9ed裫-<=//z<]鹮/oe $g[u`nCKąEWt/փD8m_譁j{}k,^ia6lNT"s#^|=εD1[f" wDtG#΍YE+1+-q60,Dڄ@PNLJoWͻ|~O?o铁$5f3Es)XDgZF6Jd\Wi9d,?:Hh@ %NHr:n$bƢ9)TIsܟ+iUʣ u[e72 h23k-c!돲]폟>|/~__nY%_9d|;ktͼ _>2>鴁\=QkVhH9+'j /O֏ι,Xf7+/7ZlR >e*́2̷_TP?{Y1G̫A}?(L>l{WfۘOvmP7E짱ԟrRmh{jQM׼ޞP're*8iLU@:#\oeU[ Y M<*IU"-g2j&r s b*3\e5ȊJ`2<,3A|xyuo!+11׻f~w;tl?'w73y<zvOPchN~;ьrya49IJ3{7kN L8oc^oג<NoD$0}زbsRiUijaUv>[=xj;b*6 / 8ږs$5˄T D$1ƵFϧkPΨqp G]Λxe/ynQOs󹪏// PN!QevdY8h[s95fάe:]sehxRrAxu Zfɢ.+D0ZdڄfT[H5sIg#\5͛&n/m&lHpLHCi g.`p6%&/7ۿ˟o^ 3)ĝP,[<5wM &$gUA=sG$Fi@-KCP&qL,Qi֠' [UrFDHP\Ҧ̪8m"< HH_ic -pZT4wׇp}}7_n|z,X#I+R`mk bۋ<ÏyuN{x0$4,4xp[m璬Au;(^۹c"F[ݪJ<^ Ysm~}N̜[[ש?a _ze0?+=, IDAT 4'PPM9* )e4WV/:nI3A@y@t4ի9{f@),EIVtOeUҬATZq2Yf·a%ΑE47U m?{O_5}iZa\i6tOaQ[8Yc^EuIvDӇRLf%%+c74 &wX (t[LP5fl@$ܝQA7e,l.D25!:,T 2._ik{VUG)#GqTV84ЕQ/q_y>ۧWO]L;9 W7pBmQ&Ptݳu8RN@A{Xf{ti6fd<ư)eEXQy5.Ǽ\:pv R1z ' /#wǵqLJvxvy3[]YcR5ƭjp{VY6uO[zF,a[B89Ae9cipekv*6UaXf>9}%$nT֠Ve+ꂙhd zKiT;gpY*'iYfl9 U4@I4HniX1$PN䔻,L6)bͿr @(BMٕӖK̐:J30Qn$Ƒ-0Z]#+N-iNFr%RM5EICr"ýv f"^kYYu(z2s(1p/Kl+:ĵ[Y͟R*J.I0lAsex=ǿ_? Yg\w1ˠ*x,Its_LdLZ}SY90FJ Ӎ((xe 23ZE_Y*:WRT+P$ld%ek*2Zb^#ɹD(r3V*y{\>|/W>=H!F2B'+U3/I[=\_|p75!s넄4IIUA4nmgV 0.vWN#T,T1K(8k?17=,ʹSܯ,YMBR^8'y~@t|vl÷_쾟?Y=?~cs}~6kHI2> V^vJtѦ ebn[̣4_,6$1KJK&SEԞH/cd!,ZsyQ#CU} ( +o?Ky4MTϼLk뺅1Au$EaYeo{f[|Dڐ,k,U E %vq3jsCp0o/9[Ρ*ս[`摣?-M_0\ԏLO=`bQ#-) Ye25֨7)<^}EDvެY$9%1|}֠0fq{)z3+ճ,͞es`N ȩF ;˵cm0;fH?.Yy*ujcJI9ofSǵ98ommͬ iZzD HD36"9mfĆʒݽMb׺s̱Lm+/ifQ~e R:Q*VCLw@\/rqHBdVzUc@K6tepd2t Q,JE{mbR gR1o־Xk] ,F8hP" ϙ3ZL`$,܂Y4jaڭ,G7c*mjMeT,k.|fZ($B9`RxNP\3V5Uf$T07$SE}}{~OC{J3N( i9zfL0)dg+sbZ3ǔDɰ Z -ߘk? pڻQ2.dS`R\xPªYp3[I ݖkɝE;\^>>|W߼}󽿼t%zlR fnb{Gox36ٷ[Km继ffEidav6JVQݣC`vE40PΈ6til=nc':tmy_Mb:ck*0'K4B}' Ys133 c OZۈ5k1܌4dMBR/BچJCp `0~J |^%EͧGtk^m8n?i1^F4lgєJ5ωe$e -nHL.gtup3קEl䂶hp7W)ƀ%,sI99T'̣ũnqQ3cʧbJk#*=vϷdn{0n<&fɉ3{ɪ o9gЖٍR=Tׄ5dNl;<*T[ j&byYvu6Ϙ>jV am}41{zm-$`P^FTۭJsgc93I5&ެH!9/kD83QZO""0ʊLweN9ICt VjUQ]9fe#\un_ߠ7XYV!m =ƘŬd 1%遭42r`Ymsnf2WVҖ`=,+ *`J P4jm֐8MNeVY-\ c gurG m͗?<?]?j?J@:my}rU${)kT`qX PPf 2I-4 k{dɴF D InYyLݤQ͡yMݛ~uגJ,hD [ UǐsX :2v/8ջw'qY0(SĜ^1;М4TV ^~欜[l-/||9mޮi&[&km #_ 3 N2wQcz]ON6q6P [kV7DjN4QcbҦGx>Ri,M"M^'Yeڟ=Ss(e^5,ʩs+nV8OxƘKQT^Rky5kG"h 2 ty ,ɒ%Ăth[׬@j$8=+}6ͤ֜3Hh-.+ 0?&70 ^h-s;adY2"" kQTEs-~vw{e 4wrfک)1ˈUtXFV(͚JU  Nw[{2?__opL,1Zgd@{ [\Z,HpԪX(W_iJrX4?_̑&( `V~\*4[}*׹s0 J`U֥tϗ0:Ի}?t,pU.cв 3|$ELcrWԾ:ܜe2:9蓕f\FSI._^jw~8u )Z8DYT*37" y#Z<<ԯsۣ5=%Rh9|ٛmsȃw#>}v|}Mw,a dd9^+a ^6kbOo֦yCe\Qk`ᶧ D sXXt*32gmcHoimm*YYio}"G&1:]pʠ9r_Os2l;m_<ݽLֳA* Ҋ*]9r T2}|۳7!3~HtƸ>ƢV]28@'-%/SFp65k0^}{dvWj#ST@gMIm[׀!>.)D1bFu<8@5͘vLAF嬜@QPN,Xɶ"`P1{<v̉dPN'8Sd2d7G7-Z*me8}f eFN*{dWJC3eq 1GRG~l4ޙGjBڻŕA7 =HTi⬤T̫Ҡh5/qZM%Ya&yjxtoU%޽\&vd- %;1Ur2XMx:=>?f lXi}Sm4h]^| 3fK{{tܚ_ҟglFeq͜F38tw:[z"=wSe˧~/q1?=DsTQ %D:LtDڴB)a`fF5ög͑GEWksUJd@\u`^54}UXjYZVYJY^󷲯~u;~ӻ=YY u[^/߾W'y'kx͸<^׿wDo3TՒ)7dmӘ6f";rNEVn^$lhn5C5B)atPX!e8̭Yn;6n2uă9 Fhe4$[ r*rmkwE|l>?o-_Q jTy"39^5 X j h.U9f(TfdI笶6&S{Y3bpcCN#sA Z@gmL]G'Z)̐S M[ݦp7Ñ0y j&5&)TPtn7m= NӶ ̼ifs+±ifU=xĞ-VaEk`*u̎ՇU QnS7=rSa皣MV##m[^gu9}Mrsة}Z&IRk,Ypx!Ծ5-lu7)Ȍ$(R5iܘ0kUY0U-uqNXH hݪlJ%%t\̙#Ľq12bVIrj <礛,)h鈰EΡG&eFMX%RRu%Yfb UK<A}ܼACbVTQH&`X/cb0y۷_ݯ?)6k\W | Q| #wh,3Յe:ͭ(Պ5iP4ۘ J٬B iAɖDx*5ؔ-sEe;c-ł>7ǧmޮFѵ"=nbΔ#12A=5wAKJ@)֌@d Ua (1Ց,WCUZX* _YY+!g^&Rwg;Lq:.i5373Ϣg?cn~>~zn?R{;۵_/u}Soq8YV/J fNqIY# ,FKB/nVp1`$`0+ %?Xϊvd ppVY ƶ`Hkc[k' ?[{_O?=k4Z9ٶ{C_rv4q6ky÷w\/[l3N6oW\oڝ}˧YJ0CGepRq3i [hW̬ l[5GQ-`/s*`ӛ˔5|>5;q}'/஬K2nFAM5!g*b~}x~Y|z$LPf\QĖ/Ijq!fסKӶfAEZ҂&VZ[*ȶZU9sF%~+j›mss>r݋&xi} dP\xJPch{^}}cHWVޑUI%p YބrͳX7q; Y0Nw54{W`IYsߛ44^0Scme^oTΚϭCp%ht#wEĪTh.:`!)MuPc/ws%9!J!yiJ5Mn 5fMT R:*U,jnbs, O3,*˄(Vr Y~tI1d;Ai,|w_QuJv!J%·mۏ_o?vU~Ά9ʌe>vze+Sp8jP Y2jh.uh90iPjB^bЂ,CwM$ZAR Bgs~m:9c\d3cl+}sX#)zO% IDATAع}quyyxU|\kSh>ޞߜymaMl\RK5!2;eۤUۛʍ{;WD՞/5wOf Is9Z9 j+UC L+mA# U94 Yn"aVU3v}C7]w?|>|v.4y͏~>U]^7yvwlT=Mp۬ao Vm+iV -47orFcˬ:UF|Me+N0ΧvD;%K&Ĝ=rea =~d37J2pIݷvq sڭ5glйtn(9zk1.w Z8K:Z[#ԼiU7i,KQ{DPcd7 @ ",6z(tUWeUfFfLf]U=\\/pݫzIضI Lտ(9O5XUԬS5k3R6NcvڶS}γ}msiۙ+߮n[Ufڶy;&8ZJ<%HvV`Ws-fƨn;{f~./n\`1 ʀ(4qwʧ7>ݶpsrlP0ǡ0СݥhTUTtf9oϕy?ĺo֣ZYB+p:o\&tS+se9'}c}/EU&֠E0vq7۠QihUUYQR͠*+jmtUBe /ti s:hVw/e",2$ES2x,%6c[H|?$:8UM%ΔQ $B7ai>湺E. z^VYr.j!҄1×o'js)d4.(d/u%)VfaZ ZiU[\66Lb-?i)[Q0drxt&[0LB-kfݽ* x|ۯo|c< e͂c Bms6*;S*˙,MV) A {`\ݓq9+ 7r~)z^fŦ*mNoo`(C܆] &npaBѪh#Z:30dGg׺˸AS'Xҹm8vy~v;3*0Ж JuMsjs|xw|x}>l~c~=6Y]s} sP+e/^[+T cLpg9=}AEe8sUls* M#g0UqJP~}B5 3%+e{z?.ڏ( Zf'pmr1`34̪[=[>lp*Mh =3$smSw*C0| }7>,FD wcۼPh5' -"*XF3tG b5d74myS gEϷ5UaU"Zbj6)/?rsHd;m0#k{kVc6,+Mk.REfÍ3"-%DCZDBJ,.RGsn*{fLnºpGXԜ װqlE91{z֜\lJ9|羙ыOVt٩|13liphlc\.P]c4mVd 5~,|ou>of==--Lay,.V^q f$-cyfk8uv fo8gB7vjU3\Ymƙks&dpU8Xo[%+gk5ef`c%ޤӗ(A"񜇅-cȱmקy|Oɛ='GE03c7Qua[?n㋳Gu+ 3 lt+4wЛCk_U[c6i\6< c3 ݟOdnʢM A7_zضhg#:Gq_MBbku!NNY8Մqp)wbfev#F㩫+rIM?7ņ~}7oOstS +p%5(s҆[ 3a׹ sUIskYm*b-X P= a>s/=1O=ygO]VdLYY}%xzzCvٜ”7_L%ܯ\f؋JЬGWrwv8.P1|`YJCQI)?'fq&yV*)dEW3 9'7<1iE SE߆",__㲍~g1jl4n愽% 'BB{lw#fn1 oKp-YC8%0 0]' nfhf8s)/UU6iN;[=:޻]m6bm F$[Ϣ9aNb늒Zfdj%Mn٫~=~ciT*wi5!2WK]٠,-g`+u [xϳ(ι|~ml, [ƦPM; YU V#3-e{6ڨK>m|x-`WJ9`E_UUjUM+b4T=Ys)5@Yl~ӆ.#zv x/_[?X-XRqt[p-ip6 `va#h0ɛt܈8nD2luY U,ɶmx3ؼZ@_?WӉG}ćwvzߞ*?TޫogG28><}cz3Dijݻ}?>}^ 0.#L/i5#Fl2bRժ5FȇeOqB-GQjiKy?-?]<>t2~y̙wQGK!YUeWS:)ꀙZ}1ۜw-+FuT-G W{nuڬD0[i.(9b欈=K. lU8άUQlcJtwBwTgǹ[=顦͚3ӼۮTS'֛) /aGn #a07Ugf<=ܽg \ݹ?**c܇k!W;l0y 2&Psժ*I:sC<8'(2CSz<[fgu^Y3ls$cJM%:Вj4FxqN@ ѠQXXA*XrރXi9d5~OXU>KX8[=%Ձv SyvmS]g*:m<،F 4”- I Oi||e\X?ëI L Mʛ檊py2NT!:mM a@_gsl@rcepsJPq)ԗҦ$XI:K$zyXbKȊpvQm ~VU `0[8n@V2s3`8dBKlboRö&YcX YFH_|XYlDm /!/)c We #dt4IZệZfm6\ XF5 h(̹$٦T7uU~{\)q3L2k8R.S`Ы|>|ͫ16}|O[<^c~R<s!}6ƫ!c#sZ=ѻG}%nY%NBl?u/ >\eBen*E.Ŝ6gv Dͨ0]M#{USjiϪ1T̀B5imc,+M0H#o6+bkI]Fi<]]A[)U(i kQN@emx&)+g:,kQy{UbN)Y٪Q'мg8:oL}XAS>(N/S ww+uZ9EMK,w |!׶49]५ ՠF[M3z:}akY9˭OAH 'Ii8̪͆omЀ wg(3DӼ"YO4pPpdb &T ]ĄA|Eev#eafd׳u%xBh0tNW7z<>>__}~kr5\,J FfMHսX_KM@[s. QUExK?DhE؀i ^f seY|q)hep2X]cxu&0J'!7_%0Ui:HJS$খb~/_bI: 0-bimD pO3kVc=Z=gus@rApυJ793FjeEezpޮ(U)geM)W`pZ ˈ6ϙr}?`љUr2ZS7*JVA&Q 0Bd $oqMȗ `M E 'a< %_5D;(3ZNWO~w~wwqO> ƕ6rOOݺS|g=}xC?zϷGߎҺQ<bpR"z&TvnIdO96p)Ѳ6r8a(B=AL;D(qo|?{wI;'`!O BMmn*g9̻O6qV:NڵCen9[%UkYf>6cWa>b@` 10'ز`$&XEeܺ&Z(Ǧ`Ջ,w_?\Dm<{m ޽.ղ4_}{I%6@IjWn[ V7[Lw|(GN ?P&a|"}1+1bkshY&mp{s=ìfjQ>3|p `܆Oj^y4~dn.>lGh q8i!m8463 @Ddaqtܷy(F;mVzI/YsNhpZNPSQf~}ۆ a tzyRa]?~~ywSMmxnƈ*iOoύ<߽~b[uv/Si~?=S<ф:rInQm!vw U9KB2fWnnrs=Q[8Qؘg]`[w~\^3>ɧ/tIˡ\΀m#&mxCΩO 1U45˙n\U5B^^ǶX ^p ucZgeۋA +sVvw*d%K8gMv~׽ow۾NоS%dy͏{?8Vd35Qb`.#:eSՙ3>1*q5Ÿ*M"&.3 oFm"Vɤx WSd=[u f5/P N7?dQǁȶujy>{2c&qVj*t۷.tz|A:2Yo  8$bT s )D&|S YުEu[RA0xۼ`Y}=5hSB|-2̓,nVUF_*Mܨz|X@Vޤ9Ag#TZA\JqkuQL2% $ۡ=4[9b`F)mN|T+K }ٯۏ~_3 K R5݌kgvà H@{2RVI ybL:!Wc2`VA<َ5ّms"!I295t%B@F{ Ѕ T,Issܷ-] 8'<}}-i&D뗙2 enF ]b [ s1˷??o_g=;TP %iD%P']qA*,u]9'Y6(U# p' f$1tViIDW1O_[<~u秬ff֥yf+wŧ?}ן~9/Qp9Dʁ yR0B*|,{+vnc;ӷECUfmcd`9UmJ+m|~|,,w ƔW?_qʏ #:{fcfD5zux7nu+6O\]}3׿1t,h?>l[Dc:3ݤbimsrЅi"yzEQ~/dEFl`FBk _oa Erl#ط7 jԩg"00se.;}iP6`v fwiI4xN vl?~4Kd1<%=@ hC[N:><ݲ{*27wos([Ꞑҟ( nMumޛLW!Ǻ hqᅅ,YV;`* }EijR:motv=[ugc#-}Ώ|֑qh4&ha*uljʬ9 y΢Te˶]b4+vzk[6.LsY14i˾cĩ 8 /g ܄޺yήWzn}tܷ3Ӣ(u\$s)3Or=GYR<^k?QC$d}&ݝ0D݄\BŠZ5ưhxHqkl],M#ΕHҺkR2A!ᤵ97Nhov鷾'ǡW׽y[|~/yKyNYNIy?Q'<^cq&83eG9 ,`y+Uv%Kym㨚j4룡:0Z/pU @:H۬pyدWu?ۄtNUf!:l<\o#ϳ0+mGgpCXud)Y>z+V|y5/5:y;3#y:yPr9ŒDU{δV'Ж{eVnaijf~cn':ݦn~+aV6zI!ׇZ278F i(4x (8eOe,g;܏< a.EDBMu/aKیF.0Y涨=,ev|<,vuه5]ʣTy.'%9y~׺#;o>?\y}3^S*h ='ۊ2a*-&]*f9#$ͪ `ŷDSAK?1ܽ0WKF+Ate,)(t$Z%sXG3(hF$mǿO"7^;ux8MQ-;r4a@{Cg7pZ$S]:=Otv|%Tlγͩ>LpGc$鹪-jDؔqDˣ։sC[:d .SF[(%'DU:NH>3:9Oý6ay ̂f!)tښm7JMz*CY UɆuw9QcH*'16씥0)LzQK$^U!.փ2à:'^zҫd#&8+ܘ\EX'T["*f }(\GdCCًLj0H%]Ѩ3\LE]%L,U%ŦCfa 0(nf(U/Fau3Gz+Ysح,eXJ3TKw4$plY|xy}}OO򣯾'wwJd8rl_L 6304vN  &0e4Yf \uΛWQ|zIfp0N2 `_@eNh5x>n|3u\O]{}Y4VP>{9{p|vkV?<~Hemp3qal96/w*?}7zlAPLyF՜,r<,nꂻ:[oW|6 S=87>H3yDO?[6?6޿L@w#XA={n+9O-<ϥotpDْ\2r8{vۨ@1̚lXc:,valaU]J&: ζߎ8$]gN9l* Uz}3,yg9c>Q;NUΆZXqlqj, E-zΚYn&آll{53-̜#V"[gjјRaifcc ]9mG~D+EF۶Etid{-YSYf&ۖvAXj֍f6[lu;3BpnjY݃f*l̒)q?y~ٱ(U%Jc|`tuWŁNkkL*~"2-~3ͬXl Nxm$gbKOs*imO޼7w?O~YJ,J.(funl,Eq17B+!^B)Hk*Ʋ*:-L0dRoҊA2qJtV +Be&-Q7, >Y;ǖÖdVwv?WOgUfJ{t7Ke>N0tOPYAu)WIC7l4aL3Tm3'S7m\ shVgX$dnB'0vك٥p36gkIZ婜3gS;4Β{0:>~ן=K_IcR.|@Ɋp,9q{yc+?8=^c~Cgtxuyu}'<կ.{v?Ϳl??w_MVo6tM4P3n݉yϜ}̜0P*>*ڢ)CNRz[jYkr-%ʈqD_wYDS$ =hٳ=\clqq@U3zC3Ϲpjљ-,lc9fcF1lH%liq܁y}߳㨚[3%x/m&7BU(*Fy)'眙uo=G|aV(K]>m}&ۍ90Jz3,\08؆.Psz|߇RsZO@'cmم ތy=q Rq34~l 2ю"}مV9SV%slL\u yɮ7ޗjv0FGe3XgݡFW%k6s&5$hb֝ZF"Yaa'Z:,ɶ-H㚴`1H x-e<"~ԎY@P _2Ohp7H֫1Ѫpt-Vco_݇w/O}v>{cx@A7|\ 9@u &&s4#ONzK'`m-q{ft;n!ɝ;V%}>~z*Ϸ7۷}+:Ou))Ítvqjٰۇ/z<}W?̯ލoֽgJoMz"]m8I` Z>vO!$(Y~z]}e}T"6|qe.\-B`{1gQv'RMs-h-n$d$ݯoM?on7gͳucFþ=1xSQѝO>`Ė~/k~8y>ۯ?ίPst" 0"W>ϓv{tOC7IJpݰCuXd)E,H_kuc߶x8MGyyU_TYQBq'Tv<[Ӕuܦڶ1ܞI2s`l5ݜֻm9Aqƀ hh:~*>E3~he}L#qlu&=Kt)SflZӻ &awŻ_Kyo5<\HVeY(/9')3fQ4h6\.#-vryz|j2oޝyUWV[Zf[\h ̹aR<,6F=""h"(TՃU!Q^ *hWYQqFLwhޜBs0&.[0>gz(hziuBn3Cm5LOAaV@ pb0iR*qj:f펍L8xPbaXtP\"Wf\|_=˿'4XF`DrҊ酲Q6Ka!QFW-k0 "S,`Mf HHZth@O=dm\=su 9V}`"愈TvX2O>=.u1aׯsӗghk2%I3@4/>=@s,@zIL(N sppA۳>LTƎ5-_#{Z181쬂[φmmy\'y8R!x}df.pk}lak;CV/3si˜9vFfX0' 'NR]2|i6!iGY]&0k-]JMD *&aD'>PUxz?WsSOfgC=gƸøk=:fpx].y޿a_z:' 72w#Iɥ͍+hٙ+H{[@`2P&SK0Oj72C< ѱQ* .c#eCԄJqڇҿxWVb%{jp&ՈؖߩQhga3٧꛳u3 )|#M(ڔv\9KPKmQPmP166[ooT(Yز+j34/`Em8u@<#ݺ;h#P0u[&i-N&)< 2؜6;dϖ54sVچ嬠L0q +{4Ѝ16F $G c@n$`l*Ij,!ͣdf+=r_y׿~˿?VWj5$;N[jDAegVc\tĬh4EA27/:n`{FmJ(0j IXY'{hf! 5{s"ڸf=Z4JjqaR*=܂*NzW~~0bh۰0+f@k|.0K #-{[Y]aLTHAJA[cJcSdmAF鹊XaˋJ3LfnnnakBγ&NUWno|/~_ٷd 'J=vh:a:WUgϵCQMCGlV-#. Ts!탐-tqPU0Yyr``&UtlUBe67ow?ۿ?/ w;*dyݬ 1vCPeP2Z/g%g*6!ll!$>:6X=1}ej.rYvg%0s+xWg?Ycy -W:͋|~|tdm{c˒+"bI[U]]-g ؆$F-^ ̳wD,8,D2{GNsdGK9Mս,αy{y@0QZs.ky.-XD QYMFI J2z&Zc3kZ/a5m&\LjQ&>|×y?O?}W?}N!٨,+gz{0nz KV ] V5hh gGLt;#dd'0lB],Cgf8N+SQ9i-Am7}~KLف6å;i.jȣ9'O]6 {y&|xQu=Pfg#ٹVQXG6Nf>Up>.8o_2T-jT \N8E{%.ÿ7﷿~{OTy%Ѵ14q|=z:i)i8:UclF'D Cpٖ)2!NQϊe^ 3vJ!F+t92&DF+!}O|?iߓ?}L`~'axo#u\|Tï-O~X5{]3½\KQ:;-95k뒺9kN/7C.+˜*u fIfξ Zނ~hajlD\Tܟ۰ zNtYMكhT.nskBj_|_܇f7Uftލbڇ]7gG9<Ɯ0(l3 P#uΣ=B:g⸥U6&`W}HTuYdj5 ib԰~QԮ+e% ڡ^m< aOC>lӑ5ƭj_7حatt*,y;P`a׵kl:QL&1ZZJt'GKwt>De;+ۃm2elVLYsε˶1BxwOAVg9Q0{SQ8E;K"ުry;r (js"2\It1kgOR$ѥ8nv:§ j7gv'`)Q,80I6L|Jm[p|T"F:IrxD'nN‰zmˆ; v^%90RcZcųBIB6/㫧o?O_?a: o":º g)Zup[0J k6l6 LP[ۘ$S<~7:7eP# #:R9̑y:`:M8IS/ѱ_(v"Q/$ 8yvi;he\_~ghBcP\-b#,(7pw_v/!o]ha;0Z?|? {cȴ:$s3ysk tWmpg|SVZL23Nraa\{k}l߮cݰܭOe KXn6ƆG{/>{Uv``U0tjJmUք>j6 U:|n3gl[`%~^fqH7bJcx}IKׇwGr}֯#?q߯[_Vuzܾ݇}ݼ}|c X}T): Rv|{ۜf>q [8*|&+UYLq~T;yKb>TtyxxtZҪ-ĸ?+ƻ%O#6J6U?>lc [=L0/YvAmYұެnPfurWC Ϣmٙ 51p:fpf^eF LXSu+ w@2.z~}BFUj[B+W5tqUjX6`CUMu\:mBվG2ܵ{\a(72"9*U՝"{UhUYW2@F zbt LU=oƎPD4)YYE&p-(zV82g P*rhnʂpID/ dJA9jfvo.?ųvƼw6')&WAaK:óìRl3v6*74am~g h tXr"\2;AUYKw9=HLE'}tNtNNW{*Pґ1(CVB gs0ڮOחOǿ׿άr4z8pǸEu7gb훓N]jξ Ÿ0^ɫm"{}7Њ7StZMmN#ǫ|{ھ9yQyOG 5 RW:-.P~دŷ/X#v-E3$XI,ޒG۝i\0#K2oE JRBFfS}6tf'tpLmPil3JZ l\ {aay?+?çן_bb⫯.?W˚>#K_>k`qyv_?~~r]E/ {նy8hX:aTnBv2*t߶;\GV?'"fCq݂gYfJKeӬ+M<16^ru!1r6-O( ;)_kzD:APctYd1..m0r-ؘ4㭌Z/EP{omRf ŕm͘3 jtg4S)gzx\~<>^hc,{PG1Ft^Uӫ. {P|[njYm]dflIt IDATX\NUꔬL0Yуr4TnL3VU`3Mbˣ^˶arC]1I`鶫Nv=7Lq  N:KA\Bs  /&uc3X)S Ql,ݬA3><||__}]ӈ0yxX@'f}rۄiq+n:˙ISgC%@C'ȟ=萆hrF2,Y֐i4R~x[`v躥n -G0N*%Lj:`snJg]lˏ|_?ߞ!3&-C}0D3aAZʈF4uŲ2%"Cnx 6 Abv^vb6SUj,F=S1:_?q~׀2MYmwfK*}~-˿OVko5os-p_%.Qv. sfn tSkN W+)ͼ|6@;mp G5d>FVѨiV2[9ƚs=ߞ?̆~Ct^qU_LK֝:|۰mo?^?\?1,޴ԢF3,@tޕ\C^y>YZ]"-rFPU8B ^q01%*[=[vph&X"ت3? q zp<ץB [y93* -q.7STЪuQk>#u0^JO^<4? #'"ek0EHA/#2 v[}//869muu&GwˍlͣL4FFQ^yٿ8":WP]s;,o&cz\S@fe̲`vfUav}xY%=Y%`W؜B,m)2n /;3^Yٚn3fgL?=ѹq.ߠq˹G$clfQ#\UM\jPUYh 59$%ͻD-Agfj/j%S*RpëQc/@fi~ U@(aid^BM2nJ4UwȠ(9}scU>,Fa 2}XV ZXqp<}l ;ýO+n (t"R d9_O?}OU/*'=f$Ы4pw-5 Y)sA'p&aRnSw夅2!u\vvx&$;zv8dj,y +pzeNZӬTc8\'M1rpk<ǼlZ} S|yuWkvPsƼ%pL*gC<@UoڝnSEJ0(%e yfx9%| xyO`g[0P%uYE¶yV;ن5nq{xڗ=09Yk6ZM7mpƸlK~Wz?z]ToVL ( e4CWuWVggsT,[ xV-t>ƾiDAkRdj6]-ky9(v"hv^5EtƭcTU^ǹ*&$!XX5b5S -Z6r-0 \0RbAlbmrO 1CP Վ^+Xՙg2שLU'8_٬'b3[禜`2܆5W޿{7Ͽ_o[L @qA Jo\2RSVK(TP`w/ٹfV U-2߬iPgr;Dd5ox>}jʷAM#DG׋?^1o:z5ai\6qbP>RΏl(I9k^@L~*\(Ԣ>{tUc:ubpyʠ):aV =* WZp4|׭>` ]Y![ֶ?MU^WVUR,r%9݆;v-J1nx|Ohgp溛y%-l嫛P*nn4P|+i#L/`#2Vj{qV]lTs`GnaxX7Y֙DllmVL&8*@Ig@JӀhhezyrʮ3lpϴ)9}V9{N:Yjx|\H0{Wƈ.4)9l8H|p x济\';X}4yvG9ҩ%mѢY/,A`& 72˩ri`U&`7oUI In;y"hl{z0?×aO{c%wo!KoS t la݂9O\M3<(Z~fS2cmnw7Nz(ͺʬj,HTFe *07ZF duxG Oo~nWO6~?Ϫl/|c3]U[fלhDk_V(y( jYh?9I2d4/A|z.% SV# žٝi] _Zfh ʶ6{6plh-ua]mi C \ƌ 2pUUGL2 uuw{5ʷ5=dk|Y]DCoX0F9'ͺKRufPճ{8y]-k,1-6ޟ*fs;{UkD=!6 3ӌUlO`D%Ǝ?7~=/{uJ:ƈ1H]z/}4fb[o'6[ZNSφ_{]sD<>_g}Ϲ~' CXxhbKHtey>*{ޫ'{o|&M$tn*kǂ%gJ;P }:S$,h=sQmUrv;DFbOF2pcMۯu ]-6|$\UD 6}RwY=:sCNn@WdS"Ugk]7k6z>>>=>]zzx[[sKvjp!R噇ζִNFq.2%S=*5V$F:PPSW%::x:嫍ݞM*q"6wOclorU6x|}F'! DdHq EaUjXZ\䒱B~:mfrdӌU+M選=Ym+Ged#2bDgzgx![P6ƛljmصf>1ޘ#J;.=mɖf6qNd%U(@KM DUVe޼^k٠16֜fc|Dݘ"sduZfΒmhfZM7#*:OILŐ܈SB MZ޶&FT7|,ٔ=hw_~>OwЌſm La%4yw%*Ff6gp᭠VN0:LNnZaєCZN1-ujvZjv-!A V(hFA>uYQ {\23?ey?ͯ{_Y #YT;9/cH@w<;"^G kLwˣ;`A#ݷ~M=}O>&LFjhNZ̆fe Vpj#{=4U%JZt9M^&^|3VZ&C<$@Lȷ19zx䑝o)դ;tJ7Gb6м֣U{GۆC2r|'ׅ!Vykej1-9^'5qVţ`1ղ70hX2n7hV&c^P[4 _>*=bce @.K9gX=&kh[yTDap'><0H){Eq:)9؅)jθPfJ(L[keia>p}=p1O_{nmٍFEޒf>>5f-&d+dojr>ڳk\{T!Xtv(˲sLZ#v>oe0-RS°avmQ2! ,* ;hs:9t㟁/!r릛P$[ϣXG¨nQ\5T{-q \z0H&hN̒Bsdk<Yu^BsׂjW+Q==}||Owh ͪW-Mf7{ex`$ViKע&XuaB!E4^֦u1%Qr\̘6gs!z׀Z٠ݫcN[MB(%dfX:Ҕesv //2oUl|=r{6 AU7A"45ծf}Fx5*l7 Wi@ jje%Z踸?~~=^7!NgU:NLʞ$m)&=>rپO2XhU: CvoFJ-B!Ƹ:އ.ha.9 [|ٙ``c?z"fdQ^}>d6rl%ʗNzUE+ 5i IDAT1\k<=xM/^&Hs4{v* V^wb ܋ҹBWv9f+-I΢hZMZC+"3{V^fZql O50x2Lg>3dere:{+7ʄvQ8c84\.4ff%@yK6z-xEHb< a2#8̥%U[Hpb4R%pCޒJm1ȧ4e0kۺM饻6]}w2 ӻwO{oϯ?3#?zTX7!,{v#<<+iV\8<6V+2*'~E-dWi+^2FtBjb12jo&n˒VaEl!35]5l1ǫv\W]K}:y?prۿmfXb[n°t8r#հm[eKω16}g?y~~~s;l^f?>o#lL{lleKֶsFۢcÇuKm,5"^9MP`3gϣc;djFNrwCq.R`!LV4WQ] 9s]=խ3bIBC,(:970.GcP2stsarZ֍Q15+f+PD0.͂؃Ӈ>XC`V; œ^B9gvgSyVV[70 - qbG |5_$2"90gmYbz986Ee%iqNzNmp7G:.TEuwg26Tn!k/1ƶE GsO-h͜v{,xMʜsY5DtIp5һFsIR(0ٵ[D\ikgH9Kiwd?xz||U=GggӯO:^j>ggT][f[l6bsc\Ìap^r$P2dAWj7AJ'S͑F5yGҜ{y܆ںu='U4Wiv-q i;MyGɎl:%Zq&hѭlSP}yʺwq0/};4 ' iyRtNUw[\EsĐ|3 6SRPS7;sv*ub(÷؄Y5c_Φf70jsY̆H4dsud14%,=}#:>Oo m~ ^s^~9LJU3@O@v#.~u !FE(}݌ϳߴm_EkgV S uyj}wVy}v[!/?s=p:3S b 1|ߡnq86 o=|.|O2o9O aQ#kz:fX2>=:K͖l[+0u[Gx!ORI(Vn)/A9cYˊMUxBxAsnn-PZwAK_~/m7W~=9{B[Yҁmߛx>0;%C%R[M5oo Fv 4m t3 3F,p23 TUl>ll=ݲj49fnzk8o[vqƾ9%XgxQmt>sVTYyvX< :pW0XSU p3ޅC;mc*̮3a%hYJ20lOF Eƻ!XeE)i.J"b q/Us3ΪSQ:kԙ qy=bZ/ W#V05d0_]8|]ugx}|iZJ4Sj㒯ݳgPyWhZ5J>7x;2v8voחgi}pS*wAVfg4H|E!Y;{:Gew&O&66RnJmٌkqKz9<* c#0};G-kZd<(۶:,IٰB-h(S6}}j0Gw#izpգ#P} m#UEvA*!3 ڹPfSkYŷhFMy -lYY`r9Ulurx=>?o?ǩ_~_㗟OlmOZV2sp55Dm8b5,Lfeյ:rz%E }9(H@/Zh-Yjol16ZǠj>yin1dO?c|ro<;e/c_8b9h^i@7F>Uի8G#pm[)s(DTϬsţtkiUmsxKӧ/?<۪in۲ؕ]aC8}|wݯ<]}t?~/-(+5!Wʻ9q|.kǴEӶБR^jLkB 46F\(GY%.MZg&| VfDi5~UET3/.o|YDZVvn؇SOnOxξՙ7+*_yTvI;aԽȪ̖u+ ᝬZ䑪Z6oeY;nC|<p||||Pfp^U#zNU5ahF,i@wG@J3_a@kmyJRɗXih~YӖiu&"ҬvY'Z*xO @ܶrkdb}H|OyS~̸~痯^癷3o~5Az@0Gbz0[-"U8Nϖ?޶oc:55gf0qU֧`J#tgihۻo0|??+Z36Tb&vfz,V<=2;+*m&X{?7uZ8yWAHqgt́Úʋ[lY4>\TKU5\Lk*X%5)rn)Bpu *ͬukTgYn.iXQM'igu̮s} {! TF1hhmQ`hB/pyh wk-FnTΪJRK .K%5 3ٙYU_RY{i̖ŐM$Y1ـI/0yhai,Y͜D{ gf/*NnQlؤIT4@mFݰ| Qz1Ki 7ᗇMN*u MTnyOM{ξOй74٦VTMx 1`d$$cmfBR58a{{i{dvlDheyL6lo; .<j4%N'B"u~ X LvPb+LD9mkŠ5s,nrP8F.hB7؁(M9W{N:0Ɔ a'xl@FiG Vy7Zt&/F7Jnh45YolzInDiCk\6lWUp>?/~9=];oyLJxPܓn-HLil{8|}&,DVJIJr}ؾ͸?xćbV=0sq]_s]<<%1|A.If',F@ٕugۭ(۳x?~ǿa;iڅJr@gRDH֍8̳Є:zj=R25gVξXM7(#\ilV Q2뒇TݰBs2V+RYîu@Q:Rw?}㎞+:f]eeftۆnio{ou_F& aՙئRT[bmNs(^sngmCQKkj2"Ӻ<ӶW$6Z,ݣ9'N ]bb7y4E x"W+MR[7n!tֹTj#A1FZ$ brv0nGYȡ>z&d͊uOiU0J9*3<tO^Z<4m5LRVaNPyVoHfÝwҭY:G^.$)g*̫qH~1q]'5{z.-~;]j5}S,جY$;}fkސ9Ce{:7ʹaƾ4fT6Y惛fUE,; VKt-L^_y17el03{6e[gbDtκ,Y9 vY%\0`1ÚUV,_e\@1j 6VU`)XPQ`V0KrӺDVuHX`tKd>MYc}Ň#oOqUew7;GدoJjx3uO1 oFpH+k $T]+nn4]h_i,MDnzS o͚xnjӪ ޫT%7lD`:apT, =qqz^{g.cnz8wq̯?~^/apg?'HQfͅ}rn L}ئӁS]\ BMzjLqX<Z6~Q/5;)yz^۶%;c̹73mll! T삅?+ TABBQB!! .yo:9<9{s#Q+ K[k9F}_fN_@G^.W><\kͺ-Ǫr'@kΆz̀B V9]n]B6_ t%S R 5uqD*Ay!p-AuFy'â%DI͛DW.np&*zK7KyyJaeh@y:Ծo۸hL{؀^ O5eLc۳% |Mt`2pFB>fG/Ɗ/ ^&HK}kE`K5{sy ",b]Ka{6T7qР_yxزСjʶ0jaG,{#̊ѦٚVVM͙QY n{}߼ IDATʪkrrTR{"8pN] ҃ʈCtmT{ܣwqө>,fC=w Ξ^v(_| (9e_)40Ep3ͼS([yyapSDl]fo{, ͚3k]}Wn,~nڪ ?l39RplZY{k40b ?ߝ͉2n #$^m5]4˙f𔃈XYbWt)(ZδIy3e^'cxJ˜zG%:w4ĩIG0NAo*3^0 oiP'2zd}cp~/=_Wڌ[]]9,s5wkʳ|||l!n.B#Kx*lt1Ʋ,tYiѳ3 s'WW1{ǟ*uUpZ]h]u0ALv6]FPUj*Ytp2 dSF|?~m=P4XCBl%2{om8L AJMw2*`Ds)Q$cIGnܖ-.Ti+f/W0Lwl ڸ.XT,%~^7LE`Ojp0O [ab 2i*k[][yv׭wf*5ɂ+zapnKerݙ9_0'3XnOW62S;U85]\[-Q/±11&Us2 }Y~yxD@tgKF*bY=k{/j*@gC]ƾ757[aivN,.FcL܊Pۂja5Z6|2c]|urTH݆a64w+_o Iv4"䤡-Ej94%d&(!6bWh[F]j76r"cAnF5Z v<ݍO>?}WOO˯O~7?~{˾Ƀ~P;hFv -ȴpA}@L`* >#dScPG&fÃۜ.Dqx0 KWIǡ O˾x>ߜ?SO~z^W]/to3&jڮHҚFy" 9q:8GO7g![SˎF0Zd!zUra:fm4f[qݟ7hGs;kM3Ӽ r?dц vO {%Nm :2gѽkX NÜntIYEOK=bg!Z%`e ^kSEs/Y {ID8x6ps?&J Nj8M9 _QlovhIe±/?CdDuJtZ]R+w Ϻ uB 9րUxض}ǟNln]w _OKm>/ }{Sa p?dfVB>Ē i<[*3C՟I(ǟ63CL.رeOaQ2bFwtpYXF<>_Ă%8ΫiwڳKn߼.WݬUѬ EKf FXl1SnX@Umnn6a۷LhFYy20i aa ^neOޙu|/̽Uma- 8!Klz5tG}=,ДM8Cܹ;"A)=ǚMٹ @ @NjK' mPp Xfnd EwEDg1˚ sf]phccbMC Gjvǟ>?<^_8&Ki:Ӷ%c]ǙF[^q%|x>gw|~ i#댪rr˿P|ZLUqه1h3}'If7HsN ˚fG3'Hcb;03)UKus9ٜ="03rqFz`7agj3!f#PlF+MnWfxyRnҬ7$-& ճZd՘ѥ}:ِ{CEn f6;N%t~1b37(Y:z,i@<&Y?lxQNt [laF*yuXxn:NsrCվ~yFDUꭳw-K{x|RA7TG`6;c bݫ8g$;gavxp$a7ekyy%1X zG>53mgU#zb5Fh8:XqYVIDfBP2')[h3P/}T6VzB0V b>^Kb5#} 4ڼBӌ10:jzU@#Zxfw+iU]U P cVf4WY`/sH YG;uwB#ϧ@ѢTd#Di< j io޿ٷ߾y~||~y}O|~s|X_}z\7oև9 Niu='IQQY}Aబm,nZW [P>r}w~9)3uSsDkď>Os{]5=}7_~/޽ٶfSjAYj-6n\LӪ9]vtJ߿{/sW[e&ZN'm_NŧrgQ ΰAfV"9ц2Q`΃v6 )atw6,s [[Yꀬ+#:nw-s!%&h-Up|/7?|*Gi TWҼ]u?QTN7oO0>/i<3+ (*-uQ-<httl`GEbi#ZΑԤOa( 5=#hurt~Z>ܦ6Ͱcwƥ{N1/5L"U,pYm<^٣).PvhMˢ"}|ݳ U-٤ӌ2nX^++qVU[FJ snN*S1XX8S]h&{a`KJK>1Ö0nNv^N66 ܍i6ܭfm9;LGGxz-G۳Ttkͼ̶7]Y%$:g_2Xbz~i4Y9&[.npZWg'܆.XneGB5Z R>%ef]j|ޣp=lۣ//j Ety]d"1݈%}_-]<t=^4kF:{{.ZY SZq=dL&9mp1FARep7#PjAqAw6uG-Ս,{ú硐nxQm eȚkՑf բԋ R-;(vDf4Զ78$G}|%E7xww߽}zo~[u ߼÷?y@_n>_|⺸;h#?j(| d/sHЇQfNI-qNsv !R uU x}%U i!{ Vußwfk^S\j D̖z5ee&ze8|?0Ԓ秷_~x_.O^2-0ۖJ/j04HuGVԥ6l:gn,RfKP_(TYQ4wCgNfuEUFġ|/s/~79#.)4Bh~>EWm>~?{?ݛ?⛷[TBfę{Uye TQ:<~@T!V%Zf YSh*S׎Oڝ-мf@:uO@mçí#ںݥ Ɩ7{(-@)mj3rӜYX=rvmB zmga6UV}z0JMR3 ǐǠtA8.c=b^f]~q ΖXF|u-ЂenThLZ{O{eY\HB׮m.*{lOjݭ&CoD7ֵ絖tӗP soߑKa c)_!^"`UP+gֲx̥ܛ'nXE[o +ILmm,qZ#4N|Y@{c̔O v=\έiKr̕I83 eۈ=RCƔYZa"l n5ݳF1Jǫl0x29ŽNwYnƜs::&u aU[wlZo3WKţsHLFdwX1pg4}wtϟ~g?{÷O|槾NUlh0iuYY i-ILV m^ T%yhfmlXKSu&ǚsW0xݟ 3oa*'H07d|[=f=蛯~e]p}w97u-㺃GU)z$%|WsS<\؍kPUP\O1D^}N77{ ̏_78w%4x^\|Q͹O0m/Rh۴,)6yje}=+ѳ{SBr*VvEXHV'0GdiCx^:m.aKE> V Pp^.pɪ@wӫ7_~=?]oOx8njޞϕy]{,NכS|}rd4Twь(( B{Ĭu`A/^Un$@D.!cu\[u(NuA{B)<ah1Ѡs,AX.c5{Y<Ϛj`1gZͲvO)jfkX0y2V~ؾxLd"}{Snd>d[5P?4k 0V l`L98c/cngyyA-8M:{|;seFVo[8?]eX o\*?eR%+EWPӂƨcl>zPDi{Zsn(4\J3 7Buՠ¨M^:l٤qpg˥ tAN^s!=FmvˆcNwde|y7~8?_?xͽ+yqs_tzѯ{>_{o7Ϗ0ͣV$>sVMۣ̜Y;MGZnTwf6.蘛w|HmfUr[7 ?U8K< +L˄]Pfy1mM':ؚY.̱Xtyz~oנӰXnڶ0cHe>eC.fE`gOgsz˃ V̺,E:Kje_qA|xzgq-?>pQh=<<|_7߼y??Oiur;TNBZn>pi܍η߹unZaNT = MV[34Lp7ɹ/??O;'b= ]`5Acc5;,%ifHG,J{2_oyu>VM&! IDATqcؘ7gzs{jv7gFf͇^ewn[{/_?y?O~Oo_]KU-۾۱=ī@)#-9,,~NmN 9fMGmh\)3*aSAB ։mvcg0@k̹͜,+jW!̐YϢu}\ bwJ/q^<ܗtޞl=i;g9 {0o[&a0; `,VRaEy0}HPL`6.5@)v~ۡSSߜ*ȺDቹf֌3?NMaӺnYqm>LЌ݅NA٤zNjn4ls @5HP7r$Uv:Xz/뜵3H԰vsc<"-Dܽچd̚Uu̬QN4d[!T+LjRS7^@TXjAz|w׷__LX7?<|+{~j>?>7Su#jIVc /vItTסzwRrgtk҃Xh̄0[bEǴ^>%oS탷S= Ow˻O_}ݭcqZoޏy~?7E?{.dm2XwE2 c00T=ɟ]7-C,BfJj1wܕ5pi:(έ!:vg"LbBݫ @wFdںc0Й1]MUC$3r979FP#Ct`$[P6&i^_!!IӮA5Θ-e$fa5-3T9Z!$trSelvZrS[;V\8‰[ḵi[iDd1urܺ# ;2wPSCBPP37Pބ1'bUa/U> Ѩca E=*HD4"pJH<@#:(4,Y= 6REB$#`rÀRd[T G1U)p-Ġ_-=@f^PVcQ{vަ]fWVΟ_;bS-",X&bubng59_z#<~ᇟxSKjafnY,='Y8pUE[`fP&$2 ߻|6~c4rƿ|[~WO<ܽk-߾Ϸ<ر]sC}q%sZJrui[:o܅'>Fsi/|opS{/ɏͯ=RS/}[o~˟.kݕEC=s 쉧~?~ɥ3:1cH޿os~9{w+W\&~[{օjf_;zf~R/g/ŝ;- [}3F)@oywoiyyEc5ǯ|[+{.޳Gu_?o>;?7@$t K\W-s;ݹu#sW'}cGO}{~ǔN/]o̗ncmE޿'n?۽m_KwT)R-_>z#Ϝ}򭇟iZ}5_guyowhǀkc `}nu{ qayC~}׷nkY S*7߼KW3~oӧ|#>}K1gޠgf" )v"4v='@LN10! !)C6qR&iV A\.bn#`B!ɵDHƅ>uE/;OƟy/}WX;=9|sM?[da3>_ɫ{?wwWd+wѳ';pɞ_}۾O|}{?/?_{ad~c??[?#_z?򺗝VW֟8ruA̍80w "CU'vL.zٿ/eW;ϝ=iD>?wojί׏<Ͷ:W\T[wk;?V,n㺾-8aD's.)ln"*#uNȁBq֨yv̈Hm\w [ Q51g:kr5z cr2V#:*XWdTTZiIMJnMh?_/jq۱0HfԈ5-YuHGh@J7"&aR:R=313iYjmV31 1##;HTw|O!8@[j`ctV܀I!@/ $l8:u;"z?uEW $MчmiGN/_97 )ZU2*PJ!E &M@ݥ!0QF:b kt k(( " ۷;z`@Lf@6Vh#Nz[-!2"{a 7&sk+sr~_?{}_ >0s˫X43ct|@_^^ݿHޟѷCߺ0[Xz|g׾'N;{s{ԣ>raTVS0d@߼?Kp׍y̤>'vmnO-]j:y$ A:Q,E O/k?.n'>ijK&Ǘ_wWx;?9.73;l[4kSl>7vn~ak"TI0CعЁM?қn|WRtz#k3oc5/vvPE_tzč šWOՕ"1w'1~gnƀ~37^spYZY%W2Hd](9 *SĹ*5!@Th1Z^H԰e @yc-! F;Zv@HH-C'jڼuR&,I͒E[%ensPiF55S6hYI.fE$"Ris'xj0pH1T 9)33XU@X l ܙAAS@SJdX`Ts؅ M{Z20sATjR{*S^3l9*ԛI@.`H2Q,bQVbnn*gZa~H(2[L^% ,I`ERvwh\ r:O^WLfT7mu̫&" L:ȓ-\G)mE亣R 8#!:[юhfN댄Y3mҁԄToۈȈ4 t3H][Ab%dFg@2N g3<$i$ j.њaL3o[Z^v)`*jH]ĈXtKZF.1㦢r6Rh^9tphBD9q```ޡP2" Dw1SFMQ$%*:("D`5TFtu-&@4V@ )$ Ǔ6>cqhPbd3t qHLsdgkJD""HEbA4nЧ8WhbaRs)!R8[r}B=-J SUG4(2* Y_rىsKGO{]MybKVSmw:t>ĦmWylwȶ-[z8ghtl:7u-1Vk D,'}K?t}^k3@l֝㈁@?1٨3Dʘz?|pKQD_/rwE^w-}Swۿx5#ժ+395)T "R"$rRdT?P/L@*Xmq7?Ծ3Fu[fSXM[O]/ G.m\Y_n {.s퇯}5GGԁ@LAMy3ᰇv.\zٮK.۱ua*^C#K/^48́~ݯ?{<;;fӐ9LYKk[S ϝZC.b !$r cnDmڰ1Ʋ9ijVwmI«O[Zl_sNYb;Η}N>|cO4 e>Vznp=rY&prg.' .?}ԻM}Ѷrw޻ks9^p]܁ͪو=Y7-{Bb7@'wjݹe)()&r7;O>+]w%;7;c" r0dt0B .NDND3̆t^s6٢-nqYpΎF'7jGJ[M+ڳ}̓OCxz=[mvݴhۚZ;գGOխ)UQn@ME<7-hW&@ɡtc^eU5& fhJ +0kJ@"Sc&8 ϐSD&K V2h-71'҂ڞ5h9hEm3)kH`Ʉ)f1{d.mm㹮s;'mM+fY@jfZKKf&.ҚDU@c,%N2 4[p] [g͒)ZeM{' !&GvFfd"J 9@R=X (1ivi3#BGl 8F1*JPF#fe=ōXQ9Z+I%wH{Č\Bu4V\X j` j=4ڂj\3ih.zmYi>zDyB l''(F1LP[,Y_WqP2us h.H@h8;;&nm 9#33I+]+or7ߠw:Gur@u$^& YϞZV}Ŏ}n,Щa03mOHPD3Y3̠Sn.?oƆ sbFDꆔN $fܺ1RG;J (El9!)=|ɁR e֌FZ;3msb nҭ0xfV !~J">c/0`?Ҁxsi=7Us'Lrn\ɪ~QUI-;7h`h,um[3\>MimH0g?zcv>ʹaڷc-[=ҙՍ[SH˪rPJJ;;|SwX,L;;}iLՠoYXXH1m߱x-wO&߾C^x -wO=b/Ջ3n#cD9qWzl'/ѧKbNp1`8عko?yʫputf;7=x#/̔-_omyzʁC|{}2{^To Z [9ٹ}}|.9zٵգ'Lm܇,w~cKb߮8c'>vGyuϻ%}NZ#R+֓G~h߾xt׽=wϝ[ٹc-w04 S_;o~=nom?WtnG{vn+ o|ҽ,wv>cg/};<Yz*/][/ݻ?wN~E}oǾ{vnrC|{ziycD j 92"c_}py}:_xfO}Soeq\'iϥZ6S'Ƿ|6{~g3_ǎ3_Wo]/rz/|С?W?#GN\q3~틞?\X"`Y0嬀JDHnNHD%eI w Nf""UʔBgM `-BMr8ܫ92ŲJEH PQʹ ^"d& 2`[;b3c f@ trm@L!mb&ikhm d0ݍ{HLdH =p" )TAU zeW2\ CQbiHL]ܔ tBDC6 !99z@Ab[Jkm%g+&bHJ E N㐫>`F̃(d崦lEnʺ.چ]9 M3x?bm#fLd|DUQ$$$w wGwW'tmn* ݡU0u.,-HP;3p >E"@){9 D֕MDͤR4H.N zpff n ";Y ;wVUFP -:(TmDQxzk/UQ4O*$8g7DcvU| |̅P9&W*)p9SD&V\`9ygaB@H @#xvϑ "AjZ Qh(I" @$%+S d`C4312*Rf QSЖ]9ĸIu^|BQ)aDD8LC"R*8!"1 *MB|K]yn޹݋{g'`*q=V[5pz􅍓gYxe;ka >@ܳv܊U,䶞OF!i[[gfBLVCF `O̶`/.ٳ ؅c'ըʶѦm0%XylLFuprr.F1f0´Gӭ۶ [L,0`;</oJ5Q#\U8!!㏞ݯEO1pXb=@l溺2 A X}:-a`iyr>2RAmV+oW{i^;73GK-=6[AۆaQZh $[nݽ/y߷ofuuÉraWWVF#dzae-ίlW UپtH307Cēz:ޠ%J&#FQYܲ@̀Ъ|'KN6Vί01Yf*cma0;x:E:gmVG̖^Dψg6&y3NM둊6MubDgB `$ a"XD]8$K1SfEQ%k KQK/`n<=n[vJ긾֭3b *,RV7?~~PX0qsW΄LDh(P$yyή 9CI(WEe[6O1jn=|ʚ* (RkҋJ0:qqu I9$H :N%+X2b5ghq TZr+u3$X=M\LQH qx"RP0z)11qIϱ GLF"TQB 9d (2`FjL#&3ԣXGu멵m۱ٵiFt@ 9[|a!m*Y- fh82^CQέ9hI% @3بZ[@F8Jm4DPF< F'.R!ul`@8Bc]xfM-"mJj !1TPik.$h[!#0\!N9AdAĐr3 S+*'G%G&4$n@D Bc;f.NA#@Z +o;e'nvC:8{.%cI uǖ_~DӈDl"V΀bl $;"8@ɼȨ@梀Τ@- "nǀ`Nஸ9V7MϏ";ov ;IF."9aDJQb\X Y3pt3){jj-GSwKE 2?8;k٭!8:k4CG!t80&l[ aX5:90qF] 0kk&C_CP:>u[ϓܘCIa~,7`Z{,KٴX@EQĭi^%OGƑB0;B,89r쑅"D.q\p{(8ZFffMlP7mLU٫\1v8nHn^9S:̦"bN4?[̍Nc[Gxa˖a 8 aDpAnwk-9ЦU/NmЩ暵V`Z?NKJ޻7ý^of2kS@oUL*. fE~9K&e2<99)#wF3m[[gD10uW j{YF spH !"Ņ}kMNH !ɓm ܀6m'T)FN{Ps ZݱlkFL"Vksߵ$'̮d wڪ b֭6b6vs1QUTDž-]+.Xs) "bD v(_]e̹{}s΄$$NP#ARzUbhyK"`W(U!ZH@蛄&!999yZsOxx\s> FҔ?(s/, XTp9UZ7VJ6r $ .f<3D {10& Ib*VBW!4NB-0Eud$\z+fG@FPe%,V7wtn2ƂT ;9 7ˡsYrD#Wh(RW@fDbɋA@PY9"UˌF+q$p*QVceaXDX:u"S&6 XDeRڱr]ǖM5mkbe.8PS%w֙L40P%dm!p\,y , s $:zQ ̈8 +8: %&)qhj&āqnqoP4Pg(F!d&ae!"S8+6AFY31QPJ1* z-m'ba} gf)Kϡglrb7 KTU3\[^5jߕ7^rtQ+)mX-`Pvfl%@B2 9g[T59@A&$$.}3 pRe&''@ e0{ "p**`bYhCԇD@f0(!0IQ `" !fĊH %g 9V-p2/-Ӆs_:;; (ЁH8ZqXIKGshS+!\OS`q@;aWRlR|2-Jaw1Tsskaau[YKb#u} n|amVlTi=P]*+KR\ٱ5C6qe>QllN '(,! ȵ7ŻYqQF/f\ȇĖ̈Fs͝w>8Vƛ.}Do?zR CvT 7]uU8 ",N)DnT*  e1bS<Yɉ}{5VEm0CQJjʓj$AnBE8999șrӻ!( Z1=+Ml'Yы5+=~j퓟ϼy" zxJ 'Jf}v 9%WM~?+/nPa",̰rg>(C@<7_{@VebtFq5H"rTNb#Xv-waݚAÞbSCHrVknFf`֕ODBߧ fMLuh x6L1 aBthF3ݹ|iX" i;1/ g)b\0 p%0X QUؒ; ܛ &+Aq/KE b~(`2$gTxWס̉AO@woTU+33M>12,!PɅ$04{G-2b)(璺\:n;@)T5 SIݥIWMFt\דIɌ\647he_ˎWu %gj@7 Ѝ7*H]ԥxW,@"vo/ΙĮ V"e> bVT%0a!ve3r B)mfiO?'gnH{ ^|͝3n:\[ɀ9yQ zo~SN8@KZ *nU5(8qPCNMz&wj6Ƞ4Z[DfVfؙ7vFY :J]K0g(I(:źv/ZY\Tmw:\,2gsf^zXRrvcfJP &/;xڷ?ym}{sY8Ah x(Tک3,f |KC IDAT3o}W?!qC#*uQbUWX׺BLT\$! 1heiG~n}֝yߖRa&s3phqg -РmsO46Μ=Oe^kb H !"$y!&a ]!*_ rիJ&" ˆ)FƃZ&9{R),bDBPah1(Vj! ٪Up0d<$ xڤ-PID87r QPPSIpRY?3 ǐ΍BPg!&(U)PqP *T5$ jTXJ,sf ō K$sJ]Yĝ(z [eE%yA$:KEbRynn8H"f:/y:NͰ,BE s$u03ōRvJĘɺ6IpPbWj&Vr. GF$9VI@\K7-zU3q}Z6G xV }h]O}Td`.>A@Dj*l0wq.V9(x`egC=J"BmKAf8IglDBمfҞM򰞝wș$s+||S:|o!lKIqc< 64,3IΐIC7^)(nfGXQb{ ")kXsWERv&rb&RED).@`6ˢb(!p@pXYpjq:\=uz{f;-DN)MCTL㖃N%+(Bb,0RS"SD֤JNCN)0b4ۥpb5* Xv=iUйjG:3<mzv}ˇ8v܃shfpe{;Nʵ 1 cku]:xLN9!./ml({.U\ڠ箒j4*pRZ]Z3.Y>zOIM&<k^rZޜuB9V}VUY TO8#AtЄ oeѓyey 6mמ:{vkcJK{VC~//ɠ$d1РMFgڮ SixdEW]┡౵8 KfZLJ\ZNñk[o=xn'\pιg/9Έ)(7N=tjz43z+s3KG]X\ҕH_>a߾_|nlo//-IOY;xhpwƓGO%]rd_S7u|X) 3 {3?sn<C;A{u7ϓ*6B^H n: LD$f>0¤ox*#hnfT(]-%V LE(E 1p !:VJ:c3Owft6ik$˥n5:JKDZ2,!Y"4R5XR 8V(2SԀ:k- IIe +(!BTV,AD5D1V K1q_t8ݤ0`bsWeU V<3S"Fr3#^k5g pP8*5;YvF¬]rzy\C-YaL%gSڝ- %MiV %uj0(\I$UI`BWٜQ RnJ2,m/#F؈)8yBP JIpV\a5ME BF, yF ?DbRdRHbO&h**恄}9LKtQ@ABG)\=IXQb[aaifg\OҬ6$L7Ϝ>;W)W-8/"?[LbL3q:L(1ȕ.zAdVTϐ7'>FQH%pș9 7!va!0_ CDq?3.'cxP&.pa-(KZBLbS!cufarFpXk@4S֤;ub?fkۉ,F]V9X`+D\0cprv6Qz~4c|eŦb$Z//-]~&n2-8rƅnwT>zaϾ鶻x|?wv7}GO;s}_#zƓv߾{[Μ^'ӧu_seBJOT=|gЃϾ[oS^3?ς2A<+ DEgSn~_S  ʩ{$@ٽtm޼0p3g/͟x}'Ÿ|g?#\^]8號;۝Aq3^[oFquwo?|EleY[_{~]XlkfG>{`ܬ5#?woa~w]zd5\}wykٵɴ]YA\DHP ֻB$[fTȅ8EI؈ԙTX4H1 -Gغun.ۻ\4g.(4q`F,$aІu.y8يs[V|1$Sf!"==9OT , PcCa" C}ӭPfʪ.fEݍ2[ᚥ8H3e1*+agI%owc9ʰRufqf~~U6=Fs3qS@H1BČ9{ ! .i*tۘ/-ݽ{\r?0W4+-V i 8Եt]i+pcBڜnkڍx UhjQJ ٝI~ _绬塓^q\y`qs2[:|/}eW\g㟹_B^Gx'?z %ʅ&DCoyny-OW~Ows󭇮~̥|wE&JB!OmЄWS!W:|;zW{m)$??7;z;>/ *śo}n[o=I?giWTH?ȇ>ɿo7w_3;o_V*Ot0͟ruq{ kb0VPP}>2.18s .9T7^_/0ݳt- "x|G_Xb3O+/{=^iK(Uk9ۿ~^/^_zۻݍ>t}'~?yiqϾW/w}Gkg?C=D,O(;b ?|`/|s=,z$0+Q̤ K3"$`p&&g;*khR&r\)A8#GĚ,eҒ B$ g`0[tnfVD(M1't4\ 9{rfs6RJຩ$V55$kQ9TA=T,DCspG$$1TrwEVF!FCAaR+JL\Ass )!̵rI((,nHE`ʍTb6)uْ;C('ENDZBNl}N) UB@F0Π†<6X-]2AB4If %9J\X*.$T!PpR23BLH@rnAH89s0٨5bNAE߾a5Afc`TjIYJ,F9YbTGapQT5!r'!6c z3bS ΢L #*yk)a_ ̘F:Nq(dؠFS*q2vk}'r9[[zawc\,':31]L%,.4ʔOg_ID8'R"-pQ23VWV P1,"j 1DB Z`6G} p*ކPg,Ξ9' ;{7\M͈d:B!Vms O}<)7ԃ(n:x`9mQ?nτd Y˴{`bJ`,,mmmx~C'3]1CQ8r`^qW8 ;3v~W圈g2} U`'~Զiks| qX/.ͬ_MS]za<7&f.ZVVggfC38677hA{:~\kg]sw~[==cœT[=ބub2p=WUa*VcEE@L}"XĩEYtţ^~UԃLi=7?y^WX>9VD:9B x2{?yۧB?]^v~`ag ƻ7~ɴրQ#(KSIe檪f4 nwՕZ¨YX%C.))uW]+Y^=;{sȟrn}2iHht<'|M7_dQ2#^F1@0zCM3(3u]'4U⦎<-63T/ҪEiZ^k"9C5(n5ǾH(])Ί[!f䜳qR8r.g+ICjB!*!e!^r.ZYkf \ȅ "(, "i`wJ`a*BQ@DrBrv!0AR+fA6Ge](T1Im@ս_sIEX d Ť.,@"F́9V!2`KXAq@aIȨ$&$ F\kg.E-7ώN5@w)K JJ"09f,kΆ҆eT*ݹCXߌ+.3&8s`)$N!#R' }>[D "B}HA!Hf#'9P{t z-lwk[i[<>4hu%iǬb5ԶKmy0DiX;mnoSyT' .hw߬y2=Ɉ SRG !Xwmp@ B3zQ/{f O) !-)EyP/0\D*9VATe`T}Ο9}nqKt ;tXWFUCn# ЍHV8<\;2[Gny<]{(WA4ZGbm%X'Jui*Bt su*,8Ls̀*u&!.^\:na{{{_| F/ŇWMJR/D۶ !3 DfUU L;; @n ݙv鱏Ye0}SH/ڭ!]}A,0TuX"FFόFd 8I6*PC1*p8@/['EYj"dTB`Nㅹz쯿n▋k6 2KKO.,h]m>/͍C eӼ̱J[W֢e'"bVVwvEuW_f>7*W칛;;'O]xg B׶Xqt#CV !Fw`.& sl۟?cO^( w=ﺧ+v:fZF5萨* *@ E$=|FͰTŦ9PJlDuTh{k: QMRʼn91_r vD_yի|#Go|ի_"ws{1lF TT*s,qqfv8w# Si1s; RLJ[rB]jd. H-XX#ú4XqvfiJ^2@G(ӔtRU(dsvnlBR39\4p *Q[X[(4bI̕$f-} a8alR2 bt/D솢f #X, "n$FKfJI*&J $^S[ U."_J-,U?sۑU*PŔDn% #&1jvR\3Q.D`cw*b^̺(b`r-\J( JUPfΎB%rRQRqCJ,L&(pj"}:W."(UPH%j́,) H8]- "U IDAT!g`qb6 X^_r-G^,5{fY\`>o>pM\X22<79p=fVFs/lуGko V0!fĒ2+(C\B\T`QȈH M&}-8cB(p'qQQb7Xp1Ȕ@Te 2 ȃgW=$$$d{]QܳgT lUx4/;R)[%Rhv5W^>vr;[qw[ˮn8]=k9zpi4޷~F<416Q2 d4w~8p4GBel)J;-Rd[0 ܐ|w5-{Ϲͯ}|nvX]rV07׾'>圲x,0z>ɮ|䮕ū>n 0djԶcNȓAʤ|_[S'G@\ &6v3@4 3u zW#<`z,M&cfTABuh o>pA/mkMkP5yRv*\t|N}t/'kG>E 6'v7wv꺔lgM])%|/ȃWC! sK!ƪ̌XnHHH8+?Ocvc:u^\"ER$eٲ!69@pK&t`#@II70!ۊ)і)D"EQ"G{50jT֜c|_e3jHq-&Iߤ27/jsаu3Qnw6-1cżv153GihnQgm0*,k=OFt@1{RMc`dOwFXFL zXo5tqnCbW\t.DZh罵}gqiOZ *Vnڄ}9Ԋt"B5k 3 ʁ,1Hi)虵!Pgb`}eБP,Q.ưI,v'we^NfAiZUz`,-Ts\L˰܅OYJ mx4j"yO2ցe "OPg㪺S"Bv3Yn SLw֦dYDelRWyI! 9SD`nNȂ H2 q@ݍ4nW- nfFr hm-lKTn =GjcPƶl<7^=i'G^//^<1Cp.Y뗷ۻ>٫1)/c>B]^m~Z;}Ne氠R 0Mpt岚3KP}-nI/Ɍ%lx,deF}.^VӶ.lw3UR$PdmLm>EMx{~9z_Sf#FO-YNr\Ud/.n^j<Ї_ӗw8ƪw~wuhc2$1]}xe:H)sݝݧ|g/}k>ݝ)ëoٟtw^+._'~~/.v+#xѱho|W7QZQg;Y|7/MsG߼~q?w># n S7`okzngU$L|/'|{7??_9>ߺ`_ڟ}'>5ݴZ4ٿo<򇞜'>~/~ŗ?>_G_x?x?6~3S>x]6/}/k.qw|/w?X}z{>Ͻ;<|~w?s_—ogW_~ܜ"콧_G>o_+?fSݸs}7Zo|{ǟxݟ/9F?U?1ڎ~Q9S~d/g~#3^N&2iG~'o|+_oџp~S}  o䗿}?7?ig_/_W_WիG>yַ_{?֗_Lޜvڠw$UH¤DJXe**yQiv K&i7c[X#k͛d5Zh'CEM>ALpriwEzc==z-BKc-9]2XP| 4i"i4zb?͗cgc/w5Znmi_}/K24WB#+MFBm [Xz=`ܼ 0b˜uCXi=}q^H(8 p0I>LE> 9aI8́3PHɛҚ93|jA|y7nRUT@, cGEGPs9ݎ|8cܻx<-xGo=PG oO/Zk;F1S`<{5cv趦?2$ kiS8tȀ2>h14^q900}{52)#ܹ >ʹ6FìsM0Gk0ir06Ub=iv44y.QQE7}_sϿGowA}nwZgRK:ܴ~ۺ'7z);CF~i:n.K7^읗7ܟno9w^Ow#OZn<ˆsWvZomBjwx͏n>n>SJcAE|}5/Ҝ5ڤL!HUUpݜ\w߼XbPlMAK1HDŨUe 9=chij(*6) j'Ek5k0shl>x{>85L%Uݓy~0iz)گ~/ĿҺ.0i섭kD9U&92UXq0ɆШZnZ?kytjdZ3as9.\WBTS۩ }YVh=[Yrj>Eb4_6TFs}U2stj>r>:rcUheZ:^:g4CᇇKYÇwXmTvx<֬F*ARtCO-%EfvcAًZM75XZ-D7qq1']t]_ʗ5/m>̏.~]Gw׷}n{?]/?-곱$c9!;xc),n~q(Ǵj7OTuOK)k|Yy1`҈lX*2dG*XșU2FtppP,bP"hͶȩJV +{H;VP1R [}M ˨qЬ͜} YK SsSFV )gyT9fA90JTsٮ`gu]Og/L2t ڐmG')8 bT"@#" 34(«5?j,3@ O8D_<잽xO<ֻA4ϗ|z7 Ǜ:h?s?e;*q*\1mvZ^ݝN绎ÇWtZ*#P9RZТE*] %br܌03L؜-!fIrM ZAVdn4YnC+ +mn4ZILӾU )X/M_{kRC۳[:{>yˊvy_ v^G v<̇/8/渰ǭNM?̑m$v'6<"mP!NF L2vY7O\w77pON`d)+b5wd%G'K3R 2 Vo leeWۗAI$L~?`VtIPTIVݐ#]fʭVQ]P1l"n]>Fǘh{^Ep\8j?ͯk_o|6MJE#H!3e5daP7sfQ,l 癿zp9Okn9dN&)`e̪tF|DEw6876fr@k;Mfr:2mKaP7[ITcnz1VDTS pV۳ly% 5Y=r!EDk?[˱ѥjᴪ iIRU *slԠ<`y٤ܘ"U\Y t+vFDqQNk GIYI8s!(}LwK62]*룻GOxslqeUs1W)4hV> D},f=b׬Z2V o 6qpHC a6SjΆ-(HSFD\G,NT^ş́,a"h1zii17'U*7 #5^ 4YABrҌa,r5* ,ӎwouqKu?4S7?pf<_\̗}[z\г$2rcj Xj}n+n=ރGk/T C٦msh!irڦLq7ePG6:r@CbmڦqR, Ti5Xn&$aeBY)06؞}@]O~w_v1] TrTV6v>{WmLVoݧ/>Ww/L=>ZΧO^{xՃ \N=Bi}*uW,M0Yb&jGv*d-^5ELi?L7w~~?̌)QQ.{кAYa ʉ;! Wa8S+馒P0a8T޶eI[fff-8тSc Fr{zcxBte Mw7J"n0la??z~~:Xeg_q9:T5Aw3 hF``( (`V}ۀuEiaӦ:1w5_ PIrk <:$miz{T5n3'z%Ufln+9߾uLgZֻՇ cTfY#GisGWeȾ蝙 ^>%s{"H3)IUzm)kTBMXl5T` l&\њa#)ܹG5C8͘\Ѹ7GgQwsDü\萙2oХ6Έs%93|LhE͍I1z]~z6d M>nY 6Gv1?~}4Th{nSq%dBs&wres(c;rTeX4gQ:q6z)3AnR9l7 <%B"e5cI@1׾UlҦJ^>x wϞ0n,4wʈ$v3cR )pcA7?~ ܜCY ]rB9,֏)!W ftdeDV9+j(Z{M6E V# gxrbD$%DNek/§]h2%$ L,fnjN1Z?C1Fq=ޜ.rsaOJs=?2XS4Z|37Y_snTŢ2 QC¤9hfؘ )f#wlüjOk|k`-GǒW뼞M.wXJ!EJ4omww0(nDMJA4߰#6BUF=@fh7id6,7϶3zf}]|ht#Nzmk<`XqK*f2 3Zn  I6;R,G_ IDATWӐHD&vvS)Z o!)wrj#0u1zI :>!#hL{6J<,kCd!K2wn_fB!J1oM'pNluܟYwǗ7/f~4?>K眥AhœzΟ7?o2'X@DPUfAgEE-د=eu:k7FԂUEmM6T+5JTJa^FL%J,I1J۰VlUDʍ&61~ӝj$BjxLgD7O>;kOukBXMVM^1z^Xק|JS*E߽l8\>\ݻ/ohk9b#^#yi8BkкWDpKw\t0Zg?˭Oq:UC;qۗy[f@4c V^qܼ^U`sR!V*. Ia@Ut [[=ެ ZP$jF@f[cEfb-On_6gy6yjyhK)aByXfcHEU^ qcwDdXc[-LPVt[naR 27sHmk!0QD, B5 A[+6V=+ӵyZnQ@K%;d䶤|`L(70״fLEY5t>xvs[&Dq,`9jUrfe hvgZ!i2HwF.c9+}Ms8%zf `@>j hFzGVZ!\e$Œ(sJ9\ 4.t m)[R͗WPŽx90c~x{ӪFG]^>d;7eY!%9KUY~l2~&`]?L-Ka A'T@Ƚb=F0eI7P IU`1sAo㖹yy<9ԨmpavFtLs`4g*s70Q V0L*yѭ`b>L ws[KaU 9#f)5 }t3knВ͇s^pv-:Q8j1ԖʌLRјY)p̄3G0$d楲klm18M31,` >T5D3N Jqa rsyl2 n %Ei<0* 9$0E2T2uy|p~FwzYa%Z3_]}+'>׮>9+0Y6٨WvLּ6ūD,+7(om# +mFve#7U@b~7Rf.CK4[{6ҀbV5cavr$/uh/KhSt,FVa6tx;o4黷?'}d5b N+qi~Fu<ߝoUvŅ9[Azͭ.חIpvy[z꼲O1447cB Uj1!Pٽ'CeuI8VeѼ޻xû|tZM'>тJ$7 RpRB4V%XJ6tjFs_fP M VjQ4J-h5ELQf`V JVuxqKtD_&}r^_OG꣯8«Kmm9Q魟("G4[CۓAZ& %n.EM20m4}MXFf z5,iiH(•0bTgXZ}m{sV},uL˔CbcqʦBܳ+AևPH'Vqb&DdY1HViI@eԶ&Ҟ)m(U3#]YnoIͭQr4- *cڙ'F%H&"ތpm5ҝPMaeSQX5"\RUTw47wt`2DNw4͘+̰Ƹ <53ewӱٚ[a]V U%z aQ%9N~ϣgP$Ycl~Ae)1(1m0'dyZlf斈D˭nN+ Iy1sYsMбќ7ʒd}fvGUpH "-7Zo׆jp@Np{f9]v~6މ`20ϖ=MQ7hFW>hNH WWѬ^v=xs9#q>/gr*]l@x]ӏ 1glZ@9#W-V6\W`s$:_FFC*CUVw<ܩ!ёF²d4ZCKFj{ͿwpjV@UIj8_5/>߾ ZMi4kALuwʔVm 殹۫Fr.JlU^$#dr4 6I`gW]! Jm*&;(mFc%jb sY b}I٫]\q`}|O?|/BÇ[u2tTO}5+Y^O?Em1Hi:E7|Pao߮y{{|/<_G Y8`5q>ZЀJFXΓl

>?>^s]hT38漘/[ `nڙ7*'c "q3=quO{VѠL:ka$g9̕⪊q+P(ŵq5&IօoJ˗_փ}}/2}a.;ܦi5g};ee y̨uZp>"DP8^s(dB(׺r=^U1tJ<Inj/04Pv"fx<^o=0'9Hм粿>qZ ,ʺɤ#Mq*}vs X6Bɰ r]HRl/45CiE!i5a9B>Dv3DAB ǁcs>Eyp/Qp)8ZZU=ֳvR>3kU]h10PAZI׬\W3xDf_D[ox_ܨ&n. Oz!{M؞MIhG^>">k²I Z~*p z{V=/cw2F/@Ff^|[ͯgGV߫qF꿿y^-VMGֱ[0$%d e}ţ6䲎d %E ݞ) Ԅnڮ }FT/ a/38iR"v PG(GU꩐w1z.fu-{LBĨgeCe#{9XAjK w5 k =^B缾Ey?~7RFA ]eAZ 0$w/8K҇èk#Έ{GwJ:UKhS%0[6v; eu "Y=jcrJ](/>_/_|{ݧ8bgBk>oNƙݵ #"Z.f)_}GB}]C^4v筺ח$<8ӾB6=~&%KR^1kXJ@ s;{ݔڄCՋ0xϷUuhxIƏFȵUبYEL]jd/Uo[ M6׵Ce#c Qӂ=͙Op]$DPC&"N*ʤquD>fx !K``~ ""#>x2|Pt~{}kc|WT ^8~voܘW?=1p0w,;̭WO"\f TgM.K o/"si#ls!]U9"BMn*G@kdPt4o>6kաիZv=ƉiN"g8ވaFl*&A8}4 S:jDUv$ۯR؋|.~Z w 0 ]9IvC jU ֙+pԏ(XkND.ˡcJk E&67&\5H2EY<2 u q$GƑJEb^"#O- D`kRW)нB2mZ\s|;zJ`FJuw//_{~O?w_?G?bf)j5Pr!U: ]Z&T}R) ܺn-*{7EUi3di)# Ep-tS b `'Y 쀊 `/D&)_u7__ymc1pUf'CV3 (EEF·[)"w0'$|܍K'UAZyZ:zao7'yBĊf BaEi$k=FnsTt<f 5[b`z]h\;kadӓv='Pn,WCpM.wbck+ɜhRNvPeٍe 5o?vOW q٬ z\{ՑؑY./nǃZ6.p[5{3k뾕WVt("-<IEPMhIp!BٱCWu]mrjM+i}p: &(2]Q7Ha)Lо?zz@[LX0 Yh= 1s\ kp!匿vrONi8Qu[g%\qFnIq٣m6"6JwDtd_GHdUO/M7[]7q^) Hm 5_3` mDl"Z-"BzLR^N7O2zLaGzu;Ʋp2Q H@&bGqc494˵Nהw{e78J?/wkPgiq[/eNNi}ois"bO*= }8DA@(rt%aԑ]ÙSObyIGNe`J }ͼ3,OAS< ,*x+7eb I?W1 MsOXw~-n+Vdqx|*U?bZVd)tLRY<%k4O!2e_c[{CTE$*6f16N!˪""^wD?hI4Z<~p3S2򇔳x4ni >p :v? AAu { =%},Ocysݯiq[RÂ0M3ֳqrRxx2O?Kzi5+$rEzT)-$J4e0nvrI ᤱ%?K<~=ʹI;9VLSk7 +|2O?c=?ΣX#DjbX9o m{Uu Ooz´`)@u]a/pA\~}WL@@4(˵!qj Zaتl8'פ ÃX:lM6ͬ`@J :E#HS#f(I$4ⵟ!&%67k6^: YOZD%`x+9td sn߂ l=":[l\aM"*MCK[ <k|qtQ4iXu]ƙ7mu#^ɯ8{Modiu "YQeIB0{{K~cWoG nA9P#wm֯63q<>}#ťY\?{FQ|8e@S8m{U&qDŽ".&-_]ʑoR>T3qܶ[qiBG0LX+;UM-_g9U`zlsx}xdUr9! wͦhc$i\0,t%Si&9zg( C H%B{gjďG ݮH3M0 nN,vF568u@#=4 !S)ڟ#+g2}V 2BqK;ͨ68[xCp#h[l$:71<(/-#wO0ԧ_bEs!Wl @Y:7Mbl!XG֏F? /-x;'= Z-@}8}1M3tœwr3"oIMQ " ^=d/$L|I[˗]G_e:~nqh' ` tW}u6L&uN'O{ZʪGt^@tb{jƀܡQ%[ 1*pMD!XM[Wmo]%frҔO'Zsc92\Ƣ(jT5A-.f]t[MZy~&CRXl UosJ躉O7p{ u_u~!mJ7..=.;TE;߮˿L ]yhw/78O,<~t:|IENDB`refind-0.11.4/docs/refind/asus-bootorder.jpg0000664000175000017500000030262212663063064021176 0ustar rodsmithrodsmithJFIF``Created with GIMPC  !"$"$CX  JIdVI1gu@"֛KQE#]΋FT:h$V !-%6Ȕ]eɑ-6c%- 6ZH-LlP4d 'm==7k57>C&[cz(~zmѬ%aD\jK}ĉ%+;+Q-dM: fX a0"s˖Kc~[x+:k=sh*9{oCyis< ogӔ"AdsieeVyIW0a"AZT\铢!P 4YT*+Mc"4 %5 H X\"ik3]5ߤgMF=aa,#5܎D*2I011" t h`$+$[P1BD+ˑ] #g}{Ɛ/2\^8'\nPn(}L#_}Gsc7Gإs5le(Эƌu4"tJ%e@ *U$JhJ!4(Di-0UŰa*8.@4e=$קԯ/s\j7__ DCD0$he ,J 5*I$b*i@ &$M%SF0#Lyݷ,QvǬ^ܱ<|Ay%Pϟ2/șN-ϧ_9deˬ;Ki<"ADvi"T(K j!RV8 )LKV9]f2M܀&'λ%6 ~|S_K_\B-J۬5bX:ƒ/.Fs)Z9ԵV2**S@C*@ $%Tq+ PS2ђI"vJV!a.&9~ )~5]b+'i~/i~qACjzI;&1#YXK% =Kn@,K& ATʊb WnFXX)%Uj --6XXulӧMg0N]sR(vqMj)5C/~_%yd)THhh=f@[,fcd!09`v) cj 2hjHUΉ9i l R*ae 0Y=%gC@ k ijTUȋVeE+)]c/|~#}?S A6b{W P5+y緀-R0(_ 3%d+@ foQp?[?>ʴY1X宺T@(b#s7YXQ8??0A] y14%G⫿x>ȩ%) k1ђV;\4h1&9j\žkjY⵼֋sӖ6ny6a&; hb0٨F\Mո̛嬙β2Je4  ԪRNI#)gV/wM`5KB5ZN NMJk= $NegTGY!IvlMTH\[҅jiF!% ө+IJ}?OADDD'ѫ=$NHZ|~-#vu:>~B{QXyO>?덬AtP+a`(JMJIXX H @3W\F+aKQ1\:ADD3@ "&*PjP++Df-JBRԤJbAR%$ w %A"V1  %Zfa Ƃp,IRȐ2VHh+J&P 1h KLI%`(RI9^rP,#jY6^BwNMkFZq +VZ%LTF$U+)JeRsךyٗYR9u%d4,D@@1Q$@A j M*Hz[d! DBX( d %kmZkZ   n]* )I\1g9-lHXUNENQ,@eK:Z. ]V4 % a:hsc@"` P4 4=YtUYzj@B㓥sl3 GW\w=@zq"oKww?0u`geάa@9{4j0`~gW.oR@5=x}ݸ?~kxz|D2gN4 :yHCAbe`Tr};/ }\?f;p瞀\o|כ{Ozo"sO|Uϲ=޾ܟ`"F-N Ñ,B DF% @6+vS:w| :; ~ɮӝۮ]_O 6̀jG_Ƿ||KVnD l-0'G7͛*`!!D /' C!7~v |}?/(c~:[#PF!?i{}~2qKe]s.@*pD-ϫ 1sY @%t/<_}:|8rW@ kNt49m+p*IZ.U% Y#zw`  M}4\suH w μ^7@ bϵQ@,ft`M(t(b(D͢/Qm)}Nu-bFg2ZMBj I^u'Yї[7Jk 6r`" Ԁ (0 $ D\X^Lf/LV TtKβ"N:  ^ ),]ZHFXʇR$"r(ALc%!RP]e%P0ꯟ ,1Ԥ+ 1 DT똩,Hv0 -rdhhJu]pja*I$F*EA%c/MujD̚%)r3X C @C CRXJXJJdc]e>;/}LDQGJ^zk*cY(,`!@ B)D`  2.5y `!X #0Q" BXJ˜QQ !m)MKlKR\N}(f*)§f,9vHk|hgA;'L  BX¦)D!Ҁ\ĝ]sחMOW˗ }y"rKo |o#>=@Ǿ/:_)/[c }y>oG1(;N]£~O֮Z=&W9V>2u6uaߋ&"rRkǩuܮ~/ښ p[ϤAQ"0B%h @@`:v)yL^;?2ۍ?saܚg.p_X?=!zO\51Tu~,/}ן wfxErkJNYS\Q;Ե$әp4K+Rɔ9K M*rHHIHYjuϏcqx}cbf{ב.P˵|{=y,HGO}8k_<=֖k㧃6>}*g}?{^ogםgOq5cQ>%ol7Yg^n(6YsFE6ԬL-b5(ъ*(![J%C2ɓRĶΌmjDY."O冹v6-?%~O7|/nvʓ3Yg]9=e ۞o(|YFiu6q,, "%LA tTHTjYʖ՗=lP]YJ NV1фgaz?˰I(g>K:9K覤NbxeLn)k>_I5hzNt&KqXX їk!՚8XaԐ)c@J1%.۞uҠr&R}Xo~ugu(Xru0z|S\T8R@ I ! 1J TG\sU=*Ң j: й ej05! czeH`4 M ZuX:H,JDD AJ(d%;nb( b @$(&%@AB(P+(C"VH *۝p KL@J*c$RYcF ƲF#!,nu=.tt Ai^BZJ!\=t'=^u˳5i\k2vd4(XD U1%BAZ ` ITȐ03-RN-1KyQZR:3XקN)Y+-4ʋ0@q 4TDRƅAEpH9E3P;DuQQQi%h @1SJBdTF" 0HtEe3H8v:b,e^qX"HZ 9dtl K$UZfTt0 PT%Z2 CiMZD +J@μiWkXhZPZ&k3:]e;֘](ԗg^[ fIof54e1ס!ĹMr,ʞFk4+\2*26zi7=o*]?sԮ^>5+;Zʢ>lSS+$saXe}ĚJ5&D0) ̉7y0Pb̈́SP1@ )4ᢤ-1tiuD*0Ĉ,ho)b8`Yu @ LSNP #@Q*d5)T+DEkV 8h PeXZ҇B(J26ԝ\ @"s,eVN"0GN H I"J .EM L'E1M5 !0231@"4#$ACP56B%FV)RDԠm 3LT:ܶ7mi$ PdKp PaJy&JxӘkp%1;|Մ>F5)MT Œ\%D.C @#h`BRL}#HG>}#HG>g9C5 QW/;!bhP5P5P5PQbtPtÚ5OR3yko%ÑjiYґebfiU5ϭ°JRM1 C1P# g!!81c1c1c a1 C1 A~t*FЪQA:o3*;NCE5GÑw#\WNػ2֘}r%#Eq=Pv<WKQJBx6['PO羇lFmź0n]gњIJBL # Q# ,Ԣ0äJ%8Ths gN2u)4d.1C5 B!CC0c!b1c0P1 C.. J#jRԥ&d*T5YLHMn']y5BMRq-KZ3 lB,B,C $,B,B,,B,B,B,@Vర t,0ty{T,BabR0aHC F)R0C  C $0ֻ]Bn?[ f`P4dV*%Qv3p;N>: TDدC}…0Hz<D7 ? jҨiLiid 2@i4kaaFa+iUd)UA+t"s 0y=_KJmUB|&%zkoHξ. Ѽ1=hi{xCOD->BqRi6TfV(nijɴ!ODzYjCDZݪJ5Dڽޟ":c$ĿWq6 Fb紌ˌp`%Ѱ2;=YΥ9L,MnMIo7bYG rگz[ZR^8~ޢZ? 633;(S[l>cO KZ }+p0\'.tKcF.cva,Laszj8C~-ujTrے:K[nG%vC!R]ٙ)& w`$֮Q)x@-vm_z;wwbbc}3Ol=>.tn* c=P"ÓX?QEYTW5ؓ)^MPu;uz|TILEmɥ69-2]C$Qn?GK17ihn%BõZjlD$4U&y"ҕLB[*Cj 3~n #Tl!Bl& )9tqn4‘AՅQaOEm1\apS]a,LŖ*HKFKrQً>X:B=9TjuKc=JరqFyFIBSMPunVJNa]}楼I[ KRۜo2'zMQd0+VTJ9oRQCȥLZ2O}h\œ!w8î/0~9!R|pr)[Q=Lyn7 $=JMIR[qKB^eC*"&aYTEtYmRJhhGGEkN ZR{uDUPSctd:3 ̦vdV>-!-P !IiTC{?S9y5!ڄ S)pe82Ne*RpjKH5wxd<2kKkkk az(c.I0)jB綥QRD)iJ|e82N S(ԓG,6ܷ U'I)1 .d#Zԭ ;~JJJJJJJJJJJJJJIP~Hb\n.JJ!,jjx @ @ @fBcۃ%%%%?jjx @ زJ.=0Zsp 4+#9[|%.q a2P)oΎL!"4e%#*+(T:'ta=R}&|b-VtF3IE98[1UfBViU 9D Y&sj)2U.B1 B!c-F1&`~#^ 0 `@ 0 `@ 0 '|gՆ] RɜTÑ5ixÌqqqqqqqp n% MuYyi㸸HI֗[q+D%jx䥷[7~G3?h<ݘ#|0۪e!P'$!~5y88[y bkk\3#,8ՍPRid)LB%!bn'!c֎W5e^o B"<#C@zG ĩEOJ) aTӕ)G|G_H0fKn4]L a3r'd˥);\SlJY('|C1QUq!FC"EMŕ%*AE!0 éN[q,!.'Wa3%bd-|]ң侹Bk æʕ4^N# Cӧ5:ߋ>WPql$\Nݞg˩ܠp]N5Uˬ~GVA]d*d%-]{wtH?f{/fv$(ɹ*[6ʬ{/~3?'_ws^^1J3MRi109 jJnנB-I,x2,JSHZG}HT32?#DmbEDcΒZGyibVi(,;2E169C9 Ic!2c!2, ....g 8)/K31!K05C-՝̰ d2eHH"B \K4Δ䗜C>3c5ܖh\FfTI9#G$:/evg)i~DšHҾ4[{FoeĊqIΖe AH2BB3*|}S֘2Z)#G$;qpxڞ)2 TkRDQmnFd= p\_=).:[rRn9*UV"Jpla Np'_l< dkMaJn3T\3EA6$&BI{⛋ e%DXWt#)%Y{" ƣSNզCqSm|n$܉|wan)~2 9 %#8qq:d2 3g/8#Tš~ QQkv_Rr a5_}^*E4f)qج}V$!՚?Q+e:*O0ח!56RʧK1qN# +$>X?Q ;AF|( }.%v/~2 ݞ{5_xg2ͦoeg)WqY+mT>3wˁcğ~f`}u 'Þ^1Oݨl>ޥŸe'?fVF{+AMI; |C<~__@2) joY_6Fb 츿=i+️&;#Dqr;Kimb*:D}"3%9md aFAJ T5Ÿi)a[&,$)[Bv:GQ*Lx 4FZvf,G&acb7ҘҘҘҘҘӘ(iLiLiiiiiiiLiiiiiiiLiLiFiiFƔiiȽWls#NO1%vߠǙG\Ktqq+hҍ⸸1 \R>5{Gw;(e(e(e(e(e(e(e(0٤.06ld62 Cc!iqpf\8C-C-C)C)C)C-C,R;b'PPPPPPPPKJLX1..*gƯh7 Pˋ@1Bn............................دfD]c%]bX.u]bX.u]bXR.b.s1s1s1s1sP.u bPơC\\]BP.u ]B.b.b.b.b.b.b.b.b>s1sP."gƯdvHXLU0 ЛCiP*W9[Ej325$Sָi;)*Y%&0qS:vCP# eJ+,5)Pݛ)-"=R5M"6D{ԈS%Oqq~qð>g~2\=')ѧ.’ -Ją2V$کHO˩!JviGЇ+JaKmƦᏼ_&Vw7]ʂ.T婨Rب-u7B(>{qq~p\_g-E=^tm!$ _='xM5Ay&u W4Icc c c `Y0J (6Ys > o\JS!򜎄/%٥qЅe22ОB}lC e04B[BmyLBv۹e22L$+g$B*S-ؑh%Mu~!-%{FY8 }pFb<`l&DXTxƫ44z Tf+H[_R OBJ #(F[C -G)ω +Qa:\n } B)Ey#:iY%lTܚD9o|Cw`.{L4H}tјDY:$-h3yqns1}DI%&jQ|$ Γj} " yA>$%)gi\ṳJrh%|fe{II-JUȂHaoԿHw qi[ZN\\\8ٲ,B,B,B,B,B,Bb!`l" - d@[eQg0$O0 9 !10AQ2@"PaBq#3R`$?~ .cgs;UkwM)T!--KHAa7!DЄ"uXcdrW+ܕ5rTԕ5555T%MMMIQUI^1/s{{LKĢ* /  K?{9|W`n5j! 7cIEժFUƒUuܢ~Y\((jVE{Q`y*& nJ**>bT%-Ѓ A.*-QVJ4 ljxU]_D7ڧZu S$ȭLgqZ» X+4T*$g6MDH$ìL*C eɏv9rOHN磡z:e/duOܧcӶH ]9P-ђo94̂dQ9[~3I^l\uI6CBy)y$&T'^CjM=APC=APCR~6# E(z!z!zeu9C=A;'s=APC8z+q^4dQ#?_jO+TO+TO+TO+TO+TZڋuSUYR?yZyZyZyZyZ7kI6u>3-W/+TO+TO+TO+TO+TO1*;-Ԕ'27ooх-aoc v0-aoc {S;{[0-aoc v0" v0-aoc {[0;[؈ɛv4({hh/ rs{DDBB,Ђ _t e̺AAAAAAAAAAE\4~#>*A|Uߓrgoi$Ii$II$I$I$I6I' :/)+3E>5"ZUe\~V =3o{ {^Mې(pIĮJ-iRr JWS'$Ֆ%WWf\/%$W[TOj%sQ:O}7o*8^#c/nBhVؑݑ=N'JBWW"5O;tq|:ШAGove__$spoٝF5\Y>uN/ :IrʍEj1:*q 4⾜i'8j.8~fj 3M7$%~t56c'˪>)%u"JgnϕX0W1eZ%wz=:?P8ߣb?!Xj5:g\yvŜM_PT|fPOcRʭK_7$R4)KaUD* ڏ\^MYܥEºfST<6biV#{Upμ");vCUv8J^$CQ1yo;M߅Ut1e>Evk)ڣ1:";y9RxqxY،' YYGç7$]:4bOpmg-YWIR+2*tv "f69ʯS7锓}FSm4%yMP:DMPUԒm9RߞbQ$ F-MЁ EёZ,ZIb1DI$I$I$AAAAAvI$hE!B I$I$I$I$I$I$I$I$I$I$I$I$I$I9$I&ySi'$f/?rQMHHAQY?"!vVbO1O uf5aT;fy}Ony}0j3O)rJ|8)x+;Z%w1WQ/Vr; 8ZF֝e׹~o_w$$$;{nwR{Oo[0L*kf~:pΥM+1uz#Q\#6wqj<^Ǖ}'3ܖb n3J W?x5 aS ] AxW.TD}C T¤.^"hTm5q=: CFpcaa0ߧݽTfiQ1wOZ*- z/ *LFUUnS j`/CcUԩU);z7Q*xN!&Q zIណbh8nؼj61UOt+bYΨY]XzC_MiړY`0ڷkj^"G~ofL}qCk&SNɾN:~T m[޶BKХJV-E7*]2KYeod[&[SWtEսj~/UIxʶ['ǒyQvNB [3ڗ*IWضAyEӐ󠏘KdOrٮElVBpUf{ds-m$[tOvĽOrYAy_~{ȭk<& a0xLnZ #,!Atd]H ;"(hhJ[N^d.> 3|mn*jAh4Y Hς@r v$IoIy$NEZy_6k$I$I&I$L.I$I$NII$bRTJhNe$KUȤ*ILJJ%IRD[I$%IRTĤ%T T"H#sB MTԁPey筒&EȶBMB;l Att|}H5KDk[x6Ev ёD$O2I$Iv9 NdNiI3 !01@Q2AP"`#3qBa?E,.D A]/AߑB(PTZ(PBa6V#GRU;E=WAe5lɫn;9 P+iRe(Zt؝݈Ⴑ=1Y:~6&P*Q((P6*T-tRmq|rʞL>>(bаaB;N*P*T5:B Z9PJjJ~m:䏦 Fܞq埡oa9ҧDRtOk77hiQh sisrJ3i*w<#T(Z5G& /\((PG4Tg*Ts L(EG\}n9b+-[,; -[,xYNe;w )ȉYN`wD2ew -;z,xYN!j-ZYk-eZYk-Vh%e|Yk-e_Ξ+-TxũWoz^xU$/XwҤ.Mʕ6~;a#Ow*yOՎm=; rcQaBTT UoO%jTTR!.;*t>V^LJ*TڷO[9R*2ҝVJmHpXp8CZTRG#90PgjН BT&Ǣ{K' ~6RgW, c}S+w *lFЮu0EòsvNFV _ (NpF:Iɕ|.a9s~+mJv;0. 1*<&'Rb^*4YLJs+Y8Il;ʕ*m6~X.^`CwcCD J6yj.OU+kE!M߳Uzٛ*TSbʬ)}Y^m*ll9tDe3ʡžâwUOA .=UD, 9&Þ/&m*m*TRҥJ*TQtMM>W]}lTR (PB ZZ^TSiRNR㙵b+XV"lʎ\h / (PBB (QxQG0})>TPTv#4?M:GS 9N+)p n;r;rw).\ܖzrp 1q#N"%=(":~Re3g ᑢulAUJҤj]T4e25K5ӱTQȦUWR"Ѝl!P= ܹQ/SL|UOTUk)UOoF5Fɔ:~j،Z^2#!K ?W&) BBay{T#CH!.OvveF9Ujjl.O?UlT N79nA6SC (QySczl ʩT4`eEM3gw'S[ʝ23Z#t)Xڟ-u mO2_Tn6¡ U_azU*Oވ@^-UJj( ƪ}Zy'ũ;n,,mO܇)UA/{hG ~5JP*PEJ*T%O,}( …"qxƸPBaXT^>(PBB BB…B ( °aiRê6,PG腍PRSotC͇;soO!1"23AQaq #B0PRr@b$4`sCScpt%5D҄?WY}ǩU͐*Œ*>{VS[! w*y*}o>U@Zb./'QFGɆk9~9f޵fv8Ğ[b> %˧dYs+?S!ܶBd-ܶGrdw-ܶGrdw-ܶGr%wH-+h޶sSrCz+7x">"rAllllllllTt3$vAG;h̖~ j'ЛpRxnYܴ:rZYNҀ;*Mc[ܔ7Of8()׍56<`{#%0eϣZjNj\~Ϋp$綵iʼ[RZ@^НJ9]ɫ6 ڃ¨TDZ#z?8)?VQ^v]nDaZ*3tZHzhs[U䦷в|a6+gv^jT^Gi-Z%s"/yͯɮ&KҊ)Cx=TPS0^ G}ixG|+_L#a`)s3[p7ZNaqēӘ[M[M[m[m[m[m[m[||||||||||||||||||||||mYf5|||||||||||||||||||||||||||||mYm7VmYm7m7mmmmmmmmm7mmmmmmm7m3f5ys{k^<׹5|m?/Nv=dlQ04-퟼퟼Ym׷cjQY'/BhKZjij)x%WEQ|6y`̵֭ l- l- ֨ϢfaƊX/Lh-ZEVV?tmOրS8_xj[}8?nۣQb7x^s>^vߤ&Ҙ8S[Gp[Gp^dkYz^]7I0 84WY}.k{bg%v;;{4P^lC.RCJ^ɤ9WXcnKYs W4:h$i\y/1s'] Ew3Z8 .65=Xd޴^-u2:פY,m=)eҽwF9'AIuG^莑ч'ԭLգ*uÝ;,X ;@ҡHf0w~N# ŬN8Mjÿ^GF4Тj -mcw<֎KDfr6HZ!2;c3;(im<Ӥoh^A_Ċщ': _U:-<21upY\eSP@Oo?j$1~ ]~8A멖8zQlֳk6ycC=,vFl)u :Cei=#E|B/R[zXm]:V#dk.cVtv}P#u~;Ig E:1Ee 6fI438rN`  b8`z4e`5ͯØ歓5Ί̼*+x *IY!XF7qucdֈؤ}:IP*pZ҉yG{xMu YH"3`S^<S᳉D5 qep~8tZ:S&mBd:|WIo8}D͘1{)e^^I !tFmڃQVf{XoAxZ|nѹZyhu舉ktqH_-׊\mɯ]5BD&@.GLW,'GF @ᚴy-V􈄱sFtiN}nky8s;rYϲD:V;`F2) 7EZ 榞)ͣ{%h|L,Fb40P|U F\X/]^M3vnaJ'-8lr{k-10WYu㣪*UIrffts0C~8+hY jYdҖz+"Ğ&gZYM)$;[7VPeZOEgG9 ;Tck1׌N;,% P_5bkJ'Pj^VQg}=J]e\|8Ō GZi#)xx+KY,H"sq< >ic25eLhi4UGFo h'5Zkь ٭3>}ip~.܋"ϣщoPk\՝@iF>CN]GZ Naj^]p:r봻_meuMq\{7 uPWWDQ:"d&sY"Ҙe Bm#G%nEvpڽ#ngZ1sֻr eE=- wmbm5M1`v`,g3>*l IU+fTTh0[#y Πinv<0`LkcG{G袍 04u֊p9T)nd҉KquhlE M)pv?>9b_{^\+&<]kCX!iyo v8k8hs~ꏜEB3st76D~ˡmֆ궕OpZC!gxc8ϓmmaZdqqIz8Β&DM!2Sv2xy#B12]@~F n9#kVM١pָ'$ u2=eM%Mk^HD:C%lȧ5}#cY@JGyOբY,?Nc/kI;JExsBZDN/nSn\7%zMH[+ HqUDtQG=`6bP46שE>V2pO3J FIN}7]q YEiÞHGN\WEBj\F]ОJ#IA<;ܿ`?NE)NY_ǣB>2+-,Ԧ2I E ^{i)s t*rT0\oӊ?+ci؝ GK M8Ы=qV똛t2 ehުy2´,>V9n`ɥ}]{_9et٤H˖jJY$z\qשj/D]2R_ mv9gcϤdLuv{}#|ݹ^8dUHǺj׍w4+G _5jϓDLM8felN㈍:og]J1}$h)J8Tsϩ?eo{]CA2${dLug_ǣIo}"^J<(ꣴGK8U:ؤ߼ʻ4O{?DpCv.֕F3%.Yv5cE!IJgÙϩ:~]eA$o6N7*Z۵My"Ce .Ƹpkv~Xi'K5_ӊҶWF :>k͚#{ tXƫMoN#K=tV/a-{a!b?%bm;;˙}뢥z<]j7(;rVgh٬j(?&Z\--`gDG֗Uݦ i 1֘yцe p䥀F0yT.tWG&6kZb9# {4cE>!GPh"ZW f78UF2tjrs2h͔âgM]x\qȨ!-P=o6n_P:MɮN--  "Mв4\ Ҋt,1⻘-cCEF(_F^zLQ1Y6炚,6y[&͉ Ajn,xZx26hFUĩn}.x+K_|uqQBh{EgPt:іr7 [â? F ,v:ɞ*b4RKwG[|t84Cq;7:3VOEoa{.@{bmzZ#JW&Ye{4i|S$ 217U-k@V쭂en5ܺ@KȥI>?Rdj[dqAF*i^jHR 4:OoKKT\lB\(kt3 $Vgϩc [G4U5&5^C(fLK@/yu u=ݿd EkJ׭q\Wq^/y+2+2+2IBږk^+\W̬̬ʳ2 "n\W/y{\W.+WjrYO.{'}@j. . . "}v*zL|q.37 E. . #Ǧ{׃p@Lzp . ,. [z]1o Ϡ'}pHUmmmmmmmmmmmYk5^> 0 wzwzwzwzwzwzwzwzwzwz̡̬̬}u2ˢqi2;mmmmmmmmmmmmYsHv}l~{6 8CԶfaEbڬtA{d4bxYb6׃uz#{sU 8u+lӾpݠF(@&]O\`]90 a}.};^sqBרCjѧ{YԊSgk-zS%#}ǀv]K "i6=B.}^dkr(9CkŌLdz6=3SDm퀶h[n`:VH$ȌrRn\:slu+!v\&6+3%T%Y,ף6v@ߥCi6qAk8[s4d׮8ZF;T^Bü+a wl;¶[xVü+a wl;¶[xVü+a i]w-+v ݻ·o[w-ۻvwrݻ·o[Vnܷn[w-ۻ>og_B d-B d-B d-B d-B d-?'zb@SD |x{KoQ:|pxm(0בRC?(v ;=Fs8vVu&7ZFZ{Ú|ZVjǭ_k>cZC9ԷClv:_\GG3w<ʽ/ Çv"ST)# 4+ 3XG_]x]A4g>NFU5֋݉9 ~T5wrAZ8n~0C&rz}cўF/uX$|}AN+^nci"4l^*5^X#z֑4*3\};>:,=5&W=[ZV`/I0YbleYN-oR aw5q_gă],5pu2Z:7kl遲ʶC~G4w =)J>]kF.KcmkfL.>"?E 6,{;F!|nt18?Xy ^+hu!jP`J$|q:J׹*[ĭ tJWS$=fʏǹ ĞTzn ӪӒѺR[HO$|sR?Jk#FJH$m0mRbiCM'U*YA$ѸSĕ0boikWb [kcQ ;eIe=C#R$U^{8 -5<ֻi;SzN FcCVڙ+˩G sh R,3Y}PF;ǚU{(9zS,eºN-_"ۢS7*z[jf[ؕLv.¿ØtJuddy}/SW5'x[rw%9tQ1 /™mrgv#.kWh#A%:ޫcFirVZYqHô[3dSic T(C'Wt7;(76,Yz5ۛ^kQkrNlIYILNM(`0M?̠F^̀Tܕ&&Eh$m'Y/NhU{)N;+~< 6s(hAogأob:`bnE8y U׎ W^irW.Yې;qZ2w) NC]ɸFp̕y-{x'dYAe mwhFy\X+hhBkAN։]2M9;Uoǁ:Ȟ(Kr#[(^KmɿAt66Q_`}Cc0| `t36P?V7<5$/} t=?K£Giʁ;)+97oqR3O/WMޥWc<~D]Y(GV3ӥQ%C.kb2*8]"i>Rt7IڱM#TäK ]jOz^JA3;-${c5CH?PS .R_J\1K;>>3Uе{8߇Gzc諢iA퉣NΆv7z*Jamz%3;t{HЪ!o}I T>ggأg;z:A^PojwoCo՗Ϗ"$Y :躮Up(ވOs3Ub_!bW}-ƺ!ԑw#wKa|'7-^0x,6DhX#]zڜt>Kx;: I4GDi@C >0yH \[tkW"oස4V|:윃=*7S_!b_!GiO joK{Vh'졫^rwuUzYL9-ʷ*{ʷ*{䷿*-ʷ*yʷ*{ʷ*{䷿*{ʷK{䷾Ky䷞Ky䷞K{䷾K{䛭ZߩڏGGK~Mtu.l7Ķ[ -|Ka%oTvtuo[ƭVxռj5T)[-,޶[Y7d|K&X?d{M[--|Ke%[ӲolĶ[ -|K&5OXK CQ¶ǃ[c~lx?u<o[xxxxxx?uoo[x?uoooo>E[ϑo>E[ϑmy---ȷ"|x< x< y-ȷ"ޏ|y-ȷ"|y-ȷ"ޏ"|y-ȷ"|y-ȷ"|y-ȷ"|y-ȷ"|{-ȷ"|{-ȷ"|{-ȅ]_=@hth}C+ z3*5[Blo@zդc/J#=㒴0f TJ8AQNGtL0s{!B7KKV9#u]#Ivj VOlsuM6+3(M4**Km-"N-u5$eqCd1W+cD,Ii#H}[ eOjsJ7[z*(cH\/#jFy#v<;C2Aeљj=ԧeóЇHQٴl µؘDe;N6L q&p,Syau hܸ2X+բѺL@4.֜kW؝ u|iNJělh՗^UM7!7-Nm|Gl`67098H/=IŽ9@ac{ |ѳac4MPF=&cK=lQ<9SZךO)4p*'6.1֠Lh%c^/qAѤ\?@5{jjY-4`nZ9,Ju.95d#F`/ ٬& n5O%1~V(e}ǘ]|0.ƙk`I8ޠ|S`0aف_Cg.yaKWʉyۡ 髅VWM`V7-yu%R8\SƂ%컵yQl-VE@܅κ*nh[ a pE"Cs8ா0.[ R3QwtftnEÁ*/WbGrh%I cal Ly֜-nƁ]|% B[ LJ$[t"Z5l"Z(GN[l4i#WEPkc8d8f+a 9EA*(A?f_@Pl-ȡވ;mpPIthI ƒh PZ[tBF8Gib]\.3gF=g2K1: _LYaߺX@3V͡34jh mnGVUTƚytڭ֋]m]ZS`몽hd6ܬ,ٳ.,"+[lGKwAxӏ}Hk pNnwKьU{K?\@ LNPL4HBT(ًź&äz!"h:N. އQjWGXE#4BRUe`P f!?FHdw1!B?v~'c߲}C}/|~qo߿7{?D ϾLB i*5/hWYTeq@6fnI+A16p0#RqR􆺒ZlCHQg]4g$C6IDMVv: d" uIpDBD:_XTbF~H&HDl\^%u՘%AVj^jQ]!E2\PMLGj5p7Hwܹ'P3*0 A HA" e5Սlu 6l 0l4eџF"Bhf 8E g'7r,7r4 #*"y^ )"(F$7 xzUbu52 9νj\2IX6940!yU{УQeĥp <+HQ&Hp&S#RXqV 'S 9q~IHc!v>"{'~N;>Nv>!N;?^N;쾐wiG}'sN;v?G~~I?Hw.Ϥs;;_;D|Nc/~I;'w>"" _H}#>oa;_D}!_vo{!v>"Mv?I'kv?H;A> M&Wo}'` NN@%{ic880bm@aS(FЏ/ Pab+N<L l,a$Axs{'g|`q~xNP`Jf3hj"2#lL* XlGTJ, 6!ӽ-GrJa{0J2F$HX%!J:]5r#BibkK+(PQ†R Qx,偞:ӵIg̹: MX"' G0R}""I:SIBIƣG @ X1+h0>?A ܥ]#2BaR Q˛#`jM(IBXCdb&d**H2h Z,rd "#d mfNId΀0 pNa&VG8o<8Eش%6!Dt1m ]%g0f8zA:Mt%b/_LZLNrY$dEZŽjJs) `֏9B*F%X$] :r2pIj8b &! U抲@3P_Hq1 :sjAl<"[@J46  D Uj! wLq YOesBnŰی'#DWH"M CqAsl"\P64Y C @csB011bbtVD< 89&pao0y>vۥs=|@CE /l=tC;(π 7PÍI`b(]8pz^]BG &J 89zX <22Gfybly @+CcJSC%ꔳ <*,x| ` GRNJwwDI@{S=0wni{L_ !V,9`1~㘼<5 Ayf)^7 ֫,E0eB݄7NMDᥛŅdXe",b)K4%-́*_: ûR&GfF:\PQ$:BZgc8 PDWVЀ ա9WGﳨTJt6B*C tDIBI\objшUp`RTܠ@ "ZPT31P5oB6+eK9<@M^DH`R<~W( /鎢ߐWPBy) !p7*2X( DvJVu`<K,`j`ЁR$;bEX rEl54"EEd Hbmj-FbbV{Zm2V"̐mE(U7 )Ъe E ƾ{1Njt[ $0L E| I:B*JThΰ%) @Qh>PA(HJ*`ؒAq\<fr!Ca$!-k!wiTD+ K`\eRI%/W*chM:#@K 1J(;Y,CP\⢙B̹tqPaJTT%:oI5+4@D@JT5 Dv0%Cz3;E#Ơ5GXԈ/!ߚ I`Zf83[F@1p-6B(| 2;PQo MYZIZd!r!AP9tᇘ40k$ 6NSHY`TGH\)(@|(̬AX,<-s-G 07<' _Ĭ#x E@!eƯ;Cz(BsNT= 7XIh R)F ZDx$dbIN𼰠`3 E]  E]H.S:6P ut5.80pթiR(RUhQ3*V*砚ZRx f bdlũPXH-!qhmĂIPa 4j%?!VSʮC'IC- LhD4 uƮ19 Q8[{g1@E@tF4z>.^'ղ@:Y -DViN !D+d{zTmԙL"/Wgyn~Oa^4j+&HZz# SReY6\[73rgpL hiiYS`Ax:j  Ùr,@uUgq7u77,5Vΰʝ&<ξp59 NePi? U!bEm*RB1<28@f;jݞhB#JKbL{7s7s{ URJ e9+||!9D&`"(;<1C@L4"rDJy0S`D33x%>k)*6(Zs(b֥RsD3hT͡cd!YV1@aq$Kz,i̬by"@*DE *YO#yŧ`eNndXL@M7!ni rE0'(A k0*[%B7Z]`vsqH4YumAU(’+xu,ƫUJA3D-@Aj,SRR[ 29fk4U&*)W ͠M*y%.L;?bwIޓ'IvIޓ'jN;vH!DgTuDދMbkQXu&!s\\T?g'Q?W?g?w?g`A- =>qǼ{8{ǿqqǼgX=8KI DDDDDDDDDBw/+t0^ZǷqn=ǴqX0*6$$iD`kg R\FTN {Gۏhh8==c@8@<8?""yk=QǁquqqgC.<* JPjҗ)`AM6ދ`A:!RRʺG2 ` :|Ag pKƄ+ duH(EPf~@W7WiNmNȪz\99(0Vd]fhx.%/E_p{x(6@Cq-6_`\`F)-^ĄEzSB;;;*RBv L6!2aQɼ7%oϲ\KR.(o)XW\2Zɾҕe *H"x6(%r @]Rx{k FnЀ@sspW"T@h38<ګ5S .P\UO.xv^ oqqqqcB1uaqqqphf4q *#d,Tp8AB&@A*`^pYs5*6,:Wy|ȭ#DR"[q*k-&/{%P3bYC #l @)HrtBlx=K C9.z4ĥQ럮KťKDk=탏:+nwnHNVY:Fҟ8㗸Co1F#b1@6ʘ"l58XF#b1F#Bm8!IpGq|@Pp\bvf_#1qq^MY[匢q#8UKx^8M0/? T> 5&)t|€*Xl_q ~qUxz3K~P GH9-=HLʲmy̓L͓( A(PF3 *2^`A`#oAEc]T h la j#\ - LjO#Ed VIv h4IjrdV&W(\X~p7t`EG8!j2*bX@ sG4YA'LЂ(訅@|MB4 ~2)~2)~2)~2)~2 Gݼz]޽>veݼwo6]_G~:~ ~J~~j~j~ ~~2'O'q"~s?D'nFz-$uDkX> € q ل:iN#ew^0/9tDc5@`mCH~x3 SfQwڊ JM8D,V Aa- r$[4X@;F 7dI=kReh(ܽ2UZ̀#>h3XU@J?Lc彆5 (6ЁBHVPFʙh[V PQ L+RRRRRRRRSIIM%4@qǼ{#8tBF(B$"zIL)))))))hRRRR"=t.C888888889P8P P*Z9īC`L"'\n8888 e 5 p'@zoȨzY7=fZfZb?J-^_SZfsnzY7=fZfZfZfZfjSs~)QjsnzYXzXXaFn N Nq-NjW9/Yvu=acX:H:ǩ=NNH7:ũ-N+9:N䜑kXT-,$# #2gP V %)2ĐS+i 0@0zF `:c۬#[LUyV:.S@BF^$hi) 0bTK|v!G i륹jQg(I&A}h,2PJP=o-ЂBx @$g-n;;(&/H±ZHWR!:!Bڰ*DЯ<T DBPas-̠a2$!Gj&)А?(BPPBȁB10rbG9 mcaxG6Mtĝ$l#o|JPmg8FX[O.S_YMg:&)k)k)GyR1k)k)Tup`k)ve5S_X N#PQǾ*RS_X3C&cyc_HJkOkk2G3w>NP IsM(ar`H3L,;@Dv zC( \kX'Lg8/#C h|D6=#ox(Hnn%=#+.\H ͳ0?aeM uLY#4 N! šuI|1nNs}7S5b̐!O??22HNqZ̬\QFSllfߦmzg,0ҏRCYYI, 1f:—c7SBNN r#u " 9W(Y }{fϦm`Vj^gT=B !QG*M0@DͿLbHMPB$pY+ӑr19Y2:将Мq8&8𓌘~'58E2ķIvޱڡZ ZGAQfSÁ!XP!P, 8+` mA!GSN\3 =GRCH ?xAvzӃ(KU7z &U#w<W`4fbQMq8l΃DQ8Q aYD~INB2١npp# !P(0b~̷;H{G=  +$5q.z0q8Ts0cp- SIyE` OS?pDP< F N!>Hts-…QCZ$ik;w` <᱕G=M(dȋXq0*;I`3'I̮P΋pCMy_3e,` ECd x=e?@y%|=dSgy| 1CHh]>B8@C@p#ĵCc:wTI**GGzls6}~ͷnf˷3oۘt}>;s{3mۙms6n^͗ngkM~fӷ3iۙnۿio' Z(dC^7U}&uhQ?jfysqʊؿdht28xrxyr? W=c{>@!xW6?b~gO؟?`Še_ ͠OOOCS'J.,_# ( a;V#B<''`L aD¾GX.pX4AOZZ~8N8N? Wズlgli37 /O e`8;p838'qg؍h٦R[?2(;s߇Yvm;s6ݹnͷnf۷3mۙvv>ӷ3}ͷngxws}ͯnfǷ0hs;gs6Ϳnf˷3gۙh}vϹ>m>am{s6=~ͧnf߷3oۙls6}>ͿngMnf۷3oۙQoN>͗~f˿1;̱"N 7hG4G.(0[) 9"eX]<(Q 0Tὂ$z1rM"քl\AR,Ec @}SEIT  C 1Z4:=z1@T֠f @NJ Fp푕>aGQ BD53F$DM| i, \Rj-Xm͜i8%PrZyEj*E d:Iht IIRg<,^YC-7@@\ yePU)Hy}<ɧ,;QǼy<1{<|y9<@6G"ss8=IkY &fY2啑^IVe*Yjw 6zW7D"5^>+˓]a‹p IRtR @(B~EՕ7"36 Q@3CPHЊ%\۸׀@XH[-YJt>@\4PY&%̘!GY%sD/+Ysb KrR\TB >-jnQDdF:P[ l(M ! !@PEXA$+m@2R,&JUN @%B*`1b1DƑ#F4F#1Bbb1ьG JG i!#B %aX|bċ,XpXb)0*((I+X(/D!,V (QooP a0",AK|pV-6]Lu0l@@$ Du3m Arn$i2:P#  @E5 ͷS6L*.0F&B ̙}L 7.mf۩- @@D 0EJ- 0`"h FP0 ŀ+9*pxcx+Þ#xd@MS A@r 0 "j`(3?yfשE`! `9!'(nXfߩF\j3<)kI h 3k"Gq?bƠ P]שlze-3ƙYu+\ ł\VFM" 6j"E4'5nuш;EqZ zR#$ dnv* 2s`;+E{@2P,P@Y A# B03chްN`L*b@jE \: !Mδ*CzZst=z Jrd`(@(A\# M_ OQB8a[DPgk)w$^08Lx4a9Ñ(,7&hOL!6rHxŬ\vpJ WVn h= S@ pa25\P1S¨s-Iu U@q10M^g iP{p͡:\zphiCɌhThLTa&W^<#KxEzP7%8TXqB gKZxXˈz@DMgCҒ13X#O8 9f9`He lm`I4k 'ҜB Qa,& ԀӔ%*HU[i, D@⧬ Ӕ&'ݢ|-> _<@LpRL sА-ЀZYL(ZҪI=uI>@5bYA7@L} 1 @D!"*=HkĖe XMh>sO@Hr34B"ZRiCC {mT_k%iXLlLq+t-2ڽm4`D ɳk=6\}R%2X*|}_yrc\j9ײ,H|F?h bq`Kp Bmۇp+2xdYO O޽rLλR[m0$Ɉ8B-9 $ZaG/mxS6}d9 ڃذk!@r- -N-i׏-!t-Wwi3 ]Rk[;ԩ.MvB9ء0,^mlRu>wplX$ =94\:f6I›m5`zC& ;IyoN`HͶv4SoFX IhϐԙkyBӟ7i=H] {Wϗ}mmg[iv: 1뻓xH5˪ZCztK--Z%QMN]J*:@֜6R%-7_x۲mk%&/mI7@#垧+ W`iGg*Z4d\4ݬyBwf*"y~Sm\YoBiT24.p}4>!̰2@^k%xK{rCHp sTL]!_(6΢ R,f䉈6 4mqޡg;fKqٓ6msH2؆0 IД vNhi5mŏ);{էEl-jm\$ImJo9h DTl鑃Vm7o4Φ S$T_ETU-RAK'  1&ն_}6mɓնmm`;FԊ)Qa$mmI$6m6mm1nle% P\SC m6mmimSV~6ܥm/&[o>:ITgo`)J@Ԑ}%d'f_YImuյ5Mn1SMINyO6)6۷n$BI$mrI:H!kwHjm m6I!$H[weIAqmmmm6g-LlI$HI$e>[( A@]6RI ߤKm.PxOƁUbhPἹЧdzNQf]: 6DD=0J,JZVXBJN´52hwwwP6&ĹmӞQ S#8͚ܿus|]i$CqetIYEP@ uk}I?[ӯ.!5R InplK͹u|e_n%luW&m6,ݳjmQh;+l3{2lQ6`Y XLio'޿菉 票dލo;Ta ܝT)\$Mw}(2$L4M>O,ģ/Ił~[rjRRzF& nPvfeDQ\3KsTc_]JNn۪M'E}K7#!;~1mH$ma2վ4Fy'=d mI&i B_ݾ hH ^'k77mm_u}mvDZcXOͧK~*!1 AQa0q@P?TGw:SB=SȄ;YDϸk6pwDhV"*ti\ox5Qw1RU+zpN16W7`ɞ'ļ;3s>c;7e/yN{񽧐:c@*k^;}ѯ^4AA)E3NZ~A?O鶻G 8|A~E.1vg*hk/:!J߃C1GD}p_4.#hO91[m?Ɩu$DCKDDBd6-}OR bDؖٸ"ja+DO(]TAG_qA_o?k:%\E~?c&|- ڑ|:nM2PvɽG{)nMA)4zKFߙ)G'RɃN?^OqZiD$B! F4ADDODB2h:6V*|ⲲENLbb XGCB4OxI^kƺ!Ϯ!>$B|)}ٲgOٿ&oɿ%W`WatD?T\^9O^)Vtp/g+3pbBFj̃"2 .&Vs5Q,%K0!xГd!4͕K)Q X헆q 㸱3=֍ O AQQD2ЄгXĴ',D6*N /9 d{-Bc##6l6F !MW*\REDkc6g;$a)EhDB" Y)Eg1DLh[004]R" A"4r,3FFAcFbk* &RzdFybR&sPn%"8t9ɪ\@t .2b!わ*D /քZ!0cI%$c+N.[8_2yP%5IwlD*QNq$=14"Xʈ)= "pi\M6-R"-[QRU)Dˊ6$&Qh7reW%Rرrto%MNF((PhYaɳu l۴=A!lJjQCme]lh tBk f͉t쬮 Q,'ԓX^_d6$mŤ8F͛&*HoxthBx'CI446_8YEF#hqưD!xѬ S{!`dPm;C䅘ECkgG<&(O햍.HDЉPdmYYvQ#{cDƧt6eNCCD5bQ[ADAF%IƲ6Cc;o#!ER2u¾ }5`<e*eBiTSCcbb6D3 ҍ(n/Ž#b,Ș5AXY9b.FAqq p6\ћsB!)DȄAˡ:й9 hd8w8Ca#L &=Z؛T%6hBzgzgzgzqwcYg;?(exLga2aΐ[=LshY)KÀ=*J;v&6R∥ecx| \Q|4hz_?~K=oߡ_C=ozߟ??ᴸ yH[4?Nߡ~ i߳0ב{!hX'#xDK2mߡ_AWJ(4ObZbGr2"ItZV%$'lD#m –aJR)R).X)F- n =a|-R\wE97 >{,F=6ڃ!%F٦RGZi!J6ѡԧ!:lI UWA G%adD.RL'f܏j=ڏj=IC$!J,zQ/;/{qG{QG2j")0. {1={G{Ey 7lzb Jhcɋ> Ƀ{g{g{g MD\1m{Yg{g{-*+(pF){Yg{g{1nVV[m.SOC/C /ShPjSSS[SSSSS[셭$RhEzjk>>>>>>>>ȷo~ 4J} ʓhBe宲x|<\KkRexs_a2 KJ!Zrx!1sL攥)JR+)LBH7|b\!BD {. GB!4B&˦͑223b6lٲ3fNDd6*#e l6l̹Q^J²v1BCVJ•.Z4\-MwyMwx{-V|.ׅ&Vk.0El_]?{_c>m.O'_xĹf͑#######!B2221 aBIILANziEq?k/Koʼn{<}=kd!1?oF ߑ6mŢݧ;2+;M|P\\\\TClټBf V+5݄E[>$qF}[ d^moȆӫMBt%G+򄽉zA6Jx/'?k3r1σ}Io{cd&c !DBK _p-!DA6>J1MN_ѤVIJ_|w_>q_3I}M=/chɮlk?zpдڿ>[JB!(>1.FR)JRe8A|E)JR)JROg"3xUp$(9fp|lS~o,#OM"UޗW%8 Iv_?> $rfB2엮 sˁ>{/$]._N:0:_͐͝%*Uh&5 aX$$WX_5?f̸ H_7!7e"5.c_'{TgJ!xE|Y5LH####!2 o"b\Mf͑##6Cx| RuXK䂔( QgǕoN$")J9cF7E/ _6d 7J\\,k;Ee$$!О5աsBb!B Bb!!rڡ^^*I iجؖ > Yh/KNc{ϟ};4ݿ/ȄcB7w<{hElv~U%z)I>z;k^ +> Q~^lmN.qX7\UًBٳb߱BDɇm V>t^<|Jep##&4VNEV,:mfٱ.G8M1X8jА ^}yos No8 `!X1#خ-LU И!v6iݟq ln4oHƕmϷ6 !&bB3\DDk<5k3F a˂;"M/_(ed&jI m~m9 CP@Z!&HH2F#-{CHBShNofM#.Rľ%7Ħľ%/*4ThѢɢ(`ׁ4TQE^ a x5M;|*. 4hF"*1(H]MTr"I aix ,g;v$>VBW@ ~Ma$HpIGBu6(E$QE CDR2Dpxd"`:&\ 4ph7b6ڂLL47LL Y_MZ):QEFlXjLG3DʈTxC.X!!Vahg<%qM G Qd6IqÄ\Rĉd ;kѕ汑4&dhXHz()qIHF47f6lMuxn\LEma8>1|7|=(&thS L&Q ,52Cfl&T726At:Qw95CH{1a(k!V"&a6l4UJ22CdGI!͏B2-&)XCPXgatҔ谢X$4L^S,2 J|'BB;aȱd""pĈdCDHceRE}tL'c.r Kh>D7ءߥ![CC] v鉑A|a+s_EXXMQraQ!F0J w++Z;t N&zb.ega:{PG%ѳM1Ƣ6\QXL] tm1tQK 1 C.)LܬAr"4@"CMD  '"'2x"!$AbtB! # cƠ9в/r.Dh" a, J7D%WbBYhJtыcf'1 Q BAtB(r:!64|}} 1sв!$p& DdxiB+e6*5&"2A6A&!єYcNOc. )WJ&pl T= TRb(1` Z-&lXT]3#<.:"'"xѣF h9hda6-fŦ%(ѨU-k,xKˁ4)qQFx u1=^ѱih0lغV+F6(L%UllHzE{ t _S̤O}|14<+xX[D^О"uv+)~r!L|Xdhgsb| LnȘބ,ZBMeQ- d X8.^;w'8̮ ҳ8a;$"Gqa7kH{5&`H5(-/ _?#k8k tx忕(czz/UJB*#.!ljmSlՓt>L! ]تMieHs\hAԻqϷ۸ݲ=u{I" p΍**4TTTTTTTQ*;.بEE*4hSXOEeeVW2YYYJޥɍm3R^NhݟZn"ػ?D›w*i8?`+(LA,BtB;wT! Bj4T_ƨSoc }˰)q24hК'<<DTH}Fۉr˿FEEEEC~m>ÚW']"F8 _3P(/R!BwD=٫\>0b9D&!ce.5S]4s-c ƹ41o- =3o[ ߗЦ/G! <EFwwi. <25~D4Cϱ }\}/I쉯r1I{O&q/quP(x Pʑ{yErƄG^LA!);Bޟ^?M)!AZ]LĈ!BBb0!7ش"!B!'— Q(QJ\)QS%à_D.NBhj6Fy oCEwqHU&++VVVR~ +W~ ƯG~b+%xW VR \ThQDDAR=WSDFf$h"9QUDDDDFy""""4DDDDDDDpT6ZBE*F^T&d4Ek' LB!!B&Ⱥ!aaB>!Bd>  CHDD!BCqA,pB22222222222222221&FLHHLLEɋRQ3ndUz)('T!= 1yC؝w/.Ȉ2,$`hyCl]48bdzpؐA(fEo! 2BQaXRRd!BtBb!1B谥b4%K*VR{)JRJ\BB8 R*E;kR%M>߱:ƱqO~?M6B!OQd)puEˍ.)Jtxu'{{1ǂ)G5$DqG+VQ_랹Mqsפ88z'h44Wp0īkix"DE% 0DƜfj,H^ƊRLphNFBb>d5|tPC6CBu~q]"'iȖЙɉ7"U{9&E4x%\GHh\ *9[/p},dCxJ|9rxfShxcX&2b&yx1HLd.F hF`HA#o Bdƻ?e5E)ׄDV͌hjrV3"T2/rOxA8UQW&גE^JbѢEEFy*QĎބC肦{a|i/74.ol6l[*Ç\:XbQ V(GaX)J^gqe$B7)!1AQaq 0@?#b4!5qȄ0E`\*2 ^Xɷݙe`\WTi_(Zђ7%E 2Po.Lu [ %e"mn`xQ_GkQ xt_fn" Ia&&2kfս[oE2o)0.MBz:Lo5Dh/"Z/ >!YJ~PQTKIB$=wE#f,x3ZtRDZ+ikP?3}X4?T֡p-CŦAgHxC!''a-ό%?O%Q}<3jQV [ cV;X4xUv<MH^-o *W#G@~C`)*ߗ紗I6|YOStΟ>; iw~W-h76&\GJ $BK Iy;1lV^0,6|n߼F5d.FιvGo(.VEnpV(]f6WQ`1(\훍CYelb" _f&C]"TVh4 d >N# XRYcR,^T5>Б֮i]1k=d*_Sj7hب;ԪI@ hy@ٍ*صAO jw=ЦU£`fzR-^yL™v9G_nI--__~Um1/1kZ=%ܯx.;ñ/PpS+jd,޼uZ0,TVS`R(CPF<\,#2v1hPnܫ«mJ8 * " 2(f6Jv aj+| QtVr8!O mfBD@D<KwrkM(1ZXL7K̕\V%YfH˲F6kl3WEy.ja&T &F%4ڠ@I[vKɮ-mHPFsk-NkDG<9m@[z U9"E(R,IpdѪӎP:b%A2kKuUK4'iBt%*g 0Ђ_=#BlStI JR=4mte,5TQviY+,9yBnam3T8}Bls \7U`&̂ɟt C~ӎ{Kx.IoD*m cr2>X^]fTT6@\2k &թkm6y$㞵Vlx:(5bڀټf%Ϭu+Ln jdkhZxIIkԔw #hA"< #u~b[= %,&]z6a)(JK4Kk(mr꣕Go%g5S"&1:0qEGRD%uUƈm@xS_GV$keNe[pD/_Ҵty"qfcda%X^G%zJ? CS_/Z߉Jw^ɬgOļi{G_ȳ=ѣy..9*D7vEoOh8jg:}BI) NA^V=q:dMf}"<5-n)]]OJia?ӆً]1g9eNsfNeQ<봬m ҏHjyk܋hG59~-Zuc4Å+"R`Eonj gRǨAm1OeoY4%}hޑ~bucZ]EqSaN< i-X-Z֭5"V? WU3=YNK ^hh) cM0!JpF(6p|}hb\4MlA]Bab(~UCJPA+= SȀ,K)"EZTճUͶe` usa-lNnm5.q ehUh"]H2hyʌ%M(bT4VWX M`^']RLhl6Z-Kqр%Jvvn z@Δ.W~Lq= !hSiy-*&>rS"֩6L,W2X9.%Z/_qqYpj7:S0#*7w :wh30&+LaeG\C1U^w6s&nùHJk!d d+ySh(U;P4PK (,Bu昿|AUiO.c*x)U+2y Z@54q/RԥAH*Jos0#Am-Bˎ|㫙[&xL<Iտx7&k_y֯ߜ] QOOGyz[Xy}ᦾ YOK^p]XZyG'-V5Ĺt}~7y 2re0n+}7MP4b ;d=ɰ2~kn^uL[2x)=v@y"Foxlo+A< .bDj7f 6oLLAX]LJ1MW=eǁqo5]Voa41UXu ?, 8/4skA>-E1L+YM top3/YXqƄ=:0<˶[$ӥD#99˿X-SW" :_5/ H+Lbnlʨ]][\vp0:,e!ɺ4&3 {0+ 4c*s -   Z=` IL.h0sV_\;P-1ZEfuywo0y8 -ƄLJ*WZvQ&I۫Dkx0* /.ņ`t[1I %Ⱥ !c^Uc|4Z].%OZtXd^,-pcќ%T tMLQ!B5_x16%Q !WUh6j0Vm) eZ0t)T) 6 B no "XFĎ&hЈK”e `ZM+tK.TġSrZ*;mn[?Dl0qscBʺ]J >XjPJ*jZz5ydX}"E=Fb5R5Y12XѼ7ƭ]-֦[JՉZ|yEk/H%PdeDib/8Q]f4a1'`MX3cK|@; P')le9( FAnrEH:k%XSZ+Bm1*QJ 1| 0/Ut\U_-5El7L-yָ40[P\kbu[N3eGx 4 NįbhڽV $VS~ue [il)}dVhV9)#(AjkUǙXAmj4At)J[K^[f\K0R `Zs)I-zcHUJ`3)em\:urk8ZQ#a""9@JXmB`]~9 % ^Uz@ΒB@0x="Q/ҺǃX*,W.haؓ]F14ƢRƒeDU@ii;A;49Rǫa\1L"KKk uL@.^64Wv/uݽ[@mV[Qu`yy٘7+ e#ҠMs2S_GAszh;0՛{M. huΓ)^Lru-g7.:-HBB[֋ ExwFCgS67ZcVtq)cQ`yM6u@oHW rFR-5U q]&0/SZ"aKhsme Jz.25z%خv'1&2fe{LA)~WLz pzG ̱ f=<b집K*,Utc v"pB-PkS?MQ]Bh8W5#C*3]/5P!iYbSk !yau)ҙM xN67L8:I4mס"Kg]"z1yx IJPEBftuJ( 8JAsu.YqtפB..f\'2zPEdq/B?3jG>d]Bh]&,ْRKF 7m ,Ц`b\hjh+ы F5IۈƐ/gZmm5^`~zޓ1 &gq=7pA(a-6}C9 `+Rm|o[5q(N@8[W Y^3A[*`m[bSeTUR eM(iH(aкbXP5?q.sxiemRiv5p`RiHԝyh1z1Zwxku5 ]'߆@6kCNF͈ ZԠ(Dd_!)b2fwKpCPE҉$՛).+"Px%zGu}CHt%Z MGs"iH Ye?qA m.ل:V^le* 1],q#BD)Q)m"f340(ڴc.<7cƽILyxy3G#@_ '=cQ0m@[Æ#hYxcUT@ldpN^,ʣ0߄2+M" 6Pk@5hs+\,; p t4o cǜ<90lQB5x5Vz nb^*)QE4ZuKeNq?wjqq{s ;!78*t-y7J+|SΝu!c)T_x)ϼb4u``e9:9c%y[8<[ϕ̙ x2͓ <1ͳyA fm~ x89Z ^S'_xtYUZ{9!.w`L`V<9Ϝ`c{; #_^0*.IeK B5jڽ.3$#B-;mqim0b[6@* mŮOLbnn^ My{HqB$b\]BZKԱe_Ӭ*U&-Bij3غeիŶWbQzLIJ(Y]6!RN ‹EW7-YY5x 0cP]{E8&3R!I[j^v xVA(+IaS+F͗ IEN(#K\hELX]loKߜe4(gטUU ]{Ck_*[LteH(1i%UuL{LDȮvX6j 4JxVq6M׫%ӕ@[VZ+^,=[YsAh[)=AU 1 PCOBX12 T(/*(\J庲bݷW9DQrɡm9c)^XJ@MTjJjBcdaRr]ɤ&@QrsQRpO쩿ggy#KC?o欸(4mu@ψ e)aTV Sw\iΜ@]40| 7K-;`:v?%`ae~O-ºH 1mJpq,BC^Z\c_`E) e@cRQ ERڙ ׇ ,3 +_`%NaS ƥIAH:`B;"@IFQ\[PYmyܔ.k_aWif9+Z[!4_.,5nZ"* I!8mk@bx@1} beJI]zP`Qɸڗf 8 .((k X4H6ZuXS/COP2lTvۚ)UADt55x㈐wR4άݱߔZbid6F5swv7&[cJ?a>#O' ?'L"tPmwR, vB%itKuM#%) #!Siwz-n52PM>sWcϽb/bZ*jQ`T~8'5QOECFSjc[xkχꭞ$yJ Xj6aJl*B/ m.`^2T1@YH )HZ&flw_zo?X,=8j6sṵav;A.i&,PjXmykT&"~8!{!Yk/KyI s|*H)Z |2O# ց5h9W!@§%KIH%`)}XZo|6rgkrx)R0.M06h0ޛU,5#A*k 21PC:ysWp/W`2tۓfP -B'\[znPSHx9Ah ky/?#k Vq57b;16%oD%YM=!YIUz1j]A# -no=ubnYK-Ax `MqL/3nY5fIgQHʗY0C%qcKpڂWcWmc0EЁ( *\-7,rҕA艬V͡Wf狼#Ɇf v>@M(S=DOo,]U8 >*ϕgʳX{̱ONrxX+|wzwR*, pLe\U׈R u)fSXaX3_ k WJ"9N .AzfUՋ;د%>5:]gC:w=;nٱ#WfUQ-Ut7<Ό{yz³u0aC^y>kWJL$cGe|W^\b&?Dp똄Ж3Or|gwtQU''''R>A8=񈘂Z;Dl4kfjk~P%#h%.V"/= mʕ M Ӆ#/ǼO'''' 7H$ZUwFuFXeQd4|,MH7a)^>>ȇOO&O>9=S_3ō':y%<%fXҐlFUG -as:ƥxiseP2Rm{)))))({蒥ŗ] #ߚDFu`~*4-yLUTp~aŏSSkOOGW9^_'CQAmyR^Fʵ5^gܧݧܧݧܣgL?qD.k9r%?n669+IhE\)+.}掱*G,̄ch_288pǤ5 5qx7ggeힱy~3=h3wo|5 DifRX'>fju%:^^$0Vw(40 u%? 9!P8jLVz)S1kx7,CMbԤɴ_0ulՇxT jEn'Si}q,O w1Ғ񙪎T}1ہpWVGAh]zNk<>i mIWJξO>? ]7<tf=|jW=bclV $GJ5n=!l.`jlڵ 3Lh3U-RUAc![_P_US#N6)`ۣ5=S偐 ^@.u#m%jRVe ٽ4lkzAXBR:TR3ʂlhÛpjƵEX"a BFY6O4 ɁJྔh5B yb~4,RH@a ʣy=dY@ j@ %]UjԺ.5 G i=΃-:|||||.~]======|=ۏ|||?]m}Om%`Ca)`nЪv@pj;KfzG-Ĺ=歏(_Hj)K_C/yffv7[ei~b>i/y}yz ޾_iw[{/_Կ<ЧxRW/x>}Kg&/XR(0y5 re9%=|Y.\|O]>}TSTSOU>OR.\.^ /1|/~7.%p6hemaYN9G\h7F5Á +{)zJ6;J%V|"ZI76@贄Kq쫨 J}"i{y==t0Ox̯(]ru~7޳¦{bŢN/Wx_y^9k)V̻G5yާ燞526α!A5Gh4\xN[+Ǎ΃u_Y_Ֆtp{:wpwt:wpK8K8;:wД {w,  Ti6778C5c5\cT`."S`,pwt/CYӼyb4YӼ"+Ɯ;(W/M%{R-ױ=]k߱>4:Ayo;+˩3z&K|Obk[bYz{_abh߱} =~L~򌱒r26p]]5Upn8d,lj_ٻGpi)zjY K3H9h-ߓ|@Y0#Se_H>9uAW9"b1n+B;8kkFtfQܞKԔIR1Eʰ:߻ KRՁ,NIґm&RʴVe_)0- [:v^ lo)*'OS>5|Zܹyr6Q;g}a%7]=Ikɳ j,.\̹r16|0Ks.[mܸUnhqMA0! %:ƥ/՘([y--;+N9q˄Xy CK9.e4AS LƢU`Ŧ*&<%rs/2ϕ\8Uqm7nңy ÌJި,SƮJJc;ZEWUjs-[ne5)S}H O=D*PΆgBqf=Y YQv7ˋ:'ZʺD֓ɍDsДM|Тr2izB"nVRtJK(,]Vba݉]c0w+{O@kF ^ؕy++&jRZ;3hBnDv>,̦؍'B+L-Fҟ0jiXE874,$ O䚾jDwuS m#y{E\^޲-*|e(շ[,a#qk84u@L5gɿrnq|-Z%".zƅTܾե~Fyn^=Ere{[39-׼zs^Ʀ~*˖ܹm//yi-[-.[̷2̟#.\re˂.\r.\_?hmqeǜ]ԛlMe){\Ur(F{Tc2 +p Gf2XZͰR(eoDj\ QʲωYVe遨FfBD EZ;Ut Q.8Fq U։cGyy=p,R29 N BV$LTy wjͬ!L0 .9NU`b–3\P2 k p\~d!`,3Y0#{,YȨY+;g+ܯrg+ܯrg+ܯrg+ܯrg+ܯq m3ReIx0c'I}fvoYܻO|>ϛqq~# bH?s}>ayO~?sSS`LNJkjԈs; zzGd1d %z▪( m(oE1/t\@F³FVIv^u vԥY+, ׽T0 (+lV.r=G6Džy0 t8*j 6k8ȴZu9fkA=E8!'[˺iVY[f2hh1 v$ B Ec+(TXt R[,(cL,QVev€Zvܱc {OGNҥjY!ЁP,o%*(k,.ؔ0 ..]8qU{JҹJҫWؖr嚵Jr}㬯xuaf'uwz|Ԡ?_?rq/W\(3/f23-%31| lt/yo3̷\̷33S3x\ᚖ֓g϶g??"M3-Ht_7b,~}8}>N.?g>}z_}>qϸcWg?saϸc?n}2)~׹01_WY=_(eia>>cσϕ?g_?f=Wg >: Qw8c7Yُ`_?e{3G{_~}?aPx=\eggx^(5}BHU@^p]r 4S ?(jJ\ўd ^tkKc/thە;S-fK/삷t @fW'c0 XQlF!S+Sr ZVߟrT:@Xݐr}Lgabc |by̢nW-¦>1oy},Y__yg> z.7w[:߼ >1B+So$ǖ([m4L5\a'45p,kyi\kxoE:zh7P>}˄ϼ1h[5E WQ%\j?1xd.aDKSr Np9 :n'LTޑ_‚KKZϬMrK啮0$b끋W:Bj{$nSk5As{ݟ{>S3m5@G* r.t%\qZ!ҡu1 0@*@Y3bEf$)3Y{L=3RtF VڡQ]eRYuYE9˚ ΟtsX$ĸ&ص^{yqKUWv˪]}JQZU͗ZNލ6_W W͏ZůX}q՘,a2~qwd`]B˻!/QtMl0͟80<ǬuF%JK?c ER ( +j94#h^d60 6]'R0$o 1m5:G֌~Q[5{ 1H1<*Թ%/` NjIkYFCXӼ{"=?4jCAk8Th Sji F0l0n]N]rG.o|2 Z0FVpXܸb .*L>Щ# Osg::aST̀{sLPN:ux{C-I` N%K_5hMrvo4h2YslHb؊ 5?U؊qTp4..*6+L\wfْؼa7k~wo9evY~i: ;lFp֦+r/tč.# yE! 2-t Ufs,`_9bjלx=KPaeuXCMb2R4:k . 2sTDݔ E{[ 5>"SSD!g'l}cߙTA^zwSh ]muKkZ)D(sZammm]*μ@?d9bg Kd9,=cLJKpP.jsnxpW%pZ?,9!7%@nicq}& Ɯ^f5QAځ;cK4"1_m/\JqҺY_MAN;M2f 6QfC.64n3,7״l2@^R\2AUR[3/X 1sUpKnXf >AJ"`"$&‘ p|%M *`7VY٣prUG{_ɜ886~mt&_(%*5S :*Eqzf{?0+=-= f-=`a)Pr~aM.F Eln TyIN"YuPuW!ShڹX E[Lg 䶲|Atс{3P4g4K7 myh-r.Сt  R2Z@ _I}Aoj`Yj*}M3ȁ JyJyk3F]L6g}K%v>T;_: 3 h2so!SPc$:3xFY3@#Xx2=;=#o3rٝye￉(rU3N2~X>/H [SLB]1K YzXfe)ϼɇq-/7 m~\)r$?={)i]˟)痃HV/sǼ: ]ۙD1C5&2ߑ7H;'EfWN& zs_gVxO-Kёs;9COl_/Xc-e^t׼ψ⧌7t(q\Wwţiߴp ^bWbe m[SRg7mW9 &knU*ƑW+K˸K `R'W#-?C}{XESj…URW-B a[ۈH/0w1yCxR PVR;'p"rXDzn^g0`(0{+AX MMk)<<<28j^\LҨu>K+*BlPBK0iApZO )n} ¾ S{h0-!B2_Y1o,jׯD* `t *b`RytL[13zyE[2fJ7c^gYRɾo]WZ&]U6s5fkx,Q, Y]TQ>$PFha$&f:"k ,ꯎ`փ:9|?2 lczTy)Y3@7jBOYr˖risW7ڣE a+ "? Ao^u%.cAV^%˗\rOkՍEus-̷).+.Z˴ E}V֕X-[̵K.]˖5l%y׋Y97+\7*0y Fu '[3j(^x*U-oYm؆k)neTQ/|#>]B[:vF|t L_,Byԡ6yi" <ْ"G|Ss#K5T/VZia SO S=gKzkD^x%wd"6s)lMcY['o3-/g?):mǴ-xZ;xJq/i-Ķq"u-N~\2NCxA//#`w zJ~%8{J}8{ÂM*g+R e.[1PA} %yE2*7--=Ij^0f^^D*!n/{'aQUi:zM:c?bݏ\g}¦`O'I>?`G!$i^ߚ"?K) iS ~ɈQ,?(KSCK={Mk?j9: %Ӧ[b,:poluI8ǣY 7XЋT3m{_rnȑiR,pg̩̑u`M0[2 )vv1B4YZT&hY`TcySјxf].[M5 wo5 ``f`U܉ %L5lTS V`*VrPoG)b"i*+m KB]*Ipۨ0U )qf3  {|}hAa^W^k1Ҷ#n(Ե6(A@#(\L- (/ "+{P!Mj\+91 M Jp%NK(il)&XomJ蠁w5Aj1@tƆ[6)̾me7 `jض`bEY%7!9E9E8KVHEE^XeGQ) }᮲ʨEEVBul-6tak1.K$PNYgi<0hr`zA]!c5cR j(X5ZSYH%QRUG1) VLǀ@z <LDMRJ%RfYJMl8PRSQ+PlҀtHc+BK.ހ/ԛwxH7%Eq hUIԱWLcEiIiJW6/ EbBKEbEA8cCDhl4b CsH)AE]+=" jl|S`QjkUwA. 2 D1FqEPs*ЅUU)Ğz+mʴ7nRLpVRZ9Y(,6t5\UR@8t:&IaKvC_:;żnCyjS(!.v7?aO7^ًCppjfTU]#^7sr:U:TBUèe|KyU*ͪ+WbUW_ 1*ϕxEϕF ]s=cOY^j^V3-,}%K޾X~M ?s1pex)VueJTK 7'uhF*@?٣+IX3sʽ/׏̺ .nR< 0՚x Lk8"cy<ʟ%JQFXIw̴n&hM a|r]ȫZSA( zPjIO4rFEbqB3*lZ>#$柙Z ޤbDcA@-ZdjB0i9-- íD ACj1JTCE%;< # ehYNm@Z)[D4m9PFm)wrwΰFVyͼa]D! 2KMl/􊺰Fo>GD%AV5h_)]J ] L#yz.V@IW nF{@V*Vp][P3DYh&$s|OXr Hڥ`s5BcQe!>sXbPXd4{$sVd)K9t6PPYD(%#~dr 6cMDP#` AjDoDGx$5P9RG?3Øڔ7 cԞeAJ*m `V*Q)anTrn@j\A[-CCQ GƂRؕ7H=C@ː -`RUɩ S]FP=.D 5<WRMb!f*5 nwi@/R ?jk(9^=y㖟޾<6^ʮ%J>ҳp7WUǭAmv͜#xW<3P̔ؤkM^ӍYuI3{Yc/e#I} o gu 5fКͲg)R$nCAAwM՗@ҵX.eѺ/0P*`X7h딵c]kB#3e:s .]s"@P݂[- 6 BZ{[iIf4-,:m 4|-lɡ&T 툴6:-x.tc^F8!KޗNL`qD4V3Sb a[h=f/CĞY@b.ًmx%l~!B3IZ 5Y#83W`~7z X5КDlexo7^ǑTh Z`Ŕѧ%XvZyp4Φ %BTf1!>yi7jʹ|P g'3(5-'GV+VeҮm.V+7!AU[ޥ嚺td.G2 >-LR7Af%‚Р&l)آն"[[/\2R7H+AY 9|¯Nς H'Y }j}j}j}j}j}j?֧֧֧ԦCkW>>ҢD ߡ>}9>?D/.^P߬\jvj07Wmzʹ/-vy3mWk2*j*!gBkc׬ Dq?*86L'rdG5]A4 {$% K߬lǔe_>M*J{O#9t}"o+yzJىfZgVw7W|/i"QIJ7j |.&as#n@NXr͘+OH7,7E3ohnh^refind-0.11.4/docs/refind/ambience.png0000664000175000017500000072727513117300645020006 0ustar rodsmithrodsmithPNG  IHDR X' pHYs  tIME -z IDATx͖ܽ:4@f1y73f?HJ*w7u|2E@ I?Tׄ/{dHb !_skq= Ez&WEr+߯xJ0z?́˔ tz$O5P s)TU6?*pxh^կyǷv<#:} uBB@HQ$[n=AŔ HIF ᕒi9r(WUoҲ//u)W}ޙsHkcyQ~1^G' O4+dY^F=k{4"ID 2ߵ,P>>bz6;u탖ozeOnYp"sI͔O6|i>*\u=io9"iYIf7{O ͋m./%CWU| 1j+,>a7`k..}CDWѕ:~EW:m*)[۝lN È-A@$(9̓6slg~H6ǬZL éւ s$<`agMB-nwBT3E46 mbigoQ\OJFR %sw}zCN{Zl!p_t TJc$G_DmPy؎yU;wMޠi~^^豹^ښ]bY߁]:΁8`L4[.+_!O?^[ɂ73W'ۥk4 }:x! mAET,̿_i4I q202wD47~̫δ?gEwL6`(Of8oZ\uq I\Ic2^E͟YsΏqR ˃'RI1rYy6 )YtaWS:lt}!W ݬ0%;b)ƒۦ?ׅCì?Zw: Gs]^$^?fG.x T]% ]x^=(b]KezOej9P9SZjPVI3L`˜w^ȔJǶq3\ $a aIB dKt:̗*b.D4K2Y&'Y.y@L{M(v-Fے~m?{: 6qSn q(5°@#6%b؜{W)t8<_Pㄻx>B!O@YnX.3IA&j?)chbTmz,LLtsp\$ cNs&Klà ,v0 q5zb9j=K`MR!*\[֠CtU᷽j^7o+)Wf9I-%97OPq클cBYZ_<9<̓?>fNEENB 䩪g׻x1nO846zh=}(~i^<ꉭ&Q$%>guR''*RڗKMEZ/P.т(*tJ' qJ§&p?z 부W@kCh3XrA {[h1ZK( 9k[Qpx-G㣷J7q7q爅^m i&dP@eʟ0M0⍢G maO(AGnt 2hhFwdB}`I:߳Vc^+5<*Ӟ sk-)'+>Hf=AŋS#dWTu.å6Or: <oCITħOo3±y%=PiK~A}tJo(T ӡǝs4Y 0V|%,rTuCe\U~SXZ5:w8K M ?]aR.6eEq:+e/4-2h8Oyk䘫ou<*{? ౺AD^ m;V\n@a]\MfK+nUPm7J?K̈́i3ܧ:NJa$ #`l "諈mb$Y޿sEjꇲJ"\M`I;qg\}:Ʀ5;w"wsavtܧ6^J4cT2:딖VCD m;XS<ݭ=YU8 YrPBa2weTPV=$7UUJ.֖"׮Pvnp \0%Y tLa+}faGZEؼIHy*Mu蛛蛽'2rtE߻x]I rCѕ[M㌿C+"7Ag@KmW8o4[p5@~.F0GӶ6}w4c%,I꣤NFOJKaϳFBI5]uNi9mn?D0 7< XV f"rru0vARD9 ˊ䕪)iGׯKNeI$o(o٬!Y D~Zc µS?aW8k.SG(i>ȟ:%y|F/RV9QfvU5~)N+,`H5E:5nѳqdG5 cDfBD 'i_~haf;,sī\)ꗈZkƩu$$04f c^*fo܇ދo>oyWM.rPH;UhVmKߴ $&](dKj aTc-zsM@G 6W/]xc){(i`;'> &VĦv]-Xz{#OqWtKv ]U3S3w|bxf!HGԙ8yOyɩR qtX¥F"k5sqN\LjGas k2kfބi6$~D0u[.,lr'~ Tj{%5+V )i\ I l r:ozz|FXa ͕ k 3XMnzzˆ-Ggw#X8΍bQAN}\8ȏ0 $meM eSYOxd3HIsJ `BjԹAƱ^N2mVذ Zs+<J]O1-8a>!pzڶ8~{3nZ# L *>gZw 5]q'b c ­]vLZ 3h˚>&g]`k ôR,"G( Cq i7ϦΔ7;'o> R{.\r#!Aׄ1>_@3E7G#F<_'EֻICa"3Ν51m m_0RBSRplX տ tzq1Z g3$axH _W)Wᚙ 7 LC1 h y1NSs+GϐކrVG /+WV/8s'dEnA!jKjYĞW`Q762Xd@'wԺkK #er~WDUgg+ĪW2qz$9b\Mf/.waJ.Lozh sz9SPsdGWЬ gX9] 7RUi몴z~:Sk:f&B׌c2^t3*+'Q{pPj<5+!tOe,̙(FRB3^AEp0k~[TI !-:Sll΍OQ K\+S¢oe;U2L X CNaC:[>M"Y?D&I6)ѳ\ ܧyl-2Q>OJ( eZCXZvn7"a8i|i{LokM\yq*9+@*TߥDO@ Na&,hh=Fޙ]^0t=EXF={PRo/+"Z b]~)'DXOZpze:/\V2ٻxoMu8]2)`e! 8~e54 ) oz7i7ŧe#W -f޳ վi_Bu&"x0 +YVijW pQL2pBsE蝹G'?HA4GX|cu潐lW>nLц]mmN IDATMQSP7usvVZSaaQ 7Gts`LV!j+R0Q Qtn-KT&xmtK`=grgW#GWbXJaZC)b½ lh O??[uh[l|T!*l'U{ R(̷@M{Hݹ)j?@0-( ^T 99 -)PWvШK sͼ{C+V+VZДUƝDs%:m)9LɆ*$UJ_Wa#ohek| hV۵@WF\dy5mӛZA:uU oWW:n  $Z*PT:nmD{DrQDu(pU@x P;+`zIEw3<]po]vݱꞯ@[՛:/kyēUDOF߮Ofjw\ CJ'n1kJֲ#jS#E.7_9g|RusrA]gs*g]'N`a ͍) ]Ԟfp68#{P<a77| g2ه*ǟw5fc08L9(`g_p6#Rrhf"gH/J /{>7X#tmќTGb,3>0(u4D(?sN' F* UƸx-nБ-6$*$bfQȬ5:+jQ5SWS==\E+-˿ٛZ[r`FZ41-gb1u9B-fn:, S.Z cؾ(fǏxoc`M3)D#C'Ӷi ,EѴ[NR-5Dt̿N|E(*h>īl@<:SMw"4GAѠ|#}%61u^F~Xlyk ^Hxv񖐣A%(5Wd[X}V5ܨu0U!'|yoe|SMc |'D :+ܝ|P*=i}$_%V/V}q@jNVˬr43׾Rr?Bho}].7O%|nz o;#U_t:pخ۔MoJKv`bCɻQB[Mdؙ.hW3kE5['݈`"IШ!#wZnK],[6*t ^we{ږFLN8@ tdb dZ-L͉"h+սYHWSCz ZM(oթ%4{(`="1=8uhI1}浲wz_u|kgpْ'uj{3N] k̕<)qX;w!7w3fuoӛ(2j0z~qiċ@ mVWVdSUDWBT/lyDQzeR}Gb+;)A Ns~k$1{QS"r|Tk(JG<M#X JT6Y!f+u(Ҏ qy$#=a fȪnDCgg#ӶZBܸɨq55|`0e5>Bxy}YyAFW[ fMa=! ҝT~ԾMŐw/҃!Wz4uŴs9'&=Hbhh GNԞm1B/t%oQ|x !Tqekᖞ]EމeOUS%yn@[eV1Yk4 ,;դa\F`qS fgVPeXUzOcBSFWg@Y137UnkN"3K>(.Sgr-,S,(Ȩon1ǥawkP]Ct6V>uqgG'+@8FWw@Zș)Hpd6 1%٣i; ݤYV2!,#Ȭ>!l8,KL ge7}~+Py:`28q^@'.rQ$# zл1YgpS:$=l :~*\5!xULWѽE߾,A ٩)J5~tEpJ^c&&h+YSeJ[bW3rGv>~>w MNkY1àr7֢&HKUm`ARO(st~ٕ t1כpgiHjs@/qwd<>B(E D <-LNI%NQ6?'kmΫy1qrqM춫T? c>|$k0gIe7c4ꑵx@pL޽̕<[Q K(: Qx,vK^UaMw %z?j-Cg|ɴu&cLM"*L<t|1[EKzncSߙ.i7VRh3]FA`D<+&E kF)2꾣 R*Pg'=+zrh)K 3@N,V ƪo.(Sh7k0W;8ԬE) 8% Q'&,kb -*v_]+!:7/k/M@sL?Dst:Ȯ}Wi-D@Tt%K)_"7D1HuD)ޙibFT#Kc hRyw^̎<bgb9(`BD>ht\b  U1*`LBB izPut8y釳LFZ!-sE%֙1L,sȞ"6WHc SW+4 B}T;۹wUP)p_=E9la\n&ɴѬǀF:C E2@Jx\A4aw@@ $^G.j*C\\F2SàbVt5M7# 2ž6XÊtS-D=1ߊP(6YЦ ٱj!|-+M:m& MxӺ~R HK+r.SoҢ,gSD*ݕJ@o;ǁ@IM ZSkpL -HY?iW]-E '9DW|h~-f mb\"u4.e /$M) n "iA;/֚IĚKa˔f GI<܆Uc6kZ7v>_+*7]iA19?Ra SsuCsLe!-&δuî vb_Qt :2{ w.%iL6-[#!xo48qE@)tC$+\ =ܓZa}ڃ:ѯ0VWInzpj=zĪ*jޠ}>]հ;,Y6,A9 Xg+,GqSٱ??燨`J, 9gŽ:MJMisv*5> IBs jdn1fKvά"G(b;Sjvi8lƾ6`41r;&4&;wUνg ͏zPBsᢧ;FÚ;n ]aOX z"OhY\蒻rb!1{P1{YŜlgAu'M|6aR#^ 6-~ C-k8ӕ+([Vl kZrU7>CWHj($+eіާ2X .:m_PIvԡԐQbTь qr' *xT-huk)/5M9 cmqfQDU jBT?MR.вUֱLOqt8d[tȁ~Z&~;ncW8syKU(IV;msu ߓ$ 0+O!7pJ}&ϩ9:C?,0XW4B/_1z&$J3}3r=!xk4,'_} bmMF Nqy@u]Ն>M\DF>EWkjR RjdAPV}FWo (%!ݯN+a?$u~Jg/toVGVhm(6t#j$4E(V)o1'J*8,NX4lg?#Z4_j{.p @lbĀM83t !1Hf[!0{`rZ`qHid "$Zfyz6Mx 1K ,F7w67xlB/B_WMT6Ӂ Hv]e.͂HD|MkIWLS-zrưAP{{uI%nlMSiEɸG5t?u *a*[ ԕuYVD-hn4`P>{6{\hhZ2*[M99/#Ӻy+Y4. EPE~)h4M4/,jPH{=X2rrn0._|(Dq2w٫8D0z%- p^l̲j3D S.ՔNcNiMq7bևr̯Yef;ת +a3gGW˶!?yOXy"-D*`ᅪ Fx*2`Q64e5bj>yUe *c] /CCY*YI _sQAgP!Dj jܸqGt w-!š %v~*1cՇ}09~ʐ+'N9ZPjgJVͷV?K.4\LQ0/kQtsϽySi[1WivLB%^iEV (*4ΨyQOA$H-SoW¬*^G<aUNLj$5 >X"=:Q]W,1Up26iv0]fxpc=0jMTL`xa/SmqhLo0ƚ!g͗Kotn8!I$!X7]ӻ|.H.+ܷyR>RxnRpᬞ/YqZGO`o)3~[WߋZ(/#RM"g UAa;z_F 5 zEV(7РJNv /Iإ}LQlK,mw/,ԞWN{NReޠ!̇%*gy$Ɗ_~=+:Zy8(˪VOKQ ̧!EY/*cXúѤ Yb;ra]㘦~g:X>lF|1&r%\$m%Ʋ'F 38՝^MCYgZVjq1D$rLISˏo7Vqek'3͚nҟk5zHpDER"ƧyXZkݼMPy/_9FW }VDEaes#$ς,Q]WHȃ}qri&#WWs>b12M sG~ ]4oESev!y8)?EI\p̶w>:$emnt.BŦ[ާ\H(9PsE~g]*BHGw~E&.ƣrXDwqgG-*[x^{,Cj65xb]Jc%Z:e%L, v ٽdo x tq؟yN^]CHM LwP j˾H Pf{To: Q@ښ"1_70o6  AK+Xz}`5RdըuW=˞ ݚ'5X[G^4rp'n!Y~05\ήT癠!0Mネ:G8A: c)ϫPAHjps-=jmW_[x{θ"T F @M"3"/eQ2Sy<Xm;wRP$ kh'vHl%ݽ[I*n"Wa u 20Um8ZM[P VcN#@r-`eh.!̺ =Yz,b8T9XwkN:e%k>si2?Vv,,dF28oBV=|PQY(5Jȁ7O6Ŀ}-=3t&kg'[u)>l$8R>NNrLl|(q) /",wb!}fޖ!2 9z6V{@L >TDbCA,@>4Qy/ϯhn+.(rg2;f)(7+iBVr^W¾sDpU!M|i,;ʑ]U2,[_P'w[  ?R}dU,j궐gUOwWyIzX{9&z9!Q \Qo0ExwXљ_={Uǔp!NOCUxBX@O.4{8'[TuLڠs,pUV_Ж" vk2H BνG">{X(U-&R Kï;1J.™" CfjںYz'j9v(f3v. ]tꂸA+mRG'vx`Ϋl4@eoo1{Sٳ}KG{IZ>* Tot&ڌXE祋fK!eaӀ^%1U=k_qWfV?jtD"h=L KߔWڈpK/8zރJ hKoia,Rmi=:M=_ kF*A%T|q۴T|3B)%VOZZ,wΞkȽd lm dy 73y\y3ּ͢c֋ccNTЭUt[v k=ӱ =ikӋ{*7D,Ŧۨ5&)TXəśHg/.d?:΋Tw^EPf}(OO= ;6ׄ4o^*XyE3+8kIiZ6hL[+i;|v=$d)Va }MƮtJ$Υ>QaBZ$USES&4(^Mz7±fe`\ Edai.ÔU51e!B0uVB8y6!|gk`![̦5^d1̷Q]r==2f1#F.ʴ"Y.FW2z+mAl#z^״LL 6%.AZ(ɪ6@ Fq 6â< T>iA G/Y>[YoR7pV zb&vG_CXougw} P5 "ImQշ|[`G>Mn(8j(5I#$Ũ <`^3~5)v(sj:0>_*xxQdO 7{ȉT?FWםwF˵D0礉qMPrۛqsu~T$: 1$+1P<]-Ha gcǢaIP=rһhfWL*]:Zk%!/rp[3c"#J++ˆS<θl}=@m8X}I R U>z^$ 0uU]qlF֍}ajECvI2G̷ʭekN4ܿʊF6E7GQtD1b1]g^0PopWv& "gkw\_[RK- ?3QS\N8v9[*0DZnkW{U9#fTohQmuUGZMlr#ܺEJ;/5S4aWih됒 Wu=RQikDkvDt1Uʯ _?[,`4^Zοb 'ȝ,> z|EG#gzQQY}Тfr1aUGXejƱY)b,WO7z(b 2,XeEmP]#$z챫;-n̶̋X_ F7G˦/g=U]kT|@|"E5owW  WVYXN" 7,԰Cmz3\*FY4%MSb/ poG4J'Ue#Cvٌ*Y! ʼD{S fWZڈz4yWXm'Pێہ64@X:5?4>Lr\HLbԫ^=nRjm43șLY0r!kg "Zc^?$XW_Ԩ Uq]Ro|oEƐ B2z-XdjTQ9``l s>1gP'lus^b/30-yĞ4ؼL~9*L`BJ7V>{_4>^[^|D~\/3RȿRț+WNk`.D"aJ NMqBa٧B׃%%s>=~ƩKLBFk8JNUoj;=s-`a 啩%sBS"ۜ#jT(aƖbf)nĆkv64q>FTAX"X m^irYт chY ֹ qt)k2MgiVRuGl(]gAàCZ:xsT)z]uϟ+:Mi\Gn>`EQ o'\Մ̳G## ކQ:!BbKJIoJ\h7pN`q&j|OTz$OKL;678aC!ǸgބkZ+SƿVܭ=KY\ >kt%2VA]2y[-RN.ch:Èa}j/Ruonplߴ!x觴M703J yX6D.K7(ľ5<˪ZRKNx%|N:(󯧤:i6 !|_oy=!/%օxCt+fwj+ 1=(i}V~؈ +-2##hZ^`Ё:⍓d~]AP /I-;R 5Mx'j* KJڸ<EWy36*C2=:-CCz]yѣT}B!DW6! 8N+nXAw&7E JDnUuT{s/7A?&NnpI9nGN4%q|г"f[t!ħ}HHEhR'(r^ x[n]2NAanʱhÁqo^xI K}Uui45~" ) 6Mʊb僳zx9B'^kYXJd(p?8яn߆x1߽`ؐ뻧O?iυY78cX{ӆb9̢koF],n ^RVN|c4ƻ =,(3=J ғSNd_&HaU~$"zsK]UXCmIy7(4VO4JA{ËĢ+J[gŌ UEWH {{9J_}(q[=eⰭ,j;syKdQ1w8ytN7դ6g^M5 <U:ފ fBl+7 /lZg|/TۜO'$xLAD]0{V.*&~@Sy}UD=n6v'פd5h+' ak穏B?ʪV0RӤS,'`nͩJjuV.Fui0e\ 8;Fֵp_iϜ3iM݄݊I͂V1+Qњg)WF3uKjp=,V #_. y1bVp{)9Cuc|eJY3\+G>EPiS:c[3E/ձ2HK5ҕe=&U~.4ݍ٘XO*)y0#W ?6anUK8 TE8 UR$M囼dtÓ7{T=a]b\Y/ HMz^[dq!}o:xN'ce79b0W@kO[C͢с(hjٚb PX 0ܖ,e:3+OW$JGA 6~+_):7Vtqƥ`o:tS)=u'$CŔk7u?]鲙Ü"u4~|6pwq4TN[-r96i$ ,<"tBT.Љc,^FKN>5hDI( Mڂ4~4=}Yn*,]{jH̎._ z.$$v"ϐz+z/'ITVVꝸ@c԰d%{nTVKeS?q^UOT*yàW:h$8Eyy \<]EșG%8[\+]W\yE0LdKPs󱔜۪HKQ6Hb:-DFqj.b޵3ûDWgg~C5HՙGWo&yJJ83ҩP31bQZڅh5Dio`Y*1N_RViۅ"Ke)EXc04 &&۔ &MV +vaV]44>PIӫ861̈́>ڈI+xLk u8{O#ViUPDӸϧ@d%|;=ΕfD{S 'c2*)yR 29l ؕ\I֓SiI+bd _huA#{eKM,zkm|W:}b2DԲ'D G'̞p3CIߌPXVU?ݘ37ā͟*!d$n*áVHS*UJnlcmN%Ҁi1V[DwO|4*Xe ߎo2cYSGS~e@O%Ms ]Y]{sWJߧWoc QHj+L]jkffCFg%G2GMs4ܑ 9zN.ݨ IDATh3_bvEӾq˔NK$yk݅FYETBro<}㑟J6|_ˏԠ0^c@i! kk x=T#vj!l3b\6)[L()ck*h$vN{|цꄱ ( GWί9V/X*VEj$Ԣ~};zo7{iִ昧,knm\7!F z-YeiҞ&?/Z)7:?*3қ`?j=jE2ysϥJPQ:/];'] f'^_]`"J&P[@)q4T'3ε ('wi]:4*1Eat%pke= 4>fe4 rAՀd4H ^*ԽJXOuj66[[+txz/sM -i.w2~t[ ~+J7j6TC9;r1(thMA D"qm1uiH)NF?2woeaB_ͩ4[(ȅ놔W,^ v 1K5 V[@$;խꍞԧ(5!P4Z1 %[Hy9Gm&ۆtzؾayLdLCΉz)xv$h^eBd;= kBf*':ڤ툮cMHڎ8T> o6/lOL'p.햟cʹ@h5g.yS\azM0\KtSqpHuw`iHyQI|K A c{&&O{zQp+^g5: s*k5-PT LͤPU$PKu]J{> ;Y _/NCRbԓZcU q o}k Dw%&CW 4mt-kW8xn߷9o?b5^7zNHko=,s4QV&(p{`W a^NVpY[psَ-]/qllG[K*v@hT=("} 虳,帟P/6OZm64^!pf e.kO4;#@H! >)FO+*h 3a q\֮[7;kb`. !qc$YS iH=]v6atQqw?>Eo@0^Z+z'Iifҥ7[E6,+gT͒~ 2d-vEM{~1F;;Uì[$ڽaZ?摜)JG.$$)T'hkj*4#FW k=e#XB湔)=tkIUjl(kkafۤm>>9E_f1H{%W Px j3NJk'ǫ<^ c1g]GUjryRd# c~k];B\衬}*hd#3-6kruޛ<<3LEjEvz$d{6:ȷB!6x,>|y1t/Ա DU]*s2uwvB=<xgvhmuvj]ųesTy=DPa:8uBQ߄A-}n%$F>JGAsŋ6=ܝB῏ը."K =E~Lj$UX&zG w ܖ%2T ʝ-r çdex§);Cu_P8&b(/>Yڹa\{ Ǐm>o'̭=ip S\(gDaX?35*W^M/\}ƛnI 77fy!Bߒp ޶"w>HI.roѡ" n p*[=ьn@~)( ]Wi`~9=vy[x=Y#* A 9ei]Wݜ:^E3ւn}>p0[$ X w^'覞1Z5Ǔ5ji@hព.Df} SnR.q7(JՔHɂڬK#i"=5SuCa1q|+Umm/$S{Vr4[o~5@yB7*v2' D=1D-(Ym1G&>;'!&|" T-5yZ|(wY )׭;7M #u炥>GW;!hf)Q' 9 >3h77=EL$:m[L{b 0^Mphf:6S (~m :kB-c;:pA|n*M5mF9|jHPu4ݺdZzHpٚƔo5ܠω,J7&.|Q;^-QX73mg[=d 4(AUQ\}G!a>+g~O=m`$ۘȯpm"=o'|3=LyA'e ެr~;`E7e?H z eE{%Y*ÄIp1 K:K<7,~?>e',\rcifȋI^_ܣ/f9Y MG7w.gSZr(oQ&6WK|VjK c؇ǖ`lay)y!{8A.=;咙$~]1aۍ['ly8xxh׮Gr24yvg1VCJ"*Td_Q[/W'V"J.띻G^v] U$r,%U^熬Qt.P& M[0j]j$QNx)%&D]w%ʎk:e 76zL3 MhSCe۠w"z1'ꍨv0'hH^Lͦ~=$;ٻ#0gߺMĥ['k{U_%N]ڂmU}l bعnyjLFw$➚Gyb||ۥ^p|p[gy o-w  i:ͨu5Da%mS!>2]euL\툡miB8F﨣z4<^qeOy 0WΪ YZ%P ;K6pwb ;& t-М p RCA2^m٣aE@jaP%!+t4%=%T1-?R7_`T=?vh^(PCZѿ3g/u,h(3k (1-{aÛ]]吮ʪ~Z ]gjo xQ2~e˿.wLxTܢ# {p;e>±nHٹ~s0u_`iJ3\G{3S7A/ >t8!M?^/X֍L䕂] w Lwûfob8Mݵ+"t&ƞ [Mn@i|?ˍi}ϞG8=S;IG f7.jB ]@1L}_0C.l\-d.ˑNѯNtST\<||KqzqBTӖljOKhrs}ei;f" UApqjY>ޡrs|#Գg)No2#,/e"PF]I. R4p=sRݫn4nhuGNa"l'Giu#4!/>Qcٹ7hVU,C;Pyc캡d•/VW~0NO!k𰏮]f(&j h:# ZuI|[˰wfbY;)8`Qruk"JU; bQHW==Kg9j?Y>,Z%z=3DgVHlKLt 6(a([{2H3.BV{i=`= =MIw=6D#Go2.cw`DL5'{I#־^v伸͎؎yDI79 _x ޱŽ0 J 4sø@2*_O { )/bq{,46ۭ@7QR9}IU{8v7r+~r~q>F'ˏ5slqIyujeg#{a4tnp}Y$i;0̺utR>p 3HM9|(p&>%P}?&[ oK*K ~Ǖ5.FYr! '!ĵ^qє9*fog3jJc7,p].~ ozABM @esl?wseG {anķB4GБ0ml4HKPD+>fR.)'?%yu[(b/z0z{Xٱ}9h[Fr9>sT4>Kw@5 um5a^9NNc}v]lRFB_?EO:kt1 x VB &p)2wU3 akٺ/Z.f(aȼ|{M2\,yg▇:8[p%Q1Yt j?/wṽ9'uk&eځxN6.b"8ʟ#*Ω8e3yvXv2ɤ9DR̺+J嚥 8$iD 6n'9v#©A!/AU Vw]-,=a¯& lޡf']fs/eQxOߐIE8R8,fZh4iqOECh 5ڀj ~î0Cxp=՚cV_]Lɷ20/*F%[j˩kH 1\ Kh`#@*u6 8S0?XF7aTHk4D^V yW(ZNo#>x\  1w0ۨvSQFN(PB_Ҽ.TĂm‹i/VV&f|2/㞋t~":$` )UJOZpxxgDLp<~0" X&wn`DE&?á{HjDĈHƉsT[,g`1g@ =:"-ܺspE("5m0#3FU+5,1&J AƏpFQg*UW61CEV[[1HsGLP.G0GbU/S&'+̔#-@31a"%ľ*b/QoTGX_kNIqp42c 1s`#_xY<^6\&kqK\b~lsNsK ԇaX z'gWNwZ8*eI4|4VwD*Tqr3-J6;O| q;#E!,?`%fFtp2(JMÅ.T3Z}G9.M )X8pF 5?“s*g~qq["rc\V-~= $e0d,Zʍn:w}6\(iBa;ڋBh٤EH2SEGbwxܺe>EzhP%T2'7 U >RĬ/uKe %7hmh$y A3eIo?bf?# Z퀚#,щRgucAuU41{6+"kYB `!/\wwK" ƾ7j[e+f#5x]*"02'?0;5J[?OE*Zl@ zIc7v wGYqwGAN,Ӗ W;uUFr|0׈y8OJﶓBlC'p_PυA}|.K`{c_ۊ ~H.R:'lWWSN.L %-ÊAlC/UHUZ+QX/,!sw&^7`w٭qoB|dY tɻZyu="6پ*g:=ˉ]kn>= "r^_/8qRA5 "DD,؏p'k58xzp%cʔVPPpR#uJ˄%" :lfC3i%MAα"8Y:&|/0Y3^@`8\kЋ)(n1ژ)-- {G['5)ucT8Kj2=ǰ&6h`]fD7дC0'!,oťɰ&/lp=TX:1G< *~:ZMQB Q$4N4SvFly +TF ̸I탲<[t}~Rɘ窤5s#aqXj̀]zjck~g{dc Y=uBp0 a356n<_tIU pCQT!"}$ rϒs0Tݽܰ8Rw.5RG0,j߆N ;^w6=g/OAVqa'ө"NFfJs3 '*JRA̴Ƨ 3k&@d]WR&-ԡD=zOZ,HWHF})*uEKBAFH'  p^=Vxff^Az6XaRh+8ƲdVJ*[t {@/jbDWB-SPZMΔz^ŲuÙ6zFXJI4I8p/J{|3+R(Vh[ĞQvxJ 6J"#~N8 L w&W/peVY78Is;/qLMF5c#@ݢPg0[ QIVwa.0R,PMeX*MGZMyo{6a W&l0N!nYq K&T0Cj"Q"W| yhP9,Q@nRޡ@nb* 7` |0 vx|c{մى1-rxCFvzeQvj-8z~=VhPHr1X) p 3E7e8M٦Pb)p rnϢ h#4?\q g!QoM+C‰ v=΄~&XɃ}saDʽ鏆!"]F9(<$}O9k_s$]sC>~[ mRJdzTbnWՇMvĬCXpҝqz}H N.A +ۦ> 32Bdib k/jaW+uf# q< )--㪂q|Dq1(^ON>Vj Mb>U+{a5'-0ac k2.{,OP*AWNS0Dx  G܆7$iQ);mZWm:u ξ}I٫!٥Ѝ( MQBɺGUJfJ/n..p;ʸ'R˚"{OѣP ,-{]y Yf 3 bܠ{[~7E: W$y.Aae- +eÕP5LfMUzލZbRQ<,T{T5!f%7; 20תb^磫"ҊK +5F3/FvI/R/N-n40~Qn|'@cB UPzc'!XA3Wq#_(zd!d[ORv ;fS^?P)K )(%ȿI]< VǙO!x06*\LV\ aGLeG Y mQBh2Qu&E~1ߩzfNdmW>Xw^12g~5OXR c0 d|Le"fRLL,oKc)Yd8Jki1jI=v(^Wm819:xCfYdyi!pco &aF/ru;S-A .mTNWdj&c5KZxۇx.XOh5Xds]?3fnT0+~y#.Xrؙ>|Z^?,#7N !c\~,a\vcȔb bͼ!jS$>*WT ! (PO#e-;WӜBsdb 7!|.!޸;龏y},W(ΊÙs ]}$rtn~ِ ֊q1lW>6zv)!?6HrУz#2˨P)&s<= j. R774Vt]Հ?4};bՌ :L`ao$M)_Z >~%pSW (Kg u& ?J2pVsO X*~٪28('kU5{Y]$">Ż"OЙC< *tp9$cZM{#^Roq!+ ".:qafq?EFIŘ,Z{`df"AL@FGź"t2uL$u%Gl`0y)M}vZviBzH@wgbү6Na[Yc#F  8C{!/ 4E(FBL#W99YwEÃ4=.` Us q!7=`]Dlhq}irg&nuEmhwt䄥)>gc1Fy;pC Wdw-NLytl_D*Ĝ őMMsK냜 t*}!`Y  'sд|wPI:_ȇW ;&r\Sȇ0rְ56Qя+ `T|@~G@Z;Rb9jw@l*PE4ͭy葛eax rq-@_A|J{g'ty3n2 4ZOBF˥ٍ;$GB`\(`> ^9u ٪5#8L(S2=7g+D!M?N5 0C،C?'q.4Ҳˤ>iD`GbuK\]B ˢ!4(:}c/[$ihI*1p6$+MW ~o]E2;߮~6)j\2x\X2, @7_:7|(wmf('Sd;d{TY@آfs UZ6)DSoB8,"[:so4}OS;L-Ϧ%44;!ʐ[$ǢW_7o"xxZ; XW)A4zq4cyb,:P|% PnBE>aD񽹨+k'z d/^U!?;]ffAgױ*G(IWٙ!uG>vs!j=1W4o8_1מANh= ُ&CSM*V) am'x/X(I6G;lj)"?e)Y/nVNE!ē^֕'HIsuv|uIOmLѝ!0timN4CMwM?ec#i$ޘ= ܗ#!2 ^LTV#"9`\gwrZ.j=~GdKTsOy"+kH̒b1w ȢBˌX8Sg J+Dq!]wt#1ѫg>#$D~2AT\2p3j1(QfG,YD +H&Vy]=ae [Gg!+/XM4mIC0k S bc9\^Ӝ>E`gZΫ̗#;% GvP +(scX0.7lMSD6yT&k̍wTʚ)QGdjT20i~[,Cnxk[TZ=\HҠt mam#gknnT@`&i% %[A:!~?3]Wq$"b]z867:jzVm\RM qѝn-U4Wde5B;כٳׁ{/soMǮ#4Ssjbl%d6H+s'")ȉ-qe~IdRU1獕:aoDJ!9 f!+]V r Eq7zGrA#0S :]9AgZ3z T{oW i+ӠN32'|e'%9g%5)0giF1n Z)l ;t q!prO9/ս*) v/vx YB`$?U\LАtA*z+>l'SԸR_m`1uXZru`k.M>xVI 3#Ē |A4蟥H܎s#]]ޠ.iŹTFpeZ0:F $-@~3+*"*$*SkF32Т t8nSBKj&X]-Ǎ\DLKB6/y F.΄q>:)Xf#Bk>bVoLH*_Aʺtl) ex%r0'|I#^G$g <dkEH>i:Wo?UoTٯxML> @JN0o}vnVX`]@K_Қ v[Ů?M:qL>bż(#fUْodmt4U_iqAhq{]1PnQ,>,񴻀bc"AހA[Td(m E-x::Ј|zSo X teoJuO9I|,-%^/+Olʯț`KPaz`g7|,ʮU:&V<5,pPU!J5Nz6bVXVƬBm筴eiKӄM&ʈjދPEMF@?q/D׀OX<-ʹץ-#_>P/ Í9lx4?(X6AD5E.R9z#< ņ,mVz~;ƳL<8Ώp%p j{R`?Vi {.Ԩۀ~_ҺzqI͌gBo{-ErXq4_FN{$yOZmpRd{|3+V2}"]rߍ!CrnQBX>Wѕ/zt%N6.\I2/PИ!"^I!ptz\EO{$4+E޽Lro#kՃK)twooչkX:TM4`V' : n;"m1;3Q-WHI84OuUTK3+7:R׬w2h2b(Bxy;~5>9m ϶%!F} 1slpEi0GT UjQ\$QypB WG֗ڗ*>5s@jbyAVET0{pƟ̅m=180֤$NI1 *a |3Rla=0I9fd}]PFܰǠK` #W| Z\υ6vsp#|u ?H^}|y_luY!f4_ű(ߛ#ƚO?'6* tz ]'?@?;VXXhl"c"ΘRc]VWWwb vE 6`Efנ,C\#Ѷٟ d>0a"_1M>$XLi{\$?Q'J֛NB5D$ z5[+d>'];U_hmZCkz{ڏJK#5ZLн;ؚmU`Vo`W,`3g"gY{_m%p٨_.[JcuS.tec)V|Z(~֑!}-|q>rCB-UGobc:Lv?z<7SV ՚Dڡ&X;d{hPi +.n|~$m~J{bAʒIN_[^^m2]ApfҎ1JX.zj+"V+k~ek{ j!%!;G<DaAt` SY.S?3i,n-ۏft C4r DNȄԀ1֤0m^sc{]i: SJ w;v4j 7Dզtctzb@}s;~dsqxQo 7LeCݙ\8mTbϙ j[^MP2 L+0k/=q;sJxOʇ-xco`4E`_E(#'/ 36UO3G %+c+&%šwK,d12kg%Yg*!$~pY`7.,!=uGK`O% uh8Ak, HY9 r~k-\2Ɗv_'a ArZP!6Kb<۾U8egFXshp't9I!ㅢ(HbDj="3>Fu$oRXm~G?Wcpp2K^jF@v5V4c'>Rw w^Y۪XUΏ-WݟC yëG".YT& jvrԂ?@g=(^^~ݩm77$TkcAyު `[ea.{ ;BI]O2%OqVZtp%sy=7xzf[ ~"„@؝gi\-BE_'9 ż7C/ch1]MPZf{BK,a+x$Dle1AS;x ozD*#cSi瀭/p|f1/V)V3뼖?}G'oocZ*F,N t)0jQ#d1slMEDҵY'̰X8!zB66nx{31M~I#-7f@lMŁ'1i.R LfVo'`=1Vt#3a7$Eӡ坡wp]-o"q{^ Y]KQW\YG%^wYs ְ[ycpˠH=f+^/3C| ut OP^ hۮw$KӳO1o˧Qǭ7"J$XwVzFv0B'.5q&D3x}z,"9Dϳz3#%xn|ū!oip@ܮ'FDvIwD$=zHBD|xzyÈ7dTO lT7(ɒzXC;/owݨR?g<8Y|v5j<ςu=%ܣGk9@qc ^1i8Tr ¦ȯ>lN/5Jo%⽿'*9^p1 ~/n~z=[a֧%LOڵa8A4uo?( ʼSa0NC{<ܙB:6Bۧy^LzR)?1F5AX̺zV޲B%@N |S^P58/l &yq0lI_{18UN֯ Rvn5[|.~ޯwxWP FQs6=AT#*+H{n2Hkr؞ϐ޽HQcaMcM.h*4zMAEu@6RHebētur Boׄiu9Ϯ";ɝv#!4t'd Npߒ-h'.1W~+wWA,J*i'EvZQ49 FQR1ItkEBPCt͵ XhJe6ɝڥV8-8q;]6.tzEe)dME̴% 1o(_Gɜ)rh*PTpETBnlI[V[V<_%~ۜ#nR-J=qΈ«"X^E1*md:YzF..cDGGխЅr|u#!@չJ*k* Gci:Nh!jQz]՝d֯U ks%h0OC10')?oaX~qh/QE8( MjmEY񞆝9DjpYv+YHr&HW%p|Ɓ>.[d0Kp zN d]FW; J7?Pi%OV꼃7{dy_̫/= XA}⿒x8vj cVt\/֜maA-+t:Xw}/K9yQZ^iZyywBbSO 泜jLW9)1\G ?pS!PŭU_]l/RS> c0sC ,u@#6;0^t(`J'{x2 *s#䙅>8uS.:aFl,Նkecэj JUI`t.)h7M,Ɯ,KZ@87H {v%I!Y!%@FEb|/=kqZo3qhvbc5gͲCCgD/wLɄnZPK'q+  # 4#-VCأП&+fvogrGbpLo4H,Tx΃jR+F&nD7Ol(T(WK_ bj*=E^hR參4erKf&{`ە!f-jX5ew;(d3=pUkA<fCE^Iv=!7eџDW`L Gn' 僣O8L@vv])Չ5@4 FcLdf+y8ȍ{5y8 7s=o;3q83,Ƒ%20X侒%g0ٝ,vGVNJN@P Jo/*,s[hx*w2+(˺6S7eI>!Ѐm00Ɛ e@]պ㘄a35(N,zϏӼ~uHiCT-Rsjrĭcg*2zpCzwc B.ۼPyS s~- {q i&jVmXȇ%~r>Ϣ4Zk2sE~"-g,b&E +w/?V_Yvo;*t8hF?YWh"|ځ4u.//F=)acC(? ZCXb]wd MbUkQwLsR*j]VqH[A0HqT-ja}]W̡?Y00Ѹ{\Gd&DŮ&!`Q7ؽ_ޏ/h s~q`wUZFւ1^ndXi n;3${MgAЕJq!g?Ļ*\Z'YPȻE@s!aEu xGj3!~O v0( rVh*/K[ Fvx %Zc#VrKeN<ƙW݅N5 K2\~b,q=b,"QŬ/MsvM5ǧYU7J0ZuNEm#OS՛߰Ya`upz*9t)?m/{/W'?> J{_37:A 1̉`r\B}vR`8%qL],Վ2v{j|{7 W0>%ALR= 8WUa nWc*hB[+{V{;,=Q rxaos;9=S覯 h&օ IDAT=h勄* %ԇ^ֲ@ATuŸ]G^Fjc/kh2zZt$V?Xh [8{Wˏ |QV0x}-,..pk7aV+㤻tYuהz# ݵ»TP;BA|#,HFuܜp5J=@or׊/:}F *! 'P$!Tqu5bTfb;>Ӕ@Я/ݾ?KW by)cqah y)92ԋ fBP -wTt4oX>-{9 ȋ ;CѩpHK`,?S薥 @+U~Jla)9+z|z;yqNnNL8kIP4j%9xҰ75/j fX>*Sk+c{m(qNAQ{ܪdu8ԔP\eMPٴZbj+a/aERF+u{Y$ mîat^ӱ$Ya+s޴{!w.)=&OBkjzJ ꝖBe0d%Uwr'=<-SYvW) 3z70Aɍ{EB Pb Vv讋 sFύœnYWN^։:\R1sKfY.H&L0-[j 'Q}3Z9B ._nb,hKln=EzmvaClevWZƒa㋪cE6㱹8)i@ѕD";_py$vftA|A|~H(z}䋯:u 9XE_0_2;Ztx FYá }^5XWjRmES Ϳ lyLnw͐\+uף(2:cTgc<|Eճ&l] M0i~_urlnЧ 36ӱ܀Wpu|"4kCJv6Ąt17I<. WKo,Pu-%Ob̛~`zNm@L  e / e냚}mJFS0ㆷ ^W6ǁ~-HN% | XG}q4Xr$:e;^R`J G٬њ;]g\Pa/__" K ;<:NxN7k2y`Ci>~)mxwʡ2LEův5آ@A1S]/_B4c̠ 9U4wzJ,.b)j; ܝivft@a53APR6*rMY)KTi3.Gp, Og^; G%q|cd.jF?( ZkJEUtHb;K|lb~遽XGf^]*e#(IpѬh/mҢnLi]q нʥ]Ev*ߠw^ Ya3=³q2aD]G` $'Bai+b[_Tߵ}(ܻoMik҇XkX3-7݂!ݭ~'hQ#jyk0}Q^9__tخ káAf|vV1X2{rFv`Q2,4#&{lO{ueYw+)|5%_}2Mx=EN 7H ɬy^d. s@=0Ԛu!T Ek@L*V0fS^H/[>]7gup!su\7I'a݄ _;b1e. "*`Xaj_E*eO@m^}JUӠbKtЇgEgƧ y~󶬃Cvch`^a5J׻i5awvmWX겨 B%_`ܷYi5sYbci'2YV<"x _UyV?fS}_ޞ͓Liq@;<7%u| (B௭Y14΋=s” 6m -a]e|<͈|gڧ(tc嬢9awX,iJS**H&3ӴPV˾U!yv mgH}sm.WA硔8x?lZkzjGoImq6sP(/=;UxZYk uqDJTv.u1K6<+J}-A3CF#!*x`i_xl?]}05ڋs`J%0s)>& 뀨9-ZSU``n:,u4n-Eq¼s#>FRD zC 8CZ/t&?m2 N^||Vetk&x{C8*(a X"`0g8:@L຾JSv4yԘ IC~`=vժ8W-4aMWIqn__Rp`=%kU ߴ 'Z-MJlȆb21>bv'r%<}pitJz_0 /!8y _Ns Sʳ)}ʂ>H?R b6 ~ʬZה`6`ǹ$s@wNڌ+ 9ܘ?/qkPCYY RS>'\QU`] EN ,lH(hКQ/i v;2a+9*G<ʊ*9<㷫#P,b3Ȣ+)ֽx:&ƫ(p- COixZdqJ -q+R ̩_qL3,sĐTZ;!A_-"KIe\)&۬vDx%næMΔUL2dCP WI0DmvISAtMu͒-A=WtSVδnnkS0~BdhCRD؝ꉤon;w/JTS3r=L2` ?X0'hA ]M"-6sTʰTDs n[pQPِB4NگJnAZl^e?>|D$s~ҦcbGH !Hvᣁ ﵸu#:p\*yzɦw;]rLKOt`怡( qf0,ZW@) &|Zd`ebA]6P;{nrn2j17Yjb"Ԗ5՚3OD6qjY4'hCbCɩ>KmmjY.;W=u0+^-Q3S)[Xеԇ=$nEج2"TtoKQ $*9mtMu ɀ[13 ,\@j)Nyʖ͌!+ -?F+ؕ u@V%! __1*}_ #|KB 28z*:lgU%=b{?!Alsw 1QԽFNȡ N–}ȭHo5hѸ>#hF۴pz_N<Ӯ&d8& )P!4+TyY"He [Afrse1cK9tIr8[-ΰG 36Q{"Um 72`$E8ʗgad%o]m7CV:̈́pHJv≗,mXޛkM*V;[InW pt4 svV\^j"8c5/E]19MnLe^8LnJ'LP+E X jx6=<%(f-}L=J?W ժ=ñ(wNX"yf-[W@_Ra5>1ma+ nlU+.uRN6H~8Nޕ0d7n1VbcA![ 6M TV,W7^"Ob,Bsxz\tS㾆:_,&}{֎,r2 LVw?G3&ix(}vSOʼne7njg_\@q>=7vr [ǂ f =8&d?h@D$WNVH4Du<4Kk0 Yםg6'5mjf{ϗ WϐL$`nqOiǵG۱P sdO#NĥN$TGi $'j0ː k/2I+vxLbe t؊h*ŧ%.,MSllYc2JaoK 4ƺyc_Թ {'ҡ0a΁aX[+\.]cRr)5^# :.Q8|U[BlAW*i޿>D'|$qi>e K䬲^l9.PGQBaj6i1 ~,w[ ~](.fG`}G?c菬<:oѢ'0,AQ@t8a 6C IDAT=BȅjP(% TV!3;>16~u{ |{jؾ dJ0x֡];c\QṑP}E]<ٺ /m+~G rr V9.A xEh%>EOwgU3)\(z}cnU7fB$aGM)a\֣iљ˝H)m&ՌeMQ QM%W, |]RM })zE-y)F1neR]p|ʵԽ%^ J-s),&c8 A\@)!A+Xn yЅqRR7=p ^9?X_Kk4.wca %4luEjk(o"=S~V_P`@g~:sm0x+L|koȅN[D?0N)X7BӅA2P"&Dq؇Jb*^d=5toˎUww$QRKJt|gnbQ a7ep]ޟa+n@iOIDXV̩PAgݠH+yq󇂠hǪZ,{FG10AErt6Ndcx1VMDDiWWk\x?pB'@!~Y5. 6ARnjȔ[vCu  چySHC2[D߉Cf=yQDLx(PsTc?Vv`O,'y33f.jdb&Y› ]-X@'-ͤ3]弩}떎*Ԭ8ir_}\ 9Zpy [ey4&a!VL JZ[N]_)[0p憿!QAVZpxG)A&mt e #Xݼ;P,ecwfeubFX*"4akDkkٺ&+ѓ"lP=,F3uBsV5bAPtLJʽ/,1i_ܔaDXYfL R!?޽d>$<{L;fS+sP>sD00)JAƠH,.h٤R"dwt(jn<욬F5vh  .On]j`͎x aв0p@{!i8< bymy@l¹\r]K$*[}d_G]cU a2x%ìgtHI\SN(B7 H &-_ N I#KY U B+֭*&]0&>H})?%m|mpBzN.5D ߪ/o+yE3Wp3_M XRg rFy,30(zZʿur\{Bv_5ZG[E($Zih5<*`H O ;>1U*OQ4/U"ѭ -<難: b3U'Z+37{mqDYigtON6=A ɻ|o۱b5pee}cD.m/Gaylٌg g>99,R`Y.'ƣAkÐjLnxgV̺boľ"πҽ/= Zrͭ%<\X#+s9~£u%?r_6TGzIѵE )\Zwʢw ?>Tw&$"=hKGyX#[Sy9I-Lс #"nC~PekoL'8q4z[6avz!NGr*2Q〷pӀFjk t'jYZ#}ByCA+ҾW-Yi4bhҌ4/aPDpVpMVڙHe efucq!#퀚8ɻydRƲ8= n<¥tjzdZ!j4CuBoѕݳqn\2׶עUJQ+;Jc"/rskAZ2(z"}v3r Ҍ2R<0#Q,&HPT?Po箍f9aq$8 2A4lUMx(5`>݁o"~ UiD`h%J mY:5q#q: .v8reΞțN&605nKS+|DPbVbsCgRI wc1(V>հ:d/0 "?.'ԣi}qKKsWr%1بJ݌uO7a9r rҲ3;~,ux!X'.S>oo ګ{{)^3 [/ZjWI tdf|CgZ qr#B lS*ʁPV#O0 _W"iwrDINzb+dJ ?^|ѳf?d06w"rzU1ϑ܄J e[99ҍIFSh>z ]hOCu` (Wqʾ<%?QݳH7cUBZ=@| %n^B448??ܷ)F˸F :=}Yo,3$fWxQiҡcU?JD.v%4ck냞] 5+Q!D_ɲwߡ2[vf?.us3p E|fi}MB/A E'<,%aMfnic^}{Cl)cTPz j!2Lڂ0L9r|uƘ_&idCւ1ؚFL/㝂{}*hҙbΔKOIPb5?k /eVd)v՛3`D|zJ;< [E|E[k,&j~]$_sySbJ\`c472_/7 !a:\QIۉh[{Bk|I< f]XnLl:6 W.j`:tl;*5CdVlft֔U %eMS$FMc]c_gSY1d:q"Pds lTS[R#| ҊL]fjJL*y7ON54ۇhb0BaokYJZk?ĺЂaU00LA^B&-?pn:fJIwx~we)u#YyiqKx$P 7Tߘ}KZRs9%'#2f3$eΪhf]e/\18ye",˸`[ 4h:SatPkINz>`LB6WE؜+|~7Y ؍Ws?$ !?[R|'SkVGb-;t?j hh&7 29JSHr#PKD`eF{K"Weh\ܸVwr'䬾{_M5UQhD8Y~O^`͆aGE k}BF8N- 7>1LoӖՄYΞЊgtx?竰lZ4^aK5.s. ?>hɥ:v3ݜ RM7'DMYϔC|< $-jx:wQ]g}Ye61e5cdz4%{j_vpz`npߋFDe&Ejv5QAT[Tnh0ʊ^bSǮO>BK-PzgǸEg e8 )ԗ [([db Aa^ZyBŎE82=M.Կqh碨5wb. rNo?SWfтkl;ݣΔ_הX:7]k*;TX2oip!e$ .SSCm f}ZBJq]aYpL/1܅!r[f ߼,z@;7ZǤfvtk$ɠ^OU< K}~oUX{`)ζl`o<mznQF”XT5bBF7S~W'P[*_2t$1 3z]2gvK(DЭ98x,[}mY^Wf*.IzÙ1{k~"f2 8ga&WDlu2SN%\&cX%yrTw^ fհÂ2vRwmV]A3Ơ0ry mͻ#winbǴc%)^4MV!u_/uCxIv5 1k_uQt=Mb$_q\#JQ[R{$%/Nã6idCөgV~̙)I<aƖWypҺMzצ/Mj:z5 %Hd&fiq\ػߝ:5y+hEIft מϛjuZ"wVm͉Hs\l4s- D<݉Ely3n ImVd31 b)'I+f@^ ړHq@Xl!P 8` {}ֽۚF3sV ݵWVX9$3-] j4ځ3b3zaQt Z 3RKsmƺ91lLs|* ufJ]y bDU0(g HMXȹpˆ:(ч\FԶDpg_9lYh; C٥x'3 D'A?Κv,`s|v~6Y%;Ք O_3·ۜpO6lq.eQeVvPL-U-S`*L9Gs~}`Jtrn9rF|KUx?-Z^.֊v['i V?THmlqꎪ@B ZJ ;YyEU5YjLJYfLHX6YWn~Upѽeb`p1'ԃFacJ#02 6M@WXǎXTuok#'=1Td_1݋A[|NRޣc)9v&H-2saGKum߄}kb:CSH4-b,@>&9W?!鸙^ ]Gd W9RDq' r!T )g/PYH3SyuH0%G kN-:M'W Ǻ\5k + Ф+KEDz؏Ӹ}sINSr4 =_Ar)*f*+s"~i?@w[[֖{qB҉> ;o-|zh[#ۼ$e\ozA]qa> Tg,lrFB Tߚ݅O"?vD>0/_k ͶNj>`Gǘ:וbaL/^ʿ2`ͭjYG04f1(.Fԣ+(:OH4rx}ㄋ%Jxd@VaTtNB2',8@h<8HD E1tʒH\ jU;9Iڲ}iH=a%3U&*^ҚlǗN/s$-9}LJ/۷ k n '+φ 6ޣ^mnUó&ɓ:&]n=QiT"Mx \c=.ײ+ ;59)cHI7SGZcRn)+n%tbfD ]'a7VTyOBw:3c\fH+J~IUB_9/d43VyY?/'T S,`1ab%!j:w^9.נǶFȍ+ꝕ"zS,=\Xף 7ج6C>~ۥ֊V kfkigߪe 5RS`M\.!"G5,GysVL:aѪkl4t!%.U LVv hd3Cɂ썩iHB7͙%5($tEvS7J1ZM>Wm/~<ڳ"Sz)@b.p&RVu;Pj`פi[po."92E3bb |)_ypF/JJW?c P[рn:_3gI6[Ѕ(6CH t7brfjCbĂap+^< PD hP}vVwZwSm3Q H "m%;jpTLFk@.N]ɸe؅hۭU['U׿#$ԙK^NH<'[h}>W| X GJ@9ftVE<h^31q"%gpN}OV(^kR ޹OxCSRjV"ColvLJ \(P+yJPdD5|H:[W4qbs0Lq45ֲkwBg'ѫG <] *VI4O/<\t4E-/h_'}L}Zbm@[Jcµ >b1$+`D͛arVF 7v V2&e (ևLCɿ?#GiFvh#xwRB&xHpeۧ>r;t :j'ق-c}6ݧmte-j(M qY'wBY y\I3/-Xh:OP8~J d\;b"_T#5O)4Dfss&CtÐ%,:׏he. 8} gP#urf2Z@$^aΜ '?eRU'On(^iB۹fٝZ_-S Wɱ祽&Fѓ >K(}r IU\2|it'gFU4*KE:g0BMB| TOeH) ^AQ?џ߹_ȵFm;d׌Q~*˩(Lm쿥'ׯv, X_k+-fKɇմ4qŋjb;$+2Wk̀lĸ.*\sKVƳ]ū'c&qm+jx%J)%$aT9*8΄Oxtn n`vN=yO;;+!өМpr4AOfp*wEuYE lm0iwf qfJI3X)v]W(&^P&nB6Lo9K]o#XATڻj► ]smrsN{$j}7t Rq)&-:CgQeѷ[\m [2%La~֚IlǶoi / 2Vn zv":y밯ص;Lϝ2!I_4;Q 㽡12s"BNcʎP{4Em)R6\wH=+ꜰL2\tR{ ^N g ǛVwEUVj^"HsCAm3~ef)S-G"4GfͳCmc* !jo3|U"Y/"bqMs}"xxkv`X[z]\Ykؒ)գ6%}|RUquvɮp?@fo~U _i-)`6?@i}!Bs;Y CⅰWCs]`釓ꪁz-tB\6v6-D|t\1Xkq>4̐sS͖dK1o 5IizPt In~vkV?|L%0n$ZZ,bk?q^sm(]DuiqLp2n'[B h8x{no"juxG{*(xg-&\^Ya SA_m[ω0.QAJ58 ?&vJ^/(2J ɈD {?`*ZDLWV>z K{yA B,eOulwL3b ZؽU ]ط3??6,ుC UQpU+Ө<8tEΊ.}똦Ln@g8fd6{P{t ssénrk ͼڭ[ <0嚶G $*.leuR]T.=;EefBHuf/ cGl8{zYOO,0R ;EzriGK6#HmЩ1DaB7㠕JE5בbK˽B.kfJQ5=6dNlLRw G.u5fĭ$jM$Ձ|Qo%8AcUdҩUI߮hnMV8 4}aCrMHDVe*RW+ّ{3A3,P`\Yȱ.Ks J* M}eO0b>bYbh2T\A&&yvMF9 EepByW~gjΉ0K:vܡ\Ӭ|[_Co+Etn`ʽfAIgf^A>3/NsvߋdcX؝_< &5"dpD=y.c/Rf°3֚p6q̤.Յv766F:7_[ѥGthq\c/QT+m(Hq\PD33C",m*L>ns/KNL=:o7vMաf-Vaզ$zYؐnH}J'dpƒb`"cU&b$!޸M߫&m¨uIƦ7M{hJ{{̭͎i;x| iC35 Ʋ!QJBl%=TԂGWQ^QJ'$׼B=R0:@#La稤sNf2FS5czAL@3-r#/*k^Mom/#E̷[B]ҳd"f9O!rbIoVVIȆ/zq}EWYZKUaJ%f0Im Vx9Z?Ns"' ւ;KoЖ4\2yR!JںSrM%U \R}mORYx(ѹe%0SCq+-.ڦ{!r;l*4m|aI2Zc90Ous(ubcu%rwtMT܂i#FNHT%.sku0[f"{N0>]3OF%;xu7ph6:f8ߺn0-afFtKꃇ]]57.>' Ңfh Om'vlᐏ;GM#z(D(b4_UƵKu ȤR/bAmL:0R B}$/>rrR۝d1}f?4y)/C ,,@*+zl Ձ2jS4IZԄ dt\vz.4VJ`p.}̧*$l_{?LLɚK2ĎǺ!zˣۉck=߁/.֏o#aIe>Nldg+[qC%c5etX3% mخ(4d`6>`fJ~F8FѻX8hTǼ,]V+qc95pp36Ao跮_6u^e3(SЛXۿiXRRu$XeKtXJ;{&fMx,ש-@E;uݟJc8Y*ʏ/ӵd{ IDAThzڨ%w-u(]J`<{\Kvq>J mVJ~'$UTsmfsv\gn3N;܊-#aQ[v, ^{MOZ.b~RllzƜ}>ǟ܊M#9Gt@Ǝ[b{gζWH0TS$O1iM'Pzm/EGQcf>;rg.sSԬɅnHQ˯ܡ)p;Ҥ4.`RJTVD' "ʂx/*8A`W5ق"%;3{26,, uC'mZx@Ol:Rh#_w! rv0.ֽ-ce'徉~Nb"hoSO%7I0WǣZrB\|j}`(CR6(v:\*֔XB 7eiOEwո%ҲKUE/h -@:f U[2gʋNh:EzqnwW_UeߨJB8UNްfjh(Oݬ+U^5ׂS-bIv "ὧH%Nٌ> *g1_`?8^9jTZoEցقpEJc8*p`DD>Rqu(]>OyuN"ib *TU2210 UL$,/r %KYbGi;AW7@;ybRPԈ2F[մDae'9or7R<' |οP'UQ6*%I{bV-,)]@q4fEz2rl';$d5^T\@28pɚli h# 7T~&o-j>8wj@nC%vl.F"ꍎa;[F9CUzVۼH_aFκl<ԑ ZcK1 4oͩwPɆrElW=pNW*=٘{hM4y[/7%s*^뫆 sH%JC=n3&*5kD 44 v^DpSg'D廲!jcBDĨWEڌ6"ROx oT8{f1UiqϬcM@_ek;M޴3o5;gy"L}k\//(u1r ~niD4p-!l`SL{B7[F&}rZ~k^TAzǐmICu<H<)oٯ j8jz% ܦm&rA *i̛"GaoNvcM4pE jM$`Vj`ڊM.(+Ioݱ֋Ps*8+(Sš|,3UM@4RE?cC%|d~61Rgmk6^7{\-fw8ZH5%׸nG[MO8|WPN,6!(T䈝PuԴ'hf:5Ƒ<<(]ڪZ=2CAX-@MdAJ _ 3T`q -PSbE Qt=<"J=|tRCsk,|3 (s:Ϗ`im ;-ī]GGjaqZPҙ^;{3sNjj~c4ygoץ < v Junzuݓ1Vq)bC=tՈvIru84U֖Hʫþi9{j=g{-1Bb@H"O".<  $ ,[}+vpOEK Vw%Ծ-@_ҙ8dκ/zrk 2z)B@+8 4B m#c,,Q:ޢ&8Z ԯKܪRBERw!88̮Gm 쫴9o&aCi#V]$aQ9`NjƼD giϡ]8Cy>l4lv:6_JCl,B3s4V4Å4SS,v ȿyԾZ'XMK7T[|%;1X q{I{Ƽx!\\-:(TLJR_ˆ*W3R]o!*uUT(K-=3X4Z ϳN: ]3\*A `dvIζ\r$e6US6 2ߍ1&F[onȼS'Q9J[@kagBpb"\u/w#a1Sp74.:*(Ra*lt-)ۣZi*AQVyN sTk6sL~HjߺK֕px#F-WxQrf䪹 32۝U%:{Wwiv*jŝEܥز3eN6q%ڿSP9+NcMKs M2t…ފ6PtE5dnAGv /@sjs|Sᮽõzoa?v:{<'YT,>+jQҝ>cg`qD&7>rr=~c2lp4ڒx-Z :? ۪(ì uNey%R ;.bϜudh32 $Җn*s3IKشUg'A%'~zP&a>4{naw~#ZQm<|hc2HHyO¬D"ccE.aL2rʢLVbd'HWuQ:葮׫t:F-E: _Uc8AZD:96srȧժ6QX ek.qϒیH.d7ecQLIxMSݳ9֤%L*TsKmnvRe VvTʈ`TԕZLZVżE(j+jAzmmv|Sbja9<8<gW6W77hGMp$GSio4h09 +r>B=))-i''w}*ˍ.M N\:R"VMUIHVcOܔe1e'⮝tu^9V S96 T q21K۝}qⳗh BRge͇+n , L%u" gȉx 6 UAQVK!|+7m~Qw@MLFr+1r%ǁs[ 1;o@n<ٴu 7,KsrHĩ'jp#;3݌C:PF;g]0sM*i 4m1RĢMAD2#%q2ۗ:x)cfP?`'*΀]NFWzRд*\'A+>&^h64/ijw#4k3KaVtle/Xz3Џ93^@Zqb*ˆg <7;֋p/4EQ]YނyhW"R.nM`qzߴ{+Uec 8eδtյlV2UĈ CВ(\FH9%U:&۔ S-8N>jm?E1Uh~Mcbhz!=oU= bɊSC.uOhW7xz <hu}ph] N.!-ŗuʪV Y֌<z@4L#>ÑzB0-CfޜYaE9L3t ǃcBͱ?*}M"Eӹ^e+O`>w'#upM}q'[ᬻD>FhtƄjM& q"`ȢΟ *1NJyZyj2fe<@[nzGL1̪*(ef+ChLH(8obTMܖט>OQEy>TB $ \"nu}K\ӗ =c^v7HUnQē%}N,NlN!/:sSfJۉfԣy%r/sy.-)tʌ2Ѫwעpj0_,Bq;.a# %{uf{"t͡V1ᵍJ6[Ҭ-!.]B/84s֜Nhqj0N}KĆu+S{dwK*5GRLجR>M~U^~GQA5Y =**EFmfXh4LqbS=s`F4`_Ź24IIpшч}a߭&_YڤbUVRr*T4prfDZr;QxX;u,R -eH@HqԊ*aAus੸j&pfQ꼰ìuKVA1jf sl_N #-xG6$F;1YX44&]4&f,MK6,Pp[5i jW\z6@*2t'5m?B? krW5GS׌"fgz8E yZg3c=?c=zss#r)n>|Gmj|=7%\>0Tř8–֤ tyCE=AO}~W'hbl?1dF=`\T-r'{tZH% d-DR-DUb݉)]'MӺ%&0S) W\3&wJ*m9B!bZ5 )P8SXgUM Zapx/k;b#h &ynT'YOn4\&2X㮳&ʤex`сMd>_]m-1:TjozP6Vc[ T/-'jF'Y0v%<1 !:x P^|w{1""JzZxz%tkTa(lxPL%'m[oכMoD F)<+>141ъ^G,a?c2ħXg6?fF2vyg>ؙb0ݤQLl#K@u%YM8؃ $Z'#3_{򉧟~O /=Hi{ӛ{}g>/ѻ_}睇?@J5s<(S!ZtXK9х Jytw%inDy1Ó R8l*k7%f_Ɂ0f?m-u#apnI2"yAE!u2)D)4da#ָ**Km5bҋZcd{rߛIQɎ#pVHnUDL ?GGk_G$&9\$M4 m؎u^#{a.aڡ zp8M& Z$mvazЂKo&qpOAќ6QufxDC.O:eĿ[N)fpxxo顧h%uZh_qhesoXai5%3A)ѣaOSQEb: N@ٶh2Ԥ>NJ98iUN'W|}I覫m7))墖imO~с ɫޘљ\MjR4..9I(2cMaC}zyF_B—uāa3Lesn{a}U2c]r[oi.|E}Cqe[:@`dI[nt)]:ՄNePƤBʰR:'UVx nwrٷj@=4{`ɂcw /+Ͻbm)]Y*PW7<W_}[| (7&bod^8y|{x*ʆYPYb0}ִV*נV0=6[?I{HV#WnnnxG=r{|-8-tQDP70dX*Xp )VHNfQd·q iKq z)7yoS4.ݓ5jGa%O={?-UF!؜lE#OS鳟ڃ6`xr[7.r¯|?W~?{=oV] $ Imr'!\+% 1c=}MΙuPn 4HhĠ{as0{G}'~_/§}'(ۦ֯~?xwy0FҌW9c.d1*'B8-ΈkwERRJ_hY-=E#<9vl^OҘLOk]uR -l ]XJi17m &ۼ0 {o}E.4qT"uR~;GG`i:H"t\NBS%#QjNqЫ*%D`1sEߤՀLg5.M}K/} K/>O>cvt$WHsB{x{}{cK^ӘH[|hS e14ӖL;mmeL[ӟҮ{VTuD&"T~,wK3QX +G}sy HͶ% B JZv %7'1Rn%t9Ο?ncea\royq%HZक़]' A 0H0|7ٿse+UDU>TB8mAyZMa^4Rq |W_ʣ=F'ut+3ܜ{_o@?`Ab/ <q*xMeTxK'VA iQ)$vtK2^>jB+ٝ:>sˏ"O~?}w{QM <裏{9y#h+ve6h2v&,kٸ+뜲j~qW$m ۅ*`^:Be@joC2S飼 ̕ʌt}gCLfBOi26!hJ׾ҧyNlg/koݦԦC:@6AkZcq<+Yٲ%/z#מ&W9Ir \In؜Pݻ{oQJo7Ou&DM嗿/~_xGono.7_˿?>|=7'>ZS[1proiW(}&5!Eٌˈ{D4}39תIdAcEZ?#S ^TJ]xѝa&ifj;LxoEoi Ttr‘1~uci)"`"/o|w?x`VGL 󁹔^6ntka-ӍoƟgg/<Ç_{o};?C3-7-RJ7?ҧ_zpIf~7vub ſ? }-͇ڼ˂{mƜ[1#DPfF(*M:}kij#JY54,UHyz<(_tجn%*$,ؘev;}J)7v[\ X6c۹ry*c2'sBGix\8IeNI΀`C9xi?oƯ/{?fXH}5\4ʳD_"/AxP0K (k>&<ڴ 4T W[`'`w輚XJF PE~bǤ6?5Dj߳pqi73q(Hsp}:Svy쩡kڐpC\Ypv\rgysKA-h;%EDgz1t/ڤ.1Coj3m4bJcuBϽ|Go[n;&4+N-#)xGvΓiLQTa>mR8+d!݆pr"[$kj۩'׿)w}xEUF(TY* OOs=/7-5ǕgXjv,+eE(κЮ_ _ȖKӼ8 \ts*zV'TZ<"T>M*ka$cVmw>dT >F+w;G 4vyЏ_6Q c=8Jm4+ΣZ>Yj> P6)d"]A"bTi+_b+lB<KCZ,JxuYP,<:Y(tsx/i;T\ڔmZ6SO1^̨LĜeqSIQ3?c0%$z k#Cۆ{K9-tN:Kz4=30>h:5ZVeZXy Ą`,tT߄X4ScB>Z׽/v(=C^V'{*W=X0PV<^ [vH aC7VIߵqV)ZƎFY3ҎIfJ\De̽wFȱD1a-e%)]|;n1cچ!!v?fÏ^y{_/{/}g?cHRFL<{]s8 ax?۶G`4oGm*(`L+J)7'输-zRnMiz;-PüyfS'Ç?ࡦ~NS̮Fo_Tz?~}_O_v}gZSQǝ\F##v rOsuMIt'/{B*@) 2ˆuHr:l. ( A( .]+SyO]B gߢYR %kő>NAk"PeYf)Žۀ A#`X+6>d * oVeɎVR竎LD2̜tg2f]y 54Oj"fT%; L,+eH_gy?ӟs1jgZ\C,|~n~~ڮ))W $.9m&TNeg$%{jp .ں=n; ]OQuPRSO$Q}Go]8嵥Jji9Z TI=v>P\͹,2V SS91?:#eyTGӉVHt봦̞?Ϝޙ>nZEO ,Q.3?\q˄=S͆ U/7D3RIfzVokz7m[FdzFd<8#p%31g.w 4뺤W {q"-J"*HjElD>"-C,iP,B? aOX_x@ IDAT?9̮\0_L@%^XEZ?Dׯ}dm|؁8]wa;wH*",-غ* +?@@\dT}/7OJe2y !Ub31_ ̄V0A,Wd`^ ښpiXŰOg| owaͭjʺQ*UO>g?y}}=zw[c!qI."3x w ȯ 1hXxW?,U=zAB1k[69J8:Dh'/vxW.u&DZ&5Ef d;T|Kɺx(o=]!4.Z"QF:qRϵ1YX$/֏= x`&A|w?:Iaqz~NE-*6P|-{ L9:*XzvY7n6sp 8(vR! 6~Ak:ħ/d6h] ADv!@p$@EhĒ ӧJɉ/̠e. ww_rXE@f]FKW/\JI&!IgL2r/Ŝ mE X4Pl_;!м,Y8%/sJ+V`ꦶDZ@vSy(\!omnw͛kA3no;مGx_|IՕ^}k_J3S'c8r'TlT=n _(t3rJ)  He ĸ\0}Qc"`HC40! .PPw$3p$;0(ͧCmRBnfKD %Zd T) bb1/g}d-INn~uQΩTOvِ# =m\jHb<Ϙ\uM a0X}E;_FTL˴1DLETԍ yfq.SL2Wxٮzg4/$w,x+˫{{{RI*n9t498}}fr"1R]/k|bY(Yѡ(Y H) -kNas0:h 81ims*j!7ͱpe)BDszvV#TAF=W.]{{ebɯjS`5wv)EhPsCb^|}_L@lЍDJ2|ujIЛW!¡ ݮ̉#fFb䟽!E#I "^)Kh@,f; &pW" nBΛ<^kvdz%roNr4ݿ3꜐Ja;v#kg5h,Q6jD5(~e DcZ%/zd; .ct&(E`F.s`}s~< C)RTWM |6G<9<8g}VXd>2bAIEf\ZS8!^rSO 8 YDZ͛Rpwt# `uca-槺a &oI >qm<10TG'6#cuX,FA84`g+uVsNQ;Q1ƦiBN$`U!'^"Ǖmv3XFST]Z{n(JTЁ4yH.zHgP =Ćޙ 1[" U 4w]^6.f|9^%d^~ 1ukxتN(w>wpA9 k{ʕu{c[&Ih=[7_@pH$@cHAmnqv`c@ub.4 o\[9t%f:92* ][!$&]fMfS[oȹO 軂J~.?2!>tE*~j#Sp$K'QDnݹCՍu2kH1ﳄX?pZjZY7ڟMʱ f I9͢Vْql>@}> 뢀uՐr)oژEQt,tLy[nQṲ8,"rREx#n@.ąmx{ة!uA̙r Bԋ 0~}:?sӓ(Sb2J]F 2ʪmG'Yho(xucy UGRg]FQ?yr~l&-xfGGwo|wdrs߹=v" aA 8 +oqmo5لdGs<@PaWҨ #.^ʾZߕx Fʄ=P_ƪI9WLHU9/РBkYG^%x9Q|"ݾs+R"Ky*z-00lll,ɠbÜpEf)XV[#ɞwJԪ5Aa K⥨ uU%"T) -U.-ǂ3@ Ԇu"䉣Rh5s17R~.RR=S2>U)_HeS}Nn#b$$rhܘujIs:xc)V+ !^RsŢ)ڭN"DѬ0gI oH/c}1ƌ#g2An.*OÆtѐ,#$+^QRҋQP~LRS?oA{('-}T7j/,e$q2ڛ+k%ȃoDIT_}LDY+ aǏp Μ|Z&/\:y3t%p{goUU`.3b!TztYDmO&}"kA`_!JV%4or;3Rl5SP'! 1DZNbo 0CHW5IZ[[;}|ŗ8:ꉗRkqusZ M[YY$ïyBruQrǠy'! ~돼|ӠT^H1š/*p/(I$wF&`IJ9D$.)*Ͻcv$Y4.])>w/Tk/U\ZI6H~H0VG"cՠ9Xo^k-9:VĽM}kL1pF9e/S)!.-4c='Ƃ:@0<-.D?+b8×jefnEܳY,Lij5IE=OHؖ]|ᥓgθm7mMl$,mu\| 4<;y|sn{ 9ǕH9wҥ#Kϝ?LRv &٣ OiJ\zڳΈ7TiSS0IZ|!ܦ]CY\t"+JT9P4[4m3`ιkClbI`POTU X&9 q:X]41'?!pLhv4FgmlJeRpM1$bZ4c oL"rLy,8  {pf8m =P%D\V}_ہ[]b9Hˠ5!v)(FD9+zP'L$࿸S.fZ#Ďܰ4\ rMCclSHk>#rS;iݳ8'3DJ]KSvgKD׫v^-BFw^ wl <;ɣGNJNR×lm 0ItW7ZlXq7q ǟ]RX0T't2Y֓;@ د)-յ@< _yp]{0LJ:VE_~knL7>O=?]|w{{Q|:B/h>}'ɩ_Y]}?̼qԩǽ;u\'N:sw׫j)N1yKXQ>zIzH.k=D&}gx*J+ ;TUhe؟p:[}H:p`<@H}pT˅ gNx豛]<5ɝ8S[~&Թ Ei.^Q7z1?wHYYWp6 * |WH^QjtjJl DnYGC=(5ppSd)ś,)QROz]rcR@qa5wTǥVÅLjǟjCK4x&M{$Q NdK&j&U譽IbOX7L3~7,[%ca*Ux~lcLTI~jM+H.?KxT$mu `T#+yӧ{)\b`dDl_DTy ۔ũSp8`>R18Qj5KY^lIuC LoMSҳ9u$.m J`GZ׾@)rQ(uf8CȒ}C„f34汍TL;6*>rNSXvI;1Wj.!P| q[86T2m-@3ŵm|?כ[[vv&"M?O'NA=P'e:L&/_{vlZɪ 3ğZJ^)ʈ/V=Uүe|= aӐ6d|Qzc;olx* NLd6(ElnbXGkS:̘L&9n_w??{ʹyO݂7pg<~jf-H*}$T2O+xnW ňް#ŴGE̸Y$0ͰQ r>DӴ3u&uf*|=GG'd>;1-?5ͤ'y"=(1c8DDS瓹ռSj6ƌKIywPKc̼vk)6~Tzս2Qi+=KgˠP. 8(K JPh.m]&sQ=ӿlZY$SB% Nޖ)j!ߤdt49*byyeaq'ո;Ŝ#bTIn$FgM&Gf}/"Ϣ6*D_8_ #7b$uΛAӏBԓڗyҥjI><!z~fSy孷޼qյ5+ ޓ'~ۯցSܔã~׫6-p'DCا%z#@n|\ $pwΒ&܎#x< .:-A&UZ}ክMRxCu (BcGY IDATas

N}V'M8ݯ=J'zbj!<UJS@!Fs lv b:+kbW7}l@ymUXڊX'В+&jM~_twE`KyO$FexUhE6L>*(+T[JkZrH~0g !19V^8V-h@ƍoՈxsP}sÃ#3*Tz בE(l瞿Ѓ`z4a~gaA ֵko\ŝ'_yͭa2r. dW~s. @?s$ 7u]|ym}Mr&΁mfJ*/f5mЂQKR0 Bf 'MucdHV6MC`pbd?Ҿ W!64RfIzV] 9LRC5yS8Uw28urt>E 4c&K<7iAd.cE1P/\lxpmos?WS\VX't%KǑ^$"}U^%BPoLiiI[ҞZOp 79@ot ]/8^5wk:OS/̓Q6S))0EnF-@An0Z(+m@=0~s2:Es(2yhusEҗ9wx"қDFt&+`zBsob^h5"Q##;Xx1;ud1Ύ `|Yb7'O<~2HIU{NӔ?Յ_Y\|q2 |U|=aj5Jͳˈ@/ѦWE"kέ`i&㧖}Z/%]%i|]bGeET* )-PLJZl4E$$ 7[R!X bZʖŪ~e29rڱA;qp혎MP81w.jla9ԝ=a?΍R&A(عO>>ydu@Kp 9s[7yL+eK}@Ҿ IZDa괉%GpqԻ3Sk6T[1&tSl U,%ւ P˩T,lc*%ѣ?3=gcLGiuKY\g'GJVaDcS1f~e?xn!Kp}r}HlWX3_K'\!YAEB@N390r(2 SMΟc# (xp\ ٩"`_}.jA u"5 (Ǣai%a_ڝ.)%q;0@0ECfÖtWWSgPeΈ0caDeCXp1T :Ty\VFE6_s8!DZN]МD%&<_2ReLNL$ a%jAT$Qjg`Ik=`V5G]ׇнk5qz/pYeFz÷_~ՕUjg֦8-&ϲ{Ũ~b)_ s%>흕c$g)mZy* GcyȨUlnvɨw0lq596)ԡҭ=qhFU]Y=Ad㇏Og" {T, DG{(׸4<{핕d2淿_ku l d %gZץygO=a5%> ʆحJy[3"+E+ᷪ*`gAu+1 ʬ*&뺄bmG2dϔR8Z:=B ͟@?kT#PTKCb| ޹0aR67(WD䳈pev3A3K"2 B:KIԣOUL l۸zhc% , emJ5%Β~4IEF2Im~*`H:(xAU;B@Ӿ%b3B09cX0op\z /lPVU VCx9 F'`tIDˤ8Oz)3ù.^yu)˞).iVVWz'c„)x~E\+ws;Dt([yr^h\ cm0^$6/_?Fî NA=x;ᶑrVUY8-q[A!Nl"i \_ri"Gnq%qQL}!e)μ&ALSۯ~+̈́(y!䏲&B!YBl0:֏ lҠC*XC{`XSa삿IQ-*WxrH8[mݽPz!\YƋc)A⧇1s:R{IhU~*uqTOӂ%F3Ռ[n 'a!Vgz`# Ꜽ# l9vBr5< ]u;DS4%錜*\FSvXϤ3LjS&_T~NK^Y[m[7-*-v y` {L{!%n' 5TG&|@ZV{拗ᅳ=aÜ}kS(5iT#dR;5%Qlu,a̪rlRRKcfsRG:Sҩ~ 9eV&"cdžaXvhu۾)nm5Hڂ7d!'aNuo%|B\Jh+Fǔ_aWF#2Rj_{iQ@0Xòg$nLkU>1c򋟯L&L[w+lV݅Dg5(_) |!//Dˠ4!Id4ݓ-DM$32_ը*X&FeJt1OP?7*9W26V#H[B=4)͍jC2h4LOd!` P-H]RYe`HN h*(3DY> {a(L8L*KP^EvB}~U Ѫ'+H_jug.8a!. !=22|M-~9E6~˃wGG1omm& HYmKv9r)n>7N;[f`Y-!o,ꡛlcŠDAFIU@=R}V1 *%, H>  V gKe)Vڢ`$to>A.D `D|~CRlmnwLzB8:Ň͢^A 0>0 bÓEw+EIzpE?.!{pZ3xU!D,. jꞔD/E%穀D'cH\ũ=hgYyK%uԽ3 ){eC}A4eH#ğK,tA,M0P_omFx52Uތ'[ũ3w5" 4m  ryK! nJ;--N.T657c3 nU2pCǪc;;, g"cAs/NV"'(󣣣ǏhKnЭ0V1o;S g*; ӥʥQ^9AxEV}Ӝ@v^ ^z6 .J64թ/͙jnR*^ #c%(;Ġ|X7DlvxM }prwulӟ>L& C1CK*=̴cq*KNsiܦr" gkA, 0֠p *(w〈e @Y(XuZzz[r5qjw`cEU-i[M܅hM$bCh>kXHRY-1`%5O.-S򷬾}a@ȫ."0͑R\v\4ZQ҃~7J;nɓܭlxics/ޓG2Ȝ_ S6;WWE$o+܃w<^6+}LElsu++("hX!r-ܺ GhN@{E+ZBX`(zs>x ULp4.[V^9:1Y#VEtqmfZ'OǎmϿo" FBG>"0vS _̮T6E{4YzP/dWh .%Л dv7糎]r?3fI s{&Rdn ~myb,کǸb7a2֦+~6-iy{QlFvnq"z/t7euvجI]6v\ƒG9 w)o*u>pl]uB6+g5=Ώ:({)Q,@2ۭOV1xqPz])߽0g&MWT)p[~}Awwm20;)/*{_e(=z>#d:]Ͱonf\z;ZFXia\[XXгA./0 ^GinD!8*?$OAocq9BR|m5To+X`W+"%:CPȰ\앗^1"࣏s!VzN73kOBblY&"atq8<43Åh"Ejx  {(u9u#puuQ/]֊vd%k @[M6ϿZ;aFJ.Fe/<UT 7n.dqKdaXD2)rAi/Vqv]?`$3] YSzOP| X%(t%ьJmF+";?F/ϑр1du5W]\XѧG'bIA~ÃzY~λܜv[;'W[32Um]8ߏ+tO|3_aSfQmum^vvs/ B cUĺ %wU;x&RCTiMJSi97Z 3IQ1VU>zLҊdǘja2E]S> TFKc ޣq{o>9gLY5q<6?Ŀ~bf%TlUSpuh4v6]ʜI$9\z:f{.7U*BֿNْۄ%R kUvh-~B0Ugǝ "f[sh!\: s)cz΅`q/^]!I9ޞds#p90hkW F|\bvS12{B8\h|.c[sqo 8 \'N4T2%"&_S&5š2 HL&ʚ}",_}уwtx-ֵkwoyv=L& `eu}}s|>;_@O1ą keex"mEgq!WCe &{6[cEyO(G6)&t졋2!I,?( cq xѳ "Zd*5ib1)&E }{}g2f}'ph`Z-(qNq'{xD(c?ryl4]Dree";!%rD%kK,V#TJCB 85u4,S.)AzrxcCY4SćmI)p+S:!4Q.ãwf.e \a`q' Y]\0UVRVp$U}YXF&]0b➯ #ZnCO&rdaaP& Jed| IDAT{o&DB1:re)98s&[ªȳ76WVVVVVWWVWWVVVE2 /'j3pA)=ڭA}v "zy:ۿ?ܬB}bnm^"Nc,=MDL5g}j7V:TҔPArw.qB+Rwa_leK j؁fthPd6X]*X(I E,S*\y\6fŌ_L!r6@}| ڋJAt%'Єʱ!FT/ Ϡ59Z (5N֌PR(907>M>n?<*1ISGl-PG$d5lj5#H]ns"b;\J+uVxbFg) ya"%|l΃hI&G6676'+tfu}okݾ /ra JW6bǶLrI -uL2D+0iN9>9v)PLAw"2(o'N#S/"0v Bfs3M!G2oH) J˲x P< ͂/gy0Okfr%Tw#xrd<E-9~L:BTc> ;(KT8OCQORxk-URFm`}xP\ ع[LPkυwB>I% BǫK#JrD(Ǩǔ+<)9G(v{ůj, u(*!duVa(ʰl357h_BTwhy2eh+pYAvMlb^c~v }5ߎ22 ©lTLe48Hr#D.=N<&eZ.`9,XXtXK&(L{2U~uE&gX H\ZJ TÃpʢ8\](^~-o "Pb"[gA8R8Ci xN;EZIAfO\߽A]%UFLzNuMco2`j#R3>Cb8j )FKkGV! H1뗧A@LJbh7g(9"fLyMa O=Kuӧ0 pvv IEVY7R҃ɲA80oCR'ay7)hXspcGWBPrHmZGeQ$HK8\ \]-JDxբҺn6_i>ǯ~O?'Sq̧Wv@>X2id N~]ՔИ QА* MFDA&Pxd8O*s 1Ui쫁ܹ{j^T/jT3<hYfZ$\?c13 ze;TҦZ1o3v<%Qk,VrE9ŻIɘ|^q625k2l4e)X\`6#8TtN)I3#qt*/븷E`9@1 іz1" !A՞s+1S{7Q+bX7F̀-,ӹID lY]['H 2=< .(L Xy10dNz7{3eɡs)VT:y2 pgij@l=PEA(LA*H+U-ŴY5QD͙T}oWhr7ckR}ykTVbvFΦh6=͎fGGGp󕍍%ٌ] MO1#( 3zekN N܆<HM1& S _{9t,B"$rKHR3qv~kQ~^T0Af1-PTnoܯ~ۯzLA\A IG,]ĤQk2&A6k2R72`O\tGrI6B#k5' ͥ1oBmU20bf>+`t'%Ǽ",1Ύ-,3tI£uYhEQήj$9g"MrtcbM Ey4(Wjts띦 /l!3OFMlz00NvT~ qB4vQ"@J$GX:-\LKA9T۸Ϊ7$N\N$ʚt66[F ̧5t˯G򈞻t`[7Y)Yd|e-90z{ho:&1y65w{ RuPJhC0u4Mԃ|*YrG"7HEz|V!X;!ٯ'rX? cyO@T2#%q3"s@~?5Q,7]$-yGż{Ig\sJ1]gAgYjaeȭ*J>wR潩,?Y~Wh2kk+: T`+)mQ9gQE>Q*G3ŻWA,EdFf(j7sNFb=fB/=" $8}N`3'A}:-%bJV!KN&Vܞ, xNRrFvؒsƉRx! bb[D ժIL^,d}*kڻ ^(DM7Tg6="&++?x?ޭ[n>Ӂ!k_| /y3/DD/`{=yjTc[%Β2Vn3UƦ0>,nЏYb{ٻ>PM ,ĬS$s[XB,E%ŋ~mLsj6I_*9;u-3ꎜ{ LN`{eHc=?<+r̞İh:S~ҥ 2ܼyوەp$g2KDE>FM91@D,|u[&rRXXB k:V_BZ"^*DYM ln ΅_SQЕ#edTwWet.>>)> F]ik~ıu8H/ה8&6 IϊI&,:j(#Y41U1X k"WsMdL(\Ro0D! EP(eWcy) T wSHȅ$k*\DC3:gJX s9WWJ3˽br&hcO"]Hd42a%V=BTZTEWzG?[788g-op=ĕ5WoBP/épnaƤCR'v+Խ[xB$Zqu`"7ga3'LXE4=gw`/齐lpecxZbLDsK sy?G4b sձHt&@ZvNY26; #1TԃiN8FA6H+q ]"|YUSĥGˑg2l?H՛@JujL 9ebD{_; '!EE<8V4>/|&'@M$E3R1f5'5[' T e0|Sϟss |՗_eD@pϟa'TiA{=6 Ňa8~1Oi9:4K!I]Yf#}eUKv $c(YK,CnᐌZ%jf0c.DUqZ&8ƭ)c9O7S$X80N~mm_}ttcZ%)"%>¬B ZĿ꺪|{WkH )vDG$U%{1MeV|0<̿lXTőbC[SDr\pz&FSISbV`7~d$rmkE?wf 4Ż*>ƫ\׸r{{Ud{kgB |ARrc4O0^$\YꨟHH@A v0i*@mSDԥAOտww/S*8&ßnIX`g3ȣE$(8HF|Ǐo=wfꔲWVWvvt0` Gh\"Jح001Ud巐#˩J{NC FgQMLLt5ǰHogOˡL.|^W^y׿(A6!a?@m\FZ0#]B3\SFMERl:0ld 0dC]gg՟`ip<0Z|Xp~H_8~p> 6Dt.YVB:GWR)]wճ;1Vq&(29ZrJye+yeBRmW$09t7ڔ1 PT8 o-B.;R#hw!Xc s@?"uXtBF=*aO *6Ք#v*l u0DSPvw`,qBh'tto@}wLb` "`9Z-",..K0¸)p" "ϒciKH릗bWӎ!Y&sM 8(Is s8܄ (:$tdq#A#09=dfVVRTWٗba.Ӟ[,2ˆeLH@~|}_>WWDUfkKmp '[|d[j?p|_Qd{P h[cУtB@8vq}y o~rW&3tg!F U9J0{y_vϜ.)KBLl6Bh0yjk`47 9.A䗭Y.o]^ܧ)& n_[aj1J6klPB׻@V{G~xN`3v7{,=}W4ۭmbFI Gx!h,,K\'b,~Nf|Ia-L0̂S$Y+WOשR ˴c)7>ɦBPzRJܙ"pIDyc4& P3Nz8Y<},1\s1^P54B(=~d6t\# naG_84rZh0C^ZkVt@d=\+CJ-K5-P]_bI  kdCR`c j1vx?-5pEa@E>`zxgEO;AG7 R!=Xk'vlZ”>z>I$xIs!U N$L2b?V+zѬ n_oQbRL[gc\Z-=mLG Z+jUW>qb"駟iW0j ER,9/ֿ Dܩrhpa!9 o%[\6B-y@Fm Ch[8=E`;IԨ&#J$+=՚td axM8:Hi"#[r[9H?݉X߅ :Wtg">\ܥFA " z@Ƭd۱3#lƬNpvcÃ/}b0fSvb`k.=y0*8 g88 3J9aN7n #2W~|zđIIh P~*XY3*'{T 1b6\W7_D ϾL&ĝ0K KxvFqY#8`4zO5~`Bp Il R`YQ،ɞiչ͒DѲ[ww~1&س1{؁$ΣUSIJ/ԩҭ"|梨p,\G׬DBT/<`A$5I 5gmz IDATphښpb*6 P] q޷<.j0M8")\*%IB-Ƿi5VM&IjrVךKz}$TNJP[WTeAͭOWmQTbGԽ +&z+2A̎ة;|?:Ƀ|#cʫJfy} ̼bZ>iF3l:{)=pLD Å^eА+WGR[Bf.$/ R">[ iD ;o"5M֙n]&3\qOv_RL{sjX||zfdtA|9"~n}WE"łA|A~k)y"lr7 blg.j1  ,m^mT6c0 5Rܭ)緤xJSRX 0|guo@=y%"뤺b Tn*F4ƆI҈ Š0!7V+(s`D9T9Gv]ƽ;Iv1("& ڬQthmP?*9+ XX] |17FzG·ȭW/wuQגA XutgQI*?{5(vT8sٳ⚒q70!}mpE(s+ yTu?jT\a"Aݳ_@Ґ$J"dH!w4h:y70Ek(iTҙKND/Sמa_4x X[:+|s`'!`B`=F3#ɾ:¸\ap-'TCn")mdWmS-VR;(N-+53meЖoRq@4~E҃І/HDO-쐽6'py|golC1o_|2F_7~'n߾/ SEzsGk~<'/^zA*0n̖mMtqTk*1Y8d> sb/ G:>ٷˆ9M;">@':p3 AƱ$Afnׂa9WdގqD1~[Sf1~p{Mǰ Ledtd{>cl=W)Z7X"GxͭJa$3ʼo2]XcQ̤G޳sgB''i>ݪTSQ X 7׆TD =3;[;,F}Fy%dC${7g{Vq/.ɲ.VV}@#u`󷙆 w9>2Ꙇ=oݐ\mf284Q}@+ kUHj1k&)GzHX=tjtVB]ZUy.~6[WO?~<7 StP "zoƷ>z-xSi߯ӧ?k'?0SC`O~M}Udb=?n@`<xx+Ǿ֖ -9gƩF6 +Nޔ0 :3J;'Nˀ gt.2N_=-ײ &CRO5Drˡex=*kїC!u:-`;q)eY0zTBp,a`ݗ+QO1;5i`BDX# j֢LR&TBK=,w\fbeYQ˵8vպ*q)jkP' Jw|AGYPEY%e.V'.ߘ˧YUC )$ي!\AKDMj,/U\މxœ+oׄ$6`04HⶺK0utRySPK0tlyXD [Dq Sb9|g+kWm&eDӟ}>yhDo}!>}{~Z;M^9+|cm/*-0'ۘh;=,;B-<S-1փy]I Rҫ0mA2KI'KhͫXuZ6I X\؃;†+/b rtO`5z啗?'tU9M(B8 JzfQxĂq'9=neXeFcrkC"n)s$AА3[H1ؖ[Jdwz>/>t?D|əM^ є}Tғa˯ N>N3puOtQTeH1%w |,Gh5?4dXf4%Y@נ*K,m3 8-6]Gw jf@5ɒ]0g5@KSimg .LT%[ҐjvB|3Ӑ F}̸+zŃ?V6s4RzqΟ~^־o٧o/|Rp}h竫/>}_ӚZV@ Hy=Nh!c6+Xw}Iʌ5ict;wؒi^zD n3l೷bkE1&l; uG"KSIgKGaX0M{v[嵗/7 Lϩ/倡# JLf%D-mLt!qyxouނKW>1KXqP/> 8(qDXg2;G$27gpx,. Mb7x{UA4lcP{f(-{V5`T.(hi{. V/{L)b'bG͹hVxBf^%ebV6A|uǟlߥ8"FA+Ѩl7 Kٳk-IýgTC:z,4G&y)Di}7ܢ=gdkϽҏܫ޾{?ۿ>yҳ/pΝӭ[g"U./<~>_>},rp7h@@ĭoݽo3ő(j8G8z>[c6H\eɉ+dl$S^U XR;YϘQlY/ q֦ӂhI3-ZN}y6ڦD-1U+ĘtdRŐ\vг3>CD?S4oG L!<LNHPi&< l 28 Kh܂߅*8u,OvnF:6CeXT61zpu IOFΧ"^FVsbB.t 5n8KW_s`!ǁ#nz=+ 1s1 %Y4Cb۩x (^[2_)_n*\1WzJZ'PDͤ(ugC9Co6A.Uodk!}2ܴUAV^{TrZRO}_UokWoTFeU?}T$?].|ǟ9D[>bZks;;:]P6|޽g{t^=|܋/ЪsGE%}Ͽ`>QX~M\xһUW{.QG+5[Y~s >_ (X7l;\V֤J" tOsҎD 9Ts}v ;ozr,>0ʤJ+RltLy1KGtan‚L/V6E$T~aSPy⺐] !^J`I@GhrĨ.g'ٵJeFf$y /d @bxUAy+ʫd'i$9rSP/E@ !iM9M},I,zɞD !6t ] 2ByCsH2w.؈(kAPZ&B)Fj%+WBR"'Aluzӏ?zf!q|uuo~ooW_fKPs9fI*{Ž_xG?~<`ZC~o?k};>%g4Z[ Z. x5Ci_7fP,Kk'-2Yu܀foLzWhDm,1*ŚZCP5i @x=8 (U񴀭$ɝ`%bL|yyU[=<lgXr4Η?aP1`JL d\ g)(.`2 F(c2Ʃ;'SSmT c1:3{&^O4ZUP4O}FA(ܭkP4+8V3kr0%`j喞0cj5σ@8*rpSQ1NmC;'"LAP黎c_ߥ('a̯|I0 LM%H%!L@:N;z%C3ʨ]ph lO }m`ڷs3շݺί|urqpqvߟ/vGmзn~?~?8ݺ&|:{%2>#X~}K#SJ`kd:PTЛZ) uOFQKEroq% kЏ۪ tV}pi&k81\>&R9]t'6]=)趖xsR(KM BAp|kao`4ׅoؼ[UX7L2rȵ{ gݯAX=g2[j$mi gCŠ՞d=x'+q#%nTLLL%$mO+{ * 3 bp)-}m"ٔIUhDr@ >I zydehv*ZFQX qwp˨2 #֑ )gXַPA`} XZ/p̊уBځ\`E,Bz?~pe_Ga{>?sۿƛbǏ} _WKݻ?xwRO|gO3w{/sI:w^D+؝٦&R)1K3W%HT7e1Vo,0وL ̜!F iɡD<ʀO\kĉ8$ _y>H#VUY蛐3ˊ//~bƾ=ky::H^ݽ iB9=YM'Zh_5cCs(z˥+q<ƧVGf( 5j,=4CV{AӾH8sgcX@]!D M~M`:)jEņ{"_D. Ёr Iܨ9ʪu?8iBD.é\H@Zsty(0aayu9M8S!IΜE:(eW}\#J6Uܿ92k+~ Jʌ5X QGSwѲd 66:7޼u.-k(CU}lC;c b^J9 E2bj} VVV5|Vx2q܉VFD1l^FD6$GE:|w'?^ݷ~ uΝƭ;w3^H u귾>~ڜO?׾9{/RwG}Ta>X[-;dqncitsݔ'xFSh ç].gqnbCUe DxiE . }xc4<2J)7ۿkW%nT8No";)ɻ'wyr:$?k$d$F4=}=7Ա=1]F%0ϒ:J(Gk@yp6,}NMu_aiPFmB<1D37`p%3AKD Zw׿$ 3*˾\ ]+aߟƁt QJ7x_[mZ#:sZd$GjAh )o˩T^d:֡ ުoV-9;!>Սp+.'yWeQ=Yv|:vFZ#{yIS_ɯW= ҩ q1G|2t bvIyB$,Ɇ0ELw:h[B}舥Yid v`юQDIGo(y, 'f]@i97>^}Ɣ#{&樭]>yks|zlƫ_So|?`o~jyѽ^{QSDh;3U*OJ3[=2uGLr\UMk\K ~8x+oƫĐL!sbTG>0۩N^V!]1sd(3"ȎBcD٠wXMHyJO鎫QNUV9 0oc-z /aK APZM:\j~!j`uZ^U'_](T_Sr [3P-TGj -Npbjߎ,Ģ8Fr IDATFycd)j,ߌ. dũO1uD˻*Nfe>2y6ԏ-먉%~g Woܱo ơVony]kA[vPYiYc#2Ny|nXs-nm Y޿_wXLw=?|p}'=w=aNLD$է}TYZ/ t}~u)C-]qv1vMӔh6(Bs)tpOXġ ]9%(myt)ǨNTml?uڱQwZ>'ag"Q~p4d kkm רd%_cOb4]27k%Yt5:52U26 18urVl1hGSfJNހZ3V{\]0E*I.b4sGˢѰz\Co+-ٚa G\%=\dJ_qM4; bi׿zWo߻G3 ,f/x_|ˇ?Ǐ.W<*c9Nn߾u{=‹>j{ǫ&j<|uu3_?ӏ>KDZ*yt}K֗ZpC U}w$`BŌi#Wըe]3Gpba;#f-OWfvBpŪe 88ak|8tӫ/@cEYbMympn=\WFMeҢNmn V'dQ0|lvR5tfHZ=m&b`l|+Aq#N0dM*P^u!j#p "9|18f.AVK̠{ ߘ! \O$ĘNM &фVMw_+0e+r͙D@LWjGa֔'wSut=+ `4mJA<'EA Aj,^-C5Pڣ[#_~WAJ|ujHt{*1v 4ÃU1W_|?˺նxAsQam>SFuVo&8MV-Q"lH`M.0bOrƄ3nD6="6՟exX`ɨ7F&QuYamžaIOn@K i=pD,]IF!y5\ro2!Rχa,l~Z#,ڲ2v1+u!0v چ##`Q_RA49tMܺ'P^oAzH%Cϰ1-%ā\DM?mc" G9(2"Jy6 >6^*>nS;VT2v XY=UG. +%qehC5X@l@I بj+<]iI]|d;Uz A9FD"[XOTdE\gPT&~B XH,)lcN/?wGM~ݵlYν:ݺuŘ_{I+t:ɫUE٧V/)ScKHÆg 0Dm(m];mc`D#;:Abt|Ss6,x`[jkW]eUē~CjD+`U:y{Ԡd]',J9Nlf.Tݴi-Zn($fV/D{ Wȧdjz]&7YÊ"A2T`0Kz3~EW%e>ikU.F=%(f, Ih!܆Zlŀ`2$˸f ;Fٔ]) 8=i᝛Yδ ][c4ᥔ@qjZ'* \;3+TEdڈh g1\Dv8(BS?Iv(wM8 rSM5WN}? 9f@uqtM)Œyή˝ƀa ='42~y;< P@QR? r:KWo￸'Q%(#JZBYrߖSx| '=V*uS/?B鳄\p~u.6\,׽t_ XO00ң)`mޗ4?)ti:"Rx n">b8鋓i$Dz">%Š~| 75=gT؉Ƌ&?w1,']#~]8kua㐆Z 9oyPhY.I3JIE.anS2mSZwa>c_J[ /h)c𹴹уv~̥5V _`2wN믍?K +]L .!!ޯ~~gՅ"f`zƇJx+ЫΧ}Zָ_NWv}ׁ˯1X{f蝠 L.ՎkD&Ejlzh *-}#r[$/F&\6p%SÃwKt8tm']H6!azLv_WWW/33{AFDmRIa1 ,d}I'е'E>:~dP#Z6}A9Qk ꈮBW6(LDۥIC6mvCmW9PTLb2&la&KXz{(l$\t;·YTD!,dn<˪Zv2hަgڨK/b>R_H&ql|2 `BxƄ&m(XrQl-q^oRd_ωIF2mk•j@S#SփwBzj/^J;?WW? q4=&2⽫KEKûj4y&`lvq"pxqDSE i.'D|Z-0` +/muC{chyVr$({ZRĔA}&|FoU$d!c:+k7>b\sKql$k&v'QM?9W .]۟1 AU:*i:V`*׼8e0M"k̵NpOU.X8n=Ҽ4UݬE\_ۓ/,tbLn>?igӟ}DO~p>-5m;bVϦ" K4ŞtWbCB1Džڋ$AkLJ qިn2TMo:aX*_QU\@CiWëh I!WU=j4IT1FJ_ݝi.AGG_{ŏ~D$w0N'?賏?U"r(tIdVO5lpK ޤPP@ޛg XN-"i″Q6/$؛&[jB+{]1tW1q 85DP(*iT,+?,y]frY7/qWJ ѭrvA k/D;t-Rq }N,m^v+NW~T`ZQOG׺Kԓ%))!T:] qʻcGTqdl~NK̝!k49d%=4a*>/GcPaKB +'y *FѪAWʭt8&_!N 9+gUʱZ0h$d .U9ZbN4ee h }w5K*L~u6?!ǿ3/܏xiJ+_y_}㯈γ>s Xtf_ͧ4 RAߧ>)qGg}B*7>/ͺ2SG O=wlXM?&݌ c[⺢CO{AFyuu#H063%ۛvQzd^i\|誔)cZϙnSW{:P¹6xzș]xү3[&C-@cVEAdL&r”sNYHzwެfҳ֎ʍ]8ٮd+O'OC&ABY}ۉ=^ɖ|5,uk"xc7-&K i2m)'VtKxiO,a.yuOwcM. >ڂ6`Yފ.**4E_Qg?bl+A^JctvK 6+^|`Ҕ pֆg>|UF}BJvKBb7WWpa&\x`д$SJC"]E^Ho+na(1ŋtL.N?.1s&L8L[VuϫDnzU|)k7|B׼5`&(y=. LRR3iG[; TSu2ܐvЧINw0U@; פ1qL92#H+E("Y cF ' *PjN=hDgT+3 #X[<(Yy>Q8EY.".!p쎯 䅿is&j{7O_NF<z[l H~{~-9#7ϗxM|6~=ETZ JCGoxau:IkqU ,C6ک\KgF5Ntt*$R 70Lmtj4lBV̞ [斒cÁA2e,X0YupHW7} U%&QC>QtLJy:E0>jRIR(]oU8im*z#hE`q`"u@,zu8[3:9\s_l5/nt`Af:Q=,ɑW2uD+h_8R诼prvL^vĝ/e;/n/[][XF-Eh`T- ה#rsS(o \<Aܮsk;SXV:-BkegeXZ|/=e `xzP?xNLꬓ0%51Cʸq~(+mqariجpΧP'K*ڴL8q4@J(c~$87q@AThpOMrǀ 9fN%.woD!(It=e-{W?*E.??׈"QKEO+lkJ*&ۨ&93 xzp- >5gF7P,0cLh[dDf{Ot)\d%Θ5\6Kjg?!>oQknk+Z{{(pWu=|j ֚[ Ds aDYLPaT@6g4_L_[26/=ucf:zªRTDJ@ ӺHWsZTh$mrP3*$sǓ^<$ѱqg(3a9d!(6mrvůG :fjՂW6ڎȚ5+ GHmBTVY"tϗ96cQm6?0c8EQeSw܌v* ƪ!tT9?Vƈʍ{CgNb7ZOɛ+,ap4}3q;"*X ^tED I5O6hʄYj2ii߇THxi.|DǪzvMjP%8Lg^*o٤,Md)YWL"`X5i)x7V<`RDie6^]=}׾~;5 @4_C|=ỿ*ɝ3$k"k;)T$m4)"!UbU(|A̼iŠhYB &틐6D)G†cMKV5垻r6]r.S039v^M!(W/븘(_Mc \bD| y*\g0|ʜڲG@5d0^mKXu,șMcƢk_)fD&&i9<'.pV逨_ktBx7D.xg5& F !엵H߷UtFGiHhsڋ2M_l5{K@;D&uLF#E֍SxQHnɛ@N;{tɅڋV|.*OrSY3棅k ,pOI IDATf 0ޑ<:5P}yo|/ŝٌۭс8q|;o;OzfXԪ¨ŝ(x8 ǭF !a oa S ĬdjHUW3M%*űKrxMvzgfL҄Bs^jތ @׋;xr-fz[ol`:%nyW E‹CX>;!W8|9<9OU $, u j=UglPW\R+UY4V ?SސeH [)l"Enc GʎVVuTr`}Y!y%LCaȲA |fU=y_|rqqsϾҳ/|.nf1y9My&\XkuF'<>Eƃ"p+U* $ɵ5V.@./6Ix3Fla"qcLz|`/d y<i"3Iڬː` ,Dڬk*I93' jz&Jlݹ/ - CT06<թӲ@%̵SBe4p ]l uP$D5'C ULW!l| M&.?z+H7Ilj~yng+Rv7 5ɨ'nVq6gT;yU[ + ٖ)ێ/>~# +8 ͬjTZ(+q+Zp5 ae#mZecyU .?nTj@MQ=PWzue5In[.yrq\؝npٺF5;Z girqbVu'aa-;~E繣kȈ(ibXljh#?#q a=l&snȎnIuj#V&noB88sI4CQy\oYX YIbGU5 7Tx?"O=ܚg-8y#ElrQlu{K.9(6E+%L% >6tN\,ÉaBOz3%Qް'|NJa pF&y&\bk5BYx!]LW)^3;1ʤ('y`*ҋP.fT?8U]7}"&J<Ǖ܉rz4UJkmeí}dǴI^PGY7F-%mYg(lR\zĤt@~Ӏd,Q~,Gw=8FMu1*XnȜ&+/hX>vp >O"ľ),qP(RFO|bW.Nhh4lf>MŔa*kufjjCe֞jv*[ݰq5 U-(B 2@ MjO岿R{D,=r-_AZް/64xHgSѦA-0,)*87!}0HhVo3Rw hsV9!5Y_bTU'wTUb[Qh֊xԊC' #_7KـB R[/RhLPHlg՘n2P"xE+H+&?Z2jΣklLxw1| OȔ_Ȟ-9?/\cA & ]IܴNΌB5wV44(QRNj?S-lF}UaPPWXl>ӂM(Әcw -HUheAob%$ưJmtXjTkRbhaRןg5Xw$ mP@[!Vմo Q7A:$hKdžAPc-L%΃0c/~wU,3fVPar 7a,,k}+gƢM*J* " s*m5Q[5cQ]ͻ _#zjn!)ȱ&1^ɭ 򇎢vRJԕqK+9{_L4Y+4/dҘRyLicAv,Ri(;4aR&M0cҏ"bn&HZEBԺ[ v0u lhIv/o=W [jBNu[=~&AvKT(if)dT[jͮ ߋփ 8,Cuf"ϫmo) 8)]ZAKV_)_FNt] \Uvۉ%]9͓#C3 ḱG& V83e2LUVL0'RYE{U:g,y/3hM85}ClSܡ+7yXjS@Yd:E,0߆t8Xs3]gp ] c؀yoH0yMT'S^Z9 1eoy yYRN0A"* RGL~2 YC=T4 p"^o&1=ߡ-E6|^:ץ23 y {# T g" &I8bӣT* ف29Z .M[mVܓ 3fScdF<9Tz5[7mR i-u'`Û^I.~sJ:Юd4m9u]y/?Zjjv]7gců+h!i 潻qHv J(`/`κMIK$)u.ÝۤLa@%3+5pcz2kʬxU:OXΧŖSIQLu\;Wx1Gj[BÃD"zɆ>8ZJ9MH䦕ЊWv rPl9BѨ^]7.70t!Hy1s6θ;6rJyzy (]*tC$^}ȡ//'; {mt*=֙LRNK/sH*#>qpIHJv^Y'4rE:㰎_蚜@KO)Mΰ] ݢ( |e2[w ٥42:M2Vx)La4ļF dō2 mB7)er4}s`,,Ms)xR17]&QhFM~q?Z8K= MFfk4ƼO9fDo<Տ}.w- 1 qT3f$izax|S,-HhLd%5. R*iG̶^-:VSL9%uihy>b&9^JrYq [y!Kw8 ih[\ 6\d^˧i.z|]NʒD}zNߟ??GtmaA2F )JqՇ/ fvHf^^+z,ٴ4A/lZ[\!9hZPذj)^e<W}cMW{ y~?e \/[~m=^e \:4 Fti~MJ#e)ĹPzug"\\5 4@k]cVUV @Dj)X cP[)_TI\WT\7v߈oe.ɎbY)ǎK5}32?ħY1,buHYQa.8tJ#X1WFɊRhcs\]]/I)҇, 'Oފ^oGTP +b Lu7Za#Li+]~{`0WJFȺ*,TKf(<sRlncY0sa B!7nޖN(OPalIfdUDxGxCz40-xh*D]_?yrew )0/ûk[l Cik'mM'SC gzE|>ӋZ~r[y(~bN`%SC"I gM"iaG6wO H \ZBD&""?ڰg> 81tPI;CSX\z`R}@S(CF-:mQ1㤊%fؓlWj&Qcv/e;苙h~9w/2uY0IXxغ4^)ژI Δ9TEvRrI˸'R}yGHe^5D>:a LLҜ4 1osNФsyqsv^|_°|%^^i$^TVk`eS} R[@HƳ9 ֊DHk&,)S1rln0,"sv-U[X!Qگzహ}-L#GэM!j^pBMڑʁHC oGb 37o Nː>!%PlKsVHv"_֑ PӮrx?Ԫ1=0?%7:(VyKe ,r3}*,uR{InGP({tn9 bױ#B_(Kcg87jIw G|^fHi^ߓ\ @  Ye MX8{ɡw1gf]X$vsAXpy-篍?Ud)5jW39giaaaUj~l.J[>Qg<WY܇>yQա/GU8 ;G.e/_Ձ|bZO=bɺP ='o?otH4B׾v<Ȝ_Ht${ݾcfBx(-hT2_kȖ 9JՁ;'זuJO~U[9@0D&fyE\͵J\0y4 ]+3b_d4.kh&4fdC+hΞɣ/{vʭ@{-tzoFpά4%m5ֿW:\/2s;t Q+'IW.X^22E~)YnOu8@^]m"ނ@9ܙz5ÃftpI29ػqM5C{!04,)4TLZ2x,~/J(c0YҵOY\֏Zxcg'ߴ"#y.dϚi+*4(]B>S-(^ujR%ŖehBek8)gpG_k^%mKtzvJҎCBI_w\V{ I.tz+z!cΫN>nJa .ٗ3Oջf*/j"oZŮ1EjXI'Ka"P-h} =4x5m,Xq.@$Brޯ9B(}Vϕ4_218q^2M+w]V"vW>[Y#e*ZWuZTzu\E92LPLJ[+?ؿXlkBp%I xSYCx,Zr>N>~EV˵QM+k%VJ 5{؆ۿ4Ko-O+,3??6:3Ὢ0)`6dx:歨B_M>g)䚃S4ל=F^1c#Q#-,M'l&6{| *JGT n>R"o%h쬕C!nuOʢ^*:Liޘ2FjZXcM+'>P\J$lr>U?cg@WT 7jǚ:svUV%Sr䶼zmdHh;LEM2vوe_scOpj0j1[3+E9a>N]Գ&2ʳGD\AuiiU`ޞ/= b&o/?S7T âv9eVʭ,zQ Fv'i%!Z"[fKi'kF#8MDm4y~+|gTgV~d KuXק\d\}BL%i KsR儔|&>P(,-EUa(ZG|7r!0-u^>6y>,m#0ڏAp>9Q53[=i@my("̢M/~} wH)%0pWh&K)v͑Fd2<>ۣ)x&QlTK%q*-sѥziӱOf +j Ҏ:ّC2Nq痐 IDAT15M4v*xW%{$/O!:/frpm[`>-nr|v%iWO\ :LzhANoo SWLC^xxIYH oS|y cIfa>bͺ;\Ӿj Ԗ*Twޓɹg:$/-NLL`7V9[~v OSD@y4H{Ζ2$rOf^fJG@A&y) Y8 7?ϿVkxNBSk>r½?ql }ob;[ª$H`Uhe9g"ܧHa{tvlMnZ9aCZ\&JF'u*Ç\C W$i|}[)PVE+ɘyeZmqU0rUhJ/ [=s*pl[g+yfjZAK6< PXCI,LS+/r~k!8Pg̓OʷpfӸ2+Z6r-z 3n{N&G[ NϨL3c bnr Pfl`|^^uqPt7&_[>A ʸC ΋|LSw)5E 'H;>TMT\ROFC+Pj$_kTB_+?ȧs8) e5P~δ[!x|eEq'4Kƴa aU=lSl:.3fYv @R _ݪa6< q{f =vf ?e Wezk~@bXp>mbL(Q.YxM&~j"N1G˧Wq=d]#͂0 ?~5O>]} m_YR#GV6ohZҋV1@enGFM KibƼPxxq,vucBDC | h`zfж/Կ>?]i{5_!;$`Fc73bBq"gi@Hr/1% lT?fKՒ}'yT><jn9Խd,3k!yNw6EOvףјYTWslFzSUUeѼzF\&p{ ,yf*jn68UǟI6;S=RɪdR] (3*H#pيv0-h$]5#v%#J;vu{0qkJϻy6C%u^8urpDcJZsЮ(Xl!>}Rwekov ZqpCSr}JEKဠD K,=?uf:n*aW;NL, W]mU]P޼N5Q::)MG+6$ثJzhM<.x)Cq; 9T7!8M?~gC\ ؔEȃRf8b\ٴVKO {-K8nRp邞66qU&ǻf$'jA}G<IXjluR(YzuTX6{d;>˚K7h#ށ7F/ddMwbbb7]j9] QR_F*GW/lI,9ژ <;5cRd\+FiQD6nZ_ZJ}0C*Ar$=TiGϝIHWLnUYb螱#pݪGs1RWq߅J2t)Kmq[5fT&me΅L]L}C}dAQ5Qe3ں;NN Rf8`xH}qaA~/wWe) N[#,SHW`܀ww|߆{=ION?r1k:qm:?|X"Eh0e6eDƥWg~V5ˀQy][U_K 'kfp_NpSno+ɚyi#*z:#d\2/KftL"Ciee)*A^OGoMRcM鯸HUp菥iϬO~4q&rKu M祒'يr.1&,?z(_XQ QmXiCʛZAXY7D4WBgżkk,X$W.؝:-|z@Ԧ4ْeȠB7]+仳gHyθ%tf.x"$[!g]P[ׇ5vW|? Gw ]B!u9v+!J.b`& 3ZfȐ6'f`T4F{aG(?QvMJ7!iȢ_K1;|љ-ʎϿD2Oyv\e )u0IދF k .֐쌽y TEIޛ_t>:7U(cdޡAzs^W  5ѷ4?a rrw0rq_S8r`*7~?5R~g6LΆ0s 'Fum osURd5jK!":Xb ;tR SvHvow.<[AzAGAv2psA"=m1{D>$:GfdOu1a&:}Z,*La,YiUP_ |ē(ݸ=6ṗj9|ZG3qPɞj9#M5^gyj\.v4Źڭ;aӸeNƯtf vv\9Fqs.i@a4R?cWi`AGE$$V^SYb T>b'x7OtچȲ|xDɾ ܮ:s^aaX x6#(Xki#:a"Ps.GyB*w^؁,։0Hu5Qv(g!`;fIPjw] A21k>W\f=z|Ro||˵p["W :l?QVJ fof0ɞ̉j9V ZlT̫DTdp/AYL*X dB}[' )㬀S+)P _VO6&t}>#BJӪ|Gyъ$SV0RK@-'Rwˌ-&>դLZ,;v$zOB51e Û3.vs5=o-zkWѯ.Ó usLt5l}YEOyI "2($ xn:툆|};%_sV1oAr[O{%j|x/:u$t!̪hb&c#Tf+[pe[-^,tvo!\a(o?EO-##I>/ OƶT,|sM_cT<}6O*=o_zz8'd.Ect.xL`mU`iV®N]0%djf5Mż\ԄLUUD~Z:X`jU ӵX\,.>5b$Nl/>҈Um\"\;oEmC[N[-mA+}Uo*/϶S돧e%8y{ x"x4M7r,ԟȑ N#s dO@Uarݞ4`!~0Y^";Fkȅ 㰨嘤 m%Q߶ dn,pg#x|x3idžޝx:_sqCU7# 3(21#ϱ SqvUʷcSrN1gϤ Eރw<7'}Ȏ(ESϼ(` :^iw=˃ (BFFUt =ɓQ+iu C;)thߥ$}TӺGv5eEw̷gTB^T(c,IlH,vIA8: ũ*}Fwݵ5Hm&L 1T-}}؞ڠYE_2U6B_\uI E0en ;;?}v=n% ~LU ([ ӦJGAxbU?_<(hj))҂z~l/,zqYՌ|(R<T A29_ )Ccr*Dz_IIm4z +"<>nzbOAh^C "ѹ\ {#؜Qt2Ds6D0\qGAY_Q,ѣ6CXcl͇Z@d+?e?VjMXuyKxf+BLl|xTJt@ʎ/z|2 =?vj9_Gٺg8vs&ev]6LwtWՓ㉪Ay_pqrWQ;Fz(+pK*dsSDM>W,`{Dab頯xZF󣛛(M<_SoZLUǦ7E0T:o衙zh6S!2fI\\ :W qQ-_W$%:Bgb f5}<*QV,WLu+5[WӖ磢 ,Ŕ+bJ2\i' I) 1o0iqLDjP$ >*-P4LzXF-EA3|\UldO\G?sFsMLV$J.:fe{n.tL3M=%veȹqb@1SȆ`cURHWy#z{iJ_5W}@Q+`?ڐrl^$LI; nzdՍ::KZվe.QV'-W%r$nuLQKFXWzH/)\Қ9vPG" wH&R95zEz8 YDBl%ȻT & r-2~Y#mHZQȬOt(,e[94;OGފ]0Zƞ5&#kOy?&kC9sA1ثz6vRI^|>Ra#i8/ y԰8+v16w}!m̥z 0> ˟;+x>JH?-l?%>Ucuy,uUo5{ 8v^SU}q+leWNhI;nnԿ/cra*LOK궵tMQ΃@/DB Fֈ8G %َi(2:kBoꟺ}2W^5)S{zU6Gn[%9?>Ї*ich1mO7 D DV}Dߜ@ GȦpDv؄Sk䴹P` |!Gpq޻)K qb ӧV$HY/M*[_=yzjdu&+(lwTGFC\7[8ޥfc9f1C%HHa ?iq޽hWo l;ZcC6ɱxF^-RXd n[vU_ɲZY ͒q.X!wghzY\p{:;SFnKc7iJvÊ~^m91#+]jEƇYL> pͨ8%c{'nG}:bԢ5Y)KN-6UK Z!8XiEM(;ZtN! IR޺an' C(ܢտ{b o:AH>wBu}:.4~i$ 1IMߤ$ P"VIJw58MEbԕˣu`n^y{xCk#2 xٍaXXO+}X&"#KOxT+]Elԡqͼc"aB=k-;{Gv Tno\_fXvQNL(Ӳh,9D[g~\h,+unI/eOЃdQ{PQ|a-%PI#""#>x='՞k}a;LۛVCP-v[ꈊK*[ɧX*,NlơYi4E 8gnD9^ݞ} u]{g} j*܋L\?S7Ŗ ,Bq;ʵDĠ#z50=1N'AOx^Xa}2'z sbUg) RAY!2ۺ/b{_v:Qޠa+靫@d^vgUW5@4RZ4}~SZ aXg-WxYc>qRcmsTZpKfUd>Hecǽ%ikw2l} ^1 eNÀdٺ|k_lvymd\\61&/}j)Ovq޸|&&rh< VvVYSN^kU=YeΑ#~@܄ESi(d/?6]K=_(3Fp,<ڕBUU %եaX Y-։=ٯa2#JO_SJO6Ş+Ϊrz7Lp{hMEa?=c25d@u&1R +ժ tzt>'}E:5Q: $.( }Pՠa% Shrd3oE%_OzlIb1 7 ؛y{q]ZYkһ5Xpn`XT: |ςiIf!j^Ӧ45\|5!Lvn)U8l()*CZ!Az!e 5Vtjڧt%61fd_lAԡ2Uy(ϐYO3*u$}s噲) }2br]cWDXb́baR^WP &Tel^W6]Yw0+mP1v W ʊ|$s#1%b`,]7 w C4g\'$& lTμ-d.29m[NZ9ТǢP-"뚿Y'@J/eC))ucdiQ[`T uڀ]:w^_O.UZrF66龩vZp.vYw]I ָIqDQ[GB࣋5Z>zH[8,얏y ;,-b~}CU; "?LS%ӌo8Ed0Mů闁ϯp~dR%6g|Eg$& lLYn"L6.၍`ds,@ۚT~I \ `@T"F>#;^^Rz\f==%"1Ր1DjASPZ A٧bC_ٸ7%rp6H4d_"$hBnvT/YEz wKKL+WM*G"ZVFK:#AeY0aMp sMs3-WXw ;ڧ&[$NTȏД7@bPLT*m|5:F1pxR UZn&-k#vX[aLE/7ԉot%<՝$37Dx7[.Qȋg(twoO6F:#>߯?+f0cQ+9V tbO%U}Yv<&j#t~vPMm}Kyu?ҧZU! eNQLnH[.AqKoW߾swk "C(l-"G'ٽsM+ @jzqwIFjVJ_dIУF ^P0qpFqlH}7,;lܰa*|z_\Xm?1ZNձL g}E^ 'ыs%?bGWz1-h%]G6>uj` 6qE"QrrHHXGMY=pT?B0 rQZ(^I|PM/;AEl% AtRēh\WfH{ΔΪQ''qs(ʕLirTrxfhrڇ1 BR ~1p(a cy>XddT. NeXL^Y1T|u~eF!AB0<ߘS7Hc#cvx4>& 2A_IXeOLs j}G *8HE7Rԍ9Z`3K>wҒߔlzCJrL)ͼkc{a`&8zR=ht_F͔gy]IqdNp fhQWA31e裓'H;[9ӽjp7C.+e黴Ck(y&ĝK(!Z{S(jrd@9a ! 1ac0컮ՄSfIZyǧ: 48\셡A, $& /O~;3nin5 vo =ټ=LǢdRdP87u7cEH[#mEӀ{W\ra"{j75#˜wA^f] uSrsd# Bk=Y^#;n쌶$3v (BXJkѽ6j3pfsd"d٧󮢜+J5H:BcD.3m $'k!$@EUl;ؼ(ͬnʁ`GޔK_,=5v;gq]uUsO^6zvlaU-GɎToT?MzRg8nY*K[nu@Yq%&P-FG8pMTWi  js6C&0$/Tܼ P^{hmB/u숎1~!$PUlǘ;ia1 "}4ӌ:y'#3mŐօ "b6Mq +ϛee4G Hc7a^gĬeR ]5/M‚Sp-2ɳ\>絶;gA0+GVA*./y4M?MZ!MpxGWqnݵ+9/apVy 7VjҦ !H= bw0Kmoj͞!94+ ŖS.N@ [FjA3~ ZGt_!{/#sݨ,Urr!zX z`eH#`oqٙYmYj1iWa8 <@oF&s5c<ʎr}<=k2zdch-íTzY b9ǠXMDD Ȑp8N o~36Z*IKNXDF[v%u;Q]?70n4LfĠ5}ѩ탫MHRK bRzxJB}w6qȜN~@Jx2jHXgd1T3<(D.AR8nF\GnDdR[2L@z>xDB? "ğGd]` l? 1Fu0Q{AՌ oG8->.V117HlNC_ϹqGJ.OfdC:{jŹUk¦ U#)q8PVKKOGw#=W#X )8KQ~3qION*"χ^s S4dnycrLM# hP@pzQ"VB\<QYDM9Frc9㉳꣄0G2X+K_\ ub: w6*@S|0߸V󂜆oYΙc'lc,b-an:^}?rH:_?l4i6ǃŔBtu8MGb\j gO+iUG.'gRԲ 9\W?&yzFsai%{>ytEZ >$qhS!cm%rUTWUHՑ᥺BޥB m Ky 3Jjߎx?c|<3.~ls Z gt[JSK\8JFy{ihڰQJ+9.YKчC}Q}OS5ɬiLTD~)PZ- ox:NzPu<|ET)ώ'WT&Q\.X_MhzP q OZ}Oycʵlש;6T@L(?"?cO 7窕!9HRZħ&7xQ~?~ϤS_E1+ UI)ș*6dr}ҕ^N kO"b@~vU "~\UUsos8hZiza,cOԙ P~*AzT(7fe GdV~3fR#Pp$A*HY*-Yʎ*DsA(5|>8 9=g(@+aR\&Oּꋴnݤ3:?? SR<{RSR?]`-T PIK ~׊fu.M4ȖTK!h\CQ ۾l@3Jce1i49֚C9y#iX=wj%MW-s-`Hs$}LybTY(XCDw'_!TX\;c#/ XH'M.7qVHȻAa4+4@>Lء;]t.'Z÷s Zݴ(Vؔj ;V)BdxJP0J`Sh.:4=Tcj4\8xf5Ā3gw7]VlI~%Wz%Qu}/ V+F &n>h$""x_kFPEO"~^&~9GkYU.65pr=݁D!l:wS߬5 P.MxZ_]e\u4YK+oڱ9p|/i+!]q IDATGN̏b ROe=]/C Ӭ'5^bԎ: ??qӬßYŗȄHq۾o_cӚ?#]_XF<&2KХA\hQ \:$2{sq ή06XfWcB oT6RBnCoHs܉{$fWXBgmq,Vklv}yy3]D6!ՒcRTʡ5Vi5#*>a?RH ?^/tD{

{88刬-:[dd[3ywKbƋt{j!sAf5/0܇iͳ[6L=F ʩe*M}jQPΕqiTlQ*~ R^j!(B[dx־%ÒC.dryI*}z)J+E,"e\onV(ۮώWW6Jewo_D]M2ΨKb$Lbe&W8Ρ.h A/ۻCzHDη?XcG*QS&:j~{A3<!r,[5Ld9; WSX| qo-pX : `O-գ_ 8N)z~vP̀V/‹7ntFfoG8HjXѝ~-W&-x'40f[KDSC^P+Mg\|gL`L^hcϗNG-Œ8 {RܗLڴ·*?,áCN-k{VMw&+!Z'$+gV:7OxUl@Df+voS0ۮtdj9n#y=;%z"sܵZfA".p0 H)iʑ3xp< 8^GqۆԂV lq)ěy3^Ug2!PƤ)T,!lA e f8^N /#q6ETxizIKAkT=J&3Il1T:d?{״<^ڮmgii'4 7yCw2Ds%= Ja%0-unix3M'GasBefTBo*8* l۵NpBHh\#젏J#tvr(u@JAն.f#Q3Lܽvucު3'ā a5R-O=dm3- da]#^Ys ,II^I$=}V]ĝm5r08Ce?PV$-C8}@zؔ(j:vaJ[U/!"zVBӔ5|̄ȣraxTl8{ p>rx{}+C]?L1'-y>̗[j 4r%v`_8AZ=3Wv8xp /ឰO6\ӥ.k }I <#AG3 ƪiY/l2>!P9 C3bLGS.0)GdyF6C_h.W%28NMC>j$8l?zSw3 ۞#,.9;_^1h( S5S2KܴaAM~ Z;;Eh7 Eű&E"qjLu|\&hAngAϿ>K:I2RH}*EH 9H0ZRC5D?b;{; 9\@b/f5O>U={'is[bP~ t[wdWGHO3?{4c|_|M80R;*#IX>{?YlD3O~<NAΫJ ^ΐj 5Hg:^cv6T'Fc'EoP+|յ=E}oJHm]D>YD.r/ u14ۖxzO,MձMD< UTma݅nJ q ??&GhTvlO|i,a.@"3Ǹk v/g7^]ZIԑZ;M^ĺsJBF|+( 2b֦y:#XT=lQPbfWUЦ7HZ]=I- uP^IpN{wWN!YaBi_ 'ގD `]^oZ4c-:ZEs׆bcd'Nҵ$-mxp]{2;n0zdmD=YXUSkiצּc^  jĎ1p2u(\_h3 ŝ#/d(*s!$ltB|Dտ"k.e}eL~?5}M$E^a<)&){^ 0FUĒ 'Ш  MN#/i ђVa!מm^eNdoڕ'Ca-꥗w‘frIlԊ^|0}J?vm,cUk8s1 kݜIvCI)rJ OSgb&qPKK(+]XdYI SL`G!V 36 F_7=J4S<ƹ'&2rsee )._ň nW^.IdXEІe|VuCċ\PRM ԇUP(-Tή^d:j< uN{l@ >ҷRԖSs%u>q9YCLِ,ؠl^0Cb9_W4,Êr_0 H'LE{ʼIB vCpRJ2(1i 9BzRlay@F{B sg65WȵcTN2*Cv*y ju_ML[Bel5̔Go6n}ڸeKM'CEzOZFjǭ~~ǼpE&GwʲN)t뺽zl06[=(FKdSr-֪+ xvAo{ @b8Džˊ\d] ([^`B(V)H_!m9Z'߭mo]4:.ZP63Tޱ%gk% @~u cuh{AMh"n_\3&1'){}lGO3gCU`"d|O=k`6XkQק`v+rcT3\Aӧm IDATq˪@0yacc6} \]{ل1;saczA_dž(g#)df;ar%RV% ڢ8pf!Z/e;4i[m PP7oO+8Nso;%"N{xgsnJVKRo"wv[`"-n~~GL^ͫ 4I`&qbHNO{v $/>5|vy K^>jzduӄڃf8c[.bdcX[Kr8ħGWQYճ1;c뒩H|H]/dMQك{gHa'xO)ITӐ:|^68#Z{wo&FƽpS#βp[IG1 TnlO_Klφ~v)/}+G!Ov%$3d YpTiBa'\|j.G8AǸG""5`m{GO:t:Ӱz[1UI lTУ{$p'_ ? cŨHΜr`4N'?jqMgmu %ȓi w+.񱲟Q_F?VYc]4!|y8/pa7(620:)PF7JuxJ2Np߰ W*"\QxK!g=W1G-.sb\+VUrC`)BOeRAwFV8NCߧ/8^U؁jp9'uR;?/'aS54R:>2:Qܴk3XgvтJ\0; ip)Lf'6]U ].]06#ʀ"UB@=4r B saOyڞ;6;*= QPri1=u|÷#KwPG)_ܾD#ރ! Ep]M2} R!9 ]8'v%vᜓ{J:~*ti5c]U@)r}&wg`8 ;/VRe_A΁77>/>m:tx#w |g9H Ǘ.? IʃR=jS ӗٖ}[LB(K;܏gXD`5%cΤ ԻRDNs=-Cu\KDQ Q{ S8o>(HXSݹȕvY$)aM[3j,a-qLh}Z֢!x[h*? Գ7f5H&EcNw| EC|;1adKـ>+G8hrEAh"mǦkGϪ3[GL< #_BW=ڣb!}/UENa%W~w]'*uieM'Q,5m9|) ԹPnFdKD= {/_bþtcڡ~5O0xtԩA)W3/D~VO NfښpFuߐCހL^/z.ALkx ,g$/9izе|T?3,=?sN'DdӀLʌER5CeäÑ:+-BDDD;||TDz㟧l_*\{*E_xqਟVܡe}ˁقZgM >]o^\yIoX-YeH:g"OQLr1(T ]hٟAIZQՄd|<+%oɇޯ6Hف\2N3lW.O19S/7S#CJ^ỽٮ# +u}/f|ne❓A`_>B4rc.EǪѮ!sf"O͂1KiKy:' |G>~p~)Fz[T\HŹr3f!A{a)c/MMfkc4Xq;wdmr|eB]EQ6%\kCsF!þ؆PUiسyπ֞&Fc:`Ņe9jVd+ҎJΝ#g,̝D3D&i/̔խ)4ٙtmإ$S CtYӧ*}r(ܙ3% = 5Eb3ч C_sBGn@C p%Ju8OC.G'24/ѓqO+Oٳ }Kh*a{^CY`$%R m[61LU9vanT*]cJ u\7uK!tъ(&=j̚r}FcY&V)c21wH j[Pr cnuʧ)-OR7Ɋҫ]I׮J*?\]/@Q}m"¸ZRF|Ez5q A;;z*>A 5F='ufFtb *#v2k/XM#?f|nN0aH뇱EƵ}w:E&HR niDŽTDcf_.^00(2+Mf (E΍sIz_(rަٯcU&NAD?vuk p:W"dX,Sa tNNT UɵmvO4̎:pg ^h|~+Qc,η mz?U~SOaXa42F$hUT(Ɂq\9>0V6Q*OG9M vOD×j A;AƩ?3Y⿵½C'ud[Žm;ʆw}ы4o X{'=v+5CoX9Ѝ?ᥝ[LAYI@Y'U 췄]R]kD~Qޡšt5[g`r*W|mfEB5 f )v,_<K>6D׺-[ nӑB*o0eݲ떭?֘ k#"[R[[YF$G7什.폸D~aȜ4 [ ٛ7v 4AsYft.Ƨo\_P Op uB.*k\BШ6v`)V>w#ڕJn GZOꍒ.M[Ȯg#ev>"Tz Q\2E38#btYڼ6y)*tm,@ox}ByH=NY V(b lsH.wo][mAn]Rg8(~摒>~kO~ݾ|w"l30,N/Fo3/KƆT*a&YbUsHX|v,hi>'ԅ\GJV~tAn< dnVmG6Gu:s3曐My&?Hs s;ӝxk#M2Rq2˭I 8n/OT㸁?b*k9ڞ9|C4I]Kc%xaH᨞Wm~T W?O@~e^-Iy7 Ӛ;1w[lކQ 0t}StxTcBWǝAZspv"*+F eKs. m5Z t8pYii64ˡm?]ݪvQR<198Y?rw̽zA>MZp,o^ m*.>-?t))`ubBLP\l!!\~hk}wKktΰ{abC7UzfY&dv UxS-zyb667 X&I224Tr+O!AYO Hx=y2PgUeno4hB.TYQ>[ #]*oQa~}DM5hPWI 1NF5"Gy0ԪZok͜ K* {u T3 RЀb܁2`E]e")<#?\k]5U~KSQ1XrUeV)5ݢi masru NJMHR˜Q(e1 n&Wq"4V_DTL*$TAً ̘ЇZgA(h-P'F]7+{bq F"nHZM~aa 7̜Og0)k5IZmh,쓅:Z2r`<ԪF ۉ(uKӲiḍ!3eyk|OX wa}IR&uԽ 8XJ( nX[=J!Yk/[2׽/Dѻ25Kί%+jlMD'QV)<$jNtiuډDNJ,I>wDϯ-h= !xkzlqV-u2=ȱS#08#8VeCd X͇${l@vN+.!~D˸/jq@W׶\KodU:j!7ih$i; ͻGnmbtHL2Oh:8!3 Umc7m .0M/>$2]F:~NZlu9X3Ud_s'YHMb5.mCO;DR {W)Ń`-&ub.! e=vY#+DQST:UP9~%RI 'BuAr[e6(x\L1G2PPR#V_4NV!Q?GY#m IDATU5xbX.ɺ7MUP%{g4-#ŭަɔS5N nqrx-LB9"I42 L&#W>/ \'r1ilP*\Q c =P8 d<,નrzy(=\{jeDľ.c}2Wg٢:&tr@ $!2 Ϝ5N:+ڴ+1 $H% &jq/m7jr})k #o̰;~*YKu zj/Qkz{ִs4e8;8H_ULZXO8Z7 <3;4 xeVqx-DŽ҇kzO e?J_)G}9Jhn!1|h~.~C6U{+M'>K\䣬|.*_۝-NVs2+LTuy1c{c7 cUlIqoUcZ+DUL*9HY嗀#Q %8_&6]u.;h8:2I@ +v{i+;}]4E """?635H %? ? K/$Y\EP!< bɤ$'T߷D64*zu`c"[0є_7b6G{>J)xq͑*^'2zwO@v$]j$&45j럀YlE.XJqoߵ>"e}KfBN땘wVO6`P>#Bȋtl3yeo}U<5@~xP-PvHj'u[S zUQNdMAg.LU[KIi"OY51:a4jA~@( T ;UU;:.\}$2Z#Ѵ{@%ET͝ZtK$`Rhm(.Q?tA*SS(Mn=A3{9iLn;d#~R5PXHpP|1]b"d]Jx%=)I*^ `!|\[`dfعcNB"ahWu.e 9}c)\,$zGryְ0 >FԔgN[-/&*2+C?k֒E\X; @=SV&$E֒Lc{V:~xߣwYl;s)y=)fv&B>UMLlqqE%KB"?2YpYyU˼~^"=#ܝ'I겉rq ̱Eg纀)[7JV3O *KʰL>YrBg I?ڼs:㙸jSڂ0"w|$,LA@>P%+ xwm2_Wyň7b5h%9[;Ld *˅2qwKf.{QzW3]G&O65%sߏG1ϲ %d)Uȴ?Z.c?p$|ϕ}l\~ףT!°CMwÕR]I_:~ yH>LY5HFs| co7?a7m>(xR8587` },{b7?1MY[ ƚ6Pa΍^%QyDž2_n/Txh^u)H?q0+F /j22ZFQao{Ppꫤ-(>S<ľqiè4F%_cPF ަo15q )H|"L;FO| AVJS7r<,')OAWsEaZ|egM dTlɓD"Z1&l#'Z?P=Α BKCr RS+pƥKQb$tF5Jwq(!&i[V],VlMa GV-Ip].5Wo.si1o/(kU"X3?P 66$kUb4^G0أ> Cjn)g1gM o m~'!x tAJh<6 TF?~$L6bgWٛDb)prw WlmRvP/$9wb:rA~Ip'cY΋ɻzN&^b*4cqse{M.wLwЎߝ]l5cby|zmE_ΕISK42\o$NNRcM2=V9'9T\3JY8yfa;), ,Ws r=aW.u}lohզm-Vp/,SE훚϶˰L$/0Ht[pz#?RyeJre +eA}}4R'zد~C<6Kl:j i{9mAJR*# tJbTspG+3o8Dds EVetGtxEp'j@_81qC хW",y΃V4Dm\ZV>P3RKE"'l}CB3""rcMԦvĥN2`y:lf1wl- s~#K%%5?2<_j=# }+z5SAfKs7K " 8:R ukO0AMk=/GxLQl#z_Z hw 9CPBvާY t BHgN=hs(׋ k4HO\Uڭ$FVU~%s@ Sћ =$ݏ"C]@?jҸYP%EnrAyxV7x'"n s*rl fpԱ\KҜ8Rz7I&3{v;;+ʐ^n,YAzI(OQ_{1%#fΖ2x&MgUU')(ʼ MEewh?pEL5Z-9x sN$RGa;kpm懾tӦicӨ95Ԃ!`#ԋcVred|.j|B&~|PXxIn0F9Q(f //Z1K#ujMw9[>RNG .}Ml 51|~g|~-E7xbڷzIީC-%PʷW]\-{-Pr&&N A)άg/e峁-(aŁ!x. lY8%S-ŷ>*+ɸ=R#L!ƍz"MZwH5NjtEӾdjf@9*:%(%1Ugsfd6w"UG-> !opM-$fG]rzW?nhJ}d||N00ЮЌ8U*@#w2gCUpbޜzAقr#Fcu#$< 8zL3X2L~fw1+sXEZeO벌zGa^9* i.GJ䦁|Ob%&zX 0`7 kĻq?@g"#/>\x,p0q eM|hmIzKǕK<*Sj:]99:sH84ɕ#z6:{  ztjFyN^q_~ų&+gqMΥ-7.Q41\بQٓk;SgCKF sz%q$]o!&Oa;,)Cj 0~X70lЀHu#bĥNGZ:ɞC4irF/殞n`6t7 r#RtFExKY189v%lDljI%~  t^֒; ~,TKHYTf9Fm6oq@83#7qw &}n~:wS;ҶYp`ȕ<{ [cI{&h ) ?ppFڇs+³t(E XR"\ge 6%QoJE% mΪX0y%c'kmՌȗ~? [ݛ3ŰN\%\r/) ,1!pNa#x9K9Kגy-Mw}͚uVid#xkgo?DIs~z,JYr5peH/TуA%gxBE`uzע5HZN'^?wC߆ NnAp[N):>CAW̚M[W۬eM<ޯt+|s&D22i<.DPj7=$kpd6y>+QZA @a ^=w9$.ۋt~Me"Ǟ2z<>x-k0}Я^8/)$ئfY^MhuY:&Q(.* $7q1qJtkSx;1[Beղcy0U5֗.S1MD#d{8 % (Yhݡ t<$ujd&; zn-x+Dj eA^B"72E\PBoag!w?Ixa7^h*aoLd$=O8WcWW;~j^*ɤR  : =; D~v(VRg~SY (\jh'N%à0|ʓ.3@i ω^tN\-쉂^D5ZkȋAm%؃u=')a-_KD6GKqֹ# {/D5H7Si=X݊l$F4">"5 ᠉#oZDćVC._%.^ᠴ_1U NNӂYa "+S 6=5+BQI o3)捽L—uiZ)jRM&//)σpF'<H4ÃM&U3IB ]w"-$AXHi+}bWַȓHڞA4@$LPP- IY)Ma0Sr T*? 3Fx"bVeDՒ ׶o^α#RQ x{ Pԉ lʧ,䘾?,gYAO'rHԴW*R_p`0 ۤGd~ji {hIa˄|Hϼ9 (t1 :0vxt z˞F &3>\YBdV >)jvʨwn Z#lKCS"@z}ofDA;n%|{f=mǡ5r~\~Ԟ4W K/^%_tcCjI]t?7 L[Fy_#P7QyFV%W6 IDATcU.椅*#"ɢNPN+hvp3u (5Ԥj\o4a ǪJ $)XKjVEQQAFdr}Sn9S EղCw뫸aI;p!/^~OWLR,Va+lNC7`G+DZYgQT"-.+lEnf^UV UAv6w(DPQ9K+m/ODQG*ʻrc"0P+ywn˱g&w .JcTjYfX5CMd%xD0fTP, nVL$bn3:'"Ydz]\F5~]k0ra~2%WWb?Qy)\ E4$GA1m'@`\<,ʹO^ dP@=SO|#Z>U̘`fGͳ82S-IkXuy*pwB8[Qf%Ղ|&aMP4B1l߼pݟ4!7g\ F"S5~5[w?f4)U OLDJ]7Ae0V!L$8@ @K-ڞG32cdM3KOɏqH7_1KDv' sk!}9i%& a<']%})c.t|b-S1Xqs5}p8"uy3Mwp l3B2uEE[Iۉ?9#K-M7¥,7SarxA? y?J{p7&:WhJ^ϵFLr]KH5Nt TX4RBO%,0Gd.Tu fcD@I8ё\=/^L/GS{hkyuU}K?2%,-VSR XͿ{%3eS.\S 7m WJUuګ+bWK޺QlR e .c0_@ _ 3)p;mK95+K7x'-i?3LKw8~ӽ:'Re3y8;܌XRv+3B ]:wҽMATbnI9Oīis9偉19{rX 16Qrգa?$=0-<&e]65N;"Ha7fýs&YqK@G4_FXUFmн<-⾷Sac8S!>|:MX./\leZ9s~_w/,MVF(ŏ)b ޡOH'2;.4G#!="4A顓5`.gҳͬ׹qvi;8QhK%t2Lٹ{;/C#6+6,ól1Nm~ߋf@Y{euGW.g{~lSiu(e~HB\ B$Qw 2:ҲoVi Mh +>WTyLN G ȡnc_5`ip tta#GUube]6CQ2b18j$I*Og"h !*u һWm{ $45GLqN

F: Gj}ԑ mêd_oç`J&3!G2 Yг75C;lϳI弘 aXIZ.=GXhP/qI﷒dfWBE1Iq13+q<*G>umTÓ%KX>)#3¿#$ZaSp;Ck6NhӤKŤ^&6жT^yfkMQ'VSg< }. sNpyѸ!NNl,5aDkTmQ1^^%ыԞՂ^[2^d,7Z ӌ'&Xi㑱k V>f].fznBb15G8WRizWZ.:6Y]!85#Jj&_ω17EN1`SUcq&8"Ug a&~={8.l+c FS"M ު'_ܭ45r4C㸳@# .3W;&z2y[w2"n\Q-h :[);ώ)VFa eg(TSDn%4]Aވ|} [4f'$ Kx_[hFgiD4(Աohtc'ʖ?ڼ̐L3/z/s)9︖'2t}jH'rCt@e f:@L͗KMڍϐji~w\Dmm c %Qhxzk惪& u ZzWoHAiqfyH'.& D 7gIG$06d 'GYƭ|$۸;IB. s}$R},$$$0fqbJv_ꀘm-YMn@hwHq`OR L~~myDµEÎP^W j68Z2l`<Yn- Oqvz]o*OZf E=ּW MYbO]?g\̞f{0/^]q&,|VmɎX7TAbBNIcxPLi'bvZw#?\\aRj5{Pӱ!l?vJ=G)ګpRn|OZ"0SI‰@U0d{^ihx[+fwVۚcYWhsC2aNBζu]5O!Pٻ3϶SAQJ"Kh? *X1l"4n-fضt+vðcʴy>gJhxgYBDe8L3o~ӑ rNO'6:9Nq i>c䮷c (g'ɱظ1vP|œδJb<%U?lb 69 }kkdƖ FX4HDr -IL5ܘ7^ת:6ЁMJ 󠿓1]TRI[s=lذ0>HLMǃwnGtUZ+%L;lxG~d|1WFڻ}fE߾-EOPdme[bbAp335 UOӬp,CY je@*bh,oͯMr4Hq0eQ94e)KFQY=[aݦ`ctݩ}>YyQ! ˱\$||kLüS 9c̍Ј&6~ pmeW^@Y)n +7^p?v Ϋ?4*y}ikXnĥ._0[%ƴ:lXhf\8͐>X07>cJNY*EfraJT:wt>ġ3׷ !E#AڗE[!fP GI(e aơRp?fFcֳψ.TKdKUË珢󆷽z~HvO]KƹsI׻~iPVa(5O3E3Si wW@x7{E~ h|__?r|s-g@b7lbcObzceC6%4 >r[x;FwpND<.D&~fOTN+ _$>= +|KpZۓ_00:Nā1 {h`5*t~waDWekHO7?\%Ӣ?Eј~$Zdv<\Q6GvbIXzǦ e^-`T6ܾ\;˒~5}p(u̢'qNFOܼoKMiF}HaYIȲi𹶍iQj~%|+4$ \*䞚" D t1۪AvwC|$mR)1`y $xu eaw^0%ad ]%ٿ$X.z~CYD$_G+BjxAV}g FYHdCÃQѻ嬜L Ȓ4J'fbQ5@Â}qԖuO&ٲ? k4IGZ +'I\If$6T'Hk`C}蠯/f)%`6jmɝalu#elX9_b-ޓNl lnٹi!Y rL-A(Qqo'e]m$^ a]<`)̀%g.6kՃ\ i<7F>s쀷=%=}iXJ[qsQc l9?qr1Lf.uCyD͝,C[ȑZ[B<ykוڥ4M^<)+A]hY,_zW{56'mj2 ="d_ZװGn.Fe>Q$dncJ1)\Jjꂎцw&Ȼ%zԅ0'x!ڝ^veEtu"(8/y ~Pxe0ݱa lP#28.qU ֛N~TQ`zy3Bja{JmǕmM߽|*qno[ґG<5U~l: BT$10\ 9|dZ%.()(fwƞ<*5u!#ִPgBSZ{j>` !p meY@z!jh֞۲|v^(pJ2h:4 *ЗLCsHaˣç6/li] WXwbkEfmg6)WդKTlqnfJ[ !#G4ڔD&->rʤZO3V/pODi%AWFY0_4}<;U%?Q~ܼ@̗sU{-Q7ɿ~t$A\M IDAT\J7kYlVqǼ>V_oIgw7loI$(J76]XؕWa(XA`}rn4}v̦CI}?,!|@U|Kɇ6\l<67 Ƈu:+~qmU1mmHpuކ6Jjv=\.*>\k}R_pm/`D9 /J^wh`b Q>LB,k|dX2~/Gʬ{c,M߫%ÏT$RijIXx< E=4c^h|mnh^;,l]im:>jS{kUi"@V+j#$Q%EhRQ#w4bsu4)fA|%m-_v=m[BBX*(`B2'\d}K`$=R7=HU@6SV ?[ IhZ f bHޏxLyC5⬕9n _vʜJݲxnLΏh:;U͌$ |׭t߹Ƥ W P^J+)S9ȷO[- k-Q|\Du.M8}5sC 77MQu~s2w#ҏc~դeքGld1;Їsc/>]R9.d3$v% Ȝ3`)1r,UDx0Qr䱴v\*ɢ[} =[ŵ\; ~$~_FAkll}b񠉝xzZ2ZZ[Ʈ)aL.eW)G?yV*}s7Sy"rXE{=Em:Y?׳!ŭGUСfQ ;t 9È_;[s;a!ϧΖ_r&"* 8>.SAd}r=!!~@tjkCh/ 1h>m߂H%/LZJTwC|p>\|{цu#, l#!(zM3Le͖E9k˙+E]tyXg8ef/)e4Ss^L!Շ R2?M,6t? Gʢp_ ~>p zp٩D^U^|  v$GGV𲛧ҝ!BK%_q3sOOFfss!X1Z$xkkh\@2d_ xf[G~ؤ=Pz*̄ܿa-WOog5Q-* p*yRf,`Ub^jƨ<)R RRo?1 aF~e^GES`*=ʇ/+T-Sԝ ͘;=SɡŽ]P<gs"3[ի*~:Wy+veټ˹ؔȷw@[gI`}xt_o .HN( @=*Q8 K[='}KxY55IB;!Sv(]En{ØutNsE/:VАBYC<(I͕MjMuc@Ce! ?~hpB5V7P]QT-^Nj0<ljDo/PPId2tc{9ك`ekWl&OpX}Z*@~,d?!}OWnwYK˫}JnZ"p͓5_&y>̏C)%6k0f. |$9D^dIBݬw `Cs.Cf!`dƱp){}nhZSn!nvŸy0us*wSw֜8 $UvvxYvęBf%K Ä]Dr$Nn/s {^Ok=HS7S*oH%aWJ[H&{ZRiOBOsnxSڼhJ{k~15ckY\+cWN9'Nvҽ>lBHZ>yl] 6us"Dž)`Ng@G\ m+&z96]+X. Z]ΰ8_? Oü@mI(?/!6Msq* a9RXXsS*(IJXwHi_FnB>ڬ:]@wZүq AC cBFw[FCVW8lް-_OnֱvJzK~^-W|&~^A؟QgU:eA(?+һĬ8F:VY& sAE5uɢmLE-9. NiZP:W?t)r˛uNgHFEm#oS1D9?("g7A)աNrX +Qg vvtd'SICnM.3T|7@K諅aWfwy Z4"xߵqR{jpĈ$ViBrG|X 1< \X@kBd;=)gWmYūҠ ƹ5A<"Xž/Ӆny- :%+ ܼltQ(,nx3Ѣ-tV#SaUGzl~}Lz BﮰUE>ܝ-'+gN`rigD {c(\ ,z<@$XfY@K,BB/i PFFlnT&v=4|:Œ;TQ߄DE8ğ^D+Af50N"j;u' 0M41RCFߜuQ0xDDqjANX[>oS^>]i\gtNB/-Q'~LKjTfjԘ ۠b.v幧Զz·n{*a~ |]4 El#plX[Mi3q] U|0X`߬cVWUz!nyftWG 7-ٞZzwK!Dt9<%7g 6b8 qmcm)vwGstقCK>z b?ŝ?} oZ)L޹+~ay?|.⋭'rmnz>AWoJѪé^<7?Q<={[Cnӿ@դ#)/W& ̒I,AE/y (9TMs/1Q sCx2r*Go0%yyr3ZZjc xNMyy9` BMEg!{g^)e壽TY^?06\+QM,p e6/$q')cÇ@=?7Yof]e_y6\N|J8PDD( OKEeQ,/xIb㹼 qs& (: qш$K+<^ / b]k|N"SP{ t{cʌ]2}DSwKT ;5MҾ ÀtrKpRQwUI͓VqJ(rk-]2&fHs%яmяٵ;ދnAuxpEG4W`tDaJDo%˓E&V״p(>_Y)Ϙxx ؛ qpr>wG0l4[-M%fɂ&_aL*!p~o"ŹV=B ;pvU7Hߞ2Е28 \ hC>N|v6O0c6 'j0-HF7Vl t!Y HV3oq9=*CP>0Q617)-K=LkN+бN]+aK~kwH qnȇGԾ첼q.8}Mk祵[ sdh.˼kgg+Ԯ˹[M'9tus&<[w;|FN*ņ7EIQ+sL3lqFK8#*}Jr&xRD+jØp)b耍6Io nBn`.Rh["&]_5o[ nH`Q$puBp <:.8(-"ˬcȮ]Rpw6~ҵ`je.x 25Hðn=di4$Jㅜ$ge?O)_1'VuVDm;)m|H4M5NMYN.g5g-hccna|4g A.v"2~Ypy9oni㚩B|I]Qq0"Ј09f]{5zۼjoʫgVcF\P(:y=A)c%3z/z IDATKsjJ!Emz(p7 s;Tn3 ULJ ㅠi֍tUjn\lv SD!&?.s P>b]Ij)K7,>2}l_75jdv r~Wzqg|lEqVԔh*_ro(B,|f9VAq>L4~8)L7Vk;mHMDfiGϿ(sr4ArIwU)wA' U+N_ʊs723L[eԠa努F|_(FJ>&á4""jp[łpFl: )9|%Q :q8x/H! eڰalb#էn<)y-t1c(4qyBNȖVޗ\q#E ٸQv, vm AcE'^Shyien`e\6۞|ذ㾱 | -zVaM o=9>'s a9ij*h2eIJU<>dWD}JND]viQ7xLT֬IS]e᳭-0>"Sp$Lk p#3pT^dN;v}$:FJ0o[Y l%ɯDauY(8G #=LRsǠLY>ݶa`g4DV|¹EvÜ&MI ;Gdicû?X\ѷ6YHmw4N%_*_ k}|/3jت͓p*0 ~D^cQ u3ީ:TiߖeDrH!![;iwlkop{y OdjbK6!޿ +.,lnUUT! 7K7~0h(\>|&M.}1K?T9%t[ wb9Iz"Sk}m1X>}35\{_Vt0aF䣎۹ĿWxJ-'PkX]*] ֛:#ΩeegeaC<|P-z:m%ϳ=RN:8<;uJ=˜GdiF Ͳ~ C 44 k sZ' CiRϩ,#us%dU[B2V5+_ &۴˱uY"7BDAY ,% &2Ed%`nLV-:-g8?bw"Ow w)]/Sk!/ 1SYN^ D1H>2j. Xbp3U[Z`!,3)_ug[C@PܥK1 AvÚmYNsFaLVt0M b辮ŪYPL닩 N|W E_ɤ_>}'ԚȓfV^-#W]_ep= =-.=`6 ǡ5?"ZuB)f}__ ,&8RCH<:wH_ۏQ{ 0i%؀P۹[[_LlP땍y'ҐZJxŲMU$v㇬ϙ`hhc| +>,}4_x.r͘SY)Ć۴XqSsq̺+=Vw}j"P Z.ftX0_3^pҝ@7Xe%0hvݥx`.)<|/)T"0C߀2 bA*wOMEH)(+첅h1GDA>Cb$|0HiU[?aeZp 1tJ{ub[|r'8өI\TF"mĢSJoj²Al$Ȇf0YiUCL_ ª̴]y-+H3r{g8![~6Q OA_EUMFkR핕ac!/.^.Tf#vF8&?$Y(<з~hRœM b1\5ѩGb|d[8HƗpҺvMܧ^$Ui˗^[.ԅ@~r rǕ;O`|g1*gAFJA{ `CL]66석1e3c )QӲ.g5;1_o-D ~4r7=DZC9ssq:X1 v:E'=<_svFq:,)7SvʿR]p-1&Q>~U-so)Ε,ywwޔ#)tY,-"gR6:jL*J!_*p"9#GObufWbcP@*'6=`]܌_hݫQhO8v&Hom'vgu޸\h)"rF*2)^xrwM9ǚoۓx6%A'jp䶭U6~m(ϝCs3JKN"%ڳ7)ydL;x#ft'˳CТN浹%gM7x\Su36j6}ѵtl¬u"%nK?#&96]$y-̈́jڻX9^>TB΋xjs) L޽δ"._`b?ɛ>p\(^DzaIsf`Lh[[/]Ÿi1KYE?H|rqO }YN42t0&WVO T+a-l.TK}Ӻ^W<6ksȑP=W8=\#3ܫ~/UR / wgi>8d|u>>pTkK**$cF%{Lh+M}qdvU߶ };#1pi(VNdd9&%8tˆ ɰ8'R"{f }e4"6J%PTmcIc%`g`5<x)rT!W[ FX3#gi'O*O4QK3vNw#TUm?˺"|?@)ް]LgEO Z[Jwr @p{O]Qxr^!d;n)Ԟ w>6ah{oIMjOFrO~oJGPs^Ztg5ԶHU'}rD6ʏ =:g9qd;Bn3Q}91#SSsGO:*3kYy(ڃHSqJbl`W9@V ȋ) 3똽Y)źŖObGe!jBvZ)[^<¡UlZ, o4v lcut148gg ENI8ɴ%\pvx܍}_u6Z`^H^{Dzzcd rR2c h;L2sC cǛ{1HRE΃Ɏ}s)a;ոM5_d&c@k\NT萐ScZ ~Zӥ iCu\d)R8޲`.bYWi?I2h`Zوs>lLy'k99+Ӷȍp9._܀CP|r0>zBx2T{v<Ϡ6v0psĞvd7s%bZnG |q.3H-Ci$Ay'~;m}\,~F{" oT_!OTKh@^Rlk=L MM=I볻믗xʿtDxqVwK;?N[SVD5vTTGh=/ŠavC\88Ÿ,K976A.`})Fߤ]i.j-K`d̽p||"O]%;|zq3 5lgPސV_(z{;ŋASEtm/CƔ΁k‡+/NlNj@ʂDV{Y6w׊@BhʗKĢI?&ҲfRz%kwebɠxىwgc7ʾk/ K3DR!|=.0*u6٭ԸH9q'6G:h-)q8m<0z.a*6!WUO=5 V\cRzϭ&og$\IOTُ!c6/Zĥy a.cG(tNp%0E䙕zTXYsNӪP[ށD7FE 7I=SE9*9؈tc`{!Ĩ, p Xzýi Zud='2?Arb;Gl& +E.M M@jG;40|va jF9 T@{֔u4+>:pbQwobv†Skm4ם\/4/%ŅxlY/4oFv%h}n<|H5g_0X)v%; b({5o0>*ae4 Xg䖎AVpR I*w}>og:X~1}]M`pb'n;AY-1&vS`v7^O\g2 yasd-Sd@m,r[ZEҭmfsSvnqa% 6LL`fV "hd"sV/]s='Ph }Fws]I1UAIP6f˻{=)ϻ9 %XdYHUñ)ZBG?Y%K)`R@:Ay} K9hxнH̜hݡC;PVk X"@\9le]rJ[Sqz ūswc(tT5N]{u9G?J>yTK=ie(I)mG8J #Mz U.W#\"qtFpG;3 z?,F.F+jL} Cw'CǾ6 ψLŝZ^x[[dHG@846Tׇr9GJwN#S'v`!=vRSr hXb111r/L]7ha\}>uuD*k`=mɡ[1@:, DjW[[S'+G%jbaPvM $!ͽ&B!?xޭkSAnOIαP_[hmi IDATżƅtтr"*Q-4**M LaU}. 4l~ >rUD)Lh9A)˱bH]8϶ʬ+iy Zh_|tcKbyœ_\m&G1(Cev1sGkm?.Co,Z~H Ћ<7qY @,:}lhCr!t$'!\WS&ByaNjYDElضqacE`Nq{S&mޗ`65WuC iCxV0wW__I9Kf5dGS*|vs{ -%,qtTL#=}*G;4#11Y{~{5Wfpm#zڱ?PXl];G;nP'Dw+P Վ5?p³N( @g<'Nx}:Cuw-CQ8TbH0|m$2|&S}McAjÀz %?QI.V**${RD?mz \ۃMY|Թل2 s3I͵6od\\)T&+l4~ ,3<[8ҍ㞅pvיܐFՉy+䆯,rL9!ޚw^; zQ^u3'8o=N$]QoM1)zƦUR:eNFegn%K6oD)[gk*ЬK)q@! \rH'Ǧ2%gU?D<\"|G5I4_WL(tbV k$ސ [VXn N"DN.~!M7΂5zP ~ u eS:ƅ02vc=0[\ ԹjlBN'!l[Ɩ_}טnؗ#Cvq*TLST$2})rFwNK/EL% &-y/IQ_4k:W2;O_ }.ΌnlBpεF5G_~Wk&?^XsWJS3voM]]X\?̹2/J[! ^rgyuau 8*#XGLA,3b:1*{Y%Z^fT3!hxI|^p'ȕ i\ m<Ӑ4E^S":^OӋLAIbPڧBdɇ( p- %M}S;Al{ND>c$8\`CrN:硝Y{ѽ h-+LW{~vn26ވ3J|~vR^ywWFiYȵ/[L&eZ3VaDvU޶B0eiY79]ޕn:䃣>߲@ܹQI/>C=-Gt]#B:u-MyӪgQ?ɤXܭV˧=Ƴ03wwQr 'lC'͇RAk4$oFHCG+hW+mh~r (EN;M7*7޳Q+P m?alUyk 6-hć${87}R 9v@tX bHv-/)%V݅xx$Tm `NfY#2a^jb&X:q \ uUPsE="FD9 ,'A!!W@G)64W{oON5Щ> ˨)q T0BۏKW,a ? DƫsQ }A"`/s({Kf'ZF}Eԑϼ€{}*oqSn`(_雐'r*QI驣f?'ow08,Rf‹űaW1cC6_y+hL c>vڿ {vEnm69j3љ E g'Ȧ t I]Jk+1) hFC ҹ}Krl(BOȢ\7?Ѵ4x8*w{m`@'%Tp GW(8ɔD'[w*刽Gԇ1q!pu$Ylb8:Y/ۍSDyiƩ6s9Mfs{Kd Ls.Ȧks[m^#F"֔2Mu^ o\!;;ez|&Y$Ϻ/0O_ ',G.) H_8V]0&r] ןV٬y6@HvYFM$ c0NCj- G-lRИVgxn|08U`ߡکmU,-kJ%gmZC}x76_̠~vGlp\<4zS@q1u>irYZNoʅ.T~UKF- )ټ5ΛDO2T!P88$laczQȳdQ`xa=8 mAz˾q~( VYN5s}Zr3[ne*ʱʊ%AϚ`ND8`ARc}'{*y),w7͞uq"ؼ9{~/)|S*p>ZÛBs C,ِi&HIBݡV$yC:8 AW>޹zqL=ӟ 6 #5'S:]T|Pq ]c[{@ `xrmg!Mn1$dY0jhE)|'|^LbRuу٬ g"Ĩ`tQB~u17ǧU~+~8r˧ud]WhohT\#BGZw[=. ;}i=E~pm3ڻP0[e Dz jٴAY@>FDblN;YW1,R{Dd>"&}irFD=7U>8JhM7YUnA0q&$$- 9rImZ(KR96>D &݉pu1wG-MUSҘD9k$''Υa z\jhOxZpͮlX-!FMk;(OO5,jt`um9gvj- >ѲXԻjA%riC(i#4?ň2 X"w}~?Tк)l#_ìE)j*f ڮQR#U5_=|d9o&|rt ;~]!W{$9x3WQͷDyv*|]Mpt(~ʻACtvK/+2Toƍ"!Xjx8C}G?LwVKac X̣Hc:WhcV_[o@?I H9V'ȵ-Uj>DzD&MIC)X>Na/)S%oK}tkC4r+{cv sq0 XRH%a{Ds`p;O,90A̍Cs9NR{ X[|ιa&gqQ[Rp<7d44)q'\ڣF<h.Ju -sd\=P_2FRou9nDgum)3hmZg: &@ ))-r<\tc C9J4/!L҆XRY\gsIZqr|koЧ+8LpQ1;/-DW:KFi¤|,Uk}0V:YD ;ֻ݅ V{=syQm"|,o#)J<ǠP;3sp*[Q xU+-A b&Xj}O:-QƮ<r\Ivt^yȴS FgKF[z.`P DvU <[ĢOR$Xxb BEϡ7_n} .]G͔{KuݹS"0w!k߱S2⡧s 訁cs0-@d(x\nꌙ*(YMN1 m{@E 9~C~rckI0J6jk |] ' /ob`?)A^ilKk~"W) !!6TP;b% wkrccZw8 9,%:+|L @4Ghؘ4ڻNy!Mq0ແ5lfJ@Km9h.ìf)ȨǯlIQq{N0K*y}p?= GJ*V!=7-F6JPJ8[f5{益Nܭ-XWS׮w#5 Z<:) $*BV%JDPLٕsKcU}sSRK_"8wBg]? @\qvoK$AXsys։%ڄ̦+eiXlLu`ݘ ^1Iv%kycd$###hymr_>JvBڶmum[XBVsǾx{ X  鮯CC7-|\2 9MZ[z p3,I`X菣Mp_+~ =zx;AH+vV˘ON}RjJtLFN~0v”)`%݃V`fn\'=1gwTte\% =;@{[M7wRN>kv4Rj5z N㪑EGxvg-^vO?K݅h[t 5⨭:4)LSdCH`rP%^YzsXO IDATCzg Y>Ƽoo_H _hj h97cie/vMK`H{Zy,^<ؓ/I7X}X +9{|߅tJG,s TUfk7uiH'TUQ-x,?9O1|hN2jOc0LER!r>ߗ D-SWGM nW%9o2: )ȡU?&;x;.0$Q[dHXW/m ]l9ЗdTXmȺFLJ^. [:E& հfJ[6 ..R60^T2|iz4ǡ/Q7|W]-~XOP(N胎"DB$lYU'U|5ɰwh_79L_'Pb#{8U% #|+VB!(*l&'ha#N&I tMaC0W'y'g~1X6*剎B@](lNBCW"_ pu:_E+ \ f{ol ²zvZn0cޱ9#|P6:u(۔Oy-7 cfND(LXz ZUµx~:"fl pW%V&w\ֻm+hDy:<ډ<5 BS/ڿgnl}2%KU%:J<Ѥ̯Y%[e lR4֟("glƪhlX b\-ݪ`f.vH yiWc 𬛕;ϴ0zqL"NFװAAC?]@8z22߸Zd_}ݓ#|y_БZ%;ٙ[r0rQ?]%zy+lǼ]Q#_>H{gכмݵ~epG[a~>7AUÛ0RTtsL +9x9l/A~r)z1>Df4רISQkV:@'gټ`Cqn#J.7NS٪:iM~T%愤.污}"}q3LF䜧/k=5kx|ˏK)<j#d,sL-]a÷mu5)u:x:f>õ(۳]Fk0o͙I M i8]A,RO\s+K,YGwWA9i%ض5i5jȇ+y6Gz,<>"A0|]χ!)/Vՠw]/^oV ќ?2dOG3 $ ~5820B{!ſ u¼kwBh*Yo#݋WOr4e| 2J{$LQ.7PgW Z0 hfIEHiy'xۤ=" 1VJ)ۧ1d^D8̈́&*41+2s'˛r_aT&#o]%TˆT65hmpq y[|lFNӐe҉XX3B˜~+h"?)StD8NP^7tSi݀vry~a(`Q돻®. @+PFhs:~:Xa<N "ҼX|~j]X:?(n.qqFW+ŝ6]:eIߡq"ߞ4ыZ6c'9 9k-TwHcLmӳ<.asDkR6Sx7BP1BZ"⦷O1v4aёiL¤hO*'0tF{?ū7K߳dD6HGr_!߻ 3hLla"\ž_X5.ٞbvϗ NHƥxj$NJe PRw]gkc?ZP]C:po숌9rr_ӝo$@8WA?9nFgKq[G_|yO{o?'lKH\r)~i|ed*A5P9^F!nٝ|J@j>ԑ6F+6#=}KȤ[d' ]28X۰KnR>yِuyO}gtY.DOv뇿p!޾}`R83(Aw=,R:Ɯ&6s.t^g i 2i rK lclR'6utz/䔎 n]I"UI"3s9GSv)W_H_!sGMH-CT['/fn o42ʾJC l3ULv'9{Ds2Vqn%' ?V^! Oy\s`}-e#cqU"XVɁ xv|wЫ1Em >gvc56-/K8UrlEc8H?ZջGg [AmO-aPYvqU?%OCql1C e/.'<fi[X= "kG؆:<ܝ R _JX> e5/q~,P̆wu |!i^`z?nq튙e׽pvkh1iw-9;iLexv@呼'3C5 wUh /ALA/B;Fghza.Nm?"PM86& V4xlJn噽)_@kv .oJ XV:vzw/) ۿhwa&d~|ڗ)DZ'CNroj|0&gXspF>aJe\@Um[Y24HF1r8zL7_6\{4#S&g;Pڹ./!lm?03\ūR ڣ|]\rN ӡO4MW+v%mm69>ge{YLK7+d!Zl?L$gyZ7\%ʲ5p*.~owp" svfg߳ <>v4!xv?~hD" śmAb C)M5tJ_D*E֚j%s}vh?US5l> ,s?l %ĢhN>oZiCu~~s\`<#Cgp*]U> 7? EcR޶ wb]wrZ2,~i*ܦT;5dGG~($oL`q^_ og]qop8D㳘y:ѳqFL?7 l%-i&4@ն.a-UN;-|ĕWL0CeJݠ79Gկ0r] hizX5-@TS+}BW g6 W=qdf̰ zSָF )qCx$:":Y5k SYAFh aHxJe#tʹT,mgI9Τ3؋ēXNfHtyv`a 6̀].}elbP3>$9CHk9#+<]H$oKjvU"t!͟j/yצB\rK+DevsN1r{`y! @ W0pUq`68+}iCPSN`8auKg"p6ƟS8FfD ✄8(ţtKd|^Hr8,n*5)!ߧ2D(s*e|kׇ~gA_fטh(羽#:HmKވGTc,]`ax_Jg0 uDde{|}+E&աQ0v M8|'$fcio- `%_@qomE!ؿ@#8TKb!Ef*6T|t_hsx5xZRɯǮ[oג%6֣d'*9+F͚y4\WG&,z+A*uuDTfpQyXiVݎsGk(8Ap忁~~L55nbW8f6t3 Ěbx\ճ,?i8KJ_ݡS?顥ޕ ¨e3mׇz~~Ix]T7D,l~ুm=C .@#XL-A!=g58^nASVȏ4P|&ɣT/~ H4\_k1J4]ԟiΑ-:Va`B IW:mP}f%8|dZZ[Dȉ`C/1?2p;Q].Xlv5ˬj*s+C2)( AJx09]BGsP7m -D~@Ħ|mqw|^v5c%AďZ73`eϧI9_9~@PL|޳lle*^cQxS*^NKCً9[6<'b֧oB\?6uKxw/ѥ؍n˱K7.oIp{E:Ԁ^U`B(.T9a0,#y.>r;Ӏ/r3DF֚uRy-Eήp ty-үHӸ-f0U-!ݯ޲Lue=vo.) fdX1CQ;j kf6ϲmmOd0)U8Xq\9H[h(qŖ!'=[-ʯэ)Ľl4pNc~-pClazI 8o3-[JLoO,3f[ƣlw=[qXޟ )֪LH󄓼G~ǘa`njhH DTde/=2{ *0 rM,Kll#/WiWO S.ާhz7f09McDḶHE ~8!{xxpM=CdzC~w{Ğ;,|VOӇaʗ:G ʣKS{nL^^'Ͳo^!wb 4 R6{ >4JY[;{f ʗƴZULͦEABd׍.d;*l &E / ]kγo]ŀ'$WӀ Hҍzw΃ gxȁ׎:1^<k1'/gT{a;lƥyG\!{iۣ(A`XukGΊ\} ǥ"[Vs V.M-wi A~>@D4{((Q~Ee7\g^CL" =|I>;c-<[O:LijC>vR_>+!1`}UQD_\ZBpsg{Pw&A;„ǣ9ب玭gn=׎ieQ> %(MtQ#7!]m䮿stcyN<=9t&_,o_ovJJƳTٍeF;^ 将U 8x@szY:$7y— ZvHu8XwyJ@ͯ5 rӒ||D%rOg_Mu3a3mxiAvǀcH7U -zceKq E{We|V9?dMۺx1bDa> xZABżi<v0\( "X2iS/i[=zx6^#NYWsX-m{<۞+Dwzju|C b!eˬ@>" @5ٶQ2LHQFp8v gU?|z;$ҩ:oM*76(#v o@Ĵ95o>N*9C[ɋ&q IDATCJ`>GeQ@U#Sݤ$֎E .xE4߬(&~0wl-<_$a. ]?(?V8^<9au;Du&Hf/7'KcnM:,I7z4e-EYh>Di2L RtYO̙ϳWPPM#Н)tw:j]da4ձq^.VZZ֗KHy_E:`Mc|, "ue.B^ UA9(2 =5z]p}+iL -^i'9uϠ4.(dj dqS5_9O\ thn4l΀}+%:X'H)!T M[Q݈_0ipkO(k{ŝvx򳹏5 ~OlRTP逫M/Glʎ<tñcHiQ5PwyqLuN)a'r:P74jÉ:MTAPGbiϘDVb(f7Cf?4xb41,x-%&CnQq}Gc0JYndˤF9":^;ѸmWQi4eȵteŦo̊" ͩa~VFQ b"x\m&$rBR1La (,- ̉78.0GgcU"y#05_-XVu RĊ]Eo!"[9&> f(重ىAm 3 7%c焴]^~>ma'5씲VyϩHsϜw G8ZVxq궫v5[T;8֧|P7$D7oВF KSN)k3=||2Z0MXL"b+V}'v2zg<$C̓Ku= NVWPѡf:U88" nOc"9<ĴK;V% 9 lb|N|յڰ6e ס|$؞6(B[M1ᢰTu&Y~X);ӱnm5d+ Cim`ju +Y#^C}ӊB^vA,ot]jktKziOVW u49UR| Iu("d4&|7xKEn2t[Zk2+|S)=ģp9xmS rjOSk]EKn"cso~OUkX1rؕZyb]jf0:6B$W"4y` u,Y5OK穟^{yf=`M6agHo.PeG+O'س;;;>Ĝ.l4iFIQN lfrU B-mğ !,zDeݘ.?VVZ/D"L4gaΛb|b,>MT Ϫ kM+Z].*j9Xo ?>XTLE`Yge ?|Gpֹݹ:Ǵ^`/QgEēmpKdذ8!'臙Z!_ W[ѳe hE}%'Nv =o1M8Ǘ6{M'nBڦwkՒ  !ʙ(Uz'~gU Tk X'\m?8ce{XA7ݖ `&֣ao{EpBvU{NZ&7m; 7ξ9hk4Ͳ|"H5GC zM߽jNX,i'dZtYSBd&Fqjyiv^kIG.N ;IMC5ꩭeȅ{ckuBgLJړ3.f5TѰUv95&Nh`];#cM>Ž傔a˲`Kq /i r'gQʃV,w>lS o8i׆%|Gxl&")9'foFy)س$z(lu{EC%?P籨^Z7_>͖;cxKrx,e6%<5w:agh'uդuM>tw7O@/zs=bT63SWz:<]--Hv'C3-p.4FVB/aƐ=?&zm%3VJ`qhݟ:j%I>:@/MnipY9v2u-q89hH ӫ}vu96@shS)Fm8yF7ř3;mR/{3ܚ2鿆=ɽ8B<;6inAjNwL7Ɍ["vSUyFi%ђWpI#A ѽ7X d:^~j;!1C/~,}h#etZU22w[%=|˩j>}47N+ήyZq/XZe^]x4ai>?2J6-n>NvIC qk(_N> H9h>.i v-k U#rrf#\p@@"ij'bgsO\jݲئΊ3*4q6)`Rqh.^f0wci@@`)`F{kANJ%T ͢-Z3ydҍ HɎZ5 h% M6Ct)Th#TwtD:Ct#5ٟW^.vlD= 87Kvd]7ۚې|{9N I991ik~ګrw/vbIІ+eS/'AG ᬦkW;<kC~cO? MF/@+)4XϦ4!#=Q!)"Z\RiG»A?* ( P@)b.{ɛ"DWQ6wGPRoP=tLnpY&wÛD{dnF&/a";M'S2Ϋi 1٤6jWN\u xct 3NǛOy6zcIy0ڮhs(Mf^秇[K  tۜY0W#\$\+mV?be#YӤ̸& uVz] {Of ]+o Z0GLP1:*- `I\n4? 'z $~^l2y^nchu%5:C-ʤߤC']/f-fLZ-+'C9ѓ{45%+6w=Rk6 VV>h& 2]UϤ/7œHPe|MAU>b9RnwyN쇖:`> }T7U"l. 3]~GNƍU%>ALQDəX{kTkwX†E4qj 1|s؟@Ve(W;bXJ-dO2ωv̨{f|~ [1A&Ul61gV0pH7[.,S<,Ty3@Y%:f߄$ g22 l?$ $NPGdH)e̢ߢS0%îKJ*z<㟬$6QU@c%XQ:vJ™D`] 7IGtxGWK =I1Q(3ǝݨrwOtݼ606گ?9mLx1x-]8]Z4yG7Q_甃 \L7=q1->6:;r].Ỳ8KOd ;v#.:$TìՔkOh!܎ѣ3ONaX 5w!\dRa+m.4m:DI4ul"!)b r[Ft>\۟dy {8C(kshxy[E' VHzN :BMq >UzJ@$ O܆d5Aob63[whF+'8P eG÷hF*x&6R]H}7olW@*lv\OGf~-3` z u_A*yԧwqD M*֤0PMp"65ҚQuEǧq VJ$s XFINeړDF7cOY9/2UI12 |5sulGB3_8UڏL5{O11>+-b9gi%LS@fA>LAkʄ79AܣL/p'[MA92Bm|PRo]iI+ӦoR 7[!-yg=Wr8K<.8 XTq@vz\'5b9xnjDpz:袰_:$ѿ5dR l[BZRPr+iu`~yh6҄Q/ nȇE #"jx,3\Jۋ3!ɜeF00v ɲ.=(]9R;|2ƍ#y1wSu\*_W8DJ*ǺJ#Jb1g x_tYgxxkH"R#vm1p$@<0`fqiʔx8L05Tb+JUu"qa2jUy~Ƴo\hC|GYr04>28b;, 3zH?v=BLkl`?nq~w5hod@jř:]Hn@!nQ\~ي+""GąH/^u+S_GS4T%b {*Ԫ-&1G+瀖ciw&'`2+iM_{kfB?hfrPVʷ6,1f xNy.4vǕPeU6{qaz2hNAu.^y~-`&:$+`Y/efb2Y8Y\a/PllIsMZBt-,VcsBEap&UpFI˽mx ILr A1ڏtz-]5P| O#w?Q~Lr"|$]'')ROla+EǀOvXb%kʒ&1t{0|3>awDr#"(Q] IDAT/{~]GlGM 5i;]8B[aDRsƗ%$")=ޢ`RHx?idϑ3~MMw~N =tO#qōUt7॒MSFE'tӁaHZ3ԻQDNb0Es@!0-,$ziVboyE0zNpӳ~lJ9,բv5666^g'@`#]0Jq*c0*o<1ڇW!77t(fz+̰q,Ӛ&6 ^}a=sr"#Sy61-X8B+|^o4Kq-4o>6z۲:U9ԣ:DdC&I8j`X9( Ŭ|U I%6:.sJ)X@zp_1J.ǎ\*ŇFϮz,noN2SQM=*23c9I͋41UBe:5)r7J 8ɯj}fKo6B$ڲI^a` S|+e*|5t T2։Q"eo"Qi7!D ha x0r e2Z%Hk_hy BY٧)Q6LpHI*m.ph!\.Q+bx~jrNo"9GP=;5 ̳q76;M)o(RtSkVB٠wa ylJ@p2r SdLK(Hy\,!aSQj7z/Ad'w?{::±~;!Hf9l M.n#)3YUxѫN ^#AGI,uwzeg7>`=\ Rs?m_ܟOn eXevIZq,|s hD; |$5vq/C@<㡌W>&& ,4Ti{ME(L eYӉqwf7ܚ! xh27|RCڈ7nZ)r~(xzѦ|1B~SJ(yaX74y}_xϷ=$v([؏u&sD!ec5I?hƊȺ@$yՎ*Ⴇ!s 3p)ye-Kt-V@a?vIvE QRQZZ$Np@oז* X~FW p^t|}n,f٧{XJ`!ݝ 3F089aqMȬs'f39lMf3o~הEva*=P},)ďe)Ulɮp$e&lAY9ZTFNJhEױk,I݃گqDEр.6,^.MYrv2[4&O4$EDb8T\5c8d%e!~&^;Lf,}me\;:pɩ#Dm!2&:#vHGH@uݗ,Ǚ z*/-!s :S2trJb)*`ffۼ<ߐj?2sA0lN;c?|?@ֹqLH`X}g>|XvY iֳ wU( 6—d[Ag:à`cmgu|x=2#uc^ 6{ #_D8J7l$ּ"SgW_Nb=YM%Wcyδj|,&3xVozp<\~&uNͳI${p|w?ٍ>ۆ CVx)`Squ h8.Tky]Yc˙J Rx~lnqđ[1@^Koo IH ?]L:v"($=0b{6yo"?7/pl,YlyW򎃯~$yj\Þ4CKثñyH~hK<3;T<Ær ɸfW 7} 4CS̕Y©x>"J\l"`ocfM*܉gVVZuU|SSdqlAi^GU77./a8pH0 Hߗ#L>rtt G}771u>ʢjQ{}ެGw5ZEsTǢZmfy_\"8gp)_{|i2 h~ωUn;B;rrOiHpfy`54e /*]NE$[D ;9x3\QWOR ˋ{O3-~)Q v.H*<|:v]hA\GE0)A&v)yv!qsYzؤCtisMW i}4u] 8+m hrtLН-IENDB`refind-0.11.4/docs/refind/installing.html0000664000175000017500000024733313372347130020562 0ustar rodsmithrodsmith The rEFInd Boot Manager: Installing rEFInd

The rEFInd Boot Manager:
Installing rEFInd

Originally written: 3/14/2012; last Web page update: 11/12/2018, referencing rEFInd 0.11.4

This Web page is provided free of charge and with no annoying outside ads; however, I did take time to prepare it, and Web hosting does cost money. If you find this Web page useful, please consider making a small donation to help keep this site up and running. Thanks!

Donate $1.00 Donate $2.50 Donate $5.00 Donate $10.00 Donate $20.00 Donate another value

This page is part of the documentation for the rEFInd boot manager. If a Web search has brought you here, you may want to start at the main page.


Don't be scared by the length of this page! Only portions of this page apply to any given user, and most people can install rEFInd from an RPM or Debian package in a matter of seconds or by using the refind-install script in minute or two.

Once you've obtained a rEFInd binary file, as described on the preceding page, you must install it to your computer's EFI System Partition (ESP) (or conceivably to some other location). The details of how you do this depend on your OS and your computer (UEFI-based PC vs. Macintosh). The upcoming sections provide details. See the Contents sidebar to the left for links to specific installation procedures. For most Linux users, an RPM or Debian package is the best way to go. If your Linux system doesn't support these formats, though, or if you're running OS X, using the refind-install script can be a good way to go. If you're using Windows, you'll have to install manually.

Installing rEFInd Using an RPM or Debian Package File

I provide RPM and Debian package files for rEFInd; and starting with version 0.8.1, I'm maintaining an Ubuntu PPA for rEFInd. If you have a working RPM-based or Debian-based Linux installation that boots in EFI mode, using one of these files is likely to be the easiest way to install rEFInd: You need only download the file and issue an appropriate installation command. In some cases, double-clicking the package in your file manager will install it. If that doesn't work, a command like the following will install the RPM on an RPM-based system:

# rpm -Uvh refind-0.11.4-1.x86_64.rpm

On a Debian-based system, the equivalent command is:

# dpkg -i refind_0.11.4-1_amd64.deb

Either command produces output similar to that described for using the refind-install script, so you can check it for error messages and other signs of trouble. The package file installs rEFInd and registers it with the EFI to be the default boot loader. The script that runs as part of the installation process tries to determine if you're using Secure Boot, and if so it will try to configure rEFInd to launch using shim; however, this won't work correctly on all systems. Ubuntu 12.10 users who are booting with Secure Boot active should be wary, since the resulting installation will probably try to use Ubuntu's version of shim, which won't work correctly with rEFInd. The shim program provided with more recent versions of Ubuntu should work correctly. Also, since version 0.11.0, refind-install supports storing Secure Boot private keys in an encrypted form. If you set up rEFInd in this way, the RPM or Debian package will fail to install, since it assumes an unencrypted Secure Boot key.

If you're using Ubuntu, you should be able to install the PPA as follows:

$ sudo apt-add-repository ppa:rodsmith/refind
$ sudo apt-get update
$ sudo apt-get install refind

The PPA version asks if you want to install rEFInd to your ESP. (Chances are you want to respond affirmatively.) The PPA version will update automatically with your other software, which you might or might not want to have happen. It's also built with GNU-EFI rather than with TianoCore. This last detail should have no practical effects, but it might be important if you've got a buggy EFI or if there's some undiscovered rEFInd bug that interacts with the build environment.

Since version 0.6.3, the installation script makes an attempt to install rEFInd in a bootable way even if you run the script from a BIOS-mode boot, and therefore the RPM and Debian packages do the same. I cannot guarantee that this will work, though, and even if it does, some of the tricks that refind-install uses might not persist for long. You might therefore want to use mvrefind to move your rEFInd installation to another name after you boot Linux for the first time from rEFInd.

Since version 0.6.2-2, my package files have installed the rEFInd binaries to /usr/share/refind-version, the documentation to /usr/share/doc/refind-version, and a few miscellaneous files elsewhere. (The PPA package omits the version number from the file paths.) Upon installation, the package runs the refind-install script to copy the files to the ESP. This enables you to re-install rEFInd after the fact by running refind-install, should some other tool or OS wipe the ESP or should the installation go awry. In such cases you can use refind-install or install manually.

Installing rEFInd Using refind-install under Linux or Mac OS X

If you're using Linux or Mac OS X, the easiest way to install rEFInd is to use the refind-install script. This script automatically copies rEFInd's files to your ESP or other target location and makes changes to your firmware's NVRAM settings so that rEFInd will start the next time you boot. If you've booted to OS X or in non-Secure-Boot EFI mode to Linux on a UEFI-based PC, refind-install will probably do the right thing, so you can get by with the quick instructions. If your setup is unusual, if your computer uses Secure Boot, or if you want to create a USB flash drive with rEFInd on it, you should read the man page for this utility.

By default, the refind-install script installs rEFInd to your disk's ESP. Under Mac OS X, you can instead install rEFInd to your current OS X boot partition by passing the script the --notesp option, or to a non-boot HFS+ partition by using the --ownhfs devicefile option. Under either OS, you can install to something other than the currently-running OS by using the --root /mountpoint option. (See Table 1 for details.)

Under Linux, refind-install will be most reliable if your ESP is already mounted at /boot or /boot/efi, as described in more detail in the Installing rEFInd Manually Using Linux section. (If you installed Linux in EFI mode, chances are your ESP is properly mounted.) If your ESP is not so mounted, refind-install will attempt to locate and mount an ESP, but this action is not guaranteed to work correctly. If you run refind-install from a BIOS/legacy-mode boot, particularly on a computer that also runs Windows, you should be aware that the tricks the script uses to install itself from BIOS mode are rather delicate. You can convert to a more conventional configuration using the mvrefind script after you've booted in EFI mode.

Prior to version 0.8.4, refind-install installed rEFInd to the OS X root partition by default. I changed this because the default configuration for OS X 10.10 ("Yosemite") makes this placement unusable. Instead, refind-install now installs to the ESP under OS X, just as it does under Linux. If you're upgrading a working install of rEFInd to the OS X root partition, it's best to pass the --notesp option to refind-install. This option is described in more detail shortly.

A sample run under Linux looks something like this:

# ./refind-install
Installing rEFInd on Linux....
ESP was found at /boot/efi using vfat
Installing driver for ext4 (ext4_x64.efi)
Copied rEFInd binary files

Copying sample configuration file as refind.conf; edit this file to configure
rEFInd.


Installation has completed successfully.

The output under OS X is a bit different:

$ ./refind-install
Not running as root; attempting to elevate privileges via sudo....
Password:
Installing rEFInd on OS X....
Installing rEFInd to the partition mounted at /Volumes/ESP
Found suspected Linux partition(s); installing ext4fs driver.
Installing driver for ext4 (ext4_ia32.efi)
Copied rEFInd binary files

Copying sample configuration file as refind.conf; edit this file to configure
rEFInd.

Installation has completed successfully.

Unmounting install dir

In either case, the details of the output differ depending on your existing configuration and how you ran the program. Unless you see an obvious warning or error, you shouldn't be concerned about minor deviations from these examples. If you run into such a situation, or if you want to install in an unusual way, read on....

Note that the change to an ESP location for rEFInd with version 0.8.4 means that, if you upgrade rEFInd from an earlier version, you may notice a rEFInd boot option in the rEFInd menu. This option will boot the old version of rEFInd (or the new one, if something went wrong and the old version continues to boot). You can rid yourself of the unwanted boot menu by deleting the old files or by using dont_scan_dirs or dont_scan_files in refind.conf. Before you do this, you should use rEFInd to identify the unwanted files—the filename and volume identifier appear under the icons when you highlight the option. You can then locate and delete them from within OS X. Before you delete the old files, though, you may want to copy over any changes you've made to the rEFInd configuration, icons, and other support files.

The refind-install script supports a number of options that can affect how it operates. For information on these options, consult the script's man page: Type man refind-install if you installed rEFInd via an RPM or Debian package; or read it in HTML form.

Installing rEFInd Manually

Sometimes the refind-install script just won't do the job, or you may need to install using an OS that it doesn't support, such as Windows. In these cases, you'll have to install rEFInd the old-fashioned way, using file-copying commands and utilities to add the program to your EFI's boot loader list. I describe how to do this with Linux, OS X, Windows, and the EFI shell.

Installing rEFInd Manually Using Linux

On a UEFI-based PC, you'll normally install rEFInd to the ESP, which is usually mounted at /boot/efi. You can verify that this is the case by using the df command:

$ df /boot/efi
Filesystem     1K-blocks  Used Available Use% Mounted on
/dev/sda1         191284 16604    174681   9% /boot/efi

This example shows that /dev/sda1 is mounted at /boot/efi, which is a typical configuration. (The ESP can be on another disk or partition, but /dev/sda1 is the most common place for an ESP.) If your output shows /boot or / under the Mounted on column, then your ESP isn't mounted. (An exception is if you're mounting the ESP at /boot. This is an unusual configuration. If you're using it, you can proceed, making suitable adjustments to subsequent commands.) If you get a df: `/boot/efi': No such file or directory error message, then the /boot/efi directory doesn't even exist. In such cases, you may need to jump through some extra hoops, as described on my EFI Boot Loader Installation page.

Assuming the ESP is mounted at /boot/efi, you can install the rEFInd files as follows (you must be root to issue these commands, or precede each of them with sudo):

  1. Type cp -r refind /boot/efi/EFI/ from the refind-version directory in which the refind directory exists. This copies all the files that rEFInd needs to work. Note that this includes all of rEFInd's drivers. This command also copies the rEFInd binaries as signed by me; if you prefer to re-sign the binaries yourself, you'll have to do so before or during the copy operation, as described on the Managing Secure Boot page.
  2. Type cd /boot/efi/EFI/refind to change into rEFInd's new directory on the ESP.
  3. You may optionally remove the rEFInd binaries for the CPU types you're not using. For instance, you might type rm refind_ia32.efi refind_aa64.efi to remove the IA32 and AARCH64 binaries if you're using an x86-64 (AMD64, X64) system.
  4. Similarly, you may optionally remove the drivers subdirectories for the CPU types you're not using. For instance, you could type rm -r drivers_ia32 drivers_aa64 to remove the x86 and ARM64 drivers from an x86-64 system. You may also want to remove some or all of the drivers for the architecture you are using. If you don't need them, they'll slow down the start process, and worse, loading unnecessary drivers can cause some systems to hang or interfere with the drivers you do need. See the page on drivers for more on this topic.
  5. Rename the configuration file by typing mv refind.conf-sample refind.conf. Consult the Editing the rEFInd Configuration File page for information on how to adjust your options.
  6. On a UEFI-based system, type efibootmgr -c -l \\EFI\\refind\\refind_x64.efi -L rEFInd to add rEFInd to your EFI's list of available boot loaders, which it stores in NVRAM. Adjust the path to the binary as required if you install somewhere else. You may also need to include additional options if your ESP isn't on /dev/sda1 or if your configuration is otherwise unusual; consult the efibootmgr man page for details. You may need to install this program on some systems; it's a standard part of most distributions' repositories. Also, if you're installing in Secure Boot mode, you must normally register shim.efi rather than the rEFInd binary, and rename refind_x64.efi to grubx64.efi. Shim 0.7 and later enables you to keep rEFInd's usual name by adding a -u "shim.efi refind_x64.efi" option to your efibootmgr command line, though. Change the filenames to the ones used by your actual Shim and rEFInd binaries, respectively.
  7. If other boot loaders are already installed, you can use efibootmgr to adjust their boot order. For instance, efibootmgr -o 3,7,2 sets the firmware to try boot loader #3 first, followed by #7, followed by #2. (The program should have displayed a list of boot loaders when you added yours in the preceding step.) Place rEFInd's number first to set it as the default boot program.

Note the use of doubled-up backslashes (\\) rather than forward slashes (/) in the directory separators when using efibootmgr. This command will work on most systems that are already booted into EFI mode; however, it won't work if you're booted in BIOS mode. You may also need to add options if your ESP is in some unusual location or if your system is unusual in some way. Consult the efibootmgr man page if you need help.

On some systems, efibootmgr won't do what you expect. On such systems, you may have better luck renaming the rEFInd files, as described in the Alternative Naming Options section.

Installing rEFInd Manually Using Mac OS X

Before installing rEFInd on a Mac, you must determine whether it uses a 32-bit or 64-bit EFI implementation. Most Intel-based Macs have 64-bit EFIs, so you should use the refind_x64.efi file with them; but very early Intel-based Macs have 32-bit EFIs (and sometimes 32-bit CPUs), which require the refind_ia32.efi file. You can determine whether your Mac needs the x86-64 or IA32 build by typing the following command in a Mac Terminal window:

$ ioreg -l -p IODeviceTree | grep firmware-abi

The result should include either EFI32 or EFI64, indicating that you should use the refind_ia32.efi or refind_x64.efi binary, respectively.

You should also be aware of your OS X version and installation options. If you used whole-disk encryption (WDE) or a logical volume for installation, you cannot install to the OS X root partition; you must install to the ESP or to a separate HFS+ partition. WDE became an option with OS X 10.7 and logical volumes are the default in OS X 10.10. If in doubt, proceed with an installation to the ESP or to a separate HFS+ partition.

The procedure for installing rEFInd on a Mac is similar to that for installing it under Linux, except that you must use the bless utility rather than efibootmgr to register the program with the firmware. Also, you'll probably have to mount your ESP manually, since that's not done by default under OS X. To be precise, you should follow these steps:

  1. Open a Terminal window in which you'll type the following commands.
  2. If you want to install rEFInd on your ESP, you must first mount it. The easy way to do this is to use the mountesp script that comes with rEFInd. When you run it, the script should tell you where the ESP was mounted. You can do the job manually by typing mkdir /Volumes/ESP followed by sudo mount -t msdos /dev/disk0s1 /Volumes/ESP. Note that you may need to change /dev/disk0s1 to something else if your ESP is at an unusual location. Type diskutil list or use a tool such as my GPT fdisk (gdisk) to examine your partition table to find your ESP if necessary.
  3. Type sudo mkdir -p /Volumes/ESP/efi/refind to create a suitable directory for rEFInd. If you want to place rEFInd on the OS X root partition, you should adjust the pathname appropriately, as in /efi/refind. Alternatively, you can use the Finder to create the directory.
  4. Copy the files in the refind subdirectory of the rEFInd binary package to the like-named directory you've just created. You can do this in the Finder or by typing sudo cp -r refind/* /Volumes/ESP/efi/refind/ in your Terminal window after changing into the rEFInd package's main directory.
  5. Remove the files for the versions of rEFInd you're not using, as in sudo rm Volumes/esp/efi/refind/refind_ia32.efi Volumes/esp/efi/refind/refind_aa64.efi on a Mac with a 64-bit EFI or sudo rm /Volumes/ESP/efi/refind/refind_x64.efi Volumes/esp/efi/refind/refind_aa64.efi on a Mac with a 32-bit EFI.
  6. Optionally, remove the drivers directories for the architectures you're not using—/Volumes/ESP/efi/refind/drivers_ia32 or /Volumes/ESP/efi/refind/drivers_x64, as appropriate. (No Mac uses an ARM CPU, so you'd also remove /Volumes/ESP/efi/refind/drivers_aa64 You may also want to remove some or all of the drivers for the architecture you are using; if you don't need them, they'll slow down the start process. See the page on drivers for more on this topic. Note that Apple's firmware includes its own HFS+ driver, so the HFS+ driver provided with rEFInd is useless on Macs.
  7. If this is your first installation, type sudo mv /Volumes/ESP/efi/refind/refind.conf-sample /Volumes/ESP/efi/refind/refind.conf (adjusting the path as necessary) to rename the sample configuration file so that it will serve as a real configuration file. (Again, you can do this with the Finder, if you prefer.)
  8. "Bless" rEFInd by typing one of the following two commands:
    • If you're installing rEFInd on the ESP, type sudo bless --mount /Volumes/ESP --setBoot --file /Volumes/ESP/efi/refind/refind_x64.efi --shortform, adjusting the mount point and exact path to the file as appropriate for your installation.
    • If you're installing rEFInd to an ordinary HFS+ volume, type sudo bless --setBoot --folder /efi/refind --file /efi/refind/refind_x64.efi. (Adjust the path and filename as necessary if you're placing rEFInd somewhere else or using the 32-bit version.)
    This is the step that's likely to fail if your system is booted with SIP active.
  9. If you don't want to reboot immediately after installing rEFInd, you may optionally unmount the ESP by typing sudo umount /dev/disk0s1 or sudo umount /Volumes/ESP. This step isn't strictly required, but if you want to keep the ESP out of your directory tree, it can be useful.

When you reboot, your Mac should bring up the rEFInd menu, and should continue to do so thereafter. If you make changes that break this association, you can re-run the bless command (if necessary, restoring the rEFInd files first). This might be necessary after installing system updates from Apple or if you upgrade rEFInd to a newer version.

If you're replacing rEFIt, you may discover that rEFInd works on the first boot, but the system reverts back to rEFIt or a direct boot to OS X on the second boot. To fix this problem, you can remove the rEFItBlesser program, which is located at /Library/StartupItems/rEFItBlesser. This program attempts to keep rEFIt set as the default boot loader, but it also has the purpose of protecting the computer from launching the wrong OS after waking from sleep. If you want that protection, my suggestion is to install rEFIt and rEFItBlesser and then replace the refit.efi file with refind_x64.efi or refind_ia32.efi (renaming it to refit.efi). Used in this way, rEFInd will still look for its own configuration file, refind.conf, so you'll need to move it but not rename it. If you don't move the icons from the rEFInd package, your icons will continue to look like rEFIt icons, and you'll be missing the new icons for specific Linux distributions that rEFInd provides. One final caveat: It's conceivable that rEFItBlesser is what's causing filesystem corruption for some users, so if you've been having this problem with rEFIt, it might be worth disabling this program and not using it with rEFInd.

If you want to remove rEFInd from your system, you can delete its files. The Mac will revert to booting using whatever standard boot loader it can find. Alternatively, you can use bless to bless another EFI boot loader. The GUI Startup Disk utility in System Preferences provides a simplified interface that enables you to select which OS X installation to boot, but it doesn't look for non-Apple boot loaders, so you can't use it to enable rEFInd.

Installing rEFInd Manually Using Windows

I know relatively little about Windows EFI management tools; however, I do know that at least two relevant tools exist: the standard bcdedit and the third-party EasyUEFI.

The EasyUEFI tool is a free (as in beer) GUI tool for managing EFI boot programs. I've only tried it once, and it seemed fairly intuitive and easy to use, but I don't have detailed instructions on how to use it. If you want to use EasyUEFI, you'll have to use it in place of bcdedit at the end of the following procedure.

Attempt this method of installation only on a UEFI-based PC; this method will not work on Windows that's installed on a Mac in BIOS/CSM/legacy mode. To install rEFInd under Windows, you must first find a way to access the ESP, which Windows normally hides from view. One way to accomplish this goal, and to proceed forward once the ESP is accessible, is as follows:

  1. Locate Command Prompt in the Start menu, right-click it, and select Run as Administrator. This action opens a Command Prompt window with administrative privileges.
  2. Type mountvol S: /S in the Administrator Command Prompt window. This makes the ESP accessible as drive S: from that window. (You can use a drive identifier other than S: if you like.)
  3. Change into the main rEFInd package directory, so that the refind subdirectory is visible when you type dir.
  4. Type xcopy /E refind S:\EFI\refind\ to copy the refind directory tree to the ESP's EFI directory. If you omit the trailing backslash from this command, xcopy will ask if you want to create the refind directory. Tell it to do so.
  5. Type S: to change to the ESP.
  6. Type cd EFI\refind to change into the refind subdirectory
  7. You may want to selectively delete some of the drivers in the drivers_x64, drivers_ia32, or drivers_aa64 directory, depending on your architecture and needs. Unnecessary drivers will slow the rEFInd start process, and can even cause the drivers you need to not work or cause a system crash. See the page on drivers for more on this topic.
  8. Type rename refind.conf-sample refind.conf to rename rEFInd's configuration file.
  9. Type bcdedit /set "{bootmgr}" path \EFI\refind\refind_x64.efi to set rEFInd as the default EFI boot program. Note that "{bootmgr}" is entered as such, including both the quotes and braces ({}). Also, change refind_x64.efi to refind_ia32.efi on systems with 32-bit EFIs. Such computers are rare, and most of them are tablets. Check your Windows bit depth to determine which binary you should use.
  10. If you like, type bcdedit /set "{bootmgr}" description "rEFInd description" to set a description (change rEFInd description as you see fit).

At this point, when you reboot, rEFInd should appear as your new default boot program. If it doesn't work for you, you have several other options, such as:

  • You can rename files on the ESP. as described later, in Alternative Naming Options.
  • You can boot from an optical disc into an emergency OS to do the job. Ubuntu, for instance, provides an EFI-bootable installer with a "try before installation" mode. You'll need to type sudo apt-get install efibootmgr to install efibootmgr, but you can then use that program as described earlier. (If you're using Ubuntu, you'll need to precede the command with sudo. If you use an Ubuntu image, you can install rEFInd via its PPA, which is an easy way to do the job. (In fact, the rEFInd PPA depends on the efibootmgr package, so you shouldn't need to manually install it.) The PPA approach may even be easier than installing from Windows using its tools, at least if you're familiar with Linux and have an Ubuntu desktop image handy.
  • You may be able to use rEFInd's bootable CD image to use rEFInd to boot an OS that's been installed but rendered inoperable because of changes to your boot order. You can then use efibootmgr, bless, or some other tool to restore rEFInd as the default boot loader.

Installing rEFInd Manually Using an EFI Shell

If you can't currently boot any OS (say, because a firmware update has wiped your NVRAM entries), you may find it convenient to install rEFInd using an EFI version 2 shell. Unfortunately, the bcfg command described here is not available in the EFI version 1 shell, and the version 2 shell is unusable on many firmware implementations prior to 2.3.1. Thus, this procedure won't work for all systems.

In addition to emergency situations, using bcfg can be desirable if efibootmgr or other OS-hosted tools don't do the job. This happens under VirtualBox, for instance. An alternative in such cases can be to use alternative names for rEFInd.

To begin, you must have a way to launch your shell. Unfortunately, this can pose a dilemma, since without rEFInd or some other boot manager, many EFI implementations lack the means to launch a shell. Some will do so, though, if the shell is stored as shellx64.efi (for x86-64) or shellia32.efi (for x86) in the root directory of the ESP. Thus, you can try copying your shell file there. You can obtain EFI 2 shells here:

Once you've booted the shell, you can proceed as follows:

  1. If you haven't installed rEFInd previously, unpack its zip file to a FAT partition. This can be the ESP itself or another partition, such as a USB flash drive. If you're simply repairing a lost NVRAM entry, you needn't move your existing rEFInd files.
  2. Identify your filesystems, which are labelled with the form fsn:, as in fs0: for the first filesystem, fs1: for the second, and so on. Type the filesystem number followed by the Enter key to begin using it. You can then type ls or dir to see the contents of the filesystem. Chances are your ESP will be fs0:, but it could be something else. (The following steps assume your ESP is fs0:; you'll need to adjust them if it's not.) If rEFInd's source files are on another device, you must identify it, too.
  3. If necessary, create a directory for rEFInd by typing mkdir fs0:\EFI\refind. (If the fs0:\EFI directory doesn't already exist, you must create it first, though.)
  4. Change to the directory in which rEFInd's files exist.
  5. Type cp refind_x64.efi fs0:\EFI\refind to copy the rEFInd binary file. (Adjust the name if you're using an IA32 or AARCH64 computer.)
  6. Type cp refind.conf-sample fs0:\EFI\refind\refind.conf to copy and rename the sample rEFInd configuration file.
  7. Type cp -r icons fs0:\EFI\refind\ to copy rEFInd's icons.
  8. Optionally, type cp -r drivers_x64 fs0:\EFI\refind\ to copy rEFInd's X64 drivers. (You could instead copy the IA32 or AARCH64 drivers or limit yourself to just the drivers you need, of course.)
  9. Type fs0:, if necessary, to change to the ESP.
  10. Type cd \EFI\refind to change to rEFInd's installation directory.
  11. If you want to edit rEFInd's options, type edit refind.conf and use the shell's built-in text editor to do so. Press F2 followed by the Enter key to save your changes and F3 to exit.
  12. Type bcfg boot dump -b to see a list of existing NVRAM entries. Pay attention to their numbers (labelled Option: and Variable:, with the latter number preceded by the string Boot, as in Boot0007). You'll want to create a boot entry for rEFInd using a number that's not in use.
  13. Type bcfg boot add 3 fs0:\EFI\refind\refind_x64.efi "rEFInd", adjusting the number (3 in this example), filesystem (fs0:), and filename (\EFI\refind\refind_x64.efi) as necessary for your system. If you're used to Linux, be sure to use backslashes (\), not Linux-style forward slashes (/), as directory separators. Note that some shells may ignore the number you entered and use another one, so watch for this possibility.
  14. Type bcfg boot mv 3 0, substituting the option number for the entry you created for 3. This moves rEFInd to the top of the boot order.
  15. Type reset to reboot the computer.

With any luck, rEFInd will start up at this point. If not, you can check your settings using a shell or an emergency system for your OS of choice. In an EFI shell, you might type bcfg boot dump -b to view your boot loader entries and verify that rEFInd appears at the top of the list. Be sure to check the pathname for typos. If you continue to have problems, you might look into giving rEFInd a fallback filename that your firmware will recognize.

Alternative Naming Options

Some EFI implementations do a poor job of honoring the boot options set via Linux's efibootmgr or other tools. You may also lack access to such utilities, such as if you must install rEFInd in Windows. In such cases, you may need to change the boot loader's name so that the EFI will see it as the default boot loader. rEFInd should then boot when your NVRAM lacks information on specific boot loaders to use. Broadly speaking, there are two alternative names that are most useful:

  • EFI/BOOT/bootarch.efi—This name is the official EFI fallback filename. It's most commonly used on bootable removable disks, but it can be used on hard disks. It's typically used only if no NVRAM entry points to a valid boot loader.
  • EFI/Microsoft/Boot/bootmgfw.efi—This filename has no official special standing in the EFI specification, but as a practical matter, many EFI implementations use it as a fallback boot loader in addition to or instead of EFI/BOOT/bootarch.efi. In fact, some give it such a high precedence that you can't boot anything that's not given this name!

If you need to use one of these names, or something more exotic, you can do so in either of two ways: You can use the mvrefind script to move your installation in one step, or you can move and rename your files manually.

Using mvrefind

The easiest way to move a rEFInd installation, at least in Linux, is to use the mvrefind script. If you installed from one of my RPM or Debian packages, this script should be installed in /usr/sbin, so you can use it like a regular Linux command; otherwise you'll need to install it to your path yourself or type its complete path. Either way, it works much like the Linux mv command, but you pass it the directory in which a rEFInd installation appears and a target location:

# mvrefind /boot/efi/EFI/BOOT /boot/efi/EFI/refind

This example moves rEFInd from /boot/efi/EFI/BOOT to /boot/efi/EFI/refind. It differs from mv in several ways:

  • The script renames rEFInd in a way that's sensitive to its source and destination directories—for instance, mvrefind knows that rEFInd (or shim, for Secure Boot installations) must be called bootx64.efi on a 64-bit installation in /boot/efi/EFI/BOOT, so it looks for rEFInd under that name when copying from this directory, or it renames rEFInd to that name when copying to it.
  • The script creates a new NVRAM entry for rEFInd when it copies to any location but EFI/BOOT or EFI/Microsoft/Boot. It refuses to copy to such locations if it's not run from an EFI-mode boot.
  • The script knows enough to back up existing boot loaders stored in EFI/BOOT or EFI/Microsoft/Boot when copying to these locations. For the former location, the script backs up EFI/BOOT as EFI/BOOT-rEFIndBackup; for the latter, it moves EFI/Microsoft/Boot/bootmgfw.efi to EFI/Microsoft/bootmgfw.efi.

The mvrefind script is likely to be useful in resolving boot problems—if your system won't boot, you can try copying the installation to /boot/efi/EFI/BOOT, /boot/efi/EFI/Microsoft/Boot, and /boot/efi/EFI/refind in turn, testing the boot process after each attempt. (These filenames all assume your ESP is mounted at /boot/efi.) You could also copy a BIOS-mode install from /boot/efi/EFI/BOOT or /boot/efi/EFI/Microsoft/Boot to /boot/efi/EFI/refind to make it more robust against Windows repairs (assuming your firmware isn't broken).

Renaming Files Manually

You can move and rename rEFInd manually from any OS by following these steps:

  1. Access your ESP, as described in earlier sections.
  2. Look for an existing directory called EFI/BOOT or EFI/Microsoft/Boot. If neither of these directories exist, skip the next step. (Note that FAT is case-insensitive, so the name may vary in case.)
  3. Rename the existing directory or boot loader file to something else. For EFI/BOOT, try renaming it to EFI/Oldboot. For EFI/Microsoft/Boot, move or rename the bootmgfw.efi file it contains. For instance, you can move it to EFI/Microsoft. This will keep the boot loader accessible to rEFInd's menu, while preventing the firmware from launching it automatically.
  4. Rename/move your EFI/refind directory to EFI/BOOT. If you're working from EFI/Microsoft/Boot, you should move the contents of your rEFInd directory to EFI/Microsoft/Boot.
  5. Rename EFI/BOOT/refind_x64.efi to the name of the boot loader it's replacing—it should become EFI/BOOT/bootx64.efi or EFI/Microsoft/Boot/bootmgfw.efi.

When you reboot, rEFInd should come up. With any luck, it will detect your old boot loader as an option, if one was installed before.

Upgrading rEFInd

If you've installed an earlier version of rEFInd, you can upgrade a bit more easily than you can install directly:

  • On a UEFI-based PC, under any OS, you should be able to replace your old rEFInd file with the new one. Make sure that the new rEFInd has the same name as the old one, and that it's for the correct CPU type. Since UEFI launches boot programs by filename, a simple file replacement will suffice to launch the new version. If the new version includes new icons, you may want to copy some or all of them.
  • On a Mac, you can copy over the old rEFInd binary file from Linux and it will usually work, provided you copy directly over the old file (rather than rename or delete the old file and then copy the new one in its place). The same caveats about icons as apply to UEFI-based PCs apply in this case. This method requires an extra step in Mac OS X, though....
  • In OS X, if you copy over the original file with the new one, you'll probably have to re-bless it to make it work.
  • Under Linux or OS X, you can re-run the refind-install script. In most cases this works fine, but you'll end up with a duplicate of the icons directory (icons-backup, which holds the original icons, whereas icons holds the icons from the new package). Normally this just wastes some disk space; but if you've customized your icons, you'll need to copy your altered icons back. Under Linux, versions 0.6.2 and later of refind-install search for rEFInd in several locations on the ESP, and will upgrade whatever is found. The same is true with versions 0.8.5 and later under OS X when installing to the ESP. If you install to a location other than the ESP under OS X, be sure to include the same option to refind-install (--notesp or --ownhfs) to replace the original rather than create a new installation to the ESP.
  • Under an RPM- or Debian-based Linux distribution, you can use your package system to install a newer version of the RPM or Debian package that I provide. This will upgrade the files in your Linux filesystem and re-run the refind-install script, so as with the previous options, you'll waste a little disk space on duplicated icons, but the process should otherwise work quite well.
  • If you installed using my Ubuntu PPA or a package provided by an OS distribution (such as the packages that ship with Arch and ALT Linux), performing a system update will probably update rEFInd, too. Depending on how the package was created, though, this update might or might not install the update to the ESP; you might need to manually re-run the installation script. Consult your distribution's documentation for details. My Ubuntu PPA will automatically run refind-install after the package is installed if you selected the option to install to the ESP; if you opted to skip this step, my PPA version will continue to do so at every update, leaving you to manually update the copy on the ESP. (You can change this behavior by typing sudo dpkg-reconfigure refind.)

In all cases, if the new version includes new or altered configuration file options, you may need to manually update your configuration file. Alternatively, if you've used the default configuration file, you can replace your working refind.conf with refind.conf-sample from the rEFInd zip file. (When using refind-install, this file will be copied to rEFInd's installation directory under its original name, so you can rename it within that directory to replace the old file.)

If you're upgrading to rEFInd from rEFIt, you can simply run the refind-install script as described earlier or perform a manual installation. Once installed, rEFInd will take over boot manager duties. You'll still be able to launch rEFIt from rEFInd; a rEFIt icon will appear in rEFInd's menu. You can eliminate this option by removing the rEFIt files, which normally reside in /EFI/refit.

Installing Additional Components

rEFInd includes the ability to launch any EFI program; however, rEFInd detects only certain programs. These include boot loaders in traditional locations and a handful of other programs. To launch most of these other programs, you must download and install them separately from rEFInd:

  • shell.efi—This file, placed in the ESP's EFI/tools directory, adds the ability to launch a text-mode EFI shell from rEFInd. Note that the download link is to a 64-bit binary that must be renamed before rEFInd will recognize it. Additional shell download links appear on the Arch Linux wiki, and on other sites; try a Web search if the shell you find doesn't work to your satisfaction.
  • Memtest86—This is a popular tool for performing basic hardware tests, and especially memory tests. rEFInd recognizes this program when it is stored in the EFI/tools, EFI/tools/memtest, EFI/tools/memtest86, EFI/memtest, or EFI/memtest86 directory, with a program filename of memtest86.efi, memtest86_x64.efi, memtest86x64.efi, or bootx64.efi. (Change x64 to ia32 on IA-32 systems.) Be sure to download the EFI version of the program. If you get the USB flash drive version, you should mount the flash drive's ESP (partition 2) and copy the EFI/BOOT directory to your own ESP's EFI/tools/memtest or other Memtest86 directory name, as just specified. rEFInd should then recognize it, provided the showtools line includes the memtest or memtest86 token.
  • gptsync.efi or gptsync_arch.efi—This program creates a hybrid MBR from your regular GPT disk. A hybrid MBR is a dangerous hack that enables Windows and OS X to coexist on a Macintosh disk. If you're using a UEFI-based PC, a hybrid MBR is likely to be useless at best, so you shouldn't create one, and it's safest to not install gptsync.efi. If you're using a hybrid MBR to enable dual-booting Windows and OS X on a Mac, though, placing this program file in the ESP's or Mac boot partition's EFI/tools directory will enable you to regenerate your hybrid MBR should some other tool convert the MBR to a standard protective MBR. You can obtain the file from the original rEFIt package, or beginning with rEFInd 0.6.9, an updated version is included in the rEFInd package. The rEFInd version of gptsync_arch.efi uses a more sophisticated algorithm for determining what GPT partitions to duplicate in the MBR and it includes additional safeguards to minimize the risk of damage should you run the program on a disk that might have been damaged. The original rEFIt version of the program usually goes by the filename gptsync.efi, whereas the updated rEFInd version ships with an architecture code, as in gptsync_x64.efi or gptsync_ia32.efi. The rEFInd refind-install script installs gptsync_arch.efi when run under OS X, but not when run on Linux. In addition to installing the program, you must edit refind.conf, uncomment the showtools line, and add gptsync to its list of options.
  • Drivers—You can install drivers to extend the capabilities of the EFI. rEFInd ships with filesystem drivers for ext2fs, ext4fs, and ReiserFS, which can enable you to boot a Linux kernel with EFI stub support from an ext2fs, ext3fs, ext4fs, or ReiserFS partition. (rEFInd also provides ISO-9660 and HFS+ drivers.) You can find additional drivers from other sources, although they're still on the scarce side. See the Using EFI Drivers page for more on this topic.
  • Secure Boot files—If you're running on a system that supports Secure Boot, chances are you'll need extra support files, such as shim.efi and MokManager.efi. I describe these in detail on the Managing Secure Boot page.
  • iPXE—This tool provides the ability to boot a computer from a network server. Consult the BUILDING.txt file in the rEFInd source code package for information on building and installing these tools. You must also activate rEFInd's support by adding the netboot option to the scanfor and/or showtools lines in refind.conf. Network-boot/iPXE support is currently experimental; I recommend that only developers or those who are willing to use "bleeding-edge" software try it. Once activated, rEFInd will present a new menu item for booting from the network server. rEFInd itself will normally be installed locally. (You can deliver rEFInd as a network-boot image, but that image will be able to boot only OSes on the local disk.)

I've seen links to other versions of these tools from time to time on the Web, so if you try one of these programs and it crashes or behaves strangely, try performing a Web search; you may turn up something that works better for you than the one to which I've linked.

Fixing Macintosh Boot Problems

I've received a few reports of a sluggish boot process (a delay of about 30 seconds before starting rEFInd) on some Macs after installing rEFInd, as well as some other Mac-specific peculiarities. I've been unable to replicate thess problems myself, and their true causes remains mysterious to me. I have found several possible solutions, though: Using the --shortform option, using the fallback filename, moving rEFInd to an HFS+ volume, clearing NVRAM entries, fixing wake problems, and fixing a failure to find Linux.

Using the --shortform Option

Prior to version 0.8.5, these instructions and the refind-install script omitted the --shortform option from the bless command when installing rEFInd to the ESP. A rEFInd user, however, discovered that using the option eliminated the 30-second delay, so it is now the default with 0.8.5's refind-install, and is specified in the instructions. If you installed rEFInd 0.8.4 or earlier, you may want to re-install or re-bless rEFInd using this option.

There is one caveat, though: The man page for bless notes that --shortform notes that its use can come "at the expense of boot time performance." Thus, it's not clear to me that this option might not actually create problems on some computers. (It's eliminated the boot delay on my 2014 MacBook Air and has no detrimental effect on an old 32-bit Mac Mini that's never had a boot delay problem, though.) Thus, if you have problems with rEFInd 0.8.5 or later, you might try running bless, as described in Installing rEFInd Manually Using OS X's step 8, but omit the --shortform option.

Using the Fallback Filename

I've received a few reports that installing rEFInd to the ESP using the fallback filename (EFI/BOOT/bootx64.efi on most systems, or EFI/BOOT/bootia32.efi on very old Macs) can work around a sluggish boot problem. In fact, version 0.8.4's refind-install script copied the rEFInd binary to this name when run under OS X. (Version 0.8.5 switches to using --shortform with the more conventional EFI/refind/refind_x64.efi or EFI/refind/refind_ia32.efi name, as just noted.) If you installed to a name other than EFI/BOOT/BOOT{ARCH}, either manually or by using the 0.8.5 or later refind-install, renaming (and re-blessing) the installation is worth trying.

Moving rEFInd to an HFS+ Volume

Most of the reports of sluggish Macintosh boots I've seen note that the user installed rEFInd to the ESP rather than to the OS X root partition. Some users have reported that re-installing rEFInd to the OS X root partition clears up the problem. This is obviously a straightforward solution to the problem, if it works. (This location is not an option when using WDE or OS X logical volumes.) Note that rEFInd can launch boot loaders that are stored on any partition that the EFI can read no matter where it's installed; therefore, you'll still be able to launch boot loaders stored on the ESP (or elsewhere) if you install it in this way.

A variant of this solution is to create a small (~100MiB) HFS+ volume to be used exclusively by rEFInd. You can then install rEFInd to that volume with the --ownhfs option to refind-install, as in ./refind-install --ownhfs /dev/disk0s6 if the volume is /dev/disk0s6. This approach has the advantage that it can be managed via OS X's own Startup Disk tool in System Preferences.

The biggest drawback to storing rEFInd on an HFS+ volume is that you won't be able to edit the rEFInd configuration file or move rEFInd-related binaries from an EFI shell if you install it in this way, since Apple's HFS+ driver for EFI is read-only. (The same is true of rEFInd's HFS+ driver, so it won't help you overcome this limitation.) You may also be limited in making changes to your rEFInd configuration from Linux or other OSes, too, since Linux's HFS+ drivers disable write support by default on volumes with an active journal. You can force write access by using the force option to mount; however, this procedure is noted as being risky in the Linux HFS+ documentation, so I don't recommend doing this on a regular basis on the OS X boot volume. This isn't as risky if you use a dedicated HFS+ rEFInd partition, though. You could even mount it as the Linux /boot partition, in which case it would also hold the Linux kernel and related files.

A variant of this solution is suggested in this blog post, which recommends placing rEFInd on an HFS+ volume on the first SATA channel. (In the blogger's case, that channel used to hold an optical drive, but that drive was replaced by a hard disk.)

Clearing the NVRAM Entries

Another possible solution is documented in a Web forum post. Be aware, though, that this procedure involves using the efibootmgr utility on Macs, which has been known to damage the firmware on some Macs. Other reports indicate that this problem has been fixed with 3.3.0 and later kernels. Thus, I present this information cautiously and with a strong "use at your own risk" warning. If you care to proceed, I recommend you update your Linux kernel to the latest possible version and then proceed as follows:

  1. Boot into Linux.
  2. Type efibootmgr as root to obtain a list of your boot loader entries. Each entry includes a boot number, as in Boot0003 or Boot0027.
  3. Remove all of the boot loader entries except rEFInd's by using efibootmgr's -b bootnum option to specify the boot entry and -B to delete it. For instance, typing efibootmgr -b 0027 -B as root deletes boot entry Boot0027. Issue a separate efibootmgr command for each boot entry.
  4. Re-install rEFInd using the install script. It's unclear from the original post if this meant installing from Linux or from OS X.

Fixing Wake Problems

Some people have reported that installing rEFInd causes problems with resuming from a suspended OS X session. I know of two workarounds to such problems:

  • Install rEFInd to an HFS+ volume using the --ownhfs option to refind-install. Unfortunately, this solution requires either creating a small HFS+ volume for rEFInd or using an already-existing non-bootable HFS+ volume (if you've got one for data storage, for example).
  • Type sudo pmset -a autopoweroff 0 in a Terminal window. This solution is likely to work if sleep operations work normally up to a point, but fail after about three hours.

I've recently acquired a 2014 MacBook Air, but I haven't yet had the chance to try to reproduce this problem and find a workaround. It's on my to-do list, though.

Fixing a Failure to Find Linux

Some users report that rEFInd doesn't detect Linux, or won't boot it when it is found. Broadly speaking, there are two common causes of this problem:

  • A malfunctioning BIOS/legacy boot—If you installed Linux in BIOS/legacy mode, as most online documentation suggests, it could be that your hybrid MBR is missing or damaged. The usual symptom of this problem is that rEFInd shows a generic Linux penguin icon and that selecting it produces a message to the effect that a bootable OS could not be found. As hybrid MBRs are ugly and dangerous, I recommend avoiding them if possible, so my preferred solution to this problem is to set up EFI filesystem drivers and boot that way; however, fixing the hybrid MBR may be an easier solution. This is especially true if you installed a 32-bit version of Linux on a 64-bit Mac (or a 64-bit version on a rare Mac with a 64-bit CPU but a 32-bit EFI).
  • EFI filesystem driver problems—Ideally, rEFInd should be able to load and run your Linux kernel directly, but this approach normally requires you to have a working EFI driver for the filesystem that holds your Linux kernel. This won't always be the case; and even if it is installed, there can be interference from other drivers, so you may need to remove the drivers that you don't use. If drivers are the root of your problem, you won't see any Linux options, or you'll see the one penguin icon (as above) with no others that point to your Linux kernel(s).

If you suspect that your hybrid MBR is damaged, you can try re-creating it with my GPT fdisk (gdisk) program. The GPT fdisk hybrid MBR documentation covers this procedure in detail. You can run gdisk from either OS X or Linux, although you may need to install it, particularly in OS X.

If you suspect driver problems, you'll need to mount your ESP (as described in the manual OS X installation instructions), locate the rEFInd drivers_x64 directory, and adjust its contents. Make sure you have a driver for the filesystem that holds your Linux kernel. If you don't know what filesystem this is, it's probably ext4fs. rEFInd ships with several filesystem drivers, including one for ext4fs. You should also remove unnecessary filesystem drivers. I've seen several reports of one driver interfering with others' operation. The biggest culprit seems to be the HFS+ driver when used on Macs.

Fixing Windows Boot Problems

Most Windows boot problems are best addressed on Windows-specific sites, so I recommend you make the rounds of Windows forums to solve such problems. There is one that deserves mention here, though: If you accidentally erase the Windows boot loader file, EFI/Microsoft/Boot/bootmgfw.efi, you won't be able to boot Windows. The simplest solution is to restore this file from a backup you prepared ahead of time. If you don't have such a backup, though, you can restore it as follows:

  1. Boot from an emergency Windows recovery disk. If you don't have one, you can prepare one from a working Windows system as described here.
  2. Type diskpart to enter the Windows disk-partitioning tool.
  3. In diskpart, type sel disk 0 followed by list vol. You should see a set of partitions. This step is intended to help you identify your ESP, which will probably be the only FAT32 partition on the disk. (If you have multiple disks, you may need to try again with sel disk 1 or higher.) Note the volume number of your ESP.
  4. Type sel vol 1, changing 1 to whatever the ESP's volume number is.
  5. Type assign letter=S: to assign the ESP a Windows disk identifier of S:. (You can use another letter if you prefer.)
  6. Type exit to exit from diskutil.
  7. Type cd /d s:\EFI\Microsoft\Boot\ to change into the Windows boot loader directory. (If this directory doesn't exist, you may need to create it first with mkdir. If rEFInd or some other boot loader occupies this directory, back it up first.
  8. Type bootrec /fixboot.
  9. Type bcdboot c:\Windows /s s: /f ALL. Note that this command should set the Windows boot loader as the default. Omit /f ALL if you don't want to adjust the EFI's default boot program.
  10. Reboot and hope it works! If the computer boots straight to Windows and you want to use rEFInd, use bcdedit in Windows, as described in step 9 of the Installing rEFInd Manually Using Windows section of this page.

For more information, see this SuperUser question and answer.

Uninstalling rEFInd

If you decide you don't want to keep rEFInd, you can uninstall it. Doing so is a matter of removing the rEFInd files from your ESP (or from your OS X boot partition, if you installed the program there). The exact details of how to do this vary from one OS to another, though; and in some cases there are alternatives to completely uninstalling rEFInd that are easier to implement.

Uninstalling rEFInd from Linux

In Linux, a command like the following, typed as root, should remove rEFInd:

# rm -r /boot/efi/EFI/refind

You must type this command as root (or use sudo in some environments, such as under Ubuntu). This example assumes that your ESP is mounted at /boot/efi and that rEFInd is installed in EFI/refind on that partition. If you've mounted your ESP elsewhere, or installed rEFInd elsewhere, you should adjust the command appropriately.

If you installed via an RPM or Debian package in Linux, using your package manager will remove the package files, but not the files that the installer places on your ESP. Thus, you must uninstall those files manually, as just described. To complete the job, you'll also have to remove /boot/refind_linux.conf, and perhaps the /etc/refind.d directory.

Uninstalling rEFInd from OS X

The easiest way to restore the standard OS X boot loader on a Mac is not to uninstall rEFInd; it's to bypass it. This can be accomplished with the Startup Disk item in the System Preferences panel:


The OS X Startup Disk tool enables you to reset a Mac
    to use the standard OS X boot loader.

Select your startup disk (Macintosh HD OS X, 10.11.3 in this example) and then click Restart. The computer should reboot into OS X, bypassing rEFInd.

I recommend stopping here, because the procedure for completely removing rEFInd from a Mac depends on your installation method and tends to be challenging for many Mac users, who are unfamiliar with the necessary command-line tools. Basically, you must reverse the steps described earlier, in Installing rEFInd Manually Using Mac OS X:

  1. You must first determine where rEFInd is installed. This can be any of several locations:
    • If you installed rEFInd 0.8.3 or earlier with the default options, or if you used the --notesp option with rEFInd 0.8.4 or later, it will be /EFI/refind on your main partition
    • If you installed rEFInd 0.8.4 or later with the default options, or if you used the --esp option with rEFInd 0.8.3 or earlier, it will be in EFI/refind or EFI/BOOT on the ESP.
    • If you used the --ownhfs option to refind-install, rEFInd will be in the System/Library/CoreServices directory on the volume you specified.
    • If you installed rEFInd manually, it will be wherever you put it.
    • In all cases, there could be duplicate (inactive) rEFInd files in unexpected places. This is particularly true if you tried installing rEFInd multiple times, each with different options to refind-install. Thus, if you delete rEFInd and it still comes up, you may have deleted the wrong files. (Note that dragging files to the Trash may have no effect, though—at least, not until you empty the Trash.)
  2. If necessary, mount the ESP or rEFInd-specific HFS+ volume, as described in Installing rEFInd Manually Using Mac OS X. (The mountesp script that comes with rEFInd will handle this task.)
  3. Verify that rEFInd is installed in the directory noted in step #1. If a refind.conf file is present, rEFInd is almost certainly installed in that directory. If not, it's not rEFInd there and you should not proceed. Be extra cautious about deleting the System/Library/CoreServices directory, since that's the default location of the OS X boot loader! Never delete this directory from your OS X root (/) partition, only from the partition you specified to refind-install using the --ownhfs option.
  4. Once you've identified the rEFInd directory, delete it, or at least the rEFInd boot file. This file may be called refind_x64.efi, bootx64.efi, boot.efi, or conceivably something else. You may need to use sudo rm at the command line to accomplish this task, as in sudo rm -r /Volumes/ESP/EFI/refind.

Uninstalling rEFInd from Windows

From Windows, you must reverse the directions for installing in Windows—type mountvol S: /S to mount your ESP as S:, then navigate to the S:\EFI directory and delete the refind subdirectory.

Post-Uninstallation Activity (UEFI-Based PCs)

On a UEFI-based PC, when the computer boots and cannot find the rEFInd files, it should move on to the next boot loader in its list. In my experience, some EFI firmware implementations remove boot loaders they can't find from their NVRAM lists, so nothing else will be required, provided you have another working boot loader in your firmware's list. If your firmware doesn't automatically clean up its NVRAM entries, rEFInd's entry will do little harm; however, you can delete it with the efibootmgr utility in Linux:

# efibootmgr --verbose
Timeout: 10 seconds
BootOrder: 0000,0007
Boot0000* rEFInd	HD(2,1b8,64000,f1b7598e-baa8-16ea-4ef6-3ff3b606ac1e)File(\EFI\refind\refind_x64.efi)
Boot0007* CD/DVD Drive	BIOS(3,0,00)PATA: HP DVD Writer 1040r     .
# efibootmgr --delete-bootnum --bootnum 0000
Timeout: 10 seconds
BootOrder: 0007
Boot0007* CD/DVD Drive

This example shows use of efibootmgr's --verbose (-v) option to display boot programs so as to identify which one is rEFInd, followed by --delete-bootnum (-B) to delete a boot program and --bootnum (-b) to identify which one to delete. Of course, in this example there's not much else left, so you'd presumably want to install another boot program at this point! If you already have another one installed, you may want to check the BootOrder line to determine which one will take precedence when you reboot. If you don't like what it shows, you can adjust it with the --bootorder (-o) option; consult efibootmgr's man page for details.

If you're not using Linux, you may be able to find a utility that serves a similar function. Under Windows, the bcdedit command, described in the section on installing rEFInd under Windows, may work, although I've not attempted this.


copyright © 2012–2018 by Roderick W. Smith

This document is licensed under the terms of the GNU Free Documentation License (FDL), version 1.3.

If you have problems with or comments about this Web page, please e-mail me at rodsmith@rodsbooks.com. Thanks.

Go to the main rEFInd page

Preventing and Repairing Boot Coups

Return to my main Web page.

refind-0.11.4/docs/refind/drivers.html0000664000175000017500000010603313372346574020076 0ustar rodsmithrodsmith The rEFInd Boot Manager: Using EFI Drivers

The rEFInd Boot Manager:
Using EFI Drivers

by Roderick W. Smith, rodsmith@rodsbooks.com

Originally written: 4/19/2012; last Web page update: 11/12/2018, referencing rEFInd 0.11.4

This Web page is provided free of charge and with no annoying outside ads; however, I did take time to prepare it, and Web hosting does cost money. If you find this Web page useful, please consider making a small donation to help keep this site up and running. Thanks!

Donate $1.00 Donate $2.50 Donate $5.00 Donate $10.00 Donate $20.00 Donate another value

This page is part of the documentation for the rEFInd boot manager. If a Web search has brought you here, you may want to start at the main page.


Beginning with version 0.2.7, rEFInd has been able to load EFI drivers, and as of version 0.4.0, it has shipped with some EFI filesystem drivers. Although EFI implementations should be able to load drivers prior to rEFInd's launch, in my experience, most EFI implementations offer such poor control over EFI driver loading that they can't be counted on to do this. Thus, if you want to use EFI drivers, rEFInd's ability to do so can be useful. This page tells you why you might want to use drivers, how you can install and use rEFInd's own drivers, where you can go to find other drivers, and provides tips on a few specific drivers.


Why Should You Use EFI Drivers?

EFI supports drivers, which can activate hardware or filesystems in the pre-boot environment. At the moment, EFI drivers are few and far between; but you can or might want to use them for various reasons:

  • You can load a filesystem driver to gain access to files on a filesystem other than FAT (or HFS+ on Macs or ISO-9660 on some systems). This is most likely to be useful on a Linux installation, since a filesystem driver can enable you to store a Linux kernel with EFI stub loader or for use by ELILO on a Linux-native filesystem if your EFI System Partition (ESP) is getting crowded.
  • You can load a driver for a plug-in disk controller to give the EFI access to its disks. Note that this is not required if you place your boot loader (and perhaps your OS kernel) on another disk, or if the plug-in disk controller includes EFI-capable firmware. It could be handy, perhaps in conjunction with a filesystem driver, to enable the EFI to read a boot loader or kernel from a disk on a plug-in controller, though. I've received one report of the NVMe driver from Clover being useful to boot from an aftermarket NVMe disk on a Mac, for instance.
  • You can load a driver for a plug-in network card to enable the computer to boot from the network, or to access the network without booting an OS. Note that rEFInd does not currently support network boots itself, though.
  • You can load a video card driver to set an appropriate video mode or to support a plug-in card that lacks EFI support in ts own firmware.
  • You can load a mouse or touchscreen driver to enable the mouse or touchscreen to work even if your firmware lacks this support. (Note that you must also explicitly activate rEFInd's mouse or touch support in refind.conf for the driver to be useful.) Note that I've not tested this myself or heard of it working, but in theory it should work, provided you find a compatible driver.

Note that most of these uses are theoretical, at least to me; I don't know of any specific examples of EFI drivers (available as separate files) for disk controller hardware, network cards, or video cards. Such drivers are often embedded in the firmware of the devices themselves, and should be loaded automatically by the EFI. Chances are good that a few such drivers are available, unknown to me, and more may become available in the future. If you happen to have a device and need support for it under EFI, searching for drivers is certainly worth doing.

To the best of my knowledge, the best reason to want EFI driver support in rEFInd is to provide access to filesystems. Although EFI filesystem driver choices are currently somewhat limited, those that are available can help to improve your installation and configuration options, particularly if you've found yourself "boxed in" by awkward installation or bugs, such as the dinky ESP that Ubuntu creates by default or the bug that prevents a Linux kernel with EFI stub loader support from booting from the ESP of at least some Macs.

As a side note, using an ISO-9660 driver can theoretically help you keep the size of a custom Linux boot CD/DVD down to a reasonable value. This is because EFI systems normally boot from optical discs by reading a FAT image file in El Torito format and treating that file as an ESP. If you need to store the kernel both in that file and directly in the ISO-9660 filesystem (to maintain bootability on BIOS systems), that can represent an unwanted extra space requirement. Placing rEFInd and an ISO-9660 driver in the FAT image file should enable you to store the kernel on the disc only once. Unfortunately, this doesn't work in practice. When the ISO-9660 driver is loaded from the El Torito image, the driver discovers that the optical disc is in use and refuses to access it. It's possible to use EFI shell commands to give the ISO-9660 driver access to the shell device, but this causes the El Torito access to go away, which means that anything loaded from the El Torito image (such as rEFInd) is likely to malfunction. Also, some EFI implementations include ISO-9660 drivers, so you might not need a separate ISO-9660 driver if you're building a disc for a particular computer.



Installing rEFInd's EFI Drivers

If you install rEFInd via the refind-install script or by installing an RPM or Debian package in a Linux distribution, the script should install the driver that matches the filesystem on which your kernels are stored automatically, with a couple of important caveats:

  • The driver must be included with the rEFInd package. As described in the next section, Selecting an EFI Driver, drivers for ext2fs, ext3fs, ext4fs, ReiserFS, Btrfs, and a few non-native filesystems come with rEFInd. If your kernels reside on XFS, JFS, ZFS, or some other more exotic filesystem, you'll need to track down drivers elsewhere, as described in Finding Additional Drivers, and install them manually.
  • If you run refind-install from OS X, the script installs only the ext4fs driver, and that only if the script finds an existing Linux partition. Thus, if you install rEFInd before installing Linux, chances are refind-install will not install any Linux driver. Also, if you use any filesystem other than ext2/3/4fs to hold your kernel, refind-install won't install the correct driver. If you install rEFInd followed by Linux and want to use rEFInd's driver, you can either re-install rEFInd or install the appropriate driver manually. The refind-install script installs all the available drivers if you pass it the --alldrivers option. (I do not recommend using this feature except for creating general-purpose USB flash drives with rEFInd, since having too many drivers can cause various problems.) See the Installing rEFInd page for details.

rEFInd's filesystem drivers reside in the refind/drivers_arch subdirectory of the rEFInd .zip file, where arch is a CPU architecture code, such as x64 or ia32. If you installed rEFInd using an RPM or Debian package, chances are the relevant files will be stored in /usr/share/refind/refind/drivers_x64/ or a similar location. You can type find /usr/share/ -name "ext4*" to find the exact location, or use your package manager to list all the files installed from the refind package. The files are named after the filesystems they handle, such as ext4_x64.efi for the x86-64 ext4fs driver. You should copy the files for the filesystems you want to use to (You may need to create this subdirectory.)

To install a driver, you must copy it from the package .zip file or from where the rEFInd RPM or Debian package placed it to the drivers or drivers_arch subdirectory of the main rEFInd installation directory. The main rEFInd directory is usually either EFI/refind or EFI/BOOT on the EFI System Partition (ESP). How to identify and access the ESP varies from one OS to another:

  • Under Linux, the ESP is normally mounted at /boot/efi, or sometimes /boot.
  • On OS X, the ESP is not normally mounted, but the mountesp script that comes with rEFInd will mount it and identify the mount point.
  • Windows also does not normally mount the ESP, but it can be mounted from an Administrator command prompt window by typing mountvol S: /S. (You can change S: to another drive identifier, if you like.)

Be careful to install drivers only for your own architecture. Attempting to load drivers for the wrong CPU type will cause a small delay at best, or may cause the computer to crash at worst. I've placed rEFInd's drivers in directories that are named to minimize this risk, but you should exercise care when copying driver files.

When you reboot after installing drivers, rEFInd should automatically detect and use the drivers you install. There's likely to be an extra delay, typically from one to five seconds, as rEFInd loads the drivers and tells the EFI to detect the filesystems they handle. For this reason, and because of the possibility of drivers harboring bugs, I recommend installing only those drivers that you need. If you like, you can install drivers you don't plan on using to some other directory, such as /drivers on the ESP's root. You can then load these drivers manually with the EFI shell's load command if the need arises in the future. You can then tell the shell to re-assign drive identifiers with map -r:

fs0: load btrfs_x64.efi
fs0: map -r

Selecting an EFI Driver

Since version 0.4.0, rEFInd has shipped with a small collection of read-only EFI filesystem drivers. These are:

by Roderick W. Smith, rodsmith@rodsbooks.com

All of these drivers rely on filesystem wrapper code written by rEFIt's author, Christoph Phisterer.

Although Linux filesystems are all case-sensitive, these drivers treat them in a case-insensitive way. Symbolic links work; however, rEFInd 0.6.11 and later ignore symbolic links, since many distributions use them in a way that creates redundant or non-functional entries in the rEFInd menu. You should be able to use hard links if you want to use a single kernel file in multiple ways (say for two distributions).

Finding Additional EFI Drivers

As already noted, I know of few EFI drivers for EFI hardware, aside from those that are built into motherboards' EFI implementations. I do, however, know of a few EFI filesystem drivers, in addition to those provided with rEFInd:

  • Pete Batard's efifs drivers—This project is an EFI driver wrapper around GRUB 2's filesystem drivers. Once compiled, the result is that GRUB 2's drivers become standalone EFI filesystem drivers, loadable independently or by rEFInd. (rEFInd version 0.8.3 or later is required.) At present (driver version 1.0; July 2016), several drivers, including NTFS, exFAT, ext2fs, ReiserFS, Btrfs, JFS, and XFS, are usable. The last time I tested them (version 0.7), some drivers were slow, and they hung on some computers, such as one of my Macs. They may have improved since then, and are likely to improve more in the future. Note that the ext2fs driver from this set works with ext3fs and ext4fs, too. In addition to the main link, you can check the github repository for the source code.
  • The LKL driver project—I have yet to look closely at this project, but I think it's a porting of the Linux kernel's filesystem drivers to EFI. The developer stated on the EFI developers' mailing list that they aren't yet stable, as of November 2016.
  • rEFIt's ext2fs and ReiserFS drivers—You can gain read-only access to ext2fs, ext3fs, and ReiserFS volumes with these drivers, originally written by Christoph Pfisterer. You can use the binaries in the refit-bin-0.14/efi/tools/drivers directory of the binary package directly on a Mac. On a UEFI-based PC, though, you'll need to break the Mac-style "fat" binary into its 32- and 64-bit components. You can use my thin program for this job. As a practical matter, there's no advantage to using these drivers over rEFInd's drivers, since the latter are updated versions of the former.
  • Clover EFI's ISO-9660, ext2fs, ext4fs, and HFS+ drivers—This project is an offshoot of TianoCore, the main UEFI project. It's primarily a Hackintosh boot loader, but it includes drivers for ISO-9660, ext2fs, ext4fs, and HFS+; however, building them requires a fair amount of expertise. These drivers are closely related to rEFInd's own drivers. Thus, as with the rEFIt drivers, there's likely to be no advantage to using the Clover drivers over the rEFInd drivers.
  • Clover's non-filesystem drivers—In addition to its filesystem drivers, Clover includes a number of hardware drivers, such as one for NVMe devices (nvmexpressdxe-64.efi) and two mouse drivers (ps2mousedxe-64.efi and usbmousedxe-64.efi, for PS/2 and USB mice, respectively). I haven't tested these drivers, but I've received a report that the NVMe driver, at least, is useful to enable booting OSes installed on NVMe devices. The easiest way to obtain these drivers is likely to be to download the .iso file, mount it, and copy the drivers from the efi/clover/drivers* directories (there are several, with varying purposes). I recommend caution when testing them, though; using an inappropriate driver could cause a system hang.
  • VirtualBox's HFS+ and ISO-9660 drivers—These drivers are available in source code form, and come with VirtualBox binaries. I've not attempted to compile them myself, but I've seen a report that suggests they may include assumptions that require use of MinGW, a GCC-based compiler for Windows (and cross-compiler to build Windows executables under Linux). I don't know of a source for binaries suitable for use on EFI-based computers; if you want to use them, you'll need to figure out how to compile them yourself. As noted earlier, rEFInd's drivers are closely related to these.
  • Ext2Pkg—This driver, based on bitbucket and with a backup on github, appears to be an ext2fs/ext3fs driver built independently of the driver written by Christoph Pfisterer. The linked-to sites provide access to source code via git but do not provide binaries. When I built binaries, they failed to work. Under VirtualBox, the driver loaded but then hung when I tried to access an ext2 filesystem. On a 32-bit Mac Mini, I got error messages when I tried to access an ext2 filesystem. As I write, the code was last updated in March of 2012. If you check the project and it's been updated more recently, it might be worth trying. Otherwise, I can't recommend this driver. I mention it here only in case it improves in the future.
  • Paragon's UFSD—According to this blog post, Paragon Software has ported its Universal File System Drivers (UFSD) to EFI, providing "transparent access to NTFS, HFS+, ExFAT, and ExtFS" (sic). The entry doesn't provide any download links, and it's unclear if the product is (or will be) available for free or on a pay basis. I haven't tried these drivers, so I can't comment on their quality.
  • Apple's APFS—Apple provides an EFI driver for its Apple Filesystem (APFS), which is an optional feature of macOS 10.12 ("Sierra") and a mandatory feature of macOS 10.13 ("High Sierra") when using flash storage devices such as SSDs. When updating to macOS 10.13, your firmware should receive an update that includes this driver, so you shouldn't need to do anything to use APFS (with one caveat, described shortly). Apple also provides the driver as an EFI binary file, stored at /usr/standalone/i386/apfs.efi in the installed OS. You can load this driver from rEFInd, but doing so is likely to be pointless—on Macs, the driver should be built into the firmware, and on non-Macs, APFS is unlikely to hold files that rEFInd could use. On the off chance that a firmware update failed, though, copying this file to the rEFInd drivers subdirectory may enable you to boot macOS. Note that APFS includes built-in LVM-like features, similar to Btrfs. Under EFI, APFS volumes are identified by directories with UUIDs as filenames. This fact means that rEFInd 0.11.1 needed modifications to locate the macOS boot loader, since its location changed, as viewed from rEFInd. If you had used rEFInd 0.11.0 or earlier, update to macOS 10.13, and find that you can no longer boot macOS, try updating rEFInd to 0.11.1 or later.

The rEFIt, Clover filesystem, and VirtualBox drivers are related, and all of them have fed into rEFInd's drivers. Specific versions can have their own quirks, though. For instance, the Clover (and I suspect VirtualBox) drivers don't return volume labels, which causes rEFInd to display loaders on those volumes as being on a disk called Unknown. (I fixed that bug for rEFInd's version, and it wasn't present in the original rEFIt drivers.) Most of these drivers also suffer from speed problems on some computers. This is worst with the ext2fs drivers under VirtualBox; on my main computer, that combination takes 3 minutes to load a Linux kernel and initial RAM disk file! Most real computers don't suffer nearly so badly, but some can take an extra five seconds or so to boot a kernel. I've fixed the worst of the speed problems in rEFInd's drivers as of version 0.7.0; however, I still see occasional reports of speed problems on specific computers.

Although I know of no readily-available hardware drivers, I do know of a couple of non-hardware non-filesystem drivers:

  • CrScreenshot—This driver adds a screenshot capability to any EFI. Note that it's available only as source code that requires the Tianocore EDK2 to build. I have not tested it. (Note also that rEFInd provides its own screen shot capability; pressing F10 takes a screen shot within rEFInd.)
  • RamDiskPkg—This is a rudimentary RAM disk driver. It must be compiled with a RAM disk image; the resulting binary is hard-coded with a fixed RAM disk image. It's therefore useful mostly for developers.

Both of these drivers are useful mainly for developers.

Driver availability could increase in the future. If you know of additional EFI drivers, please tell me about them, so I can share the information here. Likewise if you know of a source for other EFI drivers—say, for a video card or disk controller card.

Once you've obtained an EFI driver, you can install it in rEFInd just as you would install rEFInd's own drivers, as described earlier.


copyright © 2012–2018 by Roderick W. Smith

This document is licensed under the terms of the GNU Free Documentation License (FDL), version 1.3.

If you have problems with or comments about this Web page, please e-mail me at rodsmith@rodsbooks.com. Thanks.

Go to the main rEFInd page

Learn about how to adjust rEFInd's appearance

Return to my main Web page.

refind-0.11.4/docs/refind/revisions.html0000664000175000017500000027732613372351237020447 0ustar rodsmithrodsmith The rEFInd Boot Manager: Revisions

The rEFInd Boot Manager:
Revisions

by Roderick W. Smith, rodsmith@rodsbooks.com

Last Web page update: 11/12/2018

This Web page is provided free of charge and with no annoying outside ads; however, I did take time to prepare it, and Web hosting does cost money. If you find this Web page useful, please consider making a small donation to help keep this site up and running. Thanks!

Donate $1.00 Donate $2.50 Donate $5.00 Donate $10.00 Donate $20.00 Donate another value

This page is part of the documentation for the rEFInd boot manager. If a Web search has brought you here, you may want to start at the main page.


The following summarizes changes in rEFInd's public releases:

  • 0.11.4 (11/12/2018)—This release fixes a couple of small but annoying bugs introduced in version 0.11.3 and improves some filesystem drivers. More specifically:
    • Samuel Liao provided bug fixes to the NTFS driver relating to fragmented files and filesystems with cluster sizes of over 4KiB.
    • Samuel Liao also added support for zstd decompression to the btrfs driver. He's also fixed a RAID1 issue and added support for RAID5 and 6.
    • Version 0.11.3 introduced a bug in both refind-install and mountesp that caused these scripts to fail in macOS's Recovery environment. These bugs have been squashed.
    • refind-install has long had a bug that caused it to fail to properly identify the ESP in Linux when autofs was in use. This bug has been squashed.
    • rEFInd 0.11.3 introduced a bug that caused the default of booting to the last-booted OS to be lost unless it was set explicitly via default_selection in refind.conf. This has been fixed.
    • rEFInd would fail to compile with recent versions of EDK2 (obtained via git) because of an issue with Refind.Pkg.dsc. This problem has been corrected.
    • I've added referebces ti several themes in themes.html, and fixed a broken link or two. Thanks especially to AliciaTransmuted, who's been cranking out rEFInd themes!
  • 0.11.3 (7/22/2018)—This release implements a number of minor bug fixes and some more major improvements; its two changes are:
    • The new shutdown_after_timeout token in refind.conf, if set, causes rEFInd to try to shut down the computer rather than launch the default_selection when the timeout value is reached. Note, however, that this feature relies on EFI features that are not implemented by some EFIs. If the feature is not implemented, the computer will reboot or hang. This option is disabled by default, which results in the same behavior as in previous versions of rEFInd.
    • The new use_nvram token, if set to false, off, or 0, causes rEFInd to store its variables to files on the hard disk (in the vars subdirectory of rEFInd's home directory). When use_nvram is set to true or one of its synonym, as is the default, these variables are stored in NVRAM, as was always the case for previous versions. This feature is intended to improve functionality on computers with flaky NVRAM and to reduce wear-and-tear on the computer's NVRAM, albeit at the cost of increasing the risk of filesystem damage. (There's no free lunch.)
    • rEFInd now support JPEG images for banners. Note that rEFInd's JPEG support does not support transparency, so although you can use JPEGs for icons, PNGs usually work better. Also, rEFInd's JPEG support is based on the NanoJPEG library, which has some significant limitations, such as a lack of support for progressive encoding. Thus, if you have problems with a particular image, you may need to re-save it in a more basic form.
    • I've eliminated the Scanning for boot loaders; please wait message, which has generated a lot of negative comments.
    • I've fixed a bug that caused portions of the Pausing before disk scan... message to be retained when scan_delay was set to a value over 1.
    • The + symbol in default_selection may now be used in any position in the list to refer to the previously-booted OS. For instance, bzImage,+,vmlinuz now works, prioritizing any bzImage files over the previous boot, but the previous boot over vmlinuz files.
    • I've added icons for Void Linux, Ubuntu 17.10 (Artful Aardvark), and Ubuntu 18.04 (Bionic Beaver). I've also copied the gummiboot icon to os_systemd.png, since gummiboot has been renamed systemd-boot.
    • I've fixed a bug that caused rEFInd to ignore the entire refind.conf file if its first line was empty.
  • 0.11.2 (10/22/2017)—This is a minor bug-fix release; its two notable improvements are:
    • I've fixed a bug, introduced in version 0.11.1, that caused setting volumes in manual boot stanzas to not work.
    • I've fixed a bug, present since version 0.11.0, that caused the new tag-hiding feature to not work unless it was explicitly enabled in refind.conf. (It should have been enabled by default.)
  • 0.11.1 (10/9/2017)—This version is mainly a maintenance release in response to Apple's release of macOS 10.13 ("High Sierra"), although there are a couple of unrelated improvements. Its specific changes are:
    • The new Apple Filesystem (APFS) uses subvolumes, which appear as subdirectories with UUIDs as names to the EFI and EFI programs such as rEFInd. This fact means that the location of Apple's boot loader has changed, from rEFInd's perspective, necessitating a code update. This version provides that update.
    • As a follow-on to the preceding change, I discovered that compiling rEFInd with GNU-EFI resulted in a failure to properly track some files on APFS volumes. I don't know if this failure reflected a bug in Apple's EFI, in GNU-EFI, or in rEFInd; but I changed the way rEFInd tracks boot loader files internally to work around the problem. Although I've tested this version on an unusually wide number of computers, it's possible that this change will introduce new bugs. Thus, if you upgrade and have problems with boot loaders not being detected or not launching, dropping back to version 0.11.0 may be worth trying. (Be sure to contact me with a bug report, too!)
    • I've modified refind-install to be smarter about modifying existing NVRAM entries for rEFInd under Linux. Previously, refind-install was quite aggressive about deleting and re-creating these entries; however, this was causing failures on a few computers. The script now checks more carefully to see if an existing entry boots rEFInd and is set as the default; and if so, it leaves that entry alone.
    • I fixed a bug that could cause the hidden-tag maintenance feature to crash the program.
    • I fixed a bug, introduced in version 0.11.0, that caused both Apple and Microsoft second-row recovery tools to go undiscovered.
  • 0.11.0 (8/13/2017)—In addition to a few bug fixes, this version sees several new features, many of which are likely to be important to a significant number of people....
    • CJ Vaughter has improved his touch-screen code. This should both make more tablets' touch screens work and expands the support to work with mice. Both input methods are disabled by default; you must enable one by uncommenting the enable_touch or enable_mouse options in refind.conf. (Enable only one of these features, though; they're mutually exclusive!) If you enable mouse support, the mouse_speed and mouse_size options affect the mouse tracking speed and the size of the mouse pointer, too. Note that not all computers support mouse input, much less touch input. The former seems to be largely unrelated to whether the firmware's own user interface supports mice, in my testing. If you enable one of these features and your computer doesn't support it, you can still use rEFInd; but you may see a useless mouse pointer, and the default selection may not come up in a highlighted state. Also, these features do not work on 32-bit systems.
    • You can now hide OSes and external tool tags from the rEFInd main menu by pressing the minus key (-) or Delete key (on PC keyboards; some third-party Mac keyboards label this key Del, but most Apple keyboards lack this key entirely). If you accidentally hide a loder, you can recover it using the new tag recovery tool, which uses a recycle icon on the second row. Hiding or un-hiding loaders relies on the hidden_tags option being set on the showtools line; but if you hide a tag and then remove the hidden_tags option, rEFInd will continue to honor the hidden settings. This option is set by default, but if you've edited showtools for a previous installation and upgrade rEFInd, you'll need to add hidden_tags to use this new feature.
    • A new refind.conf option, dont_scan_tools, works much like dont_scan_files, but applies to external tools (shells, MokManager binaries, etc.). You can use this option to hide duplicate external tools.
    • Thanks to Pavel Penev, the refind-install script now supports a new option, --encryptkeys, which causes it to encrypt and password-protect its local Secure Boot public key. This option is useful only in conjunction with --localkeys. This feature should help prevent abuse should somebody break into your computer; the intruder won't be able to sign malware with your own key and insert it into your boot path. You must set and remember a password if you use this feature, though.
    • The refind-install and mvrefind scripts now create a file called BOOT.CSV and place it in the directory where rEFInd is installed. This file is used by the fallback.efi (aka fbx64.efi) program, which Fedora and some other distributions are now installing, to regenerate a working boot list should the NVRAM-based boot order be lost. See the page on keeping rEFInd booting for more on how to control this functionality.
    • Disk partitions can now be identified by partition GUID values in more places—namely, in dont_scan_dirs and dont_scan_files. Note that the GUIDs are partition GUIDs, which some Linux tools identify as PARTUUID values. Filesystem UUIDs are different. Partition GUIDs are fundamentally GPT features; they don't exist on MBR disks. rEFInd assigns one "fake" partition GUID to all MBR partitions, so MBR partitions can be referred to, but cannot be distinguished from one another, in this way.
    • Identifying partitions by filesystem number (e.g., fs0: or fs2:), which was deprecated with version 0.8.7 in 2015, is now no longer supported—the relevant code has been removed. You now must use filesystem labels, partition names, or partition GUIDs instead of the unreliable filesystem numbers.
    • In the past, some error messages on Macs would never appear on the display, sometimes including a prompt to press a key to continue, which could make it seem as if rEFInd had hung. rEFInd now includes new features that enable such messages to appear in most (but not yet all) cases, so you're less likely to see mysterious hangs that aren't quite hangs on Macs. This does not affect UEFI-based PCs.
    • I've fixed a bug that caused disk badges to not be scaled along with the main loader tag.
    • Apple has updated at least some EFIs in a way that broke the spoof_osx_version feature. This has been fixed.
    • I've fixed a bug that caused rEFInd to ignore references to the fallback boot loader (EFI/BOOT/bootx64.efi) in dont_scan_files in some cases.
    • I've fixed a bug in mvrefind that caused it to not restore EFI/BOOT-rEFIndBackup when moving rEFInd out of the EFI/BOOT location.
    • I've fixed a bug that caused rEFInd to not properly sort a Fedora/CentOS/RHEL vmlinuz-0-rescue* kernel to the bottom of the kernel list.
  • 0.10.9 (7/30/2017)—This version sees changes in some graphics features and in the build process....
    • To better support HiDPI/retina displays, rEFInd now automatically scales its icons and text to twice the usual size on displays wider than 1920 pixels. This change does not affect text mode (for which setting the textmode option in refind.conf is still necessary. Explicitly setting either small_icon_size or big_icon_size in refind.conf disables this feature, so you can explicitly set any icon or font size you like in the usual way.
    • rEFInd now displays its background/banner image before scanning for boot loaders, and displays a notice that it's scanning for boot loaders at this time. This will barely be noticeable on most systems, but if you have lots of OSes or kernels, you may notice the change.
    • On rare occasion, when rEFInd runs into a problem, it displays a text-mode error message and prompts the user to continue, even when it's operating in text mode. On Macs, this has caused what looks like a hang, since this text would not be displayed, but the pause for user input would still occur. rEFInd now at least displays the prompt to continue, although the error text may not appear. (This feature still needs more work.)
    • I've added icons for the Trusty (14.04), Xenial (16.04), and Zesty (17.04) versions of Ubuntu, for those who install multiple Ubuntu versions and want to distinguish them by separate icons. Sooner or later I'm likely to remove these icons as their versions reach end-of-life status.
    • I've updated the LodePNG library, which rEFInd uses to load PNG images. This is unlikely to have any obvious effects for users.
    • I've significantly reworked the build process when using the TianoCore toolkit. In brief, in addition to the tiano target for make, a new edk2 target exists, which works with newer versions of TianoCore. Behind the scenes, the new version builds rEFInd in a way that's more akin to what most TianoCore projects use. See the BUILDING.txt file for details. I'm also building most of my own binary packages with UDK2017 rather than UDK2014, which I'd been using for the past few years. (My PPA packages still use GNU-EFI.)
    • My USB flash drive and CD-R images now include the gdisk and gptsync binaries, although the latter is inactive by default, even on Macs.
  • 0.10.8 (5/21/2017)—This version's changes are modest, although a couple will be important to a few users....
    • I've added shimx64.efi.signed as a valid Shim filename, and mmx64.efi.signed as a valid MokManager filename, to refind-install, so that Ubuntu users can point to the signed Shim binaries on their root (/) partition, rather than a copy on their ESP.
    • I've made changes to enable compilation with GNU-EFI 3.0.5, which was failing with the previous version.
    • I've added an icon for Devuan GNU+Linux (a Debian spinoff that does not use systemd).
    • I've made some minor code efficiency improvements. These are unlikely to have a noticeable impact on performance by themselves.
    • I've enabled the use of partition unique GUID values with dont_scan_volumes. This should help users keep duplicate boot loaders from showing up on RAID 1 arrays.
    • I've changed "OS X" to "macOS" in assorted on-screen messages, to conform with Apple's name change as of macOS 10.12 (Sierra). Note that this change may require updating default_selection options that rely on the string OS X!
  • 0.10.7 (4/17/2017)—Soon after releasing version 0.10.6, I discovered a potentially serious bug it introduced, and so I've made this new release, with the following new features:
    • Although the memory management bug introduced with version 0.10.6 seems to be harmless on most systems, it caused hangs on one computer (using UEFI DUET), hence my rushing out this update.
    • I've answered too many queries from people who are confused by the fact that many OS X installations are identified as Boot OS X from Recovery HD on the rEFInd menu. Apple puts the boot loader for its regular installation on the Recovery HD volume if you use LVM or encrypt your root (/) partition, so rEFInd's identification is correct, but it confuses people. I've therefore adjusted rEFInd to omit the from Recovery HD part of that message.
    • I've updated refind-install to recognize mmx64.efi (or the equivalent for other architectures) as an alternative name for MokManager.efi.
  • 0.10.6 (4/16/2017)—This version includes a few small bug fixes and one new feature:
    • The new feature is the extra_kernel_version_strings token in refind.conf. This token accepts a comma-delimited list of strings that will be treated similarly to digits for purposes of matching Linux initrd files to Linux kernels. See the description on the Configuring the Boot Manager page for details.
    • Some distributions have renamed MokManager.efi to mmarch.efi (where arch is an architecture code, such as x64). I've adjusted rEFInd to recognize MokManager under this new name. I've also added fbarch.efi to the list of loaders that are not scanned by default. This loader restores a machine's NVRAM-based EFI boot manager entries from a backup file and then launches the default boot loader.
    • I've squashed a bug that could cause filesystems managed by rEFInd's filesystem drivers to not be mounted.
    • I've fixed a bug in mvrefind that would cause it to fail to move a rEFInd installation if the target directory did not exist. The script now creates the specified target, if necessary.
    • Previously, rEFInd would explicitly set the video mode when it started, even when the display was already running in that mode. This version no longer does so. This is a shot-in-the-dark attempt to work around problems on Macs with "retina" displays, which tend to boot up in suboptimal resolutions when rEFInd is used.
  • 0.10.5 (3/4/2017)—This version includes a number of modest changes, most of which will be of interest to relatively few people:
    • The touch/tablet support has been improved and so may work with a few more systems.
    • The refind-install script has been updated to work better with disks other than those whose names take the form /dev/sd? and /dev/hd? (in Linux).
    • For the benefit of new Apple laptops that lack physical Esc and function keys, additional keybindings have been added: Backspace (Delete on most Mac keyboards) now works the same as Esc, and Tab now works the same as F2/Insert/+.
    • The Linux initial RAM disk detection code has been expanded so that, if two initial RAM disk files are found for a kernel, the one with more characters after the version string that match the equivalent characters in the kernel filename will be used. For instance, suppose the kernel filename is vmlinuz-4.8.0-32-standard, and two initial RAM disk files are initrd-4.8.0-32-standard and initrd-4.8.0-32-debug. The first of those files has nine matching characters after the version string (-standard), vs. just one matching character (-) for the second. Thus, the first file will be used.
    • A second change to Linux initial RAM disk detection is that you can now specify the kernel version string with the string %v in the refind_linux.conf file's options field. Thus, if your distribution provides two initial RAM disk files per kernel, and also provides numbered kernels, you can create a refind_linux.conf file that enables you to boot with either (or both) of the initial RAM disk files that match a specific kernel.
    • I've done some minor code optimization in the functions that search for boot loaders. This had no noticeable effect on speed for me, and is likely to be more than offset by the more complex initial RAM disk processing noted above; but it might help a little bit on systems with many boot loaders or kernels.
  • 0.10.4 (10/9/2016)—The number of changes in this version is modest, but some features are important to some people:
    • Thanks to code submitted by an anonymous contributor, rEFInd now supports some touch screens. This feature relies on support in the firmware itself, though, and even some tablets lack this support, so this feature does not work on all tablets.
    • Martin Whitaker has contributed updates to the ext4fs driver to make it compatible with filesystems created with 64-bit pointers. As a practical matter, this is important because 64-bit pointers are now being used by default in some distributions. In theory, this feature may enable use on over-16TiB filesystems, but this is untested at the moment.
    • GNU-EFI version 3.0.3 or 3.0.4 has made changes that caused rEFInd's drivers to fail to compile. This version addresses those compilation problems.
    • A rEFInd coding error manifested with previous versions of rEFInd when compiled with GNU-EFI starting at version 3.0.3 or 3.0.4, causing the main rEFInd binary to crash. This problem has been fixed. To the best of my knowledge, this bug has never manifested with earlier versions of GNU-EFI or Tianocore builds.
    • The refind-install script now does a better job of detecting disks that have exotic names—those other than /dev/sd? or /dev/hd?.
  • 0.10.3 (4/24/2016)—This version features mostly modest changes and additions:
    • A new Linux script, refind-mkdefault, simplifies the task of resetting rEFInd as the default boot program. It's documented here. I've also written a new documentation page on the problem generally, which covers how to handle the problem in multiple OSes.
    • I've modified the SIP/CSR rotation code so that the SIP/CSR rotation tool will appear more reliably on Apple computers.
    • The NTFS driver has been improved to reduce the chances of it hanging randomly.
    • The code that excludes shell binaries from appearing in the main boot list has been altered to reduce the odds of an incorrect exclusion from occurring.
    • rEFInd now recognizes the fwupx64.efi program as a special case: If detected, this program is presented as a second-row option rather than as a regular boot loader. (This tool is used to update firmware on some computers.)
    • BIOS/CSM/legacy-mode OSes all now include the string Legacy in their descriptions on Macs.
  • 0.10.2 (1/26/2016)—Changes to this version are relatively modest and focus on bug fixes:
    • A bug in refind-install under OS X could cause the mountesp script to be installed as a file called /usr/local/bin if that directory was absent. This bug has been fixed.
    • Another OS X refind-install bug caused the --usedefault option to not work properly. This has been fixed.
    • A Linux refind-install bug caused Secure Boot detection to fail in some cases. This has also been fixed.
    • The mvrefind script could fail to move the Windows boot loader file (bootmgfw.efi) under some circumstances. Another bug in the same script caused mvrefind to register rEFInd using its default filename (rEFInd Boot Manager) rather than the name Windows Boot Manager when moving rEFInd to the Windows boot manager's location. Both of these bugs have been squashed.
    • A long-standing but obscure bug/quirk affects some EFIs, such as that in the HP ProBook 6470b: These EFIs connect useless drivers to partitions with no known filesystems, before rEFInd can load filesystem drivers. The result is that drivers loaded by rEFInd could not read the partitions in question. This version of rEFInd works around this problem.
    • A bug introduced in rEFInd 0.10.1 caused custom volume badge icons (read from an icon directory specified by icons_dir in refind.conf) to be ignored. I've fixed this bug.
    • Finally, a small non-bug improvement: I've added centos.crt and centos.cer public-key files for CentOS to the keys directory.
  • 0.10.1 (12/12/2015)—This version of the program features one big change that will affect very few people, another big behind-the-scenes change, and a number of small changes that will affect more people:
    • rEFInd now compiles and runs on ARM64 (aka AARCH64 or AA64) systems. To date, I've tested it only using QEMU, so this support is very preliminary, almost to the point of being theoretical.
    • I've made significant changes to the Makefiles used to compile rEFInd. This should have no effect on the way rEFInd functions, or even in how most programming tasks are done; but the changes should help simplify some future changes.
    • I've made font changes: I've removed Luxi Sans Mono and changed the default font from Nimbus Mono to Liberation Mono.
    • A bug that causes rEFInd to fail to detect boot loaders on removable media when rEFInd itself was launched from the fallback filename is now history.
    • Fedora, Red Hat, and CentOS use a special recovery kernel with a name beginning vmlinuz-0-rescue. This kernel could be newer than others, which would make it the default on in a "folded" set of kernels—a highly undesirable situation. I've therefore modified rEFInd's loader-sorting algorithm to move this rescue kernel to the end of the list, no matter what its time stamp reads.
    • I've added a workaround to gptsync to fix problems that caused it to skip through its menus using the defaults without taking user input on some Macs. I've also added 53746F72-6167-11AA-AA11-00306543ECAC (Apple Core Storage, gdisk type AF05) to the list of partition types that gptsync recognizes.
    • The refind-install script can now be run as a symbolic link in Linux, which means it can be run as a normal command.
    • I've fixed bugs in refind-install and in mkrlconf that could cause them to misidentify kernel options. See NEWS.txt for details.
    • I've moved the detailed description of refind-install from Installing rEFInd to a man page, and I've created HTML versions of the three man pages that the project now includes.
    • I've added kernel* as a pattern for matching Linux kernels, since Gentoo Linux names its kernels by this pattern.
    • I've updated LodePNG, which is the PNG graphics library that rEFInd uses, to version 20151024.
    • The rEFInd PPA now asks for confirmation before installing to the ESP when the package is first installed. Updates follow the instructions given on first installation. You can modify this setting by typing dpkg-reconfigure refind.
  • 0.10.0 (11/8/2015)—I've given this version an extra-large version number bump because of some highly user-visible changes, especially for Mac users. Changes include:
    • I've swapped out the old icons for new ones. I've replaced the old icons because the OS icons were becoming a hopeless mish-mash of styles and because I wanted to consolidate the icon collection to use a more limited set of original sources for record-keeping purposes. If you prefer the old icons, you can continue to use them. After upgrading, rename icons-backup to something else (say, icons-classic) and add a line to refind.conf to reference the new directory, as in icons_dir icons-classic.
    • A new feature, spoof_osx_version, causes rEFInd to tell a Mac that it's about to launch OS X. This alters how some Macs initialize hardware, which can make secondary video chipsets work on some Macs. See the comments in refind.conf-sample or on the Using rEFInd page for details. This feature has no effect on UEFI-based PCs.
    • Another new feature enables you to adjust a Mac's System Integrity Protection (SIP) settings from within rEFInd. To use this feature, you must adjust two lines in refind.conf: The new csr_values line sets hexadecimal values through which you can rotate using a new second-row tag that's activated by the new scanfor line option of csr_rotate. Thus, you must add or change both the scanfor and csr_values lines. See the new rEFInd and System Integrity Protection page for information on how to use this new feature. Although this feature can work on UEFI-based PCs if they contain the necessary NVRAM variable, such systems are unlikely to have this variable, and it's unlikely to be useful even if it's present.
    • If the SIP NVRAM variable is set, rEFInd now displays its current value in the About screen.
    • I've renamed several support scripts: install.sh to refind-install, mvrefind.sh to mvrefind, and mkrlconf.sh to mkrlconf. I've also added man pages for mvrefind and mkrlconf.
    • Under OS X, refind-install now checks the machine's SIP status and warns the user if it's active. To help with such installations, the script can also now be run from a boot of the Recovery HD.
    • Under Linux, refind-install and mkrlconf now use /proc/cmdline as a source for the default boot options for Linux kernels, rather than trying to extract them from GRUB configuration files—except when the --root option is used, in which case the script continues to use the GRUB configuration files as a source of boot options. This change should help rEFInd pick up exotic boot options that GRUB computes at boot time, such as Btrfs subvolume options.
    • I've added a new script, called mountesp, which mounts the ESP on Macs, using the same algorithm used by refind-install. This should help Mac users who want to edit their rEFInd configurations.
    • I've changed the default also_scan_dirs setting from boot to boot,@/boot. This change helps rEFInd pick up kernels from Btrfs volumes.
    • I've changed from .zip to a tarball (.tar.gz) as the file format for the source code package. This change simply reflects the fact that Linux is the only supported build environment for rEFInd, and tarballs are more in line with that platform than are .zip files. The primary binary file format remains a .zip file, with Debian packages and RPMs also available.
    • My 32-bit Mac Mini suffered from a bug that caused rEFInd's icon-resizing code to hang in a conversion from floating-point to integer values. I've therefore adjusted the icon-resizing code to avoid doing floating-point computations. This change has a drawback, though: It causes some images to acquire artifacts when resized, particularly on 32-bit systems. If you run into such a problem, you should scale your icon(s) or banner/background image so that it does not need to be resized. Sorry, but between a system crash and minor graphics artifacts, the graphics artifacts are the lesser of two evils.
  • 0.9.2 (9/19/2015)—Soon after releasing 0.9.1, I started receiving bug reports about problems with it and Shim 0.8. (See this thread for one such report.) It turns out that the problem was not a new bug in rEFInd, but rather a change from Shim 0.7 to Shim 0.8 that made it next to useless with rEFInd. Specifically, Shim 0.8 now de-registers itself from the EFI after a follow-on program launches another one. This is done to avoid problems in a boot path in which Shim launches fallback.efi, which in turn launches another Shim. This creates a new problem, though: rEFInd can validate just one binary before it's "cut off" from Shim. Since rEFInd's drivers are binaries, if you use a single driver, that means that you won't be able to launch anything that requires validation via Shim. I quickly discovered a workaround, which I've implemented in this release. I consider this a "band-aid" patch, though, because it relies on a quirk of Shim's logic to bypass its de-registration. As such, the workaround in this release may break with a future Shim. A true fix will take longer to develop. I want to release this workaround version to head off further problems in the near term, though. This version also introduces a new feature, which is also Shim-related: Since version 0.7, Shim has supported launching binaries other than grubx64.efi by passing them on the command line. (Actually, Shim 0.4 supported this, but it required a broken path specification.) I've added support for this feature to install.sh: Adding the --keepname option to install.sh causes the script to preserve rEFInd's regular filename and to register the approprirate follow-on parameters to have Shim launch rEFInd by that name. This works, but is likely to be more delicate than using the default Shim follow-on name of grubx64.efi. The advantage, of course, is that rEFInd needn't "lie" about its name, which makes for less confusion in filenames. For the moment, the RPM and Debian packages I build do not use this new naming feature, since I can't be sure what version of Shim might be picked up. These changes do not affect users who do not use Secure Boot.
  • 0.9.1 (9/13/2015)—This version has improved the Discoverable Partitions Specification (DPS) support in a number of ways that should make it more reliable when /etc/fstab omits references to the root (/) partition or when the GPT read-only or do-not-automount options are used to control these features. A stray DPS-related debugging print command has also been removed. I've improved rEFInd's ability to guess the Linux distribution by having it examine /etc/lsb-release as well as /etc/os_release, and I've added an icon for Elementary OS. Finally, I've made improvements to rEFInd's handling of case-insensitive string comparisons, which were buggy on some EFIs, particularly when rEFInd was compiled with GNU-EFI. rEFInd is still at the mercy of the EFI and support libraries, but many problem cases should now be resolved.
  • 0.9.0 (7/26/2015—This version gets a bump up to 0.9.0 mainly because of a highly user-visible new feature: kernel folding. With kernel folding active, multiple Linux kernels in a single directory appear as just one main-menu entry, which launches the most recent kernel (by file timestamp) by default. Older kernels appear on the first one's submenu (accessed by hitting F2 or Insert). You can disable this new feature by setting fold_linux_kernels false in refind.conf. Another new feature is support for the Discoverable Partitions Spec, which enables rEFInd to locate the Linux root (/) partition without a refind_linux.conf or /etc/fstab entry. I know of no distribution that automatically sets up its partitions in this way, but if and when this starts to happen, rEFInd will be ready. Other changes are relatively minor: The Debian postinst script now calls install.sh with --localkeys if sbsign and openssl are available, which helps if using the Ubuntu PPA on a system with custom Secure Boot keys; I've fixed a packaging bug that prevented IA32 versions of filesystem drivers and gptsync to not be built in the PPA; mkrlconf.sh now refuses to run under OS X; rEFInd now skips checking for BIOS-mode boot code on UEFI-based PCs, which should speed it up a little; I've fixed a bug that caused rEFInd to crash if it found an existing but empty refind_linux.conf file; I've made minor code changes to enable rEFInd to build under GCC 5.1; and I've added a new icon for Kali Linux (provided by Francesco D'Eugenio).
  • 0.8.7 (3/1/2015)—This release provides bug fixes and refinements to existing features. Several changes should reduce the odds of rEFInd crashing because of assorted problems. Other changes improve Secure Boot handling, including improved Secure Boot detection in install.sh, recognition of KeyTool.efi and KeyTool-signed.efi as MOK manager utilities, and reporting of Secure Boot status for x86 (IA-32) systems in the rEFInd information screen. Filesystem detection is improved (again), and XFS has been added as a known filesystem. Detection of FreeBSD's BIOS-mode boot loader is improved, which should give more Mac users the right OS icon when booting FreeBSD in BIOS mode. A bug in install.sh that caused inappropriate installation to the filename bootx64.efi or bootia32.efi, and failure to update the computer's boot list, has been squashed. Finally, I'm deprecating the use of fsx: notation for referring to filesystems. The numbering of filesystems is simply unreliable, and better alternatives (the use of partition GUIDs, partition names, and filesystem names) have been added in previous releases. The fsx: code remains in rEFInd, and if it's working for you, you can continue to use it; but sooner or later I'll remove that code, so you're advised to change your manual boot stanzas and other options that use it before that happens.
  • 0.8.6 (2/8/2015)—Most (but not all) of this release's changes focus on Windows dual-booting and Mac-specific issues. There's a new Windows 8 icon, which is now used by default as the Windows icon, although the old icon remains available and is used for Windows XP and earlier boots on Macs. If the NTFS driver is loaded, rEFInd will now exclude non-bootable NTFS volumes from the Mac boot list (this change does not affect UEFI-based PCs). A bug that caused misidentification of whole disks and NTFS volumes as being FAT has been fixed (again, this problem affected Macs, not PCs). A couple of Mac-specific install.sh bugs have been fixed, resulting in more reliable identification of the ESP and of the installation directory. Previous versions ignored a volume name of "HFS+ volume" because that name was produced by earlier versions of the rEFInd HFS+ driver for all HFS+ volumes; but the current HFS+ driver produces a real volume name, so I've removed that special case from the code. I've removed the r472 rEFIt commit, introduced in 0.8.5, because it was causing some BMP files to fail to load. Finally, the hideui token in refind.conf now accepts a value of badges, which has the effect of hiding the disk-type badges associated with OS launch icons.
  • 0.8.5 (2/1/2015)—The biggest single change with this version is a new NTFS driver contributed by Samuel Liao, who also contributed the Btrfs driver. Samuel also contributed some miscellaneous driver fixes and a change to the way the keyboard is handled, which improves responsiveness on some systems. This version also improves the way install.sh works under OS X. In particular, it tweaks the bless command in a way that may eliminate startup delays and it does a better job of detecting and replacing existing rEFInd installations (on the ESP), rather than blindly writing to EFI/BOOT. Finally, this version applies commits from late in rEFIt's history: r467, which improves handling of BIOS/legacy boots from the second and subsequent disks on Macs; and r472, which enables handling BMP images that are not vertically flipped. These commits were not present in rEFInd from the start because the starting point for rEFInd was a Debian source package taken from a slightly earlier version.
  • 0.8.4 (12/8/2014)—OS X 10.10 ("Yosemite") made changes that necessitated alterations to both rEFInd's install.sh script and rEFInd defaults. Specifically, Yosemite now uses a form of logical volume management (LVM) that makes installing rEFInd to the OS X root directory impossible, so the default location is changed to the ESP. Changes to the default for dont_scan_volumes are necessary to make the new location for the OS X boot loader show up. Another big change is in the new (but experimental) support for network booting, with the help of iPXE. See the BUILDING.txt file in the source package for details on how to build and install the necessary files. A new option for refind.conf, enable_and_lock_vmx, sets the VMX bit on Intel CPUs, which is necessary for booting some hypervisors, such as Hyper-V. This feature can be set on many computers' EFIs, but some, such as Macs, lack this ability. (Do not set this option on AMD CPUs or older Intel CPUs that lack this feature, though!) If rEFInd can't find its icons directory, it now drops back to text mode. A bug in dont_scan_files has been fixed, enabling you to specify a complete path to certain special-case boot loaders to omit them from scans. Finally, I've updated the icons for Fedora and Ubuntu and added an icon for Xubuntu.
  • 0.8.3 (7/6/2014)—This version introduces a number of minor bug fixes and feature improvements. The most user-visible of these are that on Macs, rEFInd now displays a partition's label for BIOS-bootable OSes on filesystems that rEFInd can't read; and you can now pass timeout = -1 in refind.conf to have rEFInd boot the default OS immediately unless there's a keypress when rEFInd loads, in which case that keypress is read as a shortcut key. A change that's less likely to be noticed is that the default setting for scan_all_linux_kernels is now true. Since this option had been uncommented in the sample configuration file, this change will not affect most people. I've fixed a bug that caused rEFInd to unload drivers as soon as they were loaded. This didn't affect rEFInd's drivers because they ignored the relevant EFI calls; but this was preventing some other drivers from working. I've added two new icons, one for Mythbuntu and the other for the Clover boot manager. Finally, I've removed Oracle's GPLv2 code from the core filesystem driver code, since it was incompatible with the GPLv3 used by the Btrfs driver. This change shouldn't affect the operation of the drivers, but there's a slim chance that it will.
  • 0.8.2 (6/8/2014)—I've continued to refine the UEFI BIOS-mode boot code with this version; it now uses the BIOS-mode boot entries provided by the firmware by default, and actively scans for new entries only if the deep_uefi_legacy_scan token is present in refind.conf. This change is motivated by reports I've received of BIOS-mode boot entries multiplying on some systems; however, a deep scan is required to detect the second and subsequent disks on other computers. A second important change is that the default selection is now the last-booted item rather than the first item in the list. You can still set a fixed default via the default_selection token, and in fact if you provide a list that begins with +, the default will be the previously-booted item unless it can't be found, in which case the subsequent items in the list will be tried. Minor changes include the addition of an icon for Mageia Linux, a minor bug fix in GUID-parsing code, and an update of my personal build system from TianoCore UDK2010.SR1.UP1.P1 to UDK2014. This last item will affect anybody else who uses TianoCore to build rEFInd, since some default paths have changed, so you may need to update yourself or adjust the path in Make.tiano.
  • 0.8.1 (5/15/2014)—The biggest code change in this version is that rEFInd's UEFI-style BIOS-mode boot code now works when rEFInd is built with GNU-EFI as well as when built with Tianocore. This change won't affect users of my binary builds, which have long been made with Tianocore, but if your distribution builds rEFInd with GNU-EFI, it might interest you. Some user-noticeable bug fixes include a fix to a bug that could cause rEFInd to omit boot loaders on a partition's root directory, a fix to a bug that caused .VolumeIcon.icns to take a higher-than-intended precedence on OS X boot volumes, a fix to a bug that could cause a BIOS-mode boot from the wrong device in UEFI mode, and improved centering of BIOS-mode boot descriptions on the screen. Other changes include two new optional bitmap fonts (Ubuntu Mono and Nimbus Mono), omission of messages about scanning of boot loaders when scan_delay is set to 1, a change to the search order for icons (PNG files now override ICNS files), and a conversion of all the icons in the icons directory from ICNS to PNG format. Note that this last change may necessitate changing manual boot stanzas if you refer to icons in the default icon directory, depending on how you upgrade rEFInd.
  • 0.8.0 (5/4/2014)—The biggest changes with this version relate to BIOS/CSM/legacy support, particularly on UEFI-based PCs. This version can now boot from the second (or later) hard disk on such computers, and is more likely to be able to cope with removable disks. On both Macs and PCs, you can also now use dont_scan_volumes to remove a legacy-boot option from the boot list, so long as it has a unique name (as shown in rEFInd's main menu when you highlight the option). This version also introduces the ability to use partition names and partition GUIDs to refer to devices (in dont_scan_volumes, displayed in the rEFInd menu, and so on). Note that partition names are stored in GPT data structures. These are different from filesystem names, which are stored in filesystem data structures. rEFInd now limits the length of the firmware identity string shown in the "About" screen, to prevent problems with the string overrunning the space available on an 800x600 display. Finally, I've fixed a memory-allocation bug that caused error message displays on some systems when re-scanning boot loaders. This bug might conceivably have caused some systems to hang when re-scanning, too.
  • 0.7.9 (4/20/2014)—This version includes a number of bug fixes: install.sh no longer displays error messages if the dmraid utility isn't available; the HFS+ driver now reports a correct volume name; filesystem driver bugs that could cause lockups have been fixed; a redundant "utility" in the MOK utility's description has been removed; and an (as-yet untested) attempt to fix a continuous-rescanning problem after ejecting a disc on some computers has been implemented. In addition, rEFInd now removes redundant kernel entries on Ubuntu systems to keep the menu uncluttered and a new gdisk option has been added to the showtools item. (An EFI version of my gdisk utility can be built with the help of the UEFI GPT fdisk library.)
  • 0.7.8 (3/9/2014—This version emphasizes changes to icon and banner graphics handling. Internally, rEFInd can now scale graphics, which previous versions could not do. To make use of this feature, three new refind.conf tokens now exist: big_icon_size and small_icon_size set the sizes of big (first-row OS) and small (second-row tool) icons; and banner_scale tells rEFInd to draw banners to a 1:1 scale (noscale, the default) or to scale the banner to fill the screen (fillscreen). See Table 1 on the configuration page of this document for more on these new options. I've also adjusted the post-installation script used by the RPM and Debian packages to search for existing Shim programs called shimx64.efi, not just shim.efi (as had been done before). This should help when installing a package on distributions that use the shimx64.efi filename, such as Ubuntu. Finally, I'm providing a preliminary set of Debian packaging files, which may help distribution maintainers to adopt rEFInd.
  • 0.7.7 (1/3/2014)—A new configuration file token, windows_recovery_files, leads this list of changes; you can use it to specify files that boot Windows recovery tools. If you include the windows_recovery option on the showtools line, these files will then be represented by a small Windows recovery badge on the second row rather than as a full-sized OS loader, thus reducing clutter and making the purpose of this loader clearer. You can also now specify a complete path to dont_scan_files items, including a volume specifier. The use_graphics_for, also_scan_dirs, dont_scan_dirs, dont_scan_files, scan_driver_dirs, and windows_recovery_files tokens can all now accept + as their first option, which causes subsequent list items to be added to their defaults rather than replacing them. The configuration file can now be specified at program launch by passing a -c option, as in -c myconf.conf; you can use this feature to set up a manual boot stanza that launches rEFInd with modified boot options. Scans of ext2/3/4fs and ReiserFS partitions now omit partitions with filesystem UUIDs that have already been seen. This is an effort to reduce clutter from such partitions that are components of RAID 1 arrays. The install.sh script now attempts to locate and mount an unmounted ESP when run under Linux. Finally, I've fixed a bug in both install.sh and mkrlconf.sh that caused the generated refind_linux.conf file to contain a stray line break and unnecessary PARTUUID= specification on some systems.
  • 0.7.6 (12/15/2013)—The biggest changes in this version relate to the default_selection setting. You can now provide multiple default selections by listing them within quotes and separated by commas, as in default_selection "ubuntu,fedora" which boots ubuntu if it's present and fedora if ubuntu is not present but fedora is. This should be helpful with removable disks. You can also include two times, in 24-hour format, following a default_selection specification, as in default_selection Maintenance 1:00 2:00, which boots Maintenance by default between 1:00 and 2:00. If another default_selection without a time specification preceded this line, the earlier one will still apply at other times. Another change to the main program is that you can now set screensaver -1 to have rEFInd come up with its screen blanked. You'll probably want to combine this with a short timeout value to have rEFInd boot your default OS quickly unless you press a key first. Finally, I've added a new option to the install.sh script: --ownhfs target_partition. This option is valid only under OS X. It installs rEFInd to an HFS+ volume that does not currently hold an OS X installation. The installation method differs from the usual rEFInd installation in that the result looks to the firmware more like an OS X installation. This makes rEFInd appear as an option in the firmware's own boot manager and it may help suspend-to-RAM operations.
  • 0.7.5 (11/10/2013)—This version fixes a few bugs, the most important of which is one that caused some Macs to hang when multiple EFI drivers were present. Another squashed bug caused the screen to clear to the default gray rather than the actual background color when launching OSes in graphics mode. rEFInd no longer shows all exFAT partitions as being bootable on Macs when legacy boot options are enabled; now such partitions only show up as bootable if rEFInd spots a known boot loader installed on them. Finally, I've fixed a bug that caused install.sh to fail when installing to the ESP with recent versions of OS X.
  • 0.7.4 (8/25/2013)—This version fixes problems in booting VMware's mboot64.efi boot loader and when launching boot loaders from some types of Mac drives. These fixes might improve matters for other boot loaders, too. I've also added a space to the end of the Boot X from Y description, which means you can use Y in the default_selection field even if another entry contains the same Y string, but with something added. To do this, you must enclose Y in quotes and add a space to its end, as in default_selection "Bit ", which sets the first boot loader on the Bit volume as the default, even if you also have a disk called Bitten. Finally, this version adds explicit support for the new EFI version of Memtest86. See the "Installing Additional Components" section of the Installing rEFInd page for details on this support.
  • 0.7.3 (8/7/2013)—This version fixes a bug that caused boot failures when launching BIOS-mode OSes on Macs. It also fixes a bug that caused such OSes' disk-type icons to disappear.
  • 0.7.2 (8/6/2013)—This version primarily fixes a number of minor bugs: A display glitch when the second row of icons is empty; improper scanning when a volume specification was used in also_scan_dirs; improper reading of volume badges from user-specific icons directory or from .VolumeBadge.icns files. Also, This version adds protection against loading invalid files as drivers, which can crash some EFIs, adds an icon for Funtoo Linux, and adds PreLoader.efi and shim-fedora.efi to the default dont_scan_files list.
  • 0.7.1 (7/8/2013)—The most important improvement to this version is a bug fix to the filesystem drivers. In version 0.7.0, drivers could hang the system (the Btrfs driver in particular generated problem reports, although the bug could theoretically affect any driver). Version 0.7.1 fixes this problem. I've also fixed a build problem with development versions of the TianoCore EDK2. In rEFInd proper, I've added a scan for EFI/Microsoft/Boot/bkpbootmgfw.efi, which is how recent versions of Ubuntu's Boot Repair utility rename the Windows boot loader. This change enables rEFInd to launch Windows even on systems that have been "repaired" by this overzealous tool. I've also fixed a bug that caused volume specifications in also_scan_dirs tokens to be ignored.
  • 0.7.0 (6/27/2013)—Improvements to the filesystem drivers dominate this version. The biggest change is a new Btrfs driver, created by Samuel Liao and based in part on the GRUB 2.0 Btrfs support. The drivers also now include a read cache to improve their speed. This has only a tiny effect on most computers, but on some it can speed boot times by a few seconds, and under VirtualBox the effect is dramatic—the ext2fs driver goes from a sluggish three minutes to load a kernel and initrd to three seconds. I've also changed some critical filesystem driver pointers from 32-bit to 64-bit, which may enable some of them to work with larger filesystems, although this isn't yet tested. The main rEFInd binary sports only two changes: It can now identify Btrfs volumes as such for labelling purposes and it can now filter out invalid loaders (those for the wrong architecture or Linux kernels that lack EFI stub loader support, for instance).
  • 0.6.12 (6/18/2013)—This version changes relatively little code, but it adds one feature that will simplify rEFInd installation for some users: The program can now deduce minimal Linux boot options based on an /etc/fstab file if that file is on the same partition as the kernel (in other words, if you do not use a separate /boot partition). Put another way, refind_linux.conf is no longer required for some installations, although it's still desirable. If you're already using rEFInd, this isn't likely to be important, but it can help when you're just starting out. In addition, this version adds support for the Linux Foundation's PreBootloader in the install.sh script. I've also changed the default 64-bit shell included on the CD-R and USB flash drive images to a modified version 2 shell, so as to enable use of the bcfg command to help install rEFInd (or make other changes to the firmware's boot manager configuration).
  • 0.6.11 (5/13/2013)—Two new features may have a noticeable affect for many users: First, rEFInd now ignores symbolic links on filesystems that support them. I've implemented this change because I've been receiving too many reports from users who want to remove redundant or non-functional Linux boot entries caused by symbolic links created by distributions. Although this is possible by editing the dont_scan_dirs or dont_scan_files options in refind.conf, telling users how to do this has become tedious. If you want to use links to create multiple entries for one kernel or boot loader, use hard links instead of symbolic links. The second major user-visible change is that rEFInd now tries to guess the distribution type based on the naming of the kernel file (effective only for Fedora and RHEL) or the contents of the /etc/os-release file (effective only if the installation does not have a separate /boot partition or if /etc/os-release is copied to that location on the partition that holds the kernel). There are several other minor cosmetic issues that some users may notice, including icons for Lubuntu and Kubuntu and a change in the name of the "Reboot to Firmware User Interface" option to "Reboot to Computer Setup Utility." I've also fixed a bug in gptsync that could cause it to hang if the disk had too few GPT partitions. Finally, I've improved the install.sh script so that it works better from a path with directory names that include spaces.
  • 0.6.10 (5/5/2013)—This version adds a number of minor improvements: The ability to create multiple screen shots under a sequence of names rather than using just one name; a new screen saver feature, activated by the screensaver token in refind.conf; and an option to reboot the computer into the firmware's setup utility on computers that support this feature. I've also added an OS for ChromeOS (os_chrome.icns), and I've updated the LodePNG library to the latest version, which might improve rendering of some PNG files.
  • 0.6.9 (4/25/2013)—The most visible change to this version is to the rEFInd banner image, which now includes an icon provided by Erik Kemperman. The biggest change with this version is the inclusion of an updated version of gptsync, which is popular on Macs as a means of maintaining the hybrid MBR that's required to boot Windows in BIOS mode on that platform. Because hybrid MBRs are ugly and dangerous, though, the rEFInd install.sh script installs the program only under OS X, and even then it must be activated by uncommending the scanfor line in refind.conf and adding gptsync to its options list. If you want to use gptsync on a PC, you can, but you'll need to copy the program file manually to the ESP's EFI/tools directory. Other changes with this version include working around a suspected firmware bug that can cause hangs when rEFInd starts on some systems and changing the timeout code so that rEFInd will launch its default OS even if the computer is started without a keyboard.
  • 0.6.8 (3/18/2013)—This version fixes a few obscure bugs but adds only one minor new feature. Most notably, it fixes a problem that caused "Invalid Parameter" errors to appear when scanning for boot loaders on some systems; fixes a bug that caused icons defined in files named after boot loaders to not appear; and fixes a bug in the install.sh script that caused the script to fail on some systems. It also enables you to name a shell shell.efi in the root directory (previously only shell_arch.efi worked in the root directory, although shell.efi worked in the EFI/tools directory).
  • 0.6.7 (2/3/2013)—This version fixes a few bugs and adds some minor features relating to Secure Boot. Bug fixes include keeping rEFInd out of its own menu when it's launched as EFI/Microsoft/Boot/bootmgfw.efi; keeping the dont_scan_volumes option out of the also_scan_dirs list; a fix for dont_scan_volumes so that it applies to the OS X boot loader; and a fix for a bug that caused PNG files in a user-specified icons directory to be ignored if an ICNS file was available in the standard icons directory. New features include support for the Linux Foundation's HashTool.efi as a MOK utility, scanning for MOK utilities on all volumes, and a more verbose error message when a Secure Boot authentication failure occurs.
  • 0.6.6 (1/26/2013)—This version includes two new features and a number of minor bug fixes. The first new feature is support for changing rEFInd's font via the font token in refind.conf. You're limited to monospace fonts that are encoded as PNG files; you can't use variable-width fonts or normal font files like TrueType fonts. The fonts support only ASCII characters. See the fonts section on the Theming rEFInd page for details. I've also changed the default font to a slightly larger one that's anti-aliased. The second new feature is that rEFInd now detects when the EFI/BOOT/bootx64.efi (or EFI/BOOT/bootia32.efi on 32-bit systems) boot loader is a duplicate of another boot loader, and automatically excludes it from the OS list. This is useful on systems that boot with Windows, since Windows tends to install its boot loader twice, once using the EFI/BOOT/bootx64.efi filename. Bug fixes are described in the NEWS.txt file, and include fixes for bugs that prevented manual boot stanzas in included configuration files from being detected; that caused an ASSERT error to appear on the screen on some systems if default_selection was not set; the caused Binary is whitelisted messages to persist on the screen when loading signed EFI drivers with Secure Boot active; that caused rEFInd to ignore icon tokens in refind.conf manual boot stanzas; and that caused the install.sh script to fail to update drivers when rEFInd was installed to EFI/BOOT.
  • 0.6.5 (1/16/2013)—Most of this version's changes relate to icon, graphics, and theming features. The biggest code change is in support for PNG files for banners, icons, and selection backgrounds. I've also fixed bugs that prevented large banners from being used; you can now use banners as big as the screen (or bigger, but they'll be cropped), as illustrated on the Theming rEFInd page. The text color also now automatically switches between black and white depending on the background over which it's displayed. If you don't use these features, you're likely to notice some changes in where certain elements are displayed. Most obviously, the banner appears higher on the screen than it did previously, so as to minimize the chance of overlap with text displays such as the information screen. These text displays should appear correctly even on tiny 640x480 displays (they were blank on such small displays in the past). I've added icons for Haiku and ALT Linux. Finally, the only non-graphics development is the addition of a "safe mode" boot option for OS X, which you can disable by adding safemode to the hideui option in refind.conf.
  • 0.6.4 (1/8/2013)—Bug fixes motivate this release; it corrects a couple of memory management bugs in 0.6.3 that cause rEFInd to hang at startup on some computers (unfortunately not on any of mine, so I missed this). I've also made a small change to the install.sh script so that it installs the ext2fs driver rather than the ext4fs driver if the script detects that a Linux kernel is on an ext2fs or ext3fs partition. This can keep rEFInd from scanning ext4fs partitions and picking up non-functional symbolic links to vmlinuz on such partitions.
  • 0.6.3 (1/6/2013)—The installation script and related tools see the biggest changes in this version of the program. The install.sh script can now detect a rEFInd installation in EFI/BOOT or EFI/Microsoft/Boot and update it rather than install to the default location of EFI/refind. It will also install to one of these fallback locations if it's run in BIOS mode, thus helping users who want to get a BIOS-mode install of Linux running on an EFI-based computer. A new mvrefind.sh script can move the installation between these three locations (or more exotic locations). Outside of scripts, the dont_scan_dirs and also_scan_dirs tokens can now accept volume specifications, as in myvol:EFI/bogus to not scan (or scan) the EFI/bogus directory on the myvol volume. I've also fixed a bug that caused rEFInd to ignore default boot loaders on removable disks if rEFInd was installed using the fallback filename. I've also modified the ISO-9660 driver so that it works with ISO-9660 images written to non-optical media. This may help with getting "hybrid ISO" images written to USB flash drives to boot.
  • 0.6.2 (12/30/2012)—This version's biggest changes are "behind-the-scenes" improvements. Specifically, I've completely re-worked the shim/MOK Secure Boot code, based largely on an approach used by James Bottomley in his PreLoader boot loader. This fixes some bugs, such as the inability to launch more than one EFI boot loader in Secure Boot mode. The EFI filesystem drivers can now be built with GNU-EFI, which may help distribution maintainers. I'm also providing RPM packages of rEFInd, although I recommend installing from the binary zip file. Finally, I've changed rEFInd's default text-mode setting behavior to not adjust the text mode. (Recent previous versions forced the system to use text mode 0, which cuased problems on some systems.)
  • 0.6.1 (12/21/2012)—(Mayan apocalypse edition!) This version features a number of refinements and minor bug fixes. The install.sh script now includes a new --root option to enable easier installation of rEFInd to a regular OS installation from an emergency disc. The ext4fs driver now supports the meta_bg filesystem feature. I've fixed a number of obscure display resolution-setting bugs and a bug that caused the screen to clear after displaying certain error messages but before prompting you to continue. Instead of displaying a blank filesystem label as the "from" location for a boot loader, rEFInd now describes the filesystem by its type (FAT, ext4fs, etc.) and/or size. rEFInd also now uses the filesystem label as a hint about what type of icon to display for a boot loader.
  • 0.6.0 (12/16/2012)—The donation of a working ext4fs driver from Stefan Agner has prompted another big jump in the rEFInd version number, since this driver will greatly simplify installation on many systems: You may be able to simply run the install.sh script to get a working rEFInd that boots your Linux kernels directly, bypassing GRUB or ELILO. Other improvements in this version include bug fixes and minor changes to install.sh, the addition of hint text to the rEFInd main menu, the ability to disable the options editor via the editor option to hideui in refind.conf, a new textmode option to refind.conf to set the size of the text-mode display, a change to the code that adds your initial RAM disk to the boot options so that if you specify one manually (via refind_linux.conf), it will take precedence, and assorted obscure bug fixes. The NEWS.txt file goes into more details about many of these changes, as do the relevant pages of this HTML documentation.
  • 0.5.1.1 (12/12/2012)—This is a micro-update to fix a bug in the install.sh script that prevented it from working under OS X. Aside from that, and a few small documentation changes, this version changes nothing in rEFInd.
  • 0.5.1 (12/11/2012)—The most important changes to this version are to the install.sh script. It now supports two options, --shim and --localkeys, to aid in installation on a Secure Boot system. See the Installing rEFInd and Managing Secure Boot pages for details. The script also now creates a sample /boot/refind_linux.conf file to assist in setting up boots via the Linux EFI stub loader. All of these install.sh improvements work only in Linux. A separate mkrlconf.sh script creates a /boot/refind_linux.conf file if it doesn't exist, for help in post-installation configuration. In rEFInd itself, I've fixed the bug that caused ELILO to be unable to locate its configuration file when launched in Secure Boot mode and fixed a couple of more obscure bugs. I've also added an include token to refind.conf, to enable you to create a secondary configuration file (say, one managed by scripts while leaving the main file untouched; or one dedicated to manual boot stanzas).
  • 0.5.0 (12/6/2012)—I've focused on adding support for Matthew J. Garrett's shim program to this version of rEFInd; with this support, rEFInd is capable of launching Linux kernels and other programs signed with a suitable key while the computer is in Secure Boot mode. This initial release, however, requires significant manual configuration and has some known bugs and limitations. See the Managing Secure Boot page for details. Beyond this major new feature, this version includes several more minor improvements. These include a change to the resolution token so that it applies to text mode as well as to graphics mode; a bug fix that caused the line editor to blank out lines that were left unedited; a new dont_scan_files option to blacklist boot programs by filename; support for launching MokManager and Apple's Recovery HD partitions via tools (2nd-row) icons; new --usedefault and --drivers options to the install.sh script; a change of the esp installation script option to --esp; and the ability to use quote marks inside option strings by doubling them up.
  • 0.4.7 (11/6/2012)—The most important new feature in this version is a boot options editor. From rEFInd's main menu, press Insert or F2 to see the options menu. Select one of the options and press Insert or F2 again and the screen switches to a text-mode display in which you can edit the options that will be passed to the boot loader. A second new feature is a new icon for gummiboot, which is another EFI boot manager. This version also alters the behavior of the scan_delay option, since I've been told that the previous version didn't work; the new one does. Finally, this version omits the space that followed boot options when booting most OSes. This behavior was inherited from rEFIt; a comment in the source code indicates it's needed by OS X, but I've been told it causes boot failures when launching Linux on some Macs. Thus, rEFInd now adds this space only when booting Mac OS X.
  • 0.4.6 (10/6/2012)—Thanks to contributor John Bressler, rEFInd can now boot legacy (BIOS) boot loaders on many UEFI PCs. (Previously, rEFInd could do this only on Macs.) Other changes include a new scan_delay option that inserts a delay between rEFInd starting and disk scans (to help detect disks that are slow to appear to the firmware) and a change in the default scanfor value so that legacy OSes are detected by default on Macs (but not on PCs). I've also fixed some memory management problems that caused error messages to appear on some systems when rEFInd was compiled with the TianoCore EDK2 toolkit. Finally, I'm now using the TianoCore toolkit to make my primary binary builds, since the new UEFI legacy boot support requires the TianoCore environment. (rEFInd still builds with GNU-EFI, but it doesn't support booting legacy OSes on UEFI systems when built in this way.)
  • 0.4.5 (8/12/2012)—This version fixes a couple of Mac-related bugs. The most important is that version 0.4.3 and 0.4.4 couldn't boot BIOS-based (aka CSM or Boot Camp) OS installations; 0.4.5 restores this important feature. The second bug is in the install.sh script, which would often fail to detect rEFItBlesser, thus leaving it enabled and causing rEFInd to fail to start after the first reboot into OS X.
  • 0.4.4 (6/23/2012)—This is a bug-fix release. Most importantly, it fixes a bug in the new use_graphics_for feature; in 0.4.3, the options were set incorrectly (they just happened to work as expected on my main test configuration). I've also fixed problems with volume names in the 32-bit versions of both the drivers and the TianoCore EDK2 build of rEFInd itself. Finally, I've tweaked the install.sh script to do a better job of identifying the computer's ESP under OS X.
  • 0.4.3 (6/21/2012)—The major user-visible change to this version is the addition of the use_graphics_for option, which enables you to specify the OSes that rEFInd launches in graphics mode vs. text mode. This effect is tiny on most systems, but can be important on some, as noted on the "Configuring the Boot Manager" page. There's also a change to the way graphics-mode boots are handled, to make for a slightly smoother visual transition. This version also fixes the incompatibility between the drivers and the firmware used by Macs (and probably other EFI 1.x systems). I've removed linux.conf as a valid alternative name for the refind_linux.conf file, so if you're still using the old name, now is the time to rename it! The biggest change is behind the scenes, though: I've added support for compiling rEFInd using the TianoCore EDK2, as well as the GNU-EFI toolkit that I've used up to this point. I have no intention of removing GNU-EFI support, but there's a chance that the TianoCore toolkit will help in implementing some future features or in debugging some problems. You can download either version from the downloads page.
  • 0.4.2 (6/3/2012)—I've added a new dont_scan_dirs option to the configuration file, enabling creation of a directory-scanning "blacklist." See the "Configuring the Boot Manager" page for details. This version also makes a couple of changes to the install.sh script. The first is a reminder for Mac users to update refind.conf if they need to boot BIOS-based OSes. The second change makes the script a bit smarter about updating NVRAM settings when run from Linux; it now attempts to make itself the default boot loader if an entry for rEFInd already exists but isn't the default. I've made this change in response to problem reports from users; apparently some distributions' GRUB update scripts make GRUB the default boot loader under all circumstances, which causes rEFInd to be taken out of the picture after a GRUB update. The previous install.sh code wouldn't add rEFInd back to the "top spot" after this happened, but the new code should do the trick. (Although re-installing rEFInd is overkill in this case, it's something many users would logically try.)
  • 0.4.1 (5/25/2012)—This version provides a number of small bug fixes and improvements: When re-scanning (initiated by pressing Esc in the main menu), a message that re-scanning is occurring appears on the screen; I've fixed a bug that could cause rEFInd to appear as an option in its own menu after running a shell program and re-scanning; the install.sh script now checks for, and optionally deletes, the rEFItBlesser program when run under OS X; and the HFS+ driver now returns a volume label of HFS+ volume, rather than nothing at all (unlike other drivers, the HFS+ driver can't yet return the volume's true label).
  • 0.4.0 (5/20/2012)—I've bumped up this version number more than usual to reflect the addition of four filesystem drivers (for ext2fs, ReiserFS, HFS+, and ISO-9660) to the rEFInd package. These drivers originate with the original rEFIt, VirtualBox, and Clover boot loader projects. You can learn more on the drivers page. To facilitate inclusion of drivers on the CD image, rEFInd also now supports reading drivers from architecture-specific subdirectories—drivers_x64 and drivers_ia32 for x86-64 and x86 systems, respectively. This version also adds the ability to eject removable media on some Macs (this won't work on UEFI-based PCs, unfortunately). Finally, this version fixes a problem that could cause GRUB 2 to be unable to read its configuration file in some settings when launched from rEFInd.
  • 0.3.5 (5/15/2012)—This version's biggest new feature is the ability to re-scan for boot loaders after launching the program. This is done by pressing the Esc key, which causes rEFInd to re-read its configuration file, to tell the EFI to reconnect all disks, and to do a fresh scan of all disks for loaders. This is useful if you insert a removable disk after starting the computer, if rEFInd starts before a disk has fully settled, if you make a change to the configuration file, or if you manually load a driver. This version also fixes a minor bug that could cause the scroll-right arrow to be replaced with a left-pointing arrow under some circumstances; and I've removed the scan for a BIOS Boot Partition that I added in 0.3.2, since I'm told it isn't launching correctly. (BIOS-mode GRUB 2 can still be launched on Macs from its boot code in the MBR.)
  • 0.3.4 (5/9/2012)—The biggest change to this version is the addition of the icons_dir configuration file token, which enables you to specify a directory that holds icons that override those in the default icons subdirectory. See the Theming rEFInd and Configuring the Boot Manager pages for details. This version also reduces flicker when moving your selection around the screen and modifies the install.sh script so that it can be used directly after building rEFInd from source code. Related to this, building from source now creates a binary that includes an architecture code—refind_ia32.efi or refind_x64.efi rather than refind.efi.
  • 0.3.3 (5/6/2012)—I've focused on user interface improvements for this release. The biggest improvement is in the text-mode interface, which suffered from assorted display glitches in previous releases. These have now been fixed, so the text-mode interface should be more usable. I've also fine-tuned the use of keyboard keys, particularly in graphical mode. The up and down arrow keys now move between the two rows of the display, and Page Up and Page Down scroll the first row if it's too big for the display. (They'll also move between rows, but only when at the end of the first row or the start of the second.) Returning from a failed loader or a tool or built-in function now renders that tag as the currently-selected item, rather than setting the default loader as active, as happened with previous versions.
  • 0.3.2 (5/4/2012)—rEFInd's core functionality changes very little with this version; I've tweaked the detection of BIOS-mode boot loaders to keep unbootable FAT partitions created under Linux and Windows out of the boot list, while adding detection of GRUB BIOS Boot Partitions to the list. I've also made a change that improves screen-clearing when launching EFI utilities and OSes in text mode. The major change to this version is the addition of a new Linux/OS X installation script, install.sh. In most cases, this makes it possible to install rEFInd simply by typing ./install.sh from the rEFInd package directory; however, you should see the Installing rEFInd page for details. In some cases, manual installation may still be required. Also, you may prefer to copy over the old rEFInd program file with the new one when upgrading.
  • 0.3.1 (4/27/2012)—You'll find a few minor enhancements and bug fixes in this version, none of which affect the configuration files. rEFInd now sorts its boot loader entries within each directory by date, with the newest items first. The intent is that you can specify a directory name as the default_selection and the most recent boot loader in that directory will become the default. This may obviate the need to adjust the default after adding a new Linux kernel with EFI stub loader support. I've also improved the handling of .icns files for Linux kernels that lack .efi extensions; loader-specific icons for these kernels should now take the name of the kernel plus .icns—for instance, vmlinuz-0.3.2.icns for vmlinuz-0.3.2. rEFInd also now hides all .icns files from the boot loader list. Finally, this version fixes a bug, introduced in version 0.3.0, that could cause spurious Unsupported while scanning the root directory errors under some conditions on Macs.
  • 0.3.0 (4/22/2012)—This version marks the official transition from alpha to beta status for rEFInd. This isn't because of any important objective milestone being passed; it's just that rEFInd has been used by many people who have reported no show-stopping bugs, so I'm now confident that rEFInd is stable enough for general use. That's not to say it's perfect; it still has numerous known bugs and limitations. That's why it's still beta. To get down to specifics, this version adds two new configuration file tokens: resolution, which sets the screen resolution; and scan_all_linux_kernels, which adds Linux kernel files to the boot loader list even if they lack .efi filename extensions. See the Configuring the Boot Manager page for details on these new options. I've also fixed some bugs: One that sometimes caused Macs to crash when returning from the EFI shell or other programs; another that caused rEFInd to fail to scan filesystems if the filesystem driver didn't return a volume name; and a third that caused rEFInd to fail to detect boot loaders depending on the case of the filename on some EFIs (this is really a workaround for an EFI implementation bug). The first of these is a very tentative fix and it could have negative effects on some systems (non-Mac EFI 1.x systems or Macs that weren't affected by the bug in other recent releases), so be sure to contact me if rEFInd crashes or otherwise misbehaves after you use an EFI shell.
  • 0.2.7 (4/19/2012)—I've added two new tokens to the refind.conf file, with associated new functionality. The new scan_driver_dirs option tells rEFInd where to scan for EFI drivers, in addition to the default of the drivers subdirectory of the rEFInd installation directory. For more on EFI drivers, see Using EFI Drivers. Note that previous versions of rEFInd couldn't load drivers at all, although they could make use of hardware and filesystems activated by drivers loaded before rEFInd launched. The second new token is also_scan_dirs, which adds arbitrary directories to the list that rEFInd scans for boot loaders. (Without this option, rEFInd scans each volume's boot directory and every subdirectory of the /EFI directory, with the exception of /EFI/tools and rEFInd's own directory.) This version also fixes a minor bug that caused rEFInd to sometimes include itself in the list of OS options. Finally, if you build rEFInd yourself, you should be aware that it now requires a newer version of the GNU-EFI library than it required in the past. See the BUILDING.txt file, included in the source code package, for details.
  • 0.2.6 (4/14/2012)—This version provides one bug fix and one new feature. The bug was introduced in version 0.2.5 and prevents rEFInd from identifying a Linux initial RAM disk file on some (but not all) EFI implementations. The new feature is the volume stanza token, which enables you to manually load a boot program from a filesystem other than the one from which rEFInd launched. You can specify a volume either by its label (as in volume KERNELS to load from the volume with a filesystem name KERNELS) or by number followed by a colon (as in volume 0: for the first filesystem or volume 1: for the second). See the Configuring the Boot Manager page for more on this new feature.
  • 0.2.5 (4/9/2012)—Icon-handling improvements are key in this version. I've fixed a bug that caused icons to be replaced with ugly "not-found" default icons when rEFInd was launched in certain ways. I've also added support for .VolumeIcon.icns and .VolumeBadge.icns files to set loader tags and disk-type badges, respectively. (See the configuration page for details.) I've also fixed a bug that prevented rEFInd from finding the correct initial RAM disk for Linux kernels stored in the root directory of a partition.
  • 0.2.4 (4/5/2012)—This version adds support for a new location for EFI shells (shellarch.efi in the ESP's root directory. It also adds two new refind.conf options: showtools and max_tags, and removes another one (disable). The options available in hideui are now essentially a combination of what disable and hideui did, minus functionality now present in showtools. I made these changes to reduce redundancy and to increase flexibility. See the Configuring the Boot Manager page for details.
  • 0.2.3 (3/26/2012)—I've changed the Linux kernel configuration filename from linux.conf to refind_linux.conf with this version, to avoid a name collision with a planned future Linux kernel ability to read its options from a file called linux.conf. This version also includes a tentative bug fix for a problem that caused rEFInd to hang upon launching the second program (say, a boot loader after using a shell) on some systems; but on some computers, this fix causes an (apparently harmless) error message about "(re)opening our installation volume" upon returning from the first program. I've also added a logo for Arch Linux.
  • 0.2.2 (3/23/2012)—This version fixes three bugs: One caused submenus to not appear on systems with screens of 800x600 or smaller; another caused rEFInd to hang when boot loader names were too long; and the third caused the program to fail when Linux kernels and their initial RAM disk files lacked version numbers.
  • 0.2.1 (3/19/2012)—This version adds the ability to auto-scan Linux kernels with EFI stub loader support, provided a suitable linux.conf file exists in the kernel's directory. It also adds support for manual specification of submenus in refind.conf.
  • 0.2.0 (3/14/2012)—This is the program's initial public release. It's based on rEFIt 0.14 plus a large number of patches taken from Debian's Linux-compilable rEFIt package. I then added UEFI-specific fixes, support for OS definition stanzas in the configuration file, a scrolling icon list on the main menu, and other minor improvements. This release has quite a few known bugs and limitations.

copyright © 2012–2018 by Roderick W. Smith

This document is licensed under the terms of the GNU Free Documentation License (FDL), version 1.3.

If you have problems with or comments about this Web page, please e-mail me at rodsmith@rodsbooks.com. Thanks.

Go to the main rEFInd page

Learn about problems with and the future of rEFInd

Return to my main Web page.

refind-0.11.4/docs/refind/HashTool1.png0000664000175000017500000000320312626644767020043 0ustar rodsmithrodsmithPNG  IHDRgAMA a PLTEOҧ2tEXtSoftwareXV version 3.10a-jumboFix+Enh of 200705202IDATxnJq/s]z R_ePA\e?/$p3M'O9П2-^UecZ0B=z & ^JA(PB=z^X;oΞúhau5zOظ4|UةلU7j. Up8wֿ]ݶnIau>.ĦvI(>~BgB\Iں }8Op(q0)_q? Qgl;KBo/(A!CPB=z!CupvڼzîOqWe*RTMs1uoU0,( qkl*;{?ʶ.@㳡m[{G xj4j|]Ŵ5D76:gߺ+"^/&lL&,4Q|B-$|LKdV}x! K`(Y:G MU_{Jz_}u{q!WI(].d6ӒިH}ya>B ǹߺ'LM׊]smՓܩ@Y>Nxlq|o۠6>-4A.,sxoK3鬦:Ӵ6 ga_| CaϼJ Em+,_ПŅ|?}O]ɮt [~_!CPB=z!CPB=z!CPB=z!CPB=z!CPB=z!CPo觎-/GF8a|djGF8a|djGօ?VwO"\.{ǯzg? _0Ⅻ҅O_vawU?$ qKv]n랻O&\;R 㢅Oi%V{!{JQ¸vO=~v܅ p!7Z02 ӝ/qar}.vA.(C移3n]c֗t)a߆ a۽ٛ: ]5Vr@?%4=7a}:ڤģM1¿#AϜ)RXܿ4>25 #S+ܿ5~g^>7ǯŸ c>ng% ԰W򅥯exa>Ņd"Wo۶---Mxq}'O޾}ǏlV>|Ux<(Dat̜9sժU'O={6,,lҥK~~~J[8qB(Ο?_7;~q8l=Nv:t… ?EQZ633y9̟?ذa w}2vXVbbbZZϞ=bŊ3g BCC=ZfMjj={RRR~'k$YPP`4޽{?裮]r8e˖pԨQ NNNm\z>((dJӧOn=rqqqwwOOO_.]@233!4h 흕$t$\.6^߻w?鼽wnxvvYF#Bh̘1AK.Y+(==]PkO6t֭ÇO8144t|[oEIj ?k޷oرc|hL|L&ꫯ233)D#F:`0 ,X`0BwX={ك9yU{̙/^{С/rС6m"I!듒~͛77˗?zիW;iҤ>}ܹsgͥ/"==}ذa>,))A䓞xٳg/;vHKK3c|vk 7o62̩S$- ||| k,aaa`qG3gtvvf2 "99WYYY7V,d2@GsW^ݧOYfٝ={UD\.WT_!!!5552 !T^^V `0fj^bH$555[n h4yyy/ MO|||PP믿NgMYY/2~ {[>>{U(3k֬9uW_}33 a' 7Heee^^^֎~BdÇKҋ/?FcFFFXXXd ۻ"6l I7ضmMk<(ڸ˗O:W$j4>>>׮]kVr-l"22tY 888 P"  M(H&Lv9322JKK=hh2""bǎuuu۶msss ԔnܸyܸqM͟?駲2p'wMmfkZݥK`Y>}\\\gH.\xݍ7>|lLGFo\.>'Nt:$k č7^ؓoN:USSԩSϟO^oSSS C޽<==B֎c\jUjj*^rJ>rZ_bX,Ʒ۷Y,h_rM* x뭷""",sÆ 'N "**jʔ)ӧOw㯿\PPd2̙3qDʏ?^WVVq8lٲZ$$$$$$r<ڷo{#>t "##ivΝ;}:K.nǏ'OسgOSbkŊA[O߿Kbb"~hʔ)={ ׿ES%$꫗^zO< {I|\(1cx<w"MmOk壏>"bܹ{Zb4o:HH$Izz*Z *fFQQѺuϟZ|ѣGϟ?ѣ1hZ*++j5554e\rر?=jzb NS^^~Сgee}{7n\ddhDM6MV^xQ&-Xoo߾cǎ͛7ƮZѣEEE6lxB**++ !tVj_{5/^ZQQ1{+VPEsij{Z.6m1bĭ[g}wܡZb4o:5_(2u[v5u\^$I@zխ[7^f|ڵO>qwwgX_~\.gx+֤ &9xŋ$J|>_.߿?00w߭zqyyyFFƲe|~׮]̙oZgٲe>>>ի?Ӟ={"&M$Jip­[:;;XѣGk4JegD"h?S''M a/PWW!Eܭ*\0PnnnYYY߾}ssszDYYY֎bM/_1sǏ\ rrrB!4 FBA琟P(?~~O0MÖ-[ ԣGy壹. !QXXغ7l]G0: 3uuue:r;>ީ@ Y~k Ҙjac7.///::ZR;JiiiS3 oT*Unn}f̘A!pW_} UUUWjoqm6WTmpM[:= zV}?=Ȫ a@`ggWUUիW/6+ʢ>}X;nTUU5,'댌 Ey8q"++Onƹ۷}\.OIIk:~…(Bm^tƌ.\;w.}_cС$I믿>~իrssccciڵ˗Z{44=KeeGrrrۭEZ:fjwԒ"^=ɸ]mWm/l-Y$<<:::~֭K lozzz޺uŋb8B_~sφ r5Ⱦ}z{{ikF7n蔷(IAѨ ]w-ax,1着1c|E/Y~S2vX=W~~v[#.,&3R=DaX_u떳3IwjtN_z^V'*uJtF:ؾ4 thBBBΝVlv^bcc'LêUY,VZZZLLLpppg=NؑkZmmm_u/\]'vGO`t˜Hv< 3AzBX-ȮId/܋h4bKГR|-LgL`[Jd%I*!vFFs[P7FȪV`j)ǎ+))ivǏ~ Œ3F׌g]r|%DdC T uЯ_?bfp̙/EkDh:XZ:Qߤ(nƾ35QF5  kLS+&QeP% e/d*33(H4bĈ+V ^P(O&޷oرc|hL|PYY͛o޼r%\.޽EKxӕJNN>x`eeX,ʸѣGc3±cdӧO[ٳgɓGh"""LbiӦUVV._?ϊ+ ׬Y3j(^wޟYy{{GEEu!Dd||S?~lzħ IDԔC{ Dғ;v III͛M ;၁/i&ǰl2Vo>\>u?cǎڵk˖-K.1c?v[lyn-?iҤ>}ܹsg͵VٳZ+WvU\\<`_!m۶ooyjPlllbb+>/J(N&") yz=xa&j5A ח~@$q\R~d7oΙ3庸L4ڵkڕڽ{YͨQD"ŋ[www8pD"ٺukXXXXXD"9_J5w>}~/ryyF9|̙3LfDDBHNN3gN``3ޅuIޡTovV-)ͼy YgΜߖ/_ޭ[XMG" >}d'O\p!BEFF6jO=돧P-Tdl8Kst$`ؚ5K%z܂SHj؆ H|7mvup֮]L}ٳ?h:ul)Eѓ[vrի999$I=^yhmnH5`MP%VS-!((hҤI}FaXݺu[jՈ#eH>G(XmmmJC;G)'w/j $@G:+[mz!D?yE{A3!oU¬0Da#Y[[;KCgELP)ϧo=5) a8 @Z_LBv֭: +J1HXe2L&dE[dܒw©]v <800Ƽe˖!C? :uThhCBB6mDҚ˫;w4hP 6ն.&3HIl6|>߳ AN6"hѢW_}uرG-[, >>uKtk׮ =C.\@ؚ˫}k8{w5bK.)& $ c0, X,)) t["ּOM:z>((dJӧOwS5jTBBB㟊ojztOEIfFq8zHTWW***iLњe)CY/ĦMrCgС9 v}ׯ+J`3f4۷oz-Miiiqqq?7n4۶mp8;Cmٳf¡1c`ٗ.]q QX/$)ʬ?L{N$IRT*Qjp@YrI0tm*M>/_O;_zիXt8¢ݪ999O|cVk/^xٿˎ;ԷoӧOj>>>W^s]zҥK!wYk/IDATu$kj;rB!Z[b[Omj" [)Vuezޢ_}tڴiMb0|>!4hРF#40VaP8hР#G={W^򏏏 zB7ԩSɻv?Mή:%%E&4)2$H=zcgg'ݻ]a#""qA:tϭQ"RX7rnʕ\WWv΋T#"̖%>䏆/̓HO2nUt#S(<7& .rFӒ:ba2nnneee4&B {z꯿yem.[PP`H⫌NYIBVϺ[#} avӺ޿S'QϜc e ! T ɐIRoFRnk֬s͛훞t:c-6mW^V޽?A5WXQdzS!)V[th\$m]+RBBRHw%foww<|"$Irok7Ԍ'2 >>׮]v-Z4pȊ6)F ^3)㎯#]]Lm͕bjEwHXXXÇϜ9CQԉ'([ܼySDGGjjjJJJ 7n4n8.\xݍ7>|417 ?ƃG)8U[^(sm ,Ҡg'^ک{t_| j*z}ee0`233sڵrgϞAAA]^̙cu…W\AD"+WY/IvΝ;ZZOqEܮzK_M`zuVtf4i3VxF LQ^m[Eܭ@hC0նn] T{ I@ZTJZuBO2nWuԩr=muZnl2a„cb Pxxȑ#s΍9rذaҟ>}:$$dȐ!!!!w1?cƌÇ\ro$I&ʩIn_Jx#;gddcǎL;wN8188wAAc71c <8((͛71رc>_|Ehh#FHFbr+.!sNЎ;"##jkcbbo޽[T3g= frc-$%YߢmRSSSRR͛=y,>je˖9;;O8̜9_͛?:|&9uԔ$B`DFFvp8~~~ADDDeeѣGj'Nl#% /{"FU¬7v=:t~(HΞ=h>ѣG|GITݧNWR5&ۘ1c߿ b$왉Țv:=ɸ-5b7t=-,,4 =z k^^(tҤI8X3xG ߏWZ՘"U>\YY9mڴ"| ѣGKI ,XViz_Gn@{0Dv<ِ"NM05&+r)ЩSLN>XfͩSV\v-g޽ |ʆ #qrr>}MFqBsΝ={w}C]K50 ͇eݧYqdɻO37+5iq"DQHO1S&Soʼ7j);|vvvuusj5@ ppphxEYsǭ ~L}@:֊ $T̔=Ug?,kJO ׬zfy>P P~~ulz*M(H&LvzƹbƏ2@CS]^j't:IxcmMM\RٳMZsǍ`0B0<?W%ɯd@ /h4jڋ>5NЦFHcpJ s4C\ Й%_0Y7 t;|=ez'^߳XN`qjSO 8p`HHȈ#N׈uV}???s :ts?Bf t {9'"&IB#S7Kj^PJpN6gϞ)))iii>>>˗/4;khy-B7n3llڻ`<5,IO2nVI;1&<~ץRiFF~}FEy@prsk;DdC);Ԥ\. $%%SNMKKCY;v,vٳo͚5iii'O?~cǢ.]o=:%%b4e1pL:\a-64Zlgk[kg0?_BK5+^gS qJZkE=|pطرcvڲeKjjjddҥKKKKΟ?Ȑ!I&Ν;ׯ_nnnxxx```nnCˡCnڴ֚5$oFFEQׯ_7I5WX.M?MZ$oS A;pGoG{ؾ"///88xʔ)/9sٽ{Y<</DL!mBb DQD2d2ĝ*i;3Sjzyȑ͛7t:.+e2YlllBB߱$IVUU5aÆa{#G B~~~ cj~4E600ȑ#Ç5߿ rsmWҷs$-B0횫z(A/圖yD"1xҲ!dl˯dUK8l6}~ f͚uᤤSbcH=+O-׷.11xHК5kܹy}q֥aig=v$ dvj>^xQ+./r{kT/ftw]߿$IDᑞn;+U(͛7m;Ԡ\zY,֠Ab1059Br"m aM֬vs"TGPG}gX::::::8;;;:::88ٱ @FsW>]RK[gܫ(TX+_Ӯ̙SPPp9ŋϝ;{cǎeffdY EzzmQһ;,XHS]aGri"m6<֬ZVT^V HpEB\z@ZJ%|>cX,ˤZVѨjZj{tgتgKRWPN ]6lؠBCC׭[Zp_ueХKbbbrrrX,V,YUUU}Y^^^PPĉ?C;;\`0"ڵ N8ADTTԔ)SO~=GG_Ӱ\ن̝;ݻ &c*+WXs"+ɚTr-o-팗b&kVbsh9+N"H x<`0iZJU[[P(jkkU*wК/#&bPJF+ƣ`8ɐ+3MDR֤ۚ'/>̥SŇ_(J$Z]VVd!PRK_d~]I1d)( :@f> ]+Ŧў B |>O26R#&L8BF =kO$$I<0h6ZT`0lDO0c3(F-*:\.q Jģl6U!@{ׂ+Sjcw|)SW]]G-1bx\tA2BғMZ+@ ڗ=T_қov8%45r/r(M+H)Rb0@]t$Gi67 ҞYg2hyw<SL>Ѳ=(F‰0Sd2T"ۭ[r#< hi+{~y[@\):Ʀ%<+%j>Y=]_4HO HDd#0f${GJ=cwIFT % cXJbmJ=YL<)z 4_4HoǪ+L-W1 Q&ig*k^zOzge~BByJ-n /ODZҷZ?qhA,G2|-E=2,XN7&Ny짙ILR@ Q {"Q o[vkL&/X3xPbbgQgjP~fg~֏L1g$ܚ5лt4!!R1T*h@1nA MUB0Z0 ]8ZZSt')#ez5J Hv@Qyv mjOȑol^$/ܑd2kIF]ZifnJqFb mve M;za4 6gޒ@EaZRᷙ~qvj8fSͮ$nWJu0"m(axn.CCf?ɄA֍L[Ø 9safgBx ֈ@HyvbuFFgeB٨~1Ҟ%ӯDoddKq _PH$k~"Ғ [<m.am/$jL"IT iј1HZCVg`l@ (('~+lR1LWg lyR8L͢ʁ'MT* *K-A'݄nJ-s3FJJt8)<7Orppp8;;DKi`0ڨ/B06}Z-Fh4CZ^o޶$ =y|DfИM%L H$Pr[}iI B;;;!y٤#8HMA ^`[ 1Eq\Nl!a).E"m-z7dDAx68/P(4BT l%aAP7.Dl6[(bxMpLֺEpt^h4tvŴSf9]-[oV;6z_-Ea #-$ lR&(`P[;yHO۾ nz/l)Ey!Ǜ m$am,+m [HHH a a a aHHHHulkIENDB`refind-0.11.4/docs/refind/todo.html0000664000175000017500000005536013372346574017373 0ustar rodsmithrodsmith The rEFInd Boot Manager: The Future of rEFInd

The rEFInd Boot Manager:
The Future of rEFInd

by Roderick W. Smith, rodsmith@rodsbooks.com

Originally written: 3/14/2012; last Web page update: 11/12/2018, referencing rEFInd 0.11.4

This Web page is provided free of charge and with no annoying outside ads; however, I did take time to prepare it, and Web hosting does cost money. If you find this Web page useful, please consider making a small donation to help keep this site up and running. Thanks!

Donate $1.00 Donate $2.50 Donate $5.00 Donate $10.00 Donate $20.00 Donate another value

This page is part of the documentation for the rEFInd boot manager. If a Web search has brought you here, you may want to start at the main page.


rEFInd is far from perfect. It's based on rEFIt, which has a list of active bugs on its project page on Sourceforge. I have not studied this bug list in detail for rEFInd's first release, although I've probably fixed a few of those bugs because I encountered them myself. Other bugs I may never fix because I lack the necessary hardware for testing.

This page exists to document some of rEFInd's known bugs and limitations, as well as features I hope to add in the future. Some of the items on this list are things that you may be able to help with, so if you'd like to contribute, feel free to drop me a line!

The following list groups things that need to be done into broad categories. In some cases, there's some ambiguity about how an item might best be classified. Without further ado, then:

  • Tasks with which non-programmers can help:
    • Testing! rEFIt was complex enough that changes such as the ones I've made have the potential to disrupt the program's operation in unexpected ways. Since the initial 0.2.0 release, I've continued to add features to rEFInd, and every new feature is another way for bugs to get into the program. I can only test on a handful of systems with a limited number of configurations. Therefore, if you try rEFInd and run into bugs, please report them to me!
    • rEFIt's original design, and hence rEFInd's design, enables easy theming by replacing icon files. If you'd like to design a new theme for rEFInd, feel free to submit it. I might or might not replace the icons it uses now (most of which come from the Oxygen Icons package), but I may provide links to themes on this Web site (or even host them on the project's Sourceforge page). For more information on designing themes for rEFInd, see the Theming rEFInd page.
  • Improvements to existing features:
    • As described in reference to version 0.9.2 on the Revisions page, rEFInd includes a delicate and hackish workaround to a problem introduced by Shim 0.8. Developing a better solution to that problem is a high priority.
    • rEFInd's Makefiles and, to a lesser extent, C code, support x86, x86-64, and ARM64 CPUs. EFI is also available for Itanium (IA-64) and ARM32 CPUs, so I'd like to add this support.
    • Currently, rEFInd can detect whether it's compiled for x86, x86-64, or ARM64 systems and displays this information in its "About" screen (AboutrEFInd() in main.c). I'd like to add detection for Itanium and 32-bit ARM systems, but I have no way to test such changes.
    • Further to the preceding, rEFInd's GPT-scanning code (used to extract partition names) includes assumptions about byte order, and so will work only on little-endian CPUs such as the x86 and x86-64.
    • A way to set the color of the font would be useful for theming purposes.
    • The program's font features could be greatly improved by enabling use of a standard font format, by enabling use of non-ASCII characters, and by enabling use of variable-width as well as monospace fonts.
    • The default_selection might be expanded to support some form of specification of disk types, as in a special entry for any optical disk or any external disk, no matter what its name is.
    • It would be useful to be able to specify paths to boot loaders and/or initial RAM disks relative to the rEFInd directory (or the boot loader's directory, in the case of initrds).
    • Currently the background for certain subscreens (such as the information page or submenu listings) is a solid color based on the upper-left corner of the screen. Having an option to support a transparent background is desirable to some users.
    • When delivering rEFInd as a boot loader from a network server, rEFInd is limited to its default options and can boot only local OSes, not network OSes. The cause is that the server delivers a single file, so rEFInd is divorced from its configuration and support files.
    • A way to identify specific Windows versions and present unique icons or change the text is desirable. Currently, a crude distinction of XP and earlier vs. Vista and later is possible for BIOS-booting on Macs, but no such distinction is made for EFI-mode booting, and nothing finer-grained is attempted. Improvements will probably require identifying unique features of each version's boot loader files or boot sector code.
    • The support for booting legacy (BIOS) OSes on UEFI-based PCs currently has a number of limitations. Most importantly, it works off of the list of boot devices stored in the computer's NVRAM. I'd prefer to have it scan disks and partitions, as the Mac's legacy boot support does. Also, the UEFI legacy boot code presents empty optical drives and uses generic icons rather than OS-specific icons. This said, BIOS support is becoming increasingly unimportant as the transition from BIOS to EFI continues, so I'm unlikely to put effort into this issue myself.
  • Known bugs that need squashing:
    • I've been receiving reports of blank screens when using rEFInd on some recent Mac models. I've investigated this with the help of one user, and I suspect that Apple has made changes to its firmware that are likely to affect just about any EFI program. I don't have a definitive solution, but at least one user has reported that removing rEFInd's drivers has caused the problem to go into remission. Changes made in version 0.11.0 improve error reporting on Macs, which may help with this issue.
    • Another Mac-specific display problem relates to "retina" displays: Some users report that rEFInd comes up in a lower resolution than the screen supports, and that this setting persists into the running OS X instance, and can't be adjusted using the usual OS X means. I've just recently (mid-2017) purchased an iMac with a "retina" display, so I can now begin to investigate this problem, but as of rEFInd 0.11.0, I haven't yet had a chance to look into it in depth. I've heard that this problem affects not just rEFInd, but also GRUB, and even Windows when dual-booting on a Mac; see this YouTube video and This AskUbuntu question and answers, for instance.
    • Some EFIs have bugs that cause the allegedly case-insensitive StriCmp() function to perform a case-sensitive comparison. This causes any number of bugs in file matching. For instance: Changing the case of icon filename extensions (or various other parts of icon filenames) causes icons to be replaced by ugly "generic" ones; and rEFInd sometimes appears in its own menu (the firmware sometimes returns an all-caps version of the filename, but other times returns the filename with the correct case, causing a mismatch if the path includes lowercase elements). This problem is worse when compiling rEFInd with GNU-EFI than with Tianocore. Version 0.9.1 has made improvements on this score, but some issues may continue to lurk.
    • The Shutdown option works correctly on Macs, but not on many UEFI-based PCs. On such systems, Shutdown reboots the computer. This should be fixed.
    • The media-ejection feature (F12) should be extended to work on UEFI-based PCs and early Macs. At the moment, it relies on an Apple-specific EFI extension, and I know of no standard EFI way to do it.
    • A couple of Mac users have reported that the brightness-adjustment features in Windows don't work when Windows is booted via rEFInd, but that these features do work when Windows is booted via the Mac's built-in boot manager. Unfortunately, I have no idea what causes this problem, I have no Windows installation on my Macs, and I have no way to debug it. Therefore, it's unlikely that I'll be able to fix this problem myself; but if you have the equipment and skill to do so, I'd be interested in receiving a patch.
    • If you use a true MBR disk on a Mac to boot Windows or some other BIOS-only OS, and if that disk has an extended partition, bogus additional BIOS/legacy-bootable options may appear in the rEFInd menu. The reason appears to be a bug in the handling of extended/logical partitions in the refind/lib.c file, but I haven't fully tracked it down.
    • The re-scan feature occasionally produces odd results, such as ignoring new media or keeping old media that have been ejected. This should be investigated and fixed.
    • The "scanning for boot loaders" message that appears at startup and during the re-scan feature is primitive. Some sort of dynamic icon would be nice, but perhaps impractical, given the single-tasking nature of EFI.
    • On my Mac Mini, launching a shell, returning, and performing a re-scan causes the system to be unable to launch the shell again. I have not observed this behavior on UEFI-based PCs. It seems to be caused by a truncated DevicePath to the shell, which includes the shell's pathname but not the device identifier.
    • When specifying a volume by name in dont_scan_dirs, slashes are converted to backslashes in the specification but not in the actual volume name read from disk. Thus, you can't specify a volume by name if it includes a slash (as in Fedora /boot). Workarounds are to rename the volume to omit the slash and to use a partition GUID rather than a volume label.
    • The code is in need of review to search for memory leaks and similar problems.
    • If the user has a Linux software RAID 1 array with Btrfs, HFS+, or FAT filesystem, rEFInd will detect kernels or boot loaders in RAID 1 twice. Checks to prevent this with ext2/3/4fs and ReiserFS already exist; these checks could be expanded to block such duplication with more filesystems. Using the in-rEFInd hiding feature (activated by the Delete or minus [-] key) can remove a redundant entry.
    • Some Macs experience problems with waking up from suspend states when rEFInd is installed. Using pmset to disable the autopoweroff option is claimed by some to at least partially fix the problem, though. Using the --ownhfs installation option may also help in some cases.
    • If you activate BIOS-mode support on UEFI-based PCs, you may find multiple copies of the BIOS-mode loaders added to your firmware's boot manager. Only one copy shows up in rEFInd, though.
    • If you have a manual boot stanza for a Linux kernel with both an initrd line and a second initrd file specified on the options line, both initrd files will be passed to the kernel in most situations; however, one will be omitted if you enter the submenu (via F2, Insert, or Tab) and select the default entry there. This bug is caused by the convoluted way rEFInd generates its submenus, and I'm putting off fixing it until I can give that code the overhaul it desperately needs.
  • New features I'd like to add:
    • Currently, debugging rEFInd requires adding Print() statements to the code. Adding a logging facility that supports multiple log levels and writes the output to a file would help with debugging, especially when dealing with problem reports from users.
    • I'd like to find a way to enable users to enter customizations for boot options and then save them to the refind.conf file. One possible way to implement this would be to have manual boot stanzas override auto-detected boot loader definitions for the same boot loader file.
    • Along similar lines, some users have asked for a way to take detected boot programs and create a set of manual boot stanzas for them, so that they can be modified manually.
    • Better support for touchscreens and/or configurable buttons for rEFInd's actions would enable use of rEFInd on tablet computers that lack complete keyboards. (Version 0.10.4 supports some touchscreens, but this feature relies on support in the firmware, which is not universally present.)
    • The ability to rotate the display for users who rotate their monitors or who use tablets would be helpful.
    • GRUB provides a configuration-file command called outb that enables manipulating hardware registers. Something similar, via the mm command, can be done in the EFI shell. I'd like to add such a feature to rEFInd, since it enables doing things like disabling one or another video output on Macs with two video cards.
    • I have thoughts about creating an EFI configuration tool and information utility—something to tell you about your hard disks, enable you to manage MOKs, adjust boot loader priority in the NVRAM, and so on. This would be useful in system maintenance and in recovering from boot problems.
    • An installation tool for the EFI environment would be useful. A simple EFI shell script might work, but because this function requires access to the bcfg command, this would work only from a version 2 shell or if bcfg were implemented as a standalone program. Another alternative would be a program written in C. Since Python is now available in EFI, a Python-based script might also work; but that would require installing Python.
    • It should be possible to override specific auto-detected boot loader settings—say, to change the icon for one specific boot loader.
    • A GUI configuration tool for host OSes (Linux, OS X, Windows, etc.) would be nice, but it's low on my personal priority list. If you'd like to contribute, I prefer something written in a cross-platform GUI toolkit, so that a single code base can be used on any of the major OSes.
    • The ability to produce audio output (at least a simple "beep") to signal to visually impaired users when rEFInd is ready to accept input would be helpful.
    • There's currently no way to create a manual boot stanza for a BIOS-booted OS. This isn't a big priority for me personally, but I can see how it could be for some people.
  • Improvements to the EFI drivers:
    • Drivers for additional filesystems are desirable. Only XFS and JFS are missing from the major Linux filesystems. UDF would also be a welcome addition, as might drivers for other OSes (say, for the BSDs, especially if BSD developers create a boot loader similar to Linux's EFI stub loader). Also along these lines, adding drivers for Linux LVM and RAID setups would be useful.
    • This may not be possible, or it may require a new driver, but a way to have the drivers access files (like a Linux loopback mount) is desirable.
    • When built with the GNU-EFI package, an attempt to load more than one driver on my 32-bit Mac Mini causes the computer to hang. I do not have this problem with 64-bit drivers on my UEFI-based computers. I don't know if this is a 32-bit issue or a Mac issue. This is not relevant if you're using my binary package, since I build it with the TianoCore EDK2, and the drivers built in that way don't exhibit this bug.
  • Improvements to gptsync, refind-install, or other support tools:
    • The gptsync program can return misleading error codes under some circumstances, such as when it makes no changes to the partition table. Fix this.
    • rEFInd's support for network booting is primitive and relies on the external iPXE package. In my own testing, iPXE retrieves the BIOS-mode boot loader from some servers that offer both, which makes it useless on those networks.
    • The handling of encrypted local Secure Boot keys by refind-install could be improved. Specifically, if you install without encrypted keys and then run refind-install with --encryptkeys, or vice-versa, the script is likely to ask for keys repeatedly. Error handling (if an incorrect key is entered, for instance) is also poor. If an encrypted key is used and a rEFInd RPM or Debian package is installed, that installation may fail to set things up correctly.
    • A Mac-specific package is highly desirable.

copyright © 2012–2018 by Roderick W. Smith

This document is licensed under the terms of the GNU Free Documentation License (FDL), version 1.3.

If you have problems with or comments about this Web page, please e-mail me at rodsmith@rodsbooks.com. Thanks.

Go to the main rEFInd page

Learn about problems with and the future of rEFInd

Return to my main Web page.

refind-0.11.4/docs/refind/yosemite.html0000664000175000017500000002707013372346574020261 0ustar rodsmithrodsmith The rEFInd Boot Manager: rEFInd and Yosemite

The rEFInd Boot Manager:
rEFInd and Yosemite

by Roderick W. Smith, rodsmith@rodsbooks.com

Originally written: 10/20/2014; last Web page update: 12/8/2014, referencing rEFInd 0.8.4

This Web page is provided free of charge and with no annoying outside ads; however, I did take time to prepare it, and Web hosting does cost money. If you find this Web page useful, please consider making a small donation to help keep this site up and running. Thanks!

Donate $1.00 Donate $2.50 Donate $5.00 Donate $10.00 Donate $20.00 Donate another value

This page is largely obsolete, as of rEFInd 0.8.4. This version of rEFInd makes changes to both its install.sh script and default options to make rEFInd better able to cope with OS X 10.10 without the changes to procedure described herein. I'm leaving this page in place for the benefit of those who might be running earlier versions of rEFInd with Yosemite, as well as for general educational purposes. Most readers can skip it.


This page is part of the documentation for the rEFInd boot manager. If a Web search has brought you here, you may want to start at the main page.


Recently, Apple released OS X 10.10 (aka Yosemite), and I've been getting e-mails with problem reports. Unfortunately, my only Mac is an ancient 32-bit model that can't run the latest version, so I can't investigate the cause of the problems myself; however, I think I understand most of what's going on. There are two main problems.

First, Yosemite now uses a type of logical volume management (LVM). The EFI built into the computer can't read from LVM, so an installation of rEFInd on the OS X root (/) partition, which is the default when you install rEFInd 0.8.3 and earlier using install.sh, is rendered useless.

Second, Apple seems to be placing its standard boot loader for this type of configuration on the Recovery HD volume, which had previously been used for (as the name suggests) recovery tools (and also for the regular boot loader when the main partition was encrypted). Because I'd gotten many complaints about the recovery system showing up in the main menu list, I coded rEFInd to ignore the contents of this volume by default. Thus, fixing the first problem results in rEFInd working but not detecting the Yosemite installation. Thanks, Apple, for making it to distinguish between your recovery boot loader and your regular boot loader!

Version 0.8.4 of rEFInd changes both install.sh and the rEFInd defaults to bypass these problems. Thus, rEFInd 0.8.4 should work fine when installed from OS X 10.10 using install.sh and its default options. If you continue to have problems or if you want to use Yosemite with an earlier version of rEFInd, you can fix the problems manually:

  1. Boot to OS X, using whatever means are available to you. Holding Option (or Alt) while powering up will normally give you Apple's own boot manager, which should enable you to boot to OS X. If your rEFInd installation is currently starting but is not showing an OS X option, skip to step #7; but if rEFInd isn't starting, follow steps #2–7.
  2. If you've made changes to /EFI/refind/refind.conf, back it up.
  3. Remove the /EFI/refind directory tree; it's useless now, and its presence may cause confusion.
  4. Re-install rEFInd, as described in the Installing rEFInd page; but if you install version 0.8.3 or earlier, be sure to use the --esp or --ownhfs device-file option. The latter is preferable, but requires either a dedicated partition for rEFInd or an HFS+ data partition that is currently not bootable. If you install rEFInd 0.8.4 or later, there's no need to specify --esp (as that is effectively now the default). You may use --ownhfs device-file, if you like.
  5. Ensure that the partition to which you've installed rEFInd is mounted. The details depend on how you installed it:
    • If you installed rEFInd to your ESP, typing mkdir /Volumes/esp followed by sudo mount -t msdos /dev/disk0s1 /Volumes/esp will probably work, although in some cases your ESP won't be /dev/disk0s1, so you may need to change this detail.
    • If you used the --ownhfs device-file installation option, the target partition should already be mounted, normally somewhere under /Volume. If not, locate it and mount it with Disk Utility or mount.
  6. If you backed up your refind.conf file, you can copy it over your new refind.conf file. You should copy the file to either /Volumes/esp/EFI/refind/ (if you mounted the ESP at /Volumes/esp and installed there) or to /Volumes/Mountpoint/System/Library/CoreServices/ (if you used a dedicated HFS+ volume; note that Mountpoint will be the name of the volume).
  7. Edit your new refind.conf file, which should be located as described in the previous step. In your favorite editor, locate the dont_scan_volumes line, which is commented out with a # symbol at the start of the line by default. Uncomment this line and remove the "Recovery HD" item from the line. Some users report that they need to enter one or two dummy entries, as in dont_scan_volumes foo,bar, to get it to work.

With these changes made, you should be able to reboot into rEFInd and see entries for both OS X and whatever other OSes you've installed. It's possible that you'll see two entries for OS X, though, one of which will boot to a recovery system and one of which will boot to the regular installation. If you can identify a difference in their descriptions, you may be able to use the dont_scan_volumes, dont_scan_dirs, or dont_scan_files options in refind.conf to remove the recovery option from the main list. (You should still see a recovery entry as a second-line option.)

An entirely different approach to fixing this problem is to force Yosemite to install without using LVM. I don't have a specific procedure for doing this, though; you should do a Web search or ask on a Mac-specific Web forum.


copyright © 2014 by Roderick W. Smith

This document is licensed under the terms of the GNU Free Documentation License (FDL), version 1.3.

If you have problems with or comments about this Web page, please e-mail me at rodsmith@rodsbooks.com. Thanks.

Go to the main rEFInd page

rEFInd and System Integrity Protection

Return to my main Web page.

refind-0.11.4/docs/refind/configfile.html0000664000175000017500000023660213372346574020533 0ustar rodsmithrodsmith The rEFInd Boot Manager: Configuring the Boot Manager

The rEFInd Boot Manager:
Configuring the Boot Manager

by Roderick W. Smith, rodsmith@rodsbooks.com

Originally written: 3/14/2012; last Web page update: 11/12/2018, referencing rEFInd 0.11.4

This Web page is provided free of charge and with no annoying outside ads; however, I did take time to prepare it, and Web hosting does cost money. If you find this Web page useful, please consider making a small donation to help keep this site up and running. Thanks!

Donate $1.00 Donate $2.50 Donate $5.00 Donate $10.00 Donate $20.00 Donate another value

This page is part of the documentation for the rEFInd boot manager. If a Web search has brought you here, you may want to start at the main page.


Many casual users will be able to use rEFInd without making changes to its settings; in its default configuration, the boot manager automatically detects all the EFI boot loader programs you have on your EFI System Partition (ESP) (or your OS X boot partition, in the case of Macs) in conventional locations and displays icons for them. On Macs, rEFInd also presents legacy BIOS boot options by default. Sometimes, though, you may want to tweak rEFInd's configuration. Sometimes you can obtain your desired results by adjusting the filenames of your boot loaders. Other times, you can edit rEFInd's configuration file, refind.conf, which resides in the same directory as its binary file (refind_x64.efi or whatever you've renamed it).

Broadly speaking, rEFInd's configuration file is broken down into two sections: global options and OS stanzas. The global options section sets options that apply globally—to set the timeout period, enable graphics or text mode, and so on. OS stanzas are optional, but if present, they enable you to add new boot options or replace the auto-detected options with customized ones. Both sections include configuration lines and comment lines, the latter being denoted by a leading hash mark (#). rEFInd ignores comment lines, so you can add explanatory text. The default configuration file includes numerous comments explaining each of the options.

Hiding and Displaying EFI Boot Loaders

A common complaint among rEFInd users is that rEFInd displays too many boot options. This problem is getting worse as OS vendors deliver more and more tools in the form of EFI programs installed on the ESP. It's difficult for me to keep up with this flood, and what one person considers a necessary program another may consider pointless clutter, making it hard to set useful defaults. Fortunately, rEFInd provides several ways to hide OSes—or to make them appear, if they don't by default. Methods to do this include:

  • Hiding entries dynamically—rEFInd 0.11.0 introduced a dynamic tag hiding feature. To use it, highlight a tag and hit the Delete (on PCs) or minus (-) key. (The Delete key on Macs is the Backspace key on PCs, and will not work for this; however, some Mac keyboards have a key marked Del that will do the job.) rEFInd will ask for confirmation. If you give it, the OS or external tool tag will disappear, and should remain hidden indefinitely. (Note that you cannot hide built-in tools, such as the About/Info display and the reboot-to-firmware option, in this way.) rEFInd stores the list of EFI OS tags so hidden in NVRAM or on disk (as determined by the use_nvram token in refind.conf) using the HiddenTags variable, BIOS/CSM/legacy OS tags as HiddenLegacy, and tool tags as HiddenTools. If you want to recover a tag you've hidden, you can do so by using the hidden tag maintenance function, which appears on the second row of the rEFInd menu as a recycling symbol. You can disable both the ability to hide tags and to recover them by uncommenting the scanfor item in refind.conf and ensuring that hidden_tags is not among the options. (Even if you disable this feature, rEFInd continues to honor tags it finds in NVRAM or on disk.)
  • Move, deleting, or renaming files—By default, rEFInd scans all the filesystems it can read for boot loaders. It scans most of the subdirectories of the EFI directory on every filesystem it can access for files with names that end in .efi. (rEFInd gives special treatment to the tools subdirectory, where it looks for system tools rather than boot loaders.) Thus, you can delete EFI program files, move them out of the directory tree that rEFInd scans, or rename them so that they don't have .efi extensions. Note that rEFInd does not scan its own directory or the EFI/tools directory, so those can be good places to stash seldom-used EFI binaries.
  • dont_scan_volumes—This token in refind.conf specifies volumes that rEFInd will not scan. For EFI boot loaders, you can identify a volume by its filesystem label, partition name, or partition unique GUID value. On Macs, you can identify BIOS/CSM/legacy-mode OSes to hide by specifying any unique subset of the OS tag description shown in the rEFInd main menu. In either case, this token takes a comma-delimited list, as in dont_scan_volumes ESP7,BadVolume to blacklist the ESP7 and BadVolume partitions. This token cannot be used to hide BIOS/CSM/legacy-mode loaders on UEFI-based PCs.
  • dont_scan_dirs—This token provides finer-grained control than the preceding one; you identify directories with this option. For instance, you might specify dont_scan_dirs EFI/ignore,BigDisk:/EFI/OldOS to ignore the EFI/ignore directory on all volumes and the EFI/OldOS directory on the BigDisk volume. This token cannot be used to hide BIOS/CSM/legacy-mode loaders.
  • dont_scan_files—You can hide individual files with this token. Files can be specified alone, with a leading directory path, or with a leading directory path and volume name or GUID. For instance, dont_scan_files badloader.efi,EFI/ignoreme/boring.efi,MyDisk:/EFI/someos/grubx64.efi causes badloader.efi to be ignored in any location, EFI/ignoreme/boring.efi to be ignored on any disk, and EFI/someos/grubx64.efi to be ignored only on MyDisk. As with the previous items, you can identify a disk by filesystem label, partition name, or partition unique GUID.
  • also_scan_dirs—This token does the opposite of the preceding ones: It adds a directory to the scan list, so that rEFInd can locate boot loaders stored in unusual locations. This token takes a directory path, and optionally a name (filesystem or partition), but cannot currently take a GUID value as a volume identifier.
  • scanfor—This token identifies the types of OSes for which rEFInd scans, and the types of devices on which it scans. On Macs, BIOS/CSM/legacy-mode scans are enabled by default; but you may want to disable this support by uncommenting the scanfor line and ensuring the hdbios, biosexternal, and cd are not present. These options are disabled by default on UEFI-based PCs, so if you want to boot BIOS-mode OSes, you must uncomment scanfor and add an appropriate option.

Setting OS Icons

In addition to hiding boot loaders, you can adjust their icons. You can do this in any of seven ways for auto-detected boot loaders:

  • You can name an icon file after your boot loader, but with an extension of .icns, .png, .bmp, .jpg, or .jpeg depending on the icon's format. For instance, if you're using loader.efi, you might name the icon file loader.png. (If you use the scan_all_linux_kernels option, you can give an icon for a Linux kernel without a .efi extension a name based on the kernel name but with an appropriate extension—for instance, bzImage-3.13.6.png will serve as the icon for the bzImage-3.13.6 kernel.)
  • If you're booting OS X from its standard boot loader, or if you place a boot loader file for any OS in the root directory of a partition, you can create a file called .VolumeIcon.icns, .VolumeIcon.png, .VolumeIcon.bmp, .VolumeIcon.jpg, or .VolumeIcon.jpeg that holds an icon file. OS X uses the .VolumeIcon.icns file for its volume icons, so rEFInd picks up these icons automatically, provided they include appropriate bitmaps.
  • You can place a boot loader in a directory with a name that matches one of rEFInd's standard icons, which take names of the form os_name.icns or os_name.png. To use such an icon, you would place the boot loader in the directory called name.
  • You can give the filesystem from which the boot loader is loaded a name that matches the OS name component of the icon filename. For instance, if you call your boot filesystem CentOS, it matches the os_centos.png icon. This match is performed on a word-by-word basis within the name, with "words" being delimited by spaces, dashes (-), and underscores (_). Thus, a volume called Debian-boot will match os_debian.png or os_boot.png.
  • You can give the GPT partition from which the boot loader is loaded a name that matches the OS name component of the icon filename. This works much like the previous method, except that you'd use a tool like gdisk or parted to set the partition's name, rather than tune2fs or GParted to set the filesystem's name. Note that rEFInd ignores some common default partition names (namely Microsoft basic data, Linux filesystem, and Apple HFS/HFS+) when implementing this rule, since other rules are likely to produce more accurate results.
  • rEFInd attempts to guess the Linux distribution based on data in the /etc/os-release file. This file will only be accessible if a separate /boot partition is not used, though. Manually adjusting the os-release file to change an OS icon in rEFInd is not recommended.
  • Certain boot loaders have hard-coded icons associated with them. For instance, filenames beginning with vmlinuz or bzImage acquire Linux "Tux" icon and the bootmgfw.efi loader acquires a Windows icon. Fedora and Red Hat kernels can be identified by the presence of .fc or .el strings in their filenames, and so acquire suitable icons automatically. For the most part, these are the associations you want to overcome with the preceding rules, but sometimes renaming a boot loader to a more conventional name is the better approach. Renaming a locally-compiled kernel so that it acquires a Fedora or Red Hat icon is reasonable, but I don't recommend renaming precompiled kernels unless you also manually copy them to the ESP.

As a special case, rEFInd assigns icons to the Windows and OS X boot loaders based on their conventional locations, so they get suitable icons even if they don't follow these rules.

These icon files should be in Apple's ICNS format, Portable Network Graphics (PNG) format, bitmap image file (BMP) format, or Joint Photographic Experts Group (JPEG) format, depending on the filename extension. As a general rule, PNG and ICNS files work best for icons, because they both support transparency, which is highly desirable in rEFInd icons, especially when the icon is shown against a full-screen banner. ICNS is an Apple-specific format, whereas PNG is cross-platform. BMP and JPEG files may be used as icons, but rEFInd does not support transparency with these formats. rEFInd relies on the LodePNG and NanoJPEG libraries for PNG and JPEG support, respectively. These libraries have certain limitations; for instance, NanoJPEG, and therefore rEFInd, does not support progressive JPEGs. If you have problems with a specific icon or banner image, check the libraries' pages and re-save or convert the image into a more generic form, or even to a different format.

In addition to the main OS tag icon, you can set the badge icon for a volume by creating a file called .VolumeBadge.icns, .VolumeBadge.png, .VolumeBadge.bmp, .VolumeBadge.jpg, or .VolumeBadge.jpeg in the root directory of a partition. If present, it replaces the disk-type icons that are overlaid on the main OS icon. If you use this feature, the badge is applied to all the boot loaders read from the disk, not just those stored in the root directory or the Apple boot loader location. You could use this feature to set a custom badge for different specific disks or to help differentiate multiple macOS installations on one computer. If you don't want any badges, you can add the badges option to hideui in refind.conf. Alternatively, or to hide just certain types of badges, you can replace the four badge icons in the rEFInd icons subdirectory (vol_external.png, vol_internal.png, vol_optical.png, and vol_net.png) with a completely transparent badge. The transparent.png file in the rEFInd icons directory may be used for this purpose.

The default icon sizes are 128x128 pixels for OS icons, 48x48 pixels for the second-row tools, and 32x32 pixels for badges. (These figures are all doubled on displays wider than 1920 pixels.) You can change the sizes of the big OS icons and the small tool icons with the big_icon_size and small_icon_size tokens in refind.conf, as noted in Table 1. The size of the disk-type badges is 1/4 the size of OS icons.

Adjusting the Global Configuration

You can adjust many of rEFInd's options by editing its configuration file, which is called refind.conf. You must first find this file, though. It is located in the rEFInd directory. On a UEFI-based PC, this directory will be located on the EFI System Partition (ESP), which can be in any number of places:

  • Under Linux, the ESP is usually mounted at /boot/efi, although some users, particularly in Arch and Gentoo, prefer to mount the ESP at /boot.
  • Under OS X, the ESP is not mounted by default, so you must mount it yourself to access it. Since 0.9.3, rEFInd has provided a script called mountesp, which locates and mounts the ESP. Open a Terminal and type sudo mountesp to mount the ESP. The program should tell you where it's mounted the ESP. It will remain mounted until you manually unmount it or until you reboot.
  • Under Windows, the ESP is not mounted by default. You can do so manually by opening an Administrator Command Prompt window and typing mountvol S: /S to mount it at S:. (You can change the drive letter if you like.) Note that you will be able to access the ESP only from this Administrator Command Prompt window.

As a further twist, on Macs rEFInd can exist on its own partition or on the main OS X partition, depending on the version of rEFInd you've installed and the options you passed to the installation script. rEFInd has installed to the ESP by default since version 0.8.4. rEFInd typically lives on the ESP in the EFI/refind directory, or sometimes in EFI/BOOT or elsewhere. Thus, the rEFInd configuration file might be /boot/efi/EFI/refind/refind.conf, /boot/EFI/BOOT/refind.conf, /Volumes/ESP/EFI/refind/refind.conf, S:\EFI\refind\refind.conf, or something else, depending on your OS and mount point.

You can use any text editor you like to edit refind.conf, but be sure it saves the file in plain ASCII text, not in a word processing format. (In theory, a UTF-16 encoding should also work, but this has been poorly tested.) Note that the EFI shell includes its own editor. If you need to make a change before you launch an OS, you can launch a shell, change to the rEFInd directory, and type edit refind.conf to edit the file. This EFI editor is quite primitive, but it gets the job done. After editing, you'll need to reboot or re-launch rEFInd for rEFInd to read the changed configuration file.

Global configuration file options consist of a name token followed by one or more parameters, as in:

timeout 20

This example's name token is timeout and its parameter is 20. The net effect of this line is to set the timeout period to 20 seconds—rEFInd will wait 20 seconds before launching the default boot loader. Some options can take multiple parameters. These may be separated by commas, spaces, or tabs. The global options are summarized in the Table 1.

Table 1: Global options in refind.conf
Token Possible parameters Explanation
timeout numeric value Sets the timeout period in seconds. If 0, the timeout is disabled—rEFInd waits indefinitely for user input. If -1, rEFInd will normally boot immediately to the default selection; however, if a shortcut key (for instance, W for Windows) is pressed, that system will boot instead. If any other key is pressed, the menu will show with no timeout.
shutdown_after_timeout none or one of true, on, 1, false, off, or 0 If set to false or one of its synonyms (the default), rEFInd boots the option set via default_selection when the timeout period is reached. When set to true or one of its synonyms, rEFInd attempts to shut down the computer when the timeout period is reached. Many EFIs lack software shutdown support. On them, setting this option to true will cause a reboot or a hang once the timeout value is reached!
use_nvram none or one of true, on, 1, false, off, or 0 If set to true, on, or 1 (the default), stores rEFInd-specific variables in NVRAM. If set to false, off, or 0, stores these variables in the vars subdirectory of rEFInd's home directory, if possible. (Read-only filesystems obviously make this option impossible.) Using NVRAM ties rEFInd's variables to a specific computer and increases wear on the NVRAM, whereas storing them on disk makes the variables move with rEFInd (which is potentially useful on an installation on a removable disk).
screensaver numeric value Sets the number of seconds of inactivity before the screen blanks to prevent burn-in. The display returns after most keypresses (unfortunately, not including modifiers such as Shift, Control, Alt, or Option). The default is 0, which disables this feature. Setting this token to -1 causes a blank display until the timeout value passes or you press a key.
hideui banner, label, singleuser, safemode, hwtest, arrows, hints, editor, badges, or all Removes the specified user interface features. banner removes the banner graphic or background image, label removes the text description of each tag and the countdown timer, singleuser removes the single-user option from the OS X sub-menu, safemode removes the option to boot to safe mode from the OS X sub-menu, hwtest removes the Macintosh hardware test option, arrows removes the arrows to the right or left of the OS tags when rEFInd finds too many OSes to display simultaneously, hints removes the brief description of what basic keypresses do, editor disables the options editor, badges removes the device-type badges from the OS tags, and all removes all of these features. You can specify multiple parameters with this option. The default is to set none of these values.
icons_dir directory name Specifies a directory in which custom icons may be found. This directory should contain files with the same names as the files in the standard icons directory. The directory name is specified relative to the directory in which the rEFInd binary resides. The standard icons directory is searched if an icon can't be found in the one specified by icons_dir, so you can use this location to redefine just some icons. Preferred icon file formats are PNG (*.png) and ICNS (*.icns), because both these formats support transparency. You can use BMP (*.bmp) and JPEG (*.jpg or *.jpeg), but rEFInd does not support transparency with these formats, which is highly desirable in icons. Note that if no icons directory is found (either icons or one specified by icons_dir), rEFInd switches to text-only mode, as if textonly had been specified.
banner filename Specifies a custom banner file to replace the rEFInd banner image. The file should be an ICNS, BMP, PNG, or JPEG image with a color depth of 24, 8, 4, or 1 bits. The file path is relative to the directory where the rEFInd binary is stored. Note that some image features, such as JPEG's progressive encoding scheme, are not supported. See the comments on LodePNG and NanoJPEG earlier, in Setting OS Icons.
banner_scale noscale or fillscreen Tells rEFInd whether to display banner images pixel-for-pixel (noscale) or to scale banner images to fill the screen (fillscreen). The former is the default.
big_icon_size numeric value (at least 32) Sets the size of big icons (those used for OSes on the first row). All icons are square, so only one value is specified. If icon files don't contain images of the specified size, the available images are scaled to this size. The disk-type badge size is set indirectly by this token; badges are 1/4 the size of big icons. The default value is 128 on most systems, or 256 when the screen is wider than 1920 pixels.
small_icon_size numeric value (at least 32) Sets the size of small icons (those used for tools on the second row). All icons are square, so only one value is specified. If icon files don't contain images of the specified size, the available images are scaled to this size. The default value is 48 on most systems, or 96 when the screen is wider than 1920 pixels.
selection_big filename Specifies a graphics file that can be used to highlight the OS selection icons. This should be a 144x144 image in BMP, PNG, ICNS, or JPEG format, stored in rEFInd's main directory. (Images larger or smaller than 144x144 will be scaled, but the results may be ugly.)
selection_small filename Like selection_big, this sets an alternate highlight graphic, but for the smaller utility tags on the second row. This should be a 64x64 image in BMP, PNG, ICNS, or JPEG format, stored in rEFInd's main directory. (Images larger or smaller than 64x64 will be scaled, but the results may be ugly.)
showtools shell, memtest, gdisk, gptsync, apple_recovery, csr_rotate, mok_tool, fwupdate, netboot, about, hidden_tags, exit, shutdown, reboot, and firmware Specifies which tool tags to display on the second row. shell launches an EFI shell, memtest (or memtest86) launches the Memtest86 program, gdisk launches the partitioning tool of the same name, gptsync launches a tool that creates a hybrid MBR, apple_recovery boots the OS X Recovery HD, csr_rotate rotates through System Integrity Protection (SIP) values specified by csr_values, windows_recovery boots a Windows recovery tool, mok_tool launches a tool to manage Machine Owner Keys (MOKs) on systems with Secure Boot active, fwupdate launches a firmware-update tool, netboot launches the network boot tool (iPXE), about displays information about rEFInd, hidden_tags enables you to recover tags you've hidden exit terminates rEFInd, shutdown shuts down the computer (or reboots it, on some UEFI PCs), reboot reboots the computer, and firmware reboots the computer into the computer's own setup utility. The tags appear in the order in which you specify them. The default is shell, memtest, gdisk, apple_recovery, mok_tool, about, shutdown, reboot, firmware. Note that the shell, memtest, apple_recovery, and mok_tool options all require the presence of programs not included with rEFInd. The gptsync option requires use of a like-named program which, although it ships with rEFInd 0.6.9 and later, is not installed by default except under OS X. See the "Installing Additional Components" section of the Installing rEFInd page for pointers to the shell, Memtest86, and gptsync programs. The apple_recovery option will appear only if you've got an Apple Recovery HD partition (which has a boot loader called com.apple.recovery.boot/boot.efi). The firmware option works only on computers that support this option; on other computers, the option is quietly ignored. See the Secure Boot page for information on Secure Boot and MOK management.
font font (PNG) filename You can change the font that rEFInd uses in graphics mode by specifying the font file with this token. The font file should exist in rEFInd's main directory and must be a PNG-format graphics file holding glyphs for all the characters between ASCII 32 (space) through 126 (tilde, ~), plus a glyph used for all characters outside of this range. See the Theming rEFInd page for more details.
textonly none or one of true, on, 1, false, off, or 0 rEFInd defaults to a graphical mode; however, if you prefer to do without the flashy graphics, you can run it in text mode by including this option (alone or with true, on, or 1). Passing false, off, or 0 causes graphics mode to be used. (This could be useful if you want to override a text-mode setting in an included secondary configuration file.) Text-only mode is implicitly set if rEFInd cannot find either a subdirectory called icons or a subdirectory named by icons_dir.
textmode text mode number Sets the text-mode video resolution to be used in conjunction with textonly or for the line editor and program-launch screens. This option takes a single-digit code. Mode 0 is guaranteed to be present and should be 80x25. Mode 1 is supposed to be either invalid or 80x50, but some systems use this number for something else. Higher values are system-specific. Mode 1024 is a rEFInd-specific code that means to not set any mode at all; rEFInd instead uses whatever mode was set when it launched. If you set this option to an invalid value, rEFInd pauses during startup to tell you of that fact. Note that setting textmode can sometimes force your graphics-mode resolution to a higher value than you specify in resolution. On Linux, the /sys/class/graphics/fb0/modes file holds available modes, but it may not be the same set of modes that EFI provides.
resolution one or two integer values Sets the video resolution used by rEFInd; takes either a width and a height or a single UEFI video mode number as options. For instance, resolution 1024 768 sets the resolution to 1024x768. On UEFI systems, resolution 1 sets video mode 1, the resolution of which varies from system to system. If you set a resolution that doesn't work on a UEFI-based system, rEFInd displays a message along with a list of valid modes. On an system built around EFI 1.x (such as a Mac), setting an incorrect resolution fails silently; you'll get the system's default resolution. You'll also get the system's default resolution if you set both resolution values to 0 or if you pass anything but two numbers. (Note that passing a resolution with an x, as in 1024x768, will be interpreted as one option and so will cause the default resolution to be used.) If you get a higher resolution than you request, try commenting out or changing the textmode value, since it can force the system to use a higher graphics resolution than you specify with resolution. Also, be aware that it is possible to set a valid resolution for your video card that's invalid for your monitor. If you do this, your monitor will go blank until you've booted an OS that resets the video mode.
enable_touch none or one of true, on, 1, false, off, or 0 Enables support for touch screens (as on tablets). Note that not all tablets provide the necessary support. If this feature is enabled and the tablet supports it, touching an OS or tool should launch it or enter a submenu. In a submenu, it is currently not possible to select a specific item; any touch will launch the default submenu option. This option is incompatible with enable_mouse. If both are specified, the one appearing later in refind.conf takes precedence. The default is off.
enable_mouse none or one of true, on, 1, false, off, or 0 Enables support for mice (and related pointing devices). Note that not all tablets provide the necessary support. If this feature is enabled and the computer supports it, clicking an OS or tool should launch it or enter a submenu. In a submenu, it is currently not possible to select a specific item; any click will launch the default submenu option. This option is incompatible with enable_touch. If both are specified, the one appearing later in refind.conf takes precedence. The default is off.
mouse_size numeric value Sets the size of the mouse pointer, in pixels squared. The default is 16.
mouse_speed numeric value Sets the speed of the mouse pointer, with higher numbers meaning faster tracking. The default is 1.
use_graphics_for osx, linux, elilo, grub, and windows Ordinarily, rEFInd clears the screen and displays basic boot information when launching any OS but Mac OS X. For OS X, the default behavior is to clear the screen to the default background color and display no information. You can specify the simpler Mac-style behavior by specifying the OSes or boot loaders you want to work this way with this option. (OSes that should use text-mode displays should be omitted from this list.) Note that this option doesn't affect what the boot loader does; it may display graphics, text, or nothing at all. Thus, the effect of this option is likely to last for just a fraction of a second. On at least one firmware (used on some Gigabyte boards), setting use_graphics_for linux is required to avoid a system hang when launching Linux via its EFI stub loader. To add to the default list, specify + as the first option, as in use_graphics_for + windows.
scan_driver_dirs directory path(s) Scans the specified directory or directories for EFI driver files. If rEFInd discovers .efi files in those directories, they're loaded and activated as drivers. This option sets directories to scan in addition to the drivers and drivers_arch subdirectories of the rEFInd installation directory, which are always scanned, if present.
scanfor internal, external, optical, netboot, hdbios, biosexternal, cd, and manual Tells rEFInd what methods to use to locate boot loaders. The internal, external, and optical parameters tell rEFInd to scan for EFI boot loaders on internal, external, and optical (CD, DVD, and Blu-ray) devices, respectively. The netboot option relies on the presence of the ipxe.efi and ipxe_discover.efi program files in the EFI/tools directory to assist with network (Preboot Execution Environment, or PXE) booting. Note that netboot is experimental. See the BUILDING.txt file for information on building the necessary binaries. The hdbios, biosexternal, and cd parameters are similar, but scan for BIOS boot loaders. (Note that the BIOS options scan more thoroughly and actively on Macs than on UEFI-based PCs; for the latter, only options in the firmware's boot list are scanned, as described on the Using rEFInd page.) The manual parameter tells rEFInd to scan the configuration file for manual settings. You can specify multiple parameters to have the program scan for multiple boot loader types. When you do so, the order determines the order in which the boot loaders appear in the menu. The default is internal, external, optical, manual on most systems, but internal, hdbios, external, biosexternal, optical, cd, manual on Macs.
uefi_deep_legacy_scan none or one of true, on, 1, false, off, or 0 Tells rEFInd how aggressively to scan for BIOS/CSM/legacy boot loaders on UEFI-based PCs. Ordinarily or if this option is set to false, off, or 0, rEFInd presents only those options that were available in the NVRAM when it launched. When uncommented with no option or with true, on, or 1 set, rEFInd adds every possible BIOS-mode boot device (of types specified by scanfor) as a BIOS/CSM/legacy boot option. This latter behavior is sometimes required to detect USB flash drives or hard disks beyond the first one.
scan_delay numeric (integer) value Imposes a delay before rEFInd scans for disk devices. Ordinarily this is not necessary, but on some systems, some disks (particularly external drives and optical discs) can take a few seconds to become available. If some of your disks don't appear when rEFInd starts but they do appear when you press the Esc key to re-scan, try uncommenting this option and setting it to a modest value, such as 2, 5, or even 10. The default is 0.
also_scan_dirs directory path(s) Adds the specified directory or directories to the directory list that rEFInd scans for EFI boot loaders when scanfor includes the internal, external, or optical options. Directories are specified relative to the filesystem's root directory. You may precede a directory path with a volume name and colon, as in somevol:/extra/path, to restrict the extra scan to a single volume. A volume number, preceded by fs, can be used for volumes that lack names, as in fs1:/extra/path. (This usage is deprecated.) If you don't specify a volume name or number, this option is applied to all the filesystems that rEFInd scans. If a specified directory doesn't exist, rEFInd ignores it (no error results). The default value is boot, which is useful for locating Linux kernels when you have an EFI driver for your Linux root (/) filesystem. To add to, rather than replace, the default value, specify + as the first item in the list, as in also_scan_dirs +,loaders.
dont_scan_volumes or don't_scan_volumes filesystem or partition label(s) Adds the specified volume or volumes to a volume "blacklist"—these filesystems are not scanned for EFI boot loaders. This may be useful to keep unwanted EFI boot entries, such as for an OS recovery partition, from appearing on the main list of boot loaders. You can identify a volume by its filesystem name, its GPT volume name, or by its GPT unique GUID value. The default value is LRS_ESP, to keep the Lenovo Windows recovery volume from appearing. (This volume should get its own tools icon instead—see the showtools token.) You can use dont_scan_volumes to hide disks or partitions from legacy-mode scans, too. In this case, you can enter any part of the description that appears beneath the icons to hide entries that include the string you specify.
dont_scan_dirs or don't_scan_dirs directory path(s) Adds the specified directory or directories to a directory "blacklist"—these directories are not scanned for boot loaders. You may optionally precede a directory path with a volume name and a colon to limit the blacklist to that volume; otherwise all volumes are affected. For instance, EFI/BOOT prevents scanning the EFI/BOOT directory on all volumes, whereas ESP:EFI/BOOT blocks scans of EFI/BOOT on the volume called ESP but not on other volumes. You can use a filesystem unique GUID, as in 2C17D5ED-850D-4F76-BA31-47A561740082, in place of a volume name. This token may be useful to keep duplicate boot loaders out of the menu; or to keep drivers or utilities out of the boot menu, if you've stored them in a subdirectory of EFI. This option takes precedence over also_scan_dirs; if a directory appears in both lists, it will not be scanned. To add directories to the default list rather than replace the list, specify + as the first option, as in dont_scan_dirs + EFI/dontscan. The default for this token is EFI/tools, EFI/tools/memtest86, EFI/tools/memtest, EFI/memtest86, EFI/memtest, com.apple.recovery.boot.
dont_scan_files or don't_scan_files filename(s) Adds the specified filename or filenames to a filename "blacklist" for OS loaders—these files are not included as boot loader options even if they're found on the disk. This is useful to exclude support programs (such as shim.efi and MokManager.efi) and drivers from your OS list. The default value is shim.efi, shim-fedora.efi, shimx64.efi, PreLoader.efi, TextMode.efi, ebounce.efi, GraphicsConsole.efi, MokManager.efi, HashTool.efi, HashTool-signed.efi, fb{arch}.efi (where {arch} is the architecture code, such as x64). You can add a pathname and even a volume specification (filesystem name, partition name, or partition unique GUID), as in ESP:/EFI/BOOT/backup.efi, /boot/vmlinuz-bad, to block the boot loaders only in those specified locations. To add files to the default list rather than replace the list, specify + as the first option, as in dont_scan_files + badloader.efi.
dont_scan_tools or don't_scan_tools filename(s) Adds the specified filename or filenames to a filename "blacklist" for tools—these files are not included as tools (second-line options) even if they're found on the disk and are specified to be included via showtools. This is useful to trim an overabundance of tools. For instance, if you install multiple Linux distributions, you may end up with multiple MokManager entries, but you'll need just one. You can add a pathname and even a volume specification (filesystem name, partition name, or partition unique GUID), as in ESP:/EFI/tools/shellx64.efi, EFI/ubuntu/mmx64.efi, to block the tools only in those specified locations. The default value is an empty list (nothing is excluded).
windows_recovery_files filename(s) Adds the specified filename or filenames to list that will be recognized as Windows recovery tools and presented as such on the second row, if windows_recovery is among the options to showtools. The filename must include a complete path and may optionally include a filesystem label, as in LRS_EFI:\EFI\Microsoft\Boot\LrsBootmgr.efi. Whatever you specify here is added to the dont_scan_files list. The default value is EFI\Microsoft\Boot\LrsBootmgr.efi. If you specify + as the first option, the following options will be added to the default rather than replace it.
scan_all_linux_kernels none or one of true, on, 1, false, off, or 0 When uncommented or set to true, on, or 1, causes rEFInd to add Linux kernels (files with names that begin with vmlinuz or bzImage) to the list of EFI boot loaders, even if they lack .efi filename extensions. This simplifies use of rEFInd on most Linux distributions, which usually provide kernels with EFI stub loader support but don't give those kernels names that end in .efi. Of course, the kernels must still be stored on a filesystem that rEFInd can read, and in a directory that it scans. (Drivers and the also_scan_dirs options can help with those issues.) As of version 0.8.3, this option is enabled by default; to disable this feature, you must uncomment this token and set it to false or one of its synonyms (off or 0).
fold_linux_kernels none or one of true, on, 1, false, off, or 0 When uncommented or set to true, on, or 1, causes rEFInd to "fold" all Linux kernels in a given directory into a single main-menu icon. Selecting that icon launches the most recent kernel. To launch an older kernel, you must press F2 or Insert; older kernels appear on the resulting submenu display. (You can type, as root, touch /boot/vmlinuz-{whatever}, to make /boot/vmlinuz-{whatever} your default kernel in a directory.) If you prefer to see all your kernels in the main menu, set this option to false, off, or 0. Note that this option is new with version 0.9.0, which changes the default behavior; earlier versions of rEFInd behaved as if fold_linux_kernels false was set.
extra_kernel_version_strings comma-delimited list of strings For the benefit of Linux distributions, such as Arch, that lack version numbers in their kernel filenames but that can provide multiple kernels, you can specify strings that can treated like version numbers. For instance, for Arch you might set this to linux-lts,linux; thereafter, the vmlinuz-linux-lts kernel will match to an initrd file containing the string linux-lts and vmlinuz-linux will match an initrd file with a filename that includes linux, but not linux-lts. Note that, if one specified string is a subset of the other (as in this example), the longer substring must appear first in the list. Also, if a filename includes both a specified string and one or more digits, the match covers both; for instance, vmlinuz-linux-4.8 would match an initrd file with a name that includes linux-4.8. The default is to do no extra matching.
max_tags numeric (integer) value Limits the number of tags that rEFInd will display at one time. If rEFInd discovers more loaders than this value, they're shown in a scrolling list. The default value is 0, which imposes no limit.
default_selection a substring of a boot loader's title, +, or a numeric position; optionally followed by two times in HH:MM format Sets the default boot OS based on the loader's title, which appears in the main menu beneath the icons when you select the loader. This token takes one or three variables. The first variable is a set of one or more identifiers. If you specify more than one or if the identifier contains a space, it must be in quotation marks. If more than one identifier is present, they must be specified as a comma-separated list, all within a single set of quotation marks. For instance, default_selection "alpha,beta" will launch alpha if it's available, and beta if alpha is not available but beta is. Each identifier can be any one of three things:
  • The symbol +, which refers to the previously-launched boot entry. rEFInd stores (in NVRAM) the name of a boot entry before launching it, and effectively substitutes that stored string for the + in the default_selection line the next time rEFInd launches, then matches it as a string, as described next....
  • Any string, which is matched against boot descriptions. Note that rEFInd matches substrings, so you don't need to specify the complete description string, just a unique substring. Thus, default_selection vmlinuz matches vmlinuz, boot\vmlinuz-4.8.0-22-generic, or any other string that includes vmlinuz. rEFInd stops searching when it finds the first match. Because rEFInd sorts entries within a directory in descending order by file modification time, if you specify a directory (or volume name, for loaders in a partition's root directory) as the default_selection, the newest loader in that directory will be the default. As a special case, one-character strings are matched against the first character of the description, except for digits.
  • A digit (1 to 9), in which case the boot loader at that position in the boot list is launched. For instance, default_selection 2 makes the second boot entry the default.
You may optionally follow the match string by two times, in 24-hour format, in which case the entry applies only between those two times. For instance, default_selection Safety 1:30 2:30 boots the entry called Safety by default between the hours of 1:30 and 2:30. These times are specified in whatever format the motherboard clock uses (local time or UTC). If the first value is larger than the second, as in 23:00 1:00, it is interpreted as crossing midnight—11:00 PM to 1:00 AM in this example. The last default_selection setting takes precedence over preceding ones if the time value matches. Thus, you can set a main default_selection without a time specification and then set one or more others to override the main setting at specific times. If you do not specify a default_selection, rEFInd attempts to boot the previously-booted entry, or the first entry if there's no record of that or if the previously-booted entry can't be found.
enable_and_lock_vmx none or one of true, on, 1, false, off, or 0 When set to true or a synonym, enable the CPU's VMX bit and lock the MSR. This configuration is necessary for some hypervisors (notably Microsoft's Hyper-V) to function properly. Activating it on other CPUs will, at best, have no effect, and could conceivably crash the computer, so enable it at your own risk! If your firmware supports activating these features, you should use it instead; this option is provided for users whose firmware does not provide this functionality. (Many Macs lack this configurability, for instance.) The default is false.
spoof_osx_version string (10.9 suggested) On some Macs, this option causes rEFInd to tell the firmware that the specified version of OS X is being launched, even when another OS is selected. The effect is that the firmware may initialize hardware differently, which may have beneficial (or detrimental) results. If your Mac's video output isn't working normally, this option may help. On the other hand, keyboards and mice are known to sometimes stop functioning if this option is used, so you shouldn't use it unnecessarily. This option has no effect on non-Apple hardware. The default is to not use this feature.
csr_values List of hexadecimal values Specifies values that may be set via the csr_rotate tool for Apple's System Integrity Protection (SIP). SIP stores values in NVRAM to set restrictions on what users (even root) may do in OS X 10.11. If you want to be able to control these restrictions in rEFInd, you must set the values you want to use here and set csr_rotate on the showtools line (which must also be uncommented). Note that values are specified in hexadecimal, with no leading 0x or other hexadecimal indicator. SIP is described in more detail on many Web sites, such as here and here.
include filename Includes the specified file into the current configuration file. Essentially, the included file replaces the include line, so positioning of this token is important if the included file includes options that contradict those in the main file. The included file must reside in the same directory as the rEFInd binary and the main configuration file. This option is valid only in the main configuration file; included files may not include third-tier configuration files.

As an example of rEFInd configuration, consider the following refind.conf file:

# Sample refind.conf file
timeout 5
banner custom.bmp
scan_driver_dirs drivers,EFI/tools/drivers
scanfor manual,external,optical
default_selection elilo

This example sets a timeout of 5 seconds; loads a custom graphic file called custom.bmp from the directory in which the rEFInd binary resides; scans the drivers and EFI/tools/drivers directories for EFI drivers; uses manual boot loader configuration but also scans for external EFI boot loaders and EFI boot loaders on optical discs; and sets the default boot loader to the first loader found that includes the string elilo. Of course, since this file specifies use of manual boot loader configuration, it's not complete; you'll need to add at least one OS stanza to be able to boot from anything but an external disk or optical drive, as described shortly.

Creating Manual Boot Stanzas

Manual boot stanzas in rEFInd are similar to those in GRUB Legacy, GRUB 2, or ELILO. You can use them to add EFI boot loaders to those that are auto-detected. rEFInd does not yet support manual boot stanzas for BIOS-mode boot loaders. You also cannot modify the auto-detected options; if you just want to tweak one OS's configuration, you have several options:

  • You can use the dont_scan_volumes, dont_scan_dirs, or dont_scan_files options in refind.conf to hide the tag you want to modify, then create a manual boot stanza to replace it.
  • You can move or rename the boot loader file for the boot loader you want to tweak.
  • You can disable all auto-detection options and add manual configurations for all your boot loaders, even those that work fine when auto-detected.
  • You can put up with having duplicate tags in your OS list.

Each OS stanza begins with the keyword menuentry, a name for the entry, and an open curly brace ({). Subsequent lines constitute the bulk of the stanza, which concludes with a line containing nothing but a close curly brace (}). Table 2 summarizes the keywords that you can include in a stanza.

Table 2: OS stanza definitions in refind.conf
Token Possible parameters Explanation
menuentry name for the entry Sets the name that's displayed along with the icon for this entry. If the name should contain a space, it must be enclosed in quotes. Following the name, an open curly brace ({) ends the menuentry line.
volume filesystem label, partition label, GUID value, or filesystem number Sets the volume that's used for subsequent file accesses (by icon and loader, and by implication by initrd if loader follows volume). You pass this token a filesystem's label, a partition's label, a partition's GUID, or a volume number. A filesystem or partition label is typically displayed under the volume's icon in file managers and rEFInd displays it on its menu at the end of the boot prompt string. If this label isn't unique, the first volume with the specified label is used. The matching is nominally case-insensitive, but on some EFIs it's case-sensitive. If a filesystem has no label, you can use a partition GUID number. You can also use a volume number followed by a colon, such as 0: to refer to the first filesystem or 1: to refer to the second. The assignment of numbers is arbitrary and may not be consistent across boots, though. It might change if you insert an optical disc or plug in a USB flash drive, for instance. If this option is not set, the volume defaults to the one from which rEFInd launched.
loader filename Sets the filename for the boot loader. You may use either Unix-style slashes (/) or Windows/EFI-style backslashes (\) to separate directory elements. In either case, the references are to files on the ESP from which rEFInd launched or to the one identified by a preceding volume token. The filename is specified as a path relative to the root of the filesystem, so if the file is in a directory, you must include its complete path, as in \EFI\myloader\loader.efi. This option should normally be the first in the body of an OS stanza; if it's not, some other options may be ignored. An exception is if you want to boot a loader from a volume other than the one on which rEFInd resides, in which case volume should precede loader.
initrd filename Sets the filename for a Linux kernel's initial RAM disk (initrd). This option is useful only when booting a Linux kernel that includes an EFI stub loader, which enables you to boot a kernel without the benefit of a separate boot loader. When booted in this way, though, you must normally pass an initrd filename to the boot loader. You must specify the complete EFI path to the initrd file with this option, as in initrd EFI/linux/initrd-3.3.0-rc7.img. You'll also have to use the options line to pass the Linux root filesystem, and perhaps other options (as in options "root=/dev/sda4 ro"). The initial RAM disk file must reside on the same volume as the kernel.
icon filename Sets the filename for an icon for the menu. If you omit this item, a default icon will be used, based on rEFInd's auto-detection algorithms. The filename should be a complete path from the root of the current directory, not relative to the default icons subdirectory or the one set via icons_dir.
ostype MacOS, Linux, ELILO, Windows, XOM Determines the options that are available on a sub-menu obtained by pressing the Insert key with an OS selected in the main menu. If you omit this option, rEFInd selects options using an auto-detection algorithm. Note that this option is case-sensitive.
graphics on or off Enables or disables a graphical boot mode. This option has an effect only on Macintoshes; UEFI PCs seem to be unaffected by it.
options options passed to the boot loader Pass arbitrary options to your boot loader with this line. Note that if the option string should contain spaces (as it often should) or characters that should not be modified by rEFInd's option parser (such as slashes or commas), it must be enclosed in quotes. If you must include quotes in an option, you can double them up, as in my_opt=""with quotes"", which passes my_opt="with quotes" as an option.
disabled none Disable an entry. This is often easier than commenting out an entire entry if you want to temporarily disable it.
submenuentry submenu entry name and tokens This keyword identifies a submenu entry, as described in more detail shortly.

As an example, consider the following entries:

menuentry "Ubuntu" {
    loader /EFI/ubuntu/grubx64.efi
    disabled
}

menuentry Arch {
    icon /EFI/refind/icons/os_arch.png
    volume ARCHBOOT
    loader /vmlinuz-linux
    initrd /initramfs-linux.img
    options "root=/dev/sda3 ro"
}

menuentry "Windows via shell script" {
    icon \EFI\refind\icons\os_win.png
    loader \EFI\tools\shell.efi
    options "fs0:\EFI\tools\launch_windows.nsh"
}

This example sets up three entries: one for Ubuntu, one for Arch Linux, and one to launch a shell script. Note that the final entry uses different directory separators from the first two, simply to demonstrate the fact that it's possible. (The form of directory separators in options lines is important, though, because the program being launched may expect a particular directory separator character.) The Ubuntu entry sets no icon, since rEFInd will note that the boot loader is stored in the ubuntu directory, and it will automatically find the appropriate Ubuntu icon (os_ubuntu.png). This entire entry is, however, disabled, so no matching icon will appear when you reboot unless you first comment out or delete the disabled line.

The Arch entry begins with an icon specification to be sure that the icon is loaded from the same volume as rEFInd. (If the icon were stored on the same filesystem as the kernel, you'd place the icon line after the volume line.) This entry uses the volume token to tell rEFInd to load the kernel and initial RAM disk file from the filesystem or partition called ARCHBOOT. It passes the filename for an initial RAM disk using the initrd line and free-form options using the options line.

The Windows via shell script entry may seem puzzling, but its purpose is to launch an OS (Windows in this case) after performing additional pre-boot initialization, which is handled by an EFI shell script. This works because you can pass the name of a shell script to an EFI shell—the script is named on the stanza's options line, using EFI file notation. The shell script, in turn, does whatever it needs to do and then launches the OS's boot loader:

mm 0003003E 8 -pci
fs0:\EFI\Microsoft\Boot\bootmgfw.efi

This example writes data to the computer's PCI bus via the EFI shell's mm command and then launches Windows. Chances are you won't need to engage in such operations, and I do not recommend you try this exact example unless you know what you're doing! This command was required to activate the video hardware prior to booting Windows on a computer of a person with whom I corresponded, but such needs are rare. (Using the spoof_osx_version option in rEFInd 0.9.3 and later may also help with some such problems, at least on Macs.) Another example of a similar approach can be found in this forum thread. A few pointers on finding addresses for your hardware can be found in this post.

You can combine these OS stanzas with the global refind.conf options presented earlier. The result would contain just two entries on the rEFInd boot menu (for Arch and Windows, since the Ubuntu entry is disabled), unless rEFInd found other boot options on an external or optical disk.

Creating Submenu Entries

As described on the Using rEFInd page, rEFInd can present a menu of options for certain loader tags when you press the Insert, F2, or + key. rEFInd does this automatically when it detects Mac OS X or ELILO boot loaders, when you set the OS type via the ostype option, or when booting a Linux kernel directly. The Mac OS X boot loader, in particular, accepts various options that you can use to boot in various ways.

Sometimes, you might want to create your own custom submenu entries, and rEFInd enables you to do this. To create a custom submenu, you use the submenuentry keyword inside a menuentry stanza. Normally, you'll set the submenu definitions after you've set the main menu options, since the submenu options take the main menu options as defult, and so the main options must be set first. Like a menuentry stanza, a submenuentry definition begins with the keyword, the name of the item, and an open curly brace ({). It continues until a close curly brace (}). A submenu definition can use the keywords described in Table 3. Except as otherwise noted, using an option of a given name completely overrides the setting in the main stanza.

Table 3: Submenu keywords in refind.conf
Token Possible parameters Explanation
submenuentry name for the entry Sets the name that's displayed for this entry on the submenu page. If the name should contain a space, it must be enclosed in quotes. Following the name, an open curly brace ({) ends the submenuentry line.
loader filename Sets the filename for the boot loader, as described in Table 2. Note that the loader is read from whatever filesystem is specified by the main stanza's volume option, provided that option precedes the submenu definition.
initrd filename Sets the filename for a Linux kernel's initial RAM disk (initrd), as described in Table 2. If you want to eliminate the initrd specification, you should use this keyword alone, with no options. You might do this because your main entry is for a Linux kernel with EFI stub support and this submenu entry launches ELILO, which sets the initrd in its own configuration file.
graphics on or off Enables or disables a graphical boot mode, as described in Table 2.
options options passed to the boot loader Pass arbitrary options to your boot loader with this line, as described in Table 2. As with initrd, you can eliminate all options by passing this keyword alone on a line.
add_options options passed to the boot loader This token works just like options, except that instead of replacing the default options, it causes the specified options to be added to those specified in the main stanza listing's options line.
disabled none Disable a submenu entry. This is often easier than commenting out an entire entry if you want to temporarily disable it.

The following menu entry illustrates the use of submenu entries. This is a variant of the second entry presented earlier:

menuentry Arch {
    icon /EFI/refind/icons/os_arch.png
    loader /vmlinuz-linux
    initrd /initramfs-linux.img
    options "root=/dev/sda3 ro"
    submenuentry "single-user mode" {
        add_options "single"
    }
    submenuentry "Use fallback initrd" {
        initrd /initramfs-linux-fallback.img
    }
    submenuentry "boot via SYSLINUX" {
        loader \EFI\syslinux\syslinux.efi
	initrd
	options
    }
}

The main menu item for this entry won't look different with the submenus defined than without them; but if you press the F2 or Insert key, you'll see the submenu items:


Manually defining submenus enables you to customize
    your boot options.

The main menu item appears at the top of the list—Boot using default options. The three submenus defined in this example's configuration file appear next, enabling you to launch in single-user mode, boot the standard kernel with the fallback initrd file, or boot via SYSLINUX, respectively. Submenus also include an item called Return to Main Menu that does just as it says. (Alternatively, you can return to the main menu by pressing the Esc key.)

This example illustrates some of the things you can do with submenu entries:

  • You can add kernel options when booting via the EFI stub loader—to launch single-user mode, to add graphical boot options, or what have you.
  • You can remove options. Note the empty initrd and options lines in the SYSLINUX entry, for example; these empty lines override the default entries, which are carried over to submenu entries by default.
  • You can change kernel options when booting via the EFI stub loader—to remove graphical boot options, to boot to a different root device, and so on.
  • You can change your kernel and/or initial RAM disk when booting via the EFI stub loader.
  • You can give users a choice of boot loaders. In this example, the main option boots via the kernel stub loader, but the submenu gives users the chance to boot via SYSLINUX instead. In fact, you could even boot two entirely different OSes from manually-defined submenu entries, although that could be confusing.

Adjusting the Default Boot Option

Just before launching an OS, rEFInd stores the description in the EFI variable PreviousBoot with a GUID of 36d08fa7-cf0b-42f5-8f14-68df73ed3740. The next time rEFInd launches, it reads that same variable and sets the default boot loader to that value, if it's still available and if the first item in default_selection in the refind.conf file is a plus sign (+).

Under Linux, the variable that rEFInd uses to store this information is accessible as /sys/firmware/efi/efivars/PreviousBoot-36d08fa7-cf0b-42f5-8f14-68df73ed3740. Thus, you can back up this value, modify it, and write it back out to adjust your next-booted OS. Getting this string just right can be a bit tricky, though, and if the kernel doesn't like its format, it will not let you modify the variable. If you try to modify the variable, be aware that it's stored in UTF-16 format. As with the default_selection token in refind.conf, you can enter any substring that uniquely identifies the entry you want to boot.

In principle, you should be able to use a similar procedure to force rEFInd to boot another OS by default in any other OS that supports writing EFI runtime variables. Unfortunately, I don't know the mechanisms used for this task in Windows, OS X, FreeBSD, or any other OS.

If you want to consistently boot a particular OS by default and ignore the previous boot, you can use default_selection, but omit the + at the start of the line.


copyright © 2012–2018 by Roderick W. Smith

This document is licensed under the terms of the GNU Free Documentation License (FDL), version 1.3.

If you have problems with or comments about this Web page, please e-mail me at rodsmith@rodsbooks.com. Thanks.

Go to the main rEFInd page

Learn about how to use EFI drivers with rEFInd

Return to my main Web page.

refind-0.11.4/docs/man/0000775000175000017500000000000013142210015015002 5ustar rodsmithrodsmithrefind-0.11.4/docs/man/mvrefind.80000664000175000017500000000715513372347317016742 0ustar rodsmithrodsmith.\" Copyright 2015-2017 Roderick W. Smith (rodsmith@rodsbooks.com) .\" May be distributed under the GNU Free Documentation License version 1.3 or any later version .TH "MVREFIND" "8" "0.11.4" "Roderick W. Smith" "rEFInd Manual" .SH "NAME" mvrefind \- Move a rEFInd installation from one location to another .SH "SYNOPSIS" .BI "mvrefind \fISOURCE DEST\fR" .SH "DESCRIPTION" Move a rEFInd installation from \fISOURCE\fR to \fIDEST\fR, where both \fISOURCE\fR and \fIDEST\fR are directories on the EFI System Partition (ESP), with \fISOURCE\fR containing a working rEFInd installation. This operation entails taking several actions: .TP .B * Renaming the \fISOURCE\fR directory to \fIDEST\fR. .TP .B * Renaming the rEFInd binary to a suitable value given the new destination. For instance, if \fIDEST\fR is EFI/BOOT on the EFI System Partition (ESP), the rEFInd binary should be \fIbootx64.efi\fR (or something similar but with a different architecture code). .TP .B * Altering the computer's NVRAM entries to point to rEFInd at its new location. .TP .B * If Shim is detected, renaming operations and NVRAM entry pointers are adjusted appropriately. .TP .B * If the \fIDEST\fR exists, its contents are preserved. .PP Broadly speaking, \fImvrefind\fR understands three types of locations for both \fISOURCE\fR and \fIDEST\fR, relative to the root of the ESP: .TP .B * \fBEFI/BOOT\fR -- The \fIbootx64.efi\fR (or similar for other architectures) filename in this location is the "fallback filename," which is used by removable boot media and as a boot loader of last resort on hard disks. Some EFIs can't remember their normal boot entries, and on them, rEFInd must be installed here (or as the Windows boot loader). When this directory is the \fIDEST\fR and it already exists, the existing \fIEFI/BOOT\fR is backed up to \fIEFI/BOOT\-rEFIndBackup\fR; and if the \fISOURCE\fR is \fIEFI/BOOT\fR and \fIEFI/BOOT\-rEFIndBackup\fR exists, it is renamed to \fIEFI/BOOT\fR after rEFInd is moved to its destination. .TP .B * \fBEFI/Microsoft/boot\fR -- The \fIbootmgfw.efi\fR file in this location normally holds the Windows boot loader. Machines with broken EFIs may refuse to accept or remember proper boot entries and will instead boot this entry in preference to all others. In such cases, using rEFInd requires moving the Microsoft boot loader elsewhere and replacing it with rEFInd. When this directory is the \fIDEST\fR, \fImvrefind\fR moves the original \fIbootmgfw.efi\fR file down one level (to \fIEFI/Microsoft\fR) and stores \fIrefind_x64.efi\fR (or Shim) in that location. When moving from \fIEFI/Microsoft/boot\fR, this process is reversed. .TP .B * \fBAnything else\fR -- Any other \fISOURCE\fR or \fIDEST\fR location is treated as a regular rEFInd installation, with a proper NVRAM entry created by \fIefibootmgr\fR. .PP \fImvrefind\fR attempts to identify the ESP and refuses to move between the ESP and any other partition. When it does move files, it moves the main rEFInd binary, the \fIrefind.conf\fR file, any identified Shim binary, and the \fIicons\fR, \fIicons\-backup\fR, \fIdrivers_*\fR, and \fIkeys\fR subdirectories. If other rEFInd files or directories are present in \fISOURCE\fR (such as a custom theme/icons directory), they will not be moved. If \fISOURCE\fR is empty after the specified files and subdirectories are moved, \fISOURCE\fR will be deleted. .SH "AUTHORS" Primary author: Roderick W. Smith (rodsmith@rodsbooks.com) .SH "SEE ALSO" \fBmkrlconf (8)\fR, \fBrefind-install (8)\fR \fIhttp://www.rodsbooks.com/refind/\fR .SH "AVAILABILITY" The \fBmvrefind\fR command is part of the \fIrEFInd\fR package and is available from Roderick W. Smith. refind-0.11.4/docs/man/mkrlconf.80000664000175000017500000000375413372347325016743 0ustar rodsmithrodsmith.\" Copyright 2015-2017 Roderick W. Smith (rodsmith@rodsbooks.com) .\" May be distributed under the GNU Free Documentation License version 1.3 or any later version .TH "MKRLCONF" "8" "0.11.4" "Roderick W. Smith" "rEFInd Manual" .SH "NAME" mkrlconf \- Create a Linux kernel configuration file for rEFInd .SH "SYNOPSIS" .BI "mkrlconf " [ \-\-force ] .SH "DESCRIPTION" To boot a Linux kernel directly, rEFInd must normally pass system-specific parameters to help the kernel locate its initial RAM disk (initrd) file, the installation's root filesystem, and so on. rEFInd stores this information in a file called \fIrefind_linux.conf\fR, which is stored in the same directory as the kernel(s) to which it applies. The \fImkrlconf\fR script creates this configuration file in \fI/boot\fR, using the current boot options (from \fI/proc/cmdline\fR) to populate \fI/boot/refind_linux.conf\fR with boot options that are probably (but not certainly) correct. The file created in this way has three lines, which correspond to three entries on the rEFInd suboptions menu. The first entry boots using the options found in \fI/proc/cmdline\fR. The second entry boots using the same options as the first, but with \fBsingle\fR added. The third entry boots with minimal options of \fBro root={CURRENT_ROOT_DEVICE}\fR, where \fB{CURRENT_ROOT_DEVICE}\fR identifies the current root (\fI/\fR) filesystem. Users may manually edit the \fIrefind_linux.conf\fR file to suit their needs, of course. .SH "OPTIONS" .TP .B \-\-force Ordinarily, if \fImkrlconf\fR finds an existing \fI/boot/refind_linux.conf\fR file, it refuses to replace it. The \fB\-\-force\fR option causes \fImkrlconf\fR to replace the existing file in favor of one it generates. .SH "AUTHORS" Primary author: Roderick W. Smith (rodsmith@rodsbooks.com) .SH "SEE ALSO" \fBmvrefind (8)\fR, \fBrefind-install (8)\fR \fIhttp://www.rodsbooks.com/refind/\fR .SH "AVAILABILITY" The \fBmkrlconf\fR command is part of the \fIrEFInd\fR package and is available from Roderick W. Smith. refind-0.11.4/docs/man/refind-mkdefault.80000664000175000017500000001115413372347305020340 0ustar rodsmithrodsmith.\" Copyright 2016-2017 Roderick W. Smith (rodsmith@rodsbooks.com) .\" May be distributed under the GNU Free Documentation License version 1.3 or any later version .TH "REFIND-MKDEFAULT" "8" "0.11.4" "Roderick W. Smith" "rEFInd Manual" .SH "NAME" refind-mkdefault \- Set rEFInd as the default EFI boot option .SH "SYNOPSIS" .BI "refind-mkdefault " [ \-L|\-\-label ] .SH "DESCRIPTION" EFI booting normally relies on boot manager entries stored in NVRAM, which describe the locations of EFI boot programs and the order in which the firmware will attempt to launch them. In Linux, these entries can be created, deleted, and manipulated with the \fIefibootmgr\fR utility. Many OSes and Linux packages assume that they should control the boot process, and so both create NVRAM boot entries for themselves and set these entries first in the boot order. If you intend rEFInd to control the boot process, though, such changes are undesirable and require adjustment via \fIefibootmgr\fR. Such adjustments are annoying to make and can be intimidating to non-experts. The \fIrefind-mkdefault\fR script simplifies matters: Running this script with no options sets rEFInd as the default boot program. The details of what the script does depends on the current state of the boot order list and existing boot entries: .TP .B * If a rEFInd entry already exists in the boot order and is already first in the list, no changes are made. .TP .B * If a rEFInd entry already exists in the boot order but is not first in the list, that entry is moved to the first position in the boot order. .TP .B * If more than one rEFInd entry exists in the boot order, \fIrefind-mkdefault\fR moves the one that comes earliest to the front of the boot order list. .TP .B * If no rEFInd entry exists in the boot order but a rEFInd boot entry can be found in the list of \fBBoot####\fR entries, it is added to the boot order and placed at the front of the list. .TP .B * If multiple rEFInd boot entries exist but none is in the boot order, all the entries are added to the boot order, but which one is first is uncontrolled. .PP A rEFInd entry is defined as one that contains the string \fBrefind\fR (case-insensitive). This string could exist in the description or in the filename. The string used to define the rEFInd entry can be changed via the \fI\-\-label\fR (\fI\-L\fR) option. The intent is that \fIrefind-mkdefault\fR can be called after booting via GRUB or some other means to restore rEFInd as the default boot program. It can also be placed in a startup and/or shutdown script to restore rEFInd to its default position automatically. Because it does not re-write the boot order if rEFInd is listed as the first boot entry, this practice should be low in risk. .SH "OPTIONS" .TP .B \-L | \-\-label \fI\fR Instead of searching for the string \fBrefind\fR in \fIefibootmgr\fR output as a way to identify rEFInd, search for the string \fBname\fR. .SH "RETURN VALUES" \fIrefind-mkdefault\fR returns the following values: .TP .B 0 The script completed successfully, which can mean either that no change was necessary or that the call to \fIefibootmgr\fR returned a success code. .TP .B 1 EFI boot order variables are available, and a rEFInd entry was found, but the call to \fIefibootmgr\fR returned a failure code. .TP .B 2 EFI boot entries are not available. This condition is often an indication of a buggy EFI or badly damaged NVRAM contents. .TP .B 3 No rEFInd entry could be found in the list of boot options, and so no changes were made to the boot order list. .TP .B 4 The script could not run because of OS issues -- the OS was not Linux, the \fIefibootmgr\fR utility was not available, or the script was not run as \fIroot\fR. .SH "LIMITATIONS" .TP .B * \fIrefind-mkdefault\fR does not work when booted in BIOS mode (including via a Compatibility Support Module, or CSM, on an EFI-based computer). Similarly, it does not work if \fIefibootmgr\fR is not installed or fails to work for any reason. .TP .B * The script uses a very simple algorithm to determine what to move to the start of the boot order list. This algorithm may fail if the system has redundant or non-functional rEFInd boot entries or if those entries are not named in an expected fashion. Cleaning up the boot entries by manual use of \fIefibootmgr\fR may be necessary in such cases. .SH "AUTHORS" Primary author: Roderick W. Smith (rodsmith@rodsbooks.com) .SH "SEE ALSO" \fBmvrefind (8)\fR, \fBmkrlconf (8)\fR, \fBrefind-install (8)\fR, \fBefibootmgr (8)\fR \fIhttp://www.rodsbooks.com/refind/\fR .SH "AVAILABILITY" The \fBrefind-mkdefault\fR command is part of the \fIrEFInd\fR package and is available from Roderick W. Smith. refind-0.11.4/docs/man/refind-install.80000664000175000017500000003366313372347313020042 0ustar rodsmithrodsmith.\" Copyright 2015-2017 Roderick W. Smith (rodsmith@rodsbooks.com) .\" May be distributed under the GNU Free Documentation License version 1.3 or any later version .TH "REFIND-INSTALL" "8" "0.11.4" "Roderick W. Smith" "rEFInd Manual" .SH "NAME" refind-install \- Install rEFInd to the ESP and create an NVRAM entry .SH "SYNOPSIS" .BI "refind-install " [--notesp | --usedefault \fIdevice-file\fR | --root \fImount-point\fR | --ownhfs \fIdevice-file\fR ] [--keepname] [--nodrivers | --alldrivers] [--shim \fIshim-filename\fR] [--localkeys] [--encryptkeys] [--yes] .SH "DESCRIPTION" To be useful, the rEFInd boot manager must be installed to the computer's EFI System Partition (ESP) or other EFI-accessible location. In most cases, an NVRAM entry describing rEFInd's location must also be created. These steps can be performed manually; however, the \fBrefind-install\fR command provides an automated way to perform these tasks under both Linux and OS X. The exact behavior and options vary depending on the OS, however. Some details that can affect how the script runs include the following: .TP .B * If you run the script as an ordinary user, it attempts to acquire \fBroot\fR privileges by using the \fBsudo\fR command. This works on Mac OS X and some Linux installations (such as under Ubuntu or if you've added yourself to the \fBsudo\fR users list), but on some Linux installations this will fail. On such systems, you should run \fBrefind\-install\fR as root. .TP .B * Under OS X, you can run the script with a mouse by opening a Terminal session and then dragging\-and\-dropping the \fBrefind\-install\fR file to the Terminal window. You'll need to press the Return or Enter key to run the script. .TP .B * If you're using OS X 10.7's Whole Disk Encryption (WDE) feature, or the loogical volumes feature in OS X 10.10, you must install rEFInd to the ESP or to a separate HFS+ partition. The default in rEFInd 0.8.4 and later is to install to the ESP. If you prefer to use a separate HFS+ volume, the \fB\-\-ownhfs \fIdevice-file\fR option to \fBrefind\-install\fR is required. .TP .B * If you're not using WDE or logical volumes, you can install rEFInd to the OS X root (/) partition by using the \-\-notesp option to \fBrefind\-install\fR. Using this option is recommended when upgrading from a working rEFInd installation in this location. .TP .B * If you're replacing rEFIt with rEFInd on a Mac, there's a chance that \fBrefind\-install\fR will warn you about the presence of a program called \fB/Library/StartupItems/rEFItBlesser\fR and ask if you want to delete it. This program is designed to keep rEFIt set as the boot manager by automatically re\-blessing it if the default boot manager changes. This is obviously undesirable if you install rEFInd as your primary boot manager, so it's generally best to remove this program. If you prefer to keep your options open, you can answer \fBN\fR when \fBrefind\-install\fR asks if you want to delete rEFItBlesser, and instead manually copy it elsewhere. If you subsequently decide to go back to using rEFIt as your primary boot manager, you can restore rEFItBlesser to its place. .TP .B * If you intend to boot BIOS-based OSes on a UEFI-based PC, you must edit the \fBrefind.conf\fR file's \fBscanfor\fR line to enable the relevant searches. This is not necessary on Macs, though; because of the popularity of dual boots with Windows on Macs, the BIOS/legacy scans are enabled by default on Macs. .TP .B * On Linux, \fBrefind\-install\fR checks the filesystem type of the \fB/boot\fR directory and, if a matching filesystem driver is available, installs it. Note that the "\fB/boot\fR directory" may be on a separate partition or it may be part of your root (\fB/\fR) filesystem, in which case the driver for your root filesystem is installed. This feature is unlikely to work properly from an emergency system, although it might if you have a separate \fB/boot\fR partition and if you mount that partition at \fB/boot\fR in your emergency system, and the ESP at \fB/boot/efi\fR. .TP .B * On OS X, \fBrefind\-install\fR checks your partition tables for signs of a Linux installation. If such a sign is found, the script installs the EFI filesystem driver for the Linux ext4 filesystem. This will enable rEFInd to read your Linux kernel if it's on an ext2, ext3, or ext4 filesystem. Note that some configurations will require a \fB/boot/refind_linux.conf\fR file, which can be reliably generated only under Linux. (The \fBmkrlconf\fR script that comes with rEFInd will do this job once you've booted Linux.) In the meantime, you can launch GRUB from rEFInd or press F2 or Insert twice after highlighting the Linux option in rEFInd. This will enable you to enter a \fBroot=\fI/dev/whatever\fR specification, where \fI/dev/whatever\fR is the device identifier of your Linux root (\fB/\fR) filesystem. .TP .B * If you run \fBrefind\-install\fR on Linux and if \fB/boot/refind_linux.conf\fR doesn't already exist, \fBrefind\-install\fR creates this file and populates it with a few sample entries. If \fB/boot\fR is on a FAT partition (or HFS+ on a Mac), or if it's on an ext2fs, ext3fs, ext4fs, ReiserFS, Btrfs, or HFS+ partition and you install an appropriate driver, the result is that rEFInd will detect your kernel and will probably boot it correctly. Some systems will require manual tweaking to \fBrefind_linux.conf\fR, though -- for instance, to add \fBdolvm\fR to the boot options on Gentoo systems that use LVM. .TP .B * If you pass the \fB\-\-shim\fR option to the script (along with a filename for a Shim binary), the script sets up for a Secure Boot configuration via Shim. By default, this causes the rEFInd binary to be renamed as \fBgrubx64.efi\fR. Recent versions of Shim support passing the name of the follow-on program to Shim via a parameter, though. If you want to use this feature, you can pass the \fB\-\-keepname\fR option to \fBrefind\-install\fR. .PP After you run \fBrefind\-install\fR, you should peruse the script's output to ensure that everything looks OK. \fBrefind\-install\fR displays error messages when it encounters errors, such as if the ESP is mounted read-only or if you run out of disk space. You may need to correct such problems manually and re\-run the script. In some cases you may need to fall back on manual installation, which gives you better control over details such as which partition to use for installation. .SH "OPTIONS" .TP .B \-\-notesp This option, which is valid only under OS X, tells \fBrefind-install\fR to install rEFInd to the OS X root partition rather than to the ESP. This behavior was the default in rEFInd 0.8.3 and earlier, so you may want to use it when upgrading installations of that version, unless you used \-\-esp (which is now the default behavior, although the \-\-esp option no longer exists) or \-\-ownhfs. You may also want to use \-\-notesp on new installations if you're sure you're not using whole\-disk encryption or logical volumes. .TP .B \-\-usedefault \fIdevice-file\fR You can install rEFInd to a disk using the default/fallback filename of \fBEFI/BOOT/bootx64.efi\fR (as well as \fBEFI/BOOT/bootia32.efi\fR and \fBEFI/BOOT/bootaa64.efi\fR, if the IA\-32 and ARM64 builds are available) using this option. The device\-file should be an unmounted ESP, or at least a FAT partition, as in \fB\-\-usedefault /dev/sdc1\fR. Your computer's NVRAM entries will not be modified when installing in this way. The intent is that you can create a bootable USB flash drive or install rEFInd on a computer that tends to "forget" its NVRAM settings with this option. This option is mutually exclusive with \-\-notesp and \-\-root. .TP .B \-\-ownhfs \fIdevice-file\fR This option should be used only under OS X. It's used to install rEFInd to an HFS+ volume other than a standard Mac boot volume. The result should be that rEFInd will show up in the Mac's own boot manager. More importantly, suspend\-to\-RAM operations may work correctly. Note that this option requires an HFS+ volume that is not currently an OS X boot volume. This can be a data volume or a dedicated rEFInd partition. The ESP might also work, if it's converted to use HFS+; however, HFS+ is a non\-standard filesystem for an ESP, and so is not recommended. .TP .B \-\-root \fImount-point\fR This option is intended to help install rEFInd from a "live CD" or other emergency system. To use it, you should mount your regular installation at \fI/mount\-point\fR, including your /boot directory (if it's separate) at \fI/mount\-point\fR/boot and (on Linux) your ESP at that location or at \fI/mount\-point\fR/boot/efi. The \fBrefind\-install\fR script then installs rEFInd to the appropriate location -- on Linux, \fI/mount\-point\fR/boot/EFI/refind or \fI/mount\-point\fR/boot/efi/EFI/refind, depending on where you've mounted your ESP. Under OS X, this option is useful only in conjunction with \-\-notesp, in which case rEFInd will install to \fI/mount\-point\fR/EFI/refind. The script also adds an entry to your NVRAM for rEFInd at this location. You cannot use this option with \-\-usedefault. Note that this option is not needed when doing a dual-boot Linux/OS X installation; just install normally in OS X. .TP .B \-\-nodrivers Ordinarily \fBrefind\-install\fR attempts to install the driver required to read /boot on Linux. This attempt works only if you're using ext2fs, ext3fs, ext4fs, ReiserFS, or Btrfs on the relevant partition. If you want to forego this driver installation, pass the \-\-nodrivers option. This option is implicit when you use \-\-usedefault. .TP .B \-\-alldrivers When you specify this option, \fBrefind\-install\fR copies all the driver files for your architecture. You may want to remove unused driver files after you use this option. Note that some computers hang or fail to work with any drivers if you use this option, so use it with caution. .TP .B \-\-shim \fIshim\-filename\fR or \fB\-\-preloader \fIpreloader\-filename\fR\fB If you pass this option to \fBrefind\-install\fR, the script will copy the specified shim program file to the target directory, copy the MokManager.efi file from the shim program file's directory to the target directory, copy the 64-bit version of rEFInd as grubx64.efi, and register shim with the firmware. (If you also specify \-\-usedefault, the NVRAM registration is skipped. If you also use \-\-keepname, the renaming to grubx64.efi is skipped.) When the target file is identified as PreLoader, much the same thing happens, but \fBrefind\-install\fR copies HashTool.efi instead of MokManager.efi and copies rEFInd as loader.efi rather than as grubx64.efi. The intent is to simplify rEFInd installation on a computer that uses Secure Boot; when so set up, rEFInd will boot in Secure Boot mode, with one caveat: The first time you boot, MokManager/HashTool will launch, and you must use it to locate and install a public key or register rEFInd as a trusted application. The rEFInd public key file will be located in the rEFInd directory's keys subdirectory under the name refind.cer. .TP .B \-\-localkeys This option tells \fBrefind\-install\fR to generate a new Machine Owner Key (MOK), store it in /etc/refind.d/keys as refind_local.*, and re-sign all the 64-bit rEFInd binaries with this key before installing them. This is the preferable way to install rEFInd in Secure Boot mode, since it means your binaries will be signed locally rather than with my own key, which is used to sign many other users' binaries; however, this method requires that both the \fBopenssl\fR and \fBsbsign\fR binaries be installed. The former is readily available in most distributions' repositories, but the latter is not, so this option is not the default. .TP .B \-\-encryptkeys Ordinarily, if you use the \-\-localkeys option, \fBrefind\-install\fR stores the local key files on your hard disk in an unencrypted form. Thus, should your computer be compromised, the intruder could use your own key to sign a modified boot loader, eliminating the benefits of Secure Boot. If you use this option, then the private key is stored in an encrypted form, secured via an encryption password. You must enter this password before the key can be used to sign any binary, thus reducing the risk that an intruder could hijack your boot process. This is obviously a highly desirable option, but the downside is that you must remember the password and enter it whenever you update rEFInd or any other program signed with your private key. This also makes a fully automated update of rEFInd impossible. .TP .B \-\-keepname This option is useful only in conjunction with \-\-shim. It tells \fBrefind\-install\fR to keep rEFInd's regular filename (typically refind_x64.efi) when used with shim, rather than rename the binary to grubx64.efi. This change cuts down on the chance of confusion because of filename issues; however, this feature requires that shim be launched with a command-line parameter that points to the rEFInd binary under its real name. versions of shim prior to 0.7 do not properly support this feature. (Version 0.4 supports it but with a buggy interpretation of the follow-on loader specification.) If your NVRAM variables become corrupted or are forgotten, this feature may make rEFInd harder to launch. This option is incompatible with \-\-usedefault and is unavailable when run under OS X or without the \-\-shim option. If the script discovers an existing rEFInd installation under EFI/BOOT or EFI/Microsoft/Boot and no other rEFInd installation when this option is used, it will abort. .TP .B \-\-yes This option causes the script to assume a \fBY\fR input to every yes/no prompt that can be generated under certain conditions, such as if you specify \-\-shim but \fBrefind\-install\fR detects no evidence of a Secure Boot installation. This option is intended mainly for use by scripts such as those that might be used as part of an installation via an RPM or Debian package. .SH "AUTHORS" Primary author: Roderick W. Smith (rodsmith@rodsbooks.com) .SH "SEE ALSO" \fBmkrlconf (8)\fR, \fBmvrefind (8)\fR \fIhttp://www.rodsbooks.com/refind/\fR .SH "AVAILABILITY" The \fBrefind\-install\fR command is part of the \fIrEFInd\fR package and is available from Roderick W. Smith. refind-0.11.4/NEWS.txt0000664000175000017500000030274313372345146014650 0ustar rodsmithrodsmith0.11.4 (11/12/2017): -------------------- - Fixed a problem with RefindPkg.dsc that caused compilation failures with the latest git version of TianoCore when using the edk2 target. - Fixed a refind-install bug that caused it to misidentify the ESP when adding a rEFInd boot entry when autofs was in use. - Updates to NTFS and btrfs driver, provided by Samuel Liao. - The NTFS driver fixes bugs related to fragmented files and filesystems with a cluster size of over 4KiB. - The btrfs driver adds support for zstd decompression, which requires a huge (537K) buffer; and it fixes RAID1 issues and adds RAID5/6 support. - Added references to several new themes to themes.html, and fixed a broken URL in that file. - Reverted a change to refind-install and mountesp scripts, introduced in 0.11.3, that caused them to fail when run in macOS's Recovery environment. - Fixed bug, introduced in 0.11.3, that caused the default of booting to the previously-launched loader to be lost in favor of launching the first loader found. Explicitly setting the option via default_selection still worked. 0.11.3 (7/22/2017): ------------------- - Changes to scripts for portability; should have no visible effects. - Updated pointer support to work on some (many? Most?) 32-bit systems. - Added shutdown_after_timeout feature. When set, this causes rEFInd to attempt to shut down the computer rather than boot the default option when the timeout value is reached. Note, however, that some computers will instead hang or reboot when the timeout value is reached because they lack support for the shutdown option. - Fixed bug that caused portions of the "Pausing before disk scan; please wait...." message displayed when scan_delay is set to a value over 1 to remain on screen. - Added support for JPEG images. These are most useful as background (banner) images, since alpha/transparency is not supported. For that matter, progressive, lossless, and other JPEG features are not supported, either; see https://keyj.emphy.de/nanojpeg/ for details. - Added new use_nvram token, which defaults to true to mimic the original behavior. When set to false, this option tells rEFInd to store its variables (PreviousBoot, HiddenTags, HiddenLegacy, and Hidden tools, used to enable booting the the previously-booted OS and to manage hidden OS tags) on the hard disk rather than in NVRAM. Note that this token does NOT affect rEFInd's reading NVRAM for non-rEFInd-specific variables, such as the one holding the Secure Boot status. - The "+" symbol in default_selection may now be placed anywhere in the default_selection string to refer to the previous boot. For instance, "bzImage,+,vmlinuz" now works, prioritizing any bzImage files over the previous boot, but the previous boot over vmlinuz files. - Added icons for Void Linux, Ubuntu 17.10, and Ubuntu 18.04. - Copied the gummiboot icon (os_gummiboot.png) to os_systemd.png, so that systemd-boot has an icon. - Eliminated "Scanning for boot loaders; please wait" message from initial boot scan, which seems to be universally disliked. - Fixed bug that caused rEFInd to ignore refind.conf if the first line was empty. 0.11.2 (10/22/2017): -------------------- - Fixed a bug that caused the hidden-tags feature to not work unless it was explicitly set in refind.conf. (It should have been enabled by default, and now it is.) - Fixed a bug (introduced in 0.11.1) that caused setting volumes in manual boot stanzas to fail. 0.11.1 (10/9/2017): ------------------- - Modified refind-install to be smarter about modifying NVRAM entries under Linux. It now re-creates existing rEFInd entries only if the existing entries don't point to the same location that rEFInd will use. - Modified the way rEFInd tracks boot loader files. This was made necessary by macOS 10.13/APFS, which was confusing rEFInd's old tracking code when it was compiled with GNU-EFI. Ideally, this will have no noticeable effect to end users; however, it's possible that some loaders will appear or disappear from the menu, or "file not found" errors when launching loaders will go away, after upgrading to this version of rEFInd. - Added support for new macOS boot loader locations used in macOS 10.13 ("High Sierra"). - Fixed bug that could cause hidden-tag maintenance tool to hang. - Fixed bug, introduced in 0.11.0, that caused the Apple and Microsoft recovery tools to not be detected. 0.11.0 (8/13/2017): ------------------- - Fixed lack of scaling of disk badges when other icons were properly scaled on HiDPI/retina displays. - Added new --encryptkeys option to refind-install, to improve the security of locally-generated Secure Boot keys stored on your computer's hard disk. - Fixed spoof_osx_version to work with newer Apple EFIs. - Added new mouse support: Uncomment enable_mouse in refind.conf to activate this support. You can select an OS to launch with this feature active, but you cannot use submenus via the mouse. The mouse_size and mouse_speed tokens control the mouse size in pixels and tracking speed, respectively. Note that not all computers support mice in their EFIs, which is why this feature is disabled by default. - Fixed bug that caused specifying a full path to the fallback boot loader (EFI/BOOT/bootx64.efi) in dont_scan_files to fail to work. - Added dont_scan_tools refind.conf token to enable hiding EFI tools. This feature overrides scantools -- if the latter includes, say, "shell", but the former includes "shell.efi", any shell called "shell.efi" will be ignored. As with dont_scan_files, you can specify a "bare" filename or a complete path. The point is to enable hiding redundant tools -- say, if multiple MokManager tools show up in the menu and you want just one. - A new feature enables you to hide OSes and external tool tags from the rEFInd main menu: Highlight the OS tag and hit "-" or the Delete key. The OS tag should disappear, and remain gone between reboots. A new tool tag (on the second row) with a recycling icon enables recovering OS tags hidden in this way. - You can now specify volumes by GUID number in dont_scan_dirs and dont_scan_files specifications -- e.g., "dont_scan_files 2C17D5ED-850D-4F76-BA31-47A561740082:\EFI\badloader\badloader.efi" to keep EFI\badloader\badloader.efi on the volume with a partition GUID value of 2C17D5ED-850D-4F76-BA31-47A561740082 off the menu. - I've removed support for the previously-deprecated volume-number style volume specifications (fs0:, fs1:, etc.). - Fixed bug in mvrefind that caused it to not move the EFI/BOOT-rEFIndBackup directory back to EFI/BOOT when renaming rEFInd in EFI/BOOT to something else. - The refind-install and mvrefind scripts now create a BOOT.CSV file in the rEFInd installation directory. The fallback.efi (aka fbx64.efi) program delivered with many distributions can use this file to re-create rEFInd's NVRAM boot entry should it be lost. Some distributions (such as Fedora) set up fallback.efi in the EFI/BOOT directory on the ESP, so it will run automatically if NVRAM variables are lost. All this said, there's no guarantee that rEFInd will be FIRST in the boot order should the NVRAM entries be lost. - Improved error messaging on Macs; most serious system errors should now be reported on-screen in graphics mode. - Fixed bug that caused Fedora/CentOS/RHEL "vmlinuz-0-rescue*" kernels to not be sorted down in the kernel list if they happened to be the first ones passed to rEFInd by the EFI. 0.10.9 (7/30/2017): ------------------- - The PauseForKey() function now works on Macs in graphics mode, which can help when some errors are encountered. (Most of the errors associated with this function still rely on Print(), which still doesn't work on Macs; but at least there will be a prompt to press a key.) - rEFInd now displays its background and banner before scanning for boot loaders, and displays a message that it's performing this scan. - Added support for HiDPI/retina displays: rEFInd now automatically scales icons and text to twice the normal size when the screen's horizontal resolution is above 1920. This does not occur in text mode (you must still select an appropriate text-mode resolution via the "textmode" option in refind.conf), and it can be overridden by explicitly setting the "small_icon_size", "big_icon_size", and "font" options in refind.conf. Note that icons are resized from their originals and so may look a bit chunky, by HiDPI standards; but rEFInd now embeds both 14- and 28-point fonts, so the fonts will look better. If the screen is HiDPI but 1920 pixels wide or less, the default icon and font sizes are used, so adjustment via refind.conf options may still be desirable. - Added os_trusty.png, os_xenial.png and os_zesty.png icons, for those who have multiple Ubuntu versions and want to distinguish them visually. - Updated LodePNG, which is used to load PNG images, to the latest version (20161127). - A new "edk2" target to "make" is available, which builds in the standard TianoCore way. This has the advantage over the "tiano" target of working with newer versions of EDK2, including the recently-released UDK2017 . (The "tiano" target maxes out at UDK2014.) - Improved compatibility with standard TianoCore-style build process; can now build rEFInd binary, gptsync, and drivers in the "TianoCore" way, in addition to by using Linux Makefiles. 0.10.8 (5/21/2017): ------------------- - Added shimx64.efi.signed as a valid Shim source filename, and mm{arch}.efi.signed as a valid MokManager source filename, to refind-install script. This enables users on Ubuntu to point to Ubuntu's signed Shim and MokManager files, which are stored in /usr/lib/shim under these odd filenames. - Fixed compile problems with GNU-EFI 3.0.5. - Added icon for Devuan GNU+Linux, based on the icon in the Devuan press kit (https://devuan.org/os/press/). - Minor code efficiency improvements. - Added ability to specify volumes by partition unique GUIDs in dont_scan_volumes. - Renamed "Mac OS X" to "macOS" in assorted messages, per Apple's re-branding with version 10.12 (Sierra). Unfortunately, I don't know of an easy way to tell which macOS version a given macOS boot loader will load, so it's one name or the other for everything. 0.10.7 (4/17/2017): ------------------- - Update refind-install to recognize and copy mmx64.efi as alternative name for MokManager. - Hide volume name "Recovery HD," if that's what it is, from loader description. This is done because some OS X users are getting confused and even upset over this detail, even though it's accurate, at least from an EFI/rEFInd point of view. - Fixed memory management bug (introduced in 0.10.6) that caused error messages to be displayed on some systems. 0.10.6 (4/16/2017): ------------------- - Fixed bug in drivers that could cause filesystems to not be registered, and perhaps other unknown problems. This manifested on 32-bit GNU-EFI compiles, but in principle it could cause problems on 64-bit or TianoCore builds, too. - Fixed bug in mvrefind that could cause it to fail to move the rEFInd installation because it incorrectly converted the target directory to an empty string if the target directory did not (yet) exist. - Added mm{arch}.efi as MokManager filename, and fb{arch}.efi to list of boot loaders to be ignored. - New refind.conf token: extra_kernel_version_strings, which sets strings that are treated something like digits for purposes of matching Linux kernel and initrd filenames. - Don't set the video mode if the computer is already running in the requested mode. This is a shot-in-the-dark attempt to fix problems with Mac "retina" displays, which tend to get bumped down to a lower resolution by rEFInd. 0.10.5 (3/4/2017): ------------------ - Two improvements to initrd detection for Linux kernels: - If multiple initrd files match the kernel's version number, the file with more matching characters after the version number is used, rather than the first initrd file found. - The "%v" string, if present in the refind_linux.conf file's second field, will be replaced by the kernel version number. Thus, you can specify options like: "Boot with standard initrd" "ro root=/dev/sda2 initrd=initrd-%v-std" "Boot with debug initrd" "ro root=/dev/sda2 initrd=initrd-%v-debug" This enables using multiple initrd files per kernel, to be used for different purposes. - Minor code optimization. - Add new key mappings: Backspace (Delete on Mac keyboards) works the same as Esc, and Tab works the same as F2/Insert/+. This is done for the benefit of new Apple laptops that lack physical Esc and function keys. - Fix to refind-install to work better with disks other than /dev/sd? and /dev/hd? devices. - Fixes to touch/tablet support to improve reliability. 0.10.4 (10/9/2016): ------------------- - Fixed compile problem for drivers with recent versions of GNU-EFI (3.0.4, maybe 3.0.3). - Fixed bug that could cause program crash on startup. (In practice, it manifested with GNU-EFI starting with version 3.0.3 or 3.0.4.) - An anonymous contributor has provided support for touch screens. This support requires that the "enable_touch" token be used in refind.conf. Note, however, that not all tablet computers have EFIs that provide the necessary support in the firmware. - Martin Whitaker contributed 64-bit support to the ext4fs driver, which makes it compatible with ext4fs as written by some recent Linux distributions. - Tweaked refind-install to do a better job of detecting disks other than /dev/sd? and /dev/hd? devices. 0.10.3 (4/24/2016): ------------------- - Altered RPM & Debian installation scripts so as to NOT call sbsign if Secure Boot is disabled. This is a response to Ubuntu bug #1574372 (https://bugs.launchpad.net/ubuntu/+source/sbsigntool/+bug/1574372): In Ubuntu 16.04, the sbsign program is segfaulting randomly, which prevents proper installation of the program. This change at least permits proper installation IF Secure Boot is disabled. - Changed description of BIOS/CSM/legacy OS loaders on Macs to include the string "(Legacy)", so as to more easily identify BIOS/CSM/legacy-mode OSes in the rEFInd main menu. - Added recognition of the fwupx64.efi file as a firmware update tool. This filename is excluded from the first-row launchers, and is instead presented on the second row, controlled by the "fwupdate" item on the "showtools" option line. It's enabled by default. Note that it's still a bit unclear to me how this tool is supposed to be used. rEFInd launches it with no options, but if it should take options, this will have to be changed in the future. - Tightened exclusion of shell binary filenames from boot loader scan. Previously, any filename containing the substring "shell" was excluded from scans. Now it's tighter; only files matching one of the filenames in the constant SHELL_NAMES in main.c are excluded. This change will enable programs with names that include "shell", but that aren't in rEFInd's SHELL_NAMES list, such as "shelly.efi", to be shown in the rEFInd main menu. - Fixed bug in NTFS driver that caused it to hang (and thus hang the computer) in some situations, particularly when a file on an NTFS volume had many fragments and when the computer's CSM was activated. (Fix courtesy of "S L.") - Modified SIP/CSR rotation code: If the csr-active-config EFI variable is missing AND the firmware is Apple (as identified by the string "Apple" being present in the ST->FirmwareVendor string), rEFInd treats the computer as one on which SIP is available and set to the "enabled" state (0x10). The upshot is that the SIP/CSR tool will appear if the showtools and csr_values options are set appropriately in refind.conf, even if the csr-active-config variable is missing from the NVRAM. The point of this change is that I've received reports of some Macs that run OS X 10.11 but that lack this variable. OS X acts as if SIP were enabled, but rEFInd is then unable to disable SIP. This change gives rEFInd the ability to disable SIP on such systems. The drawback is that the variable might be set on some systems that don't run OS X 10.11. This should be harmless from a technical point of view, but the presence of SIP indicators in rEFInd could be confusing. - Added refind-mkdefault script to simplify resetting rEFInd as the default boot program in Linux. The intent is to run this after GRUB, Windows, OS X, or some other tool takes over as the primary boot manager. It can be called from a startup script to handle this task automatically. 0.10.2 (1/26/2016): ------------------- - Fixed bug in refind-install that caused mountesp to be installed as a FILE called /usr/local/bin on OS X if the /usr/local/bin directory did not already exist. - Fixed bug in mvrefind that caused it to fail to move bootmgfw.efi in some situations, and another that caused it to give the resulting NVRAM entry the default rEFInd name of "rEFInd Boot Manager," rather than the intended "Windows Boot Manager" (to work around bugs in some EFIs). - Worked around bug/quirk in some EFIs (in HP ProBook 6470b laptop, at least) that prevented EFI filesystem drivers from working. (Drivers would load but not provide access to filesystems.) - Fixed refind-install bug that caused --usedefault option to not work in OS X. (This bug did not affect Linux.) - Improved Secure Boot detection in refind-install in Linux. - Fixed bug that caused custom volume badges (vol_*.png) to be read only from default location ("icons" subdirectory), effectively eliminating the ability to adjust them. - Added centos.crt and centos.cer public key files. 0.10.1 (12/12/2015): -------------------- - Change to PPA version: Installing the PPA now queries the user about whether to install to the ESP. Upgrades will remember the initial selection. - Modified time-based sorting of loaders in a single directory to push anything starting with "vmlinuz-0-rescue" to the end of the list. Fedora gives its rescue kernels filenames that begin with that string, and if such a kernel happens to be the most recent, treating it normally will cause it to become the default when kernel folding is in use. This is almost certainly undesirable, so this change keeps the rescue kernel at the end of the list instead, which is saner. - Significantly reworked the project's Makefiles. This should have no impact on ordinary users, and even most developers should barely notice it; but it should make future extensions to additional platforms or building in different environments easier. - Added workaround to gptsync for issue with some Macs' EFIs that caused the program to skip through all prompts, thus accepting the default option. This would normally cause gptsync to do nothing. - Added type code 53746F72-6167-11AA-AA11-00306543ECAC (Apple Core Storage, gdisk type AF05) to list of partition types recognized by gptsync. - Removed Luxi Sans Mono font, since I discovered it was not open source; and changed the default font from Nimbus Mono to Liberation Mono. - Added support for compiling rEFInd for ARM64 (aka AARCH64 or aa64). This works with both GNU-EFI and Tianocore UDK2014.SP1.P1. This support is currently poorly tested. In particular, I used QEMU on an x86-64 computer to create a virtualized ARM64 environment; I've not yet tested on a real computer. I couldn't get QEMU to create a video card, so I used a serial terminal, which means that the graphics features are untested -- I ran rEFInd with "textonly" uncommented in refind.conf. I've tested the ext4fs driver but no other drivers, although they all compile. (So does gptsync, although it's unlikely to be useful on ARM64.) Some rEFInd features are meaningless on ARM64, such as BIOS-mode boot support, anything geared toward Macs (csr_values/csr_rotate, spoof_osx_version, etc.), and enable_and_lock_vmx. - Fixed bug that caused rEFInd to fail to scan EFI boot loaders on removable media when rEFInd itself was launched from the fallback filename. - Moved detailed descriptions of refind-install from installing.html to a refind-install man page. To keep this information Web-accessible, I've also created HTML versions of the three man pages and linked them into the HTML documentation. - Updated LodePNG to latest version (20151024). - Fixed bugs in mkrlconf and in refind-install that could cause some kernel options to be excluded from refind_linux.conf. There were two trouble conditions: - Previously, these scripts assumed that the first option in /proc/cmdline was the kernel's filename, but this isn't always the case. (In particular, when gummiboot launches the kernel, this is not true. It might be an incorrect assumption in some other cases, too.) The fix involves checking for likely signs of a kernel filename before discarding this first option. - These scripts cut the "initrd=*" option from /proc/cmdline, but the call to "sed" was overzealous and cut until the end of input. This usually worked, since the initrd= option was usually last on the line; but if it wasn't, any options following initrd= would be lost. - Added "kernel*" as a matching pattern for Linux kernels, since this is what Gentoo uses by default. - The refind-install script can now be run as a symbolic link in Linux. This enables creating a /usr/sbin/refind-install link in Linux packages, with the binaries stashed wherever the package system likes them. This feature does NOT work in OS X, but there's relatively little need for it there. 0.10.0 (11/8/2015): ------------------- - Fixed bug that caused refind-install to not unmount the ESP when it should under OS X. - Modified refind-install and mkrlconf scripts to use /proc/cmdline as source for default boot options EXCEPT when refind-install receives the --root option. In that case, refind-install continues to use /etc/default/grub as the source of default options. The idea behind this change is that it's more reliable to get boot options from /proc/cmdline when the targeted system is the one that's booted; but --root would be used from emergency disks or live CDs, in which case the current boot options would be completely wrong, so extracting boot options from GRUB files is the best bet for getting close to the right options. - Added "@/boot" to default also_scan_dirs setting. This makes kernels show up on Btrfs volumes under Ubuntu (and perhaps others), at least when the Btrfs driver is loaded. - Added new System Integrity Protection (SIP) rotation feature for Macs running OS X 10.11 or later. This feature is disabled by default, except on CD-R and USB flash drive images, on which it's enabled. To enable it, you must make TWO changes to refind.conf: Uncomment the new "csr_values" item and add "csr_rotate" to the "showtools" line (uncommenting it, too, if it's commented out). If desired, you can set more values on "csr_values"; these are comma-delimited one-byte hexadecimal values that define various SIP states. When SIP/CSR rotation is activated, a new shield icon appears among the tools. Selecting it causes the next defined value to be set and a confirmation message to appear for three seconds. - Added display of current System Integrity Protection (SIP) mode to "About" display. - Added mountesp script for OS X to (you guessed it!) mount the ESP. - Renamed support scripts: install.sh to refind-install, mvrefind.sh to mvrefind, and mkrlconf.sh to mkrlconf. - New icons! The old ones were getting to be a jumbled mess of styles, particularly for OS tags. I used the AwOken icon set (http://alecive.deviantart.com/art/AwOken-163570862) for the core icons, then expanded from there by creating my own icons and modifying icons for Debian and Elementary OS. I'm also trying to keep better track of copyrights and licenses on icons. Between that and some icons being for OSes that probably see very little use (FreeDOS and eComstation, for instance), a few OS icons have been lost. If you prefer the old icons, you can continue to use them by upgrading rEFInd, renaming icons-backup to something else (say, icons-classic), and then adding an "icons" line in refind.conf to point to the old icons directory. - Changed from .zip to .tar.gz as source code archive format. I did this because Linux is the only officially-supported build platform, and tarballs are a more natural fit to a Linux environment. I'm leaving .zip, .deb, and .rpm files as the formats for binary packages. - Added detection of System Integrity Protection (SIP; aka "rootless") mode to OS X portion of install.sh script. When detected, and if no existing rEFInd installation is found, the script now prints a warning and brief instructions of how to enter the Recovery mode to install rEFInd and suggests aborting the installation. (The user can override and attempt installation anyhow.) If SIP is detected along with an existing rEFInd installation, the script moderates the warning and explains that an update of a working rEFInd will probably succeed, but that re-installing to fix a broken rEFInd will probably fail. - Added new "spoof_osx_version" token, which takes an OS X version number (such as "10.9") as an option. This feature, when enabled, causes rEFInd to tell a Mac's firmware that the specified version of OS X is being launched. This option is usually unnecessary, but it can help properly initialize some hardware -- particularly secondary video devices. OTOH, on some Macs it can cause hardware (notably keyboards and mice) to become unresponsive, so you should not use this option unnecessarily. - Worked around an EFI bug that affected my 32-bit Mac Mini: That system seems to have a broken EFI, or possibly a buggy CPU, that causes some (but not all) conversions from floating-point to integer numbers to hang the computer. Such operations were performed only in rEFInd's graphics-resizing code, and so would manifest only when icons or background images were resized. My fix eliminates the use of floating-point operations in the affected function, which eliminates the crashes. There may be some degradation in the quality of resized images, though, particularly on 32-bit systems. (64-bit systems use larger integers, which enable greater precision in my floating-point workaround.) - Under OS X, install.sh can now be run from the recovery system. This may help work around OS X 10.11's problems with System Integrity Protection, since it should be possible to reboot into the recovery system to install rEFInd without disabling SIP for the main installation, even for just one boot. 0.9.2 (9/19/2015): ------------------ - Added "--keepname" option to install.sh. This option causes install.sh to keep refind_x64.efi named as such rather than rename it as grubx64.efi when using Shim. This option is meaningful only if the --shim option is also used. This option passes the refind_x64.efi filename as an option to Shim, which overrides the default filename of grubx64.efi. A big caveat: Only Shim 0.7 and later supports this feature. (Shim 0.4 also works if a refind_x64.efi is referred to as "\refind_x64.efi" on the command line, but the need for a leading backslash to refer to a file in the same directory as Shim is so confusing and wrong that I cannot in good conscience support it.) I've not seen signed Shim binaries between 0.4 and 0.7, so I don't know if any of them might work. - Implemented a workaround for a bug in Shim 0.8 that prevented authentication of more than one binary. If any filesystem drivers were installed, the first one would be verified, leaving rEFInd unable to launch anything else unless it was signed by a key in the computer's main Secure Boot db list. 0.9.1 (9/13/2015): ------------------ - When rEFInd identifies the root (/) partition via the Freedesktop.org Discoverable Partitions Specification, it now checks two of the partition's attributes, as per the DPS (see http://www.freedesktop.org/wiki/Specifications/DiscoverablePartitionsSpec/): - The partition's read-only attribute determines whether to pass a "rw" or "ro" option to the kernel. - If the partition's do-not-automount flag is set, rEFInd will not pass it as a "root=" option to the kernel. This flag can be used to remove all but one partition from consideration as a root (/) partition if a system has more than one with the correct type code. - Improved Freedesktop.org Discoverable Partitions Specification support: Previously, if no refind_linux.conf file was present but an /etc/fstab file was found, rEFInd ignored the Discoverable Partitions Specification filesystem-type codes. This was fine if /etc/fstab contained a valid "/" filesystem specification, but if that was absent, the result was no "root=" specification being present. Under these circumstances (refind_linux.conf absent, /etc/fstab present but lacking a "/" entry), rEFInd now tries to identify a device to specify as "root=" via the Discoverable Partitions Specification. - Fixed bug that caused "Found match!" and a prompt to press a key to continue to be printed if any partition used the Freedesktop.org Discoverable Partitions Specification root-partition GUID. (This was leftover debugging/testing code that I somehow missed deleting.) - Added icon for Elementary OS. - Added /etc/lsb-release to files scanned for clues about the Linux distribution. This file differentiates Mint and Elementary OS from Ubuntu better than does /etc/os-release, and may also help with other closely-related distributions. - Improvements to handling of case-insensitive string comparisons. These are buggy on some EFIs, and such bugs affect things like dont_scan_* blacklists, removal of rEFInd's own directory from scanning, matching of keyword names in refind.conf, and even loading of icons. I've replaced many calls to problematic functions with safer calls, which should help a lot. There may still be problems on some systems with some computers, though; as far as I can tell, the bugs are buried deep in some EFI firmware, so I can only replace some of the most direct calls to potentially buggy system calls. 0.9.0 (7/26/2015): ------------------ - New icon for Kali Linux, submitted by Francesco D'Eugenio. - Minor code changes to ensure that rEFInd compiles with GCC 5.1. (Tested with GNU-EFI on a Fedora 22 system; not yet tested with the TianoCore EDK2.) - Added new "fold_linux_kernels" token to refind.conf. This option, when active (the default) "folds" all Linux kernels in a directory into a single entry on the rEFInd menu. The kernel with the most recent time stamp is launched by default. To launch another kernel, you must press F2 or Insert; additional kernels appear as options on the first kernel's submenu. To see the pre-0.9.0 behavior, you must set "fold_linux_kernels false" (or one of its synonyms, "off" or "0"). The point of this option is to help de-clutter the rEFInd main menu. - Added new Linux root (/) partition auto-discovery feature, based on Freedesktop.org's Discoverable Partitions Spec (DPS) (http://www.freedesktop.org/wiki/Specifications/DiscoverablePartitionsSpec/): If no refind_linux.conf file or /etc/fstab file is found, and if a partition with the correct DPS type code for the system architecture is found, rEFInd adds "ro root=/dev/disk/by-partuuid/{GUID}" to the kernel options. This will not help on LVM setups, and will get it right for only one installation on systems with multiple Linux installations, but it may help some users, if/when the DPS type codes become more common. - Fixed bug that caused a rEFInd crash if an empty refind_linux.conf file was encountered. - The mkrlconf.sh script now checks the OS on which it's running, which should help avoid confusion or problems by users who mistakenly run it under OS X. - rEFInd now skips checking for various BIOS-mode boot sector signatures when running on a UEFI-based PC; these checks are run only on Macs. This may reduce startup time on systems with many partitions. - Fixed Debian debinstall script to work correctly on IA32 systems. It had a bug that caused filesystem drivers and gptsync to not be packaged for IA32. - Modified Debian postinst file to call install.sh with --localkeys option if sbsign and openssl are available, even when NOT in Secure Boot mode or if shim is not detected. This helps with my Ubuntu PPA when using custom Secure Boot keys, since the PPA is delivered unsigned. (Users will have to have added their own local keys to their firmware's db.) For consistency, I've made the same change to the RPM .spec file. 0.8.7 (3/1/2015): ----------------- - Fixed install.sh bug that caused inappropriate installation under the name bootx64.efi (or bootia32.efi) under Linux, with a failure to update the boot entries in NVRAM, has been fixed. - Added identification of XFS as filesystem type in volume descriptions. - More fixes to filesystem type detection code. Previous version sometimes identified FAT or NTFS (or anything with a boot loader) as a whole-disk device rather than the correct filesystem type. - Added protections to the code to reduce the risk of crashes that might occur when dereferencing NULL pointers in various situations. - I'm deprecating the use of filesystem numbers (as in "fs0:") because they're unreliable -- filesystem numbers can change between boots and might not be the same as those used in an EFI shell or other program. Sooner or later I'll remove code supporting this feature. In the meantime, if it doesn't work for you, please switch to using filesystem labels, partition labels, or partition GUIDs. - Added detection of FreeBSD's BIOS-mode GPT boot loader. Previously, rEFInd could detect FreeBSD's BIOS-mode MBR boot loader, which gave FreeBSD an appropriate icon on Macs; but the BIOS-mode GPT boot loader code is different, so some recent FreeBSD installations showed up with generic grey diamond icons. This change creates FreeBSD icons instead. - Added "Secure Boot [active|inactive]" notice to "about" menu for x86 (32-bit) systems, since there are now a few 32-bit UEFI systems that support Secure Boot. (AFAIK, these are mostly tablets and convertibles such as the ASUS T100.) - Added KeyTool.efi and KeyTool-signed.efi to list of MOK managers. KeyTool is the "super-deluxe" Secure Boot key and hash manager provided as part of the efitools package. - Fixed more instances of "invalid parameter" errors on some EFIs. - Improved Secure Boot detection in install.sh. - install.sh should no longer complain when copying Shim or MokManager over itself. 0.8.6 (2/8/2015): ----------------- - Removed special case of ignoring an HFS+ name of "HFS+ volume", since the old rEFInd HFS+ driver that produced this name for all HFS+ volumes has long since been updated to deliver a real name. - Addition of new Windows 8 OS icon. On Macs and for BIOS/legacy boots, the new icon is now used for Windows Vista, 7, and 8, while the old one is used for earlier versions of Windows. For EFI-mode boots, the new icon is used universally. - If the NTFS driver is loaded, rEFInd now scans NTFS volumes on Macs for the presence of Windows boot files, and removes any NTFS volume that lacks such files from the BIOS/legacy boot list. This should help unclutter the display on Macs that contain NTFS data partitions. - Fixed bug that caused misidentification of both whole disks and NTFS volumes as being FAT. (This bug affected the identification of devices and locations in the rEFInd menu, not actual access to devices.) - Code refactoring to clear out legacy-boot functions from the ever-expanding refind/main.c file. - Added new "badges" option to the "hideui" token in refind.conf. This option hides the device-type badges associated with the OS boot options. - Reverted rEFIt commit r472, introduced in rEFInd 0.8.5 to support more BMP images because I've received bug reports that it's causing existing selection images to fail to load. - Fixed install.sh bug that caused misidentification of installation directory under OS X if an already-mounted ESP has spaces in its path. - Fixed Mac-specific install.sh bug that could cause misidentification of the ESP on disks with partition numbers of 10 or above. 0.8.5 (2/1/2015): ----------------- - Added NTFS EFI filesystem driver. - Minor improvements to filesystem driver framework code. - Changes to - Fixed bug in Btrfs driver's address reference. - Improved install.sh to make it smarter about figuring out where to install on Macs. Specifically, this version now upgrades existing installations, if found (as it always has under Linux), rather than blindly install to EFI/BOOT; it installs to EFI/refind if not existing installation is found; it installs using the --shortform option to bless, which seems to eliminate the 30-second delay problem; and it can handle an HFS+ ESP, which it treats as a separate HFS+ volume (as if the user had used --ownhfs). These changes do not affect behavior under Linux. - Added missing check of architecture type for several tools. - Applied rEFIt commit r472, which adds support for BMP images with negative height fields, indicating that the image is NOT vertically flipped. This commit and r467 were not incorporated in the original rEFInd because I forked it from a Debian rEFIt package that had been patched to build under GNU-EFI, and was apparently based on a slightly earlier version. - Applied rEFIt commit r467, which improves Mac handling of legacy boots from other than the first hard disk. 0.8.4 (12/8/2014): ------------------ - Tweaked default for dont_scan_volumes: Removed "Recovery HD". This change better suits the needs of OS X 10.10 ("Yosemite") installations, but may result in some stray Recovery HD entries on some Macs. - Updated icons for Fedora and Ubuntu and added an icon for Xubuntu. - Added new configuration option, "enable_and_lock_vmx", which sets an Intel CPU feature that's required for some types of virtualization to work. Most EFIs enable setting this feature in their own setup utilities, but some (such as most Macs) don't. - If rEFInd can't locate an icons directory (either the default or one specified by the icons_dir token), the program switches to text-only mode. - If a loader contains the string "grub" and no other clue to the loader's OS association exists, search for os_grub.{png|icns} (which is not provided with rEFInd) or os_linux.{png|icns}. (Previous versions provided a generic loader icon for GRUB.) - Fixed bug that caused dont_scan_files to not work with special-case boot loaders (for OS X and Windows) when specifying the complete path to the loader (e.g., EFI/Microsoft/Boot/bootmgfw.efi). - Added support for the iPXE network boot tool (see BUILDING.txt for building and basic use instructions). 0.8.3 (7/6/2014): ----------------- - Added new feature: Setting "timeout = -1" in refind.conf causes rEFInd to immediately boot the default option UNLESS a keypress is in the buffer when rEFInd launches. In that case, if the keypress corresponds to a shortcut key, the associated boot loader is launched; or if not, the menu is displayed. - Added new icons for Clover boot loader and for Mythbuntu Linux distribution. - rEFInd now displays the partition's label, when one is available, when offering a BIOS-mode boot option for a partition with no filesystem driver. This works only on Macs doing BIOS-mode booting. - Removed GPLv2 code from the FSW core files. This was done because the Btrfs driver is derived from the GRUB Btrfs driver, which is licensed under the GPLv3. Ironically, the GPLv2 and GPLv3 are incompatible licenses, so ensuring that the Btrfs driver doesn't rely on GPLv2 code was legally necessary. In most cases, I reverted to the original rEFIt code, although I kept my own cache code; since I wrote it, I can change its license to a BSD license. - Fixed bug that caused rEFInd to unload drivers immediately after loading them. This didn't affect rEFInd's own drivers because they didn't include the unload hooks, but it did affect some other drivers. - Changed default scan_all_linux_kernels setting from "false" to "true", and commented the option out in refind.conf-sample. This should not affect most people, since refind.conf-sample had this option commented out, and most rEFInd users either use it that way or don't have Linux kernels installed at all. I've made this change because I want rEFInd to "do the right thing" by default in as many cases as possible. For a while now, rEFInd has been excluding non-bootable files from its menu, and most kernels "in the wild" now include the EFI stub. Thus, enabling this support by default seems worthwhile. If you prefer to not scan Linux kernels by default, simply uncomment the "scan_all_linux_kernels" line and ensure it's set to "false". 0.8.2.1 (6/8/2014): ------------------- - Removed stray bit of debugging code that caused a prompt to press a key to appear at rEFInd startup. 0.8.2 (6/8/2014): ----------------- - Changed behavior when default_selection is not set: It now boots the previously-booted loader, assuming it's still available; if not, rEFInd boots the first loader (as it does now). Behavior is unchanged if default_selection is set. Note that this behavior depends on the ability of rEFInd to store an EFI variable in NVRAM. It therefore fails on systems with flaky NVRAM storage. You can view the previously-booted loader in the /sys/firmware/efi/efivars/PreviousBoot-36d08fa7-cf0b-42f5-8f14-68df73ed3740 variable under Linux. - Added icon for Mageia Linux (os_mageia.png). - Fixed bug that could misidentify a not-quite-GUID as a GUID in a manual boot stanza's "volume" line. - I've updated my personal build system, and therefore the rEFInd Makefiles and related files, to use TianoCore UDK2014 rather than UDK2010. - Added "deep_uefi_legacy_scan" token. When not set (the default), rEFInd does not modify EFI NVRAM settings when scanning for BIOS-mode boot loaders on UEFI-based (non-Mac) computers. Some computers require uncommenting this setting for rEFInd to reliably detect some BIOS-mode boot devices. Passing "0", "off", or "false" as an option resets it to the default value (useful in a loaded secondary configuration file to override a setting in the main file). 0.8.1 (5/15/2014): ------------------ - Fixed bug that could cause rEFInd to fail to detect boot loaders stored on the root directory of a partition. - Added two new bitmap fonts to those distributed with rEFInd: Ubuntu Mono and Nimbus Mono. Both come in 12-, 14-, 16-, and 24-point sizes. - Messages about pauses for scanning and re-scanning of boot loaders are now suppressed when doing an initial delayed scan when scan_delay is 1 second. - Improved centering of legacy boot option descriptions on some systems' screens. - Fixed bug that could cause a BIOS-mode boot to boot from an inappropriate device if that device had an innately high boot priority (as set by the firmware). - Changed icons from ICNS to PNG form. There are several reasons to do this, all of them minor; but together they're enough to warrant a change. PNG is more common, and therefore more accessible to most users -- particularly those who don't use OS X. The PNG files are smaller than their ICNS equivalents. PNG supports a wider range of sizes (although I'm not now using anything that ICNS doesn't support, I might in the future). The icon-scaling support added a few versions ago makes ICNS's support for multiple icon sizes relatively unimportant. - Reversed order of search for icons by extension: rEFInd now searches for PNG files before ICNS files, rather than the other way around. This makes it possible to override a volume icon for rEFInd by giving it the name .VolumeIcon.png, even when a .VolumeIcon.icns file exists on the volume and is used by OS X. - Fixed bug that caused .VolumeIcon.icns to take higher-than-intended precedence in icon setting for OS X. - Chainloading to BIOS-mode boot loaders now works on UEFI-based PCs when rEFInd is built with GNU-EFI, not just when built with Tianocore. 0.8.0 (5/4/2014): ----------------- - The "dont_scan_volumes" parameter now also works with legacy-boot volumes. Unlike with EFI volumes, where the option you pass must exactly match an entire volume name, when applied to legacy-boot volumes, it matches any part of the description that appears beneath the item when you select it in the rEFInd main menu. - Can now boot in legacy mode from second (and probably later) hard disks! - rEFInd now limits the length of the firmware name string shown in the system information screen to 65 characters. This is done because at least one EFI presents a longer string by default, and this causes the entire information display to come up empty on 800x600 displays. - rEFInd now uses the partition's name (as stored in the GPT data structures) as a fallback for the filesystem's name if the latter can't be found. Exceptions are if the partition name is one of three generic names used by GPT fdisk: "Microsoft basic data", "Linux filesystem", or "Apple HFS/HFS+". These are ignored in favor of the descriptive fallback (e.g., "20 GiB Btrfs volume") - It's now possible to specify a volume by partition GUID number in a manual boot stanza. This should be more reliable (albeit also more awkward) than using a filesystem number (such as fs0: or fs1:). - Fixed memory-allocation bug that could cause error message displays, and possibly hangs, when re-scanning boot loaders. 0.7.9 (4/20/2014): ------------------ - Attempt to fix rEFInd perpetually re-scanning after ejecting a disc on some Macs. - Added check to remove redundant (or non-functional if Secure Boot is active) kernel entries for Ubuntu, which is now including two versions of kernels, one signed and the other unsigned. - Fixed bug in install.sh that could cause it to display error messages if the dmraid utility was not installed. - The HFS+ driver now reports a correct volume name. - Fixed some EFI filesystem driver bugs that could cause lockups under some circumstances. These bugs could affect any of the filesystem drivers. - Added "gdisk" option to the "showtools" configuration file token. When active, this adds gdisk.efi or gdisk_{arch}.efi, if present in the EFI\tools directory, to the tools row. - Fixed mistaken identification of the MOK utility as the "MOK utility utility." 0.7.8 (3/9/2014): ----------------- - Added "debian" directory to source, which facilitates creation of Debian packages. Packages built in this way are built with GNU-EFI and don't run any post-installation script, so although the rEFInd binaries are on the hard disk, they aren't installed to be bootable; you must manually run install.sh. Also, at least on Ubuntu, the Make.common file's /usr/lib64 references must be changed to /usr/lib. This is more of a proof of concept and a "leg up" for distribution maintainers than anything else. - Two new options, big_icon_size and small_icon_size, set the size of the first-row OS icons and of the second-row tool icons, respectively. The big_icon_size option also indirectly sets the size of disk-type badges; they're 1/4 the size of the big icons. Default values are 128 and 48, respectively, to match the actual icon files provided with rEFInd. If the icon you're using is of a different size than you've specified, rEFInd scales it. For best quality, you should both provide icons drawn to the right size and set the icon sizes in refind.conf. - rEFInd now automatically scales icons to fit the standard icon sizes. This won't have any effect with the icons that come with rEFInd, but it can help if you want to use another icon, since you needn't scale it in a graphics program before using it. Note that rEFInd uses bitmap icons, so scaling by a huge amount (say, a 16x16 icon to fit the standard 128x128 OS icon) is not likely to look good. - Added new option, banner_scale, that tells rEFInd how to handle banners: Set to "noscale" (the default), banners are not scaled, although they'll be cropped if they're too big for the display. This is the same as the behavior in previous versions. Set to "fillscreen", rEFInd now scales the banner image (larger or smaller) to fill the display. - Adjusted the post-installation script in refind.spec (used to generate RPMs, and therefore also indirectly Debian packages) to search for existing shim program files under the filesnames shim.efi and shimx64.efi rather than just shim.efi. Ubuntu uses shimx64.efi, so Debian packages were failing to detect Ubuntu's shim in previous versions. (Note, however, that Ubuntu's early shim 0.1 is unsuitable for use with rEFInd The newer 0.4 version that's in the repositories now should work fine; it's only when installing on an older system that's NOT been updated that problems might arise. 0.7.7 (1/3/2014): ----------------- - Can now specify complete paths, optionally including volumes, in dont_scan_files. - Added shimx64.efi to the default dont_scan_files list. - Added windows_recovery_files token, to specify what program(s) launch a Windows recovery utility; and the "windows_recovery" option to "showtools," to control whether or not to display the Windows recovery utility on the second row of icons. - The use_graphics_for, also_scan_dirs, dont_scan_dirs, dont_scan_files, and scan_driver_dirs tokens in refind.conf now support "+" as the first option, which causes the remaining options to be added to the default value rather than replacing that value. (This has no practical effect for scan_driver_dirs, though, since it has a null default value.) - Added support for specifying the configuration file at program launch, via the "-c" parameter, as in "refind_x64.efi -c foo.conf" to use the foo.conf file as the main configuration file. - Scans of ext2/3/4fs and ReiserFS partitions now omit partitions with duplicate filesystem UUIDs. These are likely parts of RAID arrays and so would have the same boot loaders or kernels as the first one with a given UUID. - Added feature in install.sh: Script now tries to locate and mount an ESP in Linux, if it's currently unmounted. - Fixed bug in mkrlconf.sh and install.sh that caused a stray line break and PARTUUID= specification to appear in generated refind_linux.conf file under some circumstances. 0.7.6 (12/15/2013): ------------------- - Added support for multiple "default_selection" targets. These MUST be comma-separated AND enclosed in quotes, as in: default_selection "fred,ginger" This example will launch "fred" by default if it's available; and if it's not, rEFInd will attempt to launch "ginger" as the default. - Added support for time-sensitive "default_selection" setting. This token may now have either one or three options. If one, it's interpreted as it has been in the past, as setting a default that's independent of times. If you follow this default by two times, however, those are interpreted as the start and end times (in 24-hour format) for a default setting. For instance, "default_selection foo 8:00 17:00" causes foo to be the default from 8:00 (AM) to 17:00 (aka 5:00 PM). You can include multiple "default_selection" lines to set different defaults for a variety of times. If they're in conflict, the last one takes precedence. Note that times are hardware clock's native value, which may be local time or UTC, depending on your computer. - Added support for a blank-screen startup: Set "screensaver -1" and the screen saver will be initialized when rEFInd starts. If you set a low "timeout" value, the result will be a boot straight to the default OS unless you hit a key soon after rEFInd starts. Once you hit a key, the screensaver will be disabled. - Added --ownhfs {target} option to install.sh. This option causes rEFInd to install to an HFS+ partition in a way that's more consistent with the way the Mac's native boot loader is installed. Note that you should NOT install to an already-bootable partition with this option, since it will overwrite the existing boot loader, which would render OS X unbootable. 0.7.5 (11/10/2013): ------------------- - Fixed bug that caused unbootable exFAT partitions to show up as bootable on Macs with BIOS/CSM/legacy boot options enabled. - Fixed bug in install.sh that caused installs to the ESP on recent versions of OS X to fail. - Fixed bug that caused rEFInd to hang on some Macs when multiple EFI drivers were present. - Fixed bug that caused clear to default gray screen when launching OSes with 'use_graphics_for' enabled, even when the rEFInd background is not gray. Now rEFInd clears to the same background color used in its menu. When launching OS X, though, the OS X boot loader will itself clear to gray a second or so later; and when launching Linux, it will clear to black a second or so later. 0.7.4.1 (8/25/2013): -------------------- - My initial 0.7.4 release broke legacy-boot ability on Macs, so I quickly released this version using the original 0.7.4 filenames to fix the problem. 0.7.4 (8/25/2013): ------------------ - Fixed options passing to loader to include loader's filename as the first option. This omission had no effect on most boot loaders, but caused VMware's mboot64.efi to fail. - Added support for memtest86 as second-row option. Program must be stored in EFI/tools, EFI/tools/memtest, EFI/tools/memtest86, EFI/memtest, or EFI/memtest86; and must use the name memtest86.efi, memtest86_x64.efi, memtest86x64.efi, or bootx64.efi (changing "x64" to "ia32" on IA-32 systems). The memtest86 program is scanned for when the "showtools" option includes the "memtest" or "memtest86" token, which it does by default. - Added space to end of "Boot %s from %s" string; enables adding a space to the end of the "default_selection" item (in quotes) to set a default that matches a volume name that's identical to another one except for extra characters at the end of the non-wanted volume's name. - Fixed bug that could cause rEFInd to hang when launching boot loaders under some conditions. (Launching from Firewire drives on Macs is the known case, but there may be others.) 0.7.3 (8/7/2013): ----------------- - Fixed bug that caused missing media-type badges on BIOS-mode boot loaders on Macs. - Fixed bug that caused failure when launching BIOS-mode OSes on Macs. 0.7.2 (8/6/2013): ----------------- - Fixed bug that caused display glitches in the final entry on the first row of icons if the second row of icons was empty. - Fixed bug that could cause incorrect scanning or even a rEFInd crash when using volume specification in also_scan_dirs token. - Added protection against loading invalid drivers and other EFI programs. (Some EFIs crash when attempting to load such drivers and programs.) - Added PreLoader.efi and shim-fedora.efi to default dont_scan_files list; it's now "shim.efi, shim-fedora.efi, PreLoader.efi, TextMode.efi, ebounce.efi, GraphicsConsole.efi, MokManager.efi, HashTool.efi, HashTool-signed.efi". - Added icon for Funtoo Linux. - Fixed reading of volume badges from user-specified icons directory, which was broken. - Fixed handling of /.VolumeBadge.icns (or /.VolumeBadge.png) files, which was broken. 0.7.1 (7/8/2013): ----------------- - Fixed build problem with recent development versions of EDK2. - Added scan for Boot Repair's backup of the Windows boot loader (bkpbootmgfw.efi). If found, give separate entries for it and for bootmgfw.efi, each with its own descriptive text label. - Fixed also_scan_dirs; used to have bug that caused it to ignore volume specification, if present. - Fixed bug in driver cache that caused Btrfs driver to hang sometimes. 0.7.0 (6/27/2013): ------------------ - Added Btrfs signature to rEFInd, so that it can identify the filesystem type for volumes that lack labels. - Changed some critical filesystem driver pointers from 32-bit to 64-bit. This *SHOULD* enable use of over-2TiB filesystems (for those filesystems that support such large volumes). This capability is largely untested, though. - Added a cache to the filesystem driver core, and therefore to all the filesystem drivers. This cache greatly improves performance in VirtualBox, and offers modest performance improvements on a few "real" computers. The most dramatic improvement is on ext2/3fs under VirtualBox: Loading a kernel and initrd used to take ~200 seconds on my system, but now takes ~3 seconds! On most "real" hardware, the improvement is much less dramatic -- an improvement of a second or less, presumably because of cacheing within the EFI or on the hard disk itself. - Filter boot loaders based on a test of their validity; keeps out Linux kernels without EFI stub loader code, loaders for the wrong architecture, non-EFI loaders, etc. - New Btrfs driver, contributed by Samuel Liao based on GRUB 2.00 Btrfs code. 0.6.12 (6/18/2013): ------------------- - Changed the 64-bit EFI shell included in the CD-R and USB flash drive images to a version 2 shell that should support the "bcfg" command. - Added support for PreBootloader to refind.spec's built-in installation script. - Added support for the Linux Foundation's PreLoader to install.sh. It's treated just like shim, including using the --shim option (or, now, --preloader); but it searches for and copies HashTool.efi rather than MokManager.efi, and filenames are adjusted appropriately. - Added code to determine Linux root filesystem from /etc/fstab file, if it's on the same partition as the kernel and if the refind_linux.conf file is not available. This enables rEFInd to boot Linux without any rEFInd-specific configuration files on some (but not all) systems. 0.6.11 (5/13/2013): ------------------- - New feature: rEFInd now ignores symbolic links to files on filesystems that support them. This prevents the "vmlinuz" symbolic link that some distributions create in the root directory from appearing in the loader list. Note that this does NOT affect symbolic links to directories. - Added icons for Lubuntu and Kubuntu. - Improved the install.sh script so that it does a better job dealing with directory names that contain spaces. - rEFInd now tries to guess the Linux distribution type based on the kernel filename (Fedora and RHEL only) or the "ID" or "NAME" variables in /etc/os-release on the kernel's partition. None of these is guaranteed to work. A fallback of the Tux penguin icon remains in place in case rEFInd can't find anything substantive enough for a guess. - Added "EFI\opensuse" to the locations searched for MOK utilities, since OpenSUSE now uses that name. - Renamed "Reboot to Firmware User Interface" to "Reboot to Computer Setup Utility" in menu. - Fixed bug in gptsync that caused it to hang if the disk had too few GPT partitions to fill the MBR. 0.6.10 (5/5/2013): ------------------ - Added support for "screensaver" token. If set to a positive integer, this causes the screen to blank after the specified number of seconds of inactivity. Pressing most keys (unfortunately NOT including Shift, Alt, or Ctrl) will restore the display and restart the screen saver timeout. - Added icon for ChromeOS (os_chrome.icns in the icons subdirectory). ChromeBooks reportedly boots using the fallback filename, but if a user wants to install rEFInd on a ChromeBook, renaming the original EFI/BOOT directory to EFI/chrome and then installing rEFInd in the fallback filename will bring up this new icon for ChromeOS. - Added new option to reboot the computer into the firmware's user interface. This option is active by default, or can be set via the "firmware" option to the "showtools" token in refind.conf. It works on only some computers, though; older computers lack this feature, and when rEFInd is told to use this feature on such computers, the directive is quietly ignored. - Upgraded LodePNG library from version 20121216 to 20130415 and restructured rEFInd-specific modifications to simplify future upgrades. - Replaced hexadecimal error code with description if an error is encountered when saving a screen shot. - Enable multiple screen shots: Rather than naming all screen shots "screenshot.bmp", the name is now "screenshot_###.bmp", where "###" is a sequence number, starting with "001". 0.6.9 (4/25/2013): ------------------ - Modified default banner to include the new rEFInd icon, provided by Erik Kemperman. - Worked around a suspected firmware bug that caused rEFInd 0.6.6 to 0.6.8 to hang at startup on some systems (DUET and some Macs). - Modified rEFInd to search for gptsync under the names gptsync.efi and gptsync_{arch}.efi, where {arch} is ia32 or x64. (Previous versions searched only for gptsync.efi.) - Added gptsync program from rEFIt project, but with some changes to improve flexibility and make it less likely that UEFI users will accidentally trash their systems. - Changed timeout code so that the timeout continues if the keyboard is disconnected. This can help in booting a headless server or a system with a bluetooth or other keyboard that's not recognized by the EFI. 0.6.8 (3/18/2013): ------------------ - Added workaround for presumed EFI bug that was causing "Invalid Parameter" errors when scanning for boot loaders on some computers. - Added search for an EFI shell called shell.efi in the root directory (previously this name was only accepted in EFI\tools). - Fixed bug in install.sh that caused it to fail on some systems (Fedora 18, for instance) because of a problem identifying the ESP. - Fixed bug that caused icons named after boot loaders to not be used. 0.6.7 (2/3/2013): ----------------- - Added a more explicit error message summarizing options when a launch of a program results in a Secure Boot failure. - Changed MOK tool detection to scan all volumes, not just the rEFInd home volume. This is desirable because the Linux Foundation's HashTool can only scan its own volume, making it desirable to place copies of this program on every volume that holds EFI boot loader binaries. - Added support for launching the Linux Foundation HashTool as a means of managing MOKs (or MOK hashes, at any rate). - Fixed bug that caused rEFInd to present an entry for itself as a Microsoft OS if it was launched as EFI/Microsoft/Boot/bootmgfw.efi. - Fixed bug that caused dont_scan_volumes option to be added to also_scan_dirs list. - Fixed dont_scan_volumes so that it works with OS X boot loaders. - Fixed broken mixing of PNG and ICNS icons when using a user-specified icons directory -- previously, an ICNS file in the default directory would override a PNG file in the user-specified directory. 0.6.6 (1/26/2013): ------------------ - rEFInd now ignores the fallback boot loader (EFI/BOOT/bootx64.efi or EFI/BOOT/bootia32.efi) if it's identical to another boot loader on the same volume. This is intended to help unclutter the display on systems that run Windows, since Windows tends to duplicate its own boot loader under the fallback name. - Added new "font" token to refind.conf, which enables specifying a font in the form of a PNG file. This file must contain monospace glyphs for the 95 characters from ASCII 32 to 126 (space through tilde), inclusive, plus a glyph to be displayed for characters outside of this range, for a total of 96 glyphs. - Replaced the old font (inherited from rEFInd) with an anti-aliased version of Luxi Mono Regular 14 point. - Fixed bug that caused rEFInd to ignore manual boot stanzas in files included via the "include" token in refind.conf. - Fixed bug that caused ASSERT error on some systems (and conceivably a crash on startup on some) when default_selection line in refind.conf was commented out or empty. - Fixed bug that caused "Binary is whitelisted" message to persist on screen after loading MOK-signed drivers in Secure Boot mode. - Fixed bug that caused rEFInd to ignore the "icon" token in refind.conf manual boot stanzas. - Fixed bug in install.sh that caused the script to fail to update drivers when rEFInd was installed in EFI/BOOT/. 0.6.5 (1/16/2013): ------------------ - Improved text color support: rEFInd now uses black text against light backgrounds and white text against dark backgrounds. - Added support for PNGs as banners, icons, and selectors. - Added icon for ALT Linux. - Added "safemode" option to "hideui" token, to hide option to boot into safe mode for OS X ("-v -x" option to boot.efi). - Added icon for Haiku (os_haiku.icns). - Enable transparency of icons & main-menu text when the banner icon is sized to cover these areas. - Fixed bug that could cause rEFInd to crash if fed a banner image that's too big. Note that "too big" can be substantially smaller than the screen resolution! 0.6.4 (1/8/2013): ----------------- - Revised install.sh to copy ext2fs driver, rather than ext4fs driver, for ext2/3 filesystems. This can help keep non-functional entries from links from /vmlinuz to /boot/vmlinuz out of the menu if the system uses ext4fs on root and ext2fs or ext3fs on /boot. - Fixed a couple of memory management bugs that cause rEFInd to hang at startup on some systems. 0.6.3 (1/6/2013): ----------------- - Added the ability to specify a volume name or number in the "dont_scan_dirs" and "also_scan_dirs" tokens. - Fixed a bug that caused removable EFI media to not appear in scan lists if rEFInd was installed as EFI/BOOT/boot{arch}.efi on a hard disk. - Modified ISO-9660 driver so that it can handle discs with other than 2048-byte sectors. This makes it useful for reading "hybrid ISO" images burned to USB flash disks. - New mvrefind.sh script to move a rEFInd installation between a standard location (typically EFI/refind) and one of the fallback locations (EFI/BOOT or EFI/Microsoft/Boot). It can also do more exotic locations. - The install.sh script now installs to EFI/BOOT/bootx64.efi or EFI/Microsoft/Boot/bootmgfw.efi if it's run in BIOS mode. This is intended to give some chance of producing a bootable installation should a user accidentally install Linux in EFI mode and then install rEFInd from that installation. - The install.sh script now tries to find an existing rEFInd installation and upgrade it, even if it's in EFI/BOOT or EFI/Microsoft/Boot rather than in EFI/refind. - New "--yes" option to install.sh to help with unattended or automated installations (as from an RPM or Debian package). 0.6.2 (12/30/2012): ------------------- - Inclusion of a sample refind.spec file for the benefit of RPM distribution maintainers who might want to include rEFInd. It's a bit rough, but it gets you a good chunk of the way there.... - The EFI filesystem drivers can now be built with the GNU-EFI toolkit as well as with the TianoCore EDK2. See the BUILDING.txt file for details on how to build them with either toolkit. This improvement doesn't affect users of my binary packages, but it should make it easier for Linux distributions to adopt rEFInd into their package systems. - Tweaked refind.inf file for better build results using "native" TianoCore EDK2 build process (vs. the Makefile-based build process that I use under Linux). This won't affect those who use my binary builds or build under Linux with the "make" command. - Fixed bug that prevented Secure Boot launches from working when rEFInd was built with GNU-EFI rather than the TianoCore EDK2. - Substantial reworking of Secure Boot code, based on James Bottomley's PreLoader program. This new code eliminates the limitation of launching just one driver in Secure Boot mode and is likely to be more reliable with future or obscure boot loaders. It should also work with non-x86-64 systems, although this relies on a platform-specific shim program, which to date exists only for x86-64. The basic features are the same as before -- rEFInd relies on shim for authentication functions and will launch programs that are signed by Secure Boot keys, shim keys, or MOKs. - Altered default for "textmode" option (when it's commented out) to not adjust the text mode at all. (Prior versions set it to mode 0 by default.) 0.6.1 (12/21/2012): ------------------- - Added "--root" option to install.sh, to enable installation of rEFInd to something other than the currently-running OS. This is intended for use on emergency discs. - Thanks to Stefan Agner, the ext4fs driver now supports the "meta_bg" filesystem feature, which distributes metadata throughout the disk. This feature isn't used by default, but can be set at filesystem creation time by passing the "-O meta_bg,^resize_inode" option to mke2fs. (Using "^resize_inode" is necessary because meta_bg is incompatible with resize_inode, which IS used by default.) This feature can be used on ext3fs and ext2fs as well as on ext4fs, so the ext4fs driver can now handle some ext3fs and ext2fs partitions that the ext2fs driver can't handle. - Fixed some screen resolution-setting bugs. - Added the "words" that make up a filesystem's label (delimited by spaces, dashes, or underscores) to the list of bases used to search for OS icons. For instance, if the filesystem's label is "Arch", rEFInd searches for os_Arch.icns; if it's "Fedora 17", it searches for os_Fedora.icns and os_17.icns; and if it's "NEW_GENTOO", it searches for os_NEW.icns and os_GENTOO.icns. - Refined hints displays to be more context-sensitive, particularly in text mode. - Instead of displaying a blank filesystem label when a filesystem has none, rEFInd now displays the size and/or type of the filesystem, as in "boot EFI\foo\bar.efi from 200 MiB ext3 volume" rather than "boot EFI\foo\bar.efi from". - Fixed a bug that caused the screen to clear after displaying an error message but before displaying the "Hit any key to continue" message when a boot loader launch failed. 0.6.0 (12/16/2012): ------------------- - Fixed a memory allocation bug that could cause a program crash when specifying certain values with the "also_scan_dirs", "dont_scan_volumes", "dont_scan_dirs", "dont_scan_files", and "scan_driver_dirs" refind.conf options. - Modified Linux kernel initrd-finding code so that if an initrd is specified in refind_linux.conf, rEFInd will not add any initrd it finds. This enables an override of the default initrd, and is likely to be particularly helpful to Arch Linux users. - Added ext4fs driver! - Made "boot" the default value for "also_scan_dirs". - Added identifying screen header to line editor. - Fixed bug that caused rEFInd's display to be mis-sized upon return from a program that set the resolution itself. - Adjusted "resolution" refind.conf parameter so that it can accept EITHER a resolution as width and height OR a single digit as a UEFI mode number (which is system-specific). This is done because some systems present the same mode twice in their mode lists, perhaps varying in refresh rate, monitor output, or some other salient characteristics; specifying the mode number enables selecting the higher-numbered mode, whereas using horizontal and vertical resolution values selects the lowest-numbered mode. - Added "textmode" refind.conf parameter to set the text mode used in text-only displays, and for the line editor and boot-time handoff display even in graphics mode. - Fixed bug that caused tools (shell, etc.) to launch when they were highlighted and F2 or Insert was pressed. - Added "editor" option to the "hideui" token in refind.conf, which disables the boot options editor. - Added hints text to rEFInd main menu and sub-menus. This can be disabled by setting the new "hints" option to the "hideui" token in refind.conf. - Added "boot with minimal options" entry to refind_linux.conf file generated by install.sh. This entry boots without the options extracted from the /etc/default/grub file. - Added keys subdirectory to main distribution, to hold public Secure Boot/shim keys from known sources. - Changed install.sh --drivers option to --alldrivers, added new --nodrivers option, and made the default on Linux to install the one driver that's used on /boot (or the root filesystem if /boot isn't a separate partition). Of course, this won't install a non-existent driver, and it also won't work properly if run from an emergency disk unless you mount a separate /boot partition at that location. - Fixed bug in install.sh that prevented creation of refind_linux.conf file on Linux systems. 0.5.1.1 (12/12/2012): --------------------- - Fixed bug in install.sh that prevented it from working on OS X. 0.5.1 (12/11/2012): ------------------- - Added support for "0" options to "textonly" and "scan_all_linux_kernels" to reverse the usual meaning of these tokens. This is useful for including these options in a secondary configuration file called with the new "include" token to override a setting set in the main file. - Added "include" token for refind.conf, to enable including a secondary configuration file from a primary one. - Modified install.sh so that it creates a simple refind_linux.conf file in /boot, if that file doesn't already exist and if install.sh is run from Linux. If that directory happens to be on a FAT, HFS+, ext2fs, ext3fs, or ReiserFS volume, and if the necessary drivers are installed, the result is that rEFInd will detect the Linux installation with no further configuration on many systems. (Some may still require tweaking of kernel options, though; for instance, adding "dolvm" on Gentoo systems that use LVM.) - Added --shim and --localkeys options to install.sh to help simplify setup on systems with Secure Boot active. - Fixed (maybe) bug that caused resolution options to not be displayed on recent Macs with GOP graphics when specifying an invalid resolution in refind.conf. - Fixed bug that caused some programs (EFI shells, in particular) to hang when launching on some systems (DUET, in particular). - Implemented a fix to enable ELILO to launch with Secure Boot active. This fix might help with some other boot loaders in Secure Boot mode, too, but I don't know of any specifics. 0.5.0 (12/6/2012): ------------------ - Added the ability to include quote marks ('"') in refind.conf and refind_linux.conf tokens by doubling them up, as in: "ro root=/dev/sda4 some_value=""this is it""" This example results in the following string being passed as an option: ro root=/dev/sda4 some_value="this is it" - Changed refind.conf-sample to uncomment the scan_all_linux_kernels option by default. If this option is deleted or commented out, the program default remains to not scan all Linux kernels; but with increasing numbers of distributions shipping with kernels that include EFI stub loader support, setting the configuration file default to scan for them makes sense. - Modified the "resolution" token so that it affects text mode as well as graphics mode. On my systems, though, the actual text area is still restricted to an 80x25 area. (This seems to be a firmware limitation; my EFI shells are also so limited.) - Fixed a bug that caused the options line editor to blank out lines that were not actually edited. - Added support for using Matthew Garrett's Shim program and its Machine Owner Keys (MOKs) to extend Secure Boot capabilities. If rEFInd is launched from Shim on a computer with Secure Boot active, rEFInd will launch programs signed with either a standard UEFI Secure Boot key or a MOK. For the moment, this feature works only on x86-64 systems. - Added new "dont_scan_files" (aka "don't_scan_files") token for refind.conf. The effect is similar to dont_scan_dirs, but it creates a blacklist of filenames within directories rather than directory names. I'm initially using it to place shim.efi and MokManager.efi in the blacklist to keep these programs out of the OS list. (MokManager.efi is scanned separately as a tool; see below.) I've moved checks for ebounce.efi, GraphicsConsole.efi, and TextMode.efi to this list. (These three had previously been blacklisted by hard-coding in ScanLoaderDir().) - Added the directory from which rEFInd launched to dont_scan_dirs. This works around a bug in which rEFInd would show itself as a bogus Windows entry if it's installed as EFI/Microsoft/boot/bootmgfw.efi. - Added support for launching MokManager.efi for managing the Machine Owner Keys (MOKs) maintained by the shim boot loader developed by Fedora and SUSE. This program is scanned and presented as a second-row tool. - Added support for Apple's Recovery HD partition: If it's detected, a new icon appears on the second row. This icon can be removed by explicitly setting the "showtools" option in refind.conf and excluding the "apple_recovery" option from that line. - Fixed bug that caused text-mode ("textonly" refind.conf option enabled) menu entries to be right-aligned rather than left-aligned when rEFInd was compiled with the TianoCore EDK2. - Added "--usedefault {devicename}" and "--drivers" options to the install.sh script and changed the "esp" option to "--esp". 0.4.7 (11/6/2012): ------------------ - Added an icon for gummiboot. - Added a boot option editor: Pressing the Insert or F2 key from a boot tag's options menu opens a simple text-mode line editor on which the boot options may be edited for a one-time boot with altered options. - Modified the "scan_delay" feature to delay and then perform a re-scan, which may work better than the first attempt at this feature (which I'm told isn't working as planned). - Modified rEFInd to add a space after the command-line options only when launching Mac OS X. On some early Macs, the extra space (which had been present by default, as a carryover from rEFIt) causes problems when booting Linux kernels from FAT partitions. 0.4.6 (10/6/2012): ------------------ - Fixed some minor memory management issues. - Added new "scan_delay" feature to impose a delay before scanning for disks. - Changed default "scanfor" option from internal-external-optical to either internal-external-optical-manual (for non-Macs) or internal-hdbios-external-biosexternal-optical-cd-manual (for Macs). I've done this for two reasons: - Many Mac users have been confused by the fact that rEFInd needs reconfiguration to detect Windows (or Linux installed in BIOS mode), since rEFIt scans BIOS devices by default. Adding the BIOS options as default for them should help them. - Adding the "manual" option enables users to simply add manual boot stanzas and have them work, which is more intuitive. Adding the "manual" option will have no effect unless manual stanzas are created or uncommented, so this part of the change won't affect users' working default configurations. - Added new legacy (BIOS) boot support for UEFI-based PCs. 0.4.5 (8/12/2012): ------------------ - Fixed bug that caused a failure to boot BIOS-based OSes on Macs. - Fixed bug in install.sh that caused it to fail to detect rEFItBlesser. 0.4.4 (6/23/2012): ------------------ - Fixed bug that caused filesystem labels to be corrupted by rEFInd on 32-bit systems. - Fixed bug that caused filesystem labels to be truncated in the drivers on 32-bit systems. - Fixed bug in use_graphics_for option parsing that caused most options to set graphics mode for OS X and/or Linux but not other boot loaders/OSes. - Tweaked install script to better isolate the ESP under OS X. 0.4.3 (6/21/2012): ------------------ - rEFInd now supports compilation using the TianoCore UDK2010/EDK2 development kit in addition to GNU-EFI. - Added new "use_graphics_for" option to control which OSes to boot in graphics mode. (This effect lasts for a fraction of a second on most systems, since the boot loader that rEFInd launches is likely to set graphics or text mode itself.) - Graphics-mode booting now clears the screen to the current rEFInd background color (rather than black) and does NOT display boot messages. The intent is for a smoother transition when booting OS X, or perhaps other OSes that don't display boot loader messages. In practice, this effect will be tiny for many OSes, since the boot loader generally clears the screen within a fraction of a second of being launched; but the "flicker" of a rEFInd message in that time can sometimes be distracting. - Filesystem drivers now work on EFI 1.x systems, such as Macs. - Removed "linux.conf" as a valid alternative name for "refind_linux.conf" for holding Linux kernel options. The kernel developers plan to use "linux.conf" themselves. 0.4.2 (6/3/2012): ----------------- - Added a message to install.sh when run on Macs to remind users to update the "scanfor" line in refind.conf if they need to boot BIOS-based OSes via rEFInd. - Modified install.sh script to be smarter about running efibootmgr on Linux. It now uses the whole path to the rEFInd binary as a key to determine whether an existing entry exists, rather than just the filename portion. If an entry exists and is the first entry in the boot order, the script does nothing to the NVRAM entries. If such an entry exists but is not the default, the script deletes that entry and creates a new one (implicitly making it the first in the boot order). If such an entry does not exist, the script creates a new one (again, making it the first in the boot order). - Added "dont_scan_dirs" configuration file option, which adds directories to a "blacklist" of directories that are NOT scanned for boot loaders. 0.4.1 (5/25/2012): ------------------ - Added "scanning for new boot loaders" message to the re-scan function (hitting Esc at the main menu). It usually flashes up too quickly to be of importance, but if the scan function takes a while because of access to a CD that must be spun up, it should make it clear that the system hasn't hung. - Modified install.sh script to detect rEFItBlesser on Macs, and if present, to ask the user if it should be removed. - Cleaned up the Make.common file for the filesystem drivers. - Changed HFS+ driver to return volume label of "HFS+ volume" rather than an empty label. (The driver doesn't currently read the real volume label.) - Fixed bug that could cause rEFInd to appear in its own menu after running a shell and then re-scanning for boot loaders. 0.4.0 (5/20/2012): ------------------ - Inclusion of drivers for ISO-9660, HFS+, ReiserFS, and ext2fs. Most of these drivers originated with rEFIt, although the HFS+ driver seems to have come from Oracle's VirtualBox, with some files from Apple. I hadn't included these drivers previously because the build process proved challenging. As it is, they don't work on my Mac Mini, I suspect because the build process with the UDK2010 development kit may not work with the EFI 1.x that Apple uses. - Addition of support for drivers in the "drivers_{arch}" subdirectory of the main rEFInd binary directory (e.g., "drivers_x64" or "drivers_ia32"). Drivers may continue to be placed in the "drivers" subdirectory. - Added new feature to eject CDs (and other removable media): Press F12 to eject all such media. This function works only on some Macs, though (it relies on an Apple-specific EFI extension, and this extension isn't even implemented on all Macs, much less on UEFI-based PCs). - Fixed a problem that could cause GRUB 2 to fail to read its configuration file when launched from rEFInd. 0.3.5 (5/15/2012): ------------------ - Removed the GRUB 2 detection "reciped" added with 0.3.2, since I've received reports that it's not working as intended. - Added re-scan feature: Press the Esc key to have rEFInd re-read its configuration file, tell the EFI to scan for new filesystems, and re-scan those filesystems for boot loaders. The main purpose is to enable scanning a new removable medium that you insert after launching rEFInd; however, it can also be used to immediately implement changes to the configuration file or new drivers you load from an EFI shell. - Fixed a bug that could cause the scroll-right arrow to be replaced by the scroll-left arrow under some circumstances. 0.3.4 (5/9/2012): ----------------- - Added new configuration file option: "icons_dir", which sets the name of the subdirectory in which icons are found. See the documentation or sample configuration file for a full description. - Modified Makefile to generate rEFInd binary that includes architecture code -- refind_ia32.efi or refind_x64.efi, rather than the generic refind.efi. This is done mainly to help the install.sh script. The program can be named anything you like on the disk. (The generic name refind.efi is used on unknown architectures.) - Improved install.sh script: Fixed bug on OS X 10.7 and enable it to be used after building from source code (or via new "make install" Makefile target). - Improved screen redraws to produce less flicker when moving among the second-row tags or to the last tag on the first row. 0.3.3 (5/6/2012): ----------------- - Improved menu navigation: - In graphics mode, left & right arrow keys move left & right, while up & down arrows move between rows. - Page Up and Page Down now move through chunks of visible tags (in both text & graphics modes), jumping from one row to another only when at the edge of the row. In text mode, the "rows" are broken down as in graphics mode, but they aren't visibly distinguished on the screen. - Improved text-mode use: rEFInd now displays the proper number of entries when first started in text mode and scrolling is done sensibly when too many entries exist to fit on the screen. 0.3.2 (5/4/2012): ----------------- - Added the install.sh script to install rEFInd on Linux and Mac OS X systems. This script must be run as root (or via sudo). It requires no options, but on Mac OS X, passing it the "esp" option causes it to install rEFInd on the computer's ESP rather than the default of the currently OS X boot partition. (Under Linux, the default is to install to the ESP.) Note that there may be some unusual cases in which this script will fail to work. - Does a better job of clearing the screen when launching OSes in text mode. - Added detection "recipe" for GRUB 2's BIOS Boot Partition. - Fixed bogus detection of ESPs created by Linux's mkdosfs utility or Windows as bootable partitions when "scanfor" includes BIOS scanning options. 0.3.1 (4/27/2012): ------------------ - Fixed bug that caused spurious "Unsupported while scanning the root directory" messages under some conitions on Macs. - Modified loader scanning code to sort boot loader entries within a directory by modification time, so that the most recently-modified loader is first among those in a given directory. Thus, if you specify a directory name (or volume name, for loaders stored in the root directory of a volume) as the default_selection, the most recent of those loaders will be the default. This is intended to help with Linux kernel maintenance when using the EFI stub loader; set up this way, the most recent kernel copied to your kernel directory will be the default, obviating the need to adjust the refind.conf file when adding a new kernel. If you want to change the default among those in the default directory, you can use "touch" to adjust the modification timestamp. - Tweaked code to find loader-specific .icns file so that it finds files for Linux kernels without .efi extensions. In this case, files should be named the same as the kernels they match, but with .icns extensions. For instance, bzImage-3.3.2 should have an icon called bzImage-3.3.2.icns. (The old code would have looked for an icon called bzImage-3.3.icns.) - Eliminated bogus OS loader tags for filenames that end in ".icns" when the scan_all_linux_kernels option is set. 0.3.0 (4/22/2012): ------------------ - I'm officially upgrading this project's status from "alpha" to "beta" and giving it a bump from 0.2.x to 0.3.0. This doesn't reflect any major milestone with this version; rather, it reflects my sense that rEFInd has been "out there" for a while, and although I've gotten bug reports, they've been minor and/or have been fixed. The program still has known bugs, but my impression is that it is, overall, usable by ordinary users. - Added "resolution" option to refind.conf, which enables setting the video resolution. To use it, pass two numeric values, as in "resolution 1024 768" to use a 1024x768 video mode. Note that not all modes are supported. If you specify a non-supported video mode on a UEFI system, a message appears listing the supported video modes and you must then press a key to continue, using the default video mode (usually 800x600). Unfortunately, I don't know the calls to get a list of supported video modes on older EFI 1.x systems (including Macs), so on Macs setting an incorrect video mode silently fails (you keep using the default mode). This makes changing your video mode a hit-or-miss proposition on Macs. CAUTION: It's possible to set a legal video mode that your monitor can't handle, in which case you'll get a blank display until you boot an OS that resets the video mode. - Fixed (maybe) a bug that caused rEFInd to crash when returning from an EFI shell or other programs on Macs, particularly when rEFInd used graphical mode. I'm not 100% sure this bug is squashed because I still don't understand the cause and I only have one Mac for testing. See comments in the ReinitRefitLib() function in refit/lib.c for more details. - Added new refind.conf option: scan_all_linux_kernels, which causes Linux kernels that lack ".efi" extensions to be included in scans for EFI boot loaders. This may help integration with Linux distributions that don't give their kernels such names by default. Beware, though: It can detect unwanted files, such as older non-stub-loader kernels or .icns files used to give kernels with .efi extensions custom icons. - Improved EFI boot loader detection on boards with Gigabyte's Hybrid EFI, and perhaps other EFIs with a buggy StriCmp() function. Files with both ".efi" and ".EFI" extensions should now be detected as boot loaders. - Fixed a bug that caused rEFInd to fail to scan for drivers if the filesystem driver didn't set a volume name (that is, if the relevant field was set to NULL rather than even an empty string). In such situations, rEFInd now reports the volume name as "Unknown". 0.2.7 (4/19/2012): ------------------ - After much trial and tribulation, I've overcome a GNU-EFI limitation and enabled rEFInd to load EFI drivers. This feature was present in the original build of rEFIt but was removed in the versions that could compile under Linux, but now it's back -- and still being compiled under Linux! To use it, you should place your drivers in a convenient directory on the ESP (or whatever partition you use to launch rEFInd) and add a "scan_driver_dirs" entry to refind.conf to tell rEFInd where to look. (As always, you should specify the driver directory relative to the root of the filesystem.) Note that you can't launch drivers from another filesystem; they must be on the same volume that holds rEFInd. Those who compile from source code should note that implementing this feature necessitated using a more recent version of the GNU-EFI library. I'm currently using version 3.0p, and version 3.0i does NOT work. I don't know where the change occurred, but you may need to upgrade your GNU-EFI installation. - Fixed bug that caused rEFInd to show up in its own menu sometimes. - Added new refind.conf token: also_scan_dirs. When scanning volumes for EFI boot loaders, rEFInd always scans the root directory and every subdirectory of the /EFI directory, but it doesn't recurse into these directories. The also_scan_dirs token adds more directories to the scan list. It defaults to "elilo,boot", but you can set it to any directory or directories you like. 0.2.6 (4/14/2012): ------------------ - Added "volume" keyword to configuration file's stanza options. This option changes the volume from which subsequent files (specified by "loader" and "icon") are loaded. You pass "volume" the name/label of the FILESYSTEM you want to use (not the GPT partition name), or a number followed by a colon (e.g., "1:"). The former should reliably identify a filesystem, assuming the name is unique. The latter assigns numbers based on the order in which they're scanned, which may not be as reliable but should work when a volume is unnamed. - Fixed bug in 0.2.5 that caused failure of Linux initial RAM disk mapping on some (but not all) systems. Affected computers include at least some Intel motherboards, maybe others. 0.2.5 (4/9/2012): ----------------- - Fixed bug that caused an inability to associate initial RAM disks with Linux kernels stored in a volume's root directory. - Volume badges (that override default badges) are now stored in .VolumeBadge.icns. Although undocumented, rEFInd formerly loaded custom volume badges from .VolumeIcon.icns. This carryover from rEFIt was a confusing name, given the next (new) feature, so I've changed and documented the name.... - Added ability to set a default icon for a loader stored in the root directory of a volume: The icon is stored in .VolumeIcon.icns. This icon is also used for Mac OS X volumes booted from the standard location. - Fixed bug that caused icons to drop back to generic icons when rEFInd was launched in certain ways (such as from an EFI shell in rEFInd's directory) on certain systems. - Fixed bug that caused "unknown disable flag" to be shown (very briefly) instead of "unknown hideui flag" when an improper hideui flag was set. 0.2.4 (4/5/2012): ----------------- - Created new refind.conf entry: "showtools". This entry takes options of "shell", "gptsync", "about", "exit", "reboot", and "shutdown". This option is in some respects an affirmative version of portions of the old "disable" and "hideui" options; however, it enables users to specify the order in which these options appear on the screen. Also, the "exit" option is new; it terminates the program. The effect is usually to return to whatever tool launched it or to launch a default OS; however, this is somewhat unpredictable. The default therefore omits the "exit" option, as well as "gptsync", which has always been dangerous (but necessary on most MacOS/Windows dual-boot setups on Macs). As part of this reconfiguration, I've eliminated the "rescue Linux" option, which always seemed pointless to me. - Folded "disable" and "hideui" refind.conf entries into one ("disable"), and reduced the number of options to six: "banner", "label", "singleuser", "hwtest", "arrows", and "all". ("arrows" is new and disables the scroll arrows when a system has too many tags to display simultaneously.) - Added max_tags option to the refind.conf file, enabling users to reduce the maximum number of OS loader tags that can be displayed at once. - Updated rEFIt icon, based on the 128x128 volume label from the rEFIt CD image. - Added x86 and x86-64 EFI shells to the CD image version of the binary, but NOT to the binary zip file. The logic is that the CD image is more likely to be used directly as an emergency disc and so may need this feature, even though the source isn't part of the rEFInd project. (The source is readily available from the TianoCore project.) - EFI shells may now be stored at /shellx64.efi for x86-64 systems or at /shellia32.efi for x86 systems. The /EFI/tools/shell.efi name is also recognized; however, if both files are present, two EFI shell icons will appear on the main menu. The /efi/{refind-path/apps/shell.efi filename, which was never officially documented but worked as a carryover from rEFIt, is no longer valid. 0.2.3 (3/26/2012): ------------------ - Fixed (maybe) a bug that caused hangs when launching a second program after returning from a first. There are some weird system-to-system differences, though, and this fix causes (apparently harmless) error messages about "(re)opening our installation volume" on at least one system (a 32-bit Mac Mini). I'm committing this change because, imperfect though it is, it's preferable to the earlier version, at least on my small sample of computers. - Because of news that the Linux kernel developers are planning to use the filename linux.conf to hold Linux kernel configuration data for EFI booting, I'm transitioning rEFInd away from that name and to refind_linux.conf to avoid a conflict. This version can use either name, with refind_linux.conf taking precedence if both are present. - Added logo for Arch Linux. 0.2.2 (3/23/2012): ------------------ - Fixed bug that caused program failure when Linux kernels with EFI stub support were detected with no associated version numbers. rEFInd now permits automatic linking of *ONE* versionless kernel to *ONE* versionless initrd file. - Fixed bug that caused program hangs when a boot loader filename or label was too long. Such names are now properly truncated and program execution continues. - Fixed bug that caused no text to appear in submenus on UEFI systems with small screens (800x600). NOTE: Problem still occurs on screens smaller than this, but such systems are very rare. 0.2.1 (3/19/2012): ------------------ - Added ability to set a "default_selection" that's a title or a substring of one -- the name given to a stanza in a "menuentry" or the boot loader's filename, in most cases, although "Mac OS X", "Windows XP (XoM)", and "Microsoft EFI boot" are also titles. - Added support for semi-automatic scans of Linux kernels with EFI stub loader support. The program auto-detects matching initial RAM disk files and loads additional options from the "linux.conf" file in the same directory as the kernel. - Added support for "submenuentry" keyword and associated sub-stanza entries in refind.conf file. - Renamed icons/os_mint.icns to icons/os_linuxmint.icns to match the filename Linux Mint ACTUALLY uses for its ESP boot loader directory. 0.2.0 (3/14/2012): ------------------ - Initial public release refind-0.11.4/mkrlconf0000775000175000017500000000460413325167530015064 0ustar rodsmithrodsmith#!/usr/bin/env bash # Script to create a refind_linux.conf file for the current Linux # installation. # copyright (c) 2012-2015 by Roderick W. Smith # # This program is licensed under the terms of the GNU GPL, version 3, # or (at your option) any later version. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # Usage: # # ./mkrlconf [--force] # # Options: # # --force -- Overwrite an existing file (default is to not replace existing file) # Revision history: # # 0.10.1 -- Improve extraction of kernel options from /proc/cmdline # 0.10.0 -- Renamed from mkrlconf.sh to mkrlconf; changed to get $DefaultOptions # from /proc/cmdline rather than from GRUB # 0.9.0 -- Added check for OS type, to keep from running pointlessly on OS X # 0.7.7 -- Fixed bug that caused stray PARTUUID= and line breaks in generated file # 0.5.1 -- Initial release # # Note: mkrlconf version numbers match those of the rEFInd package # with which they first appeared. RLConfFile="/boot/refind_linux.conf" if [[ `uname -s` != "Linux" ]] ; then echo "This script is intended to be run from Linux. Aborting!" echo "" exit 1 fi if [[ ! -f $RLConfFile || $1 == "--force" ]] ; then RootFS=`df / | grep dev | cut -f 1 -d " "` StartOfDevname=`echo $RootFS | cut -b 1-7` if [[ $StartOfDevname == "/dev/sd" || $StartOfDevName == "/dev/hd" ]] ; then # Identify root filesystem by UUID rather than by device node, if possible Uuid=`blkid -o export -s UUID $RootFS 2> /dev/null | grep UUID=` if [[ -n $Uuid ]] ; then RootFS=$Uuid fi fi FirstCmdlineOption=`cat /proc/cmdline | cut -d ' ' -f 1` if [[ "$FirstCmdlineOption" =~ (vmlinuz|bzImage|kernel) ]] ; then DefaultOptions=`cat /proc/cmdline | cut -d ' ' -f 2- | sed 's/\S*initrd=\S*//g' | sed 's/ *$//' | sed 's/^ *//'` else DefaultOptions=`cat /proc/cmdline | sed 's/\S*initrd=\S*//g' | sed 's/ *$//' | sed 's/^ *//'` fi echo "\"Boot with standard options\" \"$DefaultOptions\"" > $RLConfFile echo "\"Boot to single-user mode\" \"$DefaultOptions single\"" >> $RLConfFile echo "\"Boot with minimal options\" \"ro root=$RootFS\"" >> $RLConfFile else echo "Existing $RLConfFile found! Not overwriting!" echo "To force overwriting, pass the --force option." echo "" fi refind-0.11.4/icons/0000775000175000017500000000000013372357235014437 5ustar rodsmithrodsmithrefind-0.11.4/icons/os_frugalware.png0000664000175000017500000002661212626644770020020 0ustar rodsmithrodsmithPNG  IHDR>asRGB pHYs a aJ%tIME "n IDATx}[%Wݘص_msE 6A&VEW@n>"|])_)_DOɲ(p@:("-|1h}OyWU5֪k.y>U暏1ǜw;{ǽqw;\}xAyWNo!oc^1bĽ˲? d@wr*xI  ַ~mhE_?z4̩:)H?f0}k\2`DLג$Tk̛܏d+Y(~emy+_ɾxw#D IʻcV1H}zVmܸlw>moBKy@ܴT?7,)}775 yWD Q /y O f03`)!3(FE "Rhl/|KJoSٽ2(iY}zz׏<ȯ{nY__(M{uY|RJ{n"D(+B!Zͤ,޻J1Hj|=OZg? _xqտ^YtfR@o "O 8?[%oXP}*!v75,OoyꩧZG @ ~O<4}tv3((&Q!(BLjH?Z 5u\#}ZkZ?_>A'zw>O}_%IIsly( P!Vek{RH(BDXB ]".RN^8'> uqo_l/Kyl)%$iڎ@HSG\`͘Q\dK9պrq;)[U. (#O>s=7v@o~?f 0K!Q9fA@7ʻe6~UKК 0f&LVCg}٠_#??5@ `կwO`)i)l{A:s'V}OYZT<|6l>|>C/PsF)\u>/Y}N:׫YV/?ygKjS}Ý?R~T|H+B(` ՞WNۥDEUp8< zߕ)[,hG>V|?13yM&;h,L -t-͢H, ҆,"# mF\3kR/wC^9<<|ի?;>>LABjQ+6 CJVe_;69degB&QD (Ai h2g,>O}|HV8>ЗRvk 5y#K _zp3i'xByV G ;Wm;P'ZFggg4dI>}e$5nDDq(/ȲS :[E)Dg^AȤ9! W.+Ux1Aj!`0tqqjm^vlW @O dg_4>CԿDAvc$( *k Foc9d:&!bhu T7-wxW%y!k6ydqQd;&# aʡlJ9 *&30ZRzjr *2^PEo60\^w:&j!D,N\RɟhP4LZ;i %N !-h 1 0ZEjgQJ b IVYU@L!̟fp8lecG1,F+? R ИP2PkC ܚTv=d|@:IbS)`̛ⶒSzVhog6wS!?6Z: *e4uL@TuFOUI*(s,Ѱ6̔-_T "Hgw=X bc^ DR"P+@ o׆rZE)%Fá#f*+Nz g=$qd5Ɔ6܁S{Aպc S}.Bb>_`6ׄ*MF48Ae$VV͟/JBDQT[| R2F;r*ƣ!∖"f'DY:TA"ҐC;g'by5aaYb@- 1UmRS ,,Cݛ!pU쌆Yۿwp$ah9g#;c7!ʢZ('D[}xՇ34AE[2T Կh7r=*ʳu%.t>u5C=>BUedHM؅HXJeX!35rB'Rb8)j%d]x{3[iwpW2@?cz4hr 7ר@ـl4/(ߠտC"2#7pƶ;Qd ϿDʲQ4M>@돚=džXڒD^v%q+ۖ|bB0P !̲:Rg.Eal}pSAZZ $)Q%@,PB` 80y':ײTAhkPkW ?D,EäEkq)*r(gԡ 5#YRJ $~5l6z95.U%=EUBATK<nPop\C#CǣXx4ۿBqqq`8v ;@E(E"/s$qn^r-L4Bmzn^"{WAYxy܋Qz0`9~l >7WeUPa 7 4HKYI¯6peCRNK5@3sRKʑEbCYԐ$P&>ZOQD 6ϲEPW | Zu60J3(6`ݍlH MGabu%$Ж[1dw#8=38 K:D`?q]p-<׺ *P|Pwz$ļ5 %/;C( K\hv[[*SἙ2Bۊtw<ݯ{RjZtL&(ReMהHj7gT@Q@z^|rb قyaxO~!f dw(d2&`vn4i E^ MOa= z˲l6C'u#M >uX5|4*4zt܀T>@eiarI>E&Xš\274+n{G1 5ؾIBs:}D8::BDjjzȲlBz0\$I@65_?kF3/}-!5}[Rʏ?x)DMZZ|Dk!) apQd9$ʚ6ր \3< kV Vll9>ϵ;;AFQ(5yxtԻ\*z7?͐eF"/N"#Aʄv7jI@vߴ儀l:NN /q~q@C2UPg&` ,5Ԅ{^3޶ퟩ+C2bHܞf6dPqqq(FWwKr &#'KrF8Zf!n xޔB$M ji`-j̵ !8_lCE HҤxUFDTqdvL XVl$M1 vW(I gwppߪ޿U?;d0@ Q-RbjoH)HU=V^'&[P&@j2>Fˣ^)#P zR݃'r ` XYɕ !ɖOO p)%oKH &`1pfVښ pW8Lv8э{ރNA*+;7UI0yT^BmcĤT{^~>m3OZe o G;;;XaV^2 L{=z @-ZU͕w}JjŤz, NrDum;i0I{)6~uj\_ @zJ ]BH׳)dz8\iBKMMcGrkwk`w_S׵%I]A=3Nv`CBf?裟 e+HmzvOPQQuf]M68}mnYk~oUS2piwbD/!Tz,1iƏkM,.uR̔u 4v^1Vٿ"beh&ra:X,(Y07JL]/`ΩKA'n,BSPI:jo u8/³³m޼%pHZ'|L@F\]µtuscՈ! vm^ʲ3jqt&@6/X9#ҟK 2jnih ^(e7Ό(*NkND^v%]/cS0۴cF m 4L?A%Qߍ5'l1)*` %̌|%gBǫ7$&q?9eڗi_7lʇD gb͠-f˽ds4TQFz>ڝ@E7x ]#j7 Fá=Kgڵ6.׽]kL*-a)1ő7 z q"'/rd5c4hy=7 \b TeYՄv5/3l™|l[y)zꚣ%>6DxQߔQw#/ud 0!̎dh^eR"V `9LroP5ˏv5ZRN'(@dòϴVA ^ul 8wH!tewx3\^YEQ`bU`3k:~>W=;%"loRb28s\p:$񤯦os# ‚L'n6saIhdLwǬI>Q$-:TJF6jkxs禁?,ފe)|pIKm p:(g^CNv(dd!b#S6q\05iGi$h-c6'Nڜ0 V0NTEe ¿,%Y6)v [e>&h03V-"Fm5wkZ^kEKEDyV(qW" q/m?UYSiԞ#a]zf^~mĕ\뇾LCn!̈)uaN o,\&UmV-Jf=NL-Q bL Ɉ\4$j.6=uk/c\ !t qZ j`g(K `&DC|aկ Hbr8 qe7w ^y%]C<5OϦ zAAv+{kF wgN&=`0ԍg'p`^ؙGb>íc< KMbsKDZ=ͪ)J0M@,:ꖇYtZM\0-)}&@ rS'''8<(*(% &gπ7L|@ *-jb"b|:{<=~ܡ&Xg3ܽ{sCFD>G'L*CF5DT(K0qZU@zz$HǷn!/ 2CEiXq %1Ҵ+W+C)uo/QLHLݬ:j`pQlpa @$pc>OH.7^Ͼlg2 SgDZ:vuz3r0Ґ`:%\\w7; Cv4 8^ r2>p&GIF)BJ!vzP pvPGwґ=t:h}LF#-T9X^e6q lْP5RF]{6s?(׆kۢ }H @^eP;Zb>N(Jptth#c`i Qu.*vg 9./EzUc>r8 E꫿g>sg<_ ˜L185t<!5E0PwɉK0]%Ѩy: [ר!(_l?䁡WC!F~z7Fbάj׸mTh\76ܽ&TsoBE֙<::BSk, g+;.]Q*e7n&o@θjf)lS Kt:f8޷"6!z!-<1-|ȅ -bk C@iDTΖ?1_6"wQ[#۷oqƍbi ;wo_?><:|S2"XrqC_ /)@VR5UJsaooφkaF((49L, nN=C SA^7_~]<6 P\v6FԿ6nyG8F)m#dp5*Qjt <'''u_WfooGGG8<ǘ[ ;뻧O7WI#!T *lsFa( +8P۪\awg;gTzc>)ԝǪ6lI1U!"_wޙ5\?.~姧⥗^}y"%ϧ0ѱ;`&d°|p߫̄ t:ōwޱ8::`0>@up]odtz-ST/Ru=@!G1_o+W A,,?۟g\ٚ C;J ۟(ZtV0¿1q5e.8?`0>aڢ(lzv, t ,k<'zJ4qC˼>|>D>, E941)v*N9>%"KWCnI"1,Sܼyׯ_ǝ;wluActc;(z*b?̧'@ - 9"]c'?pJD[ k8p0dR_> 7 rxE^(Y4M& RGL+I"I'x8u7oFp)jou wb0ۑtaHG# 7o8p`MjB`\7/q/S3j`'/,Tx+!ͅTe*ottJV6Gd}6=!(w޵9 M;CRO~w޹)4K =#`/}i駟~? ܭSJmē$j'u!9PP\FvѶZȄe5@@w1%B;O~[ZfZx]${ޢzD4:2S"w iV &ÚB3a~6XM2  gGsMyqzz^z/OϏҶBko2Ofwx̲e\-j9(òFJwp]JiWc?#DnP`fR^y~/os)mnjN$ {#~/|>#}GGуDDY(FֲDMBA MBZ]&8\G ӛ7o}ƍ7x㍛7n}Fn7_%&0F DcۻE|衇h{{+, 32I)I's"f&!y+nELD$Xi*8:Z(j,o{^eyqͻ1'*X7^) qi Ggl>FSnL?п3L& p@kL AA-?SSKiᛐX5y]$r 'C6 yDN7ywІ(a栅ϮK1 VSd ̝^|l FGO/w-jl\>Fd py"7F^ K-<5ltn V9 òb;11 ŽޱmdSIENDB`refind-0.11.4/icons/os_artful.png0000664000175000017500000001406013317716215017140 0ustar rodsmithrodsmithPNG  IHDR>abKGD pHYs+ tIME-KZIDATxy|ŕU=4i$:}1c ؐ6# ~rlfa7@r%@H rƷ-˲diF{j%ْuX#9N}tOu_zuH$D"H$D"H$D"H$D"H$D"H$D"H$D"H$DAg[κ8TrONU [/| *v@"[L*Dٙȗafc=)[.)d E g K0]|cq_p"Щe3m2Vs=g՞7y-X5.2~O@HS G8z;>OS >Q26 %7N\Lا))s7̨+!pak>#6m*z;_`!pAƋ~|nHN8Q)}) F1l) OkxipK{{~(T3flPE \gGϾ;[hm)ʳtmUy6MR2 !y<\Ҧ1؇cMN݌}{ĠDOy3Nu3>M"pumr/\ N@EBUɪ횂QBA~$oc@7CO $"v>Ÿ]}k< 4N1AY(1R.y&֗  ڵqOk[{[NwnM6Mɨ-S-Iv @JzR-52|`-kO^6ӚH?9鸘Yrq0H ଩M ,F# 83FlnqTh(0hku{; 6Xs=y?0H*ݗ/:x)U~(Yfd԰0)ʷ-sc/. '%q@|$t6sMS?12S-,s:>?6 uL_ǿޔk8k~bQҙvLaRJCqg2zXOcG0uјUu__01YYM;tA!$!@*JP0TB2zuMb 9 )r[z \; 4?eXx*Pvg"u>7vT^ZfNu~ckI@#$fXCw-e|=UJ>:JeszFVM>x︺@UE ! )$=Fd, -pÄ|o5m@ז\X'Yuwln[^8_Mo\5\}-7>"zYP{b]Q7> 'O:| &Jn Кb>#ʵBwK[4jB@ uZ㤥nr.Q&OoKsߑYT^hLمO$I&"vRgpi |!9oٞI K W0@=;x&S))T:SP> :;*u,@CR7Ƥb++zkpSp `|lji՜ٻ'hxd յ+tMz4U6~ ^2 8 656z񆸹Ȫ]]d̟y8>oeD$ȸx h_Gw:;bpQ ~ [ o#TrD_`f`{[B;.(8mtُU }H"q0j콠:O ^ |aaMKF""ihM6u:Ot&WFKڪKljK%JiF8@0f v|:; D@OE=3l'FqY<.yH6@t˪Kr&zّ`gPY5?ZY\ǥ'&MĚ\6QE!iLיHDzcb>2{#\:3,1@חo0O^3!XƑ Bc[{Q?z1<[MB,;x(T(zEEXc)z4, B4L vXDx:ae}.)& ܠ0fX7^u`*%%ϡ)Q.{ED@DR/4>`&@$3)\+/J@-X-8T E(+|xDNU(A]4})i6[OU)E/`k<2֥_S}M ãr PTִjN{iNk@Op5rЪReQ sr.M+.p59 Xm0刖#s X{kB ee!fMve:Fq"+-%ivӘO>p g`=\Qv0ɋuj]6q4FM1?pE&u6pM4G]8FKM<ҺXKj6f+%/MpP,﮸3)4M+MV;g2WK)QBB5s=K&!7Bp$C*Vb"Y}f pz0bpĕlPi~JS-mޡHŐO߿Q({BaM@d2U?R;t_"fz_]E _]hUU˿ ]6<!x,s@ _%nєxrg ~Vsr}-kfU8Wؔ=/B\e\ `Ȧ$=sQJԴkϣy/X!/i;?uhͯ~38^v;*W{ܻ`N- ΠQ%vLX/V{yt%/|7oɷ_7WwIdTPK| '|IV7ch>pkU7_ j k<gQDk4GּbA._Qk?xl~»ۓF'~>L.~\@.fT=!x PBS@ ?2٭]xr$H~c[?fy,K~>7~ >\ufA+,(rY؍O.r헹K ;2k7|Ab RMS>M:gn]Zv;zȼ%o((kʊ`;{^2H#湿\e Lֿ[x%-ͳ@Csc7ttvcBBSd+h\v^]rrՋGc{kde9W ){;oy&;x5MHM[pv&sJA!(V)-"kv_XY2#9(6EUKi) $_ϛ78%Jț\`.ʢPb0KM"mtEt2MŶ+>hI^Տ(ژ0kgj[ĩR5ZTTJCd 9rZ5ԭjڢ¡)-G}%0PF2#EL,ƀɡ3͚߄;J8U<{79[yՍ N߬3=K.02sHϖ.__˫R25Ej Ka8B_m3E)h2C#HZ?[!!2=-";_S00oLgEcX~y+?d-qٝpCN|쏻oN2p'l5:5J&Rr,=">/zt[t6luS[^GM!M f^#Pw^hGMu5Y.uoĒ.WPg.u=W(lWuiޙ* 97h lSVjڥuumFSC^q5֛TJ؁kw_ a r9ER\ .\aȉByӽLx׾'e4UgMО♥UggDl Z/>%ĴRb?Io0}֖yt#iDQB{"{8b^xc2LM_;w^w9N^ׯ_ÇADHY!c@JN/bccksBYYYuw:Pk0Z&''@4-5tv!@2s9MW\pivRj&"LOOcss39@p`!z^n|f4^ MQ7dG82~. {s MPDY8t(/ 8[v@ ݻhs|kS,`10{k׮}1"Ԃ1JB4aD!!ZƘ{υׁy)%A*DvRIx# ulR(H=Hc0Haٿ|[hZBԌ߇:Qc>Z-..+8PũS~A%-1@6M=c .]ԬVoDtH)Br\o+Q |! +ʤRQuon^k̨yOVJ)}$e.GҼ3(_ R-AP @ CDOիLex!ii rL@84>ő0qϷ?|&Ǧj5bswk*X< ᭷n=EmILe# 0F6Q@ @3_J, E"*mjS|7y1 n)6._c+Yq9H]"tvu ºu?ūذ!FpoRb̚/Z[uС 9٧(=]7EuuEK "߻&osl~El[e ?y#À @P:K,yahDU#o><\zǎU# {+I-,O}eLFS{?8ƿ3 h<{㩁׻ܟvwo;1<{$ljYR4N:2̣ NݮiH/쵖 ?s +'͛׮I /6[CtkE2V &7AhaXr?v8 LlxQ^G p >YTa+I;/trZN,Y{ĻOHB8f?nj9SJˁ|T,[slB}-J>Ɩ<,xTuȡCS&IfZ,˶qbǍaͲ#/ʘOmLK7snE vG\X4qa ۯt%>b[3v/.P4zOUWDE=d^}@yAVhܹ/BmngiIQzQ(~U- }Ju=yuB|*gG 5?]1͔\X7q&1Tc +}]9gft_ʻ!E"R5"U3@ܐ|vw# ?}݂9 je?y뭯Qr,'nmϙ5Υ-G~7NFnPҷ] 8yq;BD>8 @%|ʎGl:!v!BGL3d3{ǽ "Pd2vةSwi'!7^]>*/muee弬fp,-iYZ 7Mq`Sxdqk8W(聄a{[*zu,O*liEi>?d8Lv\\o7u v4ey;"ajjtyE+;zqﻐB]P-;|*+*28]Δ1s-#1+9JvC% UUKK0iZGeF!mNܲJ-p i DJZEa}l1γhdIشVQL_,Y!?ہIENDB`refind-0.11.4/icons/os_chakra.png0000664000175000017500000003272012626644770017107 0ustar rodsmithrodsmithPNG  IHDR>asRGBbKGDD(M pHYs B(xtIME(W IDATxyՕy{{I*U E  dƀ cݞ>=g}׳n346`-%}JU}=#YUYywdVFF}Gh|4>GOn?~_|H$III H|3<֬YÍ7Hmm-x<|dMP0RQ0H$DQ(]Rwy'?0 vSnkUJ9AOd R @ Bdߖ-<b'x+WRZZi\Ν+2uWFNRZn8qD -H c`o|B 77̙3BTUgGK܀0tE]](c$h}#6W?~a nlڴ#LxǸ(..N.LUEpzQ]W! 4ڞSI.C (^XrرL]"x`0/Yp`͚5}x3< ) ,яॗ>ݪ'ӄ,rэQ\+JE""i1.&.L  ?8u&86ijjJ/Y-xJ>o*7&' 9>"} ƾsoԭX K_O??aoSz':cJi o1 r7F9Z)o=xaD"q=?)X\pK()4#uԈQ޷K$"?г[t]nttt~W({Iq~34o7nh@u7ɮ](`qʼ Yؗqe֥2'hf~豧9}O}ڀd)SOQ z_B}Dԋ|yABiNH }3Fμ[߻w#l~o3w.؝n2f53rErŧ2՛@(nL*_WPu3f0{l6lir"">S^={$@4eƍ|{ -fGq}E(̥υCˋV:c"4@_ܴwhuMy݁rQ~E;+ P*E75xm)8_^Ty`5Xxp\vm< `'[~(޲o'8"AvbC1<%^ d0q=\."LIb ȝ;wp8̣>Ç/Y_X玟<Q1WH:jEvh/(2 7% WWcu:v.T*.g2seukBt=;w0t`pppʂE_.Nd rf6 `'F@z*.)%2a0 v2Ǯf-#TC6dgg8;v쐺ɽ{ISh?Z9u#w1wQzňw#=9>17 olδ-t" (ڧu_aϲe˄rᒉdտ,nZ)L:] L!1}0cs:( G(T\1LzQ\K"J}O{ƚ5kǏ_@\T]SJټ/zoGbjv#2q P@w@9﷘0%g^?FkeU,̀|r׾"~BUxoNΗy'7"#UY\e@;w̖Yn>z6# c`E ]5넉MU|!MHѹ})*HAbUzݔ]Vȇ?n#Ջ*|Ps?@CY:Хn33?Ӑ 70ƫQܞ W5HB8i?r̞=˗m۶؉嚿ǜOWnc/vt{#m}Bqc3|T-|~ uexJ rs;sO!D2 [^Ǫ,ųE [ݿ͛7nヒjZ!P[Ģ9޲Ϙ.`#r-|ziT یu؜3N/`0m:9νDw EP4eT`*Z Wįqs궙p}JD`$(g5$_5㦿ُ##`m$7` saq9 Qh H`[h}yqUx"N>Ul[45`B~|V˗/ s_e13oEJ 3k_M;-cZVR ^60X h7G0L:Dx(r3{uZfaE^/<@O=%6؋lNϕcTmUJmaa!w}6k)vT6x3<{`G̀bcO5s]à)zmNam4o|Ddi깁Yw\nI'7>kW8nRodgFNSiVqw@QP=5oH/{ɰ1' ,I6%ˀ TFmڶ#> @͔-pbʕ)3~4JMMS Asasg&}J˳6)io{ޒeh,yglOzyomM;,YЦeY@G%tLc #% WP 'qMbyWUV^㱁 7@l>kg#Wе5\)J`Ar*)9Tx.b8wu1X]]jw7x}HSSh F2O,s}uK.t(85%@"1mXz>O 9~Mk[9 Sν}ke RqR2W62e>Y!fQ0}>pП|IAqd``Bt]7w4 YrfUE$ґw |ˋ@P:/Wϧ?7۞rZ1 "5bcP&׃P =kJ- RE] W[sCZxFrTuĮgB]xzcq@8Ҿj^橝_|Dmٌ%P\#z(R DP*Q] 4G)Y,"PlBI9ˊD^gjžs0*. Ble=.@;ĺu*VIjpO)&ܯUVv 06={ޛP2* @o8Q6Ի0&> Hmm-+YP J!gVP )}?ͯuQM@ ׍\g9. PTwV(<~QV{WUvވn]_uĶCDN"D<ַ=rϷ#&=((Φ|U5܃[zl"+Q=S2vn1 )dz%sM@f:-55F@Jqx&6)=8yZ,ReH)Q2gDYw`4| #0*ޡc} J܅h~T_׹\_W S"WK"Ew1AGc `7TP26?;FIWJ /V9ov%=G}?sI.h])WQ ~wnfGR5_bѣ-lo;iX['>! tQtj-o8qon3U\R4w\sZy,h&T\S1jτ/ p)ν&DpFXP"B*p֛Rd;i߱XE~9"M@J>\៵ȬRrQrTOEHCpG80O~?7+$滖=VJ  =, b :w_m@z-lظòﮠ|݀PϨzv}#&f' [u@qUQ_"k>R3$nꫯ{G8<&%5,rRw -[rlyhH_ɴ(jF.V.(6Do$c.U.>('jKY5T<3*g*('M|xWAI:nHT^}vcؠ۾& _,K=np9 %n `$CvZ*ۚHm1u"iEJIaw0BɼIICc=e^"nY1ck\H=UW>EEdiYRш=JբQ\6(lN)y_{pw{9b{l7e& 9BF.i-+(2䖫i9~|u:vogSwϋAcƍ3{BqF唔O(Z5K2%)k ٣j*Z:[/OIDx 9Nd{6EN7Q6 ͓W'')1tt lv NHY $]+hUe%]ϒz7#i@E<d3'U4 ,6k# ]U4~d8[wsA9@>&7@=GQ23 wZ;./ "Ռxؿgpw+ >N7O(T`Y3rv?F< PXא^0D{< a<\ԭzм @ ϑӱ<銤^cXEY;v2L²%23$jq4cm;s,[5]1˗.%wݓ^@Ͳ+syYۤj&vxH.ff'wHD=.'_NNoZ-)w %y<-5 `߁dT c7™׷:c#~b\A*yѽ`sL$AT[i|ӿJdsVO#$Ct5;fPtĕles(f5LUjF )UI|̺MPx/76еD;8_O;#nj>VcJk7p@QTwvq %Al(͛veIp|P6wl=0*8-vac~>AfzV4[2-.&0VNmQtWv"~_y1N~/u7]PX9!{dDxc;8mZmI.g=w ܁⺎`}Nyo eCg =FνgY6hʹ 1^ FCsgynv6vuuvzxwBq(psy~3HlQWсadS8BdC(}]yWk4>܀[' ui"v#Vz뭲sZn]-t_wG=-Tlq$xhD"2sL.Kp]ClNwɷP0QIU&=:)yy`9<%W'P zpO;9>skխ\Y SY!,NCxɬnF(1j\+2Mynyc@]~&-/1xaKVVL'?FDuFmz=|#c$;`, a"{'TVA&^|EfvCOcW+(_ v+BR2`{p~s2%9́^URu !6%ԩS#<kDMYB["嶹It=ͻ7|'_9 2WI);HjxGg?n.N]okUECH@(Q\/5]5w4 #1PLjL7&;`GTJRP[7\h+)2VTwт$]ɡ^CgR‹vѱ{#`:t)TC4PԙQeB,9a1B 1L;0f+=ŹdL geN?Stn#=b'} յw 1֞`r -!'g 0F}OaȌ *l:wQ]Pw4B]{85[=1Qd` {*)*_J*܄-Az1Z6F Z[<%qdҾcp?O˽+_y\]EQqKD5.zj2N8Jc{xag5j4UPo]H]ݹmfy5 DQ rEF c9 {G9sl2vޝ;ɕA9t<]X)EqqмU3 LFd lDDlL\I<!hN܅M6l2N= &3'8Q@Wٻw/;v`Ϟ=TTTh" u ||ENB]h>o3䟢!, z6%VNّ8kQ"},zc6р]OIw.Xeߖo!\s9!U@uQzVڶ= i eu#aE\zIXQN (Fl,M~pYUV1远ol ^QA:\Qە"k)BCq O{rHSN 4o+gܑÏqܙ@H]h?Q\J|`Ơu,O7̣j4"}y-\C7BYJq={3|^ne~˸ rܑ42gxsNC.dGT?ك旸hq4tB:G[!Dn8o*i$YC<%x=(VRt& [| jL ;4SszT}Dp@M1@`j<ޗsMάfǦNcr͒EJ?3f$ )nT"<%+Ѽ%Pe!:OIg8P;"N%g$ 5"UySyl)%DOдBmM$KH[%RC̜%Z4+9x#bT8sj-3n:Ϲ9[=0)a=#8t>LQ}@mM(ηDkiٸ ysx0AFj^ųPmAg:hUyV)Y曆y-,pjătDSKL%m"1N\T-/_UOF4(rɵwlo#_ϼyp\Kƻ˨^/=  `1K[;H7Yg91= GhΘP: a 2B,A(|m[CR\\Xn]9}Z*~w8+'rٵ$Bm(þxQ8Y-sSCxKդ=ݷ9S~]w]Νqlo~S[.}Oɓ^P{F nF W$d|7BUOL%L0al-~}h'VHr_(@\*(}ǻУAE^4 E|Mi!( ۾|ǿLF"B4BǮ`X%H,$ `YiKP4-dA99#2~ P9ڶn;tnom|lz䞳#-bNtG#T-slN@݇VC=9D~ڏ](10$UmR:Oϡ6A\~M8Y/1x\@/]6Z"6htzl\oo<"bci]'CjMA17hǨ!17bCIoND{;@^ȷ23MZfȵdBɚXFA)jt4d `cX5fJ l :eZ!<^2hٛK!rxA(()KՖ&smcYćq'C̮WQ7 HHoD8Abm>l\MGm*tg >6 l@l״O)Zrkg'~ֲvn)2K{vi`HuL;FU9qA#dd?5."/U8+M|`taߡntTpėsqѝM奼|H lDsxmC $uG*Dn>%? a"؈G.?pQ#'"^~6rI%8r." `0r=sa$rݿsR><Yџ.z1Prqz`Q/;YzKIENDB`refind-0.11.4/icons/os_void.png0000664000175000017500000002303213175623034016601 0ustar rodsmithrodsmithPNG  IHDR>abKGD pHYs  tIME  Ȩ"7 IDATxy$}?Uӳs^]RxJO %2q F!  #@Al  DQnӼsvv?uWG.Ԣz^{=mmmmm>ܛЁA|.q>n6>n|;E* jׯ}"أLjׇ"\ J c ζlj\X2Mq_ Ǹ"'qGtwW)WB5y!$UzGߥ /G 6Ǩ) '>@w|+@p8@"gb! Ʊ >s, 0G(ŀY$* yA!)/rD0Q($Aˣ'LEN% 1I   nWʋҎ pÇqSpC(*z#bD7 o= {0DE [\4$H)ܪ3E{F3+*<[2%n58n1B8F>&QjE`! 8qD 0k{@xѢ*5NkJ" (U*'HLڀ 0 JN;X Î?_EejqnŢ v'D0J5v,}s.2Dp?m:4B8 㠈DY>e4N:~GWOP8.lc"yAp /rPSseZXIMx$H8CE6>-zChX{Ab&9JMVΩ^W@|/Paɝ,0gHm;8ڂhAiCYU.I)1A*_vQ@3#GMEX[m5觸<י" pǙg ŰoJe-8Ϫ9SbPr^B00 A ropMt?x u"~-v40CsQ.MӜan莸]Ip+!tw".'8JphG,?)#S Ah}a޷Hk;i$g#b=˱bwtL"XdkLp˼K?Q 9.9&*z}Xg3TءD2 2݅x֙K2b( &OK}p);jYĻLqD+-؈q-bܷDdLED2 cf6OTdmf]r~@$gOL29Ѩ?|vwiF'68Wljg|oArfU<.1, hˁAb O8Gg03}/0$pSG)NSw?KE<5/$yΦ%q|.Oa3LSȴ{Xbqq~OgψinyG=`DD峬w.ݮ6B` ge$]cS ,1!CWc$k4N$ +yc BiW! m0 61H yRUZ[$*qA895P nܞ!1"6§T!Vb}9v}Eyr }ARLU` &hQ`8`d)Ax?2ڬNUgF$3ž( (̿ ;KŢcBEG&dG}2!$ '3'_H4ģ‚"b"p/׬:{'o۸<+5T僘dOC,N@[~5f)QdvL BA>X#=ChOgOdC_Q'LԾzׇ hpitO($O%I|cwT5z~,C%`9$(Pasu''?pxȣσF0Sg4#$GO^S'!iO"FԄXa2jvc3h66d pWrBMfx|1_y 3ZE^^b.\;xL!p/&(s 9tͧlfхcdMA 6b^b#N³ҜUiCQocM':"nV80DYmLܜ7F-Q"O$B5ʩ}T9,0OIۥ6Z D)ÐHٛ`l&S|fP6hHe)smcsby>CQ>:xaea@Ĥ@A˿k+oƈ :!<1P%N ee"A CYs0QxEa)]eB_#(q88 cP}xNDOT'&[! bUv3賂d=ʝT ]-"Vi='7IIzj[$w n R,EtE)!y˨~TgÉ^Ciˬze^\#Fؓ!zhxy:,ɤ-t2G-|aqeyIAi߫t8aeHZWA AӈHmTtBJG eP~;w.y WFL ޙn =sřd2h֜O%zTJ1F1m|/p5j qi cbcfz{\:E`Yų0I8$0IƾZ҈EdGN0Jz\~3vO"}%;|1VE/vuK\e>yء@dfci9M%遈[)^y s@COZHaGIʦoௌei?8 M"[ūs E@ʀ h5<\ҠKH 2֦+, E@ɋ|[KT]wց ~n`HhoQ>hbj#uS2(Fhl_ՀF+5/ <պʰj 8:OxjLVJS>Ls?Ku]cVwV<$yUAs&V >oj 8)pWl H6AqI72l{hwF%~5Ը#;_5'OvXV6JeL|W44%Mfi;AcO@I?R~ {UQkL Aꆰv7=VxOMlZ+\?PhSg~? fMUn6' d9^9NNQɕM4m_z؅d-hd |;܁DEz,T3j0?wHu:NP8e@"ftմK[k`3M B΀i٧9\qaQGOJp?^/t{ ~#|TW+zџ_/>)?y$&t9A*u| o}87sZm9GI6SC:?_RKu%_5ApAC5Rr9M /9>WZUsVVo_ѢS\_6l%&YKEsiH=5Cgwf'f2̴?d.9En 侜Uݘb@d'A|8ۜfWD t!o Ք:?[CzTdQإN hpΙwit2jK3V(9a6AJ0DROZϨ7\n\{86Cw(\J(єdS`U F:tYn={x6Q*c568FٜuOJl[}`ɛG,'7#[mזrsNoLz|bf6?K=lQ$0=xNNGY)#`M*E]8=fмo/~Dt\qm;$=?ݳx*vKޫln =J\@ypO-EA)s:ҳ̂N*ţ"_prWtɜc:@td2P3У.ϲ2oV3w?XE&ů8ls22z ezΕ6 CimZ_cfD UT0"t8sLq6%\4#$ǁp/2-[4't>{سq()(ab`➙K=PX\BH-.BJz1Wx Uڄ)bЙ5$_LSaEL225}*vQb{ЋTmo6LwU?w݋A @XtW^@qm>1H Pwep<7jc`⪔ ,3Lq2[tPC+|L(C'4T W:sI8ᓆ]M9*i_xڻk((wd{GHӝNZa@UTU8ҿFA"-jhh}:1d t#S:/8}pC_DK @/H27- 03:$u8pccM h{9Ҹ^  tBEbY<3I4(pJ"2mtc&Gp(7h*NUMze-Ԋf0,=)C#.; &)MD)MICH;orF6B(PSջ`98Z⏸9/q-S_͋A "9Ġlp%4#Rtiʒ/tJ?}xA˺g~\Ĕ‘qo'eV & _8 *!@Qst[̕|uw٢"u*odu~M(zz*iE5۬'Uq ۦqGM)*LsEO:h[q쇄KGúnx&JяPYWq P~;_6 /'iqOǎzx05(6P\"+Mj&>F9W$K$]f+c_/]{Ӻg5gPGv u14@`kX7c4OTAVu*Y"5JL3O8T ;K6MVY -2mu425X,3\n˚Uc\"yOU{9 D"Do]L5+ء[M7(mV2 %UwK?m'p"]bJq4"{vV@o |_F)/B# !}Ż=WI`RdtyEء*5 q)8ŏ5)j\+{x2?C[. {@yk:#ӥG${F4{36k?v,0?/$O.zHNWk->>[]Z gPl"S,<\.&}Í"qfa:k=JcVh}G\f3Aph|@ZS(6y?}F+QgY7Y [,3͊ZՌkk@(# _T݋LG*/ /0* HH>e!r1cHj,eeOIAĽ)3${|Ţdqkw݉+ÛD~ 0*%0$ x36ۻg *P\"OrjuBwc g0Ƥ?0Xbd/]{5U7 #zGfp;g ^$`Zfe4$RV:m/ɻ?M7$ Zkqj ^-쐼8 L@{f@ڐ0Oܱ?8kW 6~ \+9fkYIh9^D@ȝL=CdgKw>:! $?MP)SW7kߌI¸ rY`ܽ  Oy2 (IERG8DׄS51*7,qsWz?Cj>:;mo\[ЈhIENDB`refind-0.11.4/icons/os_centos.png0000664000175000017500000003524012626644770017151 0ustar rodsmithrodsmithPNG  IHDR>asRGB pHYs^tIME " IDATxwxT׵6ާ̙QG D7RmĎ/qRn88INrlǸb06Ej@^G9g3A!$GŒ޵k >nwR[l;FT6 >)/ûfgPͯ 7~_4_4@(((> ӳX!6 b{ȁG߭ثIK|t: 8cz=kQM\ˣ Vsի__p8gN/R iu k<㊳:r\ oە~9s`sDm\'h.1WU^w_1}qor H~@>zm4hE.K|_3Z]h\k9cTeKg ?Fծ'IGsJsG_$~i!mrwO @KG0{Jb~)R ^;]=g&)wɡfex˾KR_^{sc #V:fd;ڗHhj}=gH s sx 4Hp)0|f 6>&ۯAR1s Gr(jKWV K) U y[3-V@u /<"r%QJF"~9pk Ad)%:30_mˁ>"O@#XHL:53`:HIP 75r2RTUyaUc0tDT !B/R"Mf[yQГ$R2AG1Q ԋ08Drum5ٙOun282uOK0Dg[,"ܜe TH 5Te*IbL&-*O.ʏ:,͞ ൻMa20(q;' `ɜQ)jɇ_cJ\8(0b L>h۱c:>|ҌL.LLk0(g$ǧܿpݓH6%VDs@N"2DHt"r 灼y}qXT5pKE ?y"}j~f@u_@Ah<}9eFXkN9.\d=a A(BZrK" 2N1")WzqiJDERwHJ<%B@_51&RUk oÿrV$=@ B}6"pbP!@P{0 '5"pƱ$^Rv204kn\ޑDQ1X ?@S@i{?h=Qom8G 3M @37qs?֑Q}ZڳI(PtG?rL-a+~ǭᆇXoJG@@F3NS?F! Piix}akCӝ\ڞDӴh  %8_9pb5}(:́3D7rנED.yNss9&GX纺յޯ[y3"`s1|X prZYIQ-;#XAˍ0`bx( 21Şy#G1>~}&,4oɞ=MñrNDIB~ :Wph֖K"~QTz+yB⁊஭+ZׇRܿ){ӻk=@Hಡc ^:]\GT~n'|~]&x5Aw}k_ꎗ:sͮ--lB&T@nl wÚ_F370 NrAOkj D ~t;ָ )]rG\ɪdFP&0fcJ6@5࿫|+Ʋ~ob뚷e"?y#Oc\ߴE| taѣ幣ncä: ZX4ưhC&*lXrd³M7P 1%AV:q̜wc8GV@ ~cACt5;5Շ؊mPǠJѮ8L`2lU@hm~ZFͪ6S~uzd,`:V)ԻV/ұ=f*D_/@(\O&oأ(/.g$W9G$PjABpٚcVoum îbH`&.HA#eOĪjxOHsnHO.H`fþ'hsaF"?ʆX^1X ̽ $ b떻Ѽ  >0k!uas?_M+|SyΒ=-kQ0ē pNd0tM:b ]9hE!ȁ FlIyc.ҁT A$(9廓Sj9ŦHP9WIa?iW 9^zcO07G6Hɝ9de c_ӸKoZp|d|vPi<3w̰G;A@TsATA$Qg&@[]倈 QpHd H:m A)˞g89Zr]C:%*AIٔ쀧>^ubW;L ,@J~1+w+uR1od9¾5M[6$]ئ\q6O^zLrʶˆk?i<( UO[!]1|mOO0dvtqLpB|nuD@Nq S"DWj̫~QS :x /\_%nFyZv %!Z}"cܮ{>nHϨm 3S6 ɉP@Rgt(q$Fe9j,E:ܔ Yji u\k2I ْ+&o4Eo?uj 8G)i5ysTLۤ-80Na yݎS &-&9.Qؐl!kuF#h D@G =?C %I(Yj6uE@.&Xْ+',oD#o?s {J%a {ˊvF 6qcnOɽlA_rXԨ0F;v~_ZG H>4=uc=uOL(5B6hN>Ɵ,V"si/j+FVwR[4rPxL#+bG*zyrՂV~X4Fl|9{|=7TVqxEg-kr'.7$g$L,8Oxpm˖[,y/{x,~i\)ߗM6`ԛ~\6P$u\#u-~yz$s"ycgZ'Ţ1˳ |{>jܸ @`s' 4ĹjI'.'<ѣỖ-7xނ?psPGc̜99yl%Vp|~R6Pdßk+~Vd5vKq`N5î_jsUyC#9fB%XK6nxWMxr:u3pzAuG wBoy #1OxtW?tI%(;>l66{bL#r@$@ "7>8l1TF "۳:[ B`[MXu>qGƙuB xƒ,Xzi >!I?p P򒇻NB Q4DtO7-@ 'D֍3!bd 8@(T#Lv(RF8pkVnz7tMe׃ʸpqC_rι݉$ C__a.2xh7J5ix>Ep1FD9r~n' CN(2"RDPX/gßkV}El(SCs#W5KB {UHGtS{#T}clV9*{>ETg:M,F{3VD *hހWb{0|phM8ؒmbhl3#1jbi3+Ӿn{6tGn!||FEZ"jLӸiA|ͭV ]7LHi=;9! 3{5d*L!CGqV+#s$7qD^}m2AE/o+ܜ6.e:eRr|(,)t=IEq3v! \3nQ .al9zbKfR3dRed,\ȕesVEhB)Ar$D2~ 9km(=WxJ@  M?ok`1_Rq~ϳ[iJV'ɬa;E,W`b:g,f=63A1A]k>C3=pK*AlUYwwM g|+  Fc!r{Ch. zU(Hv8ۛ>_ZX!m<^i{$I_bn|nͻ~G-0z6ŀV- EӉ'y,)\6@i_9V=KΈHCÆ]?8/VSϯe.QVKCD49$9sNuAqo8pCI9\,|ƱmN8ylv֟Q[Z$c?RsP,g:6n4Ukܴ{66'U0FtO=ɵ6.+Co6=rIi1od@WCFǘ }<]gFJIPC\7&IDATh:qM!Sc3#^oBI!g!@ %.hOe\~7ӡJMMi: H$닕(%AŨѱaECnovXt^783ߞ:$|F}$ѕVwؤ .@6ek;{~Uky9 "F\e\߼k[[ZjړXxϤ%?N2#$תު?.7$pGAQnG(;{pXܸs̙3zYEoؾb>'jn\0Bp$_ JD["ޒ/:n녚m^߀JED1jF F17V I"e+5}Wa*X\Pܑ#8zL0[*[uX\|pX9}~5kĜѲ9ca| .5>j0؁,]uYs<{:ۊYZ]s]؜aD +Ioꈉ]ᓆ$̕cMS:;-03ԧrGq*]9\DDQ >}ckKK w{| E-ykUwTnZ#ٔVy3A^ںq?Lَkon\%oUU0[lHdHL.TaD[jyqL>JD-,xr;knTj'%@DiiY5\ɞ1qs&P#ڽ֤71n:3>`MU@& ]nYb>]@Vy|ĉϚ};S"fJ90UZ];YV2Ĕ{fɺRoZ`x-v7jW z0 Eѿejنy9O |B߶ h^ycFκpuL9 K4S B]:οv6]E'Mͫ>mk;mᱼ-۾eÓQna 5UGrQθǎe0 QԿUt8x}{D>.H`'9x~OyȀ (N'^YϦ-Mbs ryЛN 2R猟W@I@45rmx4/g5ٜtw|6l 2dPibMc% 8Lʄ 805gZ9?+܎^umw 'םW/~џ}/Nkކ^ (ZA#D j -KmgZtdDc1U7͆D%)Isʓ̜۽m6A xpm"$X< ؕpP?e'M}%^ёwcC<8D9}g6zDzi)f@đ*CuF?Isz;7zwwZ1?zlUlh$+X'+V͝y yVk۽--` x=t ^ Ű9Y ނBx֝8]Iģs1s;jwp~O6RG$LhUݻx*)IKf&yzD$A( 7!yn5Ը&+XSIcmm!W&#tgvwkekf (g.4INn'hwL1nHwٗ|iAICdonŵ3>HNCm_s^"=/6|Z+sf `Hv#ᄡ}}-!@& |s8 |.bC~[ܿ_MX>I~&ߚ\n+^?4sP۶us@_Iɒ M&D&Iz&`4y" /ܟponr;{յ#f(hy}I,}XçݑV@ΉVmxW;7=?($@j^m\Hd UwM!B)\qŭx[TȲzhA>*474{d̮۶2 I&q_X_h;Y~ gݾ5r $NWD@=g8ԟW0|Cؑ+mCq^99A_k@Ps쾵jc-gU7)ɹME ~_ ;q"ۆX-_g|oPZ_awv mnhuhvk,]uJ^M--Y6y'(;{ (bYS;go}d[<ُ}yvoԶK_<ָd'Gd(Z}kF7?ո?2snrɎ,ktna&.IqNhG,M).a oZn7֞}o*gNh^)XfFA $ lTl ʲ;bsB>8, 4 {VYq>J4H(RJ8;O=-AH7ƶ3ڀD(X|kF7?';?{ dAN%g{ Ҩ:"r:aL(}V_]7db0ri Ć ]04DBNv Q?_رg;G.uV'G qOD@YMSPx5GWzv)XzH(g>so6'nJUAa>뭻=Ǿ1NY2MHIc_ N'94-X$ k=U7lؔcM͟\Z`\l)`#ێTl:qb]P ;#g,Q0dϹ8E=ҎUV B˳Hج.qˏʡȖXæ}mVO;ǒGn*) @9c_*ā4$e N~޷oe1EEe PɀS~M낂`LANGBΡ.E Spg_wF#9x9î}:  TӻJPqKW|TE ز;Ɗ/x?ą5XcN\5peSd(*fq7: V\$;PP M@3{R=!+.:î[vgYX$чo|P>sx(jw:ׅ6|$ 6Ea]mYT`  #j[XSY].$ge8c%ӐUUW<Y^Xxolt2](*5H-C`5v MH|Zw ^. HZN",#2 "j*4* #pN|OŜ1g^ϙ=1G_>Plqo*f,t<"3λzy4\d< MU`hS1c%ĉ5d}%YБ^xplE}wSC? qr=RS~ffr?qrǛׅd7¢ܕ3SˤdJ4Ar.$";{ 5el9fcևA_u7B7ɜ 3'9LhRDM9|pW\*O{M%H#E$Q1ٳ"b0b {@ Wo#RʊMF!^\`uRYA@E4>hU.?iV8\3$!r> ΩٽZ]vQwQpې('"~!@`Am8"?o܉6uK*x"=jS_MN{>P{aᄚmcM҉7aط/뺸^u GULpK5_jK(txզJ.8w_ܲX][ 3u!BYnesƎqp(P** nZ z! w6>|垚w&7'w|_HX:c, ƍ?h.X3klG~t7$>bE2fBg86l-x`޶L,(+M/?$`05&'3E1ڼkGʿ&Oj@lglDn2Jz^TfhCI8gVT=m[}nmcy<Jl B80];v-kkS5^5+uDBUAbqJiπPмfkakp#{#"C$4FSՐ\+,gp㋪N\d=!#`8U0@p控$lLߪLkjt.$:LJIXͲmٴhQ}+'Cs2t>4Ϧ 9$R7Bb HvFzhb5 * ;G%€0Vt:wcL!QڍVm6jgMuWTvҏ४#NhK2CSmfn3>^e4&$''^~ sl!OYGP!"fL"YrA&H`'E|L4.0(g@:Y+Wy-t77TiiϨ- "uGK-)RA?=?gǻ QJ k!=$`FTWW8dFUa-9q1 Q# Ha䳥=_t;=?3^8uےS/Sg )AQ1y@rZ7_6j1<áV6~YϮK!v~{tlMqOWJtHk3 :+AOƞAL$-AϻkvZZ&YI E6S3K S]o0YIp Yt$(K3)򻊡xF O_!$&pt]N jsX?\>xpٔ ɚ $tFz\M]wkաӛH(Uߏyօ~v1 cECJLvGݑqb,g؞ ]m;^OR_M{.-c1&@:Y ^,c9$MvePQنHAAbg!7{{KaOO~N n:H;Lﷆ*Eɻ=Iz`)"ЖX~^kHYQg& @w>$#ro˳rsE u^k[[cyyVS& $O_^޳?ӛ_x{ly.teiQ5rrڋ2Hp8p7yf5{#"}o[%5XnN^{(Q' `'_ZS'v{[)O6" 2h&n0jx@$/W̱ݞ֐:7N_cPL@UUlk8s2ycA0vg3-ߛaRR&XuR5ɇrsr[ M&;l|{|J"_25Uom9mY?/mwIMiԦ @!@\X W/E$bXU3'0KX7/hFLd0ZSbй %HH<3Y"@($~t~,"+%H 6T&v0 |z}]+Ej4=h1OptwW1Ɛ&)BMO~ʉN0;;˅ cm[A_E(n8hqW%cL>Qs-ļDQ!k-Q9{H1,rAøN/4!Gι+Y#E6vϊ,Sd0HE(JǀwBq+JrZ[.\@oɽFx(>2z{{ǷqWWס"i u.b_)B wZJ)J2nYsoqlrrn'hh :;KBB\_P1^Gwϣ(RiԩSWj LMM˲_mc `-b=3ҎC ]0DԤ~믿~~,X1h{k-(rYNxb=x'h7) 44tx5+/ĞRw_3<3Eјz}Zm-[ۼq j'ߛ}q')-syR7)i8"DQDTO?}s"9y /yUS`dgTk XCÇ˶Dt_GiB>Z+z|A^zWy@.oVٳ3MX&e:'zlX?sfWD)|soQw"Ҩ#ZeY[ ޝ;wv+kǴET{Aɲ0Qs%zm9 oۺwO}+3SS`&gH/So5'Tǽ"r-B2<<|¯=Bn!m(HRV&'?IMOqTd,xX8,Cכ y[CoPdYt29z:Gx֭pz]8k+wc:rp}|;}!=Ƒ4VvKBXL&&&M, Q=0B1ܯZ3|b~] ]Fry f/,/1ƘVZ[0^gJ.a ?I.=QMk>O$k$w~V `Arxg2Me|q/lVttPgmТ(Pi  :r0Tϖ@a\(bceJ\&0֐9G-j7ٷƥ+ꑖS:]'daz-ok]]];bZ[TF!I~x^?>a%*# j5ڄϜ%LDs+RxXCArC:Kp_og< أl;wx1ܸ1ir፵ϙJVyBj C$boXks=Q@qLOe8I(nD?xߎ;w13˫xCz{B)R 7*ttJOy;XVg?$>[Kg'CmX/o5LVsAr$/--EJ)޽L:7B{ ZG&Tʎ|&YALD("p f)vLxnJ9Dd9_gΜVWW3Je.xE,ƌI.`q뽸޹!&P(%"UEKi<@*JJ(yԩY|?}~oxx *.P1H8u'Y$9lD$BbQDx ';yvnn f.sss<-."u o/ }XS@E)5zѿMO۲"T: >`!)TDq+hfcj:k,&ID\xPD(tǒ)i$ $IH8I(xp1fY:0d e3QXNz|(ם gJXD^|QxQJYqW n_iTyrCMIENDB`refind-0.11.4/icons/tool_memtest.png0000664000175000017500000000571212626644770017671 0ustar rodsmithrodsmithPNG  IHDR00W pHYs B(xtIME $d= iIDAThYiPTWfVvٚF `7*NhDeYʌ&T22q`4Zj+)QQd56 4[7iEB S?^wolOHRdʔ$G"%r̚nERV,)s}~$##z\^dJNQL&y ><9|F+ }>0/w]ttpsSKVZ1$66?lΞ.Ͳ5AhFhhC)N[o5*59r˱sse#$~~vkP̂2ǝ̙k(n%_[*w==OXv{#GڵfP&;{jJUhiyNUe-a)55*mCP 55^aԨJE#&&8r͘1cRDEEuҥvlw灀{ jĐ@ j5= Ahs 7Rh4Ey=9BB0cƧHH҆'CBBdzMOOٳJThv)eÇO8kv,sn J0;! Ǝ O.(]:E HJzr[ݻw͟?B Ǚ1 uUWWi s?;SIǐbý{Zݕ*45!2ZmEP*w"NA_~yHEԩSu۶mo0'B%Z{}PiQQaذ4E3#4~JJ{{+׷Y(ԍ$<< [n=r첲 *Ga\2 #66R  Kdqq!"…  |o߾ \p>T*TֽG`b4_~YVWH& r| K!MbX]r 7o޼ !o I9=IaxXSJfGi00d}n>G]4 G_sXt#PcRrX2?=T3ş3y&-1/۲IENDB`refind-0.11.4/icons/svg/0000775000175000017500000000000013372357235015236 5ustar rodsmithrodsmithrefind-0.11.4/icons/svg/os_xenial.svg0000664000175000017500000001522213117634615017737 0ustar rodsmithrodsmith image/svg+xmlrefind-0.11.4/icons/svg/os_gummiboot.svg0000664000175000017500000001466412626644770020501 0ustar rodsmithrodsmith image/svg+xml refind-0.11.4/icons/svg/os_win.svg0000664000175000017500000001013212626644770017256 0ustar rodsmithrodsmith image/svg+xml refind-0.11.4/icons/svg/boot_win.svg0000664000175000017500000000672512626644770017615 0ustar rodsmithrodsmith image/svg+xml refind-0.11.4/icons/svg/mouse.svg0000664000175000017500000002534313143462441017106 0ustar rodsmithrodsmith image/svg+xml refind-0.11.4/icons/svg/tool_rescue.png0000664000175000017500000003376212626644361020302 0ustar rodsmithrodsmith image/svg+xml refind-0.11.4/icons/svg/os_netbsd.svg0000664000175000017500000005242512626644770017753 0ustar rodsmithrodsmith image/svg+xml refind-0.11.4/icons/svg/tool_fwupdate.svg0000664000175000017500000000757412707176414020647 0ustar rodsmithrodsmith image/svg+xml refind-0.11.4/icons/svg/os_elementary.svg0000664000175000017500000002252612626644770020640 0ustar rodsmithrodsmith image/svg+xml refind-0.11.4/icons/svg/os_refind.svg0000664000175000017500000001472412626644770017743 0ustar rodsmithrodsmith image/svg+xml refind-0.11.4/icons/svg/tool_memtest.svg0000664000175000017500000000530712626644770020503 0ustar rodsmithrodsmith image/svg+xml refind-0.11.4/icons/svg/os_mac.svg0000664000175000017500000001016412626644770017226 0ustar rodsmithrodsmith image/svg+xml refind-0.11.4/icons/svg/os_haiku.svg0000664000175000017500000004055312626644770017574 0ustar rodsmithrodsmith image/svg+xml refind-0.11.4/icons/svg/os_redhat.svg0000664000175000017500000001215112626644770017733 0ustar rodsmithrodsmith image/svg+xml refind-0.11.4/icons/svg/os_debian.svg0000664000175000017500000002066312626644770017715 0ustar rodsmithrodsmith image/svg+xml refind-0.11.4/icons/svg/func_csr_rotate.svg0000664000175000017500000000672412626644770021154 0ustar rodsmithrodsmith image/svg+xml refind-0.11.4/icons/svg/os_clover.svg0000664000175000017500000003142212626644770017760 0ustar rodsmithrodsmith image/svg+xml refind-0.11.4/icons/svg/os_legacy.svg0000664000175000017500000001015112626644770017726 0ustar rodsmithrodsmith image/svg+xml refind-0.11.4/icons/svg/os_refit.svg0000664000175000017500000001631312626644770017601 0ustar rodsmithrodsmith image/svg+xml refind-0.11.4/icons/svg/os_zesty.png0000664000175000017500000001105313117635257017623 0ustar rodsmithrodsmith image/svg+xmlrefind-0.11.4/icons/svg/os_devuan.svg0000664000175000017500000000737513104132770017742 0ustar rodsmithrodsmith Devuan Logo image/svg+xml Devuan Logo hellekin Dyne.org Foundation hellekin, golinux, Centurion_Dan refind-0.11.4/icons/os_win8.png0000664000175000017500000000744012626644770016544 0ustar rodsmithrodsmithPNG  IHDR>abKGDD(M pHYs  tIME 0tXIDATx_l[uǿ~//EI_ۭIvAW`hY{6`{0`o^ iað ΞV@< mNclǒeQݳ+^ҤDJDQ/@Ks~'Nc)j|ˁɑ3.g;$NLL;N-v&7ɶ;Dx ь͔ 'N",+V4q  y j!:G&)b 4'D,/t}; 05\?OoTU,=GDi^J  @K n!LDHؑ_ۋ_pթ4Tj=.L >LԐ,hź?xN-BZS@_F3S dٿsM!֜2IjUO -#_bk4vYEm%ϮaZ 65˸~0K([:L5re3AA @[ @P[68FO"&'f(.)f~n+a1 @2wz2apLl6<%l~-bt@Be3vR@[ %erK:UAp̬`d02 F#`d02 F#`d02 C#A=t =OV!Z*WõWk#Z#Z9zFoJ7_T ;XP ^\?c@K֟[>m[GjAN0|U0}D @ @,:, 5zqcߩXu40K&"asx(@Y:Pz&·/ml ^t4rcН߼5lx`-?Ѽ}Æ sዠ9admwDcR4ߨ jE-TuII|u[hJV5aKp۴(A ZyQphPj Fd{6Jdjd[%q{Èٳ0H7|UTD پ=2 LNU4Xvtgs_% v3ڑ=Gm^ i{o dN hNDGc$`v$ $l0d:xm8HZ{~ WP7u돎σ +X+ OJl} ̓Cv> Y~eRmʶ~DcAʏꫛ_Ǒo(=ʩȻRƯ-F()gg0B __ KkB8_p9- @8E WnSňڙ ~nP*e*u@ F_0%6Aqh[@9F G=f$[_跻pHs] `d02 F#`d02 F#`d0:46nͰ<[ԯ~' *6~n%\֟O8g&|K^`h  WqW^[G*,]5|ɧ4OΥ97#="/I6lW b6`7c@LRAyuU%Qץ1i`P~S>2)a9** "[qdXM#b7^Da}E`y?]f=O9ir|)xCOPʊa ܾRy`68P7Tv8_w[]P$׷Pr]%7u?C)&T\y|ڢeo ԾV8Go\c4dn^:vzO r&VAY2hKmt@jo-/:Ċ CGZmc-d;[ɪ])$_gJvld5s㭿fPF*r|'bB:HdO`R!n0RL TvjYnɭw^kDخMABwTq!Es)..TKSP0ۤ- u} cǻݸGQ;DdDAbRo/eE*;*kYHsw[pڞg\ij1SiOMrb G2Lt`>[*l+l+ypU ,[Q:`|QKť'RRιжE~@B-þw  G7} =9=ةq5FMVYMUoghRP3L!;ᑗ8uPڂ7 ILRP:eBګRz)tsgޞ)Eͥ6f9p??E}8 3w(+ZtO1gS {&D΁8ڭ K)L;x*h>ѥtR,wFx }D%nfyBk! }DAVHUGE\;}?~cmD  AzhA8-~xo?`Y%IENDB`refind-0.11.4/icons/os_chrome.png0000664000175000017500000002422712626644770017136 0ustar rodsmithrodsmithPNG  IHDR>abKGD?b pHYs  tIME  l IDATx}wt]ŵ9kٲdW nt!4!ā,? y)H!y!B<~@ bSl0Wd^"[ߢ)9ʒ-J&β-KWsf{`d12F#cd5пû-^Ê矛#v`'!22!x6z4Δ(-[4NJ(IJ<Y  D@ IYBFe%#s( xD;"48NoCF!$}K"gq8ΐ9"@~ڑt ] B v0޸N^+N^1nętW>,SC՜@-qc`4S,Ugl)ZSpYZZnbdfAQ0)`#mbp|:|hjPAm ފ٠(ߞ `(<F{oUÆᲕDҢ"ll܁#+Aombm f[~j k='AB$a 'ռ?Cˆ#s?:+]." λqK h=^peYK23xUTPߣtYG=8v^k2! qj+S2wt߁*b,^GJ3m{ܒhWDIdMn~eז>Ԡ 6~Q0">X4\r߶A\ '!(o?D}<_+WZ j>vCvϼ$i~*U?#ߏK~+м}pv4Kc2~9\^J>`ylףO M#AB|Y|tTLea]AF$7-wɇK 3XtnNT 揈n@C"޲nAy bx44w!K$=p<@ @9^񘙋EV ?0&V$#./0 7"dx<ňec C dHju_ڏBȈvwo)`h> HHHCţZ,IQd@"hOHѤ"wC\7c42 (( B2E^֗>|@Ws>8Alݝ' ae}q}^ ōKr%TG: Da X<)wKAB%6 LiN<2F( 50ofo&ϹGXĮw* 1{Z{~iYcff؊u!-װӰɉ)CtQr=t_RPUT5^hSt@?X{"Wtl>D=k*&[-ys!h}[\'MT$A'{,ʕTE_NiQH cs.j'40`k&6LaP`5^3#F")B!/˶6~oDieٴ ھpӇ/;*@QGz{RhF :G;`Q#}&2#: F N(kUP]ޮk(/k1!!|yX.o!tahu~n Ѓ\?s(/kR'b%/k D `|Y>+VXb5;NW<=P*uTB=# Yv po`!Bh4Bэfe.蟅ΓP }az>w.YPZ+bl k۵}/L:oR(氠 .LuڶP3hl}DPVV7o6P令> }9,ӟ8U̲0B٧Ȃ0aͅ/I eJ/$gWנ 8Xٶ=B}k &fU5Ξlvo1ZgYnBB<,spc@˞=$%ØDNu.;,9N@AmpboB[?3g>DF|pcdϙqm>&4d(e/u0Lysw-{R?ܸTڟbfS+Jsp,)e !xрLS>tM7g7XhI+S^`k]E-LAZ@-p?P۽zݰT0}EcKRb \HsN?\KULaP`F1ӝo:~/QIŒ/K m[lƽ;[c״׷H0Hm")h^e0Ř3N1fgO-ғ#ys"$k-4N 31'PiX1f36yj][W7Q)u^h.1f)󴑃a{>f&Pm/HcSiMVSdX^{cx>K( 4 a}q‚ktGBs̶;J9*. Q<A`.}fIfz1}au`Grfs,ƹ6=\Nv:|1 l-V@ ao/Ia /26F3ȨSV%ǡ7,+|LgBk״T.SMќ3nu,'̀!|`%֕0D&.o@kn,;gZ隀NH|!F~U/SjNW^#멟nkf^Pkʅest e b9r/mA܃wSɀylAy)MvSn:,7N!3c-Ku1D  CCCA~f~6͆aA>0p5 cR l-:4Wzd6`0^TjZsE qj `(c V$<{Vd ELFD&ŖK2J+ f;(@a.)}|z2I,pb"dE67E܍Jh0޿qb&,s 'Aj[(=$5M:4N 184N `䌃\cξe}$%ͮd4Tzxk$MJFLCz`Xn.t}A ` Y#{ǴoTO}yCދD|GgO;X!/P9r< 2AI|W[pn/R9S 7R|C ECעn~L^6py(m]Rpb}sK+I?(RP\!cϛcbO:{Vup{Ӿ=]+iQrS1$Bĩ2~ $4c1a;G'AQ5;??C%#-GvnO\]J`Jy63knqz<A_O `8W>}Mѱup%VwbgP Vo/Kq 2x[4nl۽ "Xі'|Z!;#0Wt9{%zlA%,uu2@Ҵ̉`5 1J~>%.7@ 5Br8},MBfIP3mڎn۳\J隟(RKŎM>}e7tE ֖4G7AMDWP(NwXlOTd7]]Ct ݊.]eBBi;l{X )e}&@(X7Qȱ:c3}ɜ@ $II٥`tb|w3sኾ@@3w_8o:H<¯ܳsGϯ]nwk/t.Db\ֽ&&@o&VaFA&f,m 42:xվˎm`G<"YJ&n*Yoh%}6ШߑkKFOXg;+D{VjWb"iШ+G_UO:m:RUd7)JhXe&{G!Af~c2oU^8yK™{0N_}@gbmBead,^PTr!}2 b+Cؒ Be7 ˱=Q"%b KmsukQ_6U%¹sdҝҞq{}Q/t%^םx&gY> yiBFV`bO"b1{˓r/RWrVVNl{~(V1G-k;rוt-\Vm+ 7ԑ[8rA(?V]K:)R^cwntԕr3\Hc#EP>gdNt#%CR7 'ڶxXh>Rn>R11 EN&d,BHkMu _R@?hoL:]$ L&cޚcNdZ;`afV\N. j j6 buMPtڥҸ1p à\Qʕ}y1U}/Qʯj\U`\_c<Wt H 12Y\Iڌ9 [&tE2zؑnzIᓻFQ'c:7 V")8 @h>?^< 8E,H`wt'ЩzQ4k dΙoңTGCI}a޼y:WX! ƔHlE"i1O:oQ*mjRu^zx0{b'io xPznjS' i͏LW30/i`.[5t dv耠2U&[3%P|2 Mhg5_UG(oзA38(C4ЉxŗN8k|q-EF%-SAZ=޵{4[x B_9<_uJ'zCk@#'_%cCXB0\9qRIJQ׍;Yg<+ȔݧR-SK1ge w&dΝCDI%#elge#cIeﯧ3 hΔZ\܇qcH!wnm= }vlor;cv,#.6;՞C,gb8偿 ũ5B^X|- P̱ɛ_U-Ѹݖ4(7BBG߯؟JV—rg 6L0h17b"CҞ.F>X+o|c?9v:*蚙du\V]Y{L@!?(O!| ͂3-=?pd>k,Γիб-_$CL~Ÿ̹} :l@C1}Rb(*t7j /@DŽܳ}C|hZT8n(6IJ(g u{_ظ@A8CIhM}!Ǐ`gM#U˫Bs-a\(de{´C^JNi'x6Kx}g8 _xӦO5{gs`9, ߙ_A'3Q<-U[6U61{̎sfhdR? V?tn˅g3 =$T ʔ=*8ڜ~iRxL6-Yim@IO?n?~ :$ҴT0W];ä6P9|hsIDAT yz(.8د@ 5Cg ŮZ9n? H 2lwM'3 $JQ?=ȥCꭦK:N$]P@0@*&[b`c CpAܗh|HC,A/KJ(MR6,O~-,4W#z2 8 rpdp!To ؀"vy.]Q+<&rZ/4}C@e$@'T @AoPvql6fʌ B/H I-y?ZǸ9Ű^d_wS]KW!%R%:Bx4|M6*iM)rysg[Pl? Ȝ{, n7~R+) 4oR5ʙ2ȃn!̿V2hCc?ϰ n]/Ϲm~rGCbp2S|M?۪@m 8qoySDhLaRֲ]+=00{y~vIqXJ R6__6 " DOGճgv,Oy, `C}G;V9mk1s2e}H;ûz so9}nJ^j7Jae4X}k>z#`:Y |Ҁi`ܹ*?t7ws_: NdE6?"WohW"|Zq$?hl\L`-?_ͷEq98_7~BΜq$?Pd%宆S4:)E[PyX+(ӭm)1؝4d닭1S]U41/X̔e$nz~:]CkrV KcZc+&[D5k% 5gO,o(5ZAVe1X^0rԅsr |*V!ť`cD[ vBG/ F 7{׉՟kiEktnKB U04 Z\ݜlnXVYΟWl`v9Lzf7tk}ϟbO7`ڶdW-BѮã Q^}.1X}'MЭ*lԿ<p|pnaN\K9يF;kHm kv+M%8lyuLw,l##$'zBQn'7k[hGQ њ ^i?$aKJ)|8! b 6;!ȲO\l23=Ǽ{6i?~qVB  X$EV A9 -Y[P$%:(חC% zhG1Cg|,{A^gHY֦gvpQq U'y\ٔ4PXM(ǽx<'kއ C"1KCa뇓 ,hv~y0Q7Sl`m_du*巪jǽoPMM^ %+ !Fb Hkڹ@ti~81@_̂i@ ]h|\n";2@HZ}vTd2,YCǚYTA@SZ]?! sE' uszH7жj#0rRLB;e ]p%UR C^C4') )pI)>%Yރ"ҽS=z;fњ F{ ("L9vgD,3k Өo}L|Ch37ϸ3 (PQBTO* '߆Twx?ONsG-Y24#[?\suIENDB`refind-0.11.4/icons/os_mandriva.png0000664000175000017500000003106612626644770017461 0ustar rodsmithrodsmithPNG  IHDR>asRGB pHYsSS?tIME"8+t IDATx}i]}m"Q%RAI$v\ E~h"şR4@E6;.Gee3,>yn̛:m/s9w;ǝqs9w;ǝ`Lkp.z.yrp`{rsP(tg)2X3\:I6BpZrnn׿^x衇r4W2-b]FHҎ$":eso{\X~xx3 l3//;?Poook$c1C6p-m;]}sgp+l3k_ZKF}˭ළo !u;ve3Pzꩻu|o͕H;BVٳNy3m0ƔU qMmVcǎ;45*ڙT4HQ2 Ԕ[R`FADW*|[* ح??g?|5M{fp}"~񋉷=b>gS2c)$B 񝅅~ĉ˷_m>蟘y-7Kg2c؍D2̏FfRFqs너'"REbb%"AUktv,P>gz{{U6!~|Ic ʘĉǏͱ&Oڐ(b|׿;: @!K7AD AM <\w *79@>^ Q{篽K*vS h\6kDPe"%Zs1 !D>'"% d'7z4[ֶ>tUM̊Z "xq*?UP> A[}%$;I.*F/!YDͮmE9a_|ވǩn#{{;۪X!QuMo"H"c!+B[ 1pΛ_n I1A2\EsWWX(>͵b@z*e? Sp=FZIQ6Glf;΁0 O8p+oZo;-˔ ĄKj6Tu1j[P~P*DwvZK9xɗ_~~=R@'ziځ+M_j3(uԪ(tMu6!.P8OF!znSEGף ~8p9[B{)#%ip> "HDqT&J9e"뺨jP}(r-TPǍcMӽ7z͔Q^?޻(=Dc2%`("aIĈBaPm8$:^"PQ06! B='?W GDÇ<&MfCTl/TB\n:4XR't+ }Je 4:^|{a`y jE 7KM4M 7dx{=k<+ %D<σ纘J/7b!Gt%Aˠh뺨 1lu.RƹTyɀFZErHi/=4a7o> GQ1DWsx7OG&~p=:H tjM"DBV+!c] !tjW!X7H8_! c}_Wұ01_'G>zgUU/N4$DR<&8D=O.Msx ݻJ<7-Д<ϋ_?B6w2hBxXo"zNэ%s/DT⺮OD8f_W+߿7E繩| Ԅ~᳈Ptywtt*5rhY{}HUNB6dyl(% E<فA 8= !9V+еwagFf&}`"uLsk2"L {Li'/<9Th?(JGZBq\&w@װ0 MSjad,d]"^`DF Nd>kTmdso&½ѷTo  !(LiM :@5M{{$;q@`w}}0j /WrXvvcO M9O X_cjp?gч bP9$tQHyzNm;Ji"'< us~xϞ=n `)x'f2JȢԐd,"LSaPU0.*z%l68MOYDdq6 @P=PUU"/szZ$\H.!"p6 ݵ{\ޒc_񩧞kG k'WZ> ۶\[}[Ңku(² hW7p=Z OV-c3M}+ȐDs Pg`*I+?}[5yOĺ,8? J3৥DJnh0T7Hݻs۶m(#l@|"t]`P/R!|!y4ofoEU:,˂lX\,ԩ{6v^Z_|+,-=Z}V.4H@]U(z4 {"{ehk;@d@UW<d2Ԁ m۶̕=X qPᰁysr0 3‪(0 l86p`s- V Yf!?-<E:n;A`<O&^I!pq.`L> Q\ 'aNP8QD4mO@3Z<@i@_) * '0ll܉˳DP]b  Tu Cl EU )SqsJT@T===HDCqOd.v,6t@TLX~i2LNhJ˲/ӗ\0Nzz?G)0x.p~D TJ}zL,[ضm=L%e֌-?JQyUy S=~ 81C`k~Nl Ef )y. i"TI) P,T o9((20Ʋ`Wq(^}2AJMSw}_I!97Tmۘ-sߠ) Eu0 \. ݏ>Uc-ڎ^ס]Kc`T\8z F #T$5@*q5wsB|(W\DQ}6AΞpU.rۡv07iF9ι[zmBMѶ/Wض p yFO΍UU@4_yX\8T㛚KKYLN(-qT ;w4 c(+]mr=F Ky )k\eSZvpul~?!P0or91 e O@x=;w7tӛequlzzp^?7L3 11+" jxfDˮ >hm՚e]rIN KD䌚cz0MsaU7 Mm(i Scmۦ17 ##@s0 ]d#QsPMaDZYAR!" RTH$v\35dt(QU/QLsk 4Cbnz<W`vn']AB/2cc;Q.2(H1>~?t};2Ԇcߋ|2FP%h}CIDUC.JuMU 7#ȟ%Ьj0FzqΥ&Ư`|b;aYtugdf͎qvs[4 k `R-YU$4\w:YA*:(~/`R>_H. #A)V&ti!͡Zw Rcc:>XV,r2 Lӄ( T#_N؇ T`ƺKy hKީk$lz.ȓz"_⟚tRXjI1-à* \ ݽ hƽHf !r6mGʠpWU5wG6F#xuhQzX$1H"3S$!0H{6@ Jp|R6]XDXd[EkfiOlGȠ!g2X0"; Ҡ* 4Mk'\^@LWd8U^k4 &1n>z=xj!@!BUCŖ:{j *Ni yA" >)|#]&GQIzUUp+ PT` D`q?}$I/ &""lxabDNʨ)W 8F' qo^g7D71 ]]fsbQ:tMP5 *@PP *Xyp?n&į8m8Css]]ýVmVC(9/j: 6BGc \mF78sS,COOf5hUQ88nQ ,628gA!+OE !._/dlmpp޽{?yP/yŜkEphRLDp\Bڵ/;Ԗp kT lYdsL C OHZId\DBƛj:ꫯ^u'.]um͌In*xB xPIΒļ%s3h!8:8=GW]ZgF&*ӧOOPp8SSSä+ $ǥIGv8ӕ}F x!ʻum`f &1;-]ceVvNهcۋͮK@,̙3ԧf6EC0uk?LÁm.zNO Qk7OȊV|bdf綠\Y:E VԠ*wỆo rriXً/xk$lTڵk[Z9B~/SXC35Fc{w`ݽ <q:PT8$LO`yi!5(]c`hsd 3;˫yb:T@L&58@P,ιӉ'_* :%*Z˰|lm%h.2gT.C10I( m<X*@ ?ÑGydkK9sUQ40E[q7A~|W"hLt .(詳m{@Rt^r0 eB7M`*QIDAT̨8;*ph08R ] '2Yay6;!(ńҞhf צ>o"zz`զ&:;;H4*KM+ؑե^,m$㵏y౻hL Bv~EA\gQ,vs4u]1 g>8uYB"Ipp"73o k(4gfby+!Kg&%un`RT>p}•  t͟љGòYwP E<øtV`!vùQw+1AaԠ~ue C* &L.2ٝup U1KQ8/gòسw, 7@ĕM<) Kom)@P}7ۿжv6h@X_+?õnp.~tF_N`: tgUx,`颂%[[úaƠs8m .4UctMTq }TaYNϿѱ` s56|d~62FHD>`,`P]] 6CT\23xipo`4 }|LJj{ᒂY{Kl'Ϯ`\w ggY 4Tpd 3C(v"~#c#O9TnkbF`nnn7|'5h'ڵ0Rۿ|>_X),,Fr]\,CA u@5WiԨ8 biA!:=^֎ 4M!U˵^Q5rL$P*9!+ Tmkď{Wy晷( j+ڽJS8c0};vd-r "zEdq D@#7[i+1ނl鲖s wN@&")Xfr0-? jPD{5?xr44g!(huW|{SSScOir8p`[.XQSÃũ,lT ǛD !e3?C]QX@"XLƯrfsjD[VTA-5UݺF"6^p … 7pC&̯{t0!r~!$g~P*:Ql)Y,{X p=Pl%tK0P`JDX'asZ !:ns-@3dOO1&#j+Ν "ZZ[d)P@nzzz;7#ƛL@*> j5uO7MXRv5CŽ,S! z4A]E% ['"$½ %.G^zT$MܿV;rЮ]8qSs,2@Q7B( 4]VVdpہD (Iaf/$뱁'ҷG 0Y@5UW)qCuR 3]z777w_|X,~ܿ )=J2}Y믿~{9rh9\4dN4BA뫓x\Ӫ`Apiq62'[w~JHry?|Á˷ -P `˜_x===[l. /LpBX3rh, ЊŢ:z ӴdzUiШKzytlm݄u g*IqB"CCC>s?,J,HM< R^rs{LӲV3A 9=-kkqKS@_kՋj;қ QVO\xG F*kHȳB K==Ǝ;6)CdV:2VaRhHĮcHS 9?;O?;<2rlŔ_wja tww}y fIMM/R%hXpIB6n&ڏ'QrG\:u+ \ZTBOOϺA%O҆n&af!Q.y ϭ@jFGGA af.U&M6R +|ErxJw}^|w_L}1f,4ZVBWWj+*&YaYzKhniVAzzԩ7^z‡?,I4`+ijU\tiZ. t[5eqFM>Qk:AQ$eؠ).\>ON:"ۮ*Zqhtt p'n)[qMMf3O?W^ ]&Fߚ}n Ъ'a#iJWwW7=an`H'NT.O:K/ܤ_lQuK2E8tulll|>g鿋;6|O~퓯ꇵZm Hyl8ot< KPV݋/0B>oYL1ngBx(1ًV- }_tŸ =Cow3^ -^zuZ>nlO6sG?NȃBHʕ o[bq*E,F!R^Ir\xRQuX+(zӀДM8<HofvfG?|whhsȟ XGᗓgt VGp. ,+w-;w4 Hԗ`RљϗtQǓ1 q4k×? .^V5mfAi> zWuòw}} VϺ< f"ލ5lֈt^$ ?2|/O#,_RJ{IԱ ;/" A!@lǎ;Q(t2܇IlyǑfS59ABm׊ӧ/"Y;YVI2N[S=nW4S 4OIP@tttda pHYs B(xtIME :6ORIDATx{t\us;eɒ$6&1~a`a[~[H6ġ08@K*h4$iV(8<7q *NbclIlY/ѼN;h$H֜g={{|˷|˷|˷|˷|tMLw_:W\|si2L/M׹[~"%UgC|}~U R<' llBgUUr46s#%Gv׈<& 1o`R<l[L MP3t kq2I9o3$Ehlv)ٱ۪v(r2ݪFY F~YA{ Tj)n{ )uTdtkje3`&l3K\@VK'b&[> uUcdn,ds[rߡfAJه]J/e2۪,֌`%_@0urE)82d Oj*hu݃0?EPTD}d?a,`V.~"3@6ߴ Nr9<d_`qeeZn*OGR ƎOdg6r{ATIa+y <p [ZZM?Y )5ld1>e[~\@/ioVBM[RrSyyee>9TJ~Z;uSCCzsT))z>l&YF|}^U#ۄFJ>gx˞T_s5&t==/{o+/E*6eE ۅ`e3g(.橪auu ,zzzzE6x| QbchZRrdz'([@l[wZ)3_ BVY7>g*R͹ꪫ\/rp!愊fc=*$fO67=>p@ ^J;0iĻϗtN|ysX*%Sn*uu#&ZQy 0~ ʹZB~BPp>;>HNBpSq1[Ȃ<'jWkZ>B 6U)Z޴ 0AogzL۩2#޲өt) 3`?7M_i I1dvp_~56uB$?/ ot&~ xpMcш{IٺтF`I(LdȾ#|5 M4*^ɜGjS5nq_g/M55lKFo&?RIɖd:pग़Q;-+L_L#ɻ7:KsW8tsJ փV9'4__>j]g{BD2XYLB)pSy9[Sm~4!^3Fewx !G01v%x'jdѿs[3X *"VN qEwO)Y6{vjw+F/[}65O]AJ8pfʔIL%p0[,@0t?;5+2UgdMU 'xHɊdT_=We 맽s\\T o&XIz*Žo<ֹG@;g?|~@̘1:e+߃iLY)%fdK3=$ԝH2m@uԟM7trKo,@Y& 5@/..66mTr_aH# i{V䔺FCCCsq]3bJ_~S m@+p~~\۳)k.0QkZy)Bd֬$n%%<&jnw/Uccc$PTzpf<w=6dQ'l6$B+q$L".(`C˱ͮnll4?#zW_:;Ki'oR⇲|Uc[ Á;z駟>n$n3&ϙGb?}{Mg9TD UBcD;?V]g{M%tŽo-~Nij=Yw$rINE1"@3xxA;%|Az<D":$x[/պX?хi*{&/w?s@?[zizKx罇[w/pv]VįjI@a[\W_}O #~aȎ sy ';sQXRz-Yf?rŏ{n{V4T롽&Rԓl,5XP!lq= +oaGr}C!lztB$ԉ&KK}W[iT¾/5>g)p+WvxT8e>/QL ~gϞy?ip:˭#~"Ǡtj꺺+;Wq[An7Mۏ_C5-.g0Q&L u}Uε0nl|9{ NC]ho0 aP>wkd͗p)%i $43KK\êg7JI9K\8F$as9|fOW}EO#H$6=3'z(`wO⧦2%gke@5PkF﨨HS~?ntcDS(744TQi3M0?Qkv>'RzBJl>?U&"=`.mj. CilĤ }Nf<G.`vů뽥P}*bܳbIo~'{ a޾DR`/US)ͦilWǿF0^E|n7N/飒^7\V|w)Yf-Dr\ڽ0Xmn>᥋K>D@2n}}rߵkWuqqQ;+_$/Iď&w_t$)b|DrZ4U"O\ 2pUiR X0FMڃ{G3@bBUFD@wQRF!G7Q4F %Tǔnƀ #EнiԸzq_z|=G!hq${N+L'*R xlM#cI+z)`4}-lx@x,3CJ1z"etҡ* SŖM$cbLbu`Bt6=mdVnb 0<8k46m`c"ć9^s<`ΰ nri]0v%r m?5 pÙW')ANJV1ߘp]׹-L `\rjQ+2u/ZN!Ww#zbi@!p:>:|>|~?:B~M#%^/*}!Zk`:>χ%cxĭ븄g2L~;PL={l]vˀg i4GӴ'N@@IC3 ØY\\\|>ko k2u#G!0H(i} @>}E R'b!*q8_KjFBwݽ.\ϒ.p#," It2 1@+ _"7ӭR9>*^QC=h0_УTs1NEHN (1c@"- 1Gd}n FbvkJtnt,oo18>LnAOF\)AeP{1&}aNd ʰ񉴎DO @!#;ghL<,g_4qXLY4> ---ZU -p>IENDB`refind-0.11.4/icons/os_linux.png0000664000175000017500000002356112626644770017020 0ustar rodsmithrodsmithPNG  IHDR>a =iCCPiccxڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧ:.bKGD pHYs  tIME  ,bYIDATx]ypՙ.[uXƖ0`cC0 8!&I*YʦjV6QV]BJȦB0_رeƇ$dH9y%y^UFu~QQQQQqa v V,0g 6 lY ' `1oG? GxK|sHx$ < ` ץHy N@xT[W)fH8R 9 !ӌa-[JALX1+>P1EE?8[Ąo+ ()jRM#@/ 3~4$<B:L i_3Ә8'pUl|>CW[Yt^D_:[gЊYHϲ@J_9> ?[ wB,\D2x5~}>CW "wӊ.g0ėn2H;tcrF%DGrx,VhqPhq>'Ÿp @2% 4Mdz! @ L|2DDr3"D]TAfD$$f ~e#*Ped*& Sx 8ѳ.{j,&]UHNp'R0JG`*%pU=*tY@=D+L(4y< `1vݢJ!x@}ޅiu|_M&Q>IY GD$*MbGhN\0]t\l6F4B:_G|MŒ"W($~D0nar(9qz7}ԌW998==]5\r)KP!!.満Hd Q4.CIʪypOβm KICPB@KD`n@`sܹeopGggY4Hd‹/>7Q r Z:dUVikkx c3<26 h-ZnddG?K\Yv7'Gf_6ttyn H+O%I }jhS ^wMn?Զg y0݀6NDUO$JDL,D9 ъKL2Ӹ5UyNݼ՚1{14c.Θ5< iE_zc=s&ntl&|FD  B4_O6ξP_]6k釡2+`gjU4w^]kn;Xuw ;Lq OؐuAm!LA#WM y:*]=v|}fRvPݿ˴(;1ٵApKqֺ5[2!k?A~2V1 -ķDLq P>4eqIT`li-pן@+Gf4W<~wo:M3]&3DNC@zGxdh{G?AQ-E2Up>N2c8\>˲Lbr|Vw;ڡV4nC퀨)r/@E!sL|+|ߟ/C Y.ⳃ8=Y[ >zzyf<}/`  d@Dcx `Z@uɁ Gd^/ct D-Q_WSØn囇q r24{X5}Cs jvL#w,q ۲.`ض&e|~6ehfV VG_#o#5޲~994L@!:Wn QqHJco W~o^}ЩIꡦTYA,@v(sD|o> ߍX=`mpvǁc7 76rڱs;"щ24tj$rAM2\M@ob7/eH|,ܗ!7@ L7[c %A|M^t~&p.D 9"$b=ae^ !jbQU.ǁ੭$ Y㝯_;{D3ѻ(w.A4 гA2$|*DS[r@ GN~g>sn~&$w+C,$s&"yA$|H8~'/G*#l6D̽D,~Ơ:‘(FH֫ʦ#skV" H7B$N!r?Ә_V8]_牵Mu /D|'Ӌ)jQeaߧ(}#;}~rZ().z s!uuw ,d~D4$t!f U9Bh UD }O.و(DC  &M/@eOV^-L]4>zM ctn"Y& }MѾDzD;;ct?[@k#@Oc߈*!"}mZ!N\@ a?[Qŀ+XCyJ[9 >'_sEvٰD DsնU}2tA|ʳxтր؝$<Ay$o?wp r٣9~Edf{\Lr*IwT,i1J՟&lKp*5%lDW^(bSŲAts3ap1XHM|dDPQ#ĞI7@zq7|$:j&@4?2H{u"^")y?CzJ# 믄%vBG%-H Ej+hT:Dz_#Q'sNB- ,[C jB&SO# wV 9wsYej'RGHk )Jx:G,E$wzp "U;/'mDr!(T%L{"~hEvoL| wDqX1)&B9bNÊhN4((tbF'6iy"qYȺ 0G%iQ6"V٫9WdNHYA5*&&(Y//0A dJKLoAk6nn7"iCp cD/(c"Ib.l};r#.|PW9F,$&dDw' eRrX# kRYM*d/Ud 4zTdwONN+ %r!\Duy3Rq628G( U0'(:,Ѳ-=eN|&QFi 'Ҙ;OnTN}81M C  y0bRPQ !˫.p,pZaZr"(cDlTmT>L=Qei.2l&D?4 ?7D C(((<r_*dYEE *[ ZW~2qf1Zؿ mJQʠ*|%Nw&DyS9DT&R>EmIXm D9e5$q=OLoL``8WD$m:#YFՊyE,M{qw­cQlϾpͧUe[ّUfƲG>U9enЌUмK?tKыwGqo'ga}w|w1 2/߹9m}//ge&f &zﯼ֨Xiмn["t"KvpO֬zi6joϭ vhm7!Vd+B3F{n3q+$8 nm?E@S+oN@9&6?9F@x5h5`9's}["֟?Yľ4_DDh-L}j$}g5W\ Ww^_{d+7çXAYK0^f!σY_J\{ PauG^ꉧSؾֻGsQ3x5ÈG1+! zH1*WN%ŝP}oS[(^`D7CmfkU:_ܕSmog92y"- q6w7=؈B}74w:wv rP,c+s>o76r5ԛOZFnN#nIENDB`refind-0.11.4/icons/os_freebsd.png0000664000175000017500000001353412626644770017272 0ustar rodsmithrodsmithPNG  IHDR>a pHYs B(xtIME :MaIDATxyU/OUWo!`UM peUd0(xÌ8\͠seD% A޻kU鷫zJ{_'ps0ɍ ~fNͷ:#F. c-k4fC@Lo*:uf~+AWV9!DB ?4(~ gE]-L@3:#?Ҝ P;X OLeknXGTjZ.%K;i=eIaW*}'?!XCKY1TpC@Z;?}5$c'}grօ|F3"M˦ IpJHKײl!Mp2E3ph [)o/,cCd޼HeRWX;CyXf+J|};e@3կ,jУmK`odB_ S) by<&y#>=j!9˯cÜ*iITK01pBCoYu.O}.ga8p'ˮ81[W6%`o.%@PO~W#[2I^ˬx3+\ )l cdCoŜڹ[4h<`xu>M><Ә]s |}gć&*1Nؖ.t )7bN>Mł{JUiT! O?`ɇ"+ +> Qr'oV6%`Tp_IPb9(l- ,`f A0GUL]!lcޣ\ ~3(w)KROg%\s0G ~uTL,Y"|*;(A#Xx-pc^  % ds:@>yZB>i`qDSO cS?u4WI]ued+J-"9;kʤ vfƿsܗɡ ȔheX{)u6LcJDZϱt |ZZ2'5;|C4G"';SR'W q=ަuO13ƨ`#1jV#ZNkczhy?ce\+|5$/0p#wp^U8cͭ,*GO -P 5'Vg+ ypt)|6F9ϱ2l-sBk(րI6d/_3˹M4șeۆp G+t 1 9^6(K9.?嵉CSs/(Fj)ȍL'qmsy!{\#l>G&UlzJf k;{ɭQt$?+lp=]gA̸"AԮ!'8= o4oq_ms6cM! " ä=v39ho|_Nih 6 cཌྷId0wVxڸij)b\t }s_5cһpH[@z$MEFFه䔩¬Kؿv 2n,OO>8Ȇ:j;X42':@k9V%M9]9ˉχr!xw'i )0;HМ@dDUgUZjN\:,ZN)s}}}cC@vGxR(2* ȭ̫)\-\—dW|Gp?[lL q;l^nDZ`??^Aߎ,5 6 j*̓9t\O#z%,Xfˮt#!M+ޣ>/cߕ`j`HII4N*ÎLk{׳m:%6=miO`w9 72e<`~ aDˇ8D|bcp#?‹E2V?Gf&PPM̉Ee:b{G*\,:HT18<"& )':uLXNсw/HNʬ8PFm6|T!4,l"h*њ"(?L?E ĉDL &>ڃOMme$"ukwuh+qRAHjTQ 5-2Ёmա (!QJT=@ŠxXA"Y%M$12f^meUS Ѣ NTϽJCA*K% dZI-gC;/Gbt6/{5~!#9z}ό(VnVR}ơZ%b7/[ )@8 仡Lk0~ O;a| np_?VQI]~ɋsiDGWV<XEg&&zr|?(V"8n;COyW(-JXΫ-"ɵ::Ys!e;kG>ƃtt}ۚW2Q?`pMIņs7>{f:3d ^oͳ-!sKJjc yh gMv:6]}oEUGs?Mc-b"Ɋ IpYJ3N;5VG ~'/^Kn-D|xzGݙR4^"(dLZi'@0nw wDGߍ笾X/9% c Ƭ7hʉa6'18#є-zH+Cmdm{ 9_dX3"BBXb؁IfA];ZyV?QmOrV_hgxoǻ-BB,BV12)4/9}dAS qC;+X0oĻzIY}˶;B&1w A,r9B+4b$BQ9e̙n)2h{On\J"={ѣݮtfN~*ujDf>H-XIf[ UO B4I>zZ} }B#&jC7N7PEX?Nyn?,xOq'0"!1k "y?ӿV{kWRW YZy݄_(t_MyB8g';nM賅)7XH H!͙r P"($[.Var"R0W($"'3E2L9^+俏 !_L\xemۊ CׯH(0EgPL}6cLIENDB`refind-0.11.4/icons/os_clover.png0000664000175000017500000001607512626644770017155 0ustar rodsmithrodsmithPNG  IHDR>asBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<IDATxyG}?3{Zݖl|`ȇ|IFc)b .cL*JH*`IU`$eIuٲ%[^jwO陞?h޾};,qu,2T+n)Ȫ6<2mj[s2L]]nP_gR95"Fh헬푶_n0: ~^v猌6U_ īp1rc@ie";xuth}1nb*SYC6I8ce(l}XeU Nh/g`;h&۱^c n~ y {}3qx\H!b\j2QAT/ ZJM H-|R @~*]Y ޳`Ҿ"f1bm;wxvs`TA(Pq( +6b/a]<̗x@Z2AdtfYECl`=9v)f Q@|ƃ#f|N"0^C̐LP &>ﱙiT@繋lu"B Ī`.\YI+?#ws%FhF $tm^}|61R\wwm}UDZ7KMUK5,g)9\g%>Ʌ4lƦe|YA Є&B٨pQκ8e)XUXif#8  t|R1&F3+A?,UA㏱V&@4~`6ˉyߌA) r V2v& ]#A{_b&xN ,RĠKŸ}qq;.b%!u,TD;F>WF8U @4}=ۙ4|)D]RFH2/㠃E'J\}L|&I 7QBX% _㝔^)N#|Uk2KY,\HIYŠ C<#/ NN Gp%5M@٨@7cAI(*0PA$YnAM3LGHuKX1P_w췱YgJYOe\/0Ӆ QYJ~ZH;rI!i6WL;w&e]*-[)|*ts2_'r1RN@ uf$U򖁠ha> .@ ?2kt'8I8jL)C;*?lqo6>X%h7 IdcsO*l˥4]&R:v8 Wdg-+@0U Y`@?ħzGP| -,Ħm4'Nޓqڙ\\l)4kIu[SWU$*Аh•b*ז1tЊzVE@ٜ lLƣ %"7L1 ,cPLqHEJnf[yͼꫨ1ޖZTaLAN̻%tr+ t=k:KF&V_mLaf!sNNKRݵ]:1F E|ɇiVlf#ݤ/# тċ$˳Bؤd)*%q)5br7 ދjR>uj`"㭟r4 \Jg;7<%Q*,4M;J7xê=m4PfT?@K )q?r? :4ipJDh1GI!FP%Fk{52@39=pgc'~ z AÊȭl[f m?%IJkl|FJC7 2~_e&1yRCݶ!Ƨ8i"Vhq=ĉS`ӸOg/ ,+  e 3x5|/U:(5%25\JtZ@ gYV#DK()$Yll:.#{x !õ>5LĚR%@4hɨ$Vc6 6ܣM=ΣGDme ZJn\ v`83OeSBQ=C`_ Uyr  Sp8>"Oml^A b?%p'1Pwqy&|<9 ap#W?'f*.]~ { yV(yLP!VEra ~j`?z`d]<IWL}YT(`5Sr$?lc/"E*KWZ,6>ͭ|>Mz*A=ȒY'Wlc : %&d8zr Qhl泔[H1|M[L)18 7o@m=O ivu1|uҽ^ 40Pe YB'r5*ژ4ٙڡZ isyUde}4$@rKPf|dD+#yQ1s=Hj* kqGٮ)z6ѻqRh M̝9oQşԬx/6^,3P+q89y@0#:TZ餓v:heMtq,sT|7y XW<9dE KA41 7$f}hfBWH #C?C1HIz襇n1@c>R `4"*Pd p/=j9tr1 H1H0i44W_h#a)dO%M2bB 2_<{8.v79B4Tp"_:bxXLIr@hs8^A yg;l [Nw`I/Ht.ͼ̍$X &e7Ѭ@]fp~pt11]\M [rSHh P٤GQC]g-LUh높!ͦ ۩E+3@9܌E G"-w(2k # cO-RD~ IND\$.!Am RqY2pmՃ{P'TNVu?HP x dJ`O` lׯG]XBT,a;XXN1O0cڣ"yɡc-^$EʑE\Yz$!+s[`I %O`/{9h =]PL1r%\;Yf ~R"p sz~6ަsHAU@zcߥ(_9 KgDؓ8vOa8NNw>/aW@x; 5FOEM O[r߱sHd~Qr_? ~0!0 !a ~-~dD82>0$$CCWl[îj%E|ǩq]G>>~$ V/"&xL*>"GMQ3eh l7l腅'`Tݥ`{YBTHq&D!qL @.y l-Ͻ\\'H&{!}P E^dr&0ՋxG w~XvX NMe9qgr!%@nb|d [yWIP?R ASG Q!~B Ok941s98 P$K9H0n62٣RP.h4-سVck\I'<Nj36hϓg|1 P/2#ؠrQ)?H}@TQy_u0P$e Np1sIA^VY1~2*D饗5l7Qswz\l gvQT#] ǁgi9,`&X||0Hw#b[E/x>=n"t5< ;!Ddn5T h\ n2+XRn9:==-''즋gܨK),\kư32`Ҩ.2q!OTY8aNg sH(!t@Ez z&p4CUru$Ut8! ǫ|(7ٮ&'n0pP}"\4Ho:y(t'떈 f:!'=ȏMѩḂQ<is;$e |`m;Y2d9AΊ@J+*v1=r֫4mmuK=y^&!tVqr0xJ{@qx=CjՍ9e «H7] JͫT:kko#aiN4|էh/U#[+a̛f1G7茉JfץBxyx=JbGgExQ.6]?IĶNtOCa7F*6G(+M #Jؒ|OԟU*$B@dz8z/* `{0~&d/%}4˛'*zj,i u!6s"Z$8-}tm[AH` JdBV~ [=䶯̇*m.r&,ܪum[Ql/^mPL=&βMTu * -,@YMPUdgW]ߡI[©սM]eH ,D@eS &T u*zĔ!'_I8@"Ji-otNTEhu!T]*ƣcAOKrLIENDB`refind-0.11.4/icons/os_mac.png0000664000175000017500000002451612626644770016422 0ustar rodsmithrodsmithPNG  IHDR>asBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org< IDATx}yxUk@$ 6ADYtבˆ8 ʀ!H@fYD6!$$@޻?ol$SO7{{=sϑp H$-w(YkwhD-"@Cq_@D !,'߅Kg  ~K5Iw"Kx1 AА9 ]m mM:C}2>,l111**R.I0aBe2Y˲fL̲ eYh}ճ+Vg2R9o{o6иe֗om4LhrssM0Q=t @ Bk Dh4)fҍhUh4ܟzx@*^#A[r_=vl.to;jyyy{&O<Cg6-x =zK^ \.δ"ju';v7-=#zb}A|ԫtqnf͛7>SccL ڀ4Q_QQfpp|a=ځ6۩['L/j5絁E_|ŋ4͏=0Ifc~~QFA|an7!|w=ڢz.zl)-$@}Z ^0L{pZqǚf;fr\.oXzl4Ͱkh80 c70 h}m:u^O 8N .Mn'U<կVyE"(~sݛ궺:ZzFՂeYU-]ORRң-8×_~Ur%Q"J%I;v;w㑑b2 #G@,$nײ͕RBȯ_Jz kvw޻ dٯvt[݀,`!G%OfҥK-,$Z'm ݻ"//;Jߴ?~Pttt0T0L?adtW]lf7nܘŲ>P*uf;vlT*KLLIHH PQؒWhOWUUU2 )%M'*TihfСC?>#:5@9֬YONWj]N3\w[y'$$on;vs%8 }wI7*)-~O>"*X^fl,sʕEqqqO܀[Ç? گuh#֒v8N>Ȑ!.M^Xxٟ*I-'uY|9#YXˋTkԼ]i.\xOV Ǐ mI$ɀFٳ珰h@5q7)---t#J_~???2-`괴ۙ. 55ٳTOlz; D"QҞL&3fG2 ROtZDjgH333}(HZr?!:t}qG` Z#h&N]ee5wz XF?ly>'T*_|# xMX4BտiӦݻ0Lޫ!5Mb4M6]|~z999|||T_ڵkm۶?Q :IzJKKP(‑H$q 52mV{S}x/2u0Cڹs7\]5qqq׭[$,pfṄ~D"QM@DDDDJJTصpު`ڴiƸrK/sĉ -˾@&ɧM6W^NW@8,XL&hL8qb,$&8o޽Au_xqpXXl)?Z@7@kXJb?+[|`y02@?f̘eeevUUvѢE`D{oT*m$={F mS埘8av{гg~#OD Vh4jݻd2i#G 222h7 0˗h4ezii)Y9ٓk !~ĕYHfϞjM'x(ص= / srr*Ν{G[n<0C"]y.waq111!8LZ|;R$$''O#ˉshԩS7TWW5 ~AO\F'NP(Dxmذa,~zd#AC@  ;~̙5,''ٳbYY‹/|gW(ŋuHLL|| @O6ǐ?##c\.孎7*J5pxɲ=zMV%N^ FErn3g;D34ơBlll 6'޽{sSw oO#L>W JSNI3B 0&Mz<,,#$C&Yf=+++ͣ#}| M}FOtڵɾk۷饗Or! o~"l J=ztصx۷qDZ\\\3cƌm?66VڥK$DҦߍL& }aybiRf?իW? P- yM9bٻwoVEE Z$ǜ֦} &߷-ZC裏q*Ԝ:ujpY_<{tqɒ%SPn@"L|HjΝ;rv-B.^y啧r9[O$eY?xh4;=م /JܲrlҤI=ap M(Vt;w?MMIId0 ??,B'yh8' Uѡ^ J`ry:T1bH^"ILkݼy3L 6%#]$Ҷ6lػDFF>5``d2Yk }1ŋ^PP_%ژ|ڵkST*c^ 7]vA&HOARb{>9_HNң79rdRzRSN `S=M{ݾh8|{ɉ^? g}гgpO<@&Ezn03<3<$$d-4#?50Բ}aO/$ǛRRRHbg$胗/==k.J%qaDVXF}>|xg B2{ٺ>},l˻}E%:0 s 000p͚5ςEk@ם;wW}b^SDիW{@e㎋c߰}BA6H4C<}ྰ bC^ .333^GRaN5%T>5s9G_Iܹs_Xsj{*Q}pk.\Ђ򀁯 :BUUǎ{R&{8zkE^^^@?u|]bj^`ٽ^Oh5`6ra47nj ȭpf͚aB׋&%˲jv;8|իsaYX˖;G}<33gocǎgaO,jkk5ǎKv"//|Ht 8|p*qm83L&vƍ:8zҹ_|R4ٽ$dBCCXwhʔ)?߽{7ٽ FyϞ=>oh]8wUV]vرcl~1۶m~mBP~;6[nUW.x#Q?CUUU+K,qVv0LZ }jMZwܩ{ׅ>a6c\\өSW{o߾ SN"Y XO޽(77[͸yfuJJJa A i8XtFeT*.O_ Wbĉq{ WI?L))))fMdff-XT`_J:zKcB^ղg8N,U@g&˫f=%DF@UUU;][n̓0gUa=[QQ<44UWW,[jmT墫,))R1 !//{`wp554m `6N:u{֭ mɜor]vٰaÓৠF/l1Lmbw$hQO oXfnYfm?~|Tj H~GO;|^;^\\jT` _H, 7n,}=8~Up$Ct̙G[ɧĖFگ[^_家['O:8C: Ns~o;СC'$$S)c:'/vcl9.Y$`$"0\rrUFCX,|?<>_~2  tIII[e;ԩSj&> OCΦW^yeF)ƃиx˗gqyGe:txoܯ_ &tx):qDiVV-[v:b6fhczzzō7{V ˖-#*f4޽{B㩾}ᇴsIs;62S}Ù3g;w#տs8iӦ}V,r}݁x-ҥKCCBBtRҞ-4TTTԟ:u斪i)JJJ}]AMhQ4 geeUSPRRR?cƌ3pm͛H.wtJ7 q-+RO9jZ m۶-ҥKb-i-Iq8 i~ԨQ~{ܢ"us+00kɜwo08œĺ]vhAӅ \9Pgh-`///W_h å@h4Y5e;v\[lY&ӣXMA(>6< .ޯ_a3z"n߾uLLL 7|#b WRy@J47-?:_~jM+V71k5=z4߿n9DECɷl%.\;qcpt#/gN^VW MoZZZΝ;$d 8p.0!7P(ӧO YE,Yr9J222=F!.r AfkVdV4hYAAW^^5kVijy.Lʕ+rݻ~嗏^Ҟs/X`Zn08СCC=T^^N,&|b>l e8k-z+//3r1KTL4iELH 1SrTg2攔G>b0>!)q#o,]@=zi(>,Yv!СCz1a:=;׮]{ƍUo߮*+++/..k####""QQQ~l=B$k[qصkׯ~~\n2*juUuuZ"!!!2,0222r+BCCy55aӦMya_i AObNI@*T21bx,rF`2 ,J9H$aJsh4D"a%Y"C#Jb(%箮V\?<@SXFp kҪ>"ǢӰhB%K yw^ gkz .b0d ;\>N C8$ڀh;wN{9O;P[[IMM~WRN!O2څab^ Qv|a~ nݺi }T*}a\RbŊ3?m8 ]x҉xzԓ/'1?mxF>}z3gq Ξ={?tJ/)[Ni OgޭD[cIb#hN B[bÃ571qP޺u… ek֬ɩӁo Up[8E<2ix@ڀ6i $n+еkנ3gǷСCۇHd2 k=Z}BkԔب>+&xaDŽl ;jzC& 钰 ___ /R* R)WTrR)W(2BfNכzj&^oڵÇONN#,-hz)mk Z6Z#@A*QP#uVAP#0¼iO6?=:i*l ⚁B].hۥ .ȧO_1 /^^x{1 <|"i K8=Mgdp <]mN 4pv56#ɧ /t3j'hs hf D~ 4$B#\BfOgPIENDB`refind-0.11.4/icons/func_firmware.png0000664000175000017500000000727412626644770020012 0ustar rodsmithrodsmithPNG  IHDR00W pHYs B(xtIME .l[IDATh޽{pu?{JeINL GoRЦ$HNچСi:% LhH ơblc :d$[;eI[̎v;s[1 Ǐc]?:fo6>OOWEx N!Xߑ?+^ȟZ5]VcA,*tw绳ۧ9{Us/<.j`WW<|spqW%̲_.\;3fOɴOMp5pU9q2l0X>5-Le@SGj3v/6Da̻҆~/z^ҙB' -aH"i n U\Ó615JҼ.ԧR<w9ꢀ*oKZ XՅ(9 * UlJ@ UPRdQk?*FOOzpѳhctC˥yF4 jW}b“/&8Fa-ڐ,duN'Ԝ,s?߽G YgŪU&:{7˃>Z 7)23RI8b NMe2Jd-kʠIl^ŪTY&kv:ܔ>qhRZtM.YyCR1,îRH瑫/k%Qِ枊:FXQj*5ET ""#uTQ+h59߄ȩ|QXq!NR}!bipƯϿmrcH N<@Dm\qRC~tV:U_}O OW@/L6 [uŁԄ8u4G72Fb^FE%/jYvS5DˬSS"j< 2Z BrSs)8okļiC GH( Y1W]q=P8#䝠 t}%M ZC6=_\|!8Ԏ~@boQ[˥'ȁJ!l7Tts #"Zg.|+\XPnjȊUYfl_Irtz+=< qTEl|?s1s{Tu{UgXM8S}Yvx%iTk3Hj pCO<| D[C'\n1 {3O=w7"v0R{mū{bv^*kaW`SZMi 7C#p]':BڍnhNM_ha촜$ؔ欩/5ۺ|?D[狪Xgȶw/Aeqez/MyԀgاxCKrq~ƨuՃଯvԝX+E3 5cTs@6}p\JuJ$&@)_Z+F\33edA({:Qq;QN+R@Ō¨*F4Zڑٵ|~Kv iɚ~(92?uH"݆Gd)4}pnt+7]0`ըUjW_~YGEs܅rנP,#Z'F0 hGR1LJ2ȈgϦu޴ɞgU-*dM&qRz؂B2ä́* Z݁`Q(a#:5Lߨ6JpOC}@2Bk9][?΅NjWĊ1b͝ƙOc VrO8 UqEKz:R\s bAbj79*"mGg5̙%\ 1uDmыʫmwŠֺ =5;hPQEr߷>٦M8x`Di2TJ/ly{ۻIǎ_v( 6Peu.t;ZV~bgv^h 3XEI7I-LXq|0.ݸpu՚bUZB-.& |}բoHC#%/k L/S޸TE1XkP)>Y}6h x7LGzc3U) Ut㆑kp7*@:Q Mzjo1B}(^iԚ Aqǘ(4F6eƼ,»qAob7TpQ1rSLawXWWÞXA,c)P@u2yWm:u-D0;b.$/țCƞgv%BjMzo9cS|J~o+g,Қ/ *5eWyX*Qޠ' LL)z]o?mm/v`\z4.b3i_Xn+ { g6~NO{m dg[`S? 35@`Mxu?X;jo&;=::@?T;CXo-=BCn# փC6m%slb!b--@5[Hk&kVOhM6VG7Q 8dМ̖SDLotM;ZW]~1&tEfRyo~X_)msI\c+}6T$r7 =ЮbжW6Ln̐Qd,5me8K΅i Cxp{[,&4taឍ 94Θj#AqF٧cșIopgqv/R`+=1%B@zcRPQo? xpG,|hҨ)[xgG/L![wm -XwCIENDB`refind-0.11.4/icons/func_csr_rotate.png0000664000175000017500000000334112626644770020332 0ustar rodsmithrodsmithPNG  IHDR00WsBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<^IDATh՚MlTUʹӖ~ !ԅqa..te•`\aqFcNFc4* `D14V()RGô{Ž޼vR:x&o{8J)ϖ/rǑۄaJYΤ3 $w߂4I("q X]}Ii{ AL yǙ1Y+4@uXߺp7Y~vZ2ČԘ wX;~OA"%0'qs"q$|d]O ]JzQ_| [ 1 o j$H$RIfw*z?k : @ΐ!JȰ D j?Kww94>3 W" Î`8$TV"ɥ⪨Ʈև:xf%Si b 4酑&J2D%p5OKsG0@#PdXj];wPiypئe4 W!Mx/ fJAUCX.@^o^Fx'T CG5ANe紋KZQ2# \=[Ǝd/~+X ҏIe0P Ԃ5qr^= }'('/þ*L,dOj6xeJۡ=U[fmAɣ>V6 C !p9?`## O5rԎi/:6uLt'% $!ȹ>ι_.2Ϣx/1W ByymqNxC{me p~Y?`A}͠Ӎ@KZ_ Ka3˲cJp]eг>kEBqnpm#C]hBWgV{6xj- DH XVXV>Lm 1 xqJꁡk1;5-gVxh2E(=pԷQױ}?1l$0 QBi!ќ.Z;<(}A hY'?إ-; Qy,y-UCp9KT| .u,fD!`42M)hesG6){Z&[PJ)M2+=C O (B,Sf]~^, xL4c@MteXŮ31v3r6`2 2D]Ɋ?9bd IENDB`refind-0.11.4/icons/os_crunchbang.png0000664000175000017500000002044012626644770017764 0ustar rodsmithrodsmithPNG  IHDR>asRGBbKGDD(M pHYs^tIME  &&cё IDATx}kuwnU?fzf E(KI -يI+\0/l$ +l "8?C. [ ð2m(pĬ))R9~Vݳ?ު[UU=Z>u~s \{\{\{\{\{;}аkZ>|>9-9)ǡC'''>eY\\\عsQ/| hPO=Ի퓣bwݮG@J 5ƞ(D ַҶ퇈'38я~ `:t޵km`P fFo۶m#k#~߸sοrADyLJdڸqc_Jp]/I){GOS73b0?eY333'<w !|K_*X 8;;{W.3,$,nu/4?>93_InۻwlX _0QV'S(:3=PD/̨j9uA/zO>=8x|RٳggrZZZ**Lh:u<:Y&򄔲W*RuXrTi.ĭᅝ 'Nʨ̃6UJe,dF=ٴ ]*"01???!$!,CU0jU@3NvƗVMf 9fZsBJ)֟ո=%`hc08?{?#8ziF+<'g VF@(VJgb?4Fq 4#F#>tr_^Úͦjz<HG`(ԛʒm#K)D"Sʑ;y[o:gя(,d #l@P(جNLl  k$}14F?-$L*n͎c,5r0Aס(F)` L F00nɬJ酁Qo /fQQT 㑋l=N]!T@d/L`[1^^^G̺3CY(Sq^DňBc6I%dN 4Q2zo0oBqM_f' D#fF]C2cD@F$]yLO_fB|T0' Gu3(d- YH{t`/0 - 1I>z0YX)u &aUJ~گL0je O9h4A Ev#!`d>7z>n -9 U윾zt,e0@ԭ`\>,Q@.RRmbkٳ6ljۄip,կ~u;zWO[n-} ծ;9i+֭[{{◀-Kr]XX3gXǏ/9sfyϞ=_v7ZBW ŏ~_Wz78.\Ǐϟ:uT,~/lݺSX/IbA333wޥn.\pqӦMnY4@\vzfрNGlx|N 3W<3[fggۺu붑6q-u]$۷X,nv,E WBq͛o`688Rt'0n_l2YR{w;neo׭[ʁמ={5D|'|r˚5k.۲)Q"m5-t  A@LxW, eP([ASKHBqOI]R:M\.e1@~ݺujY^v")TO#2NJ H>oGqrRwF2r q"5;.K8qgbA*L>"҈("F`{kpP S `i& 5 ]&3֛m.@(Y@j}A>A׺3X(A0]%.Jd0H>=QbnCj0IR3(U'EL2NoH07maI[`ޛ y9_1339| T(k׮]1xW_.Y|^rօ, @KDU!Z%xn&#H 0x=5 V 1lW_}u{[7oސ.\?&b `]r%~u!y)Tx㍷x≗O\#*%p(b|r Wi^ 1+CI2f4kQ@u ;eQ&ٺST*E ^@ Cd { P8j|8e;M~SĄWsƍH 2+k_A,ѣg鳟;c' Ec=b_wu1dy5i!Ҿm u3pRrܹs;oZ*o4+#movcqqĄcv&\|%)G>kff><6S+R-rxljOgN Xh\yzteH` E<{ _xzwT*aڵt֭el c~B4j7$C;)0YĚ53y,-۶2aE|~$ !՗>EJv\E~?b7!NAO0n DQF8"LЫbM*"CY# W]g" ;#=1%u-IqϿ!CIJgGLGϯ!(ꏡt,:GEq ur%n%00!Y6ҒD"fY0#P1)]J=]8ͮ)ih66 8통 Pp\ǎ6F%1Bݡ)K#])F2QK}j !jVdžޒf?0*fbŲ%_-`i#l~J-t-jFN4Rd4}:qgVS6iEu:z˗ߏcIzF:B Ɛ96B!:1iǍ_R1${^0:N^#?oW~رS1iaJAKc뾸{ݓӽp݂(fsf m6MuD!{NJ樺jZ#H6`٥p2Lﵿ/,{饗:pH&{M&:uV(&b7tݻXftEKKKK/o=zaK>]vm۲e˦n.{} /y.da"b"ru۶N8q--o=eI߀׀`gf#92纮OW^Je_|g=X9 }sy\ٳ8p^{tG2W:Okv70pF*ExBĸv5|k˖-;vHmg?8s=R!$o47m4q !>t=z^{KA !2y55} SaAg00!0H"1 af)qj֛CF%K7 T$J]9P3M 4=]MkIy7y97 lsB(f1ا;31z["漚)yt"Ve2LpU6#33s3dX)rs"Sr i@ !+ !ueY(֢۶]B\g^1Sʀm80ծΦP(,5[X3J(:< 1wCSU70ID,I\.B.!Dd,*X,.+O-CG@F O'0:-nT ͘et-˪5GXU!p].krԺQ#%$pcalh!j)D莖E4MwkZ,5H RCQUvY&-oRJ}܃ eõƆE̹:D$cՍ& {)3:1ɚAq^L1.sq,{}TLsb }P(4oBuwyO??C5a?.a:/7:tNE7%B%!rN$k9|\2zO5c{7q&&^Ry⢫u e#HY ٨j6+bԡz-_V9П!xH{9;c>/ ios4f8a^@'*Fn=)0I}urסeH !:V+jJbiDbv;t Fj1hD͞=axBѺW$6NL :Nթ6Ш.(s&i f]8s0̭PPKōv4L6J9v~.;r``@_Wʘ%a==Hyh<F棹%*rYB#BKG]711K+B+ ;?z9fߘ6 _?99ua(iǞ?o~lr >eH/wLېO~r Z 9ޓ9f1#@DNLM=L chytoAarem<-0_ 2{31%xj `Qq\$"q_7 - !zs8~;C rPi)zI?3 j4r[!bɧJe8|>*R_y( N/p@ѨLI) TT8LoO4*B>~;[,h4z |8@ݟc朔1r^po&w dL)vKb7L%4nXJ9t j#ܐ(a]<_o4=SsKεŷ/_0|idX5$]Q j{ҥ3RW %,F.:ydmժU,x7ݳT,]O>O?TZ-#hZ ?ߩ|mgffq(\ c~_!\a#45Dј8w5k&W^ԡ?N[1IDAT`U[Yh2gճg0 1QzvF q%^nᵢیȝHe3ȓZ4Ǖ5^vRD;Fm QYeHh%0\$- &8cvcf[xx^MCNnoFz!/2/IENDB`refind-0.11.4/icons/os_fedora.png0000664000175000017500000002107312626644770017115 0ustar rodsmithrodsmithPNG  IHDR>asRGB pHYs B(xtIME/TS IDATx}il\וw۪UE$od,QHEۉql9~]Ix@w"Ƿ{u]vNDTd.|`vKMJ̍|/S)j3o}kg,ۯ3s p"W3}_\|l^Q@{"6nܨ?h߸qzHB@l.&s|:We%-mҴz-jPj.%<G G?:򏚦}@d*!Bh"#=BU?rf5?&/?[ 9NpL=SR:?f#B%$@ ?m۶c(2 DIg!e:Ukk=o?߿+j\ /lg:fbO0L>5 оO?}&W?|Ǯ]1 2n!.\7q~#QMU-w7W D;w|& k\@0 2@ꩧZίBY >3C2<. 7 P?w\U_o߾=546 fk&<ƵI*N=%Vn;\ Ur>w> m?bXHi2X2C/lT^ڧ>/ T0T|[%!-WbWu.#{/|e˖-Q3-fft>sLxbbBݸqC~˖9EQ5ܰ%^O8tq؊\D"']QV̅s)0nQ| 5p'D8~ st[ouȑ#Ǐmf|>vwGuEM m{.D6߻RزQBJh~zbkW4=^L //?8׀38[gt8qBZp|DÛ*|ֿ0wo{7|_[>@03<'(4̌k===2 i9y& TD"TDĐ1Rh(vV3XP]ۻwoc=ת1̉cǎg}W^I0 `L3r*K+d߻)E ]MDjL;}pZ[@]GٮihƟyތIYK ~&H)Z>Ղ*/@M|-a_CCCl˖-k@|N$^z'p ~3lŮ)-XY+zߚy).W:::bMMMdZc>KqW'\Ioy @I>{a3Gźi}WBU o`]CER@]/>;LUmK'{.){|ܟ-1s_ Nf~ܿt7_&Amͺ^m* ,X@Qk޺ B(|~ȑߟ0Q>3=Hvˌt1K.jngu"d%uauPju6pC;`x98Ɔ}NVMsAN$dp؊O`K"TUu;l0Ǹ ԁ.晄7_zfez]%<|I| l!PEĚy U .U P3\Sz:5c4e m$%"@D+fb -_]\AOsd*'`9{怹)e}OBmލ0fH'K]{ϪMe`N*@X:-am+c_r&3x%-Ĝ Q])]U`XfzIX__oP귬|-^7f, |6BXѿߨo4%/& EM|p*$^c_^׼14s޴gQl023,Zh;c:PL⎥K;g$I*$TTy"]3ֲFêu9 fT r;nfb1c fߓc+?' b.,{OuyKRP7 8y`cݻ^|^T`HCkBk CLC),is vЉE̗d0%֦M#Mk8u"3}8L&ՑHHڵku"rukienxSGGǁ{m_F7TzyDU%lEb RC^NsXGyI x@ ۷Qi~P ZŠuV XZzjSj ݰ3M!5(51W#D,]&޻nl a0|tRNϾ?pLe/_Qު(7JCHۘi@ža97n)5ψRNYo2 @h>fPp*k\K,zRf0fH31tbOy 9\pKh}?6+T/!^Z ^6nC!f*ˋ)p'i2Q)hx&LEE`}3ödm,<+ۣH~w _qose1*S*sh[EGsc.Hfɒ&{R}M\U';nar\izfD|@м3u_!B&ܬ1<]U0uk4ˢd__Yp~EX0Wn])=d&G2#WWόFzUO,Z78!B8=YP(;pC=1;7իW*@u1OJ)PQ*zxoWug!%@Ejzݣ`\1%^0.]Κɑ&.|I'3a|7@qH$eYɏ|CcӅ{LwJp.eYEDi{^q%p螮X͈~ĚZ&!:uld ]dG.冺Lv Vz$@ȶmdG r;lȨ<EI^ePBp|@ZvZ=T@AU΀r`7~,בlWYeBD6ru+UUtl`({;.Gle3>jPܙЎR%}/W4 &u]qUpʨ?vʨ\?ޤ(Rd{zŋle>ןP ʬQP~^^k4T!p H[1' <83,Gk7( bfn/c83I;=عC礙I4 G[L) (g{v<{@jHMfb1F">֢͛h.ًSd;~s'}7` eAz#DqJ{D``oo4 XNrVjGe=;> ɑs=oNtnׯD$e;nM S<___!-SVAWPH&*iKcfS\̎^L QIV+W葧&‘mrX07RA~v!$wOWn:K4-].8ֵΞO}y[i\QTGNϵ[|ʄ/hp|e 4{湳mM`Ȣ:bF9OQu*Vl(MxٔH0بse#` 8Mo,P-h` &Q@$Tѳ@ /`K|Ǒ5 z=h5vRpT~H9v{_pv+es,nAwS'`2ҀxE !gq.<q>!yϹ5`p' ;؊Quk1=CQ.mP*%@ e٩&Bh&\̀)F~Ij܋ @L`H)tˌjzUh5?D]1k,^UREiiiYB|iK'1T?Պ*zAM jccs=l*dq öHWW5.; Pdez는d@݆;o߾x|di@Nqtc O-Hn^6bƮquz{Q"䝨*D @ߵk׊۷?,h\E}IY4 %XJ{rr{-9똉^feϲ-&3/]cP=^=(9nڿg6<-,|!)eիSTnK`S1]iJҙte)z2`Jl і6M={4=ȧ>Kn0K)zyK>Uŝ7ԆRM.jEuŅnHPt݃c7I|㓟|WMe+ r=̜O9WP^F9' if[_}~/JBCݼgD]i(ƬRmmm'|m۶}%"jf˖ βӇyOO?UmdeA\gevݪ)z9q@Pz~St9yhUKycr}=i>ƝgD3]v襗^:8䅭!XI,oϹZ{? H)jho}|ErdF鴌D"4AUF]׷!]DD|] ӶǏ?j% 47()hD1#p= Tu666fhFH Ÿi ,V$l33Q +J wfN?o9輹T z5|^9sNDov<VJURkҪGB!)lh/.^0[a.ۥz"o>|8i\lw~Ӯ4?0 +5%Ґ5[W(zktcxy6;**fRd2vuuy.\jAAP~QCѬmi +cwo4&8:zh73 -Bzv7Ѭkn":TaY76 .o3r9sɓ_8|s@I^hbIJZtE$P22aLBYU_M52ڶsw9tm{5cjö QAuV m%7қhF57mU067xXf癫&4lv;'O/O/q3Y RhF55xbf-QEQ7MV*~ԩSxWhfnXyc/<(ބ4jH3P!4*)b/YJ9688x_~رcRJ?7/eKŜȐPI5 j%D}H Zk3Ht^8wͯO%]cW8[w r$2cV.-ИF9 (nЅfl۶ޕ+Wꫯ<汑t:Bi1.jR7ȓB +9_seŊFPD#jn 0)Iӗ>|k?::vuh@/kB(D4htP4"Mb;wlZ%97h!"͵%J@ZMt:=6:::tŋ]]]eY6J/{3xyF ~ǐ3< IDAT=ATѲblmm7onXfMLQuDnhhRJkbbfٶߟ~z/599\.gaMOڬ2xqKlތG\iTNaUUqEQ˲Ա) ML[^+Yg R(N^_A;c$3|^E;)y͛r1|#_m4z Gu |] 6^M'%{4"B>‡@Ô{ٿ@̗!~^~UN@x `Ei\@e@K% TT| 3؇F[({ %Y̹r)FO3*XL]#(沶k6j6j6j68? O_UIENDB`refind-0.11.4/icons/licenses/0000775000175000017500000000000013372357235016244 5ustar rodsmithrodsmithrefind-0.11.4/icons/licenses/gpl-2.0.txt0000664000175000017500000004325412626644770020100 0ustar rodsmithrodsmith GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. refind-0.11.4/icons/licenses/lgpl-3.0.txt0000664000175000017500000001674312626644770020260 0ustar rodsmithrodsmith GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. refind-0.11.4/icons/licenses/cc-by-sa-4.0.txt0000664000175000017500000004724513104133625020702 0ustar rodsmithrodsmithAttribution-ShareAlike 4.0 International ======================================================================= Creative Commons Corporation ("Creative Commons") is not a law firm and does not provide legal services or legal advice. Distribution of Creative Commons public licenses does not create a lawyer-client or other relationship. Creative Commons makes its licenses and related information available on an "as-is" basis. Creative Commons gives no warranties regarding its licenses, any material licensed under their terms and conditions, or any related information. Creative Commons disclaims all liability for damages resulting from their use to the fullest extent possible. Using Creative Commons Public Licenses Creative Commons public licenses provide a standard set of terms and conditions that creators and other rights holders may use to share original works of authorship and other material subject to copyright and certain other rights specified in the public license below. The following considerations are for informational purposes only, are not exhaustive, and do not form part of our licenses. Considerations for licensors: Our public licenses are intended for use by those authorized to give the public permission to use material in ways otherwise restricted by copyright and certain other rights. Our licenses are irrevocable. Licensors should read and understand the terms and conditions of the license they choose before applying it. Licensors should also secure all rights necessary before applying our licenses so that the public can reuse the material as expected. Licensors should clearly mark any material not subject to the license. This includes other CC- licensed material, or material used under an exception or limitation to copyright. More considerations for licensors: wiki.creativecommons.org/Considerations_for_licensors Considerations for the public: By using one of our public licenses, a licensor grants the public permission to use the licensed material under specified terms and conditions. If the licensor's permission is not necessary for any reason--for example, because of any applicable exception or limitation to copyright--then that use is not regulated by the license. Our licenses grant only permissions under copyright and certain other rights that a licensor has authority to grant. Use of the licensed material may still be restricted for other reasons, including because others have copyright or other rights in the material. A licensor may make special requests, such as asking that all changes be marked or described. Although not required by our licenses, you are encouraged to respect those requests where reasonable. More_considerations for the public: wiki.creativecommons.org/Considerations_for_licensees ======================================================================= Creative Commons Attribution-ShareAlike 4.0 International Public License By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution-ShareAlike 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions. Section 1 -- Definitions. a. Adapted Material means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image. b. Adapter's License means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License. c. BY-SA Compatible License means a license listed at creativecommons.org/compatiblelicenses, approved by Creative Commons as essentially the equivalent of this Public License. d. Copyright and Similar Rights means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights. e. Effective Technological Measures means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements. f. Exceptions and Limitations means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material. g. License Elements means the license attributes listed in the name of a Creative Commons Public License. The License Elements of this Public License are Attribution and ShareAlike. h. Licensed Material means the artistic or literary work, database, or other material to which the Licensor applied this Public License. i. Licensed Rights means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license. j. Licensor means the individual(s) or entity(ies) granting rights under this Public License. k. Share means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them. l. Sui Generis Database Rights means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world. m. You means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning. Section 2 -- Scope. a. License grant. 1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to: a. reproduce and Share the Licensed Material, in whole or in part; and b. produce, reproduce, and Share Adapted Material. 2. Exceptions and Limitations. For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions. 3. Term. The term of this Public License is specified in Section 6(a). 4. Media and formats; technical modifications allowed. The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a) (4) never produces Adapted Material. 5. Downstream recipients. a. Offer from the Licensor -- Licensed Material. Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License. b. Additional offer from the Licensor -- Adapted Material. Every recipient of Adapted Material from You automatically receives an offer from the Licensor to exercise the Licensed Rights in the Adapted Material under the conditions of the Adapter's License You apply. c. No downstream restrictions. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material. 6. No endorsement. Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i). b. Other rights. 1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise. 2. Patent and trademark rights are not licensed under this Public License. 3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties. Section 3 -- License Conditions. Your exercise of the Licensed Rights is expressly made subject to the following conditions. a. Attribution. 1. If You Share the Licensed Material (including in modified form), You must: a. retain the following if it is supplied by the Licensor with the Licensed Material: i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated); ii. a copyright notice; iii. a notice that refers to this Public License; iv. a notice that refers to the disclaimer of warranties; v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable; b. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and c. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License. 2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information. 3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable. b. ShareAlike. In addition to the conditions in Section 3(a), if You Share Adapted Material You produce, the following conditions also apply. 1. The Adapter's License You apply must be a Creative Commons license with the same License Elements, this version or later, or a BY-SA Compatible License. 2. You must include the text of, or the URI or hyperlink to, the Adapter's License You apply. You may satisfy this condition in any reasonable manner based on the medium, means, and context in which You Share Adapted Material. 3. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, Adapted Material that restrict exercise of the rights granted under the Adapter's License You apply. Section 4 -- Sui Generis Database Rights. Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material: a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database; b. if You include all or a substantial portion of the database contents in a database in which You have Sui Generis Database Rights, then the database in which You have Sui Generis Database Rights (but not its individual contents) is Adapted Material, including for purposes of Section 3(b); and c. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database. For the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this Public License where the Licensed Rights include other Copyright and Similar Rights. Section 5 -- Disclaimer of Warranties and Limitation of Liability. a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability. Section 6 -- Term and Termination. a. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically. b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates: 1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or 2. upon express reinstatement by the Licensor. For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License. c. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License. d. Sections 1, 5, 6, 7, and 8 survive termination of this Public License. Section 7 -- Other Terms and Conditions. a. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed. b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License. Section 8 -- Interpretation. a. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License. b. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions. c. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor. d. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority. ======================================================================= Creative Commons is not a party to its public licenses. Notwithstanding, Creative Commons may elect to apply one of its public licenses to material it publishes and in those instances will be considered the “Licensor.” The text of the Creative Commons public licenses is dedicated to the public domain under the CC0 Public Domain Dedication. Except for the limited purpose of indicating that material is shared under a Creative Commons public license or as otherwise permitted by the Creative Commons policies published at creativecommons.org/policies, Creative Commons does not authorize the use of the trademark "Creative Commons" or any other trademark or logo of Creative Commons without its prior written consent including, without limitation, in connection with any unauthorized modifications to any of its public licenses or any other arrangements, understandings, or agreements concerning use of licensed material. For the avoidance of doubt, this paragraph does not form part of the public licenses. Creative Commons may be contacted at creativecommons.org. refind-0.11.4/icons/licenses/cc-3.0.txt0000664000175000017500000005334012627314412017665 0ustar rodsmithrodsmithCreative Commons Legal Code Attribution-ShareAlike 3.0 Unported CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM ITS USE. License THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS. 1. Definitions a. "Adaptation" means a work based upon the Work, or upon the Work and other pre-existing works, such as a translation, adaptation, derivative work, arrangement of music or other alterations of a literary or artistic work, or phonogram or performance and includes cinematographic adaptations or any other form in which the Work may be recast, transformed, or adapted including in any form recognizably derived from the original, except that a work that constitutes a Collection will not be considered an Adaptation for the purpose of this License. For the avoidance of doubt, where the Work is a musical work, performance or phonogram, the synchronization of the Work in timed-relation with a moving image ("synching") will be considered an Adaptation for the purpose of this License. b. "Collection" means a collection of literary or artistic works, such as encyclopedias and anthologies, or performances, phonograms or broadcasts, or other works or subject matter other than works listed in Section 1(f) below, which, by reason of the selection and arrangement of their contents, constitute intellectual creations, in which the Work is included in its entirety in unmodified form along with one or more other contributions, each constituting separate and independent works in themselves, which together are assembled into a collective whole. A work that constitutes a Collection will not be considered an Adaptation (as defined below) for the purposes of this License. c. "Creative Commons Compatible License" means a license that is listed at https://creativecommons.org/compatiblelicenses that has been approved by Creative Commons as being essentially equivalent to this License, including, at a minimum, because that license: (i) contains terms that have the same purpose, meaning and effect as the License Elements of this License; and, (ii) explicitly permits the relicensing of adaptations of works made available under that license under this License or a Creative Commons jurisdiction license with the same License Elements as this License. d. "Distribute" means to make available to the public the original and copies of the Work or Adaptation, as appropriate, through sale or other transfer of ownership. e. "License Elements" means the following high-level license attributes as selected by Licensor and indicated in the title of this License: Attribution, ShareAlike. f. "Licensor" means the individual, individuals, entity or entities that offer(s) the Work under the terms of this License. g. "Original Author" means, in the case of a literary or artistic work, the individual, individuals, entity or entities who created the Work or if no individual or entity can be identified, the publisher; and in addition (i) in the case of a performance the actors, singers, musicians, dancers, and other persons who act, sing, deliver, declaim, play in, interpret or otherwise perform literary or artistic works or expressions of folklore; (ii) in the case of a phonogram the producer being the person or legal entity who first fixes the sounds of a performance or other sounds; and, (iii) in the case of broadcasts, the organization that transmits the broadcast. h. "Work" means the literary and/or artistic work offered under the terms of this License including without limitation any production in the literary, scientific and artistic domain, whatever may be the mode or form of its expression including digital form, such as a book, pamphlet and other writing; a lecture, address, sermon or other work of the same nature; a dramatic or dramatico-musical work; a choreographic work or entertainment in dumb show; a musical composition with or without words; a cinematographic work to which are assimilated works expressed by a process analogous to cinematography; a work of drawing, painting, architecture, sculpture, engraving or lithography; a photographic work to which are assimilated works expressed by a process analogous to photography; a work of applied art; an illustration, map, plan, sketch or three-dimensional work relative to geography, topography, architecture or science; a performance; a broadcast; a phonogram; a compilation of data to the extent it is protected as a copyrightable work; or a work performed by a variety or circus performer to the extent it is not otherwise considered a literary or artistic work. i. "You" means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation. j. "Publicly Perform" means to perform public recitations of the Work and to communicate to the public those public recitations, by any means or process, including by wire or wireless means or public digital performances; to make available to the public Works in such a way that members of the public may access these Works from a place and at a place individually chosen by them; to perform the Work to the public by any means or process and the communication to the public of the performances of the Work, including by public digital performance; to broadcast and rebroadcast the Work by any means including signs, sounds or images. k. "Reproduce" means to make copies of the Work by any means including without limitation by sound or visual recordings and the right of fixation and reproducing fixations of the Work, including storage of a protected performance or phonogram in digital form or other electronic medium. 2. Fair Dealing Rights. Nothing in this License is intended to reduce, limit, or restrict any uses free from copyright or rights arising from limitations or exceptions that are provided for in connection with the copyright protection under copyright law or other applicable laws. 3. License Grant. Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below: a. to Reproduce the Work, to incorporate the Work into one or more Collections, and to Reproduce the Work as incorporated in the Collections; b. to create and Reproduce Adaptations provided that any such Adaptation, including any translation in any medium, takes reasonable steps to clearly label, demarcate or otherwise identify that changes were made to the original Work. For example, a translation could be marked "The original work was translated from English to Spanish," or a modification could indicate "The original work has been modified."; c. to Distribute and Publicly Perform the Work including as incorporated in Collections; and, d. to Distribute and Publicly Perform Adaptations. e. For the avoidance of doubt: i. Non-waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme cannot be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; ii. Waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme can be waived, the Licensor waives the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; and, iii. Voluntary License Schemes. The Licensor waives the right to collect royalties, whether individually or, in the event that the Licensor is a member of a collecting society that administers voluntary licensing schemes, via that society, from any exercise by You of the rights granted under this License. The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats. Subject to Section 8(f), all rights not expressly granted by Licensor are hereby reserved. 4. Restrictions. The license granted in Section 3 above is expressly made subject to and limited by the following restrictions: a. You may Distribute or Publicly Perform the Work only under the terms of this License. You must include a copy of, or the Uniform Resource Identifier (URI) for, this License with every copy of the Work You Distribute or Publicly Perform. You may not offer or impose any terms on the Work that restrict the terms of this License or the ability of the recipient of the Work to exercise the rights granted to that recipient under the terms of the License. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties with every copy of the Work You Distribute or Publicly Perform. When You Distribute or Publicly Perform the Work, You may not impose any effective technological measures on the Work that restrict the ability of a recipient of the Work from You to exercise the rights granted to that recipient under the terms of the License. This Section 4(a) applies to the Work as incorporated in a Collection, but this does not require the Collection apart from the Work itself to be made subject to the terms of this License. If You create a Collection, upon notice from any Licensor You must, to the extent practicable, remove from the Collection any credit as required by Section 4(c), as requested. If You create an Adaptation, upon notice from any Licensor You must, to the extent practicable, remove from the Adaptation any credit as required by Section 4(c), as requested. b. You may Distribute or Publicly Perform an Adaptation only under the terms of: (i) this License; (ii) a later version of this License with the same License Elements as this License; (iii) a Creative Commons jurisdiction license (either this or a later license version) that contains the same License Elements as this License (e.g., Attribution-ShareAlike 3.0 US)); (iv) a Creative Commons Compatible License. If you license the Adaptation under one of the licenses mentioned in (iv), you must comply with the terms of that license. If you license the Adaptation under the terms of any of the licenses mentioned in (i), (ii) or (iii) (the "Applicable License"), you must comply with the terms of the Applicable License generally and the following provisions: (I) You must include a copy of, or the URI for, the Applicable License with every copy of each Adaptation You Distribute or Publicly Perform; (II) You may not offer or impose any terms on the Adaptation that restrict the terms of the Applicable License or the ability of the recipient of the Adaptation to exercise the rights granted to that recipient under the terms of the Applicable License; (III) You must keep intact all notices that refer to the Applicable License and to the disclaimer of warranties with every copy of the Work as included in the Adaptation You Distribute or Publicly Perform; (IV) when You Distribute or Publicly Perform the Adaptation, You may not impose any effective technological measures on the Adaptation that restrict the ability of a recipient of the Adaptation from You to exercise the rights granted to that recipient under the terms of the Applicable License. This Section 4(b) applies to the Adaptation as incorporated in a Collection, but this does not require the Collection apart from the Adaptation itself to be made subject to the terms of the Applicable License. c. If You Distribute, or Publicly Perform the Work or any Adaptations or Collections, You must, unless a request has been made pursuant to Section 4(a), keep intact all copyright notices for the Work and provide, reasonable to the medium or means You are utilizing: (i) the name of the Original Author (or pseudonym, if applicable) if supplied, and/or if the Original Author and/or Licensor designate another party or parties (e.g., a sponsor institute, publishing entity, journal) for attribution ("Attribution Parties") in Licensor's copyright notice, terms of service or by other reasonable means, the name of such party or parties; (ii) the title of the Work if supplied; (iii) to the extent reasonably practicable, the URI, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work; and (iv) , consistent with Ssection 3(b), in the case of an Adaptation, a credit identifying the use of the Work in the Adaptation (e.g., "French translation of the Work by Original Author," or "Screenplay based on original Work by Original Author"). The credit required by this Section 4(c) may be implemented in any reasonable manner; provided, however, that in the case of a Adaptation or Collection, at a minimum such credit will appear, if a credit for all contributing authors of the Adaptation or Collection appears, then as part of these credits and in a manner at least as prominent as the credits for the other contributing authors. For the avoidance of doubt, You may only use the credit required by this Section for the purpose of attribution in the manner set out above and, by exercising Your rights under this License, You may not implicitly or explicitly assert or imply any connection with, sponsorship or endorsement by the Original Author, Licensor and/or Attribution Parties, as appropriate, of You or Your use of the Work, without the separate, express prior written permission of the Original Author, Licensor and/or Attribution Parties. d. Except as otherwise agreed in writing by the Licensor or as may be otherwise permitted by applicable law, if You Reproduce, Distribute or Publicly Perform the Work either by itself or as part of any Adaptations or Collections, You must not distort, mutilate, modify or take other derogatory action in relation to the Work which would be prejudicial to the Original Author's honor or reputation. Licensor agrees that in those jurisdictions (e.g. Japan), in which any exercise of the right granted in Section 3(b) of this License (the right to make Adaptations) would be deemed to be a distortion, mutilation, modification or other derogatory action prejudicial to the Original Author's honor and reputation, the Licensor will waive or not assert, as appropriate, this Section, to the fullest extent permitted by the applicable national law, to enable You to reasonably exercise Your right under Section 3(b) of this License (right to make Adaptations) but not otherwise. 5. Representations, Warranties and Disclaimer UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU. 6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 7. Termination a. This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Adaptations or Collections from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License. b. Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above. 8. Miscellaneous a. Each time You Distribute or Publicly Perform the Work or a Collection, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License. b. Each time You Distribute or Publicly Perform an Adaptation, Licensor offers to the recipient a license to the original Work on the same terms and conditions as the license granted to You under this License. c. If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. d. No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent. e. This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You. f. The rights granted under, and the subject matter referenced, in this License were drafted utilizing the terminology of the Berne Convention for the Protection of Literary and Artistic Works (as amended on September 28, 1979), the Rome Convention of 1961, the WIPO Copyright Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 and the Universal Copyright Convention (as revised on July 24, 1971). These rights and subject matter take effect in the relevant jurisdiction in which the License terms are sought to be enforced according to the corresponding provisions of the implementation of those treaty provisions in the applicable national law. If the standard suite of rights granted under applicable copyright law includes additional rights not granted under this License, such additional rights are deemed to be included in the License; this License is not intended to restrict the license of any rights under applicable law. Creative Commons Notice Creative Commons is not a party to this License, and makes no warranty whatsoever in connection with the Work. Creative Commons will not be liable to You or any party on any legal theory for any damages whatsoever, including without limitation any general, special, incidental or consequential damages arising in connection to this license. Notwithstanding the foregoing two (2) sentences, if Creative Commons has expressly identified itself as the Licensor hereunder, it shall have all rights and obligations of Licensor. Except for the limited purpose of indicating to the public that the Work is licensed under the CCPL, Creative Commons does not authorize the use by either party of the trademark "Creative Commons" or any related trademark or logo of Creative Commons without the prior written consent of Creative Commons. Any permitted use will be in compliance with Creative Commons' then-current trademark usage guidelines, as may be published on its website or otherwise made available upon request from time to time. For the avoidance of doubt, this trademark restriction does not form part of the License. Creative Commons may be contacted at https://creativecommons.org/. refind-0.11.4/icons/os_unknown.png0000664000175000017500000002664612626644770017367 0ustar rodsmithrodsmithPNG  IHDR>abKGDD(M pHYs oytIME )  IDATx}ip\ו9~;pŔdl˶P^x]XNU$N8˕hbjʉNϸ*5R\e˒jYE$ ;F{O~k&$AM;|g{Xc}>Xc}>Xc}>x\Axƞ{X,֣i"1ƂJ)CiH.(-sO@|ƿb{5M{"ލhY+UHP&9@<DxW)PXo}u>MEķڛQg<|tWw>۶sqWK`ZJORַ",x`#}NO#bu^"J߿E/*1v )~Z*w]wp+Vv=Xw]0> j w\2z{ӭzNuV?CmtGHk=P\L9CRf3Iś6 jF W<[~?u\k{ ݟ~V :N'&TaZ9CE|Ha{6fo7wnbl HA_yob1멧Z$y/;+Ttl|ܫ듇=GJuqS#n0B$ #Qtl:G= 3ivXHJuAA E+d*Ia t&}}+@`e_WW޽竜Vّ8ϤDdx[TZ]tr@Xw] C`F"788C燩MBscǎ_?3 m~={|L=DT_ʃ_a{-aiD-bdUdxu9Ū1\124_;vڹi;CZ5&|2pw}fz/7?r=%FE_-A G'f0@Bڳsƛ}`9rǎsrͿ@ |Ѣ^Oq&dWW5&B|w`$Lֈw${92$"hvqM{'?k8^SX;;;}}}EDDz͖7li$LŌ毦j4ٛ’w n)@D"ϧ }l\>l53(Hk-A9߿ڧf8iafʳ48@[C :;;#.MUȡ^\g()$0T(._.@[¿h DP=jHkALCFb.q(<^gqrhJ)z P{I@%\6,r$.Z"@)%[RPj\-"`fRX_Z\!g\na)ZJ&{mEҤ !& -W-+DJ8 кX\B\.73a/ī[,覻B -EP(###Ld2 -핸`zফHWj,"3fFsJu599j5ns#U1ؚ`' Ex۬z?~u4 ԩS8,^j?1IYB =oRI>|xaƄwY5Yv^n<T-6Q XXX8/֬ۺhG;w.7<4|ؔ5ziHx%^M.Μ9s$˕}T8(*{wåRH uSBֹ0V@(Yo-m4\2{sccc TDq2g[6[=^h H^|I..Xu(@1_{!ZB݆{mhD(!V@U[,~?HDPT҇z]JYOߚ nr/~^.\ݻ;Ǜ}0ZpuL3)9dt%3;C5.TCtԩ|;9 [5„T*`P۱cGi=Hք1̺ OF=SۃNY4JF;w [5~u&X'O,mݺytl+DDlJFY;am|SXCJ+sE?\w+psffm۶D,lbH# 潚]-Tm֡xᎱ=;m*K<Ǚyk0-B:T ,[ZB,戲*EX|0(y"g6a19hyeuG}g|O@ajZ@###`0a4\1"zG:&.)F%] )Qѱs.fvaspP<ӯizzztbIѨf烼{.on;9mrc W*OOMꩧy'_?O܆YƦMa ljxtH̭qJLyddSS fR ~ݻo߾D*TeQQ-呹Vp||eݻwv>0utt$ sXc@LMM/W@|#ܩv!B~/`yJ)B\vgggRg %_}ƍ{j})WZƍZd.&ѩSN<ӿuݹ7mB(!rl9+D-a)Rʗ>όXo_ǷvmO!jݏR BٳTûv^k[E-}uj]M1y Lftt͛{z6B|]En*4LDJ)yK_RF x˾oo!~q.l2\gu]gBZ{G{"RzRp NqL "#ln9-|TAJTgyf,MD<'N.O/peTdRj|||T*UՕ4mնU*g…Mh*Dя#kBBVMjc=ĉs ڲĎO|m(EdZt4<OQGGmxϸGf2n Jt)3ޮp ;4+H\ׁq٢FtQzr R)VNͲ4<y֟].x8_?-\ZD"@ĖWhY'Jډzk.Kō W50$8AG9Pp vl<&l4s,{߹I&cɼb@Drhh~ۄXOOOk_Wzzz O=n9<_X}2/Dv43@L@}" %^J.I<ϋc]#ݛ{=- Qq??M V:E[,o}k_ggcm-5%稩N9Am oVj3l\i 5Xҙ&7&D"FbF"J-@MR|C!&L 3~NE-[}饗CuVο_ƍ h40ǒ`ED["lK `dee/Cs`\7@ HIlB61a@P9B%7nu8w]/<3 7u0w^N/*IQzTLQP . !j~ 8E@XZ""LF ffUX`wqc̎D"T*rdddzk/~qϞ={L]K?UHW2ݾ۳@[ip2mnbqf?~1jq@fZB$!bBbLcd1dQ }'Xx<>/Iҕ@ygt*v L_%E0Ydk63cT* 25Ohe˖-?_[eaX>6uRS0 cv{ލʈ7L` 23/C \YҬ180`=`K~G'K{!.ṬFyWd)Iƌx%@`tC[dhLM+,lrMӂ7o/7[lP3'#Yl{t@` SLj\n0M\.t2Z@U B1^Ԋ7~|;cZ++z1{7#J:ׁ|5݃0Վ9Y.T'- 83Ļ# yc?^pAG[dkv0E}w7L0*ԷY73h'ST@uj#~nB\Ԋ8;;;?eElU6M^h@0Lv͂o%ۼn o,\!XEKw9Syq^{@v&~:-VL7PfްY\(gfR^:*})_ O}nO㡋7ksbǣmm2n`,Dh5$afvd oavHw,>fkgDJ6ό cMt 瀬:!)PΤXH2DdhtѣGK+qlؾ}ݚu G F\]o7ZЦ > Ujjc===ڶklV%%1<# &t@¯C  w)ww;-4ݾcǎWrVD"v, V,̒ז9F2Ѵ`u20F (6n|fe`;wn'{=RF5ډ[&!7t%j#vDY݊X& b+ul0 cKccڙm={!m=Lj  p PmP5PS4رcJpvTu7 @KNUdӺ 9ߵgs%VJ`1cᦁ$ҦQo8mPB;kBtu$=3]͎) @9@ H)LJjo۽{wb F횦}1:@y`)JW3,̈́6=D^ґukK)CP?1R{!@psb+ @Gl5xEi"n"FƚNrLb7@ !2<ˎ.,io loy-nV5!@ZpAy|@GGGGwÊ窸]aCV֔|YdJSB.Hdp!tAR0I)PI%i1%Vjk6O&x\dG(+@~DrnhCl Ep+@Xk$,|%.@ w+F" .-s1FLuҙY]6Y!PhPk3M(8qa(Wڹ[RVB2!ެhyJ.hb"VW@d]h@TKOPgݖb|Y)EM:O@Be(*( f7L鬹>Xc5YPJRV38fff2U I)ce xx@V%\d P ̀VIR(=QuSsu zHR9u4{ մe |" AɈ/pmŨT*5OD%yubZ4@@D@)0Ee҂8refn\4]F vZHDM*Z^E B9Rֈ-RW\.;{|REkP⼎k\l`VI-tx(jEFt-$ y- \lPׁicf˨@p7@ȃ05o(TS gI)KCCC\וk@m SwX +香R r 㹤JAyMrܙ~X*upΜ933>>>jZ56eM5t`"6ad3zgGGG'pt:lHvhHbjگ<|wfLeFJ)'&&^ͮTy^epppur3財a+m5wɅƻ',{E\:\T 7;;;w!"/*V Ԁԍ@JW*bg48S~ 9q>|njjjvڳ6#~Uӽg?77w'Z5ÇesM][ ?/:Ǐ-#Ѝs @,yI_EW#XJ.WP=ESB:Μw`IPH׉%()-$ Cܬ"9Dg~Y[ 4.-V<E*⑮\n/ӧO1??OpXX] j%1OkDHKc]R$|̹ {p==nz'xGlvikejf j'i 0e[[ǐ5:SzAX,i-.!\-j$ szy-tdHrU5oX¥/|Rb=pBN$ڻ{^ѫ`)pUҁs!S*RҴ+.L!@`~̙Lwww߆\`H $Ŝ5'+H[{gg]CD.]<~GRjgV֏k{RBooO4_ CLz1åHjq+^̱ozFBJ=ϫ9r䟟x@l ,J:D$F[[[>sژ=f4y`yJ\w-HANPt8u(tD0ceĕV&&&?j~~,UC?jnlb=lvExV!-B:kf5^ Wx#}*6_'O4[#}ADpM)@P(P&wuuٶm]0m, sSVE梃s AD=tŌi#]/'CC⧂VZ(TWT'O< pqXOlqr{{{iPLO꡹1s\TNkϵͧ WA3bΑC@!%o\Wf/VAcǎx~[Ʋ+[ W6 z6m~o֭Vp_b AB p󙧰:awuum\-98Wp[ Fkًsa湨5V6)N2`K)'N/ ǎ'|)_s ڿ1X8ʊŢ:~i^$ aHrԑ#G^L&3F_' MmK& φB!D"ιX&(KI\I{"d29v_DDI_I&sIVK/RϸT*2 hټza9qddf|˲ݻwlkv E:,P]&v%`Rr\zrrr|xxG|gʼϠ9uԼAt$+=vٻm۶]ݽV U(EW PMQ߫!"D"f4 ضm۶+|TtX(jI\ u[~>kL}FEv,2 8c \+/&lUӐ52q,PGSԡ`hju:>ƨuKTZ5B%[ sjWae@Je!5fծUZ NuM]_K{,j,j d7SBUwߙ T:VWc+`zdY`7~#M:LGuӯM[Jk_ ibZd4V4U~5Xz 5\.nM_F12u֮MԗG6IF5 ^!1Ot9X .6K NJh}EnЯMی7yM?*HXc}>XM3Ѭt@ZIENDB`refind-0.11.4/icons/os_devuan.png0000664000175000017500000001172013104132577017122 0ustar rodsmithrodsmithPNG  IHDR>abKGD pHYs|StIME8]IDATxylg~{aό11m`q@ ِY&[&&mVUZi#fQUMUKMI79al=}fF_sIB;7nܸqƍ7nܸqƍ7n3^lltVW7k(hBf*DH5 b۳ JK ,)_rm65"B5h#c̹sG eUW7zBwB0!̈́f'w^vs07%1? 6k޲jjkdyKdD0BmSi܋&[`& SBXz[Sa,閤;؛Fisy4Sggp @60LDP%36(MNs_WvoM Y01>bn'_F+3d ުMQ[=ԀF  `_(:::1Eldp0CJQ\߭^YrwbB.a}Ɵ breGpt \i EVz7u8+PuBMB%>m k0V`]+8!([ަNmNAuCt& aޏۻh3T 0Rt`গ [N$-=iY{.f* @Ixbr6oᦊ[DqN0\503? |߯$P2[#=UU館ܴMB,Iȇ @CCC€}>9!(v;y:kPﲉ aòލ8 `bd@E0@9s55>\-A]幋/@ @ x,6VTUUuI2E11> 䭖@ୗLNN*sYnozﭒ%>uzg0f B h0ݧPF/vu} F!YAakpݓ`"#Ep 5 67\s5k2Bq iեi/ݐ.1pa;\LO,l={KsK*Ǒ ݲvK(f"cI6>(VHgg( 7+-I *$LB( $\& Bm e92\!"dkd lXWQ7< 9<: q*hW/jE4'k$~jY>x(Ԡ #Gb uТENz}tEljЏG"!<][VNOM>Y޲zGO}E9Kisz|;JDAXz|P(s;X!È x{$i:$rT)w'iɄP$MGck< Y^92I&o}4i 8I 0Ǜ|T;ޛ)yRQZZѡJ  y$;[ !BJY>0rraYFo2y&"*t4 K0Xq8^t~&0 R\[9a ")OF"=++kb"7B~EZb#@ rnd##Ei˵鲮ޯq~!*l%#t˄8B5c@8|J*ߛ̍Pr0xu$V9Cs\IJƭ] [ do$ $l+ `TBjt#8?@Ty@5/*7ҘPq,>xT@j2Qg{QMy%iz<,r $M[EYdzG<Blc)1Y r["5{{bGYW=X17tK[B-sBOǽ$M8% |ǎ~eFYR^<;]7d>yX[00H\?m1@.="Ɵ@t=X; ]b{`׊͚Z4|ΙXK:/n#<5e$9!#uHp(0bL ?$}aihhE 4M4FK0]~b'*/wBȟyQ ӳDLjU¯`mIv 3Mz RL4`@FٙL !!5 ;r`x"#~^1oNLZ_/U|ntAU?Pds}]lAdAøwpKPч`10pv&OB~DAYW.5* Bx?`K;|C0zz-LƩ*~{ BQ94qЏ|G2o⇩=O_`v]<=K.4/V12<d'IخJ?y~r:9˟Nd}'#>`~[(< 9uy5o} {Œ@mps}/B^x7[b>H5T&&_xa@m5B~7һ]J$ξp{O>TCꝐ3ooB"ZSXpxx~6(v7be! PSأ/]^W"t^{ҽ|&xyE$=0@PX; }FOq8'xLJkZB*V{Yν|o/z !O1t%VA؎@c1s4{nhLU0uŒO*ߗc욝H9k>0֙\oUo_4lt B䂪6qE!}@)l#g4Pа0EgC%*\o ߴz}߫W7B<L ~N__+N!`#~ݝkA+oo.ϯ%lEmΥ.S-+r$>뾾I9:m퉛 r~p4.ʵ鄨"ûz{LSg| m{=٦]OE@N~(1KD{,bvי<⇨luoAR^ll)l BMک$XkF{8hjF{>ƈn oxqZplFl;!5%䗛iGѣo~9am II~5xRݭ3f}aԲÇv53+pLeφ(#|Єo)q9̠Ġa62q ?nvXQMD7֫?>q Sgx| o[V!vXvT/if34tT< "ݜ+uu;R^8pd2k FSkk.FJ Pmטv-֜`OB%%IHkUm;2a^#LEowٚ.| L5o"{ZS=vlW𙢳{ )dL^_ 3'Wo7F(좌jF/)@Bh &xLͭlم]lo׋2$!jG<~f0xx8|Y2s;~J "DT~ܓLv| 5]'.U7K9O<R iF"{[x8Ct62L׷ 26aYU`0r< zǘ2M8cz&!RǼUk]v$j?<5NntzFnW3:l̙PMu@O͝[P6I1zp@༚!>'et 8o~i p. 37u KݞDp|S-U]hM~~ѓǙbn\Aj[n|id㊮wPO?Yt-CxF19ʽ}& @?|nQ\8D5=Y0cy:9A2yԖ"Bri"`3j2DF1grz^8-eHIZ ]6jܢ_]^Z 8 #~YݪE&lFx:y > 9uE/2l$*Fr {L)06'.z`}*Baϫ2` =+^oQj_!vmB gֳsƍ7nܸqV(sjIENDB`refind-0.11.4/icons/os_ubuntu.png0000664000175000017500000002775612626644770017215 0ustar rodsmithrodsmithPNG  IHDR>abKGDD(M pHYs  tIMENv IDATx}wu߽}}zߙ-u vґDŴH7ɲs#ǎsrĉ$JrđKb>-+b4-ZDIA QvN{3xv wf|nypgwƝqgwƝqgwƝqgwƝqgw[||>ބ2UcXY8SAιC$,^JPb.˧IvM=Ѯd' @wÄ f( @" ;Gse@XMqg]Y9&/X#voE û$>(!@/!9s 1A4~szaGs"gz{DG!t3sg\?79; ]{ T#`s^gqxߘ%IDm9oTz5_ [ȟ`4Aس G}ǻU%J~!Wy_J'o)0D">Ց{Idߝ M,((O>," f|x{\w>9f;C]O M ⇅b.n&pޟ=?5M$[$8 "AnqΎ.'Ɵ,`߻WH_3@~vs^pR>i9Vˤ0.tuuC#"gAVixy11XcJ,BN|:O@ _~G"EݫHơ~B ۻv* be+c#C~<5" B*^}Ǚ)ݻkEQW4( SU)~i'"st*gn AMF/O<̻_ ]̏|`|xϞJOO?]zSZ' HfC?)k+zsfܲ9m 6yAfs8ΕUf&1i#LBʢѨdtpU^`D |<3u0J/;}~bGS>|h+h-pў v$8QQDЃXZpU" D !P$h(aJ($I< pre&1*SK=SaK6 \@\? 09j J%g{D/szO3 2OQVڶm~8 QYܽoZ *""}n :.\S^{RJAЌ{e 3'T傜c34taL]<.u=驧6&CdDD1h pUDtoO|Zq'-|f/zF*{ݻ<00`DQyZNM9UZ DDdn ~'YYjز=ri y i,*43 M\UU]Q=D.c)0@igI-Ua%;Ј(gGoe mݣÝbID$ %ͽ)^rFzi믐Hu_C}}}f0(\L$vP=Y*Icr10/_:uaTLj>GsH/K9 ]I)@o$}(\${DA àD\d\o.aNmZ+?O75OWK;;J0ܩ$i _z>~{F*###l6kA[!4M,J CB(wѱ7>)zn^|rw.oyA@QP(FQ'۩TN&v,sKamJ]릳O4Tu8{gK֛~ T":USEqλ¯aOEtZSVRUZ 7N(e$ę+~::Uk dY^QɲUUe2Ay0 zhcYVS0 <윩o4H |Q7$tsC + Xmf}󵹞Ee_}7NF.4"R+‘(M[t{ -šK+V%?Bp6 ֠W9hɈ$=+rLbmjF$qij~vrAxU- ~琠<^wwYVRI:Y/h!Ӊ]t/l(-|gGo~{s|Gixxk|>yywo#/~aլܽ I]sg.9/ 3hM$!"4X۶jUT2PV:`^>](}R 쵲Yʎ :ҧD~=XWgaz wFڌBD?{?Y˲LZSDQx7n(gyƹ׉ t4o@R圳i59%lv·,?}XMM7N㬸Є4%IOҏxi# bfoT6d&&\+Pv%XLC,&MDVVzHٿ&NUNЪogx*h@ e2z&ы;ꩅ<Қ!/ 4bW'"k]t:m|Uu]0 ΨڙAf/Ϳ& d 4McXIF0sAqnwq_$-i -@i[XKy<;8wѢ9ٕ9g78+i+r9Qx}Ji~oǜ$& R)+LRh2RD>@"0?J㍄B(j4:]:r]-|&6g%С+f=>3-)c)%O ~wAV~fUafJ|o$791tNūJŚH$$ s3e93B0K|.߬ hg1R 眽nig>-aPg`wֈf ^LOy]߯v=?~Va]J"oBlxРidgA7R MjuI$}1տV@X(hl-o9]߹$b&& p40 J%9irY $'T:~z੺}ߦCɟJۥ%I;F=>W2,h4jAoqW`w  )B-7m4 4,X2>44T1b-ImyizzZr9{6JZhl/w>eYo)¶t8M=㍝ * paO,a]GJRj۫32Rضm[-J~kïjf2B}yoaAcwF/c,FDj٥n-iYNn~9;;1M"4KJk|C8iT$\~nHe164{Ү]tRzA IxcmZ||=qNqIb^'X-8['s—K%| fYB k 6c@v>@ P 2I%2`)fNk~?KӖaz.KKa]m¤b۶ѤSuQuC#'*S`୿"+0W2PADTŜW;B%",d,NV 6\MlQ4%\؊n ZSk5 o$nQUf64e* N@90жm{y[1zy 9_{M^er5n8Gt:u%^k+JRy˻yQ1rWOv: j?d("ْ4<0CN@r}wn6wRQm^?'cGz}bAc ]ۆm@I1{ H\Yãl!! ]-ˢ^}N1&વ<1h(veyzN(݅`E&ZO6OTq \,'ηR(qbDȀ(ʪmbG5@7'gknG$]֣ ]xCſ|> ?hc֬1N/9д?5{@$5͈ \$&2Nm'0.g75 *m{ Cn&j5all,wnJusuhpe?_anAΣe}t`g쎝KGwe ]>)_6ܬGDQhh !W`0 ݆ 0oLn JtCO.7My_e|6pntBQv('_Z$ cO&S2 ܕv/ߣdꥆh٘.W&> LaS_.Wĥ]?,C\. ;Us}}{dteRHi c\.I*~ߎFV,T n0Ǖv2T '<'6v{IG7LMcvM:&yKw3]7;tx=}##ž:&RJEjiԶmҬ8ɲ|>p ^0t5Mcw]7_R෶,TIW,B,[ "It8'ϔ#_4lAkM8- `@'kOݥuwmgA\OdBs7YHqTtׅ>88hiK.I,"UȚmaEa Ƶps1tf_{sP/"B4. fm _i{vjSm߆4Y!$2N~YDD85Ÿ=ZxtM]84Fgxgק7wqiIV4XK%ZO1 S¯?Dǎ> 0#OURKcb gNn.tZ9WdKmz OO#%:]zi??s8p_tP:7fkL^멤HҪ,E%A~:zQgEuh""1\SNI˩?ǴJovlf|ɉa[6Vh7ҍŋ#aegPrc2/]zkF"s^;^z[lֈF\pnT*Q.~ϽߡAHRJ8V |^]M*L\ FkyT0Zu_+@`ĤPqӛUT] {.ZMf_8ũq!y]X~pto?D (ܶmRV˗/?E[&Yl~sEz[6@1u~l]Q [0R\~4wpX+q{8} Cb(8_Hs'c/g;wV٬Ѹ(BxֱFRUxi*>az6H_g,Bb~7\:^lHsu&E#f-(D@gU3ԙ]A/0dh>D 5WJ%x鬨p4mA;T*|>&2eKE>kf&.v-8 %-|"ܿ}#XGTD>~Lҽq5.D3WנN-³t;_©yYd6]}u &LtHDn[6ZbfEwrHLe'(pZ >\UU eYXfF>絥絛=5=6˕ \&;:@3q?w2j[@ }p ""0zՏ7{q@(T@G@iby%"2 n:6D"zM\9svΕ>Fh^/\(]_ݰEF9s<+:Js;1ŮW[ђ$f? MPK˿+luXƬs_%pm'_PzvqpE3 O֜ÿy2+mym@J-W^Й؛Ji~@]$1֤Mg21n8P4tt3ߢh{7֞ h*JOl^^(eͷ^F6'v3n)\6ŋE7fdƢNPkCf/!vj< ݷ; [Z/l!ض|^T~Ѯ U~ONU9G7/<9^?=FC/5?_eݕ&jHDqv=' 㧳މ$VZrmy+N_RO>"felտϵPoZT~3Ѭ Q@#)}}O9H:r$ ;f-7 ll+z$ZCۗ3ޢ|#@7lۘ`4.9V0 ߩ"xNzz];7byg>gN7kVZ!b7JgѮrLY` IAm'ҫ}4bv W3RhԺ}Xߞ֋3(*@B?;-cK/<15ߪ善Ϻ=o5Z'[}a/ݥB*ow`]fˇ_>]q+ 4߆ATvzTTv^^4bcͶ8Vxxxmmپ4t=6;W @zl&qF_3ӵߙ5s g/& jf5F8R',xU^ϙG~to,]\o&փf0J@hmyپNv^=&Ռ&L0xJ"+[G|пy#whioF%Wp$!7fD5J2?ROm Hh4Zp/.3~|yp*)79Z_vAYh W2fl$`}i5326Y㽚ͩѯU \x)rU=+m l"o#W v-@ G{wwELL&iQ&sX+NԜɗ ߘ-w USn|S6s-6{њ_ - 7@4Cm? >"r*)E 99ʖW>_ Z >@xmҷ6So%٠\ic@˫ И4!!K;rwTXDH>(GT=`.PƬΖѼ={d.U׾r5&C3UD۵no%Mm1 r |-kq 1 2>AK&z@Bpyu93CrW]>SsIÃ˛ [M36-U[[+A;ZYAk$WޑRۺ7qUWt~֚h e-|)x A;#u*-@[@Z/S6mzkLe6oiMVR[ja 8RS vUo|Mf[۪ߪX WUXZeFx-k~E`8mB_s;X `h&ڦFڜB Vrq@UWV@ @vZmv&XX]o;`!?m UW M^C vPv IENDB`refind-0.11.4/icons/func_exit.png0000664000175000017500000000424012626644770017135 0ustar rodsmithrodsmithPNG  IHDR00W pHYs oytIME -% ?IDAThY]PSg~$'dX`uV,.btuvfg:^tw:RV?ún;(Q F$D IIrη9'r|~"~dΝ<j&}5Dirʪ!$IMڮ.) cc ZBjLH~=}_ZW\S\rKFbygnnF V-!'d:c]`PԵ䑊ZV& ~jo/4ϟgGGAQ >uk0'ڨutp%}}￯JB$RYtM2x,=wm6]hEa<9t"odΞڥKoYȀ ߰ݼ{7fVk x1Lwf~'TY"Vk-qʏ'z7] ecV,-Q:]p q eR(~yYYc۶eV|S4_ϳip`˙QDff xhy˖I"e6a0+60*k:K@gv-[9KFschw6%_\p!HOtaak$G֝<}/Ikb g׮tB(' !u+߻w[(01YHJpV^bF1"[BF'okZ `'L  JC!_…:& ?WHp`dfkeHUf+aB!zk2&kFttV1YF* t/hV^bs{H[C+nPr~Z@@ 6?PGH~_V6xDH|@T7]p|1N뉾>_\=Ϲ²W3c,r'Bӝ;w\Gɛ{rzr*7לDN& ߰n'dUny.ud ( M]v J\x|o䘳 Nx!"}nz&X6DQ76v菣JdS$hW0{9Gs v_O^vHZEJa0Xzu/xlRT%Z@H#\pDᏘ"9J !JLW,˙̊ p$+0e^Q8`'1`=жV|sP5p}@?5UZXKL.N٭NSK6hLOrdwYN +k7d-ض}5|[ݩU5j 5ض n&tfRdՄG|ͦ'/>DB} ]KT59!SSD|ӧ_bgA@8folOޞh!Hp8 TUHm:]ɞڻ#gjB^IENDB`refind-0.11.4/icons/tool_netboot.png0000664000175000017500000000731112626644770017662 0ustar rodsmithrodsmithPNG  IHDR00W pHYs B(xtIME %'*hIDAThkl]Uv{s+vc &! !LK[`VԪ蠪/mΔDuZ2jGe(00! cBb;vl_^~ýNN@ni\{{ m36lʽn===UJ:t00{|#Ws=ǃ>*oJ_Ny+\'XTѣGnkڝPػw/K.*b/l.wq(H) @5B\02KCu=ٹe˖}޽{ cRXzox5]-@|nN |wIwްjcfz 7 ;9mmB^]U"(ɒiE-kHTCiҚ06懿} M g1o{Yz7` wyt;ƞ#477DڰO!Z+Rs&qңy(Uᖘ#+# Lc]bſl޼u}sxۻ<=S#<3h@0HkxIݧ8*Å"t *ɵ^}:Z1UV=u~i]DŸ_onn~Ra׵g1`ni-I<_^96*OGc,iC}f8yg><~ :sNJ);x7tuuUMM͏̲a'",5B`Bz>RJ3Nd- s,)u\W"T~fZvցOV+cahBIy\BXka}`e` 2nsFcRG+߻zTTTt&'[ї4]?V *M?RN;fO=yꩧxgO o7c$`"5ɻ󮣹,QXi.G!;<}d;./LHmm_N$---c1c s4v73120UuZ)gi hyM!v+Mxiwdk1؇6!Ľ/怔o*lvY{k8Osmh犩Xe:BǢF|O̎>tJs1 $, :KCLm>0xR\LE~dx|ܽDWr Ji/ΥNP9X6H#`lQ6TtFh9VXepJX"9㨮c<ƛ(_6ww~](O,9R ˱./ZkEK,- s q`g) SY?He5e9|\l5ZyřIǂLfsc6CQgv=o YE!3IT5K)MZ-. X b=dg$Sb+MSω'>|T8 {=ǎתּx%?832OsgӠu(]QE"(dsld.r<̳@jd_xuϩes@{{r\Da". jJw}k  žD"?S5ʹd2ʕ:;01G2]@&hm:ةq _,k+.Uu*#7Vώ}~bb7@A-i2}}'qqcc"~!w+ʺ*ys ͛{306c Ww:51" Ie1Nx_}@;jE"h)??m7n|8˭/RΤR)o߾s׶Ֆ'|A|9D:ˎH?-Np֔~+wMqoG+1 lvww675-hOZgl '%h9cwT/J/mb0q3S 2@RkO[QQFQ4g90`P`j5ŗx6Ȳ7uV S8|^z}m+ujv%x+馛VTWWǵq \Wp#=m۶ZW.00ځ˗/jhhF?yPJ|>7LN~MRGJNF[q}kWM@P TUTTZϯR;sg0 dgu#s$p,n]vm6Q<駟v3i79[oU*?uT56?5wN$ !2~!KQ' ͍M2o!;u}^0])iZ~}gǁG,Yrm2!ɬTJsM[ W~gwasBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org< IDATxw|UCBB$ DQZw]k[ʮ *kǎ *JBPӁ6)Lf޿?&=I!CqxL2r={{F../v.4i4͹+K`63k:9 Õ;FԾ_@N0\R{(H bU/E @M36JI^)+Ǐ *Eyj+߭|b Pt({,b RYYPWWf8AG V`0XZmXt:]` ʋիWNaa+V4630's+r`Ps;$.K*\*@ ~:iݗ ^YY9ֿk׮AAABCCJcT644UWWihhe6{9s&"&&!00lUU:(t8g8 8<"㛚?"%K*(/1|l*888+:::GY_o}g}HYݾ}v=8::>$$h4ّ_5<|MMݎ[2\J%׿udFFƴkϞ=ܭ[] }+̷2[M,&wU'N-**XQQ14""xaaa@MMMndST8@$G̻֭ۜN:5*))Xll޽{~wN!gZP՚ߌ[q%544L.))522/vڵ N@T'hEF4ξjǯ8pwygrm_얘.q-UKn.HQOWWW_ETTԉ={~zpApQ?~@ffcǎUܷo߷f΂㽍rUc nZq.;AqCsDDĄ X{ޗ_~'tD (2sΝk׮fsȑ#_~<fPΩi7#D/}'&6iڴi=z~駟~ A  j~ѢEwɓ' 0?rZJK{ jnM&bД4RUEe~-Mw"EpP\ TH{СSRRo˗/?\(pޥZ@3iҤG_ G}t+QjLwѬ#k`V; !`;:(QTDqy%ʴ]%"g(ơ;p4׉A̙3S(--M=z3} <% 1.DFqq/qPT4fR1|0Bd: mܝBR5%PP ~3Η 3q._x Nj]FIeh9s挣G%>>~N{bÆ ȁpAyȿ;vN.]~|vʕ 3</nG~z ]Ωw|[* ܠȇ_Cq-XVQiξpxHMKI{RB9aر!>_;΋)@fͺs޽6l؋VzriLZW% '߾fjO&O!"xdm4iҜcǎ=2pwnr}}RAsSyr۷ĉnjO?݈'*x_M]+dxURE>{?[ XsS|Dp2QRDL]wU{y911xHH[n-uia(hѢ^[lyرc|TbcHڝ!k5H&p7i.Բ߇Y1f7F W_]V5'''߶q:4pbs(x>_ڰ]v}RЍswRT[{>mwΦ3ERL<9pY}}}@RR?c)E>~¹P2GMXj.][矋<"MS6:G\y#_@\.l|S|޻m ?7S$a_())֥K6o,TȔs< C=iӦ۔fK5}-x|rA>);LL|0 ౣxW1@,Jʎ}5 of!22rmf镤G\>#H%,Yw߭\v]d L9?C:\_Ü+fh$,{p7 M Z@xEEEq7xٳgoC. Ҡݒ@ɓ'u:5''i< ￑ W'g=ɘOϿ _g4MqquaժU˟xx!z# |5?gΜI߿LP+gsENCriP^ظT'?-a7tgOq/nS +V۷ܢ"CNNΪ={*@K\̿o߾W]uռ{ ed.%VCxGqɑ}l ^/kKփ3yOOnI\ x'Ι3{FΝ;w2'hJ/3fܴe˖W_}CnRHwRL 4ε,1de A\sC[@7o/?o>R*ut /v׮]ό;+V/=_zt|Hn{n 9d~ǂ v~ww)}T8LϞ=nݺ9J$Γ!n8^dkupƟp!xN <#HOO/:xsO uU %gΜyfԽ{&I<:H?mk.i`rzt| 9jhЌ̔ aXUUUgdd'@Rs9r·zk?rH@84Ixρl;M΀:z\%2Ad"D6.N W8jr`3&Њ/5{ ? ,AsQ8j$HѣGl4nr˔ak/Rx{))1S_gZڀT-gj1i.Ԉ>ˆ!6hE;/?t2 VG1ed>w{~_+s88A`yO[qsbQz{P̙sUFF{$K>~h2NNa=RMٞR;ArQys<);a@RJuww#i8h%w i;j9+Qo$hO}W W沾 (.3 0ϥȍFEE- \iP 5/k :@j-.. glN}XtFغHyGy=N5B:JGVB DޡS dJ nHO*Z+56?r g Ss,mо ֭[7911q\|Y(U r??gΜRRRxXEjzwԥ^` X=KIPG7bO8b%_{$W5_c)>EeJ ss|6gRB|˿,=[O~B!FBtIJXZZl}}&== 8 2㐐a ΃7<8`|Jq)6 9)m~6MnKžT6_dz-nJX'̒JgɚNבB"8/p{Z@Xti)Sv=:@"@"%ݺu X}F a瀱)]Y;R{>8+| fmr)%D&TVLWN%tiC wV;KɝϝTkٛ8%TpI믿FkW RkZh4?ȑ# j_,|Xݱ\͈ۜ6v5h`X &utL?mM>g|5K=p"t(Iފxx/bʃ-ū&+1:B#IO"nȶo/ƍW[ZZ:O["7jo߁JޏK%ѯkN$3,? ġ4ر- )'\*ͥo4$)! @*c=wvR aiC oݾ}(q 'AKOXttbbb?iGˍ݁w_P[:S!7NU.gqvU8ENʍ^xRռBLUL wbִ3ZD$n=@& m2=ܟ4j)b寊/ %66vΝ;g̐NZ; ݩ$ @;؏bNJbV9#W[D4qkyю[#a\ƕ% sJKJJ&6ߢRJ%LA111;$7#. .΃z] ,Ch$O׻^aJ;?/W (3PONnF_=p2_{ԩx_ &00pOMMM'"ʏ ϾU()(">RבC* DKڇ딉zo0v$ ӧϺ#GzːXqi8cƌ젠cǎ=DZ{OIXˊKMC>*tin&ɻQ)  y4SdžFF:@xc7L4dggLNN7>H#JsŽݱMo\8E _|/ʔ 7p6zNtGڬ,[KN:5r2خ)tYDDD&I\s{%|'%[ٗQGjRD]S$CxQ2@s(A4i&{i$ÃXwۡeۊ(sY]TZ ,@S9\@/Ghq@zBN:gϞiӦ>Qzt:͛*O*CvX27K1gqvh\1KhibRk::=-YImAihh o"ϖ7233ÚH͢v5tޱcÜms@SٽHŊ( zv7=BƽE-;#x7ׯ_j|̫H~~~ҽ~!"JXKmƔ_GrXUky(+(2Y|cJ" s.+mΝft^,-M&SW^_W a#jA ӸǙ|@٨!n{by.u6W NΝ;Kf)d 4}!D#w_v¢_,Rˋb`( v6|@c6*Q?*jxxxbQ7 $|BomSK4t!?,$(V5(00PLtRXYY9(==]/IE4hoNȶ7Uß}\S؄nԌ돾!+@[<<3߀;3p8G\b@0 G#%^~i0]K/.N2Y+mf&wyp|tOgoŏL&aٲe[io|^y啊ù9&ߜJ~A(us5(dLgXWe@KNy+?в؃3oUÇ7!,,ldBuU߸8i5hnJf8Ni4MRZ|dk^x8>>hNN`Pݔ 갘,X49/UUU$Iȫg'jIDATWZ&}j 7$<-)͸!$ svA.~8U.'ڢԔ8K٪L&ݻ9Mk"͓QB_c:x8"G\/ݪt7hɉp|K^p{ h8 ':t(_bTuM~~~9 K~e> \LpF BYʔW&Ǡja[/lj_dzyOttf͚,^mPdwۼ6KN7ݕJ?ܱrE(]4DUebx^jp](8#c?Rksp26 gs:tٲec322 d#Y)#MңGi7tM@_Rv_ײ)Hسi}E,A vQAuҭw8o괨²)"n%]pUl-@+B{wOu:L\ \Ź%kB Dۗ[0?"qؓT 4x?=?$1t:Ը3ML83YO2*7iСyhZZ/xF2UFBn5H ⃦&[zz4xwA)\M'gL=%Y-1c~GO/}kteKWq׭eLQI ӧOfi׭[2ނ%۷qodffΉPZDmZcai> X|/Jt_Gvy*fdR 6ѳP&6L!^ }uOdlW͌RǍz'N￯ē-ek$ 6mZ~ʵ?4B>WO_M)_g*n@\A ed e1H>_tF[9;}ɯ82Cak!{d~/l~7LyXAk@Phϯ8 cd1';t7U3T?|[oYi{]$EITu;s4!--mUSSSi\zSs֛\!F%T5;UfV65\F~?;v… !wTJt~he Ie gϾgΝ zݚ5kJqšۧq\9~ןG.9e~wǞCٱ?{% w|ibjfMwr ϔqN +;`/ѣǾǚS. ȟ+J6X:]tǙ3@P$\Bq&Sd.G&NO"_#00pyRRRw0r(kvTMP1 @xEEEڬYaI Zŋ=G?Mόd˗/uݒ$˱; `_reСC>|3g@eI:_R6UHzY ogu/};'농lCnyZovk6nvQ(+ 6@]L矯KJJ:ujbT`WJFY%u^m꛰Ɂpe45y>G̙pEG^Gh{% eSA^^ޒ7.\QAq*@\ ,f݁8)݆ØyPKJW/~I.\cǎwuVgϞ-~U/REpI'NXhZ{uuiiiȧ>Ԍ^OvJ՗^h3\bt6GBK>99Iׯ)+Ws[n lbJNNg2b_T_X_xt=Ymo/iU™qS!gbLqׅXn5IIIsϕ"y&s.Sۘ |M!C;4--Y<ŕVd%O.vfc!z.1lX~8C؟_G w|݁[Got#;)GJ)M{<{G)Suu ΢8w{(~q M pE>}{>w@?k.ni g vKxE,%R9QIa`u`?UM JW呻:B;pʬgR/^Fo999#UV_|Qiv/g6@&LХ9--ѕ+Wf9%qx 8_O1vH4#AAF q}(DTs'/6.m36'j(WF'QB%WdW˶>`3gNڡCt2&&Tg*)VA B@@.==}~vv]111?uՕ+Wf9%'"?#(419`"Dh?~: jAp &,5l4V[hjr 3uw,GVϝRH@ĉCV_ իK֭XWRe>;sWHCi H̙3{=;gϞ~z` |3!R'O#ΰiLq:15AgUSIvաRĎW:\b9\x B߾}8y=QQQ;w~rݺuْ>?Ej#p*@ hnGkYYY\JJʇuuuݻ L# t۾+a攫%L\JH ĵM2ebVV֢ھ}gmT58vyx]"z &))8hР;?~l6m۶eYπ@aULTEPHR)>A}SR-ܪMڔsssg9Cjj_|jE(Ê|p-@) d68;++kNmm~~~B||3gά\t9܃"bPJfHEL)6mZtmm-3 955m۶}^^^jRGp *O:u ޭ[aaa÷nٲ0  uT2UI]N4ВD5* ..ꂂ1]~du. W|LN }:Xmaaa"##7VI g ҝv˔J06cƌh< kOEVsN5Oe]|,B)Aiv4u0&&hX,u;w>~|&UTG RSSu_~TٜhA8w?|{$풶OL.J{{.8 ch$@` )/X,j??F 000/<<asBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org< IDATx}w|U^R& $tHM0jE}Vğ軺uuUtQRP B % ! FH}w̓$̤~ɴf{B_<twz:aҋFӋڥKҏ|O% _yܷs>BF0 +l7xx59 yDxmQ$X?vXSHKssǗ-~c{ܵk7ロn*Zs-1>jLWW)JrE 70HV"x |8PSe"@DJ:/PUUjrݪۥpuU_?{Z͍5`IDx o>ߌG=l(,74xU07o@]PVyyPӠ ~)--Cʪ )'fK}6 Ü ]JFs<ĉw?`̘D^Tgi!Μ_R`>MBWW@?h xX'VUg::-.NO^ *p=k,|)S~ޱYw'#y37VK[G!R44@@ k\\*ә?\ɓ'ˌ0:t!LIb9s;}zưs"BǴې!,\Hto][TFuQ׮=?m`8:)qZ7ntD1==}]FD'd ޼2j1^?p 0?3g/\,+2#YF<0Sgg5pҥ[?tabl>^__ م~~q7+*blْpl߾r@ j`ÃD&‡\.O6H xMk6mcǂ̟ JG|O{/tՠ>`ݭI; PSTtpv_sp dZKJOMݿ| v0,~'Gn.u՞?tk_}WN=;tU:Xag `c=ʩa ?&%%@J 0gPtsWۈBvP*g qp\0hTЗ 4}TD"B4c5zM "zZ!|EEoo07 ZE$G fp/;LoNMŋ{:0n1v[[?R$qDG Z}h*|Phё#FEf&m0>ݺ-Po_##N2T@s0,zH`g7_{[u[p ^FbwZ ` D+i@SytIR?"@MM1?ؽ֬FnrJJ~7f+0>@K!AAOqDqqǾ`nvVwafZΝ;jmC/ON\ޟwee~P[`w4vEW``4de2 j#RFj `i7x0qϊtJ7!4bh^_`Ə)`J$!>T*#`҂3g˳ޝt:'x/O>)_|SD*,Wm0EGGhW?l8?NQQtZS)Ci@x84i5CoQ 3'oY@Vkp20y2?SB\@c,#xY`r۶mXǍ $M h>:PC_@GlCR)Z`ɉDGPXH^VVVVS8N-@ ?_v Yܮ۴ѿL,Za?L$b̡ <gϦ_rT,idiWff~ZmӀDz:э%`LQj@7n׮QGJd2@#ӫ7sq&NՕN7[@ $>%N[%h^GN꫾j;Ν @ PV"~HB iiNHKI CL*tWWjpөU%E 853f׿R?_ hLG+^G~Oųf-3J6H$/A3ôސ/PRB5ACB ;>z(5dFիYiaZ"U,})O?b0&FRQCӫ搋 Od3\v>2R܉BoIp@J z`$:zso3#7QU[KR@,YܻU h/kA>.\!NY׽ adծ{]3…*4j_OK["^@o3rr] /HMZ'v~ۃxqqYVx1֖^NK-o/z4,#ž9bߡX Y41I ts]mV@'o2-uk i̞|ҳ7ndd(~m%e{˷ `x1r)%%fJJZ.7%6T`@Y˽?dc]~l2"#QnݸQ棟kk+&0-+xs' 3O;w2jk@鹟U4+k_^Bolr\]ѝ?e;x|~~A 6Wl O8Q:j({xb97Ã6 g YYK+**@>6NNY0%ڸqŋ+Vxw'9Y3#:ڿX˯D"RVWUn;&2+fʁaac~pݻrرKOã̬t"^_z _߁G-a06)NP(t%%@ ||DdDX믽4..wqFd$^u#-4G?AF?zV<̢EVr0Wz0w!?%@r2NN~Ry{Ph$@ モc6k"$uO>ٰ{ε6s>ۍh%hZQ1OT^DbbSx-*Z ظu^Mݻ"CZHON/5|o6Yude.$6~ꊊls*2q"!?׹NNcd_?{a /|+J%0CG؁SۣƎ7tYBh֭KÞilR{uEH+)W\UUT*>h`ͳGyyM0{Wfg\Is˭=PϘ9{ܱco>"h5#BB^l6;wҒ*c4٢S1s&*+s]v Z%qqkmy4A n ɸ[|x>yqpP O79W_٦BGs$ZA ;w .˫@SwjH >}/;;=lg0?NYࡧC&jRw~mBy scb=%@Im1>e7son-jOFpȐ!^^BtZB!|9ptڝ1Cw299녰okhMZAcuprƽc(y0MiPTv[n,|[C[4"D^:͂1+*/b-,^R4B5`任HM fBCiݝ(+o%\|]8/yǏ/+&:88Xvvԩ4fmA(y J-|4z9G1uuu(S*tNN:Z&ܽK 3?(~#Q9xpOIOd>Z6[&y]YFϜ;kptT٬p ]h}< ӧrfܢ2Nz-<]k Օ*I`f޹< !qv=z P1IIicc[ jRR)~=QgVSoh(:]乧c4\s|ZW>:LcGA\^Ò%:ڢ?YRlY>3r2Oiu/Zc Ec'JS7*|ۦSս 'p'=0+?an_nm[pϞń h=Ӫ~KH#ؑOܾ}'.6JKX;6xEQ* oVWVւ [f^?], Ǝi(JjgB.~0|b{t`XPP4\V*tGMo Ǐ}g﵋bb76jDF'Fqc؀ )Z(U]jc5G˾^^y M\;Fr!?ղbq+օZXpuEڢXnVV{oyFiҥzl :O'vsӧ~˗9rdj@@= `s @`Di@@}ԩ11VU9;G%$OH[X ,X;G-[',L{id079ϖ$h0إK_~sQQM/mWsC1s&iV fx8’%]SZ|❷:V_ҽf.}FDwMN@#lkk?wP,<{Iμ@!r @X,5o'_? DG'2!=D\|-I9yc[~O~|-KMvbxo ݘNZm;@] `Y/[󩺏?//2!s/:ɨh_}EȦM>s&ƍm Mz4{U Ц):TQ,uǏ̙㥳f7loh) R?S8msbH_?`߾iiCyK. *ts{BԅI po zƴi 6艇mGGȀl@HR!3!AA?B>#d}ӓ/ W_ݴI)3L>^jYX jvEj: ._=5ls`J@*I[@ظmСT:|h4ZPg{J||y=:kaP{EB~dB֮%ۛ NNtf}7 B ٶp*LCCI]aaҧ~ @JÈaea5!!%wz`X͛[>VёޯPV(4ٙdU rrg>Mx55ֲqD"`Լv{ j@Ǖ0 D!ˬEnd*tpXvGy?>L(oozᴔTJOd* rt::;8P-2?\/tPTNEuZ8{cahU @_\\ނ}==}۶ pծ@5Pv6=͓ϧ@$$h(Y¶Qu`ĤI#Ǎ9ĉZp|SUCTmUPk?ƏqUy  U=U*4jm7[Bm-xii~TI-NjBG`u !OfHzeѢ>-['?~ j bP۪& 1ta#ӀU ,Y\4dedh[_ѨN4lqv m샀7dDDx^p! ͧv)!dC86`d'fp]:Ң"͎[k/]*XvmU4]cv`[x{4^,%j5L6;4v:@ jAmJcJMNy/\cǴxM,7ǃUՀ7Ldw!h"sTkwW[wW_ݑ8rd6!A"'2nެQ&Xe`SX0 c NZ*mUueeݍɓ.7nh؂Eؽ9;`D qIDATT޺UYhX ?@;d7 W, 44奥Қ;]˝5uqBJ$ؿt@_@9:zX6;'7l~,h8֍,ɋ(7>9888͊0zty9ˎ">A}~:#""C/P f.Ꭾ7n#pcd$` NO=|Є1c"}|Gʑ?wLەm7_1 Vb͡@Gͱ0RNAZ2Q O>_ᒝ_*704Y1i 8LС؀n#@cn&q0i53rߔB<< WfnwST._g!GJ[7oNI0mÆnu;XX8a%Og''QQ {Kw?Dw6+sg Ӧ!w۷ޱuUPsL(hH47d`bA\]Â<:uذ5ssͥ@ϰ <dz{{soO,%@9_ SE:a=@SO>0X"d`]ѯAs 5*؛a\bP~LCl,RZR[|> ^}QOP}mK09ɪ@U?k @@=dZ*lv6.<O*er,r//77I7lXr^Cb`|0 XHhIC0i/+Q(j>ܼ9Cye#&Wôz0hZKZk4JM@:rK]u`,93hT{MpV#deI=V@boOTrwa 0lz8xhaFRRۇ͈Ճ &tt,wשPŜ{z)`=/6kc@,zQHH9sODꪨJHs˥t`J"hhA..@P@n P aZ.(Hw^.ٿwoD&]KH(UTuXߤ~pgߴ7"K;xKٕb1ķnܨ  ܾqɉѪF *D%9cVjh^{%!%7 ̾K4y'V=)]lwqB܂4-i},ZXBZZAc\Ϲ N'7(K$Рi@nh*k `,[\"p $4ͣs{0Z%+>n(MFj0KndV4!,2,ϒR7(2o+}.4a\R&bXxOm%| ?mIENDB`refind-0.11.4/icons/tool_windows_rescue.png0000664000175000017500000001033112626644770021244 0ustar rodsmithrodsmithPNG  IHDR00WbKGD pHYs B(xtIME  fIDAThypם?瞑4c$1Mv㔃ٍC.ٜNl'eWJ8qsCCHB:i4#3oP $$qU~CQ+&=wKL)%k֬)f{<999srr)+++]reqX䨪RjF/ yH$& -#H877wo 8%0BJ)ˢ]ח:f~M~N4`ZȨ]p8f2h4p8v5 >t( }rmnn dE1M4; q!ď<ωuww7p8<5cM}iw)-:qZ !O %3l65ݭ TH VCoA)WH1~tmeeA91;=*tظ}@V7'_?E{gDVDAz-~{m-9kђ VLOt^F0^̒%Kkwڵw87pMw6yU$pCתmlmtƤ 1r$?8]]To=3 c)MӂͫPA<5jc?Mu+3Ҫ:]k7.W.BFi)>:ay6+qAvl۶mŋWtuu>eeeǏ0ͼ [?k!dC2̹1L6(;"m8*p֒NF*p|6w'fS'CI~-/3Yznݺ.hiYfJ<? ؼzyWx;v]g@'2=}MIzܢk c}G$L=[nq\G-+=ajٖ~Nٲ!5"w-` xdž]j[JDE^5J/\4! 1yG|O%Iɚ +iS9(zrTUʸs+R&PHq5dGa%4 F|2Lr"XR&'&zCriJ2D] k>^z'Z=vpX UUm{g}=//i)2.u{Fu͇p 8ӟ6d^=Bj E2 PݍfkGn;) D{Bb&m8>YNd):2ˉ] T`N:{aKe!DM+PX4'Nӣґ51\q& '|XQ۴*U)()9 EnAۛ("-XHFV<ނ{m-}@ 3gӛu]7RF\՚[^o߾F|>x ߘԔ 8X{+;N7~P`݀LU\eUdv:f~0H9OO=끃 uhTٴif+< ],V= ;N~}2!o0loyGa[!!?c75NeBCė!F/d2:th ྽n&XV6'dӘz*#:xR4bs*0w+q9> }"VRo\\DUUUׇBQ /bM}!ç~ i| asJnS))U>^ $cĪqfG?ћkWl"1$7MMMEgϮRmdH3&pK+/+Oͼ,÷v'?? /SQ5RsڨL&c!{<NJB]=GuL/gxigaӗo( x9L3p!cۿk׮oV86u2v&Xnnn[!"??9ʀEfئbT`; @%I=bc,qwlٲ哝dΘ z֩Ft:'//)}}}'iڸaOŮ"31ʼnjn>61N%æ'HiI_?ʼniJJ.Cr&D*++?cƟڎbff JULBإ"eM684`7n| {Zr %) ƀEQnw2OQeh1+65WfU6)JJJ>$ Bn{iΜ9xR49P"< $py];_Z{KkVUp8l\.=R\ r: v=Lt]d2mmmmD"Gd;;KP%:9#kkkRT"<Og0زeK5!:ّ7n^)1mr{G#Df/ȫy[ eʨO gM"]Za0QL8AIENDB`refind-0.11.4/icons/os_slackware.png0000664000175000017500000002176212626644770017636 0ustar rodsmithrodsmithPNG  IHDR>a pHYs B(xtIME %tzV IDATxy|\ŕUݛX^16f6g2_v^^d&/BI2/H2y/ ː!$!fز,[}kvk{ZRk ϧ>nI;ks &ĘcbL11&ĘcbL^=lrU. PumHM`?|aeTJ)0Z;o6 i(.B`?a| px8{m &%oڡ}&Rr1>`xD-dRċJqD˙"Dx !(F*GT1_ú0 <6q| q~|)(8  mYv5 9-u5c5@{?-xw¹>Ow h~cYly/gė2)\| ⡝bqi?` p8A<xv, E1r) xx 8|,kq Ňodb ذ]͚B#\?48_6l17s}J)InL&_)~vј d&g}z%A?JPD|d.Yz[S{ḟR"Ya\'!oD)# Y" x7߫7_)Ja)EWoSrZ>rv"("o>{( ɤ$` Wĺ)E(QjD8 F/S <,)#D0bh(#ԷC;{YgOOcd)˲,=K)vrʕV%PbϔLωZ~uE{[iWTTv:?%%čίTd" ߖ7*R@ B_¼zY|AeYQ j[Ϋ>> '7iAkWWWHa{4K/}Dd"[ćrRu90g[ZS]]}쐽Ό1cD7ih#C{l  }Z; u {vuapKo90V\jjꭆ^b[ `-:Ma;"^bigE%đn\<'yw9%n*\wTt< h)ZL~E|ڟf 1Bv"uXf[w6*oK/[ Gu?Qp|us.YtQ~Zދ_GŞiD!wedI_PJb_[E}AE } {4ߡ(}ѻy#]By/ KVSS,r{=o{\7ؠ'2L5.Fd}A ޭRD8Am!>iX" !Xe;I eVBp;TpTp%Z )]*hq?s=Z͹UBp>%BsR)/"~OMd&\UMCUr/m^lrVEÇ[}N<9+Xla2`^~U[7ZJxઍUP=ḁq7 i:p^B!g-k=dQ{B ѩK<,<*WjY&b\}5Օs4J Y-# jà-DBK +}ݥhhTU|kvӐ,G"|?௪E)N26#(2!v C1%}bBd !XXqog  SaY^Oa']!?!(c~t׼y)Q$*\$_W 15wb4%@BL((< R ْ `D/v*  V%%TEWۇ k #0I3i]GйκH!A?sba5&Džu/IٶK *fZRITT)0haL@\<<>B]R|6cS|˗?pшac`Yx *0g{=Gb]93{D {SJH;@ )W Av !/aD ? ]H[*A%xjkkZ'GP6@ȪU>GT,/s/d_ uWh&gHJ|)neΞ!Y=0 ~RV2K>Ip_}VIg6h\b9z> 3~)F)3 TrsZsY  (VF" Ӗޥ֯U!:pŰa/yo KSS^}.Dvz]Ѯڵ̼Kb@+\l) gއVJ/6qľɰU@|o`-Z3$t1!XytoW}o46+^A&}SIӦ޽φ+:֮؞,f5kRrRR %fLf\r3@9Hbsa7~^H]']R.~[83^'~~~Nn(d_2k{m$s5 \.9o3%KPFp)pOApz8ئx(D\۷F^ Ywuu7XyƘZ=.9e>/evu2FJ"Skzjߩh"[8`ŗ  y6{HlY%Qo+n}>,E'T@^pqOe6HhڜɥWݣ^(E!/.krY+[Z6jRI*on`H3Albg ~_eE^=8`?VNjD9 i7v~˳ g Ed#HpFcf-•6(6At乛Qox ZI/ fgS X .d#ð5HM*V4{׮sbu -j_NТ#* ٸ@JXYVТ.‘ǂ|8́( ]Z) ;e$zm;&|QYRe>} %,t% Y^]@ ׻oOyq߉pmʀ@jah4h:kr5Y^f`wH=X$i(Z)E8z礗uNj:;:~vny]\h &ѳ*5ƉD)zӵŒ6tY17+#hQ*۝Z$j;|Ͷ]'8hɆIg iX pTFld|C]`_9zľ*gW}"s'm۳8eN߽ʝꕁ;=gPK'd .ȹ?|$o_8 @4SGŔF|5X=~~V @ݶ5K! <"S PESO9S =,g+=(˘5X|Dx_ -@46T}ۿ`IJHJ"n߯gQy[LVŚVƊ(/>pދ5$v :9%W/U"Iv@w=55O刡gXh=XSixqd\yR2H-WÇ ࣟ8ZtY f = * j*=? çIV!gժUysl4`G<ҮxvhiX@$@tM-֚׆BmUD{+`i9eYV77RflզceӘY*V$(L#fnSnz-v ?4`k8vN"?#= ̭.|f*uUIvCV (]]]),GdZfțj؜[4+:$ HUHd*]>ig~*G Ȝ ]]wڄw'4nu ɧe,=-wsiU9rSQ>$Yt`ݺV;=h[2yv+Rǎ;ٺ`0詭5yv+Fk:{z{^7^yls֎E$h7*[4a8k k8­>zwuCȡCS!@- Ӱt@ y;WH$F4thD_Lb^|$dIdA"mч7i Ъ#_ {޸(uFͱOo Щߩ|G*D;zN䊻Ox7JX`-YܯVcmrB6+**: Jkw (HE_enxk;e?/:5ѩq EOw;z-vs LF'k*8H✄Q Rzi>KsݬAd5DUBgtYQ2dӧ {mܸzuvSjEUQQMS?R%K&y<$$-6e\<%+pePpt =}$!XҠ-5a *׵Al#ݮvi'\z*#Y$(`F2ꩂܷg.iU'B}H!\n7Ff|rU)Y~y.$vm.gDNZy$ Fn| TLhil6a}˞vuVۨ$&S#8~n 1צrߧs3l8#'RS#JszO=2+sӇ0W+L"P@svq~a~ ̞$[Bºx묫=a}FHlrD}Fsjkkk;j[1ٹ\?-bWwٽ\J;,ڿ&?{S5靴@{uZ=f򁙑t%PK}x=//oc/}_FHo$8͝d6ORgU?;L; bw]H|`߭]p7{hJ}Rվyr7j&9{)^x~N@NDW1^c ~P܏9"nA*Ii{0Q߇w5+O_71œd:ջa?=}M Fn8mgrugtdf jS׺KN+7RD' qTb'ef̜9smuW..cؖIuxɟDP`D 5 ՙ6Xٝ +( :U<f" !(^$V/g'e b@5kfY7vY2^60HvQ|<|AҰVIף8B{/R~Ox6[2fp`6445׭;MR& oOz6FqW?ML=N3PL ]fCCXɕJ$5o?+Slhoſo1WHAͭ&@Vz:.Wm7h=Rџ 0Jhllt@ASqOMՈ!e'n 666Zsi>6dIǭH4cr}jQx!l{lo~Gen$@6dccc4͟zcfd*(0Q7 ފOr[z8XH4{N!-;X2,6Qꯒ^╩*šٽ{io" YLg2QS_kjN,`LK'۾@gu|8by[o5ho8?#ϔЯ?m[L&۟啔tMJ, ,FG,Ն'{6m_?#ϖf/ng՜YAn(SY< m{ vy~5K_w@OFi NA.UdTd;Mz\hC3u&udx#ۋ(Q y=W~ 1zsTGv8VA{\ܯp@ؘ/xh{] 5 0H&UuvMx'lٗv*.t@"+lG=݇ZD7m`\-2ItKcH%®#}\qT-ܠ0\tHnB$} Έ231'O )z_$LyFL@/0.*3& TabKGDD(M pHYs B(xtIME*ؼP IDATxiם'{uWWh4DD]T))fوYaI;Y޵dž?#lia;BuxWQDiD(($NwWuG= PM7sϩTd26!$!0cY!"쾏R*c, du{28wOM`jt{`]Joү|{|pا?>dPJ@L8?\ëWn^ޔP|$$1Bbƿ=u gm5֫pkeV68FlMOC3ojmB=oݍ`wyx4N9BѤVǁ*}K2+HYFihMJ JƆLD0ˮj 'Wx؁1> 3_a憠$pb++8wmke( LBaBtUOߟr ]U1J`:B&\Zġ,sТGb?jB3-8VՄP Hg2Jե{ ʵ)؆*RBJhK)y_*w{?a<&&&Ǐ\_3Rq}3xy,>u $?6 {mgpTAQ |dm/ (Q !dR )*f]u()`fPdj2lUMд>DiJB?, Pė;vK/|;NO !Ħl& WpuKM2@fJ p;dvdEDQCe\_^Bq!Tՠ&pXAlH4!T@DtRNSBr*'?| _m6M_SO=OM3:A\j@4dGFId^(΁&rn ߽o4E[q2:@PPSYSG2 LDJ)A4O1=0LPk`  D-!o_;v46M|ꩧ"HHo(!Rzm3 `^XW0 T1R* Ba A4Oa^ſ} ,HneC v 0rPtRRp]."0(xy<;{A)P)#"|EU/}s{cJ)u]`=ܷlK=s(P 0tRHHAi:c&zz;ar\ru kZ(Ta(J I LQ@S8ʜbS(|yg6(VgQk{F%i/??䓗>B @п0Bp E8HNi /J HhA'SUp<̇!ix,\=[ӍlKȅ8xؒ,2,yƈK &|)!x\ZT %D5!L$SO~:G41>W+.G6=znaTVbHڂ!( R@x/ xket F~i25HP\NIãYB̷92*KHZ r9NV\WqrIr*UU|_W R>}?( 'g8Br>C[bx0AWث x\`#;cpQ/l#0#PL )1i,̯#)]|b$*9n4}(Ϣغj g-!q8k{`;gCF ! ?N* !طG~Gc}g[ zi,.f,;_pD&C[PPaBK@Fa )PTD~$2F EBjo˥8ҌbT@)ZPkxYR (V5ŧM*/^z饫__8W?H$AĜ&d"F<:5%ae$6I0K ̀c +p Tӡ,>CҵzUPx mpoA1_#;(7, s(ltSk:a,_4/ʭ/|k_(_ߣF5E2MLi*ϕ|h_JU)5ObJCo q#7=!8ZYUTPW/AKqNk)LsIj,iu ?!x:=BWh|ff曚ݞ6ұ"+$t|x,]MVB ?TG 8\%6!PUʂ!%jU,I$%>W?FD oe5M?;_w]]~/񿠌}Г8hSL TB4XHsxC #n7UHȝŰcQAUT7aRX_p0E52J1?Ͼ34?RH)wcc_g O\K >Gz+4:.Ra$apAH}RIoqLJh7pPdlg1)<˓w%P)%`;v3e=6X"K2^>^8JP,g1Ҁd$AqKgG U}"f| !??7>>eEQ& ުnf𹇏@$r̭CRĀJh"tɓo!Aw[JQd5dGm¾gfs~#PCTiqˀEW;qzA"=<9 eҸRzCH6,躮]o摠3>c~c&3#R]v@X5ӗ҅y3В(eE%7r%KJ HJHx ͙k8_'HfΡ%X^_`TGt2|oCSA.'XD$  w5x~A*T* N6sh(i! r\׊SBKv ;{Stü]` #<r2,*>.SWp!HO Sj'T0ꂠrZKxU\_z2t #u:=^ĖR.?Ҽ$>CCCÚJ!7v/WfKR c`fTQ(^7NvؔlE]BAo  4C6ST%AٕX2XV(64)UQ|3(5x<./3SF%d!㍦%B@cG*q haZKǓd,cLr `BҶ#2ݍ1F!\[J @`0:2=C5 $,;$:Fvfp OLX &qN xC׺ VvL ҨOrĶasIpʲuӗ0JowR OHH󳸸la: 6ç Lv--u. #o33<~V<ιksP.!do[J\k7g iCsaLK%Ht]oԚ-K hJJ~B.VVhfL h0nF{r@rY-bַ\obnS=LJ JehVT24G-Zw'%@i( W8T( C1, {`~laHOZW"k%{0l y[YrN8 yHY&;" :z:sBePY,J)L9m!$8Ӡ$2P@0d1Et0E yRG*EOvˬ^X|}H8B(6j z"<@Яs}Xuq.J?JH7/=Pv$@^WHa)>@ ,8x(I8ɪ=o|r'9qA:MR0 C3.g)cэ!LOs031࿏ksN;GC* lGGldlKSP(LFҢ%.c9-8[dM 10 <66e_A@LRlSrp8LM#3{pmw/˷C 0AEH!BCՆi0 9SA*F} sk<#q0;ݩ x? 9}[ zsF^1 '=*%#-d(r 7~VEzCiLkmȎDj 454;.,C`4g\@ !82åׅmaSWcp=/Hd {`$oH)lZm˲22,P( J"~{xeã`f]x։ ] {\8 86Ƹm /İj\'mt"B ,|x>v]BJ uRɽ[T vd-J$4FF^kx`f>QgT+yP舆G)p%f>ί 8"00[ʝCRQ20)pA S lO%TE bBxv|5q:(y0@uHaBLV j23USX{#1ܟWADdBT> 8W/pqǩ5M!y;*rːB_5S@UڙKxzrN֊,) #,C lAtZvWE rZU4T#)b0L3!T; QR_yVǎL5xbs(8"GTduEWb@!An3fS ٿgK^xH|Cº*zXIĉj˾s`1+ J$# F0ҍi&jQ[ǯxs'ҍ FCE&xQ-âbĭD$"` -j<}TRHnYqq5XcKj8ɄuJZ-c#ےX!jZg}}yi. ak !cӼ(Ӡ0(.>Aò'(@9w}_1O˗/WbĿ5}B\.әP0 kRDy(F 5T(S) zs D-P5MPW퍭dsΉd ^A1M0@"ϯrܦ9ǩ+;QȥPȦy[/JW\Gם6#--/WVVWLMޔD-@c8eH*do!B G# I4ޗIuIDAT!lE@JA^8͌2TQ@>j2ٕ2f&G`mK^>3P0=1Ngyaaa@gPS*sssKGiZes)5&Z^'L 2OdUf<Ő5uLg8.-". cO!F7R+W#fLF  }JR,B(&R fZ>k=.B/6ڢnh%)=i3+**@ԯ 10ajqKm.b-qv},Tf#F3V( <묭]|wVg1=b377W\^^^q4"utcA<:<4u7+ `&"gR\ /Kẍ́2hT@QEсݔmTڈ2zM{l- {YnwFP t4.\0_,WP(0Ӑ҂덺>] }ji6 ؗא@HJ(*6^|,V=; jXsê#ɛ8;$b)*j-m=G? cUB,|9&F2&x8s[ǏRzJG6ӧo<ЃlAu#)r*j<R*`K7ai}adR j?/ 4o7u[)U e\v_”v֐ 'Ozd FDi IaBL$:+.NЫGBWV8m eowb\QjCBRێNbIkׅ޲/\ H). =$-D]m]x/(L6E9& K)p)\c A>V@ 0=1,š 4Ϝ>~Ct Qlkkk²,ujrϸYB]RqqΉX\X!L~ lcb[+n'{D}X:g'@p884E¼u}p_.gC4Bck ʊ?6>R"c)X(;" @{B?I6oszpΥ5ӂ:ț=6O]dFcϼzXva. c @wSSv"DPފ|Re;: }k'Qȥ{6_즄 Yq(X)qj M_cPI|B@xHyy^ԩS'?-bwe1Ƽceeťb MGJp}דRu:ѭ] ##@݋Q@Xw3yBޒ7s&LKY&}߻z?Ok4!+ܿ[%׮]og2ulllDQ%2&CQnv$CYc@>ر`ySh TU}t`۞E* "*or(A X4'~/R+[_|\Q}acZ U]144etmR̮4 |~Axgt %L1VH1Rsouuu_ /jWB/ǒ="%@ܸFûx:!)MӴC?9AՌr,ڴl7SCuS))NXxPPXoxK.}^ C1_}I@_Cis\|XDBmێFqj?{kUL;4DL lٜ';ŎOOBUL'ppBV7Wsz|CRu>lοS&u)dhM@FA-4 jAVL,G7Ѡ'F1QqpfM,5 ]{ff/?~ohZK!#ίE"w;$ (H?O#80wji(4^.F庋REp=_ٷqX\h8)@S "aPdS* qNZ-={o|(1`E@:$|l;3Ng8#O۶`8  4ZGloewP,Fk Ja )[A: a)tFIJe˗ϝ;wŋC./2{KEwGy+$x@>C>wdG?|بmIUUY([[q <\rNuB]UtAU4vVYDiKiUիW;wŋc])4c~ݻĿTB"$z&A.9 pdҙi,!]vƉ*RJx7zX\~k׮-\reQJY _ sb"Cv3jLD@ȆHǤ@uݞٳghbb044MRI0lEQX4ggx:f^T+++ksssb;j[p=]]v-.zh$# %@mJGFF\.H$,˲,0 ]u1Fw* !}_{ti7FZ׊ՕZX,քP7c\_ '|ݷZ`j FG- TʴmH$V24S锭z&(aCA aD٬+3JulvzZ6v;k3$r=F8(xm1@Dn`PbDg2əض=b`ii Zm… r]0#~t4c7w+v7.;8z;!`@_,BHGQiR4MV JsRZ 5;8on+G Fm0 5#zzdRi #R&*c+NF10}Dc#A N՘dp Ød2|hh0Mǽj(JPR^vG%! $ILǫ!J4ktZd2² `&@) ÈXĎ7%G;!Ge UU[eD"\.D"#,!|0*e˜~0 |#CHێl5z9O6cuݘ y P!WqIEQ$#=Y1'4M~)H*P]cT20 #AaAb\fy$4&|K~r2S`}նmPbI=%\N%F< E>:|X/V_?\ Pmi,--,mOVErΉyn+NG7ms8zh-$o[+=)DJ-˔1uLJih4fQ*"MDޱdNPFGGqsn)b3ƬRjg2RjSuJ) (G5&&&㟂Cф뺹NB9C2 'L`C) @ȶ;MiR<h2ˇJ$!)uB:t @&,;n`qt'|[J<#QuG㜏?y|s^RRʁxv#d37OX%v^!gz]Q몪2Tq:  -] ˲ um"y^C 7ʽlwݾٓ; h&=;;K/}Ky^MBRۥ&*%$\oC 3Z!-HBUUm(VUi.6 !HbM?c۷'dc@^#O23G.%| ,..V)Q~/lK)頉:c$((I)~>??q8Ysl6W_}uӧIEQڔRR ƘC)%A>D"ao?q]f @p!!ɹs皞vɞBGAI-qagd8vx^'jAƼ6<<`nJ?(!yp}Fik@ܻ)*5UEQԿkCbayP!TfëכUxvT6uC 7NV?^|ݪ6qQy&"w,wA#n,~' f:sg5]l(@$Ki5.^6| .g$>Av>6m`2҃AM $C2&MB4)o%@+(E)e4٥veJkؘ$$5ʇq;0H_F2M!EÜxo5BeĈ_ q>_箃>ەBql"6:|][ ^r~wP^f"bًy$P @Q'P3?pg䢁ZWAQ32I$@wDlǥ$Ƽǃbb %s|uHUIENDB`refind-0.11.4/icons/os_xenial.png0000664000175000017500000002150113117634430017115 0ustar rodsmithrodsmithPNG  IHDR>abKGD pHYsffttIME c IDATx}w|TםNUbcc@pڦl&>o6ټ:=yɾݗ/nNl봵%bf:Tg$hFv9܁A|3wνD%*QJTD%*QJT=A4ѶeMAЭ{hCw 7C| ї^C) gUdN)ǟbF 0 +Dg0z]Y85=?*o Y g %N] g&l\4((5"3# ИNEnq@c4P@LL|_׈+0.Hw@P@hz^gg}AhBePPPٽr_>_{Cd^Fܘ>NcSpM>\hoܳћk׋*1pHB8?-w {6v} `/}‡ Gĸ*FDVAA0n$@E|lo *xŖx=k'9^q&CbP6|NwsG11y '=|ƺ&۹&Al (?Ŵ S= b7H~q>u@1Nֈ\!Ml,v *m\#;7ڛlDs4A\@ۺ`=PNtDR >O+3R I B =wVZ~fŕF\nz^*qEbSNnx@MZ} l Mta?T+,rZr.|uz%jC˽j+~peuCՋl_1:* @,앪# +k9*i%a+ooG:q8 {~@P6WUZjT;ANFCoy'~v`#p{]nTMrO>MT *Gu0υVS (ٺE@ډ~=<39SpPhcf$1r.!54J "vB K-϶D/U4`c'O26iTyI~vf@;7 >c >7TX-&;79H`P&- FP 7 ]q3lb!/ |&#,8Nœ0BOf-79tKoUY|oPԀz\@,4XFz \nͥFzbg&l=nz7SH!Wѽl4+XP'К,|df~_=L2}O6[JY??xnWK&7Mwr̴}yGDJ APjl2dy2 $W)0,F|Rt h2.,\X?=\~[T1@=اJ~&T-EK+5aBY\/?115]SR"Ȑk]Uq+_rȭ+UƢEUkED?;>`@cFYXZ\+*P*g>7\b5xϱr:5}#x.S)뗎[V\`?6-ݱ|q)w"[Wk 9 , V: ٘y$rQpՖtX RWdYƻifz=|dwԃFN[0ӎ׷ :p..Ĥ=Tk#-Ua_h~۰IhX$DGm\E ;Oz]Ֆ)e L7;&jj79Z@%3QꬬzquV;ʉa+|2Ria;<Æ]_2r/yrk7yɔ^jA@O˛kx*:>Uqhę Pɰnis WNVȀp6[P!#*Ho?16ȁ"]6ЋZ []Iv+#mfw}5LJzg3,܊?.Qp6L1dt.^FSfd0(xu(ЪZ_Fh)r&o\WO73z^e10ܶ[>jaP veK%'A߽AdқFd )ow!8h=B}u= YٵXPxG`;,2$6[4G -.c.ջvwzN4n[& VH$VoBpծ_:PO, HP1޾jdP aVu!+&=`e?P\&eA XSii|faW5'<2d^ RD1By6PJ۫5/.ʑЂM>驳ƘN|B!*F`@d_iDe;2dn3]b^챐#nH9P0 '%ґrb2gAQIC}ouvR#Op>;%Ru8ldмBD?#DϠ˗1,`t'ulIngv}ƽ93\ܬF;*-|=ޅ‚gֈ_~zx7\iG;"uhNw80tH,̕Ppy6`!VWZ G51j-[\&6ϞZ(' k ᓌWcd77x㟁+iL$bVxxt*sLJ` J4'Ͼ%f7jDE<1>u]pcq#ys\f#1kmc$5~ß)2iDb*">FWm8 @d#$xӅmI6}`p>>>j.nVi8+]y)Ee~\oIFPOҪ:ߪ}S`$U@'J6vNIƶ[@v pHbV.F[^H TWnXN+f85:TO./&qw7Uzzә~+,Z9@g$BcX]h::N'C;*5Z+[v(0LhlQGxz$U-`X7v]̰ɰLBI-l $ d!-8>ϸT /['r~gz{wO#u'φDaɐ 뚦!,B# p3c cI`@ }-1WP\3:g0{FTO| j Q"ֆa(,+{} =eM 0Pn&ӣż|OQ^\W'!DP[ `eQSw\ )N⇃߼uip ߽JxXJ$BY)r_VptX4bsAbOzZ*Jn}~WNY\ ܯmEaLBs%z%[1zChв~T0r 1 - E$XY󷭱7u!rM#`:^@@nAP=eaqŸN1W҃RU[S~P`+$dpԍG{%JTh ANF;TY-7~-3w|pgMwtL o[c6蕦93_b0"tK;陁 aṰzؕ *ЩN#bD'&;!qQF n4?8lK44]seoCv</PR_=ѐn2ٌ݈\߿jra~HEd>5׻-lpJ'oP~u1ڢLnknt]c9Ed>_1Nk$̢?^T),:V#vk^Hdde ߨ}rw3qf˱d>@O\ $d:Pl~{^5ݽvH4% !#]/Uc`4# kpAHċ*#(:+o<HF wٰ>m=jFҋa܄̙25B5Nyҍ dpH:P=p{rLMQ[m<Zn+瓽υfW|>Fx;q ,ZwP#wA5 9ݯUY:w"їW_t=hF2͗WeC^ rOlǨЇH9ݰGd2kB{vZg;zƢ#F1JbP^1DU $׻|}/OG7!?øNq)9Vݳs`WNL!_jg1PC;xBRwJːv•ܾ>4މ$Wos]šµh4/ s]r)}ۖzj1-@b^rg ){ a 8~/w08>”=-+"&󂐈 [\y I|{Iczi]VT&T:P4#ٽ&,SjAߏّvf{@IDAT{dp> <+-4,DFr7ljy =Bq27;W|d\QӀCX@;T Uw%J:}{( wR $%gOcpŠ7jQ\9(W7űY5"zQrG@1$q)WtW|ixoP!m)cѫ,̄,giG6)?CJmƧT.: Wsqbc'@g5\)1Ev{y,wθvq_#ovrMT5uO:^E5K1z36nD7 ~uoH1]3Z;$ 4ox7WZu--=fթC%ԢQLsx'@1J 00#3ף;{t%HFWbY^VHtOę+єIxOfoFGPXpx# T@$h)6@I<; %*QJTD%*QJt̰~IENDB`refind-0.11.4/icons/os_trusty.png0000644000175000017500000003442013117632031017204 0ustar rodsmithrodsmithPNG  IHDR>abKGD pHYs  tIME 6(T IDATxwdWu/[{SU'f4fPD ؘkc \c?s3i,rٍ ipl'nˍ@e7/jzVTn|aprNnI7nL~71݃Z~ڌE5S< C50~<ǵ|RsNlv/~d``ytle뀟sgB1JC#@ Q8Z"|P?{O?~jؚS͑v7noza y+kSᵮZpٹGr:!aX"V9`+|s/|~񦸲?كie>gй ?_AkK+#bl^[0t @A98ơnOBreQoۢ㧼Pw]WU0V8&(Q([|% ԍ*%RqA $zoQ.pM^^k3EwڏیϦN@g/.6/{~Y<:<&~_2WҖ'}~7rEUV)c_L *i҉9״iq q7[g@gؽO|`,4>'ۻ ues{)>'& '%fOZ,]$)(b'57x5-۰U՗wL͟Mo_;cy_bo>D_SU@b |RH4Wr@dOJz˓ߙT1t3n9 *J3lڔ nd70 BDߚ# T,(_dTF?0|RpE1H;}?7><4ցkq@Wy76/U{".yxq9Z'kG|Y@ ٬7-ߚ?ٶI$p%l+EH& (ɿC{&D;,csu{a'^ۋKO79FP ~?7rMlM7?y'[: Cܸ=\{<&$]t;>0ְ,p|N~uyam#5yfxuwjwOwMT/kJA\W3ncaDnaskefWF 澺6|BD W Bnn$ހ;`L}u|"9gY(!3?wP(¤h܆m\MieEM*_E8 ??CWp߉ w⯏:x:Wsr>8n6v5!ʕlۛs+ G̱$SǮ rȇ]b\ٶY0ܢyAD>+-Kb{ggo!E6ۈ ̓«ֹMSiNTtXkfr]J׼voێllwG7@E lpA](?2 K"3lj/X?靲18~jk|Oo7< x&lYC5_ߒ Ha5xf. |j2ՌDzȢ+]xKu1}ѵtr*[H Qœe3y _`ۈ WTEA!ynNsnR;%<~t_`2M>1߹? iMiA57oXߘ̍9 CsGA,@qE|l0[6>xKbggmAG"0@ZuNAڞ~yMkIo<M ;%@ %Ŀ-zn>s]%ϗ]azŋ6ir./мePRiM <ŏ}(' 2B whu"us6~4Z?Z`JxPrn3ʿy ͗G@]p:=BZ.A圙KP7vG W^TpJ"`y/HKh*-(@`Z@@ AR?|~@x6-Ab$)ki'Hn]^Yxߨ^= .# F 0C$DPIpHJ{ڒ5&_ANAU ny^O@;M}~Coۙ .?`i;@ PZ! 9Έm=p?JU=G2 hU [ ZooT}=~gxoPM 49*r!`g'RD /퓯5 f0N7ojk kt62/ْUs4j¦!UPFB_7vpc@yd|ws9<ځÈxS.EWM6)ñCF};e;^g{D(t-}c >{t/&gmD(l]sl&杴v w+qy\=.TW~$/N`_0 2έ9\3(>GM imm.\s}>? HxT?z$@ rq4+>qu!.  Ҙ Hп?U_z#c>11e#rBƺW@m{U!\!y%ٸPno+lcERUEo@*lT 9:I ef岉7퍵K4MkX`o~{T+D4t!TY''y\8 C(*h٘iJ{qу^}htXÏmT4^4_“_>ii?Im1,ZRP<%=:'9.}ON[πAʗV;}|yc~u0:VHs1{6GAA!%4C{L$}{[Q:zGuk+/‘l-+.E>SYd zq%^<stGhu =lcb'rw{kG,J>l$Z).{}F;JuZ~pђ#[]IL7oUqԿ8Ԛ4KAt~<T[ؽ /SW\fac$ͬ0:^w.c;-Gݗm f iX._D\,E 1>xba .6r@_hKL5Do ):o9[woS/8o3ϿB=1}񕏆tp5r᭗ĨEy(*_ OGc%['ЩUv ne @!@9 oOms U/a`m\<2;z`vvzH8SCW|8[8g_-#OlY*b:8o|;E @ו O5&8@s>;o^S8Hז NY}_Ь=FaTϓ@ "LذH}3`P}:XLEo]am:|4.UmwgJ!PF?bYyIgŦm9f8΋ -EY[پ `NQ&p{,u_|%;@pw%G9ǥNB XTBvEKư Gv&ZӲ jM:2r]Rzm$.lfXAyn[U䎦Kux>y lR3=: jp[\}Ҹ Dp^2v6QK%I5|͎e9Kֽgؾi__pN_vc ~Z\HΟt:ZW֬QDeehkaFG Ȏ^Nn;>\ (i-/Xw !~~W]/=9Pm}mRZ#D&ksא " xg/^ulåc(ahW (Ь 4*я'l@lKmy;DGJ+YGTv~:E\+o'G &+Nb9{8 JWއ g/܄J 'Ƀq-[! *smѥ2H4W=`1ŗ RK6ROb׿q@>kakۥ#+ ֎hCʽ|_5<ۍ{c2:}!(v*Z&A`/@k 9En]%<b[6O^01ל R/ /{?ivs~h݈}YֈZ^!tNHIB {Wй#'L'P. #wWJ MCk=Ar`XHbuyшWgci\xweF1E[[ִkdzl*wmU+ ҹТca1mxe [vtvǢ`˧/oqE9A~29F!zH]*yrI@ 8oאޠ*ANw/|f< sx{DD2}n_!!`Ёt:4qgdř_d #2PLxֆ5Q؝ ћ/+ !M3@V#+|[@Pao 8hI SeLn}~C$:-J^bFKyW~)K(7tSgTa pxt̋ MK>A-w9Vٱk TNV!i8ډ;^M߱.ЎQ`VJ}7qX[︰js>y*5IRTkxˊn !Ir4  cܨ_j3\$9KJf9 JXחr˱7ɪ عI#T`ʴ4'׏7k:9X-P WqbXTUzin[+@ڀ`AXH.I<)bPc}HX 9{ \$}%jtS<^c_Fo t,T.F03 "Mr89҃Sq@tZrMKi3e/ygpݣ'Кh8ïAo4hTʐ,s(TȲ`AulxԎ8bi wր PsGJ>W\\PVgX-`^΋rш҉XsK#JQYI05ʘI0.e-_1L|[@> eΒ7b*Y]}+ C1gVy|Xaܢ\HXS9O/.otAX14X/ UZ\Mrb(f,{%>i䜂KrH YSĞBg  b2 =t_mNDwFIDATáy˚F8@,"!K९J$ԕ1LdPU[&*}8 zČ2D t B #Y${9iV:<׫;68BBYGu4AW<\v'f%+З)iB(ԈRȞ"xTh^^ P `@)WaY;1h5 }D@ttwJخZZD 7ӹ<}r]l_EfTo1{nf@2фPA!_:`>ڢWIƂ^` 3)$k*N:ߧ/=p3]<{&5kME '7vR1DdQ[&~/c$@ P*M8> Ng"H.f{Ouq+p h"f@a3' %&Ģ2Py"1\v@CֆXMB`/r;S7;x80Cy@={1Bp N;#nQm1(t< =}Bo<hΫqh$Ѥ)BbZcH#] {2S$gޅ[٘ ,yF,FuPfZ!@4@|E@;cQbbqz=HP'ci(Z)W5ܔ%Xjx W+eNy̑2=y8q3N8i𵺁K?k`I|X3g$qs>F[9gM&@5UDX`%Fg&2O\5 Ga[0MҖZïvhA,?᳟C{4MD;3(%vAѢb<I.hQ,i+$M7.rbb: Eoδ:W!3֧b;^(b  H>Vp2o(X!C^ sү1GIN! JnJ$00|_~"V)ZH 2aE 8ʺU4Rgp n1ZqrHZuzJ\} Wf^<-T<* gCY _-yUh֡JY#:\Z=8T"q#:ijY@˲{+]j,lq!V1iVXڬ eiq&r^G\+!HuF쁌8bA0sۜ>ز [ EupoWyW{@:rAXIژՄ7`Ψs##!oNYip$g;8kDB#e)j; {oDw#SRf_;Zh.(>rqH b8P$*j  j3jbpf hW=<"ϊcA89b83P(z~CAu [0n0~xHbff1ǂ^TRY0UX2|LRrbP<":Cn1,'s%.H+:{ 9L^,l*)r R58 kw"EK\<KEcf,fYFu+9YlILh#H3 #*{ֽj>T IT<"p5ԉDYJA<#1b"8g!)4eIDApR l9?V L2<:Sm18_X*|NOrXC&:P#T-ңV%sOSQ(ɚDdqtfQƙ; mCH(JTVe Q<h8rԭ$HCyu cf `lh.k_f̲<9şr5wO5XXUvU"x"l:_g90ˆB& ;cD"`0zK / h`7ą#X9+a=$f9(*X TRIc* E&O؎H+Oz5,(NڬCN**%n6Ō8(E.( S6j)j,pMPDֻ_$VVM Ddi28k}j_J{^HQHFh3cS"댘3%* E7l~Պ?: = F=qT霢)"x:0 }(s/7-4Pֱ 9Q*& aˆN%4!"p Hα'(0o*Tʑ RG V: j2w&jk^EzTiv qh>B{Tˁ SxQg璲R%8w'8pA$i*i̅r*TQf I{8(0 +֞,3R gEPE1JB MPBbPX dcXq)v`]Yݴnga2mN6-CXaDye'e8FVP`Ra]a Ơ BZMXUI0̪r FQ(p'2Bu` zO8fYO(Xf޼ nM}G.%҄N&(tH+' s\:rG' L"3b8*c:nq8(!yaIZ@'S)&5"6r̕ljN*Z5R&bW`\pnQ= y2pbpx ؔqa JemRb4h SQa|] IJ!S]U8؍&3LYT-\Ā3j4 $b :WS:'E66s~ @A*DQv5ul=FHNljeS*NL'Z(9AdIiHlVS*jN|ϗ4!k6u>EMBri]smO1 #u){zpCag:@:r"O\BEQH`@Rs$~JHK˅H(U|@@Qʋ4u2q{BDNqV?<ȾonݻOACq. IWa*sƒ\ȹc5 U,Q"4ScU|C5pmgijAy^C"DE")'< S?ef_zqn}Js1JߑN"7 X՚Su.}g+4_&9%nnTKszv'+, ̩Su6FG_=)aڀ q#wM0>XJ'iCe(E8 xc8mܢ;Bt ds!?Ba8 VEFT. *(Uv 7Ih7v@Pmہ\J"̑--@uƣ)O5?+叇v0pv@X} vh}qT,SO vh@@zOY?i퀀n:YET_Чru23nJ ^eX>-þ{鶀O9:`% K sasBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<IDATxy\UǿUUtH:I!"hdqATqT̠,*,"$ @@CI/IoIwk?޻VիZ֫w~s9C -CyT^'RNV̐p/ SR.3?%c 50 I0m-ֻNGH `paH@b0" eB䓐7*BtC"u9: j`=e$w)yǁ99о >Z w;cA *A̠|wNWB?Y+< 瞄@4d@݋A CȉPusD.E6h~~]HCA `nwA!4s ˈL'΅oo\0sw*P< g̀Їfֵ ~jڃUn@Q__o332$% Drz)C˜*``<(!1 xm@y66J~ȁؽ>#0fy0r±R 6@CByp׀:ހY@e=e@kdLC0_&## g[A< .۱~\4CK'4w@cDܾVM(@M%1P\$OA OWb| 'O# .ظV 'Uھμ0̛¬0i"J|XfLWb!uH̷觠0'M0q$ G=& /޸jca /q} j jX:``UxWܷlnB& i2TϚ YRɕa0'_m0a<ed%<*@cvO<XbShkog kQ8F6 j`dl[ a~`2Cؼ ^u`EKh \|;/q8j,wtPP6U& ̦ۻY o6f|'a?v@0_u_6Tu D-(n/[aLZ@;] 2~:,߅Xo|!e?O&a$nD3* 07t Ș n\5`d `GX ڀ{ZBgByn:h_]'\Lnѣ(/1G0P 5<"gq_7ܽV/V{p!3:UTi tLN/ lJ6AWV8]]՞ to[Rṟ˼Q (ILD&'΃ȧϸhʧȱ_dێQkwi'L5j7wg ic=pDN7ۚXۂPz|Ux}H)PU0g<~־Ȋcǽ7 83Jl%(M 5M|j'Pyk؃0=CcXKt)af5L Ba',_RP [pq32$_0 VϛIˆ#7 "sf6(lAҳA:I CR7@;kl<8 ꮇ_ TPF W:M>H({5:("/~W#kpvBHW=G5VT3㩩/.*FaD)oid#eteWudqpK)ũ"N71$( `iGe7nU:IJ3$`Kd,N`ieA&|"0|p VYv _䐀mfz2βhgTAH; IO y.ecҝuj^?Qr͖„Yfk؋jj=bH^IWGM1 o$PGfEYqwY8&s.i(?/\,Š`K@@UgO~9K7E>Xv9]R O5B?n @3`s@$42]2 o.Yua:3N5THQU&]NH3 ?VLNw Ȯϡ 714{;ٍeu *@QXoNe8 D-^U\VjaK;; wt t"wFè.mƽu ʆ+w]OwIp;r5+&H|B0`li9}$v@vul`ޅp)XHr=dP9Vf8t@3?e$.\ IP A]]a~P|#e[ٌ*27p̙׋+ | в6ҏH}}}=veJ8 Jo#ʨ=Qo1l #IrqmlG׫9PTBswêF 7B]]aN O_ ?3ÊK7q*ICTDUn"4䈝t*`֙`d9:fu}.5)$Ƌ%HP|}o;^6./ET$?mmF}մ _ Ӿ75,{~oYrKt)gt| ?Sxx],f pΌ;XJ$U8H(7'-l]RU:^ _09~}3=˷OX*1q>O:叀YYG2TSuys}_ڻyc*Edѯ~WmLe֭^oyA(F1ÎO&7'_ŗ@hj-n.,Ʌ1ua@mAX$xc9qJ2J81=M2ԿO/>nL OPxU_k<[j[8&8u]_e\UDIԋwIgyae> 6!nB+"EW Px )d,^Y,\YY) HV1r0>'t(,E# 1bAFT Mm]{aM0OK7pwBQ>2]~ k$dFH@`kOYruap;{![>(v %mJJ f`Lk6ب7O| lg.rV)Ap?e=6„)Px]:oUX~Y)3 VeMuF3^u[p—z_0?(ל.jaB n"%lLZydѯy[l j`Fs8, q0A xbh&iFv?fJ%ln ʠbp@W&Ac3nVdfu P@RPA=kg߆,ԔEk/iP o{y?`0 넑 ( Ͼy{꧓mc4fx35@n+ϓ)? chlOP;,CU`vAȀRKEB0p[ Qa<@"y}W+@݁ cc;,߃e aZ2mܶ7h=vtuq_!Ä!x}N7i`P:dʙr|âXeqN@ q0Ɨ'k`(U,c kEǥX۬FNw[MveI*\߸hŠ?UT1:bT$ ! yWl+m}.w8O͘ޭAKe.9liP,(@`R.$WPOѪtާ2;Gw4 S%P+~xa (J$:W IaWSeTҭw:ْHF#Qѫc=TNvdlw桢{2pLtnW3^88Ҩ(lc#g쓩yr={W &42;4 oo )@}@)@.$\9{j S oT<*&T^ ) nx2s)}Ժ{)K6NMn0M8r<& @ ! A#@jU8(퐵0JM xo'^@R`H~(AO?dҥ0~>æN?#!A('bi d頑Du.@`v70`R>-Y -Jr(H<4MwJw3q rx@bhRKw<+}Ldq!Hk$BO*,A[4z\p4X"rfeZk>Hbw np{>)| Bje4]̌h2muBg5 v"Ha$Gg:C8N;&Trl) n43)`KWJ |0$~:!s(ӏSr adHI B >)o3õEӥaKAh] @aJa@IlIj%(/  XJbnlwxCaj^:EFgMɇ{G0 qḂ*k-mt;0C6.4-߮<Ez"ΩwRv}wRԔyfk&tNJ%>9~~b{I~mX J' Woman: ,Q8A{6 Kң/0m]*'`MߖjJ^6  Z w ] `G#l)+iaC`Qlj˿ DJ)jY[ElڒM ,"=+aZEci3,[.AL^{ uJ̜9_@vÈarH!ϊxX{|ke %FRa0$N JǶ` Lfa 2hGRr'1 aZgWTIENDB`refind-0.11.4/icons/os_systemd.png0000664000175000017500000001676413320156731017343 0ustar rodsmithrodsmithPNG  IHDR>asBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<qIDATxyTe߳ waSsTg.e[)f.(.R!S4+%K (-74 ВY:3<3y93ϙ;s}{Ι3yݞy"bq^nX-< QG?(rQ{<{Ͽ~O1 Jd3gyoߧU!4>)2!|s@2|Уa|j&Ht2)0c}E>@80>$ׄ9 - /֯t5k[7[m3>a$ w]`p&9}<Ȥ`M|޼Y -S`ׂ`z&@Oa!p0ؿ:Rqw tJxXp-`m …U|E A$Id0_}>nK`pA |$"jKԫI{ ( hx~4<"2n_8E6uP@SggIRw8x-2 |?\&D()PG0HUR Жy6}g& 0RG`?Rmo?SR }`AI jplӱS nBt}Ygz`{ -(!ǀwo!nƽK~2E3 PFa9oaM'z?OǏ(37S_'cxkCp;bx d> :r ؈@AMH(6I;dƏB"'Dg>>p6" p8s+> lJUKE`}}W?;fR~^cW/oE87؃`+ ]Łt0= ^~`vXN?ޥD2\x͏pN R8<0 1GϨ qOk[`r8wv JӁ󀹎$ 1 >+8 4j0: ގ-YoףI=T `/`'D5 Q9?AUKb o7@WE5w^vEdWzi? q$g䤀6DU6 }`ksCW Z$ "J@rc~SX Jw90;0Yx.).2K!u08po#K̗Ow鱂 HMR!S !Cc}^8=bX !ѾGJ MzC[!!LJ@r47` JzQK:7˺72fPO3ULs7 DE#Iv e7R 1R/mUX3 PTlKp\\|<* H~?^*( з#-^^A/F## 8^GtДU \T@dVJb C8će%iU[Wvឬi}Dԅi$Lt<>qJ&D6䩁HHȬ+oMV:N`,#tƪ[0p|a j bb({k]~UA#Ɏ!q +lFea P1 LDR&#ij9Y"8 E {0`X91MU# Gb.H5'a=! 6X`.G#zpNc;?6miY), )7J$5FW+# 1~^2״]TVwO$g}j#O@rO%˽HlcxXOE y@ǰ:JH Wo))D8w̍b9{mLHθvݬ [ LWABTp&s91"BBjQR+KMGlNDt.%5G}Qבj@:O1}4R@0/(&W{]: &!.䮰%V .UZ q9vԚ#2/qZhx| b?7-i!ZQȺϾ/fT q^ ,Wk9h2KԊL=H4l3&;\mHU5j#u7~" LNOyҊnEķ2 >՛8RPKKB}EЀ8/AUd4jGOC1x0i  TÌ7d\ 6ch垃=Ќ4~<C9v.B#N(:!0H"-ȲIY.*([ mjY8y|F.4jU ]8埉p-pV" .iC_+ov2A@ྌFQR/qkT[p^Onw8P1ST.Պ@xۧv:p1ux! -abCc`0 t} 1+:&^x| :,Dh(TTdz k.=DVv߰nZ0Z"H?#:|{ANɿ]CyU2nz/o^|滪Wqҟ{NNHx[$hk;; Yl/dr$@;t~(08^J ?KFܣ!vMMB4qM(R|%ufPF9 TYTφhћ%=BDCOApk=EnHYjA@YszU>ao,s<>$p"P["0CA0Ls^X_B ΣDuwеv_\ %I˪ oY]@`:L&m_8ulK ,R@7vh-K(lZ.%> ن|a'g󈞠Ҝh 0* `KkdXTA^6[w"!;;B l tIt)6f{>g_deЛioD 6^HA% AUȖ? m Kİ(]_l7S` %ApV] AK0]wHJ\d]*8w`lZ^J"ڀ#Wm6KxUzQk#UDaou9Σ%Hl8)D{m;PT!Dú(Wv`Ra@߁*?a"H4viF|7H<~@i]TSS3BqF 5WFV ; )Lea_UMjY8?hse\++!>@w5r^EVTpO~/;{n&.kf.b&U~hP 0sπݨwB6vqoCzG8'Vy6DV]FZXa>!6/CDS:=7e4?ʟPTB51Gqh.,[o 'AA6!x/$KmDw$ \_ :“I}vN~U;z)8^fgIRbl8!oNB:y#a3\y]P'b\[ڹ/K^`hGUZ@CJw! Jijd~ ZQc;Fm-MTc㖓ajƱ$ZXL:Jn`DXDΕw0|Q#jW_+=9Lpg`b5qWRX)k{qrօkeV\#m??t]>u5+m2ՀY{=zzYZcx(n ,qX$X?ӞvwvHIef2`!X52Yۿ(f#v8[㭅)h &Et8"&7Q?H8wқʓ`;Wpiц- uEM"!TgNzAC|:N=o/HծA!mkA tmtwYب6pojmJ) Ůͅ3egU1bh(Ro0i7yQipMK x \ә$uEC$qn)F7hB~4hN7uWhtwd>/B&2{BJ R;9-GD?p:-e C1_ }f?t]e)Fn4Y=ti@:C%VGi: mCA8EMp?u'6ΟOjguC&QGYjͿ2F:\iaBGv%o۸4fJCux`g<}`]|(O0C$H%U geY{`-l8H9#FJC&x p y6 6~7~%u tf :<jEYQh=3޿j)I^y2@E̜Y_쇮 T^}&mCB f@*?FD͓ޠ:ۏ1{0 Ӑ<{Ꙙ%0Q|l?s sj A$ۙMW9h cbݛҐysɠzrOKQ`P9w$uʿ݁}G .ҿ QYʣ*I)H!5\*m(ƛkGyR{ a&6@+ uI|}\xKK"xxQ}a{+k{..z`'-C|vVҦ 4@D9][m"?Y _i!=Adr1Jffݪ7G@?2s4mC{O_A 1-N+Ģw1^Y_ׅJXgq"}oj7 KN%4Mᤑ%2 aх/:͘-b"ߤ.BK լ&B-[SFLR옆L2.T?kgaۻVP@9_*҃(/sGM]"4}4Ò]ߤ._zU3|n {ΔfY@F>  4]w`Ӂ0 VhkuMX(,KڃF}}L^]gIw0 ;*-)eM`ЇT6]m_ޚ/lNLEwb{@AMS6pQo |_=2uY@ Ї0;n$]O+zj H_BokA,:읞d>U|Om̷cKxug^E@9l[ڀԪZ+uPSE}Sd[ZN2^`\,IENDB`refind-0.11.4/icons/os_legacy.png0000664000175000017500000001276412626644770017130 0ustar rodsmithrodsmithPNG  IHDR>asBIT|d pHYs茦btEXtSoftwarewww.inkscape.org<qIDATxkp=\<. gE.F=5bj)"3 W !@E@KC`Eu W.D k] )HvK2L_Ng23K࿪ jȄ<)tO 7nq9R}q-7ޒL7tKk"0JanP:pϣ+d]! %yp\zuŋe8! c*!^ry].w=ܳM9@TI=dP8ҥ%H.|ܼ!##q\(?|ztBA@o^|˗7kOe[F]?;Ճm  ZI,w8qbر G`P 0VyWVVִO>d2p2:%l?0L+zb>Igvvw^C iAI 8njo߾I!* Ap>9~ lH$AO<0C`ki> imHt$|RB`;Ra>)!4n+O+X|Rh"+KZ|V$=_ :ZXElS`|˶v1% - sc.X|]g`>O#$u6Pm'I! 7BBonn^o7I(R\H+`Ti_z5(uێ"ۗVlVpv*Z֕+WV\<;OR!XSSB'(p\'477;,?R,Rmmmt0AJ` y}}EQ:Sq~(ӧo۹seS>h Q”tL"|ZG=cƌ-˲?^棏>j~}tCP $;_PK/)d~nnvX KGQ^^r 8I&L>}81;S`@P˜v6Oq2O~WYbũ5kl!h6lw]v||SV掀14 'w3L47©jժSW~*OƷh:ts˖-en{q VXXm#е 5ABp>SB&d҈o% ֡C:nݺ(##wfTzozg#RP0SĸY;FzOB dTC[.ի'q9^k~顈nW3MTy#x:+@%H!V:X }~X-Z=nܸ@7a>yǨQr=SA[>O"V7>{$HIV'L t G ˖-<"A3w 0`@ӧσճQFm˜OO8yޑw.]:}̙躅b =Q4 擢h b @*'%TOJ41U|V,_]vC`?Y=' *))yUM 3Ջk((-_СC?@R+1ԯ5']@JZ'JQj @)7B01X|RGkQ`5I ؾC &|RۺPD U'1<0dÅw322ny>e[,2AU|*ց!qT9a|V&У 7ð|R9|jW('E $v5)@NdzСCxZk9I=;li>) ҇JJJfɲ,M6S.>l0ז-[ʬl>)VL909|v20];-Z人K<_سg{=o6|p֭[6vvK 4ZM^wݳa#Y1-Q~QNת233tݶ0%/t1 r aSI,Ǐ >u Pnwֻ\v3DXU$*6o޼tZf$Ge[vnذa|Vlf3rv@eɓ'V N0a3{7okk /$Ii~t…z'a tjE۷o?r,[,+$Io~ԩS +t;/^< I,>VCul+ A @|pn!Pٳg18A2 )yt+++_)$| . SĨÒn>|0Uw+ v q?SN5°m1IFEA$s>$| N@$qǎN<ـ@wϛ7oPQQѫ X1m,b@]E (bCCռ>{l>G 0J$VUU7|C9|\o޼y-l>)*DQ^>B_O@/>h柾&^\\|waa,O vપ*t۲z1e+WYbSIlfC7]z7| B@4Wyy>smn>Iv#fR-QO@Afi78.d&OoBA[6jo"}~Kt G-ߞ骯_>pg6KX Fͱ@SR A:X AJ!]v0\cdYkA b1_ە 28@TD rok';ӝ,1Z%Oe [w|+6|+>AiŴ0HbN`Ŗdg@9Ç?vWK.i܄6?SVVƚogZ ~9|qu@I[4~B IXSSS&pKA-馍@DA_kkk 28N?lquTgK4EצNs@2m:ؗ.X: "4{C}E=ݔ-L'd}v"EQt#;lNZ!@cߑĦp[m;3SZ,݌^ st9m $lfpU;ig>@3 eXl: V@ؗ_K-b8|#τ`IENDB`refind-0.11.4/icons/os_hwtest.png0000664000175000017500000003407712626644770017203 0ustar rodsmithrodsmithPNG  IHDR>a pHYs B(xtIME 71 IDATx}w|\յ>gH3mY,[1  =BB$Gxv_nH?1-|@]yLi\2 [S_(Sc~ ~ÙŹŋaŚ1.8!D֓Pb׭k^0) p _I\Om SPBّ\X7ᮿ߹{vq07 {rQ?c!cmJePП|ɭ k{sQu.?1?0IBr-TP+ ՔRZ,_~?ls Ǘ2: vmMZY7A444{ݻǗP%ףxtZ_OG4c\}]ePA޽@eE$` '8F`߾}6jfbrlWV%kSgR Οtp;gp=3.8Irb2# NLnR!cmr em71%Վ4 Q֮AO+L9uJ$Ǎů"A l @ H)c1.8?\ 4@UUš8T!hTFu9]Nƣ1ι " 44MTB"&yMq L1٘I)1e\punv' 1 +) EI`$ b zζΛ޻Q:{xӦO^c^{vO5 5Bqt}oOZtTqovR]ʣ]}"?V0!mynoxQ"F$wmܸwN\}6em_A{$fD|q(ʶSfcvm>b@uZoPIdS njb` 3 f:Z/N6zyo!\Yj'nŒl%zb$6)fo/aQ8Iǟm'S}U^ۉ8˕2b 0 `ܳM) 3/rP[26(T(T34{VBFiQ'IY@Dn_Sej vi~јhu"}W4  W3SY ;` =b ؀H6TDU&xMsPf߇(!a_p*fLYIFx! zq55:)Ly}'#3u<'F8_|c,T9lGS R?`M?"yDJh+T1 D@5P)_fG]*vH4&i;v,{սJsKW8g:v}׮=w^4s8VN$nKOT(0A MP%=cpy ^yAk)*q(yE7uܫ).]/\5}%l8V0}x0f --)P v>5>sy{.V()((ȷlVɬzlzR5s n_vJoe(.kO3\낞u00(Q+>='< @5I?)?t2)a|ɉVYY;oyιe"T;~g.0 ~n (Q[9g+: T-8c~.ߺ֛RjUze]|/ mm_%&S+]ڜw*Kg뽽?kt zߗfWRBima9W/6<գY般 j[34R[.1LTe2W1aXdTD2 :w0ek2Cg}MJ(8yes=O>ܰ#W`pxN|pGcGc,\~$*7/8L^xÙ7tyKunխL5)²U&}p ])XB ڳgOexرCRΨĄMj$#5Ȭ:Tꇖ/;3A+?wy'^d!i1\'wI͒K%/ht:C+W~ˢ[TG"x Z'"=TJ٬=+KR{7.S64*4L-J(*j\Ӄ,uateJ#Y-JSs:Te4Lݾ';Y29sk:)(xŧT`xc뮭DFU z|-[41ebΊW8(L4z;{k.  bἥk P N̨iF0ǘ")w0Gc;ֽ 7cNRNd$ZH.ZѱPIh͛a) +Pڰз߶TL}~Z BrJ(zGs]>k|ef`\"H -PA{o_e뺻1k&.)[7VDX:[Hq 9Q9WtG|l?lTV1P2'?#Z^S^0a{2Zq" Xp$)mW(%D.nu6,DKB1-7\ ?E%y”g 8KÊ Q)QN՝A%(nŭkʒ sW'LnR{&1LJ(;qNN̆)Lf?4~5 ޾};v? >uj6ba0t"Oa*`S8 7["/e^S g,-6d-*Ѱ1@*+u*Nb㊮\|5BΡ/nΏ?nMx*gQUUז[>Yws cJU#D.߸E/]_EPD@Иat^=U}+C9?9iU%4e3SdM +@g`#ԌΠDy6K&.(JDιPk= !i%[ 施{n c-ǝ쇊ѕF2nS:*SᡎXА^JMli\(ALe7?&P& >ܺuwtHT* A ZxWVLYqbYҘB^԰/m?~!FrQKQ ^BX< 1G‘ֶmM& ICIQSmS@RXźr7܈|oQXɁSLzy[@b1 N&40dNá8VMa4λ/L)U49#^7xάs.ygV=2"eyMS&xYH`բmG^mK_~iIOZ) x* )ԭs$l˴%X+q"pDT]sV݅7>y;d' R PbRa\ ]e9qx)*DOk Ņ%%>e)g7w\gpag !vm !Ĵ"R&Sies7=7oI͒yǝ͗qp0rX%t:u9ٙ i2L- >l jժ'}Oyj\s͖ AGhͬqz_Z.I_w_W?:8J `Yq}._. TWĜSWjL5eHXr|0xw[w7LAC JUUM/xa֥kBTv9HP=햝<Ѿ}~u [Ǵi^r"gQnkUK-X<߷wk]yÆ }2}m{է.qtX ֋/8 UUU9{K K )$e%H$g;.~I+c H﫯fɜ%1EQ󣮏tڢ Uln&Ir"y?a露9Ke.Ev2ttc%z{zlڲ{}~giVZ`l\pkJ!Sι!Xk*kIOz m"fi& Ӱ*ܗ@ gO}6^4hF&++ New׼iZ,h7#a{ڏyܞ@y+^KA=_  lrɸ@12e`xt8Ed:k:k#}ms}?@ ^϶Mӌ_Y}FNzh~BfTY*ioزnVBm;7yu SԮ{ʪjϨЁ۶]m3*r]-lc[eŅՅ5BѲeWwƮՍ(8> RAEٽ|~,ǝ#O/?{^{}[OsWnSU]u"Y{ʅ B RJwܷN< b G[;! La[o{RX֬}p^}h;?϶XYj'ᎎū/yPQ@]~>3b;.]si~f\p4v56-}|?r|Q#:|/ߺu`Q\m\5\pa߆luvPʾ^xAyoԥ\̹`YE"O땻>H$+o?|<7TA ܂h;ozǺ=}p3^7 HgL/0m},9d= jkw@DD- #<= خAvț',Ҿp1 kF^>̇k6 @O/)cdiC/|+Xo'TT=i16tT,Ƚ^L͔^h_;+Ypy]9"mW={ƍy|xRK<9$LBLp IXΩ1F)M:\B`NС !sNM"  žE"N]5 BF K YnK;nq^aIa\tܜipyա_<=ǧĴP(Ty' ۶moiii4h Py;;z!bN_lH0(n;, #fǿ `4pz1C')a > $SgUlbw͔BӺd^s`pB!vmݱ۪󋝊sS//W-n|Ʒ$8 `oo5kX. Ee1&% px^RaWS 5v5~pW9vuriRh`lg*36TEMvI%fJ`X;HS“4@Gޔ(k`$(`S&v֒U氃9"J<\ӽWT7,]ʥ5Ko^~knu\r/-&$і~ n|f3s__oHI %T;xQ"9 3 f_o;Nd^9+J@pPF1* VCMl'ֱG8,%NXC>Obh6(H]Y]˓˙QyfL${w}w.ν~MKn6xY~<)yOC#ncBŸA9(LaH\pS&>W$̓kw1bF7TU,ŅX qӰ\9ϙ{1ι2qZi'\~Ѝ(%ԕ͹bPH5]R~p<Kuϟ\d3lfLcA%Ϳ(Md2JjQHT,e6?#-5ڬiZ)-]r5cX_]ca՝[3gAm3IMp/c0?kq4Tu&lyٰL[o?6 Ν3b~0 JV.i TzUܚٶAOJi! Ba?arȱJ~ F[tVY6m{`+-l׻_Ӵ(RWTp]uk?nFP[VsK ^y姹IDATήC]m^7tf ]]C-msE]X@.X,6 RhiLg#hPI.Y?`Ã>ƃ8#!ĦBP4 "31 + IHؽ$:>Yj3={ۃ=طoi:Κ7o 3 f֭,[G; ;P|RIU/RwgGA8g9 #oVudVѬsg<=ȁX,6 TW}s[Cuxέ?wT?e?_Wʂ>1HNr}9ս6nL@*Wǹ1˩8HC~~gUaގ01i}`Bt9 -WJ S]ƞnlٕn*T5 Q#u *SϿx5gB;zvgliA5 $~\,~}N(*KG/vyACq*S Fg4c%Xnrw#g=FR E;Wf~9TO^t%V+jܪ{P ,Bi@؝RF.!d 2׮]'|BuLu.Hڢچ J*K%kAO TQfjH(1+!_< Ose@ވA>뷮Wo.,׬Q>zcK뛛0s$L^WOv4:X,% q׭sP0JxOo_'oۯ۰Ck.0:v< _~;[LX&T]Y20?PC\b2r8D6R" lDhNWsׁCCB146pDP3R[:Bb|y߹~o~0f+@UFZmEX骧O2˗?JLbJ_$OH bJ۷/˲HeMЦȠ`yRN@~EQZ8Q+ѵv>Ryߢ`} xGufFKuem9)K"fUUYZir`qëT唎Xss|Yh@eR\-S&#Tr@ 8gu)1qBHڕ;)D&DGi2$.zZ{3qh@kզ_uӌwo?o1"S# uJqJpԅnHhJ(s'GId{gW4# Mӆw=iKIH2jxɀХڀHS`O>#s? ;kf* F-++ }ۋU9FZ35~+R+5B.tO}+V|# \>w7N~,;t]k' ?]9ajG+ dc٪*GH}`Ő(\W8pSFûw}ZA@3jX,l~hyeu@yJ>1H|ZpF6bB߄oo# 1 `&O,59I)u;Y^pO˧#Eܛ<՞ر{Ƕk[-ssS;n97m ?vfxNL7Moݾu.yXxOyCPux؀bn'#}d#(K0AT/nҭ9G$s < mҶŹSBݜs/<}@'seE@ۚni}kFF(={ 5zM-Mu{6?ֳhҺ@NZKncق 9;|jdVy8k-4gMKcb .7Md+^K\? ٻWL Dbv% HmϾ[o¿u--_]6doy ϸyIY::;n|ۺ!i,'H)uuD8_, dZu v?;tPZGW=pɌ%0i;vX՚[>@"qSEZf2J(u=yuMHTkwwWN>J Èo۽/Ïƣ>|^ż _~%yXp4G֜b?@3ԥc MsRsn6k~nl !dIW tܺ+_oqĒ|!}6P6:CvQ ahC>yuSA_fg%pv~[NBI_IibRk&iwJBNBc`"=lW.]øZ]DT#0F'ˡz .[^&1$)"(ORjH;~>u#Iq Ns#0KNsV,?$qxg WNܥȑ27bF,Y13bQɅ2FKzD򜽿 H䱢U*"s5 clSAO'i$*`|*y/= TbL5(('4\9q#2ƍ\iưqJL4 '%cgώn˚tA@a~\j7 O\'pF܈{ϏqKoǭ} >x0[z,Z>*4͑ѱĬ[a!#1?+!ks]sZǢ̏TdtXx;FrzmD*g}?~{WvNTٟ&Oz`Ѽi.+Tj(O\ĩiδ:t{/Aeeꧩ귯oiF}HE(/?Ga1@+pK 13@|~a;v?i-oƙg~pSB u+<ӯ:uz+)BO ]謹|_s(|h\S~Ep)T&C*YtP ѠANw#H.Rա 1xP>'T538 Zw*jJ }b:Ol[Ag^޼YQ0 Ws0oyjApAf܁Dqj< ?6/{'&\&7&fI(Q˂A0*pK.^ !\ rU{E6 CutַuTA!. sNmaݳAhXG 'EQ6Bx1m"];iUZz҂47s4ݷpjbmoY3)L8IXNb5眏[HA80ge!L$ h@ߌRi cۨ.culATHBh4Me rXFgR N ) f'{:rdIqx@C"iBxmɨ>,9SD@xtƙ9gTCsZ4Nr ٻ:L3mB)84$i^~3G6q\C'IO` [3 f_ $ H%jDdEfR-sxJG ="&42djQ0I: QIU4~Ntewߡ7$BK!9MWD jN, sp(AD86`Tx^pUQUכ赗Mt0zUK@B~WtCb.R\:Fm'7u6pS ST.5h[Q9ryw[u6qpM6ϟ>Iwnӻcf,Z*+1a6v53/tBE%o{z4R)MnƮieAP7nڽbTV<\0c*S &fvm)L*Lҟ㟑z5GPH JJm|3 2v¤wdWҬnk 0%3gVᨩO;mi1Tgf4@%3 fNtQFg͚T6xN<23g6) L0q;PR_3>4M&q3h,7 i'Jސڿq :G5RE)w:,aJ L Mj舖kFimjHX=l|n^B0 "}ÚP <@}qqR0>!GaxV_-2;?!_7d.krBLB@oo`t9Y0|RwP  #( ,S01q2 i@hփ=0̞3 o'UVk:.mT@#^vh -r\c }0vcr_鰋s>i\. K Nc+M<>OL4SGz$Wa/A ANTK}|O6c:c:c:c:nk}IENDB`refind-0.11.4/icons/vol_optical.png0000664000175000017500000000456712626644770017500 0ustar rodsmithrodsmithPNG  IHDR szz pHYs B(xtIME 2"_c IDATXit;30 ( b\RT1 h%bJK#ebpaqED#FETLAdw>K~!!&+r9=}w}/3fV0}9:3f0y=yO{5=ŠhPE>$It:@y+}zܲ3\{,=UgZrq,q"AI8 0 BĞ{|.CƑp\?Y_}Æ+wuuvZIb$ / r8"_SۿG}=//Z7_Un~WKĀ`ғwL [~sk̤8'@JhMQH(+/!CNօl~e-|9ev\c)85 L}h6lve]<`}n.W-s{k,:v$=rHaC\WGYY̐%)I&)YaҌfq!4B1g4+'^ydeܿWQw떦#?^X0}[~Wx/m[; y EBBZLH (8a ^ZP~ WM5jp1:I&uuYd$i¦77(_6q¥˖kho[|`RCf zsxJϗ{uQ9F(>RO\F֕Z-X2 X___h^xᅆqƝfok* sCr΃؃0|&*zEU{#aؤClY39+0駟~ HM.^<`xV', G+""mA.ع};^jMsKSv@.AFa@ƍWϙ=oak{碶BO;UQSO4qA1 4 Amm#GB8"rD P*9Z9΋B9:ߧ&K{А&HAP!%BE|aN⻁_֭_4'8GGDQHhݭ֒K *9NRDQbI`1Ԅ̞سu_1;ӆD0 Kf4MI )I1#K,i$NQT R VW!(a?V\xmɨOJulId!In2II5)LIx%QBmTb B,|3O>55oc%K I$YYc%J8J"'Eͳmok_l-P"B4>S#u\mn2V+M=vْywH!D[Öw?)7uwK&ʁ@?~mۦ~JJJje"Hܕ +R6޼ys{fff!v}0^ #+Дo~w~M|'#Fҥ`0K$9Rg%T; ::"em& ]ty1>xov9sdu-*Amcbb/((ؽo߾JRפi#FWkJѓ?O%Ц_6ۀ>$~B1k֬*** ҋ_ӟOT_l %'շo65S|@0$A1{VW_} H6{7.N04`ϯQk,|zwufng ; 9D$j/B 9 $IEA1s̔g?GT pgЂ$M #؇joX,T}PmZ鳜>MV]s?pō7-[lP 4J$%~#GV>|X < NgR9x v_lrNj]Vx`.YEQ\>a„yZVWOKw˄C4S@gZU*311Q'dmdddQ #j:i+=+V=*|*TXX;wLܦΟ?ݻ3ŕUf"I/5J&pxxh…7݁6WVpСF7[O}Qj|n+>>^;4`3fu~/?7n\?p۔u&;5 ֭[KR%D@ :ti63z i&r`ݰ1ϵk:f͚u}ԩ}3g{w^{uMn+ cc:vbxP&0x`eddM# }ذa( P`rrëWxeF޲~-^8O>4_֊/dԥ >nrҥx[frRoWJR3'No,((r۶mǏPVb 5;ili ЭoqOE:tPkZxm X􀰭5C RTRt @IIy<>(ҥKݞW((o44+"ڬaC'VWWoۤ^7k _A#UVVڢjkkW\m۶=p83g\72**CksL&YcFxfcFl5f@q-lvpnRHHYT NS3I@]Սr[k@;7|s#--m߮p>|xjjj5i-fK0AQQQ?!zKhAnjZBqݖր 'M-[ft56&&&_ɓ'o)**ڼ'N+ EV`0L\\\\ffx/;wnIlll8rrxʅibd2ٛ(feeԩfSC 6`6{Yt:E{.lo*m:%G9zOQح^B_(eJRu9{n6pBjժawy7xsN4wإq=#Uۄt1^֨T*okf)S⛧tKm5(֦ԹўĉsԩS/X,VoyJI.-ϵww ]t˗/; dv_t:aEKmSJ̒$Ier=X}Y{lk***lHl6oիӀuV ூ N7)훢VPժm_ ZHW5,k!m/XE9Pַo9555eup5&V͛{ĉyyyݏ~rcZ)u~!ҵ3Ֆ}%*J 8O%W2g8(V*OOy =߱8/KzxJ7TM^yyy4h^^^Z20+rgk z<jBeMkżVM{?:ǪHШ,`X6`P뷶Jb*˟|I\tt$? _|*1F%a6nݺw=sPվ_0/ߪB|H[(\dIRxxI&t:%eɁG 5 Ӎ7nlhZIRS^xzh|[ 04`w9nS\&N8<))iʕ+_11q\g3{pxISLw̙GWphb)8lPs0]Ti΁䠱ڎeʞ)S"n8FDQQ;vʋdW{hBB'gϞs,KݻVk g{7vӣCcq!^OkA5j Om֖ٕ+W\x6 VNg@~6C y(00pRYYYmYYY?Ol2"wM9Ns7dЮv xC󭞏7ޢO HN ~4,,, $$sWF_fZVf:QQQ*ƍyYYY'l6w[se2:x񜞨!!!A^VZt:](56l& ޻N~~_ 4?ws\\=(nM(d?|x/>/xm_5+dft6}IENDB`refind-0.11.4/icons/tool_shell.png0000664000175000017500000000373212626644770017322 0ustar rodsmithrodsmithPNG  IHDR00W pHYs  tIME &YT fyIDATho?{mlJ(MY SXX6X Ԙ\M6R6lAEn.,*(ghʡ{wf{MU*=y3=z^y '.]T1fF[(1 Xرc 3==]}T*ZDvm,oݺғ&=8}t{8~إ*"1y[U-?kAVksyi;w033BB^.fǎٹw`g2ÌP9rQ:::b BkZ `eqqׯpWUfggb^!ZkJmipb``>&&&T*DZPks& hJµkı gfEL.SUb^7U9@>\ ^a->m>;BLv2)*+&~VS&<Y\tٸ!#oWuvQv %3PlCVp!䁄Hz;y3g|ց&s"5D$v#+z=kkS@Z/?qM2Ep!k$$DFȦ $SNƥ\컿akssZf.l!jA! 9!' Z`KKKrBHo@*Wb$3!>CFTsBfy#ͤ44jTg?YAX~?P*yejmRzdzNF%q`3*wI&m?W4Bmiogڮ;~ e ȰgnݼEmyىO:.LFYgT}pAjP@T-6IIY%Ndcu "~k?>r3l&-Ih"٨R.?϶mTB}[U<9~ ־7I4 |H&'' !"ߗ+6 z[Z01ܻp';#---?8|===)U^޿vbbԘS"8| ]il\ l^Zl9k`>55k [c`:xZIENDB`refind-0.11.4/icons/tool_fwupdate.png0000664000175000017500000001207112707176312020016 0ustar rodsmithrodsmithPNG  IHDRutX}sBIT|d pHYs wtEXtSoftwarewww.inkscape.org<IDATxk\ymg$@ R&EUCOHD!H*%j" $$MA54nE R  1`\`.v☽̜K?w<33;<܏>c\do4| i &1=aeY07 Ll>N#|, nA5V{P} >[I`3 jHdNq'`}uxᆇxY6Rjq4ZJ5_spl'R=6/gGd)|4kfTbAxu ֒$l l xNMrܲ+@ Kx"eOm[?VLSf4cOUjs(3j&@M4G0PIxp<# ȃj*T 0=&r@#@Heeĝֈ+"R#Orvqm'J.,S WZPgNPc 6;ogH9U?dga _B1T5`B`G,i\|l1O}9qHGV |+.qc[I4,eԈvk MȍOMHSV@M}O?o8ja ~<=[r$1 F8": ,͐%g} 6zxHgCO>& |cI@M)@e) 6/DZ+Ws1}H#ӯf[$Tܤ,Q&A&;BZ}|j7rc;F#lEUQ' TOq7[Xbx=6 cRAMY=>I 9oM1a:)GR8}|Wo>U1d܄1)#ikX _u^?%uR:N4Z-GLxݽX>ww< ,!RӲwєfW|hn\%~eoG9zd;?F|xT$56; KHehv'0R,˲JSuy|b-M#^}s\A#%:fF'{yMKiFy+[ԨMdnuHqW3=ӔqB;2{C=cvDq~j4y<_q#qlO%:Hk9#Au>kRH%ɻopX* AB,">[DG#S=͸|my˓@Ħ׆P~eЩQ+H^;kWÒGI(UX׺1 UY)NHn\eQNPKֽ*ŶκZfF)Mj$5j^_'ػr#@ɲM'C^I7%ѸVY5/ry|n.] SJ5&PF ٴ*DչTGbYj5N=@B^2:zhϔPzy \9yR'N4)^נH:Ŧ.Ÿ:< q1TP[=%l X6Р'u :u<L=|rnf @m=VG*Ey!B :y/jJ }PKx9ӡBPŎqjr.A՞ - fA-.0)/9bE!zH*RTP}:"rcU^fbӸY,+^p\(qYKtMh9c[#Gn&VV$88b|՗3#]pq^`ȕgx?^ .WeF[Yk[GpC_D$DQ~ku^bySlgݗ … v?ڮAMR+Dyp\˗ 3|*Pg@-lZe;*J//cL',TGSm jf1Ap힬"I`+&}b(qg+O]ۍIm5mآpΦ *biEw2mj%'#h ERa%q F4_$-eg'mNZfyB.7 k^sVl욍\۱9Z*m$2e%tt,]nc ie oXnS1H)UnxnNIt2$IۍJBH璅P X{ lnho$X^Q22ޣ+PǀOQk>vd\ꚒڻTti=S&JKT3*)D*˱ 4ƠMZohTSi0= R lfwj 02tP7 cjM:7w?EL%5%(kU)-6m^}@ob`3:I8uS{P[s 0MfZsZx7bK`LQ%Y=&^-AՀ}wpr5jԳʔuR-< ocҽ9ys9w|/r'x1'7B__w8*z[xwNhr)~p/{o%Cpji(N[|w(:Ru9$Os~U\n\X:BIZ"&I> r nCl S`UOuܡDiXYPaa%=S 7ˑΉz21.tE1rweߔ- 9P->G[آ'F0y bu_&S 3ePEJtyCr5.U.NҖζK里J40)lDw c9QPDNa׽;5*0*&\ yHHJζoǥf^P$V;tׂUf] DBkķ*QzxI&Ai [+5KvmJ] Ƹ4]3hVaiAX|}J˖Ӥ'ϛf0/t@KcI& "F 9Aro [ڍˬVKSGKgB4.PV&dLG@tCWI%JQZSSJMQ =dw3H](D K}G/T9EQVA(]i@^~qM0 oK#R>avv | ފo[ڦ4'-ڃ/pY>]򢃓g=ū)ҡWtΆ4'u\'͆ 'IN82jئ4Ew"S!zŤ1ўjB>Uz*gy]uX+ךdAE#> AH%nq_ .MfDʸxȬt3#y7ԑEJ@^l\&M4Km^}Z1. 9xvlH4r <Ϥ WzA# ꨓ<*@j oĽaIENDB`refind-0.11.4/icons/mouse.png0000664000175000017500000001135613143462331016271 0ustar rodsmithrodsmithPNG  IHDR>asBIT|d pHYstEXtSoftwarewww.inkscape.org<kIDATx{tUǿgwHw^Y](jDyD"0fugDp= 0vs\ Q ",!BxbBW'$!+7UnSs$]_w i#y?Lz'$g&9%ܲXd^1 1J-'I(Qh#[HM* r"I !$d;0 z@ ZaࡐIe2<'T2 L#> t<>å2 SN`iQɥ2dHǽ˺:1$!9>r#IIIҵkOQLNcX4 bH?hii q`ACr㳳i;l6pliiQ{|I2;`$_:n8СC; 'd[[iQ#í[:[ܹs!1n?&CrXǏO$YYY.$I\h;::@#yG.D 53eׯ_g;x!-#8Krp/Gg0H !aM\'OTK1b|$OZN6ǚl#G3g5~) P__<rLo& A"ǎٳ^A L4 ܼyӯ`PG}9s֭[jA 큔aHOo HbܹhkkSK~'\I'jK9LJJ Xb,X@y"QDNn"iٳ .*A;N  ^J'֋ #H͛7xغu+^~eCxdb0. 7oʕ+yA+7Br86`]C-&&{n \KJI{ǀV^o!3!{ttգ---X|9nݪuH>5 -%E}3g,**8(2w PL@8N,^!ON28(')aި,c#())QK,;C 2 HII j0ƍXp!=,xʏ4 .)Ւc z1` 4={6ԒcNPs;Ў9rӚd HP!AR`&%ɟT IF Q\\{zsL2@3!a޽(,,Ԛi$5E3!5)=__ؽ{7}YY=FJ ;Z6/!!!oI ֐yE ;Z6@]]v]͜9Dee%jkk{>IM6!11kתv &5I$I* "33ChSnn.^z%@uu5PZZW ׯ_GUU***::Y~=k] ֒$Ix `54e^9qDddd ''999ݎ@ii)p8:=FEE***t:A+WDRRRgIXrȏͦS'|*deey=n8p fΜ-9._ \t 7nZVݞ@s&jT@r8rÆ AЩ,4VZm2Q4|` h pA$ Qфl,@Uw`ii)>C*F9zi Uhd#C[[vڅSI %F @t $J]s[Vz`II N'.<(I6vP^Ud(Hb苞 `I4_L$ PbZs+We,[LIJ$>R$Ijp޽udC `Av $ܷ+a7)Zp`#$I7|T!`a?<&IR?eVٶmݘ1c裏>/33SWjԩS46E%Ak&''c͚5xWa[GϷy;Ig1ҡBvܩ?3z܌ϷZZZDW}x#Gb^5knA.7{El߾]ܝ`ŪTTTSMLHHۻ#FVQy3fb;I[5<#h֬Y(,,bG%?8z(.\eS]rz3hСذajڒ%Kwy\n^mɘ $_w _|CUM;v,&LK7nH6:$/ueҋ{0(//:PXn ;wT f+$5,~g)hnn]wݥ+l|jwE6/zw7łɓ'A9oF+@~GjСCmĉlkkSIH~yi/ֿݳ-[&s‘A/;|pʒ5FyD nCB^^.eѽڨۘ1cޮ,OBs#]A`aa!rss5~Q_3f]w0x9޽[+\]VHkǻ԰qƱYtQi~g ĉȜz\_!.’%Kt) + DzA>}.^XM$U$HS|:(g)͵fgϞ%s=W3z'$$нڨUYl '~Ӣ]V+V'`Zit ڊ'޳gg"қG_ZVVyr*v-9|p]5:##I&2_%/xw,P3*5{ɷ[0sFk׮r ͊FHRӴ g㣍T ?B޺bO:$?A$uJ0 ώe-$>E#zG-IRe í[paDQo@T\߳l(NC 1 L:U+$hėOX%IR _ sQ ͦ{Π?>}ׯ_W _tJށڕbԄ_5# k In3X,? D˥,Y*Q7sI:?nEKY޸qo vfee7Ԛ&#mτ >c6lw!N i#_*5_I(w(ɷ{Ҷ4lNqN-a pHYs B(xtIME  AC IDATx}{xTչo}K&0ID0@Zڪhs~Vzg/_}j[kmV*^P[E% !Hdd2='+;dLBBYy3=={qzqz? 4+(B4ḷ3g΄$I]*c *>Ho.c0Ɛ4t|())9 n V k"ˮiB񼧧FUUeD0D~~iذaz!Ȳ Q dZ_\Bb9`%O+QP w,cX 觯]>P?OXnidE?f̘1r!d9Jq{@@jvx7xLA1ѹD'ȜOI.LB2B.`P6NZ4maDtLT L9+].\JX`$-{SUՃ;޸)#Π1`s&#-#˜9sVBp'ax<ѣGuUc ]O>={Ŕҵ0k(ݺB1]_Ă(H~yOX.9}՗ObTӭTU}zӍ- 1sM /DSؖJK/%+ !~ 9TVo7Hb9`h9k8b\OYS-!?ve 0Ơidyt\: O}qby8RNkguҴE.#Kz|غuA|TC_Ӳ4uww @7"lOP!XGy` H$I"˗/dž &H -3Coa0-c,s!B,՛5dyH&z?/ Ph416دR^ohQ CuuuTU@qS]惾 /2[wxyW, @X,&D}5-_x'HfUUq< jz;c4sV,{@!{h@瞄 7Q;gs8x7O$Z{ssXg:}xLW:.4BF3 !NXg1>c"B8uຼIR\z'PNXXZ3!cɷ|i4b@C2ISYo! FC1A !{K־ MgPJNsرcdݎ4T BG?oÇӰqj:f $ӸJg4Ms !.e(11|ɓC5f {X,k1%ǁkkk㡝&PAƑ<c؏F%IYļ>!;O43;vݑ&X,%#\{gLC7ܹP(ThJ1ǖj[3A8E@y*IRZQP[[;0 )dO$-r!N@O}}}vFeeYiWZ_C5~SdBPJo=g9!"ueuE nwSs $8- s'c-Hw$I.\( %#,R~$ו>st Kt!vL" ­pˉVk&gXL@455bH)]ڢ4% (orvn|Jj>(ΣC,@N 2e&':ɜ q[_:s7F718v'H 477=o5NuDܾq(Kb!-g)2ƂBr0zw꺇SAd%\3fL:uX.a5kp$Ic.`ikkk-,,=Ϻ㎏L\UQWbqk-? @xEPQm7?nVD7\+ˠ%$>{duX,";!D 8p\ ӵq!8uuu={v(BA7Wr (PX3O$I!鯿m߻\ܞ$vVB'I FHX iC2z*R}ê\p\Zr Z)FdGeeej-%ɋ11 cB[kQj<gF7$\.M֧x] jgwOO.˵M(͖DqUxCY08aVR8D'AEgNSϻRJg;{:E :Q$0, :pd>:0/4E@l⌊3mʮ2B4AtD"q:(}hk֬'|t:tOӔxΩ* ;V92ʰ$>*E@X?W:<Ĕ"|v_@O{ -#IKK{BesY 'zH4@eϞ=UY'd>\ޣ 5N?2J)t%s ŏ"(rM+?S@hy+?Lu*^Pr{ho ](@$MT a Bcaڵ[l,$6hlc(H8;q 3QҔ{n&jz4@a 1oE!Vlq ya9f͚/┓#tD[j[U_tct/8df.r^c}FM)x8O|$bABM  u@s[:oWCglqA$IKO8`Bft@Ñus=h;[,|W-( ӧE'qD]:!݋M~_BC{5M #, `gOc]9rp5`iȼk8DNopWWθ ,f&ŧ) ƦFF7^D{͆Ov'!-X,5A8z0O#}Mg<0TL&viݸq#dYclxF#`XS-bҋDSÈ[pG"=.>D˗[ǜ @Sω>#/> y3˖-Ki}i–\z&Y<<W\"R{43]H7quoɭH$H$r㓡+IRJd3M !9s9@yy.vvK쎻=ܗ\rI*4L`X4{E6I7Ɓ;_r&!D,PJgN/zCKlF)Sh4۷Ço6E"p ú/}K:Y"r@ߴ$_n=3o~jmw\X,bvNob#C8DoV^r,] >"Ȉg'sDeX^nqww14 hѼegF 袋2puAUլt9fQFbNRʉBccz}d }̈Ȳ Y%>TTTsL0 }|kDTTVl$I2ayp_AFNe&- Xp4eiDB*-:ASfWIg霪d"`f!;f<E4}S|8hYVs9ZY>4$YXj%hԜ+Ȉl^aXJL%%%Z vvrƨ3ǒ&i2imja|Q9'f/EEE{D4̈euRJ.TUyV5:g R,$fB X]Z1zu^1F^prU]]=llbۈi"0׹con7~歯z @Z*r!fBM8JP[[`0QzA<! 1UUс6\4Vi`۶mpB: r6 A `\fftڧlB֩bHFo(X,6K^ eee(++C(iBU_k?yq s5K:Gn&BYdFИmfNZ,1UU;-D"1z?@(u@1M  B [o! !77w̸3lv[_.:Rz!}~dz_4n0|ؿ?fϞ32YRhb}!%Bn:Xػw/.\yz` :eY>Rz !䋺 <`c,eqfb{%BFgB }?G42vրn'v] ͽgZ,Ax $;NhA0UR vi9ݻiZi7޽{Sɩ$<b}ۜ9sQJQJ?w(4}TUmyŬkw}w@ cjԠkL~<{GW;B~#3jܹsE%JV1ȘV}CZ=M\Ӵzmt c( QXT4&͛xn:PJ3 asR.Rkr*++^`:!c gH^{-<C+QY<鉯?o(Ӈ{.ixWT Zx4u2'4"^{X~(2P\\DGV# D{:v^`?|FT}AML>7nϙ3/yd6vrU5n=\61sG}cχ>`vz뭣 ƌ3Z8.fV9Zzc0>)/ SehܹB+z+|v?s \.멂& RYE5`.p ַ54SkL`W^y%K.駟 ` xG|qR`ۮ(J)Y([Q_wQX`e3Oʷl2TINf=uީSE[ZZvTtc[Qa\pr@ տ\[OEuqF& eG2wyr r9 \.6~ @|:O]]Gя~D8? 0 > v W|@01?| Y®]~7jH%jņo{XzMPZZI2 W(m·ݚMCM~L}(xoDJ?1jX. w>(-[6L$s أOB`nC(c,ԺzϞ=^!`*ش#RA՟'뮻 IR=ֿCoU0Hũ,௯ٕg?z0Fo(0#,\TwC("}ࡇ3A#\?9 /t: lK+^UUugݖBv$++4 _+ΚwW/e9~EQ=Hz|ӦM )ԘƆF,Ya{r:);jW ,, ;@UNl6[PzgqRg:0iÇi~5$k\-mtN>1Hv$S-lը%NC.*X,2O0m zX \ݭM:֭(]8ÇnW{r監}9 !,9s(i\2G\3>w𲂈ȥE̞["[Wer!H$&" 5: 軠c3kW=L'$`4Y@^N5k֝!03Tx<%I*NH$|u 5_1j8~ T\T1T.{#}TWtwwk@DoR5ݔ ݸd(з/3JYrmFUU ևIDATڄ'Gɦݺdgxb܀ds%b%!"\ Odv3ƶ0WM7v;)S `E6E8<kfϞoc]]]%ٹs1>b{:m+|' @7cgCЖtuu1dt%BΘ?U~iqqٴ|]'< 5rsT'eӾŅ Zzw]R-x T;ˆQF4M{EӴ"HcszL2)mB fZ1c2joBFID_VF6$߇xlB ;;`X\ L>LQ$ !d1 I|\_p5¬ͦL={:4K-^/譠7in8O1Ƽ^nwO6#~[]WMlOöpD"H{>_Ǔ3j,˥#6@>!d>!2պhgG |~ijiF͔e9ol;7/Ywq7뚾!4p"ʺ[E+\$B',.yYל,27{-';IvFNQAҴZ t|CQޟ.nnߥƟe$d7^ֵ@OXּQQ+$KLBβ\p5@D#ig `MLB'{,w54l ϫ۽^oNNz"il"}p޻:oSsLMLqNJY]1!dbY*^kO۶֒)$ ,t/*.*]Uyc܊:;8OXlq~ JĶ6u]Ǜb H 3rB\ҳeY^q9qyIIU9O‰D"joo<Ětwo{hA^5.@rOn]1JlM0b:8\XcPQNX8ninz{_EMMMFa/2܈M@L0'fMh?HTݞG)͚8"z|(NH$B6Ɵ]u79 mnҬD"yR%rl6A,HoJVd9¾dlk)y>ZOwIC|`_fcF˦]AUuNxR,^hEB|AD}Nqp%L7c>24LAl/=+~GU }88tO?DCQq7V>AD\nj 9(~VBzc/B!>TMs:`0WU5kaмP&T rK>`ƁʽW?/pr39~ C>#0́ "ƱzpLEPmܴr Dx䉡W$8›l.6D@: $#e)gtTYoA|% pOt&"˜0&ptqqIS.q]f]<eqYsa '#J(}fpf` %Ŀ 1}LL~*`oN:ӱaW: SzNYbGqIENDB`refind-0.11.4/icons/os_debian.png0000664000175000017500000002224112626644770017075 0ustar rodsmithrodsmithPNG  IHDR>asBIT|d pHYsJJ5ȧtEXtSoftwarewww.inkscape.org< IDATx}yT[wYafa}Q qQ%Ƙh4 Qci\1ѸE1jqCAa@Eaa{o]nݞ{fXܥ[:u)q:vI88q:c'm"ˎ)9~D8#ΐ~4xY$֊kD@* RL͓֜,іC0/2A c$+H=@|9y+ 8ϑy_0NQt;EH,RaF֣>\ZN|}q-0a/#(&`~$ AXӢg (5->S-_-Y4`b> 2KWY^ 7!G:prqktڄ3"$?&=Vy:} Or5+2!̬~esыVy̶`E@t OgM GYjk`gX;17LęmxQe$ Qzܘ$*ʠj{d-ЭF= <8ȿҿ['J4-?/@T: Cz@!4m/~SI nF}R09{Rxs.il+6|9gzL808ҁ@'[@|GkaҢ{ƅ]ҶSkο@ {pW6:Q%t9F^RBaꈱsPvQSMQF#.X=s, q `pR G-|O.CY0jػ@ 6BAeH|QP L7 ;Zɚ`}k;6A- Ԍ2j`VB}H{(23,OOIxiut+؇ FN0Cj=_{>JUЕ*xd{P(yySHJ1cIϱD/no{TjD 5W΃]-[@ܝitha&Wᓁ)OA? 3+ݱ1u(/bt>a @P0hzS0JDVGW4&Qm( |&()~Ę\M;*t#'-*T~u~&v.xg%ŸO;j9vIt߮7WqެS 0%Ǣrn7.c iŊ]-kb;͆9q)Jwuo5KYJsA : G3ɇ>ϥ`lb ߻5Tndhmb2l:k#63 ]֧ #$ȘQ)$*"ܵf 52;cu|W^  8r.QE77hm2cͲѪN3 :w:/:ylh]f޴,CIo2 F&3ҡ&:HԂiػ|3  t-h#?Vf1SQ}v:Q0F[CN{ʭZg6!iS @. "2'%֑w ⿂~Zk즵fS% |U-:[La `8`Ecݟ-`Vk#LS\mmxBD>ST@g x6nwЊoZo{6U#Zwe8F ~#e 6n7ա760Vՙs`W#zTc8ݶ@V<-,Jk ױX-H_GC6y]R9AnK(ϴnkݢ( ~Kס|hoTG[{ûHV͔q 2ߘQjJvB |gba-yj1-~11(KPk~p̫^5$mV]Pqidymlp2jKejű f>xѸGƞ~L' 1RXGϴGB# jqP_">lZ`~揫Б3Pګyk. a|Z\G"$n$bfVV{a#[4j(*`Gt\ې``8~$9F3rqF̳b0KT [heOY͖7@(ClNY,I@穌Vkx)(2cן/4%C$1_7Xj%;4Y,a>ji>JIUi=C(*e_ 2њOg.8seO;꓍xo(GC$02n6W_IA 1s1\ÔPbngz? yY׿5l궞槳=_}6pd"ThbﲾFܯMkG1¢HLQT7anԯjD)/̬/z#"_ǡ8ة0F` ANIhU @3+0BjdKR1Gp Z~NYjY @ F}(B7?w6u8^\I;K&}U1 ^|d/ ZZA#\DHy gIuPp4鲾@9C--ZjW w(#;Ф^i,tGԉ9о$o'kܺ޷)޵ 'uス$xw&)5U( dzb>L}hW'''nGQlbuK9 o  i`M.2)j+n@r*1]i;_ŚzsOM{ix_xR}PU1 %cxs8-{Zor{R $v/ gZJ-Яx=l?]r}ߢo/[~81UI@"Y탗>xshf+殚WU/Ϻx1bh_wis|{S>u{Ѧ|hjd;v29 HvϢVЮ6F&sC1ծ\=iW?dm$Ŭc$xEӆs(lV=h* 9Dڽ*1s2| @6ވ* @=`NX/}cV1_jg~-?_{0L 5USJơGTH J(h2R-ݔi?@rMEȃ=,P}_c+yÈ3+O ;^4dm&?d֯B%7cNu~ (2m&?GP@3Z~+? 6E~>i4%@_]q;Rw/z~I#c/H_+f#yE{f3L3(.~Z //RUmK^,u"5]Wot. ~vm] #tE0ޱ ղGڗNR9PNO>ho /eRH3(3eA6{@$MTm$  Fv'Tm6z<~(=~m}^1@lR$\+І f5PN% \v^Tؕub Au0n:T4F R}gZ־=p3;F`6$@)zGdpyԋB`~ )Q*~2Ʒ;e7֘f|[_fY?vKǺ‡ᵸ}I 0Xɻ lƟqݲbGӏw'?ځ4tA_IۤL3ŷD=r4#N {#w;m&.y"PfO LЃ0_]ޚaM@ |bzXl)tQ)kBQމG+^;$O/KzxKOv$n|K6{)"p?u_ІZ#3쥆Ikfv=.׶Z~S45 {*V -z"dF(!g#AsĪ|uDyT'PTomA^nMI>j=,c?^lUNю8R%wt [z4fg xx4 \x MuU5E:y* hė:U4#W@@H~sĢpO@zYśJ5u8,|"{PSG#+\5}VU0 IAl eK0 h`vaWg3v0Vz9Larƨag[>8hi//|߮\d6練-wY-k&S,L5}I$M H/7d>hjUJfqʽS{4?r._ĬM+&R6fI,:fXkN /' 1OۜGmL6osoHG;y&/^ƪ Ì0OR WeSxjhL2΄[Pl!8=yoA|5>;}71ƂOA, ƹ0A#1׽2yض"ͰPqK)F7nI$'{(֖oÖq"xj쪃p@Ccv6yEA i~o"yF>{6p3!Uhn`B"AJ'd4"#]\4}Dӹ@P_IWx= "^ȉO@y 'I؉(ܻ_O&\:!xil3OX؄ 4at+iӡ,s%wcڗυ7X$k(k}uhdl*sEi?%fG-09HzF <A]SQcqF߁K *]vC榥p0F?Y$AN<F)?yVg@!_SM/>J|]LȢ;ڧj%D`V6HDEȻWpʠ'h֖UH;p2R@ԍژs7W_7wy8({n3,m$I TFĘ m4ҨFX;w/E/duPLBrA(ן[*~eŠvp$ @ic%|_~QHصX#?4L{~#?}N[& xOs^ȃ~p ,Z^8NVoSO&W태MĪΉdR2v ;Nn)hAfR|Ͳx1'~Jg@8gsoLd3,DC0 1mWg`zZWWЪr/ڴSV 7up&%L-8[i؁t,uGR692c8RD!Y[XKcvi86H#PCiÔ1% {L",vh[Ok-C|1M,@Әd2; @<㜟"b=oo.k"A\6L y_2P$M퍠u/sӥ<:@v\uvIiS=}gG߾>qiM'I@ ^gGR8Qw ZKj9727vö{4!S.]N0?MS).e>AphK3H5OMv-I@ഏ/{x Ѳj#H]| *=VrZٽ̬kTϙlvJSZ$g~G7"e+&P1nuT@».$3ZjT*At"ښBRi݉@ QF47,,YJ.ۘmigR=!S{ۜMZjjA͡ yT'{.gu48@/2P-pݙS63uφaio4lj@H7Gy8$!47j?w٧)J R@v@x>Ͱoě ({ ? Aum=)A)?vޟnz{?R$&O}\=AN gJĢ/U nL# nTr.$2& ~탕u5mw;QC$ʣi-L 7-Lnyw5,E1D/Ex6ASD;T!Zwɭ)W!jAf9@IDAT(qD&Ҹ] XiWtI/9gژ)HeCu N/K1BHsޤu:Qf~|`mX{ {"p4T<>>Lչr/SEwOjٳe?7uB:Hihqa`@%{[esk&{ &!.9xO%7t H99pW9=aq[?3Y|y>5Upi -u _ANZKƙsGFPŚW{H |w%1NW SCoPf? xQlC+顧׺sV:?ԁ'D1A]& p S152k#RDܛ-b]_YkC^r%;X]_ j@as>WDsrz;m>Nϖm;f-W:7wE%w)̈́ {_/;ŗ)b-ـc>6|KwpܬueOĢOPkr $Zȑ @U\%X͸C;)Jbg#`~[Oנmਞ)t;J5W+#Bu흴eOFcLQ n 4+ 만NEBg Wձr^zgt]4g-5zi'z@U*E* A&gvڕ߉.߇ciԭP @7v:IKeG8"_GOKWΥˋ8eshFTɮH d+Qh?:bP 8TgXCV~#d$ ȗ˿ʽ^i ;8%O4pF^VD\SJ?^1&pDKxq6GgQGG#dh\r4| Ԗs8Nnr2aIENDB`refind-0.11.4/icons/os_linuxmint.png0000664000175000017500000001414612626644770017707 0ustar rodsmithrodsmithPNG  IHDR>a pHYs B(xtIME $ 'IDATx]}xTՙs$ WB.n[?*vim]ݭn>-V J)bT,*EGZm׺[~g-TłT!$d2wgsdܙL9O;w}yy/C9C9C9C9C9'iѥJ4RIGOXup,Ʃ=sa8m<@`УK5}%  {^A1%FZfޯB'\W |Dwc^AxeY61H„y1YG!M:t21!&땶GnePۯ> nG<-]3W9 4 70BWUN:L\xeaE_ δCb G/rY%b&b& W~‚#o4L|H5q['IĘh@h3 [hL6m~df7.xZNO<& 52z?e 74%,gq]m.GV\yihM&,St˧JzG2{I\s.UO5eYJxb`um!cC`l,rJoWHbWnr8zLo3:+q7 ( ʍaJ<\@MMM(C %Y@r!bB~G\.WQQ9O ~:C^=?'-uAPN ;84Me3[6ZL2Bc^i+6Iո`u' 4]䢾vHRrD̙!_ Xҭu6 7p33iNsPDu2|%F: '?gˏ֤LKTQ0pĊ ueJÄN@ԥT0ef(0KEjgN4 iZ:Ԟz;(\1D@e/lyΜ}qBe2sLa,Z.b+eI{o|s$b*R/+x ("cIhAR # K,50k5 TWBe)9 [uKjPcwzm7ٳgXNj*ו>tZ(78-# Z='r?׀~V2iL ` %̚ ģ˃:WHܹ73p¨" 3t]+V+lDRjbG#gzלk/zX ̯Hm?߿(>֥t)0;Àޓ9ezqr?zaz@t޽!=39{WcXYlZnOtXIfKٵkW=%9uh .Б3'͗B(a ZqlwfGafU]v4U-4f;EOwZ'p;?0zBŀ5(7{#cIh]!kYtvk&)gKo@& M m$Ϟ=mj)ls*|uǞ~ȋ !՝L@Z[[Җ[.\8L=#U„8a(7B{]Ǐ]H0 (ݸзH}̽Az5R8?DbU׋18$o4JnԂ.6X<=]pQhmmmذ! @~Ѥ[ NY,tvuet ZQvSlq۷w~icS+P^O'b>Č):oHP5&JfB#"dų'nre/V#aQ1&ͻ Or]A7+[ mWĽRwģK\/NGý Ov1PŗNŔe Ű!fv[pm۶#0F4L@ۺбQyvbC_HPE.Io o;K *Pn |cʱ;dDj]p?N@ [4V5,Ӫ|rwcU.ȧ ~Dv1%%u=UU$n~*f@@0m$y1Ga \[,gYE2BrBk?޷gϞsLAHP54-/u?Wot`.+\PաF-Z4))#P@@*e(H@B5%E9ͨ^^x܊~@ӚiQ# R!b _af>O-7ODpPΚc;s"_g{FD7A\ e˖3qD%6F 'V#S :t 3f d`ך <ثPV @7=z]N5aL uht@`A=w>֎Y {e? 9p=w"p51+Dj< }ہcf2 Z ;Xt}۷Koo_5{jP7l8aŸPqU1 |rvEw+rl~o܄AԊ\+fN;uvvdA\xoaᇤokwJa:lBf吋\I3?!%}$cWj-1B T*Ga„qO4wuu4f1\@k2 't}䦖 hŀ0L搜5H_Lb2DtQ|4@{'Wv,i+Q=(Z Ǐ40D]hg#b`(͜7^K8s%8 4Mh8Xx/>|8a߲hѢښ"SQQ@8qBH23e |H$m۶hllquj U d2oIl8 yJv2& a|ݿKeŋ??aԙ3u1DtW%pϣ@`y P _dd6yaHps p0- T\X W˲,].WzO HPձ.(E}>_ܾ}ڹsg Rs2R(E0@, p @PixwX&ɂ6h5`B0n[ |O(@0^-1 BRb*ώ*nW3#}T|_3ÙeaWXAqw JӗN#D_. ki@LMF 0Ug)S0F"eF&KH֠f*U8èp!r!?>e]GS@IENDB`refind-0.11.4/icons/os_kubuntu.png0000664000175000017500000003111112626644770017344 0ustar rodsmithrodsmithPNG  IHDR>asRGBbKGD? pHYs B(xtIME:[ IDATxwt\u?Wz#A"HJ$ U"ٲ%Y͎H{9)gcds69Y$Nq(9*E($H ycüy(E߽{Çׇׇׇׇׇׇׇׇׇׇ׿K;zFT<-蝾 I2&Oi.l25,Y^W Tk!j7B]0+JȆ1L 1Gaq3a70@|1HusC!<)BH#Dr dR&8I<|0gͲkI&ڈmCw `5\%Cp#y#I<|so$O G(XI߯nV<N)BWl a#  ?Ե*?.?ъTz h;%a.|7*#k;us8 JP޽<[&A~']2@0^"}'EF ZoyU{6PY8Ҕ #ٟлk U̥ﮦA\r<T~URJ`)_%C/KADŽWZj3heY:^:R"3(0Ed&2Pxj0}%:OWxwB-A c\8|U U$ƚ>7;\Q'14BWL0c[j)dJHMag VG!AaCyb 'H/pXicj~(s1҈>ZDlSMS k)Tn5%rip_w,* E( j$mguz劂C}MؾB޹w(0 Lkv #Bi T,S L1?.^u1pN]L1"?Ma}VHVsT4^"XYRHˌNĈDO˞a1 09 hKWR)95hϋ<# Qljffҵ{dumZD@BiyYNX]a7n(nc<$JxO->˜7j n3f1@<[yGbX`yk†7&L3gKŽЙx ;AQ>R-`Th-48̹}g753w Di/4 \^;4$8܀*b!e1@Z @m:ʶ@uC uI`3_'mF&}R6ɣ2yA0JA ;þZ))-T%UabsξC26.G :HmΟ\d4OAsMBfy1|&CX'O@}J>q2u0ul[? 7\L GpW/_BGks!ڼ ߽#={a\RbU3xb"<1v]|'l >,OO{)~ ݦ37\<e}trϗ%dyѽ TL+6kRm#!RDZT}s.z;TcԮ{[.?^W7zW"'4/jeRQ.Ur(515gk!&^g;\ĵ6Fc|x+{C>i JVNC8#PA|+Jz3O.&JO N$&283eu룔N3B%Mi/ZaojV|M͸}WkKQ2NZ͸N/3ʦ:Zod4afLsceA|G@4;F>0P˚mu ypZ&P}XI~2O{XA D0}WLs2ӫ&4TfGǹ25 ґCa:L""7gRBQww{)*Vrm<(gzUe YEFhOI} %2n\ k<RHE*{9/дtuުxEkyP< R]E*Դlz#?EdN xhRl2fHJ=r`ӯe̽k@YjeM5]Fێӧq{t #27T) jr3n_Cy@g34ʙ菰f!%e!XEz ?$'h=޶$7hen(cg%:jOUr3v݃@9W@lYŎ'8[Ӟp5%HI\DB{y'Hz͍C"tQȽ WhKpdx5| 4X*tIY}/Q*m\>){BY~7_o{D׆'޷9N2ƈOe;]ϩx[R7t:(c e7R)J؍6r˧PD^"1۷?O0#C@M~gW鸹(D#C$dI,cRMOtQј`֍(rH{BpVO#h**~Mo9@|vpUIkvf3[V\_汯ͧOJpϕ+Xeg|ˊҩyQ4W}aKEYM՚ո}2I%al+/Ź~RJR=-AlXO V&-;s..U_V!s]!-d>DAln)"\F <&5{;gD ?k~4dBݎ`ʵvǍ>º[w;@oZ>XP.& Z?8\sݚJuAWkWI8|DDs4[ E,H%;P/=g67smp(Bbum**,L\ ր46Lږ4bHci#!gd1(a`_E%RZaL"ݬq:)@υ)-h  rW<=L;om7QE]ԑ2@Mp[RplNqhn3 n4wL׼M۽`hr_b*@A FJ}HGf0Vݶt b1!Hy_7*fͳF~ha^NSٴooDr AR'g^#R6Lp$}yL n`#uB@\+Ƃ!i=[&" z|dB9pird;]x#^:j(iv4#hU$~tUk0"A$c ;T{3sS&QV2*4i{檽<̞&/H%Ү<A278%2%^?k{J{{E̟OR:aB#,:x1G&0Vt@q'nlHo^dZr eN9GXAxk9&q2 )It9&prKڋ)/hF!׼R C]qq󿓿7L&4:[޾)7Hy}-.l* +E=*gߙ"ws\-rX>%9@rT#ieK4NYT-eRNzO2b8[r!.ۏ3WLi&_w@Z9Vu9NAvbHmFPѸM<iYu|R@).H̸93h>Td4z&a|:ݮ5qǙ 13SAV̓}xTD`(i7]P2u 3# PTG&?4F2BdyNJdJ{wtDwW'M(CAF{RdIXI^,ujSX[IA.?<`q;2.s$QxUKoX3cyObr+%1]+wZ~ԕIBMz70͟dܼŠ6`%:SA160Jl eg7g^vp3o^Wl㴻t D*Z6ϼg|Lsg2ӫIDAT^dD9/m߀MSxDtEq ɸ`n\#4av͆-<Ԙe)fFb9\#Ȯ,Ts΢+:)c ߤu4tE ,KgyiZv1hDD̵Cun`u9Q 4 8H#{^ sJQjQ&zp=whS#~-&fR.N[VE/._XzZtçO1.KhުrNӹKס6oBilŕPh8\1"3oh졕KMD"Hp>j]D֑u^('}=Tj) si3eUI$'ifE0%:}k3HS38IفT#_]Hq4.$.KX%#uJ6?6ڵesG0V9/ɢ v>f=+ ?[`m#PNjfF:ODf;;} !dzLڼt&~GXw3SY9+WRDBysrA81-Hym!8V"eogL!ݫN/e}nf3L'>_85hؠQZ%;#$:&ft U“7tzL_zp=/ DbJdjCG=XjBH.kq{`m)I .&S>LExG/oKq{^3!:'O97>M"Ay&0 AhDM2!`$f.n{'Ȯpl ڀ4@BQLb~vbq5*I8q@a?]r'OhitZ8eK.`$pd7WR]yŷ4$%N=S[Ix20iZͤC9:li >+L}Yw2?!a4N 9$W93s@=oq[Z2 P:-$cЩpML/h# <: ∵[1x 8{;º7=3̚mQE8Qr'yeKPs 1n#k]ԭCsW,'Xy|:̉ӻK#ױjӨx͘!67<4esOg~",.{7rG{̌\1f4It>H<'3|{" zf( >rǾoM!~`kU~Shϓ%s$cqS?[up6pNl_yow}AhQ7!iL4]$m`+Ԯ;Bus=kLU P_av[)J?Y$jS7?޲_YQvѵ4)]LJ=!6Io]ʩs~r;*;Xn;`sI X!ZM*dگv{{:p~qėF8);-E‹YaTރw.T9iJ$rME wLѿeIBn7LƨZ[ބZ^P %Pq>Q4G5K ikOv_X,nоY\B՟D'QJ3k`xIђ4o_,kzxt~mfCTd%Q,y7љ4\gkK HUxBdr KMÉYhĬX|oo!i3Nт}g7_Z¾Xj}ֈ] `K2x|=orD\fŬ i{餛cN?E۫; * ڜY?Q"nY䔺m[8p}p?+<{);IpA4 -kᓜ黜}{޶36e,|V6L:$zm3'IK_Ii?D ҈- ʴh)<~NGQ>oQtxT6 /䟠ݜ=HfrT#1v6NSڋWqEJ$H(g4{ v3h{K \Ե3\D X|~n_և[v/OI{uܾp'&9]Vly%W (ST6yP+)"or$c!>7/ rӧ!P,R/`|iɣ#x6uѷ?\etq%N^10ǹpe>߇5ovF_hIxKYm^Hຟ}!f2 QbDg%A5k(o;(#Q$FN5e;΄+P & ơ!7x+d@JUob&-4\7˟0SϜ-h1zm='I\KըhpD>f#=iLͱ]o2p(j|4㗫 L03_F(w['"߀|'۩[+hUqD$ӃV>-Xyb٘DΫJM\Kbh)S..zej n+N|"NǞ֘@ܨ܄+)R΀B'O kBu}!\yQ>+g5ބg9{.2b3( e1AP*Φkhx3BeX'%I D9+Shxd/S̞L-;yMB.QgBEF<\:5Gl~14W9B3h>Nіu*V~^!ߛsRJDB~8ܘ4=n17<%c{]*'P xQtwJDNq,J. ̐uvfL i̛:~Wο dgbfHFt F{{UJo~baT]F_ 8?N<#a+y1@QΒ V2 =@uIVEU\ (JYA)V?K D7RDg3=ts0gV̪.)B۫ye%6F(7W;0 57鬺 oFu5Bx*=+TaD@^ 8{1@>FPmcnlj. yΊ1DzOHw: LJa%dб(f`W[L||E28j}MNFigPKOxMqe}]1N d*Hr]N1)rMA/md\iHF%0GϜ ;? pO~P7ꆎ⿹IENDB`refind-0.11.4/icons/tool_mok_tool.png0000664000175000017500000000366612626644770020044 0ustar rodsmithrodsmithPNG  IHDR00W pHYs B(xtIME %嫆-UIDAThyl?of]9dLl0l7JӦI$!"&QԨ i6ji5B!JTiIiZ2p`S|bClz?<61f 73}?)7DT_ Z\߭z˝S/g>ʰˍB pXˣ`O,vİ4+D $z-vClEp]+tZd:mUW^? ȾB SRAP^hZC3Abʋo&ؐ/g+lI4$POmw!CL6!x eʦ' E慨k62qc<=/Tv6487_4OQ  VO6GΒ˦,!UAH+D'țjC)۔w}40Ā0?sp -0(ŷ3%56о:`fa@3o/>Onݖ f>)Q6 T/S271 ;Kʑi@  u-艆rwQde6A! Ǖk"B)o|GuCeEP_و ft$,@7A/>P*Di"e.1ljs6`&B(T- bD,U&P[-Mizî~gr3R]b, T^\(ۛad/;P@EExgtrjPUN$&c4siq8!h 41 _;xJ5v`RѕCf*n3UϮ>prr#fxP |A ])RA%xﱜ@J0tzeq/"(&CVU]Nw1sVRg,gQ!+E]mMyT,L #gZ)t{NjR1{CKp9u%հU>ȣGƈGbL˪Zۊ? ,͒ѠdęXh<n=[^jU gs\_N"_X=1*-Ckj ̧S߷,Vllu$7 5>WtȎZk`&0.w5\?K.ky[-EzW:C#<WBW*1Thj]ն; lh&.[tG2+0(h^ڋu͑-=a}h pN p.k 9v8@:yF {i0uIYJ/KӴ{JOMӞ, 1D=6[k68≤(8xxoOܕ'M`*k,i iQ0p 8 epF~+a)> B3M&R3ܔOQ4XzIENDB`refind-0.11.4/icons/os_netbsd.png0000664000175000017500000003013312626644770017131 0ustar rodsmithrodsmithPNG  IHDR>asBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org< IDATx}wUgNu{ge;PD@T ֐1G%?,h,EE5&(Qc)DzY.[Nq{neYu?s{93Cc\_7`}NB @@o ~.3,A}#g 1OcУ3 ~`GXw2$gCoed~=IB@3fXjkkc[[[[>d^FaaC ҁ|:3 v<@ 0g.]\2FW ѩtYQfI>Լnvc~IVIwՠKg!N8hoFM'Ƥgƚ"\\ $,p1'BVS4Q(cJq翾)?Nv>#9Cgz뭑qvyYY662@4ʘZۮm]W56RH u@_=3;ktLnV9;eYviId@+1P!2{TVjڕ#%oG^Xᣁb9R/%3tkgٴim۵oϧy0M$>ӑ1` 5Neo~yMs_v4 t8fhᳳ0@! H|NnHʠ20"G F1kezޭʫ-԰uwONiЮ;|WYEBHATIEHB]oGFl3$pL" G`=(yBDƚZ-{>nF  !ҡW3wp#GSYUK[Z/˴1McP9@830@( Lķ8E6cG>g0cc֎7_uNk~^g70"'+k Q{ǎ֓ kh 2-ZxRଂ"xm\Dxϥ rW7PR ̿@TE[Wuo)s7p#<37a![wzXz"XoΥ?|2uNm GpQiW2BgDt5~OVMSVZ"'m?^_ڦmiݳt ?{?f>3o#cw/[ZZoYH6H?P )"!BTTyuҁwY驁WZ@7B@0'''vޝwn7lYG|aBWo xbr~Syջƣ rw"g'8}Wr@}~KWk.j2v,$ibJ̼C˯mv 13 Ӑ|1Rhs)Zj]Q\]A^KQ:azdm_B'ol!] kT3{d踸Y9wozJ#LBB8#1\MnvMmaLQfbM63g,/(Su( emj]yP$궗~N fSx[w.Uv{ִM7ySopWTRhǛoJ'TBh7.r|,рpp\AhP vwUk͒$4i QْvaH `#[:jKlCHeHH Vl8Ph) e1ER>wTz4W5u*:w6γ0rw%@#ONK{Zۮd~&y1c`WݕfM<1N`K1ZHQh29ތ 1`vhmti%-rɎJwN8$Mƨ_p0XKpҦWI@G|`ĉcnMVkFsCCվm_YI8@_AHMc&$͛`)jL"'*kjriG ;j.D^Jw;[aSeold\ܕk6oLF ?7tZrQ_R&BFTݮ=R/}6mU |+f,LSrsJIK{G\͵;Wz❩ʧG0SRFa _9BDI-mCuӺ"GBE~0f8ev =i+QQ魭RIq;Od'#z҈;S)<[=Zq^fž/:Ez!,3 @azD;kmoߦrd'$;+g+-lx[CIP!8>$R⬈ɚ `v4'G}-t/DѬ2ꪪ>YTugҊB֘ qM.Y*8 ^{7GEA=U, [0ئM|E/L&< ϯ'Kfb 0A`2BDF5doh w¶rEG\Aq i|3H^)p5 dxEE_Xk;;^G30&iL AјR!QBj8`Dཞ @WVp Q5&Ԛ۔Dp^jU婭hS# hR4y1vIdz"3Dc]r LxʈBJ@W;k=Ƿ78x?2CWadAKFhӝV 3g6M@5JJ|"ӳnj=V--?/xe>EKalW+RW'GZK%ncȮ&t\pL`dh`4Vp}3!oܟMU#$A4YnK/.r=~5]>ycGFW-ۙJ3 lO+ $c0kt6lqwí=:zQpWFAts Lј]U߶k /V"uƳ;S`;W=B0TdyfR J)xQ6O_+s0tPjLSwTص|_15h},uoDE:{oeySbD)IzWӾI ~K/36pW^[n|`q'n[ZjoϷFF&dز.<}NM@)c*Z9غwHw6at|8ק7+ R)J!ΧMq9.}ܹkJ>?2'=,kL!=G^ 0W8*dg 1c, YQ $Gk_wݪ2T ŭ0iMcW,ס:x(<vj=looBiQl.i{Ac׹K iL}xrmxejL6k QziZ%t$N8g̗kSH*ypU?۾[~w p-:=?scm6lv{,ޘ$#))]1_U:w 'NNT&sDPKE[ʝ;ԚSUq5op AzYT)(!,qw跎s9`c*OcnMY:ߣmG-uU#t {:M*:v`pjjc,y瑚v}/]Q]YfS[^w4t=Wgɑ*wܑEQUjDu#EEgo~ |ށ3FŌnخrfi@͟8DY?xj}@+|'#%M7EBzܽ5UU5X7=Q4=t_a.{wPd, jv]Qxux$$/c̞5J!3-ƫhf<}Fe3Ҿ64¨3G KzTʵ+w)5;*бhlϼܥ<1f8LY; pX ^&pwfzI\.ObbuРAqqq !W\tUUU.2>qqqE}&EG-ZFoϬY2&O|n\vSS .|GZ_[9s挜0ac?sС5!C-0ɔ#'Ss\bŊƘ g}|!]22-\_0limmx ^,N\|v]@SY@͛wnnn=&i^l߲eK_~cLBW~D}~[} t@^۴?JvDpk#PؤcFlc: uoCo%YwȑƛUUZe6'2dɒ+**^;"{xɜ&n 1+N-nҥ_VWW&)Fx7gL-[s޼y͡b`o5*1ѯ1@pL 4bi2t0`5@yԊSضMm_vYƸrƶ^x?1}A؉`3W_q(0$%"tB>.^o$!I(Z˖-ۺ7&iĜ9sHIIEL m-A:a^rrC eNh ScgC.vRڙ0˥ITc}4ds}5׌C S@eYc,y'VO͛cmog!`|Zu[C O}c2^ /p$YBqxpu5C8LMAՙ7u`1،1ށcǎU+6mQQQv!b[{?edd^w'^ >7P}ꩧޔeL!>>:+5&! Q/g;'ZzAO"_|ГQBt"U':Gڦ!D$ !⻇_X8jȯ*GGhyh_;"BH2!$G^}mz[oz{Ң+Jyt~>yN)'gj8Œjkk+@[vm%z՚O:mڴlt0qBǏ;Ν;āɤqu/]!UW]506bpW[6Vc,|׷?@_ 0ƈ٥XcTJN1!+QQ Ι?|\(64ܤQfc V`U"l Bt{~TPYYXj͘={{g#7Q}F 6n) 5%%rt niջc77 :Pi5^cm~*W=mqKb{/xk!)+V|kӦyg-tHeMW2^> ;P'k~ǜ3[HII?裷+G /g iԨQXd>l40P]g;Te֭U7ex>΃AL❽:\8yublStYJ/jePV<"O&o-s]wxԄI6Ry3[jcUx_(LK؜|&(ll$:XƘҲuӦM_pk`H<Ë~aÆt>gܹ?~|_n/8Z x]:u 1bDjmmma?o }㙳jӎr !>:{tT Ic[B#gP,݃@1e (s} \#%6`R2"ʃ68--풡C2d/|,N0cyܿ5Msqmw?3+g̘1&Yw^brJ*h,+HNNNBнpOt @`EɊr3G ē7L}rk6e!@~h"o^yms0Bu,Z`rm<#pƠH3rӢExGi>|xǧ^nrsޛ?_ Ug3k333\KMM8?VkUW]{v*™ bf:TLVG( k3c|fHV>ҡ~_*eg2DTU8k+45=xmyy>++k? ~ w46WqqqE^Zrmmmy>uԿ7Iyaɔn,P\\܀ B8U$ԃu70}rrċ_V8ݲO$ iT_+" 2H^M!:< EBgŠQUUٳ>ŋ3ȱՋ/:LAp(رh/Xiii'1M< 6xΰ`IDATѣGxOֿJEEE-O#Wv6/7zqY'%WO,ďmHD{8gW{bdK} 1TUo6lإvΠpt3$?ӯڵ# `2RoY8= `I&e~C}}Qq2YW}ʽ3! Sfgf̓1I 9ư1KXwɜ*F~ 69N&ZdРAJb~m Bҙ˗K)3f YY;:֎1M/~18))i^vY戡wdOajx / uwȴ_o'F&rGqѷ"DGGX^FcjCGg&`iΘ1#i4m4nܸk(6I fUm(U48C6mڳE^__ clsӴUڍPEJ}v᧫~z>Oh35Cwщ(%~ 0d2uf:뇌 Ƃ{4Mcxl6nܹ>d$,B_`]vEħzVr<ݵkעEd:yH@#ƥXG'C%V b3|<ܯn:'B\~էFѴuCguPx]s3^d- cn]Fp91&ݫH\=[(82ȓڬڥHWj]U#.>EN&y22>>vjk m` . -ګFW3]ՎzYnyt˅OmJII x'yٳG;;` UUnbAAA=:,j(y~Y6l#+WwqEL6mݻw?wJ̴Lцf /k> iӦ H?8Jko|ygc:v:Dо9~|?܉Pbkp\EHAxȆtŊo{d_?{111O2_N%u8k[ZZvZք1wpiZKAAk/s(-X 799ybd2]hl#cLq\Ō1b_鿷o޼y?>rnk:qy^Q5ƷJtBOE;&t$i{$#z5.d5*xmVLzSvwM+XRhii~+?jt+nI^!VmqOE>ţ+lQ{.UK/H)=UUEMMxh!q)R @xQUUR1F!B=O$INe7y9t􃽷'YL&j7ƙ`i@SӘUt@ SHAv5-kXQ9CLLL޷o4j2ĉw,IN@s}v:VN@18N?1o~g`@ưWNWF&Nf .2x`j u3 mb}l}tqy&M:AxU10.zWF Wޗ#BK ]0r^:{_M 1EXԩSG1F/rۛ}'kq"HD ;n1o@u ! AO6w&L5iҤ̛V,EQRRRJlLC'J'-Oû ] feLL..Dtl93nu 0A/cJ)c`b IW9@/OUw}ڹsAJiO8pg0aYYY谍I0 z})MOw3|rr(ͦK}vR @[ RJ5M&)!##cf@% Lp+;u;wժ4M] pIII#,Ĩ9tb h^SYYY鑑T|VZccTQ22f̘)C v  `p ) (;4Mu5qILLEQO`@`}gF5@<묳F&%%EC O y%IrITh 9''8t$ 7 &BPxwn4+BbbbA0b=@aB|߳gFJ}&}ҤIb010'#E~h`ѯDv;+++74&DGGg[,с!kޑ+3<Jp9猯)&WDp8{} x<'N?v; |!$liii)--]q~7>eى8w C(**jޱc!Clعsor!^ gG1 oc'g2%t&0d<8QbQShW9 `W3p# 0 #1?ri!TIENDB`refind-0.11.4/icons/vol_net.png0000664000175000017500000000354412626644770016625 0ustar rodsmithrodsmithPNG  IHDR szz pHYs  tIME 2 )^IDATXk]3If$d[5N&K6Y..n//L /xc!`'+[ 6zhF33®h\dw ΩNÏ 5׋m$ IXEh18Fqa?l/..Z-2Zk)R !JT)J 8>}7%'Yh_ FAXdrrׯ_ [nz=.gggJ%|' C\JB.BRl6 g!B,+Ҙii,,, lի8c `bb/REDQeY}̹B%-,(J).077.kkkDQ.벷yt:댌 "wy7K_>IENDB`refind-0.11.4/icons/os_haiku.png0000664000175000017500000001330612626644770016756 0ustar rodsmithrodsmithPNG  IHDR>asBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<CIDATxidu_ULFl).3Y(q1JJ^Ȗ a @ HȈ8Hvdlj,Z,4EEIQ&8}ʇ[a5W5{s -\d Ev8`&;[Qi6d%T҅hәZ]Ь2K3E=^ۊ.- US$֊d{A(cӓ&'[A/s+]Z 1%,'XXL-AJ}K7+1ٔ|6ml-|lS U{+bJ|~+U[Ϧ,@Vw|5 c3H(?]d3gJ MYxA_'}|7, BwLے[N35UFT=J2Y>*`W$]( lD-4A雒f dy,. CߤܬHw% A>6)ܴSo.t Kvhn RCqRBgjW^`X=WoE>[%@#kb[JQkϨ-YfԵݔ( ͦ҅ff.h):,f&@ 7-p"G;-p"G;-p"G;uQʹ2y#1XG`4[U[zC-[}[-byK+)ҽߪKە5q/\Jo:tmYSʔ[I-YqtZDIMI(X^j6X2h9mF fdș1ݰ/?Fv w 4;*ԴiMָߏiy-lДR-KEug}}Us}>sO ڕ66g1BNwi.+>`Cʻ|ݾC~<dZkȑsxgm>vgsf߮[={uY/8a6Ks>\cn9: ;)O6 >Ӳc-F]xBo8^S&=v{¸gbny]ȻO м[!ڣߠ Ro]6Kv}]TlPGB:e#PG_Zn7ys:38h1sqGjo]ҏ8,XxAP|{qJ ˞JU/|5e(2^'4 q;^)꼍 Z.SަYWkooaZ6do]B8&(V[ Hdx:FsV)npڊ+(>ɶ/xXοtޏ^LAжݾUƠEM;3rNVp#uyٮzP.\e甤8"PgJ[,*J"19䔬S5B{~HPdŬW}:š]5moQ1ūOaZvnL{QK*6'ij!dS̺ဒKB^\Jc֬k"V.̤DD1+q< f'#Ԑ]BÃ8eɫ=t1`t^zNmk:թQ,CNKUfQdكB/W>\U!-A VHGݦ/;Qs# fnY/nCƼ[asoNS&nu9g1٠:'M9j e],3kxuv)q(>"41y)kPȢ0.WIݖ=d\tխ{w'L+kHK;Bۘ{3.&fsB^g׮7Z@3jw9O> .)9+`= ƭK0p{GyĨu3G4:2Yߖ=He5r8j &=:3i@jFS -L)Z\{/ϏkN;6>+,(2xИ25Qµo{ڳɜJ-huYh I8IWM?]ߴuq?d}Ma]Le52x27q."_oC<>[ Ln@v nZ;Wc˪FeЎl YwYH{pi9~9̻^g>3>7̸PFqN0U }L:;^XCj0h@P%_\qFp~Y1$ XjN=iTVN2~T\41OyސQstߓ]mhb(*=*;'ƘsV՟|v.UOۣK}Fc`\M1m G}7 yC0Œ˘0/q9ETu EX}Hq1w]7!(tRP +ͻP"me0`Y{ _D1V|)xai+=g).[0QaCq:y6VY%'oŹSn?\T u,C')&+́U7c8mWƬ݂tƯK60Y?d֪sAz3|_ƿ6|{oO.SiZO0mn- Ȫfi*4/. 5zFPllG|EqBh[n7w20+BUÕf[jX3r)붥¤Pf(,}GGsdu*n&)zh3=6ke 9a^^;Ut,'~!mf 7"`C~5fM4aN3p΀[*-,yY y$DV7#/~Lӷ"ea᭖kpal:/(}.9Iʭ9G`C16:K5a>HX7V骊%@y֘gC/;vG8lXOCr^6gޔQ#nydBsVYe֢is&͘2ew1׍W1 '߲|q`Ddekr1,p.` <!v((E3I+}N< fl1cid:W2o+I, Ҿ6GteW5+I.h6,zXm!Xd^@1*X -@$@,Ϝ׫bԴj"cbJ+I>@Q>k$JMϦ-@18S|y,`&TtƚBhrPn+HSgW6M7Z]16P͔O:NaXUx_+ c-HhuoG4|?p#eIENDB`refind-0.11.4/icons/os_refit.png0000664000175000017500000002044412626644770016767 0ustar rodsmithrodsmithPNG  IHDR>asBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org< IDATx}{xKvl- BAQ/"Bk^ӊמZcxZ.VAb"$!ol6;3c3;$;{>3B 3yJ)ZBWOjIG %#lxSPN<(2=L`>2eBcݡצ?{ ` ܟ-Xq+6r:ǂpAxBF"3˜rбd_&/\& 1/-rY˾) ]?mP䋈M8S#H |m O&T.ZW&'gGPPuQSb׎IvXs۔ Fٯ̱a!ĕ̽|R7B}X|`b]pae3 W2c8ꅪD+>8h$t ׸"BIPe[( "6PiH$= WvA`ByOC0 +a .i) krd@Hi(}3f3}o'Wv9sVڄ@ԀEw_F*$#þ{S/)qW:md)[CO@O#UD: $mr¢5Nr@NL^Dw٠zl5BM&ЅuyWl 7CC7t[tr,O:> @/Ը@D#,e1&_۟_6zԷg\qvAƁyTt5]O><~ǻ F@O'?. w)ۯvAafRE$4 >zƽPIF,G'C!V@xaiyڅvY}vD]$ɸJGPxguKް1"A/2BLx~ۆrB0&$(%$ybR >Qҕ?xzH+J^~:gQY${5 ~gê?5EdD`d0"BH)l?btkB ݑ~W/C%RF"ۮg"d^M`ݷ_=&T 6ii8_\9e6Ltwܺѭǡx,` .ycmWOgz´ (P ;&ҺpSWm<j 4* dρZeP5)(em nlzZ]GH 8jj@᯾Y~M nvOg ;?`K@"FxO!$XZ)'As gy(m\Z!"/Pwp#T35SELGY&MO|sqŸ[8$`-ґ4A~D`$`*!$Ȇ\3yu ﮮ o&7RSvw|5TjRP%gHP;c/Z5˳.gFFBJo4۟tCk°ml%3 w,*('G(Аӆf G9n* P^ #N̝EnJɚ#]g}AP% 5}($8qeG]SYh/7.Y{_ۚǡV1wM `X!7삷r/HR! YQ+kPIEL]A >C]]:P{hAYrA)y=xΨ3?Bȁ&F:5"A/Tu%tVokUGPiI"^?ɅPIU-:JH~w>!@ S.>- Ouz\GC)Mjo7 1]Rq5R U đ Yd80+  VT}{tf Θ{杋JCUP R)Ác`qʱ+.ZpmŶ^wԯ;9׳fv'grGj8{[z&P!@I 4%?OF7\#>hD|Шsʖܼyeyf;mn 7/3Q1{ oWst@%Ez*d[Ru{FECX{63޻ySӃx`Pct;#ϭHP ,=鞩yC60?G{9{򮌡31ޯ:##4$?b͠}t|gG3~b[u_3a#EbeP%r`BDДdCL+/~+"$P!"HD&Y& * @ PdJ I,nDBu՛mISRY\w=}uxoMuƻM6X %/bi@Re/׿Š\aKojXש˦MzHOqZdBe#pن_RWv"B? XojH yG~ᒊ+g\dtXB&\"M[7_{ΨĔu$v8<ܷ#l黌}zV$8{gTէe ي\3a&A#]'7~/t&iS^^WO~ů_T U w;c{bv @@V + " j ޟM']mּx_5owH=ئzC dUzO>mA ڪ\~w!|?^3zbY[029vr> wBry(ś6o}jFGnqi6Rbvv;31L+uNV(E5 DJJWn!2Q||w9h`\}*dhU / |?/}1,"q8hԉg/%ABSsD|z.efwVMݯݻg>Ĥ۸x3 ޻>QR̰h{*o&N<+`簤84 [:Íub3~fq{}p@Y4Qc {5`VG+*%#o1 -x `6$^(NzGs +HX+ZRq{Vj)E>^"~,߭˟yLH)ER`(g 70Tq`t+mk ڣm0@F =.ݸ.ɤW%٢~TzZY=#H Í~l+?RAgF|ϲſ l0;byLz쥈vCw0Nz6+{J7Ɵ%6 E㧡d }`3ǻˡ%$^OAd]p Ɠ~:WK W=˫Sw'+4h!W"7Pҫyƺ ` =l@gL8sB.d8| ("+'H.hUb&Hlw/.9 +@ _a0JKFMY{vbʙ;[#`w52&M.a8 C]ΠI N?_|uI''.sB2H؋ n?EX( 0 f亮k v&DŽm+m ]^ Ϗki@0ʇBqgvXf(q%/,s"uJJ'ٶ;> jY+)y9EX+u#>mJ8@/Ik )Y9`Yr/]zonh50Bhe;:ٓrGAK.9.'yaYhC|=~ 8qkiyyz<ڠF$|E.Eo Kg"d1} @8,rɡMV2%,O$ҝo5m IJg~עK*s+10 .܅E ¬o.sB} ˧SH(QRgHV3$A![yʁ(u^b ޸v@ahpnÛVMX|U^%hRp/S C[Ъ?RRJT Z%;ٸ?,ƓH sD $)y}z wPX3{cvXJ3tNu{-|RsEcS\+gzR2i>Sw"ߩC.8E w2e쪍 x8&_V2xq"2=ާЦ[XLBmBm2H)A[3RE, ?W!mh1<2>ߩe[;`oSM C} C1_nnzÁ0>0lwM{%LA;[~rw~`N炪ҊblE?qeAl+k%"jFF[6}XF;"}Ф ў Tb2qwI#ms<}3l^cP5LľG=t|\3K&9,~iϾжհK ,{v2h m?źGRR?]XI4I"F'ɧ5b$`]G%Y2R1U&9@KhW/5 5,p\ၭ< 4n OV1-v4`HHnRų9ob6zBJ/wu]mB+FMH|Ú.$25d9/ P_Z-`G42 vn7#f"2S0*JI/ L;č/1c/w6>7yCT˱닟?45<ڽp}dL GC^a#Hz#I[5A\zALaPkHPkCɮL9L`M> >-=aAF1:UREWOɹIr0&3>I{-"t`&9;~ٸ/M >-)kz6H0b:01 x>v7-!G$h 壏C(Z!0ӥ9Juzy4L#-zP82H\ĂI|Y4u(ݯ|!ڏw.  @\Ȩ< ~zfi-(,W=exKӫ&A#/А`DHH"BU N,r?b]gK(6.}>)z̻q0icRB|7m;B )D+Ul|pOSQU)#`hV?lѪK'9& BQ0nxM(];7\J|!cR H1IFF_,)[zNE>OTM:f@Mgݚ'kwhUZ'鏣LˠXXe,O<XRӧ8&E2*L'>^׻ÈMNmHX-!`XW <ع5{tNMhbΉ6!IHWcSѿvxU汏۫j"~hW{"uj7;f@gz xcQ>\0v0 IWwyvVM`V;4ve &CHLSpOwwVkW;xv96<SH U5? ?yC]f=|"H"\T`n|ˏ|. j׎ uru7Z,u_neB7|mD&³#օKFfPB1Tn]n]IEIENDB`refind-0.11.4/icons/vol_external.png0000664000175000017500000000250012626644770017650 0ustar rodsmithrodsmithPNG  IHDR szz pHYs B(xtIME 29՝AIDATXV[LTW]\. XCL$mvTlDbaF F?4|DZfN}?M?(yܙ 4ii+H {w?-mv}묽9v3=>Y- IK[<}*1,_VU5fw1cX®]攖0{rPU͜LuUKϼ-,xCڜЌtZcDKrAp՞@ p1RvW̘&( ޽{?-,,>>nkPhlz?0,MyRm)tDcQ0#wSdOB16ysA+W9t:]t#GD~7fg=ԘY1*` ^Wsr>x^\.9*/THkWX,q:l٢0&r5јy'E 1f^X "ZSWWW8irUSTU5\/1vlllNj B6L7{F`cmkoGEE pp .{@D]###VKA@A.%ڬVUUU'E w8_ ѵي 72%8[z>f }7777IX`4UͼѼ @`2!"n.**|_sgM`>MCs#Su rT_U^^M#lZZZZE1j#;w@!f^KD·f<=*+++[U]LAw`ccOiiis4MnDÇ+~EMD8xn~OD,55-hСCuww_OO(b)clD ^kZ ` '7mY6>ȍްa^֩sX ff01P `A-ojJZ+CȅGpiӦE 3$2Yg&0ˠ[jkR5%ب͛Z}%YY~eh6OGB4 DdIr{\;UU+ n0'MoJrkô8w]'}W7yia:5Siac O?|v}>,*vDg\ZDC̈́gl|Wvi0;3Аx|-$plT~]}X33: wp(,]h֭%;͘hOeeq$`s[:;B pyhy#<6v)J,nTE3==6XmK+Ps?y^b$kBNS865 Jm>avK]VR1\ j =4G}$'G i`,EU4-F?D..|fh_9xXȱ>7Td7W?9ƙgڙl 0^H\O \4t4> @8qk? 7HҒf̖|a+\&M0&ϺL N@G@;A/EcD B,sC/D 4A6#hd& E zԴZ!D;GFWؐk1IN*e.f Ym`1ki&# @0v1Q3F8e1!i&3$aB#6A0DZ9,#Ll spB!=$*p3ӚXS)y .I \8i*ENUUr O MfgQHrQC6'yxbo@"p=_tY*F UM_?U{Y(Rt9Be)} n_/˫ Zx1Df0%s $!l+BsvAt !Ulk`$2|)M~Ҝ`G%©q3#Vմi0kV_Djj1KKY޺G>j0#(8mt k9jĖoeVS=e^qmubMT$"~@tX߶#j,֗TZ닩K$ۧ>6~ӻ-T;Vvwu}Rޚ"ccAM{Bׯ8+;ɲ)yw`w9s?NfrCP$W-n=O]/%9nśoœ5ng mWh8s50_;,@EQNիw3)=qqBf,6Fd)Zi]ǑP~Kk HrG&xɖ *J%,3f @ *h*K;w\˱ḩ̦!.WD5fe] \e/5Apmo?ҟf]Te ğћQ[ ]S,l餱&ӴgCx~+++Q UU}i[ ڟfU=m6 "P(\(t[k eYvefY ]zbttZ[WՓ@m9^f(PxoViZyy z6#=;Xu½XV8IO M^+sAr %YHyK,[QV'wA8 @?WX"'?|d8 (p9Ԁ B5Fda0 @1<`GfWjV8 } KI@5I5֯´.rSIϐIENDB`refind-0.11.4/icons/README0000664000175000017500000001346113276567644015336 0ustar rodsmithrodsmithThis directory holds icons used by rEFInd. This file describes their sources, both in overview and in file-by-file detail, and provides pointers to the relevant licenses under which the icons are distributed. Icon Sources (Overview) ----------------------- - The AwOken 2.5 icon set - Source: http://alecive.deviantart.com/art/AwOken-163570862 - Copyright (c) 2013 by Alessandro Roncone (aka alecive on DeviantArt) - License: Creative Commons Attribution-Share Alike 3.0 (CC-SA 3.0) - Original work for rEFInd - Source: https://sourceforge.net/p/refind (this archive) - Copyright (c) 2015-2017 by Roderick W. Smith - License: LGPLv3+ or CC-SA 3.0 - Debian OS icon - Source: https://commons.wikimedia.org/wiki/File:Debian-OpenLogo.svg - Copyright (c) 1999 Debian Project - License: LGPLv3+ or CC-SA 3.0 - Devuan OS icon - Source: https://devuan.org/ui/img/devuan-emblem.svg - Copyright (c) 2017 Dyne.org foundation - License: CC-BY-SA 4.0 - Elementary OS icon - Source: https://commons.wikimedia.org/wiki/File:Elementary_logo.svg - Copyright (c) 2008 Dan Rabbit - License: GPLv2+ - Ubuntu "animal" icons (through os_xenial.png) - Source: https://wiki.ubuntu.com/Artwork/Official - Copyright (c) 2014-2017 Canonical Ltd. - License: CC-BY-SA 3.0 - Ubuntu "animal" icons (os_artful.png and os_bionic.png) - Source: frank.heimes.canonical.com - Copyright (c) 2017-2018 Canonical Ltd. - License: CC-BY-SA-3.0 - Void Linux icon - Source: https://commons.wikimedia.org/wiki/File:Void_Linux_logo.svg - Copyright: Public Domain Some icons have been altered from their original forms -- normally conversion from SVG to PNG format, resizing, changes in coloration, or addition of "drop shadow" effects. Details follow.... The "svg" subdirectory holds SVG versions of some icons (notably absent are those based on the AwOken icon set). Icon Sources (Detail) --------------------- Icons unchanged from AwOken 2.5: os_centos.png -- AwOken/clear/128x128/start-here/start-here-centos.png os_chakra.png -- AwOken/clear/128x128/start-here/start-here-chakra.png os_chrome.png -- AwOken/clear/128x128/apps/google-chrome1.png os_crunchbang.png -- AwOken/clear/128x128/start-here/start-here-crunchbang3.png os_fedora.png -- AwOken/clear/128x128/start-here/start-here-fedora5.png os_frugalware.png -- AwOken/clear/128x128/start-here/start-here-frugalware1.png os_kubuntu.png -- AwOken/clear/128x128/start-here/start-here-kubuntu.png os_lubuntu.png -- AwOken/clear/128x128/start-here/start-here-lubuntu.png os_mageia.png -- AwOken/clear/128x128/start-here/start-here-mageia.png os_mandriva.png -- AwOken/clear/128x128/start-here/start-here-mandriva5.png os_network.png -- AwOken/clear/128x128/places/network-workgroup1.png os_ubuntu.png -- AwOken/clear/128x128/start-here/start-here-ubuntu.png os_unknown.png -- AwOken/clear/128x128/actions/color-line1.png os_win8.png -- AwOken/clear/128x128/apps/live1.png Icons modified from AwOken 2.5: arrow_left.png -- AwOken/clear/128x128/actions/go-previous.png arrow_right.png -- AwOken/clear/128x128/actions/go-next.png boot_linux.png -- AwOken/clear/128x128/apps/supertux.png func_about.png -- AwOkenWhite/clear/128x128/actions/info2.png func_exit.png -- AwOkenWhite/clear/128x128/actions/application-exit2.png func_firmware.png -- AwOkenWhite/clear/128x128/status/indicator-cpufreq.png func_reset.png -- AwOkenWhite/clear/128x128/apps/gnome-session-reboot2.png func_shutdown.png -- AwOkenWhite/clear/128x128/apps/gnome-session-halt2.png os_arch.png -- AwOkenWhite/clear/128x128/start-here/start-here-arch3.png os_clover.png -- AwOkenWhite/clear/128x128/actions/tools-wizard.png os_gentoo.png -- AwOken/clear/128x128/start-here/start-here-gentoo.png os_hwtest.png -- AwOkenWhite/clear/128x128/apps/hw.png os_linux.png -- AwOkenWhite/clear/128x128/apps/supertux.png os_linuxmint.png -- AwOkenWhite/clear/128x128/start-here/start-here-mint3.png os_opensuse.png -- AwOkenWhite/clear/128x128/start-here/start-here-suse3.png os_slackware.png -- AwOkenWhite/clear/128x128/start-here/start-here-slackware1.png os_suse.png -- AwOkenWhite/clear/128x128/start-here/start-here-suse3.png os_xubuntu.png -- AwOkenWhite/clear/128x128/start-here/start-here-xubuntu1.png tool_mok_tool.png -- AwOkenWhite/clear/128x128/apps/gnome-keyring-manager.png tool_netboot.png -- AwOken/clear/128x128/places/network-workgroup1.png tool_shell.png -- AwOken/clear/128x128/apps/terminal3.png vol_external.png -- AwOkenWhite/clear/128x128/devices/drive-removable-media-usb2.png vol_internal.png -- AwOken/clear/128/128/drive-harddisk/Internal.png vol_net.png -- AwOken/clear/128/128/drive-harddisk/Server.png vol_optical.png - AwOken/clear/128x128/devices/media-optical-cd1.png Modified Elementary OS icon: os_elementary.png (GPLv2+) Modified Debian OS icon: os_debian.png (LGPLv3+ or CC-BY-SA 3.0) Modified Void Linux icon: os_void.png (public domain) Modified Ubuntu "animal" icons: os_trusty.png os_xenial.png os_zesty.png Icons created by me (Roderick W. Smith): boot_win.png func_csr_rotate.png mouse.png os_clover.png os_freebsd.png os_gummiboot.png os_haiku.png os_legacy.png os_mac.png os_netbsd.png os_redhat.png os_refind.png os_refit.png os_win.png tool_apple_rescue.png tool_fwupdate.png tool_memtest.png tool_rescue.png transparent.png In addition, some icons are combinations of two other icons from different sources: tool_part.png -- vol_internal.png with AwOken's gparted2.png tool_windows_rescue.png: os_win8.png with AwOken's gnome_network_preferences.png Licneses -------- The "licenses" subdirectory contains the text of the relevant licenses: CC-SA 3.0: Creative Commons Legal Code.html (See also https://creativecommons.org/licenses/by-sa/3.0/us/) GPLv2: gpl-2.0.txt (see also https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html) LGPLv3: lgpl-3.0.txt (see also http://www.gnu.org/licenses/lgpl-3.0.en.html) refind-0.11.4/icons/os_opensuse.png0000664000175000017500000001465412626644770017525 0ustar rodsmithrodsmithPNG  IHDR>a pHYs B(xtIME .GhKIDATx]yT՝jnM. (QsH0˜3I&3$x$9'Lr<-dO̸,N,M7tUWUwmoG<^WMBu׫WC k/PN^>;W^www܃8^hoo|B|xFr} !#Ka8*{hL*u"ypA}{0TU=$[ܪs pZ'K.= (  0 @ ;.s ^k+~4M}C5֘,"tG1@UUx*\.'M5%5n7r+Z`p.xq?}q?:u>Pb8D)L&eY0e"@i[QBI`;V&p&-RRz*p9gΜ?X<R RzRھ勐-UBV>} /$NyB U @%KvSJiv|CۓWB2Tv;akF8 @XBҺ'| `iol}pk /}u(YWkHx78Cݔw([>y0D _>;?lذ{ !!q_1vRJ_0 W |qꯧKJJ d];´%(?֣"-W.)=x-LGH ]]/%].wP @t:ڎ f3W1wwGxv9=nbkH/+|ビZk| k !pq\c4Zju?ٹ "|2`2fl@v?-r{_K4LbF3 ^me( S$E>>!O;=>A`A UgxzzC= <nmM~^vեwcsܷVhsQ gڟOOlfA:s HWI_l-=\9>g*r;uG^`ziDQwBCK Bb J̆4^b,ASiZ[kk|SOgL/XBțw=}]]Wt~Ι9[lI0ӽzEU7OˮMLRJD"ʺƗ~RsCCCa![!{?LZ7v܅_ 8/vh޽b?N+"}@a}&-L:wQY2 x׬YséNRPP09Է.0a3 Yg)&BTӴh4fI=g|9_jh4jMDB{;`0$p s7z_>e?=+AF1;6ev{#NrC$N jx$ٻ$Я~N9|k֬~Sz`Αi)H%H4ک( AAPUWviڻv YfMمg R#HDkU˺i8q"k׮(ºu.K(BH,)e9rj{n|p8f[ 6t6Te ?Ƅ͈Ѝ]!CKX&8yy:0:ny7oܸQ쫟}_EWjRI~/|_oۼH VWW3_"!<XH:cgb9s-uMe@m9o8 Hcudi xn]4BiZ}ԽT_ f򎜜QJ)aa4S G$IR}J:.D"&tnr3(2TkΟ?udEEEȶCَELZ뺾gǞ]] tOyGe PZWW͚d#TsԶC2bDm ΓiDl>n ɫVo4Lehbع a[FovMLbچ#u999S3r7:I]L٫@XXsvgrg*OX<((D" c:^ #'HoUV<8e|ít3܊4GDA2~C\ \`L}bYrZֱvlnnjnnGQO\ G7hH̺V%O>y-Bh ۱@B(@ b10nJ)2 $b#5 Ct]ިl<{ĉ>%hݻU5uJ%ˆjni]ƆYVH3K5l^ᚚcikzz^ yyycW^:t6:ykt0´7kjaR6 `#l@,++R"1 a(if:'=6MthavC1Buu,ü'n^kb-}ݜyX"6` ɖE q;FdQY*4lYacaS'e3F<@ fP S9rN dQ$IɩVWW-$:j7Xj. Ҕ勗U{Z àÖ;K;J5QQĆym۶-@b~ 㳙Mj>wBP t8mjYR[[K-ZN&BJr_g&'0y#1r=p)0I E DQ̟7oXYYΎZJPz3RQ~;!JƔnݰ6يtٳ'J"Yt]]Ἦمt9bbTm#HηҩDMe+"+b>6oqg=޾s3fWMЫh0.J{κ WW bvj4^4m$XD≥E%mmm-M-oh`55E5M420n>Uof vElY@MOV@wwwcCeyᤲI}0W]Ѓ3ԓjk*@6G T6l3f`m=_WWw=i _iTz-}{AHO&6ş{UUWh֝VU(A}HÖbfI͏m~fu 7|fj\1+ T@ɓ'i427/4$iDSFUUݫ'֫!B?THj>|7|{֜^i )B ~lm۶ u-wT^_%m5r!pawZ[H"A gQO&|{yleOSj>+bH.ߺZ+!'^|7N>{|>V۷O?|8wq{PXd F:::LGx\\|mLLIBD+v8)//'GnzQ*A 2_qb{k:?tJFli1ϕݠPh#'xro%OG/)0Mӈ԰, a[σ@Sպv 3N3T\樑_ p6HVeD} 5 KXhݬ;Sߙz$r@HSɏ\ AH'IR$I(tA'u(j0V"&lq2foHڲ~}6D\?`/ժ;G*CcȐ'q0^Nyb{b{ϗG(5`0X^vỶrnz7ٳx#k'r3:)d#@&H*vJxO{I@4%@ LMoޫlb90.:FP,[d L uGaI  D1uü vE<o tvE_4ʶvie"õʼe" 5U&L JaǎQBowGʩ((@{(i/m~`$ݟj*4 U0N=* ,arss+VSԑcyR4BeOkZtez_oD"{ᥕdP2xz"VcIy~ aD’%KrdYTi۷obϪۡ"oʶɵeLa,jD9J$IRCvc@Q{VcumKI`?'g 飷 "  lึp=5yG:zV\!qz  $۰~:w-y]U I""z?)2E\2iLur|>vξ(.1N\IENDB`refind-0.11.4/icons/os_win.png0000664000175000017500000001464512626644770016461 0ustar rodsmithrodsmithPNG  IHDR>asBIT|d pHYs BţtEXtSoftwarewww.inkscape.org<"IDATxyս?Ul,  [1&<ѸDL !%ѧ/599sѸĀ{ $!((20Lwunݮdf{jzny]0 WgfURd0iFW l]^JDEvK TBw#ny:]"f([F`w0t IBY4~ Cÿ~4n|c;Q>D]@P&Ǝt' )e0*aBF5 v6m g[͐E|O/r,aa K!|8e0q.MH6\H```_`ٯ`=ABUBH2䚇 Qe94.'3!7oJç/-gYh~ \X"BHk4|| \q0ޭ\B> 7O@a2d"=)J$"@Z/]}8h =r]{n/xA 1BI#@c4Ⱦ[xp!B7(zP:2u`z-̹^ !C9E Rp7 h$ $ :&iďgJ8Â_M`_ #14hQ$.=WS&Į__"APyOa@Qy7YԄa=G/ 'ŒW`#$ Cu9oxsG0܄ 8"<@9³I/7gn'cꗚ]Z=Bx0j[)(VY@%e7{2B ouXs27 [yZ/XoQI@<|wC~]^+=ː/f9lj& G0|"6V :HщRhUP㡜F;/19Cb*3c;@HPN 'N26yf5|,*QH}p8(co|-PE"E,:k׉f~)c- "/D?z89Z~J%Gb \rkTt/e4Sd3d+x5В#||#<)AVTpS{ঙbYrIpu'#jtnv5MAp`ԩ heÊzdD?2kx7S5qRb*[ɏDZJD*GdlCO/xqss|WAQB,Zx(CASed#4H@c]> R, ~[vHh7ᵭ.sd%\:j' ?:MPDv`;КWoV]1Dn mh$fgj!rSC>uẗ$\> "c u6}%;`}nJjBzAKAD$ppD}&.r`F)zh0 /_sWsRQ#$:QQH3H'I w4a`7``iAၩg,M1$-\g *E梓k~!BFؙTt!IP&ʝMp[c'<͵DL-VC4x֯|z WcI #If!s_Gx7QP/[VJ\m0i,' ъlܹE^_ mV@|=_nΨ :$ "s|o  \crZ[/S!^ [Z`%pj2ό$@!͠=qQ̓TQTLBtY7VGsM@ W]w/F^fǒ/\MUj<2-\>J *brjMct-B_*idLAAclGh tL+k4ޥj`QJ~Y(W 2희Y #ǟWdGCly,jdL!uЂ$xPOdg _kѣ}gL۶q\ëmm^TP E #TU3f0i,9z4cײ>yɐ5 ?W]Ŋi"ݫC EO$@% @Ő!>Cjk9ØXQAmc']0NcX--Z~<ݴې@Ug>ĢrX y$PgʣAӠ Ogsaұr!ԤR"mc.a`bX8y"6M ²m5kh-Xe`DPfItߣ⸢&Du݁NQ3ǤR$Ƀ߸qTEa7x0}Aד:>_dmGir1mE]5Wp QT2%劥r#ؼM].FSk{;@k%KdJdR_qg4Dx4uŲ^T=NuO2jR.41q T2". =-`'Ј EfNXTFr{%tJ[S3E ӗ 9FA7Ύ]67[/i!~"IENDB`refind-0.11.4/icons/func_reset.png0000664000175000017500000000505212626644770017310 0ustar rodsmithrodsmithPNG  IHDR00W pHYs B(xtIME .B IDAThZklTe~3 E *]R(-JqHXTu?̆ec.Pfو* EdRTPR[-q3oʴg6'99^: 3g^Ꝯ/JIo9sEU-p3<<x'H)ADlF8<)%0Fp_rĨ9_~ٟC( >|&Um6 y|ؑ T|McOm~(w",Y 4(cʫbYc'ߛ2L|wf!貣ТQQgAYߩS޷@U C9eZ(XtOq@OtJl9sNLhS˵r8]QlA;9yo@FϖիϞ$B\1{ɎL,9)c1Dh_n5!H߱{߼svŌEYUG/.ƭkAjx1d.c]jDDRE>X>QnE54اy!}}A5M>BP2V!)q7/{"yЄ3ηD$# 98!ZݶX4*G{x챂B&aw)s!+6Fz`?mBi(_f? q P^$՞su}̜JJX:|tA*],^{#er/I5TMOHE/)UUӝ1wa(fb]]yv7o\5"BL@9p:VpO戻 gf͛Yշ\oJ!":;#dMm~srnl9w eNHwCCD1\]2!f<ȌZ+oRrA@&+JO@}}$pwwf1F|a͕w;V<Pjjw+ &k ںo Fu \ޟE ~͹E|1< H5˦1=  M!cfo`0okslHw0EU[m6(D82Zu릮4koɒxh'VhEM;ڗ-W8L,ش_bU{ޱxʔDlM}޽ˌd2hmu}SWױ0UkS۷or|ĉzҥNO վ .`Za@ da_RM7']zs,4\dkkL~}/Epn:Z5y*tp~(.rkcn4BR@fcx\t;˗R-HA026c+MdQKs͚Np#t<.Č~g7ϚHJo9N2J?ݑ Ui*Od(~XάݷR}MM?-%25x(NNw PO6y^]`!T@ҕiDot덟_>s˖Um^+jBBguCya9IJiOHlGZ[cFbl\"ܩ_jJ [qU@w҃9җc|Ȑ0 2b1>s&Z]=pgtKA+ ɨ,eN& "t?ѣƅ={Ny"n)?ٞ|rWөVVV{0Ĥ"G^I{|P_򃈑F =Г_k ${cDgF0Zl:ŒIENDB`refind-0.11.4/icons/arrow_left.png0000664000175000017500000000256012626644770017320 0ustar rodsmithrodsmithPNG  IHDR00W pHYs oytIME +BIDAThX[lent[@ b@ iPG C'_x0|'D!A! `-HKM1Eu^:?>td%';Y (3(nz n&KR …ƜP^SW|K)˥Y#PULmο\\G0D4 (޾]M@wnhNܑ)],XJ]݁ΝWNjy0#l "-$tcx:V~{Ym E`䠔`9$tc.Bc%%׎R)^ˊFBwK޽K-[NTRRumjnt釶Yf]/5',JDqEѮfB4gDw(76\u)Ƌf_~mEņmlJق/Sظ D|},k;k/ jc{339-]F9&Y#`ڑ⦦3|#s<}y%{^}OUCx и4MqK_ ZzL4%hEGωhF-n ̞;XM3OΨܓssΝS`Ѯ^t,ɬLY &ן3qͶmׯrNRJOL鐈 :?'FLl~ta/zz #:$=PM3YZ7g-mq']ݎ,^ix;Ms22<:ywYH:d7@2uTC^C?%F" !gx<%I p*wJޔvBuwAL'1do"%ڇ]ħsSFę%u  `, wފW,<,l)UUNU4mٕVHGoDyA[(> 3X\QTer^hgH׋> 8E̖3!1j̉M8+*Z4daӾdҬ:gH8D졡vݧizuݕy>g;d_ז1K)A m|$nz)'cK)WxJf )ŹJ=~$,R#aMv|_h \Z]napHXC ^OsH'= 6;IENDB`refind-0.11.4/icons/os_gentoo.png0000664000175000017500000001657512626644770017163 0ustar rodsmithrodsmithPNG  IHDR>a pHYs B(xtIME  ?%IDATx]y|T~]fdMI,0R Uk`g[bi-~R[vE@Vjm]j]ZZ(UiDD!!;d&e2{?ޙ37dd&aw2sνyλHtKtKKapdg2Sߴ)M&䣿[:M_ψ'J>?$ HF=iiՕ<H䇂;*8mY|xp Qj`W8g14Q۵rΡL2Xٻ*F ϔ?JQ@شB P^=Ԉ(p*{ Zҗ}~ LNeշ<po?l}s(H uUqÄ鸴Z+d$MKK|ޣX/'6 w7-ZÄn(OSJ__eT$ ~[''o_j$ q_}AG !ũrsRY1κk]x3(ސe+~7>$ Qi=w$ɔ,l|ܾ}{?:-BJDѨ={q'Ecǎ|.ц['U rC3>CL^Ue'6,n>UuWVm,06~(;;{!ĘpR[ƿMSgs뿺㸻>u\'d?y:88xI E]L2n`6<0oѣ d$NRJ_e[ 㱜2YtFټ@~wesݺu!dJ! 4,5{ʢSzDz6$UE~#.,8d}I~im+m ! \j=P%5o8fN5Flf|3 =j}YVxtا^q t+;9<'*uM8#;mp}%EFMI/r+LmNthlt|BN4v|MJWغkϞ=[N)M$0u:ݏ7S90}~.=4Ĺ}YmGRňVDg?ZP(dPepAfwlᩆDNaͺŧc%@7yddR!VxG7F !T"t*$+sYϕߢ`0pلq _A[ ''|'ӂVJ" 4*RW_666N(kBcAOBPJ1Ў. J]=z H ҠE8 ΄~(I _63\0Xot9"|H\2Z8 QUNGƘv*Sw<B@5N%$b<-ܒ#|JsBO.>*A%CQ ?t?o[<`2֬_r&$biywpw%REQb[DFO@'n2s"t:DU,E_x.sS'ϸIDJ2?,] |22ܯ}s=JhZy}Y -n ra]6.Ʀ}Bu:O}aQVVTS[4V xi k%30zMK$`ݏ`6Wr7%VnnnK @!eܚ/l4R([b?я2G[7_ݬq ם" MP&:|̗ipȑFtXe+^Qqx\`,1+5k'o#d0 QJn ;grk0 wqw2RQk־9ڣP@L`lQWݾ ''jroJ體ңmmmgv;}f́F}׿4~Q(Ufbh4h$iʭWDL~@ e /0ȧzjrfEQ:48J)=׳bS|9*^(}r<{Rp8qZ-`GwŒ[.I=+^C^@,-TTj;&obOrP?> !Ѻox$ 5eM鎍aIڐnf_Q4qT.~,!l\+6I:+Yp|}.Jq-ѡ"^?Uu:Q +9w}ceјD/%}tUߚv]+BJ"|zbƜIQ(@ Gڵ:E}qoh ~T1983 y:A15\Ͻ{z տUFzܛm3oͶ F8]kb!6ZS;<^8 j0r!B#@ώGzs~E("X^J ]<՞]ҧ:M,`LaPP}sN:厷В%J[ ׼ kå&rug׎r7G ]{ǒA [so5H- m ("Mi!*;+**\/;PFn YC V=AZ"\P(GB eV}RfV= 4иYJirjת_Odhjj x͕]D.L5w;Dbb$PXW}IBw\X1"b0%`Xuk0pܛAߵ'le_8(.Z-$ʤqmf5^Ov#C#0Smٲeٓ]~Udj稩*.A}?*i՟j$]vbWU#XJ%:D@]['<## dz]Ťg=~va~ֿ~fӾЄo~3#@PW~~bm[ٞgwľ#J\Xk"Q# 䤄q a\wP%g;mmm'iCϾ|wܽx!kڴi\: eG|,?+{wYπoKj1+_E&FO5yd"f+Ν;ZB3FqI-_p2scɶmӸzwJДSO=e1|l㸛okoc|@" B㯻Lĭx=ۀjG!@b]-cO z8H_D E}ܙy[K?'UM3owL[i:zx42-¼rB.~$ZgMT+St/.=vU}&r$+؝2zkh<ˡS]X14\'nɲP(y桇",i7In%@h')Bz~o"[YYQe~hw2=ߓPicqir5ҷVZ-oG8q%twJF~K_tš&,0n%J>_6 .>,Om/}jvsUpgHRߟ(v XS/r'gWo"yBU9Q%&*[ZZNV *Y+ߛ,~* CoD"wI21S#e4 %{E+ŧKGA_[^nW'pz:/G%DtNU72cvi/LJ-}p8ȓeyuQF' DC5JKK/hΥńøyޖ/fD֪nDV㒇=G>k|-:.[1XA(G1%CCD(%vp֬$_YNj' ``Z3L'ӏR*wf@)39"?VTKzjkk;i0R bOPJ cM3;Yg= %JLw `_adz]cbEGv8;~";1yZ~ԼIw-LəRȏ1zM5˶onSutf J\pq3~ g]vTO(*iT ΀묭)x?x\-^ Fz , P_pǔM׍n!Tjlؼysc{{Oj3u#,(0@AAAe_kG_Q"d9TnIqm3`^u8҈_>w^";q xOm  L%|Œ홛g?Ye&@ZmuY-^}v"ƝQv-OKJ U< \ h4dE%>O1i@Tr:Mu#;UiӦFdgюx$}_ JQE(j!yŊI/ N4Jz^JitX֦kGΝ;[ςntݰ>VD  _y* Fc DQTeuY֦W_h,XRRn]=ߩDoKX Q dX˖-+pMm4L<xIP t Ҁ$I~I|v{[3֚MNpڵ'\Jg׎v֪ x%Nf?*!W!AyUW]Q\\l&’C8Jt4ۜhwE hTDW0@juo9>RݝWK.>5 NB^fqcIENDB`refind-0.11.4/icons/os_zesty.png0000664000175000017500000001237313117635202017020 0ustar rodsmithrodsmithPNG  IHDR>asBIT|d pHYsЦtEXtSoftwarewww.inkscape.org<xIDATxytŝǿUsN[dɒ|`!lbs !B&K&Yxo/as,BG00&`| ߷e3͡tOOwt47OW5_@ @ @ @  3@>Q߻o ?5B K=mou÷wVS $dA-5'TpC dۈĻa+%X1실oR0<]LCSY"VӿD׾ce=ٺ6zDP(v;X6-͎?dI{KƟ~IC0BO ]޷q$:{ӯumz192p:,\n!@yT7p@@Vbl@ ؊,t"6tݺL[Q 8XC}J4+´8/(!G8QJ;B6:S@p-=ޕg/NDcWP]!9ixK:z%2TeJ!l>[_d/U% dnu 쁼3ll)O/*/En#T7X=Dl]0R@^|dYg6 {Z?F^ifV9oW9 6Y2cx\(p1W68c˔9}ιJX1 `pF2?<~WC]2%eU<NWfmĖν<-q 'S nya4=˶X&Oۧ:?)}ǯ_n9!̀ŸZyK[q(<9`4~K&WgЦZ٘HhK-JmW t^}+aB `V7V߱dmC<˧:>1NE3M1ݻʱh8 :{tLfcU p^1gʸzC;̖Q @MUkKtP;b(4vh=am1 L.kT,6A_ٳ±Ba<ͯmYd" S ~Cg/M[voÜhBPaVo|ycL~ ɳZBg5҆ qF E/{NT -xHJbL]9:f0ba?ї_kC@@8.T7ʦG47ܻhudTc #ٖ^-qB aLp+'GO}%SN$um78eZ J`I6xʩr~zsM甄# s^O\bmp`Br2:Wa= P 005זѦ?~s_;,ʭtΣ*> `2;&X4R>.V{wþsn8ov|%Ü}`>~{3T*$^Eo]]Ʃ酦AqL@| w-[<Tj+lRU[2žrYC0F| P'8I4}fd yHBs{qʸ2T:ʾeSR}0Ɏ '=Lp|Z @r'oGg;Sg33SMS0A==Jd4BdJoWX,ЊxnSLcq̐N_Y"O;Ir[HS*k)nLw˃(~bMEg0/[PDU5tR:Sܻӟܭ\dd̬jYbsH=%[q?dj=roNYd픩vuXeSdJ>!˕'Ի-^4/ɢLhop)RbsY9iɃa:y9<ޑB Dz[[}ʖɃ8q}M*6Ve;Q4`YVإ~k [%3ܖɽ?|Lgd4F}?OIEKekw'-28ݙ:I+K,"#CjV L2X$H2咛JK-%{ڡwV\)w[7X}r ¯-G"ډ2 )h}DoָnhaT<*49)}e OG2TR/˓Vk:pS!S(Il햩6HR(cwLd2ۍ:7'&jtFb+合)}(}?(V^l2Ŕ꜊j;єa^\6H|q"0Ew7Ω{Q:$= d\؋?>|@ѭSb!7 T97=7d Đ@`ҺrOygVe7k uR8oRÏ(1-Ҟ4p0~cK,H%/Oi,+ WMwR `=^lWY0!0E`๫~03,Sї=9K6Qj#J^( `#d@uv~coa ݆^;r"P < cp)woge`~4 wuý;Sy iMy~7BcHZIB2@ݯgNazzz9]v\\]7zBH b??aw>6,F1d8ڡCcL4Za 4!<¬┪?NT1|1wۏiC/YBy»jƵg Alք~ L1 ޻-?3pիڞ:d gO&J1L=G?u$ӯhrid\!}0y] mBo^+bT1p| < +n{0 ;̆4 'b3@2"͙sюnCYb!n1"@G͉k )b&Cm'olI=oAW:|,C1P}icPc! nô {"% P޷L1X'"~}ӣ6MmlnW?)atNmwc*b5H?K~oG78R/6?}z{lE{5w0#ԻL[|m_??cB}h^S됹LqzPv}qg~tFy75u0óh'u9[Co0`AG"ڑ/ohl荻ǻlSdXs}4'uC{az=ô:pz1Y= ,!ja- ixيǻKn˄`A Ѫ=-Zf?l 'К%IfasBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org< IDATx}wx;gN/9%=!{/R ((*ܫ^ڻWD@*t);%i'9Mg2CD}y=e^kmj֬Y? _SNb) Q?fu P\WKomC- ҡRA+ژB'`-(%-o1Dj衏+Ay$KD0Pf`s8)6p3@!Q".zZ:n]Zdw4F(^Gi:zF4:(pXyϰ0XVFdCAU|:\5߷`B>AfQ1$:#\ PlW@&9zX5y}3-$f*{FJ`ngB>SλO3'Ûm> 8%Re\RbU 3]z' IIVjedR IiRF8^VTő<;23A$.)Fd J|x707 6IeY: D6yϰ"ϲVX(uZJUSjFK4JgQ=eNxϾo~n 23AZ*\*L3BK7va?MNٔ>wJ!^[gJSSy{CiU[I4ԖVS[;Z722T:!%IeW<dzG ;v~x~)_YT !1*!@Ji֩f2%%Ǚ­ g$-@a2TK)Ck0OiV٩:MJo1لϞ> ;P"g/aW|\I̧:dʭ])MvG#',*>P%LrXUK( Q:9'v?iuNoB3k`9vcg*@C0ZhREX$Ckn|ל)vC&fE6pG آ{ ؒt%A:xAr(-z*:z&hRdXF?3\ե:cڌRS \(CZh2>@mkWNG'fg^'ra)sE<2s$]*][0FӦC -l*SCe&@R((" ~GT8wYS0>䕤tHz\. 3tͺtښ J|փ0B()MM kA,{4C=l_Uݼ[Xq/r Ǟܹ; H~/0r\br_WCimZL`PZC- F!! Б~bQ[<>Awxߺó7adi$* J|I,y ReHaD<dz{}ؿvV11(8V:9':ANԖyj[z@ŻW'/2qޟy< ꈍ*=gy}Lm޵C,#A׿qy,p:1^"S5>1]}cŜ9p,ž]Y?2 3KÑ0A㇫۵R錆Fy:U'wо!K0ҁp#Zh]5is@.d 1l_ֹ = z 3sos(uMC1rrnG+(S\hvA3Bk@ 2 c)ƿ~ڞIz`SR*u@C\ّ]Gc\yA[-?ZkmV[hZe]\e סP 2U 1t^opJkW_DŽ#T͘2]P5$h! @ a`{J*\=QyҬB4mdSGP&{<{vt2},+Wb$ fIk^B׻:u5h~ض'׬;c 6kZC҉ܳl1(!pfξKP x 3?7{M|;ctwN1b}!ȱ;^)rxCZa bSĀ#Rڃ12C{wAEC1iHTڮy^%Q}MTͼ} LD1E3@4dn|fː{oUZlgl4dž'zrmMK9?l%k":S &SR v9NlJkԋW`e%W^X[vK#$M72.6~QpUJK__Z) %zMg#j{ftEo,|{&^_,\(<k?:1/?ҙs[t{!>b'd8nqΤu{zQׂgf."Z9d)։o^oѯ:%9(Edqꍞy%w,BDcǽt'3`$cSfX3'8')-K !_+?XH! 1>;LS'I޲Jw b`֜O ,^^BV;{ Y`;yWjsuO9qw3% A`S[Nۇ:36@++>jI̎SEڑUdr͹߁Gϗ%q3A\n`Ll?@.m?E[Ӓx_yߍ_ri" /Z*-Wv?q/z~1DQ' iI~gǧhZ''*٨hml_XWvDb_^}+ۨR/4V(J֪.OZ`˷w >]fh7PZAײ_GCXrxø`ɒ%J_?gM~p9~5g~^Sm޵CoE;*z=REJ }2GPeH&8ْ ^mLO1>)ԩ-st-g6}2D\BݤQ,v-)FL 7R R7 45Y;JL0Mր`֐u9=;A#QΈE6|Ddj&QO5TzIfPW[^Va1PNȾgNֵ8{?)M.2%:t-dj'I%K,KzޘH@Zm_ެCy^hՁ3ւ`M7O{r3^]Q<'v.Qo%k%?~CIתtZ3r 556'9ڂ?2yH]58EAvH< (y)Oc 13MNk|I Qۧ+'pǜ0Ľ GH}rS8k:@.eb@\o6fD]mINNzN%/BŎosy3Hp?fN/Gyݓh9f03~Vi߼MeN7Y3HM멺V! bp_6?=%/A׷WˆstIT c#d-y迂-J'6t@hGH^3$'i[\SyBpǒ_[nqO(z\;:< [*{ nx5MN|Zi=׃ ::| ^tQONӵw+oo;dq RoUP'Pz6h LTFآfN $Љ9-W?7Mg=p;W "=M^1NW%ėNm<^ |@m!ƧiI)>! ,ʪw~ϗΣʧnMgudo8m99b[k ԤRWpE/nyLty:/mEk.zb@h8I A->p&@M{Ի_H (No"9 E:d4jX 7cЪ}P~ǭLԵ" _sp qo2|x/8MMf Br“ y}W>}*xluuLGMmy1o`M^! Zh+hUdui).x?'::}+ۻC6Ism澓G(7;Ek5JJ֬("g*'Y)K)h@ӦDSC0('c14 {j `V8KxUܡ5hw6D[,=mZKs΂S_  G Qr@\DA'@@k5%?}. " 4WmUh4mbeΉ߽JǕ/b7R t!Ťٯ`1&Uy/*\?f!@i9K;['6 +"B9fXoȡZF9&W7\ )lյR/.qV{gȳ \m7_i9&@B[j>s%k;8Nm~0STEk֐m,,*S4RKѡ\r3(QG%@lYUy*s\Um~ڸ^ؖ TKH:!PrSAx>vCX`duP']+PP2쾁6<[YhC l!\`0v;s9Wq)[Q4Ypr7 Mj@xlJeG m-C''hkf }+ S%*dl?CV; jӉ5DPy$#d$ʉ#3R42]l 06n iXu-vo\or;/S~@yY8p. `TٛH`KGo$ۮyoU̩RWr'}.ScC9ݞO ⹈Lƞ:5eĒ)ܾ+@1d+y@y PP 5ir"f|?tڬ.yx F<r% ;ӉLю|%ujMO]@ ]>Ya@ŰWge)R cC2ګ]xRTEЩ̎yyW.n`ߍJk@ĿBe+F?}D']JkЙD.+ @m^q}r" 2:JΪXʺ}hYmˈήB%I7zʒtQ - ${ ߑHX5(kFJYϒJ:#F VL@g.Xx_6TK{(ΥTIWσ"I<6{7E.? b# )&dhiKR ?\dAȋMr2$Wv.)Cbq&6 D1}R0RkM% {h7 8z{uML|TNj'sh55^J 16^G((6V;J!o 0w{'ݯH Me !os!'j$&\3^7U13 =gW}NЪ&VBlLڸ4&xOI{]B.v5{wfDS=C ?I~rڑ5, @fε@*u.Wu 2h5-P(I+{h}a}Mhl9$,>D/=(=jo~L73X:E"'臭1kȽRlޚ2:JE7"I;ku/?BQ}<+[9OFqcVV}{ᢝ@Į@zCKM}꫻>) :B y}DS}UA"l`EU<vv]+[ǽrh/p}9Q73E 4DS M&_{8Qjn5d6$J"ByU@M+!`c%4-, pE9mM!{oV;fX,+:Om7S%U_PwHi0{ηHF Tښ(L( Dm%E`o{@d#l-_* K@-Y"]^܀ߏ/Z6hܘeUy)ش r3m3?I=wڝ(S${(jcz2AβjV ?4&XGTE,ږl|UlUdqǓF:]^cz~}ȭlmvSEmnqe;B 7B^k0HM~VG Who!oWVit5Ts)UH;AN,Ekhc[p uCtZ;/En8tH~5:5IR +ʿ!j0r;PY)VJ.#~,5Pي㧔?r2!X{+Jh3:l1/,{?'dN9Pu m+/OcsMU*r6Ǭ?~Rcd]a=_.1i(cP;Dc[Bjf9Eh{f*-u--ꔖٚNY +[T m.gA,4Tǯrj{4>YayDV~mMO>(L"(64RA׿P쵬[6 @ }eB)b z,*Wt+"1ޥ/Bދ+w*BhOju{+lbțR4rO\w5|./ ?I9A> el;c3; ?H?]ANO 1MV}8l!W \[S}Dʓgs{ӻ@޽y?3@8 _n#wL{@˫`}5Y]ڙro;1ReU<0?rtæŖ9JeA;is}]fpj;W#[|r]݋w8^2@o|U78_}jq\A\"OBTCfp7ȳ5»K˹JPZe0m,úW~xl{Ju3<1ϯ-prDt^=wLYMz&)=0ڹxyz;@%U /7O:^9$lɡydo֤SÕ="m SrGMn.3zD{b;9&5D@C?U넰7oh;?p CG5L xeϿ'mNLwɋT|tݻwIHm/$ ^ r[=hMJfQD௛ ֙"|&ׇBOw/{mHڥJE/ryvU} iB`Hlc]%@t}gCѡiEm{*gHJbM_ҵW'uH<7@nivL~mMķM L"ygYfSN m'SizW ҵψn\W0EZ_~Y/$m~rg}%?=}p/OS>M]<^]qH*Dw-u>;Y]7Ю~jڷ J -vtuO/)ܶ<_U{j^#y8~$LpڤdMf6#ڄVno/JٝUUFT0Uwg C-GtR-L2a,gb}!2!&r-s͗> "Gd$\UNؽ&RaDMFj)'r,5sΩ'Jj^\lJך=0 ħVv?r|΋y9P*͓}@\0̮R@^e=77 EAdvu+ox/; ;x%1^똗o.㛶dOK0$c'[?ֲJ5;٢]ՎR(mNn$|%򭘾Pעw7JkKxyi?+˞&57k{L :/"\iОs/|nȌBL0ɴ=E= Ҷ׳! ao+@T j&`vD?טW.+ ڷжd_ [?Rv}!B"|U1p.O)..YN&hBSJ͉F ao=k_`3,# 7Rxviw]0[ԩ-,-s{`S'p Ȫ ܮ%/I VPHohϏ"'ԷTm\3= &oy}H5J \}N)-eK6~)t鍾XR/~r7 wzJҪl]L0V('@f5Hh'щ~>Mnp,"{k! TcÕ煏ȗS%dN߯-&fIo8*g3.UU#x*9':]—/1s_Y䊎bfDȝJs=$$DD(OOhetw?:MK#;vd_p:QE&/,8ɞޟYu|EA)l.EE;} mwxږ(gȡuR 4󉴣Yw t욺0ݡ]KF ԷR6v+!JnW$YYԌO 3IQ-CW=7B <_=f$$83OW{x_tmO[=S7YD4h4T(|~u2|dI |( QG InP7r{vlps ))S‡WH0|DՀ$|*|@ۧ#tBZ}:==zd3D:\ yKDiwon0MVV|+޿ $Mv3"0]%:g6)ʵ)*XHidruGǮf2X%(2flǛ鍴5ZRk}߁Liuu)ƬN ^7Re˥7tKhrw!*)H*Lq.ɴ~f:KMZ vm7]%/~9 ȬNJ 2WY$Y3fM ^Dc[[=Fݭ=79`uQnh C;|h:>vXYf]!m$&C١g+T-1Ƿ*}HeG5dAfNlnpMv6-ž`m5ڽt?䨠$*&CĺdS*1! i{ˆ'z\;Dݭ#l%Ϸ) :2@1PYR}=u-I Eiː'1G7 ECxsUYv>"uF4^Ӽ[{eLN'Nv>tI+mI-h4}Ҍ=vdfhRZZ穌F\o/|$ƾ75tf G6l }%IH:u4S,25ͺJy|ſikjuWz{< Ɵ X )/OG)dM Đ/ć<> /| )VMuJՂh)Dln(yo"a?۵A +/&u/_UtO~ׁ>_,CHT>")eZH~ho]߾47t2X FMs~p-|z!l&3{ܣ$Ȇf~ ~y~^>kLʘ@Ǘ[k`D鐷:T|8 Q \j]s@RǤMfLXW}!YW/A B_[vO=RS&{ 5"!0|d ]?d⧐ ERm5wu\?XAG?rboJ X՜;%K*b ] ,Sox)ܾ+{OA.%$]\"~y]CC\S%U}+C:86U9n?Q)[Õ@%E" V2)_&S G}^&C~\`BǍׅƍÒ%KgNtQz EMeueN>Zo k2ڵ7 !{OEӆo|a] !oO>_ "%z_f T9D΢ЖZ*CnpB@Z *ˎdwkEǔ5:=?wVXaDm^g⽴E[f|8?Im\d7n`C.g:e]S,6:scZu@-ɯmn "0'mrip \iirsh]a,dtH>k(vڥ( !H6M*{ߥ0|Hl,)uv,ZV5 )IEǰZ li+Y:I9YMU  Sz$?=KfNHɲOj*]L#G.D]_u \]T]L %|A?3W=54[fi5.Eg<3$i{T lf9rMԶFo$r UbKXѿ} ܊(J1 W^PrMW|>hTe)MJntǬy{y"Dm_{@ (e&0lRJ3iyN>mTfjkF:L N'--%);]hȉa beu=KJ0\cpmv.ftg"mp{hw H)Rbz%Β0YV޸Aۻ׹D6+O%~1"8ʞZ7N"Jb0*{,:1+C:WY TI$z7<% (%qKM$x } $tGkTlqjURVT2ԮP6K V$T(f4&c,CmKKSYSTF{…Q|S#%`Be T[(E=E^$0R"X@ay}GӀ)Ww\_OB|((RQ(P"(P7Y*]=DANn_W W,yQjQa @b FmiWksztٹĬtJӴ"ǰ-^ٿ #~%Gx H{00NINevɹj{0Bn:SV<%)'{f س6ǥFx ,HP0BldI5|FH%] VCm4)-3UD착v+eZhCEu#'}~<^.[VVre5N^54/YK@B@C6>NW8sUqUa pHYs B(xtIME .GhKIDATx]yT՝jnM. (QsH0˜3I&3$x$9'Lr<-dO̸,N,M7tUWUwmoG<^WMBu׫WC k/PN^>;W^www܃8^hoo|B|xFr} !#Ka8*{hL*u"ypA}{0TU=$[ܪs pZ'K.= (  0 @ ;.s ^k+~4M}C5֘,"tG1@UUx*\.'M5%5n7r+Z`p.xq?}q?:u>Pb8D)L&eY0e"@i[QBI`;V&p&-RRz*p9gΜ?X<R RzRھ勐-UBV>} /$NyB U @%KvSJiv|CۓWB2Tv;akF8 @XBҺ'| `iol}pk /}u(YWkHx78Cݔw([>y0D _>;?lذ{ !!q_1vRJ_0 W |qꯧKJJ d];´%(?֣"-W.)=x-LGH ]]/%].wP @t:ڎ f3W1wwGxv9=nbkH/+|ビZk| k !pq\c4Zju?ٹ "|2`2fl@v?-r{_K4LbF3 ^me( S$E>>!O;=>A`A UgxzzC= <nmM~^vեwcsܷVhsQ gڟOOlfA:s HWI_l-=\9>g*r;uG^`ziDQwBCK Bb J̆4^b,ASiZ[kk|SOgL/XBțw=}]]Wt~Ι9[lI0ӽzEU7OˮMLRJD"ʺƗ~RsCCCa![!{?LZ7v܅_ 8/vh޽b?N+"}@a}&-L:wQY2 x׬YséNRPP09Է.0a3 Yg)&BTӴh4fI=g|9_jh4jMDB{;`0$p s7z_>e?=+AF1;6ev{#NrC$N jx$ٻ$Я~N9|k֬~Sz`Αi)H%H4ک( AAPUWviڻv YfMمg R#HDkU˺i8q"k׮(ºu.K(BH,)e9rj{n|p8f[ 6t6Te ?Ƅ͈Ѝ]!CKX&8yy:0:ny7oܸQ쫟}_EWjRI~/|_oۼH VWW3_"!<XH:cgb9s-uMe@m9o8 Hcudi xn]4BiZ}ԽT_ f򎜜QJ)aa4S G$IR}J:.D"&tnr3(2TkΟ?udEEEȶCَELZ뺾gǞ]] tOyGe PZWW͚d#TsԶC2bDm ΓiDl>n ɫVo4Lehbع a[FovMLbچ#u999S3r7:I]L٫@XXsvgrg*OX<((D" c:^ #'HoUV<8e|ít3܊4GDA2~C\ \`L}bYrZֱvlnnjnnGQO\ G7hH̺V%O>y-Bh ۱@B(@ b10nJ)2 $b#5 Ct]ިl<{ĉ>%hݻU5uJ%ˆjni]ƆYVH3K5l^ᚚcikzz^ yyycW^:t6:ykt0´7kjaR6 `#l@,++R"1 a(if:'=6MthavC1Buu,ü'n^kb-}ݜyX"6` ɖE q;FdQY*4lYacaS'e3F<@ fP S9rN dQ$IɩVWW-$:j7Xj. Ҕ勗U{Z àÖ;K;J5QQĆym۶-@b~ 㳙Mj>wBP t8mjYR[[K-ZN&BJr_g&'0y#1r=p)0I E DQ̟7oXYYΎZJPz3RQ~;!JƔnݰ6يtٳ'J"Yt]]Ἦمt9bbTm#HηҩDMe+"+b>6oqg=޾s3fWMЫh0.J{κ WW bvj4^4m$XD≥E%mmm-M-oh`55E5M420n>Uof vElY@MOV@wwwcCeyᤲI}0W]Ѓ3ԓjk*@6G T6l3f`m=_WWw=i _iTz-}{AHO&6ş{UUWh֝VU(A}HÖbfI͏m~fu 7|fj\1+ T@ɓ'i427/4$iDSFUUݫ'֫!B?THj>|7|{֜^i )B ~lm۶ u-wT^_%m5r!pawZ[H"A gQO&|{yleOSj>+bH.ߺZ+!'^|7N>{|>V۷O?|8wq{PXd F:::LGx\\|mLLIBD+v8)//'GnzQ*A 2_qb{k:?tJFli1ϕݠPh#'xro%OG/)0Mӈ԰, a[σ@Sպv 3N3T\樑_ p6HVeD} 5 KXhݬ;Sߙz$r@HSɏ\ AH'IR$I(tA'u(j0V"&lq2foHڲ~}6D\?`/ժ;G*CcȐ'q0^Nyb{b{ϗG(5`0X^vỶrnz7ٳx#k'r3:)d#@&H*vJxO{I@4%@ LMoޫlb90.:FP,[d L uGaI  D1uü vE<o tvE_4ʶvie"õʼe" 5U&L JaǎQBowGʩ((@{(i/m~`$ݟj*4 U0N=* ,arss+VSԑcyR4BeOkZtez_oD"{ᥕdP2xz"VcIy~ aD’%KrdYTi۷obϪۡ"oʶɵeLa,jD9J$IRCvc@Q{VcumKI`?'g 飷 "  lึp=5yG:zV\!qz  $۰~:w-y]U I""z?)2E\2iLur|>vξ(.1N\IENDB`refind-0.11.4/icons/os_bionic.png0000664000175000017500000001545613317720056017116 0ustar rodsmithrodsmithPNG  IHDR>abKGD pHYstt4tIMEgIDATxyT՝ǿzfFdEDpAL4ƉƉI$:l'GM&˘91qdT@@eiYizvQ4л@\w8t{ww_@ @ @ @ @ @ @ 㿳@)Ks(!6t?{*P{0Jд(9b9GvfjmQSU=޾1s2Rb5%Gir.ݞ#7/J?O疉9J2h4 [̍N!V:7*:j~ ?9~$ezd:ȩOB%6-)LMf ab־ Ps[;jc'+̡ ﹽ/CMu/?33;w{̉N%oo{"=04.ʨ %_/o?驚O֯*wL~'/ԦKcIɕRA%x#~$!H{jqƌ/KS+Ɓ< Ѽ(1l͞y70kcW(]ƙW}nj eXOF3#)ͶA8>[uSC:.3 ^-gkJ 졎]U8]OĬ_zJ,=N]78p:ΡCt Z7vnyhiKlcՖ} ͡_}[Q.y~U)ʽ3yxFRJa ,6 +K(T"?"K.M1z`{.1h7pɆtsEvK|bGYFl Ԇ,LL+?3GK;g[_ =]0H7$0ߧgZxaϻRҦ(0Α~L8.lGB4gVAPU!elD5!KDAW)O)Ź}g vGsI>H4@B ;[]?/K>%:c%_qB2Ƭ^䚣-]nݿPhEr;N*wDt Y+.=&#9ȓO贅fL@Vy Hj^ F ,4^#{m= NSw \N76[2ʔR}㘷 &`9Y9U@Nk \dh2됟{f^1O59vRDXB5h%OhSf5U.n8vap'qU jD]/? .7w#.Ho@ /YHtPԐwg=Ԣ,6F: :)ĔߨťS}sqcQ_ÑDCXg9O8 ~pe\-6Hvy@ I@Cb~*ƱG_YNˮN.a WK~Bd^7jQݼC1l\?Pp= m n jq 4','ȋ1n*kn @$Epg EW(3jC{&A}7dZ$|Uũ>M{h_.ss]@j{#`۟?@4R w1[Cx<rO!Q xm;o[^Kf2oY_J!}uទM1R}Mڗ݋ҙL:噅 ]`_基,6-fWn>wBIW BO|9@`<6%}Iv2E3>` g8TB#mD5ai`snvʂܫRԄhWgc*{U>7/ӑzu ?vF&/ |8oL_ ؖANF%#rIMQn K+:ݿPk `DE؋#b';W VJX?&5Z7GlT"> ML<%u/*}'wǺ1̢T!8q:E-.o(``,h?ȳڽln _9 w"m3Do hFZb`' 31k30KsB 1hmz F ߁}E3&ak7FjV{L{M4MD<rhZN}!c${lmHWM˂9ؽuSlOޒ?>`Np}✙ "$i䚵GM^ G`[M0;a$HyJ M=HZ=Xܲu#mz(l13NkVҗ^ӕ9|ρP|k_P Nv.X|SUjVoM_YM"FͿ]d\epB  )::i@-A4)<{402>(0{|A^2@OP>|W)1 8һ tR\t4B^vsYe dSɊֳahv1bɇZ~^Ch$8*Yw8СM]KsI^<9wQyKaA[|듘؜>B@H$B,gbq_DF^ن@LV\IIyUl?l< Y,x%0>;Sa}QasRGBbKGDD(M pHYs B(xtIME 4+CIDATx}ypי>  ) )D݇3,9*ɱXVy׎]"ʦx76ػ&Vl++9a"(D7A` 433yU잞~@kFkFkFkFkFkFkFkFkFk4 WhHq &`GdML|7mW@صxW2h'n#0%, QW~Cwh[FEлj+| CJP;cؕ hr@3JuM]K¹ xѦ(xt'"00f 1uH\%!]!a|" 3@t/˟ @`CP! \oÇϵ$@ @y iU (6P,2Ӗm볬yi7\e,*?? @]ص}(8y,|} 0LX%ch~C<@o߀r[*~[Οů~~S:-GX9$L[)u%r3C@ȃ+A; ->xZK|sQ[Qa_0< n@-O`]s?ņ@O wCa6/?=cK;p$@~ g:R3g-.O8nfM@ҬApM1".yT&y/>\txۧ;kfU<v#>.xg1PQԱe #e _TM:֬`)~O#yw}V#˾M'o~~ < <|fB3l۱y{/$Pgx/[ ~g ~l]tm*j7܍EPۻ H&x̻$szP1?$@m-} J*i uqgNcqhZqw1 Ⱦ$@ _B`;DoN ѻ(PrNѣ鋖sA$sï2{`:*>q_C(XğNFajsx`968oA6 -xT&3n046 C7p=0lmN'#hL)s`Κa!AnU<chPqRF>q 0/cHjX*u':`=z^oچ`8j%C&đW? autjfa ̮]&: !1:pKRv~'ʉw]Wg>{3ohZ>C/Jfb >C/<(uPxS]$d+h]JR巑0OFF_ ݻ<9j`z.7=:11Xfq‹ 07{,L`.62olloI>L)m[ڌ}V^ /HRqKDx}P@`(DGioq./eRfZm-[? HBU\FBƞ㓓.#H_ܺmFʜ_~0CQfzCLlK䧬+;S͛FyJ;"ۯ?9x^"' ocwx^|蝜1j+3Gd95L͍Sx{Eѻ;n'\C5h=IR'@> DlS3.2fc8i!l ,BHR C6^kuoxuAXٽ#IPJn9cLYO=. ;p?9꤮xm{fr޽cNW* Gׯk'A5<(I`9ߵbiwdcZ 5@/xcU0 ]J^_^ jq҈r5XH"~_An clvۺi7@·泩yM+;;wyS*8j9Dpk qxޞۣSʭ:wדӱ|~6N)q7NӊtÓH=Y:sm-cr|;U|幉XlH:}QN/ϴm=`J%SU9L?{nn$cj7…ߐp [2 I{5J,jsr:Z|avv8J"PHf3SDLr^ Е-zZr w]Ӕ\>?7L>61q𵩩o`+i:@J/$|&nrb|:3/' |b'h ZzyQ" 350Ԣ yYN4 g"|6ķBud<|.7-Ozy<P7NE|'׻ž],J%oG|N{|m?~u,ssscG`Wu&cqztNњ6K 8q@v=*v>@J,2|~ << gqF |0,&إ i=9{A,SNjYIiorٹvI@(K\vB/q%۳nݍ33#10޶j:=u"KDΡg?m؏3\>]L2c_s*u\WpH?雙t- ZHZ2;z8V4Mf'OYė6l.-@7XJ~rE|~6^,fg)AD|.c4!CUPU\:=5Rafd KW" ![Y@0YNƼXaǺz]R%qxud6/ciZ!ޯv#YX9ٵ<7ؠF*j)%5V;PA bXX̏TRܿ"6*d5wdYN꺮s֊|j܄7{2+S]"ÏPP(s Vd,@i3R>Tn5!!1BHh-%}hĉV#h̦ .YEKF, @ViԽ8BHP h}ARTӔ\u7Иw L2n4-[A. 2_k0 c ,ZY1 ƪ'Q0A$B>J$e_Өz;)Rē3,4]<]Q !`[–$xyӟҘ@$) B5Fqm!Z/E0ƌN4A~4fNAlwXi2fu=Kk) yd`(ԻWu6!ԣQT^Z_c/b.^y!gi$- n)Wn6&sCEh, Ifo<7 $oIj"*YXJbyISv̸ʥMJ=mCcb_ү0#]y3tEIT{il;v124y<ݫ܋I\煭Nb`?꺚d&ͯwe!(X[nggH;A <_]/O'&P}hJ `E\najyѿ^%I\ , }v CՀ1%SXT6*%'Q1X qKB@(?6<]u,la@,▾tzbQNQ22,g210Jq)Rϧ]Agy[+hkk+ߊCQү'c'4&t'ɳ'5MNV}>׷su |Gj0 930\LV6IlG>K$:V'XyNkm`YNLL9cZf2q5"# V)߿ŪCB„оΡDsXXŌo|[E+uZZ*<0^u9"I>P$}ht[lky>r&&~V8v-;A(iŪhmIO94`n qGWsU͟O$?Y($OL{Ocz@U"GO~J9o[Zχ ܵ]]Åx^]uIR[ǿoUV1J]x:8vs%@9P lAB>I3ӡ]ht-:;oظy[ jR;fLL PNp1gG2 bsBnT9\t\vֶ'80p=@Q*|^%s&?j5n+Z J|덴 w7 |;:u \htoq(% YB*8|d3Qw܏5r+?(nlk۲k͢m1,` o'sI;COn'BB~4-;?33ٹ,fI{_IX4`Vc@{4zpGǶ:Xlc sSC;⤮3ݱf'(v3F9\Mvv#ogcv?wRB!njo:}`t񌊟aғ a p| OC8 Xf \Q,s OOgqtϚf>u@bYjްYDkWMG8?DW-ϸ"$G 4-,98Q X:UdasRGBbKGDD(M pHYs B(xtIME-I IDATxwuUy"&`3@$D`HH&@I{,^J=g+[^^Zײd[H "`&OtNUo 0 Q8uS]]nn7vsnnMQ}G5j޻*1n|?%n*~ǣxqx pc)~.HF/"T?[ZBAYb] w8ʗ ; s2L)ٔÉ# GjjhuWԛ 0BAÊ2jG}ȎHxUXW Uw9AD.DNioOU( r70IgօW-7B@N]^.$k׮ 0lO+Q<"98ƸA;u+;DtivXJj~ Ȏ@ scmF%6"cM1 2 ^`⪕8V#;W#՟XKh ^EKJ'^+ ˀ/l]둤.I;Po烟3k}~}̿77?H?PB{l9֯? O]G7@"o h\|ta'FyT=3i Vn<"IU|n؊G޽{TǞYmd-|:)i{@Qh'PPӛ|c{ >kRq!2i3>s-@wr㸪~4O?ˉCc:nꛈxw{G*"9 3|v8Sy"2_kƢ Oix 9Ś@*Y-=`@vas4|D-H sqc>i$OwOz4xR>:>~R]#":F@ bf$ynq櫐JaFW8J6z>C4gU2 )^g{TrtLb}k$@J~=5+aŊB%'AsHCIwb6yRk<$߆*|PzY, ^ZOPrN ,< &4Ivq}O'vw{a = >eD+eܵSػ]`lA]kM]JH"fLls^-U˸H$]On|foT[4},GIx'஛̍A#ȎGJʸ;R5ydG5}Yl>%oB}ۏ f t|$xcwe@%&x'矰2v$GZl F j?lӱE,ω}й]tLAWLI?g-[U1M;< ujv\6\)vN .ѹ8ͯFK 1|f]x_XbE搦ҕ&N [ǹ=QQY2nΩ|6K4rHseȋf>i<Ν;('d@.>D3 Mb-čuj8m윋wyl 9l~7۰, #͋[ dSC|ԔGh;v* 蜀 pj9?xT>3<&7%LEhY€=rX04Q0" h¯ܙ* 8l~uA)uzNX _ncq߻H`&_oo.l ۷+Wf,@Fz(dFBN8wMPv N?,X?;̴dT8##i\ƤGgѹX1(+{Q_KU1TQz>9Aۦc|{ tgz]|Q$$=w߶mx衇T݊HdYϭoYeӟCmn i4r^]o}Icͤq :w]z(~B]L4z [o۶MdDelI&˝>%aekm"Ӻ U6P1p-v/$Y E8˧ڣ(;q[i!кNߩ:7֭[{޷nݚX@*{l<2m<$8݂0IB%J玣4z2tF_o鍽^lٲ$_og۲ex5^fEaeH<-KH֠._8LqVNr߉/]hNSR={ҶL}'{q{#<d,SgE݈:oJβDC|t@[[ik᛺HK^7(Gܦ Ј!Z7Azz=7o44%ݼyXjb:<kgMEv:.iu'!)Ӑ ~x&HJBt3.ͯBw?ߡ}R -_\2G )rh @} &H(lPtQS7I f q#w.#k.|6O{FS7MkV\*N sa)7d!>DыT̝p?FC)6f@hC(;ଞ $KS]rޡmQD׷zō@`L6 ~  ;#L,aOi{4sjyHa%DziS.t⬜I&ϡ$R>c>H @0Xt\mvgP *K f͢U#o1≮{;t-*DaxEY*N)I3~!JӮ Z](q-)~ЅL'L=~ŗ.]k_ z€2C@9Q{\*`-P(|b·͉J;(:?L$ qN9sXp)KHO~!)ip׈M?v6m?8H:z mblNakI ) !<ʑ4S?~w(~ TVV B q׏j($ TΫmMc>߹qƂ/qFzj 2CACݻw]KfX+RޑҢeqUO+ }~ڷ~B㤂~Cg7җ'MDee堠nW8|钴ikn||bϛo) L7w+sv|ɞ&" SKR.ٔs=L6I pl@-).y`f(f,SQv]wgp cmV9ERAR~/xk֬2Bڕd7xj@OC!v$ KB䲄 Z͡:_"qdS(P%zi{{7gz "=u`3=!If͚,V^v$9~z͚5 4$,g03$8I{ AR>19 Ơٳ\|/AӈjH!/Q[W$&!B O>d@<Ȏ%d1H=(y'xb# ^uL@Z=~/R>s,&]pn:L\A}?]`a]Y= lHrB},zi>x&_ջ>6WN| ɱtx̛t7O'^k&֮]}/Qw.4*! Fd]jk1Z<~O#|w}ɏQ`;=仑$cd)*d b~0+v ,bx+o]W_}UXF+;Fr z{a Bs*2QZH#yWt ύ]qjr0_÷ہJ$WTQ]pyWBirx(I6Pu7"ɋ{b7w=S+W^֭a4Ry|t.5lV.fQw3BLTˮ4 Իp/FvR, ȋ8sPAh4JRM!|ݺuy51(\Zn17YNs]Bch(ʵm$(7>}H?'4]:/wW6^g(ŒgtQ.a3"tnj]pAm `5]0ewz;q󑝓RN#hiOH򝑻WhڴinnÆ y|4~ HʳL|8M|j1=E k;PQgFd BzB*-3^t$94E.~ٰý?[]$7 jT,ۿذ\?x'Z8Ѵ4miqT4; n%)U _Eޡ dgueP6(9B1b;/9L[I$ 5ݛ~H(Cn:yN] |SLdoe1qŨe|{y)q߭4ge.bݝ_l.A Q4yvu S97d|/R1O~DvIiKUC$aKD64h%x˸>.hBJe$eU/`Q`0"%r-* =[I @nNUKR0~g zh2 ^^w";WI$vpϏ O1 \0|v}/O3$0p2Z9y$N"(}ZvsZZ2HIA:.xwjDiiTn+ %Fq^B6S8)Yć~g0jhT,cƭy0]JG33k,+Ym)ack7MMn:JӯvVS(/昬DIZK6YD3D,x.{&+T-HۭhHx'٘oQLH-Jb "_Ei?N.0|(% iyre]zuѰ)σ9Gw'Ϟ8˕-".[6R[ Pp\=G?1=%SUpK$콴ϐ<5QkL)$LB(5+$٘zU'cRh83,L1pfLb4rnT{Q#12U>?uز [ahK3'C 75!5{.pRQ| ǒ]!uɅvhXW#%W$T&?>W>NnppVKOgovɋ8y56@7]!7yxh1eZSHA mRQ&=Zf7i F+rj1"-'P#rg[Qdx`򌴝ݺP6K'q-@y\BMOX\/.+,@#%!Bi% aJkoxϕ??1ӗYXk 㽍5kH T΍IR=穘2#k㽧mƴ;9K1ΜGfIu0$S FE!Ҧچٌ[-d|j͸{w/2gSVխ6dec |d hE] h$c=Uh9Z7G> =[Ӻq7r0Zd({$wj6=y"[X mxmrit'i_]簈5 0_{1d3t @sKzl;tХ&#ڏDŽ/a?{7ײ!՘=Ļ:.גo*\IS([aA_~i|  Yǜ@{7_M+R,w 2Z݁ $9?ǤUXZ?J&ϡ =FJP_# ؞8s5cQ ʔշ㛼ty9 AM"3(]w+p~(yYcƒqRXPŒ&VxoH:fP TIDATb$ Wӌ$B{n| `JFi/NZ(sM'mڃ`wPwS9@;F gޙ__IJK,X wE[8gsT(D 3M^9lF:@ *U,a'O8{57͸|^~A*%q{mr>m7m5h A*Bh\F#䮁bcɘb)UxA{Q#ݸ3Y>*y]Lj}KiR(L\Uor N^F };2k18"QPc1M|tQ|Q~H?%x&mhc?Kܽ$Ca.QcҶ?h`SmWaTiv D&%GZҳ(j!I?8~ }Ƞul|L JkfI $v2X>i/|BǶaJ`c `YNt!6KocV=QV/q "XXE b`8ӛNv.򖉹᠈yJmknhP+ `! Dvv 05F}bL2On pn \@AŜL:hfH2Iw8q4ec*UX*dqA,hI:v6SJm=ga'eT+ˉN]" |=MM8]G-恢.1_K 4X?#<4L\^x}9$~ _+%LGgӭj̇\mTrp8T0CƑt_rm{&xcg6`oQ܆EǺ#h'2= ⧤0$C/(ZLB̯GŬ#;' alU,rP5B,ᵫ&#)"n^fm W";8:mN-ȐC.<:T+kĨ^PG [K_b2ve1nR2h$X%:wng132lG27Ia$>H##Q<\L~9#F Ke-F)ہN'UE6Dέ~rL%ue\Ssn}9ycڲÇH t1@R=N$ŝ7ѹsfl p¾RaA#:uIq\5P5|7 'B=O&q "9ܖfc6oZ+'.R !)_vգBņtѬck<Tm72y=?jmab FO|;BWr1JD{­ zM,!KњxFM&@ŘF.t#$ Ӡd}tB=B=dd@rcURcE0$-!$}5̋T JGG,oΜ?^T#:w"ނq3UbXMZȳ;̓STU@W}d7|*f][p:=.J BB3Aˬk:cuM*y5uLo-+tɧ+ w]%7 8+)55Bh턚Z?v@ gTdVY ZwZ z(8Ix aadw\M ϚAvzbtI$ R(Z"8n^|jNwB=*$Ł`|YTZ xO/n"=D$A2zAP48%iS5Pt |!Dn 8}Ϩde.|Sƣx}%u5!E*Gh)—H8Z"2i^6 |ЍE n(d* t |'%ZM*shdsy1C7N#7OBݍ0&: ^m3`J#wak>cĬ{&FFR+E Q\6}6[+q 3(t1'J?w2oq#]=d˦Ka Ot ӠC2Y JT5oLG2IENDB`refind-0.11.4/icons/boot_win.png0000664000175000017500000000726612626644770017004 0ustar rodsmithrodsmithPNG  IHDR>asBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<3IDATxSƟ)mb(Hh]uRVuJ `UWP̼?EAO >OìȠ tC}PTB.C>GP@.Sq000V&?F̓5UUt[-JH&b8;;CT$I,+?a?)ɲby8NXV0 ӉkYNH$ǑNy킼'˲lp:yCCCm5q/`0X,Q0L;AEX,|>>w0 f3a6ݜ)E>AF H&٩Z:df:99A:Zm[՛ulmmAEPmj(;lӓ$Io$IX__G.vsz$ HR}37Be?R) 2vvvpvvh: I ݵ݇*dYGs\]]u)=vIXpVAP. ?2 VWWJݔpvv<@ `ss;;;( nNبi( V<G"4nw_~[}9T5 k_rZ\.ǏHRuyPYquuu| bMjt:9th=HH###x@ oSb///|Ϟ=% fm3PbSvv6 &'I$8(Jҽou\Hh$8l68XVt: 4< 2 r~"H\y|}T rDBYWNF9ò,_ݼ=,baaF <OI懞^ $$f3zռ%?$I=[8L>|n\G 2"btu'JaeeSSSzM@؅m|v~%D@MEia,o'+x|PG$I M`dd8{a|5y`P/G}-$IBT捂 p:x=L&S_a97n}=k!2AP`6`0nXV?O}nՊ\.۷om\7$ T gggp8 ϲ,fffz630p\i&^vqNׯ_8==h5-e2"#"Ja||V+|>{{{J d7 YD- |>xkB!V0Qg30LX\\ H$b8;;k9U] lZj4vvE"@4EPPrg NO?yv鈬bM\^^| 2ʲp8SjCW²,x󘝝E6?\.Bpkb$Z:Ve%666P,iѨVE(bwwGGGo)d$|PqJT;Mx<?6<7AIpqq~ pez#anP<oʪh#YV+<>}3nP8Vne@DϟvPL%R `Pϡd(I <`Z;R( 1HibAeiļjX*6BP*9bhNS;T8N9!A:_Y!]G*Q,"ϕ_ATjNxmٍ=t*CrTʡP9T* @P*CrTʡP9T* @P*ӵqqZa*k؁7%~+#bIFbD*b [tff56ŢrQ"jJk[$ջ^njmIׁ*ǴI*X,JoY䐂m*R ü^/JC gZqex<-Zz8<NNV#&Iq_\\(ٻ///;RI8Ha`t:t:_D0b1X,*3C\` H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧ:. pHYs  tIME -YIDATx]rY*jgGhgw7w鎶[ vR U~|*BFP̓Y/X/$ ~0~Yo1IzAxsX8S,*IkYbHIJ,۶8Ae$IZT*uI4M;qNLw4t:bq24RT*4Me\ar(,Pnb*(Yf O$f\.slXVAȲ A\.S,IT*ZV.Ţ( I^bia&]dYjA`KIz(PJi@夅tVU(j YE$IAsXcUUu˲iؚ+XV>}icp#|k\FQ3`HX,DP;€JiOFlhM_AGx_(zJ2 F#\ 2VH`(=`z3h6EQ" `]%I"%n:}3H>,q8, nu]=||u0\?`(LqzrILӋ'?ZJ;88 Hf!hLuQ aXmfw=,i>VǛi Z^^^} Mv_1 :XL<=)Yn[bWj UxbX,5JGQ΂&g[˹Sl8< zZK;۶/_d>l`5yh!!8 HlX9,n~4N0m{<Og!$L&9aܧ$IiR4ZlEZ(ff @͛7Eض=8*Xi`U ,VFn^EP4 Cs\9㊢h4p-t@8n>g(޽38+FOzy^}"X,.@ٯfYV?8@X8f}x?;;SU50 UkZRA8??ǮSq۷$IhM kۓ1p@o`0ȸ?\V]Bxó_Pi$A%I$nF<޲ZP?qAFrYB~FR,p԰p˥iY<5M+R_bCoet*"OzUUUU?[:OYixU=Y/&;ڷ﫪 V=şꅽ^!;UU5 @EUU"e~A|mۀ8Ru8J?'7oxA_מg iŢVjJF);n(N@ϥTeYjZe]ׁ$b`leZx0}HZ%zRnw:y^u۶Tle Ҋ-;^wqqUyRX,*JR!5M%kE CQ}qs L}xv{ IDӴjJ;14+;Do&qd=UAx<~}FE]!*d첏/˫ prLP 5۳7ϡ@)4D kW&ò]kl1{)c00q7ٟVkX7M㵮B?HK -.[&&tZ.ISLn(lbp]WRlϟsy f'=ݮ8O6VUUFg[77a 6ORPpǶmurV#ûU|>̳27>~,,f>]4gܳz5){%2 %$p{Xht!.Y‚eY_|q]'bvcd2%!va)L,迪b(MX3O,(#$`A|\.gك䚦nΖgdAt$IAo%5I˩:5zs'l8.#ČԿnq-<|eqhͅHk r"Exr\.М;xߗ$:zY] >ӛ-]ʑ63)f  Ȓ=vZȃ;"!V{{+V'l=z߾}cy[m$ITU2/HuߏWz@JaIlc( kL&(:rpYz^vXq?8ﯿp280 bi'c1J4 8TAؚ?d+)P2ę؞Y84bQ*(i&A8>7 z\&r i)3 TISTPRᘹ0ff(&@m8?BM'Iv\Y?u%Q{6P pkH,b^G x# EQ0e45@6Z(=L|WZR |l<ًzj`XQFQ(H)QVȏ‘PPk1V$h IRtjR(7 c+}qƮW0 $X,O 1 "vjn&?ϑl!ӿHq._دQ([= dj}R4}5@"E16:T4T`#)+!A\ِS/]L![,O br fh[?,ڳCye ON1\+}ބ8۹pGBdٻ@:eFNssݧZf7IROR\( @YE|$ ־<x1=;pK¤@ ƒH {qjBOeY4tqeQOeh!AXD`|CpwƖe6xWV19'vVeYL:heOdG( fݜcE/J,q@@ 7oތcP[){C׏@q(NxxgggWWWD0L1Azr* = d2Nh *J;Ty%Йef3˲O?tx3$ =|p*:0{l^__?kh 6a x:_O!knKi/ppt&Ɂz B1 _VNׯMc< Z_fUq׳mǏO>km:x"$l>ISj|qNn0~ML a;fY~8{`aw,;}j0}dv8n+˕X`@Aoooo?"|h4e' 3&yqm5}lJmYV)YYp)tzy?]svfaԮv::{0 { ENG8^y.5ضGΠ8<=1Nw! z4Z\.i^jxLt$qNv; BCHy}JIM]WǦi꺾C_M~;7/3 \tӼb=o  x/A|& 0m ybD8 s ~EDf3 ʛ(Nvv$ǭ%v,*;~p W=QTR!dՍi†(4Mz7CeͭT*/Y)uN6@}DH@"43 lDGCEuFCљ4T*&$~xWNT> t7f `hayx=7LCaYu]8, =Cͣ݌G^r:Q^{ߩ( = #?<`EqBOьa Pzand">N/Q q}kyG"Xga; `噔f[׷-kX71G9?99x¿ |&IENDB`refind-0.11.4/icons/transparent.png0000664000175000017500000000032512626644770017512 0ustar rodsmithrodsmithPNG  IHDR szzsRGBbKGD pHYs  tIME 5F iTXtCommentCreated with GIMPd.e,IDATX1i3$`晀@==IENDB`refind-0.11.4/icons/func_hidden.png0000664000175000017500000001577113140467467017430 0ustar rodsmithrodsmithPNG  IHDRZZ8AbKGD pHYs oytIME 70IDATx}y|\ŕWu]{k,YE;Y؆a ̄,,3G& I!L-`8x"/Z,kZwGוZ-X&3.ݷo[SΩp\, ;h8lH DZ/go*ғ@m'.Mt - \BEBƘ!ij/=4y#CF.=@;Nz)g֝3EkUTr=g1 4OW"tx>:ͼƟ-k@EcЮ}.kڍG@fYpËKƭD0@T#LIhK9@TÔ𯳦_lrG[v9n*پ WcQv@z3O/6kDkD03M=|3.dqк6eNJBǻCZm`o)mיҋ~Hrfkkl<,5)?%TXh$&/L%TPѪUWnz12@8RDvB >/,-yG=5Hs1K=c j*c 3lou1?c|J-ϴC (2?EU>\=9d(P')}w.u`jڽ# @V@:Lf~Ԍ%=0T)\-Uu{_@ mhͮ`Y={'f WMM}b9yZi^duzhʘuȦ@Xkk.n2YEGѲ\- 5})ƑxnU?g]%~#Jۉ`ٟ}~#[+yT,w?X˖QrPq!kzADc?yDV%{a_PM/˖6>9q[āUGKq ׎ȌzܮsLŃ*P%{]}%gڽT|Pa0)t%yũk<z@ XE3[%~AarnAõ ٰ)[%PiT-"0dQ_g_~Տ[eZu#)e_m2g?Gj<(yC[|SZ}]}>vsՠ$q0Tq}]7o/KA#/bCkn BGWR&^4 s`^Hp)@7yTEPa*,FbI\\*B1]H7R 4n{hdx=4f1Gr7[m;q`N& fq{.u$ambBt VPÓ\3WfD\LjtU{c@?aM.H#T*6*Z2Jsێ;Q8l hH](-q=Δ<I 6qřͽG^\:YTyLuמ|d]ѨDEoֲtMSZ䰎0t[[_U;i(N:cpPӮb锜&Y$F0"Շ6:&QB7oPuvC O Y铲p^<7myk?Fde +*{^I jjrH%< ڟuk'!ƫ4U|jk..XL3Ai5J!wP J[ w1q%_uO,¦sՊ#=*3мw=OبSѴWDB.18Vo;A*vo }?3b˲?걘rpuuУbXUC$֦)" %j7w`hqdfp{?0prmkfh&=dLjhɜlԩc::ˇ}7LVN͝ g3|ҙEJBuh=`ҁT|f,\p fڒK .~Z\ =̂%kFa$䱌Y&<¥N7 5S级oh?תل{ׇ {S7*"DoϋW>TELiZvQFPfcld#wI{m`4'I# R~)b|4/uJSh]Sc*@m֭\qVo*!)2 W2&y-HV8tCd'4v7i ]nztڼi+W*Є%|*يzQ_Nm˟w#цrg55c`Op} s&~Meġ,Q߸&w`ɘͬ=xݣTٝ&-gE;fi[t} u5{(.7hph$ZoݚQ= d,n @zaL׋r/i\:9]{,r)4J<2߹"PrC;q'%yG[[x\')Mz!j o;>0Tif~-\>+xTkJE79:ЅxF N*X:#Bj mEݵ]/%m-`CFC5DAIBx vt/K[\GU4LI=eZ贔"R f)HLp l 4Q#pO^&)}jq;2ڈut)1Tj;rMD6@@9ۺJNwMYԞs&LG%ڬ12|Mg]Rj[+5L*}8ThM"¨aKt8lաu(ۏ;-:Yn"Txu}*^%Tz{5 YWX2$+H"ynqiD )9Ӗ 7|kc)K>g']_B:FCe xaH=;rsfTJ!Ti!Z6?:F[Tfƹx%RH!'"olwY:ijL 1RCX՟Iԯ9ӫ$9w ; h9"\n RLLJCz:XtIcb"w@v8e%2൉  ~́ <21$w`ZEW AOn:ظ睽f{Dy/_k=&*OF:Gӥx{49}:ץL7rGeE'ianuޑ?̴9T'TMp5g ~}5վյ K-|:nrO6FZ_u{k\y9#-d`T͵ӏcCF?1hrngHIΞoT0G|D813 J8=+gGBhY/6#hcJOq$:3/#Wx?P}ON ķŌVS"~I$FFOשiWس&>HDpUB3;6zi؆ޅ)L)xNrpL jfL]ѱ%%4X\t! <>¿wgFc'.y<Umÿ*JMeA jicX{7;4qϒ75+qW7گ9l}73(`TB#̹W|m08Ib¡rҬ~`bJKcD߄ ZsLdBR!q^ݽ]XS,˧,KV:gZ6sqZrj`vYFauv&G[cL+PA(ɚ7Nu%jM]rtOU!*)XO n/_%?b(u!P$tViM/R Bsb sciN l};D^pkˋ#yEfJ 4@"c[e zMÅ[5`]fXHSVIENDB`refind-0.11.4/icons/os_gummiboot.png0000664000175000017500000001676412626644770017672 0ustar rodsmithrodsmithPNG  IHDR>asBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<qIDATxyTe߳ waSsTg.e[)f.(.R!S4+%K (-74 ВY:3<3y93ϙ;s}{Ι3yݞy"bq^nX-< QG?(rQ{<{Ͽ~O1 Jd3gyoߧU!4>)2!|s@2|Уa|j&Ht2)0c}E>@80>$ׄ9 - /֯t5k[7[m3>a$ w]`p&9}<Ȥ`M|޼Y -S`ׂ`z&@Oa!p0ؿ:Rqw tJxXp-`m …U|E A$Id0_}>nK`pA |$"jKԫI{ ( hx~4<"2n_8E6uP@SggIRw8x-2 |?\&D()PG0HUR Жy6}g& 0RG`?Rmo?SR }`AI jplӱS nBt}Ygz`{ -(!ǀwo!nƽK~2E3 PFa9oaM'z?OǏ(37S_'cxkCp;bx d> :r ؈@AMH(6I;dƏB"'Dg>>p6" p8s+> lJUKE`}}W?;fR~^cW/oE87؃`+ ]Łt0= ^~`vXN?ޥD2\x͏pN R8<0 1GϨ qOk[`r8wv JӁ󀹎$ 1 >+8 4j0: ގ-YoףI=T `/`'D5 Q9?AUKb o7@WE5w^vEdWzi? q$g䤀6DU6 }`ksCW Z$ "J@rc~SX Jw90;0Yx.).2K!u08po#K̗Ow鱂 HMR!S !Cc}^8=bX !ѾGJ MzC[!!LJ@r47` JzQK:7˺72fPO3ULs7 DE#Iv e7R 1R/mUX3 PTlKp\\|<* H~?^*( з#-^^A/F## 8^GtДU \T@dVJb C8će%iU[Wvឬi}Dԅi$Lt<>qJ&D6䩁HHȬ+oMV:N`,#tƪ[0p|a j bb({k]~UA#Ɏ!q +lFea P1 LDR&#ij9Y"8 E {0`X91MU# Gb.H5'a=! 6X`.G#zpNc;?6miY), )7J$5FW+# 1~^2״]TVwO$g}j#O@rO%˽HlcxXOE y@ǰ:JH Wo))D8w̍b9{mLHθvݬ [ LWABTp&s91"BBjQR+KMGlNDt.%5G}Qבj@:O1}4R@0/(&W{]: &!.䮰%V .UZ q9vԚ#2/qZhx| b?7-i!ZQȺϾ/fT q^ ,Wk9h2KԊL=H4l3&;\mHU5j#u7~" LNOyҊnEķ2 >՛8RPKKB}EЀ8/AUd4jGOC1x0i  TÌ7d\ 6ch垃=Ќ4~<C9v.B#N(:!0H"-ȲIY.*([ mjY8y|F.4jU ]8埉p-pV" .iC_+ov2A@ྌFQR/qkT[p^Onw8P1ST.Պ@xۧv:p1ux! -abCc`0 t} 1+:&^x| :,Dh(TTdz k.=DVv߰nZ0Z"H?#:|{ANɿ]CyU2nz/o^|滪Wqҟ{NNHx[$hk;; Yl/dr$@;t~(08^J ?KFܣ!vMMB4qM(R|%ufPF9 TYTφhћ%=BDCOApk=EnHYjA@YszU>ao,s<>$p"P["0CA0Ls^X_B ΣDuwеv_\ %I˪ oY]@`:L&m_8ulK ,R@7vh-K(lZ.%> ن|a'g󈞠Ҝh 0* `KkdXTA^6[w"!;;B l tIt)6f{>g_deЛioD 6^HA% AUȖ? m Kİ(]_l7S` %ApV] AK0]wHJ\d]*8w`lZ^J"ڀ#Wm6KxUzQk#UDaou9Σ%Hl8)D{m;PT!Dú(Wv`Ra@߁*?a"H4viF|7H<~@i]TSS3BqF 5WFV ; )Lea_UMjY8?hse\++!>@w5r^EVTpO~/;{n&.kf.b&U~hP 0sπݨwB6vqoCzG8'Vy6DV]FZXa>!6/CDS:=7e4?ʟPTB51Gqh.,[o 'AA6!x/$KmDw$ \_ :“I}vN~U;z)8^fgIRbl8!oNB:y#a3\y]P'b\[ڹ/K^`hGUZ@CJw! Jijd~ ZQc;Fm-MTc㖓ajƱ$ZXL:Jn`DXDΕw0|Q#jW_+=9Lpg`b5qWRX)k{qrօkeV\#m??t]>u5+m2ՀY{=zzYZcx(n ,qX$X?ӞvwvHIef2`!X52Yۿ(f#v8[㭅)h &Et8"&7Q?H8wқʓ`;Wpiц- uEM"!TgNzAC|:N=o/HծA!mkA tmtwYب6pojmJ) Ůͅ3egU1bh(Ro0i7yQipMK x \ә$uEC$qn)F7hB~4hN7uWhtwd>/B&2{BJ R;9-GD?p:-e C1_ }f?t]e)Fn4Y=ti@:C%VGi: mCA8EMp?u'6ΟOjguC&QGYjͿ2F:\iaBGv%o۸4fJCux`g<}`]|(O0C$H%U geY{`-l8H9#FJC&x p y6 6~7~%u tf :<jEYQh=3޿j)I^y2@E̜Y_쇮 T^}&mCB f@*?FD͓ޠ:ۏ1{0 Ӑ<{Ꙙ%0Q|l?s sj A$ۙMW9h cbݛҐysɠzrOKQ`P9w$uʿ݁}G .ҿ QYʣ*I)H!5\*m(ƛkGyR{ a&6@+ uI|}\xKK"xxQ}a{+k{..z`'-C|vVҦ 4@D9][m"?Y _i!=Adr1Jffݪ7G@?2s4mC{O_A 1-N+Ģw1^Y_ׅJXgq"}oj7 KN%4Mᤑ%2 aх/:͘-b"ߤ.BK լ&B-[SFLR옆L2.T?kgaۻVP@9_*҃(/sGM]"4}4Ò]ߤ._zU3|n {ΔfY@F>  4]w`Ӂ0 VhkuMX(,KڃF}}L^]gIw0 ;*-)eM`ЇT6]m_ޚ/lNLEwb{@AMS6pQo |_=2uY@ Ї0;n$]O+zj H_BokA,:읞d>U|Om̷cKxug^E@9l[ڀԪZ+uPSE}Sd[ZN2^`\,IENDB`refind-0.11.4/refind-mkdefault0000775000175000017500000001600512707000055016457 0ustar rodsmithrodsmith#!/usr/bin/env python3 """ Set rEFInd as the default boot loader, using Linux's efibootmgr tool. Copyright (c) 2016 Roderick W. Smith Authors: Roderick W. Smith This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3, or (at your option) any later version, as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . """ import os import shlex import shutil import sys from subprocess import Popen, PIPE from argparse import ArgumentParser def discover_data(): """Extract boot entry and boot order information. :returns: boot_entries, boot_order """ command = "efibootmgr -v" bootinfo_bytes = (Popen(shlex.split(command), stdout=PIPE) .communicate()[0]) bootinfo = (bootinfo_bytes.decode(encoding="utf-8", errors="ignore") .splitlines()) boot_entries = {} boot_order = [] if len(bootinfo) > 1: for s in bootinfo: if "BootOrder" in s: try: boot_order = s.split(":")[1].replace(" ", "").split(",") except IndexError: pass else: # On Boot#### lines, #### is characters 4-8.... hex_value = s[4:8] # ....and the description starts at character 10 name = s[10:] try: # In normal efibootmgr output, only Boot#### entries # have characters 4-8 that can be interpreted as # hex values, so this will harmlessly error out on all # but Boot#### entries.... int(hex_value, 16) boot_entries[hex_value] = name except ValueError: pass return boot_entries, boot_order def add_unordered_entry(boot_entries, boot_order, label): """Find a rEFInd boot_entry and add it to the boot_order list. Run if the boot_order list includes no rEFInd entry, in the hopes of finding an existing rEFInd boot_entry that can be used. :param boot_entries: Dictionary of boot entries, with string (hex-encoded number) as key and description as value :param boot_order: List of boot numbers as strings, in boot order :param label: String used to identify rEFInd entry in efibootmgr output :returns: True if an entry was added, False otherwise """ added = False for boot_num, description in boot_entries.items(): if label.lower() in description.lower(): print("Adding Boot{} from boot options list.".format(boot_num)) boot_order.insert(0, boot_num) added = True return added def set_refind_first(boot_entries, boot_order, label): """Adjust boot_order so that rEFInd is first. :param boot_entries: Dictionary of boot entries, with string (hex-encoded number) as key and description as value :param boot_order: List of boot numbers as strings, in boot order :param label: String used to identify rEFInd entry in efibootmgr output :returns: * -1 if order already OK * 0 if order adjusted * 3 if label was not found in available entries """ first_refind_number = i = -1 retval = 0 found_first_refind = "" show_multiple_warning = True for entry in boot_order: i += 1 if label.lower() in boot_entries[entry].lower(): if found_first_refind: if show_multiple_warning: print("Found multiple {} entries! The earliest in the boot order will be made".format(label)) print("the default, but this may not be what you want. Manually checking with") print("efibootmgr is advisable!\n") show_multiple_warning = False else: found_first_refind = entry first_refind_number = i if first_refind_number == -1: if not add_unordered_entry(boot_entries, boot_order, label): print("{} was not found in the boot options list!".format(label)) print("You should create a {} entry with efibootmgr or by re-installing".format(label)) print("(with refind-install, for example)") retval = 3 elif first_refind_number == 0: print("{} is already the first entry".format(label)) retval = -1 elif first_refind_number > 0: del boot_order[first_refind_number] boot_order.insert(0, found_first_refind) print("{} is not the first boot entry; adjusting....".format(label)) return retval def save_changes(boot_order): """Save an altered boot_order. :param boot_order: List of boot numbers as strings, in boot order :returns: 0 if there were no problems, 1 otherwise """ retval = 0 order_string = ",".join(boot_order) command = "efibootmgr -o {}".format(order_string) print("Setting a boot order of {}".format(order_string)) try: Popen(shlex.split(command), stdout=PIPE).communicate()[0] except: print("An error occurred setting the new boot order!") retval = 1 return retval def main(): """Set rEFInd as the default boot option.""" description = "Sets rEFInd as the default EFI boot option" parser = ArgumentParser(description=description) parser.add_argument("-L", "--label", default="rEFInd", help=("The label used to identify rEFInd (default=rEFInd)")) args = parser.parse_args() if sys.platform != "linux": print("This program is useful only under Linux; exiting!") return(4) if shutil.which("efibootmgr") is None: print("The efibootmgr utility is not installed; exiting!") return(4) if not os.geteuid() == 0: print("This program must be run as root (or via sudo); exiting!") return(4) retval = 0 boot_entries, boot_order = discover_data() if boot_entries == {}: print("No EFI boot entries are available. This may indicate a firmware problem.") retval = 2 if boot_order == []: print("The EFI BootOrder variable is not available. This may indicate a firmware") print("problem.") if (retval == 0): changed = set_refind_first(boot_entries, boot_order, args.label) if (changed == 0): retval = save_changes(boot_order) else: print("No changes saved.") if changed > 0: retval = changed else: print("No changes saved.") return(retval) if __name__ == '__main__': sys.exit(main()) refind-0.11.4/refind-install0000775000175000017500000015635613372346054016202 0ustar rodsmithrodsmith#!/bin/bash # # Linux/MacOS X script to install rEFInd # # Usage: # # ./refind-install [options] # # options include: # "--notesp" to install to the OS X root filesystem rather than to the ESP. # This option is valid only under OS X. # "--usedefault {devicefile}" to install as default # (/EFI/BOOT/BOOTX64.EFI and similar) to the specified device # (/dev/sdd1 or whatever) without registering with the NVRAM. # "--ownhfs {devicefile}" to install to an HFS+ volume that's NOT currently # an OS X boot volume. Valid only in OS X. # "--root {dir}" to specify installation using the specified directory # as the system's root # "--alldrivers" to install all drivers along with regular files # "--nodrivers" to suppress driver installation (default in Linux is # driver used on /boot; --nodrivers is OS X default). # "--shim {shimfile}" to install a shim.efi file for Secure Boot. Valid # only under Linux. # "--preloader" is synonymous with "--shim". Valid only under Linux. # "--encryptkeys" password-protects the Secure Boot private key. # "--localkeys" to re-sign x86-64 binaries with a locally-generated key. # Valid only under Linux. # "--keepname" to keep refind_x64.efi name as such even when using shim. # Valid only under Linux. # "--yes" to assume a "yes" response to all prompts # # This program is copyright (c) 2012-2017 by Roderick W. Smith # # This program is licensed under the terms of the GNU GPL, version 3, # or (at your option) any later version. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # Revision history: # # 0.11.4 -- Fixed generation of GUID when automount of ESP in use on Linux # 0.11.3 -- Added support for ESP mounted at /efi under Linux # 0.11.1 -- In Linux, be less aggressive about replacing existing NVRAM entries # 0.11.0 -- Create BOOT.CSV file and option to encrypt SB private key # 0.10.8 -- Enabled use of shimx64.efi.signed as Shim source file # 0.10.7 -- Added mm{arch}.efi as equivalent of MokManager.efi # 0.10.6 -- Improved identification of the root device under macOS. # 0.10.5 -- More improvement to handling of disks (other than /dev/[sh]d? disks). # 0.10.4 -- Improved handling of disks (other than /dev/[sh]d? disks). # 0.10.2 -- Improved Secure Boot detection in Linux, fixed --usedefault in OS X, # and fixed bug that could cause mountesp to be installed as a FILE # called /usr/local/bin in OS X. # 0.10.1 -- Improve extraction of default kernel options from /proc/cmdline. # Add support for AMD64 (aka AARCH64, aa64) platform. Added # warning when --alldrivers used without --usedefault. # 0.10.0 -- Enable running under OS X's recovery system & add warning about # SIP & brief instructions on how to deal with it if SIP is # detected to be enabled. Also change way refind_linux.conf default # options are found; use /proc/cmdline as base. # 0.9.2 -- Added --keepname option. # 0.8.7 -- Better detection of Secure Boot mode & fixed errors when copying # Shim & MokManager files over themselves; fixed bug that caused # inappropriate installation to EFI/BOOT/bootx64.efi # 0.8.6 -- Fixed bugs that caused misidentification of ESP on disks with # partition numbers over 10 on OS X and misidentification of mount # point if already-mounted ESP had space in path. # 0.8.5 -- Refinement/cleanup of new OS X ESP-as-default policy # 0.8.4 -- OS X default changed to install to ESP under /EFI/BOOT # 0.7.9 -- Fixed bug that caused errors if dmraid utility not installed # 0.7.7 -- Fixed bug that created mangled refind_linux.conf file; added ability # to locate and mount ESP on Linux, if it's not mounted # 0.7.6 -- Added --ownhfs {device-filename} option # 0.7.5 -- Fixed bug when installing to ESP on recent versions of OS X # 0.7.2 -- Fixed code that could be confused by use of autofs to mount the ESP # 0.7.0 -- Added support for the new Btrfs driver # 0.6.12 -- Added support for PreLoader as well as for shim # 0.6.11 -- Improvements in script's ability to handle directories with spaces # in their names # 0.6.9 -- Install gptsync on Macs # 0.6.8 -- Bug fix: ESP scan now uses "uniq". # 0.6.6 -- Bug fix: Upgrade drivers when installed to EFI/BOOT. Also enable # copying shim.efi and MokManager.efi over themselves. # 0.6.4 -- Copies ext2 driver rather than ext4 driver for ext2/3fs # 0.6.3 -- Support for detecting rEFInd in EFI/BOOT and EFI/Microsoft/Boot # directories & for installing to EFI/BOOT in BIOS mode # 0.6.2-1 -- Added --yes option & tweaked key-copying for use with RPM install script # 0.6.1 -- Added --root option; minor bug fixes # 0.6.0 -- Changed --drivers to --alldrivers and added --nodrivers option; # changed default driver installation behavior in Linux to install # the driver needed to read /boot (if available) # 0.5.1.2 -- Fixed bug that caused failure to generate refind_linux.conf file # 0.5.1.1 -- Fixed bug that caused script failure under OS X # 0.5.1 -- Added --shim & --localkeys options & create sample refind_linux.conf # in /boot # 0.5.0 -- Added --usedefault & --drivers options & changed "esp" option to "--esp" # 0.4.5 -- Fixed check for rEFItBlesser in OS X # 0.4.2 -- Added notice about BIOS-based OSes & made NVRAM changes in Linux smarter # 0.4.1 -- Added check for rEFItBlesser in OS X # 0.3.3.1 -- Fixed OS X 10.7 bug; also works as make target # 0.3.2.1 -- Check for presence of source files; aborts if not present # 0.3.2 -- Initial version # # Note: install.sh version numbers match those of the rEFInd package # with which they first appeared. RootDir="/" TargetDir=/EFI/refind LocalKeysBase="refind_local" ShimSource="none" ShimType="none" KeepName=0 TargetShim="default" TargetX64="refind_x64.efi" TargetIA32="refind_ia32.efi" LocalKeys=0 EncryptKeys=0 DeleteRefindDir=0 AlwaysYes=0 # # Functions used by both OS X and Linux.... # GetParams() { InstallToEspOnMac=1 # Install the driver required to read Linux /boot, if it's available # Note: Under OS X, this will be installed only if a Linux partition # is detected, in which case the ext4fs driver will be installed. InstallDrivers="boot" while [[ $# -gt 0 ]]; do case $1 in --notesp) InstallToEspOnMac=0 ;; --ownhfs) OwnHfs=1 InstallToEspOnMac=0 TargetPart="$2" TargetDir=/System/Library/CoreServices shift ;; --usedefault) TargetDir=/EFI/BOOT TargetPart="$2" TargetX64="bootx64.efi" TargetIA32="bootia32.efi" shift ;; --root) RootDir="$2" InstallToEspOnMac=0 shift ;; --localkeys) LocalKeys=1 ;; --encryptkeys) EncryptKeys=1 ;; --shim | --preloader) ShimSource="$2" ShimType=`basename $ShimSource` shift ;; --keepname) KeepName=1 ;; --drivers | --alldrivers) InstallDrivers="all" ;; --nodrivers) InstallDrivers="none" ;; --yes) AlwaysYes=1 ;; * ) echo "Usage: $0 [--notesp | --usedefault {device-file} | --root {dir} |" echo " --ownhfs {device-file} ] [--keepname]" echo " [--nodrivers | --alldrivers] [--shim {shimfile}]" echo " [--localkeys [--encryptkeys]] [--keepname] [--yes]" exit 1 esac shift done if [[ "$InstallToEspOnMac" == 0 && "$RootDir" == '/' && "$TargetDir" == '/EFI/BOOT' ]] ; then echo "You may use --notesp OR --usedefault, but not both! Aborting!" exit 1 fi if [[ "$RootDir" != '/' && "$TargetDir" == '/EFI/BOOT' ]] ; then echo "You may use --root OR --usedefault, but not both! Aborting!" exit 1 fi if [[ "$TargetDir" != '/System/Library/CoreServices' && "$OwnHfs" == '1' ]] ; then echo "If you use --ownhfs, you may NOT use --usedefault! Aborting!" exit 1 fi if [[ "$KeepName" == 1 && "$ShimSource" == "none" ]] ; then echo "The --keepname option is meaningful only in conjunction with --shim" echo "or --preloader! Aborting!" exit 1 fi if [[ "$KeepName" == 1 && "$OSTYPE" != "linux" && "$OSTYPE" != "linux-gnu" ]] ; then echo "The --keepname option is valid only under Linux! Aborting!" exit 1 fi if [[ "$KeepName" == 1 && "$TargetDir" == "/EFI/BOOT" ]] ; then echo "The --keepname option is incompatible with --usedefault! Aborting!" exit 1 fi if [[ "$InstallDrivers" == "all" && "$TargetDir" != "/EFI/BOOT" ]] ; then echo "The --alldrivers option is meant for creating USB flash drives with (near-)" echo "universal boot support. Using it on a hard disk partition runs the risk of" echo "creating serious problems, up to and including rendering your computer" echo -n "unbootable. Are you SURE you want to proceed (Y/N)? " ReadYesNo if [[ "$YesNo" != "Y" && "$YesNo" != "y" ]] ; then echo "Aborting installation!" exit 0 fi fi if [[ "$EncryptKeys" == 1 && "$LocalKeys" == 0 ]] ; then echo "The --encryptkeys option requires the use of --localkeys! Aborting!" exit 1 fi RLConfFile="$RootDir/boot/refind_linux.conf" EtcKeysDir="$RootDir/etc/refind.d/keys" } # GetParams() # Get a yes/no response from the user and place it in the YesNo variable. # If the AlwaysYes variable is set to 1, skip the user input and set "Y" # in the YesNo variable. ReadYesNo() { if [[ $AlwaysYes == 1 ]] ; then YesNo="Y" echo "Y" else read YesNo fi } # Get a passphrase for decrpyting a private key, and store it in the # KeyPassphrase variable. # $1 Set to "--no-confirm" to skip passphrase input confirmation. ReadKeyPassphrase() { if [[ $EncryptKeys == 1 ]] && [ -z "$KeyPassphrase" ]; then while true; do echo -n "Private key passphrase (no echo): " read -r -s KeyPassphrase="$REPLY" REPLY="shred value" echo if [ "$1" == "--no-confirm" ]; then break else echo -n "Confirm passphrase (no echo): " read -r -s echo if [ "$KeyPassphrase" == "$REPLY" ]; then REPLY="shred value" break fi fi done fi } # Determine what CPU type and EFI bit depth we're using. # Sets Platform global variable to lowercase EFI platform code (currently # "x64", "ia32", or "aa64") -- the same code used in filenames. DeterminePlatform() { local CpuType case "$OSTYPE" in darwin*) CpuType=`ioreg -l -p IODeviceTree | grep firmware-abi | cut -d "\"" -f 4` if [[ "$CpuType" == EFI32 ]] ; then Platform="ia32" else Platform="x64" fi ;; linux*) CpuType=`uname -m` case "$CpuType" in aarch64) Platform="aa64" ;; x86_64) Platform="x64" ;; i?86) Platform="ia32" # If we're in EFI mode, do some sanity checks, and alert the user or even # abort. Not in BIOS mode, though, since that could be used on an emergency # disc to try to recover a troubled Linux installation. if [[ -d /sys/firmware/efi ]] ; then if [[ "$ShimSource" != "none" && "$TargetDir" != "/BOOT/EFI" ]] ; then echo "" echo "CAUTION: shim does not currently supports 32-bit systems, so you should not" echo "use the --shim option to install on such systems. Aborting!" echo "" exit 1 fi echo echo "CAUTION: This Linux installation uses a 32-bit kernel. 32-bit EFI-based" echo "computers are VERY RARE. If you've installed a 32-bit version of Linux" echo "on a 64-bit computer, you should manually install the 64-bit version of" echo "rEFInd. If you're positive you want to continue with this installation," echo "answer 'Y' to the following question..." echo echo -n "Are you sure you want to continue (Y/N)? " ReadYesNo if [[ $YesNo == "Y" || $YesNo == "y" ]] ; then echo "OK; continuing with the installation..." else exit 0 fi fi # In EFI mode ;; *) echo "Unknown CPU type '$CpuType'; aborting!" exit 1 ;; esac # case "$CpuType".... ;; *) echo "Unknown OS; aborting!" exit 1 ;; esac # case "$OSTYPE".... } # DeterminePlatform() # Abort if the rEFInd files can't be found. # Also sets $ConfFile to point to the configuration file, # $IconsDir to point to the icons directory, # $ShimSource to the source of the shim.efi file (if necessary), # $ThisDir to point to the directory in which this script resides, # and $RefindDir to point to where the rEFInd binaries live CheckForFiles() { # Note: $ThisDir points to real (not symlinked) script home on Linux, # enabling creating a symlink in /usr/sbin (or wherever); but on OS X, # "readlink" doesn't do the same thing as under Linux, so the script # must not be a symlink under OS X. case "$OSTYPE" in darwin*) ThisDir="$( cd -P "${BASH_SOURCE%/*}" && pwd )" ;; linux*) ThisDir="$(dirname "$(readlink -f "$0")")" ;; esac RefindDir="$ThisDir/refind" if [[ ! -f "$RefindDir/refind_$Platform.efi" ]] ; then echo "The rEFInd binary file is missing! Aborting installation!" exit 1 fi if [[ -f "$RefindDir/refind.conf-sample" ]] ; then ConfFile="$RefindDir/refind.conf-sample" elif [[ -f "$ThisDir/refind.conf-sample" ]] ; then ConfFile="$ThisDir/refind.conf-sample" else echo "The sample configuration file is missing! Aborting installation!" exit 1 fi if [[ -d "$RefindDir/icons" ]] ; then IconsDir="$RefindDir/icons" elif [[ -d "$ThisDir/icons" ]] ; then IconsDir="$ThisDir/icons" else echo "The icons directory is missing! Aborting installation!" exit 1 fi echo "ShimSource is $ShimSource" if [[ "$ShimSource" != "none" ]] ; then if [[ -f "$ShimSource" ]] ; then if [[ $ShimType == "shimx64.efi" || $ShimType == "shim.efi" || $ShimType == "shimx64.efi.signed" ]] ; then TargetX64="grubx64.efi" TargetAARCH64="grubaa64.efi" MokManagerSource=`dirname "$ShimSource"`/mm$Platform.efi.signed if [[ ! -f "$MokManagerSource" ]] ; then MokManagerSource=`dirname "$ShimSource"`/mm$Platform.efi fi if [[ ! -f "$MokManagerSource" ]] ; then MokManagerSource=`dirname "$ShimSource"`/MokManager.efi fi elif [[ $ShimType == "preloader.efi" || $ShimType == "PreLoader.efi" ]] ; then TargetX64="loader.efi" MokManagerSource=`dirname "$ShimSource"`/HashTool.efi else echo "Unknown shim/PreBootloader filename: $ShimType!" echo "Known filenames are shimx64.efi, shim.efi, and PreLoader.efi. Aborting!" exit 1 fi else echo "The specified shim/PreBootloader file, $ShimSource, doesn't exist!" echo "Aborting installation!" exit 1 fi fi } # CheckForFiles() # Helper for CopyRefindFiles; copies shim files (including MokManager, if it's # available) to target. CopyShimFiles() { local inode1=`ls -i "$ShimSource" 2> /dev/null | cut -f 1 -d " "` local inode2=`ls -i "$InstallDir/$TargetDir/$TargetShim" 2> /dev/null | cut -f 1 -d " "` if [[ $inode1 != $inode2 ]] ; then cp -fb "$ShimSource" "$InstallDir/$TargetDir/$TargetShim" if [[ $? != 0 ]] ; then Problems=1 fi fi inode1=`ls -i "$MokManagerSource" 2> /dev/null | cut -f 1 -d " "` local TargetMMName=`basename $MokManagerSource` if [[ $TargetMMName == "mm$Platform.efi.signed" ]] ; then TargetMMName="mm$Platform.efi" fi inode2=`ls -i "$InstallDir/$TargetDir/$TargetMMName" 2> /dev/null | cut -f 1 -d " "` if [[ $inode1 != $inode2 ]] ; then if [[ -f "$MokManagerSource" ]] ; then cp -fb "$MokManagerSource" "$InstallDir/$TargetDir/$TargetMMName" fi if [[ $? != 0 ]] ; then Problems=1 fi fi } # CopyShimFiles() # Copy the public keys to the installation medium CopyKeys() { if [[ $LocalKeys == 1 ]] ; then mkdir -p "$InstallDir/$TargetDir/keys/" cp "$EtcKeysDir/$LocalKeysBase.cer" "$InstallDir/$TargetDir/keys/" cp "$EtcKeysDir/$LocalKeysBase.crt" "$InstallDir/$TargetDir/keys/" fi } # CopyKeys() # Set varaibles for installation in EFI/BOOT directory SetVarsForBoot() { TargetDir="/EFI/BOOT" if [[ $ShimSource == "none" ]] ; then TargetX64="bootx64.efi" TargetIA32="bootia32.efi" TargetAARCH64="bootaa64.efi" else if [[ $ShimType == "shim.efi" || $ShimType == "shimx64.efi" || $ShimType == "shimx64.efi.signed" || $ShimType = "shimaa64.efi" ]] ; then TargetX64="grubx64.efi" TargetAARCH64="grubaa64.efi" elif [[ $ShimType == "preloader.efi" || $ShimType == "PreLoader.efi" ]] ; then TargetX64="loader.efi" else echo "Unknown shim/PreBootloader type: $ShimType" echo "Aborting!" exit 1 fi TargetIA32="bootia32.efi" TargetShim="boot$Platform.efi" fi if [[ $KeepName == 1 ]] ; then echo "Installation is to /EFI/BOOT, which is incompatible with --keepname! Aborting!" exit 1 fi } # SetVarsForBoot() # Set variables for installation in EFI/Microsoft/Boot directory SetVarsForMsBoot() { TargetDir="/EFI/Microsoft/Boot" if [[ $ShimSource == "none" ]] ; then TargetX64="bootmgfw.efi" TargetIA32="bootmgfw.efi" TargetAARCH64="bootmgfw.efi" else if [[ $ShimType == "shim.efi" || $ShimType == "shimx64.efi" || $ShimType == "shimaa64.efi" ]] ; then TargetX64="grubx64.efi" TargetAARCH64="grubaa64.efi" elif [[ $ShimType == "preloader.efi" || $ShimType == "PreLoader.efi" ]] ; then TargetX64="loader.efi" else echo "Unknown shim/PreBootloader type: $ShimType" echo "Aborting!" exit 1 fi TargetShim="bootmgfw.efi" fi if [[ $KeepName == 1 ]] ; then echo "Installation is to /EFI/Microsoft/Boot, which is incompatible with --keepname!" echo "Aborting!" exit 1 fi } # SetVarsForMsBoot() # TargetDir defaults to /EFI/refind; however, this function adjusts it as follows: # - If an existing refind.conf is available in /EFI/BOOT or /EFI/Microsoft/Boot, # install to that directory under the suitable name; but DO NOT do this if # refind.conf is also in /EFI/refind. # - If booted in BIOS mode and the ESP lacks any other EFI files, install to # /EFI/BOOT # - If booted in BIOS mode and there's no refind.conf file and there is a # /EFI/Microsoft/Boot/bootmgfw.efi file, move it down one level and # install under that name, "hijacking" the Windows boot loader filename DetermineTargetDir() { Upgrade=0 if [[ -f $InstallDir/EFI/BOOT/refind.conf && ! -f $InstallDir/EFI/refind/refind.conf ]] ; then SetVarsForBoot Upgrade=1 fi if [[ -f $InstallDir/EFI/Microsoft/Boot/refind.conf && ! -f $InstallDir/EFI/refind/refind.conf ]] ; then SetVarsForMsBoot Upgrade=1 fi if [[ -f $InstallDir/EFI/refind/refind.conf ]] ; then TargetDir="/EFI/refind" if [[ $ShimSource == "none" || $KeepName == 1 ]] ; then TargetX64="refind_x64.efi" TargetIA32="refind_ia32.efi" TargetAARCH64="refind_aa64.efi" fi Upgrade=1 fi if [[ $Upgrade == 1 ]] ; then echo "Found rEFInd installation in $InstallDir$TargetDir; upgrading it." fi if [[ ! -d /sys/firmware/efi && ! $OSTYPE == darwin* && $Upgrade == 0 ]] ; then # BIOS-mode FoundEfiFiles=`find "$InstallDir/EFI/BOOT" -name "*.efi" 2> /dev/null` FoundConfFiles=`find "$InstallDir" -name "refind\.conf" 2> /dev/null` if [[ ! -n "$FoundConfFiles" && -f "$InstallDir/EFI/Microsoft/Boot/bootmgfw.efi" ]] ; then mv -n "$InstallDir/EFI/Microsoft/Boot/bootmgfw.efi" "$InstallDir/EFI/Microsoft" &> /dev/null SetVarsForMsBoot echo "Running in BIOS mode with a suspected Windows installation; moving boot loader" echo "files so as to install to $InstallDir$TargetDir." elif [[ ! -n "$FoundEfiFiles" ]] ; then # In BIOS mode and no default loader; install as default loader SetVarsForBoot echo "Running in BIOS mode with no existing default boot loader; installing to" echo $InstallDir$TargetDir else echo "Running in BIOS mode with an existing default boot loader; backing it up and" echo "installing rEFInd in its place." if [[ -d "$InstallDir/EFI/BOOT-rEFIndBackup" ]] ; then echo "" echo "Caution: An existing backup of a default boot loader exists! If the current" echo "default boot loader and the backup are different boot loaders, the current" echo "one will become inaccessible." echo "" echo -n "Do you want to proceed with installation (Y/N)? " ReadYesNo if [[ $YesNo == "Y" || $YesNo == "y" ]] ; then echo "OK; continuing with the installation..." else exit 0 fi fi mv -n "$InstallDir/EFI/BOOT" "$InstallDir/EFI/BOOT-rEFIndBackup" SetVarsForBoot fi fi # BIOS-mode } # DetermineTargetDir() # Determine (or guess) the filesystem used on the Linux /boot filesystem. # Store the result in the BootFS global variable. SetBootFS() { BootFS="" case "$OSTYPE" in linux*) if command -v blkid &>/dev/null; then BootPart=`df $RootDir/boot | grep dev | cut -f 1 -d " "` BootFS=`blkid -o export $BootPart 2> /dev/null | grep TYPE= | cut -f 2 -d =` fi ;; darwin*) # 0FC63DAF-8483-4772-8E79-3D69D8477DE4 = Linux filesystem # BC13C2FF-59E6-4262-A352-B275FD6F7172 = Freedesktop $boot partition # 933AC7E1-2EB4-4F13-B844-0E14E2AEF915 = Freedesktop Linux /home # E6D6D379-F507-44C2-A23C-238F2A3DF928 = Linux LVM # A19D880F-05FC-4D3B-A006-743F0F84911E = Linux RAID # 0657FD6D-A4AB-43C4-84E5-0933C84B4F4F = Linux swap Temp=$(diskutil list | grep -i '0FC63DAF-8483-4772-8E79-3D69D8477DE4\|BC13C2FF-59E6-4262-A352-B275FD6F7172\|933AC7E1-2EB4-4F13-B844-0E14E2AEF915\|E6D6D379-F507-44C2-A23C-238F2A3DF928\|A19D880F-05FC-4D3B-A006-743F0F84911E\|0657FD6D-A4AB-43C4-84E5-0933C84B4F4F\|Linux') BootFS="" if [[ -n $Temp ]] ; then echo "Found suspected Linux partition(s); installing ext4fs driver." BootFS="ext4" fi ;; esac } # SetBootFS() # Copy drivers from $RefindDir/drivers_$1 to $InstallDir/$TargetDir/drivers_$1, # honoring the $InstallDrivers condition. Must be passed a suitable # architecture code (ia32 or x64). CopyDrivers() { if [[ $InstallDrivers == "all" ]] ; then mkdir -p "$InstallDir/$TargetDir/drivers_$1" cp "$ThisDir"/drivers_$1/*_$1.efi "$InstallDir/$TargetDir/drivers_$1/" 2> /dev/null cp "$RefindDir"/drivers_$1/*_$1.efi "$InstallDir/$TargetDir/drivers_$1/" 2> /dev/null elif [[ "$InstallDrivers" == "boot" ]] ; then SetBootFS DriverType="" case $BootFS in ext2 | ext3) DriverType="ext2" # Could use ext4, but that can create unwanted entries from symbolic # links in / to /boot/vmlinuz if a separate /boot partition is used. ;; ext4) DriverType="ext4" ;; reiserfs) DriverType="reiserfs" ;; btrfs) DriverType="btrfs" ;; hfsplus) DriverType="hfs" ;; ntfs) DriverType="ntfs" ;; *) BootFS="" esac if [[ -n $BootFS ]] ; then echo "Installing driver for $BootFS (${DriverType}_$1.efi)" mkdir -p "$InstallDir/$TargetDir/drivers_$1" cp "$ThisDir/drivers_$1/${DriverType}_$1.efi" "$InstallDir/$TargetDir/drivers_$1/" 2> /dev/null cp "$RefindDir/drivers_$1/${DriverType}_$1.efi" "$InstallDir/$TargetDir/drivers_$1"/ 2> /dev/null fi fi } # CopyDrivers() # Copy tools (currently only gptsync, and that only on Macs) to the EFI/tools # directory on the ESP. Must be passed a suitable architecture code (ia32 # or x64). CopyTools() { mkdir -p "$InstallDir/EFI/tools" if [[ $OSTYPE == darwin* ]] ; then cp -f "$RefindDir/tools_$1/gptsync_$1.efi" "$InstallDir/EFI/tools/" if [[ -f "$InstallDir/EFI/tools/gptsync.efi" ]] ; then mv "$InstallDir/EFI/tools/gptsync.efi" "$InstallDir/EFI/tools/gptsync.efi-disabled" echo "Found old gptsync.efi; disabling it by renaming it to gptsync.efi-disabled" fi fi } # CopyTools() # Copy the rEFInd files to the ESP or OS X root partition. # Sets Problems=1 if any critical commands fail. CopyRefindFiles() { mkdir -p "$InstallDir/$TargetDir" if [[ "$TargetDir" == '/EFI/BOOT' ]] ; then cp "$RefindDir/refind_ia32.efi" "$InstallDir/$TargetDir/$TargetIA32" 2> /dev/null if [[ $? != 0 ]] ; then echo "Note: IA32 (x86) binary not installed!" fi cp "$RefindDir/refind_x64.efi" "$InstallDir/$TargetDir/$TargetX64" 2> /dev/null if [[ $? != 0 ]] ; then Problems=1 fi cp "$RefindDir/refind_aa64.efi" "$InstallDir/$TargetDir/$TargetAARCH64" 2> /dev/null if [[ $? != 0 && $Platform == "aa64" ]] ; then Problems=1 fi if [[ "$ShimSource" != "none" ]] ; then TargetShim="bootx64.efi" CopyShimFiles fi if [[ $InstallDrivers == "all" ]] ; then cp -r "$RefindDir"/drivers_* "$InstallDir/$TargetDir/" 2> /dev/null cp -r "$ThisDir"/drivers_* "$InstallDir/$TargetDir/" 2> /dev/null elif [[ $Upgrade == 1 || $InstallToEspOnMac == 1 ]] ; then CopyDrivers "$Platform" CopyTools "$Platform" fi Refind="boot$Platform.efi" CopyKeys elif [[ $Platform == 'x64' || $TargetDir == "/EFI/Microsoft/Boot" ]] ; then cp "$RefindDir/refind_x64.efi" "$InstallDir/$TargetDir/$TargetX64" if [[ $? != 0 ]] ; then Problems=1 fi CopyDrivers x64 CopyTools x64 Refind="refind_x64.efi" CopyKeys if [[ "$ShimSource" != "none" ]] ; then if [[ "$TargetShim" == "default" ]] ; then TargetShim=`basename "$ShimSource"` fi CopyShimFiles Refind="$TargetShim" if [[ $LocalKeys == 0 ]] ; then echo "Storing copies of rEFInd Secure Boot public keys in $EtcKeysDir" mkdir -p "$EtcKeysDir" cp "$ThisDir/keys/refind.cer" "$EtcKeysDir" 2> /dev/null cp "$ThisDir/keys/refind.crt" "$EtcKeysDir" 2> /dev/null fi fi if [[ "$TargetDir" == '/System/Library/CoreServices' ]] ; then SetupMacHfs $TargetX64 fi elif [[ $Platform == 'ia32' || $Platform == 'aa64' ]] ; then if [[ $Platform == 'ia32' ]] ; then cp "$RefindDir/refind_ia32.efi" "$InstallDir/$TargetDir/$TargetIA32" if [[ $? != 0 ]] ; then Problems=1 fi else cp "$RefindDir/refind_aa64.efi" "$InstallDir/$TargetDir/$TargetAARCH64" if [[ $? != 0 ]] ; then Problems=1 fi fi CopyDrivers $Platform CopyTools $Platform Refind="refind_$Platform.efi" if [[ "$TargetDir" == '/System/Library/CoreServices' ]] ; then SetupMacHfs $TargetIA32 fi else echo "Unknown platform! Aborting!" exit 1 fi echo "Copied rEFInd binary files" echo "" if [[ -d "$InstallDir/$TargetDir/icons" ]] ; then rm -rf "$InstallDir/$TargetDir/icons-backup" &> /dev/null mv -f "$InstallDir/$TargetDir/icons" "$InstallDir/$TargetDir/icons-backup" echo "Notice: Backed up existing icons directory as icons-backup." fi cp -r "$IconsDir" "$InstallDir/$TargetDir" if [[ $? != 0 ]] ; then Problems=1 fi mkdir -p "$InstallDir/$TargetDir/keys" cp -rf "$ThisDir"/keys/*.[cd]er "$InstallDir/$TargetDir/keys/" 2> /dev/null cp -rf "$EtcKeysDir"/*.[cd]er "$InstallDir/$TargetDir/keys/" 2> /dev/null if [[ -f "$InstallDir/$TargetDir/refind.conf" ]] ; then echo "Existing refind.conf file found; copying sample file as refind.conf-sample" echo "to avoid overwriting your customizations." echo "" cp -f "$ConfFile" "$InstallDir/$TargetDir" if [[ $? != 0 ]] ; then Problems=1 fi else echo "Copying sample configuration file as refind.conf; edit this file to configure" echo "rEFInd." echo "" cp -f "$ConfFile" "$InstallDir/$TargetDir/refind.conf" if [[ $? != 0 ]] ; then Problems=1 fi fi if [[ $DeleteRefindDir == 1 ]] ; then echo "Deleting the temporary directory $RefindDir" rm -r "$RefindDir" fi } # CopyRefindFiles() # Mount the partition the user specified with the --usedefault or --ownhfs option MountDefaultTarget() { InstallDir=/tmp/refind_install mkdir -p "$InstallDir" UnmountEsp=1 if [[ $OSTYPE == darwin* ]] ; then if [[ $OwnHfs == '1' ]] ; then Temp=`diskutil info "$TargetPart" | grep "Mount Point"` InstallDir=`echo $Temp | cut -f 3-30 -d ' '` if [[ $InstallDir == '' ]] ; then InstallDir=/tmp/refind_install mount -t hfs "$TargetPart" "$InstallDir" else UnmountEsp=0 fi else mount -t msdos "$TargetPart" "$InstallDir" fi elif [[ $OSTYPE == linux* ]] ; then mount -t vfat "$TargetPart" "$InstallDir" fi if [[ $? != 0 ]] ; then echo "Couldn't mount $TargetPart ! Aborting!" rmdir "$InstallDir" exit 1 fi } # MountDefaultTarget() # Create a BOOT.CSV file in the same directory as rEFInd, to help in recovery # should the system's boot entry list be lost CreateBootCsvFile() { IConv=`which iconv 2> /dev/null` if [[ -x "$IConv" ]] ; then if [[ "$Platform" == "x64" && -d "$InstallDir/$TargetDir" ]] ; then echo "$TargetX64,rEFInd Boot Manager,,This is the boot entry for rEFInd" | \ $IConv -t UCS-2 > "$InstallDir/$TargetDir/BOOT.CSV" fi if [[ "$Platform" == "ia32" && -d "$InstallDir/$TargetDir" ]] ; then echo "$TargetIA32,rEFInd Boot Manager,,This is the boot entry for rEFInd" | \ $IConv -t UCS-2 > "$InstallDir/$TargetDir/BOOT.CSV" fi if [[ "$Platform" == "aarch64" && -d "$InstallDir/$TargetDir" ]] ; then echo "$TargetAARCH64,rEFInd Boot Manager,,This is the boot entry for rEFInd" | \ $IConv -t UCS-2 > "$InstallDir/$TargetDir/BOOT.CSV" fi fi exit } # CreateBootCsvFile() # # A series of OS X support functions.... # # Mount the ESP at /Volumes/ESP or determine its current mount # point. # Sets InstallDir to the ESP mount point # Sets UnmountEsp if we mounted it MountOSXESP() { # Identify the ESP. Note: This returns the FIRST ESP found; # if the system has multiple disks, this could be wrong! Temp=$(mount | sed -n -E "/^(\/dev\/disk.*) on \/ \(.*$/s//\1/p") if [ $Temp ]; then Temp=$(diskutil list | grep " EFI " | grep -o 'disk.*' | head -n 1) if [ -z $Temp ]; then echo "Warning: root device doesn't have an EFI System Partition" fi else echo "Warning: root device could not be found" fi if [ -z $Temp ]; then Temp=$(diskutil list | sed -n -E '/^ *[0-9]+:[ ]+EFI EFI[ ]+[0-9.]+ [A-Z]+[ ]+(disk[0-9]+s[0-9]+)$/ { s//\1/p q }' ) if [ -z $Temp ]; then echo "Could not find an EFI System Partition. Aborting!" exit 1 fi fi Esp=/dev/`echo $Temp` # If the ESP is mounted, use its current mount point.... Temp=`df -P | grep "$Esp "` InstallDir=`echo $Temp | cut -f 6- -d ' '` if [[ "$InstallDir" == '' ]] ; then mkdir /Volumes/ESP &> /dev/null mount -t msdos "$Esp" /Volumes/ESP # Some systems have HFS+ "ESPs." They shouldn't, but they do. If this is # detected, mount it as such and set appropriate options. if [[ $? != 0 ]] ; then mount -t hfs "$Esp" /Volumes/Esp OwnHfs=1 InstallToEspOnMac=0 if [[ $? != 0 ]] ; then echo "Unable to mount ESP! Aborting!\n" exit 1 fi fi UnmountEsp=1 InstallDir="/Volumes/ESP" fi } # MountOSXESP() # Set up for booting from Mac HFS+ volume that boots rEFInd in MJG's way # (http://mjg59.dreamwidth.org/7468.html) # Must be passed the original rEFInd binary filename (without a path). SetupMacHfs() { if [[ -s "$InstallDir/mach_kernel" ]] ; then echo "Attempt to install rEFInd to a partition with a /mach_kernel file! Aborting!" exit 1 fi cp -n "$InstallDir/$TargetDir/boot.efi" "$InstallDir/$TargetDir/boot.efi-backup" &> /dev/null ln -f "$InstallDir/$TargetDir/$1" "$InstallDir/$TargetDir/boot.efi" touch "$InstallDir/mach_kernel" rm "$InstallDir/$TargetDir/SystemVersion.plist" &> /dev/null cat - << ENDOFHERE >> "$InstallDir/$TargetDir/SystemVersion.plist" ProductBuildVersion ProductName rEFInd ProductVersion 0.11.4 ENDOFHERE } # SetupMacHfs() CheckForSIP() { if [[ -x "/usr/bin/csrutil" && -z "$TargetPart" ]] ; then local OKToInstall=`/usr/bin/csrutil status | \ grep "Protection status: disabled\|enabled (Apple Internal)\|NVRAM Protections: disabled"` if [[ -z "$OKToInstall" ]] ; then echo echo "**** ALERT: SIP ENABLED! ****" echo if [[ "$Upgrade" == "1" ]] ; then echo "You are attempting to upgrade an existing installation, but it appears that" echo "System Integrity Protection (SIP) is enabled. If rEFInd is working now, then" echo "this is fine; you can upgrade your existing rEFInd. If rEFInd is not working," echo "though, re-installing from this boot will not help. To re-enable rEFInd, you" echo "must re-install it from a Recovery system or from another OS. To enter the" echo "Recovery system and re-install rEFInd:" else echo "rEFInd cannot be installed because System Integrity Protection (SIP) seems" echo "to be enabled! You must install rEFInd from your Recovery installation or" echo "from another OS. To install from the Recovery system:" fi echo echo " 1. Reboot" echo " 2. Hold down Command+R as the chime sounds" echo " 3. When the OS has booted, select Utilities->Terminal" echo " 4. Change to this directory with the 'cd' command; it will probably be under" if [[ "`pwd | cut -b 1-8`" == "/Volumes" ]] ; then echo " `pwd`" else local RootName=`diskutil info -plist / | grep -A 1 VolumeName | grep string | cut -d \> -f 2 | cut -d \< -f 1` echo " /Volumes/$RootName`pwd`" fi echo " 5. Re-run this script." echo if [[ "$Upgrade" != "1" ]] ; then echo "If you believe SIP is NOT enabled, you may attempt an installation anyhow," echo "but it may fail." echo fi echo "For more on this subject, see http://www.rodsbooks.com/refind/sip.html" echo echo -n "Do you want to attempt installation (Y/N)? " ReadYesNo if [[ $YesNo == "N" || $YesNo == "n" ]] ; then echo "Exiting!" exit fi fi # csrutil status suggests OK to install fi # csrutil exists } # CheckForSIP() # Control the OS X installation. # Sets Problems=1 if problems found during the installation. InstallOnOSX() { echo "Installing rEFInd on OS X...." if [[ "$InstallToEspOnMac" == "1" && -z "$TargetPart" ]] ; then MountOSXESP elif [[ "$TargetDir" == "/EFI/BOOT" || "$OwnHfs" == '1' ]] ; then MountDefaultTarget else InstallDir="$RootDir/" fi echo "Installing rEFInd to the partition mounted at $InstallDir" DetermineTargetDir CheckForSIP CopyRefindFiles mkdir -p /usr/local/bin &> /dev/null cp "$ThisDir/mountesp" /usr/local/bin/ &> /dev/null if [[ $InstallToEspOnMac == "1" && -z "$TargetPart" ]] ; then bless --mount "$InstallDir" --setBoot --file "$InstallDir/$TargetDir/$Refind" --shortform elif [[ "$TargetDir" != "/EFI/BOOT" ]] ; then bless --setBoot --folder "$InstallDir/$TargetDir" --file "$InstallDir/$TargetDir/$Refind" fi if [[ $? != 0 ]] ; then Problems=1 fi if [[ -f /Library/StartupItems/rEFItBlesser || -d /Library/StartupItems/rEFItBlesser ]] ; then echo echo "/Library/StartupItems/rEFItBlesser found!" echo "This program is part of rEFIt, and will cause rEFInd to fail to work after" echo -n "its first boot. Do you want to remove rEFItBlesser (Y/N)? " ReadYesNo if [[ $YesNo == "Y" || $YesNo == "y" ]] ; then echo "Deleting /Library/StartupItems/rEFItBlesser..." rm -r /Library/StartupItems/rEFItBlesser else echo "Not deleting rEFItBlesser." fi fi } # InstallOnOSX() # # Now a series of Linux support functions.... # # Check for evidence that we're running in Secure Boot mode. If so, and if # appropriate options haven't been set, warn the user and offer to abort. # If we're NOT in Secure Boot mode but the user HAS specified the --shim # or --localkeys option, warn the user and offer to abort. CheckSecureBoot() { IsSecureBoot="0" if [[ -f /sys/firmware/efi/efivars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c ]] ; then IsSecureBoot=`od -An -t u1 /sys/firmware/efi/efivars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c | awk '{print substr($0,length,1)}'` elif [[ -f /sys/firmware/efi/vars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c/data ]] ; then IsSecureBoot=`od -An -t u1 /sys/firmware/efi/vars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c/data | tr -d '[[:space:]]'` fi if [[ $IsSecureBoot == "1" && "$TargetDir" != '/EFI/BOOT' && "$ShimSource" == "none" ]] ; then echo "" echo "CAUTION: Your computer appears to be booted with Secure Boot, but you haven't" echo "specified a valid shim.efi file source. Chances are you should re-run with" echo "the --shim option. You can read more about this topic at" echo "http://www.rodsbooks.com/refind/secureboot.html." echo "" echo -n "Do you want to proceed with installation (Y/N)? " ReadYesNo if [[ $YesNo == "Y" || $YesNo == "y" ]] ; then echo "OK; continuing with the installation..." else exit 0 fi fi if [[ "$ShimSource" != "none" && ! $IsSecureBoot == "1" ]] ; then echo "" echo "You've specified installing using a shim.efi file, but your computer does not" echo "appear to be running in Secure Boot mode. Although installing in this way" echo "should work, it's unnecessarily complex. You may continue, but unless you" echo "plan to enable Secure Boot, you should consider stopping and omitting the" echo "--shim option. You can read more about this topic at" echo "http://www.rodsbooks.com/refind/secureboot.html." echo "" echo -n "Do you want to proceed with installation (Y/N)? " ReadYesNo if [[ $YesNo == "Y" || $YesNo == "y" ]] ; then echo "OK; continuing with the installation..." else exit 0 fi fi if [[ $LocalKeys != 0 && ! $IsSecureBoot == "1" ]] ; then echo "" echo "You've specified re-signing your rEFInd binaries with locally-generated keys," echo "but your computer does not appear to be running in Secure Boot mode. The" echo "keys you generate will be useless unless you enable Secure Boot. You may" echo "proceed with this installation, but before you do so, you may want to read" echo "more about it at http://www.rodsbooks.com/refind/secureboot.html." echo "" echo -n "Do you want to proceed with installation (Y/N)? " ReadYesNo if [[ $YesNo == "Y" || $YesNo == "y" ]] ; then echo "OK; continuing with the installation..." else exit 0 fi fi } # CheckSecureBoot() # Check for the presence of locally-generated keys from a previous installation in # $EtcKeysDir (/etc/refind.d/keys). If they're not present, generate them using # openssl. GenerateKeys() { PrivateKey="$EtcKeysDir/$LocalKeysBase.key" CertKey="$EtcKeysDir/$LocalKeysBase.crt" DerKey="$EtcKeysDir/$LocalKeysBase.cer" OpenSSL=`which openssl 2> /dev/null` # Do the work only if one or more of the necessary keys is missing # TODO: Technically, we don't need the DerKey; but if it's missing and openssl # is also missing, this will fail. This could be improved. if [[ ! -f "$PrivateKey" || ! -f "$CertKey" || ! -f "$DerKey" ]] ; then echo "Generating a fresh set of local keys...." mkdir -p "$EtcKeysDir" chmod 0700 "$EtcKeysDir" if [[ ! -x "$OpenSSL" ]] ; then echo "Can't find openssl, which is required to create your private signing keys!" echo "Aborting!" exit 1 fi if [[ -f "$PrivateKey" ]] ; then echo "Backing up existing $PrivateKey" cp -f "$PrivateKey" "$PrivateKey.backup" 2> /dev/null fi if [[ -f "$CertKey" ]] ; then echo "Backing up existing $CertKey" cp -f "$CertKey" "$CertKey.backup" 2> /dev/null fi if [[ -f "$DerKey" ]] ; then echo "Backing up existing $DerKey" cp -f "$DerKey" "$DerKey.backup" 2> /dev/null fi if [[ $EncryptKeys == 1 ]]; then KeyEncryptionArgument="" else KeyEncryptionArgument="-nodes" fi "$OpenSSL" req -new -x509 -newkey rsa:2048 -keyout "$PrivateKey" -out "$CertKey" \ $KeyEncryptionArgument -days 3650 -subj "/CN=Locally-generated rEFInd key/" "$OpenSSL" x509 -in "$CertKey" -out "$DerKey" -outform DER chmod 0600 "$PrivateKey" else echo "Using existing local keys...." fi } # GenerateKeys() # Sign a single binary. Requires parameters: # $1 = source file # $2 = destination file # Also assumes that the SBSign and various key variables are set appropriately. # Aborts script on error SignOneBinary() { ReadKeyPassphrase --no-confirm if [[ "$EncryptKeys" == 1 ]] ; then SbSignCommand=$(printf "%q " "$SBSign" --key "$PrivateKey" --cert "$CertKey" --output "$2" "$1") echo "$KeyPassphrase" | script -qefc "$SbSignCommand" --force /dev/null 2>&1 | ( \ head -n 2 >/dev/null # Skip the first two lines (incl. passphrase). grep -v "data remaining.*gaps between PE/COFF sections" ) local status="${PIPESTATUS[1]}" else "$SBSign" --key "$PrivateKey" --cert "$CertKey" --output "$2" "$1" 2>&1 >/dev/null | \ grep -v "data remaining.*gaps between PE/COFF sections" local status="${PIPESTATUS[0]}" fi if [[ "$status" != 0 ]] ; then echo "Problem signing the binary $1! Aborting!" exit 1 fi } # SignOneBinary() # Re-sign the x86-64 binaries with a locally-generated key, First look for appropriate # key files in $EtcKeysDir. If they're present, use them to re-sign the binaries. If # not, try to generate new keys and store them in $EtcKeysDir. ReSignBinaries() { SBSign=`which sbsign 2> /dev/null` echo "Found sbsign at $SBSign" TempDir="/tmp/refind_local" if [[ ! -x "$SBSign" ]] ; then echo "Can't find sbsign, which is required to sign rEFInd with your own keys!" echo "Aborting!" exit 1 fi GenerateKeys mkdir -p "$TempDir/drivers_$Platform" cp "$RefindDir/refind.conf-sample $TempDir" 2> /dev/null cp "$ThisDir/refind.conf-sample $TempDir" 2> /dev/null cp "$RefindDir/refind_ia32.efi $TempDir" 2> /dev/null cp -a "$RefindDir/drivers_ia32 $TempDir" 2> /dev/null cp -a "$ThisDir/drivers_ia32 $TempDir" 2> /dev/null SignOneBinary "$RefindDir/refind_$Platform.efi" "$TempDir/refind_$Platform.efi" SaveIFS=$IFS IFS=$(echo -en "\n\b") for Driver in `ls "$RefindDir"/drivers_$Platform/*.efi "$ThisDir"/drivers_$Platform/*.efi 2> /dev/null` ; do TempName=`basename "$Driver"` SignOneBinary "$Driver" "$TempDir/drivers_$Platform/$TempName" done IFS=$SaveIFS RefindDir="$TempDir" DeleteRefindDir=1 } # ReSignBinaries() # Locate and mount an ESP, if possible, based on parted output. # Should be called only if /boot/efi is NOT an acceptable ESP. # Sets InstallDir to the mounted ESP's path ($RootDir/boot/efi) # and EspFilesystem the filesystem (always "vfat") FindLinuxESP() { echo "The ESP doesn't seem to be mounted! Trying to find it...." local Name local Drive local PartNum local TableType local DmStatus local SkipIt local Dmraid for Name in `lsblk -r | grep disk | cut -f 1 -d " "` ; do Drive="/dev/$Name" SkipIt=0 Dmraid=`which dmraid 2> /dev/null` if [ -x "$Dmraid" ] ; then DmStatus=`dmraid -r | grep $Drive` if [ -n "$DmStatus" ] ; then echo "$Drive seems to be part of a RAID array; skipping!" SkipIt=1 fi fi TableType=`parted $Drive print -m -s 2>/dev/null | awk -F: '$1 == "'$Drive'" { print $6 }'` if [[ $TableType == 'gpt' && $SkipIt == 0 ]] ; then # read only GPT disks that aren't part of dmraid array PartNum=`LANG=C parted $Drive print -m -s 2>/dev/null | awk -F: '$7 ~ "(^boot| boot)" { print $1 }' | head -n 1` if [ "$PartNum" -eq "$PartNum" ] 2> /dev/null ; then InstallDir="$RootDir/boot/efi" mkdir -p $InstallDir mount $Drive$PartNum $InstallDir EspFilesystem=`grep "$Drive$PartNum.*/boot/efi" /etc/mtab | uniq | grep -v autofs | cut -d " " -f 3` if [[ $EspFilesystem != 'vfat' ]] ; then umount $InstallDir else echo "Mounting ESP at $InstallDir" break; fi fi # $PartNum -eq $PartNum fi # TableType done } # FindLinuxESP() # Identifies the ESP's location (/boot or /boot/efi, or these locations under # the directory specified by --root); aborts if the ESP isn't mounted at # either location. # Sets InstallDir to the ESP mount point. FindMountedESP() { mount /boot &> /dev/null mount /boot/efi &> /dev/null mount /efi &> /dev/null EspLine=`df "$RootDir/efi" 2> /dev/null | grep efi` if [[ ! -n "$EspLine" ]] ; then EspLine=`df "$RootDir"/boot/efi 2> /dev/null | grep boot/efi` fi if [[ ! -n "$EspLine" ]] ; then EspLine=`df "$RootDir"/boot 2> /dev/null | grep boot` fi InstallDir=`echo $EspLine | cut -d " " -f 6` if [[ -n "$InstallDir" ]] ; then EspFilesystem=`grep -w "$InstallDir" /etc/mtab | uniq | grep -v autofs | cut -d " " -f 3` fi if [[ $EspFilesystem != 'vfat' ]] ; then FindLinuxESP fi if [[ $EspFilesystem != 'vfat' ]] ; then echo "$RootDir/$InstallDir doesn't seem to be on a VFAT filesystem. The ESP must be" echo "mounted at $RootDir/boot or $RootDir/boot/efi and it must be VFAT! Aborting!" if [[ -d /sys/firmware/efi ]] ; then exit 1 else echo "The computer appears to be running in BIOS mode and has no ESP. You should" echo "create an ESP, and ideally boot in EFI mode, before installing rEFInd." exit 0 fi fi echo "ESP was found at $InstallDir using $EspFilesystem" } # FindMountedESP # Uses efibootmgr to add an entry for rEFInd to the EFI's NVRAM, if necessary. # If this fails, sets Problems=1 AddBootEntry() { local PartNum local InstallDisk local InstallPart local InstallPartGuid local Name local ExistingEntry local KeepExistingEntry=0 local ExistingEntryBootNum local FirstBoot Efibootmgr=`which efibootmgr 2> /dev/null` if [[ "$Efibootmgr" ]] ; then InstallPart=`grep "$InstallDir" /etc/mtab | grep -v autofs | cut -d " " -f 1` for Name in `lsblk -r | grep disk | cut -f 1 -d " "` ; do if [[ $InstallPart == *"$Name"* ]] ; then InstallDisk="/dev/"$Name PartNum=${InstallPart#$InstallDisk} PartNum=`echo "${PartNum//[!0-9]/}"` break fi done if [[ -z $InstallDisk || -z $PartNum ]] ; then echo "Could not identify ESP in AddBootEntry()!" Problems=1 return 1 fi EntryFilename="$TargetDir/$Refind" EfiEntryFilename=`echo ${EntryFilename//\//\\\}` EfiEntryFilename2=`echo ${EfiEntryFilename} | sed s/\\\\\\\\/\\\\\\\\\\\\\\\\/g` InstallPartGuid=`blkid -s PARTUUID -o value "$InstallPart"` FirstBoot=`"$Efibootmgr" | grep BootOrder | cut -c 12-15` ExistingEntry=`"$Efibootmgr" -v | grep -i "$EfiEntryFilename2" | grep -i "$InstallPartGuid" | head -n 1` ExistingEntryFirstBoot=`"$Efibootmgr" -v | grep -i "$EfiEntryFilename2" | grep -i "$InstallPartGuid" | grep "Boot$FirstBoot"` if [[ "$ExistingEntry" ]] ; then ExistingEntryBootNum=`echo "$ExistingEntry" | cut -c 5-8` if [[ ! -n "$ExistingEntryFirstBoot" ]] ; then echo "An existing rEFInd boot entry exists, but isn't set as the default boot" echo "manager. The boot order is being adjusted to make rEFInd the default boot" echo "manager. If this is NOT what you want, you should use efibootmgr to" echo "manually adjust your EFI's boot order." "$Efibootmgr" -b $ExistingEntryBootNum -B &> /dev/null else KeepExistingEntry=1 fi fi if [[ "$KeepExistingEntry" == 0 ]] ; then echo "Creating new NVRAM entry" if [[ "$KeepName" == 0 ]] ; then "$Efibootmgr" -c -l "$EfiEntryFilename" -L "rEFInd Boot Manager" -d $InstallDisk -p $PartNum &> /dev/null else "$Efibootmgr" -c -l "$EfiEntryFilename" -L "rEFInd Boot Manager" -d $InstallDisk -p $PartNum \ -u "$TargetShim $TargetX64" &> /dev/null fi else echo "Keeping existing NVRAM entry" fi if [[ $? != 0 ]] ; then EfibootmgrProblems=1 Problems=1 fi else # efibootmgr not found EfibootmgrProblems=1 Problems=1 fi if [[ $EfibootmgrProblems ]] ; then echo echo "ALERT: There were problems running the efibootmgr program! You may need to" echo "rename the $Refind binary to the default name (EFI/BOOT/bootx64.efi" echo "on x86-64 systems, EFI/BOOT/bootia32.efi on x86 systems, or" echo "EFI/BOOT/bootaa64.efi on ARM64 systems) to have it run!" echo else echo "rEFInd is set as the default boot manager." fi } # AddBootEntry() # Create a minimal/sample refind_linux.conf file in /boot. GenerateRefindLinuxConf() { if [[ -f "$RLConfFile" ]] ; then echo "Existing $RLConfFile found; not overwriting." else echo "Creating $RLConfFile; edit it to adjust kernel options." RootFS=`df "$RootDir" | grep dev | cut -f 1 -d " "` StartOfDevname=`echo "$RootFS" | cut -b 1-7` if [[ "$StartOfDevname" == "/dev/sd" || "$StartOfDevName" == "/dev/hd" ]] ; then # Identify root filesystem by UUID rather than by device node, if possible Uuid=`blkid -o export -s UUID "$RootFS" 2> /dev/null | grep UUID=` if [[ -n $Uuid ]] ; then RootFS="$Uuid" fi fi if [[ $RootDir == "/" ]] ; then local FirstCmdlineOption=`cat /proc/cmdline | cut -d ' ' -f 1` if [[ "$FirstCmdlineOption" =~ (vmlinuz|bzImage|kernel) ]] ; then DefaultOptions=`cat /proc/cmdline | cut -d ' ' -f 2- | sed 's/\S*initrd=\S*//g' | sed 's/ *$//' | sed 's/^ *//'` else DefaultOptions=`cat /proc/cmdline | sed 's/\S*initrd=\S*//g' | sed 's/ *$//' | sed 's/^ *//'` fi else if [[ -f "$RootDir/etc/default/grub" ]] ; then # We want the default options used by the distribution, stored here.... source "$RootDir/etc/default/grub" echo "Setting default boot options based on $RootDir/etc/default/grub" fi DefaultOptions="ro root=$RootFS $GRUB_CMDLINE_LINUX $GRUB_CMDLINE_LINUX_DEFAULT" fi echo "\"Boot with standard options\" \"$DefaultOptions\"" > $RLConfFile echo "\"Boot to single-user mode\" \"$DefaultOptions single\"" >> $RLConfFile echo "\"Boot with minimal options\" \"ro root=$RootFS\"" >> $RLConfFile fi } # Controls rEFInd installation under Linux. # Sets Problems=1 if something goes wrong. InstallOnLinux() { if [[ "$TargetDir" == "/System/Library/CoreServices" ]] ; then echo "You may not use the --ownhfs option under Linux! Aborting!" exit 1 fi echo "Installing rEFInd on Linux...." modprobe efivars &> /dev/null if [[ $TargetDir == "/EFI/BOOT" ]] ; then MountDefaultTarget else FindMountedESP DetermineTargetDir fi if [[ $LocalKeys == 1 ]] ; then ReSignBinaries fi CheckSecureBoot CopyRefindFiles if [[ "$TargetDir" != "/EFI/BOOT" && "$TargetDir" != "/EFI/Microsoft/Boot" ]] ; then AddBootEntry GenerateRefindLinuxConf fi } # InstallOnLinux() # # The main part of the script. Sets a few environment variables, # performs a few startup checks, and then calls functions to # install under OS X or Linux, depending on the detected platform. # GetParams "$@" if [[ $UID != 0 ]] ; then echo "Not running as root; attempting to elevate privileges via sudo...." sudo "$BASH_SOURCE" "$@" if [[ $? != 0 ]] ; then echo "This script must be run as root (or using sudo). Exiting!" exit 1 else exit 0 fi fi DeterminePlatform CheckForFiles case "$OSTYPE" in darwin*) if [[ "$ShimSource" != "none" ]] ; then echo "The --shim option is not supported on OS X! Exiting!" exit 1 fi if [[ "$LocalKeys" != 0 ]] ; then echo "The --localkeys option is not supported on OS X! Exiting!" exit 1 fi InstallOnOSX $1 ;; linux*) InstallOnLinux ;; *) echo "Running on unknown OS; aborting!" if [[ "$InstallToEspOnMac" == 0 ]] ; then echo "The --notesp option is not supported on Linux! Exiting!" exit 1 fi esac CreateBootCsvFile if [[ $Problems ]] ; then echo echo "ALERT:" echo "Installation has completed, but problems were detected. Review the output for" echo "error messages and take corrective measures as necessary. You may need to" echo "re-run this script or install manually before rEFInd will work." echo else echo echo "Installation has completed successfully." echo fi if [[ $UnmountEsp == '1' ]] ; then echo "Unmounting install dir" case "$OSTYPE" in darwin*) diskutil unmount $InstallDir ;; *) umount $InstallDir ;; esac fi if [[ "$InstallDir" == /tmp/refind_install ]] ; then # sleep 5 rmdir "$InstallDir" fi refind-0.11.4/refind.spec0000664000175000017500000002331713372357230015450 0ustar rodsmithrodsmithSummary: EFI boot manager software Name: refind Version: 0.11.4 Release: 1%{?dist} Summary: EFI boot manager software License: GPLv3 URL: http://www.rodsbooks.com/refind/ Group: System Environment/Base Source: refind-src-%version.tar.gz Requires: efibootmgr BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX) %define efiarch unknown %ifarch i386 %define efiarch ia32 %endif %ifarch i486 %define efiarch ia32 %endif %ifarch i586 %define efiarch ia32 %endif %ifarch i686 %define efiarch ia32 %endif %ifarch x86_64 %define efiarch x64 %endif # Directory in which refind.key and refind.crt files are found for # signing of binaries. If absent, binaries are copied unsigned. %define keydir /mnt/refind %description A graphical boot manager for EFI- and UEFI-based computers, such as all Intel-based Macs and recent (most 2011 and later) PCs. rEFInd presents a boot menu showing all the EFI boot loaders on the EFI-accessible partitions, and optionally BIOS-bootable partitions on Macs and BIOS boot entries on UEFI PCs with CSMs. EFI-compatible OSes, including Linux, provide boot loaders that rEFInd can detect and launch. rEFInd can launch Linux EFI boot loaders such as ELILO, GRUB Legacy, GRUB 2, and 3.3.0 and later kernels with EFI stub support. EFI filesystem drivers for ext2/3/4fs, ReiserFS, Btrfs, NTFS, HFS+, and ISO-9660 enable rEFInd to read boot loaders from these filesystems, too. rEFInd's ability to detect boot loaders at runtime makes it very easy to use, particularly when paired with Linux kernels that provide EFI stub support. %prep %setup -q %build make make fs %install rm -rf $RPM_BUILD_ROOT mkdir -p $RPM_BUILD_ROOT/usr/share/refind-%{version}/refind/ # Copy the rEFInd binaries (rEFInd proper and drivers) to /usr/share/refind-%{version}, # including signing the binaries if sbsign is installed and a %{keydir}/refind.key file # is available SBSign=`which sbsign 2> /dev/null` if [[ -f %{keydir}/refind.key && -x $SBSign ]] ; then $SBSign --key %{keydir}/refind.key --cert %{keydir}/refind.crt --output $RPM_BUILD_ROOT/usr/share/refind-%{version}/refind/refind_%{efiarch}.efi refind/refind_%{efiarch}.efi mkdir -p $RPM_BUILD_ROOT/usr/share/refind-%{version}/refind/drivers_%{efiarch} for File in `ls drivers_%{efiarch}/*_x64.efi` ; do $SBSign --key %{keydir}/refind.key --cert %{keydir}/refind.crt --output $RPM_BUILD_ROOT/usr/share/refind-%{version}/refind/$File $File done mkdir -p $RPM_BUILD_ROOT/usr/share/refind-%{version}/refind/tools_%{efiarch} $SBSign --key %{keydir}/refind.key --cert %{keydir}/refind.crt --output $RPM_BUILD_ROOT/usr/share/refind-%{version}/refind/tools_%{efiarch}/gptsync_%{efiarch}.efi gptsync/gptsync_%{efiarch}.efi else install -Dp -m0644 refind/refind*.efi $RPM_BUILD_ROOT/usr/share/refind-%{version}/refind/ mkdir -p $RPM_BUILD_ROOT/usr/share/refind-%{version}/refind/drivers_%{efiarch} cp -a drivers_%{efiarch}/* $RPM_BUILD_ROOT/usr/share/refind-%{version}/refind/drivers_%{efiarch}/ mkdir -p $RPM_BUILD_ROOT/usr/share/refind-%{version}/refind/tools_%{efiarch} install -Dp -m0644 gptsync/gptsync_%{efiarch}.efi $RPM_BUILD_ROOT/usr/share/refind-%{version}/refind/tools_%{efiarch}/gptsync_%{efiarch}.efi fi # Copy configuration and support files to /usr/share/refind-%{version} install -Dp -m0644 refind.conf-sample $RPM_BUILD_ROOT/usr/share/refind-%{version}/refind/ cp -a icons $RPM_BUILD_ROOT/usr/share/refind-%{version}/refind/ rm -rf $RPM_BUILD_ROOT/usr/share/refind-%{version}/refind/icons/svg install -Dp -m0755 refind-install $RPM_BUILD_ROOT/usr/share/refind-%{version}/ # Copy documentation to /usr/share/doc/refind-%{version} mkdir -p $RPM_BUILD_ROOT/usr/share/doc/refind-%{version} cp -a docs/Styles $RPM_BUILD_ROOT/usr/share/doc/refind-%{version}/ cp -a docs/refind $RPM_BUILD_ROOT/usr/share/doc/refind-%{version}/ install -Dp -m0644 NEWS.txt COPYING.txt LICENSE.txt README.txt CREDITS.txt $RPM_BUILD_ROOT/usr/share/doc/refind-%{version} # Copy man pages to /usr/share/man/man8 mkdir -p $RPM_BUILD_ROOT/usr/share/man/man8 install -Dp -m0644 docs/man/mvrefind.8 $RPM_BUILD_ROOT/usr/share/man/man8 install -Dp -m0644 docs/man/mkrlconf.8 $RPM_BUILD_ROOT/usr/share/man/man8 install -Dp -m0644 docs/man/refind-install.8 $RPM_BUILD_ROOT/usr/share/man/man8 install -Dp -m0644 docs/man/refind-mkdefault.8 $RPM_BUILD_ROOT/usr/share/man/man8 # Copy keys to /etc/refind.d/keys mkdir -p $RPM_BUILD_ROOT/etc/refind.d/keys install -Dp -m0644 keys/* $RPM_BUILD_ROOT/etc/refind.d/keys # Copy scripts to /usr/sbin mkdir -p $RPM_BUILD_ROOT/usr/sbin install -Dp -m0755 mkrlconf $RPM_BUILD_ROOT/usr/sbin/ install -Dp -m0755 mvrefind $RPM_BUILD_ROOT/usr/sbin/ install -Dp -m0755 refind-mkdefault $RPM_BUILD_ROOT/usr/sbin/ ln -sr $RPM_BUILD_ROOT/usr/share/refind-%{version}/refind-install $RPM_BUILD_ROOT/usr/sbin # Copy banners and fonts to /usr/share/refind-%{version} cp -a banners $RPM_BUILD_ROOT/usr/share/refind-%{version}/ cp -a fonts $RPM_BUILD_ROOT/usr/share/refind-%{version}/ %clean #rm -rf $RPM_BUILD_ROOT %files %defattr(-,root,root -) %doc /usr/share/doc/refind-%{version} %doc /usr/share/man/man8 /usr/sbin/mkrlconf /usr/sbin/mvrefind /usr/sbin/refind-install /usr/sbin/refind-mkdefault /usr/share/refind-%{version} /etc/refind.d/ %post PATH=$PATH:/usr/local/bin # Remove any existing NVRAM entry for rEFInd, to avoid creating a duplicate. ExistingEntry=`efibootmgr | grep "rEFInd Boot Manager" | cut -c 5-8` if [[ -n $ExistingEntry ]] ; then efibootmgr --bootnum $ExistingEntry --delete-bootnum &> /dev/null fi cd /usr/share/refind-%{version} if [[ -f /sys/firmware/efi/vars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c/data ]] ; then IsSecureBoot=`od -An -t u1 /sys/firmware/efi/vars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c/data | tr -d '[[:space:]]'` else IsSecureBoot="0" fi # Note: Two find operations for ShimFile favors shim over PreLoader -- if both are # present, the script uses shim rather than PreLoader. ShimFile=`find /boot -name shim\.efi -o -name shimx64\.efi -o -name PreLoader\.efi 2> /dev/null | head -n 1` if [[ ! -n $ShimFile ]] ; then ShimFile=`find /boot -name PreLoader\.efi 2> /dev/null | head -n 1` fi SBSign=`which sbsign 2> /dev/null` OpenSSL=`which openssl 2> /dev/null` # Run the rEFInd installation script. Do so with the --shim option # if Secure Boot mode is suspected and if a shim program can be # found, or without it if not. If the sbsign and openssl programs # can be found, do the install using a local signing key. Note that # this option is undesirable for a distribution, since it would # then require the user to enroll an extra MOK. I'm including it # here because I'm NOT a distribution maintainer, and I want to # encourage users to use their own local keys. if [[ $IsSecureBoot == "1" && -n $ShimFile ]] ; then if [[ -n $SBSign && -n $OpenSSL ]] ; then ./refind-install --shim $ShimFile --localkeys --yes else ./refind-install --shim $ShimFile --yes fi else if [[ -n $SBSign && -n $OpenSSL ]] ; then ./refind-install --localkeys --yes else ./refind-install --yes fi fi # CAUTION: Don't create a %preun or a %postun script that deletes the files # installed by refind-install, since that script will run after an update, # thus wiping out the just-updated files. %changelog * Mon Nov 12 2018 R Smith - 0.11.4 - Updated spec file for 0.11.4 * Sun Jul 22 2018 R Smith - 0.11.3 - Updated spec file for 0.11.3 * Sun Oct 22 2017 R Smith - 0.11.2 - Updated spec file for 0.11.2 * Mon Oct 9 2017 R Smith - 0.11.1 - Updated spec file for 0.11.1 * Sun Aug 13 2017 R Smith - 0.11.0 - Updated spec file for 0.11.0 * Sun Jul 30 2017 R Smith - 0.10.9 - Updated spec file for 0.10.9 * Sun May 21 2017 R Smith - 0.10.8 - Updated spec file for 0.10.8 * Mon Apr 17 2017 R Smith - 0.10.7 - Updated spec file for 0.10.7 * Sun Apr 16 2017 R Smith - 0.10.6 - Updated spec file for 0.10.6 * Sat Mar 4 2017 R Smith - 0.10.5 - Updated spec file for 0.10.5 * Sun Oct 9 2016 R Smith - 0.10.4 - Updated spec file for 0.10.4 * Sun Apr 24 2016 R Smith - 0.10.3 - Updated spec file for 0.10.3 * Tue Jan 26 2016 R Smith - 0.10.2 - Updated spec file for 0.10.2 * Sat Dec 12 2015 R Smith - 0.10.1 - Updated spec file for 0.10.1 * Sun Nov 8 2015 R Smith - 0.10.0 - Updated spec file for 0.10.0 * Sat Sep 19 2015 R Smith - 0.9.2 - Updated spec file for 0.9.2 * Sun Sep 13 2015 R Smith - 0.9.1 - Updated spec file for 0.9.1 * Sun Jul 26 2015 R Smith - 0.9.0 - Updated spec file for 0.9.0 * Sun Mar 1 2015 R Smith - 0.8.7 - Updated spec file for 0.8.7 * Sun Feb 8 2015 R Smith - 0.8.6 - Updated spec file for 0.8.6 * Sun Feb 1 2015 R Smith - 0.8.5 - Updated spec file for 0.8.5 * Mon Dec 8 2014 R Smith - 0.8.4 - Updated spec file for 0.8.4 * Sun Jul 6 2014 R Smith - 0.8.3 - Updated spec file for 0.8.3 * Sun Jun 8 2014 R Smith - 0.8.2 - Updated spec file for 0.8.2 * Thu May 15 2014 R Smith - 0.8.1 - Updated spec file for 0.8.1 * Sun May 4 2014 R Smith - 0.8.0 - Updated spec file for 0.8.0 * Sun Apr 20 2014 R Smith - 0.7.9 - Updated spec file for 0.7.9 * Sun Mar 9 2014 R Smith - 0.7.8 - Updated spec file for 0.7.8 * Fri Jan 3 2014 R Smith - 0.7.7 - Created spec file for 0.7.7 release refind-0.11.4/include/0000755000175000017500000000000013372346070014740 5ustar rodsmithrodsmithrefind-0.11.4/include/syslinux_mbr.h0000664000175000017500000000717112626644770017670 0ustar rodsmithrodsmith/* * include/syslinux_mbr.h * MBR boot code * * The boot code in this file was taken from syslinux-3.11. It is covered * by the following license: * ; ----------------------------------------------------------------------- ; ; Copyright 2003-2004 H. Peter Anvin - All Rights Reserved ; ; Permission is hereby granted, free of charge, to any person ; obtaining a copy of this software and associated documentation ; files (the "Software"), to deal in the Software without ; restriction, including without limitation the rights to use, ; copy, modify, merge, publish, distribute, sublicense, and/or ; sell copies of the Software, and to permit persons to whom ; the Software is furnished to do so, subject to the following ; conditions: ; ; The above copyright notice and this permission notice shall ; be included in all copies or substantial portions of the Software. ; ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES ; OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT ; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, ; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ; OTHER DEALINGS IN THE SOFTWARE. ; ; ----------------------------------------------------------------------- * */ #ifndef __SYSLINUX_MBR_H__ #define __SYSLINUX_MBR_H__ #define MBR_BOOTCODE_SIZE (440) #define SYSLINUX_MBR_SIZE (304) static UINT8 syslinux_mbr[SYSLINUX_MBR_SIZE] = { 0xfa, 0x31, 0xc0, 0x8e, 0xd8, 0x8e, 0xc0, 0x8e, 0xd0, 0xbc, 0x00, 0x7c, 0xfb, 0xfc, 0x89, 0xe6, 0xbf, 0x00, 0x06, 0xb9, 0x00, 0x01, 0xf3, 0xa5, 0xea, 0x1d, 0x06, 0x00, 0x00, 0x88, 0x16, 0x00, 0x08, 0xb4, 0x08, 0xcd, 0x13, 0x31, 0xc0, 0x88, 0xf0, 0x40, 0xa3, 0xf0, 0x06, 0x80, 0xe1, 0x3f, 0x88, 0x0e, 0xf2, 0x06, 0xbe, 0xbe, 0x07, 0x31, 0xc0, 0xb9, 0x04, 0x00, 0xf6, 0x04, 0x80, 0x74, 0x03, 0x40, 0x89, 0xf7, 0x83, 0xc6, 0x10, 0xe2, 0xf3, 0x83, 0xf8, 0x01, 0x75, 0x73, 0x8a, 0x16, 0x00, 0x08, 0xb8, 0x00, 0x41, 0xbb, 0xaa, 0x55, 0x31, 0xc9, 0x30, 0xf6, 0xf9, 0xcd, 0x13, 0x72, 0x23, 0x81, 0xfb, 0x55, 0xaa, 0x75, 0x1d, 0xf6, 0xc1, 0x01, 0x74, 0x18, 0x57, 0xbe, 0xe0, 0x06, 0x8b, 0x5d, 0x08, 0x89, 0x5c, 0x08, 0x8b, 0x5d, 0x0a, 0x89, 0x5c, 0x0a, 0x8a, 0x16, 0x00, 0x08, 0xb4, 0x42, 0xeb, 0x2a, 0x57, 0x8b, 0x45, 0x08, 0x8b, 0x55, 0x0a, 0xf7, 0x36, 0xf2, 0x06, 0x42, 0x89, 0xd1, 0x31, 0xd2, 0xf7, 0x36, 0xf0, 0x06, 0x88, 0xc5, 0xd1, 0xe8, 0xd1, 0xe8, 0x24, 0xc0, 0x08, 0xc1, 0x88, 0xd6, 0x8a, 0x16, 0x00, 0x08, 0xbb, 0x00, 0x7c, 0xb8, 0x01, 0x02, 0xcd, 0x13, 0x72, 0x16, 0x5e, 0x81, 0x3e, 0xfe, 0x7d, 0x55, 0xaa, 0x75, 0x08, 0xfa, 0xea, 0x00, 0x7c, 0x00, 0x00, 0x77, 0x05, 0xbe, 0xf4, 0x06, 0xeb, 0x03, 0xbe, 0x0f, 0x07, 0xac, 0x20, 0xc0, 0x74, 0x0c, 0xb4, 0x0e, 0x8a, 0x3e, 0x62, 0x04, 0xb3, 0x07, 0xcd, 0x10, 0xeb, 0xef, 0xeb, 0xfe, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x0d, 0x0a, 0x00, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x0d, 0x0a, 0x00 }; #endif /* __SYSLINUX_MBR_H__ */ /* EOF */ refind-0.11.4/include/tiano_includes.h0000664000175000017500000001011612626644770020123 0ustar rodsmithrodsmith// A boatload of #includes needed to build the software with TianoCore's EDK2/UDK2010 // toolkit. Placed here to maintain my own sanity. #ifndef _REFIND_TIANO_INCLUDES_ #define _REFIND_TIANO_INCLUDES_ #define ST gST #define BS gBS #define RT gRT #define RS gRS #define StrDuplicate EfiStrDuplicate #define LoadedImageProtocol gEfiLoadedImageProtocolGuid #define LibFileInfo EfiLibFileInfo #define Atoi StrDecimalToUintn #define SPrint UnicodeSPrint #define StrDuplicate EfiStrDuplicate #define EFI_MAXIMUM_VARIABLE_SIZE 1024 #include #include #include #include // Protocol Includes #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Guid Includes #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Library Includes #include #include #include #include #include #include //#include //#include //#include "EfiFileLib.h" #include #include #include #include #include #include #include #include #include #include #include // IndustryStandard Includes #include #include #include #include #include #include "../EfiLib/Platform.h" BOOLEAN CheckError(IN EFI_STATUS Status, IN CHAR16 *where); // // BmLib // extern EFI_STATUS EfiLibLocateProtocol ( IN EFI_GUID *ProtocolGuid, OUT VOID **Interface ); extern EFI_FILE_HANDLE EfiLibOpenRoot ( IN EFI_HANDLE DeviceHandle ); extern EFI_FILE_SYSTEM_VOLUME_LABEL * EfiLibFileSystemVolumeLabelInfo ( IN EFI_FILE_HANDLE FHand ); extern CHAR16 * EfiStrDuplicate ( IN CHAR16 *Src ); extern EFI_FILE_INFO * EfiLibFileInfo (IN EFI_FILE_HANDLE FHand); extern EFI_FILE_SYSTEM_INFO * EfiLibFileSystemInfo (IN EFI_FILE_HANDLE Root); extern VOID * EfiReallocatePool ( IN VOID *OldPool, IN UINTN OldSize, IN UINTN NewSize ); #define PoolPrint(...) CatSPrint(NULL, __VA_ARGS__) #endifrefind-0.11.4/include/refit_call_wrapper.h0000664000175000017500000000546212626644770020777 0ustar rodsmithrodsmith#ifndef __REFIT_CALL_WRAPPER_H__ #define __REFIT_CALL_WRAPPER_H__ #ifdef __MAKEWITH_GNUEFI #if defined (EFIX64) | defined (AARCH64) # define refit_call1_wrapper(f, a1) \ uefi_call_wrapper(f, 1, (UINT64)(a1)) # define refit_call2_wrapper(f, a1, a2) \ uefi_call_wrapper(f, 2, (UINT64)(a1), (UINT64)(a2)) # define refit_call3_wrapper(f, a1, a2, a3) \ uefi_call_wrapper(f, 3, (UINT64)(a1), (UINT64)(a2), (UINT64)(a3)) # define refit_call4_wrapper(f, a1, a2, a3, a4) \ uefi_call_wrapper(f, 4, (UINT64)(a1), (UINT64)(a2), (UINT64)(a3), (UINT64)(a4)) # define refit_call5_wrapper(f, a1, a2, a3, a4, a5) \ uefi_call_wrapper(f, 5, (UINT64)(a1), (UINT64)(a2), (UINT64)(a3), (UINT64)(a4), (UINT64)(a5)) # define refit_call6_wrapper(f, a1, a2, a3, a4, a5, a6) \ uefi_call_wrapper(f, 6, (UINT64)(a1), (UINT64)(a2), (UINT64)(a3), (UINT64)(a4), (UINT64)(a5), (UINT64)(a6)) # define refit_call10_wrapper(f, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) \ uefi_call_wrapper(f, 10, (UINT64)(a1), (UINT64)(a2), (UINT64)(a3), (UINT64)(a4), (UINT64)(a5), (UINT64)(a6), (UINT64)(a7), (UINT64)(a8), (UINT64)(a9), (UINT64)(a10)) #else # define refit_call1_wrapper(f, a1) \ uefi_call_wrapper(f, 1, a1) # define refit_call2_wrapper(f, a1, a2) \ uefi_call_wrapper(f, 2, a1, a2) # define refit_call3_wrapper(f, a1, a2, a3) \ uefi_call_wrapper(f, 3, a1, a2, a3) # define refit_call4_wrapper(f, a1, a2, a3, a4) \ uefi_call_wrapper(f, 4, a1, a2, a3, a4) # define refit_call5_wrapper(f, a1, a2, a3, a4, a5) \ uefi_call_wrapper(f, 5, a1, a2, a3, a4, a5) # define refit_call6_wrapper(f, a1, a2, a3, a4, a5, a6) \ uefi_call_wrapper(f, 6, a1, a2, a3, a4, a5, a6) # define refit_call10_wrapper(f, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) \ uefi_call_wrapper(f, 10, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) #endif #else /* not GNU EFI -- TianoCore EDK2 */ #define refit_call1_wrapper(f, a1) \ f(a1) #define refit_call2_wrapper(f, a1, a2) \ f(a1, a2) #define refit_call3_wrapper(f, a1, a2, a3) \ f(a1, a2, a3) #define refit_call4_wrapper(f, a1, a2, a3, a4) \ f(a1, a2, a3, a4) #define refit_call5_wrapper(f, a1, a2, a3, a4, a5) \ f(a1, a2, a3, a4, a5) #define refit_call6_wrapper(f, a1, a2, a3, a4, a5, a6) \ f(a1, a2, a3, a4, a5, a6) #define refit_call7_wrapper(f, a1, a2, a3, a4, a5, a6, a7) \ f(a1, a2, a3, a4, a5, a6, a7) #define refit_call8_wrapper(f, a1, a2, a3, a4, a5, a6, a7, a8) \ f(a1, a2, a3, a4, a5, a6, a7, a8) #define refit_call9_wrapper(f, a1, a2, a3, a4, a5, a6, a7, a8, a9) \ f(a1, a2, a3, a4, a5, a6, a7, a8, a9) #define refit_call10_wrapper(f, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) \ f(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) #define uefi_call_wrapper(f, n, ...) \ f(__VA_ARGS__) #endif /* not GNU EFI -- TianoCore EDK2 */ #endif /* !__REFIT_CALL_WRAPPER_H__ */ refind-0.11.4/include/egemb_arrow_right.h0000664000175000017500000003223012626644770020612 0ustar rodsmithrodsmith/* * include/egemb_arrow_right.h * An encoded right arrow icon * * Copyright (c) 2015 Roderick W. Smith * All rights reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ static const UINT8 egemb_arrow_right_data[2053] = { 0xe2, 0xff, 0x8d, 0x00, 0x9d, 0xff, 0x8e, 0x00, 0x9c, 0xff, 0x90, 0x00, 0x9a, 0xff, 0x92, 0x00, 0x98, 0xff, 0x94, 0x00, 0x96, 0xff, 0x95, 0x00, 0x95, 0xff, 0x97, 0x00, 0x93, 0xff, 0x99, 0x00, 0x91, 0xff, 0x9a, 0x00, 0x90, 0xff, 0x9c, 0x00, 0x8e, 0xff, 0x9e, 0x00, 0x8c, 0xff, 0x9f, 0x00, 0x8b, 0xff, 0xa1, 0x00, 0x89, 0xff, 0xa3, 0x00, 0x87, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa3, 0x00, 0x87, 0xff, 0xa1, 0x00, 0x89, 0xff, 0x9f, 0x00, 0x8b, 0xff, 0x9e, 0x00, 0x8c, 0xff, 0x9c, 0x00, 0x8e, 0xff, 0x9a, 0x00, 0x90, 0xff, 0x99, 0x00, 0x91, 0xff, 0x97, 0x00, 0x93, 0xff, 0x95, 0x00, 0x95, 0xff, 0x94, 0x00, 0x91, 0xff, 0xe2, 0xff, 0x8d, 0x00, 0x9d, 0xff, 0x02, 0x00, 0x7d, 0x51, 0x8b, 0x00, 0x9c, 0xff, 0x03, 0x00, 0x7f, 0x7e, 0x73, 0x8c, 0x00, 0x9a, 0xff, 0x05, 0x00, 0x7f, 0x80, 0x80, 0x7b, 0x5b, 0x8c, 0x00, 0x98, 0xff, 0x01, 0x00, 0x7e, 0x80, 0x80, 0x02, 0x7f, 0x73, 0x35, 0x8c, 0x00, 0x96, 0xff, 0x01, 0x00, 0x7e, 0x82, 0x80, 0x02, 0x7d, 0x67, 0x0e, 0x8b, 0x00, 0x95, 0xff, 0x01, 0x00, 0x7e, 0x84, 0x80, 0x01, 0x79, 0x55, 0x8c, 0x00, 0x93, 0xff, 0x01, 0x00, 0x7e, 0x86, 0x80, 0x01, 0x72, 0x3d, 0x8c, 0x00, 0x91, 0xff, 0x01, 0x00, 0x7e, 0x87, 0x80, 0x02, 0x7d, 0x6a, 0x22, 0x8b, 0x00, 0x90, 0xff, 0x01, 0x00, 0x7d, 0x89, 0x80, 0x02, 0x7b, 0x5d, 0x09, 0x8b, 0x00, 0x8e, 0xff, 0x01, 0x00, 0x7d, 0x8b, 0x80, 0x01, 0x77, 0x4d, 0x8c, 0x00, 0x8c, 0xff, 0x01, 0x00, 0x7d, 0x8d, 0x80, 0x01, 0x71, 0x36, 0x8b, 0x00, 0x8b, 0xff, 0x01, 0x00, 0x7d, 0x8e, 0x80, 0x02, 0x7d, 0x67, 0x1d, 0x8b, 0x00, 0x89, 0xff, 0x01, 0x00, 0x7d, 0x90, 0x80, 0x02, 0x7b, 0x5c, 0x04, 0x8b, 0x00, 0x87, 0xff, 0x01, 0x00, 0x7d, 0x92, 0x80, 0x01, 0x76, 0x49, 0x8c, 0x00, 0x85, 0xff, 0x01, 0x00, 0x7d, 0x94, 0x80, 0x01, 0x6e, 0x31, 0x8a, 0x00, 0x85, 0xff, 0x01, 0x00, 0x7d, 0x95, 0x80, 0x02, 0x7d, 0x65, 0x17, 0x88, 0x00, 0x85, 0xff, 0x01, 0x00, 0x7d, 0x97, 0x80, 0x01, 0x7a, 0x5a, 0x87, 0x00, 0x85, 0xff, 0x01, 0x00, 0x7d, 0x99, 0x80, 0x01, 0x74, 0x45, 0x85, 0x00, 0x85, 0xff, 0x01, 0x00, 0x7d, 0x9a, 0x80, 0x02, 0x7e, 0x6c, 0x2b, 0x83, 0x00, 0x85, 0xff, 0x01, 0x00, 0x7d, 0x9c, 0x80, 0x02, 0x7c, 0x63, 0x0d, 0x81, 0x00, 0x85, 0xff, 0x01, 0x00, 0x7d, 0x9e, 0x80, 0x01, 0x79, 0x58, 0x80, 0x00, 0x85, 0xff, 0x01, 0x00, 0x7d, 0x9e, 0x80, 0x01, 0x77, 0x54, 0x80, 0x00, 0x85, 0xff, 0x01, 0x00, 0x7d, 0x9c, 0x80, 0x02, 0x7a, 0x58, 0x09, 0x81, 0x00, 0x85, 0xff, 0x01, 0x00, 0x7d, 0x9a, 0x80, 0x02, 0x7d, 0x5f, 0x1a, 0x83, 0x00, 0x85, 0xff, 0x01, 0x00, 0x7d, 0x99, 0x80, 0x01, 0x69, 0x2c, 0x85, 0x00, 0x85, 0xff, 0x01, 0x00, 0x7d, 0x97, 0x80, 0x01, 0x73, 0x3e, 0x87, 0x00, 0x85, 0xff, 0x01, 0x00, 0x7d, 0x95, 0x80, 0x02, 0x7a, 0x4e, 0x0a, 0x88, 0x00, 0x85, 0xff, 0x01, 0x00, 0x7d, 0x93, 0x80, 0x02, 0x7e, 0x5e, 0x19, 0x8a, 0x00, 0x85, 0xff, 0x01, 0x00, 0x7d, 0x92, 0x80, 0x01, 0x6b, 0x2c, 0x8c, 0x00, 0x85, 0xff, 0x01, 0x00, 0x7d, 0x90, 0x80, 0x02, 0x75, 0x42, 0x02, 0x8d, 0x00, 0x85, 0xff, 0x01, 0x00, 0x7d, 0x8e, 0x80, 0x02, 0x7a, 0x51, 0x0d, 0x8f, 0x00, 0x85, 0xff, 0x01, 0x00, 0x7d, 0x8d, 0x80, 0x01, 0x61, 0x1d, 0x91, 0x00, 0x85, 0xff, 0x01, 0x00, 0x7d, 0x8b, 0x80, 0x01, 0x6d, 0x31, 0x93, 0x00, 0x85, 0xff, 0x01, 0x00, 0x7d, 0x89, 0x80, 0x02, 0x76, 0x44, 0x03, 0x94, 0x00, 0x85, 0xff, 0x01, 0x00, 0x7d, 0x87, 0x80, 0x02, 0x7c, 0x55, 0x10, 0x96, 0x00, 0x85, 0xff, 0x01, 0x00, 0x7d, 0x85, 0x80, 0x02, 0x7f, 0x64, 0x22, 0x96, 0x00, 0x87, 0xff, 0x01, 0x00, 0x7d, 0x84, 0x80, 0x01, 0x71, 0x38, 0x96, 0x00, 0x89, 0xff, 0x01, 0x00, 0x7d, 0x82, 0x80, 0x02, 0x79, 0x4d, 0x05, 0x95, 0x00, 0x8b, 0xff, 0x01, 0x00, 0x7d, 0x80, 0x80, 0x02, 0x7e, 0x61, 0x18, 0x96, 0x00, 0x8c, 0xff, 0x05, 0x00, 0x7d, 0x80, 0x80, 0x71, 0x35, 0x96, 0x00, 0x8e, 0xff, 0x03, 0x00, 0x7e, 0x7b, 0x5a, 0x96, 0x00, 0x90, 0xff, 0x02, 0x00, 0x71, 0x1f, 0x96, 0x00, 0x91, 0xff, 0x97, 0x00, 0x93, 0xff, 0x95, 0x00, 0x95, 0xff, 0x94, 0x00, 0x91, 0xff, 0xe2, 0xff, 0x8d, 0x00, 0x9d, 0xff, 0x8e, 0x00, 0x9c, 0xff, 0x90, 0x00, 0x9a, 0xff, 0x92, 0x00, 0x98, 0xff, 0x94, 0x00, 0x96, 0xff, 0x95, 0x00, 0x95, 0xff, 0x97, 0x00, 0x93, 0xff, 0x99, 0x00, 0x91, 0xff, 0x9a, 0x00, 0x90, 0xff, 0x9c, 0x00, 0x8e, 0xff, 0x9e, 0x00, 0x8c, 0xff, 0x9f, 0x00, 0x8b, 0xff, 0xa1, 0x00, 0x89, 0xff, 0xa3, 0x00, 0x87, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa3, 0x00, 0x87, 0xff, 0xa1, 0x00, 0x89, 0xff, 0x9f, 0x00, 0x8b, 0xff, 0x9e, 0x00, 0x8c, 0xff, 0x9c, 0x00, 0x8e, 0xff, 0x9a, 0x00, 0x90, 0xff, 0x99, 0x00, 0x91, 0xff, 0x97, 0x00, 0x93, 0xff, 0x95, 0x00, 0x95, 0xff, 0x94, 0x00, 0x91, 0xff, 0xe2, 0x00, 0x03, 0x02, 0x04, 0x05, 0x06, 0x81, 0x07, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x02, 0x01, 0x01, 0x9d, 0x00, 0x10, 0x04, 0x78, 0x13, 0x0a, 0x0b, 0x0c, 0x0d, 0x0c, 0x0b, 0x0a, 0x08, 0x06, 0x05, 0x03, 0x02, 0x01, 0x01, 0x9c, 0x00, 0x12, 0x06, 0xe5, 0xd8, 0x64, 0x11, 0x13, 0x14, 0x13, 0x12, 0x10, 0x0d, 0x0b, 0x08, 0x06, 0x04, 0x03, 0x02, 0x01, 0x01, 0x9a, 0x00, 0x14, 0x08, 0xe5, 0xff, 0xff, 0xbf, 0x4c, 0x1d, 0x1d, 0x1b, 0x18, 0x15, 0x11, 0x0e, 0x0b, 0x08, 0x06, 0x04, 0x03, 0x02, 0x01, 0x01, 0x98, 0x00, 0x01, 0x0b, 0xe6, 0x80, 0xff, 0x11, 0xf9, 0xa7, 0x3e, 0x27, 0x24, 0x1f, 0x1b, 0x16, 0x11, 0x0d, 0x0a, 0x07, 0x05, 0x03, 0x02, 0x02, 0x01, 0x01, 0x96, 0x00, 0x01, 0x0e, 0xe6, 0x82, 0xff, 0x10, 0xed, 0x90, 0x36, 0x2c, 0x26, 0x20, 0x1a, 0x15, 0x10, 0x0c, 0x09, 0x07, 0x05, 0x03, 0x02, 0x01, 0x01, 0x95, 0x00, 0x01, 0x11, 0xe7, 0x84, 0xff, 0x10, 0xdb, 0x78, 0x35, 0x2d, 0x26, 0x1f, 0x19, 0x13, 0x0f, 0x0b, 0x08, 0x06, 0x04, 0x03, 0x02, 0x01, 0x01, 0x93, 0x00, 0x01, 0x14, 0xe7, 0x85, 0xff, 0x11, 0xfe, 0xc5, 0x60, 0x34, 0x2c, 0x24, 0x1d, 0x17, 0x12, 0x0e, 0x0a, 0x08, 0x05, 0x04, 0x03, 0x02, 0x01, 0x01, 0x91, 0x00, 0x01, 0x16, 0xe7, 0x87, 0xff, 0x10, 0xf8, 0xab, 0x4a, 0x32, 0x2a, 0x22, 0x1b, 0x16, 0x11, 0x0d, 0x0a, 0x07, 0x05, 0x03, 0x02, 0x01, 0x01, 0x90, 0x00, 0x01, 0x18, 0xe8, 0x89, 0xff, 0x10, 0xeb, 0x91, 0x3a, 0x2f, 0x27, 0x20, 0x1a, 0x14, 0x10, 0x0c, 0x09, 0x06, 0x05, 0x03, 0x02, 0x01, 0x01, 0x8e, 0x00, 0x01, 0x19, 0xe8, 0x8b, 0xff, 0x10, 0xd7, 0x74, 0x36, 0x2d, 0x25, 0x1e, 0x18, 0x13, 0x0f, 0x0b, 0x08, 0x06, 0x04, 0x03, 0x02, 0x01, 0x01, 0x8c, 0x00, 0x01, 0x1a, 0xe8, 0x8c, 0xff, 0x10, 0xfe, 0xbe, 0x59, 0x33, 0x2b, 0x23, 0x1d, 0x17, 0x12, 0x0e, 0x0a, 0x07, 0x05, 0x04, 0x02, 0x01, 0x01, 0x8b, 0x00, 0x01, 0x1a, 0xe8, 0x8e, 0xff, 0x10, 0xf5, 0xa4, 0x46, 0x31, 0x29, 0x22, 0x1b, 0x16, 0x11, 0x0d, 0x09, 0x07, 0x05, 0x03, 0x02, 0x01, 0x01, 0x89, 0x00, 0x01, 0x1b, 0xe8, 0x90, 0xff, 0x10, 0xe6, 0x8a, 0x39, 0x2f, 0x27, 0x20, 0x1a, 0x14, 0x0f, 0x0c, 0x09, 0x06, 0x04, 0x03, 0x02, 0x01, 0x01, 0x87, 0x00, 0x01, 0x1b, 0xe8, 0x92, 0xff, 0x10, 0xd2, 0x6d, 0x35, 0x2d, 0x25, 0x1e, 0x18, 0x13, 0x0e, 0x0b, 0x08, 0x06, 0x04, 0x03, 0x02, 0x01, 0x01, 0x85, 0x00, 0x01, 0x1b, 0xe8, 0x93, 0xff, 0x0f, 0xfc, 0xb9, 0x54, 0x33, 0x2a, 0x23, 0x1c, 0x17, 0x12, 0x0d, 0x0a, 0x07, 0x05, 0x04, 0x03, 0x02, 0x85, 0x00, 0x01, 0x1b, 0xe8, 0x95, 0xff, 0x0d, 0xf2, 0x9f, 0x42, 0x31, 0x28, 0x21, 0x1b, 0x15, 0x10, 0x0d, 0x09, 0x07, 0x05, 0x03, 0x85, 0x00, 0x01, 0x1b, 0xe8, 0x97, 0xff, 0x0b, 0xe2, 0x83, 0x37, 0x2e, 0x26, 0x1f, 0x19, 0x14, 0x0f, 0x0b, 0x08, 0x05, 0x85, 0x00, 0x01, 0x1b, 0xe8, 0x99, 0xff, 0x09, 0xcc, 0x68, 0x35, 0x2c, 0x24, 0x1d, 0x16, 0x11, 0x0d, 0x09, 0x85, 0x00, 0x01, 0x1b, 0xe8, 0x9a, 0xff, 0x08, 0xfa, 0xb3, 0x4e, 0x31, 0x28, 0x20, 0x18, 0x12, 0x0d, 0x85, 0x00, 0x01, 0x1b, 0xe8, 0x9c, 0xff, 0x06, 0xef, 0x98, 0x39, 0x2a, 0x21, 0x19, 0x12, 0x85, 0x00, 0x01, 0x1b, 0xe8, 0x9e, 0xff, 0x04, 0xdc, 0x77, 0x2a, 0x20, 0x17, 0x85, 0x00, 0x01, 0x1b, 0xe8, 0x9e, 0xff, 0x04, 0xde, 0x7d, 0x32, 0x27, 0x1c, 0x85, 0x00, 0x01, 0x1b, 0xe8, 0x9c, 0xff, 0x06, 0xf2, 0xab, 0x58, 0x46, 0x38, 0x2c, 0x20, 0x85, 0x00, 0x01, 0x1b, 0xe8, 0x9a, 0xff, 0x08, 0xfc, 0xcc, 0x82, 0x67, 0x59, 0x4a, 0x3c, 0x2f, 0x23, 0x85, 0x00, 0x01, 0x1b, 0xe8, 0x99, 0xff, 0x09, 0xe2, 0xa4, 0x80, 0x74, 0x67, 0x59, 0x4a, 0x3c, 0x2f, 0x23, 0x85, 0x00, 0x01, 0x1b, 0xe8, 0x97, 0xff, 0x0b, 0xef, 0xbc, 0x8f, 0x86, 0x7b, 0x6f, 0x62, 0x54, 0x46, 0x38, 0x2c, 0x20, 0x85, 0x00, 0x01, 0x1b, 0xe8, 0x95, 0xff, 0x0d, 0xf8, 0xcd, 0x9b, 0x8f, 0x86, 0x7c, 0x71, 0x65, 0x59, 0x4c, 0x3f, 0x32, 0x27, 0x1c, 0x85, 0x00, 0x01, 0x1b, 0xe8, 0x93, 0xff, 0x0f, 0xfe, 0xda, 0xa6, 0x93, 0x8b, 0x83, 0x79, 0x6f, 0x64, 0x58, 0x4c, 0x40, 0x35, 0x2a, 0x20, 0x17, 0x85, 0x00, 0x01, 0x1b, 0xe8, 0x92, 0xff, 0x10, 0xe8, 0xb3, 0x95, 0x8e, 0x86, 0x7d, 0x74, 0x6a, 0x5f, 0x54, 0x49, 0x3f, 0x34, 0x2a, 0x21, 0x19, 0x12, 0x85, 0x00, 0x01, 0x1b, 0xe8, 0x90, 0xff, 0x12, 0xf2, 0xc2, 0x96, 0x90, 0x88, 0x80, 0x77, 0x6d, 0x63, 0x59, 0x4e, 0x44, 0x3a, 0x31, 0x28, 0x20, 0x18, 0x12, 0x0d, 0x85, 0x00, 0x01, 0x1b, 0xe8, 0x8e, 0xff, 0x14, 0xfa, 0xd0, 0x9e, 0x91, 0x8a, 0x82, 0x79, 0x70, 0x66, 0x5c, 0x52, 0x47, 0x3e, 0x35, 0x2c, 0x24, 0x1d, 0x16, 0x11, 0x0d, 0x09, 0x85, 0x00, 0x01, 0x1b, 0xe8, 0x8c, 0xff, 0x16, 0xfe, 0xdd, 0xa8, 0x93, 0x8c, 0x84, 0x7b, 0x72, 0x68, 0x5e, 0x54, 0x4a, 0x40, 0x37, 0x2e, 0x26, 0x1f, 0x19, 0x14, 0x0f, 0x0b, 0x08, 0x05, 0x85, 0x00, 0x01, 0x1b, 0xe8, 0x8b, 0xff, 0x17, 0xea, 0xb6, 0x95, 0x8e, 0x86, 0x7e, 0x75, 0x6b, 0x61, 0x57, 0x4d, 0x43, 0x39, 0x31, 0x28, 0x21, 0x1b, 0x15, 0x10, 0x0d, 0x09, 0x07, 0x05, 0x03, 0x85, 0x00, 0x01, 0x1b, 0xe8, 0x89, 0xff, 0x19, 0xf4, 0xc6, 0x98, 0x90, 0x89, 0x80, 0x77, 0x6e, 0x64, 0x5a, 0x4f, 0x45, 0x3c, 0x33, 0x2a, 0x23, 0x1c, 0x17, 0x12, 0x0d, 0x0a, 0x07, 0x05, 0x04, 0x03, 0x02, 0x85, 0x00, 0x01, 0x1b, 0xe8, 0x87, 0xff, 0x1b, 0xfb, 0xd4, 0xa1, 0x92, 0x8b, 0x83, 0x7a, 0x70, 0x66, 0x5c, 0x52, 0x48, 0x3e, 0x35, 0x2d, 0x25, 0x1e, 0x18, 0x13, 0x0e, 0x0b, 0x08, 0x06, 0x04, 0x03, 0x02, 0x01, 0x01, 0x85, 0x00, 0x01, 0x1b, 0xe8, 0x86, 0xff, 0x1a, 0xe0, 0xab, 0x94, 0x8d, 0x85, 0x7c, 0x73, 0x69, 0x5f, 0x55, 0x4b, 0x41, 0x38, 0x2f, 0x27, 0x20, 0x1a, 0x14, 0x0f, 0x0c, 0x09, 0x06, 0x04, 0x03, 0x02, 0x01, 0x01, 0x87, 0x00, 0x01, 0x1a, 0xe8, 0x84, 0xff, 0x1a, 0xeb, 0xb7, 0x93, 0x8e, 0x87, 0x7f, 0x76, 0x6c, 0x62, 0x58, 0x4d, 0x43, 0x3a, 0x31, 0x29, 0x22, 0x1b, 0x16, 0x11, 0x0d, 0x09, 0x07, 0x05, 0x03, 0x02, 0x01, 0x01, 0x89, 0x00, 0x01, 0x1a, 0xe8, 0x82, 0xff, 0x1a, 0xf4, 0xbf, 0x8f, 0x8b, 0x87, 0x80, 0x78, 0x6f, 0x65, 0x5a, 0x50, 0x46, 0x3c, 0x33, 0x2b, 0x23, 0x1d, 0x17, 0x12, 0x0e, 0x0a, 0x07, 0x05, 0x04, 0x02, 0x01, 0x01, 0x8b, 0x00, 0x01, 0x19, 0xe8, 0x80, 0xff, 0x1b, 0xfb, 0xc5, 0x89, 0x80, 0x80, 0x7e, 0x78, 0x70, 0x67, 0x5d, 0x53, 0x49, 0x3f, 0x36, 0x2d, 0x25, 0x1e, 0x18, 0x13, 0x0f, 0x0b, 0x08, 0x06, 0x04, 0x03, 0x02, 0x01, 0x01, 0x8c, 0x00, 0x1e, 0x18, 0xe8, 0xff, 0xff, 0xcf, 0x81, 0x6a, 0x71, 0x74, 0x72, 0x6e, 0x68, 0x5f, 0x56, 0x4c, 0x42, 0x38, 0x2f, 0x27, 0x20, 0x1a, 0x14, 0x10, 0x0c, 0x09, 0x06, 0x05, 0x03, 0x02, 0x01, 0x01, 0x8e, 0x00, 0x1c, 0x16, 0xe7, 0xdd, 0x80, 0x4a, 0x56, 0x5f, 0x64, 0x65, 0x62, 0x5d, 0x56, 0x4d, 0x44, 0x3b, 0x32, 0x2a, 0x22, 0x1b, 0x16, 0x11, 0x0d, 0x0a, 0x07, 0x05, 0x03, 0x02, 0x01, 0x01, 0x90, 0x00, 0x1b, 0x14, 0x85, 0x31, 0x35, 0x41, 0x4b, 0x52, 0x55, 0x55, 0x52, 0x4c, 0x45, 0x3d, 0x34, 0x2c, 0x24, 0x1d, 0x17, 0x12, 0x0e, 0x0a, 0x08, 0x05, 0x04, 0x03, 0x02, 0x01, 0x01, 0x91, 0x00, 0x19, 0x11, 0x19, 0x23, 0x2d, 0x37, 0x3f, 0x44, 0x46, 0x44, 0x41, 0x3b, 0x35, 0x2d, 0x26, 0x1f, 0x19, 0x13, 0x0f, 0x0b, 0x08, 0x06, 0x04, 0x03, 0x02, 0x01, 0x01, 0x93, 0x00, 0x17, 0x0e, 0x15, 0x1c, 0x25, 0x2c, 0x32, 0x36, 0x36, 0x35, 0x31, 0x2c, 0x26, 0x20, 0x1a, 0x15, 0x10, 0x0c, 0x09, 0x07, 0x05, 0x03, 0x02, 0x01, 0x01, 0x95, 0x00, 0x16, 0x0b, 0x10, 0x16, 0x1c, 0x22, 0x26, 0x29, 0x29, 0x27, 0x24, 0x1f, 0x1b, 0x16, 0x11, 0x0d, 0x0a, 0x07, 0x05, 0x03, 0x02, 0x02, 0x01, 0x01, 0x91, 0x00, }; static EG_EMBEDDED_IMAGE egemb_arrow_right = { 48, 48, EG_EIPIXELMODE_COLOR_ALPHA, EG_EICOMPMODE_RLE, egemb_arrow_right_data, 2053 }; refind-0.11.4/include/Bmp.h0000664000175000017500000000252412626644770015645 0ustar rodsmithrodsmith/** @file This file defines BMP file header data structures. Copyright (c) 2006 - 2008, Intel Corporation.
All rights reserved. This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ #ifndef _BMP_H__ #define _BMP_H__ #pragma pack(1) typedef struct { UINT8 Blue; UINT8 Green; UINT8 Red; UINT8 Reserved; } BMP_COLOR_MAP; typedef struct { CHAR8 CharB; CHAR8 CharM; UINT32 Size; UINT16 Reserved[2]; UINT32 ImageOffset; UINT32 HeaderSize; UINT32 PixelWidth; UINT32 PixelHeight; UINT16 Planes; ///> Must be 1 UINT16 BitPerPixel; ///> 1, 4, 8, or 24 UINT32 CompressionType; UINT32 ImageSize; ///> Compressed image size in bytes UINT32 XPixelsPerMeter; UINT32 YPixelsPerMeter; UINT32 NumberOfColors; UINT32 ImportantColors; } BMP_IMAGE_HEADER; #pragma pack() #endif refind-0.11.4/include/PeImage2.h0000664000175000017500000000341312626644770016516 0ustar rodsmithrodsmith/** @file EFI image format for PE32, PE32+ and TE. Please note some data structures are different for PE32 and PE32+. EFI_IMAGE_NT_HEADERS32 is for PE32 and EFI_IMAGE_NT_HEADERS64 is for PE32+. This file is coded to the Visual Studio, Microsoft Portable Executable and Common Object File Format Specification, Revision 8.0 - May 16, 2006. This file also includes some definitions in PI Specification, Revision 1.0. Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php. THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ /* * Stripped down because the original file was flaking out on me and I just * needed the one definition.... * */ #ifndef _PEIMAGE2_H_ #define _PEIMAGE2_H_ typedef struct _GNUEFI_PE_COFF_LOADER_IMAGE_CONTEXT { UINT64 ImageAddress; UINT64 ImageSize; UINT64 EntryPoint; UINTN SizeOfHeaders; UINT16 ImageType; UINT16 NumberOfSections; EFI_IMAGE_SECTION_HEADER *FirstSection; EFI_IMAGE_DATA_DIRECTORY *RelocDir; EFI_IMAGE_DATA_DIRECTORY *SecDir; UINT64 NumberOfRvaAndSizes; EFI_IMAGE_OPTIONAL_HEADER_UNION *PEHdr; } GNUEFI_PE_COFF_LOADER_IMAGE_CONTEXT; #endif refind-0.11.4/include/egemb_back_selected_big.h0000664000175000017500000013670212626644770021665 0ustar rodsmithrodsmithstatic const UINT8 egemb_back_selected_big_data[7951] = { 0x83, 0x30, 0xff, 0xff, 0x01, 0xff, 0xff, 0x87, 0x30, 0xff, 0xff, 0x83, 0xff, 0x84, 0x30, 0x85, 0xff, 0x03, 0x30, 0x20, 0x18, 0x13, 0xef, 0x10, 0x03, 0x13, 0x18, 0x20, 0x30, 0x85, 0xff, 0x82, 0x30, 0x83, 0xff, 0x02, 0x0d, 0x07, 0x05, 0xf7, 0x04, 0x02, 0x05, 0x07, 0x0d, 0x83, 0xff, 0x80, 0x30, 0x82, 0xff, 0x03, 0x13, 0x06, 0x04, 0x03, 0xf9, 0x02, 0x03, 0x03, 0x04, 0x06, 0x13, 0x82, 0xff, 0x01, 0x30, 0x60, 0x81, 0xff, 0x02, 0x0c, 0x04, 0x03, 0x80, 0x02, 0xf7, 0x01, 0x80, 0x02, 0x02, 0x03, 0x04, 0x0c, 0x81, 0xff, 0x00, 0x60, 0x81, 0xff, 0x03, 0x10, 0x04, 0x03, 0x02, 0xfd, 0x01, 0x03, 0x02, 0x03, 0x04, 0x10, 0x85, 0xff, 0x02, 0x06, 0x03, 0x02, 0xff, 0x01, 0x02, 0x02, 0x03, 0x06, 0x84, 0xff, 0x02, 0x0d, 0x04, 0x02, 0xff, 0x01, 0x04, 0x01, 0x01, 0x02, 0x04, 0x0d, 0x83, 0xff, 0x02, 0x07, 0x03, 0x02, 0xff, 0x01, 0x04, 0x01, 0x01, 0x02, 0x03, 0x07, 0x83, 0xff, 0x02, 0x05, 0x02, 0x02, 0xff, 0x01, 0x04, 0x01, 0x01, 0x02, 0x02, 0x05, 0x82, 0xff, 0x02, 0x30, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x30, 0x81, 0xff, 0x02, 0x20, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x20, 0x81, 0xff, 0x02, 0x13, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x13, 0x81, 0xff, 0x02, 0x13, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x13, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x13, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x13, 0x81, 0xff, 0x02, 0x13, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x13, 0x81, 0xff, 0x02, 0x20, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x20, 0x81, 0xff, 0x02, 0x30, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x30, 0x82, 0xff, 0x02, 0x05, 0x02, 0x02, 0xff, 0x01, 0x04, 0x01, 0x01, 0x02, 0x02, 0x05, 0x83, 0xff, 0x02, 0x07, 0x03, 0x02, 0xff, 0x01, 0x04, 0x01, 0x01, 0x02, 0x03, 0x07, 0x83, 0xff, 0x02, 0x0d, 0x04, 0x02, 0xff, 0x01, 0x04, 0x01, 0x01, 0x02, 0x04, 0x0d, 0x84, 0xff, 0x02, 0x06, 0x03, 0x02, 0xff, 0x01, 0x02, 0x02, 0x03, 0x06, 0x85, 0xff, 0x03, 0x10, 0x04, 0x03, 0x02, 0xfd, 0x01, 0x03, 0x02, 0x03, 0x04, 0x10, 0x81, 0xff, 0x00, 0x60, 0x81, 0xff, 0x02, 0x0c, 0x04, 0x03, 0x80, 0x02, 0xf7, 0x01, 0x80, 0x02, 0x02, 0x03, 0x04, 0x0c, 0x81, 0xff, 0x01, 0x60, 0x30, 0x82, 0xff, 0x03, 0x10, 0x06, 0x04, 0x03, 0xf9, 0x02, 0x03, 0x03, 0x04, 0x06, 0x10, 0x82, 0xff, 0x80, 0x30, 0x83, 0xff, 0x02, 0x0d, 0x07, 0x05, 0xf7, 0x04, 0x02, 0x05, 0x07, 0x0d, 0x83, 0xff, 0x82, 0x30, 0x85, 0xff, 0x03, 0x30, 0x20, 0x13, 0x13, 0xef, 0x10, 0x03, 0x13, 0x13, 0x20, 0x30, 0x85, 0xff, 0x84, 0x30, 0xff, 0xff, 0x83, 0xff, 0x87, 0x30, 0xff, 0xff, 0x01, 0xff, 0xff, 0x83, 0x30, 0x83, 0x00, 0x00, 0xfb, 0xff, 0xfe, 0x00, 0xfb, 0x87, 0x00, 0x00, 0xf3, 0x86, 0xfe, 0xf1, 0xfd, 0x86, 0xfe, 0x00, 0xf3, 0x84, 0x00, 0x00, 0xfd, 0x81, 0xfe, 0x02, 0xfd, 0xfb, 0xf3, 0xf7, 0x00, 0x02, 0xf3, 0xfb, 0xfd, 0x81, 0xfe, 0x00, 0xfd, 0x82, 0x00, 0x00, 0xfd, 0x80, 0xfe, 0x01, 0xfd, 0xf3, 0xfd, 0x00, 0x01, 0xf3, 0xfd, 0x80, 0xfe, 0x00, 0xfd, 0x80, 0x00, 0x00, 0xfc, 0x80, 0xfe, 0x00, 0xfb, 0xff, 0x00, 0x02, 0x00, 0x00, 0xfb, 0x80, 0xfe, 0x02, 0xfc, 0x00, 0x00, 0x80, 0xfe, 0x00, 0xfb, 0xff, 0x00, 0x81, 0x00, 0x00, 0xfb, 0x80, 0xfe, 0x04, 0x00, 0xfc, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x83, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfc, 0x80, 0xfe, 0x00, 0xeb, 0xff, 0x00, 0x83, 0x00, 0x00, 0xeb, 0x82, 0xfe, 0x00, 0xfd, 0xff, 0x00, 0x85, 0x00, 0x00, 0xfd, 0x81, 0xfe, 0x00, 0xfa, 0xff, 0x00, 0x85, 0x00, 0x00, 0xfa, 0x81, 0xfe, 0x00, 0xf3, 0xff, 0x00, 0x85, 0x00, 0x00, 0xeb, 0x81, 0xfe, 0xff, 0x00, 0x87, 0x00, 0x81, 0xfe, 0xff, 0x00, 0x87, 0x00, 0x81, 0xfe, 0xff, 0x00, 0x87, 0x00, 0x80, 0xfe, 0x00, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x00, 0xfd, 0x80, 0xfe, 0xff, 0x00, 0x87, 0x00, 0x81, 0xfe, 0xff, 0x00, 0x87, 0x00, 0x81, 0xfe, 0xff, 0x00, 0x87, 0x00, 0x81, 0xfe, 0x00, 0xeb, 0xff, 0x00, 0x85, 0x00, 0x00, 0xeb, 0x81, 0xfe, 0x00, 0xfa, 0xff, 0x00, 0x85, 0x00, 0x00, 0xfa, 0x81, 0xfe, 0x00, 0xfd, 0xff, 0x00, 0x85, 0x00, 0x00, 0xfd, 0x82, 0xfe, 0x00, 0xeb, 0xff, 0x00, 0x83, 0x00, 0x00, 0xeb, 0x80, 0xfe, 0x03, 0xfc, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x83, 0x00, 0x04, 0xfd, 0xfe, 0xfe, 0xfc, 0x00, 0x80, 0xfe, 0x00, 0xfb, 0xff, 0x00, 0x81, 0x00, 0x00, 0xfb, 0x80, 0xfe, 0x02, 0x00, 0x00, 0xfc, 0x80, 0xfe, 0x00, 0xfb, 0xff, 0x00, 0x02, 0x00, 0x00, 0xfb, 0x80, 0xfe, 0x00, 0xfc, 0x80, 0x00, 0x00, 0xfd, 0x80, 0xfe, 0x01, 0xfd, 0xeb, 0xfd, 0x00, 0x01, 0xeb, 0xfd, 0x80, 0xfe, 0x00, 0xfd, 0x82, 0x00, 0x00, 0xfd, 0x81, 0xfe, 0x02, 0xfd, 0xfb, 0xf3, 0xf7, 0x00, 0x02, 0xf3, 0xfb, 0xfd, 0x81, 0xfe, 0x00, 0xfd, 0x84, 0x00, 0x00, 0xf3, 0x86, 0xfe, 0xf1, 0xfd, 0x86, 0xfe, 0x00, 0xf7, 0x87, 0x00, 0x00, 0xfc, 0xff, 0xfe, 0x00, 0xfc, 0x83, 0x00, 0x83, 0x00, 0x00, 0xfb, 0xff, 0xfe, 0x00, 0xfb, 0x87, 0x00, 0x00, 0xf3, 0x86, 0xfe, 0xf1, 0xfd, 0x86, 0xfe, 0x00, 0xf3, 0x84, 0x00, 0x00, 0xfd, 0x81, 0xfe, 0x02, 0xfd, 0xfb, 0xf3, 0xf7, 0x00, 0x02, 0xf3, 0xfb, 0xfd, 0x81, 0xfe, 0x00, 0xfd, 0x82, 0x00, 0x00, 0xfd, 0x80, 0xfe, 0x01, 0xfd, 0xf3, 0xfd, 0x00, 0x01, 0xf3, 0xfd, 0x80, 0xfe, 0x00, 0xfd, 0x80, 0x00, 0x00, 0xfc, 0x80, 0xfe, 0x00, 0xfb, 0xff, 0x00, 0x02, 0x00, 0x00, 0xfb, 0x80, 0xfe, 0x02, 0xfc, 0x00, 0x00, 0x80, 0xfe, 0x00, 0xfb, 0xff, 0x00, 0x81, 0x00, 0x00, 0xfb, 0x80, 0xfe, 0x04, 0x00, 0xfc, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x83, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfc, 0x80, 0xfe, 0x00, 0xeb, 0xff, 0x00, 0x83, 0x00, 0x00, 0xeb, 0x82, 0xfe, 0x00, 0xfd, 0xff, 0x00, 0x85, 0x00, 0x00, 0xfd, 0x81, 0xfe, 0x00, 0xfa, 0xff, 0x00, 0x85, 0x00, 0x00, 0xfa, 0x81, 0xfe, 0x00, 0xf3, 0xff, 0x00, 0x85, 0x00, 0x00, 0xeb, 0x81, 0xfe, 0xff, 0x00, 0x87, 0x00, 0x81, 0xfe, 0xff, 0x00, 0x87, 0x00, 0x81, 0xfe, 0xff, 0x00, 0x87, 0x00, 0x80, 0xfe, 0x00, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x00, 0xfd, 0x80, 0xfe, 0xff, 0x00, 0x87, 0x00, 0x81, 0xfe, 0xff, 0x00, 0x87, 0x00, 0x81, 0xfe, 0xff, 0x00, 0x87, 0x00, 0x81, 0xfe, 0x00, 0xeb, 0xff, 0x00, 0x85, 0x00, 0x00, 0xeb, 0x81, 0xfe, 0x00, 0xfa, 0xff, 0x00, 0x85, 0x00, 0x00, 0xfa, 0x81, 0xfe, 0x00, 0xfd, 0xff, 0x00, 0x85, 0x00, 0x00, 0xfd, 0x82, 0xfe, 0x00, 0xeb, 0xff, 0x00, 0x83, 0x00, 0x00, 0xeb, 0x80, 0xfe, 0x03, 0xfc, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x83, 0x00, 0x04, 0xfd, 0xfe, 0xfe, 0xfc, 0x00, 0x80, 0xfe, 0x00, 0xfb, 0xff, 0x00, 0x81, 0x00, 0x00, 0xfb, 0x80, 0xfe, 0x02, 0x00, 0x00, 0xfc, 0x80, 0xfe, 0x00, 0xfb, 0xff, 0x00, 0x02, 0x00, 0x00, 0xfb, 0x80, 0xfe, 0x00, 0xfc, 0x80, 0x00, 0x00, 0xfd, 0x80, 0xfe, 0x01, 0xfd, 0xeb, 0xfd, 0x00, 0x01, 0xeb, 0xfd, 0x80, 0xfe, 0x00, 0xfd, 0x82, 0x00, 0x00, 0xfd, 0x81, 0xfe, 0x02, 0xfd, 0xfb, 0xf3, 0xf7, 0x00, 0x02, 0xf3, 0xfb, 0xfd, 0x81, 0xfe, 0x00, 0xfd, 0x84, 0x00, 0x00, 0xf3, 0x86, 0xfe, 0xf1, 0xfd, 0x86, 0xfe, 0x00, 0xf7, 0x87, 0x00, 0x00, 0xfc, 0xff, 0xfe, 0x00, 0xfc, 0x83, 0x00, 0x83, 0x03, 0x02, 0x1f, 0x47, 0x58, 0xfb, 0x70, 0x02, 0x58, 0x47, 0x1f, 0x87, 0x03, 0x01, 0x0a, 0x58, 0x80, 0x70, 0x04, 0x6c, 0x5c, 0x54, 0x4b, 0x43, 0xf1, 0x3f, 0x04, 0x43, 0x4b, 0x54, 0x5c, 0x6c, 0x80, 0x70, 0x01, 0x58, 0x0a, 0x84, 0x03, 0x0b, 0x2f, 0x6c, 0x70, 0x70, 0x54, 0x33, 0x1b, 0x0a, 0x03, 0x04, 0x05, 0x07, 0xef, 0x08, 0x0b, 0x07, 0x05, 0x04, 0x03, 0x0a, 0x1b, 0x33, 0x54, 0x70, 0x70, 0x6c, 0x2f, 0x82, 0x03, 0x0c, 0x3b, 0x70, 0x70, 0x5c, 0x2f, 0x0a, 0x09, 0x11, 0x16, 0x1a, 0x1c, 0x1e, 0x1e, 0xef, 0x20, 0x0c, 0x1e, 0x1e, 0x1c, 0x1a, 0x16, 0x11, 0x09, 0x0a, 0x2f, 0x5c, 0x70, 0x70, 0x3b, 0x80, 0x03, 0x0d, 0x23, 0x70, 0x70, 0x54, 0x1f, 0x07, 0x14, 0x1e, 0x28, 0x2d, 0x30, 0x31, 0x32, 0x34, 0xef, 0x35, 0x1c, 0x34, 0x32, 0x31, 0x30, 0x2d, 0x28, 0x1e, 0x14, 0x07, 0x1f, 0x54, 0x70, 0x70, 0x23, 0x03, 0x01, 0x64, 0x70, 0x5c, 0x1f, 0x0b, 0x1a, 0x28, 0x32, 0x39, 0x3e, 0x41, 0x43, 0x43, 0xf1, 0x45, 0x1b, 0x43, 0x43, 0x41, 0x3e, 0x39, 0x32, 0x28, 0x1a, 0x0b, 0x1f, 0x5c, 0x70, 0x60, 0x01, 0x23, 0x70, 0x70, 0x2b, 0x08, 0x1a, 0x2a, 0x37, 0x42, 0x49, 0x4d, 0x4f, 0x51, 0x52, 0xf1, 0x53, 0x1a, 0x52, 0x51, 0x4f, 0x4d, 0x49, 0x42, 0x37, 0x2a, 0x1a, 0x08, 0x2b, 0x70, 0x70, 0x23, 0x47, 0x70, 0x50, 0x06, 0x14, 0x28, 0x37, 0x45, 0x4e, 0x55, 0x59, 0x5b, 0x5b, 0xf3, 0x5c, 0x18, 0x5b, 0x5b, 0x59, 0x55, 0x4e, 0x45, 0x37, 0x28, 0x14, 0x06, 0x50, 0x70, 0x47, 0x60, 0x70, 0x2f, 0x09, 0x20, 0x32, 0x42, 0x4e, 0x57, 0x5e, 0x60, 0x62, 0x80, 0x63, 0xef, 0x64, 0x80, 0x63, 0x17, 0x62, 0x60, 0x5e, 0x57, 0x4e, 0x42, 0x32, 0x20, 0x09, 0x2f, 0x70, 0x60, 0x68, 0x6c, 0x16, 0x11, 0x28, 0x3a, 0x49, 0x55, 0x5e, 0x63, 0x66, 0x66, 0xf5, 0x67, 0x16, 0x66, 0x66, 0x63, 0x5e, 0x56, 0x49, 0x3a, 0x28, 0x11, 0x16, 0x6c, 0x6c, 0x70, 0x5c, 0x0a, 0x18, 0x2d, 0x3f, 0x4e, 0x5a, 0x60, 0x66, 0x66, 0xf7, 0x67, 0x14, 0x66, 0x66, 0x60, 0x5a, 0x4e, 0x3f, 0x2d, 0x18, 0x06, 0x5c, 0x70, 0x70, 0x50, 0x03, 0x1a, 0x30, 0x41, 0x4f, 0x5b, 0x62, 0x66, 0xf9, 0x67, 0x12, 0x66, 0x62, 0x5b, 0x4f, 0x41, 0x30, 0x1a, 0x03, 0x50, 0x70, 0x70, 0x4b, 0x04, 0x1c, 0x32, 0x43, 0x52, 0x5b, 0x63, 0xfb, 0x67, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x32, 0x1d, 0x04, 0x4b, 0x70, 0x70, 0x43, 0x07, 0x1e, 0x32, 0x45, 0x52, 0x5c, 0x63, 0xfb, 0x67, 0x11, 0x63, 0x5c, 0x52, 0x45, 0x32, 0x1e, 0x07, 0x43, 0x70, 0x70, 0x3f, 0x07, 0x1e, 0x34, 0x45, 0x53, 0x5c, 0x63, 0xfb, 0x67, 0x11, 0x63, 0x5c, 0x53, 0x45, 0x34, 0x1e, 0x07, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x07, 0x1e, 0x34, 0x45, 0x53, 0x5c, 0x63, 0xfb, 0x67, 0x11, 0x63, 0x5c, 0x53, 0x45, 0x34, 0x1e, 0x07, 0x3f, 0x70, 0x70, 0x43, 0x07, 0x1e, 0x32, 0x45, 0x52, 0x5c, 0x63, 0xfb, 0x67, 0x11, 0x63, 0x5c, 0x52, 0x45, 0x32, 0x1e, 0x07, 0x43, 0x70, 0x70, 0x4b, 0x04, 0x1c, 0x32, 0x43, 0x52, 0x5b, 0x63, 0xfb, 0x67, 0x12, 0x63, 0x5b, 0x52, 0x43, 0x32, 0x1d, 0x04, 0x4b, 0x70, 0x70, 0x50, 0x03, 0x1a, 0x30, 0x41, 0x4f, 0x5b, 0x62, 0x66, 0xf9, 0x67, 0x14, 0x66, 0x62, 0x5b, 0x4f, 0x41, 0x30, 0x1a, 0x03, 0x50, 0x70, 0x70, 0x5c, 0x06, 0x18, 0x2d, 0x3f, 0x4e, 0x5a, 0x60, 0x66, 0x66, 0xf7, 0x67, 0x16, 0x66, 0x66, 0x60, 0x5a, 0x4e, 0x3f, 0x2d, 0x18, 0x06, 0x5c, 0x70, 0x68, 0x6c, 0x16, 0x11, 0x28, 0x3a, 0x49, 0x56, 0x5e, 0x63, 0x66, 0x66, 0xf5, 0x67, 0x17, 0x66, 0x66, 0x63, 0x5e, 0x56, 0x49, 0x3a, 0x28, 0x11, 0x16, 0x6c, 0x6c, 0x60, 0x70, 0x2f, 0x09, 0x20, 0x32, 0x42, 0x4e, 0x57, 0x5e, 0x60, 0x62, 0x80, 0x63, 0xef, 0x64, 0x80, 0x63, 0x18, 0x62, 0x60, 0x5e, 0x57, 0x4e, 0x42, 0x32, 0x20, 0x09, 0x2f, 0x70, 0x60, 0x47, 0x70, 0x50, 0x06, 0x15, 0x28, 0x37, 0x45, 0x4e, 0x55, 0x59, 0x5b, 0x5b, 0xf3, 0x5c, 0x1a, 0x5b, 0x5b, 0x59, 0x55, 0x4e, 0x45, 0x37, 0x28, 0x15, 0x06, 0x50, 0x70, 0x47, 0x23, 0x70, 0x70, 0x2b, 0x08, 0x1a, 0x2a, 0x37, 0x42, 0x49, 0x4d, 0x4f, 0x51, 0x52, 0xf1, 0x53, 0x1b, 0x52, 0x51, 0x4f, 0x4e, 0x49, 0x42, 0x37, 0x2a, 0x1a, 0x08, 0x2b, 0x70, 0x70, 0x23, 0x01, 0x60, 0x70, 0x58, 0x1f, 0x0b, 0x1a, 0x28, 0x32, 0x3a, 0x3e, 0x41, 0x43, 0x43, 0xf1, 0x45, 0x1c, 0x43, 0x43, 0x41, 0x3e, 0x3a, 0x32, 0x28, 0x1a, 0x0b, 0x1f, 0x58, 0x70, 0x60, 0x01, 0x03, 0x23, 0x70, 0x70, 0x54, 0x1f, 0x08, 0x14, 0x20, 0x28, 0x2d, 0x30, 0x31, 0x32, 0x34, 0xef, 0x35, 0x0d, 0x34, 0x32, 0x31, 0x30, 0x2d, 0x28, 0x20, 0x14, 0x08, 0x1f, 0x54, 0x70, 0x70, 0x23, 0x80, 0x03, 0x0c, 0x3b, 0x70, 0x70, 0x5c, 0x2f, 0x06, 0x09, 0x11, 0x16, 0x1a, 0x1c, 0x1e, 0x1e, 0xef, 0x20, 0x0c, 0x1e, 0x1e, 0x1c, 0x1a, 0x16, 0x11, 0x09, 0x06, 0x2f, 0x5c, 0x70, 0x70, 0x3b, 0x82, 0x03, 0x0b, 0x33, 0x6c, 0x70, 0x70, 0x54, 0x33, 0x1b, 0x0a, 0x03, 0x04, 0x07, 0x07, 0xef, 0x08, 0x0b, 0x07, 0x07, 0x04, 0x03, 0x0a, 0x1b, 0x2f, 0x54, 0x70, 0x70, 0x6c, 0x33, 0x84, 0x03, 0x01, 0x0a, 0x58, 0x80, 0x70, 0x04, 0x6c, 0x5c, 0x54, 0x4b, 0x43, 0xf1, 0x3f, 0x04, 0x43, 0x4b, 0x54, 0x5c, 0x6c, 0x80, 0x70, 0x01, 0x58, 0x0e, 0x87, 0x03, 0x02, 0x23, 0x47, 0x58, 0xfb, 0x70, 0x02, 0x58, 0x47, 0x23, 0x83, 0x03, }; static EG_EMBEDDED_IMAGE egemb_back_selected_big = { 144, 144, EG_EIPIXELMODE_COLOR_ALPHA, EG_EICOMPMODE_RLE, egemb_back_selected_big_data, 7951 }; refind-0.11.4/include/Handle.h0000664000175000017500000000662112626644770016324 0ustar rodsmithrodsmith/*++ Copyright (c) 2005, Intel Corporation All rights reserved. This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. Module Name: Handle.h Abstract: Infomation about the handle function. Revision History --*/ #ifndef _HANDLE_H #define _HANDLE_H #include "libeg.h" #define EFI_HANDLE_TYPE_UNKNOWN 0x000 #define EFI_HANDLE_TYPE_IMAGE_HANDLE 0x001 #define EFI_HANDLE_TYPE_DRIVER_BINDING_HANDLE 0x002 #define EFI_HANDLE_TYPE_DEVICE_DRIVER 0x004 #define EFI_HANDLE_TYPE_BUS_DRIVER 0x008 #define EFI_HANDLE_TYPE_DRIVER_CONFIGURATION_HANDLE 0x010 #define EFI_HANDLE_TYPE_DRIVER_DIAGNOSTICS_HANDLE 0x020 #define EFI_HANDLE_TYPE_COMPONENT_NAME_HANDLE 0x040 #define EFI_HANDLE_TYPE_DEVICE_HANDLE 0x080 #define EFI_HANDLE_TYPE_PARENT_HANDLE 0x100 #define EFI_HANDLE_TYPE_CONTROLLER_HANDLE 0x200 #define EFI_HANDLE_TYPE_CHILD_HANDLE 0x400 EFI_FILE_SYSTEM_INFO * EfiLibFileSystemInfo ( IN EFI_FILE_HANDLE FHand ); EFI_STATUS LibGetManagedChildControllerHandles ( EFI_HANDLE DriverBindingHandle, EFI_HANDLE ControllerHandle, UINTN *ChildControllerHandleCount, EFI_HANDLE **ChildControllerHandleBuffer ); EFI_STATUS LibGetManagedControllerHandles ( EFI_HANDLE DriverBindingHandle, UINTN *ControllerHandleCount, EFI_HANDLE **ControllerHandleBuffer ); EFI_STATUS LibGetChildControllerHandles ( EFI_HANDLE ControllerHandle, UINTN *HandleCount, EFI_HANDLE **HandleBuffer ); EFI_STATUS LibInstallProtocolInterfaces ( IN OUT EFI_HANDLE *Handle, ... ); VOID LibUninstallProtocolInterfaces ( IN EFI_HANDLE Handle, ... ); EFI_STATUS LibReinstallProtocolInterfaces ( IN OUT EFI_HANDLE *Handle, ... ); EFI_STATUS LibLocateHandleByDiskSignature ( IN UINT8 MBRType, IN UINT8 SignatureType, IN VOID *Signature, IN OUT UINTN *NoHandles, OUT EFI_HANDLE **Buffer ); EFI_STATUS LibLocateHandle ( IN EFI_LOCATE_SEARCH_TYPE SearchType, IN EFI_GUID * Protocol OPTIONAL, IN VOID *SearchKey OPTIONAL, IN OUT UINTN *NoHandles, OUT EFI_HANDLE **Buffer ); EFI_STATUS LibLocateProtocol ( IN EFI_GUID *ProtocolGuid, OUT VOID **Interface ); EFI_HANDLE ShellHandleFromIndex ( IN UINTN Value ); UINTN ShellHandleNoFromIndex ( IN UINTN Value ); UINTN ShellHandleToIndex ( IN EFI_HANDLE Handle ); UINTN ShellHandleNoFromStr ( IN CHAR16 *Str ); UINTN ShellGetHandleNum ( VOID ); #endifrefind-0.11.4/include/RemovableMedia.h0000664000175000017500000001330012626644770017775 0ustar rodsmithrodsmith/* * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. * * Module Name: * * RemovableMedia.h * * Abstract: * * Protocol interface for any device that supports removable media (i.e. optical drives). * Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. ("Apple") in consideration of your agreement to the following terms, and your use, installation, modification or redistribution of this Apple software constitutes acceptance of these terms. If you do not agree with these terms, please do not use, install, modify or redistribute this Apple software. In consideration of your agreement to abide by the following terms, and subject to these terms, Apple grants you a personal, non-exclusive license, under Apple's copyrights in this original Apple software (the "Apple Software"), to use, reproduce, modify and redistribute the Apple Software, with or without modifications, in source and/or binary forms; provided that if you redistribute the Apple Software in its entirety and without modifications, you must retain this notice and the following text and disclaimers in all such redistributions of the Apple Software. Neither the name, trademarks, service marks or logos of Apple Computer, Inc. may be used to endorse or promote products derived from the Apple Software without specific prior written permission from Apple. Except as expressly stated in this notice, no other rights or licenses, express or implied, are granted by Apple herein, including but not limited to any patent rights that may be infringed by your derivative works or by other works in which the Apple Software may be incorporated. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Copyright 2006 Apple Computer, Inc., All Rights Reserved */ #ifndef _APPLE_REMOVABLE_MEDIA_H #define _APPLE_REMOVABLE_MEDIA_H // // Global Id for Removable_Media Interface // // {2EA9743A-23D9-425e-872C-F615AA195788} #define APPLE_REMOVABLE_MEDIA_PROTOCOL_GUID \ { \ 0x2ea9743a, 0x23d9, 0x425e, { 0x87, 0x2c, 0xf6, 0x15, 0xaa, 0x19, 0x57, 0x88 } \ } #define APPLE_REMOVABLE_MEDIA_PROTOCOL_REVISION 0x00000001 // EFI_FORWARD_DECLARATION (APPLE_REMOVABLE_MEDIA_PROTOCOL); typedef struct _APPLE_REMOVABLE_MEDIA_PROTOCOL APPLE_REMOVABLE_MEDIA_PROTOCOL; // // Eject // typedef EFI_STATUS (EFIAPI *APPLE_REMOVABLE_MEDIA_EJECT) ( IN APPLE_REMOVABLE_MEDIA_PROTOCOL * This ) /*++ Routine Description: Eject removable media from drive (such as a CD/DVD). Arguments: This - Protocol instance pointer. Returns: EFI_SUCCESS - The media was ejected. --*/ ; // // Inject // typedef EFI_STATUS (EFIAPI *APPLE_REMOVABLE_MEDIA_INJECT) ( IN APPLE_REMOVABLE_MEDIA_PROTOCOL * This ) /*++ Routine Description: Inject removable media into drive (such as a CD/DVD). Arguments: This - Protocol instance pointer. Returns: EFI_SUCCESS - The media was injected. --*/ ; // // Allow media to be ejected // typedef EFI_STATUS (EFIAPI *APPLE_REMOVABLE_MEDIA_ALLOW_REMOVAL) ( IN APPLE_REMOVABLE_MEDIA_PROTOCOL * This ) /*++ Routine Description: Allow the media to be removed from the drive. Arguments: This - Protocol instance pointer. Returns: EFI_SUCCESS - The media can now be removed. EFI_UNSUPPORTED - The media cannot be removed. --*/ ; // // Prevent media from being ejected // typedef EFI_STATUS (EFIAPI *APPLE_REMOVABLE_MEDIA_PREVENT_REMOVAL) ( IN APPLE_REMOVABLE_MEDIA_PROTOCOL * This ) /*++ Routine Description: Prevent the media from being removed from the drive. Arguments: This - Protocol instance pointer. Returns: EFI_SUCCESS - The drive is locked, and the media cannot be removed. EFI_UNSUPPORTED - The drive cannot be locked. --*/ ; // // Detect state of removable media tray // typedef EFI_STATUS (EFIAPI *APPLE_REMOVABLE_MEDIA_DETECT_TRAY_STATE) ( IN APPLE_REMOVABLE_MEDIA_PROTOCOL * This, OUT BOOLEAN * TrayOpen ) /*++ Routine Description: Get the status of the drive tray. Arguments: This - Protocol instance pointer. TrayOpen - Status of the drive tray. Returns: EFI_SUCCESS - The status has been returned in TrayOpen. --*/ ; // // Protocol definition // struct _APPLE_REMOVABLE_MEDIA_PROTOCOL { UINT32 Revision; BOOLEAN RemovalAllowed; APPLE_REMOVABLE_MEDIA_EJECT Eject; APPLE_REMOVABLE_MEDIA_INJECT Inject; APPLE_REMOVABLE_MEDIA_ALLOW_REMOVAL AllowRemoval; APPLE_REMOVABLE_MEDIA_PREVENT_REMOVAL PreventRemoval; APPLE_REMOVABLE_MEDIA_DETECT_TRAY_STATE DetectTrayState; }; //extern EFI_GUID gAppleRemovableMediaProtocolGuid; #endif refind-0.11.4/include/egemb_back_selected_small.h0000664000175000017500000002567112626644770022236 0ustar rodsmithrodsmithstatic const UINT8 egemb_back_selected_small_data[1805] = { 0x83, 0xbf, 0xb1, 0xff, 0x87, 0xbf, 0xb5, 0xff, 0x84, 0xbf, 0x85, 0xff, 0x00, 0xbf, 0xa5, 0x00, 0x00, 0xbf, 0x85, 0xff, 0x82, 0xbf, 0x83, 0xff, 0xad, 0x00, 0x83, 0xff, 0x80, 0xbf, 0x82, 0xff, 0xb1, 0x00, 0x82, 0xff, 0x00, 0xbf, 0x82, 0xff, 0xb3, 0x00, 0x86, 0xff, 0xb5, 0x00, 0x85, 0xff, 0xb5, 0x00, 0x84, 0xff, 0xb7, 0x00, 0x83, 0xff, 0xb7, 0x00, 0x83, 0xff, 0xb7, 0x00, 0x82, 0xff, 0x00, 0xbf, 0xb7, 0x00, 0x00, 0xbf, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0x00, 0xbf, 0xb7, 0x00, 0x00, 0xbf, 0x82, 0xff, 0xb7, 0x00, 0x83, 0xff, 0xb7, 0x00, 0x83, 0xff, 0xb7, 0x00, 0x84, 0xff, 0xb5, 0x00, 0x85, 0xff, 0xb5, 0x00, 0x86, 0xff, 0xb3, 0x00, 0x82, 0xff, 0x00, 0xbf, 0x82, 0xff, 0xb1, 0x00, 0x82, 0xff, 0x80, 0xbf, 0x83, 0xff, 0xad, 0x00, 0x83, 0xff, 0x82, 0xbf, 0x85, 0xff, 0x00, 0xbf, 0xa5, 0x00, 0x00, 0xbf, 0x85, 0xff, 0x84, 0xbf, 0xb5, 0xff, 0x87, 0xbf, 0xb1, 0xff, 0x83, 0xbf, 0x83, 0x00, 0x02, 0x23, 0x4b, 0x5b, 0xab, 0x73, 0x02, 0x5b, 0x4b, 0x23, 0x87, 0x00, 0x01, 0x0f, 0x5b, 0x80, 0x73, 0x04, 0x6f, 0x5f, 0x57, 0x4f, 0x47, 0xa1, 0x43, 0x04, 0x47, 0x4f, 0x57, 0x5f, 0x6f, 0x80, 0x73, 0x01, 0x5b, 0x0f, 0x84, 0x00, 0x0b, 0x33, 0x6f, 0x73, 0x73, 0x57, 0x37, 0x1f, 0x0f, 0x00, 0x02, 0x03, 0x04, 0x9f, 0x06, 0x0b, 0x04, 0x03, 0x02, 0x00, 0x0f, 0x1f, 0x37, 0x57, 0x73, 0x73, 0x6f, 0x33, 0x82, 0x00, 0x0c, 0x3f, 0x73, 0x73, 0x5f, 0x33, 0x0f, 0x07, 0x0f, 0x14, 0x18, 0x1a, 0x1c, 0x1c, 0x9f, 0x1e, 0x0c, 0x1c, 0x1c, 0x1a, 0x18, 0x14, 0x0f, 0x07, 0x0f, 0x33, 0x5f, 0x73, 0x73, 0x3f, 0x80, 0x00, 0x0d, 0x27, 0x73, 0x73, 0x57, 0x23, 0x04, 0x12, 0x1c, 0x26, 0x2b, 0x2e, 0x2f, 0x30, 0x32, 0x9f, 0x33, 0x1c, 0x32, 0x30, 0x2f, 0x2e, 0x2b, 0x26, 0x1c, 0x12, 0x04, 0x23, 0x57, 0x73, 0x73, 0x27, 0x00, 0x03, 0x67, 0x73, 0x5f, 0x23, 0x08, 0x18, 0x26, 0x30, 0x37, 0x3c, 0x3f, 0x42, 0x42, 0xa1, 0x43, 0x1b, 0x42, 0x42, 0x3f, 0x3c, 0x37, 0x30, 0x26, 0x18, 0x08, 0x23, 0x5f, 0x73, 0x63, 0x03, 0x27, 0x73, 0x73, 0x2f, 0x06, 0x18, 0x28, 0x36, 0x40, 0x47, 0x4b, 0x4e, 0x4f, 0x50, 0xa1, 0x52, 0x1a, 0x50, 0x4f, 0x4e, 0x4b, 0x47, 0x40, 0x36, 0x28, 0x18, 0x06, 0x2f, 0x73, 0x73, 0x27, 0x4b, 0x73, 0x53, 0x0b, 0x12, 0x26, 0x36, 0x43, 0x4c, 0x53, 0x57, 0x5a, 0x5a, 0xa3, 0x5b, 0x18, 0x5a, 0x5a, 0x57, 0x53, 0x4c, 0x43, 0x36, 0x26, 0x12, 0x0b, 0x53, 0x73, 0x4b, 0x63, 0x73, 0x33, 0x07, 0x1e, 0x30, 0x40, 0x4c, 0x56, 0x5c, 0x5f, 0x60, 0x80, 0x62, 0x9f, 0x63, 0x80, 0x62, 0x17, 0x60, 0x5f, 0x5c, 0x56, 0x4c, 0x40, 0x30, 0x1e, 0x07, 0x33, 0x73, 0x63, 0x6b, 0x6f, 0x1b, 0x0f, 0x26, 0x38, 0x47, 0x53, 0x5c, 0x62, 0x64, 0x64, 0xa5, 0x66, 0x16, 0x64, 0x64, 0x62, 0x5c, 0x54, 0x47, 0x38, 0x26, 0x0f, 0x1b, 0x6f, 0x6f, 0x73, 0x5f, 0x0f, 0x16, 0x2b, 0x3e, 0x4c, 0x58, 0x5f, 0x64, 0x64, 0xa7, 0x66, 0x14, 0x64, 0x64, 0x5f, 0x58, 0x4c, 0x3e, 0x2b, 0x16, 0x0b, 0x5f, 0x73, 0x73, 0x53, 0x00, 0x18, 0x2e, 0x3f, 0x4e, 0x5a, 0x60, 0x64, 0xa9, 0x66, 0x12, 0x64, 0x60, 0x5a, 0x4e, 0x3f, 0x2e, 0x18, 0x00, 0x53, 0x73, 0x73, 0x4f, 0x02, 0x1a, 0x30, 0x42, 0x50, 0x5a, 0x62, 0xab, 0x66, 0x11, 0x62, 0x5a, 0x50, 0x42, 0x30, 0x1b, 0x02, 0x4f, 0x73, 0x73, 0x47, 0x04, 0x1c, 0x30, 0x43, 0x50, 0x5b, 0x62, 0xab, 0x66, 0x11, 0x62, 0x5b, 0x50, 0x43, 0x30, 0x1c, 0x04, 0x47, 0x73, 0x73, 0x43, 0x04, 0x1c, 0x32, 0x43, 0x52, 0x5b, 0x62, 0xab, 0x66, 0x11, 0x62, 0x5b, 0x52, 0x43, 0x32, 0x1c, 0x04, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x04, 0x1c, 0x32, 0x43, 0x52, 0x5b, 0x62, 0xab, 0x66, 0x11, 0x62, 0x5b, 0x52, 0x43, 0x32, 0x1c, 0x04, 0x43, 0x73, 0x73, 0x47, 0x04, 0x1c, 0x30, 0x43, 0x50, 0x5b, 0x62, 0xab, 0x66, 0x11, 0x62, 0x5b, 0x50, 0x43, 0x30, 0x1c, 0x04, 0x47, 0x73, 0x73, 0x4f, 0x02, 0x1a, 0x30, 0x42, 0x50, 0x5a, 0x62, 0xab, 0x66, 0x12, 0x62, 0x5a, 0x50, 0x42, 0x30, 0x1b, 0x02, 0x4f, 0x73, 0x73, 0x53, 0x00, 0x18, 0x2e, 0x3f, 0x4e, 0x5a, 0x60, 0x64, 0xa9, 0x66, 0x14, 0x64, 0x60, 0x5a, 0x4e, 0x3f, 0x2e, 0x18, 0x00, 0x53, 0x73, 0x73, 0x5f, 0x0b, 0x16, 0x2b, 0x3e, 0x4c, 0x58, 0x5f, 0x64, 0x64, 0xa7, 0x66, 0x16, 0x64, 0x64, 0x5f, 0x58, 0x4c, 0x3e, 0x2b, 0x16, 0x0b, 0x5f, 0x73, 0x6b, 0x6f, 0x1b, 0x0f, 0x26, 0x38, 0x47, 0x54, 0x5c, 0x62, 0x64, 0x64, 0xa5, 0x66, 0x17, 0x64, 0x64, 0x62, 0x5c, 0x54, 0x47, 0x38, 0x26, 0x0f, 0x1b, 0x6f, 0x6f, 0x63, 0x73, 0x33, 0x07, 0x1e, 0x30, 0x40, 0x4c, 0x56, 0x5c, 0x5f, 0x60, 0x80, 0x62, 0x9f, 0x63, 0x80, 0x62, 0x18, 0x60, 0x5f, 0x5c, 0x56, 0x4c, 0x40, 0x30, 0x1e, 0x07, 0x33, 0x73, 0x63, 0x4b, 0x73, 0x53, 0x0b, 0x13, 0x26, 0x36, 0x43, 0x4c, 0x53, 0x57, 0x5a, 0x5a, 0xa3, 0x5b, 0x1a, 0x5a, 0x5a, 0x57, 0x53, 0x4c, 0x43, 0x36, 0x26, 0x13, 0x0b, 0x53, 0x73, 0x4b, 0x27, 0x73, 0x73, 0x2f, 0x06, 0x18, 0x28, 0x36, 0x40, 0x47, 0x4b, 0x4e, 0x4f, 0x50, 0xa1, 0x52, 0x1b, 0x50, 0x4f, 0x4e, 0x4c, 0x47, 0x40, 0x36, 0x28, 0x18, 0x06, 0x2f, 0x73, 0x73, 0x27, 0x03, 0x63, 0x73, 0x5b, 0x23, 0x08, 0x18, 0x26, 0x30, 0x38, 0x3c, 0x3f, 0x42, 0x42, 0xa1, 0x43, 0x1c, 0x42, 0x42, 0x3f, 0x3c, 0x38, 0x30, 0x26, 0x18, 0x08, 0x23, 0x5b, 0x73, 0x63, 0x03, 0x00, 0x27, 0x73, 0x73, 0x57, 0x23, 0x06, 0x12, 0x1e, 0x26, 0x2b, 0x2e, 0x2f, 0x30, 0x32, 0x9f, 0x33, 0x0d, 0x32, 0x30, 0x2f, 0x2e, 0x2b, 0x26, 0x1e, 0x12, 0x06, 0x23, 0x57, 0x73, 0x73, 0x27, 0x80, 0x00, 0x0c, 0x3f, 0x73, 0x73, 0x5f, 0x33, 0x0b, 0x07, 0x0f, 0x14, 0x18, 0x1a, 0x1c, 0x1c, 0x9f, 0x1e, 0x0c, 0x1c, 0x1c, 0x1a, 0x18, 0x14, 0x0f, 0x07, 0x0b, 0x33, 0x5f, 0x73, 0x73, 0x3f, 0x82, 0x00, 0x0b, 0x37, 0x6f, 0x73, 0x73, 0x57, 0x37, 0x1f, 0x0f, 0x00, 0x02, 0x04, 0x04, 0x9f, 0x06, 0x0b, 0x04, 0x04, 0x02, 0x00, 0x0f, 0x1f, 0x33, 0x57, 0x73, 0x73, 0x6f, 0x37, 0x84, 0x00, 0x01, 0x0f, 0x5b, 0x80, 0x73, 0x04, 0x6f, 0x5f, 0x57, 0x4f, 0x47, 0xa1, 0x43, 0x04, 0x47, 0x4f, 0x57, 0x5f, 0x6f, 0x80, 0x73, 0x01, 0x5b, 0x13, 0x87, 0x00, 0x02, 0x27, 0x4b, 0x5b, 0xab, 0x73, 0x02, 0x5b, 0x4b, 0x27, 0x83, 0x00, }; static EG_EMBEDDED_IMAGE egemb_back_selected_small = { 64, 64, EG_EIPIXELMODE_GRAY_ALPHA, EG_EICOMPMODE_RLE, egemb_back_selected_small_data, 1805 }; refind-0.11.4/include/version.h0000664000175000017500000000050213372346070016575 0ustar rodsmithrodsmith/* * include/version.h * Version number header file * * Copyright (c) 2017 Roderick W. Smith * * Distributed under the terms of the GNU General Public License (GPL) * version 3 (GPLv3), a copy of which must be distributed with this * source code or binaries made from it. * */ #define REFIND_VERSION L"0.11.4" refind-0.11.4/include/PeImage.h0000664000175000017500000006341612626644770016445 0ustar rodsmithrodsmith/** @file EFI image format for PE32, PE32+ and TE. Please note some data structures are different for PE32 and PE32+. EFI_IMAGE_NT_HEADERS32 is for PE32 and EFI_IMAGE_NT_HEADERS64 is for PE32+. This file is coded to the Visual Studio, Microsoft Portable Executable and Common Object File Format Specification, Revision 8.0 - May 16, 2006. This file also includes some definitions in PI Specification, Revision 1.0. Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php. THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ #ifndef __PE_IMAGE_H__ #define __PE_IMAGE_H__ #define SIGNATURE_16(A, B) ((A) | (B << 8)) #define SIGNATURE_32(A, B, C, D) (SIGNATURE_16 (A, B) | (SIGNATURE_16 (C, D) << 16)) #define SIGNATURE_64(A, B, C, D, E, F, G, H) \ (SIGNATURE_32 (A, B, C, D) | ((UINT64) (SIGNATURE_32 (E, F, G, H)) << 32)) #define ALIGN_VALUE(Value, Alignment) ((Value) + (((Alignment) - (Value)) & ((Alignment) - 1))) #define ALIGN_POINTER(Pointer, Alignment) ((VOID *) (ALIGN_VALUE ((UINTN)(Pointer), (Alignment)))) // // PE32+ Subsystem type for EFI images // #define EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION 10 #define EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11 #define EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12 #define EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER 13 ///< defined PI Specification, 1.0 // // PE32+ Machine type for EFI images // #define IMAGE_FILE_MACHINE_I386 0x014c #define IMAGE_FILE_MACHINE_IA64 0x0200 #define IMAGE_FILE_MACHINE_EBC 0x0EBC #define IMAGE_FILE_MACHINE_X64 0x8664 #define IMAGE_FILE_MACHINE_ARMTHUMB_MIXED 0x01c2 // // EXE file formats // #define EFI_IMAGE_DOS_SIGNATURE SIGNATURE_16('M', 'Z') #define EFI_IMAGE_OS2_SIGNATURE SIGNATURE_16('N', 'E') #define EFI_IMAGE_OS2_SIGNATURE_LE SIGNATURE_16('L', 'E') #define EFI_IMAGE_NT_SIGNATURE SIGNATURE_32('P', 'E', '\0', '\0') /// /// PE images can start with an optional DOS header, so if an image is run /// under DOS it can print an error message. /// typedef struct { UINT16 e_magic; ///< Magic number. UINT16 e_cblp; ///< Bytes on last page of file. UINT16 e_cp; ///< Pages in file. UINT16 e_crlc; ///< Relocations. UINT16 e_cparhdr; ///< Size of header in paragraphs. UINT16 e_minalloc; ///< Minimum extra paragraphs needed. UINT16 e_maxalloc; ///< Maximum extra paragraphs needed. UINT16 e_ss; ///< Initial (relative) SS value. UINT16 e_sp; ///< Initial SP value. UINT16 e_csum; ///< Checksum. UINT16 e_ip; ///< Initial IP value. UINT16 e_cs; ///< Initial (relative) CS value. UINT16 e_lfarlc; ///< File address of relocation table. UINT16 e_ovno; ///< Overlay number. UINT16 e_res[4]; ///< Reserved words. UINT16 e_oemid; ///< OEM identifier (for e_oeminfo). UINT16 e_oeminfo; ///< OEM information; e_oemid specific. UINT16 e_res2[10]; ///< Reserved words. UINT32 e_lfanew; ///< File address of new exe header. } EFI_IMAGE_DOS_HEADER; /// /// COFF File Header (Object and Image). /// typedef struct { UINT16 Machine; UINT16 NumberOfSections; UINT32 TimeDateStamp; UINT32 PointerToSymbolTable; UINT32 NumberOfSymbols; UINT16 SizeOfOptionalHeader; UINT16 Characteristics; } EFI_IMAGE_FILE_HEADER; /// /// Size of EFI_IMAGE_FILE_HEADER. /// #define EFI_IMAGE_SIZEOF_FILE_HEADER 20 // // Characteristics // #define EFI_IMAGE_FILE_RELOCS_STRIPPED (1 << 0) ///< 0x0001 Relocation info stripped from file. #define EFI_IMAGE_FILE_EXECUTABLE_IMAGE (1 << 1) ///< 0x0002 File is executable (i.e. no unresolved externel references). #define EFI_IMAGE_FILE_LINE_NUMS_STRIPPED (1 << 2) ///< 0x0004 Line nunbers stripped from file. #define EFI_IMAGE_FILE_LOCAL_SYMS_STRIPPED (1 << 3) ///< 0x0008 Local symbols stripped from file. #define EFI_IMAGE_FILE_BYTES_REVERSED_LO (1 << 7) ///< 0x0080 Bytes of machine word are reversed. #define EFI_IMAGE_FILE_32BIT_MACHINE (1 << 8) ///< 0x0100 32 bit word machine. #define EFI_IMAGE_FILE_DEBUG_STRIPPED (1 << 9) ///< 0x0200 Debugging info stripped from file in .DBG file. #define EFI_IMAGE_FILE_SYSTEM (1 << 12) ///< 0x1000 System File. #define EFI_IMAGE_FILE_DLL (1 << 13) ///< 0x2000 File is a DLL. #define EFI_IMAGE_FILE_BYTES_REVERSED_HI (1 << 15) ///< 0x8000 Bytes of machine word are reversed. /// /// Header Data Directories. /// typedef struct { UINT32 VirtualAddress; UINT32 Size; } EFI_IMAGE_DATA_DIRECTORY; // // Directory Entries // #define EFI_IMAGE_DIRECTORY_ENTRY_EXPORT 0 #define EFI_IMAGE_DIRECTORY_ENTRY_IMPORT 1 #define EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE 2 #define EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 #define EFI_IMAGE_DIRECTORY_ENTRY_SECURITY 4 #define EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC 5 #define EFI_IMAGE_DIRECTORY_ENTRY_DEBUG 6 #define EFI_IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 #define EFI_IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 #define EFI_IMAGE_DIRECTORY_ENTRY_TLS 9 #define EFI_IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 #define EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES 16 /// /// @attention /// EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC means PE32 and /// EFI_IMAGE_OPTIONAL_HEADER32 must be used. The data structures only vary /// after NT additional fields. /// #define EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b /// /// Optional Header Standard Fields for PE32. /// typedef struct { /// /// Standard fields. /// UINT16 Magic; UINT8 MajorLinkerVersion; UINT8 MinorLinkerVersion; UINT32 SizeOfCode; UINT32 SizeOfInitializedData; UINT32 SizeOfUninitializedData; UINT32 AddressOfEntryPoint; UINT32 BaseOfCode; UINT32 BaseOfData; ///< PE32 contains this additional field, which is absent in PE32+. /// /// Optional Header Windows-Specific Fields. /// UINT32 ImageBase; UINT32 SectionAlignment; UINT32 FileAlignment; UINT16 MajorOperatingSystemVersion; UINT16 MinorOperatingSystemVersion; UINT16 MajorImageVersion; UINT16 MinorImageVersion; UINT16 MajorSubsystemVersion; UINT16 MinorSubsystemVersion; UINT32 Win32VersionValue; UINT32 SizeOfImage; UINT32 SizeOfHeaders; UINT32 CheckSum; UINT16 Subsystem; UINT16 DllCharacteristics; UINT32 SizeOfStackReserve; UINT32 SizeOfStackCommit; UINT32 SizeOfHeapReserve; UINT32 SizeOfHeapCommit; UINT32 LoaderFlags; UINT32 NumberOfRvaAndSizes; EFI_IMAGE_DATA_DIRECTORY DataDirectory[EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES]; } EFI_IMAGE_OPTIONAL_HEADER32; /// /// @attention /// EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC means PE32+ and /// EFI_IMAGE_OPTIONAL_HEADER64 must be used. The data structures only vary /// after NT additional fields. /// #define EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b /// /// Optional Header Standard Fields for PE32+. /// typedef struct { /// /// Standard fields. /// UINT16 Magic; UINT8 MajorLinkerVersion; UINT8 MinorLinkerVersion; UINT32 SizeOfCode; UINT32 SizeOfInitializedData; UINT32 SizeOfUninitializedData; UINT32 AddressOfEntryPoint; UINT32 BaseOfCode; /// /// Optional Header Windows-Specific Fields. /// UINT64 ImageBase; UINT32 SectionAlignment; UINT32 FileAlignment; UINT16 MajorOperatingSystemVersion; UINT16 MinorOperatingSystemVersion; UINT16 MajorImageVersion; UINT16 MinorImageVersion; UINT16 MajorSubsystemVersion; UINT16 MinorSubsystemVersion; UINT32 Win32VersionValue; UINT32 SizeOfImage; UINT32 SizeOfHeaders; UINT32 CheckSum; UINT16 Subsystem; UINT16 DllCharacteristics; UINT64 SizeOfStackReserve; UINT64 SizeOfStackCommit; UINT64 SizeOfHeapReserve; UINT64 SizeOfHeapCommit; UINT32 LoaderFlags; UINT32 NumberOfRvaAndSizes; EFI_IMAGE_DATA_DIRECTORY DataDirectory[EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES]; } EFI_IMAGE_OPTIONAL_HEADER64; /// /// @attention /// EFI_IMAGE_NT_HEADERS32 is for use ONLY by tools. /// typedef struct { UINT32 Signature; EFI_IMAGE_FILE_HEADER FileHeader; EFI_IMAGE_OPTIONAL_HEADER32 OptionalHeader; } EFI_IMAGE_NT_HEADERS32; #define EFI_IMAGE_SIZEOF_NT_OPTIONAL32_HEADER sizeof (EFI_IMAGE_NT_HEADERS32) /// /// @attention /// EFI_IMAGE_HEADERS64 is for use ONLY by tools. /// typedef struct { UINT32 Signature; EFI_IMAGE_FILE_HEADER FileHeader; EFI_IMAGE_OPTIONAL_HEADER64 OptionalHeader; } EFI_IMAGE_NT_HEADERS64; #define EFI_IMAGE_SIZEOF_NT_OPTIONAL64_HEADER sizeof (EFI_IMAGE_NT_HEADERS64) // // Other Windows Subsystem Values // #define EFI_IMAGE_SUBSYSTEM_UNKNOWN 0 #define EFI_IMAGE_SUBSYSTEM_NATIVE 1 #define EFI_IMAGE_SUBSYSTEM_WINDOWS_GUI 2 #define EFI_IMAGE_SUBSYSTEM_WINDOWS_CUI 3 #define EFI_IMAGE_SUBSYSTEM_OS2_CUI 5 #define EFI_IMAGE_SUBSYSTEM_POSIX_CUI 7 /// /// Length of ShortName. /// #define EFI_IMAGE_SIZEOF_SHORT_NAME 8 /// /// Section Table. This table immediately follows the optional header. /// typedef struct { UINT8 Name[EFI_IMAGE_SIZEOF_SHORT_NAME]; union { UINT32 PhysicalAddress; UINT32 VirtualSize; } Misc; UINT32 VirtualAddress; UINT32 SizeOfRawData; UINT32 PointerToRawData; UINT32 PointerToRelocations; UINT32 PointerToLinenumbers; UINT16 NumberOfRelocations; UINT16 NumberOfLinenumbers; UINT32 Characteristics; } EFI_IMAGE_SECTION_HEADER; /// /// Size of EFI_IMAGE_SECTION_HEADER. /// #define EFI_IMAGE_SIZEOF_SECTION_HEADER 40 // // Section Flags Values // #define EFI_IMAGE_SCN_TYPE_NO_PAD BIT3 ///< 0x00000008 ///< Reserved. #define EFI_IMAGE_SCN_CNT_CODE BIT5 ///< 0x00000020 #define EFI_IMAGE_SCN_CNT_INITIALIZED_DATA BIT6 ///< 0x00000040 #define EFI_IMAGE_SCN_CNT_UNINITIALIZED_DATA BIT7 ///< 0x00000080 #define EFI_IMAGE_SCN_LNK_OTHER BIT8 ///< 0x00000100 ///< Reserved. #define EFI_IMAGE_SCN_LNK_INFO BIT9 ///< 0x00000200 ///< Section contains comments or some other type of information. #define EFI_IMAGE_SCN_LNK_REMOVE BIT11 ///< 0x00000800 ///< Section contents will not become part of image. #define EFI_IMAGE_SCN_LNK_COMDAT BIT12 ///< 0x00001000 #define EFI_IMAGE_SCN_ALIGN_1BYTES BIT20 ///< 0x00100000 #define EFI_IMAGE_SCN_ALIGN_2BYTES BIT21 ///< 0x00200000 #define EFI_IMAGE_SCN_ALIGN_4BYTES (BIT20|BIT21) ///< 0x00300000 #define EFI_IMAGE_SCN_ALIGN_8BYTES BIT22 ///< 0x00400000 #define EFI_IMAGE_SCN_ALIGN_16BYTES (BIT20|BIT22) ///< 0x00500000 #define EFI_IMAGE_SCN_ALIGN_32BYTES (BIT21|BIT22) ///< 0x00600000 #define EFI_IMAGE_SCN_ALIGN_64BYTES (BIT20|BIT21|BIT22) ///< 0x00700000 #define EFI_IMAGE_SCN_MEM_DISCARDABLE BIT25 ///< 0x02000000 #define EFI_IMAGE_SCN_MEM_NOT_CACHED BIT26 ///< 0x04000000 #define EFI_IMAGE_SCN_MEM_NOT_PAGED BIT27 ///< 0x08000000 #define EFI_IMAGE_SCN_MEM_SHARED BIT28 ///< 0x10000000 #define EFI_IMAGE_SCN_MEM_EXECUTE BIT29 ///< 0x20000000 #define EFI_IMAGE_SCN_MEM_READ BIT30 ///< 0x40000000 #define EFI_IMAGE_SCN_MEM_WRITE BIT31 ///< 0x80000000 /// /// Size of a Symbol Table Record. /// #define EFI_IMAGE_SIZEOF_SYMBOL 18 // // Symbols have a section number of the section in which they are // defined. Otherwise, section numbers have the following meanings: // #define EFI_IMAGE_SYM_UNDEFINED (UINT16) 0 ///< Symbol is undefined or is common. #define EFI_IMAGE_SYM_ABSOLUTE (UINT16) -1 ///< Symbol is an absolute value. #define EFI_IMAGE_SYM_DEBUG (UINT16) -2 ///< Symbol is a special debug item. // // Symbol Type (fundamental) values. // #define EFI_IMAGE_SYM_TYPE_NULL 0 ///< no type. #define EFI_IMAGE_SYM_TYPE_VOID 1 ///< no valid type. #define EFI_IMAGE_SYM_TYPE_CHAR 2 ///< type character. #define EFI_IMAGE_SYM_TYPE_SHORT 3 ///< type short integer. #define EFI_IMAGE_SYM_TYPE_INT 4 #define EFI_IMAGE_SYM_TYPE_LONG 5 #define EFI_IMAGE_SYM_TYPE_FLOAT 6 #define EFI_IMAGE_SYM_TYPE_DOUBLE 7 #define EFI_IMAGE_SYM_TYPE_STRUCT 8 #define EFI_IMAGE_SYM_TYPE_UNION 9 #define EFI_IMAGE_SYM_TYPE_ENUM 10 ///< enumeration. #define EFI_IMAGE_SYM_TYPE_MOE 11 ///< member of enumeration. #define EFI_IMAGE_SYM_TYPE_BYTE 12 #define EFI_IMAGE_SYM_TYPE_WORD 13 #define EFI_IMAGE_SYM_TYPE_UINT 14 #define EFI_IMAGE_SYM_TYPE_DWORD 15 // // Symbol Type (derived) values. // #define EFI_IMAGE_SYM_DTYPE_NULL 0 ///< no derived type. #define EFI_IMAGE_SYM_DTYPE_POINTER 1 #define EFI_IMAGE_SYM_DTYPE_FUNCTION 2 #define EFI_IMAGE_SYM_DTYPE_ARRAY 3 // // Storage classes. // #define EFI_IMAGE_SYM_CLASS_END_OF_FUNCTION ((UINT8) -1) #define EFI_IMAGE_SYM_CLASS_NULL 0 #define EFI_IMAGE_SYM_CLASS_AUTOMATIC 1 #define EFI_IMAGE_SYM_CLASS_EXTERNAL 2 #define EFI_IMAGE_SYM_CLASS_STATIC 3 #define EFI_IMAGE_SYM_CLASS_REGISTER 4 #define EFI_IMAGE_SYM_CLASS_EXTERNAL_DEF 5 #define EFI_IMAGE_SYM_CLASS_LABEL 6 #define EFI_IMAGE_SYM_CLASS_UNDEFINED_LABEL 7 #define EFI_IMAGE_SYM_CLASS_MEMBER_OF_STRUCT 8 #define EFI_IMAGE_SYM_CLASS_ARGUMENT 9 #define EFI_IMAGE_SYM_CLASS_STRUCT_TAG 10 #define EFI_IMAGE_SYM_CLASS_MEMBER_OF_UNION 11 #define EFI_IMAGE_SYM_CLASS_UNION_TAG 12 #define EFI_IMAGE_SYM_CLASS_TYPE_DEFINITION 13 #define EFI_IMAGE_SYM_CLASS_UNDEFINED_STATIC 14 #define EFI_IMAGE_SYM_CLASS_ENUM_TAG 15 #define EFI_IMAGE_SYM_CLASS_MEMBER_OF_ENUM 16 #define EFI_IMAGE_SYM_CLASS_REGISTER_PARAM 17 #define EFI_IMAGE_SYM_CLASS_BIT_FIELD 18 #define EFI_IMAGE_SYM_CLASS_BLOCK 100 #define EFI_IMAGE_SYM_CLASS_FUNCTION 101 #define EFI_IMAGE_SYM_CLASS_END_OF_STRUCT 102 #define EFI_IMAGE_SYM_CLASS_FILE 103 #define EFI_IMAGE_SYM_CLASS_SECTION 104 #define EFI_IMAGE_SYM_CLASS_WEAK_EXTERNAL 105 // // type packing constants // #define EFI_IMAGE_N_BTMASK 017 #define EFI_IMAGE_N_TMASK 060 #define EFI_IMAGE_N_TMASK1 0300 #define EFI_IMAGE_N_TMASK2 0360 #define EFI_IMAGE_N_BTSHFT 4 #define EFI_IMAGE_N_TSHIFT 2 // // Communal selection types. // #define EFI_IMAGE_COMDAT_SELECT_NODUPLICATES 1 #define EFI_IMAGE_COMDAT_SELECT_ANY 2 #define EFI_IMAGE_COMDAT_SELECT_SAME_SIZE 3 #define EFI_IMAGE_COMDAT_SELECT_EXACT_MATCH 4 #define EFI_IMAGE_COMDAT_SELECT_ASSOCIATIVE 5 // // the following values only be referred in PeCoff, not defined in PECOFF. // #define EFI_IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY 1 #define EFI_IMAGE_WEAK_EXTERN_SEARCH_LIBRARY 2 #define EFI_IMAGE_WEAK_EXTERN_SEARCH_ALIAS 3 /// /// Relocation format. /// typedef struct { UINT32 VirtualAddress; UINT32 SymbolTableIndex; UINT16 Type; } EFI_IMAGE_RELOCATION; /// /// Size of EFI_IMAGE_RELOCATION /// #define EFI_IMAGE_SIZEOF_RELOCATION 10 // // I386 relocation types. // #define EFI_IMAGE_REL_I386_ABSOLUTE 0x0000 ///< Reference is absolute, no relocation is necessary. #define EFI_IMAGE_REL_I386_DIR16 0x0001 ///< Direct 16-bit reference to the symbols virtual address. #define EFI_IMAGE_REL_I386_REL16 0x0002 ///< PC-relative 16-bit reference to the symbols virtual address. #define EFI_IMAGE_REL_I386_DIR32 0x0006 ///< Direct 32-bit reference to the symbols virtual address. #define EFI_IMAGE_REL_I386_DIR32NB 0x0007 ///< Direct 32-bit reference to the symbols virtual address, base not included. #define EFI_IMAGE_REL_I386_SEG12 0x0009 ///< Direct 16-bit reference to the segment-selector bits of a 32-bit virtual address. #define EFI_IMAGE_REL_I386_SECTION 0x000A #define EFI_IMAGE_REL_I386_SECREL 0x000B #define EFI_IMAGE_REL_I386_REL32 0x0014 ///< PC-relative 32-bit reference to the symbols virtual address. // // x64 processor relocation types. // #define IMAGE_REL_AMD64_ABSOLUTE 0x0000 #define IMAGE_REL_AMD64_ADDR64 0x0001 #define IMAGE_REL_AMD64_ADDR32 0x0002 #define IMAGE_REL_AMD64_ADDR32NB 0x0003 #define IMAGE_REL_AMD64_REL32 0x0004 #define IMAGE_REL_AMD64_REL32_1 0x0005 #define IMAGE_REL_AMD64_REL32_2 0x0006 #define IMAGE_REL_AMD64_REL32_3 0x0007 #define IMAGE_REL_AMD64_REL32_4 0x0008 #define IMAGE_REL_AMD64_REL32_5 0x0009 #define IMAGE_REL_AMD64_SECTION 0x000A #define IMAGE_REL_AMD64_SECREL 0x000B #define IMAGE_REL_AMD64_SECREL7 0x000C #define IMAGE_REL_AMD64_TOKEN 0x000D #define IMAGE_REL_AMD64_SREL32 0x000E #define IMAGE_REL_AMD64_PAIR 0x000F #define IMAGE_REL_AMD64_SSPAN32 0x0010 /// /// Based relocation format. /// typedef struct { UINT32 VirtualAddress; UINT32 SizeOfBlock; } EFI_IMAGE_BASE_RELOCATION; /// /// Size of EFI_IMAGE_BASE_RELOCATION. /// #define EFI_IMAGE_SIZEOF_BASE_RELOCATION 8 // // Based relocation types. // #define EFI_IMAGE_REL_BASED_ABSOLUTE 0 #define EFI_IMAGE_REL_BASED_HIGH 1 #define EFI_IMAGE_REL_BASED_LOW 2 #define EFI_IMAGE_REL_BASED_HIGHLOW 3 #define EFI_IMAGE_REL_BASED_HIGHADJ 4 #define EFI_IMAGE_REL_BASED_MIPS_JMPADDR 5 #define EFI_IMAGE_REL_BASED_ARM_MOV32A 5 #define EFI_IMAGE_REL_BASED_ARM_MOV32T 7 #define EFI_IMAGE_REL_BASED_IA64_IMM64 9 #define EFI_IMAGE_REL_BASED_MIPS_JMPADDR16 9 #define EFI_IMAGE_REL_BASED_DIR64 10 /// /// Line number format. /// typedef struct { union { UINT32 SymbolTableIndex; ///< Symbol table index of function name if Linenumber is 0. UINT32 VirtualAddress; ///< Virtual address of line number. } Type; UINT16 Linenumber; ///< Line number. } EFI_IMAGE_LINENUMBER; /// /// Size of EFI_IMAGE_LINENUMBER. /// #define EFI_IMAGE_SIZEOF_LINENUMBER 6 // // Archive format. // #define EFI_IMAGE_ARCHIVE_START_SIZE 8 #define EFI_IMAGE_ARCHIVE_START "!\n" #define EFI_IMAGE_ARCHIVE_END "`\n" #define EFI_IMAGE_ARCHIVE_PAD "\n" #define EFI_IMAGE_ARCHIVE_LINKER_MEMBER "/ " #define EFI_IMAGE_ARCHIVE_LONGNAMES_MEMBER "// " /// /// Archive Member Headers /// typedef struct { UINT8 Name[16]; ///< File member name - `/' terminated. UINT8 Date[12]; ///< File member date - decimal. UINT8 UserID[6]; ///< File member user id - decimal. UINT8 GroupID[6]; ///< File member group id - decimal. UINT8 Mode[8]; ///< File member mode - octal. UINT8 Size[10]; ///< File member size - decimal. UINT8 EndHeader[2]; ///< String to end header. (0x60 0x0A). } EFI_IMAGE_ARCHIVE_MEMBER_HEADER; /// /// Size of EFI_IMAGE_ARCHIVE_MEMBER_HEADER. /// #define EFI_IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR 60 // // DLL Support // /// /// Export Directory Table. /// typedef struct { UINT32 Characteristics; UINT32 TimeDateStamp; UINT16 MajorVersion; UINT16 MinorVersion; UINT32 Name; UINT32 Base; UINT32 NumberOfFunctions; UINT32 NumberOfNames; UINT32 AddressOfFunctions; UINT32 AddressOfNames; UINT32 AddressOfNameOrdinals; } EFI_IMAGE_EXPORT_DIRECTORY; /// /// Hint/Name Table. /// typedef struct { UINT16 Hint; UINT8 Name[1]; } EFI_IMAGE_IMPORT_BY_NAME; /// /// Import Address Table RVA (Thunk Table). /// typedef struct { union { UINT32 Function; UINT32 Ordinal; EFI_IMAGE_IMPORT_BY_NAME *AddressOfData; } u1; } EFI_IMAGE_THUNK_DATA; #define EFI_IMAGE_ORDINAL_FLAG BIT31 ///< Flag for PE32. #define EFI_IMAGE_SNAP_BY_ORDINAL(Ordinal) ((Ordinal & EFI_IMAGE_ORDINAL_FLAG) != 0) #define EFI_IMAGE_ORDINAL(Ordinal) (Ordinal & 0xffff) /// /// Import Directory Table /// typedef struct { UINT32 Characteristics; UINT32 TimeDateStamp; UINT32 ForwarderChain; UINT32 Name; EFI_IMAGE_THUNK_DATA *FirstThunk; } EFI_IMAGE_IMPORT_DESCRIPTOR; /// /// Debug Directory Format. /// typedef struct { UINT32 Characteristics; UINT32 TimeDateStamp; UINT16 MajorVersion; UINT16 MinorVersion; UINT32 Type; UINT32 SizeOfData; UINT32 RVA; ///< The address of the debug data when loaded, relative to the image base. UINT32 FileOffset; ///< The file pointer to the debug data. } EFI_IMAGE_DEBUG_DIRECTORY_ENTRY; #define EFI_IMAGE_DEBUG_TYPE_CODEVIEW 2 ///< The Visual C++ debug information. /// /// Debug Data Structure defined in Microsoft C++. /// #define CODEVIEW_SIGNATURE_NB10 SIGNATURE_32('N', 'B', '1', '0') typedef struct { UINT32 Signature; ///< "NB10" UINT32 Unknown; UINT32 Unknown2; UINT32 Unknown3; // // Filename of .PDB goes here // } EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY; /// /// Debug Data Structure defined in Microsoft C++. /// #define CODEVIEW_SIGNATURE_RSDS SIGNATURE_32('R', 'S', 'D', 'S') typedef struct { UINT32 Signature; ///< "RSDS". UINT32 Unknown; UINT32 Unknown2; UINT32 Unknown3; UINT32 Unknown4; UINT32 Unknown5; // // Filename of .PDB goes here // } EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY; /// /// Debug Data Structure defined by Apple Mach-O to Coff utility. /// #define CODEVIEW_SIGNATURE_MTOC SIGNATURE_32('M', 'T', 'O', 'C') typedef struct { UINT32 Signature; ///< "MTOC". EFI_GUID MachOUuid; // // Filename of .DLL (Mach-O with debug info) goes here // } EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY; /// /// Resource format. /// typedef struct { UINT32 Characteristics; UINT32 TimeDateStamp; UINT16 MajorVersion; UINT16 MinorVersion; UINT16 NumberOfNamedEntries; UINT16 NumberOfIdEntries; // // Array of EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY entries goes here. // } EFI_IMAGE_RESOURCE_DIRECTORY; /// /// Resource directory entry format. /// typedef struct { union { struct { UINT32 NameOffset:31; UINT32 NameIsString:1; } s; UINT32 Id; } u1; union { UINT32 OffsetToData; struct { UINT32 OffsetToDirectory:31; UINT32 DataIsDirectory:1; } s; } u2; } EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY; /// /// Resource directory entry for string. /// typedef struct { UINT16 Length; CHAR16 String[1]; } EFI_IMAGE_RESOURCE_DIRECTORY_STRING; /// /// Resource directory entry for data array. /// typedef struct { UINT32 OffsetToData; UINT32 Size; UINT32 CodePage; UINT32 Reserved; } EFI_IMAGE_RESOURCE_DATA_ENTRY; /// /// Header format for TE images, defined in the PI Specification, 1.0. /// typedef struct { UINT16 Signature; ///< The signature for TE format = "VZ". UINT16 Machine; ///< From the original file header. UINT8 NumberOfSections; ///< From the original file header. UINT8 Subsystem; ///< From original optional header. UINT16 StrippedSize; ///< Number of bytes we removed from the header. UINT32 AddressOfEntryPoint; ///< Offset to entry point -- from original optional header. UINT32 BaseOfCode; ///< From original image -- required for ITP debug. UINT64 ImageBase; ///< From original file header. EFI_IMAGE_DATA_DIRECTORY DataDirectory[2]; ///< Only base relocation and debug directory. } EFI_TE_IMAGE_HEADER; #define EFI_TE_IMAGE_HEADER_SIGNATURE SIGNATURE_16('V', 'Z') // // Data directory indexes in our TE image header // #define EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC 0 #define EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG 1 /// /// Union of PE32, PE32+, and TE headers. /// typedef union { EFI_IMAGE_NT_HEADERS32 Pe32; EFI_IMAGE_NT_HEADERS64 Pe32Plus; EFI_TE_IMAGE_HEADER Te; } EFI_IMAGE_OPTIONAL_HEADER_UNION; typedef union { EFI_IMAGE_NT_HEADERS32 *Pe32; EFI_IMAGE_NT_HEADERS64 *Pe32Plus; EFI_TE_IMAGE_HEADER *Te; EFI_IMAGE_OPTIONAL_HEADER_UNION *Union; } EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION; typedef struct _WIN_CERTIFICATE { UINT32 dwLength; UINT16 wRevision; UINT16 wCertificateType; //UINT8 bCertificate[ANYSIZE_ARRAY]; } WIN_CERTIFICATE; typedef struct { WIN_CERTIFICATE Hdr; UINT8 CertData[1]; } WIN_CERTIFICATE_EFI_PKCS; #define SHA256_DIGEST_SIZE 32 #define WIN_CERT_TYPE_PKCS_SIGNED_DATA 0x0002 #endif refind-0.11.4/include/egemb_arrow_left.h0000664000175000017500000003357112626644770020440 0ustar rodsmithrodsmith/* * include/egemb_arrow_left.h * An encoded left arrow icon * * Copyright (c) 2015 Roderick W. Smith * All rights reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ static const UINT8 egemb_arrow_left_data[2175] = { 0xf9, 0xff, 0x8b, 0x00, 0x9d, 0xff, 0x8e, 0x00, 0x9a, 0xff, 0x90, 0x00, 0x98, 0xff, 0x92, 0x00, 0x97, 0xff, 0x93, 0x00, 0x95, 0xff, 0x95, 0x00, 0x93, 0xff, 0x97, 0x00, 0x91, 0xff, 0x99, 0x00, 0x90, 0xff, 0x9a, 0x00, 0x8e, 0xff, 0x9c, 0x00, 0x8d, 0xff, 0x9d, 0x00, 0x8b, 0xff, 0x9f, 0x00, 0x89, 0xff, 0xa1, 0x00, 0x87, 0xff, 0xa3, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x87, 0xff, 0xa3, 0x00, 0x89, 0xff, 0xa1, 0x00, 0x8b, 0xff, 0x9f, 0x00, 0x8d, 0xff, 0x9d, 0x00, 0x8e, 0xff, 0x9c, 0x00, 0x90, 0xff, 0x9a, 0x00, 0x91, 0xff, 0x99, 0x00, 0x93, 0xff, 0x96, 0x00, 0x96, 0xff, 0x94, 0x00, 0x98, 0xff, 0x92, 0x00, 0x83, 0xff, 0xf9, 0xff, 0x8b, 0x00, 0x9d, 0xff, 0x8b, 0x00, 0x02, 0x6b, 0x7e, 0x7a, 0x9a, 0xff, 0x8b, 0x00, 0x04, 0x37, 0x72, 0x7e, 0x81, 0x83, 0x98, 0xff, 0x8b, 0x00, 0x06, 0x0f, 0x60, 0x7a, 0x80, 0x86, 0x80, 0x80, 0x97, 0xff, 0x8b, 0x00, 0x07, 0x3e, 0x73, 0x7f, 0x82, 0x80, 0x84, 0x80, 0x80, 0x95, 0xff, 0x8b, 0x00, 0x03, 0x24, 0x67, 0x7d, 0x81, 0x80, 0x80, 0x02, 0x84, 0x80, 0x80, 0x93, 0xff, 0x8b, 0x00, 0x04, 0x15, 0x55, 0x77, 0x80, 0x81, 0x81, 0x80, 0x02, 0x84, 0x80, 0x80, 0x91, 0xff, 0x8b, 0x00, 0x04, 0x05, 0x44, 0x70, 0x7f, 0x82, 0x83, 0x80, 0x02, 0x84, 0x80, 0x80, 0x90, 0xff, 0x8b, 0x00, 0x03, 0x2c, 0x69, 0x7d, 0x81, 0x85, 0x80, 0x02, 0x84, 0x80, 0x80, 0x8e, 0xff, 0x8b, 0x00, 0x04, 0x1e, 0x5e, 0x79, 0x81, 0x81, 0x86, 0x80, 0x02, 0x84, 0x80, 0x80, 0x8d, 0xff, 0x8a, 0x00, 0x04, 0x11, 0x51, 0x76, 0x80, 0x81, 0x88, 0x80, 0x02, 0x84, 0x80, 0x80, 0x8b, 0xff, 0x8b, 0x00, 0x03, 0x3e, 0x70, 0x7e, 0x82, 0x8a, 0x80, 0x02, 0x84, 0x80, 0x80, 0x89, 0xff, 0x8b, 0x00, 0x03, 0x28, 0x66, 0x7b, 0x82, 0x8c, 0x80, 0x02, 0x84, 0x80, 0x80, 0x87, 0xff, 0x8b, 0x00, 0x04, 0x1b, 0x5e, 0x79, 0x81, 0x81, 0x8d, 0x80, 0x02, 0x84, 0x80, 0x80, 0x85, 0xff, 0x8b, 0x00, 0x04, 0x0d, 0x4d, 0x75, 0x80, 0x81, 0x8f, 0x80, 0x02, 0x84, 0x80, 0x80, 0x84, 0xff, 0x8b, 0x00, 0x03, 0x38, 0x6d, 0x7e, 0x82, 0x91, 0x80, 0x02, 0x84, 0x80, 0x80, 0x84, 0xff, 0x89, 0x00, 0x03, 0x26, 0x65, 0x7c, 0x81, 0x93, 0x80, 0x02, 0x84, 0x80, 0x80, 0x84, 0xff, 0x87, 0x00, 0x04, 0x18, 0x5a, 0x79, 0x80, 0x81, 0x94, 0x80, 0x02, 0x84, 0x80, 0x80, 0x84, 0xff, 0x85, 0x00, 0x04, 0x09, 0x49, 0x73, 0x80, 0x81, 0x96, 0x80, 0x02, 0x84, 0x80, 0x80, 0x84, 0xff, 0x84, 0x00, 0x03, 0x36, 0x6b, 0x7d, 0x82, 0x98, 0x80, 0x02, 0x84, 0x80, 0x80, 0x84, 0xff, 0x82, 0x00, 0x03, 0x22, 0x62, 0x7a, 0x81, 0x9a, 0x80, 0x02, 0x84, 0x80, 0x80, 0x84, 0xff, 0x80, 0x00, 0x04, 0x1a, 0x5b, 0x78, 0x80, 0x81, 0x9b, 0x80, 0x02, 0x84, 0x80, 0x80, 0x84, 0xff, 0x80, 0x00, 0x04, 0x16, 0x56, 0x77, 0x81, 0x81, 0x9b, 0x80, 0x02, 0x84, 0x80, 0x80, 0x84, 0xff, 0x82, 0x00, 0x03, 0x18, 0x58, 0x78, 0x81, 0x9a, 0x80, 0x02, 0x84, 0x80, 0x80, 0x84, 0xff, 0x84, 0x00, 0x03, 0x22, 0x5e, 0x7c, 0x82, 0x98, 0x80, 0x02, 0x84, 0x80, 0x80, 0x84, 0xff, 0x85, 0x00, 0x04, 0x04, 0x2f, 0x67, 0x7f, 0x81, 0x96, 0x80, 0x02, 0x84, 0x80, 0x80, 0x84, 0xff, 0x87, 0x00, 0x04, 0x0a, 0x40, 0x71, 0x80, 0x81, 0x94, 0x80, 0x02, 0x84, 0x80, 0x80, 0x84, 0xff, 0x89, 0x00, 0x03, 0x12, 0x4f, 0x78, 0x81, 0x93, 0x80, 0x02, 0x84, 0x80, 0x80, 0x84, 0xff, 0x8b, 0x00, 0x03, 0x1e, 0x5c, 0x7d, 0x82, 0x91, 0x80, 0x02, 0x84, 0x80, 0x80, 0x84, 0xff, 0x8c, 0x00, 0x04, 0x05, 0x30, 0x69, 0x80, 0x81, 0x8f, 0x80, 0x02, 0x84, 0x80, 0x80, 0x84, 0xff, 0x8e, 0x00, 0x04, 0x0b, 0x43, 0x72, 0x81, 0x81, 0x8d, 0x80, 0x02, 0x84, 0x80, 0x80, 0x84, 0xff, 0x90, 0x00, 0x03, 0x13, 0x50, 0x78, 0x82, 0x8c, 0x80, 0x02, 0x84, 0x80, 0x80, 0x84, 0xff, 0x92, 0x00, 0x03, 0x22, 0x5f, 0x7d, 0x82, 0x8a, 0x80, 0x02, 0x84, 0x80, 0x80, 0x84, 0xff, 0x93, 0x00, 0x04, 0x07, 0x35, 0x6b, 0x80, 0x81, 0x88, 0x80, 0x02, 0x84, 0x80, 0x80, 0x84, 0xff, 0x95, 0x00, 0x04, 0x0d, 0x44, 0x73, 0x81, 0x81, 0x86, 0x80, 0x02, 0x84, 0x80, 0x80, 0x85, 0xff, 0x96, 0x00, 0x03, 0x16, 0x55, 0x7a, 0x81, 0x85, 0x80, 0x02, 0x84, 0x80, 0x80, 0x87, 0xff, 0x95, 0x00, 0x04, 0x02, 0x28, 0x62, 0x7e, 0x82, 0x83, 0x80, 0x02, 0x84, 0x80, 0x80, 0x89, 0xff, 0x95, 0x00, 0x04, 0x09, 0x39, 0x6e, 0x80, 0x81, 0x81, 0x80, 0x02, 0x84, 0x80, 0x80, 0x8b, 0xff, 0x95, 0x00, 0x03, 0x10, 0x4d, 0x78, 0x81, 0x80, 0x80, 0x02, 0x84, 0x80, 0x80, 0x8d, 0xff, 0x95, 0x00, 0x07, 0x1f, 0x60, 0x7d, 0x82, 0x80, 0x84, 0x80, 0x80, 0x8e, 0xff, 0x95, 0x00, 0x06, 0x05, 0x3b, 0x6f, 0x80, 0x86, 0x80, 0x80, 0x90, 0xff, 0x95, 0x00, 0x04, 0x12, 0x59, 0x7a, 0x81, 0x83, 0x91, 0xff, 0x96, 0x00, 0x02, 0x3b, 0x71, 0x85, 0x93, 0xff, 0x96, 0x00, 0x96, 0xff, 0x94, 0x00, 0x98, 0xff, 0x92, 0x00, 0x83, 0xff, 0xf9, 0xff, 0x8b, 0x00, 0x9d, 0xff, 0x8e, 0x00, 0x9a, 0xff, 0x90, 0x00, 0x98, 0xff, 0x92, 0x00, 0x97, 0xff, 0x93, 0x00, 0x95, 0xff, 0x95, 0x00, 0x93, 0xff, 0x97, 0x00, 0x91, 0xff, 0x99, 0x00, 0x90, 0xff, 0x9a, 0x00, 0x8e, 0xff, 0x9c, 0x00, 0x8d, 0xff, 0x9d, 0x00, 0x8b, 0xff, 0x9f, 0x00, 0x89, 0xff, 0xa1, 0x00, 0x87, 0xff, 0xa3, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x87, 0xff, 0xa3, 0x00, 0x89, 0xff, 0xa1, 0x00, 0x8b, 0xff, 0x9f, 0x00, 0x8d, 0xff, 0x9d, 0x00, 0x8e, 0xff, 0x9c, 0x00, 0x90, 0xff, 0x9a, 0x00, 0x91, 0xff, 0x99, 0x00, 0x93, 0xff, 0x96, 0x00, 0x96, 0xff, 0x94, 0x00, 0x98, 0xff, 0x92, 0x00, 0x83, 0xff, 0xf9, 0x00, 0x06, 0x01, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x81, 0x07, 0x02, 0x06, 0x05, 0x03, 0x9d, 0x00, 0x10, 0x01, 0x01, 0x02, 0x03, 0x05, 0x06, 0x08, 0x0a, 0x0b, 0x0c, 0x0d, 0x0d, 0x0b, 0x06, 0x26, 0x57, 0x19, 0x9a, 0x00, 0x12, 0x01, 0x01, 0x02, 0x03, 0x04, 0x06, 0x09, 0x0b, 0x0d, 0x10, 0x12, 0x14, 0x14, 0x11, 0x1c, 0x67, 0xd9, 0xc6, 0x25, 0x98, 0x00, 0x80, 0x01, 0x11, 0x02, 0x04, 0x06, 0x08, 0x0b, 0x0e, 0x11, 0x15, 0x18, 0x1b, 0x1c, 0x21, 0x52, 0xba, 0xfb, 0xff, 0xc6, 0x24, 0x97, 0x00, 0x10, 0x01, 0x01, 0x02, 0x04, 0x05, 0x07, 0x0a, 0x0d, 0x11, 0x16, 0x1b, 0x1f, 0x23, 0x26, 0x46, 0xa4, 0xf3, 0x80, 0xff, 0x01, 0xc6, 0x24, 0x95, 0x00, 0x10, 0x01, 0x01, 0x02, 0x03, 0x05, 0x07, 0x09, 0x0c, 0x10, 0x15, 0x1a, 0x20, 0x26, 0x2a, 0x40, 0x90, 0xe6, 0x82, 0xff, 0x01, 0xc6, 0x24, 0x93, 0x00, 0x10, 0x01, 0x01, 0x02, 0x03, 0x04, 0x06, 0x09, 0x0b, 0x0f, 0x14, 0x19, 0x1f, 0x26, 0x2c, 0x3c, 0x7b, 0xd6, 0x84, 0xff, 0x01, 0xc6, 0x24, 0x91, 0x00, 0x80, 0x01, 0x0e, 0x02, 0x04, 0x06, 0x08, 0x0b, 0x0e, 0x12, 0x17, 0x1d, 0x24, 0x2b, 0x36, 0x66, 0xc1, 0xfb, 0x85, 0xff, 0x01, 0xc6, 0x24, 0x90, 0x00, 0x10, 0x01, 0x01, 0x02, 0x03, 0x05, 0x07, 0x0a, 0x0d, 0x11, 0x16, 0x1b, 0x22, 0x2a, 0x31, 0x52, 0xaa, 0xf3, 0x87, 0xff, 0x01, 0xc6, 0x24, 0x8e, 0x00, 0x10, 0x01, 0x01, 0x02, 0x03, 0x05, 0x07, 0x09, 0x0c, 0x10, 0x15, 0x1a, 0x20, 0x28, 0x2e, 0x44, 0x90, 0xe5, 0x89, 0xff, 0x01, 0xc6, 0x24, 0x8d, 0x00, 0x10, 0x01, 0x01, 0x03, 0x04, 0x06, 0x08, 0x0b, 0x0f, 0x14, 0x19, 0x1e, 0x25, 0x2c, 0x3c, 0x77, 0xd2, 0xfe, 0x8a, 0xff, 0x01, 0xc6, 0x24, 0x8b, 0x00, 0x10, 0x01, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0d, 0x12, 0x17, 0x1d, 0x23, 0x2b, 0x35, 0x5f, 0xbb, 0xfa, 0x8c, 0xff, 0x01, 0xc6, 0x24, 0x89, 0x00, 0x10, 0x01, 0x01, 0x02, 0x03, 0x05, 0x07, 0x09, 0x0d, 0x11, 0x16, 0x1b, 0x21, 0x29, 0x2f, 0x4d, 0xa3, 0xf0, 0x8e, 0xff, 0x01, 0xc6, 0x24, 0x87, 0x00, 0x10, 0x01, 0x01, 0x02, 0x03, 0x04, 0x06, 0x09, 0x0b, 0x0f, 0x14, 0x1a, 0x1f, 0x27, 0x2d, 0x43, 0x8b, 0xe1, 0x90, 0xff, 0x01, 0xc6, 0x24, 0x85, 0x00, 0x11, 0x01, 0x01, 0x02, 0x03, 0x04, 0x06, 0x08, 0x0b, 0x0e, 0x13, 0x18, 0x1e, 0x25, 0x2c, 0x3a, 0x71, 0xcd, 0xfd, 0x91, 0xff, 0x01, 0xc6, 0x24, 0x84, 0x00, 0x10, 0x01, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0d, 0x12, 0x17, 0x1c, 0x23, 0x2a, 0x33, 0x5b, 0xb7, 0xf8, 0x93, 0xff, 0x01, 0xc6, 0x24, 0x84, 0x00, 0x0e, 0x02, 0x03, 0x05, 0x07, 0x09, 0x0c, 0x11, 0x16, 0x1b, 0x21, 0x29, 0x2e, 0x49, 0x9f, 0xed, 0x95, 0xff, 0x01, 0xc6, 0x24, 0x84, 0x00, 0x0c, 0x04, 0x06, 0x08, 0x0b, 0x0f, 0x14, 0x19, 0x1f, 0x27, 0x2d, 0x40, 0x85, 0xdd, 0x97, 0xff, 0x01, 0xc6, 0x24, 0x84, 0x00, 0x0b, 0x06, 0x09, 0x0c, 0x11, 0x16, 0x1d, 0x24, 0x2b, 0x38, 0x6d, 0xc8, 0xfc, 0x98, 0xff, 0x01, 0xc6, 0x24, 0x84, 0x00, 0x09, 0x09, 0x0d, 0x12, 0x18, 0x20, 0x28, 0x30, 0x55, 0xb1, 0xf6, 0x9a, 0xff, 0x01, 0xc6, 0x24, 0x84, 0x00, 0x07, 0x0d, 0x12, 0x19, 0x21, 0x28, 0x43, 0x97, 0xea, 0x9c, 0xff, 0x01, 0xc6, 0x24, 0x84, 0x00, 0x05, 0x10, 0x18, 0x1e, 0x32, 0x78, 0xd6, 0x9e, 0xff, 0x01, 0xc6, 0x24, 0x84, 0x00, 0x06, 0x15, 0x1d, 0x25, 0x3a, 0x7f, 0xd9, 0xfe, 0x9d, 0xff, 0x01, 0xc6, 0x24, 0x84, 0x00, 0x07, 0x17, 0x21, 0x2c, 0x39, 0x45, 0x60, 0xa9, 0xee, 0x9c, 0xff, 0x01, 0xc6, 0x24, 0x84, 0x00, 0x09, 0x19, 0x23, 0x2f, 0x3d, 0x4b, 0x59, 0x66, 0x87, 0xc9, 0xf9, 0x9a, 0xff, 0x01, 0xc6, 0x24, 0x84, 0x00, 0x0b, 0x19, 0x23, 0x2f, 0x3d, 0x4b, 0x59, 0x67, 0x74, 0x82, 0xa7, 0xdf, 0xfd, 0x98, 0xff, 0x01, 0xc6, 0x24, 0x84, 0x00, 0x0c, 0x17, 0x21, 0x2c, 0x39, 0x47, 0x54, 0x62, 0x6f, 0x7b, 0x85, 0x94, 0xbc, 0xed, 0x97, 0xff, 0x01, 0xc6, 0x24, 0x84, 0x00, 0x0e, 0x15, 0x1d, 0x27, 0x32, 0x3f, 0x4c, 0x59, 0x65, 0x71, 0x7d, 0x86, 0x8d, 0x9e, 0xcc, 0xf5, 0x95, 0xff, 0x01, 0xc6, 0x24, 0x84, 0x00, 0x10, 0x10, 0x18, 0x20, 0x2a, 0x35, 0x40, 0x4c, 0x58, 0x64, 0x6f, 0x7a, 0x83, 0x8b, 0x93, 0xa9, 0xd9, 0xfb, 0x93, 0xff, 0x01, 0xc6, 0x24, 0x84, 0x00, 0x12, 0x0d, 0x12, 0x19, 0x21, 0x2a, 0x34, 0x3f, 0x4a, 0x55, 0x60, 0x6a, 0x74, 0x7d, 0x86, 0x8d, 0x97, 0xb5, 0xe5, 0xfe, 0x91, 0xff, 0x01, 0xc6, 0x24, 0x84, 0x00, 0x13, 0x09, 0x0d, 0x12, 0x18, 0x20, 0x28, 0x31, 0x3a, 0x45, 0x4e, 0x59, 0x64, 0x6e, 0x77, 0x7f, 0x88, 0x8f, 0x9c, 0xc2, 0xf0, 0x90, 0xff, 0x01, 0xc6, 0x24, 0x84, 0x00, 0x15, 0x06, 0x09, 0x0c, 0x11, 0x16, 0x1d, 0x24, 0x2c, 0x34, 0x3e, 0x47, 0x52, 0x5c, 0x66, 0x70, 0x79, 0x82, 0x8a, 0x91, 0xa2, 0xd0, 0xf7, 0x8e, 0xff, 0x01, 0xc6, 0x24, 0x84, 0x00, 0x17, 0x04, 0x06, 0x08, 0x0b, 0x0f, 0x14, 0x19, 0x1f, 0x27, 0x2f, 0x37, 0x40, 0x4b, 0x55, 0x5f, 0x69, 0x72, 0x7b, 0x84, 0x8c, 0x94, 0xac, 0xdc, 0xfc, 0x8c, 0xff, 0x01, 0xc6, 0x24, 0x84, 0x00, 0x19, 0x02, 0x03, 0x05, 0x07, 0x09, 0x0c, 0x11, 0x16, 0x1b, 0x21, 0x29, 0x31, 0x39, 0x43, 0x4c, 0x56, 0x61, 0x6b, 0x75, 0x7e, 0x86, 0x8d, 0x98, 0xb8, 0xe7, 0xfe, 0x8a, 0xff, 0x01, 0xc6, 0x24, 0x84, 0x00, 0x1a, 0x01, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0d, 0x12, 0x17, 0x1c, 0x23, 0x2b, 0x33, 0x3c, 0x45, 0x50, 0x5a, 0x64, 0x6e, 0x77, 0x80, 0x89, 0x90, 0x9d, 0xc6, 0xf2, 0x89, 0xff, 0x01, 0xc6, 0x24, 0x85, 0x00, 0x1b, 0x01, 0x01, 0x02, 0x03, 0x04, 0x06, 0x08, 0x0b, 0x0e, 0x13, 0x18, 0x1e, 0x25, 0x2d, 0x35, 0x3e, 0x49, 0x53, 0x5d, 0x67, 0x70, 0x7a, 0x83, 0x8b, 0x91, 0xa4, 0xd2, 0xf8, 0x87, 0xff, 0x01, 0xc6, 0x24, 0x87, 0x00, 0x1b, 0x01, 0x01, 0x02, 0x03, 0x04, 0x06, 0x09, 0x0b, 0x0f, 0x14, 0x1a, 0x1f, 0x27, 0x2f, 0x38, 0x41, 0x4a, 0x54, 0x5f, 0x6a, 0x73, 0x7c, 0x85, 0x8d, 0x95, 0xae, 0xde, 0xfd, 0x85, 0xff, 0x01, 0xc6, 0x24, 0x89, 0x00, 0x1a, 0x01, 0x01, 0x02, 0x03, 0x05, 0x07, 0x09, 0x0d, 0x11, 0x16, 0x1b, 0x21, 0x29, 0x31, 0x3a, 0x43, 0x4e, 0x58, 0x62, 0x6c, 0x76, 0x7f, 0x87, 0x8d, 0x96, 0xb8, 0xe8, 0x84, 0xff, 0x01, 0xc6, 0x24, 0x8b, 0x00, 0x1a, 0x01, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0d, 0x12, 0x17, 0x1d, 0x23, 0x2b, 0x34, 0x3c, 0x47, 0x51, 0x5b, 0x65, 0x6f, 0x78, 0x80, 0x87, 0x8a, 0x94, 0xbf, 0xf0, 0x82, 0xff, 0x01, 0xc6, 0x24, 0x8d, 0x00, 0x1a, 0x01, 0x01, 0x03, 0x04, 0x06, 0x08, 0x0b, 0x0f, 0x14, 0x19, 0x1e, 0x25, 0x2d, 0x36, 0x3f, 0x49, 0x54, 0x5e, 0x67, 0x70, 0x78, 0x7e, 0x81, 0x80, 0x8e, 0xc4, 0xf6, 0x80, 0xff, 0x01, 0xc6, 0x24, 0x8e, 0x00, 0x1e, 0x01, 0x01, 0x02, 0x03, 0x05, 0x07, 0x09, 0x0c, 0x10, 0x15, 0x1a, 0x20, 0x28, 0x30, 0x38, 0x42, 0x4b, 0x56, 0x5f, 0x68, 0x6e, 0x72, 0x74, 0x70, 0x6c, 0x86, 0xcc, 0xfc, 0xff, 0xc6, 0x24, 0x90, 0x00, 0x1c, 0x01, 0x01, 0x02, 0x03, 0x05, 0x07, 0x0a, 0x0d, 0x11, 0x16, 0x1b, 0x22, 0x2a, 0x32, 0x3b, 0x44, 0x4d, 0x56, 0x5d, 0x63, 0x65, 0x64, 0x5f, 0x55, 0x53, 0x84, 0xdf, 0xc6, 0x25, 0x91, 0x00, 0x80, 0x01, 0x18, 0x02, 0x04, 0x06, 0x08, 0x0b, 0x0e, 0x12, 0x17, 0x1d, 0x24, 0x2c, 0x34, 0x3d, 0x45, 0x4c, 0x52, 0x55, 0x56, 0x52, 0x4b, 0x41, 0x32, 0x45, 0x61, 0x17, 0x93, 0x00, 0x18, 0x01, 0x01, 0x02, 0x03, 0x04, 0x06, 0x09, 0x0b, 0x0f, 0x14, 0x19, 0x1f, 0x26, 0x2e, 0x35, 0x3b, 0x41, 0x45, 0x46, 0x44, 0x3f, 0x37, 0x2e, 0x24, 0x13, 0x96, 0x00, 0x16, 0x01, 0x01, 0x02, 0x03, 0x05, 0x07, 0x09, 0x0c, 0x10, 0x15, 0x1a, 0x20, 0x26, 0x2c, 0x32, 0x35, 0x37, 0x36, 0x32, 0x2d, 0x25, 0x1e, 0x10, 0x98, 0x00, 0x14, 0x01, 0x01, 0x02, 0x04, 0x05, 0x07, 0x0a, 0x0d, 0x11, 0x16, 0x1b, 0x1f, 0x23, 0x27, 0x29, 0x29, 0x27, 0x22, 0x1d, 0x17, 0x0c, 0x83, 0x00, }; static EG_EMBEDDED_IMAGE egemb_arrow_left = { 48, 48, EG_EIPIXELMODE_COLOR_ALPHA, EG_EICOMPMODE_RLE, egemb_arrow_left_data, 2175 }; refind-0.11.4/include/egemb_refind_banner.h0000664000175000017500000042166612626644770021076 0ustar rodsmithrodsmith/* * include/egemb_refind_banner.h * An encoded rEFInd banner graphic * * Copyright (c) 2015 Roderick W. Smith * All rights reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ static const UINT8 egemb_refind_banner_data[22887] = { 0x94, 0xd0, 0x12, 0xcf, 0xce, 0xcd, 0xcc, 0xcb, 0xc9, 0xc7, 0xc6, 0xc5, 0xc4, 0xc4, 0xc6, 0xc7, 0xc9, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xff, 0xd0, 0xb7, 0xd0, 0x18, 0xcf, 0xcf, 0xcd, 0xcc, 0xc9, 0xc6, 0xc2, 0xbc, 0xa4, 0x8b, 0x7a, 0x69, 0x73, 0x85, 0x9e, 0xb4, 0xba, 0xbe, 0xc2, 0xc6, 0xc9, 0xcc, 0xcd, 0xcf, 0xcf, 0xff, 0xd0, 0xb3, 0xd0, 0x08, 0xcf, 0xcd, 0xcb, 0xc7, 0xc2, 0xa9, 0x64, 0x2a, 0x0a, 0x83, 0x00, 0x0d, 0x01, 0x0b, 0x22, 0x56, 0x95, 0xb4, 0xbb, 0xc2, 0xc7, 0xcb, 0xcd, 0xcf, 0xd0, 0xd0, 0x81, 0xcf, 0xff, 0xd0, 0xaa, 0xd0, 0x07, 0xcf, 0xce, 0xcc, 0xc7, 0xb8, 0x73, 0x37, 0x07, 0x8a, 0x00, 0x0f, 0x04, 0x2d, 0x65, 0xa4, 0xb8, 0xc1, 0xc7, 0xcc, 0xce, 0xce, 0xcd, 0xcc, 0xcc, 0xcd, 0xce, 0xcf, 0xff, 0xd0, 0xa7, 0xd0, 0x05, 0xcf, 0xcd, 0xca, 0xc3, 0x76, 0x12, 0x90, 0x00, 0x0c, 0x11, 0x69, 0xac, 0xba, 0xc3, 0xc8, 0xca, 0xc7, 0x8f, 0xc4, 0xc7, 0xcc, 0xce, 0xa3, 0xd0, 0x8b, 0xcf, 0x89, 0xd0, 0x89, 0xcf, 0xb9, 0xd0, 0x83, 0xcf, 0x9a, 0xd0, 0x05, 0xcf, 0xcc, 0xc7, 0xb2, 0x45, 0x01, 0x92, 0x00, 0x0c, 0x01, 0x37, 0x94, 0xb2, 0xbc, 0xbf, 0x64, 0x0a, 0xb3, 0xbd, 0xc6, 0xcc, 0xcf, 0x9e, 0xd0, 0x04, 0xcf, 0xcf, 0xce, 0xcd, 0xcd, 0x89, 0xcc, 0x03, 0xcd, 0xcd, 0xce, 0xcf, 0x82, 0xd0, 0x03, 0xcf, 0xcf, 0xce, 0xcd, 0x88, 0xcc, 0x03, 0xcd, 0xcd, 0xce, 0xcf, 0x82, 0xd0, 0x06, 0xcf, 0xce, 0xce, 0xcd, 0xce, 0xcf, 0xcf, 0xa9, 0xd0, 0x07, 0xcf, 0xcd, 0xcc, 0xcb, 0xcb, 0xcc, 0xcd, 0xcf, 0x98, 0xd0, 0x04, 0xce, 0xcc, 0xc6, 0x8a, 0x1d, 0x96, 0x00, 0x0a, 0x13, 0x69, 0xa4, 0x5d, 0x0d, 0x0a, 0x83, 0xad, 0xbf, 0xca, 0xce, 0x9d, 0xd0, 0x05, 0xcf, 0xcd, 0xcb, 0xc8, 0xc6, 0xc4, 0x89, 0xc3, 0x0d, 0xc5, 0xc6, 0xc9, 0xcc, 0xce, 0xcf, 0xd0, 0xd0, 0xcf, 0xcc, 0xcb, 0xc7, 0xc6, 0xc4, 0x87, 0xc3, 0x10, 0xc5, 0xc6, 0xc9, 0xcc, 0xce, 0xcf, 0xd0, 0xcf, 0xce, 0xcc, 0xca, 0xc7, 0xc6, 0xc8, 0xcc, 0xcd, 0xcf, 0xa7, 0xd0, 0x09, 0xce, 0xcc, 0xc7, 0xbb, 0xb7, 0xbf, 0xc2, 0xc8, 0xcc, 0xcf, 0x96, 0xd0, 0x04, 0xcf, 0xcc, 0xc5, 0x63, 0x06, 0x98, 0x00, 0x09, 0x01, 0x29, 0x0a, 0x00, 0x00, 0x50, 0x9e, 0xb6, 0xc6, 0xcd, 0x9c, 0xd0, 0x06, 0xcf, 0xcc, 0xc7, 0xad, 0x87, 0x76, 0x6e, 0x88, 0x6d, 0x0e, 0x6f, 0x8b, 0xb3, 0xbc, 0xc4, 0xca, 0xce, 0xcf, 0xce, 0xcc, 0xc6, 0xa1, 0x83, 0x73, 0x6e, 0x86, 0x6d, 0x12, 0x6e, 0x8a, 0xb2, 0xbc, 0xc3, 0xca, 0xcd, 0xcf, 0xce, 0xcb, 0xc2, 0x8a, 0x69, 0x9e, 0xbb, 0xc2, 0xc9, 0xcd, 0xcf, 0xa5, 0xd0, 0x0b, 0xcf, 0xcc, 0xb7, 0x41, 0x08, 0x06, 0x37, 0xae, 0xbc, 0xc6, 0xcc, 0xcf, 0x94, 0xd0, 0x04, 0xcf, 0xcc, 0xc6, 0x79, 0x03, 0x88, 0x00, 0x06, 0x04, 0x17, 0x24, 0x25, 0x23, 0x1a, 0x09, 0x87, 0x00, 0x01, 0x07, 0x07, 0x80, 0x00, 0x05, 0x28, 0x90, 0xae, 0xc2, 0xcc, 0xcf, 0x9a, 0xd0, 0x04, 0xcf, 0xcc, 0xc5, 0x4b, 0x03, 0x8d, 0x00, 0x08, 0x06, 0x81, 0xb4, 0xc2, 0xcb, 0xcd, 0xcc, 0xba, 0x2e, 0x8c, 0x00, 0x08, 0x04, 0x77, 0xb4, 0xc2, 0xcb, 0xcd, 0xcb, 0xa9, 0x11, 0x80, 0x00, 0x04, 0x6d, 0xb2, 0xc0, 0xca, 0xce, 0xa4, 0xd0, 0x03, 0xcf, 0xcd, 0xc6, 0x56, 0x81, 0x00, 0x04, 0x6a, 0xab, 0xc0, 0xca, 0xce, 0x93, 0xd0, 0x04, 0xcf, 0xcd, 0xc7, 0x95, 0x0d, 0x86, 0x00, 0x0c, 0x12, 0x2d, 0x46, 0x66, 0x73, 0x7a, 0x7e, 0x80, 0x7f, 0x7a, 0x5c, 0x35, 0x0d, 0x83, 0x00, 0x01, 0x04, 0x04, 0x81, 0x00, 0x05, 0x17, 0x86, 0xa8, 0xc0, 0xcb, 0xcf, 0x9a, 0xd0, 0x02, 0xce, 0xc9, 0x73, 0x90, 0x00, 0x06, 0x32, 0xa1, 0xb8, 0xc6, 0xcb, 0xc6, 0x48, 0x8e, 0x00, 0x06, 0x2b, 0xa0, 0xb7, 0xc6, 0xcb, 0xc6, 0x4d, 0x81, 0x00, 0x05, 0x25, 0x9e, 0xb5, 0xc6, 0xcd, 0xcf, 0xa3, 0xd0, 0x03, 0xcf, 0xcb, 0xb3, 0x06, 0x81, 0x00, 0x05, 0x45, 0x9c, 0xb7, 0xc6, 0xce, 0xcf, 0x92, 0xd0, 0x03, 0xce, 0xc9, 0xad, 0x1b, 0x85, 0x00, 0x10, 0x08, 0x35, 0x67, 0x76, 0x84, 0x8e, 0x98, 0x9e, 0xa3, 0xa4, 0xa3, 0x9f, 0x99, 0x90, 0x81, 0x47, 0x0b, 0x80, 0x00, 0x01, 0x04, 0x04, 0x82, 0x00, 0x05, 0x0e, 0x7e, 0xa2, 0xbd, 0xca, 0xcf, 0x99, 0xd0, 0x03, 0xcf, 0xcc, 0xc4, 0x31, 0x90, 0x00, 0x06, 0x1d, 0x93, 0xb0, 0xc2, 0xc8, 0xbe, 0x0d, 0x8e, 0x00, 0x06, 0x19, 0x92, 0xaf, 0xc2, 0xc7, 0xb5, 0x06, 0x81, 0x00, 0x05, 0x17, 0x8d, 0xab, 0xc2, 0xcc, 0xcf, 0xa3, 0xd0, 0x02, 0xce, 0xc8, 0x8a, 0x82, 0x00, 0x05, 0x4d, 0x93, 0xb3, 0xc5, 0xcd, 0xcf, 0x91, 0xd0, 0x03, 0xcf, 0xcc, 0xbe, 0x32, 0x84, 0x00, 0x16, 0x01, 0x21, 0x5a, 0x76, 0x88, 0x99, 0xa5, 0xaf, 0xb6, 0xbb, 0xbd, 0xbf, 0xbe, 0xbb, 0xb7, 0xb0, 0xa5, 0x98, 0x77, 0x24, 0x00, 0x04, 0x04, 0x83, 0x00, 0x05, 0x09, 0x6a, 0x9c, 0xb9, 0xc8, 0xce, 0x99, 0xd0, 0x03, 0xcf, 0xcb, 0xbd, 0x07, 0x90, 0x00, 0x05, 0x42, 0x91, 0xae, 0xc2, 0xc5, 0x98, 0x8f, 0x00, 0x05, 0x3f, 0x90, 0xad, 0xc1, 0xc5, 0x8f, 0x82, 0x00, 0x05, 0x23, 0x85, 0xa7, 0xc0, 0xcb, 0xcf, 0xa2, 0xd0, 0x03, 0xcf, 0xcd, 0xc5, 0x64, 0x82, 0x00, 0x05, 0x5d, 0x92, 0xb3, 0xc5, 0xcd, 0xcf, 0x90, 0xd0, 0x03, 0xcf, 0xcd, 0xc6, 0x60, 0x84, 0x00, 0x0a, 0x01, 0x37, 0x6a, 0x80, 0x95, 0xa7, 0xb4, 0xbe, 0xc3, 0xc6, 0xc9, 0x80, 0xcb, 0x08, 0xca, 0xc7, 0xc4, 0xbe, 0xb3, 0xa3, 0x8c, 0x1e, 0x06, 0x84, 0x00, 0x05, 0x01, 0x49, 0x95, 0xb4, 0xc6, 0xcd, 0x95, 0xd0, 0x00, 0xcf, 0x80, 0xd0, 0x02, 0xce, 0xc8, 0xa0, 0x8d, 0x00, 0x09, 0x03, 0x15, 0x2b, 0x4d, 0x82, 0x9b, 0xb4, 0xc3, 0xc3, 0x73, 0x8b, 0x00, 0x09, 0x03, 0x15, 0x2b, 0x4d, 0x81, 0x9b, 0xb4, 0xc2, 0xc2, 0x6d, 0x82, 0x00, 0x05, 0x34, 0x84, 0xa8, 0xc0, 0xcc, 0xcf, 0x89, 0xd0, 0x01, 0xcf, 0xcf, 0x94, 0xd0, 0x03, 0xcf, 0xcc, 0xc2, 0x42, 0x81, 0x00, 0x05, 0x03, 0x6f, 0x95, 0xb4, 0xc6, 0xcd, 0x91, 0xd0, 0x03, 0xcf, 0xcb, 0xbe, 0x1a, 0x84, 0x00, 0x0a, 0x2f, 0x6d, 0x86, 0x9e, 0xb1, 0xbd, 0xc6, 0xca, 0xcc, 0xcd, 0xce, 0x80, 0xcf, 0x07, 0xce, 0xce, 0xcc, 0xc8, 0xc1, 0xb2, 0x41, 0x08, 0x86, 0x00, 0x05, 0x24, 0x8d, 0xae, 0xc2, 0xcc, 0xcf, 0x8a, 0xd0, 0x01, 0xcf, 0xcf, 0x80, 0xce, 0x80, 0xcf, 0x00, 0xce, 0x80, 0xcd, 0x04, 0xce, 0xcf, 0xcd, 0xc6, 0x7e, 0x82, 0x00, 0x04, 0x23, 0x5a, 0x66, 0x6f, 0x72, 0x83, 0x73, 0x09, 0x76, 0x7a, 0x80, 0x8b, 0x9b, 0xae, 0xbf, 0xc6, 0xc2, 0x53, 0x82, 0x00, 0x04, 0x35, 0x5d, 0x69, 0x70, 0x72, 0x81, 0x73, 0x09, 0x76, 0x7a, 0x80, 0x8a, 0x9b, 0xae, 0xbf, 0xc6, 0xc1, 0x4c, 0x82, 0x00, 0x04, 0x46, 0x88, 0xab, 0xc2, 0xcc, 0x80, 0xcf, 0x80, 0xce, 0x81, 0xcf, 0x01, 0xce, 0xce, 0x81, 0xcd, 0x02, 0xce, 0xcf, 0xcf, 0x8c, 0xd0, 0x81, 0xcf, 0x03, 0xcd, 0xc9, 0xbe, 0x21, 0x81, 0x00, 0x05, 0x11, 0x76, 0x9a, 0xb8, 0xc8, 0xce, 0x91, 0xd0, 0x02, 0xcd, 0xc7, 0x74, 0x84, 0x00, 0x09, 0x25, 0x6c, 0x86, 0xa1, 0xb4, 0xc2, 0xc9, 0xcc, 0xce, 0xcf, 0x83, 0xd0, 0x05, 0xcf, 0xce, 0xcb, 0xc2, 0x42, 0x08, 0x87, 0x00, 0x05, 0x14, 0x84, 0xa7, 0xc0, 0xcb, 0xcf, 0x89, 0xd0, 0x11, 0xcf, 0xcd, 0xcb, 0xc8, 0xc8, 0xc9, 0xcb, 0xcc, 0xcb, 0xc8, 0xc6, 0xc5, 0xc6, 0xc9, 0xcc, 0xcb, 0xc3, 0x5c, 0x82, 0x00, 0x05, 0x38, 0x6e, 0x83, 0x91, 0x97, 0x98, 0x82, 0x99, 0x09, 0x9b, 0x9e, 0xa3, 0xab, 0xb4, 0xc0, 0xc7, 0xc9, 0xc0, 0x34, 0x82, 0x00, 0x05, 0x4f, 0x73, 0x87, 0x93, 0x98, 0x98, 0x80, 0x99, 0x09, 0x9b, 0x9e, 0xa3, 0xab, 0xb4, 0xc0, 0xc6, 0xc9, 0xc0, 0x2e, 0x82, 0x00, 0x0b, 0x5b, 0x8e, 0xb0, 0xc4, 0xcc, 0xce, 0xcd, 0xcb, 0xc8, 0xc7, 0xc8, 0xcb, 0x80, 0xcc, 0x09, 0xca, 0xc7, 0xc6, 0xc4, 0xc5, 0xc6, 0xc9, 0xcc, 0xcd, 0xcf, 0x88, 0xd0, 0x0a, 0xcf, 0xcf, 0xce, 0xcd, 0xcc, 0xcb, 0xca, 0xc7, 0xc2, 0xb3, 0x06, 0x81, 0x00, 0x05, 0x21, 0x7a, 0x9f, 0xbc, 0xca, 0xce, 0x90, 0xd0, 0x03, 0xcf, 0xcc, 0xc2, 0x2e, 0x83, 0x00, 0x08, 0x11, 0x65, 0x82, 0x9e, 0xb5, 0xc3, 0xcb, 0xce, 0xcf, 0x86, 0xd0, 0x03, 0xce, 0xc7, 0x3b, 0x06, 0x88, 0x00, 0x05, 0x0b, 0x77, 0xa0, 0xbb, 0xc9, 0xce, 0x88, 0xd0, 0x12, 0xcf, 0xcc, 0xc6, 0xa7, 0x79, 0xa9, 0xbc, 0xc0, 0xc2, 0xb4, 0x87, 0x5d, 0x73, 0xa7, 0xbb, 0xc3, 0xc6, 0xc0, 0x3e, 0x82, 0x00, 0x05, 0x4e, 0x7e, 0x98, 0xa9, 0xb0, 0xb2, 0x83, 0xb3, 0x08, 0xb5, 0xba, 0xbf, 0xc4, 0xc9, 0xcc, 0xca, 0xbe, 0x17, 0x81, 0x00, 0x05, 0x03, 0x66, 0x84, 0x9e, 0xab, 0xb1, 0x81, 0xb3, 0x09, 0xb4, 0xb5, 0xba, 0xbf, 0xc4, 0xc9, 0xcc, 0xca, 0xbd, 0x11, 0x81, 0x00, 0x1b, 0x03, 0x6f, 0x94, 0xb4, 0xc6, 0xcc, 0xcc, 0xc6, 0xa1, 0x71, 0x9b, 0xbb, 0xc0, 0xc4, 0xc5, 0xc2, 0xac, 0x86, 0x63, 0x70, 0x8e, 0xac, 0xbb, 0xc1, 0xc6, 0xcc, 0xce, 0xcf, 0x84, 0xd0, 0x0b, 0xcf, 0xcf, 0xcd, 0xcb, 0xc8, 0xc5, 0xc1, 0xbe, 0xbb, 0xab, 0x92, 0x69, 0x82, 0x00, 0x05, 0x32, 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0x90, 0xd0, 0x03, 0xce, 0xc8, 0x8e, 0x01, 0x83, 0x00, 0x07, 0x3b, 0x79, 0x98, 0xb2, 0xc2, 0xcb, 0xce, 0xcf, 0x87, 0xd0, 0x08, 0xcd, 0xbc, 0x7a, 0x45, 0x23, 0x17, 0x0d, 0x07, 0x01, 0x83, 0x00, 0x05, 0x03, 0x59, 0x9a, 0xb7, 0xc7, 0xce, 0x87, 0xd0, 0x0a, 0xcf, 0xcc, 0xc6, 0x35, 0x00, 0x00, 0x03, 0x96, 0xa8, 0x49, 0x01, 0x80, 0x00, 0x05, 0x03, 0x92, 0xb4, 0xbf, 0xbb, 0x1e, 0x81, 0x00, 0x04, 0x01, 0x5c, 0x7c, 0x95, 0xa4, 0x83, 0xab, 0x0a, 0xac, 0xb1, 0xb5, 0xbb, 0xc1, 0xc7, 0xcc, 0xcd, 0xc9, 0xb3, 0x01, 0x81, 0x00, 0x04, 0x10, 0x65, 0x82, 0x9a, 0xa6, 0x81, 0xab, 0x09, 0xac, 0xb3, 0xb7, 0xbc, 0xc2, 0xc8, 0xcc, 0xcd, 0xc9, 0xae, 0x82, 0x00, 0x07, 0x11, 0x76, 0x9b, 0xb8, 0xc7, 0xcb, 0xc2, 0x25, 0x80, 0x00, 0x04, 0x60, 0xab, 0xb1, 0x6d, 0x15, 0x82, 0x00, 0x06, 0x07, 0x53, 0xa7, 0xb8, 0xc3, 0xcb, 0xce, 0x83, 0xd0, 0x09, 0xcf, 0xcd, 0xcb, 0xc6, 0xc0, 0x8d, 0x46, 0x29, 0x17, 0x04, 0x85, 0x00, 0x05, 0x46, 0x87, 0xab, 0xc2, 0xcc, 0xcf, 0x8f, 0xd0, 0x03, 0xcf, 0xcc, 0xc4, 0x46, 0x83, 0x00, 0x06, 0x11, 0x69, 0x8a, 0xa9, 0xbf, 0xca, 0xce, 0x89, 0xd0, 0x15, 0xce, 0xc8, 0xbd, 0xab, 0x99, 0x8a, 0x7e, 0x67, 0x4d, 0x2e, 0x19, 0x10, 0x09, 0x01, 0x00, 0x00, 0x32, 0x97, 0xb3, 0xc6, 0xcd, 0xcf, 0x86, 0xd0, 0x02, 0xce, 0xc9, 0x89, 0x81, 0x00, 0x01, 0x47, 0x22, 0x83, 0x00, 0x04, 0x47, 0xa3, 0xb4, 0xb2, 0x04, 0x8d, 0x00, 0x08, 0x04, 0x25, 0x69, 0xb4, 0xc0, 0xc9, 0xcc, 0xc7, 0x92, 0x8c, 0x00, 0x08, 0x0a, 0x2e, 0x82, 0xb6, 0xc2, 0xcb, 0xcc, 0xc7, 0x8d, 0x82, 0x00, 0x06, 0x21, 0x7a, 0x9f, 0xbb, 0xc8, 0xc7, 0x7d, 0x81, 0x00, 0x02, 0x1b, 0x6f, 0x1e, 0x86, 0x00, 0x05, 0x17, 0x98, 0xb4, 0xc2, 0xcb, 0xce, 0x80, 0xd0, 0x06, 0xcf, 0xce, 0xcc, 0xc6, 0xb1, 0x64, 0x1a, 0x8a, 0x00, 0x05, 0x5a, 0x8e, 0xaf, 0xc4, 0xcc, 0xcf, 0x8f, 0xd0, 0x03, 0xcf, 0xcb, 0xc0, 0x1d, 0x83, 0x00, 0x06, 0x37, 0x7a, 0x9b, 0xb6, 0xc6, 0xcd, 0xcf, 0x89, 0xd0, 0x15, 0xce, 0xcb, 0xc4, 0xbb, 0xb0, 0xa7, 0xa0, 0x9b, 0x95, 0x8e, 0x86, 0x7f, 0x6f, 0x50, 0x2e, 0x1a, 0x27, 0x99, 0xb3, 0xc5, 0xcc, 0xcf, 0x85, 0xd0, 0x03, 0xcf, 0xcd, 0xc4, 0x37, 0x89, 0x00, 0x03, 0x3a, 0x97, 0xad, 0x94, 0x90, 0x00, 0x06, 0x09, 0x98, 0xb4, 0xc3, 0xca, 0xc5, 0x70, 0x8e, 0x00, 0x06, 0x23, 0xa3, 0xb8, 0xc6, 0xcb, 0xc5, 0x6c, 0x82, 0x00, 0x06, 0x34, 0x82, 0xa5, 0xbf, 0xc7, 0xc2, 0x2b, 0x81, 0x00, 0x01, 0x01, 0x01, 0x88, 0x00, 0x0c, 0x35, 0x9f, 0xb6, 0xc6, 0xcc, 0xcf, 0xd0, 0xcf, 0xce, 0xca, 0xc3, 0x60, 0x04, 0x8b, 0x00, 0x05, 0x03, 0x6f, 0x94, 0xb4, 0xc6, 0xcd, 0x90, 0xd0, 0x03, 0xce, 0xc9, 0xa8, 0x03, 0x82, 0x00, 0x06, 0x01, 0x5a, 0x87, 0xa9, 0xc0, 0xcb, 0xcf, 0x8a, 0xd0, 0x15, 0xcf, 0xce, 0xcb, 0xc6, 0xc2, 0xbf, 0xbc, 0xb9, 0xb4, 0xaf, 0xa9, 0xa3, 0x9c, 0x96, 0x8f, 0x8d, 0x94, 0xa5, 0xb9, 0xc6, 0xcd, 0xcf, 0x85, 0xd0, 0x03, 0xcf, 0xcc, 0xc0, 0x13, 0x88, 0x00, 0x04, 0x04, 0x63, 0x95, 0xab, 0x74, 0x91, 0x00, 0x05, 0x71, 0xa8, 0xbf, 0xc7, 0xc2, 0x4f, 0x8e, 0x00, 0x06, 0x04, 0x91, 0xad, 0xc2, 0xc8, 0xc2, 0x4b, 0x82, 0x00, 0x06, 0x47, 0x88, 0xab, 0xc1, 0xc6, 0xbd, 0x08, 0x8f, 0x00, 0x09, 0x71, 0xa8, 0xbf, 0xca, 0xce, 0xcf, 0xce, 0xca, 0xbb, 0x3f, 0x8d, 0x00, 0x05, 0x11, 0x76, 0x9a, 0xb8, 0xc8, 0xce, 0x90, 0xd0, 0x02, 0xce, 0xc7, 0x7f, 0x83, 0x00, 0x06, 0x0d, 0x6f, 0x93, 0xb3, 0xc5, 0xcd, 0xcf, 0x8b, 0xd0, 0x13, 0xcf, 0xce, 0xcd, 0xcc, 0xcb, 0xca, 0xc8, 0xc6, 0xc3, 0xc0, 0xbb, 0xb5, 0xaf, 0xa9, 0xa5, 0xa9, 0xb4, 0xc0, 0xc9, 0xce, 0x86, 0xd0, 0x02, 0xce, 0xca, 0xb2, 0x87, 0x00, 0x06, 0x07, 0x22, 0x57, 0x85, 0x9e, 0xae, 0x56, 0x90, 0x00, 0x06, 0x09, 0x80, 0xa4, 0xbc, 0xc6, 0xc0, 0x31, 0x8e, 0x00, 0x06, 0x1e, 0x8a, 0xab, 0xc0, 0xc6, 0xc0, 0x2d, 0x82, 0x00, 0x05, 0x5d, 0x8e, 0xaf, 0xc2, 0xc6, 0xa2, 0x85, 0x00, 0x04, 0x12, 0x25, 0x35, 0x2e, 0x0d, 0x83, 0x00, 0x08, 0x48, 0x9a, 0xb6, 0xc6, 0xcd, 0xce, 0xca, 0xb2, 0x24, 0x87, 0x00, 0x01, 0x0a, 0x17, 0x82, 0x00, 0x05, 0x21, 0x7a, 0x9f, 0xbc, 0xca, 0xcf, 0x8f, 0xd0, 0x03, 0xcf, 0xcd, 0xc5, 0x73, 0x83, 0x00, 0x05, 0x1d, 0x76, 0x9b, 0xb9, 0xc8, 0xce, 0x8e, 0xd0, 0x81, 0xcf, 0x0d, 0xce, 0xcd, 0xcc, 0xc8, 0xc3, 0xb7, 0x7a, 0x76, 0xab, 0xb0, 0xb9, 0xc3, 0xcb, 0xce, 0x86, 0xd0, 0x02, 0xce, 0xc7, 0x8f, 0x83, 0x00, 0x0a, 0x14, 0x3c, 0x5c, 0x6c, 0x74, 0x7e, 0x8a, 0x9e, 0xae, 0xb4, 0x39, 0x8e, 0x00, 0x08, 0x0d, 0x24, 0x5a, 0x8d, 0xa9, 0xbf, 0xc5, 0xbd, 0x14, 0x8b, 0x00, 0x09, 0x01, 0x12, 0x2a, 0x6c, 0x93, 0xaf, 0xc2, 0xc6, 0xbc, 0x11, 0x81, 0x00, 0x06, 0x03, 0x6f, 0x95, 0xb4, 0xc4, 0xc4, 0x81, 0x83, 0x00, 0x07, 0x07, 0x3c, 0x69, 0x76, 0x7e, 0x80, 0x76, 0x19, 0x82, 0x00, 0x07, 0x2d, 0x8e, 0xaf, 0xc3, 0xcc, 0xcb, 0xc2, 0x32, 0x84, 0x00, 0x05, 0x0a, 0x34, 0x4c, 0x63, 0x6d, 0x5b, 0x82, 0x00, 0x05, 0x32, 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0x8f, 0xd0, 0x03, 0xcf, 0xcd, 0xc4, 0x6d, 0x83, 0x00, 0x05, 0x2b, 0x7e, 0xa1, 0xbd, 0xca, 0xcf, 0x93, 0xd0, 0x0d, 0xcf, 0xcc, 0xc6, 0x5a, 0x1d, 0x03, 0x04, 0x1e, 0x64, 0xaf, 0xbe, 0xc8, 0xcd, 0xcf, 0x85, 0xd0, 0x02, 0xcd, 0xc6, 0x6f, 0x82, 0x00, 0x0b, 0x12, 0x5b, 0x72, 0x84, 0x91, 0x99, 0xa1, 0xab, 0xb4, 0xbc, 0xb8, 0x1d, 0x81, 0x00, 0x04, 0x01, 0x44, 0x4f, 0x57, 0x5b, 0x83, 0x5d, 0x0a, 0x5f, 0x69, 0x76, 0x7f, 0x8d, 0xa1, 0xb5, 0xc3, 0xc6, 0xb0, 0x01, 0x81, 0x00, 0x04, 0x0e, 0x47, 0x50, 0x59, 0x5c, 0x81, 0x5d, 0x09, 0x5f, 0x6e, 0x77, 0x82, 0x91, 0xa6, 0xba, 0xc6, 0xc6, 0xad, 0x82, 0x00, 0x06, 0x12, 0x76, 0x9b, 0xb8, 0xc6, 0xc2, 0x60, 0x82, 0x00, 0x08, 0x03, 0x4a, 0x70, 0x86, 0x97, 0xa0, 0xa2, 0x9b, 0x5f, 0x82, 0x00, 0x06, 0x22, 0x88, 0xab, 0xc1, 0xc9, 0xc5, 0x5f, 0x83, 0x00, 0x07, 0x04, 0x30, 0x64, 0x76, 0x83, 0x8c, 0x8e, 0x5d, 0x82, 0x00, 0x05, 0x46, 0x88, 0xab, 0xc2, 0xcc, 0xcf, 0x8f, 0xd0, 0x03, 0xcf, 0xcc, 0xc3, 0x66, 0x83, 0x00, 0x05, 0x2d, 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0x93, 0xd0, 0x03, 0xce, 0xc9, 0x8d, 0x0a, 0x81, 0x00, 0x05, 0x11, 0x88, 0xb0, 0xc2, 0xcb, 0xcf, 0x84, 0xd0, 0x03, 0xcf, 0xcc, 0xc3, 0x4f, 0x82, 0x00, 0x0b, 0x3b, 0x73, 0x8e, 0xa3, 0xb0, 0xb7, 0xbc, 0xc1, 0xc5, 0xc4, 0xb5, 0x04, 0x81, 0x00, 0x05, 0x0d, 0x60, 0x77, 0x89, 0x91, 0x93, 0x82, 0x94, 0x09, 0x95, 0x97, 0x9b, 0xa1, 0xab, 0xb7, 0xc2, 0xc8, 0xc6, 0x8f, 0x82, 0x00, 0x05, 0x1e, 0x66, 0x7c, 0x8a, 0x91, 0x93, 0x80, 0x94, 0x09, 0x95, 0x98, 0x9c, 0xa4, 0xad, 0xba, 0xc4, 0xca, 0xc6, 0x8b, 0x82, 0x00, 0x06, 0x22, 0x7c, 0xa0, 0xbb, 0xc6, 0xc1, 0x40, 0x82, 0x00, 0x08, 0x30, 0x6e, 0x8a, 0xa2, 0xb3, 0xbb, 0xbb, 0xb3, 0x86, 0x82, 0x00, 0x06, 0x29, 0x85, 0xa8, 0xbf, 0xc5, 0x92, 0x01, 0x82, 0x00, 0x08, 0x15, 0x57, 0x72, 0x86, 0x98, 0xa5, 0xab, 0xab, 0x53, 0x82, 0x00, 0x05, 0x5b, 0x8e, 0xaf, 0xc4, 0xcc, 0xcf, 0x8f, 0xd0, 0x03, 0xcf, 0xcc, 0xc2, 0x69, 0x83, 0x00, 0x05, 0x27, 0x82, 0xa6, 0xc0, 0xcc, 0xcf, 0x92, 0xd0, 0x03, 0xcf, 0xcd, 0xc5, 0x2b, 0x83, 0x00, 0x04, 0x44, 0xa0, 0xba, 0xc8, 0xce, 0x84, 0xd0, 0x03, 0xcf, 0xcc, 0xc0, 0x31, 0x82, 0x00, 0x0a, 0x5d, 0x86, 0xa4, 0xb9, 0xc3, 0xc7, 0xca, 0xcc, 0xcc, 0xc6, 0x9a, 0x82, 0x00, 0x04, 0x1b, 0x71, 0x8f, 0xa5, 0xb0, 0x84, 0xb4, 0x08, 0xb6, 0xb9, 0xbc, 0xc1, 0xc6, 0xcb, 0xcc, 0xc5, 0x6e, 0x82, 0x00, 0x04, 0x32, 0x77, 0x95, 0xa8, 0xb1, 0x81, 0xb4, 0x09, 0xb5, 0xb6, 0xba, 0xbe, 0xc2, 0xc7, 0xcb, 0xcc, 0xc5, 0x6a, 0x82, 0x00, 0x06, 0x35, 0x82, 0xa5, 0xbf, 0xc6, 0xbf, 0x22, 0x81, 0x00, 0x09, 0x03, 0x5f, 0x82, 0xa0, 0xb7, 0xc3, 0xc8, 0xc7, 0xc0, 0x86, 0x82, 0x00, 0x05, 0x2f, 0x85, 0xa8, 0xbd, 0xc0, 0x35, 0x82, 0x00, 0x09, 0x08, 0x59, 0x77, 0x90, 0xa4, 0xb4, 0xbd, 0xc0, 0xb9, 0x3c, 0x81, 0x00, 0x05, 0x03, 0x6f, 0x94, 0xb4, 0xc6, 0xcd, 0x90, 0xd0, 0x03, 0xcf, 0xcc, 0xc3, 0x70, 0x83, 0x00, 0x05, 0x20, 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0x92, 0xd0, 0x03, 0xcf, 0xcc, 0xc0, 0x15, 0x83, 0x00, 0x04, 0x3f, 0x96, 0xb4, 0xc6, 0xcd, 0x84, 0xd0, 0x03, 0xcf, 0xcb, 0xbe, 0x15, 0x81, 0x00, 0x0b, 0x11, 0x70, 0x94, 0xb2, 0xc3, 0xcc, 0xce, 0xcf, 0xcf, 0xcc, 0xc6, 0x79, 0x82, 0x00, 0x04, 0x2e, 0x7e, 0x9e, 0xb7, 0xc2, 0x84, 0xc6, 0x08, 0xc7, 0xc8, 0xca, 0xcc, 0xcd, 0xce, 0xcc, 0xc2, 0x4d, 0x82, 0x00, 0x04, 0x48, 0x86, 0xa5, 0xbb, 0xc3, 0x82, 0xc6, 0x08, 0xc7, 0xc9, 0xca, 0xcc, 0xcd, 0xce, 0xcc, 0xc2, 0x4a, 0x82, 0x00, 0x06, 0x48, 0x89, 0xab, 0xc1, 0xc6, 0xbb, 0x07, 0x81, 0x00, 0x09, 0x1a, 0x71, 0x93, 0xb1, 0xc2, 0xcb, 0xcd, 0xcc, 0xc3, 0x77, 0x82, 0x00, 0x05, 0x3f, 0x88, 0xa9, 0xbb, 0xa2, 0x01, 0x81, 0x00, 0x0a, 0x01, 0x46, 0x76, 0x92, 0xab, 0xbb, 0xc4, 0xc9, 0xc7, 0xbd, 0x21, 0x81, 0x00, 0x05, 0x11, 0x76, 0x9b, 0xb8, 0xc8, 0xce, 0x90, 0xd0, 0x03, 0xcf, 0xcc, 0xc4, 0x79, 0x83, 0x00, 0x05, 0x18, 0x7e, 0xa2, 0xbd, 0xcb, 0xcf, 0x92, 0xd0, 0x03, 0xce, 0xc9, 0xb8, 0x0d, 0x83, 0x00, 0x04, 0x63, 0x93, 0xb3, 0xc6, 0xcd, 0x84, 0xd0, 0x03, 0xce, 0xc9, 0xb3, 0x01, 0x81, 0x00, 0x0b, 0x29, 0x7a, 0x9e, 0xba, 0xc8, 0xce, 0xd0, 0xd0, 0xcf, 0xcc, 0xc3, 0x57, 0x82, 0x00, 0x04, 0x41, 0x86, 0xa8, 0xc0, 0xca, 0x83, 0xcd, 0x80, 0xce, 0x81, 0xcf, 0x02, 0xcc, 0xc0, 0x2e, 0x82, 0x00, 0x04, 0x5f, 0x8e, 0xaf, 0xc2, 0xcb, 0x81, 0xcd, 0x80, 0xce, 0x06, 0xcf, 0xcf, 0xd0, 0xcf, 0xcc, 0xc0, 0x2b, 0x82, 0x00, 0x05, 0x5f, 0x8f, 0xb0, 0xc2, 0xc6, 0xa1, 0x82, 0x00, 0x09, 0x37, 0x7e, 0xa0, 0xbb, 0xc8, 0xce, 0xcf, 0xcc, 0xc3, 0x5d, 0x82, 0x00, 0x04, 0x52, 0x8c, 0xab, 0xba, 0x52, 0x82, 0x00, 0x0a, 0x22, 0x6d, 0x8b, 0xa8, 0xbc, 0xc7, 0xcc, 0xcd, 0xc9, 0xbb, 0x07, 0x81, 0x00, 0x05, 0x21, 0x7a, 0xa0, 0xbc, 0xca, 0xcf, 0x90, 0xd0, 0x04, 0xcf, 0xcd, 0xc5, 0x9b, 0x01, 0x82, 0x00, 0x05, 0x04, 0x6f, 0x9e, 0xba, 0xc9, 0xce, 0x92, 0xd0, 0x02, 0xcd, 0xc7, 0x8b, 0x83, 0x00, 0x05, 0x0a, 0x71, 0x96, 0xb4, 0xc6, 0xce, 0x84, 0xd0, 0x02, 0xce, 0xc7, 0x93, 0x82, 0x00, 0x0b, 0x42, 0x84, 0xa7, 0xc0, 0xcb, 0xcf, 0xd0, 0xd0, 0xcf, 0xcc, 0xc1, 0x38, 0x82, 0x00, 0x05, 0x56, 0x8d, 0xae, 0xc3, 0xcc, 0xcf, 0x88, 0xd0, 0x03, 0xcf, 0xcb, 0xbe, 0x11, 0x81, 0x00, 0x06, 0x04, 0x70, 0x95, 0xb4, 0xc6, 0xcd, 0xcf, 0x86, 0xd0, 0x03, 0xcf, 0xcb, 0xbd, 0x10, 0x81, 0x00, 0x06, 0x04, 0x70, 0x95, 0xb4, 0xc4, 0xc4, 0x7f, 0x82, 0x00, 0x09, 0x4d, 0x87, 0xa9, 0xc1, 0xcc, 0xcf, 0xcf, 0xcc, 0xc2, 0x40, 0x82, 0x00, 0x04, 0x67, 0x91, 0xae, 0xb7, 0x21, 0x82, 0x00, 0x09, 0x3f, 0x7c, 0x9e, 0xb7, 0xc6, 0xcc, 0xcf, 0xce, 0xc8, 0xa1, 0x82, 0x00, 0x05, 0x32, 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0x91, 0xd0, 0x03, 0xce, 0xc6, 0xb5, 0x17, 0x83, 0x00, 0x05, 0x44, 0x94, 0xb3, 0xc6, 0xcd, 0xcf, 0x90, 0xd0, 0x03, 0xcf, 0xcc, 0xc3, 0x53, 0x83, 0x00, 0x05, 0x17, 0x76, 0x9b, 0xb9, 0xc8, 0xce, 0x84, 0xd0, 0x02, 0xcd, 0xc6, 0x71, 0x82, 0x00, 0x0b, 0x59, 0x8c, 0xae, 0xc3, 0xcc, 0xcf, 0xd0, 0xd0, 0xcf, 0xcb, 0xbf, 0x1a, 0x81, 0x00, 0x05, 0x01, 0x6a, 0x93, 0xb3, 0xc6, 0xcd, 0x89, 0xd0, 0x02, 0xce, 0xc9, 0xaf, 0x82, 0x00, 0x05, 0x14, 0x76, 0x9b, 0xb9, 0xc8, 0xce, 0x87, 0xd0, 0x02, 0xce, 0xc9, 0xac, 0x82, 0x00, 0x06, 0x13, 0x76, 0x9b, 0xb8, 0xc6, 0xc2, 0x5f, 0x82, 0x00, 0x09, 0x63, 0x8f, 0xb1, 0xc4, 0xcd, 0xcf, 0xcf, 0xcb, 0xc0, 0x24, 0x81, 0x00, 0x05, 0x0a, 0x72, 0x97, 0xb2, 0xb5, 0x0a, 0x82, 0x00, 0x09, 0x5b, 0x89, 0xab, 0xc0, 0xcb, 0xcf, 0xcf, 0xce, 0xc6, 0x80, 0x82, 0x00, 0x05, 0x47, 0x88, 0xab, 0xc2, 0xcc, 0xcf, 0x91, 0xd0, 0x03, 0xce, 0xc9, 0xbb, 0x3a, 0x83, 0x00, 0x05, 0x1e, 0x89, 0xab, 0xc0, 0xcb, 0xcf, 0x90, 0xd0, 0x03, 0xce, 0xca, 0xb7, 0x14, 0x83, 0x00, 0x05, 0x25, 0x7e, 0xa2, 0xbd, 0xcb, 0xcf, 0x83, 0xd0, 0x03, 0xcf, 0xcc, 0xc3, 0x52, 0x81, 0x00, 0x05, 0x03, 0x6d, 0x93, 0xb4, 0xc6, 0xcd, 0x80, 0xd0, 0x03, 0xce, 0xca, 0xb7, 0x03, 0x81, 0x00, 0x05, 0x0d, 0x73, 0x99, 0xb7, 0xc8, 0xce, 0x89, 0xd0, 0x02, 0xce, 0xc7, 0x8c, 0x82, 0x00, 0x05, 0x24, 0x7c, 0xa1, 0xbc, 0xca, 0xcf, 0x87, 0xd0, 0x02, 0xce, 0xc7, 0x8a, 0x82, 0x00, 0x06, 0x24, 0x7c, 0xa0, 0xbb, 0xc6, 0xc1, 0x3f, 0x81, 0x00, 0x0a, 0x07, 0x71, 0x97, 0xb5, 0xc7, 0xce, 0xd0, 0xcf, 0xca, 0xbc, 0x09, 0x81, 0x00, 0x04, 0x19, 0x79, 0x9c, 0xb4, 0xa5, 0x82, 0x00, 0x0a, 0x08, 0x6d, 0x92, 0xb2, 0xc5, 0xcd, 0xcf, 0xcf, 0xcd, 0xc4, 0x5f, 0x82, 0x00, 0x05, 0x5c, 0x8e, 0xb0, 0xc4, 0xcc, 0xcf, 0x91, 0xd0, 0x03, 0xcf, 0xcb, 0xc0, 0x6e, 0x83, 0x00, 0x06, 0x01, 0x58, 0x9e, 0xb8, 0xc6, 0xcd, 0xcf, 0x8e, 0xd0, 0x03, 0xcf, 0xcc, 0xc5, 0x69, 0x84, 0x00, 0x05, 0x42, 0x86, 0xa9, 0xc1, 0xcc, 0xcf, 0x83, 0xd0, 0x03, 0xcf, 0xcc, 0xc1, 0x34, 0x81, 0x00, 0x05, 0x11, 0x76, 0x9a, 0xb8, 0xc8, 0xce, 0x80, 0xd0, 0x02, 0xce, 0xc8, 0x98, 0x82, 0x00, 0x05, 0x1d, 0x7a, 0x9e, 0xbb, 0xc8, 0xcd, 0x86, 0xcf, 0x80, 0xd0, 0x02, 0xcd, 0xc5, 0x6a, 0x82, 0x00, 0x05, 0x37, 0x82, 0xa6, 0xc0, 0xcc, 0xcf, 0x86, 0xd0, 0x03, 0xcf, 0xcd, 0xc5, 0x69, 0x82, 0x00, 0x06, 0x35, 0x82, 0xa6, 0xbf, 0xc6, 0xbf, 0x21, 0x81, 0x00, 0x09, 0x18, 0x77, 0x9c, 0xba, 0xc9, 0xce, 0xd0, 0xce, 0xc8, 0xa5, 0x82, 0x00, 0x04, 0x2a, 0x7e, 0xa1, 0xb6, 0x95, 0x82, 0x00, 0x0a, 0x06, 0x70, 0x95, 0xb4, 0xc6, 0xcd, 0xcf, 0xce, 0xcc, 0xc1, 0x40, 0x81, 0x00, 0x05, 0x03, 0x6f, 0x95, 0xb4, 0xc6, 0xcd, 0x92, 0xd0, 0x04, 0xcf, 0xcc, 0xc3, 0xab, 0x10, 0x83, 0x00, 0x05, 0x17, 0x8b, 0xab, 0xc0, 0xca, 0xce, 0x8e, 0xd0, 0x03, 0xce, 0xc9, 0xa9, 0x12, 0x83, 0x00, 0x06, 0x0b, 0x6d, 0x91, 0xb1, 0xc4, 0xcd, 0xcf, 0x83, 0xd0, 0x03, 0xcf, 0xcb, 0xbe, 0x18, 0x81, 0x00, 0x05, 0x21, 0x7a, 0x9f, 0xbc, 0xca, 0xce, 0x80, 0xd0, 0x02, 0xcd, 0xc6, 0x76, 0x82, 0x00, 0x05, 0x2d, 0x7d, 0x9f, 0xba, 0xc6, 0xca, 0x83, 0xcb, 0x08, 0xcc, 0xcc, 0xcd, 0xce, 0xcf, 0xcf, 0xcc, 0xc2, 0x4a, 0x82, 0x00, 0x05, 0x4a, 0x89, 0xab, 0xc2, 0xcc, 0xcf, 0x86, 0xd0, 0x03, 0xcf, 0xcc, 0xc2, 0x49, 0x82, 0x00, 0x06, 0x4a, 0x89, 0xab, 0xc1, 0xc6, 0xbb, 0x07, 0x81, 0x00, 0x09, 0x28, 0x7e, 0xa2, 0xbd, 0xcb, 0xcf, 0xd0, 0xce, 0xc6, 0x84, 0x82, 0x00, 0x05, 0x3e, 0x85, 0xa7, 0xb9, 0xb1, 0x04, 0x82, 0x00, 0x09, 0x5c, 0x91, 0xb0, 0xc2, 0xc9, 0xcc, 0xcc, 0xc7, 0xbc, 0x23, 0x81, 0x00, 0x05, 0x11, 0x76, 0x9b, 0xb8, 0xc8, 0xce, 0x93, 0xd0, 0x03, 0xcd, 0xc7, 0xb8, 0x42, 0x84, 0x00, 0x05, 0x3c, 0x99, 0xb3, 0xc3, 0xcb, 0xce, 0x8b, 0xd0, 0x04, 0xcf, 0xce, 0xcb, 0xc2, 0x3f, 0x84, 0x00, 0x05, 0x2a, 0x7a, 0x9c, 0xb9, 0xc8, 0xce, 0x84, 0xd0, 0x03, 0xce, 0xc9, 0xb4, 0x01, 0x81, 0x00, 0x0b, 0x32, 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0xd0, 0xd0, 0xcf, 0xcc, 0xc3, 0x55, 0x82, 0x00, 0x05, 0x3c, 0x7c, 0x9b, 0xb1, 0xbb, 0xbe, 0x82, 0xbf, 0x09, 0xc0, 0xc0, 0xc2, 0xc6, 0xca, 0xcd, 0xce, 0xcc, 0xc0, 0x2b, 0x82, 0x00, 0x05, 0x60, 0x8f, 0xb1, 0xc4, 0xcd, 0xcf, 0x86, 0xd0, 0x03, 0xcf, 0xcc, 0xc0, 0x2a, 0x82, 0x00, 0x05, 0x60, 0x8f, 0xb0, 0xc3, 0xc6, 0xa0, 0x82, 0x00, 0x09, 0x3b, 0x84, 0xa8, 0xc0, 0xcc, 0xcf, 0xcf, 0xcd, 0xc5, 0x64, 0x82, 0x00, 0x05, 0x52, 0x8b, 0xab, 0xbc, 0xb6, 0x24, 0x82, 0x00, 0x09, 0x10, 0x76, 0xa0, 0xb4, 0xbd, 0xc1, 0xc2, 0xbe, 0xb3, 0x08, 0x81, 0x00, 0x05, 0x21, 0x7a, 0xa0, 0xbc, 0xca, 0xcf, 0x93, 0xd0, 0x04, 0xcf, 0xcb, 0xc0, 0x97, 0x0a, 0x83, 0x00, 0x07, 0x01, 0x4f, 0xa0, 0xb6, 0xc4, 0xcb, 0xce, 0xcf, 0x88, 0xd0, 0x05, 0xcf, 0xce, 0xcb, 0xc2, 0x5d, 0x01, 0x83, 0x00, 0x06, 0x07, 0x5d, 0x89, 0xa9, 0xc0, 0xcb, 0xcf, 0x84, 0xd0, 0x02, 0xce, 0xc7, 0x96, 0x82, 0x00, 0x0b, 0x47, 0x88, 0xab, 0xc2, 0xcc, 0xcf, 0xd0, 0xd0, 0xcf, 0xcc, 0xc1, 0x37, 0x82, 0x00, 0x04, 0x17, 0x28, 0x2f, 0x35, 0x37, 0x83, 0x38, 0x09, 0x39, 0x52, 0x81, 0xb3, 0xc0, 0xc7, 0xcc, 0xca, 0xbd, 0x0e, 0x81, 0x00, 0x05, 0x04, 0x71, 0x96, 0xb5, 0xc6, 0xce, 0x87, 0xd0, 0x03, 0xcf, 0xcb, 0xbd, 0x0e, 0x81, 0x00, 0x06, 0x04, 0x71, 0x96, 0xb4, 0xc5, 0xc4, 0x7e, 0x82, 0x00, 0x09, 0x4f, 0x8a, 0xac, 0xc2, 0xcc, 0xcf, 0xcf, 0xcc, 0xc2, 0x46, 0x82, 0x00, 0x05, 0x69, 0x92, 0xb1, 0xc0, 0xbb, 0x48, 0x83, 0x00, 0x07, 0x01, 0x25, 0x4d, 0x5f, 0x6d, 0x6d, 0x66, 0x53, 0x82, 0x00, 0x05, 0x34, 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0x93, 0xd0, 0x04, 0xcf, 0xcd, 0xc5, 0xb4, 0x4d, 0x84, 0x00, 0x08, 0x04, 0x59, 0xa2, 0xb6, 0xc2, 0xca, 0xcd, 0xcf, 0xcf, 0x84, 0xd0, 0x06, 0xcf, 0xce, 0xcd, 0xc9, 0xc2, 0x60, 0x01, 0x84, 0x00, 0x06, 0x31, 0x77, 0x99, 0xb4, 0xc6, 0xcd, 0xcf, 0x84, 0xd0, 0x02, 0xcd, 0xc6, 0x76, 0x82, 0x00, 0x0b, 0x5d, 0x8e, 0xb0, 0xc4, 0xcc, 0xcf, 0xd0, 0xd0, 0xcf, 0xcb, 0xbf, 0x19, 0x90, 0x00, 0x05, 0x59, 0xae, 0xbf, 0xc8, 0xc7, 0xab, 0x82, 0x00, 0x05, 0x15, 0x76, 0x9c, 0xba, 0xc8, 0xce, 0x87, 0xd0, 0x02, 0xce, 0xc9, 0xab, 0x82, 0x00, 0x06, 0x15, 0x76, 0x9c, 0xb9, 0xc6, 0xc3, 0x5d, 0x82, 0x00, 0x09, 0x66, 0x91, 0xb2, 0xc5, 0xcd, 0xcf, 0xcf, 0xcc, 0xc0, 0x29, 0x81, 0x00, 0x06, 0x0a, 0x73, 0x98, 0xb5, 0xc3, 0xc0, 0x7c, 0x90, 0x00, 0x05, 0x48, 0x88, 0xab, 0xc2, 0xcc, 0xcf, 0x94, 0xd0, 0x04, 0xce, 0xca, 0xbf, 0x9f, 0x19, 0x84, 0x00, 0x08, 0x01, 0x3e, 0x9c, 0xb3, 0xbf, 0xc6, 0xcb, 0xcd, 0xce, 0x82, 0xcf, 0x06, 0xce, 0xcc, 0xca, 0xc6, 0xb1, 0x42, 0x01, 0x84, 0x00, 0x06, 0x10, 0x67, 0x8a, 0xa9, 0xbf, 0xca, 0xce, 0x84, 0xd0, 0x03, 0xcf, 0xcc, 0xc4, 0x56, 0x81, 0x00, 0x05, 0x04, 0x71, 0x96, 0xb5, 0xc6, 0xcd, 0x80, 0xd0, 0x03, 0xcf, 0xca, 0xbd, 0x07, 0x90, 0x00, 0x05, 0x18, 0x9b, 0xb4, 0xc3, 0xc5, 0x8c, 0x82, 0x00, 0x05, 0x28, 0x7f, 0xa3, 0xbe, 0xca, 0xcf, 0x87, 0xd0, 0x02, 0xce, 0xc8, 0x8c, 0x82, 0x00, 0x06, 0x29, 0x7f, 0xa3, 0xbd, 0xc6, 0xc2, 0x3f, 0x81, 0x00, 0x0a, 0x09, 0x73, 0x98, 0xb7, 0xc7, 0xce, 0xd0, 0xcf, 0xcb, 0xbe, 0x0e, 0x81, 0x00, 0x07, 0x1a, 0x7a, 0x9e, 0xbb, 0xc6, 0xc3, 0xb3, 0x2f, 0x8f, 0x00, 0x05, 0x5d, 0x8f, 0xb1, 0xc4, 0xcd, 0xcf, 0x94, 0xd0, 0x05, 0xcf, 0xcc, 0xc6, 0xb6, 0x83, 0x0e, 0x85, 0x00, 0x07, 0x1e, 0x66, 0xa9, 0xb6, 0xc0, 0xc5, 0xc8, 0xca, 0x80, 0xcb, 0x05, 0xca, 0xc7, 0xc4, 0xbe, 0x77, 0x19, 0x85, 0x00, 0x07, 0x04, 0x4e, 0x7e, 0x9e, 0xb6, 0xc6, 0xcd, 0xcf, 0x84, 0xd0, 0x03, 0xcf, 0xcc, 0xc3, 0x48, 0x81, 0x00, 0x05, 0x25, 0x7a, 0x9e, 0xbb, 0xc9, 0xce, 0x80, 0xd0, 0x03, 0xcf, 0xca, 0xbd, 0x0e, 0x90, 0x00, 0x05, 0x21, 0x8f, 0xad, 0xc1, 0xc3, 0x85, 0x82, 0x00, 0x05, 0x54, 0x89, 0xab, 0xc1, 0xcc, 0xcf, 0x87, 0xd0, 0x02, 0xce, 0xc7, 0x82, 0x82, 0x00, 0x06, 0x55, 0x89, 0xab, 0xc1, 0xc7, 0xc1, 0x37, 0x81, 0x00, 0x0a, 0x2b, 0x7e, 0xa0, 0xbc, 0xca, 0xcf, 0xd0, 0xcf, 0xcb, 0xbd, 0x08, 0x81, 0x00, 0x08, 0x3f, 0x84, 0xa7, 0xbf, 0xc9, 0xc8, 0xbd, 0x99, 0x1d, 0x8d, 0x00, 0x05, 0x0e, 0x74, 0x98, 0xb6, 0xc6, 0xce, 0x96, 0xd0, 0x05, 0xce, 0xcb, 0xc2, 0xb0, 0x73, 0x08, 0x86, 0x00, 0x0c, 0x1a, 0x57, 0x99, 0xb3, 0xb8, 0xbc, 0xbe, 0xbf, 0xbe, 0xbc, 0x97, 0x63, 0x1d, 0x87, 0x00, 0x06, 0x37, 0x76, 0x93, 0xae, 0xc1, 0xcb, 0xcf, 0x85, 0xd0, 0x03, 0xcf, 0xcc, 0xc3, 0x7c, 0x81, 0x00, 0x05, 0x58, 0x89, 0xa9, 0xc0, 0xcb, 0xcf, 0x80, 0xd0, 0x03, 0xcf, 0xcb, 0xbf, 0x48, 0x8f, 0x00, 0x07, 0x03, 0x5b, 0x91, 0xae, 0xc1, 0xc4, 0xb4, 0x0a, 0x80, 0x00, 0x05, 0x15, 0x76, 0x96, 0xb3, 0xc5, 0xcd, 0x88, 0xd0, 0x03, 0xce, 0xc7, 0xb0, 0x07, 0x80, 0x00, 0x07, 0x17, 0x76, 0x96, 0xb3, 0xc5, 0xc9, 0xc2, 0x6d, 0x80, 0x00, 0x0b, 0x01, 0x5f, 0x8b, 0xab, 0xc1, 0xcc, 0xcf, 0xd0, 0xcf, 0xcb, 0xbf, 0x3f, 0x80, 0x00, 0x0b, 0x09, 0x70, 0x92, 0xb0, 0xc3, 0xcc, 0xcc, 0xc5, 0xb4, 0x98, 0x3f, 0x0d, 0x8b, 0x00, 0x05, 0x40, 0x83, 0xa4, 0xbd, 0xca, 0xcf, 0x97, 0xd0, 0x05, 0xce, 0xc9, 0xbe, 0xab, 0x63, 0x04, 0x87, 0x00, 0x07, 0x03, 0x13, 0x28, 0x3f, 0x44, 0x3e, 0x35, 0x18, 0x89, 0x00, 0x06, 0x29, 0x70, 0x8c, 0xa8, 0xbd, 0xc8, 0xcd, 0x86, 0xd0, 0x0d, 0xcf, 0xcd, 0xc6, 0xb3, 0x4a, 0x11, 0x1e, 0x4c, 0x81, 0x9b, 0xb4, 0xc6, 0xcd, 0xcf, 0x80, 0xd0, 0x07, 0xcf, 0xcc, 0xc3, 0xaf, 0x63, 0x3c, 0x21, 0x11, 0x89, 0x0e, 0x12, 0x17, 0x29, 0x5f, 0x83, 0x9e, 0xb6, 0xc5, 0xc7, 0xbd, 0x76, 0x2b, 0x0d, 0x1e, 0x62, 0x8a, 0xa6, 0xbd, 0xc9, 0xce, 0x88, 0xd0, 0x32, 0xce, 0xc9, 0xbd, 0x6e, 0x24, 0x0d, 0x21, 0x63, 0x8a, 0xa6, 0xbd, 0xc9, 0xcc, 0xc5, 0xab, 0x46, 0x0e, 0x21, 0x4f, 0x82, 0x9e, 0xb6, 0xc6, 0xcd, 0xd0, 0xd0, 0xcf, 0xcc, 0xc2, 0x9a, 0x3f, 0x13, 0x2b, 0x5c, 0x87, 0xa3, 0xbb, 0xc8, 0xcd, 0xce, 0xcb, 0xc2, 0xb4, 0xa0, 0x8c, 0x60, 0x35, 0x28, 0x1e, 0x19, 0x13, 0x83, 0x0e, 0x07, 0x1d, 0x44, 0x7a, 0x96, 0xb1, 0xc3, 0xcc, 0xcf, 0x97, 0xd0, 0x06, 0xcf, 0xcd, 0xc7, 0xbb, 0xa8, 0x55, 0x01, 0x99, 0x00, 0x07, 0x2a, 0x6d, 0x88, 0xa3, 0xb9, 0xc6, 0xcc, 0xcf, 0x87, 0xd0, 0x0b, 0xce, 0xca, 0xbf, 0xac, 0x99, 0x8d, 0x8e, 0x9b, 0xaf, 0xc0, 0xca, 0xce, 0x82, 0xd0, 0x07, 0xce, 0xc8, 0xbd, 0xab, 0x9a, 0x8b, 0x82, 0x7e, 0x88, 0x7a, 0x12, 0x7d, 0x82, 0x8e, 0x9e, 0xb2, 0xc1, 0xca, 0xcb, 0xc3, 0xb4, 0x9f, 0x8e, 0x89, 0x90, 0xa2, 0xb6, 0xc5, 0xcc, 0xcf, 0x88, 0xd0, 0x17, 0xcf, 0xcc, 0xc3, 0xb3, 0x9e, 0x8e, 0x88, 0x90, 0xa2, 0xb6, 0xc5, 0xcc, 0xcd, 0xc9, 0xbe, 0xab, 0x98, 0x8c, 0x8e, 0x9e, 0xb1, 0xc1, 0xcb, 0xce, 0x80, 0xd0, 0x18, 0xcd, 0xc7, 0xbb, 0xa7, 0x95, 0x8d, 0x92, 0xa0, 0xb4, 0xc3, 0xcc, 0xcf, 0xcf, 0xce, 0xca, 0xc3, 0xb9, 0xab, 0x9e, 0x93, 0x8a, 0x85, 0x81, 0x7e, 0x7c, 0x82, 0x7a, 0x06, 0x7f, 0x89, 0x98, 0xab, 0xbe, 0xc9, 0xce, 0x99, 0xd0, 0x06, 0xcf, 0xcc, 0xc6, 0xba, 0xa5, 0x4f, 0x08, 0x96, 0x00, 0x08, 0x03, 0x2f, 0x69, 0x85, 0xa0, 0xb6, 0xc4, 0xcc, 0xcf, 0x88, 0xd0, 0x0b, 0xcf, 0xcd, 0xc7, 0xbe, 0xb3, 0xab, 0xac, 0xb4, 0xc0, 0xc8, 0xcd, 0xcf, 0x82, 0xd0, 0x08, 0xcf, 0xcc, 0xc7, 0xbf, 0xb4, 0xab, 0xa6, 0xa2, 0xa0, 0x86, 0x9e, 0x12, 0x9f, 0xa1, 0xa5, 0xac, 0xb7, 0xc2, 0xc9, 0xcd, 0xcd, 0xca, 0xc2, 0xb6, 0xac, 0xa9, 0xae, 0xb8, 0xc3, 0xcb, 0xce, 0x89, 0xd0, 0x17, 0xcf, 0xce, 0xca, 0xc1, 0xb5, 0xac, 0xa9, 0xae, 0xb8, 0xc3, 0xcb, 0xce, 0xcf, 0xcc, 0xc6, 0xbd, 0xb3, 0xab, 0xad, 0xb5, 0xc0, 0xc9, 0xcd, 0xcf, 0x80, 0xd0, 0x19, 0xcf, 0xcc, 0xc5, 0xbb, 0xb1, 0xab, 0xaf, 0xb8, 0xc2, 0xca, 0xce, 0xd0, 0xd0, 0xcf, 0xce, 0xcc, 0xc6, 0xc1, 0xba, 0xb3, 0xac, 0xa8, 0xa4, 0xa3, 0xa1, 0x9f, 0x80, 0x9e, 0x07, 0xa0, 0xa4, 0xa9, 0xb3, 0xbf, 0xc7, 0xcc, 0xcf, 0x9a, 0xd0, 0x07, 0xcf, 0xcc, 0xc6, 0xb9, 0xa5, 0x7a, 0x29, 0x01, 0x93, 0x00, 0x08, 0x04, 0x0b, 0x5d, 0x7a, 0x9a, 0xb3, 0xc3, 0xcb, 0xce, 0x8a, 0xd0, 0x09, 0xcf, 0xcc, 0xc9, 0xc4, 0xc2, 0xc2, 0xc6, 0xca, 0xcd, 0xcf, 0x84, 0xd0, 0x08, 0xcf, 0xcc, 0xca, 0xc6, 0xc2, 0xc0, 0xbd, 0xbc, 0xbc, 0x84, 0xbb, 0x13, 0xbc, 0xbc, 0xbd, 0xbf, 0xc2, 0xc6, 0xcb, 0xcd, 0xcf, 0xcf, 0xcd, 0xcb, 0xc6, 0xc2, 0xc1, 0xc2, 0xc6, 0xcb, 0xce, 0xcf, 0x8a, 0xd0, 0x15, 0xcf, 0xcd, 0xca, 0xc6, 0xc2, 0xc0, 0xc2, 0xc6, 0xcb, 0xce, 0xcf, 0xd0, 0xcf, 0xcc, 0xc8, 0xc4, 0xc2, 0xc2, 0xc6, 0xca, 0xcd, 0xcf, 0x81, 0xd0, 0x0a, 0xcf, 0xce, 0xcc, 0xc7, 0xc3, 0xc2, 0xc3, 0xc6, 0xcb, 0xce, 0xcf, 0x81, 0xd0, 0x09, 0xcf, 0xcd, 0xcc, 0xc8, 0xc5, 0xc2, 0xc0, 0xbf, 0xbe, 0xbd, 0x82, 0xbc, 0x05, 0xbe, 0xc1, 0xc5, 0xc9, 0xcd, 0xcf, 0x9c, 0xd0, 0x07, 0xcf, 0xcc, 0xc5, 0xba, 0xab, 0x96, 0x5a, 0x15, 0x90, 0x00, 0x0a, 0x01, 0x03, 0x00, 0x01, 0x31, 0x84, 0xa4, 0xbc, 0xc8, 0xcd, 0xcf, 0x8b, 0xd0, 0x09, 0xcf, 0xce, 0xcc, 0xcc, 0xca, 0xcb, 0xcc, 0xcc, 0xce, 0xcf, 0x99, 0xd0, 0x0d, 0xcf, 0xce, 0xcd, 0xcd, 0xce, 0xcf, 0xd0, 0xd0, 0xcf, 0xce, 0xcd, 0xcd, 0xce, 0xcf, 0xe8, 0xd0, 0x08, 0xcf, 0xcc, 0xc6, 0xbf, 0xb2, 0xa1, 0x8a, 0x3f, 0x0a, 0x8c, 0x00, 0x01, 0x04, 0x04, 0x81, 0x00, 0x05, 0x0d, 0x76, 0xa1, 0xbb, 0xc8, 0xce, 0x8b, 0xd0, 0x0b, 0xcf, 0xce, 0xca, 0xc5, 0xc0, 0xbe, 0xbe, 0xc0, 0xc5, 0xca, 0xcd, 0xcf, 0x8f, 0xd0, 0x01, 0xcf, 0xcf, 0x83, 0xd0, 0x0f, 0xcf, 0xcd, 0xcb, 0xc7, 0xc6, 0xc9, 0xcc, 0xce, 0xce, 0xcc, 0xc9, 0xc6, 0xc6, 0xca, 0xcd, 0xcf, 0xc7, 0xd0, 0x00, 0xcf, 0x9d, 0xd0, 0x0a, 0xcf, 0xcc, 0xc9, 0xc3, 0xba, 0xab, 0x9b, 0x86, 0x50, 0x29, 0x0b, 0x85, 0x00, 0x03, 0x03, 0x11, 0x22, 0x0e, 0x84, 0x00, 0x05, 0x25, 0x94, 0xb2, 0xc3, 0xcc, 0xcf, 0x8a, 0xd0, 0x0c, 0xce, 0xcb, 0xda, 0xfd, 0xfd, 0xfb, 0xef, 0xc9, 0xb4, 0xc0, 0xc8, 0xcd, 0xcf, 0x8c, 0xd0, 0x05, 0xcf, 0xce, 0xcd, 0xcd, 0xce, 0xcf, 0x81, 0xd0, 0x0f, 0xce, 0xca, 0xd9, 0xfc, 0xbc, 0xbf, 0xc6, 0xcc, 0xcc, 0xc7, 0xf4, 0xe9, 0xba, 0xc1, 0xc9, 0xce, 0xc4, 0xd0, 0x06, 0xcf, 0xcf, 0xce, 0xcd, 0xce, 0xcf, 0xcf, 0x9b, 0xd0, 0x0c, 0xcf, 0xce, 0xcc, 0xc7, 0xc0, 0xb6, 0xab, 0x9c, 0x8f, 0x84, 0x6d, 0x52, 0x3f, 0x80, 0x3a, 0x06, 0x3c, 0x4a, 0x66, 0x72, 0x76, 0x4f, 0x06, 0x83, 0x00, 0x05, 0x08, 0x66, 0xa3, 0xbb, 0xc8, 0xce, 0x89, 0xd0, 0x0d, 0xcf, 0xcd, 0xc6, 0xde, 0xff, 0xf5, 0xf8, 0xff, 0xff, 0xb7, 0xb1, 0xc1, 0xca, 0xce, 0x8b, 0xd0, 0x1b, 0xcf, 0xcc, 0xca, 0xc7, 0xc7, 0xcb, 0xcd, 0xcf, 0xd0, 0xd0, 0xcf, 0xcc, 0xc4, 0xee, 0xff, 0xbf, 0xaf, 0xbe, 0xc7, 0xc6, 0xd3, 0xff, 0xf0, 0xa6, 0xb5, 0xc4, 0xcc, 0xcf, 0xc2, 0xd0, 0x08, 0xcf, 0xce, 0xcc, 0xc9, 0xc7, 0xc8, 0xcc, 0xce, 0xcf, 0x9c, 0xd0, 0x0b, 0xcf, 0xcd, 0xcb, 0xc6, 0xc0, 0xb8, 0xaf, 0xa7, 0x9e, 0x98, 0x91, 0x8d, 0x80, 0x8a, 0x05, 0x8d, 0x92, 0x97, 0x98, 0x92, 0x25, 0x84, 0x00, 0x05, 0x19, 0x90, 0xad, 0xc1, 0xcb, 0xcf, 0x88, 0xd0, 0x0d, 0xcf, 0xcc, 0xc3, 0xe2, 0xff, 0x9d, 0x81, 0xc1, 0xff, 0xd0, 0xa2, 0xb8, 0xc6, 0xcd, 0x81, 0xcf, 0x83, 0xd0, 0x81, 0xcf, 0x1c, 0xcc, 0xc9, 0xf3, 0xe1, 0xbd, 0xc3, 0xcb, 0xce, 0xd0, 0xd0, 0xce, 0xc9, 0xc6, 0xff, 0xff, 0xcb, 0x9e, 0xb4, 0xc1, 0xc0, 0xf0, 0xff, 0xfb, 0x93, 0xa9, 0xbf, 0xcb, 0xcf, 0xd0, 0x82, 0xcf, 0x80, 0xd0, 0x81, 0xcf, 0x83, 0xd0, 0x82, 0xcf, 0x82, 0xd0, 0x82, 0xcf, 0x81, 0xd0, 0x80, 0xcf, 0x81, 0xd0, 0x85, 0xcf, 0x82, 0xd0, 0x80, 0xcf, 0x81, 0xd0, 0x81, 0xcf, 0x08, 0xce, 0xcc, 0xd4, 0xf3, 0xd3, 0xbf, 0xc6, 0xcc, 0xcf, 0x9d, 0xd0, 0x14, 0xcf, 0xcf, 0xcd, 0xcb, 0xc7, 0xc3, 0xc0, 0xbb, 0xb5, 0xb2, 0xae, 0xac, 0xab, 0xac, 0xaf, 0xb3, 0xb5, 0xb5, 0xae, 0x88, 0x0e, 0x83, 0x00, 0x06, 0x03, 0x48, 0x9e, 0xb7, 0xc6, 0xcd, 0xcf, 0x87, 0xd0, 0x0c, 0xcf, 0xcb, 0xc0, 0xeb, 0xff, 0x8a, 0x7f, 0xa1, 0xff, 0xd2, 0x99, 0xb2, 0xc3, 0x81, 0xcc, 0x01, 0xcd, 0xce, 0x80, 0xcf, 0x01, 0xce, 0xcd, 0x81, 0xcc, 0x13, 0xc9, 0xca, 0xff, 0xdc, 0xac, 0xba, 0xc6, 0xcc, 0xcf, 0xcf, 0xcd, 0xc5, 0xda, 0xff, 0xff, 0xe2, 0x8f, 0xa9, 0xb9, 0xca, 0x80, 0xff, 0x03, 0x91, 0xa0, 0xbb, 0xc8, 0x80, 0xcd, 0x01, 0xcc, 0xcc, 0x80, 0xcd, 0x0b, 0xce, 0xce, 0xcd, 0xcd, 0xcc, 0xcc, 0xcd, 0xce, 0xcf, 0xcf, 0xce, 0xcd, 0x80, 0xcc, 0x06, 0xcd, 0xcd, 0xce, 0xce, 0xcf, 0xce, 0xcd, 0x80, 0xcc, 0x01, 0xcd, 0xcd, 0x80, 0xce, 0x03, 0xcd, 0xcc, 0xcc, 0xcd, 0x81, 0xce, 0x00, 0xcd, 0x83, 0xcc, 0x08, 0xcd, 0xcd, 0xce, 0xcf, 0xce, 0xce, 0xcd, 0xcc, 0xcd, 0x80, 0xce, 0x01, 0xcd, 0xcd, 0x81, 0xcc, 0x08, 0xc6, 0xd9, 0xff, 0xc5, 0xb1, 0xbe, 0xc8, 0xcd, 0xcf, 0x9e, 0xd0, 0x08, 0xcf, 0xcf, 0xce, 0xcc, 0xcb, 0xc9, 0xc7, 0xc5, 0xc3, 0x80, 0xc2, 0x06, 0xc3, 0xc5, 0xc6, 0xc6, 0xc0, 0xaf, 0x3f, 0x84, 0x00, 0x05, 0x11, 0x85, 0xa9, 0xbf, 0xca, 0xce, 0x87, 0xd0, 0x65, 0xcf, 0xcb, 0xbf, 0xf4, 0xf9, 0x81, 0x84, 0xd2, 0xff, 0xb5, 0x97, 0xaf, 0xc0, 0xc7, 0xc6, 0xc4, 0xc4, 0xc6, 0xc9, 0xcc, 0xcd, 0xcc, 0xcb, 0xc7, 0xc5, 0xc3, 0xc5, 0xc6, 0xc2, 0xcb, 0xff, 0xc8, 0x9e, 0xaf, 0xc0, 0xcb, 0xce, 0xcf, 0xcb, 0xc0, 0xf5, 0xf9, 0xf0, 0xfc, 0x8a, 0x9f, 0xb0, 0xe9, 0xff, 0xea, 0xff, 0x9a, 0x9a, 0xb5, 0xc5, 0xc9, 0xc7, 0xc5, 0xc4, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc8, 0xc6, 0xc5, 0xc4, 0xc5, 0xc6, 0xc9, 0xcc, 0xcc, 0xca, 0xc7, 0xc5, 0xc4, 0xc4, 0xc5, 0xc6, 0xc8, 0xca, 0xcb, 0xca, 0xc6, 0xc5, 0xc4, 0xc4, 0xc5, 0xc6, 0xc7, 0xc9, 0xc9, 0xc6, 0xc5, 0xc4, 0xc6, 0xc8, 0xcb, 0xca, 0xc8, 0xc5, 0x80, 0xc3, 0x1d, 0xc4, 0xc5, 0xc4, 0xc5, 0xc7, 0xca, 0xcc, 0xca, 0xc7, 0xc5, 0xc4, 0xc5, 0xc8, 0xca, 0xca, 0xc7, 0xc6, 0xc4, 0xc4, 0xc5, 0xc4, 0xbf, 0xdb, 0xff, 0xac, 0xa2, 0xb4, 0xc4, 0xcc, 0xcf, 0xa1, 0xd0, 0x04, 0xcf, 0xcf, 0xce, 0xce, 0xcd, 0x82, 0xcc, 0x06, 0xcd, 0xcd, 0xcc, 0xc8, 0xbc, 0xa1, 0x17, 0x84, 0x00, 0x05, 0x2f, 0x98, 0xb4, 0xc4, 0xcc, 0xcf, 0x86, 0xd0, 0x7f, 0xcf, 0xca, 0xbd, 0xfe, 0xfb, 0xd6, 0xef, 0xff, 0xd3, 0x83, 0x96, 0xad, 0xbb, 0xcc, 0xdd, 0xe1, 0xd2, 0xb8, 0xbc, 0xc3, 0xc7, 0xc6, 0xcd, 0xdc, 0xe1, 0xd3, 0xb8, 0xb7, 0xc5, 0xe4, 0xff, 0xda, 0xc7, 0xa7, 0xbb, 0xc8, 0xcd, 0xcd, 0xc8, 0xcc, 0xff, 0xd0, 0xca, 0xff, 0xa2, 0x97, 0xb8, 0xff, 0xdc, 0xc0, 0xff, 0xaa, 0x96, 0xb1, 0xbe, 0xcb, 0xdb, 0xdf, 0xd2, 0xb7, 0xcf, 0xdb, 0xba, 0xc2, 0xdd, 0xcc, 0xce, 0xdd, 0xcb, 0xb8, 0xbe, 0xc3, 0xc3, 0xcf, 0xdb, 0xde, 0xd0, 0xb5, 0xd4, 0xd7, 0xbb, 0xc0, 0xc2, 0xcf, 0xdc, 0xde, 0xd0, 0xb5, 0xd6, 0xd4, 0xbb, 0xbd, 0xc9, 0xdc, 0xe1, 0xd2, 0xb8, 0xbc, 0xc1, 0xd1, 0xdd, 0xc9, 0xdd, 0xdb, 0xbe, 0xb8, 0xd9, 0xdd, 0xc6, 0xba, 0xbf, 0xc2, 0xc7, 0xda, 0xe2, 0xd6, 0xbb, 0xbb, 0xbf, 0xd4, 0xdd, 0xc1, 0xd9, 0xd8, 0xbc, 0xb4, 0xcc, 0xef, 0x06, 0xff, 0xca, 0xbf, 0xab, 0xbf, 0xca, 0xce, 0xa5, 0xd0, 0x84, 0xcf, 0x06, 0xd0, 0xcf, 0xcc, 0xc5, 0xb4, 0x5d, 0x04, 0x83, 0x00, 0x05, 0x0a, 0x70, 0xa4, 0xbc, 0xc9, 0xce, 0x86, 0xd0, 0x02, 0xce, 0xc8, 0xc2, 0x82, 0xff, 0x04, 0xf7, 0xb2, 0x93, 0xa7, 0xd5, 0x81, 0xff, 0x05, 0xf0, 0xae, 0xb4, 0xbd, 0xd7, 0xfd, 0x80, 0xff, 0x02, 0xf3, 0xaa, 0xd2, 0x80, 0xff, 0x21, 0xfb, 0x9c, 0xb4, 0xc6, 0xcc, 0xcc, 0xc4, 0xe3, 0xff, 0xa1, 0xa9, 0xff, 0xc0, 0x8d, 0xde, 0xff, 0x9e, 0xae, 0xff, 0xbc, 0x93, 0xa9, 0xd9, 0xff, 0xff, 0xf9, 0xff, 0xef, 0xf4, 0xf8, 0xa4, 0xbf, 0xff, 0xf7, 0x80, 0xff, 0x24, 0xdb, 0xab, 0xb4, 0xe1, 0xff, 0xff, 0xf9, 0xff, 0xe9, 0xfa, 0xee, 0xa7, 0xb0, 0xe2, 0xff, 0xff, 0xfd, 0xff, 0xe7, 0xfe, 0xe4, 0xa4, 0xca, 0xfd, 0xff, 0xfc, 0xff, 0xee, 0xad, 0xb0, 0xe3, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0xf6, 0x80, 0xff, 0x11, 0xc3, 0xab, 0xc5, 0xfa, 0xff, 0xfd, 0xff, 0xf5, 0xb3, 0xac, 0xed, 0xff, 0xf7, 0xff, 0xff, 0xfe, 0xa9, 0xeb, 0x80, 0xff, 0x04, 0xdd, 0xa4, 0xbb, 0xc7, 0xce, 0xae, 0xd0, 0x04, 0xce, 0xca, 0xc0, 0xab, 0x22, 0x84, 0x00, 0x05, 0x1d, 0x93, 0xb0, 0xc2, 0xcc, 0xcf, 0x85, 0xd0, 0x7f, 0xce, 0xc7, 0xc9, 0xff, 0xd2, 0x8b, 0x92, 0xb1, 0xf0, 0xff, 0xa2, 0xaf, 0xff, 0xf3, 0xba, 0xa2, 0xde, 0xff, 0xd0, 0xa2, 0xb9, 0xfd, 0xf6, 0xbd, 0xa1, 0xd9, 0xff, 0xd4, 0x93, 0xd8, 0xff, 0x8d, 0x8a, 0x9e, 0xb4, 0xc5, 0xcc, 0xca, 0xc2, 0xfb, 0xf0, 0x85, 0x91, 0xff, 0xe0, 0x96, 0xff, 0xe0, 0x82, 0xa3, 0xff, 0xcf, 0x8e, 0xb8, 0xff, 0xe7, 0xaa, 0x93, 0xaf, 0xfa, 0xff, 0xe7, 0x8e, 0xbe, 0xff, 0xef, 0xaa, 0xaa, 0xfb, 0xf9, 0x9a, 0xc4, 0xff, 0xe1, 0xa6, 0x93, 0xb5, 0xfe, 0xff, 0xdb, 0x93, 0xc7, 0xff, 0xe1, 0xa8, 0x96, 0xc0, 0xff, 0xff, 0xcd, 0x9b, 0xfb, 0xf8, 0xa1, 0x89, 0xc4, 0xff, 0xcb, 0x9b, 0xe8, 0xff, 0xd3, 0x9e, 0xd9, 0xff, 0xec, 0xa1, 0xa5, 0xfe, 0xe7, 0x99, 0xf2, 0xfe, 0xb0, 0x88, 0xb1, 0xff, 0xde, 0x97, 0xf4, 0xff, 0xc6, 0xa0, 0xd9, 0xff, 0xc1, 0x91, 0xf5, 0x06, 0xea, 0x81, 0x8e, 0xa4, 0xbb, 0xc7, 0xce, 0xae, 0xd0, 0x05, 0xcf, 0xcd, 0xc6, 0xb8, 0x81, 0x0a, 0x83, 0x00, 0x06, 0x04, 0x54, 0x9f, 0xb9, 0xc7, 0xcd, 0xcf, 0x83, 0xd0, 0x7f, 0xcf, 0xcd, 0xc6, 0xcf, 0xff, 0xbc, 0x7e, 0x85, 0x88, 0xb6, 0xff, 0xc3, 0xc9, 0xff, 0xbb, 0x86, 0x89, 0x9c, 0xff, 0xe7, 0x92, 0xcc, 0xff, 0xc5, 0x87, 0x89, 0x96, 0xff, 0xec, 0x83, 0xe2, 0xfc, 0x7d, 0x8e, 0xa6, 0xbb, 0xc7, 0xcb, 0xc6, 0xd4, 0xff, 0xc7, 0x8a, 0x8c, 0xf1, 0xfc, 0xd2, 0xff, 0xa2, 0x86, 0x9c, 0xff, 0xe2, 0x89, 0xd8, 0xff, 0xa7, 0x8e, 0x93, 0x94, 0xd3, 0xff, 0xd4, 0x82, 0xc5, 0xff, 0xa6, 0x84, 0x86, 0xdf, 0xff, 0x8e, 0xe3, 0xfe, 0x9a, 0x8e, 0x94, 0x93, 0xdf, 0xff, 0xc6, 0x85, 0xe7, 0xfe, 0x99, 0x8e, 0x93, 0x92, 0xe5, 0xff, 0xb8, 0xb5, 0xff, 0xe8, 0xc4, 0xc4, 0xc8, 0xff, 0xe5, 0x8c, 0xf2, 0xf0, 0x80, 0x81, 0xb4, 0xff, 0xa9, 0x7f, 0x86, 0xf4, 0xeb, 0xa3, 0xff, 0xf2, 0xc5, 0xc4, 0xc5, 0xf7, 0xfb, 0x89, 0xff, 0xe1, 0x80, 0x84, 0xa6, 0xff, 0xc4, 0x85, 0x07, 0xff, 0xda, 0x7f, 0x93, 0xab, 0xc0, 0xca, 0xce, 0xaf, 0xd0, 0x04, 0xcf, 0xcc, 0xc2, 0xaf, 0x35, 0x84, 0x00, 0x05, 0x15, 0x8a, 0xab, 0xc0, 0xcb, 0xce, 0x83, 0xd0, 0x73, 0xcf, 0xcc, 0xc4, 0xd7, 0xff, 0xaf, 0x8a, 0x94, 0x99, 0xc0, 0xff, 0xc4, 0xd5, 0xff, 0x9a, 0x86, 0x90, 0xa1, 0xff, 0xe2, 0x89, 0xd6, 0xff, 0xa6, 0x88, 0x91, 0x9c, 0xfe, 0xe8, 0x7e, 0xf1, 0xed, 0x86, 0x9a, 0xb2, 0xc2, 0xcb, 0xcb, 0xc2, 0xed, 0xff, 0x9e, 0x92, 0x99, 0xd8, 0xff, 0xff, 0xe2, 0x80, 0x90, 0x9b, 0xfe, 0xf2, 0x83, 0xe8, 0xf9, 0x8a, 0x90, 0x9c, 0x9e, 0xd2, 0xff, 0xc2, 0x7e, 0xd1, 0xff, 0x96, 0x8b, 0x92, 0xe7, 0xfe, 0x80, 0xf4, 0xed, 0x86, 0x91, 0x9e, 0x9e, 0xdd, 0xff, 0xb4, 0x80, 0xf5, 0xea, 0x88, 0x92, 0x9e, 0x9e, 0xdb, 0xff, 0xa3, 0xc1, 0xff, 0xe6, 0xd8, 0xd9, 0xda, 0xda, 0xd2, 0x89, 0xfe, 0xdf, 0x82, 0x8a, 0xc3, 0xff, 0x9f, 0x87, 0x90, 0xfd, 0xdf, 0xad, 0xff, 0xec, 0xd6, 0xd9, 0x80, 0xda, 0x10, 0x97, 0xff, 0xce, 0x84, 0x8e, 0xb3, 0xff, 0xbc, 0x93, 0xff, 0xcb, 0x89, 0x9f, 0xb6, 0xc5, 0xcc, 0xcf, 0xb0, 0xd0, 0x04, 0xce, 0xc8, 0xbb, 0x99, 0x14, 0x83, 0x00, 0x06, 0x01, 0x38, 0x9a, 0xb4, 0xc5, 0xcc, 0xcf, 0x82, 0xd0, 0x7f, 0xcf, 0xcc, 0xc2, 0xdf, 0xff, 0xa0, 0x8b, 0x9a, 0xb4, 0xef, 0xff, 0xa6, 0xc3, 0xff, 0xc2, 0x86, 0x94, 0xd4, 0xff, 0xc6, 0x88, 0xc6, 0xff, 0xcb, 0x89, 0x94, 0xce, 0xff, 0xcb, 0x82, 0xfe, 0xde, 0x8d, 0xa3, 0xba, 0xc7, 0xcc, 0xc9, 0xc6, 0xff, 0xe5, 0x90, 0x9b, 0xa5, 0xc4, 0xff, 0xff, 0x9f, 0x87, 0x9c, 0xa4, 0xf3, 0xff, 0x84, 0xd9, 0xff, 0xa7, 0x90, 0x9e, 0xa6, 0xf9, 0xff, 0xb2, 0x80, 0xe0, 0xfe, 0x8c, 0x96, 0x9e, 0xf1, 0xf4, 0x81, 0xe6, 0xff, 0x99, 0x92, 0x9f, 0xac, 0xfe, 0xff, 0xa4, 0x82, 0xe4, 0xff, 0x97, 0x93, 0xa0, 0xa9, 0xfc, 0xff, 0x92, 0xaf, 0xff, 0xd1, 0x70, 0x76, 0x99, 0x87, 0x85, 0x99, 0xff, 0xd2, 0x8a, 0x94, 0xd3, 0xff, 0x97, 0x93, 0xa2, 0xff, 0xd4, 0x9a, 0xff, 0xe8, 0x70, 0x74, 0x8f, 0x8d, 0x81, 0xa4, 0xff, 0xc0, 0x8c, 0x9a, 0xc2, 0xff, 0xb3, 0xa3, 0x06, 0xff, 0xbe, 0x92, 0xa9, 0xbe, 0xca, 0xce, 0xb1, 0xd0, 0x05, 0xcf, 0xcc, 0xc4, 0xb3, 0x4f, 0x01, 0x83, 0x00, 0x05, 0x08, 0x7a, 0xa6, 0xbd, 0xc9, 0xce, 0x82, 0xd0, 0x7f, 0xcf, 0xcc, 0xc1, 0xe8, 0xff, 0xee, 0xec, 0xf8, 0xff, 0xff, 0xd9, 0x81, 0x96, 0xfc, 0xff, 0xe8, 0xf1, 0xff, 0xf4, 0x8f, 0x8f, 0xa3, 0xfb, 0xff, 0xea, 0xee, 0xff, 0xf7, 0x8e, 0x95, 0xff, 0xd2, 0x93, 0xa9, 0xbf, 0xca, 0xcc, 0xc6, 0xdd, 0xff, 0xbc, 0x96, 0xa5, 0xb0, 0xb5, 0xff, 0xe9, 0x81, 0x94, 0xa9, 0xaf, 0xe8, 0xff, 0x97, 0xa9, 0xff, 0xfb, 0xd7, 0xd4, 0xf9, 0xff, 0xff, 0xa3, 0x83, 0xee, 0xf2, 0x8f, 0x9e, 0xa8, 0xfd, 0xe4, 0x86, 0xb7, 0xff, 0xf8, 0xd2, 0xd9, 0xfb, 0xff, 0xff, 0x95, 0x88, 0xb5, 0xff, 0xf3, 0xcc, 0xd3, 0xf8, 0xff, 0xff, 0x82, 0x85, 0xf4, 0xff, 0xe8, 0xdc, 0xff, 0xec, 0x92, 0xae, 0xff, 0xc5, 0x92, 0x9c, 0xe3, 0xfd, 0x92, 0x9b, 0xb5, 0xff, 0xc7, 0x83, 0xe4, 0xff, 0xf0, 0xd7, 0xfe, 0xf7, 0x97, 0xb8, 0xff, 0xb5, 0x94, 0xa2, 0xd3, 0xff, 0xa5, 0xb5, 0x06, 0xff, 0xb3, 0x98, 0xaf, 0xc2, 0xcc, 0xcf, 0xb2, 0xd0, 0x04, 0xce, 0xca, 0xbf, 0xa7, 0x1d, 0x84, 0x00, 0x05, 0x0e, 0x95, 0xb2, 0xc4, 0xcc, 0xcf, 0x81, 0xd0, 0x03, 0xcf, 0xcc, 0xc1, 0xf2, 0x80, 0xff, 0x7f, 0xf8, 0xe7, 0xbb, 0x8c, 0x8f, 0x95, 0xb1, 0xf1, 0xff, 0xfe, 0xe0, 0x97, 0x91, 0x9e, 0xa4, 0xb6, 0xef, 0xff, 0xfe, 0xe3, 0x98, 0x8b, 0xad, 0xff, 0xc8, 0x9c, 0xb0, 0xc2, 0xcb, 0xcc, 0xc5, 0xf6, 0xfb, 0x9d, 0x9f, 0xb0, 0xbb, 0xb4, 0xf5, 0xb7, 0x93, 0xa4, 0xb5, 0xb8, 0xde, 0xff, 0xaf, 0x8e, 0xba, 0xf7, 0xff, 0xff, 0xe3, 0xd7, 0xff, 0x98, 0x8d, 0xfc, 0xe6, 0x98, 0xa5, 0xb8, 0xff, 0xd8, 0x91, 0x93, 0xc5, 0xfb, 0xff, 0xff, 0xdc, 0xdf, 0xff, 0x8c, 0x93, 0x9b, 0xc0, 0xf7, 0xff, 0xff, 0xe0, 0xf2, 0xf9, 0x7a, 0x88, 0xa4, 0xe6, 0xff, 0xff, 0xea, 0xa5, 0x96, 0xc0, 0xff, 0xbd, 0x9b, 0xa4, 0xf2, 0xf2, 0x9a, 0xa3, 0xc7, 0xff, 0xbd, 0x8f, 0x9a, 0xdb, 0xfd, 0xff, 0xef, 0xb2, 0x91, 0xcb, 0xff, 0xaf, 0x9e, 0xab, 0xe1, 0xff, 0x9c, 0xc8, 0xff, 0xab, 0xa1, 0xb5, 0xc5, 0xcd, 0xcf, 0xb2, 0xd0, 0x05, 0xcf, 0xcd, 0xc6, 0xb6, 0x72, 0x08, 0x83, 0x00, 0x05, 0x07, 0x73, 0xa5, 0xbe, 0xca, 0xcf, 0x81, 0xd0, 0x76, 0xcf, 0xcc, 0xc4, 0xb4, 0x9e, 0x8f, 0x8a, 0x8a, 0x8e, 0x93, 0x9b, 0xa5, 0xab, 0xa9, 0x9e, 0x9c, 0x92, 0x8f, 0x97, 0xa3, 0xb1, 0xb5, 0xae, 0xa0, 0x9c, 0x94, 0x8e, 0x95, 0x9e, 0xa5, 0xa5, 0xa4, 0xab, 0xb9, 0xc6, 0xcc, 0xcc, 0xc6, 0xba, 0xab, 0xa5, 0xad, 0xbb, 0xc2, 0xbf, 0xb2, 0xa7, 0xa9, 0xb4, 0xc0, 0xc1, 0xb5, 0xa7, 0x9f, 0xa0, 0x9f, 0x9a, 0xa2, 0x97, 0x8f, 0x8e, 0x8e, 0x94, 0x9e, 0xa3, 0xa2, 0xa6, 0xb1, 0xb6, 0xb0, 0xa6, 0xa4, 0xa5, 0xa3, 0x9c, 0xa2, 0x96, 0x8f, 0x8e, 0x8e, 0x98, 0xa4, 0xa9, 0xa1, 0x93, 0x98, 0x8d, 0x8f, 0xff, 0xd9, 0x81, 0x95, 0xa0, 0x9b, 0x98, 0x95, 0x8f, 0x98, 0xa4, 0xab, 0xa8, 0xa5, 0xab, 0xb1, 0xaf, 0xa8, 0xa7, 0xae, 0xb3, 0xac, 0xa4, 0xa3, 0xa3, 0x9e, 0x96, 0x98, 0x8e, 0x96, 0x9e, 0x80, 0xa4, 0x0b, 0xab, 0xb4, 0xb3, 0xa9, 0x9f, 0x9e, 0x9e, 0xa3, 0xae, 0xbd, 0xc8, 0xce, 0xb4, 0xd0, 0x04, 0xcf, 0xcb, 0xc1, 0xac, 0x2b, 0x82, 0x00, 0x06, 0x01, 0x01, 0x4a, 0x9b, 0xb8, 0xc8, 0xce, 0x82, 0xd0, 0x4a, 0xce, 0xc8, 0xbf, 0xb3, 0xa8, 0xa3, 0xa3, 0xa5, 0xab, 0xb3, 0xbb, 0xbf, 0xbc, 0xb4, 0xab, 0xa6, 0xa7, 0xad, 0xb7, 0xc0, 0xc3, 0xbf, 0xb5, 0xab, 0xa6, 0xa7, 0xac, 0xb4, 0xb9, 0xb8, 0xb7, 0xbb, 0xc2, 0xca, 0xce, 0xcd, 0xca, 0xc2, 0xba, 0xb7, 0xbd, 0xc5, 0xc9, 0xc6, 0xc0, 0xbb, 0xbc, 0xc2, 0xc8, 0xc7, 0xc1, 0xb9, 0xb4, 0xb5, 0xb4, 0xb0, 0xa9, 0xa6, 0xa4, 0xa5, 0xa8, 0xad, 0xb3, 0xb5, 0xb5, 0xb8, 0xbe, 0xc1, 0xbd, 0xb8, 0xb7, 0xb9, 0xb7, 0xb1, 0xa9, 0x80, 0xa5, 0x36, 0xa9, 0xae, 0xb4, 0xde, 0xf4, 0xce, 0x9c, 0x9d, 0xde, 0xff, 0xad, 0x8d, 0xa4, 0xb2, 0xb3, 0xab, 0xa7, 0xa8, 0xad, 0xb4, 0xba, 0xb9, 0xb7, 0xbb, 0xbe, 0xbd, 0xb8, 0xb8, 0xbc, 0xbf, 0xbb, 0xb7, 0xb7, 0xb8, 0xb4, 0xac, 0xa7, 0xa7, 0xab, 0xb3, 0xb6, 0xb6, 0xb7, 0xbb, 0xc0, 0xbf, 0xb9, 0xb4, 0xb3, 0xb3, 0xb5, 0xbd, 0xc5, 0xcc, 0xcf, 0xb4, 0xd0, 0x05, 0xcf, 0xcd, 0xc7, 0xba, 0x90, 0x03, 0x82, 0x00, 0x05, 0x03, 0x53, 0x98, 0xb5, 0xc6, 0xce, 0x82, 0xd0, 0x1b, 0xcf, 0xcc, 0xc8, 0xc2, 0xbf, 0xbc, 0xbc, 0xbd, 0xc0, 0xc3, 0xc7, 0xca, 0xc8, 0xc4, 0xc0, 0xbd, 0xbe, 0xc1, 0xc6, 0xca, 0xcc, 0xc9, 0xc5, 0xc0, 0xbd, 0xbe, 0xc1, 0xc4, 0x81, 0xc6, 0x24, 0xcb, 0xcd, 0xcf, 0xcf, 0xcd, 0xc9, 0xc6, 0xc5, 0xc8, 0xcc, 0xcd, 0xcc, 0xca, 0xc7, 0xc8, 0xcb, 0xcd, 0xcc, 0xca, 0xc6, 0xc4, 0xc5, 0xc5, 0xc2, 0xbf, 0xbc, 0xbc, 0xbd, 0xbf, 0xc1, 0xc4, 0xc5, 0xc4, 0xc6, 0xc8, 0xc9, 0xc7, 0x81, 0xc6, 0x09, 0xc2, 0xbf, 0xbc, 0xbc, 0xbd, 0xbf, 0xc1, 0xc0, 0xc7, 0xfb, 0x81, 0xff, 0x0a, 0xd4, 0x88, 0x9b, 0xb1, 0xc0, 0xc2, 0xc0, 0xbe, 0xbe, 0xc1, 0xc4, 0x81, 0xc6, 0x05, 0xc8, 0xc7, 0xc6, 0xc6, 0xc7, 0xc8, 0x81, 0xc6, 0x05, 0xc5, 0xc1, 0xbe, 0xbe, 0xc0, 0xc3, 0x80, 0xc5, 0x0b, 0xc7, 0xc9, 0xc8, 0xc6, 0xc4, 0xc3, 0xc3, 0xc5, 0xc7, 0xcc, 0xce, 0xcf, 0xb5, 0xd0, 0x05, 0xcf, 0xcc, 0xc2, 0xb1, 0x34, 0x03, 0x81, 0x00, 0x05, 0x10, 0x76, 0x9b, 0xb7, 0xc7, 0xce, 0x83, 0xd0, 0x03, 0xcf, 0xcd, 0xcc, 0xcb, 0x80, 0xca, 0x20, 0xcb, 0xcc, 0xcd, 0xce, 0xce, 0xcc, 0xcb, 0xca, 0xca, 0xcc, 0xcd, 0xce, 0xcf, 0xce, 0xcc, 0xcb, 0xca, 0xca, 0xcc, 0xcc, 0xcd, 0xcd, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd0, 0xcf, 0xce, 0xcd, 0xcc, 0xcd, 0x80, 0xcf, 0x07, 0xce, 0xcd, 0xcd, 0xce, 0xcf, 0xcf, 0xce, 0xcd, 0x81, 0xcc, 0x04, 0xcb, 0xca, 0xc9, 0xca, 0xcb, 0x82, 0xcc, 0x03, 0xcd, 0xce, 0xcd, 0xcc, 0x80, 0xcd, 0x1b, 0xcc, 0xca, 0xc9, 0xc9, 0xca, 0xcb, 0xca, 0xc7, 0xbe, 0xb9, 0xc7, 0xdc, 0xd0, 0xae, 0x8c, 0x98, 0xab, 0xbd, 0xc7, 0xcb, 0xcb, 0xca, 0xca, 0xcb, 0xcc, 0xcd, 0xcd, 0xcc, 0x80, 0xcd, 0x01, 0xcc, 0xcc, 0x80, 0xcd, 0x07, 0xcc, 0xcd, 0xcd, 0xcc, 0xcc, 0xca, 0xca, 0xcb, 0x81, 0xcc, 0x03, 0xcd, 0xce, 0xcd, 0xcd, 0x81, 0xcc, 0x02, 0xcd, 0xcf, 0xcf, 0xb7, 0xd0, 0x0e, 0xce, 0xc9, 0xbd, 0xa5, 0x31, 0x0a, 0x00, 0x03, 0x10, 0x55, 0x87, 0xa5, 0xbd, 0xca, 0xcf, 0x84, 0xd0, 0x85, 0xcf, 0x80, 0xd0, 0x83, 0xcf, 0x80, 0xd0, 0x87, 0xcf, 0x83, 0xd0, 0x80, 0xcf, 0x81, 0xd0, 0x00, 0xcf, 0x82, 0xd0, 0x83, 0xcf, 0x01, 0xce, 0xce, 0x85, 0xcf, 0x00, 0xd0, 0x84, 0xcf, 0x11, 0xce, 0xce, 0xcf, 0xcf, 0xce, 0xcb, 0xc4, 0xb8, 0xa9, 0x9e, 0x98, 0x99, 0xa0, 0xac, 0xbb, 0xc6, 0xcc, 0xce, 0x9a, 0xcf, 0x01, 0xd0, 0xd0, 0x83, 0xcf, 0xb9, 0xd0, 0x0e, 0xcf, 0xcc, 0xc6, 0xb8, 0xa4, 0x7c, 0x4d, 0x55, 0x76, 0x87, 0x9e, 0xb4, 0xc4, 0xcc, 0xcf, 0xff, 0xd0, 0xbf, 0xd0, 0x0c, 0xcf, 0xcc, 0xc4, 0xb9, 0xab, 0x9e, 0x98, 0x9b, 0xa5, 0xb4, 0xc1, 0xca, 0xce, 0xff, 0xd0, 0x93, 0xd0, 0x94, 0xd0, 0x12, 0xcf, 0xce, 0xcd, 0xcc, 0xcb, 0xc9, 0xc7, 0xc6, 0xc5, 0xc4, 0xc4, 0xc6, 0xc7, 0xc9, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xff, 0xd0, 0xb7, 0xd0, 0x18, 0xcf, 0xcf, 0xcd, 0xcc, 0xc9, 0xc6, 0xc2, 0xbc, 0xa4, 0x8b, 0x7a, 0x69, 0x73, 0x85, 0x9e, 0xb4, 0xba, 0xbe, 0xc2, 0xc6, 0xc9, 0xcc, 0xcd, 0xcf, 0xcf, 0xff, 0xd0, 0xb3, 0xd0, 0x08, 0xcf, 0xcd, 0xcb, 0xc7, 0xc2, 0xa9, 0x64, 0x2a, 0x0a, 0x83, 0x00, 0x0d, 0x01, 0x0b, 0x22, 0x56, 0x95, 0xb4, 0xbb, 0xc2, 0xc7, 0xcb, 0xcd, 0xcf, 0xd0, 0xd0, 0x81, 0xcf, 0xff, 0xd0, 0xaa, 0xd0, 0x07, 0xcf, 0xce, 0xcc, 0xc7, 0xb8, 0x73, 0x37, 0x07, 0x8a, 0x00, 0x0f, 0x04, 0x2d, 0x65, 0xa4, 0xb8, 0xc1, 0xc7, 0xcc, 0xce, 0xce, 0xcd, 0xcc, 0xcc, 0xcd, 0xce, 0xcf, 0xff, 0xd0, 0xa7, 0xd0, 0x05, 0xcf, 0xcd, 0xca, 0xc3, 0x76, 0x12, 0x90, 0x00, 0x0c, 0x11, 0x69, 0xac, 0xba, 0xc3, 0xc8, 0xca, 0xc7, 0x8f, 0xc4, 0xc7, 0xcc, 0xce, 0xa3, 0xd0, 0x8b, 0xcf, 0x89, 0xd0, 0x89, 0xcf, 0xb9, 0xd0, 0x83, 0xcf, 0x9a, 0xd0, 0x05, 0xcf, 0xcc, 0xc7, 0xb2, 0x45, 0x01, 0x92, 0x00, 0x0c, 0x01, 0x37, 0x94, 0xb2, 0xbc, 0xbf, 0x64, 0x0a, 0xb3, 0xbd, 0xc6, 0xcc, 0xcf, 0x9e, 0xd0, 0x04, 0xcf, 0xcf, 0xce, 0xcd, 0xcd, 0x89, 0xcc, 0x03, 0xcd, 0xcd, 0xce, 0xcf, 0x82, 0xd0, 0x03, 0xcf, 0xcf, 0xce, 0xcd, 0x88, 0xcc, 0x03, 0xcd, 0xcd, 0xce, 0xcf, 0x82, 0xd0, 0x06, 0xcf, 0xce, 0xce, 0xcd, 0xce, 0xcf, 0xcf, 0xa9, 0xd0, 0x07, 0xcf, 0xcd, 0xcc, 0xcb, 0xcb, 0xcc, 0xcd, 0xcf, 0x98, 0xd0, 0x04, 0xce, 0xcc, 0xc6, 0x8a, 0x1d, 0x96, 0x00, 0x0a, 0x13, 0x69, 0xa4, 0x5d, 0x0d, 0x0a, 0x83, 0xad, 0xbf, 0xca, 0xce, 0x9d, 0xd0, 0x05, 0xcf, 0xcd, 0xcb, 0xc8, 0xc6, 0xc4, 0x89, 0xc3, 0x0d, 0xc5, 0xc6, 0xc9, 0xcc, 0xce, 0xcf, 0xd0, 0xd0, 0xcf, 0xcc, 0xcb, 0xc7, 0xc6, 0xc4, 0x87, 0xc3, 0x10, 0xc5, 0xc6, 0xc9, 0xcc, 0xce, 0xcf, 0xd0, 0xcf, 0xce, 0xcc, 0xca, 0xc7, 0xc6, 0xc8, 0xcc, 0xcd, 0xcf, 0xa7, 0xd0, 0x09, 0xce, 0xcc, 0xc7, 0xbb, 0xb7, 0xbf, 0xc2, 0xc8, 0xcc, 0xcf, 0x96, 0xd0, 0x04, 0xcf, 0xcc, 0xc5, 0x63, 0x06, 0x98, 0x00, 0x09, 0x01, 0x29, 0x0a, 0x00, 0x00, 0x50, 0x9e, 0xb6, 0xc6, 0xcd, 0x9c, 0xd0, 0x06, 0xcf, 0xcc, 0xc7, 0xad, 0x87, 0x76, 0x6e, 0x88, 0x6d, 0x0e, 0x6f, 0x8b, 0xb3, 0xbc, 0xc4, 0xca, 0xce, 0xcf, 0xce, 0xcc, 0xc6, 0xa1, 0x83, 0x73, 0x6e, 0x86, 0x6d, 0x12, 0x6e, 0x8a, 0xb2, 0xbc, 0xc3, 0xca, 0xcd, 0xcf, 0xce, 0xcb, 0xc2, 0x8a, 0x69, 0x9e, 0xbb, 0xc2, 0xc9, 0xcd, 0xcf, 0xa5, 0xd0, 0x0b, 0xcf, 0xcc, 0xb7, 0x41, 0x08, 0x06, 0x37, 0xae, 0xbc, 0xc6, 0xcc, 0xcf, 0x94, 0xd0, 0x04, 0xcf, 0xcc, 0xc6, 0x79, 0x03, 0x88, 0x00, 0x06, 0x04, 0x17, 0x24, 0x25, 0x23, 0x1a, 0x09, 0x87, 0x00, 0x01, 0x07, 0x07, 0x80, 0x00, 0x05, 0x28, 0x90, 0xae, 0xc2, 0xcc, 0xcf, 0x9a, 0xd0, 0x04, 0xcf, 0xcc, 0xc5, 0x4b, 0x03, 0x8d, 0x00, 0x08, 0x06, 0x81, 0xb4, 0xc2, 0xcb, 0xcd, 0xcc, 0xba, 0x2e, 0x8c, 0x00, 0x08, 0x04, 0x77, 0xb4, 0xc2, 0xcb, 0xcd, 0xcb, 0xa9, 0x11, 0x80, 0x00, 0x04, 0x6d, 0xb2, 0xc0, 0xca, 0xce, 0xa4, 0xd0, 0x03, 0xcf, 0xcd, 0xc6, 0x56, 0x81, 0x00, 0x04, 0x6a, 0xab, 0xc0, 0xca, 0xce, 0x93, 0xd0, 0x04, 0xcf, 0xcd, 0xc7, 0x95, 0x0d, 0x86, 0x00, 0x0c, 0x12, 0x2d, 0x46, 0x66, 0x73, 0x7a, 0x7e, 0x80, 0x7f, 0x7a, 0x5c, 0x35, 0x0d, 0x83, 0x00, 0x01, 0x04, 0x04, 0x81, 0x00, 0x05, 0x17, 0x86, 0xa8, 0xc0, 0xcb, 0xcf, 0x9a, 0xd0, 0x02, 0xce, 0xc9, 0x73, 0x90, 0x00, 0x06, 0x32, 0xa1, 0xb8, 0xc6, 0xcb, 0xc6, 0x48, 0x8e, 0x00, 0x06, 0x2b, 0xa0, 0xb7, 0xc6, 0xcb, 0xc6, 0x4d, 0x81, 0x00, 0x05, 0x25, 0x9e, 0xb5, 0xc6, 0xcd, 0xcf, 0xa3, 0xd0, 0x03, 0xcf, 0xcb, 0xb3, 0x06, 0x81, 0x00, 0x05, 0x45, 0x9c, 0xb7, 0xc6, 0xce, 0xcf, 0x92, 0xd0, 0x03, 0xce, 0xc9, 0xad, 0x1b, 0x85, 0x00, 0x10, 0x08, 0x35, 0x67, 0x76, 0x84, 0x8e, 0x98, 0x9e, 0xa3, 0xa4, 0xa3, 0x9f, 0x99, 0x90, 0x81, 0x47, 0x0b, 0x80, 0x00, 0x01, 0x04, 0x04, 0x82, 0x00, 0x05, 0x0e, 0x7e, 0xa2, 0xbd, 0xca, 0xcf, 0x99, 0xd0, 0x03, 0xcf, 0xcc, 0xc4, 0x31, 0x90, 0x00, 0x06, 0x1d, 0x93, 0xb0, 0xc2, 0xc8, 0xbe, 0x0d, 0x8e, 0x00, 0x06, 0x19, 0x92, 0xaf, 0xc2, 0xc7, 0xb5, 0x06, 0x81, 0x00, 0x05, 0x17, 0x8d, 0xab, 0xc2, 0xcc, 0xcf, 0xa3, 0xd0, 0x02, 0xce, 0xc8, 0x8a, 0x82, 0x00, 0x05, 0x4d, 0x93, 0xb3, 0xc5, 0xcd, 0xcf, 0x91, 0xd0, 0x03, 0xcf, 0xcc, 0xbe, 0x32, 0x84, 0x00, 0x16, 0x01, 0x21, 0x5a, 0x76, 0x88, 0x99, 0xa5, 0xaf, 0xb6, 0xbb, 0xbd, 0xbf, 0xbe, 0xbb, 0xb7, 0xb0, 0xa5, 0x98, 0x77, 0x24, 0x00, 0x04, 0x04, 0x83, 0x00, 0x05, 0x09, 0x6a, 0x9c, 0xb9, 0xc8, 0xce, 0x99, 0xd0, 0x03, 0xcf, 0xcb, 0xbd, 0x07, 0x90, 0x00, 0x05, 0x42, 0x91, 0xae, 0xc2, 0xc5, 0x98, 0x8f, 0x00, 0x05, 0x3f, 0x90, 0xad, 0xc1, 0xc5, 0x8f, 0x82, 0x00, 0x05, 0x23, 0x85, 0xa7, 0xc0, 0xcb, 0xcf, 0xa2, 0xd0, 0x03, 0xcf, 0xcd, 0xc5, 0x64, 0x82, 0x00, 0x05, 0x5d, 0x92, 0xb3, 0xc5, 0xcd, 0xcf, 0x90, 0xd0, 0x03, 0xcf, 0xcd, 0xc6, 0x60, 0x84, 0x00, 0x0a, 0x01, 0x37, 0x6a, 0x80, 0x95, 0xa7, 0xb4, 0xbe, 0xc3, 0xc6, 0xc9, 0x80, 0xcb, 0x08, 0xca, 0xc7, 0xc4, 0xbe, 0xb3, 0xa3, 0x8c, 0x1e, 0x06, 0x84, 0x00, 0x05, 0x01, 0x49, 0x95, 0xb4, 0xc6, 0xcd, 0x95, 0xd0, 0x00, 0xcf, 0x80, 0xd0, 0x02, 0xce, 0xc8, 0xa0, 0x8d, 0x00, 0x09, 0x03, 0x15, 0x2b, 0x4d, 0x82, 0x9b, 0xb4, 0xc3, 0xc3, 0x73, 0x8b, 0x00, 0x09, 0x03, 0x15, 0x2b, 0x4d, 0x81, 0x9b, 0xb4, 0xc2, 0xc2, 0x6d, 0x82, 0x00, 0x05, 0x34, 0x84, 0xa8, 0xc0, 0xcc, 0xcf, 0x89, 0xd0, 0x01, 0xcf, 0xcf, 0x94, 0xd0, 0x03, 0xcf, 0xcc, 0xc2, 0x42, 0x81, 0x00, 0x05, 0x03, 0x6f, 0x95, 0xb4, 0xc6, 0xcd, 0x91, 0xd0, 0x03, 0xcf, 0xcb, 0xbe, 0x1a, 0x84, 0x00, 0x0a, 0x2f, 0x6d, 0x86, 0x9e, 0xb1, 0xbd, 0xc6, 0xca, 0xcc, 0xcd, 0xce, 0x80, 0xcf, 0x07, 0xce, 0xce, 0xcc, 0xc8, 0xc1, 0xb2, 0x41, 0x08, 0x86, 0x00, 0x05, 0x24, 0x8d, 0xae, 0xc2, 0xcc, 0xcf, 0x8a, 0xd0, 0x01, 0xcf, 0xcf, 0x80, 0xce, 0x80, 0xcf, 0x00, 0xce, 0x80, 0xcd, 0x04, 0xce, 0xcf, 0xcd, 0xc6, 0x7e, 0x82, 0x00, 0x04, 0x23, 0x5a, 0x66, 0x6f, 0x72, 0x83, 0x73, 0x09, 0x76, 0x7a, 0x80, 0x8b, 0x9b, 0xae, 0xbf, 0xc6, 0xc2, 0x53, 0x82, 0x00, 0x04, 0x35, 0x5d, 0x69, 0x70, 0x72, 0x81, 0x73, 0x09, 0x76, 0x7a, 0x80, 0x8a, 0x9b, 0xae, 0xbf, 0xc6, 0xc1, 0x4c, 0x82, 0x00, 0x04, 0x46, 0x88, 0xab, 0xc2, 0xcc, 0x80, 0xcf, 0x80, 0xce, 0x81, 0xcf, 0x01, 0xce, 0xce, 0x81, 0xcd, 0x02, 0xce, 0xcf, 0xcf, 0x8c, 0xd0, 0x81, 0xcf, 0x03, 0xcd, 0xc9, 0xbe, 0x21, 0x81, 0x00, 0x05, 0x11, 0x76, 0x9a, 0xb8, 0xc8, 0xce, 0x91, 0xd0, 0x02, 0xcd, 0xc7, 0x74, 0x84, 0x00, 0x09, 0x25, 0x6c, 0x86, 0xa1, 0xb4, 0xc2, 0xc9, 0xcc, 0xce, 0xcf, 0x83, 0xd0, 0x05, 0xcf, 0xce, 0xcb, 0xc2, 0x42, 0x08, 0x87, 0x00, 0x05, 0x14, 0x84, 0xa7, 0xc0, 0xcb, 0xcf, 0x89, 0xd0, 0x11, 0xcf, 0xcd, 0xcb, 0xc8, 0xc8, 0xc9, 0xcb, 0xcc, 0xcb, 0xc8, 0xc6, 0xc5, 0xc6, 0xc9, 0xcc, 0xcb, 0xc3, 0x5c, 0x82, 0x00, 0x05, 0x38, 0x6e, 0x83, 0x91, 0x97, 0x98, 0x82, 0x99, 0x09, 0x9b, 0x9e, 0xa3, 0xab, 0xb4, 0xc0, 0xc7, 0xc9, 0xc0, 0x34, 0x82, 0x00, 0x05, 0x4f, 0x73, 0x87, 0x93, 0x98, 0x98, 0x80, 0x99, 0x09, 0x9b, 0x9e, 0xa3, 0xab, 0xb4, 0xc0, 0xc6, 0xc9, 0xc0, 0x2e, 0x82, 0x00, 0x0b, 0x5b, 0x8e, 0xb0, 0xc4, 0xcc, 0xce, 0xcd, 0xcb, 0xc8, 0xc7, 0xc8, 0xcb, 0x80, 0xcc, 0x09, 0xca, 0xc7, 0xc6, 0xc4, 0xc5, 0xc6, 0xc9, 0xcc, 0xcd, 0xcf, 0x88, 0xd0, 0x0a, 0xcf, 0xcf, 0xce, 0xcd, 0xcc, 0xcb, 0xca, 0xc7, 0xc2, 0xb3, 0x06, 0x81, 0x00, 0x05, 0x21, 0x7a, 0x9f, 0xbc, 0xca, 0xce, 0x90, 0xd0, 0x03, 0xcf, 0xcc, 0xc2, 0x2e, 0x83, 0x00, 0x08, 0x11, 0x65, 0x82, 0x9e, 0xb5, 0xc3, 0xcb, 0xce, 0xcf, 0x86, 0xd0, 0x03, 0xce, 0xc7, 0x3b, 0x06, 0x88, 0x00, 0x05, 0x0b, 0x77, 0xa0, 0xbb, 0xc9, 0xce, 0x88, 0xd0, 0x12, 0xcf, 0xcc, 0xc6, 0xa7, 0x79, 0xa9, 0xbc, 0xc0, 0xc2, 0xb4, 0x87, 0x5d, 0x73, 0xa7, 0xbb, 0xc3, 0xc6, 0xc0, 0x3e, 0x82, 0x00, 0x05, 0x4e, 0x7e, 0x98, 0xa9, 0xb0, 0xb2, 0x83, 0xb3, 0x08, 0xb5, 0xba, 0xbf, 0xc4, 0xc9, 0xcc, 0xca, 0xbe, 0x17, 0x81, 0x00, 0x05, 0x03, 0x66, 0x84, 0x9e, 0xab, 0xb1, 0x81, 0xb3, 0x09, 0xb4, 0xb5, 0xba, 0xbf, 0xc4, 0xc9, 0xcc, 0xca, 0xbd, 0x11, 0x81, 0x00, 0x1b, 0x03, 0x6f, 0x94, 0xb4, 0xc6, 0xcc, 0xcc, 0xc6, 0xa1, 0x71, 0x9b, 0xbb, 0xc0, 0xc4, 0xc5, 0xc2, 0xac, 0x86, 0x63, 0x70, 0x8e, 0xac, 0xbb, 0xc1, 0xc6, 0xcc, 0xce, 0xcf, 0x84, 0xd0, 0x0b, 0xcf, 0xcf, 0xcd, 0xcb, 0xc8, 0xc5, 0xc1, 0xbe, 0xbb, 0xab, 0x92, 0x69, 0x82, 0x00, 0x05, 0x32, 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0x90, 0xd0, 0x03, 0xce, 0xc8, 0x8e, 0x01, 0x83, 0x00, 0x07, 0x3b, 0x79, 0x98, 0xb2, 0xc2, 0xcb, 0xce, 0xcf, 0x87, 0xd0, 0x08, 0xcd, 0xbc, 0x7a, 0x45, 0x23, 0x17, 0x0d, 0x07, 0x01, 0x83, 0x00, 0x05, 0x03, 0x59, 0x9a, 0xb7, 0xc7, 0xce, 0x87, 0xd0, 0x0a, 0xcf, 0xcc, 0xc6, 0x35, 0x00, 0x00, 0x03, 0x96, 0xa8, 0x49, 0x01, 0x80, 0x00, 0x05, 0x03, 0x92, 0xb4, 0xbf, 0xbb, 0x1e, 0x81, 0x00, 0x04, 0x01, 0x5c, 0x7c, 0x95, 0xa4, 0x83, 0xab, 0x0a, 0xac, 0xb1, 0xb5, 0xbb, 0xc1, 0xc7, 0xcc, 0xcd, 0xc9, 0xb3, 0x01, 0x81, 0x00, 0x04, 0x10, 0x65, 0x82, 0x9a, 0xa6, 0x81, 0xab, 0x09, 0xac, 0xb3, 0xb7, 0xbc, 0xc2, 0xc8, 0xcc, 0xcd, 0xc9, 0xae, 0x82, 0x00, 0x07, 0x11, 0x76, 0x9b, 0xb8, 0xc7, 0xcb, 0xc2, 0x25, 0x80, 0x00, 0x04, 0x60, 0xab, 0xb1, 0x6d, 0x15, 0x82, 0x00, 0x06, 0x07, 0x53, 0xa7, 0xb8, 0xc3, 0xcb, 0xce, 0x83, 0xd0, 0x09, 0xcf, 0xcd, 0xcb, 0xc6, 0xc0, 0x8d, 0x46, 0x29, 0x17, 0x04, 0x85, 0x00, 0x05, 0x46, 0x87, 0xab, 0xc2, 0xcc, 0xcf, 0x8f, 0xd0, 0x03, 0xcf, 0xcc, 0xc4, 0x46, 0x83, 0x00, 0x06, 0x11, 0x69, 0x8a, 0xa9, 0xbf, 0xca, 0xce, 0x89, 0xd0, 0x15, 0xce, 0xc8, 0xbd, 0xab, 0x99, 0x8a, 0x7e, 0x67, 0x4d, 0x2e, 0x19, 0x10, 0x09, 0x01, 0x00, 0x00, 0x32, 0x97, 0xb3, 0xc6, 0xcd, 0xcf, 0x86, 0xd0, 0x02, 0xce, 0xc9, 0x89, 0x81, 0x00, 0x01, 0x47, 0x22, 0x83, 0x00, 0x04, 0x47, 0xa3, 0xb4, 0xb2, 0x04, 0x8d, 0x00, 0x08, 0x04, 0x25, 0x69, 0xb4, 0xc0, 0xc9, 0xcc, 0xc7, 0x92, 0x8c, 0x00, 0x08, 0x0a, 0x2e, 0x82, 0xb6, 0xc2, 0xcb, 0xcc, 0xc7, 0x8d, 0x82, 0x00, 0x06, 0x21, 0x7a, 0x9f, 0xbb, 0xc8, 0xc7, 0x7d, 0x81, 0x00, 0x02, 0x1b, 0x6f, 0x1e, 0x86, 0x00, 0x05, 0x17, 0x98, 0xb4, 0xc2, 0xcb, 0xce, 0x80, 0xd0, 0x06, 0xcf, 0xce, 0xcc, 0xc6, 0xb1, 0x64, 0x1a, 0x8a, 0x00, 0x05, 0x5a, 0x8e, 0xaf, 0xc4, 0xcc, 0xcf, 0x8f, 0xd0, 0x03, 0xcf, 0xcb, 0xc0, 0x1d, 0x83, 0x00, 0x06, 0x37, 0x7a, 0x9b, 0xb6, 0xc6, 0xcd, 0xcf, 0x89, 0xd0, 0x15, 0xce, 0xcb, 0xc4, 0xbb, 0xb0, 0xa7, 0xa0, 0x9b, 0x95, 0x8e, 0x86, 0x7f, 0x6f, 0x50, 0x2e, 0x1a, 0x27, 0x99, 0xb3, 0xc5, 0xcc, 0xcf, 0x85, 0xd0, 0x03, 0xcf, 0xcd, 0xc4, 0x37, 0x89, 0x00, 0x03, 0x3a, 0x97, 0xad, 0x94, 0x90, 0x00, 0x06, 0x09, 0x98, 0xb4, 0xc3, 0xca, 0xc5, 0x70, 0x8e, 0x00, 0x06, 0x23, 0xa3, 0xb8, 0xc6, 0xcb, 0xc5, 0x6c, 0x82, 0x00, 0x06, 0x34, 0x82, 0xa5, 0xbf, 0xc7, 0xc2, 0x2b, 0x81, 0x00, 0x01, 0x01, 0x01, 0x88, 0x00, 0x0c, 0x35, 0x9f, 0xb6, 0xc6, 0xcc, 0xcf, 0xd0, 0xcf, 0xce, 0xca, 0xc3, 0x60, 0x04, 0x8b, 0x00, 0x05, 0x03, 0x6f, 0x94, 0xb4, 0xc6, 0xcd, 0x90, 0xd0, 0x03, 0xce, 0xc9, 0xa8, 0x03, 0x82, 0x00, 0x06, 0x01, 0x5a, 0x87, 0xa9, 0xc0, 0xcb, 0xcf, 0x8a, 0xd0, 0x15, 0xcf, 0xce, 0xcb, 0xc6, 0xc2, 0xbf, 0xbc, 0xb9, 0xb4, 0xaf, 0xa9, 0xa3, 0x9c, 0x96, 0x8f, 0x8d, 0x94, 0xa5, 0xb9, 0xc6, 0xcd, 0xcf, 0x85, 0xd0, 0x03, 0xcf, 0xcc, 0xc0, 0x13, 0x88, 0x00, 0x04, 0x04, 0x63, 0x95, 0xab, 0x74, 0x91, 0x00, 0x05, 0x71, 0xa8, 0xbf, 0xc7, 0xc2, 0x4f, 0x8e, 0x00, 0x06, 0x04, 0x91, 0xad, 0xc2, 0xc8, 0xc2, 0x4b, 0x82, 0x00, 0x06, 0x47, 0x88, 0xab, 0xc1, 0xc6, 0xbd, 0x08, 0x8f, 0x00, 0x09, 0x71, 0xa8, 0xbf, 0xca, 0xce, 0xcf, 0xce, 0xca, 0xbb, 0x3f, 0x8d, 0x00, 0x05, 0x11, 0x76, 0x9a, 0xb8, 0xc8, 0xce, 0x90, 0xd0, 0x02, 0xce, 0xc7, 0x7f, 0x83, 0x00, 0x06, 0x0d, 0x6f, 0x93, 0xb3, 0xc5, 0xcd, 0xcf, 0x8b, 0xd0, 0x13, 0xcf, 0xce, 0xcd, 0xcc, 0xcb, 0xca, 0xc8, 0xc6, 0xc3, 0xc0, 0xbb, 0xb5, 0xaf, 0xa9, 0xa5, 0xa9, 0xb4, 0xc0, 0xc9, 0xce, 0x86, 0xd0, 0x02, 0xce, 0xca, 0xb2, 0x87, 0x00, 0x06, 0x07, 0x22, 0x57, 0x85, 0x9e, 0xae, 0x56, 0x90, 0x00, 0x06, 0x09, 0x80, 0xa4, 0xbc, 0xc6, 0xc0, 0x31, 0x8e, 0x00, 0x06, 0x1e, 0x8a, 0xab, 0xc0, 0xc6, 0xc0, 0x2d, 0x82, 0x00, 0x05, 0x5d, 0x8e, 0xaf, 0xc2, 0xc6, 0xa2, 0x85, 0x00, 0x04, 0x12, 0x25, 0x35, 0x2e, 0x0d, 0x83, 0x00, 0x08, 0x48, 0x9a, 0xb6, 0xc6, 0xcd, 0xce, 0xca, 0xb2, 0x24, 0x87, 0x00, 0x01, 0x0a, 0x17, 0x82, 0x00, 0x05, 0x21, 0x7a, 0x9f, 0xbc, 0xca, 0xcf, 0x8f, 0xd0, 0x03, 0xcf, 0xcd, 0xc5, 0x73, 0x83, 0x00, 0x05, 0x1d, 0x76, 0x9b, 0xb9, 0xc8, 0xce, 0x8e, 0xd0, 0x81, 0xcf, 0x0d, 0xce, 0xcd, 0xcc, 0xc8, 0xc3, 0xb7, 0x7a, 0x76, 0xab, 0xb0, 0xb9, 0xc3, 0xcb, 0xce, 0x86, 0xd0, 0x02, 0xce, 0xc7, 0x8f, 0x83, 0x00, 0x0a, 0x14, 0x3c, 0x5c, 0x6c, 0x74, 0x7e, 0x8a, 0x9e, 0xae, 0xb4, 0x39, 0x8e, 0x00, 0x08, 0x0d, 0x24, 0x5a, 0x8d, 0xa9, 0xbf, 0xc5, 0xbd, 0x14, 0x8b, 0x00, 0x09, 0x01, 0x12, 0x2a, 0x6c, 0x93, 0xaf, 0xc2, 0xc6, 0xbc, 0x11, 0x81, 0x00, 0x06, 0x03, 0x6f, 0x95, 0xb4, 0xc4, 0xc4, 0x81, 0x83, 0x00, 0x07, 0x07, 0x3c, 0x69, 0x76, 0x7e, 0x80, 0x76, 0x19, 0x82, 0x00, 0x07, 0x2d, 0x8e, 0xaf, 0xc3, 0xcc, 0xcb, 0xc2, 0x32, 0x84, 0x00, 0x05, 0x0a, 0x34, 0x4c, 0x63, 0x6d, 0x5b, 0x82, 0x00, 0x05, 0x32, 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0x8f, 0xd0, 0x03, 0xcf, 0xcd, 0xc4, 0x6d, 0x83, 0x00, 0x05, 0x2b, 0x7e, 0xa1, 0xbd, 0xca, 0xcf, 0x93, 0xd0, 0x0d, 0xcf, 0xcc, 0xc6, 0x5a, 0x1d, 0x03, 0x04, 0x1e, 0x64, 0xaf, 0xbe, 0xc8, 0xcd, 0xcf, 0x85, 0xd0, 0x02, 0xcd, 0xc6, 0x6f, 0x82, 0x00, 0x0b, 0x12, 0x5b, 0x72, 0x84, 0x91, 0x99, 0xa1, 0xab, 0xb4, 0xbc, 0xb8, 0x1d, 0x81, 0x00, 0x04, 0x01, 0x44, 0x4f, 0x57, 0x5b, 0x83, 0x5d, 0x0a, 0x5f, 0x69, 0x76, 0x7f, 0x8d, 0xa1, 0xb5, 0xc3, 0xc6, 0xb0, 0x01, 0x81, 0x00, 0x04, 0x0e, 0x47, 0x50, 0x59, 0x5c, 0x81, 0x5d, 0x09, 0x5f, 0x6e, 0x77, 0x82, 0x91, 0xa6, 0xba, 0xc6, 0xc6, 0xad, 0x82, 0x00, 0x06, 0x12, 0x76, 0x9b, 0xb8, 0xc6, 0xc2, 0x60, 0x82, 0x00, 0x08, 0x03, 0x4a, 0x70, 0x86, 0x97, 0xa0, 0xa2, 0x9b, 0x5f, 0x82, 0x00, 0x06, 0x22, 0x88, 0xab, 0xc1, 0xc9, 0xc5, 0x5f, 0x83, 0x00, 0x07, 0x04, 0x30, 0x64, 0x76, 0x83, 0x8c, 0x8e, 0x5d, 0x82, 0x00, 0x05, 0x46, 0x88, 0xab, 0xc2, 0xcc, 0xcf, 0x8f, 0xd0, 0x03, 0xcf, 0xcc, 0xc3, 0x66, 0x83, 0x00, 0x05, 0x2d, 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0x93, 0xd0, 0x03, 0xce, 0xc9, 0x8d, 0x0a, 0x81, 0x00, 0x05, 0x11, 0x88, 0xb0, 0xc2, 0xcb, 0xcf, 0x84, 0xd0, 0x03, 0xcf, 0xcc, 0xc3, 0x4f, 0x82, 0x00, 0x0b, 0x3b, 0x73, 0x8e, 0xa3, 0xb0, 0xb7, 0xbc, 0xc1, 0xc5, 0xc4, 0xb5, 0x04, 0x81, 0x00, 0x05, 0x0d, 0x60, 0x77, 0x89, 0x91, 0x93, 0x82, 0x94, 0x09, 0x95, 0x97, 0x9b, 0xa1, 0xab, 0xb7, 0xc2, 0xc8, 0xc6, 0x8f, 0x82, 0x00, 0x05, 0x1e, 0x66, 0x7c, 0x8a, 0x91, 0x93, 0x80, 0x94, 0x09, 0x95, 0x98, 0x9c, 0xa4, 0xad, 0xba, 0xc4, 0xca, 0xc6, 0x8b, 0x82, 0x00, 0x06, 0x22, 0x7c, 0xa0, 0xbb, 0xc6, 0xc1, 0x40, 0x82, 0x00, 0x08, 0x30, 0x6e, 0x8a, 0xa2, 0xb3, 0xbb, 0xbb, 0xb3, 0x86, 0x82, 0x00, 0x06, 0x29, 0x85, 0xa8, 0xbf, 0xc5, 0x92, 0x01, 0x82, 0x00, 0x08, 0x15, 0x57, 0x72, 0x86, 0x98, 0xa5, 0xab, 0xab, 0x53, 0x82, 0x00, 0x05, 0x5b, 0x8e, 0xaf, 0xc4, 0xcc, 0xcf, 0x8f, 0xd0, 0x03, 0xcf, 0xcc, 0xc2, 0x69, 0x83, 0x00, 0x05, 0x27, 0x82, 0xa6, 0xc0, 0xcc, 0xcf, 0x92, 0xd0, 0x03, 0xcf, 0xcd, 0xc5, 0x2b, 0x83, 0x00, 0x04, 0x44, 0xa0, 0xba, 0xc8, 0xce, 0x84, 0xd0, 0x03, 0xcf, 0xcc, 0xc0, 0x31, 0x82, 0x00, 0x0a, 0x5d, 0x86, 0xa4, 0xb9, 0xc3, 0xc7, 0xca, 0xcc, 0xcc, 0xc6, 0x9a, 0x82, 0x00, 0x04, 0x1b, 0x71, 0x8f, 0xa5, 0xb0, 0x84, 0xb4, 0x08, 0xb6, 0xb9, 0xbc, 0xc1, 0xc6, 0xcb, 0xcc, 0xc5, 0x6e, 0x82, 0x00, 0x04, 0x32, 0x77, 0x95, 0xa8, 0xb1, 0x81, 0xb4, 0x09, 0xb5, 0xb6, 0xba, 0xbe, 0xc2, 0xc7, 0xcb, 0xcc, 0xc5, 0x6a, 0x82, 0x00, 0x06, 0x35, 0x82, 0xa5, 0xbf, 0xc6, 0xbf, 0x22, 0x81, 0x00, 0x09, 0x03, 0x5f, 0x82, 0xa0, 0xb7, 0xc3, 0xc8, 0xc7, 0xc0, 0x86, 0x82, 0x00, 0x05, 0x2f, 0x85, 0xa8, 0xbd, 0xc0, 0x35, 0x82, 0x00, 0x09, 0x08, 0x59, 0x77, 0x90, 0xa4, 0xb4, 0xbd, 0xc0, 0xb9, 0x3c, 0x81, 0x00, 0x05, 0x03, 0x6f, 0x94, 0xb4, 0xc6, 0xcd, 0x90, 0xd0, 0x03, 0xcf, 0xcc, 0xc3, 0x70, 0x83, 0x00, 0x05, 0x20, 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0x92, 0xd0, 0x03, 0xcf, 0xcc, 0xc0, 0x15, 0x83, 0x00, 0x04, 0x3f, 0x96, 0xb4, 0xc6, 0xcd, 0x84, 0xd0, 0x03, 0xcf, 0xcb, 0xbe, 0x15, 0x81, 0x00, 0x0b, 0x11, 0x70, 0x94, 0xb2, 0xc3, 0xcc, 0xce, 0xcf, 0xcf, 0xcc, 0xc6, 0x79, 0x82, 0x00, 0x04, 0x2e, 0x7e, 0x9e, 0xb7, 0xc2, 0x84, 0xc6, 0x08, 0xc7, 0xc8, 0xca, 0xcc, 0xcd, 0xce, 0xcc, 0xc2, 0x4d, 0x82, 0x00, 0x04, 0x48, 0x86, 0xa5, 0xbb, 0xc3, 0x82, 0xc6, 0x08, 0xc7, 0xc9, 0xca, 0xcc, 0xcd, 0xce, 0xcc, 0xc2, 0x4a, 0x82, 0x00, 0x06, 0x48, 0x89, 0xab, 0xc1, 0xc6, 0xbb, 0x07, 0x81, 0x00, 0x09, 0x1a, 0x71, 0x93, 0xb1, 0xc2, 0xcb, 0xcd, 0xcc, 0xc3, 0x77, 0x82, 0x00, 0x05, 0x3f, 0x88, 0xa9, 0xbb, 0xa2, 0x01, 0x81, 0x00, 0x0a, 0x01, 0x46, 0x76, 0x92, 0xab, 0xbb, 0xc4, 0xc9, 0xc7, 0xbd, 0x21, 0x81, 0x00, 0x05, 0x11, 0x76, 0x9b, 0xb8, 0xc8, 0xce, 0x90, 0xd0, 0x03, 0xcf, 0xcc, 0xc4, 0x79, 0x83, 0x00, 0x05, 0x18, 0x7e, 0xa2, 0xbd, 0xcb, 0xcf, 0x92, 0xd0, 0x03, 0xce, 0xc9, 0xb8, 0x0d, 0x83, 0x00, 0x04, 0x63, 0x93, 0xb3, 0xc6, 0xcd, 0x84, 0xd0, 0x03, 0xce, 0xc9, 0xb3, 0x01, 0x81, 0x00, 0x0b, 0x29, 0x7a, 0x9e, 0xba, 0xc8, 0xce, 0xd0, 0xd0, 0xcf, 0xcc, 0xc3, 0x57, 0x82, 0x00, 0x04, 0x41, 0x86, 0xa8, 0xc0, 0xca, 0x83, 0xcd, 0x80, 0xce, 0x81, 0xcf, 0x02, 0xcc, 0xc0, 0x2e, 0x82, 0x00, 0x04, 0x5f, 0x8e, 0xaf, 0xc2, 0xcb, 0x81, 0xcd, 0x80, 0xce, 0x06, 0xcf, 0xcf, 0xd0, 0xcf, 0xcc, 0xc0, 0x2b, 0x82, 0x00, 0x05, 0x5f, 0x8f, 0xb0, 0xc2, 0xc6, 0xa1, 0x82, 0x00, 0x09, 0x37, 0x7e, 0xa0, 0xbb, 0xc8, 0xce, 0xcf, 0xcc, 0xc3, 0x5d, 0x82, 0x00, 0x04, 0x52, 0x8c, 0xab, 0xba, 0x52, 0x82, 0x00, 0x0a, 0x22, 0x6d, 0x8b, 0xa8, 0xbc, 0xc7, 0xcc, 0xcd, 0xc9, 0xbb, 0x07, 0x81, 0x00, 0x05, 0x21, 0x7a, 0xa0, 0xbc, 0xca, 0xcf, 0x90, 0xd0, 0x04, 0xcf, 0xcd, 0xc5, 0x9b, 0x01, 0x82, 0x00, 0x05, 0x04, 0x6f, 0x9e, 0xba, 0xc9, 0xce, 0x92, 0xd0, 0x02, 0xcd, 0xc7, 0x8b, 0x83, 0x00, 0x05, 0x0a, 0x71, 0x96, 0xb4, 0xc6, 0xce, 0x84, 0xd0, 0x02, 0xce, 0xc7, 0x93, 0x82, 0x00, 0x0b, 0x42, 0x84, 0xa7, 0xc0, 0xcb, 0xcf, 0xd0, 0xd0, 0xcf, 0xcc, 0xc1, 0x38, 0x82, 0x00, 0x05, 0x56, 0x8d, 0xae, 0xc3, 0xcc, 0xcf, 0x88, 0xd0, 0x03, 0xcf, 0xcb, 0xbe, 0x11, 0x81, 0x00, 0x06, 0x04, 0x70, 0x95, 0xb4, 0xc6, 0xcd, 0xcf, 0x86, 0xd0, 0x03, 0xcf, 0xcb, 0xbd, 0x10, 0x81, 0x00, 0x06, 0x04, 0x70, 0x95, 0xb4, 0xc4, 0xc4, 0x7f, 0x82, 0x00, 0x09, 0x4d, 0x87, 0xa9, 0xc1, 0xcc, 0xcf, 0xcf, 0xcc, 0xc2, 0x40, 0x82, 0x00, 0x04, 0x67, 0x91, 0xae, 0xb7, 0x21, 0x82, 0x00, 0x09, 0x3f, 0x7c, 0x9e, 0xb7, 0xc6, 0xcc, 0xcf, 0xce, 0xc8, 0xa1, 0x82, 0x00, 0x05, 0x32, 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0x91, 0xd0, 0x03, 0xce, 0xc6, 0xb5, 0x17, 0x83, 0x00, 0x05, 0x44, 0x94, 0xb3, 0xc6, 0xcd, 0xcf, 0x90, 0xd0, 0x03, 0xcf, 0xcc, 0xc3, 0x53, 0x83, 0x00, 0x05, 0x17, 0x76, 0x9b, 0xb9, 0xc8, 0xce, 0x84, 0xd0, 0x02, 0xcd, 0xc6, 0x71, 0x82, 0x00, 0x0b, 0x59, 0x8c, 0xae, 0xc3, 0xcc, 0xcf, 0xd0, 0xd0, 0xcf, 0xcb, 0xbf, 0x1a, 0x81, 0x00, 0x05, 0x01, 0x6a, 0x93, 0xb3, 0xc6, 0xcd, 0x89, 0xd0, 0x02, 0xce, 0xc9, 0xaf, 0x82, 0x00, 0x05, 0x14, 0x76, 0x9b, 0xb9, 0xc8, 0xce, 0x87, 0xd0, 0x02, 0xce, 0xc9, 0xac, 0x82, 0x00, 0x06, 0x13, 0x76, 0x9b, 0xb8, 0xc6, 0xc2, 0x5f, 0x82, 0x00, 0x09, 0x63, 0x8f, 0xb1, 0xc4, 0xcd, 0xcf, 0xcf, 0xcb, 0xc0, 0x24, 0x81, 0x00, 0x05, 0x0a, 0x72, 0x97, 0xb2, 0xb5, 0x0a, 0x82, 0x00, 0x09, 0x5b, 0x89, 0xab, 0xc0, 0xcb, 0xcf, 0xcf, 0xce, 0xc6, 0x80, 0x82, 0x00, 0x05, 0x47, 0x88, 0xab, 0xc2, 0xcc, 0xcf, 0x91, 0xd0, 0x03, 0xce, 0xc9, 0xbb, 0x3a, 0x83, 0x00, 0x05, 0x1e, 0x89, 0xab, 0xc0, 0xcb, 0xcf, 0x90, 0xd0, 0x03, 0xce, 0xca, 0xb7, 0x14, 0x83, 0x00, 0x05, 0x25, 0x7e, 0xa2, 0xbd, 0xcb, 0xcf, 0x83, 0xd0, 0x03, 0xcf, 0xcc, 0xc3, 0x52, 0x81, 0x00, 0x05, 0x03, 0x6d, 0x93, 0xb4, 0xc6, 0xcd, 0x80, 0xd0, 0x03, 0xce, 0xca, 0xb7, 0x03, 0x81, 0x00, 0x05, 0x0d, 0x73, 0x99, 0xb7, 0xc8, 0xce, 0x89, 0xd0, 0x02, 0xce, 0xc7, 0x8c, 0x82, 0x00, 0x05, 0x24, 0x7c, 0xa1, 0xbc, 0xca, 0xcf, 0x87, 0xd0, 0x02, 0xce, 0xc7, 0x8a, 0x82, 0x00, 0x06, 0x24, 0x7c, 0xa0, 0xbb, 0xc6, 0xc1, 0x3f, 0x81, 0x00, 0x0a, 0x07, 0x71, 0x97, 0xb5, 0xc7, 0xce, 0xd0, 0xcf, 0xca, 0xbc, 0x09, 0x81, 0x00, 0x04, 0x19, 0x79, 0x9c, 0xb4, 0xa5, 0x82, 0x00, 0x0a, 0x08, 0x6d, 0x92, 0xb2, 0xc5, 0xcd, 0xcf, 0xcf, 0xcd, 0xc4, 0x5f, 0x82, 0x00, 0x05, 0x5c, 0x8e, 0xb0, 0xc4, 0xcc, 0xcf, 0x91, 0xd0, 0x03, 0xcf, 0xcb, 0xc0, 0x6e, 0x83, 0x00, 0x06, 0x01, 0x58, 0x9e, 0xb8, 0xc6, 0xcd, 0xcf, 0x8e, 0xd0, 0x03, 0xcf, 0xcc, 0xc5, 0x69, 0x84, 0x00, 0x05, 0x42, 0x86, 0xa9, 0xc1, 0xcc, 0xcf, 0x83, 0xd0, 0x03, 0xcf, 0xcc, 0xc1, 0x34, 0x81, 0x00, 0x05, 0x11, 0x76, 0x9a, 0xb8, 0xc8, 0xce, 0x80, 0xd0, 0x02, 0xce, 0xc8, 0x98, 0x82, 0x00, 0x05, 0x1d, 0x7a, 0x9e, 0xbb, 0xc8, 0xcd, 0x86, 0xcf, 0x80, 0xd0, 0x02, 0xcd, 0xc5, 0x6a, 0x82, 0x00, 0x05, 0x37, 0x82, 0xa6, 0xc0, 0xcc, 0xcf, 0x86, 0xd0, 0x03, 0xcf, 0xcd, 0xc5, 0x69, 0x82, 0x00, 0x06, 0x35, 0x82, 0xa6, 0xbf, 0xc6, 0xbf, 0x21, 0x81, 0x00, 0x09, 0x18, 0x77, 0x9c, 0xba, 0xc9, 0xce, 0xd0, 0xce, 0xc8, 0xa5, 0x82, 0x00, 0x04, 0x2a, 0x7e, 0xa1, 0xb6, 0x95, 0x82, 0x00, 0x0a, 0x06, 0x70, 0x95, 0xb4, 0xc6, 0xcd, 0xcf, 0xce, 0xcc, 0xc1, 0x40, 0x81, 0x00, 0x05, 0x03, 0x6f, 0x95, 0xb4, 0xc6, 0xcd, 0x92, 0xd0, 0x04, 0xcf, 0xcc, 0xc3, 0xab, 0x10, 0x83, 0x00, 0x05, 0x17, 0x8b, 0xab, 0xc0, 0xca, 0xce, 0x8e, 0xd0, 0x03, 0xce, 0xc9, 0xa9, 0x12, 0x83, 0x00, 0x06, 0x0b, 0x6d, 0x91, 0xb1, 0xc4, 0xcd, 0xcf, 0x83, 0xd0, 0x03, 0xcf, 0xcb, 0xbe, 0x18, 0x81, 0x00, 0x05, 0x21, 0x7a, 0x9f, 0xbc, 0xca, 0xce, 0x80, 0xd0, 0x02, 0xcd, 0xc6, 0x76, 0x82, 0x00, 0x05, 0x2d, 0x7d, 0x9f, 0xba, 0xc6, 0xca, 0x83, 0xcb, 0x08, 0xcc, 0xcc, 0xcd, 0xce, 0xcf, 0xcf, 0xcc, 0xc2, 0x4a, 0x82, 0x00, 0x05, 0x4a, 0x89, 0xab, 0xc2, 0xcc, 0xcf, 0x86, 0xd0, 0x03, 0xcf, 0xcc, 0xc2, 0x49, 0x82, 0x00, 0x06, 0x4a, 0x89, 0xab, 0xc1, 0xc6, 0xbb, 0x07, 0x81, 0x00, 0x09, 0x28, 0x7e, 0xa2, 0xbd, 0xcb, 0xcf, 0xd0, 0xce, 0xc6, 0x84, 0x82, 0x00, 0x05, 0x3e, 0x85, 0xa7, 0xb9, 0xb1, 0x04, 0x82, 0x00, 0x09, 0x5c, 0x91, 0xb0, 0xc2, 0xc9, 0xcc, 0xcc, 0xc7, 0xbc, 0x23, 0x81, 0x00, 0x05, 0x11, 0x76, 0x9b, 0xb8, 0xc8, 0xce, 0x93, 0xd0, 0x03, 0xcd, 0xc7, 0xb8, 0x42, 0x84, 0x00, 0x05, 0x3c, 0x99, 0xb3, 0xc3, 0xcb, 0xce, 0x8b, 0xd0, 0x04, 0xcf, 0xce, 0xcb, 0xc2, 0x3f, 0x84, 0x00, 0x05, 0x2a, 0x7a, 0x9c, 0xb9, 0xc8, 0xce, 0x84, 0xd0, 0x03, 0xce, 0xc9, 0xb4, 0x01, 0x81, 0x00, 0x0b, 0x32, 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0xd0, 0xd0, 0xcf, 0xcc, 0xc3, 0x55, 0x82, 0x00, 0x05, 0x3c, 0x7c, 0x9b, 0xb1, 0xbb, 0xbe, 0x82, 0xbf, 0x09, 0xc0, 0xc0, 0xc2, 0xc6, 0xca, 0xcd, 0xce, 0xcc, 0xc0, 0x2b, 0x82, 0x00, 0x05, 0x60, 0x8f, 0xb1, 0xc4, 0xcd, 0xcf, 0x86, 0xd0, 0x03, 0xcf, 0xcc, 0xc0, 0x2a, 0x82, 0x00, 0x05, 0x60, 0x8f, 0xb0, 0xc3, 0xc6, 0xa0, 0x82, 0x00, 0x09, 0x3b, 0x84, 0xa8, 0xc0, 0xcc, 0xcf, 0xcf, 0xcd, 0xc5, 0x64, 0x82, 0x00, 0x05, 0x52, 0x8b, 0xab, 0xbc, 0xb6, 0x24, 0x82, 0x00, 0x09, 0x10, 0x76, 0xa0, 0xb4, 0xbd, 0xc1, 0xc2, 0xbe, 0xb3, 0x08, 0x81, 0x00, 0x05, 0x21, 0x7a, 0xa0, 0xbc, 0xca, 0xcf, 0x93, 0xd0, 0x04, 0xcf, 0xcb, 0xc0, 0x97, 0x0a, 0x83, 0x00, 0x07, 0x01, 0x4f, 0xa0, 0xb6, 0xc4, 0xcb, 0xce, 0xcf, 0x88, 0xd0, 0x05, 0xcf, 0xce, 0xcb, 0xc2, 0x5d, 0x01, 0x83, 0x00, 0x06, 0x07, 0x5d, 0x89, 0xa9, 0xc0, 0xcb, 0xcf, 0x84, 0xd0, 0x02, 0xce, 0xc7, 0x96, 0x82, 0x00, 0x0b, 0x47, 0x88, 0xab, 0xc2, 0xcc, 0xcf, 0xd0, 0xd0, 0xcf, 0xcc, 0xc1, 0x37, 0x82, 0x00, 0x04, 0x17, 0x28, 0x2f, 0x35, 0x37, 0x83, 0x38, 0x09, 0x39, 0x52, 0x81, 0xb3, 0xc0, 0xc7, 0xcc, 0xca, 0xbd, 0x0e, 0x81, 0x00, 0x05, 0x04, 0x71, 0x96, 0xb5, 0xc6, 0xce, 0x87, 0xd0, 0x03, 0xcf, 0xcb, 0xbd, 0x0e, 0x81, 0x00, 0x06, 0x04, 0x71, 0x96, 0xb4, 0xc5, 0xc4, 0x7e, 0x82, 0x00, 0x09, 0x4f, 0x8a, 0xac, 0xc2, 0xcc, 0xcf, 0xcf, 0xcc, 0xc2, 0x46, 0x82, 0x00, 0x05, 0x69, 0x92, 0xb1, 0xc0, 0xbb, 0x48, 0x83, 0x00, 0x07, 0x01, 0x25, 0x4d, 0x5f, 0x6d, 0x6d, 0x66, 0x53, 0x82, 0x00, 0x05, 0x34, 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0x93, 0xd0, 0x04, 0xcf, 0xcd, 0xc5, 0xb4, 0x4d, 0x84, 0x00, 0x08, 0x04, 0x59, 0xa2, 0xb6, 0xc2, 0xca, 0xcd, 0xcf, 0xcf, 0x84, 0xd0, 0x06, 0xcf, 0xce, 0xcd, 0xc9, 0xc2, 0x60, 0x01, 0x84, 0x00, 0x06, 0x31, 0x77, 0x99, 0xb4, 0xc6, 0xcd, 0xcf, 0x84, 0xd0, 0x02, 0xcd, 0xc6, 0x76, 0x82, 0x00, 0x0b, 0x5d, 0x8e, 0xb0, 0xc4, 0xcc, 0xcf, 0xd0, 0xd0, 0xcf, 0xcb, 0xbf, 0x19, 0x90, 0x00, 0x05, 0x59, 0xae, 0xbf, 0xc8, 0xc7, 0xab, 0x82, 0x00, 0x05, 0x15, 0x76, 0x9c, 0xba, 0xc8, 0xce, 0x87, 0xd0, 0x02, 0xce, 0xc9, 0xab, 0x82, 0x00, 0x06, 0x15, 0x76, 0x9c, 0xb9, 0xc6, 0xc3, 0x5d, 0x82, 0x00, 0x09, 0x66, 0x91, 0xb2, 0xc5, 0xcd, 0xcf, 0xcf, 0xcc, 0xc0, 0x29, 0x81, 0x00, 0x06, 0x0a, 0x73, 0x98, 0xb5, 0xc3, 0xc0, 0x7c, 0x90, 0x00, 0x05, 0x48, 0x88, 0xab, 0xc2, 0xcc, 0xcf, 0x94, 0xd0, 0x04, 0xce, 0xca, 0xbf, 0x9f, 0x19, 0x84, 0x00, 0x08, 0x01, 0x3e, 0x9c, 0xb3, 0xbf, 0xc6, 0xcb, 0xcd, 0xce, 0x82, 0xcf, 0x06, 0xce, 0xcc, 0xca, 0xc6, 0xb1, 0x42, 0x01, 0x84, 0x00, 0x06, 0x10, 0x67, 0x8a, 0xa9, 0xbf, 0xca, 0xce, 0x84, 0xd0, 0x03, 0xcf, 0xcc, 0xc4, 0x56, 0x81, 0x00, 0x05, 0x04, 0x71, 0x96, 0xb5, 0xc6, 0xcd, 0x80, 0xd0, 0x03, 0xcf, 0xca, 0xbd, 0x07, 0x90, 0x00, 0x05, 0x18, 0x9b, 0xb4, 0xc3, 0xc5, 0x8c, 0x82, 0x00, 0x05, 0x28, 0x7f, 0xa3, 0xbe, 0xca, 0xcf, 0x87, 0xd0, 0x02, 0xce, 0xc8, 0x8c, 0x82, 0x00, 0x06, 0x29, 0x7f, 0xa3, 0xbd, 0xc6, 0xc2, 0x3f, 0x81, 0x00, 0x0a, 0x09, 0x73, 0x98, 0xb7, 0xc7, 0xce, 0xd0, 0xcf, 0xcb, 0xbe, 0x0e, 0x81, 0x00, 0x07, 0x1a, 0x7a, 0x9e, 0xbb, 0xc6, 0xc3, 0xb3, 0x2f, 0x8f, 0x00, 0x05, 0x5d, 0x8f, 0xb1, 0xc4, 0xcd, 0xcf, 0x94, 0xd0, 0x05, 0xcf, 0xcc, 0xc6, 0xb6, 0x83, 0x0e, 0x85, 0x00, 0x07, 0x1e, 0x66, 0xa9, 0xb6, 0xc0, 0xc5, 0xc8, 0xca, 0x80, 0xcb, 0x05, 0xca, 0xc7, 0xc4, 0xbe, 0x77, 0x19, 0x85, 0x00, 0x07, 0x04, 0x4e, 0x7e, 0x9e, 0xb6, 0xc6, 0xcd, 0xcf, 0x84, 0xd0, 0x03, 0xcf, 0xcc, 0xc3, 0x48, 0x81, 0x00, 0x05, 0x25, 0x7a, 0x9e, 0xbb, 0xc9, 0xce, 0x80, 0xd0, 0x03, 0xcf, 0xca, 0xbd, 0x0e, 0x90, 0x00, 0x05, 0x21, 0x8f, 0xad, 0xc1, 0xc3, 0x85, 0x82, 0x00, 0x05, 0x54, 0x89, 0xab, 0xc1, 0xcc, 0xcf, 0x87, 0xd0, 0x02, 0xce, 0xc7, 0x82, 0x82, 0x00, 0x06, 0x55, 0x89, 0xab, 0xc1, 0xc7, 0xc1, 0x37, 0x81, 0x00, 0x0a, 0x2b, 0x7e, 0xa0, 0xbc, 0xca, 0xcf, 0xd0, 0xcf, 0xcb, 0xbd, 0x08, 0x81, 0x00, 0x08, 0x3f, 0x84, 0xa7, 0xbf, 0xc9, 0xc8, 0xbd, 0x99, 0x1d, 0x8d, 0x00, 0x05, 0x0e, 0x74, 0x98, 0xb6, 0xc6, 0xce, 0x96, 0xd0, 0x05, 0xce, 0xcb, 0xc2, 0xb0, 0x73, 0x08, 0x86, 0x00, 0x0c, 0x1a, 0x57, 0x99, 0xb3, 0xb8, 0xbc, 0xbe, 0xbf, 0xbe, 0xbc, 0x97, 0x63, 0x1d, 0x87, 0x00, 0x06, 0x37, 0x76, 0x93, 0xae, 0xc1, 0xcb, 0xcf, 0x85, 0xd0, 0x03, 0xcf, 0xcc, 0xc3, 0x7c, 0x81, 0x00, 0x05, 0x58, 0x89, 0xa9, 0xc0, 0xcb, 0xcf, 0x80, 0xd0, 0x03, 0xcf, 0xcb, 0xbf, 0x48, 0x8f, 0x00, 0x07, 0x03, 0x5b, 0x91, 0xae, 0xc1, 0xc4, 0xb4, 0x0a, 0x80, 0x00, 0x05, 0x15, 0x76, 0x96, 0xb3, 0xc5, 0xcd, 0x88, 0xd0, 0x03, 0xce, 0xc7, 0xb0, 0x07, 0x80, 0x00, 0x07, 0x17, 0x76, 0x96, 0xb3, 0xc5, 0xc9, 0xc2, 0x6d, 0x80, 0x00, 0x0b, 0x01, 0x5f, 0x8b, 0xab, 0xc1, 0xcc, 0xcf, 0xd0, 0xcf, 0xcb, 0xbf, 0x3f, 0x80, 0x00, 0x0b, 0x09, 0x70, 0x92, 0xb0, 0xc3, 0xcc, 0xcc, 0xc5, 0xb4, 0x98, 0x3f, 0x0d, 0x8b, 0x00, 0x05, 0x40, 0x83, 0xa4, 0xbd, 0xca, 0xcf, 0x97, 0xd0, 0x05, 0xce, 0xc9, 0xbe, 0xab, 0x63, 0x04, 0x87, 0x00, 0x07, 0x03, 0x13, 0x28, 0x3f, 0x44, 0x3e, 0x35, 0x18, 0x89, 0x00, 0x06, 0x29, 0x70, 0x8c, 0xa8, 0xbd, 0xc8, 0xcd, 0x86, 0xd0, 0x0d, 0xcf, 0xcd, 0xc6, 0xb3, 0x4a, 0x11, 0x1e, 0x4c, 0x81, 0x9b, 0xb4, 0xc6, 0xcd, 0xcf, 0x80, 0xd0, 0x07, 0xcf, 0xcc, 0xc3, 0xaf, 0x63, 0x3c, 0x21, 0x11, 0x89, 0x0e, 0x12, 0x17, 0x29, 0x5f, 0x83, 0x9e, 0xb6, 0xc5, 0xc7, 0xbd, 0x76, 0x2b, 0x0d, 0x1e, 0x62, 0x8a, 0xa6, 0xbd, 0xc9, 0xce, 0x88, 0xd0, 0x32, 0xce, 0xc9, 0xbd, 0x6e, 0x24, 0x0d, 0x21, 0x63, 0x8a, 0xa6, 0xbd, 0xc9, 0xcc, 0xc5, 0xab, 0x46, 0x0e, 0x21, 0x4f, 0x82, 0x9e, 0xb6, 0xc6, 0xcd, 0xd0, 0xd0, 0xcf, 0xcc, 0xc2, 0x9a, 0x3f, 0x13, 0x2b, 0x5c, 0x87, 0xa3, 0xbb, 0xc8, 0xcd, 0xce, 0xcb, 0xc2, 0xb4, 0xa0, 0x8c, 0x60, 0x35, 0x28, 0x1e, 0x19, 0x13, 0x83, 0x0e, 0x07, 0x1d, 0x44, 0x7a, 0x96, 0xb1, 0xc3, 0xcc, 0xcf, 0x97, 0xd0, 0x06, 0xcf, 0xcd, 0xc7, 0xbb, 0xa8, 0x55, 0x01, 0x99, 0x00, 0x07, 0x2a, 0x6d, 0x88, 0xa3, 0xb9, 0xc6, 0xcc, 0xcf, 0x87, 0xd0, 0x0b, 0xce, 0xca, 0xbf, 0xac, 0x99, 0x8d, 0x8e, 0x9b, 0xaf, 0xc0, 0xca, 0xce, 0x82, 0xd0, 0x07, 0xce, 0xc8, 0xbd, 0xab, 0x9a, 0x8b, 0x82, 0x7e, 0x88, 0x7a, 0x12, 0x7d, 0x82, 0x8e, 0x9e, 0xb2, 0xc1, 0xca, 0xcb, 0xc3, 0xb4, 0x9f, 0x8e, 0x89, 0x90, 0xa2, 0xb6, 0xc5, 0xcc, 0xcf, 0x88, 0xd0, 0x17, 0xcf, 0xcc, 0xc3, 0xb3, 0x9e, 0x8e, 0x88, 0x90, 0xa2, 0xb6, 0xc5, 0xcc, 0xcd, 0xc9, 0xbe, 0xab, 0x98, 0x8c, 0x8e, 0x9e, 0xb1, 0xc1, 0xcb, 0xce, 0x80, 0xd0, 0x18, 0xcd, 0xc7, 0xbb, 0xa7, 0x95, 0x8d, 0x92, 0xa0, 0xb4, 0xc3, 0xcc, 0xcf, 0xcf, 0xce, 0xca, 0xc3, 0xb9, 0xab, 0x9e, 0x93, 0x8a, 0x85, 0x81, 0x7e, 0x7c, 0x82, 0x7a, 0x06, 0x7f, 0x89, 0x98, 0xab, 0xbe, 0xc9, 0xce, 0x99, 0xd0, 0x06, 0xcf, 0xcc, 0xc6, 0xba, 0xa5, 0x4f, 0x08, 0x96, 0x00, 0x08, 0x03, 0x2f, 0x69, 0x85, 0xa0, 0xb6, 0xc4, 0xcc, 0xcf, 0x88, 0xd0, 0x0b, 0xcf, 0xcd, 0xc7, 0xbe, 0xb3, 0xab, 0xac, 0xb4, 0xc0, 0xc8, 0xcd, 0xcf, 0x82, 0xd0, 0x08, 0xcf, 0xcc, 0xc7, 0xbf, 0xb4, 0xab, 0xa6, 0xa2, 0xa0, 0x86, 0x9e, 0x12, 0x9f, 0xa1, 0xa5, 0xac, 0xb7, 0xc2, 0xc9, 0xcd, 0xcd, 0xca, 0xc2, 0xb6, 0xac, 0xa9, 0xae, 0xb8, 0xc3, 0xcb, 0xce, 0x89, 0xd0, 0x17, 0xcf, 0xce, 0xca, 0xc1, 0xb5, 0xac, 0xa9, 0xae, 0xb8, 0xc3, 0xcb, 0xce, 0xcf, 0xcc, 0xc6, 0xbd, 0xb3, 0xab, 0xad, 0xb5, 0xc0, 0xc9, 0xcd, 0xcf, 0x80, 0xd0, 0x19, 0xcf, 0xcc, 0xc5, 0xbb, 0xb1, 0xab, 0xaf, 0xb8, 0xc2, 0xca, 0xce, 0xd0, 0xd0, 0xcf, 0xce, 0xcc, 0xc6, 0xc1, 0xba, 0xb3, 0xac, 0xa8, 0xa4, 0xa3, 0xa1, 0x9f, 0x80, 0x9e, 0x07, 0xa0, 0xa4, 0xa9, 0xb3, 0xbf, 0xc7, 0xcc, 0xcf, 0x9a, 0xd0, 0x07, 0xcf, 0xcc, 0xc6, 0xb9, 0xa5, 0x7a, 0x29, 0x01, 0x93, 0x00, 0x08, 0x04, 0x0b, 0x5d, 0x7a, 0x9a, 0xb3, 0xc3, 0xcb, 0xce, 0x8a, 0xd0, 0x09, 0xcf, 0xcc, 0xc9, 0xc4, 0xc2, 0xc2, 0xc6, 0xca, 0xcd, 0xcf, 0x84, 0xd0, 0x08, 0xcf, 0xcc, 0xca, 0xc6, 0xc2, 0xc0, 0xbd, 0xbc, 0xbc, 0x84, 0xbb, 0x13, 0xbc, 0xbc, 0xbd, 0xbf, 0xc2, 0xc6, 0xcb, 0xcd, 0xcf, 0xcf, 0xcd, 0xcb, 0xc6, 0xc2, 0xc1, 0xc2, 0xc6, 0xcb, 0xce, 0xcf, 0x8a, 0xd0, 0x15, 0xcf, 0xcd, 0xca, 0xc6, 0xc2, 0xc0, 0xc2, 0xc6, 0xcb, 0xce, 0xcf, 0xd0, 0xcf, 0xcc, 0xc8, 0xc4, 0xc2, 0xc2, 0xc6, 0xca, 0xcd, 0xcf, 0x81, 0xd0, 0x0a, 0xcf, 0xce, 0xcc, 0xc7, 0xc3, 0xc2, 0xc3, 0xc6, 0xcb, 0xce, 0xcf, 0x81, 0xd0, 0x09, 0xcf, 0xcd, 0xcc, 0xc8, 0xc5, 0xc2, 0xc0, 0xbf, 0xbe, 0xbd, 0x82, 0xbc, 0x05, 0xbe, 0xc1, 0xc5, 0xc9, 0xcd, 0xcf, 0x9c, 0xd0, 0x07, 0xcf, 0xcc, 0xc5, 0xba, 0xab, 0x96, 0x5a, 0x15, 0x90, 0x00, 0x0a, 0x01, 0x03, 0x00, 0x01, 0x31, 0x84, 0xa4, 0xbc, 0xc8, 0xcd, 0xcf, 0x8b, 0xd0, 0x09, 0xcf, 0xce, 0xcc, 0xcc, 0xca, 0xcb, 0xcc, 0xcc, 0xce, 0xcf, 0x99, 0xd0, 0x0d, 0xcf, 0xce, 0xcd, 0xcd, 0xce, 0xcf, 0xd0, 0xd0, 0xcf, 0xce, 0xcd, 0xcd, 0xce, 0xcf, 0xe8, 0xd0, 0x08, 0xcf, 0xcc, 0xc6, 0xbf, 0xb2, 0xa1, 0x8a, 0x3f, 0x0a, 0x8c, 0x00, 0x01, 0x04, 0x04, 0x81, 0x00, 0x05, 0x0d, 0x76, 0xa1, 0xbb, 0xc8, 0xce, 0x8b, 0xd0, 0x0b, 0xcf, 0xce, 0xca, 0xc5, 0xc0, 0xbe, 0xbe, 0xc0, 0xc5, 0xca, 0xcd, 0xcf, 0x8f, 0xd0, 0x01, 0xcf, 0xcf, 0x83, 0xd0, 0x0f, 0xcf, 0xcd, 0xcb, 0xc7, 0xc6, 0xc9, 0xcc, 0xce, 0xce, 0xcc, 0xc9, 0xc6, 0xc6, 0xca, 0xcd, 0xcf, 0xc7, 0xd0, 0x00, 0xcf, 0x9d, 0xd0, 0x0a, 0xcf, 0xcc, 0xc9, 0xc3, 0xba, 0xab, 0x9b, 0x86, 0x50, 0x29, 0x0b, 0x85, 0x00, 0x03, 0x03, 0x11, 0x22, 0x0e, 0x84, 0x00, 0x05, 0x25, 0x94, 0xb2, 0xc3, 0xcc, 0xcf, 0x8a, 0xd0, 0x0c, 0xce, 0xcb, 0x76, 0x04, 0x04, 0x08, 0x1e, 0x6d, 0xb4, 0xc0, 0xc8, 0xcd, 0xcf, 0x8c, 0xd0, 0x05, 0xcf, 0xce, 0xcd, 0xcd, 0xce, 0xcf, 0x81, 0xd0, 0x0f, 0xce, 0xca, 0x7a, 0x08, 0xb0, 0xbf, 0xc6, 0xcc, 0xcc, 0xc5, 0x1e, 0x3c, 0xba, 0xc1, 0xc9, 0xce, 0xc4, 0xd0, 0x06, 0xcf, 0xcf, 0xce, 0xcd, 0xce, 0xcf, 0xcf, 0x9b, 0xd0, 0x0c, 0xcf, 0xce, 0xcc, 0xc7, 0xc0, 0xb6, 0xab, 0x9c, 0x8f, 0x84, 0x6d, 0x52, 0x3f, 0x80, 0x3a, 0x06, 0x3c, 0x4a, 0x66, 0x72, 0x76, 0x4f, 0x06, 0x83, 0x00, 0x05, 0x08, 0x66, 0xa3, 0xbb, 0xc8, 0xce, 0x89, 0xd0, 0x0d, 0xcf, 0xcd, 0xc6, 0x59, 0x00, 0x0d, 0x08, 0x00, 0x00, 0x76, 0xb1, 0xc1, 0xca, 0xce, 0x8b, 0xd0, 0x1b, 0xcf, 0xcc, 0xca, 0xc7, 0xc7, 0xcb, 0xcd, 0xcf, 0xd0, 0xd0, 0xcf, 0xcc, 0xc4, 0x2b, 0x00, 0x76, 0xaf, 0xbe, 0xc7, 0xc6, 0x7e, 0x00, 0x1b, 0xa6, 0xb5, 0xc4, 0xcc, 0xcf, 0xc2, 0xd0, 0x08, 0xcf, 0xce, 0xcc, 0xc9, 0xc7, 0xc8, 0xcc, 0xce, 0xcf, 0x9c, 0xd0, 0x0b, 0xcf, 0xcd, 0xcb, 0xc6, 0xc0, 0xb8, 0xaf, 0xa7, 0x9e, 0x98, 0x91, 0x8d, 0x80, 0x8a, 0x05, 0x8d, 0x92, 0x97, 0x98, 0x92, 0x25, 0x84, 0x00, 0x05, 0x19, 0x90, 0xad, 0xc1, 0xcb, 0xcf, 0x88, 0xd0, 0x0d, 0xcf, 0xcc, 0xc3, 0x3f, 0x00, 0x6a, 0x7d, 0x3e, 0x00, 0x3c, 0xa2, 0xb8, 0xc6, 0xcd, 0x81, 0xcf, 0x83, 0xd0, 0x81, 0xcf, 0x1c, 0xcc, 0xc0, 0x24, 0x50, 0xbd, 0xc3, 0xcb, 0xce, 0xd0, 0xd0, 0xce, 0xc9, 0xa3, 0x00, 0x00, 0x44, 0x9e, 0xb4, 0xc1, 0xc0, 0x22, 0x00, 0x04, 0x93, 0xa9, 0xbf, 0xcb, 0xcf, 0xd0, 0x82, 0xcf, 0x80, 0xd0, 0x81, 0xcf, 0x83, 0xd0, 0x82, 0xcf, 0x82, 0xd0, 0x82, 0xcf, 0x81, 0xd0, 0x80, 0xcf, 0x81, 0xd0, 0x85, 0xcf, 0x82, 0xd0, 0x80, 0xcf, 0x81, 0xd0, 0x81, 0xcf, 0x08, 0xce, 0xcc, 0x93, 0x23, 0x7a, 0xbf, 0xc6, 0xcc, 0xcf, 0x9d, 0xd0, 0x14, 0xcf, 0xcf, 0xcd, 0xcb, 0xc7, 0xc3, 0xc0, 0xbb, 0xb5, 0xb2, 0xae, 0xac, 0xab, 0xac, 0xaf, 0xb3, 0xb5, 0xb5, 0xae, 0x88, 0x0e, 0x83, 0x00, 0x06, 0x03, 0x48, 0x9e, 0xb7, 0xc6, 0xcd, 0xcf, 0x87, 0xd0, 0x0c, 0xcf, 0xcb, 0xc0, 0x29, 0x00, 0x77, 0x7f, 0x60, 0x00, 0x32, 0x99, 0xb2, 0xc3, 0x81, 0xcc, 0x01, 0xcd, 0xce, 0x80, 0xcf, 0x01, 0xce, 0xcd, 0x81, 0xcc, 0x13, 0xc9, 0xa1, 0x00, 0x46, 0xac, 0xba, 0xc6, 0xcc, 0xcf, 0xcf, 0xcd, 0xc5, 0x58, 0x00, 0x00, 0x1b, 0x8f, 0xa9, 0xb9, 0x84, 0x80, 0x00, 0x03, 0x79, 0xa0, 0xbb, 0xc8, 0x80, 0xcd, 0x01, 0xcc, 0xcc, 0x80, 0xcd, 0x0b, 0xce, 0xce, 0xcd, 0xcd, 0xcc, 0xcc, 0xcd, 0xce, 0xcf, 0xcf, 0xce, 0xcd, 0x80, 0xcc, 0x06, 0xcd, 0xcd, 0xce, 0xce, 0xcf, 0xce, 0xcd, 0x80, 0xcc, 0x01, 0xcd, 0xcd, 0x80, 0xce, 0x03, 0xcd, 0xcc, 0xcc, 0xcd, 0x81, 0xce, 0x00, 0xcd, 0x83, 0xcc, 0x08, 0xcd, 0xcd, 0xce, 0xcf, 0xce, 0xce, 0xcd, 0xcc, 0xcd, 0x80, 0xce, 0x01, 0xcd, 0xcd, 0x81, 0xcc, 0x08, 0xc6, 0x6c, 0x00, 0x73, 0xb1, 0xbe, 0xc8, 0xcd, 0xcf, 0x9e, 0xd0, 0x08, 0xcf, 0xcf, 0xce, 0xcc, 0xcb, 0xc9, 0xc7, 0xc5, 0xc3, 0x80, 0xc2, 0x06, 0xc3, 0xc5, 0xc6, 0xc6, 0xc0, 0xaf, 0x3f, 0x84, 0x00, 0x05, 0x11, 0x85, 0xa9, 0xbf, 0xca, 0xce, 0x87, 0xd0, 0x65, 0xcf, 0xcb, 0xbf, 0x14, 0x07, 0x81, 0x80, 0x31, 0x00, 0x50, 0x97, 0xaf, 0xc0, 0xc7, 0xc6, 0xc4, 0xc4, 0xc6, 0xc9, 0xcc, 0xcd, 0xcc, 0xcb, 0xc7, 0xc5, 0xc3, 0xc5, 0xc6, 0xc2, 0x82, 0x00, 0x50, 0x9e, 0xaf, 0xc0, 0xcb, 0xce, 0xcf, 0xcb, 0xc0, 0x15, 0x07, 0x0d, 0x03, 0x7f, 0x9f, 0xb0, 0x2b, 0x00, 0x13, 0x00, 0x60, 0x9a, 0xb5, 0xc5, 0xc9, 0xc7, 0xc5, 0xc4, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc8, 0xc6, 0xc5, 0xc4, 0xc5, 0xc6, 0xc9, 0xcc, 0xcc, 0xca, 0xc7, 0xc5, 0xc4, 0xc4, 0xc5, 0xc6, 0xc8, 0xca, 0xcb, 0xca, 0xc6, 0xc5, 0xc4, 0xc4, 0xc5, 0xc6, 0xc7, 0xc9, 0xc9, 0xc6, 0xc5, 0xc4, 0xc6, 0xc8, 0xcb, 0xca, 0xc8, 0xc5, 0x80, 0xc3, 0x1d, 0xc4, 0xc5, 0xc4, 0xc5, 0xc7, 0xca, 0xcc, 0xca, 0xc7, 0xc5, 0xc4, 0xc5, 0xc8, 0xca, 0xca, 0xc7, 0xc6, 0xc4, 0xc4, 0xc5, 0xc4, 0xbf, 0x4f, 0x00, 0x7a, 0xa2, 0xb4, 0xc4, 0xcc, 0xcf, 0xa1, 0xd0, 0x04, 0xcf, 0xcf, 0xce, 0xce, 0xcd, 0x82, 0xcc, 0x06, 0xcd, 0xcd, 0xcc, 0xc8, 0xbc, 0xa1, 0x17, 0x84, 0x00, 0x05, 0x2f, 0x98, 0xb4, 0xc4, 0xcc, 0xcf, 0x86, 0xd0, 0x7f, 0xcf, 0xca, 0xb9, 0x01, 0x06, 0x27, 0x0e, 0x00, 0x29, 0x82, 0x96, 0xad, 0xbb, 0x93, 0x59, 0x47, 0x66, 0xaf, 0xbc, 0xc3, 0xc7, 0xc6, 0x9a, 0x5a, 0x46, 0x63, 0xab, 0xb7, 0x8e, 0x35, 0x00, 0x2a, 0x47, 0x9f, 0xbb, 0xc8, 0xcd, 0xcd, 0xc8, 0x89, 0x00, 0x32, 0x2b, 0x00, 0x5d, 0x97, 0x81, 0x00, 0x28, 0x35, 0x00, 0x4e, 0x96, 0xb1, 0xbe, 0x99, 0x60, 0x4d, 0x69, 0xa9, 0x72, 0x5b, 0xb7, 0xac, 0x5d, 0x82, 0x76, 0x4e, 0x7a, 0xb4, 0xbe, 0xc3, 0xc3, 0x92, 0x5d, 0x4d, 0x6f, 0xae, 0x69, 0x63, 0xbb, 0xc0, 0xc2, 0x8e, 0x5c, 0x4e, 0x6f, 0xaf, 0x63, 0x6d, 0xbb, 0xbd, 0x9a, 0x5c, 0x48, 0x69, 0xb1, 0xbc, 0xc1, 0x8a, 0x5d, 0x82, 0x4d, 0x50, 0x8f, 0xa1, 0x57, 0x52, 0x88, 0xb7, 0xbf, 0xc2, 0xa9, 0x63, 0x47, 0x60, 0xa7, 0xbb, 0xbf, 0x7d, 0x5d, 0x99, 0x5a, 0x5b, 0x9e, 0xb4, 0x73, 0x1d, 0x06, 0x00, 0x3c, 0x59, 0xab, 0xbf, 0xca, 0xce, 0xa5, 0xd0, 0x84, 0xcf, 0x06, 0xd0, 0xcf, 0xcc, 0xc5, 0xb4, 0x5d, 0x04, 0x83, 0x00, 0x05, 0x0a, 0x70, 0xa4, 0xbc, 0xc9, 0xce, 0x86, 0xd0, 0x02, 0xce, 0xc8, 0xa3, 0x82, 0x00, 0x05, 0x07, 0x4c, 0x93, 0xa7, 0x5d, 0x01, 0x80, 0x00, 0x05, 0x17, 0x9e, 0xb4, 0xbd, 0x6a, 0x03, 0x80, 0x00, 0x02, 0x13, 0x92, 0x4d, 0x80, 0x00, 0x21, 0x03, 0x9b, 0xb4, 0xc6, 0xcc, 0xcc, 0xc4, 0x40, 0x00, 0x63, 0x49, 0x00, 0x3c, 0x8d, 0x2f, 0x00, 0x64, 0x46, 0x00, 0x3f, 0x93, 0xa9, 0x59, 0x01, 0x00, 0x09, 0x00, 0x19, 0x11, 0x0b, 0xa4, 0x7e, 0x00, 0x0d, 0x80, 0x00, 0x24, 0x3e, 0xab, 0xb4, 0x49, 0x00, 0x00, 0x09, 0x00, 0x21, 0x08, 0x1b, 0xa7, 0xaf, 0x42, 0x00, 0x00, 0x03, 0x00, 0x25, 0x01, 0x2b, 0xa4, 0x66, 0x03, 0x00, 0x03, 0x00, 0x1d, 0x9e, 0xb0, 0x3f, 0x00, 0x01, 0x00, 0x00, 0x04, 0x0e, 0x80, 0x00, 0x11, 0x69, 0xab, 0x84, 0x0a, 0x00, 0x04, 0x00, 0x11, 0x8c, 0xac, 0x27, 0x00, 0x0d, 0x00, 0x00, 0x01, 0x8e, 0x21, 0x80, 0x00, 0x04, 0x28, 0xa4, 0xbb, 0xc7, 0xce, 0xae, 0xd0, 0x04, 0xce, 0xca, 0xc0, 0xab, 0x22, 0x84, 0x00, 0x05, 0x1d, 0x93, 0xb0, 0xc2, 0xcc, 0xcf, 0x85, 0xd0, 0x7f, 0xce, 0xc7, 0x8a, 0x00, 0x2e, 0x63, 0x5d, 0x45, 0x0e, 0x00, 0x6e, 0x7a, 0x01, 0x11, 0x58, 0x6e, 0x27, 0x00, 0x40, 0xa2, 0x8f, 0x03, 0x0e, 0x55, 0x70, 0x2b, 0x00, 0x35, 0x8a, 0x2d, 0x00, 0x65, 0x7d, 0x9e, 0xb4, 0xc5, 0xcc, 0xca, 0xb4, 0x07, 0x13, 0x84, 0x70, 0x00, 0x1d, 0x6d, 0x01, 0x21, 0x82, 0x5c, 0x00, 0x2f, 0x8e, 0x71, 0x00, 0x25, 0x74, 0x90, 0x69, 0x06, 0x00, 0x1a, 0x8e, 0x5f, 0x00, 0x14, 0x60, 0x5f, 0x04, 0x07, 0x91, 0x63, 0x00, 0x2e, 0x7a, 0x8f, 0x60, 0x01, 0x00, 0x29, 0x93, 0x5b, 0x00, 0x2e, 0x76, 0x88, 0x4f, 0x00, 0x00, 0x35, 0x7c, 0x04, 0x0a, 0x6e, 0x80, 0x40, 0x00, 0x46, 0x9b, 0x24, 0x00, 0x32, 0x69, 0x28, 0x00, 0x13, 0x63, 0x66, 0x01, 0x1e, 0x91, 0x14, 0x01, 0x60, 0x83, 0x55, 0x00, 0x2a, 0x97, 0x0e, 0x00, 0x41, 0x6a, 0x2b, 0x00, 0x4a, 0x84, 0x0a, 0x06, 0x13, 0x71, 0x84, 0xa4, 0xbb, 0xc7, 0xce, 0xae, 0xd0, 0x05, 0xcf, 0xcd, 0xc6, 0xb8, 0x81, 0x0a, 0x83, 0x00, 0x06, 0x04, 0x54, 0x9f, 0xb9, 0xc7, 0xcd, 0xcf, 0x83, 0xd0, 0x71, 0xcf, 0xcd, 0xc6, 0x72, 0x00, 0x48, 0x7e, 0x85, 0x88, 0x4d, 0x00, 0x3f, 0x3f, 0x00, 0x4d, 0x86, 0x89, 0x73, 0x00, 0x1a, 0x92, 0x4f, 0x00, 0x48, 0x87, 0x89, 0x7a, 0x01, 0x14, 0x83, 0x1e, 0x03, 0x7c, 0x8e, 0xa6, 0xbb, 0xc7, 0xcb, 0xc6, 0x70, 0x00, 0x48, 0x8a, 0x8c, 0x11, 0x03, 0x29, 0x00, 0x5d, 0x86, 0x76, 0x00, 0x20, 0x89, 0x32, 0x00, 0x6e, 0x8e, 0x93, 0x94, 0x34, 0x00, 0x28, 0x82, 0x46, 0x00, 0x5f, 0x84, 0x86, 0x22, 0x00, 0x7e, 0x22, 0x01, 0x7a, 0x8e, 0x94, 0x93, 0x25, 0x00, 0x35, 0x85, 0x1e, 0x01, 0x7d, 0x8e, 0x93, 0x92, 0x1e, 0x00, 0x3f, 0x48, 0x00, 0x17, 0x35, 0x35, 0x32, 0x00, 0x1a, 0x8c, 0x10, 0x10, 0x7f, 0x81, 0x4d, 0x00, 0x4f, 0x7f, 0x86, 0x0d, 0x15, 0x64, 0x00, 0x0d, 0x80, 0x35, 0x12, 0x07, 0x04, 0x82, 0x01, 0x20, 0x80, 0x84, 0x63, 0x00, 0x3b, 0x7d, 0x00, 0x22, 0x7f, 0x93, 0xab, 0xc0, 0xca, 0xce, 0xaf, 0xd0, 0x04, 0xcf, 0xcc, 0xc2, 0xaf, 0x35, 0x84, 0x00, 0x05, 0x15, 0x8a, 0xab, 0xc0, 0xcb, 0xce, 0x83, 0xd0, 0x7f, 0xcf, 0xcc, 0xc4, 0x5c, 0x00, 0x5a, 0x8a, 0x94, 0x99, 0x50, 0x00, 0x38, 0x29, 0x00, 0x64, 0x86, 0x90, 0x7e, 0x00, 0x1e, 0x89, 0x37, 0x00, 0x63, 0x88, 0x91, 0x83, 0x01, 0x17, 0x7e, 0x0e, 0x11, 0x86, 0x9a, 0xb2, 0xc2, 0xcb, 0xcb, 0xc2, 0x29, 0x01, 0x7c, 0x92, 0x99, 0x35, 0x00, 0x00, 0x19, 0x80, 0x90, 0x95, 0x01, 0x0e, 0x83, 0x1a, 0x07, 0x87, 0x90, 0x9c, 0x9e, 0x3c, 0x00, 0x35, 0x7e, 0x34, 0x00, 0x73, 0x8b, 0x92, 0x1e, 0x01, 0x7f, 0x0b, 0x13, 0x86, 0x91, 0x9e, 0x9e, 0x2b, 0x00, 0x42, 0x80, 0x0b, 0x18, 0x88, 0x92, 0x9e, 0x9e, 0x2e, 0x00, 0x4d, 0x35, 0x00, 0x15, 0x20, 0x21, 0x21, 0x22, 0x2e, 0x84, 0x01, 0x21, 0x82, 0x8a, 0x47, 0x00, 0x63, 0x87, 0x8e, 0x03, 0x21, 0x4e, 0x00, 0x0e, 0x1e, 0x21, 0x21, 0x22, 0x22, 0x69, 0x00, 0x31, 0x84, 0x8e, 0x64, 0x00, 0x46, 0x6d, 0x07, 0x00, 0x34, 0x89, 0x9f, 0xb6, 0xc5, 0xcc, 0xcf, 0xb0, 0xd0, 0x04, 0xce, 0xc8, 0xbb, 0x99, 0x14, 0x83, 0x00, 0x06, 0x01, 0x38, 0x9a, 0xb4, 0xc5, 0xcc, 0xcf, 0x82, 0xd0, 0x7f, 0xcf, 0xcc, 0xc2, 0x46, 0x00, 0x6a, 0x8b, 0x96, 0x79, 0x15, 0x00, 0x54, 0x37, 0x00, 0x3c, 0x86, 0x90, 0x3e, 0x00, 0x3f, 0x88, 0x47, 0x00, 0x38, 0x89, 0x91, 0x45, 0x00, 0x35, 0x7d, 0x01, 0x21, 0x8d, 0xa3, 0xba, 0xc7, 0xcc, 0xc9, 0xa2, 0x00, 0x24, 0x90, 0x9b, 0xa5, 0x60, 0x00, 0x00, 0x52, 0x87, 0x9c, 0xa4, 0x12, 0x01, 0x7d, 0x28, 0x00, 0x60, 0x90, 0x9e, 0x98, 0x08, 0x00, 0x46, 0x80, 0x23, 0x01, 0x86, 0x96, 0x9e, 0x13, 0x0d, 0x81, 0x19, 0x00, 0x6d, 0x92, 0x9f, 0x8d, 0x01, 0x00, 0x52, 0x82, 0x1e, 0x01, 0x76, 0x93, 0xa0, 0x92, 0x03, 0x00, 0x5c, 0x46, 0x00, 0x25, 0x70, 0x76, 0x60, 0x79, 0x85, 0x77, 0x00, 0x32, 0x8a, 0x94, 0x3f, 0x00, 0x7a, 0x93, 0x8d, 0x00, 0x2f, 0x5f, 0x00, 0x11, 0x6d, 0x74, 0x67, 0x70, 0x81, 0x60, 0x00, 0x42, 0x8c, 0x9a, 0x5d, 0x00, 0x52, 0x5d, 0x06, 0x00, 0x46, 0x92, 0xa9, 0xbe, 0xca, 0xce, 0xb1, 0xd0, 0x05, 0xcf, 0xcc, 0xc4, 0xb3, 0x4f, 0x01, 0x83, 0x00, 0x05, 0x08, 0x7a, 0xa6, 0xbd, 0xc9, 0xce, 0x82, 0xd0, 0x7f, 0xcf, 0xcc, 0xc1, 0x2f, 0x00, 0x11, 0x15, 0x08, 0x00, 0x00, 0x29, 0x81, 0x6d, 0x03, 0x00, 0x19, 0x11, 0x00, 0x0d, 0x7f, 0x8f, 0x83, 0x06, 0x00, 0x17, 0x14, 0x00, 0x09, 0x76, 0x73, 0x00, 0x35, 0x93, 0xa9, 0xbf, 0xca, 0xcc, 0xc6, 0x59, 0x00, 0x5a, 0x96, 0xa5, 0xb0, 0x92, 0x00, 0x17, 0x80, 0x94, 0xa9, 0xaf, 0x29, 0x00, 0x6f, 0x5c, 0x00, 0x04, 0x30, 0x3c, 0x08, 0x00, 0x00, 0x55, 0x83, 0x13, 0x0e, 0x8f, 0x9e, 0xa5, 0x03, 0x21, 0x86, 0x4f, 0x00, 0x07, 0x37, 0x35, 0x04, 0x00, 0x00, 0x63, 0x88, 0x5f, 0x00, 0x0e, 0x41, 0x3f, 0x0a, 0x00, 0x00, 0x6c, 0x73, 0x0a, 0x00, 0x12, 0x1e, 0x00, 0x14, 0x89, 0x6e, 0x00, 0x46, 0x92, 0x9c, 0x2b, 0x03, 0x8f, 0x9b, 0x7e, 0x00, 0x44, 0x80, 0x19, 0x00, 0x0d, 0x23, 0x01, 0x07, 0x77, 0x56, 0x00, 0x57, 0x94, 0xa2, 0x4e, 0x00, 0x67, 0x4f, 0x06, 0x00, 0x59, 0x98, 0xaf, 0xc2, 0xcc, 0xcf, 0xb2, 0xd0, 0x04, 0xce, 0xca, 0xbf, 0xa7, 0x1d, 0x84, 0x00, 0x05, 0x0e, 0x95, 0xb2, 0xc4, 0xcc, 0xcf, 0x81, 0xd0, 0x03, 0xcf, 0xcc, 0xc1, 0x1a, 0x80, 0x00, 0x7f, 0x07, 0x1a, 0x4c, 0x86, 0x8f, 0x95, 0x69, 0x11, 0x00, 0x01, 0x21, 0x76, 0x91, 0x9e, 0xa4, 0x76, 0x14, 0x00, 0x01, 0x1e, 0x72, 0x8b, 0x6d, 0x00, 0x49, 0x9c, 0xb0, 0xc2, 0xcb, 0xcc, 0xc3, 0x15, 0x07, 0x90, 0x9f, 0xb0, 0xbb, 0xb4, 0x11, 0x5f, 0x93, 0xa4, 0xb5, 0xb8, 0x41, 0x00, 0x65, 0x8e, 0x54, 0x09, 0x00, 0x00, 0x21, 0x29, 0x00, 0x6a, 0x8c, 0x03, 0x22, 0x98, 0xa5, 0x97, 0x00, 0x39, 0x91, 0x92, 0x4b, 0x06, 0x00, 0x01, 0x29, 0x21, 0x00, 0x7a, 0x93, 0x9b, 0x5a, 0x0a, 0x00, 0x00, 0x22, 0x0d, 0x04, 0x7a, 0x88, 0x73, 0x1b, 0x01, 0x01, 0x17, 0x6d, 0x96, 0x62, 0x00, 0x5d, 0x9b, 0xa4, 0x17, 0x13, 0x9a, 0xa3, 0x6c, 0x00, 0x5c, 0x8f, 0x7e, 0x28, 0x01, 0x00, 0x11, 0x58, 0x91, 0x4a, 0x00, 0x71, 0x9e, 0xab, 0x3a, 0x00, 0x82, 0x44, 0x00, 0x70, 0xa1, 0xb5, 0xc5, 0xcd, 0xcf, 0xb2, 0xd0, 0x05, 0xcf, 0xcd, 0xc6, 0xb6, 0x72, 0x08, 0x83, 0x00, 0x05, 0x07, 0x73, 0xa5, 0xbe, 0xca, 0xcf, 0x81, 0xd0, 0x76, 0xcf, 0xcc, 0xc4, 0xb4, 0x9e, 0x8f, 0x8a, 0x8a, 0x8e, 0x93, 0x9b, 0xa5, 0xab, 0xa9, 0x9e, 0x86, 0x87, 0x8f, 0x97, 0xa3, 0xb1, 0xb5, 0xae, 0xa0, 0x87, 0x88, 0x8e, 0x95, 0x9e, 0xa5, 0xa5, 0xa4, 0xab, 0xb9, 0xc6, 0xcc, 0xcc, 0xc6, 0xba, 0xab, 0xa5, 0xad, 0xbb, 0xc2, 0xbf, 0xb2, 0xa7, 0xa9, 0xb4, 0xc0, 0xc1, 0xb5, 0xa7, 0x9f, 0xa0, 0x9f, 0x99, 0x81, 0x87, 0x8f, 0x8e, 0x8e, 0x94, 0x9e, 0xa3, 0xa2, 0xa6, 0xb1, 0xb6, 0xb0, 0xa6, 0xa4, 0xa5, 0xa3, 0x99, 0x7f, 0x8a, 0x8f, 0x8e, 0x8e, 0x98, 0xa4, 0xa9, 0xa1, 0x93, 0x79, 0x7a, 0x6d, 0x00, 0x20, 0x81, 0x95, 0xa0, 0x9b, 0x8a, 0x85, 0x8f, 0x98, 0xa4, 0xab, 0xa8, 0xa5, 0xab, 0xb1, 0xaf, 0xa8, 0xa7, 0xae, 0xb3, 0xac, 0xa4, 0xa3, 0xa3, 0x9e, 0x8e, 0x82, 0x8e, 0x96, 0x9e, 0x80, 0xa4, 0x0b, 0xab, 0xb4, 0xb3, 0xa9, 0x9f, 0x9e, 0x9e, 0xa3, 0xae, 0xbd, 0xc8, 0xce, 0xb4, 0xd0, 0x04, 0xcf, 0xcb, 0xc1, 0xac, 0x2b, 0x82, 0x00, 0x06, 0x01, 0x01, 0x4a, 0x9b, 0xb8, 0xc8, 0xce, 0x82, 0xd0, 0x4a, 0xce, 0xc8, 0xbf, 0xb3, 0xa8, 0xa3, 0xa3, 0xa5, 0xab, 0xb3, 0xbb, 0xbf, 0xbc, 0xb4, 0xab, 0xa6, 0xa7, 0xad, 0xb7, 0xc0, 0xc3, 0xbf, 0xb5, 0xab, 0xa6, 0xa7, 0xac, 0xb4, 0xb9, 0xb8, 0xb7, 0xbb, 0xc2, 0xca, 0xce, 0xcd, 0xca, 0xc2, 0xba, 0xb7, 0xbd, 0xc5, 0xc9, 0xc6, 0xc0, 0xbb, 0xbc, 0xc2, 0xc8, 0xc7, 0xc1, 0xb9, 0xb4, 0xb5, 0xb4, 0xb0, 0xa9, 0xa6, 0xa4, 0xa5, 0xa8, 0xad, 0xb3, 0xb5, 0xb5, 0xb8, 0xbe, 0xc1, 0xbd, 0xb8, 0xb7, 0xb9, 0xb7, 0xb1, 0xa9, 0x80, 0xa5, 0x36, 0xa9, 0xae, 0xb4, 0x52, 0x15, 0x49, 0x7a, 0x6a, 0x21, 0x00, 0x4d, 0x8d, 0xa4, 0xb2, 0xb3, 0xab, 0xa7, 0xa8, 0xad, 0xb4, 0xba, 0xb9, 0xb7, 0xbb, 0xbe, 0xbd, 0xb8, 0xb8, 0xbc, 0xbf, 0xbb, 0xb7, 0xb7, 0xb8, 0xb4, 0xac, 0xa7, 0xa7, 0xab, 0xb3, 0xb6, 0xb6, 0xb7, 0xbb, 0xc0, 0xbf, 0xb9, 0xb4, 0xb3, 0xb3, 0xb5, 0xbd, 0xc5, 0xcc, 0xcf, 0xb4, 0xd0, 0x05, 0xcf, 0xcd, 0xc7, 0xba, 0x90, 0x03, 0x82, 0x00, 0x05, 0x03, 0x53, 0x98, 0xb5, 0xc6, 0xce, 0x82, 0xd0, 0x1b, 0xcf, 0xcc, 0xc8, 0xc2, 0xbf, 0xbc, 0xbc, 0xbd, 0xc0, 0xc3, 0xc7, 0xca, 0xc8, 0xc4, 0xc0, 0xbd, 0xbe, 0xc1, 0xc6, 0xca, 0xcc, 0xc9, 0xc5, 0xc0, 0xbd, 0xbe, 0xc1, 0xc4, 0x81, 0xc6, 0x24, 0xcb, 0xcd, 0xcf, 0xcf, 0xcd, 0xc9, 0xc6, 0xc5, 0xc8, 0xcc, 0xcd, 0xcc, 0xca, 0xc7, 0xc8, 0xcb, 0xcd, 0xcc, 0xca, 0xc6, 0xc4, 0xc5, 0xc5, 0xc2, 0xbf, 0xbc, 0xbc, 0xbd, 0xbf, 0xc1, 0xc4, 0xc5, 0xc4, 0xc6, 0xc8, 0xc9, 0xc7, 0x81, 0xc6, 0x09, 0xc2, 0xbf, 0xbc, 0xbc, 0xbd, 0xbf, 0xc1, 0xc0, 0x95, 0x07, 0x81, 0x00, 0x0a, 0x2b, 0x88, 0x9b, 0xb1, 0xc0, 0xc2, 0xc0, 0xbe, 0xbe, 0xc1, 0xc4, 0x81, 0xc6, 0x05, 0xc8, 0xc7, 0xc6, 0xc6, 0xc7, 0xc8, 0x81, 0xc6, 0x05, 0xc5, 0xc1, 0xbe, 0xbe, 0xc0, 0xc3, 0x80, 0xc5, 0x0b, 0xc7, 0xc9, 0xc8, 0xc6, 0xc4, 0xc3, 0xc3, 0xc5, 0xc7, 0xcc, 0xce, 0xcf, 0xb5, 0xd0, 0x05, 0xcf, 0xcc, 0xc2, 0xb1, 0x34, 0x03, 0x81, 0x00, 0x05, 0x10, 0x76, 0x9b, 0xb7, 0xc7, 0xce, 0x83, 0xd0, 0x03, 0xcf, 0xcd, 0xcc, 0xcb, 0x80, 0xca, 0x20, 0xcb, 0xcc, 0xcd, 0xce, 0xce, 0xcc, 0xcb, 0xca, 0xca, 0xcc, 0xcd, 0xce, 0xcf, 0xce, 0xcc, 0xcb, 0xca, 0xca, 0xcc, 0xcc, 0xcd, 0xcd, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd0, 0xcf, 0xce, 0xcd, 0xcc, 0xcd, 0x80, 0xcf, 0x07, 0xce, 0xcd, 0xcd, 0xce, 0xcf, 0xcf, 0xce, 0xcd, 0x81, 0xcc, 0x04, 0xcb, 0xca, 0xc9, 0xca, 0xcb, 0x82, 0xcc, 0x03, 0xcd, 0xce, 0xcd, 0xcc, 0x80, 0xcd, 0x1b, 0xcc, 0xca, 0xc9, 0xc9, 0xca, 0xcb, 0xca, 0xc7, 0xbe, 0x96, 0x58, 0x2e, 0x37, 0x5c, 0x8c, 0x98, 0xab, 0xbd, 0xc7, 0xcb, 0xcb, 0xca, 0xca, 0xcb, 0xcc, 0xcd, 0xcd, 0xcc, 0x80, 0xcd, 0x01, 0xcc, 0xcc, 0x80, 0xcd, 0x07, 0xcc, 0xcd, 0xcd, 0xcc, 0xcc, 0xca, 0xca, 0xcb, 0x81, 0xcc, 0x03, 0xcd, 0xce, 0xcd, 0xcd, 0x81, 0xcc, 0x02, 0xcd, 0xcf, 0xcf, 0xb7, 0xd0, 0x0e, 0xce, 0xc9, 0xbd, 0xa5, 0x31, 0x0a, 0x00, 0x03, 0x10, 0x55, 0x87, 0xa5, 0xbd, 0xca, 0xcf, 0x84, 0xd0, 0x85, 0xcf, 0x80, 0xd0, 0x83, 0xcf, 0x80, 0xd0, 0x87, 0xcf, 0x83, 0xd0, 0x80, 0xcf, 0x81, 0xd0, 0x00, 0xcf, 0x82, 0xd0, 0x83, 0xcf, 0x01, 0xce, 0xce, 0x85, 0xcf, 0x00, 0xd0, 0x84, 0xcf, 0x11, 0xce, 0xce, 0xcf, 0xcf, 0xce, 0xcb, 0xc4, 0xb8, 0xa9, 0x9e, 0x98, 0x99, 0xa0, 0xac, 0xbb, 0xc6, 0xcc, 0xce, 0x9a, 0xcf, 0x01, 0xd0, 0xd0, 0x83, 0xcf, 0xb9, 0xd0, 0x0e, 0xcf, 0xcc, 0xc6, 0xb8, 0xa4, 0x7c, 0x4d, 0x55, 0x76, 0x87, 0x9e, 0xb4, 0xc4, 0xcc, 0xcf, 0xff, 0xd0, 0xbf, 0xd0, 0x0c, 0xcf, 0xcc, 0xc4, 0xb9, 0xab, 0x9e, 0x98, 0x9b, 0xa5, 0xb4, 0xc1, 0xca, 0xce, 0xff, 0xd0, 0x93, 0xd0, 0x94, 0xd0, 0x12, 0xcf, 0xce, 0xcd, 0xcc, 0xcb, 0xc9, 0xc7, 0xc6, 0xc5, 0xc4, 0xc4, 0xc6, 0xc7, 0xc9, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xff, 0xd0, 0xb7, 0xd0, 0x09, 0xcf, 0xcf, 0xcd, 0xcc, 0xc9, 0xc6, 0xc2, 0xbd, 0xbb, 0xb8, 0x80, 0xb5, 0x0b, 0xb2, 0xb4, 0xb6, 0xba, 0xbe, 0xc2, 0xc6, 0xc9, 0xcc, 0xcd, 0xcf, 0xcf, 0xff, 0xd0, 0xb3, 0xd0, 0x08, 0xcf, 0xcd, 0xcb, 0xc7, 0xc2, 0xbc, 0xb8, 0xb9, 0xbb, 0x84, 0xbc, 0x0c, 0xb9, 0xb5, 0xaf, 0xad, 0xb4, 0xbb, 0xc2, 0xc7, 0xcb, 0xcd, 0xcf, 0xd0, 0xd0, 0x81, 0xcf, 0xff, 0xd0, 0xaa, 0xd0, 0x06, 0xcf, 0xce, 0xcc, 0xc7, 0xc1, 0xba, 0xb8, 0x8b, 0xbc, 0x0f, 0xba, 0xb2, 0xac, 0xae, 0xb8, 0xc1, 0xc7, 0xcc, 0xce, 0xce, 0xcd, 0xcc, 0xcc, 0xcd, 0xce, 0xcf, 0xff, 0xd0, 0xa7, 0xd0, 0x05, 0xcf, 0xcd, 0xca, 0xc3, 0xbb, 0xb9, 0x90, 0xbc, 0x0c, 0xb6, 0xa8, 0xac, 0xba, 0xc3, 0xc8, 0xca, 0xc7, 0xc3, 0xc4, 0xc7, 0xcc, 0xce, 0xa3, 0xd0, 0x8b, 0xcf, 0x89, 0xd0, 0x89, 0xcf, 0xb9, 0xd0, 0x83, 0xcf, 0x9a, 0xd0, 0x04, 0xcf, 0xcc, 0xc7, 0xbe, 0xb8, 0x94, 0xbc, 0x0b, 0xac, 0xa3, 0xb2, 0xbc, 0xbf, 0xbb, 0xbc, 0xb5, 0xbd, 0xc6, 0xcc, 0xcf, 0x9e, 0xd0, 0x04, 0xcf, 0xcf, 0xce, 0xcd, 0xcd, 0x89, 0xcc, 0x03, 0xcd, 0xcd, 0xce, 0xcf, 0x82, 0xd0, 0x03, 0xcf, 0xcf, 0xce, 0xcd, 0x88, 0xcc, 0x03, 0xcd, 0xcd, 0xce, 0xcf, 0x82, 0xd0, 0x06, 0xcf, 0xce, 0xce, 0xcd, 0xce, 0xcf, 0xcf, 0xa9, 0xd0, 0x07, 0xcf, 0xcd, 0xcc, 0xcb, 0xcb, 0xcc, 0xcd, 0xcf, 0x98, 0xd0, 0x04, 0xce, 0xcc, 0xc6, 0xbb, 0xba, 0x96, 0xbc, 0x0a, 0xb5, 0xa1, 0xa4, 0xb2, 0xba, 0xba, 0xa4, 0xad, 0xbf, 0xca, 0xce, 0x9d, 0xd0, 0x05, 0xcf, 0xcd, 0xcb, 0xc8, 0xc6, 0xc4, 0x89, 0xc3, 0x0d, 0xc5, 0xc6, 0xc9, 0xcc, 0xce, 0xcf, 0xd0, 0xd0, 0xcf, 0xcc, 0xcb, 0xc7, 0xc6, 0xc4, 0x87, 0xc3, 0x10, 0xc5, 0xc6, 0xc9, 0xcc, 0xce, 0xcf, 0xd0, 0xcf, 0xce, 0xcc, 0xca, 0xc7, 0xc6, 0xc8, 0xcc, 0xcd, 0xcf, 0xa7, 0xd0, 0x09, 0xce, 0xcc, 0xc7, 0xbb, 0xb7, 0xbf, 0xc2, 0xc8, 0xcc, 0xcf, 0x96, 0xd0, 0x04, 0xcf, 0xcc, 0xc5, 0xbb, 0xbb, 0x98, 0xbc, 0x09, 0xba, 0xaa, 0xb8, 0xbc, 0xbc, 0x9c, 0x9e, 0xb6, 0xc6, 0xcd, 0x9c, 0xd0, 0x06, 0xcf, 0xcc, 0xc7, 0xc0, 0xba, 0xb7, 0xb5, 0x88, 0xb3, 0x0e, 0xb4, 0xb4, 0xb6, 0xbc, 0xc4, 0xca, 0xce, 0xcf, 0xce, 0xcc, 0xc6, 0xbe, 0xb9, 0xb7, 0xb5, 0x86, 0xb3, 0x12, 0xb4, 0xb4, 0xb6, 0xbc, 0xc3, 0xca, 0xcd, 0xcf, 0xce, 0xcb, 0xc4, 0xbd, 0xb9, 0xb7, 0xbb, 0xc2, 0xc9, 0xcd, 0xcf, 0xa5, 0xd0, 0x0b, 0xcf, 0xcc, 0xb7, 0x41, 0x08, 0x06, 0x37, 0xae, 0xbc, 0xc6, 0xcc, 0xcf, 0x94, 0xd0, 0x04, 0xcf, 0xcc, 0xc6, 0xbb, 0xbb, 0x88, 0xbc, 0x06, 0xb6, 0xa2, 0x94, 0x98, 0x9b, 0xa1, 0xb3, 0x87, 0xbc, 0x01, 0xb7, 0xb7, 0x80, 0xbc, 0x05, 0xa4, 0x90, 0xae, 0xc2, 0xcc, 0xcf, 0x9a, 0xd0, 0x04, 0xcf, 0xcc, 0xc6, 0xbc, 0xbb, 0x8d, 0xbc, 0x07, 0xbb, 0xaa, 0xb4, 0xc2, 0xcb, 0xcd, 0xcc, 0xc4, 0x8d, 0xbc, 0x08, 0xba, 0xab, 0xb4, 0xc2, 0xcb, 0xcd, 0xcb, 0xc1, 0xbb, 0x80, 0xbc, 0x04, 0xab, 0xb2, 0xc0, 0xca, 0xce, 0xa4, 0xd0, 0x03, 0xcf, 0xcd, 0xc6, 0x56, 0x81, 0x00, 0x04, 0x6a, 0xab, 0xc0, 0xca, 0xce, 0x93, 0xd0, 0x04, 0xcf, 0xcd, 0xc7, 0xbc, 0xbb, 0x86, 0xbc, 0x0c, 0xa4, 0x8b, 0x7d, 0x6e, 0x73, 0x7a, 0x7e, 0x80, 0x7f, 0x7b, 0x83, 0x96, 0xb1, 0x83, 0xbc, 0x01, 0xb4, 0xb3, 0x81, 0xbc, 0x05, 0xa9, 0x86, 0xa8, 0xc0, 0xcb, 0xcf, 0x9a, 0xd0, 0x02, 0xce, 0xc9, 0xbd, 0x90, 0xbc, 0x06, 0xa9, 0xa1, 0xb8, 0xc6, 0xcb, 0xc6, 0xba, 0x8e, 0xbc, 0x06, 0xab, 0xa0, 0xb7, 0xc6, 0xcb, 0xc6, 0xbb, 0x81, 0xbc, 0x05, 0xad, 0x9e, 0xb5, 0xc6, 0xcd, 0xcf, 0xa3, 0xd0, 0x03, 0xcf, 0xcb, 0xb3, 0x06, 0x81, 0x00, 0x05, 0x45, 0x9c, 0xb7, 0xc6, 0xce, 0xcf, 0x92, 0xd0, 0x03, 0xce, 0xc9, 0xc0, 0xb9, 0x85, 0xbc, 0x10, 0xb1, 0x85, 0x68, 0x76, 0x84, 0x8e, 0x98, 0x9e, 0xa3, 0xa4, 0xa3, 0x9f, 0x99, 0x90, 0x86, 0x92, 0xb1, 0x80, 0xbc, 0x01, 0xb4, 0xb3, 0x82, 0xbc, 0x05, 0xad, 0x7e, 0xa2, 0xbd, 0xca, 0xcf, 0x99, 0xd0, 0x03, 0xcf, 0xcc, 0xc4, 0xb9, 0x90, 0xbc, 0x06, 0xab, 0x93, 0xb0, 0xc2, 0xc8, 0xc0, 0xbb, 0x8e, 0xbc, 0x06, 0xad, 0x92, 0xaf, 0xc2, 0xc7, 0xbf, 0xbb, 0x81, 0xbc, 0x05, 0xac, 0x8d, 0xab, 0xc2, 0xcc, 0xcf, 0xa3, 0xd0, 0x02, 0xce, 0xc8, 0x8a, 0x82, 0x00, 0x05, 0x4d, 0x93, 0xb3, 0xc5, 0xcd, 0xcf, 0x91, 0xd0, 0x03, 0xcf, 0xcc, 0xc3, 0xb9, 0x84, 0xbc, 0x16, 0xba, 0x93, 0x6d, 0x76, 0x88, 0x99, 0xa5, 0xaf, 0xb6, 0xbb, 0xbd, 0xbf, 0xbe, 0xbb, 0xb7, 0xb0, 0xa5, 0x98, 0x8d, 0xa4, 0xbc, 0xb5, 0xb4, 0x83, 0xbc, 0x05, 0xb1, 0x7f, 0x9c, 0xb9, 0xc8, 0xce, 0x99, 0xd0, 0x02, 0xcf, 0xcb, 0xbe, 0x91, 0xbc, 0x05, 0x8f, 0x91, 0xae, 0xc2, 0xc5, 0xba, 0x8f, 0xbc, 0x05, 0x92, 0x90, 0xad, 0xc1, 0xc5, 0xb9, 0x82, 0xbc, 0x05, 0x9d, 0x85, 0xa7, 0xc0, 0xcb, 0xcf, 0xa2, 0xd0, 0x03, 0xcf, 0xcd, 0xc5, 0x64, 0x82, 0x00, 0x05, 0x5d, 0x92, 0xb3, 0xc5, 0xcd, 0xcf, 0x90, 0xd0, 0x03, 0xcf, 0xcd, 0xc6, 0xba, 0x84, 0xbc, 0x0a, 0xba, 0x7d, 0x6a, 0x80, 0x95, 0xa7, 0xb4, 0xbe, 0xc3, 0xc6, 0xc9, 0x80, 0xcb, 0x08, 0xca, 0xc7, 0xc4, 0xbe, 0xb3, 0xa3, 0x8c, 0xa8, 0xb7, 0x84, 0xbc, 0x05, 0xba, 0x8b, 0x95, 0xb4, 0xc6, 0xcd, 0x95, 0xd0, 0x00, 0xcf, 0x80, 0xd0, 0x02, 0xce, 0xc8, 0xba, 0x8d, 0xbc, 0x09, 0xba, 0xa6, 0x92, 0x83, 0x82, 0x9b, 0xb4, 0xc3, 0xc3, 0xb7, 0x8b, 0xbc, 0x09, 0xb9, 0xa5, 0x92, 0x83, 0x81, 0x9b, 0xb4, 0xc2, 0xc2, 0xb6, 0x82, 0xbc, 0x05, 0x8e, 0x84, 0xa8, 0xc0, 0xcc, 0xcf, 0x89, 0xd0, 0x01, 0xcf, 0xcf, 0x94, 0xd0, 0x03, 0xcf, 0xcc, 0xc2, 0x42, 0x81, 0x00, 0x05, 0x03, 0x6f, 0x95, 0xb4, 0xc6, 0xcd, 0x91, 0xd0, 0x03, 0xcf, 0xcb, 0xc0, 0xba, 0x84, 0xbc, 0x0a, 0x87, 0x6d, 0x86, 0x9e, 0xb1, 0xbd, 0xc6, 0xca, 0xcc, 0xcd, 0xce, 0x80, 0xcf, 0x07, 0xce, 0xce, 0xcc, 0xc8, 0xc1, 0xb2, 0xad, 0xb8, 0x86, 0xbc, 0x05, 0xa0, 0x8d, 0xae, 0xc2, 0xcc, 0xcf, 0x8a, 0xd0, 0x01, 0xcf, 0xcf, 0x80, 0xce, 0x80, 0xcf, 0x00, 0xce, 0x80, 0xcd, 0x04, 0xce, 0xcf, 0xcd, 0xc6, 0xb8, 0x82, 0xbc, 0x04, 0x88, 0x5a, 0x66, 0x6f, 0x72, 0x83, 0x73, 0x09, 0x76, 0x7a, 0x80, 0x8b, 0x9b, 0xae, 0xbf, 0xc6, 0xc2, 0xb6, 0x82, 0xbc, 0x04, 0x71, 0x5d, 0x69, 0x70, 0x72, 0x81, 0x73, 0x09, 0x76, 0x7a, 0x80, 0x8a, 0x9b, 0xae, 0xbf, 0xc6, 0xc1, 0xb4, 0x82, 0xbc, 0x04, 0x7f, 0x88, 0xab, 0xc2, 0xcc, 0x80, 0xcf, 0x80, 0xce, 0x81, 0xcf, 0x01, 0xce, 0xce, 0x81, 0xcd, 0x02, 0xce, 0xcf, 0xcf, 0x8c, 0xd0, 0x81, 0xcf, 0x03, 0xcd, 0xc9, 0xbe, 0x21, 0x81, 0x00, 0x05, 0x11, 0x76, 0x9a, 0xb8, 0xc8, 0xce, 0x91, 0xd0, 0x02, 0xcd, 0xc7, 0xb9, 0x84, 0xbc, 0x09, 0x8f, 0x6c, 0x86, 0xa1, 0xb4, 0xc2, 0xc9, 0xcc, 0xce, 0xcf, 0x83, 0xd0, 0x05, 0xcf, 0xce, 0xcb, 0xc2, 0xb8, 0xba, 0x87, 0xbc, 0x05, 0xaa, 0x84, 0xa7, 0xc0, 0xcb, 0xcf, 0x89, 0xd0, 0x11, 0xcf, 0xcd, 0xcb, 0xc8, 0xc8, 0xc9, 0xcb, 0xcc, 0xcb, 0xc8, 0xc6, 0xc5, 0xc6, 0xc9, 0xcc, 0xcb, 0xc3, 0xb5, 0x82, 0xbc, 0x05, 0x7d, 0x6e, 0x83, 0x91, 0x97, 0x98, 0x82, 0x99, 0x09, 0x9b, 0x9e, 0xa3, 0xab, 0xb4, 0xc0, 0xc7, 0xc9, 0xc0, 0xb7, 0x82, 0xbc, 0x05, 0x6a, 0x73, 0x87, 0x93, 0x98, 0x98, 0x80, 0x99, 0x09, 0x9b, 0x9e, 0xa3, 0xab, 0xb4, 0xc0, 0xc6, 0xc9, 0xc0, 0xb6, 0x82, 0xbc, 0x0b, 0x77, 0x8e, 0xb0, 0xc4, 0xcc, 0xce, 0xcd, 0xcb, 0xc8, 0xc7, 0xc8, 0xcb, 0x80, 0xcc, 0x09, 0xca, 0xc7, 0xc6, 0xc4, 0xc5, 0xc6, 0xc9, 0xcc, 0xcd, 0xcf, 0x88, 0xd0, 0x0a, 0xcf, 0xcf, 0xce, 0xcd, 0xcc, 0xcb, 0xca, 0xc7, 0xc2, 0xb3, 0x06, 0x81, 0x00, 0x05, 0x21, 0x7a, 0x9f, 0xbc, 0xca, 0xce, 0x90, 0xd0, 0x03, 0xcf, 0xcc, 0xc2, 0xb9, 0x83, 0xbc, 0x08, 0xa5, 0x66, 0x82, 0x9e, 0xb5, 0xc3, 0xcb, 0xce, 0xcf, 0x86, 0xd0, 0x03, 0xce, 0xc8, 0xbd, 0xbb, 0x88, 0xbc, 0x05, 0xb0, 0x7e, 0xa0, 0xbb, 0xc9, 0xce, 0x88, 0xd0, 0x12, 0xcf, 0xcc, 0xc6, 0xa7, 0x79, 0xa9, 0xbc, 0xc0, 0xc2, 0xb4, 0x87, 0x5d, 0x73, 0xa7, 0xbb, 0xc3, 0xc6, 0xc0, 0xb6, 0x82, 0xbc, 0x05, 0x73, 0x7e, 0x98, 0xa9, 0xb0, 0xb2, 0x83, 0xb3, 0x08, 0xb5, 0xba, 0xbf, 0xc4, 0xc9, 0xcc, 0xca, 0xbe, 0xb9, 0x81, 0xbc, 0x05, 0xb7, 0x67, 0x84, 0x9e, 0xab, 0xb1, 0x81, 0xb3, 0x09, 0xb4, 0xb5, 0xba, 0xbf, 0xc4, 0xc9, 0xcc, 0xca, 0xbd, 0xb9, 0x81, 0xbc, 0x1b, 0xb8, 0x70, 0x94, 0xb4, 0xc6, 0xcc, 0xcc, 0xc6, 0xa1, 0x71, 0x9b, 0xbb, 0xc0, 0xc4, 0xc5, 0xc2, 0xac, 0x86, 0x63, 0x70, 0x8e, 0xac, 0xbb, 0xc1, 0xc6, 0xcc, 0xce, 0xcf, 0x84, 0xd0, 0x0b, 0xcf, 0xcf, 0xcd, 0xcb, 0xc8, 0xc5, 0xc1, 0xbe, 0xbb, 0xab, 0x92, 0x69, 0x82, 0x00, 0x05, 0x32, 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0x90, 0xd0, 0x02, 0xce, 0xc8, 0xba, 0x84, 0xbc, 0x07, 0x7f, 0x79, 0x98, 0xb2, 0xc2, 0xcb, 0xce, 0xcf, 0x87, 0xd0, 0x08, 0xcd, 0xc7, 0xbb, 0xb3, 0xb1, 0xaf, 0xb1, 0xb5, 0xbb, 0x83, 0xbc, 0x05, 0xb7, 0x89, 0x9a, 0xb7, 0xc7, 0xce, 0x87, 0xd0, 0x0a, 0xcf, 0xcc, 0xc6, 0x35, 0x00, 0x00, 0x03, 0x96, 0xa8, 0x49, 0x01, 0x80, 0x00, 0x05, 0x03, 0x92, 0xb4, 0xbf, 0xbb, 0xb7, 0x82, 0xbc, 0x04, 0x68, 0x82, 0x9b, 0xaa, 0xb0, 0x82, 0xb2, 0x09, 0xb3, 0xb3, 0xb5, 0xbb, 0xc1, 0xc7, 0xcc, 0xcd, 0xc9, 0xba, 0x82, 0xbc, 0x05, 0xa9, 0x6b, 0x88, 0xa0, 0xac, 0xb1, 0x80, 0xb2, 0x09, 0xb3, 0xb4, 0xb7, 0xbc, 0xc2, 0xc8, 0xcc, 0xcd, 0xc9, 0xba, 0x82, 0xbc, 0x07, 0xa9, 0x76, 0x9b, 0xb8, 0xc7, 0xcb, 0xc2, 0x25, 0x80, 0x00, 0x04, 0x60, 0xab, 0xb1, 0x6d, 0x15, 0x82, 0x00, 0x06, 0x07, 0x53, 0xa7, 0xb8, 0xc3, 0xcb, 0xce, 0x83, 0xd0, 0x09, 0xcf, 0xcd, 0xcb, 0xc6, 0xc0, 0x8d, 0x46, 0x29, 0x17, 0x04, 0x85, 0x00, 0x05, 0x46, 0x87, 0xab, 0xc2, 0xcc, 0xcf, 0x8f, 0xd0, 0x03, 0xcf, 0xcc, 0xc4, 0xb7, 0x83, 0xbc, 0x06, 0xa8, 0x6a, 0x8a, 0xa9, 0xbf, 0xca, 0xce, 0x89, 0xd0, 0x15, 0xce, 0xc8, 0xbd, 0xab, 0x99, 0x8a, 0x7f, 0x81, 0x88, 0x97, 0xa7, 0xae, 0xb2, 0xba, 0xbc, 0xbc, 0x9e, 0x97, 0xb3, 0xc6, 0xcd, 0xcf, 0x86, 0xd0, 0x02, 0xce, 0xc9, 0x89, 0x81, 0x00, 0x01, 0x47, 0x22, 0x83, 0x00, 0x04, 0x47, 0xa3, 0xb4, 0xb3, 0xba, 0x8d, 0xbc, 0x08, 0xbb, 0xb5, 0xaf, 0xb4, 0xc0, 0xc9, 0xcc, 0xc7, 0xb8, 0x8c, 0xbc, 0x08, 0xba, 0xb3, 0xae, 0xb6, 0xc2, 0xcb, 0xcc, 0xc7, 0xb8, 0x82, 0xbc, 0x06, 0x98, 0x7a, 0x9f, 0xbb, 0xc8, 0xc7, 0x7d, 0x81, 0x00, 0x02, 0x1b, 0x6f, 0x1e, 0x86, 0x00, 0x05, 0x17, 0x98, 0xb4, 0xc2, 0xcb, 0xce, 0x80, 0xd0, 0x06, 0xcf, 0xce, 0xcc, 0xc6, 0xb1, 0x64, 0x1a, 0x8a, 0x00, 0x05, 0x5a, 0x8e, 0xaf, 0xc4, 0xcc, 0xcf, 0x8f, 0xd0, 0x03, 0xcf, 0xcb, 0xc0, 0xba, 0x83, 0xbc, 0x06, 0x80, 0x7a, 0x9b, 0xb6, 0xc6, 0xcd, 0xcf, 0x89, 0xd0, 0x15, 0xce, 0xcb, 0xc4, 0xbb, 0xb0, 0xa7, 0xa0, 0x9b, 0x95, 0x8e, 0x86, 0x7f, 0x7e, 0x88, 0x9d, 0xab, 0xa9, 0x99, 0xb3, 0xc5, 0xcc, 0xcf, 0x85, 0xd0, 0x03, 0xcf, 0xcd, 0xc4, 0x37, 0x89, 0x00, 0x03, 0x3a, 0x97, 0xad, 0xb0, 0x90, 0xbc, 0x06, 0xb8, 0x9e, 0xb4, 0xc3, 0xca, 0xc5, 0xb5, 0x8e, 0xbc, 0x06, 0xb1, 0xa3, 0xb8, 0xc6, 0xcb, 0xc5, 0xb6, 0x82, 0xbc, 0x06, 0x8c, 0x82, 0xa5, 0xbf, 0xc7, 0xc2, 0x2b, 0x81, 0x00, 0x01, 0x01, 0x01, 0x88, 0x00, 0x0c, 0x35, 0x9f, 0xb6, 0xc6, 0xcc, 0xcf, 0xd0, 0xcf, 0xce, 0xca, 0xc3, 0x60, 0x04, 0x8b, 0x00, 0x05, 0x03, 0x6f, 0x94, 0xb4, 0xc6, 0xcd, 0x90, 0xd0, 0x03, 0xce, 0xc9, 0xbc, 0xbb, 0x82, 0xbc, 0x06, 0xbb, 0x6f, 0x87, 0xa9, 0xc0, 0xcb, 0xcf, 0x8a, 0xd0, 0x15, 0xcf, 0xce, 0xcb, 0xc6, 0xc2, 0xbf, 0xbc, 0xb9, 0xb4, 0xaf, 0xa9, 0xa3, 0x9c, 0x96, 0x8f, 0x8d, 0x94, 0xa5, 0xb9, 0xc6, 0xcd, 0xcf, 0x85, 0xd0, 0x03, 0xcf, 0xcc, 0xc0, 0x13, 0x88, 0x00, 0x04, 0x04, 0x63, 0x95, 0xab, 0xb0, 0x91, 0xbc, 0x05, 0x93, 0xa8, 0xbf, 0xc7, 0xc2, 0xb6, 0x8e, 0xbc, 0x06, 0xb9, 0x91, 0xad, 0xc2, 0xc8, 0xc2, 0xb5, 0x82, 0xbc, 0x06, 0x7f, 0x88, 0xab, 0xc1, 0xc6, 0xbd, 0x08, 0x8f, 0x00, 0x09, 0x71, 0xa8, 0xbf, 0xca, 0xce, 0xcf, 0xce, 0xca, 0xbb, 0x3f, 0x8d, 0x00, 0x05, 0x11, 0x76, 0x9a, 0xb8, 0xc8, 0xce, 0x90, 0xd0, 0x02, 0xce, 0xc7, 0xb8, 0x83, 0xbc, 0x06, 0xac, 0x6f, 0x93, 0xb3, 0xc5, 0xcd, 0xcf, 0x8b, 0xd0, 0x13, 0xcf, 0xce, 0xcd, 0xcc, 0xcb, 0xca, 0xc8, 0xc6, 0xc3, 0xc0, 0xbb, 0xb5, 0xaf, 0xa9, 0xa5, 0xa9, 0xb4, 0xc0, 0xc9, 0xce, 0x86, 0xd0, 0x02, 0xce, 0xca, 0xb2, 0x87, 0x00, 0x06, 0x07, 0x22, 0x57, 0x85, 0x9e, 0xae, 0xb1, 0x90, 0xbc, 0x06, 0xb5, 0x84, 0xa4, 0xbc, 0xc6, 0xc0, 0xb6, 0x8e, 0xbc, 0x06, 0xa6, 0x8a, 0xab, 0xc0, 0xc6, 0xc0, 0xb7, 0x82, 0xbc, 0x05, 0x75, 0x8e, 0xaf, 0xc2, 0xc6, 0xa2, 0x85, 0x00, 0x04, 0x12, 0x25, 0x35, 0x2e, 0x0d, 0x83, 0x00, 0x08, 0x48, 0x9a, 0xb6, 0xc6, 0xcd, 0xce, 0xca, 0xb2, 0x24, 0x87, 0x00, 0x01, 0x0a, 0x17, 0x82, 0x00, 0x05, 0x21, 0x7a, 0x9f, 0xbc, 0xca, 0xcf, 0x8f, 0xd0, 0x03, 0xcf, 0xcd, 0xc5, 0xb6, 0x83, 0xbc, 0x05, 0x9d, 0x76, 0x9b, 0xb9, 0xc8, 0xce, 0x8e, 0xd0, 0x81, 0xcf, 0x0d, 0xce, 0xcd, 0xcc, 0xc8, 0xc3, 0xbb, 0xb5, 0xb2, 0xab, 0xb0, 0xb9, 0xc3, 0xcb, 0xce, 0x86, 0xd0, 0x02, 0xce, 0xc7, 0x8f, 0x83, 0x00, 0x0a, 0x14, 0x3c, 0x5c, 0x6c, 0x74, 0x7e, 0x8a, 0x9e, 0xae, 0xb4, 0xb4, 0x8e, 0xbc, 0x08, 0xad, 0x9b, 0x82, 0x8d, 0xa9, 0xbf, 0xc5, 0xbd, 0xb9, 0x8b, 0xbc, 0x09, 0xba, 0xa9, 0x99, 0x7f, 0x93, 0xaf, 0xc2, 0xc6, 0xbc, 0xba, 0x81, 0xbc, 0x06, 0xb7, 0x70, 0x95, 0xb4, 0xc4, 0xc4, 0x81, 0x83, 0x00, 0x07, 0x07, 0x3c, 0x69, 0x76, 0x7e, 0x80, 0x76, 0x19, 0x82, 0x00, 0x07, 0x2d, 0x8e, 0xaf, 0xc3, 0xcc, 0xcb, 0xc2, 0x32, 0x84, 0x00, 0x05, 0x0a, 0x34, 0x4c, 0x63, 0x6d, 0x5b, 0x82, 0x00, 0x05, 0x32, 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0x8f, 0xd0, 0x03, 0xcf, 0xcd, 0xc4, 0xb5, 0x83, 0xbc, 0x05, 0x8f, 0x7e, 0xa1, 0xbd, 0xca, 0xcf, 0x93, 0xd0, 0x0d, 0xcf, 0xcc, 0xc6, 0xbc, 0xba, 0xbb, 0xba, 0xb4, 0xab, 0xaf, 0xbe, 0xc8, 0xcd, 0xcf, 0x85, 0xd0, 0x02, 0xcd, 0xc6, 0x6f, 0x82, 0x00, 0x0b, 0x12, 0x5b, 0x72, 0x84, 0x91, 0x99, 0xa1, 0xab, 0xb4, 0xbc, 0xb8, 0xb9, 0x81, 0xbc, 0x04, 0xba, 0x64, 0x6c, 0x74, 0x79, 0x83, 0x7a, 0x09, 0x7c, 0x76, 0x76, 0x7f, 0x8d, 0xa1, 0xb5, 0xc3, 0xc6, 0xba, 0x82, 0xbc, 0x04, 0xa5, 0x64, 0x6d, 0x76, 0x79, 0x81, 0x7a, 0x09, 0x7c, 0x75, 0x77, 0x82, 0x91, 0xa6, 0xba, 0xc6, 0xc6, 0xbb, 0x82, 0xbc, 0x06, 0xa7, 0x76, 0x9b, 0xb8, 0xc6, 0xc2, 0x60, 0x82, 0x00, 0x08, 0x03, 0x4a, 0x70, 0x86, 0x97, 0xa0, 0xa2, 0x9b, 0x5f, 0x82, 0x00, 0x06, 0x22, 0x88, 0xab, 0xc1, 0xc9, 0xc5, 0x5f, 0x83, 0x00, 0x07, 0x04, 0x30, 0x64, 0x76, 0x83, 0x8c, 0x8e, 0x5d, 0x82, 0x00, 0x05, 0x46, 0x88, 0xab, 0xc2, 0xcc, 0xcf, 0x8f, 0xd0, 0x03, 0xcf, 0xcc, 0xc3, 0xb5, 0x83, 0xbc, 0x05, 0x92, 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0x93, 0xd0, 0x03, 0xce, 0xc9, 0xbe, 0xbb, 0x81, 0xbc, 0x05, 0xb4, 0x9d, 0xb0, 0xc2, 0xcb, 0xcf, 0x84, 0xd0, 0x03, 0xcf, 0xcc, 0xc3, 0x4f, 0x82, 0x00, 0x0a, 0x3b, 0x73, 0x8e, 0xa3, 0xb0, 0xb7, 0xbc, 0xc1, 0xc5, 0xc4, 0xb8, 0x82, 0xbc, 0x05, 0xab, 0x60, 0x77, 0x89, 0x91, 0x93, 0x82, 0x94, 0x09, 0x95, 0x97, 0x9b, 0xa1, 0xab, 0xb7, 0xc2, 0xc8, 0xc6, 0xb8, 0x82, 0xbc, 0x05, 0x93, 0x66, 0x7c, 0x8a, 0x91, 0x93, 0x80, 0x94, 0x09, 0x95, 0x98, 0x9c, 0xa4, 0xad, 0xba, 0xc4, 0xca, 0xc6, 0xb7, 0x82, 0xbc, 0x06, 0x97, 0x7c, 0xa0, 0xbb, 0xc6, 0xc1, 0x40, 0x82, 0x00, 0x08, 0x30, 0x6e, 0x8a, 0xa2, 0xb3, 0xbb, 0xbb, 0xb3, 0x86, 0x82, 0x00, 0x06, 0x29, 0x85, 0xa8, 0xbf, 0xc5, 0x92, 0x01, 0x82, 0x00, 0x08, 0x15, 0x57, 0x72, 0x86, 0x98, 0xa5, 0xab, 0xab, 0x53, 0x82, 0x00, 0x05, 0x5b, 0x8e, 0xaf, 0xc4, 0xcc, 0xcf, 0x8f, 0xd0, 0x03, 0xcf, 0xcc, 0xc2, 0xb3, 0x83, 0xbc, 0x05, 0x98, 0x82, 0xa6, 0xc0, 0xcc, 0xcf, 0x92, 0xd0, 0x03, 0xcf, 0xcd, 0xc5, 0xb9, 0x83, 0xbc, 0x04, 0x9f, 0xa0, 0xba, 0xc8, 0xce, 0x84, 0xd0, 0x03, 0xcf, 0xcc, 0xc0, 0x31, 0x82, 0x00, 0x0a, 0x5d, 0x86, 0xa4, 0xb9, 0xc3, 0xc7, 0xca, 0xcc, 0xcc, 0xc6, 0xb8, 0x82, 0xbc, 0x04, 0x9b, 0x71, 0x8f, 0xa5, 0xb0, 0x84, 0xb4, 0x08, 0xb6, 0xb9, 0xbc, 0xc1, 0xc6, 0xcb, 0xcc, 0xc5, 0xb6, 0x82, 0xbc, 0x04, 0x87, 0x77, 0x95, 0xa8, 0xb1, 0x81, 0xb4, 0x09, 0xb5, 0xb6, 0xba, 0xbe, 0xc2, 0xc7, 0xcb, 0xcc, 0xc5, 0xb6, 0x82, 0xbc, 0x06, 0x8a, 0x82, 0xa5, 0xbf, 0xc6, 0xbf, 0x22, 0x81, 0x00, 0x09, 0x03, 0x5f, 0x82, 0xa0, 0xb7, 0xc3, 0xc8, 0xc7, 0xc0, 0x86, 0x82, 0x00, 0x05, 0x2f, 0x85, 0xa8, 0xbd, 0xc0, 0x35, 0x82, 0x00, 0x09, 0x08, 0x59, 0x77, 0x90, 0xa4, 0xb4, 0xbd, 0xc0, 0xb9, 0x3c, 0x81, 0x00, 0x05, 0x03, 0x6f, 0x94, 0xb4, 0xc6, 0xcd, 0x90, 0xd0, 0x03, 0xcf, 0xcc, 0xc3, 0xb4, 0x83, 0xbc, 0x05, 0x9e, 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0x92, 0xd0, 0x03, 0xcf, 0xcc, 0xc0, 0xb9, 0x83, 0xbc, 0x04, 0x95, 0x96, 0xb4, 0xc6, 0xcd, 0x84, 0xd0, 0x03, 0xcf, 0xcb, 0xbe, 0x15, 0x81, 0x00, 0x0b, 0x11, 0x70, 0x94, 0xb2, 0xc3, 0xcc, 0xce, 0xcf, 0xcf, 0xcc, 0xc6, 0xb6, 0x82, 0xbc, 0x04, 0x8e, 0x7e, 0x9e, 0xb7, 0xc2, 0x84, 0xc6, 0x08, 0xc7, 0xc8, 0xca, 0xcc, 0xcd, 0xce, 0xcc, 0xc2, 0xb5, 0x82, 0xbc, 0x04, 0x7c, 0x86, 0xa5, 0xbb, 0xc3, 0x82, 0xc6, 0x08, 0xc7, 0xc9, 0xca, 0xcc, 0xcd, 0xce, 0xcc, 0xc2, 0xb5, 0x82, 0xbc, 0x06, 0x7e, 0x89, 0xab, 0xc1, 0xc6, 0xbb, 0x07, 0x81, 0x00, 0x09, 0x1a, 0x71, 0x93, 0xb1, 0xc2, 0xcb, 0xcd, 0xcc, 0xc3, 0x77, 0x82, 0x00, 0x05, 0x3f, 0x88, 0xa9, 0xbb, 0xa2, 0x01, 0x81, 0x00, 0x0a, 0x01, 0x46, 0x76, 0x92, 0xab, 0xbb, 0xc4, 0xc9, 0xc7, 0xbd, 0x21, 0x81, 0x00, 0x05, 0x11, 0x76, 0x9b, 0xb8, 0xc8, 0xce, 0x90, 0xd0, 0x03, 0xcf, 0xcc, 0xc4, 0xb4, 0x83, 0xbc, 0x05, 0xa4, 0x7e, 0xa2, 0xbd, 0xcb, 0xcf, 0x92, 0xd0, 0x03, 0xce, 0xc9, 0xbb, 0xbb, 0x82, 0xbc, 0x05, 0xbb, 0x76, 0x93, 0xb3, 0xc6, 0xcd, 0x84, 0xd0, 0x03, 0xce, 0xc9, 0xb3, 0x01, 0x81, 0x00, 0x0b, 0x29, 0x7a, 0x9e, 0xba, 0xc8, 0xce, 0xd0, 0xd0, 0xcf, 0xcc, 0xc3, 0xb5, 0x82, 0xbc, 0x04, 0x83, 0x86, 0xa8, 0xc0, 0xca, 0x83, 0xcd, 0x80, 0xce, 0x81, 0xcf, 0x02, 0xcc, 0xc0, 0xb6, 0x82, 0xbc, 0x04, 0x74, 0x8e, 0xaf, 0xc2, 0xcb, 0x81, 0xcd, 0x80, 0xce, 0x06, 0xcf, 0xcf, 0xd0, 0xcf, 0xcc, 0xc0, 0xb7, 0x82, 0xbc, 0x05, 0x75, 0x8f, 0xb0, 0xc2, 0xc6, 0xa1, 0x82, 0x00, 0x09, 0x37, 0x7e, 0xa0, 0xbb, 0xc8, 0xce, 0xcf, 0xcc, 0xc3, 0x5d, 0x82, 0x00, 0x04, 0x52, 0x8c, 0xab, 0xba, 0x52, 0x82, 0x00, 0x0a, 0x22, 0x6d, 0x8b, 0xa8, 0xbc, 0xc7, 0xcc, 0xcd, 0xc9, 0xbb, 0x07, 0x81, 0x00, 0x05, 0x21, 0x7a, 0xa0, 0xbc, 0xca, 0xcf, 0x90, 0xd0, 0x03, 0xcf, 0xcd, 0xc5, 0xb4, 0x83, 0xbc, 0x05, 0xb6, 0x7e, 0x9e, 0xba, 0xc9, 0xce, 0x92, 0xd0, 0x02, 0xcd, 0xc7, 0xb7, 0x83, 0xbc, 0x05, 0xb1, 0x71, 0x96, 0xb4, 0xc6, 0xce, 0x84, 0xd0, 0x02, 0xce, 0xc7, 0x93, 0x82, 0x00, 0x0b, 0x42, 0x84, 0xa7, 0xc0, 0xcb, 0xcf, 0xd0, 0xd0, 0xcf, 0xcc, 0xc1, 0xb5, 0x82, 0xbc, 0x05, 0x78, 0x8d, 0xae, 0xc3, 0xcc, 0xcf, 0x88, 0xd0, 0x03, 0xcf, 0xcb, 0xbe, 0xb9, 0x81, 0xbc, 0x06, 0xb6, 0x70, 0x95, 0xb4, 0xc6, 0xcd, 0xcf, 0x86, 0xd0, 0x03, 0xcf, 0xcb, 0xbd, 0xb9, 0x81, 0xbc, 0x06, 0xb6, 0x70, 0x95, 0xb4, 0xc4, 0xc4, 0x7f, 0x82, 0x00, 0x09, 0x4d, 0x87, 0xa9, 0xc1, 0xcc, 0xcf, 0xcf, 0xcc, 0xc2, 0x40, 0x82, 0x00, 0x04, 0x67, 0x91, 0xae, 0xb7, 0x21, 0x82, 0x00, 0x09, 0x3f, 0x7c, 0x9e, 0xb7, 0xc6, 0xcc, 0xcf, 0xce, 0xc8, 0xa1, 0x82, 0x00, 0x05, 0x32, 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0x91, 0xd0, 0x03, 0xce, 0xc6, 0xb5, 0xb6, 0x83, 0xbc, 0x05, 0x8f, 0x94, 0xb3, 0xc6, 0xcd, 0xcf, 0x90, 0xd0, 0x03, 0xcf, 0xcc, 0xc3, 0xb6, 0x83, 0xbc, 0x05, 0xa2, 0x76, 0x9b, 0xb9, 0xc8, 0xce, 0x84, 0xd0, 0x02, 0xcd, 0xc6, 0x71, 0x82, 0x00, 0x0b, 0x59, 0x8c, 0xae, 0xc3, 0xcc, 0xcf, 0xd0, 0xd0, 0xcf, 0xcb, 0xbf, 0xb8, 0x81, 0xbc, 0x05, 0xbb, 0x70, 0x93, 0xb3, 0xc6, 0xcd, 0x89, 0xd0, 0x02, 0xce, 0xc9, 0xbb, 0x82, 0xbc, 0x05, 0xa5, 0x76, 0x9b, 0xb9, 0xc8, 0xce, 0x87, 0xd0, 0x02, 0xce, 0xc9, 0xba, 0x82, 0xbc, 0x06, 0xa6, 0x76, 0x9b, 0xb8, 0xc6, 0xc2, 0x5f, 0x82, 0x00, 0x09, 0x63, 0x8f, 0xb1, 0xc4, 0xcd, 0xcf, 0xcf, 0xcb, 0xc0, 0x24, 0x81, 0x00, 0x05, 0x0a, 0x72, 0x97, 0xb2, 0xb5, 0x0a, 0x82, 0x00, 0x09, 0x5b, 0x89, 0xab, 0xc0, 0xcb, 0xcf, 0xcf, 0xce, 0xc6, 0x80, 0x82, 0x00, 0x05, 0x47, 0x88, 0xab, 0xc2, 0xcc, 0xcf, 0x91, 0xd0, 0x03, 0xce, 0xc9, 0xbb, 0xb2, 0x83, 0xbc, 0x05, 0xa1, 0x89, 0xab, 0xc0, 0xcb, 0xcf, 0x90, 0xd0, 0x03, 0xce, 0xca, 0xbd, 0xba, 0x83, 0xbc, 0x05, 0x97, 0x7e, 0xa2, 0xbd, 0xcb, 0xcf, 0x83, 0xd0, 0x03, 0xcf, 0xcc, 0xc3, 0x52, 0x81, 0x00, 0x05, 0x03, 0x6d, 0x93, 0xb4, 0xc6, 0xcd, 0x80, 0xd0, 0x03, 0xce, 0xca, 0xbb, 0xbb, 0x81, 0xbc, 0x05, 0xad, 0x73, 0x99, 0xb7, 0xc8, 0xce, 0x89, 0xd0, 0x02, 0xce, 0xc7, 0xb7, 0x82, 0xbc, 0x05, 0x96, 0x7c, 0xa1, 0xbc, 0xca, 0xcf, 0x87, 0xd0, 0x02, 0xce, 0xc7, 0xb7, 0x82, 0xbc, 0x06, 0x97, 0x7c, 0xa0, 0xbb, 0xc6, 0xc1, 0x3f, 0x81, 0x00, 0x0a, 0x07, 0x71, 0x97, 0xb5, 0xc7, 0xce, 0xd0, 0xcf, 0xca, 0xbc, 0x09, 0x81, 0x00, 0x04, 0x19, 0x79, 0x9c, 0xb4, 0xa5, 0x82, 0x00, 0x0a, 0x08, 0x6d, 0x92, 0xb2, 0xc5, 0xcd, 0xcf, 0xcf, 0xcd, 0xc4, 0x5f, 0x82, 0x00, 0x05, 0x5c, 0x8e, 0xb0, 0xc4, 0xcc, 0xcf, 0x91, 0xd0, 0x03, 0xcf, 0xcb, 0xc0, 0xae, 0x84, 0xbc, 0x05, 0x8d, 0x9e, 0xb8, 0xc6, 0xcd, 0xcf, 0x8e, 0xd0, 0x03, 0xcf, 0xcc, 0xc5, 0xb7, 0x84, 0xbc, 0x05, 0x81, 0x86, 0xa9, 0xc1, 0xcc, 0xcf, 0x83, 0xd0, 0x03, 0xcf, 0xcc, 0xc1, 0x34, 0x81, 0x00, 0x05, 0x11, 0x76, 0x9a, 0xb8, 0xc8, 0xce, 0x80, 0xd0, 0x02, 0xce, 0xc8, 0xb8, 0x82, 0xbc, 0x05, 0x9e, 0x7a, 0x9e, 0xbb, 0xc8, 0xcd, 0x86, 0xcf, 0x80, 0xd0, 0x02, 0xcd, 0xc5, 0xb6, 0x82, 0xbc, 0x05, 0x89, 0x82, 0xa6, 0xc0, 0xcc, 0xcf, 0x86, 0xd0, 0x03, 0xcf, 0xcd, 0xc5, 0xb6, 0x82, 0xbc, 0x06, 0x89, 0x82, 0xa6, 0xbf, 0xc6, 0xbf, 0x21, 0x81, 0x00, 0x09, 0x18, 0x77, 0x9c, 0xba, 0xc9, 0xce, 0xd0, 0xce, 0xc8, 0xa5, 0x82, 0x00, 0x04, 0x2a, 0x7e, 0xa1, 0xb6, 0x95, 0x82, 0x00, 0x0a, 0x06, 0x70, 0x95, 0xb4, 0xc6, 0xcd, 0xcf, 0xce, 0xcc, 0xc1, 0x40, 0x81, 0x00, 0x05, 0x03, 0x6f, 0x95, 0xb4, 0xc6, 0xcd, 0x92, 0xd0, 0x04, 0xcf, 0xcc, 0xc3, 0xb0, 0xb6, 0x83, 0xbc, 0x05, 0xac, 0x8d, 0xab, 0xc0, 0xca, 0xce, 0x8e, 0xd0, 0x03, 0xce, 0xc9, 0xbd, 0xb9, 0x83, 0xbc, 0x06, 0xae, 0x6e, 0x91, 0xb1, 0xc4, 0xcd, 0xcf, 0x83, 0xd0, 0x03, 0xcf, 0xcb, 0xbe, 0x18, 0x81, 0x00, 0x05, 0x21, 0x7a, 0x9f, 0xbc, 0xca, 0xce, 0x80, 0xd0, 0x02, 0xcd, 0xc6, 0xb6, 0x82, 0xbc, 0x05, 0x8f, 0x7d, 0x9f, 0xba, 0xc6, 0xca, 0x83, 0xcb, 0x08, 0xcc, 0xcc, 0xcd, 0xce, 0xcf, 0xcf, 0xcc, 0xc2, 0xb5, 0x82, 0xbc, 0x05, 0x7d, 0x89, 0xab, 0xc2, 0xcc, 0xcf, 0x86, 0xd0, 0x03, 0xcf, 0xcc, 0xc2, 0xb5, 0x82, 0xbc, 0x06, 0x7e, 0x89, 0xab, 0xc1, 0xc6, 0xbb, 0x07, 0x81, 0x00, 0x09, 0x28, 0x7e, 0xa2, 0xbd, 0xcb, 0xcf, 0xd0, 0xce, 0xc6, 0x84, 0x82, 0x00, 0x05, 0x3e, 0x85, 0xa7, 0xb9, 0xb1, 0x04, 0x82, 0x00, 0x09, 0x5c, 0x91, 0xb0, 0xc2, 0xc9, 0xcc, 0xcc, 0xc7, 0xbc, 0x23, 0x81, 0x00, 0x05, 0x11, 0x76, 0x9b, 0xb8, 0xc8, 0xce, 0x93, 0xd0, 0x03, 0xcd, 0xc7, 0xb8, 0xae, 0x84, 0xbc, 0x05, 0x9c, 0x99, 0xb3, 0xc3, 0xcb, 0xce, 0x8b, 0xd0, 0x04, 0xcf, 0xce, 0xcb, 0xc2, 0xb8, 0x84, 0xbc, 0x05, 0x8f, 0x7a, 0x9c, 0xb9, 0xc8, 0xce, 0x84, 0xd0, 0x03, 0xce, 0xc9, 0xb4, 0x01, 0x81, 0x00, 0x0b, 0x32, 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0xd0, 0xd0, 0xcf, 0xcc, 0xc3, 0xb5, 0x82, 0xbc, 0x05, 0x7f, 0x7c, 0x9b, 0xb1, 0xbb, 0xbe, 0x82, 0xbf, 0x09, 0xc0, 0xc0, 0xc2, 0xc6, 0xca, 0xcd, 0xce, 0xcc, 0xc0, 0xb7, 0x82, 0xbc, 0x05, 0x74, 0x8f, 0xb1, 0xc4, 0xcd, 0xcf, 0x86, 0xd0, 0x03, 0xcf, 0xcc, 0xc0, 0xb6, 0x82, 0xbc, 0x05, 0x73, 0x8f, 0xb0, 0xc3, 0xc6, 0xa0, 0x82, 0x00, 0x09, 0x3b, 0x84, 0xa8, 0xc0, 0xcc, 0xcf, 0xcf, 0xcd, 0xc5, 0x64, 0x82, 0x00, 0x05, 0x52, 0x8b, 0xab, 0xbc, 0xb6, 0x24, 0x82, 0x00, 0x09, 0x10, 0x76, 0xa0, 0xb4, 0xbd, 0xc1, 0xc2, 0xbe, 0xb3, 0x08, 0x81, 0x00, 0x05, 0x21, 0x7a, 0xa0, 0xbc, 0xca, 0xcf, 0x93, 0xd0, 0x04, 0xcf, 0xcb, 0xc0, 0xab, 0xb9, 0x83, 0xbc, 0x07, 0xbb, 0x9b, 0xa0, 0xb6, 0xc4, 0xcb, 0xce, 0xcf, 0x88, 0xd0, 0x04, 0xcf, 0xce, 0xcb, 0xc2, 0xb8, 0x84, 0xbc, 0x06, 0xb3, 0x70, 0x89, 0xa9, 0xc0, 0xcb, 0xcf, 0x84, 0xd0, 0x02, 0xce, 0xc7, 0x96, 0x82, 0x00, 0x0b, 0x47, 0x88, 0xab, 0xc2, 0xcc, 0xcf, 0xd0, 0xd0, 0xcf, 0xcc, 0xc1, 0xb7, 0x82, 0xbc, 0x04, 0xa2, 0xa4, 0xab, 0xb1, 0xb3, 0x84, 0xb4, 0x08, 0xb3, 0xb2, 0xb7, 0xc0, 0xc7, 0xcc, 0xca, 0xbd, 0xb9, 0x81, 0xbc, 0x05, 0xb4, 0x71, 0x96, 0xb5, 0xc6, 0xce, 0x87, 0xd0, 0x03, 0xcf, 0xcb, 0xbd, 0xb9, 0x81, 0xbc, 0x06, 0xb4, 0x71, 0x96, 0xb4, 0xc5, 0xc4, 0x7e, 0x82, 0x00, 0x09, 0x4f, 0x8a, 0xac, 0xc2, 0xcc, 0xcf, 0xcf, 0xcc, 0xc2, 0x46, 0x82, 0x00, 0x05, 0x69, 0x92, 0xb1, 0xc0, 0xbb, 0x48, 0x83, 0x00, 0x07, 0x01, 0x25, 0x4d, 0x5f, 0x6d, 0x6d, 0x66, 0x53, 0x82, 0x00, 0x05, 0x34, 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0x93, 0xd0, 0x04, 0xcf, 0xcd, 0xc5, 0xb4, 0xa9, 0x84, 0xbc, 0x08, 0xb9, 0x9b, 0xa2, 0xb6, 0xc2, 0xca, 0xcd, 0xcf, 0xcf, 0x84, 0xd0, 0x05, 0xcf, 0xce, 0xcd, 0xc9, 0xc2, 0xb8, 0x85, 0xbc, 0x06, 0x87, 0x77, 0x99, 0xb4, 0xc6, 0xcd, 0xcf, 0x84, 0xd0, 0x02, 0xcd, 0xc6, 0x76, 0x82, 0x00, 0x0b, 0x5d, 0x8e, 0xb0, 0xc4, 0xcc, 0xcf, 0xd0, 0xd0, 0xcf, 0xcb, 0xbf, 0xb8, 0x90, 0xbc, 0x05, 0xaa, 0xae, 0xbf, 0xc8, 0xc7, 0xba, 0x82, 0xbc, 0x05, 0xa5, 0x76, 0x9c, 0xba, 0xc8, 0xce, 0x87, 0xd0, 0x02, 0xce, 0xc9, 0xba, 0x82, 0xbc, 0x06, 0xa5, 0x76, 0x9c, 0xb9, 0xc6, 0xc3, 0x5d, 0x82, 0x00, 0x09, 0x66, 0x91, 0xb2, 0xc5, 0xcd, 0xcf, 0xcf, 0xcc, 0xc0, 0x29, 0x81, 0x00, 0x06, 0x0a, 0x73, 0x98, 0xb5, 0xc3, 0xc0, 0x7c, 0x90, 0x00, 0x05, 0x48, 0x88, 0xab, 0xc2, 0xcc, 0xcf, 0x94, 0xd0, 0x04, 0xce, 0xca, 0xbf, 0xa8, 0xb2, 0x84, 0xbc, 0x08, 0xba, 0xa5, 0xa1, 0xb3, 0xbf, 0xc6, 0xcb, 0xcd, 0xce, 0x82, 0xcf, 0x05, 0xce, 0xcc, 0xca, 0xc6, 0xbe, 0xb8, 0x85, 0xbc, 0x06, 0xa9, 0x6c, 0x8a, 0xa9, 0xbf, 0xca, 0xce, 0x84, 0xd0, 0x03, 0xcf, 0xcc, 0xc4, 0x56, 0x81, 0x00, 0x05, 0x04, 0x71, 0x96, 0xb5, 0xc6, 0xcd, 0x80, 0xd0, 0x02, 0xcf, 0xca, 0xbd, 0x91, 0xbc, 0x05, 0xb1, 0x9b, 0xb4, 0xc3, 0xc5, 0xb8, 0x82, 0xbc, 0x05, 0x94, 0x7f, 0xa3, 0xbe, 0xca, 0xcf, 0x87, 0xd0, 0x02, 0xce, 0xc8, 0xb8, 0x82, 0xbc, 0x06, 0x94, 0x7f, 0xa3, 0xbd, 0xc6, 0xc2, 0x3f, 0x81, 0x00, 0x0a, 0x09, 0x73, 0x98, 0xb7, 0xc7, 0xce, 0xd0, 0xcf, 0xcb, 0xbe, 0x0e, 0x81, 0x00, 0x07, 0x1a, 0x7a, 0x9e, 0xbb, 0xc6, 0xc3, 0xb3, 0x2f, 0x8f, 0x00, 0x05, 0x5d, 0x8f, 0xb1, 0xc4, 0xcd, 0xcf, 0x94, 0xd0, 0x05, 0xcf, 0xcc, 0xc6, 0xb6, 0xa2, 0xb4, 0x85, 0xbc, 0x07, 0xaf, 0xa4, 0xa9, 0xb6, 0xc0, 0xc5, 0xc8, 0xca, 0x80, 0xcb, 0x05, 0xca, 0xc7, 0xc4, 0xbf, 0xb8, 0xb8, 0x85, 0xbc, 0x07, 0xb4, 0x74, 0x7e, 0x9e, 0xb6, 0xc6, 0xcd, 0xcf, 0x84, 0xd0, 0x03, 0xcf, 0xcc, 0xc3, 0x48, 0x81, 0x00, 0x05, 0x25, 0x7a, 0x9e, 0xbb, 0xc9, 0xce, 0x80, 0xd0, 0x03, 0xcf, 0xca, 0xbd, 0xb9, 0x90, 0xbc, 0x05, 0xa7, 0x8f, 0xad, 0xc1, 0xc3, 0xb7, 0x82, 0xbc, 0x05, 0x78, 0x89, 0xab, 0xc1, 0xcc, 0xcf, 0x87, 0xd0, 0x02, 0xce, 0xc7, 0xb7, 0x82, 0xbc, 0x06, 0x77, 0x89, 0xab, 0xc1, 0xc7, 0xc1, 0x37, 0x81, 0x00, 0x0a, 0x2b, 0x7e, 0xa0, 0xbc, 0xca, 0xcf, 0xd0, 0xcf, 0xcb, 0xbd, 0x08, 0x81, 0x00, 0x08, 0x3f, 0x84, 0xa7, 0xbf, 0xc9, 0xc8, 0xbd, 0x99, 0x1d, 0x8d, 0x00, 0x05, 0x0e, 0x74, 0x98, 0xb6, 0xc6, 0xce, 0x96, 0xd0, 0x05, 0xce, 0xcb, 0xc2, 0xb0, 0x9f, 0xb7, 0x86, 0xbc, 0x0c, 0xb2, 0xa9, 0xaa, 0xb3, 0xb8, 0xbc, 0xbe, 0xbf, 0xbe, 0xbc, 0xb8, 0xb6, 0xb9, 0x86, 0xbc, 0x07, 0xbb, 0x83, 0x76, 0x93, 0xae, 0xc1, 0xcb, 0xcf, 0x85, 0xd0, 0x03, 0xcf, 0xcc, 0xc3, 0x7c, 0x81, 0x00, 0x05, 0x58, 0x89, 0xa9, 0xc0, 0xcb, 0xcf, 0x80, 0xd0, 0x03, 0xcf, 0xcb, 0xbf, 0xb2, 0x8f, 0xbc, 0x07, 0xb9, 0x81, 0x91, 0xae, 0xc1, 0xc4, 0xb8, 0xba, 0x80, 0xbc, 0x05, 0xa7, 0x76, 0x96, 0xb3, 0xc5, 0xcd, 0x88, 0xd0, 0x03, 0xce, 0xc7, 0xb7, 0xbb, 0x80, 0xbc, 0x07, 0xa7, 0x76, 0x96, 0xb3, 0xc5, 0xc9, 0xc2, 0x6d, 0x80, 0x00, 0x0b, 0x01, 0x5f, 0x8b, 0xab, 0xc1, 0xcc, 0xcf, 0xd0, 0xcf, 0xcb, 0xbf, 0x3f, 0x80, 0x00, 0x0b, 0x09, 0x70, 0x92, 0xb0, 0xc3, 0xcc, 0xcc, 0xc5, 0xb4, 0x98, 0x3f, 0x0d, 0x8b, 0x00, 0x05, 0x40, 0x83, 0xa4, 0xbd, 0xca, 0xcf, 0x97, 0xd0, 0x05, 0xce, 0xc9, 0xbe, 0xab, 0x9e, 0xb9, 0x87, 0xbc, 0x07, 0xbb, 0xb7, 0xb3, 0xb1, 0xb3, 0xb3, 0xb5, 0xb9, 0x89, 0xbc, 0x06, 0x8f, 0x70, 0x8c, 0xa8, 0xbd, 0xc8, 0xcd, 0x86, 0xd0, 0x0d, 0xcf, 0xcd, 0xc6, 0xb3, 0x4a, 0x11, 0x1e, 0x4c, 0x81, 0x9b, 0xb4, 0xc6, 0xcd, 0xcf, 0x80, 0xd0, 0x07, 0xcf, 0xcc, 0xc3, 0xb0, 0xa2, 0x9d, 0xa3, 0xad, 0x89, 0xac, 0x12, 0xa6, 0x97, 0x7a, 0x83, 0x9e, 0xb6, 0xc5, 0xc7, 0xbd, 0xad, 0xac, 0xb3, 0xa5, 0x7e, 0x8a, 0xa6, 0xbd, 0xc9, 0xce, 0x88, 0xd0, 0x32, 0xce, 0xc9, 0xbd, 0xab, 0xae, 0xb3, 0xa3, 0x7d, 0x8a, 0xa6, 0xbd, 0xc9, 0xcc, 0xc5, 0xab, 0x46, 0x0e, 0x21, 0x4f, 0x82, 0x9e, 0xb6, 0xc6, 0xcd, 0xd0, 0xd0, 0xcf, 0xcc, 0xc2, 0x9a, 0x3f, 0x13, 0x2b, 0x5c, 0x87, 0xa3, 0xbb, 0xc8, 0xcd, 0xce, 0xcb, 0xc2, 0xb4, 0xa0, 0x8c, 0x60, 0x35, 0x28, 0x1e, 0x19, 0x13, 0x83, 0x0e, 0x07, 0x1d, 0x44, 0x7a, 0x96, 0xb1, 0xc3, 0xcc, 0xcf, 0x97, 0xd0, 0x05, 0xcf, 0xcd, 0xc7, 0xbb, 0xa8, 0xa1, 0x99, 0xbc, 0x08, 0xbb, 0x8a, 0x6d, 0x88, 0xa3, 0xb9, 0xc6, 0xcc, 0xcf, 0x87, 0xd0, 0x0b, 0xce, 0xca, 0xbf, 0xac, 0x99, 0x8d, 0x8e, 0x9b, 0xaf, 0xc0, 0xca, 0xce, 0x82, 0xd0, 0x07, 0xce, 0xc8, 0xbd, 0xab, 0x9a, 0x8b, 0x82, 0x7e, 0x88, 0x7a, 0x12, 0x7d, 0x82, 0x8e, 0x9e, 0xb2, 0xc1, 0xca, 0xcb, 0xc3, 0xb4, 0x9f, 0x8e, 0x89, 0x90, 0xa2, 0xb6, 0xc5, 0xcc, 0xcf, 0x88, 0xd0, 0x17, 0xcf, 0xcc, 0xc3, 0xb3, 0x9e, 0x8e, 0x88, 0x90, 0xa2, 0xb6, 0xc5, 0xcc, 0xcd, 0xc9, 0xbe, 0xab, 0x98, 0x8c, 0x8e, 0x9e, 0xb1, 0xc1, 0xcb, 0xce, 0x80, 0xd0, 0x18, 0xcd, 0xc7, 0xbb, 0xa7, 0x95, 0x8d, 0x92, 0xa0, 0xb4, 0xc3, 0xcc, 0xcf, 0xcf, 0xce, 0xca, 0xc3, 0xb9, 0xab, 0x9e, 0x93, 0x8a, 0x85, 0x81, 0x7e, 0x7c, 0x82, 0x7a, 0x06, 0x7f, 0x89, 0x98, 0xab, 0xbe, 0xc9, 0xce, 0x99, 0xd0, 0x06, 0xcf, 0xcc, 0xc6, 0xba, 0xa5, 0xa0, 0xb7, 0x96, 0xbc, 0x08, 0xb6, 0x82, 0x69, 0x85, 0xa0, 0xb6, 0xc4, 0xcc, 0xcf, 0x88, 0xd0, 0x0b, 0xcf, 0xcd, 0xc7, 0xbe, 0xb3, 0xab, 0xac, 0xb4, 0xc0, 0xc8, 0xcd, 0xcf, 0x82, 0xd0, 0x08, 0xcf, 0xcc, 0xc7, 0xbf, 0xb4, 0xab, 0xa6, 0xa2, 0xa0, 0x86, 0x9e, 0x12, 0x9f, 0xa1, 0xa5, 0xac, 0xb7, 0xc2, 0xc9, 0xcd, 0xcd, 0xca, 0xc2, 0xb6, 0xac, 0xa9, 0xae, 0xb8, 0xc3, 0xcb, 0xce, 0x89, 0xd0, 0x17, 0xcf, 0xce, 0xca, 0xc1, 0xb5, 0xac, 0xa9, 0xae, 0xb8, 0xc3, 0xcb, 0xce, 0xcf, 0xcc, 0xc6, 0xbd, 0xb3, 0xab, 0xad, 0xb5, 0xc0, 0xc9, 0xcd, 0xcf, 0x80, 0xd0, 0x19, 0xcf, 0xcc, 0xc5, 0xbb, 0xb1, 0xab, 0xaf, 0xb8, 0xc2, 0xca, 0xce, 0xd0, 0xd0, 0xcf, 0xce, 0xcc, 0xc6, 0xc1, 0xba, 0xb3, 0xac, 0xa8, 0xa4, 0xa3, 0xa1, 0x9f, 0x80, 0x9e, 0x07, 0xa0, 0xa4, 0xa9, 0xb3, 0xbf, 0xc7, 0xcc, 0xcf, 0x9a, 0xd0, 0x06, 0xcf, 0xcc, 0xc6, 0xb9, 0xa5, 0x94, 0xa4, 0x94, 0xbc, 0x08, 0xb5, 0xab, 0x60, 0x7a, 0x9a, 0xb3, 0xc3, 0xcb, 0xce, 0x8a, 0xd0, 0x09, 0xcf, 0xcc, 0xc9, 0xc4, 0xc2, 0xc2, 0xc6, 0xca, 0xcd, 0xcf, 0x84, 0xd0, 0x08, 0xcf, 0xcc, 0xca, 0xc6, 0xc2, 0xc0, 0xbd, 0xbc, 0xbc, 0x84, 0xbb, 0x13, 0xbc, 0xbc, 0xbd, 0xbf, 0xc2, 0xc6, 0xcb, 0xcd, 0xcf, 0xcf, 0xcd, 0xcb, 0xc6, 0xc2, 0xc1, 0xc2, 0xc6, 0xcb, 0xce, 0xcf, 0x8a, 0xd0, 0x15, 0xcf, 0xcd, 0xca, 0xc6, 0xc2, 0xc0, 0xc2, 0xc6, 0xcb, 0xce, 0xcf, 0xd0, 0xcf, 0xcc, 0xc8, 0xc4, 0xc2, 0xc2, 0xc6, 0xca, 0xcd, 0xcf, 0x81, 0xd0, 0x0a, 0xcf, 0xce, 0xcc, 0xc7, 0xc3, 0xc2, 0xc3, 0xc6, 0xcb, 0xce, 0xcf, 0x81, 0xd0, 0x09, 0xcf, 0xcd, 0xcc, 0xc8, 0xc5, 0xc2, 0xc0, 0xbf, 0xbe, 0xbd, 0x82, 0xbc, 0x05, 0xbe, 0xc1, 0xc5, 0xc9, 0xcd, 0xcf, 0x9c, 0xd0, 0x07, 0xcf, 0xcc, 0xc5, 0xba, 0xab, 0x96, 0x93, 0xae, 0x90, 0xbc, 0x0a, 0xb9, 0xb6, 0xbc, 0xba, 0x92, 0x84, 0xa4, 0xbc, 0xc8, 0xcd, 0xcf, 0x8b, 0xd0, 0x09, 0xcf, 0xce, 0xcc, 0xcc, 0xca, 0xcb, 0xcc, 0xcc, 0xce, 0xcf, 0x99, 0xd0, 0x0d, 0xcf, 0xce, 0xcd, 0xcd, 0xce, 0xcf, 0xd0, 0xd0, 0xcf, 0xce, 0xcd, 0xcd, 0xce, 0xcf, 0xe8, 0xd0, 0x08, 0xcf, 0xcc, 0xc6, 0xbf, 0xb2, 0xa1, 0x8f, 0x9b, 0xb5, 0x8c, 0xbc, 0x01, 0xb3, 0xb4, 0x81, 0xbc, 0x05, 0xb0, 0x85, 0xa1, 0xbb, 0xc8, 0xce, 0x8b, 0xd0, 0x0b, 0xcf, 0xce, 0xca, 0xc5, 0xc0, 0xbe, 0xbe, 0xc0, 0xc5, 0xca, 0xcd, 0xcf, 0x8f, 0xd0, 0x01, 0xcf, 0xcf, 0x83, 0xd0, 0x0f, 0xcf, 0xcd, 0xcb, 0xc7, 0xc6, 0xc9, 0xcc, 0xce, 0xce, 0xcc, 0xc9, 0xc6, 0xc6, 0xca, 0xcd, 0xcf, 0xc7, 0xd0, 0x00, 0xcf, 0x9d, 0xd0, 0x0b, 0xcf, 0xcc, 0xc9, 0xc3, 0xba, 0xab, 0x9b, 0x8c, 0x90, 0x9f, 0xb1, 0xbb, 0x84, 0xbc, 0x03, 0xb7, 0xa7, 0x95, 0xac, 0x84, 0xbc, 0x05, 0xa4, 0x94, 0xb2, 0xc3, 0xcc, 0xcf, 0x8a, 0xd0, 0x0c, 0xce, 0xcb, 0x76, 0x04, 0x04, 0x08, 0x1e, 0x6d, 0xb4, 0xc0, 0xc8, 0xcd, 0xcf, 0x8c, 0xd0, 0x05, 0xcf, 0xce, 0xcd, 0xcd, 0xce, 0xcf, 0x81, 0xd0, 0x0f, 0xce, 0xca, 0x7a, 0x08, 0xb0, 0xbf, 0xc6, 0xcc, 0xcc, 0xc5, 0x1e, 0x3c, 0xba, 0xc1, 0xc9, 0xce, 0xc4, 0xd0, 0x06, 0xcf, 0xcf, 0xce, 0xcd, 0xce, 0xcf, 0xcf, 0x9b, 0xd0, 0x16, 0xcf, 0xce, 0xcc, 0xc7, 0xc0, 0xb6, 0xab, 0x9c, 0x8f, 0x84, 0x81, 0x88, 0x8e, 0x8e, 0x8d, 0x8b, 0x8c, 0x82, 0x72, 0x72, 0x76, 0x87, 0xb8, 0x83, 0xbc, 0x05, 0xb5, 0x8f, 0xa3, 0xbb, 0xc8, 0xce, 0x89, 0xd0, 0x0d, 0xcf, 0xcd, 0xc6, 0x59, 0x00, 0x0d, 0x08, 0x00, 0x00, 0x76, 0xb1, 0xc1, 0xca, 0xce, 0x8b, 0xd0, 0x1b, 0xcf, 0xcc, 0xca, 0xc7, 0xc7, 0xcb, 0xcd, 0xcf, 0xd0, 0xd0, 0xcf, 0xcc, 0xc4, 0x2b, 0x00, 0x76, 0xaf, 0xbe, 0xc7, 0xc6, 0x7e, 0x00, 0x1b, 0xa6, 0xb5, 0xc4, 0xcc, 0xcf, 0xc2, 0xd0, 0x08, 0xcf, 0xce, 0xcc, 0xc9, 0xc7, 0xc8, 0xcc, 0xce, 0xcf, 0x9c, 0xd0, 0x0b, 0xcf, 0xcd, 0xcb, 0xc6, 0xc0, 0xb8, 0xaf, 0xa7, 0x9e, 0x98, 0x91, 0x8d, 0x80, 0x8a, 0x05, 0x8d, 0x92, 0x97, 0x98, 0x92, 0xac, 0x84, 0xbc, 0x05, 0xab, 0x91, 0xad, 0xc1, 0xcb, 0xcf, 0x88, 0xd0, 0x0d, 0xcf, 0xcc, 0xc3, 0x3f, 0x00, 0x6a, 0x7d, 0x3e, 0x00, 0x3c, 0xa2, 0xb8, 0xc6, 0xcd, 0x81, 0xcf, 0x83, 0xd0, 0x81, 0xcf, 0x1c, 0xcc, 0xc0, 0x24, 0x50, 0xbd, 0xc3, 0xcb, 0xce, 0xd0, 0xd0, 0xce, 0xc9, 0xa3, 0x00, 0x00, 0x44, 0x9e, 0xb4, 0xc1, 0xc0, 0x22, 0x00, 0x04, 0x93, 0xa9, 0xbf, 0xcb, 0xcf, 0xd0, 0x82, 0xcf, 0x80, 0xd0, 0x81, 0xcf, 0x83, 0xd0, 0x82, 0xcf, 0x82, 0xd0, 0x82, 0xcf, 0x81, 0xd0, 0x80, 0xcf, 0x81, 0xd0, 0x85, 0xcf, 0x82, 0xd0, 0x80, 0xcf, 0x81, 0xd0, 0x81, 0xcf, 0x08, 0xce, 0xcc, 0x93, 0x23, 0x7a, 0xbf, 0xc6, 0xcc, 0xcf, 0x9d, 0xd0, 0x14, 0xcf, 0xcf, 0xcd, 0xcb, 0xc7, 0xc3, 0xc0, 0xbb, 0xb5, 0xb2, 0xae, 0xac, 0xab, 0xac, 0xaf, 0xb3, 0xb5, 0xb5, 0xae, 0x9e, 0xb6, 0x83, 0xbc, 0x06, 0xba, 0x99, 0x9e, 0xb7, 0xc6, 0xcd, 0xcf, 0x87, 0xd0, 0x0c, 0xcf, 0xcb, 0xc0, 0x29, 0x00, 0x77, 0x7f, 0x60, 0x00, 0x32, 0x99, 0xb2, 0xc3, 0x81, 0xcc, 0x01, 0xcd, 0xce, 0x80, 0xcf, 0x01, 0xce, 0xcd, 0x81, 0xcc, 0x13, 0xc9, 0xa1, 0x00, 0x46, 0xac, 0xba, 0xc6, 0xcc, 0xcf, 0xcf, 0xcd, 0xc5, 0x58, 0x00, 0x00, 0x1b, 0x8f, 0xa9, 0xb9, 0x84, 0x80, 0x00, 0x03, 0x79, 0xa0, 0xbb, 0xc8, 0x80, 0xcd, 0x01, 0xcc, 0xcc, 0x80, 0xcd, 0x0b, 0xce, 0xce, 0xcd, 0xcd, 0xcc, 0xcc, 0xcd, 0xce, 0xcf, 0xcf, 0xce, 0xcd, 0x80, 0xcc, 0x06, 0xcd, 0xcd, 0xce, 0xce, 0xcf, 0xce, 0xcd, 0x80, 0xcc, 0x01, 0xcd, 0xcd, 0x80, 0xce, 0x03, 0xcd, 0xcc, 0xcc, 0xcd, 0x81, 0xce, 0x00, 0xcd, 0x83, 0xcc, 0x08, 0xcd, 0xcd, 0xce, 0xcf, 0xce, 0xce, 0xcd, 0xcc, 0xcd, 0x80, 0xce, 0x01, 0xcd, 0xcd, 0x81, 0xcc, 0x08, 0xc6, 0x6c, 0x00, 0x73, 0xb1, 0xbe, 0xc8, 0xcd, 0xcf, 0x9e, 0xd0, 0x08, 0xcf, 0xcf, 0xce, 0xcc, 0xcb, 0xc9, 0xc7, 0xc5, 0xc3, 0x80, 0xc2, 0x06, 0xc3, 0xc5, 0xc6, 0xc6, 0xc0, 0xaf, 0xaa, 0x84, 0xbc, 0x05, 0xaf, 0x8d, 0xa9, 0xbf, 0xca, 0xce, 0x87, 0xd0, 0x65, 0xcf, 0xcb, 0xbf, 0x14, 0x07, 0x81, 0x80, 0x31, 0x00, 0x50, 0x97, 0xaf, 0xc0, 0xc7, 0xc6, 0xc4, 0xc4, 0xc6, 0xc9, 0xcc, 0xcd, 0xcc, 0xcb, 0xc7, 0xc5, 0xc3, 0xc5, 0xc6, 0xc2, 0x82, 0x00, 0x50, 0x9e, 0xaf, 0xc0, 0xcb, 0xce, 0xcf, 0xcb, 0xc0, 0x15, 0x07, 0x0d, 0x03, 0x7f, 0x9f, 0xb0, 0x2b, 0x00, 0x13, 0x00, 0x60, 0x9a, 0xb5, 0xc5, 0xc9, 0xc7, 0xc5, 0xc4, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc8, 0xc6, 0xc5, 0xc4, 0xc5, 0xc6, 0xc9, 0xcc, 0xcc, 0xca, 0xc7, 0xc5, 0xc4, 0xc4, 0xc5, 0xc6, 0xc8, 0xca, 0xcb, 0xca, 0xc6, 0xc5, 0xc4, 0xc4, 0xc5, 0xc6, 0xc7, 0xc9, 0xc9, 0xc6, 0xc5, 0xc4, 0xc6, 0xc8, 0xcb, 0xca, 0xc8, 0xc5, 0x80, 0xc3, 0x1d, 0xc4, 0xc5, 0xc4, 0xc5, 0xc7, 0xca, 0xcc, 0xca, 0xc7, 0xc5, 0xc4, 0xc5, 0xc8, 0xca, 0xca, 0xc7, 0xc6, 0xc4, 0xc4, 0xc5, 0xc4, 0xbf, 0x4f, 0x00, 0x7a, 0xa2, 0xb4, 0xc4, 0xcc, 0xcf, 0xa1, 0xd0, 0x04, 0xcf, 0xcf, 0xce, 0xce, 0xcd, 0x82, 0xcc, 0x06, 0xcd, 0xcd, 0xcc, 0xc8, 0xbc, 0xa7, 0xb3, 0x84, 0xbc, 0x05, 0xa1, 0x98, 0xb4, 0xc4, 0xcc, 0xcf, 0x86, 0xd0, 0x7f, 0xcf, 0xca, 0xb9, 0x01, 0x06, 0x27, 0x0e, 0x00, 0x29, 0x82, 0x96, 0xad, 0xbb, 0x93, 0x59, 0x47, 0x66, 0xaf, 0xbc, 0xc3, 0xc7, 0xc6, 0x9a, 0x5a, 0x46, 0x63, 0xab, 0xb7, 0x8e, 0x35, 0x00, 0x2a, 0x47, 0x9f, 0xbb, 0xc8, 0xcd, 0xcd, 0xc8, 0x89, 0x00, 0x32, 0x2b, 0x00, 0x5d, 0x97, 0x81, 0x00, 0x28, 0x35, 0x00, 0x4e, 0x96, 0xb1, 0xbe, 0x99, 0x60, 0x4d, 0x69, 0xa9, 0x72, 0x5b, 0xb7, 0xac, 0x5d, 0x82, 0x76, 0x4e, 0x7a, 0xb4, 0xbe, 0xc3, 0xc3, 0x92, 0x5d, 0x4d, 0x6f, 0xae, 0x69, 0x63, 0xbb, 0xc0, 0xc2, 0x8e, 0x5c, 0x4e, 0x6f, 0xaf, 0x63, 0x6d, 0xbb, 0xbd, 0x9a, 0x5c, 0x48, 0x69, 0xb1, 0xbc, 0xc1, 0x8a, 0x5d, 0x82, 0x4d, 0x50, 0x8f, 0xa1, 0x57, 0x52, 0x88, 0xb7, 0xbf, 0xc2, 0xa9, 0x63, 0x47, 0x60, 0xa7, 0xbb, 0xbf, 0x7d, 0x5d, 0x99, 0x5a, 0x5b, 0x9e, 0xb4, 0x73, 0x1d, 0x06, 0x00, 0x3c, 0x59, 0xab, 0xbf, 0xca, 0xce, 0xa5, 0xd0, 0x84, 0xcf, 0x06, 0xd0, 0xcf, 0xcc, 0xc5, 0xb4, 0xa7, 0xba, 0x83, 0xbc, 0x05, 0xb3, 0x8d, 0xa4, 0xbc, 0xc9, 0xce, 0x86, 0xd0, 0x02, 0xce, 0xc8, 0xa3, 0x82, 0x00, 0x05, 0x07, 0x4c, 0x93, 0xa7, 0x5d, 0x01, 0x80, 0x00, 0x05, 0x17, 0x9e, 0xb4, 0xbd, 0x6a, 0x03, 0x80, 0x00, 0x02, 0x13, 0x92, 0x4d, 0x80, 0x00, 0x21, 0x03, 0x9b, 0xb4, 0xc6, 0xcc, 0xcc, 0xc4, 0x40, 0x00, 0x63, 0x49, 0x00, 0x3c, 0x8d, 0x2f, 0x00, 0x64, 0x46, 0x00, 0x3f, 0x93, 0xa9, 0x59, 0x01, 0x00, 0x09, 0x00, 0x19, 0x11, 0x0b, 0xa4, 0x7e, 0x00, 0x0d, 0x80, 0x00, 0x24, 0x3e, 0xab, 0xb4, 0x49, 0x00, 0x00, 0x09, 0x00, 0x21, 0x08, 0x1b, 0xa7, 0xaf, 0x42, 0x00, 0x00, 0x03, 0x00, 0x25, 0x01, 0x2b, 0xa4, 0x66, 0x03, 0x00, 0x03, 0x00, 0x1d, 0x9e, 0xb0, 0x3f, 0x00, 0x01, 0x00, 0x00, 0x04, 0x0e, 0x80, 0x00, 0x11, 0x69, 0xab, 0x84, 0x0a, 0x00, 0x04, 0x00, 0x11, 0x8c, 0xac, 0x27, 0x00, 0x0d, 0x00, 0x00, 0x01, 0x8e, 0x21, 0x80, 0x00, 0x04, 0x28, 0xa4, 0xbb, 0xc7, 0xce, 0xae, 0xd0, 0x04, 0xce, 0xca, 0xc0, 0xab, 0xb0, 0x84, 0xbc, 0x05, 0xa8, 0x93, 0xb0, 0xc2, 0xcc, 0xcf, 0x85, 0xd0, 0x7f, 0xce, 0xc7, 0x8a, 0x00, 0x2e, 0x63, 0x5d, 0x45, 0x0e, 0x00, 0x6e, 0x7a, 0x01, 0x11, 0x58, 0x6e, 0x27, 0x00, 0x40, 0xa2, 0x8f, 0x03, 0x0e, 0x55, 0x70, 0x2b, 0x00, 0x35, 0x8a, 0x2d, 0x00, 0x65, 0x7d, 0x9e, 0xb4, 0xc5, 0xcc, 0xca, 0xb4, 0x07, 0x13, 0x84, 0x70, 0x00, 0x1d, 0x6d, 0x01, 0x21, 0x82, 0x5c, 0x00, 0x2f, 0x8e, 0x71, 0x00, 0x25, 0x74, 0x90, 0x69, 0x06, 0x00, 0x1a, 0x8e, 0x5f, 0x00, 0x14, 0x60, 0x5f, 0x04, 0x07, 0x91, 0x63, 0x00, 0x2e, 0x7a, 0x8f, 0x60, 0x01, 0x00, 0x29, 0x93, 0x5b, 0x00, 0x2e, 0x76, 0x88, 0x4f, 0x00, 0x00, 0x35, 0x7c, 0x04, 0x0a, 0x6e, 0x80, 0x40, 0x00, 0x46, 0x9b, 0x24, 0x00, 0x32, 0x69, 0x28, 0x00, 0x13, 0x63, 0x66, 0x01, 0x1e, 0x91, 0x14, 0x01, 0x60, 0x83, 0x55, 0x00, 0x2a, 0x97, 0x0e, 0x00, 0x41, 0x6a, 0x2b, 0x00, 0x4a, 0x84, 0x0a, 0x06, 0x13, 0x71, 0x84, 0xa4, 0xbb, 0xc7, 0xce, 0xae, 0xd0, 0x05, 0xcf, 0xcd, 0xc6, 0xb8, 0xa4, 0xb7, 0x83, 0xbc, 0x06, 0xb7, 0x94, 0x9f, 0xb9, 0xc7, 0xcd, 0xcf, 0x83, 0xd0, 0x71, 0xcf, 0xcd, 0xc6, 0x72, 0x00, 0x48, 0x7e, 0x85, 0x88, 0x4d, 0x00, 0x3f, 0x3f, 0x00, 0x4d, 0x86, 0x89, 0x73, 0x00, 0x1a, 0x92, 0x4f, 0x00, 0x48, 0x87, 0x89, 0x7a, 0x01, 0x14, 0x83, 0x1e, 0x03, 0x7c, 0x8e, 0xa6, 0xbb, 0xc7, 0xcb, 0xc6, 0x70, 0x00, 0x48, 0x8a, 0x8c, 0x11, 0x03, 0x29, 0x00, 0x5d, 0x86, 0x76, 0x00, 0x20, 0x89, 0x32, 0x00, 0x6e, 0x8e, 0x93, 0x94, 0x34, 0x00, 0x28, 0x82, 0x46, 0x00, 0x5f, 0x84, 0x86, 0x22, 0x00, 0x7e, 0x22, 0x01, 0x7a, 0x8e, 0x94, 0x93, 0x25, 0x00, 0x35, 0x85, 0x1e, 0x01, 0x7d, 0x8e, 0x93, 0x92, 0x1e, 0x00, 0x3f, 0x48, 0x00, 0x17, 0x35, 0x35, 0x32, 0x00, 0x1a, 0x8c, 0x10, 0x10, 0x7f, 0x81, 0x4d, 0x00, 0x4f, 0x7f, 0x86, 0x0d, 0x15, 0x64, 0x00, 0x0d, 0x80, 0x35, 0x12, 0x07, 0x04, 0x82, 0x01, 0x20, 0x80, 0x84, 0x63, 0x00, 0x3b, 0x7d, 0x00, 0x22, 0x7f, 0x93, 0xab, 0xc0, 0xca, 0xce, 0xaf, 0xd0, 0x04, 0xcf, 0xcc, 0xc2, 0xaf, 0xad, 0x84, 0xbc, 0x05, 0xad, 0x8e, 0xab, 0xc0, 0xcb, 0xce, 0x83, 0xd0, 0x7f, 0xcf, 0xcc, 0xc4, 0x5c, 0x00, 0x5a, 0x8a, 0x94, 0x99, 0x50, 0x00, 0x38, 0x29, 0x00, 0x64, 0x86, 0x90, 0x7e, 0x00, 0x1e, 0x89, 0x37, 0x00, 0x63, 0x88, 0x91, 0x83, 0x01, 0x17, 0x7e, 0x0e, 0x11, 0x86, 0x9a, 0xb2, 0xc2, 0xcb, 0xcb, 0xc2, 0x29, 0x01, 0x7c, 0x92, 0x99, 0x35, 0x00, 0x00, 0x19, 0x80, 0x90, 0x95, 0x01, 0x0e, 0x83, 0x1a, 0x07, 0x87, 0x90, 0x9c, 0x9e, 0x3c, 0x00, 0x35, 0x7e, 0x34, 0x00, 0x73, 0x8b, 0x92, 0x1e, 0x01, 0x7f, 0x0b, 0x13, 0x86, 0x91, 0x9e, 0x9e, 0x2b, 0x00, 0x42, 0x80, 0x0b, 0x18, 0x88, 0x92, 0x9e, 0x9e, 0x2e, 0x00, 0x4d, 0x35, 0x00, 0x15, 0x20, 0x21, 0x21, 0x22, 0x2e, 0x84, 0x01, 0x21, 0x82, 0x8a, 0x47, 0x00, 0x63, 0x87, 0x8e, 0x03, 0x21, 0x4e, 0x00, 0x0e, 0x1e, 0x21, 0x21, 0x22, 0x22, 0x69, 0x00, 0x31, 0x84, 0x8e, 0x64, 0x00, 0x46, 0x6d, 0x07, 0x00, 0x34, 0x89, 0x9f, 0xb6, 0xc5, 0xcc, 0xcf, 0xb0, 0xd0, 0x04, 0xce, 0xc8, 0xbb, 0xa5, 0xb5, 0x83, 0xbc, 0x06, 0xbb, 0x9d, 0x9a, 0xb4, 0xc5, 0xcc, 0xcf, 0x82, 0xd0, 0x7f, 0xcf, 0xcc, 0xc2, 0x46, 0x00, 0x6a, 0x8b, 0x96, 0x79, 0x15, 0x00, 0x54, 0x37, 0x00, 0x3c, 0x86, 0x90, 0x3e, 0x00, 0x3f, 0x88, 0x47, 0x00, 0x38, 0x89, 0x91, 0x45, 0x00, 0x35, 0x7d, 0x01, 0x21, 0x8d, 0xa3, 0xba, 0xc7, 0xcc, 0xc9, 0xa2, 0x00, 0x24, 0x90, 0x9b, 0xa5, 0x60, 0x00, 0x00, 0x52, 0x87, 0x9c, 0xa4, 0x12, 0x01, 0x7d, 0x28, 0x00, 0x60, 0x90, 0x9e, 0x98, 0x08, 0x00, 0x46, 0x80, 0x23, 0x01, 0x86, 0x96, 0x9e, 0x13, 0x0d, 0x81, 0x19, 0x00, 0x6d, 0x92, 0x9f, 0x8d, 0x01, 0x00, 0x52, 0x82, 0x1e, 0x01, 0x76, 0x93, 0xa0, 0x92, 0x03, 0x00, 0x5c, 0x46, 0x00, 0x25, 0x70, 0x76, 0x60, 0x79, 0x85, 0x77, 0x00, 0x32, 0x8a, 0x94, 0x3f, 0x00, 0x7a, 0x93, 0x8d, 0x00, 0x2f, 0x5f, 0x00, 0x11, 0x6d, 0x74, 0x67, 0x70, 0x81, 0x60, 0x00, 0x42, 0x8c, 0x9a, 0x5d, 0x00, 0x52, 0x5d, 0x06, 0x00, 0x46, 0x92, 0xa9, 0xbe, 0xca, 0xce, 0xb1, 0xd0, 0x05, 0xcf, 0xcc, 0xc4, 0xb3, 0xa9, 0xba, 0x83, 0xbc, 0x05, 0xb5, 0x8c, 0xa6, 0xbd, 0xc9, 0xce, 0x82, 0xd0, 0x7f, 0xcf, 0xcc, 0xc1, 0x2f, 0x00, 0x11, 0x15, 0x08, 0x00, 0x00, 0x29, 0x81, 0x6d, 0x03, 0x00, 0x19, 0x11, 0x00, 0x0d, 0x7f, 0x8f, 0x83, 0x06, 0x00, 0x17, 0x14, 0x00, 0x09, 0x76, 0x73, 0x00, 0x35, 0x93, 0xa9, 0xbf, 0xca, 0xcc, 0xc6, 0x59, 0x00, 0x5a, 0x96, 0xa5, 0xb0, 0x92, 0x00, 0x17, 0x80, 0x94, 0xa9, 0xaf, 0x29, 0x00, 0x6f, 0x5c, 0x00, 0x04, 0x30, 0x3c, 0x08, 0x00, 0x00, 0x55, 0x83, 0x13, 0x0e, 0x8f, 0x9e, 0xa5, 0x03, 0x21, 0x86, 0x4f, 0x00, 0x07, 0x37, 0x35, 0x04, 0x00, 0x00, 0x63, 0x88, 0x5f, 0x00, 0x0e, 0x41, 0x3f, 0x0a, 0x00, 0x00, 0x6c, 0x73, 0x0a, 0x00, 0x12, 0x1e, 0x00, 0x14, 0x89, 0x6e, 0x00, 0x46, 0x92, 0x9c, 0x2b, 0x03, 0x8f, 0x9b, 0x7e, 0x00, 0x44, 0x80, 0x19, 0x00, 0x0d, 0x23, 0x01, 0x07, 0x77, 0x56, 0x00, 0x57, 0x94, 0xa2, 0x4e, 0x00, 0x67, 0x4f, 0x06, 0x00, 0x59, 0x98, 0xaf, 0xc2, 0xcc, 0xcf, 0xb2, 0xd0, 0x04, 0xce, 0xca, 0xbf, 0xa8, 0xb1, 0x84, 0xbc, 0x05, 0xb2, 0x95, 0xb2, 0xc4, 0xcc, 0xcf, 0x81, 0xd0, 0x03, 0xcf, 0xcc, 0xc1, 0x1a, 0x80, 0x00, 0x7f, 0x07, 0x1a, 0x4c, 0x86, 0x8f, 0x95, 0x69, 0x11, 0x00, 0x01, 0x21, 0x76, 0x91, 0x9e, 0xa4, 0x76, 0x14, 0x00, 0x01, 0x1e, 0x72, 0x8b, 0x6d, 0x00, 0x49, 0x9c, 0xb0, 0xc2, 0xcb, 0xcc, 0xc3, 0x15, 0x07, 0x90, 0x9f, 0xb0, 0xbb, 0xb4, 0x11, 0x5f, 0x93, 0xa4, 0xb5, 0xb8, 0x41, 0x00, 0x65, 0x8e, 0x54, 0x09, 0x00, 0x00, 0x21, 0x29, 0x00, 0x6a, 0x8c, 0x03, 0x22, 0x98, 0xa5, 0x97, 0x00, 0x39, 0x91, 0x92, 0x4b, 0x06, 0x00, 0x01, 0x29, 0x21, 0x00, 0x7a, 0x93, 0x9b, 0x5a, 0x0a, 0x00, 0x00, 0x22, 0x0d, 0x04, 0x7a, 0x88, 0x73, 0x1b, 0x01, 0x01, 0x17, 0x6d, 0x96, 0x62, 0x00, 0x5d, 0x9b, 0xa4, 0x17, 0x13, 0x9a, 0xa3, 0x6c, 0x00, 0x5c, 0x8f, 0x7e, 0x28, 0x01, 0x00, 0x11, 0x58, 0x91, 0x4a, 0x00, 0x71, 0x9e, 0xab, 0x3a, 0x00, 0x82, 0x44, 0x00, 0x70, 0xa1, 0xb5, 0xc5, 0xcd, 0xcf, 0xb2, 0xd0, 0x05, 0xcf, 0xcd, 0xc6, 0xb6, 0xa4, 0xb8, 0x83, 0xbc, 0x05, 0xb7, 0x8b, 0xa5, 0xbe, 0xca, 0xcf, 0x81, 0xd0, 0x76, 0xcf, 0xcc, 0xc4, 0xb4, 0x9e, 0x8f, 0x8a, 0x8a, 0x8e, 0x93, 0x9b, 0xa5, 0xab, 0xa9, 0x9e, 0x86, 0x87, 0x8f, 0x97, 0xa3, 0xb1, 0xb5, 0xae, 0xa0, 0x87, 0x88, 0x8e, 0x95, 0x9e, 0xa5, 0xa5, 0xa4, 0xab, 0xb9, 0xc6, 0xcc, 0xcc, 0xc6, 0xba, 0xab, 0xa5, 0xad, 0xbb, 0xc2, 0xbf, 0xb2, 0xa7, 0xa9, 0xb4, 0xc0, 0xc1, 0xb5, 0xa7, 0x9f, 0xa0, 0x9f, 0x99, 0x81, 0x87, 0x8f, 0x8e, 0x8e, 0x94, 0x9e, 0xa3, 0xa2, 0xa6, 0xb1, 0xb6, 0xb0, 0xa6, 0xa4, 0xa5, 0xa3, 0x99, 0x7f, 0x8a, 0x8f, 0x8e, 0x8e, 0x98, 0xa4, 0xa9, 0xa1, 0x93, 0x79, 0x7a, 0x6d, 0x00, 0x20, 0x81, 0x95, 0xa0, 0x9b, 0x8a, 0x85, 0x8f, 0x98, 0xa4, 0xab, 0xa8, 0xa5, 0xab, 0xb1, 0xaf, 0xa8, 0xa7, 0xae, 0xb3, 0xac, 0xa4, 0xa3, 0xa3, 0x9e, 0x8e, 0x82, 0x8e, 0x96, 0x9e, 0x80, 0xa4, 0x0b, 0xab, 0xb4, 0xb3, 0xa9, 0x9f, 0x9e, 0x9e, 0xa3, 0xae, 0xbd, 0xc8, 0xce, 0xb4, 0xd0, 0x04, 0xcf, 0xcb, 0xc1, 0xac, 0xaf, 0x81, 0xbc, 0x80, 0xbb, 0x04, 0x92, 0x9b, 0xb8, 0xc8, 0xce, 0x82, 0xd0, 0x4a, 0xce, 0xc8, 0xbf, 0xb3, 0xa8, 0xa3, 0xa3, 0xa5, 0xab, 0xb3, 0xbb, 0xbf, 0xbc, 0xb4, 0xab, 0xa6, 0xa7, 0xad, 0xb7, 0xc0, 0xc3, 0xbf, 0xb5, 0xab, 0xa6, 0xa7, 0xac, 0xb4, 0xb9, 0xb8, 0xb7, 0xbb, 0xc2, 0xca, 0xce, 0xcd, 0xca, 0xc2, 0xba, 0xb7, 0xbd, 0xc5, 0xc9, 0xc6, 0xc0, 0xbb, 0xbc, 0xc2, 0xc8, 0xc7, 0xc1, 0xb9, 0xb4, 0xb5, 0xb4, 0xb0, 0xa9, 0xa6, 0xa4, 0xa5, 0xa8, 0xad, 0xb3, 0xb5, 0xb5, 0xb8, 0xbe, 0xc1, 0xbd, 0xb8, 0xb7, 0xb9, 0xb7, 0xb1, 0xa9, 0x80, 0xa5, 0x36, 0xa9, 0xae, 0xb4, 0x52, 0x15, 0x49, 0x7a, 0x6a, 0x21, 0x00, 0x4d, 0x8d, 0xa4, 0xb2, 0xb3, 0xab, 0xa7, 0xa8, 0xad, 0xb4, 0xba, 0xb9, 0xb7, 0xbb, 0xbe, 0xbd, 0xb8, 0xb8, 0xbc, 0xbf, 0xbb, 0xb7, 0xb7, 0xb8, 0xb4, 0xac, 0xa7, 0xa7, 0xab, 0xb3, 0xb6, 0xb6, 0xb7, 0xbb, 0xc0, 0xbf, 0xb9, 0xb4, 0xb3, 0xb3, 0xb5, 0xbd, 0xc5, 0xcc, 0xcf, 0xb4, 0xd0, 0x05, 0xcf, 0xcd, 0xc7, 0xba, 0xa4, 0xba, 0x82, 0xbc, 0x05, 0xba, 0x87, 0x98, 0xb5, 0xc6, 0xce, 0x82, 0xd0, 0x1b, 0xcf, 0xcc, 0xc8, 0xc2, 0xbf, 0xbc, 0xbc, 0xbd, 0xc0, 0xc3, 0xc7, 0xca, 0xc8, 0xc4, 0xc0, 0xbd, 0xbe, 0xc1, 0xc6, 0xca, 0xcc, 0xc9, 0xc5, 0xc0, 0xbd, 0xbe, 0xc1, 0xc4, 0x81, 0xc6, 0x24, 0xcb, 0xcd, 0xcf, 0xcf, 0xcd, 0xc9, 0xc6, 0xc5, 0xc8, 0xcc, 0xcd, 0xcc, 0xca, 0xc7, 0xc8, 0xcb, 0xcd, 0xcc, 0xca, 0xc6, 0xc4, 0xc5, 0xc5, 0xc2, 0xbf, 0xbc, 0xbc, 0xbd, 0xbf, 0xc1, 0xc4, 0xc5, 0xc4, 0xc6, 0xc8, 0xc9, 0xc7, 0x81, 0xc6, 0x09, 0xc2, 0xbf, 0xbc, 0xbc, 0xbd, 0xbf, 0xc1, 0xc0, 0x95, 0x07, 0x81, 0x00, 0x0a, 0x2b, 0x88, 0x9b, 0xb1, 0xc0, 0xc2, 0xc0, 0xbe, 0xbe, 0xc1, 0xc4, 0x81, 0xc6, 0x05, 0xc8, 0xc7, 0xc6, 0xc6, 0xc7, 0xc8, 0x81, 0xc6, 0x05, 0xc5, 0xc1, 0xbe, 0xbe, 0xc0, 0xc3, 0x80, 0xc5, 0x0b, 0xc7, 0xc9, 0xc8, 0xc6, 0xc4, 0xc3, 0xc3, 0xc5, 0xc7, 0xcc, 0xce, 0xcf, 0xb5, 0xd0, 0x05, 0xcf, 0xcc, 0xc2, 0xb1, 0xae, 0xb8, 0x81, 0xbc, 0x05, 0xad, 0x7b, 0x9b, 0xb7, 0xc7, 0xce, 0x83, 0xd0, 0x03, 0xcf, 0xcd, 0xcc, 0xcb, 0x80, 0xca, 0x20, 0xcb, 0xcc, 0xcd, 0xce, 0xce, 0xcc, 0xcb, 0xca, 0xca, 0xcc, 0xcd, 0xce, 0xcf, 0xce, 0xcc, 0xcb, 0xca, 0xca, 0xcc, 0xcc, 0xcd, 0xcd, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd0, 0xcf, 0xce, 0xcd, 0xcc, 0xcd, 0x80, 0xcf, 0x07, 0xce, 0xcd, 0xcd, 0xce, 0xcf, 0xcf, 0xce, 0xcd, 0x81, 0xcc, 0x04, 0xcb, 0xca, 0xc9, 0xca, 0xcb, 0x82, 0xcc, 0x03, 0xcd, 0xce, 0xcd, 0xcc, 0x80, 0xcd, 0x1b, 0xcc, 0xca, 0xc9, 0xc9, 0xca, 0xcb, 0xca, 0xc7, 0xbe, 0x96, 0x58, 0x2e, 0x37, 0x5c, 0x8c, 0x98, 0xab, 0xbd, 0xc7, 0xcb, 0xcb, 0xca, 0xca, 0xcb, 0xcc, 0xcd, 0xcd, 0xcc, 0x80, 0xcd, 0x01, 0xcc, 0xcc, 0x80, 0xcd, 0x07, 0xcc, 0xcd, 0xcd, 0xcc, 0xcc, 0xca, 0xca, 0xcb, 0x81, 0xcc, 0x03, 0xcd, 0xce, 0xcd, 0xcd, 0x81, 0xcc, 0x02, 0xcd, 0xcf, 0xcf, 0xb7, 0xd0, 0x0e, 0xce, 0xc9, 0xbd, 0xa7, 0xab, 0xb5, 0xbc, 0xba, 0xad, 0x7d, 0x87, 0xa5, 0xbd, 0xca, 0xcf, 0x84, 0xd0, 0x85, 0xcf, 0x80, 0xd0, 0x83, 0xcf, 0x80, 0xd0, 0x87, 0xcf, 0x83, 0xd0, 0x80, 0xcf, 0x81, 0xd0, 0x00, 0xcf, 0x82, 0xd0, 0x83, 0xcf, 0x01, 0xce, 0xce, 0x85, 0xcf, 0x00, 0xd0, 0x84, 0xcf, 0x11, 0xce, 0xce, 0xcf, 0xcf, 0xce, 0xcb, 0xc4, 0xb8, 0xa9, 0x9e, 0x98, 0x99, 0xa0, 0xac, 0xbb, 0xc6, 0xcc, 0xce, 0x9a, 0xcf, 0x01, 0xd0, 0xd0, 0x83, 0xcf, 0xb9, 0xd0, 0x0e, 0xcf, 0xcc, 0xc6, 0xb8, 0xa4, 0x94, 0x95, 0x88, 0x7b, 0x87, 0x9e, 0xb4, 0xc4, 0xcc, 0xcf, 0xff, 0xd0, 0xbf, 0xd0, 0x0c, 0xcf, 0xcc, 0xc4, 0xb9, 0xab, 0x9e, 0x98, 0x9b, 0xa5, 0xb4, 0xc1, 0xca, 0xce, 0xff, 0xd0, 0x93, 0xd0, }; static EG_EMBEDDED_IMAGE egemb_refind_banner = { 210, 64, EG_EIPIXELMODE_COLOR, EG_EICOMPMODE_RLE, egemb_refind_banner_data, 22887 }; refind-0.11.4/refind/0000755000175000017500000000000013372355001014556 5ustar rodsmithrodsmithrefind-0.11.4/refind/config.h0000664000175000017500000000720113137745310016203 0ustar rodsmithrodsmith/* * refit/config.h * General header file * * Copyright (c) 2006-2009 Christoph Pfisterer * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * * Neither the name of Christoph Pfisterer nor the names of the * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Modifications copyright (c) 2012-2015 Roderick W. Smith * * Modifications distributed under the terms of the GNU General Public * License (GPL) version 3 (GPLv3), a copy of which must be distributed * with this source code or binaries made from it. * */ #ifndef __CONFIG_H_ #define __CONFIG_H_ #ifdef __MAKEWITH_GNUEFI #include "efi.h" #else #include "../include/tiano_includes.h" #endif #include "global.h" // // config module // typedef struct { UINT8 *Buffer; UINTN BufferSize; UINTN Encoding; CHAR8 *Current8Ptr; CHAR8 *End8Ptr; CHAR16 *Current16Ptr; CHAR16 *End16Ptr; } REFIT_FILE; #define CONFIG_FILE_NAME L"refind.conf" // Note: Below is combined with MOK_NAMES and FWUPDATE_NAMES to make default #if defined (EFIX64) #define DONT_SCAN_FILES L"shim.efi,shim-fedora.efi,shim-centos.efi,shimx64.efi,PreLoader.efi,TextMode.efi,ebounce.efi,GraphicsConsole.efi,bootmgr.efi,fbx64.efi" #elif defined(EFI32) #define DONT_SCAN_FILES L"shim.efi,shim-fedora.efi,shim-centos.efi,shimx64.efi,PreLoader.efi,TextMode.efi,ebounce.efi,GraphicsConsole.efi,bootmgr.efi,fbia32.efi" #elif defined(EFIAARCH64) #define DONT_SCAN_FILES L"shim.efi,shim-fedora.efi,shim-centos.efi,shimx64.efi,PreLoader.efi,TextMode.efi,ebounce.efi,GraphicsConsole.efi,bootmgr.efi,fbaa64.efi" #else #define DONT_SCAN_FILES L"shim.efi,shim-fedora.efi,shim-centos.efi,shimx64.efi,PreLoader.efi,TextMode.efi,ebounce.efi,GraphicsConsole.efi,bootmgr.efi" #endif #define DONT_SCAN_VOLUMES L"LRS_ESP" #define ALSO_SCAN_DIRS L"boot,@/boot" EFI_STATUS ReadFile(IN EFI_FILE_HANDLE BaseDir, CHAR16 *FileName, REFIT_FILE *File, UINTN *size); VOID ReadConfig(CHAR16 *FileName); VOID ScanUserConfigured(CHAR16 *FileName); UINTN ReadTokenLine(IN REFIT_FILE *File, OUT CHAR16 ***TokenList); VOID FreeTokenLine(IN OUT CHAR16 ***TokenList, IN OUT UINTN *TokenCount); REFIT_FILE * ReadLinuxOptionsFile(IN CHAR16 *LoaderPath, IN REFIT_VOLUME *Volume); CHAR16 * GetFirstOptionsFromFile(IN CHAR16 *LoaderPath, IN REFIT_VOLUME *Volume); #endif /* EOF */ refind-0.11.4/refind/apple.h0000664000175000017500000000451412626644770016055 0ustar rodsmithrodsmith/* * refind/apple.h * * Copyright (c) 2015 Roderick W. Smith * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #ifndef __APPLE_H_ #define __APPLE_H_ // The constants related to Apple's System Integrity Protection (SIP).... #define CSR_GUID { 0x7c436110, 0xab2a, 0x4bbb, { 0xa8, 0x80, 0xfe, 0x41, 0x99, 0x5c, 0x9f, 0x82 } }; // These codes are returned in the first byte of the csr-active-config variable #define CSR_ALLOW_UNTRUSTED_KEXTS 0x01 #define CSR_ALLOW_UNRESTRICTED_FS 0x02 #define CSR_ALLOW_TASK_FOR_PID 0x04 #define CSR_ALLOW_KERNEL_DEBUGGER 0x08 #define CSR_ALLOW_APPLE_INTERNAL 0x10 #define CSR_ALLOW_UNRESTRICTED_DTRACE 0x20 #define CSR_ALLOW_UNRESTRICTED_NVRAM 0x40 #define CSR_END_OF_LIST 0xFFFFFFFF // Some summaries.... #define SIP_ENABLED CSR_ALLOW_APPLE_INTERNAL #define SIP_DISABLED (CSR_ALLOW_UNRESTRICTED_NVRAM | \ CSR_ALLOW_UNRESTRICTED_DTRACE | \ CSR_ALLOW_APPLE_INTERNAL | \ CSR_ALLOW_TASK_FOR_PID | \ CSR_ALLOW_UNRESTRICTED_FS | \ CSR_ALLOW_UNTRUSTED_KEXTS) #define CSR_MAX_LEGAL_VALUE (CSR_ALLOW_UNTRUSTED_KEXTS | \ CSR_ALLOW_UNRESTRICTED_FS | \ CSR_ALLOW_TASK_FOR_PID | \ CSR_ALLOW_KERNEL_DEBUGGER | \ CSR_ALLOW_APPLE_INTERNAL | \ CSR_ALLOW_UNRESTRICTED_DTRACE | \ CSR_ALLOW_UNRESTRICTED_NVRAM) extern CHAR16 gCsrStatus[256]; EFI_STATUS GetCsrStatus(UINT32 *CsrValue); VOID RecordgCsrStatus(UINT32 CsrStatus, BOOLEAN DisplayMessage); VOID RotateCsrValue(VOID); EFI_STATUS SetAppleOSInfo(); #endifrefind-0.11.4/refind/screen.h0000664000175000017500000000774713137653502016235 0ustar rodsmithrodsmith/* * refit/screen.h * Screen management header file * * Copyright (c) 2006-2009 Christoph Pfisterer * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * * Neither the name of Christoph Pfisterer nor the names of the * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef __SCREEN_H_ #define __SCREEN_H_ #ifdef __MAKEWITH_GNUEFI #include "efi.h" #include "efilib.h" #else #include "../include/tiano_includes.h" #endif #include "libeg.h" // // screen module // #define DONT_CHANGE_TEXT_MODE 1024 /* textmode # that's a code to not change the text mode */ #define ATTR_BASIC (EFI_LIGHTGRAY | EFI_BACKGROUND_BLACK) #define ATTR_ERROR (EFI_YELLOW | EFI_BACKGROUND_BLACK) #define ATTR_BANNER (EFI_WHITE | EFI_BACKGROUND_BLUE) #define ATTR_CHOICE_BASIC ATTR_BASIC #define ATTR_CHOICE_CURRENT (EFI_WHITE | EFI_BACKGROUND_GREEN) #define ATTR_SCROLLARROW (EFI_LIGHTGREEN | EFI_BACKGROUND_BLACK) //#define LAYOUT_TEXT_WIDTH (512) //#define LAYOUT_TEXT_WIDTH (425) #define LAYOUT_BANNER_YGAP 32 //#define FONT_CELL_WIDTH (7) //#define FONT_CELL_HEIGHT (12) // Codes for text position, used by egDisplayMessage() and PrintUglyText() #define CENTER 0 #define BOTTOM 1 #define TOP 2 #define NEXTLINE 3 extern UINTN ConWidth; extern UINTN ConHeight; extern CHAR16 *BlankLine; extern UINTN UGAWidth; extern UINTN UGAHeight; extern BOOLEAN AllowGraphicsMode; extern EG_PIXEL StdBackgroundPixel; extern EG_PIXEL MenuBackgroundPixel; VOID InitScreen(VOID); VOID SetupScreen(VOID); VOID BeginTextScreen(IN CHAR16 *Title); VOID FinishTextScreen(IN BOOLEAN WaitAlways); VOID BeginExternalScreen(IN BOOLEAN UseGraphicsMode, IN CHAR16 *Title); VOID FinishExternalScreen(VOID); VOID TerminateScreen(VOID); VOID DrawScreenHeader(IN CHAR16 *Title); #if REFIT_DEBUG > 0 VOID DebugPause(VOID); #else #define DebugPause() #endif VOID EndlessIdleLoop(VOID); BOOLEAN ReadAllKeyStrokes(VOID); VOID PrintUglyText(IN CHAR16 *Text, UINTN PositionCode); VOID PauseForKey(VOID); VOID PauseSeconds(UINTN Seconds); BOOLEAN CheckFatalError(IN EFI_STATUS Status, IN CHAR16 *where); BOOLEAN CheckError(IN EFI_STATUS Status, IN CHAR16 *where); VOID SwitchToText(IN BOOLEAN CursorEnabled); VOID SwitchToGraphics(VOID); VOID SwitchToGraphicsAndClear(VOID); VOID BltClearScreen(IN BOOLEAN ShowBanner); VOID BltImage(IN EG_IMAGE *Image, IN UINTN XPos, IN UINTN YPos); VOID BltImageAlpha(IN EG_IMAGE *Image, IN UINTN XPos, IN UINTN YPos, IN EG_PIXEL *BackgroundPixel); //VOID BltImageComposite(IN EG_IMAGE *BaseImage, IN EG_IMAGE *TopImage, IN UINTN XPos, IN UINTN YPos); VOID BltImageCompositeBadge(IN EG_IMAGE *BaseImage, IN EG_IMAGE *TopImage, IN EG_IMAGE *BadgeImage, IN UINTN XPos, IN UINTN YPos); #endif refind-0.11.4/refind/screen.c0000664000175000017500000004523213143417323016213 0ustar rodsmithrodsmith/* * refind/screen.c * Screen handling functions * * Copyright (c) 2006 Christoph Pfisterer * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * * Neither the name of Christoph Pfisterer nor the names of the * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Modifications copyright (c) 2012-2015 Roderick W. Smith * * Modifications distributed under the terms of the GNU General Public * License (GPL) version 3 (GPLv3), or (at your option) any later version. * */ /* * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "global.h" #include "screen.h" #include "config.h" #include "libegint.h" #include "lib.h" #include "menu.h" #include "mystrings.h" #include "../include/refit_call_wrapper.h" #include "../include/egemb_refind_banner.h" // Console defines and variables UINTN ConWidth; UINTN ConHeight; CHAR16 *BlankLine = NULL; // UGA defines and variables UINTN UGAWidth; UINTN UGAHeight; BOOLEAN AllowGraphicsMode; BOOLEAN HaveResized = FALSE; EG_PIXEL StdBackgroundPixel = { 0xbf, 0xbf, 0xbf, 0 }; EG_PIXEL MenuBackgroundPixel = { 0xbf, 0xbf, 0xbf, 0 }; EG_PIXEL DarkBackgroundPixel = { 0x0, 0x0, 0x0, 0 }; static BOOLEAN GraphicsScreenDirty; // general defines and variables static BOOLEAN haveError = FALSE; static VOID PrepareBlankLine(VOID) { UINTN i; MyFreePool(BlankLine); // make a buffer for a whole text line BlankLine = AllocatePool((ConWidth + 1) * sizeof(CHAR16)); for (i = 0; i < ConWidth; i++) BlankLine[i] = ' '; BlankLine[i] = 0; } // // Screen initialization and switching // VOID InitScreen(VOID) { // initialize libeg egInitScreen(); if (egHasGraphicsMode()) { egGetScreenSize(&UGAWidth, &UGAHeight); AllowGraphicsMode = TRUE; } else { AllowGraphicsMode = FALSE; egSetTextMode(GlobalConfig.RequestedTextMode); egSetGraphicsModeEnabled(FALSE); // just to be sure we are in text mode } GraphicsScreenDirty = TRUE; // disable cursor refit_call2_wrapper(ST->ConOut->EnableCursor, ST->ConOut, FALSE); // get size of text console if (refit_call4_wrapper(ST->ConOut->QueryMode, ST->ConOut, ST->ConOut->Mode->Mode, &ConWidth, &ConHeight) != EFI_SUCCESS) { // use default values on error ConWidth = 80; ConHeight = 25; } PrepareBlankLine(); // show the banner if in text mode if (GlobalConfig.TextOnly && (GlobalConfig.ScreensaverTime != -1)) DrawScreenHeader(L"Initializing..."); } // Set the screen resolution and mode (text vs. graphics). VOID SetupScreen(VOID) { UINTN NewWidth, NewHeight; // Convert mode number to horizontal & vertical resolution values if ((GlobalConfig.RequestedScreenWidth > 0) && (GlobalConfig.RequestedScreenHeight == 0)) egGetResFromMode(&(GlobalConfig.RequestedScreenWidth), &(GlobalConfig.RequestedScreenHeight)); // Set the believed-to-be current resolution to the LOWER of the current // believed-to-be resolution and the requested resolution. This is done to // enable setting a lower-than-default resolution. if ((GlobalConfig.RequestedScreenWidth > 0) && (GlobalConfig.RequestedScreenHeight > 0)) { UGAWidth = (UGAWidth < GlobalConfig.RequestedScreenWidth) ? UGAWidth : GlobalConfig.RequestedScreenWidth; UGAHeight = (UGAHeight < GlobalConfig.RequestedScreenHeight) ? UGAHeight : GlobalConfig.RequestedScreenHeight; } // Set text mode. If this requires increasing the size of the graphics mode, do so. if (egSetTextMode(GlobalConfig.RequestedTextMode)) { egGetScreenSize(&NewWidth, &NewHeight); if ((NewWidth > UGAWidth) || (NewHeight > UGAHeight)) { UGAWidth = NewWidth; UGAHeight = NewHeight; } if ((UGAWidth > GlobalConfig.RequestedScreenWidth) || (UGAHeight > GlobalConfig.RequestedScreenHeight)) { // Requested text mode forces us to use a bigger graphics mode GlobalConfig.RequestedScreenWidth = UGAWidth; GlobalConfig.RequestedScreenHeight = UGAHeight; } // if } if (GlobalConfig.RequestedScreenWidth > 0) { egSetScreenSize(&(GlobalConfig.RequestedScreenWidth), &(GlobalConfig.RequestedScreenHeight)); egGetScreenSize(&UGAWidth, &UGAHeight); } // if user requested a particular screen resolution if (GlobalConfig.TextOnly) { // switch to text mode if requested AllowGraphicsMode = FALSE; SwitchToText(FALSE); } else if (AllowGraphicsMode) { // clear screen and show banner // (now we know we'll stay in graphics mode) if ((UGAWidth >= HIDPI_MIN) && !HaveResized) { GlobalConfig.IconSizes[ICON_SIZE_BADGE] *= 2; GlobalConfig.IconSizes[ICON_SIZE_SMALL] *= 2; GlobalConfig.IconSizes[ICON_SIZE_BIG] *= 2; GlobalConfig.IconSizes[ICON_SIZE_MOUSE] *= 2; HaveResized = TRUE; } // if SwitchToGraphics(); if (GlobalConfig.ScreensaverTime != -1) { BltClearScreen(TRUE); } else { // start with screen blanked GraphicsScreenDirty = TRUE; } } } // VOID SetupScreen() VOID SwitchToText(IN BOOLEAN CursorEnabled) { egSetGraphicsModeEnabled(FALSE); refit_call2_wrapper(ST->ConOut->EnableCursor, ST->ConOut, CursorEnabled); // get size of text console if (refit_call4_wrapper(ST->ConOut->QueryMode, ST->ConOut, ST->ConOut->Mode->Mode, &ConWidth, &ConHeight) != EFI_SUCCESS) { // use default values on error ConWidth = 80; ConHeight = 25; } PrepareBlankLine(); } VOID SwitchToGraphics(VOID) { if (AllowGraphicsMode && !egIsGraphicsModeEnabled()) { egSetGraphicsModeEnabled(TRUE); GraphicsScreenDirty = TRUE; } } // // Screen control for running tools // VOID BeginTextScreen(IN CHAR16 *Title) { DrawScreenHeader(Title); SwitchToText(FALSE); // reset error flag haveError = FALSE; } VOID FinishTextScreen(IN BOOLEAN WaitAlways) { if (haveError || WaitAlways) { PauseForKey(); SwitchToText(FALSE); } // reset error flag haveError = FALSE; } VOID BeginExternalScreen(IN BOOLEAN UseGraphicsMode, IN CHAR16 *Title) { if (!AllowGraphicsMode) UseGraphicsMode = FALSE; if (UseGraphicsMode) { SwitchToGraphics(); BltClearScreen(FALSE); } else { egClearScreen(&DarkBackgroundPixel); DrawScreenHeader(Title); SwitchToText(TRUE); } // reset error flag haveError = FALSE; } VOID FinishExternalScreen(VOID) { // make sure we clean up later GraphicsScreenDirty = TRUE; if (haveError) { SwitchToText(FALSE); PauseForKey(); } // Reset the screen resolution, in case external program changed it.... SetupScreen(); // reset error flag haveError = FALSE; } VOID TerminateScreen(VOID) { // clear text screen refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BASIC); refit_call1_wrapper(ST->ConOut->ClearScreen, ST->ConOut); // enable cursor refit_call2_wrapper(ST->ConOut->EnableCursor, ST->ConOut, TRUE); } VOID DrawScreenHeader(IN CHAR16 *Title) { UINTN y; // clear to black background egClearScreen(&DarkBackgroundPixel); // first clear in graphics mode refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BASIC); refit_call1_wrapper(ST->ConOut->ClearScreen, ST->ConOut); // then clear in text mode // paint header background refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BANNER); for (y = 0; y < 3; y++) { refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 0, y); Print(BlankLine); } // print header text refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 3, 1); Print(L"rEFInd - %s", Title); // reposition cursor refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BASIC); refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 0, 4); } // // Keyboard input // BOOLEAN ReadAllKeyStrokes(VOID) { BOOLEAN GotKeyStrokes; EFI_STATUS Status; EFI_INPUT_KEY key; GotKeyStrokes = FALSE; for (;;) { Status = refit_call2_wrapper(ST->ConIn->ReadKeyStroke, ST->ConIn, &key); if (Status == EFI_SUCCESS) { GotKeyStrokes = TRUE; continue; } break; } return GotKeyStrokes; } // Displays *text without regard to appearances. Used mainly for debugging // and rare error messages. // Position code is used only in graphics mode. // TODO: Improve to handle multi-line text. VOID PrintUglyText(IN CHAR16 *Text, IN UINTN PositionCode) { EG_PIXEL BGColor = COLOR_RED; if (Text) { if (AllowGraphicsMode && MyStriCmp(L"Apple", ST->FirmwareVendor) && egIsGraphicsModeEnabled()) { egDisplayMessage(Text, &BGColor, PositionCode); GraphicsScreenDirty = TRUE; } else { // non-Mac or in text mode; a Print() statement will work Print(Text); Print(L"\n"); } // if/else } // if } // VOID PrintUglyText() VOID PauseForKey(VOID) { UINTN index; Print(L"\n"); PrintUglyText(L"* Hit any key to continue *", BOTTOM); if (ReadAllKeyStrokes()) { // remove buffered key strokes refit_call1_wrapper(BS->Stall, 5000000); // 5 seconds delay ReadAllKeyStrokes(); // empty the buffer again } refit_call3_wrapper(BS->WaitForEvent, 1, &ST->ConIn->WaitForKey, &index); ReadAllKeyStrokes(); // empty the buffer to protect the menu } // Pause a specified number of seconds VOID PauseSeconds(UINTN Seconds) { refit_call1_wrapper(BS->Stall, 1000000 * Seconds); } // VOID PauseSeconds() #if REFIT_DEBUG > 0 VOID DebugPause(VOID) { // show console and wait for key SwitchToText(FALSE); PauseForKey(); // reset error flag haveError = FALSE; } #endif VOID EndlessIdleLoop(VOID) { UINTN index; for (;;) { ReadAllKeyStrokes(); refit_call3_wrapper(BS->WaitForEvent, 1, &ST->ConIn->WaitForKey, &index); } } // // Error handling // BOOLEAN CheckFatalError(IN EFI_STATUS Status, IN CHAR16 *where) { CHAR16 *Temp = NULL; if (!EFI_ERROR(Status)) return FALSE; #ifdef __MAKEWITH_GNUEFI CHAR16 ErrorName[64]; StatusToString(ErrorName, Status); Temp = PoolPrint(L"Fatal Error: %s %s", ErrorName, where); #else Temp = PoolPrint(L"Fatal Error: %s %s", Status, where); #endif refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_ERROR); PrintUglyText(Temp, NEXTLINE); refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BASIC); haveError = TRUE; MyFreePool(Temp); return TRUE; } // BOOLEAN CheckFatalError() BOOLEAN CheckError(IN EFI_STATUS Status, IN CHAR16 *where) { CHAR16 *Temp = NULL; if (!EFI_ERROR(Status)) return FALSE; #ifdef __MAKEWITH_GNUEFI CHAR16 ErrorName[64]; StatusToString(ErrorName, Status); Temp = PoolPrint(L"Error: %s %s", ErrorName, where); #else Temp = PoolPrint(L"Error: %r %s", Status, where); #endif refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_ERROR); PrintUglyText(Temp, NEXTLINE); refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BASIC); haveError = TRUE; MyFreePool(Temp); return TRUE; } // BOOLEAN CheckError() // // Graphics functions // VOID SwitchToGraphicsAndClear(VOID) { SwitchToGraphics(); if (GraphicsScreenDirty) BltClearScreen(TRUE); } VOID BltClearScreen(BOOLEAN ShowBanner) { static EG_IMAGE *Banner = NULL; EG_IMAGE *NewBanner = NULL; INTN BannerPosX, BannerPosY; EG_PIXEL Black = { 0x0, 0x0, 0x0, 0 }; if (ShowBanner && !(GlobalConfig.HideUIFlags & HIDEUI_FLAG_BANNER)) { // load banner on first call if (Banner == NULL) { if (GlobalConfig.BannerFileName) Banner = egLoadImage(SelfDir, GlobalConfig.BannerFileName, FALSE); if (Banner == NULL) Banner = egPrepareEmbeddedImage(&egemb_refind_banner, FALSE); } if (Banner) { if (GlobalConfig.BannerScale == BANNER_FILLSCREEN) { if ((Banner->Height != UGAHeight) || (Banner->Width != UGAWidth)) { NewBanner = egScaleImage(Banner, UGAWidth, UGAHeight); } // if } else if ((Banner->Width > UGAWidth) || (Banner->Height > UGAHeight)) { NewBanner = egCropImage(Banner, 0, 0, (Banner->Width > UGAWidth) ? UGAWidth : Banner->Width, (Banner->Height > UGAHeight) ? UGAHeight : Banner->Height); } // if/elseif if (NewBanner) { MyFreePool(Banner); Banner = NewBanner; } MenuBackgroundPixel = Banner->PixelData[0]; } // if Banner exists // clear and draw banner if (GlobalConfig.ScreensaverTime != -1) egClearScreen(&MenuBackgroundPixel); else egClearScreen(&Black); if (Banner != NULL) { BannerPosX = (Banner->Width < UGAWidth) ? ((UGAWidth - Banner->Width) / 2) : 0; BannerPosY = (INTN) (ComputeRow0PosY() / 2) - (INTN) Banner->Height; if (BannerPosY < 0) BannerPosY = 0; GlobalConfig.BannerBottomEdge = BannerPosY + Banner->Height; if (GlobalConfig.ScreensaverTime != -1) BltImage(Banner, (UINTN) BannerPosX, (UINTN) BannerPosY); } } else { // not showing banner // clear to menu background color egClearScreen(&MenuBackgroundPixel); } GraphicsScreenDirty = FALSE; egFreeImage(GlobalConfig.ScreenBackground); GlobalConfig.ScreenBackground = egCopyScreen(); } // VOID BltClearScreen() VOID BltImage(IN EG_IMAGE *Image, IN UINTN XPos, IN UINTN YPos) { egDrawImage(Image, XPos, YPos); GraphicsScreenDirty = TRUE; } VOID BltImageAlpha(IN EG_IMAGE *Image, IN UINTN XPos, IN UINTN YPos, IN EG_PIXEL *BackgroundPixel) { EG_IMAGE *CompImage; // compose on background CompImage = egCreateFilledImage(Image->Width, Image->Height, FALSE, BackgroundPixel); egComposeImage(CompImage, Image, 0, 0); // blit to screen and clean up egDrawImage(CompImage, XPos, YPos); egFreeImage(CompImage); GraphicsScreenDirty = TRUE; } // VOID BltImageComposite(IN EG_IMAGE *BaseImage, IN EG_IMAGE *TopImage, IN UINTN XPos, IN UINTN YPos) // { // UINTN TotalWidth, TotalHeight, CompWidth, CompHeight, OffsetX, OffsetY; // EG_IMAGE *CompImage; // // // initialize buffer with base image // CompImage = egCopyImage(BaseImage); // TotalWidth = BaseImage->Width; // TotalHeight = BaseImage->Height; // // // place the top image // CompWidth = TopImage->Width; // if (CompWidth > TotalWidth) // CompWidth = TotalWidth; // OffsetX = (TotalWidth - CompWidth) >> 1; // CompHeight = TopImage->Height; // if (CompHeight > TotalHeight) // CompHeight = TotalHeight; // OffsetY = (TotalHeight - CompHeight) >> 1; // egComposeImage(CompImage, TopImage, OffsetX, OffsetY); // // // blit to screen and clean up // egDrawImage(CompImage, XPos, YPos); // egFreeImage(CompImage); // GraphicsScreenDirty = TRUE; // } VOID BltImageCompositeBadge(IN EG_IMAGE *BaseImage, IN EG_IMAGE *TopImage, IN EG_IMAGE *BadgeImage, IN UINTN XPos, IN UINTN YPos) { UINTN TotalWidth = 0, TotalHeight = 0, CompWidth = 0, CompHeight = 0, OffsetX = 0, OffsetY = 0; EG_IMAGE *CompImage = NULL; // initialize buffer with base image if (BaseImage != NULL) { CompImage = egCopyImage(BaseImage); TotalWidth = BaseImage->Width; TotalHeight = BaseImage->Height; } // place the top image if ((TopImage != NULL) && (CompImage != NULL)) { CompWidth = TopImage->Width; if (CompWidth > TotalWidth) CompWidth = TotalWidth; OffsetX = (TotalWidth - CompWidth) >> 1; CompHeight = TopImage->Height; if (CompHeight > TotalHeight) CompHeight = TotalHeight; OffsetY = (TotalHeight - CompHeight) >> 1; egComposeImage(CompImage, TopImage, OffsetX, OffsetY); } // place the badge image if (BadgeImage != NULL && CompImage != NULL && (BadgeImage->Width + 8) < CompWidth && (BadgeImage->Height + 8) < CompHeight) { OffsetX += CompWidth - 8 - BadgeImage->Width; OffsetY += CompHeight - 8 - BadgeImage->Height; egComposeImage(CompImage, BadgeImage, OffsetX, OffsetY); } // blit to screen and clean up if (CompImage != NULL) { if (CompImage->HasAlpha) egDrawImageWithTransparency(CompImage, NULL, XPos, YPos, CompImage->Width, CompImage->Height); else egDrawImage(CompImage, XPos, YPos); egFreeImage(CompImage); GraphicsScreenDirty = TRUE; } } refind-0.11.4/refind/pointer.h0000664000175000017500000000252413325166353016424 0ustar rodsmithrodsmith/* * refind/pointer.h * pointer device functions header file * * Copyright (c) 2018 CJ Vaughter * All rights reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef __REFIND_POINTERDEVICE_H_ #define __REFIND_POINTERDEVICE_H_ #ifdef __MAKEWITH_GNUEFI #include "efi.h" #include "efilib.h" #else #include "../include/tiano_includes.h" #endif #ifndef _EFI_POINT_H #include "../EfiLib/AbsolutePointer.h" #endif typedef struct PointerStateStruct { UINTN X, Y; BOOLEAN Press; BOOLEAN Holding; } POINTER_STATE; VOID pdInitialize(); VOID pdCleanup(); BOOLEAN pdAvailable(); UINTN pdCount(); EFI_EVENT pdWaitEvent(IN UINTN Index); EFI_STATUS pdUpdateState(); POINTER_STATE pdGetState(); VOID pdDraw(); VOID pdClear(); #endif /* EOF */ refind-0.11.4/refind/crc32.h0000664000175000017500000000442512626644770015671 0ustar rodsmithrodsmith/*- * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or * code or tables extracted from it, as desired without restriction. * * First, the polynomial itself and its table of feedback terms. The * polynomial is * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 * * Note that we take it "backwards" and put the highest-order term in * the lowest-order bit. The X^32 term is "implied"; the LSB is the * X^31 term, etc. The X^0 term (usually shown as "+1") results in * the MSB being 1 * * Note that the usual hardware shift register implementation, which * is what we're using (we're merely optimizing it by doing eight-bit * chunks at a time) shifts bits into the lowest-order term. In our * implementation, that means shifting towards the right. Why do we * do it this way? Because the calculated CRC must be transmitted in * order from highest-order term to lowest-order term. UARTs transmit * characters in order from LSB to MSB. By storing the CRC this way * we hand it to the UART in the order low-byte to high-byte; the UART * sends each low-bit to hight-bit; and the result is transmission bit * by bit from highest- to lowest-order term without requiring any bit * shuffling on our part. Reception works similarly * * The feedback terms table consists of 256, 32-bit entries. Notes * * The table can be generated at runtime if desired; code to do so * is shown later. It might not be obvious, but the feedback * terms simply represent the results of eight shift/xor opera * tions for all combinations of data and CRC register values * * The values must be right-shifted by eight bits by the "updcrc * logic; the shift must be unsigned (bring in zeroes). On some * hardware you could probably optimize the shift in assembler by * using byte-swap instructions * polynomial $edb88320 * * * CRC32 code derived from work by Gary S. Brown. */ /* * Modified slightly for use on EFI by Rod Smith */ #ifndef __CRC32_H_ #define __CRC32_H_ #ifdef __MAKEWITH_GNUEFI #include "efi.h" #include "efilib.h" #else #include "../include/tiano_includes.h" #endif UINT32 crc32(UINT32 crc, const VOID *buf, UINTN size); #endifrefind-0.11.4/refind/gpt.c0000664000175000017500000002277012775454614015546 0ustar rodsmithrodsmith/* * refind/gpt.c * Functions related to GPT data structures * * Copyright (c) 2014-2015 Roderick W. Smith * All rights reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "gpt.h" #include "lib.h" #include "screen.h" #include "crc32.h" #include "../include/refit_call_wrapper.h" #ifdef __MAKEWITH_TIANO #define BlockIoProtocol gEfiBlockIoProtocolGuid #endif extern GPT_DATA *gPartitions; // Allocate data for the main GPT_DATA structure, as well as the ProtectiveMBR // and Header structures it contains. This function does *NOT*, however, // allocate memory for the Entries data structure, since its size is variable // and is determined by the contents of Header. GPT_DATA * AllocateGptData(VOID) { GPT_DATA *GptData; GptData = AllocateZeroPool(sizeof(GPT_DATA)); if (GptData != NULL) { GptData->ProtectiveMBR = AllocateZeroPool(sizeof(MBR_RECORD)); GptData->Header = AllocateZeroPool(sizeof(GPT_HEADER)); if ((GptData->ProtectiveMBR == NULL) || (GptData->Header == NULL)) { MyFreePool(GptData->ProtectiveMBR); MyFreePool(GptData->Header); MyFreePool(GptData); GptData = NULL; } // if } // if return GptData; } // GPT_DATA * AllocateGptData() // Unallocate a single GPT_DATA structure. This does NOT follow the // linked list, though. VOID ClearGptData(GPT_DATA *Data) { if (Data) { if (Data->ProtectiveMBR) MyFreePool(Data->ProtectiveMBR); if (Data->Header) MyFreePool(Data->Header); if (Data->Entries) MyFreePool(Data->Entries); MyFreePool(Data); } // if } // VOID ClearGptData() // TODO: Make this work on big-endian systems; at the moment, it contains // little-endian assumptions! // Returns TRUE if the GPT protective MBR and header data appear valid, // FALSE otherwise. static BOOLEAN GptHeaderValid(GPT_DATA *GptData) { BOOLEAN IsValid; UINT32 CrcValue, StoredCrcValue; UINTN HeaderSize = sizeof(GPT_HEADER); if ((GptData == NULL) || (GptData->ProtectiveMBR == NULL) || (GptData->Header == NULL)) return FALSE; IsValid = (GptData->ProtectiveMBR->MBRSignature == 0xAA55); IsValid = IsValid && ((GptData->ProtectiveMBR->partitions[0].type == 0xEE) || (GptData->ProtectiveMBR->partitions[1].type == 0xEE) || (GptData->ProtectiveMBR->partitions[2].type == 0xEE) || (GptData->ProtectiveMBR->partitions[3].type == 0xEE)); IsValid = IsValid && ((GptData->Header->signature == 0x5452415020494645ULL) && (GptData->Header->spec_revision == 0x00010000) && (GptData->Header->entry_size == 128)); // Looks good so far; check CRC value.... if (IsValid) { if (GptData->Header->header_size < HeaderSize) HeaderSize = GptData->Header->header_size; StoredCrcValue = GptData->Header->header_crc32; GptData->Header->header_crc32 = 0; CrcValue = crc32(0x0, GptData->Header, HeaderSize); if (CrcValue != StoredCrcValue) IsValid = FALSE; GptData->Header->header_crc32 = StoredCrcValue; } // if return IsValid; } // BOOLEAN GptHeaderValid() // Read GPT data from Volume and store it in *Data. Note that this function // may be called on a Volume that is not in fact a GPT disk (an MBR disk, // a partition, etc.), in which case it will return EFI_LOAD_ERROR or some // other error condition. In this case, *Data will be left alone. // Note also that this function checks CRCs and does other sanity checks // on the input data, but does NOT resort to using the backup data if the // primary data structures are damaged. The intent is that the function // be very conservative about reading GPT data. Currently (version 0.7.10), // rEFInd uses the data only to provide access to partition names. This is // non-critical data, so it's OK to return nothing, but having the program // hang on reading garbage or return nonsense could be very bad. EFI_STATUS ReadGptData(REFIT_VOLUME *Volume, GPT_DATA **Data) { EFI_STATUS Status = EFI_SUCCESS; UINT64 BufferSize; UINTN i; GPT_DATA *GptData = NULL; // Temporary holding storage; transferred to *Data later if ((Volume == NULL) || (Data == NULL)) return EFI_INVALID_PARAMETER; // get block i/o if ((Status == EFI_SUCCESS) && (Volume->BlockIO == NULL)) { Status = refit_call3_wrapper(BS->HandleProtocol, Volume->DeviceHandle, &BlockIoProtocol, (VOID **) &(Volume->BlockIO)); if (EFI_ERROR(Status)) { Volume->BlockIO = NULL; Print(L"Warning: Can't get BlockIO protocol in ReadGptData().\n"); Status = EFI_NOT_READY; } } // if if ((Status == EFI_SUCCESS) && ((!Volume->BlockIO->Media->MediaPresent) || (Volume->BlockIO->Media->LogicalPartition))) Status = EFI_NO_MEDIA; if (Status == EFI_SUCCESS) { GptData = AllocateGptData(); // Note: All but GptData->Entries if (GptData == NULL) { Status = EFI_OUT_OF_RESOURCES; } // if } // if // Read the MBR and store it in GptData->ProtectiveMBR. if (Status == EFI_SUCCESS) { Status = refit_call5_wrapper(Volume->BlockIO->ReadBlocks, Volume->BlockIO, Volume->BlockIO->Media->MediaId, 0, sizeof(MBR_RECORD), (VOID*) GptData->ProtectiveMBR); } // Read the GPT header and store it in GptData->Header. if (Status == EFI_SUCCESS) { Status = refit_call5_wrapper(Volume->BlockIO->ReadBlocks, Volume->BlockIO, Volume->BlockIO->Media->MediaId, 1, sizeof(GPT_HEADER), GptData->Header); } // If it looks like a valid protective MBR & GPT header, try to do more with it.... if (Status == EFI_SUCCESS) { if (GptHeaderValid(GptData)) { // Load actual GPT table.... BufferSize = GptData->Header->entry_count * 128; GptData->Entries = AllocatePool(BufferSize); if (GptData->Entries == NULL) Status = EFI_OUT_OF_RESOURCES; if (Status == EFI_SUCCESS) Status = refit_call5_wrapper(Volume->BlockIO->ReadBlocks, Volume->BlockIO, Volume->BlockIO->Media->MediaId, GptData->Header->entry_lba, BufferSize, GptData->Entries); // Check CRC status of table if ((Status == EFI_SUCCESS) && (crc32(0x0, GptData->Entries, BufferSize) != GptData->Header->entry_crc32)) Status = EFI_CRC_ERROR; // Now, ensure that every name is null-terminated.... if (Status == EFI_SUCCESS) { for (i = 0; i < GptData->Header->entry_count; i++) GptData->Entries[i].name[35] = '\0'; } // if } else { Status = EFI_UNSUPPORTED; } // if/else valid header } // if header read OK if (Status == EFI_SUCCESS) { // Everything looks OK, so copy it over ClearGptData(*Data); *Data = GptData; } else { ClearGptData(GptData); } // if/else return Status; } // EFI_STATUS ReadGptData() // Look in gPartitions for a partition with the specified Guid. If found, return // a pointer to that partition's data. If not found, return a NULL pointer. // The calling function is responsible for freeing the returned memory. GPT_ENTRY * FindPartWithGuid(EFI_GUID *Guid) { UINTN i; GPT_ENTRY *Found = NULL; GPT_DATA *GptData; if ((Guid == NULL) || (gPartitions == NULL)) return NULL; GptData = gPartitions; while ((GptData != NULL) && (!Found)) { i = 0; while ((i < GptData->Header->entry_count) && (!Found)) { if (GuidsAreEqual((EFI_GUID*) &(GptData->Entries[i].partition_guid), Guid)) { Found = AllocateZeroPool(sizeof(GPT_ENTRY)); CopyMem(Found, &GptData->Entries[i], sizeof(GPT_ENTRY)); } else { i++; } // if/else } // while(scanning entries) GptData = GptData->NextEntry; } // while(scanning GPTs) return Found; } // GPT_ENTRY * FindPartWithGuid() // Erase the gPartitions linked-list data structure VOID ForgetPartitionTables(VOID) { GPT_DATA *Next; while (gPartitions != NULL) { Next = gPartitions->NextEntry; ClearGptData(gPartitions); gPartitions = Next; } // while } // VOID ForgetPartitionTables() // If Volume points to a whole disk with a GPT, add it to the gPartitions // linked list of GPTs. VOID AddPartitionTable(REFIT_VOLUME *Volume) { GPT_DATA *GptData = NULL, *GptList; EFI_STATUS Status; UINTN NumTables = 1; Status = ReadGptData(Volume, &GptData); if (Status == EFI_SUCCESS) { if (gPartitions == NULL) { gPartitions = GptData; } else { GptList = gPartitions; while (GptList->NextEntry != NULL) { GptList = GptList->NextEntry; NumTables++; } // while GptList->NextEntry = GptData; NumTables++; } // if/else } else if (GptData != NULL) { ClearGptData(GptData); NumTables = 0; } // if/else } // VOID AddPartitionTable() refind-0.11.4/refind/AutoGen.h0000664000175000017500000000215712626644770016317 0ustar rodsmithrodsmith/** DO NOT EDIT FILE auto-generated Module name: AutoGen.h Abstract: Auto-generated AutoGen.h for building module or library. **/ #ifndef _AUTOGENH_B8448DD1_B146_41B7_9D66_98B3A0A404D3 #define _AUTOGENH_B8448DD1_B146_41B7_9D66_98B3A0A404D3 #ifdef __cplusplus extern "C" { #endif #include #include #include extern GUID gEfiCallerIdGuid; #define EFI_CALLER_ID_GUID \ {0xB8448DD1, 0xB146, 0x41B7, {0x9D, 0x66, 0x98, 0xB3, 0xA0, 0xA4, 0x04, 0xD3}} // Definition of PCDs used in this module #define _PCD_TOKEN_PcdUgaConsumeSupport 16U #define _PCD_VALUE_PcdUgaConsumeSupport ((BOOLEAN)1U) extern const BOOLEAN _gPcd_FixedAtBuild_PcdUgaConsumeSupport; #define _PCD_GET_MODE_BOOL_PcdUgaConsumeSupport _gPcd_FixedAtBuild_PcdUgaConsumeSupport //#define _PCD_SET_MODE_BOOL_PcdUgaConsumeSupport ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD // Definition of PCDs used in libraries is in AutoGen.c EFI_STATUS EFIAPI efi_main ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ); #ifdef __cplusplus } #endif #endif refind-0.11.4/refind/Makefile0000664000175000017500000000306113141450277016225 0ustar rodsmithrodsmith# # refind/Makefile # Build control file for the rEFInd boot menu # # This program is licensed under the terms of the GNU GPL, version 3, # or (at your option) any later version. # You should have received a copy of the GNU General Public License # along with this program. If not, see . SRCDIR = . VPATH = $(SRCDIR) ARCH = $(shell uname -m | sed s,i[3456789]86,ia32,) TARGET = refind.efi ifeq ($(ARCH),ia32) LIBEG = build32 TARGET = refind_ia32.efi endif ifeq ($(ARCH),x86_64) LIBEG = build64 TARGET = refind_x64.efi endif ifeq ($(ARCH),aarch64) LIBEG = build TARGET = refind_aa64.efi endif LOCAL_GNUEFI_CFLAGS = -I$(SRCDIR) -I$(SRCDIR)/../include \ -I$(SRCDIR)/../libeg -I$(SRCDIR)/../mok LOCAL_LDFLAGS = -L$(SRCDIR)/../libeg/ -L$(SRCDIR)/../mok/ \ -L$(SRCDIR)/../EfiLib/ LOCAL_LIBS = -leg -lmok -lEfiLib OBJS = main.o mystrings.o apple.o line_edit.o config.o menu.o pointer.o \ screen.o icns.o gpt.o crc32.o lib.o driver_support.o \ legacy.o include $(SRCDIR)/../Make.common all: $(TARGET) $(SHLIB_TARGET): $(OBJS) $(LD) $(LOCAL_LDFLAGS) $(GNUEFI_LDFLAGS) $(SUBSYSTEM_LDFLAG) $(OBJS) \ -o $@ $(LOCAL_LIBS) $(GNUEFI_LIBS) $(TARGET): $(SHLIB_TARGET) $(OBJCOPY) -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel \ -j .rela -j .rel.* -j .rela.* -j .rel* -j .rela* \ -j .reloc $(FORMAT) $< $@ chmod a-x $(TARGET) clean: rm -f $(TARGET) *~ *.so $(OBJS) *.efi *.obj refind_*.txt \ refind_*.dll *.lib refind-0.11.4/refind/menu.h0000664000175000017500000000777313141071360015710 0ustar rodsmithrodsmith/* * refind/menu.h * menu functions header file * * Copyright (c) 2006-2009 Christoph Pfisterer * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * * Neither the name of Christoph Pfisterer nor the names of the * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Modifications copyright (c) 2012 Roderick W. Smith * * Modifications distributed under the terms of the GNU General Public * License (GPL) version 3 (GPLv3), a copy of which must be distributed * with this source code or binaries made from it. * */ #ifndef __REFIND_MENU_H_ #define __REFIND_MENU_H_ #ifdef __MAKEWITH_GNUEFI #include "efi.h" #include "efilib.h" #else #include "../include/tiano_includes.h" #endif #include "global.h" #include "libeg.h" #include "pointer.h" // // menu module // #define MENU_EXIT_ENTER (1) #define MENU_EXIT_ESCAPE (2) #define MENU_EXIT_DETAILS (3) #define MENU_EXIT_TIMEOUT (4) #define MENU_EXIT_EJECT (5) #define MENU_EXIT_HIDE (6) #define TAG_RETURN (99) // scrolling definitions typedef struct { INTN CurrentSelection, PreviousSelection, MaxIndex; INTN FirstVisible, LastVisible, MaxVisible; INTN FinalRow0, InitialRow1; INTN ScrollMode; BOOLEAN PaintAll, PaintSelection; } SCROLL_STATE; #define SCROLL_LINE_UP (0) #define SCROLL_LINE_DOWN (1) #define SCROLL_PAGE_UP (2) #define SCROLL_PAGE_DOWN (3) #define SCROLL_FIRST (4) #define SCROLL_LAST (5) #define SCROLL_NONE (6) #define SCROLL_LINE_RIGHT (7) #define SCROLL_LINE_LEFT (8) #define SCROLL_MODE_TEXT (0) /* Used in text mode & for GUI submenus */ #define SCROLL_MODE_ICONS (1) /* Used for main GUI menu */ #define POINTER_NO_ITEM (-1) #define POINTER_LEFT_ARROW (-2) #define POINTER_RIGHT_ARROW (-3) #define INPUT_KEY (0) #define INPUT_POINTER (1) #define INPUT_TIMEOUT (2) #define INPUT_TIMER_ERROR (3) struct _refit_menu_screen; VOID AddMenuInfoLine(IN REFIT_MENU_SCREEN *Screen, IN CHAR16 *InfoLine); VOID AddMenuEntry(IN REFIT_MENU_SCREEN *Screen, IN REFIT_MENU_ENTRY *Entry); UINTN ComputeRow0PosY(VOID); VOID MainMenuStyle(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, IN UINTN Function, IN CHAR16 *ParamText); UINTN RunMenu(IN REFIT_MENU_SCREEN *Screen, OUT REFIT_MENU_ENTRY **ChosenEntry); VOID DisplaySimpleMessage(CHAR16 *Title, CHAR16 *Message); VOID ManageHiddenTags(VOID); CHAR16* ReadHiddenTags(CHAR16 *VarName); UINTN RunMainMenu(IN REFIT_MENU_SCREEN *Screen, IN CHAR16** DefaultSelection, OUT REFIT_MENU_ENTRY **ChosenEntry); UINTN FindMainMenuItem(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, IN UINTN PosX, IN UINTN PosY); VOID GenerateWaitList(); UINTN WaitForInput(IN UINTN Timeout); #endif /* EOF */ refind-0.11.4/refind/line_edit.h0000664000175000017500000000237012626644770016706 0ustar rodsmithrodsmith/* * refind/screen_edit.h * * Line-editing functions borrowed from gummiboot * */ /* * Simple UEFI boot loader which executes configured EFI images, where the * default entry is selected by a configured pattern (glob) or an on-screen * menu. * * All gummiboot code is LGPL not GPL, to stay out of politics and to give * the freedom of copying code from programs to possible future libraries. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * Copyright (C) 2012-2013 Kay Sievers * Copyright (C) 2012 Harald Hoyer * * "Any intelligent fool can make things bigger, more complex, and more violent. " * -- Albert Einstein */ #ifndef __LINE_EDIT_H_ #define __LINE_EDIT_H_ BOOLEAN line_edit(CHAR16 *line_in, CHAR16 **line_out, UINTN x_max); #endif refind-0.11.4/refind/AutoGen.c0000664000175000017500000004600312626644770016310 0ustar rodsmithrodsmith/** DO NOT EDIT FILE auto-generated Module name: AutoGen.c Abstract: Auto-generated AutoGen.c for building module or library. **/ #include #include #include #include #include #include "AutoGen.h" GLOBAL_REMOVE_IF_UNREFERENCED GUID gEfiCallerIdGuid = {0xB8448DD1, 0xB146, 0x41B7, {0x9D, 0x66, 0x98, 0xB3, 0xA0, 0xA4, 0x04, 0xD3}}; // Guids GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiAcpiTableGuid = { 0x8868E871, 0xE4F1, 0x11D3, { 0xBC, 0x22, 0x00, 0x80, 0xC7, 0x3C, 0x88, 0x81 }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiAcpi10TableGuid = { 0xEB9D2D30, 0x2D88, 0x11D3, { 0x9A, 0x16, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiAcpi20TableGuid = { 0x8868E871, 0xE4F1, 0x11D3, { 0xBC, 0x22, 0x00, 0x80, 0xC7, 0x3C, 0x88, 0x81 }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDxeServicesTableGuid = { 0x05AD34BA, 0x6F02, 0x4214, { 0x95, 0x2E, 0x4D, 0xA0, 0x39, 0x8E, 0x2B, 0xB9 }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiEventReadyToBootGuid = { 0x7CE88FB3, 0x4BD7, 0x4679, { 0x87, 0xA8, 0xA8, 0xD8, 0xDE, 0xE5, 0x0D, 0x2B }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiEventVirtualAddressChangeGuid = { 0x13FA7698, 0xC831, 0x49C7, { 0x87, 0xEA, 0x8F, 0x43, 0xFC, 0xC2, 0x51, 0x96 }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiEventExitBootServicesGuid = { 0x27ABF055, 0xB1B8, 0x4C26, { 0x80, 0x48, 0x74, 0x8F, 0x37, 0xBA, 0xA2, 0xDF }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiFileInfoGuid = { 0x09576E92, 0x6D3F, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiFileSystemInfoGuid = { 0x09576E93, 0x6D3F, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiFileSystemVolumeLabelInfoIdGuid = { 0xDB47D7D3, 0xFE81, 0x11D3, { 0x9A, 0x35, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiGlobalVariableGuid = { 0x8BE4DF61, 0x93CA, 0x11D2, { 0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiPartTypeLegacyMbrGuid = { 0x024DEE41, 0x33E7, 0x11D3, { 0x9D, 0x69, 0x00, 0x08, 0xC7, 0x81, 0xF3, 0x9F }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiPartTypeSystemPartGuid = { 0xC12A7328, 0xF81F, 0x11D2, { 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSmbiosTableGuid = { 0xEB9D2D31, 0x2D88, 0x11D3, { 0x9A, 0x16, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSasDevicePathGuid = { 0xd487ddb4, 0x008b, 0x11d9, { 0xaf, 0xdc, 0x00, 0x10, 0x83, 0xff, 0xca, 0x4d }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiMdePkgTokenSpaceGuid = { 0x914AEBE7, 0x4635, 0x459b, { 0xAA, 0x1C, 0x11, 0xE2, 0x19, 0xB0, 0x3A, 0x10 }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiEventLegacyBootGuid = { 0x2A571201, 0x4966, 0x47F6, { 0x8B, 0x86, 0xF3, 0x1E, 0x41, 0xF3, 0x2F, 0x10 }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiHobListGuid = { 0x7739F24C, 0x93D7, 0x11D4, { 0x9A, 0x3A, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; // Protocols GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiComponentName2ProtocolGuid = { 0x6A7A5CFF, 0xE8D9, 0x4F70, { 0xBA, 0xDA, 0x75, 0xAB, 0x30, 0x25, 0xCE, 0x14 }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDevicePathToTextProtocolGuid = { 0x8B843E20, 0x8132, 0x4852, { 0x90, 0xCC, 0x55, 0x1A, 0x4E, 0x4A, 0x7F, 0x1C }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSimpleFileSystemProtocolGuid = { 0x964E5B22, 0x6459, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSimpleTextInProtocolGuid = { 0x387477C1, 0x69C7, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSimpleTextInputExProtocolGuid = {0xdd9e7534, 0x7762, 0x4698, { 0x8c, 0x14, 0xf5, 0x85, 0x17, 0xa6, 0x25, 0xaa } }; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSimpleTextOutProtocolGuid = { 0x387477C2, 0x69C7, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiUnicodeCollationProtocolGuid = { 0x1D85CD7F, 0xF43D, 0x11D2, { 0x9A, 0x0C, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiUnicodeCollation2ProtocolGuid = {0xa4c751fc, 0x23ae, 0x4c3e, { 0x92, 0xe9, 0x49, 0x64, 0xcf, 0x63, 0xf3, 0x49 }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiAcpiS3SaveProtocolGuid = { 0x125F2DE1, 0xFB85, 0x440C, { 0xA5, 0x4C, 0x4D, 0x99, 0x35, 0x8A, 0x8D, 0x38 }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiBlockIoProtocolGuid = { 0x964E5B21, 0x6459, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiCpuArchProtocolGuid = { 0x26BACCB1, 0x6F42, 0x11D4, { 0xBC, 0xE7, 0x00, 0x80, 0xC7, 0x3C, 0x88, 0x81 }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDebugPortProtocolGuid = { 0xEBA4E8D2, 0x3858, 0x41EC, { 0xA2, 0x81, 0x26, 0x47, 0xBA, 0x96, 0x60, 0xD0 }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDevicePathProtocolGuid = { 0x09576E91, 0x6D3F, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDiskIoProtocolGuid = { 0xCE345171, 0xBA0B, 0x11D2, { 0x8E, 0x4F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiExtScsiPassThruProtocolGuid = { 0x143b7632, 0xb81b, 0x4cb7, {0xab, 0xd3, 0xb6, 0x25, 0xa5, 0xb9, 0xbf, 0xfe }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiFirmwareVolume2ProtocolGuid = { 0x220e73b6, 0x6bdb, 0x4413, { 0x84, 0x5, 0xb9, 0x74, 0xb1, 0x8, 0x61, 0x9a } }; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiGraphicsOutputProtocolGuid = { 0x9042A9DE, 0x23DC, 0x4A38, { 0x96, 0xFB, 0x7A, 0xDE, 0xD0, 0x80, 0x51, 0x6A }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiHiiFontProtocolGuid = {0xe9ca4775, 0x8657, 0x47fc, {0x97, 0xe7, 0x7e, 0xd6, 0x5a, 0x08, 0x43, 0x24}}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiLegacy8259ProtocolGuid = { 0x38321dba, 0x4fe0, 0x4e17, { 0x8a, 0xec, 0x41, 0x30, 0x55, 0xea, 0xed, 0xc1 }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiLoadedImageProtocolGuid = { 0x5B1B31A1, 0x9562, 0x11D2, { 0x8E, 0x3F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiOEMBadgingProtocolGuid = { 0x170E13C0, 0xBF1B, 0x4218, { 0x87, 0x1D, 0x2A, 0xBD, 0xC6, 0xF8, 0x87, 0xBC }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiPciIoProtocolGuid = { 0x4CF5B200, 0x68B8, 0x4CA5, { 0x9E, 0xEC, 0xB2, 0x3E, 0x3F, 0x50, 0x02, 0x9A }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiScsiIoProtocolGuid = { 0x932F47e6, 0x2362, 0x4002, { 0x80, 0x3E, 0x3C, 0xD5, 0x4B, 0x13, 0x8F, 0x85 }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiScsiPassThruProtocolGuid = { 0xA59E8FCF, 0xBDA0, 0x43BB, { 0x90, 0xB1, 0xD3, 0x73, 0x2E, 0xCA, 0xA8, 0x77 }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSimpleNetworkProtocolGuid = { 0xA19832B9, 0xAC25, 0x11D3, { 0x9A, 0x2D, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; //GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiUgaDrawProtocolGuid = { 0x982C298B, 0xF4FA, 0x41CB, { 0xB8, 0x38, 0x77, 0xAA, 0x68, 0x8F, 0xB8, 0x39 }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiAbsolutePointerProtocolGuid = { 0x8D59D32B, 0xC655, 0x4AE9, { 0x9B, 0x15, 0xF2, 0x59, 0x04, 0x99, 0x2A, 0x43 } }; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiAcpiTableProtocolGuid = { 0xFFE06BDD, 0x6107, 0x46A6, { 0x7B, 0xB2, 0x5A, 0x9C, 0x7E, 0xC5, 0x27, 0x5C }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiEdidActiveProtocolGuid = { 0xBD8C1056, 0x9F36, 0x44EC, { 0x92, 0xA8, 0xA6, 0x33, 0x7F, 0x81, 0x79, 0x86 }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiEdidDiscoveredProtocolGuid = { 0x1C0C34F6, 0xD380, 0x41FA, { 0xA0, 0x49, 0x8A, 0xD0, 0x6C, 0x1A, 0x66, 0xAA }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiHiiDatabaseProtocolGuid = {0xef9fc172, 0xa1b2, 0x4693, {0xb3, 0x27, 0x6d, 0x32, 0xfc, 0x41, 0x60, 0x42}}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiHiiImageProtocolGuid = {0x31a6406a, 0x6bdf, 0x4e46, {0xb2, 0xa2, 0xeb, 0xaa, 0x89, 0xc4, 0x09, 0x20}}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiHiiProtocolGuid = { 0xd7ad636e, 0xb997, 0x459b, { 0xbf, 0x3f, 0x88, 0x46, 0x89, 0x79, 0x80, 0xe1 }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSimplePointerProtocolGuid = { 0x31878C87, 0x0B75, 0x11D5, { 0x9A, 0x4F, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSmbiosProtocolGuid = {0x3583ff6, 0xcb36, 0x4940, { 0x94, 0x7e, 0xb9, 0xb3, 0x9f, 0x4a, 0xfa, 0xf7}}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSecurityArchProtocolGuid = { 0xA46423E3, 0x4617, 0x49F1, { 0xB9, 0xFF, 0xD1, 0xBF, 0xA9, 0x11, 0x58, 0x39 }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiLegacyBiosProtocolGuid = { 0xdb9a1e3d, 0x45cb, 0x4abb, { 0x85, 0x3b, 0xe5, 0x38, 0x7f, 0xdb, 0x2e, 0x2d }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiLoadFile2ProtocolGuid = { 0x4006c0c1, 0xfcb3, 0x403e, {0x99, 0x6d, 0x4a, 0x6c, 0x87, 0x24, 0xe0, 0x6d }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiLoadFileProtocolGuid = { 0x56EC3091, 0x954C, 0x11D2, { 0x8E, 0x3F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiHiiPackageListProtocolGuid = { 0x6a1ee763, 0xd47a, 0x43b4, {0xaa, 0xbe, 0xef, 0x1d, 0xe2, 0xab, 0x56, 0xfc}}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverBindingProtocolGuid = { 0x18A031AB, 0xB443, 0x4D1A, { 0xA5, 0xC0, 0x0C, 0x09, 0x26, 0x1E, 0x9F, 0x71 }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiComponentNameProtocolGuid = { 0x107A772C, 0xD5E1, 0x11D4, { 0x9A, 0x46, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverConfigurationProtocolGuid = { 0x107A772B, 0xD5E1, 0x11D4, { 0x9A, 0x46, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverConfiguration2ProtocolGuid = { 0xBFD7DC1D, 0x24F1, 0x40D9, { 0x82, 0xE7, 0x2E, 0x09, 0xBB, 0x6B, 0x4E, 0xBE }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverDiagnosticsProtocolGuid = { 0x0784924F, 0xE296, 0x11D4, { 0x9A, 0x49, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverDiagnostics2ProtocolGuid = { 0x4D330321, 0x025F, 0x4AAC, { 0x90, 0xD8, 0x5E, 0xD9, 0x00, 0x17, 0x3B, 0x63 }}; // Definition of PCDs used in this module //GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdUgaConsumeSupport = _PCD_VALUE_PcdUgaConsumeSupport; // Definition of PCDs used in libraries #define _PCD_TOKEN_PcdMaximumLinkedListLength 2U #define _PCD_VALUE_PcdMaximumLinkedListLength 1000000U GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdMaximumLinkedListLength = _PCD_VALUE_PcdMaximumLinkedListLength; extern const UINT32 _gPcd_FixedAtBuild_PcdMaximumLinkedListLength; #define _PCD_GET_MODE_32_PcdMaximumLinkedListLength _gPcd_FixedAtBuild_PcdMaximumLinkedListLength #define _PCD_SET_MODE_32_PcdMaximumLinkedListLength ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD #define _PCD_TOKEN_PcdMaximumAsciiStringLength 3U #define _PCD_VALUE_PcdMaximumAsciiStringLength 1000000U GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdMaximumAsciiStringLength = _PCD_VALUE_PcdMaximumAsciiStringLength; extern const UINT32 _gPcd_FixedAtBuild_PcdMaximumAsciiStringLength; #define _PCD_GET_MODE_32_PcdMaximumAsciiStringLength _gPcd_FixedAtBuild_PcdMaximumAsciiStringLength #define _PCD_SET_MODE_32_PcdMaximumAsciiStringLength ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD #define _PCD_TOKEN_PcdMaximumUnicodeStringLength 4U #define _PCD_VALUE_PcdMaximumUnicodeStringLength 1000000U GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdMaximumUnicodeStringLength = _PCD_VALUE_PcdMaximumUnicodeStringLength; extern const UINT32 _gPcd_FixedAtBuild_PcdMaximumUnicodeStringLength; #define _PCD_GET_MODE_32_PcdMaximumUnicodeStringLength _gPcd_FixedAtBuild_PcdMaximumUnicodeStringLength #define _PCD_SET_MODE_32_PcdMaximumUnicodeStringLength ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD #define _PCD_TOKEN_PcdVerifyNodeInList 5U #define _PCD_VALUE_PcdVerifyNodeInList ((BOOLEAN)0U) GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdVerifyNodeInList = _PCD_VALUE_PcdVerifyNodeInList; extern const BOOLEAN _gPcd_FixedAtBuild_PcdVerifyNodeInList; #define _PCD_GET_MODE_BOOL_PcdVerifyNodeInList _gPcd_FixedAtBuild_PcdVerifyNodeInList #define _PCD_SET_MODE_BOOL_PcdVerifyNodeInList ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD #define _PCD_TOKEN_PcdMaximumDevicePathNodeCount 6U #define _PCD_VALUE_PcdMaximumDevicePathNodeCount 0U GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdMaximumDevicePathNodeCount = _PCD_VALUE_PcdMaximumDevicePathNodeCount; extern const UINT32 _gPcd_FixedAtBuild_PcdMaximumDevicePathNodeCount; #define _PCD_GET_MODE_32_PcdMaximumDevicePathNodeCount _gPcd_FixedAtBuild_PcdMaximumDevicePathNodeCount //#define _PCD_SET_MODE_32_PcdMaximumDevicePathNodeCount ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD #define _PCD_TOKEN_PcdDriverDiagnosticsDisable 6U #define _PCD_VALUE_PcdDriverDiagnosticsDisable ((BOOLEAN)0U) GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdDriverDiagnosticsDisable = _PCD_VALUE_PcdDriverDiagnosticsDisable; extern const BOOLEAN _gPcd_FixedAtBuild_PcdDriverDiagnosticsDisable; #define _PCD_GET_MODE_BOOL_PcdDriverDiagnosticsDisable _gPcd_FixedAtBuild_PcdDriverDiagnosticsDisable #define _PCD_SET_MODE_BOOL_PcdDriverDiagnosticsDisable ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD #define _PCD_TOKEN_PcdComponentNameDisable 7U #define _PCD_VALUE_PcdComponentNameDisable ((BOOLEAN)0U) GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdComponentNameDisable = _PCD_VALUE_PcdComponentNameDisable; extern const BOOLEAN _gPcd_FixedAtBuild_PcdComponentNameDisable; #define _PCD_GET_MODE_BOOL_PcdComponentNameDisable _gPcd_FixedAtBuild_PcdComponentNameDisable #define _PCD_SET_MODE_BOOL_PcdComponentNameDisable ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD #define _PCD_TOKEN_PcdDriverDiagnostics2Disable 8U #define _PCD_VALUE_PcdDriverDiagnostics2Disable ((BOOLEAN)0U) GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdDriverDiagnostics2Disable = _PCD_VALUE_PcdDriverDiagnostics2Disable; extern const BOOLEAN _gPcd_FixedAtBuild_PcdDriverDiagnostics2Disable; #define _PCD_GET_MODE_BOOL_PcdDriverDiagnostics2Disable _gPcd_FixedAtBuild_PcdDriverDiagnostics2Disable #define _PCD_SET_MODE_BOOL_PcdDriverDiagnostics2Disable ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD #define _PCD_TOKEN_PcdComponentName2Disable 9U #define _PCD_VALUE_PcdComponentName2Disable ((BOOLEAN)0U) GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdComponentName2Disable = _PCD_VALUE_PcdComponentName2Disable; extern const BOOLEAN _gPcd_FixedAtBuild_PcdComponentName2Disable; #define _PCD_GET_MODE_BOOL_PcdComponentName2Disable _gPcd_FixedAtBuild_PcdComponentName2Disable #define _PCD_SET_MODE_BOOL_PcdComponentName2Disable ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD #define _PCD_TOKEN_PcdUefiLibMaxPrintBufferSize 10U #define _PCD_VALUE_PcdUefiLibMaxPrintBufferSize 320U GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdUefiLibMaxPrintBufferSize = _PCD_VALUE_PcdUefiLibMaxPrintBufferSize; extern const UINT32 _gPcd_FixedAtBuild_PcdUefiLibMaxPrintBufferSize; #define _PCD_GET_MODE_32_PcdUefiLibMaxPrintBufferSize _gPcd_FixedAtBuild_PcdUefiLibMaxPrintBufferSize #define _PCD_SET_MODE_32_PcdUefiLibMaxPrintBufferSize ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD EFI_STATUS EFIAPI UefiBootServicesTableLibConstructor ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ); EFI_STATUS EFIAPI UefiRuntimeServicesTableLibConstructor ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ); EFI_STATUS EFIAPI UefiLibConstructor ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ); EFI_STATUS EFIAPI DxeServicesTableLibConstructor ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ); EFI_STATUS EFIAPI HobLibConstructor ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ); // VOID // EFIAPI // ProcessLibraryConstructorList ( // IN EFI_HANDLE ImageHandle, // IN EFI_SYSTEM_TABLE *SystemTable // ) // { // EFI_STATUS Status; // // Status = UefiBootServicesTableLibConstructor (ImageHandle, SystemTable); // ASSERT_EFI_ERROR (Status); // // Status = UefiRuntimeServicesTableLibConstructor (ImageHandle, SystemTable); // ASSERT_EFI_ERROR (Status); // // Status = UefiLibConstructor (ImageHandle, SystemTable); // ASSERT_EFI_ERROR (Status); // // Status = DxeServicesTableLibConstructor (ImageHandle, SystemTable); // ASSERT_EFI_ERROR (Status); // // Status = HobLibConstructor (ImageHandle, SystemTable); // ASSERT_EFI_ERROR (Status); // // } // VOID // EFIAPI // ProcessLibraryDestructorList ( // IN EFI_HANDLE ImageHandle, // IN EFI_SYSTEM_TABLE *SystemTable // ) // { // // } const UINT32 _gUefiDriverRevision = 0x00010000U; // EFI_STATUS // EFIAPI // ProcessModuleEntryPointList ( // IN EFI_HANDLE ImageHandle, // IN EFI_SYSTEM_TABLE *SystemTable // ) // // { // return efi_main (ImageHandle, SystemTable); // } VOID EFIAPI ExitDriver ( IN EFI_STATUS Status ) { if (EFI_ERROR (Status)) { ProcessLibraryDestructorList (gImageHandle, gST); } gBS->Exit (gImageHandle, Status, 0, NULL); } //GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gDriverUnloadImageCount = 0U; // EFI_STATUS // EFIAPI // ProcessModuleUnloadList ( // IN EFI_HANDLE ImageHandle // ) // { // return EFI_SUCCESS; // } // Stuff added in effort to get Secure Boot working.... #define _PCD_TOKEN_PcdDebugPropertyMask 11U #define _PCD_VALUE_PcdDebugPropertyMask 0x0fU GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdDebugPropertyMask = _PCD_VALUE_PcdDebugPropertyMask; extern const UINT8 _gPcd_FixedAtBuild_PcdDebugPropertyMask; #define _PCD_GET_MODE_8_PcdDebugPropertyMask _gPcd_FixedAtBuild_PcdDebugPropertyMask //#define _PCD_SET_MODE_8_PcdDebugPropertyMask ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD #define _PCD_TOKEN_PcdDebugClearMemoryValue 10U #define _PCD_VALUE_PcdDebugClearMemoryValue 0xAFU GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdDebugClearMemoryValue = _PCD_VALUE_PcdDebugClearMemoryValue; extern const UINT8 _gPcd_FixedAtBuild_PcdDebugClearMemoryValue; #define _PCD_GET_MODE_8_PcdDebugClearMemoryValue _gPcd_FixedAtBuild_PcdDebugClearMemoryValue //#define _PCD_SET_MODE_8_PcdDebugClearMemoryValue ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD #define _PCD_TOKEN_PcdDebugPrintErrorLevel 5U #define _PCD_VALUE_PcdDebugPrintErrorLevel 0x80000000U GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdDebugPrintErrorLevel = _PCD_VALUE_PcdDebugPrintErrorLevel; extern const UINT32 _gPcd_FixedAtBuild_PcdDebugPrintErrorLevel; #define _PCD_GET_MODE_32_PcdDebugPrintErrorLevel _gPcd_FixedAtBuild_PcdDebugPrintErrorLevel //#define _PCD_SET_MODE_32_PcdDebugPrintErrorLevel ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD refind-0.11.4/refind/menu.c.orig0000664000175000017500000021311713141072457016641 0ustar rodsmithrodsmith/* * refit/menu.c * Menu functions * * Copyright (c) 2006 Christoph Pfisterer * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * * Neither the name of Christoph Pfisterer nor the names of the * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Modifications copyright (c) 2012-2017 Roderick W. Smith * * Modifications distributed under the terms of the GNU General Public * License (GPL) version 3 (GPLv3), or (at your option) any later version. * */ /* * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "global.h" #include "screen.h" #include "lib.h" #include "menu.h" #include "config.h" #include "libeg.h" #include "libegint.h" #include "line_edit.h" #include "mystrings.h" #include "icns.h" #include "../include/refit_call_wrapper.h" #include "../include/egemb_back_selected_small.h" #include "../include/egemb_back_selected_big.h" #include "../include/egemb_arrow_left.h" #include "../include/egemb_arrow_right.h" // other menu definitions #define MENU_FUNCTION_INIT (0) #define MENU_FUNCTION_CLEANUP (1) #define MENU_FUNCTION_PAINT_ALL (2) #define MENU_FUNCTION_PAINT_SELECTION (3) #define MENU_FUNCTION_PAINT_TIMEOUT (4) #define MENU_FUNCTION_PAINT_HINTS (5) typedef VOID (*MENU_STYLE_FUNC)(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, IN UINTN Function, IN CHAR16 *ParamText); static CHAR16 ArrowUp[2] = { ARROW_UP, 0 }; static CHAR16 ArrowDown[2] = { ARROW_DOWN, 0 }; static UINTN TileSizes[2] = { 144, 64 }; // Text and icon spacing constants.... #define TEXT_YMARGIN (2) #define TITLEICON_SPACING (16) #define TILE_XSPACING (8) #define TILE_YSPACING (16) // Alignment values for PaintIcon() #define ALIGN_RIGHT 1 #define ALIGN_LEFT 0 static EG_IMAGE *SelectionImages[2] = { NULL, NULL }; static EG_PIXEL SelectionBackgroundPixel = { 0xff, 0xff, 0xff, 0 }; EFI_EVENT* WaitList = NULL; UINTN WaitListLength = 0; // Pointer variables BOOLEAN PointerEnabled = FALSE; BOOLEAN PointerActive = FALSE; BOOLEAN DrawSelection = TRUE; extern EFI_GUID RefindGuid; extern REFIT_MENU_ENTRY MenuEntryReturn; static REFIT_MENU_ENTRY MenuEntryYes = { L"Yes", TAG_RETURN, 1, 0, 0, NULL, NULL, NULL }; static REFIT_MENU_ENTRY MenuEntryNo = { L"No", TAG_RETURN, 1, 0, 0, NULL, NULL, NULL }; // // Graphics helper functions // static VOID InitSelection(VOID) { EG_IMAGE *TempSmallImage = NULL, *TempBigImage = NULL; BOOLEAN LoadedSmallImage = FALSE; if (!AllowGraphicsMode) return; if (SelectionImages[0] != NULL) return; // load small selection image if (GlobalConfig.SelectionSmallFileName != NULL) { TempSmallImage = egLoadImage(SelfDir, GlobalConfig.SelectionSmallFileName, TRUE); } if (TempSmallImage == NULL) TempSmallImage = egPrepareEmbeddedImage(&egemb_back_selected_small, TRUE); else LoadedSmallImage = TRUE; SelectionImages[1] = egScaleImage(TempSmallImage, TileSizes[1], TileSizes[1]); // load big selection image if (GlobalConfig.SelectionBigFileName != NULL) { TempBigImage = egLoadImage(SelfDir, GlobalConfig.SelectionBigFileName, TRUE); } if (TempBigImage == NULL) { if (LoadedSmallImage) { // calculate big selection image from small one TempBigImage = egCopyImage(TempSmallImage); } else { TempBigImage = egPrepareEmbeddedImage(&egemb_back_selected_big, TRUE); } } SelectionImages[0] = egScaleImage(TempBigImage, TileSizes[0], TileSizes[0]); if (TempSmallImage) egFreeImage(TempSmallImage); if (TempBigImage) egFreeImage(TempBigImage); } // VOID InitSelection() // // Scrolling functions // static VOID InitScroll(OUT SCROLL_STATE *State, IN UINTN ItemCount, IN UINTN VisibleSpace) { State->PreviousSelection = State->CurrentSelection = 0; State->MaxIndex = (INTN)ItemCount - 1; State->FirstVisible = 0; if (AllowGraphicsMode) { State->MaxVisible = UGAWidth / (TileSizes[0] + TILE_XSPACING) - 1; } else State->MaxVisible = ConHeight - 4; if ((VisibleSpace > 0) && (VisibleSpace < State->MaxVisible)) State->MaxVisible = (INTN)VisibleSpace; State->PaintAll = TRUE; State->PaintSelection = FALSE; State->LastVisible = State->FirstVisible + State->MaxVisible - 1; } // Adjust variables relating to the scrolling of tags, for when a selected icon isn't // visible given the current scrolling condition.... static VOID AdjustScrollState(IN SCROLL_STATE *State) { if (State->CurrentSelection > State->LastVisible) { State->LastVisible = State->CurrentSelection; State->FirstVisible = 1 + State->CurrentSelection - State->MaxVisible; if (State->FirstVisible < 0) // shouldn't happen, but just in case.... State->FirstVisible = 0; State->PaintAll = TRUE; } // Scroll forward if (State->CurrentSelection < State->FirstVisible) { State->FirstVisible = State->CurrentSelection; State->LastVisible = State->CurrentSelection + State->MaxVisible - 1; State->PaintAll = TRUE; } // Scroll backward } // static VOID AdjustScrollState static VOID UpdateScroll(IN OUT SCROLL_STATE *State, IN UINTN Movement) { State->PreviousSelection = State->CurrentSelection; switch (Movement) { case SCROLL_LINE_LEFT: if (State->CurrentSelection > 0) { State->CurrentSelection --; } break; case SCROLL_LINE_RIGHT: if (State->CurrentSelection < State->MaxIndex) { State->CurrentSelection ++; } break; case SCROLL_LINE_UP: if (State->ScrollMode == SCROLL_MODE_ICONS) { if (State->CurrentSelection >= State->InitialRow1) { if (State->MaxIndex > State->InitialRow1) { // avoid division by 0! State->CurrentSelection = State->FirstVisible + (State->LastVisible - State->FirstVisible) * (State->CurrentSelection - State->InitialRow1) / (State->MaxIndex - State->InitialRow1); } else { State->CurrentSelection = State->FirstVisible; } // if/else } // if in second row } else { if (State->CurrentSelection > 0) State->CurrentSelection--; } // if/else break; case SCROLL_LINE_DOWN: if (State->ScrollMode == SCROLL_MODE_ICONS) { if (State->CurrentSelection <= State->FinalRow0) { if (State->LastVisible > State->FirstVisible) { // avoid division by 0! State->CurrentSelection = State->InitialRow1 + (State->MaxIndex - State->InitialRow1) * (State->CurrentSelection - State->FirstVisible) / (State->LastVisible - State->FirstVisible); } else { State->CurrentSelection = State->InitialRow1; } // if/else } // if in first row } else { if (State->CurrentSelection < State->MaxIndex) State->CurrentSelection++; } // if/else break; case SCROLL_PAGE_UP: if (State->CurrentSelection <= State->FinalRow0) State->CurrentSelection -= State->MaxVisible; else if (State->CurrentSelection == State->InitialRow1) State->CurrentSelection = State->FinalRow0; else State->CurrentSelection = State->InitialRow1; if (State->CurrentSelection < 0) State->CurrentSelection = 0; break; case SCROLL_FIRST: if (State->CurrentSelection > 0) { State->PaintAll = TRUE; State->CurrentSelection = 0; } break; case SCROLL_PAGE_DOWN: if (State->CurrentSelection < State->FinalRow0) { State->CurrentSelection += State->MaxVisible; if (State->CurrentSelection > State->FinalRow0) State->CurrentSelection = State->FinalRow0; } else if (State->CurrentSelection == State->FinalRow0) { State->CurrentSelection++; } else { State->CurrentSelection = State->MaxIndex; } if (State->CurrentSelection > State->MaxIndex) State->CurrentSelection = State->MaxIndex; break; case SCROLL_LAST: if (State->CurrentSelection < State->MaxIndex) { State->PaintAll = TRUE; State->CurrentSelection = State->MaxIndex; } break; case SCROLL_NONE: break; } if (State->ScrollMode == SCROLL_MODE_TEXT) AdjustScrollState(State); if (!State->PaintAll && State->CurrentSelection != State->PreviousSelection) State->PaintSelection = TRUE; State->LastVisible = State->FirstVisible + State->MaxVisible - 1; } // static VOID UpdateScroll() // // menu helper functions // VOID AddMenuInfoLine(IN REFIT_MENU_SCREEN *Screen, IN CHAR16 *InfoLine) { AddListElement((VOID ***) &(Screen->InfoLines), &(Screen->InfoLineCount), InfoLine); } VOID AddMenuEntry(IN REFIT_MENU_SCREEN *Screen, IN REFIT_MENU_ENTRY *Entry) { AddListElement((VOID ***) &(Screen->Entries), &(Screen->EntryCount), Entry); } static INTN FindMenuShortcutEntry(IN REFIT_MENU_SCREEN *Screen, IN CHAR16 *Defaults) { UINTN i, j = 0, ShortcutLength; CHAR16 *Shortcut; while ((Shortcut = FindCommaDelimited(Defaults, j)) != NULL) { ShortcutLength = StrLen(Shortcut); if (ShortcutLength == 1) { if (Shortcut[0] >= 'a' && Shortcut[0] <= 'z') Shortcut[0] -= ('a' - 'A'); if (Shortcut[0]) { for (i = 0; i < Screen->EntryCount; i++) { if (Screen->Entries[i]->ShortcutDigit == Shortcut[0] || Screen->Entries[i]->ShortcutLetter == Shortcut[0]) { MyFreePool(Shortcut); return i; } // if } // for } // if } else if (ShortcutLength > 1) { for (i = 0; i < Screen->EntryCount; i++) { if (StriSubCmp(Shortcut, Screen->Entries[i]->Title)) { MyFreePool(Shortcut); return i; } // if } // for } MyFreePool(Shortcut); j++; } // while() return -1; } // static INTN FindMenuShortcutEntry() // Identify the end of row 0 and the beginning of row 1; store the results in the // appropriate fields in State. Also reduce MaxVisible if that value is greater // than the total number of row-0 tags and if we're in an icon-based screen static VOID IdentifyRows(IN SCROLL_STATE *State, IN REFIT_MENU_SCREEN *Screen) { UINTN i; State->FinalRow0 = 0; State->InitialRow1 = State->MaxIndex; for (i = 0; i <= State->MaxIndex; i++) { if (Screen->Entries[i]->Row == 0) { State->FinalRow0 = i; } else if ((Screen->Entries[i]->Row == 1) && (State->InitialRow1 > i)) { State->InitialRow1 = i; } // if/else } // for if ((State->ScrollMode == SCROLL_MODE_ICONS) && (State->MaxVisible > (State->FinalRow0 + 1))) State->MaxVisible = State->FinalRow0 + 1; } // static VOID IdentifyRows() // Blank the screen, wait for a keypress or pointer event, and restore banner/background. // Screen may still require redrawing of text and icons on return. // TODO: Support more sophisticated screen savers, such as power-saving // mode and dynamic images. static VOID SaveScreen(VOID) { EG_PIXEL Black = { 0x0, 0x0, 0x0, 0 }; egClearScreen(&Black); WaitForInput(0); if (AllowGraphicsMode) SwitchToGraphicsAndClear(); ReadAllKeyStrokes(); } // VOID SaveScreen() // // generic menu function // static UINTN RunGenericMenu(IN REFIT_MENU_SCREEN *Screen, IN MENU_STYLE_FUNC StyleFunc, IN OUT INTN *DefaultEntryIndex, OUT REFIT_MENU_ENTRY **ChosenEntry) { SCROLL_STATE State; EFI_STATUS Status; EFI_INPUT_KEY key; INTN ShortcutEntry; BOOLEAN HaveTimeout = FALSE; BOOLEAN WaitForRelease = FALSE; UINTN TimeoutCountdown = 0; INTN PreviousTime = -1, CurrentTime, TimeSinceKeystroke = 0; CHAR16 TimeoutMessage[256]; CHAR16 KeyAsString[2]; UINTN MenuExit; EFI_STATUS PointerStatus = EFI_NOT_READY; UINTN Item; if (Screen->TimeoutSeconds > 0) { HaveTimeout = TRUE; TimeoutCountdown = Screen->TimeoutSeconds * 10; } MenuExit = 0; StyleFunc(Screen, &State, MENU_FUNCTION_INIT, NULL); IdentifyRows(&State, Screen); // override the starting selection with the default index, if any if (*DefaultEntryIndex >= 0 && *DefaultEntryIndex <= State.MaxIndex) { State.CurrentSelection = *DefaultEntryIndex; if (GlobalConfig.ScreensaverTime != -1) UpdateScroll(&State, SCROLL_NONE); } if (Screen->TimeoutSeconds == -1) { Status = refit_call2_wrapper(ST->ConIn->ReadKeyStroke, ST->ConIn, &key); if (Status == EFI_NOT_READY) { MenuExit = MENU_EXIT_TIMEOUT; } else { KeyAsString[0] = key.UnicodeChar; KeyAsString[1] = 0; ShortcutEntry = FindMenuShortcutEntry(Screen, KeyAsString); if (ShortcutEntry >= 0) { State.CurrentSelection = ShortcutEntry; MenuExit = MENU_EXIT_ENTER; } else { WaitForRelease = TRUE; HaveTimeout = FALSE; } } } if (GlobalConfig.ScreensaverTime != -1) State.PaintAll = TRUE; while (!MenuExit) { // update the screen pdClear(); if (State.PaintAll && (GlobalConfig.ScreensaverTime != -1)) { StyleFunc(Screen, &State, MENU_FUNCTION_PAINT_ALL, NULL); State.PaintAll = FALSE; } else if (State.PaintSelection) { StyleFunc(Screen, &State, MENU_FUNCTION_PAINT_SELECTION, NULL); State.PaintSelection = FALSE; } if(PointerActive) { pdDraw(); } if (WaitForRelease) { Status = refit_call2_wrapper(ST->ConIn->ReadKeyStroke, ST->ConIn, &key); if (Status == EFI_SUCCESS) { // reset, because otherwise the buffer gets queued with keystrokes refit_call2_wrapper(ST->ConIn->Reset, ST->ConIn, FALSE); refit_call1_wrapper(BS->Stall, 100000); } else { WaitForRelease = FALSE; refit_call2_wrapper(ST->ConIn->Reset, ST->ConIn, TRUE); } continue; } if (HaveTimeout) { CurrentTime = (TimeoutCountdown + 5) / 10; if (CurrentTime != PreviousTime) { SPrint(TimeoutMessage, 255, L"%s in %d seconds", Screen->TimeoutText, CurrentTime); if (GlobalConfig.ScreensaverTime != -1) StyleFunc(Screen, &State, MENU_FUNCTION_PAINT_TIMEOUT, TimeoutMessage); PreviousTime = CurrentTime; } } <<<<<<< HEAD // read key press or touch event (and wait for them if applicable) if (TouchEnabled) { TouchStatus = refit_call2_wrapper(TouchProtocol->GetState, TouchProtocol, &TouchState); } Status = refit_call2_wrapper(ST->ConIn->ReadKeyStroke, ST->ConIn, &key); if (Status == EFI_SUCCESS) { TouchActive = FALSE; ======= // read key press or pointer event (and wait for them if applicable) if(PointerEnabled) { PointerStatus = pdUpdateState(); } Status = refit_call2_wrapper(ST->ConIn->ReadKeyStroke, ST->ConIn, &key); if(Status == EFI_SUCCESS) { PointerActive = FALSE; DrawSelection = TRUE; >>>>>>> d63734581c19715b3dc13ab89c520def8d5c4566 TimeSinceKeystroke = 0; } else if (PointerStatus == EFI_SUCCESS) { if (StyleFunc != MainMenuStyle && pdGetState().Press) { // prevent user from getting stuck on submenus // (the only one currently reachable without a keyboard is the about screen) MenuExit = MENU_EXIT_ENTER; break; } PointerActive = TRUE; TimeSinceKeystroke = 0; } else { if (HaveTimeout && TimeoutCountdown == 0) { // timeout expired MenuExit = MENU_EXIT_TIMEOUT; break; } else if (HaveTimeout || GlobalConfig.ScreensaverTime > 0) { UINTN ElapsCount = 1; UINTN Input = WaitForInput(1000); // 1s Timeout if(Input == INPUT_KEY || Input == INPUT_POINTER) { continue; } else if(Input == INPUT_TIMEOUT) { ElapsCount = 10; // always counted as 1s to end of the timeout } TimeSinceKeystroke += ElapsCount; if(HaveTimeout) { TimeoutCountdown = TimeoutCountdown <= ElapsCount ? 0 : TimeoutCountdown - ElapsCount; } else if (GlobalConfig.ScreensaverTime > 0 && TimeSinceKeystroke > (GlobalConfig.ScreensaverTime * 10)) { SaveScreen(); State.PaintAll = TRUE; TimeSinceKeystroke = 0; } // if } else { WaitForInput(0); } continue; } // if/else !read keystroke if (HaveTimeout) { // the user pressed a key, cancel the timeout StyleFunc(Screen, &State, MENU_FUNCTION_PAINT_TIMEOUT, L""); HaveTimeout = FALSE; if (GlobalConfig.ScreensaverTime == -1) { // cancel start-with-blank-screen coding GlobalConfig.ScreensaverTime = 0; if (!GlobalConfig.TextOnly) BltClearScreen(TRUE); } } if(!PointerActive) { // react to key press switch (key.ScanCode) { case SCAN_UP: UpdateScroll(&State, SCROLL_LINE_UP); break; case SCAN_LEFT: UpdateScroll(&State, SCROLL_LINE_LEFT); break; case SCAN_DOWN: UpdateScroll(&State, SCROLL_LINE_DOWN); break; case SCAN_RIGHT: UpdateScroll(&State, SCROLL_LINE_RIGHT); break; case SCAN_HOME: UpdateScroll(&State, SCROLL_FIRST); break; case SCAN_END: UpdateScroll(&State, SCROLL_LAST); break; case SCAN_PAGE_UP: UpdateScroll(&State, SCROLL_PAGE_UP); break; case SCAN_PAGE_DOWN: UpdateScroll(&State, SCROLL_PAGE_DOWN); break; case SCAN_ESC: MenuExit = MENU_EXIT_ESCAPE; break; case SCAN_INSERT: case SCAN_F2: MenuExit = MENU_EXIT_DETAILS; break; case SCAN_DELETE: MenuExit = MENU_EXIT_HIDE; break; case SCAN_F10: egScreenShot(); break; case 0x0016: // F12 if (EjectMedia()) MenuExit = MENU_EXIT_ESCAPE; break; } switch (key.UnicodeChar) { case CHAR_LINEFEED: case CHAR_CARRIAGE_RETURN: case ' ': MenuExit = MENU_EXIT_ENTER; break; case CHAR_BACKSPACE: MenuExit = MENU_EXIT_ESCAPE; break; case '+': case CHAR_TAB: MenuExit = MENU_EXIT_DETAILS; break; case 'd': MenuExit = MENU_EXIT_HIDE; break; default: KeyAsString[0] = key.UnicodeChar; KeyAsString[1] = 0; ShortcutEntry = FindMenuShortcutEntry(Screen, KeyAsString); if (ShortcutEntry >= 0) { State.CurrentSelection = ShortcutEntry; MenuExit = MENU_EXIT_ENTER; } break; } } else { //react to pointer event if (StyleFunc != MainMenuStyle) { continue; // nothing to find on submenus } State.PreviousSelection = State.CurrentSelection; POINTER_STATE PointerState = pdGetState(); Item = FindMainMenuItem(Screen, &State, PointerState.X, PointerState.Y); switch (Item) { case POINTER_NO_ITEM: if(DrawSelection) { DrawSelection = FALSE; State.PaintSelection = TRUE; } break; case POINTER_LEFT_ARROW: if(PointerState.Press) { UpdateScroll(&State, SCROLL_PAGE_UP); } if(DrawSelection) { DrawSelection = FALSE; State.PaintSelection = TRUE; } break; case POINTER_RIGHT_ARROW: if(PointerState.Press) { UpdateScroll(&State, SCROLL_PAGE_DOWN); } if(DrawSelection) { DrawSelection = FALSE; State.PaintSelection = TRUE; } break; default: if (!DrawSelection || Item != State.CurrentSelection) { DrawSelection = TRUE; State.PaintSelection = TRUE; State.CurrentSelection = Item; } if(PointerState.Press) { MenuExit = MENU_EXIT_ENTER; } break; } } } pdClear(); StyleFunc(Screen, &State, MENU_FUNCTION_CLEANUP, NULL); if (ChosenEntry) *ChosenEntry = Screen->Entries[State.CurrentSelection]; *DefaultEntryIndex = State.CurrentSelection; return MenuExit; } /* static UINTN RunGenericMenu() */ // // text-mode generic style // // Show information lines in text mode. static VOID ShowTextInfoLines(IN REFIT_MENU_SCREEN *Screen) { INTN i; BeginTextScreen(Screen->Title); if (Screen->InfoLineCount > 0) { refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BASIC); for (i = 0; i < (INTN)Screen->InfoLineCount; i++) { refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 3, 4 + i); refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, Screen->InfoLines[i]); } } } // VOID ShowTextInfoLines() // Do most of the work for text-based menus.... static VOID TextMenuStyle(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, IN UINTN Function, IN CHAR16 *ParamText) { INTN i; UINTN MenuWidth, ItemWidth, MenuHeight; static UINTN MenuPosY; static CHAR16 **DisplayStrings; CHAR16 TimeoutMessage[256]; State->ScrollMode = SCROLL_MODE_TEXT; switch (Function) { case MENU_FUNCTION_INIT: // vertical layout MenuPosY = 4; if (Screen->InfoLineCount > 0) MenuPosY += Screen->InfoLineCount + 1; MenuHeight = ConHeight - MenuPosY - 3; if (Screen->TimeoutSeconds > 0) MenuHeight -= 2; InitScroll(State, Screen->EntryCount, MenuHeight); // determine width of the menu MenuWidth = 20; // minimum for (i = 0; i <= State->MaxIndex; i++) { ItemWidth = StrLen(Screen->Entries[i]->Title); if (MenuWidth < ItemWidth) MenuWidth = ItemWidth; } MenuWidth += 2; if (MenuWidth > ConWidth - 3) MenuWidth = ConWidth - 3; // prepare strings for display DisplayStrings = AllocatePool(sizeof(CHAR16 *) * Screen->EntryCount); for (i = 0; i <= State->MaxIndex; i++) { // Note: Theoretically, SPrint() is a cleaner way to do this; but the // description of the StrSize parameter to SPrint implies it's measured // in characters, but in practice both TianoCore and GNU-EFI seem to // use bytes instead, resulting in truncated displays. I could just // double the size of the StrSize parameter, but that seems unsafe in // case a future library change starts treating this as characters, so // I'm doing it the hard way in this instance. // TODO: Review the above and possibly change other uses of SPrint() DisplayStrings[i] = AllocateZeroPool(2 * sizeof(CHAR16)); DisplayStrings[i][0] = L' '; MergeStrings(&DisplayStrings[i], Screen->Entries[i]->Title, 0); if (StrLen(DisplayStrings[i]) > MenuWidth) DisplayStrings[i][MenuWidth - 1] = 0; // TODO: use more elaborate techniques for shortening too long strings (ellipses in the middle) // TODO: account for double-width characters } // for break; case MENU_FUNCTION_CLEANUP: // release temporary memory for (i = 0; i <= State->MaxIndex; i++) MyFreePool(DisplayStrings[i]); MyFreePool(DisplayStrings); break; case MENU_FUNCTION_PAINT_ALL: // paint the whole screen (initially and after scrolling) ShowTextInfoLines(Screen); for (i = 0; i <= State->MaxIndex; i++) { if (i >= State->FirstVisible && i <= State->LastVisible) { refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 2, MenuPosY + (i - State->FirstVisible)); if (i == State->CurrentSelection) refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_CHOICE_CURRENT); else refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_CHOICE_BASIC); refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, DisplayStrings[i]); } } // scrolling indicators refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_SCROLLARROW); refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 0, MenuPosY); if (State->FirstVisible > 0) refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, ArrowUp); else refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, L" "); refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 0, MenuPosY + State->MaxVisible); if (State->LastVisible < State->MaxIndex) refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, ArrowDown); else refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, L" "); if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_HINTS)) { if (Screen->Hint1 != NULL) { refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 0, ConHeight - 2); refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, Screen->Hint1); } if (Screen->Hint2 != NULL) { refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 0, ConHeight - 1); refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, Screen->Hint2); } } break; case MENU_FUNCTION_PAINT_SELECTION: // redraw selection cursor refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 2, MenuPosY + (State->PreviousSelection - State->FirstVisible)); refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_CHOICE_BASIC); refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, DisplayStrings[State->PreviousSelection]); refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 2, MenuPosY + (State->CurrentSelection - State->FirstVisible)); refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_CHOICE_CURRENT); refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, DisplayStrings[State->CurrentSelection]); break; case MENU_FUNCTION_PAINT_TIMEOUT: if (ParamText[0] == 0) { // clear message refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BASIC); refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 0, ConHeight - 3); refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, BlankLine + 1); } else { // paint or update message refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_ERROR); refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 3, ConHeight - 3); SPrint(TimeoutMessage, 255, L"%s ", ParamText); refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, TimeoutMessage); } break; } } // // graphical generic style // inline static UINTN TextLineHeight(VOID) { return egGetFontHeight() + TEXT_YMARGIN * 2; } // UINTN TextLineHeight() // // Display a submenu // // Display text with a solid background (MenuBackgroundPixel or SelectionBackgroundPixel). // Indents text by one character and placed TEXT_YMARGIN pixels down from the // specified XPos and YPos locations. static VOID DrawText(IN CHAR16 *Text, IN BOOLEAN Selected, IN UINTN FieldWidth, IN UINTN XPos, IN UINTN YPos) { EG_IMAGE *TextBuffer; EG_PIXEL Bg; TextBuffer = egCreateImage(FieldWidth, TextLineHeight(), FALSE); egFillImage(TextBuffer, &MenuBackgroundPixel); Bg = MenuBackgroundPixel; if (Selected) { // draw selection bar background egFillImageArea(TextBuffer, 0, 0, FieldWidth, TextBuffer->Height, &SelectionBackgroundPixel); Bg = SelectionBackgroundPixel; } // render the text egRenderText(Text, TextBuffer, egGetFontCellWidth(), TEXT_YMARGIN, (Bg.r + Bg.g + Bg.b) / 3); egDrawImageWithTransparency(TextBuffer, NULL, XPos, YPos, TextBuffer->Width, TextBuffer->Height); // BltImage(TextBuffer, XPos, YPos); } // Finds the average brightness of the input Image. // NOTE: Passing an Image that covers the whole screen can strain the // capacity of a UINTN on a 32-bit system with a very large display. // Using UINT64 instead is unworkable, since the code won't compile // on a 32-bit system. As the intended use for this function is to handle // a single text string's background, this shouldn't be a problem, but it // may need addressing if it's applied more broadly.... static UINT8 AverageBrightness(EG_IMAGE *Image) { UINTN i; UINTN Sum = 0; if ((Image != NULL) && ((Image->Width * Image->Height) != 0)) { for (i = 0; i < (Image->Width * Image->Height); i++) { Sum += (Image->PixelData[i].r + Image->PixelData[i].g + Image->PixelData[i].b); } Sum /= (Image->Width * Image->Height * 3); } // if return (UINT8) Sum; } // UINT8 AverageBrightness() // Display text against the screen's background image. Special case: If Text is NULL // or 0-length, clear the line. Does NOT indent the text or reposition it relative // to the specified XPos and YPos values. static VOID DrawTextWithTransparency(IN CHAR16 *Text, IN UINTN XPos, IN UINTN YPos) { UINTN TextWidth; EG_IMAGE *TextBuffer = NULL; if (Text == NULL) Text = L""; egMeasureText(Text, &TextWidth, NULL); if (TextWidth == 0) { TextWidth = UGAWidth; XPos = 0; } TextBuffer = egCropImage(GlobalConfig.ScreenBackground, XPos, YPos, TextWidth, TextLineHeight()); if (TextBuffer == NULL) return; // render the text egRenderText(Text, TextBuffer, 0, 0, AverageBrightness(TextBuffer)); egDrawImageWithTransparency(TextBuffer, NULL, XPos, YPos, TextBuffer->Width, TextBuffer->Height); egFreeImage(TextBuffer); } // Compute the size & position of the window that will hold a subscreen's information. static VOID ComputeSubScreenWindowSize(REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, UINTN *XPos, UINTN *YPos, UINTN *Width, UINTN *Height, UINTN *LineWidth) { UINTN i, ItemWidth, HintTop, BannerBottomEdge, TitleWidth; UINTN FontCellWidth = egGetFontCellWidth(); UINTN FontCellHeight = egGetFontHeight(); *Width = 20; *Height = 5; TitleWidth = egComputeTextWidth(Screen->Title); for (i = 0; i < Screen->InfoLineCount; i++) { ItemWidth = StrLen(Screen->InfoLines[i]); if (*Width < ItemWidth) { *Width = ItemWidth; } (*Height)++; } for (i = 0; i <= State->MaxIndex; i++) { ItemWidth = StrLen(Screen->Entries[i]->Title); if (*Width < ItemWidth) { *Width = ItemWidth; } (*Height)++; } *Width = (*Width + 2) * FontCellWidth; *LineWidth = *Width; if (Screen->TitleImage) *Width += (Screen->TitleImage->Width + TITLEICON_SPACING * 2 + FontCellWidth); else *Width += FontCellWidth; if (*Width < TitleWidth) *Width = TitleWidth + 2 * FontCellWidth; // Keep it within the bounds of the screen, or 2/3 of the screen's width // for screens over 800 pixels wide if (*Width > UGAWidth) *Width = UGAWidth; *XPos = (UGAWidth - *Width) / 2; HintTop = UGAHeight - (FontCellHeight * 3); // top of hint text *Height *= TextLineHeight(); if (Screen->TitleImage && (*Height < (Screen->TitleImage->Height + TextLineHeight() * 4))) *Height = Screen->TitleImage->Height + TextLineHeight() * 4; if (GlobalConfig.BannerBottomEdge >= HintTop) { // probably a full-screen image; treat it as an empty banner BannerBottomEdge = 0; } else { BannerBottomEdge = GlobalConfig.BannerBottomEdge; } if (*Height > (HintTop - BannerBottomEdge - FontCellHeight * 2)) { BannerBottomEdge = 0; } if (*Height > (HintTop - BannerBottomEdge - FontCellHeight * 2)) { // TODO: Implement scrolling in text screen. *Height = (HintTop - BannerBottomEdge - FontCellHeight * 2); } *YPos = ((UGAHeight - *Height) / 2); if (*YPos < BannerBottomEdge) *YPos = BannerBottomEdge + FontCellHeight + (HintTop - BannerBottomEdge - *Height) / 2; } // VOID ComputeSubScreenWindowSize() // Displays sub-menus static VOID GraphicsMenuStyle(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, IN UINTN Function, IN CHAR16 *ParamText) { INTN i; UINTN ItemWidth; static UINTN LineWidth, MenuWidth, MenuHeight, EntriesPosX, TitlePosX, EntriesPosY, TimeoutPosY, CharWidth; EG_IMAGE *Window; EG_PIXEL *BackgroundPixel = &(GlobalConfig.ScreenBackground->PixelData[0]); CharWidth = egGetFontCellWidth(); State->ScrollMode = SCROLL_MODE_TEXT; switch (Function) { case MENU_FUNCTION_INIT: InitScroll(State, Screen->EntryCount, 0); ComputeSubScreenWindowSize(Screen, State, &EntriesPosX, &EntriesPosY, &MenuWidth, &MenuHeight, &LineWidth); TimeoutPosY = EntriesPosY + (Screen->EntryCount + 1) * TextLineHeight(); // initial painting SwitchToGraphicsAndClear(); Window = egCreateFilledImage(MenuWidth, MenuHeight, FALSE, BackgroundPixel); egDrawImage(Window, EntriesPosX, EntriesPosY); ItemWidth = egComputeTextWidth(Screen->Title); if (MenuWidth > ItemWidth) { TitlePosX = EntriesPosX + (MenuWidth - ItemWidth) / 2 - CharWidth; } else { TitlePosX = EntriesPosX; if (CharWidth > 0) { i = MenuWidth / CharWidth - 2; if (i > 0) Screen->Title[i] = 0; } // if } // if/else break; case MENU_FUNCTION_CLEANUP: // nothing to do break; case MENU_FUNCTION_PAINT_ALL: ComputeSubScreenWindowSize(Screen, State, &EntriesPosX, &EntriesPosY, &MenuWidth, &MenuHeight, &LineWidth); DrawText(Screen->Title, FALSE, (StrLen(Screen->Title) + 2) * CharWidth, TitlePosX, EntriesPosY += TextLineHeight()); if (Screen->TitleImage) { BltImageAlpha(Screen->TitleImage, EntriesPosX + TITLEICON_SPACING, EntriesPosY + TextLineHeight() * 2, BackgroundPixel); EntriesPosX += (Screen->TitleImage->Width + TITLEICON_SPACING * 2); } EntriesPosY += (TextLineHeight() * 2); if (Screen->InfoLineCount > 0) { for (i = 0; i < (INTN)Screen->InfoLineCount; i++) { DrawText(Screen->InfoLines[i], FALSE, LineWidth, EntriesPosX, EntriesPosY); EntriesPosY += TextLineHeight(); } EntriesPosY += TextLineHeight(); // also add a blank line } for (i = 0; i <= State->MaxIndex; i++) { DrawText(Screen->Entries[i]->Title, (i == State->CurrentSelection), LineWidth, EntriesPosX, EntriesPosY + i * TextLineHeight()); } if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_HINTS)) { if ((Screen->Hint1 != NULL) && (StrLen(Screen->Hint1) > 0)) DrawTextWithTransparency(Screen->Hint1, (UGAWidth - egComputeTextWidth(Screen->Hint1)) / 2, UGAHeight - (egGetFontHeight() * 3)); if ((Screen->Hint2 != NULL) && (StrLen(Screen->Hint2) > 0)) DrawTextWithTransparency(Screen->Hint2, (UGAWidth - egComputeTextWidth(Screen->Hint2)) / 2, UGAHeight - (egGetFontHeight() * 2)); } // if break; case MENU_FUNCTION_PAINT_SELECTION: // redraw selection cursor DrawText(Screen->Entries[State->PreviousSelection]->Title, FALSE, LineWidth, EntriesPosX, EntriesPosY + State->PreviousSelection * TextLineHeight()); DrawText(Screen->Entries[State->CurrentSelection]->Title, TRUE, LineWidth, EntriesPosX, EntriesPosY + State->CurrentSelection * TextLineHeight()); break; case MENU_FUNCTION_PAINT_TIMEOUT: DrawText(ParamText, FALSE, LineWidth, EntriesPosX, TimeoutPosY); break; } } // static VOID GraphicsMenuStyle() // // graphical main menu style // static VOID DrawMainMenuEntry(REFIT_MENU_ENTRY *Entry, BOOLEAN selected, UINTN XPos, UINTN YPos) { EG_IMAGE *Background; // if using pointer, don't draw selection image when not hovering if (selected && DrawSelection) { Background = egCropImage(GlobalConfig.ScreenBackground, XPos, YPos, SelectionImages[Entry->Row]->Width, SelectionImages[Entry->Row]->Height); egComposeImage(Background, SelectionImages[Entry->Row], 0, 0); BltImageCompositeBadge(Background, Entry->Image, Entry->BadgeImage, XPos, YPos); } else { // Image not selected; copy background egDrawImageWithTransparency(Entry->Image, Entry->BadgeImage, XPos, YPos, SelectionImages[Entry->Row]->Width, SelectionImages[Entry->Row]->Height); } // if/else } // VOID DrawMainMenuEntry() static VOID PaintAll(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, UINTN *itemPosX, UINTN row0PosY, UINTN row1PosY, UINTN textPosY) { INTN i; if (Screen->Entries[State->CurrentSelection]->Row == 0) AdjustScrollState(State); for (i = State->FirstVisible; i <= State->MaxIndex; i++) { if (Screen->Entries[i]->Row == 0) { if (i <= State->LastVisible) { DrawMainMenuEntry(Screen->Entries[i], (i == State->CurrentSelection) ? TRUE : FALSE, itemPosX[i - State->FirstVisible], row0PosY); } // if } else { DrawMainMenuEntry(Screen->Entries[i], (i == State->CurrentSelection) ? TRUE : FALSE, itemPosX[i], row1PosY); } } if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_LABEL) && (!PointerActive || (PointerActive && DrawSelection))) { DrawTextWithTransparency(L"", 0, textPosY); DrawTextWithTransparency(Screen->Entries[State->CurrentSelection]->Title, (UGAWidth - egComputeTextWidth(Screen->Entries[State->CurrentSelection]->Title)) >> 1, textPosY); } else { DrawTextWithTransparency(L"", 0, textPosY); } if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_HINTS)) { DrawTextWithTransparency(Screen->Hint1, (UGAWidth - egComputeTextWidth(Screen->Hint1)) / 2, UGAHeight - (egGetFontHeight() * 3)); DrawTextWithTransparency(Screen->Hint2, (UGAWidth - egComputeTextWidth(Screen->Hint2)) / 2, UGAHeight - (egGetFontHeight() * 2)); } // if } // static VOID PaintAll() // Move the selection to State->CurrentSelection, adjusting icon row if necessary... static VOID PaintSelection(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, UINTN *itemPosX, UINTN row0PosY, UINTN row1PosY, UINTN textPosY) { UINTN XSelectPrev, XSelectCur, YPosPrev, YPosCur; if (((State->CurrentSelection <= State->LastVisible) && (State->CurrentSelection >= State->FirstVisible)) || (State->CurrentSelection >= State->InitialRow1) ) { if (Screen->Entries[State->PreviousSelection]->Row == 0) { XSelectPrev = State->PreviousSelection - State->FirstVisible; YPosPrev = row0PosY; } else { XSelectPrev = State->PreviousSelection; YPosPrev = row1PosY; } // if/else if (Screen->Entries[State->CurrentSelection]->Row == 0) { XSelectCur = State->CurrentSelection - State->FirstVisible; YPosCur = row0PosY; } else { XSelectCur = State->CurrentSelection; YPosCur = row1PosY; } // if/else DrawMainMenuEntry(Screen->Entries[State->PreviousSelection], FALSE, itemPosX[XSelectPrev], YPosPrev); DrawMainMenuEntry(Screen->Entries[State->CurrentSelection], TRUE, itemPosX[XSelectCur], YPosCur); if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_LABEL) && (!PointerActive || (PointerActive && DrawSelection))) { DrawTextWithTransparency(L"", 0, textPosY); DrawTextWithTransparency(Screen->Entries[State->CurrentSelection]->Title, (UGAWidth - egComputeTextWidth(Screen->Entries[State->CurrentSelection]->Title)) >> 1, textPosY); } else { DrawTextWithTransparency(L"", 0, textPosY); } } else { // Current selection not visible; must redraw the menu.... MainMenuStyle(Screen, State, MENU_FUNCTION_PAINT_ALL, NULL); } } // static VOID MoveSelection(VOID) // Display a 48x48 icon at the specified location. Uses the image specified by // ExternalFilename if it's available, or BuiltInImage if it's not. The // Y position is specified as the center value, and so is adjusted by half // the icon's height. The X position is set along the icon's left // edge if Alignment == ALIGN_LEFT, and along the right edge if // Alignment == ALIGN_RIGHT static VOID PaintIcon(IN EG_EMBEDDED_IMAGE *BuiltInIcon, IN CHAR16 *ExternalFilename, UINTN PosX, UINTN PosY, UINTN Alignment) { EG_IMAGE *Icon = NULL; Icon = egFindIcon(ExternalFilename, GlobalConfig.IconSizes[ICON_SIZE_SMALL]); if (Icon == NULL) Icon = egPrepareEmbeddedImage(BuiltInIcon, TRUE); if (Icon != NULL) { if (Alignment == ALIGN_RIGHT) PosX -= Icon->Width; egDrawImageWithTransparency(Icon, NULL, PosX, PosY - (Icon->Height / 2), Icon->Width, Icon->Height); } } // static VOID () UINTN ComputeRow0PosY(VOID) { return ((UGAHeight / 2) - TileSizes[0] / 2); } // UINTN ComputeRow0PosY() // Display (or erase) the arrow icons to the left and right of an icon's row, // as appropriate. static VOID PaintArrows(SCROLL_STATE *State, UINTN PosX, UINTN PosY, UINTN row0Loaders) { EG_IMAGE *TempImage; UINTN Width, Height, RightX, AdjPosY; // NOTE: Assume that left and right arrows are of the same size.... Width = egemb_arrow_left.Width; Height = egemb_arrow_left.Height; RightX = (UGAWidth + (TileSizes[0] + TILE_XSPACING) * State->MaxVisible) / 2 + TILE_XSPACING; AdjPosY = PosY - (Height / 2); // For PaintIcon() calls, the starting Y position is moved to the midpoint // of the surrounding row; PaintIcon() adjusts this back up by half the // icon's height to properly center it. if ((State->FirstVisible > 0) && (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_ARROWS))) { PaintIcon(&egemb_arrow_left, L"arrow_left", PosX, PosY, ALIGN_RIGHT); } else { TempImage = egCropImage(GlobalConfig.ScreenBackground, PosX - Width, AdjPosY, Width, Height); BltImage(TempImage, PosX - Width, AdjPosY); egFreeImage(TempImage); } // if/else if ((State->LastVisible < (row0Loaders - 1)) && (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_ARROWS))) { PaintIcon(&egemb_arrow_right, L"arrow_right", RightX, PosY, ALIGN_LEFT); } else { TempImage = egCropImage(GlobalConfig.ScreenBackground, RightX, AdjPosY, Width, Height); BltImage(TempImage, RightX, AdjPosY); egFreeImage(TempImage); } // if/else } // VOID PaintArrows() // Display main menu in graphics mode VOID MainMenuStyle(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, IN UINTN Function, IN CHAR16 *ParamText) { INTN i; static UINTN row0PosX, row0PosXRunning, row1PosY, row0Loaders; UINTN row0Count, row1Count, row1PosX, row1PosXRunning; static UINTN *itemPosX; static UINTN row0PosY, textPosY; State->ScrollMode = SCROLL_MODE_ICONS; switch (Function) { case MENU_FUNCTION_INIT: InitScroll(State, Screen->EntryCount, GlobalConfig.MaxTags); // layout row0Count = 0; row1Count = 0; row0Loaders = 0; for (i = 0; i <= State->MaxIndex; i++) { if (Screen->Entries[i]->Row == 1) { row1Count++; } else { row0Loaders++; if (row0Count < State->MaxVisible) row0Count++; } } row0PosX = (UGAWidth + TILE_XSPACING - (TileSizes[0] + TILE_XSPACING) * row0Count) >> 1; row0PosY = ComputeRow0PosY(); row1PosX = (UGAWidth + TILE_XSPACING - (TileSizes[1] + TILE_XSPACING) * row1Count) >> 1; row1PosY = row0PosY + TileSizes[0] + TILE_YSPACING; if (row1Count > 0) textPosY = row1PosY + TileSizes[1] + TILE_YSPACING; else textPosY = row1PosY; itemPosX = AllocatePool(sizeof(UINTN) * Screen->EntryCount); row0PosXRunning = row0PosX; row1PosXRunning = row1PosX; for (i = 0; i <= State->MaxIndex; i++) { if (Screen->Entries[i]->Row == 0) { itemPosX[i] = row0PosXRunning; row0PosXRunning += TileSizes[0] + TILE_XSPACING; } else { itemPosX[i] = row1PosXRunning; row1PosXRunning += TileSizes[1] + TILE_XSPACING; } } // initial painting InitSelection(); SwitchToGraphicsAndClear(); break; case MENU_FUNCTION_CLEANUP: MyFreePool(itemPosX); break; case MENU_FUNCTION_PAINT_ALL: PaintAll(Screen, State, itemPosX, row0PosY, row1PosY, textPosY); // For PaintArrows(), the starting Y position is moved to the midpoint // of the surrounding row; PaintIcon() adjusts this back up by half the // icon's height to properly center it. PaintArrows(State, row0PosX - TILE_XSPACING, row0PosY + (TileSizes[0] / 2), row0Loaders); break; case MENU_FUNCTION_PAINT_SELECTION: PaintSelection(Screen, State, itemPosX, row0PosY, row1PosY, textPosY); break; case MENU_FUNCTION_PAINT_TIMEOUT: if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_LABEL)) { DrawTextWithTransparency(L"", 0, textPosY + TextLineHeight()); DrawTextWithTransparency(ParamText, (UGAWidth - egComputeTextWidth(ParamText)) >> 1, textPosY + TextLineHeight()); } break; } } // VOID MainMenuStyle() // Determines the index of the main menu item at the given coordinates. UINTN FindMainMenuItem(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, IN UINTN PosX, IN UINTN PosY) { UINTN i; static UINTN row0PosX, row0PosXRunning, row1PosY, row0Loaders; UINTN row0Count, row1Count, row1PosX, row1PosXRunning; static UINTN *itemPosX; static UINTN row0PosY; <<<<<<< HEAD UINTN itemRow; row0Count = 0; row1Count = 0; row0Loaders = 0; for (i = 0; i <= State->MaxIndex; i++) { if (Screen->Entries[i]->Row == 1) { row1Count++; } else { row0Loaders++; if (row0Count < State->MaxVisible) row0Count++; } } row0PosX = (UGAWidth + TILE_XSPACING - (TileSizes[0] + TILE_XSPACING) * row0Count) >> 1; row0PosY = ComputeRow0PosY(); row1PosX = (UGAWidth + TILE_XSPACING - (TileSizes[1] + TILE_XSPACING) * row1Count) >> 1; row1PosY = row0PosY + TileSizes[0] + TILE_YSPACING; if (PosY >= row0PosY && PosY <= row0PosY + TileSizes[0]) { itemRow = 0; if (PosX <= row0PosX) { return TOUCH_LEFT_ARROW; } else if (PosX >= (UGAWidth - row0PosX)) { return TOUCH_RIGHT_ARROW; } } else if (PosY >= row1PosY && PosY <= row1PosY + TileSizes[1]) { itemRow = 1; } else { // Y coordinate is outside of either row return TOUCH_NO_ITEM; } UINTN ItemIndex = TOUCH_NO_ITEM; itemPosX = AllocatePool(sizeof(UINTN) * Screen->EntryCount); row0PosXRunning = row0PosX; row1PosXRunning = row1PosX; for (i = 0; i <= State->MaxIndex; i++) { if (Screen->Entries[i]->Row == 0) { itemPosX[i] = row0PosXRunning; row0PosXRunning += TileSizes[0] + TILE_XSPACING; } else { itemPosX[i] = row1PosXRunning; row1PosXRunning += TileSizes[1] + TILE_XSPACING; } } for (i = State->FirstVisible; i <= State->MaxIndex; i++) { if (Screen->Entries[i]->Row == 0 && itemRow == 0) { if (i <= State->LastVisible) { if(PosX >= itemPosX[i - State->FirstVisible] && PosX <= itemPosX[i - State->FirstVisible] + TileSizes[0]) { ItemIndex = i; break; } } // if } else if (Screen->Entries[i]->Row == 1 && itemRow == 1) { if (PosX >= itemPosX[i] && PosX <= itemPosX[i] + TileSizes[1]) { ItemIndex = i; break; } } } MyFreePool(itemPosX); return ItemIndex; ======= UINTN itemRow; row0Count = 0; row1Count = 0; row0Loaders = 0; for (i = 0; i <= State->MaxIndex; i++) { if (Screen->Entries[i]->Row == 1) { row1Count++; } else { row0Loaders++; if (row0Count < State->MaxVisible) row0Count++; } } row0PosX = (UGAWidth + TILE_XSPACING - (TileSizes[0] + TILE_XSPACING) * row0Count) >> 1; row0PosY = ComputeRow0PosY(); row1PosX = (UGAWidth + TILE_XSPACING - (TileSizes[1] + TILE_XSPACING) * row1Count) >> 1; row1PosY = row0PosY + TileSizes[0] + TILE_YSPACING; if(PosY >= row0PosY && PosY <= row0PosY + TileSizes[0]) { itemRow = 0; if(PosX <= row0PosX) { return POINTER_LEFT_ARROW; } else if(PosX >= (UGAWidth - row0PosX)) { return POINTER_RIGHT_ARROW; } } else if(PosY >= row1PosY && PosY <= row1PosY + TileSizes[1]) { itemRow = 1; } else { // Y coordinate is outside of either row return POINTER_NO_ITEM; } UINTN ItemIndex = POINTER_NO_ITEM; itemPosX = AllocatePool(sizeof(UINTN) * Screen->EntryCount); row0PosXRunning = row0PosX; row1PosXRunning = row1PosX; for (i = 0; i <= State->MaxIndex; i++) { if (Screen->Entries[i]->Row == 0) { itemPosX[i] = row0PosXRunning; row0PosXRunning += TileSizes[0] + TILE_XSPACING; } else { itemPosX[i] = row1PosXRunning; row1PosXRunning += TileSizes[1] + TILE_XSPACING; } } for (i = State->FirstVisible; i <= State->MaxIndex; i++) { if (Screen->Entries[i]->Row == 0 && itemRow == 0) { if (i <= State->LastVisible) { if(PosX >= itemPosX[i - State->FirstVisible] && PosX <= itemPosX[i - State->FirstVisible] + TileSizes[0]) { ItemIndex = i; break; } } // if } else if (Screen->Entries[i]->Row == 1 && itemRow == 1) { if(PosX >= itemPosX[i] && PosX <= itemPosX[i] + TileSizes[1]) { ItemIndex = i; break; } } } MyFreePool(itemPosX); return ItemIndex; >>>>>>> d63734581c19715b3dc13ab89c520def8d5c4566 } // VOID FindMainMenuItem() VOID GenerateWaitList() { UINTN PointerCount = pdCount(); WaitListLength = 2 + PointerCount; WaitList = AllocatePool(sizeof(EFI_EVENT) * WaitListLength); WaitList[0] = ST->ConIn->WaitForKey; UINTN Index; for(Index = 0; Index < PointerCount; Index++) { WaitList[Index + 1] = pdWaitEvent(Index); } } // VOID GenerateWaitList() UINTN WaitForInput(UINTN Timeout) { UINTN Index = INPUT_TIMEOUT; UINTN Length = WaitListLength; EFI_EVENT TimerEvent; EFI_STATUS Status; if(Timeout == 0) { Length--; } else { Status = refit_call5_wrapper(BS->CreateEvent, EVT_TIMER, 0, NULL, NULL, &TimerEvent); if(EFI_ERROR(Status)) { refit_call1_wrapper(BS->Stall, 100000); // Pause for 100 ms return INPUT_TIMER_ERROR; } else { Status = refit_call3_wrapper(BS->SetTimer, TimerEvent, TimerRelative, Timeout * 10000); WaitList[Length - 1] = TimerEvent; } } Status = refit_call3_wrapper(BS->WaitForEvent, Length, WaitList, &Index); refit_call1_wrapper(BS->CloseEvent, TimerEvent); if(EFI_ERROR(Status)) { refit_call1_wrapper(BS->Stall, 100000); // Pause for 100 ms return INPUT_TIMER_ERROR; } else if(Index == 0) { return INPUT_KEY; } else if(Index < Length - 1) { return INPUT_POINTER; } return INPUT_TIMEOUT; } // UINTN WaitForInput() // Enable the user to edit boot loader options. // Returns TRUE if the user exited with edited options; FALSE if the user // pressed Esc to terminate the edit. static BOOLEAN EditOptions(LOADER_ENTRY *MenuEntry) { UINTN x_max, y_max; CHAR16 *EditedOptions; BOOLEAN retval = FALSE; if (GlobalConfig.HideUIFlags & HIDEUI_FLAG_EDITOR) { return FALSE; } refit_call4_wrapper(ST->ConOut->QueryMode, ST->ConOut, ST->ConOut->Mode->Mode, &x_max, &y_max); if (!GlobalConfig.TextOnly) SwitchToText(TRUE); if (line_edit(MenuEntry->LoadOptions, &EditedOptions, x_max)) { MyFreePool(MenuEntry->LoadOptions); MenuEntry->LoadOptions = EditedOptions; retval = TRUE; } // if if (!GlobalConfig.TextOnly) SwitchToGraphics(); return retval; } // VOID EditOptions() // // user-callable dispatcher functions // VOID DisplaySimpleMessage(CHAR16* Title, CHAR16 *Message) { MENU_STYLE_FUNC Style = TextMenuStyle; INTN DefaultEntry = 0; REFIT_MENU_ENTRY *ChosenOption; REFIT_MENU_SCREEN HideItemMenu = { NULL, NULL, 0, NULL, 0, NULL, 0, NULL, L"Press Enter to return to main menu", L"" }; if (!Message) return; if (AllowGraphicsMode) Style = GraphicsMenuStyle; HideItemMenu.TitleImage = BuiltinIcon(BUILTIN_ICON_FUNC_ABOUT); HideItemMenu.Title = Title; AddMenuInfoLine(&HideItemMenu, Message); AddMenuEntry(&HideItemMenu, &MenuEntryReturn); RunGenericMenu(&HideItemMenu, Style, &DefaultEntry, &ChosenOption); } // VOID DisplaySimpleMessage() static BOOLEAN DeleteTagFromVar(CHAR16 *ToDelete, CHAR16 *TagList, CHAR16 *VarName) { UINTN i = 0; CHAR16 *OneElement, *NewList = NULL; BOOLEAN DeletedSomething = FALSE; EFI_STATUS Status; if ((ToDelete == NULL) || (TagList == NULL) || (VarName == NULL)) return FALSE; while ((OneElement = FindCommaDelimited(TagList, i++)) != NULL) { if (!MyStriCmp(OneElement, ToDelete)) { MergeStrings(&NewList, OneElement, L','); } else { DeletedSomething = TRUE; } } // while MyFreePool(OneElement); i = StrLen(NewList); if ((i > 0) && (NewList[i - 1] == L',')) { NewList[i - 1] = '\0'; i--; } // if if (DeletedSomething) { if (i == 0) { Status = EfivarSetRaw(&RefindGuid, VarName, (CHAR8 *) NewList, 0, TRUE); } else { Status = EfivarSetRaw(&RefindGuid, VarName, (CHAR8 *) NewList, i * 2 + 2, TRUE); } // if/else CheckError(Status, L"in DeleteTagFromVar()"); } // if MyFreePool(NewList); return DeletedSomething; } // BOOLEAN DeleteTagFromVar() // Present a menu that enables the user to delete hidden tags (that is, to // un-hide them). VOID ManageHiddenTags(VOID) { CHAR16 *AllTags = NULL, *HiddenTags, *HiddenTools, *HiddenLegacy, *OneElement = NULL; INTN DefaultEntry = 0; MENU_STYLE_FUNC Style = TextMenuStyle; REFIT_MENU_ENTRY *ChosenOption, *MenuEntryItem; REFIT_MENU_SCREEN HideItemMenu = { L"Manage Hidden Tags Menu", NULL, 0, NULL, 0, NULL, 0, NULL, L"Select an option and press Enter or", L"press Esc to return to main menu without changes" }; UINTN MenuExit, i = 0; HideItemMenu.TitleImage = BuiltinIcon(BUILTIN_ICON_FUNC_HIDDEN); if (AllowGraphicsMode) Style = GraphicsMenuStyle; HiddenTags = ReadHiddenTags(L"HiddenTags"); if (HiddenTags && (HiddenTags[0] != L'\0')) AllTags = StrDuplicate(HiddenTags); HiddenTools = ReadHiddenTags(L"HiddenTools"); if (HiddenTools && (HiddenTools[0] != L'\0')) MergeStrings(&AllTags, HiddenTools, L','); HiddenLegacy = ReadHiddenTags(L"HiddenLegacy"); if (HiddenLegacy && (HiddenLegacy[0] != L'\0')) MergeStrings(&AllTags, HiddenLegacy, L','); if ((AllTags) && (StrLen(AllTags) > 0)) { AddMenuInfoLine(&HideItemMenu, L"Select a tag and press Enter to restore it"); while ((OneElement = FindCommaDelimited(AllTags, i++)) != NULL) { MenuEntryItem = AllocateZeroPool(sizeof(REFIT_MENU_ENTRY)); MenuEntryItem->Title = StrDuplicate(OneElement); MenuEntryItem->Tag = TAG_RETURN; MenuEntryItem->Row = 1; AddMenuEntry(&HideItemMenu, MenuEntryItem); } // while MenuExit = RunGenericMenu(&HideItemMenu, Style, &DefaultEntry, &ChosenOption); if (MenuExit == MENU_EXIT_ENTER) { if (DeleteTagFromVar(ChosenOption->Title, HiddenTags, L"HiddenTags") || DeleteTagFromVar(ChosenOption->Title, HiddenTools, L"HiddenTools") || DeleteTagFromVar(ChosenOption->Title, HiddenLegacy, L"HiddenLegacy")) { RescanAll(TRUE); } // if } // if } else { DisplaySimpleMessage(L"Information", L"No hidden tags found"); } MyFreePool(AllTags); MyFreePool(HiddenTags); MyFreePool(HiddenTools); MyFreePool(HiddenLegacy); MyFreePool(OneElement); } // VOID ManageHiddenTags() CHAR16* ReadHiddenTags(CHAR16 *VarName) { CHAR8 *Buffer = NULL; UINTN Size; EFI_STATUS Status; Status = EfivarGetRaw(&RefindGuid, VarName, &Buffer, &Size); if ((Status != EFI_SUCCESS) && (Status != EFI_NOT_FOUND)) CheckError(Status, L"in ReadHiddenTags()"); if ((Status == EFI_SUCCESS) && (Size == 0)) { MyFreePool(Buffer); Buffer = NULL; } return (CHAR16 *) Buffer; } // CHAR16* ReadHiddenTags() static VOID AddToHiddenTags(CHAR16 *VarName, CHAR16 *Pathname) { CHAR16 *HiddenTags; EFI_STATUS Status; if (Pathname && (StrLen(Pathname) > 0)) { HiddenTags = ReadHiddenTags(VarName); MergeStrings(&HiddenTags, Pathname, L','); Status = EfivarSetRaw(&RefindGuid, VarName, (CHAR8 *) HiddenTags, StrLen(HiddenTags) * 2 + 2, TRUE); CheckError(Status, L"in AddToHiddenTags()"); MyFreePool(HiddenTags); } // if } // VOID AddToHiddenTags() static BOOLEAN HideEfiTag(LOADER_ENTRY *Loader, REFIT_MENU_SCREEN *HideItemMenu, CHAR16 *VarName) { REFIT_VOLUME *Volume = NULL; BOOLEAN TagHidden = FALSE; CHAR16 *Filename = NULL, *FullPath = NULL; MENU_STYLE_FUNC Style = TextMenuStyle; UINTN MenuExit; INTN DefaultEntry = 1; REFIT_MENU_ENTRY *ChosenOption; if (AllowGraphicsMode) Style = GraphicsMenuStyle; FindVolumeAndFilename(Loader->DevicePath, &Volume, &Filename); if (Volume->VolName && (StrLen(Volume->VolName) > 0)) { FullPath = StrDuplicate(Volume->VolName); } else if (Volume->PartName && (StrLen(Volume->PartName) > 0)) { FullPath = StrDuplicate(Volume->PartName); } MergeStrings(&FullPath, Filename, L':'); AddMenuInfoLine(HideItemMenu, PoolPrint(L"Really hide %s?", FullPath)); AddMenuEntry(HideItemMenu, &MenuEntryYes); AddMenuEntry(HideItemMenu, &MenuEntryNo); MenuExit = RunGenericMenu(HideItemMenu, Style, &DefaultEntry, &ChosenOption); if (MyStriCmp(ChosenOption->Title, L"Yes") && (MenuExit == MENU_EXIT_ENTER)) { MyFreePool(FullPath); FullPath = NULL; MergeStrings(&FullPath, GuidAsString(&Volume->PartGuid), L'\0'); MergeStrings(&FullPath, L":", L'\0'); MergeStrings(&FullPath, Filename, (Filename[0] == L'\\' ? L'\0' : L'\\')); AddToHiddenTags(VarName, FullPath); TagHidden = TRUE; } // if MyFreePool(Volume); MyFreePool(Filename); MyFreePool(FullPath); return TagHidden; } // BOOLEAN HideEfiTag() static BOOLEAN HideLegacyTag(LEGACY_ENTRY *LegacyLoader, REFIT_MENU_SCREEN *HideItemMenu) { MENU_STYLE_FUNC Style = TextMenuStyle; REFIT_MENU_ENTRY *ChosenOption; INTN DefaultEntry = 1; UINTN MenuExit; CHAR16 *Name = NULL; if (AllowGraphicsMode) Style = GraphicsMenuStyle; if ((GlobalConfig.LegacyType == LEGACY_TYPE_MAC) && LegacyLoader->me.Title) Name = StrDuplicate(LegacyLoader->me.Title); if ((GlobalConfig.LegacyType == LEGACY_TYPE_UEFI) && LegacyLoader->BdsOption && LegacyLoader->BdsOption->Description) Name = StrDuplicate(LegacyLoader->BdsOption->Description); if (!Name) Name = StrDuplicate(L"Legacy OS"); AddMenuInfoLine(HideItemMenu, PoolPrint(L"Really hide '%s'?", Name)); AddMenuEntry(HideItemMenu, &MenuEntryYes); AddMenuEntry(HideItemMenu, &MenuEntryNo); MenuExit = RunGenericMenu(HideItemMenu, Style, &DefaultEntry, &ChosenOption); if (MyStriCmp(ChosenOption->Title, L"Yes") && (MenuExit == MENU_EXIT_ENTER)) { AddToHiddenTags(L"HiddenLegacy", Name); } // if MyFreePool(Name); return TRUE; } // BOOLEAN HideLegacyTag() static VOID HideOSTag(REFIT_MENU_ENTRY *ChosenEntry) { LOADER_ENTRY *Loader = (LOADER_ENTRY *) ChosenEntry; LEGACY_ENTRY *LegacyLoader = (LEGACY_ENTRY *) ChosenEntry; REFIT_MENU_SCREEN HideItemMenu = { NULL, NULL, 0, NULL, 0, NULL, 0, NULL, L"Select an option and press Enter or", L"press Esc to return to main menu without changes" }; HideItemMenu.TitleImage = BuiltinIcon(BUILTIN_ICON_FUNC_HIDDEN); switch (ChosenEntry->Tag) { case TAG_LOADER: if (Loader->DiscoveryType == DISCOVERY_TYPE_AUTO) { HideItemMenu.Title = L"Hide EFI OS Tag"; if (HideEfiTag(Loader, &HideItemMenu, L"HiddenTags")) RescanAll(TRUE); } else { DisplaySimpleMessage(L"Cannot Hide Entry for Manual Boot Stanza", L"You must edit refind.conf to remove this entry."); } break; case TAG_LEGACY: case TAG_LEGACY_UEFI: HideItemMenu.Title = L"Hide Legacy OS Tag"; if (HideLegacyTag(LegacyLoader, &HideItemMenu)) RescanAll(TRUE); break; case TAG_ABOUT: case TAG_REBOOT: case TAG_SHUTDOWN: case TAG_EXIT: case TAG_FIRMWARE: case TAG_CSR_ROTATE: case TAG_HIDDEN: DisplaySimpleMessage(L"Unable to Comply", L"To hide an internal tool, edit the 'showtools' line in refind.conf"); break; case TAG_TOOL: HideItemMenu.Title = L"Hide Tool Tag"; if (HideEfiTag(Loader, &HideItemMenu, L"HiddenTools")) RescanAll(TRUE); break; } // switch() } // VOID HideOsTag() UINTN RunMenu(IN REFIT_MENU_SCREEN *Screen, OUT REFIT_MENU_ENTRY **ChosenEntry) { INTN DefaultEntry = -1; MENU_STYLE_FUNC Style = TextMenuStyle; if (AllowGraphicsMode) Style = GraphicsMenuStyle; return RunGenericMenu(Screen, Style, &DefaultEntry, ChosenEntry); } UINTN RunMainMenu(REFIT_MENU_SCREEN *Screen, CHAR16** DefaultSelection, REFIT_MENU_ENTRY **ChosenEntry) { MENU_STYLE_FUNC Style = TextMenuStyle; MENU_STYLE_FUNC MainStyle = TextMenuStyle; REFIT_MENU_ENTRY *TempChosenEntry; CHAR16 *MenuTitle; UINTN MenuExit = 0; INTN DefaultEntryIndex = -1; INTN DefaultSubmenuIndex = -1; TileSizes[0] = (GlobalConfig.IconSizes[ICON_SIZE_BIG] * 9) / 8; TileSizes[1] = (GlobalConfig.IconSizes[ICON_SIZE_SMALL] * 4) / 3; if ((DefaultSelection != NULL) && (*DefaultSelection != NULL)) { // Find a menu entry that includes *DefaultSelection as a substring DefaultEntryIndex = FindMenuShortcutEntry(Screen, *DefaultSelection); } if (AllowGraphicsMode) { Style = GraphicsMenuStyle; MainStyle = MainMenuStyle; PointerEnabled = PointerActive = pdAvailable(); DrawSelection = !PointerEnabled; } GenerateWaitList(); while (!MenuExit) { MenuExit = RunGenericMenu(Screen, MainStyle, &DefaultEntryIndex, &TempChosenEntry); Screen->TimeoutSeconds = 0; MenuTitle = StrDuplicate(TempChosenEntry->Title); if (MenuExit == MENU_EXIT_DETAILS) { if (TempChosenEntry->SubScreen != NULL) { MenuExit = RunGenericMenu(TempChosenEntry->SubScreen, Style, &DefaultSubmenuIndex, &TempChosenEntry); if (MenuExit == MENU_EXIT_ESCAPE || TempChosenEntry->Tag == TAG_RETURN) MenuExit = 0; if (MenuExit == MENU_EXIT_DETAILS) { if (!EditOptions((LOADER_ENTRY *) TempChosenEntry)) MenuExit = 0; } // if } else { // no sub-screen; ignore keypress MenuExit = 0; } } // Enter sub-screen if ((MenuExit == MENU_EXIT_HIDE) && (GlobalConfig.HiddenTags)) { HideOSTag(TempChosenEntry); MenuExit = 0; } // Hide launcher } FreePool(WaitList); WaitList = NULL; WaitListLength = 0; if (ChosenEntry) *ChosenEntry = TempChosenEntry; if (DefaultSelection) { MyFreePool(*DefaultSelection); *DefaultSelection = MenuTitle; } // if return MenuExit; } /* UINTN RunMainMenu() */ refind-0.11.4/refind/main.c.orig0000664000175000017500000031550513141071554016622 0ustar rodsmithrodsmith/* * refind/main.c * Main code for the boot menu * * Copyright (c) 2006-2010 Christoph Pfisterer * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * * Neither the name of Christoph Pfisterer nor the names of the * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Modifications copyright (c) 2012-2017 Roderick W. Smith * * Modifications distributed under the terms of the GNU General Public * License (GPL) version 3 (GPLv3), or (at your option) any later version. * */ /* * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "global.h" #include "config.h" #include "screen.h" #include "legacy.h" #include "lib.h" #include "icns.h" #include "menu.h" #include "pointer.h" #include "mok.h" #include "gpt.h" #include "apple.h" #include "mystrings.h" #include "security_policy.h" #include "driver_support.h" #include "../include/Handle.h" #include "../include/refit_call_wrapper.h" #include "../include/version.h" #include "../EfiLib/BdsHelper.h" #include "../EfiLib/legacy.h" #ifdef __MAKEWITH_GNUEFI #ifndef EFI_SECURITY_VIOLATION #define EFI_SECURITY_VIOLATION EFIERR (26) #endif #endif #ifndef EFI_OS_INDICATIONS_BOOT_TO_FW_UI #define EFI_OS_INDICATIONS_BOOT_TO_FW_UI 0x0000000000000001ULL #endif #ifdef __MAKEWITH_TIANO #define LibLocateHandle gBS->LocateHandleBuffer #endif // // constants #define MACOSX_LOADER_DIR L"System\\Library\\CoreServices" #define MACOSX_LOADER_PATH ( MACOSX_LOADER_DIR L"\\boot.efi" ) #if defined (EFIX64) #define SHELL_NAMES L"\\EFI\\tools\\shell.efi,\\EFI\\tools\\shellx64.efi,\\shell.efi,\\shellx64.efi" #define GPTSYNC_NAMES L"\\EFI\\tools\\gptsync.efi,\\EFI\\tools\\gptsync_x64.efi" #define GDISK_NAMES L"\\EFI\\tools\\gdisk.efi,\\EFI\\tools\\gdisk_x64.efi" #define NETBOOT_NAMES L"\\EFI\\tools\\ipxe.efi" #define MEMTEST_NAMES L"memtest86.efi,memtest86_x64.efi,memtest86x64.efi,bootx64.efi" #define FALLBACK_FULLNAME L"EFI\\BOOT\\bootx64.efi" #define FALLBACK_BASENAME L"bootx64.efi" #define EFI_STUB_ARCH 0x8664 EFI_GUID gFreedesktopRootGuid = { 0x4f68bce3, 0xe8cd, 0x4db1, { 0x96, 0xe7, 0xfb, 0xca, 0xf9, 0x84, 0xb7, 0x09 }}; #elif defined (EFI32) #define SHELL_NAMES L"\\EFI\\tools\\shell.efi,\\EFI\\tools\\shellia32.efi,\\shell.efi,\\shellia32.efi" #define GPTSYNC_NAMES L"\\EFI\\tools\\gptsync.efi,\\EFI\\tools\\gptsync_ia32.efi" #define GDISK_NAMES L"\\EFI\\tools\\gdisk.efi,\\EFI\\tools\\gdisk_ia32.efi" #define NETBOOT_NAMES L"\\EFI\\tools\\ipxe.efi" #define MEMTEST_NAMES L"memtest86.efi,memtest86_ia32.efi,memtest86ia32.efi,bootia32.efi" #define FALLBACK_FULLNAME L"EFI\\BOOT\\bootia32.efi" #define FALLBACK_BASENAME L"bootia32.efi" #define EFI_STUB_ARCH 0x014c EFI_GUID gFreedesktopRootGuid = { 0x44479540, 0xf297, 0x41b2, { 0x9a, 0xf7, 0xd1, 0x31, 0xd5, 0xf0, 0x45, 0x8a }}; #elif defined (EFIAARCH64) #define SHELL_NAMES L"\\EFI\\tools\\shell.efi,\\EFI\\tools\\shellaa64.efi,\\shell.efi,\\shellaa64.efi" #define GPTSYNC_NAMES L"\\EFI\\tools\\gptsync.efi,\\EFI\\tools\\gptsync_aa64.efi" #define GDISK_NAMES L"\\EFI\\tools\\gdisk.efi,\\EFI\\tools\\gdisk_aa64.efi" #define NETBOOT_NAMES L"\\EFI\\tools\\ipxe.efi" #define MEMTEST_NAMES L"memtest86.efi,memtest86_aa64.efi,memtest86aa64.efi,bootaa64.efi" #define FALLBACK_FULLNAME L"EFI\\BOOT\\bootaa64.efi" #define FALLBACK_BASENAME L"bootaa64.efi" #define EFI_STUB_ARCH 0xaa64 EFI_GUID gFreedesktopRootGuid = { 0xb921b045, 0x1df0, 0x41c3, { 0xaf, 0x44, 0x4c, 0x6f, 0x28, 0x0d, 0x3f, 0xae }}; #else #define SHELL_NAMES L"\\EFI\\tools\\shell.efi,\\shell.efi" #define GPTSYNC_NAMES L"\\EFI\\tools\\gptsync.efi" #define GDISK_NAMES L"\\EFI\\tools\\gdisk.efi" #define NETBOOT_NAMES L"\\EFI\\tools\\ipxe.efi" #define MEMTEST_NAMES L"memtest86.efi" #define DRIVER_DIRS L"drivers" #define FALLBACK_FULLNAME L"EFI\\BOOT\\boot.efi" /* Not really correct */ #define FALLBACK_BASENAME L"boot.efi" /* Not really correct */ // Below is GUID for ARM32 EFI_GUID gFreedesktopRootGuid = { 0x69dad710, 0x2ce4, 0x4e3c, { 0xb1, 0x6c, 0x21, 0xa1, 0xd4, 0x9a, 0xbe, 0xd3 }}; #endif #define FAT_ARCH 0x0ef1fab9 /* ID for Apple "fat" binary */ #define IPXE_DISCOVER_NAME L"\\efi\\tools\\ipxe_discover.efi" #define IPXE_NAME L"\\efi\\tools\\ipxe.efi" // Patterns that identify Linux kernels. Added to the loader match pattern when the // scan_all_linux_kernels option is set in the configuration file. Causes kernels WITHOUT // a ".efi" extension to be found when scanning for boot loaders. #define LINUX_MATCH_PATTERNS L"vmlinuz*,bzImage*,kernel*" // Maximum length of a text string in certain menus #define MAX_LINE_LENGTH 65 static REFIT_MENU_ENTRY MenuEntryAbout = { L"About rEFInd", TAG_ABOUT, 1, 0, 'A', NULL, NULL, NULL }; static REFIT_MENU_ENTRY MenuEntryReset = { L"Reboot Computer", TAG_REBOOT, 1, 0, 'R', NULL, NULL, NULL }; static REFIT_MENU_ENTRY MenuEntryShutdown = { L"Shut Down Computer", TAG_SHUTDOWN, 1, 0, 'U', NULL, NULL, NULL }; REFIT_MENU_ENTRY MenuEntryReturn = { L"Return to Main Menu", TAG_RETURN, 1, 0, 0, NULL, NULL, NULL }; static REFIT_MENU_ENTRY MenuEntryExit = { L"Exit rEFInd", TAG_EXIT, 1, 0, 0, NULL, NULL, NULL }; static REFIT_MENU_ENTRY MenuEntryManageHidden = { L"Manage Hidden Tags Menu", TAG_HIDDEN, 1, 0, 0, NULL, NULL, NULL }; static REFIT_MENU_ENTRY MenuEntryFirmware = { L"Reboot to Computer Setup Utility", TAG_FIRMWARE, 1, 0, 0, NULL, NULL, NULL }; static REFIT_MENU_ENTRY MenuEntryRotateCsr = { L"Change SIP Policy", TAG_CSR_ROTATE, 1, 0, 0, NULL, NULL, NULL }; REFIT_MENU_SCREEN MainMenu = { L"Main Menu", NULL, 0, NULL, 0, NULL, 0, L"Automatic boot", L"Use arrow keys to move cursor; Enter to boot;", L"Insert, Tab, or F2 for more options; Esc or Backspace to refresh" }; static REFIT_MENU_SCREEN AboutMenu = { L"About", NULL, 0, NULL, 0, NULL, 0, NULL, L"Press Enter to return to main menu", L"" }; <<<<<<< HEAD REFIT_CONFIG GlobalConfig = { /* TextOnly = */ FALSE, /* ScanAllLinux = */ TRUE, /* DeepLegacyScan = */ FALSE, /* EnableAndLockVMX = */ FALSE, /* FoldLinuxKernels = */ TRUE, /* EnableTouch = */ FALSE, /* HiddenTags = */ TRUE, /* RequestedScreenWidth = */ 0, /* RequestedScreenHeight = */ 0, /* BannerBottomEdge = */ 0, /* RequestedTextMode = */ DONT_CHANGE_TEXT_MODE, /* Timeout = */ 20, /* HideUIFlags = */ 0, /* MaxTags = */ 0, /* GraphicsFor = */ GRAPHICS_FOR_OSX, /* LegacyType = */ LEGACY_TYPE_MAC, /* ScanDelay = */ 0, /* ScreensaverTime = */ 0, /* IconSizes = */ { DEFAULT_BIG_ICON_SIZE / 4, DEFAULT_SMALL_ICON_SIZE, DEFAULT_BIG_ICON_SIZE }, /* BannerScale = */ BANNER_NOSCALE, /* *DiscoveredRoot = */ NULL, /* *SelfDevicePath = */ NULL, /* *BannerFileName = */ NULL, /* *ScreenBackground = */ NULL, /* *ConfigFilename = */ CONFIG_FILE_NAME, /* *SelectionSmallFileName = */ NULL, /* *SelectionBigFileName = */ NULL, /* *DefaultSelection = */ NULL, /* *AlsoScan = */ NULL, /* *DontScanVolumes = */ NULL, /* *DontScanDirs = */ NULL, /* *DontScanFiles = */ NULL, /* *DontScanTools = */ NULL, /* *WindowsRecoveryFiles = */ NULL, /* *DriverDirs = */ NULL, /* *IconsDir = */ NULL, /* *ExtraKernelVersionStrings = */ NULL, /* *SpoofOSXVersion = */ NULL, /* CsrValues = */ NULL, /* ShowTools = */ { TAG_SHELL, TAG_MEMTEST, TAG_GDISK, TAG_APPLE_RECOVERY, TAG_WINDOWS_RECOVERY, TAG_MOK_TOOL, TAG_ABOUT, TAG_HIDDEN, TAG_SHUTDOWN, TAG_REBOOT, TAG_FIRMWARE, TAG_FWUPDATE_TOOL, 0, 0, 0, 0, 0, 0, 0, 0, 0 } ======= REFIT_CONFIG GlobalConfig = { FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, 0, 0, 0, DONT_CHANGE_TEXT_MODE, 20, 0, 0, GRAPHICS_FOR_OSX, LEGACY_TYPE_MAC, 0, 0, { DEFAULT_BIG_ICON_SIZE / 4, DEFAULT_SMALL_ICON_SIZE, DEFAULT_BIG_ICON_SIZE, DEFAULT_MOUSE_SIZE }, BANNER_NOSCALE, 1, NULL, NULL, NULL, NULL, CONFIG_FILE_NAME, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, { TAG_SHELL, TAG_MEMTEST, TAG_GDISK, TAG_APPLE_RECOVERY, TAG_WINDOWS_RECOVERY, TAG_MOK_TOOL, TAG_ABOUT, TAG_SHUTDOWN, TAG_REBOOT, TAG_FIRMWARE, TAG_FWUPDATE_TOOL, 0, 0, 0, 0, 0, 0, 0, 0 } >>>>>>> d63734581c19715b3dc13ab89c520def8d5c4566 }; EFI_GUID GlobalGuid = EFI_GLOBAL_VARIABLE; EFI_GUID RefindGuid = REFIND_GUID_VALUE; GPT_DATA *gPartitions = NULL; // Structure used to hold boot loader filenames and time stamps in // a linked list; used to sort entries within a directory. struct LOADER_LIST { CHAR16 *FileName; EFI_TIME TimeStamp; struct LOADER_LIST *NextEntry; }; // // misc functions // static VOID AboutrEFInd(VOID) { CHAR16 *FirmwareVendor; UINT32 CsrStatus; if (AboutMenu.EntryCount == 0) { AboutMenu.TitleImage = BuiltinIcon(BUILTIN_ICON_FUNC_ABOUT); AddMenuInfoLine(&AboutMenu, PoolPrint(L"rEFInd Version %s", REFIND_VERSION)); AddMenuInfoLine(&AboutMenu, L""); AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2006-2010 Christoph Pfisterer"); AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2012-2017 Roderick W. Smith"); AddMenuInfoLine(&AboutMenu, L"Portions Copyright (c) Intel Corporation and others"); AddMenuInfoLine(&AboutMenu, L"Distributed under the terms of the GNU GPLv3 license"); AddMenuInfoLine(&AboutMenu, L""); AddMenuInfoLine(&AboutMenu, L"Running on:"); AddMenuInfoLine(&AboutMenu, PoolPrint(L" EFI Revision %d.%02d", ST->Hdr.Revision >> 16, ST->Hdr.Revision & ((1 << 16) - 1))); #if defined(EFI32) AddMenuInfoLine(&AboutMenu, PoolPrint(L" Platform: x86 (32 bit); Secure Boot %s", secure_mode() ? L"active" : L"inactive")); #elif defined(EFIX64) AddMenuInfoLine(&AboutMenu, PoolPrint(L" Platform: x86_64 (64 bit); Secure Boot %s", secure_mode() ? L"active" : L"inactive")); #elif defined(EFIAARCH64) AddMenuInfoLine(&AboutMenu, PoolPrint(L" Platform: ARM (64 bit); Secure Boot %s", secure_mode() ? L"active" : L"inactive")); #else AddMenuInfoLine(&AboutMenu, L" Platform: unknown"); #endif if (GetCsrStatus(&CsrStatus) == EFI_SUCCESS) { RecordgCsrStatus(CsrStatus, FALSE); AddMenuInfoLine(&AboutMenu, gCsrStatus); } FirmwareVendor = StrDuplicate(ST->FirmwareVendor); LimitStringLength(FirmwareVendor, MAX_LINE_LENGTH); // More than ~65 causes empty info page on 800x600 display AddMenuInfoLine(&AboutMenu, PoolPrint(L" Firmware: %s %d.%02d", FirmwareVendor, ST->FirmwareRevision >> 16, ST->FirmwareRevision & ((1 << 16) - 1))); AddMenuInfoLine(&AboutMenu, PoolPrint(L" Screen Output: %s", egScreenDescription())); AddMenuInfoLine(&AboutMenu, L""); #if defined(__MAKEWITH_GNUEFI) AddMenuInfoLine(&AboutMenu, L"Built with GNU-EFI"); #else AddMenuInfoLine(&AboutMenu, L"Built with TianoCore EDK2"); #endif AddMenuInfoLine(&AboutMenu, L""); AddMenuInfoLine(&AboutMenu, L"For more information, see the rEFInd Web site:"); AddMenuInfoLine(&AboutMenu, L"http://www.rodsbooks.com/refind/"); AddMenuEntry(&AboutMenu, &MenuEntryReturn); } RunMenu(&AboutMenu, NULL); } /* VOID AboutrEFInd() */ static VOID WarnSecureBootError(CHAR16 *Name, BOOLEAN Verbose) { if (Name == NULL) Name = L"the loader"; refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_ERROR); Print(L"Secure Boot validation failure loading %s!\n", Name); refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BASIC); if (Verbose && secure_mode()) { Print(L"\nThis computer is configured with Secure Boot active, but\n%s has failed validation.\n", Name); Print(L"\nYou can:\n * Launch another boot loader\n"); Print(L" * Disable Secure Boot in your firmware\n"); Print(L" * Sign %s with a machine owner key (MOK)\n", Name); Print(L" * Use a MOK utility (often present on the second row) to add a MOK with which\n"); Print(L" %s has already been signed.\n", Name); Print(L" * Use a MOK utility to register %s (\"enroll its hash\") without\n", Name); Print(L" signing it.\n"); Print(L"\nSee http://www.rodsbooks.com/refind/secureboot.html for more information\n"); PauseForKey(); } // if } // VOID WarnSecureBootError() // Returns TRUE if this file is a valid EFI loader file, and is proper ARCH static BOOLEAN IsValidLoader(EFI_FILE *RootDir, CHAR16 *FileName) { BOOLEAN IsValid = TRUE; #if defined (EFIX64) | defined (EFI32) | defined (EFIAARCH64) EFI_STATUS Status; EFI_FILE_HANDLE FileHandle; CHAR8 Header[512]; UINTN Size = sizeof(Header); if ((RootDir == NULL) || (FileName == NULL)) { // Assume valid here, because Macs produce NULL RootDir (& maybe FileName) // when launching from a Firewire drive. This should be handled better, but // fix would have to be in StartEFIImageList() and/or in FindVolumeAndFilename(). return TRUE; } // if Status = refit_call5_wrapper(RootDir->Open, RootDir, &FileHandle, FileName, EFI_FILE_MODE_READ, 0); if (EFI_ERROR(Status)) return FALSE; Status = refit_call3_wrapper(FileHandle->Read, FileHandle, &Size, Header); refit_call1_wrapper(FileHandle->Close, FileHandle); IsValid = !EFI_ERROR(Status) && Size == sizeof(Header) && ((Header[0] == 'M' && Header[1] == 'Z' && (Size = *(UINT32 *)&Header[0x3c]) < 0x180 && Header[Size] == 'P' && Header[Size+1] == 'E' && Header[Size+2] == 0 && Header[Size+3] == 0 && *(UINT16 *)&Header[Size+4] == EFI_STUB_ARCH) || (*(UINT32 *)&Header == FAT_ARCH)); #endif return IsValid; } // BOOLEAN IsValidLoader() // Launch an EFI binary. EFI_STATUS StartEFIImageList(IN EFI_DEVICE_PATH **DevicePaths, IN CHAR16 *LoadOptions, IN UINTN LoaderType, IN CHAR16 *ImageTitle, IN CHAR8 OSType, OUT UINTN *ErrorInStep, IN BOOLEAN Verbose, IN BOOLEAN IsDriver) { EFI_STATUS Status, ReturnStatus; EFI_HANDLE ChildImageHandle, ChildImageHandle2; EFI_LOADED_IMAGE *ChildLoadedImage = NULL; REFIT_VOLUME *Volume = NULL; UINTN DevicePathIndex; CHAR16 ErrorInfo[256]; CHAR16 *FullLoadOptions = NULL; CHAR16 *Filename = NULL; CHAR16 *Temp; if (ErrorInStep != NULL) *ErrorInStep = 0; // set load options if (LoadOptions != NULL) { FullLoadOptions = StrDuplicate(LoadOptions); if ((LoaderType == TYPE_EFI) && (OSType == 'M')) { MergeStrings(&FullLoadOptions, L" ", 0); // NOTE: That last space is also added by the EFI shell and seems to be significant // when passing options to Apple's boot.efi... } // if } // if (LoadOptions != NULL) if (Verbose) Print(L"Starting %s\nUsing load options '%s'\n", ImageTitle, FullLoadOptions ? FullLoadOptions : L""); // load the image into memory ReturnStatus = Status = EFI_NOT_FOUND; // in case the list is empty for (DevicePathIndex = 0; DevicePaths[DevicePathIndex] != NULL; DevicePathIndex++) { FindVolumeAndFilename(DevicePaths[DevicePathIndex], &Volume, &Filename); // Some EFIs crash if attempting to load driver for invalid architecture, so // protect for this condition; but sometimes Volume comes back NULL, so provide // an exception. (TODO: Handle this special condition better.) if ((LoaderType == TYPE_LEGACY) || (Volume == NULL) || IsValidLoader(Volume->RootDir, Filename)) { if (Filename && (LoaderType != TYPE_LEGACY)) { Temp = PoolPrint(L"\\%s %s", Filename, FullLoadOptions ? FullLoadOptions : L""); if (Temp != NULL) { MyFreePool(FullLoadOptions); FullLoadOptions = Temp; } } // if (Filename) // NOTE: Below commented-out line could be more efficient if file were read ahead of // time and passed as a pre-loaded image to LoadImage(), but it doesn't work on my // 32-bit Mac Mini or my 64-bit Intel box when launching a Linux kernel; the // kernel returns a "Failed to handle fs_proto" error message. // TODO: Track down the cause of this error and fix it, if possible. // ReturnStatus = Status = refit_call6_wrapper(BS->LoadImage, FALSE, SelfImageHandle, DevicePaths[DevicePathIndex], // ImageData, ImageSize, &ChildImageHandle); ReturnStatus = Status = refit_call6_wrapper(BS->LoadImage, FALSE, SelfImageHandle, DevicePaths[DevicePathIndex], NULL, 0, &ChildImageHandle); if (secure_mode() && ShimLoaded()) { // Load ourself into memory. This is a trick to work around a bug in Shim 0.8, // which ties itself into the BS->LoadImage() and BS->StartImage() functions and // then unregisters itself from the EFI system table when its replacement // StartImage() function is called *IF* the previous LoadImage() was for the same // program. The result is that rEFInd can validate only the first program it // launches (often a filesystem driver). Loading a second program (rEFInd itself, // here, to keep it smaller than a kernel) works around this problem. See the // replacements.c file in Shim, and especially its start_image() function, for // the source of the problem. // NOTE: This doesn't check the return status or handle errors. It could // conceivably do weird things if, say, rEFInd were on a USB drive that the // user pulls before launching a program. refit_call6_wrapper(BS->LoadImage, FALSE, SelfImageHandle, GlobalConfig.SelfDevicePath, NULL, 0, &ChildImageHandle2); } } else { Print(L"Invalid loader file!\n"); ReturnStatus = EFI_LOAD_ERROR; } if (ReturnStatus != EFI_NOT_FOUND) { break; } } // for if ((Status == EFI_ACCESS_DENIED) || (Status == EFI_SECURITY_VIOLATION)) { WarnSecureBootError(ImageTitle, Verbose); goto bailout; } SPrint(ErrorInfo, 255, L"while loading %s", ImageTitle); if (CheckError(Status, ErrorInfo)) { if (ErrorInStep != NULL) *ErrorInStep = 1; goto bailout; } ReturnStatus = Status = refit_call3_wrapper(BS->HandleProtocol, ChildImageHandle, &LoadedImageProtocol, (VOID **) &ChildLoadedImage); if (CheckError(Status, L"while getting a LoadedImageProtocol handle")) { if (ErrorInStep != NULL) *ErrorInStep = 2; goto bailout_unload; } ChildLoadedImage->LoadOptions = (VOID *)FullLoadOptions; ChildLoadedImage->LoadOptionsSize = FullLoadOptions ? ((UINT32)StrLen(FullLoadOptions) + 1) * sizeof(CHAR16) : 0; // turn control over to the image // TODO: (optionally) re-enable the EFI watchdog timer! // close open file handles UninitRefitLib(); ReturnStatus = Status = refit_call3_wrapper(BS->StartImage, ChildImageHandle, NULL, NULL); // control returns here when the child image calls Exit() SPrint(ErrorInfo, 255, L"returned from %s", ImageTitle); if (CheckError(Status, ErrorInfo)) { if (ErrorInStep != NULL) *ErrorInStep = 3; } if (IsDriver) { // Below should have no effect on most systems, but works // around bug with some EFIs that prevents filesystem drivers // from binding to partitions. ConnectFilesystemDriver(ChildImageHandle); } // re-open file handles ReinitRefitLib(); bailout_unload: // unload the image, we don't care if it works or not... if (!IsDriver) Status = refit_call1_wrapper(BS->UnloadImage, ChildImageHandle); bailout: MyFreePool(FullLoadOptions); return ReturnStatus; } /* EFI_STATUS StartEFIImageList() */ EFI_STATUS StartEFIImage(IN EFI_DEVICE_PATH *DevicePath, IN CHAR16 *LoadOptions, IN UINTN LoaderType, IN CHAR16 *ImageTitle, IN CHAR8 OSType, OUT UINTN *ErrorInStep, IN BOOLEAN Verbose, IN BOOLEAN IsDriver) { EFI_DEVICE_PATH *DevicePaths[2]; DevicePaths[0] = DevicePath; DevicePaths[1] = NULL; return StartEFIImageList(DevicePaths, LoadOptions, LoaderType, ImageTitle, OSType, ErrorInStep, Verbose, IsDriver); } /* static EFI_STATUS StartEFIImage() */ // From gummiboot: Reboot the computer into its built-in user interface static EFI_STATUS RebootIntoFirmware(VOID) { CHAR8 *b; UINTN size; UINT64 osind; EFI_STATUS err; osind = EFI_OS_INDICATIONS_BOOT_TO_FW_UI; err = EfivarGetRaw(&GlobalGuid, L"OsIndications", &b, &size); if (err == EFI_SUCCESS) osind |= (UINT64)*b; MyFreePool(b); err = EfivarSetRaw(&GlobalGuid, L"OsIndications", (CHAR8 *)&osind, sizeof(UINT64), TRUE); if (err != EFI_SUCCESS) return err; refit_call4_wrapper(RT->ResetSystem, EfiResetCold, EFI_SUCCESS, 0, NULL); Print(L"Error calling ResetSystem: %r", err); PauseForKey(); return err; } // Record the value of the loader's name/description in rEFInd's "PreviousBoot" EFI variable, // if it's different from what's already stored there. VOID StoreLoaderName(IN CHAR16 *Name) { EFI_STATUS Status; CHAR16 *OldName = NULL; UINTN Length; if (Name) { Status = EfivarGetRaw(&RefindGuid, L"PreviousBoot", (CHAR8**) &OldName, &Length); if ((Status != EFI_SUCCESS) || (StrCmp(OldName, Name) != 0)) { EfivarSetRaw(&RefindGuid, L"PreviousBoot", (CHAR8*) Name, StrLen(Name) * 2 + 2, TRUE); } // if MyFreePool(OldName); } // if } // VOID StoreLoaderName() // // EFI OS loader functions // // See http://www.thomas-krenn.com/en/wiki/Activating_the_Intel_VT_Virtualization_Feature // for information on Intel VMX features static VOID DoEnableAndLockVMX(VOID) { #if defined (EFIX64) | defined (EFI32) UINT32 msr = 0x3a; UINT32 low_bits = 0, high_bits = 0; // is VMX active ? __asm__ volatile ("rdmsr" : "=a" (low_bits), "=d" (high_bits) : "c" (msr)); // enable and lock vmx if not locked if ((low_bits & 1) == 0) { high_bits = 0; low_bits = 0x05; msr = 0x3a; __asm__ volatile ("wrmsr" : : "c" (msr), "a" (low_bits), "d" (high_bits)); } #endif } // VOID DoEnableAndLockVMX() static VOID StartLoader(LOADER_ENTRY *Entry, CHAR16 *SelectionName) { UINTN ErrorInStep = 0; if (GlobalConfig.EnableAndLockVMX) { DoEnableAndLockVMX(); } BeginExternalScreen(Entry->UseGraphicsMode, L"Booting OS"); StoreLoaderName(SelectionName); StartEFIImage(Entry->DevicePath, Entry->LoadOptions, TYPE_EFI, Basename(Entry->LoaderPath), Entry->OSType, &ErrorInStep, !Entry->UseGraphicsMode, FALSE); FinishExternalScreen(); } // Locate an initrd or initramfs file that matches the kernel specified by LoaderPath. // The matching file has a name that begins with "init" and includes the same version // number string as is found in LoaderPath -- but not a longer version number string. // For instance, if LoaderPath is \EFI\kernels\bzImage-3.3.0.efi, and if \EFI\kernels // has a file called initramfs-3.3.0.img, this function will return the string // '\EFI\kernels\initramfs-3.3.0.img'. If the directory ALSO contains the file // initramfs-3.3.0-rc7.img or initramfs-13.3.0.img, those files will NOT match. // If more than one initrd file matches the extracted version string, the one // that matches more characters AFTER (actually, from the start of) the version // string is used. // If no matching init file can be found, returns NULL. static CHAR16 * FindInitrd(IN CHAR16 *LoaderPath, IN REFIT_VOLUME *Volume) { CHAR16 *InitrdName = NULL, *FileName, *KernelVersion, *InitrdVersion, *Path; CHAR16 *KernelPostNum, *InitrdPostNum; UINTN MaxSharedChars, SharedChars; STRING_LIST *InitrdNames = NULL, *FinalInitrdName = NULL, *CurrentInitrdName = NULL, *MaxSharedInitrd; REFIT_DIR_ITER DirIter; EFI_FILE_INFO *DirEntry; FileName = Basename(LoaderPath); KernelVersion = FindNumbers(FileName); Path = FindPath(LoaderPath); // Add trailing backslash for root directory; necessary on some systems, but must // NOT be added to all directories, since on other systems, a trailing backslash on // anything but the root directory causes them to flake out! if (StrLen(Path) == 0) { MergeStrings(&Path, L"\\", 0); } // if DirIterOpen(Volume->RootDir, Path, &DirIter); // Now add a trailing backslash if it was NOT added earlier, for consistency in // building the InitrdName later.... if ((StrLen(Path) > 0) && (Path[StrLen(Path) - 1] != L'\\')) MergeStrings(&Path, L"\\", 0); while (DirIterNext(&DirIter, 2, L"init*", &DirEntry)) { InitrdVersion = FindNumbers(DirEntry->FileName); if (((KernelVersion != NULL) && (MyStriCmp(InitrdVersion, KernelVersion))) || ((KernelVersion == NULL) && (InitrdVersion == NULL))) { CurrentInitrdName = AllocateZeroPool(sizeof(STRING_LIST)); if (InitrdNames == NULL) InitrdNames = FinalInitrdName = CurrentInitrdName; if (CurrentInitrdName) { CurrentInitrdName->Value = PoolPrint(L"%s%s", Path, DirEntry->FileName); if (CurrentInitrdName != FinalInitrdName) { FinalInitrdName->Next = CurrentInitrdName; FinalInitrdName = CurrentInitrdName; } // if } // if } // if MyFreePool(InitrdVersion); } // while if (InitrdNames) { if (InitrdNames->Next == NULL) { InitrdName = StrDuplicate(InitrdNames -> Value); } else { MaxSharedInitrd = CurrentInitrdName = InitrdNames; MaxSharedChars = 0; while (CurrentInitrdName != NULL) { KernelPostNum = MyStrStr(LoaderPath, KernelVersion); InitrdPostNum = MyStrStr(CurrentInitrdName->Value, KernelVersion); SharedChars = NumCharsInCommon(KernelPostNum, InitrdPostNum); if (SharedChars > MaxSharedChars) { MaxSharedChars = SharedChars; MaxSharedInitrd = CurrentInitrdName; } // if // TODO: Compute number of shared characters & compare with max. CurrentInitrdName = CurrentInitrdName->Next; } if (MaxSharedInitrd) InitrdName = StrDuplicate(MaxSharedInitrd->Value); } // if/else } // if DeleteStringList(InitrdNames); // Note: Don't FreePool(FileName), since Basename returns a pointer WITHIN the string it's passed. MyFreePool(KernelVersion); MyFreePool(Path); return (InitrdName); } // static CHAR16 * FindInitrd() LOADER_ENTRY * AddPreparedLoaderEntry(LOADER_ENTRY *Entry) { AddMenuEntry(&MainMenu, (REFIT_MENU_ENTRY *)Entry); return(Entry); } // LOADER_ENTRY * AddPreparedLoaderEntry() // Creates a copy of a menu screen. // Returns a pointer to the copy of the menu screen. static REFIT_MENU_SCREEN* CopyMenuScreen(REFIT_MENU_SCREEN *Entry) { REFIT_MENU_SCREEN *NewEntry; UINTN i; NewEntry = AllocateZeroPool(sizeof(REFIT_MENU_SCREEN)); if ((Entry != NULL) && (NewEntry != NULL)) { CopyMem(NewEntry, Entry, sizeof(REFIT_MENU_SCREEN)); NewEntry->Title = (Entry->Title) ? StrDuplicate(Entry->Title) : NULL; NewEntry->TimeoutText = (Entry->TimeoutText) ? StrDuplicate(Entry->TimeoutText) : NULL; if (Entry->TitleImage != NULL) { NewEntry->TitleImage = AllocatePool(sizeof(EG_IMAGE)); if (NewEntry->TitleImage != NULL) CopyMem(NewEntry->TitleImage, Entry->TitleImage, sizeof(EG_IMAGE)); } // if NewEntry->InfoLines = (CHAR16**) AllocateZeroPool(Entry->InfoLineCount * (sizeof(CHAR16*))); for (i = 0; i < Entry->InfoLineCount && NewEntry->InfoLines; i++) { NewEntry->InfoLines[i] = (Entry->InfoLines[i]) ? StrDuplicate(Entry->InfoLines[i]) : NULL; } // for NewEntry->Entries = (REFIT_MENU_ENTRY**) AllocateZeroPool(Entry->EntryCount * (sizeof (REFIT_MENU_ENTRY*))); for (i = 0; i < Entry->EntryCount && NewEntry->Entries; i++) { AddMenuEntry(NewEntry, Entry->Entries[i]); } // for NewEntry->Hint1 = (Entry->Hint1) ? StrDuplicate(Entry->Hint1) : NULL; NewEntry->Hint2 = (Entry->Hint2) ? StrDuplicate(Entry->Hint2) : NULL; } // if return (NewEntry); } // static REFIT_MENU_SCREEN* CopyMenuScreen() // Creates a copy of a menu entry. Intended to enable moving a stack-based // menu entry (such as the ones for the "reboot" and "exit" functions) to // to the heap. This enables easier deletion of the whole set of menu // entries when re-scanning. // Returns a pointer to the copy of the menu entry. static REFIT_MENU_ENTRY* CopyMenuEntry(REFIT_MENU_ENTRY *Entry) { REFIT_MENU_ENTRY *NewEntry; NewEntry = AllocateZeroPool(sizeof(REFIT_MENU_ENTRY)); if ((Entry != NULL) && (NewEntry != NULL)) { CopyMem(NewEntry, Entry, sizeof(REFIT_MENU_ENTRY)); NewEntry->Title = (Entry->Title) ? StrDuplicate(Entry->Title) : NULL; if (Entry->BadgeImage != NULL) { NewEntry->BadgeImage = AllocatePool(sizeof(EG_IMAGE)); if (NewEntry->BadgeImage != NULL) CopyMem(NewEntry->BadgeImage, Entry->BadgeImage, sizeof(EG_IMAGE)); } if (Entry->Image != NULL) { NewEntry->Image = AllocatePool(sizeof(EG_IMAGE)); if (NewEntry->Image != NULL) CopyMem(NewEntry->Image, Entry->Image, sizeof(EG_IMAGE)); } if (Entry->SubScreen != NULL) { NewEntry->SubScreen = CopyMenuScreen(Entry->SubScreen); } } // if return (NewEntry); } // REFIT_MENU_ENTRY* CopyMenuEntry() // Creates a new LOADER_ENTRY data structure and populates it with // default values from the specified Entry, or NULL values if Entry // is unspecified (NULL). // Returns a pointer to the new data structure, or NULL if it // couldn't be allocated LOADER_ENTRY *InitializeLoaderEntry(IN LOADER_ENTRY *Entry) { LOADER_ENTRY *NewEntry = NULL; NewEntry = AllocateZeroPool(sizeof(LOADER_ENTRY)); if (NewEntry != NULL) { NewEntry->me.Title = NULL; NewEntry->me.Tag = TAG_LOADER; NewEntry->Enabled = TRUE; NewEntry->UseGraphicsMode = FALSE; NewEntry->OSType = 0; NewEntry->DiscoveryType = DISCOVERY_TYPE_UNKNOWN; if (Entry != NULL) { NewEntry->LoaderPath = (Entry->LoaderPath) ? StrDuplicate(Entry->LoaderPath) : NULL; NewEntry->VolName = (Entry->VolName) ? StrDuplicate(Entry->VolName) : NULL; NewEntry->DevicePath = Entry->DevicePath; NewEntry->UseGraphicsMode = Entry->UseGraphicsMode; NewEntry->LoadOptions = (Entry->LoadOptions) ? StrDuplicate(Entry->LoadOptions) : NULL; NewEntry->InitrdPath = (Entry->InitrdPath) ? StrDuplicate(Entry->InitrdPath) : NULL; NewEntry->DiscoveryType = Entry->DiscoveryType; } } // if return (NewEntry); } // LOADER_ENTRY *InitializeLoaderEntry() // Adds InitrdPath to Options, but only if Options doesn't already include an // initrd= line. Done to enable overriding the default initrd selection in a // refind_linux.conf file's options list. // Returns a pointer to a new string. The calling function is responsible for // freeing its memory. static CHAR16 *AddInitrdToOptions(CHAR16 *Options, CHAR16 *InitrdPath) { CHAR16 *NewOptions = NULL; if (Options != NULL) NewOptions = StrDuplicate(Options); if ((InitrdPath != NULL) && !StriSubCmp(L"initrd=", Options)) { MergeStrings(&NewOptions, L"initrd=", L' '); MergeStrings(&NewOptions, InitrdPath, 0); } return NewOptions; } // CHAR16 *AddInitrdToOptions() // Prepare a REFIT_MENU_SCREEN data structure for a subscreen entry. This sets up // the default entry that launches the boot loader using the same options as the // main Entry does. Subsequent options can be added by the calling function. // If a subscreen already exists in the Entry that's passed to this function, // it's left unchanged and a pointer to it is returned. // Returns a pointer to the new subscreen data structure, or NULL if there // were problems allocating memory. REFIT_MENU_SCREEN *InitializeSubScreen(IN LOADER_ENTRY *Entry) { CHAR16 *FileName, *MainOptions = NULL; REFIT_MENU_SCREEN *SubScreen = NULL; LOADER_ENTRY *SubEntry; FileName = Basename(Entry->LoaderPath); if (Entry->me.SubScreen == NULL) { // No subscreen yet; initialize default entry.... SubScreen = AllocateZeroPool(sizeof(REFIT_MENU_SCREEN)); if (SubScreen != NULL) { SubScreen->Title = AllocateZeroPool(sizeof(CHAR16) * 256); SPrint(SubScreen->Title, 255, L"Boot Options for %s on %s", (Entry->Title != NULL) ? Entry->Title : FileName, Entry->VolName); SubScreen->TitleImage = Entry->me.Image; // default entry SubEntry = InitializeLoaderEntry(Entry); if (SubEntry != NULL) { SubEntry->me.Title = StrDuplicate(L"Boot using default options"); MainOptions = SubEntry->LoadOptions; SubEntry->LoadOptions = AddInitrdToOptions(MainOptions, SubEntry->InitrdPath); MyFreePool(MainOptions); AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); } // if (SubEntry != NULL) SubScreen->Hint1 = StrDuplicate(SUBSCREEN_HINT1); if (GlobalConfig.HideUIFlags & HIDEUI_FLAG_EDITOR) { SubScreen->Hint2 = StrDuplicate(SUBSCREEN_HINT2_NO_EDITOR); } else { SubScreen->Hint2 = StrDuplicate(SUBSCREEN_HINT2); } // if/else } // if (SubScreen != NULL) } else { // existing subscreen; less initialization, and just add new entry later.... SubScreen = Entry->me.SubScreen; } // if/else return SubScreen; } // REFIT_MENU_SCREEN *InitializeSubScreen() VOID GenerateSubScreen(LOADER_ENTRY *Entry, IN REFIT_VOLUME *Volume, IN BOOLEAN GenerateReturn) { REFIT_MENU_SCREEN *SubScreen; LOADER_ENTRY *SubEntry; CHAR16 *InitrdName, *KernelVersion = NULL; CHAR16 DiagsFileName[256]; REFIT_FILE *File; UINTN TokenCount; CHAR16 **TokenList; // create the submenu if (StrLen(Entry->Title) == 0) { MyFreePool(Entry->Title); Entry->Title = NULL; } SubScreen = InitializeSubScreen(Entry); // loader-specific submenu entries if (Entry->OSType == 'M') { // entries for macOS #if defined(EFIX64) SubEntry = InitializeLoaderEntry(Entry); if (SubEntry != NULL) { SubEntry->me.Title = L"Boot macOS with a 64-bit kernel"; SubEntry->LoadOptions = L"arch=x86_64"; SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_OSX; AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); } // if SubEntry = InitializeLoaderEntry(Entry); if (SubEntry != NULL) { SubEntry->me.Title = L"Boot macOS with a 32-bit kernel"; SubEntry->LoadOptions = L"arch=i386"; SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_OSX; AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); } // if #endif if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_SINGLEUSER)) { SubEntry = InitializeLoaderEntry(Entry); if (SubEntry != NULL) { SubEntry->me.Title = L"Boot macOS in verbose mode"; SubEntry->UseGraphicsMode = FALSE; SubEntry->LoadOptions = L"-v"; AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); } // if #if defined(EFIX64) SubEntry = InitializeLoaderEntry(Entry); if (SubEntry != NULL) { SubEntry->me.Title = L"Boot macOS in verbose mode (64-bit)"; SubEntry->UseGraphicsMode = FALSE; SubEntry->LoadOptions = L"-v arch=x86_64"; AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); } SubEntry = InitializeLoaderEntry(Entry); if (SubEntry != NULL) { SubEntry->me.Title = L"Boot macOS in verbose mode (32-bit)"; SubEntry->UseGraphicsMode = FALSE; SubEntry->LoadOptions = L"-v arch=i386"; AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); } #endif SubEntry = InitializeLoaderEntry(Entry); if (SubEntry != NULL) { SubEntry->me.Title = L"Boot macOS in single user mode"; SubEntry->UseGraphicsMode = FALSE; SubEntry->LoadOptions = L"-v -s"; AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); } // if } // single-user mode allowed if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_SAFEMODE)) { SubEntry = InitializeLoaderEntry(Entry); if (SubEntry != NULL) { SubEntry->me.Title = L"Boot macOS in safe mode"; SubEntry->UseGraphicsMode = FALSE; SubEntry->LoadOptions = L"-v -x"; AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); } // if } // safe mode allowed // check for Apple hardware diagnostics StrCpy(DiagsFileName, L"System\\Library\\CoreServices\\.diagnostics\\diags.efi"); if (FileExists(Volume->RootDir, DiagsFileName) && !(GlobalConfig.HideUIFlags & HIDEUI_FLAG_HWTEST)) { SubEntry = InitializeLoaderEntry(Entry); if (SubEntry != NULL) { SubEntry->me.Title = L"Run Apple Hardware Test"; MyFreePool(SubEntry->LoaderPath); SubEntry->LoaderPath = StrDuplicate(DiagsFileName); SubEntry->DevicePath = FileDevicePath(Volume->DeviceHandle, SubEntry->LoaderPath); SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_OSX; AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); } // if } // if diagnostics entry found } else if (Entry->OSType == 'L') { // entries for Linux kernels with EFI stub loaders File = ReadLinuxOptionsFile(Entry->LoaderPath, Volume); if (File != NULL) { InitrdName = FindInitrd(Entry->LoaderPath, Volume); TokenCount = ReadTokenLine(File, &TokenList); KernelVersion = FindNumbers(Entry->LoaderPath); ReplaceSubstring(&(TokenList[1]), KERNEL_VERSION, KernelVersion); // first entry requires special processing, since it was initially set // up with a default title but correct options by InitializeSubScreen(), // earlier.... if ((TokenCount > 1) && (SubScreen->Entries != NULL) && (SubScreen->Entries[0] != NULL)) { MyFreePool(SubScreen->Entries[0]->Title); SubScreen->Entries[0]->Title = TokenList[0] ? StrDuplicate(TokenList[0]) : StrDuplicate(L"Boot Linux"); } // if FreeTokenLine(&TokenList, &TokenCount); while ((TokenCount = ReadTokenLine(File, &TokenList)) > 1) { ReplaceSubstring(&(TokenList[1]), KERNEL_VERSION, KernelVersion); SubEntry = InitializeLoaderEntry(Entry); SubEntry->me.Title = TokenList[0] ? StrDuplicate(TokenList[0]) : StrDuplicate(L"Boot Linux"); MyFreePool(SubEntry->LoadOptions); SubEntry->LoadOptions = AddInitrdToOptions(TokenList[1], InitrdName); FreeTokenLine(&TokenList, &TokenCount); SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_LINUX; AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); } // while MyFreePool(KernelVersion); MyFreePool(InitrdName); MyFreePool(File); } // if } else if (Entry->OSType == 'E') { // entries for ELILO SubEntry = InitializeLoaderEntry(Entry); if (SubEntry != NULL) { SubEntry->me.Title = L"Run ELILO in interactive mode"; SubEntry->LoadOptions = L"-p"; SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_ELILO; AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); } SubEntry = InitializeLoaderEntry(Entry); if (SubEntry != NULL) { SubEntry->me.Title = L"Boot Linux for a 17\" iMac or a 15\" MacBook Pro (*)"; SubEntry->LoadOptions = L"-d 0 i17"; SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_ELILO; AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); } SubEntry = InitializeLoaderEntry(Entry); if (SubEntry != NULL) { SubEntry->me.Title = L"Boot Linux for a 20\" iMac (*)"; SubEntry->LoadOptions = L"-d 0 i20"; SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_ELILO; AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); } SubEntry = InitializeLoaderEntry(Entry); if (SubEntry != NULL) { SubEntry->me.Title = L"Boot Linux for a Mac Mini (*)"; SubEntry->LoadOptions = L"-d 0 mini"; SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_ELILO; AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); } AddMenuInfoLine(SubScreen, L"NOTE: This is an example. Entries"); AddMenuInfoLine(SubScreen, L"marked with (*) may not work."); } else if (Entry->OSType == 'X') { // entries for xom.efi // by default, skip the built-in selection and boot from hard disk only Entry->LoadOptions = L"-s -h"; SubEntry = InitializeLoaderEntry(Entry); if (SubEntry != NULL) { SubEntry->me.Title = L"Boot Windows from Hard Disk"; SubEntry->LoadOptions = L"-s -h"; SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_WINDOWS; AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); } SubEntry = InitializeLoaderEntry(Entry); if (SubEntry != NULL) { SubEntry->me.Title = L"Boot Windows from CD-ROM"; SubEntry->LoadOptions = L"-s -c"; SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_WINDOWS; AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); } SubEntry = InitializeLoaderEntry(Entry); if (SubEntry != NULL) { SubEntry->me.Title = L"Run XOM in text mode"; SubEntry->LoadOptions = L"-v"; SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_WINDOWS; AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); } } // entries for xom.efi if (GenerateReturn) AddMenuEntry(SubScreen, &MenuEntryReturn); Entry->me.SubScreen = SubScreen; } // VOID GenerateSubScreen() // Returns options for a Linux kernel. Reads them from an options file in the // kernel's directory; and if present, adds an initrd= option for an initial // RAM disk file with the same version number as the kernel file. static CHAR16 * GetMainLinuxOptions(IN CHAR16 * LoaderPath, IN REFIT_VOLUME *Volume) { CHAR16 *Options = NULL, *InitrdName, *FullOptions = NULL, *KernelVersion; Options = GetFirstOptionsFromFile(LoaderPath, Volume); InitrdName = FindInitrd(LoaderPath, Volume); KernelVersion = FindNumbers(InitrdName); ReplaceSubstring(&Options, KERNEL_VERSION, KernelVersion); FullOptions = AddInitrdToOptions(Options, InitrdName); MyFreePool(Options); MyFreePool(InitrdName); MyFreePool(KernelVersion); return (FullOptions); } // static CHAR16 * GetMainLinuxOptions() // Read the specified file and add values of "ID", "NAME", or "DISTRIB_ID" tokens to // OSIconName list. Intended for adding Linux distribution clues gleaned from // /etc/lsb-release and /etc/os-release files. static VOID ParseReleaseFile(CHAR16 **OSIconName, REFIT_VOLUME *Volume, CHAR16 *FileName) { UINTN FileSize = 0; REFIT_FILE File; CHAR16 **TokenList; UINTN TokenCount = 0; if ((Volume == NULL) || (FileName == NULL) || (OSIconName == NULL) || (*OSIconName == NULL)) return; if (FileExists(Volume->RootDir, FileName) && (ReadFile(Volume->RootDir, FileName, &File, &FileSize) == EFI_SUCCESS)) { do { TokenCount = ReadTokenLine(&File, &TokenList); if ((TokenCount > 1) && (MyStriCmp(TokenList[0], L"ID") || MyStriCmp(TokenList[0], L"NAME") || MyStriCmp(TokenList[0], L"DISTRIB_ID"))) { MergeWords(OSIconName, TokenList[1], L','); } // if FreeTokenLine(&TokenList, &TokenCount); } while (TokenCount > 0); MyFreePool(File.Buffer); } // if } // VOID ParseReleaseFile() // Try to guess the name of the Linux distribution & add that name to // OSIconName list. static VOID GuessLinuxDistribution(CHAR16 **OSIconName, REFIT_VOLUME *Volume, CHAR16 *LoaderPath) { // If on Linux root fs, /etc/os-release or /etc/lsb-release file probably has clues.... ParseReleaseFile(OSIconName, Volume, L"etc\\lsb-release"); ParseReleaseFile(OSIconName, Volume, L"etc\\os-release"); // Search for clues in the kernel's filename.... if (StriSubCmp(L".fc", LoaderPath)) MergeStrings(OSIconName, L"fedora", L','); if (StriSubCmp(L".el", LoaderPath)) MergeStrings(OSIconName, L"redhat", L','); } // VOID GuessLinuxDistribution() // Sets a few defaults for a loader entry -- mainly the icon, but also the OS type // code and shortcut letter. For Linux EFI stub loaders, also sets kernel options // that will (with luck) work fairly automatically. VOID SetLoaderDefaults(LOADER_ENTRY *Entry, CHAR16 *LoaderPath, REFIT_VOLUME *Volume) { CHAR16 *NameClues, *PathOnly, *NoExtension, *OSIconName = NULL, *Temp; CHAR16 ShortcutLetter = 0; NameClues = Basename(LoaderPath); PathOnly = FindPath(LoaderPath); NoExtension = StripEfiExtension(NameClues); if (Volume->DiskKind == DISK_KIND_NET) { MergeStrings(&NameClues, Entry->me.Title, L' '); } else { // locate a custom icon for the loader // Anything found here takes precedence over the "hints" in the OSIconName variable if (!Entry->me.Image) { Entry->me.Image = egLoadIconAnyType(Volume->RootDir, PathOnly, NoExtension, GlobalConfig.IconSizes[ICON_SIZE_BIG]); } if (!Entry->me.Image) { Entry->me.Image = egCopyImage(Volume->VolIconImage); } // Begin creating icon "hints" by using last part of directory path leading // to the loader Temp = FindLastDirName(LoaderPath); MergeStrings(&OSIconName, Temp, L','); MyFreePool(Temp); Temp = NULL; if (OSIconName != NULL) { ShortcutLetter = OSIconName[0]; } // Add every "word" in the volume label, delimited by spaces, dashes (-), or // underscores (_), to the list of hints to be used in searching for OS // icons. MergeWords(&OSIconName, Volume->VolName, L','); } // if/else network boot // detect specific loaders if (StriSubCmp(L"bzImage", NameClues) || StriSubCmp(L"vmlinuz", NameClues) || StriSubCmp(L"kernel", NameClues)) { if (Volume->DiskKind != DISK_KIND_NET) { GuessLinuxDistribution(&OSIconName, Volume, LoaderPath); Entry->LoadOptions = GetMainLinuxOptions(LoaderPath, Volume); } MergeStrings(&OSIconName, L"linux", L','); Entry->OSType = 'L'; if (ShortcutLetter == 0) ShortcutLetter = 'L'; Entry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_LINUX; } else if (StriSubCmp(L"refit", LoaderPath)) { MergeStrings(&OSIconName, L"refit", L','); Entry->OSType = 'R'; ShortcutLetter = 'R'; } else if (StriSubCmp(L"refind", LoaderPath)) { MergeStrings(&OSIconName, L"refind", L','); Entry->OSType = 'R'; ShortcutLetter = 'R'; } else if (MyStriCmp(LoaderPath, MACOSX_LOADER_PATH)) { MergeStrings(&OSIconName, L"mac", L','); Entry->OSType = 'M'; ShortcutLetter = 'M'; Entry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_OSX; } else if (MyStriCmp(NameClues, L"diags.efi")) { MergeStrings(&OSIconName, L"hwtest", L','); } else if (MyStriCmp(NameClues, L"e.efi") || MyStriCmp(NameClues, L"elilo.efi") || StriSubCmp(L"elilo", NameClues)) { MergeStrings(&OSIconName, L"elilo,linux", L','); Entry->OSType = 'E'; if (ShortcutLetter == 0) ShortcutLetter = 'L'; Entry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_ELILO; } else if (StriSubCmp(L"grub", NameClues)) { MergeStrings(&OSIconName, L"grub,linux", L','); Entry->OSType = 'G'; ShortcutLetter = 'G'; Entry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_GRUB; } else if (MyStriCmp(NameClues, L"cdboot.efi") || MyStriCmp(NameClues, L"bootmgr.efi") || MyStriCmp(NameClues, L"bootmgfw.efi") || MyStriCmp(NameClues, L"bkpbootmgfw.efi")) { MergeStrings(&OSIconName, L"win8", L','); Entry->OSType = 'W'; ShortcutLetter = 'W'; Entry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_WINDOWS; } else if (MyStriCmp(NameClues, L"xom.efi")) { MergeStrings(&OSIconName, L"xom,win,win8", L','); Entry->OSType = 'X'; ShortcutLetter = 'W'; Entry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_WINDOWS; } else if (StriSubCmp(L"ipxe", NameClues)) { Entry->OSType = 'N'; ShortcutLetter = 'N'; MergeStrings(&OSIconName, L"network", L','); } if ((ShortcutLetter >= 'a') && (ShortcutLetter <= 'z')) ShortcutLetter = ShortcutLetter - 'a' + 'A'; // convert lowercase to uppercase Entry->me.ShortcutLetter = ShortcutLetter; if (Entry->me.Image == NULL) Entry->me.Image = LoadOSIcon(OSIconName, L"unknown", FALSE); MyFreePool(PathOnly); } // VOID SetLoaderDefaults() // Add a specified EFI boot loader to the list, using automatic settings // for icons, options, etc. static LOADER_ENTRY * AddLoaderEntry(IN CHAR16 *LoaderPath, IN CHAR16 *LoaderTitle, IN REFIT_VOLUME *Volume, IN BOOLEAN SubScreenReturn) { LOADER_ENTRY *Entry; CleanUpPathNameSlashes(LoaderPath); Entry = InitializeLoaderEntry(NULL); Entry->DiscoveryType = DISCOVERY_TYPE_AUTO; if (Entry != NULL) { Entry->Title = StrDuplicate((LoaderTitle != NULL) ? LoaderTitle : LoaderPath); Entry->me.Title = AllocateZeroPool(sizeof(CHAR16) * 256); // Extra space at end of Entry->me.Title enables searching on Volume->VolName even if another volume // name is identical except for something added to the end (e.g., VolB1 vs. VolB12). // Note: Volume->VolName will be NULL for network boot programs. if ((Volume->VolName) && (!MyStriCmp(Volume->VolName, L"Recovery HD"))) SPrint(Entry->me.Title, 255, L"Boot %s from %s ", (LoaderTitle != NULL) ? LoaderTitle : LoaderPath, Volume->VolName); else SPrint(Entry->me.Title, 255, L"Boot %s ", (LoaderTitle != NULL) ? LoaderTitle : LoaderPath); Entry->me.Row = 0; Entry->me.BadgeImage = Volume->VolBadgeImage; if ((LoaderPath != NULL) && (LoaderPath[0] != L'\\')) { Entry->LoaderPath = StrDuplicate(L"\\"); } else { Entry->LoaderPath = NULL; } MergeStrings(&(Entry->LoaderPath), LoaderPath, 0); Entry->VolName = Volume->VolName; Entry->DevicePath = FileDevicePath(Volume->DeviceHandle, Entry->LoaderPath); SetLoaderDefaults(Entry, LoaderPath, Volume); GenerateSubScreen(Entry, Volume, SubScreenReturn); AddMenuEntry(&MainMenu, (REFIT_MENU_ENTRY *)Entry); } return(Entry); } // LOADER_ENTRY * AddLoaderEntry() // Add a Linux kernel as a submenu entry for another (pre-existing) Linux kernel entry. static VOID AddKernelToSubmenu(LOADER_ENTRY * TargetLoader, CHAR16 *FileName, REFIT_VOLUME *Volume) { REFIT_FILE *File; CHAR16 **TokenList = NULL, *InitrdName, *SubmenuName = NULL, *VolName = NULL; CHAR16 *Path = NULL, *Title, *KernelVersion; REFIT_MENU_SCREEN *SubScreen; LOADER_ENTRY *SubEntry; UINTN TokenCount; File = ReadLinuxOptionsFile(TargetLoader->LoaderPath, Volume); if (File != NULL) { SubScreen = TargetLoader->me.SubScreen; InitrdName = FindInitrd(FileName, Volume); KernelVersion = FindNumbers(FileName); while ((TokenCount = ReadTokenLine(File, &TokenList)) > 1) { ReplaceSubstring(&(TokenList[1]), KERNEL_VERSION, KernelVersion); SubEntry = InitializeLoaderEntry(TargetLoader); SplitPathName(FileName, &VolName, &Path, &SubmenuName); MergeStrings(&SubmenuName, L": ", '\0'); MergeStrings(&SubmenuName, TokenList[0] ? StrDuplicate(TokenList[0]) : StrDuplicate(L"Boot Linux"), '\0'); Title = StrDuplicate(SubmenuName); LimitStringLength(Title, MAX_LINE_LENGTH); SubEntry->me.Title = Title; MyFreePool(SubEntry->LoadOptions); SubEntry->LoadOptions = AddInitrdToOptions(TokenList[1], InitrdName); MyFreePool(SubEntry->LoaderPath); SubEntry->LoaderPath = StrDuplicate(FileName); CleanUpPathNameSlashes(SubEntry->LoaderPath); SubEntry->DevicePath = FileDevicePath(Volume->DeviceHandle, SubEntry->LoaderPath); FreeTokenLine(&TokenList, &TokenCount); SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_LINUX; AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); } // while MyFreePool(VolName); MyFreePool(Path); MyFreePool(SubmenuName); MyFreePool(InitrdName); MyFreePool(File); MyFreePool(KernelVersion); } // if } // static VOID AddKernelToSubmenu() // Returns -1 if (Time1 < Time2), +1 if (Time1 > Time2), or 0 if // (Time1 == Time2). Precision is only to the nearest second; since // this is used for sorting boot loader entries, differences smaller // than this are likely to be meaningless (and unlikely!). INTN TimeComp(IN EFI_TIME *Time1, IN EFI_TIME *Time2) { INT64 Time1InSeconds, Time2InSeconds; // Following values are overestimates; I'm assuming 31 days in every month. // This is fine for the purpose of this function, which is limited Time1InSeconds = Time1->Second + (Time1->Minute * 60) + (Time1->Hour * 3600) + (Time1->Day * 86400) + (Time1->Month * 2678400) + ((Time1->Year - 1998) * 32140800); Time2InSeconds = Time2->Second + (Time2->Minute * 60) + (Time2->Hour * 3600) + (Time2->Day * 86400) + (Time2->Month * 2678400) + ((Time2->Year - 1998) * 32140800); if (Time1InSeconds < Time2InSeconds) return (-1); else if (Time1InSeconds > Time2InSeconds) return (1); return 0; } // INTN TimeComp() // Adds a loader list element, keeping it sorted by date. EXCEPTION: Fedora's rescue // kernel, which begins with "vmlinuz-0-rescue," should not be at the top of the list, // since that will make it the default if kernel folding is enabled, so float it to // the end. // Returns the new first element (the one with the most recent date). static struct LOADER_LIST * AddLoaderListEntry(struct LOADER_LIST *LoaderList, struct LOADER_LIST *NewEntry) { struct LOADER_LIST *LatestEntry, *CurrentEntry, *PrevEntry = NULL; BOOLEAN LinuxRescue = FALSE; LatestEntry = CurrentEntry = LoaderList; if (LoaderList == NULL) { LatestEntry = NewEntry; } else { if (StriSubCmp(L"vmlinuz-0-rescue", NewEntry->FileName)) LinuxRescue = TRUE; while ((CurrentEntry != NULL) && !StriSubCmp(L"vmlinuz-0-rescue", CurrentEntry->FileName) && (LinuxRescue || (TimeComp(&(NewEntry->TimeStamp), &(CurrentEntry->TimeStamp)) < 0))) { PrevEntry = CurrentEntry; CurrentEntry = CurrentEntry->NextEntry; } // while NewEntry->NextEntry = CurrentEntry; if (PrevEntry == NULL) { LatestEntry = NewEntry; } else { PrevEntry->NextEntry = NewEntry; } // if/else } // if/else return (LatestEntry); } // static VOID AddLoaderListEntry() // Delete the LOADER_LIST linked list static VOID CleanUpLoaderList(struct LOADER_LIST *LoaderList) { struct LOADER_LIST *Temp; while (LoaderList != NULL) { Temp = LoaderList; LoaderList = LoaderList->NextEntry; MyFreePool(Temp->FileName); MyFreePool(Temp); } // while } // static VOID CleanUpLoaderList() // Returns FALSE if the specified file/volume matches the GlobalConfig.DontScanDirs // or GlobalConfig.DontScanVolumes specification, or if Path points to a volume // other than the one specified by Volume, or if the specified path is SelfDir. // Returns TRUE if none of these conditions is met -- that is, if the path is // eligible for scanning. static BOOLEAN ShouldScan(REFIT_VOLUME *Volume, CHAR16 *Path) { CHAR16 *VolName = NULL, *DontScanDir, *PathCopy = NULL, *VolGuid = NULL; UINTN i = 0; BOOLEAN ScanIt = TRUE; VolGuid = GuidAsString(&(Volume->PartGuid)); if ((IsIn(Volume->VolName, GlobalConfig.DontScanVolumes)) || (IsIn(Volume->PartName, GlobalConfig.DontScanVolumes)) || (IsIn(VolGuid, GlobalConfig.DontScanVolumes))) { MyFreePool(VolGuid); return FALSE; } else { MyFreePool(VolGuid); } // if/else if (MyStriCmp(Path, SelfDirPath) && (Volume->DeviceHandle == SelfVolume->DeviceHandle)) return FALSE; // See if Path includes an explicit volume declaration that's NOT Volume.... PathCopy = StrDuplicate(Path); if (SplitVolumeAndFilename(&PathCopy, &VolName)) { if (VolName && !MyStriCmp(VolName, Volume->VolName)) { ScanIt = FALSE; } // if } // if Path includes volume specification MyFreePool(PathCopy); MyFreePool(VolName); VolName = NULL; // See if Volume is in GlobalConfig.DontScanDirs.... while (ScanIt && (DontScanDir = FindCommaDelimited(GlobalConfig.DontScanDirs, i++))) { SplitVolumeAndFilename(&DontScanDir, &VolName); CleanUpPathNameSlashes(DontScanDir); if (VolName != NULL) { if (VolumeMatchesDescription(Volume, VolName) && MyStriCmp(DontScanDir, Path)) ScanIt = FALSE; } else { if (MyStriCmp(DontScanDir, Path)) ScanIt = FALSE; } MyFreePool(DontScanDir); MyFreePool(VolName); DontScanDir = NULL; VolName = NULL; } // while() return ScanIt; } // BOOLEAN ShouldScan() // Returns TRUE if the file is byte-for-byte identical with the fallback file // on the volume AND if the file is not itself the fallback file; returns // FALSE if the file is not identical to the fallback file OR if the file // IS the fallback file. Intended for use in excluding the fallback boot // loader when it's a duplicate of another boot loader. static BOOLEAN DuplicatesFallback(IN REFIT_VOLUME *Volume, IN CHAR16 *FileName) { CHAR8 *FileContents, *FallbackContents; EFI_FILE_HANDLE FileHandle, FallbackHandle; EFI_FILE_INFO *FileInfo, *FallbackInfo; UINTN FileSize = 0, FallbackSize = 0; EFI_STATUS Status; BOOLEAN AreIdentical = FALSE; if (!FileExists(Volume->RootDir, FileName) || !FileExists(Volume->RootDir, FALLBACK_FULLNAME)) return FALSE; CleanUpPathNameSlashes(FileName); if (MyStriCmp(FileName, FALLBACK_FULLNAME)) return FALSE; // identical filenames, so not a duplicate.... Status = refit_call5_wrapper(Volume->RootDir->Open, Volume->RootDir, &FileHandle, FileName, EFI_FILE_MODE_READ, 0); if (Status == EFI_SUCCESS) { FileInfo = LibFileInfo(FileHandle); FileSize = FileInfo->FileSize; } else { return FALSE; } Status = refit_call5_wrapper(Volume->RootDir->Open, Volume->RootDir, &FallbackHandle, FALLBACK_FULLNAME, EFI_FILE_MODE_READ, 0); if (Status == EFI_SUCCESS) { FallbackInfo = LibFileInfo(FallbackHandle); FallbackSize = FallbackInfo->FileSize; } else { refit_call1_wrapper(FileHandle->Close, FileHandle); return FALSE; } if (FallbackSize == FileSize) { // could be identical; do full check.... FileContents = AllocatePool(FileSize); FallbackContents = AllocatePool(FallbackSize); if (FileContents && FallbackContents) { Status = refit_call3_wrapper(FileHandle->Read, FileHandle, &FileSize, FileContents); if (Status == EFI_SUCCESS) { Status = refit_call3_wrapper(FallbackHandle->Read, FallbackHandle, &FallbackSize, FallbackContents); } if (Status == EFI_SUCCESS) { AreIdentical = (CompareMem(FileContents, FallbackContents, FileSize) == 0); } // if } // if MyFreePool(FileContents); MyFreePool(FallbackContents); } // if/else // BUG ALERT: Some systems (e.g., DUET, some Macs with large displays) crash if the // following two calls are reversed. Go figure.... refit_call1_wrapper(FileHandle->Close, FallbackHandle); refit_call1_wrapper(FileHandle->Close, FileHandle); return AreIdentical; } // BOOLEAN DuplicatesFallback() // Returns FALSE if two measures of file size are identical for a single file, // TRUE if not or if the file can't be opened and the other measure is non-0. // Despite the function's name, this isn't really a direct test of symbolic // link status, since EFI doesn't officially support symlinks. It does seem // to be a reliable indicator, though. (OTOH, some disk errors might cause a // file to fail to open, which would return a false positive -- but as I use // this function to exclude symbolic links from the list of boot loaders, // that would be fine, since such boot loaders wouldn't work.) // CAUTION: *FullName MUST be properly cleaned up (via CleanUpPathNameSlashes()) static BOOLEAN IsSymbolicLink(REFIT_VOLUME *Volume, CHAR16 *FullName, EFI_FILE_INFO *DirEntry) { EFI_FILE_HANDLE FileHandle; EFI_FILE_INFO *FileInfo = NULL; EFI_STATUS Status; UINTN FileSize2 = 0; Status = refit_call5_wrapper(Volume->RootDir->Open, Volume->RootDir, &FileHandle, FullName, EFI_FILE_MODE_READ, 0); if (Status == EFI_SUCCESS) { FileInfo = LibFileInfo(FileHandle); if (FileInfo != NULL) FileSize2 = FileInfo->FileSize; } MyFreePool(FileInfo); return (DirEntry->FileSize != FileSize2); } // BOOLEAN IsSymbolicLink() // Returns TRUE if a file with the same name as the original but with // ".efi.signed" is also present in the same directory. Ubuntu is using // this filename as a signed version of the original unsigned kernel, and // there's no point in cluttering the display with two kernels that will // behave identically on non-SB systems, or when one will fail when SB // is active. // CAUTION: *FullName MUST be properly cleaned up (via CleanUpPathNameSlashes()) static BOOLEAN HasSignedCounterpart(IN REFIT_VOLUME *Volume, IN CHAR16 *FullName) { CHAR16 *NewFile = NULL; BOOLEAN retval = FALSE; MergeStrings(&NewFile, FullName, 0); MergeStrings(&NewFile, L".efi.signed", 0); if (NewFile != NULL) { if (FileExists(Volume->RootDir, NewFile)) retval = TRUE; MyFreePool(NewFile); } // if return retval; } // BOOLEAN HasSignedCounterpart() // Scan an individual directory for EFI boot loader files and, if found, // add them to the list. Exception: Ignores FALLBACK_FULLNAME, which is picked // up in ScanEfiFiles(). Sorts the entries within the loader directory so that // the most recent one appears first in the list. // Returns TRUE if a duplicate for FALLBACK_FILENAME was found, FALSE if not. static BOOLEAN ScanLoaderDir(IN REFIT_VOLUME *Volume, IN CHAR16 *Path, IN CHAR16 *Pattern) { EFI_STATUS Status; REFIT_DIR_ITER DirIter; EFI_FILE_INFO *DirEntry; CHAR16 Message[256], *Extension, *FullName; struct LOADER_LIST *LoaderList = NULL, *NewLoader; LOADER_ENTRY *FirstKernel = NULL, *LatestEntry = NULL; BOOLEAN FoundFallbackDuplicate = FALSE, IsLinux = FALSE, InSelfPath; InSelfPath = MyStriCmp(Path, SelfDirPath); if ((!SelfDirPath || !Path || (InSelfPath && (Volume->DeviceHandle != SelfVolume->DeviceHandle)) || (!InSelfPath)) && (ShouldScan(Volume, Path))) { // look through contents of the directory DirIterOpen(Volume->RootDir, Path, &DirIter); while (DirIterNext(&DirIter, 2, Pattern, &DirEntry)) { Extension = FindExtension(DirEntry->FileName); FullName = StrDuplicate(Path); MergeStrings(&FullName, DirEntry->FileName, L'\\'); CleanUpPathNameSlashes(FullName); if (DirEntry->FileName[0] == '.' || MyStriCmp(Extension, L".icns") || MyStriCmp(Extension, L".png") || (MyStriCmp(DirEntry->FileName, FALLBACK_BASENAME) && (MyStriCmp(Path, L"EFI\\BOOT"))) || FilenameIn(Volume, Path, DirEntry->FileName, SHELL_NAMES) || IsSymbolicLink(Volume, FullName, DirEntry) || /* is symbolic link */ HasSignedCounterpart(Volume, FullName) || /* a file with same name plus ".efi.signed" is present */ FilenameIn(Volume, Path, DirEntry->FileName, GlobalConfig.DontScanFiles) || !IsValidLoader(Volume->RootDir, FullName)) { continue; // skip this } NewLoader = AllocateZeroPool(sizeof(struct LOADER_LIST)); if (NewLoader != NULL) { NewLoader->FileName = StrDuplicate(FullName); NewLoader->TimeStamp = DirEntry->ModificationTime; LoaderList = AddLoaderListEntry(LoaderList, NewLoader); if (DuplicatesFallback(Volume, FullName)) FoundFallbackDuplicate = TRUE; } // if MyFreePool(Extension); MyFreePool(FullName); } // while NewLoader = LoaderList; while (NewLoader != NULL) { IsLinux = (StriSubCmp(L"bzImage", NewLoader->FileName) || StriSubCmp(L"vmlinuz", NewLoader->FileName) || StriSubCmp(L"kernel", NewLoader->FileName)); if ((FirstKernel != NULL) && IsLinux && GlobalConfig.FoldLinuxKernels) { AddKernelToSubmenu(FirstKernel, NewLoader->FileName, Volume); } else { LatestEntry = AddLoaderEntry(NewLoader->FileName, NULL, Volume, !(IsLinux && GlobalConfig.FoldLinuxKernels)); if (IsLinux && (FirstKernel == NULL)) FirstKernel = LatestEntry; } NewLoader = NewLoader->NextEntry; } // while if ((NewLoader != NULL) && (FirstKernel != NULL) && IsLinux && GlobalConfig.FoldLinuxKernels) AddMenuEntry(FirstKernel->me.SubScreen, &MenuEntryReturn); CleanUpLoaderList(LoaderList); Status = DirIterClose(&DirIter); // NOTE: EFI_INVALID_PARAMETER really is an error that should be reported; // but I've gotten reports from users who are getting this error occasionally // and I can't find anything wrong or reproduce the problem, so I'm putting // it down to buggy EFI implementations and ignoring that particular error.... if ((Status != EFI_NOT_FOUND) && (Status != EFI_INVALID_PARAMETER)) { if (Path) SPrint(Message, 255, L"while scanning the %s directory on %s", Path, Volume->VolName); else SPrint(Message, 255, L"while scanning the root directory on %s", Path, Volume->VolName); CheckError(Status, Message); } // if (Status != EFI_NOT_FOUND) } // if not scanning a blacklisted directory return FoundFallbackDuplicate; } /* static VOID ScanLoaderDir() */ // Run the IPXE_DISCOVER_NAME program, which obtains the IP address of the boot // server and the name of the boot file it delivers. CHAR16* RuniPXEDiscover(EFI_HANDLE Volume) { EFI_STATUS Status; EFI_DEVICE_PATH *FilePath; EFI_HANDLE iPXEHandle; CHAR16 *boot_info = NULL; UINTN boot_info_size = 0; FilePath = FileDevicePath (Volume, IPXE_DISCOVER_NAME); Status = refit_call6_wrapper(BS->LoadImage, FALSE, SelfImageHandle, FilePath, NULL, 0, &iPXEHandle); if (Status != 0) return NULL; Status = refit_call3_wrapper(BS->StartImage, iPXEHandle, &boot_info_size, &boot_info); return boot_info; } // RuniPXEDiscover() // Scan for network (PXE) boot servers. This function relies on the presence // of the IPXE_DISCOVER_NAME and IPXE_NAME program files on the volume from // which rEFInd launched. As of December 6, 2014, these tools aren't entirely // reliable. See BUILDING.txt for information on building them. static VOID ScanNetboot() { CHAR16 *iPXEFileName = IPXE_NAME; CHAR16 *Location; REFIT_VOLUME *NetVolume; if (FileExists(SelfVolume->RootDir, IPXE_DISCOVER_NAME) && FileExists(SelfVolume->RootDir, IPXE_NAME) && IsValidLoader(SelfVolume->RootDir, IPXE_DISCOVER_NAME) && IsValidLoader(SelfVolume->RootDir, IPXE_NAME)) { Location = RuniPXEDiscover(SelfVolume->DeviceHandle); if (Location != NULL && FileExists(SelfVolume->RootDir, iPXEFileName)) { NetVolume = AllocatePool(sizeof(REFIT_VOLUME)); CopyMem(NetVolume, SelfVolume, sizeof(REFIT_VOLUME)); NetVolume->DiskKind = DISK_KIND_NET; NetVolume->VolBadgeImage = BuiltinIcon(BUILTIN_ICON_VOL_NET); NetVolume->PartName = NetVolume->VolName = NULL; AddLoaderEntry(iPXEFileName, Location, NetVolume, TRUE); MyFreePool(NetVolume); } // if support files exist and are valid } } // VOID ScanNetBoot() static VOID ScanEfiFiles(REFIT_VOLUME *Volume) { EFI_STATUS Status; REFIT_DIR_ITER EfiDirIter; EFI_FILE_INFO *EfiDirEntry; CHAR16 FileName[256], *Directory = NULL, *MatchPatterns, *VolName = NULL, *SelfPath, *Temp; UINTN i, Length; BOOLEAN ScanFallbackLoader = TRUE; BOOLEAN FoundBRBackup = FALSE; if (Volume && (Volume->RootDir != NULL) && (Volume->VolName != NULL) && (Volume->IsReadable)) { MatchPatterns = StrDuplicate(LOADER_MATCH_PATTERNS); if (GlobalConfig.ScanAllLinux) MergeStrings(&MatchPatterns, LINUX_MATCH_PATTERNS, L','); // check for macOS boot loader if (ShouldScan(Volume, MACOSX_LOADER_DIR)) { StrCpy(FileName, MACOSX_LOADER_PATH); if (FileExists(Volume->RootDir, FileName) && !FilenameIn(Volume, MACOSX_LOADER_DIR, L"boot.efi", GlobalConfig.DontScanFiles)) { AddLoaderEntry(FileName, L"macOS", Volume, TRUE); if (DuplicatesFallback(Volume, FileName)) ScanFallbackLoader = FALSE; } // check for XOM StrCpy(FileName, L"System\\Library\\CoreServices\\xom.efi"); if (FileExists(Volume->RootDir, FileName) && !FilenameIn(Volume, MACOSX_LOADER_DIR, L"xom.efi", GlobalConfig.DontScanFiles)) { AddLoaderEntry(FileName, L"Windows XP (XoM)", Volume, TRUE); if (DuplicatesFallback(Volume, FileName)) ScanFallbackLoader = FALSE; } } // if should scan Mac directory // check for Microsoft boot loader/menu if (ShouldScan(Volume, L"EFI\\Microsoft\\Boot")) { StrCpy(FileName, L"EFI\\Microsoft\\Boot\\bkpbootmgfw.efi"); if (FileExists(Volume->RootDir, FileName) && !FilenameIn(Volume, L"EFI\\Microsoft\\Boot", L"bkpbootmgfw.efi", GlobalConfig.DontScanFiles)) { AddLoaderEntry(FileName, L"Microsoft EFI boot (Boot Repair backup)", Volume, TRUE); FoundBRBackup = TRUE; if (DuplicatesFallback(Volume, FileName)) ScanFallbackLoader = FALSE; } StrCpy(FileName, L"EFI\\Microsoft\\Boot\\bootmgfw.efi"); if (FileExists(Volume->RootDir, FileName) && !FilenameIn(Volume, L"EFI\\Microsoft\\Boot", L"bootmgfw.efi", GlobalConfig.DontScanFiles)) { if (FoundBRBackup) AddLoaderEntry(FileName, L"Supposed Microsoft EFI boot (probably GRUB)", Volume, TRUE); else AddLoaderEntry(FileName, L"Microsoft EFI boot", Volume, TRUE); if (DuplicatesFallback(Volume, FileName)) ScanFallbackLoader = FALSE; } } // if // scan the root directory for EFI executables if (ScanLoaderDir(Volume, L"\\", MatchPatterns)) ScanFallbackLoader = FALSE; // scan subdirectories of the EFI directory (as per the standard) DirIterOpen(Volume->RootDir, L"EFI", &EfiDirIter); while (DirIterNext(&EfiDirIter, 1, NULL, &EfiDirEntry)) { if (MyStriCmp(EfiDirEntry->FileName, L"tools") || EfiDirEntry->FileName[0] == '.') continue; // skip this, doesn't contain boot loaders or is scanned later SPrint(FileName, 255, L"EFI\\%s", EfiDirEntry->FileName); if (ScanLoaderDir(Volume, FileName, MatchPatterns)) ScanFallbackLoader = FALSE; } // while() Status = DirIterClose(&EfiDirIter); if ((Status != EFI_NOT_FOUND) && (Status != EFI_INVALID_PARAMETER)) { Temp = PoolPrint(L"while scanning the EFI directory on %s", Volume->VolName); CheckError(Status, Temp); MyFreePool(Temp); } // if // Scan user-specified (or additional default) directories.... i = 0; while ((Directory = FindCommaDelimited(GlobalConfig.AlsoScan, i++)) != NULL) { if (ShouldScan(Volume, Directory)) { SplitVolumeAndFilename(&Directory, &VolName); CleanUpPathNameSlashes(Directory); Length = StrLen(Directory); if ((Length > 0) && ScanLoaderDir(Volume, Directory, MatchPatterns)) ScanFallbackLoader = FALSE; MyFreePool(VolName); } // if should scan dir MyFreePool(Directory); } // while // Don't scan the fallback loader if it's on the same volume and a duplicate of rEFInd itself.... SelfPath = DevicePathToStr(SelfLoadedImage->FilePath); CleanUpPathNameSlashes(SelfPath); if ((Volume->DeviceHandle == SelfLoadedImage->DeviceHandle) && DuplicatesFallback(Volume, SelfPath)) ScanFallbackLoader = FALSE; // If not a duplicate & if it exists & if it's not us, create an entry // for the fallback boot loader if (ScanFallbackLoader && FileExists(Volume->RootDir, FALLBACK_FULLNAME) && ShouldScan(Volume, L"EFI\\BOOT") && !FilenameIn(Volume, L"EFI\\BOOT", FALLBACK_BASENAME, GlobalConfig.DontScanFiles)) { AddLoaderEntry(FALLBACK_FULLNAME, L"Fallback boot loader", Volume, TRUE); } } // if } // static VOID ScanEfiFiles() // Scan internal disks for valid EFI boot loaders.... static VOID ScanInternal(VOID) { UINTN VolumeIndex; for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) { if (Volumes[VolumeIndex]->DiskKind == DISK_KIND_INTERNAL) { ScanEfiFiles(Volumes[VolumeIndex]); } } // for } // static VOID ScanInternal() // Scan external disks for valid EFI boot loaders.... static VOID ScanExternal(VOID) { UINTN VolumeIndex; for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) { if (Volumes[VolumeIndex]->DiskKind == DISK_KIND_EXTERNAL) { ScanEfiFiles(Volumes[VolumeIndex]); } } // for } // static VOID ScanExternal() // Scan internal disks for valid EFI boot loaders.... static VOID ScanOptical(VOID) { UINTN VolumeIndex; for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) { if (Volumes[VolumeIndex]->DiskKind == DISK_KIND_OPTICAL) { ScanEfiFiles(Volumes[VolumeIndex]); } } // for } // static VOID ScanOptical() // default volume badge icon based on disk kind EG_IMAGE * GetDiskBadge(IN UINTN DiskType) { EG_IMAGE * Badge = NULL; switch (DiskType) { case BBS_HARDDISK: Badge = BuiltinIcon(BUILTIN_ICON_VOL_INTERNAL); break; case BBS_USB: Badge = BuiltinIcon(BUILTIN_ICON_VOL_EXTERNAL); break; case BBS_CDROM: Badge = BuiltinIcon(BUILTIN_ICON_VOL_OPTICAL); break; } // switch() return Badge; } // EG_IMAGE * GetDiskBadge() // // pre-boot tool functions // static VOID StartTool(IN LOADER_ENTRY *Entry) { BeginExternalScreen(Entry->UseGraphicsMode, Entry->me.Title + 6); // assumes "Start " as assigned below StoreLoaderName(Entry->me.Title); StartEFIImage(Entry->DevicePath, Entry->LoadOptions, TYPE_EFI, Basename(Entry->LoaderPath), Entry->OSType, NULL, TRUE, FALSE); FinishExternalScreen(); } /* static VOID StartTool() */ static LOADER_ENTRY * AddToolEntry(EFI_HANDLE DeviceHandle, IN CHAR16 *LoaderPath, IN CHAR16 *LoaderTitle, IN EG_IMAGE *Image, IN CHAR16 ShortcutLetter, IN BOOLEAN UseGraphicsMode) { LOADER_ENTRY *Entry; CHAR16 *TitleStr = NULL; Entry = AllocateZeroPool(sizeof(LOADER_ENTRY)); TitleStr = PoolPrint(L"Start %s", LoaderTitle); Entry->me.Title = TitleStr; Entry->me.Tag = TAG_TOOL; Entry->me.Row = 1; Entry->me.ShortcutLetter = ShortcutLetter; Entry->me.Image = Image; Entry->LoaderPath = (LoaderPath) ? StrDuplicate(LoaderPath) : NULL; Entry->DevicePath = FileDevicePath(DeviceHandle, Entry->LoaderPath); Entry->UseGraphicsMode = UseGraphicsMode; AddMenuEntry(&MainMenu, (REFIT_MENU_ENTRY *)Entry); return Entry; } /* static LOADER_ENTRY * AddToolEntry() */ // Locates boot loaders. NOTE: This assumes that GlobalConfig.LegacyType is set correctly. static VOID ScanForBootloaders(BOOLEAN ShowMessage) { UINTN i; CHAR8 s; BOOLEAN ScanForLegacy = FALSE; EG_PIXEL BGColor = COLOR_LIGHTBLUE; CHAR16 *HiddenTags; if (ShowMessage) egDisplayMessage(L"Scanning for boot loaders; please wait....", &BGColor, CENTER); // Determine up-front if we'll be scanning for legacy loaders.... for (i = 0; i < NUM_SCAN_OPTIONS; i++) { s = GlobalConfig.ScanFor[i]; if ((s == 'c') || (s == 'C') || (s == 'h') || (s == 'H') || (s == 'b') || (s == 'B')) ScanForLegacy = TRUE; } // for // If UEFI & scanning for legacy loaders & deep legacy scan, update NVRAM boot manager list if ((GlobalConfig.LegacyType == LEGACY_TYPE_UEFI) && ScanForLegacy && GlobalConfig.DeepLegacyScan) { BdsDeleteAllInvalidLegacyBootOptions(); BdsAddNonExistingLegacyBootOptions(); } // if HiddenTags = ReadHiddenTags(L"HiddenTags"); if ((HiddenTags) && (StrLen(HiddenTags) > 0)) { MergeStrings(&GlobalConfig.DontScanFiles, HiddenTags, L','); } HiddenTags = ReadHiddenTags(L"HiddenLegacy"); if ((HiddenTags) && (StrLen(HiddenTags) > 0)) { MergeStrings(&GlobalConfig.DontScanVolumes, HiddenTags, L','); } MyFreePool(HiddenTags); // scan for loaders and tools, add them to the menu for (i = 0; i < NUM_SCAN_OPTIONS; i++) { switch(GlobalConfig.ScanFor[i]) { case 'c': case 'C': ScanLegacyDisc(); break; case 'h': case 'H': ScanLegacyInternal(); break; case 'b': case 'B': ScanLegacyExternal(); break; case 'm': case 'M': ScanUserConfigured(GlobalConfig.ConfigFilename); break; case 'e': case 'E': ScanExternal(); break; case 'i': case 'I': ScanInternal(); break; case 'o': case 'O': ScanOptical(); break; case 'n': case 'N': ScanNetboot(); break; } // switch() } // for // assign shortcut keys for (i = 0; i < MainMenu.EntryCount && MainMenu.Entries[i]->Row == 0 && i < 9; i++) MainMenu.Entries[i]->ShortcutDigit = (CHAR16)('1' + i); // wait for user ACK when there were errors FinishTextScreen(FALSE); } // static VOID ScanForBootloaders() // Checks to see if a specified file seems to be a valid tool. // Returns TRUE if it passes all tests, FALSE otherwise static BOOLEAN IsValidTool(IN REFIT_VOLUME *BaseVolume, CHAR16 *PathName) { CHAR16 *DontVolName = NULL, *DontPathName = NULL, *DontFileName = NULL, *DontScanThis; CHAR16 *TestVolName = NULL, *TestPathName = NULL, *TestFileName = NULL; BOOLEAN retval = TRUE; UINTN i = 0; if (FileExists(BaseVolume->RootDir, PathName) && IsValidLoader(BaseVolume->RootDir, PathName)) { SplitPathName(PathName, &TestVolName, &TestPathName, &TestFileName); while (retval && (DontScanThis = FindCommaDelimited(GlobalConfig.DontScanTools, i++))) { SplitPathName(DontScanThis, &DontVolName, &DontPathName, &DontFileName); if (MyStriCmp(TestFileName, DontFileName) && ((DontPathName == NULL) || (MyStriCmp(TestPathName, DontPathName))) && ((DontVolName == NULL) || (VolumeMatchesDescription(BaseVolume, DontVolName)))) { retval = FALSE; } // if } // while } else retval = FALSE; MyFreePool(TestVolName); MyFreePool(TestPathName); MyFreePool(TestFileName); return retval; } // VOID IsValidTool() // Locate a single tool from the specified Locations using one of the // specified Names and add it to the menu. static VOID FindTool(CHAR16 *Locations, CHAR16 *Names, CHAR16 *Description, UINTN Icon) { UINTN j = 0, k, VolumeIndex; CHAR16 *DirName, *FileName, *PathName, FullDescription[256]; while ((DirName = FindCommaDelimited(Locations, j++)) != NULL) { k = 0; while ((FileName = FindCommaDelimited(Names, k++)) != NULL) { PathName = StrDuplicate(DirName); MergeStrings(&PathName, FileName, MyStriCmp(PathName, L"\\") ? 0 : L'\\'); for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) { if ((Volumes[VolumeIndex]->RootDir != NULL) && (IsValidTool(Volumes[VolumeIndex], PathName))) { SPrint(FullDescription, 255, L"%s at %s on %s", Description, PathName, Volumes[VolumeIndex]->VolName); AddToolEntry(Volumes[VolumeIndex]->DeviceHandle, PathName, FullDescription, BuiltinIcon(Icon), 'S', FALSE); } // if } // for MyFreePool(PathName); MyFreePool(FileName); } // while Names MyFreePool(DirName); } // while Locations } // VOID FindTool() // Add the second-row tags containing built-in and external tools (EFI shell, // reboot, etc.) static VOID ScanForTools(VOID) { CHAR16 *FileName = NULL, *VolName = NULL, *MokLocations, Description[256], *HiddenTools; REFIT_MENU_ENTRY *TempMenuEntry; UINTN i, j, VolumeIndex; UINT64 osind; CHAR8 *b = 0; UINT32 CsrValue; MokLocations = StrDuplicate(MOK_LOCATIONS); if (MokLocations != NULL) MergeStrings(&MokLocations, SelfDirPath, L','); HiddenTools = ReadHiddenTags(L"HiddenTools"); if ((HiddenTools) && (StrLen(HiddenTools) > 0)) { MergeStrings(&GlobalConfig.DontScanTools, HiddenTools, L','); } MyFreePool(HiddenTools); for (i = 0; i < NUM_TOOLS; i++) { switch(GlobalConfig.ShowTools[i]) { // NOTE: Be sure that FileName is NULL at the end of each case. case TAG_SHUTDOWN: TempMenuEntry = CopyMenuEntry(&MenuEntryShutdown); TempMenuEntry->Image = BuiltinIcon(BUILTIN_ICON_FUNC_SHUTDOWN); AddMenuEntry(&MainMenu, TempMenuEntry); break; case TAG_REBOOT: TempMenuEntry = CopyMenuEntry(&MenuEntryReset); TempMenuEntry->Image = BuiltinIcon(BUILTIN_ICON_FUNC_RESET); AddMenuEntry(&MainMenu, TempMenuEntry); break; case TAG_ABOUT: TempMenuEntry = CopyMenuEntry(&MenuEntryAbout); TempMenuEntry->Image = BuiltinIcon(BUILTIN_ICON_FUNC_ABOUT); AddMenuEntry(&MainMenu, TempMenuEntry); break; case TAG_EXIT: TempMenuEntry = CopyMenuEntry(&MenuEntryExit); TempMenuEntry->Image = BuiltinIcon(BUILTIN_ICON_FUNC_EXIT); AddMenuEntry(&MainMenu, TempMenuEntry); break; case TAG_HIDDEN: if (GlobalConfig.HiddenTags) { TempMenuEntry = CopyMenuEntry(&MenuEntryManageHidden); TempMenuEntry->Image = BuiltinIcon(BUILTIN_ICON_FUNC_HIDDEN); AddMenuEntry(&MainMenu, TempMenuEntry); } break; case TAG_FIRMWARE: if (EfivarGetRaw(&GlobalGuid, L"OsIndicationsSupported", &b, &j) == EFI_SUCCESS) { osind = (UINT64)*b; if (osind & EFI_OS_INDICATIONS_BOOT_TO_FW_UI) { TempMenuEntry = CopyMenuEntry(&MenuEntryFirmware); TempMenuEntry->Image = BuiltinIcon(BUILTIN_ICON_FUNC_FIRMWARE); AddMenuEntry(&MainMenu, TempMenuEntry); } // if } // if break; case TAG_SHELL: j = 0; while ((FileName = FindCommaDelimited(SHELL_NAMES, j++)) != NULL) { if (IsValidTool(SelfVolume, FileName)) { AddToolEntry(SelfLoadedImage->DeviceHandle, FileName, L"EFI Shell", BuiltinIcon(BUILTIN_ICON_TOOL_SHELL), 'S', FALSE); } MyFreePool(FileName); } // while break; case TAG_GPTSYNC: j = 0; while ((FileName = FindCommaDelimited(GPTSYNC_NAMES, j++)) != NULL) { if (IsValidTool(SelfVolume, FileName)) { AddToolEntry(SelfLoadedImage->DeviceHandle, FileName, L"Hybrid MBR tool", BuiltinIcon(BUILTIN_ICON_TOOL_PART), 'P', FALSE); } // if MyFreePool(FileName); } // while FileName = NULL; break; case TAG_GDISK: j = 0; while ((FileName = FindCommaDelimited(GDISK_NAMES, j++)) != NULL) { if (IsValidTool(SelfVolume, FileName)) { AddToolEntry(SelfLoadedImage->DeviceHandle, FileName, L"disk partitioning tool", BuiltinIcon(BUILTIN_ICON_TOOL_PART), 'G', FALSE); } // if MyFreePool(FileName); } // while FileName = NULL; break; case TAG_NETBOOT: j = 0; while ((FileName = FindCommaDelimited(NETBOOT_NAMES, j++)) != NULL) { if (IsValidTool(SelfVolume, FileName)) { AddToolEntry(SelfLoadedImage->DeviceHandle, FileName, L"Netboot", BuiltinIcon(BUILTIN_ICON_TOOL_NETBOOT), 'N', FALSE); } // if MyFreePool(FileName); } // while FileName = NULL; break; case TAG_APPLE_RECOVERY: FileName = StrDuplicate(L"\\com.apple.recovery.boot\\boot.efi"); for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) { if ((Volumes[VolumeIndex]->RootDir != NULL) && (IsValidTool(SelfVolume, FileName))) { SPrint(Description, 255, L"Apple Recovery on %s", Volumes[VolumeIndex]->VolName); AddToolEntry(Volumes[VolumeIndex]->DeviceHandle, FileName, Description, BuiltinIcon(BUILTIN_ICON_TOOL_APPLE_RESCUE), 'R', TRUE); } // if } // for MyFreePool(FileName); FileName = NULL; break; case TAG_WINDOWS_RECOVERY: j = 0; while ((FileName = FindCommaDelimited(GlobalConfig.WindowsRecoveryFiles, j++)) != NULL) { SplitVolumeAndFilename(&FileName, &VolName); for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) { if ((Volumes[VolumeIndex]->RootDir != NULL) && (IsValidTool(SelfVolume, FileName)) && ((VolName == NULL) || MyStriCmp(VolName, Volumes[VolumeIndex]->VolName))) { SPrint(Description, 255, L"Microsoft Recovery on %s", Volumes[VolumeIndex]->VolName); AddToolEntry(Volumes[VolumeIndex]->DeviceHandle, FileName, Description, BuiltinIcon(BUILTIN_ICON_TOOL_WINDOWS_RESCUE), 'R', TRUE); } // if } // for } // while MyFreePool(FileName); FileName = NULL; MyFreePool(VolName); VolName = NULL; break; case TAG_MOK_TOOL: FindTool(MokLocations, MOK_NAMES, L"MOK utility", BUILTIN_ICON_TOOL_MOK_TOOL); break; case TAG_FWUPDATE_TOOL: FindTool(MokLocations, FWUPDATE_NAMES, L"firmware update utility", BUILTIN_ICON_TOOL_FWUPDATE); break; case TAG_CSR_ROTATE: if ((GetCsrStatus(&CsrValue) == EFI_SUCCESS) && (GlobalConfig.CsrValues)) { TempMenuEntry = CopyMenuEntry(&MenuEntryRotateCsr); TempMenuEntry->Image = BuiltinIcon(BUILTIN_ICON_FUNC_CSR_ROTATE); AddMenuEntry(&MainMenu, TempMenuEntry); } // if break; case TAG_MEMTEST: FindTool(MEMTEST_LOCATIONS, MEMTEST_NAMES, L"Memory test utility", BUILTIN_ICON_TOOL_MEMTEST); break; } // switch() } // for } // static VOID ScanForTools // Rescan for boot loaders VOID RescanAll(BOOLEAN DisplayMessage) { FreeList((VOID ***) &(MainMenu.Entries), &MainMenu.EntryCount); MainMenu.Entries = NULL; MainMenu.EntryCount = 0; ConnectAllDriversToAllControllers(); ScanVolumes(); ReadConfig(GlobalConfig.ConfigFilename); SetVolumeIcons(); ScanForBootloaders(TRUE); ScanForTools(); } // VOID RescanAll() #ifdef __MAKEWITH_TIANO // Minimal initialization function static VOID InitializeLib(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable) { gST = SystemTable; // gImageHandle = ImageHandle; gBS = SystemTable->BootServices; // gRS = SystemTable->RuntimeServices; gRT = SystemTable->RuntimeServices; // Some BDS functions need gRT to be set EfiGetSystemConfigurationTable (&gEfiDxeServicesTableGuid, (VOID **) &gDS); } #endif // Set up our own Secure Boot extensions.... // Returns TRUE on success, FALSE otherwise static BOOLEAN SecureBootSetup(VOID) { EFI_STATUS Status; BOOLEAN Success = FALSE; if (secure_mode() && ShimLoaded()) { Status = security_policy_install(); if (Status == EFI_SUCCESS) { Success = TRUE; } else { Print(L"Failed to install MOK Secure Boot extensions"); PauseForKey(); } } return Success; } // VOID SecureBootSetup() // Remove our own Secure Boot extensions.... // Returns TRUE on success, FALSE otherwise static BOOLEAN SecureBootUninstall(VOID) { EFI_STATUS Status; BOOLEAN Success = TRUE; if (secure_mode()) { Status = security_policy_uninstall(); if (Status != EFI_SUCCESS) { Success = FALSE; BeginTextScreen(L"Secure Boot Policy Failure"); Print(L"Failed to uninstall MOK Secure Boot extensions; forcing a reboot."); PauseForKey(); refit_call4_wrapper(RT->ResetSystem, EfiResetCold, EFI_SUCCESS, 0, NULL); } } return Success; } // VOID SecureBootUninstall // Sets the global configuration filename; will be CONFIG_FILE_NAME unless the // "-c" command-line option is set, in which case that takes precedence. // If an error is encountered, leaves the value alone (it should be set to // CONFIG_FILE_NAME when GlobalConfig is initialized). static VOID SetConfigFilename(EFI_HANDLE ImageHandle) { EFI_LOADED_IMAGE *Info; CHAR16 *Options, *FileName, *SubString; EFI_STATUS Status; Status = refit_call3_wrapper(BS->HandleProtocol, ImageHandle, &LoadedImageProtocol, (VOID **) &Info); if ((Status == EFI_SUCCESS) && (Info->LoadOptionsSize > 0)) { Options = (CHAR16 *) Info->LoadOptions; SubString = MyStrStr(Options, L" -c "); if (SubString) { FileName = StrDuplicate(&SubString[4]); if (FileName) { LimitStringLength(FileName, 256); } if (FileExists(SelfDir, FileName)) { GlobalConfig.ConfigFilename = FileName; } else { Print(L"Specified configuration file (%s) doesn't exist; using\n'refind.conf' default\n", FileName); MyFreePool(FileName); } // if/else } // if } // if } // VOID SetConfigFilename() // // main entry point // EFI_STATUS EFIAPI efi_main (EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) { EFI_STATUS Status; BOOLEAN MainLoopRunning = TRUE; BOOLEAN MokProtocol; REFIT_MENU_ENTRY *ChosenEntry; UINTN MenuExit, i; CHAR16 *SelectionName = NULL; EG_PIXEL BGColor = COLOR_LIGHTBLUE; // bootstrap InitializeLib(ImageHandle, SystemTable); Status = InitRefitLib(ImageHandle); if (EFI_ERROR(Status)) return Status; // read configuration CopyMem(GlobalConfig.ScanFor, "ieom ", NUM_SCAN_OPTIONS); FindLegacyBootType(); if (GlobalConfig.LegacyType == LEGACY_TYPE_MAC) CopyMem(GlobalConfig.ScanFor, "ihebocm ", NUM_SCAN_OPTIONS); SetConfigFilename(ImageHandle); MokProtocol = SecureBootSetup(); LoadDrivers(); ScanVolumes(); // Do before ReadConfig() because it needs SelfVolume->VolName ReadConfig(GlobalConfig.ConfigFilename); SetVolumeIcons(); if (GlobalConfig.SpoofOSXVersion && GlobalConfig.SpoofOSXVersion[0] != L'\0') SetAppleOSInfo(); InitScreen(); WarnIfLegacyProblems(); MainMenu.TimeoutSeconds = GlobalConfig.Timeout; // disable EFI watchdog timer refit_call4_wrapper(BS->SetWatchdogTimer, 0x0000, 0x0000, 0x0000, NULL); // further bootstrap (now with config available) SetupScreen(); <<<<<<< HEAD ScanForBootloaders(GlobalConfig.ScanDelay == 0); ScanForTools(); // SetupScreen() clears the screen; but ScanForBootloaders() may display a // message that must be deleted, so do so BltClearScreen(TRUE); ======= pdInitialize(); >>>>>>> d63734581c19715b3dc13ab89c520def8d5c4566 if (GlobalConfig.ScanDelay > 0) { if (GlobalConfig.ScanDelay > 1) egDisplayMessage(L"Pausing before disk scan; please wait....", &BGColor, CENTER); for (i = 0; i < GlobalConfig.ScanDelay; i++) refit_call1_wrapper(BS->Stall, 1000000); BltClearScreen(TRUE); RescanAll(GlobalConfig.ScanDelay > 1); } // if if (GlobalConfig.DefaultSelection) SelectionName = StrDuplicate(GlobalConfig.DefaultSelection); while (MainLoopRunning) { MenuExit = RunMainMenu(&MainMenu, &SelectionName, &ChosenEntry); // The Escape key triggers a re-scan operation.... if (MenuExit == MENU_EXIT_ESCAPE) { MenuExit = 0; RescanAll(TRUE); continue; } switch (ChosenEntry->Tag) { case TAG_REBOOT: // Reboot TerminateScreen(); refit_call4_wrapper(RT->ResetSystem, EfiResetCold, EFI_SUCCESS, 0, NULL); MainLoopRunning = FALSE; // just in case we get this far break; case TAG_SHUTDOWN: // Shut Down TerminateScreen(); refit_call4_wrapper(RT->ResetSystem, EfiResetShutdown, EFI_SUCCESS, 0, NULL); MainLoopRunning = FALSE; // just in case we get this far break; case TAG_ABOUT: // About rEFInd AboutrEFInd(); break; case TAG_LOADER: // Boot OS via .EFI loader StartLoader((LOADER_ENTRY *)ChosenEntry, SelectionName); break; case TAG_LEGACY: // Boot legacy OS StartLegacy((LEGACY_ENTRY *)ChosenEntry, SelectionName); break; case TAG_LEGACY_UEFI: // Boot a legacy OS on a non-Mac StartLegacyUEFI((LEGACY_ENTRY *)ChosenEntry, SelectionName); break; case TAG_TOOL: // Start a EFI tool StartTool((LOADER_ENTRY *)ChosenEntry); break; case TAG_HIDDEN: // Manage hidden tag entries ManageHiddenTags(); break; case TAG_EXIT: // Terminate rEFInd if ((MokProtocol) && !SecureBootUninstall()) { MainLoopRunning = FALSE; // just in case we get this far } else { BeginTextScreen(L" "); return EFI_SUCCESS; } break; case TAG_FIRMWARE: // Reboot into firmware's user interface RebootIntoFirmware(); break; case TAG_CSR_ROTATE: RotateCsrValue(); break; } // switch() } // while() // If we end up here, things have gone wrong. Try to reboot, and if that // fails, go into an endless loop. refit_call4_wrapper(RT->ResetSystem, EfiResetCold, EFI_SUCCESS, 0, NULL); EndlessIdleLoop(); return EFI_SUCCESS; } /* efi_main() */ �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/refind/mystrings.h��������������������������������������������������������������������0000664�0001750�0001750�00000004510�13141476117�016776� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * refit/mystrings.h * String functions header file * * Copyright (c) 2012-2015 Roderick W. Smith * * Distributed under the terms of the GNU General Public License (GPL) * version 3 (GPLv3), or (at your option) any later version. * */ /* * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __MYSTRINGS_H_ #define __MYSTRINGS_H_ #ifdef __MAKEWITH_GNUEFI #include <efi.h> #include <efilib.h> #else #include "../include/tiano_includes.h" #endif #include "../EfiLib/GenericBdsLib.h" typedef struct _string_list { CHAR16 *Value; struct _string_list *Next; } STRING_LIST; BOOLEAN StriSubCmp(IN CHAR16 *TargetStr, IN CHAR16 *BigStr); BOOLEAN MyStriCmp(IN CONST CHAR16 *String1, IN CONST CHAR16 *String2); CHAR16* MyStrStr (IN CHAR16 *String, IN CHAR16 *StrCharSet); VOID ToLower(CHAR16 * MyString); VOID MergeStrings(IN OUT CHAR16 **First, IN CHAR16 *Second, CHAR16 AddChar); VOID MergeWords(CHAR16 **MergeTo, CHAR16 *InString, CHAR16 AddChar); BOOLEAN LimitStringLength(CHAR16 *TheString, UINTN Limit); CHAR16 *FindNumbers(IN CHAR16 *InString); UINTN NumCharsInCommon(IN CHAR16* String1, IN CHAR16* String2); CHAR16 *FindCommaDelimited(IN CHAR16 *InString, IN UINTN Index); BOOLEAN DeleteItemFromCsvList(CHAR16 *ToDelete, CHAR16 *List); BOOLEAN IsIn(IN CHAR16 *SmallString, IN CHAR16 *List); BOOLEAN IsInSubstring(IN CHAR16 *BigString, IN CHAR16 *List); BOOLEAN ReplaceSubstring(IN OUT CHAR16 **MainString, IN CHAR16 *SearchString, IN CHAR16 *ReplString); BOOLEAN IsValidHex(CHAR16 *Input); UINT64 StrToHex(CHAR16 *Input, UINTN Position, UINTN NumChars); BOOLEAN IsGuid(CHAR16 *UnknownString); CHAR16 * GuidAsString(EFI_GUID *GuidData); EFI_GUID StringAsGuid(CHAR16 * InString); VOID DeleteStringList(STRING_LIST *StringList); #endif����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/refind/legacy.h�����������������������������������������������������������������������0000664�0001750�0001750�00000004330�12651436544�016210� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * refind/legacy.h * Functions related to BIOS/CSM/legacy booting * * Copyright (c) 2006 Christoph Pfisterer * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * * Neither the name of Christoph Pfisterer nor the names of the * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Modifications copyright (c) 2012-2015 Roderick W. Smith * * Modifications distributed under the terms of the GNU General Public * License (GPL) version 3 (GPLv3), a copy of which must be distributed * with this source code or binaries made from it. * */ #include "global.h" VOID ScanShell(VOID); VOID StartLegacy(IN LEGACY_ENTRY *Entry, IN CHAR16 *SelectionName); VOID StartLegacyUEFI(LEGACY_ENTRY *Entry, CHAR16 *SelectionName); VOID ScanLegacyDisc(VOID); VOID ScanLegacyInternal(VOID); VOID ScanLegacyExternal(VOID); VOID FindLegacyBootType(VOID); VOID WarnIfLegacyProblems(VOID); ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/refind/gpt.h��������������������������������������������������������������������������0000664�0001750�0001750�00000004004�12626644770�015540� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * refind/gpt.h * Functions related to GPT data structures * * Copyright (c) 2014-2015 Roderick W. Smith * All rights reserved. * * This program is distributed under the terms of the GNU General Public * License (GPL) version 3 (GPLv3), a copy of which must be distributed * with this source code or binaries made from it. * */ #include "global.h" #ifndef __GPT_H_ #define __GPT_H_ #ifdef __MAKEWITH_GNUEFI #include "efi.h" #include "efilib.h" #else #include "../include/tiano_includes.h" #endif #pragma pack(1) typedef struct { UINT8 flags; UINT8 start_chs[3]; UINT8 type; UINT8 end_chs[3]; UINT32 start_lba; UINT32 size; } MBR_PART_INFO; // A 512-byte data structure into which the MBR can be loaded in one // go. Also used when loading logical partitions. typedef struct { UINT8 code[440]; UINT32 diskSignature; UINT16 nulls; MBR_PART_INFO partitions[4]; UINT16 MBRSignature; } MBR_RECORD; typedef struct { UINT64 signature; UINT32 spec_revision; UINT32 header_size; UINT32 header_crc32; UINT32 reserved; UINT64 header_lba; UINT64 alternate_header_lba; UINT64 first_usable_lba; UINT64 last_usable_lba; UINT8 disk_guid[16]; UINT64 entry_lba; UINT32 entry_count; UINT32 entry_size; UINT32 entry_crc32; UINT8 reserved2[420]; } GPT_HEADER; typedef struct { UINT8 type_guid[16]; UINT8 partition_guid[16]; UINT64 start_lba; UINT64 end_lba; UINT64 attributes; CHAR16 name[36]; } GPT_ENTRY; typedef struct _gpt_data { MBR_RECORD *ProtectiveMBR; GPT_HEADER *Header; GPT_ENTRY *Entries; struct _gpt_data *NextEntry; } GPT_DATA; #pragma pack(0) VOID ClearGptData(GPT_DATA *Data); EFI_STATUS ReadGptData(REFIT_VOLUME *Volume, GPT_DATA **Data); // CHAR16 * PartNameFromGuid(EFI_GUID *Guid); GPT_ENTRY * FindPartWithGuid(EFI_GUID *Guid); VOID ForgetPartitionTables(VOID); VOID AddPartitionTable(REFIT_VOLUME *Volume); #endif����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/refind/icns.c�������������������������������������������������������������������������0000664�0001750�0001750�00000013505�13143415241�015663� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * refit/icns.c * Loader for .icns icon files * * Copyright (c) 2006-2007 Christoph Pfisterer * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * * Neither the name of Christoph Pfisterer nor the names of the * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "global.h" #include "lib.h" #include "icns.h" #include "config.h" #include "mystrings.h" #include "../refind/screen.h" // // well-known icons // typedef struct { EG_IMAGE *Image; CHAR16 *FileName; UINTN IconSize; } BUILTIN_ICON; BUILTIN_ICON BuiltinIconTable[BUILTIN_ICON_COUNT] = { { NULL, L"func_about", ICON_SIZE_SMALL }, { NULL, L"func_reset", ICON_SIZE_SMALL }, { NULL, L"func_shutdown", ICON_SIZE_SMALL }, { NULL, L"func_exit", ICON_SIZE_SMALL }, { NULL, L"func_firmware", ICON_SIZE_SMALL }, { NULL, L"func_csr_rotate", ICON_SIZE_SMALL }, { NULL, L"func_hidden", ICON_SIZE_SMALL }, { NULL, L"tool_shell", ICON_SIZE_SMALL }, { NULL, L"tool_part", ICON_SIZE_SMALL }, { NULL, L"tool_rescue", ICON_SIZE_SMALL }, { NULL, L"tool_apple_rescue", ICON_SIZE_SMALL }, { NULL, L"tool_windows_rescue", ICON_SIZE_SMALL }, { NULL, L"tool_mok_tool", ICON_SIZE_SMALL }, { NULL, L"tool_fwupdate", ICON_SIZE_SMALL }, { NULL, L"tool_memtest", ICON_SIZE_SMALL }, { NULL, L"tool_netboot", ICON_SIZE_SMALL }, { NULL, L"vol_internal", ICON_SIZE_BADGE }, { NULL, L"vol_external", ICON_SIZE_BADGE }, { NULL, L"vol_optical", ICON_SIZE_BADGE }, { NULL, L"vol_net", ICON_SIZE_BADGE }, { NULL, L"mouse", ICON_SIZE_MOUSE } }; EG_IMAGE * BuiltinIcon(IN UINTN Id) { if (Id >= BUILTIN_ICON_COUNT) return NULL; if (BuiltinIconTable[Id].Image == NULL) { BuiltinIconTable[Id].Image = egFindIcon(BuiltinIconTable[Id].FileName, GlobalConfig.IconSizes[BuiltinIconTable[Id].IconSize]); if (BuiltinIconTable[Id].Image == NULL) BuiltinIconTable[Id].Image = DummyImage(GlobalConfig.IconSizes[BuiltinIconTable[Id].IconSize]); } // if return BuiltinIconTable[Id].Image; } // // Load an icon for an operating system // // Load an OS icon from among the comma-delimited list provided in OSIconName. // Searches for icons with extensions in the ICON_EXTENSIONS list (via // egFindIcon()). // Returns image data. On failure, returns an ugly "dummy" icon. EG_IMAGE * LoadOSIcon(IN CHAR16 *OSIconName OPTIONAL, IN CHAR16 *FallbackIconName, BOOLEAN BootLogo) { EG_IMAGE *Image = NULL; CHAR16 *CutoutName, BaseName[256]; UINTN Index = 0; if (GlobalConfig.TextOnly) // skip loading if it's not used anyway return NULL; // First, try to find an icon from the OSIconName list.... while (((CutoutName = FindCommaDelimited(OSIconName, Index++)) != NULL) && (Image == NULL)) { SPrint(BaseName, 255, L"%s_%s", BootLogo ? L"boot" : L"os", CutoutName); Image = egFindIcon(BaseName, GlobalConfig.IconSizes[ICON_SIZE_BIG]); } // If that fails, try again using the FallbackIconName.... if (Image == NULL) { SPrint(BaseName, 255, L"%s_%s", BootLogo ? L"boot" : L"os", FallbackIconName); Image = egFindIcon(BaseName, GlobalConfig.IconSizes[ICON_SIZE_BIG]); } // If that fails and if BootLogo was set, try again using the "os_" start of the name.... if (BootLogo && (Image == NULL)) { SPrint(BaseName, 255, L"os_%s", FallbackIconName); Image = egFindIcon(BaseName, GlobalConfig.IconSizes[ICON_SIZE_BIG]); } // If all of these fail, return the dummy image.... if (Image == NULL) Image = DummyImage(GlobalConfig.IconSizes[ICON_SIZE_BIG]); return Image; } /* EG_IMAGE * LoadOSIcon() */ static EG_PIXEL BlackPixel = { 0x00, 0x00, 0x00, 0 }; //static EG_PIXEL YellowPixel = { 0x00, 0xff, 0xff, 0 }; EG_IMAGE * DummyImage(IN UINTN PixelSize) { EG_IMAGE *Image; UINTN x, y, LineOffset; CHAR8 *Ptr, *YPtr; Image = egCreateFilledImage(PixelSize, PixelSize, TRUE, &BlackPixel); LineOffset = PixelSize * 4; YPtr = (CHAR8 *)Image->PixelData + ((PixelSize - 32) >> 1) * (LineOffset + 4); for (y = 0; y < 32; y++) { Ptr = YPtr; for (x = 0; x < 32; x++) { if (((x + y) % 12) < 6) { *Ptr++ = 0; *Ptr++ = 0; *Ptr++ = 0; } else { *Ptr++ = 0; *Ptr++ = 255; *Ptr++ = 255; } *Ptr++ = 144; } YPtr += LineOffset; } return Image; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/refind/legacy.c�����������������������������������������������������������������������0000664�0001750�0001750�00000076432�13166563003�016210� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * refind/legacy.c * Functions related to BIOS/CSM/legacy booting * * Copyright (c) 2006 Christoph Pfisterer * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * * Neither the name of Christoph Pfisterer nor the names of the * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Modifications copyright (c) 2012-2015 Roderick W. Smith * * Modifications distributed under the terms of the GNU General Public * License (GPL) version 3 (GPLv3), or (at your option) any later version. * */ /* * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "global.h" #include "icns.h" #include "legacy.h" #include "lib.h" #include "menu.h" #include "../include/refit_call_wrapper.h" #include "screen.h" #include "../include/syslinux_mbr.h" #include "mystrings.h" #include "../EfiLib/BdsHelper.h" #include "../EfiLib/legacy.h" #include "../include/Handle.h" extern REFIT_MENU_ENTRY MenuEntryReturn; extern REFIT_MENU_SCREEN MainMenu; #ifndef __MAKEWITH_GNUEFI #define LibLocateHandle gBS->LocateHandleBuffer #define DevicePathProtocol gEfiDevicePathProtocolGuid #endif EFI_GUID EfiGlobalVariableGuid = { 0x8BE4DF61, 0x93CA, 0x11D2, { 0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C }}; static EFI_STATUS ActivateMbrPartition(IN EFI_BLOCK_IO *BlockIO, IN UINTN PartitionIndex) { EFI_STATUS Status; UINT8 SectorBuffer[512]; MBR_PARTITION_INFO *MbrTable, *EMbrTable; UINT32 ExtBase, ExtCurrent, NextExtCurrent; UINTN LogicalPartitionIndex = 4; UINTN i; BOOLEAN HaveBootCode; // read MBR Status = refit_call5_wrapper(BlockIO->ReadBlocks, BlockIO, BlockIO->Media->MediaId, 0, 512, SectorBuffer); if (EFI_ERROR(Status)) return Status; if (*((UINT16 *)(SectorBuffer + 510)) != 0xaa55) return EFI_NOT_FOUND; // safety measure #1 // add boot code if necessary HaveBootCode = FALSE; for (i = 0; i < MBR_BOOTCODE_SIZE; i++) { if (SectorBuffer[i] != 0) { HaveBootCode = TRUE; break; } } if (!HaveBootCode) { // no boot code found in the MBR, add the syslinux MBR code SetMem(SectorBuffer, MBR_BOOTCODE_SIZE, 0); CopyMem(SectorBuffer, syslinux_mbr, SYSLINUX_MBR_SIZE); } // set the partition active MbrTable = (MBR_PARTITION_INFO *)(SectorBuffer + 446); ExtBase = 0; for (i = 0; i < 4; i++) { if (MbrTable[i].Flags != 0x00 && MbrTable[i].Flags != 0x80) return EFI_NOT_FOUND; // safety measure #2 if (i == PartitionIndex) MbrTable[i].Flags = 0x80; else if (PartitionIndex >= 4 && IS_EXTENDED_PART_TYPE(MbrTable[i].Type)) { MbrTable[i].Flags = 0x80; ExtBase = MbrTable[i].StartLBA; } else MbrTable[i].Flags = 0x00; } // write MBR Status = refit_call5_wrapper(BlockIO->WriteBlocks, BlockIO, BlockIO->Media->MediaId, 0, 512, SectorBuffer); if (EFI_ERROR(Status)) return Status; if (PartitionIndex >= 4) { // we have to activate a logical partition, so walk the EMBR chain // NOTE: ExtBase was set above while looking at the MBR table for (ExtCurrent = ExtBase; ExtCurrent; ExtCurrent = NextExtCurrent) { // read current EMBR Status = refit_call5_wrapper(BlockIO->ReadBlocks, BlockIO, BlockIO->Media->MediaId, ExtCurrent, 512, SectorBuffer); if (EFI_ERROR(Status)) return Status; if (*((UINT16 *)(SectorBuffer + 510)) != 0xaa55) return EFI_NOT_FOUND; // safety measure #3 // scan EMBR, set appropriate partition active EMbrTable = (MBR_PARTITION_INFO *)(SectorBuffer + 446); NextExtCurrent = 0; for (i = 0; i < 4; i++) { if (EMbrTable[i].Flags != 0x00 && EMbrTable[i].Flags != 0x80) return EFI_NOT_FOUND; // safety measure #4 if (EMbrTable[i].StartLBA == 0 || EMbrTable[i].Size == 0) break; if (IS_EXTENDED_PART_TYPE(EMbrTable[i].Type)) { // link to next EMBR NextExtCurrent = ExtBase + EMbrTable[i].StartLBA; EMbrTable[i].Flags = (PartitionIndex >= LogicalPartitionIndex) ? 0x80 : 0x00; break; } else { // logical partition EMbrTable[i].Flags = (PartitionIndex == LogicalPartitionIndex) ? 0x80 : 0x00; LogicalPartitionIndex++; } } // write current EMBR Status = refit_call5_wrapper(BlockIO->WriteBlocks, BlockIO, BlockIO->Media->MediaId, ExtCurrent, 512, SectorBuffer); if (EFI_ERROR(Status)) return Status; if (PartitionIndex < LogicalPartitionIndex) break; // stop the loop, no need to touch further EMBRs } } return EFI_SUCCESS; } /* static EFI_STATUS ActivateMbrPartition() */ static EFI_GUID AppleVariableVendorID = { 0x7C436110, 0xAB2A, 0x4BBB, { 0xA8, 0x80, 0xFE, 0x41, 0x99, 0x5C, 0x9F, 0x82 } }; static EFI_STATUS WriteBootDiskHint(IN EFI_DEVICE_PATH *WholeDiskDevicePath) { EFI_STATUS Status; Status = refit_call5_wrapper(RT->SetVariable, L"BootCampHD", &AppleVariableVendorID, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, GetDevicePathSize(WholeDiskDevicePath), WholeDiskDevicePath); if (EFI_ERROR(Status)) return Status; return EFI_SUCCESS; } // // firmware device path discovery // static UINT8 LegacyLoaderMediaPathData[] = { 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B, 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B, 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00, }; static EFI_DEVICE_PATH *LegacyLoaderMediaPath = (EFI_DEVICE_PATH *)LegacyLoaderMediaPathData; static VOID ExtractLegacyLoaderPaths(EFI_DEVICE_PATH **PathList, UINTN MaxPaths, EFI_DEVICE_PATH **HardcodedPathList) { EFI_STATUS Status; UINTN HandleCount = 0; UINTN HandleIndex, HardcodedIndex; EFI_HANDLE *Handles; EFI_HANDLE Handle; UINTN PathCount = 0; UINTN PathIndex; EFI_LOADED_IMAGE *LoadedImage; EFI_DEVICE_PATH *DevicePath; BOOLEAN Seen; MaxPaths--; // leave space for the terminating NULL pointer // get all LoadedImage handles Status = LibLocateHandle(ByProtocol, &LoadedImageProtocol, NULL, &HandleCount, &Handles); if (CheckError(Status, L"while listing LoadedImage handles")) { if (HardcodedPathList) { for (HardcodedIndex = 0; HardcodedPathList[HardcodedIndex] && PathCount < MaxPaths; HardcodedIndex++) PathList[PathCount++] = HardcodedPathList[HardcodedIndex]; } PathList[PathCount] = NULL; return; } for (HandleIndex = 0; HandleIndex < HandleCount && PathCount < MaxPaths; HandleIndex++) { Handle = Handles[HandleIndex]; Status = refit_call3_wrapper(BS->HandleProtocol, Handle, &LoadedImageProtocol, (VOID **) &LoadedImage); if (EFI_ERROR(Status)) continue; // This can only happen if the firmware scewed up, ignore it. Status = refit_call3_wrapper(BS->HandleProtocol, LoadedImage->DeviceHandle, &DevicePathProtocol, (VOID **) &DevicePath); if (EFI_ERROR(Status)) continue; // This happens, ignore it. // Only grab memory range nodes if (DevicePathType(DevicePath) != HARDWARE_DEVICE_PATH || DevicePathSubType(DevicePath) != HW_MEMMAP_DP) continue; // Check if we have this device path in the list already // WARNING: This assumes the first node in the device path is unique! Seen = FALSE; for (PathIndex = 0; PathIndex < PathCount; PathIndex++) { if (DevicePathNodeLength(DevicePath) != DevicePathNodeLength(PathList[PathIndex])) continue; if (CompareMem(DevicePath, PathList[PathIndex], DevicePathNodeLength(DevicePath)) == 0) { Seen = TRUE; break; } } if (Seen) continue; PathList[PathCount++] = AppendDevicePath(DevicePath, LegacyLoaderMediaPath); } MyFreePool(Handles); if (HardcodedPathList) { for (HardcodedIndex = 0; HardcodedPathList[HardcodedIndex] && PathCount < MaxPaths; HardcodedIndex++) PathList[PathCount++] = HardcodedPathList[HardcodedIndex]; } PathList[PathCount] = NULL; } /* VOID ExtractLegacyLoaderPaths() */ // early 2006 Core Duo / Core Solo models static UINT8 LegacyLoaderDevicePath1Data[] = { 0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF9, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B, 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B, 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00, }; // mid-2006 Mac Pro (and probably other Core 2 models) static UINT8 LegacyLoaderDevicePath2Data[] = { 0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF7, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B, 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B, 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00, }; // mid-2007 MBP ("Santa Rosa" based models) static UINT8 LegacyLoaderDevicePath3Data[] = { 0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B, 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B, 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00, }; // early-2008 MBA static UINT8 LegacyLoaderDevicePath4Data[] = { 0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B, 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B, 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00, }; // late-2008 MB/MBP (NVidia chipset) static UINT8 LegacyLoaderDevicePath5Data[] = { 0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x40, 0xCB, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B, 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B, 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00, }; static EFI_DEVICE_PATH *LegacyLoaderList[] = { (EFI_DEVICE_PATH *)LegacyLoaderDevicePath1Data, (EFI_DEVICE_PATH *)LegacyLoaderDevicePath2Data, (EFI_DEVICE_PATH *)LegacyLoaderDevicePath3Data, (EFI_DEVICE_PATH *)LegacyLoaderDevicePath4Data, (EFI_DEVICE_PATH *)LegacyLoaderDevicePath5Data, NULL }; #define MAX_DISCOVERED_PATHS (16) // Launch a BIOS boot loader (Mac mode) static EFI_STATUS StartLegacyImageList(IN EFI_DEVICE_PATH **DevicePaths, IN CHAR16 *LoadOptions, OUT UINTN *ErrorInStep) { EFI_STATUS Status, ReturnStatus; EFI_HANDLE ChildImageHandle; EFI_LOADED_IMAGE *ChildLoadedImage = NULL; UINTN DevicePathIndex; CHAR16 ErrorInfo[256]; CHAR16 *FullLoadOptions = NULL; if (ErrorInStep != NULL) *ErrorInStep = 0; // set load options if (LoadOptions != NULL) { FullLoadOptions = StrDuplicate(LoadOptions); } // if (LoadOptions != NULL) Print(L"Starting legacy loader\nUsing load options '%s'\n", FullLoadOptions ? FullLoadOptions : L""); // load the image into memory ReturnStatus = Status = EFI_NOT_FOUND; // in case the list is empty for (DevicePathIndex = 0; DevicePaths[DevicePathIndex] != NULL; DevicePathIndex++) { ReturnStatus = Status = refit_call6_wrapper(BS->LoadImage, FALSE, SelfImageHandle, DevicePaths[DevicePathIndex], NULL, 0, &ChildImageHandle); if (ReturnStatus != EFI_NOT_FOUND) { break; } } // for SPrint(ErrorInfo, 255, L"while loading legacy loader"); if (CheckError(Status, ErrorInfo)) { if (ErrorInStep != NULL) *ErrorInStep = 1; goto bailout; } ReturnStatus = Status = refit_call3_wrapper(BS->HandleProtocol, ChildImageHandle, &LoadedImageProtocol, (VOID **) &ChildLoadedImage); if (CheckError(Status, L"while getting a LoadedImageProtocol handle")) { if (ErrorInStep != NULL) *ErrorInStep = 2; goto bailout_unload; } ChildLoadedImage->LoadOptions = (VOID *)FullLoadOptions; ChildLoadedImage->LoadOptionsSize = FullLoadOptions ? ((UINT32)StrLen(FullLoadOptions) + 1) * sizeof(CHAR16) : 0; // turn control over to the image // TODO: (optionally) re-enable the EFI watchdog timer! // close open file handles UninitRefitLib(); ReturnStatus = Status = refit_call3_wrapper(BS->StartImage, ChildImageHandle, NULL, NULL); // control returns here when the child image calls Exit() SPrint(ErrorInfo, 255, L"returned from legacy loader"); if (CheckError(Status, ErrorInfo)) { if (ErrorInStep != NULL) *ErrorInStep = 3; } // re-open file handles ReinitRefitLib(); bailout_unload: // unload the image, we don't care if it works or not... Status = refit_call1_wrapper(BS->UnloadImage, ChildImageHandle); bailout: MyFreePool(FullLoadOptions); return ReturnStatus; } /* EFI_STATUS StartLegacyImageList() */ VOID StartLegacy(IN LEGACY_ENTRY *Entry, IN CHAR16 *SelectionName) { EFI_STATUS Status; EG_IMAGE *BootLogoImage; UINTN ErrorInStep = 0; EFI_DEVICE_PATH *DiscoveredPathList[MAX_DISCOVERED_PATHS]; BeginExternalScreen(TRUE, L"Booting Legacy OS (Mac mode)"); BootLogoImage = LoadOSIcon(Entry->Volume->OSIconName, L"legacy", TRUE); if (BootLogoImage != NULL) BltImageAlpha(BootLogoImage, (UGAWidth - BootLogoImage->Width ) >> 1, (UGAHeight - BootLogoImage->Height) >> 1, &StdBackgroundPixel); if (Entry->Volume->IsMbrPartition) ActivateMbrPartition(Entry->Volume->WholeDiskBlockIO, Entry->Volume->MbrPartitionIndex); if (Entry->Volume->DiskKind != DISK_KIND_OPTICAL && Entry->Volume->WholeDiskDevicePath != NULL) WriteBootDiskHint(Entry->Volume->WholeDiskDevicePath); ExtractLegacyLoaderPaths(DiscoveredPathList, MAX_DISCOVERED_PATHS, LegacyLoaderList); StoreLoaderName(SelectionName); Status = StartLegacyImageList(DiscoveredPathList, Entry->LoadOptions, &ErrorInStep); if (Status == EFI_NOT_FOUND) { if (ErrorInStep == 1) { Print(L"\nPlease make sure that you have the latest firmware update installed.\n"); } else if (ErrorInStep == 3) { Print(L"\nThe firmware refused to boot from the selected volume. Note that external\n" L"hard drives are not well-supported by Apple's firmware for legacy OS booting.\n"); } } FinishExternalScreen(); } /* static VOID StartLegacy() */ // Start a device on a non-Mac using the EFI_LEGACY_BIOS_PROTOCOL VOID StartLegacyUEFI(LEGACY_ENTRY *Entry, CHAR16 *SelectionName) { BeginExternalScreen(TRUE, L"Booting Legacy OS (UEFI mode)"); StoreLoaderName(SelectionName); BdsLibConnectDevicePath (Entry->BdsOption->DevicePath); BdsLibDoLegacyBoot(Entry->BdsOption); // If we get here, it means that there was a failure.... Print(L"Failure booting legacy (BIOS) OS."); PauseForKey(); FinishExternalScreen(); } // static VOID StartLegacyUEFI() static LEGACY_ENTRY * AddLegacyEntry(IN CHAR16 *LoaderTitle, IN REFIT_VOLUME *Volume) { LEGACY_ENTRY *Entry, *SubEntry; REFIT_MENU_SCREEN *SubScreen; CHAR16 *VolDesc, *LegacyTitle; CHAR16 ShortcutLetter = 0; if (LoaderTitle == NULL) { if (Volume->OSName != NULL) { LoaderTitle = Volume->OSName; if (LoaderTitle[0] == 'W' || LoaderTitle[0] == 'L') ShortcutLetter = LoaderTitle[0]; } else LoaderTitle = L"Legacy OS"; } if (Volume->VolName != NULL) VolDesc = Volume->VolName; else VolDesc = (Volume->DiskKind == DISK_KIND_OPTICAL) ? L"CD" : L"HD"; LegacyTitle = AllocateZeroPool(256 * sizeof(CHAR16)); if (LegacyTitle != NULL) SPrint(LegacyTitle, 255, L"Boot %s from %s", LoaderTitle, VolDesc); if (IsInSubstring(LegacyTitle, GlobalConfig.DontScanVolumes)) { MyFreePool(LegacyTitle); return NULL; } // if // prepare the menu entry Entry = AllocateZeroPool(sizeof(LEGACY_ENTRY)); Entry->me.Title = LegacyTitle; Entry->me.Tag = TAG_LEGACY; Entry->me.Row = 0; Entry->me.ShortcutLetter = ShortcutLetter; Entry->me.Image = LoadOSIcon(Volume->OSIconName, L"legacy", FALSE); Entry->me.BadgeImage = Volume->VolBadgeImage; Entry->Volume = Volume; Entry->LoadOptions = (Volume->DiskKind == DISK_KIND_OPTICAL) ? L"CD" : ((Volume->DiskKind == DISK_KIND_EXTERNAL) ? L"USB" : L"HD"); Entry->Enabled = TRUE; // create the submenu SubScreen = AllocateZeroPool(sizeof(REFIT_MENU_SCREEN)); SubScreen->Title = AllocateZeroPool(256 * sizeof(CHAR16)); SPrint(SubScreen->Title, 255, L"Boot Options for %s on %s", LoaderTitle, VolDesc); SubScreen->TitleImage = Entry->me.Image; SubScreen->Hint1 = StrDuplicate(SUBSCREEN_HINT1); if (GlobalConfig.HideUIFlags & HIDEUI_FLAG_EDITOR) { SubScreen->Hint2 = StrDuplicate(SUBSCREEN_HINT2_NO_EDITOR); } else { SubScreen->Hint2 = StrDuplicate(SUBSCREEN_HINT2); } // if/else // default entry SubEntry = AllocateZeroPool(sizeof(LEGACY_ENTRY)); SubEntry->me.Title = AllocateZeroPool(256 * sizeof(CHAR16)); SPrint(SubEntry->me.Title, 255, L"Boot %s", LoaderTitle); SubEntry->me.Tag = TAG_LEGACY; SubEntry->Volume = Entry->Volume; SubEntry->LoadOptions = Entry->LoadOptions; AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); AddMenuEntry(SubScreen, &MenuEntryReturn); Entry->me.SubScreen = SubScreen; AddMenuEntry(&MainMenu, (REFIT_MENU_ENTRY *)Entry); return Entry; } /* static LEGACY_ENTRY * AddLegacyEntry() */ /** Create a rEFInd boot option from a Legacy BIOS protocol option. */ static LEGACY_ENTRY * AddLegacyEntryUEFI(BDS_COMMON_OPTION *BdsOption, IN UINT16 DiskType) { LEGACY_ENTRY *Entry, *SubEntry; REFIT_MENU_SCREEN *SubScreen; CHAR16 ShortcutLetter = 0; CHAR16 *LegacyDescription = StrDuplicate(BdsOption->Description); if (IsInSubstring(LegacyDescription, GlobalConfig.DontScanVolumes)) return NULL; // Remove stray spaces, since many EFIs produce descriptions with lots of // extra spaces, especially at the end; this throws off centering of the // description on the screen.... LimitStringLength(LegacyDescription, 100); // prepare the menu entry Entry = AllocateZeroPool(sizeof(LEGACY_ENTRY)); Entry->me.Title = AllocateZeroPool(256 * sizeof(CHAR16)); SPrint(Entry->me.Title, 255, L"Boot legacy OS from %s", LegacyDescription); Entry->me.Tag = TAG_LEGACY_UEFI; Entry->me.Row = 0; Entry->me.ShortcutLetter = ShortcutLetter; Entry->me.Image = LoadOSIcon(L"legacy", L"legacy", TRUE); Entry->LoadOptions = (DiskType == BBS_CDROM) ? L"CD" : ((DiskType == BBS_USB) ? L"USB" : L"HD"); Entry->me.BadgeImage = GetDiskBadge(DiskType); Entry->BdsOption = BdsOption; Entry->Enabled = TRUE; // create the submenu SubScreen = AllocateZeroPool(sizeof(REFIT_MENU_SCREEN)); SubScreen->Title = AllocateZeroPool(256 * sizeof(CHAR16)); SPrint(SubScreen->Title, 255, L"No boot options for legacy target"); SubScreen->TitleImage = Entry->me.Image; SubScreen->Hint1 = StrDuplicate(SUBSCREEN_HINT1); if (GlobalConfig.HideUIFlags & HIDEUI_FLAG_EDITOR) { SubScreen->Hint2 = StrDuplicate(SUBSCREEN_HINT2_NO_EDITOR); } else { SubScreen->Hint2 = StrDuplicate(SUBSCREEN_HINT2); } // if/else // default entry SubEntry = AllocateZeroPool(sizeof(LEGACY_ENTRY)); SubEntry->me.Title = AllocateZeroPool(256 * sizeof(CHAR16)); SPrint(SubEntry->me.Title, 255, L"Boot %s", LegacyDescription); SubEntry->me.Tag = TAG_LEGACY_UEFI; Entry->BdsOption = BdsOption; AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); AddMenuEntry(SubScreen, &MenuEntryReturn); Entry->me.SubScreen = SubScreen; AddMenuEntry(&MainMenu, (REFIT_MENU_ENTRY *)Entry); return Entry; } /* static LEGACY_ENTRY * AddLegacyEntryUEFI() */ /** Scan for legacy BIOS targets on machines that implement EFI_LEGACY_BIOS_PROTOCOL. In testing, protocol has not been implemented on Macs but has been implemented on most UEFI PCs. Restricts output to disks of the specified DiskType. */ static VOID ScanLegacyUEFI(IN UINTN DiskType) { EFI_STATUS Status; EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; UINT16 *BootOrder = NULL; UINTN Index = 0; CHAR16 BootOption[10]; UINTN BootOrderSize = 0; CHAR16 Buffer[20]; BDS_COMMON_OPTION *BdsOption; LIST_ENTRY TempList; BBS_BBS_DEVICE_PATH *BbsDevicePath = NULL; BOOLEAN SearchingForUsb = FALSE; InitializeListHead (&TempList); ZeroMem (Buffer, sizeof (Buffer)); // If LegacyBios protocol is not implemented on this platform, then //we do not support this type of legacy boot on this machine. Status = refit_call3_wrapper(gBS->LocateProtocol, &gEfiLegacyBootProtocolGuid, NULL, (VOID **) &LegacyBios); if (EFI_ERROR (Status)) return; // EFI calls USB drives BBS_HARDDRIVE, but we want to distinguish them, // so we set DiskType inappropriately elsewhere in the program and // "translate" it here. if (DiskType == BBS_USB) { DiskType = BBS_HARDDISK; SearchingForUsb = TRUE; } // if // Grab the boot order BootOrder = BdsLibGetVariableAndSize(L"BootOrder", &EfiGlobalVariableGuid, &BootOrderSize); if (BootOrder == NULL) { BootOrderSize = 0; } Index = 0; while (Index < BootOrderSize / sizeof (UINT16)) { // Grab each boot option variable from the boot order, and convert // the variable into a BDS boot option UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]); BdsOption = BdsLibVariableToOption (&TempList, BootOption); if (BdsOption != NULL) { BbsDevicePath = (BBS_BBS_DEVICE_PATH *)BdsOption->DevicePath; // Only add the entry if it is of a requested type (e.g. USB, HD) // Two checks necessary because some systems return EFI boot loaders // with a DeviceType value that would inappropriately include them // as legacy loaders.... if ((BbsDevicePath->DeviceType == DiskType) && (BdsOption->DevicePath->Type == DEVICE_TYPE_BIOS)) { // USB flash drives appear as hard disks with certain media flags set. // Look for this, and if present, pass it on with the (technically // incorrect, but internally useful) BBS_TYPE_USB flag set. if (DiskType == BBS_HARDDISK) { if (SearchingForUsb && (BbsDevicePath->StatusFlag & (BBS_MEDIA_PRESENT | BBS_MEDIA_MAYBE_PRESENT))) { AddLegacyEntryUEFI(BdsOption, BBS_USB); } else if (!SearchingForUsb && !(BbsDevicePath->StatusFlag & (BBS_MEDIA_PRESENT | BBS_MEDIA_MAYBE_PRESENT))) { AddLegacyEntryUEFI(BdsOption, DiskType); } } else { AddLegacyEntryUEFI(BdsOption, DiskType); } // if/else } // if } // if (BdsOption != NULL) Index++; } // while } /* static VOID ScanLegacyUEFI() */ static VOID ScanLegacyVolume(REFIT_VOLUME *Volume, UINTN VolumeIndex) { UINTN VolumeIndex2; BOOLEAN ShowVolume, HideIfOthersFound; ShowVolume = FALSE; HideIfOthersFound = FALSE; // if (Volume->IsAppleLegacy) { // Print(L" Volume is Apple legacy\n"); // ShowVolume = TRUE; // HideIfOthersFound = TRUE; // } else if (Volume->HasBootCode) { ShowVolume = TRUE; if (Volume->BlockIO == Volume->WholeDiskBlockIO && Volume->BlockIOOffset == 0 && Volume->OSName == NULL) // this is a whole disk (MBR) entry; hide if we have entries for partitions HideIfOthersFound = TRUE; } if (HideIfOthersFound) { // check for other bootable entries on the same disk for (VolumeIndex2 = 0; VolumeIndex2 < VolumesCount; VolumeIndex2++) { if (VolumeIndex2 != VolumeIndex && Volumes[VolumeIndex2]->HasBootCode && Volumes[VolumeIndex2]->WholeDiskBlockIO == Volume->WholeDiskBlockIO) ShowVolume = FALSE; } } if (ShowVolume) AddLegacyEntry(NULL, Volume); } // static VOID ScanLegacyVolume() // Scan attached optical discs for legacy (BIOS) boot code // and add anything found to the list.... VOID ScanLegacyDisc(VOID) { UINTN VolumeIndex; REFIT_VOLUME *Volume; if (GlobalConfig.LegacyType == LEGACY_TYPE_MAC) { for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) { Volume = Volumes[VolumeIndex]; if (Volume->DiskKind == DISK_KIND_OPTICAL) ScanLegacyVolume(Volume, VolumeIndex); } // for } else if (GlobalConfig.LegacyType == LEGACY_TYPE_UEFI) { ScanLegacyUEFI(BBS_CDROM); } } /* VOID ScanLegacyDisc() */ // Scan internal hard disks for legacy (BIOS) boot code // and add anything found to the list.... VOID ScanLegacyInternal(VOID) { UINTN VolumeIndex; REFIT_VOLUME *Volume; if (GlobalConfig.LegacyType == LEGACY_TYPE_MAC) { for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) { Volume = Volumes[VolumeIndex]; if (Volume->DiskKind == DISK_KIND_INTERNAL) ScanLegacyVolume(Volume, VolumeIndex); } // for } else if (GlobalConfig.LegacyType == LEGACY_TYPE_UEFI) { // TODO: This actually picks up USB flash drives, too; try to find // a way to differentiate the two.... ScanLegacyUEFI(BBS_HARDDISK); } } /* VOID ScanLegacyInternal() */ // Scan external disks for legacy (BIOS) boot code // and add anything found to the list.... VOID ScanLegacyExternal(VOID) { UINTN VolumeIndex; REFIT_VOLUME *Volume; if (GlobalConfig.LegacyType == LEGACY_TYPE_MAC) { for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) { Volume = Volumes[VolumeIndex]; if (Volume->DiskKind == DISK_KIND_EXTERNAL) ScanLegacyVolume(Volume, VolumeIndex); } // for } else if (GlobalConfig.LegacyType == LEGACY_TYPE_UEFI) { // TODO: This actually doesn't do anything useful; leaving in hopes of // fixing it later.... ScanLegacyUEFI(BBS_USB); } } /* VOID ScanLegacyExternal() */ // Determine what (if any) type of legacy (BIOS) boot support is available VOID FindLegacyBootType(VOID) { EFI_STATUS Status; EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; GlobalConfig.LegacyType = LEGACY_TYPE_NONE; // UEFI-style legacy BIOS support is available only with some EFI implementations.... Status = refit_call3_wrapper(gBS->LocateProtocol, &gEfiLegacyBootProtocolGuid, NULL, (VOID **) &LegacyBios); if (!EFI_ERROR (Status)) GlobalConfig.LegacyType = LEGACY_TYPE_UEFI; // Macs have their own system. If the firmware vendor code contains the // string "Apple", assume it's available. Note that this overrides the // UEFI type, and might yield false positives if the vendor string // contains "Apple" as part of something bigger, so this isn't 100% // perfect. if (StriSubCmp(L"Apple", ST->FirmwareVendor)) GlobalConfig.LegacyType = LEGACY_TYPE_MAC; } // VOID FindLegacyBootType // Warn the user if legacy OS scans are enabled but the firmware can't support them.... VOID WarnIfLegacyProblems(VOID) { BOOLEAN found = FALSE; UINTN i = 0; if (GlobalConfig.LegacyType == LEGACY_TYPE_NONE) { do { if (GlobalConfig.ScanFor[i] == 'h' || GlobalConfig.ScanFor[i] == 'b' || GlobalConfig.ScanFor[i] == 'c' || GlobalConfig.ScanFor[i] == 'H' || GlobalConfig.ScanFor[i] == 'B' || GlobalConfig.ScanFor[i] == 'C') found = TRUE; i++; } while ((i < NUM_SCAN_OPTIONS) && (!found)); if (found) { Print(L"NOTE: refind.conf's 'scanfor' line specifies scanning for one or more legacy\n"); Print(L"(BIOS) boot options; however, this is not possible because your computer lacks\n"); Print(L"the necessary Compatibility Support Module (CSM) support or that support is\n"); Print(L"disabled in your firmware.\n"); PauseForKey(); } // if (found) } // if no legacy support } // VOID WarnIfLegacyProblems() ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/refind/driver_support.h���������������������������������������������������������������0000664�0001750�0001750�00000004577�13166731161�020043� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * File to implement LibScanHandleDatabase(), which is used by rEFInd's * driver-loading code (inherited from rEFIt), but which has not been * implemented in GNU-EFI and seems to have been dropped from current * versions of the Tianocore library. This function was taken from a git * site with EFI code. The original file bore the following copyright * notice: * * Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR> * This program and the accompanying materials are licensed and made available under * the terms and conditions of the BSD License that accompanies this distribution. * The full text of the license may be found at * http://opensource.org/licenses/bsd-license.php. * * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. * */ #ifndef _DRIVER_SUPPORT #define _DRIVER_SUPPORT #ifdef __MAKEWITH_GNUEFI #include <efi.h> #else #include "../include/tiano_includes.h" #endif #include "global.h" #define EFI_HANDLE_TYPE_UNKNOWN 0x000 #define EFI_HANDLE_TYPE_IMAGE_HANDLE 0x001 #define EFI_HANDLE_TYPE_DRIVER_BINDING_HANDLE 0x002 #define EFI_HANDLE_TYPE_DEVICE_DRIVER 0x004 #define EFI_HANDLE_TYPE_BUS_DRIVER 0x008 #define EFI_HANDLE_TYPE_DRIVER_CONFIGURATION_HANDLE 0x010 #define EFI_HANDLE_TYPE_DRIVER_DIAGNOSTICS_HANDLE 0x020 #define EFI_HANDLE_TYPE_COMPONENT_NAME_HANDLE 0x040 #define EFI_HANDLE_TYPE_DEVICE_HANDLE 0x080 #define EFI_HANDLE_TYPE_PARENT_HANDLE 0x100 #define EFI_HANDLE_TYPE_CONTROLLER_HANDLE 0x200 #define EFI_HANDLE_TYPE_CHILD_HANDLE 0x400 // Below is from http://git.etherboot.org/?p=mirror/efi/shell/.git;a=commitdiff;h=b1b0c63423cac54dc964c2930e04aebb46a946ec; // Seems to have been replaced by ParseHandleDatabaseByRelationshipWithType(), but the latter isn't working for me.... EFI_STATUS LibScanHandleDatabase ( EFI_HANDLE DriverBindingHandle, OPTIONAL UINT32 *DriverBindingHandleIndex, OPTIONAL EFI_HANDLE ControllerHandle, OPTIONAL UINT32 *ControllerHandleIndex, OPTIONAL UINTN *HandleCount, EFI_HANDLE **HandleBuffer, UINT32 **HandleType ); EFI_STATUS ConnectAllDriversToAllControllers(VOID); VOID ConnectFilesystemDriver(EFI_HANDLE DriverHandle); BOOLEAN LoadDrivers(VOID); #endif ���������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/refind/apple.c������������������������������������������������������������������������0000664�0001750�0001750�00000014527�13141144020�016025� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * refind/apple.c * Functions specific to Apple computers * * Copyright (c) 2015 Roderick W. Smith * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ #include "global.h" #include "config.h" #include "lib.h" #include "screen.h" #include "apple.h" #include "mystrings.h" #include "../include/refit_call_wrapper.h" CHAR16 gCsrStatus[256]; // Get CSR (Apple's System Integrity Protection [SIP], or "rootless") status // information. If the variable is not present and the firmware is Apple, fake // it and claim it's enabled, since that's how OS X 10.11 treats a system with // the variable absent. EFI_STATUS GetCsrStatus(UINT32 *CsrStatus) { UINT32 *ReturnValue = NULL; UINTN CsrLength; EFI_GUID CsrGuid = CSR_GUID; EFI_STATUS Status = EFI_INVALID_PARAMETER; if (CsrStatus) { Status = EfivarGetRaw(&CsrGuid, L"csr-active-config", (CHAR8**) &ReturnValue, &CsrLength); if (Status == EFI_SUCCESS) { if (CsrLength == 4) { *CsrStatus = *ReturnValue; } else { Status = EFI_BAD_BUFFER_SIZE; SPrint(gCsrStatus, 255, L" Unknown System Integrity Protection version"); } MyFreePool(ReturnValue); } else if ((Status == EFI_NOT_FOUND) && (StriSubCmp(L"Apple", ST->FirmwareVendor))) { *CsrStatus = SIP_ENABLED; Status = EFI_SUCCESS; } // if (Status == EFI_SUCCESS) } // if (CsrStatus) return Status; } // INTN GetCsrStatus() // Store string describing CSR status value in gCsrStatus variable, which appears // on the Info page. If DisplayMessage is TRUE, displays the new value of // gCsrStatus on the screen for three seconds. VOID RecordgCsrStatus(UINT32 CsrStatus, BOOLEAN DisplayMessage) { EG_PIXEL BGColor = COLOR_LIGHTBLUE; switch (CsrStatus) { case SIP_ENABLED: SPrint(gCsrStatus, 255, L" System Integrity Protection is enabled (0x%02x)", CsrStatus); break; case SIP_DISABLED: SPrint(gCsrStatus, 255, L" System Integrity Protection is disabled (0x%02x)", CsrStatus); break; default: SPrint(gCsrStatus, 255, L" System Integrity Protection status: 0x%02x", CsrStatus); } // switch if (DisplayMessage) { egDisplayMessage(gCsrStatus, &BGColor, CENTER); PauseSeconds(3); } // if } // VOID RecordgCsrStatus() // Find the current CSR status and reset it to the next one in the // GlobalConfig.CsrValues list, or to the first value if the current // value is not on the list. VOID RotateCsrValue(VOID) { UINT32 CurrentValue, TargetCsr; UINT32_LIST *ListItem; EFI_GUID CsrGuid = CSR_GUID; EFI_STATUS Status; Status = GetCsrStatus(&CurrentValue); if ((Status == EFI_SUCCESS) && GlobalConfig.CsrValues) { ListItem = GlobalConfig.CsrValues; while ((ListItem != NULL) && (ListItem->Value != CurrentValue)) ListItem = ListItem->Next; if (ListItem == NULL || ListItem->Next == NULL) { TargetCsr = GlobalConfig.CsrValues->Value; } else { TargetCsr = ListItem->Next->Value; } Status = EfivarSetRaw(&CsrGuid, L"csr-active-config", (CHAR8 *) &TargetCsr, 4, TRUE); if (Status == EFI_SUCCESS) RecordgCsrStatus(TargetCsr, TRUE); else SPrint(gCsrStatus, 255, L" Error setting System Integrity Protection code."); } // if } // VOID RotateCsrValue() /* * The below definitions and SetAppleOSInfo() function are based on a GRUB patch * by Andreas Heider: * https://lists.gnu.org/archive/html/grub-devel/2013-12/msg00442.html */ #define EFI_APPLE_SET_OS_PROTOCOL_GUID \ { 0xc5c5da95, 0x7d5c, 0x45e6, \ { 0xb2, 0xf1, 0x3f, 0xd5, 0x2b, 0xb1, 0x00, 0x77 } \ } typedef struct EfiAppleSetOsInterface { UINT64 Version; EFI_STATUS EFIAPI (*SetOsVersion) (IN CHAR8 *Version); EFI_STATUS EFIAPI (*SetOsVendor) (IN CHAR8 *Vendor); } EfiAppleSetOsInterface; // Function to tell the firmware that OS X is being launched. This is // required to work around problems on some Macs that don't fully // initialize some hardware (especially video displays) when third-party // OSes are launched in EFI mode. EFI_STATUS SetAppleOSInfo() { CHAR16 *AppleOSVersion = NULL; CHAR8 *AppleOSVersion8 = NULL; EFI_STATUS Status; EFI_GUID apple_set_os_guid = EFI_APPLE_SET_OS_PROTOCOL_GUID; EfiAppleSetOsInterface *SetOs = NULL; Status = refit_call3_wrapper(BS->LocateProtocol, &apple_set_os_guid, NULL, (VOID**) &SetOs); // If not a Mac, ignore the call.... if ((Status != EFI_SUCCESS) || (!SetOs)) return EFI_SUCCESS; if ((SetOs->Version != 0) && GlobalConfig.SpoofOSXVersion) { AppleOSVersion = StrDuplicate(L"Mac OS X"); MergeStrings(&AppleOSVersion, GlobalConfig.SpoofOSXVersion, ' '); if (AppleOSVersion) { AppleOSVersion8 = AllocateZeroPool((StrLen(AppleOSVersion) + 1) * sizeof(CHAR8)); UnicodeStrToAsciiStr(AppleOSVersion, AppleOSVersion8); if (AppleOSVersion8) { Status = refit_call1_wrapper (SetOs->SetOsVersion, AppleOSVersion8); if (!EFI_ERROR(Status)) Status = EFI_SUCCESS; MyFreePool(AppleOSVersion8); } else { Status = EFI_OUT_OF_RESOURCES; Print(L"Out of resources in SetAppleOSInfo!\n"); } if ((Status == EFI_SUCCESS) && (SetOs->Version >= 2)) Status = refit_call1_wrapper (SetOs->SetOsVendor, (CHAR8 *) "Apple Inc."); MyFreePool(AppleOSVersion); } // if (AppleOSVersion) } // if if (Status != EFI_SUCCESS) Print(L"Unable to set firmware boot type!\n"); return (Status); } // EFI_STATUS SetAppleOSInfo()�������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/refind/driver_support.c���������������������������������������������������������������0000664�0001750�0001750�00000057236�13166731463�020043� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Functions related to drivers. Original copyright notices below.... */ /* * Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR> * This program and the accompanying materials are licensed and made available under * the terms and conditions of the BSD License that accompanies this distribution. * The full text of the license may be found at * http://opensource.org/licenses/bsd-license.php. * * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. * */ /* * refit/main.c * Main code for the boot menu * * Copyright (c) 2006-2010 Christoph Pfisterer * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * * Neither the name of Christoph Pfisterer nor the names of the * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Modifications copyright (c) 2012-2017 Roderick W. Smith * * Modifications distributed under the terms of the GNU General Public * License (GPL) version 3 (GPLv3), or (at your option) any later version. * */ /* * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "driver_support.h" #include "lib.h" #include "mystrings.h" #include "screen.h" #include "../include/refit_call_wrapper.h" #if defined (EFIX64) #define DRIVER_DIRS L"drivers,drivers_x64" #elif defined (EFI32) #define DRIVER_DIRS L"drivers,drivers_ia32" #elif defined (EFIAARCH64) #define DRIVER_DIRS L"drivers,drivers_aa64" #else #define DRIVER_DIRS L"drivers" #endif // Following "global" constants are from EDK2's AutoGen.c.... EFI_GUID gMyEfiLoadedImageProtocolGuid = { 0x5B1B31A1, 0x9562, 0x11D2, { 0x8E, 0x3F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; EFI_GUID gMyEfiDriverBindingProtocolGuid = { 0x18A031AB, 0xB443, 0x4D1A, { 0xA5, 0xC0, 0x0C, 0x09, 0x26, 0x1E, 0x9F, 0x71 }}; EFI_GUID gMyEfiDriverConfigurationProtocolGuid = { 0x107A772B, 0xD5E1, 0x11D4, { 0x9A, 0x46, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; EFI_GUID gMyEfiDriverDiagnosticsProtocolGuid = { 0x0784924F, 0xE296, 0x11D4, { 0x9A, 0x49, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; EFI_GUID gMyEfiComponentNameProtocolGuid = { 0x107A772C, 0xD5E1, 0x11D4, { 0x9A, 0x46, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; EFI_GUID gMyEfiDevicePathProtocolGuid = { 0x09576E91, 0x6D3F, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; EFI_GUID gMyEfiDiskIoProtocolGuid = { 0xCE345171, 0xBA0B, 0x11D2, { 0x8E, 0x4F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; EFI_GUID gMyEfiBlockIoProtocolGuid = { 0x964E5B21, 0x6459, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; EFI_GUID gMyEfiSimpleFileSystemProtocolGuid = { 0x964E5B22, 0x6459, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; #ifdef __MAKEWITH_GNUEFI struct MY_EFI_SIMPLE_FILE_SYSTEM_PROTOCOL; struct MY_EFI_FILE_PROTOCOL; typedef EFI_STATUS (EFIAPI *MY_EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_OPEN_VOLUME)( IN struct MY_EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This, OUT struct MY_EFI_FILE_PROTOCOL **Root ); typedef struct _MY_MY_EFI_SIMPLE_FILE_SYSTEM_PROTOCOL { UINT64 Revision; MY_EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_OPEN_VOLUME OpenVolume; } MY_EFI_SIMPLE_FILE_SYSTEM_PROTOCOL; typedef struct _MY_EFI_FILE_PROTOCOL { UINT64 Revision; EFI_FILE_OPEN Open; EFI_FILE_CLOSE Close; EFI_FILE_DELETE Delete; EFI_FILE_READ Read; EFI_FILE_WRITE Write; EFI_FILE_GET_POSITION GetPosition; EFI_FILE_SET_POSITION SetPosition; EFI_FILE_GET_INFO GetInfo; EFI_FILE_SET_INFO SetInfo; EFI_FILE_FLUSH Flush; } MY_EFI_FILE_PROTOCOL; typedef struct _MY_EFI_BLOCK_IO_PROTOCOL { UINT64 Revision; EFI_BLOCK_IO_MEDIA *Media; EFI_BLOCK_RESET Reset; EFI_BLOCK_READ ReadBlocks; EFI_BLOCK_WRITE WriteBlocks; EFI_BLOCK_FLUSH FlushBlocks; } MY_EFI_BLOCK_IO_PROTOCOL; #else /* Make with Tianocore */ #define MY_EFI_SIMPLE_FILE_SYSTEM_PROTOCOL EFI_SIMPLE_FILE_SYSTEM_PROTOCOL #define MY_EFI_FILE_PROTOCOL EFI_FILE_PROTOCOL #define MY_EFI_BLOCK_IO_PROTOCOL EFI_BLOCK_IO_PROTOCOL #endif /* LibScanHandleDatabase() is used by rEFInd's driver-loading code (inherited * from rEFIt), but has not been implemented in GNU-EFI and seems to have been * dropped from current versions of the Tianocore library. This function was * taken from http://git.etherboot.org/?p=mirror/efi/shell/.git;a=commitdiff;h=b1b0c63423cac54dc964c2930e04aebb46a946ec, * The original files are copyright 2006-2011 Intel and BSD-licensed. Minor * modifications by Roderick Smith are GPLv3. */ EFI_STATUS LibScanHandleDatabase (EFI_HANDLE DriverBindingHandle, OPTIONAL UINT32 *DriverBindingHandleIndex, OPTIONAL EFI_HANDLE ControllerHandle, OPTIONAL UINT32 *ControllerHandleIndex, OPTIONAL UINTN *HandleCount, EFI_HANDLE **HandleBuffer, UINT32 **HandleType) { EFI_STATUS Status; UINTN HandleIndex; EFI_GUID **ProtocolGuidArray; UINTN ArrayCount; UINTN ProtocolIndex; EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfo; UINTN OpenInfoCount; UINTN OpenInfoIndex; UINTN ChildIndex; BOOLEAN DriverBindingHandleIndexValid; DriverBindingHandleIndexValid = FALSE; if (DriverBindingHandleIndex != NULL) { *DriverBindingHandleIndex = 0xffffffff; } if (ControllerHandleIndex != NULL) { *ControllerHandleIndex = 0xffffffff; } *HandleCount = 0; *HandleBuffer = NULL; *HandleType = NULL; // // Retrieve the list of all handles from the handle database // Status = refit_call5_wrapper(BS->LocateHandleBuffer, AllHandles, NULL, NULL, HandleCount, HandleBuffer ); if (EFI_ERROR (Status)) { goto Error; } *HandleType = AllocatePool (*HandleCount * sizeof (UINT32)); if (*HandleType == NULL) { goto Error; } for (HandleIndex = 0; HandleIndex < *HandleCount; HandleIndex++) { // // Assume that the handle type is unknown // (*HandleType)[HandleIndex] = EFI_HANDLE_TYPE_UNKNOWN; if (DriverBindingHandle != NULL && DriverBindingHandleIndex != NULL && (*HandleBuffer)[HandleIndex] == DriverBindingHandle ) { *DriverBindingHandleIndex = (UINT32) HandleIndex; DriverBindingHandleIndexValid = TRUE; } if (ControllerHandle != NULL && ControllerHandleIndex != NULL && (*HandleBuffer)[HandleIndex] == ControllerHandle) { *ControllerHandleIndex = (UINT32) HandleIndex; } } for (HandleIndex = 0; HandleIndex < *HandleCount; HandleIndex++) { // // Retrieve the list of all the protocols on each handle // Status = refit_call3_wrapper(BS->ProtocolsPerHandle, (*HandleBuffer)[HandleIndex], &ProtocolGuidArray, &ArrayCount ); if (!EFI_ERROR (Status)) { for (ProtocolIndex = 0; ProtocolIndex < ArrayCount; ProtocolIndex++) { if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gMyEfiLoadedImageProtocolGuid) == 0) { (*HandleType)[HandleIndex] |= EFI_HANDLE_TYPE_IMAGE_HANDLE; } if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gMyEfiDriverBindingProtocolGuid) == 0) { (*HandleType)[HandleIndex] |= EFI_HANDLE_TYPE_DRIVER_BINDING_HANDLE; } if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gMyEfiDriverConfigurationProtocolGuid) == 0) { (*HandleType)[HandleIndex] |= EFI_HANDLE_TYPE_DRIVER_CONFIGURATION_HANDLE; } if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gMyEfiDriverDiagnosticsProtocolGuid) == 0) { (*HandleType)[HandleIndex] |= EFI_HANDLE_TYPE_DRIVER_DIAGNOSTICS_HANDLE; } if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gMyEfiComponentNameProtocolGuid) == 0) { (*HandleType)[HandleIndex] |= EFI_HANDLE_TYPE_COMPONENT_NAME_HANDLE; } if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gMyEfiDevicePathProtocolGuid) == 0) { (*HandleType)[HandleIndex] |= EFI_HANDLE_TYPE_DEVICE_HANDLE; } // // Retrieve the list of agents that have opened each protocol // Status = refit_call4_wrapper(BS->OpenProtocolInformation, (*HandleBuffer)[HandleIndex], ProtocolGuidArray[ProtocolIndex], &OpenInfo, &OpenInfoCount ); if (!EFI_ERROR (Status)) { for (OpenInfoIndex = 0; OpenInfoIndex < OpenInfoCount; OpenInfoIndex++) { if (DriverBindingHandle != NULL && OpenInfo[OpenInfoIndex].AgentHandle == DriverBindingHandle) { if ((OpenInfo[OpenInfoIndex].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) == EFI_OPEN_PROTOCOL_BY_DRIVER) { // // Mark the device handle as being managed by the driver specified by DriverBindingHandle // (*HandleType)[HandleIndex] |= (EFI_HANDLE_TYPE_DEVICE_HANDLE | EFI_HANDLE_TYPE_CONTROLLER_HANDLE); // // Mark the DriverBindingHandle as being a driver that is managing at least one controller // if (DriverBindingHandleIndexValid) { (*HandleType)[*DriverBindingHandleIndex] |= EFI_HANDLE_TYPE_DEVICE_DRIVER; } } if (( OpenInfo[OpenInfoIndex].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER ) == EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER ) { // // Mark the DriverBindingHandle as being a driver that is managing at least one child controller // if (DriverBindingHandleIndexValid) { (*HandleType)[*DriverBindingHandleIndex] |= EFI_HANDLE_TYPE_BUS_DRIVER; } } if (ControllerHandle != NULL && (*HandleBuffer)[HandleIndex] == ControllerHandle) { if (( OpenInfo[OpenInfoIndex].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER ) == EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER ) { for (ChildIndex = 0; ChildIndex < *HandleCount; ChildIndex++) { if ((*HandleBuffer)[ChildIndex] == OpenInfo[OpenInfoIndex].ControllerHandle) { (*HandleType)[ChildIndex] |= (EFI_HANDLE_TYPE_DEVICE_HANDLE | EFI_HANDLE_TYPE_CHILD_HANDLE); } } } } } if (DriverBindingHandle == NULL && OpenInfo[OpenInfoIndex].ControllerHandle == ControllerHandle) { if ((OpenInfo[OpenInfoIndex].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) == EFI_OPEN_PROTOCOL_BY_DRIVER) { for (ChildIndex = 0; ChildIndex < *HandleCount; ChildIndex++) { if ((*HandleBuffer)[ChildIndex] == OpenInfo[OpenInfoIndex].AgentHandle) { (*HandleType)[ChildIndex] |= EFI_HANDLE_TYPE_DEVICE_DRIVER; } } } if (( OpenInfo[OpenInfoIndex].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER ) == EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER ) { (*HandleType)[HandleIndex] |= EFI_HANDLE_TYPE_PARENT_HANDLE; for (ChildIndex = 0; ChildIndex < *HandleCount; ChildIndex++) { if ((*HandleBuffer)[ChildIndex] == OpenInfo[OpenInfoIndex].AgentHandle) { (*HandleType)[ChildIndex] |= EFI_HANDLE_TYPE_BUS_DRIVER; } } } } } MyFreePool (OpenInfo); } } MyFreePool (ProtocolGuidArray); } } return EFI_SUCCESS; Error: MyFreePool (*HandleType); MyFreePool (*HandleBuffer); *HandleCount = 0; *HandleBuffer = NULL; *HandleType = NULL; return Status; } /* EFI_STATUS LibScanHandleDatabase() */ #ifdef __MAKEWITH_GNUEFI /* Modified from EDK2 function of a similar name; original copyright Intel & * BSD-licensed; modifications by Roderick Smith are GPLv3. */ EFI_STATUS ConnectAllDriversToAllControllers(VOID) { EFI_STATUS Status; UINTN AllHandleCount; EFI_HANDLE *AllHandleBuffer; UINTN Index; UINTN HandleCount; EFI_HANDLE *HandleBuffer; UINT32 *HandleType; UINTN HandleIndex; BOOLEAN Parent; BOOLEAN Device; Status = LibLocateHandle(AllHandles, NULL, NULL, &AllHandleCount, &AllHandleBuffer); if (EFI_ERROR(Status)) return Status; for (Index = 0; Index < AllHandleCount; Index++) { // // Scan the handle database // Status = LibScanHandleDatabase(NULL, NULL, AllHandleBuffer[Index], NULL, &HandleCount, &HandleBuffer, &HandleType); if (EFI_ERROR (Status)) goto Done; Device = TRUE; if (HandleType[Index] & EFI_HANDLE_TYPE_DRIVER_BINDING_HANDLE) Device = FALSE; if (HandleType[Index] & EFI_HANDLE_TYPE_IMAGE_HANDLE) Device = FALSE; if (Device) { Parent = FALSE; for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) { if (HandleType[HandleIndex] & EFI_HANDLE_TYPE_PARENT_HANDLE) Parent = TRUE; } // for if (!Parent) { if (HandleType[Index] & EFI_HANDLE_TYPE_DEVICE_HANDLE) { Status = refit_call4_wrapper(BS->ConnectController, AllHandleBuffer[Index], NULL, NULL, TRUE); } } } MyFreePool (HandleBuffer); MyFreePool (HandleType); } Done: MyFreePool (AllHandleBuffer); return Status; } /* EFI_STATUS ConnectAllDriversToAllControllers() */ #else EFI_STATUS ConnectAllDriversToAllControllers(VOID) { BdsLibConnectAllDriversToAllControllers(); return 0; } #endif /* * ConnectFilesystemDriver() is modified from DisconnectInvalidDiskIoChildDrivers() * in Clover (https://sourceforge.net/projects/cloverefiboot/), which is derived * from rEFIt. The refit/main.c file from which this function was taken continues * to bear rEFIt's original copyright/licence notice (BSD); modifications by * Roderick Smith (2016) are GPLv3. */ /** * Some UEFI's (like HPQ EFI from HP notebooks) have DiskIo protocols * opened BY_DRIVER (by Partition driver in HP case) even when no file system * is produced from this DiskIo. This then blocks our FS drivers from connecting * and producing file systems. * To fix it: we will disconnect drivers that connected to DiskIo BY_DRIVER * if this is partition volume and if those drivers did not produce file system, * then try to connect every unconnected device to the driver whose handle is * passed to us. This should have no effect on systems unaffected by this EFI * bug/quirk. */ VOID ConnectFilesystemDriver(EFI_HANDLE DriverHandle) { EFI_STATUS Status; UINTN HandleCount = 0; UINTN Index; UINTN OpenInfoIndex; EFI_HANDLE *Handles = NULL; MY_EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs; MY_EFI_BLOCK_IO_PROTOCOL *BlockIo; EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfo; UINTN OpenInfoCount; EFI_HANDLE DriverHandleList[2]; // // Get all DiskIo handles // Status = refit_call5_wrapper(gBS->LocateHandleBuffer, ByProtocol, &gMyEfiDiskIoProtocolGuid, NULL, &HandleCount, &Handles); if (EFI_ERROR(Status) || HandleCount == 0) return; // // Check every DiskIo handle // for (Index = 0; Index < HandleCount; Index++) { // // If this is not partition - skip it. // This is then whole disk and DiskIo // should be opened here BY_DRIVER by Partition driver // to produce partition volumes. // Status = refit_call3_wrapper(gBS->HandleProtocol, Handles[Index], &gMyEfiBlockIoProtocolGuid, (VOID **) &BlockIo); if (EFI_ERROR (Status)) continue; if (BlockIo->Media == NULL || !BlockIo->Media->LogicalPartition) continue; // // If SimpleFileSystem is already produced - skip it, this is ok // Status = refit_call3_wrapper(gBS->HandleProtocol, Handles[Index], &gMyEfiSimpleFileSystemProtocolGuid, (VOID **) &Fs); if (Status == EFI_SUCCESS) continue; // // If no SimpleFileSystem on this handle but DiskIo is opened BY_DRIVER // then disconnect this connection and try to connect our driver to it // Status = refit_call4_wrapper(gBS->OpenProtocolInformation, Handles[Index], &gMyEfiDiskIoProtocolGuid, &OpenInfo, &OpenInfoCount); if (EFI_ERROR (Status)) continue; DriverHandleList[1] = NULL; for (OpenInfoIndex = 0; OpenInfoIndex < OpenInfoCount; OpenInfoIndex++) { if ((OpenInfo[OpenInfoIndex].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) == EFI_OPEN_PROTOCOL_BY_DRIVER) { Status = refit_call3_wrapper(gBS->DisconnectController, Handles[Index], OpenInfo[OpenInfoIndex].AgentHandle, NULL); if (!(EFI_ERROR(Status))) { DriverHandleList[0] = DriverHandle; refit_call4_wrapper(gBS->ConnectController, Handles[Index], DriverHandleList, NULL, FALSE); } // if } // if } // for FreePool (OpenInfo); } FreePool(Handles); } // VOID ConnectFilesystemDriver() // Scan a directory for drivers. // Originally from rEFIt's main.c (BSD), but modified since then (GPLv3). static UINTN ScanDriverDir(IN CHAR16 *Path) { EFI_STATUS Status; REFIT_DIR_ITER DirIter; UINTN NumFound = 0; EFI_FILE_INFO *DirEntry; CHAR16 FileName[256]; CleanUpPathNameSlashes(Path); // look through contents of the directory DirIterOpen(SelfRootDir, Path, &DirIter); while (DirIterNext(&DirIter, 2, LOADER_MATCH_PATTERNS, &DirEntry)) { if (DirEntry->FileName[0] == '.') continue; // skip this SPrint(FileName, 255, L"%s\\%s", Path, DirEntry->FileName); NumFound++; Status = StartEFIImage(SelfVolume, FileName, L"", DirEntry->FileName, 0, FALSE, TRUE); } // while Status = DirIterClose(&DirIter); if ((Status != EFI_NOT_FOUND) && (Status != EFI_INVALID_PARAMETER)) { SPrint(FileName, 255, L"while scanning the %s directory", Path); CheckError(Status, FileName); } return (NumFound); } // static UINTN ScanDriverDir() // Load all EFI drivers from rEFInd's "drivers" subdirectory and from the // directories specified by the user in the "scan_driver_dirs" configuration // file line. // Originally from rEFIt's main.c (BSD), but modified since then (GPLv3). // Returns TRUE if any drivers are loaded, FALSE otherwise. BOOLEAN LoadDrivers(VOID) { CHAR16 *Directory, *SelfDirectory; UINTN i = 0, Length, NumFound = 0; // load drivers from the subdirectories of rEFInd's home directory specified // in the DRIVER_DIRS constant. while ((Directory = FindCommaDelimited(DRIVER_DIRS, i++)) != NULL) { SelfDirectory = SelfDirPath ? StrDuplicate(SelfDirPath) : NULL; CleanUpPathNameSlashes(SelfDirectory); MergeStrings(&SelfDirectory, Directory, L'\\'); NumFound += ScanDriverDir(SelfDirectory); MyFreePool(Directory); MyFreePool(SelfDirectory); } // Scan additional user-specified driver directories.... i = 0; while ((Directory = FindCommaDelimited(GlobalConfig.DriverDirs, i++)) != NULL) { CleanUpPathNameSlashes(Directory); Length = StrLen(Directory); if (Length > 0) { NumFound += ScanDriverDir(Directory); } // if MyFreePool(Directory); } // while // connect all devices if (NumFound > 0) ConnectAllDriversToAllControllers(); return (NumFound > 0); } /* BOOLEAN LoadDrivers() */ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/refind/icns.h�������������������������������������������������������������������������0000664�0001750�0001750�00000006245�13141071534�015674� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * refit/icns.h * Icon management header file * * Copyright (c) 2006-2009 Christoph Pfisterer * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * * Neither the name of Christoph Pfisterer nor the names of the * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Modifications copyright (c) 2012-2015 Roderick W. Smith * * Modifications distributed under the terms of the GNU General Public * License (GPL) version 3 (GPLv3), a copy of which must be distributed * with this source code or binaries made from it. * */ #ifndef __ICNS_H_ #define __ICNS_H_ // // icns loader module // EG_IMAGE * LoadOSIcon(IN CHAR16 *OSIconName OPTIONAL, IN CHAR16 *FallbackIconName, BOOLEAN BootLogo); EG_IMAGE * DummyImage(IN UINTN PixelSize); EG_IMAGE * BuiltinIcon(IN UINTN Id); #define BUILTIN_ICON_FUNC_ABOUT (0) #define BUILTIN_ICON_FUNC_RESET (1) #define BUILTIN_ICON_FUNC_SHUTDOWN (2) #define BUILTIN_ICON_FUNC_EXIT (3) #define BUILTIN_ICON_FUNC_FIRMWARE (4) #define BUILTIN_ICON_FUNC_CSR_ROTATE (5) #define BUILTIN_ICON_FUNC_HIDDEN (6) #define BUILTIN_ICON_TOOL_SHELL (7) #define BUILTIN_ICON_TOOL_PART (8) #define BUILTIN_ICON_TOOL_RESCUE (9) #define BUILTIN_ICON_TOOL_APPLE_RESCUE (10) #define BUILTIN_ICON_TOOL_WINDOWS_RESCUE (11) #define BUILTIN_ICON_TOOL_MOK_TOOL (12) #define BUILTIN_ICON_TOOL_FWUPDATE (13) #define BUILTIN_ICON_TOOL_MEMTEST (14) #define BUILTIN_ICON_TOOL_NETBOOT (15) #define BUILTIN_ICON_VOL_INTERNAL (16) #define BUILTIN_ICON_VOL_EXTERNAL (17) #define BUILTIN_ICON_VOL_OPTICAL (18) #define BUILTIN_ICON_VOL_NET (19) #define BUILTIN_ICON_MOUSE (20) #define BUILTIN_ICON_COUNT (21) #endif /* EOF */ �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/refind/config.c�����������������������������������������������������������������������0000664�0001750�0001750�00000136567�13325626735�016230� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * refind/config.c * Configuration file functions * * Copyright (c) 2006 Christoph Pfisterer * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * * Neither the name of Christoph Pfisterer nor the names of the * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Modifications copyright (c) 2012-2015 Roderick W. Smith * * Modifications distributed under the terms of the GNU General Public * License (GPL) version 3 (GPLv3) or (at your option) any later version. * */ /* * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "global.h" #include "lib.h" #include "icns.h" #include "menu.h" #include "config.h" #include "screen.h" #include "apple.h" #include "mystrings.h" #include "../include/refit_call_wrapper.h" #include "../mok/mok.h" // constants #define LINUX_OPTIONS_FILENAMES L"refind_linux.conf,refind-linux.conf" #define MAXCONFIGFILESIZE (128*1024) #define ENCODING_ISO8859_1 (0) #define ENCODING_UTF8 (1) #define ENCODING_UTF16_LE (2) #define GetTime ST->RuntimeServices->GetTime #define LAST_MINUTE 1439 /* Last minute of a day */ extern REFIT_MENU_ENTRY MenuEntryReturn; //static REFIT_MENU_ENTRY MenuEntryReturn = { L"Return to Main Menu", TAG_RETURN, 0, 0, 0, NULL, NULL, NULL }; // // read a file into a buffer // EFI_STATUS ReadFile(IN EFI_FILE_HANDLE BaseDir, IN CHAR16 *FileName, IN OUT REFIT_FILE *File, OUT UINTN *size) { EFI_STATUS Status; EFI_FILE_HANDLE FileHandle; EFI_FILE_INFO *FileInfo; UINT64 ReadSize; CHAR16 Message[256]; File->Buffer = NULL; File->BufferSize = 0; // read the file, allocating a buffer on the way Status = refit_call5_wrapper(BaseDir->Open, BaseDir, &FileHandle, FileName, EFI_FILE_MODE_READ, 0); SPrint(Message, 255, L"while loading the file '%s'", FileName); if (CheckError(Status, Message)) return Status; FileInfo = LibFileInfo(FileHandle); if (FileInfo == NULL) { // TODO: print and register the error refit_call1_wrapper(FileHandle->Close, FileHandle); return EFI_LOAD_ERROR; } ReadSize = FileInfo->FileSize; FreePool(FileInfo); File->BufferSize = (UINTN)ReadSize; File->Buffer = AllocatePool(File->BufferSize); if (File->Buffer == NULL) { size = 0; return EFI_OUT_OF_RESOURCES; } else { *size = File->BufferSize; } // if/else Status = refit_call3_wrapper(FileHandle->Read, FileHandle, &File->BufferSize, File->Buffer); if (CheckError(Status, Message)) { MyFreePool(File->Buffer); File->Buffer = NULL; refit_call1_wrapper(FileHandle->Close, FileHandle); return Status; } Status = refit_call1_wrapper(FileHandle->Close, FileHandle); // setup for reading File->Current8Ptr = (CHAR8 *)File->Buffer; File->End8Ptr = File->Current8Ptr + File->BufferSize; File->Current16Ptr = (CHAR16 *)File->Buffer; File->End16Ptr = File->Current16Ptr + (File->BufferSize >> 1); // detect encoding File->Encoding = ENCODING_ISO8859_1; // default: 1:1 translation of CHAR8 to CHAR16 if (File->BufferSize >= 4) { if (File->Buffer[0] == 0xFF && File->Buffer[1] == 0xFE) { // BOM in UTF-16 little endian (or UTF-32 little endian) File->Encoding = ENCODING_UTF16_LE; // use CHAR16 as is File->Current16Ptr++; } else if (File->Buffer[0] == 0xEF && File->Buffer[1] == 0xBB && File->Buffer[2] == 0xBF) { // BOM in UTF-8 File->Encoding = ENCODING_UTF8; // translate from UTF-8 to UTF-16 File->Current8Ptr += 3; } else if (File->Buffer[1] == 0 && File->Buffer[3] == 0) { File->Encoding = ENCODING_UTF16_LE; // use CHAR16 as is } // TODO: detect other encodings as they are implemented } return EFI_SUCCESS; } // // get a single line of text from a file // static CHAR16 *ReadLine(REFIT_FILE *File) { CHAR16 *Line, *q; UINTN LineLength; if (File->Buffer == NULL) return NULL; if (File->Encoding == ENCODING_ISO8859_1 || File->Encoding == ENCODING_UTF8) { CHAR8 *p, *LineStart, *LineEnd; p = File->Current8Ptr; if (p >= File->End8Ptr) return NULL; LineStart = p; for (; p < File->End8Ptr; p++) if (*p == 13 || *p == 10) break; LineEnd = p; for (; p < File->End8Ptr; p++) if (*p != 13 && *p != 10) break; File->Current8Ptr = p; LineLength = (UINTN)(LineEnd - LineStart) + 1; Line = AllocatePool(LineLength * sizeof(CHAR16)); if (Line == NULL) return NULL; q = Line; if (File->Encoding == ENCODING_ISO8859_1) { for (p = LineStart; p < LineEnd; ) *q++ = *p++; } else if (File->Encoding == ENCODING_UTF8) { // TODO: actually handle UTF-8 for (p = LineStart; p < LineEnd; ) *q++ = *p++; } *q = 0; } else if (File->Encoding == ENCODING_UTF16_LE) { CHAR16 *p, *LineStart, *LineEnd; p = File->Current16Ptr; if (p >= File->End16Ptr) return NULL; LineStart = p; for (; p < File->End16Ptr; p++) if (*p == 13 || *p == 10) break; LineEnd = p; for (; p < File->End16Ptr; p++) if (*p != 13 && *p != 10) break; File->Current16Ptr = p; LineLength = (UINTN)(LineEnd - LineStart) + 1; Line = AllocatePool(LineLength * sizeof(CHAR16)); if (Line == NULL) return NULL; for (p = LineStart, q = Line; p < LineEnd; ) *q++ = *p++; *q = 0; } else return NULL; // unsupported encoding return Line; } // Returns FALSE if *p points to the end of a token, TRUE otherwise. // Also modifies *p **IF** the first and second characters are both // quotes ('"'); it deletes one of them. static BOOLEAN KeepReading(IN OUT CHAR16 *p, IN OUT BOOLEAN *IsQuoted) { BOOLEAN MoreToRead = FALSE; CHAR16 *Temp = NULL; if ((p == NULL) || (IsQuoted == NULL)) return FALSE; if (*p == L'\0') return FALSE; if ((*p != ' ' && *p != '\t' && *p != '=' && *p != '#' && *p != ',') || *IsQuoted) { MoreToRead = TRUE; } if (*p == L'"') { if (p[1] == L'"') { Temp = StrDuplicate(&p[1]); if (Temp != NULL) { StrCpy(p, Temp); FreePool(Temp); } MoreToRead = TRUE; } else { *IsQuoted = !(*IsQuoted); MoreToRead = FALSE; } // if/else second character is a quote } // if first character is a quote return MoreToRead; } // BOOLEAN KeepReading() // // get a line of tokens from a file // UINTN ReadTokenLine(IN REFIT_FILE *File, OUT CHAR16 ***TokenList) { BOOLEAN LineFinished, IsQuoted = FALSE; CHAR16 *Line, *Token, *p; UINTN TokenCount = 0; *TokenList = NULL; while (TokenCount == 0) { Line = ReadLine(File); if (Line == NULL) return(0); p = Line; LineFinished = FALSE; while (!LineFinished) { // skip whitespace & find start of token while ((*p == ' ' || *p == '\t' || *p == '=' || *p == ',') && !IsQuoted) p++; if (*p == 0 || *p == '#') break; if (*p == '"') { IsQuoted = !IsQuoted; p++; } // if Token = p; // find end of token while (KeepReading(p, &IsQuoted)) { if ((*p == L'/') && !IsQuoted) // Switch Unix-style to DOS-style directory separators *p = L'\\'; p++; } // while if (*p == L'\0' || *p == L'#') LineFinished = TRUE; *p++ = 0; AddListElement((VOID ***)TokenList, &TokenCount, (VOID *)StrDuplicate(Token)); } FreePool(Line); } return (TokenCount); } /* ReadTokenLine() */ VOID FreeTokenLine(IN OUT CHAR16 ***TokenList, IN OUT UINTN *TokenCount) { // TODO: also free the items FreeList((VOID ***)TokenList, TokenCount); } // handle a parameter with a single integer argument static VOID HandleInt(IN CHAR16 **TokenList, IN UINTN TokenCount, OUT UINTN *Value) { if (TokenCount == 2) { if (StrCmp(TokenList[1], L"-1") == 0) *Value = -1; else *Value = Atoi(TokenList[1]); } } // handle a parameter with a single string argument static VOID HandleString(IN CHAR16 **TokenList, IN UINTN TokenCount, OUT CHAR16 **Target) { if ((TokenCount == 2) && Target) { MyFreePool(*Target); *Target = StrDuplicate(TokenList[1]); } // if } // static VOID HandleString() // Handle a parameter with a series of string arguments, to replace or be added to a // comma-delimited list. Passes each token through the CleanUpPathNameSlashes() function // to ensure consistency in subsequent comparisons of filenames. If the first // non-keyword token is "+", the list is added to the existing target string; otherwise, // the tokens replace the current string. static VOID HandleStrings(IN CHAR16 **TokenList, IN UINTN TokenCount, OUT CHAR16 **Target) { UINTN i; BOOLEAN AddMode = FALSE; if ((TokenCount > 2) && (StrCmp(TokenList[1], L"+") == 0)) { AddMode = TRUE; } if ((*Target != NULL) && !AddMode) { FreePool(*Target); *Target = NULL; } // if for (i = 1; i < TokenCount; i++) { if ((i != 1) || !AddMode) { CleanUpPathNameSlashes(TokenList[i]); MergeStrings(Target, TokenList[i], L','); } // if } // for } // static VOID HandleStrings() // Handle a parameter with a series of hexadecimal arguments, to replace or be added to a // linked list of UINT32 values. Any item with a non-hexadecimal value is discarded, as is // any value that exceeds MaxValue. If the first non-keyword token is "+", the new list is // added to the existing Target; otherwise, the interpreted tokens replace the current // Target. static VOID HandleHexes(IN CHAR16 **TokenList, IN UINTN TokenCount, IN UINTN MaxValue, OUT UINT32_LIST **Target) { UINTN InputIndex = 1, i; UINT32 Value; UINT32_LIST *EndOfList = NULL; UINT32_LIST *NewEntry; if ((TokenCount > 2) && (StrCmp(TokenList[1], L"+") == 0)) { InputIndex = 2; EndOfList = *Target; while (EndOfList && (EndOfList->Next != NULL)) { EndOfList = EndOfList->Next; } } else { EraseUint32List(Target); } for (i = InputIndex; i < TokenCount; i++) { if (IsValidHex(TokenList[i])) { Value = (UINT32) StrToHex(TokenList[i], 0, 8); if (Value <= MaxValue) { NewEntry = AllocatePool(sizeof(UINT32_LIST)); if (NewEntry) { NewEntry->Value = Value; NewEntry->Next = NULL; if (EndOfList == NULL) { EndOfList = NewEntry; *Target = NewEntry; } else { EndOfList->Next = NewEntry; EndOfList = NewEntry; } // if/else } // if allocated memory for NewEntry } // if (Value < MaxValue) } // if is valid hex value } // for } // static VOID HandleHexes() // Convert TimeString (in "HH:MM" format) to a pure-minute format. Values should be // in the range from 0 (for 00:00, or midnight) to 1439 (for 23:59; aka LAST_MINUTE). // Any value outside that range denotes an error in the specification. Note that if // the input is a number that includes no colon, this function will return the original // number in UINTN form. static UINTN HandleTime(IN CHAR16 *TimeString) { UINTN Hour = 0, Minute = 0, TimeLength, i = 0; TimeLength = StrLen(TimeString); while (i < TimeLength) { if (TimeString[i] == L':') { Hour = Minute; Minute = 0; } // if if ((TimeString[i] >= L'0') && (TimeString[i] <= '9')) { Minute *= 10; Minute += (TimeString[i] - L'0'); } // if i++; } // while return (Hour * 60 + Minute); } // BOOLEAN HandleTime() static BOOLEAN HandleBoolean(IN CHAR16 **TokenList, IN UINTN TokenCount) { BOOLEAN TruthValue = TRUE; if ((TokenCount >= 2) && ((StrCmp(TokenList[1], L"0") == 0) || MyStriCmp(TokenList[1], L"false") || MyStriCmp(TokenList[1], L"off"))) { TruthValue = FALSE; } // if return TruthValue; } // BOOLEAN HandleBoolean // Sets the default boot loader IF the current time is within the bounds // defined by the third and fourth tokens in the TokenList. static VOID SetDefaultByTime(IN CHAR16 **TokenList, OUT CHAR16 **Default) { EFI_STATUS Status; EFI_TIME CurrentTime; UINTN StartTime, EndTime, Now; BOOLEAN SetIt = FALSE; StartTime = HandleTime(TokenList[2]); EndTime = HandleTime(TokenList[3]); if ((StartTime <= LAST_MINUTE) && (EndTime <= LAST_MINUTE)) { Status = refit_call2_wrapper(GetTime, &CurrentTime, NULL); if (Status != EFI_SUCCESS) return; Now = CurrentTime.Hour * 60 + CurrentTime.Minute; if (Now > LAST_MINUTE) { // Shouldn't happen; just being paranoid Print(L"Warning: Impossible system time: %d:%d\n", CurrentTime.Hour, CurrentTime.Minute); return; } // if impossible time if (StartTime < EndTime) { // Time range does NOT cross midnight if ((Now >= StartTime) && (Now <= EndTime)) SetIt = TRUE; } else { // Time range DOES cross midnight if ((Now >= StartTime) && (Now <= EndTime)) SetIt = TRUE; } // if/else time range crosses midnight if (SetIt) { MyFreePool(*Default); *Default = StrDuplicate(TokenList[1]); } // if (SetIt) } // if ((StartTime <= LAST_MINUTE) && (EndTime <= LAST_MINUTE)) } // VOID SetDefaultByTime() // read config file VOID ReadConfig(CHAR16 *FileName) { EFI_STATUS Status; REFIT_FILE File; CHAR16 **TokenList; CHAR16 *FlagName; CHAR16 *TempStr = NULL; UINTN TokenCount, i; // Set a few defaults only if we're loading the default file. if (MyStriCmp(FileName, GlobalConfig.ConfigFilename)) { MyFreePool(GlobalConfig.AlsoScan); GlobalConfig.AlsoScan = StrDuplicate(ALSO_SCAN_DIRS); MyFreePool(GlobalConfig.DontScanDirs); if (SelfVolume) { if (SelfVolume->VolName) { TempStr = SelfVolume->VolName ? StrDuplicate(SelfVolume->VolName) : NULL; } else { TempStr = GuidAsString(&(SelfVolume->PartGuid)); } // if/else } MergeStrings(&TempStr, SelfDirPath, L':'); MergeStrings(&TempStr, MEMTEST_LOCATIONS, L','); GlobalConfig.DontScanDirs = TempStr; MyFreePool(GlobalConfig.DontScanFiles); GlobalConfig.DontScanFiles = StrDuplicate(DONT_SCAN_FILES); MyFreePool(GlobalConfig.DontScanTools); GlobalConfig.DontScanTools = NULL; MergeStrings(&(GlobalConfig.DontScanFiles), MOK_NAMES, L','); MergeStrings(&(GlobalConfig.DontScanFiles), FWUPDATE_NAMES, L','); MyFreePool(GlobalConfig.DontScanVolumes); GlobalConfig.DontScanVolumes = StrDuplicate(DONT_SCAN_VOLUMES); GlobalConfig.WindowsRecoveryFiles = StrDuplicate(WINDOWS_RECOVERY_FILES); GlobalConfig.MacOSRecoveryFiles = StrDuplicate(MACOS_RECOVERY_FILES); MyFreePool(GlobalConfig.DefaultSelection); GlobalConfig.DefaultSelection = StrDuplicate(L"+"); } // if if (!FileExists(SelfDir, FileName)) { Print(L"Configuration file '%s' missing!\n", FileName); if (!FileExists(SelfDir, L"icons")) { Print(L"Icons directory doesn't exist; setting textonly = TRUE!\n"); GlobalConfig.TextOnly = TRUE; } return; } Status = ReadFile(SelfDir, FileName, &File, &i); if (EFI_ERROR(Status)) return; for (;;) { TokenCount = ReadTokenLine(&File, &TokenList); if (TokenCount == 0) break; if (MyStriCmp(TokenList[0], L"timeout")) { HandleInt(TokenList, TokenCount, &(GlobalConfig.Timeout)); } else if (MyStriCmp(TokenList[0], L"shutdown_after_timeout")) { GlobalConfig.ShutdownAfterTimeout = HandleBoolean(TokenList, TokenCount); } else if (MyStriCmp(TokenList[0], L"hideui")) { for (i = 1; i < TokenCount; i++) { FlagName = TokenList[i]; if (MyStriCmp(FlagName, L"banner")) { GlobalConfig.HideUIFlags |= HIDEUI_FLAG_BANNER; } else if (MyStriCmp(FlagName, L"label")) { GlobalConfig.HideUIFlags |= HIDEUI_FLAG_LABEL; } else if (MyStriCmp(FlagName, L"singleuser")) { GlobalConfig.HideUIFlags |= HIDEUI_FLAG_SINGLEUSER; } else if (MyStriCmp(FlagName, L"hwtest")) { GlobalConfig.HideUIFlags |= HIDEUI_FLAG_HWTEST; } else if (MyStriCmp(FlagName, L"arrows")) { GlobalConfig.HideUIFlags |= HIDEUI_FLAG_ARROWS; } else if (MyStriCmp(FlagName, L"hints")) { GlobalConfig.HideUIFlags |= HIDEUI_FLAG_HINTS; } else if (MyStriCmp(FlagName, L"editor")) { GlobalConfig.HideUIFlags |= HIDEUI_FLAG_EDITOR; } else if (MyStriCmp(FlagName, L"safemode")) { GlobalConfig.HideUIFlags |= HIDEUI_FLAG_SAFEMODE; } else if (MyStriCmp(FlagName, L"badges")) { GlobalConfig.HideUIFlags |= HIDEUI_FLAG_BADGES; } else if (MyStriCmp(FlagName, L"all")) { GlobalConfig.HideUIFlags = HIDEUI_FLAG_ALL; } else { Print(L" unknown hideui flag: '%s'\n", FlagName); } } } else if (MyStriCmp(TokenList[0], L"icons_dir")) { HandleString(TokenList, TokenCount, &(GlobalConfig.IconsDir)); } else if (MyStriCmp(TokenList[0], L"scanfor")) { for (i = 0; i < NUM_SCAN_OPTIONS; i++) { if (i < TokenCount) GlobalConfig.ScanFor[i] = TokenList[i][0]; else GlobalConfig.ScanFor[i] = ' '; } } else if (MyStriCmp(TokenList[0], L"use_nvram")) { GlobalConfig.UseNvram = HandleBoolean(TokenList, TokenCount); } else if (MyStriCmp(TokenList[0], L"uefi_deep_legacy_scan")) { GlobalConfig.DeepLegacyScan = HandleBoolean(TokenList, TokenCount); } else if (MyStriCmp(TokenList[0], L"scan_delay") && (TokenCount == 2)) { HandleInt(TokenList, TokenCount, &(GlobalConfig.ScanDelay)); } else if (MyStriCmp(TokenList[0], L"also_scan_dirs")) { HandleStrings(TokenList, TokenCount, &(GlobalConfig.AlsoScan)); } else if (MyStriCmp(TokenList[0], L"don't_scan_volumes") || MyStriCmp(TokenList[0], L"dont_scan_volumes")) { // Note: Don't use HandleStrings() because it modifies slashes, which might be present in volume name MyFreePool(GlobalConfig.DontScanVolumes); GlobalConfig.DontScanVolumes = NULL; for (i = 1; i < TokenCount; i++) { MergeStrings(&GlobalConfig.DontScanVolumes, TokenList[i], L','); } } else if (MyStriCmp(TokenList[0], L"don't_scan_dirs") || MyStriCmp(TokenList[0], L"dont_scan_dirs")) { HandleStrings(TokenList, TokenCount, &(GlobalConfig.DontScanDirs)); } else if (MyStriCmp(TokenList[0], L"don't_scan_files") || MyStriCmp(TokenList[0], L"dont_scan_files")) { HandleStrings(TokenList, TokenCount, &(GlobalConfig.DontScanFiles)); } else if (MyStriCmp(TokenList[0], L"don't_scan_tools") || MyStriCmp(TokenList[0], L"dont_scan_tools")) { HandleStrings(TokenList, TokenCount, &(GlobalConfig.DontScanTools)); } else if (MyStriCmp(TokenList[0], L"windows_recovery_files")) { HandleStrings(TokenList, TokenCount, &(GlobalConfig.WindowsRecoveryFiles)); } else if (MyStriCmp(TokenList[0], L"scan_driver_dirs")) { HandleStrings(TokenList, TokenCount, &(GlobalConfig.DriverDirs)); } else if (MyStriCmp(TokenList[0], L"showtools")) { SetMem(GlobalConfig.ShowTools, NUM_TOOLS * sizeof(UINTN), 0); GlobalConfig.HiddenTags = FALSE; for (i = 1; (i < TokenCount) && (i < NUM_TOOLS); i++) { FlagName = TokenList[i]; if (MyStriCmp(FlagName, L"shell")) { GlobalConfig.ShowTools[i - 1] = TAG_SHELL; } else if (MyStriCmp(FlagName, L"gptsync")) { GlobalConfig.ShowTools[i - 1] = TAG_GPTSYNC; } else if (MyStriCmp(FlagName, L"gdisk")) { GlobalConfig.ShowTools[i - 1] = TAG_GDISK; } else if (MyStriCmp(FlagName, L"about")) { GlobalConfig.ShowTools[i - 1] = TAG_ABOUT; } else if (MyStriCmp(FlagName, L"exit")) { GlobalConfig.ShowTools[i - 1] = TAG_EXIT; } else if (MyStriCmp(FlagName, L"reboot")) { GlobalConfig.ShowTools[i - 1] = TAG_REBOOT; } else if (MyStriCmp(FlagName, L"shutdown")) { GlobalConfig.ShowTools[i - 1] = TAG_SHUTDOWN; } else if (MyStriCmp(FlagName, L"apple_recovery")) { GlobalConfig.ShowTools[i - 1] = TAG_APPLE_RECOVERY; } else if (MyStriCmp(FlagName, L"windows_recovery")) { GlobalConfig.ShowTools[i - 1] = TAG_WINDOWS_RECOVERY; } else if (MyStriCmp(FlagName, L"mok_tool")) { GlobalConfig.ShowTools[i - 1] = TAG_MOK_TOOL; } else if (MyStriCmp(FlagName, L"fwupdate")) { GlobalConfig.ShowTools[i - 1] = TAG_FWUPDATE_TOOL; } else if (MyStriCmp(FlagName, L"csr_rotate")) { GlobalConfig.ShowTools[i - 1] = TAG_CSR_ROTATE; } else if (MyStriCmp(FlagName, L"firmware")) { GlobalConfig.ShowTools[i - 1] = TAG_FIRMWARE; } else if (MyStriCmp(FlagName, L"memtest86") || MyStriCmp(FlagName, L"memtest")) { GlobalConfig.ShowTools[i - 1] = TAG_MEMTEST; } else if (MyStriCmp(FlagName, L"netboot")) { GlobalConfig.ShowTools[i - 1] = TAG_NETBOOT; } else if (MyStriCmp(FlagName, L"hidden_tags")) { GlobalConfig.ShowTools[i - 1] = TAG_HIDDEN; GlobalConfig.HiddenTags = TRUE; } else { Print(L" unknown showtools flag: '%s'\n", FlagName); } } // showtools options } else if (MyStriCmp(TokenList[0], L"banner")) { HandleString(TokenList, TokenCount, &(GlobalConfig.BannerFileName)); } else if (MyStriCmp(TokenList[0], L"banner_scale") && (TokenCount == 2)) { if (MyStriCmp(TokenList[1], L"noscale")) { GlobalConfig.BannerScale = BANNER_NOSCALE; } else if (MyStriCmp(TokenList[1], L"fillscreen") || MyStriCmp(TokenList[1], L"fullscreen")) { GlobalConfig.BannerScale = BANNER_FILLSCREEN; } else { Print(L" unknown banner_type flag: '%s'\n", TokenList[1]); } // if/else } else if (MyStriCmp(TokenList[0], L"small_icon_size") && (TokenCount == 2)) { HandleInt(TokenList, TokenCount, &i); if (i >= 32) { GlobalConfig.IconSizes[ICON_SIZE_SMALL] = i; HaveResized = TRUE; } } else if (MyStriCmp(TokenList[0], L"big_icon_size") && (TokenCount == 2)) { HandleInt(TokenList, TokenCount, &i); if (i >= 32) { GlobalConfig.IconSizes[ICON_SIZE_BIG] = i; GlobalConfig.IconSizes[ICON_SIZE_BADGE] = i / 4; HaveResized = TRUE; } } else if (MyStriCmp(TokenList[0], L"mouse_size") && (TokenCount == 2)) { HandleInt(TokenList, TokenCount, &i); if (i >= DEFAULT_MOUSE_SIZE) { GlobalConfig.IconSizes[ICON_SIZE_MOUSE] = i; } } else if (MyStriCmp(TokenList[0], L"selection_small")) { HandleString(TokenList, TokenCount, &(GlobalConfig.SelectionSmallFileName)); } else if (MyStriCmp(TokenList[0], L"selection_big")) { HandleString(TokenList, TokenCount, &(GlobalConfig.SelectionBigFileName)); } else if (MyStriCmp(TokenList[0], L"default_selection")) { if (TokenCount == 4) { SetDefaultByTime(TokenList, &(GlobalConfig.DefaultSelection)); } else { HandleString(TokenList, TokenCount, &(GlobalConfig.DefaultSelection)); } } else if (MyStriCmp(TokenList[0], L"textonly")) { GlobalConfig.TextOnly = HandleBoolean(TokenList, TokenCount); } else if (MyStriCmp(TokenList[0], L"textmode")) { HandleInt(TokenList, TokenCount, &(GlobalConfig.RequestedTextMode)); } else if (MyStriCmp(TokenList[0], L"resolution") && ((TokenCount == 2) || (TokenCount == 3))) { GlobalConfig.RequestedScreenWidth = Atoi(TokenList[1]); if (TokenCount == 3) GlobalConfig.RequestedScreenHeight = Atoi(TokenList[2]); else GlobalConfig.RequestedScreenHeight = 0; } else if (MyStriCmp(TokenList[0], L"screensaver")) { HandleInt(TokenList, TokenCount, &(GlobalConfig.ScreensaverTime)); } else if (MyStriCmp(TokenList[0], L"use_graphics_for")) { if ((TokenCount == 2) || ((TokenCount > 2) && (!MyStriCmp(TokenList[1], L"+")))) GlobalConfig.GraphicsFor = 0; for (i = 1; i < TokenCount; i++) { if (MyStriCmp(TokenList[i], L"osx")) { GlobalConfig.GraphicsFor |= GRAPHICS_FOR_OSX; } else if (MyStriCmp(TokenList[i], L"linux")) { GlobalConfig.GraphicsFor |= GRAPHICS_FOR_LINUX; } else if (MyStriCmp(TokenList[i], L"elilo")) { GlobalConfig.GraphicsFor |= GRAPHICS_FOR_ELILO; } else if (MyStriCmp(TokenList[i], L"grub")) { GlobalConfig.GraphicsFor |= GRAPHICS_FOR_GRUB; } else if (MyStriCmp(TokenList[i], L"windows")) { GlobalConfig.GraphicsFor |= GRAPHICS_FOR_WINDOWS; } } // for (graphics_on tokens) } else if (MyStriCmp(TokenList[0], L"font") && (TokenCount == 2)) { egLoadFont(TokenList[1]); } else if (MyStriCmp(TokenList[0], L"scan_all_linux_kernels")) { GlobalConfig.ScanAllLinux = HandleBoolean(TokenList, TokenCount); } else if (MyStriCmp(TokenList[0], L"fold_linux_kernels")) { GlobalConfig.FoldLinuxKernels = HandleBoolean(TokenList, TokenCount); } else if (MyStriCmp(TokenList[0], L"extra_kernel_version_strings")) { HandleStrings(TokenList, TokenCount, &(GlobalConfig.ExtraKernelVersionStrings)); } else if (MyStriCmp(TokenList[0], L"max_tags")) { HandleInt(TokenList, TokenCount, &(GlobalConfig.MaxTags)); } else if (MyStriCmp(TokenList[0], L"enable_and_lock_vmx")) { GlobalConfig.EnableAndLockVMX = HandleBoolean(TokenList, TokenCount); } else if (MyStriCmp(TokenList[0], L"spoof_osx_version")) { HandleString(TokenList, TokenCount, &(GlobalConfig.SpoofOSXVersion)); } else if (MyStriCmp(TokenList[0], L"csr_values")) { HandleHexes(TokenList, TokenCount, CSR_MAX_LEGAL_VALUE, &(GlobalConfig.CsrValues)); } else if (MyStriCmp(TokenList[0], L"include") && (TokenCount == 2) && MyStriCmp(FileName, GlobalConfig.ConfigFilename)) { if (!MyStriCmp(TokenList[1], FileName)) { ReadConfig(TokenList[1]); } } else if (MyStriCmp(TokenList[0], L"enable_mouse")) { GlobalConfig.EnableMouse = HandleBoolean(TokenList, TokenCount); if(GlobalConfig.EnableMouse) { GlobalConfig.EnableTouch = FALSE; } } else if (MyStriCmp(TokenList[0], L"enable_touch")) { GlobalConfig.EnableTouch = HandleBoolean(TokenList, TokenCount); if(GlobalConfig.EnableTouch) { GlobalConfig.EnableMouse = FALSE; } } else if (MyStriCmp(TokenList[0], L"mouse_speed") && (TokenCount == 2)) { HandleInt(TokenList, TokenCount, &i); if (i < 1) i = 1; if (i > 32) i = 32; GlobalConfig.MouseSpeed = i; } FreeTokenLine(&TokenList, &TokenCount); } if ((GlobalConfig.DontScanFiles) && (GlobalConfig.WindowsRecoveryFiles)) MergeStrings(&(GlobalConfig.DontScanFiles), GlobalConfig.WindowsRecoveryFiles, L','); MyFreePool(File.Buffer); if (!FileExists(SelfDir, L"icons") && !FileExists(SelfDir, GlobalConfig.IconsDir)) { Print(L"Icons directory doesn't exist; setting textonly = TRUE!\n"); GlobalConfig.TextOnly = TRUE; } } /* VOID ReadConfig() */ static VOID AddSubmenu(LOADER_ENTRY *Entry, REFIT_FILE *File, REFIT_VOLUME *Volume, CHAR16 *Title) { REFIT_MENU_SCREEN *SubScreen; LOADER_ENTRY *SubEntry; UINTN TokenCount; CHAR16 **TokenList; SubScreen = InitializeSubScreen(Entry); // Set defaults for the new entry; will be modified based on lines read from the config. file.... SubEntry = InitializeLoaderEntry(Entry); if ((SubEntry == NULL) || (SubScreen == NULL)) return; SubEntry->me.Title = StrDuplicate(Title); while (((TokenCount = ReadTokenLine(File, &TokenList)) > 0) && (StrCmp(TokenList[0], L"}") != 0)) { if (MyStriCmp(TokenList[0], L"loader") && (TokenCount > 1)) { // set the boot loader filename MyFreePool(SubEntry->LoaderPath); SubEntry->LoaderPath = StrDuplicate(TokenList[1]); SubEntry->Volume = Volume; } else if (MyStriCmp(TokenList[0], L"volume") && (TokenCount > 1)) { if (FindVolume(&Volume, TokenList[1])) { if ((Volume != NULL) && (Volume->IsReadable) && (Volume->RootDir)) { MyFreePool(SubEntry->me.Title); SubEntry->me.Title = AllocateZeroPool(256 * sizeof(CHAR16)); SPrint(SubEntry->me.Title, 255, L"Boot %s from %s", (Title != NULL) ? Title : L"Unknown", Volume->VolName); SubEntry->me.BadgeImage = Volume->VolBadgeImage; SubEntry->Volume = Volume; } // if volume is readable } // if match found } else if (MyStriCmp(TokenList[0], L"initrd")) { MyFreePool(SubEntry->InitrdPath); SubEntry->InitrdPath = NULL; if (TokenCount > 1) { SubEntry->InitrdPath = StrDuplicate(TokenList[1]); } } else if (MyStriCmp(TokenList[0], L"options")) { MyFreePool(SubEntry->LoadOptions); SubEntry->LoadOptions = NULL; if (TokenCount > 1) { SubEntry->LoadOptions = StrDuplicate(TokenList[1]); } // if/else } else if (MyStriCmp(TokenList[0], L"add_options") && (TokenCount > 1)) { MergeStrings(&SubEntry->LoadOptions, TokenList[1], L' '); } else if (MyStriCmp(TokenList[0], L"graphics") && (TokenCount > 1)) { SubEntry->UseGraphicsMode = MyStriCmp(TokenList[1], L"on"); } else if (MyStriCmp(TokenList[0], L"disabled")) { SubEntry->Enabled = FALSE; } // ief/elseif FreeTokenLine(&TokenList, &TokenCount); } // while() if (SubEntry->InitrdPath != NULL) { MergeStrings(&SubEntry->LoadOptions, L"initrd=", L' '); MergeStrings(&SubEntry->LoadOptions, SubEntry->InitrdPath, 0); MyFreePool(SubEntry->InitrdPath); SubEntry->InitrdPath = NULL; } // if if (SubEntry->Enabled == TRUE) { AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); } Entry->me.SubScreen = SubScreen; } // VOID AddSubmenu() // Adds the options from a SINGLE refind.conf stanza to a new loader entry and returns // that entry. The calling function is then responsible for adding the entry to the // list of entries. static LOADER_ENTRY * AddStanzaEntries(REFIT_FILE *File, REFIT_VOLUME *Volume, CHAR16 *Title) { CHAR16 **TokenList; UINTN TokenCount; LOADER_ENTRY *Entry; BOOLEAN DefaultsSet = FALSE, AddedSubmenu = FALSE; REFIT_VOLUME *CurrentVolume = Volume; // prepare the menu entry Entry = InitializeLoaderEntry(NULL); if (Entry == NULL) return NULL; Entry->Title = StrDuplicate(Title); Entry->me.Title = AllocateZeroPool(256 * sizeof(CHAR16)); SPrint(Entry->me.Title, 255, L"Boot %s from %s", (Title != NULL) ? Title : L"Unknown", CurrentVolume->VolName); Entry->me.Row = 0; Entry->me.BadgeImage = CurrentVolume->VolBadgeImage; Entry->Volume = CurrentVolume; Entry->DiscoveryType = DISCOVERY_TYPE_MANUAL; // Parse the config file to add options for a single stanza, terminating when the token // is "}" or when the end of file is reached. while (((TokenCount = ReadTokenLine(File, &TokenList)) > 0) && (StrCmp(TokenList[0], L"}") != 0)) { if (MyStriCmp(TokenList[0], L"loader") && (TokenCount > 1)) { // set the boot loader filename Entry->LoaderPath = StrDuplicate(TokenList[1]); SetLoaderDefaults(Entry, TokenList[1], CurrentVolume); MyFreePool(Entry->LoadOptions); Entry->LoadOptions = NULL; // Discard default options, if any DefaultsSet = TRUE; } else if (MyStriCmp(TokenList[0], L"volume") && (TokenCount > 1)) { if (FindVolume(&CurrentVolume, TokenList[1])) { if ((CurrentVolume != NULL) && (CurrentVolume->IsReadable) && (CurrentVolume->RootDir)) { MyFreePool(Entry->me.Title); Entry->me.Title = AllocateZeroPool(256 * sizeof(CHAR16)); SPrint(Entry->me.Title, 255, L"Boot %s from %s", (Title != NULL) ? Title : L"Unknown", CurrentVolume->VolName); Entry->me.BadgeImage = CurrentVolume->VolBadgeImage; Entry->Volume = CurrentVolume; } // if volume is readable } // if match found } else if (MyStriCmp(TokenList[0], L"icon") && (TokenCount > 1)) { MyFreePool(Entry->me.Image); Entry->me.Image = egLoadIcon(CurrentVolume->RootDir, TokenList[1], GlobalConfig.IconSizes[ICON_SIZE_BIG]); if (Entry->me.Image == NULL) { Entry->me.Image = DummyImage(GlobalConfig.IconSizes[ICON_SIZE_BIG]); } } else if (MyStriCmp(TokenList[0], L"initrd") && (TokenCount > 1)) { MyFreePool(Entry->InitrdPath); Entry->InitrdPath = StrDuplicate(TokenList[1]); } else if (MyStriCmp(TokenList[0], L"options") && (TokenCount > 1)) { MyFreePool(Entry->LoadOptions); Entry->LoadOptions = StrDuplicate(TokenList[1]); } else if (MyStriCmp(TokenList[0], L"ostype") && (TokenCount > 1)) { if (TokenCount > 1) { Entry->OSType = TokenList[1][0]; } } else if (MyStriCmp(TokenList[0], L"graphics") && (TokenCount > 1)) { Entry->UseGraphicsMode = MyStriCmp(TokenList[1], L"on"); } else if (MyStriCmp(TokenList[0], L"disabled")) { Entry->Enabled = FALSE; } else if (MyStriCmp(TokenList[0], L"submenuentry") && (TokenCount > 1)) { AddSubmenu(Entry, File, CurrentVolume, TokenList[1]); AddedSubmenu = TRUE; } // set options to pass to the loader program FreeTokenLine(&TokenList, &TokenCount); } // while() if (AddedSubmenu) AddMenuEntry(Entry->me.SubScreen, &MenuEntryReturn); if (Entry->InitrdPath) { MergeStrings(&Entry->LoadOptions, L"initrd=", L' '); MergeStrings(&Entry->LoadOptions, Entry->InitrdPath, 0); MyFreePool(Entry->InitrdPath); Entry->InitrdPath = NULL; } // if if (!DefaultsSet) SetLoaderDefaults(Entry, L"\\EFI\\BOOT\\nemo.efi", CurrentVolume); // user included no "loader" line; use bogus one return(Entry); } // static VOID AddStanzaEntries() // Read the user-configured menu entries from refind.conf and add or delete // entries based on the contents of that file.... VOID ScanUserConfigured(CHAR16 *FileName) { EFI_STATUS Status; REFIT_FILE File; REFIT_VOLUME *Volume; CHAR16 **TokenList; CHAR16 *Title = NULL; UINTN TokenCount, size; LOADER_ENTRY *Entry; if (FileExists(SelfDir, FileName)) { Status = ReadFile(SelfDir, FileName, &File, &size); if (EFI_ERROR(Status)) return; Volume = SelfVolume; while ((TokenCount = ReadTokenLine(&File, &TokenList)) > 0) { if (MyStriCmp(TokenList[0], L"menuentry") && (TokenCount > 1)) { Title = StrDuplicate(TokenList[1]); Entry = AddStanzaEntries(&File, Volume, TokenList[1]); if (Entry->Enabled) { if (Entry->me.SubScreen == NULL) GenerateSubScreen(Entry, Volume, TRUE); AddPreparedLoaderEntry(Entry); } else { MyFreePool(Entry); } // if/else MyFreePool(Title); } else if (MyStriCmp(TokenList[0], L"include") && (TokenCount == 2) && MyStriCmp(FileName, GlobalConfig.ConfigFilename)) { if (!MyStriCmp(TokenList[1], FileName)) { ScanUserConfigured(TokenList[1]); } } // if/else if... FreeTokenLine(&TokenList, &TokenCount); } // while() } // if() } // VOID ScanUserConfigured() // Create an options file based on /etc/fstab. The resulting file has two options // lines, one of which boots the system with "ro root={rootfs}" and the other of // which boots the system with "ro root={rootfs} single", where "{rootfs}" is the // filesystem identifier associated with the "/" line in /etc/fstab. static REFIT_FILE * GenerateOptionsFromEtcFstab(REFIT_VOLUME *Volume) { UINTN TokenCount, i; REFIT_FILE *Options = NULL, *Fstab = NULL; EFI_STATUS Status; CHAR16 **TokenList, *Line, Root[100]; if (FileExists(Volume->RootDir, L"\\etc\\fstab")) { Options = AllocateZeroPool(sizeof(REFIT_FILE)); Fstab = AllocateZeroPool(sizeof(REFIT_FILE)); Status = ReadFile(Volume->RootDir, L"\\etc\\fstab", Fstab, &i); if (CheckError(Status, L"while reading /etc/fstab")) { if (Options != NULL) FreePool(Options); if (Fstab != NULL) FreePool(Fstab); Options = NULL; Fstab = NULL; } else { // File read; locate root fs and create entries Options->Encoding = ENCODING_UTF16_LE; while ((TokenCount = ReadTokenLine(Fstab, &TokenList)) > 0) { if (TokenCount > 2) { Root[0] = '\0'; if (StrCmp(TokenList[1], L"\\") == 0) { SPrint(Root, 99, L"%s", TokenList[0]); } else if (StrCmp(TokenList[2], L"\\") == 0) { SPrint(Root, 99, L"%s=%s", TokenList[0], TokenList[1]); } // if/elseif/elseif if (Root[0] != L'\0') { for (i = 0; i < StrLen(Root); i++) if (Root[i] == '\\') Root[i] = '/'; Line = PoolPrint(L"\"Boot with normal options\" \"ro root=%s\"\n", Root); MergeStrings((CHAR16 **) &(Options->Buffer), Line, 0); MyFreePool(Line); Line = PoolPrint(L"\"Boot into single-user mode\" \"ro root=%s single\"\n", Root); MergeStrings((CHAR16**) &(Options->Buffer), Line, 0); Options->BufferSize = StrLen((CHAR16*) Options->Buffer) * sizeof(CHAR16); } // if } // if FreeTokenLine(&TokenList, &TokenCount); } // while if (Options->Buffer) { Options->Current8Ptr = (CHAR8 *)Options->Buffer; Options->End8Ptr = Options->Current8Ptr + Options->BufferSize; Options->Current16Ptr = (CHAR16 *)Options->Buffer; Options->End16Ptr = Options->Current16Ptr + (Options->BufferSize >> 1); } else { MyFreePool(Options); Options = NULL; } MyFreePool(Fstab->Buffer); MyFreePool(Fstab); } // if/else file read error } // if /etc/fstab exists return Options; } // GenerateOptionsFromEtcFstab() // Create options from partition type codes. Specifically, if the earlier // partition scan found a partition with a type code corresponding to a root // filesystem according to the Freedesktop.org Discoverable Partitions Spec // (http://www.freedesktop.org/wiki/Specifications/DiscoverablePartitionsSpec/), // this function returns an appropriate file with two lines, one with // "ro root=/dev/disk/by-partuuid/{GUID}" and the other with that plus "single". // Note that this function returns the LAST partition found with the // appropriate type code, so this will work poorly on dual-boot systems or // if the type code is set incorrectly. static REFIT_FILE * GenerateOptionsFromPartTypes(VOID) { REFIT_FILE *Options = NULL; CHAR16 *Line, *GuidString, *WriteStatus; if (GlobalConfig.DiscoveredRoot) { Options = AllocateZeroPool(sizeof(REFIT_FILE)); if (Options) { Options->Encoding = ENCODING_UTF16_LE; GuidString = GuidAsString(&(GlobalConfig.DiscoveredRoot->PartGuid)); WriteStatus = GlobalConfig.DiscoveredRoot->IsMarkedReadOnly ? L"ro" : L"rw"; ToLower(GuidString); if (GuidString) { Line = PoolPrint(L"\"Boot with normal options\" \"%s root=/dev/disk/by-partuuid/%s\"\n", WriteStatus, GuidString); MergeStrings((CHAR16 **) &(Options->Buffer), Line, 0); MyFreePool(Line); Line = PoolPrint(L"\"Boot into single-user mode\" \"%s root=/dev/disk/by-partuuid/%s single\"\n", WriteStatus, GuidString); MergeStrings((CHAR16**) &(Options->Buffer), Line, 0); MyFreePool(Line); MyFreePool(GuidString); } // if (GuidString) Options->BufferSize = StrLen((CHAR16*) Options->Buffer) * sizeof(CHAR16); Options->Current8Ptr = (CHAR8 *)Options->Buffer; Options->End8Ptr = Options->Current8Ptr + Options->BufferSize; Options->Current16Ptr = (CHAR16 *)Options->Buffer; Options->End16Ptr = Options->Current16Ptr + (Options->BufferSize >> 1); } // if (Options allocated OK) } // if (partition has root GUID) return Options; } // REFIT_FILE * GenerateOptionsFromPartTypes() // Read a Linux kernel options file for a Linux boot loader into memory. The LoaderPath // and Volume variables identify the location of the options file, but not its name -- // you pass this function the filename of the Linux kernel, initial RAM disk, or other // file in the target directory, and this function finds the file with a name in the // comma-delimited list of names specified by LINUX_OPTIONS_FILENAMES within that // directory and loads it. If a rEFInd options file can't be found, try to generate // minimal options from /etc/fstab on the same volume as the kernel. This typically // works only if the kernel is being read from the Linux root filesystem. // // The return value is a pointer to the REFIT_FILE handle for the file, or NULL if // it wasn't found. REFIT_FILE * ReadLinuxOptionsFile(IN CHAR16 *LoaderPath, IN REFIT_VOLUME *Volume) { CHAR16 *OptionsFilename, *FullFilename; BOOLEAN GoOn = TRUE, FileFound = FALSE; UINTN i = 0, size; REFIT_FILE *File = NULL; EFI_STATUS Status; do { OptionsFilename = FindCommaDelimited(LINUX_OPTIONS_FILENAMES, i++); FullFilename = FindPath(LoaderPath); if ((OptionsFilename != NULL) && (FullFilename != NULL)) { MergeStrings(&FullFilename, OptionsFilename, '\\'); if (FileExists(Volume->RootDir, FullFilename)) { File = AllocateZeroPool(sizeof(REFIT_FILE)); Status = ReadFile(Volume->RootDir, FullFilename, File, &size); if (CheckError(Status, L"while loading the Linux options file")) { if (File != NULL) FreePool(File); File = NULL; } else { GoOn = FALSE; FileFound = TRUE; } // if/else error } // if file exists } else { // a filename string is NULL GoOn = FALSE; } // if/else MyFreePool(OptionsFilename); MyFreePool(FullFilename); OptionsFilename = FullFilename = NULL; } while (GoOn); if (!FileFound) { // No refind_linux.conf file; look for /etc/fstab and try to pull values from there.... File = GenerateOptionsFromEtcFstab(Volume); // If still no joy, try to use Freedesktop.org Discoverable Partitions Spec.... if (!File) File = GenerateOptionsFromPartTypes(); } // if return (File); } // static REFIT_FILE * ReadLinuxOptionsFile() // Retrieve a single line of options from a Linux kernel options file CHAR16 * GetFirstOptionsFromFile(IN CHAR16 *LoaderPath, IN REFIT_VOLUME *Volume) { UINTN TokenCount; CHAR16 *Options = NULL; CHAR16 **TokenList; REFIT_FILE *File; File = ReadLinuxOptionsFile(LoaderPath, Volume); if (File != NULL) { TokenCount = ReadTokenLine(File, &TokenList); if (TokenCount > 1) Options = StrDuplicate(TokenList[1]); FreeTokenLine(&TokenList, &TokenCount); FreePool(File); } // if return Options; } // static CHAR16 * GetOptionsFile() �����������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/refind/pointer.c����������������������������������������������������������������������0000664�0001750�0001750�00000025661�13325166353�016426� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * refind/pointer.c * Pointer device functions * * Copyright (c) 2018 CJ Vaughter * All rights reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "pointer.h" #include "global.h" #include "screen.h" #include "icns.h" #include "../include/refit_call_wrapper.h" EFI_HANDLE* APointerHandles = NULL; EFI_ABSOLUTE_POINTER_PROTOCOL** APointerProtocol = NULL; EFI_GUID APointerGuid = EFI_ABSOLUTE_POINTER_PROTOCOL_GUID; UINTN NumAPointerDevices = 0; EFI_HANDLE* SPointerHandles = NULL; EFI_SIMPLE_POINTER_PROTOCOL** SPointerProtocol = NULL; EFI_GUID SPointerGuid = EFI_SIMPLE_POINTER_PROTOCOL_GUID; UINTN NumSPointerDevices = 0; BOOLEAN PointerAvailable = FALSE; UINTN LastXPos = 0, LastYPos = 0; EG_IMAGE* MouseImage = NULL; EG_IMAGE* Background = NULL; POINTER_STATE State; //////////////////////////////////////////////////////////////////////////////// // Initialize all pointer devices //////////////////////////////////////////////////////////////////////////////// VOID pdInitialize() { pdCleanup(); // just in case if (!(GlobalConfig.EnableMouse || GlobalConfig.EnableTouch)) return; // Get all handles that support absolute pointer protocol (usually touchscreens, but sometimes mice) UINTN NumPointerHandles = 0; EFI_STATUS handlestatus = refit_call5_wrapper(BS->LocateHandleBuffer, ByProtocol, &APointerGuid, NULL, &NumPointerHandles, &APointerHandles); if (!EFI_ERROR(handlestatus)) { APointerProtocol = AllocatePool(sizeof(EFI_ABSOLUTE_POINTER_PROTOCOL*) * NumPointerHandles); UINTN Index; for(Index = 0; Index < NumPointerHandles; Index++) { // Open the protocol on the handle EFI_STATUS status = refit_call6_wrapper(BS->OpenProtocol, APointerHandles[Index], &APointerGuid, (VOID **) &APointerProtocol[NumAPointerDevices], SelfImageHandle, NULL, EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL); if (status == EFI_SUCCESS) { NumAPointerDevices++; } } } else { GlobalConfig.EnableTouch = FALSE; } // Get all handles that support simple pointer protocol (mice) NumPointerHandles = 0; handlestatus = refit_call5_wrapper(BS->LocateHandleBuffer, ByProtocol, &SPointerGuid, NULL, &NumPointerHandles, &SPointerHandles); if(!EFI_ERROR(handlestatus)) { SPointerProtocol = AllocatePool(sizeof(EFI_SIMPLE_POINTER_PROTOCOL*) * NumPointerHandles); UINTN Index; for(Index = 0; Index < NumPointerHandles; Index++) { // Open the protocol on the handle EFI_STATUS status = refit_call6_wrapper(BS->OpenProtocol, SPointerHandles[Index], &SPointerGuid, (VOID **) &SPointerProtocol[NumSPointerDevices], SelfImageHandle, NULL, EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL); if (status == EFI_SUCCESS) { NumSPointerDevices++; } } } else { GlobalConfig.EnableMouse = FALSE; } PointerAvailable = (NumAPointerDevices + NumSPointerDevices > 0); // load mouse icon if (PointerAvailable && GlobalConfig.EnableMouse) { MouseImage = BuiltinIcon(BUILTIN_ICON_MOUSE); } } //////////////////////////////////////////////////////////////////////////////// // Frees allocated memory and closes pointer protocols //////////////////////////////////////////////////////////////////////////////// VOID pdCleanup() { PointerAvailable = FALSE; pdClear(); if(APointerHandles) { UINTN Index; for(Index = 0; Index < NumAPointerDevices; Index++) { refit_call4_wrapper(BS->CloseProtocol, APointerHandles[Index], &APointerGuid, SelfImageHandle, NULL); } FreePool(APointerHandles); APointerHandles = NULL; } if(APointerProtocol) { FreePool(APointerProtocol); APointerProtocol = NULL; } if(SPointerHandles) { UINTN Index; for(Index = 0; Index < NumSPointerDevices; Index++) { refit_call4_wrapper(BS->CloseProtocol, SPointerHandles[Index], &SPointerGuid, SelfImageHandle, NULL); } FreePool(SPointerHandles); SPointerHandles = NULL; } if(SPointerProtocol) { FreePool(SPointerProtocol); SPointerProtocol = NULL; } if(MouseImage) { egFreeImage(MouseImage); Background = NULL; } NumAPointerDevices = 0; NumSPointerDevices = 0; LastXPos = UGAWidth / 2; LastYPos = UGAHeight / 2; State.X = UGAWidth / 2; State.Y = UGAHeight / 2; State.Press = FALSE; State.Holding = FALSE; } //////////////////////////////////////////////////////////////////////////////// // Returns whether or not any pointer devices are available //////////////////////////////////////////////////////////////////////////////// BOOLEAN pdAvailable() { return PointerAvailable; } //////////////////////////////////////////////////////////////////////////////// // Returns the number of pointer devices available //////////////////////////////////////////////////////////////////////////////// UINTN pdCount() { return NumAPointerDevices + NumSPointerDevices; } //////////////////////////////////////////////////////////////////////////////// // Returns a pointer device's WaitForInput event //////////////////////////////////////////////////////////////////////////////// EFI_EVENT pdWaitEvent(UINTN Index) { if(!PointerAvailable || Index >= NumAPointerDevices + NumSPointerDevices) { return NULL; } if(Index >= NumAPointerDevices) { return SPointerProtocol[Index - NumAPointerDevices]->WaitForInput; } return APointerProtocol[Index]->WaitForInput; } //////////////////////////////////////////////////////////////////////////////// // Gets the current state of all pointer devices and assigns State to // the first available device's state //////////////////////////////////////////////////////////////////////////////// EFI_STATUS pdUpdateState() { #if defined(EFI32) && defined(__MAKEWITH_GNUEFI) return EFI_NOT_READY; #else if(!PointerAvailable) { return EFI_NOT_READY; } EFI_STATUS Status = EFI_NOT_READY; EFI_ABSOLUTE_POINTER_STATE APointerState; EFI_SIMPLE_POINTER_STATE SPointerState; BOOLEAN LastHolding = State.Holding; UINTN Index; for(Index = 0; Index < NumAPointerDevices; Index++) { EFI_STATUS PointerStatus = refit_call2_wrapper(APointerProtocol[Index]->GetState, APointerProtocol[Index], &APointerState); // if new state found and we haven't already found a new state if(!EFI_ERROR(PointerStatus) && EFI_ERROR(Status)) { Status = EFI_SUCCESS; #ifdef EFI32 State.X = (UINTN)DivU64x64Remainder(APointerState.CurrentX * UGAWidth, APointerProtocol[Index]->Mode->AbsoluteMaxX, NULL); State.Y = (UINTN)DivU64x64Remainder(APointerState.CurrentY * UGAHeight, APointerProtocol[Index]->Mode->AbsoluteMaxY, NULL); #else State.X = (APointerState.CurrentX * UGAWidth) / APointerProtocol[Index]->Mode->AbsoluteMaxX; State.Y = (APointerState.CurrentY * UGAHeight) / APointerProtocol[Index]->Mode->AbsoluteMaxY; #endif State.Holding = (APointerState.ActiveButtons & EFI_ABSP_TouchActive); } } for(Index = 0; Index < NumSPointerDevices; Index++) { EFI_STATUS PointerStatus = refit_call2_wrapper(SPointerProtocol[Index]->GetState, SPointerProtocol[Index], &SPointerState); // if new state found and we haven't already found a new state if(!EFI_ERROR(PointerStatus) && EFI_ERROR(Status)) { Status = EFI_SUCCESS; INTN TargetX = 0; INTN TargetY = 0; #ifdef EFI32 TargetX = State.X + (INTN)DivS64x64Remainder(SPointerState.RelativeMovementX * GlobalConfig.MouseSpeed, SPointerProtocol[Index]->Mode->ResolutionX, NULL); TargetY = State.Y + (INTN)DivS64x64Remainder(SPointerState.RelativeMovementY * GlobalConfig.MouseSpeed, SPointerProtocol[Index]->Mode->ResolutionY, NULL); #else TargetX = State.X + SPointerState.RelativeMovementX * GlobalConfig.MouseSpeed / SPointerProtocol[Index]->Mode->ResolutionX; TargetY = State.Y + SPointerState.RelativeMovementY * GlobalConfig.MouseSpeed / SPointerProtocol[Index]->Mode->ResolutionY; #endif if(TargetX < 0) { State.X = 0; } else if(TargetX >= UGAWidth) { State.X = UGAWidth - 1; } else { State.X = (UINTN)TargetX; } if(TargetY < 0) { State.Y = 0; } else if(TargetY >= UGAHeight) { State.Y = UGAHeight - 1; } else { State.Y = (UINTN)TargetY; } State.Holding = SPointerState.LeftButton; } } State.Press = (LastHolding && !State.Holding); return Status; #endif } //////////////////////////////////////////////////////////////////////////////// // Returns the current pointer state //////////////////////////////////////////////////////////////////////////////// POINTER_STATE pdGetState() { return State; } //////////////////////////////////////////////////////////////////////////////// // Draw the mouse at the current coordinates //////////////////////////////////////////////////////////////////////////////// VOID pdDraw() { if(Background) { egFreeImage(Background); Background = NULL; } if(MouseImage) { UINTN Width = MouseImage->Width; UINTN Height = MouseImage->Height; if(State.X + Width > UGAWidth) { Width = UGAWidth - State.X; } if(State.Y + Height > UGAHeight) { Height = UGAHeight - State.Y; } Background = egCopyScreenArea(State.X, State.Y, Width, Height); if(Background) { BltImageCompositeBadge(Background, MouseImage, NULL, State.X, State.Y); } } LastXPos = State.X; LastYPos = State.Y; } //////////////////////////////////////////////////////////////////////////////// // Restores the background at the position the mouse was last drawn //////////////////////////////////////////////////////////////////////////////// VOID pdClear() { if (Background) { egDrawImage(Background, LastXPos, LastYPos); egFreeImage(Background); Background = NULL; } } �������������������������������������������������������������������������������refind-0.11.4/refind/main.c�������������������������������������������������������������������������0000664�0001750�0001750�00000317006�13363455754�015677� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * refind/main.c * Main code for the boot menu * * Copyright (c) 2006-2010 Christoph Pfisterer * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * * Neither the name of Christoph Pfisterer nor the names of the * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Modifications copyright (c) 2012-2017 Roderick W. Smith * * Modifications distributed under the terms of the GNU General Public * License (GPL) version 3 (GPLv3), or (at your option) any later version. * */ /* * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "global.h" #include "config.h" #include "screen.h" #include "legacy.h" #include "lib.h" #include "icns.h" #include "menu.h" #include "pointer.h" #include "mok.h" #include "gpt.h" #include "apple.h" #include "mystrings.h" #include "security_policy.h" #include "driver_support.h" #include "../include/Handle.h" #include "../include/refit_call_wrapper.h" #include "../include/version.h" #include "../EfiLib/BdsHelper.h" #include "../EfiLib/legacy.h" #ifdef __MAKEWITH_GNUEFI #ifndef EFI_SECURITY_VIOLATION #define EFI_SECURITY_VIOLATION EFIERR (26) #endif #endif #ifndef EFI_OS_INDICATIONS_BOOT_TO_FW_UI #define EFI_OS_INDICATIONS_BOOT_TO_FW_UI 0x0000000000000001ULL #endif #ifdef __MAKEWITH_TIANO #define LibLocateHandle gBS->LocateHandleBuffer #endif // // constants #define MACOSX_LOADER_DIR L"System\\Library\\CoreServices" #define MACOSX_LOADER_PATH ( MACOSX_LOADER_DIR L"\\boot.efi" ) #if defined (EFIX64) #define SHELL_NAMES L"\\EFI\\tools\\shell.efi,\\EFI\\tools\\shellx64.efi,\\shell.efi,\\shellx64.efi" #define GPTSYNC_NAMES L"\\EFI\\tools\\gptsync.efi,\\EFI\\tools\\gptsync_x64.efi" #define GDISK_NAMES L"\\EFI\\tools\\gdisk.efi,\\EFI\\tools\\gdisk_x64.efi" #define NETBOOT_NAMES L"\\EFI\\tools\\ipxe.efi" #define MEMTEST_NAMES L"memtest86.efi,memtest86_x64.efi,memtest86x64.efi,bootx64.efi" #define FALLBACK_FULLNAME L"EFI\\BOOT\\bootx64.efi" #define FALLBACK_BASENAME L"bootx64.efi" #define EFI_STUB_ARCH 0x8664 EFI_GUID gFreedesktopRootGuid = { 0x4f68bce3, 0xe8cd, 0x4db1, { 0x96, 0xe7, 0xfb, 0xca, 0xf9, 0x84, 0xb7, 0x09 }}; #elif defined (EFI32) #define SHELL_NAMES L"\\EFI\\tools\\shell.efi,\\EFI\\tools\\shellia32.efi,\\shell.efi,\\shellia32.efi" #define GPTSYNC_NAMES L"\\EFI\\tools\\gptsync.efi,\\EFI\\tools\\gptsync_ia32.efi" #define GDISK_NAMES L"\\EFI\\tools\\gdisk.efi,\\EFI\\tools\\gdisk_ia32.efi" #define NETBOOT_NAMES L"\\EFI\\tools\\ipxe.efi" #define MEMTEST_NAMES L"memtest86.efi,memtest86_ia32.efi,memtest86ia32.efi,bootia32.efi" #define FALLBACK_FULLNAME L"EFI\\BOOT\\bootia32.efi" #define FALLBACK_BASENAME L"bootia32.efi" #define EFI_STUB_ARCH 0x014c EFI_GUID gFreedesktopRootGuid = { 0x44479540, 0xf297, 0x41b2, { 0x9a, 0xf7, 0xd1, 0x31, 0xd5, 0xf0, 0x45, 0x8a }}; #elif defined (EFIAARCH64) #define SHELL_NAMES L"\\EFI\\tools\\shell.efi,\\EFI\\tools\\shellaa64.efi,\\shell.efi,\\shellaa64.efi" #define GPTSYNC_NAMES L"\\EFI\\tools\\gptsync.efi,\\EFI\\tools\\gptsync_aa64.efi" #define GDISK_NAMES L"\\EFI\\tools\\gdisk.efi,\\EFI\\tools\\gdisk_aa64.efi" #define NETBOOT_NAMES L"\\EFI\\tools\\ipxe.efi" #define MEMTEST_NAMES L"memtest86.efi,memtest86_aa64.efi,memtest86aa64.efi,bootaa64.efi" #define FALLBACK_FULLNAME L"EFI\\BOOT\\bootaa64.efi" #define FALLBACK_BASENAME L"bootaa64.efi" #define EFI_STUB_ARCH 0xaa64 EFI_GUID gFreedesktopRootGuid = { 0xb921b045, 0x1df0, 0x41c3, { 0xaf, 0x44, 0x4c, 0x6f, 0x28, 0x0d, 0x3f, 0xae }}; #else #define SHELL_NAMES L"\\EFI\\tools\\shell.efi,\\shell.efi" #define GPTSYNC_NAMES L"\\EFI\\tools\\gptsync.efi" #define GDISK_NAMES L"\\EFI\\tools\\gdisk.efi" #define NETBOOT_NAMES L"\\EFI\\tools\\ipxe.efi" #define MEMTEST_NAMES L"memtest86.efi" #define DRIVER_DIRS L"drivers" #define FALLBACK_FULLNAME L"EFI\\BOOT\\boot.efi" /* Not really correct */ #define FALLBACK_BASENAME L"boot.efi" /* Not really correct */ // Below is GUID for ARM32 EFI_GUID gFreedesktopRootGuid = { 0x69dad710, 0x2ce4, 0x4e3c, { 0xb1, 0x6c, 0x21, 0xa1, 0xd4, 0x9a, 0xbe, 0xd3 }}; #endif #define FAT_ARCH 0x0ef1fab9 /* ID for Apple "fat" binary */ #define IPXE_DISCOVER_NAME L"\\efi\\tools\\ipxe_discover.efi" #define IPXE_NAME L"\\efi\\tools\\ipxe.efi" // Patterns that identify Linux kernels. Added to the loader match pattern when the // scan_all_linux_kernels option is set in the configuration file. Causes kernels WITHOUT // a ".efi" extension to be found when scanning for boot loaders. #define LINUX_MATCH_PATTERNS L"vmlinuz*,bzImage*,kernel*" // Maximum length of a text string in certain menus #define MAX_LINE_LENGTH 65 static REFIT_MENU_ENTRY MenuEntryAbout = { L"About rEFInd", TAG_ABOUT, 1, 0, 'A', NULL, NULL, NULL }; static REFIT_MENU_ENTRY MenuEntryReset = { L"Reboot Computer", TAG_REBOOT, 1, 0, 'R', NULL, NULL, NULL }; static REFIT_MENU_ENTRY MenuEntryShutdown = { L"Shut Down Computer", TAG_SHUTDOWN, 1, 0, 'U', NULL, NULL, NULL }; REFIT_MENU_ENTRY MenuEntryReturn = { L"Return to Main Menu", TAG_RETURN, 1, 0, 0, NULL, NULL, NULL }; static REFIT_MENU_ENTRY MenuEntryExit = { L"Exit rEFInd", TAG_EXIT, 1, 0, 0, NULL, NULL, NULL }; static REFIT_MENU_ENTRY MenuEntryManageHidden = { L"Manage Hidden Tags Menu", TAG_HIDDEN, 1, 0, 0, NULL, NULL, NULL }; static REFIT_MENU_ENTRY MenuEntryFirmware = { L"Reboot to Computer Setup Utility", TAG_FIRMWARE, 1, 0, 0, NULL, NULL, NULL }; static REFIT_MENU_ENTRY MenuEntryRotateCsr = { L"Change SIP Policy", TAG_CSR_ROTATE, 1, 0, 0, NULL, NULL, NULL }; REFIT_MENU_SCREEN MainMenu = { L"Main Menu", NULL, 0, NULL, 0, NULL, 0, L"Automatic boot", L"Use arrow keys to move cursor; Enter to boot;", L"Insert, Tab, or F2 for more options; Esc or Backspace to refresh" }; static REFIT_MENU_SCREEN AboutMenu = { L"About", NULL, 0, NULL, 0, NULL, 0, NULL, L"Press Enter to return to main menu", L"" }; REFIT_CONFIG GlobalConfig = { /* TextOnly = */ FALSE, /* ScanAllLinux = */ TRUE, /* DeepLegacyScan = */ FALSE, /* EnableAndLockVMX = */ FALSE, /* FoldLinuxKernels = */ TRUE, /* EnableMouse = */ FALSE, /* EnableTouch = */ FALSE, /* HiddenTags = */ TRUE, /* UseNvram = */ TRUE, /* ShutdownAfterTimeout = */ FALSE, /* RequestedScreenWidth = */ 0, /* RequestedScreenHeight = */ 0, /* BannerBottomEdge = */ 0, /* RequestedTextMode = */ DONT_CHANGE_TEXT_MODE, /* Timeout = */ 20, /* HideUIFlags = */ 0, /* MaxTags = */ 0, /* GraphicsFor = */ GRAPHICS_FOR_OSX, /* LegacyType = */ LEGACY_TYPE_MAC, /* ScanDelay = */ 0, /* ScreensaverTime = */ 0, /* MouseSpeed = */ 4, /* IconSizes = */ { DEFAULT_BIG_ICON_SIZE / 4, DEFAULT_SMALL_ICON_SIZE, DEFAULT_BIG_ICON_SIZE, DEFAULT_MOUSE_SIZE }, /* BannerScale = */ BANNER_NOSCALE, /* *DiscoveredRoot = */ NULL, /* *SelfDevicePath = */ NULL, /* *BannerFileName = */ NULL, /* *ScreenBackground = */ NULL, /* *ConfigFilename = */ CONFIG_FILE_NAME, /* *SelectionSmallFileName = */ NULL, /* *SelectionBigFileName = */ NULL, /* *DefaultSelection = */ NULL, /* *AlsoScan = */ NULL, /* *DontScanVolumes = */ NULL, /* *DontScanDirs = */ NULL, /* *DontScanFiles = */ NULL, /* *DontScanTools = */ NULL, /* *WindowsRecoveryFiles = */ NULL, /* *MacOSRecoveryFiles = */ NULL, /* *DriverDirs = */ NULL, /* *IconsDir = */ NULL, /* *ExtraKernelVersionStrings = */ NULL, /* *SpoofOSXVersion = */ NULL, /* CsrValues = */ NULL, /* ShowTools = */ { TAG_SHELL, TAG_MEMTEST, TAG_GDISK, TAG_APPLE_RECOVERY, TAG_WINDOWS_RECOVERY, TAG_MOK_TOOL, TAG_ABOUT, TAG_HIDDEN, TAG_SHUTDOWN, TAG_REBOOT, TAG_FIRMWARE, TAG_FWUPDATE_TOOL, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }; EFI_GUID GlobalGuid = EFI_GLOBAL_VARIABLE; EFI_GUID RefindGuid = REFIND_GUID_VALUE; GPT_DATA *gPartitions = NULL; // Structure used to hold boot loader filenames and time stamps in // a linked list; used to sort entries within a directory. struct LOADER_LIST { CHAR16 *FileName; EFI_TIME TimeStamp; struct LOADER_LIST *NextEntry; }; // // misc functions // static VOID AboutrEFInd(VOID) { CHAR16 *FirmwareVendor; UINT32 CsrStatus; if (AboutMenu.EntryCount == 0) { AboutMenu.TitleImage = BuiltinIcon(BUILTIN_ICON_FUNC_ABOUT); AddMenuInfoLine(&AboutMenu, PoolPrint(L"rEFInd Version %s", REFIND_VERSION)); AddMenuInfoLine(&AboutMenu, L""); AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2006-2010 Christoph Pfisterer"); AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2012-2017 Roderick W. Smith"); AddMenuInfoLine(&AboutMenu, L"Portions Copyright (c) Intel Corporation and others"); AddMenuInfoLine(&AboutMenu, L"Distributed under the terms of the GNU GPLv3 license"); AddMenuInfoLine(&AboutMenu, L""); AddMenuInfoLine(&AboutMenu, L"Running on:"); AddMenuInfoLine(&AboutMenu, PoolPrint(L" EFI Revision %d.%02d", ST->Hdr.Revision >> 16, ST->Hdr.Revision & ((1 << 16) - 1))); #if defined(EFI32) AddMenuInfoLine(&AboutMenu, PoolPrint(L" Platform: x86 (32 bit); Secure Boot %s", secure_mode() ? L"active" : L"inactive")); #elif defined(EFIX64) AddMenuInfoLine(&AboutMenu, PoolPrint(L" Platform: x86_64 (64 bit); Secure Boot %s", secure_mode() ? L"active" : L"inactive")); #elif defined(EFIAARCH64) AddMenuInfoLine(&AboutMenu, PoolPrint(L" Platform: ARM (64 bit); Secure Boot %s", secure_mode() ? L"active" : L"inactive")); #else AddMenuInfoLine(&AboutMenu, L" Platform: unknown"); #endif if (GetCsrStatus(&CsrStatus) == EFI_SUCCESS) { RecordgCsrStatus(CsrStatus, FALSE); AddMenuInfoLine(&AboutMenu, gCsrStatus); } FirmwareVendor = StrDuplicate(ST->FirmwareVendor); LimitStringLength(FirmwareVendor, MAX_LINE_LENGTH); // More than ~65 causes empty info page on 800x600 display AddMenuInfoLine(&AboutMenu, PoolPrint(L" Firmware: %s %d.%02d", FirmwareVendor, ST->FirmwareRevision >> 16, ST->FirmwareRevision & ((1 << 16) - 1))); AddMenuInfoLine(&AboutMenu, PoolPrint(L" Screen Output: %s", egScreenDescription())); AddMenuInfoLine(&AboutMenu, L""); #if defined(__MAKEWITH_GNUEFI) AddMenuInfoLine(&AboutMenu, L"Built with GNU-EFI"); #else AddMenuInfoLine(&AboutMenu, L"Built with TianoCore EDK2"); #endif AddMenuInfoLine(&AboutMenu, L""); AddMenuInfoLine(&AboutMenu, L"For more information, see the rEFInd Web site:"); AddMenuInfoLine(&AboutMenu, L"http://www.rodsbooks.com/refind/"); AddMenuEntry(&AboutMenu, &MenuEntryReturn); } RunMenu(&AboutMenu, NULL); } /* VOID AboutrEFInd() */ static VOID WarnSecureBootError(CHAR16 *Name, BOOLEAN Verbose) { if (Name == NULL) Name = L"the loader"; refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_ERROR); Print(L"Secure Boot validation failure loading %s!\n", Name); refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BASIC); if (Verbose && secure_mode()) { Print(L"\nThis computer is configured with Secure Boot active, but\n%s has failed validation.\n", Name); Print(L"\nYou can:\n * Launch another boot loader\n"); Print(L" * Disable Secure Boot in your firmware\n"); Print(L" * Sign %s with a machine owner key (MOK)\n", Name); Print(L" * Use a MOK utility (often present on the second row) to add a MOK with which\n"); Print(L" %s has already been signed.\n", Name); Print(L" * Use a MOK utility to register %s (\"enroll its hash\") without\n", Name); Print(L" signing it.\n"); Print(L"\nSee http://www.rodsbooks.com/refind/secureboot.html for more information\n"); PauseForKey(); } // if } // VOID WarnSecureBootError() // Returns TRUE if this file is a valid EFI loader file, and is proper ARCH static BOOLEAN IsValidLoader(EFI_FILE *RootDir, CHAR16 *FileName) { BOOLEAN IsValid = TRUE; #if defined (EFIX64) | defined (EFI32) | defined (EFIAARCH64) EFI_STATUS Status; EFI_FILE_HANDLE FileHandle; CHAR8 Header[512]; UINTN Size = sizeof(Header); if ((RootDir == NULL) || (FileName == NULL)) { // Assume valid here, because Macs produce NULL RootDir (& maybe FileName) // when launching from a Firewire drive. This should be handled better, but // fix would have to be in StartEFIImage() and/or in FindVolumeAndFilename(). return TRUE; } // if Status = refit_call5_wrapper(RootDir->Open, RootDir, &FileHandle, FileName, EFI_FILE_MODE_READ, 0); if (EFI_ERROR(Status)) return FALSE; Status = refit_call3_wrapper(FileHandle->Read, FileHandle, &Size, Header); refit_call1_wrapper(FileHandle->Close, FileHandle); IsValid = !EFI_ERROR(Status) && Size == sizeof(Header) && ((Header[0] == 'M' && Header[1] == 'Z' && (Size = *(UINT32 *)&Header[0x3c]) < 0x180 && Header[Size] == 'P' && Header[Size+1] == 'E' && Header[Size+2] == 0 && Header[Size+3] == 0 && *(UINT16 *)&Header[Size+4] == EFI_STUB_ARCH) || (*(UINT32 *)&Header == FAT_ARCH)); #endif return IsValid; } // BOOLEAN IsValidLoader() // Launch an EFI binary. EFI_STATUS StartEFIImage(IN REFIT_VOLUME *Volume, IN CHAR16 *Filename, IN CHAR16 *LoadOptions, IN CHAR16 *ImageTitle, IN CHAR8 OSType, IN BOOLEAN Verbose, IN BOOLEAN IsDriver) { EFI_STATUS Status, ReturnStatus; EFI_HANDLE ChildImageHandle, ChildImageHandle2; EFI_DEVICE_PATH *DevicePath; EFI_LOADED_IMAGE *ChildLoadedImage = NULL; CHAR16 ErrorInfo[256]; CHAR16 *FullLoadOptions = NULL; CHAR16 *Temp; // set load options if (LoadOptions != NULL) { FullLoadOptions = StrDuplicate(LoadOptions); if (OSType == 'M') { MergeStrings(&FullLoadOptions, L" ", 0); // NOTE: That last space is also added by the EFI shell and seems to be significant // when passing options to Apple's boot.efi... } // if } // if (LoadOptions != NULL) if (Verbose) Print(L"Starting %s\nUsing load options '%s'\n", ImageTitle, FullLoadOptions ? FullLoadOptions : L""); // load the image into memory ReturnStatus = Status = EFI_NOT_FOUND; // in case the list is empty // Some EFIs crash if attempting to load driver for invalid architecture, so // protect for this condition; but sometimes Volume comes back NULL, so provide // an exception. (TODO: Handle this special condition better.) if (IsValidLoader(Volume->RootDir, Filename)) { if (Filename) { Temp = PoolPrint(L"\\%s %s", Filename, FullLoadOptions ? FullLoadOptions : L""); if (Temp != NULL) { MyFreePool(FullLoadOptions); FullLoadOptions = Temp; } } // if (Filename) DevicePath = FileDevicePath(Volume->DeviceHandle, Filename); // NOTE: Below commented-out line could be more efficient if file were read ahead of // time and passed as a pre-loaded image to LoadImage(), but it doesn't work on my // 32-bit Mac Mini or my 64-bit Intel box when launching a Linux kernel; the // kernel returns a "Failed to handle fs_proto" error message. // TODO: Track down the cause of this error and fix it, if possible. // ReturnStatus = Status = refit_call6_wrapper(BS->LoadImage, FALSE, SelfImageHandle, DevicePath, // ImageData, ImageSize, &ChildImageHandle); ReturnStatus = Status = refit_call6_wrapper(BS->LoadImage, FALSE, SelfImageHandle, DevicePath, NULL, 0, &ChildImageHandle); if (secure_mode() && ShimLoaded()) { // Load ourself into memory. This is a trick to work around a bug in Shim 0.8, // which ties itself into the BS->LoadImage() and BS->StartImage() functions and // then unregisters itself from the EFI system table when its replacement // StartImage() function is called *IF* the previous LoadImage() was for the same // program. The result is that rEFInd can validate only the first program it // launches (often a filesystem driver). Loading a second program (rEFInd itself, // here, to keep it smaller than a kernel) works around this problem. See the // replacements.c file in Shim, and especially its start_image() function, for // the source of the problem. // NOTE: This doesn't check the return status or handle errors. It could // conceivably do weird things if, say, rEFInd were on a USB drive that the // user pulls before launching a program. refit_call6_wrapper(BS->LoadImage, FALSE, SelfImageHandle, GlobalConfig.SelfDevicePath, NULL, 0, &ChildImageHandle2); } } else { Print(L"Invalid loader file!\n"); ReturnStatus = EFI_LOAD_ERROR; } if ((Status == EFI_ACCESS_DENIED) || (Status == EFI_SECURITY_VIOLATION)) { WarnSecureBootError(ImageTitle, Verbose); goto bailout; } SPrint(ErrorInfo, 255, L"while loading %s", ImageTitle); if (CheckError(Status, ErrorInfo)) { goto bailout; } ReturnStatus = Status = refit_call3_wrapper(BS->HandleProtocol, ChildImageHandle, &LoadedImageProtocol, (VOID **) &ChildLoadedImage); if (CheckError(Status, L"while getting a LoadedImageProtocol handle")) { goto bailout_unload; } ChildLoadedImage->LoadOptions = (VOID *)FullLoadOptions; ChildLoadedImage->LoadOptionsSize = FullLoadOptions ? ((UINT32)StrLen(FullLoadOptions) + 1) * sizeof(CHAR16) : 0; // turn control over to the image // TODO: (optionally) re-enable the EFI watchdog timer! // close open file handles UninitRefitLib(); ReturnStatus = Status = refit_call3_wrapper(BS->StartImage, ChildImageHandle, NULL, NULL); // control returns here when the child image calls Exit() SPrint(ErrorInfo, 255, L"returned from %s", ImageTitle); CheckError(Status, ErrorInfo); if (IsDriver) { // Below should have no effect on most systems, but works // around bug with some EFIs that prevents filesystem drivers // from binding to partitions. ConnectFilesystemDriver(ChildImageHandle); } // re-open file handles ReinitRefitLib(); bailout_unload: // unload the image, we don't care if it works or not... if (!IsDriver) Status = refit_call1_wrapper(BS->UnloadImage, ChildImageHandle); bailout: MyFreePool(FullLoadOptions); return ReturnStatus; } /* EFI_STATUS StartEFIImage() */ // From gummiboot: Reboot the computer into its built-in user interface static EFI_STATUS RebootIntoFirmware(VOID) { CHAR8 *b; UINTN size; UINT64 osind; EFI_STATUS err; osind = EFI_OS_INDICATIONS_BOOT_TO_FW_UI; err = EfivarGetRaw(&GlobalGuid, L"OsIndications", &b, &size); if (err == EFI_SUCCESS) osind |= (UINT64)*b; MyFreePool(b); err = EfivarSetRaw(&GlobalGuid, L"OsIndications", (CHAR8 *)&osind, sizeof(UINT64), TRUE); if (err != EFI_SUCCESS) return err; refit_call4_wrapper(RT->ResetSystem, EfiResetCold, EFI_SUCCESS, 0, NULL); Print(L"Error calling ResetSystem: %r", err); PauseForKey(); return err; } // Record the value of the loader's name/description in rEFInd's "PreviousBoot" EFI variable, // if it's different from what's already stored there. VOID StoreLoaderName(IN CHAR16 *Name) { EFI_STATUS Status; CHAR16 *OldName = NULL; UINTN Length; if (Name) { Status = EfivarGetRaw(&RefindGuid, L"PreviousBoot", (CHAR8**) &OldName, &Length); if ((Status != EFI_SUCCESS) || (StrCmp(OldName, Name) != 0)) { EfivarSetRaw(&RefindGuid, L"PreviousBoot", (CHAR8*) Name, StrLen(Name) * 2 + 2, TRUE); } // if MyFreePool(OldName); } // if } // VOID StoreLoaderName() // // EFI OS loader functions // // See http://www.thomas-krenn.com/en/wiki/Activating_the_Intel_VT_Virtualization_Feature // for information on Intel VMX features static VOID DoEnableAndLockVMX(VOID) { #if defined (EFIX64) | defined (EFI32) UINT32 msr = 0x3a; UINT32 low_bits = 0, high_bits = 0; // is VMX active ? __asm__ volatile ("rdmsr" : "=a" (low_bits), "=d" (high_bits) : "c" (msr)); // enable and lock vmx if not locked if ((low_bits & 1) == 0) { high_bits = 0; low_bits = 0x05; msr = 0x3a; __asm__ volatile ("wrmsr" : : "c" (msr), "a" (low_bits), "d" (high_bits)); } #endif } // VOID DoEnableAndLockVMX() static VOID StartLoader(LOADER_ENTRY *Entry, CHAR16 *SelectionName) { if (GlobalConfig.EnableAndLockVMX) { DoEnableAndLockVMX(); } BeginExternalScreen(Entry->UseGraphicsMode, L"Booting OS"); StoreLoaderName(SelectionName); StartEFIImage(Entry->Volume, Entry->LoaderPath, Entry->LoadOptions, Basename(Entry->LoaderPath), Entry->OSType, !Entry->UseGraphicsMode, FALSE); FinishExternalScreen(); } // Locate an initrd or initramfs file that matches the kernel specified by LoaderPath. // The matching file has a name that begins with "init" and includes the same version // number string as is found in LoaderPath -- but not a longer version number string. // For instance, if LoaderPath is \EFI\kernels\bzImage-3.3.0.efi, and if \EFI\kernels // has a file called initramfs-3.3.0.img, this function will return the string // '\EFI\kernels\initramfs-3.3.0.img'. If the directory ALSO contains the file // initramfs-3.3.0-rc7.img or initramfs-13.3.0.img, those files will NOT match. // If more than one initrd file matches the extracted version string, the one // that matches more characters AFTER (actually, from the start of) the version // string is used. // If more than one initrd file matches the extracted version string AND they match // the same amount of characters, the initrd file with the shortest file name is used. // If no matching init file can be found, returns NULL. static CHAR16 * FindInitrd(IN CHAR16 *LoaderPath, IN REFIT_VOLUME *Volume) { CHAR16 *InitrdName = NULL, *FileName, *KernelVersion, *InitrdVersion, *Path; CHAR16 *KernelPostNum, *InitrdPostNum; UINTN MaxSharedChars, SharedChars; STRING_LIST *InitrdNames = NULL, *FinalInitrdName = NULL, *CurrentInitrdName = NULL, *MaxSharedInitrd; REFIT_DIR_ITER DirIter; EFI_FILE_INFO *DirEntry; FileName = Basename(LoaderPath); KernelVersion = FindNumbers(FileName); Path = FindPath(LoaderPath); // Add trailing backslash for root directory; necessary on some systems, but must // NOT be added to all directories, since on other systems, a trailing backslash on // anything but the root directory causes them to flake out! if (StrLen(Path) == 0) { MergeStrings(&Path, L"\\", 0); } // if DirIterOpen(Volume->RootDir, Path, &DirIter); // Now add a trailing backslash if it was NOT added earlier, for consistency in // building the InitrdName later.... if ((StrLen(Path) > 0) && (Path[StrLen(Path) - 1] != L'\\')) MergeStrings(&Path, L"\\", 0); while (DirIterNext(&DirIter, 2, L"init*", &DirEntry)) { InitrdVersion = FindNumbers(DirEntry->FileName); if (((KernelVersion != NULL) && (MyStriCmp(InitrdVersion, KernelVersion))) || ((KernelVersion == NULL) && (InitrdVersion == NULL))) { CurrentInitrdName = AllocateZeroPool(sizeof(STRING_LIST)); if (InitrdNames == NULL) InitrdNames = FinalInitrdName = CurrentInitrdName; if (CurrentInitrdName) { CurrentInitrdName->Value = PoolPrint(L"%s%s", Path, DirEntry->FileName); if (CurrentInitrdName != FinalInitrdName) { FinalInitrdName->Next = CurrentInitrdName; FinalInitrdName = CurrentInitrdName; } // if } // if } // if } // while if (InitrdNames) { if (InitrdNames->Next == NULL) { InitrdName = StrDuplicate(InitrdNames -> Value); } else { MaxSharedInitrd = CurrentInitrdName = InitrdNames; MaxSharedChars = 0; while (CurrentInitrdName != NULL) { KernelPostNum = MyStrStr(LoaderPath, KernelVersion); InitrdPostNum = MyStrStr(CurrentInitrdName->Value, KernelVersion); SharedChars = NumCharsInCommon(KernelPostNum, InitrdPostNum); if (SharedChars > MaxSharedChars || (SharedChars == MaxSharedChars && StrLen(CurrentInitrdName->Value) < StrLen(MaxSharedInitrd->Value))) { MaxSharedChars = SharedChars; MaxSharedInitrd = CurrentInitrdName; } // if // TODO: Compute number of shared characters & compare with max. CurrentInitrdName = CurrentInitrdName->Next; } if (MaxSharedInitrd) InitrdName = StrDuplicate(MaxSharedInitrd->Value); } // if/else } // if DeleteStringList(InitrdNames); // Note: Don't FreePool(FileName), since Basename returns a pointer WITHIN the string it's passed. MyFreePool(KernelVersion); MyFreePool(Path); return (InitrdName); } // static CHAR16 * FindInitrd() LOADER_ENTRY * AddPreparedLoaderEntry(LOADER_ENTRY *Entry) { AddMenuEntry(&MainMenu, (REFIT_MENU_ENTRY *)Entry); return(Entry); } // LOADER_ENTRY * AddPreparedLoaderEntry() // Creates a copy of a menu screen. // Returns a pointer to the copy of the menu screen. static REFIT_MENU_SCREEN* CopyMenuScreen(REFIT_MENU_SCREEN *Entry) { REFIT_MENU_SCREEN *NewEntry; UINTN i; NewEntry = AllocateZeroPool(sizeof(REFIT_MENU_SCREEN)); if ((Entry != NULL) && (NewEntry != NULL)) { CopyMem(NewEntry, Entry, sizeof(REFIT_MENU_SCREEN)); NewEntry->Title = (Entry->Title) ? StrDuplicate(Entry->Title) : NULL; NewEntry->TimeoutText = (Entry->TimeoutText) ? StrDuplicate(Entry->TimeoutText) : NULL; if (Entry->TitleImage != NULL) { NewEntry->TitleImage = AllocatePool(sizeof(EG_IMAGE)); if (NewEntry->TitleImage != NULL) CopyMem(NewEntry->TitleImage, Entry->TitleImage, sizeof(EG_IMAGE)); } // if NewEntry->InfoLines = (CHAR16**) AllocateZeroPool(Entry->InfoLineCount * (sizeof(CHAR16*))); for (i = 0; i < Entry->InfoLineCount && NewEntry->InfoLines; i++) { NewEntry->InfoLines[i] = (Entry->InfoLines[i]) ? StrDuplicate(Entry->InfoLines[i]) : NULL; } // for NewEntry->Entries = (REFIT_MENU_ENTRY**) AllocateZeroPool(Entry->EntryCount * (sizeof (REFIT_MENU_ENTRY*))); for (i = 0; i < Entry->EntryCount && NewEntry->Entries; i++) { AddMenuEntry(NewEntry, Entry->Entries[i]); } // for NewEntry->Hint1 = (Entry->Hint1) ? StrDuplicate(Entry->Hint1) : NULL; NewEntry->Hint2 = (Entry->Hint2) ? StrDuplicate(Entry->Hint2) : NULL; } // if return (NewEntry); } // static REFIT_MENU_SCREEN* CopyMenuScreen() // Creates a copy of a menu entry. Intended to enable moving a stack-based // menu entry (such as the ones for the "reboot" and "exit" functions) to // to the heap. This enables easier deletion of the whole set of menu // entries when re-scanning. // Returns a pointer to the copy of the menu entry. static REFIT_MENU_ENTRY* CopyMenuEntry(REFIT_MENU_ENTRY *Entry) { REFIT_MENU_ENTRY *NewEntry; NewEntry = AllocateZeroPool(sizeof(REFIT_MENU_ENTRY)); if ((Entry != NULL) && (NewEntry != NULL)) { CopyMem(NewEntry, Entry, sizeof(REFIT_MENU_ENTRY)); NewEntry->Title = (Entry->Title) ? StrDuplicate(Entry->Title) : NULL; if (Entry->BadgeImage != NULL) { NewEntry->BadgeImage = AllocatePool(sizeof(EG_IMAGE)); if (NewEntry->BadgeImage != NULL) CopyMem(NewEntry->BadgeImage, Entry->BadgeImage, sizeof(EG_IMAGE)); } if (Entry->Image != NULL) { NewEntry->Image = AllocatePool(sizeof(EG_IMAGE)); if (NewEntry->Image != NULL) CopyMem(NewEntry->Image, Entry->Image, sizeof(EG_IMAGE)); } if (Entry->SubScreen != NULL) { NewEntry->SubScreen = CopyMenuScreen(Entry->SubScreen); } } // if return (NewEntry); } // REFIT_MENU_ENTRY* CopyMenuEntry() // Creates a new LOADER_ENTRY data structure and populates it with // default values from the specified Entry, or NULL values if Entry // is unspecified (NULL). // Returns a pointer to the new data structure, or NULL if it // couldn't be allocated LOADER_ENTRY *InitializeLoaderEntry(IN LOADER_ENTRY *Entry) { LOADER_ENTRY *NewEntry = NULL; NewEntry = AllocateZeroPool(sizeof(LOADER_ENTRY)); if (NewEntry != NULL) { NewEntry->me.Title = NULL; NewEntry->me.Tag = TAG_LOADER; NewEntry->Enabled = TRUE; NewEntry->UseGraphicsMode = FALSE; NewEntry->OSType = 0; if (Entry != NULL) { NewEntry->LoaderPath = (Entry->LoaderPath) ? StrDuplicate(Entry->LoaderPath) : NULL; NewEntry->Volume = Entry->Volume; NewEntry->UseGraphicsMode = Entry->UseGraphicsMode; NewEntry->LoadOptions = (Entry->LoadOptions) ? StrDuplicate(Entry->LoadOptions) : NULL; NewEntry->InitrdPath = (Entry->InitrdPath) ? StrDuplicate(Entry->InitrdPath) : NULL; } } // if return (NewEntry); } // LOADER_ENTRY *InitializeLoaderEntry() // Adds InitrdPath to Options, but only if Options doesn't already include an // initrd= line. Done to enable overriding the default initrd selection in a // refind_linux.conf file's options list. // Returns a pointer to a new string. The calling function is responsible for // freeing its memory. static CHAR16 *AddInitrdToOptions(CHAR16 *Options, CHAR16 *InitrdPath) { CHAR16 *NewOptions = NULL; if (Options != NULL) NewOptions = StrDuplicate(Options); if ((InitrdPath != NULL) && !StriSubCmp(L"initrd=", Options)) { MergeStrings(&NewOptions, L"initrd=", L' '); MergeStrings(&NewOptions, InitrdPath, 0); } return NewOptions; } // CHAR16 *AddInitrdToOptions() // Prepare a REFIT_MENU_SCREEN data structure for a subscreen entry. This sets up // the default entry that launches the boot loader using the same options as the // main Entry does. Subsequent options can be added by the calling function. // If a subscreen already exists in the Entry that's passed to this function, // it's left unchanged and a pointer to it is returned. // Returns a pointer to the new subscreen data structure, or NULL if there // were problems allocating memory. REFIT_MENU_SCREEN *InitializeSubScreen(IN LOADER_ENTRY *Entry) { CHAR16 *FileName, *MainOptions = NULL; REFIT_MENU_SCREEN *SubScreen = NULL; LOADER_ENTRY *SubEntry; FileName = Basename(Entry->LoaderPath); if (Entry->me.SubScreen == NULL) { // No subscreen yet; initialize default entry.... SubScreen = AllocateZeroPool(sizeof(REFIT_MENU_SCREEN)); if (SubScreen != NULL) { SubScreen->Title = AllocateZeroPool(sizeof(CHAR16) * 256); SPrint(SubScreen->Title, 255, L"Boot Options for %s on %s", (Entry->Title != NULL) ? Entry->Title : FileName, Entry->Volume->VolName); SubScreen->TitleImage = Entry->me.Image; // default entry SubEntry = InitializeLoaderEntry(Entry); if (SubEntry != NULL) { SubEntry->me.Title = StrDuplicate(L"Boot using default options"); MainOptions = SubEntry->LoadOptions; SubEntry->LoadOptions = AddInitrdToOptions(MainOptions, SubEntry->InitrdPath); MyFreePool(MainOptions); AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); } // if (SubEntry != NULL) SubScreen->Hint1 = StrDuplicate(SUBSCREEN_HINT1); if (GlobalConfig.HideUIFlags & HIDEUI_FLAG_EDITOR) { SubScreen->Hint2 = StrDuplicate(SUBSCREEN_HINT2_NO_EDITOR); } else { SubScreen->Hint2 = StrDuplicate(SUBSCREEN_HINT2); } // if/else } // if (SubScreen != NULL) } else { // existing subscreen; less initialization, and just add new entry later.... SubScreen = Entry->me.SubScreen; } // if/else return SubScreen; } // REFIT_MENU_SCREEN *InitializeSubScreen() VOID GenerateSubScreen(LOADER_ENTRY *Entry, IN REFIT_VOLUME *Volume, IN BOOLEAN GenerateReturn) { REFIT_MENU_SCREEN *SubScreen; LOADER_ENTRY *SubEntry; CHAR16 *InitrdName, *KernelVersion = NULL; CHAR16 DiagsFileName[256]; REFIT_FILE *File; UINTN TokenCount; CHAR16 **TokenList; // create the submenu if (StrLen(Entry->Title) == 0) { MyFreePool(Entry->Title); Entry->Title = NULL; } SubScreen = InitializeSubScreen(Entry); // loader-specific submenu entries if (Entry->OSType == 'M') { // entries for macOS #if defined(EFIX64) SubEntry = InitializeLoaderEntry(Entry); if (SubEntry != NULL) { SubEntry->me.Title = L"Boot macOS with a 64-bit kernel"; SubEntry->LoadOptions = L"arch=x86_64"; SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_OSX; AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); } // if SubEntry = InitializeLoaderEntry(Entry); if (SubEntry != NULL) { SubEntry->me.Title = L"Boot macOS with a 32-bit kernel"; SubEntry->LoadOptions = L"arch=i386"; SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_OSX; AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); } // if #endif if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_SINGLEUSER)) { SubEntry = InitializeLoaderEntry(Entry); if (SubEntry != NULL) { SubEntry->me.Title = L"Boot macOS in verbose mode"; SubEntry->UseGraphicsMode = FALSE; SubEntry->LoadOptions = L"-v"; AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); } // if #if defined(EFIX64) SubEntry = InitializeLoaderEntry(Entry); if (SubEntry != NULL) { SubEntry->me.Title = L"Boot macOS in verbose mode (64-bit)"; SubEntry->UseGraphicsMode = FALSE; SubEntry->LoadOptions = L"-v arch=x86_64"; AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); } SubEntry = InitializeLoaderEntry(Entry); if (SubEntry != NULL) { SubEntry->me.Title = L"Boot macOS in verbose mode (32-bit)"; SubEntry->UseGraphicsMode = FALSE; SubEntry->LoadOptions = L"-v arch=i386"; AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); } #endif SubEntry = InitializeLoaderEntry(Entry); if (SubEntry != NULL) { SubEntry->me.Title = L"Boot macOS in single user mode"; SubEntry->UseGraphicsMode = FALSE; SubEntry->LoadOptions = L"-v -s"; AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); } // if } // single-user mode allowed if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_SAFEMODE)) { SubEntry = InitializeLoaderEntry(Entry); if (SubEntry != NULL) { SubEntry->me.Title = L"Boot macOS in safe mode"; SubEntry->UseGraphicsMode = FALSE; SubEntry->LoadOptions = L"-v -x"; AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); } // if } // safe mode allowed // check for Apple hardware diagnostics StrCpy(DiagsFileName, L"System\\Library\\CoreServices\\.diagnostics\\diags.efi"); if (FileExists(Volume->RootDir, DiagsFileName) && !(GlobalConfig.HideUIFlags & HIDEUI_FLAG_HWTEST)) { SubEntry = InitializeLoaderEntry(Entry); if (SubEntry != NULL) { SubEntry->me.Title = L"Run Apple Hardware Test"; MyFreePool(SubEntry->LoaderPath); SubEntry->LoaderPath = StrDuplicate(DiagsFileName); SubEntry->Volume = Volume; SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_OSX; AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); } // if } // if diagnostics entry found } else if (Entry->OSType == 'L') { // entries for Linux kernels with EFI stub loaders File = ReadLinuxOptionsFile(Entry->LoaderPath, Volume); if (File != NULL) { InitrdName = FindInitrd(Entry->LoaderPath, Volume); TokenCount = ReadTokenLine(File, &TokenList); KernelVersion = FindNumbers(Entry->LoaderPath); ReplaceSubstring(&(TokenList[1]), KERNEL_VERSION, KernelVersion); // first entry requires special processing, since it was initially set // up with a default title but correct options by InitializeSubScreen(), // earlier.... if ((TokenCount > 1) && (SubScreen->Entries != NULL) && (SubScreen->Entries[0] != NULL)) { MyFreePool(SubScreen->Entries[0]->Title); SubScreen->Entries[0]->Title = TokenList[0] ? StrDuplicate(TokenList[0]) : StrDuplicate(L"Boot Linux"); } // if FreeTokenLine(&TokenList, &TokenCount); while ((TokenCount = ReadTokenLine(File, &TokenList)) > 1) { ReplaceSubstring(&(TokenList[1]), KERNEL_VERSION, KernelVersion); SubEntry = InitializeLoaderEntry(Entry); SubEntry->me.Title = TokenList[0] ? StrDuplicate(TokenList[0]) : StrDuplicate(L"Boot Linux"); MyFreePool(SubEntry->LoadOptions); SubEntry->LoadOptions = AddInitrdToOptions(TokenList[1], InitrdName); FreeTokenLine(&TokenList, &TokenCount); SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_LINUX; AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); } // while MyFreePool(KernelVersion); MyFreePool(InitrdName); MyFreePool(File); } // if } else if (Entry->OSType == 'E') { // entries for ELILO SubEntry = InitializeLoaderEntry(Entry); if (SubEntry != NULL) { SubEntry->me.Title = L"Run ELILO in interactive mode"; SubEntry->LoadOptions = L"-p"; SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_ELILO; AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); } SubEntry = InitializeLoaderEntry(Entry); if (SubEntry != NULL) { SubEntry->me.Title = L"Boot Linux for a 17\" iMac or a 15\" MacBook Pro (*)"; SubEntry->LoadOptions = L"-d 0 i17"; SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_ELILO; AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); } SubEntry = InitializeLoaderEntry(Entry); if (SubEntry != NULL) { SubEntry->me.Title = L"Boot Linux for a 20\" iMac (*)"; SubEntry->LoadOptions = L"-d 0 i20"; SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_ELILO; AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); } SubEntry = InitializeLoaderEntry(Entry); if (SubEntry != NULL) { SubEntry->me.Title = L"Boot Linux for a Mac Mini (*)"; SubEntry->LoadOptions = L"-d 0 mini"; SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_ELILO; AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); } AddMenuInfoLine(SubScreen, L"NOTE: This is an example. Entries"); AddMenuInfoLine(SubScreen, L"marked with (*) may not work."); } else if (Entry->OSType == 'X') { // entries for xom.efi // by default, skip the built-in selection and boot from hard disk only Entry->LoadOptions = L"-s -h"; SubEntry = InitializeLoaderEntry(Entry); if (SubEntry != NULL) { SubEntry->me.Title = L"Boot Windows from Hard Disk"; SubEntry->LoadOptions = L"-s -h"; SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_WINDOWS; AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); } SubEntry = InitializeLoaderEntry(Entry); if (SubEntry != NULL) { SubEntry->me.Title = L"Boot Windows from CD-ROM"; SubEntry->LoadOptions = L"-s -c"; SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_WINDOWS; AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); } SubEntry = InitializeLoaderEntry(Entry); if (SubEntry != NULL) { SubEntry->me.Title = L"Run XOM in text mode"; SubEntry->LoadOptions = L"-v"; SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_WINDOWS; AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); } } // entries for xom.efi if (GenerateReturn) AddMenuEntry(SubScreen, &MenuEntryReturn); Entry->me.SubScreen = SubScreen; } // VOID GenerateSubScreen() // Returns options for a Linux kernel. Reads them from an options file in the // kernel's directory; and if present, adds an initrd= option for an initial // RAM disk file with the same version number as the kernel file. static CHAR16 * GetMainLinuxOptions(IN CHAR16 * LoaderPath, IN REFIT_VOLUME *Volume) { CHAR16 *Options = NULL, *InitrdName, *FullOptions = NULL, *KernelVersion; Options = GetFirstOptionsFromFile(LoaderPath, Volume); InitrdName = FindInitrd(LoaderPath, Volume); KernelVersion = FindNumbers(InitrdName); ReplaceSubstring(&Options, KERNEL_VERSION, KernelVersion); FullOptions = AddInitrdToOptions(Options, InitrdName); MyFreePool(Options); MyFreePool(InitrdName); MyFreePool(KernelVersion); return (FullOptions); } // static CHAR16 * GetMainLinuxOptions() // Read the specified file and add values of "ID", "NAME", or "DISTRIB_ID" tokens to // OSIconName list. Intended for adding Linux distribution clues gleaned from // /etc/lsb-release and /etc/os-release files. static VOID ParseReleaseFile(CHAR16 **OSIconName, REFIT_VOLUME *Volume, CHAR16 *FileName) { UINTN FileSize = 0; REFIT_FILE File; CHAR16 **TokenList; UINTN TokenCount = 0; if ((Volume == NULL) || (FileName == NULL) || (OSIconName == NULL) || (*OSIconName == NULL)) return; if (FileExists(Volume->RootDir, FileName) && (ReadFile(Volume->RootDir, FileName, &File, &FileSize) == EFI_SUCCESS)) { do { TokenCount = ReadTokenLine(&File, &TokenList); if ((TokenCount > 1) && (MyStriCmp(TokenList[0], L"ID") || MyStriCmp(TokenList[0], L"NAME") || MyStriCmp(TokenList[0], L"DISTRIB_ID"))) { MergeWords(OSIconName, TokenList[1], L','); } // if FreeTokenLine(&TokenList, &TokenCount); } while (TokenCount > 0); MyFreePool(File.Buffer); } // if } // VOID ParseReleaseFile() // Try to guess the name of the Linux distribution & add that name to // OSIconName list. static VOID GuessLinuxDistribution(CHAR16 **OSIconName, REFIT_VOLUME *Volume, CHAR16 *LoaderPath) { // If on Linux root fs, /etc/os-release or /etc/lsb-release file probably has clues.... ParseReleaseFile(OSIconName, Volume, L"etc\\lsb-release"); ParseReleaseFile(OSIconName, Volume, L"etc\\os-release"); // Search for clues in the kernel's filename.... if (StriSubCmp(L".fc", LoaderPath)) MergeStrings(OSIconName, L"fedora", L','); if (StriSubCmp(L".el", LoaderPath)) MergeStrings(OSIconName, L"redhat", L','); } // VOID GuessLinuxDistribution() // Sets a few defaults for a loader entry -- mainly the icon, but also the OS type // code and shortcut letter. For Linux EFI stub loaders, also sets kernel options // that will (with luck) work fairly automatically. VOID SetLoaderDefaults(LOADER_ENTRY *Entry, CHAR16 *LoaderPath, REFIT_VOLUME *Volume) { CHAR16 *NameClues, *PathOnly, *NoExtension, *OSIconName = NULL, *Temp; CHAR16 ShortcutLetter = 0; NameClues = Basename(LoaderPath); PathOnly = FindPath(LoaderPath); NoExtension = StripEfiExtension(NameClues); if (Volume->DiskKind == DISK_KIND_NET) { MergeStrings(&NameClues, Entry->me.Title, L' '); } else { // locate a custom icon for the loader // Anything found here takes precedence over the "hints" in the OSIconName variable if (!Entry->me.Image) { Entry->me.Image = egLoadIconAnyType(Volume->RootDir, PathOnly, NoExtension, GlobalConfig.IconSizes[ICON_SIZE_BIG]); } if (!Entry->me.Image) { Entry->me.Image = egCopyImage(Volume->VolIconImage); } // Begin creating icon "hints" by using last part of directory path leading // to the loader Temp = FindLastDirName(LoaderPath); MergeStrings(&OSIconName, Temp, L','); MyFreePool(Temp); Temp = NULL; if (OSIconName != NULL) { ShortcutLetter = OSIconName[0]; } // Add every "word" in the volume label, delimited by spaces, dashes (-), or // underscores (_), to the list of hints to be used in searching for OS // icons. MergeWords(&OSIconName, Volume->VolName, L','); } // if/else network boot // detect specific loaders if (StriSubCmp(L"bzImage", NameClues) || StriSubCmp(L"vmlinuz", NameClues) || StriSubCmp(L"kernel", NameClues)) { if (Volume->DiskKind != DISK_KIND_NET) { GuessLinuxDistribution(&OSIconName, Volume, LoaderPath); Entry->LoadOptions = GetMainLinuxOptions(LoaderPath, Volume); } MergeStrings(&OSIconName, L"linux", L','); Entry->OSType = 'L'; if (ShortcutLetter == 0) ShortcutLetter = 'L'; Entry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_LINUX; } else if (StriSubCmp(L"refit", LoaderPath)) { MergeStrings(&OSIconName, L"refit", L','); Entry->OSType = 'R'; ShortcutLetter = 'R'; } else if (StriSubCmp(L"refind", LoaderPath)) { MergeStrings(&OSIconName, L"refind", L','); Entry->OSType = 'R'; ShortcutLetter = 'R'; } else if (StriSubCmp(MACOSX_LOADER_PATH, LoaderPath)) { MergeStrings(&OSIconName, L"mac", L','); Entry->OSType = 'M'; ShortcutLetter = 'M'; Entry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_OSX; } else if (MyStriCmp(NameClues, L"diags.efi")) { MergeStrings(&OSIconName, L"hwtest", L','); } else if (MyStriCmp(NameClues, L"e.efi") || MyStriCmp(NameClues, L"elilo.efi") || StriSubCmp(L"elilo", NameClues)) { MergeStrings(&OSIconName, L"elilo,linux", L','); Entry->OSType = 'E'; if (ShortcutLetter == 0) ShortcutLetter = 'L'; Entry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_ELILO; } else if (StriSubCmp(L"grub", NameClues)) { MergeStrings(&OSIconName, L"grub,linux", L','); Entry->OSType = 'G'; ShortcutLetter = 'G'; Entry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_GRUB; } else if (MyStriCmp(NameClues, L"cdboot.efi") || MyStriCmp(NameClues, L"bootmgr.efi") || MyStriCmp(NameClues, L"bootmgfw.efi") || MyStriCmp(NameClues, L"bkpbootmgfw.efi")) { MergeStrings(&OSIconName, L"win8", L','); Entry->OSType = 'W'; ShortcutLetter = 'W'; Entry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_WINDOWS; } else if (MyStriCmp(NameClues, L"xom.efi")) { MergeStrings(&OSIconName, L"xom,win,win8", L','); Entry->OSType = 'X'; ShortcutLetter = 'W'; Entry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_WINDOWS; } else if (StriSubCmp(L"ipxe", NameClues)) { Entry->OSType = 'N'; ShortcutLetter = 'N'; MergeStrings(&OSIconName, L"network", L','); } if ((ShortcutLetter >= 'a') && (ShortcutLetter <= 'z')) ShortcutLetter = ShortcutLetter - 'a' + 'A'; // convert lowercase to uppercase Entry->me.ShortcutLetter = ShortcutLetter; if (Entry->me.Image == NULL) Entry->me.Image = LoadOSIcon(OSIconName, L"unknown", FALSE); MyFreePool(PathOnly); } // VOID SetLoaderDefaults() // Add a specified EFI boot loader to the list, using automatic settings // for icons, options, etc. static LOADER_ENTRY * AddLoaderEntry(IN CHAR16 *LoaderPath, IN CHAR16 *LoaderTitle, IN REFIT_VOLUME *Volume, IN BOOLEAN SubScreenReturn) { LOADER_ENTRY *Entry; CleanUpPathNameSlashes(LoaderPath); Entry = InitializeLoaderEntry(NULL); Entry->DiscoveryType = DISCOVERY_TYPE_AUTO; if (Entry != NULL) { Entry->Title = StrDuplicate((LoaderTitle != NULL) ? LoaderTitle : LoaderPath); Entry->me.Title = AllocateZeroPool(sizeof(CHAR16) * 256); // Extra space at end of Entry->me.Title enables searching on Volume->VolName even if another volume // name is identical except for something added to the end (e.g., VolB1 vs. VolB12). // Note: Volume->VolName will be NULL for network boot programs. if ((Volume->VolName) && (!MyStriCmp(Volume->VolName, L"Recovery HD"))) SPrint(Entry->me.Title, 255, L"Boot %s from %s ", (LoaderTitle != NULL) ? LoaderTitle : LoaderPath, Volume->VolName); else SPrint(Entry->me.Title, 255, L"Boot %s ", (LoaderTitle != NULL) ? LoaderTitle : LoaderPath); Entry->me.Row = 0; Entry->me.BadgeImage = Volume->VolBadgeImage; if ((LoaderPath != NULL) && (LoaderPath[0] != L'\\')) { Entry->LoaderPath = StrDuplicate(L"\\"); } else { Entry->LoaderPath = NULL; } MergeStrings(&(Entry->LoaderPath), LoaderPath, 0); Entry->Volume = Volume; SetLoaderDefaults(Entry, LoaderPath, Volume); GenerateSubScreen(Entry, Volume, SubScreenReturn); AddMenuEntry(&MainMenu, (REFIT_MENU_ENTRY *)Entry); } return(Entry); } // LOADER_ENTRY * AddLoaderEntry() // Add a Linux kernel as a submenu entry for another (pre-existing) Linux kernel entry. static VOID AddKernelToSubmenu(LOADER_ENTRY * TargetLoader, CHAR16 *FileName, REFIT_VOLUME *Volume) { REFIT_FILE *File; CHAR16 **TokenList = NULL, *InitrdName, *SubmenuName = NULL, *VolName = NULL; CHAR16 *Path = NULL, *Title, *KernelVersion; REFIT_MENU_SCREEN *SubScreen; LOADER_ENTRY *SubEntry; UINTN TokenCount; File = ReadLinuxOptionsFile(TargetLoader->LoaderPath, Volume); if (File != NULL) { SubScreen = TargetLoader->me.SubScreen; InitrdName = FindInitrd(FileName, Volume); KernelVersion = FindNumbers(FileName); while ((TokenCount = ReadTokenLine(File, &TokenList)) > 1) { ReplaceSubstring(&(TokenList[1]), KERNEL_VERSION, KernelVersion); SubEntry = InitializeLoaderEntry(TargetLoader); SplitPathName(FileName, &VolName, &Path, &SubmenuName); MergeStrings(&SubmenuName, L": ", '\0'); MergeStrings(&SubmenuName, TokenList[0] ? StrDuplicate(TokenList[0]) : StrDuplicate(L"Boot Linux"), '\0'); Title = StrDuplicate(SubmenuName); LimitStringLength(Title, MAX_LINE_LENGTH); SubEntry->me.Title = Title; MyFreePool(SubEntry->LoadOptions); SubEntry->LoadOptions = AddInitrdToOptions(TokenList[1], InitrdName); MyFreePool(SubEntry->LoaderPath); SubEntry->LoaderPath = StrDuplicate(FileName); CleanUpPathNameSlashes(SubEntry->LoaderPath); SubEntry->Volume = Volume; FreeTokenLine(&TokenList, &TokenCount); SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_LINUX; AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); } // while MyFreePool(VolName); MyFreePool(Path); MyFreePool(SubmenuName); MyFreePool(InitrdName); MyFreePool(File); MyFreePool(KernelVersion); } // if } // static VOID AddKernelToSubmenu() // Returns -1 if (Time1 < Time2), +1 if (Time1 > Time2), or 0 if // (Time1 == Time2). Precision is only to the nearest second; since // this is used for sorting boot loader entries, differences smaller // than this are likely to be meaningless (and unlikely!). INTN TimeComp(IN EFI_TIME *Time1, IN EFI_TIME *Time2) { INT64 Time1InSeconds, Time2InSeconds; // Following values are overestimates; I'm assuming 31 days in every month. // This is fine for the purpose of this function, which is limited Time1InSeconds = Time1->Second + (Time1->Minute * 60) + (Time1->Hour * 3600) + (Time1->Day * 86400) + (Time1->Month * 2678400) + ((Time1->Year - 1998) * 32140800); Time2InSeconds = Time2->Second + (Time2->Minute * 60) + (Time2->Hour * 3600) + (Time2->Day * 86400) + (Time2->Month * 2678400) + ((Time2->Year - 1998) * 32140800); if (Time1InSeconds < Time2InSeconds) return (-1); else if (Time1InSeconds > Time2InSeconds) return (1); return 0; } // INTN TimeComp() // Adds a loader list element, keeping it sorted by date. EXCEPTION: Fedora's rescue // kernel, which begins with "vmlinuz-0-rescue," should not be at the top of the list, // since that will make it the default if kernel folding is enabled, so float it to // the end. // Returns the new first element (the one with the most recent date). static struct LOADER_LIST * AddLoaderListEntry(struct LOADER_LIST *LoaderList, struct LOADER_LIST *NewEntry) { struct LOADER_LIST *LatestEntry, *CurrentEntry, *PrevEntry = NULL; BOOLEAN LinuxRescue = FALSE; LatestEntry = CurrentEntry = LoaderList; if (LoaderList == NULL) { LatestEntry = NewEntry; } else { if (StriSubCmp(L"vmlinuz-0-rescue", NewEntry->FileName)) LinuxRescue = TRUE; while ((CurrentEntry != NULL) && !StriSubCmp(L"vmlinuz-0-rescue", CurrentEntry->FileName) && (LinuxRescue || (TimeComp(&(NewEntry->TimeStamp), &(CurrentEntry->TimeStamp)) < 0))) { PrevEntry = CurrentEntry; CurrentEntry = CurrentEntry->NextEntry; } // while NewEntry->NextEntry = CurrentEntry; if (PrevEntry == NULL) { LatestEntry = NewEntry; } else { PrevEntry->NextEntry = NewEntry; } // if/else } // if/else return (LatestEntry); } // static VOID AddLoaderListEntry() // Delete the LOADER_LIST linked list static VOID CleanUpLoaderList(struct LOADER_LIST *LoaderList) { struct LOADER_LIST *Temp; while (LoaderList != NULL) { Temp = LoaderList; LoaderList = LoaderList->NextEntry; MyFreePool(Temp->FileName); MyFreePool(Temp); } // while } // static VOID CleanUpLoaderList() // Returns FALSE if the specified file/volume matches the GlobalConfig.DontScanDirs // or GlobalConfig.DontScanVolumes specification, or if Path points to a volume // other than the one specified by Volume, or if the specified path is SelfDir. // Returns TRUE if none of these conditions is met -- that is, if the path is // eligible for scanning. static BOOLEAN ShouldScan(REFIT_VOLUME *Volume, CHAR16 *Path) { CHAR16 *VolName = NULL, *DontScanDir, *PathCopy = NULL, *VolGuid = NULL; UINTN i = 0; BOOLEAN ScanIt = TRUE; VolGuid = GuidAsString(&(Volume->PartGuid)); if ((IsIn(Volume->VolName, GlobalConfig.DontScanVolumes)) || (IsIn(Volume->PartName, GlobalConfig.DontScanVolumes)) || (IsIn(VolGuid, GlobalConfig.DontScanVolumes))) { MyFreePool(VolGuid); return FALSE; } else { MyFreePool(VolGuid); } // if/else if (MyStriCmp(Path, SelfDirPath) && (Volume->DeviceHandle == SelfVolume->DeviceHandle)) return FALSE; // See if Path includes an explicit volume declaration that's NOT Volume.... PathCopy = StrDuplicate(Path); if (SplitVolumeAndFilename(&PathCopy, &VolName)) { if (VolName && !MyStriCmp(VolName, Volume->VolName)) { ScanIt = FALSE; } // if } // if Path includes volume specification MyFreePool(PathCopy); MyFreePool(VolName); VolName = NULL; // See if Volume is in GlobalConfig.DontScanDirs.... while (ScanIt && (DontScanDir = FindCommaDelimited(GlobalConfig.DontScanDirs, i++))) { SplitVolumeAndFilename(&DontScanDir, &VolName); CleanUpPathNameSlashes(DontScanDir); if (VolName != NULL) { if (VolumeMatchesDescription(Volume, VolName) && MyStriCmp(DontScanDir, Path)) ScanIt = FALSE; } else { if (MyStriCmp(DontScanDir, Path)) ScanIt = FALSE; } MyFreePool(DontScanDir); MyFreePool(VolName); DontScanDir = NULL; VolName = NULL; } // while() return ScanIt; } // BOOLEAN ShouldScan() // Returns TRUE if the file is byte-for-byte identical with the fallback file // on the volume AND if the file is not itself the fallback file; returns // FALSE if the file is not identical to the fallback file OR if the file // IS the fallback file. Intended for use in excluding the fallback boot // loader when it's a duplicate of another boot loader. static BOOLEAN DuplicatesFallback(IN REFIT_VOLUME *Volume, IN CHAR16 *FileName) { CHAR8 *FileContents, *FallbackContents; EFI_FILE_HANDLE FileHandle, FallbackHandle; EFI_FILE_INFO *FileInfo, *FallbackInfo; UINTN FileSize = 0, FallbackSize = 0; EFI_STATUS Status; BOOLEAN AreIdentical = FALSE; if (!FileExists(Volume->RootDir, FileName) || !FileExists(Volume->RootDir, FALLBACK_FULLNAME)) return FALSE; CleanUpPathNameSlashes(FileName); if (MyStriCmp(FileName, FALLBACK_FULLNAME)) return FALSE; // identical filenames, so not a duplicate.... Status = refit_call5_wrapper(Volume->RootDir->Open, Volume->RootDir, &FileHandle, FileName, EFI_FILE_MODE_READ, 0); if (Status == EFI_SUCCESS) { FileInfo = LibFileInfo(FileHandle); FileSize = FileInfo->FileSize; } else { return FALSE; } Status = refit_call5_wrapper(Volume->RootDir->Open, Volume->RootDir, &FallbackHandle, FALLBACK_FULLNAME, EFI_FILE_MODE_READ, 0); if (Status == EFI_SUCCESS) { FallbackInfo = LibFileInfo(FallbackHandle); FallbackSize = FallbackInfo->FileSize; } else { refit_call1_wrapper(FileHandle->Close, FileHandle); return FALSE; } if (FallbackSize == FileSize) { // could be identical; do full check.... FileContents = AllocatePool(FileSize); FallbackContents = AllocatePool(FallbackSize); if (FileContents && FallbackContents) { Status = refit_call3_wrapper(FileHandle->Read, FileHandle, &FileSize, FileContents); if (Status == EFI_SUCCESS) { Status = refit_call3_wrapper(FallbackHandle->Read, FallbackHandle, &FallbackSize, FallbackContents); } if (Status == EFI_SUCCESS) { AreIdentical = (CompareMem(FileContents, FallbackContents, FileSize) == 0); } // if } // if MyFreePool(FileContents); MyFreePool(FallbackContents); } // if/else // BUG ALERT: Some systems (e.g., DUET, some Macs with large displays) crash if the // following two calls are reversed. Go figure.... refit_call1_wrapper(FileHandle->Close, FallbackHandle); refit_call1_wrapper(FileHandle->Close, FileHandle); return AreIdentical; } // BOOLEAN DuplicatesFallback() // Returns FALSE if two measures of file size are identical for a single file, // TRUE if not or if the file can't be opened and the other measure is non-0. // Despite the function's name, this isn't really a direct test of symbolic // link status, since EFI doesn't officially support symlinks. It does seem // to be a reliable indicator, though. (OTOH, some disk errors might cause a // file to fail to open, which would return a false positive -- but as I use // this function to exclude symbolic links from the list of boot loaders, // that would be fine, since such boot loaders wouldn't work.) // CAUTION: *FullName MUST be properly cleaned up (via CleanUpPathNameSlashes()) static BOOLEAN IsSymbolicLink(REFIT_VOLUME *Volume, CHAR16 *FullName, EFI_FILE_INFO *DirEntry) { EFI_FILE_HANDLE FileHandle; EFI_FILE_INFO *FileInfo = NULL; EFI_STATUS Status; UINTN FileSize2 = 0; Status = refit_call5_wrapper(Volume->RootDir->Open, Volume->RootDir, &FileHandle, FullName, EFI_FILE_MODE_READ, 0); if (Status == EFI_SUCCESS) { FileInfo = LibFileInfo(FileHandle); if (FileInfo != NULL) FileSize2 = FileInfo->FileSize; } MyFreePool(FileInfo); return (DirEntry->FileSize != FileSize2); } // BOOLEAN IsSymbolicLink() // Returns TRUE if a file with the same name as the original but with // ".efi.signed" is also present in the same directory. Ubuntu is using // this filename as a signed version of the original unsigned kernel, and // there's no point in cluttering the display with two kernels that will // behave identically on non-SB systems, or when one will fail when SB // is active. // CAUTION: *FullName MUST be properly cleaned up (via CleanUpPathNameSlashes()) static BOOLEAN HasSignedCounterpart(IN REFIT_VOLUME *Volume, IN CHAR16 *FullName) { CHAR16 *NewFile = NULL; BOOLEAN retval = FALSE; MergeStrings(&NewFile, FullName, 0); MergeStrings(&NewFile, L".efi.signed", 0); if (NewFile != NULL) { if (FileExists(Volume->RootDir, NewFile)) retval = TRUE; MyFreePool(NewFile); } // if return retval; } // BOOLEAN HasSignedCounterpart() // Scan an individual directory for EFI boot loader files and, if found, // add them to the list. Exception: Ignores FALLBACK_FULLNAME, which is picked // up in ScanEfiFiles(). Sorts the entries within the loader directory so that // the most recent one appears first in the list. // Returns TRUE if a duplicate for FALLBACK_FILENAME was found, FALSE if not. static BOOLEAN ScanLoaderDir(IN REFIT_VOLUME *Volume, IN CHAR16 *Path, IN CHAR16 *Pattern) { EFI_STATUS Status; REFIT_DIR_ITER DirIter; EFI_FILE_INFO *DirEntry; CHAR16 Message[256], *Extension, *FullName; struct LOADER_LIST *LoaderList = NULL, *NewLoader; LOADER_ENTRY *FirstKernel = NULL, *LatestEntry = NULL; BOOLEAN FoundFallbackDuplicate = FALSE, IsLinux = FALSE, InSelfPath; InSelfPath = MyStriCmp(Path, SelfDirPath); if ((!SelfDirPath || !Path || (InSelfPath && (Volume->DeviceHandle != SelfVolume->DeviceHandle)) || (!InSelfPath)) && (ShouldScan(Volume, Path))) { // look through contents of the directory DirIterOpen(Volume->RootDir, Path, &DirIter); while (DirIterNext(&DirIter, 2, Pattern, &DirEntry)) { Extension = FindExtension(DirEntry->FileName); FullName = StrDuplicate(Path); MergeStrings(&FullName, DirEntry->FileName, L'\\'); CleanUpPathNameSlashes(FullName); if (DirEntry->FileName[0] == '.' || MyStriCmp(Extension, L".icns") || MyStriCmp(Extension, L".png") || (MyStriCmp(DirEntry->FileName, FALLBACK_BASENAME) && (MyStriCmp(Path, L"EFI\\BOOT"))) || FilenameIn(Volume, Path, DirEntry->FileName, SHELL_NAMES) || IsSymbolicLink(Volume, FullName, DirEntry) || /* is symbolic link */ HasSignedCounterpart(Volume, FullName) || /* a file with same name plus ".efi.signed" is present */ FilenameIn(Volume, Path, DirEntry->FileName, GlobalConfig.DontScanFiles) || !IsValidLoader(Volume->RootDir, FullName)) { continue; // skip this } NewLoader = AllocateZeroPool(sizeof(struct LOADER_LIST)); if (NewLoader != NULL) { NewLoader->FileName = StrDuplicate(FullName); NewLoader->TimeStamp = DirEntry->ModificationTime; LoaderList = AddLoaderListEntry(LoaderList, NewLoader); if (DuplicatesFallback(Volume, FullName)) FoundFallbackDuplicate = TRUE; } // if MyFreePool(Extension); MyFreePool(FullName); } // while NewLoader = LoaderList; while (NewLoader != NULL) { IsLinux = (StriSubCmp(L"bzImage", NewLoader->FileName) || StriSubCmp(L"vmlinuz", NewLoader->FileName) || StriSubCmp(L"kernel", NewLoader->FileName)); if ((FirstKernel != NULL) && IsLinux && GlobalConfig.FoldLinuxKernels) { AddKernelToSubmenu(FirstKernel, NewLoader->FileName, Volume); } else { LatestEntry = AddLoaderEntry(NewLoader->FileName, NULL, Volume, !(IsLinux && GlobalConfig.FoldLinuxKernels)); if (IsLinux && (FirstKernel == NULL)) FirstKernel = LatestEntry; } NewLoader = NewLoader->NextEntry; } // while if ((NewLoader != NULL) && (FirstKernel != NULL) && IsLinux && GlobalConfig.FoldLinuxKernels) AddMenuEntry(FirstKernel->me.SubScreen, &MenuEntryReturn); CleanUpLoaderList(LoaderList); Status = DirIterClose(&DirIter); // NOTE: EFI_INVALID_PARAMETER really is an error that should be reported; // but I've gotten reports from users who are getting this error occasionally // and I can't find anything wrong or reproduce the problem, so I'm putting // it down to buggy EFI implementations and ignoring that particular error.... if ((Status != EFI_NOT_FOUND) && (Status != EFI_INVALID_PARAMETER)) { if (Path) SPrint(Message, 255, L"while scanning the %s directory on %s", Path, Volume->VolName); else SPrint(Message, 255, L"while scanning the root directory on %s", Path, Volume->VolName); CheckError(Status, Message); } // if (Status != EFI_NOT_FOUND) } // if not scanning a blacklisted directory return FoundFallbackDuplicate; } /* static VOID ScanLoaderDir() */ // Run the IPXE_DISCOVER_NAME program, which obtains the IP address of the boot // server and the name of the boot file it delivers. CHAR16* RuniPXEDiscover(EFI_HANDLE Volume) { EFI_STATUS Status; EFI_DEVICE_PATH *FilePath; EFI_HANDLE iPXEHandle; CHAR16 *boot_info = NULL; UINTN boot_info_size = 0; FilePath = FileDevicePath (Volume, IPXE_DISCOVER_NAME); Status = refit_call6_wrapper(BS->LoadImage, FALSE, SelfImageHandle, FilePath, NULL, 0, &iPXEHandle); if (Status != 0) return NULL; Status = refit_call3_wrapper(BS->StartImage, iPXEHandle, &boot_info_size, &boot_info); return boot_info; } // RuniPXEDiscover() // Scan for network (PXE) boot servers. This function relies on the presence // of the IPXE_DISCOVER_NAME and IPXE_NAME program files on the volume from // which rEFInd launched. As of December 6, 2014, these tools aren't entirely // reliable. See BUILDING.txt for information on building them. static VOID ScanNetboot() { CHAR16 *iPXEFileName = IPXE_NAME; CHAR16 *Location; REFIT_VOLUME *NetVolume; if (FileExists(SelfVolume->RootDir, IPXE_DISCOVER_NAME) && FileExists(SelfVolume->RootDir, IPXE_NAME) && IsValidLoader(SelfVolume->RootDir, IPXE_DISCOVER_NAME) && IsValidLoader(SelfVolume->RootDir, IPXE_NAME)) { Location = RuniPXEDiscover(SelfVolume->DeviceHandle); if (Location != NULL && FileExists(SelfVolume->RootDir, iPXEFileName)) { NetVolume = AllocatePool(sizeof(REFIT_VOLUME)); CopyMem(NetVolume, SelfVolume, sizeof(REFIT_VOLUME)); NetVolume->DiskKind = DISK_KIND_NET; NetVolume->VolBadgeImage = BuiltinIcon(BUILTIN_ICON_VOL_NET); NetVolume->PartName = NetVolume->VolName = NULL; AddLoaderEntry(iPXEFileName, Location, NetVolume, TRUE); MyFreePool(NetVolume); } // if support files exist and are valid } } // VOID ScanNetBoot() // Adds *FullFileName as a macOS loader, if it exists. // Returns TRUE if the fallback loader is NOT a duplicate of this one, // FALSE if it IS a duplicate. static BOOLEAN ScanMacOsLoader(REFIT_VOLUME *Volume, CHAR16* FullFileName) { BOOLEAN ScanFallbackLoader = TRUE; CHAR16 *VolName = NULL, *PathName = NULL, *FileName = NULL; SplitPathName(FullFileName, &VolName, &PathName, &FileName); if (FileExists(Volume->RootDir, FullFileName) && !FilenameIn(Volume, PathName, L"boot.efi", GlobalConfig.DontScanFiles)) { AddLoaderEntry(FullFileName, L"macOS", Volume, TRUE); if (DuplicatesFallback(Volume, FullFileName)) ScanFallbackLoader = FALSE; } // if MyFreePool(VolName); MyFreePool(PathName); MyFreePool(FileName); return ScanFallbackLoader; } // VOID ScanMacOsLoader() static VOID ScanEfiFiles(REFIT_VOLUME *Volume) { EFI_STATUS Status; REFIT_DIR_ITER EfiDirIter; EFI_FILE_INFO *EfiDirEntry; CHAR16 FileName[256], *Directory = NULL, *MatchPatterns, *VolName = NULL, *SelfPath, *Temp; UINTN i, Length; BOOLEAN ScanFallbackLoader = TRUE; BOOLEAN FoundBRBackup = FALSE; if (Volume && (Volume->RootDir != NULL) && (Volume->VolName != NULL) && (Volume->IsReadable)) { MatchPatterns = StrDuplicate(LOADER_MATCH_PATTERNS); if (GlobalConfig.ScanAllLinux) MergeStrings(&MatchPatterns, LINUX_MATCH_PATTERNS, L','); // check for macOS boot loader if (ShouldScan(Volume, MACOSX_LOADER_DIR)) { StrCpy(FileName, MACOSX_LOADER_PATH); ScanFallbackLoader &= ScanMacOsLoader(Volume, FileName); DirIterOpen(Volume->RootDir, L"\\", &EfiDirIter); while (DirIterNext(&EfiDirIter, 1, NULL, &EfiDirEntry)) { if (IsGuid(EfiDirEntry->FileName)) { SPrint(FileName, 255, L"%s\\%s", EfiDirEntry->FileName, MACOSX_LOADER_PATH); ScanFallbackLoader &= ScanMacOsLoader(Volume, FileName); SPrint(FileName, 255, L"%s\\%s", EfiDirEntry->FileName, L"boot.efi"); if (!StriSubCmp(FileName, GlobalConfig.MacOSRecoveryFiles)) MergeStrings(&GlobalConfig.MacOSRecoveryFiles, FileName, L','); } // if } // while Status = DirIterClose(&EfiDirIter); // check for XOM StrCpy(FileName, L"System\\Library\\CoreServices\\xom.efi"); if (FileExists(Volume->RootDir, FileName) && !FilenameIn(Volume, MACOSX_LOADER_DIR, L"xom.efi", GlobalConfig.DontScanFiles)) { AddLoaderEntry(FileName, L"Windows XP (XoM)", Volume, TRUE); if (DuplicatesFallback(Volume, FileName)) ScanFallbackLoader = FALSE; } } // if should scan Mac directory // check for Microsoft boot loader/menu if (ShouldScan(Volume, L"EFI\\Microsoft\\Boot")) { StrCpy(FileName, L"EFI\\Microsoft\\Boot\\bkpbootmgfw.efi"); if (FileExists(Volume->RootDir, FileName) && !FilenameIn(Volume, L"EFI\\Microsoft\\Boot", L"bkpbootmgfw.efi", GlobalConfig.DontScanFiles)) { AddLoaderEntry(FileName, L"Microsoft EFI boot (Boot Repair backup)", Volume, TRUE); FoundBRBackup = TRUE; if (DuplicatesFallback(Volume, FileName)) ScanFallbackLoader = FALSE; } StrCpy(FileName, L"EFI\\Microsoft\\Boot\\bootmgfw.efi"); if (FileExists(Volume->RootDir, FileName) && !FilenameIn(Volume, L"EFI\\Microsoft\\Boot", L"bootmgfw.efi", GlobalConfig.DontScanFiles)) { if (FoundBRBackup) AddLoaderEntry(FileName, L"Supposed Microsoft EFI boot (probably GRUB)", Volume, TRUE); else AddLoaderEntry(FileName, L"Microsoft EFI boot", Volume, TRUE); if (DuplicatesFallback(Volume, FileName)) ScanFallbackLoader = FALSE; } } // if // scan the root directory for EFI executables if (ScanLoaderDir(Volume, L"\\", MatchPatterns)) ScanFallbackLoader = FALSE; // scan subdirectories of the EFI directory (as per the standard) DirIterOpen(Volume->RootDir, L"EFI", &EfiDirIter); while (DirIterNext(&EfiDirIter, 1, NULL, &EfiDirEntry)) { if (MyStriCmp(EfiDirEntry->FileName, L"tools") || EfiDirEntry->FileName[0] == '.') continue; // skip this, doesn't contain boot loaders or is scanned later SPrint(FileName, 255, L"EFI\\%s", EfiDirEntry->FileName); if (ScanLoaderDir(Volume, FileName, MatchPatterns)) ScanFallbackLoader = FALSE; } // while() Status = DirIterClose(&EfiDirIter); if ((Status != EFI_NOT_FOUND) && (Status != EFI_INVALID_PARAMETER)) { Temp = PoolPrint(L"while scanning the EFI directory on %s", Volume->VolName); CheckError(Status, Temp); MyFreePool(Temp); } // if // Scan user-specified (or additional default) directories.... i = 0; while ((Directory = FindCommaDelimited(GlobalConfig.AlsoScan, i++)) != NULL) { if (ShouldScan(Volume, Directory)) { SplitVolumeAndFilename(&Directory, &VolName); CleanUpPathNameSlashes(Directory); Length = StrLen(Directory); if ((Length > 0) && ScanLoaderDir(Volume, Directory, MatchPatterns)) ScanFallbackLoader = FALSE; MyFreePool(VolName); } // if should scan dir MyFreePool(Directory); } // while // Don't scan the fallback loader if it's on the same volume and a duplicate of rEFInd itself.... SelfPath = DevicePathToStr(SelfLoadedImage->FilePath); CleanUpPathNameSlashes(SelfPath); if ((Volume->DeviceHandle == SelfLoadedImage->DeviceHandle) && DuplicatesFallback(Volume, SelfPath)) ScanFallbackLoader = FALSE; // If not a duplicate & if it exists & if it's not us, create an entry // for the fallback boot loader if (ScanFallbackLoader && FileExists(Volume->RootDir, FALLBACK_FULLNAME) && ShouldScan(Volume, L"EFI\\BOOT") && !FilenameIn(Volume, L"EFI\\BOOT", FALLBACK_BASENAME, GlobalConfig.DontScanFiles)) { AddLoaderEntry(FALLBACK_FULLNAME, L"Fallback boot loader", Volume, TRUE); } } // if } // static VOID ScanEfiFiles() // Scan internal disks for valid EFI boot loaders.... static VOID ScanInternal(VOID) { UINTN VolumeIndex; for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) { if (Volumes[VolumeIndex]->DiskKind == DISK_KIND_INTERNAL) { ScanEfiFiles(Volumes[VolumeIndex]); } } // for } // static VOID ScanInternal() // Scan external disks for valid EFI boot loaders.... static VOID ScanExternal(VOID) { UINTN VolumeIndex; for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) { if (Volumes[VolumeIndex]->DiskKind == DISK_KIND_EXTERNAL) { ScanEfiFiles(Volumes[VolumeIndex]); } } // for } // static VOID ScanExternal() // Scan internal disks for valid EFI boot loaders.... static VOID ScanOptical(VOID) { UINTN VolumeIndex; for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) { if (Volumes[VolumeIndex]->DiskKind == DISK_KIND_OPTICAL) { ScanEfiFiles(Volumes[VolumeIndex]); } } // for } // static VOID ScanOptical() // default volume badge icon based on disk kind EG_IMAGE * GetDiskBadge(IN UINTN DiskType) { EG_IMAGE * Badge = NULL; switch (DiskType) { case BBS_HARDDISK: Badge = BuiltinIcon(BUILTIN_ICON_VOL_INTERNAL); break; case BBS_USB: Badge = BuiltinIcon(BUILTIN_ICON_VOL_EXTERNAL); break; case BBS_CDROM: Badge = BuiltinIcon(BUILTIN_ICON_VOL_OPTICAL); break; } // switch() return Badge; } // EG_IMAGE * GetDiskBadge() // // pre-boot tool functions // static VOID StartTool(IN LOADER_ENTRY *Entry) { BeginExternalScreen(Entry->UseGraphicsMode, Entry->me.Title + 6); // assumes "Start <title>" as assigned below StoreLoaderName(Entry->me.Title); StartEFIImage(Entry->Volume, Entry->LoaderPath, Entry->LoadOptions, Basename(Entry->LoaderPath), Entry->OSType, TRUE, FALSE); FinishExternalScreen(); } /* static VOID StartTool() */ static LOADER_ENTRY * AddToolEntry(REFIT_VOLUME *Volume,IN CHAR16 *LoaderPath, IN CHAR16 *LoaderTitle, IN EG_IMAGE *Image, IN CHAR16 ShortcutLetter, IN BOOLEAN UseGraphicsMode) { LOADER_ENTRY *Entry; CHAR16 *TitleStr = NULL; Entry = AllocateZeroPool(sizeof(LOADER_ENTRY)); TitleStr = PoolPrint(L"Start %s", LoaderTitle); Entry->me.Title = TitleStr; Entry->me.Tag = TAG_TOOL; Entry->me.Row = 1; Entry->me.ShortcutLetter = ShortcutLetter; Entry->me.Image = Image; Entry->LoaderPath = (LoaderPath) ? StrDuplicate(LoaderPath) : NULL; Entry->Volume = Volume; Entry->UseGraphicsMode = UseGraphicsMode; AddMenuEntry(&MainMenu, (REFIT_MENU_ENTRY *)Entry); return Entry; } /* static LOADER_ENTRY * AddToolEntry() */ // Locates boot loaders. NOTE: This assumes that GlobalConfig.LegacyType is set correctly. static VOID ScanForBootloaders(BOOLEAN ShowMessage) { UINTN i; CHAR8 s; BOOLEAN ScanForLegacy = FALSE; EG_PIXEL BGColor = COLOR_LIGHTBLUE; CHAR16 *HiddenTags; if (ShowMessage) egDisplayMessage(L"Scanning for boot loaders; please wait....", &BGColor, CENTER); // Determine up-front if we'll be scanning for legacy loaders.... for (i = 0; i < NUM_SCAN_OPTIONS; i++) { s = GlobalConfig.ScanFor[i]; if ((s == 'c') || (s == 'C') || (s == 'h') || (s == 'H') || (s == 'b') || (s == 'B')) ScanForLegacy = TRUE; } // for // If UEFI & scanning for legacy loaders & deep legacy scan, update NVRAM boot manager list if ((GlobalConfig.LegacyType == LEGACY_TYPE_UEFI) && ScanForLegacy && GlobalConfig.DeepLegacyScan) { BdsDeleteAllInvalidLegacyBootOptions(); BdsAddNonExistingLegacyBootOptions(); } // if HiddenTags = ReadHiddenTags(L"HiddenTags"); if ((HiddenTags) && (StrLen(HiddenTags) > 0)) { MergeStrings(&GlobalConfig.DontScanFiles, HiddenTags, L','); } HiddenTags = ReadHiddenTags(L"HiddenLegacy"); if ((HiddenTags) && (StrLen(HiddenTags) > 0)) { MergeStrings(&GlobalConfig.DontScanVolumes, HiddenTags, L','); } MyFreePool(HiddenTags); // scan for loaders and tools, add them to the menu for (i = 0; i < NUM_SCAN_OPTIONS; i++) { switch(GlobalConfig.ScanFor[i]) { case 'c': case 'C': ScanLegacyDisc(); break; case 'h': case 'H': ScanLegacyInternal(); break; case 'b': case 'B': ScanLegacyExternal(); break; case 'm': case 'M': ScanUserConfigured(GlobalConfig.ConfigFilename); break; case 'e': case 'E': ScanExternal(); break; case 'i': case 'I': ScanInternal(); break; case 'o': case 'O': ScanOptical(); break; case 'n': case 'N': ScanNetboot(); break; } // switch() } // for // assign shortcut keys for (i = 0; i < MainMenu.EntryCount && MainMenu.Entries[i]->Row == 0 && i < 9; i++) MainMenu.Entries[i]->ShortcutDigit = (CHAR16)('1' + i); // wait for user ACK when there were errors FinishTextScreen(FALSE); } // static VOID ScanForBootloaders() // Checks to see if a specified file seems to be a valid tool. // Returns TRUE if it passes all tests, FALSE otherwise static BOOLEAN IsValidTool(IN REFIT_VOLUME *BaseVolume, CHAR16 *PathName) { CHAR16 *DontVolName = NULL, *DontPathName = NULL, *DontFileName = NULL, *DontScanThis; CHAR16 *TestVolName = NULL, *TestPathName = NULL, *TestFileName = NULL; BOOLEAN retval = TRUE; UINTN i = 0; if (FileExists(BaseVolume->RootDir, PathName) && IsValidLoader(BaseVolume->RootDir, PathName)) { SplitPathName(PathName, &TestVolName, &TestPathName, &TestFileName); while (retval && (DontScanThis = FindCommaDelimited(GlobalConfig.DontScanTools, i++))) { SplitPathName(DontScanThis, &DontVolName, &DontPathName, &DontFileName); if (MyStriCmp(TestFileName, DontFileName) && ((DontPathName == NULL) || (MyStriCmp(TestPathName, DontPathName))) && ((DontVolName == NULL) || (VolumeMatchesDescription(BaseVolume, DontVolName)))) { retval = FALSE; } // if } // while } else retval = FALSE; MyFreePool(TestVolName); MyFreePool(TestPathName); MyFreePool(TestFileName); return retval; } // VOID IsValidTool() // Locate a single tool from the specified Locations using one of the // specified Names and add it to the menu. static VOID FindTool(CHAR16 *Locations, CHAR16 *Names, CHAR16 *Description, UINTN Icon) { UINTN j = 0, k, VolumeIndex; CHAR16 *DirName, *FileName, *PathName, FullDescription[256]; while ((DirName = FindCommaDelimited(Locations, j++)) != NULL) { k = 0; while ((FileName = FindCommaDelimited(Names, k++)) != NULL) { PathName = StrDuplicate(DirName); MergeStrings(&PathName, FileName, MyStriCmp(PathName, L"\\") ? 0 : L'\\'); for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) { if ((Volumes[VolumeIndex]->RootDir != NULL) && (IsValidTool(Volumes[VolumeIndex], PathName))) { SPrint(FullDescription, 255, L"%s at %s on %s", Description, PathName, Volumes[VolumeIndex]->VolName); AddToolEntry(Volumes[VolumeIndex], PathName, FullDescription, BuiltinIcon(Icon), 'S', FALSE); } // if } // for MyFreePool(PathName); MyFreePool(FileName); } // while Names MyFreePool(DirName); } // while Locations } // VOID FindTool() // Add the second-row tags containing built-in and external tools (EFI shell, // reboot, etc.) static VOID ScanForTools(VOID) { CHAR16 *FileName = NULL, *VolName = NULL, *MokLocations, Description[256], *HiddenTools; REFIT_MENU_ENTRY *TempMenuEntry; UINTN i, j, VolumeIndex; UINT64 osind; CHAR8 *b = 0; UINT32 CsrValue; MokLocations = StrDuplicate(MOK_LOCATIONS); if (MokLocations != NULL) MergeStrings(&MokLocations, SelfDirPath, L','); HiddenTools = ReadHiddenTags(L"HiddenTools"); if ((HiddenTools) && (StrLen(HiddenTools) > 0)) { MergeStrings(&GlobalConfig.DontScanTools, HiddenTools, L','); } MyFreePool(HiddenTools); for (i = 0; i < NUM_TOOLS; i++) { switch(GlobalConfig.ShowTools[i]) { // NOTE: Be sure that FileName is NULL at the end of each case. case TAG_SHUTDOWN: TempMenuEntry = CopyMenuEntry(&MenuEntryShutdown); TempMenuEntry->Image = BuiltinIcon(BUILTIN_ICON_FUNC_SHUTDOWN); AddMenuEntry(&MainMenu, TempMenuEntry); break; case TAG_REBOOT: TempMenuEntry = CopyMenuEntry(&MenuEntryReset); TempMenuEntry->Image = BuiltinIcon(BUILTIN_ICON_FUNC_RESET); AddMenuEntry(&MainMenu, TempMenuEntry); break; case TAG_ABOUT: TempMenuEntry = CopyMenuEntry(&MenuEntryAbout); TempMenuEntry->Image = BuiltinIcon(BUILTIN_ICON_FUNC_ABOUT); AddMenuEntry(&MainMenu, TempMenuEntry); break; case TAG_EXIT: TempMenuEntry = CopyMenuEntry(&MenuEntryExit); TempMenuEntry->Image = BuiltinIcon(BUILTIN_ICON_FUNC_EXIT); AddMenuEntry(&MainMenu, TempMenuEntry); break; case TAG_HIDDEN: if (GlobalConfig.HiddenTags) { TempMenuEntry = CopyMenuEntry(&MenuEntryManageHidden); TempMenuEntry->Image = BuiltinIcon(BUILTIN_ICON_FUNC_HIDDEN); AddMenuEntry(&MainMenu, TempMenuEntry); } break; case TAG_FIRMWARE: if (EfivarGetRaw(&GlobalGuid, L"OsIndicationsSupported", &b, &j) == EFI_SUCCESS) { osind = (UINT64)*b; if (osind & EFI_OS_INDICATIONS_BOOT_TO_FW_UI) { TempMenuEntry = CopyMenuEntry(&MenuEntryFirmware); TempMenuEntry->Image = BuiltinIcon(BUILTIN_ICON_FUNC_FIRMWARE); AddMenuEntry(&MainMenu, TempMenuEntry); } // if } // if break; case TAG_SHELL: j = 0; while ((FileName = FindCommaDelimited(SHELL_NAMES, j++)) != NULL) { if (IsValidTool(SelfVolume, FileName)) { AddToolEntry(SelfVolume, FileName, L"EFI Shell", BuiltinIcon(BUILTIN_ICON_TOOL_SHELL), 'S', FALSE); } MyFreePool(FileName); } // while break; case TAG_GPTSYNC: j = 0; while ((FileName = FindCommaDelimited(GPTSYNC_NAMES, j++)) != NULL) { if (IsValidTool(SelfVolume, FileName)) { AddToolEntry(SelfLoadedImage->DeviceHandle, FileName, L"Hybrid MBR tool", BuiltinIcon(BUILTIN_ICON_TOOL_PART), 'P', FALSE); } // if MyFreePool(FileName); } // while FileName = NULL; break; case TAG_GDISK: j = 0; while ((FileName = FindCommaDelimited(GDISK_NAMES, j++)) != NULL) { if (IsValidTool(SelfVolume, FileName)) { AddToolEntry(SelfVolume, FileName, L"disk partitioning tool", BuiltinIcon(BUILTIN_ICON_TOOL_PART), 'G', FALSE); } // if MyFreePool(FileName); } // while FileName = NULL; break; case TAG_NETBOOT: j = 0; while ((FileName = FindCommaDelimited(NETBOOT_NAMES, j++)) != NULL) { if (IsValidTool(SelfVolume, FileName)) { AddToolEntry(SelfVolume, FileName, L"Netboot", BuiltinIcon(BUILTIN_ICON_TOOL_NETBOOT), 'N', FALSE); } // if MyFreePool(FileName); } // while FileName = NULL; break; case TAG_APPLE_RECOVERY: for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) { j = 0; while ((FileName = FindCommaDelimited(GlobalConfig.MacOSRecoveryFiles, j++)) != NULL) { if ((Volumes[VolumeIndex]->RootDir != NULL)) { if ((IsValidTool(Volumes[VolumeIndex], FileName))) { SPrint(Description, 255, L"Apple Recovery on %s", Volumes[VolumeIndex]->VolName); AddToolEntry(Volumes[VolumeIndex], FileName, Description, BuiltinIcon(BUILTIN_ICON_TOOL_APPLE_RESCUE), 'R', TRUE); } // if } // if } // while } // for break; case TAG_WINDOWS_RECOVERY: j = 0; while ((FileName = FindCommaDelimited(GlobalConfig.WindowsRecoveryFiles, j++)) != NULL) { SplitVolumeAndFilename(&FileName, &VolName); for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) { if ((Volumes[VolumeIndex]->RootDir != NULL) && (IsValidTool(Volumes[VolumeIndex], FileName)) && ((VolName == NULL) || MyStriCmp(VolName, Volumes[VolumeIndex]->VolName))) { SPrint(Description, 255, L"Microsoft Recovery on %s", Volumes[VolumeIndex]->VolName); AddToolEntry(Volumes[VolumeIndex], FileName, Description, BuiltinIcon(BUILTIN_ICON_TOOL_WINDOWS_RESCUE), 'R', TRUE); } // if } // for } // while MyFreePool(FileName); FileName = NULL; MyFreePool(VolName); VolName = NULL; break; case TAG_MOK_TOOL: FindTool(MokLocations, MOK_NAMES, L"MOK utility", BUILTIN_ICON_TOOL_MOK_TOOL); break; case TAG_FWUPDATE_TOOL: FindTool(MokLocations, FWUPDATE_NAMES, L"firmware update utility", BUILTIN_ICON_TOOL_FWUPDATE); break; case TAG_CSR_ROTATE: if ((GetCsrStatus(&CsrValue) == EFI_SUCCESS) && (GlobalConfig.CsrValues)) { TempMenuEntry = CopyMenuEntry(&MenuEntryRotateCsr); TempMenuEntry->Image = BuiltinIcon(BUILTIN_ICON_FUNC_CSR_ROTATE); AddMenuEntry(&MainMenu, TempMenuEntry); } // if break; case TAG_MEMTEST: FindTool(MEMTEST_LOCATIONS, MEMTEST_NAMES, L"Memory test utility", BUILTIN_ICON_TOOL_MEMTEST); break; } // switch() } // for } // static VOID ScanForTools // Rescan for boot loaders VOID RescanAll(BOOLEAN DisplayMessage) { FreeList((VOID ***) &(MainMenu.Entries), &MainMenu.EntryCount); MainMenu.Entries = NULL; MainMenu.EntryCount = 0; ConnectAllDriversToAllControllers(); ScanVolumes(); ReadConfig(GlobalConfig.ConfigFilename); SetVolumeIcons(); ScanForBootloaders(TRUE); ScanForTools(); } // VOID RescanAll() #ifdef __MAKEWITH_TIANO // Minimal initialization function static VOID InitializeLib(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable) { gST = SystemTable; // gImageHandle = ImageHandle; gBS = SystemTable->BootServices; // gRS = SystemTable->RuntimeServices; gRT = SystemTable->RuntimeServices; // Some BDS functions need gRT to be set EfiGetSystemConfigurationTable (&gEfiDxeServicesTableGuid, (VOID **) &gDS); } #endif // Set up our own Secure Boot extensions.... // Returns TRUE on success, FALSE otherwise static BOOLEAN SecureBootSetup(VOID) { EFI_STATUS Status; BOOLEAN Success = FALSE; if (secure_mode() && ShimLoaded()) { Status = security_policy_install(); if (Status == EFI_SUCCESS) { Success = TRUE; } else { Print(L"Failed to install MOK Secure Boot extensions"); PauseForKey(); } } return Success; } // VOID SecureBootSetup() // Remove our own Secure Boot extensions.... // Returns TRUE on success, FALSE otherwise static BOOLEAN SecureBootUninstall(VOID) { EFI_STATUS Status; BOOLEAN Success = TRUE; if (secure_mode()) { Status = security_policy_uninstall(); if (Status != EFI_SUCCESS) { Success = FALSE; BeginTextScreen(L"Secure Boot Policy Failure"); Print(L"Failed to uninstall MOK Secure Boot extensions; forcing a reboot."); PauseForKey(); refit_call4_wrapper(RT->ResetSystem, EfiResetCold, EFI_SUCCESS, 0, NULL); } } return Success; } // VOID SecureBootUninstall // Sets the global configuration filename; will be CONFIG_FILE_NAME unless the // "-c" command-line option is set, in which case that takes precedence. // If an error is encountered, leaves the value alone (it should be set to // CONFIG_FILE_NAME when GlobalConfig is initialized). static VOID SetConfigFilename(EFI_HANDLE ImageHandle) { EFI_LOADED_IMAGE *Info; CHAR16 *Options, *FileName, *SubString; EFI_STATUS Status; Status = refit_call3_wrapper(BS->HandleProtocol, ImageHandle, &LoadedImageProtocol, (VOID **) &Info); if ((Status == EFI_SUCCESS) && (Info->LoadOptionsSize > 0)) { Options = (CHAR16 *) Info->LoadOptions; SubString = MyStrStr(Options, L" -c "); if (SubString) { FileName = StrDuplicate(&SubString[4]); if (FileName) { LimitStringLength(FileName, 256); } if (FileExists(SelfDir, FileName)) { GlobalConfig.ConfigFilename = FileName; } else { Print(L"Specified configuration file (%s) doesn't exist; using\n'refind.conf' default\n", FileName); MyFreePool(FileName); } // if/else } // if } // if } // VOID SetConfigFilename() // Adjust the GlobalConfig.DefaultSelection variable: Replace all "+" elements with the // rEFInd PreviousBoot variable, if it's available. If it's not available, delete that // element. VOID AdjustDefaultSelection() { UINTN i = 0, j; CHAR16 *Element = NULL, *NewCommaDelimited = NULL, *PreviousBoot = NULL; EFI_STATUS Status; while ((Element = FindCommaDelimited(GlobalConfig.DefaultSelection, i++)) != NULL) { if (MyStriCmp(Element, L"+")) { Status = EfivarGetRaw(&RefindGuid, L"PreviousBoot", (CHAR8 **) &PreviousBoot, &j); if (Status == EFI_SUCCESS) { MyFreePool(Element); Element = PreviousBoot; } else { Element = NULL; } } // if if (Element && StrLen(Element)) { MergeStrings(&NewCommaDelimited, Element, L','); } // if MyFreePool(Element); } // while MyFreePool(GlobalConfig.DefaultSelection); GlobalConfig.DefaultSelection = NewCommaDelimited; } // AdjustDefaultSelection() // // main entry point // EFI_STATUS EFIAPI efi_main (EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) { EFI_STATUS Status; BOOLEAN MainLoopRunning = TRUE; BOOLEAN MokProtocol; REFIT_MENU_ENTRY *ChosenEntry; UINTN MenuExit, i; CHAR16 *SelectionName = NULL; EG_PIXEL BGColor = COLOR_LIGHTBLUE; // bootstrap InitializeLib(ImageHandle, SystemTable); Status = InitRefitLib(ImageHandle); if (EFI_ERROR(Status)) return Status; // read configuration CopyMem(GlobalConfig.ScanFor, "ieom ", NUM_SCAN_OPTIONS); FindLegacyBootType(); if (GlobalConfig.LegacyType == LEGACY_TYPE_MAC) CopyMem(GlobalConfig.ScanFor, "ihebocm ", NUM_SCAN_OPTIONS); SetConfigFilename(ImageHandle); MokProtocol = SecureBootSetup(); // Scan volumes first to find SelfVolume, which is required by LoadDrivers(); // however, if drivers are loaded, a second call to ScanVolumes() is needed // to register the new filesystem(s) accessed by the drivers. // Also, ScanVolumes() must be done before ReadConfig(), which needs // SelfVolume->VolName. ScanVolumes(); if (LoadDrivers()) ScanVolumes(); ReadConfig(GlobalConfig.ConfigFilename); AdjustDefaultSelection(); if (GlobalConfig.SpoofOSXVersion && GlobalConfig.SpoofOSXVersion[0] != L'\0') SetAppleOSInfo(); InitScreen(); WarnIfLegacyProblems(); MainMenu.TimeoutSeconds = GlobalConfig.Timeout; // disable EFI watchdog timer refit_call4_wrapper(BS->SetWatchdogTimer, 0x0000, 0x0000, 0x0000, NULL); // further bootstrap (now with config available) SetupScreen(); SetVolumeIcons(); ScanForBootloaders(FALSE); ScanForTools(); // SetupScreen() clears the screen; but ScanForBootloaders() may display a // message that must be deleted, so do so BltClearScreen(TRUE); pdInitialize(); if (GlobalConfig.ScanDelay > 0) { if (GlobalConfig.ScanDelay > 1) egDisplayMessage(L"Pausing before disk scan; please wait....", &BGColor, CENTER); for (i = 0; i < GlobalConfig.ScanDelay; i++) refit_call1_wrapper(BS->Stall, 1000000); RescanAll(GlobalConfig.ScanDelay > 1); BltClearScreen(TRUE); } // if if (GlobalConfig.DefaultSelection) SelectionName = StrDuplicate(GlobalConfig.DefaultSelection); if (GlobalConfig.ShutdownAfterTimeout) MainMenu.TimeoutText = L"Shutdown"; while (MainLoopRunning) { MenuExit = RunMainMenu(&MainMenu, &SelectionName, &ChosenEntry); // The Escape key triggers a re-scan operation.... if (MenuExit == MENU_EXIT_ESCAPE) { MenuExit = 0; RescanAll(TRUE); continue; } if ((MenuExit == MENU_EXIT_TIMEOUT) && GlobalConfig.ShutdownAfterTimeout) { ChosenEntry->Tag = TAG_SHUTDOWN; } switch (ChosenEntry->Tag) { case TAG_REBOOT: // Reboot TerminateScreen(); refit_call4_wrapper(RT->ResetSystem, EfiResetCold, EFI_SUCCESS, 0, NULL); MainLoopRunning = FALSE; // just in case we get this far break; case TAG_SHUTDOWN: // Shut Down TerminateScreen(); refit_call4_wrapper(RT->ResetSystem, EfiResetShutdown, EFI_SUCCESS, 0, NULL); MainLoopRunning = FALSE; // just in case we get this far break; case TAG_ABOUT: // About rEFInd AboutrEFInd(); break; case TAG_LOADER: // Boot OS via .EFI loader StartLoader((LOADER_ENTRY *)ChosenEntry, SelectionName); break; case TAG_LEGACY: // Boot legacy OS StartLegacy((LEGACY_ENTRY *)ChosenEntry, SelectionName); break; case TAG_LEGACY_UEFI: // Boot a legacy OS on a non-Mac StartLegacyUEFI((LEGACY_ENTRY *)ChosenEntry, SelectionName); break; case TAG_TOOL: // Start a EFI tool StartTool((LOADER_ENTRY *)ChosenEntry); break; case TAG_HIDDEN: // Manage hidden tag entries ManageHiddenTags(); break; case TAG_EXIT: // Terminate rEFInd if ((MokProtocol) && !SecureBootUninstall()) { MainLoopRunning = FALSE; // just in case we get this far } else { BeginTextScreen(L" "); return EFI_SUCCESS; } break; case TAG_FIRMWARE: // Reboot into firmware's user interface RebootIntoFirmware(); break; case TAG_CSR_ROTATE: RotateCsrValue(); break; } // switch() } // while() // If we end up here, things have gone wrong. Try to reboot, and if that // fails, go into an endless loop. refit_call4_wrapper(RT->ResetSystem, EfiResetCold, EFI_SUCCESS, 0, NULL); EndlessIdleLoop(); return EFI_SUCCESS; } /* efi_main() */ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/refind/crc32.c������������������������������������������������������������������������0000664�0001750�0001750�00000012765�12626644770�015672� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*- * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or * code or tables extracted from it, as desired without restriction. * * First, the polynomial itself and its table of feedback terms. The * polynomial is * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 * * Note that we take it "backwards" and put the highest-order term in * the lowest-order bit. The X^32 term is "implied"; the LSB is the * X^31 term, etc. The X^0 term (usually shown as "+1") results in * the MSB being 1 * * Note that the usual hardware shift register implementation, which * is what we're using (we're merely optimizing it by doing eight-bit * chunks at a time) shifts bits into the lowest-order term. In our * implementation, that means shifting towards the right. Why do we * do it this way? Because the calculated CRC must be transmitted in * order from highest-order term to lowest-order term. UARTs transmit * characters in order from LSB to MSB. By storing the CRC this way * we hand it to the UART in the order low-byte to high-byte; the UART * sends each low-bit to hight-bit; and the result is transmission bit * by bit from highest- to lowest-order term without requiring any bit * shuffling on our part. Reception works similarly * * The feedback terms table consists of 256, 32-bit entries. Notes * * The table can be generated at runtime if desired; code to do so * is shown later. It might not be obvious, but the feedback * terms simply represent the results of eight shift/xor opera * tions for all combinations of data and CRC register values * * The values must be right-shifted by eight bits by the "updcrc * logic; the shift must be unsigned (bring in zeroes). On some * hardware you could probably optimize the shift in assembler by * using byte-swap instructions * polynomial $edb88320 * * * CRC32 code derived from work by Gary S. Brown. */ /* * Modified slightly for use on EFI by Rod Smith */ #include "crc32.h" static UINT32 crc32_tab[] = { 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d }; UINT32 crc32(UINT32 crc, const VOID *buf, UINTN size) { const UINT8 *p; p = buf; crc = crc ^ ~0U; while (size--) crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8); return crc ^ ~0U; } �����������refind-0.11.4/refind/lib.h��������������������������������������������������������������������������0000664�0001750�0001750�00000012125�13166730410�015502� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * refit/lib.h * General header file * * Copyright (c) 2006-2009 Christoph Pfisterer * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * * Neither the name of Christoph Pfisterer nor the names of the * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Modifications copyright (c) 2012-2015 Roderick W. Smith * * Modifications distributed under the terms of the GNU General Public * License (GPL) version 3 (GPLv3), a copy of which must be distributed * with this source code or binaries made from it. * */ #ifndef __LIB_H_ #define __LIB_H_ #ifdef __MAKEWITH_GNUEFI #include "efi.h" #include "efilib.h" #define EFI_DEVICE_PATH_PROTOCOL EFI_DEVICE_PATH #else #include "../include/tiano_includes.h" #endif #include "global.h" #include "libeg.h" // // lib module // // types typedef struct { EFI_STATUS LastStatus; EFI_FILE_HANDLE DirHandle; BOOLEAN CloseDirHandle; EFI_FILE_INFO *LastFileInfo; } REFIT_DIR_ITER; #define DISK_KIND_INTERNAL (0) #define DISK_KIND_EXTERNAL (1) #define DISK_KIND_OPTICAL (2) #define DISK_KIND_NET (3) #define VOL_UNREADABLE 999 #define IS_EXTENDED_PART_TYPE(type) ((type) == 0x05 || (type) == 0x0f || (type) == 0x85) // GPT attributes of interest to us for Freedesktop.org Discoverable // Partitions Specification.... #define GPT_READ_ONLY 0x1000000000000000 #define GPT_NO_AUTOMOUNT 0x8000000000000000 // Partition names to be ignored when setting volume name #define IGNORE_PARTITION_NAMES L"Microsoft basic data,Linux filesystem,Apple HFS/HFS+" extern EFI_GUID gFreedesktopRootGuid; EFI_STATUS InitRefitLib(IN EFI_HANDLE ImageHandle); VOID UninitRefitLib(VOID); EFI_STATUS ReinitRefitLib(VOID); EFI_STATUS EfivarGetRaw(EFI_GUID *vendor, CHAR16 *name, CHAR8 **buffer, UINTN *size); EFI_STATUS EfivarSetRaw(EFI_GUID *vendor, CHAR16 *name, CHAR8 *buf, UINTN size, BOOLEAN persistent); VOID CleanUpPathNameSlashes(IN OUT CHAR16 *PathName); VOID CreateList(OUT VOID ***ListPtr, OUT UINTN *ElementCount, IN UINTN InitialElementCount); VOID AddListElement(IN OUT VOID ***ListPtr, IN OUT UINTN *ElementCount, IN VOID *NewElement); VOID FreeList(IN OUT VOID ***ListPtr, IN OUT UINTN *ElementCount); VOID SetVolumeBadgeIcon(REFIT_VOLUME *Volume); VOID ScanVolumes(VOID); VOID SetVolumeIcons(VOID); BOOLEAN FileExists(IN EFI_FILE *BaseDir, IN CHAR16 *RelativePath); EFI_STATUS DirNextEntry(IN EFI_FILE *Directory, IN OUT EFI_FILE_INFO **DirEntry, IN UINTN FilterMode); VOID DirIterOpen(IN EFI_FILE *BaseDir, IN CHAR16 *RelativePath OPTIONAL, OUT REFIT_DIR_ITER *DirIter); BOOLEAN DirIterNext(IN OUT REFIT_DIR_ITER *DirIter, IN UINTN FilterMode, IN CHAR16 *FilePattern OPTIONAL, OUT EFI_FILE_INFO **DirEntry); EFI_STATUS DirIterClose(IN OUT REFIT_DIR_ITER *DirIter); CHAR16 * Basename(IN CHAR16 *Path); CHAR16 * StripEfiExtension(CHAR16 *FileName); INTN FindMem(IN VOID *Buffer, IN UINTN BufferLength, IN VOID *SearchString, IN UINTN SearchStringLength); VOID ReinitVolumes(VOID); CHAR16 *FindExtension(IN CHAR16 *Path); CHAR16 *FindLastDirName(IN CHAR16 *Path); CHAR16 *FindPath(IN CHAR16* FullPath); VOID FindVolumeAndFilename(IN EFI_DEVICE_PATH *loadpath, OUT REFIT_VOLUME **DeviceVolume, OUT CHAR16 **loader); BOOLEAN SplitVolumeAndFilename(IN OUT CHAR16 **Path, OUT CHAR16 **VolName); VOID SplitPathName(CHAR16 *InPath, CHAR16 **VolName, CHAR16 **Path, CHAR16 **Filename); BOOLEAN FindVolume(REFIT_VOLUME **Volume, CHAR16 *Identifier); BOOLEAN VolumeMatchesDescription(REFIT_VOLUME *Volume, CHAR16 *Description); BOOLEAN FilenameIn(IN REFIT_VOLUME *Volume, IN CHAR16 *Directory, IN CHAR16 *Filename, IN CHAR16 *List); VOID MyFreePool(IN OUT VOID *Pointer); BOOLEAN EjectMedia(VOID); BOOLEAN GuidsAreEqual(EFI_GUID *Guid1, EFI_GUID *Guid2); VOID EraseUint32List(UINT32_LIST **TheList); #endif�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/refind/menu.c�������������������������������������������������������������������������0000664�0001750�0001750�00000214356�13166732374�015720� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * refit/menu.c * Menu functions * * Copyright (c) 2006 Christoph Pfisterer * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * * Neither the name of Christoph Pfisterer nor the names of the * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Modifications copyright (c) 2012-2017 Roderick W. Smith * * Modifications distributed under the terms of the GNU General Public * License (GPL) version 3 (GPLv3), or (at your option) any later version. * */ /* * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "global.h" #include "screen.h" #include "lib.h" #include "menu.h" #include "config.h" #include "libeg.h" #include "libegint.h" #include "line_edit.h" #include "mystrings.h" #include "icns.h" #include "../include/refit_call_wrapper.h" #include "../include/egemb_back_selected_small.h" #include "../include/egemb_back_selected_big.h" #include "../include/egemb_arrow_left.h" #include "../include/egemb_arrow_right.h" // other menu definitions #define MENU_FUNCTION_INIT (0) #define MENU_FUNCTION_CLEANUP (1) #define MENU_FUNCTION_PAINT_ALL (2) #define MENU_FUNCTION_PAINT_SELECTION (3) #define MENU_FUNCTION_PAINT_TIMEOUT (4) #define MENU_FUNCTION_PAINT_HINTS (5) typedef VOID (*MENU_STYLE_FUNC)(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, IN UINTN Function, IN CHAR16 *ParamText); static CHAR16 ArrowUp[2] = { ARROW_UP, 0 }; static CHAR16 ArrowDown[2] = { ARROW_DOWN, 0 }; static UINTN TileSizes[2] = { 144, 64 }; // Text and icon spacing constants.... #define TEXT_YMARGIN (2) #define TITLEICON_SPACING (16) #define TILE_XSPACING (8) #define TILE_YSPACING (16) // Alignment values for PaintIcon() #define ALIGN_RIGHT 1 #define ALIGN_LEFT 0 static EG_IMAGE *SelectionImages[2] = { NULL, NULL }; static EG_PIXEL SelectionBackgroundPixel = { 0xff, 0xff, 0xff, 0 }; EFI_EVENT* WaitList = NULL; UINTN WaitListLength = 0; // Pointer variables BOOLEAN PointerEnabled = FALSE; BOOLEAN PointerActive = FALSE; BOOLEAN DrawSelection = TRUE; extern EFI_GUID RefindGuid; extern REFIT_MENU_ENTRY MenuEntryReturn; static REFIT_MENU_ENTRY MenuEntryYes = { L"Yes", TAG_RETURN, 1, 0, 0, NULL, NULL, NULL }; static REFIT_MENU_ENTRY MenuEntryNo = { L"No", TAG_RETURN, 1, 0, 0, NULL, NULL, NULL }; // // Graphics helper functions // static VOID InitSelection(VOID) { EG_IMAGE *TempSmallImage = NULL, *TempBigImage = NULL; BOOLEAN LoadedSmallImage = FALSE; if (!AllowGraphicsMode) return; if (SelectionImages[0] != NULL) return; // load small selection image if (GlobalConfig.SelectionSmallFileName != NULL) { TempSmallImage = egLoadImage(SelfDir, GlobalConfig.SelectionSmallFileName, TRUE); } if (TempSmallImage == NULL) TempSmallImage = egPrepareEmbeddedImage(&egemb_back_selected_small, TRUE); else LoadedSmallImage = TRUE; SelectionImages[1] = egScaleImage(TempSmallImage, TileSizes[1], TileSizes[1]); // load big selection image if (GlobalConfig.SelectionBigFileName != NULL) { TempBigImage = egLoadImage(SelfDir, GlobalConfig.SelectionBigFileName, TRUE); } if (TempBigImage == NULL) { if (LoadedSmallImage) { // calculate big selection image from small one TempBigImage = egCopyImage(TempSmallImage); } else { TempBigImage = egPrepareEmbeddedImage(&egemb_back_selected_big, TRUE); } } SelectionImages[0] = egScaleImage(TempBigImage, TileSizes[0], TileSizes[0]); if (TempSmallImage) egFreeImage(TempSmallImage); if (TempBigImage) egFreeImage(TempBigImage); } // VOID InitSelection() // // Scrolling functions // static VOID InitScroll(OUT SCROLL_STATE *State, IN UINTN ItemCount, IN UINTN VisibleSpace) { State->PreviousSelection = State->CurrentSelection = 0; State->MaxIndex = (INTN)ItemCount - 1; State->FirstVisible = 0; if (AllowGraphicsMode) { State->MaxVisible = UGAWidth / (TileSizes[0] + TILE_XSPACING) - 1; } else State->MaxVisible = ConHeight - 4; if ((VisibleSpace > 0) && (VisibleSpace < State->MaxVisible)) State->MaxVisible = (INTN)VisibleSpace; State->PaintAll = TRUE; State->PaintSelection = FALSE; State->LastVisible = State->FirstVisible + State->MaxVisible - 1; } // Adjust variables relating to the scrolling of tags, for when a selected icon isn't // visible given the current scrolling condition.... static VOID AdjustScrollState(IN SCROLL_STATE *State) { if (State->CurrentSelection > State->LastVisible) { State->LastVisible = State->CurrentSelection; State->FirstVisible = 1 + State->CurrentSelection - State->MaxVisible; if (State->FirstVisible < 0) // shouldn't happen, but just in case.... State->FirstVisible = 0; State->PaintAll = TRUE; } // Scroll forward if (State->CurrentSelection < State->FirstVisible) { State->FirstVisible = State->CurrentSelection; State->LastVisible = State->CurrentSelection + State->MaxVisible - 1; State->PaintAll = TRUE; } // Scroll backward } // static VOID AdjustScrollState static VOID UpdateScroll(IN OUT SCROLL_STATE *State, IN UINTN Movement) { State->PreviousSelection = State->CurrentSelection; switch (Movement) { case SCROLL_LINE_LEFT: if (State->CurrentSelection > 0) { State->CurrentSelection --; } break; case SCROLL_LINE_RIGHT: if (State->CurrentSelection < State->MaxIndex) { State->CurrentSelection ++; } break; case SCROLL_LINE_UP: if (State->ScrollMode == SCROLL_MODE_ICONS) { if (State->CurrentSelection >= State->InitialRow1) { if (State->MaxIndex > State->InitialRow1) { // avoid division by 0! State->CurrentSelection = State->FirstVisible + (State->LastVisible - State->FirstVisible) * (State->CurrentSelection - State->InitialRow1) / (State->MaxIndex - State->InitialRow1); } else { State->CurrentSelection = State->FirstVisible; } // if/else } // if in second row } else { if (State->CurrentSelection > 0) State->CurrentSelection--; } // if/else break; case SCROLL_LINE_DOWN: if (State->ScrollMode == SCROLL_MODE_ICONS) { if (State->CurrentSelection <= State->FinalRow0) { if (State->LastVisible > State->FirstVisible) { // avoid division by 0! State->CurrentSelection = State->InitialRow1 + (State->MaxIndex - State->InitialRow1) * (State->CurrentSelection - State->FirstVisible) / (State->LastVisible - State->FirstVisible); } else { State->CurrentSelection = State->InitialRow1; } // if/else } // if in first row } else { if (State->CurrentSelection < State->MaxIndex) State->CurrentSelection++; } // if/else break; case SCROLL_PAGE_UP: if (State->CurrentSelection <= State->FinalRow0) State->CurrentSelection -= State->MaxVisible; else if (State->CurrentSelection == State->InitialRow1) State->CurrentSelection = State->FinalRow0; else State->CurrentSelection = State->InitialRow1; if (State->CurrentSelection < 0) State->CurrentSelection = 0; break; case SCROLL_FIRST: if (State->CurrentSelection > 0) { State->PaintAll = TRUE; State->CurrentSelection = 0; } break; case SCROLL_PAGE_DOWN: if (State->CurrentSelection < State->FinalRow0) { State->CurrentSelection += State->MaxVisible; if (State->CurrentSelection > State->FinalRow0) State->CurrentSelection = State->FinalRow0; } else if (State->CurrentSelection == State->FinalRow0) { State->CurrentSelection++; } else { State->CurrentSelection = State->MaxIndex; } if (State->CurrentSelection > State->MaxIndex) State->CurrentSelection = State->MaxIndex; break; case SCROLL_LAST: if (State->CurrentSelection < State->MaxIndex) { State->PaintAll = TRUE; State->CurrentSelection = State->MaxIndex; } break; case SCROLL_NONE: break; } if (State->ScrollMode == SCROLL_MODE_TEXT) AdjustScrollState(State); if (!State->PaintAll && State->CurrentSelection != State->PreviousSelection) State->PaintSelection = TRUE; State->LastVisible = State->FirstVisible + State->MaxVisible - 1; } // static VOID UpdateScroll() // // menu helper functions // VOID AddMenuInfoLine(IN REFIT_MENU_SCREEN *Screen, IN CHAR16 *InfoLine) { AddListElement((VOID ***) &(Screen->InfoLines), &(Screen->InfoLineCount), InfoLine); } VOID AddMenuEntry(IN REFIT_MENU_SCREEN *Screen, IN REFIT_MENU_ENTRY *Entry) { AddListElement((VOID ***) &(Screen->Entries), &(Screen->EntryCount), Entry); } static INTN FindMenuShortcutEntry(IN REFIT_MENU_SCREEN *Screen, IN CHAR16 *Defaults) { UINTN i, j = 0, ShortcutLength; CHAR16 *Shortcut; while ((Shortcut = FindCommaDelimited(Defaults, j)) != NULL) { ShortcutLength = StrLen(Shortcut); if (ShortcutLength == 1) { if (Shortcut[0] >= 'a' && Shortcut[0] <= 'z') Shortcut[0] -= ('a' - 'A'); if (Shortcut[0]) { for (i = 0; i < Screen->EntryCount; i++) { if (Screen->Entries[i]->ShortcutDigit == Shortcut[0] || Screen->Entries[i]->ShortcutLetter == Shortcut[0]) { MyFreePool(Shortcut); return i; } // if } // for } // if } else if (ShortcutLength > 1) { for (i = 0; i < Screen->EntryCount; i++) { if (StriSubCmp(Shortcut, Screen->Entries[i]->Title)) { MyFreePool(Shortcut); return i; } // if } // for } MyFreePool(Shortcut); j++; } // while() return -1; } // static INTN FindMenuShortcutEntry() // Identify the end of row 0 and the beginning of row 1; store the results in the // appropriate fields in State. Also reduce MaxVisible if that value is greater // than the total number of row-0 tags and if we're in an icon-based screen static VOID IdentifyRows(IN SCROLL_STATE *State, IN REFIT_MENU_SCREEN *Screen) { UINTN i; State->FinalRow0 = 0; State->InitialRow1 = State->MaxIndex; for (i = 0; i <= State->MaxIndex; i++) { if (Screen->Entries[i]->Row == 0) { State->FinalRow0 = i; } else if ((Screen->Entries[i]->Row == 1) && (State->InitialRow1 > i)) { State->InitialRow1 = i; } // if/else } // for if ((State->ScrollMode == SCROLL_MODE_ICONS) && (State->MaxVisible > (State->FinalRow0 + 1))) State->MaxVisible = State->FinalRow0 + 1; } // static VOID IdentifyRows() // Blank the screen, wait for a keypress or pointer event, and restore banner/background. // Screen may still require redrawing of text and icons on return. // TODO: Support more sophisticated screen savers, such as power-saving // mode and dynamic images. static VOID SaveScreen(VOID) { EG_PIXEL Black = { 0x0, 0x0, 0x0, 0 }; egClearScreen(&Black); WaitForInput(0); if (AllowGraphicsMode) SwitchToGraphicsAndClear(); ReadAllKeyStrokes(); } // VOID SaveScreen() // // generic menu function // static UINTN RunGenericMenu(IN REFIT_MENU_SCREEN *Screen, IN MENU_STYLE_FUNC StyleFunc, IN OUT INTN *DefaultEntryIndex, OUT REFIT_MENU_ENTRY **ChosenEntry) { SCROLL_STATE State; EFI_STATUS Status; EFI_INPUT_KEY key; INTN ShortcutEntry; BOOLEAN HaveTimeout = FALSE; BOOLEAN WaitForRelease = FALSE; UINTN TimeoutCountdown = 0; INTN PreviousTime = -1, CurrentTime, TimeSinceKeystroke = 0; CHAR16 TimeoutMessage[256]; CHAR16 KeyAsString[2]; UINTN MenuExit; EFI_STATUS PointerStatus = EFI_NOT_READY; UINTN Item; if (Screen->TimeoutSeconds > 0) { HaveTimeout = TRUE; TimeoutCountdown = Screen->TimeoutSeconds * 10; } MenuExit = 0; StyleFunc(Screen, &State, MENU_FUNCTION_INIT, NULL); IdentifyRows(&State, Screen); // override the starting selection with the default index, if any if (*DefaultEntryIndex >= 0 && *DefaultEntryIndex <= State.MaxIndex) { State.CurrentSelection = *DefaultEntryIndex; if (GlobalConfig.ScreensaverTime != -1) UpdateScroll(&State, SCROLL_NONE); } if (Screen->TimeoutSeconds == -1) { Status = refit_call2_wrapper(ST->ConIn->ReadKeyStroke, ST->ConIn, &key); if (Status == EFI_NOT_READY) { MenuExit = MENU_EXIT_TIMEOUT; } else { KeyAsString[0] = key.UnicodeChar; KeyAsString[1] = 0; ShortcutEntry = FindMenuShortcutEntry(Screen, KeyAsString); if (ShortcutEntry >= 0) { State.CurrentSelection = ShortcutEntry; MenuExit = MENU_EXIT_ENTER; } else { WaitForRelease = TRUE; HaveTimeout = FALSE; } } } if (GlobalConfig.ScreensaverTime != -1) State.PaintAll = TRUE; while (!MenuExit) { // update the screen pdClear(); if (State.PaintAll && (GlobalConfig.ScreensaverTime != -1)) { StyleFunc(Screen, &State, MENU_FUNCTION_PAINT_ALL, NULL); State.PaintAll = FALSE; } else if (State.PaintSelection) { StyleFunc(Screen, &State, MENU_FUNCTION_PAINT_SELECTION, NULL); State.PaintSelection = FALSE; } pdDraw(); if (WaitForRelease) { Status = refit_call2_wrapper(ST->ConIn->ReadKeyStroke, ST->ConIn, &key); if (Status == EFI_SUCCESS) { // reset, because otherwise the buffer gets queued with keystrokes refit_call2_wrapper(ST->ConIn->Reset, ST->ConIn, FALSE); refit_call1_wrapper(BS->Stall, 100000); } else { WaitForRelease = FALSE; refit_call2_wrapper(ST->ConIn->Reset, ST->ConIn, TRUE); } continue; } if (HaveTimeout) { CurrentTime = (TimeoutCountdown + 5) / 10; if (CurrentTime != PreviousTime) { SPrint(TimeoutMessage, 255, L"%s in %d seconds", Screen->TimeoutText, CurrentTime); if (GlobalConfig.ScreensaverTime != -1) StyleFunc(Screen, &State, MENU_FUNCTION_PAINT_TIMEOUT, TimeoutMessage); PreviousTime = CurrentTime; } } // read key press or pointer event (and wait for them if applicable) if (PointerEnabled) { PointerStatus = pdUpdateState(); } Status = refit_call2_wrapper(ST->ConIn->ReadKeyStroke, ST->ConIn, &key); if (Status == EFI_SUCCESS) { PointerActive = FALSE; DrawSelection = TRUE; TimeSinceKeystroke = 0; } else if (PointerStatus == EFI_SUCCESS) { if (StyleFunc != MainMenuStyle && pdGetState().Press) { // prevent user from getting stuck on submenus // (the only one currently reachable without a keyboard is the about screen) MenuExit = MENU_EXIT_ENTER; break; } PointerActive = TRUE; TimeSinceKeystroke = 0; } else { if (HaveTimeout && TimeoutCountdown == 0) { // timeout expired MenuExit = MENU_EXIT_TIMEOUT; break; } else if (HaveTimeout || GlobalConfig.ScreensaverTime > 0) { UINTN ElapsCount = 1; UINTN Input = WaitForInput(1000); // 1s Timeout if (Input == INPUT_KEY || Input == INPUT_POINTER) { continue; } else if (Input == INPUT_TIMEOUT) { ElapsCount = 10; // always counted as 1s to end of the timeout } TimeSinceKeystroke += ElapsCount; if (HaveTimeout) { TimeoutCountdown = TimeoutCountdown <= ElapsCount ? 0 : TimeoutCountdown - ElapsCount; } else if (GlobalConfig.ScreensaverTime > 0 && TimeSinceKeystroke > (GlobalConfig.ScreensaverTime * 10)) { SaveScreen(); State.PaintAll = TRUE; TimeSinceKeystroke = 0; } // if } else { WaitForInput(0); } continue; } // if/else !read keystroke if (HaveTimeout) { // the user pressed a key, cancel the timeout StyleFunc(Screen, &State, MENU_FUNCTION_PAINT_TIMEOUT, L""); HaveTimeout = FALSE; if (GlobalConfig.ScreensaverTime == -1) { // cancel start-with-blank-screen coding GlobalConfig.ScreensaverTime = 0; if (!GlobalConfig.TextOnly) BltClearScreen(TRUE); } } if (!PointerActive) { // react to key press switch (key.ScanCode) { case SCAN_UP: UpdateScroll(&State, SCROLL_LINE_UP); break; case SCAN_LEFT: UpdateScroll(&State, SCROLL_LINE_LEFT); break; case SCAN_DOWN: UpdateScroll(&State, SCROLL_LINE_DOWN); break; case SCAN_RIGHT: UpdateScroll(&State, SCROLL_LINE_RIGHT); break; case SCAN_HOME: UpdateScroll(&State, SCROLL_FIRST); break; case SCAN_END: UpdateScroll(&State, SCROLL_LAST); break; case SCAN_PAGE_UP: UpdateScroll(&State, SCROLL_PAGE_UP); break; case SCAN_PAGE_DOWN: UpdateScroll(&State, SCROLL_PAGE_DOWN); break; case SCAN_ESC: MenuExit = MENU_EXIT_ESCAPE; break; case SCAN_INSERT: case SCAN_F2: MenuExit = MENU_EXIT_DETAILS; break; case SCAN_DELETE: MenuExit = MENU_EXIT_HIDE; break; case SCAN_F10: egScreenShot(); break; case 0x0016: // F12 if (EjectMedia()) MenuExit = MENU_EXIT_ESCAPE; break; } switch (key.UnicodeChar) { case CHAR_LINEFEED: case CHAR_CARRIAGE_RETURN: case ' ': MenuExit = MENU_EXIT_ENTER; break; case CHAR_BACKSPACE: MenuExit = MENU_EXIT_ESCAPE; break; case '+': case CHAR_TAB: MenuExit = MENU_EXIT_DETAILS; break; case '-': MenuExit = MENU_EXIT_HIDE; break; default: KeyAsString[0] = key.UnicodeChar; KeyAsString[1] = 0; ShortcutEntry = FindMenuShortcutEntry(Screen, KeyAsString); if (ShortcutEntry >= 0) { State.CurrentSelection = ShortcutEntry; MenuExit = MENU_EXIT_ENTER; } break; } } else { //react to pointer event if (StyleFunc != MainMenuStyle) { continue; // nothing to find on submenus } State.PreviousSelection = State.CurrentSelection; POINTER_STATE PointerState = pdGetState(); Item = FindMainMenuItem(Screen, &State, PointerState.X, PointerState.Y); switch (Item) { case POINTER_NO_ITEM: if(DrawSelection) { DrawSelection = FALSE; State.PaintSelection = TRUE; } break; case POINTER_LEFT_ARROW: if(PointerState.Press) { UpdateScroll(&State, SCROLL_PAGE_UP); } if(DrawSelection) { DrawSelection = FALSE; State.PaintSelection = TRUE; } break; case POINTER_RIGHT_ARROW: if(PointerState.Press) { UpdateScroll(&State, SCROLL_PAGE_DOWN); } if(DrawSelection) { DrawSelection = FALSE; State.PaintSelection = TRUE; } break; default: if (!DrawSelection || Item != State.CurrentSelection) { DrawSelection = TRUE; State.PaintSelection = TRUE; State.CurrentSelection = Item; } if(PointerState.Press) { MenuExit = MENU_EXIT_ENTER; } break; } } } pdClear(); StyleFunc(Screen, &State, MENU_FUNCTION_CLEANUP, NULL); if (ChosenEntry) *ChosenEntry = Screen->Entries[State.CurrentSelection]; *DefaultEntryIndex = State.CurrentSelection; return MenuExit; } /* static UINTN RunGenericMenu() */ // // text-mode generic style // // Show information lines in text mode. static VOID ShowTextInfoLines(IN REFIT_MENU_SCREEN *Screen) { INTN i; BeginTextScreen(Screen->Title); if (Screen->InfoLineCount > 0) { refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BASIC); for (i = 0; i < (INTN)Screen->InfoLineCount; i++) { refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 3, 4 + i); refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, Screen->InfoLines[i]); } } } // VOID ShowTextInfoLines() // Do most of the work for text-based menus.... static VOID TextMenuStyle(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, IN UINTN Function, IN CHAR16 *ParamText) { INTN i; UINTN MenuWidth, ItemWidth, MenuHeight; static UINTN MenuPosY; static CHAR16 **DisplayStrings; CHAR16 TimeoutMessage[256]; State->ScrollMode = SCROLL_MODE_TEXT; switch (Function) { case MENU_FUNCTION_INIT: // vertical layout MenuPosY = 4; if (Screen->InfoLineCount > 0) MenuPosY += Screen->InfoLineCount + 1; MenuHeight = ConHeight - MenuPosY - 3; if (Screen->TimeoutSeconds > 0) MenuHeight -= 2; InitScroll(State, Screen->EntryCount, MenuHeight); // determine width of the menu MenuWidth = 20; // minimum for (i = 0; i <= State->MaxIndex; i++) { ItemWidth = StrLen(Screen->Entries[i]->Title); if (MenuWidth < ItemWidth) MenuWidth = ItemWidth; } MenuWidth += 2; if (MenuWidth > ConWidth - 3) MenuWidth = ConWidth - 3; // prepare strings for display DisplayStrings = AllocatePool(sizeof(CHAR16 *) * Screen->EntryCount); for (i = 0; i <= State->MaxIndex; i++) { // Note: Theoretically, SPrint() is a cleaner way to do this; but the // description of the StrSize parameter to SPrint implies it's measured // in characters, but in practice both TianoCore and GNU-EFI seem to // use bytes instead, resulting in truncated displays. I could just // double the size of the StrSize parameter, but that seems unsafe in // case a future library change starts treating this as characters, so // I'm doing it the hard way in this instance. // TODO: Review the above and possibly change other uses of SPrint() DisplayStrings[i] = AllocateZeroPool(2 * sizeof(CHAR16)); DisplayStrings[i][0] = L' '; MergeStrings(&DisplayStrings[i], Screen->Entries[i]->Title, 0); if (StrLen(DisplayStrings[i]) > MenuWidth) DisplayStrings[i][MenuWidth - 1] = 0; // TODO: use more elaborate techniques for shortening too long strings (ellipses in the middle) // TODO: account for double-width characters } // for break; case MENU_FUNCTION_CLEANUP: // release temporary memory for (i = 0; i <= State->MaxIndex; i++) MyFreePool(DisplayStrings[i]); MyFreePool(DisplayStrings); break; case MENU_FUNCTION_PAINT_ALL: // paint the whole screen (initially and after scrolling) ShowTextInfoLines(Screen); for (i = 0; i <= State->MaxIndex; i++) { if (i >= State->FirstVisible && i <= State->LastVisible) { refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 2, MenuPosY + (i - State->FirstVisible)); if (i == State->CurrentSelection) refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_CHOICE_CURRENT); else refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_CHOICE_BASIC); refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, DisplayStrings[i]); } } // scrolling indicators refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_SCROLLARROW); refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 0, MenuPosY); if (State->FirstVisible > 0) refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, ArrowUp); else refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, L" "); refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 0, MenuPosY + State->MaxVisible); if (State->LastVisible < State->MaxIndex) refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, ArrowDown); else refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, L" "); if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_HINTS)) { if (Screen->Hint1 != NULL) { refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 0, ConHeight - 2); refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, Screen->Hint1); } if (Screen->Hint2 != NULL) { refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 0, ConHeight - 1); refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, Screen->Hint2); } } break; case MENU_FUNCTION_PAINT_SELECTION: // redraw selection cursor refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 2, MenuPosY + (State->PreviousSelection - State->FirstVisible)); refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_CHOICE_BASIC); refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, DisplayStrings[State->PreviousSelection]); refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 2, MenuPosY + (State->CurrentSelection - State->FirstVisible)); refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_CHOICE_CURRENT); refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, DisplayStrings[State->CurrentSelection]); break; case MENU_FUNCTION_PAINT_TIMEOUT: if (ParamText[0] == 0) { // clear message refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BASIC); refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 0, ConHeight - 3); refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, BlankLine + 1); } else { // paint or update message refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_ERROR); refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 3, ConHeight - 3); SPrint(TimeoutMessage, 255, L"%s ", ParamText); refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, TimeoutMessage); } break; } } // // graphical generic style // inline static UINTN TextLineHeight(VOID) { return egGetFontHeight() + TEXT_YMARGIN * 2; } // UINTN TextLineHeight() // // Display a submenu // // Display text with a solid background (MenuBackgroundPixel or SelectionBackgroundPixel). // Indents text by one character and placed TEXT_YMARGIN pixels down from the // specified XPos and YPos locations. static VOID DrawText(IN CHAR16 *Text, IN BOOLEAN Selected, IN UINTN FieldWidth, IN UINTN XPos, IN UINTN YPos) { EG_IMAGE *TextBuffer; EG_PIXEL Bg; TextBuffer = egCreateImage(FieldWidth, TextLineHeight(), FALSE); egFillImage(TextBuffer, &MenuBackgroundPixel); Bg = MenuBackgroundPixel; if (Selected) { // draw selection bar background egFillImageArea(TextBuffer, 0, 0, FieldWidth, TextBuffer->Height, &SelectionBackgroundPixel); Bg = SelectionBackgroundPixel; } // render the text egRenderText(Text, TextBuffer, egGetFontCellWidth(), TEXT_YMARGIN, (Bg.r + Bg.g + Bg.b) / 3); egDrawImageWithTransparency(TextBuffer, NULL, XPos, YPos, TextBuffer->Width, TextBuffer->Height); // BltImage(TextBuffer, XPos, YPos); } // Finds the average brightness of the input Image. // NOTE: Passing an Image that covers the whole screen can strain the // capacity of a UINTN on a 32-bit system with a very large display. // Using UINT64 instead is unworkable, since the code won't compile // on a 32-bit system. As the intended use for this function is to handle // a single text string's background, this shouldn't be a problem, but it // may need addressing if it's applied more broadly.... static UINT8 AverageBrightness(EG_IMAGE *Image) { UINTN i; UINTN Sum = 0; if ((Image != NULL) && ((Image->Width * Image->Height) != 0)) { for (i = 0; i < (Image->Width * Image->Height); i++) { Sum += (Image->PixelData[i].r + Image->PixelData[i].g + Image->PixelData[i].b); } Sum /= (Image->Width * Image->Height * 3); } // if return (UINT8) Sum; } // UINT8 AverageBrightness() // Display text against the screen's background image. Special case: If Text is NULL // or 0-length, clear the line. Does NOT indent the text or reposition it relative // to the specified XPos and YPos values. static VOID DrawTextWithTransparency(IN CHAR16 *Text, IN UINTN XPos, IN UINTN YPos) { UINTN TextWidth; EG_IMAGE *TextBuffer = NULL; if (Text == NULL) Text = L""; egMeasureText(Text, &TextWidth, NULL); if (TextWidth == 0) { TextWidth = UGAWidth; XPos = 0; } TextBuffer = egCropImage(GlobalConfig.ScreenBackground, XPos, YPos, TextWidth, TextLineHeight()); if (TextBuffer == NULL) return; // render the text egRenderText(Text, TextBuffer, 0, 0, AverageBrightness(TextBuffer)); egDrawImageWithTransparency(TextBuffer, NULL, XPos, YPos, TextBuffer->Width, TextBuffer->Height); egFreeImage(TextBuffer); } // Compute the size & position of the window that will hold a subscreen's information. static VOID ComputeSubScreenWindowSize(REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, UINTN *XPos, UINTN *YPos, UINTN *Width, UINTN *Height, UINTN *LineWidth) { UINTN i, ItemWidth, HintTop, BannerBottomEdge, TitleWidth; UINTN FontCellWidth = egGetFontCellWidth(); UINTN FontCellHeight = egGetFontHeight(); *Width = 20; *Height = 5; TitleWidth = egComputeTextWidth(Screen->Title); for (i = 0; i < Screen->InfoLineCount; i++) { ItemWidth = StrLen(Screen->InfoLines[i]); if (*Width < ItemWidth) { *Width = ItemWidth; } (*Height)++; } for (i = 0; i <= State->MaxIndex; i++) { ItemWidth = StrLen(Screen->Entries[i]->Title); if (*Width < ItemWidth) { *Width = ItemWidth; } (*Height)++; } *Width = (*Width + 2) * FontCellWidth; *LineWidth = *Width; if (Screen->TitleImage) *Width += (Screen->TitleImage->Width + TITLEICON_SPACING * 2 + FontCellWidth); else *Width += FontCellWidth; if (*Width < TitleWidth) *Width = TitleWidth + 2 * FontCellWidth; // Keep it within the bounds of the screen, or 2/3 of the screen's width // for screens over 800 pixels wide if (*Width > UGAWidth) *Width = UGAWidth; *XPos = (UGAWidth - *Width) / 2; HintTop = UGAHeight - (FontCellHeight * 3); // top of hint text *Height *= TextLineHeight(); if (Screen->TitleImage && (*Height < (Screen->TitleImage->Height + TextLineHeight() * 4))) *Height = Screen->TitleImage->Height + TextLineHeight() * 4; if (GlobalConfig.BannerBottomEdge >= HintTop) { // probably a full-screen image; treat it as an empty banner BannerBottomEdge = 0; } else { BannerBottomEdge = GlobalConfig.BannerBottomEdge; } if (*Height > (HintTop - BannerBottomEdge - FontCellHeight * 2)) { BannerBottomEdge = 0; } if (*Height > (HintTop - BannerBottomEdge - FontCellHeight * 2)) { // TODO: Implement scrolling in text screen. *Height = (HintTop - BannerBottomEdge - FontCellHeight * 2); } *YPos = ((UGAHeight - *Height) / 2); if (*YPos < BannerBottomEdge) *YPos = BannerBottomEdge + FontCellHeight + (HintTop - BannerBottomEdge - *Height) / 2; } // VOID ComputeSubScreenWindowSize() // Displays sub-menus static VOID GraphicsMenuStyle(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, IN UINTN Function, IN CHAR16 *ParamText) { INTN i; UINTN ItemWidth; static UINTN LineWidth, MenuWidth, MenuHeight, EntriesPosX, TitlePosX, EntriesPosY, TimeoutPosY, CharWidth; EG_IMAGE *Window; EG_PIXEL *BackgroundPixel = &(GlobalConfig.ScreenBackground->PixelData[0]); CharWidth = egGetFontCellWidth(); State->ScrollMode = SCROLL_MODE_TEXT; switch (Function) { case MENU_FUNCTION_INIT: InitScroll(State, Screen->EntryCount, 0); ComputeSubScreenWindowSize(Screen, State, &EntriesPosX, &EntriesPosY, &MenuWidth, &MenuHeight, &LineWidth); TimeoutPosY = EntriesPosY + (Screen->EntryCount + 1) * TextLineHeight(); // initial painting SwitchToGraphicsAndClear(); Window = egCreateFilledImage(MenuWidth, MenuHeight, FALSE, BackgroundPixel); egDrawImage(Window, EntriesPosX, EntriesPosY); ItemWidth = egComputeTextWidth(Screen->Title); if (MenuWidth > ItemWidth) { TitlePosX = EntriesPosX + (MenuWidth - ItemWidth) / 2 - CharWidth; } else { TitlePosX = EntriesPosX; if (CharWidth > 0) { i = MenuWidth / CharWidth - 2; if (i > 0) Screen->Title[i] = 0; } // if } // if/else break; case MENU_FUNCTION_CLEANUP: // nothing to do break; case MENU_FUNCTION_PAINT_ALL: ComputeSubScreenWindowSize(Screen, State, &EntriesPosX, &EntriesPosY, &MenuWidth, &MenuHeight, &LineWidth); DrawText(Screen->Title, FALSE, (StrLen(Screen->Title) + 2) * CharWidth, TitlePosX, EntriesPosY += TextLineHeight()); if (Screen->TitleImage) { BltImageAlpha(Screen->TitleImage, EntriesPosX + TITLEICON_SPACING, EntriesPosY + TextLineHeight() * 2, BackgroundPixel); EntriesPosX += (Screen->TitleImage->Width + TITLEICON_SPACING * 2); } EntriesPosY += (TextLineHeight() * 2); if (Screen->InfoLineCount > 0) { for (i = 0; i < (INTN)Screen->InfoLineCount; i++) { DrawText(Screen->InfoLines[i], FALSE, LineWidth, EntriesPosX, EntriesPosY); EntriesPosY += TextLineHeight(); } EntriesPosY += TextLineHeight(); // also add a blank line } for (i = 0; i <= State->MaxIndex; i++) { DrawText(Screen->Entries[i]->Title, (i == State->CurrentSelection), LineWidth, EntriesPosX, EntriesPosY + i * TextLineHeight()); } if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_HINTS)) { if ((Screen->Hint1 != NULL) && (StrLen(Screen->Hint1) > 0)) DrawTextWithTransparency(Screen->Hint1, (UGAWidth - egComputeTextWidth(Screen->Hint1)) / 2, UGAHeight - (egGetFontHeight() * 3)); if ((Screen->Hint2 != NULL) && (StrLen(Screen->Hint2) > 0)) DrawTextWithTransparency(Screen->Hint2, (UGAWidth - egComputeTextWidth(Screen->Hint2)) / 2, UGAHeight - (egGetFontHeight() * 2)); } // if break; case MENU_FUNCTION_PAINT_SELECTION: // redraw selection cursor DrawText(Screen->Entries[State->PreviousSelection]->Title, FALSE, LineWidth, EntriesPosX, EntriesPosY + State->PreviousSelection * TextLineHeight()); DrawText(Screen->Entries[State->CurrentSelection]->Title, TRUE, LineWidth, EntriesPosX, EntriesPosY + State->CurrentSelection * TextLineHeight()); break; case MENU_FUNCTION_PAINT_TIMEOUT: DrawText(ParamText, FALSE, LineWidth, EntriesPosX, TimeoutPosY); break; } } // static VOID GraphicsMenuStyle() // // graphical main menu style // static VOID DrawMainMenuEntry(REFIT_MENU_ENTRY *Entry, BOOLEAN selected, UINTN XPos, UINTN YPos) { EG_IMAGE *Background; // if using pointer, don't draw selection image when not hovering if (selected && DrawSelection) { Background = egCropImage(GlobalConfig.ScreenBackground, XPos, YPos, SelectionImages[Entry->Row]->Width, SelectionImages[Entry->Row]->Height); egComposeImage(Background, SelectionImages[Entry->Row], 0, 0); BltImageCompositeBadge(Background, Entry->Image, Entry->BadgeImage, XPos, YPos); } else { // Image not selected; copy background egDrawImageWithTransparency(Entry->Image, Entry->BadgeImage, XPos, YPos, SelectionImages[Entry->Row]->Width, SelectionImages[Entry->Row]->Height); } // if/else } // VOID DrawMainMenuEntry() static VOID PaintAll(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, UINTN *itemPosX, UINTN row0PosY, UINTN row1PosY, UINTN textPosY) { INTN i; if (Screen->Entries[State->CurrentSelection]->Row == 0) AdjustScrollState(State); for (i = State->FirstVisible; i <= State->MaxIndex; i++) { if (Screen->Entries[i]->Row == 0) { if (i <= State->LastVisible) { DrawMainMenuEntry(Screen->Entries[i], (i == State->CurrentSelection) ? TRUE : FALSE, itemPosX[i - State->FirstVisible], row0PosY); } // if } else { DrawMainMenuEntry(Screen->Entries[i], (i == State->CurrentSelection) ? TRUE : FALSE, itemPosX[i], row1PosY); } } if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_LABEL) && (!PointerActive || (PointerActive && DrawSelection))) { DrawTextWithTransparency(L"", 0, textPosY); DrawTextWithTransparency(Screen->Entries[State->CurrentSelection]->Title, (UGAWidth - egComputeTextWidth(Screen->Entries[State->CurrentSelection]->Title)) >> 1, textPosY); } else { DrawTextWithTransparency(L"", 0, textPosY); } if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_HINTS)) { DrawTextWithTransparency(Screen->Hint1, (UGAWidth - egComputeTextWidth(Screen->Hint1)) / 2, UGAHeight - (egGetFontHeight() * 3)); DrawTextWithTransparency(Screen->Hint2, (UGAWidth - egComputeTextWidth(Screen->Hint2)) / 2, UGAHeight - (egGetFontHeight() * 2)); } // if } // static VOID PaintAll() // Move the selection to State->CurrentSelection, adjusting icon row if necessary... static VOID PaintSelection(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, UINTN *itemPosX, UINTN row0PosY, UINTN row1PosY, UINTN textPosY) { UINTN XSelectPrev, XSelectCur, YPosPrev, YPosCur; if (((State->CurrentSelection <= State->LastVisible) && (State->CurrentSelection >= State->FirstVisible)) || (State->CurrentSelection >= State->InitialRow1) ) { if (Screen->Entries[State->PreviousSelection]->Row == 0) { XSelectPrev = State->PreviousSelection - State->FirstVisible; YPosPrev = row0PosY; } else { XSelectPrev = State->PreviousSelection; YPosPrev = row1PosY; } // if/else if (Screen->Entries[State->CurrentSelection]->Row == 0) { XSelectCur = State->CurrentSelection - State->FirstVisible; YPosCur = row0PosY; } else { XSelectCur = State->CurrentSelection; YPosCur = row1PosY; } // if/else DrawMainMenuEntry(Screen->Entries[State->PreviousSelection], FALSE, itemPosX[XSelectPrev], YPosPrev); DrawMainMenuEntry(Screen->Entries[State->CurrentSelection], TRUE, itemPosX[XSelectCur], YPosCur); if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_LABEL) && (!PointerActive || (PointerActive && DrawSelection))) { DrawTextWithTransparency(L"", 0, textPosY); DrawTextWithTransparency(Screen->Entries[State->CurrentSelection]->Title, (UGAWidth - egComputeTextWidth(Screen->Entries[State->CurrentSelection]->Title)) >> 1, textPosY); } else { DrawTextWithTransparency(L"", 0, textPosY); } } else { // Current selection not visible; must redraw the menu.... MainMenuStyle(Screen, State, MENU_FUNCTION_PAINT_ALL, NULL); } } // static VOID MoveSelection(VOID) // Display a 48x48 icon at the specified location. Uses the image specified by // ExternalFilename if it's available, or BuiltInImage if it's not. The // Y position is specified as the center value, and so is adjusted by half // the icon's height. The X position is set along the icon's left // edge if Alignment == ALIGN_LEFT, and along the right edge if // Alignment == ALIGN_RIGHT static VOID PaintIcon(IN EG_EMBEDDED_IMAGE *BuiltInIcon, IN CHAR16 *ExternalFilename, UINTN PosX, UINTN PosY, UINTN Alignment) { EG_IMAGE *Icon = NULL; Icon = egFindIcon(ExternalFilename, GlobalConfig.IconSizes[ICON_SIZE_SMALL]); if (Icon == NULL) Icon = egPrepareEmbeddedImage(BuiltInIcon, TRUE); if (Icon != NULL) { if (Alignment == ALIGN_RIGHT) PosX -= Icon->Width; egDrawImageWithTransparency(Icon, NULL, PosX, PosY - (Icon->Height / 2), Icon->Width, Icon->Height); } } // static VOID () UINTN ComputeRow0PosY(VOID) { return ((UGAHeight / 2) - TileSizes[0] / 2); } // UINTN ComputeRow0PosY() // Display (or erase) the arrow icons to the left and right of an icon's row, // as appropriate. static VOID PaintArrows(SCROLL_STATE *State, UINTN PosX, UINTN PosY, UINTN row0Loaders) { EG_IMAGE *TempImage; UINTN Width, Height, RightX, AdjPosY; // NOTE: Assume that left and right arrows are of the same size.... Width = egemb_arrow_left.Width; Height = egemb_arrow_left.Height; RightX = (UGAWidth + (TileSizes[0] + TILE_XSPACING) * State->MaxVisible) / 2 + TILE_XSPACING; AdjPosY = PosY - (Height / 2); // For PaintIcon() calls, the starting Y position is moved to the midpoint // of the surrounding row; PaintIcon() adjusts this back up by half the // icon's height to properly center it. if ((State->FirstVisible > 0) && (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_ARROWS))) { PaintIcon(&egemb_arrow_left, L"arrow_left", PosX, PosY, ALIGN_RIGHT); } else { TempImage = egCropImage(GlobalConfig.ScreenBackground, PosX - Width, AdjPosY, Width, Height); BltImage(TempImage, PosX - Width, AdjPosY); egFreeImage(TempImage); } // if/else if ((State->LastVisible < (row0Loaders - 1)) && (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_ARROWS))) { PaintIcon(&egemb_arrow_right, L"arrow_right", RightX, PosY, ALIGN_LEFT); } else { TempImage = egCropImage(GlobalConfig.ScreenBackground, RightX, AdjPosY, Width, Height); BltImage(TempImage, RightX, AdjPosY); egFreeImage(TempImage); } // if/else } // VOID PaintArrows() // Display main menu in graphics mode VOID MainMenuStyle(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, IN UINTN Function, IN CHAR16 *ParamText) { INTN i; static UINTN row0PosX, row0PosXRunning, row1PosY, row0Loaders; UINTN row0Count, row1Count, row1PosX, row1PosXRunning; static UINTN *itemPosX; static UINTN row0PosY, textPosY; State->ScrollMode = SCROLL_MODE_ICONS; switch (Function) { case MENU_FUNCTION_INIT: InitScroll(State, Screen->EntryCount, GlobalConfig.MaxTags); // layout row0Count = 0; row1Count = 0; row0Loaders = 0; for (i = 0; i <= State->MaxIndex; i++) { if (Screen->Entries[i]->Row == 1) { row1Count++; } else { row0Loaders++; if (row0Count < State->MaxVisible) row0Count++; } } row0PosX = (UGAWidth + TILE_XSPACING - (TileSizes[0] + TILE_XSPACING) * row0Count) >> 1; row0PosY = ComputeRow0PosY(); row1PosX = (UGAWidth + TILE_XSPACING - (TileSizes[1] + TILE_XSPACING) * row1Count) >> 1; row1PosY = row0PosY + TileSizes[0] + TILE_YSPACING; if (row1Count > 0) textPosY = row1PosY + TileSizes[1] + TILE_YSPACING; else textPosY = row1PosY; itemPosX = AllocatePool(sizeof(UINTN) * Screen->EntryCount); row0PosXRunning = row0PosX; row1PosXRunning = row1PosX; for (i = 0; i <= State->MaxIndex; i++) { if (Screen->Entries[i]->Row == 0) { itemPosX[i] = row0PosXRunning; row0PosXRunning += TileSizes[0] + TILE_XSPACING; } else { itemPosX[i] = row1PosXRunning; row1PosXRunning += TileSizes[1] + TILE_XSPACING; } } // initial painting InitSelection(); SwitchToGraphicsAndClear(); break; case MENU_FUNCTION_CLEANUP: MyFreePool(itemPosX); break; case MENU_FUNCTION_PAINT_ALL: PaintAll(Screen, State, itemPosX, row0PosY, row1PosY, textPosY); // For PaintArrows(), the starting Y position is moved to the midpoint // of the surrounding row; PaintIcon() adjusts this back up by half the // icon's height to properly center it. PaintArrows(State, row0PosX - TILE_XSPACING, row0PosY + (TileSizes[0] / 2), row0Loaders); break; case MENU_FUNCTION_PAINT_SELECTION: PaintSelection(Screen, State, itemPosX, row0PosY, row1PosY, textPosY); break; case MENU_FUNCTION_PAINT_TIMEOUT: if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_LABEL)) { DrawTextWithTransparency(L"", 0, textPosY + TextLineHeight()); DrawTextWithTransparency(ParamText, (UGAWidth - egComputeTextWidth(ParamText)) >> 1, textPosY + TextLineHeight()); } break; } } // VOID MainMenuStyle() // Determines the index of the main menu item at the given coordinates. UINTN FindMainMenuItem(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, IN UINTN PosX, IN UINTN PosY) { UINTN i; static UINTN row0PosX, row0PosXRunning, row1PosY, row0Loaders; UINTN row0Count, row1Count, row1PosX, row1PosXRunning; static UINTN *itemPosX; static UINTN row0PosY; UINTN itemRow; row0Count = 0; row1Count = 0; row0Loaders = 0; for (i = 0; i <= State->MaxIndex; i++) { if (Screen->Entries[i]->Row == 1) { row1Count++; } else { row0Loaders++; if (row0Count < State->MaxVisible) row0Count++; } } row0PosX = (UGAWidth + TILE_XSPACING - (TileSizes[0] + TILE_XSPACING) * row0Count) >> 1; row0PosY = ComputeRow0PosY(); row1PosX = (UGAWidth + TILE_XSPACING - (TileSizes[1] + TILE_XSPACING) * row1Count) >> 1; row1PosY = row0PosY + TileSizes[0] + TILE_YSPACING; if (PosY >= row0PosY && PosY <= row0PosY + TileSizes[0]) { itemRow = 0; if(PosX <= row0PosX) { return POINTER_LEFT_ARROW; } else if(PosX >= (UGAWidth - row0PosX)) { return POINTER_RIGHT_ARROW; } } else if (PosY >= row1PosY && PosY <= row1PosY + TileSizes[1]) { itemRow = 1; } else { // Y coordinate is outside of either row return POINTER_NO_ITEM; } UINTN ItemIndex = POINTER_NO_ITEM; itemPosX = AllocatePool(sizeof(UINTN) * Screen->EntryCount); row0PosXRunning = row0PosX; row1PosXRunning = row1PosX; for (i = 0; i <= State->MaxIndex; i++) { if (Screen->Entries[i]->Row == 0) { itemPosX[i] = row0PosXRunning; row0PosXRunning += TileSizes[0] + TILE_XSPACING; } else { itemPosX[i] = row1PosXRunning; row1PosXRunning += TileSizes[1] + TILE_XSPACING; } } for (i = State->FirstVisible; i <= State->MaxIndex; i++) { if (Screen->Entries[i]->Row == 0 && itemRow == 0) { if (i <= State->LastVisible) { if(PosX >= itemPosX[i - State->FirstVisible] && PosX <= itemPosX[i - State->FirstVisible] + TileSizes[0]) { ItemIndex = i; break; } } // if } else if (Screen->Entries[i]->Row == 1 && itemRow == 1) { if(PosX >= itemPosX[i] && PosX <= itemPosX[i] + TileSizes[1]) { ItemIndex = i; break; } } } MyFreePool(itemPosX); return ItemIndex; } // VOID FindMainMenuItem() VOID GenerateWaitList() { UINTN PointerCount = pdCount(); WaitListLength = 2 + PointerCount; WaitList = AllocatePool(sizeof(EFI_EVENT) * WaitListLength); WaitList[0] = ST->ConIn->WaitForKey; UINTN Index; for(Index = 0; Index < PointerCount; Index++) { WaitList[Index + 1] = pdWaitEvent(Index); } } // VOID GenerateWaitList() UINTN WaitForInput(UINTN Timeout) { UINTN Index = INPUT_TIMEOUT; UINTN Length = WaitListLength; EFI_EVENT TimerEvent; EFI_STATUS Status; if (Timeout == 0) { Length--; } else { Status = refit_call5_wrapper(BS->CreateEvent, EVT_TIMER, 0, NULL, NULL, &TimerEvent); if(EFI_ERROR(Status)) { refit_call1_wrapper(BS->Stall, 100000); // Pause for 100 ms return INPUT_TIMER_ERROR; } else { Status = refit_call3_wrapper(BS->SetTimer, TimerEvent, TimerRelative, Timeout * 10000); WaitList[Length - 1] = TimerEvent; } } Status = refit_call3_wrapper(BS->WaitForEvent, Length, WaitList, &Index); refit_call1_wrapper(BS->CloseEvent, TimerEvent); if(EFI_ERROR(Status)) { refit_call1_wrapper(BS->Stall, 100000); // Pause for 100 ms return INPUT_TIMER_ERROR; } else if(Index == 0) { return INPUT_KEY; } else if(Index < Length - 1) { return INPUT_POINTER; } return INPUT_TIMEOUT; } // UINTN WaitForInput() // Enable the user to edit boot loader options. // Returns TRUE if the user exited with edited options; FALSE if the user // pressed Esc to terminate the edit. static BOOLEAN EditOptions(LOADER_ENTRY *MenuEntry) { UINTN x_max, y_max; CHAR16 *EditedOptions; BOOLEAN retval = FALSE; if (GlobalConfig.HideUIFlags & HIDEUI_FLAG_EDITOR) { return FALSE; } refit_call4_wrapper(ST->ConOut->QueryMode, ST->ConOut, ST->ConOut->Mode->Mode, &x_max, &y_max); if (!GlobalConfig.TextOnly) SwitchToText(TRUE); if (line_edit(MenuEntry->LoadOptions, &EditedOptions, x_max)) { MyFreePool(MenuEntry->LoadOptions); MenuEntry->LoadOptions = EditedOptions; retval = TRUE; } // if if (!GlobalConfig.TextOnly) SwitchToGraphics(); return retval; } // VOID EditOptions() // // user-callable dispatcher functions // VOID DisplaySimpleMessage(CHAR16* Title, CHAR16 *Message) { MENU_STYLE_FUNC Style = TextMenuStyle; INTN DefaultEntry = 0; REFIT_MENU_ENTRY *ChosenOption; REFIT_MENU_SCREEN HideItemMenu = { NULL, NULL, 0, NULL, 0, NULL, 0, NULL, L"Press Enter to return to main menu", L"" }; if (!Message) return; if (AllowGraphicsMode) Style = GraphicsMenuStyle; HideItemMenu.TitleImage = BuiltinIcon(BUILTIN_ICON_FUNC_ABOUT); HideItemMenu.Title = Title; AddMenuInfoLine(&HideItemMenu, Message); AddMenuEntry(&HideItemMenu, &MenuEntryReturn); RunGenericMenu(&HideItemMenu, Style, &DefaultEntry, &ChosenOption); } // VOID DisplaySimpleMessage() // Check each filename in FilenameList to be sure it refers to a valid file. If // not, delete it. This works only on filenames that are complete, with volume, // path, and filename components; if the filename omits the volume, the search // is not done and the item is left intact, no matter what. // Returns TRUE if any files were deleted, FALSE otherwise. static BOOLEAN RemoveInvalidFilenames(CHAR16 *FilenameList, CHAR16 *VarName) { UINTN i = 0; CHAR16 *Filename, *OneElement, *VolName = NULL /*, *NewList = NULL */; REFIT_VOLUME *Volume; EFI_FILE_HANDLE FileHandle; BOOLEAN DeleteIt = FALSE, DeletedSomething = FALSE; EFI_STATUS Status; while ((OneElement = FindCommaDelimited(FilenameList, i)) != NULL) { DeleteIt = FALSE; Filename = StrDuplicate(OneElement); if (SplitVolumeAndFilename(&Filename, &VolName)) { DeleteIt = TRUE; if (FindVolume(&Volume, VolName) && Volume->RootDir) { Status = refit_call5_wrapper(Volume->RootDir->Open, Volume->RootDir, &FileHandle, Filename, EFI_FILE_MODE_READ, 0); if (Status == EFI_SUCCESS) { DeleteIt = FALSE; refit_call1_wrapper(FileHandle->Close, FileHandle); } // if file exists } // if volume exists } // if list item includes volume if (DeleteIt) { DeleteItemFromCsvList(OneElement, FilenameList); } else { i++; } MyFreePool(OneElement); MyFreePool(Filename); MyFreePool(VolName); DeletedSomething |= DeleteIt; } // while() return DeletedSomething; } // BOOLEAN RemoveInvalidFilenames() // Present a menu that enables the user to delete hidden tags (that is, to // un-hide them). VOID ManageHiddenTags(VOID) { CHAR16 *AllTags = NULL, *HiddenTags, *HiddenTools, *HiddenLegacy, *OneElement = NULL; INTN DefaultEntry = 0; MENU_STYLE_FUNC Style = TextMenuStyle; REFIT_MENU_ENTRY *ChosenOption, *MenuEntryItem = NULL; REFIT_MENU_SCREEN HideItemMenu = { L"Manage Hidden Tags Menu", NULL, 0, NULL, 0, NULL, 0, NULL, L"Select an option and press Enter or", L"press Esc to return to main menu without changes" }; UINTN MenuExit, i = 0; BOOLEAN SaveTags = FALSE, SaveTools = FALSE, SaveLegacy = FALSE; EFI_STATUS Status; HideItemMenu.TitleImage = BuiltinIcon(BUILTIN_ICON_FUNC_HIDDEN); if (AllowGraphicsMode) Style = GraphicsMenuStyle; HiddenTags = ReadHiddenTags(L"HiddenTags"); SaveTags = RemoveInvalidFilenames(HiddenTags, L"HiddenTags"); if (HiddenTags && (HiddenTags[0] != L'\0')) AllTags = StrDuplicate(HiddenTags); HiddenTools = ReadHiddenTags(L"HiddenTools"); SaveTools = RemoveInvalidFilenames(HiddenTools, L"HiddenTools"); if (HiddenTools && (HiddenTools[0] != L'\0')) MergeStrings(&AllTags, HiddenTools, L','); HiddenLegacy = ReadHiddenTags(L"HiddenLegacy"); if (HiddenLegacy && (HiddenLegacy[0] != L'\0')) MergeStrings(&AllTags, HiddenLegacy, L','); if ((AllTags) && (StrLen(AllTags) > 0)) { AddMenuInfoLine(&HideItemMenu, L"Select a tag and press Enter to restore it"); while ((OneElement = FindCommaDelimited(AllTags, i++)) != NULL) { MenuEntryItem = AllocateZeroPool(sizeof(REFIT_MENU_ENTRY)); MenuEntryItem->Title = StrDuplicate(OneElement); MenuEntryItem->Tag = TAG_RETURN; MenuEntryItem->Row = 1; AddMenuEntry(&HideItemMenu, MenuEntryItem); } // while MenuExit = RunGenericMenu(&HideItemMenu, Style, &DefaultEntry, &ChosenOption); if (MenuExit == MENU_EXIT_ENTER) { SaveTags |= DeleteItemFromCsvList(ChosenOption->Title, HiddenTags); SaveTools |= DeleteItemFromCsvList(ChosenOption->Title, HiddenTools); if (DeleteItemFromCsvList(ChosenOption->Title, HiddenLegacy)) { i = HiddenLegacy ? StrLen(HiddenLegacy) : 0; Status = EfivarSetRaw(&RefindGuid, L"HiddenLegacy", (CHAR8 *) HiddenLegacy, i * 2 + 2 * (i > 0), TRUE); SaveLegacy = TRUE; CheckError(Status, L"in ManageHiddenTags()"); } // if } // if if (SaveTags) { i = HiddenTags ? StrLen(HiddenTags) : 0; Status = EfivarSetRaw(&RefindGuid, L"HiddenTags", (CHAR8 *) HiddenTags, i * 2 + 2 * (i > 0), TRUE); CheckError(Status, L"in ManageHiddenTags()"); } if (SaveTools) { i = HiddenTools ? StrLen(HiddenTools) : 0; Status = EfivarSetRaw(&RefindGuid, L"HiddenTools", (CHAR8 *) HiddenTools, i * 2 + 2 * (i > 0), TRUE); CheckError(Status, L"in ManageHiddenTags()"); } if (SaveTags || SaveTools || SaveLegacy) RescanAll(TRUE); } else { DisplaySimpleMessage(L"Information", L"No hidden tags found"); } MyFreePool(AllTags); MyFreePool(HiddenTags); MyFreePool(HiddenTools); MyFreePool(HiddenLegacy); MyFreePool(OneElement); MyFreePool(MenuEntryItem); } // VOID ManageHiddenTags() CHAR16* ReadHiddenTags(CHAR16 *VarName) { CHAR8 *Buffer = NULL; UINTN Size; EFI_STATUS Status; Status = EfivarGetRaw(&RefindGuid, VarName, &Buffer, &Size); if ((Status != EFI_SUCCESS) && (Status != EFI_NOT_FOUND)) CheckError(Status, L"in ReadHiddenTags()"); if ((Status == EFI_SUCCESS) && (Size == 0)) { MyFreePool(Buffer); Buffer = NULL; } return (CHAR16 *) Buffer; } // CHAR16* ReadHiddenTags() // Add PathName to the hidden tags variable specified by *VarName. static VOID AddToHiddenTags(CHAR16 *VarName, CHAR16 *Pathname) { CHAR16 *HiddenTags; EFI_STATUS Status; if (Pathname && (StrLen(Pathname) > 0)) { HiddenTags = ReadHiddenTags(VarName); MergeStrings(&HiddenTags, Pathname, L','); Status = EfivarSetRaw(&RefindGuid, VarName, (CHAR8 *) HiddenTags, StrLen(HiddenTags) * 2 + 2, TRUE); CheckError(Status, L"in AddToHiddenTags()"); MyFreePool(HiddenTags); } // if } // VOID AddToHiddenTags() // Adds a filename, specified by the *Loader variable, to the *VarName EFI variable, // using the mostly-prepared *HideItemMenu structure to prompt the user to confirm // hiding that item. // Returns TRUE if item was hidden, FALSE otherwise. static BOOLEAN HideEfiTag(LOADER_ENTRY *Loader, REFIT_MENU_SCREEN *HideItemMenu, CHAR16 *VarName) { REFIT_VOLUME *TestVolume = NULL; BOOLEAN TagHidden = FALSE; CHAR16 *FullPath = NULL, *GuidStr = NULL; MENU_STYLE_FUNC Style = TextMenuStyle; UINTN MenuExit; INTN DefaultEntry = 1; REFIT_MENU_ENTRY *ChosenOption; if ((!Loader) || (!(Loader->Volume)) || (!(Loader->LoaderPath)) || (!HideItemMenu) || (!VarName)) return FALSE; if (AllowGraphicsMode) Style = GraphicsMenuStyle; if (Loader->Volume->VolName && (StrLen(Loader->Volume->VolName) > 0)) { FullPath = StrDuplicate(Loader->Volume->VolName); } else if (Loader->Volume->PartName && (StrLen(Loader->Volume->PartName) > 0)) { FullPath = StrDuplicate(Loader->Volume->PartName); } MergeStrings(&FullPath, Loader->LoaderPath, L':'); AddMenuInfoLine(HideItemMenu, PoolPrint(L"Really hide %s?", FullPath)); AddMenuEntry(HideItemMenu, &MenuEntryYes); AddMenuEntry(HideItemMenu, &MenuEntryNo); MenuExit = RunGenericMenu(HideItemMenu, Style, &DefaultEntry, &ChosenOption); if (ChosenOption && MyStriCmp(ChosenOption->Title, L"Yes") && (MenuExit == MENU_EXIT_ENTER)) { GuidStr = GuidAsString(&Loader->Volume->PartGuid); if (FindVolume(&TestVolume, GuidStr) && TestVolume->RootDir) { MyFreePool(FullPath); FullPath = NULL; MergeStrings(&FullPath, GuidAsString(&Loader->Volume->PartGuid), L'\0'); MergeStrings(&FullPath, L":", L'\0'); MergeStrings(&FullPath, Loader->LoaderPath, (Loader->LoaderPath[0] == L'\\' ? L'\0' : L'\\')); } AddToHiddenTags(VarName, FullPath); TagHidden = TRUE; } // if MyFreePool(FullPath); MyFreePool(GuidStr); return TagHidden; } // BOOLEAN HideEfiTag() static BOOLEAN HideLegacyTag(LEGACY_ENTRY *LegacyLoader, REFIT_MENU_SCREEN *HideItemMenu) { MENU_STYLE_FUNC Style = TextMenuStyle; REFIT_MENU_ENTRY *ChosenOption; INTN DefaultEntry = 1; UINTN MenuExit; CHAR16 *Name = NULL; BOOLEAN TagHidden = FALSE; if (AllowGraphicsMode) Style = GraphicsMenuStyle; if ((GlobalConfig.LegacyType == LEGACY_TYPE_MAC) && LegacyLoader->me.Title) Name = StrDuplicate(LegacyLoader->me.Title); if ((GlobalConfig.LegacyType == LEGACY_TYPE_UEFI) && LegacyLoader->BdsOption && LegacyLoader->BdsOption->Description) Name = StrDuplicate(LegacyLoader->BdsOption->Description); if (!Name) Name = StrDuplicate(L"Legacy OS"); AddMenuInfoLine(HideItemMenu, PoolPrint(L"Really hide '%s'?", Name)); AddMenuEntry(HideItemMenu, &MenuEntryYes); AddMenuEntry(HideItemMenu, &MenuEntryNo); MenuExit = RunGenericMenu(HideItemMenu, Style, &DefaultEntry, &ChosenOption); if (MyStriCmp(ChosenOption->Title, L"Yes") && (MenuExit == MENU_EXIT_ENTER)) { AddToHiddenTags(L"HiddenLegacy", Name); TagHidden = TRUE; } // if MyFreePool(Name); return TagHidden; } // BOOLEAN HideLegacyTag() static VOID HideTag(REFIT_MENU_ENTRY *ChosenEntry) { LOADER_ENTRY *Loader = (LOADER_ENTRY *) ChosenEntry; LEGACY_ENTRY *LegacyLoader = (LEGACY_ENTRY *) ChosenEntry; REFIT_MENU_SCREEN HideItemMenu = { NULL, NULL, 0, NULL, 0, NULL, 0, NULL, L"Select an option and press Enter or", L"press Esc to return to main menu without changes" }; if (ChosenEntry == NULL) return; HideItemMenu.TitleImage = BuiltinIcon(BUILTIN_ICON_FUNC_HIDDEN); // BUG: The RescanAll() calls should be conditional on successful calls to // HideEfiTag() or HideLegacyTag(); but for the former, this causes // crashes on a second call hide a tag if the user chose "No" to the first // call. This seems to be related to memory management of Volumes; the // crash occurs in FindVolumeAndFilename() and lib.c when calling // DevicePathToStr(). Calling RescanAll() on all returns from HideEfiTag() // seems to be an effective workaround, but there's likely a memory // management bug somewhere that's the root cause. switch (ChosenEntry->Tag) { case TAG_LOADER: if (Loader->DiscoveryType == DISCOVERY_TYPE_AUTO) { HideItemMenu.Title = L"Hide EFI OS Tag"; HideEfiTag(Loader, &HideItemMenu, L"HiddenTags"); RescanAll(TRUE); } else { DisplaySimpleMessage(L"Cannot Hide Entry for Manual Boot Stanza", L"You must edit refind.conf to remove this entry."); } break; case TAG_LEGACY: case TAG_LEGACY_UEFI: HideItemMenu.Title = L"Hide Legacy OS Tag"; if (HideLegacyTag(LegacyLoader, &HideItemMenu)) RescanAll(TRUE); break; case TAG_ABOUT: case TAG_REBOOT: case TAG_SHUTDOWN: case TAG_EXIT: case TAG_FIRMWARE: case TAG_CSR_ROTATE: case TAG_HIDDEN: DisplaySimpleMessage(L"Unable to Comply", L"To hide an internal tool, edit the 'showtools' line in refind.conf"); break; case TAG_TOOL: HideItemMenu.Title = L"Hide Tool Tag"; HideEfiTag(Loader, &HideItemMenu, L"HiddenTools"); RescanAll(TRUE); break; } // switch() } // VOID HideTag() UINTN RunMenu(IN REFIT_MENU_SCREEN *Screen, OUT REFIT_MENU_ENTRY **ChosenEntry) { INTN DefaultEntry = -1; MENU_STYLE_FUNC Style = TextMenuStyle; if (AllowGraphicsMode) Style = GraphicsMenuStyle; return RunGenericMenu(Screen, Style, &DefaultEntry, ChosenEntry); } UINTN RunMainMenu(REFIT_MENU_SCREEN *Screen, CHAR16** DefaultSelection, REFIT_MENU_ENTRY **ChosenEntry) { MENU_STYLE_FUNC Style = TextMenuStyle; MENU_STYLE_FUNC MainStyle = TextMenuStyle; REFIT_MENU_ENTRY *TempChosenEntry; CHAR16 *MenuTitle; UINTN MenuExit = 0; INTN DefaultEntryIndex = -1; INTN DefaultSubmenuIndex = -1; TileSizes[0] = (GlobalConfig.IconSizes[ICON_SIZE_BIG] * 9) / 8; TileSizes[1] = (GlobalConfig.IconSizes[ICON_SIZE_SMALL] * 4) / 3; if ((DefaultSelection != NULL) && (*DefaultSelection != NULL)) { // Find a menu entry that includes *DefaultSelection as a substring DefaultEntryIndex = FindMenuShortcutEntry(Screen, *DefaultSelection); } if (AllowGraphicsMode) { Style = GraphicsMenuStyle; MainStyle = MainMenuStyle; PointerEnabled = PointerActive = pdAvailable(); DrawSelection = !PointerEnabled; } // Generate this now and keep it around forever, since it's likely to be // used after this function terminates.... GenerateWaitList(); while (!MenuExit) { MenuExit = RunGenericMenu(Screen, MainStyle, &DefaultEntryIndex, &TempChosenEntry); Screen->TimeoutSeconds = 0; MenuTitle = StrDuplicate(TempChosenEntry->Title); if (MenuExit == MENU_EXIT_DETAILS) { if (TempChosenEntry->SubScreen != NULL) { MenuExit = RunGenericMenu(TempChosenEntry->SubScreen, Style, &DefaultSubmenuIndex, &TempChosenEntry); if (MenuExit == MENU_EXIT_ESCAPE || TempChosenEntry->Tag == TAG_RETURN) MenuExit = 0; if (MenuExit == MENU_EXIT_DETAILS) { if (!EditOptions((LOADER_ENTRY *) TempChosenEntry)) MenuExit = 0; } // if } else { // no sub-screen; ignore keypress MenuExit = 0; } } // Enter sub-screen if (MenuExit == MENU_EXIT_HIDE) { if (GlobalConfig.HiddenTags) HideTag(TempChosenEntry); MenuExit = 0; } // Hide launcher } if (ChosenEntry) *ChosenEntry = TempChosenEntry; if (DefaultSelection) { MyFreePool(*DefaultSelection); *DefaultSelection = MenuTitle; } // if return MenuExit; } /* UINTN RunMainMenu() */ ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/refind/line_edit.c��������������������������������������������������������������������0000664�0001750�0001750�00000015204�13004646042�016662� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������// Line-editing functions borrowed from gummiboot (cursor_left(), // cursor_right(), & line_edit()). /* * Simple UEFI boot loader which executes configured EFI images, where the * default entry is selected by a configured pattern (glob) or an on-screen * menu. * * All gummiboot code is LGPL not GPL, to stay out of politics and to give * the freedom of copying code from programs to possible future libraries. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * Copyright (C) 2012-2013 Kay Sievers <kay@vrfy.org> * Copyright (C) 2012 Harald Hoyer <harald@redhat.com> * * "Any intelligent fool can make things bigger, more complex, and more violent. " * -- Albert Einstein */ #include "global.h" #include "screen.h" #include "lib.h" #include "../include/refit_call_wrapper.h" static void cursor_left(UINTN *cursor, UINTN *first) { if ((*cursor) > 0) (*cursor)--; else if ((*first) > 0) (*first)--; } static void cursor_right(UINTN *cursor, UINTN *first, UINTN x_max, UINTN len) { if ((*cursor)+2 < x_max) (*cursor)++; else if ((*first) + (*cursor) < len) (*first)++; } BOOLEAN line_edit(CHAR16 *line_in, CHAR16 **line_out, UINTN x_max) { CHAR16 *line; UINTN size; UINTN len; UINTN first; UINTN y_pos = 3; CHAR16 *print; UINTN cursor; BOOLEAN exit; BOOLEAN enter; DrawScreenHeader(L"Line Editor"); refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, (ConWidth - 71) / 2, ConHeight - 1); refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, L"Use cursor keys to edit, Esc to exit, Enter to boot with edited options"); if (!line_in) line_in = L""; size = StrLen(line_in) + 1024; line = AllocatePool(size * sizeof(CHAR16)); StrCpy(line, line_in); len = StrLen(line); print = AllocatePool(x_max * sizeof(CHAR16)); refit_call2_wrapper(ST->ConOut->EnableCursor, ST->ConOut, TRUE); first = 0; cursor = 0; enter = FALSE; exit = FALSE; while (!exit) { UINTN index; EFI_STATUS err; EFI_INPUT_KEY key; UINTN i; i = len - first; if (i >= x_max-2) i = x_max-2; CopyMem(print, line + first, i * sizeof(CHAR16)); print[i++] = ' '; print[i] = '\0'; refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 0, y_pos); refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, print); refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, cursor, y_pos); refit_call3_wrapper(BS->WaitForEvent, 1, &ST->ConIn->WaitForKey, &index); err = refit_call2_wrapper(ST->ConIn->ReadKeyStroke, ST->ConIn, &key); if (EFI_ERROR(err)) continue; switch (key.ScanCode) { case SCAN_ESC: exit = TRUE; break; case SCAN_HOME: cursor = 0; first = 0; continue; case SCAN_END: cursor = len; if (cursor >= x_max) { cursor = x_max-2; first = len - (x_max-2); } continue; case SCAN_UP: while((first + cursor) && line[first + cursor] == ' ') cursor_left(&cursor, &first); while((first + cursor) && line[first + cursor] != ' ') cursor_left(&cursor, &first); while((first + cursor) && line[first + cursor] == ' ') cursor_left(&cursor, &first); if (first + cursor != len && first + cursor) cursor_right(&cursor, &first, x_max, len); refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, cursor, y_pos); continue; case SCAN_DOWN: while(line[first + cursor] && line[first + cursor] == ' ') cursor_right(&cursor, &first, x_max, len); while(line[first + cursor] && line[first + cursor] != ' ') cursor_right(&cursor, &first, x_max, len); while(line[first + cursor] && line[first + cursor] == ' ') cursor_right(&cursor, &first, x_max, len); refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, cursor, y_pos); continue; case SCAN_RIGHT: if (first + cursor == len) continue; cursor_right(&cursor, &first, x_max, len); refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, cursor, y_pos); continue; case SCAN_LEFT: cursor_left(&cursor, &first); refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, cursor, y_pos); continue; case SCAN_DELETE: if (len == 0) continue; if (first + cursor == len) continue; for (i = first + cursor; i < len; i++) line[i] = line[i+1]; line[len-1] = ' '; len--; continue; } switch (key.UnicodeChar) { case CHAR_LINEFEED: case CHAR_CARRIAGE_RETURN: *line_out = line; line = NULL; enter = TRUE; exit = TRUE; break; case CHAR_BACKSPACE: if (len == 0) continue; if (first == 0 && cursor == 0) continue; for (i = first + cursor-1; i < len; i++) line[i] = line[i+1]; len--; if (cursor > 0) cursor--; if (cursor > 0 || first == 0) continue; /* show full line if it fits */ if (len < x_max-2) { cursor = first; first = 0; continue; } /* jump left to see what we delete */ if (first > 10) { first -= 10; cursor = 10; } else { cursor = first; first = 0; } continue; case '\t': case ' ' ... '~': case 0x80 ... 0xffff: if (len+1 == size) continue; for (i = len; i > first + cursor; i--) line[i] = line[i-1]; line[first + cursor] = key.UnicodeChar; len++; line[len] = '\0'; if (cursor+2 < x_max) cursor++; else if (first + cursor < len) first++; continue; } } refit_call2_wrapper(ST->ConOut->EnableCursor, ST->ConOut, FALSE); MyFreePool(print); MyFreePool(line); return enter; } /* BOOLEAN line_edit() */ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/refind/lib.c��������������������������������������������������������������������������0000664�0001750�0001750�00000205253�13322730326�015503� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * refind/lib.c * General library functions * * Copyright (c) 2006-2009 Christoph Pfisterer * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * * Neither the name of Christoph Pfisterer nor the names of the * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Modifications copyright (c) 2012-2017 Roderick W. Smith * * Modifications distributed under the terms of the GNU General Public * License (GPL) version 3 (GPLv3), or (at your option) any later version. * */ /* * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "global.h" #include "lib.h" #include "icns.h" #include "screen.h" #include "../include/refit_call_wrapper.h" #include "../include/RemovableMedia.h" #include "gpt.h" #include "config.h" #include "mystrings.h" #ifdef __MAKEWITH_GNUEFI #define EfiReallocatePool ReallocatePool #else #define LibLocateHandle gBS->LocateHandleBuffer #define DevicePathProtocol gEfiDevicePathProtocolGuid #define BlockIoProtocol gEfiBlockIoProtocolGuid #define LibFileSystemInfo EfiLibFileSystemInfo #define LibOpenRoot EfiLibOpenRoot EFI_DEVICE_PATH EndDevicePath[] = { {END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, {END_DEVICE_PATH_LENGTH, 0}} }; #endif // "Magic" signatures for various filesystems #define FAT_MAGIC 0xAA55 #define EXT2_SUPER_MAGIC 0xEF53 #define HFSPLUS_MAGIC1 0x2B48 #define HFSPLUS_MAGIC2 0x5848 #define REISERFS_SUPER_MAGIC_STRING "ReIsErFs" #define REISER2FS_SUPER_MAGIC_STRING "ReIsEr2Fs" #define REISER2FS_JR_SUPER_MAGIC_STRING "ReIsEr3Fs" #define BTRFS_SIGNATURE "_BHRfS_M" #define XFS_SIGNATURE "XFSB" #define NTFS_SIGNATURE "NTFS " // variables EFI_HANDLE SelfImageHandle; EFI_LOADED_IMAGE *SelfLoadedImage; EFI_FILE *SelfRootDir; EFI_FILE *SelfDir; CHAR16 *SelfDirPath; REFIT_VOLUME *SelfVolume = NULL; REFIT_VOLUME **Volumes = NULL; UINTN VolumesCount = 0; extern GPT_DATA *gPartitions; extern EFI_GUID RefindGuid; // Maximum size for disk sectors #define SECTOR_SIZE 4096 // Number of bytes to read from a partition to determine its filesystem type // and identify its boot loader, and hence probable BIOS-mode OS installation #define SAMPLE_SIZE 69632 /* 68 KiB -- ReiserFS superblock begins at 64 KiB */ // // Pathname manipulations // // Converts forward slashes to backslashes, removes duplicate slashes, and // removes slashes from both the start and end of the pathname. // Necessary because some (buggy?) EFI implementations produce "\/" strings // in pathnames, because some user inputs can produce duplicate directory // separators, and because we want consistent start and end slashes for // directory comparisons. A special case: If the PathName refers to root, // but is non-empty, return "\", since some firmware implementations flake // out if this isn't present. VOID CleanUpPathNameSlashes(IN OUT CHAR16 *PathName) { UINTN Source = 0, Dest = 0; if ((PathName == NULL) || (PathName[0] == '\0')) return; while (PathName[Source] != '\0') { if ((PathName[Source] == L'/') || (PathName[Source] == L'\\')) { if (Dest == 0) { // Skip slash if to first position Source++; } else { PathName[Dest] = L'\\'; do { // Skip subsequent slashes Source++; } while ((PathName[Source] == L'/') || (PathName[Source] == L'\\')); Dest++; } // if/else } else { // Regular character; copy it straight.... PathName[Dest] = PathName[Source]; Source++; Dest++; } // if/else } // while() if ((Dest > 0) && (PathName[Dest - 1] == L'\\')) Dest--; PathName[Dest] = L'\0'; if (PathName[0] == L'\0') { PathName[0] = L'\\'; PathName[1] = L'\0'; } } // CleanUpPathNameSlashes() // Splits an EFI device path into device and filename components. For instance, if InString is // PciRoot(0x0)/Pci(0x1f,0x2)/Ata(Secondary,Master,0x0)/HD(2,GPT,8314ae90-ada3-48e9-9c3b-09a88f80d921,0x96028,0xfa000)/\bzImage-3.5.1.efi, // this function will truncate that input to // PciRoot(0x0)/Pci(0x1f,0x2)/Ata(Secondary,Master,0x0)/HD(2,GPT,8314ae90-ada3-48e9-9c3b-09a88f80d921,0x96028,0xfa000) // and return bzImage-3.5.1.efi as its return value. // It does this by searching for the last ")" character in InString, copying everything // after that string (after some cleanup) as the return value, and truncating the original // input value. // If InString contains no ")" character, this function leaves the original input string // unmodified and also returns that string. If InString is NULL, this function returns NULL. static CHAR16* SplitDeviceString(IN OUT CHAR16 *InString) { INTN i; CHAR16 *FileName = NULL; BOOLEAN Found = FALSE; if (InString != NULL) { i = StrLen(InString) - 1; while ((i >= 0) && (!Found)) { if (InString[i] == L')') { Found = TRUE; FileName = StrDuplicate(&InString[i + 1]); CleanUpPathNameSlashes(FileName); InString[i + 1] = '\0'; } // if i--; } // while if (FileName == NULL) FileName = StrDuplicate(InString); } // if return FileName; } // static CHAR16* SplitDeviceString() // // Library initialization and de-initialization // static EFI_STATUS FinishInitRefitLib(VOID) { EFI_STATUS Status; if (SelfRootDir == NULL) { SelfRootDir = LibOpenRoot(SelfLoadedImage->DeviceHandle); if (SelfRootDir == NULL) { CheckError(EFI_LOAD_ERROR, L"while (re)opening our installation volume"); return EFI_LOAD_ERROR; } } Status = refit_call5_wrapper(SelfRootDir->Open, SelfRootDir, &SelfDir, SelfDirPath, EFI_FILE_MODE_READ, 0); if (CheckFatalError(Status, L"while opening our installation directory")) return EFI_LOAD_ERROR; return EFI_SUCCESS; } EFI_STATUS InitRefitLib(IN EFI_HANDLE ImageHandle) { EFI_STATUS Status; CHAR16 *DevicePathAsString, *Temp = NULL; SelfImageHandle = ImageHandle; Status = refit_call3_wrapper(BS->HandleProtocol, SelfImageHandle, &LoadedImageProtocol, (VOID **) &SelfLoadedImage); if (CheckFatalError(Status, L"while getting a LoadedImageProtocol handle")) return EFI_LOAD_ERROR; // find the current directory DevicePathAsString = DevicePathToStr(SelfLoadedImage->FilePath); GlobalConfig.SelfDevicePath = FileDevicePath(SelfLoadedImage->DeviceHandle, DevicePathAsString); CleanUpPathNameSlashes(DevicePathAsString); MyFreePool(SelfDirPath); Temp = FindPath(DevicePathAsString); SelfDirPath = SplitDeviceString(Temp); MyFreePool(DevicePathAsString); MyFreePool(Temp); return FinishInitRefitLib(); } static VOID UninitVolumes(VOID) { REFIT_VOLUME *Volume; UINTN VolumeIndex; for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) { Volume = Volumes[VolumeIndex]; if (Volume->RootDir != NULL) { refit_call1_wrapper(Volume->RootDir->Close, Volume->RootDir); Volume->RootDir = NULL; } Volume->DeviceHandle = NULL; Volume->BlockIO = NULL; Volume->WholeDiskBlockIO = NULL; } } /* VOID UninitVolumes() */ VOID ReinitVolumes(VOID) { EFI_STATUS Status; REFIT_VOLUME *Volume; UINTN VolumeIndex; EFI_DEVICE_PATH *RemainingDevicePath; EFI_HANDLE DeviceHandle, WholeDiskHandle; for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) { Volume = Volumes[VolumeIndex]; if (Volume->DevicePath != NULL) { // get the handle for that path RemainingDevicePath = Volume->DevicePath; Status = refit_call3_wrapper(BS->LocateDevicePath, &BlockIoProtocol, &RemainingDevicePath, &DeviceHandle); if (!EFI_ERROR(Status)) { Volume->DeviceHandle = DeviceHandle; // get the root directory Volume->RootDir = LibOpenRoot(Volume->DeviceHandle); } else CheckError(Status, L"from LocateDevicePath"); } if (Volume->WholeDiskDevicePath != NULL) { // get the handle for that path RemainingDevicePath = Volume->WholeDiskDevicePath; Status = refit_call3_wrapper(BS->LocateDevicePath, &BlockIoProtocol, &RemainingDevicePath, &WholeDiskHandle); if (!EFI_ERROR(Status)) { // get the BlockIO protocol Status = refit_call3_wrapper(BS->HandleProtocol, WholeDiskHandle, &BlockIoProtocol, (VOID **) &Volume->WholeDiskBlockIO); if (EFI_ERROR(Status)) { Volume->WholeDiskBlockIO = NULL; CheckError(Status, L"from HandleProtocol"); } } else CheckError(Status, L"from LocateDevicePath"); } } } /* VOID ReinitVolumes(VOID) */ // called before running external programs to close open file handles VOID UninitRefitLib(VOID) { // This piece of code was made to correspond to weirdness in ReinitRefitLib(). // See the comment on it there. if(SelfRootDir == SelfVolume->RootDir) SelfRootDir=0; UninitVolumes(); if (SelfDir != NULL) { refit_call1_wrapper(SelfDir->Close, SelfDir); SelfDir = NULL; } if (SelfRootDir != NULL) { refit_call1_wrapper(SelfRootDir->Close, SelfRootDir); SelfRootDir = NULL; } } /* VOID UninitRefitLib() */ // called after running external programs to re-open file handles EFI_STATUS ReinitRefitLib(VOID) { ReinitVolumes(); if ((ST->Hdr.Revision >> 16) == 1) { // Below two lines were in rEFIt, but seem to cause system crashes or // reboots when launching OSes after returning from programs on most // systems. OTOH, my Mac Mini produces errors about "(re)opening our // installation volume" (see the next function) when returning from // programs when these two lines are removed, and it often crashes // when returning from a program or when launching a second program // with these lines removed. Therefore, the preceding if() statement // executes these lines only on EFIs with a major version number of 1 // (which Macs have) and not with 2 (which UEFI PCs have). My selection // of hardware on which to test is limited, though, so this may be the // wrong test, or there may be a better way to fix this problem. // TODO: Figure out cause of above weirdness and fix it more // reliably! if (SelfVolume != NULL && SelfVolume->RootDir != NULL) SelfRootDir = SelfVolume->RootDir; } // if return FinishInitRefitLib(); } // // EFI variable read and write functions // // Retrieve a raw EFI variable, either from NVRAM or from a disk file under // rEFInd's "vars" subdirectory, depending on GlobalConfig.UseNvram. // Returns EFI status EFI_STATUS EfivarGetRaw(EFI_GUID *vendor, CHAR16 *name, CHAR8 **buffer, UINTN *size) { UINT8 *buf = NULL; UINTN l; EFI_STATUS Status; EFI_FILE *VarsDir = NULL; if ((GlobalConfig.UseNvram == FALSE) && GuidsAreEqual(vendor, &RefindGuid)) { Status = refit_call5_wrapper(SelfDir->Open, SelfDir, &VarsDir, L"vars", EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE, EFI_FILE_DIRECTORY); if (Status == EFI_SUCCESS) Status = egLoadFile(VarsDir, name, &buf, size); } else { l = sizeof(CHAR16 *) * EFI_MAXIMUM_VARIABLE_SIZE; buf = AllocatePool(l); if (!buf) return EFI_OUT_OF_RESOURCES; Status = refit_call5_wrapper(RT->GetVariable, name, vendor, NULL, &l, buf); } if (EFI_ERROR(Status) == EFI_SUCCESS) { *buffer = (CHAR8*) buf; if (size) *size = l; } else MyFreePool(buf); return Status; } // EFI_STATUS EfivarGetRaw() // Set an EFI variable, either to NVRAM or to a disk file under rEFInd's // "vars" subdirectory, depending on GlobalConfig.UseNvram. // Returns EFI status EFI_STATUS EfivarSetRaw(EFI_GUID *vendor, CHAR16 *name, CHAR8 *buf, UINTN size, BOOLEAN persistent) { UINT32 flags; EFI_FILE *VarsDir = NULL; EFI_STATUS Status; if ((GlobalConfig.UseNvram == FALSE) && GuidsAreEqual(vendor, &RefindGuid)) { Status = refit_call5_wrapper(SelfDir->Open, SelfDir, &VarsDir, L"vars", EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, EFI_FILE_DIRECTORY); if (Status == EFI_SUCCESS) { Status = egSaveFile(VarsDir, name, (UINT8 *) buf, size); } } else { flags = EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS; if (persistent) flags |= EFI_VARIABLE_NON_VOLATILE; Status = refit_call5_wrapper(RT->SetVariable, name, vendor, flags, size, buf); } return Status; } // EFI_STATUS EfivarSetRaw() // // list functions // VOID AddListElement(IN OUT VOID ***ListPtr, IN OUT UINTN *ElementCount, IN VOID *NewElement) { UINTN AllocateCount; if ((*ElementCount & 15) == 0) { AllocateCount = *ElementCount + 16; if (*ElementCount == 0) *ListPtr = AllocatePool(sizeof(VOID *) * AllocateCount); else *ListPtr = EfiReallocatePool(*ListPtr, sizeof(VOID *) * (*ElementCount), sizeof(VOID *) * AllocateCount); } (*ListPtr)[*ElementCount] = NewElement; (*ElementCount)++; } /* VOID AddListElement() */ VOID FreeList(IN OUT VOID ***ListPtr, IN OUT UINTN *ElementCount) { UINTN i; if ((*ElementCount > 0) && (**ListPtr != NULL)) { for (i = 0; i < *ElementCount; i++) { // TODO: call a user-provided routine for each element here MyFreePool((*ListPtr)[i]); } MyFreePool(*ListPtr); } } // VOID FreeList() // // volume functions // // Return a pointer to a string containing a filesystem type name. If the // filesystem type is unknown, a blank (but non-null) string is returned. // The returned variable is a constant that should NOT be freed. static CHAR16 *FSTypeName(IN UINT32 TypeCode) { CHAR16 *retval = NULL; switch (TypeCode) { case FS_TYPE_WHOLEDISK: retval = L" whole disk"; break; case FS_TYPE_FAT: retval = L" FAT"; break; case FS_TYPE_HFSPLUS: retval = L" HFS+"; break; case FS_TYPE_EXT2: retval = L" ext2"; break; case FS_TYPE_EXT3: retval = L" ext3"; break; case FS_TYPE_EXT4: retval = L" ext4"; break; case FS_TYPE_REISERFS: retval = L" ReiserFS"; break; case FS_TYPE_BTRFS: retval = L" Btrfs"; break; case FS_TYPE_XFS: retval = L" XFS"; break; case FS_TYPE_ISO9660: retval = L" ISO-9660"; break; case FS_TYPE_NTFS: retval = L" NTFS"; break; default: retval = L""; break; } // switch return retval; } // CHAR16 *FSTypeName() // Identify the filesystem type and record the filesystem's UUID/serial number, // if possible. Expects a Buffer containing the first few (normally at least // 4096) bytes of the filesystem. Sets the filesystem type code in Volume->FSType // and the UUID/serial number in Volume->VolUuid. Note that the UUID value is // recognized differently for each filesystem, and is currently supported only // for NTFS, ext2/3/4fs, and ReiserFS (and for NTFS it's really a 64-bit serial // number not a UUID or GUID). If the UUID can't be determined, it's set to 0. // Also, the UUID is just read directly into memory; it is *NOT* valid when // displayed by GuidAsString() or used in other GUID/UUID-manipulating // functions. (As I write, it's being used merely to detect partitions that are // part of a RAID 1 array.) static VOID SetFilesystemData(IN UINT8 *Buffer, IN UINTN BufferSize, IN OUT REFIT_VOLUME *Volume) { UINT32 *Ext2Incompat, *Ext2Compat; UINT16 *Magic16; char *MagicString; EFI_FILE *RootDir; if ((Buffer != NULL) && (Volume != NULL)) { SetMem(&(Volume->VolUuid), sizeof(EFI_GUID), 0); Volume->FSType = FS_TYPE_UNKNOWN; if (BufferSize >= (1024 + 100)) { Magic16 = (UINT16*) (Buffer + 1024 + 56); if (*Magic16 == EXT2_SUPER_MAGIC) { // ext2/3/4 Ext2Compat = (UINT32*) (Buffer + 1024 + 92); Ext2Incompat = (UINT32*) (Buffer + 1024 + 96); if ((*Ext2Incompat & 0x0040) || (*Ext2Incompat & 0x0200)) { // check for extents or flex_bg Volume->FSType = FS_TYPE_EXT4; } else if (*Ext2Compat & 0x0004) { // check for journal Volume->FSType = FS_TYPE_EXT3; } else { // none of these features; presume it's ext2... Volume->FSType = FS_TYPE_EXT2; } CopyMem(&(Volume->VolUuid), Buffer + 1024 + 120, sizeof(EFI_GUID)); return; } } // search for ext2/3/4 magic if (BufferSize >= (65536 + 100)) { MagicString = (char*) (Buffer + 65536 + 52); if ((CompareMem(MagicString, REISERFS_SUPER_MAGIC_STRING, 8) == 0) || (CompareMem(MagicString, REISER2FS_SUPER_MAGIC_STRING, 9) == 0) || (CompareMem(MagicString, REISER2FS_JR_SUPER_MAGIC_STRING, 9) == 0)) { Volume->FSType = FS_TYPE_REISERFS; CopyMem(&(Volume->VolUuid), Buffer + 65536 + 84, sizeof(EFI_GUID)); return; } // if } // search for ReiserFS magic if (BufferSize >= (65536 + 64 + 8)) { MagicString = (char*) (Buffer + 65536 + 64); if (CompareMem(MagicString, BTRFS_SIGNATURE, 8) == 0) { Volume->FSType = FS_TYPE_BTRFS; return; } // if } // search for Btrfs magic if (BufferSize >= 512) { MagicString = (char*) Buffer; if (CompareMem(MagicString, XFS_SIGNATURE, 4) == 0) { Volume->FSType = FS_TYPE_XFS; return; } } // search for XFS magic if (BufferSize >= (1024 + 2)) { Magic16 = (UINT16*) (Buffer + 1024); if ((*Magic16 == HFSPLUS_MAGIC1) || (*Magic16 == HFSPLUS_MAGIC2)) { Volume->FSType = FS_TYPE_HFSPLUS; return; } } // search for HFS+ magic if (BufferSize >= 512) { // Search for NTFS, FAT, and MBR/EBR. // These all have 0xAA55 at the end of the first sector, but FAT and // MBR/EBR are not easily distinguished. Thus, we first look for NTFS // "magic"; then check to see if the volume can be mounted, thus // relying on the EFI's built-in FAT driver to identify FAT; and then // check to see if the "volume" is in fact a whole-disk device. Magic16 = (UINT16*) (Buffer + 510); if (*Magic16 == FAT_MAGIC) { MagicString = (char*) (Buffer + 3); if (CompareMem(MagicString, NTFS_SIGNATURE, 8) == 0) { Volume->FSType = FS_TYPE_NTFS; CopyMem(&(Volume->VolUuid), Buffer + 0x48, sizeof(UINT64)); } else { RootDir = LibOpenRoot(Volume->DeviceHandle); if (RootDir != NULL) { Volume->FSType = FS_TYPE_FAT; } else if (!Volume->BlockIO->Media->LogicalPartition) { Volume->FSType = FS_TYPE_WHOLEDISK; } // if/elseif/else } // if/else return; } // if } // search for FAT and NTFS magic // If no other filesystem is identified and block size is right, assume // it's ISO-9660.... if (Volume->BlockIO->Media->BlockSize == 2048) { Volume->FSType = FS_TYPE_ISO9660; return; } } // if ((Buffer != NULL) && (Volume != NULL)) } // UINT32 SetFilesystemData() static VOID ScanVolumeBootcode(REFIT_VOLUME *Volume, BOOLEAN *Bootable) { EFI_STATUS Status; UINT8 Buffer[SAMPLE_SIZE]; UINTN i; MBR_PARTITION_INFO *MbrTable; BOOLEAN MbrTableFound = FALSE; Volume->HasBootCode = FALSE; Volume->OSIconName = NULL; Volume->OSName = NULL; *Bootable = FALSE; if (Volume->BlockIO == NULL) return; if (Volume->BlockIO->Media->BlockSize > SAMPLE_SIZE) return; // our buffer is too small... // look at the boot sector (this is used for both hard disks and El Torito images!) Status = refit_call5_wrapper(Volume->BlockIO->ReadBlocks, Volume->BlockIO, Volume->BlockIO->Media->MediaId, Volume->BlockIOOffset, SAMPLE_SIZE, Buffer); if (!EFI_ERROR(Status)) { SetFilesystemData(Buffer, SAMPLE_SIZE, Volume); } if ((Status == EFI_SUCCESS) && (GlobalConfig.LegacyType == LEGACY_TYPE_MAC)) { if ((*((UINT16 *)(Buffer + 510)) == 0xaa55 && Buffer[0] != 0) && (FindMem(Buffer, 512, "EXFAT", 5) == -1)) { *Bootable = TRUE; Volume->HasBootCode = TRUE; } // detect specific boot codes if (CompareMem(Buffer + 2, "LILO", 4) == 0 || CompareMem(Buffer + 6, "LILO", 4) == 0 || CompareMem(Buffer + 3, "SYSLINUX", 8) == 0 || FindMem(Buffer, SECTOR_SIZE, "ISOLINUX", 8) >= 0) { Volume->HasBootCode = TRUE; Volume->OSIconName = L"linux"; Volume->OSName = L"Linux (Legacy)"; } else if (FindMem(Buffer, 512, "Geom\0Hard Disk\0Read\0 Error", 26) >= 0) { // GRUB Volume->HasBootCode = TRUE; Volume->OSIconName = L"grub,linux"; Volume->OSName = L"Linux (Legacy)"; } else if ((*((UINT32 *)(Buffer + 502)) == 0 && *((UINT32 *)(Buffer + 506)) == 50000 && *((UINT16 *)(Buffer + 510)) == 0xaa55) || FindMem(Buffer, SECTOR_SIZE, "Starting the BTX loader", 23) >= 0) { Volume->HasBootCode = TRUE; Volume->OSIconName = L"freebsd"; Volume->OSName = L"FreeBSD (Legacy)"; // If more differentiation needed, also search for // "Invalid partition table" &/or "Missing boot loader". } else if ((*((UINT16 *)(Buffer + 510)) == 0xaa55) && (FindMem(Buffer, SECTOR_SIZE, "Boot loader too large", 21) >= 0) && (FindMem(Buffer, SECTOR_SIZE, "I/O error loading boot loader", 29) >= 0)) { Volume->HasBootCode = TRUE; Volume->OSIconName = L"freebsd"; Volume->OSName = L"FreeBSD (Legacy)"; } else if (FindMem(Buffer, 512, "!Loading", 8) >= 0 || FindMem(Buffer, SECTOR_SIZE, "/cdboot\0/CDBOOT\0", 16) >= 0) { Volume->HasBootCode = TRUE; Volume->OSIconName = L"openbsd"; Volume->OSName = L"OpenBSD (Legacy)"; } else if (FindMem(Buffer, 512, "Not a bootxx image", 18) >= 0 || *((UINT32 *)(Buffer + 1028)) == 0x7886b6d1) { Volume->HasBootCode = TRUE; Volume->OSIconName = L"netbsd"; Volume->OSName = L"NetBSD (Legacy)"; // Windows NT/200x/XP } else if (FindMem(Buffer, SECTOR_SIZE, "NTLDR", 5) >= 0) { Volume->HasBootCode = TRUE; Volume->OSIconName = L"win"; Volume->OSName = L"Windows (Legacy)"; // Windows Vista/7/8 } else if (FindMem(Buffer, SECTOR_SIZE, "BOOTMGR", 7) >= 0) { Volume->HasBootCode = TRUE; Volume->OSIconName = L"win8,win"; Volume->OSName = L"Windows (Legacy)"; } else if (FindMem(Buffer, 512, "CPUBOOT SYS", 11) >= 0 || FindMem(Buffer, 512, "KERNEL SYS", 11) >= 0) { Volume->HasBootCode = TRUE; Volume->OSIconName = L"freedos"; Volume->OSName = L"FreeDOS (Legacy)"; } else if (FindMem(Buffer, 512, "OS2LDR", 6) >= 0 || FindMem(Buffer, 512, "OS2BOOT", 7) >= 0) { Volume->HasBootCode = TRUE; Volume->OSIconName = L"ecomstation"; Volume->OSName = L"eComStation (Legacy)"; } else if (FindMem(Buffer, 512, "Be Boot Loader", 14) >= 0) { Volume->HasBootCode = TRUE; Volume->OSIconName = L"beos"; Volume->OSName = L"BeOS (Legacy)"; } else if (FindMem(Buffer, 512, "yT Boot Loader", 14) >= 0) { Volume->HasBootCode = TRUE; Volume->OSIconName = L"zeta,beos"; Volume->OSName = L"ZETA (Legacy)"; } else if (FindMem(Buffer, 512, "\x04" "beos\x06" "system\x05" "zbeos", 18) >= 0 || FindMem(Buffer, 512, "\x06" "system\x0c" "haiku_loader", 20) >= 0) { Volume->HasBootCode = TRUE; Volume->OSIconName = L"haiku,beos"; Volume->OSName = L"Haiku (Legacy)"; } // NOTE: If you add an operating system with a name that starts with 'W' or 'L', you // need to fix AddLegacyEntry in refind/legacy.c. #if REFIT_DEBUG > 0 Print(L" Result of bootcode detection: %s %s (%s)\n", Volume->HasBootCode ? L"bootable" : L"non-bootable", Volume->OSName, Volume->OSIconName); #endif // dummy FAT boot sector (created by OS X's newfs_msdos) if (FindMem(Buffer, 512, "Non-system disk", 15) >= 0) Volume->HasBootCode = FALSE; // dummy FAT boot sector (created by Linux's mkdosfs) if (FindMem(Buffer, 512, "This is not a bootable disk", 27) >= 0) Volume->HasBootCode = FALSE; // dummy FAT boot sector (created by Windows) if (FindMem(Buffer, 512, "Press any key to restart", 24) >= 0) Volume->HasBootCode = FALSE; // check for MBR partition table if (*((UINT16 *)(Buffer + 510)) == 0xaa55) { MbrTable = (MBR_PARTITION_INFO *)(Buffer + 446); for (i = 0; i < 4; i++) if (MbrTable[i].StartLBA && MbrTable[i].Size) MbrTableFound = TRUE; for (i = 0; i < 4; i++) if (MbrTable[i].Flags != 0x00 && MbrTable[i].Flags != 0x80) MbrTableFound = FALSE; if (MbrTableFound) { Volume->MbrPartitionTable = AllocatePool(4 * 16); CopyMem(Volume->MbrPartitionTable, MbrTable, 4 * 16); } } } else { #if REFIT_DEBUG > 0 CheckError(Status, L"while reading boot sector"); #endif } } /* VOID ScanVolumeBootcode() */ // Set default volume badge icon based on /.VolumeBadge.{icns|png} file or disk kind VOID SetVolumeBadgeIcon(REFIT_VOLUME *Volume) { if (GlobalConfig.HideUIFlags & HIDEUI_FLAG_BADGES) return; if (Volume->VolBadgeImage == NULL) { Volume->VolBadgeImage = egLoadIconAnyType(Volume->RootDir, L"", L".VolumeBadge", GlobalConfig.IconSizes[ICON_SIZE_BADGE]); } if (Volume->VolBadgeImage == NULL) { switch (Volume->DiskKind) { case DISK_KIND_INTERNAL: Volume->VolBadgeImage = BuiltinIcon(BUILTIN_ICON_VOL_INTERNAL); break; case DISK_KIND_EXTERNAL: Volume->VolBadgeImage = BuiltinIcon(BUILTIN_ICON_VOL_EXTERNAL); break; case DISK_KIND_OPTICAL: Volume->VolBadgeImage = BuiltinIcon(BUILTIN_ICON_VOL_OPTICAL); break; case DISK_KIND_NET: Volume->VolBadgeImage = BuiltinIcon(BUILTIN_ICON_VOL_NET); break; } // switch() } } // VOID SetVolumeBadgeIcon() // Return a string representing the input size in IEEE-1541 units. // The calling function is responsible for freeing the allocated memory. static CHAR16 *SizeInIEEEUnits(UINT64 SizeInBytes) { UINT64 SizeInIeee; UINTN Index = 0, NumPrefixes; CHAR16 *Units, *Prefixes = L" KMGTPEZ"; CHAR16 *TheValue; TheValue = AllocateZeroPool(sizeof(CHAR16) * 256); if (TheValue != NULL) { NumPrefixes = StrLen(Prefixes); SizeInIeee = SizeInBytes; while ((SizeInIeee > 1024) && (Index < (NumPrefixes - 1))) { Index++; SizeInIeee /= 1024; } // while if (Prefixes[Index] == ' ') { Units = StrDuplicate(L"-byte"); } else { Units = StrDuplicate(L" iB"); Units[1] = Prefixes[Index]; } // if/else SPrint(TheValue, 255, L"%ld%s", SizeInIeee, Units); } // if return TheValue; } // CHAR16 *SizeInIEEEUnits() // Return a name for the volume. Ideally this should be the label for the // filesystem or volume, but this function falls back to describing the // filesystem by size (200 MiB, etc.) and/or type (ext2, HFS+, etc.), if // this information can be extracted. // The calling function is responsible for freeing the memory allocated // for the name string. static CHAR16 *GetVolumeName(REFIT_VOLUME *Volume) { EFI_FILE_SYSTEM_INFO *FileSystemInfoPtr = NULL; CHAR16 *FoundName = NULL; CHAR16 *SISize, *TypeName; if (Volume->RootDir != NULL) { FileSystemInfoPtr = LibFileSystemInfo(Volume->RootDir); } if ((FileSystemInfoPtr != NULL) && (FileSystemInfoPtr->VolumeLabel != NULL) && (StrLen(FileSystemInfoPtr->VolumeLabel) > 0)) { FoundName = StrDuplicate(FileSystemInfoPtr->VolumeLabel); } // If no filesystem name, try to use the partition name.... if ((FoundName == NULL) && (Volume->PartName != NULL) && (StrLen(Volume->PartName) > 0) && !IsIn(Volume->PartName, IGNORE_PARTITION_NAMES)) { FoundName = StrDuplicate(Volume->PartName); } // if use partition name // No filesystem or acceptable partition name, so use fs type and size if ((FoundName == NULL) && (FileSystemInfoPtr != NULL)) { FoundName = AllocateZeroPool(sizeof(CHAR16) * 256); if (FoundName != NULL) { SISize = SizeInIEEEUnits(FileSystemInfoPtr->VolumeSize); SPrint(FoundName, 255, L"%s%s volume", SISize, FSTypeName(Volume->FSType)); MyFreePool(SISize); } // if allocated memory OK } // if (FoundName == NULL) MyFreePool(FileSystemInfoPtr); if (FoundName == NULL) { FoundName = AllocateZeroPool(sizeof(CHAR16) * 256); if (FoundName != NULL) { TypeName = FSTypeName(Volume->FSType); // NOTE: Don't free TypeName; function returns constant if (StrLen(TypeName) > 0) SPrint(FoundName, 255, L"%s volume", TypeName); else SPrint(FoundName, 255, L"unknown volume"); } // if allocated memory OK } // if // TODO: Above could be improved/extended, in case filesystem name is not found, // such as: // - use or add disk/partition number (e.g., "(hd0,2)") // Desperate fallback name.... if (FoundName == NULL) { FoundName = StrDuplicate(L"unknown volume"); } return FoundName; } // static CHAR16 *GetVolumeName() // Determine the unique GUID, type code GUID, and name of the volume and store them. static VOID SetPartGuidAndName(REFIT_VOLUME *Volume, EFI_DEVICE_PATH_PROTOCOL *DevicePath) { HARDDRIVE_DEVICE_PATH *HdDevicePath; GPT_ENTRY *PartInfo; if ((Volume == NULL) || (DevicePath == NULL)) return; if ((DevicePath->Type == MEDIA_DEVICE_PATH) && (DevicePath->SubType == MEDIA_HARDDRIVE_DP)) { HdDevicePath = (HARDDRIVE_DEVICE_PATH*) DevicePath; if (HdDevicePath->SignatureType == SIGNATURE_TYPE_GUID) { Volume->PartGuid = *((EFI_GUID*) HdDevicePath->Signature); PartInfo = FindPartWithGuid(&(Volume->PartGuid)); if (PartInfo) { Volume->PartName = StrDuplicate(PartInfo->name); CopyMem(&(Volume->PartTypeGuid), PartInfo->type_guid, sizeof(EFI_GUID)); if (GuidsAreEqual(&(Volume->PartTypeGuid), &gFreedesktopRootGuid) && ((PartInfo->attributes & GPT_NO_AUTOMOUNT) == 0)) { GlobalConfig.DiscoveredRoot = Volume; } // if (GUIDs match && automounting OK) Volume->IsMarkedReadOnly = ((PartInfo->attributes & GPT_READ_ONLY) > 0); } // if (PartInfo exists) } else { // TODO: Better to assign a random GUID to MBR partitions, but I couldn't // find an EFI function to do this. The below GUID is just one that I // generated in Linux. Volume->PartGuid = StringAsGuid(L"92a6c61f-7130-49b9-b05c-8d7e7b039127"); } // if/else (GPT disk) } // if (disk device) } // VOID SetPartGuid() // Return TRUE if NTFS boot files are found or if Volume is unreadable, // FALSE otherwise. The idea is to weed out non-boot NTFS volumes from // BIOS/legacy boot list on Macs. We can't assume NTFS will be readable, // so return TRUE if it's unreadable; but if it IS readable, return // TRUE only if Windows boot files are found. static BOOLEAN HasWindowsBiosBootFiles(REFIT_VOLUME *Volume) { BOOLEAN FilesFound = TRUE; if (Volume->RootDir != NULL) { FilesFound = FileExists(Volume->RootDir, L"NTLDR") || // Windows NT/200x/XP boot file FileExists(Volume->RootDir, L"bootmgr"); // Windows Vista/7/8 boot file } // if return FilesFound; } // static VOID HasWindowsBiosBootFiles() VOID ScanVolume(REFIT_VOLUME *Volume) { EFI_STATUS Status; EFI_DEVICE_PATH *DevicePath, *NextDevicePath; EFI_DEVICE_PATH *DiskDevicePath, *RemainingDevicePath; EFI_HANDLE WholeDiskHandle; UINTN PartialLength; BOOLEAN Bootable; // get device path Volume->DevicePath = DuplicateDevicePath(DevicePathFromHandle(Volume->DeviceHandle)); #if REFIT_DEBUG > 0 if (Volume->DevicePath != NULL) { Print(L"* %s\n", DevicePathToStr(Volume->DevicePath)); #if REFIT_DEBUG >= 2 DumpHex(1, 0, DevicePathSize(Volume->DevicePath), Volume->DevicePath); #endif } #endif Volume->DiskKind = DISK_KIND_INTERNAL; // default // get block i/o Status = refit_call3_wrapper(BS->HandleProtocol, Volume->DeviceHandle, &BlockIoProtocol, (VOID **) &(Volume->BlockIO)); if (EFI_ERROR(Status)) { Volume->BlockIO = NULL; Print(L"Warning: Can't get BlockIO protocol.\n"); } else { if (Volume->BlockIO->Media->BlockSize == 2048) Volume->DiskKind = DISK_KIND_OPTICAL; } // scan for bootcode and MBR table Bootable = FALSE; ScanVolumeBootcode(Volume, &Bootable); // detect device type DevicePath = Volume->DevicePath; while (DevicePath != NULL && !IsDevicePathEndType(DevicePath)) { NextDevicePath = NextDevicePathNode(DevicePath); if (DevicePathType(DevicePath) == MEDIA_DEVICE_PATH) { SetPartGuidAndName(Volume, DevicePath); } if (DevicePathType(DevicePath) == MESSAGING_DEVICE_PATH && (DevicePathSubType(DevicePath) == MSG_USB_DP || DevicePathSubType(DevicePath) == MSG_USB_CLASS_DP || DevicePathSubType(DevicePath) == MSG_1394_DP || DevicePathSubType(DevicePath) == MSG_FIBRECHANNEL_DP)) Volume->DiskKind = DISK_KIND_EXTERNAL; // USB/FireWire/FC device -> external if (DevicePathType(DevicePath) == MEDIA_DEVICE_PATH && DevicePathSubType(DevicePath) == MEDIA_CDROM_DP) { Volume->DiskKind = DISK_KIND_OPTICAL; // El Torito entry -> optical disk Bootable = TRUE; } // if (DevicePathType(DevicePath) == MEDIA_DEVICE_PATH && DevicePathSubType(DevicePath) == MEDIA_VENDOR_DP) { // Volume->IsAppleLegacy = TRUE; // legacy BIOS device entry // // TODO: also check for Boot Camp GUID // Bootable = FALSE; // this handle's BlockIO is just an alias for the whole device // } if (DevicePathType(DevicePath) == MESSAGING_DEVICE_PATH) { // make a device path for the whole device PartialLength = (UINT8 *)NextDevicePath - (UINT8 *)(Volume->DevicePath); DiskDevicePath = (EFI_DEVICE_PATH *)AllocatePool(PartialLength + sizeof(EFI_DEVICE_PATH)); CopyMem(DiskDevicePath, Volume->DevicePath, PartialLength); CopyMem((UINT8 *)DiskDevicePath + PartialLength, EndDevicePath, sizeof(EFI_DEVICE_PATH)); // get the handle for that path RemainingDevicePath = DiskDevicePath; Status = refit_call3_wrapper(BS->LocateDevicePath, &BlockIoProtocol, &RemainingDevicePath, &WholeDiskHandle); FreePool(DiskDevicePath); if (!EFI_ERROR(Status)) { //Print(L" - original handle: %08x - disk handle: %08x\n", (UINT32)DeviceHandle, (UINT32)WholeDiskHandle); // get the device path for later Status = refit_call3_wrapper(BS->HandleProtocol, WholeDiskHandle, &DevicePathProtocol, (VOID **) &DiskDevicePath); if (!EFI_ERROR(Status)) { Volume->WholeDiskDevicePath = DuplicateDevicePath(DiskDevicePath); } // look at the BlockIO protocol Status = refit_call3_wrapper(BS->HandleProtocol, WholeDiskHandle, &BlockIoProtocol, (VOID **) &Volume->WholeDiskBlockIO); if (!EFI_ERROR(Status)) { // check the media block size if (Volume->WholeDiskBlockIO->Media->BlockSize == 2048) Volume->DiskKind = DISK_KIND_OPTICAL; } else { Volume->WholeDiskBlockIO = NULL; //CheckError(Status, L"from HandleProtocol"); } } //else // CheckError(Status, L"from LocateDevicePath"); } DevicePath = NextDevicePath; } // while if (!Bootable) { #if REFIT_DEBUG > 0 if (Volume->HasBootCode) Print(L" Volume considered non-bootable, but boot code is present\n"); #endif Volume->HasBootCode = FALSE; } // open the root directory of the volume Volume->RootDir = LibOpenRoot(Volume->DeviceHandle); Volume->VolName = GetVolumeName(Volume); if (Volume->RootDir == NULL) { Volume->IsReadable = FALSE; return; } else { Volume->IsReadable = TRUE; if ((GlobalConfig.LegacyType == LEGACY_TYPE_MAC) && (Volume->FSType == FS_TYPE_NTFS) && Volume->HasBootCode) { // VBR boot code found on NTFS, but volume is not actually bootable // unless there are actual boot file, so check for them.... Volume->HasBootCode = HasWindowsBiosBootFiles(Volume); } } // if/else } // ScanVolume() static VOID ScanExtendedPartition(REFIT_VOLUME *WholeDiskVolume, MBR_PARTITION_INFO *MbrEntry) { EFI_STATUS Status; REFIT_VOLUME *Volume; UINT32 ExtBase, ExtCurrent, NextExtCurrent; UINTN i; UINTN LogicalPartitionIndex = 4; UINT8 SectorBuffer[512]; BOOLEAN Bootable; MBR_PARTITION_INFO *EMbrTable; ExtBase = MbrEntry->StartLBA; for (ExtCurrent = ExtBase; ExtCurrent; ExtCurrent = NextExtCurrent) { // read current EMBR Status = refit_call5_wrapper(WholeDiskVolume->BlockIO->ReadBlocks, WholeDiskVolume->BlockIO, WholeDiskVolume->BlockIO->Media->MediaId, ExtCurrent, 512, SectorBuffer); if (EFI_ERROR(Status)) break; if (*((UINT16 *)(SectorBuffer + 510)) != 0xaa55) break; EMbrTable = (MBR_PARTITION_INFO *)(SectorBuffer + 446); // scan logical partitions in this EMBR NextExtCurrent = 0; for (i = 0; i < 4; i++) { if ((EMbrTable[i].Flags != 0x00 && EMbrTable[i].Flags != 0x80) || EMbrTable[i].StartLBA == 0 || EMbrTable[i].Size == 0) break; if (IS_EXTENDED_PART_TYPE(EMbrTable[i].Type)) { // set next ExtCurrent NextExtCurrent = ExtBase + EMbrTable[i].StartLBA; break; } else { // found a logical partition Volume = AllocateZeroPool(sizeof(REFIT_VOLUME)); Volume->DiskKind = WholeDiskVolume->DiskKind; Volume->IsMbrPartition = TRUE; Volume->MbrPartitionIndex = LogicalPartitionIndex++; Volume->VolName = AllocateZeroPool(256 * sizeof(UINT16)); SPrint(Volume->VolName, 255, L"Partition %d", Volume->MbrPartitionIndex + 1); Volume->BlockIO = WholeDiskVolume->BlockIO; Volume->BlockIOOffset = ExtCurrent + EMbrTable[i].StartLBA; Volume->WholeDiskBlockIO = WholeDiskVolume->BlockIO; Bootable = FALSE; ScanVolumeBootcode(Volume, &Bootable); if (!Bootable) Volume->HasBootCode = FALSE; SetVolumeBadgeIcon(Volume); AddListElement((VOID ***) &Volumes, &VolumesCount, Volume); } // if/else } // for } // for } /* VOID ScanExtendedPartition() */ VOID ScanVolumes(VOID) { EFI_STATUS Status; EFI_HANDLE *Handles; REFIT_VOLUME *Volume, *WholeDiskVolume; MBR_PARTITION_INFO *MbrTable; UINTN HandleCount = 0; UINTN HandleIndex; UINTN VolumeIndex, VolumeIndex2; UINTN PartitionIndex; UINTN SectorSum, i; UINT8 *SectorBuffer1, *SectorBuffer2; EFI_GUID *UuidList; EFI_GUID NullUuid = NULL_GUID_VALUE; MyFreePool(Volumes); Volumes = NULL; VolumesCount = 0; ForgetPartitionTables(); // get all filesystem handles Status = LibLocateHandle(ByProtocol, &BlockIoProtocol, NULL, &HandleCount, &Handles); if (Status == EFI_NOT_FOUND) { return; // no filesystems. strange, but true... } if (CheckError(Status, L"while listing all file systems")) return; UuidList = AllocateZeroPool(sizeof(EFI_GUID) * HandleCount); // first pass: collect information about all handles for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) { Volume = AllocateZeroPool(sizeof(REFIT_VOLUME)); Volume->DeviceHandle = Handles[HandleIndex]; AddPartitionTable(Volume); ScanVolume(Volume); if (UuidList) { UuidList[HandleIndex] = Volume->VolUuid; for (i = 0; i < HandleIndex; i++) { if ((CompareMem(&(Volume->VolUuid), &(UuidList[i]), sizeof(EFI_GUID)) == 0) && (CompareMem(&(Volume->VolUuid), &NullUuid, sizeof(EFI_GUID)) != 0)) { // Duplicate filesystem UUID Volume->IsReadable = FALSE; } // if } // for } // if AddListElement((VOID ***) &Volumes, &VolumesCount, Volume); if (Volume->DeviceHandle == SelfLoadedImage->DeviceHandle) SelfVolume = Volume; } MyFreePool(Handles); if (SelfVolume == NULL) Print(L"WARNING: SelfVolume not found"); // second pass: relate partitions and whole disk devices for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) { Volume = Volumes[VolumeIndex]; // check MBR partition table for extended partitions if (Volume->BlockIO != NULL && Volume->WholeDiskBlockIO != NULL && Volume->BlockIO == Volume->WholeDiskBlockIO && Volume->BlockIOOffset == 0 && Volume->MbrPartitionTable != NULL) { MbrTable = Volume->MbrPartitionTable; for (PartitionIndex = 0; PartitionIndex < 4; PartitionIndex++) { if (IS_EXTENDED_PART_TYPE(MbrTable[PartitionIndex].Type)) { ScanExtendedPartition(Volume, MbrTable + PartitionIndex); } } } // search for corresponding whole disk volume entry WholeDiskVolume = NULL; if (Volume->BlockIO != NULL && Volume->WholeDiskBlockIO != NULL && Volume->BlockIO != Volume->WholeDiskBlockIO) { for (VolumeIndex2 = 0; VolumeIndex2 < VolumesCount; VolumeIndex2++) { if (Volumes[VolumeIndex2]->BlockIO == Volume->WholeDiskBlockIO && Volumes[VolumeIndex2]->BlockIOOffset == 0) { WholeDiskVolume = Volumes[VolumeIndex2]; } } } if (WholeDiskVolume != NULL && WholeDiskVolume->MbrPartitionTable != NULL) { // check if this volume is one of the partitions in the table MbrTable = WholeDiskVolume->MbrPartitionTable; SectorBuffer1 = AllocatePool(512); SectorBuffer2 = AllocatePool(512); for (PartitionIndex = 0; PartitionIndex < 4; PartitionIndex++) { // check size if ((UINT64)(MbrTable[PartitionIndex].Size) != Volume->BlockIO->Media->LastBlock + 1) continue; // compare boot sector read through offset vs. directly Status = refit_call5_wrapper(Volume->BlockIO->ReadBlocks, Volume->BlockIO, Volume->BlockIO->Media->MediaId, Volume->BlockIOOffset, 512, SectorBuffer1); if (EFI_ERROR(Status)) break; Status = refit_call5_wrapper(Volume->WholeDiskBlockIO->ReadBlocks, Volume->WholeDiskBlockIO, Volume->WholeDiskBlockIO->Media->MediaId, MbrTable[PartitionIndex].StartLBA, 512, SectorBuffer2); if (EFI_ERROR(Status)) break; if (CompareMem(SectorBuffer1, SectorBuffer2, 512) != 0) continue; SectorSum = 0; for (i = 0; i < 512; i++) SectorSum += SectorBuffer1[i]; if (SectorSum < 1000) continue; // TODO: mark entry as non-bootable if it is an extended partition // now we're reasonably sure the association is correct... Volume->IsMbrPartition = TRUE; Volume->MbrPartitionIndex = PartitionIndex; if (Volume->VolName == NULL) { Volume->VolName = AllocateZeroPool(sizeof(CHAR16) * 256); SPrint(Volume->VolName, 255, L"Partition %d", PartitionIndex + 1); } break; } MyFreePool(SectorBuffer1); MyFreePool(SectorBuffer2); } } // for } /* VOID ScanVolumes() */ VOID SetVolumeIcons(VOID) { UINTN VolumeIndex; REFIT_VOLUME *Volume; for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) { Volume = Volumes[VolumeIndex]; // Set volume icon based on .VolumeBadge icon or disk kind SetVolumeBadgeIcon(Volume); if (Volumes[VolumeIndex]->DiskKind == DISK_KIND_INTERNAL) { // get custom volume icons if present if (!Volume->VolIconImage) { Volume->VolIconImage = egLoadIconAnyType(Volume->RootDir, L"", L".VolumeIcon", GlobalConfig.IconSizes[ICON_SIZE_BIG]); } } } // for } // VOID SetVolumeIcons() // // file and dir functions // BOOLEAN FileExists(IN EFI_FILE *BaseDir, IN CHAR16 *RelativePath) { EFI_STATUS Status; EFI_FILE_HANDLE TestFile; if (BaseDir != NULL) { Status = refit_call5_wrapper(BaseDir->Open, BaseDir, &TestFile, RelativePath, EFI_FILE_MODE_READ, 0); if (Status == EFI_SUCCESS) { refit_call1_wrapper(TestFile->Close, TestFile); return TRUE; } } return FALSE; } EFI_STATUS DirNextEntry(IN EFI_FILE *Directory, IN OUT EFI_FILE_INFO **DirEntry, IN UINTN FilterMode) { EFI_STATUS Status; VOID *Buffer; UINTN LastBufferSize, BufferSize; INTN IterCount; for (;;) { // free pointer from last call if (*DirEntry != NULL) { FreePool(*DirEntry); *DirEntry = NULL; } // read next directory entry LastBufferSize = BufferSize = 256; Buffer = AllocatePool(BufferSize); for (IterCount = 0; ; IterCount++) { Status = refit_call3_wrapper(Directory->Read, Directory, &BufferSize, Buffer); if (Status != EFI_BUFFER_TOO_SMALL || IterCount >= 4) break; if (BufferSize <= LastBufferSize) { Print(L"FS Driver requests bad buffer size %d (was %d), using %d instead\n", BufferSize, LastBufferSize, LastBufferSize * 2); BufferSize = LastBufferSize * 2; #if REFIT_DEBUG > 0 } else { Print(L"Reallocating buffer from %d to %d\n", LastBufferSize, BufferSize); #endif } Buffer = EfiReallocatePool(Buffer, LastBufferSize, BufferSize); LastBufferSize = BufferSize; } if (EFI_ERROR(Status)) { MyFreePool(Buffer); Buffer = NULL; break; } // check for end of listing if (BufferSize == 0) { // end of directory listing MyFreePool(Buffer); Buffer = NULL; break; } // entry is ready to be returned *DirEntry = (EFI_FILE_INFO *)Buffer; // filter results if (FilterMode == 1) { // only return directories if (((*DirEntry)->Attribute & EFI_FILE_DIRECTORY)) break; } else if (FilterMode == 2) { // only return files if (((*DirEntry)->Attribute & EFI_FILE_DIRECTORY) == 0) break; } else // no filter or unknown filter -> return everything break; } return Status; } VOID DirIterOpen(IN EFI_FILE *BaseDir, IN CHAR16 *RelativePath OPTIONAL, OUT REFIT_DIR_ITER *DirIter) { if (RelativePath == NULL) { DirIter->LastStatus = EFI_SUCCESS; DirIter->DirHandle = BaseDir; DirIter->CloseDirHandle = FALSE; } else { DirIter->LastStatus = refit_call5_wrapper(BaseDir->Open, BaseDir, &(DirIter->DirHandle), RelativePath, EFI_FILE_MODE_READ, 0); DirIter->CloseDirHandle = EFI_ERROR(DirIter->LastStatus) ? FALSE : TRUE; } DirIter->LastFileInfo = NULL; } #ifndef __MAKEWITH_GNUEFI EFI_UNICODE_COLLATION_PROTOCOL *mUnicodeCollation = NULL; static EFI_STATUS InitializeUnicodeCollationProtocol (VOID) { EFI_STATUS Status; if (mUnicodeCollation != NULL) { return EFI_SUCCESS; } // // BUGBUG: Proper impelmentation is to locate all Unicode Collation Protocol // instances first and then select one which support English language. // Current implementation just pick the first instance. // Status = gBS->LocateProtocol ( &gEfiUnicodeCollation2ProtocolGuid, NULL, (VOID **) &mUnicodeCollation ); if (EFI_ERROR(Status)) { Status = gBS->LocateProtocol ( &gEfiUnicodeCollationProtocolGuid, NULL, (VOID **) &mUnicodeCollation ); } return Status; } static BOOLEAN MetaiMatch (IN CHAR16 *String, IN CHAR16 *Pattern) { if (!mUnicodeCollation) { InitializeUnicodeCollationProtocol(); } if (mUnicodeCollation) return mUnicodeCollation->MetaiMatch (mUnicodeCollation, String, Pattern); return FALSE; // Shouldn't happen } #endif BOOLEAN DirIterNext(IN OUT REFIT_DIR_ITER *DirIter, IN UINTN FilterMode, IN CHAR16 *FilePattern OPTIONAL, OUT EFI_FILE_INFO **DirEntry) { BOOLEAN KeepGoing = TRUE; UINTN i; CHAR16 *OnePattern; if (DirIter->LastFileInfo != NULL) { FreePool(DirIter->LastFileInfo); DirIter->LastFileInfo = NULL; } if (EFI_ERROR(DirIter->LastStatus)) return FALSE; // stop iteration do { DirIter->LastStatus = DirNextEntry(DirIter->DirHandle, &(DirIter->LastFileInfo), FilterMode); if (EFI_ERROR(DirIter->LastStatus)) return FALSE; if (DirIter->LastFileInfo == NULL) // end of listing return FALSE; if (FilePattern != NULL) { if ((DirIter->LastFileInfo->Attribute & EFI_FILE_DIRECTORY)) KeepGoing = FALSE; i = 0; while (KeepGoing && (OnePattern = FindCommaDelimited(FilePattern, i++)) != NULL) { if (MetaiMatch(DirIter->LastFileInfo->FileName, OnePattern)) KeepGoing = FALSE; } // while // else continue loop } else break; } while (KeepGoing && FilePattern); *DirEntry = DirIter->LastFileInfo; return TRUE; } EFI_STATUS DirIterClose(IN OUT REFIT_DIR_ITER *DirIter) { if (DirIter->LastFileInfo != NULL) { FreePool(DirIter->LastFileInfo); DirIter->LastFileInfo = NULL; } if ((DirIter->CloseDirHandle) && (DirIter->DirHandle->Close)) refit_call1_wrapper(DirIter->DirHandle->Close, DirIter->DirHandle); return DirIter->LastStatus; } // // file name manipulation // // Returns the filename portion (minus path name) of the // specified file CHAR16 * Basename(IN CHAR16 *Path) { CHAR16 *FileName; UINTN i; FileName = Path; if (Path != NULL) { for (i = StrLen(Path); i > 0; i--) { if (Path[i-1] == '\\' || Path[i-1] == '/') { FileName = Path + i; break; } } } return FileName; } // Remove the .efi extension from FileName -- for instance, if FileName is // "fred.efi", returns "fred". If the filename contains no .efi extension, // returns a copy of the original input. CHAR16 * StripEfiExtension(IN CHAR16 *FileName) { UINTN Length; CHAR16 *Copy = NULL; if ((FileName != NULL) && ((Copy = StrDuplicate(FileName)) != NULL)) { Length = StrLen(Copy); if ((Length >= 4) && MyStriCmp(&Copy[Length - 4], L".efi")) { Copy[Length - 4] = 0; } // if } // if return Copy; } // CHAR16 * StripExtension() // // memory string search // INTN FindMem(IN VOID *Buffer, IN UINTN BufferLength, IN VOID *SearchString, IN UINTN SearchStringLength) { UINT8 *BufferPtr; UINTN Offset; BufferPtr = Buffer; BufferLength -= SearchStringLength; for (Offset = 0; Offset < BufferLength; Offset++, BufferPtr++) { if (CompareMem(BufferPtr, SearchString, SearchStringLength) == 0) return (INTN)Offset; } return -1; } // Takes an input pathname (*Path) and returns the part of the filename from // the final dot onwards, converted to lowercase. If the filename includes // no dots, or if the input is NULL, returns an empty (but allocated) string. // The calling function is responsible for freeing the memory associated with // the return value. CHAR16 *FindExtension(IN CHAR16 *Path) { CHAR16 *Extension; BOOLEAN Found = FALSE, FoundSlash = FALSE; INTN i; Extension = AllocateZeroPool(sizeof(CHAR16)); if (Path) { i = StrLen(Path); while ((!Found) && (!FoundSlash) && (i >= 0)) { if (Path[i] == L'.') Found = TRUE; else if ((Path[i] == L'/') || (Path[i] == L'\\')) FoundSlash = TRUE; if (!Found) i--; } // while if (Found) { MergeStrings(&Extension, &Path[i], 0); ToLower(Extension); } // if (Found) } // if return (Extension); } // CHAR16 *FindExtension() // Takes an input pathname (*Path) and locates the final directory component // of that name. For instance, if the input path is 'EFI\foo\bar.efi', this // function returns the string 'foo'. // Assumes the pathname is separated with backslashes. CHAR16 *FindLastDirName(IN CHAR16 *Path) { UINTN i, StartOfElement = 0, EndOfElement = 0, PathLength, CopyLength; CHAR16 *Found = NULL; if (Path == NULL) return NULL; PathLength = StrLen(Path); // Find start & end of target element for (i = 0; i < PathLength; i++) { if (Path[i] == '\\') { StartOfElement = EndOfElement; EndOfElement = i; } // if } // for // Extract the target element if (EndOfElement > 0) { while ((StartOfElement < PathLength) && (Path[StartOfElement] == '\\')) { StartOfElement++; } // while EndOfElement--; if (EndOfElement >= StartOfElement) { CopyLength = EndOfElement - StartOfElement + 1; Found = StrDuplicate(&Path[StartOfElement]); if (Found != NULL) Found[CopyLength] = 0; } // if (EndOfElement >= StartOfElement) } // if (EndOfElement > 0) return (Found); } // CHAR16 *FindLastDirName() // Returns the directory portion of a pathname. For instance, // if FullPath is 'EFI\foo\bar.efi', this function returns the // string 'EFI\foo'. The calling function is responsible for // freeing the returned string's memory. CHAR16 *FindPath(IN CHAR16* FullPath) { UINTN i, LastBackslash = 0; CHAR16 *PathOnly = NULL; if (FullPath != NULL) { for (i = 0; i < StrLen(FullPath); i++) { if (FullPath[i] == '\\') LastBackslash = i; } // for PathOnly = StrDuplicate(FullPath); if (PathOnly != NULL) PathOnly[LastBackslash] = 0; } // if return (PathOnly); } // Takes an input loadpath, splits it into disk and filename components, finds a matching // DeviceVolume, and returns that and the filename (*loader). VOID FindVolumeAndFilename(IN EFI_DEVICE_PATH *loadpath, OUT REFIT_VOLUME **DeviceVolume, OUT CHAR16 **loader) { CHAR16 *DeviceString, *VolumeDeviceString, *Temp; UINTN i = 0; BOOLEAN Found = FALSE; if (!loadpath || !DeviceVolume || !loader) return; MyFreePool(*loader); MyFreePool(*DeviceVolume); *DeviceVolume = NULL; DeviceString = DevicePathToStr(loadpath); *loader = SplitDeviceString(DeviceString); while ((i < VolumesCount) && (!Found)) { if (Volumes[i]->DevicePath == NULL) { i++; continue; } VolumeDeviceString = DevicePathToStr(Volumes[i]->DevicePath); Temp = SplitDeviceString(VolumeDeviceString); if (MyStriCmp(DeviceString, VolumeDeviceString)) { Found = TRUE; *DeviceVolume = Volumes[i]; } MyFreePool(Temp); MyFreePool(VolumeDeviceString); i++; } // while MyFreePool(DeviceString); } // VOID FindVolumeAndFilename() // Splits a volume/filename string (e.g., "fs0:\EFI\BOOT") into separate // volume and filename components (e.g., "fs0" and "\EFI\BOOT"), returning // the filename component in the original *Path variable and the split-off // volume component in the *VolName variable. // Returns TRUE if both components are found, FALSE otherwise. BOOLEAN SplitVolumeAndFilename(IN OUT CHAR16 **Path, OUT CHAR16 **VolName) { UINTN i = 0, Length; CHAR16 *Filename; if (*Path == NULL) return FALSE; if (*VolName != NULL) { MyFreePool(*VolName); *VolName = NULL; } Length = StrLen(*Path); while ((i < Length) && ((*Path)[i] != L':')) { i++; } // while if (i < Length) { Filename = StrDuplicate((*Path) + i + 1); (*Path)[i] = 0; *VolName = *Path; *Path = Filename; return TRUE; } else { return FALSE; } } // BOOLEAN SplitVolumeAndFilename() // Take an input path name, which may include a volume specification and/or // a path, and return separate volume, path, and file names. For instance, // "BIGVOL:\EFI\ubuntu\grubx64.efi" will return a VolName of "BIGVOL", a Path // of "EFI\ubuntu", and a Filename of "grubx64.efi". If an element is missing, // the returned pointer is NULL. The calling function is responsible for // freeing the allocated memory. VOID SplitPathName(CHAR16 *InPath, CHAR16 **VolName, CHAR16 **Path, CHAR16 **Filename) { CHAR16 *Temp = NULL; MyFreePool(*VolName); MyFreePool(*Path); MyFreePool(*Filename); *VolName = *Path = *Filename = NULL; Temp = StrDuplicate(InPath); SplitVolumeAndFilename(&Temp, VolName); // VolName is NULL or has volume; Temp has rest of path CleanUpPathNameSlashes(Temp); *Path = FindPath(Temp); // *Path has path (may be 0-length); Temp unchanged. *Filename = StrDuplicate(Temp + StrLen(*Path)); CleanUpPathNameSlashes(*Filename); if (StrLen(*Path) == 0) { MyFreePool(*Path); *Path = NULL; } if (StrLen(*Filename) == 0) { MyFreePool(*Filename); *Filename = NULL; } MyFreePool(Temp); } // VOID SplitPathName() // Finds a volume with the specified Identifier (a filesystem label, a // partition name, or a partition GUID). If found, sets *Volume to point // to that volume. If not, leaves it unchanged. // Returns TRUE if a match was found, FALSE if not. BOOLEAN FindVolume(REFIT_VOLUME **Volume, CHAR16 *Identifier) { UINTN i = 0; BOOLEAN Found = FALSE; while ((i < VolumesCount) && (!Found)) { if (VolumeMatchesDescription(Volumes[i], Identifier)) { *Volume = Volumes[i]; Found = TRUE; } // if i++; } // while() return (Found); } // static VOID FindVolume() // Returns TRUE if Description matches Volume's VolName, PartName, or (once // transformed) PartGuid fields, FALSE otherwise (or if either pointer is NULL) BOOLEAN VolumeMatchesDescription(REFIT_VOLUME *Volume, CHAR16 *Description) { EFI_GUID TargetVolGuid = NULL_GUID_VALUE; if ((Volume == NULL) || (Description == NULL)) return FALSE; if (IsGuid(Description)) { TargetVolGuid = StringAsGuid(Description); return GuidsAreEqual(&TargetVolGuid, &(Volume->PartGuid)); } else { return (MyStriCmp(Description, Volume->VolName) || MyStriCmp(Description, Volume->PartName)); } } // BOOLEAN VolumeMatchesDescription() // Returns TRUE if specified Volume, Directory, and Filename correspond to an // element in the comma-delimited List, FALSE otherwise. Note that Directory and // Filename must *NOT* include a volume or path specification (that's part of // the Volume variable), but the List elements may. Performs comparison // case-insensitively. BOOLEAN FilenameIn(REFIT_VOLUME *Volume, CHAR16 *Directory, CHAR16 *Filename, CHAR16 *List) { UINTN i = 0; BOOLEAN Found = FALSE; CHAR16 *OneElement; CHAR16 *TargetVolName = NULL, *TargetPath = NULL, *TargetFilename = NULL; if (Filename && List) { while (!Found && (OneElement = FindCommaDelimited(List, i++))) { Found = TRUE; SplitPathName(OneElement, &TargetVolName, &TargetPath, &TargetFilename); if (((TargetVolName != NULL) && (!VolumeMatchesDescription(Volume, TargetVolName))) || ((TargetPath != NULL) && (!MyStriCmp(TargetPath, Directory))) || ((TargetFilename != NULL) && (!MyStriCmp(TargetFilename, Filename)))) { Found = FALSE; } // if MyFreePool(OneElement); } // while MyFreePool(TargetVolName); MyFreePool(TargetPath); MyFreePool(TargetFilename); } // if return Found; } // BOOLEAN FilenameIn() // Implement FreePool the way it should have been done to begin with, so that // it doesn't throw an ASSERT message if fed a NULL pointer.... VOID MyFreePool(IN VOID *Pointer) { if (Pointer != NULL) FreePool(Pointer); } static EFI_GUID AppleRemovableMediaGuid = APPLE_REMOVABLE_MEDIA_PROTOCOL_GUID; // Eject all removable media. // Returns TRUE if any media were ejected, FALSE otherwise. BOOLEAN EjectMedia(VOID) { EFI_STATUS Status; UINTN HandleIndex, HandleCount = 0, Ejected = 0; EFI_HANDLE *Handles, Handle; APPLE_REMOVABLE_MEDIA_PROTOCOL *Ejectable; Status = LibLocateHandle(ByProtocol, &AppleRemovableMediaGuid, NULL, &HandleCount, &Handles); if (EFI_ERROR(Status) || HandleCount == 0) return (FALSE); // probably not an Apple system for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) { Handle = Handles[HandleIndex]; Status = refit_call3_wrapper(BS->HandleProtocol, Handle, &AppleRemovableMediaGuid, (VOID **) &Ejectable); if (EFI_ERROR(Status)) continue; Status = refit_call1_wrapper(Ejectable->Eject, Ejectable); if (!EFI_ERROR(Status)) Ejected++; } MyFreePool(Handles); return (Ejected > 0); } // VOID EjectMedia() // Returns TRUE if the two GUIDs are equal, FALSE otherwise BOOLEAN GuidsAreEqual(EFI_GUID *Guid1, EFI_GUID *Guid2) { return (CompareMem(Guid1, Guid2, 16) == 0); } // BOOLEAN GuidsAreEqual() // Erase linked-list of UINT32 values.... VOID EraseUint32List(UINT32_LIST **TheList) { UINT32_LIST *NextItem; while (*TheList) { NextItem = (*TheList)->Next; FreePool(*TheList); *TheList = NextItem; } // while } // EraseUin32List() �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/refind/mystrings.c��������������������������������������������������������������������0000664�0001750�0001750�00000045443�13317550704�017003� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * refind/mystrings.c * String-manipulation functions * * Copyright (c) 2012-2015 Roderick W. Smith * * Distributed under the terms of the GNU General Public License (GPL) * version 3 (GPLv3), or (at your option) any later version. * */ /* * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "mystrings.h" #include "lib.h" #include "screen.h" BOOLEAN StriSubCmp(IN CHAR16 *SmallStr, IN CHAR16 *BigStr) { BOOLEAN Found = 0, Terminate = 0; UINTN BigIndex = 0, SmallIndex = 0, BigStart = 0; if (SmallStr && BigStr) { while (!Terminate) { if (BigStr[BigIndex] == '\0') { Terminate = 1; } if (SmallStr[SmallIndex] == '\0') { Found = 1; Terminate = 1; } if ((SmallStr[SmallIndex] & ~0x20) == (BigStr[BigIndex] & ~0x20)) { SmallIndex++; BigIndex++; } else { SmallIndex = 0; BigStart++; BigIndex = BigStart; } } // while } // if return Found; } // BOOLEAN StriSubCmp() // Performs a case-insensitive string comparison. This function is necesary // because some EFIs have buggy StriCmp() functions that actually perform // case-sensitive comparisons. // Returns TRUE if strings are identical, FALSE otherwise. BOOLEAN MyStriCmp(IN CONST CHAR16 *FirstString, IN CONST CHAR16 *SecondString) { if (FirstString && SecondString) { while ((*FirstString != L'\0') && ((*FirstString & ~0x20) == (*SecondString & ~0x20))) { FirstString++; SecondString++; } return (*FirstString == *SecondString); } else { return FALSE; } } // BOOLEAN MyStriCmp() /*++ * * Routine Description: * * Find a substring. * * Arguments: * * String - Null-terminated string to search. * StrCharSet - Null-terminated string to search for. * * Returns: * The address of the first occurrence of the matching substring if successful, or NULL otherwise. * --*/ CHAR16* MyStrStr (IN CHAR16 *String, IN CHAR16 *StrCharSet) { CHAR16 *Src; CHAR16 *Sub; if ((String == NULL) || (StrCharSet == NULL)) return NULL; Src = String; Sub = StrCharSet; while ((*String != L'\0') && (*StrCharSet != L'\0')) { if (*String++ != *StrCharSet) { String = ++Src; StrCharSet = Sub; } else { StrCharSet++; } } if (*StrCharSet == L'\0') { return Src; } else { return NULL; } } // CHAR16 *MyStrStr() // Convert input string to all-lowercase. // DO NOT USE the standard StrLwr() function, since it's broken on some EFIs! VOID ToLower(CHAR16 * MyString) { UINTN i = 0; if (MyString) { while (MyString[i] != L'\0') { if ((MyString[i] >= L'A') && (MyString[i] <= L'Z')) MyString[i] = MyString[i] - L'A' + L'a'; i++; } // while } // if } // VOID ToLower() // Merges two strings, creating a new one and returning a pointer to it. // If AddChar != 0, the specified character is placed between the two original // strings (unless the first string is NULL or empty). The original input // string *First is de-allocated and replaced by the new merged string. // This is similar to StrCat, but safer and more flexible because // MergeStrings allocates memory that's the correct size for the // new merged string, so it can take a NULL *First and it cleans // up the old memory. It should *NOT* be used with a constant // *First, though.... VOID MergeStrings(IN OUT CHAR16 **First, IN CHAR16 *Second, CHAR16 AddChar) { UINTN Length1 = 0, Length2 = 0; CHAR16* NewString; if (*First != NULL) Length1 = StrLen(*First); if (Second != NULL) Length2 = StrLen(Second); NewString = AllocatePool(sizeof(CHAR16) * (Length1 + Length2 + 2)); if (NewString != NULL) { if ((*First != NULL) && (Length1 == 0)) { MyFreePool(*First); *First = NULL; } NewString[0] = L'\0'; if (*First != NULL) { StrCat(NewString, *First); if (AddChar) { NewString[Length1] = AddChar; NewString[Length1 + 1] = '\0'; } // if (AddChar) } // if (*First != NULL) if (Second != NULL) StrCat(NewString, Second); MyFreePool(*First); *First = NewString; } else { Print(L"Error! Unable to allocate memory in MergeStrings()!\n"); } // if/else } // VOID MergeStrings() // Similar to MergeStrings, but breaks the input string into word chunks and // merges each word separately. Words are defined as string fragments separated // by ' ', '_', or '-'. VOID MergeWords(CHAR16 **MergeTo, CHAR16 *SourceString, CHAR16 AddChar) { CHAR16 *Temp, *Word, *p; BOOLEAN LineFinished = FALSE; if (SourceString) { Temp = Word = p = StrDuplicate(SourceString); if (Temp) { while (!LineFinished) { if ((*p == L' ') || (*p == L'_') || (*p == L'-') || (*p == L'\0')) { if (*p == L'\0') LineFinished = TRUE; *p = L'\0'; if (*Word != L'\0') MergeStrings(MergeTo, Word, AddChar); Word = p + 1; } // if p++; } // while MyFreePool(Temp); } else { Print(L"Error! Unable to allocate memory in MergeWords()!\n"); } // if/else } // if } // VOID MergeWords() // Restrict TheString to at most Limit characters. // Does this in two ways: // - Locates stretches of two or more spaces and compresses // them down to one space. // - Truncates TheString // Returns TRUE if changes were made, FALSE otherwise BOOLEAN LimitStringLength(CHAR16 *TheString, UINTN Limit) { CHAR16 *SubString, *TempString; UINTN i; BOOLEAN HasChanged = FALSE; // SubString will be NULL or point WITHIN TheString SubString = MyStrStr(TheString, L" "); while (SubString != NULL) { i = 0; while (SubString[i] == L' ') i++; if (i >= StrLen(SubString)) { SubString[0] = '\0'; HasChanged = TRUE; } else { TempString = StrDuplicate(&SubString[i]); if (TempString != NULL) { StrCpy(&SubString[1], TempString); MyFreePool(TempString); HasChanged = TRUE; } else { // memory allocation problem; abort to avoid potentially infinite loop! break; } // if/else } // if/else SubString = MyStrStr(TheString, L" "); } // while // If the string is still too long, truncate it.... if (StrLen(TheString) > Limit) { TheString[Limit] = '\0'; HasChanged = TRUE; } // if return HasChanged; } // BOOLEAN LimitStringLength() // Returns all the digits in the input string, including intervening // non-digit characters. For instance, if InString is "foo-3.3.4-7.img", // this function returns "3.3.4-7". The GlobalConfig.ExtraKernelVersionStrings // variable specifies extra strings that may be treated as numbers. If // InString contains no digits or ExtraKernelVersionStrings, the return value // is NULL. CHAR16 *FindNumbers(IN CHAR16 *InString) { UINTN i = 0, StartOfElement, EndOfElement = 0, CopyLength; CHAR16 *Found = NULL, *ExtraFound = NULL, *LookFor; if (InString == NULL) return NULL; StartOfElement = StrLen(InString); // Find extra_kernel_version_strings while ((ExtraFound == NULL) && (LookFor = FindCommaDelimited(GlobalConfig.ExtraKernelVersionStrings, i++))) { if ((ExtraFound = MyStrStr(InString, LookFor))) { StartOfElement = ExtraFound - InString; EndOfElement = StartOfElement + StrLen(LookFor) - 1; } // if } // while // Find start & end of target element for (i = 0; InString[i] != L'\0'; i++) { if ((InString[i] >= L'0') && (InString[i] <= L'9')) { if (StartOfElement > i) StartOfElement = i; if (EndOfElement < i) EndOfElement = i; } // if } // for // Extract the target element if (EndOfElement > 0) { if (EndOfElement >= StartOfElement) { CopyLength = EndOfElement - StartOfElement + 1; Found = StrDuplicate(&InString[StartOfElement]); if (Found != NULL) Found[CopyLength] = 0; } // if (EndOfElement >= StartOfElement) } // if (EndOfElement > 0) return (Found); } // CHAR16 *FindNumbers() // Returns the number of characters that are in common between // String1 and String2 before they diverge. For instance, if // String1 is "FooBar" and String2 is "FoodiesBar", this function // will return "3", since they both start with "Foo". UINTN NumCharsInCommon(IN CHAR16* String1, IN CHAR16* String2) { UINTN Count = 0; if ((String1 == NULL) || (String2 == NULL)) return 0; while ((String1[Count] != L'\0') && (String2[Count] != L'\0') && (String1[Count] == String2[Count])) Count++; return Count; } // UINTN NumCharsInCommon() // Find the #Index element (numbered from 0) in a comma-delimited string // of elements. // Returns the found element, or NULL if Index is out of range or InString // is NULL. Note that the calling function is responsible for freeing the // memory associated with the returned string pointer. CHAR16 *FindCommaDelimited(IN CHAR16 *InString, IN UINTN Index) { UINTN StartPos = 0, CurPos = 0, InLength; BOOLEAN Found = FALSE; CHAR16 *FoundString = NULL; if (InString != NULL) { InLength = StrLen(InString); // After while() loop, StartPos marks start of item #Index while ((Index > 0) && (CurPos < InLength)) { if (InString[CurPos] == L',') { Index--; StartPos = CurPos + 1; } // if CurPos++; } // while // After while() loop, CurPos is one past the end of the element while ((CurPos < InLength) && (!Found)) { if (InString[CurPos] == L',') Found = TRUE; else CurPos++; } // while if (Index == 0) FoundString = StrDuplicate(&InString[StartPos]); if (FoundString != NULL) FoundString[CurPos - StartPos] = 0; } // if return (FoundString); } // CHAR16 *FindCommaDelimited() // Delete an individual element from a comma-separated value list. // This function modifies the original *List string, but not the // *ToDelete string! // Returns TRUE if the item was deleted, FALSE otherwise. BOOLEAN DeleteItemFromCsvList(CHAR16 *ToDelete, CHAR16 *List) { CHAR16 *Found, *Comma; if ((ToDelete == NULL) || (List == NULL)) return FALSE; if ((Found = MyStrStr(List, ToDelete)) != NULL) { if ((Comma = MyStrStr(Found, L",")) == NULL) { // Found is final element if (Found == List) { // Found is ONLY element List[0] = L'\0'; } else { // Delete the comma preceding Found.... Found--; Found[0] = L'\0'; } // if/else } else { // Found is NOT final element StrCpy(Found, &Comma[1]); } // if/else return TRUE; } else { return FALSE; } // if/else } // BOOLEAN DeleteItemFromCsvList() // Returns TRUE if SmallString is an element in the comma-delimited List, // FALSE otherwise. Performs comparison case-insensitively. BOOLEAN IsIn(IN CHAR16 *SmallString, IN CHAR16 *List) { UINTN i = 0; BOOLEAN Found = FALSE; CHAR16 *OneElement; if (SmallString && List) { while (!Found && (OneElement = FindCommaDelimited(List, i++))) { if (MyStriCmp(OneElement, SmallString)) Found = TRUE; } // while } // if return Found; } // BOOLEAN IsIn() // Returns TRUE if any element of List can be found as a substring of // BigString, FALSE otherwise. Performs comparisons case-insensitively. BOOLEAN IsInSubstring(IN CHAR16 *BigString, IN CHAR16 *List) { UINTN i = 0, ElementLength; BOOLEAN Found = FALSE; CHAR16 *OneElement; if (BigString && List) { while (!Found && (OneElement = FindCommaDelimited(List, i++))) { ElementLength = StrLen(OneElement); if ((ElementLength <= StrLen(BigString)) && (StriSubCmp(OneElement, BigString))) Found = TRUE; } // while } // if return Found; } // BOOLEAN IsSubstringIn() // Replace *SearchString in **MainString with *ReplString -- but if *SearchString // is preceded by "%", instead remove that character. // Returns TRUE if replacement was done, FALSE otherwise. BOOLEAN ReplaceSubstring(IN OUT CHAR16 **MainString, IN CHAR16 *SearchString, IN CHAR16 *ReplString) { BOOLEAN WasReplaced = FALSE; CHAR16 *FoundSearchString, *NewString, *EndString; FoundSearchString = MyStrStr(*MainString, SearchString); if (FoundSearchString) { NewString = AllocateZeroPool(sizeof(CHAR16) * StrLen(*MainString)); if (NewString) { EndString = &(FoundSearchString[StrLen(SearchString)]); FoundSearchString[0] = L'\0'; if ((FoundSearchString > *MainString) && (FoundSearchString[-1] == L'%')) { FoundSearchString[-1] = L'\0'; ReplString = SearchString; } // if StrCpy(NewString, *MainString); MergeStrings(&NewString, ReplString, L'\0'); MergeStrings(&NewString, EndString, L'\0'); MyFreePool(MainString); *MainString = NewString; WasReplaced = TRUE; } // if } // if return WasReplaced; } // BOOLEAN ReplaceSubstring() // Returns TRUE if *Input contains nothing but valid hexadecimal characters, // FALSE otherwise. Note that a leading "0x" is NOT acceptable in the input! BOOLEAN IsValidHex(CHAR16 *Input) { BOOLEAN IsHex = TRUE; UINTN i = 0; while ((Input[i] != L'\0') && IsHex) { if (!(((Input[i] >= L'0') && (Input[i] <= L'9')) || ((Input[i] >= L'A') && (Input[i] <= L'F')) || ((Input[i] >= L'a') && (Input[i] <= L'f')))) { IsHex = FALSE; } i++; } // while return IsHex; } // BOOLEAN IsValidHex() // Converts consecutive characters in the input string into a // number, interpreting the string as a hexadecimal number, starting // at the specified position and continuing for the specified number // of characters or until the end of the string, whichever is first. // NumChars must be between 1 and 16. Ignores invalid characters. UINT64 StrToHex(CHAR16 *Input, UINTN Pos, UINTN NumChars) { UINT64 retval = 0x00; UINTN NumDone = 0, InputLength; CHAR16 a; if ((Input == NULL) || (NumChars == 0) || (NumChars > 16)) { return 0; } InputLength = StrLen(Input); while ((Pos <= InputLength) && (NumDone < NumChars)) { a = Input[Pos]; if ((a >= '0') && (a <= '9')) { retval *= 0x10; retval += (a - '0'); NumDone++; } if ((a >= 'a') && (a <= 'f')) { retval *= 0x10; retval += (a - 'a' + 0x0a); NumDone++; } if ((a >= 'A') && (a <= 'F')) { retval *= 0x10; retval += (a - 'A' + 0x0a); NumDone++; } Pos++; } // while() return retval; } // StrToHex() // Returns TRUE if UnknownString can be interpreted as a GUID, FALSE otherwise. // Note that the input string must have no extraneous spaces and must be // conventionally formatted as a 36-character GUID, complete with dashes in // appropriate places. BOOLEAN IsGuid(CHAR16 *UnknownString) { UINTN Length, i; BOOLEAN retval = TRUE; CHAR16 a; if (UnknownString == NULL) return FALSE; Length = StrLen(UnknownString); if (Length != 36) return FALSE; for (i = 0; i < Length; i++) { a = UnknownString[i]; if ((i == 8) || (i == 13) || (i == 18) || (i == 23)) { if (a != L'-') retval = FALSE; } else if (((a < L'a') || (a > L'f')) && ((a < L'A') || (a > L'F')) && ((a < L'0') && (a > L'9'))) { retval = FALSE; } // if/else if } // for return retval; } // BOOLEAN IsGuid() // Return the GUID as a string, suitable for display to the user. Note that the calling // function is responsible for freeing the allocated memory. CHAR16 * GuidAsString(EFI_GUID *GuidData) { CHAR16 *TheString; TheString = AllocateZeroPool(42 * sizeof(CHAR16)); if (GuidData && (TheString != 0)) { SPrint (TheString, 82, L"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", (UINTN)GuidData->Data1, (UINTN)GuidData->Data2, (UINTN)GuidData->Data3, (UINTN)GuidData->Data4[0], (UINTN)GuidData->Data4[1], (UINTN)GuidData->Data4[2], (UINTN)GuidData->Data4[3], (UINTN)GuidData->Data4[4], (UINTN)GuidData->Data4[5], (UINTN)GuidData->Data4[6], (UINTN)GuidData->Data4[7]); } return TheString; } // GuidAsString(EFI_GUID *GuidData) EFI_GUID StringAsGuid(CHAR16 * InString) { EFI_GUID Guid = NULL_GUID_VALUE; if (!IsGuid(InString)) { return Guid; } Guid.Data1 = (UINT32) StrToHex(InString, 0, 8); Guid.Data2 = (UINT16) StrToHex(InString, 9, 4); Guid.Data3 = (UINT16) StrToHex(InString, 14, 4); Guid.Data4[0] = (UINT8) StrToHex(InString, 19, 2); Guid.Data4[1] = (UINT8) StrToHex(InString, 21, 2); Guid.Data4[2] = (UINT8) StrToHex(InString, 23, 2); Guid.Data4[3] = (UINT8) StrToHex(InString, 26, 2); Guid.Data4[4] = (UINT8) StrToHex(InString, 28, 2); Guid.Data4[5] = (UINT8) StrToHex(InString, 30, 2); Guid.Data4[6] = (UINT8) StrToHex(InString, 32, 2); Guid.Data4[7] = (UINT8) StrToHex(InString, 34, 2); return Guid; } // EFI_GUID StringAsGuid() // Delete the STRING_LIST pointed to by *StringList. VOID DeleteStringList(STRING_LIST *StringList) { STRING_LIST *Current = StringList, *Previous; while (Current != NULL) { MyFreePool(Current->Value); Previous = Current; Current = Current->Next; MyFreePool(Previous); } } // VOID DeleteStringList() �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/refind/global.h�����������������������������������������������������������������������0000664�0001750�0001750�00000033574�13324370261�016207� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * refit/global.h * Global header file * * Copyright (c) 2006-2009 Christoph Pfisterer * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * * Neither the name of Christoph Pfisterer nor the names of the * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Modifications copyright (c) 2012-2015 Roderick W. Smith * * Modifications distributed under the terms of the GNU General Public * License (GPL) version 3 (GPLv3), a copy of which must be distributed * with this source code or binaries made from it. * */ #ifndef __GLOBAL_H_ #define __GLOBAL_H_ #ifdef __MAKEWITH_GNUEFI #include <efi.h> #include <efilib.h> #else #include "../include/tiano_includes.h" #endif #include "../EfiLib/GenericBdsLib.h" #include "../libeg/libeg.h" #define REFIT_DEBUG (0) // Tag classifications; used in various ways. #define TAG_ABOUT (1) #define TAG_REBOOT (2) #define TAG_SHUTDOWN (3) #define TAG_TOOL (4) #define TAG_LOADER (5) #define TAG_LEGACY (6) #define TAG_EXIT (7) #define TAG_SHELL (8) #define TAG_GPTSYNC (9) #define TAG_LEGACY_UEFI (10) #define TAG_APPLE_RECOVERY (11) #define TAG_WINDOWS_RECOVERY (12) #define TAG_MOK_TOOL (13) #define TAG_FIRMWARE (14) #define TAG_MEMTEST (15) #define TAG_GDISK (16) #define TAG_NETBOOT (17) #define TAG_CSR_ROTATE (18) #define TAG_FWUPDATE_TOOL (19) #define TAG_HIDDEN (20) #define NUM_TOOLS (21) #define NUM_SCAN_OPTIONS 10 #define DEFAULT_ICONS_DIR L"icons" // OS bit codes; used in GlobalConfig.GraphicsOn #define GRAPHICS_FOR_OSX 1 #define GRAPHICS_FOR_LINUX 2 #define GRAPHICS_FOR_ELILO 4 #define GRAPHICS_FOR_GRUB 8 #define GRAPHICS_FOR_WINDOWS 16 // Type of legacy (BIOS) boot support detected #define LEGACY_TYPE_NONE 0 #define LEGACY_TYPE_MAC 1 #define LEGACY_TYPE_UEFI 2 // How was a loader added to the menu? #define DISCOVERY_TYPE_UNKNOWN 0 #define DISCOVERY_TYPE_AUTO 1 #define DISCOVERY_TYPE_MANUAL 2 #ifdef __MAKEWITH_GNUEFI // // define BBS Device Types // #define BBS_FLOPPY 0x01 #define BBS_HARDDISK 0x02 #define BBS_CDROM 0x03 #define BBS_PCMCIA 0x04 #define BBS_USB 0x05 #define BBS_EMBED_NETWORK 0x06 #define BBS_BEV_DEVICE 0x80 #define BBS_UNKNOWN 0xff #endif // BIOS Boot Specification (BBS) device types, as returned in DevicePath->Type field #define DEVICE_TYPE_HW 0x01 #define DEVICE_TYPE_ACPI 0x02 /* returned by UEFI boot loader on USB */ #define DEVICE_TYPE_MESSAGING 0x03 #define DEVICE_TYPE_MEDIA 0x04 /* returned by EFI boot loaders on hard disk */ #define DEVICE_TYPE_BIOS 0x05 /* returned by legacy (BIOS) boot loaders */ #define DEVICE_TYPE_END 0x75 /* end of path */ // Filesystem type identifiers. Not all are yet used.... #define FS_TYPE_UNKNOWN 0 #define FS_TYPE_WHOLEDISK 1 #define FS_TYPE_FAT 2 #define FS_TYPE_EXFAT 3 #define FS_TYPE_NTFS 4 #define FS_TYPE_EXT2 5 #define FS_TYPE_EXT3 6 #define FS_TYPE_EXT4 7 #define FS_TYPE_HFSPLUS 8 #define FS_TYPE_REISERFS 9 #define FS_TYPE_BTRFS 10 #define FS_TYPE_XFS 11 #define FS_TYPE_ISO9660 12 // How to scale banner images #define BANNER_NOSCALE 0 #define BANNER_FILLSCREEN 1 // Sizes of the default icons; badges are 1/4 the big icon size #define DEFAULT_SMALL_ICON_SIZE 48 #define DEFAULT_BIG_ICON_SIZE 128 #define DEFAULT_MOUSE_SIZE 16 // Codes for types of icon sizes; used for indexing into GlobalConfig.IconSizes[] #define ICON_SIZE_BADGE 0 #define ICON_SIZE_SMALL 1 #define ICON_SIZE_BIG 2 #define ICON_SIZE_MOUSE 3 // Minimum horizontal resolution for a screen to be consider high-DPI #define HIDPI_MIN 1921 // Names of binaries that can manage MOKs.... #if defined (EFIX64) #define MOK_NAMES L"MokManager.efi,HashTool.efi,HashTool-signed.efi,KeyTool.efi,KeyTool-signed.efi,mmx64.efi" #elif defined(EFI32) #define MOK_NAMES L"MokManager.efi,HashTool.efi,HashTool-signed.efi,KeyTool.efi,KeyTool-signed.efi,mmia32.efi" #elif defined(EFIAARCH64) #define MOK_NAMES L"MokManager.efi,HashTool.efi,HashTool-signed.efi,KeyTool.efi,KeyTool-signed.efi,mmaa64.efi" #else #define MOK_NAMES L"MokManager.efi,HashTool.efi,HashTool-signed.efi,KeyTool.efi,KeyTool-signed.efi" #endif // Names of binaries that can update firmware.... #if defined (EFIX64) #define FWUPDATE_NAMES L"fwupx64.efi" #elif defined(EFI32) #define FWUPDATE_NAMES L"fwupia32.efi" #elif defined(EFIAARCH64) #define FWUPDATE_NAMES L"fwupaa64.efi" #else #define FWUPDATE_NAMES L"fwup.efi" #endif // Directories to search for these MOK-managing programs. Note that SelfDir is // searched in addition to these locations.... #define MOK_LOCATIONS L"\\,EFI\\tools,EFI\\fedora,EFI\\redhat,EFI\\ubuntu,EFI\\suse,EFI\\opensuse,EFI\\altlinux" // Directories to search for memtest86.... #define MEMTEST_LOCATIONS L"EFI\\tools,EFI\\tools\\memtest86,EFI\\tools\\memtest,EFI\\memtest86,EFI\\memtest" // Files that may be Windows recovery files #define WINDOWS_RECOVERY_FILES L"EFI\\Microsoft\\Boot\\LrsBootmgr.efi,Recovery:\\EFI\\BOOT\\bootx64.efi,Recovery:\\EFI\\BOOT\\bootia32.efi,\\EFI\\OEM\\Boot\\bootmgfw.efi" // Files that may be macOS recovery files #define MACOS_RECOVERY_FILES L"com.apple.recovery.boot\\boot.efi" // Filename patterns that identify EFI boot loaders. Note that a single case (either L"*.efi" or // L"*.EFI") is fine for most systems; but Gigabyte's buggy Hybrid EFI does a case-sensitive // comparison when it should do a case-insensitive comparison, so I'm doubling this up. It does // no harm on other computers, AFAIK. In theory, every case variation should be done for // completeness, but that's ridiculous.... #define LOADER_MATCH_PATTERNS L"*.efi,*.EFI" // Definitions for the "hideui" option in refind.conf #define HIDEUI_FLAG_NONE (0x0000) #define HIDEUI_FLAG_BANNER (0x0001) #define HIDEUI_FLAG_LABEL (0x0002) #define HIDEUI_FLAG_SINGLEUSER (0x0004) #define HIDEUI_FLAG_HWTEST (0x0008) #define HIDEUI_FLAG_ARROWS (0x0010) #define HIDEUI_FLAG_HINTS (0x0020) #define HIDEUI_FLAG_EDITOR (0x0040) #define HIDEUI_FLAG_SAFEMODE (0x0080) #define HIDEUI_FLAG_BADGES (0x0100) #define HIDEUI_FLAG_ALL ((0xffff)) // Default hint text for program-launch submenus #define SUBSCREEN_HINT1 L"Use arrow keys to move cursor; Enter to boot;" #define SUBSCREEN_HINT2 L"Insert or F2 to edit options; Esc to return to main menu" #define SUBSCREEN_HINT2_NO_EDITOR L"Esc to return to main menu" #define NULL_GUID_VALUE { 0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }; #define REFIND_GUID_VALUE { 0x36D08FA7, 0xCF0B, 0x42F5, {0x8F, 0x14, 0x68, 0xDF, 0x73, 0xED, 0x37, 0x40} }; // Configuration file variables #define KERNEL_VERSION L"%v" // // global definitions // // global types typedef struct _uint32_list { UINT32 Value; struct _uint32_list *Next; } UINT32_LIST; typedef struct { UINT8 Flags; UINT8 StartCHS1; UINT8 StartCHS2; UINT8 StartCHS3; UINT8 Type; UINT8 EndCHS1; UINT8 EndCHS2; UINT8 EndCHS3; UINT32 StartLBA; UINT32 Size; } MBR_PARTITION_INFO; typedef struct { EFI_DEVICE_PATH *DevicePath; EFI_HANDLE DeviceHandle; EFI_FILE *RootDir; CHAR16 *VolName; CHAR16 *PartName; EFI_GUID VolUuid; EFI_GUID PartGuid; EFI_GUID PartTypeGuid; BOOLEAN IsMarkedReadOnly; EG_IMAGE *VolIconImage; EG_IMAGE *VolBadgeImage; UINTN DiskKind; // BOOLEAN IsAppleLegacy; BOOLEAN HasBootCode; CHAR16 *OSIconName; CHAR16 *OSName; BOOLEAN IsMbrPartition; UINTN MbrPartitionIndex; EFI_BLOCK_IO *BlockIO; UINT64 BlockIOOffset; EFI_BLOCK_IO *WholeDiskBlockIO; EFI_DEVICE_PATH *WholeDiskDevicePath; MBR_PARTITION_INFO *MbrPartitionTable; BOOLEAN IsReadable; UINT32 FSType; } REFIT_VOLUME; typedef struct _refit_menu_entry { CHAR16 *Title; UINTN Tag; UINTN Row; CHAR16 ShortcutDigit; CHAR16 ShortcutLetter; EG_IMAGE *Image; EG_IMAGE *BadgeImage; struct _refit_menu_screen *SubScreen; } REFIT_MENU_ENTRY; typedef struct _refit_menu_screen { CHAR16 *Title; EG_IMAGE *TitleImage; UINTN InfoLineCount; CHAR16 **InfoLines; UINTN EntryCount; // total number of entries registered REFIT_MENU_ENTRY **Entries; UINTN TimeoutSeconds; CHAR16 *TimeoutText; CHAR16 *Hint1; CHAR16 *Hint2; } REFIT_MENU_SCREEN; typedef struct { REFIT_MENU_ENTRY me; CHAR16 *Title; CHAR16 *LoaderPath; REFIT_VOLUME *Volume; BOOLEAN UseGraphicsMode; BOOLEAN Enabled; CHAR16 *LoadOptions; CHAR16 *InitrdPath; // Linux stub loader only CHAR8 OSType; UINTN DiscoveryType; } LOADER_ENTRY; typedef struct { REFIT_MENU_ENTRY me; REFIT_VOLUME *Volume; BDS_COMMON_OPTION *BdsOption; CHAR16 *LoadOptions; BOOLEAN Enabled; } LEGACY_ENTRY; typedef struct { BOOLEAN TextOnly; BOOLEAN ScanAllLinux; BOOLEAN DeepLegacyScan; BOOLEAN EnableAndLockVMX; BOOLEAN FoldLinuxKernels; BOOLEAN EnableMouse; BOOLEAN EnableTouch; BOOLEAN HiddenTags; BOOLEAN UseNvram; BOOLEAN ShutdownAfterTimeout; UINTN RequestedScreenWidth; UINTN RequestedScreenHeight; UINTN BannerBottomEdge; UINTN RequestedTextMode; UINTN Timeout; UINTN HideUIFlags; UINTN MaxTags; // max. number of OS entries to show simultaneously in graphics mode UINTN GraphicsFor; UINTN LegacyType; UINTN ScanDelay; UINTN ScreensaverTime; UINTN MouseSpeed; UINTN IconSizes[4]; UINTN BannerScale; REFIT_VOLUME *DiscoveredRoot; EFI_DEVICE_PATH *SelfDevicePath; CHAR16 *BannerFileName; EG_IMAGE *ScreenBackground; CHAR16 *ConfigFilename; CHAR16 *SelectionSmallFileName; CHAR16 *SelectionBigFileName; CHAR16 *DefaultSelection; CHAR16 *AlsoScan; CHAR16 *DontScanVolumes; CHAR16 *DontScanDirs; CHAR16 *DontScanFiles; CHAR16 *DontScanTools; CHAR16 *WindowsRecoveryFiles; CHAR16 *MacOSRecoveryFiles; CHAR16 *DriverDirs; CHAR16 *IconsDir; CHAR16 *ExtraKernelVersionStrings; CHAR16 *SpoofOSXVersion; UINT32_LIST *CsrValues; UINTN ShowTools[NUM_TOOLS]; CHAR8 ScanFor[NUM_SCAN_OPTIONS]; // codes of types of loaders for which to scan } REFIT_CONFIG; // Global variables extern EFI_HANDLE SelfImageHandle; extern EFI_LOADED_IMAGE *SelfLoadedImage; extern EFI_FILE *SelfRootDir; extern EFI_FILE *SelfDir; extern CHAR16 *SelfDirPath; extern REFIT_VOLUME *SelfVolume; extern REFIT_VOLUME **Volumes; extern UINTN VolumesCount; extern REFIT_CONFIG GlobalConfig; extern EFI_GUID gEfiLegacyBootProtocolGuid; extern EFI_GUID gEfiGlobalVariableGuid; extern BOOLEAN HaveResized; EFI_STATUS StartEFIImage(IN REFIT_VOLUME *Volume, IN CHAR16 *Filename, IN CHAR16 *LoadOptions, IN CHAR16 *ImageTitle, IN CHAR8 OSType, IN BOOLEAN Verbose, IN BOOLEAN IsDriver); LOADER_ENTRY *InitializeLoaderEntry(IN LOADER_ENTRY *Entry); REFIT_MENU_SCREEN *InitializeSubScreen(IN LOADER_ENTRY *Entry); VOID GenerateSubScreen(LOADER_ENTRY *Entry, IN REFIT_VOLUME *Volume, IN BOOLEAN GenerateReturn); EG_IMAGE * GetDiskBadge(IN UINTN DiskType); LOADER_ENTRY * MakeGenericLoaderEntry(VOID); VOID SetLoaderDefaults(LOADER_ENTRY *Entry, CHAR16 *LoaderPath, IN REFIT_VOLUME *Volume); LOADER_ENTRY * AddPreparedLoaderEntry(LOADER_ENTRY *Entry); VOID StoreLoaderName(IN CHAR16 *Name); VOID RescanAll(BOOLEAN DisplayMessage); #endif /* EOF */ ������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/refind/icns.h.orig��������������������������������������������������������������������0000664�0001750�0001750�00000007527�13141071401�016630� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * refit/icns.h * Icon management header file * * Copyright (c) 2006-2009 Christoph Pfisterer * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * * Neither the name of Christoph Pfisterer nor the names of the * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Modifications copyright (c) 2012-2015 Roderick W. Smith * * Modifications distributed under the terms of the GNU General Public * License (GPL) version 3 (GPLv3), a copy of which must be distributed * with this source code or binaries made from it. * */ #ifndef __ICNS_H_ #define __ICNS_H_ // // icns loader module // EG_IMAGE * LoadOSIcon(IN CHAR16 *OSIconName OPTIONAL, IN CHAR16 *FallbackIconName, BOOLEAN BootLogo); EG_IMAGE * DummyImage(IN UINTN PixelSize); EG_IMAGE * BuiltinIcon(IN UINTN Id); #define BUILTIN_ICON_FUNC_ABOUT (0) #define BUILTIN_ICON_FUNC_RESET (1) #define BUILTIN_ICON_FUNC_SHUTDOWN (2) #define BUILTIN_ICON_FUNC_EXIT (3) #define BUILTIN_ICON_FUNC_FIRMWARE (4) #define BUILTIN_ICON_FUNC_CSR_ROTATE (5) <<<<<<< HEAD #define BUILTIN_ICON_FUNC_HIDDEN (6) #define BUILTIN_ICON_TOOL_SHELL (7) #define BUILTIN_ICON_TOOL_PART (8) #define BUILTIN_ICON_TOOL_RESCUE (9) #define BUILTIN_ICON_TOOL_APPLE_RESCUE (10) #define BUILTIN_ICON_TOOL_WINDOWS_RESCUE (11) #define BUILTIN_ICON_TOOL_MOK_TOOL (12) #define BUILTIN_ICON_TOOL_FWUPDATE (13) #define BUILTIN_ICON_TOOL_MEMTEST (14) #define BUILTIN_ICON_TOOL_NETBOOT (15) #define BUILTIN_ICON_VOL_INTERNAL (16) #define BUILTIN_ICON_VOL_EXTERNAL (17) #define BUILTIN_ICON_VOL_OPTICAL (18) #define BUILTIN_ICON_VOL_NET (19) ======= #define BUILTIN_ICON_TOOL_SHELL (6) #define BUILTIN_ICON_TOOL_PART (7) #define BUILTIN_ICON_TOOL_RESCUE (8) #define BUILTIN_ICON_TOOL_APPLE_RESCUE (9) #define BUILTIN_ICON_TOOL_WINDOWS_RESCUE (10) #define BUILTIN_ICON_TOOL_MOK_TOOL (11) #define BUILTIN_ICON_TOOL_FWUPDATE (12) #define BUILTIN_ICON_TOOL_MEMTEST (13) #define BUILTIN_ICON_TOOL_NETBOOT (14) #define BUILTIN_ICON_VOL_INTERNAL (15) #define BUILTIN_ICON_VOL_EXTERNAL (16) #define BUILTIN_ICON_VOL_OPTICAL (17) #define BUILTIN_ICON_VOL_NET (18) #define BUILTIN_ICON_MOUSE (19) >>>>>>> d63734581c19715b3dc13ab89c520def8d5c4566 #define BUILTIN_ICON_COUNT (20) #endif /* EOF */ �������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/refind/Make.tiano���������������������������������������������������������������������0000664�0001750�0001750�00000006005�13141450277�016477� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # refind/Make.tiano # Build control file for rEFInd, using TianoCore EDK2 # Requires that EfiLib, mok, and libeg subdirectories be built before this # file is used. # # This program is licensed under the terms of the GNU GPL, version 3, # or (at your option) any later version. # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. include ../Make.common EFILIB = $(TIANOBASE)/Build/Mde/$(TARGET)_$(TOOL_CHAIN_TAG)/$(UC_ARCH)/MdePkg/Library ALL_EFILIBS = $(EFILIB)/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib/OUTPUT/BaseDebugPrintErrorLevelLib.lib \ $(EFILIB)/BasePrintLib/BasePrintLib/OUTPUT/BasePrintLib.lib \ $(EFILIB)/BasePcdLibNull/BasePcdLibNull/OUTPUT/BasePcdLibNull.lib \ $(EFILIB)/UefiDebugLibStdErr/UefiDebugLibStdErr/OUTPUT/UefiDebugLibStdErr.lib \ $(EFILIB)/BaseLib/BaseLib/OUTPUT/BaseLib.lib \ $(EFILIB)/BaseMemoryLib/BaseMemoryLib/OUTPUT/BaseMemoryLib.lib \ $(EFILIB)/UefiBootServicesTableLib/UefiBootServicesTableLib/OUTPUT/UefiBootServicesTableLib.lib \ $(EFILIB)/UefiMemoryAllocationLib/UefiMemoryAllocationLib/OUTPUT/UefiMemoryAllocationLib.lib \ $(EFILIB)/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib/OUTPUT/UefiRuntimeServicesTableLib.lib \ $(EFILIB)/UefiDevicePathLib/UefiDevicePathLib/OUTPUT/UefiDevicePathLib.lib \ $(EFILIB)/UefiLib/UefiLib/OUTPUT/UefiLib.lib \ $(EFILIB)/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull/OUTPUT/PeCoffExtraActionLibNull.lib \ $(EFILIB)/UefiApplicationEntryPoint/UefiApplicationEntryPoint/OUTPUT/UefiApplicationEntryPoint.lib \ $(EFILIB)/DxeServicesLib/DxeServicesLib/OUTPUT/DxeServicesLib.lib \ $(EFILIB)/DxeServicesTableLib/DxeServicesTableLib/OUTPUT/DxeServicesTableLib.lib \ $(EFILIB)/DxeHobLib/DxeHobLib/OUTPUT/DxeHobLib.lib \ $(EFILIB)/BasePeCoffLib/BasePeCoffLib/OUTPUT/BasePeCoffLib.lib ifeq ($(ARCH),aarch64) ALL_EFILIBS += $(EFILIB)/BaseStackCheckLib/BaseStackCheckLib/OUTPUT/BaseStackCheckLib.lib endif SOURCE_NAMES = apple config mystrings line_edit driver_support icns \ lib main menu pointer screen gpt crc32 legacy AutoGen OBJS = $(SOURCE_NAMES:=.obj) all: $(BUILDME) $(AR_TARGET): $(OBJS) $(AR) -cr $(AR_TARGET).lib $(OBJS) $(DLL_TARGET)_$(FILENAME_CODE).dll: $(OBJS) ../libeg/libeg.lib ../EfiLib/EfiLib.lib ../mok/mok.lib $(LD) -o $(DLL_TARGET)_$(FILENAME_CODE).dll $(TIANO_LDFLAGS) \ --start-group $(ALL_EFILIBS) $(OBJS) ../libeg/libeg.lib \ ../EfiLib/EfiLib.lib ../mok/mok.lib --end-group $(BUILDME): $(DLL_TARGET)_$(FILENAME_CODE).dll $(OBJCOPY) --strip-unneeded -R .eh_frame $(DLL_TARGET)_$(FILENAME_CODE).dll $(GENFW) -e UEFI_APPLICATION -o $(BUILDME)_$(FILENAME_CODE).efi \ $(DLL_TARGET)_$(FILENAME_CODE).dll clean: make clean ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/��������������������������������������������������������������������������0000755�0001750�0001750�00000000000�13372347460�015670� 5����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/ext4.inf������������������������������������������������������������������0000664�0001750�0001750�00000003652�13112553164�017252� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������## @file # # ext4.inf file to build rEFInd's ext4fs driver using the EDK2/UDK201# # development kit. # # Copyright (c) 2012-2017 by Roderick W. Smith # Released under the terms of the GPLv3 (or, at your discretion, any later # version), a copy of which should come with this file. # ## [Defines] INF_VERSION = 0x00010005 BASE_NAME = ext4 FILE_GUID = FD60D756-A4A9-4B87-BABF-E246DA740D4C MODULE_TYPE = UEFI_DRIVER EDK_RELEASE_VERSION = 0x00020000 EFI_SPECIFICATION_VERSION = 0x00010000 VERSION_STRING = 1.0 ENTRY_POINT = fsw_efi_main FSTYPE = ext4 # # The following information is for reference only and not required by the build tools. # # VALID_ARCHITECTURES = IA32 X64 IPF EBC # [Sources] fsw_efi.c fsw_ext4.c fsw_core.c fsw_efi.c fsw_lib.c fsw_efi_lib.c [Packages] MdePkg/MdePkg.dec MdeModulePkg/MdeModulePkg.dec IntelFrameworkPkg/IntelFrameworkPkg.dec IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec [LibraryClasses] UefiDriverEntryPoint DxeServicesLib DxeServicesTableLib MemoryAllocationLib [LibraryClasses.AARCH64] BaseStackCheckLib # Comment out CompilerIntrinsicsLib when compiling for AARCH64 using UDK2014 CompilerIntrinsicsLib [Guids] [Ppis] [Protocols] [FeaturePcd] [Pcd] [BuildOptions.IA32] XCODE:*_*_*_CC_FLAGS = -Os -DEFI32 -D__MAKEWITH_TIANO -DFSTYPE=ext4 GCC:*_*_*_CC_FLAGS = -Os -DEFI32 -D__MAKEWITH_TIANO -DFSTYPE=ext4 [BuildOptions.X64] XCODE:*_*_*_CC_FLAGS = -Os -DEFIX64 -D__MAKEWITH_TIANO -DFSTYPE=ext4 GCC:*_*_*_CC_FLAGS = -Os -DEFIX64 -D__MAKEWITH_TIANO -DFSTYPE=ext4 [BuildOptions.AARCH64] XCODE:*_*_*_CC_FLAGS = -Os -DEFIAARCH64 -D__MAKEWITH_TIANO -DFSTYPE=ext4 GCC:*_*_*_CC_FLAGS = -Os -DEFIAARCH64 -D__MAKEWITH_TIANO -DFSTYPE=ext4 ��������������������������������������������������������������������������������������refind-0.11.4/filesystems/test/���������������������������������������������������������������������0000775�0001750�0001750�00000000000�12626644770�016656� 5����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/test/fsw_posix.h����������������������������������������������������������0000664�0001750�0001750�00000006341�12626644770�021054� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/** * \file fsw_posix.h * POSIX user space host environment header. */ /*- * Copyright (c) 2006 Christoph Pfisterer * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * * Neither the name of Christoph Pfisterer nor the names of the * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _FSW_POSIX_H_ #define _FSW_POSIX_H_ #include "fsw_core.h" #include <fcntl.h> #include <sys/types.h> #include <sys/dir.h> /** * POSIX Host: Private per-volume structure. */ struct fsw_posix_volume { struct fsw_volume *vol; //!< FSW volume structure int fd; //!< System file descriptor for data access }; /** * POSIX Host: Private structure for an open file. */ struct fsw_posix_file { struct fsw_posix_volume *pvol; //!< POSIX host volume structure struct fsw_shandle shand; //!< FSW handle for this file }; /** * POSIX Host: Private structure for an open directory. */ struct fsw_posix_dir { struct fsw_posix_volume *pvol; //!< POSIX host volume structure struct fsw_shandle shand; //!< FSW handle for this file }; /* functions */ struct fsw_posix_volume * fsw_posix_mount(const char *path, struct fsw_fstype_table *fstype_table); int fsw_posix_unmount(struct fsw_posix_volume *pvol); struct fsw_posix_file * fsw_posix_open(struct fsw_posix_volume *pvol, const char *path, int flags, mode_t mode); ssize_t fsw_posix_read(struct fsw_posix_file *file, void *buf, size_t nbytes); off_t fsw_posix_lseek(struct fsw_posix_file *file, off_t offset, int whence); int fsw_posix_close(struct fsw_posix_file *file); struct fsw_posix_dir * fsw_posix_opendir(struct fsw_posix_volume *pvol, const char *path); struct dirent * fsw_posix_readdir(struct fsw_posix_dir *dir); void fsw_posix_rewinddir(struct fsw_posix_dir *dir); int fsw_posix_closedir(struct fsw_posix_dir *dir); #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/test/fsw_posix.c����������������������������������������������������������0000664�0001750�0001750�00000032703�12626644770�021050� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/** * \file fsw_posix.c * POSIX user space host environment code. */ /*- * Copyright (c) 2006 Christoph Pfisterer * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * * Neither the name of Christoph Pfisterer nor the names of the * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "fsw_posix.h" #ifndef FSTYPE /** The file system type name to use. */ #define FSTYPE ext2 #endif // function prototypes fsw_status_t fsw_posix_open_dno(struct fsw_posix_volume *pvol, const char *path, int required_type, struct fsw_shandle *shand); void fsw_posix_change_blocksize(struct fsw_volume *vol, fsw_u32 old_phys_blocksize, fsw_u32 old_log_blocksize, fsw_u32 new_phys_blocksize, fsw_u32 new_log_blocksize); fsw_status_t fsw_posix_read_block(struct fsw_volume *vol, fsw_u32 phys_bno, void *buffer); /** * Dispatch table for our FSW host driver. */ struct fsw_host_table fsw_posix_host_table = { FSW_STRING_TYPE_ISO88591, fsw_posix_change_blocksize, fsw_posix_read_block }; extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(FSTYPE); /** * Mount function. */ struct fsw_posix_volume * fsw_posix_mount(const char *path, struct fsw_fstype_table *fstype_table) { fsw_status_t status; struct fsw_posix_volume *pvol; // allocate volume structure status = fsw_alloc_zero(sizeof(struct fsw_posix_volume), (void **)&pvol); if (status) return NULL; pvol->fd = -1; // open underlying file/device pvol->fd = open(path, O_RDONLY, 0); if (pvol->fd < 0) { fprintf(stderr, "fsw_posix_mount: %s: %s\n", path, strerror(errno)); fsw_free(pvol); return NULL; } // mount the filesystem if (fstype_table == NULL) fstype_table = &FSW_FSTYPE_TABLE_NAME(FSTYPE); status = fsw_mount(pvol, &fsw_posix_host_table, fstype_table, &pvol->vol); if (status) { fprintf(stderr, "fsw_posix_mount: fsw_mount returned %d\n", status); fsw_free(pvol); return NULL; } return pvol; } /** * Unmount function. */ int fsw_posix_unmount(struct fsw_posix_volume *pvol) { if (pvol->vol != NULL) fsw_unmount(pvol->vol); fsw_free(pvol); return 0; } /** * Open a named regular file. */ struct fsw_posix_file * fsw_posix_open(struct fsw_posix_volume *pvol, const char *path, int flags, mode_t mode) { fsw_status_t status; struct fsw_posix_file *file; // TODO: check flags for unwanted values // allocate file structure status = fsw_alloc(sizeof(struct fsw_posix_file), &file); if (status) return NULL; file->pvol = pvol; // open the file status = fsw_posix_open_dno(pvol, path, FSW_DNODE_TYPE_FILE, &file->shand); if (status) { fprintf(stderr, "fsw_posix_open: open_dno returned %d\n", status); fsw_free(file); return NULL; } return file; } /** * Read data from a regular file. */ ssize_t fsw_posix_read(struct fsw_posix_file *file, void *buf, size_t nbytes) { fsw_status_t status; fsw_u32 buffer_size; buffer_size = nbytes; status = fsw_shandle_read(&file->shand, &buffer_size, buf); if (status) return -1; return buffer_size; } /** * Change position within a regular file. */ off_t fsw_posix_lseek(struct fsw_posix_file *file, off_t offset, int whence) { fsw_u64 base_offset = 0; // get base offset base_offset = 0; if (whence == SEEK_CUR) base_offset = file->shand.pos; else if (whence == SEEK_END) base_offset = file->shand.dnode->size; // calculate new offset, prevent seeks before the start of the file if (offset < 0 && -offset > base_offset) file->shand.pos = 0; else file->shand.pos = base_offset + offset; return file->shand.pos; } /** * Close a regular file. */ int fsw_posix_close(struct fsw_posix_file *file) { fsw_shandle_close(&file->shand); fsw_free(file); return 0; } /** * Open a directory for iteration. */ struct fsw_posix_dir * fsw_posix_opendir(struct fsw_posix_volume *pvol, const char *path) { fsw_status_t status; struct fsw_posix_dir *dir; // allocate file structure status = fsw_alloc(sizeof(struct fsw_posix_dir), &dir); if (status) return NULL; dir->pvol = pvol; // open the directory status = fsw_posix_open_dno(pvol, path, FSW_DNODE_TYPE_DIR, &dir->shand); if (status) { fprintf(stderr, "fsw_posix_opendir: open_dno returned %d\n", status); fsw_free(dir); return NULL; } return dir; } /** * Read the next entry from a directory. */ struct dirent * fsw_posix_readdir(struct fsw_posix_dir *dir) { fsw_status_t status; struct fsw_dnode *dno; static struct dirent dent; // get next entry from file system status = fsw_dnode_dir_read(&dir->shand, &dno); if (status) { if (status != 4) fprintf(stderr, "fsw_posix_readdir: fsw_dnode_dir_read returned %d\n", status); return NULL; } status = fsw_dnode_fill(dno); if (status) { fprintf(stderr, "fsw_posix_readdir: fsw_dnode_fill returned %d\n", status); fsw_dnode_release(dno); return NULL; } // fill dirent structure dent.d_fileno = dno->dnode_id; dent.d_reclen = 8 + dno->name.size + 1; switch (dno->type) { case FSW_DNODE_TYPE_FILE: dent.d_type = DT_REG; break; case FSW_DNODE_TYPE_DIR: dent.d_type = DT_DIR; break; case FSW_DNODE_TYPE_SYMLINK: dent.d_type = DT_LNK; break; default: dent.d_type = DT_UNKNOWN; break; } #if 0 dent.d_namlen = dno->name.size; #endif memcpy(dent.d_name, dno->name.data, dno->name.size); dent.d_name[dno->name.size] = 0; return &dent; } /** * Rewind a directory to the start. */ void fsw_posix_rewinddir(struct fsw_posix_dir *dir) { dir->shand.pos = 0; } /** * Close a directory. */ int fsw_posix_closedir(struct fsw_posix_dir *dir) { fsw_shandle_close(&dir->shand); fsw_free(dir); return 0; } /** * Open a shand of a required type by path. */ fsw_status_t fsw_posix_open_dno(struct fsw_posix_volume *pvol, const char *path, int required_type, struct fsw_shandle *shand) { fsw_status_t status; struct fsw_dnode *dno; struct fsw_dnode *target_dno; struct fsw_string lookup_path; lookup_path.type = FSW_STRING_TYPE_ISO88591; lookup_path.len = strlen(path); lookup_path.size = lookup_path.len; lookup_path.data = (void *)path; // resolve the path (symlinks along the way are automatically resolved) status = fsw_dnode_lookup_path(pvol->vol->root, &lookup_path, '/', &dno); if (status) { fprintf(stderr, "fsw_posix_open_dno: fsw_dnode_lookup_path returned %d\n", status); return status; } // if the final node is a symlink, also resolve it status = fsw_dnode_resolve(dno, &target_dno); fsw_dnode_release(dno); if (status) { fprintf(stderr, "fsw_posix_open_dno: fsw_dnode_resolve returned %d\n", status); return status; } dno = target_dno; // check that it is a regular file status = fsw_dnode_fill(dno); if (status) { fprintf(stderr, "fsw_posix_open_dno: fsw_dnode_fill returned %d\n", status); fsw_dnode_release(dno); return status; } if (dno->type != required_type) { fprintf(stderr, "fsw_posix_open_dno: dnode is not of the requested type\n"); fsw_dnode_release(dno); return FSW_UNSUPPORTED; } // open shandle status = fsw_shandle_open(dno, shand); if (status) { fprintf(stderr, "fsw_posix_open_dno: fsw_shandle_open returned %d\n", status); } fsw_dnode_release(dno); return status; } /** * FSW interface function for block size changes. This function is called by the FSW core * when the file system driver changes the block sizes for the volume. */ void fsw_posix_change_blocksize(struct fsw_volume *vol, fsw_u32 old_phys_blocksize, fsw_u32 old_log_blocksize, fsw_u32 new_phys_blocksize, fsw_u32 new_log_blocksize) { // nothing to do } /** * FSW interface function to read data blocks. This function is called by the FSW core * to read a block of data from the device. The buffer is allocated by the core code. */ fsw_status_t fsw_posix_read_block(struct fsw_volume *vol, fsw_u32 phys_bno, void *buffer) { struct fsw_posix_volume *pvol = (struct fsw_posix_volume *)vol->host_data; off_t block_offset, seek_result; ssize_t read_result; FSW_MSG_DEBUGV((FSW_MSGSTR("fsw_posix_read_block: %d (%d)\n"), phys_bno, vol->phys_blocksize)); // read from disk block_offset = (off_t)phys_bno * vol->phys_blocksize; seek_result = lseek(pvol->fd, block_offset, SEEK_SET); if (seek_result != block_offset) return FSW_IO_ERROR; read_result = read(pvol->fd, buffer, vol->phys_blocksize); if (read_result != vol->phys_blocksize) return FSW_IO_ERROR; return FSW_SUCCESS; } /** * Time mapping callback for the fsw_dnode_stat call. This function converts * a Posix style timestamp into an EFI_TIME structure and writes it to the * appropriate member of the EFI_FILE_INFO structure that we're filling. */ /* static void fsw_posix_store_time_posix(struct fsw_dnode_stat *sb, int which, fsw_u32 posix_time) { EFI_FILE_INFO *FileInfo = (EFI_FILE_INFO *)sb->host_data; if (which == FSW_DNODE_STAT_CTIME) fsw_posix_decode_time(&FileInfo->CreateTime, posix_time); else if (which == FSW_DNODE_STAT_MTIME) fsw_posix_decode_time(&FileInfo->ModificationTime, posix_time); else if (which == FSW_DNODE_STAT_ATIME) fsw_posix_decode_time(&FileInfo->LastAccessTime, posix_time); } */ /** * Mode mapping callback for the fsw_dnode_stat call. This function looks at * the Posix mode passed by the file system driver and makes appropriate * adjustments to the EFI_FILE_INFO structure that we're filling. */ /* static void fsw_posix_store_attr_posix(struct fsw_dnode_stat *sb, fsw_u16 posix_mode) { EFI_FILE_INFO *FileInfo = (EFI_FILE_INFO *)sb->host_data; if ((posix_mode & S_IWUSR) == 0) FileInfo->Attribute |= EFI_FILE_READ_ONLY; } */ /** * Common function to fill an EFI_FILE_INFO with information about a dnode. */ /* EFI_STATUS fsw_posix_dnode_fill_FileInfo(IN FSW_VOLUME_DATA *Volume, IN struct fsw_dnode *dno, IN OUT UINTN *BufferSize, OUT VOID *Buffer) { EFI_STATUS Status; EFI_FILE_INFO *FileInfo; UINTN RequiredSize; struct fsw_dnode_stat sb; // make sure the dnode has complete info Status = fsw_posix_map_status(fsw_dnode_fill(dno), Volume); if (EFI_ERROR(Status)) return Status; // TODO: check/assert that the dno's name is in UTF16 // check buffer size RequiredSize = SIZE_OF_EFI_FILE_INFO + fsw_posix_strsize(&dno->name); if (*BufferSize < RequiredSize) { // TODO: wind back the directory in this case *BufferSize = RequiredSize; return EFI_BUFFER_TOO_SMALL; } // fill structure ZeroMem(Buffer, RequiredSize); FileInfo = (EFI_FILE_INFO *)Buffer; FileInfo->Size = RequiredSize; FileInfo->FileSize = dno->size; FileInfo->Attribute = 0; if (dno->type == FSW_DNODE_TYPE_DIR) FileInfo->Attribute |= EFI_FILE_DIRECTORY; fsw_posix_strcpy(FileInfo->FileName, &dno->name); // get the missing info from the fs driver ZeroMem(&sb, sizeof(struct fsw_dnode_stat)); sb.store_time_posix = fsw_posix_store_time_posix; sb.store_attr_posix = fsw_posix_store_attr_posix; sb.host_data = FileInfo; Status = fsw_posix_map_status(fsw_dnode_stat(dno, &sb), Volume); if (EFI_ERROR(Status)) return Status; FileInfo->PhysicalSize = sb.used_bytes; // prepare for return *BufferSize = RequiredSize; return EFI_SUCCESS; } */ // EOF �������������������������������������������������������������refind-0.11.4/filesystems/test/lslr.c���������������������������������������������������������������0000664�0001750�0001750�00000007547�12626644770�020013� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/** * \file lslr.c * Test program for the POSIX user space environment. */ /*- * Copyright (c) 2012 Stefan Agner * Copyright (c) 2006 Christoph Pfisterer * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * * Neither the name of Christoph Pfisterer nor the names of the * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define FSW_DEBUG_LEVEL 3 #include "fsw_posix.h" //extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(ext2); //extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(reiserfs); extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(FSTYPE); static struct fsw_fstype_table *fstypes[] = { //&FSW_FSTYPE_TABLE_NAME(ext2), //&FSW_FSTYPE_TABLE_NAME(reiserfs), &FSW_FSTYPE_TABLE_NAME(FSTYPE ), NULL }; static int listdir(struct fsw_posix_volume *vol, char *path, int level) { struct fsw_posix_dir *dir; struct dirent *dent; int i; char subpath[4096]; dir = fsw_posix_opendir(vol, path); if (dir == NULL) { fprintf(stderr, "opendir(%s) call failed.\n", path); return 1; } while ((dent = fsw_posix_readdir(dir)) != NULL) { for (i = 0; i < level*2; i++) fputc(' ', stderr); fprintf(stderr, "%d %s\n", dent->d_type, dent->d_name); if (dent->d_type == DT_DIR) { snprintf(subpath, 4095, "%s%s/", path, dent->d_name); listdir(vol, subpath, level + 1); } } fsw_posix_closedir(dir); return 0; } static int catfile(struct fsw_posix_volume *vol, char *path) { struct fsw_posix_file *file; int r; char buf[256]; file = fsw_posix_open(vol, path, 0, 0); if (file == NULL) { fprintf(stderr, "open(%s) call failed.\n", path); return 1; } while ((r=fsw_posix_read(file, buf, sizeof(buf))) > 0) { int i; for (i=0; i<r; i++) { printf("%c", buf[i]); } } fsw_posix_close(file); return 0; } int main(int argc, char **argv) { struct fsw_posix_volume *vol; int i; if (argc != 2) { fprintf(stderr, "Usage: lslr <file/device>\n"); return 1; } for (i = 0; fstypes[i]; i++) { vol = fsw_posix_mount(argv[1], fstypes[i]); if (vol != NULL) { fprintf(stderr, "Mounted as '%s'.\n", fstypes[i]->name.data); break; } } if (vol == NULL) { fprintf(stderr, "Mounting failed.\n"); return 1; } listdir(vol, "/boot/", 0); catfile(vol, "/boot/testfile.txt"); fsw_posix_unmount(vol); return 0; } // EOF ���������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/test/Makefile�������������������������������������������������������������0000664�0001750�0001750�00000001162�12626644770�020316� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� DRIVERNAME = xfs CC = /usr/bin/gcc CFLAGS = -Wall -g -D_REENTRANT -DVERSION=\"$(VERSION)\" -DHOST_POSIX -I ../ -DFSTYPE=$(DRIVERNAME) FSW_NAMES = ../fsw_core ../fsw_lib FSW_OBJS = $(FSW_NAMES:=.o) LSLR_OBJS = $(FSW_OBJS) ../fsw_$(DRIVERNAME).o fsw_posix.o lslr.o LSLR_BIN = lslr LSROOT_OBJS = $(FSW_OBJS) ../fsw_xfs.o .fsw_posix.o lsroot.o LSROOT_BIN = lsroot $(LSLR_BIN): $(LSLR_OBJS) $(CC) $(CFLAGS) -o $(LSLR_BIN) $(LSLR_OBJS) $(LDFLAGS) $(LSROOT_BIN): $(LSROOT_OBJS) $(CC) $(CFLAGS) -o $(LSROOT_BIN) $(LSROOT_OBJS) $(LDFLAGS) all: $(LSLR_BIN) $(LSROOT_BIN) clean: @rm -f *.o ../*.o lslr lsroot ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/test/fsw_posix_base.h�����������������������������������������������������0000664�0001750�0001750�00000005645�12626644770�022054� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/** * \file fsw_posix_base.h * Base definitions for the POSIX user space host environment. */ /*- * Copyright (c) 2006 Christoph Pfisterer * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * * Neither the name of Christoph Pfisterer nor the names of the * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _FSW_POSIX_BASE_H_ #define _FSW_POSIX_BASE_H_ #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <string.h> #include <unistd.h> #include <errno.h> #define FSW_LITTLE_ENDIAN (1) // TODO: use info from the headers to define FSW_LITTLE_ENDIAN or FSW_BIG_ENDIAN // types typedef int8_t fsw_s8; typedef uint8_t fsw_u8; typedef int16_t fsw_s16; typedef uint16_t fsw_u16; typedef int32_t fsw_s32; typedef uint32_t fsw_u32; typedef int64_t fsw_s64; typedef uint64_t fsw_u64; // allocation functions #define fsw_alloc(size, ptrptr) (((*(ptrptr) = malloc(size)) == NULL) ? FSW_OUT_OF_MEMORY : FSW_SUCCESS) #define fsw_free(ptr) free(ptr) // memory functions #define fsw_memzero(dest,size) memset(dest,0,size) #define fsw_memcpy(dest,src,size) memcpy(dest,src,size) #define fsw_memeq(p1,p2,size) (memcmp(p1,p2,size) == 0) // message printing #define FSW_MSGSTR(s) s #define FSW_MSGFUNC(str, ...) (fprintf(stderr, str, ##__VA_ARGS__)) // 64-bit hooks #define FSW_U64_SHR(val,shiftbits) ((val) >> (shiftbits)) #define FSW_U64_DIV(val,divisor) ((val) / (divisor)) #define DEBUG(x) #define RShiftU64(val, shift) ((val) >> (shift)) #define LShiftU64(val, shift) ((val) << (shift)) #endif �������������������������������������������������������������������������������������������refind-0.11.4/filesystems/test/README���������������������������������������������������������������0000664�0001750�0001750�00000000206�12626644770�017534� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������This folder contains tests for VBoxFsDxe module, allowing up and test filesystems without EFI environment and launching whole VBox. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/test/lsroot.c�������������������������������������������������������������0000664�0001750�0001750�00000005527�12626644770�020355� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/** * \file lsroot.c * Example program for the POSIX user space environment. */ /*- * Copyright (c) 2006 Christoph Pfisterer * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * * Neither the name of Christoph Pfisterer nor the names of the * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "fsw_posix.h" extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(reiserfs); extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(iso9660); extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(hfs); extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(ext2); extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(ext4); int main(int argc, char **argv) { struct fsw_posix_volume *vol; struct fsw_posix_dir *dir; struct dirent *dent; if (argc != 2) { fprintf(stderr, "Usage: lsroot <file/device>\n"); return 1; } //vol = fsw_posix_mount(argv[1], &FSW_FSTYPE_TABLE_NAME(ext2)); //vol = fsw_posix_mount(argv[1], &FSW_FSTYPE_TABLE_NAME(reiserfs)); vol = fsw_posix_mount(argv[1], &FSW_FSTYPE_TABLE_NAME(FSTYPE)); if (vol == NULL) { fprintf(stderr, "Mounting failed.\n"); return 1; } //dir = fsw_posix_opendir(vol, "/drivers/net/"); dir = fsw_posix_opendir(vol, "/"); if (dir == NULL) { fprintf(stderr, "opendir call failed.\n"); return 1; } while ((dent = fsw_posix_readdir(dir)) != NULL) { fprintf(stderr, "- %s\n", dent->d_name); } fsw_posix_closedir(dir); fsw_posix_unmount(vol); return 0; } // EOF �������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/gzio.c��������������������������������������������������������������������0000664�0001750�0001750�00000101172�13111657653�017007� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * this file take from grub 2.0 * for btrfs UEFI driver */ /* gzio.c - decompression support for gzip */ /* * GRUB -- GRand Unified Bootloader * Copyright (C) 1999,2005,2006,2007,2009 Free Software Foundation, Inc. * * GRUB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRUB is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GRUB. If not, see <http://www.gnu.org/licenses/>. */ /* * Most of this file was originally the source file "inflate.c", written * by Mark Adler. It has been very heavily modified. In particular, the * original would run through the whole file at once, and this version can * be stopped and restarted on any boundary during the decompression process. * * The license and header comments that file are included here. */ /* inflate.c -- Not copyrighted 1992 by Mark Adler version c10p1, 10 January 1993 */ /* You can do whatever you like with this source file, though I would prefer that if you modify it and redistribute it that you include comments to that effect with your name and the date. Thank you. */ #if 0 #include <grub/err.h> #include <grub/types.h> #include <grub/mm.h> #include <grub/misc.h> #include <grub/fs.h> #include <grub/file.h> #include <grub/dl.h> #include <grub/deflate.h> #include <grub/i18n.h> GRUB_MOD_LICENSE ("GPLv3+"); #endif /* * Window Size * * This must be a power of two, and at least 32K for zip's deflate method */ #define WSIZE 0x8000 #define INBUFSIZ 0x2000 /* The state stored in filesystem-specific data. */ struct grub_gzio { int err; /* If input is in memory following fields are used instead of file. */ int mem_input_size, mem_input_off; uint8_t *mem_input; /* The offset at which the data starts in the underlying file. */ int data_offset; /* The type of current block. */ int block_type; /* The length of current block. */ int block_len; /* The flag of the last block. */ int last_block; /* The flag of codes. */ int code_state; /* The length of a copy. */ unsigned inflate_n; /* The index of a copy. */ unsigned inflate_d; /* The input buffer. */ uint8_t inbuf[INBUFSIZ]; int inbuf_d; /* The bit buffer. */ unsigned long bb; /* The bits in the bit buffer. */ unsigned bk; /* The sliding window in uncompressed data. */ uint8_t slide[WSIZE]; /* Current position in the slide. */ unsigned wp; /* The literal/length code table. */ struct huft *tl; /* The distance code table. */ struct huft *td; /* The lookup bits for the literal/length code table. */ int bl; /* The lookup bits for the distance code table. */ int bd; /* The original offset value. */ int saved_offset; }; typedef struct grub_gzio *grub_gzio_t; /* Function prototypes */ static void initialize_tables (grub_gzio_t); /* Little-Endian defines for the 2-byte magic numbers for gzip files. */ #define GZIP_MAGIC grub_le_to_cpu16 (0x8B1F) #define OLD_GZIP_MAGIC grub_le_to_cpu16 (0x9E1F) /* Compression methods (see algorithm.doc) */ #define STORED 0 #define COMPRESSED 1 //#define PACKED 2 #define LZHED 3 /* methods 4 to 7 reserved */ #define DEFLATED 8 #define MAX_METHODS 9 /* gzip flag byte */ #define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ #define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ #define ORIG_NAME 0x08 /* bit 3 set: original file name present */ #define COMMENT 0x10 /* bit 4 set: file comment present */ #define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ #define RESERVED 0xC0 /* bit 6,7: reserved */ #define UNSUPPORTED_FLAGS (CONTINUATION | ENCRYPTED | RESERVED) /* inflate block codes */ #define INFLATE_STORED 0 #define INFLATE_FIXED 1 #define INFLATE_DYNAMIC 2 typedef unsigned char uch; typedef unsigned short ush; typedef unsigned long ulg; /* Huffman code lookup table entry--this entry is four bytes for machines that have 16-bit pointers (e.g. PC's in the small or medium model). Valid extra bits are 0..13. e == 15 is EOB (end of block), e == 16 means that v is a literal, 16 < e < 32 means that v is a pointer to the next table, which codes e - 16 bits, and lastly e == 99 indicates an unused code. If a code with e == 99 is looked up, this implies an error in the data. */ struct huft { uch e; /* number of extra bits or operation */ uch b; /* number of bits in this code or subcode */ union { ush n; /* literal, length base, or distance base */ struct huft *t; /* pointer to next level of table */ } v; }; /* The inflate algorithm uses a sliding 32K byte window on the uncompressed stream to find repeated byte strings. This is implemented here as a circular buffer. The index is updated simply by incrementing and then and'ing with 0x7fff (32K-1). */ /* It is left to other modules to supply the 32K area. It is assumed to be usable as if it were declared "uch slide[32768];" or as just "uch *slide;" and then malloc'ed in the latter case. The definition must be in unzip.h, included above. */ /* Tables for deflate from PKZIP's appnote.txt. */ static unsigned bitorder[] = { /* Order of the bit length code lengths */ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; static ush cplens[] = { /* Copy lengths for literal codes 257..285 */ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; /* note: see note #13 above about the 258 in this list. */ static ush cplext[] = { /* Extra bits for literal codes 257..285 */ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99}; /* 99==invalid */ static ush cpdist[] = { /* Copy offsets for distance codes 0..29 */ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577}; static ush cpdext[] = { /* Extra bits for distance codes */ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13}; /* Huffman code decoding is performed using a multi-level table lookup. The fastest way to decode is to simply build a lookup table whose size is determined by the longest code. However, the time it takes to build this table can also be a factor if the data being decoded is not very long. The most common codes are necessarily the shortest codes, so those codes dominate the decoding time, and hence the speed. The idea is you can have a shorter table that decodes the shorter, more probable codes, and then point to subsidiary tables for the longer codes. The time it costs to decode the longer codes is then traded against the time it takes to make longer tables. This results of this trade are in the variables lbits and dbits below. lbits is the number of bits the first level table for literal/ length codes can decode in one step, and dbits is the same thing for the distance codes. Subsequent tables are also less than or equal to those sizes. These values may be adjusted either when all of the codes are shorter than that, in which case the longest code length in bits is used, or when the shortest code is *longer* than the requested table size, in which case the length of the shortest code in bits is used. There are two different values for the two tables, since they code a different number of possibilities each. The literal/length table codes 286 possible values, or in a flat code, a little over eight bits. The distance table codes 30 possible values, or a little less than five bits, flat. The optimum values for speed end up being about one bit more than those, so lbits is 8+1 and dbits is 5+1. The optimum values may differ though from machine to machine, and possibly even between compilers. Your mileage may vary. */ static int lbits = 9; /* bits in base literal/length lookup table */ static int dbits = 6; /* bits in base distance lookup table */ /* If BMAX needs to be larger than 16, then h and x[] should be ulg. */ #define BMAX 16 /* maximum bit length of any code (16 for explode) */ #define N_MAX 288 /* maximum number of codes in any set */ /* Macros for inflate() bit peeking and grabbing. The usage is: NEEDBITS(j) x = b & mask_bits[j]; DUMPBITS(j) where NEEDBITS makes sure that b has at least j bits in it, and DUMPBITS removes the bits from b. The macros use the variable k for the number of bits in b. Normally, b and k are register variables for speed, and are initialized at the beginning of a routine that uses these macros from a global bit buffer and count. If we assume that EOB will be the longest code, then we will never ask for bits with NEEDBITS that are beyond the end of the stream. So, NEEDBITS should not read any more bytes than are needed to meet the request. Then no bytes need to be "returned" to the buffer at the end of the last block. However, this assumption is not true for fixed blocks--the EOB code is 7 bits, but the other literal/length codes can be 8 or 9 bits. (The EOB code is shorter than other codes because fixed blocks are generally short. So, while a block always has an EOB, many other literal/length codes have a significantly lower probability of showing up at all.) However, by making the first table have a lookup of seven bits, the EOB code will be found in that first lookup, and so will not require that too many bits be pulled from the stream. */ static ush mask_bits[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff }; #pragma GCC diagnostic ignored "-Wunsafe-loop-optimizations" #define NEEDBITS(n) do {while(k<(n)){b|=((ulg)get_byte(gzio))<<k;k+=8;}} while (0) #define DUMPBITS(n) do {b>>=(n);k-=(n);} while (0) static int get_byte (grub_gzio_t gzio) { if (gzio->mem_input_off < gzio->mem_input_size) return gzio->mem_input[gzio->mem_input_off++]; return 0; } static void gzio_seek (grub_gzio_t gzio, grub_off_t off) { if (off > gzio->mem_input_size) gzio->err = -1; else gzio->mem_input_off = off; } /* more function prototypes */ static int huft_build (unsigned *, unsigned, unsigned, ush *, ush *, struct huft **, int *); static int huft_free (struct huft *); static int inflate_codes_in_window (grub_gzio_t); /* Given a list of code lengths and a maximum table size, make a set of tables to decode that set of codes. Return zero on success, one if the given code set is incomplete (the tables are still built in this case), two if the input is invalid (all zero length codes or an oversubscribed set of lengths), and three if not enough memory. */ static int huft_build (unsigned *b, /* code lengths in bits (all assumed <= BMAX) */ unsigned n, /* number of codes (assumed <= N_MAX) */ unsigned s, /* number of simple-valued codes (0..s-1) */ ush * d, /* list of base values for non-simple codes */ ush * e, /* list of extra bits for non-simple codes */ struct huft **t, /* result: starting table */ int *m) /* maximum lookup bits, returns actual */ { unsigned a; /* counter for codes of length k */ unsigned c[BMAX + 1]; /* bit length count table */ unsigned f; /* i repeats in table every f entries */ int g; /* maximum code length */ int h; /* table level */ register unsigned i; /* counter, current code */ register unsigned j; /* counter */ register int k; /* number of bits in current code */ int l; /* bits per table (returned in m) */ register unsigned *p; /* pointer into c[], b[], or v[] */ register struct huft *q; /* points to current table */ struct huft r; /* table entry for structure assignment */ struct huft *u[BMAX]; /* table stack */ unsigned v[N_MAX]; /* values in order of bit length */ register int w; /* bits before this table == (l * h) */ unsigned x[BMAX + 1]; /* bit offsets, then code stack */ unsigned *xp; /* pointer into x */ int y; /* number of dummy codes added */ unsigned z; /* number of entries in current table */ /* Generate counts for each bit length */ fsw_memzero ((char *) c, sizeof (c)); p = b; i = n; do { c[*p]++; /* assume all entries <= BMAX */ p++; /* Can't combine with above line (Solaris bug) */ } while (--i); if (c[0] == n) /* null input--all zero length codes */ { *t = (struct huft *) NULL; *m = 0; return 0; } /* Find minimum and maximum length, bound *m by those */ l = *m; for (j = 1; j <= BMAX; j++) if (c[j]) break; k = j; /* minimum code length */ if ((unsigned) l < j) l = j; for (i = BMAX; i; i--) if (c[i]) break; g = i; /* maximum code length */ if ((unsigned) l > i) l = i; *m = l; /* Adjust last length count to fill out codes, if needed */ for (y = 1 << j; j < i; j++, y <<= 1) if ((y -= c[j]) < 0) return 2; /* bad input: more codes than bits */ if ((y -= c[i]) < 0) return 2; c[i] += y; /* Generate starting offsets into the value table for each length */ x[1] = j = 0; p = c + 1; xp = x + 2; while (--i) { /* note that i == g from above */ *xp++ = (j += *p++); } /* Make a table of values in order of bit lengths */ p = b; i = 0; do { if ((j = *p++) != 0) v[x[j]++] = i; } while (++i < n); /* Generate the Huffman codes and for each, make the table entries */ x[0] = i = 0; /* first Huffman code is zero */ p = v; /* grab values in bit order */ h = -1; /* no tables yet--level -1 */ w = -l; /* bits decoded == (l * h) */ u[0] = (struct huft *) NULL; /* just to keep compilers happy */ q = (struct huft *) NULL; /* ditto */ z = 0; /* ditto */ /* go through the bit lengths (k already is bits in shortest code) */ for (; k <= g; k++) { a = c[k]; while (a--) { /* here i is the Huffman code of length k bits for value *p */ /* make tables up to required level */ while (k > w + l) { h++; w += l; /* previous table always l bits */ /* compute minimum size table less than or equal to l bits */ z = (z = (unsigned) (g - w)) > (unsigned) l ? (unsigned) l : z; /* upper limit on table size */ if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ { /* too few codes for k-w bit table */ f -= a + 1; /* deduct codes from patterns left */ xp = c + k; while (++j < z) /* try smaller tables up to z bits */ { if ((f <<= 1) <= *++xp) break; /* enough codes to use up j bits */ f -= *xp; /* else deduct codes from patterns */ } } z = 1 << j; /* table entries for j-bit table */ /* allocate and link in new table */ q = (struct huft *) AllocatePool ((z + 1) * sizeof (struct huft)); if (! q) { if (h) huft_free (u[0]); return 3; } *t = q + 1; /* link to list for huft_free() */ *(t = &(q->v.t)) = (struct huft *) NULL; u[h] = ++q; /* table starts after link */ /* connect to last table, if there is one */ if (h) { x[h] = i; /* save pattern for backing up */ r.b = (uch) l; /* bits to dump before this table */ r.e = (uch) (16 + j); /* bits in this table */ r.v.t = q; /* pointer to this table */ j = i >> (w - l); /* (get around Turbo C bug) */ u[h - 1][j] = r; /* connect to last table */ } } /* set up table entry in r */ r.b = (uch) (k - w); if (p >= v + n) r.e = 99; /* out of values--invalid code */ else if (*p < s) { r.e = (uch) (*p < 256 ? 16 : 15); /* 256 is end-of-block code */ r.v.n = (ush) (*p); /* simple code is just the value */ p++; /* one compiler does not like *p++ */ } else { r.e = (uch) e[*p - s]; /* non-simple--look up in lists */ r.v.n = d[*p++ - s]; } /* fill code-like entries with r */ f = 1 << (k - w); for (j = i >> w; j < z; j += f) q[j] = r; /* backwards increment the k-bit code i */ for (j = 1 << (k - 1); i & j; j >>= 1) i ^= j; i ^= j; /* backup over finished tables */ while ((i & ((1 << w) - 1)) != x[h]) { h--; /* don't need to update q */ w -= l; } } } /* Return true (1) if we were given an incomplete table */ return y != 0 && g != 1; } /* Free the malloc'ed tables built by huft_build(), which makes a linked list of the tables it made, with the links in a dummy first entry of each table. */ static int huft_free (struct huft *t) { register struct huft *p, *q; /* Go through linked list, freeing from the malloced (t[-1]) address. */ p = t; while (p != (struct huft *) NULL) { q = (--p)->v.t; FreePool ((char *) p); p = q; } return 0; } /* * inflate (decompress) the codes in a deflated (compressed) block. * Return an error code or zero if it all goes ok. */ static int inflate_codes_in_window (grub_gzio_t gzio) { register unsigned e; /* table entry flag/number of extra bits */ unsigned n, d; /* length and index for copy */ unsigned w; /* current window position */ struct huft *t; /* pointer to table entry */ unsigned ml, md; /* masks for bl and bd bits */ register ulg b; /* bit buffer */ register unsigned k; /* number of bits in bit buffer */ /* make local copies of globals */ d = gzio->inflate_d; n = gzio->inflate_n; b = gzio->bb; /* initialize bit buffer */ k = gzio->bk; w = gzio->wp; /* initialize window position */ /* inflate the coded data */ ml = mask_bits[gzio->bl]; /* precompute masks for speed */ md = mask_bits[gzio->bd]; for (;;) /* do until end of block */ { if (! gzio->code_state) { NEEDBITS ((unsigned) gzio->bl); if ((e = (t = gzio->tl + ((unsigned) b & ml))->e) > 16) do { if (e == 99) { gzio->err = -1; return 1; } DUMPBITS (t->b); e -= 16; NEEDBITS (e); } while ((e = (t = t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16); DUMPBITS (t->b); if (e == 16) /* then it's a literal */ { gzio->slide[w++] = (uch) t->v.n; if (w == WSIZE) break; } else /* it's an EOB or a length */ { /* exit if end of block */ if (e == 15) { gzio->block_len = 0; break; } /* get length of block to copy */ NEEDBITS (e); n = t->v.n + ((unsigned) b & mask_bits[e]); DUMPBITS (e); /* decode distance of block to copy */ NEEDBITS ((unsigned) gzio->bd); if ((e = (t = gzio->td + ((unsigned) b & md))->e) > 16) do { if (e == 99) { gzio->err = -1; return 1; } DUMPBITS (t->b); e -= 16; NEEDBITS (e); } while ((e = (t = t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16); DUMPBITS (t->b); NEEDBITS (e); d = w - t->v.n - ((unsigned) b & mask_bits[e]); DUMPBITS (e); gzio->code_state++; } } if (gzio->code_state) { /* do the copy */ do { n -= (e = (e = WSIZE - ((d &= WSIZE - 1) > w ? d : w)) > n ? n : e); if (w - d >= e) { fsw_memcpy (gzio->slide + w, gzio->slide + d, e); w += e; d += e; } else /* purposefully use the overlap for extra copies here!! */ { while (e--) gzio->slide[w++] = gzio->slide[d++]; } if (w == WSIZE) break; } while (n); if (! n) gzio->code_state--; /* did we break from the loop too soon? */ if (w == WSIZE) break; } } /* restore the globals from the locals */ gzio->inflate_d = d; gzio->inflate_n = n; gzio->wp = w; /* restore global window pointer */ gzio->bb = b; /* restore global bit buffer */ gzio->bk = k; return ! gzio->block_len; } /* get header for an inflated type 0 (stored) block. */ static void init_stored_block (grub_gzio_t gzio) { register ulg b; /* bit buffer */ register unsigned k; /* number of bits in bit buffer */ /* make local copies of globals */ b = gzio->bb; /* initialize bit buffer */ k = gzio->bk; /* go to byte boundary */ DUMPBITS (k & 7); /* get the length and its complement */ NEEDBITS (16); gzio->block_len = ((unsigned) b & 0xffff); DUMPBITS (16); NEEDBITS (16); if (gzio->block_len != (int) ((~b) & 0xffff)) gzio->err = -1; DUMPBITS (16); /* restore global variables */ gzio->bb = b; gzio->bk = k; } /* get header for an inflated type 1 (fixed Huffman codes) block. We should either replace this with a custom decoder, or at least precompute the Huffman tables. */ static void init_fixed_block (grub_gzio_t gzio) { int i; /* temporary variable */ unsigned l[288]; /* length list for huft_build */ /* set up literal table */ for (i = 0; i < 144; i++) l[i] = 8; for (; i < 256; i++) l[i] = 9; for (; i < 280; i++) l[i] = 7; for (; i < 288; i++) /* make a complete, but wrong code set */ l[i] = 8; gzio->bl = 7; if (huft_build (l, 288, 257, cplens, cplext, &gzio->tl, &gzio->bl) != 0) { gzio->err = -1; return; } /* set up distance table */ for (i = 0; i < 30; i++) /* make an incomplete code set */ l[i] = 5; gzio->bd = 5; if (huft_build (l, 30, 0, cpdist, cpdext, &gzio->td, &gzio->bd) > 1) { gzio->err = -1; huft_free (gzio->tl); gzio->tl = 0; return; } /* indicate we're now working on a block */ gzio->code_state = 0; gzio->block_len++; } /* get header for an inflated type 2 (dynamic Huffman codes) block. */ static void init_dynamic_block (grub_gzio_t gzio) { int i; /* temporary variables */ unsigned j; unsigned l; /* last length */ unsigned m; /* mask for bit lengths table */ unsigned n; /* number of lengths to get */ unsigned nb; /* number of bit length codes */ unsigned nl; /* number of literal/length codes */ unsigned nd; /* number of distance codes */ unsigned ll[286 + 30]; /* literal/length and distance code lengths */ register ulg b; /* bit buffer */ register unsigned k; /* number of bits in bit buffer */ /* make local bit buffer */ b = gzio->bb; k = gzio->bk; /* read in table lengths */ NEEDBITS (5); nl = 257 + ((unsigned) b & 0x1f); /* number of literal/length codes */ DUMPBITS (5); NEEDBITS (5); nd = 1 + ((unsigned) b & 0x1f); /* number of distance codes */ DUMPBITS (5); NEEDBITS (4); nb = 4 + ((unsigned) b & 0xf); /* number of bit length codes */ DUMPBITS (4); if (nl > 286 || nd > 30) { gzio->err = -1; return; } /* read in bit-length-code lengths */ for (j = 0; j < nb; j++) { NEEDBITS (3); ll[bitorder[j]] = (unsigned) b & 7; DUMPBITS (3); } for (; j < 19; j++) ll[bitorder[j]] = 0; /* build decoding table for trees--single level, 7 bit lookup */ gzio->bl = 7; if (huft_build (ll, 19, 19, NULL, NULL, &gzio->tl, &gzio->bl) != 0) { gzio->err = -1; return; } /* read in literal and distance code lengths */ n = nl + nd; m = mask_bits[gzio->bl]; i = l = 0; while ((unsigned) i < n) { NEEDBITS ((unsigned) gzio->bl); j = (gzio->td = gzio->tl + ((unsigned) b & m))->b; DUMPBITS (j); j = gzio->td->v.n; if (j < 16) /* length of code in bits (0..15) */ ll[i++] = l = j; /* save last length in l */ else if (j == 16) /* repeat last length 3 to 6 times */ { NEEDBITS (2); j = 3 + ((unsigned) b & 3); DUMPBITS (2); if ((unsigned) i + j > n) { gzio->err = -1; return; } while (j--) ll[i++] = l; } else if (j == 17) /* 3 to 10 zero length codes */ { NEEDBITS (3); j = 3 + ((unsigned) b & 7); DUMPBITS (3); if ((unsigned) i + j > n) { gzio->err = -1; return; } while (j--) ll[i++] = 0; l = 0; } else /* j == 18: 11 to 138 zero length codes */ { NEEDBITS (7); j = 11 + ((unsigned) b & 0x7f); DUMPBITS (7); if ((unsigned) i + j > n) { gzio->err = -1; return; } while (j--) ll[i++] = 0; l = 0; } } /* free decoding table for trees */ huft_free (gzio->tl); gzio->td = 0; gzio->tl = 0; /* restore the global bit buffer */ gzio->bb = b; gzio->bk = k; /* build the decoding tables for literal/length and distance codes */ gzio->bl = lbits; if (huft_build (ll, nl, 257, cplens, cplext, &gzio->tl, &gzio->bl) != 0) { gzio->err = -1; return; } gzio->bd = dbits; if (huft_build (ll + nl, nd, 0, cpdist, cpdext, &gzio->td, &gzio->bd) != 0) { huft_free (gzio->tl); gzio->tl = 0; gzio->err = -1; return; } /* indicate we're now working on a block */ gzio->code_state = 0; gzio->block_len++; } static void get_new_block (grub_gzio_t gzio) { register ulg b; /* bit buffer */ register unsigned k; /* number of bits in bit buffer */ /* make local bit buffer */ b = gzio->bb; k = gzio->bk; /* read in last block bit */ NEEDBITS (1); gzio->last_block = (int) b & 1; DUMPBITS (1); /* read in block type */ NEEDBITS (2); gzio->block_type = (unsigned) b & 3; DUMPBITS (2); /* restore the global bit buffer */ gzio->bb = b; gzio->bk = k; switch (gzio->block_type) { case INFLATE_STORED: init_stored_block (gzio); break; case INFLATE_FIXED: init_fixed_block (gzio); break; case INFLATE_DYNAMIC: init_dynamic_block (gzio); break; default: break; } } static void inflate_window (grub_gzio_t gzio) { /* initialize window */ gzio->wp = 0; /* * Main decompression loop. */ while (gzio->wp < WSIZE && !gzio->err) { if (! gzio->block_len) { if (gzio->last_block) break; get_new_block (gzio); } if (gzio->block_type > INFLATE_DYNAMIC) gzio->err = -1; if (gzio->err) return; /* * Expand stored block here. */ if (gzio->block_type == INFLATE_STORED) { int w = gzio->wp; /* * This is basically a glorified pass-through */ while (gzio->block_len && w < WSIZE && !gzio->err) { gzio->slide[w++] = get_byte (gzio); gzio->block_len--; } gzio->wp = w; continue; } /* * Expand other kind of block. */ if (inflate_codes_in_window (gzio)) { huft_free (gzio->tl); huft_free (gzio->td); gzio->tl = 0; gzio->td = 0; } } gzio->saved_offset += WSIZE; /* XXX do CRC calculation here! */ } static void initialize_tables (grub_gzio_t gzio) { gzio->saved_offset = 0; gzio_seek (gzio, gzio->data_offset); /* Initialize the bit buffer. */ gzio->bk = 0; gzio->bb = 0; /* Reset partial decompression code. */ gzio->last_block = 0; gzio->block_len = 0; /* Reset memory allocation stuff. */ huft_free (gzio->tl); huft_free (gzio->td); } static int test_zlib_header (grub_gzio_t gzio) { uint8_t cmf, flg; cmf = get_byte (gzio); flg = get_byte (gzio); /* Check that compression method is DEFLATE. */ if ((cmf & 0xf) != DEFLATED) { return 0; } if ((cmf * 256 + flg) % 31) { return 0; } /* Dictionary isn't supported. */ if (flg & 0x20) { return 0; } gzio->data_offset = 2; initialize_tables (gzio); return 1; } static grub_ssize_t grub_gzio_read_real (grub_gzio_t gzio, grub_off_t offset, char *buf, grub_size_t len) { grub_ssize_t ret = 0; /* Do we reset decompression to the beginning of the file? */ if (gzio->saved_offset > offset + WSIZE) initialize_tables (gzio); /* * This loop operates upon uncompressed data only. The only * special thing it does is to make sure the decompression * window is within the range of data it needs. */ while (len > 0 && !gzio->err) { register grub_size_t size; register char *srcaddr; while (offset >= gzio->saved_offset) inflate_window (gzio); srcaddr = (char *) ((offset & (WSIZE - 1)) + gzio->slide); size = gzio->saved_offset - offset; if (size > len) size = len; fsw_memcpy (buf, srcaddr, size); buf += size; len -= size; ret += size; offset += size; } if (gzio->err) ret = -1; return ret; } grub_ssize_t grub_zlib_decompress (char *inbuf, grub_size_t insize, grub_off_t off, char *outbuf, grub_size_t outsize) { grub_gzio_t gzio = 0; grub_ssize_t ret; gzio = AllocatePool (sizeof (*gzio)); if (! gzio) return -1; fsw_memzero(gzio, sizeof(*gzio)); gzio->mem_input = (uint8_t *) inbuf; gzio->mem_input_size = insize; gzio->mem_input_off = 0; if (!test_zlib_header (gzio)) { FreePool (gzio); return -1; } ret = grub_gzio_read_real (gzio, off, outbuf, outsize); FreePool (gzio); /* FIXME: Check Adler. */ return ret; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/reiserfs.inf��������������������������������������������������������������0000664�0001750�0001750�00000003724�13112552673�020214� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������## @file # # reiserfs.inf file to build rEFInd's Reiserfs driver using the EDK2/UDK201# # development kit. # # Copyright (c) 2012-2017 by Roderick W. Smith # Released under the terms of the GPLv3 (or, at your discretion, any later # version), a copy of which should come with this file. # ## [Defines] INF_VERSION = 0x00010005 BASE_NAME = reiserfs FILE_GUID = a62085ec-ab35-4964-bd45-eb0114b13d39 MODULE_TYPE = UEFI_DRIVER EDK_RELEASE_VERSION = 0x00020000 EFI_SPECIFICATION_VERSION = 0x00010000 VERSION_STRING = 1.0 ENTRY_POINT = fsw_efi_main FSTYPE = reiserfs # # The following information is for reference only and not required by the build tools. # # VALID_ARCHITECTURES = IA32 X64 IPF EBC # [Sources] fsw_efi.c fsw_reiserfs.c fsw_core.c fsw_efi.c fsw_lib.c fsw_efi_lib.c [Packages] MdePkg/MdePkg.dec MdeModulePkg/MdeModulePkg.dec IntelFrameworkPkg/IntelFrameworkPkg.dec IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec [LibraryClasses] UefiDriverEntryPoint DxeServicesLib DxeServicesTableLib MemoryAllocationLib [LibraryClasses.AARCH64] BaseStackCheckLib # Comment out CompilerIntrinsicsLib when compiling for AARCH64 using UDK2014 CompilerIntrinsicsLib [Guids] [Ppis] [Protocols] [FeaturePcd] [Pcd] [BuildOptions.IA32] XCODE:*_*_*_CC_FLAGS = -Os -DEFI32 -D__MAKEWITH_TIANO -DFSTYPE=reiserfs GCC:*_*_*_CC_FLAGS = -Os -DEFI32 -D__MAKEWITH_TIANO -DFSTYPE=reiserfs [BuildOptions.X64] XCODE:*_*_*_CC_FLAGS = -Os -DEFIX64 -D__MAKEWITH_TIANO -DFSTYPE=reiserfs GCC:*_*_*_CC_FLAGS = -Os -DEFIX64 -D__MAKEWITH_TIANO -DFSTYPE=reiserfs [BuildOptions.AARCH64] XCODE:*_*_*_CC_FLAGS = -Os -DEFIAARCH64 -D__MAKEWITH_TIANO -DFSTYPE=reiserfs GCC:*_*_*_CC_FLAGS = -Os -DEFIAARCH64 -D__MAKEWITH_TIANO -DFSTYPE=reiserfs ��������������������������������������������refind-0.11.4/filesystems/fsw_base.h����������������������������������������������������������������0000664�0001750�0001750�00000007646�12630652566�017653� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/** * \file fsw_base.h * Base definitions switch. */ /*- * This code is based on: * * Copyright (c) 2006 Christoph Pfisterer * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * * Neither the name of Christoph Pfisterer nor the names of the * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _FSW_BASE_H_ #define _FSW_BASE_H_ #ifdef __MAKEWITH_TIANO #include "fsw_efi_base.h" #endif #ifdef HOST_POSIX #include "test/fsw_posix_base.h" #endif #ifndef FSW_DEBUG_LEVEL /** * Global debugging level. Can be set locally for the scope of a single * file by defining the macro before fsw_base.h is included. */ #define FSW_DEBUG_LEVEL 1 #endif // message printing #if FSW_DEBUG_LEVEL >= 1 #define FSW_MSG_ASSERT(params) FSW_MSGFUNC params #else #define FSW_MSG_ASSERT(params) #endif #if FSW_DEBUG_LEVEL >= 2 #define FSW_MSG_DEBUG(params) FSW_MSGFUNC params #else #define FSW_MSG_DEBUG(params) #endif #if FSW_DEBUG_LEVEL >= 3 #define FSW_MSG_DEBUGV(params) FSW_MSGFUNC params #else #define FSW_MSG_DEBUGV(params) #endif // Documentation for system-dependent defines /** * \typedef fsw_s8 * Signed 8-bit integer. */ /** * \typedef fsw_u8 * Unsigned 8-bit integer. */ /** * \typedef fsw_s16 * Signed 16-bit integer. */ /** * \typedef fsw_u16 * Unsigned 16-bit integer. */ /** * \typedef fsw_s32 * Signed 32-bit integer. */ /** * \typedef fsw_u32 * Unsigned 32-bit integer. */ /** * \typedef fsw_s64 * Signed 64-bit integer. */ /** * \typedef fsw_u64 * Unsigned 64-bit integer. */ /** * \def fsw_alloc(size,ptrptr) * Allocate memory on the heap. This function or macro allocates \a size * bytes of memory using host-specific methods. The address of the * allocated memory block is stored into the pointer variable pointed * to by \a ptrptr. A status code is returned; FSW_SUCCESS if the block * was allocated or FSW_OUT_OF_MEMORY if there is not enough memory * to allocated the requested block. */ /** * \def fsw_free(ptr) * Release allocated memory. This function or macro returns an allocated * memory block to the heap for reuse. Does not return a status. */ /** * \def fsw_memcpy(dest,src,size) * Copies a block of memory from \a src to \a dest. The two memory blocks * must not overlap, or the result of the operation will be undefined. * Does not return a status. */ /** * \def fsw_memeq(dest,src,size) * Compares two blocks of memory for equality. Returns boolean true if the * memory blocks are equal, boolean false if they are different. */ /** * \def fsw_memzero(dest,size) * Initializes a block of memory with zeros. Does not return a status. */ #endif ������������������������������������������������������������������������������������������refind-0.11.4/filesystems/ntfs.inf������������������������������������������������������������������0000664�0001750�0001750�00000003650�13112553141�017331� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������## @file # # ntfs.inf file to build rEFInd's NTFS driver using the EDK2/UDK201# # development kit. # # Copyright (c) 2012-2017 by Roderick W. Smith # Released under the terms of the GPLv3 (or, at your discretion, any later # version), a copy of which should come with this file. # ## [Defines] INF_VERSION = 0x00010005 BASE_NAME = ntfs FILE_GUID = a916a90d-fb2c-4797-82cd-415c8802999f MODULE_TYPE = UEFI_DRIVER EDK_RELEASE_VERSION = 0x00020000 EFI_SPECIFICATION_VERSION = 0x00010000 VERSION_STRING = 1.0 ENTRY_POINT = fsw_efi_main FSTYPE = ntfs # # The following information is for reference only and not required by the build tools. # # VALID_ARCHITECTURES = IA32 X64 IPF EBC # [Sources] fsw_efi.c fsw_ntfs.c fsw_core.c fsw_efi.c fsw_lib.c fsw_efi_lib.c [Packages] MdePkg/MdePkg.dec MdeModulePkg/MdeModulePkg.dec IntelFrameworkPkg/IntelFrameworkPkg.dec IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec [LibraryClasses] UefiDriverEntryPoint DxeServicesLib DxeServicesTableLib MemoryAllocationLib [LibraryClasses.AARCH64] BaseStackCheckLib # Comment out CompilerIntrinsicsLib when compiling for AARCH64 using UDK2014 CompilerIntrinsicsLib [Guids] [Ppis] [Protocols] [FeaturePcd] [Pcd] [BuildOptions.IA32] XCODE:*_*_*_CC_FLAGS = -Os -DEFI32 -D__MAKEWITH_TIANO -DFSTYPE=ntfs GCC:*_*_*_CC_FLAGS = -Os -DEFI32 -D__MAKEWITH_TIANO -DFSTYPE=ntfs [BuildOptions.X64] XCODE:*_*_*_CC_FLAGS = -Os -DEFIX64 -D__MAKEWITH_TIANO -DFSTYPE=ntfs GCC:*_*_*_CC_FLAGS = -Os -DEFIX64 -D__MAKEWITH_TIANO -DFSTYPE=ntfs [BuildOptions.AARCH64] XCODE:*_*_*_CC_FLAGS = -Os -DEFIAARCH64 -D__MAKEWITH_TIANO -DFSTYPE=ntfs GCC:*_*_*_CC_FLAGS = -Os -DEFIAARCH64 -D__MAKEWITH_TIANO -DFSTYPE=ntfs ����������������������������������������������������������������������������������������refind-0.11.4/filesystems/fsw_ntfs.c����������������������������������������������������������������0000664�0001750�0001750�00000123103�13363360624�017664� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/** * \file fsw_ntfs.c * ntfs file system driver code. * Copyright (C) 2015 by Samuel Liao */ /*- * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "fsw_core.h" #define Print(x...) /* */ static inline fsw_u8 GETU8(fsw_u8 *buf, int pos) { return buf[pos]; } static inline fsw_u16 GETU16(fsw_u8 *buf, int pos) { return fsw_u16_le_swap(*(fsw_u16 *)(buf+pos)); } static inline fsw_u32 GETU32(fsw_u8 *buf, int pos) { return fsw_u32_le_swap(*(fsw_u32 *)(buf+pos)); } static inline fsw_u64 GETU64(fsw_u8 *buf, int pos) { return fsw_u64_le_swap(*(fsw_u64 *)(buf+pos)); } #define MFTMASK ((1ULL<<48) - 1) #define BADMFT (~0ULL) #define MFTNO_MFT 0 #define MFTNO_VOLUME 3 #define MFTNO_ROOT 5 #define MFTNO_UPCASE 10 #define MFTNO_META 16 #define BADVCN (~0ULL) #define AT_STANDARD_INFORMATION 0x10 #define AT_ATTRIBUTE_LIST 0x20 #define AT_FILENAME 0x30 /* UNUSED */ #define AT_VOLUME_NAME 0x60 #define AT_VOLUME_INFORMATION 0x70 /* UNUSED */ #define AT_DATA 0x80 #define AT_INDEX_ROOT 0x90 #define AT_INDEX_ALLOCATION 0xa0 #define AT_BITMAP 0xb0 #define AT_REPARSE_POINT 0xc0 #define ATTRMASK 0xFFFF #define ATTRBITS 16 /* $I30 is LE, we can't use L"$I30" */ #define NAME_I30 "$\0I\0003\0000\0" #define AT_I30 0x40000 static const fsw_u16 upcase[0x80] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, }; struct extent_slot { fsw_u64 vcn; fsw_u64 lcn; fsw_u64 cnt; }; struct extent_map { /* * we build mft extent table instead use generic code, to prevent * read_mft recursive or dead loop. * While mft has too many fragments, it need AT_ATTRIBUTE_LIST for extra * data, the AT_ATTRIBUTE_LIST parsing code need call read_mft again. */ struct extent_slot *extent; int total; int used; }; struct ntfs_mft { fsw_u64 mftno; /* current MFT no */ fsw_u8 *buf; /* current MFT record data */ fsw_u8 *atlst; /* AT_ATTRIBUTE_LIST data */ int atlen; /* AT_ATTRIBUTE_LIST size */ }; struct ntfs_attr { fsw_u64 emftno; /* MFT no of emft */ fsw_u8 *emft; /* cached extend MFT record */ fsw_u8 *ptr; /* current attribute data */ int len; /* current attribute size */ int type; /* current attribute type */ }; struct fsw_ntfs_volume { struct fsw_volume g; struct extent_map extmap; /* MFT extent map */ fsw_u64 totalbytes; /* volume size */ const fsw_u16 *upcase; /* upcase map for non-ascii */ int upcount; /* upcase map size */ fsw_u8 sctbits; /* sector size */ fsw_u8 clbits; /* cluster size */ fsw_u8 mftbits; /* MFT record size */ fsw_u8 idxbits; /* unused index size, use AT_INDEX_ROOT instead */ }; struct fsw_ntfs_dnode { struct fsw_dnode g; struct ntfs_mft mft; struct ntfs_attr attr; /* AT_INDEX_ALLOCATION:$I30/AT_DATA */ fsw_u8 *idxroot; /* AT_INDEX_ROOT:$I30 */ fsw_u8 *idxbmp; /* AT_BITMAP:$I30 */ unsigned int embeded:1; /* embeded AT_DATA */ unsigned int has_idxtree:1; /* valid AT_INDEX_ALLOCATION:$I30 */ unsigned int compressed:1; /* compressed AT_DATA */ unsigned int unreadable:1; /* unreadable/encrypted AT_DATA */ unsigned int cpfull:1; /* in-compressable chunk */ unsigned int cpzero:1; /* empty chunk */ unsigned int cperror:1; /* decompress error */ unsigned int islink:1; /* is symlink: AT_REPARSE_POINT */ int idxsz; /* size of index block */ int rootsz; /* size of idxroot: AT_INDEX_ROOT:$I30 */ int bmpsz; /* size of idxbmp: AT_BITMAP:$I30 */ struct extent_slot cext; /* cached extent */ fsw_u64 fsize; /* logical file size */ fsw_u64 finited; /* initialized file size */ fsw_u64 cvcn; /* vcn of compress chunk: cbuf */ fsw_u64 clcn[16]; /* cluster map of compress chunk */ fsw_u8 *cbuf; /* compress chunk/index block/symlink target */ }; static fsw_status_t fixup(fsw_u8 *record, char *magic, int sectorsize, int size) { int off, cnt, i; fsw_u16 val; if(*(int *)record != *(int *)magic) return FSW_VOLUME_CORRUPTED; off = GETU16(record, 4); cnt = GETU16(record, 6); if(size && sectorsize*(cnt-1) != size) return FSW_VOLUME_CORRUPTED; val = GETU16(record, off); for(i=1; i<cnt; i++) { if(GETU16(record, i*sectorsize-2)!=val) return FSW_VOLUME_CORRUPTED; *(fsw_u16 *)(record+i*sectorsize-2) = *(fsw_u16 *)(record+off+i*2); } return FSW_SUCCESS; } /* only supported attribute name is $I30 */ static fsw_status_t find_attribute_direct(fsw_u8 *mft, int mftsize, int type, fsw_u8 **outptr, int *outlen) { int namelen; fsw_u32 n; if(GETU32(mft, 0x18) < mftsize) mftsize = GETU32(mft, 0x18); mftsize -= GETU16(mft, 0x14); mft += GETU16(mft, 0x14); namelen = type>>ATTRBITS; type &= ATTRMASK; for(n = 0; mftsize >= 8; mft += n, mftsize -= n) { int t = GETU32(mft, 0); n = GETU32(mft, 4); if( t==0 || (t+1)==0 || t==0xffff || n<24 || mftsize<n) break; fsw_u8 ns = GETU8(mft, 9); fsw_u8 *nm = mft + GETU8(mft, 10); if(type==t && namelen==ns && (ns==0 || fsw_memeq(NAME_I30, nm, ns*2))) { if(outptr) *outptr = mft; if(outlen) *outlen = n; return FSW_SUCCESS; } } return FSW_NOT_FOUND; } /* only supported attribute name is $I30 */ static fsw_status_t find_attrlist_direct(fsw_u8 *atlst, int atlen, int type, fsw_u64 vcn, fsw_u64 *out, int *pos) { fsw_u64 mftno = BADMFT; int namelen; namelen = type>>ATTRBITS; type &= ATTRMASK; while( *pos + 0x18 <= atlen) { int off = *pos; fsw_u32 t = GETU32(atlst, off); fsw_u32 n = GETU16(atlst, off+4); *pos = off + n; if(t==0 || (t+1)==0 || t==0xffff || n < 0x18 || *pos > atlen) break; fsw_u8 ns = GETU8(atlst, off+6); fsw_u8 *nm = atlst + off + GETU8(atlst, off+7); if( type == t && namelen==ns && (ns==0 || fsw_memeq(NAME_I30, nm, ns*2))) { fsw_u64 avcn = GETU64(atlst, off+8); if(vcn < avcn) { if(mftno == BADMFT) return FSW_NOT_FOUND; *out = mftno; return FSW_SUCCESS; } if(vcn == avcn) { *out = GETU64(atlst, off+0x10) & MFTMASK; return FSW_SUCCESS; } mftno = GETU64(atlst, off+0x10) & MFTMASK; } } if(mftno != BADMFT) { *out = mftno; return FSW_SUCCESS; } return FSW_NOT_FOUND; } static fsw_status_t get_extent(fsw_u8 **rlep, int *rlenp, fsw_u64 *lcnp, fsw_u64 *lenp, fsw_u64 *pos) { fsw_u8 *rle = *rlep; fsw_u8 *rle_end = rle + *rlenp; int f = *rle++; fsw_u64 m = 1; fsw_u64 c = 0; fsw_u64 v = 0; int n = f & 0xf; if(n==0) return FSW_NOT_FOUND; if(rle + n > rle_end) return FSW_VOLUME_CORRUPTED; while(--n >= 0) { c += m * (*rle++); m <<= 8; } n = f >> 4; if(n==0) { /* LCN 0 as sparse, due to we don't need $Boot */ *lcnp = 0; *lenp = c; } else { if(rle + n > rle_end) return FSW_VOLUME_CORRUPTED; m = 1; while(--n >= 0) { v += m * (*rle++); m <<= 8; } *pos += v; if(v & (m>>1)) *pos -= m; *lcnp = *pos; *lenp = c; } *rlenp -= rle - *rlep; *rlep = rle; return FSW_SUCCESS; } static inline int attribute_ondisk(fsw_u8 *ptr, int len) { return GETU8(ptr, 8); } static inline int attribute_compressed(fsw_u8 *ptr, int len) { return (GETU8(ptr, 12) & 0xFF) == 1; } static inline int attribute_compressed_future(fsw_u8 *ptr, int len) { return (GETU8(ptr, 12) & 0xFF) > 1; } static inline int attribute_sparse(fsw_u8 *ptr, int len) { return GETU8(ptr, 12) & 0x8000; } static inline int attribute_encrypted(fsw_u8 *ptr, int len) { return GETU8(ptr, 12) & 0x4000; } static void attribute_get_embeded(fsw_u8 *ptr, int len, fsw_u8 **outp, int *outlenp) { int off = GETU16(ptr, 0x14); int olen = GETU16(ptr, 0x10); if(olen + off > len) olen = len - off; *outp = ptr + off; *outlenp = olen; } static void attribute_get_rle(fsw_u8 *ptr, int len, fsw_u8 **outp, int *outlenp) { int off = GETU16(ptr, 0x20); int olen = len - off; *outp = ptr + off; *outlenp = olen; } static inline int attribute_rle_offset(fsw_u8 *ptr, int len) { return GETU16(ptr, 0x20); } static inline fsw_u64 attribute_size(fsw_u8 *ptr, int len) { return GETU8(ptr, 8) ? GETU64(ptr, 0x30) : GETU16(ptr, 0x10); } static inline fsw_u64 attribute_inited_size(fsw_u8 *ptr, int len) { return GETU8(ptr, 8) ? GETU64(ptr, 0x38) : GETU16(ptr, 0x10); } static inline int attribute_has_vcn(fsw_u8 *ptr, int len, fsw_u64 vcn) { if(GETU8(ptr, 8)==0) return 1; return vcn >= GETU64(ptr, 0x10) && vcn <= GETU64(ptr, 0x18); } static inline fsw_u64 attribute_first_vcn(fsw_u8 *ptr, int len) { return GETU8(ptr, 8) ? GETU64(ptr, 0x10) : 0; } static inline fsw_u64 attribute_last_vcn(fsw_u8 *ptr, int len) { return GETU8(ptr, 8) ? GETU64(ptr, 0x18) : 0; } static fsw_status_t read_attribute_direct(struct fsw_ntfs_volume *vol, fsw_u8 *ptr, int len, fsw_u8 **optrp, int *olenp) { fsw_status_t err; int olen; if(attribute_ondisk(ptr, len) == 0) { /* EMBEDED DATA */ attribute_get_embeded(ptr, len, &ptr, &len); *olenp = len; if(optrp) { if((err = fsw_alloc(len, (void **)optrp)) != FSW_SUCCESS) return err; fsw_memcpy(*optrp, ptr, len); } return FSW_SUCCESS; } olen = attribute_size(ptr, len); *olenp = olen; if(!optrp) return FSW_SUCCESS; if((err = fsw_alloc_zero(olen, (void **)optrp)) != FSW_SUCCESS) return err; fsw_u8 *buf = *optrp; attribute_get_rle(ptr, len, &ptr, &len); fsw_u64 pos = 0; int clustersize = 1<<vol->clbits; fsw_u64 lcn, cnt; while(len > 0 && get_extent(&ptr, &len, &lcn, &cnt, &pos)==FSW_SUCCESS) { if(lcn) { for(; cnt>0; lcn++, cnt--) { fsw_u8 *block; if (fsw_block_get(&vol->g, lcn, 0, (void **)&block) != FSW_SUCCESS) { fsw_free(*optrp); *optrp = NULL; *olenp = 0; return FSW_VOLUME_CORRUPTED; } fsw_memcpy(buf, block, clustersize > olen ? olen : clustersize); fsw_block_release(&vol->g, lcn, block); buf += clustersize; olen -= clustersize; } } else { buf += cnt << vol->clbits; olen -= cnt << vol->clbits; } } return FSW_SUCCESS; } static void init_mft(struct fsw_ntfs_volume *vol, struct ntfs_mft *mft, fsw_u64 mftno) { mft->mftno = mftno; mft->atlst = NULL; mft->atlen = fsw_alloc(1<<vol->mftbits, &mft->buf); mft->atlen = 0; } static void free_mft(struct ntfs_mft *mft) { if(mft->buf) fsw_free(mft->buf); if(mft->atlst) fsw_free(mft->atlst); } static fsw_status_t load_atlist(struct fsw_ntfs_volume *vol, struct ntfs_mft *mft) { fsw_u8 *ptr; int len; fsw_status_t err = find_attribute_direct(mft->buf, 1<<vol->mftbits, AT_ATTRIBUTE_LIST, &ptr, &len); if(err != FSW_SUCCESS) return err; return read_attribute_direct(vol, ptr, len, &mft->atlst, &mft->atlen); } static fsw_status_t read_mft(struct fsw_ntfs_volume *vol, fsw_u8 *mft, fsw_u64 mftno) { int l = 0; int r = vol->extmap.used - 1; int m; fsw_u64 vcn = (mftno << vol->mftbits) >> vol->clbits; struct extent_slot *e = vol->extmap.extent; while(l <= r) { m = (l+r)/2; if(vcn < e[m].vcn) { r = m - 1; } else if(vcn >= e[m].vcn + e[m].cnt) { l = m + 1; } else if(vol->mftbits <= vol->clbits) { fsw_u64 lcn = e[m].lcn + (vcn - e[m].vcn); int offset = (mftno << vol->mftbits) & ((1<<vol->clbits)-1); fsw_u8 *buffer; fsw_status_t err; if(e[m].lcn + 1 == 0) return FSW_VOLUME_CORRUPTED; if ((err = fsw_block_get(&vol->g, lcn, 0, (void **)&buffer)) != FSW_SUCCESS) return FSW_VOLUME_CORRUPTED; fsw_memcpy(mft, buffer+offset, 1<<vol->mftbits); fsw_block_release(&vol->g, lcn, buffer); return fixup(mft, "FILE", 1<<vol->sctbits, 1<<vol->mftbits); } else { fsw_u8 *p = mft; fsw_u64 lcn = e[m].lcn + (vcn - e[m].vcn); fsw_u64 ecnt = e[m].cnt - (vcn - e[m].vcn); int count = 1 << (vol->mftbits - vol->clbits); fsw_status_t err; if(e[m].lcn + 1 == 0) return FSW_VOLUME_CORRUPTED; while(count-- > 0) { fsw_u8 *buffer; if ((err = fsw_block_get(&vol->g, lcn, 0, (void **)&buffer)) != FSW_SUCCESS) return FSW_VOLUME_CORRUPTED; fsw_memcpy(p, buffer, 1<<vol->clbits); fsw_block_release(&vol->g, lcn, buffer); p += 1<<vol->clbits; ecnt--; vcn++; if(count==0) break; if(ecnt > 0) { lcn++; } else if(++m >= vol->extmap.used || e[m].vcn != vcn) { return FSW_VOLUME_CORRUPTED; } else { lcn = e[m].lcn; ecnt = e[m].cnt; } } return fixup(mft, "FILE", 1<<vol->sctbits, 1<<vol->mftbits); } } return FSW_NOT_FOUND; } static void init_attr(struct fsw_ntfs_volume *vol, struct ntfs_attr *attr, int type) { fsw_memzero(attr, sizeof(*attr)); attr->type = type; attr->emftno = BADMFT; } static void free_attr(struct ntfs_attr *attr) { if(attr->emft) fsw_free(attr->emft); } static fsw_status_t find_attribute(struct fsw_ntfs_volume *vol, struct ntfs_mft *mft, struct ntfs_attr *attr, fsw_u64 vcn) { fsw_u8 *buf = mft->buf; if(mft->atlst && mft->atlen) { fsw_status_t err; fsw_u64 mftno; int pos = 0; err = find_attrlist_direct(mft->atlst, mft->atlen, attr->type, vcn, &mftno, &pos); if(err != FSW_SUCCESS) return err; if(mftno == mft->mftno) { buf = mft->buf; } else if(mftno == attr->emftno && attr->emft) { buf = attr->emft; } else { attr->emftno = BADMFT; if(attr->emft==NULL) { err = fsw_alloc(1<<vol->mftbits, &attr->emft); if(err != FSW_SUCCESS) return err; } err = read_mft(vol, attr->emft, mftno); if(err != FSW_SUCCESS) return err; attr->emftno = mftno; buf = attr->emft; } } return find_attribute_direct(buf, 1<<vol->mftbits, attr->type, &attr->ptr, &attr->len); } static fsw_status_t read_small_attribute(struct fsw_ntfs_volume *vol, struct ntfs_mft *mft, int type, fsw_u8 **optrp, int *olenp) { fsw_status_t err; struct ntfs_attr attr; init_attr(vol, &attr, type); err = find_attribute(vol, mft, &attr, 0); if(err == FSW_SUCCESS) err = read_attribute_direct(vol, attr.ptr, attr.len, optrp, olenp); free_attr(&attr); return err; } static void add_single_mft_map(struct fsw_ntfs_volume *vol, fsw_u8 *mft) { fsw_u8 *ptr; int len; if(find_attribute_direct(mft, 1<<vol->mftbits, AT_DATA, &ptr, &len)!=FSW_SUCCESS) return; if(attribute_ondisk(ptr, len) == 0) return; fsw_u64 vcn = GETU64(ptr, 0x10); int off = GETU16(ptr, 0x20); ptr += off; len -= off; fsw_u64 pos = 0; fsw_u64 lcn, cnt; while(len > 0 && get_extent(&ptr, &len, &lcn, &cnt, &pos)==FSW_SUCCESS) { if(lcn) { int u = vol->extmap.used; if(u >= vol->extmap.total) { vol->extmap.total = vol->extmap.extent ? u*2 : 16; struct extent_slot *e; if(fsw_alloc(vol->extmap.total * sizeof(struct extent_slot), &e)!=FSW_SUCCESS) break; if(vol->extmap.extent) { fsw_memcpy(e, vol->extmap.extent, u*sizeof(struct extent_slot)); fsw_free(vol->extmap.extent); } vol->extmap.extent = e; } vol->extmap.extent[u].vcn = vcn; vol->extmap.extent[u].lcn = lcn; vol->extmap.extent[u].cnt = cnt; vol->extmap.used++; } vcn += cnt; } } static void add_mft_map(struct fsw_ntfs_volume *vol, struct ntfs_mft *mft) { load_atlist(vol, mft); add_single_mft_map(vol, mft->buf); if(mft->atlst == NULL) return; fsw_u64 mftno; int pos = 0; fsw_u8 *emft; if(fsw_alloc(1<<vol->mftbits, &emft) != FSW_SUCCESS) return; while(find_attrlist_direct(mft->atlst, mft->atlen, AT_DATA, 0, &mftno, &pos) == FSW_SUCCESS) { if(mftno == 0) continue; if(read_mft(vol, emft, mftno)==FSW_SUCCESS) add_single_mft_map(vol, emft); } fsw_free(emft); } static int tobits(fsw_u32 val) { return 31 - __builtin_clz(val); } static fsw_status_t fsw_ntfs_volume_mount(struct fsw_volume *volg) { struct fsw_ntfs_volume *vol = (struct fsw_ntfs_volume *)volg; fsw_status_t err; fsw_u8 *buffer; int sector_size; int cluster_size; signed char tmp; fsw_u64 mft_start[2]; struct ntfs_mft mft0; fsw_set_blocksize(volg, 512, 512); if ((err = fsw_block_get(volg, 0, 0, (void **)&buffer)) != FSW_SUCCESS) return FSW_UNSUPPORTED; if (!fsw_memeq(buffer+3, "NTFS ", 8)) return FSW_UNSUPPORTED; sector_size = GETU16(buffer, 0xB); if(sector_size==0 || (sector_size & (sector_size-1)) || sector_size < 0x100 || sector_size > 0x1000) return FSW_UNSUPPORTED; vol->sctbits = tobits(sector_size); vol->totalbytes = GETU64(buffer, 0x28) << vol->sctbits; Print(L"NTFS size=%ld M\n", vol->totalbytes>>20); cluster_size = GETU8(buffer, 0xD) * sector_size; if(cluster_size==0 || (cluster_size & (cluster_size-1)) || cluster_size > 0x10000) return FSW_UNSUPPORTED; vol->clbits = tobits(cluster_size); tmp = GETU8(buffer, 0x40); if(tmp > 0) vol->mftbits = vol->clbits + tobits(tmp); else vol->mftbits = -tmp; if(vol->mftbits < vol->sctbits || vol->mftbits > 16) return FSW_UNSUPPORTED; tmp = GETU8(buffer, 0x44); if(tmp > 0) vol->idxbits = vol->clbits + tobits(tmp); else vol->idxbits = -tmp; if(vol->idxbits < vol->sctbits || vol->idxbits > 16) return FSW_UNSUPPORTED; mft_start[0] = GETU64(buffer, 0x30); mft_start[1] = GETU64(buffer, 0x38); fsw_block_release(volg, 0, (void *)buffer); fsw_set_blocksize(volg, cluster_size, cluster_size); init_mft(vol, &mft0, MFTNO_MFT); for(tmp=0; tmp<2; tmp++) { fsw_u8 *ptr = mft0.buf; int len = 1 << vol->mftbits; fsw_u64 lcn = mft_start[tmp]; while(len > 0) { if ((err = fsw_block_get(volg, lcn, 0, (void **)&buffer)) != FSW_SUCCESS) { free_mft(&mft0); return FSW_UNSUPPORTED; } int n = vol->mftbits < vol->clbits ? (1<<vol->mftbits) : cluster_size; fsw_memcpy(ptr, buffer, n); fsw_block_release(volg, lcn, (void *)buffer); ptr += n; len -= n; lcn++; } err = fixup(mft0.buf, "FILE", sector_size, 1<<vol->mftbits); if(err != FSW_SUCCESS) return err; } add_mft_map(vol, &mft0); { int i; for(i=0; i<vol->extmap.used; i++) Print(L"extent %d: vcn=%lx lcn=%lx len=%lx\n", i, vol->extmap.extent[i].vcn, vol->extmap.extent[i].lcn, vol->extmap.extent[i].cnt); } free_mft(&mft0); /* load $Volume name */ init_mft(vol, &mft0, MFTNO_VOLUME); fsw_u8 *ptr; int len; if(read_mft(vol, mft0.buf, MFTNO_VOLUME)==FSW_SUCCESS && find_attribute_direct(mft0.buf, 1<<vol->mftbits, AT_VOLUME_NAME, &ptr, &len)==FSW_SUCCESS && GETU8(ptr, 8)==0) { struct fsw_string s; s.type = FSW_STRING_TYPE_UTF16_LE; s.size = GETU16(ptr, 0x10); s.len = s.size / 2; s.data = ptr + GETU16(ptr, 0x14); Print(L"Volume name [%.*ls]\n", s.len, s.data); err = fsw_strdup_coerce(&volg->label, volg->host_string_type, &s); } free_mft(&mft0); err = fsw_dnode_create_root(volg, MFTNO_ROOT, &volg->root); if (err) return err; return FSW_SUCCESS; } static void fsw_ntfs_volume_free(struct fsw_volume *volg) { struct fsw_ntfs_volume *vol = (struct fsw_ntfs_volume *)volg; if(vol->extmap.extent) fsw_free(vol->extmap.extent); if(vol->upcase && vol->upcase != upcase) fsw_free((void *)vol->upcase); } static fsw_status_t fsw_ntfs_volume_stat(struct fsw_volume *volg, struct fsw_volume_stat *sb) { struct fsw_ntfs_volume *vol = (struct fsw_ntfs_volume *)volg; sb->total_bytes = vol->totalbytes; /* reading through cluster bitmap is too costly */ sb->free_bytes = 0; return FSW_SUCCESS; } static void fsw_ntfs_dnode_free(struct fsw_volume *vol, struct fsw_dnode *dnog) { struct fsw_ntfs_dnode *dno = (struct fsw_ntfs_dnode *)dnog; free_mft(&dno->mft); free_attr(&dno->attr); if(dno->idxroot) fsw_free(dno->idxroot); if(dno->idxbmp) fsw_free(dno->idxbmp); if(dno->cbuf) fsw_free(dno->cbuf); } static fsw_status_t fsw_ntfs_dnode_fill(struct fsw_volume *volg, struct fsw_dnode *dnog) { struct fsw_ntfs_volume *vol = (struct fsw_ntfs_volume *)volg; struct fsw_ntfs_dnode *dno = (struct fsw_ntfs_dnode *)dnog; fsw_status_t err; int len; if(dno->mft.buf != NULL) return FSW_SUCCESS; init_mft(vol, &dno->mft, dno->g.dnode_id); err = read_mft(vol, dno->mft.buf, dno->g.dnode_id); if(err != FSW_SUCCESS) goto error_out; len = GETU8(dno->mft.buf, 22); if( (len & 1) == 0 ) { err = FSW_NOT_FOUND; goto error_out; } load_atlist(vol, &dno->mft); if(read_small_attribute(vol, &dno->mft, AT_REPARSE_POINT, &dno->cbuf, &len)==FSW_SUCCESS) { switch(GETU32(dno->cbuf, 0)) { case 0xa0000003: case 0xa000000c: dno->g.size = len; dno->g.type = FSW_DNODE_TYPE_SYMLINK; dno->islink = 1; dno->fsize = len; return FSW_SUCCESS; default: fsw_free(dno->cbuf); dno->cbuf = NULL; }; } if( (len & 2) ) { dno->g.type = FSW_DNODE_TYPE_DIR; /* $INDEX_ROOT:$I30 must present */ err = read_small_attribute(vol, &dno->mft, AT_INDEX_ROOT|AT_I30, &dno->idxroot, &dno->rootsz); if(err != FSW_SUCCESS) { Print(L"dno_fill INDEX_ROOT:$I30 error %d\n", err); goto error_out; } dno->idxsz = GETU32(dno->idxroot, 8); if(dno->idxsz == 0) dno->idxsz = 1<<vol->idxbits; /* $Bitmap:$I30 is optional */ err = read_small_attribute(vol, &dno->mft, AT_BITMAP|AT_I30, &dno->idxbmp, &dno->bmpsz); if(err != FSW_SUCCESS && err != FSW_NOT_FOUND) { Print(L"dno_fill $Bitmap:$I30 error %d\n", err); goto error_out; } /* $INDEX_ALLOCATION:$I30 is optional */ init_attr(vol, &dno->attr, AT_INDEX_ALLOCATION|AT_I30); err = find_attribute(vol, &dno->mft, &dno->attr, 0); if(err == FSW_SUCCESS) { dno->has_idxtree = 1; dno->fsize = attribute_size(dno->attr.ptr, dno->attr.len); dno->finited = dno->fsize; } else if(err != FSW_NOT_FOUND) { Print(L"dno_fill $INDEX_ALLOCATION:$I30 error %d\n", err); goto error_out; } } else { dno->g.type = FSW_DNODE_TYPE_FILE; init_attr(vol, &dno->attr, AT_DATA); err = find_attribute(vol, &dno->mft, &dno->attr, 0); if(err != FSW_SUCCESS) { Print(L"dno_fill AT_DATA error %d\n", err); goto error_out; } dno->embeded = !attribute_ondisk(dno->attr.ptr, dno->attr.len); dno->fsize = attribute_size(dno->attr.ptr, dno->attr.len); dno->finited = attribute_inited_size(dno->attr.ptr, dno->attr.len); if(attribute_encrypted(dno->attr.ptr, dno->attr.len)) dno->unreadable = 1; else if(attribute_compressed_future(dno->attr.ptr, dno->attr.len)) dno->unreadable = 1; else if(attribute_compressed(dno->attr.ptr, dno->attr.len)) dno->compressed = 1; dno->cvcn = BADVCN; dno->g.size = dno->fsize; } return FSW_SUCCESS; error_out: fsw_ntfs_dnode_free(volg, dnog); // clear tag for good dnode dno->mft.buf = NULL; return err; } static fsw_u32 get_ntfs_time(fsw_u8 *buf, int pos) { fsw_u64 t = GETU64(buf, pos); t = FSW_U64_DIV(t, 10000000); t -= 134774ULL * 86400; return t; } static fsw_status_t fsw_ntfs_dnode_stat(struct fsw_volume *volg, struct fsw_dnode *dnog, struct fsw_dnode_stat *sb) { struct fsw_ntfs_volume *vol = (struct fsw_ntfs_volume *)volg; struct fsw_ntfs_dnode *dno = (struct fsw_ntfs_dnode *)dnog; fsw_status_t err; fsw_u16 attr; fsw_u8 *ptr; int len; err = find_attribute_direct(dno->mft.buf, 1<<vol->mftbits, AT_STANDARD_INFORMATION, &ptr, &len); if(err != FSW_SUCCESS || GETU8(ptr, 8)) return err; ptr += GETU16(ptr, 0x14); attr = GETU8(ptr, 0x20); /* only lower 8 of 32 bit is used */ #ifndef EFI_FILE_READ_ONLY #define EFI_FILE_READ_ONLY 1 #define EFI_FILE_HIDDEN 2 #define EFI_FILE_SYSTEM 4 #define EFI_FILE_DIRECTORY 0x10 #define EFI_FILE_ARCHIVE 0x20 #endif attr &= EFI_FILE_READ_ONLY | EFI_FILE_HIDDEN | EFI_FILE_SYSTEM | EFI_FILE_ARCHIVE; /* add DIR again if symlink */ if(GETU8(dno->mft.buf, 22) & 2) attr |= EFI_FILE_DIRECTORY; fsw_store_attr_efi(sb, attr); sb->used_bytes = dno->fsize; fsw_store_time_posix(sb, FSW_DNODE_STAT_ATIME, get_ntfs_time(ptr, 24)); fsw_store_time_posix(sb, FSW_DNODE_STAT_CTIME, get_ntfs_time(ptr, 8)); fsw_store_time_posix(sb, FSW_DNODE_STAT_MTIME, get_ntfs_time(ptr, 16)); return FSW_SUCCESS; } static fsw_status_t fsw_ntfs_dnode_get_lcn(struct fsw_ntfs_volume *vol, struct fsw_ntfs_dnode *dno, fsw_u64 vcn, fsw_u64 *lcnp) { fsw_status_t err; if(vcn >= dno->cext.vcn && vcn < dno->cext.vcn+dno->cext.cnt) { *lcnp = dno->cext.lcn + vcn - dno->cext.vcn; return FSW_SUCCESS; } if(!attribute_has_vcn(dno->attr.ptr, dno->attr.len, vcn)) { err = find_attribute(vol, &dno->mft, &dno->attr, vcn); if( err != FSW_SUCCESS ) return err; if(!attribute_has_vcn(dno->attr.ptr, dno->attr.len, vcn)) return FSW_VOLUME_CORRUPTED; } fsw_u8 *ptr = dno->attr.ptr; int len = dno->attr.len; fsw_u64 pos = 0; fsw_u64 lcn, cnt; fsw_u64 svcn = attribute_first_vcn(ptr, len); fsw_u64 evcn = attribute_last_vcn(ptr, len) + 1; int off = GETU16(ptr, 0x20); ptr += off; len -= off; while(len > 0 && get_extent(&ptr, &len, &lcn, &cnt, &pos)==FSW_SUCCESS) { if(vcn >= svcn && vcn < svcn+cnt) { dno->cext.vcn = svcn; dno->cext.lcn = lcn; dno->cext.cnt = cnt; if(lcn == 0) return FSW_NOT_FOUND; *lcnp = lcn + vcn - svcn; return FSW_SUCCESS; } svcn += cnt; if(svcn >= evcn) break; } return FSW_NOT_FOUND; } static int fsw_ntfs_read_buffer(struct fsw_ntfs_volume *vol, struct fsw_ntfs_dnode *dno, fsw_u8 *buf, fsw_u64 offset, int size) { if(dno->embeded) { fsw_u8 *ptr; int len; attribute_get_embeded(dno->attr.ptr, dno->attr.len, &ptr, &len); if(offset >= len) return 0; ptr += offset; len -= offset; if(size > len) size = len; fsw_memcpy(buf, ptr, size); return size; } if(!dno->attr.ptr || !dno->attr.len) { Print(L"BAD--------: attr.ptr %p attr.len %x cleared\n", dno->attr.ptr, dno->attr.len); if(find_attribute(vol, &dno->mft, &dno->attr, 0) != FSW_SUCCESS) return 0; } if(offset >= dno->fsize) return 0; if(offset + size >= dno->fsize) size = dno->fsize - offset; if(offset >= dno->finited) { fsw_memzero(buf, size); return size; } int ret = 0; int zsize = 0; if(offset + size >= dno->finited) { zsize = offset + size - dno->finited; size = dno->finited - offset; } fsw_u64 vcn = offset >> vol->clbits; int boff = offset & ((1<<vol->clbits)-1); fsw_u64 lcn = 0; while(size > 0) { fsw_u8 *block; fsw_status_t err; int bsz; err = fsw_ntfs_dnode_get_lcn(vol, dno, vcn, &lcn); if (err != FSW_SUCCESS) break; err = fsw_block_get(&vol->g, lcn, 0, (void **)&block); if (err != FSW_SUCCESS) break; bsz = (1<<vol->clbits) - boff; if(bsz > size) bsz = size; fsw_memcpy(buf, block+boff, bsz); fsw_block_release(&vol->g, lcn, block); ret += bsz; buf += bsz; size -= bsz; boff = 0; vcn++; } if(size==0 && zsize > 0) { fsw_memzero(buf, zsize); ret += zsize; } return ret; } static fsw_status_t fsw_ntfs_get_extent_embeded(struct fsw_ntfs_volume *vol, struct fsw_ntfs_dnode *dno, struct fsw_extent *extent) { fsw_status_t err; if(extent->log_start > 0) return FSW_NOT_FOUND; extent->log_count = 1; err = fsw_alloc(1<<vol->clbits, &extent->buffer); if(err != FSW_SUCCESS) return err; fsw_u8 *ptr; int len; attribute_get_embeded(dno->attr.ptr, dno->attr.len, &ptr, &len); if(len > (1<<vol->clbits)) len = 1<<vol->clbits; fsw_memcpy(extent->buffer, ptr, len); extent->type = FSW_EXTENT_TYPE_BUFFER; return FSW_SUCCESS; } static int ntfs_decomp_1page(fsw_u8 *src, int slen, fsw_u8 *dst) { int soff = 0; int doff = 0; while(soff < slen) { int j; int tag = src[soff++]; for(j = 0; j < 8 && soff < slen; j++) { if(tag & (1<<j)){ int len; int back; int bits; if(!doff || soff + 2 > slen) return -1; len = GETU16(src, soff); soff += 2; bits = __builtin_clz((doff-1)>>3)-19; back = (len >> bits) + 1; len = (len & ((1<<bits)-1)) + 3; if(doff < back || doff + len > 0x1000) return -1; while(len-- > 0) { dst[doff] = dst[doff-back]; doff++; } } else { if(doff >= 0x1000) return -1; dst[doff++] = src[soff++]; } } } return doff; } static int ntfs_decomp(fsw_u8 *src, int slen, fsw_u8 *dst, int npage) { fsw_u8 *se = src + slen; fsw_u8 *de = dst + (npage<<12); int i; for(i=0; i<npage; i++) { fsw_u16 slen = GETU16(src, 0); int comp = slen & 0x8000; slen = (slen&0xfff)+1; src += 2; if(src + slen > se || dst + 0x1000 > de) return -1; if(!comp) { fsw_memcpy(dst, src, slen); if(slen < 0x1000) fsw_memzero(dst+slen, 0x1000-slen); } else if(slen == 1) { fsw_memzero(dst, 0x1000); } else { int dlen = ntfs_decomp_1page(src, slen, dst); if(dlen < 0) return -1; if(dlen < 0x1000) fsw_memzero(dst+dlen, 0x1000-dlen); } src += slen; dst += 0x1000; } return 0; } static fsw_status_t fsw_ntfs_get_extent_compressed(struct fsw_ntfs_volume *vol, struct fsw_ntfs_dnode *dno, struct fsw_extent *extent) { if(vol->clbits > 16) return FSW_VOLUME_CORRUPTED; if((extent->log_start << vol->clbits) > dno->fsize) return FSW_NOT_FOUND; int i; fsw_u64 vcn = extent->log_start & ~15; if(vcn == dno->cvcn) goto hit; dno->cvcn = vcn; dno->cperror = 0; dno->cpfull = 0; dno->cpzero = 0; for(i=0; i<16; i++) { fsw_status_t err; err = fsw_ntfs_dnode_get_lcn(vol, dno, vcn+i, &dno->clcn[i]); if(err == FSW_NOT_FOUND) { break; } else if(err != FSW_SUCCESS) { Print(L"BAD LCN\n"); dno->cperror = 1; return FSW_VOLUME_CORRUPTED; } } if(i == 0) dno->cpzero = 1; else if(i==16) dno->cpfull = 1; else { fsw_status_t err; if(dno->cbuf == NULL) { err = fsw_alloc(16<<vol->clbits, &dno->cbuf); if(err != FSW_SUCCESS) { dno->cvcn = BADVCN; return err; } } fsw_u8 *src; err = fsw_alloc(i << vol->clbits, &src); if(err != FSW_SUCCESS) { dno->cvcn = BADVCN; return err; } int b; for(b=0; b<i; b++) { char *block; if (fsw_block_get(&vol->g, dno->clcn[b], 0, (void **)&block) != FSW_SUCCESS) { dno->cperror = 1; Print(L"Read ERROR at block %d\n", i); break; } fsw_memcpy(src+(b<<vol->clbits), block, 1<<vol->clbits); fsw_block_release(&vol->g, dno->clcn[b], block); } if(dno->fsize >= ((vcn+16)<<vol->clbits)) b = 16<<vol->clbits>>12; else b = (dno->fsize - (vcn << vol->clbits) + 0xfff)>>12; if(!dno->cperror && ntfs_decomp(src, i<<vol->clbits, dno->cbuf, b) < 0) dno->cperror = 1; fsw_free(src); } hit: if(dno->cperror) return FSW_VOLUME_CORRUPTED; i = extent->log_start - vcn; if(dno->cpfull) { fsw_u64 lcn = dno->clcn[i]; extent->phys_start = lcn; extent->log_count = 1; extent->type = FSW_EXTENT_TYPE_PHYSBLOCK; for(i++, lcn++; i<16 && lcn==dno->clcn[i]; i++, lcn++) extent->log_count++; } else if(dno->cpzero) { extent->log_count = 16 - i; extent->buffer = NULL; extent->type = FSW_EXTENT_TYPE_SPARSE; } else { extent->log_count = 1; fsw_status_t err = fsw_alloc(1<<vol->clbits, &extent->buffer); if(err != FSW_SUCCESS) return err; fsw_memcpy(extent->buffer, dno->cbuf + (i<<vol->clbits), 1<<vol->clbits); extent->type = FSW_EXTENT_TYPE_BUFFER; } return FSW_SUCCESS; } static fsw_status_t fsw_ntfs_get_extent_sparse(struct fsw_ntfs_volume *vol, struct fsw_ntfs_dnode *dno, struct fsw_extent *extent) { fsw_status_t err; if((extent->log_start << vol->clbits) > dno->fsize) return FSW_NOT_FOUND; if((extent->log_start << vol->clbits) > dno->finited) { extent->log_count = 1; extent->buffer = NULL; extent->type = FSW_EXTENT_TYPE_SPARSE; return FSW_SUCCESS; } fsw_u64 lcn; err = fsw_ntfs_dnode_get_lcn(vol, dno, extent->log_start, &lcn); if(err == FSW_NOT_FOUND) { extent->log_count = 1; extent->buffer = NULL; extent->type = FSW_EXTENT_TYPE_SPARSE; return FSW_SUCCESS; } if(err != FSW_SUCCESS) return err; extent->phys_start = lcn; extent->log_count = 1; if(extent->log_start >= dno->cext.vcn && extent->log_start < dno->cext.vcn+dno->cext.cnt) extent->log_count = dno->cext.cnt + extent->log_start - dno->cext.vcn; extent->type = FSW_EXTENT_TYPE_PHYSBLOCK; return FSW_SUCCESS; } static fsw_status_t fsw_ntfs_get_extent(struct fsw_volume *volg, struct fsw_dnode *dnog, struct fsw_extent *extent) { struct fsw_ntfs_volume *vol = (struct fsw_ntfs_volume *)volg; struct fsw_ntfs_dnode *dno = (struct fsw_ntfs_dnode *)dnog; if(dno->unreadable) return FSW_UNSUPPORTED; if(dno->embeded) return fsw_ntfs_get_extent_embeded(vol, dno, extent); if(dno->compressed) return fsw_ntfs_get_extent_compressed(vol, dno, extent); return fsw_ntfs_get_extent_sparse(vol, dno, extent); } static fsw_status_t load_upcase(struct fsw_ntfs_volume *vol) { fsw_status_t err; struct ntfs_mft mft; init_mft(vol, &mft, MFTNO_UPCASE); err = read_mft(vol, mft.buf, MFTNO_UPCASE); if(err == FSW_SUCCESS) { if((err = read_small_attribute(vol, &mft, AT_DATA, (fsw_u8 **)&vol->upcase, &vol->upcount))==FSW_SUCCESS) { vol->upcount /= 2; #ifndef FSW_LITTLE_ENDIAN int i; for( i=0; i<vol->upcount; i++) vol->upcase[i] = fsw_u16_le_swap(vol->upcase[i]); #endif } } free_mft(&mft); return err; } static int ntfs_filename_cmp(struct fsw_ntfs_volume *vol, fsw_u8 *p1, int s1, fsw_u8 *p2, int s2) { while(s1 > 0 && s2 > 0) { fsw_u16 c1 = GETU16(p1,0); fsw_u16 c2 = GETU16(p2,0); if(c1 < 0x80 || c2 < 0x80) { if(c1 < 0x80) c1 = upcase[c1]; if(c2 < 0x80) c2 = upcase[c2]; } else { /* * Only load upcase table if both char is international. * We assume international char never upcased to ASCII. */ if(!vol->upcase) { load_upcase(vol); if(!vol->upcase) { /* use raw value & prevent load again */ vol->upcase = upcase; vol->upcount = 0; } } if(c1 < vol->upcount) c1 = vol->upcase[c1]; if(c2 < vol->upcount) c2 = vol->upcase[c2]; } if(c1 < c2) return -1; if(c1 > c2) return 1; p1+=2; p2+=2; s1--; s2--; } if(s1 < s2) return -1; if(s1 > s2) return 1; return 0; } static fsw_status_t fsw_ntfs_create_subnode(struct fsw_ntfs_dnode *dno, fsw_u8 *buf, struct fsw_dnode **child_dno) { fsw_u64 mftno = GETU64(buf, 0) & MFTMASK; if(mftno < MFTNO_META) return FSW_NOT_FOUND; int type = GETU32(buf, 0x48) & 0x10000000 ? FSW_DNODE_TYPE_DIR: FSW_DNODE_TYPE_FILE; struct fsw_string s; s.type = FSW_STRING_TYPE_UTF16_LE; s.len = GETU8(buf, 0x50); s.size = s.len * 2; s.data = buf + 0x52; return fsw_dnode_create(&dno->g, mftno, type, &s, child_dno); } static fsw_u8 *fsw_ntfs_read_index_block(struct fsw_ntfs_volume *vol, struct fsw_ntfs_dnode *dno, fsw_u64 block) { if(dno->cbuf==NULL) { if(fsw_alloc(dno->idxsz, &dno->cbuf) != FSW_SUCCESS) return NULL; } else if(block == dno->cvcn) return dno->cbuf; dno->cvcn = BADVCN; if(fsw_ntfs_read_buffer(vol, dno, dno->cbuf, (block-1)*dno->idxsz, dno->idxsz) != dno->idxsz) return NULL; if(fixup(dno->cbuf, "INDX", 1<<vol->sctbits, dno->idxsz) != FSW_SUCCESS) return NULL; dno->cvcn = block; return dno->cbuf; } static fsw_status_t fsw_ntfs_dir_lookup(struct fsw_volume *volg, struct fsw_dnode *dnog, struct fsw_string *lookup_name, struct fsw_dnode **child_dno) { struct fsw_ntfs_volume *vol = (struct fsw_ntfs_volume *)volg; struct fsw_ntfs_dnode *dno = (struct fsw_ntfs_dnode *)dnog; int depth = 0; struct fsw_string s; fsw_u8 *buf; int len; int off; fsw_status_t err; fsw_u64 block; fsw_u8 cpb; *child_dno = NULL; err = fsw_strdup_coerce(&s, FSW_STRING_TYPE_UTF16_LE, lookup_name); if(err) return err; /* start from AT_INDEX_ROOT */ buf = dno->idxroot + 16; len = dno->rootsz - 16; if(len < 0x18) goto notfound; cpb = GETU8(dno->idxroot, 12); if(cpb == 0) cpb = 1; while(depth < 10) { /* real index size */ if(GETU32(buf, 4) < len) len = GETU32(buf, 4); /* skip index header */ off = GETU32(buf, 0); if(off >= len) goto notfound; block = 0; while(off + 0x18 <= len) { int flag = GETU8(buf, off+12); int next = off + GETU16(buf, off+8); int cmp; if(flag & 2) { /* the end of index entry */ cmp = -1; Print(L"depth %d len %x off %x flag %x next %x cmp %d\n", depth, len, off, flag, next, cmp); } else { int nlen = GETU8(buf, off+0x50); fsw_u8 *name = buf+off+0x52; cmp = ntfs_filename_cmp(vol, s.data, s.len, name, nlen); Print(L"depth %d len %x off %x flag %x next %x cmp %d name %d[%.*ls]\n", depth, len, off, flag, next, cmp, nlen, nlen, name); } if(cmp == 0) { fsw_strfree(&s); return fsw_ntfs_create_subnode(dno, buf+off, child_dno); } else if(cmp < 0) { if(!(flag & 1) || !dno->has_idxtree) goto notfound; block = FSW_U64_DIV(GETU64(buf, next-8), cpb) + 1; break; } else { /* cmp > 0 */ off = next; } } if(!block) break; if(!(buf = fsw_ntfs_read_index_block(vol, dno, block))) break; buf += 24; len = dno->idxsz - 24; depth++; } notfound: fsw_strfree(&s); return FSW_NOT_FOUND; } static inline void set_shand_pos( struct fsw_shandle *shand, int block, int off) { shand->pos = (((fsw_u64)block) << 32) + off; } static inline int test_idxbmp(struct fsw_ntfs_dnode *dno, int block) { int mask; if(dno->idxbmp==NULL) return 1; block--; mask = 1 << (block & 7); block >>= 3; if(block > dno->bmpsz) return 0; return dno->idxbmp[block] & mask; } #define shand_pos(x,y) (((fsw_u64)(x)<<32)|(y)) static fsw_status_t fsw_ntfs_dir_read(struct fsw_volume *volg, struct fsw_dnode *dnog, struct fsw_shandle *shand, struct fsw_dnode **child_dno) { struct fsw_ntfs_volume *vol = (struct fsw_ntfs_volume *)volg; struct fsw_ntfs_dnode *dno = (struct fsw_ntfs_dnode *)dnog; /* * high 32 bit: index block# * 0 --> index root * >0 --> vcn+1 * low 32 bit: index offset */ int off = shand->pos & 0xFFFFFFFF; int block = shand->pos >> 32; int mblocks; mblocks = FSW_U64_DIV(dno->fsize, dno->idxsz); while(block <= mblocks) { fsw_u8 *buf; int len; if(block == 0) { /* AT_INDEX_ROOT */ buf = dno->idxroot + 16; len = dno->rootsz - 16; if(len < 0x18) goto miss; } else if(!test_idxbmp(dno, block) || !(buf = fsw_ntfs_read_index_block(vol, dno, block))) { /* unused or bad index block */ goto miss; } else { /* AT_INDEX_ALLOCATION block */ buf += 24; len = dno->idxsz - 24; } if(GETU32(buf, 4) < len) len = GETU32(buf, 4); if(off == 0) off = GETU32(buf, 0); Print(L"block %d len %x off %x\n", block, len, off); while(off + 0x18 <= len) { int flag = GETU8(buf, off+12); if(flag & 2) break; int next = off + GETU16(buf, off+8); Print(L"flag %x next %x nt %x [%.*ls]\n", flag, next, GETU8(buf, off+0x51), GETU8(buf, off+0x50), buf+off+0x52); if((GETU8(buf, off+0x51) != 2)) { /* LONG FILE NAME */ fsw_status_t err = fsw_ntfs_create_subnode(dno, buf+off, child_dno); if(err != FSW_NOT_FOUND) { set_shand_pos(shand, block, next); return err; } // skip internal MFT record } off = next; } miss: if(!dno->has_idxtree) break; block++; off = 0; } set_shand_pos(shand, mblocks+1, 0); return FSW_NOT_FOUND; } static fsw_status_t fsw_ntfs_readlink(struct fsw_volume *volg, struct fsw_dnode *dnog, struct fsw_string *link) { struct fsw_ntfs_dnode *dno = (struct fsw_ntfs_dnode *)dnog; fsw_u8 *name; int i; int len; if(!dno->islink) return FSW_UNSUPPORTED; name = dno->cbuf + 0x10 + GETU16(dno->cbuf, 8); len = GETU16(dno->cbuf, 10); if(GETU32(dno->cbuf, 0) == 0xa000000c) name += 4; for(i=0; i<len; i+=2) if(GETU16(name, i)=='\\') *(fsw_u16 *)(name+i) = fsw_u16_le_swap('/'); if(len > 6 && GETU16(name,0)=='/' && GETU16(name,2)=='?' && GETU16(name,4)=='?' && GETU16(name,6)=='/' && GETU16(name,10)==':' && GETU16(name,12)=='/' && (GETU16(name,8)|0x20)>='a' && (GETU16(name,8)|0x20)<='z') { len -= 12; name += 12; } struct fsw_string s; s.type = FSW_STRING_TYPE_UTF16_LE; s.size = len; s.len = len/2; s.data = name; return fsw_strdup_coerce(link, volg->host_string_type, &s); } // // Dispatch Table // struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(ntfs) = { { FSW_STRING_TYPE_UTF8, 4, 4, "ntfs" }, sizeof(struct fsw_ntfs_volume), sizeof(struct fsw_ntfs_dnode), fsw_ntfs_volume_mount, fsw_ntfs_volume_free, fsw_ntfs_volume_stat, fsw_ntfs_dnode_fill, fsw_ntfs_dnode_free, fsw_ntfs_dnode_stat, fsw_ntfs_get_extent, fsw_ntfs_dir_lookup, fsw_ntfs_dir_read, fsw_ntfs_readlink, }; // EOF �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/btrfs.inf�����������������������������������������������������������������0000664�0001750�0001750�00000003750�13112553200�017474� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������## @file # # btrfs.inf file to build rEFInd's Btrfs driver using the EDK2/UDK201# # development kit. # # Copyright (c) 2012-2017 by Roderick W. Smith # Released under the terms of the GPLv3 (or, at your discretion, any later # version), a copy of which should come with this file. # ## [Defines] INF_VERSION = 0x00010005 BASE_NAME = btrfs FILE_GUID = 1388238d-a3f1-4f93-94c6-2fad8196e5d2 MODULE_TYPE = UEFI_DRIVER EDK_RELEASE_VERSION = 0x00020000 EFI_SPECIFICATION_VERSION = 0x00010000 VERSION_STRING = 1.0 ENTRY_POINT = fsw_efi_main FSTYPE = btrfs # # The following information is for reference only and not required by the build tools. # # VALID_ARCHITECTURES = IA32 X64 IPF EBC # [Sources] fsw_efi.c fsw_btrfs.c fsw_core.c fsw_efi.c fsw_lib.c fsw_efi_lib.c [Packages] MdePkg/MdePkg.dec MdeModulePkg/MdeModulePkg.dec IntelFrameworkPkg/IntelFrameworkPkg.dec IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec [LibraryClasses] UefiDriverEntryPoint DxeServicesLib DxeServicesTableLib MemoryAllocationLib [LibraryClasses.AARCH64] BaseStackCheckLib # Comment out CompilerIntrinsicsLib when compiling for AARCH64 using UDK2014 CompilerIntrinsicsLib [Guids] [Ppis] [Protocols] gEfiDiskIoProtocolGuid gEfiBlockIoProtocolGuid [FeaturePcd] [Pcd] [BuildOptions.IA32] XCODE:*_*_*_CC_FLAGS = -Os -DEFI32 -D__MAKEWITH_TIANO -DFSTYPE=btrfs GCC:*_*_*_CC_FLAGS = -Os -DEFI32 -D__MAKEWITH_TIANO -DFSTYPE=btrfs [BuildOptions.X64] XCODE:*_*_*_CC_FLAGS = -Os -DEFIX64 -D__MAKEWITH_TIANO -DFSTYPE=btrfs GCC:*_*_*_CC_FLAGS = -Os -DEFIX64 -D__MAKEWITH_TIANO -DFSTYPE=btrfs [BuildOptions.AARCH64] XCODE:*_*_*_CC_FLAGS = -Os -DEFIAARCH64 -D__MAKEWITH_TIANO -DFSTYPE=btrfs GCC:*_*_*_CC_FLAGS = -Os -DEFIAARCH64 -D__MAKEWITH_TIANO -DFSTYPE=btrfs ������������������������refind-0.11.4/filesystems/fsw_reiserfs.h������������������������������������������������������������0000664�0001750�0001750�00000004617�12626644770�020561� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/** * \file fsw_reiserfs.h * ReiserFS file system driver header. */ /*- * Copyright (c) 2006 Christoph Pfisterer * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _FSW_REISERFS_H_ #define _FSW_REISERFS_H_ #define VOLSTRUCTNAME fsw_reiserfs_volume #define DNODESTRUCTNAME fsw_reiserfs_dnode #include "fsw_core.h" #include "fsw_reiserfs_disk.h" //! Block size (in shift bits) to be used when reading the reiserfs superblock. #define REISERFS_SUPERBLOCK_BLOCKSIZEBITS 12 //! Block size (in bytes) to be used when reading the reiserfs superblock. #define REISERFS_SUPERBLOCK_BLOCKSIZE (1<<REISERFS_SUPERBLOCK_BLOCKSIZEBITS) /** * ReiserFS: Results from a tree search. */ struct fsw_reiserfs_item { int valid; // the found item struct item_head ih; fsw_u64 item_offset; fsw_u32 item_type; fsw_u8 *item_data; // path information fsw_u32 path_bno[MAX_HEIGHT]; fsw_u32 path_index[MAX_HEIGHT]; // block release information fsw_u32 block_bno; void *block_buffer; }; /** * ReiserFS: Volume structure with reiserfs-specific data. */ struct fsw_reiserfs_volume { struct fsw_volume g; //!< Generic volume structure struct reiserfs_super_block *sb; //!< Full raw reiserfs superblock structure int version; //!< Flag for 3.5 or 3.6 format }; /** * ReiserFS: Dnode structure with reiserfs-specific data. */ struct fsw_reiserfs_dnode { struct fsw_dnode g; //!< Generic dnode structure fsw_u32 dir_id; //!< Locality ID for the reiserfs tree (parent dir id) struct stat_data_v1 *sd_v1; //!< Full stat_data, version 1 struct stat_data *sd_v2; //!< Full stat_data, version 2 }; #endif �����������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/fsw_efi_lib.c�������������������������������������������������������������0000664�0001750�0001750�00000010046�13074421551�020300� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/** * \file fsw_efi_lib.c * EFI host environment library functions. */ /*- * Copyright (c) 2006 Christoph Pfisterer * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * * Neither the name of Christoph Pfisterer nor the names of the * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "fsw_efi.h" // // time conversion // // Adopted from public domain code in FreeBSD libc. // #define SECSPERMIN 60 #define MINSPERHOUR 60 #define HOURSPERDAY 24 #define DAYSPERWEEK 7 #define DAYSPERNYEAR 365 #define DAYSPERLYEAR 366 #define SECSPERHOUR (SECSPERMIN * MINSPERHOUR) #define SECSPERDAY ((long) SECSPERHOUR * HOURSPERDAY) #define MONSPERYEAR 12 #define EPOCH_YEAR 1970 #define EPOCH_WDAY TM_THURSDAY #define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0)) #define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400) static const int mon_lengths[2][MONSPERYEAR] = { { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } }; static const int year_lengths[2] = { DAYSPERNYEAR, DAYSPERLYEAR }; VOID fsw_efi_decode_time(OUT EFI_TIME *EfiTime, IN UINT32 UnixTime) { long days, rem; int y, newy, yleap; const int *ip; ZeroMem(EfiTime, sizeof(EFI_TIME)); days = UnixTime / SECSPERDAY; rem = UnixTime % SECSPERDAY; EfiTime->Hour = (UINT8) (rem / SECSPERHOUR); rem = rem % SECSPERHOUR; EfiTime->Minute = (UINT8) (rem / SECSPERMIN); EfiTime->Second = (UINT8) (rem % SECSPERMIN); y = EPOCH_YEAR; while (days < 0 || days >= (long) year_lengths[yleap = isleap(y)]) { newy = y + days / DAYSPERNYEAR; if (days < 0) --newy; days -= (newy - y) * DAYSPERNYEAR + LEAPS_THRU_END_OF(newy - 1) - LEAPS_THRU_END_OF(y - 1); y = newy; } EfiTime->Year = (UINT16)y; ip = mon_lengths[yleap]; for (EfiTime->Month = 0; days >= (long) ip[EfiTime->Month]; ++(EfiTime->Month)) days = days - (long) ip[EfiTime->Month]; EfiTime->Month++; // adjust range to EFI conventions EfiTime->Day = (UINT8) (days + 1); } // // String functions, used for file and volume info // UINTN fsw_efi_strsize(struct fsw_string *s) { if (s->type == FSW_STRING_TYPE_EMPTY) return sizeof(CHAR16); return (s->len + 1) * sizeof(CHAR16); } VOID fsw_efi_strcpy(CHAR16 *Dest, struct fsw_string *src) { if ((src->type == FSW_STRING_TYPE_EMPTY) | (src->size == 0)) { Dest[0] = 0; } else if (src->type == FSW_STRING_TYPE_UTF16) { CopyMem(Dest, src->data, src->size); Dest[src->len] = 0; } else { // TODO: coerce, recurse Dest[0] = 0; } } // EOF ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/fsw_reiserfs.c������������������������������������������������������������0000664�0001750�0001750�00000102367�12626644770�020555� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/** * \file fsw_reiserfs.c * ReiserFS file system driver code. */ /*- * Copyright (c) 2006 Christoph Pfisterer * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "fsw_reiserfs.h" // functions static fsw_status_t fsw_reiserfs_volume_mount(struct fsw_reiserfs_volume *vol); static void fsw_reiserfs_volume_free(struct fsw_reiserfs_volume *vol); static fsw_status_t fsw_reiserfs_volume_stat(struct fsw_reiserfs_volume *vol, struct fsw_volume_stat *sb); static fsw_status_t fsw_reiserfs_dnode_fill(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno); static void fsw_reiserfs_dnode_free(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno); static fsw_status_t fsw_reiserfs_dnode_stat(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno, struct fsw_dnode_stat *sb); static fsw_status_t fsw_reiserfs_get_extent(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno, struct fsw_extent *extent); static fsw_status_t fsw_reiserfs_dir_lookup(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno, struct fsw_string *lookup_name, struct fsw_reiserfs_dnode **child_dno); static fsw_status_t fsw_reiserfs_dir_read(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno, struct fsw_shandle *shand, struct fsw_reiserfs_dnode **child_dno); static fsw_status_t fsw_reiserfs_readlink(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno, struct fsw_string *link); static fsw_status_t fsw_reiserfs_item_search(struct fsw_reiserfs_volume *vol, fsw_u32 dir_id, fsw_u32 objectid, fsw_u64 offset, struct fsw_reiserfs_item *item); static fsw_status_t fsw_reiserfs_item_next(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_item *item); static void fsw_reiserfs_item_release(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_item *item); // // Dispatch Table // struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(reiserfs) = { { FSW_STRING_TYPE_ISO88591, 8, 8, "reiserfs" }, sizeof(struct fsw_reiserfs_volume), sizeof(struct fsw_reiserfs_dnode), fsw_reiserfs_volume_mount, fsw_reiserfs_volume_free, fsw_reiserfs_volume_stat, fsw_reiserfs_dnode_fill, fsw_reiserfs_dnode_free, fsw_reiserfs_dnode_stat, fsw_reiserfs_get_extent, fsw_reiserfs_dir_lookup, fsw_reiserfs_dir_read, fsw_reiserfs_readlink, }; // misc data static fsw_u32 superblock_offsets[3] = { REISERFS_DISK_OFFSET_IN_BYTES >> REISERFS_SUPERBLOCK_BLOCKSIZEBITS, REISERFS_OLD_DISK_OFFSET_IN_BYTES >> REISERFS_SUPERBLOCK_BLOCKSIZEBITS, 0 }; /** * Mount an reiserfs volume. Reads the superblock and constructs the * root directory dnode. */ static fsw_status_t fsw_reiserfs_volume_mount(struct fsw_reiserfs_volume *vol) { fsw_status_t status; void *buffer; fsw_u32 blocksize; int i; struct fsw_string s; // allocate memory to keep the superblock around status = fsw_alloc(sizeof(struct reiserfs_super_block), &vol->sb); if (status) return status; // read the superblock into its buffer fsw_set_blocksize(vol, REISERFS_SUPERBLOCK_BLOCKSIZE, REISERFS_SUPERBLOCK_BLOCKSIZE); for (i = 0; superblock_offsets[i]; i++) { status = fsw_block_get(vol, superblock_offsets[i], 0, &buffer); if (status) return status; fsw_memcpy(vol->sb, buffer, sizeof(struct reiserfs_super_block)); fsw_block_release(vol, superblock_offsets[i], buffer); // check for one of the magic strings if (fsw_memeq(vol->sb->s_v1.s_magic, REISERFS_SUPER_MAGIC_STRING, 8)) { vol->version = REISERFS_VERSION_1; break; } else if (fsw_memeq(vol->sb->s_v1.s_magic, REISER2FS_SUPER_MAGIC_STRING, 9)) { vol->version = REISERFS_VERSION_2; break; } else if (fsw_memeq(vol->sb->s_v1.s_magic, REISER2FS_JR_SUPER_MAGIC_STRING, 9)) { vol->version = vol->sb->s_v1.s_version; if (vol->version == REISERFS_VERSION_1 || vol->version == REISERFS_VERSION_2) break; } } if (superblock_offsets[i] == 0) return FSW_UNSUPPORTED; // check the superblock if (vol->sb->s_v1.s_root_block == -1) // unfinished 'reiserfsck --rebuild-tree' return FSW_VOLUME_CORRUPTED; /* if (vol->sb->s_rev_level != EXT2_GOOD_OLD_REV && vol->sb->s_rev_level != EXT2_DYNAMIC_REV) return FSW_UNSUPPORTED; if (vol->sb->s_rev_level == EXT2_DYNAMIC_REV && (vol->sb->s_feature_incompat & ~(EXT2_FEATURE_INCOMPAT_FILETYPE | EXT3_FEATURE_INCOMPAT_RECOVER))) return FSW_UNSUPPORTED; */ // set real blocksize blocksize = vol->sb->s_v1.s_blocksize; fsw_set_blocksize(vol, blocksize, blocksize); // get other info from superblock /* vol->ind_bcnt = EXT2_ADDR_PER_BLOCK(vol->sb); vol->dind_bcnt = vol->ind_bcnt * vol->ind_bcnt; vol->inode_size = EXT2_INODE_SIZE(vol->sb); */ for (i = 0; i < 16; i++) if (vol->sb->s_label[i] == 0) break; s.type = FSW_STRING_TYPE_ISO88591; s.size = s.len = i; s.data = vol->sb->s_label; status = fsw_strdup_coerce(&vol->g.label, vol->g.host_string_type, &s); if (status) return status; // setup the root dnode status = fsw_dnode_create_root(vol, REISERFS_ROOT_OBJECTID, &vol->g.root); if (status) return status; vol->g.root->dir_id = REISERFS_ROOT_PARENT_OBJECTID; FSW_MSG_DEBUG((FSW_MSGSTR("fsw_reiserfs_volume_mount: success, blocksize %d tree height %d\n"), blocksize, vol->sb->s_v1.s_tree_height)); return FSW_SUCCESS; } /** * Free the volume data structure. Called by the core after an unmount or after * an unsuccessful mount to release the memory used by the file system type specific * part of the volume structure. */ static void fsw_reiserfs_volume_free(struct fsw_reiserfs_volume *vol) { if (vol->sb) fsw_free(vol->sb); } /** * Get in-depth information on a volume. */ static fsw_status_t fsw_reiserfs_volume_stat(struct fsw_reiserfs_volume *vol, struct fsw_volume_stat *sb) { sb->total_bytes = (fsw_u64)vol->sb->s_v1.s_block_count * vol->g.log_blocksize; sb->free_bytes = (fsw_u64)vol->sb->s_v1.s_free_blocks * vol->g.log_blocksize; return FSW_SUCCESS; } /** * Get full information on a dnode from disk. This function is called by the core * whenever it needs to access fields in the dnode structure that may not * be filled immediately upon creation of the dnode. In the case of reiserfs, we * delay fetching of the stat data until dnode_fill is called. The size and * type fields are invalid until this function has been called. */ static fsw_status_t fsw_reiserfs_dnode_fill(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno) { fsw_status_t status; fsw_u32 item_len, mode; struct fsw_reiserfs_item item; if (dno->sd_v1 || dno->sd_v2) return FSW_SUCCESS; FSW_MSG_DEBUG((FSW_MSGSTR("fsw_reiserfs_dnode_fill: object %d/%d\n"), dno->dir_id, dno->g.dnode_id)); // find stat data item in reiserfs tree status = fsw_reiserfs_item_search(vol, dno->dir_id, dno->g.dnode_id, 0, &item); if (status == FSW_NOT_FOUND) { FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_dnode_fill: cannot find stat_data for object %d/%d\n"), dno->dir_id, dno->g.dnode_id)); return FSW_VOLUME_CORRUPTED; } if (status) return status; if (item.item_offset != 0) { FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_dnode_fill: got item that's not stat_data\n"))); fsw_reiserfs_item_release(vol, &item); return FSW_VOLUME_CORRUPTED; } item_len = item.ih.ih_item_len; // get data in appropriate version if (item.ih.ih_version == KEY_FORMAT_3_5 && item_len == SD_V1_SIZE) { // have stat_data_v1 structure status = fsw_memdup((void **)&dno->sd_v1, item.item_data, item_len); fsw_reiserfs_item_release(vol, &item); if (status) return status; // get info from the inode dno->g.size = dno->sd_v1->sd_size; mode = dno->sd_v1->sd_mode; } else if (item.ih.ih_version == KEY_FORMAT_3_6 && item_len == SD_V2_SIZE) { // have stat_data_v2 structure status = fsw_memdup((void **)&dno->sd_v2, item.item_data, item_len); fsw_reiserfs_item_release(vol, &item); if (status) return status; // get info from the inode dno->g.size = dno->sd_v2->sd_size; mode = dno->sd_v2->sd_mode; } else { FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_dnode_fill: version %d(%d) and size %d(%d) not recognized for stat_data\n"), item.ih.ih_version, KEY_FORMAT_3_6, item_len, SD_V2_SIZE)); fsw_reiserfs_item_release(vol, &item); return FSW_VOLUME_CORRUPTED; } // get node type from mode field if (S_ISREG(mode)) dno->g.type = FSW_DNODE_TYPE_FILE; else if (S_ISDIR(mode)) dno->g.type = FSW_DNODE_TYPE_DIR; else if (S_ISLNK(mode)) dno->g.type = FSW_DNODE_TYPE_SYMLINK; else dno->g.type = FSW_DNODE_TYPE_SPECIAL; return FSW_SUCCESS; } /** * Free the dnode data structure. Called by the core when deallocating a dnode * structure to release the memory used by the file system type specific part * of the dnode structure. */ static void fsw_reiserfs_dnode_free(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno) { if (dno->sd_v1) fsw_free(dno->sd_v1); if (dno->sd_v2) fsw_free(dno->sd_v2); } /** * Get in-depth information on a dnode. The core makes sure that fsw_reiserfs_dnode_fill * has been called on the dnode before this function is called. Note that some * data is not directly stored into the structure, but passed to a host-specific * callback that converts it to the host-specific format. */ static fsw_status_t fsw_reiserfs_dnode_stat(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno, struct fsw_dnode_stat *sb) { if (dno->sd_v1) { if (dno->g.type == FSW_DNODE_TYPE_SPECIAL) sb->used_bytes = 0; else sb->used_bytes = dno->sd_v1->u.sd_blocks * vol->g.log_blocksize; fsw_store_time_posix(sb, FSW_DNODE_STAT_CTIME, dno->sd_v1->sd_ctime); fsw_store_time_posix(sb, FSW_DNODE_STAT_ATIME, dno->sd_v1->sd_atime); fsw_store_time_posix(sb, FSW_DNODE_STAT_MTIME, dno->sd_v1->sd_mtime); fsw_store_attr_posix(sb, dno->sd_v1->sd_mode); } else if (dno->sd_v2) { sb->used_bytes = dno->sd_v2->sd_blocks * vol->g.log_blocksize; fsw_store_time_posix(sb, FSW_DNODE_STAT_CTIME, dno->sd_v2->sd_ctime); fsw_store_time_posix(sb, FSW_DNODE_STAT_ATIME, dno->sd_v2->sd_atime); fsw_store_time_posix(sb, FSW_DNODE_STAT_MTIME, dno->sd_v2->sd_mtime); fsw_store_attr_posix(sb, dno->sd_v2->sd_mode); } return FSW_SUCCESS; } /** * Retrieve file data mapping information. This function is called by the core when * fsw_shandle_read needs to know where on the disk the required piece of the file's * data can be found. The core makes sure that fsw_reiserfs_dnode_fill has been called * on the dnode before. Our task here is to get the physical disk block number for * the requested logical block number. */ static fsw_status_t fsw_reiserfs_get_extent(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno, struct fsw_extent *extent) { fsw_status_t status; fsw_u64 search_offset, intra_offset; struct fsw_reiserfs_item item; fsw_u32 intra_bno, nr_item; // Preconditions: The caller has checked that the requested logical block // is within the file's size. The dnode has complete information, i.e. // fsw_reiserfs_dnode_read_info was called successfully on it. FSW_MSG_DEBUG((FSW_MSGSTR("fsw_reiserfs_get_extent: mapping block %d of object %d/%d\n"), extent->log_start, dno->dir_id, dno->g.dnode_id)); extent->type = FSW_EXTENT_TYPE_SPARSE; extent->log_count = 1; // get the item for the requested block search_offset = (fsw_u64)extent->log_start * vol->g.log_blocksize + 1; status = fsw_reiserfs_item_search(vol, dno->dir_id, dno->g.dnode_id, search_offset, &item); if (status) return status; if (item.item_offset == 0) { fsw_reiserfs_item_release(vol, &item); return FSW_SUCCESS; // no data items found, assume all-sparse file } intra_offset = search_offset - item.item_offset; // check the kind of block if (item.item_type == TYPE_INDIRECT || item.item_type == V1_INDIRECT_UNIQUENESS) { // indirect item, contains block numbers if (intra_offset & (vol->g.log_blocksize - 1)) { FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_get_extent: intra_offset not block-aligned for indirect block\n"))); goto bail; } intra_bno = (fsw_u32)FSW_U64_DIV(intra_offset, vol->g.log_blocksize); nr_item = item.ih.ih_item_len / sizeof(fsw_u32); if (intra_bno >= nr_item) { FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_get_extent: indirect block too small\n"))); goto bail; } extent->type = FSW_EXTENT_TYPE_PHYSBLOCK; extent->phys_start = ((fsw_u32 *)item.item_data)[intra_bno]; // TODO: check if the following blocks can be aggregated into one extent fsw_reiserfs_item_release(vol, &item); return FSW_SUCCESS; } else if (item.item_type == TYPE_DIRECT || item.item_type == V1_DIRECT_UNIQUENESS) { // direct item, contains file data // TODO: Check if direct items always start on block boundaries. If not, we may have // to do extra work here. if (intra_offset != 0) { FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_get_extent: intra_offset not aligned for direct block\n"))); goto bail; } extent->type = FSW_EXTENT_TYPE_BUFFER; status = fsw_memdup(&extent->buffer, item.item_data, item.ih.ih_item_len); fsw_reiserfs_item_release(vol, &item); if (status) return status; return FSW_SUCCESS; } bail: fsw_reiserfs_item_release(vol, &item); return FSW_VOLUME_CORRUPTED; /* // check if the following blocks can be aggregated into one extent file_bcnt = (fsw_u32)((dno->g.size + vol->g.log_blocksize - 1) & (vol->g.log_blocksize - 1)); while (path[i] + extent->log_count < buf_bcnt && // indirect block has more block pointers extent->log_start + extent->log_count < file_bcnt) { // file has more blocks if (buffer[path[i] + extent->log_count] == buffer[path[i] + extent->log_count - 1] + 1) extent->log_count++; else break; } */ } /** * Lookup a directory's child dnode by name. This function is called on a directory * to retrieve the directory entry with the given name. A dnode is constructed for * this entry and returned. The core makes sure that fsw_reiserfs_dnode_fill has been called * and the dnode is actually a directory. */ static fsw_status_t fsw_reiserfs_dir_lookup(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno, struct fsw_string *lookup_name, struct fsw_reiserfs_dnode **child_dno_out) { fsw_status_t status; struct fsw_reiserfs_item item; fsw_u32 nr_item, i, name_offset, next_name_offset, name_len; fsw_u32 child_dir_id; struct reiserfs_de_head *dhead; struct fsw_string entry_name; // Preconditions: The caller has checked that dno is a directory node. // BIG TODOS: Use the hash function to start with the item containing the entry. // Use binary search within the item. entry_name.type = FSW_STRING_TYPE_ISO88591; // get the item for that position status = fsw_reiserfs_item_search(vol, dno->dir_id, dno->g.dnode_id, FIRST_ITEM_OFFSET, &item); if (status) return status; if (item.item_offset == 0) { fsw_reiserfs_item_release(vol, &item); return FSW_NOT_FOUND; // empty directory or something } for(;;) { // search the directory item dhead = (struct reiserfs_de_head *)item.item_data; nr_item = item.ih.u.ih_entry_count; next_name_offset = item.ih.ih_item_len; for (i = 0; i < nr_item; i++, dhead++, next_name_offset = name_offset) { // get the name name_offset = dhead->deh_location; name_len = next_name_offset - name_offset; while (name_len > 0 && item.item_data[name_offset + name_len - 1] == 0) name_len--; entry_name.len = entry_name.size = name_len; entry_name.data = item.item_data + name_offset; // compare name if (fsw_streq(lookup_name, &entry_name)) { // found the entry we're looking for! // setup a dnode for the child item status = fsw_dnode_create(dno, dhead->deh_objectid, FSW_DNODE_TYPE_UNKNOWN, &entry_name, child_dno_out); child_dir_id = dhead->deh_dir_id; fsw_reiserfs_item_release(vol, &item); if (status) return status; (*child_dno_out)->dir_id = child_dir_id; return FSW_SUCCESS; } } // We didn't find the next directory entry in this item. Look for the next // item of the directory. status = fsw_reiserfs_item_next(vol, &item); if (status) return status; } } /** * Get the next directory entry when reading a directory. This function is called during * directory iteration to retrieve the next directory entry. A dnode is constructed for * the entry and returned. The core makes sure that fsw_reiserfs_dnode_fill has been called * and the dnode is actually a directory. The shandle provided by the caller is used to * record the position in the directory between calls. */ static fsw_status_t fsw_reiserfs_dir_read(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno, struct fsw_shandle *shand, struct fsw_reiserfs_dnode **child_dno_out) { fsw_status_t status; struct fsw_reiserfs_item item; fsw_u32 nr_item, i, name_offset, next_name_offset, name_len; fsw_u32 child_dir_id; struct reiserfs_de_head *dhead; struct fsw_string entry_name; // Preconditions: The caller has checked that dno is a directory node. The caller // has opened a storage handle to the directory's storage and keeps it around between // calls. // BIG TODOS: Use binary search within the item. // adjust pointer to first entry if necessary if (shand->pos == 0) shand->pos = FIRST_ITEM_OFFSET; // get the item for that position status = fsw_reiserfs_item_search(vol, dno->dir_id, dno->g.dnode_id, shand->pos, &item); if (status) return status; if (item.item_offset == 0) { fsw_reiserfs_item_release(vol, &item); return FSW_NOT_FOUND; // empty directory or something } for(;;) { // search the directory item dhead = (struct reiserfs_de_head *)item.item_data; nr_item = item.ih.u.ih_entry_count; for (i = 0; i < nr_item; i++, dhead++) { if (dhead->deh_offset < shand->pos) continue; // not yet past the last entry returned if (dhead->deh_offset == DOT_OFFSET || dhead->deh_offset == DOT_DOT_OFFSET) continue; // never report . or .. // get the name name_offset = dhead->deh_location; if (i == 0) next_name_offset = item.ih.ih_item_len; else next_name_offset = dhead[-1].deh_location; name_len = next_name_offset - name_offset; while (name_len > 0 && item.item_data[name_offset + name_len - 1] == 0) name_len--; entry_name.type = FSW_STRING_TYPE_ISO88591; entry_name.len = entry_name.size = name_len; entry_name.data = item.item_data + name_offset; if (fsw_streq_cstr(&entry_name, ".reiserfs_priv")) continue; // never report this special file // found the next entry! shand->pos = dhead->deh_offset + 1; // setup a dnode for the child item status = fsw_dnode_create(dno, dhead->deh_objectid, FSW_DNODE_TYPE_UNKNOWN, &entry_name, child_dno_out); child_dir_id = dhead->deh_dir_id; fsw_reiserfs_item_release(vol, &item); if (status) return status; (*child_dno_out)->dir_id = child_dir_id; return FSW_SUCCESS; } // We didn't find the next directory entry in this item. Look for the next // item of the directory. status = fsw_reiserfs_item_next(vol, &item); if (status) return status; } } /** * Get the target path of a symbolic link. This function is called when a symbolic * link needs to be resolved. The core makes sure that the fsw_reiserfs_dnode_fill has been * called on the dnode and that it really is a symlink. */ static fsw_status_t fsw_reiserfs_readlink(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno, struct fsw_string *link_target) { return fsw_dnode_readlink_data(dno, link_target); } /** * Compare an on-disk tree key against the search key. */ static int fsw_reiserfs_compare_key(struct reiserfs_key *key, fsw_u32 dir_id, fsw_u32 objectid, fsw_u64 offset) { fsw_u32 key_type; fsw_u64 key_offset; if (key->k_dir_id > dir_id) return FIRST_GREATER; if (key->k_dir_id < dir_id) return SECOND_GREATER; if (key->k_objectid > objectid) return FIRST_GREATER; if (key->k_objectid < objectid) return SECOND_GREATER; // determine format of the on-disk key key_type = (fsw_u32)FSW_U64_SHR(key->u.k_offset_v2.v, 60); if (key_type != TYPE_DIRECT && key_type != TYPE_INDIRECT && key_type != TYPE_DIRENTRY) { // detected 3.5 format (_v1) key_offset = key->u.k_offset_v1.k_offset; } else { // detected 3.6 format (_v2) key_offset = key->u.k_offset_v2.v & (~0ULL >> 4); } if (key_offset > offset) return FIRST_GREATER; if (key_offset < offset) return SECOND_GREATER; return KEYS_IDENTICAL; } /** * Find an item by key in the reiserfs tree. */ static fsw_status_t fsw_reiserfs_item_search(struct fsw_reiserfs_volume *vol, fsw_u32 dir_id, fsw_u32 objectid, fsw_u64 offset, struct fsw_reiserfs_item *item) { fsw_status_t status; int comp_result; fsw_u32 tree_bno, next_tree_bno, tree_level, nr_item, i; fsw_u8 *buffer; struct block_head *bhead; struct reiserfs_key *key; struct item_head *ihead; FSW_MSG_DEBUG((FSW_MSGSTR("fsw_reiserfs_item_search: searching %d/%d/%lld\n"), dir_id, objectid, offset)); // BIG TODOS: Use binary search within the item. // Remember tree path for "get next item" function. item->valid = 0; item->block_bno = 0; // walk the tree tree_bno = vol->sb->s_v1.s_root_block; for (tree_level = vol->sb->s_v1.s_tree_height - 1; ; tree_level--) { // get the current tree block into memory status = fsw_block_get(vol, tree_bno, tree_level, (void **)&buffer); if (status) return status; bhead = (struct block_head *)buffer; if (bhead->blk_level != tree_level) { FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_item_search: tree block %d has not expected level %d\n"), tree_bno, tree_level)); fsw_block_release(vol, tree_bno, buffer); return FSW_VOLUME_CORRUPTED; } nr_item = bhead->blk_nr_item; FSW_MSG_DEBUGV((FSW_MSGSTR("fsw_reiserfs_item_search: visiting block %d level %d items %d\n"), tree_bno, tree_level, nr_item)); item->path_bno[tree_level] = tree_bno; // check if we have reached a leaf block if (tree_level == DISK_LEAF_NODE_LEVEL) break; // search internal node block, look for the path to follow key = (struct reiserfs_key *)(buffer + BLKH_SIZE); for (i = 0; i < nr_item; i++, key++) { if (fsw_reiserfs_compare_key(key, dir_id, objectid, offset) == FIRST_GREATER) break; } item->path_index[tree_level] = i; next_tree_bno = ((struct disk_child *)(buffer + BLKH_SIZE + nr_item * KEY_SIZE))[i].dc_block_number; fsw_block_release(vol, tree_bno, buffer); tree_bno = next_tree_bno; } // search leaf node block, look for our data ihead = (struct item_head *)(buffer + BLKH_SIZE); for (i = 0; i < nr_item; i++, ihead++) { comp_result = fsw_reiserfs_compare_key(&ihead->ih_key, dir_id, objectid, offset); if (comp_result == KEYS_IDENTICAL) break; if (comp_result == FIRST_GREATER) { // Current key is greater than the search key. Use the last key before this // one as the preliminary result. if (i == 0) { fsw_block_release(vol, tree_bno, buffer); return FSW_NOT_FOUND; } i--, ihead--; break; } } if (i >= nr_item) { // Go back to the last key, it was smaller than the search key. // NOTE: The first key of the next leaf block is guaranteed to be greater than // our search key. i--, ihead--; } item->path_index[tree_level] = i; // Since we may have a key that is smaller than the search key, verify that // it is for the same object. if (ihead->ih_key.k_dir_id != dir_id || ihead->ih_key.k_objectid != objectid) { fsw_block_release(vol, tree_bno, buffer); return FSW_NOT_FOUND; // Found no key for this object at all } // return results fsw_memcpy(&item->ih, ihead, sizeof(struct item_head)); item->item_type = (fsw_u32)FSW_U64_SHR(ihead->ih_key.u.k_offset_v2.v, 60); if (item->item_type != TYPE_DIRECT && item->item_type != TYPE_INDIRECT && item->item_type != TYPE_DIRENTRY) { // 3.5 format (_v1) item->item_type = ihead->ih_key.u.k_offset_v1.k_uniqueness; item->item_offset = ihead->ih_key.u.k_offset_v1.k_offset; } else { // 3.6 format (_v2) item->item_offset = ihead->ih_key.u.k_offset_v2.v & (~0ULL >> 4); } item->item_data = buffer + ihead->ih_item_location; item->valid = 1; // add information for block release item->block_bno = tree_bno; item->block_buffer = buffer; FSW_MSG_DEBUG((FSW_MSGSTR("fsw_reiserfs_item_search: found %d/%d/%lld (%d)\n"), ihead->ih_key.k_dir_id, ihead->ih_key.k_objectid, item->item_offset, item->item_type)); return FSW_SUCCESS; } /** * Find the next item in the reiserfs tree for an already-found item. */ static fsw_status_t fsw_reiserfs_item_next(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_item *item) { fsw_status_t status; fsw_u32 dir_id, objectid; fsw_u32 tree_bno, next_tree_bno, tree_level, nr_item, nr_ptr_item; fsw_u8 *buffer; struct block_head *bhead; struct item_head *ihead; if (!item->valid) return FSW_NOT_FOUND; fsw_reiserfs_item_release(vol, item); // TODO: maybe delay this and/or use the cached block! dir_id = item->ih.ih_key.k_dir_id; objectid = item->ih.ih_key.k_objectid; FSW_MSG_DEBUG((FSW_MSGSTR("fsw_reiserfs_item_next: next for %d/%d/%lld\n"), dir_id, objectid, item->item_offset)); // find a node that has more items, moving up until we find one for (tree_level = DISK_LEAF_NODE_LEVEL; tree_level < vol->sb->s_v1.s_tree_height; tree_level++) { // get the current tree block into memory tree_bno = item->path_bno[tree_level]; status = fsw_block_get(vol, tree_bno, tree_level, (void **)&buffer); if (status) return status; bhead = (struct block_head *)buffer; if (bhead->blk_level != tree_level) { FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_item_next: tree block %d has not expected level %d\n"), tree_bno, tree_level)); fsw_block_release(vol, tree_bno, buffer); return FSW_VOLUME_CORRUPTED; } nr_item = bhead->blk_nr_item; FSW_MSG_DEBUGV((FSW_MSGSTR("fsw_reiserfs_item_next: visiting block %d level %d items %d\n"), tree_bno, tree_level, nr_item)); nr_ptr_item = nr_item + ((tree_level > DISK_LEAF_NODE_LEVEL) ? 1 : 0); // internal nodes have (nr_item) keys and (nr_item+1) pointers item->path_index[tree_level]++; if (item->path_index[tree_level] >= nr_ptr_item) { item->path_index[tree_level] = 0; fsw_block_release(vol, tree_bno, buffer); continue; // this node doesn't have any more items, move up one level } // we have a new path to follow, move down to the leaf node again while (tree_level > DISK_LEAF_NODE_LEVEL) { // get next pointer from current block next_tree_bno = ((struct disk_child *)(buffer + BLKH_SIZE + nr_item * KEY_SIZE))[item->path_index[tree_level]].dc_block_number; fsw_block_release(vol, tree_bno, buffer); tree_bno = next_tree_bno; tree_level--; // get the current tree block into memory status = fsw_block_get(vol, tree_bno, tree_level, (void **)&buffer); if (status) return status; bhead = (struct block_head *)buffer; if (bhead->blk_level != tree_level) { FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_item_next: tree block %d has not expected level %d\n"), tree_bno, tree_level)); fsw_block_release(vol, tree_bno, buffer); return FSW_VOLUME_CORRUPTED; } nr_item = bhead->blk_nr_item; FSW_MSG_DEBUGV((FSW_MSGSTR("fsw_reiserfs_item_next: visiting block %d level %d items %d\n"), tree_bno, tree_level, nr_item)); item->path_bno[tree_level] = tree_bno; } // get the item from the leaf node ihead = ((struct item_head *)(buffer + BLKH_SIZE)) + item->path_index[tree_level]; // We now have the item that follows the previous one in the tree. Check that it // belongs to the same object. if (ihead->ih_key.k_dir_id != dir_id || ihead->ih_key.k_objectid != objectid) { fsw_block_release(vol, tree_bno, buffer); return FSW_NOT_FOUND; // Found no next key for this object } // return results fsw_memcpy(&item->ih, ihead, sizeof(struct item_head)); item->item_type = (fsw_u32)FSW_U64_SHR(ihead->ih_key.u.k_offset_v2.v, 60); if (item->item_type != TYPE_DIRECT && item->item_type != TYPE_INDIRECT && item->item_type != TYPE_DIRENTRY) { // 3.5 format (_v1) item->item_type = ihead->ih_key.u.k_offset_v1.k_uniqueness; item->item_offset = ihead->ih_key.u.k_offset_v1.k_offset; } else { // 3.6 format (_v2) item->item_offset = ihead->ih_key.u.k_offset_v2.v & (~0ULL >> 4); } item->item_data = buffer + ihead->ih_item_location; item->valid = 1; // add information for block release item->block_bno = tree_bno; item->block_buffer = buffer; FSW_MSG_DEBUG((FSW_MSGSTR("fsw_reiserfs_item_next: found %d/%d/%lld (%d)\n"), ihead->ih_key.k_dir_id, ihead->ih_key.k_objectid, item->item_offset, item->item_type)); return FSW_SUCCESS; } // we went to the highest level node and there still were no more items... return FSW_NOT_FOUND; } /** * Release the disk block still referenced by an item search result. */ static void fsw_reiserfs_item_release(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_item *item) { if (!item->valid) return; if (item->block_bno > 0) { fsw_block_release(vol, item->block_bno, item->block_buffer); item->block_bno = 0; } } // EOF �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/fsw_core.h����������������������������������������������������������������0000664�0001750�0001750�00000044217�13112307445�017651� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/** * \file fsw_core.h * Core file system wrapper abstraction layer header. */ /*- * Copyright (c) 2006 Christoph Pfisterer * Portions Copyright (c) The Regents of the University of California. * Portions Copyright (c) UNIX System Laboratories, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * * Neither the name of Christoph Pfisterer nor the names of the * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _FSW_CORE_H_ #define _FSW_CORE_H_ #include "fsw_base.h" #ifdef __MAKEWITH_GNUEFI #include "fsw_efi_base.h" #endif /** Maximum size for a path, specifically symlink target paths. */ #define FSW_PATH_MAX (4096) /** Helper macro for token concatenation. */ #define FSW_CONCAT3(a,b,c) a##b##c /** Expands to the name of a fstype dispatch table (fsw_fstype_table) for a named file system type. */ #define FSW_FSTYPE_TABLE_NAME(t) FSW_CONCAT3(fsw_,t,_table) /** Indicates that the block cache entry is empty. */ #define FSW_INVALID_BNO 0xFFFFFFFFFFFFFFFF // // Byte-swapping macros // /** * \name Byte Order Macros * Implements big endian vs. little endian awareness and conversion. */ /*@{*/ typedef fsw_u16 fsw_u16_le; typedef fsw_u16 fsw_u16_be; typedef fsw_u32 fsw_u32_le; typedef fsw_u32 fsw_u32_be; typedef fsw_u64 fsw_u64_le; typedef fsw_u64 fsw_u64_be; #define FSW_SWAPVALUE_U16(v) ((((fsw_u16)(v) & 0xff00) >> 8) | \ (((fsw_u16)(v) & 0x00ff) << 8)) #define FSW_SWAPVALUE_U32(v) ((((fsw_u32)(v) & 0xff000000UL) >> 24) | \ (((fsw_u32)(v) & 0x00ff0000UL) >> 8) | \ (((fsw_u32)(v) & 0x0000ff00UL) << 8) | \ (((fsw_u32)(v) & 0x000000ffUL) << 24)) #define FSW_SWAPVALUE_U64(v) ((((fsw_u64)(v) & 0xff00000000000000ULL) >> 56) | \ (((fsw_u64)(v) & 0x00ff000000000000ULL) >> 40) | \ (((fsw_u64)(v) & 0x0000ff0000000000ULL) >> 24) | \ (((fsw_u64)(v) & 0x000000ff00000000ULL) >> 8) | \ (((fsw_u64)(v) & 0x00000000ff000000ULL) << 8) | \ (((fsw_u64)(v) & 0x0000000000ff0000ULL) << 24) | \ (((fsw_u64)(v) & 0x000000000000ff00ULL) << 40) | \ (((fsw_u64)(v) & 0x00000000000000ffULL) << 56)) #ifdef FSW_LITTLE_ENDIAN #define fsw_u16_le_swap(v) (v) #define fsw_u16_be_swap(v) FSW_SWAPVALUE_U16(v) #define fsw_u32_le_swap(v) (v) #define fsw_u32_be_swap(v) FSW_SWAPVALUE_U32(v) #define fsw_u64_le_swap(v) (v) #define fsw_u64_be_swap(v) FSW_SWAPVALUE_U64(v) #define fsw_u16_le_sip(var) #define fsw_u16_be_sip(var) (var = FSW_SWAPVALUE_U16(var)) #define fsw_u32_le_sip(var) #define fsw_u32_be_sip(var) (var = FSW_SWAPVALUE_U32(var)) #define fsw_u64_le_sip(var) #define fsw_u64_be_sip(var) (var = FSW_SWAPVALUE_U64(var)) #else #ifdef FSW_BIG_ENDIAN #define fsw_u16_le_swap(v) FSW_SWAPVALUE_U16(v) #define fsw_u16_be_swap(v) (v) #define fsw_u32_le_swap(v) FSW_SWAPVALUE_U32(v) #define fsw_u32_be_swap(v) (v) #define fsw_u64_le_swap(v) FSW_SWAPVALUE_U64(v) #define fsw_u64_be_swap(v) (v) #define fsw_u16_le_sip(var) (var = FSW_SWAPVALUE_U16(var)) #define fsw_u16_be_sip(var) #define fsw_u32_le_sip(var) (var = FSW_SWAPVALUE_U32(var)) #define fsw_u32_be_sip(var) #define fsw_u64_le_sip(var) (var = FSW_SWAPVALUE_U64(var)) #define fsw_u64_be_sip(var) #else #fail Neither FSW_BIG_ENDIAN nor FSW_LITTLE_ENDIAN are defined #endif #endif /*@}*/ // // The following evil hack avoids a lot of casts between generic and fstype-specific // structures. // #ifndef VOLSTRUCTNAME #define VOLSTRUCTNAME fsw_volume #else struct VOLSTRUCTNAME; #endif #ifndef DNODESTRUCTNAME #define DNODESTRUCTNAME fsw_dnode #else struct DNODESTRUCTNAME; #endif /** * Status code type, returned from all functions that can fail. */ typedef int fsw_status_t; /** * Possible status codes. */ enum { FSW_SUCCESS, FSW_OUT_OF_MEMORY, FSW_IO_ERROR, FSW_UNSUPPORTED, FSW_NOT_FOUND, FSW_VOLUME_CORRUPTED, FSW_UNKNOWN_ERROR }; /** * Core: A string with explicit length and encoding information. */ struct fsw_string { int type; //!< Encoding of the string - empty, ISO-8859-1, UTF8, UTF16 int len; //!< Length in characters int size; //!< Total data size in bytes void *data; //!< Data pointer (may be NULL if type is EMPTY or len is zero) }; /** * Possible string types / encodings. In the case of FSW_STRING_TYPE_EMPTY, * all other members of the fsw_string structure may be invalid. */ enum { FSW_STRING_TYPE_EMPTY, FSW_STRING_TYPE_ISO88591, FSW_STRING_TYPE_UTF8, FSW_STRING_TYPE_UTF16, FSW_STRING_TYPE_UTF16_SWAPPED }; #ifdef FSW_LITTLE_ENDIAN #define FSW_STRING_TYPE_UTF16_LE FSW_STRING_TYPE_UTF16 #define FSW_STRING_TYPE_UTF16_BE FSW_STRING_TYPE_UTF16_SWAPPED #else #define FSW_STRING_TYPE_UTF16_LE FSW_STRING_TYPE_UTF16_SWAPPED #define FSW_STRING_TYPE_UTF16_BE FSW_STRING_TYPE_UTF16 #endif /** Static initializer for an empty string. */ #define FSW_STRING_INIT { FSW_STRING_TYPE_EMPTY, 0, 0, NULL } /* forward declarations */ struct fsw_dnode; struct fsw_host_table; struct fsw_fstype_table; struct fsw_blockcache { fsw_u32 refcount; //!< Reference count fsw_u32 cache_level; //!< Level of importance of this block fsw_u64 phys_bno; //!< Physical block number void *data; //!< Block data buffer }; /** * Core: Represents a mounted volume. */ struct fsw_volume { fsw_u32 phys_blocksize; //!< Block size for disk access / file system structures fsw_u32 log_blocksize; //!< Block size for logical file data struct DNODESTRUCTNAME *root; //!< Root directory dnode struct fsw_string label; //!< Volume label struct fsw_dnode *dnode_head; //!< List of all dnodes allocated for this volume struct fsw_blockcache *bcache; //!< Array of block cache entries fsw_u32 bcache_size; //!< Number of entries in the block cache array void *host_data; //!< Hook for a host-specific data structure struct fsw_host_table *host_table; //!< Dispatch table for host-specific functions struct fsw_fstype_table *fstype_table; //!< Dispatch table for file system specific functions int host_string_type; //!< String type used by the host environment }; /** * Core: Represents a "directory node" - a file, directory, symlink, whatever. */ struct fsw_dnode { fsw_u32 refcount; //!< Reference count struct VOLSTRUCTNAME *vol; //!< The volume this dnode belongs to struct DNODESTRUCTNAME *parent; //!< Parent directory dnode struct fsw_string name; //!< Name of this item in the parent directory fsw_u64 tree_id; //!< Unique id number (usually the btrfs subvolume) fsw_u64 dnode_id; //!< Unique id number (usually the inode number) int type; //!< Type of the dnode - file, dir, symlink, special fsw_u64 size; //!< Data size in bytes struct fsw_dnode *next; //!< Doubly-linked list of all dnodes: previous dnode struct fsw_dnode *prev; //!< Doubly-linked list of all dnodes: next dnode }; /** * Possible dnode types. FSW_DNODE_TYPE_UNKNOWN may only be used before * fsw_dnode_fill has been called on the dnode. */ enum { FSW_DNODE_TYPE_UNKNOWN, FSW_DNODE_TYPE_FILE, FSW_DNODE_TYPE_DIR, FSW_DNODE_TYPE_SYMLINK, FSW_DNODE_TYPE_SPECIAL }; /** * Core: Stores the mapping of a region of a file to the data on disk. */ struct fsw_extent { fsw_u32 type; //!< Type of extent specification fsw_u64 log_start; //!< Starting logical block number fsw_u32 log_count; //!< Logical block count fsw_u64 phys_start; //!< Starting physical block number (for FSW_EXTENT_TYPE_PHYSBLOCK only) void *buffer; //!< Allocated buffer pointer (for FSW_EXTENT_TYPE_BUFFER only) }; /** * Possible extent representation types. FSW_EXTENT_TYPE_INVALID is for shandle's * internal use only, it must not be returned from a get_extent function. */ enum { FSW_EXTENT_TYPE_INVALID, FSW_EXTENT_TYPE_SPARSE, FSW_EXTENT_TYPE_PHYSBLOCK, FSW_EXTENT_TYPE_BUFFER }; /** * Core: An access structure to a dnode's raw data. There can be multiple * shandles per dnode, each of them has its own position pointer. */ struct fsw_shandle { struct fsw_dnode *dnode; //!< The dnode this handle reads data from fsw_u64 pos; //!< Current file pointer in bytes struct fsw_extent extent; //!< Current extent }; /** * Core: Used in gathering detailed information on a volume. */ struct fsw_volume_stat { fsw_u64 total_bytes; //!< Total size of data area size in bytes fsw_u64 free_bytes; //!< Bytes still available for storing file data }; /** * Core: Used in gathering detailed information on a dnode. */ struct fsw_dnode_stat { fsw_u64 used_bytes; //!< Bytes actually used by the file on disk void *host_data; //!< Hook for a host-specific data structure }; /** * Type of the timestamp passed into store_time_posix. */ enum { FSW_DNODE_STAT_CTIME, FSW_DNODE_STAT_MTIME, FSW_DNODE_STAT_ATIME }; /** * Core: Function table for a host environment. */ struct fsw_host_table { int native_string_type; //!< String type used by the host environment void EFIAPI (*change_blocksize)(struct fsw_volume *vol, fsw_u32 old_phys_blocksize, fsw_u32 old_log_blocksize, fsw_u32 new_phys_blocksize, fsw_u32 new_log_blocksize); fsw_status_t EFIAPI (*read_block)(struct fsw_volume *vol, fsw_u64 phys_bno, void *buffer); }; /** * Core: Function table for a file system driver. */ struct fsw_fstype_table { struct fsw_string name; //!< String giving the name of the file system fsw_u32 volume_struct_size; //!< Size for allocating the fsw_volume structure fsw_u32 dnode_struct_size; //!< Size for allocating the fsw_dnode structure fsw_status_t (*volume_mount)(struct VOLSTRUCTNAME *vol); void (*volume_free)(struct VOLSTRUCTNAME *vol); fsw_status_t (*volume_stat)(struct VOLSTRUCTNAME *vol, struct fsw_volume_stat *sb); fsw_status_t (*dnode_fill)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno); void (*dnode_free)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno); fsw_status_t (*dnode_stat)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno, struct fsw_dnode_stat *sb); fsw_status_t (*get_extent)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno, struct fsw_extent *extent); fsw_status_t (*dir_lookup)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno, struct fsw_string *lookup_name, struct DNODESTRUCTNAME **child_dno); fsw_status_t (*dir_read)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno, struct fsw_shandle *shand, struct DNODESTRUCTNAME **child_dno); fsw_status_t (*readlink)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno, struct fsw_string *link_target); }; /** * \name Volume Functions */ /*@{*/ fsw_status_t fsw_mount(void *host_data, struct fsw_host_table *host_table, struct fsw_fstype_table *fstype_table, struct fsw_volume **vol_out); void fsw_unmount(struct fsw_volume *vol); fsw_status_t fsw_volume_stat(struct fsw_volume *vol, struct fsw_volume_stat *sb); void fsw_set_blocksize(struct VOLSTRUCTNAME *vol, fsw_u32 phys_blocksize, fsw_u32 log_blocksize); fsw_status_t fsw_block_get(struct VOLSTRUCTNAME *vol, fsw_u64 phys_bno, fsw_u32 cache_level, void **buffer_out); void fsw_block_release(struct VOLSTRUCTNAME *vol, fsw_u64 phys_bno, void *buffer); /*@}*/ /** * \name dnode Functions */ /*@{*/ fsw_status_t fsw_dnode_create_root(struct VOLSTRUCTNAME *vol, fsw_u64 dnode_id, struct DNODESTRUCTNAME **dno_out); fsw_status_t fsw_dnode_create(struct DNODESTRUCTNAME *parent_dno, fsw_u64 dnode_id, int type, struct fsw_string *name, struct DNODESTRUCTNAME **dno_out); fsw_status_t fsw_dnode_create_root_with_tree(struct VOLSTRUCTNAME *vol, fsw_u64 tree_id, fsw_u64 dnode_id, struct DNODESTRUCTNAME **dno_out); fsw_status_t fsw_dnode_create_with_tree(struct DNODESTRUCTNAME *parent_dno, fsw_u64 tree_id, fsw_u64 dnode_id, int type, struct fsw_string *name, struct DNODESTRUCTNAME **dno_out); void fsw_dnode_retain(struct fsw_dnode *dno); void fsw_dnode_release(struct fsw_dnode *dno); fsw_status_t fsw_dnode_fill(struct fsw_dnode *dno); fsw_status_t fsw_dnode_stat(struct fsw_dnode *dno, struct fsw_dnode_stat *sb); fsw_status_t fsw_dnode_lookup(struct fsw_dnode *dno, struct fsw_string *lookup_name, struct fsw_dnode **child_dno_out); fsw_status_t fsw_dnode_lookup_path(struct fsw_dnode *dno, struct fsw_string *lookup_path, char separator, struct fsw_dnode **child_dno_out); fsw_status_t fsw_dnode_dir_read(struct fsw_shandle *shand, struct fsw_dnode **child_dno_out); fsw_status_t fsw_dnode_readlink(struct fsw_dnode *dno, struct fsw_string *link_target); fsw_status_t fsw_dnode_readlink_data(struct DNODESTRUCTNAME *dno, struct fsw_string *link_target); fsw_status_t fsw_dnode_resolve(struct fsw_dnode *dno, struct fsw_dnode **target_dno_out); void fsw_store_time_posix(struct fsw_dnode_stat *sb, int which, fsw_u32 posix_time); void fsw_store_attr_posix(struct fsw_dnode_stat *sb, fsw_u16 posix_mode); void fsw_store_attr_efi(struct fsw_dnode_stat *sb, fsw_u16 attr); /*@}*/ /** * \name shandle Functions */ /*@{*/ fsw_status_t fsw_shandle_open(struct DNODESTRUCTNAME *dno, struct fsw_shandle *shand); void fsw_shandle_close(struct fsw_shandle *shand); fsw_status_t fsw_shandle_read(struct fsw_shandle *shand, fsw_u32 *buffer_size_inout, void *buffer); /*@}*/ /** * \name Memory Functions */ /*@{*/ fsw_status_t fsw_alloc_zero(int len, void **ptr_out); fsw_status_t fsw_memdup(void **dest_out, void *src, int len); /*@}*/ /** * \name String Functions */ /*@{*/ int fsw_strlen(struct fsw_string *s); int fsw_streq(struct fsw_string *s1, struct fsw_string *s2); int fsw_streq_cstr(struct fsw_string *s1, const char *s2); fsw_status_t fsw_strdup_coerce(struct fsw_string *dest, int type, struct fsw_string *src); void fsw_strsplit(struct fsw_string *lookup_name, struct fsw_string *buffer, char separator); void fsw_strfree(struct fsw_string *s); /*@}*/ /** * \name Posix Mode Macros * These macros can be used globally to test fields and bits in * Posix-style modes. * * Taken from FreeBSD sys/stat.h. */ /*@{*/ #ifndef S_IRWXU #define S_ISUID 0004000 /* set user id on execution */ #define S_ISGID 0002000 /* set group id on execution */ #define S_ISTXT 0001000 /* sticky bit */ #define S_IRWXU 0000700 /* RWX mask for owner */ #define S_IRUSR 0000400 /* R for owner */ #define S_IWUSR 0000200 /* W for owner */ #define S_IXUSR 0000100 /* X for owner */ #define S_IRWXG 0000070 /* RWX mask for group */ #define S_IRGRP 0000040 /* R for group */ #define S_IWGRP 0000020 /* W for group */ #define S_IXGRP 0000010 /* X for group */ #define S_IRWXO 0000007 /* RWX mask for other */ #define S_IROTH 0000004 /* R for other */ #define S_IWOTH 0000002 /* W for other */ #define S_IXOTH 0000001 /* X for other */ #define S_IFMT 0170000 /* type of file mask */ #define S_IFIFO 0010000 /* named pipe (fifo) */ #define S_IFCHR 0020000 /* character special */ #define S_IFDIR 0040000 /* directory */ #define S_IFBLK 0060000 /* block special */ #define S_IFREG 0100000 /* regular */ #define S_IFLNK 0120000 /* symbolic link */ #define S_IFSOCK 0140000 /* socket */ #define S_ISVTX 0001000 /* save swapped text even after use */ #define S_IFWHT 0160000 /* whiteout */ #define S_ISDIR(m) (((m) & 0170000) == 0040000) /* directory */ #define S_ISCHR(m) (((m) & 0170000) == 0020000) /* char special */ #define S_ISBLK(m) (((m) & 0170000) == 0060000) /* block special */ #define S_ISREG(m) (((m) & 0170000) == 0100000) /* regular file */ #define S_ISFIFO(m) (((m) & 0170000) == 0010000) /* fifo or socket */ #define S_ISLNK(m) (((m) & 0170000) == 0120000) /* symbolic link */ #define S_ISSOCK(m) (((m) & 0170000) == 0140000) /* socket */ #define S_ISWHT(m) (((m) & 0170000) == 0160000) /* whiteout */ #define S_BLKSIZE 512 /* block size used in the stat struct */ #endif /*@}*/ #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/fsw_ext2.h����������������������������������������������������������������0000664�0001750�0001750�00000003762�12626644770�017621� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/** * \file fsw_ext2.h * ext2 file system driver header. */ /*- * Copyright (c) 2006 Christoph Pfisterer * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _FSW_EXT2_H_ #define _FSW_EXT2_H_ #define VOLSTRUCTNAME fsw_ext2_volume #define DNODESTRUCTNAME fsw_ext2_dnode #include "fsw_core.h" #include "fsw_ext2_disk.h" //! Block size to be used when reading the ext2 superblock. #define EXT2_SUPERBLOCK_BLOCKSIZE 1024 //! Block number where the (master copy of the) ext2 superblock resides. #define EXT2_SUPERBLOCK_BLOCKNO 1 /** * ext2: Volume structure with ext2-specific data. */ struct fsw_ext2_volume { struct fsw_volume g; //!< Generic volume structure struct ext2_super_block *sb; //!< Full raw ext2 superblock structure fsw_u32 *inotab_bno; //!< Block numbers of the inode tables fsw_u32 ind_bcnt; //!< Number of blocks addressable through an indirect block fsw_u32 dind_bcnt; //!< Number of blocks addressable through a double-indirect block fsw_u32 inode_size; //!< Size of inode structure in bytes }; /** * ext2: Dnode structure with ext2-specific data. */ struct fsw_ext2_dnode { struct fsw_dnode g; //!< Generic dnode structure struct ext2_inode *raw; //!< Full raw inode structure }; #endif ��������������refind-0.11.4/filesystems/fsw_hfs.c�����������������������������������������������������������������0000664�0001750�0001750�00000122636�12626644770�017514� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Id: fsw_hfs.c 33540 2010-10-28 09:27:05Z vboxsync $ */ /** @file * fsw_hfs.c - HFS file system driver code, see * * http://developer.apple.com/technotes/tn/tn1150.html * * Current limitations: * - Doesn't support permissions * - Complete Unicode case-insensitiveness disabled (large tables) * - No links * - Only supports pure HFS+ (i.e. no HFS, or HFS+ embedded to HFS) */ /* * Copyright (C) 2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; * you can redistribute it and/or modify it under the terms of the GNU * General Public License (GPL) as published by the Free Software * Foundation, in version 2 as it comes in the "COPYING" file of the * VirtualBox OSE distribution. VirtualBox OSE is distributed in the * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. */ #include "fsw_hfs.h" #ifdef HOST_POSIX #define DPRINT(x) printf(x) #define DPRINT2(x,y) printf(x,y) #define BP(msg) do { printf("ERROR: %s", msg); asm("int3"); } while (0) #else #define CONCAT(x,y) x##y #define DPRINT(x) Print(CONCAT(L,x)) #define DPRINT2(x,y) Print(CONCAT(L,x), y) #define BP(msg) DPRINT(msg) #endif // functions #if 0 void dump_str(fsw_u16* p, fsw_u32 len, int swap) { int i; for (i=0; i<len; i++) { fprintf(stderr, "%c", swap ? be16_to_cpu(p[i]) : p[i]); } fprintf(stderr, "\n"); } #endif static fsw_status_t fsw_hfs_volume_mount(struct fsw_hfs_volume *vol); static void fsw_hfs_volume_free(struct fsw_hfs_volume *vol); static fsw_status_t fsw_hfs_volume_stat(struct fsw_hfs_volume *vol, struct fsw_volume_stat *sb); static fsw_status_t fsw_hfs_dnode_fill(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno); static void fsw_hfs_dnode_free(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno); static fsw_status_t fsw_hfs_dnode_stat(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno, struct fsw_dnode_stat *sb); static fsw_status_t fsw_hfs_get_extent(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno, struct fsw_extent *extent); static fsw_status_t fsw_hfs_dir_lookup(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno, struct fsw_string *lookup_name, struct fsw_hfs_dnode **child_dno); static fsw_status_t fsw_hfs_dir_read(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno, struct fsw_shandle *shand, struct fsw_hfs_dnode **child_dno); #if 0 static fsw_status_t fsw_hfs_read_dirrec(struct fsw_shandle *shand, struct hfs_dirrec_buffer *dirrec_buffer); #endif static fsw_status_t fsw_hfs_readlink(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno, struct fsw_string *link); // // Dispatch Table // struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(hfs) = { { FSW_STRING_TYPE_ISO88591, 4, 4, "hfs" }, sizeof(struct fsw_hfs_volume), sizeof(struct fsw_hfs_dnode), fsw_hfs_volume_mount, // volume open fsw_hfs_volume_free, // volume close fsw_hfs_volume_stat, // volume info: total_bytes, free_bytes fsw_hfs_dnode_fill, //return FSW_SUCCESS; fsw_hfs_dnode_free, // empty fsw_hfs_dnode_stat, //size and times fsw_hfs_get_extent, // get the physical disk block number for the requested logical block number fsw_hfs_dir_lookup, //retrieve the directory entry with the given name fsw_hfs_dir_read, // next directory entry when reading a directory fsw_hfs_readlink, // return FSW_UNSUPPORTED; }; static const fsw_u16 fsw_latin_case_fold[] = { /* 0 */ 0xFFFF, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, /* 1 */ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, /* 2 */ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, /* 3 */ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, /* 4 */ 0x0040, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, /* 5 */ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, /* 6 */ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, /* 7 */ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, /* 8 */ 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, /* 9 */ 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, /* A */ 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, /* B */ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, /* C */ 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00E6, 0x00C7, 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, /* D */ 0x00F0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, 0x00F8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00FE, 0x00DF, /* E */ 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, /* F */ 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF, }; static fsw_u16 fsw_to_lower(fsw_u16 ch) { if (ch < 0x0100) return fsw_latin_case_fold[ch]; return ch; } static fsw_s32 fsw_hfs_read_block (struct fsw_hfs_dnode * dno, fsw_u32 log_bno, fsw_u32 off, fsw_s32 len, fsw_u8 * buf) { fsw_status_t status; struct fsw_extent extent; fsw_u32 phys_bno; fsw_u8* buffer; extent.log_start = log_bno; status = fsw_hfs_get_extent(dno->g.vol, dno, &extent); if (status) return status; phys_bno = extent.phys_start; //Slice - increase cache level from 0 to 3 status = fsw_block_get(dno->g.vol, phys_bno, 3, (void **)&buffer); if (status) return status; fsw_memcpy(buf, buffer + off, len); fsw_block_release(dno->g.vol, phys_bno, buffer); return FSW_SUCCESS; } /* Read data from HFS file. */ static fsw_s32 fsw_hfs_read_file (struct fsw_hfs_dnode * dno, fsw_u64 pos, fsw_s32 len, fsw_u8 * buf) { fsw_status_t status; fsw_u32 log_bno; fsw_u32 block_size_bits = dno->g.vol->block_size_shift; fsw_u32 block_size = (1 << block_size_bits); fsw_u32 block_size_mask = block_size - 1; fsw_s32 read = 0; while (len > 0) { fsw_u32 off = (fsw_u32)(pos & block_size_mask); fsw_s32 next_len = len; log_bno = (fsw_u32)RShiftU64(pos, block_size_bits); if ( next_len >= 0 && (fsw_u32)next_len > block_size) next_len = block_size; status = fsw_hfs_read_block(dno, log_bno, off, next_len, buf); if (status) return -1; buf += next_len; pos += next_len; len -= next_len; read += next_len; } return read; } static fsw_s32 fsw_hfs_compute_shift(fsw_u32 size) { fsw_s32 i; for (i=0; i<32; i++) { if ((size >> i) == 0) return i - 1; } // BP("BUG\n"); return 0; } /** * Mount an HFS+ volume. Reads the superblock and constructs the * root directory dnode. */ //algo from Chameleon /* void HFSGetDescription(CICell ih, char *str, long strMaxLen) { UInt16 nodeSize; UInt32 firstLeafNode; long long dirIndex; char *name; long flags, time; if (HFSInitPartition(ih) == -1) { return; } // Fill some crucial data structures by side effect. dirIndex = 0; HFSGetDirEntry(ih, "/", &dirIndex, &name, &flags, &time, 0, 0); // Now we can loook up the volume name node. nodeSize = be16_to_cpu(gBTHeaders[kBTreeCatalog]->nodeSize); firstLeafNode = SWAP_BE32(gBTHeaders[kBTreeCatalog]->firstLeafNode); dirIndex = (long long) firstLeafNode * nodeSize; GetCatalogEntry(&dirIndex, &name, &flags, &time, 0, 0); strncpy(str, name, strMaxLen); str[strMaxLen] = '\0'; } */ static fsw_status_t fsw_hfs_volume_mount(struct fsw_hfs_volume *vol) { fsw_status_t status, rv; void *buffer = NULL; HFSPlusVolumeHeader *voldesc; fsw_u32 blockno; struct fsw_string s; HFSMasterDirectoryBlock* mdb; fsw_u32 firstLeafNum; fsw_u64 catfOffset; fsw_u8 cbuff[sizeof (BTNodeDescriptor) + sizeof (HFSPlusCatalogKey)]; rv = FSW_UNSUPPORTED; vol->primary_voldesc = NULL; fsw_set_blocksize(vol, HFS_BLOCKSIZE, HFS_BLOCKSIZE); blockno = HFS_SUPERBLOCK_BLOCKNO; #define CHECK(s) \ if (status) { \ rv = status; \ break; \ } vol->emb_block_off = 0; vol->hfs_kind = 0; do { fsw_u16 signature; BTHeaderRec tree_header; fsw_s32 r; fsw_u32 block_size; status = fsw_block_get(vol, blockno, 0, &buffer); CHECK(status); voldesc = (HFSPlusVolumeHeader *)buffer; mdb = (HFSMasterDirectoryBlock*)buffer; signature = be16_to_cpu(voldesc->signature); if ((signature == kHFSPlusSigWord) || (signature == kHFSXSigWord)) //H+ or HX { if (vol->hfs_kind == 0) { // DPRINT("found HFS+\n"); vol->hfs_kind = FSW_HFS_PLUS; } } else if (signature == kHFSSigWord) // 'BD' { if (be16_to_cpu(mdb->drEmbedSigWord) == kHFSPlusSigWord) { DPRINT("found HFS+ inside HFS, untested\n"); vol->hfs_kind = FSW_HFS_PLUS_EMB; vol->emb_block_off = be32_to_cpu(mdb->drEmbedExtent.startBlock); blockno += vol->emb_block_off; /* retry */ continue; } else { DPRINT("found plain HFS, unsupported\n"); vol->hfs_kind = FSW_HFS_PLAIN; } rv = FSW_UNSUPPORTED; break; } else { rv = FSW_UNSUPPORTED; break; } status = fsw_memdup((void **)&vol->primary_voldesc, voldesc, sizeof(*voldesc)); CHECK(status); block_size = be32_to_cpu(voldesc->blockSize); vol->block_size_shift = fsw_hfs_compute_shift(block_size); fsw_block_release(vol, blockno, buffer); buffer = NULL; voldesc = NULL; fsw_set_blocksize(vol, block_size, block_size); /* set default/fallback volume name */ s.type = FSW_STRING_TYPE_ISO88591; s.size = s.len = kHFSMaxVolumeNameChars; s.data = "HFS+ volume"; status = fsw_strdup_coerce(&vol->g.label, vol->g.host_string_type, &s); CHECK(status); /* Setup catalog dnode */ status = fsw_dnode_create_root(vol, kHFSCatalogFileID, &vol->catalog_tree.file); CHECK(status); fsw_memcpy (vol->catalog_tree.file->extents, vol->primary_voldesc->catalogFile.extents, sizeof vol->catalog_tree.file->extents); vol->catalog_tree.file->g.size = be64_to_cpu(vol->primary_voldesc->catalogFile.logicalSize); /* Setup extents overflow file */ status = fsw_dnode_create_root(vol, kHFSExtentsFileID, &vol->extents_tree.file); fsw_memcpy (vol->extents_tree.file->extents, vol->primary_voldesc->extentsFile.extents, sizeof vol->extents_tree.file->extents); vol->extents_tree.file->g.size = be64_to_cpu(vol->primary_voldesc->extentsFile.logicalSize); /* Setup the root dnode */ status = fsw_dnode_create_root(vol, kHFSRootFolderID, &vol->g.root); CHECK(status); /* * Read catalog file, we know that first record is in the first node, right after * the node descriptor. */ r = fsw_hfs_read_file(vol->catalog_tree.file, sizeof (BTNodeDescriptor), sizeof (BTHeaderRec), (fsw_u8 *) &tree_header); if (r <= 0) { status = FSW_VOLUME_CORRUPTED; break; } vol->case_sensitive = (signature == kHFSXSigWord) && (tree_header.keyCompareType == kHFSBinaryCompare); vol->catalog_tree.root_node = be32_to_cpu (tree_header.rootNode); vol->catalog_tree.node_size = be16_to_cpu (tree_header.nodeSize); //nms42 /* Take Volume Name before tree_header overwritten */ firstLeafNum = be32_to_cpu(tree_header.firstLeafNode); catfOffset = firstLeafNum * vol->catalog_tree.node_size; r = fsw_hfs_read_file(vol->catalog_tree.file, catfOffset, sizeof (cbuff), cbuff); if (r == sizeof (cbuff)) { BTNodeDescriptor* btnd; HFSPlusCatalogKey* ck; btnd = (BTNodeDescriptor*) cbuff; ck = (HFSPlusCatalogKey*) (cbuff + sizeof(BTNodeDescriptor)); if (btnd->kind == kBTLeafNode && be32_to_cpu (ck->parentID) == kHFSRootParentID) { struct fsw_string vn; vn.type = FSW_STRING_TYPE_UTF16_BE; vn.len = be16_to_cpu (ck->nodeName.length); vn.size = vn.len * sizeof (fsw_u16); vn.data = ck->nodeName.unicode; fsw_strfree (&vol->g.label); status = fsw_strdup_coerce(&vol->g.label, vol->g.host_string_type, &vn); CHECK(status); } // if } // if /* Read extents overflow file */ r = fsw_hfs_read_file(vol->extents_tree.file, sizeof (BTNodeDescriptor), sizeof (BTHeaderRec), (fsw_u8 *) &tree_header); if (r <= 0) { status = FSW_VOLUME_CORRUPTED; break; } vol->extents_tree.root_node = be32_to_cpu (tree_header.rootNode); vol->extents_tree.node_size = be16_to_cpu (tree_header.nodeSize); rv = FSW_SUCCESS; } while (0); #undef CHECK if (buffer != NULL) fsw_block_release(vol, blockno, buffer); return rv; } //Here is a method to obtain Volume label from Apple //how to implement it? /* UInt16 nodeSize; UInt32 firstLeafNode; long long dirIndex; char *name; long flags, time; char *nodeBuf, *testKey, *entry; if (HFSInitPartition(ih) == -1) { return; } // Fill some crucial data structures by side effect. dirIndex = 0; HFSGetDirEntry(ih, "/", &dirIndex, &name, &flags, &time, 0, 0); // Now we can loook up the volume name node. nodeSize = SWAP_BE16(gBTHeaders[kBTreeCatalog]->nodeSize); firstLeafNode = SWAP_BE32(gBTHeaders[kBTreeCatalog]->firstLeafNode); dirIndex = (long long) firstLeafNode * nodeSize; index = (long) (*dirIndex % nodeSize); == 0 curNode = (long) (*dirIndex / nodeSize); == firstLeafNode //GetCatalogEntry(&dirIndex, &name, &flags, &time, 0, 0); // Read the BTree node and get the record for index. ReadExtent(extent, extentSize, kHFSCatalogFileID, (long long) curNode * nodeSize, nodeSize, nodeBuf, 1); GetBTreeRecord(index, nodeBuf, nodeSize, &testKey, &entry); utf_encodestr(((HFSPlusCatalogKey *)testKey)->nodeName.unicode, SWAP_BE16(((HFSPlusCatalogKey *)testKey)->nodeName.length), (u_int8_t *)gTempStr, 256, OSBigEndian); *name = gTempStr; strncpy(str, name, strMaxLen); str[strMaxLen] = '\0'; */ /** * Free the volume data structure. Called by the core after an unmount or after * an unsuccessful mount to release the memory used by the file system type specific * part of the volume structure. */ static void fsw_hfs_volume_free(struct fsw_hfs_volume *vol) { if (vol->primary_voldesc) { fsw_free(vol->primary_voldesc); vol->primary_voldesc = NULL; } } /** * Get in-depth information on a volume. */ static fsw_status_t fsw_hfs_volume_stat(struct fsw_hfs_volume *vol, struct fsw_volume_stat *sb) { sb->total_bytes = be32_to_cpu(vol->primary_voldesc->totalBlocks) << vol->block_size_shift; sb->free_bytes = be32_to_cpu(vol->primary_voldesc->freeBlocks) << vol->block_size_shift; return FSW_SUCCESS; } /** * Get full information on a dnode from disk. This function is called by the core * whenever it needs to access fields in the dnode structure that may not * be filled immediately upon creation of the dnode. */ static fsw_status_t fsw_hfs_dnode_fill(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno) { return FSW_SUCCESS; } /** * Free the dnode data structure. Called by the core when deallocating a dnode * structure to release the memory used by the file system type specific part * of the dnode structure. */ static void fsw_hfs_dnode_free(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno) { } static fsw_u32 mac_to_posix(fsw_u32 mac_time) { /* Mac time is 1904 year based */ return mac_time ? mac_time - 2082844800 : 0; } /** * Get in-depth information on a dnode. The core makes sure that fsw_hfs_dnode_fill * has been called on the dnode before this function is called. Note that some * data is not directly stored into the structure, but passed to a host-specific * callback that converts it to the host-specific format. */ static fsw_status_t fsw_hfs_dnode_stat(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno, struct fsw_dnode_stat *sb) { sb->used_bytes = dno->used_bytes; fsw_store_time_posix(sb, FSW_DNODE_STAT_CTIME, mac_to_posix(dno->ctime)); fsw_store_time_posix(sb, FSW_DNODE_STAT_MTIME, mac_to_posix(dno->mtime)); fsw_store_time_posix(sb, FSW_DNODE_STAT_ATIME, 0); fsw_store_attr_posix(sb, 0700); return FSW_SUCCESS; } static int fsw_hfs_find_block(HFSPlusExtentRecord * exts, fsw_u32 * lbno, fsw_u32 * pbno) { int i; fsw_u32 cur_lbno = *lbno; for (i = 0; i < 8; i++) { fsw_u32 start = be32_to_cpu ((*exts)[i].startBlock); fsw_u32 count = be32_to_cpu ((*exts)[i].blockCount); if (cur_lbno < count) { *pbno = start + cur_lbno; return 1; } cur_lbno -= count; } *lbno = cur_lbno; return 0; } /* Find record offset, numbering starts from the end */ static fsw_u32 fsw_hfs_btree_recoffset (struct fsw_hfs_btree * btree, BTNodeDescriptor * node, fsw_u32 index) { fsw_u8 *cnode = (fsw_u8 *) node; fsw_u16 *recptr; recptr = (fsw_u16 *) (cnode+btree->node_size - index * 2 - 2); return be16_to_cpu(*recptr); } /* Pointer to the key inside node */ static BTreeKey * fsw_hfs_btree_rec (struct fsw_hfs_btree * btree, BTNodeDescriptor * node, fsw_u32 index) { fsw_u8 *cnode = (fsw_u8 *) node; fsw_u32 offset; offset = fsw_hfs_btree_recoffset (btree, node, index); return (BTreeKey *) (cnode + offset); } static fsw_status_t fsw_hfs_btree_search (struct fsw_hfs_btree * btree, BTreeKey * key, int (*compare_keys) (BTreeKey* key1, BTreeKey* key2), BTNodeDescriptor ** result, fsw_u32 * key_offset) { BTNodeDescriptor* node; fsw_u32 currnode; fsw_u32 rec; fsw_status_t status; fsw_u8* buffer = NULL; currnode = btree->root_node; status = fsw_alloc(btree->node_size, &buffer); if (status) return status; node = (BTNodeDescriptor*)buffer; while (1) { int cmp = 0; int match; fsw_u32 count; readnode: match = 0; /* Read a node. */ if (fsw_hfs_read_file (btree->file, (fsw_u64)currnode * btree->node_size, btree->node_size, buffer) <= 0) { status = FSW_VOLUME_CORRUPTED; break; } if (be16_to_cpu(*(fsw_u16*)(buffer + btree->node_size - 2)) != sizeof(BTNodeDescriptor)) BP("corrupted node\n"); count = be16_to_cpu (node->numRecords); #if 1 for (rec = 0; rec < count; rec++) { BTreeKey *currkey; currkey = fsw_hfs_btree_rec (btree, node, rec); cmp = compare_keys (currkey, key); //fprintf(stderr, "rec=%d cmp=%d kind=%d \n", rec, cmp, node->kind); /* Leaf node. */ if (node->kind == kBTLeafNode) { if (cmp == 0) { /* Found! */ *result = node; *key_offset = rec; status = FSW_SUCCESS; goto done; } } else if (node->kind == kBTIndexNode) { fsw_u32 *pointer; if (cmp > 0) break; pointer = (fsw_u32 *) ((char *) currkey + be16_to_cpu (currkey->length16) + 2); currnode = be32_to_cpu (*pointer); match = 1; } } if (node->kind == kBTLeafNode && cmp < 0 && node->fLink) { currnode = be32_to_cpu(node->fLink); goto readnode; } else if (!match) { status = FSW_NOT_FOUND; break; } #else /* Perform binary search */ fsw_u32 lower = 0; fsw_u32 upper = count - 1; fsw_s32 cmp = -1; BTreeKey *currkey = NULL; if (count == 0) { status = FSW_NOT_FOUND; goto done; } while (lower <= upper) { fsw_u32 index = (lower + upper) / 2; currkey = fsw_hfs_btree_rec (btree, node, index); cmp = compare_keys (currkey, key); if (cmp < 0) upper = index - 1; if (cmp > 0) lower = index + 1; if (cmp == 0) { /* Found! */ *result = node; *key_offset = rec; status = FSW_SUCCESS; goto done; } } if (cmp < 0) currkey = fsw_hfs_btree_rec (btree, node, upper); if (node->kind == kBTIndexNode && currkey) { fsw_u32 *pointer; pointer = (fsw_u32 *) ((char *) currkey + be16_to_cpu (currkey->length16) + 2); currnode = be32_to_cpu (*pointer); } else { status = FSW_NOT_FOUND; break; } #endif } done: if (buffer != NULL && status != FSW_SUCCESS) fsw_free(buffer); return status; } typedef struct { fsw_u32 id; fsw_u32 type; struct fsw_string * name; fsw_u64 size; fsw_u64 used; fsw_u32 ctime; fsw_u32 mtime; HFSPlusExtentRecord extents; } file_info_t; typedef struct { fsw_u32 cur_pos; /* current position */ fsw_u32 parent; struct fsw_hfs_volume * vol; struct fsw_shandle * shandle; /* this one track iterator's state */ file_info_t file_info; } visitor_parameter_t; static int fsw_hfs_btree_visit_node(BTreeKey *record, void* param) { visitor_parameter_t* vp = (visitor_parameter_t*)param; fsw_u8* base = (fsw_u8*)record->rawData + be16_to_cpu(record->length16) + 2; fsw_u16 rec_type = be16_to_cpu(*(fsw_u16*)base); struct HFSPlusCatalogKey* cat_key = (HFSPlusCatalogKey*)record; fsw_u16 name_len; fsw_u16 *name_ptr; fsw_u32 i; struct fsw_string * file_name; if (be32_to_cpu(cat_key->parentID) != vp->parent) return -1; /* not smth we care about */ if (vp->shandle->pos != vp->cur_pos++) return 0; switch (rec_type) { case kHFSPlusFolderRecord: { HFSPlusCatalogFolder* folder_info = (HFSPlusCatalogFolder*)base; vp->file_info.id = be32_to_cpu(folder_info->folderID); vp->file_info.type = FSW_DNODE_TYPE_DIR; vp->file_info.size = be32_to_cpu(folder_info->valence); vp->file_info.used = be32_to_cpu(folder_info->valence); vp->file_info.ctime = be32_to_cpu(folder_info->createDate); vp->file_info.mtime = be32_to_cpu(folder_info->contentModDate); break; } case kHFSPlusFileRecord: { HFSPlusCatalogFile* file_info = (HFSPlusCatalogFile*)base; vp->file_info.id = be32_to_cpu(file_info->fileID); vp->file_info.type = FSW_DNODE_TYPE_FILE; vp->file_info.size = be64_to_cpu(file_info->dataFork.logicalSize); vp->file_info.used = LShiftU64(be32_to_cpu(file_info->dataFork.totalBlocks), vp->vol->block_size_shift); vp->file_info.ctime = be32_to_cpu(file_info->createDate); vp->file_info.mtime = be32_to_cpu(file_info->contentModDate); fsw_memcpy(&vp->file_info.extents, &file_info->dataFork.extents, sizeof vp->file_info.extents); break; } case kHFSPlusFolderThreadRecord: case kHFSPlusFileThreadRecord: { vp->shandle->pos++; return 0; } default: BP("unknown file type\n"); vp->file_info.type = FSW_DNODE_TYPE_UNKNOWN; break; } name_len = be16_to_cpu(cat_key->nodeName.length); file_name = vp->file_info.name; file_name->len = name_len; fsw_memdup(&file_name->data, &cat_key->nodeName.unicode[0], 2*name_len); file_name->size = 2*name_len; file_name->type = FSW_STRING_TYPE_UTF16; name_ptr = (fsw_u16*)file_name->data; for (i=0; i<name_len; i++) { name_ptr[i] = be16_to_cpu(name_ptr[i]); } vp->shandle->pos++; return 1; } static fsw_status_t fsw_hfs_btree_iterate_node (struct fsw_hfs_btree * btree, BTNodeDescriptor * first_node, fsw_u32 first_rec, int (*callback) (BTreeKey *record, void* param), void * param) { fsw_status_t status; /* We modify node, so make a copy */ BTNodeDescriptor* node = first_node; fsw_u8* buffer = NULL; status = fsw_alloc(btree->node_size, &buffer); if (status) return status; while (1) { fsw_u32 i; fsw_u32 count = be16_to_cpu(node->numRecords); fsw_u32 next_node; /* Iterate over all records in this node. */ for (i = first_rec; i < count; i++) { int rv = callback(fsw_hfs_btree_rec (btree, node, i), param); switch (rv) { case 1: status = FSW_SUCCESS; goto done; case -1: status = FSW_NOT_FOUND; goto done; } /* if callback returned 0 - continue */ } next_node = be32_to_cpu(node->fLink); if (!next_node) { status = FSW_NOT_FOUND; break; } if (fsw_hfs_read_file (btree->file, next_node * btree->node_size, btree->node_size, buffer) <= 0) { status = FSW_VOLUME_CORRUPTED; return 1; } node = (BTNodeDescriptor*)buffer; first_rec = 0; } done: if (buffer) fsw_free(buffer); return status; } #if 0 void deb(fsw_u16* p, int len, int swap) { int i; for (i=0; i<len; i++) { printf("%c", swap ? be16_to_cpu(p[i]) : p[i]); } printf("\n"); } #endif static int fsw_hfs_cmp_extkey(BTreeKey* key1, BTreeKey* key2) { HFSPlusExtentKey* ekey1 = (HFSPlusExtentKey*)key1; HFSPlusExtentKey* ekey2 = (HFSPlusExtentKey*)key2; int result; /* First key is read from the FS data, second is in-memory in CPU endianess */ result = be32_to_cpu(ekey1->fileID) - ekey2->fileID; if (result) return result; result = ekey1->forkType - ekey2->forkType; if (result) return result; result = be32_to_cpu(ekey1->startBlock) - ekey2->startBlock; return result; } static int fsw_hfs_cmp_catkey (BTreeKey *key1, BTreeKey *key2) { HFSPlusCatalogKey *ckey1 = (HFSPlusCatalogKey*)key1; HFSPlusCatalogKey *ckey2 = (HFSPlusCatalogKey*)key2; int apos, bpos, lc; fsw_u16 ac, bc; fsw_u32 parentId1; int key1Len; fsw_u16 *p1; fsw_u16 *p2; parentId1 = be32_to_cpu(ckey1->parentID); if (parentId1 > ckey2->parentID) return 1; if (parentId1 < ckey2->parentID) return -1; p1 = &ckey1->nodeName.unicode[0]; p2 = &ckey2->nodeName.unicode[0]; key1Len = be16_to_cpu (ckey1->nodeName.length); apos = bpos = 0; while(1) { /* get next valid character from ckey1 */ for (lc = 0; lc == 0 && apos < key1Len; apos++) { ac = be16_to_cpu(p1[apos]); lc = ac; }; ac = (fsw_u16)lc; /* get next valid character from ckey2 */ for (lc = 0; lc == 0 && bpos < ckey2->nodeName.length; bpos++) { bc = p2[bpos]; lc = bc; }; bc = (fsw_u16)lc; if (ac != bc || (ac == 0 && bc == 0)) return ac - bc; } } static int fsw_hfs_cmpi_catkey (BTreeKey *key1, BTreeKey *key2) { HFSPlusCatalogKey *ckey1 = (HFSPlusCatalogKey*)key1; HFSPlusCatalogKey *ckey2 = (HFSPlusCatalogKey*)key2; int apos, bpos, lc; fsw_u16 ac, bc; fsw_u32 parentId1; int key1Len; fsw_u16 *p1; fsw_u16 *p2; parentId1 = be32_to_cpu(ckey1->parentID); if (parentId1 > ckey2->parentID) return 1; if (parentId1 < ckey2->parentID) return -1; key1Len = be16_to_cpu (ckey1->nodeName.length); if (key1Len == 0 && ckey2->nodeName.length == 0) return 0; p1 = &ckey1->nodeName.unicode[0]; p2 = &ckey2->nodeName.unicode[0]; apos = bpos = 0; while(1) { /* get next valid character from ckey1 */ for (lc = 0; lc == 0 && apos < key1Len; apos++) { ac = be16_to_cpu(p1[apos]); lc = ac ? fsw_to_lower(ac) : 0; }; ac = (fsw_u16)lc; /* get next valid character from ckey2 */ for (lc = 0; lc == 0 && bpos < ckey2->nodeName.length; bpos++) { bc = p2[bpos]; lc = bc ? fsw_to_lower(bc) : 0; }; bc = (fsw_u16)lc; if (ac != bc || (ac == 0 && bc == 0)) return ac - bc; } } /** * Retrieve file data mapping information. This function is called by the core when * fsw_shandle_read needs to know where on the disk the required piece of the file's * data can be found. The core makes sure that fsw_hfs_dnode_fill has been called * on the dnode before. Our task here is to get the physical disk block number for * the requested logical block number. */ static fsw_status_t fsw_hfs_get_extent(struct fsw_hfs_volume * vol, struct fsw_hfs_dnode * dno, struct fsw_extent * extent) { fsw_status_t status; fsw_u32 lbno; HFSPlusExtentRecord *exts; BTNodeDescriptor *node = NULL; extent->type = FSW_EXTENT_TYPE_PHYSBLOCK; extent->log_count = 1; lbno = extent->log_start; /* we only care about data forks atm, do we? */ exts = &dno->extents; while (1) { struct HFSPlusExtentKey* key; struct HFSPlusExtentKey overflowkey; fsw_u32 ptr; fsw_u32 phys_bno; if (fsw_hfs_find_block(exts, &lbno, &phys_bno)) { extent->phys_start = phys_bno + vol->emb_block_off; status = FSW_SUCCESS; break; } /* Find appropriate overflow record */ overflowkey.fileID = dno->g.dnode_id; overflowkey.startBlock = extent->log_start - lbno; if (node != NULL) { fsw_free(node); node = NULL; } status = fsw_hfs_btree_search (&vol->extents_tree, (BTreeKey*)&overflowkey, fsw_hfs_cmp_extkey, &node, &ptr); if (status) break; key = (struct HFSPlusExtentKey *) fsw_hfs_btree_rec (&vol->extents_tree, node, ptr); exts = (HFSPlusExtentRecord*) (key + 1); } if (node != NULL) fsw_free(node); return status; } static const fsw_u16* g_blacklist[] = { //L"AppleIntelCPUPowerManagement.kext", NULL }; //#define HFS_FILE_INJECTION #ifdef HFS_FILE_INJECTION static struct { const fsw_u16* path; const fsw_u16* name; } g_injectList[] = { { L"/System/Library/Extensions", L"ApplePS2Controller.kext" }, { NULL, NULL } }; #endif static fsw_status_t create_hfs_dnode(struct fsw_hfs_dnode * dno, file_info_t * file_info, struct fsw_hfs_dnode ** child_dno_out) { fsw_status_t status; struct fsw_hfs_dnode * baby; status = fsw_dnode_create(dno, file_info->id, file_info->type, file_info->name, &baby); if (status) return status; baby->g.size = file_info->size; baby->used_bytes = file_info->used; baby->ctime = file_info->ctime; baby->mtime = file_info->mtime; /* Fill-in extents info */ if (file_info->type == FSW_DNODE_TYPE_FILE) { fsw_memcpy(baby->extents, &file_info->extents, sizeof file_info->extents); } *child_dno_out = baby; return FSW_SUCCESS; } /** * Lookup a directory's child dnode by name. This function is called on a directory * to retrieve the directory entry with the given name. A dnode is constructed for * this entry and returned. The core makes sure that fsw_hfs_dnode_fill has been called * and the dnode is actually a directory. */ static fsw_status_t fsw_hfs_dir_lookup(struct fsw_hfs_volume * vol, struct fsw_hfs_dnode * dno, struct fsw_string * lookup_name, struct fsw_hfs_dnode ** child_dno_out) { fsw_status_t status; struct HFSPlusCatalogKey catkey; fsw_u32 ptr; fsw_u16 rec_type; BTNodeDescriptor * node = NULL; struct fsw_string rec_name; int free_data = 0, i; HFSPlusCatalogKey* file_key; file_info_t file_info; fsw_u8* base; fsw_memzero(&file_info, sizeof file_info); file_info.name = &rec_name; catkey.parentID = dno->g.dnode_id; catkey.nodeName.length = (fsw_u16)lookup_name->len; /* no need to allocate anything */ if (lookup_name->type == FSW_STRING_TYPE_UTF16) { fsw_memcpy(catkey.nodeName.unicode, lookup_name->data, lookup_name->size); rec_name = *lookup_name; } else { status = fsw_strdup_coerce(&rec_name, FSW_STRING_TYPE_UTF16, lookup_name); /* nothing allocated so far */ if (status) goto done; free_data = 1; fsw_memcpy(catkey.nodeName.unicode, rec_name.data, rec_name.size); } /* Dirty hack: blacklisting of certain files on FS driver level */ for (i = 0; g_blacklist[i]; i++) { if (fsw_memeq(g_blacklist[i], catkey.nodeName.unicode, catkey.nodeName.length*2)) { DPRINT2("Blacklisted %s\n", g_blacklist[i]); status = FSW_NOT_FOUND; goto done; } } #ifdef HFS_FILE_INJECTION if (fsw_hfs_inject(vol, dno, catkey.nodeName.unicode, catkey.nodeName.length, &file_info)) { status = FSW_SUCCESS; goto create; } #endif catkey.keyLength = (fsw_u16)(5 + rec_name.size); status = fsw_hfs_btree_search (&vol->catalog_tree, (BTreeKey*)&catkey, vol->case_sensitive ? fsw_hfs_cmp_catkey : fsw_hfs_cmpi_catkey, &node, &ptr); if (status) goto done; file_key = (HFSPlusCatalogKey *)fsw_hfs_btree_rec (&vol->catalog_tree, node, ptr); /* for plain HFS "-(keySize & 1)" would be needed */ base = (fsw_u8*)file_key + be16_to_cpu(file_key->keyLength) + 2; rec_type = be16_to_cpu(*(fsw_u16*)base); /** @todo: read additional info */ switch (rec_type) { case kHFSPlusFolderRecord: { HFSPlusCatalogFolder* info = (HFSPlusCatalogFolder*)base; file_info.id = be32_to_cpu(info->folderID); file_info.type = FSW_DNODE_TYPE_DIR; /* @todo: return number of elements, maybe use smth else */ file_info.size = be32_to_cpu(info->valence); file_info.used = be32_to_cpu(info->valence); file_info.ctime = be32_to_cpu(info->createDate); file_info.mtime = be32_to_cpu(info->contentModDate); break; } case kHFSPlusFileRecord: { HFSPlusCatalogFile* info = (HFSPlusCatalogFile*)base; file_info.id = be32_to_cpu(info->fileID); file_info.type = FSW_DNODE_TYPE_FILE; file_info.size = be64_to_cpu(info->dataFork.logicalSize); file_info.used = LShiftU64(be32_to_cpu(info->dataFork.totalBlocks), vol->block_size_shift); file_info.ctime = be32_to_cpu(info->createDate); file_info.mtime = be32_to_cpu(info->contentModDate); fsw_memcpy(&file_info.extents, &info->dataFork.extents, sizeof file_info.extents); break; } default: BP("unknown file type\n"); file_info.type = FSW_DNODE_TYPE_UNKNOWN; break; } #ifdef HFS_FILE_INJECTION create: #endif status = create_hfs_dnode(dno, &file_info, child_dno_out); if (status) goto done; done: if (node != NULL) fsw_free(node); if (free_data) fsw_strfree(&rec_name); return status; } /** * Get the next directory entry when reading a directory. This function is called during * directory iteration to retrieve the next directory entry. A dnode is constructed for * the entry and returned. The core makes sure that fsw_hfs_dnode_fill has been called * and the dnode is actually a directory. The shandle provided by the caller is used to * record the position in the directory between calls. */ static fsw_status_t fsw_hfs_dir_read(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno, struct fsw_shandle *shand, struct fsw_hfs_dnode **child_dno_out) { fsw_status_t status; struct HFSPlusCatalogKey catkey; fsw_u32 ptr; BTNodeDescriptor * node = NULL; visitor_parameter_t param; struct fsw_string rec_name; catkey.parentID = dno->g.dnode_id; catkey.nodeName.length = 0; fsw_memzero(¶m, sizeof(param)); rec_name.type = FSW_STRING_TYPE_EMPTY; param.file_info.name = &rec_name; status = fsw_hfs_btree_search (&vol->catalog_tree, (BTreeKey*)&catkey, vol->case_sensitive ? fsw_hfs_cmp_catkey : fsw_hfs_cmpi_catkey, &node, &ptr); if (status) goto done; /* Iterator updates shand state */ param.vol = vol; param.shandle = shand; param.parent = dno->g.dnode_id; param.cur_pos = 0; status = fsw_hfs_btree_iterate_node (&vol->catalog_tree, node, ptr, fsw_hfs_btree_visit_node, ¶m); if (status) goto done; status = create_hfs_dnode(dno, ¶m.file_info, child_dno_out); if (status) goto done; done: fsw_strfree(&rec_name); return status; } /** * Get the target path of a symbolic link. This function is called when a symbolic * link needs to be resolved. The core makes sure that the fsw_hfs_dnode_fill has been * called on the dnode and that it really is a symlink. * */ static fsw_status_t fsw_hfs_readlink(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno, struct fsw_string *link_target) { return FSW_UNSUPPORTED; } // EOF ��������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/crc32c.c������������������������������������������������������������������0000664�0001750�0001750�00000003620�13112612263�017102� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * this file take from grub 2.0 * for btrfs UEFI driver */ /* * GRUB -- GRand Unified Bootloader * Copyright (C) 2008 Free Software Foundation, Inc. * * GRUB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRUB is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GRUB. If not, see <http://www.gnu.org/licenses/>. */ static uint32_t crc32c_table [256]; static void init_crc32c_table (void) { auto uint32_t reflect (uint32_t ref, int len); uint32_t reflect (uint32_t ref, int len) { uint32_t result = 0; int i; for (i = 1; i <= len; i++) { if (ref & 1) result |= 1 << (len - i); ref >>= 1; } return result; } static int crc32c_table_inited; if(crc32c_table_inited) return; crc32c_table_inited = 1; uint32_t polynomial = 0x1edc6f41; int i, j; for(i = 0; i < 256; i++) { crc32c_table[i] = reflect(i, 8) << 24; for (j = 0; j < 8; j++) crc32c_table[i] = (crc32c_table[i] << 1) ^ (crc32c_table[i] & (1 << 31) ? polynomial : 0); crc32c_table[i] = reflect(crc32c_table[i], 32); } } uint32_t grub_getcrc32c (uint32_t crc, const void *buf, int size) { int i; const uint8_t *data = buf; if (! crc32c_table[1]) init_crc32c_table (); crc^= 0xffffffff; for (i = 0; i < size; i++) { crc = (crc >> 8) ^ crc32c_table[(crc & 0xFF) ^ *data]; data++; } return crc ^ 0xffffffff; } ����������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/lzodefs.h�����������������������������������������������������������������0000664�0001750�0001750�00000205544�12626644770�017530� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * this file take from grub 2.0 * for btrfs UEFI driver */ /* lzodefs.h -- architecture, OS and compiler specific defines This file is part of the LZO real-time data compression library. Copyright (C) 2011 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2010 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2009 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer All Rights Reserved. The LZO library is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The LZO library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the LZO library; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Markus F.X.J. Oberhumer <markus@oberhumer.com> http://www.oberhumer.com/opensource/lzo/ */ #ifndef __LZODEFS_H_INCLUDED #define __LZODEFS_H_INCLUDED 1 #if defined(__CYGWIN32__) && !defined(__CYGWIN__) # define __CYGWIN__ __CYGWIN32__ #endif #if defined(__IBMCPP__) && !defined(__IBMC__) # define __IBMC__ __IBMCPP__ #endif #if defined(__ICL) && defined(_WIN32) && !defined(__INTEL_COMPILER) # define __INTEL_COMPILER __ICL #endif #if 1 && defined(__INTERIX) && defined(__GNUC__) && !defined(_ALL_SOURCE) # define _ALL_SOURCE 1 #endif #if defined(__mips__) && defined(__R5900__) # if !defined(__LONG_MAX__) # define __LONG_MAX__ 9223372036854775807L # endif #endif #if defined(__INTEL_COMPILER) && defined(__linux__) # pragma warning(disable: 193) #endif #if defined(__KEIL__) && defined(__C166__) # pragma warning disable = 322 #elif 0 && defined(__C251__) # pragma warning disable = 322 #endif #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__MWERKS__) # if (_MSC_VER >= 1300) # pragma warning(disable: 4668) # endif #endif #if 0 && defined(__WATCOMC__) # if (__WATCOMC__ >= 1050) && (__WATCOMC__ < 1060) # pragma warning 203 9 # endif #endif #if defined(__BORLANDC__) && defined(__MSDOS__) && !defined(__FLAT__) # pragma option -h #endif #if 0 #define LZO_0xffffL 0xfffful #define LZO_0xffffffffL 0xfffffffful #else #define LZO_0xffffL 65535ul #define LZO_0xffffffffL 4294967295ul #endif #if (LZO_0xffffL == LZO_0xffffffffL) # error "your preprocessor is broken 1" #endif #if (16ul * 16384ul != 262144ul) # error "your preprocessor is broken 2" #endif #if 0 #if (32767 >= 4294967295ul) # error "your preprocessor is broken 3" #endif #if (65535u >= 4294967295ul) # error "your preprocessor is broken 4" #endif #endif #if (UINT_MAX == LZO_0xffffL) #if defined(__ZTC__) && defined(__I86__) && !defined(__OS2__) # if !defined(MSDOS) # define MSDOS 1 # endif # if !defined(_MSDOS) # define _MSDOS 1 # endif #elif 0 && defined(__VERSION) && defined(MB_LEN_MAX) # if (__VERSION == 520) && (MB_LEN_MAX == 1) # if !defined(__AZTEC_C__) # define __AZTEC_C__ __VERSION # endif # if !defined(__DOS__) # define __DOS__ 1 # endif # endif #endif #endif #if defined(_MSC_VER) && defined(M_I86HM) && (UINT_MAX == LZO_0xffffL) # define ptrdiff_t long # define _PTRDIFF_T_DEFINED 1 #endif #if (UINT_MAX == LZO_0xffffL) # undef __LZO_RENAME_A # undef __LZO_RENAME_B # if defined(__AZTEC_C__) && defined(__DOS__) # define __LZO_RENAME_A 1 # elif defined(_MSC_VER) && defined(MSDOS) # if (_MSC_VER < 600) # define __LZO_RENAME_A 1 # elif (_MSC_VER < 700) # define __LZO_RENAME_B 1 # endif # elif defined(__TSC__) && defined(__OS2__) # define __LZO_RENAME_A 1 # elif defined(__MSDOS__) && defined(__TURBOC__) && (__TURBOC__ < 0x0410) # define __LZO_RENAME_A 1 # elif defined(__PACIFIC__) && defined(DOS) # if !defined(__far) # define __far far # endif # if !defined(__near) # define __near near # endif # endif # if defined(__LZO_RENAME_A) # if !defined(__cdecl) # define __cdecl cdecl # endif # if !defined(__far) # define __far far # endif # if !defined(__huge) # define __huge huge # endif # if !defined(__near) # define __near near # endif # if !defined(__pascal) # define __pascal pascal # endif # if !defined(__huge) # define __huge huge # endif # elif defined(__LZO_RENAME_B) # if !defined(__cdecl) # define __cdecl _cdecl # endif # if !defined(__far) # define __far _far # endif # if !defined(__huge) # define __huge _huge # endif # if !defined(__near) # define __near _near # endif # if !defined(__pascal) # define __pascal _pascal # endif # elif (defined(__PUREC__) || defined(__TURBOC__)) && defined(__TOS__) # if !defined(__cdecl) # define __cdecl cdecl # endif # if !defined(__pascal) # define __pascal pascal # endif # endif # undef __LZO_RENAME_A # undef __LZO_RENAME_B #endif #if (UINT_MAX == LZO_0xffffL) #if defined(__AZTEC_C__) && defined(__DOS__) # define LZO_BROKEN_CDECL_ALT_SYNTAX 1 #elif defined(_MSC_VER) && defined(MSDOS) # if (_MSC_VER < 600) # define LZO_BROKEN_INTEGRAL_CONSTANTS 1 # endif # if (_MSC_VER < 700) # define LZO_BROKEN_INTEGRAL_PROMOTION 1 # define LZO_BROKEN_SIZEOF 1 # endif #elif defined(__PACIFIC__) && defined(DOS) # define LZO_BROKEN_INTEGRAL_CONSTANTS 1 #elif defined(__TURBOC__) && defined(__MSDOS__) # if (__TURBOC__ < 0x0150) # define LZO_BROKEN_CDECL_ALT_SYNTAX 1 # define LZO_BROKEN_INTEGRAL_CONSTANTS 1 # define LZO_BROKEN_INTEGRAL_PROMOTION 1 # endif # if (__TURBOC__ < 0x0200) # define LZO_BROKEN_SIZEOF 1 # endif # if (__TURBOC__ < 0x0400) && defined(__cplusplus) # define LZO_BROKEN_CDECL_ALT_SYNTAX 1 # endif #elif (defined(__PUREC__) || defined(__TURBOC__)) && defined(__TOS__) # define LZO_BROKEN_CDECL_ALT_SYNTAX 1 # define LZO_BROKEN_SIZEOF 1 #endif #endif #if defined(__WATCOMC__) && (__WATCOMC__ < 900) # define LZO_BROKEN_INTEGRAL_CONSTANTS 1 #endif #if defined(_CRAY) && defined(_CRAY1) # define LZO_BROKEN_SIGNED_RIGHT_SHIFT 1 #endif #define LZO_PP_STRINGIZE(x) #x #define LZO_PP_MACRO_EXPAND(x) LZO_PP_STRINGIZE(x) #define LZO_PP_CONCAT2(a,b) a ## b #define LZO_PP_CONCAT3(a,b,c) a ## b ## c #define LZO_PP_CONCAT4(a,b,c,d) a ## b ## c ## d #define LZO_PP_CONCAT5(a,b,c,d,e) a ## b ## c ## d ## e #define LZO_PP_ECONCAT2(a,b) LZO_PP_CONCAT2(a,b) #define LZO_PP_ECONCAT3(a,b,c) LZO_PP_CONCAT3(a,b,c) #define LZO_PP_ECONCAT4(a,b,c,d) LZO_PP_CONCAT4(a,b,c,d) #define LZO_PP_ECONCAT5(a,b,c,d,e) LZO_PP_CONCAT5(a,b,c,d,e) #if 1 #define LZO_CPP_STRINGIZE(x) #x #define LZO_CPP_MACRO_EXPAND(x) LZO_CPP_STRINGIZE(x) #define LZO_CPP_CONCAT2(a,b) a ## b #define LZO_CPP_CONCAT3(a,b,c) a ## b ## c #define LZO_CPP_CONCAT4(a,b,c,d) a ## b ## c ## d #define LZO_CPP_CONCAT5(a,b,c,d,e) a ## b ## c ## d ## e #define LZO_CPP_ECONCAT2(a,b) LZO_CPP_CONCAT2(a,b) #define LZO_CPP_ECONCAT3(a,b,c) LZO_CPP_CONCAT3(a,b,c) #define LZO_CPP_ECONCAT4(a,b,c,d) LZO_CPP_CONCAT4(a,b,c,d) #define LZO_CPP_ECONCAT5(a,b,c,d,e) LZO_CPP_CONCAT5(a,b,c,d,e) #endif #define __LZO_MASK_GEN(o,b) (((((o) << ((b)-1)) - (o)) << 1) + (o)) #if 1 && defined(__cplusplus) # if !defined(__STDC_CONSTANT_MACROS) # define __STDC_CONSTANT_MACROS 1 # endif # if !defined(__STDC_LIMIT_MACROS) # define __STDC_LIMIT_MACROS 1 # endif #endif #if defined(__cplusplus) # define LZO_EXTERN_C extern "C" #else # define LZO_EXTERN_C extern #endif #if !defined(__LZO_OS_OVERRIDE) #if (LZO_OS_FREESTANDING) # define LZO_INFO_OS "freestanding" #elif (LZO_OS_EMBEDDED) # define LZO_INFO_OS "embedded" #elif 1 && defined(__IAR_SYSTEMS_ICC__) # define LZO_OS_EMBEDDED 1 # define LZO_INFO_OS "embedded" #elif defined(__CYGWIN__) && defined(__GNUC__) # define LZO_OS_CYGWIN 1 # define LZO_INFO_OS "cygwin" #elif defined(__EMX__) && defined(__GNUC__) # define LZO_OS_EMX 1 # define LZO_INFO_OS "emx" #elif defined(__BEOS__) # define LZO_OS_BEOS 1 # define LZO_INFO_OS "beos" #elif defined(__Lynx__) # define LZO_OS_LYNXOS 1 # define LZO_INFO_OS "lynxos" #elif defined(__OS400__) # define LZO_OS_OS400 1 # define LZO_INFO_OS "os400" #elif defined(__QNX__) # define LZO_OS_QNX 1 # define LZO_INFO_OS "qnx" #elif defined(__BORLANDC__) && defined(__DPMI32__) && (__BORLANDC__ >= 0x0460) # define LZO_OS_DOS32 1 # define LZO_INFO_OS "dos32" #elif defined(__BORLANDC__) && defined(__DPMI16__) # define LZO_OS_DOS16 1 # define LZO_INFO_OS "dos16" #elif defined(__ZTC__) && defined(DOS386) # define LZO_OS_DOS32 1 # define LZO_INFO_OS "dos32" #elif defined(__OS2__) || defined(__OS2V2__) # if (UINT_MAX == LZO_0xffffL) # define LZO_OS_OS216 1 # define LZO_INFO_OS "os216" # elif (UINT_MAX == LZO_0xffffffffL) # define LZO_OS_OS2 1 # define LZO_INFO_OS "os2" # else # error "check your limits.h header" # endif #elif defined(__WIN64__) || defined(_WIN64) || defined(WIN64) # define LZO_OS_WIN64 1 # define LZO_INFO_OS "win64" #elif defined(__WIN32__) || defined(_WIN32) || defined(WIN32) || defined(__WINDOWS_386__) # define LZO_OS_WIN32 1 # define LZO_INFO_OS "win32" #elif defined(__MWERKS__) && defined(__INTEL__) # define LZO_OS_WIN32 1 # define LZO_INFO_OS "win32" #elif defined(__WINDOWS__) || defined(_WINDOWS) || defined(_Windows) # if (UINT_MAX == LZO_0xffffL) # define LZO_OS_WIN16 1 # define LZO_INFO_OS "win16" # elif (UINT_MAX == LZO_0xffffffffL) # define LZO_OS_WIN32 1 # define LZO_INFO_OS "win32" # else # error "check your limits.h header" # endif #elif defined(__DOS__) || defined(__MSDOS__) || defined(_MSDOS) || defined(MSDOS) || (defined(__PACIFIC__) && defined(DOS)) # if (UINT_MAX == LZO_0xffffL) # define LZO_OS_DOS16 1 # define LZO_INFO_OS "dos16" # elif (UINT_MAX == LZO_0xffffffffL) # define LZO_OS_DOS32 1 # define LZO_INFO_OS "dos32" # else # error "check your limits.h header" # endif #elif defined(__WATCOMC__) # if defined(__NT__) && (UINT_MAX == LZO_0xffffL) # define LZO_OS_DOS16 1 # define LZO_INFO_OS "dos16" # elif defined(__NT__) && (__WATCOMC__ < 1100) # define LZO_OS_WIN32 1 # define LZO_INFO_OS "win32" # elif defined(__linux__) || defined(__LINUX__) # define LZO_OS_POSIX 1 # define LZO_INFO_OS "posix" # else # error "please specify a target using the -bt compiler option" # endif #elif defined(__palmos__) # define LZO_OS_PALMOS 1 # define LZO_INFO_OS "palmos" #elif defined(__TOS__) || defined(__atarist__) # define LZO_OS_TOS 1 # define LZO_INFO_OS "tos" #elif defined(macintosh) && !defined(__ppc__) # define LZO_OS_MACCLASSIC 1 # define LZO_INFO_OS "macclassic" #elif defined(__VMS) # define LZO_OS_VMS 1 # define LZO_INFO_OS "vms" #elif ((defined(__mips__) && defined(__R5900__)) || defined(__MIPS_PSX2__)) # define LZO_OS_CONSOLE 1 # define LZO_OS_CONSOLE_PS2 1 # define LZO_INFO_OS "console" # define LZO_INFO_OS_CONSOLE "ps2" #elif (defined(__mips__) && defined(__psp__)) # define LZO_OS_CONSOLE 1 # define LZO_OS_CONSOLE_PSP 1 # define LZO_INFO_OS "console" # define LZO_INFO_OS_CONSOLE "psp" #else # define LZO_OS_POSIX 1 # define LZO_INFO_OS "posix" #endif #if (LZO_OS_POSIX) # if defined(_AIX) || defined(__AIX__) || defined(__aix__) # define LZO_OS_POSIX_AIX 1 # define LZO_INFO_OS_POSIX "aix" # elif defined(__FreeBSD__) # define LZO_OS_POSIX_FREEBSD 1 # define LZO_INFO_OS_POSIX "freebsd" # elif defined(__hpux__) || defined(__hpux) # define LZO_OS_POSIX_HPUX 1 # define LZO_INFO_OS_POSIX "hpux" # elif defined(__INTERIX) # define LZO_OS_POSIX_INTERIX 1 # define LZO_INFO_OS_POSIX "interix" # elif defined(__IRIX__) || defined(__irix__) # define LZO_OS_POSIX_IRIX 1 # define LZO_INFO_OS_POSIX "irix" # elif defined(__linux__) || defined(__linux) || defined(__LINUX__) # define LZO_OS_POSIX_LINUX 1 # define LZO_INFO_OS_POSIX "linux" # elif defined(__APPLE__) || defined(__MACOS__) # define LZO_OS_POSIX_MACOSX 1 # define LZO_INFO_OS_POSIX "macosx" # elif defined(__minix__) || defined(__minix) # define LZO_OS_POSIX_MINIX 1 # define LZO_INFO_OS_POSIX "minix" # elif defined(__NetBSD__) # define LZO_OS_POSIX_NETBSD 1 # define LZO_INFO_OS_POSIX "netbsd" # elif defined(__OpenBSD__) # define LZO_OS_POSIX_OPENBSD 1 # define LZO_INFO_OS_POSIX "openbsd" # elif defined(__osf__) # define LZO_OS_POSIX_OSF 1 # define LZO_INFO_OS_POSIX "osf" # elif defined(__solaris__) || defined(__sun) # if defined(__SVR4) || defined(__svr4__) # define LZO_OS_POSIX_SOLARIS 1 # define LZO_INFO_OS_POSIX "solaris" # else # define LZO_OS_POSIX_SUNOS 1 # define LZO_INFO_OS_POSIX "sunos" # endif # elif defined(__ultrix__) || defined(__ultrix) # define LZO_OS_POSIX_ULTRIX 1 # define LZO_INFO_OS_POSIX "ultrix" # elif defined(_UNICOS) # define LZO_OS_POSIX_UNICOS 1 # define LZO_INFO_OS_POSIX "unicos" # else # define LZO_OS_POSIX_UNKNOWN 1 # define LZO_INFO_OS_POSIX "unknown" # endif #endif #endif #if (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16) # if (UINT_MAX != LZO_0xffffL) # error "this should not happen" # endif # if (ULONG_MAX != LZO_0xffffffffL) # error "this should not happen" # endif #endif #if (LZO_OS_DOS32 || LZO_OS_OS2 || LZO_OS_WIN32 || LZO_OS_WIN64) # if (UINT_MAX != LZO_0xffffffffL) # error "this should not happen" # endif # if (ULONG_MAX != LZO_0xffffffffL) # error "this should not happen" # endif #endif #if defined(CIL) && defined(_GNUCC) && defined(__GNUC__) # define LZO_CC_CILLY 1 # define LZO_INFO_CC "Cilly" # if defined(__CILLY__) # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__CILLY__) # else # define LZO_INFO_CCVER "unknown" # endif #elif 0 && defined(SDCC) && defined(__VERSION__) && !defined(__GNUC__) # define LZO_CC_SDCC 1 # define LZO_INFO_CC "sdcc" # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(SDCC) #elif defined(__PATHSCALE__) && defined(__PATHCC_PATCHLEVEL__) # define LZO_CC_PATHSCALE (__PATHCC__ * 0x10000L + __PATHCC_MINOR__ * 0x100 + __PATHCC_PATCHLEVEL__) # define LZO_INFO_CC "Pathscale C" # define LZO_INFO_CCVER __PATHSCALE__ #elif defined(__INTEL_COMPILER) # define LZO_CC_INTELC 1 # define LZO_INFO_CC "Intel C" # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__INTEL_COMPILER) # if defined(_WIN32) || defined(_WIN64) # define LZO_CC_SYNTAX_MSC 1 # else # define LZO_CC_SYNTAX_GNUC 1 # endif #elif defined(__POCC__) && defined(_WIN32) # define LZO_CC_PELLESC 1 # define LZO_INFO_CC "Pelles C" # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__POCC__) #elif defined(__clang__) && defined(__llvm__) && defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__) # if defined(__GNUC_PATCHLEVEL__) # define LZO_CC_CLANG_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__) # else # define LZO_CC_CLANG_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100) # endif # if defined(__clang_major__) && defined(__clang_minor__) && defined(__clang_patchlevel__) # define LZO_CC_CLANG_CLANG (__clang_major__ * 0x10000L + __clang_minor__ * 0x100 + __clang_patchlevel__) # else # define LZO_CC_CLANG_CLANG 0x010000L # endif # define LZO_CC_CLANG LZO_CC_CLANG_GNUC # define LZO_INFO_CC "clang" # define LZO_INFO_CCVER __VERSION__ #elif defined(__llvm__) && defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__) # if defined(__GNUC_PATCHLEVEL__) # define LZO_CC_LLVM_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__) # else # define LZO_CC_LLVM_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100) # endif # define LZO_CC_LLVM LZO_CC_LLVM_GNUC # define LZO_INFO_CC "llvm-gcc" # define LZO_INFO_CCVER __VERSION__ #elif defined(__GNUC__) && defined(__VERSION__) # if defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) # define LZO_CC_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__) # elif defined(__GNUC_MINOR__) # define LZO_CC_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100) # else # define LZO_CC_GNUC (__GNUC__ * 0x10000L) # endif # define LZO_INFO_CC "gcc" # define LZO_INFO_CCVER __VERSION__ #elif defined(__ACK__) && defined(_ACK) # define LZO_CC_ACK 1 # define LZO_INFO_CC "Amsterdam Compiler Kit C" # define LZO_INFO_CCVER "unknown" #elif defined(__AZTEC_C__) # define LZO_CC_AZTECC 1 # define LZO_INFO_CC "Aztec C" # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__AZTEC_C__) #elif defined(__CODEGEARC__) # define LZO_CC_CODEGEARC 1 # define LZO_INFO_CC "CodeGear C" # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__CODEGEARC__) #elif defined(__BORLANDC__) # define LZO_CC_BORLANDC 1 # define LZO_INFO_CC "Borland C" # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__BORLANDC__) #elif defined(_CRAYC) && defined(_RELEASE) # define LZO_CC_CRAYC 1 # define LZO_INFO_CC "Cray C" # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(_RELEASE) #elif defined(__DMC__) && defined(__SC__) # define LZO_CC_DMC 1 # define LZO_INFO_CC "Digital Mars C" # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__DMC__) #elif defined(__DECC) # define LZO_CC_DECC 1 # define LZO_INFO_CC "DEC C" # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__DECC) #elif defined(__HIGHC__) # define LZO_CC_HIGHC 1 # define LZO_INFO_CC "MetaWare High C" # define LZO_INFO_CCVER "unknown" #elif defined(__IAR_SYSTEMS_ICC__) # define LZO_CC_IARC 1 # define LZO_INFO_CC "IAR C" # if defined(__VER__) # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__VER__) # else # define LZO_INFO_CCVER "unknown" # endif #elif defined(__IBMC__) # define LZO_CC_IBMC 1 # define LZO_INFO_CC "IBM C" # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__IBMC__) #elif defined(__KEIL__) && defined(__C166__) # define LZO_CC_KEILC 1 # define LZO_INFO_CC "Keil C" # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__C166__) #elif defined(__LCC__) && defined(_WIN32) && defined(__LCCOPTIMLEVEL) # define LZO_CC_LCCWIN32 1 # define LZO_INFO_CC "lcc-win32" # define LZO_INFO_CCVER "unknown" #elif defined(__LCC__) # define LZO_CC_LCC 1 # define LZO_INFO_CC "lcc" # if defined(__LCC_VERSION__) # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__LCC_VERSION__) # else # define LZO_INFO_CCVER "unknown" # endif #elif defined(_MSC_VER) # define LZO_CC_MSC 1 # define LZO_INFO_CC "Microsoft C" # if defined(_MSC_FULL_VER) # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(_MSC_VER) "." LZO_PP_MACRO_EXPAND(_MSC_FULL_VER) # else # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(_MSC_VER) # endif #elif defined(__MWERKS__) # define LZO_CC_MWERKS 1 # define LZO_INFO_CC "Metrowerks C" # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__MWERKS__) #elif (defined(__NDPC__) || defined(__NDPX__)) && defined(__i386) # define LZO_CC_NDPC 1 # define LZO_INFO_CC "Microway NDP C" # define LZO_INFO_CCVER "unknown" #elif defined(__PACIFIC__) # define LZO_CC_PACIFICC 1 # define LZO_INFO_CC "Pacific C" # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__PACIFIC__) #elif defined(__PGI) && (defined(__linux__) || defined(__WIN32__)) # define LZO_CC_PGI 1 # define LZO_INFO_CC "Portland Group PGI C" # define LZO_INFO_CCVER "unknown" #elif defined(__PUREC__) && defined(__TOS__) # define LZO_CC_PUREC 1 # define LZO_INFO_CC "Pure C" # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__PUREC__) #elif defined(__SC__) && defined(__ZTC__) # define LZO_CC_SYMANTECC 1 # define LZO_INFO_CC "Symantec C" # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__SC__) #elif defined(__SUNPRO_C) # define LZO_INFO_CC "SunPro C" # if ((__SUNPRO_C)+0 > 0) # define LZO_CC_SUNPROC __SUNPRO_C # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__SUNPRO_C) # else # define LZO_CC_SUNPROC 1 # define LZO_INFO_CCVER "unknown" # endif #elif defined(__SUNPRO_CC) # define LZO_INFO_CC "SunPro C" # if ((__SUNPRO_CC)+0 > 0) # define LZO_CC_SUNPROC __SUNPRO_CC # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__SUNPRO_CC) # else # define LZO_CC_SUNPROC 1 # define LZO_INFO_CCVER "unknown" # endif #elif defined(__TINYC__) # define LZO_CC_TINYC 1 # define LZO_INFO_CC "Tiny C" # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__TINYC__) #elif defined(__TSC__) # define LZO_CC_TOPSPEEDC 1 # define LZO_INFO_CC "TopSpeed C" # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__TSC__) #elif defined(__WATCOMC__) # define LZO_CC_WATCOMC 1 # define LZO_INFO_CC "Watcom C" # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__WATCOMC__) #elif defined(__TURBOC__) # define LZO_CC_TURBOC 1 # define LZO_INFO_CC "Turbo C" # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__TURBOC__) #elif defined(__ZTC__) # define LZO_CC_ZORTECHC 1 # define LZO_INFO_CC "Zortech C" # if (__ZTC__ == 0x310) # define LZO_INFO_CCVER "0x310" # else # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__ZTC__) # endif #else # define LZO_CC_UNKNOWN 1 # define LZO_INFO_CC "unknown" # define LZO_INFO_CCVER "unknown" #endif #if 0 && (LZO_CC_MSC && (_MSC_VER >= 1200)) && !defined(_MSC_FULL_VER) # error "LZO_CC_MSC: _MSC_FULL_VER is not defined" #endif #if !defined(__LZO_ARCH_OVERRIDE) && !(LZO_ARCH_GENERIC) && defined(_CRAY) # if (UINT_MAX > LZO_0xffffffffL) && defined(_CRAY) # if defined(_CRAYMPP) || defined(_CRAYT3D) || defined(_CRAYT3E) # define LZO_ARCH_CRAY_MPP 1 # elif defined(_CRAY1) # define LZO_ARCH_CRAY_PVP 1 # endif # endif #endif #if !defined(__LZO_ARCH_OVERRIDE) #if (LZO_ARCH_GENERIC) # define LZO_INFO_ARCH "generic" #elif (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16) # define LZO_ARCH_I086 1 # define LZO_ARCH_IA16 1 # define LZO_INFO_ARCH "i086" #elif defined(__alpha__) || defined(__alpha) || defined(_M_ALPHA) # define LZO_ARCH_ALPHA 1 # define LZO_INFO_ARCH "alpha" #elif (LZO_ARCH_CRAY_MPP) && (defined(_CRAYT3D) || defined(_CRAYT3E)) # define LZO_ARCH_ALPHA 1 # define LZO_INFO_ARCH "alpha" #elif defined(__amd64__) || defined(__x86_64__) || defined(_M_AMD64) # define LZO_ARCH_AMD64 1 # define LZO_INFO_ARCH "amd64" #elif defined(__thumb__) || (defined(_M_ARM) && defined(_M_THUMB)) # define LZO_ARCH_ARM 1 # define LZO_ARCH_ARM_THUMB 1 # define LZO_INFO_ARCH "arm_thumb" #elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCARM__) # define LZO_ARCH_ARM 1 # if defined(__CPU_MODE__) && ((__CPU_MODE__)+0 == 1) # define LZO_ARCH_ARM_THUMB 1 # define LZO_INFO_ARCH "arm_thumb" # elif defined(__CPU_MODE__) && ((__CPU_MODE__)+0 == 2) # define LZO_INFO_ARCH "arm" # else # define LZO_INFO_ARCH "arm" # endif #elif defined(__arm__) || defined(_M_ARM) # define LZO_ARCH_ARM 1 # define LZO_INFO_ARCH "arm" #elif (UINT_MAX <= LZO_0xffffL) && defined(__AVR__) # define LZO_ARCH_AVR 1 # define LZO_INFO_ARCH "avr" #elif defined(__avr32__) || defined(__AVR32__) # define LZO_ARCH_AVR32 1 # define LZO_INFO_ARCH "avr32" #elif defined(__bfin__) # define LZO_ARCH_BLACKFIN 1 # define LZO_INFO_ARCH "blackfin" #elif (UINT_MAX == LZO_0xffffL) && defined(__C166__) # define LZO_ARCH_C166 1 # define LZO_INFO_ARCH "c166" #elif defined(__cris__) # define LZO_ARCH_CRIS 1 # define LZO_INFO_ARCH "cris" #elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCEZ80__) # define LZO_ARCH_EZ80 1 # define LZO_INFO_ARCH "ez80" #elif defined(__H8300__) || defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__) # define LZO_ARCH_H8300 1 # define LZO_INFO_ARCH "h8300" #elif defined(__hppa__) || defined(__hppa) # define LZO_ARCH_HPPA 1 # define LZO_INFO_ARCH "hppa" #elif defined(__386__) || defined(__i386__) || defined(__i386) || defined(_M_IX86) || defined(_M_I386) # define LZO_ARCH_I386 1 # define LZO_ARCH_IA32 1 # define LZO_INFO_ARCH "i386" #elif (LZO_CC_ZORTECHC && defined(__I86__)) # define LZO_ARCH_I386 1 # define LZO_ARCH_IA32 1 # define LZO_INFO_ARCH "i386" #elif (LZO_OS_DOS32 && LZO_CC_HIGHC) && defined(_I386) # define LZO_ARCH_I386 1 # define LZO_ARCH_IA32 1 # define LZO_INFO_ARCH "i386" #elif defined(__ia64__) || defined(__ia64) || defined(_M_IA64) # define LZO_ARCH_IA64 1 # define LZO_INFO_ARCH "ia64" #elif (UINT_MAX == LZO_0xffffL) && defined(__m32c__) # define LZO_ARCH_M16C 1 # define LZO_INFO_ARCH "m16c" #elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCM16C__) # define LZO_ARCH_M16C 1 # define LZO_INFO_ARCH "m16c" #elif defined(__m32r__) # define LZO_ARCH_M32R 1 # define LZO_INFO_ARCH "m32r" #elif (LZO_OS_TOS) || defined(__m68k__) || defined(__m68000__) || defined(__mc68000__) || defined(__mc68020__) || defined(_M_M68K) # define LZO_ARCH_M68K 1 # define LZO_INFO_ARCH "m68k" #elif (UINT_MAX == LZO_0xffffL) && defined(__C251__) # define LZO_ARCH_MCS251 1 # define LZO_INFO_ARCH "mcs251" #elif (UINT_MAX == LZO_0xffffL) && defined(__C51__) # define LZO_ARCH_MCS51 1 # define LZO_INFO_ARCH "mcs51" #elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICC8051__) # define LZO_ARCH_MCS51 1 # define LZO_INFO_ARCH "mcs51" #elif defined(__mips__) || defined(__mips) || defined(_MIPS_ARCH) || defined(_M_MRX000) # define LZO_ARCH_MIPS 1 # define LZO_INFO_ARCH "mips" #elif (UINT_MAX == LZO_0xffffL) && defined(__MSP430__) # define LZO_ARCH_MSP430 1 # define LZO_INFO_ARCH "msp430" #elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICC430__) # define LZO_ARCH_MSP430 1 # define LZO_INFO_ARCH "msp430" #elif defined(__powerpc__) || defined(__powerpc) || defined(__ppc__) || defined(__PPC__) || defined(_M_PPC) || defined(_ARCH_PPC) || defined(_ARCH_PWR) # define LZO_ARCH_POWERPC 1 # define LZO_INFO_ARCH "powerpc" #elif defined(__s390__) || defined(__s390) || defined(__s390x__) || defined(__s390x) # define LZO_ARCH_S390 1 # define LZO_INFO_ARCH "s390" #elif defined(__sh__) || defined(_M_SH) # define LZO_ARCH_SH 1 # define LZO_INFO_ARCH "sh" #elif defined(__sparc__) || defined(__sparc) || defined(__sparcv8) # define LZO_ARCH_SPARC 1 # define LZO_INFO_ARCH "sparc" #elif defined(__SPU__) # define LZO_ARCH_SPU 1 # define LZO_INFO_ARCH "spu" #elif (UINT_MAX == LZO_0xffffL) && defined(__z80) # define LZO_ARCH_Z80 1 # define LZO_INFO_ARCH "z80" #elif (LZO_ARCH_CRAY_PVP) # if defined(_CRAYSV1) # define LZO_ARCH_CRAY_SV1 1 # define LZO_INFO_ARCH "cray_sv1" # elif (_ADDR64) # define LZO_ARCH_CRAY_T90 1 # define LZO_INFO_ARCH "cray_t90" # elif (_ADDR32) # define LZO_ARCH_CRAY_YMP 1 # define LZO_INFO_ARCH "cray_ymp" # else # define LZO_ARCH_CRAY_XMP 1 # define LZO_INFO_ARCH "cray_xmp" # endif #else # define LZO_ARCH_UNKNOWN 1 # define LZO_INFO_ARCH "unknown" #endif #endif #if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_DOS32 || LZO_OS_OS2) # error "FIXME - missing define for CPU architecture" #endif #if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_WIN32) # error "FIXME - missing WIN32 define for CPU architecture" #endif #if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_WIN64) # error "FIXME - missing WIN64 define for CPU architecture" #endif #if (LZO_OS_OS216 || LZO_OS_WIN16) # define LZO_ARCH_I086PM 1 # define LZO_ARCH_IA16PM 1 #elif 1 && (LZO_OS_DOS16 && defined(BLX286)) # define LZO_ARCH_I086PM 1 # define LZO_ARCH_IA16PM 1 #elif 1 && (LZO_OS_DOS16 && defined(DOSX286)) # define LZO_ARCH_I086PM 1 # define LZO_ARCH_IA16PM 1 #elif 1 && (LZO_OS_DOS16 && LZO_CC_BORLANDC && defined(__DPMI16__)) # define LZO_ARCH_I086PM 1 # define LZO_ARCH_IA16PM 1 #endif #if (LZO_ARCH_ARM_THUMB) && !(LZO_ARCH_ARM) # error "this should not happen" #endif #if (LZO_ARCH_I086PM) && !(LZO_ARCH_I086) # error "this should not happen" #endif #if (LZO_ARCH_I086) # if (UINT_MAX != LZO_0xffffL) # error "this should not happen" # endif # if (ULONG_MAX != LZO_0xffffffffL) # error "this should not happen" # endif #endif #if (LZO_ARCH_I386) # if (UINT_MAX != LZO_0xffffL) && defined(__i386_int16__) # error "this should not happen" # endif # if (UINT_MAX != LZO_0xffffffffL) && !defined(__i386_int16__) # error "this should not happen" # endif # if (ULONG_MAX != LZO_0xffffffffL) # error "this should not happen" # endif #endif #if !defined(__LZO_MM_OVERRIDE) #if (LZO_ARCH_I086) #if (UINT_MAX != LZO_0xffffL) # error "this should not happen" #endif #if defined(__TINY__) || defined(M_I86TM) || defined(_M_I86TM) # define LZO_MM_TINY 1 #elif defined(__HUGE__) || defined(_HUGE_) || defined(M_I86HM) || defined(_M_I86HM) # define LZO_MM_HUGE 1 #elif defined(__SMALL__) || defined(M_I86SM) || defined(_M_I86SM) || defined(SMALL_MODEL) # define LZO_MM_SMALL 1 #elif defined(__MEDIUM__) || defined(M_I86MM) || defined(_M_I86MM) # define LZO_MM_MEDIUM 1 #elif defined(__COMPACT__) || defined(M_I86CM) || defined(_M_I86CM) # define LZO_MM_COMPACT 1 #elif defined(__LARGE__) || defined(M_I86LM) || defined(_M_I86LM) || defined(LARGE_MODEL) # define LZO_MM_LARGE 1 #elif (LZO_CC_AZTECC) # if defined(_LARGE_CODE) && defined(_LARGE_DATA) # define LZO_MM_LARGE 1 # elif defined(_LARGE_CODE) # define LZO_MM_MEDIUM 1 # elif defined(_LARGE_DATA) # define LZO_MM_COMPACT 1 # else # define LZO_MM_SMALL 1 # endif #elif (LZO_CC_ZORTECHC && defined(__VCM__)) # define LZO_MM_LARGE 1 #else # error "unknown memory model" #endif #if (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16) #define LZO_HAVE_MM_HUGE_PTR 1 #define LZO_HAVE_MM_HUGE_ARRAY 1 #if (LZO_MM_TINY) # undef LZO_HAVE_MM_HUGE_ARRAY #endif #if (LZO_CC_AZTECC || LZO_CC_PACIFICC || LZO_CC_ZORTECHC) # undef LZO_HAVE_MM_HUGE_PTR # undef LZO_HAVE_MM_HUGE_ARRAY #elif (LZO_CC_DMC || LZO_CC_SYMANTECC) # undef LZO_HAVE_MM_HUGE_ARRAY #elif (LZO_CC_MSC && defined(_QC)) # undef LZO_HAVE_MM_HUGE_ARRAY # if (_MSC_VER < 600) # undef LZO_HAVE_MM_HUGE_PTR # endif #elif (LZO_CC_TURBOC && (__TURBOC__ < 0x0295)) # undef LZO_HAVE_MM_HUGE_ARRAY #endif #if (LZO_ARCH_I086PM) && !(LZO_HAVE_MM_HUGE_PTR) # if (LZO_OS_DOS16) # error "this should not happen" # elif (LZO_CC_ZORTECHC) # else # error "this should not happen" # endif #endif #ifdef __cplusplus extern "C" { #endif #if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0200)) extern void __near __cdecl _AHSHIFT(void); # define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT) #elif (LZO_CC_DMC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC) extern void __near __cdecl _AHSHIFT(void); # define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT) #elif (LZO_CC_MSC || LZO_CC_TOPSPEEDC) extern void __near __cdecl _AHSHIFT(void); # define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT) #elif (LZO_CC_TURBOC && (__TURBOC__ >= 0x0295)) extern void __near __cdecl _AHSHIFT(void); # define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT) #elif ((LZO_CC_AZTECC || LZO_CC_PACIFICC || LZO_CC_TURBOC) && LZO_OS_DOS16) # define LZO_MM_AHSHIFT 12 #elif (LZO_CC_WATCOMC) extern unsigned char _HShift; # define LZO_MM_AHSHIFT ((unsigned) _HShift) #else # error "FIXME - implement LZO_MM_AHSHIFT" #endif #ifdef __cplusplus } #endif #endif #elif (LZO_ARCH_C166) #if !defined(__MODEL__) # error "FIXME - C166 __MODEL__" #elif ((__MODEL__) == 0) # define LZO_MM_SMALL 1 #elif ((__MODEL__) == 1) # define LZO_MM_SMALL 1 #elif ((__MODEL__) == 2) # define LZO_MM_LARGE 1 #elif ((__MODEL__) == 3) # define LZO_MM_TINY 1 #elif ((__MODEL__) == 4) # define LZO_MM_XTINY 1 #elif ((__MODEL__) == 5) # define LZO_MM_XSMALL 1 #else # error "FIXME - C166 __MODEL__" #endif #elif (LZO_ARCH_MCS251) #if !defined(__MODEL__) # error "FIXME - MCS251 __MODEL__" #elif ((__MODEL__) == 0) # define LZO_MM_SMALL 1 #elif ((__MODEL__) == 2) # define LZO_MM_LARGE 1 #elif ((__MODEL__) == 3) # define LZO_MM_TINY 1 #elif ((__MODEL__) == 4) # define LZO_MM_XTINY 1 #elif ((__MODEL__) == 5) # define LZO_MM_XSMALL 1 #else # error "FIXME - MCS251 __MODEL__" #endif #elif (LZO_ARCH_MCS51) #if !defined(__MODEL__) # error "FIXME - MCS51 __MODEL__" #elif ((__MODEL__) == 1) # define LZO_MM_SMALL 1 #elif ((__MODEL__) == 2) # define LZO_MM_LARGE 1 #elif ((__MODEL__) == 3) # define LZO_MM_TINY 1 #elif ((__MODEL__) == 4) # define LZO_MM_XTINY 1 #elif ((__MODEL__) == 5) # define LZO_MM_XSMALL 1 #else # error "FIXME - MCS51 __MODEL__" #endif #elif (LZO_ARCH_CRAY_PVP) # define LZO_MM_PVP 1 #else # define LZO_MM_FLAT 1 #endif #if (LZO_MM_COMPACT) # define LZO_INFO_MM "compact" #elif (LZO_MM_FLAT) # define LZO_INFO_MM "flat" #elif (LZO_MM_HUGE) # define LZO_INFO_MM "huge" #elif (LZO_MM_LARGE) # define LZO_INFO_MM "large" #elif (LZO_MM_MEDIUM) # define LZO_INFO_MM "medium" #elif (LZO_MM_PVP) # define LZO_INFO_MM "pvp" #elif (LZO_MM_SMALL) # define LZO_INFO_MM "small" #elif (LZO_MM_TINY) # define LZO_INFO_MM "tiny" #else # error "unknown memory model" #endif #endif #if defined(SIZEOF_SHORT) # define LZO_SIZEOF_SHORT (SIZEOF_SHORT) #endif #if defined(SIZEOF_INT) # define LZO_SIZEOF_INT (SIZEOF_INT) #endif #if defined(SIZEOF_LONG) # define LZO_SIZEOF_LONG (SIZEOF_LONG) #endif #if defined(SIZEOF_LONG_LONG) # define LZO_SIZEOF_LONG_LONG (SIZEOF_LONG_LONG) #endif #if defined(SIZEOF___INT16) # define LZO_SIZEOF___INT16 (SIZEOF___INT16) #endif #if defined(SIZEOF___INT32) # define LZO_SIZEOF___INT32 (SIZEOF___INT32) #endif #if defined(SIZEOF___INT64) # define LZO_SIZEOF___INT64 (SIZEOF___INT64) #endif #if defined(SIZEOF_VOID_P) # define LZO_SIZEOF_VOID_P (SIZEOF_VOID_P) #endif #if defined(SIZEOF_SIZE_T) # define LZO_SIZEOF_SIZE_T (SIZEOF_SIZE_T) #endif #if defined(SIZEOF_PTRDIFF_T) # define LZO_SIZEOF_PTRDIFF_T (SIZEOF_PTRDIFF_T) #endif #define __LZO_LSR(x,b) (((x)+0ul) >> (b)) #if !defined(LZO_SIZEOF_SHORT) # if (LZO_ARCH_CRAY_PVP) # define LZO_SIZEOF_SHORT 8 # elif (USHRT_MAX == LZO_0xffffL) # define LZO_SIZEOF_SHORT 2 # elif (__LZO_LSR(USHRT_MAX,7) == 1) # define LZO_SIZEOF_SHORT 1 # elif (__LZO_LSR(USHRT_MAX,15) == 1) # define LZO_SIZEOF_SHORT 2 # elif (__LZO_LSR(USHRT_MAX,31) == 1) # define LZO_SIZEOF_SHORT 4 # elif (__LZO_LSR(USHRT_MAX,63) == 1) # define LZO_SIZEOF_SHORT 8 # elif (__LZO_LSR(USHRT_MAX,127) == 1) # define LZO_SIZEOF_SHORT 16 # else # error "LZO_SIZEOF_SHORT" # endif #endif #if !defined(LZO_SIZEOF_INT) # if (LZO_ARCH_CRAY_PVP) # define LZO_SIZEOF_INT 8 # elif (UINT_MAX == LZO_0xffffL) # define LZO_SIZEOF_INT 2 # elif (UINT_MAX == LZO_0xffffffffL) # define LZO_SIZEOF_INT 4 # elif (__LZO_LSR(UINT_MAX,7) == 1) # define LZO_SIZEOF_INT 1 # elif (__LZO_LSR(UINT_MAX,15) == 1) # define LZO_SIZEOF_INT 2 # elif (__LZO_LSR(UINT_MAX,31) == 1) # define LZO_SIZEOF_INT 4 # elif (__LZO_LSR(UINT_MAX,63) == 1) # define LZO_SIZEOF_INT 8 # elif (__LZO_LSR(UINT_MAX,127) == 1) # define LZO_SIZEOF_INT 16 # else # error "LZO_SIZEOF_INT" # endif #endif #if !defined(LZO_SIZEOF_LONG) # if (ULONG_MAX == LZO_0xffffffffL) # define LZO_SIZEOF_LONG 4 # elif (__LZO_LSR(ULONG_MAX,7) == 1) # define LZO_SIZEOF_LONG 1 # elif (__LZO_LSR(ULONG_MAX,15) == 1) # define LZO_SIZEOF_LONG 2 # elif (__LZO_LSR(ULONG_MAX,31) == 1) # define LZO_SIZEOF_LONG 4 # elif (__LZO_LSR(ULONG_MAX,63) == 1) # define LZO_SIZEOF_LONG 8 # elif (__LZO_LSR(ULONG_MAX,127) == 1) # define LZO_SIZEOF_LONG 16 # else # error "LZO_SIZEOF_LONG" # endif #endif #if !defined(LZO_SIZEOF_LONG_LONG) && !defined(LZO_SIZEOF___INT64) #if (LZO_SIZEOF_LONG > 0 && LZO_SIZEOF_LONG < 8) # if defined(__LONG_MAX__) && defined(__LONG_LONG_MAX__) # if (LZO_CC_GNUC >= 0x030300ul) # if ((__LONG_MAX__)+0 == (__LONG_LONG_MAX__)+0) # define LZO_SIZEOF_LONG_LONG LZO_SIZEOF_LONG # elif (__LZO_LSR(__LONG_LONG_MAX__,30) == 1) # define LZO_SIZEOF_LONG_LONG 4 # endif # endif # endif #endif #endif #if !defined(LZO_SIZEOF_LONG_LONG) && !defined(LZO_SIZEOF___INT64) #if (LZO_SIZEOF_LONG > 0 && LZO_SIZEOF_LONG < 8) #if (LZO_ARCH_I086 && LZO_CC_DMC) #elif (LZO_CC_CILLY) && defined(__GNUC__) # define LZO_SIZEOF_LONG_LONG 8 #elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE) # define LZO_SIZEOF_LONG_LONG 8 #elif ((LZO_OS_WIN32 || LZO_OS_WIN64 || defined(_WIN32)) && LZO_CC_MSC && (_MSC_VER >= 1400)) # define LZO_SIZEOF_LONG_LONG 8 #elif (LZO_OS_WIN64 || defined(_WIN64)) # define LZO_SIZEOF___INT64 8 #elif (LZO_ARCH_I386 && (LZO_CC_DMC)) # define LZO_SIZEOF_LONG_LONG 8 #elif (LZO_ARCH_I386 && (LZO_CC_SYMANTECC && (__SC__ >= 0x700))) # define LZO_SIZEOF_LONG_LONG 8 #elif (LZO_ARCH_I386 && (LZO_CC_INTELC && defined(__linux__))) # define LZO_SIZEOF_LONG_LONG 8 #elif (LZO_ARCH_I386 && (LZO_CC_MWERKS || LZO_CC_PELLESC || LZO_CC_PGI || LZO_CC_SUNPROC)) # define LZO_SIZEOF_LONG_LONG 8 #elif (LZO_ARCH_I386 && (LZO_CC_INTELC || LZO_CC_MSC)) # define LZO_SIZEOF___INT64 8 #elif ((LZO_OS_WIN32 || defined(_WIN32)) && (LZO_CC_MSC)) # define LZO_SIZEOF___INT64 8 #elif (LZO_ARCH_I386 && (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0520))) # define LZO_SIZEOF___INT64 8 #elif (LZO_ARCH_I386 && (LZO_CC_WATCOMC && (__WATCOMC__ >= 1100))) # define LZO_SIZEOF___INT64 8 #elif (LZO_CC_WATCOMC && defined(_INTEGRAL_MAX_BITS) && (_INTEGRAL_MAX_BITS == 64)) # define LZO_SIZEOF___INT64 8 #elif (LZO_OS_OS400 || defined(__OS400__)) && defined(__LLP64_IFC__) # define LZO_SIZEOF_LONG_LONG 8 #elif (defined(__vms) || defined(__VMS)) && (__INITIAL_POINTER_SIZE+0 == 64) # define LZO_SIZEOF_LONG_LONG 8 #elif (LZO_CC_SDCC) && (LZO_SIZEOF_INT == 2) #elif 1 && defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) # define LZO_SIZEOF_LONG_LONG 8 #endif #endif #endif #if defined(__cplusplus) && (LZO_CC_GNUC) # if (LZO_CC_GNUC < 0x020800ul) # undef LZO_SIZEOF_LONG_LONG # endif #endif #if (LZO_CFG_NO_LONG_LONG) || defined(__NO_LONG_LONG) # undef LZO_SIZEOF_LONG_LONG #endif #if !defined(LZO_SIZEOF_VOID_P) #if (LZO_ARCH_I086) # define __LZO_WORDSIZE 2 # if (LZO_MM_TINY || LZO_MM_SMALL || LZO_MM_MEDIUM) # define LZO_SIZEOF_VOID_P 2 # elif (LZO_MM_COMPACT || LZO_MM_LARGE || LZO_MM_HUGE) # define LZO_SIZEOF_VOID_P 4 # else # error "LZO_MM" # endif #elif (LZO_ARCH_AVR || LZO_ARCH_Z80) # define __LZO_WORDSIZE 1 # define LZO_SIZEOF_VOID_P 2 #elif (LZO_ARCH_C166 || LZO_ARCH_MCS51 || LZO_ARCH_MCS251 || LZO_ARCH_MSP430) # define LZO_SIZEOF_VOID_P 2 #elif (LZO_ARCH_H8300) # if defined(__NORMAL_MODE__) # define __LZO_WORDSIZE 4 # define LZO_SIZEOF_VOID_P 2 # elif defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__) # define __LZO_WORDSIZE 4 # define LZO_SIZEOF_VOID_P 4 # else # define __LZO_WORDSIZE 2 # define LZO_SIZEOF_VOID_P 2 # endif # if (LZO_CC_GNUC && (LZO_CC_GNUC < 0x040000ul)) && (LZO_SIZEOF_INT == 4) # define LZO_SIZEOF_SIZE_T LZO_SIZEOF_INT # define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_INT # endif #elif (LZO_ARCH_M16C) # define __LZO_WORDSIZE 2 # if defined(__m32c_cpu__) || defined(__m32cm_cpu__) # define LZO_SIZEOF_VOID_P 4 # else # define LZO_SIZEOF_VOID_P 2 # endif #elif (LZO_SIZEOF_LONG == 8) && ((defined(__mips__) && defined(__R5900__)) || defined(__MIPS_PSX2__)) # define __LZO_WORDSIZE 8 # define LZO_SIZEOF_VOID_P 4 #elif defined(__LLP64__) || defined(__LLP64) || defined(_LLP64) || defined(_WIN64) # define __LZO_WORDSIZE 8 # define LZO_SIZEOF_VOID_P 8 #elif (LZO_OS_OS400 || defined(__OS400__)) && defined(__LLP64_IFC__) # define LZO_SIZEOF_VOID_P LZO_SIZEOF_LONG # define LZO_SIZEOF_SIZE_T LZO_SIZEOF_LONG # define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_LONG #elif (LZO_OS_OS400 || defined(__OS400__)) # define __LZO_WORDSIZE LZO_SIZEOF_LONG # define LZO_SIZEOF_VOID_P 16 # define LZO_SIZEOF_SIZE_T LZO_SIZEOF_LONG # define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_LONG #elif (defined(__vms) || defined(__VMS)) && (__INITIAL_POINTER_SIZE+0 == 64) # define LZO_SIZEOF_VOID_P 8 # define LZO_SIZEOF_SIZE_T LZO_SIZEOF_LONG # define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_LONG #elif (LZO_ARCH_SPU) # if 0 # define __LZO_WORDSIZE 16 # endif # define LZO_SIZEOF_VOID_P 4 #else # define LZO_SIZEOF_VOID_P LZO_SIZEOF_LONG #endif #endif #if !defined(LZO_WORDSIZE) # if defined(__LZO_WORDSIZE) # define LZO_WORDSIZE __LZO_WORDSIZE # else # define LZO_WORDSIZE LZO_SIZEOF_VOID_P # endif #endif #if !defined(LZO_SIZEOF_SIZE_T) #if (LZO_ARCH_I086 || LZO_ARCH_M16C) # define LZO_SIZEOF_SIZE_T 2 #else # define LZO_SIZEOF_SIZE_T LZO_SIZEOF_VOID_P #endif #endif #if !defined(LZO_SIZEOF_PTRDIFF_T) #if (LZO_ARCH_I086) # if (LZO_MM_TINY || LZO_MM_SMALL || LZO_MM_MEDIUM || LZO_MM_HUGE) # define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_VOID_P # elif (LZO_MM_COMPACT || LZO_MM_LARGE) # if (LZO_CC_BORLANDC || LZO_CC_TURBOC) # define LZO_SIZEOF_PTRDIFF_T 4 # else # define LZO_SIZEOF_PTRDIFF_T 2 # endif # else # error "LZO_MM" # endif #else # define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_SIZE_T #endif #endif #if (LZO_ABI_NEUTRAL_ENDIAN) # undef LZO_ABI_BIG_ENDIAN # undef LZO_ABI_LITTLE_ENDIAN #elif !(LZO_ABI_BIG_ENDIAN) && !(LZO_ABI_LITTLE_ENDIAN) #if (LZO_ARCH_ALPHA) && (LZO_ARCH_CRAY_MPP) # define LZO_ABI_BIG_ENDIAN 1 #elif (LZO_ARCH_IA64) && (LZO_OS_POSIX_LINUX || LZO_OS_WIN64) # define LZO_ABI_LITTLE_ENDIAN 1 #elif (LZO_ARCH_ALPHA || LZO_ARCH_AMD64 || LZO_ARCH_BLACKFIN || LZO_ARCH_CRIS || LZO_ARCH_I086 || LZO_ARCH_I386 || LZO_ARCH_MSP430) # define LZO_ABI_LITTLE_ENDIAN 1 #elif (LZO_ARCH_AVR32 || LZO_ARCH_M68K || LZO_ARCH_S390) # define LZO_ABI_BIG_ENDIAN 1 #elif 1 && defined(__IAR_SYSTEMS_ICC__) && defined(__LITTLE_ENDIAN__) # if (__LITTLE_ENDIAN__ == 1) # define LZO_ABI_LITTLE_ENDIAN 1 # else # define LZO_ABI_BIG_ENDIAN 1 # endif #elif 1 && defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__) # define LZO_ABI_BIG_ENDIAN 1 #elif 1 && defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__) # define LZO_ABI_LITTLE_ENDIAN 1 #elif 1 && (LZO_ARCH_ARM) && defined(__ARMEB__) && !defined(__ARMEL__) # define LZO_ABI_BIG_ENDIAN 1 #elif 1 && (LZO_ARCH_ARM) && defined(__ARMEL__) && !defined(__ARMEB__) # define LZO_ABI_LITTLE_ENDIAN 1 #elif 1 && (LZO_ARCH_MIPS) && defined(__MIPSEB__) && !defined(__MIPSEL__) # define LZO_ABI_BIG_ENDIAN 1 #elif 1 && (LZO_ARCH_MIPS) && defined(__MIPSEL__) && !defined(__MIPSEB__) # define LZO_ABI_LITTLE_ENDIAN 1 #endif #endif #if (LZO_ABI_BIG_ENDIAN) && (LZO_ABI_LITTLE_ENDIAN) # error "this should not happen" #endif #if (LZO_ABI_BIG_ENDIAN) # define LZO_INFO_ABI_ENDIAN "be" #elif (LZO_ABI_LITTLE_ENDIAN) # define LZO_INFO_ABI_ENDIAN "le" #elif (LZO_ABI_NEUTRAL_ENDIAN) # define LZO_INFO_ABI_ENDIAN "neutral" #endif #if (LZO_SIZEOF_INT == 1 && LZO_SIZEOF_LONG == 2 && LZO_SIZEOF_VOID_P == 2) # define LZO_ABI_I8LP16 1 # define LZO_INFO_ABI_PM "i8lp16" #elif (LZO_SIZEOF_INT == 2 && LZO_SIZEOF_LONG == 2 && LZO_SIZEOF_VOID_P == 2) # define LZO_ABI_ILP16 1 # define LZO_INFO_ABI_PM "ilp16" #elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 4 && LZO_SIZEOF_VOID_P == 4) # define LZO_ABI_ILP32 1 # define LZO_INFO_ABI_PM "ilp32" #elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 4 && LZO_SIZEOF_VOID_P == 8 && LZO_SIZEOF_SIZE_T == 8) # define LZO_ABI_LLP64 1 # define LZO_INFO_ABI_PM "llp64" #elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 8) # define LZO_ABI_LP64 1 # define LZO_INFO_ABI_PM "lp64" #elif (LZO_SIZEOF_INT == 8 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 8) # define LZO_ABI_ILP64 1 # define LZO_INFO_ABI_PM "ilp64" #elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 4) # define LZO_ABI_IP32L64 1 # define LZO_INFO_ABI_PM "ip32l64" #endif #if !defined(__LZO_LIBC_OVERRIDE) #if (LZO_LIBC_NAKED) # define LZO_INFO_LIBC "naked" #elif (LZO_LIBC_FREESTANDING) # define LZO_INFO_LIBC "freestanding" #elif (LZO_LIBC_MOSTLY_FREESTANDING) # define LZO_INFO_LIBC "mfreestanding" #elif (LZO_LIBC_ISOC90) # define LZO_INFO_LIBC "isoc90" #elif (LZO_LIBC_ISOC99) # define LZO_INFO_LIBC "isoc99" #elif defined(__dietlibc__) # define LZO_LIBC_DIETLIBC 1 # define LZO_INFO_LIBC "dietlibc" #elif defined(_NEWLIB_VERSION) # define LZO_LIBC_NEWLIB 1 # define LZO_INFO_LIBC "newlib" #elif defined(__UCLIBC__) && defined(__UCLIBC_MAJOR__) && defined(__UCLIBC_MINOR__) # if defined(__UCLIBC_SUBLEVEL__) # define LZO_LIBC_UCLIBC (__UCLIBC_MAJOR__ * 0x10000L + __UCLIBC_MINOR__ * 0x100 + __UCLIBC_SUBLEVEL__) # else # define LZO_LIBC_UCLIBC 0x00090bL # endif # define LZO_INFO_LIBC "uclibc" #elif defined(__GLIBC__) && defined(__GLIBC_MINOR__) # define LZO_LIBC_GLIBC (__GLIBC__ * 0x10000L + __GLIBC_MINOR__ * 0x100) # define LZO_INFO_LIBC "glibc" #elif (LZO_CC_MWERKS) && defined(__MSL__) # define LZO_LIBC_MSL __MSL__ # define LZO_INFO_LIBC "msl" #elif 1 && defined(__IAR_SYSTEMS_ICC__) # define LZO_LIBC_ISOC90 1 # define LZO_INFO_LIBC "isoc90" #else # define LZO_LIBC_DEFAULT 1 # define LZO_INFO_LIBC "default" #endif #endif #if !defined(__lzo_gnuc_extension__) #if (LZO_CC_GNUC >= 0x020800ul) # define __lzo_gnuc_extension__ __extension__ #elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) # define __lzo_gnuc_extension__ __extension__ #else # define __lzo_gnuc_extension__ /*empty*/ #endif #endif #if !defined(__lzo_ua_volatile) # define __lzo_ua_volatile volatile #endif #if !defined(__lzo_alignof) #if (LZO_CC_CILLY || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI) # define __lzo_alignof(e) __alignof__(e) #elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 700)) # define __lzo_alignof(e) __alignof__(e) #elif (LZO_CC_MSC && (_MSC_VER >= 1300)) # define __lzo_alignof(e) __alignof(e) #elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100)) # define __lzo_alignof(e) __alignof__(e) #endif #endif #if defined(__lzo_alignof) # define __lzo_HAVE_alignof 1 #endif #if !defined(__lzo_constructor) #if (LZO_CC_GNUC >= 0x030400ul) # define __lzo_constructor __attribute__((__constructor__,__used__)) #elif (LZO_CC_GNUC >= 0x020700ul) # define __lzo_constructor __attribute__((__constructor__)) #elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) # define __lzo_constructor __attribute__((__constructor__)) #endif #endif #if defined(__lzo_constructor) # define __lzo_HAVE_constructor 1 #endif #if !defined(__lzo_destructor) #if (LZO_CC_GNUC >= 0x030400ul) # define __lzo_destructor __attribute__((__destructor__,__used__)) #elif (LZO_CC_GNUC >= 0x020700ul) # define __lzo_destructor __attribute__((__destructor__)) #elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) # define __lzo_destructor __attribute__((__destructor__)) #endif #endif #if defined(__lzo_destructor) # define __lzo_HAVE_destructor 1 #endif #if (__lzo_HAVE_destructor) && !(__lzo_HAVE_constructor) # error "this should not happen" #endif #if !defined(__lzo_inline) #if (LZO_CC_TURBOC && (__TURBOC__ <= 0x0295)) #elif defined(__cplusplus) # define __lzo_inline inline #elif (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0550)) # define __lzo_inline __inline #elif (LZO_CC_CILLY || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI) # define __lzo_inline __inline__ #elif (LZO_CC_DMC) # define __lzo_inline __inline #elif (LZO_CC_INTELC) # define __lzo_inline __inline #elif (LZO_CC_MWERKS && (__MWERKS__ >= 0x2405)) # define __lzo_inline __inline #elif (LZO_CC_MSC && (_MSC_VER >= 900)) # define __lzo_inline __inline #elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100)) # define __lzo_inline __inline__ #elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) # define __lzo_inline inline #endif #endif #if defined(__lzo_inline) # define __lzo_HAVE_inline 1 #else # define __lzo_inline /*empty*/ #endif #if !defined(__lzo_forceinline) #if (LZO_CC_GNUC >= 0x030200ul) # define __lzo_forceinline __inline__ __attribute__((__always_inline__)) #elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC) # define __lzo_forceinline __forceinline #elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC) # define __lzo_forceinline __inline__ __attribute__((__always_inline__)) #elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) # define __lzo_forceinline __inline__ __attribute__((__always_inline__)) #elif (LZO_CC_MSC && (_MSC_VER >= 1200)) # define __lzo_forceinline __forceinline #elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100)) # define __lzo_forceinline __inline__ __attribute__((__always_inline__)) #endif #endif #if defined(__lzo_forceinline) # define __lzo_HAVE_forceinline 1 #else # define __lzo_forceinline /*empty*/ #endif #if !defined(__lzo_noinline) #if 1 && (LZO_ARCH_I386) && (LZO_CC_GNUC >= 0x040000ul) && (LZO_CC_GNUC < 0x040003ul) # define __lzo_noinline __attribute__((__noinline__,__used__)) #elif (LZO_CC_GNUC >= 0x030200ul) # define __lzo_noinline __attribute__((__noinline__)) #elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_MSC) # define __lzo_noinline __declspec(noinline) #elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC) # define __lzo_noinline __attribute__((__noinline__)) #elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) # define __lzo_noinline __attribute__((__noinline__)) #elif (LZO_CC_MSC && (_MSC_VER >= 1300)) # define __lzo_noinline __declspec(noinline) #elif (LZO_CC_MWERKS && (__MWERKS__ >= 0x3200) && (LZO_OS_WIN32 || LZO_OS_WIN64)) # if defined(__cplusplus) # else # define __lzo_noinline __declspec(noinline) # endif #elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100)) # define __lzo_noinline __attribute__((__noinline__)) #endif #endif #if defined(__lzo_noinline) # define __lzo_HAVE_noinline 1 #else # define __lzo_noinline /*empty*/ #endif #if (__lzo_HAVE_forceinline || __lzo_HAVE_noinline) && !(__lzo_HAVE_inline) # error "this should not happen" #endif #if !defined(__lzo_noreturn) #if (LZO_CC_GNUC >= 0x020700ul) # define __lzo_noreturn __attribute__((__noreturn__)) #elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC) # define __lzo_noreturn __declspec(noreturn) #elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_GNUC) # define __lzo_noreturn __attribute__((__noreturn__)) #elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) # define __lzo_noreturn __attribute__((__noreturn__)) #elif (LZO_CC_MSC && (_MSC_VER >= 1200)) # define __lzo_noreturn __declspec(noreturn) #endif #endif #if defined(__lzo_noreturn) # define __lzo_HAVE_noreturn 1 #else # define __lzo_noreturn /*empty*/ #endif #if !defined(__lzo_nothrow) #if (LZO_CC_GNUC >= 0x030300ul) # define __lzo_nothrow __attribute__((__nothrow__)) #elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC) && defined(__cplusplus) # define __lzo_nothrow __declspec(nothrow) #elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 900) && LZO_CC_SYNTAX_GNUC) # define __lzo_nothrow __attribute__((__nothrow__)) #elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) # define __lzo_nothrow __attribute__((__nothrow__)) #elif (LZO_CC_MSC && (_MSC_VER >= 1200)) && defined(__cplusplus) # define __lzo_nothrow __declspec(nothrow) #endif #endif #if defined(__lzo_nothrow) # define __lzo_HAVE_nothrow 1 #else # define __lzo_nothrow /*empty*/ #endif #if !defined(__lzo_restrict) #if (LZO_CC_GNUC >= 0x030400ul) # define __lzo_restrict __restrict__ #elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_GNUC) # define __lzo_restrict __restrict__ #elif (LZO_CC_CLANG || LZO_CC_LLVM) # define __lzo_restrict __restrict__ #elif (LZO_CC_MSC && (_MSC_VER >= 1400)) # define __lzo_restrict __restrict #endif #endif #if defined(__lzo_restrict) # define __lzo_HAVE_restrict 1 #else # define __lzo_restrict /*empty*/ #endif #if !defined(__lzo_likely) && !defined(__lzo_unlikely) #if (LZO_CC_GNUC >= 0x030200ul) # define __lzo_likely(e) (__builtin_expect(!!(e),1)) # define __lzo_unlikely(e) (__builtin_expect(!!(e),0)) #elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800)) # define __lzo_likely(e) (__builtin_expect(!!(e),1)) # define __lzo_unlikely(e) (__builtin_expect(!!(e),0)) #elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) # define __lzo_likely(e) (__builtin_expect(!!(e),1)) # define __lzo_unlikely(e) (__builtin_expect(!!(e),0)) #endif #endif #if defined(__lzo_likely) # define __lzo_HAVE_likely 1 #else # define __lzo_likely(e) (e) #endif #if defined(__lzo_unlikely) # define __lzo_HAVE_unlikely 1 #else # define __lzo_unlikely(e) (e) #endif #if !defined(LZO_UNUSED) # if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0600)) # define LZO_UNUSED(var) ((void) &var) # elif (LZO_CC_BORLANDC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PELLESC || LZO_CC_TURBOC) # define LZO_UNUSED(var) if (&var) ; else # elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE) # define LZO_UNUSED(var) ((void) var) # elif (LZO_CC_MSC && (_MSC_VER < 900)) # define LZO_UNUSED(var) if (&var) ; else # elif (LZO_CC_KEILC) # define LZO_UNUSED(var) {extern int __lzo_unused[1-2*!(sizeof(var)>0)];} # elif (LZO_CC_PACIFICC) # define LZO_UNUSED(var) ((void) sizeof(var)) # elif (LZO_CC_WATCOMC) && defined(__cplusplus) # define LZO_UNUSED(var) ((void) var) # else # define LZO_UNUSED(var) ((void) &var) # endif #endif #if !defined(LZO_UNUSED_FUNC) # if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0600)) # define LZO_UNUSED_FUNC(func) ((void) func) # elif (LZO_CC_BORLANDC || LZO_CC_NDPC || LZO_CC_TURBOC) # define LZO_UNUSED_FUNC(func) if (func) ; else # elif (LZO_CC_CLANG || LZO_CC_LLVM) # define LZO_UNUSED_FUNC(func) ((void) &func) # elif (LZO_CC_MSC && (_MSC_VER < 900)) # define LZO_UNUSED_FUNC(func) if (func) ; else # elif (LZO_CC_MSC) # define LZO_UNUSED_FUNC(func) ((void) &func) # elif (LZO_CC_KEILC || LZO_CC_PELLESC) # define LZO_UNUSED_FUNC(func) {extern int __lzo_unused[1-2*!(sizeof((int)func)>0)];} # else # define LZO_UNUSED_FUNC(func) ((void) func) # endif #endif #if !defined(LZO_UNUSED_LABEL) # if (LZO_CC_WATCOMC) && defined(__cplusplus) # define LZO_UNUSED_LABEL(l) switch(0) case 1:goto l # elif (LZO_CC_CLANG || LZO_CC_INTELC || LZO_CC_WATCOMC) # define LZO_UNUSED_LABEL(l) if (0) goto l # else # define LZO_UNUSED_LABEL(l) switch(0) case 1:goto l # endif #endif #if !defined(LZO_DEFINE_UNINITIALIZED_VAR) # if 0 # define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init) type var # elif 0 && (LZO_CC_GNUC) # define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init) type var = var # else # define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init) type var = init # endif #endif #if !defined(LZO_UNCONST_CAST) # if 0 && defined(__cplusplus) # define LZO_UNCONST_CAST(t,e) (const_cast<t> (e)) # elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE) # define LZO_UNCONST_CAST(t,e) ((t) ((void *) ((char *) ((lzo_uintptr_t) ((const void *) (e)))))) # else # define LZO_UNCONST_CAST(t,e) ((t) ((void *) ((char *) ((const void *) (e))))) # endif #endif #if !defined(LZO_COMPILE_TIME_ASSERT_HEADER) # if (LZO_CC_AZTECC || LZO_CC_ZORTECHC) # define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1-!(e)]; # elif (LZO_CC_DMC || LZO_CC_SYMANTECC) # define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1u-2*!(e)]; # elif (LZO_CC_TURBOC && (__TURBOC__ == 0x0295)) # define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1-!(e)]; # else # define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1-2*!(e)]; # endif #endif #if !defined(LZO_COMPILE_TIME_ASSERT) # if (LZO_CC_AZTECC) # define LZO_COMPILE_TIME_ASSERT(e) {typedef int __lzo_cta_t[1-!(e)];} # elif (LZO_CC_DMC || LZO_CC_PACIFICC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC) # define LZO_COMPILE_TIME_ASSERT(e) switch(0) case 1:case !(e):break; # elif (LZO_CC_MSC && (_MSC_VER < 900)) # define LZO_COMPILE_TIME_ASSERT(e) switch(0) case 1:case !(e):break; # elif (LZO_CC_TURBOC && (__TURBOC__ == 0x0295)) # define LZO_COMPILE_TIME_ASSERT(e) switch(0) case 1:case !(e):break; # else # define LZO_COMPILE_TIME_ASSERT(e) {typedef int __lzo_cta_t[1-2*!(e)];} # endif #endif #if (LZO_ARCH_I086 || LZO_ARCH_I386) && (LZO_OS_DOS16 || LZO_OS_DOS32 || LZO_OS_OS2 || LZO_OS_OS216 || LZO_OS_WIN16 || LZO_OS_WIN32 || LZO_OS_WIN64) # if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC) # elif (LZO_CC_DMC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC) # define __lzo_cdecl __cdecl # define __lzo_cdecl_atexit /*empty*/ # define __lzo_cdecl_main __cdecl # if (LZO_OS_OS2 && (LZO_CC_DMC || LZO_CC_SYMANTECC)) # define __lzo_cdecl_qsort __pascal # elif (LZO_OS_OS2 && (LZO_CC_ZORTECHC)) # define __lzo_cdecl_qsort _stdcall # else # define __lzo_cdecl_qsort __cdecl # endif # elif (LZO_CC_WATCOMC) # define __lzo_cdecl __cdecl # else # define __lzo_cdecl __cdecl # define __lzo_cdecl_atexit __cdecl # define __lzo_cdecl_main __cdecl # define __lzo_cdecl_qsort __cdecl # endif # if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC || LZO_CC_WATCOMC) # elif (LZO_OS_OS2 && (LZO_CC_DMC || LZO_CC_SYMANTECC)) # define __lzo_cdecl_sighandler __pascal # elif (LZO_OS_OS2 && (LZO_CC_ZORTECHC)) # define __lzo_cdecl_sighandler _stdcall # elif (LZO_CC_MSC && (_MSC_VER >= 1400)) && defined(_M_CEE_PURE) # define __lzo_cdecl_sighandler __clrcall # elif (LZO_CC_MSC && (_MSC_VER >= 600 && _MSC_VER < 700)) # if defined(_DLL) # define __lzo_cdecl_sighandler _far _cdecl _loadds # elif defined(_MT) # define __lzo_cdecl_sighandler _far _cdecl # else # define __lzo_cdecl_sighandler _cdecl # endif # else # define __lzo_cdecl_sighandler __cdecl # endif #elif (LZO_ARCH_I386) && (LZO_CC_WATCOMC) # define __lzo_cdecl __cdecl #elif (LZO_ARCH_M68K && LZO_OS_TOS && (LZO_CC_PUREC || LZO_CC_TURBOC)) # define __lzo_cdecl cdecl #endif #if !defined(__lzo_cdecl) # define __lzo_cdecl /*empty*/ #endif #if !defined(__lzo_cdecl_atexit) # define __lzo_cdecl_atexit /*empty*/ #endif #if !defined(__lzo_cdecl_main) # define __lzo_cdecl_main /*empty*/ #endif #if !defined(__lzo_cdecl_qsort) # define __lzo_cdecl_qsort /*empty*/ #endif #if !defined(__lzo_cdecl_sighandler) # define __lzo_cdecl_sighandler /*empty*/ #endif #if !defined(__lzo_cdecl_va) # define __lzo_cdecl_va __lzo_cdecl #endif #if !(LZO_CFG_NO_WINDOWS_H) #if (LZO_OS_CYGWIN || (LZO_OS_EMX && defined(__RSXNT__)) || LZO_OS_WIN32 || LZO_OS_WIN64) # if (LZO_CC_WATCOMC && (__WATCOMC__ < 1000)) # elif (LZO_OS_WIN32 && LZO_CC_GNUC) && defined(__PW32__) # elif ((LZO_OS_CYGWIN || defined(__MINGW32__)) && (LZO_CC_GNUC && (LZO_CC_GNUC < 0x025f00ul))) # else # define LZO_HAVE_WINDOWS_H 1 # endif #endif #endif #if (LZO_ARCH_ALPHA) # define LZO_OPT_AVOID_UINT_INDEX 1 # define LZO_OPT_AVOID_SHORT 1 # define LZO_OPT_AVOID_USHORT 1 #elif (LZO_ARCH_AMD64) # define LZO_OPT_AVOID_INT_INDEX 1 # define LZO_OPT_AVOID_UINT_INDEX 1 # define LZO_OPT_UNALIGNED16 1 # define LZO_OPT_UNALIGNED32 1 # define LZO_OPT_UNALIGNED64 1 #elif (LZO_ARCH_ARM && LZO_ARCH_ARM_THUMB) #elif (LZO_ARCH_ARM) # define LZO_OPT_AVOID_SHORT 1 # define LZO_OPT_AVOID_USHORT 1 #elif (LZO_ARCH_CRIS) # define LZO_OPT_UNALIGNED16 1 # define LZO_OPT_UNALIGNED32 1 #elif (LZO_ARCH_I386) # define LZO_OPT_UNALIGNED16 1 # define LZO_OPT_UNALIGNED32 1 #elif (LZO_ARCH_IA64) # define LZO_OPT_AVOID_INT_INDEX 1 # define LZO_OPT_AVOID_UINT_INDEX 1 # define LZO_OPT_PREFER_POSTINC 1 #elif (LZO_ARCH_M68K) # define LZO_OPT_PREFER_POSTINC 1 # define LZO_OPT_PREFER_PREDEC 1 # if defined(__mc68020__) && !defined(__mcoldfire__) # define LZO_OPT_UNALIGNED16 1 # define LZO_OPT_UNALIGNED32 1 # endif #elif (LZO_ARCH_MIPS) # define LZO_OPT_AVOID_UINT_INDEX 1 #elif (LZO_ARCH_POWERPC) # define LZO_OPT_PREFER_PREINC 1 # define LZO_OPT_PREFER_PREDEC 1 # if (LZO_ABI_BIG_ENDIAN) # define LZO_OPT_UNALIGNED16 1 # define LZO_OPT_UNALIGNED32 1 # endif #elif (LZO_ARCH_S390) # define LZO_OPT_UNALIGNED16 1 # define LZO_OPT_UNALIGNED32 1 # if (LZO_SIZEOF_SIZE_T == 8) # define LZO_OPT_UNALIGNED64 1 # endif #elif (LZO_ARCH_SH) # define LZO_OPT_PREFER_POSTINC 1 # define LZO_OPT_PREFER_PREDEC 1 #endif #ifndef LZO_CFG_NO_INLINE_ASM #if (LZO_CC_LLVM) # define LZO_CFG_NO_INLINE_ASM 1 #endif #endif #ifndef LZO_CFG_NO_UNALIGNED #if (LZO_ABI_NEUTRAL_ENDIAN) || (LZO_ARCH_GENERIC) # define LZO_CFG_NO_UNALIGNED 1 #endif #endif #if (LZO_CFG_NO_UNALIGNED) # undef LZO_OPT_UNALIGNED16 # undef LZO_OPT_UNALIGNED32 # undef LZO_OPT_UNALIGNED64 #endif #if (LZO_CFG_NO_INLINE_ASM) #elif (LZO_ARCH_I386 && (LZO_OS_DOS32 || LZO_OS_WIN32) && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC)) # define LZO_ASM_SYNTAX_MSC 1 #elif (LZO_OS_WIN64 && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC)) #elif (LZO_ARCH_I386 && LZO_CC_GNUC && (LZO_CC_GNUC == 0x011f00ul)) #elif (LZO_ARCH_I386 && (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE)) # define LZO_ASM_SYNTAX_GNUC 1 #elif (LZO_ARCH_AMD64 && (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE)) # define LZO_ASM_SYNTAX_GNUC 1 #endif #if (LZO_ASM_SYNTAX_GNUC) #if (LZO_ARCH_I386 && LZO_CC_GNUC && (LZO_CC_GNUC < 0x020000ul)) # define __LZO_ASM_CLOBBER "ax" #elif (LZO_CC_INTELC) # define __LZO_ASM_CLOBBER "memory" #else # define __LZO_ASM_CLOBBER "cc", "memory" #endif #endif #if defined(__LZO_INFOSTR_MM) #elif (LZO_MM_FLAT) && (defined(__LZO_INFOSTR_PM) || defined(LZO_INFO_ABI_PM)) # define __LZO_INFOSTR_MM "" #elif defined(LZO_INFO_MM) # define __LZO_INFOSTR_MM "." LZO_INFO_MM #else # define __LZO_INFOSTR_MM "" #endif #if defined(__LZO_INFOSTR_PM) #elif defined(LZO_INFO_ABI_PM) # define __LZO_INFOSTR_PM "." LZO_INFO_ABI_PM #else # define __LZO_INFOSTR_PM "" #endif #if defined(__LZO_INFOSTR_ENDIAN) #elif defined(LZO_INFO_ABI_ENDIAN) # define __LZO_INFOSTR_ENDIAN "." LZO_INFO_ABI_ENDIAN #else # define __LZO_INFOSTR_ENDIAN "" #endif #if defined(__LZO_INFOSTR_OSNAME) #elif defined(LZO_INFO_OS_CONSOLE) # define __LZO_INFOSTR_OSNAME LZO_INFO_OS "." LZO_INFO_OS_CONSOLE #elif defined(LZO_INFO_OS_POSIX) # define __LZO_INFOSTR_OSNAME LZO_INFO_OS "." LZO_INFO_OS_POSIX #else # define __LZO_INFOSTR_OSNAME LZO_INFO_OS #endif #if defined(__LZO_INFOSTR_LIBC) #elif defined(LZO_INFO_LIBC) # define __LZO_INFOSTR_LIBC "." LZO_INFO_LIBC #else # define __LZO_INFOSTR_LIBC "" #endif #if defined(__LZO_INFOSTR_CCVER) #elif defined(LZO_INFO_CCVER) # define __LZO_INFOSTR_CCVER " " LZO_INFO_CCVER #else # define __LZO_INFOSTR_CCVER "" #endif #define LZO_INFO_STRING \ LZO_INFO_ARCH __LZO_INFOSTR_MM __LZO_INFOSTR_PM __LZO_INFOSTR_ENDIAN \ " " __LZO_INFOSTR_OSNAME __LZO_INFOSTR_LIBC " " LZO_INFO_CC __LZO_INFOSTR_CCVER #endif /* already included */ /* vim:set ts=4 et: */ ������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/fsw_ext2.c����������������������������������������������������������������0000664�0001750�0001750�00000046701�13112025560�017571� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/** * \file fsw_ext2.c * ext2 file system driver code. */ /*- * Copyright (c) 2006 Christoph Pfisterer * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "fsw_ext2.h" // functions static fsw_status_t fsw_ext2_volume_mount(struct fsw_ext2_volume *vol); static void fsw_ext2_volume_free(struct fsw_ext2_volume *vol); static fsw_status_t fsw_ext2_volume_stat(struct fsw_ext2_volume *vol, struct fsw_volume_stat *sb); static fsw_status_t fsw_ext2_dnode_fill(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno); static void fsw_ext2_dnode_free(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno); static fsw_status_t fsw_ext2_dnode_stat(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno, struct fsw_dnode_stat *sb); static fsw_status_t fsw_ext2_get_extent(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno, struct fsw_extent *extent); static fsw_status_t fsw_ext2_dir_lookup(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno, struct fsw_string *lookup_name, struct fsw_ext2_dnode **child_dno); static fsw_status_t fsw_ext2_dir_read(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno, struct fsw_shandle *shand, struct fsw_ext2_dnode **child_dno); static fsw_status_t fsw_ext2_read_dentry(struct fsw_shandle *shand, struct ext2_dir_entry *entry); static fsw_status_t fsw_ext2_readlink(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno, struct fsw_string *link); // // Dispatch Table // struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(ext2) = { { FSW_STRING_TYPE_ISO88591, 4, 4, "ext2" }, sizeof(struct fsw_ext2_volume), sizeof(struct fsw_ext2_dnode), fsw_ext2_volume_mount, fsw_ext2_volume_free, fsw_ext2_volume_stat, fsw_ext2_dnode_fill, fsw_ext2_dnode_free, fsw_ext2_dnode_stat, fsw_ext2_get_extent, fsw_ext2_dir_lookup, fsw_ext2_dir_read, fsw_ext2_readlink, }; /** * Mount an ext2 volume. Reads the superblock and constructs the * root directory dnode. */ static fsw_status_t fsw_ext2_volume_mount(struct fsw_ext2_volume *vol) { fsw_status_t status; void *buffer; fsw_u32 blocksize; fsw_u32 groupcnt, groupno, gdesc_per_block, gdesc_bno, gdesc_index; struct ext2_group_desc *gdesc; int i; struct fsw_string s; // allocate memory to keep the superblock around status = fsw_alloc(sizeof(struct ext2_super_block), &vol->sb); if (status) return status; // read the superblock into its buffer fsw_set_blocksize(vol, EXT2_SUPERBLOCK_BLOCKSIZE, EXT2_SUPERBLOCK_BLOCKSIZE); status = fsw_block_get(vol, EXT2_SUPERBLOCK_BLOCKNO, 0, &buffer); if (status) return status; fsw_memcpy(vol->sb, buffer, sizeof(struct ext2_super_block)); fsw_block_release(vol, EXT2_SUPERBLOCK_BLOCKNO, buffer); // check the superblock if (vol->sb->s_magic != EXT2_SUPER_MAGIC) return FSW_UNSUPPORTED; if (vol->sb->s_rev_level != EXT2_GOOD_OLD_REV && vol->sb->s_rev_level != EXT2_DYNAMIC_REV) return FSW_UNSUPPORTED; if (vol->sb->s_rev_level == EXT2_DYNAMIC_REV && (vol->sb->s_feature_incompat & ~(EXT2_FEATURE_INCOMPAT_FILETYPE | EXT3_FEATURE_INCOMPAT_RECOVER))) return FSW_UNSUPPORTED; /* if (vol->sb->s_rev_level == EXT2_DYNAMIC_REV && (vol->sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER)) Print(L"Ext2 WARNING: This ext3 file system needs recovery, trying to use it anyway.\n"); */ // set real blocksize blocksize = EXT2_BLOCK_SIZE(vol->sb); fsw_set_blocksize(vol, blocksize, blocksize); // get other info from superblock vol->ind_bcnt = EXT2_ADDR_PER_BLOCK(vol->sb); vol->dind_bcnt = vol->ind_bcnt * vol->ind_bcnt; vol->inode_size = EXT2_INODE_SIZE(vol->sb); for (i = 0; i < 16; i++) if (vol->sb->s_volume_name[i] == 0) break; s.type = FSW_STRING_TYPE_ISO88591; s.size = s.len = i; s.data = vol->sb->s_volume_name; status = fsw_strdup_coerce(&vol->g.label, vol->g.host_string_type, &s); if (status) return status; // read the group descriptors to get inode table offsets groupcnt = ((vol->sb->s_inodes_count - 2) / vol->sb->s_inodes_per_group) + 1; gdesc_per_block = (vol->g.phys_blocksize / sizeof(struct ext2_group_desc)); status = fsw_alloc(sizeof(fsw_u32) * groupcnt, &vol->inotab_bno); if (status) return status; for (groupno = 0; groupno < groupcnt; groupno++) { // get the block group descriptor gdesc_bno = (vol->sb->s_first_data_block + 1) + groupno / gdesc_per_block; gdesc_index = groupno % gdesc_per_block; status = fsw_block_get(vol, gdesc_bno, 1, (void **)&buffer); if (status) return status; gdesc = ((struct ext2_group_desc *)(buffer)) + gdesc_index; vol->inotab_bno[groupno] = gdesc->bg_inode_table; fsw_block_release(vol, gdesc_bno, buffer); } // setup the root dnode status = fsw_dnode_create_root(vol, EXT2_ROOT_INO, &vol->g.root); if (status) return status; FSW_MSG_DEBUG((FSW_MSGSTR("fsw_ext2_volume_mount: success, blocksize %d\n"), blocksize)); return FSW_SUCCESS; } /** * Free the volume data structure. Called by the core after an unmount or after * an unsuccessful mount to release the memory used by the file system type specific * part of the volume structure. */ static void fsw_ext2_volume_free(struct fsw_ext2_volume *vol) { if (vol->sb) fsw_free(vol->sb); if (vol->inotab_bno) fsw_free(vol->inotab_bno); } /** * Get in-depth information on a volume. */ static fsw_status_t fsw_ext2_volume_stat(struct fsw_ext2_volume *vol, struct fsw_volume_stat *sb) { sb->total_bytes = (fsw_u64)vol->sb->s_blocks_count * vol->g.log_blocksize; sb->free_bytes = (fsw_u64)vol->sb->s_free_blocks_count * vol->g.log_blocksize; return FSW_SUCCESS; } /** * Get full information on a dnode from disk. This function is called by the core * whenever it needs to access fields in the dnode structure that may not * be filled immediately upon creation of the dnode. In the case of ext2, we * delay fetching of the inode structure until dnode_fill is called. The size and * type fields are invalid until this function has been called. */ static fsw_status_t fsw_ext2_dnode_fill(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno) { fsw_status_t status; fsw_u32 groupno, ino_in_group, ino_bno, ino_index; fsw_u8 *buffer; if (dno->raw) return FSW_SUCCESS; FSW_MSG_DEBUG((FSW_MSGSTR("fsw_ext2_dnode_fill: inode %d\n"), dno->g.dnode_id)); // read the inode block groupno = (fsw_u32) (dno->g.dnode_id - 1) / vol->sb->s_inodes_per_group; ino_in_group = (fsw_u32) (dno->g.dnode_id - 1) % vol->sb->s_inodes_per_group; ino_bno = vol->inotab_bno[groupno] + ino_in_group / (vol->g.phys_blocksize / vol->inode_size); ino_index = ino_in_group % (vol->g.phys_blocksize / vol->inode_size); status = fsw_block_get(vol, ino_bno, 2, (void **)&buffer); if (status) return status; // keep our inode around status = fsw_memdup((void **)&dno->raw, buffer + ino_index * vol->inode_size, vol->inode_size); fsw_block_release(vol, ino_bno, buffer); if (status) return status; // get info from the inode dno->g.size = dno->raw->i_size; // TODO: check docs for 64-bit sized files if (S_ISREG(dno->raw->i_mode)) dno->g.type = FSW_DNODE_TYPE_FILE; else if (S_ISDIR(dno->raw->i_mode)) dno->g.type = FSW_DNODE_TYPE_DIR; else if (S_ISLNK(dno->raw->i_mode)) dno->g.type = FSW_DNODE_TYPE_SYMLINK; else dno->g.type = FSW_DNODE_TYPE_SPECIAL; return FSW_SUCCESS; } /** * Free the dnode data structure. Called by the core when deallocating a dnode * structure to release the memory used by the file system type specific part * of the dnode structure. */ static void fsw_ext2_dnode_free(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno) { if (dno->raw) fsw_free(dno->raw); } /** * Get in-depth information on a dnode. The core makes sure that fsw_ext2_dnode_fill * has been called on the dnode before this function is called. Note that some * data is not directly stored into the structure, but passed to a host-specific * callback that converts it to the host-specific format. */ static fsw_status_t fsw_ext2_dnode_stat(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno, struct fsw_dnode_stat *sb) { sb->used_bytes = dno->raw->i_blocks * 512; // very, very strange... fsw_store_time_posix(sb, FSW_DNODE_STAT_CTIME, dno->raw->i_ctime); fsw_store_time_posix(sb, FSW_DNODE_STAT_ATIME, dno->raw->i_atime); fsw_store_time_posix(sb, FSW_DNODE_STAT_MTIME, dno->raw->i_mtime); fsw_store_attr_posix(sb, dno->raw->i_mode); return FSW_SUCCESS; } /** * Retrieve file data mapping information. This function is called by the core when * fsw_shandle_read needs to know where on the disk the required piece of the file's * data can be found. The core makes sure that fsw_ext2_dnode_fill has been called * on the dnode before. Our task here is to get the physical disk block number for * the requested logical block number. * * The ext2 file system does not use extents, but stores a list of block numbers * using the usual direct, indirect, double-indirect, triple-indirect scheme. To * optimize access, this function checks if the following file blocks are mapped * to consecutive disk blocks and returns a combined extent if possible. */ static fsw_status_t fsw_ext2_get_extent(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno, struct fsw_extent *extent) { fsw_status_t status; fsw_u32 bno, release_bno, buf_bcnt, file_bcnt; fsw_u32 *buffer; int path[5], i; // Preconditions: The caller has checked that the requested logical block // is within the file's size. The dnode has complete information, i.e. // fsw_ext2_dnode_read_info was called successfully on it. extent->type = FSW_EXTENT_TYPE_PHYSBLOCK; extent->log_count = 1; bno = extent->log_start; // try direct block pointers in the inode if (bno < EXT2_NDIR_BLOCKS) { path[0] = bno; path[1] = -1; } else { bno -= EXT2_NDIR_BLOCKS; // try indirect block if (bno < vol->ind_bcnt) { path[0] = EXT2_IND_BLOCK; path[1] = bno; path[2] = -1; } else { bno -= vol->ind_bcnt; // try double-indirect block if (bno < vol->dind_bcnt) { path[0] = EXT2_DIND_BLOCK; path[1] = bno / vol->ind_bcnt; path[2] = bno % vol->ind_bcnt; path[3] = -1; } else { bno -= vol->dind_bcnt; // use the triple-indirect block path[0] = EXT2_TIND_BLOCK; path[1] = bno / vol->dind_bcnt; path[2] = (bno / vol->ind_bcnt) % vol->ind_bcnt; path[3] = bno % vol->ind_bcnt; path[4] = -1; } } } // follow the indirection path buffer = dno->raw->i_block; buf_bcnt = EXT2_NDIR_BLOCKS; release_bno = 0; for (i = 0; ; i++) { bno = buffer[path[i]]; if (bno == 0) { extent->type = FSW_EXTENT_TYPE_SPARSE; if (release_bno) fsw_block_release(vol, release_bno, buffer); return FSW_SUCCESS; } if (path[i+1] < 0) break; if (release_bno) fsw_block_release(vol, release_bno, buffer); status = fsw_block_get(vol, bno, 1, (void **)&buffer); if (status) return status; release_bno = bno; buf_bcnt = vol->ind_bcnt; } extent->phys_start = bno; // check if the following blocks can be aggregated into one extent file_bcnt = (fsw_u32)((dno->g.size + vol->g.log_blocksize - 1) & (vol->g.log_blocksize - 1)); while (path[i] + extent->log_count < buf_bcnt && // indirect block has more block pointers extent->log_start + extent->log_count < file_bcnt) { // file has more blocks if (buffer[path[i] + extent->log_count] == buffer[path[i] + extent->log_count - 1] + 1) extent->log_count++; else break; } if (release_bno) fsw_block_release(vol, release_bno, buffer); return FSW_SUCCESS; } /** * Lookup a directory's child dnode by name. This function is called on a directory * to retrieve the directory entry with the given name. A dnode is constructed for * this entry and returned. The core makes sure that fsw_ext2_dnode_fill has been called * and the dnode is actually a directory. */ static fsw_status_t fsw_ext2_dir_lookup(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno, struct fsw_string *lookup_name, struct fsw_ext2_dnode **child_dno_out) { fsw_status_t status; struct fsw_shandle shand; fsw_u32 child_ino; struct ext2_dir_entry entry; struct fsw_string entry_name; // Preconditions: The caller has checked that dno is a directory node. entry_name.type = FSW_STRING_TYPE_ISO88591; // setup handle to read the directory status = fsw_shandle_open(dno, &shand); if (status) return status; // scan the directory for the file child_ino = 0; while (child_ino == 0) { // read next entry status = fsw_ext2_read_dentry(&shand, &entry); if (status) goto errorexit; if (entry.inode == 0) { // end of directory reached status = FSW_NOT_FOUND; goto errorexit; } // compare name entry_name.len = entry_name.size = entry.name_len; entry_name.data = entry.name; if (fsw_streq(lookup_name, &entry_name)) { child_ino = entry.inode; break; } } // setup a dnode for the child item status = fsw_dnode_create(dno, child_ino, FSW_DNODE_TYPE_UNKNOWN, &entry_name, child_dno_out); errorexit: fsw_shandle_close(&shand); return status; } /** * Get the next directory entry when reading a directory. This function is called during * directory iteration to retrieve the next directory entry. A dnode is constructed for * the entry and returned. The core makes sure that fsw_ext2_dnode_fill has been called * and the dnode is actually a directory. The shandle provided by the caller is used to * record the position in the directory between calls. */ static fsw_status_t fsw_ext2_dir_read(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno, struct fsw_shandle *shand, struct fsw_ext2_dnode **child_dno_out) { fsw_status_t status; struct ext2_dir_entry entry; struct fsw_string entry_name; // Preconditions: The caller has checked that dno is a directory node. The caller // has opened a storage handle to the directory's storage and keeps it around between // calls. while (1) { // read next entry status = fsw_ext2_read_dentry(shand, &entry); if (status) return status; if (entry.inode == 0) // end of directory return FSW_NOT_FOUND; // skip . and .. if ((entry.name_len == 1 && entry.name[0] == '.') || (entry.name_len == 2 && entry.name[0] == '.' && entry.name[1] == '.')) continue; break; } // setup name entry_name.type = FSW_STRING_TYPE_ISO88591; entry_name.len = entry_name.size = entry.name_len; entry_name.data = entry.name; // setup a dnode for the child item status = fsw_dnode_create(dno, entry.inode, FSW_DNODE_TYPE_UNKNOWN, &entry_name, child_dno_out); return status; } /** * Read a directory entry from the directory's raw data. This internal function is used * to read a raw ext2 directory entry into memory. The shandle's position pointer is adjusted * to point to the next entry. */ static fsw_status_t fsw_ext2_read_dentry(struct fsw_shandle *shand, struct ext2_dir_entry *entry) { fsw_status_t status; fsw_u32 buffer_size; while (1) { // read dir_entry header (fixed length) buffer_size = 8; status = fsw_shandle_read(shand, &buffer_size, entry); if (status) return status; if (buffer_size < 8 || entry->rec_len == 0) { // end of directory reached entry->inode = 0; return FSW_SUCCESS; } if (entry->rec_len < 8) return FSW_VOLUME_CORRUPTED; if (entry->inode != 0) { // this entry is used if (entry->rec_len < 8 + entry->name_len) return FSW_VOLUME_CORRUPTED; break; } // valid, but unused entry, skip it shand->pos += entry->rec_len - 8; } // read file name (variable length) buffer_size = entry->name_len; status = fsw_shandle_read(shand, &buffer_size, entry->name); if (status) return status; if (buffer_size < entry->name_len) return FSW_VOLUME_CORRUPTED; // skip any remaining padding shand->pos += entry->rec_len - (8 + entry->name_len); return FSW_SUCCESS; } /** * Get the target path of a symbolic link. This function is called when a symbolic * link needs to be resolved. The core makes sure that the fsw_ext2_dnode_fill has been * called on the dnode and that it really is a symlink. * * For ext2, the target path can be stored inline in the inode structure (in the space * otherwise occupied by the block pointers) or in the inode's data. There is no flag * indicating this, only the number of blocks entry (i_blocks) can be used as an * indication. The check used here comes from the Linux kernel. */ static fsw_status_t fsw_ext2_readlink(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno, struct fsw_string *link_target) { fsw_status_t status; int ea_blocks; struct fsw_string s; if (dno->g.size > FSW_PATH_MAX) return FSW_VOLUME_CORRUPTED; ea_blocks = dno->raw->i_file_acl ? (vol->g.log_blocksize >> 9) : 0; if (dno->raw->i_blocks - ea_blocks == 0) { // "fast" symlink, path is stored inside the inode s.type = FSW_STRING_TYPE_ISO88591; s.size = s.len = (int)dno->g.size; s.data = dno->raw->i_block; status = fsw_strdup_coerce(link_target, vol->g.host_string_type, &s); } else { // "slow" symlink, path is stored in normal inode data status = fsw_dnode_readlink_data(dno, link_target); } return status; } // EOF ���������������������������������������������������������������refind-0.11.4/filesystems/fsw_ext2_disk.h�����������������������������������������������������������0000664�0001750�0001750�00000036020�12626644770�020624� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/** * \file fsw_ext2_disk.h * ext2 file system on-disk structures. */ /*- * Copyright (c) 2006 Christoph Pfisterer * Portions Copyright (c) 1991-2006 by various Linux kernel contributors * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _FSW_EXT2_DISK_H_ #define _FSW_EXT2_DISK_H_ // types typedef fsw_s8 __s8; typedef fsw_u8 __u8; typedef fsw_s16 __s16; typedef fsw_u16 __u16; typedef fsw_s32 __s32; typedef fsw_u32 __u32; typedef fsw_s64 __s64; typedef fsw_u64 __u64; typedef __u16 __le16; typedef __u32 __le32; typedef __u64 __le64; // // from Linux kernel, include/linux/ext2_fs.h // /* * Special inode numbers */ #define EXT2_BAD_INO 1 /* Bad blocks inode */ #define EXT2_ROOT_INO 2 /* Root inode */ #define EXT2_BOOT_LOADER_INO 5 /* Boot loader inode */ #define EXT2_UNDEL_DIR_INO 6 /* Undelete directory inode */ /* * The second extended file system magic number */ #define EXT2_SUPER_MAGIC 0xEF53 /* * Macro-instructions used to manage several block sizes */ #define EXT2_MIN_BLOCK_SIZE 1024 #define EXT2_MAX_BLOCK_SIZE 4096 #define EXT2_MIN_BLOCK_LOG_SIZE 10 #define EXT2_BLOCK_SIZE(s) (EXT2_MIN_BLOCK_SIZE << (s)->s_log_block_size) #define EXT2_ADDR_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (__u32)) #define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10) #define EXT2_INODE_SIZE(s) (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \ EXT2_GOOD_OLD_INODE_SIZE : \ (s)->s_inode_size) #define EXT2_FIRST_INO(s) (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \ EXT2_GOOD_OLD_FIRST_INO : \ (s)->s_first_ino) /* * Structure of a blocks group descriptor */ struct ext2_group_desc { __le32 bg_block_bitmap; /* Blocks bitmap block */ __le32 bg_inode_bitmap; /* Inodes bitmap block */ __le32 bg_inode_table; /* Inodes table block */ __le16 bg_free_blocks_count; /* Free blocks count */ __le16 bg_free_inodes_count; /* Free inodes count */ __le16 bg_used_dirs_count; /* Directories count */ __le16 bg_pad; __le32 bg_reserved[3]; }; /* * Macro-instructions used to manage group descriptors */ #define EXT2_BLOCKS_PER_GROUP(s) ((s)->s_blocks_per_group) #define EXT2_DESC_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc)) #define EXT2_INODES_PER_GROUP(s) ((s)->s_inodes_per_group) /* * Constants relative to the data blocks */ #define EXT2_NDIR_BLOCKS 12 #define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS #define EXT2_DIND_BLOCK (EXT2_IND_BLOCK + 1) #define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1) #define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1) /* * Inode flags */ #define EXT2_SECRM_FL 0x00000001 /* Secure deletion */ #define EXT2_UNRM_FL 0x00000002 /* Undelete */ #define EXT2_COMPR_FL 0x00000004 /* Compress file */ #define EXT2_SYNC_FL 0x00000008 /* Synchronous updates */ #define EXT2_IMMUTABLE_FL 0x00000010 /* Immutable file */ #define EXT2_APPEND_FL 0x00000020 /* writes to file may only append */ #define EXT2_NODUMP_FL 0x00000040 /* do not dump file */ #define EXT2_NOATIME_FL 0x00000080 /* do not update atime */ /* Reserved for compression usage... */ #define EXT2_DIRTY_FL 0x00000100 #define EXT2_COMPRBLK_FL 0x00000200 /* One or more compressed clusters */ #define EXT2_NOCOMP_FL 0x00000400 /* Don't compress */ #define EXT2_ECOMPR_FL 0x00000800 /* Compression error */ /* End compression flags --- maybe not all used */ #define EXT2_BTREE_FL 0x00001000 /* btree format dir */ #define EXT2_INDEX_FL 0x00001000 /* hash-indexed directory */ #define EXT2_IMAGIC_FL 0x00002000 /* AFS directory */ #define EXT2_JOURNAL_DATA_FL 0x00004000 /* Reserved for ext3 */ #define EXT2_NOTAIL_FL 0x00008000 /* file tail should not be merged */ #define EXT2_DIRSYNC_FL 0x00010000 /* dirsync behaviour (directories only) */ #define EXT2_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/ #define EXT2_RESERVED_FL 0x80000000 /* reserved for ext2 lib */ #define EXT2_FL_USER_VISIBLE 0x0003DFFF /* User visible flags */ #define EXT2_FL_USER_MODIFIABLE 0x000380FF /* User modifiable flags */ /* * Structure of an inode on the disk */ struct ext2_inode { __le16 i_mode; /* 0: File mode */ __le16 i_uid; /* 2: Low 16 bits of Owner Uid */ __le32 i_size; /* 4: Size in bytes */ __le32 i_atime; /* 8: Access time */ __le32 i_ctime; /* 12: Creation time */ __le32 i_mtime; /* 16: Modification time */ __le32 i_dtime; /* 20: Deletion Time */ __le16 i_gid; /* 24: Low 16 bits of Group Id */ __le16 i_links_count; /* 26: Links count */ __le32 i_blocks; /* 28: Blocks count */ __le32 i_flags; /* 32: File flags */ union { struct { __le32 l_i_reserved1; } linux1; struct { __le32 h_i_translator; } hurd1; struct { __le32 m_i_reserved1; } masix1; } osd1; /* 36: OS dependent 1 */ __le32 i_block[EXT2_N_BLOCKS];/* 40: Pointers to blocks */ __le32 i_generation; /* 100: File version (for NFS) */ __le32 i_file_acl; /* 104: File ACL */ __le32 i_dir_acl; /* 108: Directory ACL */ __le32 i_faddr; /* 112: Fragment address */ union { struct { __u8 l_i_frag; /* 116: Fragment number */ __u8 l_i_fsize; /* 117: Fragment size */ __u16 i_pad1; __le16 l_i_uid_high; /* 120: these 2 fields */ __le16 l_i_gid_high; /* 122: were reserved2[0] */ __u32 l_i_reserved2; } linux2; struct { __u8 h_i_frag; /* Fragment number */ __u8 h_i_fsize; /* Fragment size */ __le16 h_i_mode_high; __le16 h_i_uid_high; __le16 h_i_gid_high; __le32 h_i_author; } hurd2; struct { __u8 m_i_frag; /* Fragment number */ __u8 m_i_fsize; /* Fragment size */ __u16 m_pad1; __u32 m_i_reserved2[2]; } masix2; } osd2; /* OS dependent 2 */ }; #define i_size_high i_dir_acl /* * Structure of the super block */ struct ext2_super_block { __le32 s_inodes_count; /* Inodes count */ __le32 s_blocks_count; /* Blocks count */ __le32 s_r_blocks_count; /* Reserved blocks count */ __le32 s_free_blocks_count; /* Free blocks count */ __le32 s_free_inodes_count; /* Free inodes count */ __le32 s_first_data_block; /* First Data Block */ __le32 s_log_block_size; /* Block size */ __le32 s_log_frag_size; /* Fragment size */ __le32 s_blocks_per_group; /* # Blocks per group */ __le32 s_frags_per_group; /* # Fragments per group */ __le32 s_inodes_per_group; /* # Inodes per group */ __le32 s_mtime; /* Mount time */ __le32 s_wtime; /* Write time */ __le16 s_mnt_count; /* Mount count */ __le16 s_max_mnt_count; /* Maximal mount count */ __le16 s_magic; /* Magic signature */ __le16 s_state; /* File system state */ __le16 s_errors; /* Behaviour when detecting errors */ __le16 s_minor_rev_level; /* minor revision level */ __le32 s_lastcheck; /* time of last check */ __le32 s_checkinterval; /* max. time between checks */ __le32 s_creator_os; /* OS */ __le32 s_rev_level; /* Revision level */ __le16 s_def_resuid; /* Default uid for reserved blocks */ __le16 s_def_resgid; /* Default gid for reserved blocks */ /* * These fields are for EXT2_DYNAMIC_REV superblocks only. * * Note: the difference between the compatible feature set and * the incompatible feature set is that if there is a bit set * in the incompatible feature set that the kernel doesn't * know about, it should refuse to mount the filesystem. * * e2fsck's requirements are more strict; if it doesn't know * about a feature in either the compatible or incompatible * feature set, it must abort and not try to meddle with * things it doesn't understand... */ __le32 s_first_ino; /* First non-reserved inode */ __le16 s_inode_size; /* size of inode structure */ __le16 s_block_group_nr; /* block group # of this superblock */ __le32 s_feature_compat; /* compatible feature set */ __le32 s_feature_incompat; /* incompatible feature set */ __le32 s_feature_ro_compat; /* readonly-compatible feature set */ __u8 s_uuid[16]; /* 128-bit uuid for volume */ char s_volume_name[16]; /* volume name */ char s_last_mounted[64]; /* directory where last mounted */ __le32 s_algorithm_usage_bitmap; /* For compression */ /* * Performance hints. Directory preallocation should only * happen if the EXT2_COMPAT_PREALLOC flag is on. */ __u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/ __u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */ __u16 s_padding1; /* * Journaling support valid if EXT3_FEATURE_COMPAT_HAS_JOURNAL set. */ __u8 s_journal_uuid[16]; /* uuid of journal superblock */ __u32 s_journal_inum; /* inode number of journal file */ __u32 s_journal_dev; /* device number of journal file */ __u32 s_last_orphan; /* start of list of inodes to delete */ __u32 s_hash_seed[4]; /* HTREE hash seed */ __u8 s_def_hash_version; /* Default hash version to use */ __u8 s_reserved_char_pad; __u16 s_reserved_word_pad; __le32 s_default_mount_opts; __le32 s_first_meta_bg; /* First metablock block group */ __u32 s_reserved[190]; /* Padding to the end of the block */ }; /* * Revision levels */ #define EXT2_GOOD_OLD_REV 0 /* The good old (original) format */ #define EXT2_DYNAMIC_REV 1 /* V2 format w/ dynamic inode sizes */ #define EXT2_CURRENT_REV EXT2_GOOD_OLD_REV #define EXT2_MAX_SUPP_REV EXT2_DYNAMIC_REV #define EXT2_GOOD_OLD_INODE_SIZE 128 /* * Feature set definitions */ #define EXT2_HAS_COMPAT_FEATURE(sb,mask) \ ( EXT2_SB(sb)->s_es->s_feature_compat & cpu_to_le32(mask) ) #define EXT2_HAS_RO_COMPAT_FEATURE(sb,mask) \ ( EXT2_SB(sb)->s_es->s_feature_ro_compat & cpu_to_le32(mask) ) #define EXT2_HAS_INCOMPAT_FEATURE(sb,mask) \ ( EXT2_SB(sb)->s_es->s_feature_incompat & cpu_to_le32(mask) ) #define EXT2_SET_COMPAT_FEATURE(sb,mask) \ EXT2_SB(sb)->s_es->s_feature_compat |= cpu_to_le32(mask) #define EXT2_SET_RO_COMPAT_FEATURE(sb,mask) \ EXT2_SB(sb)->s_es->s_feature_ro_compat |= cpu_to_le32(mask) #define EXT2_SET_INCOMPAT_FEATURE(sb,mask) \ EXT2_SB(sb)->s_es->s_feature_incompat |= cpu_to_le32(mask) #define EXT2_CLEAR_COMPAT_FEATURE(sb,mask) \ EXT2_SB(sb)->s_es->s_feature_compat &= ~cpu_to_le32(mask) #define EXT2_CLEAR_RO_COMPAT_FEATURE(sb,mask) \ EXT2_SB(sb)->s_es->s_feature_ro_compat &= ~cpu_to_le32(mask) #define EXT2_CLEAR_INCOMPAT_FEATURE(sb,mask) \ EXT2_SB(sb)->s_es->s_feature_incompat &= ~cpu_to_le32(mask) #define EXT2_FEATURE_COMPAT_DIR_PREALLOC 0x0001 #define EXT2_FEATURE_COMPAT_IMAGIC_INODES 0x0002 #define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004 #define EXT2_FEATURE_COMPAT_EXT_ATTR 0x0008 #define EXT2_FEATURE_COMPAT_RESIZE_INO 0x0010 #define EXT2_FEATURE_COMPAT_DIR_INDEX 0x0020 #define EXT2_FEATURE_COMPAT_ANY 0xffffffff #define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001 #define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002 #define EXT2_FEATURE_RO_COMPAT_BTREE_DIR 0x0004 #define EXT2_FEATURE_RO_COMPAT_ANY 0xffffffff #define EXT2_FEATURE_INCOMPAT_COMPRESSION 0x0001 #define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002 #define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004 #define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 #define EXT2_FEATURE_INCOMPAT_META_BG 0x0010 #define EXT2_FEATURE_INCOMPAT_ANY 0xffffffff /* #define EXT2_FEATURE_COMPAT_SUPP EXT2_FEATURE_COMPAT_EXT_ATTR #define EXT2_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE| \ EXT2_FEATURE_INCOMPAT_META_BG) #define EXT2_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \ EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \ EXT2_FEATURE_RO_COMPAT_BTREE_DIR) #define EXT2_FEATURE_RO_COMPAT_UNSUPPORTED ~EXT2_FEATURE_RO_COMPAT_SUPP #define EXT2_FEATURE_INCOMPAT_UNSUPPORTED ~EXT2_FEATURE_INCOMPAT_SUPP */ /* * Structure of a directory entry */ #define EXT2_NAME_LEN 255 struct ext2_dir_entry { __le32 inode; /* Inode number */ __le16 rec_len; /* Directory entry length */ __u8 name_len; /* Name length */ __u8 file_type; char name[EXT2_NAME_LEN]; /* File name */ }; // NOTE: The original Linux kernel header defines ext2_dir_entry with the original // layout and ext2_dir_entry_2 with the revised layout. We simply use the revised one. /* * Ext2 directory file types. Only the low 3 bits are used. The * other bits are reserved for now. */ enum { EXT2_FT_UNKNOWN, EXT2_FT_REG_FILE, EXT2_FT_DIR, EXT2_FT_CHRDEV, EXT2_FT_BLKDEV, EXT2_FT_FIFO, EXT2_FT_SOCK, EXT2_FT_SYMLINK, EXT2_FT_MAX }; #endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/AutoGen.h�����������������������������������������������������������������0000664�0001750�0001750�00000003223�13074520570�017377� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/** DO NOT EDIT FILE auto-generated Module name: AutoGen.h Abstract: Auto-generated AutoGen.h for building module or library. **/ #ifndef _AUTOGENH_B34E5765_2E02_4DAF_867F_7F40BE6FC33D #define _AUTOGENH_B34E5765_2E02_4DAF_867F_7F40BE6FC33D #ifdef __cplusplus extern "C" { #endif #include <Base.h> #include <Uefi.h> #include <Library/PcdLib.h> // Definition of PCDs used in this module #define _PCD_TOKEN_PcdUefiVariableDefaultLang 18U #define _PCD_PATCHABLE_PcdUefiVariableDefaultLang_SIZE 5 #define _PCD_VALUE_PcdUefiVariableDefaultLang _gPcd_FixedAtBuild_PcdUefiVariableDefaultLang extern const UINT8 _gPcd_FixedAtBuild_PcdUefiVariableDefaultLang[5]; #define _PCD_GET_MODE_PTR_PcdUefiVariableDefaultLang _gPcd_FixedAtBuild_PcdUefiVariableDefaultLang //#define _PCD_SET_MODE_PTR_PcdUefiVariableDefaultLang ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD #define _PCD_TOKEN_PcdUefiVariableDefaultPlatformLang 19U #define _PCD_PATCHABLE_PcdUefiVariableDefaultPlatformLang_SIZE 7 #define _PCD_VALUE_PcdUefiVariableDefaultPlatformLang _gPcd_FixedAtBuild_PcdUefiVariableDefaultPlatformLang extern const UINT8 _gPcd_FixedAtBuild_PcdUefiVariableDefaultPlatformLang[7]; #define _PCD_GET_MODE_PTR_PcdUefiVariableDefaultPlatformLang _gPcd_FixedAtBuild_PcdUefiVariableDefaultPlatformLang //#define _PCD_SET_MODE_PTR_PcdUefiVariableDefaultPlatformLang ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD // Definition of PCDs used in libraries is in AutoGen.c EFI_STATUS EFIAPI fsw_efi_main ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ); #ifdef __cplusplus } #endif #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/Makefile������������������������������������������������������������������0000664�0001750�0001750�00000004172�12631403226�017324� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# meta-Makefile for rEFInd filesystem drivers # # Most of the functionality is in Make.tiano; this Makefile merely # deletes critical temporary files and calls Make.tiano with the # name of the driver to be built. This is done because of a dependency # in the fsw_efi.c file on the filesystem type; this file must be # recompiled for each new filesystem built. # This program is licensed under the terms of the GNU GPL, version 3, # or (at your option) any later version. # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. INSTALL_DIR = /boot/efi/EFI/refind/drivers FILESYSTEMS = ext2 ext4 reiserfs iso9660 hfs btrfs ntfs FILESYSTEMS_GNUEFI = ext2_gnuefi ext4_gnuefi reiserfs_gnuefi iso9660_gnuefi hfs_gnuefi btrfs_gnuefi ntfs_gnuefi TEXTFILES = $(FILESYSTEMS:=*.txt) # Build the drivers with TianoCore EDK2..... all: $(FILESYSTEMS) ext2: rm -f fsw_efi.obj +make DRIVERNAME=ext2 -f Make.tiano ext4: rm -f fsw_efi.obj +make DRIVERNAME=ext4 -f Make.tiano reiserfs: rm -f fsw_efi.obj +make DRIVERNAME=reiserfs -f Make.tiano iso9660: rm -f fsw_efi.obj +make DRIVERNAME=iso9660 -f Make.tiano hfs: rm -f fsw_efi.obj +make DRIVERNAME=hfs -f Make.tiano btrfs: rm -f fsw_efi.obj +make DRIVERNAME=btrfs -f Make.tiano ntfs: rm -f fsw_efi.obj +make DRIVERNAME=ntfs -f Make.tiano # Build the drivers with GNU-EFI.... gnuefi: $(FILESYSTEMS_GNUEFI) all_gnuefi: $(FILESYSTEMS_GNUEFI) ext2_gnuefi: rm -f fsw_efi.o +make DRIVERNAME=ext2 -f Make.gnuefi ext4_gnuefi: rm -f fsw_efi.o +make DRIVERNAME=ext4 -f Make.gnuefi reiserfs_gnuefi: rm -f fsw_efi.o +make DRIVERNAME=reiserfs -f Make.gnuefi iso9660_gnuefi: rm -f fsw_efi.o +make DRIVERNAME=iso9660 -f Make.gnuefi hfs_gnuefi: rm -f fsw_efi.o +make DRIVERNAME=hfs -f Make.gnuefi btrfs_gnuefi: rm -f fsw_efi.o +make DRIVERNAME=btrfs -f Make.gnuefi ntfs_gnuefi: rm -f fsw_efi.o +make DRIVERNAME=ntfs -f Make.gnuefi # utility rules clean: rm -f *~ *.bak *.o *.obj *.so *.efi *.dll err.txt $(TEXTFILES) +make -C test clean install: mkdir -p $(INSTALL_DIR) cp *.efi $(INSTALL_DIR) # DO NOT DELETE ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/minilzo.h�����������������������������������������������������������������0000664�0001750�0001750�00000007234�12626644770�017537� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * this file take from grub 2.0 * for btrfs UEFI driver */ /* minilzo.h -- mini subset of the LZO real-time data compression library This file is part of the LZO real-time data compression library. Copyright (C) 2011 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2010 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2009 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer All Rights Reserved. The LZO library is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The LZO library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the LZO library; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Markus F.X.J. Oberhumer <markus@oberhumer.com> http://www.oberhumer.com/opensource/lzo/ */ /* * NOTE: * the full LZO package can be found at * http://www.oberhumer.com/opensource/lzo/ */ #ifndef __MINILZO_H #define __MINILZO_H 1 #define MINILZO_VERSION 0x2050 #ifdef __LZOCONF_H # error "you cannot use both LZO and miniLZO" #endif #undef LZO_HAVE_CONFIG_H #include "lzoconf.h" #if !defined(LZO_VERSION) || (LZO_VERSION != MINILZO_VERSION) # error "version mismatch in header files" #endif #ifdef __cplusplus extern "C" { #endif /*********************************************************************** // ************************************************************************/ /* Memory required for the wrkmem parameter. * When the required size is 0, you can also pass a NULL pointer. */ #define LZO1X_MEM_COMPRESS LZO1X_1_MEM_COMPRESS #define LZO1X_1_MEM_COMPRESS ((lzo_uint32) (16384L * lzo_sizeof_dict_t)) #define LZO1X_MEM_DECOMPRESS (0) /* compression */ LZO_EXTERN(int) lzo1x_1_compress ( const lzo_bytep src, lzo_uint src_len, lzo_bytep dst, lzo_uintp dst_len, lzo_voidp wrkmem ); /* decompression */ LZO_EXTERN(int) lzo1x_decompress ( const lzo_bytep src, lzo_uint src_len, lzo_bytep dst, lzo_uintp dst_len, lzo_voidp wrkmem /* NOT USED */ ); /* safe decompression with overrun testing */ LZO_EXTERN(int) lzo1x_decompress_safe ( const lzo_bytep src, lzo_uint src_len, lzo_bytep dst, lzo_uintp dst_len, lzo_voidp wrkmem /* NOT USED */ ); #ifdef __cplusplus } /* extern "C" */ #endif #endif /* already included */ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/lzoconf.h�����������������������������������������������������������������0000664�0001750�0001750�00000035762�12626644770�017537� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * this file take from grub 2.0 * for btrfs UEFI driver */ /* lzoconf.h -- configuration of the LZO data compression library This file is part of the LZO real-time data compression library. Copyright (C) 2011 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2010 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2009 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer All Rights Reserved. The LZO library is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The LZO library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the LZO library; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Markus F.X.J. Oberhumer <markus@oberhumer.com> http://www.oberhumer.com/opensource/lzo/ */ #ifndef __LZOCONF_H_INCLUDED #define __LZOCONF_H_INCLUDED 1 #define LZO_VERSION 0x2050 #define LZO_VERSION_STRING "2.05" #define LZO_VERSION_DATE "Apr 23 2011" /* internal Autoconf configuration file - only used when building LZO */ #if defined(LZO_HAVE_CONFIG_H) # include <config.h> #endif #include <limits.h> #include <stddef.h> /*********************************************************************** // LZO requires a conforming <limits.h> ************************************************************************/ #if !defined(CHAR_BIT) || (CHAR_BIT != 8) # error "invalid CHAR_BIT" #endif #if !defined(UCHAR_MAX) || !defined(UINT_MAX) || !defined(ULONG_MAX) # error "check your compiler installation" #endif #if (USHRT_MAX < 1) || (UINT_MAX < 1) || (ULONG_MAX < 1) # error "your limits.h macros are broken" #endif /* get OS and architecture defines */ #ifndef __LZODEFS_H_INCLUDED #include "lzodefs.h" #endif #ifdef __cplusplus extern "C" { #endif /*********************************************************************** // some core defines ************************************************************************/ #if !defined(LZO_UINT32_C) # if (UINT_MAX < LZO_0xffffffffL) # define LZO_UINT32_C(c) c ## UL # else # define LZO_UINT32_C(c) ((c) + 0U) # endif #endif /* memory checkers */ #if !defined(__LZO_CHECKER) # if defined(__BOUNDS_CHECKING_ON) # define __LZO_CHECKER 1 # elif defined(__CHECKER__) # define __LZO_CHECKER 1 # elif defined(__INSURE__) # define __LZO_CHECKER 1 # elif defined(__PURIFY__) # define __LZO_CHECKER 1 # endif #endif /*********************************************************************** // integral and pointer types ************************************************************************/ /* lzo_uint should match size_t */ #if !defined(LZO_UINT_MAX) # if defined(LZO_ABI_LLP64) /* WIN64 */ # if defined(LZO_OS_WIN64) typedef unsigned __int64 lzo_uint; typedef __int64 lzo_int; # else typedef unsigned long long lzo_uint; typedef long long lzo_int; # endif # define LZO_UINT_MAX 0xffffffffffffffffull # define LZO_INT_MAX 9223372036854775807LL # define LZO_INT_MIN (-1LL - LZO_INT_MAX) # elif defined(LZO_ABI_IP32L64) /* MIPS R5900 */ typedef unsigned int lzo_uint; typedef int lzo_int; # define LZO_UINT_MAX UINT_MAX # define LZO_INT_MAX INT_MAX # define LZO_INT_MIN INT_MIN # elif (ULONG_MAX >= LZO_0xffffffffL) typedef unsigned long lzo_uint; typedef long lzo_int; # define LZO_UINT_MAX ULONG_MAX # define LZO_INT_MAX LONG_MAX # define LZO_INT_MIN LONG_MIN # else # error "lzo_uint" # endif #endif /* Integral types with 32 bits or more. */ #if !defined(LZO_UINT32_MAX) # if (UINT_MAX >= LZO_0xffffffffL) typedef unsigned int lzo_uint32; typedef int lzo_int32; # define LZO_UINT32_MAX UINT_MAX # define LZO_INT32_MAX INT_MAX # define LZO_INT32_MIN INT_MIN # elif (ULONG_MAX >= LZO_0xffffffffL) typedef unsigned long lzo_uint32; typedef long lzo_int32; # define LZO_UINT32_MAX ULONG_MAX # define LZO_INT32_MAX LONG_MAX # define LZO_INT32_MIN LONG_MIN # else # error "lzo_uint32" # endif #endif /* Integral types with exactly 64 bits. */ #if !defined(LZO_UINT64_MAX) # if (LZO_UINT_MAX >= LZO_0xffffffffL) # if ((((LZO_UINT_MAX) >> 31) >> 31) == 3) # define lzo_uint64 lzo_uint # define lzo_int64 lzo_int # define LZO_UINT64_MAX LZO_UINT_MAX # define LZO_INT64_MAX LZO_INT_MAX # define LZO_INT64_MIN LZO_INT_MIN # endif # elif (ULONG_MAX >= LZO_0xffffffffL) # if ((((ULONG_MAX) >> 31) >> 31) == 3) typedef unsigned long lzo_uint64; typedef long lzo_int64; # define LZO_UINT64_MAX ULONG_MAX # define LZO_INT64_MAX LONG_MAX # define LZO_INT64_MIN LONG_MIN # endif # endif #endif /* The larger type of lzo_uint and lzo_uint32. */ #if (LZO_UINT_MAX >= LZO_UINT32_MAX) # define lzo_xint lzo_uint #else # define lzo_xint lzo_uint32 #endif /* Memory model that allows to access memory at offsets of lzo_uint. */ #if !defined(__LZO_MMODEL) # if (LZO_UINT_MAX <= UINT_MAX) # define __LZO_MMODEL /*empty*/ # elif defined(LZO_HAVE_MM_HUGE_PTR) # define __LZO_MMODEL_HUGE 1 # define __LZO_MMODEL __huge # else # define __LZO_MMODEL /*empty*/ # endif #endif /* no typedef here because of const-pointer issues */ #define lzo_bytep unsigned char __LZO_MMODEL * #define lzo_charp char __LZO_MMODEL * #define lzo_voidp void __LZO_MMODEL * #define lzo_shortp short __LZO_MMODEL * #define lzo_ushortp unsigned short __LZO_MMODEL * #define lzo_uint32p lzo_uint32 __LZO_MMODEL * #define lzo_int32p lzo_int32 __LZO_MMODEL * #if defined(LZO_UINT64_MAX) #define lzo_uint64p lzo_uint64 __LZO_MMODEL * #define lzo_int64p lzo_int64 __LZO_MMODEL * #endif #define lzo_uintp lzo_uint __LZO_MMODEL * #define lzo_intp lzo_int __LZO_MMODEL * #define lzo_xintp lzo_xint __LZO_MMODEL * #define lzo_voidpp lzo_voidp __LZO_MMODEL * #define lzo_bytepp lzo_bytep __LZO_MMODEL * /* deprecated - use 'lzo_bytep' instead of 'lzo_byte *' */ #define lzo_byte unsigned char __LZO_MMODEL typedef int lzo_bool; /*********************************************************************** // function types ************************************************************************/ /* name mangling */ #if !defined(__LZO_EXTERN_C) # ifdef __cplusplus # define __LZO_EXTERN_C extern "C" # else # define __LZO_EXTERN_C extern # endif #endif /* calling convention */ #if !defined(__LZO_CDECL) # define __LZO_CDECL __lzo_cdecl #endif /* DLL export information */ #if !defined(__LZO_EXPORT1) # define __LZO_EXPORT1 /*empty*/ #endif #if !defined(__LZO_EXPORT2) # define __LZO_EXPORT2 /*empty*/ #endif /* __cdecl calling convention for public C and assembly functions */ #if !defined(LZO_PUBLIC) # define LZO_PUBLIC(_rettype) __LZO_EXPORT1 _rettype __LZO_EXPORT2 __LZO_CDECL #endif #if !defined(LZO_EXTERN) # define LZO_EXTERN(_rettype) __LZO_EXTERN_C LZO_PUBLIC(_rettype) #endif #if !defined(LZO_PRIVATE) # define LZO_PRIVATE(_rettype) static _rettype __LZO_CDECL #endif /* function types */ typedef int (__LZO_CDECL *lzo_compress_t) ( const lzo_bytep src, lzo_uint src_len, lzo_bytep dst, lzo_uintp dst_len, lzo_voidp wrkmem ); typedef int (__LZO_CDECL *lzo_decompress_t) ( const lzo_bytep src, lzo_uint src_len, lzo_bytep dst, lzo_uintp dst_len, lzo_voidp wrkmem ); typedef int (__LZO_CDECL *lzo_optimize_t) ( lzo_bytep src, lzo_uint src_len, lzo_bytep dst, lzo_uintp dst_len, lzo_voidp wrkmem ); typedef int (__LZO_CDECL *lzo_compress_dict_t)(const lzo_bytep src, lzo_uint src_len, lzo_bytep dst, lzo_uintp dst_len, lzo_voidp wrkmem, const lzo_bytep dict, lzo_uint dict_len ); typedef int (__LZO_CDECL *lzo_decompress_dict_t)(const lzo_bytep src, lzo_uint src_len, lzo_bytep dst, lzo_uintp dst_len, lzo_voidp wrkmem, const lzo_bytep dict, lzo_uint dict_len ); /* Callback interface. Currently only the progress indicator ("nprogress") * is used, but this may change in a future release. */ struct lzo_callback_t; typedef struct lzo_callback_t lzo_callback_t; #define lzo_callback_p lzo_callback_t __LZO_MMODEL * /* malloc & free function types */ typedef lzo_voidp (__LZO_CDECL *lzo_alloc_func_t) (lzo_callback_p self, lzo_uint items, lzo_uint size); typedef void (__LZO_CDECL *lzo_free_func_t) (lzo_callback_p self, lzo_voidp ptr); /* a progress indicator callback function */ typedef void (__LZO_CDECL *lzo_progress_func_t) (lzo_callback_p, lzo_uint, lzo_uint, int); struct lzo_callback_t { /* custom allocators (set to 0 to disable) */ lzo_alloc_func_t nalloc; /* [not used right now] */ lzo_free_func_t nfree; /* [not used right now] */ /* a progress indicator callback function (set to 0 to disable) */ lzo_progress_func_t nprogress; /* NOTE: the first parameter "self" of the nalloc/nfree/nprogress * callbacks points back to this struct, so you are free to store * some extra info in the following variables. */ lzo_voidp user1; lzo_xint user2; lzo_xint user3; }; /*********************************************************************** // error codes and prototypes ************************************************************************/ /* Error codes for the compression/decompression functions. Negative * values are errors, positive values will be used for special but * normal events. */ #define LZO_E_OK 0 #define LZO_E_ERROR (-1) #define LZO_E_OUT_OF_MEMORY (-2) /* [lzo_alloc_func_t failure] */ #define LZO_E_NOT_COMPRESSIBLE (-3) /* [not used right now] */ #define LZO_E_INPUT_OVERRUN (-4) #define LZO_E_OUTPUT_OVERRUN (-5) #define LZO_E_LOOKBEHIND_OVERRUN (-6) #define LZO_E_EOF_NOT_FOUND (-7) #define LZO_E_INPUT_NOT_CONSUMED (-8) #define LZO_E_NOT_YET_IMPLEMENTED (-9) /* [not used right now] */ #define LZO_E_INVALID_ARGUMENT (-10) #ifndef lzo_sizeof_dict_t # define lzo_sizeof_dict_t ((unsigned)sizeof(lzo_bytep)) #endif /* lzo_init() should be the first function you call. * Check the return code ! * * lzo_init() is a macro to allow checking that the library and the * compiler's view of various types are consistent. */ #define lzo_init() __lzo_init_v2(LZO_VERSION,(int)sizeof(short),(int)sizeof(int),\ (int)sizeof(long),(int)sizeof(lzo_uint32),(int)sizeof(lzo_uint),\ (int)lzo_sizeof_dict_t,(int)sizeof(char *),(int)sizeof(lzo_voidp),\ (int)sizeof(lzo_callback_t)) LZO_EXTERN(int) __lzo_init_v2(unsigned,int,int,int,int,int,int,int,int,int); /* version functions (useful for shared libraries) */ LZO_EXTERN(unsigned) lzo_version(void); LZO_EXTERN(const char *) lzo_version_string(void); LZO_EXTERN(const char *) lzo_version_date(void); LZO_EXTERN(const lzo_charp) _lzo_version_string(void); LZO_EXTERN(const lzo_charp) _lzo_version_date(void); /* string functions */ LZO_EXTERN(int) lzo_memcmp(const lzo_voidp a, const lzo_voidp b, lzo_uint len); LZO_EXTERN(lzo_voidp) lzo_memcpy(lzo_voidp dst, const lzo_voidp src, lzo_uint len); LZO_EXTERN(lzo_voidp) lzo_memmove(lzo_voidp dst, const lzo_voidp src, lzo_uint len); LZO_EXTERN(lzo_voidp) lzo_memset(lzo_voidp buf, int c, lzo_uint len); /* checksum functions */ LZO_EXTERN(lzo_uint32) lzo_adler32(lzo_uint32 c, const lzo_bytep buf, lzo_uint len); LZO_EXTERN(lzo_uint32) lzo_crc32(lzo_uint32 c, const lzo_bytep buf, lzo_uint len); LZO_EXTERN(const lzo_uint32p) lzo_get_crc32_table(void); /* misc. */ LZO_EXTERN(int) _lzo_config_check(void); typedef union { lzo_bytep p; lzo_uint u; } __lzo_pu_u; typedef union { lzo_bytep p; lzo_uint32 u32; } __lzo_pu32_u; typedef union { void *vp; lzo_bytep bp; lzo_uint u; lzo_uint32 u32; unsigned long l; } lzo_align_t; /* align a char pointer on a boundary that is a multiple of 'size' */ LZO_EXTERN(unsigned) __lzo_align_gap(const lzo_voidp p, lzo_uint size); #define LZO_PTR_ALIGN_UP(p,size) \ ((p) + (lzo_uint) __lzo_align_gap((const lzo_voidp)(p),(lzo_uint)(size))) /*********************************************************************** // deprecated macros - only for backward compatibility with LZO v1.xx ************************************************************************/ #if defined(LZO_CFG_COMPAT) #define __LZOCONF_H 1 #if defined(LZO_ARCH_I086) # define __LZO_i386 1 #elif defined(LZO_ARCH_I386) # define __LZO_i386 1 #endif #if defined(LZO_OS_DOS16) # define __LZO_DOS 1 # define __LZO_DOS16 1 #elif defined(LZO_OS_DOS32) # define __LZO_DOS 1 #elif defined(LZO_OS_WIN16) # define __LZO_WIN 1 # define __LZO_WIN16 1 #elif defined(LZO_OS_WIN32) # define __LZO_WIN 1 #endif #define __LZO_CMODEL /*empty*/ #define __LZO_DMODEL /*empty*/ #define __LZO_ENTRY __LZO_CDECL #define LZO_EXTERN_CDECL LZO_EXTERN #define LZO_ALIGN LZO_PTR_ALIGN_UP #define lzo_compress_asm_t lzo_compress_t #define lzo_decompress_asm_t lzo_decompress_t #endif /* LZO_CFG_COMPAT */ #ifdef __cplusplus } /* extern "C" */ #endif #endif /* already included */ /* vim:set ts=4 et: */ ��������������refind-0.11.4/filesystems/fsw_iso9660.c�������������������������������������������������������������0000664�0001750�0001750�00000063026�13151263212�020026� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Id: fsw_iso9660.c 33540 2010-10-28 09:27:05Z vboxsync $ */ /** @file * fsw_iso9660.c - ISO9660 file system driver code. * * Current limitations: * - Files must be in one extent (i.e. Level 2) * - No Joliet or Rock Ridge extensions * - No interleaving * - inode number generation strategy fails on volumes > 2 GB * - No blocksizes != 2048 * - No High Sierra or anything else != 'CD001' * - No volume sets with directories pointing at other volumes * - No extended attribute records */ /* * Copyright (C) 2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; * you can redistribute it and/or modify it under the terms of the GNU * General Public License (GPL) as published by the Free Software * Foundation, in version 2 as it comes in the "COPYING" file of the * VirtualBox OSE distribution. VirtualBox OSE is distributed in the * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. */ /*- * This code is based on: * * Copyright (c) 2006 Christoph Pfisterer * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * * Neither the name of Christoph Pfisterer nor the names of the * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "fsw_iso9660.h" //#include <Protocol/MsgLog.h> #ifndef DEBUG_ISO #define DEBUG_ISO 1 #endif #if DEBUG_ISO == 2 #define DBG(x...) AsciiPrint(x) #elif DEBUG_ISO == 1 #define DBG(x...) BootLog(x) #else #define DBG(x...) #endif //#define MsgLog(x...) if(msgCursor){AsciiSPrint(msgCursor, BOOTER_LOG_SIZE, x); while(*msgCursor){msgCursor++;}} // extern CHAR8 *msgCursor; // extern MESSAGE_LOG_PROTOCOL *Msg; // functions static fsw_status_t fsw_iso9660_volume_mount(struct fsw_iso9660_volume *vol); static void fsw_iso9660_volume_free(struct fsw_iso9660_volume *vol); static fsw_status_t fsw_iso9660_volume_stat(struct fsw_iso9660_volume *vol, struct fsw_volume_stat *sb); static fsw_status_t fsw_iso9660_dnode_fill(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno); static void fsw_iso9660_dnode_free(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno); static fsw_status_t fsw_iso9660_dnode_stat(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno, struct fsw_dnode_stat *sb); static fsw_status_t fsw_iso9660_get_extent(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno, struct fsw_extent *extent); static fsw_status_t fsw_iso9660_dir_lookup(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno, struct fsw_string *lookup_name, struct fsw_iso9660_dnode **child_dno); static fsw_status_t fsw_iso9660_dir_read(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno, struct fsw_shandle *shand, struct fsw_iso9660_dnode **child_dno); static fsw_status_t fsw_iso9660_read_dirrec(struct fsw_iso9660_volume *vol, struct fsw_shandle *shand, struct iso9660_dirrec_buffer *dirrec_buffer); static fsw_status_t fsw_iso9660_readlink(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno, struct fsw_string *link); static fsw_status_t rr_find_sp(struct iso9660_dirrec *dirrec, struct fsw_rock_ridge_susp_sp **psp); static fsw_status_t rr_find_nm(struct fsw_iso9660_volume *vol, struct iso9660_dirrec *dirrec, int off, struct fsw_string *str); static fsw_status_t rr_read_ce(struct fsw_iso9660_volume *vol, union fsw_rock_ridge_susp_ce *ce, fsw_u8 *begin); //static void dump_dirrec(struct iso9660_dirrec *dirrec); // // Dispatch Table // struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(iso9660) = { { FSW_STRING_TYPE_ISO88591, 4, 4, "iso9660" }, sizeof(struct fsw_iso9660_volume), sizeof(struct fsw_iso9660_dnode), fsw_iso9660_volume_mount, fsw_iso9660_volume_free, fsw_iso9660_volume_stat, fsw_iso9660_dnode_fill, fsw_iso9660_dnode_free, fsw_iso9660_dnode_stat, fsw_iso9660_get_extent, fsw_iso9660_dir_lookup, fsw_iso9660_dir_read, fsw_iso9660_readlink, }; static fsw_status_t rr_find_sp(struct iso9660_dirrec *dirrec, struct fsw_rock_ridge_susp_sp **psp) { fsw_u8 *r; int off = 0; struct fsw_rock_ridge_susp_sp *sp; r = (fsw_u8 *)((fsw_u8 *)dirrec + sizeof(*dirrec) + dirrec->file_identifier_length); off = (int)(r - (fsw_u8 *)dirrec); while(off < dirrec->dirrec_length) { if (*r == 'S') { sp = (struct fsw_rock_ridge_susp_sp *)r; if( sp->e.sig[0] == 'S' && sp->e.sig[1] == 'P' && sp->magic[0] == 0xbe && sp->magic[1] == 0xef) { *psp = sp; return FSW_SUCCESS; } } r++; off = (int)(r - (fsw_u8 *)dirrec); } *psp = NULL; return FSW_NOT_FOUND; } static fsw_status_t rr_find_nm(struct fsw_iso9660_volume *vol, struct iso9660_dirrec *dirrec, int off, struct fsw_string *str) { fsw_u8 *r, *begin; int fCe = 0; struct fsw_rock_ridge_susp_nm *nm; int limit = dirrec->dirrec_length; begin = (fsw_u8 *)dirrec; r = (fsw_u8 *)dirrec + off; str->data = NULL; str->len = 0; str->size = 0; str->type = 0; while(off < limit) { if (r[0] == 'C' && r[1] == 'E' && r[2] == 28) { int rc; int ce_off; union fsw_rock_ridge_susp_ce *ce; if (fCe == 0) fsw_alloc_zero(ISO9660_BLOCKSIZE, (void *)&begin); fCe = 1; // DEBUG((DEBUG_WARN, "%a:%d we found CE before NM or its continuation\n", __FILE__, __LINE__)); ce = (union fsw_rock_ridge_susp_ce *)r; limit = ISOINT(ce->X.len); ce_off = ISOINT(ce->X.offset); rc = rr_read_ce(vol, ce, begin); if (rc != FSW_SUCCESS) { fsw_free(begin); return rc; } begin += ce_off; r = begin; } if (r[0] == 'N' && r[1] == 'M') { nm = (struct fsw_rock_ridge_susp_nm *)r; if( nm->e.sig[0] == 'N' && nm->e.sig[1] == 'M') { int len = 0; fsw_u8 *tmp = NULL; if (nm->flags & RR_NM_CURR) { fsw_memdup(str->data, ".", 1); str->len = 1; goto done; } if (nm->flags & RR_NM_PARE) { fsw_memdup(str->data, "..", 2); str->len = 2; goto done; } len = nm->e.len - sizeof(struct fsw_rock_ridge_susp_nm) + 1; fsw_alloc_zero(str->len + len, (void **)&tmp); if (str->data != NULL) { fsw_memcpy(tmp, str->data, str->len); fsw_free(str->data); } // DEBUG((DEBUG_INFO, "dst:%p src:%p len:%d\n", tmp + str->len, &nm->name[0], len)); fsw_memcpy(tmp + str->len, &nm->name[0], len); str->data = tmp; str->len += len; if ((nm->flags & RR_NM_CONT) == 0) goto done; } } r++; off = (int)(r - (fsw_u8 *)begin); } if(fCe == 1) fsw_free(begin); return FSW_NOT_FOUND; done: str->type = FSW_STRING_TYPE_ISO88591; str->size = str->len; if(fCe == 1) fsw_free(begin); return FSW_SUCCESS; } static fsw_status_t rr_read_ce(struct fsw_iso9660_volume *vol, union fsw_rock_ridge_susp_ce *ce, fsw_u8 *begin) { int rc; // int i; // fsw_u8 *r = begin + ISOINT(ce->X.offset); // int len = ISOINT(ce->X.len); rc = vol->g.host_table->read_block(&vol->g, ISOINT(ce->X.block_loc), begin); if (rc != FSW_SUCCESS) return rc; /* for (i = 0; i < len; ++i) { DEBUG((DEBUG_INFO, "%d: (%d:%x)%c ", i, r[i], r[i], r[i])); }*/ return FSW_SUCCESS; } /* static void dump_dirrec(struct iso9660_dirrec *dirrec) { int i; fsw_u8 *r = (fsw_u8 *)dirrec + dirrec->file_identifier_length; int len = dirrec->dirrec_length; for (i = dirrec->file_identifier_length; i < len; ++i) { DEBUG((DEBUG_INFO, "%d: (%d:%x)%c ", i, r[i], r[i], r[i])); } }*/ /** * Mount an ISO9660 volume. Reads the superblock and constructs the * root directory dnode. */ static fsw_status_t fsw_iso9660_volume_mount(struct fsw_iso9660_volume *vol) { fsw_status_t status; void *buffer; fsw_u32 blockno; struct iso9660_volume_descriptor *voldesc; struct iso9660_primary_volume_descriptor *pvoldesc; fsw_u32 voldesc_type; int i; struct fsw_string s; struct iso9660_dirrec rootdir; int sua_pos; char *sig; struct fsw_rock_ridge_susp_entry *entry; // read through the Volume Descriptor Set fsw_set_blocksize(vol, ISO9660_BLOCKSIZE, ISO9660_BLOCKSIZE); blockno = ISO9660_SUPERBLOCK_BLOCKNO; do { // DBG("iso9660: check blockno=%d\n", blockno); status = fsw_block_get(vol, blockno, 0, &buffer); if (status) return status; voldesc = (struct iso9660_volume_descriptor *)buffer; voldesc_type = voldesc->volume_descriptor_type; if (fsw_memeq(voldesc->standard_identifier, "CD001", 5)) { // descriptor follows ISO 9660 standard if (voldesc_type == 1 && voldesc->volume_descriptor_version == 1) { // suitable Primary Volume Descriptor found // DBG("iso9660: suitable Primary Volume Descriptor found\n"); if (vol->primary_voldesc) { fsw_free(vol->primary_voldesc); vol->primary_voldesc = NULL; } status = fsw_memdup((void **)&vol->primary_voldesc, voldesc, ISO9660_BLOCKSIZE); } } else if (!fsw_memeq(voldesc->standard_identifier, "CD", 2)) { // completely alien standard identifier, stop reading voldesc_type = 255; } fsw_block_release(vol, blockno, buffer); blockno++; } while (!status && voldesc_type != 255); if (status) return status; // get information from Primary Volume Descriptor if (vol->primary_voldesc == NULL) return FSW_UNSUPPORTED; pvoldesc = vol->primary_voldesc; // if (ISOINT(pvoldesc->logical_block_size) != 2048) // return FSW_UNSUPPORTED; // get volume name for (i = 32; i > 0; i--) if (pvoldesc->volume_identifier[i-1] != ' ') break; s.type = FSW_STRING_TYPE_ISO88591; s.size = s.len = i; s.data = pvoldesc->volume_identifier; status = fsw_strdup_coerce(&vol->g.label, vol->g.host_string_type, &s); if (status) return status; // setup the root dnode status = fsw_dnode_create_root(vol, ISO9660_SUPERBLOCK_BLOCKNO << ISO9660_BLOCKSIZE_BITS, &vol->g.root); if (status) return status; fsw_memcpy(&vol->g.root->dirrec, &pvoldesc->root_directory, sizeof(struct iso9660_dirrec)); if ( pvoldesc->escape[0] == 0x25 && pvoldesc->escape[1] == 0x2f && ( pvoldesc->escape[2] == 0x40 || pvoldesc->escape[2] == 0x43 || pvoldesc->escape[2] == 0x45)) { // FSW_MSG_DEBUG((FSW_MSGSTR("fsw_iso9660_volume_mount: success (joliet!!!)\n"))); // DBG("fsw_iso9660_volume_mount: success (joliet!!!)\n"); vol->fJoliet = 1; } rootdir = pvoldesc->root_directory; sua_pos = (sizeof(struct iso9660_dirrec)) + rootdir.file_identifier_length + (rootdir.file_identifier_length % 2) - 2; //int sua_size = rootdir.dirrec_length - rootdir.file_identifier_length; //FSW_MSG_DEBUG((FSW_MSGSTR("fsw_iso9660_volume_mount: success (SUA(pos:%x, sz:%d)!!!)\n"), sua_pos, sua_size)); #if 1 status = fsw_block_get(vol, ISOINT(rootdir.extent_location), 0, &buffer); sig = (char *)buffer + sua_pos; entry = (struct fsw_rock_ridge_susp_entry *)sig; if ( entry->sig[0] == 'S' && entry->sig[1] == 'P') { struct fsw_rock_ridge_susp_sp *sp = (struct fsw_rock_ridge_susp_sp *)entry; if (sp->magic[0] == 0xbe && sp->magic[1] == 0xef) { vol->fRockRidge = 1; } else { // FSW_MSG_DEBUG((FSW_MSGSTR("fsw_iso9660_volume_mount: SP magic isn't valid\n"))); // DBG("fsw_iso9660_volume_mount: SP magic isn't valid\n"); } } #endif // release volume descriptors fsw_free(vol->primary_voldesc); vol->primary_voldesc = NULL; // FSW_MSG_DEBUG((FSW_MSGSTR("fsw_iso9660_volume_mount: success\n"))); // DBG("fsw_iso9660_volume_mount: success\n"); return FSW_SUCCESS; } /** * Free the volume data structure. Called by the core after an unmount or after * an unsuccessful mount to release the memory used by the file system type specific * part of the volume structure. */ static void fsw_iso9660_volume_free(struct fsw_iso9660_volume *vol) { if (vol->primary_voldesc) fsw_free(vol->primary_voldesc); } /** * Get in-depth information on a volume. */ static fsw_status_t fsw_iso9660_volume_stat(struct fsw_iso9660_volume *vol, struct fsw_volume_stat *sb) { sb->total_bytes = 0; //(fsw_u64)vol->sb->s_blocks_count * vol->g.log_blocksize; sb->free_bytes = 0; return FSW_SUCCESS; } /** * Get full information on a dnode from disk. This function is called by the core * whenever it needs to access fields in the dnode structure that may not * be filled immediately upon creation of the dnode. In the case of iso9660, we * delay fetching of the inode structure until dnode_fill is called. The size and * type fields are invalid until this function has been called. */ static fsw_status_t fsw_iso9660_dnode_fill(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno) { // get info from the directory record dno->g.size = ISOINT(dno->dirrec.data_length); if (dno->dirrec.file_flags & 0x02) dno->g.type = FSW_DNODE_TYPE_DIR; else dno->g.type = FSW_DNODE_TYPE_FILE; return FSW_SUCCESS; } /** * Free the dnode data structure. Called by the core when deallocating a dnode * structure to release the memory used by the file system type specific part * of the dnode structure. */ static void fsw_iso9660_dnode_free(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno) { } /** * Get in-depth information on a dnode. The core makes sure that fsw_iso9660_dnode_fill * has been called on the dnode before this function is called. Note that some * data is not directly stored into the structure, but passed to a host-specific * callback that converts it to the host-specific format. */ static fsw_status_t fsw_iso9660_dnode_stat(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno, struct fsw_dnode_stat *sb) { sb->used_bytes = (dno->g.size + (ISO9660_BLOCKSIZE-1)) & ~(ISO9660_BLOCKSIZE-1); /* fsw_store_time_posix(sb, FSW_DNODE_STAT_CTIME, dno->raw->i_ctime); fsw_store_time_posix(sb, FSW_DNODE_STAT_ATIME, dno->raw->i_atime); fsw_store_time_posix(sb, FSW_DNODE_STAT_MTIME, dno->raw->i_mtime); fsw_store_attr_posix(sb, dno->raw->i_mode); */ return FSW_SUCCESS; } /** * Retrieve file data mapping information. This function is called by the core when * fsw_shandle_read needs to know where on the disk the required piece of the file's * data can be found. The core makes sure that fsw_iso9660_dnode_fill has been called * on the dnode before. Our task here is to get the physical disk block number for * the requested logical block number. */ static fsw_status_t fsw_iso9660_get_extent(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno, struct fsw_extent *extent) { // Preconditions: The caller has checked that the requested logical block // is within the file's size. The dnode has complete information, i.e. // fsw_iso9660_dnode_read_info was called successfully on it. extent->type = FSW_EXTENT_TYPE_PHYSBLOCK; extent->phys_start = ISOINT(dno->dirrec.extent_location); extent->log_start = 0; extent->log_count = (ISOINT(dno->dirrec.data_length) + (ISO9660_BLOCKSIZE-1)) >> ISO9660_BLOCKSIZE_BITS; return FSW_SUCCESS; } /** * Lookup a directory's child dnode by name. This function is called on a directory * to retrieve the directory entry with the given name. A dnode is constructed for * this entry and returned. The core makes sure that fsw_iso9660_dnode_fill has been called * and the dnode is actually a directory. */ static fsw_status_t fsw_iso9660_dir_lookup(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno, struct fsw_string *lookup_name, struct fsw_iso9660_dnode **child_dno_out) { fsw_status_t status; struct fsw_shandle shand; struct iso9660_dirrec_buffer dirrec_buffer; struct iso9660_dirrec *dirrec = &dirrec_buffer.dirrec; // Preconditions: The caller has checked that dno is a directory node. // setup handle to read the directory status = fsw_shandle_open(dno, &shand); if (status) return status; // scan the directory for the file while (1) { // read next entry status = fsw_iso9660_read_dirrec(vol, &shand, &dirrec_buffer); if (status) goto errorexit; if (dirrec->dirrec_length == 0) { // end of directory reached status = FSW_NOT_FOUND; goto errorexit; } // skip . and .. if (dirrec->file_identifier_length == 1 && (dirrec->file_identifier[0] == 0 || dirrec->file_identifier[0] == 1)) continue; // compare name if (fsw_streq(lookup_name, &dirrec_buffer.name)) // TODO: compare case-insensitively break; } // setup a dnode for the child item status = fsw_dnode_create(dno, dirrec_buffer.ino, FSW_DNODE_TYPE_UNKNOWN, &dirrec_buffer.name, child_dno_out); if (status == FSW_SUCCESS) fsw_memcpy(&(*child_dno_out)->dirrec, dirrec, sizeof(struct iso9660_dirrec)); errorexit: fsw_shandle_close(&shand); return status; } /** * Get the next directory entry when reading a directory. This function is called during * directory iteration to retrieve the next directory entry. A dnode is constructed for * the entry and returned. The core makes sure that fsw_iso9660_dnode_fill has been called * and the dnode is actually a directory. The shandle provided by the caller is used to * record the position in the directory between calls. */ static fsw_status_t fsw_iso9660_dir_read(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno, struct fsw_shandle *shand, struct fsw_iso9660_dnode **child_dno_out) { fsw_status_t status; struct iso9660_dirrec_buffer dirrec_buffer; struct iso9660_dirrec *dirrec = &dirrec_buffer.dirrec; // Preconditions: The caller has checked that dno is a directory node. The caller // has opened a storage handle to the directory's storage and keeps it around between // calls. /* (vasily) directory nodes are 4096 bytes that is two logical blocks so read dir operation * should read both blocks. */ while (1) { // read next entry if (shand->pos >= dno->g.size) return FSW_NOT_FOUND; // end of directory status = fsw_iso9660_read_dirrec(vol, shand, &dirrec_buffer); if (status) return status; if (dirrec->dirrec_length == 0) { // try the next block shand->pos =(shand->pos & ~(vol->g.log_blocksize - 1)) + vol->g.log_blocksize; continue; } // skip . and .. if (dirrec->file_identifier_length == 1 && (dirrec->file_identifier[0] == 0 || dirrec->file_identifier[0] == 1)) continue; break; } // setup a dnode for the child item status = fsw_dnode_create(dno, dirrec_buffer.ino, FSW_DNODE_TYPE_UNKNOWN, &dirrec_buffer.name, child_dno_out); if (status == FSW_SUCCESS) fsw_memcpy(&(*child_dno_out)->dirrec, dirrec, sizeof(struct iso9660_dirrec)); return status; } /** * Read a directory entry from the directory's raw data. This internal function is used * to read a raw iso9660 directory entry into memory. The shandle's position pointer is adjusted * to point to the next entry. */ static fsw_status_t fsw_iso9660_read_dirrec(struct fsw_iso9660_volume *vol, struct fsw_shandle *shand, struct iso9660_dirrec_buffer *dirrec_buffer) { fsw_status_t status; fsw_u32 i, buffer_size, remaining_size, name_len; struct fsw_rock_ridge_susp_sp *sp = NULL; struct iso9660_dirrec *dirrec = &dirrec_buffer->dirrec; int sp_off; int rc; dirrec_buffer->ino = (ISOINT(((struct fsw_iso9660_dnode *)shand->dnode)->dirrec.extent_location) << ISO9660_BLOCKSIZE_BITS) + (fsw_u32)shand->pos; // read fixed size part of directory record buffer_size = 33; status = fsw_shandle_read(shand, &buffer_size, dirrec); if (status) { // DEBUG((DEBUG_INFO, "%a:%d \n", __FILE__, __LINE__)); return status; } if (buffer_size < 33 || dirrec->dirrec_length == 0) { // end of directory reached fsw_u8 *r; r = (fsw_u8 *)dirrec; // DEBUG((DEBUG_INFO, "%a:%d bs:%d dl:%d\n", __FILE__, __LINE__, buffer_size, dirrec->dirrec_length)); for(i = 0; i < buffer_size; ++i) { DEBUG((DEBUG_INFO, "r[%d]:%c", i, r[i])); } dirrec->dirrec_length = 0; return FSW_SUCCESS; } if (dirrec->dirrec_length < 33 || dirrec->dirrec_length < 33 + dirrec->file_identifier_length) return FSW_VOLUME_CORRUPTED; // DEBUG((DEBUG_INFO, "%a:%d, dirrec_length: %d\n", __FILE__, __LINE__, dirrec->dirrec_length)); // read variable size part of directory record buffer_size = remaining_size = dirrec->dirrec_length - 33; status = fsw_shandle_read(shand, &buffer_size, dirrec->file_identifier); if (status) return status; if (buffer_size < remaining_size) return FSW_VOLUME_CORRUPTED; // dump_dirrec(dirrec); if (vol->fRockRidge) { sp_off = sizeof(*dirrec) + dirrec->file_identifier_length; rc = rr_find_sp(dirrec, &sp); if ( rc == FSW_SUCCESS && sp != NULL) { sp_off = (fsw_u8 *)&sp[1] - (fsw_u8*)dirrec + sp->skip; } rc = rr_find_nm(vol, dirrec, sp_off, &dirrec_buffer->name); if (rc == FSW_SUCCESS) return FSW_SUCCESS; } // setup name name_len = dirrec->file_identifier_length; for (i = name_len - 1; i > 0; i--) { if (dirrec->file_identifier[i] == ';') { name_len = i; // cut the ISO9660 version number off break; } } if (name_len > 0 && dirrec->file_identifier[name_len-1] == '.') name_len--; // also cut the extension separator if the extension is empty dirrec_buffer->name.type = FSW_STRING_TYPE_ISO88591; dirrec_buffer->name.len = dirrec_buffer->name.size = name_len; dirrec_buffer->name.data = dirrec->file_identifier; // DEBUG((DEBUG_INFO, "%a:%d: dirrec_buffer->name.data:%a\n", __FILE__, __LINE__, dirrec_buffer->name.data)); return FSW_SUCCESS; } /** * Get the target path of a symbolic link. This function is called when a symbolic * link needs to be resolved. The core makes sure that the fsw_iso9660_dnode_fill has been * called on the dnode and that it really is a symlink. * * For iso9660, the target path can be stored inline in the inode structure (in the space * otherwise occupied by the block pointers) or in the inode's data. There is no flag * indicating this, only the number of blocks entry (i_blocks) can be used as an * indication. The check used here comes from the Linux kernel. */ static fsw_status_t fsw_iso9660_readlink(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno, struct fsw_string *link_target) { fsw_status_t status; if (dno->g.size > FSW_PATH_MAX) return FSW_VOLUME_CORRUPTED; status = fsw_dnode_readlink_data(dno, link_target); return status; } // EOF ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/edk2/���������������������������������������������������������������������0000775�0001750�0001750�00000000000�13106171410�016500� 5����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/edk2/DriverBinding.h������������������������������������������������������0000664�0001750�0001750�00000014406�13106171410�021404� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*++ Copyright (c) 2004, Intel Corporation. All rights reserved.<BR> This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. Module Name: DriverBinding.h Abstract: EFI ControllerHandle Driver Protocol Revision History --*/ /* * rEFInd NOTE: This file is included only when compiling with GNU-EFI, * which has not traditionally provided the definitions supplied here. * Unfortunately, recent (ca. 3.0.5) versions of GNU-EFI have added * SOME of these functions to an existing header file, creating problems * when trying to maintain compatibility with multiple GNU-EFI versions. * I've therefore renamed the relevant defines, types, and functions, * both here and in fsw_efi.c; and included a define to match the only * used name (REFIND_EFI_DRIVER_BINDING_PROTOCOL) to the traditional * name (EFI_DRIVER_BINDING_PROTOCOL) in fsw_efi.c for compiling with * TianoCore. */ #ifndef _EFI_DRIVER_BINDING_H_ #define _EFI_DRIVER_BINDING_H_ #include <efidevp.h> #define REFIND_EFI_DRIVER_BINDING_PROTOCOL_GUID \ { \ 0x18a031ab, 0xb443, 0x4d1a, {0xa5, 0xc0, 0xc, 0x9, 0x26, 0x1e, 0x9f, 0x71} \ } #define EFI_FORWARD_DECLARATION(x) typedef struct _##x x EFI_FORWARD_DECLARATION (REFIND_EFI_DRIVER_BINDING_PROTOCOL); // Begin included from DevicePath.h.... /// /// Device Path guid definition for backward-compatible with EFI1.1. /// //#define DEVICE_PATH_PROTOCOL EFI_DEVICE_PATH_PROTOCOL_GUID #pragma pack(1) /** This protocol can be used on any device handle to obtain generic path/location information concerning the physical device or logical device. If the handle does not logically map to a physical device, the handle may not necessarily support the device path protocol. The device path describes the location of the device the handle is for. The size of the Device Path can be determined from the structures that make up the Device Path. **/ typedef struct { UINT8 Type; ///< 0x01 Hardware Device Path. ///< 0x02 ACPI Device Path. ///< 0x03 Messaging Device Path. ///< 0x04 Media Device Path. ///< 0x05 BIOS Boot Specification Device Path. ///< 0x7F End of Hardware Device Path. UINT8 SubType; ///< Varies by Type ///< 0xFF End Entire Device Path, or ///< 0x01 End This Instance of a Device Path and start a new ///< Device Path. UINT8 Length[2]; ///< Specific Device Path data. Type and Sub-Type define ///< type of data. Size of data is included in Length. } REFIND_EFI_DEVICE_PATH_PROTOCOL; #pragma pack() // End included from DevicePath.h typedef EFI_STATUS (EFI_FUNCTION EFIAPI *EFI_DRIVER_BINDING_SUPPORTED) ( IN REFIND_EFI_DRIVER_BINDING_PROTOCOL * This, IN EFI_HANDLE ControllerHandle, IN REFIND_EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL ) /*++ Routine Description: Test to see if this driver supports ControllerHandle. Arguments: This - Protocol instance pointer. ControllerHandle - Handle of device to test RemainingDevicePath - Optional parameter use to pick a specific child device to start. Returns: EFI_SUCCESS - This driver supports this device EFI_ALREADY_STARTED - This driver is already running on this device other - This driver does not support this device --*/ ; typedef EFI_STATUS (EFI_FUNCTION EFIAPI *EFI_DRIVER_BINDING_START) ( IN REFIND_EFI_DRIVER_BINDING_PROTOCOL * This, IN EFI_HANDLE ControllerHandle, IN REFIND_EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL ) /*++ Routine Description: Start this driver on ControllerHandle. Arguments: This - Protocol instance pointer. ControllerHandle - Handle of device to bind driver to RemainingDevicePath - Optional parameter use to pick a specific child device to start. Returns: EFI_SUCCESS - This driver is added to ControllerHandle EFI_ALREADY_STARTED - This driver is already running on ControllerHandle other - This driver does not support this device --*/ ; typedef EFI_STATUS (EFI_FUNCTION EFIAPI *EFI_DRIVER_BINDING_STOP) ( IN REFIND_EFI_DRIVER_BINDING_PROTOCOL * This, IN EFI_HANDLE ControllerHandle, IN UINTN NumberOfChildren, IN EFI_HANDLE * ChildHandleBuffer ) /*++ Routine Description: Stop this driver on ControllerHandle. Arguments: This - Protocol instance pointer. ControllerHandle - Handle of device to stop driver on NumberOfChildren - Number of Handles in ChildHandleBuffer. If number of children is zero stop the entire bus driver. ChildHandleBuffer - List of Child Handles to Stop. Returns: EFI_SUCCESS - This driver is removed ControllerHandle other - This driver was not removed from this device --*/ ; // // Interface structure for the ControllerHandle Driver Protocol // struct _REFIND_EFI_DRIVER_BINDING_PROTOCOL { EFI_DRIVER_BINDING_SUPPORTED Supported; EFI_DRIVER_BINDING_START Start; EFI_DRIVER_BINDING_STOP Stop; UINT32 Version; EFI_HANDLE ImageHandle; EFI_HANDLE DriverBindingHandle; }; extern EFI_GUID gEfiDriverBindingProtocolGuid; #endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/edk2/ComponentName.h������������������������������������������������������0000664�0001750�0001750�00000015704�12775523233�021442� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/** @file EFI Component Name Protocol as defined in the EFI 1.1 specification. This protocol is used to retrieve user readable names of EFI Drivers and controllers managed by EFI Drivers. Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR> This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License that accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php. THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ /* * rEFInd NOTE: This file is included only when compiling with GNU-EFI, * which has not traditionally provided the definitions supplied here. * Unfortunately, recent (ca. 3.0.4) versions of GNU-EFI have added * SOME of these functions to an existing header file, creating problems * when trying to maintain compatibility with multiple GNU-EFI versions. * I've therefore renamed the relevant defines, types, and functions, * both here and in fsw_efi.c; and included a define to match the only * used name (REFIND_EFI_COMPONENT_NAME_PROTOCOL) to the traditional * name (EFI_COMPONENT_NAME_PROTOCOL) in fsw_efi.c for compiling with * TianoCore. */ #ifndef __REFIND_EFI_COMPONENT_NAME_H__ #define __REFIND_EFI_COMPONENT_NAME_H__ /// /// The global ID for the Component Name Protocol. /// #define REFIND_EFI_COMPONENT_NAME_PROTOCOL_GUID \ { \ 0x107a772c, 0xd5e1, 0x11d4, {0x9a, 0x46, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \ } typedef struct _REFIND_EFI_COMPONENT_NAME_PROTOCOL REFIND_EFI_COMPONENT_NAME_PROTOCOL; /** Retrieves a Unicode string that is the user-readable name of the EFI Driver. @param This A pointer to the REFIND_EFI_COMPONENT_NAME_PROTOCOL instance. @param Language A pointer to a three-character ISO 639-2 language identifier. This is the language of the driver name that that the caller is requesting, and it must match one of the languages specified in SupportedLanguages. The number of languages supported by a driver is up to the driver writer. @param DriverName A pointer to the Unicode string to return. This Unicode string is the name of the driver specified by This in the language specified by Language. @retval EFI_SUCCESS The Unicode string for the Driver specified by This and the language specified by Language was returned in DriverName. @retval EFI_INVALID_PARAMETER Language is NULL. @retval EFI_INVALID_PARAMETER DriverName is NULL. @retval EFI_UNSUPPORTED The driver specified by This does not support the language specified by Language. **/ typedef EFI_STATUS (EFI_FUNCTION EFIAPI *REFIND_EFI_COMPONENT_NAME_GET_DRIVER_NAME)( IN REFIND_EFI_COMPONENT_NAME_PROTOCOL *This, IN CHAR8 *Language, OUT CHAR16 **DriverName ); /** Retrieves a Unicode string that is the user readable name of the controller that is being managed by an EFI Driver. @param This A pointer to the REFIND_EFI_COMPONENT_NAME_PROTOCOL instance. @param ControllerHandle The handle of a controller that the driver specified by This is managing. This handle specifies the controller whose name is to be returned. @param ChildHandle The handle of the child controller to retrieve the name of. This is an optional parameter that may be NULL. It will be NULL for device drivers. It will also be NULL for a bus drivers that wish to retrieve the name of the bus controller. It will not be NULL for a bus driver that wishes to retrieve the name of a child controller. @param Language A pointer to a three character ISO 639-2 language identifier. This is the language of the controller name that the caller is requesting, and it must match one of the languages specified in SupportedLanguages. The number of languages supported by a driver is up to the driver writer. @param ControllerName A pointer to the Unicode string to return. This Unicode string is the name of the controller specified by ControllerHandle and ChildHandle in the language specified by Language, from the point of view of the driver specified by This. @retval EFI_SUCCESS The Unicode string for the user-readable name in the language specified by Language for the driver specified by This was returned in DriverName. @retval EFI_INVALID_PARAMETER ControllerHandle is NULL. @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid EFI_HANDLE. @retval EFI_INVALID_PARAMETER Language is NULL. @retval EFI_INVALID_PARAMETER ControllerName is NULL. @retval EFI_UNSUPPORTED The driver specified by This is not currently managing the controller specified by ControllerHandle and ChildHandle. @retval EFI_UNSUPPORTED The driver specified by This does not support the language specified by Language. **/ typedef EFI_STATUS (EFI_FUNCTION EFIAPI *REFIND_EFI_COMPONENT_NAME_GET_CONTROLLER_NAME)( IN REFIND_EFI_COMPONENT_NAME_PROTOCOL *This, IN EFI_HANDLE ControllerHandle, IN EFI_HANDLE ChildHandle OPTIONAL, IN CHAR8 *Language, OUT CHAR16 **ControllerName ); /// /// This protocol is used to retrieve user readable names of drivers /// and controllers managed by UEFI Drivers. /// struct _REFIND_EFI_COMPONENT_NAME_PROTOCOL { REFIND_EFI_COMPONENT_NAME_GET_DRIVER_NAME GetDriverName; REFIND_EFI_COMPONENT_NAME_GET_CONTROLLER_NAME GetControllerName; /// /// A Null-terminated ASCII string that contains one or more /// ISO 639-2 language codes. This is the list of language codes /// that this protocol supports. /// CHAR8 *SupportedLanguages; }; extern EFI_GUID gEfiComponentNameProtocolGuid; #endif ������������������������������������������������������������refind-0.11.4/filesystems/fsw_lib.c�����������������������������������������������������������������0000664�0001750�0001750�00000021310�12631614465�017457� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/** * \file fsw_lib.c * Core file system wrapper library functions. */ /*- * Copyright (c) 2006 Christoph Pfisterer * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * * Neither the name of Christoph Pfisterer nor the names of the * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "fsw_core.h" /* Include generated string encoding specific functions */ #include "fsw_strfunc.h" /** * Allocate memory and clear it. */ fsw_status_t fsw_alloc_zero(int len, void **ptr_out) { fsw_status_t status; status = fsw_alloc(len, ptr_out); if (status) return status; fsw_memzero(*ptr_out, len); return FSW_SUCCESS; } /** * Duplicate a piece of data. */ fsw_status_t fsw_memdup(void **dest_out, void *src, int len) { fsw_status_t status; status = fsw_alloc(len, dest_out); if (status) return status; fsw_memcpy(*dest_out, src, len); return FSW_SUCCESS; } /** * Get the length of a string. Returns the number of characters in the string. */ int fsw_strlen(struct fsw_string *s) { if (s->type == FSW_STRING_TYPE_EMPTY) return 0; return s->len; } /** * Compare two strings for equality. The two strings are compared, taking their * encoding into account. If they are considered equal, boolean true is returned. * Otherwise, boolean false is returned. */ int fsw_streq(struct fsw_string *s1, struct fsw_string *s2) { struct fsw_string temp_s; // handle empty strings if (s1->type == FSW_STRING_TYPE_EMPTY) { temp_s.type = FSW_STRING_TYPE_ISO88591; temp_s.size = temp_s.len = 0; temp_s.data = NULL; return fsw_streq(&temp_s, s2); } if (s2->type == FSW_STRING_TYPE_EMPTY) { temp_s.type = FSW_STRING_TYPE_ISO88591; temp_s.size = temp_s.len = 0; temp_s.data = NULL; return fsw_streq(s1, &temp_s); } // check length (count of chars) if (s1->len != s2->len) return 0; if (s1->len == 0) // both strings are empty return 1; if (s1->type == s2->type) { // same type, do a dumb memory compare if (s1->size != s2->size) return 0; return fsw_memeq(s1->data, s2->data, s1->size); } // dispatch to type-specific functions #define STREQ_DISPATCH(type1, type2) \ if (s1->type == FSW_STRING_TYPE_##type1 && s2->type == FSW_STRING_TYPE_##type2) \ return fsw_streq_##type1##_##type2(s1->data, s2->data, s1->len); \ if (s2->type == FSW_STRING_TYPE_##type1 && s1->type == FSW_STRING_TYPE_##type2) \ return fsw_streq_##type1##_##type2(s2->data, s1->data, s1->len); STREQ_DISPATCH(ISO88591, UTF8); STREQ_DISPATCH(ISO88591, UTF16); STREQ_DISPATCH(ISO88591, UTF16_SWAPPED); STREQ_DISPATCH(UTF8, UTF16); STREQ_DISPATCH(UTF8, UTF16_SWAPPED); STREQ_DISPATCH(UTF16, UTF16_SWAPPED); // final fallback return 0; } /** * Compare a string with a C string constant. This sets up a string descriptor * for the string constant (second argument) and runs fsw_streq on the two * strings. Currently the C string is interpreted as ISO 8859-1. * Returns boolean true if the strings are considered equal, boolean false otherwise. */ int fsw_streq_cstr(struct fsw_string *s1, const char *s2) { struct fsw_string temp_s; int i; for (i = 0; s2[i]; i++) ; temp_s.type = FSW_STRING_TYPE_ISO88591; temp_s.size = temp_s.len = i; temp_s.data = (char *)s2; return fsw_streq(s1, &temp_s); } /** * Creates a duplicate of a string, converting it to the given encoding during the copy. * If the function returns FSW_SUCCESS, the caller must free the string later with * fsw_strfree. */ fsw_status_t fsw_strdup_coerce(struct fsw_string *dest, int type, struct fsw_string *src) { fsw_status_t status; if (src->type == FSW_STRING_TYPE_EMPTY || src->len == 0) { dest->type = type; dest->size = dest->len = 0; dest->data = NULL; return FSW_SUCCESS; } if (src->type == type) { dest->type = type; dest->len = src->len; dest->size = src->size; status = fsw_alloc(dest->size, &dest->data); if (status) return status; fsw_memcpy(dest->data, src->data, dest->size); return FSW_SUCCESS; } // dispatch to type-specific functions #define STRCOERCE_DISPATCH(type1, type2) \ if (src->type == FSW_STRING_TYPE_##type1 && type == FSW_STRING_TYPE_##type2) \ return fsw_strcoerce_##type1##_##type2(src->data, src->len, dest); STRCOERCE_DISPATCH(UTF8, ISO88591); STRCOERCE_DISPATCH(UTF16, ISO88591); STRCOERCE_DISPATCH(UTF16_SWAPPED, ISO88591); STRCOERCE_DISPATCH(ISO88591, UTF8); STRCOERCE_DISPATCH(UTF16, UTF8); STRCOERCE_DISPATCH(UTF16_SWAPPED, UTF8); STRCOERCE_DISPATCH(ISO88591, UTF16); STRCOERCE_DISPATCH(UTF8, UTF16); STRCOERCE_DISPATCH(UTF16_SWAPPED, UTF16); return FSW_UNSUPPORTED; } /** * Splits a string at the first occurence of the separator character. * The buffer string is searched for the separator character. If it is found, the * element string descriptor is filled to point at the part of the buffer string * before the separator. The buffer string itself is adjusted to point at the * remaining part of the string (without the separator). * * If the separator is not found in the buffer string, then element is changed to * point at the whole buffer string, and the buffer string itself is changed into * an empty string. * * This function only manipulates the pointers and lengths in the two string descriptors, * it does not change the actual string. If the buffer string is dynamically allocated, * you must make a copy of it so that you can release it later. */ void fsw_strsplit(struct fsw_string *element, struct fsw_string *buffer, char separator) { int i, maxlen; if (buffer->type == FSW_STRING_TYPE_EMPTY || buffer->len == 0) { element->type = FSW_STRING_TYPE_EMPTY; return; } maxlen = buffer->len; *element = *buffer; if (buffer->type == FSW_STRING_TYPE_ISO88591) { fsw_u8 *p; p = (fsw_u8 *)element->data; for (i = 0; i < maxlen; i++, p++) { if (*p == separator) { buffer->data = p + 1; buffer->len -= i + 1; break; } } element->len = i; if (i == maxlen) { buffer->data = p; buffer->len -= i; } element->size = element->len; buffer->size = buffer->len; } else if (buffer->type == FSW_STRING_TYPE_UTF16) { fsw_u16 *p; p = (fsw_u16 *)element->data; for (i = 0; i < maxlen; i++, p++) { if (*p == separator) { buffer->data = p + 1; buffer->len -= i + 1; break; } } element->len = i; if (i == maxlen) { buffer->data = p; buffer->len -= i; } element->size = element->len * sizeof(fsw_u16); buffer->size = buffer->len * sizeof(fsw_u16); } else { // fallback buffer->type = FSW_STRING_TYPE_EMPTY; } // TODO: support UTF8 and UTF16_SWAPPED } /** * Frees the memory used by a string returned from fsw_strdup_coerce. */ void fsw_strfree(struct fsw_string *s) { if (s->type != FSW_STRING_TYPE_EMPTY && s->data) fsw_free(s->data); s->type = FSW_STRING_TYPE_EMPTY; } // EOF ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/AutoGen.c�����������������������������������������������������������������0000664�0001750�0001750�00000031530�13074521006�017367� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/** DO NOT EDIT FILE auto-generated Module name: AutoGen.c Abstract: Auto-generated AutoGen.c for building module or library. **/ #include <Uefi.h> #include <Library/BaseLib.h> #include <Library/DebugLib.h> #include <Library/UefiBootServicesTableLib.h> #include <Library/UefiDriverEntryPoint.h> #include "AutoGen.h" // Guids GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiFileInfoGuid = { 0x09576E92, 0x6D3F, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiFileSystemInfoGuid = { 0x09576E93, 0x6D3F, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiFileSystemVolumeLabelInfoIdGuid = { 0xDB47D7D3, 0xFE81, 0x11D3, { 0x9A, 0x35, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiMdePkgTokenSpaceGuid = { 0x914AEBE7, 0x4635, 0x459b, { 0xAA, 0x1C, 0x11, 0xE2, 0x19, 0xB0, 0x3A, 0x10 }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiEventReadyToBootGuid = { 0x7CE88FB3, 0x4BD7, 0x4679, { 0x87, 0xA8, 0xA8, 0xD8, 0xDE, 0xE5, 0x0D, 0x2B }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiEventLegacyBootGuid = { 0x2A571201, 0x4966, 0x47F6, { 0x8B, 0x86, 0xF3, 0x1E, 0x41, 0xF3, 0x2F, 0x10 }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiGlobalVariableGuid = { 0x8BE4DF61, 0x93CA, 0x11D2, { 0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C }}; // Protocols GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDiskIoProtocolGuid = { 0xCE345171, 0xBA0B, 0x11D2, { 0x8E, 0x4F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiBlockIoProtocolGuid = { 0x964E5B21, 0x6459, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSimpleFileSystemProtocolGuid = { 0x964E5B22, 0x6459, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiUnicodeCollationProtocolGuid = { 0x1D85CD7F, 0xF43D, 0x11D2, { 0x9A, 0x0C, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiUnicodeCollation2ProtocolGuid = {0xa4c751fc, 0x23ae, 0x4c3e, { 0x92, 0xe9, 0x49, 0x64, 0xcf, 0x63, 0xf3, 0x49 }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gMsgLogProtocolGuid = {0x511CE018, 0x0018, 0x4002, {0x20, 0x12, 0x17, 0x38, 0x05, 0x01, 0x02, 0x03 }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDevicePathProtocolGuid = { 0x09576E91, 0x6D3F, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverBindingProtocolGuid = { 0x18A031AB, 0xB443, 0x4D1A, { 0xA5, 0xC0, 0x0C, 0x09, 0x26, 0x1E, 0x9F, 0x71 }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSimpleTextOutProtocolGuid = { 0x387477C2, 0x69C7, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiGraphicsOutputProtocolGuid = { 0x9042A9DE, 0x23DC, 0x4A38, { 0x96, 0xFB, 0x7A, 0xDE, 0xD0, 0x80, 0x51, 0x6A }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiHiiFontProtocolGuid = {0xe9ca4775, 0x8657, 0x47fc, {0x97, 0xe7, 0x7e, 0xd6, 0x5a, 0x08, 0x43, 0x24}}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiUgaDrawProtocolGuid = { 0x982C298B, 0xF4FA, 0x41CB, { 0xB8, 0x38, 0x77, 0xAA, 0x68, 0x8F, 0xB8, 0x39 }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiComponentNameProtocolGuid = { 0x107A772C, 0xD5E1, 0x11D4, { 0x9A, 0x46, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiComponentName2ProtocolGuid = { 0x6A7A5CFF, 0xE8D9, 0x4F70, { 0xBA, 0xDA, 0x75, 0xAB, 0x30, 0x25, 0xCE, 0x14 }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverConfigurationProtocolGuid = { 0x107A772B, 0xD5E1, 0x11D4, { 0x9A, 0x46, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverConfiguration2ProtocolGuid = { 0xBFD7DC1D, 0x24F1, 0x40D9, { 0x82, 0xE7, 0x2E, 0x09, 0xBB, 0x6B, 0x4E, 0xBE }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverDiagnosticsProtocolGuid = { 0x0784924F, 0xE296, 0x11D4, { 0x9A, 0x49, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverDiagnostics2ProtocolGuid = { 0x4D330321, 0x025F, 0x4AAC, { 0x90, 0xD8, 0x5E, 0xD9, 0x00, 0x17, 0x3B, 0x63 }}; GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiLoadedImageProtocolGuid = { 0x5B1B31A1, 0x9562, 0x11D2, { 0x8E, 0x3F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; // Definition of PCDs used in this module GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdUefiVariableDefaultLang[5] = {101, 110, 103, 0 }; GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdUefiVariableDefaultPlatformLang[7] = {101, 110, 45, 85, 83, 0 }; // Definition of PCDs used in libraries #define _PCD_TOKEN_PcdDebugPrintErrorLevel 5U #define _PCD_VALUE_PcdDebugPrintErrorLevel 0x80000000U GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdDebugPrintErrorLevel = _PCD_VALUE_PcdDebugPrintErrorLevel; extern const UINT32 _gPcd_FixedAtBuild_PcdDebugPrintErrorLevel; #define _PCD_GET_MODE_32_PcdDebugPrintErrorLevel _gPcd_FixedAtBuild_PcdDebugPrintErrorLevel //#define _PCD_SET_MODE_32_PcdDebugPrintErrorLevel ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD #define _PCD_TOKEN_PcdDebugClearMemoryValue 10U #define _PCD_VALUE_PcdDebugClearMemoryValue 0xAFU GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdDebugClearMemoryValue = _PCD_VALUE_PcdDebugClearMemoryValue; extern const UINT8 _gPcd_FixedAtBuild_PcdDebugClearMemoryValue; #define _PCD_GET_MODE_8_PcdDebugClearMemoryValue _gPcd_FixedAtBuild_PcdDebugClearMemoryValue //#define _PCD_SET_MODE_8_PcdDebugClearMemoryValue ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD #define _PCD_TOKEN_PcdDebugPropertyMask 11U #define _PCD_VALUE_PcdDebugPropertyMask 0x0fU GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdDebugPropertyMask = _PCD_VALUE_PcdDebugPropertyMask; extern const UINT8 _gPcd_FixedAtBuild_PcdDebugPropertyMask; #define _PCD_GET_MODE_8_PcdDebugPropertyMask _gPcd_FixedAtBuild_PcdDebugPropertyMask //#define _PCD_SET_MODE_8_PcdDebugPropertyMask ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD #define _PCD_TOKEN_PcdMaximumLinkedListLength 6U #define _PCD_VALUE_PcdMaximumLinkedListLength 1000000U GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdMaximumLinkedListLength = _PCD_VALUE_PcdMaximumLinkedListLength; extern const UINT32 _gPcd_FixedAtBuild_PcdMaximumLinkedListLength; #define _PCD_GET_MODE_32_PcdMaximumLinkedListLength _gPcd_FixedAtBuild_PcdMaximumLinkedListLength //#define _PCD_SET_MODE_32_PcdMaximumLinkedListLength ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD #define _PCD_TOKEN_PcdMaximumAsciiStringLength 7U #define _PCD_VALUE_PcdMaximumAsciiStringLength 1000000U GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdMaximumAsciiStringLength = _PCD_VALUE_PcdMaximumAsciiStringLength; extern const UINT32 _gPcd_FixedAtBuild_PcdMaximumAsciiStringLength; #define _PCD_GET_MODE_32_PcdMaximumAsciiStringLength _gPcd_FixedAtBuild_PcdMaximumAsciiStringLength //#define _PCD_SET_MODE_32_PcdMaximumAsciiStringLength ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD #define _PCD_TOKEN_PcdMaximumUnicodeStringLength 8U #define _PCD_VALUE_PcdMaximumUnicodeStringLength 1000000U GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdMaximumUnicodeStringLength = _PCD_VALUE_PcdMaximumUnicodeStringLength; extern const UINT32 _gPcd_FixedAtBuild_PcdMaximumUnicodeStringLength; #define _PCD_GET_MODE_32_PcdMaximumUnicodeStringLength _gPcd_FixedAtBuild_PcdMaximumUnicodeStringLength //#define _PCD_SET_MODE_32_PcdMaximumUnicodeStringLength ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD #define _PCD_TOKEN_PcdVerifyNodeInList 9U #define _PCD_VALUE_PcdVerifyNodeInList ((BOOLEAN)0U) GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdVerifyNodeInList = _PCD_VALUE_PcdVerifyNodeInList; extern const BOOLEAN _gPcd_FixedAtBuild_PcdVerifyNodeInList; #define _PCD_GET_MODE_BOOL_PcdVerifyNodeInList _gPcd_FixedAtBuild_PcdVerifyNodeInList //#define _PCD_SET_MODE_BOOL_PcdVerifyNodeInList ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD #define _PCD_TOKEN_PcdDriverDiagnosticsDisable 12U #define _PCD_VALUE_PcdDriverDiagnosticsDisable ((BOOLEAN)0U) GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdDriverDiagnosticsDisable = _PCD_VALUE_PcdDriverDiagnosticsDisable; extern const BOOLEAN _gPcd_FixedAtBuild_PcdDriverDiagnosticsDisable; #define _PCD_GET_MODE_BOOL_PcdDriverDiagnosticsDisable _gPcd_FixedAtBuild_PcdDriverDiagnosticsDisable //#define _PCD_SET_MODE_BOOL_PcdDriverDiagnosticsDisable ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD #define _PCD_TOKEN_PcdComponentNameDisable 13U #define _PCD_VALUE_PcdComponentNameDisable ((BOOLEAN)0U) GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdComponentNameDisable = _PCD_VALUE_PcdComponentNameDisable; extern const BOOLEAN _gPcd_FixedAtBuild_PcdComponentNameDisable; #define _PCD_GET_MODE_BOOL_PcdComponentNameDisable _gPcd_FixedAtBuild_PcdComponentNameDisable //#define _PCD_SET_MODE_BOOL_PcdComponentNameDisable ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD #define _PCD_TOKEN_PcdDriverDiagnostics2Disable 14U #define _PCD_VALUE_PcdDriverDiagnostics2Disable ((BOOLEAN)1U) GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdDriverDiagnostics2Disable = _PCD_VALUE_PcdDriverDiagnostics2Disable; extern const BOOLEAN _gPcd_FixedAtBuild_PcdDriverDiagnostics2Disable; #define _PCD_GET_MODE_BOOL_PcdDriverDiagnostics2Disable _gPcd_FixedAtBuild_PcdDriverDiagnostics2Disable //#define _PCD_SET_MODE_BOOL_PcdDriverDiagnostics2Disable ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD #define _PCD_TOKEN_PcdComponentName2Disable 15U #define _PCD_VALUE_PcdComponentName2Disable ((BOOLEAN)1U) GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdComponentName2Disable = _PCD_VALUE_PcdComponentName2Disable; extern const BOOLEAN _gPcd_FixedAtBuild_PcdComponentName2Disable; #define _PCD_GET_MODE_BOOL_PcdComponentName2Disable _gPcd_FixedAtBuild_PcdComponentName2Disable //#define _PCD_SET_MODE_BOOL_PcdComponentName2Disable ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD #define _PCD_TOKEN_PcdUgaConsumeSupport 16U #define _PCD_VALUE_PcdUgaConsumeSupport ((BOOLEAN)1U) GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdUgaConsumeSupport = _PCD_VALUE_PcdUgaConsumeSupport; extern const BOOLEAN _gPcd_FixedAtBuild_PcdUgaConsumeSupport; #define _PCD_GET_MODE_BOOL_PcdUgaConsumeSupport _gPcd_FixedAtBuild_PcdUgaConsumeSupport //#define _PCD_SET_MODE_BOOL_PcdUgaConsumeSupport ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD #define _PCD_TOKEN_PcdUefiLibMaxPrintBufferSize 17U #define _PCD_VALUE_PcdUefiLibMaxPrintBufferSize 320U GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdUefiLibMaxPrintBufferSize = _PCD_VALUE_PcdUefiLibMaxPrintBufferSize; extern const UINT32 _gPcd_FixedAtBuild_PcdUefiLibMaxPrintBufferSize; #define _PCD_GET_MODE_32_PcdUefiLibMaxPrintBufferSize _gPcd_FixedAtBuild_PcdUefiLibMaxPrintBufferSize //#define _PCD_SET_MODE_32_PcdUefiLibMaxPrintBufferSize ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD EFI_STATUS EFIAPI UefiBootServicesTableLibConstructor ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ); EFI_STATUS EFIAPI UefiRuntimeServicesTableLibConstructor ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ); EFI_STATUS EFIAPI UefiLibConstructor ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ); VOID EFIAPI ProcessLibraryConstructorList ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; Status = UefiBootServicesTableLibConstructor (ImageHandle, SystemTable); ASSERT_EFI_ERROR (Status); Status = UefiRuntimeServicesTableLibConstructor (ImageHandle, SystemTable); ASSERT_EFI_ERROR (Status); Status = UefiLibConstructor (ImageHandle, SystemTable); ASSERT_EFI_ERROR (Status); } VOID EFIAPI ProcessLibraryDestructorList ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { } //const UINT32 _gUefiDriverRevision = 0x00020000U; const UINT32 _gUefiDriverRevision = 0x00010000U; const UINT32 _gDxeRevision = 0x00000000U; EFI_STATUS EFIAPI ProcessModuleEntryPointList ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { return fsw_efi_main (ImageHandle, SystemTable); } VOID EFIAPI ExitDriver ( IN EFI_STATUS Status ) { if (EFI_ERROR (Status)) { ProcessLibraryDestructorList (gImageHandle, gST); } gBS->Exit (gImageHandle, Status, 0, NULL); } GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gDriverUnloadImageCount = 0U; EFI_STATUS EFIAPI ProcessModuleUnloadList ( IN EFI_HANDLE ImageHandle ) { return EFI_SUCCESS; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/Make.gnuefi���������������������������������������������������������������0000664�0001750�0001750�00000002437�12631122762�017745� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # filesystems/Make.gnuefi # Build control file for the EFI drivers, as built with GNU-EFI # # This program is licensed under the terms of the GNU GPL, version 3, # or (at your option) any later version. # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. SRCDIR = . VPATH = $(SRCDIR) HOSTARCH = $(shell uname -m | sed s,i[3456789]86,ia32,) LOCAL_GNUEFI_CFLAGS = -DFSTYPE=$(DRIVERNAME) -I$(SRCDIR) ifeq ($(HOSTARCH),x86_64) LOCAL_GNUEFI_CFLAGS += "-DEFIAPI=__attribute__((ms_abi))" endif OBJS = fsw_core.o fsw_efi.o fsw_efi_lib.o fsw_lib.o fsw_$(DRIVERNAME).o TARGET = $(DRIVERNAME)_$(FILENAME_CODE).efi include $(SRCDIR)/../Make.common all: $(TARGET) ifeq ($(HOSTARCH),aarch64) # Set symbol for driver SUBSYSTEM_LDFLAG = -defsym=EFI_SUBSYSTEM=0xb endif $(SHLIB_TARGET): $(OBJS) $(LD) $(GNUEFI_LDFLAGS) $(SUBSYSTEM_LDFLAG) $(OBJS) -o $@ $(LOCAL_LIBS) $(GNUEFI_LIBS) $(TARGET): $(SHLIB_TARGET) $(OBJCOPY) -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel \ -j .rela -j .rel.* -j .rela.* -j .rel* -j .rela* \ -j .reloc $(FORMAT_DRIVER) $< $@ chmod a-x $(TARGET) mkdir -p ../drivers_$(FILENAME_CODE) cp $(TARGET) ../drivers_$(FILENAME_CODE) # EOF ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/iso9660.inf���������������������������������������������������������������0000664�0001750�0001750�00000003712�13112553147�017503� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������## @file # # iso9660.inf file to build rEFInd's ISO-9660 driver using the EDK2/UDK201# # development kit. # # Copyright (c) 2012-2017 by Roderick W. Smith # Released under the terms of the GPLv3 (or, at your discretion, any later # version), a copy of which should come with this file. # ## [Defines] INF_VERSION = 0x00010005 BASE_NAME = iso9660 FILE_GUID = ff0c069a-8544-4535-b3c7-61fa106ab88d MODULE_TYPE = UEFI_DRIVER EDK_RELEASE_VERSION = 0x00020000 EFI_SPECIFICATION_VERSION = 0x00010000 VERSION_STRING = 1.0 ENTRY_POINT = fsw_efi_main FSTYPE = iso9660 # # The following information is for reference only and not required by the build tools. # # VALID_ARCHITECTURES = IA32 X64 IPF EBC # [Sources] fsw_efi.c fsw_iso9660.c fsw_core.c fsw_efi.c fsw_lib.c fsw_efi_lib.c [Packages] MdePkg/MdePkg.dec MdeModulePkg/MdeModulePkg.dec IntelFrameworkPkg/IntelFrameworkPkg.dec IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec [LibraryClasses] UefiDriverEntryPoint DxeServicesLib DxeServicesTableLib MemoryAllocationLib [LibraryClasses.AARCH64] BaseStackCheckLib # Comment out CompilerIntrinsicsLib when compiling for AARCH64 using UDK2014 CompilerIntrinsicsLib [Guids] [Ppis] [Protocols] [FeaturePcd] [Pcd] [BuildOptions.IA32] XCODE:*_*_*_CC_FLAGS = -Os -DEFI32 -D__MAKEWITH_TIANO -DFSTYPE=iso9660 GCC:*_*_*_CC_FLAGS = -Os -DEFI32 -D__MAKEWITH_TIANO -DFSTYPE=iso9660 [BuildOptions.X64] XCODE:*_*_*_CC_FLAGS = -Os -DEFIX64 -D__MAKEWITH_TIANO -DFSTYPE=iso9660 GCC:*_*_*_CC_FLAGS = -Os -DEFIX64 -D__MAKEWITH_TIANO -DFSTYPE=iso9660 [BuildOptions.AARCH64] XCODE:*_*_*_CC_FLAGS = -Os -DEFIAARCH64 -D__MAKEWITH_TIANO -DFSTYPE=iso9660 GCC:*_*_*_CC_FLAGS = -Os -DEFIAARCH64 -D__MAKEWITH_TIANO -DFSTYPE=iso9660 ������������������������������������������������������refind-0.11.4/filesystems/LICENSE_GPL.txt�����������������������������������������������������������0000664�0001750�0001750�00000043110�12626644770�020223� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. <one line to give the program's name and a brief idea of what it does.> Copyright (C) <year> <name of author> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. <signature of Ty Coon>, 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/fsw_core.c����������������������������������������������������������������0000664�0001750�0001750�00000100353�13363351412�017637� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Id: fsw_core.c 29125 2010-05-06 09:43:05Z vboxsync $ */ /** @file * fsw_core.c - Core file system wrapper abstraction layer code. */ /*- * This code is based on: * * Copyright (c) 2006 Christoph Pfisterer * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * * Neither the name of Christoph Pfisterer nor the names of the * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "fsw_core.h" #include "fsw_efi.h" // functions static void fsw_blockcache_free(struct fsw_volume *vol); #define MAX_CACHE_LEVEL (5) /** * Mount a volume with a given file system driver. This function is called by the * host driver to make a volume accessible. The file system driver to use is specified * by a pointer to its dispatch table. The file system driver will look at the * data on the volume to determine if it can read the format. If the volume is found * unsuitable, FSW_UNSUPPORTED is returned. * * If this function returns FSW_SUCCESS, *vol_out points at a valid volume data * structure. The caller must release it later by calling fsw_unmount. * * If this function returns an error status, the caller only needs to clean up its * own buffers that may have been allocated through the read_block interface. */ fsw_status_t fsw_mount(void *host_data, struct fsw_host_table *host_table, struct fsw_fstype_table *fstype_table, struct fsw_volume **vol_out) { fsw_status_t status; struct fsw_volume *vol; // allocate memory for the structure status = fsw_alloc_zero(fstype_table->volume_struct_size, (void **)&vol); if (status) return status; // initialize fields vol->phys_blocksize = 512; vol->log_blocksize = 512; vol->label.type = FSW_STRING_TYPE_EMPTY; vol->host_data = host_data; vol->host_table = host_table; vol->fstype_table = fstype_table; vol->host_string_type = host_table->native_string_type; // let the fs driver mount the file system status = vol->fstype_table->volume_mount(vol); if (status) goto errorexit; // TODO: anything else? *vol_out = vol; return FSW_SUCCESS; errorexit: fsw_unmount(vol); return status; } /** * Unmount a volume by releasing all memory associated with it. This function is * called by the host driver when a volume is no longer needed. It is also called * by the core after a failed mount to clean up any allocated memory. * * Note that all dnodes must have been released before calling this function. */ void fsw_unmount(struct fsw_volume *vol) { if (vol->root) fsw_dnode_release(vol->root); // TODO: check that no other dnodes are still around vol->fstype_table->volume_free(vol); fsw_blockcache_free(vol); fsw_strfree(&vol->label); fsw_free(vol); } /** * Get in-depth information on the volume. This function can be called by the host * driver to get additional information on the volume. */ fsw_status_t fsw_volume_stat(struct fsw_volume *vol, struct fsw_volume_stat *sb) { return vol->fstype_table->volume_stat(vol, sb); } /** * Set the physical and logical block sizes of the volume. This functions is called by * the file system driver to announce the block sizes it wants to use for accessing * the disk (physical) and for addressing file contents (logical). * Usually both sizes will be the same but there may be file systems that need to access * metadata at a smaller block size than the allocation unit for files. * * Calling this function causes the block cache to be dropped. All pointers returned * from fsw_block_get become invalid. This function should only be called while * mounting the file system, not as a part of file access operations. * * Both sizes are measured in bytes, must be powers of 2, and must not be smaller * than 512 bytes. The logical block size cannot be smaller than the physical block size. */ void fsw_set_blocksize(struct fsw_volume *vol, fsw_u32 phys_blocksize, fsw_u32 log_blocksize) { // TODO: Check the sizes. Both must be powers of 2. log_blocksize must not be smaller than // phys_blocksize. // drop core block cache if present fsw_blockcache_free(vol); // signal host driver to drop caches etc. vol->host_table->change_blocksize(vol, vol->phys_blocksize, vol->log_blocksize, phys_blocksize, log_blocksize); vol->phys_blocksize = phys_blocksize; vol->log_blocksize = log_blocksize; } /** * Get a block of data from the disk. This function is called by the file system driver * or by core functions. It calls through to the host driver's device access routine. * Given a physical block number, it reads the block into memory (or fetches it from the * block cache) and returns the address of the memory buffer. The caller should provide * an indication of how important the block is in the cache_level parameter. Blocks with * a low level are purged first. Some suggestions for cache levels: * * - 0: File data * - 1: Directory data, symlink data * - 2: File system metadata * - 3..5: File system metadata with a high rate of access * * If this function returns successfully, the returned data pointer is valid until the * caller calls fsw_block_release. */ fsw_status_t fsw_block_get(struct VOLSTRUCTNAME *vol, fsw_u64 phys_bno, fsw_u32 cache_level, void **buffer_out) { fsw_status_t status; fsw_u32 i, discard_level, new_bcache_size; struct fsw_blockcache *new_bcache; // TODO: allow the host driver to do its own caching; just call through if // the appropriate function pointers are set if (cache_level > MAX_CACHE_LEVEL) cache_level = MAX_CACHE_LEVEL; // check block cache for (i = 0; i < vol->bcache_size; i++) { if (vol->bcache[i].phys_bno == phys_bno) { // cache hit! if (vol->bcache[i].cache_level < cache_level) vol->bcache[i].cache_level = cache_level; // promote the entry vol->bcache[i].refcount++; *buffer_out = vol->bcache[i].data; return FSW_SUCCESS; } } // find a free entry in the cache table for (i = 0; i < vol->bcache_size; i++) { if (vol->bcache[i].phys_bno == (fsw_u64)FSW_INVALID_BNO) break; } if (i >= vol->bcache_size) { for (discard_level = 0; discard_level <= MAX_CACHE_LEVEL; discard_level++) { for (i = 0; i < vol->bcache_size; i++) { if (vol->bcache[i].refcount == 0 && vol->bcache[i].cache_level <= discard_level) break; } if (i < vol->bcache_size) break; } } if (i >= vol->bcache_size) { // enlarge / create the cache if (vol->bcache_size < 16) new_bcache_size = 16; else new_bcache_size = vol->bcache_size << 1; status = fsw_alloc(new_bcache_size * sizeof(struct fsw_blockcache), &new_bcache); if (status) return status; if (vol->bcache_size > 0) fsw_memcpy(new_bcache, vol->bcache, vol->bcache_size * sizeof(struct fsw_blockcache)); for (i = vol->bcache_size; i < new_bcache_size; i++) { new_bcache[i].refcount = 0; new_bcache[i].cache_level = 0; new_bcache[i].phys_bno = (fsw_u64)FSW_INVALID_BNO; new_bcache[i].data = NULL; } i = vol->bcache_size; // switch caches if (vol->bcache != NULL) fsw_free(vol->bcache); vol->bcache = new_bcache; vol->bcache_size = new_bcache_size; } vol->bcache[i].phys_bno = (fsw_u64)FSW_INVALID_BNO; // read the data if (vol->bcache[i].data == NULL) { status = fsw_alloc(vol->phys_blocksize, &vol->bcache[i].data); if (status) return status; } status = vol->host_table->read_block(vol, phys_bno, vol->bcache[i].data); if (status) return status; vol->bcache[i].phys_bno = phys_bno; vol->bcache[i].cache_level = cache_level; vol->bcache[i].refcount = 1; *buffer_out = vol->bcache[i].data; return FSW_SUCCESS; } /** * Releases a disk block. This function must be called to release disk blocks returned * from fsw_block_get. */ void fsw_block_release(struct VOLSTRUCTNAME *vol, fsw_u64 phys_bno, void *buffer) { fsw_u32 i; // TODO: allow the host driver to do its own caching; just call through if // the appropriate function pointers are set // update block cache for (i = 0; i < vol->bcache_size; i++) { if (vol->bcache[i].phys_bno == phys_bno && vol->bcache[i].refcount > 0) vol->bcache[i].refcount--; } } /** * Release the block cache. Called internally when changing block sizes and when * unmounting the volume. It frees all data occupied by the generic block cache. */ static void fsw_blockcache_free(struct fsw_volume *vol) { fsw_u32 i; for (i = 0; i < vol->bcache_size; i++) { if (vol->bcache[i].data != NULL) fsw_free(vol->bcache[i].data); } if (vol->bcache != NULL) { fsw_free(vol->bcache); vol->bcache = NULL; } vol->bcache_size = 0; fsw_efi_clear_cache(); } /** * Add a new dnode to the list of known dnodes. This internal function is used when a * dnode is created to add it to the dnode list that is used to search for existing * dnodes by id. */ static void fsw_dnode_register(struct fsw_volume *vol, struct fsw_dnode *dno) { dno->next = vol->dnode_head; if (vol->dnode_head != NULL) vol->dnode_head->prev = dno; dno->prev = NULL; vol->dnode_head = dno; } /** * Create a dnode representing the root directory. This function is called by the file system * driver while mounting the file system. The root directory is special because it has no parent * dnode, its name is defined to be empty, and its type is also fixed. Otherwise, this functions * behaves in the same way as fsw_dnode_create. */ fsw_status_t fsw_dnode_create_root_with_tree(struct fsw_volume *vol, fsw_u64 tree_id, fsw_u64 dnode_id, struct fsw_dnode **dno_out) { fsw_status_t status; struct fsw_dnode *dno; // allocate memory for the structure status = fsw_alloc_zero(vol->fstype_table->dnode_struct_size, (void **)&dno); if (status) return status; // fill the structure dno->vol = vol; dno->parent = NULL; dno->tree_id = tree_id; dno->dnode_id = dnode_id; dno->type = FSW_DNODE_TYPE_DIR; dno->refcount = 1; dno->name.type = FSW_STRING_TYPE_EMPTY; // TODO: instead, call a function to create an empty string in the native string type fsw_dnode_register(vol, dno); *dno_out = dno; return FSW_SUCCESS; } fsw_status_t fsw_dnode_create_root(struct fsw_volume *vol, fsw_u64 dnode_id, struct fsw_dnode **dno_out) { return fsw_dnode_create_root_with_tree( vol, 0, dnode_id, dno_out); } /** * Create a new dnode representing a file system object. This function is called by * the file system driver in response to directory lookup or read requests. Note that * if there already is a dnode with the given dnode_id on record, then no new object * is created. Instead, the existing dnode is returned and its reference count * increased. All other parameters are ignored in this case. * * The type passed into this function may be FSW_DNODE_TYPE_UNKNOWN. It is sufficient * to fill the type field during the dnode_fill call. * * The name parameter must describe a string with the object's name. A copy will be * stored in the dnode structure for future reference. The name will not be used to * shortcut directory lookups, but may be used to reconstruct paths. * * If the function returns successfully, *dno_out contains a pointer to the dnode * that must be released by the caller with fsw_dnode_release. */ fsw_status_t fsw_dnode_create_with_tree(struct fsw_dnode *parent_dno, fsw_u64 tree_id, fsw_u64 dnode_id, int type, struct fsw_string *name, struct fsw_dnode **dno_out) { fsw_status_t status; struct fsw_volume *vol = parent_dno->vol; struct fsw_dnode *dno; // check if we already have a dnode with the same id for (dno = vol->dnode_head; dno; dno = dno->next) { if (dno->dnode_id == dnode_id && dno->tree_id == tree_id) { fsw_dnode_retain(dno); *dno_out = dno; return FSW_SUCCESS; } } // allocate memory for the structure status = fsw_alloc_zero(vol->fstype_table->dnode_struct_size, (void **)&dno); if (status) return status; // fill the structure dno->vol = vol; dno->parent = parent_dno; fsw_dnode_retain(dno->parent); dno->tree_id = tree_id; dno->dnode_id = dnode_id; dno->type = type; dno->refcount = 1; status = fsw_strdup_coerce(&dno->name, vol->host_table->native_string_type, name); if (status) { fsw_free(dno); return status; } fsw_dnode_register(vol, dno); *dno_out = dno; return FSW_SUCCESS; } fsw_status_t fsw_dnode_create(struct fsw_dnode *parent_dno, fsw_u64 dnode_id, int type, struct fsw_string *name, struct fsw_dnode **dno_out) { return fsw_dnode_create_with_tree(parent_dno, 0, dnode_id, type, name, dno_out); } /** * Increases the reference count of a dnode. This must be balanced with * fsw_dnode_release calls. Note that some dnode functions return a retained * dnode pointer to their caller. */ void fsw_dnode_retain(struct fsw_dnode *dno) { dno->refcount++; } /** * Release a dnode pointer, deallocating it if this was the last reference. * This function decrements the reference counter of the dnode. If the counter * reaches zero, the dnode is freed. Since the parent dnode is released * during that process, this function may cause it to be freed, too. */ void fsw_dnode_release(struct fsw_dnode *dno) { struct fsw_volume *vol = dno->vol; struct fsw_dnode *parent_dno; dno->refcount--; if (dno->refcount == 0) { parent_dno = dno->parent; // de-register from volume's list if (dno->next) dno->next->prev = dno->prev; if (dno->prev) dno->prev->next = dno->next; if (vol->dnode_head == dno) vol->dnode_head = dno->next; // run fstype-specific cleanup vol->fstype_table->dnode_free(vol, dno); fsw_strfree(&dno->name); fsw_free(dno); // release our pointer to the parent, possibly deallocating it, too if (parent_dno) fsw_dnode_release(parent_dno); } } /** * Get full information about a dnode from disk. This function is called by the host * driver as well as by the core functions. Some file systems defer reading full * information on a dnode until it is actually needed (i.e. separation between * directory and inode information). This function makes sure that all information * is available in the dnode structure. The following fields may not have a correct * value until fsw_dnode_fill has been called: * * type, size */ fsw_status_t fsw_dnode_fill(struct fsw_dnode *dno) { // TODO: check a flag right here, call fstype's dnode_fill only once per dnode return dno->vol->fstype_table->dnode_fill(dno->vol, dno); } /** * Get extended information about a dnode. This function can be called by the host * driver to get a full compliment of information about a dnode in addition to the * fields of the fsw_dnode structure itself. * * Some data requires host-specific conversion to be useful (i.e. timestamps) and * will be passed to callback functions instead of being written into the structure. * These callbacks must be filled in by the caller. */ fsw_status_t fsw_dnode_stat(struct fsw_dnode *dno, struct fsw_dnode_stat *sb) { fsw_status_t status; status = fsw_dnode_fill(dno); if (status) return status; sb->used_bytes = 0; status = dno->vol->fstype_table->dnode_stat(dno->vol, dno, sb); if (!status && !sb->used_bytes) sb->used_bytes = FSW_U64_DIV(dno->size + dno->vol->log_blocksize - 1, dno->vol->log_blocksize); return status; } /** * Lookup a directory entry by name. This function is called by the host driver. * Given a directory dnode and a file name, it looks up the named entry in the * directory. * * If the dnode is not a directory, the call will fail. The caller is responsible for * resolving symbolic links before calling this function. * * If the function returns FSW_SUCCESS, *child_dno_out points to the requested directory * entry. The caller must call fsw_dnode_release on it. */ fsw_status_t fsw_dnode_lookup(struct fsw_dnode *dno, struct fsw_string *lookup_name, struct fsw_dnode **child_dno_out) { fsw_status_t status; status = fsw_dnode_fill(dno); if (status) return status; if (dno->type != FSW_DNODE_TYPE_DIR) return FSW_UNSUPPORTED; return dno->vol->fstype_table->dir_lookup(dno->vol, dno, lookup_name, child_dno_out); } /** * Find a file system object by path. This function is called by the host driver. * Given a directory dnode and a relative or absolute path, it walks the directory * tree until it finds the target dnode. If an intermediate node turns out to be * a symlink, it is resolved automatically. If the target node is a symlink, it * is not resolved. * * If the function returns FSW_SUCCESS, *child_dno_out points to the requested directory * entry. The caller must call fsw_dnode_release on it. */ fsw_status_t fsw_dnode_lookup_path(struct fsw_dnode *dno, struct fsw_string *lookup_path, char separator, struct fsw_dnode **child_dno_out) { fsw_status_t status; struct fsw_volume *vol = dno->vol; struct fsw_dnode *child_dno = NULL; struct fsw_string lookup_name; struct fsw_string remaining_path; int root_if_empty; remaining_path = *lookup_path; fsw_dnode_retain(dno); // loop over the path for (root_if_empty = 1; fsw_strlen(&remaining_path) > 0; root_if_empty = 0) { // parse next path component fsw_strsplit(&lookup_name, &remaining_path, separator); FSW_MSG_DEBUG((FSW_MSGSTR("fsw_dnode_lookup_path: split into %d '%s' and %d '%s'\n"), lookup_name.len, lookup_name.data, remaining_path.len, remaining_path.data)); if (fsw_strlen(&lookup_name) == 0) { // empty path component if (root_if_empty) child_dno = vol->root; else child_dno = dno; fsw_dnode_retain(child_dno); } else { // do an actual directory lookup // ensure we have full information status = fsw_dnode_fill(dno); if (status) goto errorexit; // resolve symlink if necessary if (dno->type == FSW_DNODE_TYPE_SYMLINK) { status = fsw_dnode_resolve(dno, &child_dno); if (status) goto errorexit; // symlink target becomes the new dno fsw_dnode_release(dno); dno = child_dno; // is already retained child_dno = NULL; // ensure we have full information status = fsw_dnode_fill(dno); if (status) goto errorexit; } // make sure we operate on a directory if (dno->type != FSW_DNODE_TYPE_DIR) { return FSW_UNSUPPORTED; goto errorexit; } // check special paths if (fsw_streq_cstr(&lookup_name, ".")) { // self directory child_dno = dno; fsw_dnode_retain(child_dno); } else if (fsw_streq_cstr(&lookup_name, "..")) { // parent directory if (dno->parent == NULL) { // We cannot go up from the root directory. Caution: Certain apps like the EFI shell // rely on this behaviour! status = FSW_NOT_FOUND; goto errorexit; } child_dno = dno->parent; fsw_dnode_retain(child_dno); } else { // do an actual lookup status = vol->fstype_table->dir_lookup(vol, dno, &lookup_name, &child_dno); if (status) goto errorexit; } } // child_dno becomes the new dno fsw_dnode_release(dno); dno = child_dno; // is already retained child_dno = NULL; FSW_MSG_DEBUG((FSW_MSGSTR("fsw_dnode_lookup_path: now at inode %d\n"), dno->dnode_id)); } *child_dno_out = dno; return FSW_SUCCESS; errorexit: FSW_MSG_DEBUG((FSW_MSGSTR("fsw_dnode_lookup_path: leaving with error %d\n"), status)); fsw_dnode_release(dno); if (child_dno != NULL) fsw_dnode_release(child_dno); return status; } /** * Get the next directory item in sequential order. This function is called by the * host driver to read the complete contents of a directory in sequential (file system * defined) order. Calling this function returns the next entry. Iteration state is * kept by a shandle on the directory's dnode. The caller must set up the shandle * when starting the iteration. * * When the end of the directory is reached, this function returns FSW_NOT_FOUND. * If the function returns FSW_SUCCESS, *child_dno_out points to the next directory * entry. The caller must call fsw_dnode_release on it. */ fsw_status_t fsw_dnode_dir_read(struct fsw_shandle *shand, struct fsw_dnode **child_dno_out) { fsw_status_t status; struct fsw_dnode *dno = shand->dnode; fsw_u64 saved_pos; if (dno->type != FSW_DNODE_TYPE_DIR) return FSW_UNSUPPORTED; saved_pos = shand->pos; status = dno->vol->fstype_table->dir_read(dno->vol, dno, shand, child_dno_out); if (status) shand->pos = saved_pos; return status; } /** * Read the target path of a symbolic link. This function is called by the host driver * to read the "content" of a symbolic link, that is the relative or absolute path * it points to. * * If the function returns FSW_SUCCESS, the string handle provided by the caller is * filled with a string in the host's preferred encoding. The caller is responsible * for calling fsw_strfree on the string. */ fsw_status_t fsw_dnode_readlink(struct fsw_dnode *dno, struct fsw_string *target_name) { fsw_status_t status; status = fsw_dnode_fill(dno); if (status) return status; if (dno->type != FSW_DNODE_TYPE_SYMLINK) return FSW_UNSUPPORTED; return dno->vol->fstype_table->readlink(dno->vol, dno, target_name); } /** * Read the target path of a symbolic link by accessing file data. This function can * be called by the file system driver if the file system stores the target path * as normal file data. This function will open an shandle, read the whole content * of the file into a buffer, and build a string from that. Currently the encoding * for the string is fixed as FSW_STRING_TYPE_ISO88591. * * If the function returns FSW_SUCCESS, the string handle provided by the caller is * filled with a string in the host's preferred encoding. The caller is responsible * for calling fsw_strfree on the string. */ fsw_status_t fsw_dnode_readlink_data(struct fsw_dnode *dno, struct fsw_string *link_target) { fsw_status_t status; struct fsw_shandle shand; fsw_u32 buffer_size; char buffer[FSW_PATH_MAX]; struct fsw_string s; if (dno->size > FSW_PATH_MAX) return FSW_VOLUME_CORRUPTED; s.type = FSW_STRING_TYPE_ISO88591; s.size = s.len = (int)dno->size; s.data = buffer; // open shandle and read the data status = fsw_shandle_open(dno, &shand); if (status) return status; buffer_size = (fsw_u32)s.size; status = fsw_shandle_read(&shand, &buffer_size, buffer); fsw_shandle_close(&shand); if (status) return status; if ((int)buffer_size < s.size) return FSW_VOLUME_CORRUPTED; status = fsw_strdup_coerce(link_target, dno->vol->host_string_type, &s); return status; } /** * Resolve a symbolic link. This function can be called by the host driver to make * sure the a dnode is fully resolved instead of pointing at a symlink. If the dnode * passed in is not a symlink, it is returned unmodified. * * Note that absolute paths will be resolved relative to the root directory of the * volume. If the host is an operating system with its own VFS layer, it should * resolve symlinks on its own. * * If the function returns FSW_SUCCESS, *target_dno_out points at a dnode that is * not a symlink. The caller is responsible for calling fsw_dnode_release on it. */ fsw_status_t fsw_dnode_resolve(struct fsw_dnode *dno, struct fsw_dnode **target_dno_out) { fsw_status_t status; struct fsw_string target_name; struct fsw_dnode *target_dno; /* Linux kernel max link count is 40 */ int link_count = 40; fsw_dnode_retain(dno); while (--link_count > 0) { // get full information status = fsw_dnode_fill(dno); if (status) goto errorexit; if (dno->type != FSW_DNODE_TYPE_SYMLINK) { // found a non-symlink target, return it *target_dno_out = dno; return FSW_SUCCESS; } if (dno->parent == NULL) { // safety measure, cannot happen in theory status = FSW_NOT_FOUND; goto errorexit; } // read the link's target status = fsw_dnode_readlink(dno, &target_name); if (status) goto errorexit; // resolve it status = fsw_dnode_lookup_path(dno->parent, &target_name, '/', &target_dno); fsw_strfree(&target_name); if (status) goto errorexit; // target_dno becomes the new dno fsw_dnode_release(dno); dno = target_dno; // is already retained } if(link_count == 0) status = FSW_NOT_FOUND; errorexit: fsw_dnode_release(dno); return status; } /** * Set up a shandle (storage handle) to access a file's data. This function is called * by the host driver and by the core when they need to access a file's data. It is also * used in accessing the raw data of directories and symlinks if the file system uses * the same mechanisms for storing the data of those items. * * The storage for the fsw_shandle structure is provided by the caller. The dnode and pos * fields may be accessed, pos may also be written to to set the file pointer. The file's * data size is available as shand->dnode->size. * * If this function returns FSW_SUCCESS, the caller must call fsw_shandle_close to release * the dnode reference held by the shandle. */ fsw_status_t fsw_shandle_open(struct fsw_dnode *dno, struct fsw_shandle *shand) { fsw_status_t status; struct fsw_volume *vol = dno->vol; // read full dnode information into memory status = vol->fstype_table->dnode_fill(vol, dno); if (status) return status; // setup shandle fsw_dnode_retain(dno); shand->dnode = dno; shand->pos = 0; shand->extent.type = FSW_EXTENT_TYPE_INVALID; return FSW_SUCCESS; } /** * Close a shandle after accessing the dnode's data. This function is called by the host * driver or core functions when they are finished with accessing a file's data. It * releases the dnode reference and frees any buffers associated with the shandle itself. * The dnode is only released if this was the last reference using it. */ void fsw_shandle_close(struct fsw_shandle *shand) { if (shand->extent.type == FSW_EXTENT_TYPE_BUFFER) fsw_free(shand->extent.buffer); fsw_dnode_release(shand->dnode); } /** * Read data from a shandle (storage handle for a dnode). This function is called by the * host driver or internally when data is read from a file. TODO: more */ fsw_status_t fsw_shandle_read(struct fsw_shandle *shand, fsw_u32 *buffer_size_inout, void *buffer_in) { fsw_status_t status; struct fsw_dnode *dno = shand->dnode; struct fsw_volume *vol = dno->vol; fsw_u8 *buffer, *block_buffer; fsw_u64 buflen, copylen, pos; fsw_u64 log_bno, pos_in_extent, phys_bno, pos_in_physblock; fsw_u32 cache_level; if (shand->pos >= dno->size) { // already at EOF *buffer_size_inout = 0; return FSW_SUCCESS; } // initialize vars buffer = buffer_in; buflen = *buffer_size_inout; pos = (fsw_u32)shand->pos; cache_level = (dno->type != FSW_DNODE_TYPE_FILE) ? 1 : 0; // restrict read to file size if (buflen > dno->size - pos) buflen = (fsw_u32)(dno->size - pos); while (buflen > 0) { // get extent for the current logical block log_bno = FSW_U64_DIV(pos, vol->log_blocksize); if (shand->extent.type == FSW_EXTENT_TYPE_INVALID || log_bno < shand->extent.log_start || log_bno >= shand->extent.log_start + shand->extent.log_count) { if (shand->extent.type == FSW_EXTENT_TYPE_BUFFER) fsw_free(shand->extent.buffer); // ask the file system for the proper extent shand->extent.log_start = log_bno; status = vol->fstype_table->get_extent(vol, dno, &shand->extent); if (status) { shand->extent.type = FSW_EXTENT_TYPE_INVALID; return status; } } pos_in_extent = pos - shand->extent.log_start * vol->log_blocksize; // dispatch by extent type if (shand->extent.type == FSW_EXTENT_TYPE_PHYSBLOCK) { // convert to physical block number and offset phys_bno = shand->extent.phys_start + FSW_U64_DIV(pos_in_extent, vol->phys_blocksize); pos_in_physblock = pos_in_extent & (vol->phys_blocksize - 1); copylen = vol->phys_blocksize - pos_in_physblock; if (copylen > buflen) copylen = buflen; // get one physical block status = fsw_block_get(vol, phys_bno, cache_level, (void **)&block_buffer); if (status) return status; // copy data from it fsw_memcpy(buffer, block_buffer + pos_in_physblock, copylen); fsw_block_release(vol, phys_bno, block_buffer); } else if (shand->extent.type == FSW_EXTENT_TYPE_BUFFER) { copylen = shand->extent.log_count * vol->log_blocksize - pos_in_extent; if (copylen > buflen) copylen = buflen; fsw_memcpy(buffer, (fsw_u8 *)shand->extent.buffer + pos_in_extent, copylen); } else { // _SPARSE or _INVALID copylen = shand->extent.log_count * vol->log_blocksize - pos_in_extent; if (copylen > buflen) copylen = buflen; fsw_memzero(buffer, copylen); } buffer += copylen; buflen -= copylen; pos += copylen; } *buffer_size_inout = (fsw_u32)(pos - shand->pos); shand->pos = pos; return FSW_SUCCESS; } // EOF �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/fsw_strfunc.h�������������������������������������������������������������0000664�0001750�0001750�00000033402�12631615017�020401� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* fsw_strfunc.h generated by mk_fsw_strfunc.py */ /*- * Copyright (c) 2006 Christoph Pfisterer * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * * Neither the name of Christoph Pfisterer nor the names of the * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ static int fsw_streq_ISO88591_UTF8(void *s1data, void *s2data, int len) { int i; fsw_u8 *p1 = (fsw_u8 *)s1data; fsw_u8 *p2 = (fsw_u8 *)s2data; fsw_u32 c1, c2; for (i = 0; i < len; i++) { c1 = *p1++; c2 = *p2++; if ((c2 & 0xe0) == 0xc0) { c2 = ((c2 & 0x1f) << 6) | (*p2++ & 0x3f); } else if ((c2 & 0xf0) == 0xe0) { c2 = ((c2 & 0x0f) << 12) | ((*p2++ & 0x3f) << 6); c2 |= (*p2++ & 0x3f); } else if ((c2 & 0xf8) == 0xf0) { c2 = ((c2 & 0x07) << 18) | ((*p2++ & 0x3f) << 12); c2 |= ((*p2++ & 0x3f) << 6); c2 |= (*p2++ & 0x3f); } if (c1 != c2) return 0; } return 1; } static int fsw_streq_ISO88591_UTF16(void *s1data, void *s2data, int len) { int i; fsw_u8 *p1 = (fsw_u8 *)s1data; fsw_u16 *p2 = (fsw_u16 *)s2data; fsw_u32 c1, c2; for (i = 0; i < len; i++) { c1 = *p1++; c2 = *p2++; if (c1 != c2) return 0; } return 1; } static int fsw_streq_ISO88591_UTF16_SWAPPED(void *s1data, void *s2data, int len) { int i; fsw_u8 *p1 = (fsw_u8 *)s1data; fsw_u16 *p2 = (fsw_u16 *)s2data; fsw_u32 c1, c2; for (i = 0; i < len; i++) { c1 = *p1++; c2 = *p2++; c2 = FSW_SWAPVALUE_U16(c2); if (c1 != c2) return 0; } return 1; } static int fsw_streq_UTF8_UTF16(void *s1data, void *s2data, int len) { int i; fsw_u8 *p1 = (fsw_u8 *)s1data; fsw_u16 *p2 = (fsw_u16 *)s2data; fsw_u32 c1, c2; for (i = 0; i < len; i++) { c1 = *p1++; if ((c1 & 0xe0) == 0xc0) { c1 = ((c1 & 0x1f) << 6) | (*p1++ & 0x3f); } else if ((c1 & 0xf0) == 0xe0) { c1 = ((c1 & 0x0f) << 12) | ((*p1++ & 0x3f) << 6); c1 |= (*p1++ & 0x3f); } else if ((c1 & 0xf8) == 0xf0) { c1 = ((c1 & 0x07) << 18) | ((*p1++ & 0x3f) << 12); c1 |= ((*p1++ & 0x3f) << 6); c1 |= (*p1++ & 0x3f); } c2 = *p2++; if (c1 != c2) return 0; } return 1; } static int fsw_streq_UTF8_UTF16_SWAPPED(void *s1data, void *s2data, int len) { int i; fsw_u8 *p1 = (fsw_u8 *)s1data; fsw_u16 *p2 = (fsw_u16 *)s2data; fsw_u32 c1, c2; for (i = 0; i < len; i++) { c1 = *p1++; if ((c1 & 0xe0) == 0xc0) { c1 = ((c1 & 0x1f) << 6) | (*p1++ & 0x3f); } else if ((c1 & 0xf0) == 0xe0) { c1 = ((c1 & 0x0f) << 12) | ((*p1++ & 0x3f) << 6); c1 |= (*p1++ & 0x3f); } else if ((c1 & 0xf8) == 0xf0) { c1 = ((c1 & 0x07) << 18) | ((*p1++ & 0x3f) << 12); c1 |= ((*p1++ & 0x3f) << 6); c1 |= (*p1++ & 0x3f); } c2 = *p2++; c2 = FSW_SWAPVALUE_U16(c2); if (c1 != c2) return 0; } return 1; } static int fsw_streq_UTF16_UTF16_SWAPPED(void *s1data, void *s2data, int len) { int i; fsw_u16 *p1 = (fsw_u16 *)s1data; fsw_u16 *p2 = (fsw_u16 *)s2data; fsw_u32 c1, c2; for (i = 0; i < len; i++) { c1 = *p1++; c2 = *p2++; c2 = FSW_SWAPVALUE_U16(c2); if (c1 != c2) return 0; } return 1; } static fsw_status_t fsw_strcoerce_UTF8_ISO88591(void *srcdata, int srclen, struct fsw_string *dest) { fsw_status_t status; int i; fsw_u8 *sp; fsw_u8 *dp; fsw_u32 c; dest->type = FSW_STRING_TYPE_ISO88591; dest->len = srclen; dest->size = srclen * sizeof(fsw_u8); status = fsw_alloc(dest->size, &dest->data); if (status) return status; sp = (fsw_u8 *)srcdata; dp = (fsw_u8 *)dest->data; for (i = 0; i < srclen; i++) { c = *sp++; if ((c & 0xe0) == 0xc0) { c = ((c & 0x1f) << 6) | (*sp++ & 0x3f); } else if ((c & 0xf0) == 0xe0) { c = ((c & 0x0f) << 12) | ((*sp++ & 0x3f) << 6); c |= (*sp++ & 0x3f); } else if ((c & 0xf8) == 0xf0) { c = ((c & 0x07) << 18) | ((*sp++ & 0x3f) << 12); c |= ((*sp++ & 0x3f) << 6); c |= (*sp++ & 0x3f); } *dp++ = (fsw_u8)c; } return FSW_SUCCESS; } static fsw_status_t fsw_strcoerce_UTF16_ISO88591(void *srcdata, int srclen, struct fsw_string *dest) { fsw_status_t status; int i; fsw_u16 *sp; fsw_u8 *dp; fsw_u32 c; dest->type = FSW_STRING_TYPE_ISO88591; dest->len = srclen; dest->size = srclen * sizeof(fsw_u8); status = fsw_alloc(dest->size, &dest->data); if (status) return status; sp = (fsw_u16 *)srcdata; dp = (fsw_u8 *)dest->data; for (i = 0; i < srclen; i++) { c = *sp++; *dp++ = (fsw_u8)c; } return FSW_SUCCESS; } static fsw_status_t fsw_strcoerce_UTF16_SWAPPED_ISO88591(void *srcdata, int srclen, struct fsw_string *dest) { fsw_status_t status; int i; fsw_u16 *sp; fsw_u8 *dp; fsw_u32 c; dest->type = FSW_STRING_TYPE_ISO88591; dest->len = srclen; dest->size = srclen * sizeof(fsw_u8); status = fsw_alloc(dest->size, &dest->data); if (status) return status; sp = (fsw_u16 *)srcdata; dp = (fsw_u8 *)dest->data; for (i = 0; i < srclen; i++) { c = *sp++; c = FSW_SWAPVALUE_U16(c); *dp++ = (fsw_u8)c; } return FSW_SUCCESS; } static fsw_status_t fsw_strcoerce_ISO88591_UTF16(void *srcdata, int srclen, struct fsw_string *dest) { fsw_status_t status; int i; fsw_u8 *sp; fsw_u16 *dp; fsw_u32 c; dest->type = FSW_STRING_TYPE_UTF16; dest->len = srclen; dest->size = srclen * sizeof(fsw_u16); status = fsw_alloc(dest->size, &dest->data); if (status) return status; sp = (fsw_u8 *)srcdata; dp = (fsw_u16 *)dest->data; for (i = 0; i < srclen; i++) { c = *sp++; *dp++ = (fsw_u16)c; } return FSW_SUCCESS; } static fsw_status_t fsw_strcoerce_UTF8_UTF16(void *srcdata, int srclen, struct fsw_string *dest) { fsw_status_t status; int i; fsw_u8 *sp; fsw_u16 *dp; fsw_u32 c; dest->type = FSW_STRING_TYPE_UTF16; dest->len = srclen; dest->size = srclen * sizeof(fsw_u16); status = fsw_alloc(dest->size, &dest->data); if (status) return status; sp = (fsw_u8 *)srcdata; dp = (fsw_u16 *)dest->data; for (i = 0; i < srclen; i++) { c = *sp++; if ((c & 0xe0) == 0xc0) { c = ((c & 0x1f) << 6) | (*sp++ & 0x3f); } else if ((c & 0xf0) == 0xe0) { c = ((c & 0x0f) << 12) | ((*sp++ & 0x3f) << 6); c |= (*sp++ & 0x3f); } else if ((c & 0xf8) == 0xf0) { c = ((c & 0x07) << 18) | ((*sp++ & 0x3f) << 12); c |= ((*sp++ & 0x3f) << 6); c |= (*sp++ & 0x3f); } *dp++ = (fsw_u16)c; } return FSW_SUCCESS; } static fsw_status_t fsw_strcoerce_UTF16_SWAPPED_UTF16(void *srcdata, int srclen, struct fsw_string *dest) { fsw_status_t status; int i; fsw_u16 *sp; fsw_u16 *dp; fsw_u32 c; dest->type = FSW_STRING_TYPE_UTF16; dest->len = srclen; dest->size = srclen * sizeof(fsw_u16); status = fsw_alloc(dest->size, &dest->data); if (status) return status; sp = (fsw_u16 *)srcdata; dp = (fsw_u16 *)dest->data; for (i = 0; i < srclen; i++) { c = *sp++; c = FSW_SWAPVALUE_U16(c); *dp++ = (fsw_u16)c; } return FSW_SUCCESS; } static fsw_status_t fsw_strcoerce_ISO88591_UTF8(void *srcdata, int srclen, struct fsw_string *dest) { fsw_status_t status; int i, destsize; fsw_u8 *sp; fsw_u8 *dp; fsw_u32 c; sp = (fsw_u8 *)srcdata; destsize = 0; for (i = 0; i < srclen; i++) { c = *sp++; if (c < 0x000080) destsize++; else if (c < 0x000800) destsize += 2; else if (c < 0x010000) destsize += 3; else destsize += 4; } dest->type = FSW_STRING_TYPE_UTF8; dest->len = srclen; dest->size = destsize; status = fsw_alloc(dest->size, &dest->data); if (status) return status; sp = (fsw_u8 *)srcdata; dp = (fsw_u8 *)dest->data; for (i = 0; i < srclen; i++) { c = *sp++; if (c < 0x000080) { *dp++ = (fsw_u8)c; } else if (c < 0x000800) { *dp++ = (fsw_u8)(0xc0 | ((c >> 6) & 0x1f)); *dp++ = (fsw_u8)(0x80 | (c & 0x3f)); } else if (c < 0x010000) { *dp++ = (fsw_u8)(0xe0 | ((c >> 12) & 0x0f)); *dp++ = (fsw_u8)(0x80 | ((c >> 6) & 0x3f)); *dp++ = (fsw_u8)(0x80 | (c & 0x3f)); } else { *dp++ = (fsw_u8)(0xf0 | ((c >> 18) & 0x07)); *dp++ = (fsw_u8)(0x80 | ((c >> 12) & 0x3f)); *dp++ = (fsw_u8)(0x80 | ((c >> 6) & 0x3f)); *dp++ = (fsw_u8)(0x80 | (c & 0x3f)); } } return FSW_SUCCESS; } static fsw_status_t fsw_strcoerce_UTF16_UTF8(void *srcdata, int srclen, struct fsw_string *dest) { fsw_status_t status; int i, destsize; fsw_u16 *sp; fsw_u8 *dp; fsw_u32 c; sp = (fsw_u16 *)srcdata; destsize = 0; for (i = 0; i < srclen; i++) { c = *sp++; if (c < 0x000080) destsize++; else if (c < 0x000800) destsize += 2; else if (c < 0x010000) destsize += 3; else destsize += 4; } dest->type = FSW_STRING_TYPE_UTF8; dest->len = srclen; dest->size = destsize; status = fsw_alloc(dest->size, &dest->data); if (status) return status; sp = (fsw_u16 *)srcdata; dp = (fsw_u8 *)dest->data; for (i = 0; i < srclen; i++) { c = *sp++; if (c < 0x000080) { *dp++ = (fsw_u8)c; } else if (c < 0x000800) { *dp++ = (fsw_u8)(0xc0 | ((c >> 6) & 0x1f)); *dp++ = (fsw_u8)(0x80 | (c & 0x3f)); } else if (c < 0x010000) { *dp++ = (fsw_u8)(0xe0 | ((c >> 12) & 0x0f)); *dp++ = (fsw_u8)(0x80 | ((c >> 6) & 0x3f)); *dp++ = (fsw_u8)(0x80 | (c & 0x3f)); } else { *dp++ = (fsw_u8)(0xf0 | ((c >> 18) & 0x07)); *dp++ = (fsw_u8)(0x80 | ((c >> 12) & 0x3f)); *dp++ = (fsw_u8)(0x80 | ((c >> 6) & 0x3f)); *dp++ = (fsw_u8)(0x80 | (c & 0x3f)); } } return FSW_SUCCESS; } static fsw_status_t fsw_strcoerce_UTF16_SWAPPED_UTF8(void *srcdata, int srclen, struct fsw_string *dest) { fsw_status_t status; int i, destsize; fsw_u16 *sp; fsw_u8 *dp; fsw_u32 c; sp = (fsw_u16 *)srcdata; destsize = 0; for (i = 0; i < srclen; i++) { c = *sp++; c = FSW_SWAPVALUE_U16(c); if (c < 0x000080) destsize++; else if (c < 0x000800) destsize += 2; else if (c < 0x010000) destsize += 3; else destsize += 4; } dest->type = FSW_STRING_TYPE_UTF8; dest->len = srclen; dest->size = destsize; status = fsw_alloc(dest->size, &dest->data); if (status) return status; sp = (fsw_u16 *)srcdata; dp = (fsw_u8 *)dest->data; for (i = 0; i < srclen; i++) { c = *sp++; c = FSW_SWAPVALUE_U16(c); if (c < 0x000080) { *dp++ = (fsw_u8)c; } else if (c < 0x000800) { *dp++ = (fsw_u8)(0xc0 | ((c >> 6) & 0x1f)); *dp++ = (fsw_u8)(0x80 | (c & 0x3f)); } else if (c < 0x010000) { *dp++ = (fsw_u8)(0xe0 | ((c >> 12) & 0x0f)); *dp++ = (fsw_u8)(0x80 | ((c >> 6) & 0x3f)); *dp++ = (fsw_u8)(0x80 | (c & 0x3f)); } else { *dp++ = (fsw_u8)(0xf0 | ((c >> 18) & 0x07)); *dp++ = (fsw_u8)(0x80 | ((c >> 12) & 0x3f)); *dp++ = (fsw_u8)(0x80 | ((c >> 6) & 0x3f)); *dp++ = (fsw_u8)(0x80 | (c & 0x3f)); } } return FSW_SUCCESS; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/fsw_btrfs_zstd.h����������������������������������������������������������0000644�0001750�0001750�00000006100�13363346003�021071� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2016-present, Facebook, Inc. * All rights reserved. * */ #define PAGE_SIZE 4096 #define uint64_t fsw_u64 #define uint32_t fsw_u32 #define uint16_t fsw_u16 #define int16_t fsw_s16 #define uintptr_t unsigned long #define sys_memmove fsw_memcpy static inline uint16_t get_unaligned_le16(const void *s) { const unsigned char *p = (const unsigned char *)s; return p[0]+ (p[1]<<8); } static inline uint32_t get_unaligned_le32(const void *s) { const unsigned char *p = (const unsigned char *)s; return p[0]+ (p[1]<<8) + (p[2]<<16) + (p[3]<<24); } static inline uint64_t get_unaligned_le64(const void *s) { const unsigned char *p = (const unsigned char *)s; uint64_t v0 = get_unaligned_le32(p); uint64_t v1 = get_unaligned_le32(p+4); return v0 + (v1<<32); } static inline void put_unaligned_le16(uint16_t v, void *s) { unsigned char *p = (unsigned char *)s; p[0] = v & 0xff; p[1] = v >> 8; } #define UP_U32(a) (((a)+3) >> 2) #include "zstd/xxhash64.c" #include "zstd/zstd_decompress.c" #include "zstd/fse_decompress.c" #include "zstd/huf_decompress.c" #define ZSTD_BTRFS_MAX_WINDOWLOG 17 #define ZSTD_BTRFS_MAX_INPUT (1 << ZSTD_BTRFS_MAX_WINDOWLOG) static fsw_ssize_t zstd_decompress(char *data_in, fsw_size_t srclen, grub_off_t start_byte, char *data_out, fsw_size_t destlen) { ZSTD_DStream *stream; ZSTD_inBuffer in_buf; ZSTD_outBuffer out_buf; fsw_ssize_t ret = 0; size_t ret2; size_t workspace_size = ZSTD_DStreamWorkspaceBound(ZSTD_BTRFS_MAX_INPUT); void * workspace; in_buf.src = data_in; in_buf.pos = 0; in_buf.size = srclen; out_buf.dst = NULL; workspace = AllocatePool(workspace_size); if(!workspace) { ret = -FSW_OUT_OF_MEMORY; goto finish; } stream = ZSTD_initDStream(ZSTD_BTRFS_MAX_INPUT, workspace, workspace_size); if (!stream) { DPRINT(L"BTRFS: ZSTD_initDStream failed\n"); ret = -FSW_OUT_OF_MEMORY; goto finish; } while(start_byte > 0) { out_buf.size = start_byte < PAGE_SIZE ? start_byte : PAGE_SIZE; if(out_buf.dst == NULL) out_buf.dst = AllocatePool(out_buf.size); out_buf.pos = 0; ret2 = ZSTD_decompressStream(stream, &out_buf, &in_buf); if (ZSTD_isError(ret2)) { DPRINT(L"BTRFS: ZSTD_decompressStream returned %d\n", ZSTD_getErrorCode(ret2)); ret = -FSW_VOLUME_CORRUPTED; goto finish; } if(out_buf.pos == 0 && in_buf.pos == in_buf.size) { DPRINT(L"BTRFS: ZSTD_decompressStream ended early\n"); ret = -FSW_VOLUME_CORRUPTED; goto finish; } start_byte -= out_buf.pos; } if(out_buf.dst) FreePool(out_buf.dst); out_buf.dst = data_out; out_buf.size = destlen; out_buf.pos = 0; ret2 = ZSTD_decompressStream(stream, &out_buf, &in_buf); if (ZSTD_isError(ret2)) { DPRINT(L"BTRFS: ZSTD_decompressStream returned %d\n", ZSTD_getErrorCode(ret2)); ret = -FSW_VOLUME_CORRUPTED; goto finish; } ret = destlen; finish: if(out_buf.dst && out_buf.dst != data_out) FreePool(out_buf.dst); if(workspace) FreePool(workspace); if (out_buf.pos < destlen) memset(data_out + out_buf.pos, 0, destlen - out_buf.pos); return ret; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/fsw_iso9660.h�������������������������������������������������������������0000664�0001750�0001750�00000013755�12626644770�020061� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Id: fsw_iso9660.h 29125 2010-05-06 09:43:05Z vboxsync $ */ /** @file * fsw_iso9660.h - ISO9660 file system driver header. */ /*- * Copyright (c) 2006 Christoph Pfisterer * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * * Neither the name of Christoph Pfisterer nor the names of the * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _FSW_ISO9660_H_ #define _FSW_ISO9660_H_ #define VOLSTRUCTNAME fsw_iso9660_volume #define DNODESTRUCTNAME fsw_iso9660_dnode #include "fsw_core.h" //! Block size for ISO9660 volumes. #define ISO9660_BLOCKSIZE 2048 #define ISO9660_BLOCKSIZE_BITS 11 //! Block number where the ISO9660 superblock resides. #define ISO9660_SUPERBLOCK_BLOCKNO 16 //Slice - we already have shifted blockIO by 16 //but we should use ParentBlockIo //#define ISO9660_SUPERBLOCK_BLOCKNO 0 #pragma pack(1) typedef struct { fsw_u16 lsb; fsw_u16 msb; } iso9660_u16; typedef struct { fsw_u32 lsb; fsw_u32 msb; } iso9660_u32; #define ISOINT(lsbmsbvalue) ((lsbmsbvalue).lsb) struct iso9660_dirrec { fsw_u8 dirrec_length; fsw_u8 ear_length; iso9660_u32 extent_location; iso9660_u32 data_length; fsw_u8 recording_datetime[7]; fsw_u8 file_flags; fsw_u8 file_unit_size; fsw_u8 interleave_gap_size; iso9660_u16 volume_sequence_number; fsw_u8 file_identifier_length; char file_identifier[1]; }; //#if sizeof(struct fsw_iso9660_dirrec) != 34 //#fail Structure fsw_iso9660_dirrec has wrong size //#endif struct iso9660_volume_descriptor { fsw_u8 volume_descriptor_type; char standard_identifier[5]; fsw_u8 volume_descriptor_version; }; struct iso9660_primary_volume_descriptor { fsw_u8 volume_descriptor_type; char standard_identifier[5]; fsw_u8 volume_descriptor_version; fsw_u8 unused1; char system_identifier[32]; char volume_identifier[32]; fsw_u8 unused2[8]; iso9660_u32 volume_space_size; fsw_u8 unused3[4]; fsw_u8 escape[3]; fsw_u8 unused4[25]; iso9660_u16 volume_set_size; iso9660_u16 volume_sequence_number; iso9660_u16 logical_block_size; iso9660_u32 path_table_size; fsw_u32 location_type_l_path_table; fsw_u32 location_optional_type_l_path_table; fsw_u32 location_type_m_path_table; fsw_u32 location_optional_type_m_path_table; struct iso9660_dirrec root_directory; char volume_set_identifier[128]; char publisher_identifier[128]; char data_preparer_identifier[128]; char application_identifier[128]; char copyright_file_identifier[37]; char abstract_file_identifier[37]; char bibliographic_file_identifier[37]; char volume_creation_datetime[17]; char volume_modification_datetime[17]; char volume_expiration_datetime[17]; char volume_effective_datetime[17]; fsw_u8 file_structure_version; fsw_u8 reserved1; fsw_u8 application_use[512]; fsw_u8 reserved2[653]; }; //#if sizeof(struct fsw_iso9660_volume_descriptor) != 2048 //#fail Structure fsw_iso9660_volume_descriptor has wrong size //#endif #pragma pack() struct iso9660_dirrec_buffer { fsw_u32 ino; struct fsw_string name; struct iso9660_dirrec dirrec; char dirrec_buffer[222]; }; /** * ISO9660: Volume structure with ISO9660-specific data. */ struct fsw_iso9660_volume { struct fsw_volume g; //!< Generic volume structure /*Note: don't move g!*/ int fJoliet; /*Joliet specific fields*/ int fRockRidge; /*Rock Ridge specific fields*/ int rr_susp_skip; struct iso9660_primary_volume_descriptor *primary_voldesc; //!< Full Primary Volume Descriptor }; /** * ISO9660: Dnode structure with ISO9660-specific data. */ struct fsw_iso9660_dnode { struct fsw_dnode g; //!< Generic dnode structure struct iso9660_dirrec dirrec; //!< Fixed part of the directory record (i.e. w/o name) }; struct fsw_rock_ridge_susp_entry { fsw_u8 sig[2]; fsw_u8 len; fsw_u8 ver; }; struct fsw_rock_ridge_susp_sp { struct fsw_rock_ridge_susp_entry e; fsw_u8 magic[2]; fsw_u8 skip; }; struct fsw_rock_ridge_susp_nm { struct fsw_rock_ridge_susp_entry e; fsw_u8 flags; fsw_u8 name[1]; }; #define RR_NM_CONT (1<<0) #define RR_NM_CURR (1<<1) #define RR_NM_PARE (1<<2) union fsw_rock_ridge_susp_ce { struct X{ struct fsw_rock_ridge_susp_entry e; iso9660_u32 block_loc; iso9660_u32 offset; iso9660_u32 len; } X; fsw_u8 raw[28]; }; #endif �������������������refind-0.11.4/filesystems/fsw_efi_base.h������������������������������������������������������������0000664�0001750�0001750�00000005341�13363456427�020466� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/** * \file fsw_efi_base.h * Base definitions for the EFI host environment. */ /*- * Copyright (c) 2006 Christoph Pfisterer * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * * Neither the name of Christoph Pfisterer nor the names of the * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _FSW_EFI_BASE_H_ #define _FSW_EFI_BASE_H_ // If its EDK2 EFI Toolkit #ifdef __MAKEWITH_TIANO #include "fsw_efi_edk2_base.h" #else // Intel EFI Toolkit #include <efi.h> #include <efilib.h> #endif #define FSW_LITTLE_ENDIAN (1) // types, reuse EFI types typedef INT8 fsw_s8; typedef UINT8 fsw_u8; typedef INT16 fsw_s16; typedef UINT16 fsw_u16; typedef INT32 fsw_s32; typedef UINT32 fsw_u32; typedef INT64 fsw_s64; typedef UINT64 fsw_u64; // allocation functions #define fsw_alloc(size, ptrptr) (((*(ptrptr) = AllocatePool(size)) == NULL) ? FSW_OUT_OF_MEMORY : FSW_SUCCESS) #define fsw_free(ptr) FreePool(ptr) // memory functions #define fsw_memzero(dest,size) ZeroMem(dest,size) #define fsw_memcpy(dest,src,size) CopyMem(dest,src,size) #define fsw_memeq(p1,p2,size) (CompareMem(p1,p2,size) == 0) // message printing #define FSW_MSGSTR(s) L##s #define FSW_MSGFUNC Print // 64-bit hooks #define FSW_U64_SHR(val,shiftbits) RShiftU64((val), (shiftbits)) #define FSW_U64_DIV(val,divisor) DivU64x32((val), (divisor), NULL) #ifdef __MAKEWITH_GNUEFI #define DivU64x32Remainder DivU64x32 #endif #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/design.dox����������������������������������������������������������������0000664�0001750�0001750�00000012130�12626644770�017661� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * \file design.dox * Documentation title page with design information */ /** \mainpage File System Wrapper Documentation Welcome to the documentation for FSW. This doxygen-generated documentation is intended for developers that either want to integrate FSW into their own project or want to write additional file system drivers. \section goals Design Goals File System Wrapper wants to provide reusable, read-only file system drivers for a range of common file systems. Reusability is achieved through a common abstraction layer (called the "core"), which serves as the API for the host environment driver. Once the required glue code is written for a host environment, that host has access to all file system types implemented by FSW, with no code to be written per file system type. Why read-only? There are a range of reasons why FSW only provides read-only access: - Read-only drivers are much easier to write than read-write drivers. - Write access isn't easily abstracted in an OS-independent way because of more delicate buffer I/O handling requirements and features like journalling. - There is no risk of destroying data on the disk. - Having read access is much better than having no access at all. (Read-only drivers for several file systems can be written in the time it would take to develop a read-write driver for just one file system.) - Boot loaders only need read access in most cases. \section model Object and Data Model \subsection main_objects Main Objects There are three main "objects" that FSW works with: volume, dnode, and shandle. The fsw_volume structure keeps the information that applies to a file system volume as a whole. Most importantly, it keeps pointers to the host driver and file system driver dispatch tables, which are used by the core to call the appropriate functions. The fsw_dnode structure represents a "directory node", that is any file-like object in the file system: regular files, directories, symbolic links as well as special files like device nodes. When compared with Unix-style file systems, a dnode is very similar to an inode, but it retains some essential information from the directory: the canonical name and the parent directory. FSW requires that a dnode is uniquely identified by an integer number (currently 32 bit in size). Inode numbers can be used for this purpose, non-Unix file systems will have to come up with a unique number in some way. The fsw_shandle structure is used to access file data ("storage handle"). A dnode only represents the file as such and doesn't offer access to its data. An shandle is linked to a certain dnode, but there may be several shandles per dnode. The shandle stores a file position pointer (byte offset) that can be changed at will. With the current design, an shandle is also used for directory iteration, even if the file system stores directory information in a central tree structure. \subsection disk_access Disk Data Access Data on the disk is accessed in blocks, addressed by a sequential number starting at zero. The block size to use can be set by the file system driver. FSW supports two separate block sizes: the "physical block size" is used when accessing the disk, the "logical block size" is used when accessing a file's data. For most file systems, these two are identical, but there may be some where the file allocation block size is larger than the sector or block size used to store metadata. (FAT comes to mind as an example.) For accessing the actual file data, the file system driver doesn't handle the disk I/O, but merely returns information about the mapping from file logical blocks to disk physical blocks in the fsw_extent structure. This allows host OS buffer mechanisms to be used for file data. In special cases, like tail-packing, fragments or compressed file systems, the file system driver can return file data in an allocated buffer. \subsection data_hooks Data Extension Hooks File system specific data can be stored by extending the fsw_volume and fsw_dnode structures. The core code uses the structure sizes stored in the fsw_fstype_table to allocate memory for these structures. The fsw_shandle and fsw_extent structures are not designed to be extended. Host specific data must be stored in separate structures private to the host environment driver. The fsw_volume structure provides a host_data variable to store a pointer. The fsw_dnode structure has no such field, because it is assumed that all actions regarding dnodes are initiated on the host side and so the host-specific private structure is known. \section callconv Calling Conventions All functions that can fail return a status code in a fsw_status_t. This type is an integer. A boolean test yields true if there was an error and false if the function executed successfully, i.e. success is signalled by a 0 return value. Functions that return data do so either by filling a structure passed in by the caller, or by allocating a structure on the heap and returning a pointer through a double-indirect parameter. A returned object pointer is the last parameter in the parameter list. (More to be written about specific conventions for dnodes, shandles, strings.) */ ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/zstd/���������������������������������������������������������������������0000775�0001750�0001750�00000000000�13363346003�016646� 5����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/zstd/xxhash.h�������������������������������������������������������������0000644�0001750�0001750�00000012436�13363346003�020326� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * xxHash - Extremely Fast Hash algorithm * Copyright (C) 2012-2016, Yann Collet. * * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License version 2 as published by the * Free Software Foundation. This program is dual-licensed; you may select * either version 2 of the GNU General Public License ("GPL") or BSD license * ("BSD"). * * You can contact the author at: * - xxHash homepage: http://cyan4973.github.io/xxHash/ * - xxHash source repository: https://github.com/Cyan4973/xxHash */ /* * Notice extracted from xxHash homepage: * * xxHash is an extremely fast Hash algorithm, running at RAM speed limits. * It also successfully passes all tests from the SMHasher suite. * * Comparison (single thread, Windows Seven 32 bits, using SMHasher on a Core 2 * Duo @3GHz) * * Name Speed Q.Score Author * xxHash 5.4 GB/s 10 * CrapWow 3.2 GB/s 2 Andrew * MumurHash 3a 2.7 GB/s 10 Austin Appleby * SpookyHash 2.0 GB/s 10 Bob Jenkins * SBox 1.4 GB/s 9 Bret Mulvey * Lookup3 1.2 GB/s 9 Bob Jenkins * SuperFastHash 1.2 GB/s 1 Paul Hsieh * CityHash64 1.05 GB/s 10 Pike & Alakuijala * FNV 0.55 GB/s 5 Fowler, Noll, Vo * CRC32 0.43 GB/s 9 * MD5-32 0.33 GB/s 10 Ronald L. Rivest * SHA1-32 0.28 GB/s 10 * * Q.Score is a measure of quality of the hash function. * It depends on successfully passing SMHasher test set. * 10 is a perfect score. * * A 64-bits version, named xxh64 offers much better speed, * but for 64-bits applications only. * Name Speed on 64 bits Speed on 32 bits * xxh64 13.8 GB/s 1.9 GB/s * xxh32 6.8 GB/s 6.0 GB/s */ #ifndef XXHASH_H #define XXHASH_H /** * xxh64() - calculate the 64-bit hash of the input with a given seed. * * @input: The data to hash. * @length: The length of the data to hash. * @seed: The seed can be used to alter the result predictably. * * This function runs 2x faster on 64-bit systems, but slower on 32-bit systems. * * Return: The 64-bit hash of the data. */ uint64_t xxh64(const void *input, size_t length, uint64_t seed); /*-**************************** * Streaming Hash Functions *****************************/ /* * These definitions are only meant to allow allocation of XXH state * statically, on stack, or in a struct for example. * Do not use members directly. */ /** * struct xxh32_state - private xxh64 state, do not use members directly */ struct xxh64_state { uint64_t total_len; uint64_t v1; uint64_t v2; uint64_t v3; uint64_t v4; uint64_t mem64[4]; uint32_t memsize; }; /** * xxh64_reset() - reset the xxh64 state to start a new hashing operation * * @state: The xxh64 state to reset. * @seed: Initialize the hash state with this seed. */ void xxh64_reset(struct xxh64_state *state, uint64_t seed); /** * xxh64_update() - hash the data given and update the xxh64 state * @state: The xxh64 state to update. * @input: The data to hash. * @length: The length of the data to hash. * * After calling xxh64_reset() call xxh64_update() as many times as necessary. * * Return: Zero on success, otherwise an error code. */ int xxh64_update(struct xxh64_state *state, const void *input, size_t length); /** * xxh64_digest() - produce the current xxh64 hash * * @state: Produce the current xxh64 hash of this state. * * A hash value can be produced at any time. It is still possible to continue * inserting input into the hash state after a call to xxh64_digest(), and * generate new hashes later on, by calling xxh64_digest() again. * * Return: The xxh64 hash stored in the state. */ uint64_t xxh64_digest(const struct xxh64_state *state); /*-************************** * Utils ***************************/ #endif /* XXHASH_H */ ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/zstd/xxhash64.c�����������������������������������������������������������0000644�0001750�0001750�00000014212�13363346003�020465� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * xxHash - Extremely Fast Hash algorithm * Copyright (C) 2012-2016, Yann Collet. * * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License version 2 as published by the * Free Software Foundation. This program is dual-licensed; you may select * either version 2 of the GNU General Public License ("GPL") or BSD license * ("BSD"). * * You can contact the author at: * - xxHash homepage: http://cyan4973.github.io/xxHash/ * - xxHash source repository: https://github.com/Cyan4973/xxHash */ #include "xxhash.h" /*-************************************* * Macros **************************************/ #define xxh_rotl64(x, r) ((x << r) | (x >> (64 - r))) #ifdef __LITTLE_ENDIAN # define XXH_CPU_LITTLE_ENDIAN 1 #else # define XXH_CPU_LITTLE_ENDIAN 0 #endif /*-************************************* * Constants **************************************/ static const uint64_t PRIME64_1 = 11400714785074694791ULL; static const uint64_t PRIME64_2 = 14029467366897019727ULL; static const uint64_t PRIME64_3 = 1609587929392839161ULL; static const uint64_t PRIME64_4 = 9650029242287828579ULL; static const uint64_t PRIME64_5 = 2870177450012600261ULL; /*-************************** * Utils ***************************/ static uint64_t xxh64_round(uint64_t acc, const uint64_t input) { acc += input * PRIME64_2; acc = xxh_rotl64(acc, 31); acc *= PRIME64_1; return acc; } static uint64_t xxh64_merge_round(uint64_t acc, uint64_t val) { val = xxh64_round(0, val); acc ^= val; acc = acc * PRIME64_1 + PRIME64_4; return acc; } /*-************************************************** * Advanced Hash Functions ***************************************************/ void xxh64_reset(struct xxh64_state *statePtr, const uint64_t seed) { /* use a local state for memcpy() to avoid strict-aliasing warnings */ struct xxh64_state state; memset(&state, 0, sizeof(state)); state.v1 = seed + PRIME64_1 + PRIME64_2; state.v2 = seed + PRIME64_2; state.v3 = seed + 0; state.v4 = seed - PRIME64_1; memcpy(statePtr, &state, sizeof(state)); } int xxh64_update(struct xxh64_state *state, const void *input, const size_t len) { const uint8_t *p = (const uint8_t *)input; const uint8_t *const b_end = p + len; if (input == NULL) return -1; state->total_len += len; if (state->memsize + len < 32) { /* fill in tmp buffer */ memcpy(((uint8_t *)state->mem64) + state->memsize, input, len); state->memsize += (uint32_t)len; return 0; } if (state->memsize) { /* tmp buffer is full */ uint64_t *p64 = state->mem64; memcpy(((uint8_t *)p64) + state->memsize, input, 32 - state->memsize); state->v1 = xxh64_round(state->v1, get_unaligned_le64(p64)); p64++; state->v2 = xxh64_round(state->v2, get_unaligned_le64(p64)); p64++; state->v3 = xxh64_round(state->v3, get_unaligned_le64(p64)); p64++; state->v4 = xxh64_round(state->v4, get_unaligned_le64(p64)); p += 32 - state->memsize; state->memsize = 0; } if (p + 32 <= b_end) { const uint8_t *const limit = b_end - 32; uint64_t v1 = state->v1; uint64_t v2 = state->v2; uint64_t v3 = state->v3; uint64_t v4 = state->v4; do { v1 = xxh64_round(v1, get_unaligned_le64(p)); p += 8; v2 = xxh64_round(v2, get_unaligned_le64(p)); p += 8; v3 = xxh64_round(v3, get_unaligned_le64(p)); p += 8; v4 = xxh64_round(v4, get_unaligned_le64(p)); p += 8; } while (p <= limit); state->v1 = v1; state->v2 = v2; state->v3 = v3; state->v4 = v4; } if (p < b_end) { memcpy(state->mem64, p, (size_t)(b_end-p)); state->memsize = (uint32_t)(b_end - p); } return 0; } uint64_t xxh64_digest(const struct xxh64_state *state) { const uint8_t *p = (const uint8_t *)state->mem64; const uint8_t *const b_end = (const uint8_t *)state->mem64 + state->memsize; uint64_t h64; if (state->total_len >= 32) { const uint64_t v1 = state->v1; const uint64_t v2 = state->v2; const uint64_t v3 = state->v3; const uint64_t v4 = state->v4; h64 = xxh_rotl64(v1, 1) + xxh_rotl64(v2, 7) + xxh_rotl64(v3, 12) + xxh_rotl64(v4, 18); h64 = xxh64_merge_round(h64, v1); h64 = xxh64_merge_round(h64, v2); h64 = xxh64_merge_round(h64, v3); h64 = xxh64_merge_round(h64, v4); } else { h64 = state->v3 + PRIME64_5; } h64 += (uint64_t)state->total_len; while (p + 8 <= b_end) { const uint64_t k1 = xxh64_round(0, get_unaligned_le64(p)); h64 ^= k1; h64 = xxh_rotl64(h64, 27) * PRIME64_1 + PRIME64_4; p += 8; } if (p + 4 <= b_end) { h64 ^= (uint64_t)(get_unaligned_le32(p)) * PRIME64_1; h64 = xxh_rotl64(h64, 23) * PRIME64_2 + PRIME64_3; p += 4; } while (p < b_end) { h64 ^= (*p) * PRIME64_5; h64 = xxh_rotl64(h64, 11) * PRIME64_1; p++; } h64 ^= h64 >> 33; h64 *= PRIME64_2; h64 ^= h64 >> 29; h64 *= PRIME64_3; h64 ^= h64 >> 32; return h64; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/zstd/fse.h����������������������������������������������������������������0000644�0001750�0001750�00000053125�13363346003�017600� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * FSE : Finite State Entropy codec * Public Prototypes declaration * Copyright (C) 2013-2016, Yann Collet. * * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License version 2 as published by the * Free Software Foundation. This program is dual-licensed; you may select * either version 2 of the GNU General Public License ("GPL") or BSD license * ("BSD"). * * You can contact the author at : * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy */ #ifndef FSE_H #define FSE_H /*-***************************************** * Dependencies ******************************************/ /*-***************************************** * FSE_PUBLIC_API : control library symbols visibility ******************************************/ #define FSE_PUBLIC_API /*------ Version ------*/ #define FSE_VERSION_MAJOR 0 #define FSE_VERSION_MINOR 9 #define FSE_VERSION_RELEASE 0 #define FSE_LIB_VERSION FSE_VERSION_MAJOR.FSE_VERSION_MINOR.FSE_VERSION_RELEASE #define FSE_QUOTE(str) #str #define FSE_EXPAND_AND_QUOTE(str) FSE_QUOTE(str) #define FSE_VERSION_STRING FSE_EXPAND_AND_QUOTE(FSE_LIB_VERSION) #define FSE_VERSION_NUMBER (FSE_VERSION_MAJOR * 100 * 100 + FSE_VERSION_MINOR * 100 + FSE_VERSION_RELEASE) FSE_PUBLIC_API unsigned FSE_versionNumber(void); /**< library version number; to be used when checking dll version */ /*-***************************************** * Tool functions ******************************************/ FSE_PUBLIC_API size_t FSE_compressBound(size_t size); /* maximum compressed size */ /* Error Management */ FSE_PUBLIC_API unsigned FSE_isError(size_t code); /* tells if a return value is an error code */ /*-***************************************** * FSE detailed API ******************************************/ /*! FSE_compress() does the following: 1. count symbol occurrence from source[] into table count[] 2. normalize counters so that sum(count[]) == Power_of_2 (2^tableLog) 3. save normalized counters to memory buffer using writeNCount() 4. build encoding table 'CTable' from normalized counters 5. encode the data stream using encoding table 'CTable' FSE_decompress() does the following: 1. read normalized counters with readNCount() 2. build decoding table 'DTable' from normalized counters 3. decode the data stream using decoding table 'DTable' The following API allows targeting specific sub-functions for advanced tasks. For example, it's possible to compress several blocks using the same 'CTable', or to save and provide normalized distribution using external method. */ /* *** COMPRESSION *** */ /*! FSE_optimalTableLog(): dynamically downsize 'tableLog' when conditions are met. It saves CPU time, by using smaller tables, while preserving or even improving compression ratio. @return : recommended tableLog (necessarily <= 'maxTableLog') */ FSE_PUBLIC_API unsigned FSE_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue); /*! FSE_normalizeCount(): normalize counts so that sum(count[]) == Power_of_2 (2^tableLog) 'normalizedCounter' is a table of short, of minimum size (maxSymbolValue+1). @return : tableLog, or an errorCode, which can be tested using FSE_isError() */ FSE_PUBLIC_API size_t FSE_normalizeCount(short *normalizedCounter, unsigned tableLog, const unsigned *count, size_t srcSize, unsigned maxSymbolValue); /*! FSE_NCountWriteBound(): Provides the maximum possible size of an FSE normalized table, given 'maxSymbolValue' and 'tableLog'. Typically useful for allocation purpose. */ FSE_PUBLIC_API size_t FSE_NCountWriteBound(unsigned maxSymbolValue, unsigned tableLog); /*! FSE_writeNCount(): Compactly save 'normalizedCounter' into 'buffer'. @return : size of the compressed table, or an errorCode, which can be tested using FSE_isError(). */ FSE_PUBLIC_API size_t FSE_writeNCount(void *buffer, size_t bufferSize, const short *normalizedCounter, unsigned maxSymbolValue, unsigned tableLog); /*! Constructor and Destructor of FSE_CTable. Note that FSE_CTable size depends on 'tableLog' and 'maxSymbolValue' */ typedef unsigned FSE_CTable; /* don't allocate that. It's only meant to be more restrictive than void* */ /*! FSE_compress_usingCTable(): Compress `src` using `ct` into `dst` which must be already allocated. @return : size of compressed data (<= `dstCapacity`), or 0 if compressed data could not fit into `dst`, or an errorCode, which can be tested using FSE_isError() */ FSE_PUBLIC_API size_t FSE_compress_usingCTable(void *dst, size_t dstCapacity, const void *src, size_t srcSize, const FSE_CTable *ct); /*! Tutorial : ---------- The first step is to count all symbols. FSE_count() does this job very fast. Result will be saved into 'count', a table of unsigned int, which must be already allocated, and have 'maxSymbolValuePtr[0]+1' cells. 'src' is a table of bytes of size 'srcSize'. All values within 'src' MUST be <= maxSymbolValuePtr[0] maxSymbolValuePtr[0] will be updated, with its real value (necessarily <= original value) FSE_count() will return the number of occurrence of the most frequent symbol. This can be used to know if there is a single symbol within 'src', and to quickly evaluate its compressibility. If there is an error, the function will return an ErrorCode (which can be tested using FSE_isError()). The next step is to normalize the frequencies. FSE_normalizeCount() will ensure that sum of frequencies is == 2 ^'tableLog'. It also guarantees a minimum of 1 to any Symbol with frequency >= 1. You can use 'tableLog'==0 to mean "use default tableLog value". If you are unsure of which tableLog value to use, you can ask FSE_optimalTableLog(), which will provide the optimal valid tableLog given sourceSize, maxSymbolValue, and a user-defined maximum (0 means "default"). The result of FSE_normalizeCount() will be saved into a table, called 'normalizedCounter', which is a table of signed short. 'normalizedCounter' must be already allocated, and have at least 'maxSymbolValue+1' cells. The return value is tableLog if everything proceeded as expected. It is 0 if there is a single symbol within distribution. If there is an error (ex: invalid tableLog value), the function will return an ErrorCode (which can be tested using FSE_isError()). 'normalizedCounter' can be saved in a compact manner to a memory area using FSE_writeNCount(). 'buffer' must be already allocated. For guaranteed success, buffer size must be at least FSE_headerBound(). The result of the function is the number of bytes written into 'buffer'. If there is an error, the function will return an ErrorCode (which can be tested using FSE_isError(); ex : buffer size too small). 'normalizedCounter' can then be used to create the compression table 'CTable'. The space required by 'CTable' must be already allocated, using FSE_createCTable(). You can then use FSE_buildCTable() to fill 'CTable'. If there is an error, both functions will return an ErrorCode (which can be tested using FSE_isError()). 'CTable' can then be used to compress 'src', with FSE_compress_usingCTable(). Similar to FSE_count(), the convention is that 'src' is assumed to be a table of char of size 'srcSize' The function returns the size of compressed data (without header), necessarily <= `dstCapacity`. If it returns '0', compressed data could not fit into 'dst'. If there is an error, the function will return an ErrorCode (which can be tested using FSE_isError()). */ /* *** DECOMPRESSION *** */ /*! FSE_readNCount(): Read compactly saved 'normalizedCounter' from 'rBuffer'. @return : size read from 'rBuffer', or an errorCode, which can be tested using FSE_isError(). maxSymbolValuePtr[0] and tableLogPtr[0] will also be updated with their respective values */ FSE_PUBLIC_API size_t FSE_readNCount(short *normalizedCounter, unsigned *maxSymbolValuePtr, unsigned *tableLogPtr, const void *rBuffer, size_t rBuffSize); /*! Constructor and Destructor of FSE_DTable. Note that its size depends on 'tableLog' */ typedef unsigned FSE_DTable; /* don't allocate that. It's just a way to be more restrictive than void* */ /*! FSE_buildDTable(): Builds 'dt', which must be already allocated, using FSE_createDTable(). return : 0, or an errorCode, which can be tested using FSE_isError() */ FSE_PUBLIC_API size_t FSE_buildDTable_wksp(FSE_DTable *dt, const short *normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void *workspace, size_t workspaceSize); /*! FSE_decompress_usingDTable(): Decompress compressed source `cSrc` of size `cSrcSize` using `dt` into `dst` which must be already allocated. @return : size of regenerated data (necessarily <= `dstCapacity`), or an errorCode, which can be tested using FSE_isError() */ FSE_PUBLIC_API size_t FSE_decompress_usingDTable(void *dst, size_t dstCapacity, const void *cSrc, size_t cSrcSize, const FSE_DTable *dt); /*! Tutorial : ---------- (Note : these functions only decompress FSE-compressed blocks. If block is uncompressed, use memcpy() instead If block is a single repeated byte, use memset() instead ) The first step is to obtain the normalized frequencies of symbols. This can be performed by FSE_readNCount() if it was saved using FSE_writeNCount(). 'normalizedCounter' must be already allocated, and have at least 'maxSymbolValuePtr[0]+1' cells of signed short. In practice, that means it's necessary to know 'maxSymbolValue' beforehand, or size the table to handle worst case situations (typically 256). FSE_readNCount() will provide 'tableLog' and 'maxSymbolValue'. The result of FSE_readNCount() is the number of bytes read from 'rBuffer'. Note that 'rBufferSize' must be at least 4 bytes, even if useful information is less than that. If there is an error, the function will return an error code, which can be tested using FSE_isError(). The next step is to build the decompression tables 'FSE_DTable' from 'normalizedCounter'. This is performed by the function FSE_buildDTable(). The space required by 'FSE_DTable' must be already allocated using FSE_createDTable(). If there is an error, the function will return an error code, which can be tested using FSE_isError(). `FSE_DTable` can then be used to decompress `cSrc`, with FSE_decompress_usingDTable(). `cSrcSize` must be strictly correct, otherwise decompression will fail. FSE_decompress_usingDTable() result will tell how many bytes were regenerated (<=`dstCapacity`). If there is an error, the function will return an error code, which can be tested using FSE_isError(). (ex: dst buffer too small) */ /* *** Dependency *** */ #include "bitstream.h" /* ***************************************** * Static allocation *******************************************/ /* FSE buffer bounds */ #define FSE_NCOUNTBOUND 512 #define FSE_BLOCKBOUND(size) (size + (size >> 7)) #define FSE_COMPRESSBOUND(size) (FSE_NCOUNTBOUND + FSE_BLOCKBOUND(size)) /* Macro version, useful for static allocation */ /* It is possible to statically allocate FSE CTable/DTable as a table of FSE_CTable/FSE_DTable using below macros */ #define FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) (1 + (1 << (maxTableLog - 1)) + ((maxSymbolValue + 1) * 2)) #define FSE_DTABLE_SIZE_U32(maxTableLog) (1 + (1 << maxTableLog)) /* ***************************************** * FSE advanced API *******************************************/ /* FSE_count_wksp() : * Same as FSE_count(), but using an externally provided scratch buffer. * `workSpace` size must be table of >= `1024` unsigned */ size_t FSE_count_wksp(unsigned *count, unsigned *maxSymbolValuePtr, const void *source, size_t sourceSize, unsigned *workSpace); /* FSE_countFast_wksp() : * Same as FSE_countFast(), but using an externally provided scratch buffer. * `workSpace` must be a table of minimum `1024` unsigned */ size_t FSE_countFast_wksp(unsigned *count, unsigned *maxSymbolValuePtr, const void *src, size_t srcSize, unsigned *workSpace); /*! FSE_count_simple * Same as FSE_countFast(), but does not use any additional memory (not even on stack). * This function is unsafe, and will segfault if any value within `src` is `> *maxSymbolValuePtr` (presuming it's also the size of `count`). */ size_t FSE_count_simple(unsigned *count, unsigned *maxSymbolValuePtr, const void *src, size_t srcSize); unsigned FSE_optimalTableLog_internal(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue, unsigned minus); /**< same as FSE_optimalTableLog(), which used `minus==2` */ size_t FSE_buildCTable_raw(FSE_CTable *ct, unsigned nbBits); /**< build a fake FSE_CTable, designed for a flat distribution, where each symbol uses nbBits */ size_t FSE_buildCTable_rle(FSE_CTable *ct, unsigned char symbolValue); /**< build a fake FSE_CTable, designed to compress always the same symbolValue */ /* FSE_buildCTable_wksp() : * Same as FSE_buildCTable(), but using an externally allocated scratch buffer (`workSpace`). * `wkspSize` must be >= `(1<<tableLog)`. */ size_t FSE_buildCTable_wksp(FSE_CTable *ct, const short *normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void *workSpace, size_t wkspSize); size_t FSE_buildDTable_raw(FSE_DTable *dt, unsigned nbBits); /**< build a fake FSE_DTable, designed to read a flat distribution where each symbol uses nbBits */ size_t FSE_buildDTable_rle(FSE_DTable *dt, unsigned char symbolValue); /**< build a fake FSE_DTable, designed to always generate the same symbolValue */ size_t FSE_decompress_wksp(void *dst, size_t dstCapacity, const void *cSrc, size_t cSrcSize, unsigned maxLog, void *workspace, size_t workspaceSize); /**< same as FSE_decompress(), using an externally allocated `workSpace` produced with `FSE_DTABLE_SIZE_U32(maxLog)` */ /* ***************************************** * FSE symbol decompression API *******************************************/ typedef struct { size_t state; const void *table; /* precise table may vary, depending on U16 */ } FSE_DState_t; static void FSE_initDState(FSE_DState_t *DStatePtr, BIT_DStream_t *bitD, const FSE_DTable *dt); static unsigned char FSE_decodeSymbol(FSE_DState_t *DStatePtr, BIT_DStream_t *bitD); static unsigned FSE_endOfDState(const FSE_DState_t *DStatePtr); /**< Let's now decompose FSE_decompress_usingDTable() into its unitary components. You will decode FSE-encoded symbols from the bitStream, and also any other bitFields you put in, **in reverse order**. You will need a few variables to track your bitStream. They are : BIT_DStream_t DStream; // Stream context FSE_DState_t DState; // State context. Multiple ones are possible FSE_DTable* DTablePtr; // Decoding table, provided by FSE_buildDTable() The first thing to do is to init the bitStream. errorCode = BIT_initDStream(&DStream, srcBuffer, srcSize); You should then retrieve your initial state(s) (in reverse flushing order if you have several ones) : errorCode = FSE_initDState(&DState, &DStream, DTablePtr); You can then decode your data, symbol after symbol. For information the maximum number of bits read by FSE_decodeSymbol() is 'tableLog'. Keep in mind that symbols are decoded in reverse order, like a LIFO stack (last in, first out). unsigned char symbol = FSE_decodeSymbol(&DState, &DStream); You can retrieve any bitfield you eventually stored into the bitStream (in reverse order) Note : maximum allowed nbBits is 25, for 32-bits compatibility size_t bitField = BIT_readBits(&DStream, nbBits); All above operations only read from local register (which size depends on size_t). Refueling the register from memory is manually performed by the reload method. endSignal = FSE_reloadDStream(&DStream); BIT_reloadDStream() result tells if there is still some more data to read from DStream. BIT_DStream_unfinished : there is still some data left into the DStream. BIT_DStream_endOfBuffer : Dstream reached end of buffer. Its container may no longer be completely filled. BIT_DStream_completed : Dstream reached its exact end, corresponding in general to decompression completed. BIT_DStream_tooFar : Dstream went too far. Decompression result is corrupted. When reaching end of buffer (BIT_DStream_endOfBuffer), progress slowly, notably if you decode multiple symbols per loop, to properly detect the exact end of stream. After each decoded symbol, check if DStream is fully consumed using this simple test : BIT_reloadDStream(&DStream) >= BIT_DStream_completed When it's done, verify decompression is fully completed, by checking both DStream and the relevant states. Checking if DStream has reached its end is performed by : BIT_endOfDStream(&DStream); Check also the states. There might be some symbols left there, if some high probability ones (>50%) are possible. FSE_endOfDState(&DState); */ /* ***************************************** * FSE unsafe API *******************************************/ static unsigned char FSE_decodeSymbolFast(FSE_DState_t *DStatePtr, BIT_DStream_t *bitD); /* faster, but works only if nbBits is always >= 1 (otherwise, result will be corrupted) */ /* ====== Decompression ====== */ typedef struct { U16 tableLog; U16 fastMode; } FSE_DTableHeader; /* sizeof U32 */ typedef struct { unsigned short newState; unsigned char symbol; unsigned char nbBits; } FSE_decode_t; /* size == U32 */ ZSTD_STATIC void FSE_initDState(FSE_DState_t *DStatePtr, BIT_DStream_t *bitD, const FSE_DTable *dt) { const void *ptr = dt; const FSE_DTableHeader *const DTableH = (const FSE_DTableHeader *)ptr; DStatePtr->state = BIT_readBits(bitD, DTableH->tableLog); BIT_reloadDStream(bitD); DStatePtr->table = dt + 1; } ZSTD_STATIC BYTE FSE_peekSymbol(const FSE_DState_t *DStatePtr) { FSE_decode_t const DInfo = ((const FSE_decode_t *)(DStatePtr->table))[DStatePtr->state]; return DInfo.symbol; } ZSTD_STATIC void FSE_updateState(FSE_DState_t *DStatePtr, BIT_DStream_t *bitD) { FSE_decode_t const DInfo = ((const FSE_decode_t *)(DStatePtr->table))[DStatePtr->state]; U32 const nbBits = DInfo.nbBits; size_t const lowBits = BIT_readBits(bitD, nbBits); DStatePtr->state = DInfo.newState + lowBits; } ZSTD_STATIC BYTE FSE_decodeSymbol(FSE_DState_t *DStatePtr, BIT_DStream_t *bitD) { FSE_decode_t const DInfo = ((const FSE_decode_t *)(DStatePtr->table))[DStatePtr->state]; U32 const nbBits = DInfo.nbBits; BYTE const symbol = DInfo.symbol; size_t const lowBits = BIT_readBits(bitD, nbBits); DStatePtr->state = DInfo.newState + lowBits; return symbol; } /*! FSE_decodeSymbolFast() : unsafe, only works if no symbol has a probability > 50% */ ZSTD_STATIC BYTE FSE_decodeSymbolFast(FSE_DState_t *DStatePtr, BIT_DStream_t *bitD) { FSE_decode_t const DInfo = ((const FSE_decode_t *)(DStatePtr->table))[DStatePtr->state]; U32 const nbBits = DInfo.nbBits; BYTE const symbol = DInfo.symbol; size_t const lowBits = BIT_readBitsFast(bitD, nbBits); DStatePtr->state = DInfo.newState + lowBits; return symbol; } ZSTD_STATIC unsigned FSE_endOfDState(const FSE_DState_t *DStatePtr) { return DStatePtr->state == 0; } /* ************************************************************** * Tuning parameters ****************************************************************/ /*!MEMORY_USAGE : * Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.) * Increasing memory usage improves compression ratio * Reduced memory usage can improve speed, due to cache effect * Recommended max value is 14, for 16KB, which nicely fits into Intel x86 L1 cache */ #ifndef FSE_MAX_MEMORY_USAGE #define FSE_MAX_MEMORY_USAGE 14 #endif #ifndef FSE_DEFAULT_MEMORY_USAGE #define FSE_DEFAULT_MEMORY_USAGE 13 #endif /*!FSE_MAX_SYMBOL_VALUE : * Maximum symbol value authorized. * Required for proper stack allocation */ #ifndef FSE_MAX_SYMBOL_VALUE #define FSE_MAX_SYMBOL_VALUE 255 #endif /* ************************************************************** * template functions type & suffix ****************************************************************/ #define FSE_FUNCTION_TYPE BYTE #define FSE_FUNCTION_EXTENSION #define FSE_DECODE_TYPE FSE_decode_t /* *************************************************************** * Constants *****************************************************************/ #define FSE_MAX_TABLELOG (FSE_MAX_MEMORY_USAGE - 2) #define FSE_MAX_TABLESIZE (1U << FSE_MAX_TABLELOG) #define FSE_MAXTABLESIZE_MASK (FSE_MAX_TABLESIZE - 1) #define FSE_DEFAULT_TABLELOG (FSE_DEFAULT_MEMORY_USAGE - 2) #define FSE_MIN_TABLELOG 5 #define FSE_TABLELOG_ABSOLUTE_MAX 15 #if FSE_MAX_TABLELOG > FSE_TABLELOG_ABSOLUTE_MAX #error "FSE_MAX_TABLELOG > FSE_TABLELOG_ABSOLUTE_MAX is not supported" #endif #define FSE_TABLESTEP(tableSize) ((tableSize >> 1) + (tableSize >> 3) + 3) #endif /* FSE_H */ �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/zstd/mem.h����������������������������������������������������������������0000644�0001750�0001750�00000004442�13363346003�017577� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/** * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of https://github.com/facebook/zstd. * An additional grant of patent rights can be found in the PATENTS file in the * same directory. * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License version 2 as published by the * Free Software Foundation. This program is dual-licensed; you may select * either version 2 of the GNU General Public License ("GPL") or BSD license * ("BSD"). */ #ifndef MEM_H_MODULE #define MEM_H_MODULE /*-**************************************** * Dependencies ******************************************/ /*-**************************************** * Compiler specifics ******************************************/ #define ZSTD_STATIC static __inline __attribute__((unused)) /*-************************************************************** * Basic Types *****************************************************************/ typedef uint8_t BYTE; typedef uint16_t U16; typedef int16_t S16; typedef uint32_t U32; typedef int32_t S32; typedef uint64_t U64; typedef int64_t S64; typedef ptrdiff_t iPtrDiff; typedef uintptr_t uPtrDiff; /*-************************************************************** * Memory I/O *****************************************************************/ ZSTD_STATIC unsigned ZSTD_32bits(void) { return sizeof(size_t) == 4; } ZSTD_STATIC unsigned ZSTD_64bits(void) { return sizeof(size_t) == 8; } /*=== Little endian r/w ===*/ ZSTD_STATIC U16 ZSTD_readLE16(const void *memPtr) { return get_unaligned_le16(memPtr); } ZSTD_STATIC void ZSTD_writeLE16(void *memPtr, U16 val) { put_unaligned_le16(val, memPtr); } ZSTD_STATIC U32 ZSTD_readLE24(const void *memPtr) { return ZSTD_readLE16(memPtr) + (((const BYTE *)memPtr)[2] << 16); } ZSTD_STATIC U32 ZSTD_readLE32(const void *memPtr) { return get_unaligned_le32(memPtr); } ZSTD_STATIC U64 ZSTD_readLE64(const void *memPtr) { return get_unaligned_le64(memPtr); } ZSTD_STATIC size_t ZSTD_readLEST(const void *memPtr) { if (ZSTD_32bits()) return (size_t)ZSTD_readLE32(memPtr); else return (size_t)ZSTD_readLE64(memPtr); } #endif /* MEM_H_MODULE */ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/zstd/fse_decompress.c�����������������������������������������������������0000644�0001750�0001750�00000030572�13363346003�022020� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * FSE : Finite State Entropy decoder * Copyright (C) 2013-2015, Yann Collet. * * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License version 2 as published by the * Free Software Foundation. This program is dual-licensed; you may select * either version 2 of the GNU General Public License ("GPL") or BSD license * ("BSD"). * * You can contact the author at : * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy */ /* ************************************************************** * Compiler specifics ****************************************************************/ #define FORCE_INLINE static __always_inline /* ************************************************************** * Includes ****************************************************************/ #include "bitstream.h" #include "fse.h" /* ************************************************************** * Error Management ****************************************************************/ #define FSE_STATIC_ASSERT(c) \ { \ enum { FSE_static_assert = 1 / (int)(!!(c)) }; \ } /* use only *after* variable declarations */ /* ************************************************************** * Templates ****************************************************************/ /* designed to be included for type-specific functions (template emulation in C) Objective is to write these functions only once, for improved maintenance */ /* safety checks */ #ifndef FSE_FUNCTION_EXTENSION #error "FSE_FUNCTION_EXTENSION must be defined" #endif #ifndef FSE_FUNCTION_TYPE #error "FSE_FUNCTION_TYPE must be defined" #endif /* Function names */ #define FSE_CAT(X, Y) X##Y #define FSE_FUNCTION_NAME(X, Y) FSE_CAT(X, Y) #define FSE_TYPE_NAME(X, Y) FSE_CAT(X, Y) /* Function templates */ size_t FSE_buildDTable_wksp(FSE_DTable *dt, const short *normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void *workspace, size_t workspaceSize) { void *const tdPtr = dt + 1; /* because *dt is unsigned, 32-bits aligned on 32-bits */ FSE_DECODE_TYPE *const tableDecode = (FSE_DECODE_TYPE *)(tdPtr); U16 *symbolNext = (U16 *)workspace; U32 const maxSV1 = maxSymbolValue + 1; U32 const tableSize = 1 << tableLog; U32 highThreshold = tableSize - 1; /* Sanity Checks */ if (workspaceSize < sizeof(U16) * (FSE_MAX_SYMBOL_VALUE + 1)) return ERROR(tableLog_tooLarge); if (maxSymbolValue > FSE_MAX_SYMBOL_VALUE) return ERROR(maxSymbolValue_tooLarge); if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge); /* Init, lay down lowprob symbols */ { FSE_DTableHeader DTableH; DTableH.tableLog = (U16)tableLog; DTableH.fastMode = 1; { S16 const largeLimit = (S16)(1 << (tableLog - 1)); U32 s; for (s = 0; s < maxSV1; s++) { if (normalizedCounter[s] == -1) { tableDecode[highThreshold--].symbol = (FSE_FUNCTION_TYPE)s; symbolNext[s] = 1; } else { if (normalizedCounter[s] >= largeLimit) DTableH.fastMode = 0; symbolNext[s] = normalizedCounter[s]; } } } memcpy(dt, &DTableH, sizeof(DTableH)); } /* Spread symbols */ { U32 const tableMask = tableSize - 1; U32 const step = FSE_TABLESTEP(tableSize); U32 s, position = 0; for (s = 0; s < maxSV1; s++) { int i; for (i = 0; i < normalizedCounter[s]; i++) { tableDecode[position].symbol = (FSE_FUNCTION_TYPE)s; position = (position + step) & tableMask; while (position > highThreshold) position = (position + step) & tableMask; /* lowprob area */ } } if (position != 0) return ERROR(GENERIC); /* position must reach all cells once, otherwise normalizedCounter is incorrect */ } /* Build Decoding table */ { U32 u; for (u = 0; u < tableSize; u++) { FSE_FUNCTION_TYPE const symbol = (FSE_FUNCTION_TYPE)(tableDecode[u].symbol); U16 nextState = symbolNext[symbol]++; tableDecode[u].nbBits = (BYTE)(tableLog - BIT_highbit32((U32)nextState)); tableDecode[u].newState = (U16)((nextState << tableDecode[u].nbBits) - tableSize); } } return 0; } /*-******************************************************* * Decompression (Byte symbols) *********************************************************/ size_t FSE_buildDTable_rle(FSE_DTable *dt, BYTE symbolValue) { void *ptr = dt; FSE_DTableHeader *const DTableH = (FSE_DTableHeader *)ptr; void *dPtr = dt + 1; FSE_decode_t *const cell = (FSE_decode_t *)dPtr; DTableH->tableLog = 0; DTableH->fastMode = 0; cell->newState = 0; cell->symbol = symbolValue; cell->nbBits = 0; return 0; } FORCE_INLINE size_t FSE_decompress_usingDTable_generic(void *dst, size_t maxDstSize, const void *cSrc, size_t cSrcSize, const FSE_DTable *dt, const unsigned fast) { BYTE *const ostart = (BYTE *)dst; BYTE *op = ostart; BYTE *const omax = op + maxDstSize; BYTE *const olimit = omax - 3; BIT_DStream_t bitD; FSE_DState_t state1; FSE_DState_t state2; /* Init */ CHECK_F(BIT_initDStream(&bitD, cSrc, cSrcSize)); FSE_initDState(&state1, &bitD, dt); FSE_initDState(&state2, &bitD, dt); #define FSE_GETSYMBOL(statePtr) fast ? FSE_decodeSymbolFast(statePtr, &bitD) : FSE_decodeSymbol(statePtr, &bitD) /* 4 symbols per loop */ for (; (BIT_reloadDStream(&bitD) == BIT_DStream_unfinished) & (op < olimit); op += 4) { op[0] = FSE_GETSYMBOL(&state1); if (FSE_MAX_TABLELOG * 2 + 7 > sizeof(bitD.bitContainer) * 8) /* This test must be static */ BIT_reloadDStream(&bitD); op[1] = FSE_GETSYMBOL(&state2); if (FSE_MAX_TABLELOG * 4 + 7 > sizeof(bitD.bitContainer) * 8) /* This test must be static */ { if (BIT_reloadDStream(&bitD) > BIT_DStream_unfinished) { op += 2; break; } } op[2] = FSE_GETSYMBOL(&state1); if (FSE_MAX_TABLELOG * 2 + 7 > sizeof(bitD.bitContainer) * 8) /* This test must be static */ BIT_reloadDStream(&bitD); op[3] = FSE_GETSYMBOL(&state2); } /* tail */ /* note : BIT_reloadDStream(&bitD) >= FSE_DStream_partiallyFilled; Ends at exactly BIT_DStream_completed */ while (1) { if (op > (omax - 2)) return ERROR(dstSize_tooSmall); *op++ = FSE_GETSYMBOL(&state1); if (BIT_reloadDStream(&bitD) == BIT_DStream_overflow) { *op++ = FSE_GETSYMBOL(&state2); break; } if (op > (omax - 2)) return ERROR(dstSize_tooSmall); *op++ = FSE_GETSYMBOL(&state2); if (BIT_reloadDStream(&bitD) == BIT_DStream_overflow) { *op++ = FSE_GETSYMBOL(&state1); break; } } return op - ostart; } size_t FSE_decompress_usingDTable(void *dst, size_t originalSize, const void *cSrc, size_t cSrcSize, const FSE_DTable *dt) { const void *ptr = dt; const FSE_DTableHeader *DTableH = (const FSE_DTableHeader *)ptr; const U32 fastMode = DTableH->fastMode; /* select fast mode (static) */ if (fastMode) return FSE_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 1); return FSE_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 0); } size_t FSE_decompress_wksp(void *dst, size_t dstCapacity, const void *cSrc, size_t cSrcSize, unsigned maxLog, void *workspace, size_t workspaceSize) { const BYTE *const istart = (const BYTE *)cSrc; const BYTE *ip = istart; unsigned tableLog; unsigned maxSymbolValue = FSE_MAX_SYMBOL_VALUE; size_t NCountLength; FSE_DTable *dt; short *counting; size_t spaceUsed32 = 0; FSE_STATIC_ASSERT(sizeof(FSE_DTable) == sizeof(U32)); dt = (FSE_DTable *)((U32 *)workspace + spaceUsed32); spaceUsed32 += FSE_DTABLE_SIZE_U32(maxLog); counting = (short *)((U32 *)workspace + spaceUsed32); spaceUsed32 += UP_U32(sizeof(short) * (FSE_MAX_SYMBOL_VALUE + 1)); if ((spaceUsed32 << 2) > workspaceSize) return ERROR(tableLog_tooLarge); workspace = (U32 *)workspace + spaceUsed32; workspaceSize -= (spaceUsed32 << 2); /* normal FSE decoding mode */ NCountLength = FSE_readNCount(counting, &maxSymbolValue, &tableLog, istart, cSrcSize); if (FSE_isError(NCountLength)) return NCountLength; // if (NCountLength >= cSrcSize) return ERROR(srcSize_wrong); /* too small input size; supposed to be already checked in NCountLength, only remaining // case : NCountLength==cSrcSize */ if (tableLog > maxLog) return ERROR(tableLog_tooLarge); ip += NCountLength; cSrcSize -= NCountLength; CHECK_F(FSE_buildDTable_wksp(dt, counting, maxSymbolValue, tableLog, workspace, workspaceSize)); return FSE_decompress_usingDTable(dst, dstCapacity, ip, cSrcSize, dt); /* always return, even if it is an error code */ } /*-************************************************************** * FSE NCount encoding-decoding ****************************************************************/ size_t FSE_readNCount(short *normalizedCounter, unsigned *maxSVPtr, unsigned *tableLogPtr, const void *headerBuffer, size_t hbSize) { const BYTE *const istart = (const BYTE *)headerBuffer; const BYTE *const iend = istart + hbSize; const BYTE *ip = istart; int nbBits; int remaining; int threshold; U32 bitStream; int bitCount; unsigned charnum = 0; int previous0 = 0; if (hbSize < 4) return ERROR(srcSize_wrong); bitStream = ZSTD_readLE32(ip); nbBits = (bitStream & 0xF) + FSE_MIN_TABLELOG; /* extract tableLog */ if (nbBits > FSE_TABLELOG_ABSOLUTE_MAX) return ERROR(tableLog_tooLarge); bitStream >>= 4; bitCount = 4; *tableLogPtr = nbBits; remaining = (1 << nbBits) + 1; threshold = 1 << nbBits; nbBits++; while ((remaining > 1) & (charnum <= *maxSVPtr)) { if (previous0) { unsigned n0 = charnum; while ((bitStream & 0xFFFF) == 0xFFFF) { n0 += 24; if (ip < iend - 5) { ip += 2; bitStream = ZSTD_readLE32(ip) >> bitCount; } else { bitStream >>= 16; bitCount += 16; } } while ((bitStream & 3) == 3) { n0 += 3; bitStream >>= 2; bitCount += 2; } n0 += bitStream & 3; bitCount += 2; if (n0 > *maxSVPtr) return ERROR(maxSymbolValue_tooSmall); while (charnum < n0) normalizedCounter[charnum++] = 0; if ((ip <= iend - 7) || (ip + (bitCount >> 3) <= iend - 4)) { ip += bitCount >> 3; bitCount &= 7; bitStream = ZSTD_readLE32(ip) >> bitCount; } else { bitStream >>= 2; } } { int const max = (2 * threshold - 1) - remaining; int count; if ((bitStream & (threshold - 1)) < (U32)max) { count = bitStream & (threshold - 1); bitCount += nbBits - 1; } else { count = bitStream & (2 * threshold - 1); if (count >= threshold) count -= max; bitCount += nbBits; } count--; /* extra accuracy */ remaining -= count < 0 ? -count : count; /* -1 means +1 */ normalizedCounter[charnum++] = (short)count; previous0 = !count; while (remaining < threshold) { nbBits--; threshold >>= 1; } if ((ip <= iend - 7) || (ip + (bitCount >> 3) <= iend - 4)) { ip += bitCount >> 3; bitCount &= 7; } else { bitCount -= (int)(8 * (iend - 4 - ip)); ip = iend - 4; } bitStream = ZSTD_readLE32(ip) >> (bitCount & 31); } } /* while ((remaining>1) & (charnum<=*maxSVPtr)) */ if (remaining != 1) return ERROR(corruption_detected); if (bitCount > 32) return ERROR(corruption_detected); *maxSVPtr = charnum - 1; ip += (bitCount + 7) >> 3; return ip - istart; } ��������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/zstd/huf_decompress.c�����������������������������������������������������0000644�0001750�0001750�00000076756�13363346003�022043� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Huffman decoder, part of New Generation Entropy library * Copyright (C) 2013-2016, Yann Collet. * * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License version 2 as published by the * Free Software Foundation. This program is dual-licensed; you may select * either version 2 of the GNU General Public License ("GPL") or BSD license * ("BSD"). * * You can contact the author at : * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy */ /* ************************************************************** * Compiler specifics ****************************************************************/ #define FORCE_INLINE static __always_inline /* ************************************************************** * Dependencies ****************************************************************/ #include "bitstream.h" /* BIT_* */ #include "fse.h" /* header compression */ #include "huf.h" /* ************************************************************** * Error Management ****************************************************************/ #define HUF_STATIC_ASSERT(c) \ { \ enum { HUF_static_assert = 1 / (int)(!!(c)) }; \ } /* use only *after* variable declarations */ /*-***************************/ /* generic DTableDesc */ /*-***************************/ typedef struct { BYTE maxTableLog; BYTE tableType; BYTE tableLog; BYTE reserved; } DTableDesc; static DTableDesc HUF_getDTableDesc(const HUF_DTable *table) { DTableDesc dtd; memcpy(&dtd, table, sizeof(dtd)); return dtd; } /*-***************************/ /* single-symbol decoding */ /*-***************************/ typedef struct { BYTE byte; BYTE nbBits; } HUF_DEltX2; /* single-symbol decoding */ size_t HUF_readDTableX2_wksp(HUF_DTable *DTable, const void *src, size_t srcSize, void *workspace, size_t workspaceSize) { U32 tableLog = 0; U32 nbSymbols = 0; size_t iSize; void *const dtPtr = DTable + 1; HUF_DEltX2 *const dt = (HUF_DEltX2 *)dtPtr; U32 *rankVal; BYTE *huffWeight; size_t spaceUsed32 = 0; rankVal = (U32 *)workspace + spaceUsed32; spaceUsed32 += HUF_TABLELOG_ABSOLUTEMAX + 1; huffWeight = (BYTE *)((U32 *)workspace + spaceUsed32); spaceUsed32 += UP_U32(HUF_SYMBOLVALUE_MAX + 1); if ((spaceUsed32 << 2) > workspaceSize) return ERROR(tableLog_tooLarge); workspace = (U32 *)workspace + spaceUsed32; workspaceSize -= (spaceUsed32 << 2); HUF_STATIC_ASSERT(sizeof(DTableDesc) == sizeof(HUF_DTable)); /* memset(huffWeight, 0, sizeof(huffWeight)); */ /* is not necessary, even though some analyzer complain ... */ iSize = HUF_readStats_wksp(huffWeight, HUF_SYMBOLVALUE_MAX + 1, rankVal, &nbSymbols, &tableLog, src, srcSize, workspace, workspaceSize); if (HUF_isError(iSize)) return iSize; /* Table header */ { DTableDesc dtd = HUF_getDTableDesc(DTable); if (tableLog > (U32)(dtd.maxTableLog + 1)) return ERROR(tableLog_tooLarge); /* DTable too small, Huffman tree cannot fit in */ dtd.tableType = 0; dtd.tableLog = (BYTE)tableLog; memcpy(DTable, &dtd, sizeof(dtd)); } /* Calculate starting value for each rank */ { U32 n, nextRankStart = 0; for (n = 1; n < tableLog + 1; n++) { U32 const curr = nextRankStart; nextRankStart += (rankVal[n] << (n - 1)); rankVal[n] = curr; } } /* fill DTable */ { U32 n; for (n = 0; n < nbSymbols; n++) { U32 const w = huffWeight[n]; U32 const length = (1 << w) >> 1; U32 u; HUF_DEltX2 D; D.byte = (BYTE)n; D.nbBits = (BYTE)(tableLog + 1 - w); for (u = rankVal[w]; u < rankVal[w] + length; u++) dt[u] = D; rankVal[w] += length; } } return iSize; } static BYTE HUF_decodeSymbolX2(BIT_DStream_t *Dstream, const HUF_DEltX2 *dt, const U32 dtLog) { size_t const val = BIT_lookBitsFast(Dstream, dtLog); /* note : dtLog >= 1 */ BYTE const c = dt[val].byte; BIT_skipBits(Dstream, dt[val].nbBits); return c; } #define HUF_DECODE_SYMBOLX2_0(ptr, DStreamPtr) *ptr++ = HUF_decodeSymbolX2(DStreamPtr, dt, dtLog) #define HUF_DECODE_SYMBOLX2_1(ptr, DStreamPtr) \ if (ZSTD_64bits() || (HUF_TABLELOG_MAX <= 12)) \ HUF_DECODE_SYMBOLX2_0(ptr, DStreamPtr) #define HUF_DECODE_SYMBOLX2_2(ptr, DStreamPtr) \ if (ZSTD_64bits()) \ HUF_DECODE_SYMBOLX2_0(ptr, DStreamPtr) FORCE_INLINE size_t HUF_decodeStreamX2(BYTE *p, BIT_DStream_t *const bitDPtr, BYTE *const pEnd, const HUF_DEltX2 *const dt, const U32 dtLog) { BYTE *const pStart = p; /* up to 4 symbols at a time */ while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) && (p <= pEnd - 4)) { HUF_DECODE_SYMBOLX2_2(p, bitDPtr); HUF_DECODE_SYMBOLX2_1(p, bitDPtr); HUF_DECODE_SYMBOLX2_2(p, bitDPtr); HUF_DECODE_SYMBOLX2_0(p, bitDPtr); } /* closer to the end */ while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) && (p < pEnd)) HUF_DECODE_SYMBOLX2_0(p, bitDPtr); /* no more data to retrieve from bitstream, hence no need to reload */ while (p < pEnd) HUF_DECODE_SYMBOLX2_0(p, bitDPtr); return pEnd - pStart; } static size_t HUF_decompress1X2_usingDTable_internal(void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable) { BYTE *op = (BYTE *)dst; BYTE *const oend = op + dstSize; const void *dtPtr = DTable + 1; const HUF_DEltX2 *const dt = (const HUF_DEltX2 *)dtPtr; BIT_DStream_t bitD; DTableDesc const dtd = HUF_getDTableDesc(DTable); U32 const dtLog = dtd.tableLog; { size_t const errorCode = BIT_initDStream(&bitD, cSrc, cSrcSize); if (HUF_isError(errorCode)) return errorCode; } HUF_decodeStreamX2(op, &bitD, oend, dt, dtLog); /* check */ if (!BIT_endOfDStream(&bitD)) return ERROR(corruption_detected); return dstSize; } size_t HUF_decompress1X2_DCtx_wksp(HUF_DTable *DCtx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t workspaceSize) { const BYTE *ip = (const BYTE *)cSrc; size_t const hSize = HUF_readDTableX2_wksp(DCtx, cSrc, cSrcSize, workspace, workspaceSize); if (HUF_isError(hSize)) return hSize; if (hSize >= cSrcSize) return ERROR(srcSize_wrong); ip += hSize; cSrcSize -= hSize; return HUF_decompress1X2_usingDTable_internal(dst, dstSize, ip, cSrcSize, DCtx); } static size_t HUF_decompress4X2_usingDTable_internal(void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable) { /* Check */ if (cSrcSize < 10) return ERROR(corruption_detected); /* strict minimum : jump table + 1 byte per stream */ { const BYTE *const istart = (const BYTE *)cSrc; BYTE *const ostart = (BYTE *)dst; BYTE *const oend = ostart + dstSize; const void *const dtPtr = DTable + 1; const HUF_DEltX2 *const dt = (const HUF_DEltX2 *)dtPtr; /* Init */ BIT_DStream_t bitD1; BIT_DStream_t bitD2; BIT_DStream_t bitD3; BIT_DStream_t bitD4; size_t const length1 = ZSTD_readLE16(istart); size_t const length2 = ZSTD_readLE16(istart + 2); size_t const length3 = ZSTD_readLE16(istart + 4); size_t const length4 = cSrcSize - (length1 + length2 + length3 + 6); const BYTE *const istart1 = istart + 6; /* jumpTable */ const BYTE *const istart2 = istart1 + length1; const BYTE *const istart3 = istart2 + length2; const BYTE *const istart4 = istart3 + length3; const size_t segmentSize = (dstSize + 3) / 4; BYTE *const opStart2 = ostart + segmentSize; BYTE *const opStart3 = opStart2 + segmentSize; BYTE *const opStart4 = opStart3 + segmentSize; BYTE *op1 = ostart; BYTE *op2 = opStart2; BYTE *op3 = opStart3; BYTE *op4 = opStart4; U32 endSignal; DTableDesc const dtd = HUF_getDTableDesc(DTable); U32 const dtLog = dtd.tableLog; if (length4 > cSrcSize) return ERROR(corruption_detected); /* overflow */ { size_t const errorCode = BIT_initDStream(&bitD1, istart1, length1); if (HUF_isError(errorCode)) return errorCode; } { size_t const errorCode = BIT_initDStream(&bitD2, istart2, length2); if (HUF_isError(errorCode)) return errorCode; } { size_t const errorCode = BIT_initDStream(&bitD3, istart3, length3); if (HUF_isError(errorCode)) return errorCode; } { size_t const errorCode = BIT_initDStream(&bitD4, istart4, length4); if (HUF_isError(errorCode)) return errorCode; } /* 16-32 symbols per loop (4-8 symbols per stream) */ endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4); for (; (endSignal == BIT_DStream_unfinished) && (op4 < (oend - 7));) { HUF_DECODE_SYMBOLX2_2(op1, &bitD1); HUF_DECODE_SYMBOLX2_2(op2, &bitD2); HUF_DECODE_SYMBOLX2_2(op3, &bitD3); HUF_DECODE_SYMBOLX2_2(op4, &bitD4); HUF_DECODE_SYMBOLX2_1(op1, &bitD1); HUF_DECODE_SYMBOLX2_1(op2, &bitD2); HUF_DECODE_SYMBOLX2_1(op3, &bitD3); HUF_DECODE_SYMBOLX2_1(op4, &bitD4); HUF_DECODE_SYMBOLX2_2(op1, &bitD1); HUF_DECODE_SYMBOLX2_2(op2, &bitD2); HUF_DECODE_SYMBOLX2_2(op3, &bitD3); HUF_DECODE_SYMBOLX2_2(op4, &bitD4); HUF_DECODE_SYMBOLX2_0(op1, &bitD1); HUF_DECODE_SYMBOLX2_0(op2, &bitD2); HUF_DECODE_SYMBOLX2_0(op3, &bitD3); HUF_DECODE_SYMBOLX2_0(op4, &bitD4); endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4); } /* check corruption */ if (op1 > opStart2) return ERROR(corruption_detected); if (op2 > opStart3) return ERROR(corruption_detected); if (op3 > opStart4) return ERROR(corruption_detected); /* note : op4 supposed already verified within main loop */ /* finish bitStreams one by one */ HUF_decodeStreamX2(op1, &bitD1, opStart2, dt, dtLog); HUF_decodeStreamX2(op2, &bitD2, opStart3, dt, dtLog); HUF_decodeStreamX2(op3, &bitD3, opStart4, dt, dtLog); HUF_decodeStreamX2(op4, &bitD4, oend, dt, dtLog); /* check */ endSignal = BIT_endOfDStream(&bitD1) & BIT_endOfDStream(&bitD2) & BIT_endOfDStream(&bitD3) & BIT_endOfDStream(&bitD4); if (!endSignal) return ERROR(corruption_detected); /* decoded size */ return dstSize; } } size_t HUF_decompress4X2_DCtx_wksp(HUF_DTable *dctx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t workspaceSize) { const BYTE *ip = (const BYTE *)cSrc; size_t const hSize = HUF_readDTableX2_wksp(dctx, cSrc, cSrcSize, workspace, workspaceSize); if (HUF_isError(hSize)) return hSize; if (hSize >= cSrcSize) return ERROR(srcSize_wrong); ip += hSize; cSrcSize -= hSize; return HUF_decompress4X2_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx); } /* *************************/ /* double-symbols decoding */ /* *************************/ typedef struct { U16 sequence; BYTE nbBits; BYTE length; } HUF_DEltX4; /* double-symbols decoding */ typedef struct { BYTE symbol; BYTE weight; } sortedSymbol_t; /* HUF_fillDTableX4Level2() : * `rankValOrigin` must be a table of at least (HUF_TABLELOG_MAX + 1) U32 */ static void HUF_fillDTableX4Level2(HUF_DEltX4 *DTable, U32 sizeLog, const U32 consumed, const U32 *rankValOrigin, const int minWeight, const sortedSymbol_t *sortedSymbols, const U32 sortedListSize, U32 nbBitsBaseline, U16 baseSeq) { HUF_DEltX4 DElt; U32 rankVal[HUF_TABLELOG_MAX + 1]; /* get pre-calculated rankVal */ memcpy(rankVal, rankValOrigin, sizeof(rankVal)); /* fill skipped values */ if (minWeight > 1) { U32 i, skipSize = rankVal[minWeight]; ZSTD_writeLE16(&(DElt.sequence), baseSeq); DElt.nbBits = (BYTE)(consumed); DElt.length = 1; for (i = 0; i < skipSize; i++) DTable[i] = DElt; } /* fill DTable */ { U32 s; for (s = 0; s < sortedListSize; s++) { /* note : sortedSymbols already skipped */ const U32 symbol = sortedSymbols[s].symbol; const U32 weight = sortedSymbols[s].weight; const U32 nbBits = nbBitsBaseline - weight; const U32 length = 1 << (sizeLog - nbBits); const U32 start = rankVal[weight]; U32 i = start; const U32 end = start + length; ZSTD_writeLE16(&(DElt.sequence), (U16)(baseSeq + (symbol << 8))); DElt.nbBits = (BYTE)(nbBits + consumed); DElt.length = 2; do { DTable[i++] = DElt; } while (i < end); /* since length >= 1 */ rankVal[weight] += length; } } } typedef U32 rankVal_t[HUF_TABLELOG_MAX][HUF_TABLELOG_MAX + 1]; typedef U32 rankValCol_t[HUF_TABLELOG_MAX + 1]; static void HUF_fillDTableX4(HUF_DEltX4 *DTable, const U32 targetLog, const sortedSymbol_t *sortedList, const U32 sortedListSize, const U32 *rankStart, rankVal_t rankValOrigin, const U32 maxWeight, const U32 nbBitsBaseline) { U32 rankVal[HUF_TABLELOG_MAX + 1]; const int scaleLog = nbBitsBaseline - targetLog; /* note : targetLog >= srcLog, hence scaleLog <= 1 */ const U32 minBits = nbBitsBaseline - maxWeight; U32 s; memcpy(rankVal, rankValOrigin, sizeof(rankVal)); /* fill DTable */ for (s = 0; s < sortedListSize; s++) { const U16 symbol = sortedList[s].symbol; const U32 weight = sortedList[s].weight; const U32 nbBits = nbBitsBaseline - weight; const U32 start = rankVal[weight]; const U32 length = 1 << (targetLog - nbBits); if (targetLog - nbBits >= minBits) { /* enough room for a second symbol */ U32 sortedRank; int minWeight = nbBits + scaleLog; if (minWeight < 1) minWeight = 1; sortedRank = rankStart[minWeight]; HUF_fillDTableX4Level2(DTable + start, targetLog - nbBits, nbBits, rankValOrigin[nbBits], minWeight, sortedList + sortedRank, sortedListSize - sortedRank, nbBitsBaseline, symbol); } else { HUF_DEltX4 DElt; ZSTD_writeLE16(&(DElt.sequence), symbol); DElt.nbBits = (BYTE)(nbBits); DElt.length = 1; { U32 const end = start + length; U32 u; for (u = start; u < end; u++) DTable[u] = DElt; } } rankVal[weight] += length; } } size_t HUF_readDTableX4_wksp(HUF_DTable *DTable, const void *src, size_t srcSize, void *workspace, size_t workspaceSize) { U32 tableLog, maxW, sizeOfSort, nbSymbols; DTableDesc dtd = HUF_getDTableDesc(DTable); U32 const maxTableLog = dtd.maxTableLog; size_t iSize; void *dtPtr = DTable + 1; /* force compiler to avoid strict-aliasing */ HUF_DEltX4 *const dt = (HUF_DEltX4 *)dtPtr; U32 *rankStart; rankValCol_t *rankVal; U32 *rankStats; U32 *rankStart0; sortedSymbol_t *sortedSymbol; BYTE *weightList; size_t spaceUsed32 = 0; HUF_STATIC_ASSERT((sizeof(rankValCol_t) & 3) == 0); rankVal = (rankValCol_t *)((U32 *)workspace + spaceUsed32); spaceUsed32 += (sizeof(rankValCol_t) * HUF_TABLELOG_MAX) >> 2; rankStats = (U32 *)workspace + spaceUsed32; spaceUsed32 += HUF_TABLELOG_MAX + 1; rankStart0 = (U32 *)workspace + spaceUsed32; spaceUsed32 += HUF_TABLELOG_MAX + 2; sortedSymbol = (sortedSymbol_t *)((U32 *)workspace + spaceUsed32); spaceUsed32 += UP_U32(sizeof(sortedSymbol_t) * (HUF_SYMBOLVALUE_MAX + 1)); weightList = (BYTE *)((U32 *)workspace + spaceUsed32); spaceUsed32 += UP_U32(HUF_SYMBOLVALUE_MAX + 1); if ((spaceUsed32 << 2) > workspaceSize) return ERROR(tableLog_tooLarge); workspace = (U32 *)workspace + spaceUsed32; workspaceSize -= (spaceUsed32 << 2); rankStart = rankStart0 + 1; memset(rankStats, 0, sizeof(U32) * (2 * HUF_TABLELOG_MAX + 2 + 1)); HUF_STATIC_ASSERT(sizeof(HUF_DEltX4) == sizeof(HUF_DTable)); /* if compiler fails here, assertion is wrong */ if (maxTableLog > HUF_TABLELOG_MAX) return ERROR(tableLog_tooLarge); /* memset(weightList, 0, sizeof(weightList)); */ /* is not necessary, even though some analyzer complain ... */ iSize = HUF_readStats_wksp(weightList, HUF_SYMBOLVALUE_MAX + 1, rankStats, &nbSymbols, &tableLog, src, srcSize, workspace, workspaceSize); if (HUF_isError(iSize)) return iSize; /* check result */ if (tableLog > maxTableLog) return ERROR(tableLog_tooLarge); /* DTable can't fit code depth */ /* find maxWeight */ for (maxW = tableLog; rankStats[maxW] == 0; maxW--) { } /* necessarily finds a solution before 0 */ /* Get start index of each weight */ { U32 w, nextRankStart = 0; for (w = 1; w < maxW + 1; w++) { U32 curr = nextRankStart; nextRankStart += rankStats[w]; rankStart[w] = curr; } rankStart[0] = nextRankStart; /* put all 0w symbols at the end of sorted list*/ sizeOfSort = nextRankStart; } /* sort symbols by weight */ { U32 s; for (s = 0; s < nbSymbols; s++) { U32 const w = weightList[s]; U32 const r = rankStart[w]++; sortedSymbol[r].symbol = (BYTE)s; sortedSymbol[r].weight = (BYTE)w; } rankStart[0] = 0; /* forget 0w symbols; this is beginning of weight(1) */ } /* Build rankVal */ { U32 *const rankVal0 = rankVal[0]; { int const rescale = (maxTableLog - tableLog) - 1; /* tableLog <= maxTableLog */ U32 nextRankVal = 0; U32 w; for (w = 1; w < maxW + 1; w++) { U32 curr = nextRankVal; nextRankVal += rankStats[w] << (w + rescale); rankVal0[w] = curr; } } { U32 const minBits = tableLog + 1 - maxW; U32 consumed; for (consumed = minBits; consumed < maxTableLog - minBits + 1; consumed++) { U32 *const rankValPtr = rankVal[consumed]; U32 w; for (w = 1; w < maxW + 1; w++) { rankValPtr[w] = rankVal0[w] >> consumed; } } } } HUF_fillDTableX4(dt, maxTableLog, sortedSymbol, sizeOfSort, rankStart0, rankVal, maxW, tableLog + 1); dtd.tableLog = (BYTE)maxTableLog; dtd.tableType = 1; memcpy(DTable, &dtd, sizeof(dtd)); return iSize; } static U32 HUF_decodeSymbolX4(void *op, BIT_DStream_t *DStream, const HUF_DEltX4 *dt, const U32 dtLog) { size_t const val = BIT_lookBitsFast(DStream, dtLog); /* note : dtLog >= 1 */ memcpy(op, dt + val, 2); BIT_skipBits(DStream, dt[val].nbBits); return dt[val].length; } static U32 HUF_decodeLastSymbolX4(void *op, BIT_DStream_t *DStream, const HUF_DEltX4 *dt, const U32 dtLog) { size_t const val = BIT_lookBitsFast(DStream, dtLog); /* note : dtLog >= 1 */ memcpy(op, dt + val, 1); if (dt[val].length == 1) BIT_skipBits(DStream, dt[val].nbBits); else { if (DStream->bitsConsumed < (sizeof(DStream->bitContainer) * 8)) { BIT_skipBits(DStream, dt[val].nbBits); if (DStream->bitsConsumed > (sizeof(DStream->bitContainer) * 8)) /* ugly hack; works only because it's the last symbol. Note : can't easily extract nbBits from just this symbol */ DStream->bitsConsumed = (sizeof(DStream->bitContainer) * 8); } } return 1; } #define HUF_DECODE_SYMBOLX4_0(ptr, DStreamPtr) ptr += HUF_decodeSymbolX4(ptr, DStreamPtr, dt, dtLog) #define HUF_DECODE_SYMBOLX4_1(ptr, DStreamPtr) \ if (ZSTD_64bits() || (HUF_TABLELOG_MAX <= 12)) \ ptr += HUF_decodeSymbolX4(ptr, DStreamPtr, dt, dtLog) #define HUF_DECODE_SYMBOLX4_2(ptr, DStreamPtr) \ if (ZSTD_64bits()) \ ptr += HUF_decodeSymbolX4(ptr, DStreamPtr, dt, dtLog) FORCE_INLINE size_t HUF_decodeStreamX4(BYTE *p, BIT_DStream_t *bitDPtr, BYTE *const pEnd, const HUF_DEltX4 *const dt, const U32 dtLog) { BYTE *const pStart = p; /* up to 8 symbols at a time */ while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd - (sizeof(bitDPtr->bitContainer) - 1))) { HUF_DECODE_SYMBOLX4_2(p, bitDPtr); HUF_DECODE_SYMBOLX4_1(p, bitDPtr); HUF_DECODE_SYMBOLX4_2(p, bitDPtr); HUF_DECODE_SYMBOLX4_0(p, bitDPtr); } /* closer to end : up to 2 symbols at a time */ while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p <= pEnd - 2)) HUF_DECODE_SYMBOLX4_0(p, bitDPtr); while (p <= pEnd - 2) HUF_DECODE_SYMBOLX4_0(p, bitDPtr); /* no need to reload : reached the end of DStream */ if (p < pEnd) p += HUF_decodeLastSymbolX4(p, bitDPtr, dt, dtLog); return p - pStart; } static size_t HUF_decompress1X4_usingDTable_internal(void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable) { BIT_DStream_t bitD; /* Init */ { size_t const errorCode = BIT_initDStream(&bitD, cSrc, cSrcSize); if (HUF_isError(errorCode)) return errorCode; } /* decode */ { BYTE *const ostart = (BYTE *)dst; BYTE *const oend = ostart + dstSize; const void *const dtPtr = DTable + 1; /* force compiler to not use strict-aliasing */ const HUF_DEltX4 *const dt = (const HUF_DEltX4 *)dtPtr; DTableDesc const dtd = HUF_getDTableDesc(DTable); HUF_decodeStreamX4(ostart, &bitD, oend, dt, dtd.tableLog); } /* check */ if (!BIT_endOfDStream(&bitD)) return ERROR(corruption_detected); /* decoded size */ return dstSize; } static size_t HUF_decompress4X4_usingDTable_internal(void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable) { if (cSrcSize < 10) return ERROR(corruption_detected); /* strict minimum : jump table + 1 byte per stream */ { const BYTE *const istart = (const BYTE *)cSrc; BYTE *const ostart = (BYTE *)dst; BYTE *const oend = ostart + dstSize; const void *const dtPtr = DTable + 1; const HUF_DEltX4 *const dt = (const HUF_DEltX4 *)dtPtr; /* Init */ BIT_DStream_t bitD1; BIT_DStream_t bitD2; BIT_DStream_t bitD3; BIT_DStream_t bitD4; size_t const length1 = ZSTD_readLE16(istart); size_t const length2 = ZSTD_readLE16(istart + 2); size_t const length3 = ZSTD_readLE16(istart + 4); size_t const length4 = cSrcSize - (length1 + length2 + length3 + 6); const BYTE *const istart1 = istart + 6; /* jumpTable */ const BYTE *const istart2 = istart1 + length1; const BYTE *const istart3 = istart2 + length2; const BYTE *const istart4 = istart3 + length3; size_t const segmentSize = (dstSize + 3) / 4; BYTE *const opStart2 = ostart + segmentSize; BYTE *const opStart3 = opStart2 + segmentSize; BYTE *const opStart4 = opStart3 + segmentSize; BYTE *op1 = ostart; BYTE *op2 = opStart2; BYTE *op3 = opStart3; BYTE *op4 = opStart4; U32 endSignal; DTableDesc const dtd = HUF_getDTableDesc(DTable); U32 const dtLog = dtd.tableLog; if (length4 > cSrcSize) return ERROR(corruption_detected); /* overflow */ { size_t const errorCode = BIT_initDStream(&bitD1, istart1, length1); if (HUF_isError(errorCode)) return errorCode; } { size_t const errorCode = BIT_initDStream(&bitD2, istart2, length2); if (HUF_isError(errorCode)) return errorCode; } { size_t const errorCode = BIT_initDStream(&bitD3, istart3, length3); if (HUF_isError(errorCode)) return errorCode; } { size_t const errorCode = BIT_initDStream(&bitD4, istart4, length4); if (HUF_isError(errorCode)) return errorCode; } /* 16-32 symbols per loop (4-8 symbols per stream) */ endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4); for (; (endSignal == BIT_DStream_unfinished) & (op4 < (oend - (sizeof(bitD4.bitContainer) - 1)));) { HUF_DECODE_SYMBOLX4_2(op1, &bitD1); HUF_DECODE_SYMBOLX4_2(op2, &bitD2); HUF_DECODE_SYMBOLX4_2(op3, &bitD3); HUF_DECODE_SYMBOLX4_2(op4, &bitD4); HUF_DECODE_SYMBOLX4_1(op1, &bitD1); HUF_DECODE_SYMBOLX4_1(op2, &bitD2); HUF_DECODE_SYMBOLX4_1(op3, &bitD3); HUF_DECODE_SYMBOLX4_1(op4, &bitD4); HUF_DECODE_SYMBOLX4_2(op1, &bitD1); HUF_DECODE_SYMBOLX4_2(op2, &bitD2); HUF_DECODE_SYMBOLX4_2(op3, &bitD3); HUF_DECODE_SYMBOLX4_2(op4, &bitD4); HUF_DECODE_SYMBOLX4_0(op1, &bitD1); HUF_DECODE_SYMBOLX4_0(op2, &bitD2); HUF_DECODE_SYMBOLX4_0(op3, &bitD3); HUF_DECODE_SYMBOLX4_0(op4, &bitD4); endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4); } /* check corruption */ if (op1 > opStart2) return ERROR(corruption_detected); if (op2 > opStart3) return ERROR(corruption_detected); if (op3 > opStart4) return ERROR(corruption_detected); /* note : op4 already verified within main loop */ /* finish bitStreams one by one */ HUF_decodeStreamX4(op1, &bitD1, opStart2, dt, dtLog); HUF_decodeStreamX4(op2, &bitD2, opStart3, dt, dtLog); HUF_decodeStreamX4(op3, &bitD3, opStart4, dt, dtLog); HUF_decodeStreamX4(op4, &bitD4, oend, dt, dtLog); /* check */ { U32 const endCheck = BIT_endOfDStream(&bitD1) & BIT_endOfDStream(&bitD2) & BIT_endOfDStream(&bitD3) & BIT_endOfDStream(&bitD4); if (!endCheck) return ERROR(corruption_detected); } /* decoded size */ return dstSize; } } size_t HUF_decompress4X4_DCtx_wksp(HUF_DTable *dctx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t workspaceSize) { const BYTE *ip = (const BYTE *)cSrc; size_t hSize = HUF_readDTableX4_wksp(dctx, cSrc, cSrcSize, workspace, workspaceSize); if (HUF_isError(hSize)) return hSize; if (hSize >= cSrcSize) return ERROR(srcSize_wrong); ip += hSize; cSrcSize -= hSize; return HUF_decompress4X4_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx); } /* ********************************/ /* Generic decompression selector */ /* ********************************/ size_t HUF_decompress1X_usingDTable(void *dst, size_t maxDstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable) { DTableDesc const dtd = HUF_getDTableDesc(DTable); return dtd.tableType ? HUF_decompress1X4_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable) : HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable); } size_t HUF_decompress4X_usingDTable(void *dst, size_t maxDstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable) { DTableDesc const dtd = HUF_getDTableDesc(DTable); return dtd.tableType ? HUF_decompress4X4_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable) : HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable); } typedef struct { U32 tableTime; U32 decode256Time; } algo_time_t; static const algo_time_t algoTime[16 /* Quantization */][3 /* single, double, quad */] = { /* single, double, quad */ {{0, 0}, {1, 1}, {2, 2}}, /* Q==0 : impossible */ {{0, 0}, {1, 1}, {2, 2}}, /* Q==1 : impossible */ {{38, 130}, {1313, 74}, {2151, 38}}, /* Q == 2 : 12-18% */ {{448, 128}, {1353, 74}, {2238, 41}}, /* Q == 3 : 18-25% */ {{556, 128}, {1353, 74}, {2238, 47}}, /* Q == 4 : 25-32% */ {{714, 128}, {1418, 74}, {2436, 53}}, /* Q == 5 : 32-38% */ {{883, 128}, {1437, 74}, {2464, 61}}, /* Q == 6 : 38-44% */ {{897, 128}, {1515, 75}, {2622, 68}}, /* Q == 7 : 44-50% */ {{926, 128}, {1613, 75}, {2730, 75}}, /* Q == 8 : 50-56% */ {{947, 128}, {1729, 77}, {3359, 77}}, /* Q == 9 : 56-62% */ {{1107, 128}, {2083, 81}, {4006, 84}}, /* Q ==10 : 62-69% */ {{1177, 128}, {2379, 87}, {4785, 88}}, /* Q ==11 : 69-75% */ {{1242, 128}, {2415, 93}, {5155, 84}}, /* Q ==12 : 75-81% */ {{1349, 128}, {2644, 106}, {5260, 106}}, /* Q ==13 : 81-87% */ {{1455, 128}, {2422, 124}, {4174, 124}}, /* Q ==14 : 87-93% */ {{722, 128}, {1891, 145}, {1936, 146}}, /* Q ==15 : 93-99% */ }; /** HUF_selectDecoder() : * Tells which decoder is likely to decode faster, * based on a set of pre-determined metrics. * @return : 0==HUF_decompress4X2, 1==HUF_decompress4X4 . * Assumption : 0 < cSrcSize < dstSize <= 128 KB */ U32 HUF_selectDecoder(size_t dstSize, size_t cSrcSize) { /* decoder timing evaluation */ U32 const Q = (U32)(cSrcSize * 16 / dstSize); /* Q < 16 since dstSize > cSrcSize */ U32 const D256 = (U32)(dstSize >> 8); U32 const DTime0 = algoTime[Q][0].tableTime + (algoTime[Q][0].decode256Time * D256); U32 DTime1 = algoTime[Q][1].tableTime + (algoTime[Q][1].decode256Time * D256); DTime1 += DTime1 >> 3; /* advantage to algorithm using less memory, for cache eviction */ return DTime1 < DTime0; } size_t HUF_decompress4X_hufOnly_wksp(HUF_DTable *dctx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t workspaceSize) { /* validation checks */ if (dstSize == 0) return ERROR(dstSize_tooSmall); if ((cSrcSize >= dstSize) || (cSrcSize <= 1)) return ERROR(corruption_detected); /* invalid */ { U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize); return algoNb ? HUF_decompress4X4_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workspace, workspaceSize) : HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workspace, workspaceSize); } } /*! HUF_readStats() : Read compact Huffman tree, saved by HUF_writeCTable(). `huffWeight` is destination buffer. `rankStats` is assumed to be a table of at least HUF_TABLELOG_MAX U32. @return : size read from `src` , or an error Code . Note : Needed by HUF_readCTable() and HUF_readDTableX?() . */ size_t HUF_readStats_wksp(BYTE *huffWeight, size_t hwSize, U32 *rankStats, U32 *nbSymbolsPtr, U32 *tableLogPtr, const void *src, size_t srcSize, void *workspace, size_t workspaceSize) { U32 weightTotal; const BYTE *ip = (const BYTE *)src; size_t iSize; size_t oSize; if (!srcSize) return ERROR(srcSize_wrong); iSize = ip[0]; /* memset(huffWeight, 0, hwSize); */ /* is not necessary, even though some analyzer complain ... */ if (iSize >= 128) { /* special header */ oSize = iSize - 127; iSize = ((oSize + 1) / 2); if (iSize + 1 > srcSize) return ERROR(srcSize_wrong); if (oSize >= hwSize) return ERROR(corruption_detected); ip += 1; { U32 n; for (n = 0; n < oSize; n += 2) { huffWeight[n] = ip[n / 2] >> 4; huffWeight[n + 1] = ip[n / 2] & 15; } } } else { /* header compressed with FSE (normal case) */ if (iSize + 1 > srcSize) return ERROR(srcSize_wrong); oSize = FSE_decompress_wksp(huffWeight, hwSize - 1, ip + 1, iSize, 6, workspace, workspaceSize); /* max (hwSize-1) values decoded, as last one is implied */ if (FSE_isError(oSize)) return oSize; } /* collect weight stats */ memset(rankStats, 0, (HUF_TABLELOG_MAX + 1) * sizeof(U32)); weightTotal = 0; { U32 n; for (n = 0; n < oSize; n++) { if (huffWeight[n] >= HUF_TABLELOG_MAX) return ERROR(corruption_detected); rankStats[huffWeight[n]]++; weightTotal += (1 << huffWeight[n]) >> 1; } } if (weightTotal == 0) return ERROR(corruption_detected); /* get last non-null symbol weight (implied, total must be 2^n) */ { U32 const tableLog = BIT_highbit32(weightTotal) + 1; if (tableLog > HUF_TABLELOG_MAX) return ERROR(corruption_detected); *tableLogPtr = tableLog; /* determine last weight */ { U32 const total = 1 << tableLog; U32 const rest = total - weightTotal; U32 const verif = 1 << BIT_highbit32(rest); U32 const lastWeight = BIT_highbit32(rest) + 1; if (verif != rest) return ERROR(corruption_detected); /* last value must be a clean power of 2 */ huffWeight[oSize] = (BYTE)lastWeight; rankStats[lastWeight]++; } } /* check tree construction validity */ if ((rankStats[1] < 2) || (rankStats[1] & 1)) return ERROR(corruption_detected); /* by construction : at least 2 elts of rank 1, must be even */ /* results */ *nbSymbolsPtr = (U32)(oSize + 1); return iSize + 1; } ������������������refind-0.11.4/filesystems/zstd/zstd_decompress.c����������������������������������������������������0000644�0001750�0001750�00000203504�13363346003�022224� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/** * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of https://github.com/facebook/zstd. * An additional grant of patent rights can be found in the PATENTS file in the * same directory. * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License version 2 as published by the * Free Software Foundation. This program is dual-licensed; you may select * either version 2 of the GNU General Public License ("GPL") or BSD license * ("BSD"). */ /* *************************************************************** * Tuning parameters *****************************************************************/ /*! * MAXWINDOWSIZE_DEFAULT : * maximum window size accepted by DStream, by default. * Frames requiring more memory will be rejected. */ #ifndef ZSTD_MAXWINDOWSIZE_DEFAULT #define ZSTD_MAXWINDOWSIZE_DEFAULT ((1 << ZSTD_WINDOWLOG_MAX) + 1) /* defined within zstd.h */ #endif /*-******************************************************* * Dependencies *********************************************************/ #include "fse.h" #include "huf.h" #include "mem.h" /* low level memory routines */ #include "zstd_internal.h" #define ZSTD_PREFETCH(ptr) __builtin_prefetch(ptr, 0, 0) /*_******************************************************* * Memory operations **********************************************************/ static void ZSTD_copy4(void *dst, const void *src) { memcpy(dst, src, 4); } /*-************************************************************* * Context management ***************************************************************/ typedef enum { ZSTDds_getFrameHeaderSize, ZSTDds_decodeFrameHeader, ZSTDds_decodeBlockHeader, ZSTDds_decompressBlock, ZSTDds_decompressLastBlock, ZSTDds_checkChecksum, ZSTDds_decodeSkippableHeader, ZSTDds_skipFrame } ZSTD_dStage; typedef enum { ZSTDnit_frameHeader, ZSTDnit_blockHeader, ZSTDnit_block, ZSTDnit_lastBlock, ZSTDnit_checksum, ZSTDnit_skippableFrame } ZSTD_nextInputType_e; typedef struct { FSE_DTable LLTable[FSE_DTABLE_SIZE_U32(LLFSELog)]; FSE_DTable OFTable[FSE_DTABLE_SIZE_U32(OffFSELog)]; FSE_DTable MLTable[FSE_DTABLE_SIZE_U32(MLFSELog)]; HUF_DTable hufTable[HUF_DTABLE_SIZE(HufLog)]; /* can accommodate HUF_decompress4X */ U64 workspace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32 / 2]; U32 rep[ZSTD_REP_NUM]; } ZSTD_entropyTables_t; struct ZSTD_DCtx_s { const FSE_DTable *LLTptr; const FSE_DTable *MLTptr; const FSE_DTable *OFTptr; const HUF_DTable *HUFptr; ZSTD_entropyTables_t entropy; const void *previousDstEnd; /* detect continuity */ const void *base; /* start of curr segment */ const void *vBase; /* virtual start of previous segment if it was just before curr one */ const void *dictEnd; /* end of previous segment */ size_t expected; ZSTD_frameParams fParams; blockType_e bType; /* used in ZSTD_decompressContinue(), to transfer blockType between header decoding and block decoding stages */ ZSTD_dStage stage; U32 litEntropy; U32 fseEntropy; struct xxh64_state xxhState; size_t headerSize; U32 dictID; const BYTE *litPtr; size_t litSize; size_t rleSize; BYTE litBuffer[ZSTD_BLOCKSIZE_ABSOLUTEMAX + WILDCOPY_OVERLENGTH]; BYTE headerBuffer[ZSTD_FRAMEHEADERSIZE_MAX]; }; /* typedef'd to ZSTD_DCtx within "zstd.h" */ typedef struct ZSTD_DCtx_s ZSTD_DCtx; size_t ZSTD_decompressBegin(ZSTD_DCtx *dctx) { dctx->expected = ZSTD_frameHeaderSize_prefix; dctx->stage = ZSTDds_getFrameHeaderSize; dctx->previousDstEnd = NULL; dctx->base = NULL; dctx->vBase = NULL; dctx->dictEnd = NULL; dctx->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001); /* cover both little and big endian */ dctx->litEntropy = dctx->fseEntropy = 0; dctx->dictID = 0; ZSTD_STATIC_ASSERT(sizeof(dctx->entropy.rep) == sizeof(repStartValue)); memcpy(dctx->entropy.rep, repStartValue, sizeof(repStartValue)); /* initial repcodes */ dctx->LLTptr = dctx->entropy.LLTable; dctx->MLTptr = dctx->entropy.MLTable; dctx->OFTptr = dctx->entropy.OFTable; dctx->HUFptr = dctx->entropy.hufTable; return 0; } /*-************************************************************* * Decompression section ***************************************************************/ /** ZSTD_frameHeaderSize() : * srcSize must be >= ZSTD_frameHeaderSize_prefix. * @return : size of the Frame Header */ static size_t ZSTD_frameHeaderSize(const void *src, size_t srcSize) { if (srcSize < ZSTD_frameHeaderSize_prefix) return ERROR(srcSize_wrong); { BYTE const fhd = ((const BYTE *)src)[4]; U32 const dictID = fhd & 3; U32 const singleSegment = (fhd >> 5) & 1; U32 const fcsId = fhd >> 6; return ZSTD_frameHeaderSize_prefix + !singleSegment + ZSTD_did_fieldSize[dictID] + ZSTD_fcs_fieldSize[fcsId] + (singleSegment && !fcsId); } } /** ZSTD_getFrameParams() : * decode Frame Header, or require larger `srcSize`. * @return : 0, `fparamsPtr` is correctly filled, * >0, `srcSize` is too small, result is expected `srcSize`, * or an error code, which can be tested using ZSTD_isError() */ size_t ZSTD_getFrameParams(ZSTD_frameParams *fparamsPtr, const void *src, size_t srcSize) { const BYTE *ip = (const BYTE *)src; if (srcSize < ZSTD_frameHeaderSize_prefix) return ZSTD_frameHeaderSize_prefix; if (ZSTD_readLE32(src) != ZSTD_MAGICNUMBER) { if ((ZSTD_readLE32(src) & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) { if (srcSize < ZSTD_skippableHeaderSize) return ZSTD_skippableHeaderSize; /* magic number + skippable frame length */ memset(fparamsPtr, 0, sizeof(*fparamsPtr)); fparamsPtr->frameContentSize = ZSTD_readLE32((const char *)src + 4); fparamsPtr->windowSize = 0; /* windowSize==0 means a frame is skippable */ return 0; } return ERROR(prefix_unknown); } /* ensure there is enough `srcSize` to fully read/decode frame header */ { size_t const fhsize = ZSTD_frameHeaderSize(src, srcSize); if (srcSize < fhsize) return fhsize; } { BYTE const fhdByte = ip[4]; size_t pos = 5; U32 const dictIDSizeCode = fhdByte & 3; U32 const checksumFlag = (fhdByte >> 2) & 1; U32 const singleSegment = (fhdByte >> 5) & 1; U32 const fcsID = fhdByte >> 6; U32 const windowSizeMax = 1U << ZSTD_WINDOWLOG_MAX; U32 windowSize = 0; U32 dictID = 0; U64 frameContentSize = 0; if ((fhdByte & 0x08) != 0) return ERROR(frameParameter_unsupported); /* reserved bits, which must be zero */ if (!singleSegment) { BYTE const wlByte = ip[pos++]; U32 const windowLog = (wlByte >> 3) + ZSTD_WINDOWLOG_ABSOLUTEMIN; if (windowLog > ZSTD_WINDOWLOG_MAX) return ERROR(frameParameter_windowTooLarge); /* avoids issue with 1 << windowLog */ windowSize = (1U << windowLog); windowSize += (windowSize >> 3) * (wlByte & 7); } switch (dictIDSizeCode) { default: /* impossible */ case 0: break; case 1: dictID = ip[pos]; pos++; break; case 2: dictID = ZSTD_readLE16(ip + pos); pos += 2; break; case 3: dictID = ZSTD_readLE32(ip + pos); pos += 4; break; } switch (fcsID) { default: /* impossible */ case 0: if (singleSegment) frameContentSize = ip[pos]; break; case 1: frameContentSize = ZSTD_readLE16(ip + pos) + 256; break; case 2: frameContentSize = ZSTD_readLE32(ip + pos); break; case 3: frameContentSize = ZSTD_readLE64(ip + pos); break; } if (!windowSize) windowSize = (U32)frameContentSize; if (windowSize > windowSizeMax) return ERROR(frameParameter_windowTooLarge); fparamsPtr->frameContentSize = frameContentSize; fparamsPtr->windowSize = windowSize; fparamsPtr->dictID = dictID; fparamsPtr->checksumFlag = checksumFlag; } return 0; } /** ZSTD_decodeFrameHeader() : * `headerSize` must be the size provided by ZSTD_frameHeaderSize(). * @return : 0 if success, or an error code, which can be tested using ZSTD_isError() */ static size_t ZSTD_decodeFrameHeader(ZSTD_DCtx *dctx, const void *src, size_t headerSize) { size_t const result = ZSTD_getFrameParams(&(dctx->fParams), src, headerSize); if (ZSTD_isError(result)) return result; /* invalid header */ if (result > 0) return ERROR(srcSize_wrong); /* headerSize too small */ if (dctx->fParams.dictID && (dctx->dictID != dctx->fParams.dictID)) return ERROR(dictionary_wrong); if (dctx->fParams.checksumFlag) xxh64_reset(&dctx->xxhState, 0); return 0; } typedef struct { blockType_e blockType; U32 lastBlock; U32 origSize; } blockProperties_t; /*! ZSTD_getcBlockSize() : * Provides the size of compressed block from block header `src` */ size_t ZSTD_getcBlockSize(const void *src, size_t srcSize, blockProperties_t *bpPtr) { if (srcSize < ZSTD_blockHeaderSize) return ERROR(srcSize_wrong); { U32 const cBlockHeader = ZSTD_readLE24(src); U32 const cSize = cBlockHeader >> 3; bpPtr->lastBlock = cBlockHeader & 1; bpPtr->blockType = (blockType_e)((cBlockHeader >> 1) & 3); bpPtr->origSize = cSize; /* only useful for RLE */ if (bpPtr->blockType == bt_rle) return 1; if (bpPtr->blockType == bt_reserved) return ERROR(corruption_detected); return cSize; } } static size_t ZSTD_copyRawBlock(void *dst, size_t dstCapacity, const void *src, size_t srcSize) { if (srcSize > dstCapacity) return ERROR(dstSize_tooSmall); memcpy(dst, src, srcSize); return srcSize; } static size_t ZSTD_setRleBlock(void *dst, size_t dstCapacity, const void *src, size_t srcSize, size_t regenSize) { if (srcSize != 1) return ERROR(srcSize_wrong); if (regenSize > dstCapacity) return ERROR(dstSize_tooSmall); memset(dst, *(const BYTE *)src, regenSize); return regenSize; } /*! ZSTD_decodeLiteralsBlock() : @return : nb of bytes read from src (< srcSize ) */ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx *dctx, const void *src, size_t srcSize) /* note : srcSize < BLOCKSIZE */ { if (srcSize < MIN_CBLOCK_SIZE) return ERROR(corruption_detected); { const BYTE *const istart = (const BYTE *)src; symbolEncodingType_e const litEncType = (symbolEncodingType_e)(istart[0] & 3); switch (litEncType) { case set_repeat: if (dctx->litEntropy == 0) return ERROR(dictionary_corrupted); /* fall-through */ case set_compressed: if (srcSize < 5) return ERROR(corruption_detected); /* srcSize >= MIN_CBLOCK_SIZE == 3; here we need up to 5 for case 3 */ { size_t lhSize, litSize, litCSize; U32 singleStream = 0; U32 const lhlCode = (istart[0] >> 2) & 3; U32 const lhc = ZSTD_readLE32(istart); switch (lhlCode) { case 0: case 1: default: /* note : default is impossible, since lhlCode into [0..3] */ /* 2 - 2 - 10 - 10 */ singleStream = !lhlCode; lhSize = 3; litSize = (lhc >> 4) & 0x3FF; litCSize = (lhc >> 14) & 0x3FF; break; case 2: /* 2 - 2 - 14 - 14 */ lhSize = 4; litSize = (lhc >> 4) & 0x3FFF; litCSize = lhc >> 18; break; case 3: /* 2 - 2 - 18 - 18 */ lhSize = 5; litSize = (lhc >> 4) & 0x3FFFF; litCSize = (lhc >> 22) + (istart[4] << 10); break; } if (litSize > ZSTD_BLOCKSIZE_ABSOLUTEMAX) return ERROR(corruption_detected); if (litCSize + lhSize > srcSize) return ERROR(corruption_detected); if (HUF_isError( (litEncType == set_repeat) ? (singleStream ? HUF_decompress1X_usingDTable(dctx->litBuffer, litSize, istart + lhSize, litCSize, dctx->HUFptr) : HUF_decompress4X_usingDTable(dctx->litBuffer, litSize, istart + lhSize, litCSize, dctx->HUFptr)) : (singleStream ? HUF_decompress1X2_DCtx_wksp(dctx->entropy.hufTable, dctx->litBuffer, litSize, istart + lhSize, litCSize, dctx->entropy.workspace, sizeof(dctx->entropy.workspace)) : HUF_decompress4X_hufOnly_wksp(dctx->entropy.hufTable, dctx->litBuffer, litSize, istart + lhSize, litCSize, dctx->entropy.workspace, sizeof(dctx->entropy.workspace))))) return ERROR(corruption_detected); dctx->litPtr = dctx->litBuffer; dctx->litSize = litSize; dctx->litEntropy = 1; if (litEncType == set_compressed) dctx->HUFptr = dctx->entropy.hufTable; memset(dctx->litBuffer + dctx->litSize, 0, WILDCOPY_OVERLENGTH); return litCSize + lhSize; } case set_basic: { size_t litSize, lhSize; U32 const lhlCode = ((istart[0]) >> 2) & 3; switch (lhlCode) { case 0: case 2: default: /* note : default is impossible, since lhlCode into [0..3] */ lhSize = 1; litSize = istart[0] >> 3; break; case 1: lhSize = 2; litSize = ZSTD_readLE16(istart) >> 4; break; case 3: lhSize = 3; litSize = ZSTD_readLE24(istart) >> 4; break; } if (lhSize + litSize + WILDCOPY_OVERLENGTH > srcSize) { /* risk reading beyond src buffer with wildcopy */ if (litSize + lhSize > srcSize) return ERROR(corruption_detected); memcpy(dctx->litBuffer, istart + lhSize, litSize); dctx->litPtr = dctx->litBuffer; dctx->litSize = litSize; memset(dctx->litBuffer + dctx->litSize, 0, WILDCOPY_OVERLENGTH); return lhSize + litSize; } /* direct reference into compressed stream */ dctx->litPtr = istart + lhSize; dctx->litSize = litSize; return lhSize + litSize; } case set_rle: { U32 const lhlCode = ((istart[0]) >> 2) & 3; size_t litSize, lhSize; switch (lhlCode) { case 0: case 2: default: /* note : default is impossible, since lhlCode into [0..3] */ lhSize = 1; litSize = istart[0] >> 3; break; case 1: lhSize = 2; litSize = ZSTD_readLE16(istart) >> 4; break; case 3: lhSize = 3; litSize = ZSTD_readLE24(istart) >> 4; if (srcSize < 4) return ERROR(corruption_detected); /* srcSize >= MIN_CBLOCK_SIZE == 3; here we need lhSize+1 = 4 */ break; } if (litSize > ZSTD_BLOCKSIZE_ABSOLUTEMAX) return ERROR(corruption_detected); memset(dctx->litBuffer, istart[lhSize], litSize + WILDCOPY_OVERLENGTH); dctx->litPtr = dctx->litBuffer; dctx->litSize = litSize; return lhSize + 1; } default: return ERROR(corruption_detected); /* impossible */ } } } typedef union { FSE_decode_t realData; U32 alignedBy4; } FSE_decode_t4; static const FSE_decode_t4 LL_defaultDTable[(1 << LL_DEFAULTNORMLOG) + 1] = { {{LL_DEFAULTNORMLOG, 1, 1}}, /* header : tableLog, fastMode, fastMode */ {{0, 0, 4}}, /* 0 : base, symbol, bits */ {{16, 0, 4}}, {{32, 1, 5}}, {{0, 3, 5}}, {{0, 4, 5}}, {{0, 6, 5}}, {{0, 7, 5}}, {{0, 9, 5}}, {{0, 10, 5}}, {{0, 12, 5}}, {{0, 14, 6}}, {{0, 16, 5}}, {{0, 18, 5}}, {{0, 19, 5}}, {{0, 21, 5}}, {{0, 22, 5}}, {{0, 24, 5}}, {{32, 25, 5}}, {{0, 26, 5}}, {{0, 27, 6}}, {{0, 29, 6}}, {{0, 31, 6}}, {{32, 0, 4}}, {{0, 1, 4}}, {{0, 2, 5}}, {{32, 4, 5}}, {{0, 5, 5}}, {{32, 7, 5}}, {{0, 8, 5}}, {{32, 10, 5}}, {{0, 11, 5}}, {{0, 13, 6}}, {{32, 16, 5}}, {{0, 17, 5}}, {{32, 19, 5}}, {{0, 20, 5}}, {{32, 22, 5}}, {{0, 23, 5}}, {{0, 25, 4}}, {{16, 25, 4}}, {{32, 26, 5}}, {{0, 28, 6}}, {{0, 30, 6}}, {{48, 0, 4}}, {{16, 1, 4}}, {{32, 2, 5}}, {{32, 3, 5}}, {{32, 5, 5}}, {{32, 6, 5}}, {{32, 8, 5}}, {{32, 9, 5}}, {{32, 11, 5}}, {{32, 12, 5}}, {{0, 15, 6}}, {{32, 17, 5}}, {{32, 18, 5}}, {{32, 20, 5}}, {{32, 21, 5}}, {{32, 23, 5}}, {{32, 24, 5}}, {{0, 35, 6}}, {{0, 34, 6}}, {{0, 33, 6}}, {{0, 32, 6}}, }; /* LL_defaultDTable */ static const FSE_decode_t4 ML_defaultDTable[(1 << ML_DEFAULTNORMLOG) + 1] = { {{ML_DEFAULTNORMLOG, 1, 1}}, /* header : tableLog, fastMode, fastMode */ {{0, 0, 6}}, /* 0 : base, symbol, bits */ {{0, 1, 4}}, {{32, 2, 5}}, {{0, 3, 5}}, {{0, 5, 5}}, {{0, 6, 5}}, {{0, 8, 5}}, {{0, 10, 6}}, {{0, 13, 6}}, {{0, 16, 6}}, {{0, 19, 6}}, {{0, 22, 6}}, {{0, 25, 6}}, {{0, 28, 6}}, {{0, 31, 6}}, {{0, 33, 6}}, {{0, 35, 6}}, {{0, 37, 6}}, {{0, 39, 6}}, {{0, 41, 6}}, {{0, 43, 6}}, {{0, 45, 6}}, {{16, 1, 4}}, {{0, 2, 4}}, {{32, 3, 5}}, {{0, 4, 5}}, {{32, 6, 5}}, {{0, 7, 5}}, {{0, 9, 6}}, {{0, 12, 6}}, {{0, 15, 6}}, {{0, 18, 6}}, {{0, 21, 6}}, {{0, 24, 6}}, {{0, 27, 6}}, {{0, 30, 6}}, {{0, 32, 6}}, {{0, 34, 6}}, {{0, 36, 6}}, {{0, 38, 6}}, {{0, 40, 6}}, {{0, 42, 6}}, {{0, 44, 6}}, {{32, 1, 4}}, {{48, 1, 4}}, {{16, 2, 4}}, {{32, 4, 5}}, {{32, 5, 5}}, {{32, 7, 5}}, {{32, 8, 5}}, {{0, 11, 6}}, {{0, 14, 6}}, {{0, 17, 6}}, {{0, 20, 6}}, {{0, 23, 6}}, {{0, 26, 6}}, {{0, 29, 6}}, {{0, 52, 6}}, {{0, 51, 6}}, {{0, 50, 6}}, {{0, 49, 6}}, {{0, 48, 6}}, {{0, 47, 6}}, {{0, 46, 6}}, }; /* ML_defaultDTable */ static const FSE_decode_t4 OF_defaultDTable[(1 << OF_DEFAULTNORMLOG) + 1] = { {{OF_DEFAULTNORMLOG, 1, 1}}, /* header : tableLog, fastMode, fastMode */ {{0, 0, 5}}, /* 0 : base, symbol, bits */ {{0, 6, 4}}, {{0, 9, 5}}, {{0, 15, 5}}, {{0, 21, 5}}, {{0, 3, 5}}, {{0, 7, 4}}, {{0, 12, 5}}, {{0, 18, 5}}, {{0, 23, 5}}, {{0, 5, 5}}, {{0, 8, 4}}, {{0, 14, 5}}, {{0, 20, 5}}, {{0, 2, 5}}, {{16, 7, 4}}, {{0, 11, 5}}, {{0, 17, 5}}, {{0, 22, 5}}, {{0, 4, 5}}, {{16, 8, 4}}, {{0, 13, 5}}, {{0, 19, 5}}, {{0, 1, 5}}, {{16, 6, 4}}, {{0, 10, 5}}, {{0, 16, 5}}, {{0, 28, 5}}, {{0, 27, 5}}, {{0, 26, 5}}, {{0, 25, 5}}, {{0, 24, 5}}, }; /* OF_defaultDTable */ /*! ZSTD_buildSeqTable() : @return : nb bytes read from src, or an error code if it fails, testable with ZSTD_isError() */ static size_t ZSTD_buildSeqTable(FSE_DTable *DTableSpace, const FSE_DTable **DTablePtr, symbolEncodingType_e type, U32 max, U32 maxLog, const void *src, size_t srcSize, const FSE_decode_t4 *defaultTable, U32 flagRepeatTable, void *workspace, size_t workspaceSize) { const void *const tmpPtr = defaultTable; /* bypass strict aliasing */ switch (type) { case set_rle: if (!srcSize) return ERROR(srcSize_wrong); if ((*(const BYTE *)src) > max) return ERROR(corruption_detected); FSE_buildDTable_rle(DTableSpace, *(const BYTE *)src); *DTablePtr = DTableSpace; return 1; case set_basic: *DTablePtr = (const FSE_DTable *)tmpPtr; return 0; case set_repeat: if (!flagRepeatTable) return ERROR(corruption_detected); return 0; default: /* impossible */ case set_compressed: { U32 tableLog; S16 *norm = (S16 *)workspace; size_t const spaceUsed32 = UP_U32(sizeof(S16) * (MaxSeq + 1)); if ((spaceUsed32 << 2) > workspaceSize) return ERROR(GENERIC); workspace = (U32 *)workspace + spaceUsed32; workspaceSize -= (spaceUsed32 << 2); { size_t const headerSize = FSE_readNCount(norm, &max, &tableLog, src, srcSize); if (FSE_isError(headerSize)) return ERROR(corruption_detected); if (tableLog > maxLog) return ERROR(corruption_detected); FSE_buildDTable_wksp(DTableSpace, norm, max, tableLog, workspace, workspaceSize); *DTablePtr = DTableSpace; return headerSize; } } } } size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx *dctx, int *nbSeqPtr, const void *src, size_t srcSize) { const BYTE *const istart = (const BYTE *const)src; const BYTE *const iend = istart + srcSize; const BYTE *ip = istart; /* check */ if (srcSize < MIN_SEQUENCES_SIZE) return ERROR(srcSize_wrong); /* SeqHead */ { int nbSeq = *ip++; if (!nbSeq) { *nbSeqPtr = 0; return 1; } if (nbSeq > 0x7F) { if (nbSeq == 0xFF) { if (ip + 2 > iend) return ERROR(srcSize_wrong); nbSeq = ZSTD_readLE16(ip) + LONGNBSEQ, ip += 2; } else { if (ip >= iend) return ERROR(srcSize_wrong); nbSeq = ((nbSeq - 0x80) << 8) + *ip++; } } *nbSeqPtr = nbSeq; } /* FSE table descriptors */ if (ip + 4 > iend) return ERROR(srcSize_wrong); /* minimum possible size */ { symbolEncodingType_e const LLtype = (symbolEncodingType_e)(*ip >> 6); symbolEncodingType_e const OFtype = (symbolEncodingType_e)((*ip >> 4) & 3); symbolEncodingType_e const MLtype = (symbolEncodingType_e)((*ip >> 2) & 3); ip++; /* Build DTables */ { size_t const llhSize = ZSTD_buildSeqTable(dctx->entropy.LLTable, &dctx->LLTptr, LLtype, MaxLL, LLFSELog, ip, iend - ip, LL_defaultDTable, dctx->fseEntropy, dctx->entropy.workspace, sizeof(dctx->entropy.workspace)); if (ZSTD_isError(llhSize)) return ERROR(corruption_detected); ip += llhSize; } { size_t const ofhSize = ZSTD_buildSeqTable(dctx->entropy.OFTable, &dctx->OFTptr, OFtype, MaxOff, OffFSELog, ip, iend - ip, OF_defaultDTable, dctx->fseEntropy, dctx->entropy.workspace, sizeof(dctx->entropy.workspace)); if (ZSTD_isError(ofhSize)) return ERROR(corruption_detected); ip += ofhSize; } { size_t const mlhSize = ZSTD_buildSeqTable(dctx->entropy.MLTable, &dctx->MLTptr, MLtype, MaxML, MLFSELog, ip, iend - ip, ML_defaultDTable, dctx->fseEntropy, dctx->entropy.workspace, sizeof(dctx->entropy.workspace)); if (ZSTD_isError(mlhSize)) return ERROR(corruption_detected); ip += mlhSize; } } return ip - istart; } typedef struct { size_t litLength; size_t matchLength; size_t offset; const BYTE *match; } seq_t; typedef struct { BIT_DStream_t DStream; FSE_DState_t stateLL; FSE_DState_t stateOffb; FSE_DState_t stateML; size_t prevOffset[ZSTD_REP_NUM]; const BYTE *base; size_t pos; uPtrDiff gotoDict; } seqState_t; FORCE_NOINLINE size_t ZSTD_execSequenceLast7(BYTE *op, BYTE *const oend, seq_t sequence, const BYTE **litPtr, const BYTE *const litLimit, const BYTE *const base, const BYTE *const vBase, const BYTE *const dictEnd) { BYTE *const oLitEnd = op + sequence.litLength; size_t const sequenceLength = sequence.litLength + sequence.matchLength; BYTE *const oMatchEnd = op + sequenceLength; /* risk : address space overflow (32-bits) */ BYTE *const oend_w = oend - WILDCOPY_OVERLENGTH; const BYTE *const iLitEnd = *litPtr + sequence.litLength; const BYTE *match = oLitEnd - sequence.offset; /* check */ if (oMatchEnd > oend) return ERROR(dstSize_tooSmall); /* last match must start at a minimum distance of WILDCOPY_OVERLENGTH from oend */ if (iLitEnd > litLimit) return ERROR(corruption_detected); /* over-read beyond lit buffer */ if (oLitEnd <= oend_w) return ERROR(GENERIC); /* Precondition */ /* copy literals */ if (op < oend_w) { ZSTD_wildcopy(op, *litPtr, oend_w - op); *litPtr += oend_w - op; op = oend_w; } while (op < oLitEnd) *op++ = *(*litPtr)++; /* copy Match */ if (sequence.offset > (size_t)(oLitEnd - base)) { /* offset beyond prefix */ if (sequence.offset > (size_t)(oLitEnd - vBase)) return ERROR(corruption_detected); match = dictEnd - (base - match); if (match + sequence.matchLength <= dictEnd) { sys_memmove(oLitEnd, match, sequence.matchLength); return sequenceLength; } /* span extDict & currPrefixSegment */ { size_t const length1 = dictEnd - match; sys_memmove(oLitEnd, match, length1); op = oLitEnd + length1; sequence.matchLength -= length1; match = base; } } while (op < oMatchEnd) *op++ = *match++; return sequenceLength; } static seq_t ZSTD_decodeSequence(seqState_t *seqState) { seq_t seq; U32 const llCode = FSE_peekSymbol(&seqState->stateLL); U32 const mlCode = FSE_peekSymbol(&seqState->stateML); U32 const ofCode = FSE_peekSymbol(&seqState->stateOffb); /* <= maxOff, by table construction */ U32 const llBits = LL_bits[llCode]; U32 const mlBits = ML_bits[mlCode]; U32 const ofBits = ofCode; U32 const totalBits = llBits + mlBits + ofBits; static const U32 LL_base[MaxLL + 1] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 22, 24, 28, 32, 40, 48, 64, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000, 0x10000}; static const U32 ML_base[MaxML + 1] = {3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 37, 39, 41, 43, 47, 51, 59, 67, 83, 99, 0x83, 0x103, 0x203, 0x403, 0x803, 0x1003, 0x2003, 0x4003, 0x8003, 0x10003}; static const U32 OF_base[MaxOff + 1] = {0, 1, 1, 5, 0xD, 0x1D, 0x3D, 0x7D, 0xFD, 0x1FD, 0x3FD, 0x7FD, 0xFFD, 0x1FFD, 0x3FFD, 0x7FFD, 0xFFFD, 0x1FFFD, 0x3FFFD, 0x7FFFD, 0xFFFFD, 0x1FFFFD, 0x3FFFFD, 0x7FFFFD, 0xFFFFFD, 0x1FFFFFD, 0x3FFFFFD, 0x7FFFFFD, 0xFFFFFFD}; /* sequence */ { size_t offset; if (!ofCode) offset = 0; else { offset = OF_base[ofCode] + BIT_readBitsFast(&seqState->DStream, ofBits); /* <= (ZSTD_WINDOWLOG_MAX-1) bits */ if (ZSTD_32bits()) BIT_reloadDStream(&seqState->DStream); } if (ofCode <= 1) { offset += (llCode == 0); if (offset) { size_t temp = (offset == 3) ? seqState->prevOffset[0] - 1 : seqState->prevOffset[offset]; temp += !temp; /* 0 is not valid; input is corrupted; force offset to 1 */ if (offset != 1) seqState->prevOffset[2] = seqState->prevOffset[1]; seqState->prevOffset[1] = seqState->prevOffset[0]; seqState->prevOffset[0] = offset = temp; } else { offset = seqState->prevOffset[0]; } } else { seqState->prevOffset[2] = seqState->prevOffset[1]; seqState->prevOffset[1] = seqState->prevOffset[0]; seqState->prevOffset[0] = offset; } seq.offset = offset; } seq.matchLength = ML_base[mlCode] + ((mlCode > 31) ? BIT_readBitsFast(&seqState->DStream, mlBits) : 0); /* <= 16 bits */ if (ZSTD_32bits() && (mlBits + llBits > 24)) BIT_reloadDStream(&seqState->DStream); seq.litLength = LL_base[llCode] + ((llCode > 15) ? BIT_readBitsFast(&seqState->DStream, llBits) : 0); /* <= 16 bits */ if (ZSTD_32bits() || (totalBits > 64 - 7 - (LLFSELog + MLFSELog + OffFSELog))) BIT_reloadDStream(&seqState->DStream); /* ANS state update */ FSE_updateState(&seqState->stateLL, &seqState->DStream); /* <= 9 bits */ FSE_updateState(&seqState->stateML, &seqState->DStream); /* <= 9 bits */ if (ZSTD_32bits()) BIT_reloadDStream(&seqState->DStream); /* <= 18 bits */ FSE_updateState(&seqState->stateOffb, &seqState->DStream); /* <= 8 bits */ seq.match = NULL; return seq; } FORCE_INLINE size_t ZSTD_execSequence(BYTE *op, BYTE *const oend, seq_t sequence, const BYTE **litPtr, const BYTE *const litLimit, const BYTE *const base, const BYTE *const vBase, const BYTE *const dictEnd) { BYTE *const oLitEnd = op + sequence.litLength; size_t const sequenceLength = sequence.litLength + sequence.matchLength; BYTE *const oMatchEnd = op + sequenceLength; /* risk : address space overflow (32-bits) */ BYTE *const oend_w = oend - WILDCOPY_OVERLENGTH; const BYTE *const iLitEnd = *litPtr + sequence.litLength; const BYTE *match = oLitEnd - sequence.offset; /* check */ if (oMatchEnd > oend) return ERROR(dstSize_tooSmall); /* last match must start at a minimum distance of WILDCOPY_OVERLENGTH from oend */ if (iLitEnd > litLimit) return ERROR(corruption_detected); /* over-read beyond lit buffer */ if (oLitEnd > oend_w) return ZSTD_execSequenceLast7(op, oend, sequence, litPtr, litLimit, base, vBase, dictEnd); /* copy Literals */ ZSTD_copy8(op, *litPtr); if (sequence.litLength > 8) ZSTD_wildcopy(op + 8, (*litPtr) + 8, sequence.litLength - 8); /* note : since oLitEnd <= oend-WILDCOPY_OVERLENGTH, no risk of overwrite beyond oend */ op = oLitEnd; *litPtr = iLitEnd; /* update for next sequence */ /* copy Match */ if (sequence.offset > (size_t)(oLitEnd - base)) { /* offset beyond prefix */ if (sequence.offset > (size_t)(oLitEnd - vBase)) return ERROR(corruption_detected); match = dictEnd + (match - base); if (match + sequence.matchLength <= dictEnd) { sys_memmove(oLitEnd, match, sequence.matchLength); return sequenceLength; } /* span extDict & currPrefixSegment */ { size_t const length1 = dictEnd - match; sys_memmove(oLitEnd, match, length1); op = oLitEnd + length1; sequence.matchLength -= length1; match = base; if (op > oend_w || sequence.matchLength < MINMATCH) { U32 i; for (i = 0; i < sequence.matchLength; ++i) op[i] = match[i]; return sequenceLength; } } } /* Requirement: op <= oend_w && sequence.matchLength >= MINMATCH */ /* match within prefix */ if (sequence.offset < 8) { /* close range match, overlap */ static const U32 dec32table[] = {0, 1, 2, 1, 4, 4, 4, 4}; /* added */ static const int dec64table[] = {8, 8, 8, 7, 8, 9, 10, 11}; /* subtracted */ int const sub2 = dec64table[sequence.offset]; op[0] = match[0]; op[1] = match[1]; op[2] = match[2]; op[3] = match[3]; match += dec32table[sequence.offset]; ZSTD_copy4(op + 4, match); match -= sub2; } else { ZSTD_copy8(op, match); } op += 8; match += 8; if (oMatchEnd > oend - (16 - MINMATCH)) { if (op < oend_w) { ZSTD_wildcopy(op, match, oend_w - op); match += oend_w - op; op = oend_w; } while (op < oMatchEnd) *op++ = *match++; } else { ZSTD_wildcopy(op, match, (ptrdiff_t)sequence.matchLength - 8); /* works even if matchLength < 8 */ } return sequenceLength; } static size_t ZSTD_decompressSequences(ZSTD_DCtx *dctx, void *dst, size_t maxDstSize, const void *seqStart, size_t seqSize) { const BYTE *ip = (const BYTE *)seqStart; const BYTE *const iend = ip + seqSize; BYTE *const ostart = (BYTE * const)dst; BYTE *const oend = ostart + maxDstSize; BYTE *op = ostart; const BYTE *litPtr = dctx->litPtr; const BYTE *const litEnd = litPtr + dctx->litSize; const BYTE *const base = (const BYTE *)(dctx->base); const BYTE *const vBase = (const BYTE *)(dctx->vBase); const BYTE *const dictEnd = (const BYTE *)(dctx->dictEnd); int nbSeq; /* Build Decoding Tables */ { size_t const seqHSize = ZSTD_decodeSeqHeaders(dctx, &nbSeq, ip, seqSize); if (ZSTD_isError(seqHSize)) return seqHSize; ip += seqHSize; } /* Regen sequences */ if (nbSeq) { seqState_t seqState; dctx->fseEntropy = 1; { U32 i; for (i = 0; i < ZSTD_REP_NUM; i++) seqState.prevOffset[i] = dctx->entropy.rep[i]; } CHECK_E(BIT_initDStream(&seqState.DStream, ip, iend - ip), corruption_detected); FSE_initDState(&seqState.stateLL, &seqState.DStream, dctx->LLTptr); FSE_initDState(&seqState.stateOffb, &seqState.DStream, dctx->OFTptr); FSE_initDState(&seqState.stateML, &seqState.DStream, dctx->MLTptr); for (; (BIT_reloadDStream(&(seqState.DStream)) <= BIT_DStream_completed) && nbSeq;) { nbSeq--; { seq_t const sequence = ZSTD_decodeSequence(&seqState); size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequence, &litPtr, litEnd, base, vBase, dictEnd); if (ZSTD_isError(oneSeqSize)) return oneSeqSize; op += oneSeqSize; } } /* check if reached exact end */ if (nbSeq) return ERROR(corruption_detected); /* save reps for next block */ { U32 i; for (i = 0; i < ZSTD_REP_NUM; i++) dctx->entropy.rep[i] = (U32)(seqState.prevOffset[i]); } } /* last literal segment */ { size_t const lastLLSize = litEnd - litPtr; if (lastLLSize > (size_t)(oend - op)) return ERROR(dstSize_tooSmall); memcpy(op, litPtr, lastLLSize); op += lastLLSize; } return op - ostart; } FORCE_INLINE seq_t ZSTD_decodeSequenceLong_generic(seqState_t *seqState, int const longOffsets) { seq_t seq; U32 const llCode = FSE_peekSymbol(&seqState->stateLL); U32 const mlCode = FSE_peekSymbol(&seqState->stateML); U32 const ofCode = FSE_peekSymbol(&seqState->stateOffb); /* <= maxOff, by table construction */ U32 const llBits = LL_bits[llCode]; U32 const mlBits = ML_bits[mlCode]; U32 const ofBits = ofCode; U32 const totalBits = llBits + mlBits + ofBits; static const U32 LL_base[MaxLL + 1] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 22, 24, 28, 32, 40, 48, 64, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000, 0x10000}; static const U32 ML_base[MaxML + 1] = {3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 37, 39, 41, 43, 47, 51, 59, 67, 83, 99, 0x83, 0x103, 0x203, 0x403, 0x803, 0x1003, 0x2003, 0x4003, 0x8003, 0x10003}; static const U32 OF_base[MaxOff + 1] = {0, 1, 1, 5, 0xD, 0x1D, 0x3D, 0x7D, 0xFD, 0x1FD, 0x3FD, 0x7FD, 0xFFD, 0x1FFD, 0x3FFD, 0x7FFD, 0xFFFD, 0x1FFFD, 0x3FFFD, 0x7FFFD, 0xFFFFD, 0x1FFFFD, 0x3FFFFD, 0x7FFFFD, 0xFFFFFD, 0x1FFFFFD, 0x3FFFFFD, 0x7FFFFFD, 0xFFFFFFD}; /* sequence */ { size_t offset; if (!ofCode) offset = 0; else { if (longOffsets) { int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN); offset = OF_base[ofCode] + (BIT_readBitsFast(&seqState->DStream, ofBits - extraBits) << extraBits); if (ZSTD_32bits() || extraBits) BIT_reloadDStream(&seqState->DStream); if (extraBits) offset += BIT_readBitsFast(&seqState->DStream, extraBits); } else { offset = OF_base[ofCode] + BIT_readBitsFast(&seqState->DStream, ofBits); /* <= (ZSTD_WINDOWLOG_MAX-1) bits */ if (ZSTD_32bits()) BIT_reloadDStream(&seqState->DStream); } } if (ofCode <= 1) { offset += (llCode == 0); if (offset) { size_t temp = (offset == 3) ? seqState->prevOffset[0] - 1 : seqState->prevOffset[offset]; temp += !temp; /* 0 is not valid; input is corrupted; force offset to 1 */ if (offset != 1) seqState->prevOffset[2] = seqState->prevOffset[1]; seqState->prevOffset[1] = seqState->prevOffset[0]; seqState->prevOffset[0] = offset = temp; } else { offset = seqState->prevOffset[0]; } } else { seqState->prevOffset[2] = seqState->prevOffset[1]; seqState->prevOffset[1] = seqState->prevOffset[0]; seqState->prevOffset[0] = offset; } seq.offset = offset; } seq.matchLength = ML_base[mlCode] + ((mlCode > 31) ? BIT_readBitsFast(&seqState->DStream, mlBits) : 0); /* <= 16 bits */ if (ZSTD_32bits() && (mlBits + llBits > 24)) BIT_reloadDStream(&seqState->DStream); seq.litLength = LL_base[llCode] + ((llCode > 15) ? BIT_readBitsFast(&seqState->DStream, llBits) : 0); /* <= 16 bits */ if (ZSTD_32bits() || (totalBits > 64 - 7 - (LLFSELog + MLFSELog + OffFSELog))) BIT_reloadDStream(&seqState->DStream); { size_t const pos = seqState->pos + seq.litLength; seq.match = seqState->base + pos - seq.offset; /* single memory segment */ if (seq.offset > pos) seq.match += seqState->gotoDict; /* separate memory segment */ seqState->pos = pos + seq.matchLength; } /* ANS state update */ FSE_updateState(&seqState->stateLL, &seqState->DStream); /* <= 9 bits */ FSE_updateState(&seqState->stateML, &seqState->DStream); /* <= 9 bits */ if (ZSTD_32bits()) BIT_reloadDStream(&seqState->DStream); /* <= 18 bits */ FSE_updateState(&seqState->stateOffb, &seqState->DStream); /* <= 8 bits */ return seq; } static seq_t ZSTD_decodeSequenceLong(seqState_t *seqState, unsigned const windowSize) { if (ZSTD_highbit32(windowSize) > STREAM_ACCUMULATOR_MIN) { return ZSTD_decodeSequenceLong_generic(seqState, 1); } else { return ZSTD_decodeSequenceLong_generic(seqState, 0); } } FORCE_INLINE size_t ZSTD_execSequenceLong(BYTE *op, BYTE *const oend, seq_t sequence, const BYTE **litPtr, const BYTE *const litLimit, const BYTE *const base, const BYTE *const vBase, const BYTE *const dictEnd) { BYTE *const oLitEnd = op + sequence.litLength; size_t const sequenceLength = sequence.litLength + sequence.matchLength; BYTE *const oMatchEnd = op + sequenceLength; /* risk : address space overflow (32-bits) */ BYTE *const oend_w = oend - WILDCOPY_OVERLENGTH; const BYTE *const iLitEnd = *litPtr + sequence.litLength; const BYTE *match = sequence.match; /* check */ if (oMatchEnd > oend) return ERROR(dstSize_tooSmall); /* last match must start at a minimum distance of WILDCOPY_OVERLENGTH from oend */ if (iLitEnd > litLimit) return ERROR(corruption_detected); /* over-read beyond lit buffer */ if (oLitEnd > oend_w) return ZSTD_execSequenceLast7(op, oend, sequence, litPtr, litLimit, base, vBase, dictEnd); /* copy Literals */ ZSTD_copy8(op, *litPtr); if (sequence.litLength > 8) ZSTD_wildcopy(op + 8, (*litPtr) + 8, sequence.litLength - 8); /* note : since oLitEnd <= oend-WILDCOPY_OVERLENGTH, no risk of overwrite beyond oend */ op = oLitEnd; *litPtr = iLitEnd; /* update for next sequence */ /* copy Match */ if (sequence.offset > (size_t)(oLitEnd - base)) { /* offset beyond prefix */ if (sequence.offset > (size_t)(oLitEnd - vBase)) return ERROR(corruption_detected); if (match + sequence.matchLength <= dictEnd) { sys_memmove(oLitEnd, match, sequence.matchLength); return sequenceLength; } /* span extDict & currPrefixSegment */ { size_t const length1 = dictEnd - match; sys_memmove(oLitEnd, match, length1); op = oLitEnd + length1; sequence.matchLength -= length1; match = base; if (op > oend_w || sequence.matchLength < MINMATCH) { U32 i; for (i = 0; i < sequence.matchLength; ++i) op[i] = match[i]; return sequenceLength; } } } /* Requirement: op <= oend_w && sequence.matchLength >= MINMATCH */ /* match within prefix */ if (sequence.offset < 8) { /* close range match, overlap */ static const U32 dec32table[] = {0, 1, 2, 1, 4, 4, 4, 4}; /* added */ static const int dec64table[] = {8, 8, 8, 7, 8, 9, 10, 11}; /* subtracted */ int const sub2 = dec64table[sequence.offset]; op[0] = match[0]; op[1] = match[1]; op[2] = match[2]; op[3] = match[3]; match += dec32table[sequence.offset]; ZSTD_copy4(op + 4, match); match -= sub2; } else { ZSTD_copy8(op, match); } op += 8; match += 8; if (oMatchEnd > oend - (16 - MINMATCH)) { if (op < oend_w) { ZSTD_wildcopy(op, match, oend_w - op); match += oend_w - op; op = oend_w; } while (op < oMatchEnd) *op++ = *match++; } else { ZSTD_wildcopy(op, match, (ptrdiff_t)sequence.matchLength - 8); /* works even if matchLength < 8 */ } return sequenceLength; } static size_t ZSTD_decompressSequencesLong(ZSTD_DCtx *dctx, void *dst, size_t maxDstSize, const void *seqStart, size_t seqSize) { const BYTE *ip = (const BYTE *)seqStart; const BYTE *const iend = ip + seqSize; BYTE *const ostart = (BYTE * const)dst; BYTE *const oend = ostart + maxDstSize; BYTE *op = ostart; const BYTE *litPtr = dctx->litPtr; const BYTE *const litEnd = litPtr + dctx->litSize; const BYTE *const base = (const BYTE *)(dctx->base); const BYTE *const vBase = (const BYTE *)(dctx->vBase); const BYTE *const dictEnd = (const BYTE *)(dctx->dictEnd); unsigned const windowSize = dctx->fParams.windowSize; int nbSeq; /* Build Decoding Tables */ { size_t const seqHSize = ZSTD_decodeSeqHeaders(dctx, &nbSeq, ip, seqSize); if (ZSTD_isError(seqHSize)) return seqHSize; ip += seqHSize; } /* Regen sequences */ if (nbSeq) { #define STORED_SEQS 4 #define STOSEQ_MASK (STORED_SEQS - 1) #define ADVANCED_SEQS 4 seq_t *sequences = (seq_t *)dctx->entropy.workspace; int const seqAdvance = MIN(nbSeq, ADVANCED_SEQS); seqState_t seqState; int seqNb; ZSTD_STATIC_ASSERT(sizeof(dctx->entropy.workspace) >= sizeof(seq_t) * STORED_SEQS); dctx->fseEntropy = 1; { U32 i; for (i = 0; i < ZSTD_REP_NUM; i++) seqState.prevOffset[i] = dctx->entropy.rep[i]; } seqState.base = base; seqState.pos = (size_t)(op - base); seqState.gotoDict = (uPtrDiff)dictEnd - (uPtrDiff)base; /* cast to avoid undefined behaviour */ CHECK_E(BIT_initDStream(&seqState.DStream, ip, iend - ip), corruption_detected); FSE_initDState(&seqState.stateLL, &seqState.DStream, dctx->LLTptr); FSE_initDState(&seqState.stateOffb, &seqState.DStream, dctx->OFTptr); FSE_initDState(&seqState.stateML, &seqState.DStream, dctx->MLTptr); /* prepare in advance */ for (seqNb = 0; (BIT_reloadDStream(&seqState.DStream) <= BIT_DStream_completed) && seqNb < seqAdvance; seqNb++) { sequences[seqNb] = ZSTD_decodeSequenceLong(&seqState, windowSize); } if (seqNb < seqAdvance) return ERROR(corruption_detected); /* decode and decompress */ for (; (BIT_reloadDStream(&(seqState.DStream)) <= BIT_DStream_completed) && seqNb < nbSeq; seqNb++) { seq_t const sequence = ZSTD_decodeSequenceLong(&seqState, windowSize); size_t const oneSeqSize = ZSTD_execSequenceLong(op, oend, sequences[(seqNb - ADVANCED_SEQS) & STOSEQ_MASK], &litPtr, litEnd, base, vBase, dictEnd); if (ZSTD_isError(oneSeqSize)) return oneSeqSize; ZSTD_PREFETCH(sequence.match); sequences[seqNb & STOSEQ_MASK] = sequence; op += oneSeqSize; } if (seqNb < nbSeq) return ERROR(corruption_detected); /* finish queue */ seqNb -= seqAdvance; for (; seqNb < nbSeq; seqNb++) { size_t const oneSeqSize = ZSTD_execSequenceLong(op, oend, sequences[seqNb & STOSEQ_MASK], &litPtr, litEnd, base, vBase, dictEnd); if (ZSTD_isError(oneSeqSize)) return oneSeqSize; op += oneSeqSize; } /* save reps for next block */ { U32 i; for (i = 0; i < ZSTD_REP_NUM; i++) dctx->entropy.rep[i] = (U32)(seqState.prevOffset[i]); } } /* last literal segment */ { size_t const lastLLSize = litEnd - litPtr; if (lastLLSize > (size_t)(oend - op)) return ERROR(dstSize_tooSmall); memcpy(op, litPtr, lastLLSize); op += lastLLSize; } return op - ostart; } static size_t ZSTD_decompressBlock_internal(ZSTD_DCtx *dctx, void *dst, size_t dstCapacity, const void *src, size_t srcSize) { /* blockType == blockCompressed */ const BYTE *ip = (const BYTE *)src; if (srcSize >= ZSTD_BLOCKSIZE_ABSOLUTEMAX) return ERROR(srcSize_wrong); /* Decode literals section */ { size_t const litCSize = ZSTD_decodeLiteralsBlock(dctx, src, srcSize); if (ZSTD_isError(litCSize)) return litCSize; ip += litCSize; srcSize -= litCSize; } if (sizeof(size_t) > 4) /* do not enable prefetching on 32-bits x86, as it's performance detrimental */ /* likely because of register pressure */ /* if that's the correct cause, then 32-bits ARM should be affected differently */ /* it would be good to test this on ARM real hardware, to see if prefetch version improves speed */ if (dctx->fParams.windowSize > (1 << 23)) return ZSTD_decompressSequencesLong(dctx, dst, dstCapacity, ip, srcSize); return ZSTD_decompressSequences(dctx, dst, dstCapacity, ip, srcSize); } static void ZSTD_checkContinuity(ZSTD_DCtx *dctx, const void *dst) { if (dst != dctx->previousDstEnd) { /* not contiguous */ dctx->dictEnd = dctx->previousDstEnd; dctx->vBase = (const char *)dst - ((const char *)(dctx->previousDstEnd) - (const char *)(dctx->base)); dctx->base = dst; dctx->previousDstEnd = dst; } } size_t ZSTD_decompressBlock(ZSTD_DCtx *dctx, void *dst, size_t dstCapacity, const void *src, size_t srcSize) { size_t dSize; ZSTD_checkContinuity(dctx, dst); dSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize); dctx->previousDstEnd = (char *)dst + dSize; return dSize; } size_t ZSTD_generateNxBytes(void *dst, size_t dstCapacity, BYTE byte, size_t length) { if (length > dstCapacity) return ERROR(dstSize_tooSmall); memset(dst, byte, length); return length; } /** ZSTD_findFrameCompressedSize() : * compatible with legacy mode * `src` must point to the start of a ZSTD frame, ZSTD legacy frame, or skippable frame * `srcSize` must be at least as large as the frame contained * @return : the compressed size of the frame starting at `src` */ size_t ZSTD_findFrameCompressedSize(const void *src, size_t srcSize) { if (srcSize >= ZSTD_skippableHeaderSize && (ZSTD_readLE32(src) & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) { return ZSTD_skippableHeaderSize + ZSTD_readLE32((const BYTE *)src + 4); } else { const BYTE *ip = (const BYTE *)src; const BYTE *const ipstart = ip; size_t remainingSize = srcSize; ZSTD_frameParams fParams; size_t const headerSize = ZSTD_frameHeaderSize(ip, remainingSize); if (ZSTD_isError(headerSize)) return headerSize; /* Frame Header */ { size_t const ret = ZSTD_getFrameParams(&fParams, ip, remainingSize); if (ZSTD_isError(ret)) return ret; if (ret > 0) return ERROR(srcSize_wrong); } ip += headerSize; remainingSize -= headerSize; /* Loop on each block */ while (1) { blockProperties_t blockProperties; size_t const cBlockSize = ZSTD_getcBlockSize(ip, remainingSize, &blockProperties); if (ZSTD_isError(cBlockSize)) return cBlockSize; if (ZSTD_blockHeaderSize + cBlockSize > remainingSize) return ERROR(srcSize_wrong); ip += ZSTD_blockHeaderSize + cBlockSize; remainingSize -= ZSTD_blockHeaderSize + cBlockSize; if (blockProperties.lastBlock) break; } if (fParams.checksumFlag) { /* Frame content checksum */ if (remainingSize < 4) return ERROR(srcSize_wrong); ip += 4; remainingSize -= 4; } return ip - ipstart; } } /*! ZSTD_decompressFrame() : * @dctx must be properly initialized */ static size_t ZSTD_decompressFrame(ZSTD_DCtx *dctx, void *dst, size_t dstCapacity, const void **srcPtr, size_t *srcSizePtr) { const BYTE *ip = (const BYTE *)(*srcPtr); BYTE *const ostart = (BYTE * const)dst; BYTE *const oend = ostart + dstCapacity; BYTE *op = ostart; size_t remainingSize = *srcSizePtr; /* check */ if (remainingSize < ZSTD_frameHeaderSize_min + ZSTD_blockHeaderSize) return ERROR(srcSize_wrong); /* Frame Header */ { size_t const frameHeaderSize = ZSTD_frameHeaderSize(ip, ZSTD_frameHeaderSize_prefix); if (ZSTD_isError(frameHeaderSize)) return frameHeaderSize; if (remainingSize < frameHeaderSize + ZSTD_blockHeaderSize) return ERROR(srcSize_wrong); CHECK_F(ZSTD_decodeFrameHeader(dctx, ip, frameHeaderSize)); ip += frameHeaderSize; remainingSize -= frameHeaderSize; } /* Loop on each block */ while (1) { size_t decodedSize; blockProperties_t blockProperties; size_t const cBlockSize = ZSTD_getcBlockSize(ip, remainingSize, &blockProperties); if (ZSTD_isError(cBlockSize)) return cBlockSize; ip += ZSTD_blockHeaderSize; remainingSize -= ZSTD_blockHeaderSize; if (cBlockSize > remainingSize) return ERROR(srcSize_wrong); switch (blockProperties.blockType) { case bt_compressed: decodedSize = ZSTD_decompressBlock_internal(dctx, op, oend - op, ip, cBlockSize); break; case bt_raw: decodedSize = ZSTD_copyRawBlock(op, oend - op, ip, cBlockSize); break; case bt_rle: decodedSize = ZSTD_generateNxBytes(op, oend - op, *ip, blockProperties.origSize); break; case bt_reserved: default: return ERROR(corruption_detected); } if (ZSTD_isError(decodedSize)) return decodedSize; if (dctx->fParams.checksumFlag) xxh64_update(&dctx->xxhState, op, decodedSize); op += decodedSize; ip += cBlockSize; remainingSize -= cBlockSize; if (blockProperties.lastBlock) break; } if (dctx->fParams.checksumFlag) { /* Frame content checksum verification */ U32 const checkCalc = (U32)xxh64_digest(&dctx->xxhState); U32 checkRead; if (remainingSize < 4) return ERROR(checksum_wrong); checkRead = ZSTD_readLE32(ip); if (checkRead != checkCalc) return ERROR(checksum_wrong); ip += 4; remainingSize -= 4; } /* Allow caller to get size read */ *srcPtr = ip; *srcSizePtr = remainingSize; return op - ostart; } static size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx *dctx, const void *dict, size_t dictSize); static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx *dctx, void *dst, size_t dstCapacity, const void *src, size_t srcSize, const void *dict, size_t dictSize) { void *const dststart = dst; while (srcSize >= ZSTD_frameHeaderSize_prefix) { U32 magicNumber; magicNumber = ZSTD_readLE32(src); if (magicNumber != ZSTD_MAGICNUMBER) { if ((magicNumber & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) { size_t skippableSize; if (srcSize < ZSTD_skippableHeaderSize) return ERROR(srcSize_wrong); skippableSize = ZSTD_readLE32((const BYTE *)src + 4) + ZSTD_skippableHeaderSize; if (srcSize < skippableSize) { return ERROR(srcSize_wrong); } src = (const BYTE *)src + skippableSize; srcSize -= skippableSize; continue; } else { return ERROR(prefix_unknown); } } /* this will initialize correctly with no dict if dict == NULL */ CHECK_F(ZSTD_decompressBegin_usingDict(dctx, dict, dictSize)); ZSTD_checkContinuity(dctx, dst); { const size_t res = ZSTD_decompressFrame(dctx, dst, dstCapacity, &src, &srcSize); if (ZSTD_isError(res)) return res; /* don't need to bounds check this, ZSTD_decompressFrame will have * already */ dst = (BYTE *)dst + res; dstCapacity -= res; } } if (srcSize) return ERROR(srcSize_wrong); /* input not entirely consumed */ return (BYTE *)dst - (BYTE *)dststart; } /*-************************************** * Advanced Streaming Decompression API * Bufferless and synchronous ****************************************/ size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx *dctx) { return dctx->expected; } static ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx *dctx) { switch (dctx->stage) { default: /* should not happen */ case ZSTDds_getFrameHeaderSize: case ZSTDds_decodeFrameHeader: return ZSTDnit_frameHeader; case ZSTDds_decodeBlockHeader: return ZSTDnit_blockHeader; case ZSTDds_decompressBlock: return ZSTDnit_block; case ZSTDds_decompressLastBlock: return ZSTDnit_lastBlock; case ZSTDds_checkChecksum: return ZSTDnit_checksum; case ZSTDds_decodeSkippableHeader: case ZSTDds_skipFrame: return ZSTDnit_skippableFrame; } } int ZSTD_isSkipFrame(ZSTD_DCtx *dctx) { return dctx->stage == ZSTDds_skipFrame; } /* for zbuff */ /** ZSTD_decompressContinue() : * @return : nb of bytes generated into `dst` (necessarily <= `dstCapacity) * or an error code, which can be tested using ZSTD_isError() */ size_t ZSTD_decompressContinue(ZSTD_DCtx *dctx, void *dst, size_t dstCapacity, const void *src, size_t srcSize) { /* Sanity check */ if (srcSize != dctx->expected) return ERROR(srcSize_wrong); if (dstCapacity) ZSTD_checkContinuity(dctx, dst); switch (dctx->stage) { case ZSTDds_getFrameHeaderSize: if (srcSize != ZSTD_frameHeaderSize_prefix) return ERROR(srcSize_wrong); /* impossible */ if ((ZSTD_readLE32(src) & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) { /* skippable frame */ memcpy(dctx->headerBuffer, src, ZSTD_frameHeaderSize_prefix); dctx->expected = ZSTD_skippableHeaderSize - ZSTD_frameHeaderSize_prefix; /* magic number + skippable frame length */ dctx->stage = ZSTDds_decodeSkippableHeader; return 0; } dctx->headerSize = ZSTD_frameHeaderSize(src, ZSTD_frameHeaderSize_prefix); if (ZSTD_isError(dctx->headerSize)) return dctx->headerSize; memcpy(dctx->headerBuffer, src, ZSTD_frameHeaderSize_prefix); if (dctx->headerSize > ZSTD_frameHeaderSize_prefix) { dctx->expected = dctx->headerSize - ZSTD_frameHeaderSize_prefix; dctx->stage = ZSTDds_decodeFrameHeader; return 0; } dctx->expected = 0; /* not necessary to copy more */ case ZSTDds_decodeFrameHeader: memcpy(dctx->headerBuffer + ZSTD_frameHeaderSize_prefix, src, dctx->expected); CHECK_F(ZSTD_decodeFrameHeader(dctx, dctx->headerBuffer, dctx->headerSize)); dctx->expected = ZSTD_blockHeaderSize; dctx->stage = ZSTDds_decodeBlockHeader; return 0; case ZSTDds_decodeBlockHeader: { blockProperties_t bp; size_t const cBlockSize = ZSTD_getcBlockSize(src, ZSTD_blockHeaderSize, &bp); if (ZSTD_isError(cBlockSize)) return cBlockSize; dctx->expected = cBlockSize; dctx->bType = bp.blockType; dctx->rleSize = bp.origSize; if (cBlockSize) { dctx->stage = bp.lastBlock ? ZSTDds_decompressLastBlock : ZSTDds_decompressBlock; return 0; } /* empty block */ if (bp.lastBlock) { if (dctx->fParams.checksumFlag) { dctx->expected = 4; dctx->stage = ZSTDds_checkChecksum; } else { dctx->expected = 0; /* end of frame */ dctx->stage = ZSTDds_getFrameHeaderSize; } } else { dctx->expected = 3; /* go directly to next header */ dctx->stage = ZSTDds_decodeBlockHeader; } return 0; } case ZSTDds_decompressLastBlock: case ZSTDds_decompressBlock: { size_t rSize; switch (dctx->bType) { case bt_compressed: rSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize); break; case bt_raw: rSize = ZSTD_copyRawBlock(dst, dstCapacity, src, srcSize); break; case bt_rle: rSize = ZSTD_setRleBlock(dst, dstCapacity, src, srcSize, dctx->rleSize); break; case bt_reserved: /* should never happen */ default: return ERROR(corruption_detected); } if (ZSTD_isError(rSize)) return rSize; if (dctx->fParams.checksumFlag) xxh64_update(&dctx->xxhState, dst, rSize); if (dctx->stage == ZSTDds_decompressLastBlock) { /* end of frame */ if (dctx->fParams.checksumFlag) { /* another round for frame checksum */ dctx->expected = 4; dctx->stage = ZSTDds_checkChecksum; } else { dctx->expected = 0; /* ends here */ dctx->stage = ZSTDds_getFrameHeaderSize; } } else { dctx->stage = ZSTDds_decodeBlockHeader; dctx->expected = ZSTD_blockHeaderSize; dctx->previousDstEnd = (char *)dst + rSize; } return rSize; } case ZSTDds_checkChecksum: { U32 const h32 = (U32)xxh64_digest(&dctx->xxhState); U32 const check32 = ZSTD_readLE32(src); /* srcSize == 4, guaranteed by dctx->expected */ if (check32 != h32) return ERROR(checksum_wrong); dctx->expected = 0; dctx->stage = ZSTDds_getFrameHeaderSize; return 0; } case ZSTDds_decodeSkippableHeader: { memcpy(dctx->headerBuffer + ZSTD_frameHeaderSize_prefix, src, dctx->expected); dctx->expected = ZSTD_readLE32(dctx->headerBuffer + 4); dctx->stage = ZSTDds_skipFrame; return 0; } case ZSTDds_skipFrame: { dctx->expected = 0; dctx->stage = ZSTDds_getFrameHeaderSize; return 0; } default: return ERROR(GENERIC); /* impossible */ } } static size_t ZSTD_refDictContent(ZSTD_DCtx *dctx, const void *dict, size_t dictSize) { dctx->dictEnd = dctx->previousDstEnd; dctx->vBase = (const char *)dict - ((const char *)(dctx->previousDstEnd) - (const char *)(dctx->base)); dctx->base = dict; dctx->previousDstEnd = (const char *)dict + dictSize; return 0; } /* ZSTD_loadEntropy() : * dict : must point at beginning of a valid zstd dictionary * @return : size of entropy tables read */ static size_t ZSTD_loadEntropy(ZSTD_entropyTables_t *entropy, const void *const dict, size_t const dictSize) { const BYTE *dictPtr = (const BYTE *)dict; const BYTE *const dictEnd = dictPtr + dictSize; if (dictSize <= 8) return ERROR(dictionary_corrupted); dictPtr += 8; /* skip header = magic + dictID */ { size_t const hSize = HUF_readDTableX4_wksp(entropy->hufTable, dictPtr, dictEnd - dictPtr, entropy->workspace, sizeof(entropy->workspace)); if (HUF_isError(hSize)) return ERROR(dictionary_corrupted); dictPtr += hSize; } { short offcodeNCount[MaxOff + 1]; U32 offcodeMaxValue = MaxOff, offcodeLog; size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd - dictPtr); if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted); if (offcodeLog > OffFSELog) return ERROR(dictionary_corrupted); CHECK_E(FSE_buildDTable_wksp(entropy->OFTable, offcodeNCount, offcodeMaxValue, offcodeLog, entropy->workspace, sizeof(entropy->workspace)), dictionary_corrupted); dictPtr += offcodeHeaderSize; } { short matchlengthNCount[MaxML + 1]; unsigned matchlengthMaxValue = MaxML, matchlengthLog; size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd - dictPtr); if (FSE_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted); if (matchlengthLog > MLFSELog) return ERROR(dictionary_corrupted); CHECK_E(FSE_buildDTable_wksp(entropy->MLTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog, entropy->workspace, sizeof(entropy->workspace)), dictionary_corrupted); dictPtr += matchlengthHeaderSize; } { short litlengthNCount[MaxLL + 1]; unsigned litlengthMaxValue = MaxLL, litlengthLog; size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd - dictPtr); if (FSE_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted); if (litlengthLog > LLFSELog) return ERROR(dictionary_corrupted); CHECK_E(FSE_buildDTable_wksp(entropy->LLTable, litlengthNCount, litlengthMaxValue, litlengthLog, entropy->workspace, sizeof(entropy->workspace)), dictionary_corrupted); dictPtr += litlengthHeaderSize; } if (dictPtr + 12 > dictEnd) return ERROR(dictionary_corrupted); { int i; size_t const dictContentSize = (size_t)(dictEnd - (dictPtr + 12)); for (i = 0; i < 3; i++) { U32 const rep = ZSTD_readLE32(dictPtr); dictPtr += 4; if (rep == 0 || rep >= dictContentSize) return ERROR(dictionary_corrupted); entropy->rep[i] = rep; } } return dictPtr - (const BYTE *)dict; } static size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx *dctx, const void *dict, size_t dictSize) { if (dictSize < 8) return ZSTD_refDictContent(dctx, dict, dictSize); { U32 const magic = ZSTD_readLE32(dict); if (magic != ZSTD_DICT_MAGIC) { return ZSTD_refDictContent(dctx, dict, dictSize); /* pure content mode */ } } dctx->dictID = ZSTD_readLE32((const char *)dict + 4); /* load entropy tables */ { size_t const eSize = ZSTD_loadEntropy(&dctx->entropy, dict, dictSize); if (ZSTD_isError(eSize)) return ERROR(dictionary_corrupted); dict = (const char *)dict + eSize; dictSize -= eSize; } dctx->litEntropy = dctx->fseEntropy = 1; /* reference dictionary content */ return ZSTD_refDictContent(dctx, dict, dictSize); } static size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx *dctx, const void *dict, size_t dictSize) { CHECK_F(ZSTD_decompressBegin(dctx)); if (dict && dictSize) CHECK_E(ZSTD_decompress_insertDictionary(dctx, dict, dictSize), dictionary_corrupted); return 0; } /*===================================== * Streaming decompression *====================================*/ typedef enum { zdss_init, zdss_loadHeader, zdss_read, zdss_load, zdss_flush } ZSTD_dStreamStage; /* *** Resource management *** */ struct ZSTD_DStream_s { ZSTD_DCtx *dctx; ZSTD_frameParams fParams; ZSTD_dStreamStage stage; char *inBuff; size_t inBuffSize; size_t inPos; size_t maxWindowSize; char *outBuff; size_t outBuffSize; size_t outStart; size_t outEnd; size_t blockSize; BYTE headerBuffer[ZSTD_FRAMEHEADERSIZE_MAX]; /* tmp buffer to store frame header */ size_t lhSize; U32 hostageByte; }; /* typedef'd to ZSTD_DStream within "zstd.h" */ typedef struct ZSTD_DStreamWorkspace { ZSTD_DStream DStream; ZSTD_DCtx DCtx; char Buffer[0]; } ZSTD_DStreamWorkspace; size_t ZSTD_DStreamWorkspaceBound(size_t maxWindowSize) { size_t const blockSize = MIN(maxWindowSize, ZSTD_BLOCKSIZE_ABSOLUTEMAX); size_t const inBuffSize = blockSize; size_t const outBuffSize = maxWindowSize + blockSize + WILDCOPY_OVERLENGTH * 2; return sizeof(ZSTD_DStreamWorkspace) + inBuffSize + outBuffSize; } ZSTD_DStream *ZSTD_initDStream(size_t maxWindowSize, void *workspace, size_t workspaceSize) { ZSTD_DStreamWorkspace *ws = (ZSTD_DStreamWorkspace *)workspace; ZSTD_DStream *zds = &ws->DStream; memset(zds, 0, sizeof(ZSTD_DStream)); zds->dctx = &ws->DCtx; ZSTD_decompressBegin(zds->dctx); zds->maxWindowSize = maxWindowSize; zds->stage = zdss_loadHeader; zds->lhSize = zds->inPos = zds->outStart = zds->outEnd = 0; zds->hostageByte = 0; size_t const blockSize = MIN(zds->maxWindowSize, ZSTD_BLOCKSIZE_ABSOLUTEMAX); size_t const neededOutSize = zds->maxWindowSize + blockSize + WILDCOPY_OVERLENGTH * 2; zds->inBuff = ws->Buffer; zds->inBuffSize = blockSize; zds->outBuff = ws->Buffer + blockSize; zds->outBuffSize = neededOutSize; return zds; } /* *** Initialization *** */ size_t ZSTD_resetDStream(ZSTD_DStream *zds) { zds->stage = zdss_loadHeader; zds->lhSize = zds->inPos = zds->outStart = zds->outEnd = 0; zds->hostageByte = 0; return ZSTD_frameHeaderSize_prefix; } /* ***** Decompression ***** */ ZSTD_STATIC size_t ZSTD_limitCopy(void *dst, size_t dstCapacity, const void *src, size_t srcSize) { size_t const length = MIN(dstCapacity, srcSize); memcpy(dst, src, length); return length; } size_t ZSTD_decompressStream(ZSTD_DStream *zds, ZSTD_outBuffer *output, ZSTD_inBuffer *input) { const char *const istart = (const char *)(input->src) + input->pos; const char *const iend = (const char *)(input->src) + input->size; const char *ip = istart; char *const ostart = (char *)(output->dst) + output->pos; char *const oend = (char *)(output->dst) + output->size; char *op = ostart; U32 someMoreWork = 1; while (someMoreWork) { switch (zds->stage) { case zdss_init: ZSTD_resetDStream(zds); /* transparent reset on starting decoding a new frame */ /* fall-through */ case zdss_loadHeader: { size_t const hSize = ZSTD_getFrameParams(&zds->fParams, zds->headerBuffer, zds->lhSize); if (ZSTD_isError(hSize)) return hSize; if (hSize != 0) { /* need more input */ size_t const toLoad = hSize - zds->lhSize; /* if hSize!=0, hSize > zds->lhSize */ if (toLoad > (size_t)(iend - ip)) { /* not enough input to load full header */ memcpy(zds->headerBuffer + zds->lhSize, ip, iend - ip); zds->lhSize += iend - ip; input->pos = input->size; return (MAX(ZSTD_frameHeaderSize_min, hSize) - zds->lhSize) + ZSTD_blockHeaderSize; /* remaining header bytes + next block header */ } memcpy(zds->headerBuffer + zds->lhSize, ip, toLoad); zds->lhSize = hSize; ip += toLoad; break; } /* check for single-pass mode opportunity */ if (zds->fParams.frameContentSize && zds->fParams.windowSize /* skippable frame if == 0 */ && (U64)(size_t)(oend - op) >= zds->fParams.frameContentSize) { size_t const cSize = ZSTD_findFrameCompressedSize(istart, iend - istart); if (cSize <= (size_t)(iend - istart)) { size_t const decompressedSize = ZSTD_decompressMultiFrame(zds->dctx, op, oend - op, istart, cSize, NULL, 0); if (ZSTD_isError(decompressedSize)) return decompressedSize; ip = istart + cSize; op += decompressedSize; zds->dctx->expected = 0; zds->stage = zdss_init; someMoreWork = 0; break; } } /* Consume header */ ZSTD_decompressBegin(zds->dctx); { size_t const h1Size = ZSTD_nextSrcSizeToDecompress(zds->dctx); /* == ZSTD_frameHeaderSize_prefix */ CHECK_F(ZSTD_decompressContinue(zds->dctx, NULL, 0, zds->headerBuffer, h1Size)); { size_t const h2Size = ZSTD_nextSrcSizeToDecompress(zds->dctx); CHECK_F(ZSTD_decompressContinue(zds->dctx, NULL, 0, zds->headerBuffer + h1Size, h2Size)); } } zds->fParams.windowSize = MAX(zds->fParams.windowSize, 1U << ZSTD_WINDOWLOG_ABSOLUTEMIN); if (zds->fParams.windowSize > zds->maxWindowSize) return ERROR(frameParameter_windowTooLarge); zds->stage = zdss_read; } /* pass-through */ case zdss_read: { size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zds->dctx); if (neededInSize == 0) { /* end of frame */ zds->stage = zdss_init; someMoreWork = 0; break; } if ((size_t)(iend - ip) >= neededInSize) { /* decode directly from src */ const int isSkipFrame = ZSTD_isSkipFrame(zds->dctx); size_t const decodedSize = ZSTD_decompressContinue(zds->dctx, zds->outBuff + zds->outStart, (isSkipFrame ? 0 : zds->outBuffSize - zds->outStart), ip, neededInSize); if (ZSTD_isError(decodedSize)) return decodedSize; ip += neededInSize; if (!decodedSize && !isSkipFrame) break; /* this was just a header */ zds->outEnd = zds->outStart + decodedSize; zds->stage = zdss_flush; break; } if (ip == iend) { someMoreWork = 0; break; } /* no more input */ zds->stage = zdss_load; /* pass-through */ } case zdss_load: { size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zds->dctx); size_t const toLoad = neededInSize - zds->inPos; /* should always be <= remaining space within inBuff */ size_t loadedSize; if (toLoad > zds->inBuffSize - zds->inPos) return ERROR(corruption_detected); /* should never happen */ loadedSize = ZSTD_limitCopy(zds->inBuff + zds->inPos, toLoad, ip, iend - ip); ip += loadedSize; zds->inPos += loadedSize; if (loadedSize < toLoad) { someMoreWork = 0; break; } /* not enough input, wait for more */ /* decode loaded input */ { const int isSkipFrame = ZSTD_isSkipFrame(zds->dctx); size_t const decodedSize = ZSTD_decompressContinue(zds->dctx, zds->outBuff + zds->outStart, zds->outBuffSize - zds->outStart, zds->inBuff, neededInSize); if (ZSTD_isError(decodedSize)) return decodedSize; zds->inPos = 0; /* input is consumed */ if (!decodedSize && !isSkipFrame) { zds->stage = zdss_read; break; } /* this was just a header */ zds->outEnd = zds->outStart + decodedSize; zds->stage = zdss_flush; /* pass-through */ } } case zdss_flush: { size_t const toFlushSize = zds->outEnd - zds->outStart; size_t const flushedSize = ZSTD_limitCopy(op, oend - op, zds->outBuff + zds->outStart, toFlushSize); op += flushedSize; zds->outStart += flushedSize; if (flushedSize == toFlushSize) { /* flush completed */ zds->stage = zdss_read; if (zds->outStart + zds->blockSize > zds->outBuffSize) zds->outStart = zds->outEnd = 0; break; } /* cannot complete flush */ someMoreWork = 0; break; } default: return ERROR(GENERIC); /* impossible */ } } /* result */ input->pos += (size_t)(ip - istart); output->pos += (size_t)(op - ostart); { size_t nextSrcSizeHint = ZSTD_nextSrcSizeToDecompress(zds->dctx); if (!nextSrcSizeHint) { /* frame fully decoded */ if (zds->outEnd == zds->outStart) { /* output fully flushed */ if (zds->hostageByte) { if (input->pos >= input->size) { zds->stage = zdss_read; return 1; } /* can't release hostage (not present) */ input->pos++; /* release hostage */ } return 0; } if (!zds->hostageByte) { /* output not fully flushed; keep last byte as hostage; will be released when all output is flushed */ input->pos--; /* note : pos > 0, otherwise, impossible to finish reading last block */ zds->hostageByte = 1; } return 1; } nextSrcSizeHint += ZSTD_blockHeaderSize * (ZSTD_nextInputType(zds->dctx) == ZSTDnit_block); /* preload header of next block */ if (zds->inPos > nextSrcSizeHint) return ERROR(GENERIC); /* should never happen */ nextSrcSizeHint -= zds->inPos; /* already loaded*/ return nextSrcSizeHint; } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/zstd/huf.h����������������������������������������������������������������0000644�0001750�0001750�00000027777�13363346003�017623� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Huffman coder, part of New Generation Entropy library * header file * Copyright (C) 2013-2016, Yann Collet. * * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License version 2 as published by the * Free Software Foundation. This program is dual-licensed; you may select * either version 2 of the GNU General Public License ("GPL") or BSD license * ("BSD"). * * You can contact the author at : * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy */ #ifndef HUF_H_298734234 #define HUF_H_298734234 /* *** Dependencies *** */ /* *** Tool functions *** */ #define HUF_BLOCKSIZE_MAX (128 * 1024) /**< maximum input size for a single block compressed with HUF_compress */ size_t HUF_compressBound(size_t size); /**< maximum compressed size (worst case) */ /* Error Management */ unsigned HUF_isError(size_t code); /**< tells if a return value is an error code */ /* *** Advanced function *** */ /** HUF_compress4X_wksp() : * Same as HUF_compress2(), but uses externally allocated `workSpace`, which must be a table of >= 1024 unsigned */ size_t HUF_compress4X_wksp(void *dst, size_t dstSize, const void *src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void *workSpace, size_t wkspSize); /**< `workSpace` must be a table of at least HUF_COMPRESS_WORKSPACE_SIZE_U32 unsigned */ /* *** Dependencies *** */ #include "mem.h" /* U32 */ /* *** Constants *** */ #define HUF_TABLELOG_MAX 12 /* max configured tableLog (for static allocation); can be modified up to HUF_ABSOLUTEMAX_TABLELOG */ #define HUF_TABLELOG_DEFAULT 11 /* tableLog by default, when not specified */ #define HUF_SYMBOLVALUE_MAX 255 #define HUF_TABLELOG_ABSOLUTEMAX 15 /* absolute limit of HUF_MAX_TABLELOG. Beyond that value, code does not work */ #if (HUF_TABLELOG_MAX > HUF_TABLELOG_ABSOLUTEMAX) #error "HUF_TABLELOG_MAX is too large !" #endif /* **************************************** * Static allocation ******************************************/ /* HUF buffer bounds */ #define HUF_CTABLEBOUND 129 #define HUF_BLOCKBOUND(size) (size + (size >> 8) + 8) /* only true if incompressible pre-filtered with fast heuristic */ #define HUF_COMPRESSBOUND(size) (HUF_CTABLEBOUND + HUF_BLOCKBOUND(size)) /* Macro version, useful for static allocation */ /* static allocation of HUF's Compression Table */ #define HUF_CREATE_STATIC_CTABLE(name, maxSymbolValue) \ U32 name##hb[maxSymbolValue + 1]; \ void *name##hv = &(name##hb); \ HUF_CElt *name = (HUF_CElt *)(name##hv) /* no final ; */ /* static allocation of HUF's DTable */ typedef U32 HUF_DTable; #define HUF_DTABLE_SIZE(maxTableLog) (1 + (1 << (maxTableLog))) #define HUF_CREATE_STATIC_DTABLEX2(DTable, maxTableLog) HUF_DTable DTable[HUF_DTABLE_SIZE((maxTableLog)-1)] = {((U32)((maxTableLog)-1) * 0x01000001)} #define HUF_CREATE_STATIC_DTABLEX4(DTable, maxTableLog) HUF_DTable DTable[HUF_DTABLE_SIZE(maxTableLog)] = {((U32)(maxTableLog)*0x01000001)} /* The workspace must have alignment at least 4 and be at least this large */ #define HUF_COMPRESS_WORKSPACE_SIZE (6 << 10) #define HUF_COMPRESS_WORKSPACE_SIZE_U32 (HUF_COMPRESS_WORKSPACE_SIZE / sizeof(U32)) /* The workspace must have alignment at least 4 and be at least this large */ #define HUF_DECOMPRESS_WORKSPACE_SIZE (3 << 10) #define HUF_DECOMPRESS_WORKSPACE_SIZE_U32 (HUF_DECOMPRESS_WORKSPACE_SIZE / sizeof(U32)) /* **************************************** * Advanced decompression functions ******************************************/ size_t HUF_decompress4X_DCtx_wksp(HUF_DTable *dctx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t workspaceSize); /**< decodes RLE and uncompressed */ size_t HUF_decompress4X_hufOnly_wksp(HUF_DTable *dctx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t workspaceSize); /**< considers RLE and uncompressed as errors */ size_t HUF_decompress4X2_DCtx_wksp(HUF_DTable *dctx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t workspaceSize); /**< single-symbol decoder */ size_t HUF_decompress4X4_DCtx_wksp(HUF_DTable *dctx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t workspaceSize); /**< double-symbols decoder */ /* **************************************** * HUF detailed API ******************************************/ /*! HUF_compress() does the following: 1. count symbol occurrence from source[] into table count[] using FSE_count() 2. (optional) refine tableLog using HUF_optimalTableLog() 3. build Huffman table from count using HUF_buildCTable() 4. save Huffman table to memory buffer using HUF_writeCTable_wksp() 5. encode the data stream using HUF_compress4X_usingCTable() The following API allows targeting specific sub-functions for advanced tasks. For example, it's possible to compress several blocks using the same 'CTable', or to save and regenerate 'CTable' using external methods. */ /* FSE_count() : find it within "fse.h" */ unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue); typedef struct HUF_CElt_s HUF_CElt; /* incomplete type */ size_t HUF_writeCTable_wksp(void *dst, size_t maxDstSize, const HUF_CElt *CTable, unsigned maxSymbolValue, unsigned huffLog, void *workspace, size_t workspaceSize); size_t HUF_compress4X_usingCTable(void *dst, size_t dstSize, const void *src, size_t srcSize, const HUF_CElt *CTable); typedef enum { HUF_repeat_none, /**< Cannot use the previous table */ HUF_repeat_check, /**< Can use the previous table but it must be checked. Note : The previous table must have been constructed by HUF_compress{1, 4}X_repeat */ HUF_repeat_valid /**< Can use the previous table and it is asumed to be valid */ } HUF_repeat; /** HUF_compress4X_repeat() : * Same as HUF_compress4X_wksp(), but considers using hufTable if *repeat != HUF_repeat_none. * If it uses hufTable it does not modify hufTable or repeat. * If it doesn't, it sets *repeat = HUF_repeat_none, and it sets hufTable to the table used. * If preferRepeat then the old table will always be used if valid. */ size_t HUF_compress4X_repeat(void *dst, size_t dstSize, const void *src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void *workSpace, size_t wkspSize, HUF_CElt *hufTable, HUF_repeat *repeat, int preferRepeat); /**< `workSpace` must be a table of at least HUF_COMPRESS_WORKSPACE_SIZE_U32 unsigned */ /** HUF_buildCTable_wksp() : * Same as HUF_buildCTable(), but using externally allocated scratch buffer. * `workSpace` must be aligned on 4-bytes boundaries, and be at least as large as a table of 1024 unsigned. */ size_t HUF_buildCTable_wksp(HUF_CElt *tree, const U32 *count, U32 maxSymbolValue, U32 maxNbBits, void *workSpace, size_t wkspSize); /*! HUF_readStats() : Read compact Huffman tree, saved by HUF_writeCTable(). `huffWeight` is destination buffer. @return : size read from `src` , or an error Code . Note : Needed by HUF_readCTable() and HUF_readDTableXn() . */ size_t HUF_readStats_wksp(BYTE *huffWeight, size_t hwSize, U32 *rankStats, U32 *nbSymbolsPtr, U32 *tableLogPtr, const void *src, size_t srcSize, void *workspace, size_t workspaceSize); /** HUF_readCTable() : * Loading a CTable saved with HUF_writeCTable() */ size_t HUF_readCTable_wksp(HUF_CElt *CTable, unsigned maxSymbolValue, const void *src, size_t srcSize, void *workspace, size_t workspaceSize); /* HUF_decompress() does the following: 1. select the decompression algorithm (X2, X4) based on pre-computed heuristics 2. build Huffman table from save, using HUF_readDTableXn() 3. decode 1 or 4 segments in parallel using HUF_decompressSXn_usingDTable */ /** HUF_selectDecoder() : * Tells which decoder is likely to decode faster, * based on a set of pre-determined metrics. * @return : 0==HUF_decompress4X2, 1==HUF_decompress4X4 . * Assumption : 0 < cSrcSize < dstSize <= 128 KB */ U32 HUF_selectDecoder(size_t dstSize, size_t cSrcSize); size_t HUF_readDTableX2_wksp(HUF_DTable *DTable, const void *src, size_t srcSize, void *workspace, size_t workspaceSize); size_t HUF_readDTableX4_wksp(HUF_DTable *DTable, const void *src, size_t srcSize, void *workspace, size_t workspaceSize); size_t HUF_decompress4X_usingDTable(void *dst, size_t maxDstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable); size_t HUF_decompress4X2_usingDTable(void *dst, size_t maxDstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable); size_t HUF_decompress4X4_usingDTable(void *dst, size_t maxDstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable); /* single stream variants */ size_t HUF_compress1X_wksp(void *dst, size_t dstSize, const void *src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void *workSpace, size_t wkspSize); /**< `workSpace` must be a table of at least HUF_COMPRESS_WORKSPACE_SIZE_U32 unsigned */ size_t HUF_compress1X_usingCTable(void *dst, size_t dstSize, const void *src, size_t srcSize, const HUF_CElt *CTable); /** HUF_compress1X_repeat() : * Same as HUF_compress1X_wksp(), but considers using hufTable if *repeat != HUF_repeat_none. * If it uses hufTable it does not modify hufTable or repeat. * If it doesn't, it sets *repeat = HUF_repeat_none, and it sets hufTable to the table used. * If preferRepeat then the old table will always be used if valid. */ size_t HUF_compress1X_repeat(void *dst, size_t dstSize, const void *src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void *workSpace, size_t wkspSize, HUF_CElt *hufTable, HUF_repeat *repeat, int preferRepeat); /**< `workSpace` must be a table of at least HUF_COMPRESS_WORKSPACE_SIZE_U32 unsigned */ size_t HUF_decompress1X_DCtx_wksp(HUF_DTable *dctx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t workspaceSize); size_t HUF_decompress1X2_DCtx_wksp(HUF_DTable *dctx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t workspaceSize); /**< single-symbol decoder */ size_t HUF_decompress1X4_DCtx_wksp(HUF_DTable *dctx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t workspaceSize); /**< double-symbols decoder */ size_t HUF_decompress1X_usingDTable(void *dst, size_t maxDstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable); /**< automatic selection of sing or double symbol decoder, based on DTable */ size_t HUF_decompress1X2_usingDTable(void *dst, size_t maxDstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable); size_t HUF_decompress1X4_usingDTable(void *dst, size_t maxDstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable); #endif /* HUF_H_298734234 */ �refind-0.11.4/filesystems/zstd/error_private.h������������������������������������������������������0000644�0001750�0001750�00000002561�13363346003�021704� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/** * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of https://github.com/facebook/zstd. * An additional grant of patent rights can be found in the PATENTS file in the * same directory. * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License version 2 as published by the * Free Software Foundation. This program is dual-licensed; you may select * either version 2 of the GNU General Public License ("GPL") or BSD license * ("BSD"). */ /* Note : this module is expected to remain private, do not expose it */ #ifndef ERROR_H_MODULE #define ERROR_H_MODULE /* **************************************** * Dependencies ******************************************/ #include "zstd.h" /* enum list */ /*-**************************************** * Customization (error_public.h) ******************************************/ #define PREFIX(name) ZSTD_error_##name /*-**************************************** * Error codes handling ******************************************/ #define ERROR(name) ((size_t)-PREFIX(name)) #define ERR_isError ZSTD_isError /* for inlining */ #define FSE_isError ZSTD_isError #define HUF_isError ZSTD_isError #endif /* ERROR_H_MODULE */ �����������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/zstd/zstd_internal.h������������������������������������������������������0000644�0001750�0001750�00000013146�13363346003�021702� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/** * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of https://github.com/facebook/zstd. * An additional grant of patent rights can be found in the PATENTS file in the * same directory. * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License version 2 as published by the * Free Software Foundation. This program is dual-licensed; you may select * either version 2 of the GNU General Public License ("GPL") or BSD license * ("BSD"). */ #ifndef ZSTD_CCOMMON_H_MODULE #define ZSTD_CCOMMON_H_MODULE /*-******************************************************* * Compiler specifics *********************************************************/ #define FORCE_INLINE static __always_inline #define FORCE_NOINLINE static /*noinline*/ /*-************************************* * Dependencies ***************************************/ #include "error_private.h" #include "mem.h" #include "xxhash.h" #include "zstd.h" /*-************************************* * shared macros ***************************************/ #ifndef MIN #define MIN(a, b) ((a) < (b) ? (a) : (b)) #endif #ifndef MAX #define MAX(a, b) ((a) > (b) ? (a) : (b)) #endif #define CHECK_F(f) \ { \ size_t const errcod = f; \ if (ERR_isError(errcod)) \ return errcod; \ } /* check and Forward error code */ #define CHECK_E(f, e) \ { \ size_t const errcod = f; \ if (ZSTD_isError(errcod)) \ return ERROR(e); \ } /* check and send Error code */ #define ZSTD_STATIC_ASSERT(c) \ { \ enum { ZSTD_static_assert = 1 / (int)(!!(c)) }; \ } /*-************************************* * Common constants ***************************************/ #define ZSTD_OPT_NUM (1 << 12) #define ZSTD_DICT_MAGIC 0xEC30A437 /* v0.7+ */ #define ZSTD_REP_NUM 3 /* number of repcodes */ #define ZSTD_REP_CHECK (ZSTD_REP_NUM) /* number of repcodes to check by the optimal parser */ #define ZSTD_REP_MOVE (ZSTD_REP_NUM - 1) #define ZSTD_REP_MOVE_OPT (ZSTD_REP_NUM) static const U32 repStartValue[ZSTD_REP_NUM] = {1, 4, 8}; #define ZSTD_WINDOWLOG_ABSOLUTEMIN 10 static const size_t ZSTD_fcs_fieldSize[4] = {0, 2, 4, 8}; static const size_t ZSTD_did_fieldSize[4] = {0, 1, 2, 4}; #define ZSTD_BLOCKHEADERSIZE 3 /* C standard doesn't allow `static const` variable to be init using another `static const` variable */ static const size_t ZSTD_blockHeaderSize = ZSTD_BLOCKHEADERSIZE; typedef enum { bt_raw, bt_rle, bt_compressed, bt_reserved } blockType_e; #define MIN_SEQUENCES_SIZE 1 /* nbSeq==0 */ #define MIN_CBLOCK_SIZE (1 /*litCSize*/ + 1 /* RLE or RAW */ + MIN_SEQUENCES_SIZE /* nbSeq==0 */) /* for a non-null block */ #define HufLog 12 typedef enum { set_basic, set_rle, set_compressed, set_repeat } symbolEncodingType_e; #define LONGNBSEQ 0x7F00 #define MINMATCH 3 #define EQUAL_READ32 4 #define Litbits 8 #define MaxLit ((1 << Litbits) - 1) #define MaxML 52 #define MaxLL 35 #define MaxOff 28 #define MaxSeq MAX(MaxLL, MaxML) /* Assumption : MaxOff < MaxLL,MaxML */ #define MLFSELog 9 #define LLFSELog 9 #define OffFSELog 8 static const U32 LL_bits[MaxLL + 1] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; static const S16 LL_defaultNorm[MaxLL + 1] = {4, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 1, 1, 1, 1, 1, -1, -1, -1, -1}; #define LL_DEFAULTNORMLOG 6 /* for static allocation */ static const U32 LL_defaultNormLog = LL_DEFAULTNORMLOG; static const U32 ML_bits[MaxML + 1] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; static const S16 ML_defaultNorm[MaxML + 1] = {1, 4, 3, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1}; #define ML_DEFAULTNORMLOG 6 /* for static allocation */ static const U32 ML_defaultNormLog = ML_DEFAULTNORMLOG; static const S16 OF_defaultNorm[MaxOff + 1] = {1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1}; #define OF_DEFAULTNORMLOG 5 /* for static allocation */ static const U32 OF_defaultNormLog = OF_DEFAULTNORMLOG; /*-******************************************* * Shared functions to include for inlining *********************************************/ ZSTD_STATIC void ZSTD_copy8(void *dst, const void *src) { memcpy(dst, src, 8); } /*! ZSTD_wildcopy() : * custom version of memcpy(), can copy up to 7 bytes too many (8 bytes if length==0) */ #define WILDCOPY_OVERLENGTH 8 ZSTD_STATIC void ZSTD_wildcopy(void *dst, const void *src, ptrdiff_t length) { const BYTE* ip = (const BYTE*)src; BYTE* op = (BYTE*)dst; BYTE* const oend = op + length; /* Work around https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81388. * Avoid the bad case where the loop only runs once by handling the * special case separately. This doesn't trigger the bug because it * doesn't involve pointer/integer overflow. */ if (length <= 8) return ZSTD_copy8(dst, src); do { ZSTD_copy8(op, ip); op += 8; ip += 8; } while (op < oend); } /*====== common function ======*/ ZSTD_STATIC U32 ZSTD_highbit32(U32 val) { return 31 - __builtin_clz(val); } #endif /* ZSTD_CCOMMON_H_MODULE */ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/zstd/bitstream.h����������������������������������������������������������0000644�0001750�0001750�00000024574�13363346003�021023� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * bitstream * Part of FSE library * header file (to include) * Copyright (C) 2013-2016, Yann Collet. * * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License version 2 as published by the * Free Software Foundation. This program is dual-licensed; you may select * either version 2 of the GNU General Public License ("GPL") or BSD license * ("BSD"). * * You can contact the author at : * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy */ #ifndef BITSTREAM_H_MODULE #define BITSTREAM_H_MODULE /* * This API consists of small unitary functions, which must be inlined for best performance. * Since link-time-optimization is not available for all compilers, * these functions are defined into a .h to be included. */ /*-**************************************** * Dependencies ******************************************/ #include "error_private.h" /* error codes and messages */ #include "mem.h" /* unaligned access routines */ /*========================================= * Target specific =========================================*/ #define STREAM_ACCUMULATOR_MIN_32 25 #define STREAM_ACCUMULATOR_MIN_64 57 #define STREAM_ACCUMULATOR_MIN ((U32)(ZSTD_32bits() ? STREAM_ACCUMULATOR_MIN_32 : STREAM_ACCUMULATOR_MIN_64)) /*-******************************************** * bitStream decoding API (read backward) **********************************************/ typedef struct { size_t bitContainer; unsigned bitsConsumed; const char *ptr; const char *start; } BIT_DStream_t; typedef enum { BIT_DStream_unfinished = 0, BIT_DStream_endOfBuffer = 1, BIT_DStream_completed = 2, BIT_DStream_overflow = 3 } BIT_DStream_status; /* result of BIT_reloadDStream() */ /* 1,2,4,8 would be better for bitmap combinations, but slows down performance a bit ... :( */ ZSTD_STATIC size_t BIT_initDStream(BIT_DStream_t *bitD, const void *srcBuffer, size_t srcSize); ZSTD_STATIC size_t BIT_readBits(BIT_DStream_t *bitD, unsigned nbBits); ZSTD_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t *bitD); ZSTD_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t *bitD); /* Start by invoking BIT_initDStream(). * A chunk of the bitStream is then stored into a local register. * Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (size_t). * You can then retrieve bitFields stored into the local register, **in reverse order**. * Local register is explicitly reloaded from memory by the BIT_reloadDStream() method. * A reload guarantee a minimum of ((8*sizeof(bitD->bitContainer))-7) bits when its result is BIT_DStream_unfinished. * Otherwise, it can be less than that, so proceed accordingly. * Checking if DStream has reached its end can be performed with BIT_endOfDStream(). */ ZSTD_STATIC size_t BIT_readBitsFast(BIT_DStream_t *bitD, unsigned nbBits); /* faster, but works only if nbBits >= 1 */ /*-************************************************************** * Internal functions ****************************************************************/ ZSTD_STATIC unsigned BIT_highbit32(register U32 val) { return 31 - __builtin_clz(val); } /*===== Local Constants =====*/ static const unsigned BIT_mask[] = {0, 1, 3, 7, 0xF, 0x1F, 0x3F, 0x7F, 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF, 0x1FFFF, 0x3FFFF, 0x7FFFF, 0xFFFFF, 0x1FFFFF, 0x3FFFFF, 0x7FFFFF, 0xFFFFFF, 0x1FFFFFF, 0x3FFFFFF}; /* up to 26 bits */ /*-******************************************************** * bitStream decoding **********************************************************/ /*! BIT_initDStream() : * Initialize a BIT_DStream_t. * `bitD` : a pointer to an already allocated BIT_DStream_t structure. * `srcSize` must be the *exact* size of the bitStream, in bytes. * @return : size of stream (== srcSize) or an errorCode if a problem is detected */ ZSTD_STATIC size_t BIT_initDStream(BIT_DStream_t *bitD, const void *srcBuffer, size_t srcSize) { if (srcSize < 1) { memset(bitD, 0, sizeof(*bitD)); return ERROR(srcSize_wrong); } if (srcSize >= sizeof(bitD->bitContainer)) { /* normal case */ bitD->start = (const char *)srcBuffer; bitD->ptr = (const char *)srcBuffer + srcSize - sizeof(bitD->bitContainer); bitD->bitContainer = ZSTD_readLEST(bitD->ptr); { BYTE const lastByte = ((const BYTE *)srcBuffer)[srcSize - 1]; bitD->bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0; /* ensures bitsConsumed is always set */ if (lastByte == 0) return ERROR(GENERIC); /* endMark not present */ } } else { bitD->start = (const char *)srcBuffer; bitD->ptr = bitD->start; bitD->bitContainer = *(const BYTE *)(bitD->start); switch (srcSize) { case 7: bitD->bitContainer += (size_t)(((const BYTE *)(srcBuffer))[6]) << (sizeof(bitD->bitContainer) * 8 - 16); case 6: bitD->bitContainer += (size_t)(((const BYTE *)(srcBuffer))[5]) << (sizeof(bitD->bitContainer) * 8 - 24); case 5: bitD->bitContainer += (size_t)(((const BYTE *)(srcBuffer))[4]) << (sizeof(bitD->bitContainer) * 8 - 32); case 4: bitD->bitContainer += (size_t)(((const BYTE *)(srcBuffer))[3]) << 24; case 3: bitD->bitContainer += (size_t)(((const BYTE *)(srcBuffer))[2]) << 16; case 2: bitD->bitContainer += (size_t)(((const BYTE *)(srcBuffer))[1]) << 8; default:; } { BYTE const lastByte = ((const BYTE *)srcBuffer)[srcSize - 1]; bitD->bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0; if (lastByte == 0) return ERROR(GENERIC); /* endMark not present */ } bitD->bitsConsumed += (U32)(sizeof(bitD->bitContainer) - srcSize) * 8; } return srcSize; } ZSTD_STATIC size_t BIT_getUpperBits(size_t bitContainer, U32 const start) { return bitContainer >> start; } ZSTD_STATIC size_t BIT_getMiddleBits(size_t bitContainer, U32 const start, U32 const nbBits) { return (bitContainer >> start) & BIT_mask[nbBits]; } ZSTD_STATIC size_t BIT_getLowerBits(size_t bitContainer, U32 const nbBits) { return bitContainer & BIT_mask[nbBits]; } /*! BIT_lookBits() : * Provides next n bits from local register. * local register is not modified. * On 32-bits, maxNbBits==24. * On 64-bits, maxNbBits==56. * @return : value extracted */ ZSTD_STATIC size_t BIT_lookBits(const BIT_DStream_t *bitD, U32 nbBits) { U32 const bitMask = sizeof(bitD->bitContainer) * 8 - 1; return ((bitD->bitContainer << (bitD->bitsConsumed & bitMask)) >> 1) >> ((bitMask - nbBits) & bitMask); } /*! BIT_lookBitsFast() : * unsafe version; only works only if nbBits >= 1 */ ZSTD_STATIC size_t BIT_lookBitsFast(const BIT_DStream_t *bitD, U32 nbBits) { U32 const bitMask = sizeof(bitD->bitContainer) * 8 - 1; return (bitD->bitContainer << (bitD->bitsConsumed & bitMask)) >> (((bitMask + 1) - nbBits) & bitMask); } ZSTD_STATIC void BIT_skipBits(BIT_DStream_t *bitD, U32 nbBits) { bitD->bitsConsumed += nbBits; } /*! BIT_readBits() : * Read (consume) next n bits from local register and update. * Pay attention to not read more than nbBits contained into local register. * @return : extracted value. */ ZSTD_STATIC size_t BIT_readBits(BIT_DStream_t *bitD, U32 nbBits) { size_t const value = BIT_lookBits(bitD, nbBits); BIT_skipBits(bitD, nbBits); return value; } /*! BIT_readBitsFast() : * unsafe version; only works only if nbBits >= 1 */ ZSTD_STATIC size_t BIT_readBitsFast(BIT_DStream_t *bitD, U32 nbBits) { size_t const value = BIT_lookBitsFast(bitD, nbBits); BIT_skipBits(bitD, nbBits); return value; } /*! BIT_reloadDStream() : * Refill `bitD` from buffer previously set in BIT_initDStream() . * This function is safe, it guarantees it will not read beyond src buffer. * @return : status of `BIT_DStream_t` internal register. if status == BIT_DStream_unfinished, internal register is filled with >= (sizeof(bitD->bitContainer)*8 - 7) bits */ ZSTD_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t *bitD) { if (bitD->bitsConsumed > (sizeof(bitD->bitContainer) * 8)) /* should not happen => corruption detected */ return BIT_DStream_overflow; if (bitD->ptr >= bitD->start + sizeof(bitD->bitContainer)) { bitD->ptr -= bitD->bitsConsumed >> 3; bitD->bitsConsumed &= 7; bitD->bitContainer = ZSTD_readLEST(bitD->ptr); return BIT_DStream_unfinished; } if (bitD->ptr == bitD->start) { if (bitD->bitsConsumed < sizeof(bitD->bitContainer) * 8) return BIT_DStream_endOfBuffer; return BIT_DStream_completed; } { U32 nbBytes = bitD->bitsConsumed >> 3; BIT_DStream_status result = BIT_DStream_unfinished; if (bitD->ptr - nbBytes < bitD->start) { nbBytes = (U32)(bitD->ptr - bitD->start); /* ptr > start */ result = BIT_DStream_endOfBuffer; } bitD->ptr -= nbBytes; bitD->bitsConsumed -= nbBytes * 8; bitD->bitContainer = ZSTD_readLEST(bitD->ptr); /* reminder : srcSize > sizeof(bitD) */ return result; } } /*! BIT_endOfDStream() : * @return Tells if DStream has exactly reached its end (all bits consumed). */ ZSTD_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t *DStream) { return ((DStream->ptr == DStream->start) && (DStream->bitsConsumed == sizeof(DStream->bitContainer) * 8)); } #endif /* BITSTREAM_H_MODULE */ ������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/zstd/zstd.h���������������������������������������������������������������0000644�0001750�0001750�00000040762�13363346003�020012� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of https://github.com/facebook/zstd. * An additional grant of patent rights can be found in the PATENTS file in the * same directory. * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License version 2 as published by the * Free Software Foundation. This program is dual-licensed; you may select * either version 2 of the GNU General Public License ("GPL") or BSD license * ("BSD"). */ #ifndef ZSTD_H #define ZSTD_H /* ====== Dependency ======*/ /*-***************************************************************************** * Introduction * * zstd, short for Zstandard, is a fast lossless compression algorithm, * targeting real-time compression scenarios at zlib-level and better * compression ratios. The zstd compression library provides in-memory * compression and decompression functions. The library supports compression * levels from 1 up to ZSTD_maxCLevel() which is 22. Levels >= 20, labeled * ultra, should be used with caution, as they require more memory. * Compression can be done in: * - a single step, reusing a context (described as Explicit memory management) * - unbounded multiple steps (described as Streaming compression) * The compression ratio achievable on small data can be highly improved using * compression with a dictionary in: * - a single step (described as Simple dictionary API) * - a single step, reusing a dictionary (described as Fast dictionary API) ******************************************************************************/ /*====== Helper functions ======*/ /** * enum ZSTD_ErrorCode - zstd error codes * * Functions that return size_t can be checked for errors using ZSTD_isError() * and the ZSTD_ErrorCode can be extracted using ZSTD_getErrorCode(). */ typedef enum { ZSTD_error_no_error, ZSTD_error_GENERIC, ZSTD_error_prefix_unknown, ZSTD_error_frameParameter_unsupported, ZSTD_error_frameParameter_windowTooLarge, ZSTD_error_dstSize_tooSmall, ZSTD_error_srcSize_wrong, ZSTD_error_corruption_detected, ZSTD_error_checksum_wrong, ZSTD_error_tableLog_tooLarge, ZSTD_error_maxSymbolValue_tooLarge, ZSTD_error_maxSymbolValue_tooSmall, ZSTD_error_dictionary_corrupted, ZSTD_error_dictionary_wrong, ZSTD_error_maxCode } ZSTD_ErrorCode; /** * ZSTD_maxCLevel() - maximum compression level available * * Return: Maximum compression level available. */ int ZSTD_maxCLevel(void); /** * ZSTD_compressBound() - maximum compressed size in worst case scenario * @srcSize: The size of the data to compress. * * Return: The maximum compressed size in the worst case scenario. */ size_t ZSTD_compressBound(size_t srcSize); /** * ZSTD_isError() - tells if a size_t function result is an error code * @code: The function result to check for error. * * Return: Non-zero iff the code is an error. */ static __attribute__((unused)) unsigned int ZSTD_isError(size_t code) { return code > (size_t)-ZSTD_error_maxCode; } /** * ZSTD_getErrorCode() - translates an error function result to a ZSTD_ErrorCode * @functionResult: The result of a function for which ZSTD_isError() is true. * * Return: The ZSTD_ErrorCode corresponding to the functionResult or 0 * if the functionResult isn't an error. */ static __attribute__((unused)) ZSTD_ErrorCode ZSTD_getErrorCode( size_t functionResult) { if (!ZSTD_isError(functionResult)) return (ZSTD_ErrorCode)0; return (ZSTD_ErrorCode)(0 - functionResult); } /** * enum ZSTD_strategy - zstd compression search strategy * * From faster to stronger. */ typedef enum { ZSTD_fast, ZSTD_dfast, ZSTD_greedy, ZSTD_lazy, ZSTD_lazy2, ZSTD_btlazy2, ZSTD_btopt, ZSTD_btopt2 } ZSTD_strategy; /** * struct ZSTD_compressionParameters - zstd compression parameters * @windowLog: Log of the largest match distance. Larger means more * compression, and more memory needed during decompression. * @chainLog: Fully searched segment. Larger means more compression, slower, * and more memory (useless for fast). * @hashLog: Dispatch table. Larger means more compression, * slower, and more memory. * @searchLog: Number of searches. Larger means more compression and slower. * @searchLength: Match length searched. Larger means faster decompression, * sometimes less compression. * @targetLength: Acceptable match size for optimal parser (only). Larger means * more compression, and slower. * @strategy: The zstd compression strategy. */ typedef struct { unsigned int windowLog; unsigned int chainLog; unsigned int hashLog; unsigned int searchLog; unsigned int searchLength; unsigned int targetLength; ZSTD_strategy strategy; } ZSTD_compressionParameters; /** * struct ZSTD_frameParameters - zstd frame parameters * @contentSizeFlag: Controls whether content size will be present in the frame * header (when known). * @checksumFlag: Controls whether a 32-bit checksum is generated at the end * of the frame for error detection. * @noDictIDFlag: Controls whether dictID will be saved into the frame header * when using dictionary compression. * * The default value is all fields set to 0. */ typedef struct { unsigned int contentSizeFlag; unsigned int checksumFlag; unsigned int noDictIDFlag; } ZSTD_frameParameters; /** * struct ZSTD_parameters - zstd parameters * @cParams: The compression parameters. * @fParams: The frame parameters. */ typedef struct { ZSTD_compressionParameters cParams; ZSTD_frameParameters fParams; } ZSTD_parameters; /** * ZSTD_getCParams() - returns ZSTD_compressionParameters for selected level * @compressionLevel: The compression level from 1 to ZSTD_maxCLevel(). * @estimatedSrcSize: The estimated source size to compress or 0 if unknown. * @dictSize: The dictionary size or 0 if a dictionary isn't being used. * * Return: The selected ZSTD_compressionParameters. */ ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long estimatedSrcSize, size_t dictSize); /** * ZSTD_getParams() - returns ZSTD_parameters for selected level * @compressionLevel: The compression level from 1 to ZSTD_maxCLevel(). * @estimatedSrcSize: The estimated source size to compress or 0 if unknown. * @dictSize: The dictionary size or 0 if a dictionary isn't being used. * * The same as ZSTD_getCParams() except also selects the default frame * parameters (all zero). * * Return: The selected ZSTD_parameters. */ ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long estimatedSrcSize, size_t dictSize); /*-************************** * Streaming ***************************/ /** * struct ZSTD_inBuffer - input buffer for streaming * @src: Start of the input buffer. * @size: Size of the input buffer. * @pos: Position where reading stopped. Will be updated. * Necessarily 0 <= pos <= size. */ typedef struct ZSTD_inBuffer_s { const void *src; size_t size; size_t pos; } ZSTD_inBuffer; /** * struct ZSTD_outBuffer - output buffer for streaming * @dst: Start of the output buffer. * @size: Size of the output buffer. * @pos: Position where writing stopped. Will be updated. * Necessarily 0 <= pos <= size. */ typedef struct ZSTD_outBuffer_s { void *dst; size_t size; size_t pos; } ZSTD_outBuffer; /*-***************************************************************************** * Streaming decompression - HowTo * * A ZSTD_DStream object is required to track streaming operations. * Use ZSTD_initDStream() to initialize a ZSTD_DStream object. * ZSTD_DStream objects can be re-used multiple times. * * Use ZSTD_decompressStream() repetitively to consume your input. * The function will update both `pos` fields. * If `input->pos < input->size`, some input has not been consumed. * It's up to the caller to present again remaining data. * If `output->pos < output->size`, decoder has flushed everything it could. * Returns 0 iff a frame is completely decoded and fully flushed. * Otherwise it returns a suggested next input size that will never load more * than the current frame. ******************************************************************************/ /** * ZSTD_DStreamWorkspaceBound() - memory needed to initialize a ZSTD_DStream * @maxWindowSize: The maximum window size allowed for compressed frames. * * Return: A lower bound on the size of the workspace that is passed to * ZSTD_initDStream(). */ size_t ZSTD_DStreamWorkspaceBound(size_t maxWindowSize); /** * struct ZSTD_DStream - the zstd streaming decompression context */ typedef struct ZSTD_DStream_s ZSTD_DStream; /*===== ZSTD_DStream management functions =====*/ /** * ZSTD_initDStream() - initialize a zstd streaming decompression context * @maxWindowSize: The maximum window size allowed for compressed frames. * @workspace: The workspace to emplace the context into. It must outlive * the returned context. * @workspaceSize: The size of workspace. * Use ZSTD_DStreamWorkspaceBound(maxWindowSize) to determine * how large the workspace must be. * * Return: The zstd streaming decompression context. */ ZSTD_DStream *ZSTD_initDStream(size_t maxWindowSize, void *workspace, size_t workspaceSize); /*===== Streaming decompression functions =====*/ /** * ZSTD_resetDStream() - reset the context using parameters from creation * @zds: The zstd streaming decompression context to reset. * * Resets the context using the parameters from creation. Skips dictionary * loading, since it can be reused. * * Return: Zero or an error, which can be checked using ZSTD_isError(). */ size_t ZSTD_resetDStream(ZSTD_DStream *zds); /** * ZSTD_decompressStream() - streaming decompress some of input into output * @zds: The zstd streaming decompression context. * @output: Destination buffer. `output.pos` is updated to indicate how much * decompressed data was written. * @input: Source buffer. `input.pos` is updated to indicate how much data was * read. Note that it may not consume the entire input, in which case * `input.pos < input.size`, and it's up to the caller to present * remaining data again. * * The `input` and `output` buffers may be any size. Guaranteed to make some * forward progress if `input` and `output` are not empty. * ZSTD_decompressStream() will not consume the last byte of the frame until * the entire frame is flushed. * * Return: Returns 0 iff a frame is completely decoded and fully flushed. * Otherwise returns a hint for the number of bytes to use as the input * for the next function call or an error, which can be checked using * ZSTD_isError(). The size hint will never load more than the frame. */ size_t ZSTD_decompressStream(ZSTD_DStream *zds, ZSTD_outBuffer *output, ZSTD_inBuffer *input); /** * ZSTD_DStreamInSize() - recommended size for the input buffer * * Return: The recommended size for the input buffer. */ size_t ZSTD_DStreamInSize(void); /** * ZSTD_DStreamOutSize() - recommended size for the output buffer * * When the output buffer is at least this large, it is guaranteed to be large * enough to flush at least one complete decompressed block. * * Return: The recommended size for the output buffer. */ size_t ZSTD_DStreamOutSize(void); /* --- Constants ---*/ #define ZSTD_MAGICNUMBER 0xFD2FB528 /* >= v0.8.0 */ #define ZSTD_MAGIC_SKIPPABLE_START 0x184D2A50U #define ZSTD_CONTENTSIZE_UNKNOWN (0ULL - 1) #define ZSTD_CONTENTSIZE_ERROR (0ULL - 2) #define ZSTD_WINDOWLOG_MAX_32 27 #define ZSTD_WINDOWLOG_MAX_64 27 #define ZSTD_WINDOWLOG_MAX \ ((unsigned int)(sizeof(size_t) == 4 \ ? ZSTD_WINDOWLOG_MAX_32 \ : ZSTD_WINDOWLOG_MAX_64)) #define ZSTD_WINDOWLOG_MIN 10 #define ZSTD_HASHLOG_MAX ZSTD_WINDOWLOG_MAX #define ZSTD_HASHLOG_MIN 6 #define ZSTD_CHAINLOG_MAX (ZSTD_WINDOWLOG_MAX+1) #define ZSTD_CHAINLOG_MIN ZSTD_HASHLOG_MIN #define ZSTD_HASHLOG3_MAX 17 #define ZSTD_SEARCHLOG_MAX (ZSTD_WINDOWLOG_MAX-1) #define ZSTD_SEARCHLOG_MIN 1 /* only for ZSTD_fast, other strategies are limited to 6 */ #define ZSTD_SEARCHLENGTH_MAX 7 /* only for ZSTD_btopt, other strategies are limited to 4 */ #define ZSTD_SEARCHLENGTH_MIN 3 #define ZSTD_TARGETLENGTH_MIN 4 #define ZSTD_TARGETLENGTH_MAX 999 /* for static allocation */ #define ZSTD_FRAMEHEADERSIZE_MAX 18 #define ZSTD_FRAMEHEADERSIZE_MIN 6 static const size_t ZSTD_frameHeaderSize_prefix = 5; static const size_t ZSTD_frameHeaderSize_min = ZSTD_FRAMEHEADERSIZE_MIN; static const size_t ZSTD_frameHeaderSize_max = ZSTD_FRAMEHEADERSIZE_MAX; /* magic number + skippable frame length */ static const size_t ZSTD_skippableHeaderSize = 8; /*-************************************* * Compressed size functions **************************************/ /** * ZSTD_findFrameCompressedSize() - returns the size of a compressed frame * @src: Source buffer. It should point to the start of a zstd encoded frame * or a skippable frame. * @srcSize: The size of the source buffer. It must be at least as large as the * size of the frame. * * Return: The compressed size of the frame pointed to by `src` or an error, * which can be check with ZSTD_isError(). * Suitable to pass to ZSTD_decompress() or similar functions. */ size_t ZSTD_findFrameCompressedSize(const void *src, size_t srcSize); /*-************************************* * Decompressed size functions **************************************/ /** * struct ZSTD_frameParams - zstd frame parameters stored in the frame header * @frameContentSize: The frame content size, or 0 if not present. * @windowSize: The window size, or 0 if the frame is a skippable frame. * @dictID: The dictionary id, or 0 if not present. * @checksumFlag: Whether a checksum was used. */ typedef struct { unsigned long long frameContentSize; unsigned int windowSize; unsigned int dictID; unsigned int checksumFlag; } ZSTD_frameParams; /** * ZSTD_getFrameParams() - extracts parameters from a zstd or skippable frame * @fparamsPtr: On success the frame parameters are written here. * @src: The source buffer. It must point to a zstd or skippable frame. * @srcSize: The size of the source buffer. `ZSTD_frameHeaderSize_max` is * always large enough to succeed. * * Return: 0 on success. If more data is required it returns how many bytes * must be provided to make forward progress. Otherwise it returns * an error, which can be checked using ZSTD_isError(). */ size_t ZSTD_getFrameParams(ZSTD_frameParams *fparamsPtr, const void *src, size_t srcSize); /*-***************************************************************************** * Block functions * * Block functions produce and decode raw zstd blocks, without frame metadata. * Frame metadata cost is typically ~18 bytes, which can be non-negligible for * very small blocks (< 100 bytes). User will have to take in charge required * information to regenerate data, such as compressed and content sizes. * * A few rules to respect: * - Compressing and decompressing require a context structure * + Use ZSTD_initCCtx() and ZSTD_initDCtx() * - It is necessary to init context before starting * + compression : ZSTD_compressBegin() * + decompression : ZSTD_decompressBegin() * + variants _usingDict() are also allowed * + copyCCtx() and copyDCtx() work too * - Block size is limited, it must be <= ZSTD_getBlockSizeMax() * + If you need to compress more, cut data into multiple blocks * + Consider using the regular ZSTD_compress() instead, as frame metadata * costs become negligible when source size is large. * - When a block is considered not compressible enough, ZSTD_compressBlock() * result will be zero. In which case, nothing is produced into `dst`. * + User must test for such outcome and deal directly with uncompressed data * + ZSTD_decompressBlock() doesn't accept uncompressed data as input!!! * + In case of multiple successive blocks, decoder must be informed of * uncompressed block existence to follow proper history. Use * ZSTD_insertBlock() in such a case. ******************************************************************************/ /* Define for static allocation */ #define ZSTD_BLOCKSIZE_ABSOLUTEMAX (128 * 1024) #endif /* ZSTD_H */ ��������������refind-0.11.4/filesystems/hfs.inf�������������������������������������������������������������������0000664�0001750�0001750�00000003636�13112553155�017150� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������## @file # # hfs.inf file to build rEFInd's HFS+ driver using the EDK2/UDK201# # development kit. # # Copyright (c) 2012-2017 by Roderick W. Smith # Released under the terms of the GPLv3 (or, at your discretion, any later # version), a copy of which should come with this file. # ## [Defines] INF_VERSION = 0x00010005 BASE_NAME = hfs FILE_GUID = cc9ec9b9-d3e0-418e-bfa2-b8148f11ffb8 MODULE_TYPE = UEFI_DRIVER EDK_RELEASE_VERSION = 0x00020000 EFI_SPECIFICATION_VERSION = 0x00010000 VERSION_STRING = 1.0 ENTRY_POINT = fsw_efi_main FSTYPE = hfs # # The following information is for reference only and not required by the build tools. # # VALID_ARCHITECTURES = IA32 X64 IPF EBC # [Sources] fsw_efi.c fsw_hfs.c fsw_core.c fsw_efi.c fsw_lib.c fsw_efi_lib.c [Packages] MdePkg/MdePkg.dec MdeModulePkg/MdeModulePkg.dec IntelFrameworkPkg/IntelFrameworkPkg.dec IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec [LibraryClasses] UefiDriverEntryPoint DxeServicesLib DxeServicesTableLib MemoryAllocationLib [LibraryClasses.AARCH64] BaseStackCheckLib # Comment out CompilerIntrinsicsLib when compiling for AARCH64 using UDK2014 CompilerIntrinsicsLib [Guids] [Ppis] [Protocols] [FeaturePcd] [Pcd] [BuildOptions.IA32] XCODE:*_*_*_CC_FLAGS = -Os -DEFI32 -D__MAKEWITH_TIANO -DFSTYPE=hfs GCC:*_*_*_CC_FLAGS = -Os -DEFI32 -D__MAKEWITH_TIANO -DFSTYPE=hfs [BuildOptions.X64] XCODE:*_*_*_CC_FLAGS = -Os -DEFIX64 -D__MAKEWITH_TIANO -DFSTYPE=hfs GCC:*_*_*_CC_FLAGS = -Os -DEFIX64 -D__MAKEWITH_TIANO -DFSTYPE=hfs [BuildOptions.AARCH64] XCODE:*_*_*_CC_FLAGS = -Os -DEFIAARCH64 -D__MAKEWITH_TIANO -DFSTYPE=hfs GCC:*_*_*_CC_FLAGS = -Os -DEFIAARCH64 -D__MAKEWITH_TIANO -DFSTYPE=hfs ��������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/fsw_reiserfs_disk.h�������������������������������������������������������0000664�0001750�0001750�00000206461�12626644770�021574� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/** * \file fsw_reiserfs_disk.h * ReiserFS file system on-disk structures. */ /*- * Copyright (c) 2006 Christoph Pfisterer * Portions Copyright (c) 1991-2006 by various Linux kernel contributors * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _FSW_REISERFS_DISK_H_ #define _FSW_REISERFS_DISK_H_ // types typedef fsw_s8 __s8; typedef fsw_u8 __u8; typedef fsw_s16 __s16; typedef fsw_u16 __u16; typedef fsw_s32 __s32; typedef fsw_u32 __u32; typedef fsw_s64 __s64; typedef fsw_u64 __u64; typedef __u16 __le16; typedef __u32 __le32; typedef __u64 __le64; #define le16_to_cpu(x) (x) #define cpu_to_le16(x) (x) #define le32_to_cpu(x) (x) #define cpu_to_le32(x) (x) #define le64_to_cpu(x) (x) #define cpu_to_le64(x) (x) #ifdef __GCC__ #define ATTR_PACKED __attribute__ ((__packed__)) #else #define ATTR_PACKED #endif #pragma pack(1) // // from Linux kernel, include/linux/reiserfs_fs.h // /* * Disk Data Structures */ /***************************************************************************/ /* SUPER BLOCK */ /***************************************************************************/ /* * Structure of super block on disk, a version of which in RAM is often accessed as REISERFS_SB(s)->s_rs * the version in RAM is part of a larger structure containing fields never written to disk. */ #define UNSET_HASH 0 // read_super will guess about, what hash names // in directories were sorted with #define TEA_HASH 1 #define YURA_HASH 2 #define R5_HASH 3 #define DEFAULT_HASH R5_HASH struct journal_params { __le32 jp_journal_1st_block; /* where does journal start from on its * device */ __le32 jp_journal_dev; /* journal device st_rdev */ __le32 jp_journal_size; /* size of the journal */ __le32 jp_journal_trans_max; /* max number of blocks in a transaction. */ __le32 jp_journal_magic; /* random value made on fs creation (this * was sb_journal_block_count) */ __le32 jp_journal_max_batch; /* max number of blocks to batch into a * trans */ __le32 jp_journal_max_commit_age; /* in seconds, how old can an async * commit be */ __le32 jp_journal_max_trans_age; /* in seconds, how old can a transaction * be */ }; /* this is the super from 3.5.X, where X >= 10 */ struct reiserfs_super_block_v1 { __le32 s_block_count; /* blocks count */ __le32 s_free_blocks; /* free blocks count */ __le32 s_root_block; /* root block number */ struct journal_params s_journal; __le16 s_blocksize; /* block size */ __le16 s_oid_maxsize; /* max size of object id array, see * get_objectid() commentary */ __le16 s_oid_cursize; /* current size of object id array */ __le16 s_umount_state; /* this is set to 1 when filesystem was * umounted, to 2 - when not */ char s_magic[10]; /* reiserfs magic string indicates that * file system is reiserfs: * "ReIsErFs" or "ReIsEr2Fs" or "ReIsEr3Fs" */ __le16 s_fs_state; /* it is set to used by fsck to mark which * phase of rebuilding is done */ __le32 s_hash_function_code; /* indicate, what hash function is being use * to sort names in a directory*/ __le16 s_tree_height; /* height of disk tree */ __le16 s_bmap_nr; /* amount of bitmap blocks needed to address * each block of file system */ __le16 s_version; /* this field is only reliable on filesystem * with non-standard journal */ __le16 s_reserved_for_journal; /* size in blocks of journal area on main * device, we need to keep after * making fs with non-standard journal */ } ATTR_PACKED; #define SB_SIZE_V1 (sizeof(struct reiserfs_super_block_v1)) /* this is the on disk super block */ struct reiserfs_super_block { struct reiserfs_super_block_v1 s_v1; __le32 s_inode_generation; __le32 s_flags; /* Right now used only by inode-attributes, if enabled */ unsigned char s_uuid[16]; /* filesystem unique identifier */ unsigned char s_label[16]; /* filesystem volume label */ char s_unused[88]; /* zero filled by mkreiserfs and * reiserfs_convert_objectid_map_v1() * so any additions must be updated * there as well. */ } ATTR_PACKED; #define SB_SIZE (sizeof(struct reiserfs_super_block)) #define REISERFS_VERSION_1 0 #define REISERFS_VERSION_2 2 // on-disk super block fields converted to cpu form #define SB_DISK_SUPER_BLOCK(s) (REISERFS_SB(s)->s_rs) #define SB_V1_DISK_SUPER_BLOCK(s) (&(SB_DISK_SUPER_BLOCK(s)->s_v1)) #define SB_BLOCKSIZE(s) \ le32_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_blocksize)) #define SB_BLOCK_COUNT(s) \ le32_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_block_count)) #define SB_FREE_BLOCKS(s) \ le32_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_free_blocks)) #define SB_REISERFS_MAGIC(s) \ (SB_V1_DISK_SUPER_BLOCK(s)->s_magic) #define SB_ROOT_BLOCK(s) \ le32_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_root_block)) #define SB_TREE_HEIGHT(s) \ le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_tree_height)) #define SB_REISERFS_STATE(s) \ le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_umount_state)) #define SB_VERSION(s) le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_version)) #define SB_BMAP_NR(s) le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_bmap_nr)) #define SB_ONDISK_JP(s) (&SB_V1_DISK_SUPER_BLOCK(s)->s_journal) #define SB_ONDISK_JOURNAL_SIZE(s) \ le32_to_cpu ((SB_ONDISK_JP(s)->jp_journal_size)) #define SB_ONDISK_JOURNAL_1st_BLOCK(s) \ le32_to_cpu ((SB_ONDISK_JP(s)->jp_journal_1st_block)) #define SB_ONDISK_JOURNAL_DEVICE(s) \ le32_to_cpu ((SB_ONDISK_JP(s)->jp_journal_dev)) #define SB_ONDISK_RESERVED_FOR_JOURNAL(s) \ le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_reserved_for_journal)) #define is_block_in_log_or_reserved_area(s, block) \ block >= SB_JOURNAL_1st_RESERVED_BLOCK(s) \ && block < SB_JOURNAL_1st_RESERVED_BLOCK(s) + \ ((!is_reiserfs_jr(SB_DISK_SUPER_BLOCK(s)) ? \ SB_ONDISK_JOURNAL_SIZE(s) + 1 : SB_ONDISK_RESERVED_FOR_JOURNAL(s))) /* used by gcc */ #define REISERFS_SUPER_MAGIC 0x52654973 /* used by file system utilities that look at the superblock, etc. */ #define REISERFS_SUPER_MAGIC_STRING "ReIsErFs" #define REISER2FS_SUPER_MAGIC_STRING "ReIsEr2Fs" #define REISER2FS_JR_SUPER_MAGIC_STRING "ReIsEr3Fs" /* ReiserFS leaves the first 64k unused, so that partition labels have enough space. If someone wants to write a fancy bootloader that needs more than 64k, let us know, and this will be increased in size. This number must be larger than than the largest block size on any platform, or code will break. -Hans */ #define REISERFS_DISK_OFFSET_IN_BYTES (64 * 1024) #define REISERFS_FIRST_BLOCK unused_define #define REISERFS_JOURNAL_OFFSET_IN_BYTES REISERFS_DISK_OFFSET_IN_BYTES /* the spot for the super in versions 3.5 - 3.5.10 (inclusive) */ #define REISERFS_OLD_DISK_OFFSET_IN_BYTES (8 * 1024) // reiserfs internal error code (used by search_by_key adn fix_nodes)) #define CARRY_ON 0 #define REPEAT_SEARCH -1 #define IO_ERROR -2 #define NO_DISK_SPACE -3 #define NO_BALANCING_NEEDED (-4) #define NO_MORE_UNUSED_CONTIGUOUS_BLOCKS (-5) #define QUOTA_EXCEEDED -6 typedef __u32 b_blocknr_t; typedef __le32 unp_t; struct unfm_nodeinfo { unp_t unfm_nodenum; unsigned short unfm_freespace; }; /* there are two formats of keys: 3.5 and 3.6 */ #define KEY_FORMAT_3_5 0 #define KEY_FORMAT_3_6 1 /* there are two stat datas */ #define STAT_DATA_V1 0 #define STAT_DATA_V2 1 /** this says about version of key of all items (but stat data) the object consists of */ #define get_inode_item_key_version( inode ) \ ((REISERFS_I(inode)->i_flags & i_item_key_version_mask) ? KEY_FORMAT_3_6 : KEY_FORMAT_3_5) #define set_inode_item_key_version( inode, version ) \ ({ if((version)==KEY_FORMAT_3_6) \ REISERFS_I(inode)->i_flags |= i_item_key_version_mask; \ else \ REISERFS_I(inode)->i_flags &= ~i_item_key_version_mask; }) #define get_inode_sd_version(inode) \ ((REISERFS_I(inode)->i_flags & i_stat_data_version_mask) ? STAT_DATA_V2 : STAT_DATA_V1) #define set_inode_sd_version(inode, version) \ ({ if((version)==STAT_DATA_V2) \ REISERFS_I(inode)->i_flags |= i_stat_data_version_mask; \ else \ REISERFS_I(inode)->i_flags &= ~i_stat_data_version_mask; }) /* This is an aggressive tail suppression policy, I am hoping it improves our benchmarks. The principle behind it is that percentage space saving is what matters, not absolute space saving. This is non-intuitive, but it helps to understand it if you consider that the cost to access 4 blocks is not much more than the cost to access 1 block, if you have to do a seek and rotate. A tail risks a non-linear disk access that is significant as a percentage of total time cost for a 4 block file and saves an amount of space that is less significant as a percentage of space, or so goes the hypothesis. -Hans */ #define STORE_TAIL_IN_UNFM_S1(n_file_size,n_tail_size,n_block_size) \ (\ (!(n_tail_size)) || \ (((n_tail_size) > MAX_DIRECT_ITEM_LEN(n_block_size)) || \ ( (n_file_size) >= (n_block_size) * 4 ) || \ ( ( (n_file_size) >= (n_block_size) * 3 ) && \ ( (n_tail_size) >= (MAX_DIRECT_ITEM_LEN(n_block_size))/4) ) || \ ( ( (n_file_size) >= (n_block_size) * 2 ) && \ ( (n_tail_size) >= (MAX_DIRECT_ITEM_LEN(n_block_size))/2) ) || \ ( ( (n_file_size) >= (n_block_size) ) && \ ( (n_tail_size) >= (MAX_DIRECT_ITEM_LEN(n_block_size) * 3)/4) ) ) \ ) /* Another strategy for tails, this one means only create a tail if all the file would fit into one DIRECT item. Primary intention for this one is to increase performance by decreasing seeking. */ #define STORE_TAIL_IN_UNFM_S2(n_file_size,n_tail_size,n_block_size) \ (\ (!(n_tail_size)) || \ (((n_file_size) > MAX_DIRECT_ITEM_LEN(n_block_size)) ) \ ) /* * values for s_umount_state field */ #define REISERFS_VALID_FS 1 #define REISERFS_ERROR_FS 2 // // there are 5 item types currently // #define TYPE_STAT_DATA 0 #define TYPE_INDIRECT 1 #define TYPE_DIRECT 2 #define TYPE_DIRENTRY 3 #define TYPE_MAXTYPE 3 #define TYPE_ANY 15 // FIXME: comment is required /***************************************************************************/ /* KEY & ITEM HEAD */ /***************************************************************************/ // // directories use this key as well as old files // struct offset_v1 { __le32 k_offset; __le32 k_uniqueness; } ATTR_PACKED; struct offset_v2 { __le64 v; } ATTR_PACKED; /* static inline __u16 offset_v2_k_type(const struct offset_v2 *v2) { __u8 type = le64_to_cpu(v2->v) >> 60; return (type <= TYPE_MAXTYPE) ? type : TYPE_ANY; } static inline loff_t offset_v2_k_offset(const struct offset_v2 *v2) { return le64_to_cpu(v2->v) & (~0ULL >> 4); } */ /* Key of an item determines its location in the S+tree, and is composed of 4 components */ struct reiserfs_key { __le32 k_dir_id; /* packing locality: by default parent directory object id */ __le32 k_objectid; /* object identifier */ union { struct offset_v1 k_offset_v1; struct offset_v2 k_offset_v2; } ATTR_PACKED u; } ATTR_PACKED; struct in_core_key { __u32 k_dir_id; /* packing locality: by default parent directory object id */ __u32 k_objectid; /* object identifier */ __u64 k_offset; __u8 k_type; }; struct cpu_key { struct in_core_key on_disk_key; int version; int key_length; /* 3 in all cases but direct2indirect and indirect2direct conversion */ }; /* Our function for comparing keys can compare keys of different lengths. It takes as a parameter the length of the keys it is to compare. These defines are used in determining what is to be passed to it as that parameter. */ #define REISERFS_FULL_KEY_LEN 4 #define REISERFS_SHORT_KEY_LEN 2 /* The result of the key compare */ #define FIRST_GREATER 1 #define SECOND_GREATER -1 #define KEYS_IDENTICAL 0 #define KEY_FOUND 1 #define KEY_NOT_FOUND 0 #define KEY_SIZE (sizeof(struct reiserfs_key)) #define SHORT_KEY_SIZE (sizeof (__u32) + sizeof (__u32)) /* return values for search_by_key and clones */ #define ITEM_FOUND 1 #define ITEM_NOT_FOUND 0 #define ENTRY_FOUND 1 #define ENTRY_NOT_FOUND 0 #define DIRECTORY_NOT_FOUND -1 #define REGULAR_FILE_FOUND -2 #define DIRECTORY_FOUND -3 #define BYTE_FOUND 1 #define BYTE_NOT_FOUND 0 #define FILE_NOT_FOUND -1 #define POSITION_FOUND 1 #define POSITION_NOT_FOUND 0 // return values for reiserfs_find_entry and search_by_entry_key #define NAME_FOUND 1 #define NAME_NOT_FOUND 0 #define GOTO_PREVIOUS_ITEM 2 #define NAME_FOUND_INVISIBLE 3 /* Everything in the filesystem is stored as a set of items. The item head contains the key of the item, its free space (for indirect items) and specifies the location of the item itself within the block. */ struct item_head { /* Everything in the tree is found by searching for it based on * its key.*/ struct reiserfs_key ih_key; union { /* The free space in the last unformatted node of an indirect item if this is an indirect item. This equals 0xFFFF iff this is a direct item or stat data item. Note that the key, not this field, is used to determine the item type, and thus which field this union contains. */ __le16 ih_free_space_reserved; /* Iff this is a directory item, this field equals the number of directory entries in the directory item. */ __le16 ih_entry_count; } ATTR_PACKED u; __le16 ih_item_len; /* total size of the item body */ __le16 ih_item_location; /* an offset to the item body * within the block */ __le16 ih_version; /* 0 for all old items, 2 for new ones. Highest bit is set by fsck temporary, cleaned after all done */ } ATTR_PACKED; /* size of item header */ #define IH_SIZE (sizeof(struct item_head)) #define ih_free_space(ih) le16_to_cpu((ih)->u.ih_free_space_reserved) #define ih_version(ih) le16_to_cpu((ih)->ih_version) #define ih_entry_count(ih) le16_to_cpu((ih)->u.ih_entry_count) #define ih_location(ih) le16_to_cpu((ih)->ih_item_location) #define ih_item_len(ih) le16_to_cpu((ih)->ih_item_len) #define unreachable_item(ih) (ih_version(ih) & (1 << 15)) #define get_ih_free_space(ih) (ih_version (ih) == KEY_FORMAT_3_6 ? 0 : ih_free_space (ih)) /* these operate on indirect items, where you've got an array of ints ** at a possibly unaligned location. These are a noop on ia32 ** ** p is the array of __u32, i is the index into the array, v is the value ** to store there. */ #define get_block_num(p, i) le32_to_cpu(get_unaligned((p) + (i))) // // in old version uniqueness field shows key type // #define V1_SD_UNIQUENESS 0 #define V1_INDIRECT_UNIQUENESS 0xfffffffe #define V1_DIRECT_UNIQUENESS 0xffffffff #define V1_DIRENTRY_UNIQUENESS 500 #define V1_ANY_UNIQUENESS 555 // FIXME: comment is required // // here are conversion routines // /* static inline int uniqueness2type(__u32 uniqueness) { switch ((int)uniqueness) { case V1_SD_UNIQUENESS: return TYPE_STAT_DATA; case V1_INDIRECT_UNIQUENESS: return TYPE_INDIRECT; case V1_DIRECT_UNIQUENESS: return TYPE_DIRECT; case V1_DIRENTRY_UNIQUENESS: return TYPE_DIRENTRY; default: reiserfs_warning(NULL, "vs-500: unknown uniqueness %d", uniqueness); case V1_ANY_UNIQUENESS: return TYPE_ANY; } } static inline __u32 type2uniqueness(int type) { switch (type) { case TYPE_STAT_DATA: return V1_SD_UNIQUENESS; case TYPE_INDIRECT: return V1_INDIRECT_UNIQUENESS; case TYPE_DIRECT: return V1_DIRECT_UNIQUENESS; case TYPE_DIRENTRY: return V1_DIRENTRY_UNIQUENESS; default: reiserfs_warning(NULL, "vs-501: unknown type %d", type); case TYPE_ANY: return V1_ANY_UNIQUENESS; } } */ // // key is pointer to on disk key which is stored in le, result is cpu, // there is no way to get version of object from key, so, provide // version to these defines // /* static inline loff_t le_key_k_offset(int version, const struct reiserfs_key *key) { return (version == KEY_FORMAT_3_5) ? le32_to_cpu(key->u.k_offset_v1.k_offset) : offset_v2_k_offset(&(key->u.k_offset_v2)); } static inline loff_t le_ih_k_offset(const struct item_head *ih) { return le_key_k_offset(ih_version(ih), &(ih->ih_key)); } static inline loff_t le_key_k_type(int version, const struct reiserfs_key *key) { return (version == KEY_FORMAT_3_5) ? uniqueness2type(le32_to_cpu(key->u.k_offset_v1.k_uniqueness)) : offset_v2_k_type(&(key->u.k_offset_v2)); } static inline loff_t le_ih_k_type(const struct item_head *ih) { return le_key_k_type(ih_version(ih), &(ih->ih_key)); } */ #define is_direntry_le_key(version,key) (le_key_k_type (version, key) == TYPE_DIRENTRY) #define is_direct_le_key(version,key) (le_key_k_type (version, key) == TYPE_DIRECT) #define is_indirect_le_key(version,key) (le_key_k_type (version, key) == TYPE_INDIRECT) #define is_statdata_le_key(version,key) (le_key_k_type (version, key) == TYPE_STAT_DATA) // // item header has version. // #define is_direntry_le_ih(ih) is_direntry_le_key (ih_version (ih), &((ih)->ih_key)) #define is_direct_le_ih(ih) is_direct_le_key (ih_version (ih), &((ih)->ih_key)) #define is_indirect_le_ih(ih) is_indirect_le_key (ih_version(ih), &((ih)->ih_key)) #define is_statdata_le_ih(ih) is_statdata_le_key (ih_version (ih), &((ih)->ih_key)) // // key is pointer to cpu key, result is cpu // /* static inline loff_t cpu_key_k_offset(const struct cpu_key *key) { return key->on_disk_key.k_offset; } static inline loff_t cpu_key_k_type(const struct cpu_key *key) { return key->on_disk_key.k_type; } static inline void cpu_key_k_offset_dec(struct cpu_key *key) { key->on_disk_key.k_offset--; } */ #define is_direntry_cpu_key(key) (cpu_key_k_type (key) == TYPE_DIRENTRY) #define is_direct_cpu_key(key) (cpu_key_k_type (key) == TYPE_DIRECT) #define is_indirect_cpu_key(key) (cpu_key_k_type (key) == TYPE_INDIRECT) #define is_statdata_cpu_key(key) (cpu_key_k_type (key) == TYPE_STAT_DATA) /* are these used ? */ #define is_direntry_cpu_ih(ih) (is_direntry_cpu_key (&((ih)->ih_key))) #define is_direct_cpu_ih(ih) (is_direct_cpu_key (&((ih)->ih_key))) #define is_indirect_cpu_ih(ih) (is_indirect_cpu_key (&((ih)->ih_key))) #define is_statdata_cpu_ih(ih) (is_statdata_cpu_key (&((ih)->ih_key))) #define I_K_KEY_IN_ITEM(p_s_ih, p_s_key, n_blocksize) \ ( ! COMP_SHORT_KEYS(p_s_ih, p_s_key) && \ I_OFF_BYTE_IN_ITEM(p_s_ih, k_offset (p_s_key), n_blocksize) ) /* maximal length of item */ #define MAX_ITEM_LEN(block_size) (block_size - BLKH_SIZE - IH_SIZE) #define MIN_ITEM_LEN 1 /* object identifier for root dir */ #define REISERFS_ROOT_OBJECTID 2 #define REISERFS_ROOT_PARENT_OBJECTID 1 /* * Picture represents a leaf of the S+tree * ______________________________________________________ * | | Array of | | | * |Block | Object-Item | F r e e | Objects- | * | head | Headers | S p a c e | Items | * |______|_______________|___________________|___________| */ /* Header of a disk block. More precisely, header of a formatted leaf or internal node, and not the header of an unformatted node. */ struct block_head { __le16 blk_level; /* Level of a block in the tree. */ __le16 blk_nr_item; /* Number of keys/items in a block. */ __le16 blk_free_space; /* Block free space in bytes. */ __le16 blk_reserved; /* dump this in v4/planA */ struct reiserfs_key blk_right_delim_key; /* kept only for compatibility */ }; #define BLKH_SIZE (sizeof(struct block_head)) #define blkh_level(p_blkh) (le16_to_cpu((p_blkh)->blk_level)) #define blkh_nr_item(p_blkh) (le16_to_cpu((p_blkh)->blk_nr_item)) #define blkh_free_space(p_blkh) (le16_to_cpu((p_blkh)->blk_free_space)) #define blkh_reserved(p_blkh) (le16_to_cpu((p_blkh)->blk_reserved)) #define blkh_right_delim_key(p_blkh) ((p_blkh)->blk_right_delim_key) /* * values for blk_level field of the struct block_head */ #define FREE_LEVEL 0 /* when node gets removed from the tree its blk_level is set to FREE_LEVEL. It is then used to see whether the node is still in the tree */ #define DISK_LEAF_NODE_LEVEL 1 /* Leaf node level. */ /* Given the buffer head of a formatted node, resolve to the block head of that node. */ #define B_BLK_HEAD(p_s_bh) ((struct block_head *)((p_s_bh)->b_data)) /* Number of items that are in buffer. */ #define B_NR_ITEMS(p_s_bh) (blkh_nr_item(B_BLK_HEAD(p_s_bh))) #define B_LEVEL(p_s_bh) (blkh_level(B_BLK_HEAD(p_s_bh))) #define B_FREE_SPACE(p_s_bh) (blkh_free_space(B_BLK_HEAD(p_s_bh))) /* Get right delimiting key. -- little endian */ #define B_PRIGHT_DELIM_KEY(p_s_bh) (&(blk_right_delim_key(B_BLK_HEAD(p_s_bh)) /* Does the buffer contain a disk leaf. */ #define B_IS_ITEMS_LEVEL(p_s_bh) (B_LEVEL(p_s_bh) == DISK_LEAF_NODE_LEVEL) /* Does the buffer contain a disk internal node */ #define B_IS_KEYS_LEVEL(p_s_bh) (B_LEVEL(p_s_bh) > DISK_LEAF_NODE_LEVEL \ && B_LEVEL(p_s_bh) <= MAX_HEIGHT) /***************************************************************************/ /* STAT DATA */ /***************************************************************************/ // // old stat data is 32 bytes long. We are going to distinguish new one by // different size // struct stat_data_v1 { __le16 sd_mode; /* file type, permissions */ __le16 sd_nlink; /* number of hard links */ __le16 sd_uid; /* owner */ __le16 sd_gid; /* group */ __le32 sd_size; /* file size */ __le32 sd_atime; /* time of last access */ __le32 sd_mtime; /* time file was last modified */ __le32 sd_ctime; /* time inode (stat data) was last changed (except changes to sd_atime and sd_mtime) */ union { __le32 sd_rdev; __le32 sd_blocks; /* number of blocks file uses */ } ATTR_PACKED u; __le32 sd_first_direct_byte; /* first byte of file which is stored in a direct item: except that if it equals 1 it is a symlink and if it equals ~(__u32)0 there is no direct item. The existence of this field really grates on me. Let's replace it with a macro based on sd_size and our tail suppression policy. Someday. -Hans */ } ATTR_PACKED; #define SD_V1_SIZE (sizeof(struct stat_data_v1)) #define stat_data_v1(ih) (ih_version (ih) == KEY_FORMAT_3_5) #define sd_v1_mode(sdp) (le16_to_cpu((sdp)->sd_mode)) #define set_sd_v1_mode(sdp,v) ((sdp)->sd_mode = cpu_to_le16(v)) #define sd_v1_nlink(sdp) (le16_to_cpu((sdp)->sd_nlink)) #define set_sd_v1_nlink(sdp,v) ((sdp)->sd_nlink = cpu_to_le16(v)) #define sd_v1_uid(sdp) (le16_to_cpu((sdp)->sd_uid)) #define set_sd_v1_uid(sdp,v) ((sdp)->sd_uid = cpu_to_le16(v)) #define sd_v1_gid(sdp) (le16_to_cpu((sdp)->sd_gid)) #define set_sd_v1_gid(sdp,v) ((sdp)->sd_gid = cpu_to_le16(v)) #define sd_v1_size(sdp) (le32_to_cpu((sdp)->sd_size)) #define set_sd_v1_size(sdp,v) ((sdp)->sd_size = cpu_to_le32(v)) #define sd_v1_atime(sdp) (le32_to_cpu((sdp)->sd_atime)) #define set_sd_v1_atime(sdp,v) ((sdp)->sd_atime = cpu_to_le32(v)) #define sd_v1_mtime(sdp) (le32_to_cpu((sdp)->sd_mtime)) #define set_sd_v1_mtime(sdp,v) ((sdp)->sd_mtime = cpu_to_le32(v)) #define sd_v1_ctime(sdp) (le32_to_cpu((sdp)->sd_ctime)) #define set_sd_v1_ctime(sdp,v) ((sdp)->sd_ctime = cpu_to_le32(v)) #define sd_v1_rdev(sdp) (le32_to_cpu((sdp)->u.sd_rdev)) #define set_sd_v1_rdev(sdp,v) ((sdp)->u.sd_rdev = cpu_to_le32(v)) #define sd_v1_blocks(sdp) (le32_to_cpu((sdp)->u.sd_blocks)) #define set_sd_v1_blocks(sdp,v) ((sdp)->u.sd_blocks = cpu_to_le32(v)) #define sd_v1_first_direct_byte(sdp) \ (le32_to_cpu((sdp)->sd_first_direct_byte)) #define set_sd_v1_first_direct_byte(sdp,v) \ ((sdp)->sd_first_direct_byte = cpu_to_le32(v)) /* #include <linux/ext2_fs.h> */ /* inode flags stored in sd_attrs (nee sd_reserved) */ /* we want common flags to have the same values as in ext2, so chattr(1) will work without problems */ #define REISERFS_IMMUTABLE_FL EXT2_IMMUTABLE_FL #define REISERFS_APPEND_FL EXT2_APPEND_FL #define REISERFS_SYNC_FL EXT2_SYNC_FL #define REISERFS_NOATIME_FL EXT2_NOATIME_FL #define REISERFS_NODUMP_FL EXT2_NODUMP_FL #define REISERFS_SECRM_FL EXT2_SECRM_FL #define REISERFS_UNRM_FL EXT2_UNRM_FL #define REISERFS_COMPR_FL EXT2_COMPR_FL #define REISERFS_NOTAIL_FL EXT2_NOTAIL_FL /* persistent flags that file inherits from the parent directory */ #define REISERFS_INHERIT_MASK ( REISERFS_IMMUTABLE_FL | \ REISERFS_SYNC_FL | \ REISERFS_NOATIME_FL | \ REISERFS_NODUMP_FL | \ REISERFS_SECRM_FL | \ REISERFS_COMPR_FL | \ REISERFS_NOTAIL_FL ) /* Stat Data on disk (reiserfs version of UFS disk inode minus the address blocks) */ struct stat_data { __le16 sd_mode; /* file type, permissions */ __le16 sd_attrs; /* persistent inode flags */ __le32 sd_nlink; /* number of hard links */ __le64 sd_size; /* file size */ __le32 sd_uid; /* owner */ __le32 sd_gid; /* group */ __le32 sd_atime; /* time of last access */ __le32 sd_mtime; /* time file was last modified */ __le32 sd_ctime; /* time inode (stat data) was last changed (except changes to sd_atime and sd_mtime) */ __le32 sd_blocks; union { __le32 sd_rdev; __le32 sd_generation; //__le32 sd_first_direct_byte; /* first byte of file which is stored in a direct item: except that if it equals 1 it is a symlink and if it equals ~(__u32)0 there is no direct item. The existence of this field really grates on me. Let's replace it with a macro based on sd_size and our tail suppression policy? */ } ATTR_PACKED u; } ATTR_PACKED; // // this is 44 bytes long // #define SD_SIZE (sizeof(struct stat_data)) #define SD_V2_SIZE SD_SIZE #define stat_data_v2(ih) (ih_version (ih) == KEY_FORMAT_3_6) #define sd_v2_mode(sdp) (le16_to_cpu((sdp)->sd_mode)) #define set_sd_v2_mode(sdp,v) ((sdp)->sd_mode = cpu_to_le16(v)) /* sd_reserved */ /* set_sd_reserved */ #define sd_v2_nlink(sdp) (le32_to_cpu((sdp)->sd_nlink)) #define set_sd_v2_nlink(sdp,v) ((sdp)->sd_nlink = cpu_to_le32(v)) #define sd_v2_size(sdp) (le64_to_cpu((sdp)->sd_size)) #define set_sd_v2_size(sdp,v) ((sdp)->sd_size = cpu_to_le64(v)) #define sd_v2_uid(sdp) (le32_to_cpu((sdp)->sd_uid)) #define set_sd_v2_uid(sdp,v) ((sdp)->sd_uid = cpu_to_le32(v)) #define sd_v2_gid(sdp) (le32_to_cpu((sdp)->sd_gid)) #define set_sd_v2_gid(sdp,v) ((sdp)->sd_gid = cpu_to_le32(v)) #define sd_v2_atime(sdp) (le32_to_cpu((sdp)->sd_atime)) #define set_sd_v2_atime(sdp,v) ((sdp)->sd_atime = cpu_to_le32(v)) #define sd_v2_mtime(sdp) (le32_to_cpu((sdp)->sd_mtime)) #define set_sd_v2_mtime(sdp,v) ((sdp)->sd_mtime = cpu_to_le32(v)) #define sd_v2_ctime(sdp) (le32_to_cpu((sdp)->sd_ctime)) #define set_sd_v2_ctime(sdp,v) ((sdp)->sd_ctime = cpu_to_le32(v)) #define sd_v2_blocks(sdp) (le32_to_cpu((sdp)->sd_blocks)) #define set_sd_v2_blocks(sdp,v) ((sdp)->sd_blocks = cpu_to_le32(v)) #define sd_v2_rdev(sdp) (le32_to_cpu((sdp)->u.sd_rdev)) #define set_sd_v2_rdev(sdp,v) ((sdp)->u.sd_rdev = cpu_to_le32(v)) #define sd_v2_generation(sdp) (le32_to_cpu((sdp)->u.sd_generation)) #define set_sd_v2_generation(sdp,v) ((sdp)->u.sd_generation = cpu_to_le32(v)) #define sd_v2_attrs(sdp) (le16_to_cpu((sdp)->sd_attrs)) #define set_sd_v2_attrs(sdp,v) ((sdp)->sd_attrs = cpu_to_le16(v)) /***************************************************************************/ /* DIRECTORY STRUCTURE */ /***************************************************************************/ /* Picture represents the structure of directory items ________________________________________________ | Array of | | | | | | | directory |N-1| N-2 | .... | 1st |0th| | entry headers | | | | | | |_______________|___|_____|________|_______|___| <---- directory entries ------> First directory item has k_offset component 1. We store "." and ".." in one item, always, we never split "." and ".." into differing items. This makes, among other things, the code for removing directories simpler. */ #define SD_OFFSET 0 #define SD_UNIQUENESS 0 #define DOT_OFFSET 1 #define DOT_DOT_OFFSET 2 #define DIRENTRY_UNIQUENESS 500 /* */ #define FIRST_ITEM_OFFSET 1 /* Q: How to get key of object pointed to by entry from entry? A: Each directory entry has its header. This header has deh_dir_id and deh_objectid fields, those are key of object, entry points to */ /* NOT IMPLEMENTED: Directory will someday contain stat data of object */ struct reiserfs_de_head { __le32 deh_offset; /* third component of the directory entry key */ __le32 deh_dir_id; /* objectid of the parent directory of the object, that is referenced by directory entry */ __le32 deh_objectid; /* objectid of the object, that is referenced by directory entry */ __le16 deh_location; /* offset of name in the whole item */ __le16 deh_state; /* whether 1) entry contains stat data (for future), and 2) whether entry is hidden (unlinked) */ } ATTR_PACKED; #define DEH_SIZE sizeof(struct reiserfs_de_head) #define deh_offset(p_deh) (le32_to_cpu((p_deh)->deh_offset)) #define deh_dir_id(p_deh) (le32_to_cpu((p_deh)->deh_dir_id)) #define deh_objectid(p_deh) (le32_to_cpu((p_deh)->deh_objectid)) #define deh_location(p_deh) (le16_to_cpu((p_deh)->deh_location)) #define deh_state(p_deh) (le16_to_cpu((p_deh)->deh_state)) #define put_deh_offset(p_deh,v) ((p_deh)->deh_offset = cpu_to_le32((v))) #define put_deh_dir_id(p_deh,v) ((p_deh)->deh_dir_id = cpu_to_le32((v))) #define put_deh_objectid(p_deh,v) ((p_deh)->deh_objectid = cpu_to_le32((v))) #define put_deh_location(p_deh,v) ((p_deh)->deh_location = cpu_to_le16((v))) #define put_deh_state(p_deh,v) ((p_deh)->deh_state = cpu_to_le16((v))) /* empty directory contains two entries "." and ".." and their headers */ #define EMPTY_DIR_SIZE \ (DEH_SIZE * 2 + ROUND_UP (strlen (".")) + ROUND_UP (strlen (".."))) /* old format directories have this size when empty */ #define EMPTY_DIR_SIZE_V1 (DEH_SIZE * 2 + 3) #define DEH_Statdata 0 /* not used now */ #define DEH_Visible 2 /* 64 bit systems (and the S/390) need to be aligned explicitly -jdm */ #if BITS_PER_LONG == 64 || defined(__s390__) || defined(__hppa__) # define ADDR_UNALIGNED_BITS (3) #endif /* These are only used to manipulate deh_state. * Because of this, we'll use the ext2_ bit routines, * since they are little endian */ #ifdef ADDR_UNALIGNED_BITS # define aligned_address(addr) ((void *)((long)(addr) & ~((1UL << ADDR_UNALIGNED_BITS) - 1))) # define unaligned_offset(addr) (((int)((long)(addr) & ((1 << ADDR_UNALIGNED_BITS) - 1))) << 3) # define set_bit_unaligned(nr, addr) ext2_set_bit((nr) + unaligned_offset(addr), aligned_address(addr)) # define clear_bit_unaligned(nr, addr) ext2_clear_bit((nr) + unaligned_offset(addr), aligned_address(addr)) # define test_bit_unaligned(nr, addr) ext2_test_bit((nr) + unaligned_offset(addr), aligned_address(addr)) #else # define set_bit_unaligned(nr, addr) ext2_set_bit(nr, addr) # define clear_bit_unaligned(nr, addr) ext2_clear_bit(nr, addr) # define test_bit_unaligned(nr, addr) ext2_test_bit(nr, addr) #endif #define mark_de_with_sd(deh) set_bit_unaligned (DEH_Statdata, &((deh)->deh_state)) #define mark_de_without_sd(deh) clear_bit_unaligned (DEH_Statdata, &((deh)->deh_state)) #define mark_de_visible(deh) set_bit_unaligned (DEH_Visible, &((deh)->deh_state)) #define mark_de_hidden(deh) clear_bit_unaligned (DEH_Visible, &((deh)->deh_state)) #define de_with_sd(deh) test_bit_unaligned (DEH_Statdata, &((deh)->deh_state)) #define de_visible(deh) test_bit_unaligned (DEH_Visible, &((deh)->deh_state)) #define de_hidden(deh) !test_bit_unaligned (DEH_Visible, &((deh)->deh_state)) /* extern void make_empty_dir_item_v1(char *body, __le32 dirid, __le32 objid, __le32 par_dirid, __le32 par_objid); extern void make_empty_dir_item(char *body, __le32 dirid, __le32 objid, __le32 par_dirid, __le32 par_objid); */ /* array of the entry headers */ /* get item body */ #define B_I_PITEM(bh,ih) ( (bh)->b_data + ih_location(ih) ) #define B_I_DEH(bh,ih) ((struct reiserfs_de_head *)(B_I_PITEM(bh,ih))) /* length of the directory entry in directory item. This define calculates length of i-th directory entry using directory entry locations from dir entry head. When it calculates length of 0-th directory entry, it uses length of whole item in place of entry location of the non-existent following entry in the calculation. See picture above.*/ /* #define I_DEH_N_ENTRY_LENGTH(ih,deh,i) \ ((i) ? (deh_location((deh)-1) - deh_location((deh))) : (ih_item_len((ih)) - deh_location((deh)))) */ /* static inline int entry_length(const struct buffer_head *bh, const struct item_head *ih, int pos_in_item) { struct reiserfs_de_head *deh; deh = B_I_DEH(bh, ih) + pos_in_item; if (pos_in_item) return deh_location(deh - 1) - deh_location(deh); return ih_item_len(ih) - deh_location(deh); } */ /* number of entries in the directory item, depends on ENTRY_COUNT being at the start of directory dynamic data. */ #define I_ENTRY_COUNT(ih) (ih_entry_count((ih))) /* name by bh, ih and entry_num */ #define B_I_E_NAME(bh,ih,entry_num) ((char *)(bh->b_data + ih_location(ih) + deh_location(B_I_DEH(bh,ih)+(entry_num)))) // two entries per block (at least) #define REISERFS_MAX_NAME(block_size) 255 /* this structure is used for operations on directory entries. It is not a disk structure. */ /* When reiserfs_find_entry or search_by_entry_key find directory entry, they return filled reiserfs_dir_entry structure */ struct reiserfs_dir_entry { struct buffer_head *de_bh; int de_item_num; struct item_head *de_ih; int de_entry_num; struct reiserfs_de_head *de_deh; int de_entrylen; int de_namelen; char *de_name; unsigned long *de_gen_number_bit_string; __u32 de_dir_id; __u32 de_objectid; struct cpu_key de_entry_key; }; /* these defines are useful when a particular member of a reiserfs_dir_entry is needed */ /* pointer to file name, stored in entry */ #define B_I_DEH_ENTRY_FILE_NAME(bh,ih,deh) (B_I_PITEM (bh, ih) + deh_location(deh)) /* length of name */ #define I_DEH_N_ENTRY_FILE_NAME_LENGTH(ih,deh,entry_num) \ (I_DEH_N_ENTRY_LENGTH (ih, deh, entry_num) - (de_with_sd (deh) ? SD_SIZE : 0)) /* hash value occupies bits from 7 up to 30 */ #define GET_HASH_VALUE(offset) ((offset) & 0x7fffff80LL) /* generation number occupies 7 bits starting from 0 up to 6 */ #define GET_GENERATION_NUMBER(offset) ((offset) & 0x7fLL) #define MAX_GENERATION_NUMBER 127 #define SET_GENERATION_NUMBER(offset,gen_number) (GET_HASH_VALUE(offset)|(gen_number)) /* * Picture represents an internal node of the reiserfs tree * ______________________________________________________ * | | Array of | Array of | Free | * |block | keys | pointers | space | * | head | N | N+1 | | * |______|_______________|___________________|___________| */ /***************************************************************************/ /* DISK CHILD */ /***************************************************************************/ /* Disk child pointer: The pointer from an internal node of the tree to a node that is on disk. */ struct disk_child { __le32 dc_block_number; /* Disk child's block number. */ __le16 dc_size; /* Disk child's used space. */ __le16 dc_reserved; }; #define DC_SIZE (sizeof(struct disk_child)) #define dc_block_number(dc_p) (le32_to_cpu((dc_p)->dc_block_number)) #define dc_size(dc_p) (le16_to_cpu((dc_p)->dc_size)) /* Get disk child by buffer header and position in the tree node. */ #define B_N_CHILD(p_s_bh,n_pos) ((struct disk_child *)\ ((p_s_bh)->b_data+BLKH_SIZE+B_NR_ITEMS(p_s_bh)*KEY_SIZE+DC_SIZE*(n_pos))) /* Get disk child number by buffer header and position in the tree node. */ #define B_N_CHILD_NUM(p_s_bh,n_pos) (dc_block_number(B_N_CHILD(p_s_bh,n_pos))) #define PUT_B_N_CHILD_NUM(p_s_bh,n_pos, val) (put_dc_block_number(B_N_CHILD(p_s_bh,n_pos), val )) /* maximal value of field child_size in structure disk_child */ /* child size is the combined size of all items and their headers */ #define MAX_CHILD_SIZE(bh) ((int)( (bh)->b_size - BLKH_SIZE )) /* amount of used space in buffer (not including block head) */ #define B_CHILD_SIZE(cur) (MAX_CHILD_SIZE(cur)-(B_FREE_SPACE(cur))) /* max and min number of keys in internal node */ #define MAX_NR_KEY(bh) ( (MAX_CHILD_SIZE(bh)-DC_SIZE)/(KEY_SIZE+DC_SIZE) ) #define MIN_NR_KEY(bh) (MAX_NR_KEY(bh)/2) /***************************************************************************/ /* PATH STRUCTURES AND DEFINES */ /***************************************************************************/ /* Search_by_key fills up the path from the root to the leaf as it descends the tree looking for the key. It uses reiserfs_bread to try to find buffers in the cache given their block number. If it does not find them in the cache it reads them from disk. For each node search_by_key finds using reiserfs_bread it then uses bin_search to look through that node. bin_search will find the position of the block_number of the next node if it is looking through an internal node. If it is looking through a leaf node bin_search will find the position of the item which has key either equal to given key, or which is the maximal key less than the given key. */ struct path_element { struct buffer_head *pe_buffer; /* Pointer to the buffer at the path in the tree. */ int pe_position; /* Position in the tree node which is placed in the */ /* buffer above. */ }; #define MAX_HEIGHT 5 /* maximal height of a tree. don't change this without changing JOURNAL_PER_BALANCE_CNT */ #define EXTENDED_MAX_HEIGHT 7 /* Must be equals MAX_HEIGHT + FIRST_PATH_ELEMENT_OFFSET */ #define FIRST_PATH_ELEMENT_OFFSET 2 /* Must be equal to at least 2. */ #define ILLEGAL_PATH_ELEMENT_OFFSET 1 /* Must be equal to FIRST_PATH_ELEMENT_OFFSET - 1 */ #define MAX_FEB_SIZE 6 /* this MUST be MAX_HEIGHT + 1. See about FEB below */ /* We need to keep track of who the ancestors of nodes are. When we perform a search we record which nodes were visited while descending the tree looking for the node we searched for. This list of nodes is called the path. This information is used while performing balancing. Note that this path information may become invalid, and this means we must check it when using it to see if it is still valid. You'll need to read search_by_key and the comments in it, especially about decrement_counters_in_path(), to understand this structure. Paths make the code so much harder to work with and debug.... An enormous number of bugs are due to them, and trying to write or modify code that uses them just makes my head hurt. They are based on an excessive effort to avoid disturbing the precious VFS code.:-( The gods only know how we are going to SMP the code that uses them. znodes are the way! */ #define PATH_READA 0x1 /* do read ahead */ #define PATH_READA_BACK 0x2 /* read backwards */ struct path { int path_length; /* Length of the array above. */ int reada; struct path_element path_elements[EXTENDED_MAX_HEIGHT]; /* Array of the path elements. */ int pos_in_item; }; #define pos_in_item(path) ((path)->pos_in_item) #define INITIALIZE_PATH(var) \ struct path var = {.path_length = ILLEGAL_PATH_ELEMENT_OFFSET, .reada = 0,} /* Get path element by path and path position. */ #define PATH_OFFSET_PELEMENT(p_s_path,n_offset) ((p_s_path)->path_elements +(n_offset)) /* Get buffer header at the path by path and path position. */ #define PATH_OFFSET_PBUFFER(p_s_path,n_offset) (PATH_OFFSET_PELEMENT(p_s_path,n_offset)->pe_buffer) /* Get position in the element at the path by path and path position. */ #define PATH_OFFSET_POSITION(p_s_path,n_offset) (PATH_OFFSET_PELEMENT(p_s_path,n_offset)->pe_position) #define PATH_PLAST_BUFFER(p_s_path) (PATH_OFFSET_PBUFFER((p_s_path), (p_s_path)->path_length)) /* you know, to the person who didn't write this the macro name does not at first suggest what it does. Maybe POSITION_FROM_PATH_END? Or maybe we should just focus on dumping paths... -Hans */ #define PATH_LAST_POSITION(p_s_path) (PATH_OFFSET_POSITION((p_s_path), (p_s_path)->path_length)) #define PATH_PITEM_HEAD(p_s_path) B_N_PITEM_HEAD(PATH_PLAST_BUFFER(p_s_path),PATH_LAST_POSITION(p_s_path)) /* in do_balance leaf has h == 0 in contrast with path structure, where root has level == 0. That is why we need these defines */ #define PATH_H_PBUFFER(p_s_path, h) PATH_OFFSET_PBUFFER (p_s_path, p_s_path->path_length - (h)) /* tb->S[h] */ #define PATH_H_PPARENT(path, h) PATH_H_PBUFFER (path, (h) + 1) /* tb->F[h] or tb->S[0]->b_parent */ #define PATH_H_POSITION(path, h) PATH_OFFSET_POSITION (path, path->path_length - (h)) #define PATH_H_B_ITEM_ORDER(path, h) PATH_H_POSITION(path, h + 1) /* tb->S[h]->b_item_order */ #define PATH_H_PATH_OFFSET(p_s_path, n_h) ((p_s_path)->path_length - (n_h)) #define get_last_bh(path) PATH_PLAST_BUFFER(path) #define get_ih(path) PATH_PITEM_HEAD(path) #define get_item_pos(path) PATH_LAST_POSITION(path) #define get_item(path) ((void *)B_N_PITEM(PATH_PLAST_BUFFER(path), PATH_LAST_POSITION (path))) #define item_moved(ih,path) comp_items(ih, path) #define path_changed(ih,path) comp_items (ih, path) /***************************************************************************/ /* MISC */ /***************************************************************************/ /* Size of pointer to the unformatted node. */ #define UNFM_P_SIZE (sizeof(unp_t)) #define UNFM_P_SHIFT 2 // in in-core inode key is stored on le form #define INODE_PKEY(inode) ((struct reiserfs_key *)(REISERFS_I(inode)->i_key)) #define MAX_UL_INT 0xffffffff #define MAX_INT 0x7ffffff #define MAX_US_INT 0xffff // reiserfs version 2 has max offset 60 bits. Version 1 - 32 bit offset #define U32_MAX (~(__u32)0) /* static inline loff_t max_reiserfs_offset(struct inode *inode) { if (get_inode_item_key_version(inode) == KEY_FORMAT_3_5) return (loff_t) U32_MAX; return (loff_t) ((~(__u64) 0) >> 4); } */ /*#define MAX_KEY_UNIQUENESS MAX_UL_INT*/ #define MAX_KEY_OBJECTID MAX_UL_INT #define MAX_B_NUM MAX_UL_INT #define MAX_FC_NUM MAX_US_INT /* the purpose is to detect overflow of an unsigned short */ #define REISERFS_LINK_MAX (MAX_US_INT - 1000) /* The following defines are used in reiserfs_insert_item and reiserfs_append_item */ #define REISERFS_KERNEL_MEM 0 /* reiserfs kernel memory mode */ #define REISERFS_USER_MEM 1 /* reiserfs user memory mode */ #define fs_generation(s) (REISERFS_SB(s)->s_generation_counter) #define get_generation(s) atomic_read (&fs_generation(s)) #define FILESYSTEM_CHANGED_TB(tb) (get_generation((tb)->tb_sb) != (tb)->fs_gen) #define __fs_changed(gen,s) (gen != get_generation (s)) #define fs_changed(gen,s) ({cond_resched(); __fs_changed(gen, s);}) /***************************************************************************/ /* FIXATE NODES */ /***************************************************************************/ #define VI_TYPE_LEFT_MERGEABLE 1 #define VI_TYPE_RIGHT_MERGEABLE 2 /* To make any changes in the tree we always first find node, that contains item to be changed/deleted or place to insert a new item. We call this node S. To do balancing we need to decide what we will shift to left/right neighbor, or to a new node, where new item will be etc. To make this analysis simpler we build virtual node. Virtual node is an array of items, that will replace items of node S. (For instance if we are going to delete an item, virtual node does not contain it). Virtual node keeps information about item sizes and types, mergeability of first and last items, sizes of all entries in directory item. We use this array of items when calculating what we can shift to neighbors and how many nodes we have to have if we do not any shiftings, if we shift to left/right neighbor or to both. */ struct virtual_item { int vi_index; // index in the array of item operations unsigned short vi_type; // left/right mergeability unsigned short vi_item_len; /* length of item that it will have after balancing */ struct item_head *vi_ih; const char *vi_item; // body of item (old or new) const void *vi_new_data; // 0 always but paste mode void *vi_uarea; // item specific area }; struct virtual_node { char *vn_free_ptr; /* this is a pointer to the free space in the buffer */ unsigned short vn_nr_item; /* number of items in virtual node */ short vn_size; /* size of node , that node would have if it has unlimited size and no balancing is performed */ short vn_mode; /* mode of balancing (paste, insert, delete, cut) */ short vn_affected_item_num; short vn_pos_in_item; struct item_head *vn_ins_ih; /* item header of inserted item, 0 for other modes */ const void *vn_data; struct virtual_item *vn_vi; /* array of items (including a new one, excluding item to be deleted) */ }; /* used by directory items when creating virtual nodes */ struct direntry_uarea { int flags; __u16 entry_count; __u16 entry_sizes[1]; } ATTR_PACKED; /***************************************************************************/ /* TREE BALANCE */ /***************************************************************************/ /* This temporary structure is used in tree balance algorithms, and constructed as we go to the extent that its various parts are needed. It contains arrays of nodes that can potentially be involved in the balancing of node S, and parameters that define how each of the nodes must be balanced. Note that in these algorithms for balancing the worst case is to need to balance the current node S and the left and right neighbors and all of their parents plus create a new node. We implement S1 balancing for the leaf nodes and S0 balancing for the internal nodes (S1 and S0 are defined in our papers.)*/ #define MAX_FREE_BLOCK 7 /* size of the array of buffers to free at end of do_balance */ /* maximum number of FEB blocknrs on a single level */ #define MAX_AMOUNT_NEEDED 2 /* someday somebody will prefix every field in this struct with tb_ */ struct tree_balance { int tb_mode; int need_balance_dirty; struct super_block *tb_sb; struct reiserfs_transaction_handle *transaction_handle; struct path *tb_path; struct buffer_head *L[MAX_HEIGHT]; /* array of left neighbors of nodes in the path */ struct buffer_head *R[MAX_HEIGHT]; /* array of right neighbors of nodes in the path */ struct buffer_head *FL[MAX_HEIGHT]; /* array of fathers of the left neighbors */ struct buffer_head *FR[MAX_HEIGHT]; /* array of fathers of the right neighbors */ struct buffer_head *CFL[MAX_HEIGHT]; /* array of common parents of center node and its left neighbor */ struct buffer_head *CFR[MAX_HEIGHT]; /* array of common parents of center node and its right neighbor */ struct buffer_head *FEB[MAX_FEB_SIZE]; /* array of empty buffers. Number of buffers in array equals cur_blknum. */ struct buffer_head *used[MAX_FEB_SIZE]; struct buffer_head *thrown[MAX_FEB_SIZE]; int lnum[MAX_HEIGHT]; /* array of number of items which must be shifted to the left in order to balance the current node; for leaves includes item that will be partially shifted; for internal nodes, it is the number of child pointers rather than items. It includes the new item being created. The code sometimes subtracts one to get the number of wholly shifted items for other purposes. */ int rnum[MAX_HEIGHT]; /* substitute right for left in comment above */ int lkey[MAX_HEIGHT]; /* array indexed by height h mapping the key delimiting L[h] and S[h] to its item number within the node CFL[h] */ int rkey[MAX_HEIGHT]; /* substitute r for l in comment above */ int insert_size[MAX_HEIGHT]; /* the number of bytes by we are trying to add or remove from S[h]. A negative value means removing. */ int blknum[MAX_HEIGHT]; /* number of nodes that will replace node S[h] after balancing on the level h of the tree. If 0 then S is being deleted, if 1 then S is remaining and no new nodes are being created, if 2 or 3 then 1 or 2 new nodes is being created */ /* fields that are used only for balancing leaves of the tree */ int cur_blknum; /* number of empty blocks having been already allocated */ int s0num; /* number of items that fall into left most node when S[0] splits */ int s1num; /* number of items that fall into first new node when S[0] splits */ int s2num; /* number of items that fall into second new node when S[0] splits */ int lbytes; /* number of bytes which can flow to the left neighbor from the left */ /* most liquid item that cannot be shifted from S[0] entirely */ /* if -1 then nothing will be partially shifted */ int rbytes; /* number of bytes which will flow to the right neighbor from the right */ /* most liquid item that cannot be shifted from S[0] entirely */ /* if -1 then nothing will be partially shifted */ int s1bytes; /* number of bytes which flow to the first new node when S[0] splits */ /* note: if S[0] splits into 3 nodes, then items do not need to be cut */ int s2bytes; struct buffer_head *buf_to_free[MAX_FREE_BLOCK]; /* buffers which are to be freed after do_balance finishes by unfix_nodes */ char *vn_buf; /* kmalloced memory. Used to create virtual node and keep map of dirtied bitmap blocks */ int vn_buf_size; /* size of the vn_buf */ struct virtual_node *tb_vn; /* VN starts after bitmap of bitmap blocks */ int fs_gen; /* saved value of `reiserfs_generation' counter see FILESYSTEM_CHANGED() macro in reiserfs_fs.h */ #ifdef DISPLACE_NEW_PACKING_LOCALITIES struct in_core_key key; /* key pointer, to pass to block allocator or another low-level subsystem */ #endif }; /* These are modes of balancing */ /* When inserting an item. */ #define M_INSERT 'i' /* When inserting into (directories only) or appending onto an already existant item. */ #define M_PASTE 'p' /* When deleting an item. */ #define M_DELETE 'd' /* When truncating an item or removing an entry from a (directory) item. */ #define M_CUT 'c' /* used when balancing on leaf level skipped (in reiserfsck) */ #define M_INTERNAL 'n' /* When further balancing is not needed, then do_balance does not need to be called. */ #define M_SKIP_BALANCING 's' #define M_CONVERT 'v' /* modes of leaf_move_items */ #define LEAF_FROM_S_TO_L 0 #define LEAF_FROM_S_TO_R 1 #define LEAF_FROM_R_TO_L 2 #define LEAF_FROM_L_TO_R 3 #define LEAF_FROM_S_TO_SNEW 4 #define FIRST_TO_LAST 0 #define LAST_TO_FIRST 1 /* used in do_balance for passing parent of node information that has been gotten from tb struct */ struct buffer_info { struct tree_balance *tb; struct buffer_head *bi_bh; struct buffer_head *bi_parent; int bi_position; }; /* there are 4 types of items: stat data, directory item, indirect, direct. +-------------------+------------+--------------+------------+ | | k_offset | k_uniqueness | mergeable? | +-------------------+------------+--------------+------------+ | stat data | 0 | 0 | no | +-------------------+------------+--------------+------------+ | 1st directory item| DOT_OFFSET |DIRENTRY_UNIQUENESS| no | | non 1st directory | hash value | | yes | | item | | | | +-------------------+------------+--------------+------------+ | indirect item | offset + 1 |TYPE_INDIRECT | if this is not the first indirect item of the object +-------------------+------------+--------------+------------+ | direct item | offset + 1 |TYPE_DIRECT | if not this is not the first direct item of the object +-------------------+------------+--------------+------------+ */ struct item_operations { int (*bytes_number) (struct item_head * ih, int block_size); void (*decrement_key) (struct cpu_key *); int (*is_left_mergeable) (struct reiserfs_key * ih, unsigned long bsize); void (*print_item) (struct item_head *, char *item); void (*check_item) (struct item_head *, char *item); int (*create_vi) (struct virtual_node * vn, struct virtual_item * vi, int is_affected, int insert_size); int (*check_left) (struct virtual_item * vi, int free, int start_skip, int end_skip); int (*check_right) (struct virtual_item * vi, int free); int (*part_size) (struct virtual_item * vi, int from, int to); int (*unit_num) (struct virtual_item * vi); void (*print_vi) (struct virtual_item * vi); }; extern struct item_operations *item_ops[TYPE_ANY + 1]; #define op_bytes_number(ih,bsize) item_ops[le_ih_k_type (ih)]->bytes_number (ih, bsize) #define op_is_left_mergeable(key,bsize) item_ops[le_key_k_type (le_key_version (key), key)]->is_left_mergeable (key, bsize) #define op_print_item(ih,item) item_ops[le_ih_k_type (ih)]->print_item (ih, item) #define op_check_item(ih,item) item_ops[le_ih_k_type (ih)]->check_item (ih, item) #define op_create_vi(vn,vi,is_affected,insert_size) item_ops[le_ih_k_type ((vi)->vi_ih)]->create_vi (vn,vi,is_affected,insert_size) #define op_check_left(vi,free,start_skip,end_skip) item_ops[(vi)->vi_index]->check_left (vi, free, start_skip, end_skip) #define op_check_right(vi,free) item_ops[(vi)->vi_index]->check_right (vi, free) #define op_part_size(vi,from,to) item_ops[(vi)->vi_index]->part_size (vi, from, to) #define op_unit_num(vi) item_ops[(vi)->vi_index]->unit_num (vi) #define op_print_vi(vi) item_ops[(vi)->vi_index]->print_vi (vi) #define COMP_SHORT_KEYS comp_short_keys /* number of blocks pointed to by the indirect item */ #define I_UNFM_NUM(p_s_ih) ( ih_item_len(p_s_ih) / UNFM_P_SIZE ) /* the used space within the unformatted node corresponding to pos within the item pointed to by ih */ #define I_POS_UNFM_SIZE(ih,pos,size) (((pos) == I_UNFM_NUM(ih) - 1 ) ? (size) - ih_free_space(ih) : (size)) /* number of bytes contained by the direct item or the unformatted nodes the indirect item points to */ /* get the item header */ #define B_N_PITEM_HEAD(bh,item_num) ( (struct item_head * )((bh)->b_data + BLKH_SIZE) + (item_num) ) /* get key */ #define B_N_PDELIM_KEY(bh,item_num) ( (struct reiserfs_key * )((bh)->b_data + BLKH_SIZE) + (item_num) ) /* get the key */ #define B_N_PKEY(bh,item_num) ( &(B_N_PITEM_HEAD(bh,item_num)->ih_key) ) /* get item body */ #define B_N_PITEM(bh,item_num) ( (bh)->b_data + ih_location(B_N_PITEM_HEAD((bh),(item_num)))) /* get the stat data by the buffer header and the item order */ #define B_N_STAT_DATA(bh,nr) \ ( (struct stat_data *)((bh)->b_data + ih_location(B_N_PITEM_HEAD((bh),(nr))) ) ) /* following defines use reiserfs buffer header and item header */ /* get stat-data */ #define B_I_STAT_DATA(bh, ih) ( (struct stat_data * )((bh)->b_data + ih_location(ih)) ) // this is 3976 for size==4096 #define MAX_DIRECT_ITEM_LEN(size) ((size) - BLKH_SIZE - 2*IH_SIZE - SD_SIZE - UNFM_P_SIZE) /* indirect items consist of entries which contain blocknrs, pos indicates which entry, and B_I_POS_UNFM_POINTER resolves to the blocknr contained by the entry pos points to */ #define B_I_POS_UNFM_POINTER(bh,ih,pos) le32_to_cpu(*(((unp_t *)B_I_PITEM(bh,ih)) + (pos))) #define PUT_B_I_POS_UNFM_POINTER(bh,ih,pos, val) do {*(((unp_t *)B_I_PITEM(bh,ih)) + (pos)) = cpu_to_le32(val); } while (0) struct reiserfs_iget_args { __u32 objectid; __u32 dirid; }; /***************************************************************************/ /* FUNCTION DECLARATIONS */ /***************************************************************************/ /*#ifdef __KERNEL__*/ #define get_journal_desc_magic(bh) (bh->b_data + bh->b_size - 12) #define journal_trans_half(blocksize) \ ((blocksize - sizeof (struct reiserfs_journal_desc) + sizeof (__u32) - 12) / sizeof (__u32)) /* journal.c see journal.c for all the comments here */ /* first block written in a commit. */ struct reiserfs_journal_desc { __le32 j_trans_id; /* id of commit */ __le32 j_len; /* length of commit. len +1 is the commit block */ __le32 j_mount_id; /* mount id of this trans */ __le32 j_realblock[1]; /* real locations for each block */ }; #define get_desc_trans_id(d) le32_to_cpu((d)->j_trans_id) #define get_desc_trans_len(d) le32_to_cpu((d)->j_len) #define get_desc_mount_id(d) le32_to_cpu((d)->j_mount_id) #define set_desc_trans_id(d,val) do { (d)->j_trans_id = cpu_to_le32 (val); } while (0) #define set_desc_trans_len(d,val) do { (d)->j_len = cpu_to_le32 (val); } while (0) #define set_desc_mount_id(d,val) do { (d)->j_mount_id = cpu_to_le32 (val); } while (0) /* last block written in a commit */ struct reiserfs_journal_commit { __le32 j_trans_id; /* must match j_trans_id from the desc block */ __le32 j_len; /* ditto */ __le32 j_realblock[1]; /* real locations for each block */ }; #define get_commit_trans_id(c) le32_to_cpu((c)->j_trans_id) #define get_commit_trans_len(c) le32_to_cpu((c)->j_len) #define get_commit_mount_id(c) le32_to_cpu((c)->j_mount_id) #define set_commit_trans_id(c,val) do { (c)->j_trans_id = cpu_to_le32 (val); } while (0) #define set_commit_trans_len(c,val) do { (c)->j_len = cpu_to_le32 (val); } while (0) /* this header block gets written whenever a transaction is considered fully flushed, and is more recent than the ** last fully flushed transaction. fully flushed means all the log blocks and all the real blocks are on disk, ** and this transaction does not need to be replayed. */ struct reiserfs_journal_header { __le32 j_last_flush_trans_id; /* id of last fully flushed transaction */ __le32 j_first_unflushed_offset; /* offset in the log of where to start replay after a crash */ __le32 j_mount_id; /* 12 */ struct journal_params jh_journal; }; /* biggest tunable defines are right here */ #define JOURNAL_BLOCK_COUNT 8192 /* number of blocks in the journal */ #define JOURNAL_TRANS_MAX_DEFAULT 1024 /* biggest possible single transaction, don't change for now (8/3/99) */ #define JOURNAL_TRANS_MIN_DEFAULT 256 #define JOURNAL_MAX_BATCH_DEFAULT 900 /* max blocks to batch into one transaction, don't make this any bigger than 900 */ #define JOURNAL_MIN_RATIO 2 #define JOURNAL_MAX_COMMIT_AGE 30 #define JOURNAL_MAX_TRANS_AGE 30 #define JOURNAL_PER_BALANCE_CNT (3 * (MAX_HEIGHT-2) + 9) #ifdef CONFIG_QUOTA /* We need to update data and inode (atime) */ #define REISERFS_QUOTA_TRANS_BLOCKS(s) (REISERFS_SB(s)->s_mount_opt & (1<<REISERFS_QUOTA) ? 2 : 0) /* 1 balancing, 1 bitmap, 1 data per write + stat data update */ #define REISERFS_QUOTA_INIT_BLOCKS(s) (REISERFS_SB(s)->s_mount_opt & (1<<REISERFS_QUOTA) ? \ (DQUOT_INIT_ALLOC*(JOURNAL_PER_BALANCE_CNT+2)+DQUOT_INIT_REWRITE+1) : 0) /* same as with INIT */ #define REISERFS_QUOTA_DEL_BLOCKS(s) (REISERFS_SB(s)->s_mount_opt & (1<<REISERFS_QUOTA) ? \ (DQUOT_DEL_ALLOC*(JOURNAL_PER_BALANCE_CNT+2)+DQUOT_DEL_REWRITE+1) : 0) #else #define REISERFS_QUOTA_TRANS_BLOCKS(s) 0 #define REISERFS_QUOTA_INIT_BLOCKS(s) 0 #define REISERFS_QUOTA_DEL_BLOCKS(s) 0 #endif /* both of these can be as low as 1, or as high as you want. The min is the ** number of 4k bitmap nodes preallocated on mount. New nodes are allocated ** as needed, and released when transactions are committed. On release, if ** the current number of nodes is > max, the node is freed, otherwise, ** it is put on a free list for faster use later. */ #define REISERFS_MIN_BITMAP_NODES 10 #define REISERFS_MAX_BITMAP_NODES 100 #define JBH_HASH_SHIFT 13 /* these are based on journal hash size of 8192 */ #define JBH_HASH_MASK 8191 #define _jhashfn(sb,block) \ (((unsigned long)sb>>L1_CACHE_SHIFT) ^ \ (((block)<<(JBH_HASH_SHIFT - 6)) ^ ((block) >> 13) ^ ((block) << (JBH_HASH_SHIFT - 12)))) #define journal_hash(t,sb,block) ((t)[_jhashfn((sb),(block)) & JBH_HASH_MASK]) // We need these to make journal.c code more readable #define journal_find_get_block(s, block) __find_get_block(SB_JOURNAL(s)->j_dev_bd, block, s->s_blocksize) #define journal_getblk(s, block) __getblk(SB_JOURNAL(s)->j_dev_bd, block, s->s_blocksize) #define journal_bread(s, block) __bread(SB_JOURNAL(s)->j_dev_bd, block, s->s_blocksize) //enum reiserfs_bh_state_bits { // BH_JDirty = BH_PrivateStart, /* buffer is in current transaction */ // BH_JDirty_wait, // BH_JNew, /* disk block was taken off free list before // * being in a finished transaction, or // * written to disk. Can be reused immed. */ // BH_JPrepared, // BH_JRestore_dirty, // BH_JTest, // debugging only will go away //}; /* BUFFER_FNS(JDirty, journaled); TAS_BUFFER_FNS(JDirty, journaled); BUFFER_FNS(JDirty_wait, journal_dirty); TAS_BUFFER_FNS(JDirty_wait, journal_dirty); BUFFER_FNS(JNew, journal_new); TAS_BUFFER_FNS(JNew, journal_new); BUFFER_FNS(JPrepared, journal_prepared); TAS_BUFFER_FNS(JPrepared, journal_prepared); BUFFER_FNS(JRestore_dirty, journal_restore_dirty); TAS_BUFFER_FNS(JRestore_dirty, journal_restore_dirty); BUFFER_FNS(JTest, journal_test); TAS_BUFFER_FNS(JTest, journal_test); */ /* ** transaction handle which is passed around for all journal calls */ struct reiserfs_transaction_handle { struct super_block *t_super; /* super for this FS when journal_begin was called. saves calls to reiserfs_get_super also used by nested transactions to make sure they are nesting on the right FS _must_ be first in the handle */ int t_refcount; int t_blocks_logged; /* number of blocks this writer has logged */ int t_blocks_allocated; /* number of blocks this writer allocated */ unsigned long t_trans_id; /* sanity check, equals the current trans id */ void *t_handle_save; /* save existing current->journal_info */ unsigned displace_new_blocks:1; /* if new block allocation occurres, that block should be displaced from others */ //struct list_head t_list; }; /* used to keep track of ordered and tail writes, attached to the buffer * head through b_journal_head. */ struct reiserfs_jh { struct reiserfs_journal_list *jl; struct buffer_head *bh; //struct list_head list; }; // // get key version from on disk key - kludge // /* static inline int le_key_version(const struct reiserfs_key *key) { int type; type = offset_v2_k_type(&(key->u.k_offset_v2)); if (type != TYPE_DIRECT && type != TYPE_INDIRECT && type != TYPE_DIRENTRY) return KEY_FORMAT_3_5; return KEY_FORMAT_3_6; } static inline void copy_key(struct reiserfs_key *to, const struct reiserfs_key *from) { memcpy(to, from, KEY_SIZE); } */ #define i_block_size(inode) ((inode)->i_sb->s_blocksize) #define file_size(inode) ((inode)->i_size) #define tail_size(inode) (file_size (inode) & (i_block_size (inode) - 1)) #define tail_has_to_be_packed(inode) (have_large_tails ((inode)->i_sb)?\ !STORE_TAIL_IN_UNFM_S1(file_size (inode), tail_size(inode), inode->i_sb->s_blocksize):have_small_tails ((inode)->i_sb)?!STORE_TAIL_IN_UNFM_S2(file_size (inode), tail_size(inode), inode->i_sb->s_blocksize):0 ) /* inode.c */ /* args for the create parameter of reiserfs_get_block */ #define GET_BLOCK_NO_CREATE 0 /* don't create new blocks or convert tails */ #define GET_BLOCK_CREATE 1 /* add anything you need to find block */ #define GET_BLOCK_NO_HOLE 2 /* return -ENOENT for file holes */ #define GET_BLOCK_READ_DIRECT 4 /* read the tail if indirect item not found */ #define GET_BLOCK_NO_IMUX 8 /* i_mutex is not held, don't preallocate */ #define GET_BLOCK_NO_DANGLE 16 /* don't leave any transactions running */ /* bitmap.c */ /* structure contains hints for block allocator, and it is a container for * arguments, such as node, search path, transaction_handle, etc. */ struct __reiserfs_blocknr_hint { struct inode *inode; /* inode passed to allocator, if we allocate unf. nodes */ long block; /* file offset, in blocks */ struct in_core_key key; struct path *path; /* search path, used by allocator to deternine search_start by * various ways */ struct reiserfs_transaction_handle *th; /* transaction handle is needed to log super blocks and * bitmap blocks changes */ b_blocknr_t beg, end; b_blocknr_t search_start; /* a field used to transfer search start value (block number) * between different block allocator procedures * (determine_search_start() and others) */ int prealloc_size; /* is set in determine_prealloc_size() function, used by underlayed * function that do actual allocation */ unsigned formatted_node:1; /* the allocator uses different polices for getting disk space for * formatted/unformatted blocks with/without preallocation */ unsigned preallocate:1; }; typedef struct __reiserfs_blocknr_hint reiserfs_blocknr_hint_t; /* hashes.c */ __u32 keyed_hash(const signed char *msg, int len); __u32 yura_hash(const signed char *msg, int len); __u32 r5_hash(const signed char *msg, int len); /* the ext2 bit routines adjust for big or little endian as ** appropriate for the arch, so in our laziness we use them rather ** than using the bit routines they call more directly. These ** routines must be used when changing on disk bitmaps. */ #define reiserfs_test_and_set_le_bit ext2_set_bit #define reiserfs_test_and_clear_le_bit ext2_clear_bit #define reiserfs_test_le_bit ext2_test_bit #define reiserfs_find_next_zero_le_bit ext2_find_next_zero_bit /* sometimes reiserfs_truncate may require to allocate few new blocks to perform indirect2direct conversion. People probably used to think, that truncate should work without problems on a filesystem without free disk space. They may complain that they can not truncate due to lack of free disk space. This spare space allows us to not worry about it. 500 is probably too much, but it should be absolutely safe */ #define SPARE_SPACE 500 /* ioctl's command */ #define REISERFS_IOC_UNPACK _IOW(0xCD,1,long) /* define following flags to be the same as in ext2, so that chattr(1), lsattr(1) will work with us. */ #define REISERFS_IOC_GETFLAGS EXT2_IOC_GETFLAGS #define REISERFS_IOC_SETFLAGS EXT2_IOC_SETFLAGS #define REISERFS_IOC_GETVERSION EXT2_IOC_GETVERSION #define REISERFS_IOC_SETVERSION EXT2_IOC_SETVERSION #pragma pack() #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/mk_fsw_strfunc.py���������������������������������������������������������0000755�0001750�0001750�00000014215�12631615174�021277� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env python # # Copyright (c) 2006 Christoph Pfisterer # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the # distribution. # # * Neither the name of Christoph Pfisterer nor the names of the # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # # mk_fsw_strfunc.py # # definitions types = { 'ISO88591': 'fsw_u8', 'UTF8': 'fsw_u8', 'UTF16': 'fsw_u16', 'UTF16_SWAPPED': 'fsw_u16', } getnext = { 'ISO88591': 'VARC = *VARP++;', 'UTF8': """VARC = *VARP++; if ((VARC & 0xe0) == 0xc0) { VARC = ((VARC & 0x1f) << 6) | (*VARP++ & 0x3f); } else if ((VARC & 0xf0) == 0xe0) { VARC = ((VARC & 0x0f) << 12) | ((*VARP++ & 0x3f) << 6); VARC |= (*VARP++ & 0x3f); } else if ((VARC & 0xf8) == 0xf0) { VARC = ((VARC & 0x07) << 18) | ((*VARP++ & 0x3f) << 12); VARC |= ((*VARP++ & 0x3f) << 6); VARC |= (*VARP++ & 0x3f); }""", 'UTF16': 'VARC = *VARP++;', 'UTF16_SWAPPED': 'VARC = *VARP++; VARC = FSW_SWAPVALUE_U16(VARC);', } combos = ( ('ISO88591', 'UTF8'), ('ISO88591', 'UTF16'), ('ISO88591', 'UTF16_SWAPPED'), ('UTF8', 'UTF16'), ('UTF8', 'UTF16_SWAPPED'), ('UTF16', 'UTF16_SWAPPED') ) coerce_combos = {} for combo in combos: coerce_combos.setdefault(combo[0], []).append(combo[1]) coerce_combos.setdefault(combo[1], []).append(combo[0]) # generate functions output = """/* fsw_strfunc.h generated by mk_fsw_strfunc.py */ """ # generate streq functions (symmetric) for combo in combos: (enc1, enc2) = combo type1 = types[enc1] type2 = types[enc2] getnext1 = getnext[enc1].replace('VARC', 'c1').replace('VARP', 'p1').replace("\n", "\n ") getnext2 = getnext[enc2].replace('VARC', 'c2').replace('VARP', 'p2').replace("\n", "\n ") output += """ static int fsw_streq_%(enc1)s_%(enc2)s(void *s1data, void *s2data, int len) { int i; %(type1)s *p1 = (%(type1)s *)s1data; %(type2)s *p2 = (%(type2)s *)s2data; fsw_u32 c1, c2; for (i = 0; i < len; i++) { %(getnext1)s %(getnext2)s if (c1 != c2) return 0; } return 1; } """ % locals() # generate strcoerce functions (asymmetric, destination-specific) for enc2 in ('ISO88591', 'UTF16'): for enc1 in coerce_combos[enc2]: type1 = types[enc1] type2 = types[enc2] getnext1 = getnext[enc1].replace('VARC', 'c').replace('VARP', 'sp').replace("\n", "\n ") output += """ static fsw_status_t fsw_strcoerce_%(enc1)s_%(enc2)s(void *srcdata, int srclen, struct fsw_string *dest) { fsw_status_t status; int i; %(type1)s *sp; %(type2)s *dp; fsw_u32 c; dest->type = FSW_STRING_TYPE_%(enc2)s; dest->len = srclen; dest->size = srclen * sizeof(%(type2)s); status = fsw_alloc(dest->size, &dest->data); if (status) return status; sp = (%(type1)s *)srcdata; dp = (%(type2)s *)dest->data; for (i = 0; i < srclen; i++) { %(getnext1)s *dp++ = c; } return FSW_SUCCESS; } """ % locals() for enc2 in ('UTF8',): for enc1 in coerce_combos[enc2]: type1 = types[enc1] type2 = types[enc2] getnext1 = getnext[enc1].replace('VARC', 'c').replace('VARP', 'sp').replace("\n", "\n ") output += """ static fsw_status_t fsw_strcoerce_%(enc1)s_%(enc2)s(void *srcdata, int srclen, struct fsw_string *dest) { fsw_status_t status; int i, destsize; %(type1)s *sp; %(type2)s *dp; fsw_u32 c; sp = (%(type1)s *)srcdata; destsize = 0; for (i = 0; i < srclen; i++) { %(getnext1)s if (c < 0x000080) destsize++; else if (c < 0x000800) destsize += 2; else if (c < 0x010000) destsize += 3; else destsize += 4; } dest->type = FSW_STRING_TYPE_%(enc2)s; dest->len = srclen; dest->size = destsize; status = fsw_alloc(dest->size, &dest->data); if (status) return status; sp = (%(type1)s *)srcdata; dp = (%(type2)s *)dest->data; for (i = 0; i < srclen; i++) { %(getnext1)s if (c < 0x000080) { *dp++ = c; } else if (c < 0x000800) { *dp++ = 0xc0 | ((c >> 6) & 0x1f); *dp++ = 0x80 | (c & 0x3f); } else if (c < 0x010000) { *dp++ = 0xe0 | ((c >> 12) & 0x0f); *dp++ = 0x80 | ((c >> 6) & 0x3f); *dp++ = 0x80 | (c & 0x3f); } else { *dp++ = 0xf0 | ((c >> 18) & 0x07); *dp++ = 0x80 | ((c >> 12) & 0x3f); *dp++ = 0x80 | ((c >> 6) & 0x3f); *dp++ = 0x80 | (c & 0x3f); } } return FSW_SUCCESS; } """ % locals() # coerce functions with destination UFT16_SWAPPED missing by design # write output file f = file("fsw_strfunc.h", "w") f.write(output) f.close() # EOF �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/fsw_efi.h�����������������������������������������������������������������0000664�0001750�0001750�00000010054�13106171410�017446� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/** * \file fsw_efi.h * EFI host environment header. */ /*- * Copyright (c) 2006 Christoph Pfisterer * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * * Neither the name of Christoph Pfisterer nor the names of the * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _FSW_EFI_H_ #define _FSW_EFI_H_ #include "fsw_core.h" #ifdef __MAKEWITH_GNUEFI #define CompareGuid(a, b) CompareGuid(a, b)==0 #endif #define REFIND_EFI_DISK_IO_PROTOCOL_GUID \ { \ 0xce345171, 0xba0b, 0x11d2, {0x8e, 0x4f, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \ } #define REFIND_EFI_BLOCK_IO_PROTOCOL_GUID \ { \ 0x964e5b21, 0x6459, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \ } /** * EFI Host: Private per-volume structure. */ typedef struct { UINT64 Signature; //!< Used to identify this structure EFI_FILE_IO_INTERFACE FileSystem; //!< Published EFI protocol interface structure EFI_HANDLE Handle; //!< The device handle the protocol is attached to EFI_DISK_IO *DiskIo; //!< The Disk I/O protocol we use for disk access UINT32 MediaId; //!< The media ID from the Block I/O protocol EFI_STATUS LastIOStatus; //!< Last status from Disk I/O struct fsw_volume *vol; //!< FSW volume structure } FSW_VOLUME_DATA; /** Signature for the volume structure. */ #define FSW_VOLUME_DATA_SIGNATURE EFI_SIGNATURE_32 ('f', 's', 'w', 'V') /** Access macro for the volume structure. */ #define FSW_VOLUME_FROM_FILE_SYSTEM(a) CR (a, FSW_VOLUME_DATA, FileSystem, FSW_VOLUME_DATA_SIGNATURE) /** * EFI Host: Private structure for a EFI_FILE interface. */ typedef struct { UINT64 Signature; //!< Used to identify this structure EFI_FILE FileHandle; //!< Published EFI protocol interface structure UINT64 Type; //!< File type used for dispatching struct fsw_shandle shand; //!< FSW handle for this file } FSW_FILE_DATA; /** File type: regular file. */ #define FSW_EFI_FILE_TYPE_FILE (0) /** File type: directory. */ #define FSW_EFI_FILE_TYPE_DIR (1) /** Signature for the file handle structure. */ #define FSW_FILE_DATA_SIGNATURE EFI_SIGNATURE_32 ('f', 's', 'w', 'F') /** Access macro for the file handle structure. */ #define FSW_FILE_FROM_FILE_HANDLE(a) CR (a, FSW_FILE_DATA, FileHandle, FSW_FILE_DATA_SIGNATURE) // // Library functions // VOID fsw_efi_decode_time(OUT EFI_TIME *EfiTime, IN UINT32 UnixTime); UINTN fsw_efi_strsize(struct fsw_string *s); VOID fsw_efi_strcpy(CHAR16 *Dest, struct fsw_string *src); VOID EFIAPI fsw_efi_clear_cache(VOID); #endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/ext2.inf������������������������������������������������������������������0000664�0001750�0001750�00000003635�13112553171�017247� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������## @file # # ext2.inf file to build rEFInd's ext2fs driver using the EDK2/UDK201# # development kit. # # Copyright (c) 2012-2017 by Roderick W. Smith # Released under the terms of the GPLv3 (or, at your discretion, any later # version), a copy of which should come with this file. # ## [Defines] INF_VERSION = 0x00010005 BASE_NAME = ext2 FILE_GUID = c1ad9a39-9e9c-4c5f-ac48-ddeb05408ad2 MODULE_TYPE = UEFI_DRIVER EDK_RELEASE_VERSION = 0x00020000 EFI_SPECIFICATION_VERSION = 0x00010000 VERSION_STRING = 1.0 ENTRY_POINT = fsw_efi_main FSTYPE = ext2 # # The following information is for reference only and not required by the build tools. # # VALID_ARCHITECTURES = IA32 X64 IPF EBC # [Sources] fsw_efi.c fsw_ext2.c fsw_core.c fsw_lib.c fsw_efi_lib.c [Packages] MdePkg/MdePkg.dec MdeModulePkg/MdeModulePkg.dec IntelFrameworkPkg/IntelFrameworkPkg.dec IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec [LibraryClasses] UefiDriverEntryPoint DxeServicesLib DxeServicesTableLib MemoryAllocationLib [LibraryClasses.AARCH64] BaseStackCheckLib # Comment out CompilerIntrinsicsLib when compiling for AARCH64 using UDK2014 CompilerIntrinsicsLib [Guids] [Ppis] [Protocols] [FeaturePcd] [Pcd] [BuildOptions.IA32] XCODE:*_*_*_CC_FLAGS = -Os -DEFI32 -D__MAKEWITH_TIANO -DFSTYPE=ext2 GCC:*_*_*_CC_FLAGS = -Os -DEFI32 -D__MAKEWITH_TIANO -DFSTYPE=ext2 [BuildOptions.X64] XCODE:*_*_*_CC_FLAGS = -Os -DEFIX64 -D__MAKEWITH_TIANO -DFSTYPE=ext2 GCC:*_*_*_CC_FLAGS = -Os -DEFIX64 -D__MAKEWITH_TIANO -DFSTYPE=ext2 [BuildOptions.AARCH64] XCODE:*_*_*_CC_FLAGS = -Os -DEFIAARCH64 -D__MAKEWITH_TIANO -DFSTYPE=ext2 GCC:*_*_*_CC_FLAGS = -Os -DEFIAARCH64 -D__MAKEWITH_TIANO -DFSTYPE=ext2 ���������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/LICENSE.txt���������������������������������������������������������������0000664�0001750�0001750�00000004056�12626644770�017527� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Licensing for the filesystem drivers is complex. Three different licenses apply to various parts of the code: * Christoph Pfisterer's original file system wrapper (FSW) code is covered by a BSD-style license. Many of the source files with names that take the form fsw_*.[ch] are so licensed, but this is NOT generally true of filesystem-specific files (e.g., fsw_ext2.c or fsw_btrfs.c). * Certain filesystem drivers are licensed under the GPLv2, either because they borrow code from the Linux kernel or because a developer (typically Oracle) applied the GPLv2 license to them. This is true of the ext2fs, ext4fs, ReiserFS, HFS+, and ISO-9660 drivers. * At least one filesystem driver (Btrfs) uses code taken from GRUB, and so uses the GPLv3 (or later) license. Note that the GPLv2 and GPLv3 are, ironically, not compatible licenses. Thus, code from GPLv2 and GPLv3 projects should not be mixed. The BSD license used by Pfisterer's original code is compatible with both versions of the GPL, so the fact that both GPLv2 and GPLv3 drivers is built upon it is OK. If you intend to contribute to this project's drivers or use the code yourself, please keep this fact in mind. The below was written by Christoph Pfisterer with respect to his original code: File System Wrapper License ============================= The various parts of the File System Wrapper source code come from different sources and may carry different licenses. Here's a quick account of the situation: * The core code was written from scratch and is covered by a BSD-style license. * The EFI host driver was written from scratch, possibly using code from the TianoCore project and Intel's EFI Application Toolkit. It is covered by a BSD-style license. * The ext2 and reiserfs file system drivers use definitions from the Linux kernel source. The actual code was written from scratch, using multiple sources for reference. These drivers are covered by the GNU GPL. For more details, see each file's boilerplate comment. The full text of the GNU GPL is in the file LICENSE_GPL.txt. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/fsw_btrfs.c���������������������������������������������������������������0000664�0001750�0001750�00000206035�13363455356�020047� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * fsw_btrfs.c: * btrfs UEFI driver * by Samuel Liao * Copyright (c) 2013 Tencent, Inc. * * This driver base on grub 2.0 btrfs implementation. */ /* btrfs.c - B-tree file system. */ /* * GRUB -- GRand Unified Bootloader * Copyright (C) 2010 Free Software Foundation, Inc. * * GRUB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRUB is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GRUB. If not, see <http://www.gnu.org/licenses/>. */ //#define DPRINT(x...) Print(x) #include "fsw_core.h" #define uint8_t fsw_u8 #define uint16_t fsw_u16 #define uint32_t fsw_u32 #define uint64_t fsw_u64 #define int64_t fsw_s64 #define int32_t fsw_s32 #ifndef DPRINT #define DPRINT(x...) /* */ #endif /* no single io/element size over 2G */ #define fsw_size_t int #define fsw_ssize_t int /* never zip over 2G, 32bit is enough */ #define grub_off_t int32_t #define grub_size_t int32_t #define grub_ssize_t int32_t #include "crc32c.c" #include "gzio.c" #define MINILZO_CFG_SKIP_LZO_PTR 1 #define MINILZO_CFG_SKIP_LZO_UTIL 1 #define MINILZO_CFG_SKIP_LZO_STRING 1 #define MINILZO_CFG_SKIP_LZO_INIT 1 #define MINILZO_CFG_SKIP_LZO1X_DECOMPRESS 1 #define MINILZO_CFG_SKIP_LZO1X_1_COMPRESS 1 #define MINILZO_CFG_SKIP_LZO_STRING 1 #include "minilzo.c" #include "scandisk.c" #define BTRFS_DEFAULT_BLOCK_SIZE 4096 #define GRUB_BTRFS_SIGNATURE "_BHRfS_M" /* From http://www.oberhumer.com/opensource/lzo/lzofaq.php * LZO will expand incompressible data by a little amount. I still haven't * computed the exact values, but I suggest using these formulas for * a worst-case expansion calculation: * * output_block_size = input_block_size + (input_block_size / 16) + 64 + 3 * */ #define GRUB_BTRFS_LZO_BLOCK_SIZE 4096 #define GRUB_BTRFS_LZO_BLOCK_MAX_CSIZE (GRUB_BTRFS_LZO_BLOCK_SIZE + \ (GRUB_BTRFS_LZO_BLOCK_SIZE / 16) + 64 + 3) /* * on disk struct has prefix 'btrfs_', little endian * on memory struct has prefix 'fsw_btrfs_' */ typedef uint8_t btrfs_checksum_t[0x20]; typedef uint32_t btrfs_uuid_t[4]; struct btrfs_device { uint64_t device_id; uint64_t size; uint8_t dummy[0x62 - 0x10]; } __attribute__ ((__packed__)); struct btrfs_superblock { btrfs_checksum_t checksum; btrfs_uuid_t uuid; uint8_t dummy[0x10]; uint8_t signature[sizeof (GRUB_BTRFS_SIGNATURE) - 1]; uint64_t generation; uint64_t root_tree; uint64_t chunk_tree; uint8_t dummy2[0x10]; uint64_t total_bytes; uint64_t bytes_used; uint64_t root_dir_objectid; #define BTRFS_MAX_NUM_DEVICES 0x10000 uint64_t num_devices; uint32_t sectorsize; uint32_t nodesize; uint8_t dummy3[0x31]; struct btrfs_device this_device; char label[0x100]; uint8_t dummy4[0x100]; uint8_t bootstrap_mapping[0x800]; } __attribute__ ((__packed__)); struct btrfs_header { btrfs_checksum_t checksum; btrfs_uuid_t uuid; uint8_t dummy[0x30]; uint32_t nitems; uint8_t level; } __attribute__ ((__packed__)); struct fsw_btrfs_device_desc { struct fsw_volume * dev; uint64_t id; }; #define RECOVER_CACHE_SIZE 17 struct fsw_btrfs_recover_cache { uint64_t device_id; uint64_t offset; char *buffer; BOOLEAN valid; }; struct fsw_btrfs_volume { struct fsw_volume g; //!< Generic volume structure /* superblock shadows */ uint8_t bootstrap_mapping[0x800]; btrfs_uuid_t uuid; uint64_t total_bytes; uint64_t bytes_used; uint64_t chunk_tree; uint64_t root_tree; uint64_t top_tree; /* top volume tree */ unsigned num_devices; unsigned sectorshift; unsigned sectorsize; int is_master; int rescan_once; struct fsw_btrfs_device_desc *devices_attached; unsigned n_devices_attached; unsigned n_devices_allocated; /* Cached extent data. */ uint64_t extstart; uint64_t extend; uint64_t extino; uint64_t exttree; uint32_t extsize; struct btrfs_extent_data *extent; struct fsw_btrfs_recover_cache *rcache; }; enum { GRUB_BTRFS_ITEM_TYPE_INODE_ITEM = 0x01, GRUB_BTRFS_ITEM_TYPE_INODE_REF = 0x0c, GRUB_BTRFS_ITEM_TYPE_DIR_ITEM = 0x54, GRUB_BTRFS_ITEM_TYPE_EXTENT_ITEM = 0x6c, GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM = 0x84, GRUB_BTRFS_ITEM_TYPE_DEVICE = 0xd8, GRUB_BTRFS_ITEM_TYPE_CHUNK = 0xe4 }; struct btrfs_key { uint64_t object_id; uint8_t type; uint64_t offset; } __attribute__ ((__packed__)); struct btrfs_chunk_item { uint64_t size; uint64_t dummy; uint64_t stripe_length; uint64_t type; #define GRUB_BTRFS_CHUNK_TYPE_BITS_DONTCARE 0x07 #define GRUB_BTRFS_CHUNK_TYPE_SINGLE 0x00 #define GRUB_BTRFS_CHUNK_TYPE_RAID0 0x08 #define GRUB_BTRFS_CHUNK_TYPE_RAID1 0x10 #define GRUB_BTRFS_CHUNK_TYPE_DUPLICATED 0x20 #define GRUB_BTRFS_CHUNK_TYPE_RAID10 0x40 #define GRUB_BTRFS_CHUNK_TYPE_RAID5 0x80 #define GRUB_BTRFS_CHUNK_TYPE_RAID6 0x100 uint8_t dummy2[0xc]; uint16_t nstripes; uint16_t nsubstripes; #define RAID5_TAG 0x100000 } __attribute__ ((__packed__)); struct btrfs_chunk_stripe { uint64_t device_id; uint64_t offset; btrfs_uuid_t device_uuid; } __attribute__ ((__packed__)); struct btrfs_leaf_node { struct btrfs_key key; uint32_t offset; uint32_t size; } __attribute__ ((__packed__)); struct btrfs_internal_node { struct btrfs_key key; uint64_t addr; uint64_t dummy; } __attribute__ ((__packed__)); struct btrfs_dir_item { struct btrfs_key key; uint64_t transid; uint16_t m; uint16_t n; #define GRUB_BTRFS_DIR_ITEM_TYPE_REGULAR 1 #define GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY 2 #define GRUB_BTRFS_DIR_ITEM_TYPE_SYMLINK 7 uint8_t type; char name[0]; } __attribute__ ((__packed__)); struct fsw_btrfs_leaf_descriptor { unsigned depth; unsigned allocated; struct { uint64_t addr; unsigned iter; unsigned maxiter; int leaf; } *data; }; struct btrfs_root_item { uint8_t dummy[0xb0]; uint64_t tree; uint64_t inode; } __attribute__ ((__packed__)); struct btrfs_time { int64_t sec; uint32_t nanosec; } __attribute__ ((__packed__)); struct btrfs_inode { uint64_t gen_id; uint64_t trans_id; uint64_t size; uint64_t nbytes; uint64_t block_group; uint32_t nlink; uint32_t uid; uint32_t gid; uint32_t mode; uint64_t rdev; uint64_t flags; uint64_t seq; uint64_t reserved[4]; struct btrfs_time atime; struct btrfs_time ctime; struct btrfs_time mtime; struct btrfs_time otime; } __attribute__ ((__packed__)); struct fsw_btrfs_dnode { struct fsw_dnode g; //!< Generic dnode structure struct btrfs_inode *raw; //!< Full raw inode structure }; struct btrfs_extent_data { uint64_t dummy; uint64_t size; uint8_t compression; uint8_t encryption; uint16_t encoding; uint8_t type; union { char inl[0]; struct { uint64_t laddr; uint64_t compressed_size; uint64_t offset; uint64_t filled; }; }; } __attribute__ ((__packed__)); #define GRUB_BTRFS_EXTENT_INLINE 0 #define GRUB_BTRFS_EXTENT_REGULAR 1 #define GRUB_BTRFS_COMPRESSION_NONE 0 #define GRUB_BTRFS_COMPRESSION_ZLIB 1 #define GRUB_BTRFS_COMPRESSION_LZO 2 #define GRUB_BTRFS_COMPRESSION_ZSTD 3 #define GRUB_BTRFS_COMPRESSION_MAX 3 #define GRUB_BTRFS_OBJECT_ID_CHUNK 0x100 struct fsw_btrfs_uuid_list { struct fsw_btrfs_volume *master; struct fsw_btrfs_uuid_list *next; }; static int uuid_eq(btrfs_uuid_t u1, btrfs_uuid_t u2) { return u1[0]==u2[0] && u1[1]==u2[1] && u1[2]==u2[2] && u1[3]==u2[3]; } static struct fsw_btrfs_uuid_list *master_uuid_list = NULL; static int master_uuid_add(struct fsw_btrfs_volume *vol, struct fsw_btrfs_volume **master_out) { struct fsw_btrfs_uuid_list *l; for (l = master_uuid_list; l; l=l->next) if(uuid_eq(l->master->uuid, vol->uuid)) { if(master_out) *master_out = l->master; return 0; } l = AllocatePool(sizeof(struct fsw_btrfs_uuid_list)); l->master = vol; l->next = master_uuid_list; master_uuid_list = l; return 1; } static void master_uuid_remove(struct fsw_btrfs_volume *vol) { struct fsw_btrfs_uuid_list **lp; for (lp = &master_uuid_list; *lp; lp=&(*lp)->next) if((*lp)->master == vol) { struct fsw_btrfs_uuid_list *n = *lp; *lp = n->next; FreePool(n); break; } } static fsw_status_t btrfs_set_superblock_info(struct fsw_btrfs_volume *vol, struct btrfs_superblock *sb) { int i; vol->uuid[0] = sb->uuid[0]; vol->uuid[1] = sb->uuid[1]; vol->uuid[2] = sb->uuid[2]; vol->uuid[3] = sb->uuid[3]; vol->chunk_tree = sb->chunk_tree; vol->root_tree = sb->root_tree; vol->total_bytes = fsw_u64_le_swap(sb->total_bytes); vol->bytes_used = fsw_u64_le_swap(sb->bytes_used); vol->sectorshift = 0; vol->sectorsize = fsw_u32_le_swap(sb->sectorsize); for(i=9; i<20; i++) { if((1UL<<i) == vol->sectorsize) { vol->sectorshift = i; break; } } if(fsw_u64_le_swap(sb->num_devices) > BTRFS_MAX_NUM_DEVICES) vol->num_devices = BTRFS_MAX_NUM_DEVICES; else vol->num_devices = fsw_u64_le_swap(sb->num_devices); fsw_memcpy(vol->bootstrap_mapping, sb->bootstrap_mapping, sizeof(vol->bootstrap_mapping)); return FSW_SUCCESS; } static uint64_t superblock_pos[4] = { 64 / 4, 64 * 1024 / 4, 256 * 1048576 / 4, 1048576ULL * 1048576ULL / 4 }; static fsw_status_t fsw_btrfs_read_logical(struct fsw_btrfs_volume *vol, uint64_t addr, void *buf, fsw_size_t size, int rdepth, int cache_level); static fsw_status_t btrfs_read_superblock (struct fsw_volume *vol, struct btrfs_superblock *sb_out) { unsigned i; uint64_t total_blocks = 1024; fsw_status_t err = FSW_SUCCESS; fsw_set_blocksize(vol, BTRFS_DEFAULT_BLOCK_SIZE, BTRFS_DEFAULT_BLOCK_SIZE); for (i = 0; i < 4; i++) { uint8_t *buffer; struct btrfs_superblock *sb; /* Don't try additional superblocks beyond device size. */ if (total_blocks <= superblock_pos[i]) break; err = fsw_block_get(vol, superblock_pos[i], 0, (void **)&buffer); if (err) { fsw_block_release(vol, superblock_pos[i], buffer); break; } sb = (struct btrfs_superblock *)buffer; if (!fsw_memeq (sb->signature, GRUB_BTRFS_SIGNATURE, sizeof (GRUB_BTRFS_SIGNATURE) - 1)) { fsw_block_release(vol, superblock_pos[i], buffer); break; } if (i == 0 || fsw_u64_le_swap (sb->generation) > fsw_u64_le_swap (sb_out->generation)) { fsw_memcpy (sb_out, sb, sizeof (*sb)); total_blocks = fsw_u64_le_swap (sb->this_device.size) >> 12; } fsw_block_release(vol, superblock_pos[i], buffer); } if ((err == FSW_UNSUPPORTED || !err) && i == 0) return FSW_UNSUPPORTED; if (err == FSW_UNSUPPORTED) err = FSW_SUCCESS; if(err == 0) DPRINT(L"btrfs: UUID: %08x-%08x-%08x-%08x device id: %d\n", sb_out->uuid[0], sb_out->uuid[1], sb_out->uuid[2], sb_out->uuid[3], sb_out->this_device.device_id); return err; } static int key_cmp (const struct btrfs_key *a, const struct btrfs_key *b) { if (fsw_u64_le_swap (a->object_id) < fsw_u64_le_swap (b->object_id)) return -1; if (fsw_u64_le_swap (a->object_id) > fsw_u64_le_swap (b->object_id)) return +1; if (a->type < b->type) return -1; if (a->type > b->type) return +1; if (fsw_u64_le_swap (a->offset) < fsw_u64_le_swap (b->offset)) return -1; if (fsw_u64_le_swap (a->offset) > fsw_u64_le_swap (b->offset)) return +1; return 0; } static void free_iterator (struct fsw_btrfs_leaf_descriptor *desc) { fsw_free (desc->data); } static fsw_status_t save_ref (struct fsw_btrfs_leaf_descriptor *desc, uint64_t addr, unsigned i, unsigned m, int l) { desc->depth++; if (desc->allocated < desc->depth) { void *newdata; int oldsize = sizeof (desc->data[0]) * desc->allocated; desc->allocated *= 2; newdata = AllocatePool (sizeof (desc->data[0]) * desc->allocated); if (!newdata) return FSW_OUT_OF_MEMORY; fsw_memcpy(newdata, desc->data, oldsize); FreePool(desc->data); desc->data = newdata; } desc->data[desc->depth - 1].addr = addr; desc->data[desc->depth - 1].iter = i; desc->data[desc->depth - 1].maxiter = m; desc->data[desc->depth - 1].leaf = l; return FSW_SUCCESS; } static int next (struct fsw_btrfs_volume *vol, struct fsw_btrfs_leaf_descriptor *desc, uint64_t * outaddr, fsw_size_t * outsize, struct btrfs_key *key_out) { fsw_status_t err; struct btrfs_leaf_node leaf; for (; desc->depth > 0; desc->depth--) { desc->data[desc->depth - 1].iter++; if (desc->data[desc->depth - 1].iter < desc->data[desc->depth - 1].maxiter) break; } if (desc->depth == 0) return 0; while (!desc->data[desc->depth - 1].leaf) { struct btrfs_internal_node node; struct btrfs_header head; fsw_memzero(&node, sizeof(node)); err = fsw_btrfs_read_logical (vol, desc->data[desc->depth - 1].iter * sizeof (node) + sizeof (struct btrfs_header) + desc->data[desc->depth - 1].addr, &node, sizeof (node), 0, 1); if (err) return -err; err = fsw_btrfs_read_logical (vol, fsw_u64_le_swap (node.addr), &head, sizeof (head), 0, 1); if (err) return -err; save_ref (desc, fsw_u64_le_swap (node.addr), 0, fsw_u32_le_swap (head.nitems), !head.level); } err = fsw_btrfs_read_logical (vol, desc->data[desc->depth - 1].iter * sizeof (leaf) + sizeof (struct btrfs_header) + desc->data[desc->depth - 1].addr, &leaf, sizeof (leaf), 0, 1); if (err) return -err; *outsize = fsw_u32_le_swap (leaf.size); *outaddr = desc->data[desc->depth - 1].addr + sizeof (struct btrfs_header) + fsw_u32_le_swap (leaf.offset); *key_out = leaf.key; return 1; } #define depth2cache(x) ((x) >= 4 ? 1 : 5-(x)) static fsw_status_t lower_bound (struct fsw_btrfs_volume *vol, const struct btrfs_key *key_in, struct btrfs_key *key_out, uint64_t root, uint64_t *outaddr, fsw_size_t *outsize, struct fsw_btrfs_leaf_descriptor *desc, int rdepth) { uint64_t addr = fsw_u64_le_swap (root); int depth = -1; if (desc) { desc->allocated = 16; desc->depth = 0; desc->data = AllocatePool (sizeof (desc->data[0]) * desc->allocated); if (!desc->data) return FSW_OUT_OF_MEMORY; } /* > 2 would work as well but be robust and allow a bit more just in case. */ if (rdepth > 10) return FSW_VOLUME_CORRUPTED; DPRINT (L"btrfs: retrieving %lx %x %lx\n", key_in->object_id, key_in->type, key_in->offset); while (1) { fsw_status_t err; struct btrfs_header head; fsw_memzero(&head, sizeof(head)); reiter: depth++; /* FIXME: preread few nodes into buffer. */ err = fsw_btrfs_read_logical (vol, addr, &head, sizeof (head), rdepth + 1, depth2cache(rdepth)); if (err) return err; addr += sizeof (head); if (head.level) { unsigned i; struct btrfs_internal_node node, node_last; int have_last = 0; fsw_memzero (&node_last, sizeof (node_last)); for (i = 0; i < fsw_u32_le_swap (head.nitems); i++) { err = fsw_btrfs_read_logical (vol, addr + i * sizeof (node), &node, sizeof (node), rdepth + 1, depth2cache(rdepth)); if (err) return err; DPRINT (L"btrfs: internal node (depth %d) %lx %x %lx\n", depth, node.key.object_id, node.key.type, node.key.offset); if (key_cmp (&node.key, key_in) == 0) { err = FSW_SUCCESS; if (desc) err = save_ref (desc, addr - sizeof (head), i, fsw_u32_le_swap (head.nitems), 0); if (err) return err; addr = fsw_u64_le_swap (node.addr); goto reiter; } if (key_cmp (&node.key, key_in) > 0) break; node_last = node; have_last = 1; } if (have_last) { err = FSW_SUCCESS; if (desc) err = save_ref (desc, addr - sizeof (head), i - 1, fsw_u32_le_swap (head.nitems), 0); if (err) return err; addr = fsw_u64_le_swap (node_last.addr); goto reiter; } *outsize = 0; *outaddr = 0; fsw_memzero (key_out, sizeof (*key_out)); if (desc) return save_ref (desc, addr - sizeof (head), -1, fsw_u32_le_swap (head.nitems), 0); return FSW_SUCCESS; } { unsigned i; struct btrfs_leaf_node leaf, leaf_last; int have_last = 0; for (i = 0; i < fsw_u32_le_swap (head.nitems); i++) { err = fsw_btrfs_read_logical (vol, addr + i * sizeof (leaf), &leaf, sizeof (leaf), rdepth + 1, depth2cache(rdepth)); if (err) return err; DPRINT (L"btrfs: leaf (depth %d) %lx %x %lx\n", depth, leaf.key.object_id, leaf.key.type, leaf.key.offset); if (key_cmp (&leaf.key, key_in) == 0) { fsw_memcpy (key_out, &leaf.key, sizeof (*key_out)); *outsize = fsw_u32_le_swap (leaf.size); *outaddr = addr + fsw_u32_le_swap (leaf.offset); if (desc) return save_ref (desc, addr - sizeof (head), i, fsw_u32_le_swap (head.nitems), 1); return FSW_SUCCESS; } if (key_cmp (&leaf.key, key_in) > 0) break; have_last = 1; leaf_last = leaf; } if (have_last) { fsw_memcpy (key_out, &leaf_last.key, sizeof (*key_out)); *outsize = fsw_u32_le_swap (leaf_last.size); *outaddr = addr + fsw_u32_le_swap (leaf_last.offset); if (desc) return save_ref (desc, addr - sizeof (head), i - 1, fsw_u32_le_swap (head.nitems), 1); return FSW_SUCCESS; } *outsize = 0; *outaddr = 0; fsw_memzero (key_out, sizeof (*key_out)); if (desc) return save_ref (desc, addr - sizeof (head), -1, fsw_u32_le_swap (head.nitems), 1); return FSW_SUCCESS; } } } static int btrfs_add_multi_device(struct fsw_btrfs_volume *master, struct fsw_volume *slave, struct btrfs_superblock *sb) { int i; for( i = 0; i < master->n_devices_attached; i++) if(sb->this_device.device_id == master->devices_attached[i].id) return FSW_UNSUPPORTED; slave = clone_dummy_volume(slave); if(slave == NULL) return FSW_OUT_OF_MEMORY; fsw_set_blocksize(slave, master->sectorsize, master->sectorsize); master->devices_attached[i].id = sb->this_device.device_id; master->devices_attached[i].dev = slave; master->n_devices_attached++; DPRINT(L"Found slave %d\n", sb->this_device.device_id); return FSW_SUCCESS; } static int scan_disks_hook(struct fsw_volume *volg, struct fsw_volume *slave) { struct fsw_btrfs_volume *vol = (struct fsw_btrfs_volume *)volg; struct btrfs_superblock sb; fsw_status_t err; if(vol->n_devices_attached >= vol->n_devices_allocated) return FSW_UNSUPPORTED; err = btrfs_read_superblock(slave, &sb); if(err) return FSW_UNSUPPORTED; if(!uuid_eq(vol->uuid, sb.uuid)) return FSW_UNSUPPORTED; return btrfs_add_multi_device(vol, slave, &sb); } static int do_rescan_once(struct fsw_btrfs_volume *vol) { if(vol->rescan_once == 0 || vol->n_devices_attached >= vol->n_devices_allocated) return 0; vol->rescan_once = 0; return scan_disks(scan_disks_hook, &vol->g); } static struct fsw_volume * find_device (struct fsw_btrfs_volume *vol, uint64_t id) { int i; for (i = 0; i < vol->n_devices_attached; i++) if (id == vol->devices_attached[i].id) return vol->devices_attached[i].dev; DPRINT(L"sub device %d not found\n", id); return NULL; } struct stripe_table { struct fsw_volume *dev; uint64_t off; char *ptr; }; static void block_xor(char *dst, const char *src, uint32_t blocksize) { UINTN *d = (UINTN *)dst; const UINTN *s = (const UINTN *)src; blocksize /= sizeof(UINTN); uint32_t i; for( i = 0; i < blocksize; i++) d[i] ^= s[i]; } static void stripe_xor(char *dst, struct stripe_table *stripe, int data_stripes, uint32_t blocksize) { unsigned i, j; UINTN c; for(j = 0; j < blocksize; j += sizeof(UINTN)) { /* data + P stripes */ for(c=0, i=0; i <= data_stripes; i++) if(stripe[i].ptr) c ^= *(UINTN *)(stripe[i].ptr + j); *(UINTN *)(dst + j) = c; } } static void stripe_release(struct stripe_table *stripe, int count, uint32_t offset) { unsigned i; for(i = 0; i < count; i++) { if(stripe[i].ptr) { fsw_block_release(stripe[i].dev, stripe[i].off + offset, (void *)stripe[i].ptr); } } } /* x**y. */ static uint8_t powx[255 * 2]; /* Such an s that x**s = y */ static unsigned powx_inv[256]; static const uint8_t poly = 0x1d; static void block_mulx (unsigned mul, char *buf, uint32_t size) { uint32_t i; uint8_t *p = (uint8_t *) buf; for (i = 0; i < size; i++, p++) if (*p) *p = powx[mul + powx_inv[*p]]; } static void block_mulx_xor (char *dst, unsigned mul, const char *buf, uint32_t size) { uint32_t i; const uint8_t *p = (const uint8_t *) buf; uint8_t *q = (uint8_t *) dst; for (i = 0; i < size; i++, p++, q++) if (*p) *q ^= powx[mul + powx_inv[*p]]; } static void raid6_init_table (void) { static int initialized = 0; unsigned i; if(initialized) return; uint8_t cur = 1; for (i = 0; i < 255; i++) { powx[i] = cur; powx[i + 255] = cur; powx_inv[cur] = i; if (cur & 0x80) cur = (cur << 1) ^ poly; else cur <<= 1; } initialized = 1; } static struct fsw_btrfs_recover_cache *get_recover_cache(struct fsw_btrfs_volume *vol, uint64_t device_id, uint64_t offset) { if(vol->rcache == NULL) { if(fsw_alloc_zero(sizeof(struct fsw_btrfs_recover_cache) * RECOVER_CACHE_SIZE, (void **)&vol->rcache) != FSW_SUCCESS) return NULL; } #ifdef __MAKEWITH_TIANO unsigned hash; #else UINTN hash; #endif DivU64x32Remainder(((device_id >> 32) | device_id | (offset >> 32) | offset), RECOVER_CACHE_SIZE, &hash); struct fsw_btrfs_recover_cache *rc = &vol->rcache[hash]; if(rc->buffer == NULL) { if(fsw_alloc_zero(vol->sectorsize, (void **)&rc->buffer) != FSW_SUCCESS) return NULL; } if(rc->device_id != device_id || rc->offset != offset) { rc->valid = FALSE; rc->device_id = device_id; rc->offset = offset; } return rc; } static fsw_status_t fsw_btrfs_read_logical (struct fsw_btrfs_volume *vol, uint64_t addr, void *buf, fsw_size_t size, int rdepth, int cache_level) { struct stripe_table *stripe_table = NULL; int challoc = 0; struct btrfs_chunk_item *chunk = NULL; fsw_status_t err = 0; while (size > 0) { uint8_t *ptr; struct btrfs_key *key; uint64_t csize; struct btrfs_key key_out; struct btrfs_key key_in; fsw_size_t chsize; uint64_t chaddr; err = 0; for (ptr = vol->bootstrap_mapping; ptr < vol->bootstrap_mapping + sizeof (vol->bootstrap_mapping) - sizeof (struct btrfs_key);) { key = (struct btrfs_key *) ptr; if (key->type != GRUB_BTRFS_ITEM_TYPE_CHUNK) break; chunk = (struct btrfs_chunk_item *) (key + 1); if (fsw_u64_le_swap (key->offset) <= addr && addr < fsw_u64_le_swap (key->offset) + fsw_u64_le_swap (chunk->size)) { goto chunk_found; } ptr += sizeof (*key) + sizeof (*chunk) + sizeof (struct btrfs_chunk_stripe) * fsw_u16_le_swap (chunk->nstripes); } key_in.object_id = fsw_u64_le_swap (GRUB_BTRFS_OBJECT_ID_CHUNK); key_in.type = GRUB_BTRFS_ITEM_TYPE_CHUNK; key_in.offset = fsw_u64_le_swap (addr); err = lower_bound (vol, &key_in, &key_out, vol->chunk_tree, &chaddr, &chsize, NULL, rdepth); if (err) return err; key = &key_out; if (key->type != GRUB_BTRFS_ITEM_TYPE_CHUNK || !(fsw_u64_le_swap (key->offset) <= addr)) { return FSW_VOLUME_CORRUPTED; } // "couldn't find the chunk descriptor"); chunk = AllocatePool (chsize); if (!chunk) { return FSW_OUT_OF_MEMORY; } challoc = 1; err = fsw_btrfs_read_logical (vol, chaddr, chunk, chsize, rdepth, cache_level < 5 ? cache_level+1 : 5); if (err) goto io_error; chunk_found: { #ifdef __MAKEWITH_GNUEFI #define UINTREM UINTN #else #undef DivU64x32 #define DivU64x32 DivU64x32Remainder #define UINTREM UINT32 #endif UINTREM stripen; UINTREM stripeq; UINTREM stripe_offset; uint64_t off = addr - fsw_u64_le_swap (key->offset); unsigned redundancy = 1; unsigned i; if (fsw_u64_le_swap (chunk->size) <= off) //"couldn't find the chunk descriptor"); goto volume_corrupted; uint16_t nstripes = fsw_u16_le_swap (chunk->nstripes); DPRINT(L"btrfs chunk 0x%lx+0xlx %d stripes (%d substripes) of %lx\n", fsw_u64_le_swap (key->offset), fsw_u64_le_swap (chunk->size), nstripes, fsw_u16_le_swap (chunk->nsubstripes), fsw_u64_le_swap (chunk->stripe_length)); /* gnu-efi has no DivU64x64Remainder, limited to DivU64x32 */ switch (fsw_u64_le_swap (chunk->type) & ~GRUB_BTRFS_CHUNK_TYPE_BITS_DONTCARE) { case GRUB_BTRFS_CHUNK_TYPE_SINGLE: { uint64_t stripe_length; stripe_length = DivU64x32 (fsw_u64_le_swap (chunk->size), nstripes, NULL); if(stripe_length >= 1ULL<<32) return FSW_VOLUME_CORRUPTED; stripen = DivU64x32 (off, (uint32_t)stripe_length, &stripe_offset); csize = (stripen + 1) * stripe_length - off; DPRINT(L"read_logical %d chunk_found single csize=%d\n", __LINE__, csize); break; } case GRUB_BTRFS_CHUNK_TYPE_DUPLICATED: case GRUB_BTRFS_CHUNK_TYPE_RAID1: { stripen = 0; stripe_offset = off; csize = fsw_u64_le_swap (chunk->size) - off; redundancy = 2; DPRINT(L"read_logical %d chunk_found dup/raid1 off=%lx csize=%d\n", __LINE__, stripe_offset, csize); break; } case GRUB_BTRFS_CHUNK_TYPE_RAID0: { uint64_t stripe_length = fsw_u64_le_swap (chunk->stripe_length); uint64_t middle, high; UINTREM low; if(stripe_length > 1UL<<30) return FSW_VOLUME_CORRUPTED; middle = DivU64x32 (off, (uint32_t)stripe_length, &low); high = DivU64x32 (middle, nstripes, &stripen); stripe_offset = low + fsw_u64_le_swap (chunk->stripe_length) * high; csize = fsw_u64_le_swap (chunk->stripe_length) - low; DPRINT(L"read_logical %d chunk_found raid0 csize=%d\n", __LINE__, csize); break; } case GRUB_BTRFS_CHUNK_TYPE_RAID10: { uint64_t stripe_length = fsw_u64_le_swap (chunk->stripe_length); uint64_t middle, high; UINTREM low; if(stripe_length > 1UL<<30) return FSW_VOLUME_CORRUPTED; middle = DivU64x32 (off, stripe_length, &low); high = DivU64x32 (middle, nstripes / fsw_u16_le_swap (chunk->nsubstripes), &stripen); stripen *= fsw_u16_le_swap (chunk->nsubstripes); redundancy = fsw_u16_le_swap (chunk->nsubstripes); stripe_offset = low + fsw_u64_le_swap (chunk->stripe_length) * high; csize = fsw_u64_le_swap (chunk->stripe_length) - low; DPRINT(L"read_logical %d chunk_found raid01 csize=%d\n", __LINE__, csize); break; } case GRUB_BTRFS_CHUNK_TYPE_RAID5: case GRUB_BTRFS_CHUNK_TYPE_RAID6: { uint64_t stripe_length = fsw_u64_le_swap (chunk->stripe_length); uint64_t middle, high; uint16_t nparities = (fsw_u64_le_swap(chunk->type) & GRUB_BTRFS_CHUNK_TYPE_RAID6) ? 2 : 1; UINTREM low; if(stripe_length > 1UL<<30 || nstripes > 255) goto volume_corrupted; middle = DivU64x32 (off, stripe_length, &low); high = DivU64x32 (middle, nstripes - nparities, &stripen); DivU64x32(high + stripen, nstripes, &stripen); if(nparities == 1) { stripeq = RAID5_TAG; } else { middle = DivU64x32(high + nstripes -1, nstripes, &stripeq); } redundancy = RAID5_TAG; stripe_offset = low + fsw_u64_le_swap (chunk->stripe_length) * high; csize = fsw_u64_le_swap (chunk->stripe_length) - low; DPRINT(L"read_logical %d chunk_found raid01 csize=%d\n", __LINE__, csize); break; } default: DPRINT (L"btrfs: unsupported RAID\n"); err = FSW_UNSUPPORTED; goto io_error; } if (csize == 0) //"couldn't find the chunk descriptor"); goto volume_corrupted; if (csize > (uint64_t) size) csize = size; if(redundancy < RAID5_TAG) { begin_direct_read: err = 0; for (i = 0; !err && i < redundancy; i++) { struct btrfs_chunk_stripe *stripe; uint64_t paddr; struct fsw_volume *dev; stripe = (struct btrfs_chunk_stripe *) (chunk + 1); /* Right now the redundancy handling is easy. With RAID5-like it will be more difficult. */ stripe += stripen + i; paddr = fsw_u64_le_swap (stripe->offset) + stripe_offset; DPRINT (L"btrfs: chunk 0x%lx+0x%lx (%d stripes (%d substripes) of %lx) stripe %lx maps to 0x%lx\n", fsw_u64_le_swap (key->offset), fsw_u64_le_swap (chunk->size), nstripes, fsw_u16_le_swap (chunk->nsubstripes), fsw_u64_le_swap (chunk->stripe_length), stripen, stripe->offset); DPRINT (L"btrfs: reading paddr 0x%lx for laddr 0x%lx\n", paddr, addr); dev = find_device (vol, stripe->device_id); if (!dev) continue; uint32_t off = paddr & (vol->sectorsize - 1); paddr >>= vol->sectorshift; uint64_t n = 0; while(n < csize) { char *buffer; err = fsw_block_get(dev, paddr, cache_level, (void **)&buffer); if(err) break; int s = vol->sectorsize - off; if(s > csize - n) s = csize - n; fsw_memcpy(buf+n, buffer+off, s); fsw_block_release(dev, paddr, (void *)buffer); n += s; off = 0; paddr++; } DPRINT (L"read logical: err %d csize %d got %d\n", err, csize, n); if(n>=csize) break; } if (i == redundancy) { if(do_rescan_once(vol) > 0) goto begin_direct_read; if(err == 0) goto volume_corrupted; } if (err) goto io_error; } else { // RAID5/RAID6 struct btrfs_chunk_stripe *stripe = (struct btrfs_chunk_stripe *) (chunk + 1); unsigned sectorsize = vol->sectorsize; { uint64_t sectormask = fsw_u64_le_swap(sectorsize - 1); for(i = 0; i < nstripes; i++) if(stripe[i].offset & sectormask) goto volume_corrupted; } struct fsw_volume *dev = find_device (vol, stripe[stripen].device_id); if(dev == NULL && do_rescan_once(vol) > 0) dev = find_device (vol, stripe[stripen].device_id); uint32_t posN = stripen; BOOLEAN is_raid5 = stripeq == RAID5_TAG; uint32_t dstripes = nstripes - (is_raid5 ? 1 : 2); uint64_t n = 0; uint32_t off = stripe_offset & (sectorsize - 1); stripe_offset >>= vol->sectorshift; while(n < csize) { int used_bytes = sectorsize - off; if(used_bytes > csize - n) used_bytes = csize - n; char *buffer; struct fsw_btrfs_recover_cache *rcache = NULL; uint64_t paddrN = (fsw_u64_le_swap (stripe[stripen].offset) >> vol->sectorshift) + stripe_offset; if(dev && !(err = fsw_block_get(dev, paddrN, cache_level, (void **)&buffer))) { // reading direct sector first fsw_memcpy(buf+n, buffer+off, used_bytes); fsw_block_release(dev, paddrN, (void *)buffer); } else if((rcache = get_recover_cache(vol, stripe[stripen].device_id, paddrN)) == NULL) { err = FSW_OUT_OF_MEMORY; goto io_error; } else if(rcache->valid) { // hit recovered cache fsw_memcpy(buf+n, rcache->buffer+off, used_bytes); } else { // need recover data if(!stripe_table) { // build&rotate(raid6) stripe table err = fsw_alloc_zero(sizeof(struct stripe_table) * nstripes, (void **)&stripe_table); if(err) goto io_error; unsigned dev_count = 0; uint32_t stripeI = is_raid5 ? 0 : (stripeq + 1) % nstripes; for(i = 0; i < nstripes; i++) { if(stripeI == stripen) { stripe_table[i].dev = NULL; posN = i; } else { stripe_table[i].off = fsw_u64_le_swap (stripe[stripeI].offset) >> vol->sectorshift; stripe_table[i].dev = find_device (vol, stripe[stripeI].device_id); if(stripe_table[i].dev == NULL && do_rescan_once(vol) > 0) stripe_table[i].dev = find_device (vol, stripe[stripeI].device_id); if(stripe_table[i].dev) dev_count ++; } stripeI = stripeI == nstripes -1 ? 0 : stripeI + 1; } if(dev_count < dstripes) // no enough dev, no recover available goto volume_corrupted; } // reading data uint32_t bad2 = RAID5_TAG; err = 0; for(i = 0; i < nstripes; i++) { stripe_table[i].ptr = NULL; if(i == posN) { // the target, first failed } else { err = stripe_table[i].dev == NULL ? FSW_IO_ERROR : fsw_block_get(stripe_table[i].dev, stripe_table[i].off + stripe_offset, cache_level, (void **)&(stripe_table[i].ptr)); if(err) { if(is_raid5 || bad2 != RAID5_TAG) // third failed break; // second failed bad2 = i; err = 0; } else { if(i == dstripes && bad2 == RAID5_TAG) // P ok & one failed, XOR recover & skip reading Q break; } } } char *pbuf; // only used by double data failed if(err) { // too many failed stripe_release(stripe_table, i, stripe_offset); } else if(bad2 == RAID5_TAG) { // single failed stripe_xor(rcache->buffer, stripe_table, i, sectorsize); stripe_release(stripe_table, i+1, stripe_offset); } else { raid6_init_table(); // calc Q fsw_memzero(rcache->buffer, sectorsize); for( i = 0; i < nstripes - 2; i++) { if(stripe_table[i].ptr) block_mulx_xor(rcache->buffer, i, stripe_table[i].ptr, sectorsize); } block_xor(rcache->buffer, /*Q*/stripe_table[nstripes - 1].ptr, sectorsize); if(bad2 == nstripes - 2) { // target & P failed block_mulx(255 - posN, rcache->buffer, sectorsize); } else if((err = fsw_alloc(sectorsize, (void **)&pbuf))==FSW_SUCCESS) { // double data failed unsigned int c = ((255 ^ posN) + (255 ^ powx_inv[(powx[bad2 + (posN ^ 255)] ^ 1)]))%255; block_mulx (c, rcache->buffer, sectorsize); stripe_xor(pbuf, stripe_table, dstripes, sectorsize); block_mulx_xor(rcache->buffer, (bad2+c)%255, pbuf, sectorsize); fsw_free(pbuf); } stripe_release(stripe_table, nstripes, stripe_offset); } if(err) goto io_error; fsw_memcpy(buf+n, rcache->buffer+off, used_bytes); rcache->valid = TRUE; } err = 0; n += used_bytes; off = 0; stripe_offset++; DPRINT (L"read logical: err %d csize %d got %d\n", err, csize, n); } } } size -= csize; buf = (uint8_t *) buf + csize; addr += csize; if (challoc && chunk) FreePool (chunk); challoc = 0; if(stripe_table) fsw_free(stripe_table); stripe_table = NULL; } return FSW_SUCCESS; volume_corrupted: err = FSW_VOLUME_CORRUPTED; io_error: if(challoc && chunk) FreePool (chunk); if(stripe_table) FreePool(stripe_table); return err; } static fsw_status_t fsw_btrfs_get_default_root(struct fsw_btrfs_volume *vol, uint64_t root_dir_objectid); static fsw_status_t fsw_btrfs_volume_mount(struct fsw_volume *volg) { struct btrfs_superblock sblock; struct fsw_btrfs_volume *vol = (struct fsw_btrfs_volume *)volg; struct fsw_btrfs_volume *master_out = NULL; struct fsw_string s; fsw_status_t err; int i; init_crc32c_table(); err = btrfs_read_superblock (volg, &sblock); if (err) return err; btrfs_set_superblock_info(vol, &sblock); if(vol->sectorshift == 0) return FSW_UNSUPPORTED; if(vol->num_devices >= BTRFS_MAX_NUM_DEVICES) return FSW_UNSUPPORTED; vol->is_master = master_uuid_add(vol, &master_out); /* already mounted via other device */ if(vol->is_master == 0) { #define FAKE_LABEL "btrfs.multi.device" s.type = FSW_STRING_TYPE_UTF8; s.size = s.len = sizeof(FAKE_LABEL)-1; s.data = FAKE_LABEL; err = fsw_strdup_coerce(&volg->label, volg->host_string_type, &s); if (err) return err; btrfs_add_multi_device(master_out, volg, &sblock); /* create fake root */ return fsw_dnode_create_root_with_tree(volg, 0, 0, &volg->root); } fsw_set_blocksize(volg, vol->sectorsize, vol->sectorsize); vol->n_devices_allocated = vol->num_devices; vol->rescan_once = vol->num_devices > 1; err = fsw_alloc(sizeof(struct fsw_btrfs_device_desc) * vol->n_devices_allocated, (void **)&vol->devices_attached); if (err) return err; vol->n_devices_attached = 1; vol->devices_attached[0].dev = volg; vol->devices_attached[0].id = sblock.this_device.device_id; for (i = 0; i < 0x100; i++) if (sblock.label[i] == 0) break; s.type = FSW_STRING_TYPE_UTF8; s.size = s.len = i; s.data = sblock.label; err = fsw_strdup_coerce(&volg->label, volg->host_string_type, &s); if (err) { FreePool (vol->devices_attached); vol->devices_attached = NULL; return err; } err = fsw_btrfs_get_default_root(vol, sblock.root_dir_objectid); if (err) { DPRINT(L"root not found\n"); FreePool (vol->devices_attached); vol->devices_attached = NULL; return err; } return FSW_SUCCESS; } static void fsw_btrfs_volume_free(struct fsw_volume *volg) { unsigned i; struct fsw_btrfs_volume *vol = (struct fsw_btrfs_volume *)volg; if (vol==NULL) return; if (vol->is_master) master_uuid_remove(vol); if(vol->devices_attached) { /* The device 0 is closed one layer upper. */ for (i = 1; i < vol->n_devices_attached; i++) { if(vol->devices_attached[i].dev) fsw_unmount (vol->devices_attached[i].dev); } FreePool (vol->devices_attached); } if(vol->extent) FreePool (vol->extent); if(vol->rcache) { for(i = 0; i < RECOVER_CACHE_SIZE; i++) if(vol->rcache->buffer) FreePool(vol->rcache->buffer); FreePool (vol->rcache); } } static fsw_status_t fsw_btrfs_volume_stat(struct fsw_volume *volg, struct fsw_volume_stat *sb) { struct fsw_btrfs_volume *vol = (struct fsw_btrfs_volume *)volg; sb->total_bytes = vol->total_bytes; sb->free_bytes = vol->bytes_used; return FSW_SUCCESS; } static fsw_status_t fsw_btrfs_read_inode (struct fsw_btrfs_volume *vol, struct btrfs_inode *inode, uint64_t num, uint64_t tree) { struct btrfs_key key_in, key_out; uint64_t elemaddr; fsw_size_t elemsize; fsw_status_t err; key_in.object_id = num; key_in.type = GRUB_BTRFS_ITEM_TYPE_INODE_ITEM; key_in.offset = 0; err = lower_bound (vol, &key_in, &key_out, tree, &elemaddr, &elemsize, NULL, 0); if (err) return err; if (num != key_out.object_id || key_out.type != GRUB_BTRFS_ITEM_TYPE_INODE_ITEM) return FSW_NOT_FOUND; return fsw_btrfs_read_logical (vol, elemaddr, inode, sizeof (*inode), 0, 2); } static fsw_status_t fsw_btrfs_dnode_fill(struct fsw_volume *volg, struct fsw_dnode *dnog) { struct fsw_btrfs_volume *vol = (struct fsw_btrfs_volume *)volg; struct fsw_btrfs_dnode *dno = (struct fsw_btrfs_dnode *)dnog; fsw_status_t err; uint32_t mode; /* slave device got empty root */ if (!vol->is_master) { dno->g.size = 0; dno->g.type = FSW_DNODE_TYPE_DIR; return FSW_SUCCESS; } if (dno->raw) return FSW_SUCCESS; dno->raw = AllocatePool(sizeof(struct btrfs_inode)); if(dno->raw == NULL) return FSW_OUT_OF_MEMORY; err = fsw_btrfs_read_inode(vol, dno->raw, dno->g.dnode_id, dno->g.tree_id); if (err) { FreePool(dno->raw); dno->raw = NULL; return err; } // get info from the inode dno->g.size = fsw_u64_le_swap(dno->raw->size); // TODO: check docs for 64-bit sized files mode = fsw_u32_le_swap(dno->raw->mode); if (S_ISREG(mode)) dno->g.type = FSW_DNODE_TYPE_FILE; else if (S_ISDIR(mode)) dno->g.type = FSW_DNODE_TYPE_DIR; else if (S_ISLNK(mode)) dno->g.type = FSW_DNODE_TYPE_SYMLINK; else dno->g.type = FSW_DNODE_TYPE_SPECIAL; return FSW_SUCCESS; } static void fsw_btrfs_dnode_free(struct fsw_volume *volg, struct fsw_dnode *dnog) { struct fsw_btrfs_dnode *dno = (struct fsw_btrfs_dnode *)dnog; if (dno->raw) FreePool(dno->raw); } static fsw_status_t fsw_btrfs_dnode_stat(struct fsw_volume *volg, struct fsw_dnode *dnog, struct fsw_dnode_stat *sb) { struct fsw_btrfs_dnode *dno = (struct fsw_btrfs_dnode *)dnog; /* slave device got empty root */ if(dno->raw == NULL) { sb->used_bytes = 0; fsw_store_time_posix(sb, FSW_DNODE_STAT_CTIME, 0); fsw_store_time_posix(sb, FSW_DNODE_STAT_ATIME, 0); fsw_store_time_posix(sb, FSW_DNODE_STAT_MTIME, 0); return FSW_SUCCESS; } sb->used_bytes = fsw_u64_le_swap(dno->raw->nbytes); fsw_store_time_posix(sb, FSW_DNODE_STAT_ATIME, fsw_u64_le_swap(dno->raw->atime.sec)); fsw_store_time_posix(sb, FSW_DNODE_STAT_CTIME, fsw_u64_le_swap(dno->raw->ctime.sec)); fsw_store_time_posix(sb, FSW_DNODE_STAT_MTIME, fsw_u64_le_swap(dno->raw->mtime.sec)); fsw_store_attr_posix(sb, fsw_u32_le_swap(dno->raw->mode)); return FSW_SUCCESS; } static fsw_ssize_t grub_btrfs_lzo_decompress(char *ibuf, fsw_size_t isize, grub_off_t off, char *obuf, fsw_size_t osize) { uint32_t total_size, cblock_size; fsw_size_t ret = 0; unsigned char buf[GRUB_BTRFS_LZO_BLOCK_SIZE]; char *ibuf0 = ibuf; #define fsw_get_unaligned32(x) (*(uint32_t *)(x)) total_size = fsw_u32_le_swap (fsw_get_unaligned32(ibuf)); ibuf += sizeof (total_size); if (isize < total_size) return -1; /* Jump forward to first block with requested data. */ while (off >= GRUB_BTRFS_LZO_BLOCK_SIZE) { /* Don't let following uint32_t cross the page boundary. */ if (((ibuf - ibuf0) & 0xffc) == 0xffc) ibuf = ((ibuf - ibuf0 + 3) & ~3) + ibuf0; cblock_size = fsw_u32_le_swap (fsw_get_unaligned32 (ibuf)); ibuf += sizeof (cblock_size); if (cblock_size > GRUB_BTRFS_LZO_BLOCK_MAX_CSIZE) return -1; off -= GRUB_BTRFS_LZO_BLOCK_SIZE; ibuf += cblock_size; } while (osize > 0) { lzo_uint usize = GRUB_BTRFS_LZO_BLOCK_SIZE; /* Don't let following uint32_t cross the page boundary. */ if (((ibuf - ibuf0) & 0xffc) == 0xffc) ibuf = ((ibuf - ibuf0 + 3) & ~3) + ibuf0; cblock_size = fsw_u32_le_swap (fsw_get_unaligned32 (ibuf)); ibuf += sizeof (cblock_size); if (cblock_size > GRUB_BTRFS_LZO_BLOCK_MAX_CSIZE) return -1; /* Block partially filled with requested data. */ if (off > 0 || osize < GRUB_BTRFS_LZO_BLOCK_SIZE) { fsw_size_t to_copy = GRUB_BTRFS_LZO_BLOCK_SIZE - off; if (to_copy > osize) to_copy = osize; if (lzo1x_decompress_safe ((lzo_bytep)ibuf, cblock_size, (lzo_bytep)buf, &usize, NULL) != 0) return -1; if (to_copy > usize) to_copy = usize; fsw_memcpy(obuf, buf + off, to_copy); osize -= to_copy; ret += to_copy; obuf += to_copy; ibuf += cblock_size; off = 0; continue; } /* Decompress whole block directly to output buffer. */ if (lzo1x_decompress_safe ((lzo_bytep)ibuf, cblock_size, (lzo_bytep)obuf, &usize, NULL) != 0) return -1; osize -= usize; ret += usize; obuf += usize; ibuf += cblock_size; } return ret; } #include "fsw_btrfs_zstd.h" typedef fsw_ssize_t (*decompressor_t)(char *ibuf, fsw_size_t isize, grub_off_t off, char *obuf, fsw_size_t osize); static decompressor_t btrfs_decompressor_table[GRUB_BTRFS_COMPRESSION_MAX] = { grub_zlib_decompress, grub_btrfs_lzo_decompress, zstd_decompress, }; static fsw_ssize_t btrfs_decompress(uint8_t comp, char *ibuf, fsw_size_t isize, grub_off_t off, char *obuf, fsw_size_t osize) { return btrfs_decompressor_table[comp-1](ibuf, isize, off, obuf, osize); } static fsw_status_t fsw_btrfs_get_extent(struct fsw_volume *volg, struct fsw_dnode *dnog, struct fsw_extent *extent) { struct fsw_btrfs_volume *vol = (struct fsw_btrfs_volume *)volg; uint64_t ino = dnog->dnode_id; uint64_t tree = dnog->tree_id; uint64_t pos0 = extent->log_start << vol->sectorshift; extent->type = FSW_EXTENT_TYPE_INVALID; extent->log_count = 1; uint64_t pos = pos0; fsw_size_t csize; fsw_status_t err; uint64_t extoff; char *buf = NULL; uint64_t count; /* slave device got empty root */ if (!vol->is_master) return FSW_NOT_FOUND; if (!vol->extent || vol->extstart > pos || vol->extino != ino || vol->exttree != tree || vol->extend <= pos) { struct btrfs_key key_in, key_out; uint64_t elemaddr; fsw_size_t elemsize; if(vol->extent) { FreePool (vol->extent); vol->extent = NULL; } key_in.object_id = ino; key_in.type = GRUB_BTRFS_ITEM_TYPE_EXTENT_ITEM; key_in.offset = fsw_u64_le_swap (pos); err = lower_bound (vol, &key_in, &key_out, tree, &elemaddr, &elemsize, NULL, 0); if (err) return FSW_VOLUME_CORRUPTED; if (key_out.object_id != ino || key_out.type != GRUB_BTRFS_ITEM_TYPE_EXTENT_ITEM) { return FSW_VOLUME_CORRUPTED; } if ((fsw_ssize_t) elemsize < ((char *) &vol->extent->inl - (char *) vol->extent)) { return FSW_VOLUME_CORRUPTED; } vol->extstart = fsw_u64_le_swap (key_out.offset); vol->extsize = elemsize; vol->extent = AllocatePool (elemsize); vol->extino = ino; vol->exttree = tree; if (!vol->extent) return FSW_OUT_OF_MEMORY; err = fsw_btrfs_read_logical (vol, elemaddr, vol->extent, elemsize, 0, 1); if (err) return err; vol->extend = vol->extstart + fsw_u64_le_swap (vol->extent->size); if (vol->extent->type == GRUB_BTRFS_EXTENT_REGULAR && (char *) vol->extent + elemsize >= (char *) &vol->extent->filled + sizeof (vol->extent->filled)) vol->extend = vol->extstart + fsw_u64_le_swap (vol->extent->filled); DPRINT (L"btrfs: %lx +0x%lx\n", fsw_u64_le_swap (key_out.offset), fsw_u64_le_swap (vol->extent->size)); if (vol->extend <= pos) { return FSW_VOLUME_CORRUPTED; } } csize = vol->extend - pos; extoff = pos - vol->extstart; if (vol->extent->encryption ||vol->extent->encoding) { return FSW_UNSUPPORTED; } switch(vol->extent->compression) { case GRUB_BTRFS_COMPRESSION_LZO: case GRUB_BTRFS_COMPRESSION_ZLIB: case GRUB_BTRFS_COMPRESSION_ZSTD: case GRUB_BTRFS_COMPRESSION_NONE: break; default: return FSW_UNSUPPORTED; } count = ( csize + vol->sectorsize - 1) >> vol->sectorshift; switch (vol->extent->type) { case GRUB_BTRFS_EXTENT_INLINE: buf = AllocatePool( count << vol->sectorshift); if(!buf) return FSW_OUT_OF_MEMORY; if (vol->extent->compression == GRUB_BTRFS_COMPRESSION_NONE) fsw_memcpy (buf, vol->extent->inl + extoff, csize); else if (btrfs_decompress (vol->extent->compression, vol->extent->inl, vol->extsize - ((uint8_t *) vol->extent->inl - (uint8_t *) vol->extent), extoff, buf, csize) != (fsw_ssize_t) csize) { FreePool(buf); return FSW_VOLUME_CORRUPTED; } break; case GRUB_BTRFS_EXTENT_REGULAR: if (!vol->extent->laddr) break; if (vol->extent->compression == GRUB_BTRFS_COMPRESSION_NONE) { if( count > 64 ) { count = 64; csize = count << vol->sectorshift; } buf = AllocatePool( count << vol->sectorshift); if(!buf) return FSW_OUT_OF_MEMORY; err = fsw_btrfs_read_logical (vol, fsw_u64_le_swap (vol->extent->laddr) + fsw_u64_le_swap (vol->extent->offset) + extoff, buf, csize, 0, 0); if (err) { FreePool(buf); return err; } break; } if (vol->extent->compression > GRUB_BTRFS_COMPRESSION_MAX) return -FSW_VOLUME_CORRUPTED; { char *tmp; uint64_t zsize; fsw_ssize_t ret; zsize = fsw_u64_le_swap (vol->extent->compressed_size); tmp = AllocatePool (zsize); if (!tmp) return -FSW_OUT_OF_MEMORY; err = fsw_btrfs_read_logical (vol, fsw_u64_le_swap (vol->extent->laddr), tmp, zsize, 0, 0); if (err) { FreePool (tmp); return -FSW_VOLUME_CORRUPTED; } buf = AllocatePool( count << vol->sectorshift); if(!buf) { FreePool(tmp); return FSW_OUT_OF_MEMORY; } ret = btrfs_decompress ( vol->extent->compression, tmp, zsize, extoff + fsw_u64_le_swap (vol->extent->offset), buf, csize); FreePool (tmp); if (ret != (fsw_ssize_t) csize) { FreePool(tmp); return -FSW_VOLUME_CORRUPTED; } break; } break; default: return -FSW_VOLUME_CORRUPTED; } extent->log_count = count; if(buf) { if(csize < (count << vol->sectorshift)) fsw_memzero( buf + csize, (count << vol->sectorshift) - csize); extent->buffer = buf; extent->type = FSW_EXTENT_TYPE_BUFFER; } else { extent->buffer = NULL; extent->type = FSW_EXTENT_TYPE_SPARSE; } return FSW_SUCCESS; } static fsw_status_t fsw_btrfs_readlink(struct fsw_volume *volg, struct fsw_dnode *dnog, struct fsw_string *link_target) { struct fsw_btrfs_volume *vol = (struct fsw_btrfs_volume *)volg; struct fsw_btrfs_dnode *dno = (struct fsw_btrfs_dnode *)dnog; int i; fsw_status_t status; struct fsw_string s; char *tmp; if (dno->g.size > FSW_PATH_MAX) return FSW_VOLUME_CORRUPTED; tmp = AllocatePool(dno->g.size); if(!tmp) return FSW_OUT_OF_MEMORY; i = 0; do { struct fsw_extent extent; int size; extent.log_start = i; status = fsw_btrfs_get_extent(volg, dnog, &extent); if(status || extent.type != FSW_EXTENT_TYPE_BUFFER) { FreePool(tmp); if(extent.buffer) FreePool(extent.buffer); return FSW_VOLUME_CORRUPTED; } size = extent.log_count << vol->sectorshift; if(size > (dno->g.size - (i<<vol->sectorshift))) size = dno->g.size - (i<<vol->sectorshift); fsw_memcpy(tmp + (i<<vol->sectorshift), extent.buffer, size); FreePool(extent.buffer); i += extent.log_count; } while( (i << vol->sectorshift) < dno->g.size); s.type = FSW_STRING_TYPE_UTF8; s.size = s.len = (int)dno->g.size; s.data = tmp; status = fsw_strdup_coerce(link_target, volg->host_string_type, &s); FreePool(tmp); return FSW_SUCCESS; } static fsw_status_t fsw_btrfs_lookup_dir_item(struct fsw_btrfs_volume *vol, uint64_t tree_id, uint64_t object_id, struct fsw_string *lookup_name, struct btrfs_dir_item **direl_buf, struct btrfs_dir_item **direl_out ) { uint64_t elemaddr; fsw_size_t elemsize; fsw_size_t allocated = 0; struct btrfs_key key; struct btrfs_key key_out; struct btrfs_dir_item *cdirel; fsw_status_t err; *direl_buf = NULL; key.object_id = object_id; key.type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; key.offset = fsw_u64_le_swap (~grub_getcrc32c (1, lookup_name->data, lookup_name->size)); err = lower_bound (vol, &key, &key_out, tree_id, &elemaddr, &elemsize, NULL, 0); if (err) return err; if (key_cmp (&key, &key_out) != 0) return FSW_NOT_FOUND; if (elemsize > allocated) { allocated = 2 * elemsize; if(*direl_buf) FreePool (*direl_buf); *direl_buf = AllocatePool (allocated + 1); if (!*direl_buf) return FSW_OUT_OF_MEMORY; } err = fsw_btrfs_read_logical (vol, elemaddr, *direl_buf, elemsize, 0, 1); if (err) return err; for (cdirel = *direl_buf; (uint8_t *) cdirel - (uint8_t *) *direl_buf < (fsw_ssize_t) elemsize; cdirel = (void *) ((uint8_t *) (*direl_buf + 1) + fsw_u16_le_swap (cdirel->n) + fsw_u16_le_swap (cdirel->m))) { if (lookup_name->size == fsw_u16_le_swap (cdirel->n) && fsw_memeq (cdirel->name, lookup_name->data, lookup_name->size)) break; } if ((uint8_t *) cdirel - (uint8_t *) *direl_buf >= (fsw_ssize_t) elemsize) return FSW_NOT_FOUND; *direl_out = cdirel; return FSW_SUCCESS; } static fsw_status_t fsw_btrfs_get_root_tree( struct fsw_btrfs_volume *vol, struct btrfs_key *key_in, uint64_t *tree_out) { fsw_status_t err; struct btrfs_root_item ri; struct btrfs_key key_out; uint64_t elemaddr; fsw_size_t elemsize; err = lower_bound (vol, key_in, &key_out, vol->root_tree, &elemaddr, &elemsize, NULL, 0); if (err) return err; if (key_in->object_id != key_out.object_id || key_in->type != key_out.type) return FSW_NOT_FOUND; err = fsw_btrfs_read_logical (vol, elemaddr, &ri, sizeof (ri), 0, 1); if (err) return err; *tree_out = ri.tree; return FSW_SUCCESS; } static fsw_status_t fsw_btrfs_get_sub_dnode( struct fsw_btrfs_volume *vol, struct fsw_btrfs_dnode *dno, struct btrfs_dir_item *cdirel, struct fsw_string *name, struct fsw_dnode **child_dno_out) { fsw_status_t err; int child_type; uint64_t tree_id = dno->g.tree_id; uint64_t child_id; switch (cdirel->key.type) { case GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM: err = fsw_btrfs_get_root_tree (vol, &cdirel->key, &tree_id); if (err) return err; child_type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY; child_id = fsw_u64_le_swap(GRUB_BTRFS_OBJECT_ID_CHUNK); break; case GRUB_BTRFS_ITEM_TYPE_INODE_ITEM: child_type = cdirel->type; child_id = cdirel->key.object_id; break; default: DPRINT (L"btrfs: unrecognised object type 0x%x", cdirel->key.type); return FSW_VOLUME_CORRUPTED; } switch(child_type) { case GRUB_BTRFS_DIR_ITEM_TYPE_REGULAR: child_type = FSW_DNODE_TYPE_FILE; break; case GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY: child_type = FSW_DNODE_TYPE_DIR; break; case GRUB_BTRFS_DIR_ITEM_TYPE_SYMLINK: child_type = FSW_DNODE_TYPE_SYMLINK; break; default: child_type = FSW_DNODE_TYPE_SPECIAL; break; } return fsw_dnode_create_with_tree(&dno->g, tree_id, child_id, child_type, name, child_dno_out); } static fsw_status_t fsw_btrfs_dir_lookup(struct fsw_volume *volg, struct fsw_dnode *dnog, struct fsw_string *lookup_name, struct fsw_dnode **child_dno_out) { struct fsw_btrfs_volume *vol = (struct fsw_btrfs_volume *)volg; struct fsw_btrfs_dnode *dno = (struct fsw_btrfs_dnode *)dnog; fsw_status_t err; struct fsw_string s; *child_dno_out = NULL; /* slave device got empty root */ if (!vol->is_master) return FSW_NOT_FOUND; err = fsw_strdup_coerce(&s, FSW_STRING_TYPE_UTF8, lookup_name); if(err) return err; /* treat '...' under root as top root */ if(dnog == volg->root && s.size == 3 && ((char *)s.data)[0]=='.' && ((char *)s.data)[1]=='.' && ((char *)s.data)[2]=='.') { fsw_strfree (&s); if(dnog->tree_id == vol->top_tree) { fsw_dnode_retain(dnog); *child_dno_out = dnog; return FSW_SUCCESS; } return fsw_dnode_create_with_tree(dnog, vol->top_tree, fsw_u64_le_swap(GRUB_BTRFS_OBJECT_ID_CHUNK), FSW_DNODE_TYPE_DIR, lookup_name, child_dno_out); } struct btrfs_dir_item *direl=NULL, *cdirel; err = fsw_btrfs_lookup_dir_item(vol, dnog->tree_id, dnog->dnode_id, &s, &direl, &cdirel); if(!err) err = fsw_btrfs_get_sub_dnode(vol, dno, cdirel, lookup_name, child_dno_out); if(direl) FreePool (direl); fsw_strfree (&s); return err; } static fsw_status_t fsw_btrfs_get_default_root(struct fsw_btrfs_volume *vol, uint64_t root_dir_objectid) { fsw_status_t err; struct fsw_string s; struct btrfs_dir_item *direl=NULL, *cdirel; struct btrfs_key top_root_key; /* Get to top tree id */ top_root_key.object_id = fsw_u64_le_swap(5UL); top_root_key.type = GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM; top_root_key.offset = -1LL; err = fsw_btrfs_get_root_tree (vol, &top_root_key, &vol->top_tree); if (err) return err; uint64_t default_tree_id = vol->top_tree; s.type = FSW_STRING_TYPE_UTF8; s.data = "default"; s.size = 7; err = fsw_btrfs_lookup_dir_item(vol, vol->root_tree, root_dir_objectid, &s, &direl, &cdirel); /* if "default" is failed or invalid, use top tree */ if (!err && /* failed */ cdirel->type == GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY && /* not dir */ cdirel->key.type == GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM && /* not tree */ cdirel->key.object_id != fsw_u64_le_swap(5UL)) fsw_btrfs_get_root_tree (vol, &cdirel->key, &default_tree_id); err = fsw_dnode_create_root_with_tree(&vol->g, default_tree_id, fsw_u64_le_swap (GRUB_BTRFS_OBJECT_ID_CHUNK), &vol->g.root); if (direl) FreePool (direl); return err; } static fsw_status_t fsw_btrfs_dir_read(struct fsw_volume *volg, struct fsw_dnode *dnog, struct fsw_shandle *shand, struct fsw_dnode **child_dno_out) { struct fsw_btrfs_volume *vol = (struct fsw_btrfs_volume *)volg; struct fsw_btrfs_dnode *dno = (struct fsw_btrfs_dnode *)dnog; fsw_status_t err; struct btrfs_key key_in, key_out; uint64_t elemaddr; fsw_size_t elemsize; fsw_size_t allocated = 0; struct btrfs_dir_item *direl = NULL; struct fsw_btrfs_leaf_descriptor desc; int r = 0; uint64_t tree = dnog->tree_id; /* slave device got empty root */ if (!vol->is_master) return FSW_NOT_FOUND; key_in.object_id = dnog->dnode_id; key_in.type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; key_in.offset = shand->pos; if((int64_t)key_in.offset == -1LL) { return FSW_NOT_FOUND; } err = lower_bound (vol, &key_in, &key_out, tree, &elemaddr, &elemsize, &desc, 0); if (err) { return err; } DPRINT(L"key_in %lx:%x:%lx out %lx:%x:%lx elem %lx+%lx\n", key_in.object_id, key_in.type, key_in.offset, key_out.object_id, key_out.type, key_out.offset, elemaddr, elemsize); if (key_out.type != GRUB_BTRFS_ITEM_TYPE_DIR_ITEM || key_out.object_id != key_in.object_id) { r = next (vol, &desc, &elemaddr, &elemsize, &key_out); if (r <= 0) goto out; DPRINT(L"next out %lx:%x:%lx\n", key_out.object_id, key_out.type, key_out.offset, elemaddr, elemsize); } if (key_out.type == GRUB_BTRFS_ITEM_TYPE_DIR_ITEM && key_out.object_id == key_in.object_id && fsw_u64_le_swap(key_out.offset) <= fsw_u64_le_swap(key_in.offset)) { r = next (vol, &desc, &elemaddr, &elemsize, &key_out); if (r <= 0) goto out; DPRINT(L"next out %lx:%x:%lx\n", key_out.object_id, key_out.type, key_out.offset, elemaddr, elemsize); } do { struct btrfs_dir_item *cdirel; if (key_out.type != GRUB_BTRFS_ITEM_TYPE_DIR_ITEM || key_out.object_id != key_in.object_id) { r = 0; break; } if (elemsize > allocated) { allocated = 2 * elemsize; if(direl) FreePool (direl); direl = AllocatePool (allocated + 1); if (!direl) { r = -FSW_OUT_OF_MEMORY; break; } } err = fsw_btrfs_read_logical (vol, elemaddr, direl, elemsize, 0, 1); if (err) { r = -err; break; } for (cdirel = direl; (uint8_t *) cdirel - (uint8_t *) direl < (fsw_ssize_t) elemsize; cdirel = (void *) ((uint8_t *) (direl + 1) + fsw_u16_le_swap (cdirel->n) + fsw_u16_le_swap (cdirel->m))) { struct fsw_string s; s.type = FSW_STRING_TYPE_UTF8; s.size = s.len = fsw_u16_le_swap (cdirel->n); s.data = cdirel->name; DPRINT(L"item key %lx:%x%lx, type %lx, namelen=%lx\n", cdirel->key.object_id, cdirel->key.type, cdirel->key.offset, cdirel->type, s.size); if(!err) { err = fsw_btrfs_get_sub_dnode(vol, dno, cdirel, &s, child_dno_out); if(direl) FreePool (direl); free_iterator (&desc); shand->pos = key_out.offset; return FSW_SUCCESS; } } r = next (vol, &desc, &elemaddr, &elemsize, &key_out); DPRINT(L"next2 out %lx:%x:%lx\n", key_out.object_id, key_out.type, key_out.offset, elemaddr, elemsize); } while (r > 0); out: if(direl) FreePool (direl); free_iterator (&desc); r = r < 0 ? -r : FSW_NOT_FOUND; return r; } // // Dispatch Table // struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(btrfs) = { { FSW_STRING_TYPE_UTF8, 5, 5, "btrfs" }, sizeof(struct fsw_btrfs_volume), sizeof(struct fsw_btrfs_dnode), fsw_btrfs_volume_mount, fsw_btrfs_volume_free, fsw_btrfs_volume_stat, fsw_btrfs_dnode_fill, fsw_btrfs_dnode_free, fsw_btrfs_dnode_stat, fsw_btrfs_get_extent, fsw_btrfs_dir_lookup, fsw_btrfs_dir_read, fsw_btrfs_readlink, }; ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/fsw_ext4.c����������������������������������������������������������������0000664�0001750�0001750�00000066522�13112025560�017576� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/** * \file fsw_ext4.c * ext4 file system driver code. */ /*- * Copyright (c) 2012 Stefan Agner * Portions Copyright (c) 2006 Christoph Pfisterer * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "fsw_ext4.h" // functions static fsw_status_t fsw_ext4_volume_mount(struct fsw_ext4_volume *vol); static void fsw_ext4_volume_free(struct fsw_ext4_volume *vol); static fsw_status_t fsw_ext4_volume_stat(struct fsw_ext4_volume *vol, struct fsw_volume_stat *sb); static fsw_status_t fsw_ext4_dnode_fill(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno); static void fsw_ext4_dnode_free(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno); static fsw_status_t fsw_ext4_dnode_stat(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno, struct fsw_dnode_stat *sb); static fsw_status_t fsw_ext4_get_extent(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno, struct fsw_extent *extent); static fsw_status_t fsw_ext4_get_by_blkaddr(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno, struct fsw_extent *extent); static fsw_status_t fsw_ext4_get_by_extent(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno, struct fsw_extent *extent); static fsw_status_t fsw_ext4_dir_lookup(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno, struct fsw_string *lookup_name, struct fsw_ext4_dnode **child_dno); static fsw_status_t fsw_ext4_dir_read(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno, struct fsw_shandle *shand, struct fsw_ext4_dnode **child_dno); static fsw_status_t fsw_ext4_read_dentry(struct fsw_shandle *shand, struct ext4_dir_entry *entry); static fsw_status_t fsw_ext4_readlink(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno, struct fsw_string *link); // // Dispatch Table // struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(ext4) = { { FSW_STRING_TYPE_ISO88591, 4, 4, "ext4" }, sizeof(struct fsw_ext4_volume), sizeof(struct fsw_ext4_dnode), fsw_ext4_volume_mount, fsw_ext4_volume_free, fsw_ext4_volume_stat, fsw_ext4_dnode_fill, fsw_ext4_dnode_free, fsw_ext4_dnode_stat, fsw_ext4_get_extent, fsw_ext4_dir_lookup, fsw_ext4_dir_read, fsw_ext4_readlink, }; static __inline int test_root(fsw_u32 a, int b) { fsw_u32 num = b; while (a > num) num *= b; return num == a; } static int fsw_ext4_group_sparse(fsw_u32 group) { if (group <= 1) return 1; if (!(group & 1)) return 0; return (test_root(group, 7) || test_root(group, 5) || test_root(group, 3)); } /* calculate the first block number of the group */ static __inline fsw_u64 fsw_ext4_group_first_block_no(struct ext4_super_block *sb, fsw_u32 group_no) { return group_no * (fsw_u64)EXT4_BLOCKS_PER_GROUP(sb) + sb->s_first_data_block; } /** * Mount an ext4 volume. Reads the superblock and constructs the * root directory dnode. */ static fsw_status_t fsw_ext4_volume_mount(struct fsw_ext4_volume *vol) { fsw_status_t status; void *buffer; fsw_u32 blocksize; fsw_u32 groupcnt, groupno, gdesc_per_block, gdesc_index, metabg_of_gdesc; fsw_u64 gdesc_bno; struct ext4_group_desc *gdesc; int i; struct fsw_string s; // allocate memory to keep the superblock around status = fsw_alloc(sizeof(struct ext4_super_block), &vol->sb); if (status) return status; // read the superblock into its buffer fsw_set_blocksize(vol, EXT4_SUPERBLOCK_BLOCKSIZE, EXT4_SUPERBLOCK_BLOCKSIZE); status = fsw_block_get(vol, EXT4_SUPERBLOCK_BLOCKNO, 0, &buffer); if (status) return status; fsw_memcpy(vol->sb, buffer, sizeof(struct ext4_super_block)); fsw_block_release(vol, EXT4_SUPERBLOCK_BLOCKNO, buffer); // check the superblock if (vol->sb->s_magic != EXT4_SUPER_MAGIC) return FSW_UNSUPPORTED; if (vol->sb->s_rev_level != EXT4_GOOD_OLD_REV && vol->sb->s_rev_level != EXT4_DYNAMIC_REV) return FSW_UNSUPPORTED; FSW_MSG_DEBUG((FSW_MSGSTR("fsw_ext4_volume_mount: Incompat flag %x\n"), vol->sb->s_feature_incompat)); if (vol->sb->s_rev_level == EXT4_DYNAMIC_REV && (vol->sb->s_feature_incompat & ~(EXT4_FEATURE_INCOMPAT_FILETYPE | EXT4_FEATURE_INCOMPAT_RECOVER | EXT4_FEATURE_INCOMPAT_EXTENTS | EXT4_FEATURE_INCOMPAT_FLEX_BG | EXT4_FEATURE_INCOMPAT_64BIT | EXT4_FEATURE_INCOMPAT_META_BG))) return FSW_UNSUPPORTED; if (vol->sb->s_rev_level == EXT4_DYNAMIC_REV && (vol->sb->s_feature_incompat & EXT4_FEATURE_INCOMPAT_RECOVER)) { FSW_MSG_DEBUG((FSW_MSGSTR("fsw_ext4_volume_mount: This ext3 file system needs recovery\n"))); // Print(L"Ext4 WARNING: This file system needs recovery, trying to use it anyway.\n"); } blocksize = EXT4_BLOCK_SIZE(vol->sb); if (blocksize < EXT4_MIN_BLOCK_SIZE || blocksize > EXT4_MAX_BLOCK_SIZE) return FSW_UNSUPPORTED; // set real blocksize fsw_set_blocksize(vol, blocksize, blocksize); // get other info from superblock vol->ind_bcnt = EXT4_ADDR_PER_BLOCK(vol->sb); vol->dind_bcnt = vol->ind_bcnt * vol->ind_bcnt; vol->inode_size = vol->sb->s_inode_size;//EXT4_INODE_SIZE(vol->sb); for (i = 0; i < 16; i++) if (vol->sb->s_volume_name[i] == 0) break; s.type = FSW_STRING_TYPE_ISO88591; s.size = s.len = i; s.data = vol->sb->s_volume_name; status = fsw_strdup_coerce(&vol->g.label, vol->g.host_string_type, &s); if (status) return status; // size of group descriptor depends on feature.... if (!(vol->sb->s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT)) { // Default minimal group descriptor size... (this might not be set in old ext2 filesystems, therefor set it!) vol->sb->s_desc_size = EXT4_MIN_DESC_SIZE; } // Calculate group descriptor count the way the kernel does it... groupcnt = (vol->sb->s_blocks_count_lo - vol->sb->s_first_data_block + vol->sb->s_blocks_per_group - 1) / vol->sb->s_blocks_per_group; // Descriptors in one block... s_desc_size needs to be set! (Usually 128 since normal block // descriptors are 32 byte and block size is 4096) gdesc_per_block = EXT4_DESC_PER_BLOCK(vol->sb); // Read the group descriptors to get inode table offsets status = fsw_alloc(sizeof(fsw_u64) * groupcnt, &vol->inotab_bno); if (status) return status; // Loop through all block group descriptors in order to get inode table locations for (groupno = 0; groupno < groupcnt; groupno++) { // Calculate the block number which contains the block group descriptor we look for if(vol->sb->s_feature_incompat & EXT4_FEATURE_INCOMPAT_META_BG && groupno >= vol->sb->s_first_meta_bg) { // If option meta_bg is set, the block group descriptor is in meta block group... metabg_of_gdesc = (fsw_u32)(groupno / gdesc_per_block) * gdesc_per_block; gdesc_bno = fsw_ext4_group_first_block_no(vol->sb, metabg_of_gdesc); // We need to know if the block group in questition has a super block, if yes, the // block group descriptors are in the next block number if(!(vol->sb->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER) || fsw_ext4_group_sparse(metabg_of_gdesc)) gdesc_bno += 1; } else { // All group descriptors follow the super block (+1) gdesc_bno = (vol->sb->s_first_data_block + 1) + groupno / gdesc_per_block; } gdesc_index = groupno % gdesc_per_block; // Get block if necessary... status = fsw_block_get(vol, gdesc_bno, 1, (void **)&buffer); if (status) return status; // Get group descriptor table and block number of inode table... gdesc = (struct ext4_group_desc *)((char *)buffer + gdesc_index * vol->sb->s_desc_size); vol->inotab_bno[groupno] = gdesc->bg_inode_table_lo; if (vol->sb->s_desc_size >= EXT4_MIN_DESC_SIZE_64BIT) vol->inotab_bno[groupno] |= (fsw_u64)gdesc->bg_inode_table_hi << 32; fsw_block_release(vol, gdesc_bno, buffer); } // setup the root dnode status = fsw_dnode_create_root(vol, EXT4_ROOT_INO, &vol->g.root); if (status) return status; FSW_MSG_DEBUG((FSW_MSGSTR("fsw_ext4_volume_mount: success, blocksize %d\n"), blocksize)); return FSW_SUCCESS; } /** * Free the volume data structure. Called by the core after an unmount or after * an unsuccessful mount to release the memory used by the file system type specific * part of the volume structure. */ static void fsw_ext4_volume_free(struct fsw_ext4_volume *vol) { if (vol->sb) fsw_free(vol->sb); if (vol->inotab_bno) fsw_free(vol->inotab_bno); } /** * Get in-depth information on a volume. */ static fsw_status_t fsw_ext4_volume_stat(struct fsw_ext4_volume *vol, struct fsw_volume_stat *sb) { fsw_u64 count; count = vol->sb->s_blocks_count_lo; if (vol->sb->s_desc_size >= EXT4_MIN_DESC_SIZE_64BIT) count |= (fsw_u64)vol->sb->s_blocks_count_hi << 32; sb->total_bytes = count * vol->g.log_blocksize; count = vol->sb->s_free_blocks_count_lo; if (vol->sb->s_desc_size >= EXT4_MIN_DESC_SIZE_64BIT) count |= (fsw_u64)vol->sb->s_free_blocks_count_hi << 32; sb->free_bytes = count * vol->g.log_blocksize; return FSW_SUCCESS; } /** * Get full information on a dnode from disk. This function is called by the core * whenever it needs to access fields in the dnode structure that may not * be filled immediately upon creation of the dnode. In the case of ext4, we * delay fetching of the inode structure until dnode_fill is called. The size and * type fields are invalid until this function has been called. */ static fsw_status_t fsw_ext4_dnode_fill(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno) { fsw_status_t status; fsw_u32 groupno, ino_in_group, ino_index; fsw_u64 ino_bno; fsw_u8 *buffer; if (dno->raw) return FSW_SUCCESS; // read the inode block groupno = (fsw_u32) (dno->g.dnode_id - 1) / vol->sb->s_inodes_per_group; ino_in_group = (fsw_u32) (dno->g.dnode_id - 1) % vol->sb->s_inodes_per_group; ino_bno = vol->inotab_bno[groupno] + ino_in_group / (vol->g.phys_blocksize / vol->inode_size); ino_index = ino_in_group % (vol->g.phys_blocksize / vol->inode_size); status = fsw_block_get(vol, ino_bno, 2, (void **)&buffer); if (status) return status; // keep our inode around status = fsw_memdup((void **)&dno->raw, buffer + ino_index * vol->inode_size, vol->inode_size); fsw_block_release(vol, ino_bno, buffer); if (status) return status; // get info from the inode dno->g.size = dno->raw->i_size_lo; // TODO: check docs for 64-bit sized files if (S_ISREG(dno->raw->i_mode)) dno->g.type = FSW_DNODE_TYPE_FILE; else if (S_ISDIR(dno->raw->i_mode)) dno->g.type = FSW_DNODE_TYPE_DIR; else if (S_ISLNK(dno->raw->i_mode)) dno->g.type = FSW_DNODE_TYPE_SYMLINK; else dno->g.type = FSW_DNODE_TYPE_SPECIAL; FSW_MSG_DEBUG((FSW_MSGSTR("fsw_ext4_dnode_fill: inode flags %x\n"), dno->raw->i_flags)); FSW_MSG_DEBUG((FSW_MSGSTR("fsw_ext4_dnode_fill: i_mode %x\n"), dno->raw->i_mode)); return FSW_SUCCESS; } /** * Free the dnode data structure. Called by the core when deallocating a dnode * structure to release the memory used by the file system type specific part * of the dnode structure. */ static void fsw_ext4_dnode_free(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno) { if (dno->raw) fsw_free(dno->raw); } /** * Get in-depth information on a dnode. The core makes sure that fsw_ext4_dnode_fill * has been called on the dnode before this function is called. Note that some * data is not directly stored into the structure, but passed to a host-specific * callback that converts it to the host-specific format. */ static fsw_status_t fsw_ext4_dnode_stat(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno, struct fsw_dnode_stat *sb) { sb->used_bytes = dno->raw->i_blocks_lo * EXT4_BLOCK_SIZE(vol->sb); // very, very strange... fsw_store_time_posix(sb, FSW_DNODE_STAT_CTIME, dno->raw->i_ctime); fsw_store_time_posix(sb, FSW_DNODE_STAT_ATIME, dno->raw->i_atime); fsw_store_time_posix(sb, FSW_DNODE_STAT_MTIME, dno->raw->i_mtime); fsw_store_attr_posix(sb, dno->raw->i_mode); return FSW_SUCCESS; } /** * Retrieve file data mapping information. This function is called by the core when * fsw_shandle_read needs to know where on the disk the required piece of the file's * data can be found. The core makes sure that fsw_ext4_dnode_fill has been called * on the dnode before. Our task here is to get the physical disk block number for * the requested logical block number. * * The ext4 file system usually uses extents do to store those disk block numbers. * However, since ext4 is backward compatible, depending on inode flags the old direct * and indirect addressing scheme can still be in place... */ static fsw_status_t fsw_ext4_get_extent(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno, struct fsw_extent *extent) { // Preconditions: The caller has checked that the requested logical block // is within the file's size. The dnode has complete information, i.e. // fsw_ext4_dnode_read_info was called successfully on it. FSW_MSG_DEBUG((FSW_MSGSTR("fsw_ext4_get_extent: inode %d, block %d\n"), dno->g.dnode_id, extent->log_start)); extent->type = FSW_EXTENT_TYPE_PHYSBLOCK; extent->log_count = 1; if(dno->raw->i_flags & 1 << EXT4_INODE_EXTENTS) { FSW_MSG_DEBUG((FSW_MSGSTR("fsw_ext4_get_extent: inode %d uses extents\n"), dno->g.dnode_id)); return fsw_ext4_get_by_extent(vol, dno, extent); } else { FSW_MSG_DEBUG((FSW_MSGSTR("fsw_ext4_get_extent: inode %d uses direct/indirect block addressing\n"), dno->g.dnode_id)); return fsw_ext4_get_by_blkaddr(vol, dno, extent); } } /** * New ext4 extents... */ static fsw_status_t fsw_ext4_get_by_extent(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno, struct fsw_extent *extent) { fsw_status_t status; fsw_u32 bno, buf_offset; int ext_cnt; void *buffer; struct ext4_extent_header *ext4_extent_header; struct ext4_extent_idx *ext4_extent_idx; struct ext4_extent *ext4_extent; // Logical block requested by core... bno = extent->log_start; // First buffer is the i_block field from inode... buffer = (void *)dno->raw->i_block; buf_offset = 0; while(1) { ext4_extent_header = (struct ext4_extent_header *)((char *)buffer + buf_offset); buf_offset += sizeof(struct ext4_extent_header); FSW_MSG_DEBUG((FSW_MSGSTR("fsw_ext4_get_by_extent: extent header with %d entries\n"), ext4_extent_header->eh_entries)); if(ext4_extent_header->eh_magic != EXT4_EXT_MAGIC) return FSW_VOLUME_CORRUPTED; for(ext_cnt = 0;ext_cnt < ext4_extent_header->eh_entries;ext_cnt++) { if(ext4_extent_header->eh_depth == 0) { // Leaf node, the header follows actual extents ext4_extent = (struct ext4_extent *)((char *)buffer + buf_offset); buf_offset += sizeof(struct ext4_extent); FSW_MSG_DEBUG((FSW_MSGSTR("fsw_ext4_get_by_extent: extent node cover %d...\n"), ext4_extent->ee_block)); // Is the requested block in this extent? if(bno >= ext4_extent->ee_block && bno < ext4_extent->ee_block + ext4_extent->ee_len) { extent->phys_start = ((fsw_u64)ext4_extent->ee_start_hi << 32) | ext4_extent->ee_start_lo; extent->phys_start += (bno - ext4_extent->ee_block); extent->log_count = ext4_extent->ee_len - (bno - ext4_extent->ee_block); return FSW_SUCCESS; } } else { FSW_MSG_DEBUG((FSW_MSGSTR("fsw_ext4_get_by_extent: index extents, depth %d\n"), ext4_extent_header->eh_depth)); ext4_extent_idx = (struct ext4_extent_idx *)((char *)buffer + buf_offset); buf_offset += sizeof(struct ext4_extent_idx); FSW_MSG_DEBUG((FSW_MSGSTR("fsw_ext4_get_by_extent: index node covers block %d...\n"), ext4_extent_idx->ei_block)); if(bno >= ext4_extent_idx->ei_block) { // Follow extent tree... fsw_u64 phys_bno = ((fsw_u64)ext4_extent_idx->ei_leaf_hi << 32) | ext4_extent_idx->ei_leaf_lo; status = fsw_block_get(vol, phys_bno, 1, (void **)&buffer); if (status) return status; buf_offset = 0; break; } } } } return FSW_NOT_FOUND; } /** * The ext2/ext3 file system does not use extents, but stores a list of block numbers * using the usual direct, indirect, double-indirect, triple-indirect scheme. To * optimize access, this function checks if the following file blocks are mapped * to consecutive disk blocks and returns a combined extent if possible. */ static fsw_status_t fsw_ext4_get_by_blkaddr(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno, struct fsw_extent *extent) { fsw_status_t status; fsw_u32 bno, release_bno, buf_bcnt, file_bcnt; int path[5], i; fsw_u32 *buffer; bno = extent->log_start; // try direct block pointers in the inode if (bno < EXT4_NDIR_BLOCKS) { path[0] = bno; path[1] = -1; } else { bno -= EXT4_NDIR_BLOCKS; // try indirect block if (bno < vol->ind_bcnt) { path[0] = EXT4_IND_BLOCK; path[1] = bno; path[2] = -1; } else { bno -= vol->ind_bcnt; // try double-indirect block if (bno < vol->dind_bcnt) { path[0] = EXT4_DIND_BLOCK; path[1] = bno / vol->ind_bcnt; path[2] = bno % vol->ind_bcnt; path[3] = -1; } else { bno -= vol->dind_bcnt; // use the triple-indirect block path[0] = EXT4_TIND_BLOCK; path[1] = bno / vol->dind_bcnt; path[2] = (bno / vol->ind_bcnt) % vol->ind_bcnt; path[3] = bno % vol->ind_bcnt; path[4] = -1; } } } // follow the indirection path buffer = dno->raw->i_block; buf_bcnt = EXT4_NDIR_BLOCKS; release_bno = 0; for (i = 0; ; i++) { bno = buffer[path[i]]; if (bno == 0) { extent->type = FSW_EXTENT_TYPE_SPARSE; if (release_bno) fsw_block_release(vol, release_bno, buffer); return FSW_SUCCESS; } if (path[i+1] < 0) break; if (release_bno) fsw_block_release(vol, release_bno, buffer); status = fsw_block_get(vol, bno, 1, (void **)&buffer); if (status) return status; release_bno = bno; buf_bcnt = vol->ind_bcnt; } extent->phys_start = bno; // check if the following blocks can be aggregated into one extent file_bcnt = (fsw_u32)((dno->g.size + vol->g.log_blocksize - 1) & (vol->g.log_blocksize - 1)); while (path[i] + extent->log_count < buf_bcnt && // indirect block has more block pointers extent->log_start + extent->log_count < file_bcnt) { // file has more blocks if (buffer[path[i] + extent->log_count] == buffer[path[i] + extent->log_count - 1] + 1) extent->log_count++; else break; } if (release_bno) fsw_block_release(vol, release_bno, buffer); return FSW_SUCCESS; } /** * Lookup a directory's child dnode by name. This function is called on a directory * to retrieve the directory entry with the given name. A dnode is constructed for * this entry and returned. The core makes sure that fsw_ext4_dnode_fill has been called * and the dnode is actually a directory. */ static fsw_status_t fsw_ext4_dir_lookup(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno, struct fsw_string *lookup_name, struct fsw_ext4_dnode **child_dno_out) { fsw_status_t status; struct fsw_shandle shand; fsw_u32 child_ino; struct ext4_dir_entry entry; struct fsw_string entry_name; // Preconditions: The caller has checked that dno is a directory node. entry_name.type = FSW_STRING_TYPE_ISO88591; // setup handle to read the directory status = fsw_shandle_open(dno, &shand); if (status) return status; // scan the directory for the file child_ino = 0; while (child_ino == 0) { // read next entry status = fsw_ext4_read_dentry(&shand, &entry); if (status) goto errorexit; if (entry.inode == 0) { // end of directory reached status = FSW_NOT_FOUND; goto errorexit; } // compare name entry_name.len = entry_name.size = entry.name_len; entry_name.data = entry.name; if (fsw_streq(lookup_name, &entry_name)) { child_ino = entry.inode; break; } } // setup a dnode for the child item status = fsw_dnode_create(dno, child_ino, FSW_DNODE_TYPE_UNKNOWN, &entry_name, child_dno_out); errorexit: fsw_shandle_close(&shand); return status; } /** * Get the next directory entry when reading a directory. This function is called during * directory iteration to retrieve the next directory entry. A dnode is constructed for * the entry and returned. The core makes sure that fsw_ext4_dnode_fill has been called * and the dnode is actually a directory. The shandle provided by the caller is used to * record the position in the directory between calls. */ static fsw_status_t fsw_ext4_dir_read(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno, struct fsw_shandle *shand, struct fsw_ext4_dnode **child_dno_out) { fsw_status_t status; struct ext4_dir_entry entry; struct fsw_string entry_name; // Preconditions: The caller has checked that dno is a directory node. The caller // has opened a storage handle to the directory's storage and keeps it around between // calls. FSW_MSG_DEBUG((FSW_MSGSTR("fsw_ext4_dir_read: started reading dir\n"))); while (1) { // read next entry status = fsw_ext4_read_dentry(shand, &entry); if (status) return status; if (entry.inode == 0) // end of directory return FSW_NOT_FOUND; // skip . and .. if ((entry.name_len == 1 && entry.name[0] == '.') || (entry.name_len == 2 && entry.name[0] == '.' && entry.name[1] == '.')) continue; break; } // setup name entry_name.type = FSW_STRING_TYPE_ISO88591; entry_name.len = entry_name.size = entry.name_len; entry_name.data = entry.name; // setup a dnode for the child item status = fsw_dnode_create(dno, entry.inode, FSW_DNODE_TYPE_UNKNOWN, &entry_name, child_dno_out); return status; } /** * Read a directory entry from the directory's raw data. This internal function is used * to read a raw ext2 directory entry into memory. The shandle's position pointer is adjusted * to point to the next entry. */ static fsw_status_t fsw_ext4_read_dentry(struct fsw_shandle *shand, struct ext4_dir_entry *entry) { fsw_status_t status; fsw_u32 buffer_size; while (1) { // read dir_entry header (fixed length) buffer_size = 8; status = fsw_shandle_read(shand, &buffer_size, entry); if (status) return status; if (buffer_size < 8 || entry->rec_len == 0) { // end of directory reached entry->inode = 0; return FSW_SUCCESS; } if (entry->rec_len < 8) return FSW_VOLUME_CORRUPTED; if (entry->inode != 0) { // this entry is used if (entry->rec_len < 8 + entry->name_len) return FSW_VOLUME_CORRUPTED; break; } // valid, but unused entry, skip it shand->pos += entry->rec_len - 8; } // read file name (variable length) buffer_size = entry->name_len; status = fsw_shandle_read(shand, &buffer_size, entry->name); if (status) return status; if (buffer_size < entry->name_len) return FSW_VOLUME_CORRUPTED; // skip any remaining padding shand->pos += entry->rec_len - (8 + entry->name_len); return FSW_SUCCESS; } /** * Get the target path of a symbolic link. This function is called when a symbolic * link needs to be resolved. The core makes sure that the fsw_ext4_dnode_fill has been * called on the dnode and that it really is a symlink. * * For ext4, the target path can be stored inline in the inode structure (in the space * otherwise occupied by the block pointers) or in the inode's data. There is no flag * indicating this, only the number of blocks entry (i_blocks) can be used as an * indication. The check used here comes from the Linux kernel. */ static fsw_status_t fsw_ext4_readlink(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno, struct fsw_string *link_target) { fsw_status_t status; int ea_blocks; struct fsw_string s; if (dno->g.size > FSW_PATH_MAX) return FSW_VOLUME_CORRUPTED; /* Linux kernels ext4_inode_is_fast_symlink... */ ea_blocks = dno->raw->i_file_acl_lo ? (vol->g.log_blocksize >> 9) : 0; if (dno->raw->i_blocks_lo - ea_blocks == 0) { // "fast" symlink, path is stored inside the inode s.type = FSW_STRING_TYPE_ISO88591; s.size = s.len = (int)dno->g.size; s.data = dno->raw->i_block; status = fsw_strdup_coerce(link_target, vol->g.host_string_type, &s); } else { // "slow" symlink, path is stored in normal inode data status = fsw_dnode_readlink_data(dno, link_target); } return status; } // EOF ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/gnuefi.txt����������������������������������������������������������������0000644�0001750�0001750�00000025604�12627612326�017713� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������rm -f fsw_efi.o make DRIVERNAME=ext2 -f Make.gnuefi make[1]: Entering directory `/other/nessus/programming/refind/current/filesystems' /usr/bin/gcc -DFSTYPE=ext2 -m32 -malign-double -I. -I./../include -I./../libeg -I/usr/include/efi -I/usr/include/efi/ia32 -I/usr/include/efi/protocol -I../include -I../refind -I../libeg -DCONFIG_ia32 -D__MAKEWITH_GNUEFI -DEFI32 -malign-double -O2 -fno-strict-aliasing -fno-stack-protector -fpic -fshort-wchar -Wall -c fsw_core.c -o fsw_core.o /usr/bin/gcc -DFSTYPE=ext2 -m32 -malign-double -I. -I./../include -I./../libeg -I/usr/include/efi -I/usr/include/efi/ia32 -I/usr/include/efi/protocol -I../include -I../refind -I../libeg -DCONFIG_ia32 -D__MAKEWITH_GNUEFI -DEFI32 -malign-double -O2 -fno-strict-aliasing -fno-stack-protector -fpic -fshort-wchar -Wall -c fsw_efi.c -o fsw_efi.o /usr/bin/gcc -DFSTYPE=ext2 -m32 -malign-double -I. -I./../include -I./../libeg -I/usr/include/efi -I/usr/include/efi/ia32 -I/usr/include/efi/protocol -I../include -I../refind -I../libeg -DCONFIG_ia32 -D__MAKEWITH_GNUEFI -DEFI32 -malign-double -O2 -fno-strict-aliasing -fno-stack-protector -fpic -fshort-wchar -Wall -c fsw_efi_lib.c -o fsw_efi_lib.o /usr/bin/gcc -DFSTYPE=ext2 -m32 -malign-double -I. -I./../include -I./../libeg -I/usr/include/efi -I/usr/include/efi/ia32 -I/usr/include/efi/protocol -I../include -I../refind -I../libeg -DCONFIG_ia32 -D__MAKEWITH_GNUEFI -DEFI32 -malign-double -O2 -fno-strict-aliasing -fno-stack-protector -fpic -fshort-wchar -Wall -c fsw_lib.c -o fsw_lib.o /usr/bin/gcc -DFSTYPE=ext2 -m32 -malign-double -I. -I./../include -I./../libeg -I/usr/include/efi -I/usr/include/efi/ia32 -I/usr/include/efi/protocol -I../include -I../refind -I../libeg -DCONFIG_ia32 -D__MAKEWITH_GNUEFI -DEFI32 -malign-double -O2 -fno-strict-aliasing -fno-stack-protector -fpic -fshort-wchar -Wall -c fsw_ext2.c -o fsw_ext2.o /usr/bin/ld -T /usr/lib/elf_ia32_efi.lds -shared -Bsymbolic -L/usr/lib -L/usr/lib /usr/lib/crt0-efi-ia32.o fsw_core.o fsw_efi.o fsw_efi_lib.o fsw_lib.o fsw_ext2.o -o ext2_ia32.so -lefi -lgnuefi /usr/lib/gcc/i686-linux-gnu/4.8/libgcc.a /usr/bin/objcopy -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel \ -j .rela -j .rel.* -j .rela.* -j .rel* -j .rela* \ -j .reloc --target=efi-bsdrv-ia32 ext2_ia32.so ext2_ia32.efi chmod a-x ext2_ia32.efi mkdir -p ../drivers_ia32 cp ext2_ia32.efi ../drivers_ia32 make[1]: Leaving directory `/other/nessus/programming/refind/current/filesystems' rm -f fsw_efi.o make DRIVERNAME=ext4 -f Make.gnuefi make[1]: Entering directory `/other/nessus/programming/refind/current/filesystems' /usr/bin/gcc -DFSTYPE=ext4 -m32 -malign-double -I. -I./../include -I./../libeg -I/usr/include/efi -I/usr/include/efi/ia32 -I/usr/include/efi/protocol -I../include -I../refind -I../libeg -DCONFIG_ia32 -D__MAKEWITH_GNUEFI -DEFI32 -malign-double -O2 -fno-strict-aliasing -fno-stack-protector -fpic -fshort-wchar -Wall -c fsw_efi.c -o fsw_efi.o /usr/bin/gcc -DFSTYPE=ext4 -m32 -malign-double -I. -I./../include -I./../libeg -I/usr/include/efi -I/usr/include/efi/ia32 -I/usr/include/efi/protocol -I../include -I../refind -I../libeg -DCONFIG_ia32 -D__MAKEWITH_GNUEFI -DEFI32 -malign-double -O2 -fno-strict-aliasing -fno-stack-protector -fpic -fshort-wchar -Wall -c fsw_ext4.c -o fsw_ext4.o /usr/bin/ld -T /usr/lib/elf_ia32_efi.lds -shared -Bsymbolic -L/usr/lib -L/usr/lib /usr/lib/crt0-efi-ia32.o fsw_core.o fsw_efi.o fsw_efi_lib.o fsw_lib.o fsw_ext4.o -o ext4_ia32.so -lefi -lgnuefi /usr/lib/gcc/i686-linux-gnu/4.8/libgcc.a /usr/bin/objcopy -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel \ -j .rela -j .rel.* -j .rela.* -j .rel* -j .rela* \ -j .reloc --target=efi-bsdrv-ia32 ext4_ia32.so ext4_ia32.efi chmod a-x ext4_ia32.efi mkdir -p ../drivers_ia32 cp ext4_ia32.efi ../drivers_ia32 make[1]: Leaving directory `/other/nessus/programming/refind/current/filesystems' rm -f fsw_efi.o make DRIVERNAME=reiserfs -f Make.gnuefi make[1]: Entering directory `/other/nessus/programming/refind/current/filesystems' /usr/bin/gcc -DFSTYPE=reiserfs -m32 -malign-double -I. -I./../include -I./../libeg -I/usr/include/efi -I/usr/include/efi/ia32 -I/usr/include/efi/protocol -I../include -I../refind -I../libeg -DCONFIG_ia32 -D__MAKEWITH_GNUEFI -DEFI32 -malign-double -O2 -fno-strict-aliasing -fno-stack-protector -fpic -fshort-wchar -Wall -c fsw_efi.c -o fsw_efi.o /usr/bin/gcc -DFSTYPE=reiserfs -m32 -malign-double -I. -I./../include -I./../libeg -I/usr/include/efi -I/usr/include/efi/ia32 -I/usr/include/efi/protocol -I../include -I../refind -I../libeg -DCONFIG_ia32 -D__MAKEWITH_GNUEFI -DEFI32 -malign-double -O2 -fno-strict-aliasing -fno-stack-protector -fpic -fshort-wchar -Wall -c fsw_reiserfs.c -o fsw_reiserfs.o /usr/bin/ld -T /usr/lib/elf_ia32_efi.lds -shared -Bsymbolic -L/usr/lib -L/usr/lib /usr/lib/crt0-efi-ia32.o fsw_core.o fsw_efi.o fsw_efi_lib.o fsw_lib.o fsw_reiserfs.o -o reiserfs_ia32.so -lefi -lgnuefi /usr/lib/gcc/i686-linux-gnu/4.8/libgcc.a /usr/bin/objcopy -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel \ -j .rela -j .rel.* -j .rela.* -j .rel* -j .rela* \ -j .reloc --target=efi-bsdrv-ia32 reiserfs_ia32.so reiserfs_ia32.efi chmod a-x reiserfs_ia32.efi mkdir -p ../drivers_ia32 cp reiserfs_ia32.efi ../drivers_ia32 make[1]: Leaving directory `/other/nessus/programming/refind/current/filesystems' rm -f fsw_efi.o make DRIVERNAME=iso9660 -f Make.gnuefi make[1]: Entering directory `/other/nessus/programming/refind/current/filesystems' /usr/bin/gcc -DFSTYPE=iso9660 -m32 -malign-double -I. -I./../include -I./../libeg -I/usr/include/efi -I/usr/include/efi/ia32 -I/usr/include/efi/protocol -I../include -I../refind -I../libeg -DCONFIG_ia32 -D__MAKEWITH_GNUEFI -DEFI32 -malign-double -O2 -fno-strict-aliasing -fno-stack-protector -fpic -fshort-wchar -Wall -c fsw_efi.c -o fsw_efi.o /usr/bin/gcc -DFSTYPE=iso9660 -m32 -malign-double -I. -I./../include -I./../libeg -I/usr/include/efi -I/usr/include/efi/ia32 -I/usr/include/efi/protocol -I../include -I../refind -I../libeg -DCONFIG_ia32 -D__MAKEWITH_GNUEFI -DEFI32 -malign-double -O2 -fno-strict-aliasing -fno-stack-protector -fpic -fshort-wchar -Wall -c fsw_iso9660.c -o fsw_iso9660.o /usr/bin/ld -T /usr/lib/elf_ia32_efi.lds -shared -Bsymbolic -L/usr/lib -L/usr/lib /usr/lib/crt0-efi-ia32.o fsw_core.o fsw_efi.o fsw_efi_lib.o fsw_lib.o fsw_iso9660.o -o iso9660_ia32.so -lefi -lgnuefi /usr/lib/gcc/i686-linux-gnu/4.8/libgcc.a /usr/bin/objcopy -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel \ -j .rela -j .rel.* -j .rela.* -j .rel* -j .rela* \ -j .reloc --target=efi-bsdrv-ia32 iso9660_ia32.so iso9660_ia32.efi chmod a-x iso9660_ia32.efi mkdir -p ../drivers_ia32 cp iso9660_ia32.efi ../drivers_ia32 make[1]: Leaving directory `/other/nessus/programming/refind/current/filesystems' rm -f fsw_efi.o make DRIVERNAME=hfs -f Make.gnuefi make[1]: Entering directory `/other/nessus/programming/refind/current/filesystems' /usr/bin/gcc -DFSTYPE=hfs -m32 -malign-double -I. -I./../include -I./../libeg -I/usr/include/efi -I/usr/include/efi/ia32 -I/usr/include/efi/protocol -I../include -I../refind -I../libeg -DCONFIG_ia32 -D__MAKEWITH_GNUEFI -DEFI32 -malign-double -O2 -fno-strict-aliasing -fno-stack-protector -fpic -fshort-wchar -Wall -c fsw_efi.c -o fsw_efi.o /usr/bin/gcc -DFSTYPE=hfs -m32 -malign-double -I. -I./../include -I./../libeg -I/usr/include/efi -I/usr/include/efi/ia32 -I/usr/include/efi/protocol -I../include -I../refind -I../libeg -DCONFIG_ia32 -D__MAKEWITH_GNUEFI -DEFI32 -malign-double -O2 -fno-strict-aliasing -fno-stack-protector -fpic -fshort-wchar -Wall -c fsw_hfs.c -o fsw_hfs.o /usr/bin/ld -T /usr/lib/elf_ia32_efi.lds -shared -Bsymbolic -L/usr/lib -L/usr/lib /usr/lib/crt0-efi-ia32.o fsw_core.o fsw_efi.o fsw_efi_lib.o fsw_lib.o fsw_hfs.o -o hfs_ia32.so -lefi -lgnuefi /usr/lib/gcc/i686-linux-gnu/4.8/libgcc.a /usr/bin/objcopy -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel \ -j .rela -j .rel.* -j .rela.* -j .rel* -j .rela* \ -j .reloc --target=efi-bsdrv-ia32 hfs_ia32.so hfs_ia32.efi chmod a-x hfs_ia32.efi mkdir -p ../drivers_ia32 cp hfs_ia32.efi ../drivers_ia32 make[1]: Leaving directory `/other/nessus/programming/refind/current/filesystems' rm -f fsw_efi.o make DRIVERNAME=btrfs -f Make.gnuefi make[1]: Entering directory `/other/nessus/programming/refind/current/filesystems' /usr/bin/gcc -DFSTYPE=btrfs -m32 -malign-double -I. -I./../include -I./../libeg -I/usr/include/efi -I/usr/include/efi/ia32 -I/usr/include/efi/protocol -I../include -I../refind -I../libeg -DCONFIG_ia32 -D__MAKEWITH_GNUEFI -DEFI32 -malign-double -O2 -fno-strict-aliasing -fno-stack-protector -fpic -fshort-wchar -Wall -c fsw_efi.c -o fsw_efi.o /usr/bin/gcc -DFSTYPE=btrfs -m32 -malign-double -I. -I./../include -I./../libeg -I/usr/include/efi -I/usr/include/efi/ia32 -I/usr/include/efi/protocol -I../include -I../refind -I../libeg -DCONFIG_ia32 -D__MAKEWITH_GNUEFI -DEFI32 -malign-double -O2 -fno-strict-aliasing -fno-stack-protector -fpic -fshort-wchar -Wall -c fsw_btrfs.c -o fsw_btrfs.o /usr/bin/ld -T /usr/lib/elf_ia32_efi.lds -shared -Bsymbolic -L/usr/lib -L/usr/lib /usr/lib/crt0-efi-ia32.o fsw_core.o fsw_efi.o fsw_efi_lib.o fsw_lib.o fsw_btrfs.o -o btrfs_ia32.so -lefi -lgnuefi /usr/lib/gcc/i686-linux-gnu/4.8/libgcc.a /usr/bin/objcopy -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel \ -j .rela -j .rel.* -j .rela.* -j .rel* -j .rela* \ -j .reloc --target=efi-bsdrv-ia32 btrfs_ia32.so btrfs_ia32.efi chmod a-x btrfs_ia32.efi mkdir -p ../drivers_ia32 cp btrfs_ia32.efi ../drivers_ia32 make[1]: Leaving directory `/other/nessus/programming/refind/current/filesystems' rm -f fsw_efi.o make DRIVERNAME=ntfs -f Make.gnuefi make[1]: Entering directory `/other/nessus/programming/refind/current/filesystems' /usr/bin/gcc -DFSTYPE=ntfs -m32 -malign-double -I. -I./../include -I./../libeg -I/usr/include/efi -I/usr/include/efi/ia32 -I/usr/include/efi/protocol -I../include -I../refind -I../libeg -DCONFIG_ia32 -D__MAKEWITH_GNUEFI -DEFI32 -malign-double -O2 -fno-strict-aliasing -fno-stack-protector -fpic -fshort-wchar -Wall -c fsw_efi.c -o fsw_efi.o /usr/bin/gcc -DFSTYPE=ntfs -m32 -malign-double -I. -I./../include -I./../libeg -I/usr/include/efi -I/usr/include/efi/ia32 -I/usr/include/efi/protocol -I../include -I../refind -I../libeg -DCONFIG_ia32 -D__MAKEWITH_GNUEFI -DEFI32 -malign-double -O2 -fno-strict-aliasing -fno-stack-protector -fpic -fshort-wchar -Wall -c fsw_ntfs.c -o fsw_ntfs.o /usr/bin/ld -T /usr/lib/elf_ia32_efi.lds -shared -Bsymbolic -L/usr/lib -L/usr/lib /usr/lib/crt0-efi-ia32.o fsw_core.o fsw_efi.o fsw_efi_lib.o fsw_lib.o fsw_ntfs.o -o ntfs_ia32.so -lefi -lgnuefi /usr/lib/gcc/i686-linux-gnu/4.8/libgcc.a /usr/bin/objcopy -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel \ -j .rela -j .rel.* -j .rela.* -j .rel* -j .rela* \ -j .reloc --target=efi-bsdrv-ia32 ntfs_ia32.so ntfs_ia32.efi chmod a-x ntfs_ia32.efi mkdir -p ../drivers_ia32 cp ntfs_ia32.efi ../drivers_ia32 make[1]: Leaving directory `/other/nessus/programming/refind/current/filesystems' ����������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/hfs_format.h��������������������������������������������������������������0000664�0001750�0001750�00000074715�12630650772�020210� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Id: hfs_format.h 33540 2010-10-28 09:27:05Z vboxsync $ */ /** @file * hfs_format.h */ /* * Copyright (C) 2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; * you can redistribute it and/or modify it under the terms of the GNU * General Public License (GPL) as published by the Free Software * Foundation, in version 2 as it comes in the "COPYING" file of the * VirtualBox OSE distribution. VirtualBox OSE is distributed in the * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. */ /* * This code is based on: * * Copyright (c) 2000-2007 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. The rights granted to you under the License * may not be used to create, or enable the creation or redistribution of, * unlawful or unlicensed copies of an Apple operating system, or to * circumvent, violate, or enable the circumvention or violation of, any * terms of an Apple operating system software license agreement. * * Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ #ifndef __HFS_FORMAT__ #define __HFS_FORMAT__ // #if !defined(__MAKEWITH_TIANO) && !defined(HOST_POSIX) // // Only available on Mac? and Intel EFI Toolkit? // #include <sys/types.h> // #include <sys/appleapiopts.h> // #endif #ifdef _MSC_VER # pragma pack(push,2) # define HFS_ALIGNMENT #else #define HFS_ALIGNMENT __attribute__((aligned(2), packed)) #endif /* * hfs_format.c * * This file describes the on-disk format for HFS and HFS Plus volumes. * The HFS Plus volume format is described in detail in Apple Technote 1150. * * http://developer.apple.com/technotes/tn/tn1150.html * */ #ifdef __cplusplus extern "C" { #endif /* some on-disk hfs structures have 68K alignment (misaligned) */ /* Signatures used to differentiate between HFS and HFS Plus volumes */ enum { kHFSSigWord = 0x4244, /* 'BD' in ASCII */ kHFSPlusSigWord = 0x482B, /* 'H+' in ASCII */ kHFSXSigWord = 0x4858, /* 'HX' in ASCII */ kHFSPlusVersion = 0x0004, /* 'H+' volumes are version 4 only */ kHFSXVersion = 0x0005, /* 'HX' volumes start with version 5 */ kHFSPlusMountVersion = 0x31302E30, /* '10.0' for Mac OS X */ kHFSJMountVersion = 0x4846534a, /* 'HFSJ' for journaled HFS+ on OS X */ kFSKMountVersion = 0x46534b21 /* 'FSK!' for failed journal replay */ }; #ifdef __APPLE_API_PRIVATE /* * Mac OS X has two special directories on HFS+ volumes for hardlinked files * and hardlinked directories as well as for open-unlinked files. * * These directories and their contents are not exported from the filesystem * under Mac OS X. */ #define HFSPLUSMETADATAFOLDER "\xE2\x90\x80\xE2\x90\x80\xE2\x90\x80\xE2\x90\x80HFS+ Private Data" #define HFSPLUS_DIR_METADATA_FOLDER ".HFS+ Private Directory Data\xd" /* * Files in the "HFS+ Private Data" folder have one of the following prefixes * followed by a decimal number (no leading zeros) for the file ID. * * Note: Earlier version of Mac OS X used a 32 bit random number for the link * ref number instead of the file id. * * e.g. iNode7182000 and temp3296 */ #define HFS_INODE_PREFIX "iNode" #define HFS_DELETE_PREFIX "temp" /* * Files in the ".HFS+ Private Directory Data" folder have the following * prefix followed by a decimal number (no leading zeros) for the file ID. * * e.g. dir_555 */ #define HFS_DIRINODE_PREFIX "dir_" /* * Hardlink inodes save the head of the link chain in * an extended attribute named FIRST_LINK_XATTR_NAME. * The attribute data is the decimal value in ASCII * of the cnid for the first link in the chain. * * This extended attribute is private (i.e. its not * exported in the getxattr/listxattr POSIX APIs). */ #define FIRST_LINK_XATTR_NAME "com.apple.system.hfs.firstlink" #define FIRST_LINK_XATTR_REC_SIZE (sizeof(HFSPlusAttrData) - 2 + 12) #endif /* __APPLE_API_PRIVATE */ /* * Indirect link files (hard links) have the following type/creator. */ enum { kHardLinkFileType = 0x686C6E6B, /* 'hlnk' */ kHFSPlusCreator = 0x6866732B /* 'hfs+' */ }; /* * File type and creator for symbolic links */ enum { kSymLinkFileType = 0x736C6E6B, /* 'slnk' */ kSymLinkCreator = 0x72686170 /* 'rhap' */ }; #ifndef _HFSUNISTR255_DEFINED_ #define _HFSUNISTR255_DEFINED_ /* Unicode strings are used for HFS Plus file and folder names */ struct HFSUniStr255 { u_int16_t length; /* number of unicode characters */ u_int16_t unicode[255]; /* unicode characters */ } HFS_ALIGNMENT; typedef struct HFSUniStr255 HFSUniStr255; typedef const HFSUniStr255 *ConstHFSUniStr255Param; #endif /* _HFSUNISTR255_DEFINED_ */ enum { kHFSMaxVolumeNameChars = 27, kHFSMaxFileNameChars = 31, kHFSPlusMaxFileNameChars = 255 }; /* Extent overflow file data structures */ /* HFS Extent key */ struct HFSExtentKey { u_int8_t keyLength; /* length of key, excluding this field */ u_int8_t forkType; /* 0 = data fork, FF = resource fork */ u_int32_t fileID; /* file ID */ u_int16_t startBlock; /* first file allocation block number in this extent */ } HFS_ALIGNMENT; typedef struct HFSExtentKey HFSExtentKey; /* HFS Plus Extent key */ struct HFSPlusExtentKey { u_int16_t keyLength; /* length of key, excluding this field */ u_int8_t forkType; /* 0 = data fork, FF = resource fork */ u_int8_t pad; /* make the other fields align on 32-bit boundary */ u_int32_t fileID; /* file ID */ u_int32_t startBlock; /* first file allocation block number in this extent */ } HFS_ALIGNMENT; typedef struct HFSPlusExtentKey HFSPlusExtentKey; /* Number of extent descriptors per extent record */ enum { kHFSExtentDensity = 3, kHFSPlusExtentDensity = 8 }; /* HFS extent descriptor */ struct HFSExtentDescriptor { u_int16_t startBlock; /* first allocation block */ u_int16_t blockCount; /* number of allocation blocks */ } HFS_ALIGNMENT; typedef struct HFSExtentDescriptor HFSExtentDescriptor; /* HFS Plus extent descriptor */ struct HFSPlusExtentDescriptor { u_int32_t startBlock; /* first allocation block */ u_int32_t blockCount; /* number of allocation blocks */ } HFS_ALIGNMENT; typedef struct HFSPlusExtentDescriptor HFSPlusExtentDescriptor; /* HFS extent record */ typedef HFSExtentDescriptor HFSExtentRecord[3]; /* HFS Plus extent record */ typedef HFSPlusExtentDescriptor HFSPlusExtentRecord[8]; /* Finder information */ struct FndrFileInfo { u_int32_t fdType; /* file type */ u_int32_t fdCreator; /* file creator */ u_int16_t fdFlags; /* Finder flags */ struct { int16_t v; /* file's location */ int16_t h; } fdLocation; int16_t opaque; } HFS_ALIGNMENT; typedef struct FndrFileInfo FndrFileInfo; struct FndrDirInfo { struct { /* folder's window rectangle */ int16_t top; int16_t left; int16_t bottom; int16_t right; } frRect; unsigned short frFlags; /* Finder flags */ struct { u_int16_t v; /* folder's location */ u_int16_t h; } frLocation; int16_t opaque; } HFS_ALIGNMENT; typedef struct FndrDirInfo FndrDirInfo; struct FndrOpaqueInfo { int8_t opaque[16]; } HFS_ALIGNMENT; typedef struct FndrOpaqueInfo FndrOpaqueInfo; /* HFS Plus Fork data info - 80 bytes */ struct HFSPlusForkData { u_int64_t logicalSize; /* fork's logical size in bytes */ u_int32_t clumpSize; /* fork's clump size in bytes */ u_int32_t totalBlocks; /* total blocks used by this fork */ HFSPlusExtentRecord extents; /* initial set of extents */ } HFS_ALIGNMENT; typedef struct HFSPlusForkData HFSPlusForkData; /* Mac OS X has 16 bytes worth of "BSD" info. * * Note: Mac OS 9 implementations and applications * should preserve, but not change, this information. */ struct HFSPlusBSDInfo { u_int32_t ownerID; /* user-id of owner or hard link chain previous link */ u_int32_t groupID; /* group-id of owner or hard link chain next link */ u_int8_t adminFlags; /* super-user changeable flags */ u_int8_t ownerFlags; /* owner changeable flags */ u_int16_t fileMode; /* file type and permission bits */ union { u_int32_t iNodeNum; /* indirect node number (hard links only) */ u_int32_t linkCount; /* links that refer to this indirect node */ u_int32_t rawDevice; /* special file device (FBLK and FCHR only) */ } special; } HFS_ALIGNMENT; typedef struct HFSPlusBSDInfo HFSPlusBSDInfo; /* * Hardlink "links" resolve to an inode * and the actual uid/gid comes from that * inode. * * We repurpose the links's uid/gid fields * for the hardlink link chain. The chain * consists of a doubly linked list of file * ids. */ #define hl_firstLinkID reserved1 /* Valid only if HasLinkChain flag is set (indirect nodes only) */ #define hl_prevLinkID bsdInfo.ownerID /* Valid only if HasLinkChain flag is set */ #define hl_nextLinkID bsdInfo.groupID /* Valid only if HasLinkChain flag is set */ #define hl_linkReference bsdInfo.special.iNodeNum #define hl_linkCount bsdInfo.special.linkCount /* Catalog file data structures */ enum { kHFSRootParentID = 1, /* Parent ID of the root folder */ kHFSRootFolderID = 2, /* Folder ID of the root folder */ kHFSExtentsFileID = 3, /* File ID of the extents file */ kHFSCatalogFileID = 4, /* File ID of the catalog file */ kHFSBadBlockFileID = 5, /* File ID of the bad allocation block file */ kHFSAllocationFileID = 6, /* File ID of the allocation file (HFS Plus only) */ kHFSStartupFileID = 7, /* File ID of the startup file (HFS Plus only) */ kHFSAttributesFileID = 8, /* File ID of the attribute file (HFS Plus only) */ kHFSAttributeDataFileID = 13, /* Used in Mac OS X runtime for extent based attributes */ /* kHFSAttributeDataFileID is never stored on disk. */ kHFSRepairCatalogFileID = 14, /* Used when rebuilding Catalog B-tree */ kHFSBogusExtentFileID = 15, /* Used for exchanging extents in extents file */ kHFSFirstUserCatalogNodeID = 16 }; /* HFS catalog key */ struct HFSCatalogKey { u_int8_t keyLength; /* key length (in bytes) */ u_int8_t reserved; /* reserved (set to zero) */ u_int32_t parentID; /* parent folder ID */ u_int8_t nodeName[kHFSMaxFileNameChars + 1]; /* catalog node name */ } HFS_ALIGNMENT; typedef struct HFSCatalogKey HFSCatalogKey; /* HFS Plus catalog key */ struct HFSPlusCatalogKey { u_int16_t keyLength; /* key length (in bytes) */ u_int32_t parentID; /* parent folder ID */ HFSUniStr255 nodeName; /* catalog node name */ } HFS_ALIGNMENT; typedef struct HFSPlusCatalogKey HFSPlusCatalogKey; /* Catalog record types */ enum { /* HFS Catalog Records */ kHFSFolderRecord = 0x0100, /* Folder record */ kHFSFileRecord = 0x0200, /* File record */ kHFSFolderThreadRecord = 0x0300, /* Folder thread record */ kHFSFileThreadRecord = 0x0400, /* File thread record */ /* HFS Plus Catalog Records */ kHFSPlusFolderRecord = 1, /* Folder record */ kHFSPlusFileRecord = 2, /* File record */ kHFSPlusFolderThreadRecord = 3, /* Folder thread record */ kHFSPlusFileThreadRecord = 4 /* File thread record */ }; /* Catalog file record flags */ enum { kHFSFileLockedBit = 0x0000, /* file is locked and cannot be written to */ kHFSFileLockedMask = 0x0001, kHFSThreadExistsBit = 0x0001, /* a file thread record exists for this file */ kHFSThreadExistsMask = 0x0002, kHFSHasAttributesBit = 0x0002, /* object has extended attributes */ kHFSHasAttributesMask = 0x0004, kHFSHasSecurityBit = 0x0003, /* object has security data (ACLs) */ kHFSHasSecurityMask = 0x0008, kHFSHasFolderCountBit = 0x0004, /* only for HFSX, folder maintains a separate sub-folder count */ kHFSHasFolderCountMask = 0x0010, /* (sum of folder records and directory hard links) */ kHFSHasLinkChainBit = 0x0005, /* has hardlink chain (inode or link) */ kHFSHasLinkChainMask = 0x0020, kHFSHasChildLinkBit = 0x0006, /* folder has a child that's a dir link */ kHFSHasChildLinkMask = 0x0040 }; /* HFS catalog folder record - 70 bytes */ struct HFSCatalogFolder { int16_t recordType; /* == kHFSFolderRecord */ u_int16_t flags; /* folder flags */ u_int16_t valence; /* folder valence */ u_int32_t folderID; /* folder ID */ u_int32_t createDate; /* date and time of creation */ u_int32_t modifyDate; /* date and time of last modification */ u_int32_t backupDate; /* date and time of last backup */ FndrDirInfo userInfo; /* Finder information */ FndrOpaqueInfo finderInfo; /* additional Finder information */ u_int32_t reserved[4]; /* reserved - initialized as zero */ } HFS_ALIGNMENT; typedef struct HFSCatalogFolder HFSCatalogFolder; /* HFS Plus catalog folder record - 88 bytes */ struct HFSPlusCatalogFolder { int16_t recordType; /* == kHFSPlusFolderRecord */ u_int16_t flags; /* file flags */ u_int32_t valence; /* folder's item count */ u_int32_t folderID; /* folder ID */ u_int32_t createDate; /* date and time of creation */ u_int32_t contentModDate; /* date and time of last content modification */ u_int32_t attributeModDate; /* date and time of last attribute modification */ u_int32_t accessDate; /* date and time of last access (MacOS X only) */ u_int32_t backupDate; /* date and time of last backup */ HFSPlusBSDInfo bsdInfo; /* permissions (for MacOS X) */ FndrDirInfo userInfo; /* Finder information */ FndrOpaqueInfo finderInfo; /* additional Finder information */ u_int32_t textEncoding; /* hint for name conversions */ u_int32_t folderCount; /* number of enclosed folders, active when HasFolderCount is set */ } HFS_ALIGNMENT; typedef struct HFSPlusCatalogFolder HFSPlusCatalogFolder; /* HFS catalog file record - 102 bytes */ struct HFSCatalogFile { int16_t recordType; /* == kHFSFileRecord */ u_int8_t flags; /* file flags */ int8_t fileType; /* file type (unused ?) */ FndrFileInfo userInfo; /* Finder information */ u_int32_t fileID; /* file ID */ u_int16_t dataStartBlock; /* not used - set to zero */ int32_t dataLogicalSize; /* logical EOF of data fork */ int32_t dataPhysicalSize; /* physical EOF of data fork */ u_int16_t rsrcStartBlock; /* not used - set to zero */ int32_t rsrcLogicalSize; /* logical EOF of resource fork */ int32_t rsrcPhysicalSize; /* physical EOF of resource fork */ u_int32_t createDate; /* date and time of creation */ u_int32_t modifyDate; /* date and time of last modification */ u_int32_t backupDate; /* date and time of last backup */ FndrOpaqueInfo finderInfo; /* additional Finder information */ u_int16_t clumpSize; /* file clump size (not used) */ HFSExtentRecord dataExtents; /* first data fork extent record */ HFSExtentRecord rsrcExtents; /* first resource fork extent record */ u_int32_t reserved; /* reserved - initialized as zero */ } HFS_ALIGNMENT; typedef struct HFSCatalogFile HFSCatalogFile; /* HFS Plus catalog file record - 248 bytes */ struct HFSPlusCatalogFile { int16_t recordType; /* == kHFSPlusFileRecord */ u_int16_t flags; /* file flags */ u_int32_t reserved1; /* reserved - initialized as zero */ u_int32_t fileID; /* file ID */ u_int32_t createDate; /* date and time of creation */ u_int32_t contentModDate; /* date and time of last content modification */ u_int32_t attributeModDate; /* date and time of last attribute modification */ u_int32_t accessDate; /* date and time of last access (MacOS X only) */ u_int32_t backupDate; /* date and time of last backup */ HFSPlusBSDInfo bsdInfo; /* permissions (for MacOS X) */ FndrFileInfo userInfo; /* Finder information */ FndrOpaqueInfo finderInfo; /* additional Finder information */ u_int32_t textEncoding; /* hint for name conversions */ u_int32_t reserved2; /* reserved - initialized as zero */ /* Note: these start on double long (64 bit) boundary */ HFSPlusForkData dataFork; /* size and block data for data fork */ HFSPlusForkData resourceFork; /* size and block data for resource fork */ } HFS_ALIGNMENT; typedef struct HFSPlusCatalogFile HFSPlusCatalogFile; /* HFS catalog thread record - 46 bytes */ struct HFSCatalogThread { int16_t recordType; /* == kHFSFolderThreadRecord or kHFSFileThreadRecord */ int32_t reserved[2]; /* reserved - initialized as zero */ u_int32_t parentID; /* parent ID for this catalog node */ u_int8_t nodeName[kHFSMaxFileNameChars + 1]; /* name of this catalog node */ } HFS_ALIGNMENT; typedef struct HFSCatalogThread HFSCatalogThread; /* HFS Plus catalog thread record -- 264 bytes */ struct HFSPlusCatalogThread { int16_t recordType; /* == kHFSPlusFolderThreadRecord or kHFSPlusFileThreadRecord */ int16_t reserved; /* reserved - initialized as zero */ u_int32_t parentID; /* parent ID for this catalog node */ HFSUniStr255 nodeName; /* name of this catalog node (variable length) */ } HFS_ALIGNMENT; typedef struct HFSPlusCatalogThread HFSPlusCatalogThread; #ifdef __APPLE_API_UNSTABLE /* These are the types of records in the attribute B-tree. The values were chosen so that they wouldn't conflict with the catalog record types. */ enum { kHFSPlusAttrInlineData = 0x10, /* attributes whose data fits in a b-tree node */ kHFSPlusAttrForkData = 0x20, /* extent based attributes (data lives in extents) */ kHFSPlusAttrExtents = 0x30 /* overflow extents for large attributes */ }; /* HFSPlusAttrForkData For larger attributes, whose value is stored in allocation blocks. If the attribute has more than 8 extents, there will be additional records (of type HFSPlusAttrExtents) for this attribute. */ struct HFSPlusAttrForkData { u_int32_t recordType; /* == kHFSPlusAttrForkData*/ u_int32_t reserved; HFSPlusForkData theFork; /* size and first extents of value*/ } HFS_ALIGNMENT; typedef struct HFSPlusAttrForkData HFSPlusAttrForkData; /* HFSPlusAttrExtents This record contains information about overflow extents for large, fragmented attributes. */ struct HFSPlusAttrExtents { u_int32_t recordType; /* == kHFSPlusAttrExtents*/ u_int32_t reserved; HFSPlusExtentRecord extents; /* additional extents*/ } HFS_ALIGNMENT; typedef struct HFSPlusAttrExtents HFSPlusAttrExtents; /* * Attributes B-tree Data Record * * For small attributes, whose entire value is stored * within a single B-tree record. */ struct HFSPlusAttrData { u_int32_t recordType; /* == kHFSPlusAttrInlineData */ u_int32_t reserved[2]; u_int32_t attrSize; /* size of attribute data in bytes */ u_int8_t attrData[2]; /* variable length */ } HFS_ALIGNMENT; typedef struct HFSPlusAttrData HFSPlusAttrData; /* HFSPlusAttrInlineData is obsolete use HFSPlusAttrData instead */ struct HFSPlusAttrInlineData { u_int32_t recordType; u_int32_t reserved; u_int32_t logicalSize; u_int8_t userData[2]; } HFS_ALIGNMENT; typedef struct HFSPlusAttrInlineData HFSPlusAttrInlineData; /* A generic Attribute Record*/ union HFSPlusAttrRecord { u_int32_t recordType; HFSPlusAttrInlineData inlineData; /* NOT USED */ HFSPlusAttrData attrData; HFSPlusAttrForkData forkData; HFSPlusAttrExtents overflowExtents; }; typedef union HFSPlusAttrRecord HFSPlusAttrRecord; /* Attribute key */ enum { kHFSMaxAttrNameLen = 127 }; struct HFSPlusAttrKey { u_int16_t keyLength; /* key length (in bytes) */ u_int16_t pad; /* set to zero */ u_int32_t fileID; /* file associated with attribute */ u_int32_t startBlock; /* first allocation block number for extents */ u_int16_t attrNameLen; /* number of unicode characters */ u_int16_t attrName[kHFSMaxAttrNameLen]; /* attribute name (Unicode) */ } HFS_ALIGNMENT; typedef struct HFSPlusAttrKey HFSPlusAttrKey; #define kHFSPlusAttrKeyMaximumLength (sizeof(HFSPlusAttrKey) - sizeof(u_int16_t)) #define kHFSPlusAttrKeyMinimumLength (kHFSPlusAttrKeyMaximumLength - kHFSMaxAttrNameLen*sizeof(u_int16_t)) #endif /* __APPLE_API_UNSTABLE */ /* Key and node lengths */ enum { kHFSPlusExtentKeyMaximumLength = sizeof(HFSPlusExtentKey) - sizeof(u_int16_t), kHFSExtentKeyMaximumLength = sizeof(HFSExtentKey) - sizeof(u_int8_t), kHFSPlusCatalogKeyMaximumLength = sizeof(HFSPlusCatalogKey) - sizeof(u_int16_t), kHFSPlusCatalogKeyMinimumLength = kHFSPlusCatalogKeyMaximumLength - sizeof(HFSUniStr255) + sizeof(u_int16_t), kHFSCatalogKeyMaximumLength = sizeof(HFSCatalogKey) - sizeof(u_int8_t), kHFSCatalogKeyMinimumLength = kHFSCatalogKeyMaximumLength - (kHFSMaxFileNameChars + 1) + sizeof(u_int8_t), kHFSPlusCatalogMinNodeSize = 4096, kHFSPlusExtentMinNodeSize = 512, kHFSPlusAttrMinNodeSize = 4096 }; /* HFS and HFS Plus volume attribute bits */ enum { /* Bits 0-6 are reserved (always cleared by MountVol call) */ kHFSVolumeHardwareLockBit = 7, /* volume is locked by hardware */ kHFSVolumeUnmountedBit = 8, /* volume was successfully unmounted */ kHFSVolumeSparedBlocksBit = 9, /* volume has bad blocks spared */ kHFSVolumeNoCacheRequiredBit = 10, /* don't cache volume blocks (i.e. RAM or ROM disk) */ kHFSBootVolumeInconsistentBit = 11, /* boot volume is inconsistent (System 7.6 and later) */ kHFSCatalogNodeIDsReusedBit = 12, kHFSVolumeJournaledBit = 13, /* this volume has a journal on it */ kHFSVolumeInconsistentBit = 14, /* serious inconsistencies detected at runtime */ kHFSVolumeSoftwareLockBit = 15, /* volume is locked by software */ kHFSVolumeHardwareLockMask = 1 << kHFSVolumeHardwareLockBit, kHFSVolumeUnmountedMask = 1 << kHFSVolumeUnmountedBit, kHFSVolumeSparedBlocksMask = 1 << kHFSVolumeSparedBlocksBit, kHFSVolumeNoCacheRequiredMask = 1 << kHFSVolumeNoCacheRequiredBit, kHFSBootVolumeInconsistentMask = 1 << kHFSBootVolumeInconsistentBit, kHFSCatalogNodeIDsReusedMask = 1 << kHFSCatalogNodeIDsReusedBit, kHFSVolumeJournaledMask = 1 << kHFSVolumeJournaledBit, kHFSVolumeInconsistentMask = 1 << kHFSVolumeInconsistentBit, kHFSVolumeSoftwareLockMask = 1 << kHFSVolumeSoftwareLockBit, kHFSMDBAttributesMask = 0x8380 }; /* HFS Master Directory Block - 162 bytes */ /* Stored at sector #2 (3rd sector) and second-to-last sector. */ struct HFSMasterDirectoryBlock { u_int16_t drSigWord; /* == kHFSSigWord = 0x4244 = 'BD' or 'H+' or 'HX'*/ u_int32_t drCrDate; /* date and time of volume creation */ u_int32_t drLsMod; /* date and time of last modification */ u_int16_t drAtrb; /* volume attributes */ u_int16_t drNmFls; /* number of files in root folder */ u_int16_t drVBMSt; /* first block of volume bitmap */ u_int16_t drAllocPtr; /* start of next allocation search */ u_int16_t drNmAlBlks; /* number of allocation blocks in volume */ u_int32_t drAlBlkSiz; /* size (in bytes) of allocation blocks */ u_int32_t drClpSiz; /* default clump size */ u_int16_t drAlBlSt; /* first allocation block in volume */ u_int32_t drNxtCNID; /* next unused catalog node ID */ u_int16_t drFreeBks; /* number of unused allocation blocks */ u_int8_t drVN[kHFSMaxVolumeNameChars + 1]; /* volume name */ u_int32_t drVolBkUp; /* date and time of last backup */ u_int16_t drVSeqNum; /* volume backup sequence number */ u_int32_t drWrCnt; /* volume write count */ u_int32_t drXTClpSiz; /* clump size for extents overflow file */ u_int32_t drCTClpSiz; /* clump size for catalog file */ u_int16_t drNmRtDirs; /* number of directories in root folder */ u_int32_t drFilCnt; /* number of files in volume */ u_int32_t drDirCnt; /* number of directories in volume */ u_int32_t drFndrInfo[8]; /* information used by the Finder */ u_int16_t drEmbedSigWord; /* embedded volume signature (formerly drVCSize) */ HFSExtentDescriptor drEmbedExtent; /* embedded volume location and size (formerly drVBMCSize and drCtlCSize) */ u_int32_t drXTFlSize; /* size of extents overflow file */ HFSExtentRecord drXTExtRec; /* extent record for extents overflow file */ u_int32_t drCTFlSize; /* size of catalog file */ HFSExtentRecord drCTExtRec; /* extent record for catalog file */ } HFS_ALIGNMENT; typedef struct HFSMasterDirectoryBlock HFSMasterDirectoryBlock; #ifdef __APPLE_API_UNSTABLE #define SET_HFS_TEXT_ENCODING(hint) \ (0x656e6300 | ((hint) & 0xff)) #define GET_HFS_TEXT_ENCODING(hint) \ (((hint) & 0xffffff00) == 0x656e6300 ? (hint) & 0x000000ff : 0xffffffffU) #endif /* __APPLE_API_UNSTABLE */ /* 48 2B 00 04 80 00 20 00 48 46 53 4A 00 AD 7E 98 //H+ HFSJ C9 12 D3 9E CB 84 F3 1D 00 00 00 00 C9 26 31 A8 00 12 1D 9D 00 03 66 B9 00 00 10 00 01 A1 2C CF 00 44 67 DF 01 35 EB A8 00 01 00 00 00 01 00 00 10 8B 1C EA 08 E4 9C 1B 00 00 00 00 02 00 00 8B 00 00 02 E7 10 3F CB 93 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 E7 6A 45 F3 37 EF 97 E9 A6 00 00 00 00 00 34 30 00 00 00 00 00 00 00 03 43 00 00 00 01 00 00 03 43 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 70 00 00 00 70 00 00 00 00 07 00 00 00 13 45 00 00 07 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 2A F8 00 00 01 90 00 00 00 02 AF 80 00 01 AA 55 00 01 90 00 00 14 5A C7 00 00 19 00 00 3D E4 E3 00 00 19 00 00 95 44 F7 00 00 19 00 00 9D 3B 18 00 00 32 00 00 E3 58 1C 00 00 19 00 00 48 1C 72 00 00 19 00 00 BB 6A 05 00 00 19 00 00 00 00 00 06 40 00 00 01 90 00 00 00 00 64 00 00 06 80 00 00 00 19 00 00 38 2A 2F 00 00 19 00 00 38 DB 2C 00 00 19 00 00 A6 A2 1F 00 00 19 00 */ /* HFS Plus Volume Header - 512 bytes */ /* Stored at sector #2 (3rd sector) and second-to-last sector. */ struct HFSPlusVolumeHeader { u_int16_t signature; /* == kHFSPlusSigWord */ u_int16_t version; /* == kHFSPlusVersion */ u_int32_t attributes; /* volume attributes */ u_int32_t lastMountedVersion; /* implementation version which last mounted volume */ u_int32_t journalInfoBlock; /* block addr of journal info (if volume is journaled, zero otherwise) */ u_int32_t createDate; /* date and time of volume creation */ u_int32_t modifyDate; /* date and time of last modification */ u_int32_t backupDate; /* date and time of last backup */ u_int32_t checkedDate; /* date and time of last disk check */ u_int32_t fileCount; /* number of files in volume */ u_int32_t folderCount; /* number of directories in volume */ u_int32_t blockSize; /* size (in bytes) of allocation blocks */ u_int32_t totalBlocks; /* number of allocation blocks in volume (includes this header and VBM*/ u_int32_t freeBlocks; /* number of unused allocation blocks */ u_int32_t nextAllocation; /* start of next allocation search */ u_int32_t rsrcClumpSize; /* default resource fork clump size */ u_int32_t dataClumpSize; /* default data fork clump size */ u_int32_t nextCatalogID; /* next unused catalog node ID */ u_int32_t writeCount; /* volume write count */ u_int64_t encodingsBitmap; /* which encodings have been use on this volume */ u_int8_t finderInfo[32]; /* information used by the Finder */ HFSPlusForkData allocationFile; /* allocation bitmap file */ HFSPlusForkData extentsFile; /* extents B-tree file */ HFSPlusForkData catalogFile; /* catalog B-tree file */ HFSPlusForkData attributesFile; /* extended attributes B-tree file */ HFSPlusForkData startupFile; /* boot file (secondary loader) */ } HFS_ALIGNMENT; typedef struct HFSPlusVolumeHeader HFSPlusVolumeHeader; /* B-tree structures */ enum BTreeKeyLimits{ kMaxKeyLength = 520 }; union BTreeKey{ u_int8_t length8; u_int16_t length16; u_int8_t rawData [kMaxKeyLength+2]; }; typedef union BTreeKey BTreeKey; /* BTNodeDescriptor -- Every B-tree node starts with these fields. */ struct BTNodeDescriptor { u_int32_t fLink; /* next node at this level*/ u_int32_t bLink; /* previous node at this level*/ int8_t kind; /* kind of node (leaf, index, header, map)*/ u_int8_t height; /* zero for header, map; child is one more than parent*/ u_int16_t numRecords; /* number of records in this node*/ u_int16_t reserved; /* reserved - initialized as zero */ } HFS_ALIGNMENT; typedef struct BTNodeDescriptor BTNodeDescriptor; /* Constants for BTNodeDescriptor kind */ enum { kBTLeafNode = -1, kBTIndexNode = 0, kBTHeaderNode = 1, kBTMapNode = 2 }; /* BTHeaderRec -- The first record of a B-tree header node */ struct BTHeaderRec { u_int16_t treeDepth; /* maximum height (usually leaf nodes) */ u_int32_t rootNode; /* node number of root node */ u_int32_t leafRecords; /* number of leaf records in all leaf nodes */ u_int32_t firstLeafNode; /* node number of first leaf node */ u_int32_t lastLeafNode; /* node number of last leaf node */ u_int16_t nodeSize; /* size of a node, in bytes */ u_int16_t maxKeyLength; /* reserved */ u_int32_t totalNodes; /* total number of nodes in tree */ u_int32_t freeNodes; /* number of unused (free) nodes in tree */ u_int16_t reserved1; /* unused */ u_int32_t clumpSize; /* reserved */ u_int8_t btreeType; /* reserved */ u_int8_t keyCompareType; /* Key string Comparison Type */ u_int32_t attributes; /* persistent attributes about the tree */ u_int32_t reserved3[16]; /* reserved */ } HFS_ALIGNMENT; typedef struct BTHeaderRec BTHeaderRec; /* Constants for BTHeaderRec attributes */ enum { kBTBadCloseMask = 0x00000001, /* reserved */ kBTBigKeysMask = 0x00000002, /* key length field is 16 bits */ kBTVariableIndexKeysMask = 0x00000004 /* keys in index nodes are variable length */ }; /* Catalog Key Name Comparison Type */ enum { kHFSCaseFolding = 0xCF, /* case folding (case-insensitive) */ kHFSBinaryCompare = 0xBC /* binary compare (case-sensitive) */ }; /* JournalInfoBlock - Structure that describes where our journal lives */ struct JournalInfoBlock { u_int32_t flags; u_int32_t device_signature[8]; // signature used to locate our device. u_int64_t offset; // byte offset to the journal on the device u_int64_t size; // size in bytes of the journal u_int32_t reserved[32]; } HFS_ALIGNMENT; typedef struct JournalInfoBlock JournalInfoBlock; enum { kJIJournalInFSMask = 0x00000001, kJIJournalOnOtherDeviceMask = 0x00000002, kJIJournalNeedInitMask = 0x00000004 }; #ifdef __cplusplus } #endif #ifdef _MSC_VER # pragma pack(pop) #endif #endif /* __HFS_FORMAT__ */ ���������������������������������������������������refind-0.11.4/filesystems/fsw_efi.c�����������������������������������������������������������������0000664�0001750�0001750�00000126146�13372346126�017470� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/** * \file fsw_efi.c * EFI host environment code. */ /*- * Copyright (c) 2006 Christoph Pfisterer * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * * Neither the name of Christoph Pfisterer nor the names of the * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Changes by Roderick Smith are licensed under the preceding terms. */ #include "fsw_efi.h" #include "fsw_core.h" #ifdef __MAKEWITH_GNUEFI #include "edk2/DriverBinding.h" #include "edk2/ComponentName.h" #define gMyEfiSimpleFileSystemProtocolGuid FileSystemProtocol #else #define REFIND_EFI_DRIVER_BINDING_PROTOCOL EFI_DRIVER_BINDING_PROTOCOL #define REFIND_EFI_COMPONENT_NAME_PROTOCOL EFI_COMPONENT_NAME_PROTOCOL #define REFIND_EFI_COMPONENT_NAME_PROTOCOL_GUID EFI_COMPONENT_NAME_PROTOCOL_GUID #define REFIND_EFI_DRIVER_BINDING_PROTOCOL_GUID EFI_DRIVER_BINDING_PROTOCOL_GUID #define REFIND_EFI_DEVICE_PATH_PROTOCOL EFI_DEVICE_PATH_PROTOCOL #define EFI_FILE_SYSTEM_VOLUME_LABEL_INFO_ID \ { 0xDB47D7D3,0xFE81, 0x11d3, {0x9A, 0x35, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D} } #define gMyEfiSimpleFileSystemProtocolGuid gEfiSimpleFileSystemProtocolGuid #endif #include "../include/refit_call_wrapper.h" #include "../include/version.h" #define DEBUG_LEVEL 0 #ifndef FSTYPE /** The file system type name to use. */ #define FSTYPE ext2 #endif EFI_GUID gMyEfiDriverBindingProtocolGuid = REFIND_EFI_DRIVER_BINDING_PROTOCOL_GUID; EFI_GUID gMyEfiComponentNameProtocolGuid = REFIND_EFI_COMPONENT_NAME_PROTOCOL_GUID; EFI_GUID gMyEfiDiskIoProtocolGuid = REFIND_EFI_DISK_IO_PROTOCOL_GUID; EFI_GUID gMyEfiBlockIoProtocolGuid = REFIND_EFI_BLOCK_IO_PROTOCOL_GUID; EFI_GUID gMyEfiFileInfoGuid = EFI_FILE_INFO_ID; EFI_GUID gMyEfiFileSystemInfoGuid = EFI_FILE_SYSTEM_INFO_ID; EFI_GUID gMyEfiFileSystemVolumeLabelInfoIdGuid = EFI_FILE_SYSTEM_VOLUME_LABEL_INFO_ID; /** Helper macro for stringification. */ #define FSW_EFI_STRINGIFY(x) #x /** Expands to the EFI driver name given the file system type name. */ #define FSW_EFI_DRIVER_NAME(t) L"rEFInd 0.11.4 " FSW_EFI_STRINGIFY(t) L" File System Driver" // function prototypes EFI_STATUS EFIAPI fsw_efi_DriverBinding_Supported(IN REFIND_EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle, IN REFIND_EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath); EFI_STATUS EFIAPI fsw_efi_DriverBinding_Start(IN REFIND_EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle, IN REFIND_EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath); EFI_STATUS EFIAPI fsw_efi_DriverBinding_Stop(IN REFIND_EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle, IN UINTN NumberOfChildren, IN EFI_HANDLE *ChildHandleBuffer); EFI_STATUS EFIAPI fsw_efi_ComponentName_GetDriverName(IN REFIND_EFI_COMPONENT_NAME_PROTOCOL *This, IN CHAR8 *Language, OUT CHAR16 **DriverName); EFI_STATUS EFIAPI fsw_efi_ComponentName_GetControllerName(IN REFIND_EFI_COMPONENT_NAME_PROTOCOL *This, IN EFI_HANDLE ControllerHandle, IN EFI_HANDLE ChildHandle OPTIONAL, IN CHAR8 *Language, OUT CHAR16 **ControllerName); void EFIAPI fsw_efi_change_blocksize(struct fsw_volume *vol, fsw_u32 old_phys_blocksize, fsw_u32 old_log_blocksize, fsw_u32 new_phys_blocksize, fsw_u32 new_log_blocksize); fsw_status_t EFIAPI fsw_efi_read_block(struct fsw_volume *vol, fsw_u64 phys_bno, void *buffer); EFI_STATUS fsw_efi_map_status(fsw_status_t fsw_status, FSW_VOLUME_DATA *Volume); EFI_STATUS EFIAPI fsw_efi_FileSystem_OpenVolume(IN EFI_FILE_IO_INTERFACE *This, OUT EFI_FILE **Root); EFI_STATUS fsw_efi_dnode_to_FileHandle(IN struct fsw_dnode *dno, OUT EFI_FILE **NewFileHandle); EFI_STATUS fsw_efi_file_read(IN FSW_FILE_DATA *File, IN OUT UINTN *BufferSize, OUT VOID *Buffer); EFI_STATUS fsw_efi_file_getpos(IN FSW_FILE_DATA *File, OUT UINT64 *Position); EFI_STATUS fsw_efi_file_setpos(IN FSW_FILE_DATA *File, IN UINT64 Position); EFI_STATUS fsw_efi_dir_open(IN FSW_FILE_DATA *File, OUT EFI_FILE **NewHandle, IN CHAR16 *FileName, IN UINT64 OpenMode, IN UINT64 Attributes); EFI_STATUS fsw_efi_dir_read(IN FSW_FILE_DATA *File, IN OUT UINTN *BufferSize, OUT VOID *Buffer); EFI_STATUS fsw_efi_dir_setpos(IN FSW_FILE_DATA *File, IN UINT64 Position); EFI_STATUS fsw_efi_dnode_getinfo(IN FSW_FILE_DATA *File, IN EFI_GUID *InformationType, IN OUT UINTN *BufferSize, OUT VOID *Buffer); EFI_STATUS fsw_efi_dnode_fill_FileInfo(IN FSW_VOLUME_DATA *Volume, IN struct fsw_dnode *dno, IN OUT UINTN *BufferSize, OUT VOID *Buffer); /** * Structure for holding disk cache data. */ #define CACHE_SIZE 131072 /* 128KiB */ struct cache_data { fsw_u8 *Cache; fsw_u64 CacheStart; BOOLEAN CacheValid; FSW_VOLUME_DATA *Volume; // NOTE: Do not deallocate; copied here to ID volume }; #define NUM_CACHES 2 /* Don't increase without modifying fsw_efi_read_block() */ static struct cache_data Caches[NUM_CACHES]; static int LastRead = -1; /** * Interface structure for the EFI Driver Binding protocol. */ REFIND_EFI_DRIVER_BINDING_PROTOCOL fsw_efi_DriverBinding_table = { fsw_efi_DriverBinding_Supported, fsw_efi_DriverBinding_Start, fsw_efi_DriverBinding_Stop, 0x10, NULL, NULL }; /** * Interface structure for the EFI Component Name protocol. */ REFIND_EFI_COMPONENT_NAME_PROTOCOL fsw_efi_ComponentName_table = { fsw_efi_ComponentName_GetDriverName, fsw_efi_ComponentName_GetControllerName, (CHAR8*) "eng" }; /** * Dispatch table for our FSW host driver. */ struct fsw_host_table fsw_efi_host_table = { FSW_STRING_TYPE_UTF16, fsw_efi_change_blocksize, fsw_efi_read_block }; extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(FSTYPE); VOID EFIAPI fsw_efi_clear_cache(VOID) { int i; // clear the cache for (i = 0; i < NUM_CACHES; i++) { if (Caches[i].Cache != NULL) { FreePool(Caches[i].Cache); Caches[i].Cache = NULL; } // if Caches[i].CacheStart = 0; Caches[i].CacheValid = FALSE; Caches[i].Volume = NULL; } LastRead = -1; } // VOID EFIAPI fsw_efi_clear_cache(); /** * Image entry point. Installs the Driver Binding and Component Name protocols * on the image's handle. Actually mounting a file system is initiated through * the Driver Binding protocol at the firmware's request. */ EFI_STATUS EFIAPI fsw_efi_main(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable) { EFI_STATUS Status; #ifndef __MAKEWITH_TIANO // Not available in EDK2 toolkit InitializeLib(ImageHandle, SystemTable); #endif // complete Driver Binding protocol instance fsw_efi_DriverBinding_table.ImageHandle = ImageHandle; fsw_efi_DriverBinding_table.DriverBindingHandle = ImageHandle; // install Driver Binding protocol Status = refit_call4_wrapper(BS->InstallProtocolInterface, &fsw_efi_DriverBinding_table.DriverBindingHandle, &gMyEfiDriverBindingProtocolGuid, EFI_NATIVE_INTERFACE, &fsw_efi_DriverBinding_table); if (EFI_ERROR (Status)) { return Status; } // install Component Name protocol Status = refit_call4_wrapper(BS->InstallProtocolInterface, &fsw_efi_DriverBinding_table.DriverBindingHandle, &gMyEfiComponentNameProtocolGuid, EFI_NATIVE_INTERFACE, &fsw_efi_ComponentName_table); if (EFI_ERROR (Status)) { return Status; } // OverrideFunctions(); // Msg = NULL; // msgCursor = NULL; // Status = BS->LocateProtocol(&gMsgLogProtocolGuid, NULL, (VOID **) &Msg); // if (!EFI_ERROR(Status) && (Msg != NULL)) { // msgCursor = Msg->Cursor; // BootLog("MsgLog installed into VBoxFs\n"); // } return EFI_SUCCESS; } #ifdef __MAKEWITH_GNUEFI EFI_DRIVER_ENTRY_POINT(fsw_efi_main) #endif /** * Driver Binding EFI protocol, Supported function. This function is called by EFI * to test if this driver can handle a certain device. Our implementation only checks * if the device is a disk (i.e. that it supports the Block I/O and Disk I/O protocols) * and implicitly checks if the disk is already in use by another driver. */ EFI_STATUS EFIAPI fsw_efi_DriverBinding_Supported(IN REFIND_EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle, IN REFIND_EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath) { EFI_STATUS Status; EFI_DISK_IO *DiskIo; // we check for both DiskIO and BlockIO protocols // first, open DiskIO Status = refit_call6_wrapper(BS->OpenProtocol, ControllerHandle, &gMyEfiDiskIoProtocolGuid, (VOID **) &DiskIo, This->DriverBindingHandle, ControllerHandle, EFI_OPEN_PROTOCOL_BY_DRIVER); if (EFI_ERROR(Status)) return Status; // we were just checking, close it again refit_call4_wrapper(BS->CloseProtocol, ControllerHandle, &gMyEfiDiskIoProtocolGuid, This->DriverBindingHandle, ControllerHandle); // next, check BlockIO without actually opening it Status = refit_call6_wrapper(BS->OpenProtocol, ControllerHandle, &gMyEfiBlockIoProtocolGuid, NULL, This->DriverBindingHandle, ControllerHandle, EFI_OPEN_PROTOCOL_TEST_PROTOCOL); return Status; } /** * Driver Binding EFI protocol, Start function. This function is called by EFI * to start driving the given device. It is still possible at this point to * return EFI_UNSUPPORTED, and in fact we will do so if the file system driver * cannot find the superblock signature (or equivalent) that it expects. * * This function allocates memory for a per-volume structure, opens the * required protocols (just Disk I/O in our case, Block I/O is only looked * at to get the MediaId field), and lets the FSW core mount the file system. * If successful, an EFI Simple File System protocol is exported on the * device handle. */ EFI_STATUS EFIAPI fsw_efi_DriverBinding_Start(IN REFIND_EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle, IN REFIND_EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath) { EFI_STATUS Status; EFI_BLOCK_IO *BlockIo; EFI_DISK_IO *DiskIo; FSW_VOLUME_DATA *Volume; #if DEBUG_LEVEL Print(L"fsw_efi_DriverBinding_Start\n"); #endif // open consumed protocols Status = refit_call6_wrapper(BS->OpenProtocol, ControllerHandle, &gMyEfiBlockIoProtocolGuid, (VOID **) &BlockIo, This->DriverBindingHandle, ControllerHandle, EFI_OPEN_PROTOCOL_GET_PROTOCOL); // NOTE: we only want to look at the MediaId if (EFI_ERROR(Status)) { // Print(L"Fsw ERROR: OpenProtocol(BlockIo) returned %x\n", Status); return Status; } Status = refit_call6_wrapper(BS->OpenProtocol, ControllerHandle, &gMyEfiDiskIoProtocolGuid, (VOID **) &DiskIo, This->DriverBindingHandle, ControllerHandle, EFI_OPEN_PROTOCOL_BY_DRIVER); if (EFI_ERROR(Status)) { Print(L"Fsw ERROR: OpenProtocol(DiskIo) returned %x\n", Status); return Status; } // allocate volume structure Volume = AllocateZeroPool(sizeof(FSW_VOLUME_DATA)); Volume->Signature = FSW_VOLUME_DATA_SIGNATURE; Volume->Handle = ControllerHandle; Volume->DiskIo = DiskIo; Volume->MediaId = BlockIo->Media->MediaId; Volume->LastIOStatus = EFI_SUCCESS; // mount the filesystem Status = fsw_efi_map_status(fsw_mount(Volume, &fsw_efi_host_table, &FSW_FSTYPE_TABLE_NAME(FSTYPE), &Volume->vol), Volume); if (!EFI_ERROR(Status)) { // register the SimpleFileSystem protocol Volume->FileSystem.Revision = EFI_FILE_IO_INTERFACE_REVISION; Volume->FileSystem.OpenVolume = fsw_efi_FileSystem_OpenVolume; Status = refit_call4_wrapper(BS->InstallMultipleProtocolInterfaces, &ControllerHandle, &gMyEfiSimpleFileSystemProtocolGuid, &Volume->FileSystem, NULL); if (EFI_ERROR(Status)) { // Print(L"Fsw ERROR: InstallMultipleProtocolInterfaces returned %x\n", Status); } } // on errors, close the opened protocols if (EFI_ERROR(Status)) { if (Volume->vol != NULL) fsw_unmount(Volume->vol); FreePool(Volume); refit_call4_wrapper(BS->CloseProtocol, ControllerHandle, &gMyEfiDiskIoProtocolGuid, This->DriverBindingHandle, ControllerHandle); } return Status; } /** * Driver Binding EFI protocol, Stop function. This function is called by EFI * to stop the driver on the given device. This translates to an unmount * call for the FSW core. * * We assume that all file handles on the volume have been closed before * the driver is stopped. At least with the EFI shell, that is actually the * case; it closes all file handles between commands. */ EFI_STATUS EFIAPI fsw_efi_DriverBinding_Stop(IN REFIND_EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle, IN UINTN NumberOfChildren, IN EFI_HANDLE *ChildHandleBuffer) { EFI_STATUS Status; EFI_FILE_IO_INTERFACE *FileSystem; FSW_VOLUME_DATA *Volume; #if DEBUG_LEVEL Print(L"fsw_efi_DriverBinding_Stop\n"); #endif // get the installed SimpleFileSystem interface Status = refit_call6_wrapper(BS->OpenProtocol, ControllerHandle, &gMyEfiSimpleFileSystemProtocolGuid, (VOID **) &FileSystem, This->DriverBindingHandle, ControllerHandle, EFI_OPEN_PROTOCOL_GET_PROTOCOL); if (EFI_ERROR(Status)) return EFI_UNSUPPORTED; // get private data structure Volume = FSW_VOLUME_FROM_FILE_SYSTEM(FileSystem); // uninstall Simple File System protocol Status = refit_call4_wrapper(BS->UninstallMultipleProtocolInterfaces, ControllerHandle, &gMyEfiSimpleFileSystemProtocolGuid, &Volume->FileSystem, NULL); if (EFI_ERROR(Status)) { // Print(L"Fsw ERROR: UninstallMultipleProtocolInterfaces returned %x\n", Status); return Status; } #if DEBUG_LEVEL Print(L"fsw_efi_DriverBinding_Stop: protocol uninstalled successfully\n"); #endif // release private data structure if (Volume->vol != NULL) fsw_unmount(Volume->vol); FreePool(Volume); // close the consumed protocols Status = refit_call4_wrapper(BS->CloseProtocol, ControllerHandle, &gMyEfiDiskIoProtocolGuid, This->DriverBindingHandle, ControllerHandle); // clear the cache fsw_efi_clear_cache(); return Status; } /** * Component Name EFI protocol, GetDriverName function. Used by the EFI * environment to inquire the name of this driver. The name returned is * based on the file system type actually used in compilation. */ EFI_STATUS EFIAPI fsw_efi_ComponentName_GetDriverName(IN REFIND_EFI_COMPONENT_NAME_PROTOCOL *This, IN CHAR8 *Language, OUT CHAR16 **DriverName) { if (Language == NULL || DriverName == NULL) return EFI_INVALID_PARAMETER; if (Language[0] == 'e' && Language[1] == 'n' && Language[2] == 'g' && Language[3] == 0) { *DriverName = FSW_EFI_DRIVER_NAME(FSTYPE); return EFI_SUCCESS; } return EFI_UNSUPPORTED; } /** * Component Name EFI protocol, GetControllerName function. Not implemented * because this is not a "bus" driver in the sense of the EFI Driver Model. */ EFI_STATUS EFIAPI fsw_efi_ComponentName_GetControllerName(IN REFIND_EFI_COMPONENT_NAME_PROTOCOL *This, IN EFI_HANDLE ControllerHandle, IN EFI_HANDLE ChildHandle OPTIONAL, IN CHAR8 *Language, OUT CHAR16 **ControllerName) { return EFI_UNSUPPORTED; } /** * FSW interface function for block size changes. This function is called by the FSW core * when the file system driver changes the block sizes for the volume. */ void EFIAPI fsw_efi_change_blocksize(struct fsw_volume *vol, fsw_u32 old_phys_blocksize, fsw_u32 old_log_blocksize, fsw_u32 new_phys_blocksize, fsw_u32 new_log_blocksize) { // nothing to do } /** * FSW interface function to read data blocks. This function is called by the FSW core * to read a block of data from the device. The buffer is allocated by the core code. * Two caches are maintained, so as to improve performance on some systems. (VirtualBox * is particularly susceptible to performance problems with an uncached driver -- the * ext2 driver can take 200 seconds to load a Linux kernel under VirtualBox, whereas * the time is more like 3 seconds with a cache!) Two independent caches are maintained * because the ext2fs driver tends to alternate between accessing two parts of the * disk. */ fsw_status_t EFIAPI fsw_efi_read_block(struct fsw_volume *vol, fsw_u64 phys_bno, void *buffer) { int i, ReadCache = -1; FSW_VOLUME_DATA *Volume = (FSW_VOLUME_DATA *)vol->host_data; EFI_STATUS Status = EFI_SUCCESS; BOOLEAN ReadOneBlock = FALSE; UINT64 StartRead = (UINT64) phys_bno * (UINT64) vol->phys_blocksize; if (buffer == NULL) return (fsw_status_t) EFI_BAD_BUFFER_SIZE; // Initialize static data structures, if necessary.... if (LastRead < 0) { fsw_efi_clear_cache(); } // if // Look for a cache hit on the current query.... i = 0; do { if ((Caches[i].Volume == Volume) && (Caches[i].CacheValid == TRUE) && (StartRead >= Caches[i].CacheStart) && ((StartRead + vol->phys_blocksize) <= (Caches[i].CacheStart + CACHE_SIZE))) { ReadCache = i; } i++; } while ((i < NUM_CACHES) && (ReadCache < 0)); // No cache hit found; load new cache and pass it on.... if (ReadCache < 0) { if (LastRead == -1) LastRead = 1; ReadCache = 1 - LastRead; // NOTE: If NUM_CACHES > 2, this must become more complex Caches[ReadCache].CacheValid = FALSE; if (Caches[ReadCache].Cache == NULL) Caches[ReadCache].Cache = AllocatePool(CACHE_SIZE); if (Caches[ReadCache].Cache != NULL) { // TODO: Below call hangs on my 32-bit Mac Mini when compiled with GNU-EFI. // The same binary is fine under VirtualBox, and the same call is fine when // compiled with Tianocore. Further clue: Omitting "Status =" avoids the // hang but produces a failure to mount the filesystem, even when the same // change is made to later similar call. Calling Volume->DiskIo->ReadDisk() // directly (without refit_call5_wrapper()) changes nothing. Placing Print() // statements at the start and end of the function, and before and after the // ReadDisk() call, suggests that when it fails, the program is executing // code starting mid-function, so there seems to be something messed up in // the way the function is being called. FIGURE THIS OUT! Status = refit_call5_wrapper(Volume->DiskIo->ReadDisk, Volume->DiskIo, Volume->MediaId, StartRead, (UINTN) CACHE_SIZE, (VOID*) Caches[ReadCache].Cache); if (!EFI_ERROR(Status)) { Caches[ReadCache].CacheStart = StartRead; Caches[ReadCache].CacheValid = TRUE; Caches[ReadCache].Volume = Volume; LastRead = ReadCache; } else { ReadOneBlock = TRUE; } } else { ReadOneBlock = TRUE; } // if cache memory allocated } // if (ReadCache < 0) if (Caches[ReadCache].Cache != NULL && Caches[ReadCache].CacheValid == TRUE && vol->phys_blocksize > 0) { CopyMem(buffer, &Caches[ReadCache].Cache[StartRead - Caches[ReadCache].CacheStart], vol->phys_blocksize); } else { ReadOneBlock = TRUE; } if (ReadOneBlock) { // Something's failed, so try a simple disk read of one block.... Status = refit_call5_wrapper(Volume->DiskIo->ReadDisk, Volume->DiskIo, Volume->MediaId, phys_bno * vol->phys_blocksize, (UINTN) vol->phys_blocksize, (VOID*) buffer); } Volume->LastIOStatus = Status; return Status; } // fsw_status_t *fsw_efi_read_block() /** * Map FSW status codes to EFI status codes. The FSW_IO_ERROR code is only produced * by fsw_efi_read_block, so we map it back to the EFI status code remembered from * the last I/O operation. */ EFI_STATUS fsw_efi_map_status(fsw_status_t fsw_status, FSW_VOLUME_DATA *Volume) { switch (fsw_status) { case FSW_SUCCESS: return EFI_SUCCESS; case FSW_OUT_OF_MEMORY: return EFI_VOLUME_CORRUPTED; case FSW_IO_ERROR: return Volume->LastIOStatus; case FSW_UNSUPPORTED: return EFI_UNSUPPORTED; case FSW_NOT_FOUND: return EFI_NOT_FOUND; case FSW_VOLUME_CORRUPTED: return EFI_VOLUME_CORRUPTED; default: return EFI_DEVICE_ERROR; } } /** * File System EFI protocol, OpenVolume function. Creates a file handle for * the root directory and returns it. Note that this function may be called * multiple times and returns a new file handle each time. Each returned * handle is closed by the client using it. */ EFI_STATUS EFIAPI fsw_efi_FileSystem_OpenVolume(IN EFI_FILE_IO_INTERFACE *This, OUT EFI_FILE **Root) { EFI_STATUS Status; FSW_VOLUME_DATA *Volume = FSW_VOLUME_FROM_FILE_SYSTEM(This); #if DEBUG_LEVEL Print(L"fsw_efi_FileSystem_OpenVolume\n"); #endif fsw_efi_clear_cache(); Status = fsw_efi_dnode_to_FileHandle(Volume->vol->root, Root); return Status; } /** * File Handle EFI protocol, Open function. Dispatches the call * based on the kind of file handle. */ EFI_STATUS EFIAPI fsw_efi_FileHandle_Open(IN EFI_FILE *This, OUT EFI_FILE **NewHandle, IN CHAR16 *FileName, IN UINT64 OpenMode, IN UINT64 Attributes) { FSW_FILE_DATA *File = FSW_FILE_FROM_FILE_HANDLE(This); if (File->Type == FSW_EFI_FILE_TYPE_DIR) return fsw_efi_dir_open(File, NewHandle, FileName, OpenMode, Attributes); // not supported for regular files return EFI_UNSUPPORTED; } /** * File Handle EFI protocol, Close function. Closes the FSW shandle * and frees the memory used for the structure. */ EFI_STATUS EFIAPI fsw_efi_FileHandle_Close(IN EFI_FILE *This) { FSW_FILE_DATA *File = FSW_FILE_FROM_FILE_HANDLE(This); #if DEBUG_LEVEL Print(L"fsw_efi_FileHandle_Close\n"); #endif fsw_shandle_close(&File->shand); FreePool(File); return EFI_SUCCESS; } /** * File Handle EFI protocol, Delete function. Calls through to Close * and returns a warning because this driver is read-only. */ EFI_STATUS EFIAPI fsw_efi_FileHandle_Delete(IN EFI_FILE *This) { EFI_STATUS Status; Status = refit_call1_wrapper(This->Close, This); if (Status == EFI_SUCCESS) { // this driver is read-only Status = EFI_WARN_DELETE_FAILURE; } return Status; } /** * File Handle EFI protocol, Read function. Dispatches the call * based on the kind of file handle. */ EFI_STATUS EFIAPI fsw_efi_FileHandle_Read(IN EFI_FILE *This, IN OUT UINTN *BufferSize, OUT VOID *Buffer) { FSW_FILE_DATA *File = FSW_FILE_FROM_FILE_HANDLE(This); if (File->Type == FSW_EFI_FILE_TYPE_FILE) return fsw_efi_file_read(File, BufferSize, Buffer); else if (File->Type == FSW_EFI_FILE_TYPE_DIR) return fsw_efi_dir_read(File, BufferSize, Buffer); return EFI_UNSUPPORTED; } /** * File Handle EFI protocol, Write function. Returns unsupported status * because this driver is read-only. */ EFI_STATUS EFIAPI fsw_efi_FileHandle_Write(IN EFI_FILE *This, IN OUT UINTN *BufferSize, IN VOID *Buffer) { // this driver is read-only return EFI_WRITE_PROTECTED; } /** * File Handle EFI protocol, GetPosition function. Dispatches the call * based on the kind of file handle. */ EFI_STATUS EFIAPI fsw_efi_FileHandle_GetPosition(IN EFI_FILE *This, OUT UINT64 *Position) { FSW_FILE_DATA *File = FSW_FILE_FROM_FILE_HANDLE(This); if (File->Type == FSW_EFI_FILE_TYPE_FILE) return fsw_efi_file_getpos(File, Position); // not defined for directories return EFI_UNSUPPORTED; } /** * File Handle EFI protocol, SetPosition function. Dispatches the call * based on the kind of file handle. */ EFI_STATUS EFIAPI fsw_efi_FileHandle_SetPosition(IN EFI_FILE *This, IN UINT64 Position) { FSW_FILE_DATA *File = FSW_FILE_FROM_FILE_HANDLE(This); if (File->Type == FSW_EFI_FILE_TYPE_FILE) return fsw_efi_file_setpos(File, Position); else if (File->Type == FSW_EFI_FILE_TYPE_DIR) return fsw_efi_dir_setpos(File, Position); return EFI_UNSUPPORTED; } /** * File Handle EFI protocol, GetInfo function. Dispatches to the common * function implementing this. */ EFI_STATUS EFIAPI fsw_efi_FileHandle_GetInfo(IN EFI_FILE *This, IN EFI_GUID *InformationType, IN OUT UINTN *BufferSize, OUT VOID *Buffer) { FSW_FILE_DATA *File = FSW_FILE_FROM_FILE_HANDLE(This); return fsw_efi_dnode_getinfo(File, InformationType, BufferSize, Buffer); } /** * File Handle EFI protocol, SetInfo function. Returns unsupported status * because this driver is read-only. */ EFI_STATUS EFIAPI fsw_efi_FileHandle_SetInfo(IN EFI_FILE *This, IN EFI_GUID *InformationType, IN UINTN BufferSize, IN VOID *Buffer) { // this driver is read-only return EFI_WRITE_PROTECTED; } /** * File Handle EFI protocol, Flush function. Returns unsupported status * because this driver is read-only. */ EFI_STATUS EFIAPI fsw_efi_FileHandle_Flush(IN EFI_FILE *This) { // this driver is read-only return EFI_WRITE_PROTECTED; } /** * Set up a file handle for a dnode. This function allocates a data structure * for a file handle, opens a FSW shandle and populates the EFI_FILE structure * with the interface functions. */ EFI_STATUS fsw_efi_dnode_to_FileHandle(IN struct fsw_dnode *dno, OUT EFI_FILE **NewFileHandle) { EFI_STATUS Status; FSW_FILE_DATA *File; // make sure the dnode has complete info Status = fsw_efi_map_status(fsw_dnode_fill(dno), (FSW_VOLUME_DATA *)dno->vol->host_data); if (EFI_ERROR(Status)) return Status; // check type if (dno->type != FSW_DNODE_TYPE_FILE && dno->type != FSW_DNODE_TYPE_DIR) return EFI_UNSUPPORTED; // allocate file structure File = AllocateZeroPool(sizeof(FSW_FILE_DATA)); File->Signature = FSW_FILE_DATA_SIGNATURE; if (dno->type == FSW_DNODE_TYPE_FILE) File->Type = FSW_EFI_FILE_TYPE_FILE; else if (dno->type == FSW_DNODE_TYPE_DIR) File->Type = FSW_EFI_FILE_TYPE_DIR; // open shandle Status = fsw_efi_map_status(fsw_shandle_open(dno, &File->shand), (FSW_VOLUME_DATA *)dno->vol->host_data); if (EFI_ERROR(Status)) { FreePool(File); return Status; } // populate the file handle File->FileHandle.Revision = EFI_FILE_HANDLE_REVISION; File->FileHandle.Open = fsw_efi_FileHandle_Open; File->FileHandle.Close = fsw_efi_FileHandle_Close; File->FileHandle.Delete = fsw_efi_FileHandle_Delete; File->FileHandle.Read = fsw_efi_FileHandle_Read; File->FileHandle.Write = fsw_efi_FileHandle_Write; File->FileHandle.GetPosition = fsw_efi_FileHandle_GetPosition; File->FileHandle.SetPosition = fsw_efi_FileHandle_SetPosition; File->FileHandle.GetInfo = fsw_efi_FileHandle_GetInfo; File->FileHandle.SetInfo = fsw_efi_FileHandle_SetInfo; File->FileHandle.Flush = fsw_efi_FileHandle_Flush; *NewFileHandle = &File->FileHandle; return EFI_SUCCESS; } /** * Data read function for regular files. Calls through to fsw_shandle_read. */ EFI_STATUS fsw_efi_file_read(IN FSW_FILE_DATA *File, IN OUT UINTN *BufferSize, OUT VOID *Buffer) { EFI_STATUS Status; fsw_u32 buffer_size; #if DEBUG_LEVEL Print(L"fsw_efi_file_read %d bytes\n", *BufferSize); #endif buffer_size = (fsw_u32)*BufferSize; Status = fsw_efi_map_status(fsw_shandle_read(&File->shand, &buffer_size, Buffer), (FSW_VOLUME_DATA *)File->shand.dnode->vol->host_data); *BufferSize = buffer_size; return Status; } /** * Get file position for regular files. */ EFI_STATUS fsw_efi_file_getpos(IN FSW_FILE_DATA *File, OUT UINT64 *Position) { *Position = File->shand.pos; return EFI_SUCCESS; } /** * Set file position for regular files. EFI specifies the all-ones value * to be a special value for the end of the file. */ EFI_STATUS fsw_efi_file_setpos(IN FSW_FILE_DATA *File, IN UINT64 Position) { if (Position == 0xFFFFFFFFFFFFFFFFULL) File->shand.pos = File->shand.dnode->size; else File->shand.pos = Position; return EFI_SUCCESS; } /** * Open function used to open new file handles relative to a directory. * In EFI, the "open file" function is implemented by directory file handles * and is passed a relative or volume-absolute path to the file or directory * to open. We use fsw_dnode_lookup_path to find the node plus an additional * call to fsw_dnode_resolve because EFI has no concept of symbolic links. */ EFI_STATUS fsw_efi_dir_open(IN FSW_FILE_DATA *File, OUT EFI_FILE **NewHandle, IN CHAR16 *FileName, IN UINT64 OpenMode, IN UINT64 Attributes) { EFI_STATUS Status; FSW_VOLUME_DATA *Volume = (FSW_VOLUME_DATA *)File->shand.dnode->vol->host_data; struct fsw_dnode *dno; struct fsw_dnode *target_dno; struct fsw_string lookup_path; #if DEBUG_LEVEL Print(L"fsw_efi_dir_open: '%s'\n", FileName); #endif if (OpenMode != EFI_FILE_MODE_READ) return EFI_WRITE_PROTECTED; lookup_path.type = FSW_STRING_TYPE_UTF16; lookup_path.len = (int)StrLen(FileName); lookup_path.size = lookup_path.len * sizeof(fsw_u16); lookup_path.data = FileName; // resolve the path (symlinks along the way are automatically resolved) Status = fsw_efi_map_status(fsw_dnode_lookup_path(File->shand.dnode, &lookup_path, '\\', &dno), Volume); if (EFI_ERROR(Status)) return Status; // if the final node is a symlink, also resolve it Status = fsw_efi_map_status(fsw_dnode_resolve(dno, &target_dno), Volume); fsw_dnode_release(dno); if (EFI_ERROR(Status)) return Status; dno = target_dno; // make a new EFI handle for the target dnode Status = fsw_efi_dnode_to_FileHandle(dno, NewHandle); fsw_dnode_release(dno); return Status; } /** * Read function for directories. A file handle read on a directory retrieves * the next directory entry. */ EFI_STATUS fsw_efi_dir_read(IN FSW_FILE_DATA *File, IN OUT UINTN *BufferSize, OUT VOID *Buffer) { EFI_STATUS Status; FSW_VOLUME_DATA *Volume = (FSW_VOLUME_DATA *)File->shand.dnode->vol->host_data; struct fsw_dnode *dno; #if DEBUG_LEVEL Print(L"fsw_efi_dir_read...\n"); #endif // read the next entry Status = fsw_efi_map_status(fsw_dnode_dir_read(&File->shand, &dno), Volume); if (Status == EFI_NOT_FOUND) { // end of directory *BufferSize = 0; #if DEBUG_LEVEL Print(L"...no more entries\n"); #endif return EFI_SUCCESS; } if (EFI_ERROR(Status)) return Status; // get info into buffer Status = fsw_efi_dnode_fill_FileInfo(Volume, dno, BufferSize, Buffer); fsw_dnode_release(dno); return Status; } /** * Set file position for directories. The only allowed set position operation * for directories is to rewind the directory completely by setting the * position to zero. */ EFI_STATUS fsw_efi_dir_setpos(IN FSW_FILE_DATA *File, IN UINT64 Position) { if (Position == 0) { File->shand.pos = 0; return EFI_SUCCESS; } else { // directories can only rewind to the start return EFI_UNSUPPORTED; } } /** * Get file or volume information. This function implements the GetInfo call * for all file handles. Control is dispatched according to the type of information * requested by the caller. */ EFI_STATUS fsw_efi_dnode_getinfo(IN FSW_FILE_DATA *File, IN EFI_GUID *InformationType, IN OUT UINTN *BufferSize, OUT VOID *Buffer) { EFI_STATUS Status; FSW_VOLUME_DATA *Volume = (FSW_VOLUME_DATA *)File->shand.dnode->vol->host_data; EFI_FILE_SYSTEM_INFO *FSInfo; UINTN RequiredSize; struct fsw_volume_stat vsb; if (CompareGuid(InformationType, &gMyEfiFileInfoGuid)) { #if DEBUG_LEVEL Print(L"fsw_efi_dnode_getinfo: FILE_INFO\n"); #endif Status = fsw_efi_dnode_fill_FileInfo(Volume, File->shand.dnode, BufferSize, Buffer); } else if (CompareGuid(InformationType, &gMyEfiFileSystemInfoGuid)) { #if DEBUG_LEVEL Print(L"fsw_efi_dnode_getinfo: FILE_SYSTEM_INFO\n"); #endif // check buffer size RequiredSize = SIZE_OF_EFI_FILE_SYSTEM_INFO + fsw_efi_strsize(&Volume->vol->label); if (*BufferSize < RequiredSize) { *BufferSize = RequiredSize; return EFI_BUFFER_TOO_SMALL; } // fill structure FSInfo = (EFI_FILE_SYSTEM_INFO *)Buffer; FSInfo->Size = RequiredSize; FSInfo->ReadOnly = TRUE; FSInfo->BlockSize = Volume->vol->log_blocksize; fsw_efi_strcpy(FSInfo->VolumeLabel, &Volume->vol->label); // get the missing info from the fs driver ZeroMem(&vsb, sizeof(struct fsw_volume_stat)); Status = fsw_efi_map_status(fsw_volume_stat(Volume->vol, &vsb), Volume); if (EFI_ERROR(Status)) return Status; FSInfo->VolumeSize = vsb.total_bytes; FSInfo->FreeSpace = vsb.free_bytes; // prepare for return *BufferSize = RequiredSize; Status = EFI_SUCCESS; } else if (CompareGuid(InformationType, &gMyEfiFileSystemVolumeLabelInfoIdGuid)) { #if DEBUG_LEVEL Print(L"fsw_efi_dnode_getinfo: FILE_SYSTEM_VOLUME_LABEL\n"); #endif // check buffer size RequiredSize = SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL_INFO + fsw_efi_strsize(&Volume->vol->label); if (*BufferSize < RequiredSize) { *BufferSize = RequiredSize; return EFI_BUFFER_TOO_SMALL; } // copy volume label fsw_efi_strcpy(((EFI_FILE_SYSTEM_VOLUME_LABEL_INFO *)Buffer)->VolumeLabel, &Volume->vol->label); // prepare for return *BufferSize = RequiredSize; Status = EFI_SUCCESS; } else { Status = EFI_UNSUPPORTED; } return Status; } /** * Time mapping callback for the fsw_dnode_stat call. This function converts * a Posix style timestamp into an EFI_TIME structure and writes it to the * appropriate member of the EFI_FILE_INFO structure that we're filling. */ void fsw_store_time_posix(struct fsw_dnode_stat *sb, int which, fsw_u32 posix_time) { EFI_FILE_INFO *FileInfo = (EFI_FILE_INFO *)sb->host_data; if (which == FSW_DNODE_STAT_CTIME) fsw_efi_decode_time(&FileInfo->CreateTime, posix_time); else if (which == FSW_DNODE_STAT_MTIME) fsw_efi_decode_time(&FileInfo->ModificationTime, posix_time); else if (which == FSW_DNODE_STAT_ATIME) fsw_efi_decode_time(&FileInfo->LastAccessTime, posix_time); } /** * Mode mapping callback for the fsw_dnode_stat call. This function looks at * the Posix mode passed by the file system driver and makes appropriate * adjustments to the EFI_FILE_INFO structure that we're filling. */ void fsw_store_attr_posix(struct fsw_dnode_stat *sb, fsw_u16 posix_mode) { EFI_FILE_INFO *FileInfo = (EFI_FILE_INFO *)sb->host_data; if ((posix_mode & S_IWUSR) == 0) FileInfo->Attribute |= EFI_FILE_READ_ONLY; } void fsw_store_attr_efi(struct fsw_dnode_stat *sb, fsw_u16 attr) { EFI_FILE_INFO *FileInfo = (EFI_FILE_INFO *)sb->host_data; FileInfo->Attribute |= attr; } /** * Common function to fill an EFI_FILE_INFO with information about a dnode. */ EFI_STATUS fsw_efi_dnode_fill_FileInfo(IN FSW_VOLUME_DATA *Volume, IN struct fsw_dnode *dno, IN OUT UINTN *BufferSize, OUT VOID *Buffer) { EFI_STATUS Status; EFI_FILE_INFO *FileInfo; UINTN RequiredSize; struct fsw_dnode_stat sb; // make sure the dnode has complete info Status = fsw_efi_map_status(fsw_dnode_fill(dno), Volume); if (EFI_ERROR(Status)) return Status; // TODO: check/assert that the dno's name is in UTF16 // check buffer size RequiredSize = SIZE_OF_EFI_FILE_INFO + fsw_efi_strsize(&dno->name); if (*BufferSize < RequiredSize) { // TODO: wind back the directory in this case #if DEBUG_LEVEL Print(L"...BUFFER TOO SMALL\n"); #endif *BufferSize = RequiredSize; return EFI_BUFFER_TOO_SMALL; } // fill structure ZeroMem(Buffer, RequiredSize); FileInfo = (EFI_FILE_INFO *)Buffer; FileInfo->Size = RequiredSize; FileInfo->FileSize = dno->size; FileInfo->Attribute = 0; if (dno->type == FSW_DNODE_TYPE_DIR) FileInfo->Attribute |= EFI_FILE_DIRECTORY; fsw_efi_strcpy(FileInfo->FileName, &dno->name); // get the missing info from the fs driver ZeroMem(&sb, sizeof(struct fsw_dnode_stat)); sb.host_data = FileInfo; Status = fsw_efi_map_status(fsw_dnode_stat(dno, &sb), Volume); if (EFI_ERROR(Status)) return Status; FileInfo->PhysicalSize = sb.used_bytes; // prepare for return *BufferSize = RequiredSize; #if DEBUG_LEVEL Print(L"...returning '%s'\n", FileInfo->FileName); #endif return EFI_SUCCESS; } // EOF ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/minilzo.c�����������������������������������������������������������������0000664�0001750�0001750�00000422327�12626644770�017536� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * this file take from grub 2.0 * for btrfs UEFI driver */ /* minilzo.c -- mini subset of the LZO real-time data compression library This file is part of the LZO real-time data compression library. Copyright (C) 2011 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2010 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2009 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer All Rights Reserved. The LZO library is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The LZO library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the LZO library; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Markus F.X.J. Oberhumer <markus@oberhumer.com> http://www.oberhumer.com/opensource/lzo/ */ /* * NOTE: * the full LZO package can be found at * http://www.oberhumer.com/opensource/lzo/ */ #define __LZO_IN_MINILZO 1 #if defined(LZO_CFG_FREESTANDING) # undef MINILZO_HAVE_CONFIG_H # define LZO_LIBC_FREESTANDING 1 # define LZO_OS_FREESTANDING 1 #endif #ifdef MINILZO_HAVE_CONFIG_H # include <config.h> #endif #include <limits.h> #include <stddef.h> #if defined(MINILZO_CFG_USE_INTERNAL_LZODEFS) #ifndef __LZODEFS_H_INCLUDED #define __LZODEFS_H_INCLUDED 1 #if defined(__CYGWIN32__) && !defined(__CYGWIN__) # define __CYGWIN__ __CYGWIN32__ #endif #if defined(__IBMCPP__) && !defined(__IBMC__) # define __IBMC__ __IBMCPP__ #endif #if defined(__ICL) && defined(_WIN32) && !defined(__INTEL_COMPILER) # define __INTEL_COMPILER __ICL #endif #if 1 && defined(__INTERIX) && defined(__GNUC__) && !defined(_ALL_SOURCE) # define _ALL_SOURCE 1 #endif #if defined(__mips__) && defined(__R5900__) # if !defined(__LONG_MAX__) # define __LONG_MAX__ 9223372036854775807L # endif #endif #if defined(__INTEL_COMPILER) && defined(__linux__) # pragma warning(disable: 193) #endif #if defined(__KEIL__) && defined(__C166__) # pragma warning disable = 322 #elif 0 && defined(__C251__) # pragma warning disable = 322 #endif #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__MWERKS__) # if (_MSC_VER >= 1300) # pragma warning(disable: 4668) # endif #endif #if 0 && defined(__WATCOMC__) # if (__WATCOMC__ >= 1050) && (__WATCOMC__ < 1060) # pragma warning 203 9 # endif #endif #if defined(__BORLANDC__) && defined(__MSDOS__) && !defined(__FLAT__) # pragma option -h #endif #if 0 #define LZO_0xffffL 0xfffful #define LZO_0xffffffffL 0xfffffffful #else #define LZO_0xffffL 65535ul #define LZO_0xffffffffL 4294967295ul #endif #if (LZO_0xffffL == LZO_0xffffffffL) # error "your preprocessor is broken 1" #endif #if (16ul * 16384ul != 262144ul) # error "your preprocessor is broken 2" #endif #if 0 #if (32767 >= 4294967295ul) # error "your preprocessor is broken 3" #endif #if (65535u >= 4294967295ul) # error "your preprocessor is broken 4" #endif #endif #if (UINT_MAX == LZO_0xffffL) #if defined(__ZTC__) && defined(__I86__) && !defined(__OS2__) # if !defined(MSDOS) # define MSDOS 1 # endif # if !defined(_MSDOS) # define _MSDOS 1 # endif #elif 0 && defined(__VERSION) && defined(MB_LEN_MAX) # if (__VERSION == 520) && (MB_LEN_MAX == 1) # if !defined(__AZTEC_C__) # define __AZTEC_C__ __VERSION # endif # if !defined(__DOS__) # define __DOS__ 1 # endif # endif #endif #endif #if defined(_MSC_VER) && defined(M_I86HM) && (UINT_MAX == LZO_0xffffL) # define ptrdiff_t long # define _PTRDIFF_T_DEFINED 1 #endif #if (UINT_MAX == LZO_0xffffL) # undef __LZO_RENAME_A # undef __LZO_RENAME_B # if defined(__AZTEC_C__) && defined(__DOS__) # define __LZO_RENAME_A 1 # elif defined(_MSC_VER) && defined(MSDOS) # if (_MSC_VER < 600) # define __LZO_RENAME_A 1 # elif (_MSC_VER < 700) # define __LZO_RENAME_B 1 # endif # elif defined(__TSC__) && defined(__OS2__) # define __LZO_RENAME_A 1 # elif defined(__MSDOS__) && defined(__TURBOC__) && (__TURBOC__ < 0x0410) # define __LZO_RENAME_A 1 # elif defined(__PACIFIC__) && defined(DOS) # if !defined(__far) # define __far far # endif # if !defined(__near) # define __near near # endif # endif # if defined(__LZO_RENAME_A) # if !defined(__cdecl) # define __cdecl cdecl # endif # if !defined(__far) # define __far far # endif # if !defined(__huge) # define __huge huge # endif # if !defined(__near) # define __near near # endif # if !defined(__pascal) # define __pascal pascal # endif # if !defined(__huge) # define __huge huge # endif # elif defined(__LZO_RENAME_B) # if !defined(__cdecl) # define __cdecl _cdecl # endif # if !defined(__far) # define __far _far # endif # if !defined(__huge) # define __huge _huge # endif # if !defined(__near) # define __near _near # endif # if !defined(__pascal) # define __pascal _pascal # endif # elif (defined(__PUREC__) || defined(__TURBOC__)) && defined(__TOS__) # if !defined(__cdecl) # define __cdecl cdecl # endif # if !defined(__pascal) # define __pascal pascal # endif # endif # undef __LZO_RENAME_A # undef __LZO_RENAME_B #endif #if (UINT_MAX == LZO_0xffffL) #if defined(__AZTEC_C__) && defined(__DOS__) # define LZO_BROKEN_CDECL_ALT_SYNTAX 1 #elif defined(_MSC_VER) && defined(MSDOS) # if (_MSC_VER < 600) # define LZO_BROKEN_INTEGRAL_CONSTANTS 1 # endif # if (_MSC_VER < 700) # define LZO_BROKEN_INTEGRAL_PROMOTION 1 # define LZO_BROKEN_SIZEOF 1 # endif #elif defined(__PACIFIC__) && defined(DOS) # define LZO_BROKEN_INTEGRAL_CONSTANTS 1 #elif defined(__TURBOC__) && defined(__MSDOS__) # if (__TURBOC__ < 0x0150) # define LZO_BROKEN_CDECL_ALT_SYNTAX 1 # define LZO_BROKEN_INTEGRAL_CONSTANTS 1 # define LZO_BROKEN_INTEGRAL_PROMOTION 1 # endif # if (__TURBOC__ < 0x0200) # define LZO_BROKEN_SIZEOF 1 # endif # if (__TURBOC__ < 0x0400) && defined(__cplusplus) # define LZO_BROKEN_CDECL_ALT_SYNTAX 1 # endif #elif (defined(__PUREC__) || defined(__TURBOC__)) && defined(__TOS__) # define LZO_BROKEN_CDECL_ALT_SYNTAX 1 # define LZO_BROKEN_SIZEOF 1 #endif #endif #if defined(__WATCOMC__) && (__WATCOMC__ < 900) # define LZO_BROKEN_INTEGRAL_CONSTANTS 1 #endif #if defined(_CRAY) && defined(_CRAY1) # define LZO_BROKEN_SIGNED_RIGHT_SHIFT 1 #endif #define LZO_PP_STRINGIZE(x) #x #define LZO_PP_MACRO_EXPAND(x) LZO_PP_STRINGIZE(x) #define LZO_PP_CONCAT2(a,b) a ## b #define LZO_PP_CONCAT3(a,b,c) a ## b ## c #define LZO_PP_CONCAT4(a,b,c,d) a ## b ## c ## d #define LZO_PP_CONCAT5(a,b,c,d,e) a ## b ## c ## d ## e #define LZO_PP_ECONCAT2(a,b) LZO_PP_CONCAT2(a,b) #define LZO_PP_ECONCAT3(a,b,c) LZO_PP_CONCAT3(a,b,c) #define LZO_PP_ECONCAT4(a,b,c,d) LZO_PP_CONCAT4(a,b,c,d) #define LZO_PP_ECONCAT5(a,b,c,d,e) LZO_PP_CONCAT5(a,b,c,d,e) #if 1 #define LZO_CPP_STRINGIZE(x) #x #define LZO_CPP_MACRO_EXPAND(x) LZO_CPP_STRINGIZE(x) #define LZO_CPP_CONCAT2(a,b) a ## b #define LZO_CPP_CONCAT3(a,b,c) a ## b ## c #define LZO_CPP_CONCAT4(a,b,c,d) a ## b ## c ## d #define LZO_CPP_CONCAT5(a,b,c,d,e) a ## b ## c ## d ## e #define LZO_CPP_ECONCAT2(a,b) LZO_CPP_CONCAT2(a,b) #define LZO_CPP_ECONCAT3(a,b,c) LZO_CPP_CONCAT3(a,b,c) #define LZO_CPP_ECONCAT4(a,b,c,d) LZO_CPP_CONCAT4(a,b,c,d) #define LZO_CPP_ECONCAT5(a,b,c,d,e) LZO_CPP_CONCAT5(a,b,c,d,e) #endif #define __LZO_MASK_GEN(o,b) (((((o) << ((b)-1)) - (o)) << 1) + (o)) #if 1 && defined(__cplusplus) # if !defined(__STDC_CONSTANT_MACROS) # define __STDC_CONSTANT_MACROS 1 # endif # if !defined(__STDC_LIMIT_MACROS) # define __STDC_LIMIT_MACROS 1 # endif #endif #if defined(__cplusplus) # define LZO_EXTERN_C extern "C" #else # define LZO_EXTERN_C extern #endif #if !defined(__LZO_OS_OVERRIDE) #if (LZO_OS_FREESTANDING) # define LZO_INFO_OS "freestanding" #elif (LZO_OS_EMBEDDED) # define LZO_INFO_OS "embedded" #elif 1 && defined(__IAR_SYSTEMS_ICC__) # define LZO_OS_EMBEDDED 1 # define LZO_INFO_OS "embedded" #elif defined(__CYGWIN__) && defined(__GNUC__) # define LZO_OS_CYGWIN 1 # define LZO_INFO_OS "cygwin" #elif defined(__EMX__) && defined(__GNUC__) # define LZO_OS_EMX 1 # define LZO_INFO_OS "emx" #elif defined(__BEOS__) # define LZO_OS_BEOS 1 # define LZO_INFO_OS "beos" #elif defined(__Lynx__) # define LZO_OS_LYNXOS 1 # define LZO_INFO_OS "lynxos" #elif defined(__OS400__) # define LZO_OS_OS400 1 # define LZO_INFO_OS "os400" #elif defined(__QNX__) # define LZO_OS_QNX 1 # define LZO_INFO_OS "qnx" #elif defined(__BORLANDC__) && defined(__DPMI32__) && (__BORLANDC__ >= 0x0460) # define LZO_OS_DOS32 1 # define LZO_INFO_OS "dos32" #elif defined(__BORLANDC__) && defined(__DPMI16__) # define LZO_OS_DOS16 1 # define LZO_INFO_OS "dos16" #elif defined(__ZTC__) && defined(DOS386) # define LZO_OS_DOS32 1 # define LZO_INFO_OS "dos32" #elif defined(__OS2__) || defined(__OS2V2__) # if (UINT_MAX == LZO_0xffffL) # define LZO_OS_OS216 1 # define LZO_INFO_OS "os216" # elif (UINT_MAX == LZO_0xffffffffL) # define LZO_OS_OS2 1 # define LZO_INFO_OS "os2" # else # error "check your limits.h header" # endif #elif defined(__WIN64__) || defined(_WIN64) || defined(WIN64) # define LZO_OS_WIN64 1 # define LZO_INFO_OS "win64" #elif defined(__WIN32__) || defined(_WIN32) || defined(WIN32) || defined(__WINDOWS_386__) # define LZO_OS_WIN32 1 # define LZO_INFO_OS "win32" #elif defined(__MWERKS__) && defined(__INTEL__) # define LZO_OS_WIN32 1 # define LZO_INFO_OS "win32" #elif defined(__WINDOWS__) || defined(_WINDOWS) || defined(_Windows) # if (UINT_MAX == LZO_0xffffL) # define LZO_OS_WIN16 1 # define LZO_INFO_OS "win16" # elif (UINT_MAX == LZO_0xffffffffL) # define LZO_OS_WIN32 1 # define LZO_INFO_OS "win32" # else # error "check your limits.h header" # endif #elif defined(__DOS__) || defined(__MSDOS__) || defined(_MSDOS) || defined(MSDOS) || (defined(__PACIFIC__) && defined(DOS)) # if (UINT_MAX == LZO_0xffffL) # define LZO_OS_DOS16 1 # define LZO_INFO_OS "dos16" # elif (UINT_MAX == LZO_0xffffffffL) # define LZO_OS_DOS32 1 # define LZO_INFO_OS "dos32" # else # error "check your limits.h header" # endif #elif defined(__WATCOMC__) # if defined(__NT__) && (UINT_MAX == LZO_0xffffL) # define LZO_OS_DOS16 1 # define LZO_INFO_OS "dos16" # elif defined(__NT__) && (__WATCOMC__ < 1100) # define LZO_OS_WIN32 1 # define LZO_INFO_OS "win32" # elif defined(__linux__) || defined(__LINUX__) # define LZO_OS_POSIX 1 # define LZO_INFO_OS "posix" # else # error "please specify a target using the -bt compiler option" # endif #elif defined(__palmos__) # define LZO_OS_PALMOS 1 # define LZO_INFO_OS "palmos" #elif defined(__TOS__) || defined(__atarist__) # define LZO_OS_TOS 1 # define LZO_INFO_OS "tos" #elif defined(macintosh) && !defined(__ppc__) # define LZO_OS_MACCLASSIC 1 # define LZO_INFO_OS "macclassic" #elif defined(__VMS) # define LZO_OS_VMS 1 # define LZO_INFO_OS "vms" #elif ((defined(__mips__) && defined(__R5900__)) || defined(__MIPS_PSX2__)) # define LZO_OS_CONSOLE 1 # define LZO_OS_CONSOLE_PS2 1 # define LZO_INFO_OS "console" # define LZO_INFO_OS_CONSOLE "ps2" #elif (defined(__mips__) && defined(__psp__)) # define LZO_OS_CONSOLE 1 # define LZO_OS_CONSOLE_PSP 1 # define LZO_INFO_OS "console" # define LZO_INFO_OS_CONSOLE "psp" #else # define LZO_OS_POSIX 1 # define LZO_INFO_OS "posix" #endif #if (LZO_OS_POSIX) # if defined(_AIX) || defined(__AIX__) || defined(__aix__) # define LZO_OS_POSIX_AIX 1 # define LZO_INFO_OS_POSIX "aix" # elif defined(__FreeBSD__) # define LZO_OS_POSIX_FREEBSD 1 # define LZO_INFO_OS_POSIX "freebsd" # elif defined(__hpux__) || defined(__hpux) # define LZO_OS_POSIX_HPUX 1 # define LZO_INFO_OS_POSIX "hpux" # elif defined(__INTERIX) # define LZO_OS_POSIX_INTERIX 1 # define LZO_INFO_OS_POSIX "interix" # elif defined(__IRIX__) || defined(__irix__) # define LZO_OS_POSIX_IRIX 1 # define LZO_INFO_OS_POSIX "irix" # elif defined(__linux__) || defined(__linux) || defined(__LINUX__) # define LZO_OS_POSIX_LINUX 1 # define LZO_INFO_OS_POSIX "linux" # elif defined(__APPLE__) || defined(__MACOS__) # define LZO_OS_POSIX_MACOSX 1 # define LZO_INFO_OS_POSIX "macosx" # elif defined(__minix__) || defined(__minix) # define LZO_OS_POSIX_MINIX 1 # define LZO_INFO_OS_POSIX "minix" # elif defined(__NetBSD__) # define LZO_OS_POSIX_NETBSD 1 # define LZO_INFO_OS_POSIX "netbsd" # elif defined(__OpenBSD__) # define LZO_OS_POSIX_OPENBSD 1 # define LZO_INFO_OS_POSIX "openbsd" # elif defined(__osf__) # define LZO_OS_POSIX_OSF 1 # define LZO_INFO_OS_POSIX "osf" # elif defined(__solaris__) || defined(__sun) # if defined(__SVR4) || defined(__svr4__) # define LZO_OS_POSIX_SOLARIS 1 # define LZO_INFO_OS_POSIX "solaris" # else # define LZO_OS_POSIX_SUNOS 1 # define LZO_INFO_OS_POSIX "sunos" # endif # elif defined(__ultrix__) || defined(__ultrix) # define LZO_OS_POSIX_ULTRIX 1 # define LZO_INFO_OS_POSIX "ultrix" # elif defined(_UNICOS) # define LZO_OS_POSIX_UNICOS 1 # define LZO_INFO_OS_POSIX "unicos" # else # define LZO_OS_POSIX_UNKNOWN 1 # define LZO_INFO_OS_POSIX "unknown" # endif #endif #endif #if (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16) # if (UINT_MAX != LZO_0xffffL) # error "this should not happen" # endif # if (ULONG_MAX != LZO_0xffffffffL) # error "this should not happen" # endif #endif #if (LZO_OS_DOS32 || LZO_OS_OS2 || LZO_OS_WIN32 || LZO_OS_WIN64) # if (UINT_MAX != LZO_0xffffffffL) # error "this should not happen" # endif # if (ULONG_MAX != LZO_0xffffffffL) # error "this should not happen" # endif #endif #if defined(CIL) && defined(_GNUCC) && defined(__GNUC__) # define LZO_CC_CILLY 1 # define LZO_INFO_CC "Cilly" # if defined(__CILLY__) # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__CILLY__) # else # define LZO_INFO_CCVER "unknown" # endif #elif 0 && defined(SDCC) && defined(__VERSION__) && !defined(__GNUC__) # define LZO_CC_SDCC 1 # define LZO_INFO_CC "sdcc" # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(SDCC) #elif defined(__PATHSCALE__) && defined(__PATHCC_PATCHLEVEL__) # define LZO_CC_PATHSCALE (__PATHCC__ * 0x10000L + __PATHCC_MINOR__ * 0x100 + __PATHCC_PATCHLEVEL__) # define LZO_INFO_CC "Pathscale C" # define LZO_INFO_CCVER __PATHSCALE__ #elif defined(__INTEL_COMPILER) # define LZO_CC_INTELC 1 # define LZO_INFO_CC "Intel C" # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__INTEL_COMPILER) # if defined(_WIN32) || defined(_WIN64) # define LZO_CC_SYNTAX_MSC 1 # else # define LZO_CC_SYNTAX_GNUC 1 # endif #elif defined(__POCC__) && defined(_WIN32) # define LZO_CC_PELLESC 1 # define LZO_INFO_CC "Pelles C" # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__POCC__) #elif defined(__clang__) && defined(__llvm__) && defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__) # if defined(__GNUC_PATCHLEVEL__) # define LZO_CC_CLANG_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__) # else # define LZO_CC_CLANG_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100) # endif # if defined(__clang_major__) && defined(__clang_minor__) && defined(__clang_patchlevel__) # define LZO_CC_CLANG_CLANG (__clang_major__ * 0x10000L + __clang_minor__ * 0x100 + __clang_patchlevel__) # else # define LZO_CC_CLANG_CLANG 0x010000L # endif # define LZO_CC_CLANG LZO_CC_CLANG_GNUC # define LZO_INFO_CC "clang" # define LZO_INFO_CCVER __VERSION__ #elif defined(__llvm__) && defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__) # if defined(__GNUC_PATCHLEVEL__) # define LZO_CC_LLVM_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__) # else # define LZO_CC_LLVM_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100) # endif # define LZO_CC_LLVM LZO_CC_LLVM_GNUC # define LZO_INFO_CC "llvm-gcc" # define LZO_INFO_CCVER __VERSION__ #elif defined(__GNUC__) && defined(__VERSION__) # if defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) # define LZO_CC_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__) # elif defined(__GNUC_MINOR__) # define LZO_CC_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100) # else # define LZO_CC_GNUC (__GNUC__ * 0x10000L) # endif # define LZO_INFO_CC "gcc" # define LZO_INFO_CCVER __VERSION__ #elif defined(__ACK__) && defined(_ACK) # define LZO_CC_ACK 1 # define LZO_INFO_CC "Amsterdam Compiler Kit C" # define LZO_INFO_CCVER "unknown" #elif defined(__AZTEC_C__) # define LZO_CC_AZTECC 1 # define LZO_INFO_CC "Aztec C" # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__AZTEC_C__) #elif defined(__CODEGEARC__) # define LZO_CC_CODEGEARC 1 # define LZO_INFO_CC "CodeGear C" # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__CODEGEARC__) #elif defined(__BORLANDC__) # define LZO_CC_BORLANDC 1 # define LZO_INFO_CC "Borland C" # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__BORLANDC__) #elif defined(_CRAYC) && defined(_RELEASE) # define LZO_CC_CRAYC 1 # define LZO_INFO_CC "Cray C" # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(_RELEASE) #elif defined(__DMC__) && defined(__SC__) # define LZO_CC_DMC 1 # define LZO_INFO_CC "Digital Mars C" # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__DMC__) #elif defined(__DECC) # define LZO_CC_DECC 1 # define LZO_INFO_CC "DEC C" # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__DECC) #elif defined(__HIGHC__) # define LZO_CC_HIGHC 1 # define LZO_INFO_CC "MetaWare High C" # define LZO_INFO_CCVER "unknown" #elif defined(__IAR_SYSTEMS_ICC__) # define LZO_CC_IARC 1 # define LZO_INFO_CC "IAR C" # if defined(__VER__) # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__VER__) # else # define LZO_INFO_CCVER "unknown" # endif #elif defined(__IBMC__) # define LZO_CC_IBMC 1 # define LZO_INFO_CC "IBM C" # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__IBMC__) #elif defined(__KEIL__) && defined(__C166__) # define LZO_CC_KEILC 1 # define LZO_INFO_CC "Keil C" # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__C166__) #elif defined(__LCC__) && defined(_WIN32) && defined(__LCCOPTIMLEVEL) # define LZO_CC_LCCWIN32 1 # define LZO_INFO_CC "lcc-win32" # define LZO_INFO_CCVER "unknown" #elif defined(__LCC__) # define LZO_CC_LCC 1 # define LZO_INFO_CC "lcc" # if defined(__LCC_VERSION__) # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__LCC_VERSION__) # else # define LZO_INFO_CCVER "unknown" # endif #elif defined(_MSC_VER) # define LZO_CC_MSC 1 # define LZO_INFO_CC "Microsoft C" # if defined(_MSC_FULL_VER) # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(_MSC_VER) "." LZO_PP_MACRO_EXPAND(_MSC_FULL_VER) # else # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(_MSC_VER) # endif #elif defined(__MWERKS__) # define LZO_CC_MWERKS 1 # define LZO_INFO_CC "Metrowerks C" # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__MWERKS__) #elif (defined(__NDPC__) || defined(__NDPX__)) && defined(__i386) # define LZO_CC_NDPC 1 # define LZO_INFO_CC "Microway NDP C" # define LZO_INFO_CCVER "unknown" #elif defined(__PACIFIC__) # define LZO_CC_PACIFICC 1 # define LZO_INFO_CC "Pacific C" # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__PACIFIC__) #elif defined(__PGI) && (defined(__linux__) || defined(__WIN32__)) # define LZO_CC_PGI 1 # define LZO_INFO_CC "Portland Group PGI C" # define LZO_INFO_CCVER "unknown" #elif defined(__PUREC__) && defined(__TOS__) # define LZO_CC_PUREC 1 # define LZO_INFO_CC "Pure C" # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__PUREC__) #elif defined(__SC__) && defined(__ZTC__) # define LZO_CC_SYMANTECC 1 # define LZO_INFO_CC "Symantec C" # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__SC__) #elif defined(__SUNPRO_C) # define LZO_INFO_CC "SunPro C" # if ((__SUNPRO_C)+0 > 0) # define LZO_CC_SUNPROC __SUNPRO_C # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__SUNPRO_C) # else # define LZO_CC_SUNPROC 1 # define LZO_INFO_CCVER "unknown" # endif #elif defined(__SUNPRO_CC) # define LZO_INFO_CC "SunPro C" # if ((__SUNPRO_CC)+0 > 0) # define LZO_CC_SUNPROC __SUNPRO_CC # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__SUNPRO_CC) # else # define LZO_CC_SUNPROC 1 # define LZO_INFO_CCVER "unknown" # endif #elif defined(__TINYC__) # define LZO_CC_TINYC 1 # define LZO_INFO_CC "Tiny C" # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__TINYC__) #elif defined(__TSC__) # define LZO_CC_TOPSPEEDC 1 # define LZO_INFO_CC "TopSpeed C" # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__TSC__) #elif defined(__WATCOMC__) # define LZO_CC_WATCOMC 1 # define LZO_INFO_CC "Watcom C" # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__WATCOMC__) #elif defined(__TURBOC__) # define LZO_CC_TURBOC 1 # define LZO_INFO_CC "Turbo C" # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__TURBOC__) #elif defined(__ZTC__) # define LZO_CC_ZORTECHC 1 # define LZO_INFO_CC "Zortech C" # if (__ZTC__ == 0x310) # define LZO_INFO_CCVER "0x310" # else # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__ZTC__) # endif #else # define LZO_CC_UNKNOWN 1 # define LZO_INFO_CC "unknown" # define LZO_INFO_CCVER "unknown" #endif #if 0 && (LZO_CC_MSC && (_MSC_VER >= 1200)) && !defined(_MSC_FULL_VER) # error "LZO_CC_MSC: _MSC_FULL_VER is not defined" #endif #if !defined(__LZO_ARCH_OVERRIDE) && !(LZO_ARCH_GENERIC) && defined(_CRAY) # if (UINT_MAX > LZO_0xffffffffL) && defined(_CRAY) # if defined(_CRAYMPP) || defined(_CRAYT3D) || defined(_CRAYT3E) # define LZO_ARCH_CRAY_MPP 1 # elif defined(_CRAY1) # define LZO_ARCH_CRAY_PVP 1 # endif # endif #endif #if !defined(__LZO_ARCH_OVERRIDE) #if (LZO_ARCH_GENERIC) # define LZO_INFO_ARCH "generic" #elif (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16) # define LZO_ARCH_I086 1 # define LZO_ARCH_IA16 1 # define LZO_INFO_ARCH "i086" #elif defined(__alpha__) || defined(__alpha) || defined(_M_ALPHA) # define LZO_ARCH_ALPHA 1 # define LZO_INFO_ARCH "alpha" #elif (LZO_ARCH_CRAY_MPP) && (defined(_CRAYT3D) || defined(_CRAYT3E)) # define LZO_ARCH_ALPHA 1 # define LZO_INFO_ARCH "alpha" #elif defined(__amd64__) || defined(__x86_64__) || defined(_M_AMD64) # define LZO_ARCH_AMD64 1 # define LZO_INFO_ARCH "amd64" #elif defined(__thumb__) || (defined(_M_ARM) && defined(_M_THUMB)) # define LZO_ARCH_ARM 1 # define LZO_ARCH_ARM_THUMB 1 # define LZO_INFO_ARCH "arm_thumb" #elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCARM__) # define LZO_ARCH_ARM 1 # if defined(__CPU_MODE__) && ((__CPU_MODE__)+0 == 1) # define LZO_ARCH_ARM_THUMB 1 # define LZO_INFO_ARCH "arm_thumb" # elif defined(__CPU_MODE__) && ((__CPU_MODE__)+0 == 2) # define LZO_INFO_ARCH "arm" # else # define LZO_INFO_ARCH "arm" # endif #elif defined(__arm__) || defined(_M_ARM) # define LZO_ARCH_ARM 1 # define LZO_INFO_ARCH "arm" #elif (UINT_MAX <= LZO_0xffffL) && defined(__AVR__) # define LZO_ARCH_AVR 1 # define LZO_INFO_ARCH "avr" #elif defined(__avr32__) || defined(__AVR32__) # define LZO_ARCH_AVR32 1 # define LZO_INFO_ARCH "avr32" #elif defined(__bfin__) # define LZO_ARCH_BLACKFIN 1 # define LZO_INFO_ARCH "blackfin" #elif (UINT_MAX == LZO_0xffffL) && defined(__C166__) # define LZO_ARCH_C166 1 # define LZO_INFO_ARCH "c166" #elif defined(__cris__) # define LZO_ARCH_CRIS 1 # define LZO_INFO_ARCH "cris" #elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCEZ80__) # define LZO_ARCH_EZ80 1 # define LZO_INFO_ARCH "ez80" #elif defined(__H8300__) || defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__) # define LZO_ARCH_H8300 1 # define LZO_INFO_ARCH "h8300" #elif defined(__hppa__) || defined(__hppa) # define LZO_ARCH_HPPA 1 # define LZO_INFO_ARCH "hppa" #elif defined(__386__) || defined(__i386__) || defined(__i386) || defined(_M_IX86) || defined(_M_I386) # define LZO_ARCH_I386 1 # define LZO_ARCH_IA32 1 # define LZO_INFO_ARCH "i386" #elif (LZO_CC_ZORTECHC && defined(__I86__)) # define LZO_ARCH_I386 1 # define LZO_ARCH_IA32 1 # define LZO_INFO_ARCH "i386" #elif (LZO_OS_DOS32 && LZO_CC_HIGHC) && defined(_I386) # define LZO_ARCH_I386 1 # define LZO_ARCH_IA32 1 # define LZO_INFO_ARCH "i386" #elif defined(__ia64__) || defined(__ia64) || defined(_M_IA64) # define LZO_ARCH_IA64 1 # define LZO_INFO_ARCH "ia64" #elif (UINT_MAX == LZO_0xffffL) && defined(__m32c__) # define LZO_ARCH_M16C 1 # define LZO_INFO_ARCH "m16c" #elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCM16C__) # define LZO_ARCH_M16C 1 # define LZO_INFO_ARCH "m16c" #elif defined(__m32r__) # define LZO_ARCH_M32R 1 # define LZO_INFO_ARCH "m32r" #elif (LZO_OS_TOS) || defined(__m68k__) || defined(__m68000__) || defined(__mc68000__) || defined(__mc68020__) || defined(_M_M68K) # define LZO_ARCH_M68K 1 # define LZO_INFO_ARCH "m68k" #elif (UINT_MAX == LZO_0xffffL) && defined(__C251__) # define LZO_ARCH_MCS251 1 # define LZO_INFO_ARCH "mcs251" #elif (UINT_MAX == LZO_0xffffL) && defined(__C51__) # define LZO_ARCH_MCS51 1 # define LZO_INFO_ARCH "mcs51" #elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICC8051__) # define LZO_ARCH_MCS51 1 # define LZO_INFO_ARCH "mcs51" #elif defined(__mips__) || defined(__mips) || defined(_MIPS_ARCH) || defined(_M_MRX000) # define LZO_ARCH_MIPS 1 # define LZO_INFO_ARCH "mips" #elif (UINT_MAX == LZO_0xffffL) && defined(__MSP430__) # define LZO_ARCH_MSP430 1 # define LZO_INFO_ARCH "msp430" #elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICC430__) # define LZO_ARCH_MSP430 1 # define LZO_INFO_ARCH "msp430" #elif defined(__powerpc__) || defined(__powerpc) || defined(__ppc__) || defined(__PPC__) || defined(_M_PPC) || defined(_ARCH_PPC) || defined(_ARCH_PWR) # define LZO_ARCH_POWERPC 1 # define LZO_INFO_ARCH "powerpc" #elif defined(__s390__) || defined(__s390) || defined(__s390x__) || defined(__s390x) # define LZO_ARCH_S390 1 # define LZO_INFO_ARCH "s390" #elif defined(__sh__) || defined(_M_SH) # define LZO_ARCH_SH 1 # define LZO_INFO_ARCH "sh" #elif defined(__sparc__) || defined(__sparc) || defined(__sparcv8) # define LZO_ARCH_SPARC 1 # define LZO_INFO_ARCH "sparc" #elif defined(__SPU__) # define LZO_ARCH_SPU 1 # define LZO_INFO_ARCH "spu" #elif (UINT_MAX == LZO_0xffffL) && defined(__z80) # define LZO_ARCH_Z80 1 # define LZO_INFO_ARCH "z80" #elif (LZO_ARCH_CRAY_PVP) # if defined(_CRAYSV1) # define LZO_ARCH_CRAY_SV1 1 # define LZO_INFO_ARCH "cray_sv1" # elif (_ADDR64) # define LZO_ARCH_CRAY_T90 1 # define LZO_INFO_ARCH "cray_t90" # elif (_ADDR32) # define LZO_ARCH_CRAY_YMP 1 # define LZO_INFO_ARCH "cray_ymp" # else # define LZO_ARCH_CRAY_XMP 1 # define LZO_INFO_ARCH "cray_xmp" # endif #else # define LZO_ARCH_UNKNOWN 1 # define LZO_INFO_ARCH "unknown" #endif #endif #if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_DOS32 || LZO_OS_OS2) # error "FIXME - missing define for CPU architecture" #endif #if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_WIN32) # error "FIXME - missing WIN32 define for CPU architecture" #endif #if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_WIN64) # error "FIXME - missing WIN64 define for CPU architecture" #endif #if (LZO_OS_OS216 || LZO_OS_WIN16) # define LZO_ARCH_I086PM 1 # define LZO_ARCH_IA16PM 1 #elif 1 && (LZO_OS_DOS16 && defined(BLX286)) # define LZO_ARCH_I086PM 1 # define LZO_ARCH_IA16PM 1 #elif 1 && (LZO_OS_DOS16 && defined(DOSX286)) # define LZO_ARCH_I086PM 1 # define LZO_ARCH_IA16PM 1 #elif 1 && (LZO_OS_DOS16 && LZO_CC_BORLANDC && defined(__DPMI16__)) # define LZO_ARCH_I086PM 1 # define LZO_ARCH_IA16PM 1 #endif #if (LZO_ARCH_ARM_THUMB) && !(LZO_ARCH_ARM) # error "this should not happen" #endif #if (LZO_ARCH_I086PM) && !(LZO_ARCH_I086) # error "this should not happen" #endif #if (LZO_ARCH_I086) # if (UINT_MAX != LZO_0xffffL) # error "this should not happen" # endif # if (ULONG_MAX != LZO_0xffffffffL) # error "this should not happen" # endif #endif #if (LZO_ARCH_I386) # if (UINT_MAX != LZO_0xffffL) && defined(__i386_int16__) # error "this should not happen" # endif # if (UINT_MAX != LZO_0xffffffffL) && !defined(__i386_int16__) # error "this should not happen" # endif # if (ULONG_MAX != LZO_0xffffffffL) # error "this should not happen" # endif #endif #if !defined(__LZO_MM_OVERRIDE) #if (LZO_ARCH_I086) #if (UINT_MAX != LZO_0xffffL) # error "this should not happen" #endif #if defined(__TINY__) || defined(M_I86TM) || defined(_M_I86TM) # define LZO_MM_TINY 1 #elif defined(__HUGE__) || defined(_HUGE_) || defined(M_I86HM) || defined(_M_I86HM) # define LZO_MM_HUGE 1 #elif defined(__SMALL__) || defined(M_I86SM) || defined(_M_I86SM) || defined(SMALL_MODEL) # define LZO_MM_SMALL 1 #elif defined(__MEDIUM__) || defined(M_I86MM) || defined(_M_I86MM) # define LZO_MM_MEDIUM 1 #elif defined(__COMPACT__) || defined(M_I86CM) || defined(_M_I86CM) # define LZO_MM_COMPACT 1 #elif defined(__LARGE__) || defined(M_I86LM) || defined(_M_I86LM) || defined(LARGE_MODEL) # define LZO_MM_LARGE 1 #elif (LZO_CC_AZTECC) # if defined(_LARGE_CODE) && defined(_LARGE_DATA) # define LZO_MM_LARGE 1 # elif defined(_LARGE_CODE) # define LZO_MM_MEDIUM 1 # elif defined(_LARGE_DATA) # define LZO_MM_COMPACT 1 # else # define LZO_MM_SMALL 1 # endif #elif (LZO_CC_ZORTECHC && defined(__VCM__)) # define LZO_MM_LARGE 1 #else # error "unknown memory model" #endif #if (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16) #define LZO_HAVE_MM_HUGE_PTR 1 #define LZO_HAVE_MM_HUGE_ARRAY 1 #if (LZO_MM_TINY) # undef LZO_HAVE_MM_HUGE_ARRAY #endif #if (LZO_CC_AZTECC || LZO_CC_PACIFICC || LZO_CC_ZORTECHC) # undef LZO_HAVE_MM_HUGE_PTR # undef LZO_HAVE_MM_HUGE_ARRAY #elif (LZO_CC_DMC || LZO_CC_SYMANTECC) # undef LZO_HAVE_MM_HUGE_ARRAY #elif (LZO_CC_MSC && defined(_QC)) # undef LZO_HAVE_MM_HUGE_ARRAY # if (_MSC_VER < 600) # undef LZO_HAVE_MM_HUGE_PTR # endif #elif (LZO_CC_TURBOC && (__TURBOC__ < 0x0295)) # undef LZO_HAVE_MM_HUGE_ARRAY #endif #if (LZO_ARCH_I086PM) && !(LZO_HAVE_MM_HUGE_PTR) # if (LZO_OS_DOS16) # error "this should not happen" # elif (LZO_CC_ZORTECHC) # else # error "this should not happen" # endif #endif #ifdef __cplusplus extern "C" { #endif #if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0200)) extern void __near __cdecl _AHSHIFT(void); # define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT) #elif (LZO_CC_DMC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC) extern void __near __cdecl _AHSHIFT(void); # define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT) #elif (LZO_CC_MSC || LZO_CC_TOPSPEEDC) extern void __near __cdecl _AHSHIFT(void); # define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT) #elif (LZO_CC_TURBOC && (__TURBOC__ >= 0x0295)) extern void __near __cdecl _AHSHIFT(void); # define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT) #elif ((LZO_CC_AZTECC || LZO_CC_PACIFICC || LZO_CC_TURBOC) && LZO_OS_DOS16) # define LZO_MM_AHSHIFT 12 #elif (LZO_CC_WATCOMC) extern unsigned char _HShift; # define LZO_MM_AHSHIFT ((unsigned) _HShift) #else # error "FIXME - implement LZO_MM_AHSHIFT" #endif #ifdef __cplusplus } #endif #endif #elif (LZO_ARCH_C166) #if !defined(__MODEL__) # error "FIXME - C166 __MODEL__" #elif ((__MODEL__) == 0) # define LZO_MM_SMALL 1 #elif ((__MODEL__) == 1) # define LZO_MM_SMALL 1 #elif ((__MODEL__) == 2) # define LZO_MM_LARGE 1 #elif ((__MODEL__) == 3) # define LZO_MM_TINY 1 #elif ((__MODEL__) == 4) # define LZO_MM_XTINY 1 #elif ((__MODEL__) == 5) # define LZO_MM_XSMALL 1 #else # error "FIXME - C166 __MODEL__" #endif #elif (LZO_ARCH_MCS251) #if !defined(__MODEL__) # error "FIXME - MCS251 __MODEL__" #elif ((__MODEL__) == 0) # define LZO_MM_SMALL 1 #elif ((__MODEL__) == 2) # define LZO_MM_LARGE 1 #elif ((__MODEL__) == 3) # define LZO_MM_TINY 1 #elif ((__MODEL__) == 4) # define LZO_MM_XTINY 1 #elif ((__MODEL__) == 5) # define LZO_MM_XSMALL 1 #else # error "FIXME - MCS251 __MODEL__" #endif #elif (LZO_ARCH_MCS51) #if !defined(__MODEL__) # error "FIXME - MCS51 __MODEL__" #elif ((__MODEL__) == 1) # define LZO_MM_SMALL 1 #elif ((__MODEL__) == 2) # define LZO_MM_LARGE 1 #elif ((__MODEL__) == 3) # define LZO_MM_TINY 1 #elif ((__MODEL__) == 4) # define LZO_MM_XTINY 1 #elif ((__MODEL__) == 5) # define LZO_MM_XSMALL 1 #else # error "FIXME - MCS51 __MODEL__" #endif #elif (LZO_ARCH_CRAY_PVP) # define LZO_MM_PVP 1 #else # define LZO_MM_FLAT 1 #endif #if (LZO_MM_COMPACT) # define LZO_INFO_MM "compact" #elif (LZO_MM_FLAT) # define LZO_INFO_MM "flat" #elif (LZO_MM_HUGE) # define LZO_INFO_MM "huge" #elif (LZO_MM_LARGE) # define LZO_INFO_MM "large" #elif (LZO_MM_MEDIUM) # define LZO_INFO_MM "medium" #elif (LZO_MM_PVP) # define LZO_INFO_MM "pvp" #elif (LZO_MM_SMALL) # define LZO_INFO_MM "small" #elif (LZO_MM_TINY) # define LZO_INFO_MM "tiny" #else # error "unknown memory model" #endif #endif #if defined(SIZEOF_SHORT) # define LZO_SIZEOF_SHORT (SIZEOF_SHORT) #endif #if defined(SIZEOF_INT) # define LZO_SIZEOF_INT (SIZEOF_INT) #endif #if defined(SIZEOF_LONG) # define LZO_SIZEOF_LONG (SIZEOF_LONG) #endif #if defined(SIZEOF_LONG_LONG) # define LZO_SIZEOF_LONG_LONG (SIZEOF_LONG_LONG) #endif #if defined(SIZEOF___INT16) # define LZO_SIZEOF___INT16 (SIZEOF___INT16) #endif #if defined(SIZEOF___INT32) # define LZO_SIZEOF___INT32 (SIZEOF___INT32) #endif #if defined(SIZEOF___INT64) # define LZO_SIZEOF___INT64 (SIZEOF___INT64) #endif #if defined(SIZEOF_VOID_P) # define LZO_SIZEOF_VOID_P (SIZEOF_VOID_P) #endif #if defined(SIZEOF_SIZE_T) # define LZO_SIZEOF_SIZE_T (SIZEOF_SIZE_T) #endif #if defined(SIZEOF_PTRDIFF_T) # define LZO_SIZEOF_PTRDIFF_T (SIZEOF_PTRDIFF_T) #endif #define __LZO_LSR(x,b) (((x)+0ul) >> (b)) #if !defined(LZO_SIZEOF_SHORT) # if (LZO_ARCH_CRAY_PVP) # define LZO_SIZEOF_SHORT 8 # elif (USHRT_MAX == LZO_0xffffL) # define LZO_SIZEOF_SHORT 2 # elif (__LZO_LSR(USHRT_MAX,7) == 1) # define LZO_SIZEOF_SHORT 1 # elif (__LZO_LSR(USHRT_MAX,15) == 1) # define LZO_SIZEOF_SHORT 2 # elif (__LZO_LSR(USHRT_MAX,31) == 1) # define LZO_SIZEOF_SHORT 4 # elif (__LZO_LSR(USHRT_MAX,63) == 1) # define LZO_SIZEOF_SHORT 8 # elif (__LZO_LSR(USHRT_MAX,127) == 1) # define LZO_SIZEOF_SHORT 16 # else # error "LZO_SIZEOF_SHORT" # endif #endif #if !defined(LZO_SIZEOF_INT) # if (LZO_ARCH_CRAY_PVP) # define LZO_SIZEOF_INT 8 # elif (UINT_MAX == LZO_0xffffL) # define LZO_SIZEOF_INT 2 # elif (UINT_MAX == LZO_0xffffffffL) # define LZO_SIZEOF_INT 4 # elif (__LZO_LSR(UINT_MAX,7) == 1) # define LZO_SIZEOF_INT 1 # elif (__LZO_LSR(UINT_MAX,15) == 1) # define LZO_SIZEOF_INT 2 # elif (__LZO_LSR(UINT_MAX,31) == 1) # define LZO_SIZEOF_INT 4 # elif (__LZO_LSR(UINT_MAX,63) == 1) # define LZO_SIZEOF_INT 8 # elif (__LZO_LSR(UINT_MAX,127) == 1) # define LZO_SIZEOF_INT 16 # else # error "LZO_SIZEOF_INT" # endif #endif #if !defined(LZO_SIZEOF_LONG) # if (ULONG_MAX == LZO_0xffffffffL) # define LZO_SIZEOF_LONG 4 # elif (__LZO_LSR(ULONG_MAX,7) == 1) # define LZO_SIZEOF_LONG 1 # elif (__LZO_LSR(ULONG_MAX,15) == 1) # define LZO_SIZEOF_LONG 2 # elif (__LZO_LSR(ULONG_MAX,31) == 1) # define LZO_SIZEOF_LONG 4 # elif (__LZO_LSR(ULONG_MAX,63) == 1) # define LZO_SIZEOF_LONG 8 # elif (__LZO_LSR(ULONG_MAX,127) == 1) # define LZO_SIZEOF_LONG 16 # else # error "LZO_SIZEOF_LONG" # endif #endif #if !defined(LZO_SIZEOF_LONG_LONG) && !defined(LZO_SIZEOF___INT64) #if (LZO_SIZEOF_LONG > 0 && LZO_SIZEOF_LONG < 8) # if defined(__LONG_MAX__) && defined(__LONG_LONG_MAX__) # if (LZO_CC_GNUC >= 0x030300ul) # if ((__LONG_MAX__)+0 == (__LONG_LONG_MAX__)+0) # define LZO_SIZEOF_LONG_LONG LZO_SIZEOF_LONG # elif (__LZO_LSR(__LONG_LONG_MAX__,30) == 1) # define LZO_SIZEOF_LONG_LONG 4 # endif # endif # endif #endif #endif #if !defined(LZO_SIZEOF_LONG_LONG) && !defined(LZO_SIZEOF___INT64) #if (LZO_SIZEOF_LONG > 0 && LZO_SIZEOF_LONG < 8) #if (LZO_ARCH_I086 && LZO_CC_DMC) #elif (LZO_CC_CILLY) && defined(__GNUC__) # define LZO_SIZEOF_LONG_LONG 8 #elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE) # define LZO_SIZEOF_LONG_LONG 8 #elif ((LZO_OS_WIN32 || LZO_OS_WIN64 || defined(_WIN32)) && LZO_CC_MSC && (_MSC_VER >= 1400)) # define LZO_SIZEOF_LONG_LONG 8 #elif (LZO_OS_WIN64 || defined(_WIN64)) # define LZO_SIZEOF___INT64 8 #elif (LZO_ARCH_I386 && (LZO_CC_DMC)) # define LZO_SIZEOF_LONG_LONG 8 #elif (LZO_ARCH_I386 && (LZO_CC_SYMANTECC && (__SC__ >= 0x700))) # define LZO_SIZEOF_LONG_LONG 8 #elif (LZO_ARCH_I386 && (LZO_CC_INTELC && defined(__linux__))) # define LZO_SIZEOF_LONG_LONG 8 #elif (LZO_ARCH_I386 && (LZO_CC_MWERKS || LZO_CC_PELLESC || LZO_CC_PGI || LZO_CC_SUNPROC)) # define LZO_SIZEOF_LONG_LONG 8 #elif (LZO_ARCH_I386 && (LZO_CC_INTELC || LZO_CC_MSC)) # define LZO_SIZEOF___INT64 8 #elif ((LZO_OS_WIN32 || defined(_WIN32)) && (LZO_CC_MSC)) # define LZO_SIZEOF___INT64 8 #elif (LZO_ARCH_I386 && (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0520))) # define LZO_SIZEOF___INT64 8 #elif (LZO_ARCH_I386 && (LZO_CC_WATCOMC && (__WATCOMC__ >= 1100))) # define LZO_SIZEOF___INT64 8 #elif (LZO_CC_WATCOMC && defined(_INTEGRAL_MAX_BITS) && (_INTEGRAL_MAX_BITS == 64)) # define LZO_SIZEOF___INT64 8 #elif (LZO_OS_OS400 || defined(__OS400__)) && defined(__LLP64_IFC__) # define LZO_SIZEOF_LONG_LONG 8 #elif (defined(__vms) || defined(__VMS)) && (__INITIAL_POINTER_SIZE+0 == 64) # define LZO_SIZEOF_LONG_LONG 8 #elif (LZO_CC_SDCC) && (LZO_SIZEOF_INT == 2) #elif 1 && defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) # define LZO_SIZEOF_LONG_LONG 8 #endif #endif #endif #if defined(__cplusplus) && (LZO_CC_GNUC) # if (LZO_CC_GNUC < 0x020800ul) # undef LZO_SIZEOF_LONG_LONG # endif #endif #if (LZO_CFG_NO_LONG_LONG) || defined(__NO_LONG_LONG) # undef LZO_SIZEOF_LONG_LONG #endif #if !defined(LZO_SIZEOF_VOID_P) #if (LZO_ARCH_I086) # define __LZO_WORDSIZE 2 # if (LZO_MM_TINY || LZO_MM_SMALL || LZO_MM_MEDIUM) # define LZO_SIZEOF_VOID_P 2 # elif (LZO_MM_COMPACT || LZO_MM_LARGE || LZO_MM_HUGE) # define LZO_SIZEOF_VOID_P 4 # else # error "LZO_MM" # endif #elif (LZO_ARCH_AVR || LZO_ARCH_Z80) # define __LZO_WORDSIZE 1 # define LZO_SIZEOF_VOID_P 2 #elif (LZO_ARCH_C166 || LZO_ARCH_MCS51 || LZO_ARCH_MCS251 || LZO_ARCH_MSP430) # define LZO_SIZEOF_VOID_P 2 #elif (LZO_ARCH_H8300) # if defined(__NORMAL_MODE__) # define __LZO_WORDSIZE 4 # define LZO_SIZEOF_VOID_P 2 # elif defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__) # define __LZO_WORDSIZE 4 # define LZO_SIZEOF_VOID_P 4 # else # define __LZO_WORDSIZE 2 # define LZO_SIZEOF_VOID_P 2 # endif # if (LZO_CC_GNUC && (LZO_CC_GNUC < 0x040000ul)) && (LZO_SIZEOF_INT == 4) # define LZO_SIZEOF_SIZE_T LZO_SIZEOF_INT # define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_INT # endif #elif (LZO_ARCH_M16C) # define __LZO_WORDSIZE 2 # if defined(__m32c_cpu__) || defined(__m32cm_cpu__) # define LZO_SIZEOF_VOID_P 4 # else # define LZO_SIZEOF_VOID_P 2 # endif #elif (LZO_SIZEOF_LONG == 8) && ((defined(__mips__) && defined(__R5900__)) || defined(__MIPS_PSX2__)) # define __LZO_WORDSIZE 8 # define LZO_SIZEOF_VOID_P 4 #elif defined(__LLP64__) || defined(__LLP64) || defined(_LLP64) || defined(_WIN64) # define __LZO_WORDSIZE 8 # define LZO_SIZEOF_VOID_P 8 #elif (LZO_OS_OS400 || defined(__OS400__)) && defined(__LLP64_IFC__) # define LZO_SIZEOF_VOID_P LZO_SIZEOF_LONG # define LZO_SIZEOF_SIZE_T LZO_SIZEOF_LONG # define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_LONG #elif (LZO_OS_OS400 || defined(__OS400__)) # define __LZO_WORDSIZE LZO_SIZEOF_LONG # define LZO_SIZEOF_VOID_P 16 # define LZO_SIZEOF_SIZE_T LZO_SIZEOF_LONG # define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_LONG #elif (defined(__vms) || defined(__VMS)) && (__INITIAL_POINTER_SIZE+0 == 64) # define LZO_SIZEOF_VOID_P 8 # define LZO_SIZEOF_SIZE_T LZO_SIZEOF_LONG # define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_LONG #elif (LZO_ARCH_SPU) # if 0 # define __LZO_WORDSIZE 16 # endif # define LZO_SIZEOF_VOID_P 4 #else # define LZO_SIZEOF_VOID_P LZO_SIZEOF_LONG #endif #endif #if !defined(LZO_WORDSIZE) # if defined(__LZO_WORDSIZE) # define LZO_WORDSIZE __LZO_WORDSIZE # else # define LZO_WORDSIZE LZO_SIZEOF_VOID_P # endif #endif #if !defined(LZO_SIZEOF_SIZE_T) #if (LZO_ARCH_I086 || LZO_ARCH_M16C) # define LZO_SIZEOF_SIZE_T 2 #else # define LZO_SIZEOF_SIZE_T LZO_SIZEOF_VOID_P #endif #endif #if !defined(LZO_SIZEOF_PTRDIFF_T) #if (LZO_ARCH_I086) # if (LZO_MM_TINY || LZO_MM_SMALL || LZO_MM_MEDIUM || LZO_MM_HUGE) # define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_VOID_P # elif (LZO_MM_COMPACT || LZO_MM_LARGE) # if (LZO_CC_BORLANDC || LZO_CC_TURBOC) # define LZO_SIZEOF_PTRDIFF_T 4 # else # define LZO_SIZEOF_PTRDIFF_T 2 # endif # else # error "LZO_MM" # endif #else # define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_SIZE_T #endif #endif #if (LZO_ABI_NEUTRAL_ENDIAN) # undef LZO_ABI_BIG_ENDIAN # undef LZO_ABI_LITTLE_ENDIAN #elif !(LZO_ABI_BIG_ENDIAN) && !(LZO_ABI_LITTLE_ENDIAN) #if (LZO_ARCH_ALPHA) && (LZO_ARCH_CRAY_MPP) # define LZO_ABI_BIG_ENDIAN 1 #elif (LZO_ARCH_IA64) && (LZO_OS_POSIX_LINUX || LZO_OS_WIN64) # define LZO_ABI_LITTLE_ENDIAN 1 #elif (LZO_ARCH_ALPHA || LZO_ARCH_AMD64 || LZO_ARCH_BLACKFIN || LZO_ARCH_CRIS || LZO_ARCH_I086 || LZO_ARCH_I386 || LZO_ARCH_MSP430) # define LZO_ABI_LITTLE_ENDIAN 1 #elif (LZO_ARCH_AVR32 || LZO_ARCH_M68K || LZO_ARCH_S390) # define LZO_ABI_BIG_ENDIAN 1 #elif 1 && defined(__IAR_SYSTEMS_ICC__) && defined(__LITTLE_ENDIAN__) # if (__LITTLE_ENDIAN__ == 1) # define LZO_ABI_LITTLE_ENDIAN 1 # else # define LZO_ABI_BIG_ENDIAN 1 # endif #elif 1 && defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__) # define LZO_ABI_BIG_ENDIAN 1 #elif 1 && defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__) # define LZO_ABI_LITTLE_ENDIAN 1 #elif 1 && (LZO_ARCH_ARM) && defined(__ARMEB__) && !defined(__ARMEL__) # define LZO_ABI_BIG_ENDIAN 1 #elif 1 && (LZO_ARCH_ARM) && defined(__ARMEL__) && !defined(__ARMEB__) # define LZO_ABI_LITTLE_ENDIAN 1 #elif 1 && (LZO_ARCH_MIPS) && defined(__MIPSEB__) && !defined(__MIPSEL__) # define LZO_ABI_BIG_ENDIAN 1 #elif 1 && (LZO_ARCH_MIPS) && defined(__MIPSEL__) && !defined(__MIPSEB__) # define LZO_ABI_LITTLE_ENDIAN 1 #endif #endif #if (LZO_ABI_BIG_ENDIAN) && (LZO_ABI_LITTLE_ENDIAN) # error "this should not happen" #endif #if (LZO_ABI_BIG_ENDIAN) # define LZO_INFO_ABI_ENDIAN "be" #elif (LZO_ABI_LITTLE_ENDIAN) # define LZO_INFO_ABI_ENDIAN "le" #elif (LZO_ABI_NEUTRAL_ENDIAN) # define LZO_INFO_ABI_ENDIAN "neutral" #endif #if (LZO_SIZEOF_INT == 1 && LZO_SIZEOF_LONG == 2 && LZO_SIZEOF_VOID_P == 2) # define LZO_ABI_I8LP16 1 # define LZO_INFO_ABI_PM "i8lp16" #elif (LZO_SIZEOF_INT == 2 && LZO_SIZEOF_LONG == 2 && LZO_SIZEOF_VOID_P == 2) # define LZO_ABI_ILP16 1 # define LZO_INFO_ABI_PM "ilp16" #elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 4 && LZO_SIZEOF_VOID_P == 4) # define LZO_ABI_ILP32 1 # define LZO_INFO_ABI_PM "ilp32" #elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 4 && LZO_SIZEOF_VOID_P == 8 && LZO_SIZEOF_SIZE_T == 8) # define LZO_ABI_LLP64 1 # define LZO_INFO_ABI_PM "llp64" #elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 8) # define LZO_ABI_LP64 1 # define LZO_INFO_ABI_PM "lp64" #elif (LZO_SIZEOF_INT == 8 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 8) # define LZO_ABI_ILP64 1 # define LZO_INFO_ABI_PM "ilp64" #elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 4) # define LZO_ABI_IP32L64 1 # define LZO_INFO_ABI_PM "ip32l64" #endif #if !defined(__LZO_LIBC_OVERRIDE) #if (LZO_LIBC_NAKED) # define LZO_INFO_LIBC "naked" #elif (LZO_LIBC_FREESTANDING) # define LZO_INFO_LIBC "freestanding" #elif (LZO_LIBC_MOSTLY_FREESTANDING) # define LZO_INFO_LIBC "mfreestanding" #elif (LZO_LIBC_ISOC90) # define LZO_INFO_LIBC "isoc90" #elif (LZO_LIBC_ISOC99) # define LZO_INFO_LIBC "isoc99" #elif defined(__dietlibc__) # define LZO_LIBC_DIETLIBC 1 # define LZO_INFO_LIBC "dietlibc" #elif defined(_NEWLIB_VERSION) # define LZO_LIBC_NEWLIB 1 # define LZO_INFO_LIBC "newlib" #elif defined(__UCLIBC__) && defined(__UCLIBC_MAJOR__) && defined(__UCLIBC_MINOR__) # if defined(__UCLIBC_SUBLEVEL__) # define LZO_LIBC_UCLIBC (__UCLIBC_MAJOR__ * 0x10000L + __UCLIBC_MINOR__ * 0x100 + __UCLIBC_SUBLEVEL__) # else # define LZO_LIBC_UCLIBC 0x00090bL # endif # define LZO_INFO_LIBC "uclibc" #elif defined(__GLIBC__) && defined(__GLIBC_MINOR__) # define LZO_LIBC_GLIBC (__GLIBC__ * 0x10000L + __GLIBC_MINOR__ * 0x100) # define LZO_INFO_LIBC "glibc" #elif (LZO_CC_MWERKS) && defined(__MSL__) # define LZO_LIBC_MSL __MSL__ # define LZO_INFO_LIBC "msl" #elif 1 && defined(__IAR_SYSTEMS_ICC__) # define LZO_LIBC_ISOC90 1 # define LZO_INFO_LIBC "isoc90" #else # define LZO_LIBC_DEFAULT 1 # define LZO_INFO_LIBC "default" #endif #endif #if !defined(__lzo_gnuc_extension__) #if (LZO_CC_GNUC >= 0x020800ul) # define __lzo_gnuc_extension__ __extension__ #elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) # define __lzo_gnuc_extension__ __extension__ #else # define __lzo_gnuc_extension__ /*empty*/ #endif #endif #if !defined(__lzo_ua_volatile) # define __lzo_ua_volatile volatile #endif #if !defined(__lzo_alignof) #if (LZO_CC_CILLY || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI) # define __lzo_alignof(e) __alignof__(e) #elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 700)) # define __lzo_alignof(e) __alignof__(e) #elif (LZO_CC_MSC && (_MSC_VER >= 1300)) # define __lzo_alignof(e) __alignof(e) #elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100)) # define __lzo_alignof(e) __alignof__(e) #endif #endif #if defined(__lzo_alignof) # define __lzo_HAVE_alignof 1 #endif #if !defined(__lzo_constructor) #if (LZO_CC_GNUC >= 0x030400ul) # define __lzo_constructor __attribute__((__constructor__,__used__)) #elif (LZO_CC_GNUC >= 0x020700ul) # define __lzo_constructor __attribute__((__constructor__)) #elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) # define __lzo_constructor __attribute__((__constructor__)) #endif #endif #if defined(__lzo_constructor) # define __lzo_HAVE_constructor 1 #endif #if !defined(__lzo_destructor) #if (LZO_CC_GNUC >= 0x030400ul) # define __lzo_destructor __attribute__((__destructor__,__used__)) #elif (LZO_CC_GNUC >= 0x020700ul) # define __lzo_destructor __attribute__((__destructor__)) #elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) # define __lzo_destructor __attribute__((__destructor__)) #endif #endif #if defined(__lzo_destructor) # define __lzo_HAVE_destructor 1 #endif #if (__lzo_HAVE_destructor) && !(__lzo_HAVE_constructor) # error "this should not happen" #endif #if !defined(__lzo_inline) #if (LZO_CC_TURBOC && (__TURBOC__ <= 0x0295)) #elif defined(__cplusplus) # define __lzo_inline inline #elif (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0550)) # define __lzo_inline __inline #elif (LZO_CC_CILLY || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI) # define __lzo_inline __inline__ #elif (LZO_CC_DMC) # define __lzo_inline __inline #elif (LZO_CC_INTELC) # define __lzo_inline __inline #elif (LZO_CC_MWERKS && (__MWERKS__ >= 0x2405)) # define __lzo_inline __inline #elif (LZO_CC_MSC && (_MSC_VER >= 900)) # define __lzo_inline __inline #elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100)) # define __lzo_inline __inline__ #elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) # define __lzo_inline inline #endif #endif #if defined(__lzo_inline) # define __lzo_HAVE_inline 1 #else # define __lzo_inline /*empty*/ #endif #if !defined(__lzo_forceinline) #if (LZO_CC_GNUC >= 0x030200ul) # define __lzo_forceinline __inline__ __attribute__((__always_inline__)) #elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC) # define __lzo_forceinline __forceinline #elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC) # define __lzo_forceinline __inline__ __attribute__((__always_inline__)) #elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) # define __lzo_forceinline __inline__ __attribute__((__always_inline__)) #elif (LZO_CC_MSC && (_MSC_VER >= 1200)) # define __lzo_forceinline __forceinline #elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100)) # define __lzo_forceinline __inline__ __attribute__((__always_inline__)) #endif #endif #if defined(__lzo_forceinline) # define __lzo_HAVE_forceinline 1 #else # define __lzo_forceinline /*empty*/ #endif #if !defined(__lzo_noinline) #if 1 && (LZO_ARCH_I386) && (LZO_CC_GNUC >= 0x040000ul) && (LZO_CC_GNUC < 0x040003ul) # define __lzo_noinline __attribute__((__noinline__,__used__)) #elif (LZO_CC_GNUC >= 0x030200ul) # define __lzo_noinline __attribute__((__noinline__)) #elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_MSC) # define __lzo_noinline __declspec(noinline) #elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC) # define __lzo_noinline __attribute__((__noinline__)) #elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) # define __lzo_noinline __attribute__((__noinline__)) #elif (LZO_CC_MSC && (_MSC_VER >= 1300)) # define __lzo_noinline __declspec(noinline) #elif (LZO_CC_MWERKS && (__MWERKS__ >= 0x3200) && (LZO_OS_WIN32 || LZO_OS_WIN64)) # if defined(__cplusplus) # else # define __lzo_noinline __declspec(noinline) # endif #elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100)) # define __lzo_noinline __attribute__((__noinline__)) #endif #endif #if defined(__lzo_noinline) # define __lzo_HAVE_noinline 1 #else # define __lzo_noinline /*empty*/ #endif #if (__lzo_HAVE_forceinline || __lzo_HAVE_noinline) && !(__lzo_HAVE_inline) # error "this should not happen" #endif #if !defined(__lzo_noreturn) #if (LZO_CC_GNUC >= 0x020700ul) # define __lzo_noreturn __attribute__((__noreturn__)) #elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC) # define __lzo_noreturn __declspec(noreturn) #elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_GNUC) # define __lzo_noreturn __attribute__((__noreturn__)) #elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) # define __lzo_noreturn __attribute__((__noreturn__)) #elif (LZO_CC_MSC && (_MSC_VER >= 1200)) # define __lzo_noreturn __declspec(noreturn) #endif #endif #if defined(__lzo_noreturn) # define __lzo_HAVE_noreturn 1 #else # define __lzo_noreturn /*empty*/ #endif #if !defined(__lzo_nothrow) #if (LZO_CC_GNUC >= 0x030300ul) # define __lzo_nothrow __attribute__((__nothrow__)) #elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC) && defined(__cplusplus) # define __lzo_nothrow __declspec(nothrow) #elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 900) && LZO_CC_SYNTAX_GNUC) # define __lzo_nothrow __attribute__((__nothrow__)) #elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) # define __lzo_nothrow __attribute__((__nothrow__)) #elif (LZO_CC_MSC && (_MSC_VER >= 1200)) && defined(__cplusplus) # define __lzo_nothrow __declspec(nothrow) #endif #endif #if defined(__lzo_nothrow) # define __lzo_HAVE_nothrow 1 #else # define __lzo_nothrow /*empty*/ #endif #if !defined(__lzo_restrict) #if (LZO_CC_GNUC >= 0x030400ul) # define __lzo_restrict __restrict__ #elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_GNUC) # define __lzo_restrict __restrict__ #elif (LZO_CC_CLANG || LZO_CC_LLVM) # define __lzo_restrict __restrict__ #elif (LZO_CC_MSC && (_MSC_VER >= 1400)) # define __lzo_restrict __restrict #endif #endif #if defined(__lzo_restrict) # define __lzo_HAVE_restrict 1 #else # define __lzo_restrict /*empty*/ #endif #if !defined(__lzo_likely) && !defined(__lzo_unlikely) #if (LZO_CC_GNUC >= 0x030200ul) # define __lzo_likely(e) (__builtin_expect(!!(e),1)) # define __lzo_unlikely(e) (__builtin_expect(!!(e),0)) #elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800)) # define __lzo_likely(e) (__builtin_expect(!!(e),1)) # define __lzo_unlikely(e) (__builtin_expect(!!(e),0)) #elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) # define __lzo_likely(e) (__builtin_expect(!!(e),1)) # define __lzo_unlikely(e) (__builtin_expect(!!(e),0)) #endif #endif #if defined(__lzo_likely) # define __lzo_HAVE_likely 1 #else # define __lzo_likely(e) (e) #endif #if defined(__lzo_unlikely) # define __lzo_HAVE_unlikely 1 #else # define __lzo_unlikely(e) (e) #endif #if !defined(LZO_UNUSED) # if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0600)) # define LZO_UNUSED(var) ((void) &var) # elif (LZO_CC_BORLANDC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PELLESC || LZO_CC_TURBOC) # define LZO_UNUSED(var) if (&var) ; else # elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE) # define LZO_UNUSED(var) ((void) var) # elif (LZO_CC_MSC && (_MSC_VER < 900)) # define LZO_UNUSED(var) if (&var) ; else # elif (LZO_CC_KEILC) # define LZO_UNUSED(var) {extern int __lzo_unused[1-2*!(sizeof(var)>0)];} # elif (LZO_CC_PACIFICC) # define LZO_UNUSED(var) ((void) sizeof(var)) # elif (LZO_CC_WATCOMC) && defined(__cplusplus) # define LZO_UNUSED(var) ((void) var) # else # define LZO_UNUSED(var) ((void) &var) # endif #endif #if !defined(LZO_UNUSED_FUNC) # if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0600)) # define LZO_UNUSED_FUNC(func) ((void) func) # elif (LZO_CC_BORLANDC || LZO_CC_NDPC || LZO_CC_TURBOC) # define LZO_UNUSED_FUNC(func) if (func) ; else # elif (LZO_CC_CLANG || LZO_CC_LLVM) # define LZO_UNUSED_FUNC(func) ((void) &func) # elif (LZO_CC_MSC && (_MSC_VER < 900)) # define LZO_UNUSED_FUNC(func) if (func) ; else # elif (LZO_CC_MSC) # define LZO_UNUSED_FUNC(func) ((void) &func) # elif (LZO_CC_KEILC || LZO_CC_PELLESC) # define LZO_UNUSED_FUNC(func) {extern int __lzo_unused[1-2*!(sizeof((int)func)>0)];} # else # define LZO_UNUSED_FUNC(func) ((void) func) # endif #endif #if !defined(LZO_UNUSED_LABEL) # if (LZO_CC_WATCOMC) && defined(__cplusplus) # define LZO_UNUSED_LABEL(l) switch(0) case 1:goto l # elif (LZO_CC_CLANG || LZO_CC_INTELC || LZO_CC_WATCOMC) # define LZO_UNUSED_LABEL(l) if (0) goto l # else # define LZO_UNUSED_LABEL(l) switch(0) case 1:goto l # endif #endif #if !defined(LZO_DEFINE_UNINITIALIZED_VAR) # if 0 # define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init) type var # elif 0 && (LZO_CC_GNUC) # define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init) type var = var # else # define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init) type var = init # endif #endif #if !defined(LZO_UNCONST_CAST) # if 0 && defined(__cplusplus) # define LZO_UNCONST_CAST(t,e) (const_cast<t> (e)) # elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE) # define LZO_UNCONST_CAST(t,e) ((t) ((void *) ((char *) ((lzo_uintptr_t) ((const void *) (e)))))) # else # define LZO_UNCONST_CAST(t,e) ((t) ((void *) ((char *) ((const void *) (e))))) # endif #endif #if !defined(LZO_COMPILE_TIME_ASSERT_HEADER) # if (LZO_CC_AZTECC || LZO_CC_ZORTECHC) # define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1-!(e)]; # elif (LZO_CC_DMC || LZO_CC_SYMANTECC) # define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1u-2*!(e)]; # elif (LZO_CC_TURBOC && (__TURBOC__ == 0x0295)) # define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1-!(e)]; # else # define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1-2*!(e)]; # endif #endif #if !defined(LZO_COMPILE_TIME_ASSERT) # if (LZO_CC_AZTECC) # define LZO_COMPILE_TIME_ASSERT(e) {typedef int __lzo_cta_t[1-!(e)];} # elif (LZO_CC_DMC || LZO_CC_PACIFICC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC) # define LZO_COMPILE_TIME_ASSERT(e) switch(0) case 1:case !(e):break; # elif (LZO_CC_MSC && (_MSC_VER < 900)) # define LZO_COMPILE_TIME_ASSERT(e) switch(0) case 1:case !(e):break; # elif (LZO_CC_TURBOC && (__TURBOC__ == 0x0295)) # define LZO_COMPILE_TIME_ASSERT(e) switch(0) case 1:case !(e):break; # else # define LZO_COMPILE_TIME_ASSERT(e) {typedef int __lzo_cta_t[1-2*!(e)];} # endif #endif #if (LZO_ARCH_I086 || LZO_ARCH_I386) && (LZO_OS_DOS16 || LZO_OS_DOS32 || LZO_OS_OS2 || LZO_OS_OS216 || LZO_OS_WIN16 || LZO_OS_WIN32 || LZO_OS_WIN64) # if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC) # elif (LZO_CC_DMC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC) # define __lzo_cdecl __cdecl # define __lzo_cdecl_atexit /*empty*/ # define __lzo_cdecl_main __cdecl # if (LZO_OS_OS2 && (LZO_CC_DMC || LZO_CC_SYMANTECC)) # define __lzo_cdecl_qsort __pascal # elif (LZO_OS_OS2 && (LZO_CC_ZORTECHC)) # define __lzo_cdecl_qsort _stdcall # else # define __lzo_cdecl_qsort __cdecl # endif # elif (LZO_CC_WATCOMC) # define __lzo_cdecl __cdecl # else # define __lzo_cdecl __cdecl # define __lzo_cdecl_atexit __cdecl # define __lzo_cdecl_main __cdecl # define __lzo_cdecl_qsort __cdecl # endif # if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC || LZO_CC_WATCOMC) # elif (LZO_OS_OS2 && (LZO_CC_DMC || LZO_CC_SYMANTECC)) # define __lzo_cdecl_sighandler __pascal # elif (LZO_OS_OS2 && (LZO_CC_ZORTECHC)) # define __lzo_cdecl_sighandler _stdcall # elif (LZO_CC_MSC && (_MSC_VER >= 1400)) && defined(_M_CEE_PURE) # define __lzo_cdecl_sighandler __clrcall # elif (LZO_CC_MSC && (_MSC_VER >= 600 && _MSC_VER < 700)) # if defined(_DLL) # define __lzo_cdecl_sighandler _far _cdecl _loadds # elif defined(_MT) # define __lzo_cdecl_sighandler _far _cdecl # else # define __lzo_cdecl_sighandler _cdecl # endif # else # define __lzo_cdecl_sighandler __cdecl # endif #elif (LZO_ARCH_I386) && (LZO_CC_WATCOMC) # define __lzo_cdecl __cdecl #elif (LZO_ARCH_M68K && LZO_OS_TOS && (LZO_CC_PUREC || LZO_CC_TURBOC)) # define __lzo_cdecl cdecl #endif #if !defined(__lzo_cdecl) # define __lzo_cdecl /*empty*/ #endif #if !defined(__lzo_cdecl_atexit) # define __lzo_cdecl_atexit /*empty*/ #endif #if !defined(__lzo_cdecl_main) # define __lzo_cdecl_main /*empty*/ #endif #if !defined(__lzo_cdecl_qsort) # define __lzo_cdecl_qsort /*empty*/ #endif #if !defined(__lzo_cdecl_sighandler) # define __lzo_cdecl_sighandler /*empty*/ #endif #if !defined(__lzo_cdecl_va) # define __lzo_cdecl_va __lzo_cdecl #endif #if !(LZO_CFG_NO_WINDOWS_H) #if (LZO_OS_CYGWIN || (LZO_OS_EMX && defined(__RSXNT__)) || LZO_OS_WIN32 || LZO_OS_WIN64) # if (LZO_CC_WATCOMC && (__WATCOMC__ < 1000)) # elif (LZO_OS_WIN32 && LZO_CC_GNUC) && defined(__PW32__) # elif ((LZO_OS_CYGWIN || defined(__MINGW32__)) && (LZO_CC_GNUC && (LZO_CC_GNUC < 0x025f00ul))) # else # define LZO_HAVE_WINDOWS_H 1 # endif #endif #endif #if (LZO_ARCH_ALPHA) # define LZO_OPT_AVOID_UINT_INDEX 1 # define LZO_OPT_AVOID_SHORT 1 # define LZO_OPT_AVOID_USHORT 1 #elif (LZO_ARCH_AMD64) # define LZO_OPT_AVOID_INT_INDEX 1 # define LZO_OPT_AVOID_UINT_INDEX 1 # define LZO_OPT_UNALIGNED16 1 # define LZO_OPT_UNALIGNED32 1 # define LZO_OPT_UNALIGNED64 1 #elif (LZO_ARCH_ARM && LZO_ARCH_ARM_THUMB) #elif (LZO_ARCH_ARM) # define LZO_OPT_AVOID_SHORT 1 # define LZO_OPT_AVOID_USHORT 1 #elif (LZO_ARCH_CRIS) # define LZO_OPT_UNALIGNED16 1 # define LZO_OPT_UNALIGNED32 1 #elif (LZO_ARCH_I386) # define LZO_OPT_UNALIGNED16 1 # define LZO_OPT_UNALIGNED32 1 #elif (LZO_ARCH_IA64) # define LZO_OPT_AVOID_INT_INDEX 1 # define LZO_OPT_AVOID_UINT_INDEX 1 # define LZO_OPT_PREFER_POSTINC 1 #elif (LZO_ARCH_M68K) # define LZO_OPT_PREFER_POSTINC 1 # define LZO_OPT_PREFER_PREDEC 1 # if defined(__mc68020__) && !defined(__mcoldfire__) # define LZO_OPT_UNALIGNED16 1 # define LZO_OPT_UNALIGNED32 1 # endif #elif (LZO_ARCH_MIPS) # define LZO_OPT_AVOID_UINT_INDEX 1 #elif (LZO_ARCH_POWERPC) # define LZO_OPT_PREFER_PREINC 1 # define LZO_OPT_PREFER_PREDEC 1 # if (LZO_ABI_BIG_ENDIAN) # define LZO_OPT_UNALIGNED16 1 # define LZO_OPT_UNALIGNED32 1 # endif #elif (LZO_ARCH_S390) # define LZO_OPT_UNALIGNED16 1 # define LZO_OPT_UNALIGNED32 1 # if (LZO_SIZEOF_SIZE_T == 8) # define LZO_OPT_UNALIGNED64 1 # endif #elif (LZO_ARCH_SH) # define LZO_OPT_PREFER_POSTINC 1 # define LZO_OPT_PREFER_PREDEC 1 #endif #ifndef LZO_CFG_NO_INLINE_ASM #if (LZO_CC_LLVM) # define LZO_CFG_NO_INLINE_ASM 1 #endif #endif #ifndef LZO_CFG_NO_UNALIGNED #if (LZO_ABI_NEUTRAL_ENDIAN) || (LZO_ARCH_GENERIC) # define LZO_CFG_NO_UNALIGNED 1 #endif #endif #if (LZO_CFG_NO_UNALIGNED) # undef LZO_OPT_UNALIGNED16 # undef LZO_OPT_UNALIGNED32 # undef LZO_OPT_UNALIGNED64 #endif #if (LZO_CFG_NO_INLINE_ASM) #elif (LZO_ARCH_I386 && (LZO_OS_DOS32 || LZO_OS_WIN32) && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC)) # define LZO_ASM_SYNTAX_MSC 1 #elif (LZO_OS_WIN64 && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC)) #elif (LZO_ARCH_I386 && LZO_CC_GNUC && (LZO_CC_GNUC == 0x011f00ul)) #elif (LZO_ARCH_I386 && (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE)) # define LZO_ASM_SYNTAX_GNUC 1 #elif (LZO_ARCH_AMD64 && (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE)) # define LZO_ASM_SYNTAX_GNUC 1 #endif #if (LZO_ASM_SYNTAX_GNUC) #if (LZO_ARCH_I386 && LZO_CC_GNUC && (LZO_CC_GNUC < 0x020000ul)) # define __LZO_ASM_CLOBBER "ax" #elif (LZO_CC_INTELC) # define __LZO_ASM_CLOBBER "memory" #else # define __LZO_ASM_CLOBBER "cc", "memory" #endif #endif #if defined(__LZO_INFOSTR_MM) #elif (LZO_MM_FLAT) && (defined(__LZO_INFOSTR_PM) || defined(LZO_INFO_ABI_PM)) # define __LZO_INFOSTR_MM "" #elif defined(LZO_INFO_MM) # define __LZO_INFOSTR_MM "." LZO_INFO_MM #else # define __LZO_INFOSTR_MM "" #endif #if defined(__LZO_INFOSTR_PM) #elif defined(LZO_INFO_ABI_PM) # define __LZO_INFOSTR_PM "." LZO_INFO_ABI_PM #else # define __LZO_INFOSTR_PM "" #endif #if defined(__LZO_INFOSTR_ENDIAN) #elif defined(LZO_INFO_ABI_ENDIAN) # define __LZO_INFOSTR_ENDIAN "." LZO_INFO_ABI_ENDIAN #else # define __LZO_INFOSTR_ENDIAN "" #endif #if defined(__LZO_INFOSTR_OSNAME) #elif defined(LZO_INFO_OS_CONSOLE) # define __LZO_INFOSTR_OSNAME LZO_INFO_OS "." LZO_INFO_OS_CONSOLE #elif defined(LZO_INFO_OS_POSIX) # define __LZO_INFOSTR_OSNAME LZO_INFO_OS "." LZO_INFO_OS_POSIX #else # define __LZO_INFOSTR_OSNAME LZO_INFO_OS #endif #if defined(__LZO_INFOSTR_LIBC) #elif defined(LZO_INFO_LIBC) # define __LZO_INFOSTR_LIBC "." LZO_INFO_LIBC #else # define __LZO_INFOSTR_LIBC "" #endif #if defined(__LZO_INFOSTR_CCVER) #elif defined(LZO_INFO_CCVER) # define __LZO_INFOSTR_CCVER " " LZO_INFO_CCVER #else # define __LZO_INFOSTR_CCVER "" #endif #define LZO_INFO_STRING \ LZO_INFO_ARCH __LZO_INFOSTR_MM __LZO_INFOSTR_PM __LZO_INFOSTR_ENDIAN \ " " __LZO_INFOSTR_OSNAME __LZO_INFOSTR_LIBC " " LZO_INFO_CC __LZO_INFOSTR_CCVER #endif #endif #undef LZO_HAVE_CONFIG_H #include "minilzo.h" #if !defined(MINILZO_VERSION) || (MINILZO_VERSION != 0x2050) # error "version mismatch in miniLZO source files" #endif #ifdef MINILZO_HAVE_CONFIG_H # define LZO_HAVE_CONFIG_H 1 #endif #ifndef __LZO_CONF_H #define __LZO_CONF_H 1 #if !defined(__LZO_IN_MINILZO) #if (LZO_CFG_FREESTANDING) # define LZO_LIBC_FREESTANDING 1 # define LZO_OS_FREESTANDING 1 # define ACC_LIBC_FREESTANDING 1 # define ACC_OS_FREESTANDING 1 #endif #if (LZO_CFG_NO_UNALIGNED) # define ACC_CFG_NO_UNALIGNED 1 #endif #if (LZO_ARCH_GENERIC) # define ACC_ARCH_GENERIC 1 #endif #if (LZO_ABI_NEUTRAL_ENDIAN) # define ACC_ABI_NEUTRAL_ENDIAN 1 #endif #if (LZO_HAVE_CONFIG_H) # define ACC_CONFIG_NO_HEADER 1 #endif #if defined(LZO_CFG_EXTRA_CONFIG_HEADER) # include LZO_CFG_EXTRA_CONFIG_HEADER #endif #if defined(__LZOCONF_H) || defined(__LZOCONF_H_INCLUDED) # error "include this file first" #endif #include "lzo/lzoconf.h" #endif #if (LZO_VERSION < 0x02000) || !defined(__LZOCONF_H_INCLUDED) # error "version mismatch" #endif #if (LZO_CC_BORLANDC && LZO_ARCH_I086) # pragma option -h #endif #if (LZO_CC_MSC && (_MSC_VER >= 1000)) # pragma warning(disable: 4127 4701) #endif #if (LZO_CC_MSC && (_MSC_VER >= 1300)) # pragma warning(disable: 4820) # pragma warning(disable: 4514 4710 4711) #endif #if (LZO_CC_SUNPROC) #if !defined(__cplusplus) # pragma error_messages(off,E_END_OF_LOOP_CODE_NOT_REACHED) # pragma error_messages(off,E_LOOP_NOT_ENTERED_AT_TOP) # pragma error_messages(off,E_STATEMENT_NOT_REACHED) #endif #endif #if (__LZO_MMODEL_HUGE) && !(LZO_HAVE_MM_HUGE_PTR) # error "this should not happen - check defines for __huge" #endif #if defined(__LZO_IN_MINILZO) || defined(LZO_CFG_FREESTANDING) #elif (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16) # define ACC_WANT_ACC_INCD_H 1 # define ACC_WANT_ACC_INCE_H 1 # define ACC_WANT_ACC_INCI_H 1 #elif 1 # include <string.h> #else # define ACC_WANT_ACC_INCD_H 1 #endif #if (LZO_ARCH_I086) # define ACC_MM_AHSHIFT LZO_MM_AHSHIFT # define ACC_PTR_FP_OFF(x) (((const unsigned __far*)&(x))[0]) # define ACC_PTR_FP_SEG(x) (((const unsigned __far*)&(x))[1]) # define ACC_PTR_MK_FP(s,o) ((void __far*)(((unsigned long)(s)<<16)+(unsigned)(o))) #endif #if !defined(lzo_uintptr_t) # if defined(__LZO_MMODEL_HUGE) # define lzo_uintptr_t unsigned long # elif 1 && defined(LZO_OS_OS400) && (LZO_SIZEOF_VOID_P == 16) # define __LZO_UINTPTR_T_IS_POINTER 1 typedef char* lzo_uintptr_t; # define lzo_uintptr_t lzo_uintptr_t # elif (LZO_SIZEOF_SIZE_T == LZO_SIZEOF_VOID_P) # define lzo_uintptr_t size_t # elif (LZO_SIZEOF_LONG == LZO_SIZEOF_VOID_P) # define lzo_uintptr_t unsigned long # elif (LZO_SIZEOF_INT == LZO_SIZEOF_VOID_P) # define lzo_uintptr_t unsigned int # elif (LZO_SIZEOF_LONG_LONG == LZO_SIZEOF_VOID_P) # define lzo_uintptr_t unsigned long long # else # define lzo_uintptr_t size_t # endif #endif LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uintptr_t) >= sizeof(lzo_voidp)) #if 1 && !defined(LZO_CFG_FREESTANDING) #if 1 && !defined(HAVE_STRING_H) #define HAVE_STRING_H 1 #endif #if 1 && !defined(HAVE_MEMCMP) #define HAVE_MEMCMP 1 #endif #if 1 && !defined(HAVE_MEMCPY) #define HAVE_MEMCPY 1 #endif #if 1 && !defined(HAVE_MEMMOVE) #define HAVE_MEMMOVE 1 #endif #if 1 && !defined(HAVE_MEMSET) #define HAVE_MEMSET 1 #endif #endif #if 1 && defined(HAVE_STRING_H) #include <string.h> #endif #if (LZO_CFG_FREESTANDING) # undef HAVE_MEMCMP # undef HAVE_MEMCPY # undef HAVE_MEMMOVE # undef HAVE_MEMSET #endif #if !(HAVE_MEMCMP) # undef memcmp # define memcmp(a,b,c) lzo_memcmp(a,b,c) #elif !(__LZO_MMODEL_HUGE) # undef lzo_memcmp # define lzo_memcmp(a,b,c) memcmp(a,b,c) #endif #if !(HAVE_MEMCPY) # undef memcpy # define memcpy(a,b,c) lzo_memcpy(a,b,c) #elif !(__LZO_MMODEL_HUGE) # undef lzo_memcpy # define lzo_memcpy(a,b,c) memcpy(a,b,c) #endif #if !(HAVE_MEMMOVE) # undef memmove # define memmove(a,b,c) lzo_memmove(a,b,c) #elif !(__LZO_MMODEL_HUGE) # undef lzo_memmove # define lzo_memmove(a,b,c) memmove(a,b,c) #endif #if !(HAVE_MEMSET) # undef memset # define memset(a,b,c) lzo_memset(a,b,c) #elif !(__LZO_MMODEL_HUGE) # undef lzo_memset # define lzo_memset(a,b,c) memset(a,b,c) #endif #undef NDEBUG #if (LZO_CFG_FREESTANDING) # undef LZO_DEBUG # define NDEBUG 1 # undef assert # define assert(e) ((void)0) #else # if !defined(LZO_DEBUG) # define NDEBUG 1 # endif # include <assert.h> #endif #if 0 && defined(__BOUNDS_CHECKING_ON) # include <unchecked.h> #else # define BOUNDS_CHECKING_OFF_DURING(stmt) stmt # define BOUNDS_CHECKING_OFF_IN_EXPR(expr) (expr) #endif #if !defined(__lzo_inline) # define __lzo_inline /*empty*/ #endif #if !defined(__lzo_forceinline) # define __lzo_forceinline /*empty*/ #endif #if !defined(__lzo_noinline) # define __lzo_noinline /*empty*/ #endif #if (LZO_CFG_PGO) # undef __acc_likely # undef __acc_unlikely # undef __lzo_likely # undef __lzo_unlikely # define __acc_likely(e) (e) # define __acc_unlikely(e) (e) # define __lzo_likely(e) (e) # define __lzo_unlikely(e) (e) #endif #if 1 # define LZO_BYTE(x) ((unsigned char) (x)) #else # define LZO_BYTE(x) ((unsigned char) ((x) & 0xff)) #endif #define LZO_MAX(a,b) ((a) >= (b) ? (a) : (b)) #define LZO_MIN(a,b) ((a) <= (b) ? (a) : (b)) #define LZO_MAX3(a,b,c) ((a) >= (b) ? LZO_MAX(a,c) : LZO_MAX(b,c)) #define LZO_MIN3(a,b,c) ((a) <= (b) ? LZO_MIN(a,c) : LZO_MIN(b,c)) #define lzo_sizeof(type) ((lzo_uint) (sizeof(type))) #define LZO_HIGH(array) ((lzo_uint) (sizeof(array)/sizeof(*(array)))) #define LZO_SIZE(bits) (1u << (bits)) #define LZO_MASK(bits) (LZO_SIZE(bits) - 1) #define LZO_LSIZE(bits) (1ul << (bits)) #define LZO_LMASK(bits) (LZO_LSIZE(bits) - 1) #define LZO_USIZE(bits) ((lzo_uint) 1 << (bits)) #define LZO_UMASK(bits) (LZO_USIZE(bits) - 1) #if !defined(DMUL) #if 0 # define DMUL(a,b) ((lzo_xint) ((lzo_uint32)(a) * (lzo_uint32)(b))) #else # define DMUL(a,b) ((lzo_xint) ((a) * (b))) #endif #endif #if 1 && (LZO_ARCH_AMD64 || LZO_ARCH_I386 || LZO_ARCH_POWERPC) # if (LZO_SIZEOF_SHORT == 2) # define LZO_UNALIGNED_OK_2 1 # endif # if (LZO_SIZEOF_INT == 4) # define LZO_UNALIGNED_OK_4 1 # endif #endif #if 1 && (LZO_ARCH_AMD64) # if defined(LZO_UINT64_MAX) # define LZO_UNALIGNED_OK_8 1 # endif #endif #if (LZO_CFG_NO_UNALIGNED) # undef LZO_UNALIGNED_OK_2 # undef LZO_UNALIGNED_OK_4 # undef LZO_UNALIGNED_OK_8 #endif #undef UA_GET16 #undef UA_SET16 #undef UA_COPY16 #undef UA_GET32 #undef UA_SET32 #undef UA_COPY32 #undef UA_GET64 #undef UA_SET64 #undef UA_COPY64 #if defined(LZO_UNALIGNED_OK_2) LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(unsigned short) == 2) # if 1 && defined(ACC_UA_COPY16) # define UA_GET16 ACC_UA_GET16 # define UA_SET16 ACC_UA_SET16 # define UA_COPY16 ACC_UA_COPY16 # else # define UA_GET16(p) (* (__lzo_ua_volatile const lzo_ushortp) (__lzo_ua_volatile const lzo_voidp) (p)) # define UA_SET16(p,v) ((* (__lzo_ua_volatile lzo_ushortp) (__lzo_ua_volatile lzo_voidp) (p)) = (unsigned short) (v)) # define UA_COPY16(d,s) UA_SET16(d, UA_GET16(s)) # endif #endif #if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4) LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint32) == 4) # if 1 && defined(ACC_UA_COPY32) # define UA_GET32 ACC_UA_GET32 # define UA_SET32 ACC_UA_SET32 # define UA_COPY32 ACC_UA_COPY32 # else # define UA_GET32(p) (* (__lzo_ua_volatile const lzo_uint32p) (__lzo_ua_volatile const lzo_voidp) (p)) # define UA_SET32(p,v) ((* (__lzo_ua_volatile lzo_uint32p) (__lzo_ua_volatile lzo_voidp) (p)) = (lzo_uint32) (v)) # define UA_COPY32(d,s) UA_SET32(d, UA_GET32(s)) # endif #endif #if defined(LZO_UNALIGNED_OK_8) LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint64) == 8) # if 1 && defined(ACC_UA_COPY64) # define UA_GET64 ACC_UA_GET64 # define UA_SET64 ACC_UA_SET64 # define UA_COPY64 ACC_UA_COPY64 # else # define UA_GET64(p) (* (__lzo_ua_volatile const lzo_uint64p) (__lzo_ua_volatile const lzo_voidp) (p)) # define UA_SET64(p,v) ((* (__lzo_ua_volatile lzo_uint64p) (__lzo_ua_volatile lzo_voidp) (p)) = (lzo_uint64) (v)) # define UA_COPY64(d,s) UA_SET64(d, UA_GET64(s)) # endif #endif #define MEMCPY8_DS(dest,src,len) \ lzo_memcpy(dest,src,len); dest += len; src += len #define BZERO8_PTR(s,l,n) \ lzo_memset((lzo_voidp)(s),0,(lzo_uint)(l)*(n)) #define MEMCPY_DS(dest,src,len) \ do *dest++ = *src++; while (--len > 0) LZO_EXTERN(const lzo_bytep) lzo_copyright(void); #ifndef __LZO_PTR_H #define __LZO_PTR_H 1 #ifdef __cplusplus extern "C" { #endif #if !defined(lzo_uintptr_t) # if (__LZO_MMODEL_HUGE) # define lzo_uintptr_t unsigned long # else # define lzo_uintptr_t acc_uintptr_t # ifdef __ACC_INTPTR_T_IS_POINTER # define __LZO_UINTPTR_T_IS_POINTER 1 # endif # endif #endif #if (LZO_ARCH_I086) #define PTR(a) ((lzo_bytep) (a)) #define PTR_ALIGNED_4(a) ((ACC_PTR_FP_OFF(a) & 3) == 0) #define PTR_ALIGNED2_4(a,b) (((ACC_PTR_FP_OFF(a) | ACC_PTR_FP_OFF(b)) & 3) == 0) #elif (LZO_MM_PVP) #define PTR(a) ((lzo_bytep) (a)) #define PTR_ALIGNED_8(a) ((((lzo_uintptr_t)(a)) >> 61) == 0) #define PTR_ALIGNED2_8(a,b) ((((lzo_uintptr_t)(a)|(lzo_uintptr_t)(b)) >> 61) == 0) #else #define PTR(a) ((lzo_uintptr_t) (a)) #define PTR_LINEAR(a) PTR(a) #define PTR_ALIGNED_4(a) ((PTR_LINEAR(a) & 3) == 0) #define PTR_ALIGNED_8(a) ((PTR_LINEAR(a) & 7) == 0) #define PTR_ALIGNED2_4(a,b) (((PTR_LINEAR(a) | PTR_LINEAR(b)) & 3) == 0) #define PTR_ALIGNED2_8(a,b) (((PTR_LINEAR(a) | PTR_LINEAR(b)) & 7) == 0) #endif #define PTR_LT(a,b) (PTR(a) < PTR(b)) #define PTR_GE(a,b) (PTR(a) >= PTR(b)) #define PTR_DIFF(a,b) (PTR(a) - PTR(b)) #define pd(a,b) ((lzo_uint) ((a)-(b))) LZO_EXTERN(lzo_uintptr_t) __lzo_ptr_linear(const lzo_voidp ptr); typedef union { char a_char; unsigned char a_uchar; short a_short; unsigned short a_ushort; int a_int; unsigned int a_uint; long a_long; unsigned long a_ulong; lzo_int a_lzo_int; lzo_uint a_lzo_uint; lzo_int32 a_lzo_int32; lzo_uint32 a_lzo_uint32; #if defined(LZO_UINT64_MAX) lzo_int64 a_lzo_int64; lzo_uint64 a_lzo_uint64; #endif ptrdiff_t a_ptrdiff_t; lzo_uintptr_t a_lzo_uintptr_t; lzo_voidp a_lzo_voidp; void * a_void_p; lzo_bytep a_lzo_bytep; lzo_bytepp a_lzo_bytepp; lzo_uintp a_lzo_uintp; lzo_uint * a_lzo_uint_p; lzo_uint32p a_lzo_uint32p; lzo_uint32 * a_lzo_uint32_p; unsigned char * a_uchar_p; char * a_char_p; } lzo_full_align_t; #ifdef __cplusplus } #endif #endif #ifndef LZO_DETERMINISTIC #define LZO_DETERMINISTIC 1 #endif #ifndef LZO_DICT_USE_PTR #define LZO_DICT_USE_PTR 1 #if 0 && (LZO_ARCH_I086) # undef LZO_DICT_USE_PTR # define LZO_DICT_USE_PTR 0 #endif #endif #if (LZO_DICT_USE_PTR) # define lzo_dict_t const lzo_bytep # define lzo_dict_p lzo_dict_t __LZO_MMODEL * #else # define lzo_dict_t lzo_uint # define lzo_dict_p lzo_dict_t __LZO_MMODEL * #endif #endif #if !defined(MINILZO_CFG_SKIP_LZO_PTR) LZO_PUBLIC(lzo_uintptr_t) __lzo_ptr_linear(const lzo_voidp ptr) { lzo_uintptr_t p; #if (LZO_ARCH_I086) p = (((lzo_uintptr_t)(ACC_PTR_FP_SEG(ptr))) << (16 - ACC_MM_AHSHIFT)) + (ACC_PTR_FP_OFF(ptr)); #elif (LZO_MM_PVP) p = (lzo_uintptr_t) (ptr); p = (p << 3) | (p >> 61); #else p = (lzo_uintptr_t) PTR_LINEAR(ptr); #endif return p; } LZO_PUBLIC(unsigned) __lzo_align_gap(const lzo_voidp ptr, lzo_uint size) { #if defined(__LZO_UINTPTR_T_IS_POINTER) size_t n = (size_t) ptr; n = (((n + size - 1) / size) * size) - n; #else lzo_uintptr_t p, n; p = __lzo_ptr_linear(ptr); n = (((p + size - 1) / size) * size) - p; #endif assert(size > 0); assert((long)n >= 0); assert(n <= size); return (unsigned)n; } #endif #if !defined(MINILZO_CFG_SKIP_LZO_UTIL) /* If you use the LZO library in a product, I would appreciate that you * keep this copyright string in the executable of your product. */ static const char __lzo_copyright[] = #if !defined(__LZO_IN_MINLZO) LZO_VERSION_STRING; #else "\r\n\n" "LZO data compression library.\n" "$Copyright: LZO Copyright (C) 1996-2011 Markus Franz Xaver Johannes Oberhumer\n" "<markus@oberhumer.com>\n" "http://www.oberhumer.com $\n\n" "$Id: LZO version: v" LZO_VERSION_STRING ", " LZO_VERSION_DATE " $\n" "$Info: " LZO_INFO_STRING " $\n"; #endif LZO_PUBLIC(const lzo_bytep) lzo_copyright(void) { #if (LZO_OS_DOS16 && LZO_CC_TURBOC) return (lzo_voidp) __lzo_copyright; #else return (const lzo_bytep) __lzo_copyright; #endif } LZO_PUBLIC(unsigned) lzo_version(void) { return LZO_VERSION; } LZO_PUBLIC(const char *) lzo_version_string(void) { return LZO_VERSION_STRING; } LZO_PUBLIC(const char *) lzo_version_date(void) { return LZO_VERSION_DATE; } LZO_PUBLIC(const lzo_charp) _lzo_version_string(void) { return LZO_VERSION_STRING; } LZO_PUBLIC(const lzo_charp) _lzo_version_date(void) { return LZO_VERSION_DATE; } #define LZO_BASE 65521u #define LZO_NMAX 5552 #define LZO_DO1(buf,i) s1 += buf[i]; s2 += s1 #define LZO_DO2(buf,i) LZO_DO1(buf,i); LZO_DO1(buf,i+1); #define LZO_DO4(buf,i) LZO_DO2(buf,i); LZO_DO2(buf,i+2); #define LZO_DO8(buf,i) LZO_DO4(buf,i); LZO_DO4(buf,i+4); #define LZO_DO16(buf,i) LZO_DO8(buf,i); LZO_DO8(buf,i+8); LZO_PUBLIC(lzo_uint32) lzo_adler32(lzo_uint32 adler, const lzo_bytep buf, lzo_uint len) { lzo_uint32 s1 = adler & 0xffff; lzo_uint32 s2 = (adler >> 16) & 0xffff; unsigned k; if (buf == NULL) return 1; while (len > 0) { k = len < LZO_NMAX ? (unsigned) len : LZO_NMAX; len -= k; if (k >= 16) do { LZO_DO16(buf,0); buf += 16; k -= 16; } while (k >= 16); if (k != 0) do { s1 += *buf++; s2 += s1; } while (--k > 0); s1 %= LZO_BASE; s2 %= LZO_BASE; } return (s2 << 16) | s1; } #undef LZO_DO1 #undef LZO_DO2 #undef LZO_DO4 #undef LZO_DO8 #undef LZO_DO16 #endif #if !defined(MINILZO_CFG_SKIP_LZO_STRING) #undef lzo_memcmp #undef lzo_memcpy #undef lzo_memmove #undef lzo_memset #if !defined(__LZO_MMODEL_HUGE) # undef LZO_HAVE_MM_HUGE_PTR #endif #define lzo_hsize_t lzo_uint #define lzo_hvoid_p lzo_voidp #define lzo_hbyte_p lzo_bytep #define LZOLIB_PUBLIC(r,f) LZO_PUBLIC(r) f #define lzo_hmemcmp lzo_memcmp #define lzo_hmemcpy lzo_memcpy #define lzo_hmemmove lzo_memmove #define lzo_hmemset lzo_memset #define __LZOLIB_HMEMCPY_CH_INCLUDED 1 #if !defined(LZOLIB_PUBLIC) # define LZOLIB_PUBLIC(r,f) r __LZOLIB_FUNCNAME(f) #endif LZOLIB_PUBLIC(int, lzo_hmemcmp) (const lzo_hvoid_p s1, const lzo_hvoid_p s2, lzo_hsize_t len) { #if (LZO_HAVE_MM_HUGE_PTR) || !(HAVE_MEMCMP) const lzo_hbyte_p p1 = (const lzo_hbyte_p) s1; const lzo_hbyte_p p2 = (const lzo_hbyte_p) s2; if __lzo_likely(len > 0) do { int d = *p1 - *p2; if (d != 0) return d; p1++; p2++; } while __lzo_likely(--len > 0); return 0; #else return memcmp(s1, s2, len); #endif } LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemcpy) (lzo_hvoid_p dest, const lzo_hvoid_p src, lzo_hsize_t len) { #if (LZO_HAVE_MM_HUGE_PTR) || !(HAVE_MEMCPY) lzo_hbyte_p p1 = (lzo_hbyte_p) dest; const lzo_hbyte_p p2 = (const lzo_hbyte_p) src; if (!(len > 0) || p1 == p2) return dest; do *p1++ = *p2++; while __lzo_likely(--len > 0); return dest; #else return memcpy(dest, src, len); #endif } LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemmove) (lzo_hvoid_p dest, const lzo_hvoid_p src, lzo_hsize_t len) { #if (LZO_HAVE_MM_HUGE_PTR) || !(HAVE_MEMMOVE) lzo_hbyte_p p1 = (lzo_hbyte_p) dest; const lzo_hbyte_p p2 = (const lzo_hbyte_p) src; if (!(len > 0) || p1 == p2) return dest; if (p1 < p2) { do *p1++ = *p2++; while __lzo_likely(--len > 0); } else { p1 += len; p2 += len; do *--p1 = *--p2; while __lzo_likely(--len > 0); } return dest; #else return memmove(dest, src, len); #endif } LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemset) (lzo_hvoid_p s, int c, lzo_hsize_t len) { #if (LZO_HAVE_MM_HUGE_PTR) || !(HAVE_MEMSET) lzo_hbyte_p p = (lzo_hbyte_p) s; if __lzo_likely(len > 0) do *p++ = (unsigned char) c; while __lzo_likely(--len > 0); return s; #else return memset(s, c, len); #endif } #undef LZOLIB_PUBLIC #endif #if !defined(MINILZO_CFG_SKIP_LZO_INIT) #if !defined(__LZO_IN_MINILZO) #define ACC_WANT_ACC_CHK_CH 1 #undef ACCCHK_ASSERT ACCCHK_ASSERT_IS_SIGNED_T(lzo_int) ACCCHK_ASSERT_IS_UNSIGNED_T(lzo_uint) ACCCHK_ASSERT_IS_SIGNED_T(lzo_int32) ACCCHK_ASSERT_IS_UNSIGNED_T(lzo_uint32) ACCCHK_ASSERT((LZO_UINT32_C(1) << (int)(8*sizeof(LZO_UINT32_C(1))-1)) > 0) ACCCHK_ASSERT(sizeof(lzo_uint32) >= 4) #if defined(LZO_UINT64_MAX) ACCCHK_ASSERT(sizeof(lzo_uint64) == 8) ACCCHK_ASSERT_IS_SIGNED_T(lzo_int64) ACCCHK_ASSERT_IS_UNSIGNED_T(lzo_uint64) #endif #if !defined(__LZO_UINTPTR_T_IS_POINTER) ACCCHK_ASSERT_IS_UNSIGNED_T(lzo_uintptr_t) #endif ACCCHK_ASSERT(sizeof(lzo_uintptr_t) >= sizeof(lzo_voidp)) ACCCHK_ASSERT_IS_UNSIGNED_T(lzo_xint) ACCCHK_ASSERT(sizeof(lzo_xint) >= sizeof(lzo_uint32)) ACCCHK_ASSERT(sizeof(lzo_xint) >= sizeof(lzo_uint)) ACCCHK_ASSERT(sizeof(lzo_xint) == sizeof(lzo_uint32) || sizeof(lzo_xint) == sizeof(lzo_uint)) #endif #undef ACCCHK_ASSERT #if 0 #define WANT_lzo_bitops_clz32 1 #define WANT_lzo_bitops_clz64 1 #endif #define WANT_lzo_bitops_ctz32 1 #define WANT_lzo_bitops_ctz64 1 #if (defined(_WIN32) || defined(_WIN64)) && ((LZO_CC_INTELC && (__INTEL_COMPILER >= 1000)) || (LZO_CC_MSC && (_MSC_VER >= 1400))) #include <intrin.h> #if !defined(lzo_bitops_clz32) && defined(WANT_lzo_bitops_clz32) && 0 #pragma intrinsic(_BitScanReverse) static __lzo_inline unsigned lzo_bitops_clz32(lzo_uint32 v) { unsigned long r; (void) _BitScanReverse(&r, v); return (unsigned) r; } #define lzo_bitops_clz32 lzo_bitops_clz32 #endif #if !defined(lzo_bitops_clz64) && defined(WANT_lzo_bitops_clz64) && defined(LZO_UINT64_MAX) && 0 #pragma intrinsic(_BitScanReverse64) static __lzo_inline unsigned lzo_bitops_clz64(lzo_uint64 v) { unsigned long r; (void) _BitScanReverse64(&r, v); return (unsigned) r; } #define lzo_bitops_clz64 lzo_bitops_clz64 #endif #if !defined(lzo_bitops_ctz32) && defined(WANT_lzo_bitops_ctz32) #pragma intrinsic(_BitScanForward) static __lzo_inline unsigned lzo_bitops_ctz32(lzo_uint32 v) { unsigned long r; (void) _BitScanForward(&r, v); return (unsigned) r; } #define lzo_bitops_ctz32 lzo_bitops_ctz32 #endif #if !defined(lzo_bitops_ctz64) && defined(WANT_lzo_bitops_ctz64) && defined(LZO_UINT64_MAX) #pragma intrinsic(_BitScanForward64) static __lzo_inline unsigned lzo_bitops_ctz64(lzo_uint64 v) { unsigned long r; (void) _BitScanForward64(&r, v); return (unsigned) r; } #define lzo_bitops_ctz64 lzo_bitops_ctz64 #endif #elif (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x030400ul) || (LZO_CC_INTELC && (__INTEL_COMPILER >= 1000)) || LZO_CC_LLVM) #if !defined(lzo_bitops_clz32) && defined(WANT_lzo_bitops_clz32) #define lzo_bitops_clz32(v) ((unsigned) __builtin_clz(v)) #endif #if !defined(lzo_bitops_clz64) && defined(WANT_lzo_bitops_clz64) && defined(LZO_UINT64_MAX) #define lzo_bitops_clz64(v) ((unsigned) __builtin_clzll(v)) #endif #if !defined(lzo_bitops_ctz32) && defined(WANT_lzo_bitops_ctz32) #define lzo_bitops_ctz32(v) ((unsigned) __builtin_ctz(v)) #endif #if !defined(lzo_bitops_ctz64) && defined(WANT_lzo_bitops_ctz64) && defined(LZO_UINT64_MAX) #define lzo_bitops_ctz64(v) ((unsigned) __builtin_ctzll(v)) #endif #if !defined(lzo_bitops_popcount32) && defined(WANT_lzo_bitops_popcount32) #define lzo_bitops_popcount32(v) ((unsigned) __builtin_popcount(v)) #endif #if !defined(lzo_bitops_popcount32) && defined(WANT_lzo_bitops_popcount64) && defined(LZO_UINT64_MAX) #define lzo_bitops_popcount64(v) ((unsigned) __builtin_popcountll(v)) #endif #endif #if 0 #define u2p(ptr,off) ((lzo_voidp) (((lzo_bytep)(lzo_voidp)(ptr)) + (off))) #else static __lzo_noinline lzo_voidp u2p(lzo_voidp ptr, lzo_uint off) { return (lzo_voidp) ((lzo_bytep) ptr + off); } #endif LZO_PUBLIC(int) _lzo_config_check(void) { lzo_bool r = 1; union { lzo_xint a[2]; unsigned char b[2*LZO_MAX(8,sizeof(lzo_xint))]; #if defined(LZO_UNALIGNED_OK_8) lzo_uint64 c[2]; #endif unsigned short x[2]; lzo_uint32 y[2]; lzo_uint z[2]; } u; lzo_voidp p; u.a[0] = u.a[1] = 0; p = u2p(&u, 0); r &= ((* (lzo_bytep) p) == 0); #if !defined(LZO_CFG_NO_CONFIG_CHECK) #if defined(LZO_ABI_BIG_ENDIAN) u.a[0] = u.a[1] = 0; u.b[sizeof(lzo_uint) - 1] = 128; p = u2p(&u, 0); r &= ((* (lzo_uintp) p) == 128); #endif #if defined(LZO_ABI_LITTLE_ENDIAN) u.a[0] = u.a[1] = 0; u.b[0] = 128; p = u2p(&u, 0); r &= ((* (lzo_uintp) p) == 128); #endif #if defined(LZO_UNALIGNED_OK_2) u.a[0] = u.a[1] = 0; u.b[0] = 1; u.b[sizeof(unsigned short) + 1] = 2; p = u2p(&u, 1); r &= ((* (lzo_ushortp) p) == 0); #endif #if defined(LZO_UNALIGNED_OK_4) u.a[0] = u.a[1] = 0; u.b[0] = 3; u.b[sizeof(lzo_uint32) + 1] = 4; p = u2p(&u, 1); r &= ((* (lzo_uint32p) p) == 0); #endif #if defined(LZO_UNALIGNED_OK_8) u.c[0] = u.c[1] = 0; u.b[0] = 5; u.b[sizeof(lzo_uint64) + 1] = 6; p = u2p(&u, 1); r &= ((* (lzo_uint64p) p) == 0); #endif #if defined(lzo_bitops_clz32) { unsigned i; lzo_uint32 v = 1; for (i = 0; i < 31; i++, v <<= 1) r &= lzo_bitops_clz32(v) == 31 - i; } #endif #if defined(lzo_bitops_clz64) { unsigned i; lzo_uint64 v = 1; for (i = 0; i < 63; i++, v <<= 1) r &= lzo_bitops_clz64(v) == 63 - i; } #endif #if defined(lzo_bitops_ctz32) { unsigned i; lzo_uint32 v = 1; for (i = 0; i < 31; i++, v <<= 1) r &= lzo_bitops_ctz32(v) == i; } #endif #if defined(lzo_bitops_ctz64) { unsigned i; lzo_uint64 v = 1; for (i = 0; i < 63; i++, v <<= 1) r &= lzo_bitops_ctz64(v) == i; } #endif #endif return r == 1 ? LZO_E_OK : LZO_E_ERROR; } LZO_PUBLIC(int) __lzo_init_v2(unsigned v, int s1, int s2, int s3, int s4, int s5, int s6, int s7, int s8, int s9) { int r; #if defined(__LZO_IN_MINILZO) #elif (LZO_CC_MSC && ((_MSC_VER) < 700)) #else #define ACC_WANT_ACC_CHK_CH 1 #undef ACCCHK_ASSERT #define ACCCHK_ASSERT(expr) LZO_COMPILE_TIME_ASSERT(expr) #endif #undef ACCCHK_ASSERT if (v == 0) return LZO_E_ERROR; r = (s1 == -1 || s1 == (int) sizeof(short)) && (s2 == -1 || s2 == (int) sizeof(int)) && (s3 == -1 || s3 == (int) sizeof(long)) && (s4 == -1 || s4 == (int) sizeof(lzo_uint32)) && (s5 == -1 || s5 == (int) sizeof(lzo_uint)) && (s6 == -1 || s6 == (int) lzo_sizeof_dict_t) && (s7 == -1 || s7 == (int) sizeof(char *)) && (s8 == -1 || s8 == (int) sizeof(lzo_voidp)) && (s9 == -1 || s9 == (int) sizeof(lzo_callback_t)); if (!r) return LZO_E_ERROR; r = _lzo_config_check(); if (r != LZO_E_OK) return r; return r; } #if !defined(__LZO_IN_MINILZO) #if (LZO_OS_WIN16 && LZO_CC_WATCOMC) && defined(__SW_BD) #if 0 BOOL FAR PASCAL LibMain ( HANDLE hInstance, WORD wDataSegment, WORD wHeapSize, LPSTR lpszCmdLine ) #else int __far __pascal LibMain ( int a, short b, short c, long d ) #endif { LZO_UNUSED(a); LZO_UNUSED(b); LZO_UNUSED(c); LZO_UNUSED(d); return 1; } #endif #endif #endif #define LZO1X 1 #define LZO_EOF_CODE 1 #define M2_MAX_OFFSET 0x0800 #if !defined(MINILZO_CFG_SKIP_LZO1X_1_COMPRESS) #if 1 && defined(UA_GET32) #undef LZO_DICT_USE_PTR #define LZO_DICT_USE_PTR 0 #undef lzo_dict_t #define lzo_dict_t unsigned short #endif #define LZO_NEED_DICT_H 1 #ifndef D_BITS #define D_BITS 14 #endif #define D_INDEX1(d,p) d = DM(DMUL(0x21,DX3(p,5,5,6)) >> 5) #define D_INDEX2(d,p) d = (d & (D_MASK & 0x7ff)) ^ (D_HIGH | 0x1f) #if 1 #define DINDEX(dv,p) DM(((DMUL(0x1824429d,dv)) >> (32-D_BITS))) #else #define DINDEX(dv,p) DM((dv) + ((dv) >> (32-D_BITS))) #endif #ifndef __LZO_CONFIG1X_H #define __LZO_CONFIG1X_H 1 #if !defined(LZO1X) && !defined(LZO1Y) && !defined(LZO1Z) # define LZO1X 1 #endif #if !defined(__LZO_IN_MINILZO) #include "lzo/lzo1x.h" #endif #ifndef LZO_EOF_CODE #define LZO_EOF_CODE 1 #endif #undef LZO_DETERMINISTIC #define M1_MAX_OFFSET 0x0400 #ifndef M2_MAX_OFFSET #define M2_MAX_OFFSET 0x0800 #endif #define M3_MAX_OFFSET 0x4000 #define M4_MAX_OFFSET 0xbfff #define MX_MAX_OFFSET (M1_MAX_OFFSET + M2_MAX_OFFSET) #define M1_MIN_LEN 2 #define M1_MAX_LEN 2 #define M2_MIN_LEN 3 #ifndef M2_MAX_LEN #define M2_MAX_LEN 8 #endif #define M3_MIN_LEN 3 #define M3_MAX_LEN 33 #define M4_MIN_LEN 3 #define M4_MAX_LEN 9 #define M1_MARKER 0 #define M2_MARKER 64 #define M3_MARKER 32 #define M4_MARKER 16 #ifndef MIN_LOOKAHEAD #define MIN_LOOKAHEAD (M2_MAX_LEN + 1) #endif #if defined(LZO_NEED_DICT_H) #ifndef LZO_HASH #define LZO_HASH LZO_HASH_LZO_INCREMENTAL_B #endif #define DL_MIN_LEN M2_MIN_LEN #ifndef __LZO_DICT_H #define __LZO_DICT_H 1 #ifdef __cplusplus extern "C" { #endif #if !defined(D_BITS) && defined(DBITS) # define D_BITS DBITS #endif #if !defined(D_BITS) # error "D_BITS is not defined" #endif #if (D_BITS < 16) # define D_SIZE LZO_SIZE(D_BITS) # define D_MASK LZO_MASK(D_BITS) #else # define D_SIZE LZO_USIZE(D_BITS) # define D_MASK LZO_UMASK(D_BITS) #endif #define D_HIGH ((D_MASK >> 1) + 1) #if !defined(DD_BITS) # define DD_BITS 0 #endif #define DD_SIZE LZO_SIZE(DD_BITS) #define DD_MASK LZO_MASK(DD_BITS) #if !defined(DL_BITS) # define DL_BITS (D_BITS - DD_BITS) #endif #if (DL_BITS < 16) # define DL_SIZE LZO_SIZE(DL_BITS) # define DL_MASK LZO_MASK(DL_BITS) #else # define DL_SIZE LZO_USIZE(DL_BITS) # define DL_MASK LZO_UMASK(DL_BITS) #endif #if (D_BITS != DL_BITS + DD_BITS) # error "D_BITS does not match" #endif #if (D_BITS < 6 || D_BITS > 18) # error "invalid D_BITS" #endif #if (DL_BITS < 6 || DL_BITS > 20) # error "invalid DL_BITS" #endif #if (DD_BITS < 0 || DD_BITS > 6) # error "invalid DD_BITS" #endif #if !defined(DL_MIN_LEN) # define DL_MIN_LEN 3 #endif #if !defined(DL_SHIFT) # define DL_SHIFT ((DL_BITS + (DL_MIN_LEN - 1)) / DL_MIN_LEN) #endif #define LZO_HASH_GZIP 1 #define LZO_HASH_GZIP_INCREMENTAL 2 #define LZO_HASH_LZO_INCREMENTAL_A 3 #define LZO_HASH_LZO_INCREMENTAL_B 4 #if !defined(LZO_HASH) # error "choose a hashing strategy" #endif #undef DM #undef DX #if (DL_MIN_LEN == 3) # define _DV2_A(p,shift1,shift2) \ (((( (lzo_xint)((p)[0]) << shift1) ^ (p)[1]) << shift2) ^ (p)[2]) # define _DV2_B(p,shift1,shift2) \ (((( (lzo_xint)((p)[2]) << shift1) ^ (p)[1]) << shift2) ^ (p)[0]) # define _DV3_B(p,shift1,shift2,shift3) \ ((_DV2_B((p)+1,shift1,shift2) << (shift3)) ^ (p)[0]) #elif (DL_MIN_LEN == 2) # define _DV2_A(p,shift1,shift2) \ (( (lzo_xint)(p[0]) << shift1) ^ p[1]) # define _DV2_B(p,shift1,shift2) \ (( (lzo_xint)(p[1]) << shift1) ^ p[2]) #else # error "invalid DL_MIN_LEN" #endif #define _DV_A(p,shift) _DV2_A(p,shift,shift) #define _DV_B(p,shift) _DV2_B(p,shift,shift) #define DA2(p,s1,s2) \ (((((lzo_xint)((p)[2]) << (s2)) + (p)[1]) << (s1)) + (p)[0]) #define DS2(p,s1,s2) \ (((((lzo_xint)((p)[2]) << (s2)) - (p)[1]) << (s1)) - (p)[0]) #define DX2(p,s1,s2) \ (((((lzo_xint)((p)[2]) << (s2)) ^ (p)[1]) << (s1)) ^ (p)[0]) #define DA3(p,s1,s2,s3) ((DA2((p)+1,s2,s3) << (s1)) + (p)[0]) #define DS3(p,s1,s2,s3) ((DS2((p)+1,s2,s3) << (s1)) - (p)[0]) #define DX3(p,s1,s2,s3) ((DX2((p)+1,s2,s3) << (s1)) ^ (p)[0]) #define DMS(v,s) ((lzo_uint) (((v) & (D_MASK >> (s))) << (s))) #define DM(v) DMS(v,0) #if (LZO_HASH == LZO_HASH_GZIP) # define _DINDEX(dv,p) (_DV_A((p),DL_SHIFT)) #elif (LZO_HASH == LZO_HASH_GZIP_INCREMENTAL) # define __LZO_HASH_INCREMENTAL 1 # define DVAL_FIRST(dv,p) dv = _DV_A((p),DL_SHIFT) # define DVAL_NEXT(dv,p) dv = (((dv) << DL_SHIFT) ^ p[2]) # define _DINDEX(dv,p) (dv) # define DVAL_LOOKAHEAD DL_MIN_LEN #elif (LZO_HASH == LZO_HASH_LZO_INCREMENTAL_A) # define __LZO_HASH_INCREMENTAL 1 # define DVAL_FIRST(dv,p) dv = _DV_A((p),5) # define DVAL_NEXT(dv,p) \ dv ^= (lzo_xint)(p[-1]) << (2*5); dv = (((dv) << 5) ^ p[2]) # define _DINDEX(dv,p) ((DMUL(0x9f5f,dv)) >> 5) # define DVAL_LOOKAHEAD DL_MIN_LEN #elif (LZO_HASH == LZO_HASH_LZO_INCREMENTAL_B) # define __LZO_HASH_INCREMENTAL 1 # define DVAL_FIRST(dv,p) dv = _DV_B((p),5) # define DVAL_NEXT(dv,p) \ dv ^= p[-1]; dv = (((dv) >> 5) ^ ((lzo_xint)(p[2]) << (2*5))) # define _DINDEX(dv,p) ((DMUL(0x9f5f,dv)) >> 5) # define DVAL_LOOKAHEAD DL_MIN_LEN #else # error "choose a hashing strategy" #endif #ifndef DINDEX #define DINDEX(dv,p) ((lzo_uint)((_DINDEX(dv,p)) & DL_MASK) << DD_BITS) #endif #if !defined(DINDEX1) && defined(D_INDEX1) #define DINDEX1 D_INDEX1 #endif #if !defined(DINDEX2) && defined(D_INDEX2) #define DINDEX2 D_INDEX2 #endif #if !defined(__LZO_HASH_INCREMENTAL) # define DVAL_FIRST(dv,p) ((void) 0) # define DVAL_NEXT(dv,p) ((void) 0) # define DVAL_LOOKAHEAD 0 #endif #if !defined(DVAL_ASSERT) #if defined(__LZO_HASH_INCREMENTAL) && !defined(NDEBUG) #if (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x020700ul) || LZO_CC_LLVM) static void __attribute__((__unused__)) #else static void #endif DVAL_ASSERT(lzo_xint dv, const lzo_bytep p) { lzo_xint df; DVAL_FIRST(df,(p)); assert(DINDEX(dv,p) == DINDEX(df,p)); } #else # define DVAL_ASSERT(dv,p) ((void) 0) #endif #endif #if (LZO_DICT_USE_PTR) # define DENTRY(p,in) (p) # define GINDEX(m_pos,m_off,dict,dindex,in) m_pos = dict[dindex] #else # define DENTRY(p,in) ((lzo_dict_t) pd(p, in)) # define GINDEX(m_pos,m_off,dict,dindex,in) m_off = dict[dindex] #endif #if (DD_BITS == 0) # define UPDATE_D(dict,drun,dv,p,in) dict[ DINDEX(dv,p) ] = DENTRY(p,in) # define UPDATE_I(dict,drun,index,p,in) dict[index] = DENTRY(p,in) # define UPDATE_P(ptr,drun,p,in) (ptr)[0] = DENTRY(p,in) #else # define UPDATE_D(dict,drun,dv,p,in) \ dict[ DINDEX(dv,p) + drun++ ] = DENTRY(p,in); drun &= DD_MASK # define UPDATE_I(dict,drun,index,p,in) \ dict[ (index) + drun++ ] = DENTRY(p,in); drun &= DD_MASK # define UPDATE_P(ptr,drun,p,in) \ (ptr) [ drun++ ] = DENTRY(p,in); drun &= DD_MASK #endif #if (LZO_DICT_USE_PTR) #define LZO_CHECK_MPOS_DET(m_pos,m_off,in,ip,max_offset) \ (m_pos == NULL || (m_off = pd(ip, m_pos)) > max_offset) #define LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,max_offset) \ (BOUNDS_CHECKING_OFF_IN_EXPR(( \ m_pos = ip - (lzo_uint) PTR_DIFF(ip,m_pos), \ PTR_LT(m_pos,in) || \ (m_off = (lzo_uint) PTR_DIFF(ip,m_pos)) == 0 || \ m_off > max_offset ))) #else #define LZO_CHECK_MPOS_DET(m_pos,m_off,in,ip,max_offset) \ (m_off == 0 || \ ((m_off = pd(ip, in) - m_off) > max_offset) || \ (m_pos = (ip) - (m_off), 0) ) #define LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,max_offset) \ (pd(ip, in) <= m_off || \ ((m_off = pd(ip, in) - m_off) > max_offset) || \ (m_pos = (ip) - (m_off), 0) ) #endif #if (LZO_DETERMINISTIC) # define LZO_CHECK_MPOS LZO_CHECK_MPOS_DET #else # define LZO_CHECK_MPOS LZO_CHECK_MPOS_NON_DET #endif #ifdef __cplusplus } #endif #endif #endif #endif #define LZO_DETERMINISTIC !(LZO_DICT_USE_PTR) #ifndef DO_COMPRESS #define DO_COMPRESS lzo1x_1_compress #endif #if 1 && defined(DO_COMPRESS) && !defined(do_compress) # define do_compress LZO_CPP_ECONCAT2(DO_COMPRESS,_core) #endif #if defined(UA_GET64) # define WANT_lzo_bitops_ctz64 1 #elif defined(UA_GET32) # define WANT_lzo_bitops_ctz32 1 #endif #if (defined(_WIN32) || defined(_WIN64)) && ((LZO_CC_INTELC && (__INTEL_COMPILER >= 1000)) || (LZO_CC_MSC && (_MSC_VER >= 1400))) #include <intrin.h> #if !defined(lzo_bitops_clz32) && defined(WANT_lzo_bitops_clz32) && 0 #pragma intrinsic(_BitScanReverse) static __lzo_inline unsigned lzo_bitops_clz32(lzo_uint32 v) { unsigned long r; (void) _BitScanReverse(&r, v); return (unsigned) r; } #define lzo_bitops_clz32 lzo_bitops_clz32 #endif #if !defined(lzo_bitops_clz64) && defined(WANT_lzo_bitops_clz64) && defined(LZO_UINT64_MAX) && 0 #pragma intrinsic(_BitScanReverse64) static __lzo_inline unsigned lzo_bitops_clz64(lzo_uint64 v) { unsigned long r; (void) _BitScanReverse64(&r, v); return (unsigned) r; } #define lzo_bitops_clz64 lzo_bitops_clz64 #endif #if !defined(lzo_bitops_ctz32) && defined(WANT_lzo_bitops_ctz32) #pragma intrinsic(_BitScanForward) static __lzo_inline unsigned lzo_bitops_ctz32(lzo_uint32 v) { unsigned long r; (void) _BitScanForward(&r, v); return (unsigned) r; } #define lzo_bitops_ctz32 lzo_bitops_ctz32 #endif #if !defined(lzo_bitops_ctz64) && defined(WANT_lzo_bitops_ctz64) && defined(LZO_UINT64_MAX) #pragma intrinsic(_BitScanForward64) static __lzo_inline unsigned lzo_bitops_ctz64(lzo_uint64 v) { unsigned long r; (void) _BitScanForward64(&r, v); return (unsigned) r; } #define lzo_bitops_ctz64 lzo_bitops_ctz64 #endif #elif (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x030400ul) || (LZO_CC_INTELC && (__INTEL_COMPILER >= 1000)) || LZO_CC_LLVM) #if !defined(lzo_bitops_clz32) && defined(WANT_lzo_bitops_clz32) #define lzo_bitops_clz32(v) ((unsigned) __builtin_clz(v)) #endif #if !defined(lzo_bitops_clz64) && defined(WANT_lzo_bitops_clz64) && defined(LZO_UINT64_MAX) #define lzo_bitops_clz64(v) ((unsigned) __builtin_clzll(v)) #endif #if !defined(lzo_bitops_ctz32) && defined(WANT_lzo_bitops_ctz32) #define lzo_bitops_ctz32(v) ((unsigned) __builtin_ctz(v)) #endif #if !defined(lzo_bitops_ctz64) && defined(WANT_lzo_bitops_ctz64) && defined(LZO_UINT64_MAX) #define lzo_bitops_ctz64(v) ((unsigned) __builtin_ctzll(v)) #endif #if !defined(lzo_bitops_popcount32) && defined(WANT_lzo_bitops_popcount32) #define lzo_bitops_popcount32(v) ((unsigned) __builtin_popcount(v)) #endif #if !defined(lzo_bitops_popcount32) && defined(WANT_lzo_bitops_popcount64) && defined(LZO_UINT64_MAX) #define lzo_bitops_popcount64(v) ((unsigned) __builtin_popcountll(v)) #endif #endif static __lzo_noinline lzo_uint do_compress ( const lzo_bytep in , lzo_uint in_len, lzo_bytep out, lzo_uintp out_len, lzo_uint ti, lzo_voidp wrkmem) { register const lzo_bytep ip; lzo_bytep op; const lzo_bytep const in_end = in + in_len; const lzo_bytep const ip_end = in + in_len - 20; const lzo_bytep ii; lzo_dict_p const dict = (lzo_dict_p) wrkmem; op = out; ip = in; ii = ip - ti; ip += ti < 4 ? 4 - ti : 0; for (;;) { const lzo_bytep m_pos; #if !(LZO_DETERMINISTIC) LZO_DEFINE_UNINITIALIZED_VAR(lzo_uint, m_off, 0); lzo_uint m_len; lzo_uint dindex; next: if __lzo_unlikely(ip >= ip_end) break; DINDEX1(dindex,ip); GINDEX(m_pos,m_off,dict,dindex,in); if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET)) goto literal; #if 1 if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3]) goto try_match; DINDEX2(dindex,ip); #endif GINDEX(m_pos,m_off,dict,dindex,in); if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET)) goto literal; if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3]) goto try_match; goto literal; try_match: #if defined(UA_GET32) if (UA_GET32(m_pos) != UA_GET32(ip)) #else if (m_pos[0] != ip[0] || m_pos[1] != ip[1] || m_pos[2] != ip[2] || m_pos[3] != ip[3]) #endif { literal: UPDATE_I(dict,0,dindex,ip,in); ip += 1 + ((ip - ii) >> 5); continue; } UPDATE_I(dict,0,dindex,ip,in); #else lzo_uint m_off; lzo_uint m_len; { lzo_uint32 dv; lzo_uint dindex; literal: ip += 1 + ((ip - ii) >> 5); next: if __lzo_unlikely(ip >= ip_end) break; dv = UA_GET32(ip); dindex = DINDEX(dv,ip); GINDEX(m_off,m_pos,in+dict,dindex,in); UPDATE_I(dict,0,dindex,ip,in); if __lzo_unlikely(dv != UA_GET32(m_pos)) goto literal; } #endif { register lzo_uint t = pd(ip,ii); if (t != 0) { if (t <= 3) { op[-2] |= LZO_BYTE(t); #if defined(UA_COPY32) UA_COPY32(op, ii); op += t; #else { do *op++ = *ii++; while (--t > 0); } #endif } #if defined(UA_COPY32) || defined(UA_COPY64) else if (t <= 16) { *op++ = LZO_BYTE(t - 3); #if defined(UA_COPY64) UA_COPY64(op, ii); UA_COPY64(op+8, ii+8); #else UA_COPY32(op, ii); UA_COPY32(op+4, ii+4); UA_COPY32(op+8, ii+8); UA_COPY32(op+12, ii+12); #endif op += t; } #endif else { if (t <= 18) *op++ = LZO_BYTE(t - 3); else { register lzo_uint tt = t - 18; *op++ = 0; while __lzo_unlikely(tt > 255) { tt -= 255; #if 1 && (LZO_CC_MSC && (_MSC_VER >= 1400)) * (volatile unsigned char *) op++ = 0; #else *op++ = 0; #endif } assert(tt > 0); *op++ = LZO_BYTE(tt); } #if defined(UA_COPY32) || defined(UA_COPY64) do { #if defined(UA_COPY64) UA_COPY64(op, ii); UA_COPY64(op+8, ii+8); #else UA_COPY32(op, ii); UA_COPY32(op+4, ii+4); UA_COPY32(op+8, ii+8); UA_COPY32(op+12, ii+12); #endif op += 16; ii += 16; t -= 16; } while (t >= 16); if (t > 0) #endif { do *op++ = *ii++; while (--t > 0); } } } } m_len = 4; { #if defined(UA_GET64) lzo_uint64 v; v = UA_GET64(ip + m_len) ^ UA_GET64(m_pos + m_len); if __lzo_unlikely(v == 0) { do { m_len += 8; v = UA_GET64(ip + m_len) ^ UA_GET64(m_pos + m_len); if __lzo_unlikely(ip + m_len >= ip_end) goto m_len_done; } while (v == 0); } #if (LZO_ABI_LITTLE_ENDIAN) && defined(lzo_bitops_ctz64) m_len += lzo_bitops_ctz64(v) / CHAR_BIT; #elif (LZO_ABI_LITTLE_ENDIAN) if ((v & UCHAR_MAX) == 0) do { v >>= CHAR_BIT; m_len += 1; } while ((v & UCHAR_MAX) == 0); #else if (ip[m_len] == m_pos[m_len]) do { m_len += 1; } while (ip[m_len] == m_pos[m_len]); #endif #elif defined(UA_GET32) lzo_uint32 v; v = UA_GET32(ip + m_len) ^ UA_GET32(m_pos + m_len); if __lzo_unlikely(v == 0) { do { m_len += 4; v = UA_GET32(ip + m_len) ^ UA_GET32(m_pos + m_len); if __lzo_unlikely(ip + m_len >= ip_end) goto m_len_done; } while (v == 0); } #if (LZO_ABI_LITTLE_ENDIAN) && defined(lzo_bitops_ctz32) m_len += lzo_bitops_ctz32(v) / CHAR_BIT; #elif (LZO_ABI_LITTLE_ENDIAN) if ((v & UCHAR_MAX) == 0) do { v >>= CHAR_BIT; m_len += 1; } while ((v & UCHAR_MAX) == 0); #else if (ip[m_len] == m_pos[m_len]) do { m_len += 1; } while (ip[m_len] == m_pos[m_len]); #endif #else if __lzo_unlikely(ip[m_len] == m_pos[m_len]) { do { m_len += 1; if __lzo_unlikely(ip + m_len >= ip_end) goto m_len_done; } while (ip[m_len] == m_pos[m_len]); } #endif } m_len_done: m_off = pd(ip,m_pos); ip += m_len; ii = ip; if (m_len <= M2_MAX_LEN && m_off <= M2_MAX_OFFSET) { m_off -= 1; #if defined(LZO1X) *op++ = LZO_BYTE(((m_len - 1) << 5) | ((m_off & 7) << 2)); *op++ = LZO_BYTE(m_off >> 3); #elif defined(LZO1Y) *op++ = LZO_BYTE(((m_len + 1) << 4) | ((m_off & 3) << 2)); *op++ = LZO_BYTE(m_off >> 2); #endif } else if (m_off <= M3_MAX_OFFSET) { m_off -= 1; if (m_len <= M3_MAX_LEN) *op++ = LZO_BYTE(M3_MARKER | (m_len - 2)); else { m_len -= M3_MAX_LEN; *op++ = M3_MARKER | 0; while __lzo_unlikely(m_len > 255) { m_len -= 255; #if 1 && (LZO_CC_MSC && (_MSC_VER >= 1400)) * (volatile unsigned char *) op++ = 0; #else *op++ = 0; #endif } *op++ = LZO_BYTE(m_len); } *op++ = LZO_BYTE(m_off << 2); *op++ = LZO_BYTE(m_off >> 6); } else { m_off -= 0x4000; if (m_len <= M4_MAX_LEN) *op++ = LZO_BYTE(M4_MARKER | ((m_off >> 11) & 8) | (m_len - 2)); else { m_len -= M4_MAX_LEN; *op++ = LZO_BYTE(M4_MARKER | ((m_off >> 11) & 8)); while __lzo_unlikely(m_len > 255) { m_len -= 255; #if 1 && (LZO_CC_MSC && (_MSC_VER >= 1400)) * (volatile unsigned char *) op++ = 0; #else *op++ = 0; #endif } *op++ = LZO_BYTE(m_len); } *op++ = LZO_BYTE(m_off << 2); *op++ = LZO_BYTE(m_off >> 6); } goto next; } *out_len = pd(op, out); return pd(in_end,ii); } LZO_PUBLIC(int) DO_COMPRESS ( const lzo_bytep in , lzo_uint in_len, lzo_bytep out, lzo_uintp out_len, lzo_voidp wrkmem ) { const lzo_bytep ip = in; lzo_bytep op = out; lzo_uint l = in_len; lzo_uint t = 0; while (l > 20) { lzo_uint ll = l; lzo_uintptr_t ll_end; #if 0 || (LZO_DETERMINISTIC) ll = LZO_MIN(ll, 49152); #endif ll_end = (lzo_uintptr_t)ip + ll; if ((ll_end + ((t + ll) >> 5)) <= ll_end || (const lzo_bytep)(ll_end + ((t + ll) >> 5)) <= ip + ll) break; #if (LZO_DETERMINISTIC) lzo_memset(wrkmem, 0, ((lzo_uint)1 << D_BITS) * sizeof(lzo_dict_t)); #endif t = do_compress(ip,ll,op,out_len,t,wrkmem); ip += ll; op += *out_len; l -= ll; } t += l; if (t > 0) { const lzo_bytep ii = in + in_len - t; if (op == out && t <= 238) *op++ = LZO_BYTE(17 + t); else if (t <= 3) op[-2] |= LZO_BYTE(t); else if (t <= 18) *op++ = LZO_BYTE(t - 3); else { lzo_uint tt = t - 18; *op++ = 0; while (tt > 255) { tt -= 255; #if 1 && (LZO_CC_MSC && (_MSC_VER >= 1400)) * (volatile unsigned char *) op++ = 0; #else *op++ = 0; #endif } assert(tt > 0); *op++ = LZO_BYTE(tt); } do *op++ = *ii++; while (--t > 0); } *op++ = M4_MARKER | 1; *op++ = 0; *op++ = 0; *out_len = pd(op, out); return LZO_E_OK; } #endif #undef do_compress #undef DO_COMPRESS #undef LZO_HASH #undef LZO_TEST_OVERRUN #undef DO_DECOMPRESS #define DO_DECOMPRESS lzo1x_decompress #if !defined(MINILZO_CFG_SKIP_LZO1X_DECOMPRESS) #if defined(LZO_TEST_OVERRUN) # if !defined(LZO_TEST_OVERRUN_INPUT) # define LZO_TEST_OVERRUN_INPUT 2 # endif # if !defined(LZO_TEST_OVERRUN_OUTPUT) # define LZO_TEST_OVERRUN_OUTPUT 2 # endif # if !defined(LZO_TEST_OVERRUN_LOOKBEHIND) # define LZO_TEST_OVERRUN_LOOKBEHIND 1 # endif #endif #undef TEST_IP #undef TEST_OP #undef TEST_LB #undef TEST_LBO #undef NEED_IP #undef NEED_OP #undef HAVE_TEST_IP #undef HAVE_TEST_OP #undef HAVE_NEED_IP #undef HAVE_NEED_OP #undef HAVE_ANY_IP #undef HAVE_ANY_OP #if defined(LZO_TEST_OVERRUN_INPUT) # if (LZO_TEST_OVERRUN_INPUT >= 1) # define TEST_IP (ip < ip_end) # endif # if (LZO_TEST_OVERRUN_INPUT >= 2) # define NEED_IP(x) \ if ((lzo_uint)(ip_end - ip) < (lzo_uint)(x)) goto input_overrun # endif #endif #if defined(LZO_TEST_OVERRUN_OUTPUT) # if (LZO_TEST_OVERRUN_OUTPUT >= 1) # define TEST_OP (op <= op_end) # endif # if (LZO_TEST_OVERRUN_OUTPUT >= 2) # undef TEST_OP # define NEED_OP(x) \ if ((lzo_uint)(op_end - op) < (lzo_uint)(x)) goto output_overrun # endif #endif #if defined(LZO_TEST_OVERRUN_LOOKBEHIND) # define TEST_LB(m_pos) if (m_pos < out || m_pos >= op) goto lookbehind_overrun # define TEST_LBO(m_pos,o) if (m_pos < out || m_pos >= op - (o)) goto lookbehind_overrun #else # define TEST_LB(m_pos) ((void) 0) # define TEST_LBO(m_pos,o) ((void) 0) #endif #if !defined(LZO_EOF_CODE) && !defined(TEST_IP) # define TEST_IP (ip < ip_end) #endif #if defined(TEST_IP) # define HAVE_TEST_IP 1 #else # define TEST_IP 1 #endif #if defined(TEST_OP) # define HAVE_TEST_OP 1 #else # define TEST_OP 1 #endif #if defined(NEED_IP) # define HAVE_NEED_IP 1 #else # define NEED_IP(x) ((void) 0) #endif #if defined(NEED_OP) # define HAVE_NEED_OP 1 #else # define NEED_OP(x) ((void) 0) #endif #if defined(HAVE_TEST_IP) || defined(HAVE_NEED_IP) # define HAVE_ANY_IP 1 #endif #if defined(HAVE_TEST_OP) || defined(HAVE_NEED_OP) # define HAVE_ANY_OP 1 #endif #if defined(DO_DECOMPRESS) LZO_PUBLIC(int) DO_DECOMPRESS ( const lzo_bytep in , lzo_uint in_len, lzo_bytep out, lzo_uintp out_len, lzo_voidp wrkmem ) #endif { register lzo_bytep op; register const lzo_bytep ip; register lzo_uint t; #if defined(COPY_DICT) lzo_uint m_off; const lzo_bytep dict_end; #else register const lzo_bytep m_pos; #endif const lzo_bytep const ip_end = in + in_len; #if defined(HAVE_ANY_OP) lzo_bytep const op_end = out + *out_len; #endif #if defined(LZO1Z) lzo_uint last_m_off = 0; #endif LZO_UNUSED(wrkmem); #if defined(COPY_DICT) if (dict) { if (dict_len > M4_MAX_OFFSET) { dict += dict_len - M4_MAX_OFFSET; dict_len = M4_MAX_OFFSET; } dict_end = dict + dict_len; } else { dict_len = 0; dict_end = NULL; } #endif *out_len = 0; op = out; ip = in; if (*ip > 17) { t = *ip++ - 17; if (t < 4) goto match_next; assert(t > 0); NEED_OP(t); NEED_IP(t+1); do *op++ = *ip++; while (--t > 0); goto first_literal_run; } while (TEST_IP && TEST_OP) { t = *ip++; if (t >= 16) goto match; if (t == 0) { NEED_IP(1); while (*ip == 0) { t += 255; ip++; NEED_IP(1); } t += 15 + *ip++; } assert(t > 0); NEED_OP(t+3); NEED_IP(t+4); #if defined(LZO_UNALIGNED_OK_8) && defined(LZO_UNALIGNED_OK_4) t += 3; if (t >= 8) do { UA_COPY64(op,ip); op += 8; ip += 8; t -= 8; } while (t >= 8); if (t >= 4) { UA_COPY32(op,ip); op += 4; ip += 4; t -= 4; } if (t > 0) { *op++ = *ip++; if (t > 1) { *op++ = *ip++; if (t > 2) { *op++ = *ip++; } } } #elif defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4) #if !defined(LZO_UNALIGNED_OK_4) if (PTR_ALIGNED2_4(op,ip)) { #endif UA_COPY32(op,ip); op += 4; ip += 4; if (--t > 0) { if (t >= 4) { do { UA_COPY32(op,ip); op += 4; ip += 4; t -= 4; } while (t >= 4); if (t > 0) do *op++ = *ip++; while (--t > 0); } else do *op++ = *ip++; while (--t > 0); } #if !defined(LZO_UNALIGNED_OK_4) } else #endif #endif #if !defined(LZO_UNALIGNED_OK_4) && !defined(LZO_UNALIGNED_OK_8) { *op++ = *ip++; *op++ = *ip++; *op++ = *ip++; do *op++ = *ip++; while (--t > 0); } #endif first_literal_run: t = *ip++; if (t >= 16) goto match; #if defined(COPY_DICT) #if defined(LZO1Z) m_off = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2); last_m_off = m_off; #else m_off = (1 + M2_MAX_OFFSET) + (t >> 2) + (*ip++ << 2); #endif NEED_OP(3); t = 3; COPY_DICT(t,m_off) #else #if defined(LZO1Z) t = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2); m_pos = op - t; last_m_off = t; #else m_pos = op - (1 + M2_MAX_OFFSET); m_pos -= t >> 2; m_pos -= *ip++ << 2; #endif TEST_LB(m_pos); NEED_OP(3); *op++ = *m_pos++; *op++ = *m_pos++; *op++ = *m_pos; #endif goto match_done; do { match: if (t >= 64) { #if defined(COPY_DICT) #if defined(LZO1X) m_off = 1 + ((t >> 2) & 7) + (*ip++ << 3); t = (t >> 5) - 1; #elif defined(LZO1Y) m_off = 1 + ((t >> 2) & 3) + (*ip++ << 2); t = (t >> 4) - 3; #elif defined(LZO1Z) m_off = t & 0x1f; if (m_off >= 0x1c) m_off = last_m_off; else { m_off = 1 + (m_off << 6) + (*ip++ >> 2); last_m_off = m_off; } t = (t >> 5) - 1; #endif #else #if defined(LZO1X) m_pos = op - 1; m_pos -= (t >> 2) & 7; m_pos -= *ip++ << 3; t = (t >> 5) - 1; #elif defined(LZO1Y) m_pos = op - 1; m_pos -= (t >> 2) & 3; m_pos -= *ip++ << 2; t = (t >> 4) - 3; #elif defined(LZO1Z) { lzo_uint off = t & 0x1f; m_pos = op; if (off >= 0x1c) { assert(last_m_off > 0); m_pos -= last_m_off; } else { off = 1 + (off << 6) + (*ip++ >> 2); m_pos -= off; last_m_off = off; } } t = (t >> 5) - 1; #endif TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1); goto copy_match; #endif } else if (t >= 32) { t &= 31; if (t == 0) { NEED_IP(1); while (*ip == 0) { t += 255; ip++; NEED_IP(1); } t += 31 + *ip++; } #if defined(COPY_DICT) #if defined(LZO1Z) m_off = 1 + (ip[0] << 6) + (ip[1] >> 2); last_m_off = m_off; #else m_off = 1 + (ip[0] >> 2) + (ip[1] << 6); #endif #else #if defined(LZO1Z) { lzo_uint off = 1 + (ip[0] << 6) + (ip[1] >> 2); m_pos = op - off; last_m_off = off; } #elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN) m_pos = op - 1; m_pos -= UA_GET16(ip) >> 2; #else m_pos = op - 1; m_pos -= (ip[0] >> 2) + (ip[1] << 6); #endif #endif ip += 2; } else if (t >= 16) { #if defined(COPY_DICT) m_off = (t & 8) << 11; #else m_pos = op; m_pos -= (t & 8) << 11; #endif t &= 7; if (t == 0) { NEED_IP(1); while (*ip == 0) { t += 255; ip++; NEED_IP(1); } t += 7 + *ip++; } #if defined(COPY_DICT) #if defined(LZO1Z) m_off += (ip[0] << 6) + (ip[1] >> 2); #else m_off += (ip[0] >> 2) + (ip[1] << 6); #endif ip += 2; if (m_off == 0) goto eof_found; m_off += 0x4000; #if defined(LZO1Z) last_m_off = m_off; #endif #else #if defined(LZO1Z) m_pos -= (ip[0] << 6) + (ip[1] >> 2); #elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN) m_pos -= UA_GET16(ip) >> 2; #else m_pos -= (ip[0] >> 2) + (ip[1] << 6); #endif ip += 2; if (m_pos == op) goto eof_found; m_pos -= 0x4000; #if defined(LZO1Z) last_m_off = pd((const lzo_bytep)op, m_pos); #endif #endif } else { #if defined(COPY_DICT) #if defined(LZO1Z) m_off = 1 + (t << 6) + (*ip++ >> 2); last_m_off = m_off; #else m_off = 1 + (t >> 2) + (*ip++ << 2); #endif NEED_OP(2); t = 2; COPY_DICT(t,m_off) #else #if defined(LZO1Z) t = 1 + (t << 6) + (*ip++ >> 2); m_pos = op - t; last_m_off = t; #else m_pos = op - 1; m_pos -= t >> 2; m_pos -= *ip++ << 2; #endif TEST_LB(m_pos); NEED_OP(2); *op++ = *m_pos++; *op++ = *m_pos; #endif goto match_done; } #if defined(COPY_DICT) NEED_OP(t+3-1); t += 3-1; COPY_DICT(t,m_off) #else TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1); #if defined(LZO_UNALIGNED_OK_8) && defined(LZO_UNALIGNED_OK_4) if (op - m_pos >= 8) { t += (3 - 1); if (t >= 8) do { UA_COPY64(op,m_pos); op += 8; m_pos += 8; t -= 8; } while (t >= 8); if (t >= 4) { UA_COPY32(op,m_pos); op += 4; m_pos += 4; t -= 4; } if (t > 0) { *op++ = m_pos[0]; if (t > 1) { *op++ = m_pos[1]; if (t > 2) { *op++ = m_pos[2]; } } } } else #elif defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4) #if !defined(LZO_UNALIGNED_OK_4) if (t >= 2 * 4 - (3 - 1) && PTR_ALIGNED2_4(op,m_pos)) { assert((op - m_pos) >= 4); #else if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4) { #endif UA_COPY32(op,m_pos); op += 4; m_pos += 4; t -= 4 - (3 - 1); do { UA_COPY32(op,m_pos); op += 4; m_pos += 4; t -= 4; } while (t >= 4); if (t > 0) do *op++ = *m_pos++; while (--t > 0); } else #endif { copy_match: *op++ = *m_pos++; *op++ = *m_pos++; do *op++ = *m_pos++; while (--t > 0); } #endif match_done: #if defined(LZO1Z) t = ip[-1] & 3; #else t = ip[-2] & 3; #endif if (t == 0) break; match_next: assert(t > 0); assert(t < 4); NEED_OP(t); NEED_IP(t+1); #if 0 do *op++ = *ip++; while (--t > 0); #else *op++ = *ip++; if (t > 1) { *op++ = *ip++; if (t > 2) { *op++ = *ip++; } } #endif t = *ip++; } while (TEST_IP && TEST_OP); } #if defined(HAVE_TEST_IP) || defined(HAVE_TEST_OP) *out_len = pd(op, out); return LZO_E_EOF_NOT_FOUND; #endif eof_found: assert(t == 1); *out_len = pd(op, out); return (ip == ip_end ? LZO_E_OK : (ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN)); #if defined(HAVE_NEED_IP) input_overrun: *out_len = pd(op, out); return LZO_E_INPUT_OVERRUN; #endif #if defined(HAVE_NEED_OP) output_overrun: *out_len = pd(op, out); return LZO_E_OUTPUT_OVERRUN; #endif #if defined(LZO_TEST_OVERRUN_LOOKBEHIND) lookbehind_overrun: *out_len = pd(op, out); return LZO_E_LOOKBEHIND_OVERRUN; #endif } #endif #define LZO_TEST_OVERRUN 1 #undef DO_DECOMPRESS #define DO_DECOMPRESS lzo1x_decompress_safe #if !defined(MINILZO_CFG_SKIP_LZO1X_DECOMPRESS_SAFE) #if defined(LZO_TEST_OVERRUN) # if !defined(LZO_TEST_OVERRUN_INPUT) # define LZO_TEST_OVERRUN_INPUT 2 # endif # if !defined(LZO_TEST_OVERRUN_OUTPUT) # define LZO_TEST_OVERRUN_OUTPUT 2 # endif # if !defined(LZO_TEST_OVERRUN_LOOKBEHIND) # define LZO_TEST_OVERRUN_LOOKBEHIND 1 # endif #endif #undef TEST_IP #undef TEST_OP #undef TEST_LB #undef TEST_LBO #undef NEED_IP #undef NEED_OP #undef HAVE_TEST_IP #undef HAVE_TEST_OP #undef HAVE_NEED_IP #undef HAVE_NEED_OP #undef HAVE_ANY_IP #undef HAVE_ANY_OP #if defined(LZO_TEST_OVERRUN_INPUT) # if (LZO_TEST_OVERRUN_INPUT >= 1) # define TEST_IP (ip < ip_end) # endif # if (LZO_TEST_OVERRUN_INPUT >= 2) # define NEED_IP(x) \ if ((lzo_uint)(ip_end - ip) < (lzo_uint)(x)) goto input_overrun # endif #endif #if defined(LZO_TEST_OVERRUN_OUTPUT) # if (LZO_TEST_OVERRUN_OUTPUT >= 1) # define TEST_OP (op <= op_end) # endif # if (LZO_TEST_OVERRUN_OUTPUT >= 2) # undef TEST_OP # define NEED_OP(x) \ if ((lzo_uint)(op_end - op) < (lzo_uint)(x)) goto output_overrun # endif #endif #if defined(LZO_TEST_OVERRUN_LOOKBEHIND) # define TEST_LB(m_pos) if (m_pos < out || m_pos >= op) goto lookbehind_overrun # define TEST_LBO(m_pos,o) if (m_pos < out || m_pos >= op - (o)) goto lookbehind_overrun #else # define TEST_LB(m_pos) ((void) 0) # define TEST_LBO(m_pos,o) ((void) 0) #endif #if !defined(LZO_EOF_CODE) && !defined(TEST_IP) # define TEST_IP (ip < ip_end) #endif #if defined(TEST_IP) # define HAVE_TEST_IP 1 #else # define TEST_IP 1 #endif #if defined(TEST_OP) # define HAVE_TEST_OP 1 #else # define TEST_OP 1 #endif #if defined(NEED_IP) # define HAVE_NEED_IP 1 #else # define NEED_IP(x) ((void) 0) #endif #if defined(NEED_OP) # define HAVE_NEED_OP 1 #else # define NEED_OP(x) ((void) 0) #endif #if defined(HAVE_TEST_IP) || defined(HAVE_NEED_IP) # define HAVE_ANY_IP 1 #endif #if defined(HAVE_TEST_OP) || defined(HAVE_NEED_OP) # define HAVE_ANY_OP 1 #endif #if defined(DO_DECOMPRESS) LZO_PUBLIC(int) DO_DECOMPRESS ( const lzo_bytep in , lzo_uint in_len, lzo_bytep out, lzo_uintp out_len, lzo_voidp wrkmem ) #endif { register lzo_bytep op; register const lzo_bytep ip; register lzo_uint t; #if defined(COPY_DICT) lzo_uint m_off; const lzo_bytep dict_end; #else register const lzo_bytep m_pos; #endif const lzo_bytep const ip_end = in + in_len; #if defined(HAVE_ANY_OP) lzo_bytep const op_end = out + *out_len; #endif #if defined(LZO1Z) lzo_uint last_m_off = 0; #endif LZO_UNUSED(wrkmem); #if defined(COPY_DICT) if (dict) { if (dict_len > M4_MAX_OFFSET) { dict += dict_len - M4_MAX_OFFSET; dict_len = M4_MAX_OFFSET; } dict_end = dict + dict_len; } else { dict_len = 0; dict_end = NULL; } #endif *out_len = 0; op = out; ip = in; if (*ip > 17) { t = *ip++ - 17; if (t < 4) goto match_next; assert(t > 0); NEED_OP(t); NEED_IP(t+1); do *op++ = *ip++; while (--t > 0); goto first_literal_run; } while (TEST_IP && TEST_OP) { t = *ip++; if (t >= 16) goto match; if (t == 0) { NEED_IP(1); while (*ip == 0) { t += 255; ip++; NEED_IP(1); } t += 15 + *ip++; } assert(t > 0); NEED_OP(t+3); NEED_IP(t+4); #if defined(LZO_UNALIGNED_OK_8) && defined(LZO_UNALIGNED_OK_4) t += 3; if (t >= 8) do { UA_COPY64(op,ip); op += 8; ip += 8; t -= 8; } while (t >= 8); if (t >= 4) { UA_COPY32(op,ip); op += 4; ip += 4; t -= 4; } if (t > 0) { *op++ = *ip++; if (t > 1) { *op++ = *ip++; if (t > 2) { *op++ = *ip++; } } } #elif defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4) #if !defined(LZO_UNALIGNED_OK_4) if (PTR_ALIGNED2_4(op,ip)) { #endif UA_COPY32(op,ip); op += 4; ip += 4; if (--t > 0) { if (t >= 4) { do { UA_COPY32(op,ip); op += 4; ip += 4; t -= 4; } while (t >= 4); if (t > 0) do *op++ = *ip++; while (--t > 0); } else do *op++ = *ip++; while (--t > 0); } #if !defined(LZO_UNALIGNED_OK_4) } else #endif #endif #if !defined(LZO_UNALIGNED_OK_4) && !defined(LZO_UNALIGNED_OK_8) { *op++ = *ip++; *op++ = *ip++; *op++ = *ip++; do *op++ = *ip++; while (--t > 0); } #endif first_literal_run: t = *ip++; if (t >= 16) goto match; #if defined(COPY_DICT) #if defined(LZO1Z) m_off = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2); last_m_off = m_off; #else m_off = (1 + M2_MAX_OFFSET) + (t >> 2) + (*ip++ << 2); #endif NEED_OP(3); t = 3; COPY_DICT(t,m_off) #else #if defined(LZO1Z) t = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2); m_pos = op - t; last_m_off = t; #else m_pos = op - (1 + M2_MAX_OFFSET); m_pos -= t >> 2; m_pos -= *ip++ << 2; #endif TEST_LB(m_pos); NEED_OP(3); *op++ = *m_pos++; *op++ = *m_pos++; *op++ = *m_pos; #endif goto match_done; do { match: if (t >= 64) { #if defined(COPY_DICT) #if defined(LZO1X) m_off = 1 + ((t >> 2) & 7) + (*ip++ << 3); t = (t >> 5) - 1; #elif defined(LZO1Y) m_off = 1 + ((t >> 2) & 3) + (*ip++ << 2); t = (t >> 4) - 3; #elif defined(LZO1Z) m_off = t & 0x1f; if (m_off >= 0x1c) m_off = last_m_off; else { m_off = 1 + (m_off << 6) + (*ip++ >> 2); last_m_off = m_off; } t = (t >> 5) - 1; #endif #else #if defined(LZO1X) m_pos = op - 1; m_pos -= (t >> 2) & 7; m_pos -= *ip++ << 3; t = (t >> 5) - 1; #elif defined(LZO1Y) m_pos = op - 1; m_pos -= (t >> 2) & 3; m_pos -= *ip++ << 2; t = (t >> 4) - 3; #elif defined(LZO1Z) { lzo_uint off = t & 0x1f; m_pos = op; if (off >= 0x1c) { assert(last_m_off > 0); m_pos -= last_m_off; } else { off = 1 + (off << 6) + (*ip++ >> 2); m_pos -= off; last_m_off = off; } } t = (t >> 5) - 1; #endif TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1); goto copy_match; #endif } else if (t >= 32) { t &= 31; if (t == 0) { NEED_IP(1); while (*ip == 0) { t += 255; ip++; NEED_IP(1); } t += 31 + *ip++; } #if defined(COPY_DICT) #if defined(LZO1Z) m_off = 1 + (ip[0] << 6) + (ip[1] >> 2); last_m_off = m_off; #else m_off = 1 + (ip[0] >> 2) + (ip[1] << 6); #endif #else #if defined(LZO1Z) { lzo_uint off = 1 + (ip[0] << 6) + (ip[1] >> 2); m_pos = op - off; last_m_off = off; } #elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN) m_pos = op - 1; m_pos -= UA_GET16(ip) >> 2; #else m_pos = op - 1; m_pos -= (ip[0] >> 2) + (ip[1] << 6); #endif #endif ip += 2; } else if (t >= 16) { #if defined(COPY_DICT) m_off = (t & 8) << 11; #else m_pos = op; m_pos -= (t & 8) << 11; #endif t &= 7; if (t == 0) { NEED_IP(1); while (*ip == 0) { t += 255; ip++; NEED_IP(1); } t += 7 + *ip++; } #if defined(COPY_DICT) #if defined(LZO1Z) m_off += (ip[0] << 6) + (ip[1] >> 2); #else m_off += (ip[0] >> 2) + (ip[1] << 6); #endif ip += 2; if (m_off == 0) goto eof_found; m_off += 0x4000; #if defined(LZO1Z) last_m_off = m_off; #endif #else #if defined(LZO1Z) m_pos -= (ip[0] << 6) + (ip[1] >> 2); #elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN) m_pos -= UA_GET16(ip) >> 2; #else m_pos -= (ip[0] >> 2) + (ip[1] << 6); #endif ip += 2; if (m_pos == op) goto eof_found; m_pos -= 0x4000; #if defined(LZO1Z) last_m_off = pd((const lzo_bytep)op, m_pos); #endif #endif } else { #if defined(COPY_DICT) #if defined(LZO1Z) m_off = 1 + (t << 6) + (*ip++ >> 2); last_m_off = m_off; #else m_off = 1 + (t >> 2) + (*ip++ << 2); #endif NEED_OP(2); t = 2; COPY_DICT(t,m_off) #else #if defined(LZO1Z) t = 1 + (t << 6) + (*ip++ >> 2); m_pos = op - t; last_m_off = t; #else m_pos = op - 1; m_pos -= t >> 2; m_pos -= *ip++ << 2; #endif TEST_LB(m_pos); NEED_OP(2); *op++ = *m_pos++; *op++ = *m_pos; #endif goto match_done; } #if defined(COPY_DICT) NEED_OP(t+3-1); t += 3-1; COPY_DICT(t,m_off) #else TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1); #if defined(LZO_UNALIGNED_OK_8) && defined(LZO_UNALIGNED_OK_4) if (op - m_pos >= 8) { t += (3 - 1); if (t >= 8) do { UA_COPY64(op,m_pos); op += 8; m_pos += 8; t -= 8; } while (t >= 8); if (t >= 4) { UA_COPY32(op,m_pos); op += 4; m_pos += 4; t -= 4; } if (t > 0) { *op++ = m_pos[0]; if (t > 1) { *op++ = m_pos[1]; if (t > 2) { *op++ = m_pos[2]; } } } } else #elif defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4) #if !defined(LZO_UNALIGNED_OK_4) if (t >= 2 * 4 - (3 - 1) && PTR_ALIGNED2_4(op,m_pos)) { assert((op - m_pos) >= 4); #else if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4) { #endif UA_COPY32(op,m_pos); op += 4; m_pos += 4; t -= 4 - (3 - 1); do { UA_COPY32(op,m_pos); op += 4; m_pos += 4; t -= 4; } while (t >= 4); if (t > 0) do *op++ = *m_pos++; while (--t > 0); } else #endif { copy_match: *op++ = *m_pos++; *op++ = *m_pos++; do *op++ = *m_pos++; while (--t > 0); } #endif match_done: #if defined(LZO1Z) t = ip[-1] & 3; #else t = ip[-2] & 3; #endif if (t == 0) break; match_next: assert(t > 0); assert(t < 4); NEED_OP(t); NEED_IP(t+1); #if 0 do *op++ = *ip++; while (--t > 0); #else *op++ = *ip++; if (t > 1) { *op++ = *ip++; if (t > 2) { *op++ = *ip++; } } #endif t = *ip++; } while (TEST_IP && TEST_OP); } #if defined(HAVE_TEST_IP) || defined(HAVE_TEST_OP) *out_len = pd(op, out); return LZO_E_EOF_NOT_FOUND; #endif eof_found: assert(t == 1); *out_len = pd(op, out); return (ip == ip_end ? LZO_E_OK : (ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN)); #if defined(HAVE_NEED_IP) input_overrun: *out_len = pd(op, out); return LZO_E_INPUT_OVERRUN; #endif #if defined(HAVE_NEED_OP) output_overrun: *out_len = pd(op, out); return LZO_E_OUTPUT_OVERRUN; #endif #if defined(LZO_TEST_OVERRUN_LOOKBEHIND) lookbehind_overrun: *out_len = pd(op, out); return LZO_E_LOOKBEHIND_OVERRUN; #endif } #endif /***** End of minilzo.c *****/ ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/scandisk.c����������������������������������������������������������������0000664�0001750�0001750�00000010045�13106171410�017616� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * scandisk.c * Scanning disk for btrfs multi-devices * by Samuel Liao * * Copyright (c) 2013 Tencent, Inc. */ /* * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "fsw_efi.h" #ifdef __MAKEWITH_GNUEFI #include "edk2/DriverBinding.h" #include "edk2/ComponentName.h" extern EFI_GUID gMyEfiDiskIoProtocolGuid; extern EFI_GUID gMyEfiBlockIoProtocolGuid; #else #define gMyEfiBlockIoProtocolGuid gEfiBlockIoProtocolGuid #define gMyEfiDiskIoProtocolGuid gEfiDiskIoProtocolGuid #endif #include "../include/refit_call_wrapper.h" extern struct fsw_host_table fsw_efi_host_table; static void dummy_volume_free(struct fsw_volume *vol) { } static struct fsw_fstype_table dummy_fstype = { { FSW_STRING_TYPE_UTF8, 4, 4, "dummy" }, sizeof(struct fsw_volume), sizeof(struct fsw_dnode), NULL, //volume_mount, dummy_volume_free, //volume_free, NULL, //volume_stat, NULL, //dnode_fill, NULL, //dnode_free, NULL, //dnode_stat, NULL, //get_extent, NULL, //dir_lookup, NULL, //dir_read, NULL, //readlink, }; static struct fsw_volume *create_dummy_volume(EFI_DISK_IO *diskio, UINT32 mediaid) { fsw_status_t err; struct fsw_volume *vol; FSW_VOLUME_DATA *Volume; err = fsw_alloc_zero(sizeof(struct fsw_volume), (void **)&vol); if(err) return NULL; err = fsw_alloc_zero(sizeof(FSW_VOLUME_DATA), (void **)&Volume); if(err) { fsw_free(vol); return NULL; } /* fstype_table->volume_free for fsw_unmount */ vol->fstype_table = &dummy_fstype; /* host_data needded to fsw_block_get()/fsw_efi_read_block() */ Volume->DiskIo = diskio; Volume->MediaId = mediaid; vol->host_data = Volume; vol->host_table = &fsw_efi_host_table; return vol; } static struct fsw_volume *clone_dummy_volume(struct fsw_volume *vol) { FSW_VOLUME_DATA *Volume = (FSW_VOLUME_DATA *)vol->host_data; return create_dummy_volume(Volume->DiskIo, Volume->MediaId); } static void free_dummy_volume(struct fsw_volume *vol) { fsw_free(vol->host_data); fsw_unmount(vol); } static int scan_disks(int (*hook)(struct fsw_volume *, struct fsw_volume *), struct fsw_volume *master) { EFI_STATUS Status; EFI_HANDLE *Handles; UINTN HandleCount = 0; UINTN i; UINTN scanned = 0; // Driver hangs if compiled with GNU-EFI unless there's a Print() statement somewhere. // I'm still trying to track that down; in the meantime, work around it.... #if defined(__MAKEWITH_GNUEFI) Print(L" "); #endif DPRINT(L"Scanning disks\n"); Status = refit_call5_wrapper(BS->LocateHandleBuffer, ByProtocol, &gMyEfiDiskIoProtocolGuid, NULL, &HandleCount, &Handles); if (Status == EFI_NOT_FOUND) return -1; // no filesystems. strange, but true... for (i = 0; i < HandleCount; i++) { EFI_DISK_IO *diskio; EFI_BLOCK_IO *blockio; Status = refit_call3_wrapper(BS->HandleProtocol, Handles[i], &gMyEfiDiskIoProtocolGuid, (VOID **) &diskio); if (Status != 0) continue; Status = refit_call3_wrapper(BS->HandleProtocol, Handles[i], &gMyEfiBlockIoProtocolGuid, (VOID **) &blockio); if (Status != 0) continue; struct fsw_volume *vol = create_dummy_volume(diskio, blockio->Media->MediaId); if(vol) { DPRINT(L"Checking disk %d\n", i); if(hook(master, vol) == FSW_SUCCESS) scanned++; free_dummy_volume(vol); } } return scanned; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/fsw_ext4_disk.h�����������������������������������������������������������0000664�0001750�0001750�00000047542�12626644770�020641� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/** * \file fsw_ext4_disk.h * ext4 file system on-disk structures. */ /*- * Copyright (c) 2012 Stefan Agner * Portions Copyright (c) 2006 Christoph Pfisterer * Portions Copyright (c) 1991-2012 by various Linux kernel contributors * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _FSW_EXT4_DISK_H_ #define _FSW_EXT4_DISK_H_ // types typedef fsw_s8 __s8; typedef fsw_u8 __u8; typedef fsw_s16 __s16; typedef fsw_u16 __u16; typedef fsw_s32 __s32; typedef fsw_u32 __u32; typedef fsw_s64 __s64; typedef fsw_u64 __u64; typedef __u16 __le16; typedef __u32 __le32; typedef __u64 __le64; // // from Linux kernel, fs/ext4/ext4.h // /* * Special inode numbers */ #define EXT4_BAD_INO 1 /* Bad blocks inode */ #define EXT4_ROOT_INO 2 /* Root inode */ #define EXT4_USR_QUOTA_INO 3 /* User quota inode */ #define EXT4_GRP_QUOTA_INO 4 /* Group quota inode */ #define EXT4_BOOT_LOADER_INO 5 /* Boot loader inode */ #define EXT4_UNDEL_DIR_INO 6 /* Undelete directory inode */ #define EXT4_RESIZE_INO 7 /* Reserved group descriptors inode */ #define EXT4_JOURNAL_INO 8 /* Journal inode */ /* * The second extended file system magic number */ #define EXT4_SUPER_MAGIC 0xEF53 /* * Macro-instructions used to manage several block sizes */ #define EXT4_MIN_BLOCK_SIZE 1024 #define EXT4_MAX_BLOCK_SIZE 4096 #define EXT4_MIN_BLOCK_LOG_SIZE 10 #define EXT4_BLOCK_SIZE(s) (EXT4_MIN_BLOCK_SIZE << (s)->s_log_block_size) #define EXT4_ADDR_PER_BLOCK(s) (EXT4_BLOCK_SIZE(s) / sizeof (__u32)) #define EXT4_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10) #define EXT4_INODE_SIZE(s) (((s)->s_rev_level == EXT4_GOOD_OLD_REV) ? \ EXT4_GOOD_OLD_INODE_SIZE : \ (s)->s_inode_size) /* * Structure of a blocks group descriptor */ struct ext4_group_desc { __le32 bg_block_bitmap_lo; /* Blocks bitmap block */ __le32 bg_inode_bitmap_lo; /* Inodes bitmap block */ __le32 bg_inode_table_lo; /* Inodes table block */ __le16 bg_free_blocks_count_lo;/* Free blocks count */ __le16 bg_free_inodes_count_lo;/* Free inodes count */ __le16 bg_used_dirs_count_lo; /* Directories count */ __le16 bg_flags; /* EXT4_BG_flags (INODE_UNINIT, etc) */ __le32 bg_exclude_bitmap_lo; /* Exclude bitmap for snapshots */ __le16 bg_block_bitmap_csum_lo;/* crc32c(s_uuid+grp_num+bbitmap) LE */ __le16 bg_inode_bitmap_csum_lo;/* crc32c(s_uuid+grp_num+ibitmap) LE */ __le16 bg_itable_unused_lo; /* Unused inodes count */ __le16 bg_checksum; /* crc16(sb_uuid+group+desc) */ __le32 bg_block_bitmap_hi; /* Blocks bitmap block MSB */ __le32 bg_inode_bitmap_hi; /* Inodes bitmap block MSB */ __le32 bg_inode_table_hi; /* Inodes table block MSB */ __le16 bg_free_blocks_count_hi;/* Free blocks count MSB */ __le16 bg_free_inodes_count_hi;/* Free inodes count MSB */ __le16 bg_used_dirs_count_hi; /* Directories count MSB */ __le16 bg_itable_unused_hi; /* Unused inodes count MSB */ __le32 bg_exclude_bitmap_hi; /* Exclude bitmap block MSB */ __le16 bg_block_bitmap_csum_hi;/* crc32c(s_uuid+grp_num+bbitmap) BE */ __le16 bg_inode_bitmap_csum_hi;/* crc32c(s_uuid+grp_num+ibitmap) BE */ __u32 bg_reserved; }; /* * Macro-instructions used to manage group descriptors */ #define EXT4_MIN_DESC_SIZE 32 #define EXT4_MIN_DESC_SIZE_64BIT 64 #define EXT4_MAX_DESC_SIZE EXT4_MIN_BLOCK_SIZE #define EXT4_DESC_SIZE(s) ((s)->s_desc_size) #define EXT4_BLOCKS_PER_GROUP(s) ((s)->s_blocks_per_group) #define EXT4_DESC_PER_BLOCK(s) (EXT4_BLOCK_SIZE(s) / EXT4_DESC_SIZE(s)) #define EXT4_INODES_PER_GROUP(s) ((s)->s_inodes_per_group) /* * Constants relative to the data blocks */ #define EXT4_NDIR_BLOCKS 12 #define EXT4_IND_BLOCK EXT4_NDIR_BLOCKS #define EXT4_DIND_BLOCK (EXT4_IND_BLOCK + 1) #define EXT4_TIND_BLOCK (EXT4_DIND_BLOCK + 1) #define EXT4_N_BLOCKS (EXT4_TIND_BLOCK + 1) /* * Inode flags */ #define EXT4_SECRM_FL 0x00000001 /* Secure deletion */ #define EXT4_UNRM_FL 0x00000002 /* Undelete */ #define EXT4_COMPR_FL 0x00000004 /* Compress file */ #define EXT4_SYNC_FL 0x00000008 /* Synchronous updates */ #define EXT4_IMMUTABLE_FL 0x00000010 /* Immutable file */ #define EXT4_APPEND_FL 0x00000020 /* writes to file may only append */ #define EXT4_NODUMP_FL 0x00000040 /* do not dump file */ #define EXT4_NOATIME_FL 0x00000080 /* do not update atime */ /* Reserved for compression usage... */ #define EXT4_DIRTY_FL 0x00000100 #define EXT4_COMPRBLK_FL 0x00000200 /* One or more compressed clusters */ #define EXT4_NOCOMP_FL 0x00000400 /* Don't compress */ #define EXT4_ECOMPR_FL 0x00000800 /* Compression error */ /* End compression flags --- maybe not all used */ #define EXT4_INDEX_FL 0x00001000 /* hash-indexed directory */ #define EXT4_IMAGIC_FL 0x00002000 /* AFS directory */ #define EXT4_JOURNAL_DATA_FL 0x00004000 /* Reserved for ext3 */ #define EXT4_NOTAIL_FL 0x00008000 /* file tail should not be merged */ #define EXT4_DIRSYNC_FL 0x00010000 /* dirsync behaviour (directories only) */ #define EXT4_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/ #define EXT4_HUGE_FILE_FL 0x00040000 /* Set to each huge file */ #define EXT4_EXTENTS_FL 0x00080000 /* Inode uses extents */ #define EXT4_EA_INODE_FL 0x00200000 /* Inode used for large EA */ #define EXT4_EOFBLOCKS_FL 0x00400000 /* Blocks allocated beyond EOF */ #define EXT4_RESERVED_FL 0x80000000 /* reserved for ext4 lib */ #define EXT4_FL_USER_VISIBLE 0x004BDFFF /* User visible flags */ #define EXT4_FL_USER_MODIFIABLE 0x004B80FF /* User modifiable flags */ /* * Structure of an inode on the disk */ struct ext4_inode { __le16 i_mode; /* File mode */ __le16 i_uid; /* Low 16 bits of Owner Uid */ __le32 i_size_lo; /* Size in bytes */ __le32 i_atime; /* Access time */ __le32 i_ctime; /* Inode Change time */ __le32 i_mtime; /* Modification time */ __le32 i_dtime; /* Deletion Time */ __le16 i_gid; /* Low 16 bits of Group Id */ __le16 i_links_count; /* Links count */ __le32 i_blocks_lo; /* Blocks count */ __le32 i_flags; /* File flags */ union { struct { __le32 l_i_version; } linux1; struct { __u32 h_i_translator; } hurd1; struct { __u32 m_i_reserved1; } masix1; } osd1; /* OS dependent 1 */ __le32 i_block[EXT4_N_BLOCKS];/* Pointers to blocks */ __le32 i_generation; /* File version (for NFS) */ __le32 i_file_acl_lo; /* File ACL */ __le32 i_size_high; __le32 i_obso_faddr; /* Obsoleted fragment address */ union { struct { __le16 l_i_blocks_high; /* were l_i_reserved1 */ __le16 l_i_file_acl_high; __le16 l_i_uid_high; /* these 2 fields */ __le16 l_i_gid_high; /* were reserved2[0] */ __le16 l_i_checksum_lo;/* crc32c(uuid+inum+inode) LE */ __le16 l_i_reserved; } linux2; struct { __le16 h_i_reserved1; /* Obsoleted fragment number/size which are removed in ext4 */ __u16 h_i_mode_high; __u16 h_i_uid_high; __u16 h_i_gid_high; __u32 h_i_author; } hurd2; struct { __le16 h_i_reserved1; /* Obsoleted fragment number/size which are removed in ext4 */ __le16 m_i_file_acl_high; __u32 m_i_reserved2[2]; } masix2; } osd2; /* OS dependent 2 */ __le16 i_extra_isize; __le16 i_checksum_hi; /* crc32c(uuid+inum+inode) BE */ __le32 i_ctime_extra; /* extra Change time (nsec << 2 | epoch) */ __le32 i_mtime_extra; /* extra Modification time(nsec << 2 | epoch) */ __le32 i_atime_extra; /* extra Access time (nsec << 2 | epoch) */ __le32 i_crtime; /* File Creation time */ __le32 i_crtime_extra; /* extra FileCreationtime (nsec << 2 | epoch) */ __le32 i_version_hi; /* high 32 bits for 64-bit version */ }; /* * Inode flags used for atomic set/get */ enum { EXT4_INODE_SECRM = 0, /* Secure deletion */ EXT4_INODE_UNRM = 1, /* Undelete */ EXT4_INODE_COMPR = 2, /* Compress file */ EXT4_INODE_SYNC = 3, /* Synchronous updates */ EXT4_INODE_IMMUTABLE = 4, /* Immutable file */ EXT4_INODE_APPEND = 5, /* writes to file may only append */ EXT4_INODE_NODUMP = 6, /* do not dump file */ EXT4_INODE_NOATIME = 7, /* do not update atime */ /* Reserved for compression usage... */ EXT4_INODE_DIRTY = 8, EXT4_INODE_COMPRBLK = 9, /* One or more compressed clusters */ EXT4_INODE_NOCOMPR = 10, /* Don't compress */ EXT4_INODE_ECOMPR = 11, /* Compression error */ /* End compression flags --- maybe not all used */ EXT4_INODE_INDEX = 12, /* hash-indexed directory */ EXT4_INODE_IMAGIC = 13, /* AFS directory */ EXT4_INODE_JOURNAL_DATA = 14, /* file data should be journaled */ EXT4_INODE_NOTAIL = 15, /* file tail should not be merged */ EXT4_INODE_DIRSYNC = 16, /* dirsync behaviour (directories only) */ EXT4_INODE_TOPDIR = 17, /* Top of directory hierarchies*/ EXT4_INODE_HUGE_FILE = 18, /* Set to each huge file */ EXT4_INODE_EXTENTS = 19, /* Inode uses extents */ EXT4_INODE_EA_INODE = 21, /* Inode used for large EA */ EXT4_INODE_EOFBLOCKS = 22, /* Blocks allocated beyond EOF */ EXT4_INODE_RESERVED = 31, /* reserved for ext4 lib */ }; /* * Structure of the super block */ struct ext4_super_block { /*00*/ __le32 s_inodes_count; /* Inodes count */ __le32 s_blocks_count_lo; /* Blocks count */ __le32 s_r_blocks_count_lo; /* Reserved blocks count */ __le32 s_free_blocks_count_lo; /* Free blocks count */ /*10*/ __le32 s_free_inodes_count; /* Free inodes count */ __le32 s_first_data_block; /* First Data Block */ __le32 s_log_block_size; /* Block size */ __le32 s_log_cluster_size; /* Allocation cluster size */ /*20*/ __le32 s_blocks_per_group; /* # Blocks per group */ __le32 s_clusters_per_group; /* # Clusters per group */ __le32 s_inodes_per_group; /* # Inodes per group */ __le32 s_mtime; /* Mount time */ /*30*/ __le32 s_wtime; /* Write time */ __le16 s_mnt_count; /* Mount count */ __le16 s_max_mnt_count; /* Maximal mount count */ __le16 s_magic; /* Magic signature */ __le16 s_state; /* File system state */ __le16 s_errors; /* Behaviour when detecting errors */ __le16 s_minor_rev_level; /* minor revision level */ /*40*/ __le32 s_lastcheck; /* time of last check */ __le32 s_checkinterval; /* max. time between checks */ __le32 s_creator_os; /* OS */ __le32 s_rev_level; /* Revision level */ /*50*/ __le16 s_def_resuid; /* Default uid for reserved blocks */ __le16 s_def_resgid; /* Default gid for reserved blocks */ /* * These fields are for EXT4_DYNAMIC_REV superblocks only. * * Note: the difference between the compatible feature set and * the incompatible feature set is that if there is a bit set * in the incompatible feature set that the kernel doesn't * know about, it should refuse to mount the filesystem. * * e2fsck's requirements are more strict; if it doesn't know * about a feature in either the compatible or incompatible * feature set, it must abort and not try to meddle with * things it doesn't understand... */ __le32 s_first_ino; /* First non-reserved inode */ __le16 s_inode_size; /* size of inode structure */ __le16 s_block_group_nr; /* block group # of this superblock */ __le32 s_feature_compat; /* compatible feature set */ /*60*/ __le32 s_feature_incompat; /* incompatible feature set */ __le32 s_feature_ro_compat; /* readonly-compatible feature set */ /*68*/ __u8 s_uuid[16]; /* 128-bit uuid for volume */ /*78*/ char s_volume_name[16]; /* volume name */ /*88*/ char s_last_mounted[64]; /* directory where last mounted */ /*C8*/ __le32 s_algorithm_usage_bitmap; /* For compression */ /* * Performance hints. Directory preallocation should only * happen if the EXT4_FEATURE_COMPAT_DIR_PREALLOC flag is on. */ __u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/ __u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */ __le16 s_reserved_gdt_blocks; /* Per group desc for online growth */ /* * Journaling support valid if EXT4_FEATURE_COMPAT_HAS_JOURNAL set. */ /*D0*/ __u8 s_journal_uuid[16]; /* uuid of journal superblock */ /*E0*/ __le32 s_journal_inum; /* inode number of journal file */ __le32 s_journal_dev; /* device number of journal file */ __le32 s_last_orphan; /* start of list of inodes to delete */ __le32 s_hash_seed[4]; /* HTREE hash seed */ __u8 s_def_hash_version; /* Default hash version to use */ __u8 s_jnl_backup_type; __le16 s_desc_size; /* size of group descriptor */ /*100*/ __le32 s_default_mount_opts; __le32 s_first_meta_bg; /* First metablock block group */ __le32 s_mkfs_time; /* When the filesystem was created */ __le32 s_jnl_blocks[17]; /* Backup of the journal inode */ /* 64bit support valid if EXT4_FEATURE_COMPAT_64BIT */ /*150*/ __le32 s_blocks_count_hi; /* Blocks count */ __le32 s_r_blocks_count_hi; /* Reserved blocks count */ __le32 s_free_blocks_count_hi; /* Free blocks count */ __le16 s_min_extra_isize; /* All inodes have at least # bytes */ __le16 s_want_extra_isize; /* New inodes should reserve # bytes */ __le32 s_flags; /* Miscellaneous flags */ __le16 s_raid_stride; /* RAID stride */ __le16 s_mmp_update_interval; /* # seconds to wait in MMP checking */ __le64 s_mmp_block; /* Block for multi-mount protection */ __le32 s_raid_stripe_width; /* blocks on all data disks (N*stride)*/ __u8 s_log_groups_per_flex; /* FLEX_BG group size */ __u8 s_checksum_type; /* metadata checksum algorithm used */ __le16 s_reserved_pad; __le64 s_kbytes_written; /* nr of lifetime kilobytes written */ __le32 s_snapshot_inum; /* Inode number of active snapshot */ __le32 s_snapshot_id; /* sequential ID of active snapshot */ __le64 s_snapshot_r_blocks_count; /* reserved blocks for active snapshot's future use */ __le32 s_snapshot_list; /* inode number of the head of the on-disk snapshot list */ #define EXT4_S_ERR_START offsetof(struct ext4_super_block, s_error_count) __le32 s_error_count; /* number of fs errors */ __le32 s_first_error_time; /* first time an error happened */ __le32 s_first_error_ino; /* inode involved in first error */ __le64 s_first_error_block; /* block involved of first error */ __u8 s_first_error_func[32]; /* function where the error happened */ __le32 s_first_error_line; /* line number where error happened */ __le32 s_last_error_time; /* most recent time of an error */ __le32 s_last_error_ino; /* inode involved in last error */ __le32 s_last_error_line; /* line number where error happened */ __le64 s_last_error_block; /* block involved of last error */ __u8 s_last_error_func[32]; /* function where the error happened */ #define EXT4_S_ERR_END offsetof(struct ext4_super_block, s_mount_opts) __u8 s_mount_opts[64]; __le32 s_usr_quota_inum; /* inode for tracking user quota */ __le32 s_grp_quota_inum; /* inode for tracking group quota */ __le32 s_overhead_clusters; /* overhead blocks/clusters in fs */ __le32 s_reserved[108]; /* Padding to the end of the block */ __le32 s_checksum; /* crc32c(superblock) */ }; /* * Revision levels */ #define EXT4_GOOD_OLD_REV 0 /* The good old (original) format */ #define EXT4_DYNAMIC_REV 1 /* V2 format w/ dynamic inode sizes */ #define EXT4_CURRENT_REV EXT4_GOOD_OLD_REV #define EXT4_MAX_SUPP_REV EXT4_DYNAMIC_REV #define EXT4_GOOD_OLD_INODE_SIZE 128 /* * Feature set definitions (only the once we need for read support) */ #define EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001 #define EXT4_FEATURE_INCOMPAT_COMPRESSION 0x0001 #define EXT4_FEATURE_INCOMPAT_FILETYPE 0x0002 #define EXT4_FEATURE_INCOMPAT_RECOVER 0x0004 /* Needs recovery */ #define EXT4_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 /* Journal device */ #define EXT4_FEATURE_INCOMPAT_META_BG 0x0010 #define EXT4_FEATURE_INCOMPAT_EXTENTS 0x0040 /* extents support */ #define EXT4_FEATURE_INCOMPAT_64BIT 0x0080 #define EXT4_FEATURE_INCOMPAT_MMP 0x0100 #define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x0200 #define EXT4_FEATURE_INCOMPAT_EA_INODE 0x0400 /* EA in inode */ #define EXT4_FEATURE_INCOMPAT_DIRDATA 0x1000 /* data in dirent */ #define EXT4_FEATURE_INCOMPAT_BG_USE_META_CSUM 0x2000 /* use crc32c for bg */ #define EXT4_FEATURE_INCOMPAT_LARGEDIR 0x4000 /* >2GB or 3-lvl htree */ #define EXT4_FEATURE_INCOMPAT_INLINEDATA 0x8000 /* data in inode */ #define EXT4_FEATURE_INCOMPAT_SUPP (EXT4_FEATURE_INCOMPAT_FILETYPE| \ EXT4_FEATURE_INCOMPAT_RECOVER| \ EXT4_FEATURE_INCOMPAT_META_BG| \ EXT4_FEATURE_INCOMPAT_EXTENTS| \ EXT4_FEATURE_INCOMPAT_64BIT| \ EXT4_FEATURE_INCOMPAT_FLEX_BG| \ EXT4_FEATURE_INCOMPAT_MMP) /* * Structure of a directory entry */ #define EXT4_NAME_LEN 255 struct ext4_dir_entry { __le32 inode; /* Inode number */ __le16 rec_len; /* Directory entry length */ __u8 name_len; /* Name length */ __u8 file_type; char name[EXT4_NAME_LEN]; /* File name */ }; // NOTE: The original Linux kernel header defines ext4_dir_entry with the original // layout and ext4_dir_entry_2 with the revised layout. We simply use the revised one. /* * Ext2 directory file types. Only the low 3 bits are used. The * other bits are reserved for now. */ enum { EXT4_FT_UNKNOWN, EXT4_FT_REG_FILE, EXT4_FT_DIR, EXT4_FT_CHRDEV, EXT4_FT_BLKDEV, EXT4_FT_FIFO, EXT4_FT_SOCK, EXT4_FT_SYMLINK, EXT4_FT_MAX }; /* * ext4_inode has i_block array (60 bytes total). * The first 12 bytes store ext4_extent_header; * the remainder stores an array of ext4_extent. * For non-inode extent blocks, ext4_extent_tail * follows the array. */ /* * This is the extent tail on-disk structure. * All other extent structures are 12 bytes long. It turns out that * block_size % 12 >= 4 for at least all powers of 2 greater than 512, which * covers all valid ext4 block sizes. Therefore, this tail structure can be * crammed into the end of the block without having to rebalance the tree. */ struct ext4_extent_tail { __le32 et_checksum; /* crc32c(uuid+inum+extent_block) */ }; /* * This is the extent on-disk structure. * It's used at the bottom of the tree. */ struct ext4_extent { __le32 ee_block; /* first logical block extent covers */ __le16 ee_len; /* number of blocks covered by extent */ __le16 ee_start_hi; /* high 16 bits of physical block */ __le32 ee_start_lo; /* low 32 bits of physical block */ }; /* * This is index on-disk structure. * It's used at all the levels except the bottom. */ struct ext4_extent_idx { __le32 ei_block; /* index covers logical blocks from 'block' */ __le32 ei_leaf_lo; /* pointer to the physical block of the next * * level. leaf or next index could be there */ __le16 ei_leaf_hi; /* high 16 bits of physical block */ __u16 ei_unused; }; /* * Each block (leaves and indexes), even inode-stored has header. */ struct ext4_extent_header { __le16 eh_magic; /* probably will support different formats */ __le16 eh_entries; /* number of valid entries */ __le16 eh_max; /* capacity of store in entries */ __le16 eh_depth; /* has tree real underlying blocks? */ __le32 eh_generation; /* generation of the tree */ }; #define EXT4_EXT_MAGIC (0xf30a) #endif ��������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/fsw_efi_edk2_base.h�������������������������������������������������������0000664�0001750�0001750�00000005676�12626644770�021407� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/** * \file fsw_efi_edk2_base.h * Base definitions for the EDK EFI Toolkit environment. */ /* * Copyright (c) 2012 Stefan Agner * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * * Neither the name of Christoph Pfisterer nor the names of the * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _FSW_EFI_EDK2_BASE_H_ #define _FSW_EFI_EDK2_BASE_H_ /* * Here is common declarations for EDK<->EDK2 compatibility */ # include <Base.h> # include <Uefi.h> # include <Library/DebugLib.h> # include <Library/BaseLib.h> # include <Protocol/DriverBinding.h> # include <Library/BaseMemoryLib.h> # include <Library/UefiRuntimeServicesTableLib.h> # include <Library/UefiDriverEntryPoint.h> # include <Library/UefiBootServicesTableLib.h> # include <Library/MemoryAllocationLib.h> # include <Library/DevicePathLib.h> # include <Protocol/DevicePathFromText.h> # include <Protocol/DevicePathToText.h> # include <Protocol/DebugPort.h> # include <Protocol/DebugSupport.h> # include <Library/PrintLib.h> # include <Library/UefiLib.h> # include <Protocol/SimpleFileSystem.h> # include <Protocol/BlockIo.h> # include <Protocol/DiskIo.h> # include <Guid/FileSystemInfo.h> # include <Guid/FileInfo.h> # include <Guid/FileSystemVolumeLabelInfo.h> # include <Protocol/ComponentName.h> # define BS gBS # define EFI_FILE_HANDLE_REVISION EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION # define SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL_INFO SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL # define EFI_FILE_SYSTEM_VOLUME_LABEL_INFO EFI_FILE_SYSTEM_VOLUME_LABEL # define EFI_SIGNATURE_32(a, b, c, d) SIGNATURE_32(a, b, c, d) # define DivU64x32(x,y,z) DivU64x32((x),(y)) #endif ������������������������������������������������������������������refind-0.11.4/filesystems/fsw_ext4.h����������������������������������������������������������������0000644�0001750�0001750�00000004036�12773017116�017603� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/** * \file fsw_ext4.h * ext4 file system driver header. */ /*- * Copyright (c) 2012 Stefan Agner * Portions Copyright (c) 2006 Christoph Pfisterer * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _FSW_EXT4_H_ #define _FSW_EXT4_H_ #define VOLSTRUCTNAME fsw_ext4_volume #define DNODESTRUCTNAME fsw_ext4_dnode #include "fsw_core.h" #include "fsw_ext4_disk.h" //! Block size to be used when reading the ext4 superblock. #define EXT4_SUPERBLOCK_BLOCKSIZE 1024 //! Block number where the (master copy of the) ext4 superblock resides. #define EXT4_SUPERBLOCK_BLOCKNO 1 /** * ext4: Volume structure with ext2-specific data. */ struct fsw_ext4_volume { struct fsw_volume g; //!< Generic volume structure struct ext4_super_block *sb; //!< Full raw ext2 superblock structure fsw_u64 *inotab_bno; //!< Block numbers of the inode tables fsw_u32 ind_bcnt; //!< Number of blocks addressable through an indirect block fsw_u32 dind_bcnt; //!< Number of blocks addressable through a double-indirect block fsw_u32 inode_size; //!< Size of inode structure in bytes }; /** * ext2: Dnode structure with ext2-specific data. */ struct fsw_ext4_dnode { struct fsw_dnode g; //!< Generic dnode structure struct ext4_inode *raw; //!< Full raw inode structure }; #endif ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/fsw_hfs.h�����������������������������������������������������������������0000664�0001750�0001750�00000010200�12626644770�017500� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Id: fsw_hfs.h 29125 2010-05-06 09:43:05Z vboxsync $ */ /** @file * fsw_hfs.h - HFS file system driver header. */ /* * Copyright (C) 2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; * you can redistribute it and/or modify it under the terms of the GNU * General Public License (GPL) as published by the Free Software * Foundation, in version 2 as it comes in the "COPYING" file of the * VirtualBox OSE distribution. VirtualBox OSE is distributed in the * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. */ #ifndef _FSW_HFS_H_ #define _FSW_HFS_H_ #define VOLSTRUCTNAME fsw_hfs_volume #define DNODESTRUCTNAME fsw_hfs_dnode #include "fsw_core.h" //! Block size for HFS volumes. #define HFS_BLOCKSIZE 512 //! Block number where the HFS superblock resides. #define HFS_SUPERBLOCK_BLOCKNO 2 /* Make world look Applish enough for the system header describing HFS layout */ #define __APPLE_API_PRIVATE #define __APPLE_API_UNSTABLE #define u_int8_t fsw_u8 #define u_int16_t fsw_u16 #define u_int32_t fsw_u32 #define u_int64_t fsw_u64 #define int8_t fsw_s8 #define int16_t fsw_s16 #define int32_t fsw_s32 #define int64_t fsw_s64 #include "hfs_format.h" #undef u_int8_t #undef u_int16_t #undef u_int32_t #undef u_int64_t #undef int8_t #undef int16_t #undef int32_t #undef int64_t #pragma pack(1) #ifdef _MSC_VER /* vasily: disable warning for non-standard anonymous struct/union * declarations */ # pragma warning (disable:4201) # define inline __inline #endif struct hfs_dirrec { fsw_u8 _dummy; }; struct fsw_hfs_key { union { struct HFSPlusExtentKey ext_key; struct HFSPlusCatalogKey cat_key; fsw_u16 key_len; /* Length is at the beginning of all keys */ }; }; #pragma pack() typedef enum { /* Regular HFS */ FSW_HFS_PLAIN = 0, /* HFS+ */ FSW_HFS_PLUS, /* HFS+ embedded to HFS */ FSW_HFS_PLUS_EMB } fsw_hfs_kind; /** * HFS: Dnode structure with HFS-specific data. */ struct fsw_hfs_dnode { struct fsw_dnode g; //!< Generic dnode structure HFSPlusExtentRecord extents; fsw_u32 ctime; fsw_u32 mtime; fsw_u64 used_bytes; }; /** * HFS: In-memory B-tree structure. */ struct fsw_hfs_btree { fsw_u32 root_node; fsw_u32 node_size; struct fsw_hfs_dnode* file; }; /** * HFS: In-memory volume structure with HFS-specific data. */ struct fsw_hfs_volume { struct fsw_volume g; //!< Generic volume structure struct HFSPlusVolumeHeader *primary_voldesc; //!< Volume Descriptor struct fsw_hfs_btree catalog_tree; // Catalog tree struct fsw_hfs_btree extents_tree; // Extents overflow tree struct fsw_hfs_dnode root_file; int case_sensitive; fsw_u32 block_size_shift; fsw_hfs_kind hfs_kind; fsw_u32 emb_block_off; }; /* Endianess swappers */ static inline fsw_u16 swab16(fsw_u16 x) { return (x<<8 | ((x & 0xff00)>>8)); } static inline fsw_u32 swab32(fsw_u32 x) { return x<<24 | x>>24 | (x & (fsw_u32)0x0000ff00UL)<<8 | (x & (fsw_u32)0x00ff0000UL)>>8; } static inline fsw_u64 swab64(fsw_u64 x) { return x<<56 | x>>56 | (x & (fsw_u64)0x000000000000ff00ULL)<<40 | (x & (fsw_u64)0x0000000000ff0000ULL)<<24 | (x & (fsw_u64)0x00000000ff000000ULL)<< 8 | (x & (fsw_u64)0x000000ff00000000ULL)>> 8 | (x & (fsw_u64)0x0000ff0000000000ULL)>>24 | (x & (fsw_u64)0x00ff000000000000ULL)>>40; } static inline fsw_u16 be16_to_cpu(fsw_u16 x) { return swab16(x); } static inline fsw_u16 cpu_to_be16(fsw_u16 x) { return swab16(x); } static inline fsw_u32 cpu_to_be32(fsw_u32 x) { return swab32(x); } static inline fsw_u32 be32_to_cpu(fsw_u32 x) { return swab32(x); } static inline fsw_u64 be64_to_cpu(fsw_u64 x) { return swab64(x); } #endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/RamDiskDxe/���������������������������������������������������������������0000775�0001750�0001750�00000000000�13113047761�017657� 5����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/RamDiskDxe/RamDiskDxe.uni�������������������������������������������������0000664�0001750�0001750�00000001743�13113047761�022374� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������// /** @file // Produces EFI_RAM_DISK_PROTOCOL and provides the capability to // create/remove RAM disks in a setup browser. // // Copyright (c) 2016, Intel Corporation. All rights reserved.<BR> // // This program and the accompanying materials // are licensed and made available under the terms and conditions of the BSD License // which accompanies this distribution. The full text of the license may be found at // http://opensource.org/licenses/bsd-license.php // // THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, // WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. // // **/ #string STR_MODULE_ABSTRACT #language en-US "Produces EFI_RAM_DISK_PROTOCOL and provides the capability to create/remove RAM disks in a setup browser." #string STR_MODULE_DESCRIPTION #language en-US "This module produces EFI_RAM_DISK_PROTOCOL and provides the capability to create/remove RAM disks in a setup browser." �����������������������������refind-0.11.4/filesystems/RamDiskDxe/RamDisk.asl����������������������������������������������������0000664�0001750�0001750�00000001756�13113047761�021723� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/** @file The definition block in ACPI table for NVDIMM root device. Copyright (c) 2016, Intel Corporation. All rights reserved.<BR> This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ DefinitionBlock ( "RamDisk.aml", "SSDT", 2, "INTEL ", "RamDisk ", 0x1000 ) { Scope (\_SB) { Device (NVDR) { // // Define _HID, "ACPI0012" NVDIMM Root Device // Name (_HID, "ACPI0012") // // Readable name of this device // Name (_STR, Unicode ("NVDIMM Root Device")) Method (_STA, 0) { Return (0x0f) } } } } ������������������refind-0.11.4/filesystems/RamDiskDxe/RamDiskImpl.h��������������������������������������������������0000664�0001750�0001750�00000064140�13113047761�022211� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/** @file The header file of RamDiskDxe driver. Copyright (c) 2016, Intel Corporation. All rights reserved.<BR> This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ #ifndef _RAM_DISK_IMPL_H_ #define _RAM_DISK_IMPL_H_ #include <Uefi.h> #include <Library/BaseLib.h> #include <Library/BaseMemoryLib.h> #include <Library/DebugLib.h> #include <Library/UefiLib.h> #include <Library/UefiDriverEntryPoint.h> #include <Library/UefiBootServicesTableLib.h> #include <Library/UefiHiiServicesLib.h> #include <Library/MemoryAllocationLib.h> #include <Library/HiiLib.h> #include <Library/FileExplorerLib.h> #include <Library/DevicePathLib.h> #include <Library/PrintLib.h> #include <Library/PcdLib.h> #include <Library/DxeServicesLib.h> #include <Protocol/RamDisk.h> #include <Protocol/BlockIo.h> #include <Protocol/BlockIo2.h> #include <Protocol/HiiConfigAccess.h> #include <Protocol/SimpleFileSystem.h> #include <Protocol/AcpiTable.h> #include <Protocol/AcpiSystemDescriptionTable.h> #include <Guid/MdeModuleHii.h> #include <Guid/RamDiskHii.h> #include <Guid/FileInfo.h> #include <IndustryStandard/Acpi61.h> #include "RamDiskNVData.h" /// /// RAM disk general definitions and declarations /// // // Block size for RAM disk // #define RAM_DISK_BLOCK_SIZE 512 // // Iterate through the double linked list. NOT delete safe // #define EFI_LIST_FOR_EACH(Entry, ListHead) \ for(Entry = (ListHead)->ForwardLink; Entry != (ListHead); Entry = Entry->ForwardLink) // // Iterate through the double linked list. This is delete-safe. // Do not touch NextEntry // #define EFI_LIST_FOR_EACH_SAFE(Entry, NextEntry, ListHead) \ for(Entry = (ListHead)->ForwardLink, NextEntry = Entry->ForwardLink;\ Entry != (ListHead); Entry = NextEntry, NextEntry = Entry->ForwardLink) // // RamDiskDxe driver maintains a list of registered RAM disks. // extern LIST_ENTRY RegisteredRamDisks; // // Pointers to the EFI_ACPI_TABLE_PROTOCOL and EFI_ACPI_SDT_PROTOCOL. // extern EFI_ACPI_TABLE_PROTOCOL *mAcpiTableProtocol; extern EFI_ACPI_SDT_PROTOCOL *mAcpiSdtProtocol; // // RAM Disk create method. // typedef enum _RAM_DISK_CREATE_METHOD { RamDiskCreateOthers = 0, RamDiskCreateHii } RAM_DISK_CREATE_METHOD; // // RamDiskDxe driver maintains a list of registered RAM disks. // The struct contains the list entry and the information of each RAM // disk // typedef struct { UINTN Signature; EFI_HANDLE Handle; EFI_BLOCK_IO_PROTOCOL BlockIo; EFI_BLOCK_IO2_PROTOCOL BlockIo2; EFI_BLOCK_IO_MEDIA Media; EFI_DEVICE_PATH_PROTOCOL *DevicePath; UINT64 StartingAddr; UINT64 Size; EFI_GUID TypeGuid; UINT16 InstanceNumber; RAM_DISK_CREATE_METHOD CreateMethod; BOOLEAN InNfit; EFI_QUESTION_ID CheckBoxId; BOOLEAN CheckBoxChecked; LIST_ENTRY ThisInstance; } RAM_DISK_PRIVATE_DATA; #define RAM_DISK_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('R', 'D', 'S', 'K') #define RAM_DISK_PRIVATE_FROM_BLKIO(a) CR (a, RAM_DISK_PRIVATE_DATA, BlockIo, RAM_DISK_PRIVATE_DATA_SIGNATURE) #define RAM_DISK_PRIVATE_FROM_BLKIO2(a) CR (a, RAM_DISK_PRIVATE_DATA, BlockIo2, RAM_DISK_PRIVATE_DATA_SIGNATURE) #define RAM_DISK_PRIVATE_FROM_THIS(a) CR (a, RAM_DISK_PRIVATE_DATA, ThisInstance, RAM_DISK_PRIVATE_DATA_SIGNATURE) /// /// RAM disk HII-related definitions and declarations /// // // Tool generated IFR binary data and String package data // extern UINT8 RamDiskHiiBin[]; extern UINT8 RamDiskDxeStrings[]; typedef struct { VENDOR_DEVICE_PATH VendorDevicePath; EFI_DEVICE_PATH_PROTOCOL End; } HII_VENDOR_DEVICE_PATH; typedef struct { UINTN Signature; RAM_DISK_CONFIGURATION ConfigStore; EFI_HII_CONFIG_ACCESS_PROTOCOL ConfigAccess; EFI_HANDLE DriverHandle; EFI_HII_HANDLE HiiHandle; } RAM_DISK_CONFIG_PRIVATE_DATA; extern RAM_DISK_CONFIG_PRIVATE_DATA mRamDiskConfigPrivateDataTemplate; #define RAM_DISK_CONFIG_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('R', 'C', 'F', 'G') #define RAM_DISK_CONFIG_PRIVATE_FROM_THIS(a) CR (a, RAM_DISK_CONFIG_PRIVATE_DATA, ConfigAccess, RAM_DISK_CONFIG_PRIVATE_DATA_SIGNATURE) /** Register a RAM disk with specified address, size and type. @param[in] RamDiskBase The base address of registered RAM disk. @param[in] RamDiskSize The size of registered RAM disk. @param[in] RamDiskType The type of registered RAM disk. The GUID can be any of the values defined in section 9.3.6.9, or a vendor defined GUID. @param[in] ParentDevicePath Pointer to the parent device path. If there is no parent device path then ParentDevicePath is NULL. @param[out] DevicePath On return, points to a pointer to the device path of the RAM disk device. If ParentDevicePath is not NULL, the returned DevicePath is created by appending a RAM disk node to the parent device path. If ParentDevicePath is NULL, the returned DevicePath is a RAM disk device path without appending. This function is responsible for allocating the buffer DevicePath with the boot service AllocatePool(). @retval EFI_SUCCESS The RAM disk is registered successfully. @retval EFI_INVALID_PARAMETER DevicePath or RamDiskType is NULL. RamDiskSize is 0. @retval EFI_ALREADY_STARTED A Device Path Protocol instance to be created is already present in the handle database. @retval EFI_OUT_OF_RESOURCES The RAM disk register operation fails due to resource limitation. **/ EFI_STATUS EFIAPI RamDiskRegister ( IN UINT64 RamDiskBase, IN UINT64 RamDiskSize, IN EFI_GUID *RamDiskType, IN EFI_DEVICE_PATH *ParentDevicePath OPTIONAL, OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath ); /** Unregister a RAM disk specified by DevicePath. @param[in] DevicePath A pointer to the device path that describes a RAM Disk device. @retval EFI_SUCCESS The RAM disk is unregistered successfully. @retval EFI_INVALID_PARAMETER DevicePath is NULL. @retval EFI_UNSUPPORTED The device specified by DevicePath is not a valid ramdisk device path and not supported by the driver. @retval EFI_NOT_FOUND The RAM disk pointed by DevicePath doesn't exist. **/ EFI_STATUS EFIAPI RamDiskUnregister ( IN EFI_DEVICE_PATH_PROTOCOL *DevicePath ); /** Initialize the BlockIO protocol of a RAM disk device. @param[in] PrivateData Points to RAM disk private data. **/ VOID RamDiskInitBlockIo ( IN RAM_DISK_PRIVATE_DATA *PrivateData ); /** Reset the Block Device. @param[in] This Indicates a pointer to the calling context. @param[in] ExtendedVerification Driver may perform diagnostics on reset. @retval EFI_SUCCESS The device was reset. @retval EFI_DEVICE_ERROR The device is not functioning properly and could not be reset. **/ EFI_STATUS EFIAPI RamDiskBlkIoReset ( IN EFI_BLOCK_IO_PROTOCOL *This, IN BOOLEAN ExtendedVerification ); /** Read BufferSize bytes from Lba into Buffer. @param[in] This Indicates a pointer to the calling context. @param[in] MediaId Id of the media, changes every time the media is replaced. @param[in] Lba The starting Logical Block Address to read from. @param[in] BufferSize Size of Buffer, must be a multiple of device block size. @param[out] Buffer A pointer to the destination buffer for the data. The caller is responsible for either having implicit or explicit ownership of the buffer. @retval EFI_SUCCESS The data was read correctly from the device. @retval EFI_DEVICE_ERROR The device reported an error while performing the read. @retval EFI_NO_MEDIA There is no media in the device. @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device. @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device. @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid, or the buffer is not on proper alignment. **/ EFI_STATUS EFIAPI RamDiskBlkIoReadBlocks ( IN EFI_BLOCK_IO_PROTOCOL *This, IN UINT32 MediaId, IN EFI_LBA Lba, IN UINTN BufferSize, OUT VOID *Buffer ); /** Write BufferSize bytes from Lba into Buffer. @param[in] This Indicates a pointer to the calling context. @param[in] MediaId The media ID that the write request is for. @param[in] Lba The starting logical block address to be written. The caller is responsible for writing to only legitimate locations. @param[in] BufferSize Size of Buffer, must be a multiple of device block size. @param[in] Buffer A pointer to the source buffer for the data. @retval EFI_SUCCESS The data was written correctly to the device. @retval EFI_WRITE_PROTECTED The device can not be written to. @retval EFI_DEVICE_ERROR The device reported an error while performing the write. @retval EFI_NO_MEDIA There is no media in the device. @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device. @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device. @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid, or the buffer is not on proper alignment. **/ EFI_STATUS EFIAPI RamDiskBlkIoWriteBlocks ( IN EFI_BLOCK_IO_PROTOCOL *This, IN UINT32 MediaId, IN EFI_LBA Lba, IN UINTN BufferSize, IN VOID *Buffer ); /** Flush the Block Device. @param[in] This Indicates a pointer to the calling context. @retval EFI_SUCCESS All outstanding data was written to the device. @retval EFI_DEVICE_ERROR The device reported an error while writting back the data @retval EFI_NO_MEDIA There is no media in the device. **/ EFI_STATUS EFIAPI RamDiskBlkIoFlushBlocks ( IN EFI_BLOCK_IO_PROTOCOL *This ); /** Resets the block device hardware. @param[in] This The pointer of EFI_BLOCK_IO2_PROTOCOL. @param[in] ExtendedVerification The flag about if extend verificate. @retval EFI_SUCCESS The device was reset. @retval EFI_DEVICE_ERROR The block device is not functioning correctly and could not be reset. **/ EFI_STATUS EFIAPI RamDiskBlkIo2Reset ( IN EFI_BLOCK_IO2_PROTOCOL *This, IN BOOLEAN ExtendedVerification ); /** Reads the requested number of blocks from the device. @param[in] This Indicates a pointer to the calling context. @param[in] MediaId The media ID that the read request is for. @param[in] Lba The starting logical block address to read from on the device. @param[in, out] Token A pointer to the token associated with the transaction. @param[in] BufferSize The size of the Buffer in bytes. This must be a multiple of the intrinsic block size of the device. @param[out] Buffer A pointer to the destination buffer for the data. The caller is responsible for either having implicit or explicit ownership of the buffer. @retval EFI_SUCCESS The read request was queued if Token->Event is not NULL. The data was read correctly from the device if the Token->Event is NULL. @retval EFI_DEVICE_ERROR The device reported an error while attempting to perform the read operation. @retval EFI_NO_MEDIA There is no media in the device. @retval EFI_MEDIA_CHANGED The MediaId is not for the current media. @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the intrinsic block size of the device. @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid, or the buffer is not on proper alignment. @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. **/ EFI_STATUS EFIAPI RamDiskBlkIo2ReadBlocksEx ( IN EFI_BLOCK_IO2_PROTOCOL *This, IN UINT32 MediaId, IN EFI_LBA Lba, IN OUT EFI_BLOCK_IO2_TOKEN *Token, IN UINTN BufferSize, OUT VOID *Buffer ); /** Writes a specified number of blocks to the device. @param[in] This Indicates a pointer to the calling context. @param[in] MediaId The media ID that the write request is for. @param[in] Lba The starting logical block address to be written. The caller is responsible for writing to only legitimate locations. @param[in, out] Token A pointer to the token associated with the transaction. @param[in] BufferSize The size in bytes of Buffer. This must be a multiple of the intrinsic block size of the device. @param[in] Buffer A pointer to the source buffer for the data. @retval EFI_SUCCESS The write request was queued if Event is not NULL. The data was written correctly to the device if the Event is NULL. @retval EFI_WRITE_PROTECTED The device cannot be written to. @retval EFI_NO_MEDIA There is no media in the device. @retval EFI_MEDIA_CHANGED The MediaId is not for the current media. @retval EFI_DEVICE_ERROR The device reported an error while attempting to perform the write operation. @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the intrinsic block size of the device. @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid, or the buffer is not on proper alignment. @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. **/ EFI_STATUS EFIAPI RamDiskBlkIo2WriteBlocksEx ( IN EFI_BLOCK_IO2_PROTOCOL *This, IN UINT32 MediaId, IN EFI_LBA Lba, IN OUT EFI_BLOCK_IO2_TOKEN *Token, IN UINTN BufferSize, IN VOID *Buffer ); /** Flushes all modified data to a physical block device. @param[in] This Indicates a pointer to the calling context. @param[in, out] Token A pointer to the token associated with the transaction. @retval EFI_SUCCESS The flush request was queued if Event is not NULL. All outstanding data was written correctly to the device if the Event is NULL. @retval EFI_DEVICE_ERROR The device reported an error while attempting to write data. @retval EFI_WRITE_PROTECTED The device cannot be written to. @retval EFI_NO_MEDIA There is no media in the device. @retval EFI_MEDIA_CHANGED The MediaId is not for the current media. @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. **/ EFI_STATUS EFIAPI RamDiskBlkIo2FlushBlocksEx ( IN EFI_BLOCK_IO2_PROTOCOL *This, IN OUT EFI_BLOCK_IO2_TOKEN *Token ); /** This function publish the RAM disk configuration Form. @param[in, out] ConfigPrivateData Points to RAM disk configuration private data. @retval EFI_SUCCESS HII Form is installed successfully. @retval EFI_OUT_OF_RESOURCES Not enough resource for HII Form installation. @retval Others Other errors as indicated. **/ EFI_STATUS InstallRamDiskConfigForm ( IN OUT RAM_DISK_CONFIG_PRIVATE_DATA *ConfigPrivateData ); /** This function removes RAM disk configuration Form. @param[in, out] ConfigPrivateData Points to RAM disk configuration private data. **/ VOID UninstallRamDiskConfigForm ( IN OUT RAM_DISK_CONFIG_PRIVATE_DATA *ConfigPrivateData ); /** Unregister all registered RAM disks. **/ VOID UnregisterAllRamDisks ( VOID ); /** This function allows a caller to extract the current configuration for one or more named elements from the target driver. @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. @param[in] Request A null-terminated Unicode string in <ConfigRequest> format. @param[out] Progress On return, points to a character in the Request string. Points to the string's null terminator if request was successful. Points to the most recent '&' before the first failing name/value pair (or the beginning of the string if the failure is in the first name/value pair) if the request was not successful. @param[out] Results A null-terminated Unicode string in <ConfigAltResp> format which has all values filled in for the names in the Request string. String to be allocated by the called function. @retval EFI_SUCCESS The Results is filled with the requested values. @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results. @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name. @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver. **/ EFI_STATUS EFIAPI RamDiskExtractConfig ( IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, IN CONST EFI_STRING Request, OUT EFI_STRING *Progress, OUT EFI_STRING *Results ); /** This function processes the results of changes in configuration. @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. @param[in] Configuration A null-terminated Unicode string in <ConfigResp> format. @param[out] Progress A pointer to a string filled in with the offset of the most recent '&' before the first failing name/value pair (or the beginning of the string if the failure is in the first name/value pair) or the terminating NULL if all was successful. @retval EFI_SUCCESS The Results is processed successfully. @retval EFI_INVALID_PARAMETER Configuration is NULL. @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver. **/ EFI_STATUS EFIAPI RamDiskRouteConfig ( IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, IN CONST EFI_STRING Configuration, OUT EFI_STRING *Progress ); /** This function processes the results of changes in configuration. @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. @param[in] Action Specifies the type of action taken by the browser. @param[in] QuestionId A unique value which is sent to the original exporting driver so that it can identify the type of data to expect. @param[in] Type The type of value for the question. @param[in] Value A pointer to the data being sent to the original exporting driver. @param[out] ActionRequest On return, points to the action requested by the callback function. @retval EFI_SUCCESS The callback successfully handled the action. @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data. @retval EFI_DEVICE_ERROR The variable could not be saved. @retval EFI_UNSUPPORTED The specified Action is not supported by the callback. **/ EFI_STATUS EFIAPI RamDiskCallback ( IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, IN EFI_BROWSER_ACTION Action, IN EFI_QUESTION_ID QuestionId, IN UINT8 Type, IN EFI_IFR_TYPE_VALUE *Value, OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest ); /** This function gets the file information from an open file descriptor, and stores it in a buffer allocated from pool. @param[in] FHand File Handle. @return A pointer to a buffer with file information or NULL is returned. **/ EFI_FILE_INFO * FileInfo ( IN EFI_FILE_HANDLE FHand ); /** This function will open a file or directory referenced by DevicePath. This function opens a file with the open mode according to the file path. The Attributes is valid only for EFI_FILE_MODE_CREATE. @param[in, out] FilePath On input, the device path to the file. On output, the remaining device path. @param[out] FileHandle Pointer to the file handle. @param[in] OpenMode The mode to open the file with. @param[in] Attributes The file's file attributes. @retval EFI_SUCCESS The information was set. @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. @retval EFI_UNSUPPORTED Could not open the file path. @retval EFI_NOT_FOUND The specified file could not be found on the device or the file system could not be found on the device. @retval EFI_NO_MEDIA The device has no medium. @retval EFI_MEDIA_CHANGED The device has a different medium in it or the medium is no longer supported. @retval EFI_DEVICE_ERROR The device reported an error. @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. @retval EFI_WRITE_PROTECTED The file or medium is write protected. @retval EFI_ACCESS_DENIED The file was opened read only. @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file. @retval EFI_VOLUME_FULL The volume is full. **/ EFI_STATUS EFIAPI OpenFileByDevicePath( IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath, OUT EFI_FILE_HANDLE *FileHandle, IN UINT64 OpenMode, IN UINT64 Attributes ); /** Publish the RAM disk NVDIMM Firmware Interface Table (NFIT) to the ACPI table. @param[in] PrivateData Points to RAM disk private data. @retval EFI_SUCCESS The RAM disk NFIT has been published. @retval others The RAM disk NFIT has not been published. **/ EFI_STATUS RamDiskPublishNfit ( IN RAM_DISK_PRIVATE_DATA *PrivateData ); #endif ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/RamDiskDxe/RamDiskNVData.h������������������������������������������������0000664�0001750�0001750�00000003313�13113047761�022420� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/** @file Header file for NV data structure definition. Copyright (c) 2016, Intel Corporation. All rights reserved.<BR> (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR> This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ #ifndef _RAM_DISK_NVDATA_H_ #define _RAM_DISK_NVDATA_H_ #include <Guid/HiiPlatformSetupFormset.h> #include <Guid/RamDiskHii.h> #define MAIN_FORM_ID 0x1000 #define MAIN_GOTO_FILE_EXPLORER_ID 0x1001 #define MAIN_REMOVE_RD_QUESTION_ID 0x1002 #define MAIN_LABEL_LIST_START 0x1003 #define MAIN_LABEL_LIST_END 0x1004 #define MAIN_CHECKBOX_QUESTION_ID_START 0x1100 #define CREATE_RAW_RAM_DISK_FORM_ID 0x2000 #define CREATE_RAW_SIZE_QUESTION_ID 0x2001 #define CREATE_RAW_SUBMIT_QUESTION_ID 0x2002 #define CREATE_RAW_DISCARD_QUESTION_ID 0x2003 #define CREATE_RAW_MEMORY_TYPE_QUESTION_ID 0x2004 #define RAM_DISK_BOOT_SERVICE_DATA_MEMORY 0x00 #define RAM_DISK_RESERVED_MEMORY 0x01 #define RAM_DISK_MEMORY_TYPE_MAX 0x02 typedef struct { // // The size of the RAM disk to be created. // UINT64 Size; // // Selected RAM Disk Memory Type // UINT8 MemType; } RAM_DISK_CONFIGURATION; #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/RamDiskDxe/RamDiskDriver.c������������������������������������������������0000664�0001750�0001750�00000014735�13113047761�022543� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/** @file The driver entry point for RamDiskDxe driver. Copyright (c) 2016, Intel Corporation. All rights reserved.<BR> This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ #include "RamDiskImpl.h" // // Handle for the EFI_RAM_DISK_PROTOCOL instance // EFI_HANDLE mRamDiskHandle = NULL; // // The EFI_RAM_DISK_PROTOCOL instances that is installed onto the driver // handle // EFI_RAM_DISK_PROTOCOL mRamDiskProtocol = { RamDiskRegister, RamDiskUnregister }; // // RamDiskDxe driver maintains a list of registered RAM disks. // LIST_ENTRY RegisteredRamDisks; // // Pointers to the EFI_ACPI_TABLE_PROTOCOL and EFI_ACPI_SDT_PROTOCOL. // EFI_ACPI_TABLE_PROTOCOL *mAcpiTableProtocol = NULL; EFI_ACPI_SDT_PROTOCOL *mAcpiSdtProtocol = NULL; /** Check whether EFI_ACPI_TABLE_PROTOCOL and EFI_ACPI_SDT_PROTOCOL are produced. If both protocols are produced, publish all the reserved memory type RAM disks to the NVDIMM Firmware Interface Table (NFIT). @param[in] Event Event whose notification function is being invoked. @param[in] Context The pointer to the notification function's context, which is implementation-dependent. **/ VOID EFIAPI RamDiskAcpiCheck ( IN EFI_EVENT Event, IN VOID *Context ) { EFI_STATUS Status; LIST_ENTRY *Entry; RAM_DISK_PRIVATE_DATA *PrivateData; gBS->CloseEvent (Event); // // Locate the EFI_ACPI_TABLE_PROTOCOL. // Status = gBS->LocateProtocol ( &gEfiAcpiTableProtocolGuid, NULL, (VOID **)&mAcpiTableProtocol ); if (EFI_ERROR (Status)) { DEBUG (( EFI_D_INFO, "RamDiskAcpiCheck: Cannot locate the EFI ACPI Table Protocol, " "unable to publish RAM disks to NFIT.\n" )); return; } // // Locate the EFI_ACPI_SDT_PROTOCOL. // Status = gBS->LocateProtocol ( &gEfiAcpiSdtProtocolGuid, NULL, (VOID **)&mAcpiSdtProtocol ); if (EFI_ERROR (Status)) { DEBUG (( EFI_D_INFO, "RamDiskAcpiCheck: Cannot locate the EFI ACPI Sdt Protocol, " "unable to publish RAM disks to NFIT.\n" )); mAcpiTableProtocol = NULL; return; } EFI_LIST_FOR_EACH (Entry, &RegisteredRamDisks) { PrivateData = RAM_DISK_PRIVATE_FROM_THIS (Entry); RamDiskPublishNfit (PrivateData); } } /** The entry point for RamDiskDxe driver. @param[in] ImageHandle The image handle of the driver. @param[in] SystemTable The system table. @retval EFI_ALREADY_STARTED The driver already exists in system. @retval EFI_OUT_OF_RESOURCES Fail to execute entry point due to lack of resources. @retval EFI_SUCCES All the related protocols are installed on the driver. **/ EFI_STATUS EFIAPI RamDiskDxeEntryPoint ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; RAM_DISK_CONFIG_PRIVATE_DATA *ConfigPrivate; VOID *DummyInterface; EFI_EVENT Event; // // If already started, return. // Status = gBS->LocateProtocol ( &gEfiRamDiskProtocolGuid, NULL, &DummyInterface ); if (!EFI_ERROR (Status)) { DEBUG ((EFI_D_INFO, "Driver already started!\n")); return EFI_ALREADY_STARTED; } // // Create a private data structure. // ConfigPrivate = AllocateCopyPool (sizeof (RAM_DISK_CONFIG_PRIVATE_DATA), &mRamDiskConfigPrivateDataTemplate); if (ConfigPrivate == NULL) { return EFI_OUT_OF_RESOURCES; } // // Install RAM disk configuration form // Status = InstallRamDiskConfigForm (ConfigPrivate); if (EFI_ERROR (Status)) { goto ErrorExit; } // // Install the EFI_RAM_DISK_PROTOCOL and RAM disk private data onto a // new handle // Status = gBS->InstallMultipleProtocolInterfaces ( &mRamDiskHandle, &gEfiRamDiskProtocolGuid, &mRamDiskProtocol, &gEfiCallerIdGuid, ConfigPrivate, NULL ); if (EFI_ERROR (Status)) { goto ErrorExit; } // // Initialize the list of registered RAM disks maintained by the driver // InitializeListHead (&RegisteredRamDisks); Status = EfiCreateEventReadyToBootEx ( TPL_CALLBACK, RamDiskAcpiCheck, NULL, &Event ); ASSERT_EFI_ERROR (Status); return EFI_SUCCESS; ErrorExit: if (ConfigPrivate != NULL) { UninstallRamDiskConfigForm (ConfigPrivate); } return Status; } /** Unload the RamDiskDxe driver and its configuration form. @param[in] ImageHandle The driver's image handle. @retval EFI_SUCCESS The RamDiskDxe driver and its configuration form is unloaded. @retval Others Failed to unload the form. **/ EFI_STATUS EFIAPI RamDiskDxeUnload ( IN EFI_HANDLE ImageHandle ) { EFI_STATUS Status; RAM_DISK_CONFIG_PRIVATE_DATA *ConfigPrivate; Status = gBS->HandleProtocol ( mRamDiskHandle, &gEfiCallerIdGuid, (VOID **) &ConfigPrivate ); if (EFI_ERROR (Status)) { return Status; } ASSERT (ConfigPrivate->Signature == RAM_DISK_CONFIG_PRIVATE_DATA_SIGNATURE); // // Unregister all registered RAM disks // UnregisterAllRamDisks (); gBS->UninstallMultipleProtocolInterfaces ( mRamDiskHandle, &gEfiRamDiskProtocolGuid, &mRamDiskProtocol, &gEfiCallerIdGuid, ConfigPrivate, NULL ); UninstallRamDiskConfigForm (ConfigPrivate); return EFI_SUCCESS; } �����������������������������������refind-0.11.4/filesystems/RamDiskDxe/RamDiskHiiStrings.uni������������������������������������������0000664�0001750�0001750�00000005262�13113047761�023737� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������// /** @file // String definitions for RamDiskDxe driver form. // // Copyright (c) 2016, Intel Corporation. All rights reserved.<BR> // (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR> // This program and the accompanying materials // are licensed and made available under the terms and conditions of the BSD License // which accompanies this distribution. The full text of the license may be found at // http://opensource.org/licenses/bsd-license.php // // THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, // WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. // // **/ #langdef en-US "English" #string STR_FORM_SET_TITLE #language en-US "RAM Disk Configuration" #string STR_FORM_SET_TITLE_HELP #language en-US "Press <Enter> to add/remove RAM disks." #string STR_MAIN_FORM_TITLE #language en-US "RAM Disk HII Main Screen" #string STR_RAM_DISK_NULL_STRING #language en-US "" #string STR_RAM_DISK_LIST_TEXT #language en-US "Created RAM disk list:" #string STR_RAM_DISK_LIST_HELP #language en-US "Select for remove" #string STR_GOTO_ADD_RAW_FORM #language en-US "Create raw" #string STR_GOTO_ADD_RAW_FORM_HELP #language en-US "Create a raw RAM disk." #string STR_GOTO_ADD_FROM_FILE_FORM #language en-US "Create from file" #string STR_GOTO_ADD_FROM_FILE_FORM_HELP #language en-US "Create a RAM disk from a given file." #string STR_REMOVE_SEL_HELP #language en-US "Remove selected RAM disk(s)" #string STR_REMOVE_SEL_TEXT #language en-US "Remove selected RAM disk(s)." #string STR_ADD_RAW_FORM_TITLE #language en-US "Add A Raw RAM Disk" #string STR_ADD_RAW_FORM_SUBTITLE_TEXT #language en-US " " #string STR_SIZE_PROMPT #language en-US "Size (Hex):" #string STR_SIZE_HELP #language en-US "The valid RAM disk size should be multiples of the RAM disk block size." #string STR_MEMORY_TYPE_PROMPT #language en-US "Disk Memory Type:" #string STR_MEMORY_TYPE_HELP #language en-US "Specifies type of memory to use from available memory pool in system to create a disk." #string STR_RAM_DISK_BOOT_SERVICE_DATA_MEMORY #language en-US "Boot Service Data" #string STR_RAM_DISK_RESERVED_MEMORY #language en-US "Reserved" #string STR_CREATE_AND_EXIT_HELP #language en-US "Create a new RAM disk with the given starting and ending address." #string STR_CREATE_AND_EXIT_PROMPT #language en-US "Create & Exit" #string STR_DISCARD_AND_EXIT_HELP #language en-US "Discard and exit." #string STR_DISCARD_AND_EXIT_PROMPT #language en-US "Discard & Exit" ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/RamDiskDxe/RamDiskImpl.c��������������������������������������������������0000664�0001750�0001750�00000055030�13113047761�022202� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/** @file HII Config Access protocol implementation of RamDiskDxe driver. Copyright (c) 2016, Intel Corporation. All rights reserved.<BR> (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR> This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ #include "RamDiskImpl.h" CHAR16 mRamDiskStorageName[] = L"RAM_DISK_CONFIGURATION"; RAM_DISK_CONFIG_PRIVATE_DATA mRamDiskConfigPrivateDataTemplate = { RAM_DISK_CONFIG_PRIVATE_DATA_SIGNATURE, { EFI_PAGE_SIZE, RAM_DISK_BOOT_SERVICE_DATA_MEMORY }, { RamDiskExtractConfig, RamDiskRouteConfig, RamDiskCallback } }; HII_VENDOR_DEVICE_PATH mRamDiskHiiVendorDevicePath = { { { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, { (UINT8) (sizeof (VENDOR_DEVICE_PATH)), (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8) } }, RAM_DISK_FORM_SET_GUID }, { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { (UINT8) (END_DEVICE_PATH_LENGTH), (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8) } } }; /** This function publish the RAM disk configuration Form. @param[in, out] ConfigPrivateData Points to RAM disk configuration private data. @retval EFI_SUCCESS HII Form is installed successfully. @retval EFI_OUT_OF_RESOURCES Not enough resource for HII Form installation. @retval Others Other errors as indicated. **/ EFI_STATUS InstallRamDiskConfigForm ( IN OUT RAM_DISK_CONFIG_PRIVATE_DATA *ConfigPrivateData ) { EFI_STATUS Status; EFI_HII_HANDLE HiiHandle; EFI_HANDLE DriverHandle; EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess; DriverHandle = NULL; ConfigAccess = &ConfigPrivateData->ConfigAccess; Status = gBS->InstallMultipleProtocolInterfaces ( &DriverHandle, &gEfiDevicePathProtocolGuid, &mRamDiskHiiVendorDevicePath, &gEfiHiiConfigAccessProtocolGuid, ConfigAccess, NULL ); if (EFI_ERROR (Status)) { return Status; } ConfigPrivateData->DriverHandle = DriverHandle; // // Publish the HII package list // HiiHandle = HiiAddPackages ( &gRamDiskFormSetGuid, DriverHandle, RamDiskDxeStrings, RamDiskHiiBin, NULL ); if (HiiHandle == NULL) { gBS->UninstallMultipleProtocolInterfaces ( DriverHandle, &gEfiDevicePathProtocolGuid, &mRamDiskHiiVendorDevicePath, &gEfiHiiConfigAccessProtocolGuid, ConfigAccess, NULL ); return EFI_OUT_OF_RESOURCES; } ConfigPrivateData->HiiHandle = HiiHandle; return EFI_SUCCESS; } /** This function removes RAM disk configuration Form. @param[in, out] ConfigPrivateData Points to RAM disk configuration private data. **/ VOID UninstallRamDiskConfigForm ( IN OUT RAM_DISK_CONFIG_PRIVATE_DATA *ConfigPrivateData ) { // // Uninstall HII package list // if (ConfigPrivateData->HiiHandle != NULL) { HiiRemovePackages (ConfigPrivateData->HiiHandle); ConfigPrivateData->HiiHandle = NULL; } // // Uninstall HII Config Access Protocol // if (ConfigPrivateData->DriverHandle != NULL) { gBS->UninstallMultipleProtocolInterfaces ( ConfigPrivateData->DriverHandle, &gEfiDevicePathProtocolGuid, &mRamDiskHiiVendorDevicePath, &gEfiHiiConfigAccessProtocolGuid, &ConfigPrivateData->ConfigAccess, NULL ); ConfigPrivateData->DriverHandle = NULL; } FreePool (ConfigPrivateData); } /** Unregister all registered RAM disks. **/ VOID UnregisterAllRamDisks ( VOID ) { LIST_ENTRY *Entry; LIST_ENTRY *NextEntry; RAM_DISK_PRIVATE_DATA *PrivateData; if (!IsListEmpty(&RegisteredRamDisks)) { EFI_LIST_FOR_EACH_SAFE (Entry, NextEntry, &RegisteredRamDisks) { PrivateData = RAM_DISK_PRIVATE_FROM_THIS (Entry); gBS->UninstallMultipleProtocolInterfaces ( PrivateData->Handle, &gEfiBlockIoProtocolGuid, &PrivateData->BlockIo, &gEfiBlockIo2ProtocolGuid, &PrivateData->BlockIo2, &gEfiDevicePathProtocolGuid, (EFI_DEVICE_PATH_PROTOCOL *) PrivateData->DevicePath, NULL ); RemoveEntryList (&PrivateData->ThisInstance); if (RamDiskCreateHii == PrivateData->CreateMethod) { // // If a RAM disk is created within HII, then the RamDiskDxe driver // driver is responsible for freeing the allocated memory for the // RAM disk. // FreePool ((VOID *)(UINTN) PrivateData->StartingAddr); } FreePool (PrivateData->DevicePath); FreePool (PrivateData); } } } /** This function allows a caller to extract the current configuration for one or more named elements from the target driver. @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. @param[in] Request A null-terminated Unicode string in <ConfigRequest> format. @param[out] Progress On return, points to a character in the Request string. Points to the string's null terminator if request was successful. Points to the most recent '&' before the first failing name/value pair (or the beginning of the string if the failure is in the first name/value pair) if the request was not successful. @param[out] Results A null-terminated Unicode string in <ConfigAltResp> format which has all values filled in for the names in the Request string. String to be allocated by the called function. @retval EFI_SUCCESS The Results is filled with the requested values. @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results. @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name. @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver. **/ EFI_STATUS EFIAPI RamDiskExtractConfig ( IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, IN CONST EFI_STRING Request, OUT EFI_STRING *Progress, OUT EFI_STRING *Results ) { if (Progress == NULL || Results == NULL) { return EFI_INVALID_PARAMETER; } *Progress = Request; return EFI_NOT_FOUND; } /** This function processes the results of changes in configuration. @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. @param[in] Configuration A null-terminated Unicode string in <ConfigResp> format. @param[out] Progress A pointer to a string filled in with the offset of the most recent '&' before the first failing name/value pair (or the beginning of the string if the failure is in the first name/value pair) or the terminating NULL if all was successful. @retval EFI_SUCCESS The Results is processed successfully. @retval EFI_INVALID_PARAMETER Configuration is NULL. @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver. **/ EFI_STATUS EFIAPI RamDiskRouteConfig ( IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, IN CONST EFI_STRING Configuration, OUT EFI_STRING *Progress ) { if (Configuration == NULL || Progress == NULL) { return EFI_INVALID_PARAMETER; } return EFI_NOT_FOUND; } /** Allocate memory and register the RAM disk created within RamDiskDxe driver HII. @param[in] Size If creating raw, size of the RAM disk to create. If creating from file, zero. @param[in] FileHandle If creating raw, NULL. If creating from file, the file handle. @param[in] MemoryType Type of memory to be used to create RAM Disk. @retval EFI_SUCCESS RAM disk is created and registered. @retval EFI_OUT_OF_RESOURCES Not enough storage is available to match the size required. **/ EFI_STATUS HiiCreateRamDisk ( IN UINT64 Size, IN EFI_FILE_HANDLE FileHandle, IN UINT8 MemoryType ) { EFI_STATUS Status; UINTN BufferSize; UINT64 *StartingAddr; EFI_INPUT_KEY Key; EFI_DEVICE_PATH_PROTOCOL *DevicePath; RAM_DISK_PRIVATE_DATA *PrivateData; EFI_FILE_INFO *FileInformation; FileInformation = NULL; StartingAddr = NULL; if (FileHandle != NULL) { // // Create from file. // FileInformation = FileInfo (FileHandle); if (NULL == FileInformation) { do { CreatePopUp ( EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"", L"Not enough memory to get the file information!", L"Press ENTER to continue ...", L"", NULL ); } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); return EFI_OUT_OF_RESOURCES; } // // Update the size of RAM disk according to the file size. // Size = FileInformation->FileSize; } if (Size > (UINTN) -1) { do { CreatePopUp ( EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"", L"The given RAM disk size is too large!", L"Press ENTER to continue ...", L"", NULL ); } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); return EFI_OUT_OF_RESOURCES; } if (MemoryType == RAM_DISK_BOOT_SERVICE_DATA_MEMORY) { Status = gBS->AllocatePool ( EfiBootServicesData, (UINTN)Size, (VOID**)&StartingAddr ); } else if (MemoryType == RAM_DISK_RESERVED_MEMORY) { Status = gBS->AllocatePool ( EfiReservedMemoryType, (UINTN)Size, (VOID**)&StartingAddr ); } else { Status = EFI_INVALID_PARAMETER; } if ((StartingAddr == NULL) || EFI_ERROR(Status)) { do { CreatePopUp ( EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"", L"Not enough memory to create the RAM disk!", L"Press ENTER to continue ...", L"", NULL ); } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); return EFI_OUT_OF_RESOURCES; } if (FileHandle != NULL) { // // Copy the file content to the RAM disk. // BufferSize = (UINTN) Size; FileHandle->Read ( FileHandle, &BufferSize, (VOID *)(UINTN) StartingAddr ); if (BufferSize != FileInformation->FileSize) { do { CreatePopUp ( EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"", L"File content read error!", L"Press ENTER to continue ...", L"", NULL ); } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); return EFI_DEVICE_ERROR; } } // // Register the newly created RAM disk. // Status = RamDiskRegister ( ((UINT64)(UINTN) StartingAddr), Size, &gEfiVirtualDiskGuid, NULL, &DevicePath ); if (EFI_ERROR (Status)) { do { CreatePopUp ( EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"", L"Fail to register the newly created RAM disk!", L"Press ENTER to continue ...", L"", NULL ); } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); return Status; } // // If RAM disk is created within HII, memory should be freed when the // RAM disk is unregisterd. // PrivateData = RAM_DISK_PRIVATE_FROM_THIS (RegisteredRamDisks.BackLink); PrivateData->CreateMethod = RamDiskCreateHii; return EFI_SUCCESS; } /** This function updates the registered RAM disks list on the main form. @param[in, out] ConfigPrivate Private data for configurating hii data for RAM disks. **/ VOID UpdateMainForm ( IN OUT RAM_DISK_CONFIG_PRIVATE_DATA *ConfigPrivate ) { VOID *StartOpCodeHandle; VOID *EndOpCodeHandle; EFI_IFR_GUID_LABEL *StartLabel; EFI_IFR_GUID_LABEL *EndLabel; LIST_ENTRY *Entry; UINTN Index; RAM_DISK_PRIVATE_DATA *PrivateData; CHAR16 *String; CHAR16 RamDiskStr[128]; EFI_STRING_ID StringId; // // Init OpCode Handle // StartOpCodeHandle = HiiAllocateOpCodeHandle (); ASSERT (StartOpCodeHandle != NULL); EndOpCodeHandle = HiiAllocateOpCodeHandle (); ASSERT (EndOpCodeHandle != NULL); // // Create Hii Extend Label OpCode as the start opcode // StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode ( StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL) ); StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; StartLabel->Number = MAIN_LABEL_LIST_START; // // Create Hii Extend Label OpCode as the end opcode // EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode ( EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL) ); EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; EndLabel->Number = MAIN_LABEL_LIST_END; Index = 0; EFI_LIST_FOR_EACH (Entry, &RegisteredRamDisks) { PrivateData = RAM_DISK_PRIVATE_FROM_THIS (Entry); PrivateData->CheckBoxId = (EFI_QUESTION_ID) (MAIN_CHECKBOX_QUESTION_ID_START + Index); // // CheckBox is unchecked by default. // PrivateData->CheckBoxChecked = FALSE; String = RamDiskStr; UnicodeSPrint ( String, sizeof (RamDiskStr), L" RAM Disk %d: [0x%lx, 0x%lx]\n", Index, PrivateData->StartingAddr, PrivateData->StartingAddr + PrivateData->Size - 1 ); StringId = HiiSetString (ConfigPrivate->HiiHandle, 0, RamDiskStr, NULL); ASSERT (StringId != 0); HiiCreateCheckBoxOpCode ( StartOpCodeHandle, PrivateData->CheckBoxId, 0, 0, StringId, STRING_TOKEN (STR_RAM_DISK_LIST_HELP), EFI_IFR_FLAG_CALLBACK, 0, NULL ); Index++; } HiiUpdateForm ( ConfigPrivate->HiiHandle, &gRamDiskFormSetGuid, MAIN_FORM_ID, StartOpCodeHandle, EndOpCodeHandle ); HiiFreeOpCodeHandle (StartOpCodeHandle); HiiFreeOpCodeHandle (EndOpCodeHandle); } /** This function processes the results of changes in configuration. @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. @param[in] Action Specifies the type of action taken by the browser. @param[in] QuestionId A unique value which is sent to the original exporting driver so that it can identify the type of data to expect. @param[in] Type The type of value for the question. @param[in] Value A pointer to the data being sent to the original exporting driver. @param[out] ActionRequest On return, points to the action requested by the callback function. @retval EFI_SUCCESS The callback successfully handled the action. @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data. @retval EFI_DEVICE_ERROR The variable could not be saved. @retval EFI_UNSUPPORTED The specified Action is not supported by the callback. **/ EFI_STATUS EFIAPI RamDiskCallback ( IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, IN EFI_BROWSER_ACTION Action, IN EFI_QUESTION_ID QuestionId, IN UINT8 Type, IN EFI_IFR_TYPE_VALUE *Value, OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest ) { EFI_STATUS Status; RAM_DISK_PRIVATE_DATA *PrivateData; RAM_DISK_CONFIG_PRIVATE_DATA *ConfigPrivate; EFI_DEVICE_PATH_PROTOCOL *FileDevPath; EFI_FILE_HANDLE FileHandle; LIST_ENTRY *Entry; LIST_ENTRY *NextEntry; if ((This == NULL) || (Value == NULL) || (ActionRequest == NULL)) { return EFI_INVALID_PARAMETER; } ConfigPrivate = RAM_DISK_CONFIG_PRIVATE_FROM_THIS (This); if (Action == EFI_BROWSER_ACTION_RETRIEVE) { Status = EFI_UNSUPPORTED; if (QuestionId == CREATE_RAW_SIZE_QUESTION_ID) { Value->u64 = EFI_PAGE_SIZE; ConfigPrivate->ConfigStore.Size = EFI_PAGE_SIZE; Status = EFI_SUCCESS; } else if (QuestionId == CREATE_RAW_MEMORY_TYPE_QUESTION_ID) { Value->u8 = RAM_DISK_BOOT_SERVICE_DATA_MEMORY; ConfigPrivate->ConfigStore.MemType = RAM_DISK_BOOT_SERVICE_DATA_MEMORY; Status = EFI_SUCCESS; } return Status; } if ((Action != EFI_BROWSER_ACTION_CHANGED) && (Action != EFI_BROWSER_ACTION_CHANGING) && (Action != EFI_BROWSER_ACTION_FORM_OPEN)) { return EFI_UNSUPPORTED; } // // Update the RAM disk list show at the main form first. // if (Action == EFI_BROWSER_ACTION_FORM_OPEN) { Status = EFI_UNSUPPORTED; if (QuestionId == MAIN_GOTO_FILE_EXPLORER_ID) { UpdateMainForm (ConfigPrivate); Status = EFI_SUCCESS; } return Status; } Status = EFI_SUCCESS; if (Action == EFI_BROWSER_ACTION_CHANGING) { switch (QuestionId) { case MAIN_GOTO_FILE_EXPLORER_ID: Status = ChooseFile (NULL, NULL, NULL, &FileDevPath); if (EFI_ERROR (Status)) { break; } if (FileDevPath != NULL) { // // Open the file. // Status = OpenFileByDevicePath ( &FileDevPath, &FileHandle, EFI_FILE_MODE_READ, 0 ); if (EFI_ERROR (Status)) { break; } // // Create from file, RAM disk size is zero. It will be updated // according to the file size. // Status = HiiCreateRamDisk ( 0, FileHandle, ConfigPrivate->ConfigStore.MemType ); if (EFI_ERROR (Status)) { break; } // // Refresh the registered RAM disks list. // UpdateMainForm (ConfigPrivate); } break; default: break; } } else if (Action == EFI_BROWSER_ACTION_CHANGED) { switch (QuestionId) { case MAIN_REMOVE_RD_QUESTION_ID: // // Remove the selected RAM disks // EFI_LIST_FOR_EACH_SAFE (Entry, NextEntry, &RegisteredRamDisks) { PrivateData = RAM_DISK_PRIVATE_FROM_THIS (Entry); if (PrivateData->CheckBoxChecked) { RamDiskUnregister ( (EFI_DEVICE_PATH_PROTOCOL *) PrivateData->DevicePath ); } } UpdateMainForm (ConfigPrivate); *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY; break; case CREATE_RAW_SIZE_QUESTION_ID: ConfigPrivate->ConfigStore.Size = Value->u64; break; case CREATE_RAW_MEMORY_TYPE_QUESTION_ID: ConfigPrivate->ConfigStore.MemType = Value->u8; break; case CREATE_RAW_SUBMIT_QUESTION_ID: // // Create raw, FileHandle is NULL. // Status = HiiCreateRamDisk ( ConfigPrivate->ConfigStore.Size, NULL, ConfigPrivate->ConfigStore.MemType ); if (EFI_ERROR (Status)) { break; } // // Refresh the registered RAM disks list. // UpdateMainForm (ConfigPrivate); *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT; break; case CREATE_RAW_DISCARD_QUESTION_ID: *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT; break; default: // // QuestionIds for checkboxes // if ((QuestionId >= MAIN_CHECKBOX_QUESTION_ID_START) && (QuestionId < CREATE_RAW_RAM_DISK_FORM_ID)) { EFI_LIST_FOR_EACH (Entry, &RegisteredRamDisks) { PrivateData = RAM_DISK_PRIVATE_FROM_THIS (Entry); if (PrivateData->CheckBoxId == QuestionId) { PrivateData->CheckBoxChecked = (BOOLEAN) (Value->u8 != 0); } } } break; } } return EFI_SUCCESS; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/RamDiskDxe/RamDiskFileExplorer.c������������������������������������������0000664�0001750�0001750�00000017050�13113047761�023701� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/** @file Internal file explorer helper functions for RamDiskDxe driver. Copyright (c) 2016, Intel Corporation. All rights reserved.<BR> This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ #include "RamDiskImpl.h" /** Helper function called as part of the code needed to allocate the proper sized buffer for various EFI interfaces. @param[in, out] Status Current status. @param[in, out] Buffer Current allocated buffer, or NULL. @param[in] BufferSize Current buffer size needed. @retval TRUE If the buffer was reallocated and the caller should try the API again. @retval FALSE The caller should not call this function again. **/ BOOLEAN GrowBuffer ( IN OUT EFI_STATUS *Status, IN OUT VOID **Buffer, IN UINTN BufferSize ) { BOOLEAN TryAgain; // // If this is an initial request, buffer will be null with a new buffer size // if ((*Buffer == NULL) && (BufferSize != 0)) { *Status = EFI_BUFFER_TOO_SMALL; } // // If the status code is "buffer too small", resize the buffer // TryAgain = FALSE; if (*Status == EFI_BUFFER_TOO_SMALL) { if (*Buffer != NULL) { FreePool (*Buffer); } *Buffer = AllocateZeroPool (BufferSize); if (*Buffer != NULL) { TryAgain = TRUE; } else { *Status = EFI_OUT_OF_RESOURCES; } } // // If there's an error, free the buffer // if (!TryAgain && EFI_ERROR (*Status) && (*Buffer != NULL)) { FreePool (*Buffer); *Buffer = NULL; } return TryAgain; } /** This function gets the file information from an open file descriptor, and stores it in a buffer allocated from pool. @param[in] FHand File Handle. @return A pointer to a buffer with file information or NULL is returned. **/ EFI_FILE_INFO * FileInfo ( IN EFI_FILE_HANDLE FHand ) { EFI_STATUS Status; EFI_FILE_INFO *Buffer; UINTN BufferSize; // // Initialize for GrowBuffer loop // Buffer = NULL; BufferSize = SIZE_OF_EFI_FILE_INFO + 200; // // Call the real function // while (GrowBuffer (&Status, (VOID **) &Buffer, BufferSize)) { Status = FHand->GetInfo ( FHand, &gEfiFileInfoGuid, &BufferSize, Buffer ); } return Buffer; } /** This function will open a file or directory referenced by DevicePath. This function opens a file with the open mode according to the file path. The Attributes is valid only for EFI_FILE_MODE_CREATE. @param[in, out] FilePath On input, the device path to the file. On output, the remaining device path. @param[out] FileHandle Pointer to the file handle. @param[in] OpenMode The mode to open the file with. @param[in] Attributes The file's file attributes. @retval EFI_SUCCESS The information was set. @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. @retval EFI_UNSUPPORTED Could not open the file path. @retval EFI_NOT_FOUND The specified file could not be found on the device or the file system could not be found on the device. @retval EFI_NO_MEDIA The device has no medium. @retval EFI_MEDIA_CHANGED The device has a different medium in it or the medium is no longer supported. @retval EFI_DEVICE_ERROR The device reported an error. @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. @retval EFI_WRITE_PROTECTED The file or medium is write protected. @retval EFI_ACCESS_DENIED The file was opened read only. @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file. @retval EFI_VOLUME_FULL The volume is full. **/ EFI_STATUS EFIAPI OpenFileByDevicePath( IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath, OUT EFI_FILE_HANDLE *FileHandle, IN UINT64 OpenMode, IN UINT64 Attributes ) { EFI_STATUS Status; EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *EfiSimpleFileSystemProtocol; EFI_FILE_PROTOCOL *Handle1; EFI_FILE_PROTOCOL *Handle2; EFI_HANDLE DeviceHandle; if ((FilePath == NULL || FileHandle == NULL)) { return EFI_INVALID_PARAMETER; } Status = gBS->LocateDevicePath ( &gEfiSimpleFileSystemProtocolGuid, FilePath, &DeviceHandle ); if (EFI_ERROR (Status)) { return Status; } Status = gBS->OpenProtocol( DeviceHandle, &gEfiSimpleFileSystemProtocolGuid, (VOID**)&EfiSimpleFileSystemProtocol, gImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL ); if (EFI_ERROR (Status)) { return Status; } Status = EfiSimpleFileSystemProtocol->OpenVolume(EfiSimpleFileSystemProtocol, &Handle1); if (EFI_ERROR (Status)) { FileHandle = NULL; return Status; } // // go down directories one node at a time. // while (!IsDevicePathEnd (*FilePath)) { // // For file system access each node should be a file path component // if (DevicePathType (*FilePath) != MEDIA_DEVICE_PATH || DevicePathSubType (*FilePath) != MEDIA_FILEPATH_DP ) { FileHandle = NULL; return (EFI_INVALID_PARAMETER); } // // Open this file path node // Handle2 = Handle1; Handle1 = NULL; // // Try to test opening an existing file // Status = Handle2->Open ( Handle2, &Handle1, ((FILEPATH_DEVICE_PATH*)*FilePath)->PathName, OpenMode &~EFI_FILE_MODE_CREATE, 0 ); // // see if the error was that it needs to be created // if ((EFI_ERROR (Status)) && (OpenMode != (OpenMode &~EFI_FILE_MODE_CREATE))) { Status = Handle2->Open ( Handle2, &Handle1, ((FILEPATH_DEVICE_PATH*)*FilePath)->PathName, OpenMode, Attributes ); } // // Close the last node // Handle2->Close (Handle2); if (EFI_ERROR(Status)) { return (Status); } // // Get the next node // *FilePath = NextDevicePathNode (*FilePath); } // // This is a weak spot since if the undefined SHELL_FILE_HANDLE format changes this must change also! // *FileHandle = (VOID*)Handle1; return EFI_SUCCESS; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/RamDiskDxe/RamDiskHii.vfr�������������������������������������������������0000664�0001750�0001750�00000006557�13113047761�022377� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������///** @file // VFR file used by the RamDiskDxe driver. // // Copyright (c) 2016, Intel Corporation. All rights reserved.<BR> // (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR> // This program and the accompanying materials // are licensed and made available under the terms and conditions of the BSD License // which accompanies this distribution. The full text of the license may be found at // http://opensource.org/licenses/bsd-license.php // // THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, // WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. // //**/ #include "RamDiskNVData.h" formset guid = RAM_DISK_FORM_SET_GUID, title = STRING_TOKEN(STR_FORM_SET_TITLE), help = STRING_TOKEN(STR_FORM_SET_TITLE_HELP), classguid = EFI_HII_PLATFORM_SETUP_FORMSET_GUID, // // Form #1 "Main Form - Add/Remove/Show RAM Disks" // form formid = MAIN_FORM_ID, title = STRING_TOKEN(STR_MAIN_FORM_TITLE); oneof questionid = CREATE_RAW_MEMORY_TYPE_QUESTION_ID, prompt = STRING_TOKEN(STR_MEMORY_TYPE_PROMPT), help = STRING_TOKEN(STR_MEMORY_TYPE_HELP), flags = NUMERIC_SIZE_1 | INTERACTIVE, option text = STRING_TOKEN(STR_RAM_DISK_BOOT_SERVICE_DATA_MEMORY), value = RAM_DISK_BOOT_SERVICE_DATA_MEMORY, flags = DEFAULT; option text = STRING_TOKEN(STR_RAM_DISK_RESERVED_MEMORY), value = RAM_DISK_RESERVED_MEMORY, flags = 0; endoneof; subtitle text = STRING_TOKEN(STR_RAM_DISK_NULL_STRING); goto CREATE_RAW_RAM_DISK_FORM_ID, prompt = STRING_TOKEN(STR_GOTO_ADD_RAW_FORM), help = STRING_TOKEN(STR_GOTO_ADD_RAW_FORM_HELP); goto MAIN_FORM_ID, prompt = STRING_TOKEN(STR_GOTO_ADD_FROM_FILE_FORM), help = STRING_TOKEN(STR_GOTO_ADD_FROM_FILE_FORM_HELP), flags = INTERACTIVE, key = MAIN_GOTO_FILE_EXPLORER_ID; subtitle text = STRING_TOKEN(STR_RAM_DISK_NULL_STRING); subtitle text = STRING_TOKEN(STR_RAM_DISK_LIST_TEXT); label MAIN_LABEL_LIST_START; label MAIN_LABEL_LIST_END; subtitle text = STRING_TOKEN(STR_RAM_DISK_NULL_STRING); text help = STRING_TOKEN(STR_REMOVE_SEL_HELP), text = STRING_TOKEN(STR_REMOVE_SEL_TEXT), flags = INTERACTIVE, key = MAIN_REMOVE_RD_QUESTION_ID; endform; // // Form #2 "Add New Raw RAM Disk" // form formid = CREATE_RAW_RAM_DISK_FORM_ID, title = STRING_TOKEN(STR_ADD_RAW_FORM_TITLE); subtitle text = STRING_TOKEN(STR_RAM_DISK_NULL_STRING); numeric questionid = CREATE_RAW_SIZE_QUESTION_ID, prompt = STRING_TOKEN(STR_SIZE_PROMPT), help = STRING_TOKEN(STR_SIZE_HELP), flags = NUMERIC_SIZE_8 | DISPLAY_UINT_HEX | INTERACTIVE, minimum = 1, maximum = 0xFFFFFFFFFFFFFFFF, endnumeric; subtitle text = STRING_TOKEN(STR_RAM_DISK_NULL_STRING); text help = STRING_TOKEN(STR_CREATE_AND_EXIT_HELP), text = STRING_TOKEN(STR_CREATE_AND_EXIT_PROMPT), flags = INTERACTIVE, key = CREATE_RAW_SUBMIT_QUESTION_ID; text help = STRING_TOKEN(STR_DISCARD_AND_EXIT_HELP), text = STRING_TOKEN(STR_DISCARD_AND_EXIT_PROMPT), flags = INTERACTIVE, key = CREATE_RAW_DISCARD_QUESTION_ID; endform; endformset; �������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/RamDiskDxe/RamDiskProtocol.c����������������������������������������������0000664�0001750�0001750�00000067655�13113047761�023122� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/** @file The realization of EFI_RAM_DISK_PROTOCOL. Copyright (c) 2016, Intel Corporation. All rights reserved.<BR> (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR> This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ #include "RamDiskImpl.h" RAM_DISK_PRIVATE_DATA mRamDiskPrivateDataTemplate = { RAM_DISK_PRIVATE_DATA_SIGNATURE, NULL }; MEDIA_RAM_DISK_DEVICE_PATH mRamDiskDeviceNodeTemplate = { { MEDIA_DEVICE_PATH, MEDIA_RAM_DISK_DP, { (UINT8) (sizeof (MEDIA_RAM_DISK_DEVICE_PATH)), (UINT8) ((sizeof (MEDIA_RAM_DISK_DEVICE_PATH)) >> 8) } } }; BOOLEAN mRamDiskSsdtTableKeyValid = FALSE; UINTN mRamDiskSsdtTableKey; /** Initialize the RAM disk device node. @param[in] PrivateData Points to RAM disk private data. @param[in, out] RamDiskDevNode Points to the RAM disk device node. **/ VOID RamDiskInitDeviceNode ( IN RAM_DISK_PRIVATE_DATA *PrivateData, IN OUT MEDIA_RAM_DISK_DEVICE_PATH *RamDiskDevNode ) { WriteUnaligned64 ( (UINT64 *) &(RamDiskDevNode->StartingAddr[0]), (UINT64) PrivateData->StartingAddr ); WriteUnaligned64 ( (UINT64 *) &(RamDiskDevNode->EndingAddr[0]), (UINT64) PrivateData->StartingAddr + PrivateData->Size - 1 ); CopyGuid (&RamDiskDevNode->TypeGuid, &PrivateData->TypeGuid); RamDiskDevNode->Instance = PrivateData->InstanceNumber; } /** Initialize and publish NVDIMM root device SSDT in ACPI table. @retval EFI_SUCCESS The NVDIMM root device SSDT is published. @retval Others The NVDIMM root device SSDT is not published. **/ EFI_STATUS RamDiskPublishSsdt ( VOID ) { EFI_STATUS Status; EFI_ACPI_DESCRIPTION_HEADER *Table; UINTN SectionInstance; UINTN TableSize; Status = EFI_SUCCESS; SectionInstance = 0; // // Scan all the EFI raw section instances in FV to find the NVDIMM root // device SSDT. // while (TRUE) { Status = GetSectionFromFv ( &gEfiCallerIdGuid, EFI_SECTION_RAW, SectionInstance, (VOID **) &Table, &TableSize ); if (EFI_ERROR (Status)) { break; } if (Table->OemTableId == SIGNATURE_64 ('R', 'a', 'm', 'D', 'i', 's', 'k', ' ')) { Status = mAcpiTableProtocol->InstallAcpiTable ( mAcpiTableProtocol, Table, TableSize, &mRamDiskSsdtTableKey ); ASSERT_EFI_ERROR (Status); if (!EFI_ERROR (Status)) { mRamDiskSsdtTableKeyValid = TRUE; } FreePool (Table); return Status; } else { FreePool (Table); SectionInstance++; } } return Status; } /** Publish the RAM disk NVDIMM Firmware Interface Table (NFIT) to the ACPI table. @param[in] PrivateData Points to RAM disk private data. @retval EFI_SUCCESS The RAM disk NFIT has been published. @retval others The RAM disk NFIT has not been published. **/ EFI_STATUS RamDiskPublishNfit ( IN RAM_DISK_PRIVATE_DATA *PrivateData ) { EFI_STATUS Status; EFI_MEMORY_DESCRIPTOR *MemoryMap; EFI_MEMORY_DESCRIPTOR *MemoryMapEntry; EFI_MEMORY_DESCRIPTOR *MemoryMapEnd; UINTN TableIndex; VOID *TableHeader; EFI_ACPI_TABLE_VERSION TableVersion; UINTN TableKey; EFI_ACPI_DESCRIPTION_HEADER *NfitHeader; EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE *SpaRange; VOID *Nfit; UINT32 NfitLen; UINTN MemoryMapSize; UINTN MapKey; UINTN DescriptorSize; UINT32 DescriptorVersion; UINT64 CurrentData; UINT8 Checksum; BOOLEAN MemoryFound; // // Get the EFI memory map. // MemoryMapSize = 0; MemoryMap = NULL; MemoryFound = FALSE; Status = gBS->GetMemoryMap ( &MemoryMapSize, MemoryMap, &MapKey, &DescriptorSize, &DescriptorVersion ); ASSERT (Status == EFI_BUFFER_TOO_SMALL); do { MemoryMap = (EFI_MEMORY_DESCRIPTOR *) AllocatePool (MemoryMapSize); ASSERT (MemoryMap != NULL); Status = gBS->GetMemoryMap ( &MemoryMapSize, MemoryMap, &MapKey, &DescriptorSize, &DescriptorVersion ); if (EFI_ERROR (Status)) { FreePool (MemoryMap); } } while (Status == EFI_BUFFER_TOO_SMALL); ASSERT_EFI_ERROR (Status); MemoryMapEntry = MemoryMap; MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + MemoryMapSize); while ((UINTN) MemoryMapEntry < (UINTN) MemoryMapEnd) { if ((MemoryMapEntry->Type == EfiReservedMemoryType) && (MemoryMapEntry->PhysicalStart <= PrivateData->StartingAddr) && (MemoryMapEntry->PhysicalStart + MultU64x32 (MemoryMapEntry->NumberOfPages, EFI_PAGE_SIZE) >= PrivateData->StartingAddr + PrivateData->Size)) { MemoryFound = TRUE; DEBUG (( EFI_D_INFO, "RamDiskPublishNfit: RAM disk with reserved meomry type, will publish to NFIT.\n" )); break; } MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize); } FreePool (MemoryMap); if (!MemoryFound) { return EFI_NOT_FOUND; } // // Determine whether there is a NFIT already in the ACPI table. // Status = EFI_SUCCESS; TableIndex = 0; TableKey = 0; TableHeader = NULL; while (!EFI_ERROR (Status)) { Status = mAcpiSdtProtocol->GetAcpiTable ( TableIndex, (EFI_ACPI_SDT_HEADER **)&TableHeader, &TableVersion, &TableKey ); if (!EFI_ERROR (Status)) { TableIndex++; if (((EFI_ACPI_SDT_HEADER *)TableHeader)->Signature == EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE_STRUCTURE_SIGNATURE) { break; } } } if (!EFI_ERROR (Status)) { // // A NFIT is already in the ACPI table. // DEBUG (( EFI_D_INFO, "RamDiskPublishNfit: A NFIT is already exist in the ACPI Table.\n" )); NfitHeader = (EFI_ACPI_DESCRIPTION_HEADER *)TableHeader; NfitLen = NfitHeader->Length + sizeof (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE); Nfit = AllocateZeroPool (NfitLen); if (Nfit == NULL) { return EFI_OUT_OF_RESOURCES; } CopyMem (Nfit, TableHeader, NfitHeader->Length); // // Update the NFIT head pointer. // NfitHeader = (EFI_ACPI_DESCRIPTION_HEADER *)Nfit; // // Uninstall the origin NFIT from the ACPI table. // Status = mAcpiTableProtocol->UninstallAcpiTable ( mAcpiTableProtocol, TableKey ); ASSERT_EFI_ERROR (Status); if (EFI_ERROR (Status)) { FreePool (Nfit); return Status; } // // Append the System Physical Address (SPA) Range Structure at the end // of the origin NFIT. // SpaRange = (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE *) ((UINT8 *)Nfit + NfitHeader->Length); // // Update the length field of the NFIT // NfitHeader->Length = NfitLen; // // The checksum will be updated after the new contents are appended. // NfitHeader->Checksum = 0; } else { // // Assumption is made that if no NFIT is in the ACPI table, there is no // NVDIMM root device in the \SB scope. // Therefore, a NVDIMM root device will be reported via Secondary System // Description Table (SSDT). // Status = RamDiskPublishSsdt (); if (EFI_ERROR (Status)) { return Status; } // // No NFIT is in the ACPI table, we will create one here. // DEBUG (( EFI_D_INFO, "RamDiskPublishNfit: No NFIT is in the ACPI Table, will create one.\n" )); NfitLen = sizeof (EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE) + sizeof (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE); Nfit = AllocateZeroPool (NfitLen); if (Nfit == NULL) { return EFI_OUT_OF_RESOURCES; } SpaRange = (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE *) ((UINT8 *)Nfit + sizeof (EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE)); NfitHeader = (EFI_ACPI_DESCRIPTION_HEADER *)Nfit; NfitHeader->Signature = EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE_STRUCTURE_SIGNATURE; NfitHeader->Length = NfitLen; NfitHeader->Revision = EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE_REVISION; NfitHeader->Checksum = 0; NfitHeader->OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision); NfitHeader->CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId); NfitHeader->CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision); CurrentData = PcdGet64 (PcdAcpiDefaultOemTableId); CopyMem (NfitHeader->OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (NfitHeader->OemId)); CopyMem (&NfitHeader->OemTableId, &CurrentData, sizeof (UINT64)); } // // Fill in the content of the SPA Range Structure. // SpaRange->Type = EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE_TYPE; SpaRange->Length = sizeof (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE); SpaRange->SystemPhysicalAddressRangeBase = PrivateData->StartingAddr; SpaRange->SystemPhysicalAddressRangeLength = PrivateData->Size; CopyGuid (&SpaRange->AddressRangeTypeGUID, &PrivateData->TypeGuid); Checksum = CalculateCheckSum8((UINT8 *)Nfit, NfitHeader->Length); NfitHeader->Checksum = Checksum; // // Publish the NFIT to the ACPI table. // Note, since the NFIT might be modified by other driver, therefore, we // do not track the returning TableKey from the InstallAcpiTable(). // Status = mAcpiTableProtocol->InstallAcpiTable ( mAcpiTableProtocol, Nfit, NfitHeader->Length, &TableKey ); ASSERT_EFI_ERROR (Status); FreePool (Nfit); if (EFI_ERROR (Status)) { return Status; } PrivateData->InNfit = TRUE; return EFI_SUCCESS; } /** Unpublish the RAM disk NVDIMM Firmware Interface Table (NFIT) from the ACPI table. @param[in] PrivateData Points to RAM disk private data. @retval EFI_SUCCESS The RAM disk NFIT has been unpublished. @retval others The RAM disk NFIT has not been unpublished. **/ EFI_STATUS RamDiskUnpublishNfit ( IN RAM_DISK_PRIVATE_DATA *PrivateData ) { EFI_STATUS Status; UINTN TableIndex; VOID *TableHeader; EFI_ACPI_TABLE_VERSION TableVersion; UINTN TableKey; EFI_ACPI_DESCRIPTION_HEADER *NewNfitHeader; EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE *SpaRange; VOID *NewNfit; VOID *NewNfitPtr; EFI_ACPI_6_1_NFIT_STRUCTURE_HEADER *NfitStructHeader; UINT32 NewNfitLen; UINT32 RemainLen; UINT8 Checksum; // // Find the NFIT in the ACPI table. // Status = EFI_SUCCESS; TableIndex = 0; TableKey = 0; TableHeader = NULL; while (!EFI_ERROR (Status)) { Status = mAcpiSdtProtocol->GetAcpiTable ( TableIndex, (EFI_ACPI_SDT_HEADER **)&TableHeader, &TableVersion, &TableKey ); if (!EFI_ERROR (Status)) { TableIndex++; if (((EFI_ACPI_SDT_HEADER *)TableHeader)->Signature == EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE_STRUCTURE_SIGNATURE) { break; } } } if (EFI_ERROR (Status)) { // // No NFIT is found in the ACPI table. // return EFI_NOT_FOUND; } NewNfitLen = ((EFI_ACPI_DESCRIPTION_HEADER *)TableHeader)->Length - sizeof (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE); // // After removing this RAM disk from the NFIT, if no other structure is in // the NFIT, we just remove the NFIT and the SSDT which is used to report // the NVDIMM root device. // if (NewNfitLen == sizeof (EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE)) { // // Remove the NFIT. // Status = mAcpiTableProtocol->UninstallAcpiTable ( mAcpiTableProtocol, TableKey ); ASSERT_EFI_ERROR (Status); if (EFI_ERROR (Status)) { return Status; } // // Remove the SSDT which is used by RamDiskDxe driver to report the NVDIMM // root device. // We do not care the return status since this SSDT might already be // uninstalled by other drivers to update the information of the NVDIMM // root device. // if (mRamDiskSsdtTableKeyValid) { mRamDiskSsdtTableKeyValid = FALSE; mAcpiTableProtocol->UninstallAcpiTable ( mAcpiTableProtocol, mRamDiskSsdtTableKey ); } return EFI_SUCCESS; } NewNfit = AllocateZeroPool (NewNfitLen); if (NewNfit == NULL) { return EFI_OUT_OF_RESOURCES; } // // Get a copy of the old NFIT header content. // CopyMem (NewNfit, TableHeader, sizeof (EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE)); NewNfitHeader = (EFI_ACPI_DESCRIPTION_HEADER *)NewNfit; NewNfitHeader->Length = NewNfitLen; NewNfitHeader->Checksum = 0; // // Copy the content of required NFIT structures. // NewNfitPtr = (UINT8 *)NewNfit + sizeof (EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE); RemainLen = NewNfitLen - sizeof (EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE); NfitStructHeader = (EFI_ACPI_6_1_NFIT_STRUCTURE_HEADER *) ((UINT8 *)TableHeader + sizeof (EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE)); while (RemainLen > 0) { if ((NfitStructHeader->Type == EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE_TYPE) && (NfitStructHeader->Length == sizeof (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE))) { SpaRange = (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE *)NfitStructHeader; if ((SpaRange->SystemPhysicalAddressRangeBase == PrivateData->StartingAddr) && (SpaRange->SystemPhysicalAddressRangeLength == PrivateData->Size) && (CompareGuid (&SpaRange->AddressRangeTypeGUID, &PrivateData->TypeGuid))) { // // Skip the SPA Range Structure for the RAM disk to be unpublished // from NFIT. // NfitStructHeader = (EFI_ACPI_6_1_NFIT_STRUCTURE_HEADER *) ((UINT8 *)NfitStructHeader + NfitStructHeader->Length); continue; } } // // Copy the content of origin NFIT. // CopyMem (NewNfitPtr, NfitStructHeader, NfitStructHeader->Length); NewNfitPtr = (UINT8 *)NewNfitPtr + NfitStructHeader->Length; // // Move to the header of next NFIT structure. // RemainLen -= NfitStructHeader->Length; NfitStructHeader = (EFI_ACPI_6_1_NFIT_STRUCTURE_HEADER *) ((UINT8 *)NfitStructHeader + NfitStructHeader->Length); } Checksum = CalculateCheckSum8((UINT8 *)NewNfit, NewNfitHeader->Length); NewNfitHeader->Checksum = Checksum; Status = mAcpiTableProtocol->UninstallAcpiTable ( mAcpiTableProtocol, TableKey ); ASSERT_EFI_ERROR (Status); if (EFI_ERROR (Status)) { FreePool (NewNfit); return Status; } // // Publish the NFIT to the ACPI table. // Note, since the NFIT might be modified by other driver, therefore, we // do not track the returning TableKey from the InstallAcpiTable(). // Status = mAcpiTableProtocol->InstallAcpiTable ( mAcpiTableProtocol, NewNfit, NewNfitLen, &TableKey ); ASSERT_EFI_ERROR (Status); FreePool (NewNfit); if (EFI_ERROR (Status)) { return Status; } return EFI_SUCCESS; } /** Register a RAM disk with specified address, size and type. @param[in] RamDiskBase The base address of registered RAM disk. @param[in] RamDiskSize The size of registered RAM disk. @param[in] RamDiskType The type of registered RAM disk. The GUID can be any of the values defined in section 9.3.6.9, or a vendor defined GUID. @param[in] ParentDevicePath Pointer to the parent device path. If there is no parent device path then ParentDevicePath is NULL. @param[out] DevicePath On return, points to a pointer to the device path of the RAM disk device. If ParentDevicePath is not NULL, the returned DevicePath is created by appending a RAM disk node to the parent device path. If ParentDevicePath is NULL, the returned DevicePath is a RAM disk device path without appending. This function is responsible for allocating the buffer DevicePath with the boot service AllocatePool(). @retval EFI_SUCCESS The RAM disk is registered successfully. @retval EFI_INVALID_PARAMETER DevicePath or RamDiskType is NULL. RamDiskSize is 0. @retval EFI_ALREADY_STARTED A Device Path Protocol instance to be created is already present in the handle database. @retval EFI_OUT_OF_RESOURCES The RAM disk register operation fails due to resource limitation. **/ EFI_STATUS EFIAPI RamDiskRegister ( IN UINT64 RamDiskBase, IN UINT64 RamDiskSize, IN EFI_GUID *RamDiskType, IN EFI_DEVICE_PATH *ParentDevicePath OPTIONAL, OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath ) { EFI_STATUS Status; RAM_DISK_PRIVATE_DATA *PrivateData; RAM_DISK_PRIVATE_DATA *RegisteredPrivateData; MEDIA_RAM_DISK_DEVICE_PATH *RamDiskDevNode; UINTN DevicePathSize; LIST_ENTRY *Entry; if ((0 == RamDiskSize) || (NULL == RamDiskType) || (NULL == DevicePath)) { return EFI_INVALID_PARAMETER; } // // Add check to prevent data read across the memory boundary // if (RamDiskBase + RamDiskSize > ((UINTN) -1) - RAM_DISK_BLOCK_SIZE + 1) { return EFI_INVALID_PARAMETER; } RamDiskDevNode = NULL; // // Create a new RAM disk instance and initialize its private data // PrivateData = AllocateCopyPool ( sizeof (RAM_DISK_PRIVATE_DATA), &mRamDiskPrivateDataTemplate ); if (NULL == PrivateData) { return EFI_OUT_OF_RESOURCES; } PrivateData->StartingAddr = RamDiskBase; PrivateData->Size = RamDiskSize; CopyGuid (&PrivateData->TypeGuid, RamDiskType); InitializeListHead (&PrivateData->ThisInstance); // // Generate device path information for the registered RAM disk // RamDiskDevNode = AllocateCopyPool ( sizeof (MEDIA_RAM_DISK_DEVICE_PATH), &mRamDiskDeviceNodeTemplate ); if (NULL == RamDiskDevNode) { Status = EFI_OUT_OF_RESOURCES; goto ErrorExit; } RamDiskInitDeviceNode (PrivateData, RamDiskDevNode); *DevicePath = AppendDevicePathNode ( ParentDevicePath, (EFI_DEVICE_PATH_PROTOCOL *) RamDiskDevNode ); if (NULL == *DevicePath) { Status = EFI_OUT_OF_RESOURCES; goto ErrorExit; } PrivateData->DevicePath = *DevicePath; // // Check whether the created device path is already present in the handle // database // if (!IsListEmpty(&RegisteredRamDisks)) { DevicePathSize = GetDevicePathSize (PrivateData->DevicePath); EFI_LIST_FOR_EACH (Entry, &RegisteredRamDisks) { RegisteredPrivateData = RAM_DISK_PRIVATE_FROM_THIS (Entry); if (DevicePathSize == GetDevicePathSize (RegisteredPrivateData->DevicePath)) { // // Compare device path // if ((CompareMem ( PrivateData->DevicePath, RegisteredPrivateData->DevicePath, DevicePathSize)) == 0) { *DevicePath = NULL; Status = EFI_ALREADY_STARTED; goto ErrorExit; } } } } // // Fill Block IO protocol informations for the RAM disk // RamDiskInitBlockIo (PrivateData); // // Install EFI_DEVICE_PATH_PROTOCOL & EFI_BLOCK_IO(2)_PROTOCOL on a new // handle // Status = gBS->InstallMultipleProtocolInterfaces ( &PrivateData->Handle, &gEfiBlockIoProtocolGuid, &PrivateData->BlockIo, &gEfiBlockIo2ProtocolGuid, &PrivateData->BlockIo2, &gEfiDevicePathProtocolGuid, PrivateData->DevicePath, NULL ); if (EFI_ERROR (Status)) { goto ErrorExit; } // // Insert the newly created one to the registered RAM disk list // InsertTailList (&RegisteredRamDisks, &PrivateData->ThisInstance); gBS->ConnectController (PrivateData->Handle, NULL, NULL, TRUE); FreePool (RamDiskDevNode); if ((mAcpiTableProtocol != NULL) && (mAcpiSdtProtocol != NULL)) { RamDiskPublishNfit (PrivateData); } return EFI_SUCCESS; ErrorExit: if (RamDiskDevNode != NULL) { FreePool (RamDiskDevNode); } if (PrivateData != NULL) { if (PrivateData->DevicePath) { FreePool (PrivateData->DevicePath); } FreePool (PrivateData); } return Status; } /** Unregister a RAM disk specified by DevicePath. @param[in] DevicePath A pointer to the device path that describes a RAM Disk device. @retval EFI_SUCCESS The RAM disk is unregistered successfully. @retval EFI_INVALID_PARAMETER DevicePath is NULL. @retval EFI_UNSUPPORTED The device specified by DevicePath is not a valid ramdisk device path and not supported by the driver. @retval EFI_NOT_FOUND The RAM disk pointed by DevicePath doesn't exist. **/ EFI_STATUS EFIAPI RamDiskUnregister ( IN EFI_DEVICE_PATH_PROTOCOL *DevicePath ) { LIST_ENTRY *Entry; LIST_ENTRY *NextEntry; BOOLEAN Found; UINT64 StartingAddr; UINT64 EndingAddr; EFI_DEVICE_PATH_PROTOCOL *Header; MEDIA_RAM_DISK_DEVICE_PATH *RamDiskDevNode; RAM_DISK_PRIVATE_DATA *PrivateData; if (NULL == DevicePath) { return EFI_INVALID_PARAMETER; } // // Locate the RAM disk device node. // RamDiskDevNode = NULL; Header = DevicePath; do { // // Test if the current device node is a RAM disk. // if ((MEDIA_DEVICE_PATH == Header->Type) && (MEDIA_RAM_DISK_DP == Header->SubType)) { RamDiskDevNode = (MEDIA_RAM_DISK_DEVICE_PATH *) Header; break; } Header = NextDevicePathNode (Header); } while ((Header->Type != END_DEVICE_PATH_TYPE)); if (NULL == RamDiskDevNode) { return EFI_UNSUPPORTED; } Found = FALSE; StartingAddr = ReadUnaligned64 ((UINT64 *) &(RamDiskDevNode->StartingAddr[0])); EndingAddr = ReadUnaligned64 ((UINT64 *) &(RamDiskDevNode->EndingAddr[0])); if (!IsListEmpty(&RegisteredRamDisks)) { EFI_LIST_FOR_EACH_SAFE (Entry, NextEntry, &RegisteredRamDisks) { PrivateData = RAM_DISK_PRIVATE_FROM_THIS (Entry); // // Unregister the RAM disk given by its starting address, ending address // and type guid. // if ((StartingAddr == PrivateData->StartingAddr) && (EndingAddr == PrivateData->StartingAddr + PrivateData->Size - 1) && (CompareGuid (&RamDiskDevNode->TypeGuid, &PrivateData->TypeGuid))) { // // Remove the content for this RAM disk in NFIT. // if (PrivateData->InNfit) { RamDiskUnpublishNfit (PrivateData); } // // Uninstall the EFI_DEVICE_PATH_PROTOCOL & EFI_BLOCK_IO(2)_PROTOCOL // gBS->UninstallMultipleProtocolInterfaces ( PrivateData->Handle, &gEfiBlockIoProtocolGuid, &PrivateData->BlockIo, &gEfiBlockIo2ProtocolGuid, &PrivateData->BlockIo2, &gEfiDevicePathProtocolGuid, (EFI_DEVICE_PATH_PROTOCOL *) PrivateData->DevicePath, NULL ); RemoveEntryList (&PrivateData->ThisInstance); if (RamDiskCreateHii == PrivateData->CreateMethod) { // // If a RAM disk is created within HII, then the RamDiskDxe driver // driver is responsible for freeing the allocated memory for the // RAM disk. // FreePool ((VOID *)(UINTN) PrivateData->StartingAddr); } FreePool (PrivateData->DevicePath); FreePool (PrivateData); Found = TRUE; break; } } } if (TRUE == Found) { return EFI_SUCCESS; } else { return EFI_NOT_FOUND; } } �����������������������������������������������������������������������������������refind-0.11.4/filesystems/RamDiskDxe/RamDiskBlockIo.c�����������������������������������������������0000664�0001750�0001750�00000040433�13113047761�022624� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/** @file Produce EFI_BLOCK_IO_PROTOCOL on a RAM disk device. Copyright (c) 2016, Intel Corporation. All rights reserved.<BR> This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ #include "RamDiskImpl.h" // // The EFI_BLOCK_IO_PROTOCOL instances that is installed onto the handle // for newly registered RAM disks // EFI_BLOCK_IO_PROTOCOL mRamDiskBlockIoTemplate = { EFI_BLOCK_IO_PROTOCOL_REVISION, (EFI_BLOCK_IO_MEDIA *) 0, RamDiskBlkIoReset, RamDiskBlkIoReadBlocks, RamDiskBlkIoWriteBlocks, RamDiskBlkIoFlushBlocks }; // // The EFI_BLOCK_IO_PROTOCOL2 instances that is installed onto the handle // for newly registered RAM disks // EFI_BLOCK_IO2_PROTOCOL mRamDiskBlockIo2Template = { (EFI_BLOCK_IO_MEDIA *) 0, RamDiskBlkIo2Reset, RamDiskBlkIo2ReadBlocksEx, RamDiskBlkIo2WriteBlocksEx, RamDiskBlkIo2FlushBlocksEx }; /** Initialize the BlockIO & BlockIO2 protocol of a RAM disk device. @param[in] PrivateData Points to RAM disk private data. **/ VOID RamDiskInitBlockIo ( IN RAM_DISK_PRIVATE_DATA *PrivateData ) { EFI_BLOCK_IO_PROTOCOL *BlockIo; EFI_BLOCK_IO2_PROTOCOL *BlockIo2; EFI_BLOCK_IO_MEDIA *Media; BlockIo = &PrivateData->BlockIo; BlockIo2 = &PrivateData->BlockIo2; Media = &PrivateData->Media; CopyMem (BlockIo, &mRamDiskBlockIoTemplate, sizeof (EFI_BLOCK_IO_PROTOCOL)); CopyMem (BlockIo2, &mRamDiskBlockIo2Template, sizeof (EFI_BLOCK_IO2_PROTOCOL)); BlockIo->Media = Media; BlockIo2->Media = Media; Media->RemovableMedia = FALSE; Media->MediaPresent = TRUE; Media->LogicalPartition = FALSE; Media->ReadOnly = FALSE; Media->WriteCaching = FALSE; Media->BlockSize = RAM_DISK_BLOCK_SIZE; Media->LastBlock = DivU64x32 ( PrivateData->Size + RAM_DISK_BLOCK_SIZE - 1, RAM_DISK_BLOCK_SIZE ) - 1; } /** Reset the Block Device. @param This Indicates a pointer to the calling context. @param ExtendedVerification Driver may perform diagnostics on reset. @retval EFI_SUCCESS The device was reset. @retval EFI_DEVICE_ERROR The device is not functioning properly and could not be reset. **/ EFI_STATUS EFIAPI RamDiskBlkIoReset ( IN EFI_BLOCK_IO_PROTOCOL *This, IN BOOLEAN ExtendedVerification ) { return EFI_SUCCESS; } /** Read BufferSize bytes from Lba into Buffer. @param[in] This Indicates a pointer to the calling context. @param[in] MediaId Id of the media, changes every time the media is replaced. @param[in] Lba The starting Logical Block Address to read from. @param[in] BufferSize Size of Buffer, must be a multiple of device block size. @param[out] Buffer A pointer to the destination buffer for the data. The caller is responsible for either having implicit or explicit ownership of the buffer. @retval EFI_SUCCESS The data was read correctly from the device. @retval EFI_DEVICE_ERROR The device reported an error while performing the read. @retval EFI_NO_MEDIA There is no media in the device. @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device. @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device. @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid, or the buffer is not on proper alignment. **/ EFI_STATUS EFIAPI RamDiskBlkIoReadBlocks ( IN EFI_BLOCK_IO_PROTOCOL *This, IN UINT32 MediaId, IN EFI_LBA Lba, IN UINTN BufferSize, OUT VOID *Buffer ) { RAM_DISK_PRIVATE_DATA *PrivateData; UINTN NumberOfBlocks; if (Buffer == NULL) { return EFI_INVALID_PARAMETER; } if (BufferSize == 0) { return EFI_SUCCESS; } PrivateData = RAM_DISK_PRIVATE_FROM_BLKIO (This); if (MediaId != PrivateData->Media.MediaId) { return EFI_MEDIA_CHANGED; } if ((BufferSize % PrivateData->Media.BlockSize) != 0) { return EFI_BAD_BUFFER_SIZE; } if (Lba > PrivateData->Media.LastBlock) { return EFI_INVALID_PARAMETER; } NumberOfBlocks = BufferSize / PrivateData->Media.BlockSize; if ((Lba + NumberOfBlocks - 1) > PrivateData->Media.LastBlock) { return EFI_INVALID_PARAMETER; } CopyMem ( Buffer, (VOID *)(UINTN)(PrivateData->StartingAddr + MultU64x32 (Lba, PrivateData->Media.BlockSize)), BufferSize ); return EFI_SUCCESS; } /** Write BufferSize bytes from Lba into Buffer. @param[in] This Indicates a pointer to the calling context. @param[in] MediaId The media ID that the write request is for. @param[in] Lba The starting logical block address to be written. The caller is responsible for writing to only legitimate locations. @param[in] BufferSize Size of Buffer, must be a multiple of device block size. @param[in] Buffer A pointer to the source buffer for the data. @retval EFI_SUCCESS The data was written correctly to the device. @retval EFI_WRITE_PROTECTED The device can not be written to. @retval EFI_DEVICE_ERROR The device reported an error while performing the write. @retval EFI_NO_MEDIA There is no media in the device. @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device. @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device. @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid, or the buffer is not on proper alignment. **/ EFI_STATUS EFIAPI RamDiskBlkIoWriteBlocks ( IN EFI_BLOCK_IO_PROTOCOL *This, IN UINT32 MediaId, IN EFI_LBA Lba, IN UINTN BufferSize, IN VOID *Buffer ) { RAM_DISK_PRIVATE_DATA *PrivateData; UINTN NumberOfBlocks; if (Buffer == NULL) { return EFI_INVALID_PARAMETER; } if (BufferSize == 0) { return EFI_SUCCESS; } PrivateData = RAM_DISK_PRIVATE_FROM_BLKIO (This); if (MediaId != PrivateData->Media.MediaId) { return EFI_MEDIA_CHANGED; } if (TRUE == PrivateData->Media.ReadOnly) { return EFI_WRITE_PROTECTED; } if ((BufferSize % PrivateData->Media.BlockSize) != 0) { return EFI_BAD_BUFFER_SIZE; } if (Lba > PrivateData->Media.LastBlock) { return EFI_INVALID_PARAMETER; } NumberOfBlocks = BufferSize / PrivateData->Media.BlockSize; if ((Lba + NumberOfBlocks - 1) > PrivateData->Media.LastBlock) { return EFI_INVALID_PARAMETER; } CopyMem ( (VOID *)(UINTN)(PrivateData->StartingAddr + MultU64x32 (Lba, PrivateData->Media.BlockSize)), Buffer, BufferSize ); return EFI_SUCCESS; } /** Flush the Block Device. @param[in] This Indicates a pointer to the calling context. @retval EFI_SUCCESS All outstanding data was written to the device. @retval EFI_DEVICE_ERROR The device reported an error while writting back the data @retval EFI_NO_MEDIA There is no media in the device. **/ EFI_STATUS EFIAPI RamDiskBlkIoFlushBlocks ( IN EFI_BLOCK_IO_PROTOCOL *This ) { return EFI_SUCCESS; } /** Resets the block device hardware. @param[in] This The pointer of EFI_BLOCK_IO2_PROTOCOL. @param[in] ExtendedVerification The flag about if extend verificate. @retval EFI_SUCCESS The device was reset. @retval EFI_DEVICE_ERROR The block device is not functioning correctly and could not be reset. **/ EFI_STATUS EFIAPI RamDiskBlkIo2Reset ( IN EFI_BLOCK_IO2_PROTOCOL *This, IN BOOLEAN ExtendedVerification ) { return EFI_SUCCESS; } /** Reads the requested number of blocks from the device. @param[in] This Indicates a pointer to the calling context. @param[in] MediaId The media ID that the read request is for. @param[in] Lba The starting logical block address to read from on the device. @param[in, out] Token A pointer to the token associated with the transaction. @param[in] BufferSize The size of the Buffer in bytes. This must be a multiple of the intrinsic block size of the device. @param[out] Buffer A pointer to the destination buffer for the data. The caller is responsible for either having implicit or explicit ownership of the buffer. @retval EFI_SUCCESS The read request was queued if Token->Event is not NULL. The data was read correctly from the device if the Token->Event is NULL. @retval EFI_DEVICE_ERROR The device reported an error while attempting to perform the read operation. @retval EFI_NO_MEDIA There is no media in the device. @retval EFI_MEDIA_CHANGED The MediaId is not for the current media. @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the intrinsic block size of the device. @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid, or the buffer is not on proper alignment. @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. **/ EFI_STATUS EFIAPI RamDiskBlkIo2ReadBlocksEx ( IN EFI_BLOCK_IO2_PROTOCOL *This, IN UINT32 MediaId, IN EFI_LBA Lba, IN OUT EFI_BLOCK_IO2_TOKEN *Token, IN UINTN BufferSize, OUT VOID *Buffer ) { RAM_DISK_PRIVATE_DATA *PrivateData; EFI_STATUS Status; PrivateData = RAM_DISK_PRIVATE_FROM_BLKIO2 (This); Status = RamDiskBlkIoReadBlocks ( &PrivateData->BlockIo, MediaId, Lba, BufferSize, Buffer ); if (EFI_ERROR (Status)) { return Status; } // // If caller's event is given, signal it after the memory read completes. // if ((Token != NULL) && (Token->Event != NULL)) { Token->TransactionStatus = EFI_SUCCESS; gBS->SignalEvent (Token->Event); } return EFI_SUCCESS; } /** Writes a specified number of blocks to the device. @param[in] This Indicates a pointer to the calling context. @param[in] MediaId The media ID that the write request is for. @param[in] Lba The starting logical block address to be written. The caller is responsible for writing to only legitimate locations. @param[in, out] Token A pointer to the token associated with the transaction. @param[in] BufferSize The size in bytes of Buffer. This must be a multiple of the intrinsic block size of the device. @param[in] Buffer A pointer to the source buffer for the data. @retval EFI_SUCCESS The write request was queued if Event is not NULL. The data was written correctly to the device if the Event is NULL. @retval EFI_WRITE_PROTECTED The device cannot be written to. @retval EFI_NO_MEDIA There is no media in the device. @retval EFI_MEDIA_CHANGED The MediaId is not for the current media. @retval EFI_DEVICE_ERROR The device reported an error while attempting to perform the write operation. @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the intrinsic block size of the device. @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid, or the buffer is not on proper alignment. @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. **/ EFI_STATUS EFIAPI RamDiskBlkIo2WriteBlocksEx ( IN EFI_BLOCK_IO2_PROTOCOL *This, IN UINT32 MediaId, IN EFI_LBA Lba, IN OUT EFI_BLOCK_IO2_TOKEN *Token, IN UINTN BufferSize, IN VOID *Buffer ) { RAM_DISK_PRIVATE_DATA *PrivateData; EFI_STATUS Status; PrivateData = RAM_DISK_PRIVATE_FROM_BLKIO2 (This); Status = RamDiskBlkIoWriteBlocks ( &PrivateData->BlockIo, MediaId, Lba, BufferSize, Buffer ); if (EFI_ERROR (Status)) { return Status; } // // If caller's event is given, signal it after the memory write completes. // if ((Token != NULL) && (Token->Event != NULL)) { Token->TransactionStatus = EFI_SUCCESS; gBS->SignalEvent (Token->Event); } return EFI_SUCCESS; } /** Flushes all modified data to a physical block device. @param[in] This Indicates a pointer to the calling context. @param[in, out] Token A pointer to the token associated with the transaction. @retval EFI_SUCCESS The flush request was queued if Event is not NULL. All outstanding data was written correctly to the device if the Event is NULL. @retval EFI_DEVICE_ERROR The device reported an error while attempting to write data. @retval EFI_WRITE_PROTECTED The device cannot be written to. @retval EFI_NO_MEDIA There is no media in the device. @retval EFI_MEDIA_CHANGED The MediaId is not for the current media. @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. **/ EFI_STATUS EFIAPI RamDiskBlkIo2FlushBlocksEx ( IN EFI_BLOCK_IO2_PROTOCOL *This, IN OUT EFI_BLOCK_IO2_TOKEN *Token ) { RAM_DISK_PRIVATE_DATA *PrivateData; PrivateData = RAM_DISK_PRIVATE_FROM_BLKIO2 (This); if (TRUE == PrivateData->Media.ReadOnly) { return EFI_WRITE_PROTECTED; } // // If caller's event is given, signal it directly. // if ((Token != NULL) && (Token->Event != NULL)) { Token->TransactionStatus = EFI_SUCCESS; gBS->SignalEvent (Token->Event); } return EFI_SUCCESS; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/RamDiskDxe/RamDiskDxe.inf�������������������������������������������������0000664�0001750�0001750�00000006141�13113047761�022352� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������## @file # Produces EFI_RAM_DISK_PROTOCOL and provides the capability to # create/remove RAM disks in a setup browser. # # Copyright (c) 2016, Intel Corporation. All rights reserved.<BR> # This program and the accompanying materials # are licensed and made available under the terms and conditions of the BSD License # which accompanies this distribution. The full text of the license may be found at # http://opensource.org/licenses/bsd-license.php # # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. # ## [Defines] INF_VERSION = 0x00010005 BASE_NAME = RamDiskDxe MODULE_UNI_FILE = RamDiskDxe.uni FILE_GUID = 28A03FF4-12B3-4305-A417-BB1A4F94081E MODULE_TYPE = DXE_DRIVER VERSION_STRING = 1.0 ENTRY_POINT = RamDiskDxeEntryPoint UNLOAD_IMAGE = RamDiskDxeUnload # # The following information is for reference only and not required by the build tools. # # VALID_ARCHITECTURES = IA32 X64 ARM AARCH64 # [Sources] RamDiskDriver.c RamDiskImpl.c RamDiskBlockIo.c RamDiskProtocol.c RamDiskFileExplorer.c RamDiskImpl.h RamDiskHii.vfr RamDiskHiiStrings.uni RamDiskNVData.h RamDisk.asl [Packages] MdePkg/MdePkg.dec MdeModulePkg/MdeModulePkg.dec [LibraryClasses] BaseLib BaseMemoryLib DebugLib UefiLib UefiDriverEntryPoint UefiBootServicesTableLib UefiHiiServicesLib MemoryAllocationLib HiiLib FileExplorerLib DevicePathLib PrintLib PcdLib DxeServicesLib [Guids] gEfiIfrTianoGuid ## PRODUCES ## GUID # HII opcode ## PRODUCES ## HII ## CONSUMES ## HII gRamDiskFormSetGuid gEfiVirtualDiskGuid ## SOMETIMES_CONSUMES ## GUID gEfiFileInfoGuid ## SOMETIMES_CONSUMES ## GUID # Indicate the information type [Protocols] gEfiRamDiskProtocolGuid ## PRODUCES gEfiHiiConfigAccessProtocolGuid ## PRODUCES gEfiDevicePathProtocolGuid ## PRODUCES gEfiBlockIoProtocolGuid ## PRODUCES gEfiBlockIo2ProtocolGuid ## PRODUCES gEfiSimpleFileSystemProtocolGuid ## SOMETIMES_CONSUMES gEfiAcpiTableProtocolGuid ## SOMETIMES_CONSUMES gEfiAcpiSdtProtocolGuid ## SOMETIMES_CONSUMES [Pcd] gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemId ## SOMETIMES_CONSUMES gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemTableId ## SOMETIMES_CONSUMES gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemRevision ## SOMETIMES_CONSUMES gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorId ## SOMETIMES_CONSUMES gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorRevision ## SOMETIMES_CONSUMES [Depex] gEfiHiiConfigRoutingProtocolGuid AND gEfiHiiDatabaseProtocolGuid �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/filesystems/Make.tiano����������������������������������������������������������������0000664�0001750�0001750�00000005531�13137426703�017604� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # filesystems/Make.tiano # Build control file for rEFInd's EFI filesystem drivers # # This program is licensed under the terms of the GNU GPL, version 3, # or (at your option) any later version. # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. include ../Make.common # Below file defines TARGET (RELEASE or DEBUG) and TOOL_CHAIN_TAG (GCC44, GCC45, or GCC46) #include $(TIANOBASE)/Conf/target.txt EFILIB = $(TIANOBASE)/Build/Mde/$(TARGET)_$(TOOL_CHAIN_TAG)/$(UC_ARCH)/MdePkg/Library ALL_EFILIBS = $(EFILIB)/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib/OUTPUT/BaseDebugPrintErrorLevelLib.lib \ $(EFILIB)/BasePrintLib/BasePrintLib/OUTPUT/BasePrintLib.lib \ $(EFILIB)/BasePcdLibNull/BasePcdLibNull/OUTPUT/BasePcdLibNull.lib \ $(EFILIB)/UefiDebugLibConOut/UefiDebugLibConOut/OUTPUT/UefiDebugLibConOut.lib \ $(EFILIB)/BaseLib/BaseLib/OUTPUT/BaseLib.lib \ $(EFILIB)/BaseMemoryLib/BaseMemoryLib/OUTPUT/BaseMemoryLib.lib \ $(EFILIB)/UefiBootServicesTableLib/UefiBootServicesTableLib/OUTPUT/UefiBootServicesTableLib.lib \ $(EFILIB)/UefiMemoryAllocationLib/UefiMemoryAllocationLib/OUTPUT/UefiMemoryAllocationLib.lib \ $(EFILIB)/UefiDevicePathLib/UefiDevicePathLib/OUTPUT/UefiDevicePathLib.lib \ $(EFILIB)/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib/OUTPUT/UefiRuntimeServicesTableLib.lib \ $(EFILIB)/UefiLib/UefiLib/OUTPUT/UefiLib.lib \ $(EFILIB)/UefiDriverEntryPoint/UefiDriverEntryPoint/OUTPUT/UefiDriverEntryPoint.lib ifeq ($(ARCH),aarch64) ALL_EFILIBS += $(EFILIB)/BaseStackCheckLib/BaseStackCheckLib/OUTPUT/BaseStackCheckLib.lib endif TIANO_INCLUDE_DIRS = -I $(TIANOBASE)/MdePkg \ -I $(TIANOBASE)/MdePkg/Include \ -I $(TIANOBASE)/MdePkg/Include/$(ARCHDIR) \ -I $(TIANOBASE)/EdkCompatibilityPkg/Foundation/Framework/Include \ -I $(TIANOBASE)/EdkCompatibilityPkg/Foundation/Library/Dxe/Include FSW_NAMES = fsw_efi fsw_core fsw_efi_lib fsw_lib AutoGen OBJS = $(FSW_NAMES:=.obj) #DRIVERNAME = ext2 BUILDME = $(DRIVERNAME)_$(FILENAME_CODE).efi ENTRYPOINT = _ModuleEntryPoint %.obj: %.c $(CC) $(ARCH_CFLAGS) $(CFLAGS) $(TIANO_INCLUDE_DIRS) \ -DFSTYPE=$(DRIVERNAME) -DNO_BUILTIN_VA_FUNCS \ -D__MAKEWITH_TIANO -c $< -o $@ ifneq (,$(filter %.efi,$(BUILDME))) DLL_TARGET = $(subst .efi,.dll,$(BUILDME)) all: $(BUILDME) $(DLL_TARGET): $(OBJS) fsw_$(DRIVERNAME).obj $(LD) -o $(DRIVERNAME)_$(FILENAME_CODE).dll $(TIANO_LDFLAGS) \ --start-group $(ALL_EFILIBS) $(OBJS) fsw_$(DRIVERNAME).obj --end-group $(BUILDME): $(DLL_TARGET) $(OBJCOPY) --strip-unneeded -R .eh_frame $(DLL_TARGET) $(GENFW) -e UEFI_DRIVER -o $(BUILDME) $(DLL_TARGET) mkdir -p ../drivers_$(FILENAME_CODE) cp $(BUILDME) ../drivers_$(FILENAME_CODE) endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/refind.conf-sample��������������������������������������������������������������������0000664�0001750�0001750�00000075422�13346217350�016725� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # refind.conf # Configuration file for the rEFInd boot menu # # Timeout in seconds for the main menu screen. Setting the timeout to 0 # disables automatic booting (i.e., no timeout). Setting it to -1 causes # an immediate boot to the default OS *UNLESS* a keypress is in the buffer # when rEFInd launches, in which case that keypress is interpreted as a # shortcut key. If no matching shortcut is found, rEFInd displays its # menu with no timeout. # timeout 20 # Normally, when the timeout period has passed, rEFInd boots the # default_selection. If the following option is uncommented, though, # rEFInd will instead attempt to shut down the computer. # CAUTION: MANY COMPUTERS WILL INSTEAD HANG OR REBOOT! Macs and more # recent UEFI-based PCs are most likely to work with this feature. # Default value is true # #shutdown_after_timeout # Whether to store rEFInd's rEFInd-specific variables in NVRAM (1, true, # or on) or in files in the "vars" subdirectory of rEFInd's directory on # disk (0, false, or off). Using NVRAM works well with most computers; # however, it increases wear on the motherboard's NVRAM, and if the EFI # is buggy or the NVRAM is old and worn out, it may not work at all. # Storing variables on disk is a viable alternative in such cases, or # if you want to minimize wear and tear on the NVRAM; however, it won't # work if rEFInd is stored on a filesystem that's read-only to the EFI # (such as an HFS+ volume), and it increases the risk of filesystem # damage. Note that this option affects ONLY rEFInd's own variables, # such as the PreviousBoot, HiddenTags, HiddenTools, and HiddenLegacy # variables. It does NOT affect Secure Boot or other non-rEFInd # variables. # Default is true # #use_nvram false # Screen saver timeout; the screen blanks after the specified number of # seconds with no keyboard input. The screen returns after most keypresses # (unfortunately, not including modifier keys such as Shift, Control, Alt, # or Option). Setting a value of "-1" causes rEFInd to start up with its # screen saver active. The default is 0, which disables the screen saver. # #screensaver 300 # Hide user interface elements for personal preference or to increase # security: # banner - the rEFInd title banner (built-in or loaded via "banner") # label - boot option text label in the menu # singleuser - remove the submenu options to boot macOS in single-user # or verbose modes; affects ONLY macOS # safemode - remove the submenu option to boot macOS in "safe mode" # hwtest - the submenu option to run Apple's hardware test # arrows - scroll arrows on the OS selection tag line # hints - brief command summary in the menu # editor - the options editor (+, F2, or Insert on boot options menu) # badges - device-type badges for boot options # all - all of the above # Default is none of these (all elements active) # #hideui singleuser #hideui all # Set the name of a subdirectory in which icons are stored. Icons must # have the same names they have in the standard directory. The directory # name is specified relative to the main rEFInd binary's directory. If # an icon can't be found in the specified directory, an attempt is made # to load it from the default directory; thus, you can replace just some # icons in your own directory and rely on the default for others. # Icon files may be in any supported format -- ICNS (*.icns), BMP (*.bmp), # PNG (*.png), or JPEG (*.jpg or *.jpeg); however, rEFInd's BMP and JPEG # implementations do not support transparency, which is highly desirable # in icons. # Default is "icons". # #icons_dir myicons #icons_dir icons/snowy # Use a custom title banner instead of the rEFInd icon and name. The file # path is relative to the directory where refind.efi is located. The color # in the top left corner of the image is used as the background color # for the menu screens. Currently uncompressed BMP images with color # depths of 24, 8, 4 or 1 bits are supported, as well as PNG and JPEG # images. (ICNS images can also be used, but ICNS has limitations that # make it a poor choice for this purpose.) PNG and JPEG support is # limited by the underlying libraries; some files, like progressive JPEGs, # will not work. # #banner hostname.bmp #banner mybanner.jpg #banner icons/snowy/banner-snowy.png # Specify how to handle banners that aren't exactly the same as the screen # size: # noscale - Crop if too big, show with border if too small # fillscreen - Fill the screen # Default is noscale # #banner_scale fillscreen # Icon sizes. All icons are square, so just one value is specified. The # big icons are used for OS selectors in the first row and the small # icons are used for tools on the second row. Drive-type badges are 1/4 # the size of the big icons. Legal values are 32 and above. If the icon # files do not hold icons of the proper size, the icons are scaled to # the specified size. The default values are 48 and 128 for small and # big icons, respectively. # #small_icon_size 96 #big_icon_size 256 # Custom images for the selection background. There is a big one (144 x 144) # for the OS icons, and a small one (64 x 64) for the function icons in the # second row. If only a small image is given, that one is also used for # the big icons by stretching it in the middle. If only a big one is given, # the built-in default will be used for the small icons. If an image other # than the optimal size is specified, it will be scaled in a way that may # be ugly. # # Like the banner option above, these options take a filename of an # uncompressed BMP, PNG, JPEG, or ICNS image file with a color depth of # 24, 8, 4, or 1 bits. The PNG or ICNS format is required if you need # transparency support (to let you "see through" to a full-screen banner). # #selection_big selection-big.bmp #selection_small selection-small.bmp # Set the font to be used for all textual displays in graphics mode. # For best results, the font must be a PNG file with alpha channel # transparency. It must contain ASCII characters 32-126 (space through # tilde), inclusive, plus a glyph to be displayed in place of characters # outside of this range, for a total of 96 glyphs. Only monospaced fonts # are supported. Fonts may be of any size, although large fonts can # produce display irregularities. # The default is rEFInd's built-in font, Luxi Mono Regular 12 point. # #font myfont.png # Use text mode only. When enabled, this option forces rEFInd into text mode. # Passing this option a "0" value causes graphics mode to be used. Pasing # it no value or any non-0 value causes text mode to be used. # Default is to use graphics mode. # #textonly # Set the EFI text mode to be used for textual displays. This option # takes a single digit that refers to a mode number. Mode 0 is normally # 80x25, 1 is sometimes 80x50, and higher numbers are system-specific # modes. Mode 1024 is a special code that tells rEFInd to not set the # text mode; it uses whatever was in use when the program was launched. # If you specify an invalid mode, rEFInd pauses during boot to inform # you of valid modes. # CAUTION: On VirtualBox, and perhaps on some real computers, specifying # a text mode and uncommenting the "textonly" option while NOT specifying # a resolution can result in an unusable display in the booted OS. # Default is 1024 (no change) # #textmode 2 # Set the screen's video resolution. Pass this option either: # * two values, corresponding to the X and Y resolutions # * one value, corresponding to a GOP (UEFI) video mode # Note that not all resolutions are supported. On UEFI systems, passing # an incorrect value results in a message being shown on the screen to # that effect, along with a list of supported modes. On EFI 1.x systems # (e.g., Macintoshes), setting an incorrect mode silently fails. On both # types of systems, setting an incorrect resolution results in the default # resolution being used. A resolution of 1024x768 usually works, but higher # values often don't. # Default is "0 0" (use the system default resolution, usually 800x600). # #resolution 1024 768 #resolution 1440 900 #resolution 3 # Enable touch screen support. If active, this feature enables use of # touch screen controls (as on tablets). Note, however, that not all # tablets' EFIs provide the necessary underlying support, so this # feature may not work for you. If it does work, you should be able # to launch an OS or tool by touching it. In a submenu, touching # anywhere launches the currently-selection item; there is, at present, # no way to select a specific submenu item. This feature is mutually # exclusive with the enable_mouse feature. If both are uncommented, # the one read most recently takes precedence. # #enable_touch # Enable mouse support. If active, this feature enables use of the # computer's mouse. Note, however, that not all computers' EFIs # provide the necessary underlying support, so this feature may not # work for you. If it does work, you should be able to launch an # OS or tool by clicking it with the mouse pointer. This feature # is mutually exclusive with the enable_touch feature. If both # are uncommented, the one read most recently takes precedence. # #enable_mouse # Size of the mouse pointer, in pixels, per side. # Default is 16 # #mouse_size # Speed of mouse tracking. Higher numbers equate to faster # mouse movement. This option requires that enable_mouse be # uncommented. # Legal values are between 1 and 32. Default is 4. # #mouse_speed 4 # Launch specified OSes in graphics mode. By default, rEFInd switches # to text mode and displays basic pre-launch information when launching # all OSes except macOS. Using graphics mode can produce a more seamless # transition, but displays no information, which can make matters # difficult if you must debug a problem. Also, on at least one known # computer, using graphics mode prevents a crash when using the Linux # kernel's EFI stub loader. You can specify an empty list to boot all # OSes in text mode. # Valid options: # osx - macOS # linux - A Linux kernel with EFI stub loader # elilo - The ELILO boot loader # grub - The GRUB (Legacy or 2) boot loader # windows - Microsoft Windows # Default value: osx # #use_graphics_for osx,linux # Which non-bootloader tools to show on the tools line, and in what # order to display them: # shell - the EFI shell (requires external program; see rEFInd # documentation for details) # memtest - the memtest86 program, in EFI/tools, EFI/memtest86, # EFI/memtest, EFI/tools/memtest86, or EFI/tools/memtest # gptsync - the (dangerous) gptsync.efi utility (requires external # program; see rEFInd documentation for details) # gdisk - the gdisk partitioning program # apple_recovery - boots the Apple Recovery HD partition, if present # windows_recovery - boots an OEM Windows recovery tool, if present # (see also the windows_recovery_files option) # mok_tool - makes available the Machine Owner Key (MOK) maintenance # tool, MokManager.efi, used on Secure Boot systems # csr_rotate - adjusts Apple System Integrity Protection (SIP) # policy. Requires "csr_values" to be set. # about - an "about this program" option # hidden_tags - manage hidden tags # exit - a tag to exit from rEFInd # shutdown - shuts down the computer (a bug causes this to reboot # many UEFI systems) # reboot - a tag to reboot the computer # firmware - a tag to reboot the computer into the firmware's # user interface (ignored on older computers) # fwupdate - a tag to update the firmware; launches the fwupx64.efi # (or similar) program # netboot - launch the ipxe.efi tool for network (PXE) booting # Default is shell,memtest,gdisk,apple_recovery,windows_recovery,mok_tool,about,hidden_tags,shutdown,reboot,firmware,fwupdate # #showtools shell, gdisk, memtest, mok_tool, apple_recovery, windows_recovery, about, hidden_tags, reboot, exit, firmware, fwupdate # Tool binaries to be excluded from the tools line, even if the # general class is specified in showtools. This enables trimming an # overabundance of tools, as when you see multiple mok_tool entries # after installing multiple Linux distributions. # Just as with dont_scan_files, you can specify a filename alone, a # full pathname, or a volume identifier (filesystem label, partition # name, or partition GUID) and a full pathname. # Default is an empty list (nothing is excluded) # #dont_scan_tools ESP2:/EFI/ubuntu/mmx64.efi,gptsync_x64.efi # Boot loaders that can launch a Windows restore or emergency system. # These tend to be OEM-specific. # Default is LRS_ESP:/EFI/Microsoft/Boot/LrsBootmgr.efi # #windows_recovery_files LRS_ESP:/EFI/Microsoft/Boot/LrsBootmgr.efi # Directories in which to search for EFI drivers. These drivers can # provide filesystem support, give access to hard disks on plug-in # controllers, etc. In most cases none are needed, but if you add # EFI drivers and you want rEFInd to automatically load them, you # should specify one or more paths here. rEFInd always scans the # "drivers" and "drivers_{arch}" subdirectories of its own installation # directory (where "{arch}" is your architecture code); this option # specifies ADDITIONAL directories to scan. # Default is to scan no additional directories for EFI drivers # #scan_driver_dirs EFI/tools/drivers,drivers # Which types of boot loaders to search, and in what order to display them: # internal - internal EFI disk-based boot loaders # external - external EFI disk-based boot loaders # optical - EFI optical discs (CD, DVD, etc.) # netboot - EFI network (PXE) boot options # hdbios - BIOS disk-based boot loaders # biosexternal - BIOS external boot loaders (USB, eSATA, etc.) # cd - BIOS optical-disc boot loaders # manual - use stanzas later in this configuration file # Note that the legacy BIOS options require firmware support, which is # not present on all computers. # The netboot option is experimental and relies on the ipxe.efi and # ipxe_discover.efi program files. # On UEFI PCs, default is internal,external,optical,manual # On Macs, default is internal,hdbios,external,biosexternal,optical,cd,manual # #scanfor internal,external,optical,manual # By default, rEFInd relies on the UEFI firmware to detect BIOS-mode boot # devices. This sometimes doesn't detect all the available devices, though. # For these cases, uefi_deep_legacy_scan results in a forced scan and # modification of NVRAM variables on each boot. Adding "0", "off", or # "false" resets to the default value. This token has no effect on Macs or # when no BIOS-mode options are set via scanfor. # Default is unset (or "uefi_deep_legacy_scan false") # #uefi_deep_legacy_scan # Delay for the specified number of seconds before scanning disks. # This can help some users who find that some of their disks # (usually external or optical discs) aren't detected initially, # but are detected after pressing Esc. # The default is 0. # #scan_delay 5 # When scanning volumes for EFI boot loaders, rEFInd always looks for # macOS's and Microsoft Windows' boot loaders in their normal locations, # and scans the root directory and every subdirectory of the /EFI directory # for additional boot loaders, but it doesn't recurse into these directories. # The also_scan_dirs token adds more directories to the scan list. # Directories are specified relative to the volume's root directory. This # option applies to ALL the volumes that rEFInd scans UNLESS you include # a volume name and colon before the directory name, as in "myvol:/somedir" # to scan the somedir directory only on the filesystem named myvol. If a # specified directory doesn't exist, it's ignored (no error condition # results). The default is to scan the "boot" directory in addition to # various hard-coded directories. # #also_scan_dirs boot,ESP2:EFI/linux/kernels # Partitions (or whole disks, for legacy-mode boots) to omit from scans. # For EFI-mode scans, you normally specify a volume by its label, which you # can obtain in an EFI shell by typing "vol", from Linux by typing # "blkid /dev/{devicename}", or by examining the disk's label in various # OSes' file browsers. It's also possible to identify a partition by its # unique GUID (aka its "PARTUUID" in Linux parlance). (Note that this is # NOT the partition TYPE CODE GUID.) This identifier can be obtained via # "blkid" in Linux or "diskutil info {partition-id}" in macOS. # For legacy-mode scans, you can specify any subset of the boot loader # description shown when you highlight the option in rEFInd. # The default is "LRS_ESP". # #dont_scan_volumes "Recovery HD" # Directories that should NOT be scanned for boot loaders. By default, # rEFInd doesn't scan its own directory, the EFI/tools directory, the # EFI/memtest directory, the EFI/memtest86 directory, or the # com.apple.recovery.boot directory. Using the dont_scan_dirs option # enables you to "blacklist" other directories; but be sure to use "+" # as the first element if you want to continue blacklisting existing # directories. You might use this token to keep EFI/boot/bootx64.efi out # of the menu if that's a duplicate of another boot loader or to exclude # a directory that holds drivers or non-bootloader utilities provided by # a hardware manufacturer. If a directory is listed both here and in # also_scan_dirs, dont_scan_dirs takes precedence. Note that this # blacklist applies to ALL the filesystems that rEFInd scans, not just # the ESP, unless you precede the directory name by a filesystem name or # partition unique GUID, as in "myvol:EFI/somedir" to exclude EFI/somedir # from the scan on the myvol volume but not on other volumes. # #dont_scan_dirs ESP:/EFI/boot,EFI/Dell,EFI/memtest86 # Files that should NOT be included as EFI boot loaders (on the # first line of the display). If you're using a boot loader that # relies on support programs or drivers that are installed alongside # the main binary or if you want to "blacklist" certain loaders by # name rather than location, use this option. Note that this will # NOT prevent certain binaries from showing up in the second-row # set of tools. Most notably, various Secure Boot and recovery # tools are present in this list, but may appear as second-row # items. # The file may be specified as a bare name (e.g., "notme.efi"), as # a complete pathname (e.g., "/EFI/somedir/notme.efi"), or as a # complete pathname with volume (e.g., "SOMEDISK:/EFI/somedir/notme.efi" # or 2C17D5ED-850D-4F76-BA31-47A561740082:/EFI/somedir/notme.efi"). # OS tags hidden via the Delete or '-' key in the rEFInd menu are # added to this list, but stored in NVRAM. # The default is shim.efi,shim-fedora.efi,shimx64.efi,PreLoader.efi, # TextMode.efi,ebounce.efi,GraphicsConsole.efi,MokManager.efi,HashTool.efi, # HashTool-signed.efi,bootmgr.efi,fb{arch}.efi # (where "{arch}" is the architecture code, like "x64"). # #dont_scan_files shim.efi,MokManager.efi # Scan for Linux kernels that lack a ".efi" filename extension. This is # useful for better integration with Linux distributions that provide # kernels with EFI stub loaders but that don't give those kernels filenames # that end in ".efi", particularly if the kernels are stored on a # filesystem that the EFI can read. When set to "1", "true", or "on", this # option causes all files in scanned directories with names that begin with # "vmlinuz" or "bzImage" to be included as loaders, even if they lack ".efi" # extensions. Passing this option a "0", "false", or "off" value causes # kernels without ".efi" extensions to NOT be scanned. # Default is "true" -- to scan for kernels without ".efi" extensions. # #scan_all_linux_kernels false # Combine all Linux kernels in a given directory into a single entry. # When so set, the kernel with the most recent time stamp will be launched # by default, and its filename will appear in the entry's description. # To launch other kernels, the user must press F2 or Insert; alternate # kernels then appear as options on the sub-menu. # Default is "true" -- kernels are "folded" into a single menu entry. # #fold_linux_kernels false # Comma-delimited list of strings to treat as if they were numbers for the # purpose of kernel version number detection. These strings are matched on a # first-found basis; that is, if you want to treat both "linux-lts" and # "linux" as version strings, they MUST be specified as "linux-lts,linux", # since if you specify it the other way, both vmlinuz-linux and # vmlinuz-linux-lts will return with "linux" as the "version string," which # is not what you'd want. Also, if the kernel or initrd file includes both a # specified string and digits, the "version string" includes both. For # instance, "vmlinuz-linux-4.8" would yield a version string of "linux-4.8". # This option is intended for Arch and other distributions that don't include # version numbers in their kernel filenames, but may provide other uniquely # identifying strings for multiple kernels. If this feature causes problems # (say, if your kernel filename includes "linux" but the initrd filename # doesn't), be sure this is set to an empty string # (extra_kernel_version_strings "") or comment out the option to disable it. # Default is no extra version strings # #extra_kernel_version_strings linux-lts,linux # Set the maximum number of tags that can be displayed on the screen at # any time. If more loaders are discovered than this value, rEFInd shows # a subset in a scrolling list. If this value is set too high for the # screen to handle, it's reduced to the value that the screen can manage. # If this value is set to 0 (the default), it's adjusted to the number # that the screen can handle. # #max_tags 0 # Set the default menu selection. The available arguments match the # keyboard accelerators available within rEFInd. You may select the # default loader using: # - A digit between 1 and 9, in which case the Nth loader in the menu # will be the default. # - A "+" symbol at the start of the string, which refers to the most # recently booted loader. # - Any substring that corresponds to a portion of the loader's title # (usually the OS's name, boot loader's path, or a volume or # filesystem title). # You may also specify multiple selectors by separating them with commas # and enclosing the list in quotes. (The "+" option is only meaningful in # this context.) # If you follow the selector(s) with two times, in 24-hour format, the # default will apply only between those times. The times are in the # motherboard's time standard, whether that's UTC or local time, so if # you use UTC, you'll need to adjust this from local time manually. # Times may span midnight as in "23:30 00:30", which applies to 11:30 PM # to 12:30 AM. You may specify multiple default_selection lines, in which # case the last one to match takes precedence. Thus, you can set a main # option without a time followed by one or more that include times to # set different defaults for different times of day. # The default behavior is to boot the previously-booted OS. # #default_selection 1 #default_selection Microsoft #default_selection "+,bzImage,vmlinuz" #default_selection Maintenance 23:30 2:00 #default_selection "Maintenance,macOS" 1:00 2:30 # Enable VMX bit and lock the CPU MSR if unlocked. # On some Intel Apple computers, the firmware does not lock the MSR 0x3A. # The symptom on Windows is Hyper-V not working even if the CPU # meets the minimum requirements (HW assisted virtualization and SLAT) # DO NOT SET THIS EXCEPT ON INTEL CPUs THAT SUPPORT VMX! See # http://www.thomas-krenn.com/en/wiki/Activating_the_Intel_VT_Virtualization_Feature # for more on this subject. # The default is false: Don't try to enable and lock the MSR. # #enable_and_lock_vmx false # Tell a Mac's EFI that macOS is about to be launched, even when it's not. # This option causes some Macs to initialize their hardware differently than # when a third-party OS is launched normally. In some cases (particularly on # Macs with multiple video cards), using this option can cause hardware to # work that would not otherwise work. On the other hand, using this option # when it is not necessary can cause hardware (such as keyboards and mice) to # become inaccessible. Therefore, you should not enable this option if your # non-Apple OSes work correctly; enable it only if you have problems with # some hardware devices. When needed, a value of "10.9" usually works, but # you can experiment with other values. This feature has no effect on # non-Apple computers. # The default is inactive (no macOS spoofing is done). # #spoof_osx_version 10.9 # Set the CSR values for Apple's System Integrity Protection (SIP) feature. # Values are one-byte (two-character) hexadecimal numbers. These values # define which specific security features are enabled. Below are the codes # for what the values mean. Add them up (in hexadecimal!) to set new values. # Apple's "csrutil enable" and "csrutil disable" commands set values of 10 # and 77, respectively. # CSR_ALLOW_UNTRUSTED_KEXTS 0x01 # CSR_ALLOW_UNRESTRICTED_FS 0x02 # CSR_ALLOW_TASK_FOR_PID 0x04 # CSR_ALLOW_KERNEL_DEBUGGER 0x08 # CSR_ALLOW_APPLE_INTERNAL 0x10 # CSR_ALLOW_UNRESTRICTED_DTRACE 0x20 # CSR_ALLOW_UNRESTRICTED_NVRAM 0x40 # #csr_values 10,77 # Include a secondary configuration file within this one. This secondary # file is loaded as if its options appeared at the point of the "include" # token itself, so if you want to override a setting in the main file, # the secondary file must be referenced AFTER the setting you want to # override. Note that the secondary file may NOT load a tertiary file. # #include manual.conf # Sample manual configuration stanzas. Each begins with the "menuentry" # keyword followed by a name that's to appear in the menu (use quotes # if you want the name to contain a space) and an open curly brace # ("{"). Each entry ends with a close curly brace ("}"). Common # keywords within each stanza include: # # volume - identifies the filesystem from which subsequent files # are loaded. You can specify the volume by filesystem # label, by partition label, or by partition GUID number # (but NOT yet by filesystem UUID number). # loader - identifies the boot loader file # initrd - Specifies an initial RAM disk file # icon - specifies a custom boot loader icon # ostype - OS type code to determine boot options available by # pressing Insert. Valid values are "MacOS", "Linux", # "Windows", and "XOM". Case-sensitive. # graphics - set to "on" to enable graphics-mode boot (useful # mainly for MacOS) or "off" for text-mode boot. # Default is auto-detected from loader filename. # options - sets options to be passed to the boot loader; use # quotes if more than one option should be passed or # if any options use characters that might be changed # by rEFInd parsing procedures (=, /, #, or tab). # disabled - use alone or set to "yes" to disable this entry. # # Note that you can use either DOS/Windows/EFI-style backslashes (\) # or Unix-style forward slashes (/) as directory separators. Either # way, all file references are on the ESP from which rEFInd was # launched. # Use of quotes around parameters causes them to be interpreted as # one keyword, and for parsing of special characters (spaces, =, /, # and #) to be disabled. This is useful mainly with the "options" # keyword. Use of quotes around parameters that specify filenames is # permissible, but you must then use backslashes instead of slashes, # except when you must pass a forward slash to the loader, as when # passing a root= option to a Linux kernel. # Below are several sample boot stanzas. All are disabled by default. # Find one similar to what you need, copy it, remove the "disabled" line, # and adjust the entries to suit your needs. # A sample entry for a Linux 3.13 kernel with EFI boot stub support # on a partition with a GUID of 904404F8-B481-440C-A1E3-11A5A954E601. # This entry includes Linux-specific boot options and specification # of an initial RAM disk. Note uses of Linux-style forward slashes. # Also note that a leading slash is optional in file specifications. menuentry Linux { icon EFI/refind/icons/os_linux.png volume 904404F8-B481-440C-A1E3-11A5A954E601 loader bzImage-3.3.0-rc7 initrd initrd-3.3.0.img options "ro root=UUID=5f96cafa-e0a7-4057-b18f-fa709db5b837" disabled } # Below is a more complex Linux example, specifically for Arch Linux. # This example MUST be modified for your specific installation; if nothing # else, the PARTUUID code must be changed for your disk. Because Arch Linux # does not include version numbers in its kernel and initrd filenames, you # may need to use manual boot stanzas when using fallback initrds or # multiple kernels with Arch. This example is modified from one in the Arch # wiki page on rEFInd (https://wiki.archlinux.org/index.php/rEFInd). menuentry "Arch Linux" { icon /EFI/refind/icons/os_arch.png volume "Arch Linux" loader /boot/vmlinuz-linux initrd /boot/initramfs-linux.img options "root=PARTUUID=5028fa50-0079-4c40-b240-abfaf28693ea rw add_efi_memmap" submenuentry "Boot using fallback initramfs" { initrd /boot/initramfs-linux-fallback.img } submenuentry "Boot to terminal" { add_options "systemd.unit=multi-user.target" } disabled } # A sample entry for loading Ubuntu using its standard name for # its GRUB 2 boot loader. Note uses of Linux-style forward slashes menuentry Ubuntu { loader /EFI/ubuntu/grubx64.efi icon /EFI/refind/icons/os_linux.png disabled } # A minimal ELILO entry, which probably offers nothing that # auto-detection can't accomplish. menuentry "ELILO" { loader \EFI\elilo\elilo.efi disabled } # Like the ELILO entry, this one offers nothing that auto-detection # can't do; but you might use it if you want to disable auto-detection # but still boot Windows.... menuentry "Windows 7" { loader \EFI\Microsoft\Boot\bootmgfw.efi disabled } # EFI shells are programs just like boot loaders, and can be # launched in the same way. You can pass a shell the name of a # script that it's to run on the "options" line. The script # could initialize hardware and then launch an OS, or it could # do something entirely different. menuentry "Windows via shell script" { icon \EFI\refind\icons\os_win.png loader \EFI\tools\shell.efi options "fs0:\EFI\tools\launch_windows.nsh" disabled } # Mac OS is normally detected and run automatically; however, # if you want to do something unusual, a manual boot stanza may # be the way to do it. This one does nothing very unusual, but # it may serve as a starting point. Note that you'll almost # certainly need to change the "volume" line for this example # to work. menuentry "My macOS" { icon \EFI\refind\icons\os_mac.png volume "macOS boot" loader \System\Library\CoreServices\boot.efi disabled } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/Make.common���������������������������������������������������������������������������0000664�0001750�0001750�00000013261�13322741303�015402� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Make.common # Common make rules for building with gnu-efi # # This program is licensed under the terms of the GNU GPL, version 3, # or (at your option) any later version. # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. # This file contains make definitions common to several (or all) of the make # files in the rEFInd code subdirectories. Some options are specific to # particular architectures or build systems and others are more universal. # # Environment definitions -- where stuff is and what sort of system is being # used to compile rEFInd.... # EFIINC = /usr/include/efi GNUEFILIB = /usr/lib EFILIB = /usr/lib EFICRT0 = /usr/lib # Comment out above and uncomment below if using locally-compiled GNU-EFI.... #EFIINC = /usr/local/include/efi #GNUEFILIB = /usr/local/lib #EFILIB = /usr/local/lib #EFICRT0 = /usr/local/lib HOSTARCH = $(shell uname -m | sed s,i[3456789]86,ia32,) ARCH ?= $(HOSTARCH) # Note: TIANOBASE is defined in master Makefile and exported GENFW = $(TIANOBASE)/BaseTools/Source/C/bin/GenFw prefix = /usr/bin/ ifeq ($(ARCH),aarch64) CC = $(prefix)aarch64-linux-gnu-gcc AS = $(prefix)aarch64-linux-gnu-as LD = $(prefix)aarch64-linux-gnu-ld AR = $(prefix)aarch64-linux-gnu-ar RANLIB = $(prefix)aarch64-linux-gnu-ranlib OBJCOPY = $(prefix)aarch64-linux-gnu-objcopy else CC = $(prefix)gcc AS = $(prefix)as LD = $(prefix)ld AR = $(prefix)ar RANLIB = $(prefix)ranlib OBJCOPY = $(prefix)objcopy endif ifeq ($(MAKEWITH),TIANO) # Below file defines TARGET (RELEASE or DEBUG) and TOOL_CHAIN_TAG (GCC44, GCC45, GCC46, or GCC47) include $(TIANOBASE)/Conf/target.txt endif # # C compiler flags # # ...for both GNU-EFI and TianoCore.... OPTIMFLAGS = -Os -fno-strict-aliasing CFLAGS = $(OPTIMFLAGS) -fno-stack-protector -fshort-wchar -Wall # ...for GNU-EFI.... GNUEFI_CFLAGS = -fpic -I$(EFIINC) -I$(EFIINC)/$(ARCH) -I$(EFIINC)/protocol -I../include -I../refind -I../libeg -I../mok # ...and for TianoCore.... TIANO_INCLUDE_DIRS = -I $(TIANOBASE)/MdePkg \ -I $(TIANOBASE)/MdePkg/Include \ -I $(TIANOBASE)/MdeModulePkg/ \ -I $(TIANOBASE)/MdeModulePkg/Include \ -I $(TIANOBASE)/IntelFrameworkPkg/Include \ -I $(TIANOBASE)/MdePkg/Include/$(ARCHDIR) \ -I .. \ -I ../refind \ -I ../libeg \ -I ../include \ -I ../mok # # Linker flags # # for GNU-EFI.... SUBSYSTEM_LDFLAG = GNUEFI_LDSCRIPT = $(EFICRT0)/elf_$(ARCH)_efi.lds CRTOBJS = $(EFICRT0)/crt0-efi-$(ARCH).o GNUEFI_LDFLAGS = -T $(GNUEFI_LDSCRIPT) -shared -Bsymbolic -nostdlib -L$(EFILIB) -L$(GNUEFILIB) $(CRTOBJS) GNUEFI_LIBS = -lefi -lgnuefi $(shell $(CC) -print-libgcc-file-name) #LIBS = -lefi -lgnuefi $(shell $(CC) $(ARCH3264) -print-libgcc-file-name) # ...and for TianoCore.... ENTRYPOINT=efi_main TIANO_LDSCRIPT = $(TIANOBASE)/BaseTools/Scripts/gcc4.9-ld-script #TIANO_LDSCRIPT = /usr/local/UDK2014/MyWorkSpace/BaseTools/Scripts/gcc4.9-ld-script TIANO_LDFLAGS = -nostdlib -n -q --gc-sections --script=$(TIANO_LDSCRIPT) \ --entry $(ENTRYPOINT) -u $(ENTRYPOINT) -m $(LD_CODE) # # objcopy flags for GNU-EFI # FORMAT = --target=efi-app-$(ARCH) FORMAT_DRIVER = --target=efi-bsdrv-$(ARCH) # # Modifications on a per-architecture basis.... # ifeq ($(ARCH),x86_64) GNUEFI_LDFLAGS += -znocombreloc -zdefs ARCH_CFLAGS = -DEFIX64 -DEFI_FUNCTION_WRAPPER -m64 -mno-red-zone ifeq ($(MAKEWITH),TIANO) ARCH_CFLAGS += -mcmodel=large "-DEFIAPI=__attribute__((ms_abi))" endif ARCHDIR = X64 UC_ARCH = X64 FILENAME_CODE = x64 LD_CODE = elf_x86_64 endif ifeq ($(ARCH),ia32) GNUEFI_LDFLAGS += -znocombreloc -zdefs # In practice, cross-compiling filesystem drivers works, but not the main # rEFInd binary.... ifeq ($(HOSTARCH),x86_64) GNUEFILIB := $(GNUEFILIB)32 EFILIB := $(EFILIB)32 EFICRT0 := $(EFICRT0)32 endif ARCH_CFLAGS = -m32 -DEFI32 -malign-double ARCHDIR = Ia32 UC_ARCH = IA32 FILENAME_CODE = ia32 LD_CODE = elf_i386 endif ifeq ($(ARCH), aarch64) GNUEFI_CFLAGS += -DEFIAARCH64 FORMAT = -O binary FORMAT_DRIVER = -O binary SUBSYSTEM_LDFLAG = -defsym=EFI_SUBSYSTEM=0xa LDFLAGS += --warn-common --no-undefined --fatal-warnings ARCH_CFLAGS = -fno-merge-constants -ffreestanding -DEFIAARCH64 ifeq ($(MAKEWITH),TIANO) ARCH_CFLAGS += -mcmodel=large -Wno-address -Wno-missing-braces -Wno-array-bounds -ffunction-sections -fdata-sections endif ifeq ($(MAKEWITH),GNUEFI) ARCH_CFLAGS += -fno-stack-check endif ARCHDIR = AArch64 UC_ARCH = AARCH64 FILENAME_CODE = aa64 LD_CODE = aarch64elf endif # GNU-EFI compilation path uses .o files for compiled object code %.o: %.c $(CC) $(CFLAGS) $(ARCH_CFLAGS) $(GNUEFI_CFLAGS) $(LOCAL_GNUEFI_CFLAGS) \ -D__MAKEWITH_GNUEFI -c $< -o $@ # TianoCore compilation path uses .obj files for compiled object code %.obj: %.c $(CC) $(CFLAGS) $(ARCH_CFLAGS) $(TIANO_INCLUDE_DIRS) -DNO_BUILTIN_VA_FUNCS \ -D__MAKEWITH_TIANO -c $< -o $@ # rules for EFI applications ifneq (,$(filter %.efi,$(TARGET))) SHLIB_TARGET = $(subst .efi,.so,$(TARGET)) endif # rules for libraries ifneq (,$(filter %.a,$(TARGET))) $(TARGET): $(OBJS) $(AR) cq $@ $(OBJS) endif # utility rules #clean: # rm -f $(TARGET) *~ *.so $(OBJS) *.efi *.obj refind_*.txt refind_*.dll *.lib # EOF �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/refind.inf����������������������������������������������������������������������������0000664�0001750�0001750�00000013464�13322744502�015271� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������## @file # # refind.inf file to build rEFInd using the EDK2/UDK201# development # kit. # # Copyright (c) 2012-2017 by Roderick W. Smith # Released under the terms of the GPLv3 (or, at your discretion, any later # version), a copy of which should come with this file. # ## [Defines] INF_VERSION = 0x00010005 BASE_NAME = refind FILE_GUID = B8448DD1-B146-41B7-9D66-98B3A0A404D3 MODULE_TYPE = UEFI_APPLICATION EDK_RELEASE_VERSION = 0x00020000 EFI_SPECIFICATION_VERSION = 0x00010000 VERSION_STRING = 1.0 ENTRY_POINT = efi_main # # The following information is for reference only and not required by the build tools. # # VALID_ARCHITECTURES = IA32 X64 IPF EBC AARCH64 # [Sources] EfiLib/GenericBdsLib.h EfiLib/BmLib.c EfiLib/DevicePath.c #included into GenericBdsLib EfiLib/BdsConnect.c #included into GenericBdsLib EfiLib/BdsHelper.c EfiLib/BdsTianoCore.c EfiLib/legacy.c mok/mok.c mok/guid.c mok/security_policy.c mok/simple_file.c refind/apple.c refind/main.c refind/config.c refind/icns.c refind/legacy.c refind/lib.c refind/line_edit.c refind/menu.c refind/mystrings.c refind/screen.c refind/pointer.c refind/driver_support.c refind/gpt.c refind/crc32.c libeg/image.c libeg/load_bmp.c libeg/load_icns.c libeg/lodepng.c libeg/lodepng_xtra.c libeg/nanojpeg.c libeg/nanojpeg_xtra.c libeg/screen.c libeg/text.c [Packages] MdePkg/MdePkg.dec MdeModulePkg/MdeModulePkg.dec IntelFrameworkPkg/IntelFrameworkPkg.dec IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec # Uncomment the below when compiling with OS X # StdLib/StdLib.dec [Packages.XCODE] StdLib/StdLib.dec [LibraryClasses] UefiApplicationEntryPoint UefiBootServicesTableLib UefiLib MemoryAllocationLib BaseMemoryLib BaseLib DevicePathLib DebugLib DxeServicesLib DxeServicesTableLib HobLib MemoryAllocationLib IoLib PerformanceLib [LibraryClasses.AARCH64] BaseStackCheckLib # Comment out CompilerIntrinsicsLib when compiling for AARCH64 using UDK2014 CompilerIntrinsicsLib [Guids] gEfiAcpiTableGuid gEfiAcpi10TableGuid gEfiAcpi20TableGuid gEfiDxeServicesTableGuid gEfiEventReadyToBootGuid gEfiEventVirtualAddressChangeGuid gEfiEventExitBootServicesGuid gEfiFileInfoGuid ## CONSUMES ## GUID gEfiFileSystemInfoGuid ## CONSUMES ## GUID gEfiFileSystemVolumeLabelInfoIdGuid gEfiGlobalVariableGuid gEfiPartTypeLegacyMbrGuid gEfiPartTypeSystemPartGuid gEfiSmbiosTableGuid gEfiSasDevicePathGuid [Ppis] [Protocols] gEfiComponentName2ProtocolGuid # ALWAYS_CONSUMED gEfiDevicePathToTextProtocolGuid # ALWAYS_CONSUMED gEfiSimpleFileSystemProtocolGuid # ALWAYS_CONSUMED gEfiSimpleTextInProtocolGuid # ALWAYS_CONSUMED gEfiSimpleTextInputExProtocolGuid # ALWAYS_CONSUMED gEfiSimpleTextOutProtocolGuid # ALWAYS_CONSUMED gEfiUnicodeCollationProtocolGuid # ALWAYS_CONSUMED gEfiUnicodeCollation2ProtocolGuid # ALWAYS_CONSUMED gEfiAcpiS3SaveProtocolGuid # PROTOCOL CONSUMES gEfiBlockIoProtocolGuid # PROTOCOL CONSUMES gEfiCpuArchProtocolGuid # PROTOCOL CONSUMES gEfiDebugPortProtocolGuid # PROTOCOL CONSUMES gEfiDevicePathProtocolGuid # PROTOCOL CONSUMES gEfiDiskIoProtocolGuid # PROTOCOL CONSUMES gEfiExtScsiPassThruProtocolGuid ## PROTOCOL SOMETIMES_CONSUMES gEfiFirmwareVolume2ProtocolGuid # PROTOCOL CONSUMES gEfiGraphicsOutputProtocolGuid # PROTOCOL SOMETIMES_CONSUMES gEfiHiiFontProtocolGuid # PROTOCOL CONSUMES gEfiLegacy8259ProtocolGuid ## PROTOCOL SOMETIMES_CONSUMES gEfiLoadedImageProtocolGuid # PROTOCOL CONSUMES gEfiOEMBadgingProtocolGuid # PROTOCOL CONSUMES gEfiPciIoProtocolGuid # PROTOCOL CONSUMES gEfiScsiIoProtocolGuid ## PROTOCOL SOMETIMES_CONSUMES gEfiScsiPassThruProtocolGuid ## PROTOCOL SOMETIMES_CONSUMES gEfiSimpleNetworkProtocolGuid # PROTOCOL CONSUMES gEfiUgaDrawProtocolGuid |PcdUgaConsumeSupport # PROTOCOL SOMETIMES_CONSUMES gEfiAbsolutePointerProtocolGuid gEfiAcpiTableProtocolGuid gEfiEdidActiveProtocolGuid gEfiEdidDiscoveredProtocolGuid gEfiHiiDatabaseProtocolGuid gEfiHiiImageProtocolGuid gEfiHiiProtocolGuid gEfiSimplePointerProtocolGuid gEfiSmbiosProtocolGuid gEfiSecurityArchProtocolGuid gEfiScsiIoProtocolGuid ## PROTOCOL SOMETIMES_CONSUMES gEfiScsiPassThruProtocolGuid ## PROTOCOL SOMETIMES_CONSUMES gEfiExtScsiPassThruProtocolGuid ## PROTOCOL SOMETIMES_CONSUMES gEfiLegacyBiosProtocolGuid # PROTOCOL TO_START gEfiLoadFile2ProtocolGuid gEfiLoadFileProtocolGuid gEfiHiiPackageListProtocolGuid [FeaturePcd] gEfiMdePkgTokenSpaceGuid.PcdUgaConsumeSupport [Pcd] [BuildOptions.IA32] XCODE:*_*_*_CC_FLAGS = -Os -DEFI32 -D__MAKEWITH_TIANO GCC:*_*_*_CC_FLAGS = -Os -DEFI32 -D__MAKEWITH_TIANO [BuildOptions.X64] XCODE:*_*_*_CC_FLAGS = -Os -DEFIX64 -D__MAKEWITH_TIANO GCC:*_*_*_CC_FLAGS = -Os -DEFIX64 -D__MAKEWITH_TIANO [BuildOptions.AARCH64] XCODE:*_*_*_CC_FLAGS = -Os -DEFIAARCH64 -D__MAKEWITH_TIANO GCC:*_*_*_CC_FLAGS = -Os -DEFIAARCH64 -D__MAKEWITH_TIANO ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/LICENSE.txt���������������������������������������������������������������������������0000664�0001750�0001750�00000004234�12626644767�015164� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� rEFIt License =============== Copyright (c) 2006 Christoph Pfisterer All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Christoph Pfisterer nor the names of the contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Additional Notice =================== Parts of the file system driver sub-projects are covered by the GNU GPL instead. See the LICENSE.txt files in the fs_ext2 and fsw directories for more information. Additional Additional Notice ============================= The preceding license terms apply to the original rEFIt program. Modifications to the program made in forking the project as rEFInd are covered by the GNU GPL, version 3. See the file COPYING.txt for details of the GPLv3 license. The rEFInd documentation (HTML files) are covered by the GNU FDL, version 1.3. See the file FDL-1.3.txt in the documentation directory for details of the FDL license. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/net/����������������������������������������������������������������������������������0000775�0001750�0001750�00000000000�12626644770�014116� 5����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/net/discovery/������������������������������������������������������������������������0000775�0001750�0001750�00000000000�12626644770�016125� 5����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/net/discovery/Makefile.housekeeping���������������������������������������������������0000664�0001750�0001750�00000120335�12626644770�022256� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# -*- makefile -*- : Force emacs to use Makefile mode # # This file contains various boring housekeeping functions that would # otherwise seriously clutter up the main Makefile. ############################################################################### # # Find a usable "echo -e" substitute. # TAB := $(shell $(PRINTF) '\t') ECHO_E_ECHO := $(ECHO) ECHO_E_ECHO_E := $(ECHO) -e ECHO_E_BIN_ECHO := /bin/echo ECHO_E_BIN_ECHO_E := /bin/echo -e ECHO_E_ECHO_TAB := $(shell $(ECHO_E_ECHO) '\t' | cat) ECHO_E_ECHO_E_TAB := $(shell $(ECHO_E_ECHO_E) '\t' | cat) ECHO_E_BIN_ECHO_TAB := $(shell $(ECHO_E_BIN_ECHO) '\t') ECHO_E_BIN_ECHO_E_TAB := $(shell $(ECHO_E_BIN_ECHO_E) '\t') ifeq ($(ECHO_E_ECHO_TAB),$(TAB)) ECHO_E := $(ECHO_E_ECHO) endif ifeq ($(ECHO_E_ECHO_E_TAB),$(TAB)) ECHO_E := $(ECHO_E_ECHO_E) endif ifeq ($(ECHO_E_BIN_ECHO_TAB),$(TAB)) ECHO_E := $(ECHO_E_BIN_ECHO) endif ifeq ($(ECHO_E_BIN_ECHO_E_TAB),$(TAB)) ECHO_E := $(ECHO_E_BIN_ECHO_E) endif .echocheck : ifdef ECHO_E @$(TOUCH) $@ else @$(PRINTF) '%24s : x%sx\n' 'tab' '$(TAB)' @$(PRINTF) '%24s : x%sx\n' '"$(ECHO_E_ECHO) \t"' \ '$(ECHO_E_ECHO_TAB)' @$(PRINTF) '%24s : x%sx\n' '"$(ECHO_E_ECHO_E) \t"' \ '$(ECHO_E_ECHO_E_TAB)' @$(PRINTF) '%24s : x%sx\n' '"$(ECHO_E_BIN_ECHO) \t"' \ '$(ECHO_E_BIN_ECHO_TAB)' @$(PRINTF) '%24s : x%sx\n' '"$(ECHO_E_BIN_ECHO_E) \t"' \ '$(ECHO_E_BIN_ECHO_E_TAB)' @$(ECHO) "No usable \"echo -e\" substitute found" @exit 1 endif MAKEDEPS += .echocheck VERYCLEANUP += .echocheck echo : @$(ECHO) "Using \"$(ECHO_E)\" for \"echo -e\"" ############################################################################### # # Generate a usable "seq" substitute # define seq $(shell awk 'BEGIN { for ( i = $(1) ; i <= $(2) ; i++ ) print i }') endef ############################################################################### # # Determine host OS # HOST_OS := $(shell uname -s) hostos : @$(ECHO) $(HOST_OS) ############################################################################### # # Determine compiler CCDEFS := $(shell $(CC) -E -x c -c /dev/null -dM | cut -d" " -f2) ccdefs: @$(ECHO) $(CCDEFS) ifeq ($(filter __ICC,$(CCDEFS)),__ICC) CCTYPE := icc else CCTYPE := gcc endif cctype: @$(ECHO) $(CCTYPE) ############################################################################### # # Check for tools that can cause failed builds # ifeq ($(CCTYPE),gcc) GCC_2_96_BANNER := $(shell $(CC) -v 2>&1 | grep -is 'gcc version 2\.96') ifneq ($(GCC_2_96_BANNER),) $(warning gcc 2.96 is unsuitable for compiling iPXE) $(warning Use gcc 2.95 or a newer version instead) $(error Unsuitable build environment found) endif endif PERL_UNICODE_CHECK := $(shell $(PERL) -e 'use bytes; print chr(255)' | wc -c) ifeq ($(PERL_UNICODE_CHECK),2) $(warning Your Perl version has a Unicode handling bug) $(warning Execute this command before building iPXE:) $(warning export LANG=$${LANG%.UTF-8}) $(error Unsuitable build environment found) endif LD_GOLD_BANNER := $(shell $(LD) -v 2>&1 | grep 'GNU gold') ifneq ($(LD_GOLD_BANNER),) $(warning GNU gold is unsuitable for building iPXE) $(warning Use GNU ld instead) $(error Unsuitable build environment found) endif ############################################################################### # # Check if $(eval ...) is available to use # HAVE_EVAL := ifndef NO_EVAL $(eval HAVE_EVAL := yes) endif eval : @$(ECHO) $(HAVE_EVAL) ############################################################################### # # Check for various tool workarounds # WORKAROUND_CFLAGS := WORKAROUND_ASFLAGS := WORKAROUND_LDFLAGS := # Make syntax does not allow use of comma or space in certain places. # This ugly workaround is suggested in the manual. # COMMA := , EMPTY := SPACE := $(EMPTY) $(EMPTY) HASH := \# define NEWLINE endef # Some widespread patched versions of gcc include -fstack-protector by # default, even when -ffreestanding is specified. We therefore need # to disable -fstack-protector if the compiler supports it. # ifeq ($(CCTYPE),gcc) SP_TEST = $(CC) -fno-stack-protector -x c -c /dev/null \ -o /dev/null >/dev/null 2>&1 SP_FLAGS := $(shell $(SP_TEST) && $(ECHO) '-fno-stack-protector') WORKAROUND_CFLAGS += $(SP_FLAGS) endif # Some widespread patched versions of gcc include -fPIE -Wl,-pie by # default. Note that gcc will exit *successfully* if it fails to # recognise an option that starts with "no", so we have to test for # output on stderr instead of checking the exit status. # ifeq ($(CCTYPE),gcc) PIE_TEST = [ -z "`$(CC) -fno-PIE -nopie -x c -c /dev/null -o /dev/null 2>&1`" ] PIE_FLAGS := $(shell $(PIE_TEST) && $(ECHO) '-fno-PIE -nopie') WORKAROUND_CFLAGS += $(PIE_FLAGS) endif # gcc 4.4 generates .eh_frame sections by default, which distort the # output of "size". Inhibit this. # ifeq ($(CCTYPE),gcc) CFI_TEST = $(CC) -fno-dwarf2-cfi-asm -fno-exceptions -fno-unwind-tables \ -fno-asynchronous-unwind-tables -x c -c /dev/null \ -o /dev/null >/dev/null 2>&1 CFI_FLAGS := $(shell $(CFI_TEST) && \ $(ECHO) '-fno-dwarf2-cfi-asm -fno-exceptions ' \ '-fno-unwind-tables -fno-asynchronous-unwind-tables') WORKAROUND_CFLAGS += $(CFI_FLAGS) endif # gcc 4.6 generates spurious warnings if -Waddress is in force. # Inhibit this. # ifeq ($(CCTYPE),gcc) WNA_TEST = $(CC) -Wno-address -x c -c /dev/null -o /dev/null >/dev/null 2>&1 WNA_FLAGS := $(shell $(WNA_TEST) && $(ECHO) '-Wno-address') WORKAROUND_CFLAGS += $(WNA_FLAGS) endif # Some versions of gas choke on division operators, treating them as # comment markers. Specifying --divide will work around this problem, # but isn't available on older gas versions. # DIVIDE_TEST = $(AS) --divide /dev/null -o /dev/null 2>/dev/null DIVIDE_FLAGS := $(shell $(DIVIDE_TEST) && $(ECHO) '--divide') WORKAROUND_ASFLAGS += $(DIVIDE_FLAGS) ############################################################################### # # Build verbosity # ifeq ($(V),1) Q := QM := @\# else Q := @ QM := @ endif ############################################################################### # # Checker # ifeq ($(C),1) export REAL_CC := $(CC) CC := cgcc CFLAGS += -Wno-decl endif ############################################################################### # # Set BIN according to whatever was specified on the command line as # the build target. # # Determine how many different BIN directories are mentioned in the # make goals. # BIN_GOALS := $(filter bin bin/% bin-%,$(MAKECMDGOALS)) BIN_GOALS_BINS := $(sort $(foreach BG,$(BIN_GOALS),\ $(firstword $(subst /, ,$(BG))))) NUM_BINS := $(words $(BIN_GOALS_BINS)) ifeq ($(NUM_BINS),0) # No BIN directory was specified. Set BIN to "bin" as a sensible # default. BIN := bin else # NUM_BINS == 0 ifeq ($(NUM_BINS),1) # If exactly one BIN directory was specified, set BIN to match this # directory. # BIN := $(firstword $(BIN_GOALS_BINS)) else # NUM_BINS == 1 # More than one BIN directory was specified. We cannot handle the # latter case within a single make invocation, so set up recursive # targets for each BIN directory. Use exactly one target for each BIN # directory since running multiple make invocations within the same # BIN directory is likely to cause problems. # # Leave $(BIN) undefined. This has implications for any target that # depends on $(BIN); such targets should be made conditional upon the # existence of $(BIN). # BIN_GOALS_FIRST := $(foreach BGB,$(BIN_GOALS_BINS),\ $(firstword $(filter $(BGB)/%,$(BIN_GOALS)))) BIN_GOALS_OTHER := $(filter-out $(BIN_GOALS_FIRST),$(BIN_GOALS)) $(BIN_GOALS_FIRST) : % : BIN_RECURSE $(Q)$(MAKE) --no-print-directory BIN=$(firstword $(subst /, ,$@)) \ $(filter $(firstword $(subst /, ,$@))/%, $(BIN_GOALS)) $(BIN_GOALS_OTHER) : % : BIN_RECURSE $(Q)$(TRUE) .PHONY : BIN_RECURSE endif # NUM_BINS == 1 endif # NUM_BINS == 0 ifdef BIN # Create $(BIN) directory if it doesn't exist yet # ifeq ($(wildcard $(BIN)),) $(shell $(MKDIR) -p $(BIN)) endif # Target to allow e.g. "make bin-efi arch" # $(BIN) : @# Do nothing, silently .PHONY : $(BIN) # Remove everything in $(BIN) for a "make clean" # CLEANUP += $(BIN)/*.* # Avoid picking up directories endif # defined(BIN) # Determine whether or not we need to include the dependency files # NO_DEP_TARGETS := $(BIN) clean veryclean ifeq ($(MAKECMDGOALS),) NEED_DEPS := 1 endif ifneq ($(strip $(filter-out $(NO_DEP_TARGETS),$(MAKECMDGOALS))),) NEED_DEPS := 1 endif ############################################################################### # # Select build architecture and platform based on $(BIN) # # BIN has the form bin[-[arch-]platform] ARCHS := $(patsubst arch/%,%,$(wildcard arch/*)) PLATFORMS := $(patsubst config/defaults/%.h,%,\ $(wildcard config/defaults/*.h)) archs : @$(ECHO) $(ARCHS) platforms : @$(ECHO) $(PLATFORMS) ifdef BIN # Determine architecture portion of $(BIN), if present BIN_ARCH := $(strip $(foreach A,$(ARCHS),\ $(patsubst bin-$(A)-%,$(A),\ $(filter bin-$(A)-%,$(BIN))))) # Determine platform portion of $(BIN), if present ifeq ($(BIN_ARCH),) BIN_PLATFORM := $(patsubst bin-%,%,$(filter bin-%,$(BIN))) else BIN_PLATFORM := $(patsubst bin-$(BIN_ARCH)-%,%,$(BIN)) endif # Determine build architecture DEFAULT_ARCH := i386 ARCH := $(firstword $(BIN_ARCH) $(DEFAULT_ARCH)) CFLAGS += -DARCH=$(ARCH) arch : @$(ECHO) $(ARCH) .PHONY : arch # Determine build platform DEFAULT_PLATFORM := pcbios PLATFORM := $(firstword $(BIN_PLATFORM) $(DEFAULT_PLATFORM)) CFLAGS += -DPLATFORM=$(PLATFORM) platform : @$(ECHO) $(PLATFORM) endif # defined(BIN) # Include architecture-specific Makefile ifdef ARCH MAKEDEPS += arch/$(ARCH)/Makefile include arch/$(ARCH)/Makefile endif # Include architecture-specific include path ifdef ARCH INCDIRS += arch/$(ARCH)/include INCDIRS += arch/$(ARCH)/include/$(PLATFORM) endif ############################################################################### # # Source file handling # SRCDIRS lists all directories containing source files. srcdirs : @$(ECHO) $(SRCDIRS) # SRCS lists all .c or .S files found in any SRCDIR # SRCS += $(wildcard $(patsubst %,%/*.c,$(SRCDIRS))) SRCS += $(wildcard $(patsubst %,%/*.S,$(SRCDIRS))) srcs : @$(ECHO) $(SRCS) # AUTO_SRCS lists all files in SRCS that are not mentioned in # NON_AUTO_SRCS. Files should be added to NON_AUTO_SRCS if they # cannot be built using the standard build template. # AUTO_SRCS = $(filter-out $(NON_AUTO_SRCS),$(SRCS)) autosrcs : @$(ECHO) $(AUTO_SRCS) # Just about everything else in this section depends upon having # $(BIN) set ifdef BIN # INCDIRS lists the include path incdirs : @$(ECHO) $(INCDIRS) # Common flags # CFLAGS += $(foreach INC,$(INCDIRS),-I$(INC)) CFLAGS += -Os CFLAGS += -g ifeq ($(CCTYPE),gcc) CFLAGS += -ffreestanding CFLAGS += -Wall -W -Wformat-nonliteral HOST_CFLAGS += -Wall -W -Wformat-nonliteral endif ifeq ($(CCTYPE),icc) CFLAGS += -fno-builtin CFLAGS += -no-ip CFLAGS += -no-gcc CFLAGS += -diag-disable 111 # Unreachable code CFLAGS += -diag-disable 128 # Unreachable loop CFLAGS += -diag-disable 170 # Array boundary checks CFLAGS += -diag-disable 177 # Unused functions CFLAGS += -diag-disable 181 # printf() format checks CFLAGS += -diag-disable 188 # enum strictness CFLAGS += -diag-disable 193 # Undefined preprocessor identifiers CFLAGS += -diag-disable 280 # switch ( constant ) CFLAGS += -diag-disable 310 # K&R parameter lists CFLAGS += -diag-disable 424 # Extra semicolon CFLAGS += -diag-disable 589 # Declarations mid-code CFLAGS += -diag-disable 593 # Unused variables CFLAGS += -diag-disable 810 # Casting ints to smaller ints CFLAGS += -diag-disable 981 # Sequence point violations CFLAGS += -diag-disable 1292 # Ignored attributes CFLAGS += -diag-disable 1338 # void pointer arithmetic CFLAGS += -diag-disable 1361 # Variable-length arrays CFLAGS += -diag-disable 1418 # Missing prototypes CFLAGS += -diag-disable 1419 # Missing prototypes CFLAGS += -diag-disable 1599 # Hidden variables CFLAGS += -Wall -Wmissing-declarations endif CFLAGS += $(WORKAROUND_CFLAGS) $(EXTRA_CFLAGS) ASFLAGS += $(WORKAROUND_ASFLAGS) $(EXTRA_ASFLAGS) LDFLAGS += $(WORKAROUND_LDFLAGS) $(EXTRA_LDFLAGS) HOST_CFLAGS += -O2 -g # Inhibit -Werror if NO_WERROR is specified on make command line # ifneq ($(NO_WERROR),1) CFLAGS += -Werror ASFLAGS += --fatal-warnings HOST_CFLAGS += -Werror endif # Function trace recorder state in the last build. This is needed # in order to correctly rebuild whenever the function recorder is # enabled/disabled. # FNREC_STATE := $(BIN)/.fnrec.state ifeq ($(wildcard $(FNREC_STATE)),) FNREC_OLD := <invalid> else FNREC_OLD := $(shell cat $(FNREC_STATE)) endif ifeq ($(FNREC_OLD),$(FNREC)) $(FNREC_STATE) : else $(FNREC_STATE) : clean $(shell $(ECHO) "$(FNREC)" > $(FNREC_STATE)) endif VERYCLEANUP += $(FNREC_STATE) MAKEDEPS += $(FNREC_STATE) ifeq ($(FNREC),1) # Enabling -finstrument-functions affects gcc's analysis and leads to spurious # warnings about use of uninitialised variables. # CFLAGS += -Wno-uninitialized CFLAGS += -finstrument-functions CFLAGS += -finstrument-functions-exclude-file-list=core/fnrec.c endif # Enable per-item sections and section garbage collection. Note that # some older versions of gcc support -fdata-sections but treat it as # implying -fno-common, which would break our build. Some other older # versions issue a spurious and uninhibitable warning if # -ffunction-sections is used with -g, which would also break our # build since we use -Werror. # ifeq ($(CCTYPE),gcc) DS_TEST = $(ECHO) 'char x;' | \ $(CC) -fdata-sections -S -x c - -o - 2>/dev/null | \ grep -E '\.comm' > /dev/null DS_FLAGS := $(shell $(DS_TEST) && $(ECHO) '-fdata-sections') FS_TEST = $(CC) -ffunction-sections -g -c -x c /dev/null \ -o /dev/null 2>/dev/null FS_FLAGS := $(shell $(FS_TEST) && $(ECHO) '-ffunction-sections') CFLAGS += $(FS_FLAGS) $(DS_FLAGS) endif LDFLAGS += --gc-sections # Force creation of static binaries (required for OpenBSD, does no # harm on other platforms). # LDFLAGS += -static # compiler.h is needed for our linking and debugging system # CFLAGS += -include include/compiler.h # CFLAGS for specific object types # CFLAGS_c += CFLAGS_S += -DASSEMBLY # Base object name of the current target # OBJECT = $(firstword $(subst ., ,$(@F))) # CFLAGS for specific object files. You can define # e.g. CFLAGS_rtl8139, and have those flags automatically used when # compiling bin/rtl8139.o. # OBJ_CFLAGS = $(CFLAGS_$(OBJECT)) -DOBJECT=$(subst -,_,$(OBJECT)) $(BIN)/%.flags : @$(ECHO) $(OBJ_CFLAGS) # ICC requires postprocessing objects to fix up table alignments # ifeq ($(CCTYPE),icc) POST_O = && $(ICCFIX) $@ POST_O_DEPS := $(ICCFIX) else POST_O := POST_O_DEPS := endif # Rules for specific object types. # COMPILE_c = $(CC) $(CFLAGS) $(CFLAGS_c) $(OBJ_CFLAGS) RULE_c = $(Q)$(COMPILE_c) -c $< -o $@ $(POST_O) RULE_c_to_dbg%.o = $(Q)$(COMPILE_c) -DDBGLVL_MAX=$* -c $< -o $@ $(POST_O) RULE_c_to_c = $(Q)$(COMPILE_c) -E -c $< > $@ RULE_c_to_s = $(Q)$(COMPILE_c) -S -g0 -c $< -o $@ PREPROCESS_S = $(CPP) $(CFLAGS) $(CFLAGS_S) $(OBJ_CFLAGS) ASSEMBLE_S = $(AS) $(ASFLAGS) RULE_S = $(Q)$(PREPROCESS_S) $< | $(ASSEMBLE_S) -o $@ RULE_S_to_dbg%.o = $(Q)$(PREPROCESS_S) -DDBGLVL_MAX=$* $< | $(ASSEMBLE_S) -o $@ RULE_S_to_s = $(Q)$(PREPROCESS_S) $< > $@ DEBUG_TARGETS += dbg%.o c s # List of embedded images included in the last build of embedded.o. # This is needed in order to correctly rebuild embedded.o whenever the # list of objects changes. # EMBED := $(EMBEDDED_IMAGE) # Maintain backwards compatibility EMBEDDED_LIST := $(BIN)/.embedded.list ifeq ($(wildcard $(EMBEDDED_LIST)),) EMBED_OLD := <invalid> else EMBED_OLD := $(shell cat $(EMBEDDED_LIST)) endif ifneq ($(EMBED_OLD),$(EMBED)) $(shell $(ECHO) "$(EMBED)" > $(EMBEDDED_LIST)) endif $(EMBEDDED_LIST) : $(MAKEDEPS) VERYCLEANUP += $(EMBEDDED_LIST) EMBEDDED_FILES := $(subst $(COMMA), ,$(EMBED)) EMBED_ALL := $(foreach i,$(call seq,1,$(words $(EMBEDDED_FILES))),\ EMBED ( $(i), \"$(word $(i), $(EMBEDDED_FILES))\",\ \"$(notdir $(word $(i),$(EMBEDDED_FILES)))\" )) embedded_DEPS += $(EMBEDDED_FILES) $(EMBEDDED_LIST) CFLAGS_embedded = -DEMBED_ALL="$(EMBED_ALL)" # List of trusted root certificates # TRUSTED_LIST := $(BIN)/.trusted.list ifeq ($(wildcard $(TRUSTED_LIST)),) TRUST_OLD := <invalid> else TRUST_OLD := $(shell cat $(TRUSTED_LIST)) endif ifneq ($(TRUST_OLD),$(TRUST)) $(shell $(ECHO) "$(TRUST)" > $(TRUSTED_LIST)) endif $(TRUSTED_LIST) : $(MAKEDEPS) VERYCLEANUP += $(TRUSTED_LIST) # Trusted root certificate fingerprints # TRUSTED_CERTS := $(subst $(COMMA), ,$(TRUST)) TRUSTED_FPS := $(foreach CERT,$(TRUSTED_CERTS),\ 0x$(subst :,$(COMMA) 0x,$(lastword $(subst =, ,\ $(shell $(OPENSSL) x509 -in $(CERT) -noout -sha256 \ -fingerprint))))$(COMMA)) rootcert_DEPS += $(TRUSTED_FILES) $(TRUSTED_LIST) CFLAGS_rootcert = $(if $(TRUSTED_FPS),-DTRUSTED="$(TRUSTED_FPS)") # List of embedded certificates # CERT_LIST := $(BIN)/.certificate.list ifeq ($(wildcard $(CERT_LIST)),) CERT_OLD := <invalid> else CERT_OLD := $(shell cat $(CERT_LIST)) endif ifneq ($(CERT_OLD),$(CERT)) $(shell $(ECHO) "$(CERT)" > $(CERT_LIST)) endif $(CERT_LIST) : $(MAKEDEPS) VERYCLEANUP += $(CERT_LIST) # Embedded certificates concatenated and then split into one file per # certificate (even if original files contained certificate chains) # CERT_FILES := $(subst $(COMMA), ,$(CERT)) CERT_CONCAT := $(BIN)/.certificates.pem ifneq ($(CERT),) CERT_COUNT := $(shell grep "BEGIN CERTIFICATE" $(CERT_FILES) | wc -l) $(CERT_CONCAT) : $(CERT_FILES) $(CERT_LIST) $(Q)cat $(CERT_FILES) > $@ # We must use an (otherwise unnecessary) pattern rule here to encode # the fact that one "csplit" command generates multiple targets CERT_PEMS := $(foreach i,$(call seq,1,$(CERT_COUNT)),\ $(BIN)/.certificate.pem.$(i)) $(subst .pem.,.%.,$(CERT_PEMS)) : $(BIN)/.certificates.% $(Q)$(CSPLIT) -q -n 1 -f $(BIN)/.certificate.pem. $< \ '/BEGIN CERTIFICATE/' '{*}' CERT_DERS := $(subst .certificate.pem.,.certificate.der.,$(CERT_PEMS)) $(BIN)/.certificate.der.% : $(BIN)/.certificate.pem.% $(Q)$(OPENSSL) x509 -in $< -outform DER -out $@ CERT_ALL := $(foreach i,$(call seq,1,$(CERT_COUNT)),\ CERT ( $(i), \"$(word $(i),$(CERT_DERS))\" )) endif certstore_DEPS += $(CERT_LIST) $(CERT_FILES) $(CERT_PEMS) $(CERT_DERS) CFLAGS_certstore += -DCERT_ALL="$(CERT_ALL)" CLEANUP += $(BIN)/.certificate.* $(BIN)/.certificates.* # (Single-element) list of private keys # ifdef KEY PRIVKEY := $(KEY) # Maintain backwards compatibility endif PRIVKEY_LIST := $(BIN)/.private_key.list ifeq ($(wildcard $(PRIVKEY_LIST)),) PRIVKEY_OLD := <invalid> else PRIVKEY_OLD := $(shell cat $(PRIVKEY_LIST)) endif ifneq ($(PRIVKEY_OLD),$(PRIVKEY)) $(shell $(ECHO) "$(PRIVKEY)" > $(PRIVKEY_LIST)) endif $(PRIVKEY_LIST) : $(MAKEDEPS) VERYCLEANUP += $(PRIVKEY_LIST) # Embedded private key # PRIVKEY_INC := $(BIN)/.private_key.der ifdef PRIVKEY $(PRIVKEY_INC) : $(PRIVKEY) $(PRIVKEY_LIST) $(Q)$(OPENSSL) rsa -in $< -outform DER -out $@ privkey_DEPS += $(PRIVKEY_INC) endif CLEANUP += $(BIN)/.private_key.* privkey_DEPS += $(PRIVKEY_LIST) CFLAGS_privkey += $(if $(PRIVKEY),-DPRIVATE_KEY="\"$(PRIVKEY_INC)\"") # (Single-element) list of named configurations # CONFIG_LIST := $(BIN)/.config.list ifeq ($(wildcard $(CONFIG_LIST)),) CONFIG_OLD := <invalid> else CONFIG_OLD := $(shell cat $(CONFIG_LIST)) endif ifneq ($(CONFIG_OLD),$(CONFIG)) $(shell $(ECHO) "$(CONFIG)" > $(CONFIG_LIST)) endif $(CONFIG_LIST) : $(MAKEDEPS) VERYCLEANUP += $(CONFIG_LIST) # Named configurations # ifneq ($(CONFIG),) ifneq ($(wildcard config/$(CONFIG)),) CFLAGS += -DCONFIG=$(CONFIG) endif CFLAGS += -DLOCAL_CONFIG=$(CONFIG) endif config/named.h : $(CONFIG_LIST) $(Q)$(TOUCH) $@ .PRECIOUS : config/named.h # These files use .incbin inline assembly to include a binary file. # Unfortunately ccache does not detect this dependency and caches # builds even when the binary file has changed. # $(BIN)/embedded.% : override CC := env CCACHE_DISABLE=1 $(CC) $(BIN)/certstore.% : override CC := env CCACHE_DISABLE=1 $(CC) $(BIN)/privkey.% : override CC := env CCACHE_DISABLE=1 $(CC) # Debug message autocolourisation range # DBGCOL_LIST := $(BIN)/.dbgcol.list ifeq ($(wildcard $(DBGCOL_LIST)),) DBGCOL_OLD := <invalid> else DBGCOL_OLD := $(shell cat $(DBGCOL_LIST)) endif ifneq ($(DBGCOL_OLD),$(DBGCOL)) $(shell $(ECHO) "$(DBGCOL)" > $(DBGCOL_LIST)) endif $(DBGCOL_LIST) : $(MAKEDEPS) VERYCLEANUP += $(DBGCOL_LIST) DBGCOL_COLOURS := $(subst -, ,$(DBGCOL)) DBGCOL_MIN := $(word 1,$(DBGCOL_COLOURS)) DBGCOL_MAX := $(word 2,$(DBGCOL_COLOURS)) debug_DEPS += $(DBGCOL_LIST) CFLAGS_debug += $(if $(DBGCOL_MIN),-DDBGCOL_MIN=$(DBGCOL_MIN)) CFLAGS_debug += $(if $(DBGCOL_MAX),-DDBGCOL_MAX=$(DBGCOL_MAX)) # We automatically generate rules for any file mentioned in AUTO_SRCS # using the following set of templates. We use $(eval ...) if # available, otherwise we generate separate Makefile fragments and # include them. # deps_template : generate dependency list for a given source file # # $(1) is the full path to the source file (e.g. "drivers/net/rtl8139.c") # define deps_template_file $(call deps_template_parts,$(1),$(subst .,,$(suffix $(1))),$(basename $(notdir $(1)))) endef # # $(1) is the full path to the source file (e.g. "drivers/net/rtl8139.c") # $(2) is the source type (e.g. "c") # $(3) is the source base name (e.g. "rtl8139") # define deps_template_parts @$(ECHO) " [DEPS] $(1)" @$(MKDIR) -p $(BIN)/deps/$(dir $(1)) $(Q)$(CPP) $(CFLAGS) $(CFLAGS_$(2)) $(CFLAGS_$(3)) -DOBJECT=$(3) \ -Wno-error -M $(1) -MG -MP | \ sed 's/\.o\s*:/_DEPS +=/' > $(BIN)/deps/$(1).d $(Q)$(if $(findstring drivers/,$(1)),\ $(PERL) $(PARSEROM) $(1) >> $(BIN)/deps/$(1).d) endef # rules_template : generate rules for a given source file # # $(1) is the full path to the source file (e.g. "drivers/net/rtl8139.c") # define rules_template $(call rules_template_parts,$(1),$(subst .,,$(suffix $(1))),$(basename $(notdir $(1)))) endef # # $(1) is the full path to the source file (e.g. "drivers/net/rtl8139.c") # $(2) is the source type (e.g. "c") # $(3) is the source base name (e.g. "rtl8139") # define rules_template_parts $$(BIN)/$(3).o : $(1) $$(MAKEDEPS) $$(POST_O_DEPS) $$($(3)_DEPS) $$(QM)$(ECHO) " [BUILD] $$@" $$(RULE_$(2)) BOBJS += $$(BIN)/$(3).o $(foreach TGT,$(DEBUG_TARGETS),$(if $(RULE_$(2)_to_$(TGT)),$(NEWLINE)$(call rules_template_target,$(1),$(2),$(3),$(TGT)))) $$(BIN)/deps/$(1).d : $$($(3)_DEPS) TAGS : $$($(3)_DEPS) endef # # $(1) is the full path to the source file (e.g. "drivers/net/rtl8139.c") # $(2) is the source type (e.g. "c") # $(3) is the source base name (e.g. "rtl8139") # $(4) is the destination type (e.g. "dbg%.o") # define rules_template_target $$(BIN)/$(3).$(4) : $(1) $$(MAKEDEPS) $$(POST_O_DEPS) $$($(3)_DEPS) $$(QM)$(ECHO) " [BUILD] $$@" $$(RULE_$(2)_to_$(4)) $(TGT)_OBJS += $$(BIN)/$(3).$(4) endef # # $(1) is the full path to the source file (e.g. "drivers/net/rtl8139.c") # define rules_template_file @$(ECHO) " [RULES] $(1)" @$(MKDIR) -p $(BIN)/rules/$(dir $(1)) @$(ECHO_E) '$(subst $(NEWLINE),\n,$(call rules_template,$(1)))' \ > $(BIN)/rules/$(1).r endef # Generate the dependency files # $(BIN)/deps/%.d : % $(MAKEDEPS) $(PARSEROM) $(call deps_template_file,$<) # Calculate list of dependency files # AUTO_DEPS = $(patsubst %,$(BIN)/deps/%.d,$(AUTO_SRCS)) autodeps : @$(ECHO) $(AUTO_DEPS) VERYCLEANUP += $(BIN)/deps # Include dependency files # ifdef NEED_DEPS ifneq ($(AUTO_DEPS),) -include $(AUTO_DEPS) endif endif # Generate the rules files # $(BIN)/rules/%.r : % $(MAKEDEPS) $(call rules_template_file,$<) # Calculate list of rules files # AUTO_RULES = $(patsubst %,$(BIN)/rules/%.r,$(AUTO_SRCS)) autorules : @$(ECHO) $(AUTO_RULES) VERYCLEANUP += $(BIN)/rules # Evaluate rules (or include rules files) # ifdef NEED_DEPS ifneq ($(AUTO_RULES),) ifneq ($(HAVE_EVAL),) $(foreach SRC,$(AUTO_SRCS),$(eval $(call rules_template,$(SRC)))) else -include $(AUTO_RULES) endif endif endif # The following variables are created by the rules files # bobjs : @$(ECHO) $(BOBJS) drivers : @$(ECHO) $(DRIVERS) .PHONY : drivers roms : @$(ECHO) $(ROMS) # Generate error usage information # $(BIN)/%.einfo : $(BIN)/%.o $(QM)$(ECHO) " [EINFO] $@" $(Q)$(OBJCOPY) -O binary -j .einfo --set-section-flags .einfo=alloc \ $< $@ EINFOS := $(patsubst $(BIN)/%.o,$(BIN)/%.einfo,$(BOBJS)) $(BIN)/errors : $(EINFOS) $(EINFO) $(QM)$(ECHO) " [EINFO] $@" $(Q)$(EINFO) $(EINFOS) | sort > $@ CLEANUP += $(BIN)/errors # Doesn't match the $(BIN)/*.* pattern # Generate the NIC file from the parsed source files. The NIC file is # only for rom-o-matic. # $(BIN)/NIC : $(AUTO_DEPS) @$(ECHO) '# This is an automatically generated file, do not edit' > $@ @$(ECHO) '# It does not affect anything in the build, ' \ 'it is only for rom-o-matic' >> $@ @$(ECHO) >> $@ @perl -ne 'chomp; print "$$1\n" if /\# NIC\t(.*)$$/' $^ >> $@ CLEANUP += $(BIN)/NIC # Doesn't match the $(BIN)/*.* pattern # Analyse a target name (e.g. "bin/dfe538--prism2_pci.rom.tmp") and # derive the variables: # # TGT_ELEMENTS : the elements of the target (e.g. "dfe538 prism2_pci") # TGT_PREFIX : the prefix type (e.g. "pcirom") # TGT_DRIVERS : the driver for each element (e.g. "rtl8139 prism2_pci") # TGT_ROM_NAME : the ROM name (e.g. "dfe538") # DRIVERS_ipxe = $(DRIVERS) CARD_DRIVER = $(firstword $(DRIVER_$(1)) $(1)) TGT_ELEMENTS = $(subst --, ,$(firstword $(subst ., ,$(notdir $@)))) TGT_ROM_NAME = $(firstword $(TGT_ELEMENTS)) TGT_DRIVERS = $(strip $(if $(DRIVERS_$(TGT_ROM_NAME)), \ $(DRIVERS_$(TGT_ROM_NAME)), \ $(foreach TGT_ELEMENT,$(TGT_ELEMENTS), \ $(call CARD_DRIVER,$(TGT_ELEMENT))) )) TGT_PREFIX_NAME = $(word 2,$(subst ., ,$(notdir $@))) TGT_PREFIX = $(strip $(if $(filter rom,$(TGT_PREFIX_NAME)), \ $(ROM_TYPE_$(TGT_ROM_NAME))rom, \ $(TGT_PREFIX_NAME))) # Look up ROM IDs for the current target # (e.g. "bin/dfe538--prism2_pci.rom.tmp") and derive the variables: # # TGT_PCI_VENDOR : the PCI vendor ID (e.g. "0x1186") # TGT_PCI_DEVICE : the PCI device ID (e.g. "0x1300") # TGT_PCI_VENDOR = $(PCI_VENDOR_$(TGT_ROM_NAME)) TGT_PCI_DEVICE = $(PCI_DEVICE_$(TGT_ROM_NAME)) # Calculate link-time options for the current target # (e.g. "bin/dfe538--prism2_pci.rom.tmp") and derive the variables: # # TGT_LD_DRIVERS : symbols to require in order to drag in the relevant drivers # (e.g. "obj_rtl8139 obj_prism2_pci") # TGT_LD_IDS : symbols to define in order to fill in ID structures in the # ROM header (e.g."pci_vendor_id=0x1186 pci_device_id=0x1300") # TGT_LD_DRIVERS = $(subst -,_,$(patsubst %,obj_%,$(TGT_DRIVERS))) TGT_LD_IDS = pci_vendor_id=$(firstword $(TGT_PCI_VENDOR) 0) \ pci_device_id=$(firstword $(TGT_PCI_DEVICE) 0) ifndef TGT_LD_ENTRY TGT_LD_ENTRY = _$(TGT_PREFIX)_start endif # Calculate linker flags based on link-time options for the current # target type (e.g. "bin/dfe538--prism2_pci.rom.tmp") and derive the # variables: # # TGT_LD_FLAGS : target-specific flags to pass to linker (e.g. # "-u obj_zpciprefix -u obj_rtl8139 -u obj_prism2_pci # --defsym pci_vendor=0x1186 --defsym pci_device=0x1300") # TGT_LD_FLAGS = $(foreach SYM,$(TGT_LD_ENTRY) $(TGT_LD_DRIVERS) obj_config,\ -u $(SYM) --defsym check_$(SYM)=$(SYM) ) \ $(patsubst %,--defsym %,$(TGT_LD_IDS)) \ -e $(TGT_LD_ENTRY) # Calculate list of debugging versions of objects to be included in # the target. # DEBUG_LIST = $(subst $(COMMA), ,$(DEBUG)) DEBUG_OBJ_LEVEL = $(firstword $(word 2,$(subst :, ,$(1))) 1) DEBUG_OBJ_BASE = $(word 1,$(subst :, ,$(1))).dbg$(call DEBUG_OBJ_LEVEL,$(1)) DEBUG_OBJ = $(BIN)/$(call DEBUG_OBJ_BASE,$(1)).o DEBUG_ORIG_OBJ = $(BIN)/$(word 1,$(subst :, ,$(1))).o DEBUG_OBJS = $(foreach D,$(DEBUG_LIST),$(call DEBUG_OBJ,$(D))) DEBUG_ORIG_OBJS = $(foreach D,$(DEBUG_LIST),$(call DEBUG_ORIG_OBJ,$(D))) BLIB_OBJS = $(DEBUG_OBJS) $(filter-out $(DEBUG_ORIG_OBJS),$(BOBJS)) # Print out all derived information for a given target. # $(BIN)/%.info : @$(ECHO) 'Elements : $(TGT_ELEMENTS)' @$(ECHO) 'Prefix : $(TGT_PREFIX)' @$(ECHO) 'Drivers : $(TGT_DRIVERS)' @$(ECHO) 'ROM name : $(TGT_ROM_NAME)' @$(ECHO) @$(ECHO) 'PCI vendor : $(TGT_PCI_VENDOR)' @$(ECHO) 'PCI device : $(TGT_PCI_DEVICE)' @$(ECHO) @$(ECHO) 'LD driver symbols : $(TGT_LD_DRIVERS)' @$(ECHO) 'LD ID symbols : $(TGT_LD_IDS)' @$(ECHO) 'LD entry point : $(TGT_LD_ENTRY)' @$(ECHO) @$(ECHO) 'LD target flags : $(TGT_LD_FLAGS)' @$(ECHO) @$(ECHO) 'Debugging objects : $(DEBUG_OBJS)' @$(ECHO) 'Replaced objects : $(DEBUG_ORIG_OBJS)' # List of objects included in the last build of blib. This is needed # in order to correctly rebuild blib whenever the list of objects # changes. # BLIB_LIST := $(BIN)/.blib.list ifeq ($(wildcard $(BLIB_LIST)),) BLIB_OBJS_OLD := <invalid> else BLIB_OBJS_OLD := $(shell cat $(BLIB_LIST)) endif ifneq ($(BLIB_OBJS_OLD),$(BLIB_OBJS)) $(shell $(ECHO) "$(BLIB_OBJS)" > $(BLIB_LIST)) endif $(BLIB_LIST) : $(MAKEDEPS) VERYCLEANUP += $(BLIB_LIST) # Library of all objects # BLIB = $(BIN)/blib.a $(BLIB) : $(BLIB_OBJS) $(BLIB_LIST) $(MAKEDEPS) $(Q)$(RM) $(BLIB) $(QM)$(ECHO) " [AR] $@" $(Q)$(AR) r $@ $(BLIB_OBJS) $(Q)$(RANLIB) $@ blib : $(BLIB) # Command to generate build ID. Must be unique for each $(BIN)/%.tmp, # even within the same build run. # BUILD_ID_CMD := perl -e 'printf "0x%08x", int ( rand ( 0xffffffff ) );' # Build timestamp # BUILD_TIMESTAMP := $(shell date +%s) # Build version # GIT_INDEX := $(if $(GITVERSION),$(if $(wildcard ../.git/index),../.git/index)) $(BIN)/version.%.o : core/version.c $(MAKEDEPS) $(GIT_INDEX) $(QM)$(ECHO) " [VERSION] $@" $(Q)$(COMPILE_c) -DBUILD_NAME="\"$*\"" \ -DVERSION_MAJOR=$(VERSION_MAJOR) \ -DVERSION_MINOR=$(VERSION_MINOR) \ -DVERSION_PATCH=$(VERSION_PATCH) \ -DVERSION="\"$(VERSION)\"" \ -c $< -o $@ # Build an intermediate object file from the objects required for the # specified target. # $(BIN)/%.tmp : $(BIN)/version.%.o $(BLIB) $(MAKEDEPS) $(LDSCRIPT) $(QM)$(ECHO) " [LD] $@" $(Q)$(LD) $(LDFLAGS) -T $(LDSCRIPT) $(TGT_LD_FLAGS) $< $(BLIB) -o $@ \ --defsym _build_id=`$(BUILD_ID_CMD)` \ --defsym _build_timestamp=$(BUILD_TIMESTAMP) \ -Map $(BIN)/$*.tmp.map $(Q)$(OBJDUMP) -ht $@ | $(PERL) $(SORTOBJDUMP) >> $(BIN)/$*.tmp.map # Keep intermediate object file (useful for debugging) .PRECIOUS : $(BIN)/%.tmp # Show a linker map for the specified target # $(BIN)/%.map : $(BIN)/%.tmp @less $(BIN)/$*.tmp.map # Get objects list for the specified target # define objs_list $(sort $(foreach OBJ_SYMBOL,\ $(filter obj_%,$(shell $(NM) $(1) | cut -d" " -f3)),\ $(patsubst obj_%,%,$(OBJ_SYMBOL)))) endef $(BIN)/%.objs : $(BIN)/%.tmp $(Q)$(ECHO) $(call objs_list,$<) $(BIN)/%.sizes : $(BIN)/%.tmp $(Q)$(SIZE) -t $(foreach OBJ,$(call objs_list,$<),$(wildcard $(BIN)/$(subst _,?,$(OBJ)).o)) | \ sort -g # Get dependency list for the specified target # define deps_list $(sort $(foreach OBJ,$(call objs_list,$(1)),$($(OBJ)_DEPS))) endef $(BIN)/%.deps : $(BIN)/%.tmp $(Q)$(ECHO) $(call deps_list,$<) # Get unneeded source files for the specified target # define nodeps_list $(sort $(filter-out $(call deps_list,$(1)),\ $(foreach BOBJ,$(BOBJS),\ $($(basename $(notdir $(BOBJ)))_DEPS)))) endef $(BIN)/%.nodeps : $(BIN)/%.tmp $(Q)$(ECHO) $(call nodeps_list,$<) # Get licensing verdict for the specified target # define licensable_deps_list $(filter-out config/local/%.h,\ $(filter-out $(BIN)/.%.list,\ $(call deps_list,$(1)))) endef define unlicensed_deps_list $(shell grep -L FILE_LICENCE $(call licensable_deps_list,$(1))) endef define licence_list $(sort $(foreach LICENCE,\ $(filter __licence__%,$(shell $(NM) $(1) | cut -d" " -f3)),\ $(word 2,$(subst __, ,$(LICENCE))))) endef $(BIN)/%.licence_list : $(BIN)/%.tmp $(Q)$(ECHO) $(call licence_list,$<) $(BIN)/%.licence : $(BIN)/%.tmp $(QM)$(ECHO) " [LICENCE] $@" $(Q)$(if $(strip $(call unlicensed_deps_list,$<)),\ echo -n "Unable to determine licence because the following " ;\ echo "files are missing a licence declaration:" ;\ echo $(call unlicensed_deps_list,$<);\ exit 1,\ $(PERL) $(LICENCE) $(call licence_list,$<)) # Extract compression information from intermediate object file # $(BIN)/%.zinfo : $(BIN)/%.tmp $(QM)$(ECHO) " [ZINFO] $@" $(Q)$(OBJCOPY) -O binary -j .zinfo $< $@ # Build raw binary file from intermediate object file # $(BIN)/%.bin : $(BIN)/%.tmp $(QM)$(ECHO) " [BIN] $@" $(Q)$(OBJCOPY) -O binary -R .zinfo $< $@ # Compress raw binary file # $(BIN)/%.zbin : $(BIN)/%.bin $(BIN)/%.zinfo $(ZBIN) $(QM)$(ECHO) " [ZBIN] $@" $(Q)$(ZBIN) $(BIN)/$*.bin $(BIN)/$*.zinfo > $@ # Rules for each media format. These are generated and placed in an # external Makefile fragment. We could do this via $(eval ...), but # that would require make >= 3.80. # # Note that there's an alternative way to generate most .rom images: # they can be copied from their 'master' ROM image using cp and # reprocessed with makerom to add the PCI IDs and ident string. The # relevant rule would look something like: # # $(BIN)/dfe538%rom : $(BIN)/rtl8139%rom # cat $< $@ # $(FINALISE_rom) # # You can derive the ROM/driver relationships using the variables # DRIVER_<rom> and/or ROMS_<driver>. # # We don't currently do this, because (a) it would require generating # yet more Makefile fragments (since you need a rule for each ROM in # ROMS), and (b) the linker is so fast that it probably wouldn't make # much difference to the overall build time. # Add NON_AUTO_MEDIA to the media list, so that they show up in the # output of "make" # MEDIA += $(NON_AUTO_MEDIA) media : @$(ECHO) $(MEDIA) AUTO_MEDIA = $(filter-out $(NON_AUTO_MEDIA),$(MEDIA)) automedia : @$(ECHO) $(AUTO_MEDIA) # media_template : create media rules # # $(1) is the media name (e.g. "rom") # define media_template $(if $(filter $(1),$(AUTO_MEDIA)),$(call auto_media_template,$(1))) LIST_$(1) := $$(if $$(LIST_NAME_$(1)),$$($$(LIST_NAME_$(1))),$$(DRIVERS)) ALL_$(1) = $$(foreach ITEM,$$(LIST_$(1)),$$(BIN)/$$(ITEM).$(1)) $$(BIN)/all$(1)s : $$(ALL_$(1)) $$(BIN)/allall : $$(BIN)/all$(1)s all$(1)s : $$(BIN)/all$(1)s allall : $$(BIN)/allall endef # # $(1) is the media name (e.g. "rom") # define auto_media_template $$(BIN)/%.$(1) : $$(BIN)/%.$(1).zbin $$(QM)echo " [FINISH] $$@" $$(Q)$$(CP) $$< $$@ $$(Q)$$(if $$(PAD_$(1)),$$(PAD_$(1)) $$@) $$(Q)$$(if $$(FINALISE_$(1)),$$(FINALISE_$(1)) $$@) endef # # $(1) is the media name (e.g. "rom") # define media_template_file @$(ECHO) " [MEDIARULES] $(1)" @$(MKDIR) -p $(BIN)/rules/$(dir $(1)) @$(ECHO_E) '$(subst $(NEWLINE),\n,$(call media_template,$(1)))' \ > $(BIN)/rules/$(1).media.r endef # Generate media rules files # $(BIN)/rules/%.media.r : $(MAKEDEPS) $(call media_template_file,$*) # Calculate list of media rules files # MEDIA_RULES = $(patsubst %,$(BIN)/rules/%.media.r,$(MEDIA)) mediarules : @$(ECHO) $(MEDIA_RULES) # Evaluate media rules (or include media rules files) # ifdef NEED_DEPS ifneq ($(MEDIA_RULES),) ifneq ($(HAVE_EVAL),) $(foreach MEDIUM,$(MEDIA),$(eval $(call media_template,$(MEDIUM)))) else -include $(MEDIA_RULES) endif endif endif # Alias for ipxe.% # $(BIN)/etherboot.% : $(BIN)/ipxe.% ln -sf $(notdir $<) $@ endif # defined(BIN) ############################################################################### # # The compression utilities # $(NRV2B) : util/nrv2b.c $(MAKEDEPS) $(QM)$(ECHO) " [HOSTCC] $@" $(Q)$(HOST_CC) $(HOST_CFLAGS) -DENCODE -DDECODE -DMAIN -DVERBOSE \ -DNDEBUG -DBITSIZE=32 -DENDIAN=0 -o $@ $< CLEANUP += $(NRV2B) $(ZBIN) : util/zbin.c util/nrv2b.c $(MAKEDEPS) $(QM)$(ECHO) " [HOSTCC] $@" $(Q)$(HOST_CC) $(HOST_CFLAGS) -o $@ $< CLEANUP += $(ZBIN) ############################################################################### # # The EFI image converter # ELF2EFI_CFLAGS := -I$(BINUTILS_DIR)/include -I$(BFD_DIR)/include \ -I$(ZLIB_DIR)/include -idirafter include ELF2EFI_LDFLAGS := -L$(BINUTILS_DIR)/lib -L$(BFD_DIR)/lib -L$(ZLIB_DIR)/lib \ -lbfd -ldl -liberty -lz -Wl,--no-warn-search-mismatch $(ELF2EFI32) : util/elf2efi.c $(MAKEDEPS) $(QM)$(ECHO) " [HOSTCC] $@" $(Q)$(HOST_CC) $(HOST_CFLAGS) $(ELF2EFI_CFLAGS) -DEFI_TARGET_IA32 $< \ $(ELF2EFI_LDFLAGS) -o $@ CLEANUP += $(ELF2EFI32) $(ELF2EFI64) : util/elf2efi.c $(MAKEDEPS) $(QM)$(ECHO) " [HOSTCC] $@" $(Q)$(HOST_CC) $(HOST_CFLAGS) $(ELF2EFI_CFLAGS) -DEFI_TARGET_X64 $< \ $(ELF2EFI_LDFLAGS) -o $@ CLEANUP += $(ELF2EFI64) $(EFIROM) : util/efirom.c $(MAKEDEPS) $(QM)$(ECHO) " [HOSTCC] $@" $(Q)$(HOST_CC) $(HOST_CFLAGS) -idirafter include -o $@ $< CLEANUP += $(EFIROM) $(EFIFATBIN) : util/efifatbin.c $(MAKEDEPS) $(QM)$(ECHO) " [HOSTCC] $@" $(Q)$(HOST_CC) $(HOST_CFLAGS) -idirafter include -o $@ $< CLEANUP += $(EFIFATBIN) ############################################################################### # # The ICC fixup utility # $(ICCFIX) : util/iccfix.c $(MAKEDEPS) $(QM)$(ECHO) " [HOSTCC] $@" $(Q)$(HOST_CC) $(HOST_CFLAGS) -idirafter include -o $@ $< CLEANUP += $(ICCFIX) ############################################################################### # # The error usage information utility # $(EINFO) : util/einfo.c $(MAKEDEPS) $(QM)$(ECHO) " [HOSTCC] $@" $(Q)$(HOST_CC) $(HOST_CFLAGS) -idirafter include -o $@ $< CLEANUP += $(EINFO) ############################################################################### # # Local configs # CONFIG_HEADERS := $(patsubst config/%,%,$(wildcard config/*.h)) CONFIG_LOCAL_HEADERS := $(foreach HEADER,$(CONFIG_HEADERS),\ config/local/$(HEADER)) $(CONFIG_LOCAL_HEADERS) : $(Q)$(TOUCH) $@ .PRECIOUS : $(CONFIG_LOCAL_HEADERS) ifneq ($(CONFIG),) CONFIG_LOCAL_NAMED_HEADERS := $(foreach HEADER,$(CONFIG_HEADERS),\ config/local/$(CONFIG)/$(HEADER)) $(CONFIG_LOCAL_NAMED_HEADERS) : $(Q)$(MKDIR) -p $(dir $@) $(Q)$(TOUCH) $@ .PRECIOUS : $(CONFIG_LOCAL_NAMED_HEADERS) endif ############################################################################### # # Auto-incrementing build serial number. Append "bs" to your list of # build targets to get a serial number printed at the end of the # build. Enable -DBUILD_SERIAL in order to see it when the code runs. # BUILDSERIAL_H = config/.buildserial.h BUILDSERIAL_NOW = config/.buildserial.now BUILDSERIAL_NEXT = config/.buildserial.next $(BUILDSERIAL_NOW) $(BUILDSERIAL_NEXT) : $(ECHO) 1 > $@ $(BUILDSERIAL_H) : $(BUILDSERIAL_NOW) $(BUILDSERIAL_NEXT) $(ECHO) '#define BUILD_SERIAL_NUM $(shell cat $<)' > $@ ifeq ($(filter bs,$(MAKECMDGOALS)),bs) $(shell diff -q $(BUILDSERIAL_NOW) $(BUILDSERIAL_NEXT) > /dev/null || \ cp -f $(BUILDSERIAL_NEXT) $(BUILDSERIAL_NOW)) endif bs : $(BUILDSERIAL_NOW) @$(ECHO) $$(( $(shell cat $<) + 1 )) > $(BUILDSERIAL_NEXT) @$(ECHO) "Build serial number is $(shell cat $<)" ############################################################################### # # Build the TAGS file(s) for emacs # TAGS : ctags -e -R -f $@ --exclude=bin CLEANUP += TAGS ############################################################################### # # Force rebuild for any given target # %.rebuild : rm -f $* $(Q)$(MAKE) $* ############################################################################### # # Symbol table checks # ifdef BIN SYMTAB = $(BIN)/symtab $(SYMTAB) : $(BLIB) $(OBJDUMP) -w -t $< > $@ CLEANUP += $(BIN)/symtab symcheck : $(SYMTAB) $(PERL) $(SYMCHECK) $< endif # defined(BIN) ############################################################################### # # Build bochs symbol table # ifdef BIN $(BIN)/%.bxs : $(BIN)/%.tmp $(NM) $< | cut -d" " -f1,3 > $@ endif # defined(BIN) ############################################################################### # # Documentation # ifdef BIN $(BIN)/doxygen.cfg : doxygen.cfg $(MAKEDEPS) $(Q)$(PERL) -pe 's{\@SRCDIRS\@}{$(SRCDIRS)}; ' \ -e 's{\@INCDIRS\@}{$(filter-out .,$(INCDIRS))}; ' \ -e 's{\@BIN\@}{$(BIN)}; ' \ -e 's{\@ARCH\@}{$(ARCH)}; ' \ $< > $@ $(BIN)/doc : $(BIN)/doxygen.cfg $(Q)$(DOXYGEN) $< .PHONY : $(BIN)/doc doc : $(BIN)/doc doc-clean : $(Q)$(RM) -r $(BIN)/doc VERYCLEANUP += $(BIN)/doc docview : @[ -f $(BIN)/doc/html/index.html ] || $(MAKE) $(BIN)/doc @if [ -n "$$BROWSER" ] ; then \ ( $$BROWSER $(BIN)/doc/html/index.html & ) ; \ else \ $(ECHO) "Documentation index in $(BIN)/doc/html/index.html" ; \ fi endif # defined(BIN) ############################################################################### # # Keyboard maps # hci/keymap/keymap_%.c : $(Q)$(PERL) $(GENKEYMAP) $* > $@ ############################################################################### # # Force deletion of incomplete targets # .DELETE_ON_ERROR : ############################################################################### # # Clean-up # ifeq ($(NUM_BINS),0) ALLBINS := bin{,-*} CLEANUP := $(patsubst $(BIN)/%,$(ALLBINS)/%,$(CLEANUP)) VERYCLEANUP := $(patsubst $(BIN)/%,$(ALLBINS)/%,$(VERYCLEANUP)) endif clean : $(RM) $(CLEANUP) veryclean : clean $(RM) -r $(VERYCLEANUP) ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/net/discovery/efi_discovery_prefix.c��������������������������������������������������0000664�0001750�0001750�00000010042�12626644770�022475� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2009 Michael Brown <mbrown@fensystems.co.uk>. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ FILE_LICENCE ( GPL2_OR_LATER ); #include <stdlib.h> #include <ipxe/efi/efi_driver.h> #include <ipxe/efi/efi_snp.h> #include <ipxe/efi/efi_strings.h> #include <ipxe/umalloc.h> #include <ipxe/uri.h> #include <ipxe/init.h> #include <usr/ifmgmt.h> #include <usr/route.h> #include <usr/autoboot.h> #define MAX_EXIT_BUFFER_SIZE 256 /** * Close all open net devices * * Called before a fresh boot attempt in order to free up memory. We * don't just close the device immediately after the boot fails, * because there may still be TCP connections in the process of * closing. */ static void close_all_netdevs ( void ) { struct net_device *netdev; for_each_netdev ( netdev ) { ifclose ( netdev ); } } static struct uri* try_getting_next_server ( struct net_device *netdev ) { struct uri *filename; /* Close all other network devices */ close_all_netdevs(); /* Open device and display device status */ if ( ifopen ( netdev ) != 0 ) goto err_ifopen; ifstat ( netdev ); /* Configure device */ if (ifconf ( netdev, NULL )!= 0 ) goto err_dhcp; route(); /* Fetch next server and filename */ filename = fetch_next_server_and_filename ( NULL ); if ( ! filename ) goto err_filename; if ( ! uri_has_path ( filename ) ) { /* Ignore empty filename */ uri_put ( filename ); filename = NULL; } return filename; err_filename: err_dhcp: err_ifopen: return NULL; } static struct uri* efi_discover ( void ) { struct net_device *netdev; struct uri* filename = NULL; for_each_netdev ( netdev ) { filename = try_getting_next_server ( netdev ); } return filename; } /** * EFI entry point * * @v image_handle Image handle * @v systab System table * @ret efirc EFI return status code */ EFI_STATUS EFIAPI _efi_discovery_start ( EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *systab ) { EFI_STATUS efirc; struct uri* filename; userptr_t user_buf; wchar_t* exit_buf; /* Initialise EFI environment */ if ( ( efirc = efi_init ( image_handle, systab ) ) != 0 ) goto err_init; if ( ( user_buf = umalloc(MAX_EXIT_BUFFER_SIZE*2) ) == 0) { efirc = EFI_OUT_OF_RESOURCES; goto err_init; } exit_buf = (wchar_t *)user_to_phys(user_buf,0); initialise(); startup(); if ( ( filename = efi_discover() ) == NULL) { efirc = EFI_NOT_FOUND; goto err_filename; } efi_snp_release(); efi_loaded_image->Unload ( image_handle ); efi_driver_reconnect_all(); efi_snprintf(exit_buf,MAX_EXIT_BUFFER_SIZE,"%s - %s", filename->host, filename->path); uri_put(filename); systab->BootServices->Exit(image_handle, efirc, MAX_EXIT_BUFFER_SIZE, (CHAR16 *) exit_buf); err_filename: err_init: systab->BootServices->Exit(image_handle, efirc, 0, NULL); return efirc; } /** * Probe EFI root bus * * @v rootdev EFI root device */ static int efi_probe ( struct root_device *rootdev __unused ) { return efi_driver_connect_all(); } /** * Remove EFI root bus * * @v rootdev EFI root device */ static void efi_remove ( struct root_device *rootdev __unused ) { efi_driver_disconnect_all(); } /** EFI root device driver */ static struct root_driver efi_root_driver = { .probe = efi_probe, .remove = efi_remove, }; /** EFI root device */ struct root_device efi_root_device __root_device = { .dev = { .name = "EFI" }, .driver = &efi_root_driver, }; ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/net/discovery/console.h���������������������������������������������������������������0000664�0001750�0001750�00000000023�12626644770�017733� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#undef CONSOLE_EFI �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/net/Makefile��������������������������������������������������������������������������0000664�0001750�0001750�00000001337�12626644770�015562� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������IPXE_GIT=git://git.ipxe.org/ipxe.git EFI_PREFIX=efi_discovery_prefix.c EFI_DISCOVERY_BINARY=ipxe_discovery.efi EFI_DISCOVERY_ENTRY=_efi_discovery_start IPXE_SRC = ipxe source: rm -rf $(IPXE_SRC)/ git clone $(IPXE_GIT) cp discovery/$(EFI_PREFIX) ipxe/src/arch/x86/prefix/ cp discovery/Makefile.housekeeping ipxe/src/Makefile.housekeeping netboot: mkdir -p bin cp discovery/console.h ipxe/src/config/local/console.h;\ cd ipxe/src;\ make bin-x86_64-efi/ipxe.efi TGT_LD_ENTRY=$(EFI_DISCOVERY_ENTRY);\ cp bin-x86_64-efi/ipxe.efi ../../bin/$(EFI_DISCOVERY_BINARY);\ rm -r bin-x86_64-efi/;\ rm config/local/console.h;\ make bin-x86_64-efi/ipxe.efi;\ cp bin-x86_64-efi/ipxe.efi ../../bin/ipxe.efi;\ cd ../../ clean: rm -r bin/ �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/EfiLib/�������������������������������������������������������������������������������0000775�0001750�0001750�00000000000�13372347460�014455� 5����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/EfiLib/BmLib.c������������������������������������������������������������������������0000664�0001750�0001750�00000011551�12626644767�015624� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/** @file Utility routines used by boot maintenance modules. Copyright (c) 2004 - 2009, Intel Corporation. All rights reserved.<BR> This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ #ifdef __MAKEWITH_TIANO #include "Platform.h" #else #include "gnuefi-helper.h" #endif #include "../include/refit_call_wrapper.h" /** Find the first instance of this Protocol in the system and return it's interface. @param ProtocolGuid Provides the protocol to search for @param Interface On return, a pointer to the first interface that matches ProtocolGuid @retval EFI_SUCCESS A protocol instance matching ProtocolGuid was found @retval EFI_NOT_FOUND No protocol instances were found that match ProtocolGuid **/ EFI_STATUS EfiLibLocateProtocol ( IN EFI_GUID *ProtocolGuid, OUT VOID **Interface ) { EFI_STATUS Status; Status = refit_call3_wrapper(gBS->LocateProtocol, ProtocolGuid, NULL, (VOID **) Interface ); return Status; } /** Function opens and returns a file handle to the root directory of a volume. @param DeviceHandle A handle for a device @return A valid file handle or NULL is returned **/ EFI_FILE_HANDLE EfiLibOpenRoot ( IN EFI_HANDLE DeviceHandle ) { EFI_STATUS Status; EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume; EFI_FILE_HANDLE File; File = NULL; // // File the file system interface to the device // Status = refit_call3_wrapper(gBS->HandleProtocol, DeviceHandle, &gEfiSimpleFileSystemProtocolGuid, (VOID **) &Volume ); // // Open the root directory of the volume // if (!EFI_ERROR (Status)) { Status = Volume->OpenVolume ( Volume, &File ); } // // Done // return EFI_ERROR (Status) ? NULL : File; } /** Duplicate a string. @param Src The source. @return A new string which is duplicated copy of the source. @retval NULL If there is not enough memory. **/ CHAR16 * EfiStrDuplicate ( IN CHAR16 *Src ) { CHAR16 *Dest; UINTN Size; Size = StrSize (Src); //at least 2bytes Dest = AllocateZeroPool (Size); if (Dest != NULL) { CopyMem (Dest, Src, Size); } return Dest; } /** Function gets the file information from an open file descriptor, and stores it in a buffer allocated from pool. @param FHand File Handle. @return A pointer to a buffer with file information or NULL is returned **/ EFI_FILE_INFO * EfiLibFileInfo ( IN EFI_FILE_HANDLE FHand ) { EFI_STATUS Status; EFI_FILE_INFO *FileInfo = NULL; UINTN Size = 0; Status = FHand->GetInfo (FHand, &gEfiFileInfoGuid, &Size, FileInfo); if (Status == EFI_BUFFER_TOO_SMALL) { FileInfo = AllocateZeroPool (Size); Status = FHand->GetInfo (FHand, &gEfiFileInfoGuid, &Size, FileInfo); } return EFI_ERROR(Status)?NULL:FileInfo; } EFI_FILE_SYSTEM_INFO * EfiLibFileSystemInfo ( IN EFI_FILE_HANDLE FHand ) { EFI_STATUS Status; EFI_FILE_SYSTEM_INFO *FileSystemInfo = NULL; UINTN Size = 0; Status = FHand->GetInfo (FHand, &gEfiFileSystemInfoGuid, &Size, FileSystemInfo); if (Status == EFI_BUFFER_TOO_SMALL) { FileSystemInfo = AllocateZeroPool (Size); Status = FHand->GetInfo (FHand, &gEfiFileSystemInfoGuid, &Size, FileSystemInfo); } return EFI_ERROR(Status)?NULL:FileSystemInfo; } /** Adjusts the size of a previously allocated buffer. @param OldPool - A pointer to the buffer whose size is being adjusted. @param OldSize - The size of the current buffer. @param NewSize - The size of the new buffer. @return The newly allocated buffer. @retval NULL Allocation failed. **/ VOID * EfiReallocatePool ( IN VOID *OldPool, IN UINTN OldSize, IN UINTN NewSize ) { VOID *NewPool; NewPool = NULL; if (NewSize != 0) { NewPool = AllocateZeroPool (NewSize); } if (OldPool != NULL) { if (NewPool != NULL) { CopyMem (NewPool, OldPool, OldSize < NewSize ? OldSize : NewSize); } FreePool (OldPool); } return NewPool; } �������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/EfiLib/gnuefi-helper.c����������������������������������������������������������������0000664�0001750�0001750�00000023256�13141476231�017354� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * EfiLib/gnuefi-helper.c * GNU-EFI support functions * * Borrowed from the TianoCore EDK II, with modifications by Rod Smith * * Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR> * This program and the accompanying materials * are licensed and made available under the terms and conditions of the BSD License * which accompanies this distribution. The full text of the license may be found at * http://opensource.org/licenses/bsd-license.php * * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. * */ #include "gnuefi-helper.h" #include "DevicePathUtilities.h" #include "refit_call_wrapper.h" #include "LegacyBios.h" EFI_GUID gEfiDevicePathUtilitiesProtocolGuid = { 0x09576E91, 0x6D3F, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; EFI_GUID gEfiLegacyBiosProtocolGuid = { 0xdb9a1e3d, 0x45cb, 0x4abb, { 0x85, 0x3b, 0xe5, 0x38, 0x7f, 0xdb, 0x2e, 0x2d }}; /** Convert a Null-terminated Unicode string to a Null-terminated ASCII string and returns the ASCII string. This function converts the content of the Unicode string Source to the ASCII string Destination by copying the lower 8 bits of each Unicode character. It returns Destination. The function terminates the ASCII string Destination by appending a Null-terminator character at the end. The caller is responsible to make sure Destination points to a buffer with size equal or greater than (StrLen (Source) + 1) in bytes. If Destination is NULL, then ASSERT(). If Source is NULL, then ASSERT(). If Source is not aligned on a 16-bit boundary, then ASSERT(). If Source and Destination overlap, then ASSERT(). If any Unicode characters in Source contain non-zero value in the upper 8 bits, then ASSERT(). If PcdMaximumUnicodeStringLength is not zero, and Source contains more than PcdMaximumUnicodeStringLength Unicode characters not including the Null-terminator, then ASSERT(). If PcdMaximumAsciiStringLength is not zero, and Source contains more than PcdMaximumAsciiStringLength Unicode characters not including the Null-terminator, then ASSERT(). @param Source Pointer to a Null-terminated Unicode string. @param Destination Pointer to a Null-terminated ASCII string. @reture Destination **/ CHAR8 * UnicodeStrToAsciiStr ( IN CHAR16 *Source, OUT CHAR8 *Destination ) { ASSERT (Destination != NULL); ASSERT (Source != NULL); ASSERT (((UINTN) Source & 0x01) == 0); // // Source and Destination should not overlap // ASSERT ((UINTN) ((CHAR16 *) Destination - Source) > StrLen (Source)); ASSERT ((UINTN) ((CHAR8 *) Source - Destination) > StrLen (Source)); // // // // If PcdMaximumUnicodeStringLength is not zero, // // length of Source should not more than PcdMaximumUnicodeStringLength // // // if (PcdGet32 (PcdMaximumUnicodeStringLength) != 0) { // ASSERT (StrLen (Source) < PcdGet32 (PcdMaximumUnicodeStringLength)); // } while (*Source != '\0') { // // If any Unicode characters in Source contain // non-zero value in the upper 8 bits, then ASSERT(). // ASSERT (*Source < 0x100); *(Destination++) = (CHAR8) *(Source++); } *Destination = '\0'; return Destination; } /** Returns the length of a Null-terminated ASCII string. This function returns the number of ASCII characters in the Null-terminated ASCII string specified by String. If String is NULL, then ASSERT(). If PcdMaximumAsciiStringLength is not zero and String contains more than PcdMaximumAsciiStringLength ASCII characters not including the Null-terminator, then ASSERT(). @param String Pointer to a Null-terminated ASCII string. @return The length of String. **/ UINTN AsciiStrLen ( IN CONST CHAR8 *String ) { UINTN Length; ASSERT (String != NULL); for (Length = 0; *String != '\0'; String++, Length++) { // // // // If PcdMaximumUnicodeStringLength is not zero, // // length should not more than PcdMaximumUnicodeStringLength // // // if (PcdGet32 (PcdMaximumAsciiStringLength) != 0) { // ASSERT (Length < PcdGet32 (PcdMaximumAsciiStringLength)); // } } return Length; } /** Determine whether a given device path is valid. If DevicePath is NULL, then ASSERT(). @param DevicePath A pointer to a device path data structure. @param MaxSize The maximum size of the device path data structure. @retval TRUE DevicePath is valid. @retval FALSE The length of any node node in the DevicePath is less than sizeof (EFI_DEVICE_PATH_PROTOCOL). @retval FALSE If MaxSize is not zero, the size of the DevicePath exceeds MaxSize. @retval FALSE If PcdMaximumDevicePathNodeCount is not zero, the node count of the DevicePath exceeds PcdMaximumDevicePathNodeCount. **/ BOOLEAN EFIAPI IsDevicePathValid ( IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath, IN UINTN MaxSize ) { // UINTN Count; UINTN Size; UINTN NodeLength; ASSERT (DevicePath != NULL); for (/* Count = 0, */ Size = 0; !IsDevicePathEnd (DevicePath); DevicePath = NextDevicePathNode (DevicePath)) { NodeLength = DevicePathNodeLength (DevicePath); if (NodeLength < sizeof (EFI_DEVICE_PATH_PROTOCOL)) { return FALSE; } if (MaxSize > 0) { Size += NodeLength; if (Size + END_DEVICE_PATH_LENGTH > MaxSize) { return FALSE; } } // if (PcdGet32 (PcdMaximumDevicePathNodeCount) > 0) { // Count++; // if (Count >= PcdGet32 (PcdMaximumDevicePathNodeCount)) { // return FALSE; // } // } } // // Only return TRUE when the End Device Path node is valid. // return (BOOLEAN) (DevicePathNodeLength (DevicePath) == END_DEVICE_PATH_LENGTH); } /** Returns the size of a device path in bytes. This function returns the size, in bytes, of the device path data structure specified by DevicePath including the end of device path node. If DevicePath is NULL or invalid, then 0 is returned. @param DevicePath A pointer to a device path data structure. @retval 0 If DevicePath is NULL or invalid. @retval Others The size of a device path in bytes. **/ UINTN EFIAPI GetDevicePathSize ( IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath ) { CONST EFI_DEVICE_PATH_PROTOCOL *Start; if (DevicePath == NULL) { return 0; } if (!IsDevicePathValid (DevicePath, 0)) { return 0; } // // Search for the end of the device path structure // Start = DevicePath; while (!IsDevicePathEnd (DevicePath)) { DevicePath = NextDevicePathNode (DevicePath); } // // Compute the size and add back in the size of the end device path structure // return ((UINTN) DevicePath - (UINTN) Start) + DevicePathNodeLength (DevicePath); } /** Creates a copy of the current device path instance and returns a pointer to the next device path instance. This function creates a copy of the current device path instance. It also updates DevicePath to point to the next device path instance in the device path (or NULL if no more) and updates Size to hold the size of the device path instance copy. If DevicePath is NULL, then NULL is returned. If DevicePath points to a invalid device path, then NULL is returned. If there is not enough memory to allocate space for the new device path, then NULL is returned. The memory is allocated from EFI boot services memory. It is the responsibility of the caller to free the memory allocated. If Size is NULL, then ASSERT(). @param DevicePath On input, this holds the pointer to the current device path instance. On output, this holds the pointer to the next device path instance or NULL if there are no more device path instances in the device path pointer to a device path data structure. @param Size On output, this holds the size of the device path instance, in bytes or zero, if DevicePath is NULL. @return A pointer to the current device path instance. **/ EFI_DEVICE_PATH_PROTOCOL * EFIAPI GetNextDevicePathInstance ( IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath, OUT UINTN *Size ) { EFI_DEVICE_PATH_PROTOCOL *DevPath; EFI_DEVICE_PATH_PROTOCOL *ReturnValue; UINT8 Temp; ASSERT (Size != NULL); if (DevicePath == NULL || *DevicePath == NULL) { *Size = 0; return NULL; } if (!IsDevicePathValid (*DevicePath, 0)) { return NULL; } // // Find the end of the device path instance // DevPath = *DevicePath; while (!IsDevicePathEndType (DevPath)) { DevPath = NextDevicePathNode (DevPath); } // // Compute the size of the device path instance // *Size = ((UINTN) DevPath - (UINTN) (*DevicePath)) + sizeof (EFI_DEVICE_PATH_PROTOCOL); // // Make a copy and return the device path instance // Temp = DevPath->SubType; DevPath->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE; ReturnValue = DuplicateDevicePath (*DevicePath); DevPath->SubType = Temp; // // If DevPath is the end of an entire device path, then another instance // does not follow, so *DevicePath is set to NULL. // if (DevicePathSubType (DevPath) == END_ENTIRE_DEVICE_PATH_SUBTYPE) { *DevicePath = NULL; } else { *DevicePath = NextDevicePathNode (DevPath); } return ReturnValue; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/EfiLib/DevicePathUtilities.h����������������������������������������������������������0000664�0001750�0001750�00000015706�12626644767�020562� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*++ Copyright (c) 2006 - 2007, Intel Corporation. All rights reserved.<BR> This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. Module Name: DevicePathUtilities.h Abstract: --*/ #ifndef _DEVICE_PATH_UTILITIES_PROTOCOL_H_ #define _DEVICE_PATH_UTILITIES_PROTOCOL_H_ // // Device Path Utilities protocol // #define EFI_DEVICE_PATH_UTILITIES_PROTOCOL_GUID \ { \ 0x379be4e, 0xd706, 0x437d, {0xb0, 0x37, 0xed, 0xb8, 0x2f, 0xb7, 0x72, 0xa4} \ } typedef UINTN EFIAPI (EFIAPI *EFI_DEVICE_PATH_UTILS_GET_DEVICE_PATH_SIZE) ( IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath ) /*++ Routine Description: Returns the size of the device path, in bytes. Arguments: DevicePath - Points to the start of the EFI device path. Returns: Size - Size of the specified device path, in bytes, including the end-of-path tag. --*/ ; typedef EFI_DEVICE_PATH_PROTOCOL* EFIAPI (EFIAPI *EFI_DEVICE_PATH_UTILS_DUP_DEVICE_PATH) ( IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath ) /*++ Routine Description: Create a duplicate of the specified path. Arguments: DevicePath - Points to the source EFI device path. Returns: Pointer - A pointer to the duplicate device path. NULL - Insufficient memory. --*/ ; typedef EFI_DEVICE_PATH_PROTOCOL* EFIAPI (EFIAPI *EFI_DEVICE_PATH_UTILS_APPEND_PATH) ( IN CONST EFI_DEVICE_PATH_PROTOCOL *Src1, IN CONST EFI_DEVICE_PATH_PROTOCOL *Src2 ) /*++ Routine Description: Create a new path by appending the second device path to the first. Arguments: Src1 - Points to the first device path. If NULL, then it is ignored. Src2 - Points to the second device path. If NULL, then it is ignored. Returns: Pointer - A pointer to the newly created device path. NULL - Memory could not be allocated or either DevicePath or DeviceNode is NULL. --*/ ; typedef EFI_DEVICE_PATH_PROTOCOL* EFIAPI (EFIAPI *EFI_DEVICE_PATH_UTILS_APPEND_NODE) ( IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath, IN CONST EFI_DEVICE_PATH_PROTOCOL *DeviceNode ) /*++ Routine Description: Creates a new path by appending the device node to the device path. Arguments: DevicePath - Points to the device path. DeviceNode - Points to the device node. Returns: Pointer - A pointer to the allocated device node. NULL - Memory could not be allocated or either DevicePath or DeviceNode is NULL. --*/ ; typedef EFI_DEVICE_PATH_PROTOCOL* EFIAPI (EFIAPI *EFI_DEVICE_PATH_UTILS_APPEND_INSTANCE) ( IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath, IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePathInstance ) /*++ Routine Description: Creates a new path by appending the specified device path instance to the specified device path. Arguments: DevicePath - Points to the device path. If NULL, then ignored. DevicePathInstance - Points to the device path instance. Returns: Pointer - A pointer to the newly created device path NULL - Memory could not be allocated or DevicePathInstance is NULL. --*/ ; typedef EFI_DEVICE_PATH_PROTOCOL* EFIAPI (EFIAPI *EFI_DEVICE_PATH_UTILS_GET_NEXT_INSTANCE) ( IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathInstance, OUT UINTN *DevicePathInstanceSize ) /*++ Routine Description: Creates a copy of the current device path instance and returns a pointer to the next device path instance. Arguments: DevicePathInstance - On input, this holds the pointer to the current device path instance. On output, this holds the pointer to the next device path instance or NULL if there are no more device path instances in the device path. DevicePathInstanceSize - On output, this holds the size of the device path instance, in bytes or zero, if DevicePathInstance is zero. Returns: Pointer - A pointer to the copy of the current device path instance. NULL - DevicePathInstace was NULL on entry or there was insufficient memory. --*/ ; typedef BOOLEAN EFIAPI (EFIAPI *EFI_DEVICE_PATH_UTILS_IS_MULTI_INSTANCE) ( IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath ) /*++ Routine Description: Returns whether a device path is multi-instance. Arguments: DevicePath - Points to the device path. If NULL, then ignored. Returns: TRUE - The device path has more than one instance FALSE - The device path is empty or contains only a single instance. --*/ ; typedef EFI_DEVICE_PATH_PROTOCOL* EFIAPI (EFIAPI *EFI_DEVICE_PATH_UTILS_CREATE_NODE) ( IN UINT8 NodeType, IN UINT8 NodeSubType, IN UINT16 NodeLength ) /*++ Routine Description: Creates a device node Arguments: NodeType - NodeType is the device node type (EFI_DEVICE_PATH.Type) for the new device node. NodeSubType - NodeSubType is the device node sub-type EFI_DEVICE_PATH.SubType) for the new device node. NodeLength - NodeLength is the length of the device node (EFI_DEVICE_PATH.Length) for the new device node. Returns: Pointer - A pointer to the newly created device node. NULL - NodeLength is less than the size of the header or there was insufficient memory. --*/ ; typedef struct { EFI_DEVICE_PATH_UTILS_GET_DEVICE_PATH_SIZE GetDevicePathSize; EFI_DEVICE_PATH_UTILS_DUP_DEVICE_PATH DuplicateDevicePath; EFI_DEVICE_PATH_UTILS_APPEND_PATH AppendDevicePath; EFI_DEVICE_PATH_UTILS_APPEND_NODE AppendDeviceNode; EFI_DEVICE_PATH_UTILS_APPEND_INSTANCE AppendDevicePathInstance; EFI_DEVICE_PATH_UTILS_GET_NEXT_INSTANCE GetNextDevicePathInstance; EFI_DEVICE_PATH_UTILS_IS_MULTI_INSTANCE IsDevicePathMultiInstance; EFI_DEVICE_PATH_UTILS_CREATE_NODE CreateDeviceNode; } EFI_DEVICE_PATH_UTILITIES_PROTOCOL; extern EFI_GUID gEfiDevicePathUtilitiesProtocolGuid; #endif ����������������������������������������������������������refind-0.11.4/EfiLib/gnuefi-helper.h����������������������������������������������������������������0000664�0001750�0001750�00000002730�12626644767�017375� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * EfiLib/gnuefi-helper.h * Header file for GNU-EFI support in legacy boot code * * Borrowed from the TianoCore EDK II, with modifications by Rod Smith * * Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR> * This program and the accompanying materials * are licensed and made available under the terms and conditions of the BSD License * which accompanies this distribution. The full text of the license may be found at * http://opensource.org/licenses/bsd-license.php * * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. * */ /* * THIS FILE SHOULD NOT BE INCLUDED WHEN COMPILING UNDER TIANOCORE'S TOOLKIT! */ #ifndef __EFILIB_GNUEFI_H #define __EFILIB_GNUEFI_H #include "efi.h" #include "efilib.h" #define EFI_DEVICE_PATH_PROTOCOL EFI_DEVICE_PATH #define UnicodeSPrint SPrint #define gRT RT #define gBS BS #ifndef CONST #define CONST #endif #define ASSERT_EFI_ERROR(status) ASSERT(!EFI_ERROR(status)) CHAR8 * UnicodeStrToAsciiStr ( IN CHAR16 *Source, OUT CHAR8 *Destination ); UINTN AsciiStrLen ( IN CONST CHAR8 *String ); UINTN EFIAPI GetDevicePathSize ( IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath ); EFI_DEVICE_PATH_PROTOCOL * EFIAPI GetNextDevicePathInstance ( IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath, OUT UINTN *Size ); #endif ����������������������������������������refind-0.11.4/EfiLib/Makefile�����������������������������������������������������������������������0000664�0001750�0001750�00000001050�12631122026�016073� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # EfiLib/Makefile # # This program is licensed under the terms of the GNU GPL, version 3, # or (at your option) any later version. # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. SRCDIR = . VPATH = $(SRCDIR) LOCAL_GNUEFI_CFLAGS = -I$(SRCDIR) -I$(SRCDIR)/../include OBJS = gnuefi-helper.o legacy.o BdsHelper.o BdsTianoCore.o TARGET = libEfiLib.a all: $(TARGET) include $(SRCDIR)/../Make.common clean: rm -f *.o *.obj *~ *.lib *.a ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/EfiLib/BdsConnect.c�������������������������������������������������������������������0000664�0001750�0001750�00000020536�12626644767�016664� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/** @file BDS Lib functions which relate with connect the device Copyright (c) 2004 - 2008, Intel Corporation. All rights reserved.<BR> This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ #include "Platform.h" EFI_STATUS ScanDeviceHandles(EFI_HANDLE ControllerHandle, UINTN *HandleCount, EFI_HANDLE **HandleBuffer, UINT32 **HandleType) { EFI_STATUS Status; UINTN HandleIndex; EFI_GUID **ProtocolGuidArray; UINTN ArrayCount; UINTN ProtocolIndex; EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfo; UINTN OpenInfoCount; UINTN OpenInfoIndex; UINTN ChildIndex; *HandleCount = 0; *HandleBuffer = NULL; *HandleType = NULL; // // Retrieve the list of all handles from the handle database // Status = gBS->LocateHandleBuffer (AllHandles, NULL, NULL, HandleCount, HandleBuffer); if (EFI_ERROR (Status)) goto Error; *HandleType = AllocatePool (*HandleCount * sizeof (UINT32)); if (*HandleType == NULL) goto Error; for (HandleIndex = 0; HandleIndex < *HandleCount; HandleIndex++) { (*HandleType)[HandleIndex] = EFI_HANDLE_TYPE_UNKNOWN; // // Retrieve the list of all the protocols on each handle // Status = gBS->ProtocolsPerHandle ( (*HandleBuffer)[HandleIndex], &ProtocolGuidArray, &ArrayCount ); if (!EFI_ERROR (Status)) { for (ProtocolIndex = 0; ProtocolIndex < ArrayCount; ProtocolIndex++) { if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiLoadedImageProtocolGuid)) { (*HandleType)[HandleIndex] |= EFI_HANDLE_TYPE_IMAGE_HANDLE; } if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiDriverBindingProtocolGuid)) { (*HandleType)[HandleIndex] |= EFI_HANDLE_TYPE_DRIVER_BINDING_HANDLE; } if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiDriverConfigurationProtocolGuid)) { (*HandleType)[HandleIndex] |= EFI_HANDLE_TYPE_DRIVER_CONFIGURATION_HANDLE; } if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiDriverDiagnosticsProtocolGuid)) { (*HandleType)[HandleIndex] |= EFI_HANDLE_TYPE_DRIVER_DIAGNOSTICS_HANDLE; } if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiComponentName2ProtocolGuid)) { (*HandleType)[HandleIndex] |= EFI_HANDLE_TYPE_COMPONENT_NAME_HANDLE; } if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiComponentNameProtocolGuid) ) { (*HandleType)[HandleIndex] |= EFI_HANDLE_TYPE_COMPONENT_NAME_HANDLE; } if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiDevicePathProtocolGuid)) { (*HandleType)[HandleIndex] |= EFI_HANDLE_TYPE_DEVICE_HANDLE; } // // Retrieve the list of agents that have opened each protocol // Status = gBS->OpenProtocolInformation ( (*HandleBuffer)[HandleIndex], ProtocolGuidArray[ProtocolIndex], &OpenInfo, &OpenInfoCount ); if (!EFI_ERROR (Status)) { for (OpenInfoIndex = 0; OpenInfoIndex < OpenInfoCount; OpenInfoIndex++) { if (OpenInfo[OpenInfoIndex].ControllerHandle == ControllerHandle) { if ((OpenInfo[OpenInfoIndex].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) == EFI_OPEN_PROTOCOL_BY_DRIVER) { for (ChildIndex = 0; ChildIndex < *HandleCount; ChildIndex++) { if ((*HandleBuffer)[ChildIndex] == OpenInfo[OpenInfoIndex].AgentHandle) { (*HandleType)[ChildIndex] |= EFI_HANDLE_TYPE_DEVICE_DRIVER; } } } if ((OpenInfo[OpenInfoIndex].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) == EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) { (*HandleType)[HandleIndex] |= EFI_HANDLE_TYPE_PARENT_HANDLE; for (ChildIndex = 0; ChildIndex < *HandleCount; ChildIndex++) { if ((*HandleBuffer)[ChildIndex] == OpenInfo[OpenInfoIndex].AgentHandle) { (*HandleType)[ChildIndex] |= EFI_HANDLE_TYPE_BUS_DRIVER; } } } } } FreePool (OpenInfo); } } FreePool (ProtocolGuidArray); } } return EFI_SUCCESS; Error: if (*HandleType != NULL) { FreePool (*HandleType); } if (*HandleBuffer != NULL) { FreePool (*HandleBuffer); } *HandleCount = 0; *HandleBuffer = NULL; *HandleType = NULL; return Status; } EFI_STATUS BdsLibConnectMostlyAllEfi() { EFI_STATUS Status; UINTN AllHandleCount; EFI_HANDLE *AllHandleBuffer; UINTN Index; UINTN HandleCount; EFI_HANDLE *HandleBuffer; UINT32 *HandleType; UINTN HandleIndex; BOOLEAN Parent; BOOLEAN Device; EFI_PCI_IO_PROTOCOL* PciIo; PCI_TYPE00 Pci; Status = gBS->LocateHandleBuffer (AllHandles, NULL, NULL, &AllHandleCount, &AllHandleBuffer); if (CheckError(Status, L"locating handle buffer")) return Status; for (Index = 0; Index < AllHandleCount; Index++) { Status = ScanDeviceHandles(AllHandleBuffer[Index], &HandleCount, &HandleBuffer, &HandleType); if (EFI_ERROR (Status)) goto Done; Device = TRUE; if (HandleType[Index] & EFI_HANDLE_TYPE_DRIVER_BINDING_HANDLE) Device = FALSE; if (HandleType[Index] & EFI_HANDLE_TYPE_IMAGE_HANDLE) Device = FALSE; if (Device) { Parent = FALSE; for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) { if (HandleType[HandleIndex] & EFI_HANDLE_TYPE_PARENT_HANDLE) Parent = TRUE; } if (!Parent) { if (HandleType[Index] & EFI_HANDLE_TYPE_DEVICE_HANDLE) { Status = gBS->HandleProtocol (AllHandleBuffer[Index], &gEfiPciIoProtocolGuid, (VOID*)&PciIo); if (!EFI_ERROR (Status)) { Status = PciIo->Pci.Read (PciIo,EfiPciIoWidthUint32, 0, sizeof (Pci) / sizeof (UINT32), &Pci); if (!EFI_ERROR (Status)) { if(IS_PCI_VGA(&Pci)==TRUE) { gBS->DisconnectController(AllHandleBuffer[Index], NULL, NULL); } } } Status = gBS->ConnectController(AllHandleBuffer[Index], NULL, NULL, TRUE); } } } FreePool (HandleBuffer); FreePool (HandleType); } Done: FreePool (AllHandleBuffer); return Status; } /** Connects all drivers to all controllers. This function make sure all the current system driver will manage the correspoinding controllers if have. And at the same time, make sure all the system controllers have driver to manage it if have. **/ VOID EFIAPI BdsLibConnectAllDriversToAllControllers ( VOID ) { EFI_STATUS Status; do { // // Connect All EFI 1.10 drivers following EFI 1.10 algorithm // //BdsLibConnectAllEfi (); BdsLibConnectMostlyAllEfi (); // // Check to see if it's possible to dispatch an more DXE drivers. // The BdsLibConnectAllEfi () may have made new DXE drivers show up. // If anything is Dispatched Status == EFI_SUCCESS and we will try // the connect again. // Status = gDS->Dispatch (); } while (!EFI_ERROR (Status)); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/EfiLib/AbsolutePointer.h��������������������������������������������������������������0000664�0001750�0001750�00000017147�12774524343�017761� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/** @file The file provides services that allow information about an absolute pointer device to be retrieved. Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR> This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ #ifndef __ABSOLUTE_POINTER_H__ #define __ABSOLUTE_POINTER_H__ #define EFI_ABSOLUTE_POINTER_PROTOCOL_GUID \ { 0x8D59D32B, 0xC655, 0x4AE9, { 0x9B, 0x15, 0xF2, 0x59, 0x04, 0x99, 0x2A, 0x43 } } typedef struct _EFI_ABSOLUTE_POINTER_PROTOCOL EFI_ABSOLUTE_POINTER_PROTOCOL; //******************************************************* // EFI_ABSOLUTE_POINTER_MODE //******************************************************* /** The following data values in the EFI_ABSOLUTE_POINTER_MODE interface are read-only and are changed by using the appropriate interface functions. **/ typedef struct { UINT64 AbsoluteMinX; ///< The Absolute Minimum of the device on the x-axis UINT64 AbsoluteMinY; ///< The Absolute Minimum of the device on the y axis. UINT64 AbsoluteMinZ; ///< The Absolute Minimum of the device on the z-axis UINT64 AbsoluteMaxX; ///< The Absolute Maximum of the device on the x-axis. If 0, and the ///< AbsoluteMinX is 0, then the pointer device does not support a xaxis UINT64 AbsoluteMaxY; ///< The Absolute Maximum of the device on the y -axis. If 0, and the ///< AbsoluteMinX is 0, then the pointer device does not support a yaxis. UINT64 AbsoluteMaxZ; ///< The Absolute Maximum of the device on the z-axis. If 0 , and the ///< AbsoluteMinX is 0, then the pointer device does not support a zaxis UINT32 Attributes; ///< The following bits are set as needed (or'd together) to indicate the ///< capabilities of the device supported. The remaining bits are undefined ///< and should be 0 } EFI_ABSOLUTE_POINTER_MODE; /// /// If set, indicates this device supports an alternate button input. /// #define EFI_ABSP_SupportsAltActive 0x00000001 /// /// If set, indicates this device returns pressure data in parameter CurrentZ. /// #define EFI_ABSP_SupportsPressureAsZ 0x00000002 /** This function resets the pointer device hardware. As part of initialization process, the firmware/device will make a quick but reasonable attempt to verify that the device is functioning. If the ExtendedVerification flag is TRUE the firmware may take an extended amount of time to verify the device is operating on reset. Otherwise the reset operation is to occur as quickly as possible. The hardware verification process is not defined by this specification and is left up to the platform firmware or driver to implement. @param This A pointer to the EFI_ABSOLUTE_POINTER_PROTOCOL instance. @param ExtendedVerification Indicates that the driver may perform a more exhaustive verification operation of the device during reset. @retval EFI_SUCCESS The device was reset. @retval EFI_DEVICE_ERROR The device is not functioning correctly and could not be reset. **/ typedef EFI_STATUS (EFIAPI *EFI_ABSOLUTE_POINTER_RESET)( IN EFI_ABSOLUTE_POINTER_PROTOCOL *This, IN BOOLEAN ExtendedVerification ); /// /// This bit is set if the touch sensor is active. /// #define EFI_ABSP_TouchActive 0x00000001 /// /// This bit is set if the alt sensor, such as pen-side button, is active /// #define EFI_ABS_AltActive 0x00000002 /** Definition of EFI_ABSOLUTE_POINTER_STATE. **/ typedef struct { /// /// The unsigned position of the activation on the x axis. If the AboluteMinX /// and the AboluteMaxX fields of the EFI_ABSOLUTE_POINTER_MODE structure are /// both 0, then this pointer device does not support an x-axis, and this field /// must be ignored. /// UINT64 CurrentX; /// /// The unsigned position of the activation on the y axis. If the AboluteMinY /// and the AboluteMaxY fields of the EFI_ABSOLUTE_POINTER_MODE structure are /// both 0, then this pointer device does not support an y-axis, and this field /// must be ignored. /// UINT64 CurrentY; /// /// The unsigned position of the activation on the z axis, or the pressure /// measurement. If the AboluteMinZ and the AboluteMaxZ fields of the /// EFI_ABSOLUTE_POINTER_MODE structure are both 0, then this pointer device /// does not support an z-axis, and this field must be ignored. /// UINT64 CurrentZ; /// /// Bits are set to 1 in this structure item to indicate that device buttons are /// active. /// UINT32 ActiveButtons; } EFI_ABSOLUTE_POINTER_STATE; /** The GetState() function retrieves the current state of a pointer device. This includes information on the active state associated with the pointer device and the current position of the axes associated with the pointer device. If the state of the pointer device has not changed since the last call to GetState(), then EFI_NOT_READY is returned. If the state of the pointer device has changed since the last call to GetState(), then the state information is placed in State, and EFI_SUCCESS is returned. If a device error occurs while attempting to retrieve the state information, then EFI_DEVICE_ERROR is returned. @param This A pointer to the EFI_ABSOLUTE_POINTER_PROTOCOL instance. @param State A pointer to the state information on the pointer device. @retval EFI_SUCCESS The state of the pointer device was returned in State. @retval EFI_NOT_READY The state of the pointer device has not changed since the last call to GetState(). @retval EFI_DEVICE_ERROR A device error occurred while attempting to retrieve the pointer device's current state. **/ typedef EFI_STATUS (EFIAPI *EFI_ABSOLUTE_POINTER_GET_STATE)( IN EFI_ABSOLUTE_POINTER_PROTOCOL *This, IN OUT EFI_ABSOLUTE_POINTER_STATE *State ); /// /// The EFI_ABSOLUTE_POINTER_PROTOCOL provides a set of services /// for a pointer device that can be used as an input device from an /// application written to this specification. The services include /// the ability to: reset the pointer device, retrieve the state of /// the pointer device, and retrieve the capabilities of the pointer /// device. The service also provides certain data items describing the device. /// struct _EFI_ABSOLUTE_POINTER_PROTOCOL { EFI_ABSOLUTE_POINTER_RESET Reset; EFI_ABSOLUTE_POINTER_GET_STATE GetState; /// /// Event to use with WaitForEvent() to wait for input from the pointer device. /// EFI_EVENT WaitForInput; /// /// Pointer to EFI_ABSOLUTE_POINTER_MODE data. /// EFI_ABSOLUTE_POINTER_MODE *Mode; }; extern EFI_GUID gEfiAbsolutePointerProtocolGuid; #endif �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/EfiLib/BdsHelper.h��������������������������������������������������������������������0000664�0001750�0001750�00000002626�12627675161�016510� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * EfiLib/BdsHelper.c * Functions to call legacy BIOS API. * */ /** Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR> This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ #ifdef __MAKEWITH_TIANO #include "../include/tiano_includes.h" #else #include "gnuefi-helper.h" #include "GenericBdsLib.h" #endif #ifndef _BDS_HELPER_H_ #define _BDS_HELPER_H_ /** Boot the legacy system with the boot option @param Option The legacy boot option which have BBS device path @retval EFI_UNSUPPORTED There is no legacybios protocol, do not support legacy boot. @retval EFI_STATUS Return the status of LegacyBios->LegacyBoot (). **/ EFI_STATUS BdsLibDoLegacyBoot ( IN BDS_COMMON_OPTION *Option ); EFI_STATUS BdsConnectDevicePath ( IN EFI_DEVICE_PATH_PROTOCOL * DevicePath, OUT EFI_HANDLE * Handle, OUT EFI_DEVICE_PATH_PROTOCOL ** RemainingDevicePath ); #endif //_BDS_HELPER_H_ ����������������������������������������������������������������������������������������������������������refind-0.11.4/EfiLib/legacy.h�����������������������������������������������������������������������0000664�0001750�0001750�00000004363�12626644767�016113� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * EfiLib/legacy.h * CSM/legacy boot support functions * * Taken from Tianocore source code (mostly IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/BBSsupport.c) * * Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR> * This program and the accompanying materials * are licensed and made available under the terms and conditions of the BSD License * which accompanies this distribution. The full text of the license may be found at * http://opensource.org/licenses/bsd-license.php * * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. * */ #include "LegacyBios.h" #ifndef __LEGACY_H_ #define __LEGACY_H_ #define BBS_MEDIA_PRESENT 0x0800 #define BBS_MEDIA_MAYBE_PRESENT 0x0400 typedef UINT8 BBS_TYPE; #define VAR_FLAG EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE #pragma pack(1) /// /// For each legacy boot option in BBS table, a corresponding Boot#### variables is created. /// The structure saves the mapping relationship between #### and the index in the BBS table. /// typedef struct { UINT16 BootOptionNumber; UINT16 BbsIndex; UINT16 BbsType; } BOOT_OPTION_BBS_MAPPING; #pragma pack() #pragma pack(1) typedef struct { BBS_TYPE BbsType; /// /// Length = sizeof (UINT16) + sizeof (Data) /// UINT16 Length; UINT16 Data[1]; } LEGACY_DEV_ORDER_ENTRY; #pragma pack() EFI_STATUS BdsAddNonExistingLegacyBootOptions ( VOID ); /** Delete all the invalid legacy boot options. @retval EFI_SUCCESS All invalide legacy boot options are deleted. @retval EFI_OUT_OF_RESOURCES Fail to allocate necessary memory. @retval EFI_NOT_FOUND Fail to retrive variable of boot order. **/ EFI_STATUS BdsDeleteAllInvalidLegacyBootOptions ( VOID ); BOOLEAN BdsIsLegacyBootOption ( IN UINT8 *BootOptionVar, OUT BBS_TABLE **BbsEntry, OUT UINT16 *BbsIndex ); VOID BdsBuildLegacyDevNameString ( IN BBS_TABLE *CurBBSEntry, IN UINTN Index, IN UINTN BufSize, OUT CHAR16 *BootString ); #endif�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/EfiLib/LegacyBios.h�������������������������������������������������������������������0000664�0001750�0001750�00000147370�12626644767�016676� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/** @file The EFI Legacy BIOS Protocol is used to abstract legacy Option ROM usage under EFI and Legacy OS boot. This file also includes all the related COMPATIBILIY16 structures and defintions. Note: The names for EFI_IA32_REGISTER_SET elements were picked to follow well known naming conventions. Thunk is the code that switches from 32-bit protected environment into the 16-bit real-mode environment. Reverse thunk is the code that does the opposite. Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR> This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License that accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php. THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. @par Revision Reference: This protocol is defined in Framework for EFI Compatibility Support Module spec Version 0.97. **/ #ifndef _EFI_LEGACY_BIOS_H_ #define _EFI_LEGACY_BIOS_H_ /// /// /// #pragma pack(1) typedef UINT8 SERIAL_MODE; typedef UINT8 PARALLEL_MODE; #define EFI_COMPATIBILITY16_TABLE_SIGNATURE SIGNATURE_32 ('I', 'F', 'E', '$') /// /// There is a table located within the traditional BIOS in either the 0xF000:xxxx or 0xE000:xxxx /// physical address range. It is located on a 16-byte boundary and provides the physical address of the /// entry point for the Compatibility16 functions. These functions provide the platform-specific /// information that is required by the generic EfiCompatibility code. The functions are invoked via /// thunking by using EFI_LEGACY_BIOS_PROTOCOL.FarCall86() with the 32-bit physical /// entry point. /// typedef struct { /// /// The string "$EFI" denotes the start of the EfiCompatibility table. Byte 0 is "I," byte /// 1 is "F," byte 2 is "E," and byte 3 is "$" and is normally accessed as a DWORD or UINT32. /// UINT32 Signature; /// /// The value required such that byte checksum of TableLength equals zero. /// UINT8 TableChecksum; /// /// The length of this table. /// UINT8 TableLength; /// /// The major EFI revision for which this table was generated. /// UINT8 EfiMajorRevision; /// /// The minor EFI revision for which this table was generated. /// UINT8 EfiMinorRevision; /// /// The major revision of this table. /// UINT8 TableMajorRevision; /// /// The minor revision of this table. /// UINT8 TableMinorRevision; /// /// Reserved for future usage. /// UINT16 Reserved; /// /// The segment of the entry point within the traditional BIOS for Compatibility16 functions. /// UINT16 Compatibility16CallSegment; /// /// The offset of the entry point within the traditional BIOS for Compatibility16 functions. /// UINT16 Compatibility16CallOffset; /// /// The segment of the entry point within the traditional BIOS for EfiCompatibility /// to invoke the PnP installation check. /// UINT16 PnPInstallationCheckSegment; /// /// The Offset of the entry point within the traditional BIOS for EfiCompatibility /// to invoke the PnP installation check. /// UINT16 PnPInstallationCheckOffset; /// /// EFI system resources table. Type EFI_SYSTEM_TABLE is defined in the IntelPlatform ///Innovation Framework for EFI Driver Execution Environment Core Interface Specification (DXE CIS). /// UINT32 EfiSystemTable; /// /// The address of an OEM-provided identifier string. The string is null terminated. /// UINT32 OemIdStringPointer; /// /// The 32-bit physical address where ACPI RSD PTR is stored within the traditional /// BIOS. The remained of the ACPI tables are located at their EFI addresses. The size /// reserved is the maximum for ACPI 2.0. The EfiCompatibility will fill in the ACPI /// RSD PTR with either the ACPI 1.0b or 2.0 values. /// UINT32 AcpiRsdPtrPointer; /// /// The OEM revision number. Usage is undefined but provided for OEM module usage. /// UINT16 OemRevision; /// /// The 32-bit physical address where INT15 E820 data is stored within the traditional /// BIOS. The EfiCompatibility code will fill in the E820Pointer value and copy the /// data to the indicated area. /// UINT32 E820Pointer; /// /// The length of the E820 data and is filled in by the EfiCompatibility code. /// UINT32 E820Length; /// /// The 32-bit physical address where the $PIR table is stored in the traditional BIOS. /// The EfiCompatibility code will fill in the IrqRoutingTablePointer value and /// copy the data to the indicated area. /// UINT32 IrqRoutingTablePointer; /// /// The length of the $PIR table and is filled in by the EfiCompatibility code. /// UINT32 IrqRoutingTableLength; /// /// The 32-bit physical address where the MP table is stored in the traditional BIOS. /// The EfiCompatibility code will fill in the MpTablePtr value and copy the data /// to the indicated area. /// UINT32 MpTablePtr; /// /// The length of the MP table and is filled in by the EfiCompatibility code. /// UINT32 MpTableLength; /// /// The segment of the OEM-specific INT table/code. /// UINT16 OemIntSegment; /// /// The offset of the OEM-specific INT table/code. /// UINT16 OemIntOffset; /// /// The segment of the OEM-specific 32-bit table/code. /// UINT16 Oem32Segment; /// /// The offset of the OEM-specific 32-bit table/code. /// UINT16 Oem32Offset; /// /// The segment of the OEM-specific 16-bit table/code. /// UINT16 Oem16Segment; /// /// The offset of the OEM-specific 16-bit table/code. /// UINT16 Oem16Offset; /// /// The segment of the TPM binary passed to 16-bit CSM. /// UINT16 TpmSegment; /// /// The offset of the TPM binary passed to 16-bit CSM. /// UINT16 TpmOffset; /// /// A pointer to a string identifying the independent BIOS vendor. /// UINT32 IbvPointer; /// /// This field is NULL for all systems not supporting PCI Express. This field is the base /// value of the start of the PCI Express memory-mapped configuration registers and /// must be filled in prior to EfiCompatibility code issuing the Compatibility16 function /// Compatibility16InitializeYourself(). /// Compatibility16InitializeYourself() is defined in Compatability16 /// Functions. /// UINT32 PciExpressBase; /// /// Maximum PCI bus number assigned. /// UINT8 LastPciBus; } EFI_COMPATIBILITY16_TABLE; /// /// Functions provided by the CSM binary which communicate between the EfiCompatibility /// and Compatability16 code. /// /// Inconsistent with the specification here: /// The member's name started with "Compatibility16" [defined in Intel Framework /// Compatibility Support Module Specification / 0.97 version] /// has been changed to "Legacy16" since keeping backward compatible. /// typedef enum { /// /// Causes the Compatibility16 code to do any internal initialization required. /// Input: /// AX = Compatibility16InitializeYourself /// ES:BX = Pointer to EFI_TO_COMPATIBILITY16_INIT_TABLE /// Return: /// AX = Return Status codes /// Legacy16InitializeYourself = 0x0000, /// /// Causes the Compatibility16 BIOS to perform any drive number translations to match the boot sequence. /// Input: /// AX = Compatibility16UpdateBbs /// ES:BX = Pointer to EFI_TO_COMPATIBILITY16_BOOT_TABLE /// Return: /// AX = Returned status codes /// Legacy16UpdateBbs = 0x0001, /// /// Allows the Compatibility16 code to perform any final actions before booting. The Compatibility16 /// code is read/write. /// Input: /// AX = Compatibility16PrepareToBoot /// ES:BX = Pointer to EFI_TO_COMPATIBILITY16_BOOT_TABLE structure /// Return: /// AX = Returned status codes /// Legacy16PrepareToBoot = 0x0002, /// /// Causes the Compatibility16 BIOS to boot. The Compatibility16 code is Read/Only. /// Input: /// AX = Compatibility16Boot /// Output: /// AX = Returned status codes /// Legacy16Boot = 0x0003, /// /// Allows the Compatibility16 code to get the last device from which a boot was attempted. This is /// stored in CMOS and is the priority number of the last attempted boot device. /// Input: /// AX = Compatibility16RetrieveLastBootDevice /// Output: /// AX = Returned status codes /// BX = Priority number of the boot device. /// Legacy16RetrieveLastBootDevice = 0x0004, /// /// Allows the Compatibility16 code rehook INT13, INT18, and/or INT19 after dispatching a legacy OpROM. /// Input: /// AX = Compatibility16DispatchOprom /// ES:BX = Pointer to EFI_DISPATCH_OPROM_TABLE /// Output: /// AX = Returned status codes /// BX = Number of non-BBS-compliant devices found. Equals 0 if BBS compliant. /// Legacy16DispatchOprom = 0x0005, /// /// Finds a free area in the 0xFxxxx or 0xExxxx region of the specified length and returns the address /// of that region. /// Input: /// AX = Compatibility16GetTableAddress /// BX = Allocation region /// 00 = Allocate from either 0xE0000 or 0xF0000 64 KB blocks. /// Bit 0 = 1 Allocate from 0xF0000 64 KB block /// Bit 1 = 1 Allocate from 0xE0000 64 KB block /// CX = Requested length in bytes. /// DX = Required address alignment. Bit mapped. First non-zero bit from the right is the alignment. /// Output: /// AX = Returned status codes /// DS:BX = Address of the region /// Legacy16GetTableAddress = 0x0006, /// /// Enables the EfiCompatibility module to do any nonstandard processing of keyboard LEDs or state. /// Input: /// AX = Compatibility16SetKeyboardLeds /// CL = LED status. /// Bit 0 Scroll Lock 0 = Off /// Bit 1 NumLock /// Bit 2 Caps Lock /// Output: /// AX = Returned status codes /// Legacy16SetKeyboardLeds = 0x0007, /// /// Enables the EfiCompatibility module to install an interrupt handler for PCI mass media devices that /// do not have an OpROM associated with them. An example is SATA. /// Input: /// AX = Compatibility16InstallPciHandler /// ES:BX = Pointer to EFI_LEGACY_INSTALL_PCI_HANDLER structure /// Output: /// AX = Returned status codes /// Legacy16InstallPciHandler = 0x0008 } EFI_COMPATIBILITY_FUNCTIONS; /// /// EFI_DISPATCH_OPROM_TABLE /// typedef struct { UINT16 PnPInstallationCheckSegment; ///< A pointer to the PnpInstallationCheck data structure. UINT16 PnPInstallationCheckOffset; ///< A pointer to the PnpInstallationCheck data structure. UINT16 OpromSegment; ///< The segment where the OpROM was placed. Offset is assumed to be 3. UINT8 PciBus; ///< The PCI bus. UINT8 PciDeviceFunction; ///< The PCI device * 0x08 | PCI function. UINT8 NumberBbsEntries; ///< The number of valid BBS table entries upon entry and exit. The IBV code may ///< increase this number, if BBS-compliant devices also hook INTs in order to force the ///< OpROM BIOS Setup to be executed. UINT32 BbsTablePointer; ///< A pointer to the BBS table. UINT16 RuntimeSegment; ///< The segment where the OpROM can be relocated to. If this value is 0x0000, this ///< means that the relocation of this run time code is not supported. ///< Inconsistent with specification here: ///< The member's name "OpromDestinationSegment" [defined in Intel Framework Compatibility Support Module Specification / 0.97 version] ///< has been changed to "RuntimeSegment" since keeping backward compatible. } EFI_DISPATCH_OPROM_TABLE; /// /// EFI_TO_COMPATIBILITY16_INIT_TABLE /// typedef struct { /// /// Starting address of memory under 1 MB. The ending address is assumed to be 640 KB or 0x9FFFF. /// UINT32 BiosLessThan1MB; /// /// The starting address of the high memory block. /// UINT32 HiPmmMemory; /// /// The length of high memory block. /// UINT32 HiPmmMemorySizeInBytes; /// /// The segment of the reverse thunk call code. /// UINT16 ReverseThunkCallSegment; /// /// The offset of the reverse thunk call code. /// UINT16 ReverseThunkCallOffset; /// /// The number of E820 entries copied to the Compatibility16 BIOS. /// UINT32 NumberE820Entries; /// /// The amount of usable memory above 1 MB, e.g., E820 type 1 memory. /// UINT32 OsMemoryAbove1Mb; /// /// The start of thunk code in main memory. Memory cannot be used by BIOS or PMM. /// UINT32 ThunkStart; /// /// The size of the thunk code. /// UINT32 ThunkSizeInBytes; /// /// Starting address of memory under 1 MB. /// UINT32 LowPmmMemory; /// /// The length of low Memory block. /// UINT32 LowPmmMemorySizeInBytes; } EFI_TO_COMPATIBILITY16_INIT_TABLE; /// /// DEVICE_PRODUCER_SERIAL. /// typedef struct { UINT16 Address; ///< I/O address assigned to the serial port. UINT8 Irq; ///< IRQ assigned to the serial port. SERIAL_MODE Mode; ///< Mode of serial port. Values are defined below. } DEVICE_PRODUCER_SERIAL; /// /// DEVICE_PRODUCER_SERIAL's modes. ///@{ #define DEVICE_SERIAL_MODE_NORMAL 0x00 #define DEVICE_SERIAL_MODE_IRDA 0x01 #define DEVICE_SERIAL_MODE_ASK_IR 0x02 #define DEVICE_SERIAL_MODE_DUPLEX_HALF 0x00 #define DEVICE_SERIAL_MODE_DUPLEX_FULL 0x10 ///@) /// /// DEVICE_PRODUCER_PARALLEL. /// typedef struct { UINT16 Address; ///< I/O address assigned to the parallel port. UINT8 Irq; ///< IRQ assigned to the parallel port. UINT8 Dma; ///< DMA assigned to the parallel port. PARALLEL_MODE Mode; ///< Mode of the parallel port. Values are defined below. } DEVICE_PRODUCER_PARALLEL; /// /// DEVICE_PRODUCER_PARALLEL's modes. ///@{ #define DEVICE_PARALLEL_MODE_MODE_OUTPUT_ONLY 0x00 #define DEVICE_PARALLEL_MODE_MODE_BIDIRECTIONAL 0x01 #define DEVICE_PARALLEL_MODE_MODE_EPP 0x02 #define DEVICE_PARALLEL_MODE_MODE_ECP 0x03 ///@} /// /// DEVICE_PRODUCER_FLOPPY /// typedef struct { UINT16 Address; ///< I/O address assigned to the floppy. UINT8 Irq; ///< IRQ assigned to the floppy. UINT8 Dma; ///< DMA assigned to the floppy. UINT8 NumberOfFloppy; ///< Number of floppies in the system. } DEVICE_PRODUCER_FLOPPY; /// /// LEGACY_DEVICE_FLAGS /// typedef struct { UINT32 A20Kybd : 1; ///< A20 controller by keyboard controller. UINT32 A20Port90 : 1; ///< A20 controlled by port 0x92. UINT32 Reserved : 30; ///< Reserved for future usage. } LEGACY_DEVICE_FLAGS; /// /// DEVICE_PRODUCER_DATA_HEADER /// typedef struct { DEVICE_PRODUCER_SERIAL Serial[4]; ///< Data for serial port x. Type DEVICE_PRODUCER_SERIAL is defined below. DEVICE_PRODUCER_PARALLEL Parallel[3]; ///< Data for parallel port x. Type DEVICE_PRODUCER_PARALLEL is defined below. DEVICE_PRODUCER_FLOPPY Floppy; ///< Data for floppy. Type DEVICE_PRODUCER_FLOPPY is defined below. UINT8 MousePresent; ///< Flag to indicate if mouse is present. LEGACY_DEVICE_FLAGS Flags; ///< Miscellaneous Boolean state information passed to CSM. } DEVICE_PRODUCER_DATA_HEADER; /// /// ATAPI_IDENTIFY /// typedef struct { UINT16 Raw[256]; ///< Raw data from the IDE IdentifyDrive command. } ATAPI_IDENTIFY; /// /// HDD_INFO /// typedef struct { /// /// Status of IDE device. Values are defined below. There is one HDD_INFO structure /// per IDE controller. The IdentifyDrive is per drive. Index 0 is master and index /// 1 is slave. /// UINT16 Status; /// /// PCI bus of IDE controller. /// UINT32 Bus; /// /// PCI device of IDE controller. /// UINT32 Device; /// /// PCI function of IDE controller. /// UINT32 Function; /// /// Command ports base address. /// UINT16 CommandBaseAddress; /// /// Control ports base address. /// UINT16 ControlBaseAddress; /// /// Bus master address. /// UINT16 BusMasterAddress; UINT8 HddIrq; /// /// Data that identifies the drive data; one per possible attached drive. /// ATAPI_IDENTIFY IdentifyDrive[2]; } HDD_INFO; /// /// HDD_INFO status bits /// #define HDD_PRIMARY 0x01 #define HDD_SECONDARY 0x02 #define HDD_MASTER_ATAPI_CDROM 0x04 #define HDD_SLAVE_ATAPI_CDROM 0x08 #define HDD_MASTER_IDE 0x20 #define HDD_SLAVE_IDE 0x40 #define HDD_MASTER_ATAPI_ZIPDISK 0x10 #define HDD_SLAVE_ATAPI_ZIPDISK 0x80 /// /// BBS_STATUS_FLAGS;\. /// typedef struct { UINT16 OldPosition : 4; ///< Prior priority. UINT16 Reserved1 : 4; ///< Reserved for future use. UINT16 Enabled : 1; ///< If 0, ignore this entry. UINT16 Failed : 1; ///< 0 = Not known if boot failure occurred. ///< 1 = Boot attempted failed. /// /// State of media present. /// 00 = No bootable media is present in the device. /// 01 = Unknown if a bootable media present. /// 10 = Media is present and appears bootable. /// 11 = Reserved. /// UINT16 MediaPresent : 2; UINT16 Reserved2 : 4; ///< Reserved for future use. } BBS_STATUS_FLAGS; /// /// BBS_TABLE, device type values & boot priority values. /// typedef struct { /// /// The boot priority for this boot device. Values are defined below. /// UINT16 BootPriority; /// /// The PCI bus for this boot device. /// UINT32 Bus; /// /// The PCI device for this boot device. /// UINT32 Device; /// /// The PCI function for the boot device. /// UINT32 Function; /// /// The PCI class for this boot device. /// UINT8 Class; /// /// The PCI Subclass for this boot device. /// UINT8 SubClass; /// /// Segment:offset address of an ASCIIZ description string describing the manufacturer. /// UINT16 MfgStringOffset; /// /// Segment:offset address of an ASCIIZ description string describing the manufacturer. /// UINT16 MfgStringSegment; /// /// BBS device type. BBS device types are defined below. /// UINT16 DeviceType; /// /// Status of this boot device. Type BBS_STATUS_FLAGS is defined below. /// BBS_STATUS_FLAGS StatusFlags; /// /// Segment:Offset address of boot loader for IPL devices or install INT13 handler for /// BCV devices. /// UINT16 BootHandlerOffset; /// /// Segment:Offset address of boot loader for IPL devices or install INT13 handler for /// BCV devices. /// UINT16 BootHandlerSegment; /// /// Segment:offset address of an ASCIIZ description string describing this device. /// UINT16 DescStringOffset; /// /// Segment:offset address of an ASCIIZ description string describing this device. /// UINT16 DescStringSegment; /// /// Reserved. /// UINT32 InitPerReserved; /// /// The use of these fields is IBV dependent. They can be used to flag that an OpROM /// has hooked the specified IRQ. The OpROM may be BBS compliant as some SCSI /// BBS-compliant OpROMs also hook IRQ vectors in order to run their BIOS Setup /// UINT32 AdditionalIrq13Handler; /// /// The use of these fields is IBV dependent. They can be used to flag that an OpROM /// has hooked the specified IRQ. The OpROM may be BBS compliant as some SCSI /// BBS-compliant OpROMs also hook IRQ vectors in order to run their BIOS Setup /// UINT32 AdditionalIrq18Handler; /// /// The use of these fields is IBV dependent. They can be used to flag that an OpROM /// has hooked the specified IRQ. The OpROM may be BBS compliant as some SCSI /// BBS-compliant OpROMs also hook IRQ vectors in order to run their BIOS Setup /// UINT32 AdditionalIrq19Handler; /// /// The use of these fields is IBV dependent. They can be used to flag that an OpROM /// has hooked the specified IRQ. The OpROM may be BBS compliant as some SCSI /// BBS-compliant OpROMs also hook IRQ vectors in order to run their BIOS Setup /// UINT32 AdditionalIrq40Handler; UINT8 AssignedDriveNumber; UINT32 AdditionalIrq41Handler; UINT32 AdditionalIrq46Handler; UINT32 IBV1; UINT32 IBV2; } BBS_TABLE; /// /// BBS device type values ///@{ #define BBS_FLOPPY 0x01 #define BBS_HARDDISK 0x02 #define BBS_CDROM 0x03 #define BBS_PCMCIA 0x04 #define BBS_USB 0x05 #define BBS_EMBED_NETWORK 0x06 #define BBS_BEV_DEVICE 0x80 #define BBS_UNKNOWN 0xff ///@} /// /// BBS boot priority values ///@{ #define BBS_DO_NOT_BOOT_FROM 0xFFFC #define BBS_LOWEST_PRIORITY 0xFFFD #define BBS_UNPRIORITIZED_ENTRY 0xFFFE #define BBS_IGNORE_ENTRY 0xFFFF ///@} /// /// SMM_ATTRIBUTES /// typedef struct { /// /// Access mechanism used to generate the soft SMI. Defined types are below. The other /// values are reserved for future usage. /// UINT16 Type : 3; /// /// The size of "port" in bits. Defined values are below. /// UINT16 PortGranularity : 3; /// /// The size of data in bits. Defined values are below. /// UINT16 DataGranularity : 3; /// /// Reserved for future use. /// UINT16 Reserved : 7; } SMM_ATTRIBUTES; /// /// SMM_ATTRIBUTES type values. ///@{ #define STANDARD_IO 0x00 #define STANDARD_MEMORY 0x01 ///@} /// /// SMM_ATTRIBUTES port size constants. ///@{ #define PORT_SIZE_8 0x00 #define PORT_SIZE_16 0x01 #define PORT_SIZE_32 0x02 #define PORT_SIZE_64 0x03 ///@} /// /// SMM_ATTRIBUTES data size constants. ///@{ #define DATA_SIZE_8 0x00 #define DATA_SIZE_16 0x01 #define DATA_SIZE_32 0x02 #define DATA_SIZE_64 0x03 ///@} /// /// SMM_FUNCTION & relating constants. /// typedef struct { UINT16 Function : 15; UINT16 Owner : 1; } SMM_FUNCTION; /// /// SMM_FUNCTION Function constants. ///@{ #define INT15_D042 0x0000 #define GET_USB_BOOT_INFO 0x0001 #define DMI_PNP_50_57 0x0002 ///@} /// /// SMM_FUNCTION Owner constants. ///@{ #define STANDARD_OWNER 0x0 #define OEM_OWNER 0x1 ///@} /// /// This structure assumes both port and data sizes are 1. SmmAttribute must be /// properly to reflect that assumption. /// typedef struct { /// /// Describes the access mechanism, SmmPort, and SmmData sizes. Type /// SMM_ATTRIBUTES is defined below. /// SMM_ATTRIBUTES SmmAttributes; /// /// Function Soft SMI is to perform. Type SMM_FUNCTION is defined below. /// SMM_FUNCTION SmmFunction; /// /// SmmPort size depends upon SmmAttributes and ranges from2 bytes to 16 bytes. /// UINT8 SmmPort; /// /// SmmData size depends upon SmmAttributes and ranges from2 bytes to 16 bytes. /// UINT8 SmmData; } SMM_ENTRY; /// /// SMM_TABLE /// typedef struct { UINT16 NumSmmEntries; ///< Number of entries represented by SmmEntry. SMM_ENTRY SmmEntry; ///< One entry per function. Type SMM_ENTRY is defined below. } SMM_TABLE; /// /// UDC_ATTRIBUTES /// typedef struct { /// /// This bit set indicates that the ServiceAreaData is valid. /// UINT8 DirectoryServiceValidity : 1; /// /// This bit set indicates to use the Reserve Area Boot Code Address (RACBA) only if /// DirectoryServiceValidity is 0. /// UINT8 RabcaUsedFlag : 1; /// /// This bit set indicates to execute hard disk diagnostics. /// UINT8 ExecuteHddDiagnosticsFlag : 1; /// /// Reserved for future use. Set to 0. /// UINT8 Reserved : 5; } UDC_ATTRIBUTES; /// /// UD_TABLE /// typedef struct { /// /// This field contains the bit-mapped attributes of the PARTIES information. Type /// UDC_ATTRIBUTES is defined below. /// UDC_ATTRIBUTES Attributes; /// /// This field contains the zero-based device on which the selected /// ServiceDataArea is present. It is 0 for master and 1 for the slave device. /// UINT8 DeviceNumber; /// /// This field contains the zero-based index into the BbsTable for the parent device. /// This index allows the user to reference the parent device information such as PCI /// bus, device function. /// UINT8 BbsTableEntryNumberForParentDevice; /// /// This field contains the zero-based index into the BbsTable for the boot entry. /// UINT8 BbsTableEntryNumberForBoot; /// /// This field contains the zero-based index into the BbsTable for the HDD diagnostics entry. /// UINT8 BbsTableEntryNumberForHddDiag; /// /// The raw Beer data. /// UINT8 BeerData[128]; /// /// The raw data of selected service area. /// UINT8 ServiceAreaData[64]; } UD_TABLE; #define EFI_TO_LEGACY_MAJOR_VERSION 0x02 #define EFI_TO_LEGACY_MINOR_VERSION 0x00 #define MAX_IDE_CONTROLLER 8 /// /// EFI_TO_COMPATIBILITY16_BOOT_TABLE /// typedef struct { UINT16 MajorVersion; ///< The EfiCompatibility major version number. UINT16 MinorVersion; ///< The EfiCompatibility minor version number. UINT32 AcpiTable; ///< The location of the RSDT ACPI table. < 4G range. UINT32 SmbiosTable; ///< The location of the SMBIOS table in EFI memory. < 4G range. UINT32 SmbiosTableLength; // // Legacy SIO state // DEVICE_PRODUCER_DATA_HEADER SioData; ///< Standard traditional device information. UINT16 DevicePathType; ///< The default boot type. UINT16 PciIrqMask; ///< Mask of which IRQs have been assigned to PCI. UINT32 NumberE820Entries; ///< Number of E820 entries. The number can change from the ///< Compatibility16InitializeYourself() function. // // Controller & Drive Identify[2] per controller information // HDD_INFO HddInfo[MAX_IDE_CONTROLLER]; ///< Hard disk drive information, including raw Identify Drive data. UINT32 NumberBbsEntries; ///< Number of entries in the BBS table UINT32 BbsTable; ///< A pointer to the BBS table. Type BBS_TABLE is defined below. UINT32 SmmTable; ///< A pointer to the SMM table. Type SMM_TABLE is defined below. UINT32 OsMemoryAbove1Mb; ///< The amount of usable memory above 1 MB, i.e. E820 type 1 memory. This value can ///< differ from the value in EFI_TO_COMPATIBILITY16_INIT_TABLE as more ///< memory may have been discovered. UINT32 UnconventionalDeviceTable; ///< Information to boot off an unconventional device like a PARTIES partition. Type ///< UD_TABLE is defined below. } EFI_TO_COMPATIBILITY16_BOOT_TABLE; /// /// EFI_LEGACY_INSTALL_PCI_HANDLER /// typedef struct { UINT8 PciBus; ///< The PCI bus of the device. UINT8 PciDeviceFun; ///< The PCI device in bits 7:3 and function in bits 2:0. UINT8 PciSegment; ///< The PCI segment of the device. UINT8 PciClass; ///< The PCI class code of the device. UINT8 PciSubclass; ///< The PCI subclass code of the device. UINT8 PciInterface; ///< The PCI interface code of the device. // // Primary section // UINT8 PrimaryIrq; ///< The primary device IRQ. UINT8 PrimaryReserved; ///< Reserved. UINT16 PrimaryControl; ///< The primary device control I/O base. UINT16 PrimaryBase; ///< The primary device I/O base. UINT16 PrimaryBusMaster; ///< The primary device bus master I/O base. // // Secondary Section // UINT8 SecondaryIrq; ///< The secondary device IRQ. UINT8 SecondaryReserved; ///< Reserved. UINT16 SecondaryControl; ///< The secondary device control I/O base. UINT16 SecondaryBase; ///< The secondary device I/O base. UINT16 SecondaryBusMaster; ///< The secondary device bus master I/O base. } EFI_LEGACY_INSTALL_PCI_HANDLER; // // Restore default pack value // #pragma pack() #define EFI_LEGACY_BIOS_PROTOCOL_GUID \ { \ 0xdb9a1e3d, 0x45cb, 0x4abb, {0x85, 0x3b, 0xe5, 0x38, 0x7f, 0xdb, 0x2e, 0x2d } \ } typedef struct _EFI_LEGACY_BIOS_PROTOCOL EFI_LEGACY_BIOS_PROTOCOL; /// /// Flags returned by CheckPciRom(). /// #define NO_ROM 0x00 #define ROM_FOUND 0x01 #define VALID_LEGACY_ROM 0x02 #define ROM_WITH_CONFIG 0x04 ///< Not defined in the Framework CSM Specification. /// /// The following macros do not appear in the Framework CSM Specification and /// are kept for backward compatibility only. They convert 32-bit address (_Adr) /// to Segment:Offset 16-bit form. /// ///@{ #define EFI_SEGMENT(_Adr) (UINT16) ((UINT16) (((UINTN) (_Adr)) >> 4) & 0xf000) #define EFI_OFFSET(_Adr) (UINT16) (((UINT16) ((UINTN) (_Adr))) & 0xffff) ///@} #define CARRY_FLAG 0x01 /// /// EFI_EFLAGS_REG /// typedef struct { UINT32 CF:1; UINT32 Reserved1:1; UINT32 PF:1; UINT32 Reserved2:1; UINT32 AF:1; UINT32 Reserved3:1; UINT32 ZF:1; UINT32 SF:1; UINT32 TF:1; UINT32 IF:1; UINT32 DF:1; UINT32 OF:1; UINT32 IOPL:2; UINT32 NT:1; UINT32 Reserved4:2; UINT32 VM:1; UINT32 Reserved5:14; } EFI_EFLAGS_REG; /// /// EFI_DWORD_REGS /// typedef struct { UINT32 EAX; UINT32 EBX; UINT32 ECX; UINT32 EDX; UINT32 ESI; UINT32 EDI; EFI_EFLAGS_REG EFlags; UINT16 ES; UINT16 CS; UINT16 SS; UINT16 DS; UINT16 FS; UINT16 GS; UINT32 EBP; UINT32 ESP; } EFI_DWORD_REGS; /// /// EFI_FLAGS_REG /// typedef struct { UINT16 CF:1; UINT16 Reserved1:1; UINT16 PF:1; UINT16 Reserved2:1; UINT16 AF:1; UINT16 Reserved3:1; UINT16 ZF:1; UINT16 SF:1; UINT16 TF:1; UINT16 IF:1; UINT16 DF:1; UINT16 OF:1; UINT16 IOPL:2; UINT16 NT:1; UINT16 Reserved4:1; } EFI_FLAGS_REG; /// /// EFI_WORD_REGS /// typedef struct { UINT16 AX; UINT16 ReservedAX; UINT16 BX; UINT16 ReservedBX; UINT16 CX; UINT16 ReservedCX; UINT16 DX; UINT16 ReservedDX; UINT16 SI; UINT16 ReservedSI; UINT16 DI; UINT16 ReservedDI; EFI_FLAGS_REG Flags; UINT16 ReservedFlags; UINT16 ES; UINT16 CS; UINT16 SS; UINT16 DS; UINT16 FS; UINT16 GS; UINT16 BP; UINT16 ReservedBP; UINT16 SP; UINT16 ReservedSP; } EFI_WORD_REGS; /// /// EFI_BYTE_REGS /// typedef struct { UINT8 AL, AH; UINT16 ReservedAX; UINT8 BL, BH; UINT16 ReservedBX; UINT8 CL, CH; UINT16 ReservedCX; UINT8 DL, DH; UINT16 ReservedDX; } EFI_BYTE_REGS; /// /// EFI_IA32_REGISTER_SET /// typedef union { EFI_DWORD_REGS E; EFI_WORD_REGS X; EFI_BYTE_REGS H; } EFI_IA32_REGISTER_SET; /** Thunk to 16-bit real mode and execute a software interrupt with a vector of BiosInt. Regs will contain the 16-bit register context on entry and exit. @param[in] This The protocol instance pointer. @param[in] BiosInt The processor interrupt vector to invoke. @param[in,out] Reg Register contexted passed into (and returned) from thunk to 16-bit mode. @retval TRUE Thunk completed with no BIOS errors in the target code. See Regs for status. @retval FALSE There was a BIOS error in the target code. **/ typedef BOOLEAN (EFIAPI *EFI_LEGACY_BIOS_INT86)( IN EFI_LEGACY_BIOS_PROTOCOL *This, IN UINT8 BiosInt, IN OUT EFI_IA32_REGISTER_SET *Regs ); /** Thunk to 16-bit real mode and call Segment:Offset. Regs will contain the 16-bit register context on entry and exit. Arguments can be passed on the Stack argument @param[in] This The protocol instance pointer. @param[in] Segment The segemnt of 16-bit mode call. @param[in] Offset The offset of 16-bit mdoe call. @param[in] Reg Register contexted passed into (and returned) from thunk to 16-bit mode. @param[in] Stack The caller allocated stack used to pass arguments. @param[in] StackSize The size of Stack in bytes. @retval FALSE Thunk completed with no BIOS errors in the target code. See Regs for status. @retval TRUE There was a BIOS error in the target code. **/ typedef BOOLEAN (EFIAPI *EFI_LEGACY_BIOS_FARCALL86)( IN EFI_LEGACY_BIOS_PROTOCOL *This, IN UINT16 Segment, IN UINT16 Offset, IN EFI_IA32_REGISTER_SET *Regs, IN VOID *Stack, IN UINTN StackSize ); /** Test to see if a legacy PCI ROM exists for this device. Optionally return the Legacy ROM instance for this PCI device. @param[in] This The protocol instance pointer. @param[in] PciHandle The PCI PC-AT OPROM from this devices ROM BAR will be loaded @param[out] RomImage Return the legacy PCI ROM for this device. @param[out] RomSize The size of ROM Image. @param[out] Flags Indicates if ROM found and if PC-AT. Multiple bits can be set as follows: - 00 = No ROM. - 01 = ROM Found. - 02 = ROM is a valid legacy ROM. @retval EFI_SUCCESS The Legacy Option ROM availible for this device @retval EFI_UNSUPPORTED The Legacy Option ROM is not supported. **/ typedef EFI_STATUS (EFIAPI *EFI_LEGACY_BIOS_CHECK_ROM)( IN EFI_LEGACY_BIOS_PROTOCOL *This, IN EFI_HANDLE PciHandle, OUT VOID **RomImage, OPTIONAL OUT UINTN *RomSize, OPTIONAL OUT UINTN *Flags ); /** Load a legacy PC-AT OPROM on the PciHandle device. Return information about how many disks were added by the OPROM and the shadow address and size. DiskStart & DiskEnd are INT 13h drive letters. Thus 0x80 is C: @param[in] This The protocol instance pointer. @param[in] PciHandle The PCI PC-AT OPROM from this devices ROM BAR will be loaded. This value is NULL if RomImage is non-NULL. This is the normal case. @param[in] RomImage A PCI PC-AT ROM image. This argument is non-NULL if there is no hardware associated with the ROM and thus no PciHandle, otherwise is must be NULL. Example is PXE base code. @param[out] Flags The type of ROM discovered. Multiple bits can be set, as follows: - 00 = No ROM. - 01 = ROM found. - 02 = ROM is a valid legacy ROM. @param[out] DiskStart The disk number of first device hooked by the ROM. If DiskStart is the same as DiskEnd no disked were hooked. @param[out] DiskEnd disk number of the last device hooked by the ROM. @param[out] RomShadowAddress Shadow address of PC-AT ROM. @param[out] RomShadowSize Size of RomShadowAddress in bytes. @retval EFI_SUCCESS Thunk completed, see Regs for status. @retval EFI_INVALID_PARAMETER PciHandle not found **/ typedef EFI_STATUS (EFIAPI *EFI_LEGACY_BIOS_INSTALL_ROM)( IN EFI_LEGACY_BIOS_PROTOCOL *This, IN EFI_HANDLE PciHandle, IN VOID **RomImage, OUT UINTN *Flags, OUT UINT8 *DiskStart, OPTIONAL OUT UINT8 *DiskEnd, OPTIONAL OUT VOID **RomShadowAddress, OPTIONAL OUT UINT32 *ShadowedRomSize OPTIONAL ); /** This function attempts to traditionally boot the specified BootOption. If the EFI context has been compromised, this function will not return. This procedure is not used for loading an EFI-aware OS off a traditional device. The following actions occur: - Get EFI SMBIOS data structures, convert them to a traditional format, and copy to Compatibility16. - Get a pointer to ACPI data structures and copy the Compatibility16 RSD PTR to F0000 block. - Find the traditional SMI handler from a firmware volume and register the traditional SMI handler with the EFI SMI handler. - Build onboard IDE information and pass this information to the Compatibility16 code. - Make sure all PCI Interrupt Line registers are programmed to match 8259. - Reconfigure SIO devices from EFI mode (polled) into traditional mode (interrupt driven). - Shadow all PCI ROMs. - Set up BDA and EBDA standard areas before the legacy boot. - Construct the Compatibility16 boot memory map and pass it to the Compatibility16 code. - Invoke the Compatibility16 table function Compatibility16PrepareToBoot(). This invocation causes a thunk into the Compatibility16 code, which sets all appropriate internal data structures. The boot device list is a parameter. - Invoke the Compatibility16 Table function Compatibility16Boot(). This invocation causes a thunk into the Compatibility16 code, which does an INT19. - If the Compatibility16Boot() function returns, then the boot failed in a graceful manner--meaning that the EFI code is still valid. An ungraceful boot failure causes a reset because the state of EFI code is unknown. @param[in] This The protocol instance pointer. @param[in] BootOption The EFI Device Path from BootXXXX variable. @param[in] LoadOptionSize The size of LoadOption in size. @param[in] LoadOption LThe oadOption from BootXXXX variable. @retval EFI_DEVICE_ERROR Failed to boot from any boot device and memory is uncorrupted. Note: This function normally does not returns. It will either boot the OS or reset the system if memory has been "corrupted" by loading a boot sector and passing control to it. **/ typedef EFI_STATUS (EFIAPI *EFI_LEGACY_BIOS_BOOT)( IN EFI_LEGACY_BIOS_PROTOCOL *This, IN BBS_BBS_DEVICE_PATH *BootOption, IN UINT32 LoadOptionsSize, IN VOID *LoadOptions ); /** This function takes the Leds input parameter and sets/resets the BDA accordingly. Leds is also passed to Compatibility16 code, in case any special processing is required. This function is normally called from EFI Setup drivers that handle user-selectable keyboard options such as boot with NUM LOCK on/off. This function does not touch the keyboard or keyboard LEDs but only the BDA. @param[in] This The protocol instance pointer. @param[in] Leds The status of current Scroll, Num & Cap lock LEDS: - Bit 0 is Scroll Lock 0 = Not locked. - Bit 1 is Num Lock. - Bit 2 is Caps Lock. @retval EFI_SUCCESS The BDA was updated successfully. **/ typedef EFI_STATUS (EFIAPI *EFI_LEGACY_BIOS_UPDATE_KEYBOARD_LED_STATUS)( IN EFI_LEGACY_BIOS_PROTOCOL *This, IN UINT8 Leds ); /** Retrieve legacy BBS info and assign boot priority. @param[in] This The protocol instance pointer. @param[out] HddCount The number of HDD_INFO structures. @param[out] HddInfo Onboard IDE controller information. @param[out] BbsCount The number of BBS_TABLE structures. @param[in,out] BbsTable Points to List of BBS_TABLE. @retval EFI_SUCCESS Tables were returned. **/ typedef EFI_STATUS (EFIAPI *EFI_LEGACY_BIOS_GET_BBS_INFO)( IN EFI_LEGACY_BIOS_PROTOCOL *This, OUT UINT16 *HddCount, OUT HDD_INFO **HddInfo, OUT UINT16 *BbsCount, IN OUT BBS_TABLE **BbsTable ); /** Assign drive number to legacy HDD drives prior to booting an EFI aware OS so the OS can access drives without an EFI driver. @param[in] This The protocol instance pointer. @param[out] BbsCount The number of BBS_TABLE structures @param[out] BbsTable List of BBS entries @retval EFI_SUCCESS Drive numbers assigned. **/ typedef EFI_STATUS (EFIAPI *EFI_LEGACY_BIOS_PREPARE_TO_BOOT_EFI)( IN EFI_LEGACY_BIOS_PROTOCOL *This, OUT UINT16 *BbsCount, OUT BBS_TABLE **BbsTable ); /** To boot from an unconventional device like parties and/or execute HDD diagnostics. @param[in] This The protocol instance pointer. @param[in] Attributes How to interpret the other input parameters. @param[in] BbsEntry The 0-based index into the BbsTable for the parent device. @param[in] BeerData A pointer to the 128 bytes of ram BEER data. @param[in] ServiceAreaData A pointer to the 64 bytes of raw Service Area data. The caller must provide a pointer to the specific Service Area and not the start all Service Areas. @retval EFI_INVALID_PARAMETER If error. Does NOT return if no error. **/ typedef EFI_STATUS (EFIAPI *EFI_LEGACY_BIOS_BOOT_UNCONVENTIONAL_DEVICE)( IN EFI_LEGACY_BIOS_PROTOCOL *This, IN UDC_ATTRIBUTES Attributes, IN UINTN BbsEntry, IN VOID *BeerData, IN VOID *ServiceAreaData ); /** Shadow all legacy16 OPROMs that haven't been shadowed. Warning: Use this with caution. This routine disconnects all EFI drivers. If used externally, then the caller must re-connect EFI drivers. @param[in] This The protocol instance pointer. @retval EFI_SUCCESS OPROMs were shadowed. **/ typedef EFI_STATUS (EFIAPI *EFI_LEGACY_BIOS_SHADOW_ALL_LEGACY_OPROMS)( IN EFI_LEGACY_BIOS_PROTOCOL *This ); /** Get a region from the LegacyBios for S3 usage. @param[in] This The protocol instance pointer. @param[in] LegacyMemorySize The size of required region. @param[in] Region The region to use. 00 = Either 0xE0000 or 0xF0000 block. - Bit0 = 1 0xF0000 block. - Bit1 = 1 0xE0000 block. @param[in] Alignment Address alignment. Bit mapped. The first non-zero bit from right is alignment. @param[out] LegacyMemoryAddress The Region Assigned @retval EFI_SUCCESS The Region was assigned. @retval EFI_ACCESS_DENIED The function was previously invoked. @retval Other The Region was not assigned. **/ typedef EFI_STATUS (EFIAPI *EFI_LEGACY_BIOS_GET_LEGACY_REGION)( IN EFI_LEGACY_BIOS_PROTOCOL *This, IN UINTN LegacyMemorySize, IN UINTN Region, IN UINTN Alignment, OUT VOID **LegacyMemoryAddress ); /** Get a region from the LegacyBios for Tiano usage. Can only be invoked once. @param[in] This The protocol instance pointer. @param[in] LegacyMemorySize The size of data to copy. @param[in] LegacyMemoryAddress The Legacy Region destination address. Note: must be in region assigned by LegacyBiosGetLegacyRegion. @param[in] LegacyMemorySourceAddress The source of the data to copy. @retval EFI_SUCCESS The Region assigned. @retval EFI_ACCESS_DENIED Destination was outside an assigned region. **/ typedef EFI_STATUS (EFIAPI *EFI_LEGACY_BIOS_COPY_LEGACY_REGION)( IN EFI_LEGACY_BIOS_PROTOCOL *This, IN UINTN LegacyMemorySize, IN VOID *LegacyMemoryAddress, IN VOID *LegacyMemorySourceAddress ); /// /// Abstracts the traditional BIOS from the rest of EFI. The LegacyBoot() /// member function allows the BDS to support booting a traditional OS. /// EFI thunks drivers that make EFI bindings for BIOS INT services use /// all the other member functions. /// struct _EFI_LEGACY_BIOS_PROTOCOL { /// /// Performs traditional software INT. See the Int86() function description. /// EFI_LEGACY_BIOS_INT86 Int86; /// /// Performs a far call into Compatibility16 or traditional OpROM code. /// EFI_LEGACY_BIOS_FARCALL86 FarCall86; /// /// Checks if a traditional OpROM exists for this device. /// EFI_LEGACY_BIOS_CHECK_ROM CheckPciRom; /// /// Loads a traditional OpROM in traditional OpROM address space. /// EFI_LEGACY_BIOS_INSTALL_ROM InstallPciRom; /// /// Boots a traditional OS. /// EFI_LEGACY_BIOS_BOOT LegacyBoot; /// /// Updates BDA to reflect the current EFI keyboard LED status. /// EFI_LEGACY_BIOS_UPDATE_KEYBOARD_LED_STATUS UpdateKeyboardLedStatus; /// /// Allows an external agent, such as BIOS Setup, to get the BBS data. /// EFI_LEGACY_BIOS_GET_BBS_INFO GetBbsInfo; /// /// Causes all legacy OpROMs to be shadowed. /// EFI_LEGACY_BIOS_SHADOW_ALL_LEGACY_OPROMS ShadowAllLegacyOproms; /// /// Performs all actions prior to boot. Used when booting an EFI-aware OS /// rather than a legacy OS. /// EFI_LEGACY_BIOS_PREPARE_TO_BOOT_EFI PrepareToBootEfi; /// /// Allows EFI to reserve an area in the 0xE0000 or 0xF0000 block. /// EFI_LEGACY_BIOS_GET_LEGACY_REGION GetLegacyRegion; /// /// Allows EFI to copy data to the area specified by GetLegacyRegion. /// EFI_LEGACY_BIOS_COPY_LEGACY_REGION CopyLegacyRegion; /// /// Allows the user to boot off an unconventional device such as a PARTIES partition. /// EFI_LEGACY_BIOS_BOOT_UNCONVENTIONAL_DEVICE BootUnconventionalDevice; }; extern EFI_GUID gEfiLegacyBiosProtocolGuid; #endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/EfiLib/legacy.c�����������������������������������������������������������������������0000664�0001750�0001750�00000072364�13106171410�016062� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * EfiLib/legacy.c * CSM/legacy boot support functions * * Taken from Tianocore source code (mostly IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/BBSsupport.c) * * Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR> * This program and the accompanying materials * are licensed and made available under the terms and conditions of the BSD License * which accompanies this distribution. The full text of the license may be found at * http://opensource.org/licenses/bsd-license.php * * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. * */ #ifdef __MAKEWITH_GNUEFI #include "efi.h" #include "efilib.h" #include "gnuefi-helper.h" #define EFI_DEVICE_PATH_PROTOCOL EFI_DEVICE_PATH #define EfiReallocatePool ReallocatePool #define EfiLibLocateProtocol LibLocateProtocol #else #include "../include/tiano_includes.h" #endif #include "legacy.h" #include "GenericBdsLib.h" #include "../refind/global.h" #include "../include/refit_call_wrapper.h" BOOT_OPTION_BBS_MAPPING *mBootOptionBbsMapping = NULL; UINTN mBootOptionBbsMappingCount = 0; extern EFI_DEVICE_PATH EndDevicePath[]; extern EFI_GUID gEfiLegacyBiosProtocolGuid; EFI_GUID gEfiLegacyDevOrderVariableGuid = { 0xa56074db, 0x65fe, 0x45f7, {0xbd, 0x21, 0x2d, 0x2b, 0xdd, 0x8e, 0x96, 0x52 }}; static EFI_GUID EfiGlobalVariableGuid = { 0x8BE4DF61, 0x93CA, 0x11D2, { 0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C }}; /** Translate the first n characters of an Ascii string to Unicode characters. The count n is indicated by parameter Size. If Size is greater than the length of string, then the entire string is translated. @param AStr Pointer to input Ascii string. @param Size The number of characters to translate. @param UStr Pointer to output Unicode string buffer. **/ VOID AsciiToUnicodeSize ( IN UINT8 *AStr, IN UINTN Size, OUT UINT16 *UStr ) { UINTN Idx; Idx = 0; while (AStr[Idx] != 0) { UStr[Idx] = (CHAR16) AStr[Idx]; if (Idx == Size) { break; } Idx++; } UStr[Idx] = 0; } /** Build Legacy Device Name String according. @param CurBBSEntry BBS Table. @param Index Index. @param BufSize The buffer size. @param BootString The output string. **/ VOID BdsBuildLegacyDevNameString ( IN BBS_TABLE *CurBBSEntry, IN UINTN Index, IN UINTN BufSize, OUT CHAR16 *BootString ) { CHAR16 *Fmt; CHAR16 *Type; UINT8 *StringDesc; CHAR16 Temp[80]; switch (Index) { // // Primary Master // case 1: Fmt = L"Primary Master %s"; break; // // Primary Slave // case 2: Fmt = L"Primary Slave %s"; break; // // Secondary Master // case 3: Fmt = L"Secondary Master %s"; break; // // Secondary Slave // case 4: Fmt = L"Secondary Slave %s"; break; default: Fmt = L"%s"; break; } switch (CurBBSEntry->DeviceType) { case BBS_FLOPPY: Type = L"Floppy"; break; case BBS_HARDDISK: Type = L"Harddisk"; break; case BBS_CDROM: Type = L"CDROM"; break; case BBS_PCMCIA: Type = L"PCMCIAe"; break; case BBS_USB: Type = L"USB"; break; case BBS_EMBED_NETWORK: Type = L"Network"; break; case BBS_BEV_DEVICE: Type = L"BEVe"; break; case BBS_UNKNOWN: default: Type = L"Unknown"; break; } // // If current BBS entry has its description then use it. // StringDesc = (UINT8 *) (UINTN) ((CurBBSEntry->DescStringSegment << 4) + CurBBSEntry->DescStringOffset); if (NULL != StringDesc) { // // Only get fisrt 32 characters, this is suggested by BBS spec // AsciiToUnicodeSize (StringDesc, 32, Temp); Fmt = L"%s"; Type = Temp; } // // BbsTable 16 entries are for onboard IDE. // Set description string for SATA harddisks, Harddisk 0 ~ Harddisk 11 // if (Index >= 5 && Index <= 16 && (CurBBSEntry->DeviceType == BBS_HARDDISK || CurBBSEntry->DeviceType == BBS_CDROM)) { Fmt = L"%s %d"; UnicodeSPrint (BootString, BufSize, Fmt, Type, Index - 5); } else { UnicodeSPrint (BootString, BufSize, Fmt, Type); } } /** Check if the boot option is a legacy one. @param BootOptionVar The boot option data payload. @param BbsEntry The BBS Table. @param BbsIndex The table index. @retval TRUE It is a legacy boot option. @retval FALSE It is not a legacy boot option. **/ BOOLEAN BdsIsLegacyBootOption ( IN UINT8 *BootOptionVar, OUT BBS_TABLE **BbsEntry, OUT UINT16 *BbsIndex ) { UINT8 *Ptr; EFI_DEVICE_PATH_PROTOCOL *DevicePath; BOOLEAN Ret; UINT16 DevPathLen; Ptr = BootOptionVar; Ptr += sizeof (UINT32); DevPathLen = *(UINT16 *) Ptr; Ptr += sizeof (UINT16); Ptr += StrSize ((UINT16 *) Ptr); DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr; if ((BBS_DEVICE_PATH == DevicePath->Type) && (BBS_BBS_DP == DevicePath->SubType)) { Ptr += DevPathLen; *BbsEntry = (BBS_TABLE *) Ptr; Ptr += sizeof (BBS_TABLE); *BbsIndex = *(UINT16 *) Ptr; Ret = TRUE; } else { *BbsEntry = NULL; Ret = FALSE; } return Ret; } /** Find all legacy boot option by device type. @param BootOrder The boot order array. @param BootOptionNum The number of boot option. @param DevType Device type. @param DevName Device name. @param Attribute The boot option attribute. @param BbsIndex The BBS table index. @param OptionNumber The boot option index. @retval TRUE The Legacy boot option is found. @retval FALSE The legacy boot option is not found. **/ BOOLEAN BdsFindLegacyBootOptionByDevTypeAndName ( IN UINT16 *BootOrder, IN UINTN BootOptionNum, IN UINT16 DevType, IN CHAR16 *DevName, OUT UINT32 *Attribute, OUT UINT16 *BbsIndex, OUT UINT16 *OptionNumber ) { UINTN Index; CHAR16 BootOption[10]; UINTN BootOptionSize; UINT8 *BootOptionVar; BBS_TABLE *BbsEntry; BOOLEAN Found; BbsEntry = NULL; Found = FALSE; if (NULL == BootOrder) { return Found; } // // Loop all boot option from variable // for (Index = 0; Index < BootOptionNum; Index++) { UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", (UINTN) BootOrder[Index]); BootOptionVar = BdsLibGetVariableAndSize ( BootOption, &EfiGlobalVariableGuid, &BootOptionSize ); if (NULL == BootOptionVar) { continue; } // // Skip Non-legacy boot option // if (!BdsIsLegacyBootOption (BootOptionVar, &BbsEntry, BbsIndex)) { FreePool (BootOptionVar); continue; } if ( (BbsEntry->DeviceType != DevType) || (StrCmp (DevName, (CHAR16*)(BootOptionVar + sizeof (UINT32) + sizeof (UINT16))) != 0) ) { FreePool (BootOptionVar); continue; } *Attribute = *(UINT32 *) BootOptionVar; *OptionNumber = BootOrder[Index]; Found = TRUE; FreePool (BootOptionVar); break; } return Found; } /** Create a legacy boot option for the specified entry of BBS table, save it as variable, and append it to the boot order list. @param CurrentBbsEntry Pointer to current BBS table. @param CurrentBbsDevPath Pointer to the Device Path Protocol instance of BBS @param Index Index of the specified entry in BBS table. @param BootOrderList On input, the original boot order list. On output, the new boot order list attached with the created node. @param BootOrderListSize On input, the original size of boot order list. On output, the size of new boot order list. @retval EFI_SUCCESS Boot Option successfully created. @retval EFI_OUT_OF_RESOURCES Fail to allocate necessary memory. @retval Other Error occurs while setting variable. **/ EFI_STATUS BdsCreateLegacyBootOption ( IN BBS_TABLE *CurrentBbsEntry, IN EFI_DEVICE_PATH_PROTOCOL *CurrentBbsDevPath, IN UINTN Index, IN OUT UINT16 **BootOrderList, IN OUT UINTN *BootOrderListSize ) { EFI_STATUS Status; UINT16 CurrentBootOptionNo; UINT16 BootString[10]; CHAR16 BootDesc[100]; CHAR8 HelpString[100]; UINT16 *NewBootOrderList; UINTN BufferSize; UINTN StringLen; VOID *Buffer; UINT8 *Ptr; UINT16 CurrentBbsDevPathSize; UINTN BootOrderIndex; UINTN BootOrderLastIndex; UINTN ArrayIndex; BOOLEAN IndexNotFound; BBS_BBS_DEVICE_PATH *NewBbsDevPathNode; if ((*BootOrderList) == NULL) { CurrentBootOptionNo = 0; } else { for (ArrayIndex = 0; ArrayIndex < (UINTN) (*BootOrderListSize / sizeof (UINT16)); ArrayIndex++) { IndexNotFound = TRUE; for (BootOrderIndex = 0; BootOrderIndex < (UINTN) (*BootOrderListSize / sizeof (UINT16)); BootOrderIndex++) { if ((*BootOrderList)[BootOrderIndex] == ArrayIndex) { IndexNotFound = FALSE; break; } } if (!IndexNotFound) { continue; } else { break; } } CurrentBootOptionNo = (UINT16) ArrayIndex; } UnicodeSPrint ( BootString, sizeof (BootString), L"Boot%04x", CurrentBootOptionNo ); BdsBuildLegacyDevNameString (CurrentBbsEntry, Index, sizeof (BootDesc), BootDesc); // // Create new BBS device path node with description string // UnicodeStrToAsciiStr (BootDesc, HelpString); StringLen = AsciiStrLen (HelpString); NewBbsDevPathNode = AllocateZeroPool (sizeof (BBS_BBS_DEVICE_PATH) + StringLen); if (NewBbsDevPathNode == NULL) { return EFI_OUT_OF_RESOURCES; } CopyMem (NewBbsDevPathNode, CurrentBbsDevPath, sizeof (BBS_BBS_DEVICE_PATH)); CopyMem (NewBbsDevPathNode->String, HelpString, StringLen + 1); SetDevicePathNodeLength (&(NewBbsDevPathNode->Header), sizeof (BBS_BBS_DEVICE_PATH) + StringLen); // // Create entire new CurrentBbsDevPath with end node // CurrentBbsDevPath = AppendDevicePathNode ( EndDevicePath, (EFI_DEVICE_PATH_PROTOCOL *) NewBbsDevPathNode ); if (CurrentBbsDevPath == NULL) { FreePool (NewBbsDevPathNode); return EFI_OUT_OF_RESOURCES; } CurrentBbsDevPathSize = (UINT16) (GetDevicePathSize (CurrentBbsDevPath)); BufferSize = sizeof (UINT32) + sizeof (UINT16) + StrSize (BootDesc) + CurrentBbsDevPathSize + sizeof (BBS_TABLE) + sizeof (UINT16); Buffer = AllocateZeroPool (BufferSize); if (Buffer == NULL) { FreePool (NewBbsDevPathNode); FreePool (CurrentBbsDevPath); return EFI_OUT_OF_RESOURCES; } Ptr = (UINT8 *) Buffer; *((UINT32 *) Ptr) = LOAD_OPTION_ACTIVE; Ptr += sizeof (UINT32); *((UINT16 *) Ptr) = CurrentBbsDevPathSize; Ptr += sizeof (UINT16); CopyMem ( Ptr, BootDesc, StrSize (BootDesc) ); Ptr += StrSize (BootDesc); CopyMem ( Ptr, CurrentBbsDevPath, CurrentBbsDevPathSize ); Ptr += CurrentBbsDevPathSize; CopyMem ( Ptr, CurrentBbsEntry, sizeof (BBS_TABLE) ); Ptr += sizeof (BBS_TABLE); *((UINT16 *) Ptr) = (UINT16) Index; Status = refit_call5_wrapper(gRT->SetVariable, BootString, &EfiGlobalVariableGuid, VAR_FLAG, BufferSize, Buffer ); FreePool (Buffer); Buffer = NULL; NewBootOrderList = AllocateZeroPool (*BootOrderListSize + sizeof (UINT16)); if (NULL == NewBootOrderList) { FreePool (NewBbsDevPathNode); FreePool (CurrentBbsDevPath); return EFI_OUT_OF_RESOURCES; } if (*BootOrderList != NULL) { CopyMem (NewBootOrderList, *BootOrderList, *BootOrderListSize); FreePool (*BootOrderList); } BootOrderLastIndex = (UINTN) (*BootOrderListSize / sizeof (UINT16)); NewBootOrderList[BootOrderLastIndex] = CurrentBootOptionNo; *BootOrderListSize += sizeof (UINT16); *BootOrderList = NewBootOrderList; FreePool (NewBbsDevPathNode); FreePool (CurrentBbsDevPath); return Status; } /** Create a legacy boot option. @param BbsItem The BBS Table entry. @param Index Index of the specified entry in BBS table. @param BootOrderList The boot order list. @param BootOrderListSize The size of boot order list. @retval EFI_OUT_OF_RESOURCE No enough memory. @retval EFI_SUCCESS The function complete successfully. @return Other value if the legacy boot option is not created. **/ EFI_STATUS BdsCreateOneLegacyBootOption ( IN BBS_TABLE *BbsItem, IN UINTN Index, IN OUT UINT16 **BootOrderList, IN OUT UINTN *BootOrderListSize ) { BBS_BBS_DEVICE_PATH BbsDevPathNode; EFI_STATUS Status; EFI_DEVICE_PATH_PROTOCOL *DevPath; DevPath = NULL; // // Create device path node. // BbsDevPathNode.Header.Type = BBS_DEVICE_PATH; BbsDevPathNode.Header.SubType = BBS_BBS_DP; SetDevicePathNodeLength (&BbsDevPathNode.Header, sizeof (BBS_BBS_DEVICE_PATH)); BbsDevPathNode.DeviceType = BbsItem->DeviceType; CopyMem (&BbsDevPathNode.StatusFlag, &BbsItem->StatusFlags, sizeof (UINT16)); DevPath = AppendDevicePathNode ( EndDevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &BbsDevPathNode ); if (NULL == DevPath) { return EFI_OUT_OF_RESOURCES; } Status = BdsCreateLegacyBootOption ( BbsItem, DevPath, Index, BootOrderList, BootOrderListSize ); BbsItem->BootPriority = 0x00; FreePool (DevPath); return Status; } /** Group the legacy boot options in the BootOption. The routine assumes the boot options in the beginning that covers all the device types are ordered properly and re-position the following boot options just after the corresponding boot options with the same device type. For example: 1. Input = [Harddisk1 CdRom2 Efi1 Harddisk0 CdRom0 CdRom1 Harddisk2 Efi0] Assuming [Harddisk1 CdRom2 Efi1] is ordered properly Output = [Harddisk1 Harddisk0 Harddisk2 CdRom2 CdRom0 CdRom1 Efi1 Efi0] 2. Input = [Efi1 Efi0 CdRom1 Harddisk0 Harddisk1 Harddisk2 CdRom0 CdRom2] Assuming [Efi1 Efi0 CdRom1 Harddisk0] is ordered properly Output = [Efi1 Efi0 CdRom1 CdRom0 CdRom2 Harddisk0 Harddisk1 Harddisk2] @param BootOption Pointer to buffer containing Boot Option Numbers @param BootOptionCount Count of the Boot Option Numbers **/ VOID GroupMultipleLegacyBootOption4SameType ( UINT16 *BootOption, UINTN BootOptionCount ) { UINTN DeviceTypeIndex[7]; UINTN Index; UINTN MappingIndex; UINTN *NextIndex; UINT16 OptionNumber; UINTN DeviceIndex; SetMem (DeviceTypeIndex, sizeof (DeviceTypeIndex), 0xFF); for (Index = 0; Index < BootOptionCount; Index++) { // // Find the DeviceType // for (MappingIndex = 0; MappingIndex < mBootOptionBbsMappingCount; MappingIndex++) { if (mBootOptionBbsMapping[MappingIndex].BootOptionNumber == BootOption[Index]) { break; } } if (MappingIndex == mBootOptionBbsMappingCount) { // // Is not a legacy boot option // continue; } ASSERT ((mBootOptionBbsMapping[MappingIndex].BbsType & 0xF) < sizeof (DeviceTypeIndex) / sizeof (DeviceTypeIndex[0])); NextIndex = &DeviceTypeIndex[mBootOptionBbsMapping[MappingIndex].BbsType & 0xF]; if (*NextIndex == (UINTN) -1) { // // *NextIndex is the index in BootOption to put the next Option Number for the same type // *NextIndex = Index + 1; } else { // // insert the current boot option before *NextIndex, causing [*Next .. Index] shift right one position // OptionNumber = BootOption[Index]; CopyMem (&BootOption[*NextIndex + 1], &BootOption[*NextIndex], (Index - *NextIndex) * sizeof (UINT16)); BootOption[*NextIndex] = OptionNumber; // // Update the DeviceTypeIndex array to reflect the right shift operation // for (DeviceIndex = 0; DeviceIndex < sizeof (DeviceTypeIndex) / sizeof (DeviceTypeIndex[0]); DeviceIndex++) { if (DeviceTypeIndex[DeviceIndex] != (UINTN) -1 && DeviceTypeIndex[DeviceIndex] >= *NextIndex) { DeviceTypeIndex[DeviceIndex]++; } } } } } /** Function returns the value of the specified variable. @param Name A Null-terminated Unicode string that is the name of the vendor's variable. @param VendorGuid A unique identifier for the vendor. @return The payload of the variable. @retval NULL If the variable can't be read. **/ VOID * EfiLibGetVariable ( IN CHAR16 *Name, IN EFI_GUID *VendorGuid ) { UINTN VarSize; return BdsLibGetVariableAndSize (Name, VendorGuid, &VarSize); } /** Function deletes the variable specified by VarName and VarGuid. @param VarName A Null-terminated Unicode string that is the name of the vendor's variable. @param VarGuid A unique identifier for the vendor. @retval EFI_SUCCESS The variable was found and removed @retval EFI_UNSUPPORTED The variable store was inaccessible @retval EFI_OUT_OF_RESOURCES The temporary buffer was not available @retval EFI_NOT_FOUND The variable was not found **/ EFI_STATUS EfiLibDeleteVariable ( IN CHAR16 *VarName, IN EFI_GUID *VarGuid ) { VOID *VarBuf; EFI_STATUS Status; VarBuf = EfiLibGetVariable (VarName, VarGuid); Status = EFI_NOT_FOUND; if (VarBuf != NULL) { // // Delete variable from Storage // Status = refit_call5_wrapper(gRT->SetVariable, VarName, VarGuid, VAR_FLAG, 0, NULL); ASSERT (!EFI_ERROR (Status)); FreePool (VarBuf); } return Status; } /** Add the legacy boot options from BBS table if they do not exist. @retval EFI_SUCCESS The boot options are added successfully or they are already in boot options. @retval EFI_NOT_FOUND No legacy boot options is found. @retval EFI_OUT_OF_RESOURCE No enough memory. @return Other value LegacyBoot options are not added. **/ EFI_STATUS BdsAddNonExistingLegacyBootOptions ( VOID ) { UINT16 *BootOrder; UINTN BootOrderSize; EFI_STATUS Status; CHAR16 Desc[100]; UINT16 HddCount; UINT16 BbsCount; HDD_INFO *LocalHddInfo; BBS_TABLE *LocalBbsTable; UINT16 BbsIndex; EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; UINT16 Index; UINT32 Attribute; UINT16 OptionNumber; BOOLEAN Exist; HddCount = 0; BbsCount = 0; LocalHddInfo = NULL; LocalBbsTable = NULL; Status = EfiLibLocateProtocol (&gEfiLegacyBiosProtocolGuid, (VOID **) &LegacyBios); if (EFI_ERROR (Status)) { return Status; } if (mBootOptionBbsMapping != NULL) { FreePool (mBootOptionBbsMapping); mBootOptionBbsMapping = NULL; mBootOptionBbsMappingCount = 0; } refit_call5_wrapper(LegacyBios->GetBbsInfo, LegacyBios, &HddCount, &LocalHddInfo, &BbsCount, &LocalBbsTable ); BootOrder = BdsLibGetVariableAndSize ( L"BootOrder", &EfiGlobalVariableGuid, &BootOrderSize ); if (BootOrder == NULL) { BootOrderSize = 0; } for (Index = 0; Index < BbsCount; Index++) { if ((LocalBbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) || (LocalBbsTable[Index].BootPriority == BBS_DO_NOT_BOOT_FROM) ) { continue; } BdsBuildLegacyDevNameString (&LocalBbsTable[Index], Index, sizeof (Desc), Desc); Exist = BdsFindLegacyBootOptionByDevTypeAndName ( BootOrder, BootOrderSize / sizeof (UINT16), LocalBbsTable[Index].DeviceType, Desc, &Attribute, &BbsIndex, &OptionNumber ); if (!Exist) { // // Not found such type of legacy device in boot options or we found but it's disabled // so we have to create one and put it to the tail of boot order list // Status = BdsCreateOneLegacyBootOption ( &LocalBbsTable[Index], Index, &BootOrder, &BootOrderSize ); if (EFI_ERROR (Status)) { break; } BbsIndex = Index; OptionNumber = BootOrder[BootOrderSize / sizeof (UINT16) - 1]; } ASSERT (BbsIndex == Index); // // Save the BbsIndex // mBootOptionBbsMapping = EfiReallocatePool ( mBootOptionBbsMapping, mBootOptionBbsMappingCount * sizeof (BOOT_OPTION_BBS_MAPPING), (mBootOptionBbsMappingCount + 1) * sizeof (BOOT_OPTION_BBS_MAPPING) ); ASSERT (mBootOptionBbsMapping != NULL); mBootOptionBbsMapping[mBootOptionBbsMappingCount].BootOptionNumber = OptionNumber; mBootOptionBbsMapping[mBootOptionBbsMappingCount].BbsIndex = Index; mBootOptionBbsMapping[mBootOptionBbsMappingCount].BbsType = LocalBbsTable[Index].DeviceType; mBootOptionBbsMappingCount ++; } // // Group the Boot Option Number in BootOrder for the same type devices // GroupMultipleLegacyBootOption4SameType ( BootOrder, BootOrderSize / sizeof (UINT16) ); if (BootOrderSize > 0) { Status = refit_call5_wrapper(gRT->SetVariable, L"BootOrder", &EfiGlobalVariableGuid, VAR_FLAG, BootOrderSize, BootOrder ); } else { EfiLibDeleteVariable (L"BootOrder", &EfiGlobalVariableGuid); } if (BootOrder != NULL) { FreePool (BootOrder); } return Status; } /** Deletete the Boot Option from EFI Variable. The Boot Order Arrray is also updated. @param OptionNumber The number of Boot option want to be deleted. @param BootOrder The Boot Order array. @param BootOrderSize The size of the Boot Order Array. @retval EFI_SUCCESS The Boot Option Variable was found and removed @retval EFI_UNSUPPORTED The Boot Option Variable store was inaccessible @retval EFI_NOT_FOUND The Boot Option Variable was not found **/ EFI_STATUS BdsDeleteBootOption ( IN UINTN OptionNumber, IN OUT UINT16 *BootOrder, IN OUT UINTN *BootOrderSize ) { UINT16 BootOption[100]; UINTN Index; EFI_STATUS Status; UINTN Index2Del; Status = EFI_SUCCESS; Index2Del = 0; UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", OptionNumber); Status = EfiLibDeleteVariable (BootOption, &EfiGlobalVariableGuid); // // adjust boot order array // for (Index = 0; Index < *BootOrderSize / sizeof (UINT16); Index++) { if (BootOrder[Index] == OptionNumber) { Index2Del = Index; break; } } if (Index != *BootOrderSize / sizeof (UINT16)) { for (Index = 0; Index < *BootOrderSize / sizeof (UINT16) - 1; Index++) { if (Index >= Index2Del) { BootOrder[Index] = BootOrder[Index + 1]; } } *BootOrderSize -= sizeof (UINT16); } return Status; } /** Delete all the invalid legacy boot options. @retval EFI_SUCCESS All invalide legacy boot options are deleted. @retval EFI_OUT_OF_RESOURCES Fail to allocate necessary memory. @retval EFI_NOT_FOUND Fail to retrive variable of boot order. **/ EFI_STATUS BdsDeleteAllInvalidLegacyBootOptions ( VOID ) { UINT16 *BootOrder; UINT8 *BootOptionVar; UINTN BootOrderSize; UINTN BootOptionSize; EFI_STATUS Status; UINT16 HddCount; UINT16 BbsCount; HDD_INFO *LocalHddInfo; BBS_TABLE *LocalBbsTable; BBS_TABLE *BbsEntry; UINT16 BbsIndex; EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; UINTN Index; UINT16 BootOption[10]; UINT16 BootDesc[100]; BOOLEAN DescStringMatch; Status = EFI_SUCCESS; BootOrder = NULL; BootOrderSize = 0; HddCount = 0; BbsCount = 0; LocalHddInfo = NULL; LocalBbsTable = NULL; BbsEntry = NULL; Status = EfiLibLocateProtocol (&gEfiLegacyBiosProtocolGuid, (VOID **) &LegacyBios); if (EFI_ERROR (Status)) { return Status; } refit_call5_wrapper(LegacyBios->GetBbsInfo, LegacyBios, &HddCount, &LocalHddInfo, &BbsCount, &LocalBbsTable ); BootOrder = BdsLibGetVariableAndSize ( L"BootOrder", &EfiGlobalVariableGuid, &BootOrderSize ); if (BootOrder == NULL) { BootOrderSize = 0; } Index = 0; while (Index < BootOrderSize / sizeof (UINT16)) { UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]); BootOptionVar = BdsLibGetVariableAndSize ( BootOption, &EfiGlobalVariableGuid, &BootOptionSize ); if (NULL == BootOptionVar) { BootOptionSize = 0; Status = refit_call5_wrapper(gRT->GetVariable, BootOption, &EfiGlobalVariableGuid, NULL, &BootOptionSize, BootOptionVar ); if (Status == EFI_NOT_FOUND) { // // Update BootOrder // BdsDeleteBootOption ( BootOrder[Index], BootOrder, &BootOrderSize ); continue; } else { FreePool (BootOrder); return EFI_OUT_OF_RESOURCES; } } // // Skip Non-Legacy boot option // if (!BdsIsLegacyBootOption (BootOptionVar, &BbsEntry, &BbsIndex)) { if (BootOptionVar!= NULL) { FreePool (BootOptionVar); } Index++; continue; } if (BbsIndex < BbsCount) { // // Check if BBS Description String is changed // DescStringMatch = FALSE; BdsBuildLegacyDevNameString ( &LocalBbsTable[BbsIndex], BbsIndex, sizeof (BootDesc), BootDesc ); if (StrCmp (BootDesc, (UINT16*)(BootOptionVar + sizeof (UINT32) + sizeof (UINT16))) == 0) { DescStringMatch = TRUE; } if (!((LocalBbsTable[BbsIndex].BootPriority == BBS_IGNORE_ENTRY) || (LocalBbsTable[BbsIndex].BootPriority == BBS_DO_NOT_BOOT_FROM)) && (LocalBbsTable[BbsIndex].DeviceType == BbsEntry->DeviceType) && DescStringMatch) { Index++; continue; } } if (BootOptionVar != NULL) { FreePool (BootOptionVar); } // // should delete // BdsDeleteBootOption ( BootOrder[Index], BootOrder, &BootOrderSize ); } // // Adjust the number of boot options. // if (BootOrderSize != 0) { Status = refit_call5_wrapper(gRT->SetVariable, L"BootOrder", &EfiGlobalVariableGuid, VAR_FLAG, BootOrderSize, BootOrder ); } else { EfiLibDeleteVariable (L"BootOrder", &EfiGlobalVariableGuid); } if (BootOrder != NULL) { FreePool (BootOrder); } return Status; } /** Fill the device order buffer. @param BbsTable The BBS table. @param BbsType The BBS Type. @param BbsCount The BBS Count. @param Buf device order buffer. @return The device order buffer. **/ UINT16 * BdsFillDevOrderBuf ( IN BBS_TABLE *BbsTable, IN BBS_TYPE BbsType, IN UINTN BbsCount, OUT UINT16 *Buf ) { UINTN Index; for (Index = 0; Index < BbsCount; Index++) { if (BbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) { continue; } if (BbsTable[Index].DeviceType != BbsType) { continue; } *Buf = (UINT16) (Index & 0xFF); Buf++; } return Buf; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/EfiLib/GenericBdsLib.h����������������������������������������������������������������0000664�0001750�0001750�00000101740�13106171410�017246� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/** @file Generic BDS library defines general interfaces for a BDS driver, including: 1) BDS boot policy interface. 2) BDS boot device connect interface. 3) BDS Misc interfaces for mainting boot variable, ouput string. Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR> This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License that accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php. THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ #ifndef _GENERIC_BDS_LIB_H_ #define _GENERIC_BDS_LIB_H_ #ifdef __MAKEWITH_GNUEFI #include "gnuefi-helper.h" #endif //#include <Protocol/UserManager.h> /// /// Constants which are variable names used to access variables. /// #define VAR_LEGACY_DEV_ORDER L"LegacyDevOrder" /// /// Data structures and defines. /// #define FRONT_PAGE_QUESTION_ID 0x0000 #define FRONT_PAGE_DATA_WIDTH 0x01 /// /// ConnectType /// #define CONSOLE_OUT 0x00000001 #define STD_ERROR 0x00000002 #define CONSOLE_IN 0x00000004 #define CONSOLE_ALL (CONSOLE_OUT | CONSOLE_IN | STD_ERROR) /// /// Load Option Attributes /// #define LOAD_OPTION_ACTIVE 0x00000001 #define LOAD_OPTION_FORCE_RECONNECT 0x00000002 #define LOAD_OPTION_HIDDEN 0x00000008 #define LOAD_OPTION_CATEGORY 0x00001F00 #define LOAD_OPTION_CATEGORY_BOOT 0x00000000 #define LOAD_OPTION_CATEGORY_APP 0x00000100 #define EFI_BOOT_OPTION_SUPPORT_KEY 0x00000001 #define EFI_BOOT_OPTION_SUPPORT_APP 0x00000002 #define IS_LOAD_OPTION_TYPE(_c, _Mask) (BOOLEAN) (((_c) & (_Mask)) != 0) /// /// Define the maximum characters that will be accepted. /// #define MAX_CHAR 480 #define MAX_CHAR_SIZE (MAX_CHAR * 2) /// /// Define maximum characters for boot option variable "BootXXXX". /// #define BOOT_OPTION_MAX_CHAR 10 // // This data structure is the part of BDS_CONNECT_ENTRY // #ifdef __MAKEWITH_TIANO #define BDS_LOAD_OPTION_SIGNATURE SIGNATURE_32 ('B', 'd', 'C', 'O') #else #define BDS_LOAD_OPTION_SIGNATURE EFI_SIGNATURE_32 ('B', 'd', 'C', 'O') #endif typedef struct { UINTN Signature; LIST_ENTRY Link; EFI_DEVICE_PATH_PROTOCOL *DevicePath; CHAR16 *OptionName; UINTN OptionNumber; UINT16 BootCurrent; UINT32 Attribute; CHAR16 *Description; VOID *LoadOptions; UINT32 LoadOptionsSize; CHAR16 *StatusString; } BDS_COMMON_OPTION; typedef struct { EFI_DEVICE_PATH_PROTOCOL *DevicePath; UINTN ConnectType; } BDS_CONSOLE_CONNECT_ENTRY; // // Bds boot related lib functions // /** Boot from the UEFI spec defined "BootNext" variable. **/ VOID EFIAPI BdsLibBootNext ( VOID ); /** Process the boot option according to the UEFI specification. The legacy boot option device path includes BBS_DEVICE_PATH. @param Option The boot option to be processed. @param DevicePath The device path describing where to load the boot image or the legcy BBS device path to boot the legacy OS. @param ExitDataSize The size of exit data. @param ExitData Data returned when Boot image failed. @retval EFI_SUCCESS Boot from the input boot option succeeded. @retval EFI_NOT_FOUND The Device Path is not found in the system. **/ EFI_STATUS EFIAPI BdsLibBootViaBootOption ( IN BDS_COMMON_OPTION * Option, IN EFI_DEVICE_PATH_PROTOCOL * DevicePath, OUT UINTN *ExitDataSize, OUT CHAR16 **ExitData OPTIONAL ); /** This function will enumerate all possible boot devices in the system, and automatically create boot options for Network, Shell, Removable BlockIo, and Non-BlockIo Simplefile devices. BDS separates EFI boot options into six types: 1. Network - The boot option points to the SimpleNetworkProtocol device. Bds will try to automatically create this type of boot option during enumeration. 2. Shell - The boot option points to internal flash shell. Bds will try to automatically create this type of boot option during enumeration. 3. Removable BlockIo - The boot option points to a removable media device, such as a USB flash drive or DVD drive. These devices should contain a *removable* blockIo protocol in their device handle. Bds will try to automatically create this type boot option when enumerate. 4. Fixed BlockIo - The boot option points to a Fixed blockIo device, such as a hard disk. These devices should contain a *fixed* blockIo protocol in their device handle. BDS will skip fixed blockIo devices, and not automatically create boot option for them. But BDS will help to delete those fixed blockIo boot options, whose description rules conflict with other auto-created boot options. 5. Non-BlockIo Simplefile - The boot option points to a device whose handle has SimpleFileSystem Protocol, but has no blockio protocol. These devices do not offer blockIo protocol, but BDS still can get the \EFI\BOOT\boot{machinename}.EFI by SimpleFileSystem Protocol. 6. File - The boot option points to a file. These boot options are usually created by the user, either manually or with an OS loader. BDS will not delete or modify these boot options. This function will enumerate all possible boot devices in the system, and automatically create boot options for Network, Shell, Removable BlockIo, and Non-BlockIo Simplefile devices. It will excute once every boot. @param BdsBootOptionList The header of the linked list that indexed all current boot options. @retval EFI_SUCCESS Finished all the boot device enumerations and created the boot option based on the boot device. @retval EFI_OUT_OF_RESOURCES Failed to enumerate the boot device and create the boot option list. **/ EFI_STATUS EFIAPI BdsLibEnumerateAllBootOption ( IN OUT LIST_ENTRY *BdsBootOptionList ); /** Build the boot option with the handle parsed in. @param Handle The handle representing the device path for which to create a boot option. @param BdsBootOptionList The header of the link list that indexed all current boot options. @param String The description of the boot option. **/ VOID EFIAPI BdsLibBuildOptionFromHandle ( IN EFI_HANDLE Handle, IN LIST_ENTRY *BdsBootOptionList, IN CHAR16 *String ); /** Build the on flash shell boot option with the handle parsed in. @param Handle The handle which present the device path to create the on flash shell boot option. @param BdsBootOptionList The header of the link list that indexed all current boot options. **/ VOID EFIAPI BdsLibBuildOptionFromShell ( IN EFI_HANDLE Handle, IN OUT LIST_ENTRY *BdsBootOptionList ); /** The function will go through the driver option link list, and then load and start every driver to which the driver option device path points. @param BdsDriverLists The header of the current driver option link list. **/ VOID EFIAPI BdsLibLoadDrivers ( IN LIST_ENTRY *BdsDriverLists ); /** This function processes BootOrder or DriverOrder variables, by calling BdsLibVariableToOption () for each UINT16 in the variables. @param BdsCommonOptionList The header of the option list base on the variable VariableName. @param VariableName An EFI Variable name indicate the BootOrder or DriverOrder. @retval EFI_SUCCESS Successfully created the boot option or driver option list. @retval EFI_OUT_OF_RESOURCES Failed to get the boot option or the driver option list. **/ EFI_STATUS EFIAPI BdsLibBuildOptionFromVar ( IN LIST_ENTRY *BdsCommonOptionList, IN CHAR16 *VariableName ); /** This function reads the EFI variable (VendorGuid/Name) and returns a dynamically allocated buffer and the size of the buffer. If it fails, return NULL. @param Name The string part of the EFI variable name. @param VendorGuid The GUID part of the EFI variable name. @param VariableSize Returns the size of the EFI variable that was read. @return Dynamically allocated memory that contains a copy of the EFI variable. The caller is responsible for freeing the buffer. @retval NULL The variable was not read. **/ VOID * BdsLibGetVariableAndSize ( IN CHAR16 *Name, IN EFI_GUID *VendorGuid, OUT UINTN *VariableSize ); /** This function prints a series of strings. @param ConOut A pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL. @param ... A variable argument list containing a series of strings, the last string must be NULL. @retval EFI_SUCCESS Successfully printed out the string using ConOut. @retval EFI_STATUS Return the status of the ConOut->OutputString (). **/ // EFI_STATUS // EFIAPI // BdsLibOutputStrings ( // IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut, // ... // ); /** Build the boot#### or driver#### option from the VariableName. The build boot#### or driver#### will also be linked to BdsCommonOptionList. @param BdsCommonOptionList The header of the boot#### or driver#### option link list. @param VariableName EFI Variable name, indicates if it is boot#### or driver####. @retval BDS_COMMON_OPTION The option that was created. @retval NULL Failed to get the new option. **/ BDS_COMMON_OPTION * BdsLibVariableToOption ( IN OUT LIST_ENTRY *BdsCommonOptionList, IN CHAR16 *VariableName ); /** This function creates all handles associated with the given device path node. If the handle associated with one device path node cannot be created, then it tries to execute the dispatch to load the missing drivers. @param DevicePathToConnect The device path to be connected. Can be a multi-instance device path. @retval EFI_SUCCESS All handles associates with every device path node were created. @retval EFI_OUT_OF_RESOURCES Not enough resources to create new handles. @retval EFI_NOT_FOUND At least one handle could not be created. **/ EFI_STATUS BdsLibConnectDevicePath ( IN EFI_DEVICE_PATH_PROTOCOL *DevicePathToConnect ); // // Bds connect and disconnect driver lib funcions // /** This function connects all system drivers with the corresponding controllers. **/ VOID EFIAPI BdsLibConnectAllDriversToAllControllers ( VOID ); /** This function will connect console device based on the console device variable ConIn, ConOut and ErrOut. @retval EFI_SUCCESS At least one of the ConIn and ConOut devices have been connected. @retval EFI_STATUS Return the status of BdsLibConnectConsoleVariable (). **/ EFI_STATUS EFIAPI BdsLibConnectAllDefaultConsoles ( VOID ); /** This function updates the console variable based on ConVarName. It can add or remove one specific console device path from the variable @param ConVarName The console-related variable name: ConIn, ConOut, ErrOut. @param CustomizedConDevicePath The console device path to be added to the console variable ConVarName. Cannot be multi-instance. @param ExclusiveDevicePath The console device path to be removed from the console variable ConVarName. Cannot be multi-instance. @retval EFI_UNSUPPORTED The added device path is the same as a removed one. @retval EFI_SUCCESS Successfully added or removed the device path from the console variable. **/ EFI_STATUS EFIAPI BdsLibUpdateConsoleVariable ( IN CHAR16 *ConVarName, IN EFI_DEVICE_PATH_PROTOCOL *CustomizedConDevicePath, IN EFI_DEVICE_PATH_PROTOCOL *ExclusiveDevicePath ); /** Connect the console device base on the variable ConVarName. If ConVarName is a multi-instance device path, and at least one instance connects successfully, then this function will return success. @param ConVarName The console related variable name: ConIn, ConOut, ErrOut. @retval EFI_NOT_FOUND No console devices were connected successfully @retval EFI_SUCCESS Connected at least one instance of the console device path based on the variable ConVarName. **/ EFI_STATUS EFIAPI BdsLibConnectConsoleVariable ( IN CHAR16 *ConVarName ); // // Bds device path related lib functions // /** Delete the instance in Multi that overlaps with Single. @param Multi A pointer to a multi-instance device path data structure. @param Single A pointer to a single-instance device path data structure. @return This function removes the device path instances in Multi that overlap Single, and returns the resulting device path. If there is no remaining device path as a result, this function will return NULL. **/ EFI_DEVICE_PATH_PROTOCOL * EFIAPI BdsLibDelPartMatchInstance ( IN EFI_DEVICE_PATH_PROTOCOL *Multi, IN EFI_DEVICE_PATH_PROTOCOL *Single ); /** This function compares a device path data structure to that of all the nodes of a second device path instance. @param Multi A pointer to a multi-instance device path data structure. @param Single A pointer to a single-instance device path data structure. @retval TRUE If the Single device path is contained within a Multi device path. @retval FALSE The Single device path is not contained within a Multi device path. **/ BOOLEAN EFIAPI BdsLibMatchDevicePaths ( IN EFI_DEVICE_PATH_PROTOCOL *Multi, IN EFI_DEVICE_PATH_PROTOCOL *Single ); /** This function converts an input device structure to a Unicode string. @param DevPath A pointer to the device path structure. @return A newly allocated Unicode string that represents the device path. **/ CHAR16 * EFIAPI DevicePathToStr ( IN EFI_DEVICE_PATH_PROTOCOL *DevPath ); #ifdef __MAKEWITH_TIANO // // Internal definitions // typedef struct { CHAR16 *Str; UINTN Len; UINTN Maxlen; } POOL_PRINT; #endif typedef VOID (*DEV_PATH_FUNCTION) ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ); typedef struct { UINT8 Type; UINT8 SubType; DEV_PATH_FUNCTION Function; } DEVICE_PATH_STRING_TABLE; typedef struct { EFI_DEVICE_PATH_PROTOCOL Header; EFI_GUID Guid; UINT8 VendorDefinedData[1]; } VENDOR_DEVICE_PATH_WITH_DATA; typedef struct { EFI_DEVICE_PATH_PROTOCOL Header; UINT16 NetworkProtocol; UINT16 LoginOption; UINT64 Lun; UINT16 TargetPortalGroupTag; CHAR16 TargetName[1]; } ISCSI_DEVICE_PATH_WITH_NAME; // // BBS support macros and functions // #if defined(MDE_CPU_IA32) || defined(MDE_CPU_X64) #define REFRESH_LEGACY_BOOT_OPTIONS \ BdsDeleteAllInvalidLegacyBootOptions ();\ BdsAddNonExistingLegacyBootOptions (); \ BdsUpdateLegacyDevOrder () #else #define REFRESH_LEGACY_BOOT_OPTIONS #endif /** Delete all the invalid legacy boot options. @retval EFI_SUCCESS All invalid legacy boot options are deleted. @retval EFI_OUT_OF_RESOURCES Failed to allocate necessary memory. @retval EFI_NOT_FOUND Failed to retrieve variable of boot order. **/ EFI_STATUS BdsDeleteAllInvalidLegacyBootOptions ( VOID ); /** Add the legacy boot options from BBS table if they do not exist. @retval EFI_SUCCESS The boot options were added successfully, or they are already in boot options. @retval EFI_NOT_FOUND No legacy boot options is found. @retval EFI_OUT_OF_RESOURCE No enough memory. @return Other value LegacyBoot options are not added. **/ EFI_STATUS BdsAddNonExistingLegacyBootOptions ( VOID ); /** Add the legacy boot devices from BBS table into the legacy device boot order. @retval EFI_SUCCESS The boot devices were added successfully. @retval EFI_NOT_FOUND The legacy boot devices are not found. @retval EFI_OUT_OF_RESOURCES Memory or storage is not enough. @retval EFI_DEVICE_ERROR Failed to add the legacy device boot order into EFI variable because of a hardware error. **/ EFI_STATUS EFIAPI BdsUpdateLegacyDevOrder ( VOID ); /** Refresh the boot priority for BBS entries based on boot option entry and boot order. @param Entry The boot option is to be checked for a refreshed BBS table. @retval EFI_SUCCESS The boot priority for BBS entries refreshed successfully. @retval EFI_NOT_FOUND BBS entries can't be found. @retval EFI_OUT_OF_RESOURCES Failed to get the legacy device boot order. **/ EFI_STATUS EFIAPI BdsRefreshBbsTableForBoot ( IN BDS_COMMON_OPTION *Entry ); /** Delete the Boot Option from EFI Variable. The Boot Order Arrray is also updated. @param OptionNumber The number of Boot options wanting to be deleted. @param BootOrder The Boot Order array. @param BootOrderSize The size of the Boot Order Array. @retval EFI_SUCCESS The Boot Option Variable was found and removed. @retval EFI_UNSUPPORTED The Boot Option Variable store was inaccessible. @retval EFI_NOT_FOUND The Boot Option Variable was not found. **/ EFI_STATUS BdsDeleteBootOption ( IN UINTN OptionNumber, IN OUT UINT16 *BootOrder, IN OUT UINTN *BootOrderSize ); // //The interface functions related to the Setup Browser Reset Reminder feature // /** Enable the setup browser reset reminder feature. This routine is used in a platform tip. If the platform policy needs the feature, use the routine to enable it. **/ VOID EFIAPI EnableResetReminderFeature ( VOID ); /** Disable the setup browser reset reminder feature. This routine is used in a platform tip. If the platform policy does not want the feature, use the routine to disable it. **/ VOID EFIAPI DisableResetReminderFeature ( VOID ); /** Record the info that a reset is required. A module boolean variable is used to record whether a reset is required. **/ VOID EFIAPI EnableResetRequired ( VOID ); /** Record the info that no reset is required. A module boolean variable is used to record whether a reset is required. **/ VOID EFIAPI DisableResetRequired ( VOID ); /** Check whether platform policy enables the reset reminder feature. The default is enabled. **/ BOOLEAN EFIAPI IsResetReminderFeatureEnable ( VOID ); /** Check if the user changed any option setting that needs a system reset to be effective. **/ BOOLEAN EFIAPI IsResetRequired ( VOID ); /** Check whether a reset is needed, and finish the reset reminder feature. If a reset is needed, pop up a menu to notice user, and finish the feature according to the user selection. **/ VOID EFIAPI SetupResetReminder ( VOID ); /// /// Define the boot type with which to classify the boot option type. /// Different boot option types could have different boot behaviors. /// Use their device path node (Type + SubType) as the type value. /// The boot type here can be added according to requirements. /// /// /// ACPI boot type. For ACPI devices, using sub-types to distinguish devices is not allowed, so hardcode their values. /// #define BDS_EFI_ACPI_FLOPPY_BOOT 0x0201 /// /// Message boot type /// If a device path of boot option only points to a message node, the boot option is a message boot type. /// #define BDS_EFI_MESSAGE_ATAPI_BOOT 0x0301 // Type 03; Sub-Type 01 #define BDS_EFI_MESSAGE_SCSI_BOOT 0x0302 // Type 03; Sub-Type 02 #define BDS_EFI_MESSAGE_USB_DEVICE_BOOT 0x0305 // Type 03; Sub-Type 05 #define BDS_EFI_MESSAGE_SATA_BOOT 0x0312 // Type 03; Sub-Type 18 #define BDS_EFI_MESSAGE_MAC_BOOT 0x030b // Type 03; Sub-Type 11 #define BDS_EFI_MESSAGE_MISC_BOOT 0x03FF /// /// Media boot type /// If a device path of boot option contains a media node, the boot option is media boot type. /// #define BDS_EFI_MEDIA_HD_BOOT 0x0401 // Type 04; Sub-Type 01 #define BDS_EFI_MEDIA_CDROM_BOOT 0x0402 // Type 04; Sub-Type 02 /// /// BBS boot type /// If a device path of boot option contains a BBS node, the boot option is BBS boot type. /// #define BDS_LEGACY_BBS_BOOT 0x0501 // Type 05; Sub-Type 01 #define BDS_EFI_UNSUPPORT 0xFFFF /** Check whether an instance in BlockIoDevicePath has the same partition node as the HardDriveDevicePath device path. @param BlockIoDevicePath Multi device path instances to check. @param HardDriveDevicePath A device path starting with a hard drive media device path. @retval TRUE There is a matched device path instance. @retval FALSE There is no matched device path instance. **/ BOOLEAN EFIAPI MatchPartitionDevicePathNode ( IN EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath, IN HARDDRIVE_DEVICE_PATH *HardDriveDevicePath ); /** Expand a device path that starts with a hard drive media device path node to be a full device path that includes the full hardware path to the device. This function enables the device to boot. To avoid requiring a connect on every boot, the front match is saved in a variable (the part point to the partition node. E.g. ACPI() /PCI()/ATA()/Partition() ). All successful history device paths that point to the front part of the partition node will be saved. @param HardDriveDevicePath EFI Device Path to boot, if it starts with a hard drive media device path. @return A Pointer to the full device path, or NULL if a valid Hard Drive devic path cannot be found. **/ EFI_DEVICE_PATH_PROTOCOL * EFIAPI BdsExpandPartitionPartialDevicePathToFull ( IN HARDDRIVE_DEVICE_PATH *HardDriveDevicePath ); /** Return the bootable media handle. First, check whether the device is connected. Second, check whether the device path points to a device that supports SimpleFileSystemProtocol. Third, detect the the default boot file in the Media, and return the removable Media handle. @param DevicePath The Device Path to a bootable device. @return The bootable media handle. If the media on the DevicePath is not bootable, NULL will return. **/ EFI_HANDLE EFIAPI BdsLibGetBootableHandle ( IN EFI_DEVICE_PATH_PROTOCOL *DevicePath ); /** Checks whether the Device path in a boot option points to a valid bootable device, and if the device is ready to boot now. @param DevPath The Device path in a boot option. @param CheckMedia If TRUE, check whether the device is ready to boot now. @retval TRUE The Device path is valid. @retval FALSE The Device path is invalid. **/ BOOLEAN EFIAPI BdsLibIsValidEFIBootOptDevicePath ( IN EFI_DEVICE_PATH_PROTOCOL *DevPath, IN BOOLEAN CheckMedia ); /** Checks whether the Device path in a boot option points to a valid bootable device, and if the device is ready to boot now. If Description is not NULL and the device path points to a fixed BlockIo device, this function checks whether the description conflicts with other auto-created boot options. @param DevPath The Device path in a boot option. @param CheckMedia If TRUE, checks if the device is ready to boot now. @param Description The description of a boot option. @retval TRUE The Device path is valid. @retval FALSE The Device path is invalid. **/ BOOLEAN EFIAPI BdsLibIsValidEFIBootOptDevicePathExt ( IN EFI_DEVICE_PATH_PROTOCOL *DevPath, IN BOOLEAN CheckMedia, IN CHAR16 *Description ); /** For a bootable Device path, return its boot type. @param DevicePath The bootable device Path to check. @retval BDS_EFI_MEDIA_HD_BOOT The given device path contains MEDIA_DEVICE_PATH type device path node, whose subtype is MEDIA_HARDDRIVE_DP. @retval BDS_EFI_MEDIA_CDROM_BOOT If given device path contains MEDIA_DEVICE_PATH type device path node, whose subtype is MEDIA_CDROM_DP. @retval BDS_EFI_ACPI_FLOPPY_BOOT A given device path contains ACPI_DEVICE_PATH type device path node, whose HID is floppy device. @retval BDS_EFI_MESSAGE_ATAPI_BOOT A given device path contains MESSAGING_DEVICE_PATH type device path node, and its last device path node's subtype is MSG_ATAPI_DP. @retval BDS_EFI_MESSAGE_SCSI_BOOT A given device path contains MESSAGING_DEVICE_PATH type device path node, and its last device path node's subtype is MSG_SCSI_DP. @retval BDS_EFI_MESSAGE_USB_DEVICE_BOOT A given device path contains MESSAGING_DEVICE_PATH type device path node, and its last device path node's subtype is MSG_USB_DP. @retval BDS_EFI_MESSAGE_MISC_BOOT The device path does not contain any media device path node, and its last device path node points to a message device path node. @retval BDS_LEGACY_BBS_BOOT A given device path contains BBS_DEVICE_PATH type device path node. @retval BDS_EFI_UNSUPPORT An EFI Removable BlockIO device path does not point to a media and message device. **/ UINT32 EFIAPI BdsGetBootTypeFromDevicePath ( IN EFI_DEVICE_PATH_PROTOCOL *DevicePath ); /** This routine registers a function to adjust the different types of memory page numbers just before booting, and saves the updated info into the variable for the next boot to use. **/ VOID EFIAPI BdsLibSaveMemoryTypeInformation ( VOID ); /** Identify a user and, if authenticated, returns the current user profile handle. @param[out] User Points to the user profile handle. @retval EFI_SUCCESS The user is successfully identified, or user identification is not supported. @retval EFI_ACCESS_DENIED The user was not successfully identified. **/ /** This function checks if a Fv file device path is valid, according to a file GUID. If it is invalid, it tries to return the valid device path. FV address maybe changes for memory layout adjust from time to time, use this funciton could promise the Fv file device path is right. @param DevicePath On input, the Fv file device path to check. On output, the updated valid Fv file device path @param FileGuid the Fv file GUID. @retval EFI_INVALID_PARAMETER The input DevicePath or FileGuid is invalid. @retval EFI_UNSUPPORTED The input DevicePath does not contain an Fv file GUID at all. @retval EFI_ALREADY_STARTED The input DevicePath has pointed to the Fv file and is valid. @retval EFI_SUCCESS Successfully updated the invalid DevicePath and returned the updated device path in DevicePath. **/ EFI_STATUS EFIAPI BdsLibUpdateFvFileDevicePath ( IN OUT EFI_DEVICE_PATH_PROTOCOL ** DevicePath, IN EFI_GUID *FileGuid ); /** Connect the specific USB device that matches the RemainingDevicePath, and whose bus is determined by Host Controller (Uhci or Ehci). @param HostControllerPI Uhci (0x00) or Ehci (0x20) or Both uhci and ehci (0xFF). @param RemainingDevicePath A short-form device path that starts with the first element being a USB WWID or a USB Class device path. @retval EFI_SUCCESS The specific Usb device is connected successfully. @retval EFI_INVALID_PARAMETER Invalid HostControllerPi (not 0x00, 0x20 or 0xFF) or RemainingDevicePath is not the USB class device path. @retval EFI_NOT_FOUND The device specified by device path is not found. **/ EFI_STATUS EFIAPI BdsLibConnectUsbDevByShortFormDP( IN UINT8 HostControllerPI, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath ); // // The implementation of this function is provided by Platform code. // /** Convert Vendor device path to a device name. @param Str The buffer storing device name. @param DevPath The pointer to vendor device path. **/ VOID DevPathVendor ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ); /** Concatenates a formatted unicode string to an allocated pool. The caller must free the resulting buffer. @param Str Tracks the allocated pool, size in use, and amount of pool allocated. @param Fmt The format string. @param ... The data will be printed. @return Allocated buffer with the formatted string printed in it. The caller must free the allocated buffer. The buffer allocation is not packed. **/ CHAR16 * EFIAPI MyCatPrint ( IN OUT POOL_PRINT *Str, IN CHAR16 *Fmt, ... ); /** Use SystemTable ConOut to stop video based Simple Text Out consoles from going to the video device. Put up LogoFile on every video device that is a console. @param[in] LogoFile The file name of logo to display on the center of the screen. @retval EFI_SUCCESS ConsoleControl has been flipped to graphics and logo displayed. @retval EFI_UNSUPPORTED Logo not found. **/ EFI_STATUS EFIAPI EnableQuietBoot ( IN EFI_GUID *LogoFile ); /** Use SystemTable ConOut to turn on video based Simple Text Out consoles. The Simple Text Out screens will now be synced up with all non-video output devices. @retval EFI_SUCCESS UGA devices are back in text mode and synced up. **/ EFI_STATUS EFIAPI DisableQuietBoot ( VOID ); #endif ��������������������������������refind-0.11.4/EfiLib/BdsHelper.c��������������������������������������������������������������������0000664�0001750�0001750�00000012416�12627675150�016477� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * EfiLib/BdsHelper.c * Functions to call legacy BIOS API. * */ /** Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR> This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ #include "BdsHelper.h" #include "legacy.h" #include "mystrings.h" #include "../refind/screen.h" #include "../refind/lib.h" #include "../include/refit_call_wrapper.h" EFI_GUID gEfiLegacyBootProtocolGuid = { 0xdb9a1e3d, 0x45cb, 0x4abb, { 0x85, 0x3b, 0xe5, 0x38, 0x7f, 0xdb, 0x2e, 0x2d }}; /** Internal helper function. Update the BBS Table so that devices of DeviceType have their boot priority updated to a high/bootable value. See "DeviceType values" in http://www.intel.com/content/dam/doc/reference-guide/efi-compatibility-support-module-specification-v097.pdf NOTE: This function should probably be refactored! Currently, all devices of type are enabled. This should be updated so that only a specific device is enabled. The wrong device could boot if there are multiple targets of the same type. @param DeviceType The device type that we wish to enable **/ VOID UpdateBbsTable (BDS_COMMON_OPTION *Option) { UINT16 Idx; EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; EFI_STATUS Status; UINT16 HddCount = 0; HDD_INFO *HddInfo = NULL; UINT16 BbsCount = 0; BBS_TABLE *LocalBbsTable = NULL; BBS_BBS_DEVICE_PATH *OptionBBS; CHAR16 Desc[100]; Status = refit_call3_wrapper(gBS->LocateProtocol, &gEfiLegacyBootProtocolGuid, NULL, (VOID **) &LegacyBios); if (EFI_ERROR (Status) || (Option == NULL)) { return; } OptionBBS = (BBS_BBS_DEVICE_PATH *) Option->DevicePath; Status = refit_call5_wrapper(LegacyBios->GetBbsInfo, LegacyBios, &HddCount, &HddInfo, &BbsCount, &LocalBbsTable); // Print (L"\n"); // Print (L" NO Prio bb/dd/ff cl/sc Type Stat segm:offs\n"); // Print (L"=============================================\n"); for (Idx = 0; Idx < BbsCount; Idx++) { if(LocalBbsTable[Idx].DeviceType == 0) { continue; } BdsBuildLegacyDevNameString (&LocalBbsTable[Idx], Idx, sizeof (Desc), Desc); // Set devices of a particular type to BootPriority of 0 or 1. 0 is the highest priority. if (LocalBbsTable[Idx].DeviceType == OptionBBS->DeviceType) { if (MyStriCmp(Desc, Option->Description)) { // This entry exactly matches what we're looking for; make it highest priority LocalBbsTable[Idx].BootPriority = 0; } else { // This entry doesn't exactly match, but is the right disk type; make it a bit lower // in priority. Done mainly as a fallback in case of string-matching weirdness. LocalBbsTable[Idx].BootPriority = 1; } // if/else } else if (LocalBbsTable[Idx].BootPriority <= 1) { // Something's got a high enough boot priority to interfere with booting // our chosen entry, so bump it down a bit.... LocalBbsTable[Idx].BootPriority = 2; } // if/else if // Print ( // L" %02x: %04x %02x/%02x/%02x %02x/%02x %04x %04x %04x:%04x\n", // (UINTN) Idx, // (UINTN) LocalBbsTable[Idx].BootPriority, // (UINTN) LocalBbsTable[Idx].Bus, // (UINTN) LocalBbsTable[Idx].Device, // (UINTN) LocalBbsTable[Idx].Function, // (UINTN) LocalBbsTable[Idx].Class, // (UINTN) LocalBbsTable[Idx].SubClass, // (UINTN) LocalBbsTable[Idx].DeviceType, // (UINTN) * (UINT16 *) &LocalBbsTable[Idx].StatusFlags, // (UINTN) LocalBbsTable[Idx].BootHandlerSegment, // (UINTN) LocalBbsTable[Idx].BootHandlerOffset, // (UINTN) ((LocalBbsTable[Idx].MfgStringSegment << 4) + LocalBbsTable[Idx].MfgStringOffset), // (UINTN) ((LocalBbsTable[Idx].DescStringSegment << 4) + LocalBbsTable[Idx].DescStringOffset) // ); // Print(L"%s\n", Desc); } // for // PauseForKey(); } /** Boot the legacy system with the boot option @param Option The legacy boot option which have BBS device path @retval EFI_UNSUPPORTED There is no legacybios protocol, do not support legacy boot. @retval EFI_STATUS Return the status of LegacyBios->LegacyBoot (). **/ EFI_STATUS BdsLibDoLegacyBoot ( IN BDS_COMMON_OPTION *Option ) { EFI_STATUS Status; EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; Status = refit_call3_wrapper(gBS->LocateProtocol, &gEfiLegacyBootProtocolGuid, NULL, (VOID **) &LegacyBios); if (EFI_ERROR (Status)) { return EFI_UNSUPPORTED; } UpdateBbsTable(Option); return refit_call4_wrapper(LegacyBios->LegacyBoot, LegacyBios, (BBS_BBS_DEVICE_PATH *) Option->DevicePath, Option->LoadOptionsSize, Option->LoadOptions); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/EfiLib/DevicePath.c�������������������������������������������������������������������0000664�0001750�0001750�00000114667�13106171410�016635� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/** @file BDS internal function define the default device path string, it can be replaced by platform device path. Copyright (c) 2004 - 2009, Intel Corporation. All rights reserved.<BR> This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ #include "Platform.h" /** Concatenates a formatted unicode string to allocated pool. The caller must free the resulting buffer. @param Str Tracks the allocated pool, size in use, and amount of pool allocated. @param Fmt The format string @param ... The data will be printed. @return Allocated buffer with the formatted string printed in it. The caller must free the allocated buffer. The buffer allocation is not packed. **/ CHAR16 * EFIAPI MyCatPrint ( IN OUT POOL_PRINT *Str, IN CHAR16 *Fmt, ... ) { UINT16 *AppendStr; VA_LIST Args; UINTN StringSize; AppendStr = AllocateZeroPool (0x1000); if (AppendStr == NULL) { return Str->Str; } VA_START (Args, Fmt); UnicodeVSPrint (AppendStr, 0x1000, Fmt, Args); VA_END (Args); if (NULL == Str->Str) { StringSize = StrSize (AppendStr); Str->Str = AllocateZeroPool (StringSize); ASSERT (Str->Str != NULL); } else { StringSize = StrSize (AppendStr); StringSize += (StrSize (Str->Str) - sizeof (UINT16)); Str->Str = EfiReallocatePool ( Str->Str, StrSize (Str->Str), StringSize ); ASSERT (Str->Str != NULL); } Str->Maxlen = MAX_CHAR * sizeof (UINT16); if (StringSize < Str->Maxlen) { StrCat (Str->Str, AppendStr); Str->Len = StringSize - sizeof (UINT16); } FreePool (AppendStr); return Str->Str; } /** Convert Device Path to a Unicode string for printing. @param Str The buffer holding the output string. This buffer contains the length of the string and the maixmum length reserved for the string buffer. @param DevPath The device path. **/ VOID DevPathPci ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { PCI_DEVICE_PATH *Pci; Pci = DevPath; MyCatPrint (Str, L"Pci(%x|%x)", (UINTN) Pci->Device, (UINTN) Pci->Function); } /** Convert Device Path to a Unicode string for printing. @param Str The buffer holding the output string. This buffer contains the length of the string and the maixmum length reserved for the string buffer. @param DevPath The device path. **/ VOID DevPathPccard ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { PCCARD_DEVICE_PATH *Pccard; Pccard = DevPath; MyCatPrint (Str, L"Pcmcia(Function%x)", (UINTN) Pccard->FunctionNumber); } /** Convert Device Path to a Unicode string for printing. @param Str The buffer holding the output string. This buffer contains the length of the string and the maixmum length reserved for the string buffer. @param DevPath The device path. **/ VOID DevPathMemMap ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { MEMMAP_DEVICE_PATH *MemMap; MemMap = DevPath; MyCatPrint ( Str, L"MemMap(%d:%lx-%lx)", (UINTN) MemMap->MemoryType, MemMap->StartingAddress, MemMap->EndingAddress ); } /** Convert Device Path to a Unicode string for printing. @param Str The buffer holding the output string. This buffer contains the length of the string and the maixmum length reserved for the string buffer. @param DevPath The device path. **/ VOID DevPathController ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { CONTROLLER_DEVICE_PATH *Controller; Controller = DevPath; MyCatPrint (Str, L"Ctrl(%d)", (UINTN) Controller->ControllerNumber); } /** Convert Vendor device path to device name. @param Str The buffer store device name @param DevPath Pointer to vendor device path **/ VOID DevPathVendor ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { VENDOR_DEVICE_PATH *Vendor; CHAR16 *Type; UINTN DataLength; UINTN Index; // UINT32 FlowControlMap; UINT16 Info; Vendor = DevPath; switch (DevicePathType (&Vendor->Header)) { case HARDWARE_DEVICE_PATH: Type = L"Hw"; break; case MESSAGING_DEVICE_PATH: Type = L"Msg"; /* if (CompareGuid (&Vendor->Guid, &gEfiPcAnsiGuid)) { MyCatPrint (Str, L"VenPcAnsi()"); return ; } else if (CompareGuid (&Vendor->Guid, &gEfiVT100Guid)) { MyCatPrint (Str, L"VenVt100()"); return ; } else if (CompareGuid (&Vendor->Guid, &gEfiVT100PlusGuid)) { MyCatPrint (Str, L"VenVt100Plus()"); return ; } else if (CompareGuid (&Vendor->Guid, &gEfiVTUTF8Guid)) { MyCatPrint (Str, L"VenUft8()"); return ; } else if (CompareGuid (&Vendor->Guid, &gEfiUartDevicePathGuid )) { FlowControlMap = (((UART_FLOW_CONTROL_DEVICE_PATH *) Vendor)->FlowControlMap); switch (FlowControlMap & 0x00000003) { case 0: MyCatPrint (Str, L"UartFlowCtrl(%s)", L"None"); break; case 1: MyCatPrint (Str, L"UartFlowCtrl(%s)", L"Hardware"); break; case 2: MyCatPrint (Str, L"UartFlowCtrl(%s)", L"XonXoff"); break; default: break; } return ; } else */ if (CompareGuid (&Vendor->Guid, &gEfiSasDevicePathGuid)) { MyCatPrint ( Str, L"SAS(%lx,%lx,%x,", ((SAS_DEVICE_PATH *) Vendor)->SasAddress, ((SAS_DEVICE_PATH *) Vendor)->Lun, (UINTN) ((SAS_DEVICE_PATH *) Vendor)->RelativeTargetPort ); Info = (((SAS_DEVICE_PATH *) Vendor)->DeviceTopology); if ((Info & 0x0f) == 0) { MyCatPrint (Str, L"NoTopology,0,0,0,"); } else if (((Info & 0x0f) == 1) || ((Info & 0x0f) == 2)) { MyCatPrint ( Str, L"%s,%s,%s,", ((Info & (0x1 << 4)) != 0) ? L"SATA" : L"SAS", ((Info & (0x1 << 5)) != 0) ? L"External" : L"Internal", ((Info & (0x1 << 6)) != 0) ? L"Expanded" : L"Direct" ); if ((Info & 0x0f) == 1) { MyCatPrint (Str, L"0,"); } else { MyCatPrint (Str, L"%x,", (UINTN) ((Info >> 8) & 0xff)); } } else { MyCatPrint (Str, L"0,0,0,0,"); } MyCatPrint (Str, L"%x)", (UINTN) ((SAS_DEVICE_PATH *) Vendor)->Reserved); return ; } else if (CompareGuid (&Vendor->Guid, &gEfiDebugPortProtocolGuid)) { MyCatPrint (Str, L"DebugPort()"); return ; } break; case MEDIA_DEVICE_PATH: Type = L"Media"; break; default: Type = L"?"; break; } MyCatPrint (Str, L"Ven%s(%g", Type, &Vendor->Guid); DataLength = DevicePathNodeLength (&Vendor->Header) - sizeof (VENDOR_DEVICE_PATH); if (DataLength > 0) { MyCatPrint (Str, L","); for (Index = 0; Index < DataLength; Index++) { MyCatPrint (Str, L"%02x", (UINTN) ((VENDOR_DEVICE_PATH_WITH_DATA *) Vendor)->VendorDefinedData[Index]); } } MyCatPrint (Str, L")"); } /** Convert Device Path to a Unicode string for printing. @param Str The buffer holding the output string. This buffer contains the length of the string and the maixmum length reserved for the string buffer. @param DevPath The device path. **/ VOID DevPathAcpi ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { ACPI_HID_DEVICE_PATH *Acpi; Acpi = DevPath; if ((Acpi->HID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) { MyCatPrint (Str, L"Acpi(PNP%04x,%x)", (UINTN) EISA_ID_TO_NUM (Acpi->HID), (UINTN) Acpi->UID); } else { MyCatPrint (Str, L"Acpi(%08x,%x)", (UINTN) Acpi->HID, (UINTN) Acpi->UID); } } /** Convert Device Path to a Unicode string for printing. @param Str The buffer holding the output string. This buffer contains the length of the string and the maixmum length reserved for the string buffer. @param DevPath The device path. **/ VOID DevPathExtendedAcpi ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { ACPI_EXTENDED_HID_DEVICE_PATH *ExtendedAcpi; // // Index for HID, UID and CID strings, 0 for non-exist // UINT16 HIDSTRIdx; UINT16 UIDSTRIdx; UINT16 CIDSTRIdx; UINT16 Index; UINT16 Length; UINT16 Anchor; CHAR8 *AsChar8Array; HIDSTRIdx = 0; UIDSTRIdx = 0; CIDSTRIdx = 0; ExtendedAcpi = DevPath; Length = (UINT16) DevicePathNodeLength ((EFI_DEVICE_PATH_PROTOCOL *) ExtendedAcpi); AsChar8Array = (CHAR8 *) ExtendedAcpi; // // find HIDSTR // Anchor = 16; for (Index = Anchor; Index < Length && AsChar8Array[Index] != '\0'; Index++) { ; } if (Index > Anchor) { HIDSTRIdx = Anchor; } // // find UIDSTR // Anchor = (UINT16) (Index + 1); for (Index = Anchor; Index < Length && AsChar8Array[Index] != '\0'; Index++) { ; } if (Index > Anchor) { UIDSTRIdx = Anchor; } // // find CIDSTR // Anchor = (UINT16) (Index + 1); for (Index = Anchor; Index < Length && AsChar8Array[Index] != '\0'; Index++) { ; } if (Index > Anchor) { CIDSTRIdx = Anchor; } if (HIDSTRIdx == 0 && CIDSTRIdx == 0 && ExtendedAcpi->UID == 0) { MyCatPrint (Str, L"AcpiExp("); if ((ExtendedAcpi->HID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) { MyCatPrint (Str, L"PNP%04x,", (UINTN) EISA_ID_TO_NUM (ExtendedAcpi->HID)); } else { MyCatPrint (Str, L"%08x,", (UINTN) ExtendedAcpi->HID); } if ((ExtendedAcpi->CID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) { MyCatPrint (Str, L"PNP%04x,", (UINTN) EISA_ID_TO_NUM (ExtendedAcpi->CID)); } else { MyCatPrint (Str, L"%08x,", (UINTN) ExtendedAcpi->CID); } if (UIDSTRIdx != 0) { MyCatPrint (Str, L"%a)", AsChar8Array + UIDSTRIdx); } else { MyCatPrint (Str, L"\"\")"); } } else { MyCatPrint (Str, L"AcpiEx("); if ((ExtendedAcpi->HID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) { MyCatPrint (Str, L"PNP%04x,", (UINTN) EISA_ID_TO_NUM (ExtendedAcpi->HID)); } else { MyCatPrint (Str, L"%08x,", (UINTN) ExtendedAcpi->HID); } if ((ExtendedAcpi->CID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) { MyCatPrint (Str, L"PNP%04x,", (UINTN) EISA_ID_TO_NUM (ExtendedAcpi->CID)); } else { MyCatPrint (Str, L"%08x,", (UINTN) ExtendedAcpi->CID); } MyCatPrint (Str, L"%x,", (UINTN) ExtendedAcpi->UID); if (HIDSTRIdx != 0) { MyCatPrint (Str, L"%a,", AsChar8Array + HIDSTRIdx); } else { MyCatPrint (Str, L"\"\","); } if (CIDSTRIdx != 0) { MyCatPrint (Str, L"%a,", AsChar8Array + CIDSTRIdx); } else { MyCatPrint (Str, L"\"\","); } if (UIDSTRIdx != 0) { MyCatPrint (Str, L"%a)", AsChar8Array + UIDSTRIdx); } else { MyCatPrint (Str, L"\"\")"); } } } /** Convert Device Path to a Unicode string for printing. @param Str The buffer holding the output string. This buffer contains the length of the string and the maixmum length reserved for the string buffer. @param DevPath The device path. **/ VOID DevPathAdrAcpi ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { ACPI_ADR_DEVICE_PATH *AcpiAdr; UINT16 Index; UINT16 Length; UINT16 AdditionalAdrCount; AcpiAdr = DevPath; Length = (UINT16) DevicePathNodeLength ((EFI_DEVICE_PATH_PROTOCOL *) AcpiAdr); AdditionalAdrCount = (UINT16) ((Length - 8) / 4); MyCatPrint (Str, L"AcpiAdr(%x", (UINTN) AcpiAdr->ADR); for (Index = 0; Index < AdditionalAdrCount; Index++) { MyCatPrint (Str, L",%x", (UINTN) *(UINT32 *) ((UINT8 *) AcpiAdr + 8 + Index * 4)); } MyCatPrint (Str, L")"); } /** Convert Device Path to a Unicode string for printing. @param Str The buffer holding the output string. This buffer contains the length of the string and the maixmum length reserved for the string buffer. @param DevPath The device path. **/ VOID DevPathAtapi ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { ATAPI_DEVICE_PATH *Atapi; Atapi = DevPath; MyCatPrint ( Str, L"Ata(%s,%s)", (Atapi->PrimarySecondary != 0)? L"Secondary" : L"Primary", (Atapi->SlaveMaster != 0)? L"Slave" : L"Master" ); } /** Convert Device Path to a Unicode string for printing. @param Str The buffer holding the output string. This buffer contains the length of the string and the maixmum length reserved for the string buffer. @param DevPath The device path. **/ VOID DevPathScsi ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { SCSI_DEVICE_PATH *Scsi; Scsi = DevPath; MyCatPrint (Str, L"Scsi(Pun%x,Lun%x)", (UINTN) Scsi->Pun, (UINTN) Scsi->Lun); } /** Convert Device Path to a Unicode string for printing. @param Str The buffer holding the output string. This buffer contains the length of the string and the maixmum length reserved for the string buffer. @param DevPath The device path. **/ VOID DevPathFibre ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { FIBRECHANNEL_DEVICE_PATH *Fibre; Fibre = DevPath; MyCatPrint (Str, L"Fibre(Wwn%lx,Lun%x)", Fibre->WWN, Fibre->Lun); } /** Convert Device Path to a Unicode string for printing. @param Str The buffer holding the output string. This buffer contains the length of the string and the maixmum length reserved for the string buffer. @param DevPath The device path. **/ VOID DevPath1394 ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { F1394_DEVICE_PATH *F1394Path; F1394Path = DevPath; MyCatPrint (Str, L"1394(%lx)", &F1394Path->Guid); } /** Convert Device Path to a Unicode string for printing. @param Str The buffer holding the output string. This buffer contains the length of the string and the maixmum length reserved for the string buffer. @param DevPath The device path. **/ VOID DevPathUsb ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { USB_DEVICE_PATH *Usb; Usb = DevPath; MyCatPrint (Str, L"Usb(%x,%x)", (UINTN) Usb->ParentPortNumber, (UINTN) Usb->InterfaceNumber); } /** Convert Device Path to a Unicode string for printing. @param Str The buffer holding the output string. This buffer contains the length of the string and the maixmum length reserved for the string buffer. @param DevPath The device path. **/ VOID DevPathUsbWWID ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { USB_WWID_DEVICE_PATH *UsbWWId; UsbWWId = DevPath; MyCatPrint ( Str, L"UsbWwid(%x,%x,%x,\"WWID\")", (UINTN) UsbWWId->VendorId, (UINTN) UsbWWId->ProductId, (UINTN) UsbWWId->InterfaceNumber ); } /** Convert Device Path to a Unicode string for printing. @param Str The buffer holding the output string. This buffer contains the length of the string and the maixmum length reserved for the string buffer. @param DevPath The device path. **/ VOID DevPathLogicalUnit ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { DEVICE_LOGICAL_UNIT_DEVICE_PATH *LogicalUnit; LogicalUnit = DevPath; MyCatPrint (Str, L"Unit(%x)", (UINTN) LogicalUnit->Lun); } /** Convert Device Path to a Unicode string for printing. @param Str The buffer holding the output string. This buffer contains the length of the string and the maixmum length reserved for the string buffer. @param DevPath The device path. **/ VOID DevPathUsbClass ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { USB_CLASS_DEVICE_PATH *UsbClass; UsbClass = DevPath; MyCatPrint ( Str, L"Usb Class(%x,%x,%x,%x,%x)", (UINTN) UsbClass->VendorId, (UINTN) UsbClass->ProductId, (UINTN) UsbClass->DeviceClass, (UINTN) UsbClass->DeviceSubClass, (UINTN) UsbClass->DeviceProtocol ); } /** Convert Device Path to a Unicode string for printing. @param Str The buffer holding the output string. This buffer contains the length of the string and the maixmum length reserved for the string buffer. @param DevPath The device path. **/ VOID DevPathSata ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { SATA_DEVICE_PATH *Sata; Sata = DevPath; if ((Sata->PortMultiplierPortNumber & SATA_HBA_DIRECT_CONNECT_FLAG) != 0) { MyCatPrint ( Str, L"Sata(%x,%x)", (UINTN) Sata->HBAPortNumber, (UINTN) Sata->Lun ); } else { MyCatPrint ( Str, L"Sata(%x,%x,%x)", (UINTN) Sata->HBAPortNumber, (UINTN) Sata->PortMultiplierPortNumber, (UINTN) Sata->Lun ); } } /** Convert Device Path to a Unicode string for printing. @param Str The buffer holding the output string. This buffer contains the length of the string and the maixmum length reserved for the string buffer. @param DevPath The device path. **/ VOID DevPathI2O ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { I2O_DEVICE_PATH *I2OPath; I2OPath = DevPath; MyCatPrint (Str, L"I2O(%x)", (UINTN) I2OPath->Tid); } /** Convert Device Path to a Unicode string for printing. @param Str The buffer holding the output string. This buffer contains the length of the string and the maixmum length reserved for the string buffer. @param DevPath The device path. **/ VOID DevPathMacAddr ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { MAC_ADDR_DEVICE_PATH *MACDevPath; UINTN HwAddressSize; UINTN Index; MACDevPath = DevPath; HwAddressSize = sizeof (EFI_MAC_ADDRESS); if (MACDevPath->IfType == 0x01 || MACDevPath->IfType == 0x00) { HwAddressSize = 6; } MyCatPrint (Str, L"Mac("); for (Index = 0; Index < HwAddressSize; Index++) { MyCatPrint (Str, L"%02x", (UINTN) MACDevPath->MacAddress.Addr[Index]); } MyCatPrint (Str, L")"); } /** Convert Device Path to a Unicode string for printing. @param Str The buffer holding the output string. This buffer contains the length of the string and the maixmum length reserved for the string buffer. @param DevPath The device path. **/ VOID DevPathIPv4 ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { IPv4_DEVICE_PATH *IPDevPath; IPDevPath = DevPath; MyCatPrint ( Str, L"IPv4(%d.%d.%d.%d:%d)", (UINTN) IPDevPath->RemoteIpAddress.Addr[0], (UINTN) IPDevPath->RemoteIpAddress.Addr[1], (UINTN) IPDevPath->RemoteIpAddress.Addr[2], (UINTN) IPDevPath->RemoteIpAddress.Addr[3], (UINTN) IPDevPath->RemotePort ); } /** Convert Device Path to a Unicode string for printing. @param Str The buffer holding the output string. This buffer contains the length of the string and the maixmum length reserved for the string buffer. @param DevPath The device path. **/ VOID DevPathIPv6 ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { IPv6_DEVICE_PATH *IPv6DevPath; IPv6DevPath = DevPath; MyCatPrint ( Str, L"IPv6(%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x)", (UINTN) IPv6DevPath->RemoteIpAddress.Addr[0], (UINTN) IPv6DevPath->RemoteIpAddress.Addr[1], (UINTN) IPv6DevPath->RemoteIpAddress.Addr[2], (UINTN) IPv6DevPath->RemoteIpAddress.Addr[3], (UINTN) IPv6DevPath->RemoteIpAddress.Addr[4], (UINTN) IPv6DevPath->RemoteIpAddress.Addr[5], (UINTN) IPv6DevPath->RemoteIpAddress.Addr[6], (UINTN) IPv6DevPath->RemoteIpAddress.Addr[7], (UINTN) IPv6DevPath->RemoteIpAddress.Addr[8], (UINTN) IPv6DevPath->RemoteIpAddress.Addr[9], (UINTN) IPv6DevPath->RemoteIpAddress.Addr[10], (UINTN) IPv6DevPath->RemoteIpAddress.Addr[11], (UINTN) IPv6DevPath->RemoteIpAddress.Addr[12], (UINTN) IPv6DevPath->RemoteIpAddress.Addr[13], (UINTN) IPv6DevPath->RemoteIpAddress.Addr[14], (UINTN) IPv6DevPath->RemoteIpAddress.Addr[15] ); } /** Convert Device Path to a Unicode string for printing. @param Str The buffer holding the output string. This buffer contains the length of the string and the maixmum length reserved for the string buffer. @param DevPath The device path. **/ VOID DevPathInfiniBand ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { INFINIBAND_DEVICE_PATH *InfiniBand; InfiniBand = DevPath; MyCatPrint ( Str, L"Infiniband(%x,%g,%lx,%lx,%lx)", (UINTN) InfiniBand->ResourceFlags, InfiniBand->PortGid, InfiniBand->ServiceId, InfiniBand->TargetPortId, InfiniBand->DeviceId ); } /** Convert Device Path to a Unicode string for printing. @param Str The buffer holding the output string. This buffer contains the length of the string and the maixmum length reserved for the string buffer. @param DevPath The device path. **/ VOID DevPathUart ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { UART_DEVICE_PATH *Uart; CHAR8 Parity; Uart = DevPath; switch (Uart->Parity) { case 0: Parity = 'D'; break; case 1: Parity = 'N'; break; case 2: Parity = 'E'; break; case 3: Parity = 'O'; break; case 4: Parity = 'M'; break; case 5: Parity = 'S'; break; default: Parity = 'x'; break; } if (Uart->BaudRate == 0) { MyCatPrint (Str, L"Uart(DEFAULT,%c,", Parity); } else { MyCatPrint (Str, L"Uart(%ld,%c,", Uart->BaudRate, Parity); } if (Uart->DataBits == 0) { MyCatPrint (Str, L"D,"); } else { MyCatPrint (Str, L"%d,", (UINTN) Uart->DataBits); } switch (Uart->StopBits) { case 0: MyCatPrint (Str, L"D)"); break; case 1: MyCatPrint (Str, L"1)"); break; case 2: MyCatPrint (Str, L"1.5)"); break; case 3: MyCatPrint (Str, L"2)"); break; default: MyCatPrint (Str, L"x)"); break; } } /** Convert Device Path to a Unicode string for printing. @param Str The buffer holding the output string. This buffer contains the length of the string and the maixmum length reserved for the string buffer. @param DevPath The device path. **/ VOID DevPathiSCSI ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { ISCSI_DEVICE_PATH_WITH_NAME *IScsi; UINT16 Options; IScsi = DevPath; MyCatPrint ( Str, L"iSCSI(%a,%x,%lx,", IScsi->TargetName, (UINTN) IScsi->TargetPortalGroupTag, IScsi->Lun ); Options = IScsi->LoginOption; MyCatPrint (Str, L"%s,", (((Options >> 1) & 0x0001) != 0) ? L"CRC32C" : L"None"); MyCatPrint (Str, L"%s,", (((Options >> 3) & 0x0001) != 0) ? L"CRC32C" : L"None"); if (((Options >> 11) & 0x0001) != 0) { MyCatPrint (Str, L"%s,", L"None"); } else if (((Options >> 12) & 0x0001) != 0) { MyCatPrint (Str, L"%s,", L"CHAP_UNI"); } else { MyCatPrint (Str, L"%s,", L"CHAP_BI"); } MyCatPrint (Str, L"%s)", (IScsi->NetworkProtocol == 0) ? L"TCP" : L"reserved"); } /** Convert Device Path to a Unicode string for printing. @param Str The buffer holding the output string. This buffer contains the length of the string and the maixmum length reserved for the string buffer. @param DevPath The device path. **/ VOID DevPathVlan ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { VLAN_DEVICE_PATH *Vlan; Vlan = DevPath; MyCatPrint (Str, L"Vlan(%d)", (UINTN) Vlan->VlanId); } /** Convert Device Path to a Unicode string for printing. @param Str The buffer holding the output string. This buffer contains the length of the string and the maixmum length reserved for the string buffer. @param DevPath The device path. **/ VOID DevPathHardDrive ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { HARDDRIVE_DEVICE_PATH *Hd; Hd = DevPath; switch (Hd->SignatureType) { case SIGNATURE_TYPE_MBR: MyCatPrint ( Str, L"HD(Part%d,Sig%08x)", (UINTN) Hd->PartitionNumber, (UINTN) *((UINT32 *) (&(Hd->Signature[0]))) ); break; case SIGNATURE_TYPE_GUID: MyCatPrint ( Str, L"HD(Part%d,Sig%g)", (UINTN) Hd->PartitionNumber, (EFI_GUID *) &(Hd->Signature[0]) ); break; default: MyCatPrint ( Str, L"HD(Part%d,MBRType=%02x,SigType=%02x)", (UINTN) Hd->PartitionNumber, (UINTN) Hd->MBRType, (UINTN) Hd->SignatureType ); break; } } /** Convert Device Path to a Unicode string for printing. @param Str The buffer holding the output string. This buffer contains the length of the string and the maixmum length reserved for the string buffer. @param DevPath The device path. **/ VOID DevPathCDROM ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { CDROM_DEVICE_PATH *Cd; Cd = DevPath; MyCatPrint (Str, L"CDROM(Entry%x)", (UINTN) Cd->BootEntry); } /** Convert Device Path to a Unicode string for printing. @param Str The buffer holding the output string. This buffer contains the length of the string and the maixmum length reserved for the string buffer. @param DevPath The device path. **/ VOID DevPathFilePath ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { FILEPATH_DEVICE_PATH *Fp; Fp = DevPath; MyCatPrint (Str, L"%s", Fp->PathName); } /** Convert Device Path to a Unicode string for printing. @param Str The buffer holding the output string. This buffer contains the length of the string and the maixmum length reserved for the string buffer. @param DevPath The device path. **/ VOID DevPathMediaProtocol ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { MEDIA_PROTOCOL_DEVICE_PATH *MediaProt; MediaProt = DevPath; MyCatPrint (Str, L"Media(%g)", &MediaProt->Protocol); } /** Convert Device Path to a Unicode string for printing. @param Str The buffer holding the output string. This buffer contains the length of the string and the maixmum length reserved for the string buffer. @param DevPath The device path. **/ VOID DevPathFvFilePath ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvFilePath; FvFilePath = DevPath; MyCatPrint (Str, L"%g", &FvFilePath->FvFileName); } /** Convert Device Path to a Unicode string for printing. @param Str The buffer holding the output string. This buffer contains the length of the string and the maixmum length reserved for the string buffer. @param DevPath The device path. **/ VOID MyDevPathRelativeOffsetRange ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH *Offset; Offset = DevPath; MyCatPrint ( Str, L"Offset(%lx,%lx)", Offset->StartingOffset, Offset->EndingOffset ); } /** Convert Device Path to a Unicode string for printing. @param Str The buffer holding the output string. This buffer contains the length of the string and the maixmum length reserved for the string buffer. @param DevPath The device path. **/ VOID DevPathBssBss ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { BBS_BBS_DEVICE_PATH *Bbs; CHAR16 *Type; Bbs = DevPath; switch (Bbs->DeviceType) { case BBS_TYPE_FLOPPY: Type = L"Floppy"; break; case BBS_TYPE_HARDDRIVE: Type = L"Harddrive"; break; case BBS_TYPE_CDROM: Type = L"CDROM"; break; case BBS_TYPE_PCMCIA: Type = L"PCMCIA"; break; case BBS_TYPE_USB: Type = L"Usb"; break; case BBS_TYPE_EMBEDDED_NETWORK: Type = L"Net"; break; case BBS_TYPE_BEV: Type = L"BEV"; break; default: Type = L"?"; break; } MyCatPrint (Str, L"Legacy-%s", Type); } /** Convert Device Path to a Unicode string for printing. @param Str The buffer holding the output string. This buffer contains the length of the string and the maixmum length reserved for the string buffer. @param DevPath The device path. **/ VOID DevPathEndInstance ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { MyCatPrint (Str, L","); } /** Convert Device Path to a Unicode string for printing. @param Str The buffer holding the output string. This buffer contains the length of the string and the maixmum length reserved for the string buffer. @param DevPath The device path. **/ VOID DevPathNodeUnknown ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { MyCatPrint (Str, L"?"); } /** Convert Device Path to a Unicode string for printing. @param Str The buffer holding the output string. This buffer contains the length of the string and the maximum length reserved for the string buffer. @param DevPath The device path. **/ VOID DevPathFvPath ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { MEDIA_FW_VOL_DEVICE_PATH *FvPath; FvPath = DevPath; MyCatPrint (Str, L"Fv(%g)", &FvPath->FvName); } DEVICE_PATH_STRING_TABLE DevPathTable[] = { { HARDWARE_DEVICE_PATH, HW_PCI_DP, DevPathPci }, { HARDWARE_DEVICE_PATH, HW_PCCARD_DP, DevPathPccard }, { HARDWARE_DEVICE_PATH, HW_MEMMAP_DP, DevPathMemMap }, { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, DevPathVendor }, { HARDWARE_DEVICE_PATH, HW_CONTROLLER_DP, DevPathController }, { ACPI_DEVICE_PATH, ACPI_DP, DevPathAcpi }, { ACPI_DEVICE_PATH, ACPI_EXTENDED_DP, DevPathExtendedAcpi }, { ACPI_DEVICE_PATH, ACPI_ADR_DP, DevPathAdrAcpi }, { MESSAGING_DEVICE_PATH, MSG_ATAPI_DP, DevPathAtapi }, { MESSAGING_DEVICE_PATH, MSG_SCSI_DP, DevPathScsi }, { MESSAGING_DEVICE_PATH, MSG_FIBRECHANNEL_DP, DevPathFibre }, { MESSAGING_DEVICE_PATH, MSG_1394_DP, DevPath1394 }, { MESSAGING_DEVICE_PATH, MSG_USB_DP, DevPathUsb }, { MESSAGING_DEVICE_PATH, MSG_USB_WWID_DP, DevPathUsbWWID }, { MESSAGING_DEVICE_PATH, MSG_DEVICE_LOGICAL_UNIT_DP, DevPathLogicalUnit }, { MESSAGING_DEVICE_PATH, MSG_USB_CLASS_DP, DevPathUsbClass }, { MESSAGING_DEVICE_PATH, MSG_SATA_DP, DevPathSata }, { MESSAGING_DEVICE_PATH, MSG_I2O_DP, DevPathI2O }, { MESSAGING_DEVICE_PATH, MSG_MAC_ADDR_DP, DevPathMacAddr }, { MESSAGING_DEVICE_PATH, MSG_IPv4_DP, DevPathIPv4 }, { MESSAGING_DEVICE_PATH, MSG_IPv6_DP, DevPathIPv6 }, { MESSAGING_DEVICE_PATH, MSG_INFINIBAND_DP, DevPathInfiniBand }, { MESSAGING_DEVICE_PATH, MSG_UART_DP, DevPathUart }, { MESSAGING_DEVICE_PATH, MSG_VENDOR_DP, DevPathVendor }, { MESSAGING_DEVICE_PATH, MSG_ISCSI_DP, DevPathiSCSI }, { MESSAGING_DEVICE_PATH, MSG_VLAN_DP, DevPathVlan }, { MEDIA_DEVICE_PATH, MEDIA_HARDDRIVE_DP, DevPathHardDrive }, { MEDIA_DEVICE_PATH, MEDIA_CDROM_DP, DevPathCDROM }, { MEDIA_DEVICE_PATH, MEDIA_VENDOR_DP, DevPathVendor }, { MEDIA_DEVICE_PATH, MEDIA_FILEPATH_DP, DevPathFilePath }, { MEDIA_DEVICE_PATH, MEDIA_PROTOCOL_DP, DevPathMediaProtocol }, { MEDIA_DEVICE_PATH, MEDIA_PIWG_FW_VOL_DP, DevPathFvPath, }, { MEDIA_DEVICE_PATH, MEDIA_PIWG_FW_FILE_DP, DevPathFvFilePath }, { MEDIA_DEVICE_PATH, MEDIA_RELATIVE_OFFSET_RANGE_DP, MyDevPathRelativeOffsetRange, }, { BBS_DEVICE_PATH, BBS_BBS_DP, DevPathBssBss }, { END_DEVICE_PATH_TYPE, END_INSTANCE_DEVICE_PATH_SUBTYPE, DevPathEndInstance }, { 0, 0, NULL } }; /** This function converts an input device structure to a Unicode string. @param DevPath A pointer to the device path structure. @return A new allocated Unicode string that represents the device path. **/ CHAR16 * EFIAPI DevicePathToStr ( IN EFI_DEVICE_PATH_PROTOCOL *DevPath ) { POOL_PRINT Str; EFI_DEVICE_PATH_PROTOCOL *DevPathNode; VOID (*DumpNode) (POOL_PRINT *, VOID *); UINTN Index; UINTN NewSize; EFI_STATUS Status; CHAR16 *ToText; EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *DevPathToText; ZeroMem (&Str, sizeof (Str)); if (DevPath == NULL) { goto Done; } Status = gBS->LocateProtocol ( &gEfiDevicePathToTextProtocolGuid, NULL, (VOID **) &DevPathToText ); if (!EFI_ERROR (Status)) { ToText = DevPathToText->ConvertDevicePathToText ( DevPath, FALSE, TRUE ); ASSERT (ToText != NULL); return ToText; } // // Process each device path node // DevPathNode = DevPath; while (!IsDevicePathEnd (DevPathNode)) { // // Find the handler to dump this device path node // DumpNode = NULL; for (Index = 0; DevPathTable[Index].Function != NULL; Index += 1) { if (DevicePathType (DevPathNode) == DevPathTable[Index].Type && DevicePathSubType (DevPathNode) == DevPathTable[Index].SubType ) { DumpNode = DevPathTable[Index].Function; break; } } // // If not found, use a generic function // if (!DumpNode) { DumpNode = DevPathNodeUnknown; } // // Put a path seperator in if needed // if ((Str.Len != 0) && (DumpNode != DevPathEndInstance)) { MyCatPrint (&Str, L"/"); } // // Print this node of the device path // DumpNode (&Str, DevPathNode); // // Next device path node // DevPathNode = NextDevicePathNode (DevPathNode); } Done: NewSize = (Str.Len + 1) * sizeof (CHAR16); Str.Str = EfiReallocatePool (Str.Str, NewSize, NewSize); ASSERT (Str.Str != NULL); Str.Str[Str.Len] = 0; return Str.Str; } �������������������������������������������������������������������������refind-0.11.4/EfiLib/BdsTianoCore.c�����������������������������������������������������������������0000664�0001750�0001750�00000025066�13141626753�017145� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/** @file BDS Lib functions which relate with create or process the boot option. Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR> This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ #ifdef __MAKEWITH_TIANO #include "../include/tiano_includes.h" #else #include "BdsHelper.h" #include "gnuefi-helper.h" #endif #include "../include/refit_call_wrapper.h" EFI_GUID EfiDevicePathProtocolGuid = { 0x09576E91, 0x6D3F, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; /** This function will create all handles associate with every device path node. If the handle associate with one device path node can not be created success, then still give one chance to do the dispatch, which load the missing drivers if possible. @param DevicePathToConnect The device path which will be connected, it can be a multi-instance device path @retval EFI_SUCCESS All handles associate with every device path node have been created @retval EFI_OUT_OF_RESOURCES There is no resource to create new handles @retval EFI_NOT_FOUND Create the handle associate with one device path node failed **/ EFI_STATUS BdsLibConnectDevicePath ( IN EFI_DEVICE_PATH_PROTOCOL *DevicePathToConnect ) { EFI_STATUS Status; EFI_DEVICE_PATH_PROTOCOL *DevicePath; EFI_DEVICE_PATH_PROTOCOL *CopyOfDevicePath; EFI_DEVICE_PATH_PROTOCOL *Instance; EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath; EFI_DEVICE_PATH_PROTOCOL *Next; EFI_HANDLE Handle; EFI_HANDLE PreviousHandle; UINTN Size; if (DevicePathToConnect == NULL) { return EFI_SUCCESS; } DevicePath = DuplicateDevicePath (DevicePathToConnect); if (DevicePath == NULL) { return EFI_OUT_OF_RESOURCES; } CopyOfDevicePath = DevicePath; do { // // The outer loop handles multi instance device paths. // Only console variables contain multiple instance device paths. // // After this call DevicePath points to the next Instance // Instance = GetNextDevicePathInstance (&DevicePath, &Size); if (Instance == NULL) { FreePool (CopyOfDevicePath); return EFI_OUT_OF_RESOURCES; } Next = Instance; while (!IsDevicePathEndType (Next)) { Next = NextDevicePathNode (Next); } SetDevicePathEndNode (Next); // // Start the real work of connect with RemainingDevicePath // PreviousHandle = NULL; do { // // Find the handle that best matches the Device Path. If it is only a // partial match the remaining part of the device path is returned in // RemainingDevicePath. // RemainingDevicePath = Instance; Status = refit_call3_wrapper(gBS->LocateDevicePath, &EfiDevicePathProtocolGuid, &RemainingDevicePath, &Handle); if (!EFI_ERROR (Status)) { #ifdef __MAKEWITH_TIANO if (Handle == PreviousHandle) { // // If no forward progress is made try invoking the Dispatcher. // A new FV may have been added to the system an new drivers // may now be found. // Status == EFI_SUCCESS means a driver was dispatched // Status == EFI_NOT_FOUND means no new drivers were dispatched // Status = gDS->Dispatch (); } #endif if (!EFI_ERROR (Status)) { PreviousHandle = Handle; // // Connect all drivers that apply to Handle and RemainingDevicePath, // the Recursive flag is FALSE so only one level will be expanded. // // Do not check the connect status here, if the connect controller fail, // then still give the chance to do dispatch, because partial // RemainingDevicepath may be in the new FV // // 1. If the connect fail, RemainingDevicepath and handle will not // change, so next time will do the dispatch, then dispatch's status // will take effect // 2. If the connect success, the RemainingDevicepath and handle will // change, then avoid the dispatch, we have chance to continue the // next connection // refit_call4_wrapper(gBS->ConnectController, Handle, NULL, RemainingDevicePath, FALSE); } } // // Loop until RemainingDevicePath is an empty device path // } while (!EFI_ERROR (Status) && !IsDevicePathEnd (RemainingDevicePath)); } while (DevicePath != NULL); if (CopyOfDevicePath != NULL) { FreePool (CopyOfDevicePath); } // // All handle with DevicePath exists in the handle database // return Status; } /** Build the boot#### or driver#### option from the VariableName, the build boot#### or driver#### will also be linked to BdsCommonOptionList. @param BdsCommonOptionList The header of the boot#### or driver#### option link list @param VariableName EFI Variable name indicate if it is boot#### or driver#### @retval BDS_COMMON_OPTION Get the option just been created @retval NULL Failed to get the new option **/ BDS_COMMON_OPTION * BdsLibVariableToOption ( IN OUT LIST_ENTRY *BdsCommonOptionList, IN CHAR16 *VariableName ) { UINT32 Attribute; UINT16 FilePathSize; UINT8 *Variable; UINT8 *TempPtr; UINTN VariableSize; EFI_DEVICE_PATH_PROTOCOL *DevicePath; BDS_COMMON_OPTION *Option; VOID *LoadOptions; UINT32 LoadOptionsSize; CHAR16 *Description; UINT8 NumOff; EFI_GUID EfiGlobalVariableGuid = { 0x8BE4DF61, 0x93CA, 0x11D2, { 0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C }}; // // Read the variable. We will never free this data. // Variable = BdsLibGetVariableAndSize ( VariableName, &EfiGlobalVariableGuid, &VariableSize ); if (Variable == NULL) { return NULL; } // // Notes: careful defined the variable of Boot#### or // Driver####, consider use some macro to abstract the code // // // Get the option attribute // TempPtr = Variable; Attribute = *(UINT32 *) Variable; TempPtr += sizeof (UINT32); // // Get the option's device path size // FilePathSize = *(UINT16 *) TempPtr; TempPtr += sizeof (UINT16); // // Get the option's description string // Description = (CHAR16 *) TempPtr; // // Get the option's description string size // TempPtr += StrSize ((CHAR16 *) TempPtr); // // Get the option's device path // DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr; TempPtr += FilePathSize; LoadOptions = TempPtr; LoadOptionsSize = (UINT32) (VariableSize - (UINTN) (TempPtr - Variable)); // // The Console variables may have multiple device paths, so make // an Entry for each one. // Option = AllocateZeroPool (sizeof (BDS_COMMON_OPTION)); if (Option == NULL) { return NULL; } Option->Signature = BDS_LOAD_OPTION_SIGNATURE; Option->DevicePath = AllocateZeroPool (GetDevicePathSize (DevicePath)); ASSERT(Option->DevicePath != NULL); CopyMem (Option->DevicePath, DevicePath, GetDevicePathSize (DevicePath)); Option->Attribute = Attribute; Option->Description = AllocateZeroPool (StrSize (Description)); ASSERT(Option->Description != NULL); CopyMem (Option->Description, Description, StrSize (Description)); Option->LoadOptions = AllocateZeroPool (LoadOptionsSize); ASSERT(Option->LoadOptions != NULL); CopyMem (Option->LoadOptions, LoadOptions, LoadOptionsSize); Option->LoadOptionsSize = LoadOptionsSize; // // Get the value from VariableName Unicode string // since the ISO standard assumes ASCII equivalent abbreviations, we can be safe in converting this // Unicode stream to ASCII without any loss in meaning. // if (*VariableName == 'B') { NumOff = (UINT8) (sizeof (L"Boot") / sizeof(CHAR16) - 1); Option->BootCurrent = (UINT16) ((VariableName[NumOff] -'0') * 0x1000); Option->BootCurrent = (UINT16) (Option->BootCurrent + ((VariableName[NumOff+1]-'0') * 0x100)); Option->BootCurrent = (UINT16) (Option->BootCurrent + ((VariableName[NumOff+2]-'0') * 0x10)); Option->BootCurrent = (UINT16) (Option->BootCurrent + ((VariableName[NumOff+3]-'0'))); } // // Insert active entry to BdsDeviceList // if ((Option->Attribute & LOAD_OPTION_ACTIVE) == LOAD_OPTION_ACTIVE) { InsertTailList (BdsCommonOptionList, &Option->Link); FreePool (Variable); return Option; } FreePool (Variable); FreePool (Option); return NULL; } /** Read the EFI variable (VendorGuid/Name) and return a dynamically allocated buffer, and the size of the buffer. If failure return NULL. @param Name String part of EFI variable name @param VendorGuid GUID part of EFI variable name @param VariableSize Returns the size of the EFI variable that was read @return Dynamically allocated memory that contains a copy of the EFI variable Caller is responsible freeing the buffer. @retval NULL Variable was not read **/ VOID * BdsLibGetVariableAndSize ( IN CHAR16 *Name, IN EFI_GUID *VendorGuid, OUT UINTN *VariableSize ) { EFI_STATUS Status; UINTN BufferSize; VOID *Buffer; Buffer = NULL; // // Pass in a zero size buffer to find the required buffer size. // BufferSize = 0; Status = refit_call5_wrapper(gRT->GetVariable, Name, VendorGuid, NULL, &BufferSize, Buffer); if (Status == EFI_BUFFER_TOO_SMALL) { // // Allocate the buffer to return // Buffer = AllocateZeroPool (BufferSize); if (Buffer == NULL) { return NULL; } // // Read variable into the allocated buffer. // Status = refit_call5_wrapper(gRT->GetVariable, Name, VendorGuid, NULL, &BufferSize, Buffer); if (EFI_ERROR (Status)) { BufferSize = 0; } } *VariableSize = BufferSize; return Buffer; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/EfiLib/Platform.h���������������������������������������������������������������������0000664�0001750�0001750�00000004672�13111633155�016411� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Headers collection for procedures */ /** Copyright (c) 2004 - 2008, Intel Corporation. All rights reserved.<BR> This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ #ifndef __REFIT_PLATFORM_H__ #define __REFIT_PLATFORM_H__ #include <Uefi.h> #include <Guid/Acpi.h> #include <Guid/EventGroup.h> #include <Guid/SmBios.h> #include <Guid/Mps.h> #include <Library/BaseLib.h> #include <Library/BaseMemoryLib.h> #include <Library/DebugLib.h> #include <Library/HiiLib.h> #include <Library/MemoryAllocationLib.h> #include <Library/PcdLib.h> #include <Library/PerformanceLib.h> #include <Library/PeCoffGetEntryPointLib.h> #include <Library/TimerLib.h> #include <Library/UefiBootServicesTableLib.h> #include <Library/UefiDriverEntryPoint.h> #include <Library/UefiLib.h> #include <Library/UefiRuntimeServicesTableLib.h> #include <Library/UefiRuntimeLib.h> #include <Framework/FrameworkInternalFormRepresentation.h> #include <IndustryStandard/Acpi10.h> #include <IndustryStandard/Acpi20.h> #include <Protocol/Cpu.h> #include <Protocol/CpuIo.h> #include <Protocol/DataHub.h> #include <Protocol/DevicePathToText.h> #include <Protocol/FrameworkHii.h> #include <Protocol/Smbios.h> #include <Protocol/VariableWrite.h> #include <Protocol/Variable.h> #include "../include/Bmp.h" #include "../libeg/efiConsoleControl.h" #include "../EfiLib/GenericBdsLib.h" #include "../refind/global.h" #define EFI_HANDLE_TYPE_UNKNOWN 0x000 #define EFI_HANDLE_TYPE_IMAGE_HANDLE 0x001 #define EFI_HANDLE_TYPE_DRIVER_BINDING_HANDLE 0x002 #define EFI_HANDLE_TYPE_DEVICE_DRIVER 0x004 #define EFI_HANDLE_TYPE_BUS_DRIVER 0x008 #define EFI_HANDLE_TYPE_DRIVER_CONFIGURATION_HANDLE 0x010 #define EFI_HANDLE_TYPE_DRIVER_DIAGNOSTICS_HANDLE 0x020 #define EFI_HANDLE_TYPE_COMPONENT_NAME_HANDLE 0x040 #define EFI_HANDLE_TYPE_DEVICE_HANDLE 0x080 #define EFI_HANDLE_TYPE_PARENT_HANDLE 0x100 #define EFI_HANDLE_TYPE_CONTROLLER_HANDLE 0x200 #define EFI_HANDLE_TYPE_CHILD_HANDLE 0x400 EFI_STATUS EFIAPI InitializeConsoleSim (VOID); #endif ����������������������������������������������������������������������refind-0.11.4/EfiLib/Make.tiano���������������������������������������������������������������������0000664�0001750�0001750�00000001133�12631122022�016342� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # EfiLib/Make.tiano # Build control file for EfiLib components of rEFInd, using TianoCore EDK2 # # This program is licensed under the terms of the GNU GPL, version 3, # or (at your option) any later version. # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. include ../Make.common SOURCE_NAMES = legacy BmLib BdsConnect DevicePath BdsHelper BdsTianoCore OBJS = $(SOURCE_NAMES:=.obj) all: $(AR_TARGET) $(AR_TARGET): $(OBJS) $(AR) -cr $(AR_TARGET).lib $(OBJS) clean: rm -f $(OBJS) *~ *.lib �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/mvrefind������������������������������������������������������������������������������0000775�0001750�0001750�00000024172�13363622744�015072� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env bash # # Linux script to move an existing rEFInd installation from one directory to # another # # copyright (c) 2013-2015 by Roderick W. Smith # # This program is licensed under the terms of the GNU GPL, version 3, # or (at your option) any later version. # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. # Usage: # # ./mvrefind /path/to/source /path/to/destination # # Typically used to "hijack" or "unhijack" a Windows boot loader location or # to help convert a rEFInd installation made in BIOS mode to one that works # in EFI mode. # # Revision history: # # 0.11.0 -- Added creation of BOOT.CSV file to tasks # 0.10.2 -- Fixed bug in moving bootmgfw.efi in some situations # 0.10.1 -- Generalized to support ARM64 (aka AARCH64, aa64) # 0.10.0 -- Renamed from mvrefind.sh to mvrefind # 0.6.3 -- Initial release # # Note: mvrefind version numbers match those of the rEFInd package # with which they first appeared. RootDir="/" SourceShim="shim.efi" TargetShim=$SourceShim SourceDir=`readlink -m ${1}` TargetDir=`readlink -m ${2}` # Identifies the ESP's location (/boot or /boot/efi); aborts if the ESP isn't # mounted at either location. Also splits the ESP location from SourceDir and # TargetDir, leaving them intact but creating new EspSourceDir and EspTargetDir # variables containing only the ESP components thereof. These new variables # are also converted to all-lowercase and any trailing slash is stripped, to # assist in comparisons. (This is reasonable because FAT is case-insensitive.) # Sets InstallDir to the ESP mount point. FindLinuxESP() { EspLine=`df $RootDir/boot/efi 2> /dev/null | grep boot/efi` if [[ ! -n $EspLine ]] ; then EspLine=`df $RootDir/boot | grep boot` fi InstallDir=`echo $EspLine | cut -d " " -f 6` if [[ -n $InstallDir ]] ; then EspFilesystem=`grep $InstallDir /etc/mtab | grep -v autofs | cut -d " " -f 3` fi if [[ $EspFilesystem != 'vfat' ]] ; then echo "$RootDir/boot/efi doesn't seem to be on a VFAT filesystem. The ESP must be" echo "mounted at $RootDir/boot or $RootDir/boot/efi and it must be VFAT! Aborting!" exit 1 fi # Sanity check on source & target.... EspPathLength=`expr length $InstallDir` Temp=`echo $SourceDir | cut -c 1-$EspPathLength` if [[ $Temp != $InstallDir ]] ; then echo "$SourceDir isn't on the ESP ($InstallDir)! Aborting!" exit 1 fi Temp=`echo $TargetDir | cut -c 1-$EspPathLength` if [[ $Temp != $InstallDir ]] ; then echo "$TargetDir isn't on the ESP ($InstallDir)! Aborting!" exit 1 fi # Temporarily replace "/" in pathnames with ",", so as to enable sed to # work on them TempInstallDir=`echo $InstallDir | tr '/' ','` Temp=`echo $SourceDir | tr '/' ',' | sed s/${TempInstallDir}//g | tr ',' '/' | tr '[A-Z]' '[a-z]'` EspSourceDir=`dirname $Temp`/`basename $Temp` Temp=`echo $TargetDir | tr '/' ',' | sed s/${TempInstallDir}//g | tr ',' '/' | tr '[A-Z]' '[a-z]'` EspTargetDir=`dirname $Temp`/`basename $Temp` if [[ $EspSourceDir == $EspTargetDir ]] ; then echo "$SourceDir is the same as $TargetDir! Aborting!" exit 1 fi } # FindLinuxESP DeterminePlatform() { CpuType=`uname -m` case "$CpuType" in aarch64) Platform="aa64" ;; x86_64) Platform="x64" ;; i?86) Platform="ia32" ;; *) echo "Unsupported CPU type; aborting!" exit 1 esac Source="refind_$Platform.efi" Target=$Source } # Adjust filename variables appropriately for their locations and detected # presence (or lack thereof) of shim installation AdjustFilenames() { if [[ -f $SourceDir/grub$Platform.efi ]] ; then Source="grub$Platform.efi" Target=$Source if [[ $EspSourceDir == "/efi/boot" ]] ; then SourceShim="boot$Platform.efi" elif [[ $EspSourceDir == "/efi/microsoft/boot" ]] ; then SourceShim="bootmgfw.efi" fi else SourceShim="none" TargetShim="none" if [[ $EspSourceDir == "/efi/boot" ]] ; then Source="boot$Platform.efi" elif [[ $EspSourceDir == "/efi/microsoft/boot" ]] ; then Source="bootmgfw.efi" fi fi if [[ $EspTargetDir == "/efi/boot" ]] ; then if [[ $TargetShim == "none" ]] ; then Target="boot$Platform.efi" else TargetShim="boot$Platform.efi" fi elif [[ $EspTargetDir == "/efi/microsoft/boot" ]] ; then if [[ $TargetShim == "none" ]] ; then Target="bootmgfw.efi" else TargetShim="bootmgfw.efi" fi fi } # AdjustFilenames() # Checks for the presence of necessary files, including both boot loaders # and support utilities (efibootmgr, etc.) CheckForFiles() { if [[ (! -f $SourceDir/$Source) || ($SourceShim != "none" && ! -f $SourceDir/SourceShim) || ! -f $SourceDir/refind.conf ]] ; then echo "There doesn't seem to be a rEFInd installation at $SourceDir!" echo "Aborting!" exit 1 fi if [[ $EspTargetDir != "/efi/boot" && $EspTargetDir != "/efi/microsoft/boot" ]] ; then Efibootmgr=`which efibootmgr 2> /dev/null` if [[ ! -f $Efibootmgr ]] ; then echo "Moving to a non-default directory requires a working efibootmgr utility, but" echo "one can't be found! Aborting!" exit 1 elif [[ ! -d "/sys/firmware/efi" ]] ; then echo "Moving to a non-default directory requires a boot into EFI mode, but we seem" echo "to be running in BIOS mode. (Perhaps typing 'modprobe efivars' will fix this." echo "Aborting!" fi fi } # CheckForFiles() # Do final checks & then move the files! MoveFiles() { ExistingFiles=`find $TargetDir -name "*.efi" 2> /dev/null` if [[ -n $ExistingFiles && $EspTargetDir != "/efi/boot" && $EspTargetDir != "/efi/microsoft/boot" ]] ; then echo "$TargetDir isn't empty! Aborting!" exit 1 fi if [[ $EspTargetDir == "/efi/boot" && -d $TargetDir ]] ; then if [[ -d $InstallDir/EFI/BOOT-rEFIndBackup ]] ; then echo "" echo "Caution: An existing backup of a default boot loader exists! If the current" echo "default boot loader and the backup are different boot loaders, the current" echo "one will become inaccessible." echo "" echo -n "Do you want to proceed with moving (Y/N)? " read YesNo if [[ $YesNo == "Y" || $YesNo == "y" ]] ; then echo "OK; continuing with the move..." else exit 0 fi else mv $TargetDir $InstallDir/EFI/BOOT-refindBackup &> /dev/null fi fi if [[ $EspTargetDir == "/efi/microsoft/boot" && -d $TargetDir ]] ; then mv -n $TargetDir/bootmgfw.efi $InstallDir/EFI/Microsoft/ fi mkdir -p $TargetDir mv $SourceDir/icons $TargetDir/ 2> /dev/null mv $SourceDir/icons-backup $TargetDir/ 2> /dev/null mv $SourceDir/drivers_* $TargetDir/ 2> /dev/null mv $SourceDir/keys $TargetDir 2> /dev/null mv $SourceDir/$Source $TargetDir/$Target 2> /dev/null mv $SourceDir/$SourceShim $TargetDir/$TargetShim 2> /dev/null mv $SourceDir/refind.conf* $TargetDir/ 2> /dev/null rm $SourceDir/BOOT.CSV rmdir $SourceDir 2> /dev/null } # MoveFiles() # Clean up after moving files -- mainly restoring old backed-up files, if present PostMoveCleanup() { if [[ "$EspSourceDir" == "/efi/boot" && -d "$InstallDir/EFI/BOOT-rEFIndBackup" && ! -d $SourceDir ]] ; then mv "$InstallDir/EFI/BOOT-rEFIndBackup" "$SourceDir" 2> /dev/null fi if [[ "$EspSourceDir" == "/efi/microsoft/boot" && -f "$InstallDir/EFI/Microsoft/bootmgfw.efi" ]] ; then mv -n "$InstallDir/EFI/Microsoft/bootmgfw.efi" "$SourceDir/bootmgfw.efi" fi } # PostMoveCleanup() # Create a BOOT.CSV file in the same directory as rEFInd, to help in recovery # should the system's boot entry list be lost CreateBootCsvFile() { IConv=`which iconv 2> /dev/null` if [[ -x "$IConv" && -d "$TargetDir" ]] ; then echo "$Target,rEFInd boot manager,,This is the boot entry for rEFInd" | \ $IConv -t UCS-2 > "$TargetDir/BOOT.CSV" fi exit } # CreateBootCsvFile() # If necessary, create a new NVRAM entry for the new location AddNvramEntry() { InstallIt="0" Efibootmgr=`which efibootmgr 2> /dev/null` InstallDisk=`grep $InstallDir /etc/mtab | grep -v autofs | cut -d " " -f 1 | cut -c 1-8` PartNum=`grep $InstallDir /etc/mtab | grep -v autofs | cut -d " " -f 1 | cut -c 9-10` if [[ $TargetShim != "none" ]] ; then EntryFilename=$EspTargetDir/$TargetShim else EntryFilename=$EspTargetDir/$Target fi # if/else EfiEntryFilename=`echo ${EntryFilename//\//\\\}` EfiEntryFilename2=`echo ${EfiEntryFilename} | sed s/\\\\\\\\/\\\\\\\\\\\\\\\\/g` ExistingEntry=`$Efibootmgr -v | grep -i $EfiEntryFilename2` if [[ $ExistingEntry ]] ; then ExistingEntryBootNum=`echo $ExistingEntry | cut -c 5-8` FirstBoot=`$Efibootmgr | grep BootOrder | cut -c 12-15` if [[ $ExistingEntryBootNum != $FirstBoot ]] ; then $Efibootmgr -b $ExistingEntryBootNum -B &> /dev/null InstallIt="1" fi else InstallIt="1" fi if [[ $InstallIt == "1" ]] ; then if [[ $EspTargetDir == "/efi/microsoft/boot" ]] ; then # Name it the way some firmware expects -- see http://mjg59.dreamwidth.org/20187.html $Efibootmgr -c -l $EfiEntryFilename -L "Windows Boot Manager" -d $InstallDisk -p $PartNum &> /dev/null else $Efibootmgr -c -l $EfiEntryFilename -L "rEFInd Boot Manager" -d $InstallDisk -p $PartNum &> /dev/null fi if [[ $? != 0 ]] ; then EfibootmgrProblems=1 fi fi if [[ $EfibootmgrProblems ]] ; then echo echo "ALERT: There were problems running the efibootmgr program! Your moved rEFInd" echo "might not run!" echo fi } # AddNvramEntry # # Main body of script # if [[ $# != 2 ]] ; then echo "Usage: $0 {source-directory} {target-directory}" exit 1 fi if [[ `whoami` != "root" ]] ; then echo "Not running as root! Aborting!" exit 1 fi FindLinuxESP DeterminePlatform AdjustFilenames CheckForFiles MoveFiles PostMoveCleanup CreateBootCsvFile AddNvramEntry ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/libeg/��������������������������������������������������������������������������������0000755�0001750�0001750�00000000000�13372347460�014403� 5����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/libeg/nanojpeg.c����������������������������������������������������������������������0000644�0001750�0001750�00000100367�13324114436�016347� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������// NanoJPEG -- KeyJ's Tiny Baseline JPEG Decoder // version 1.3.5 (2016-11-14) // Copyright (c) 2009-2016 Martin J. Fiedler <martin.fiedler@gmx.net> // published under the terms of the MIT license // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to // deal in the Software without restriction, including without limitation the // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or // sell copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. /////////////////////////////////////////////////////////////////////////////// // DOCUMENTATION SECTION // // read this if you want to know what this is all about // /////////////////////////////////////////////////////////////////////////////// // INTRODUCTION // ============ // // This is a minimal decoder for baseline JPEG images. It accepts memory dumps // of JPEG files as input and generates either 8-bit grayscale or packed 24-bit // RGB images as output. It does not parse JFIF or Exif headers; all JPEG files // are assumed to be either grayscale or YCbCr. CMYK or other color spaces are // not supported. All YCbCr subsampling schemes with power-of-two ratios are // supported, as are restart intervals. Progressive or lossless JPEG is not // supported. // Summed up, NanoJPEG should be able to decode all images from digital cameras // and most common forms of other non-progressive JPEG images. // The decoder is not optimized for speed, it's optimized for simplicity and // small code. Image quality should be at a reasonable level. A bicubic chroma // upsampling filter ensures that subsampled YCbCr images are rendered in // decent quality. The decoder is not meant to deal with broken JPEG files in // a graceful manner; if anything is wrong with the bitstream, decoding will // simply fail. // The code should work with every modern C compiler without problems and // should not emit any warnings. It uses only (at least) 32-bit integer // arithmetic and is supposed to be endianness independent and 64-bit clean. // However, it is not thread-safe. // COMPILE-TIME CONFIGURATION // ========================== // // The following aspects of NanoJPEG can be controlled with preprocessor // defines: // // _NJ_EXAMPLE_PROGRAM = Compile a main() function with an example // program. // _NJ_INCLUDE_HEADER_ONLY = Don't compile anything, just act as a header // file for NanoJPEG. Example: // #define _NJ_INCLUDE_HEADER_ONLY // #include "nanojpeg.c" // int main(void) { // njInit(); // // your code here // njDone(); // } // NJ_USE_LIBC=1 = Use the malloc(), free(), memset() and memcpy() // functions from the standard C library (default). // NJ_USE_LIBC=0 = Don't use the standard C library. In this mode, // external functions njAlloc(), njFreeMem(), // njFillMem() and njCopyMem() need to be defined // and implemented somewhere. // NJ_USE_WIN32=0 = Normal mode (default). // NJ_USE_WIN32=1 = If compiling with MSVC for Win32 and // NJ_USE_LIBC=0, NanoJPEG will use its own // implementations of the required C library // functions (default if compiling with MSVC and // NJ_USE_LIBC=0). // NJ_CHROMA_FILTER=1 = Use the bicubic chroma upsampling filter // (default). // NJ_CHROMA_FILTER=0 = Use simple pixel repetition for chroma upsampling // (bad quality, but faster and less code). // API // === // // For API documentation, read the "header section" below. // EXAMPLE // ======= // // A few pages below, you can find an example program that uses NanoJPEG to // convert JPEG files into PGM or PPM. To compile it, use something like // gcc -O3 -D_NJ_EXAMPLE_PROGRAM -o nanojpeg nanojpeg.c // You may also add -std=c99 -Wall -Wextra -pedantic -Werror, if you want :) // The only thing you might need is -Wno-shift-negative-value, because this // code relies on the target machine using two's complement arithmetic, but // the C standard does not, even though *any* practically useful machine // nowadays uses two's complement. /////////////////////////////////////////////////////////////////////////////// // HEADER SECTION // // copy and pase this into nanojpeg.h if you want // /////////////////////////////////////////////////////////////////////////////// #ifndef _NANOJPEG_H #define _NANOJPEG_H // Modified: Map libc-style free() and malloc() to their EFI equivalents.... #define free FreePool #define malloc AllocatePool #define memset MyMemSet #define memcpy MyMemCpy // nj_result_t: Result codes for njDecode(). typedef enum _nj_result { NJ_OK = 0, // no error, decoding successful NJ_NO_JPEG, // not a JPEG file NJ_UNSUPPORTED, // unsupported format NJ_OUT_OF_MEM, // out of memory NJ_INTERNAL_ERR, // internal error NJ_SYNTAX_ERROR, // syntax error __NJ_FINISHED, // used internally, will never be reported } nj_result_t; // njInit: Initialize NanoJPEG. // For safety reasons, this should be called at least one time before using // using any of the other NanoJPEG functions. // Returns 1 on success, 0 on failure. int njInit(void); // njDecode: Decode a JPEG image. // Decodes a memory dump of a JPEG file into internal buffers. // Parameters: // jpeg = The pointer to the memory dump. // size = The size of the JPEG file. // Return value: The error code in case of failure, or NJ_OK (zero) on success. nj_result_t njDecode(const void* jpeg, const int size); // njGetWidth: Return the width (in pixels) of the most recently decoded // image. If njDecode() failed, the result of njGetWidth() is undefined. int njGetWidth(void); // njGetHeight: Return the height (in pixels) of the most recently decoded // image. If njDecode() failed, the result of njGetHeight() is undefined. int njGetHeight(void); // njIsColor: Return 1 if the most recently decoded image is a color image // (RGB) or 0 if it is a grayscale image. If njDecode() failed, the result // of njGetWidth() is undefined. int njIsColor(void); // njGetImage: Returns the decoded image data. // Returns a pointer to the most recently image. The memory layout it byte- // oriented, top-down, without any padding between lines. Pixels of color // images will be stored as three consecutive bytes for the red, green and // blue channels. This data format is thus compatible with the PGM or PPM // file formats and the OpenGL texture formats GL_LUMINANCE8 or GL_RGB8. // If njDecode() failed, the result of njGetImage() is undefined. unsigned char* njGetImage(void); // njGetImageSize: Returns the size (in bytes) of the image data returned // by njGetImage(). If njDecode() failed, the result of njGetImageSize() is // undefined. int njGetImageSize(void); // njDone: Uninitialize NanoJPEG. // Resets NanoJPEG's internal state and frees all memory that has been // allocated at run-time by NanoJPEG. It is still possible to decode another // image after a njDone() call. void njDone(void); #endif//_NANOJPEG_H /////////////////////////////////////////////////////////////////////////////// // CONFIGURATION SECTION // // adjust the default settings for the NJ_ defines here // /////////////////////////////////////////////////////////////////////////////// #ifndef NJ_USE_LIBC #define NJ_USE_LIBC 1 #endif #ifndef NJ_USE_WIN32 #ifdef _MSC_VER #define NJ_USE_WIN32 (!NJ_USE_LIBC) #else #define NJ_USE_WIN32 0 #endif #endif #ifndef NJ_CHROMA_FILTER #define NJ_CHROMA_FILTER 1 #endif /////////////////////////////////////////////////////////////////////////////// // EXAMPLE PROGRAM // // just define _NJ_EXAMPLE_PROGRAM to compile this (requires NJ_USE_LIBC) // /////////////////////////////////////////////////////////////////////////////// #ifdef _NJ_EXAMPLE_PROGRAM #include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, char* argv[]) { int size; char *buf; FILE *f; if (argc < 2) { printf("Usage: %s <input.jpg> [<output.ppm>]\n", argv[0]); return 2; } f = fopen(argv[1], "rb"); if (!f) { printf("Error opening the input file.\n"); return 1; } fseek(f, 0, SEEK_END); size = (int) ftell(f); buf = (char*) malloc(size); fseek(f, 0, SEEK_SET); size = (int) fread(buf, 1, size, f); fclose(f); njInit(); if (njDecode(buf, size)) { free((void*)buf); printf("Error decoding the input file.\n"); return 1; } free((void*)buf); f = fopen((argc > 2) ? argv[2] : (njIsColor() ? "nanojpeg_out.ppm" : "nanojpeg_out.pgm"), "wb"); if (!f) { printf("Error opening the output file.\n"); return 1; } fprintf(f, "P%d\n%d %d\n255\n", njIsColor() ? 6 : 5, njGetWidth(), njGetHeight()); fwrite(njGetImage(), 1, njGetImageSize(), f); fclose(f); njDone(); return 0; } #endif /////////////////////////////////////////////////////////////////////////////// // IMPLEMENTATION SECTION // // you may stop reading here // /////////////////////////////////////////////////////////////////////////////// #ifndef _NJ_INCLUDE_HEADER_ONLY #ifdef _MSC_VER #define NJ_INLINE static __inline #define NJ_FORCE_INLINE static __forceinline #else #define NJ_INLINE static inline #define NJ_FORCE_INLINE static inline #endif #if NJ_USE_LIBC #include <stdlib.h> #include <string.h> #define njAllocMem malloc #define njFreeMem free #define njFillMem memset #define njCopyMem memcpy #elif NJ_USE_WIN32 #include <windows.h> #define njAllocMem(size) ((void*) LocalAlloc(LMEM_FIXED, (SIZE_T)(size))) #define njFreeMem(block) ((void) LocalFree((HLOCAL) block)) NJ_INLINE void njFillMem(void* block, unsigned char value, int count) { __asm { mov edi, block mov al, value mov ecx, count rep stosb } } NJ_INLINE void njCopyMem(void* dest, const void* src, int count) { __asm { mov edi, dest mov esi, src mov ecx, count rep movsb } } #else extern void* njAllocMem(int size); extern void njFreeMem(void* block); extern void njFillMem(void* block, unsigned char byte, int size); extern void njCopyMem(void* dest, const void* src, int size); #endif typedef struct _nj_code { unsigned char bits, code; } nj_vlc_code_t; typedef struct _nj_cmp { int cid; int ssx, ssy; int width, height; int stride; int qtsel; int actabsel, dctabsel; int dcpred; unsigned char *pixels; } nj_component_t; // Modified structure: Change vlctab[4][65536] to *vlctab[4] so as to minimize // stack use. (The original code caused the refind_x64.efi binary to blow up // from ~260KiB to ~790KiB!) This change, of course, also necessitates changes // to the njInit() and njDone() functions, as well. typedef struct _nj_ctx { nj_result_t error; const unsigned char *pos; int size; int length; int width, height; int mbwidth, mbheight; int mbsizex, mbsizey; int ncomp; nj_component_t comp[3]; int qtused, qtavail; unsigned char qtab[4][64]; nj_vlc_code_t *vlctab[4]; int buf, bufbits; int block[64]; int rstinterval; unsigned char *rgb; } nj_context_t; static nj_context_t nj; static const char njZZ[64] = { 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63 }; NJ_FORCE_INLINE unsigned char njClip(const int x) { return (x < 0) ? 0 : ((x > 0xFF) ? 0xFF : (unsigned char) x); } #define W1 2841 #define W2 2676 #define W3 2408 #define W5 1609 #define W6 1108 #define W7 565 NJ_INLINE void njRowIDCT(int* blk) { int x0, x1, x2, x3, x4, x5, x6, x7, x8; if (!((x1 = blk[4] << 11) | (x2 = blk[6]) | (x3 = blk[2]) | (x4 = blk[1]) | (x5 = blk[7]) | (x6 = blk[5]) | (x7 = blk[3]))) { blk[0] = blk[1] = blk[2] = blk[3] = blk[4] = blk[5] = blk[6] = blk[7] = blk[0] << 3; return; } x0 = (blk[0] << 11) + 128; x8 = W7 * (x4 + x5); x4 = x8 + (W1 - W7) * x4; x5 = x8 - (W1 + W7) * x5; x8 = W3 * (x6 + x7); x6 = x8 - (W3 - W5) * x6; x7 = x8 - (W3 + W5) * x7; x8 = x0 + x1; x0 -= x1; x1 = W6 * (x3 + x2); x2 = x1 - (W2 + W6) * x2; x3 = x1 + (W2 - W6) * x3; x1 = x4 + x6; x4 -= x6; x6 = x5 + x7; x5 -= x7; x7 = x8 + x3; x8 -= x3; x3 = x0 + x2; x0 -= x2; x2 = (181 * (x4 + x5) + 128) >> 8; x4 = (181 * (x4 - x5) + 128) >> 8; blk[0] = (x7 + x1) >> 8; blk[1] = (x3 + x2) >> 8; blk[2] = (x0 + x4) >> 8; blk[3] = (x8 + x6) >> 8; blk[4] = (x8 - x6) >> 8; blk[5] = (x0 - x4) >> 8; blk[6] = (x3 - x2) >> 8; blk[7] = (x7 - x1) >> 8; } NJ_INLINE void njColIDCT(const int* blk, unsigned char *out, int stride) { int x0, x1, x2, x3, x4, x5, x6, x7, x8; if (!((x1 = blk[8*4] << 8) | (x2 = blk[8*6]) | (x3 = blk[8*2]) | (x4 = blk[8*1]) | (x5 = blk[8*7]) | (x6 = blk[8*5]) | (x7 = blk[8*3]))) { x1 = njClip(((blk[0] + 32) >> 6) + 128); for (x0 = 8; x0; --x0) { *out = (unsigned char) x1; out += stride; } return; } x0 = (blk[0] << 8) + 8192; x8 = W7 * (x4 + x5) + 4; x4 = (x8 + (W1 - W7) * x4) >> 3; x5 = (x8 - (W1 + W7) * x5) >> 3; x8 = W3 * (x6 + x7) + 4; x6 = (x8 - (W3 - W5) * x6) >> 3; x7 = (x8 - (W3 + W5) * x7) >> 3; x8 = x0 + x1; x0 -= x1; x1 = W6 * (x3 + x2) + 4; x2 = (x1 - (W2 + W6) * x2) >> 3; x3 = (x1 + (W2 - W6) * x3) >> 3; x1 = x4 + x6; x4 -= x6; x6 = x5 + x7; x5 -= x7; x7 = x8 + x3; x8 -= x3; x3 = x0 + x2; x0 -= x2; x2 = (181 * (x4 + x5) + 128) >> 8; x4 = (181 * (x4 - x5) + 128) >> 8; *out = njClip(((x7 + x1) >> 14) + 128); out += stride; *out = njClip(((x3 + x2) >> 14) + 128); out += stride; *out = njClip(((x0 + x4) >> 14) + 128); out += stride; *out = njClip(((x8 + x6) >> 14) + 128); out += stride; *out = njClip(((x8 - x6) >> 14) + 128); out += stride; *out = njClip(((x0 - x4) >> 14) + 128); out += stride; *out = njClip(((x3 - x2) >> 14) + 128); out += stride; *out = njClip(((x7 - x1) >> 14) + 128); } #define njThrow(e) do { nj.error = e; return; } while (0) #define njCheckError() do { if (nj.error) return; } while (0) static int njShowBits(int bits) { unsigned char newbyte; if (!bits) return 0; while (nj.bufbits < bits) { if (nj.size <= 0) { nj.buf = (nj.buf << 8) | 0xFF; nj.bufbits += 8; continue; } newbyte = *nj.pos++; nj.size--; nj.bufbits += 8; nj.buf = (nj.buf << 8) | newbyte; if (newbyte == 0xFF) { if (nj.size) { unsigned char marker = *nj.pos++; nj.size--; switch (marker) { case 0x00: case 0xFF: break; case 0xD9: nj.size = 0; break; default: if ((marker & 0xF8) != 0xD0) nj.error = NJ_SYNTAX_ERROR; else { nj.buf = (nj.buf << 8) | marker; nj.bufbits += 8; } } } else nj.error = NJ_SYNTAX_ERROR; } } return (nj.buf >> (nj.bufbits - bits)) & ((1 << bits) - 1); } NJ_INLINE void njSkipBits(int bits) { if (nj.bufbits < bits) (void) njShowBits(bits); nj.bufbits -= bits; } NJ_INLINE int njGetBits(int bits) { int res = njShowBits(bits); njSkipBits(bits); return res; } NJ_INLINE void njByteAlign(void) { nj.bufbits &= 0xF8; } static void njSkip(int count) { nj.pos += count; nj.size -= count; nj.length -= count; if (nj.size < 0) nj.error = NJ_SYNTAX_ERROR; } NJ_INLINE unsigned short njDecode16(const unsigned char *pos) { return (pos[0] << 8) | pos[1]; } static void njDecodeLength(void) { if (nj.size < 2) njThrow(NJ_SYNTAX_ERROR); nj.length = njDecode16(nj.pos); if (nj.length > nj.size) njThrow(NJ_SYNTAX_ERROR); njSkip(2); } NJ_INLINE void njSkipMarker(void) { njDecodeLength(); njSkip(nj.length); } NJ_INLINE void njDecodeSOF(void) { int i, ssxmax = 0, ssymax = 0; nj_component_t* c; njDecodeLength(); njCheckError(); if (nj.length < 9) njThrow(NJ_SYNTAX_ERROR); if (nj.pos[0] != 8) njThrow(NJ_UNSUPPORTED); nj.height = njDecode16(nj.pos+1); nj.width = njDecode16(nj.pos+3); if (!nj.width || !nj.height) njThrow(NJ_SYNTAX_ERROR); nj.ncomp = nj.pos[5]; njSkip(6); switch (nj.ncomp) { case 1: case 3: break; default: njThrow(NJ_UNSUPPORTED); } if (nj.length < (nj.ncomp * 3)) njThrow(NJ_SYNTAX_ERROR); for (i = 0, c = nj.comp; i < nj.ncomp; ++i, ++c) { c->cid = nj.pos[0]; if (!(c->ssx = nj.pos[1] >> 4)) njThrow(NJ_SYNTAX_ERROR); if (c->ssx & (c->ssx - 1)) njThrow(NJ_UNSUPPORTED); // non-power of two if (!(c->ssy = nj.pos[1] & 15)) njThrow(NJ_SYNTAX_ERROR); if (c->ssy & (c->ssy - 1)) njThrow(NJ_UNSUPPORTED); // non-power of two if ((c->qtsel = nj.pos[2]) & 0xFC) njThrow(NJ_SYNTAX_ERROR); njSkip(3); nj.qtused |= 1 << c->qtsel; if (c->ssx > ssxmax) ssxmax = c->ssx; if (c->ssy > ssymax) ssymax = c->ssy; } if (nj.ncomp == 1) { c = nj.comp; c->ssx = c->ssy = ssxmax = ssymax = 1; } nj.mbsizex = ssxmax << 3; nj.mbsizey = ssymax << 3; nj.mbwidth = (nj.width + nj.mbsizex - 1) / nj.mbsizex; nj.mbheight = (nj.height + nj.mbsizey - 1) / nj.mbsizey; for (i = 0, c = nj.comp; i < nj.ncomp; ++i, ++c) { c->width = (nj.width * c->ssx + ssxmax - 1) / ssxmax; c->height = (nj.height * c->ssy + ssymax - 1) / ssymax; c->stride = nj.mbwidth * c->ssx << 3; if (((c->width < 3) && (c->ssx != ssxmax)) || ((c->height < 3) && (c->ssy != ssymax))) njThrow(NJ_UNSUPPORTED); if (!(c->pixels = (unsigned char*) njAllocMem(c->stride * nj.mbheight * c->ssy << 3))) njThrow(NJ_OUT_OF_MEM); } if (nj.ncomp == 3) { nj.rgb = (unsigned char*) njAllocMem(nj.width * nj.height * nj.ncomp); if (!nj.rgb) njThrow(NJ_OUT_OF_MEM); } njSkip(nj.length); } NJ_INLINE void njDecodeDHT(void) { int codelen, currcnt, remain, spread, i, j; nj_vlc_code_t *vlc; static unsigned char counts[16]; njDecodeLength(); njCheckError(); while (nj.length >= 17) { i = nj.pos[0]; if (i & 0xEC) njThrow(NJ_SYNTAX_ERROR); if (i & 0x02) njThrow(NJ_UNSUPPORTED); i = (i | (i >> 3)) & 3; // combined DC/AC + tableid value for (codelen = 1; codelen <= 16; ++codelen) counts[codelen - 1] = nj.pos[codelen]; njSkip(17); vlc = &nj.vlctab[i][0]; remain = spread = 65536; for (codelen = 1; codelen <= 16; ++codelen) { spread >>= 1; currcnt = counts[codelen - 1]; if (!currcnt) continue; if (nj.length < currcnt) njThrow(NJ_SYNTAX_ERROR); remain -= currcnt << (16 - codelen); if (remain < 0) njThrow(NJ_SYNTAX_ERROR); for (i = 0; i < currcnt; ++i) { register unsigned char code = nj.pos[i]; for (j = spread; j; --j) { vlc->bits = (unsigned char) codelen; vlc->code = code; ++vlc; } } njSkip(currcnt); } while (remain--) { vlc->bits = 0; ++vlc; } } if (nj.length) njThrow(NJ_SYNTAX_ERROR); } NJ_INLINE void njDecodeDQT(void) { int i; unsigned char *t; njDecodeLength(); njCheckError(); while (nj.length >= 65) { i = nj.pos[0]; if (i & 0xFC) njThrow(NJ_SYNTAX_ERROR); nj.qtavail |= 1 << i; t = &nj.qtab[i][0]; for (i = 0; i < 64; ++i) t[i] = nj.pos[i + 1]; njSkip(65); } if (nj.length) njThrow(NJ_SYNTAX_ERROR); } NJ_INLINE void njDecodeDRI(void) { njDecodeLength(); njCheckError(); if (nj.length < 2) njThrow(NJ_SYNTAX_ERROR); nj.rstinterval = njDecode16(nj.pos); njSkip(nj.length); } static int njGetVLC(nj_vlc_code_t* vlc, unsigned char* code) { int value = njShowBits(16); int bits = vlc[value].bits; if (!bits) { nj.error = NJ_SYNTAX_ERROR; return 0; } njSkipBits(bits); value = vlc[value].code; if (code) *code = (unsigned char) value; bits = value & 15; if (!bits) return 0; value = njGetBits(bits); if (value < (1 << (bits - 1))) value += ((-1) << bits) + 1; return value; } NJ_INLINE void njDecodeBlock(nj_component_t* c, unsigned char* out) { unsigned char code = 0; int value, coef = 0; njFillMem(nj.block, 0, sizeof(nj.block)); c->dcpred += njGetVLC(&nj.vlctab[c->dctabsel][0], NULL); nj.block[0] = (c->dcpred) * nj.qtab[c->qtsel][0]; do { value = njGetVLC(&nj.vlctab[c->actabsel][0], &code); if (!code) break; // EOB if (!(code & 0x0F) && (code != 0xF0)) njThrow(NJ_SYNTAX_ERROR); coef += (code >> 4) + 1; if (coef > 63) njThrow(NJ_SYNTAX_ERROR); nj.block[(int) njZZ[coef]] = value * nj.qtab[c->qtsel][coef]; } while (coef < 63); for (coef = 0; coef < 64; coef += 8) njRowIDCT(&nj.block[coef]); for (coef = 0; coef < 8; ++coef) njColIDCT(&nj.block[coef], &out[coef], c->stride); } NJ_INLINE void njDecodeScan(void) { int i, mbx, mby, sbx, sby; int rstcount = nj.rstinterval, nextrst = 0; nj_component_t* c; njDecodeLength(); njCheckError(); if (nj.length < (4 + 2 * nj.ncomp)) njThrow(NJ_SYNTAX_ERROR); if (nj.pos[0] != nj.ncomp) njThrow(NJ_UNSUPPORTED); njSkip(1); for (i = 0, c = nj.comp; i < nj.ncomp; ++i, ++c) { if (nj.pos[0] != c->cid) njThrow(NJ_SYNTAX_ERROR); if (nj.pos[1] & 0xEE) njThrow(NJ_SYNTAX_ERROR); c->dctabsel = nj.pos[1] >> 4; c->actabsel = (nj.pos[1] & 1) | 2; njSkip(2); } if (nj.pos[0] || (nj.pos[1] != 63) || nj.pos[2]) njThrow(NJ_UNSUPPORTED); njSkip(nj.length); for (mbx = mby = 0;;) { for (i = 0, c = nj.comp; i < nj.ncomp; ++i, ++c) for (sby = 0; sby < c->ssy; ++sby) for (sbx = 0; sbx < c->ssx; ++sbx) { njDecodeBlock(c, &c->pixels[((mby * c->ssy + sby) * c->stride + mbx * c->ssx + sbx) << 3]); njCheckError(); } if (++mbx >= nj.mbwidth) { mbx = 0; if (++mby >= nj.mbheight) break; } if (nj.rstinterval && !(--rstcount)) { njByteAlign(); i = njGetBits(16); if (((i & 0xFFF8) != 0xFFD0) || ((i & 7) != nextrst)) njThrow(NJ_SYNTAX_ERROR); nextrst = (nextrst + 1) & 7; rstcount = nj.rstinterval; for (i = 0; i < 3; ++i) nj.comp[i].dcpred = 0; } } nj.error = __NJ_FINISHED; } #if NJ_CHROMA_FILTER #define CF4A (-9) #define CF4B (111) #define CF4C (29) #define CF4D (-3) #define CF3A (28) #define CF3B (109) #define CF3C (-9) #define CF3X (104) #define CF3Y (27) #define CF3Z (-3) #define CF2A (139) #define CF2B (-11) #define CF(x) njClip(((x) + 64) >> 7) NJ_INLINE void njUpsampleH(nj_component_t* c) { const int xmax = c->width - 3; unsigned char *out, *lin, *lout; int x, y; out = (unsigned char*) njAllocMem((c->width * c->height) << 1); if (!out) njThrow(NJ_OUT_OF_MEM); lin = c->pixels; lout = out; for (y = c->height; y; --y) { lout[0] = CF(CF2A * lin[0] + CF2B * lin[1]); lout[1] = CF(CF3X * lin[0] + CF3Y * lin[1] + CF3Z * lin[2]); lout[2] = CF(CF3A * lin[0] + CF3B * lin[1] + CF3C * lin[2]); for (x = 0; x < xmax; ++x) { lout[(x << 1) + 3] = CF(CF4A * lin[x] + CF4B * lin[x + 1] + CF4C * lin[x + 2] + CF4D * lin[x + 3]); lout[(x << 1) + 4] = CF(CF4D * lin[x] + CF4C * lin[x + 1] + CF4B * lin[x + 2] + CF4A * lin[x + 3]); } lin += c->stride; lout += c->width << 1; lout[-3] = CF(CF3A * lin[-1] + CF3B * lin[-2] + CF3C * lin[-3]); lout[-2] = CF(CF3X * lin[-1] + CF3Y * lin[-2] + CF3Z * lin[-3]); lout[-1] = CF(CF2A * lin[-1] + CF2B * lin[-2]); } c->width <<= 1; c->stride = c->width; njFreeMem((void*)c->pixels); c->pixels = out; } NJ_INLINE void njUpsampleV(nj_component_t* c) { const int w = c->width, s1 = c->stride, s2 = s1 + s1; unsigned char *out, *cin, *cout; int x, y; out = (unsigned char*) njAllocMem((c->width * c->height) << 1); if (!out) njThrow(NJ_OUT_OF_MEM); for (x = 0; x < w; ++x) { cin = &c->pixels[x]; cout = &out[x]; *cout = CF(CF2A * cin[0] + CF2B * cin[s1]); cout += w; *cout = CF(CF3X * cin[0] + CF3Y * cin[s1] + CF3Z * cin[s2]); cout += w; *cout = CF(CF3A * cin[0] + CF3B * cin[s1] + CF3C * cin[s2]); cout += w; cin += s1; for (y = c->height - 3; y; --y) { *cout = CF(CF4A * cin[-s1] + CF4B * cin[0] + CF4C * cin[s1] + CF4D * cin[s2]); cout += w; *cout = CF(CF4D * cin[-s1] + CF4C * cin[0] + CF4B * cin[s1] + CF4A * cin[s2]); cout += w; cin += s1; } cin += s1; *cout = CF(CF3A * cin[0] + CF3B * cin[-s1] + CF3C * cin[-s2]); cout += w; *cout = CF(CF3X * cin[0] + CF3Y * cin[-s1] + CF3Z * cin[-s2]); cout += w; *cout = CF(CF2A * cin[0] + CF2B * cin[-s1]); } c->height <<= 1; c->stride = c->width; njFreeMem((void*) c->pixels); c->pixels = out; } #else NJ_INLINE void njUpsample(nj_component_t* c) { int x, y, xshift = 0, yshift = 0; unsigned char *out, *lin, *lout; while (c->width < nj.width) { c->width <<= 1; ++xshift; } while (c->height < nj.height) { c->height <<= 1; ++yshift; } out = (unsigned char*) njAllocMem(c->width * c->height); if (!out) njThrow(NJ_OUT_OF_MEM); lin = c->pixels; lout = out; for (y = 0; y < c->height; ++y) { lin = &c->pixels[(y >> yshift) * c->stride]; for (x = 0; x < c->width; ++x) lout[x] = lin[x >> xshift]; lout += c->width; } c->stride = c->width; njFreeMem((void*) c->pixels); c->pixels = out; } #endif NJ_INLINE void njConvert(void) { int i; nj_component_t* c; for (i = 0, c = nj.comp; i < nj.ncomp; ++i, ++c) { #if NJ_CHROMA_FILTER while ((c->width < nj.width) || (c->height < nj.height)) { if (c->width < nj.width) njUpsampleH(c); njCheckError(); if (c->height < nj.height) njUpsampleV(c); njCheckError(); } #else if ((c->width < nj.width) || (c->height < nj.height)) njUpsample(c); #endif if ((c->width < nj.width) || (c->height < nj.height)) njThrow(NJ_INTERNAL_ERR); } if (nj.ncomp == 3) { // convert to RGB int x, yy; unsigned char *prgb = nj.rgb; const unsigned char *py = nj.comp[0].pixels; const unsigned char *pcb = nj.comp[1].pixels; const unsigned char *pcr = nj.comp[2].pixels; for (yy = nj.height; yy; --yy) { for (x = 0; x < nj.width; ++x) { register int y = py[x] << 8; register int cb = pcb[x] - 128; register int cr = pcr[x] - 128; *prgb++ = njClip((y + 359 * cr + 128) >> 8); *prgb++ = njClip((y - 88 * cb - 183 * cr + 128) >> 8); *prgb++ = njClip((y + 454 * cb + 128) >> 8); } py += nj.comp[0].stride; pcb += nj.comp[1].stride; pcr += nj.comp[2].stride; } } else if (nj.comp[0].width != nj.comp[0].stride) { // grayscale -> only remove stride unsigned char *pin = &nj.comp[0].pixels[nj.comp[0].stride]; unsigned char *pout = &nj.comp[0].pixels[nj.comp[0].width]; int y; for (y = nj.comp[0].height - 1; y; --y) { njCopyMem(pout, pin, nj.comp[0].width); pin += nj.comp[0].stride; pout += nj.comp[0].width; } nj.comp[0].stride = nj.comp[0].width; } } // Modified njInit(); uses dynamic assignment of nj.vlctab[i] variable, to // avoid a 3x increase in binary size caused by the original static (stack) // definition. // Returns 1 on success, 0 on failure. DO NOT USE SUBSEQUENT FUNCTIONS IF // njInit() FAILS! int njInit(void) { int i, retval = 1; njFillMem(&nj, 0, sizeof(nj_context_t)); for (i = 0; i < 4; i++) { nj.vlctab[i] = njAllocMem(sizeof(nj_vlc_code_t) * 65536); if (nj.vlctab[i]) njFillMem(nj.vlctab[i], 0, sizeof(nj_vlc_code_t) * 65536); else retval = 0; } // for if (retval == 0) { for (i = 0; i < 4; i++) { njFreeMem(nj.vlctab[i]); nj.vlctab[i] = NULL; } // for } // if return retval; } // Modified njDone(); uses dynamic assignment of nj.vlctab[i] variable, to // avoid a 3x increase in binary size caused by the original static (stack) // definition. void njDone(void) { int i; for (i = 0; i < 3; ++i) if (nj.comp[i].pixels) njFreeMem((void*) nj.comp[i].pixels); if (nj.rgb) njFreeMem((void*) nj.rgb); for (i = 0; i < 4; i++) njFreeMem(nj.vlctab[i]); njInit(); } nj_result_t njDecode(const void* jpeg, const int size) { njDone(); nj.pos = (const unsigned char*) jpeg; nj.size = size & 0x7FFFFFFF; if (nj.size < 2) return NJ_NO_JPEG; if ((nj.pos[0] ^ 0xFF) | (nj.pos[1] ^ 0xD8)) return NJ_NO_JPEG; njSkip(2); while (!nj.error) { if ((nj.size < 2) || (nj.pos[0] != 0xFF)) return NJ_SYNTAX_ERROR; njSkip(2); switch (nj.pos[-1]) { case 0xC0: njDecodeSOF(); break; case 0xC4: njDecodeDHT(); break; case 0xDB: njDecodeDQT(); break; case 0xDD: njDecodeDRI(); break; case 0xDA: njDecodeScan(); break; case 0xFE: njSkipMarker(); break; default: if ((nj.pos[-1] & 0xF0) == 0xE0) njSkipMarker(); else return NJ_UNSUPPORTED; } } if (nj.error != __NJ_FINISHED) return nj.error; nj.error = NJ_OK; njConvert(); return nj.error; } int njGetWidth(void) { return nj.width; } int njGetHeight(void) { return nj.height; } int njIsColor(void) { return (nj.ncomp != 1); } unsigned char* njGetImage(void) { return (nj.ncomp == 1) ? nj.comp[0].pixels : nj.rgb; } int njGetImageSize(void) { return nj.width * nj.height * nj.ncomp; } #endif // _NJ_INCLUDE_HEADER_ONLY �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/libeg/lodepng.h�����������������������������������������������������������������������0000664�0001750�0001750�00000242314�13141476702�016210� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* LodePNG version 20161127 Copyright (c) 2005-2016 Lode Vandevenne This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ /* * This version of lodepng.h is modified for use with rEFInd. Some options * are commented out and several definitions (commented on shortly) are added * for GNU-EFI compatibility. The associated lodepng.c file is unmodified * from the original. */ #ifndef LODEPNG_H #define LODEPNG_H #include <string.h> /*for size_t*/ // Below block of lines required for GNU-EFI and TianoCore (program hangs // when run without them, and associated function in lodepng_xtra.c) int MyStrlen(const char *InString); #define strlen(c) MyStrlen(c) #include <stdlib.h> #define abs(x) (((x) < 0) ? -(x) : (x)) #ifdef __MAKEWITH_GNUEFI #include <efi.h> #include <efilib.h> #else #include "../include/tiano_includes.h" #endif VOID *MyMemSet(VOID *s, int c, size_t n); VOID *MyMemCpy(void *__restrict __dest, const void *__restrict __src, size_t __n); #define memset(s, c, n) MyMemSet(s, c, n) #define memcpy(d, s, n) MyMemCpy(d, s, n) extern const char* LODEPNG_VERSION_STRING; /* The following #defines are used to create code sections. They can be disabled to disable code sections, which can give faster compile time and smaller binary. The "NO_COMPILE" defines are designed to be used to pass as defines to the compiler command to disable them without modifying this header, e.g. -DLODEPNG_NO_COMPILE_ZLIB for gcc. In addition to those below, you can also define LODEPNG_NO_COMPILE_CRC to allow implementing a custom lodepng_crc32. */ /*deflate & zlib. If disabled, you must specify alternative zlib functions in the custom_zlib field of the compress and decompress settings*/ #ifndef LODEPNG_NO_COMPILE_ZLIB #define LODEPNG_COMPILE_ZLIB #endif /*png encoder and png decoder*/ #ifndef LODEPNG_NO_COMPILE_PNG #define LODEPNG_COMPILE_PNG #endif /*deflate&zlib decoder and png decoder*/ #ifndef LODEPNG_NO_COMPILE_DECODER #define LODEPNG_COMPILE_DECODER #endif /*deflate&zlib encoder and png encoder*/ // #ifndef LODEPNG_NO_COMPILE_ENCODER // #define LODEPNG_COMPILE_ENCODER // #endif /*the optional built in harddisk file loading and saving functions*/ // #ifndef LODEPNG_NO_COMPILE_DISK // #define LODEPNG_COMPILE_DISK // #endif /*support for chunks other than IHDR, IDAT, PLTE, tRNS, IEND: ancillary and unknown chunks*/ // #ifndef LODEPNG_NO_COMPILE_ANCILLARY_CHUNKS // #define LODEPNG_COMPILE_ANCILLARY_CHUNKS // #endif /*ability to convert error numerical codes to English text string*/ // #ifndef LODEPNG_NO_COMPILE_ERROR_TEXT // #define LODEPNG_COMPILE_ERROR_TEXT // #endif /*Compile the default allocators (C's free, malloc and realloc). If you disable this, you can define the functions lodepng_free, lodepng_malloc and lodepng_realloc in your source files with custom allocators.*/ // #ifndef LODEPNG_NO_COMPILE_ALLOCATORS // #define LODEPNG_COMPILE_ALLOCATORS // #endif /*compile the C++ version (you can disable the C++ wrapper here even when compiling for C++)*/ #ifdef __cplusplus #ifndef LODEPNG_NO_COMPILE_CPP #define LODEPNG_COMPILE_CPP #endif #endif #ifdef LODEPNG_COMPILE_CPP #include <vector> #include <string> #endif /*LODEPNG_COMPILE_CPP*/ #ifdef LODEPNG_COMPILE_PNG /*The PNG color types (also used for raw).*/ typedef enum LodePNGColorType { LCT_GREY = 0, /*greyscale: 1,2,4,8,16 bit*/ LCT_RGB = 2, /*RGB: 8,16 bit*/ LCT_PALETTE = 3, /*palette: 1,2,4,8 bit*/ LCT_GREY_ALPHA = 4, /*greyscale with alpha: 8,16 bit*/ LCT_RGBA = 6 /*RGB with alpha: 8,16 bit*/ } LodePNGColorType; #ifdef LODEPNG_COMPILE_DECODER /* Converts PNG data in memory to raw pixel data. out: Output parameter. Pointer to buffer that will contain the raw pixel data. After decoding, its size is w * h * (bytes per pixel) bytes larger than initially. Bytes per pixel depends on colortype and bitdepth. Must be freed after usage with free(*out). Note: for 16-bit per channel colors, uses big endian format like PNG does. w: Output parameter. Pointer to width of pixel data. h: Output parameter. Pointer to height of pixel data. in: Memory buffer with the PNG file. insize: size of the in buffer. colortype: the desired color type for the raw output image. See explanation on PNG color types. bitdepth: the desired bit depth for the raw output image. See explanation on PNG color types. Return value: LodePNG error code (0 means no error). */ unsigned lodepng_decode_memory(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, size_t insize, LodePNGColorType colortype, unsigned bitdepth); /*Same as lodepng_decode_memory, but always decodes to 32-bit RGBA raw image*/ unsigned lodepng_decode32(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, size_t insize); /*Same as lodepng_decode_memory, but always decodes to 24-bit RGB raw image*/ unsigned lodepng_decode24(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, size_t insize); #ifdef LODEPNG_COMPILE_DISK /* Load PNG from disk, from file with given name. Same as the other decode functions, but instead takes a filename as input. */ unsigned lodepng_decode_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename, LodePNGColorType colortype, unsigned bitdepth); /*Same as lodepng_decode_file, but always decodes to 32-bit RGBA raw image.*/ unsigned lodepng_decode32_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename); /*Same as lodepng_decode_file, but always decodes to 24-bit RGB raw image.*/ unsigned lodepng_decode24_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename); #endif /*LODEPNG_COMPILE_DISK*/ #endif /*LODEPNG_COMPILE_DECODER*/ #ifdef LODEPNG_COMPILE_ENCODER /* Converts raw pixel data into a PNG image in memory. The colortype and bitdepth of the output PNG image cannot be chosen, they are automatically determined by the colortype, bitdepth and content of the input pixel data. Note: for 16-bit per channel colors, needs big endian format like PNG does. out: Output parameter. Pointer to buffer that will contain the PNG image data. Must be freed after usage with free(*out). outsize: Output parameter. Pointer to the size in bytes of the out buffer. image: The raw pixel data to encode. The size of this buffer should be w * h * (bytes per pixel), bytes per pixel depends on colortype and bitdepth. w: width of the raw pixel data in pixels. h: height of the raw pixel data in pixels. colortype: the color type of the raw input image. See explanation on PNG color types. bitdepth: the bit depth of the raw input image. See explanation on PNG color types. Return value: LodePNG error code (0 means no error). */ unsigned lodepng_encode_memory(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth); /*Same as lodepng_encode_memory, but always encodes from 32-bit RGBA raw image.*/ unsigned lodepng_encode32(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h); /*Same as lodepng_encode_memory, but always encodes from 24-bit RGB raw image.*/ unsigned lodepng_encode24(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h); #ifdef LODEPNG_COMPILE_DISK /* Converts raw pixel data into a PNG file on disk. Same as the other encode functions, but instead takes a filename as output. NOTE: This overwrites existing files without warning! */ unsigned lodepng_encode_file(const char* filename, const unsigned char* image, unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth); /*Same as lodepng_encode_file, but always encodes from 32-bit RGBA raw image.*/ unsigned lodepng_encode32_file(const char* filename, const unsigned char* image, unsigned w, unsigned h); /*Same as lodepng_encode_file, but always encodes from 24-bit RGB raw image.*/ unsigned lodepng_encode24_file(const char* filename, const unsigned char* image, unsigned w, unsigned h); #endif /*LODEPNG_COMPILE_DISK*/ #endif /*LODEPNG_COMPILE_ENCODER*/ #ifdef LODEPNG_COMPILE_CPP namespace lodepng { #ifdef LODEPNG_COMPILE_DECODER /*Same as lodepng_decode_memory, but decodes to an std::vector. The colortype is the format to output the pixels to. Default is RGBA 8-bit per channel.*/ unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h, const unsigned char* in, size_t insize, LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h, const std::vector<unsigned char>& in, LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); #ifdef LODEPNG_COMPILE_DISK /* Converts PNG file from disk to raw pixel data in memory. Same as the other decode functions, but instead takes a filename as input. */ unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h, const std::string& filename, LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); #endif /* LODEPNG_COMPILE_DISK */ #endif /* LODEPNG_COMPILE_DECODER */ #ifdef LODEPNG_COMPILE_ENCODER /*Same as lodepng_encode_memory, but encodes to an std::vector. colortype is that of the raw input data. The output PNG color type will be auto chosen.*/ unsigned encode(std::vector<unsigned char>& out, const unsigned char* in, unsigned w, unsigned h, LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); unsigned encode(std::vector<unsigned char>& out, const std::vector<unsigned char>& in, unsigned w, unsigned h, LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); #ifdef LODEPNG_COMPILE_DISK /* Converts 32-bit RGBA raw pixel data into a PNG file on disk. Same as the other encode functions, but instead takes a filename as output. NOTE: This overwrites existing files without warning! */ unsigned encode(const std::string& filename, const unsigned char* in, unsigned w, unsigned h, LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); unsigned encode(const std::string& filename, const std::vector<unsigned char>& in, unsigned w, unsigned h, LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); #endif /* LODEPNG_COMPILE_DISK */ #endif /* LODEPNG_COMPILE_ENCODER */ } /* namespace lodepng */ #endif /*LODEPNG_COMPILE_CPP*/ #endif /*LODEPNG_COMPILE_PNG*/ #ifdef LODEPNG_COMPILE_ERROR_TEXT /*Returns an English description of the numerical error code.*/ const char* lodepng_error_text(unsigned code); #endif /*LODEPNG_COMPILE_ERROR_TEXT*/ #ifdef LODEPNG_COMPILE_DECODER /*Settings for zlib decompression*/ typedef struct LodePNGDecompressSettings LodePNGDecompressSettings; struct LodePNGDecompressSettings { unsigned ignore_adler32; /*if 1, continue and don't give an error message if the Adler32 checksum is corrupted*/ /*use custom zlib decoder instead of built in one (default: null)*/ unsigned (*custom_zlib)(unsigned char**, size_t*, const unsigned char*, size_t, const LodePNGDecompressSettings*); /*use custom deflate decoder instead of built in one (default: null) if custom_zlib is used, custom_deflate is ignored since only the built in zlib function will call custom_deflate*/ unsigned (*custom_inflate)(unsigned char**, size_t*, const unsigned char*, size_t, const LodePNGDecompressSettings*); const void* custom_context; /*optional custom settings for custom functions*/ }; extern const LodePNGDecompressSettings lodepng_default_decompress_settings; void lodepng_decompress_settings_init(LodePNGDecompressSettings* settings); #endif /*LODEPNG_COMPILE_DECODER*/ #ifdef LODEPNG_COMPILE_ENCODER /* Settings for zlib compression. Tweaking these settings tweaks the balance between speed and compression ratio. */ typedef struct LodePNGCompressSettings LodePNGCompressSettings; struct LodePNGCompressSettings /*deflate = compress*/ { /*LZ77 related settings*/ unsigned btype; /*the block type for LZ (0, 1, 2 or 3, see zlib standard). Should be 2 for proper compression.*/ unsigned use_lz77; /*whether or not to use LZ77. Should be 1 for proper compression.*/ unsigned windowsize; /*must be a power of two <= 32768. higher compresses more but is slower. Default value: 2048.*/ unsigned minmatch; /*mininum lz77 length. 3 is normally best, 6 can be better for some PNGs. Default: 0*/ unsigned nicematch; /*stop searching if >= this length found. Set to 258 for best compression. Default: 128*/ unsigned lazymatching; /*use lazy matching: better compression but a bit slower. Default: true*/ /*use custom zlib encoder instead of built in one (default: null)*/ unsigned (*custom_zlib)(unsigned char**, size_t*, const unsigned char*, size_t, const LodePNGCompressSettings*); /*use custom deflate encoder instead of built in one (default: null) if custom_zlib is used, custom_deflate is ignored since only the built in zlib function will call custom_deflate*/ unsigned (*custom_deflate)(unsigned char**, size_t*, const unsigned char*, size_t, const LodePNGCompressSettings*); const void* custom_context; /*optional custom settings for custom functions*/ }; extern const LodePNGCompressSettings lodepng_default_compress_settings; void lodepng_compress_settings_init(LodePNGCompressSettings* settings); #endif /*LODEPNG_COMPILE_ENCODER*/ #ifdef LODEPNG_COMPILE_PNG /* Color mode of an image. Contains all information required to decode the pixel bits to RGBA colors. This information is the same as used in the PNG file format, and is used both for PNG and raw image data in LodePNG. */ typedef struct LodePNGColorMode { /*header (IHDR)*/ LodePNGColorType colortype; /*color type, see PNG standard or documentation further in this header file*/ unsigned bitdepth; /*bits per sample, see PNG standard or documentation further in this header file*/ /* palette (PLTE and tRNS) Dynamically allocated with the colors of the palette, including alpha. When encoding a PNG, to store your colors in the palette of the LodePNGColorMode, first use lodepng_palette_clear, then for each color use lodepng_palette_add. If you encode an image without alpha with palette, don't forget to put value 255 in each A byte of the palette. When decoding, by default you can ignore this palette, since LodePNG already fills the palette colors in the pixels of the raw RGBA output. The palette is only supported for color type 3. */ unsigned char* palette; /*palette in RGBARGBA... order. When allocated, must be either 0, or have size 1024*/ size_t palettesize; /*palette size in number of colors (amount of bytes is 4 * palettesize)*/ /* transparent color key (tRNS) This color uses the same bit depth as the bitdepth value in this struct, which can be 1-bit to 16-bit. For greyscale PNGs, r, g and b will all 3 be set to the same. When decoding, by default you can ignore this information, since LodePNG sets pixels with this key to transparent already in the raw RGBA output. The color key is only supported for color types 0 and 2. */ unsigned key_defined; /*is a transparent color key given? 0 = false, 1 = true*/ unsigned key_r; /*red/greyscale component of color key*/ unsigned key_g; /*green component of color key*/ unsigned key_b; /*blue component of color key*/ } LodePNGColorMode; /*init, cleanup and copy functions to use with this struct*/ void lodepng_color_mode_init(LodePNGColorMode* info); void lodepng_color_mode_cleanup(LodePNGColorMode* info); /*return value is error code (0 means no error)*/ unsigned lodepng_color_mode_copy(LodePNGColorMode* dest, const LodePNGColorMode* source); void lodepng_palette_clear(LodePNGColorMode* info); /*add 1 color to the palette*/ unsigned lodepng_palette_add(LodePNGColorMode* info, unsigned char r, unsigned char g, unsigned char b, unsigned char a); /*get the total amount of bits per pixel, based on colortype and bitdepth in the struct*/ unsigned lodepng_get_bpp(const LodePNGColorMode* info); /*get the amount of color channels used, based on colortype in the struct. If a palette is used, it counts as 1 channel.*/ unsigned lodepng_get_channels(const LodePNGColorMode* info); /*is it a greyscale type? (only colortype 0 or 4)*/ unsigned lodepng_is_greyscale_type(const LodePNGColorMode* info); /*has it got an alpha channel? (only colortype 2 or 6)*/ unsigned lodepng_is_alpha_type(const LodePNGColorMode* info); /*has it got a palette? (only colortype 3)*/ unsigned lodepng_is_palette_type(const LodePNGColorMode* info); /*only returns true if there is a palette and there is a value in the palette with alpha < 255. Loops through the palette to check this.*/ unsigned lodepng_has_palette_alpha(const LodePNGColorMode* info); /* Check if the given color info indicates the possibility of having non-opaque pixels in the PNG image. Returns true if the image can have translucent or invisible pixels (it still be opaque if it doesn't use such pixels). Returns false if the image can only have opaque pixels. In detail, it returns true only if it's a color type with alpha, or has a palette with non-opaque values, or if "key_defined" is true. */ unsigned lodepng_can_have_alpha(const LodePNGColorMode* info); /*Returns the byte size of a raw image buffer with given width, height and color mode*/ size_t lodepng_get_raw_size(unsigned w, unsigned h, const LodePNGColorMode* color); #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS /*The information of a Time chunk in PNG.*/ typedef struct LodePNGTime { unsigned year; /*2 bytes used (0-65535)*/ unsigned month; /*1-12*/ unsigned day; /*1-31*/ unsigned hour; /*0-23*/ unsigned minute; /*0-59*/ unsigned second; /*0-60 (to allow for leap seconds)*/ } LodePNGTime; #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ /*Information about the PNG image, except pixels, width and height.*/ typedef struct LodePNGInfo { /*header (IHDR), palette (PLTE) and transparency (tRNS) chunks*/ unsigned compression_method;/*compression method of the original file. Always 0.*/ unsigned filter_method; /*filter method of the original file*/ unsigned interlace_method; /*interlace method of the original file*/ LodePNGColorMode color; /*color type and bits, palette and transparency of the PNG file*/ #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS /* suggested background color chunk (bKGD) This color uses the same color mode as the PNG (except alpha channel), which can be 1-bit to 16-bit. For greyscale PNGs, r, g and b will all 3 be set to the same. When encoding the encoder writes the red one. For palette PNGs: When decoding, the RGB value will be stored, not a palette index. But when encoding, specify the index of the palette in background_r, the other two are then ignored. The decoder does not use this background color to edit the color of pixels. */ unsigned background_defined; /*is a suggested background color given?*/ unsigned background_r; /*red component of suggested background color*/ unsigned background_g; /*green component of suggested background color*/ unsigned background_b; /*blue component of suggested background color*/ /* non-international text chunks (tEXt and zTXt) The char** arrays each contain num strings. The actual messages are in text_strings, while text_keys are keywords that give a short description what the actual text represents, e.g. Title, Author, Description, or anything else. A keyword is minimum 1 character and maximum 79 characters long. It's discouraged to use a single line length longer than 79 characters for texts. Don't allocate these text buffers yourself. Use the init/cleanup functions correctly and use lodepng_add_text and lodepng_clear_text. */ size_t text_num; /*the amount of texts in these char** buffers (there may be more texts in itext)*/ char** text_keys; /*the keyword of a text chunk (e.g. "Comment")*/ char** text_strings; /*the actual text*/ /* international text chunks (iTXt) Similar to the non-international text chunks, but with additional strings "langtags" and "transkeys". */ size_t itext_num; /*the amount of international texts in this PNG*/ char** itext_keys; /*the English keyword of the text chunk (e.g. "Comment")*/ char** itext_langtags; /*language tag for this text's language, ISO/IEC 646 string, e.g. ISO 639 language tag*/ char** itext_transkeys; /*keyword translated to the international language - UTF-8 string*/ char** itext_strings; /*the actual international text - UTF-8 string*/ /*time chunk (tIME)*/ unsigned time_defined; /*set to 1 to make the encoder generate a tIME chunk*/ LodePNGTime time; /*phys chunk (pHYs)*/ unsigned phys_defined; /*if 0, there is no pHYs chunk and the values below are undefined, if 1 else there is one*/ unsigned phys_x; /*pixels per unit in x direction*/ unsigned phys_y; /*pixels per unit in y direction*/ unsigned phys_unit; /*may be 0 (unknown unit) or 1 (metre)*/ /* unknown chunks There are 3 buffers, one for each position in the PNG where unknown chunks can appear each buffer contains all unknown chunks for that position consecutively The 3 buffers are the unknown chunks between certain critical chunks: 0: IHDR-PLTE, 1: PLTE-IDAT, 2: IDAT-IEND Do not allocate or traverse this data yourself. Use the chunk traversing functions declared later, such as lodepng_chunk_next and lodepng_chunk_append, to read/write this struct. */ unsigned char* unknown_chunks_data[3]; size_t unknown_chunks_size[3]; /*size in bytes of the unknown chunks, given for protection*/ #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ } LodePNGInfo; /*init, cleanup and copy functions to use with this struct*/ void lodepng_info_init(LodePNGInfo* info); void lodepng_info_cleanup(LodePNGInfo* info); /*return value is error code (0 means no error)*/ unsigned lodepng_info_copy(LodePNGInfo* dest, const LodePNGInfo* source); #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS void lodepng_clear_text(LodePNGInfo* info); /*use this to clear the texts again after you filled them in*/ unsigned lodepng_add_text(LodePNGInfo* info, const char* key, const char* str); /*push back both texts at once*/ void lodepng_clear_itext(LodePNGInfo* info); /*use this to clear the itexts again after you filled them in*/ unsigned lodepng_add_itext(LodePNGInfo* info, const char* key, const char* langtag, const char* transkey, const char* str); /*push back the 4 texts of 1 chunk at once*/ #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ /* Converts raw buffer from one color type to another color type, based on LodePNGColorMode structs to describe the input and output color type. See the reference manual at the end of this header file to see which color conversions are supported. return value = LodePNG error code (0 if all went ok, an error if the conversion isn't supported) The out buffer must have size (w * h * bpp + 7) / 8, where bpp is the bits per pixel of the output color type (lodepng_get_bpp). For < 8 bpp images, there should not be padding bits at the end of scanlines. For 16-bit per channel colors, uses big endian format like PNG does. Return value is LodePNG error code */ unsigned lodepng_convert(unsigned char* out, const unsigned char* in, const LodePNGColorMode* mode_out, const LodePNGColorMode* mode_in, unsigned w, unsigned h); #ifdef LODEPNG_COMPILE_DECODER /* Settings for the decoder. This contains settings for the PNG and the Zlib decoder, but not the Info settings from the Info structs. */ typedef struct LodePNGDecoderSettings { LodePNGDecompressSettings zlibsettings; /*in here is the setting to ignore Adler32 checksums*/ unsigned ignore_crc; /*ignore CRC checksums*/ unsigned color_convert; /*whether to convert the PNG to the color type you want. Default: yes*/ #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS unsigned read_text_chunks; /*if false but remember_unknown_chunks is true, they're stored in the unknown chunks*/ /*store all bytes from unknown chunks in the LodePNGInfo (off by default, useful for a png editor)*/ unsigned remember_unknown_chunks; #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ } LodePNGDecoderSettings; void lodepng_decoder_settings_init(LodePNGDecoderSettings* settings); #endif /*LODEPNG_COMPILE_DECODER*/ #ifdef LODEPNG_COMPILE_ENCODER /*automatically use color type with less bits per pixel if losslessly possible. Default: AUTO*/ typedef enum LodePNGFilterStrategy { /*every filter at zero*/ LFS_ZERO, /*Use filter that gives minimum sum, as described in the official PNG filter heuristic.*/ LFS_MINSUM, /*Use the filter type that gives smallest Shannon entropy for this scanline. Depending on the image, this is better or worse than minsum.*/ LFS_ENTROPY, /* Brute-force-search PNG filters by compressing each filter for each scanline. Experimental, very slow, and only rarely gives better compression than MINSUM. */ LFS_BRUTE_FORCE, /*use predefined_filters buffer: you specify the filter type for each scanline*/ LFS_PREDEFINED } LodePNGFilterStrategy; /*Gives characteristics about the colors of the image, which helps decide which color model to use for encoding. Used internally by default if "auto_convert" is enabled. Public because it's useful for custom algorithms.*/ typedef struct LodePNGColorProfile { unsigned colored; /*not greyscale*/ unsigned key; /*image is not opaque and color key is possible instead of full alpha*/ unsigned short key_r; /*key values, always as 16-bit, in 8-bit case the byte is duplicated, e.g. 65535 means 255*/ unsigned short key_g; unsigned short key_b; unsigned alpha; /*image is not opaque and alpha channel or alpha palette required*/ unsigned numcolors; /*amount of colors, up to 257. Not valid if bits == 16.*/ unsigned char palette[1024]; /*Remembers up to the first 256 RGBA colors, in no particular order*/ unsigned bits; /*bits per channel (not for palette). 1,2 or 4 for greyscale only. 16 if 16-bit per channel required.*/ } LodePNGColorProfile; void lodepng_color_profile_init(LodePNGColorProfile* profile); /*Get a LodePNGColorProfile of the image.*/ unsigned lodepng_get_color_profile(LodePNGColorProfile* profile, const unsigned char* image, unsigned w, unsigned h, const LodePNGColorMode* mode_in); /*The function LodePNG uses internally to decide the PNG color with auto_convert. Chooses an optimal color model, e.g. grey if only grey pixels, palette if < 256 colors, ...*/ unsigned lodepng_auto_choose_color(LodePNGColorMode* mode_out, const unsigned char* image, unsigned w, unsigned h, const LodePNGColorMode* mode_in); /*Settings for the encoder.*/ typedef struct LodePNGEncoderSettings { LodePNGCompressSettings zlibsettings; /*settings for the zlib encoder, such as window size, ...*/ unsigned auto_convert; /*automatically choose output PNG color type. Default: true*/ /*If true, follows the official PNG heuristic: if the PNG uses a palette or lower than 8 bit depth, set all filters to zero. Otherwise use the filter_strategy. Note that to completely follow the official PNG heuristic, filter_palette_zero must be true and filter_strategy must be LFS_MINSUM*/ unsigned filter_palette_zero; /*Which filter strategy to use when not using zeroes due to filter_palette_zero. Set filter_palette_zero to 0 to ensure always using your chosen strategy. Default: LFS_MINSUM*/ LodePNGFilterStrategy filter_strategy; /*used if filter_strategy is LFS_PREDEFINED. In that case, this must point to a buffer with the same length as the amount of scanlines in the image, and each value must <= 5. You have to cleanup this buffer, LodePNG will never free it. Don't forget that filter_palette_zero must be set to 0 to ensure this is also used on palette or low bitdepth images.*/ const unsigned char* predefined_filters; /*force creating a PLTE chunk if colortype is 2 or 6 (= a suggested palette). If colortype is 3, PLTE is _always_ created.*/ unsigned force_palette; #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS /*add LodePNG identifier and version as a text chunk, for debugging*/ unsigned add_id; /*encode text chunks as zTXt chunks instead of tEXt chunks, and use compression in iTXt chunks*/ unsigned text_compression; #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ } LodePNGEncoderSettings; void lodepng_encoder_settings_init(LodePNGEncoderSettings* settings); #endif /*LODEPNG_COMPILE_ENCODER*/ #if defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) /*The settings, state and information for extended encoding and decoding.*/ typedef struct LodePNGState { #ifdef LODEPNG_COMPILE_DECODER LodePNGDecoderSettings decoder; /*the decoding settings*/ #endif /*LODEPNG_COMPILE_DECODER*/ #ifdef LODEPNG_COMPILE_ENCODER LodePNGEncoderSettings encoder; /*the encoding settings*/ #endif /*LODEPNG_COMPILE_ENCODER*/ LodePNGColorMode info_raw; /*specifies the format in which you would like to get the raw pixel buffer*/ LodePNGInfo info_png; /*info of the PNG image obtained after decoding*/ unsigned error; #ifdef LODEPNG_COMPILE_CPP /* For the lodepng::State subclass. */ virtual ~LodePNGState(){} #endif } LodePNGState; /*init, cleanup and copy functions to use with this struct*/ void lodepng_state_init(LodePNGState* state); void lodepng_state_cleanup(LodePNGState* state); void lodepng_state_copy(LodePNGState* dest, const LodePNGState* source); #endif /* defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) */ #ifdef LODEPNG_COMPILE_DECODER /* Same as lodepng_decode_memory, but uses a LodePNGState to allow custom settings and getting much more information about the PNG image and color mode. */ unsigned lodepng_decode(unsigned char** out, unsigned* w, unsigned* h, LodePNGState* state, const unsigned char* in, size_t insize); /* Read the PNG header, but not the actual data. This returns only the information that is in the header chunk of the PNG, such as width, height and color type. The information is placed in the info_png field of the LodePNGState. */ unsigned lodepng_inspect(unsigned* w, unsigned* h, LodePNGState* state, const unsigned char* in, size_t insize); #endif /*LODEPNG_COMPILE_DECODER*/ #ifdef LODEPNG_COMPILE_ENCODER /*This function allocates the out buffer with standard malloc and stores the size in *outsize.*/ unsigned lodepng_encode(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h, LodePNGState* state); #endif /*LODEPNG_COMPILE_ENCODER*/ /* The lodepng_chunk functions are normally not needed, except to traverse the unknown chunks stored in the LodePNGInfo struct, or add new ones to it. It also allows traversing the chunks of an encoded PNG file yourself. PNG standard chunk naming conventions: First byte: uppercase = critical, lowercase = ancillary Second byte: uppercase = public, lowercase = private Third byte: must be uppercase Fourth byte: uppercase = unsafe to copy, lowercase = safe to copy */ /* Gets the length of the data of the chunk. Total chunk length has 12 bytes more. There must be at least 4 bytes to read from. If the result value is too large, it may be corrupt data. */ unsigned lodepng_chunk_length(const unsigned char* chunk); /*puts the 4-byte type in null terminated string*/ void lodepng_chunk_type(char type[5], const unsigned char* chunk); /*check if the type is the given type*/ unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type); /*0: it's one of the critical chunk types, 1: it's an ancillary chunk (see PNG standard)*/ unsigned char lodepng_chunk_ancillary(const unsigned char* chunk); /*0: public, 1: private (see PNG standard)*/ unsigned char lodepng_chunk_private(const unsigned char* chunk); /*0: the chunk is unsafe to copy, 1: the chunk is safe to copy (see PNG standard)*/ unsigned char lodepng_chunk_safetocopy(const unsigned char* chunk); /*get pointer to the data of the chunk, where the input points to the header of the chunk*/ unsigned char* lodepng_chunk_data(unsigned char* chunk); const unsigned char* lodepng_chunk_data_const(const unsigned char* chunk); /*returns 0 if the crc is correct, 1 if it's incorrect (0 for OK as usual!)*/ unsigned lodepng_chunk_check_crc(const unsigned char* chunk); /*generates the correct CRC from the data and puts it in the last 4 bytes of the chunk*/ void lodepng_chunk_generate_crc(unsigned char* chunk); /*iterate to next chunks. don't use on IEND chunk, as there is no next chunk then*/ unsigned char* lodepng_chunk_next(unsigned char* chunk); const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk); /* Appends chunk to the data in out. The given chunk should already have its chunk header. The out variable and outlength are updated to reflect the new reallocated buffer. Returns error code (0 if it went ok) */ unsigned lodepng_chunk_append(unsigned char** out, size_t* outlength, const unsigned char* chunk); /* Appends new chunk to out. The chunk to append is given by giving its length, type and data separately. The type is a 4-letter string. The out variable and outlength are updated to reflect the new reallocated buffer. Returne error code (0 if it went ok) */ unsigned lodepng_chunk_create(unsigned char** out, size_t* outlength, unsigned length, const char* type, const unsigned char* data); /*Calculate CRC32 of buffer*/ unsigned lodepng_crc32(const unsigned char* buf, size_t len); #endif /*LODEPNG_COMPILE_PNG*/ #ifdef LODEPNG_COMPILE_ZLIB /* This zlib part can be used independently to zlib compress and decompress a buffer. It cannot be used to create gzip files however, and it only supports the part of zlib that is required for PNG, it does not support dictionaries. */ #ifdef LODEPNG_COMPILE_DECODER /*Inflate a buffer. Inflate is the decompression step of deflate. Out buffer must be freed after use.*/ unsigned lodepng_inflate(unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize, const LodePNGDecompressSettings* settings); /* Decompresses Zlib data. Reallocates the out buffer and appends the data. The data must be according to the zlib specification. Either, *out must be NULL and *outsize must be 0, or, *out must be a valid buffer and *outsize its size in bytes. out must be freed by user after usage. */ unsigned lodepng_zlib_decompress(unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize, const LodePNGDecompressSettings* settings); #endif /*LODEPNG_COMPILE_DECODER*/ #ifdef LODEPNG_COMPILE_ENCODER /* Compresses data with Zlib. Reallocates the out buffer and appends the data. Zlib adds a small header and trailer around the deflate data. The data is output in the format of the zlib specification. Either, *out must be NULL and *outsize must be 0, or, *out must be a valid buffer and *outsize its size in bytes. out must be freed by user after usage. */ unsigned lodepng_zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize, const LodePNGCompressSettings* settings); /* Find length-limited Huffman code for given frequencies. This function is in the public interface only for tests, it's used internally by lodepng_deflate. */ unsigned lodepng_huffman_code_lengths(unsigned* lengths, const unsigned* frequencies, size_t numcodes, unsigned maxbitlen); /*Compress a buffer with deflate. See RFC 1951. Out buffer must be freed after use.*/ unsigned lodepng_deflate(unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize, const LodePNGCompressSettings* settings); #endif /*LODEPNG_COMPILE_ENCODER*/ #endif /*LODEPNG_COMPILE_ZLIB*/ #ifdef LODEPNG_COMPILE_DISK /* Load a file from disk into buffer. The function allocates the out buffer, and after usage you should free it. out: output parameter, contains pointer to loaded buffer. outsize: output parameter, size of the allocated out buffer filename: the path to the file to load return value: error code (0 means ok) */ unsigned lodepng_load_file(unsigned char** out, size_t* outsize, const char* filename); /* Save a file from buffer to disk. Warning, if it exists, this function overwrites the file without warning! buffer: the buffer to write buffersize: size of the buffer to write filename: the path to the file to save to return value: error code (0 means ok) */ unsigned lodepng_save_file(const unsigned char* buffer, size_t buffersize, const char* filename); #endif /*LODEPNG_COMPILE_DISK*/ #ifdef LODEPNG_COMPILE_CPP /* The LodePNG C++ wrapper uses std::vectors instead of manually allocated memory buffers. */ namespace lodepng { #ifdef LODEPNG_COMPILE_PNG class State : public LodePNGState { public: State(); State(const State& other); virtual ~State(); State& operator=(const State& other); }; #ifdef LODEPNG_COMPILE_DECODER /* Same as other lodepng::decode, but using a State for more settings and information. */ unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h, State& state, const unsigned char* in, size_t insize); unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h, State& state, const std::vector<unsigned char>& in); #endif /*LODEPNG_COMPILE_DECODER*/ #ifdef LODEPNG_COMPILE_ENCODER /* Same as other lodepng::encode, but using a State for more settings and information. */ unsigned encode(std::vector<unsigned char>& out, const unsigned char* in, unsigned w, unsigned h, State& state); unsigned encode(std::vector<unsigned char>& out, const std::vector<unsigned char>& in, unsigned w, unsigned h, State& state); #endif /*LODEPNG_COMPILE_ENCODER*/ #ifdef LODEPNG_COMPILE_DISK /* Load a file from disk into an std::vector. return value: error code (0 means ok) */ unsigned load_file(std::vector<unsigned char>& buffer, const std::string& filename); /* Save the binary data in an std::vector to a file on disk. The file is overwritten without warning. */ unsigned save_file(const std::vector<unsigned char>& buffer, const std::string& filename); #endif /* LODEPNG_COMPILE_DISK */ #endif /* LODEPNG_COMPILE_PNG */ #ifdef LODEPNG_COMPILE_ZLIB #ifdef LODEPNG_COMPILE_DECODER /* Zlib-decompress an unsigned char buffer */ unsigned decompress(std::vector<unsigned char>& out, const unsigned char* in, size_t insize, const LodePNGDecompressSettings& settings = lodepng_default_decompress_settings); /* Zlib-decompress an std::vector */ unsigned decompress(std::vector<unsigned char>& out, const std::vector<unsigned char>& in, const LodePNGDecompressSettings& settings = lodepng_default_decompress_settings); #endif /* LODEPNG_COMPILE_DECODER */ #ifdef LODEPNG_COMPILE_ENCODER /* Zlib-compress an unsigned char buffer */ unsigned compress(std::vector<unsigned char>& out, const unsigned char* in, size_t insize, const LodePNGCompressSettings& settings = lodepng_default_compress_settings); /* Zlib-compress an std::vector */ unsigned compress(std::vector<unsigned char>& out, const std::vector<unsigned char>& in, const LodePNGCompressSettings& settings = lodepng_default_compress_settings); #endif /* LODEPNG_COMPILE_ENCODER */ #endif /* LODEPNG_COMPILE_ZLIB */ } /* namespace lodepng */ #endif /*LODEPNG_COMPILE_CPP*/ /* TODO: [.] test if there are no memory leaks or security exploits - done a lot but needs to be checked often [.] check compatibility with various compilers - done but needs to be redone for every newer version [X] converting color to 16-bit per channel types [ ] read all public PNG chunk types (but never let the color profile and gamma ones touch RGB values) [ ] make sure encoder generates no chunks with size > (2^31)-1 [ ] partial decoding (stream processing) [X] let the "isFullyOpaque" function check color keys and transparent palettes too [X] better name for the variables "codes", "codesD", "codelengthcodes", "clcl" and "lldl" [ ] don't stop decoding on errors like 69, 57, 58 (make warnings) [ ] make warnings like: oob palette, checksum fail, data after iend, wrong/unknown crit chunk, no null terminator in text, ... [ ] let the C++ wrapper catch exceptions coming from the standard library and return LodePNG error codes [ ] allow user to provide custom color conversion functions, e.g. for premultiplied alpha, padding bits or not, ... [ ] allow user to give data (void*) to custom allocator */ #endif /*LODEPNG_H inclusion guard*/ /* LodePNG Documentation --------------------- 0. table of contents -------------------- 1. about 1.1. supported features 1.2. features not supported 2. C and C++ version 3. security 4. decoding 5. encoding 6. color conversions 6.1. PNG color types 6.2. color conversions 6.3. padding bits 6.4. A note about 16-bits per channel and endianness 7. error values 8. chunks and PNG editing 9. compiler support 10. examples 10.1. decoder C++ example 10.2. decoder C example 11. state settings reference 12. changes 13. contact information 1. about -------- PNG is a file format to store raster images losslessly with good compression, supporting different color types and alpha channel. LodePNG is a PNG codec according to the Portable Network Graphics (PNG) Specification (Second Edition) - W3C Recommendation 10 November 2003. The specifications used are: *) Portable Network Graphics (PNG) Specification (Second Edition): http://www.w3.org/TR/2003/REC-PNG-20031110 *) RFC 1950 ZLIB Compressed Data Format version 3.3: http://www.gzip.org/zlib/rfc-zlib.html *) RFC 1951 DEFLATE Compressed Data Format Specification ver 1.3: http://www.gzip.org/zlib/rfc-deflate.html The most recent version of LodePNG can currently be found at http://lodev.org/lodepng/ LodePNG works both in C (ISO C90) and C++, with a C++ wrapper that adds extra functionality. LodePNG exists out of two files: -lodepng.h: the header file for both C and C++ -lodepng.c(pp): give it the name lodepng.c or lodepng.cpp (or .cc) depending on your usage If you want to start using LodePNG right away without reading this doc, get the examples from the LodePNG website to see how to use it in code, or check the smaller examples in chapter 13 here. LodePNG is simple but only supports the basic requirements. To achieve simplicity, the following design choices were made: There are no dependencies on any external library. There are functions to decode and encode a PNG with a single function call, and extended versions of these functions taking a LodePNGState struct allowing to specify or get more information. By default the colors of the raw image are always RGB or RGBA, no matter what color type the PNG file uses. To read and write files, there are simple functions to convert the files to/from buffers in memory. This all makes LodePNG suitable for loading textures in games, demos and small programs, ... It's less suitable for full fledged image editors, loading PNGs over network (it requires all the image data to be available before decoding can begin), life-critical systems, ... 1.1. supported features ----------------------- The following features are supported by the decoder: *) decoding of PNGs with any color type, bit depth and interlace mode, to a 24- or 32-bit color raw image, or the same color type as the PNG *) encoding of PNGs, from any raw image to 24- or 32-bit color, or the same color type as the raw image *) Adam7 interlace and deinterlace for any color type *) loading the image from harddisk or decoding it from a buffer from other sources than harddisk *) support for alpha channels, including RGBA color model, translucent palettes and color keying *) zlib decompression (inflate) *) zlib compression (deflate) *) CRC32 and ADLER32 checksums *) handling of unknown chunks, allowing making a PNG editor that stores custom and unknown chunks. *) the following chunks are supported (generated/interpreted) by both encoder and decoder: IHDR: header information PLTE: color palette IDAT: pixel data IEND: the final chunk tRNS: transparency for palettized images tEXt: textual information zTXt: compressed textual information iTXt: international textual information bKGD: suggested background color pHYs: physical dimensions tIME: modification time 1.2. features not supported --------------------------- The following features are _not_ supported: *) some features needed to make a conformant PNG-Editor might be still missing. *) partial loading/stream processing. All data must be available and is processed in one call. *) The following public chunks are not supported but treated as unknown chunks by LodePNG cHRM, gAMA, iCCP, sRGB, sBIT, hIST, sPLT Some of these are not supported on purpose: LodePNG wants to provide the RGB values stored in the pixels, not values modified by system dependent gamma or color models. 2. C and C++ version -------------------- The C version uses buffers allocated with alloc that you need to free() yourself. You need to use init and cleanup functions for each struct whenever using a struct from the C version to avoid exploits and memory leaks. The C++ version has extra functions with std::vectors in the interface and the lodepng::State class which is a LodePNGState with constructor and destructor. These files work without modification for both C and C++ compilers because all the additional C++ code is in "#ifdef __cplusplus" blocks that make C-compilers ignore it, and the C code is made to compile both with strict ISO C90 and C++. To use the C++ version, you need to rename the source file to lodepng.cpp (instead of lodepng.c), and compile it with a C++ compiler. To use the C version, you need to rename the source file to lodepng.c (instead of lodepng.cpp), and compile it with a C compiler. 3. Security ----------- Even if carefully designed, it's always possible that LodePNG contains possible exploits. If you discover one, please let me know, and it will be fixed. When using LodePNG, care has to be taken with the C version of LodePNG, as well as the C-style structs when working with C++. The following conventions are used for all C-style structs: -if a struct has a corresponding init function, always call the init function when making a new one -if a struct has a corresponding cleanup function, call it before the struct disappears to avoid memory leaks -if a struct has a corresponding copy function, use the copy function instead of "=". The destination must also be inited already. 4. Decoding ----------- Decoding converts a PNG compressed image to a raw pixel buffer. Most documentation on using the decoder is at its declarations in the header above. For C, simple decoding can be done with functions such as lodepng_decode32, and more advanced decoding can be done with the struct LodePNGState and lodepng_decode. For C++, all decoding can be done with the various lodepng::decode functions, and lodepng::State can be used for advanced features. When using the LodePNGState, it uses the following fields for decoding: *) LodePNGInfo info_png: it stores extra information about the PNG (the input) in here *) LodePNGColorMode info_raw: here you can say what color mode of the raw image (the output) you want to get *) LodePNGDecoderSettings decoder: you can specify a few extra settings for the decoder to use LodePNGInfo info_png -------------------- After decoding, this contains extra information of the PNG image, except the actual pixels, width and height because these are already gotten directly from the decoder functions. It contains for example the original color type of the PNG image, text comments, suggested background color, etc... More details about the LodePNGInfo struct are at its declaration documentation. LodePNGColorMode info_raw ------------------------- When decoding, here you can specify which color type you want the resulting raw image to be. If this is different from the colortype of the PNG, then the decoder will automatically convert the result. This conversion always works, except if you want it to convert a color PNG to greyscale or to a palette with missing colors. By default, 32-bit color is used for the result. LodePNGDecoderSettings decoder ------------------------------ The settings can be used to ignore the errors created by invalid CRC and Adler32 chunks, and to disable the decoding of tEXt chunks. There's also a setting color_convert, true by default. If false, no conversion is done, the resulting data will be as it was in the PNG (after decompression) and you'll have to puzzle the colors of the pixels together yourself using the color type information in the LodePNGInfo. 5. Encoding ----------- Encoding converts a raw pixel buffer to a PNG compressed image. Most documentation on using the encoder is at its declarations in the header above. For C, simple encoding can be done with functions such as lodepng_encode32, and more advanced decoding can be done with the struct LodePNGState and lodepng_encode. For C++, all encoding can be done with the various lodepng::encode functions, and lodepng::State can be used for advanced features. Like the decoder, the encoder can also give errors. However it gives less errors since the encoder input is trusted, the decoder input (a PNG image that could be forged by anyone) is not trusted. When using the LodePNGState, it uses the following fields for encoding: *) LodePNGInfo info_png: here you specify how you want the PNG (the output) to be. *) LodePNGColorMode info_raw: here you say what color type of the raw image (the input) has *) LodePNGEncoderSettings encoder: you can specify a few settings for the encoder to use LodePNGInfo info_png -------------------- When encoding, you use this the opposite way as when decoding: for encoding, you fill in the values you want the PNG to have before encoding. By default it's not needed to specify a color type for the PNG since it's automatically chosen, but it's possible to choose it yourself given the right settings. The encoder will not always exactly match the LodePNGInfo struct you give, it tries as close as possible. Some things are ignored by the encoder. The encoder uses, for example, the following settings from it when applicable: colortype and bitdepth, text chunks, time chunk, the color key, the palette, the background color, the interlace method, unknown chunks, ... When encoding to a PNG with colortype 3, the encoder will generate a PLTE chunk. If the palette contains any colors for which the alpha channel is not 255 (so there are translucent colors in the palette), it'll add a tRNS chunk. LodePNGColorMode info_raw ------------------------- You specify the color type of the raw image that you give to the input here, including a possible transparent color key and palette you happen to be using in your raw image data. By default, 32-bit color is assumed, meaning your input has to be in RGBA format with 4 bytes (unsigned chars) per pixel. LodePNGEncoderSettings encoder ------------------------------ The following settings are supported (some are in sub-structs): *) auto_convert: when this option is enabled, the encoder will automatically choose the smallest possible color mode (including color key) that can encode the colors of all pixels without information loss. *) btype: the block type for LZ77. 0 = uncompressed, 1 = fixed huffman tree, 2 = dynamic huffman tree (best compression). Should be 2 for proper compression. *) use_lz77: whether or not to use LZ77 for compressed block types. Should be true for proper compression. *) windowsize: the window size used by the LZ77 encoder (1 - 32768). Has value 2048 by default, but can be set to 32768 for better, but slow, compression. *) force_palette: if colortype is 2 or 6, you can make the encoder write a PLTE chunk if force_palette is true. This can used as suggested palette to convert to by viewers that don't support more than 256 colors (if those still exist) *) add_id: add text chunk "Encoder: LodePNG <version>" to the image. *) text_compression: default 1. If 1, it'll store texts as zTXt instead of tEXt chunks. zTXt chunks use zlib compression on the text. This gives a smaller result on large texts but a larger result on small texts (such as a single program name). It's all tEXt or all zTXt though, there's no separate setting per text yet. 6. color conversions -------------------- An important thing to note about LodePNG, is that the color type of the PNG, and the color type of the raw image, are completely independent. By default, when you decode a PNG, you get the result as a raw image in the color type you want, no matter whether the PNG was encoded with a palette, greyscale or RGBA color. And if you encode an image, by default LodePNG will automatically choose the PNG color type that gives good compression based on the values of colors and amount of colors in the image. It can be configured to let you control it instead as well, though. To be able to do this, LodePNG does conversions from one color mode to another. It can convert from almost any color type to any other color type, except the following conversions: RGB to greyscale is not supported, and converting to a palette when the palette doesn't have a required color is not supported. This is not supported on purpose: this is information loss which requires a color reduction algorithm that is beyong the scope of a PNG encoder (yes, RGB to grey is easy, but there are multiple ways if you want to give some channels more weight). By default, when decoding, you get the raw image in 32-bit RGBA or 24-bit RGB color, no matter what color type the PNG has. And by default when encoding, LodePNG automatically picks the best color model for the output PNG, and expects the input image to be 32-bit RGBA or 24-bit RGB. So, unless you want to control the color format of the images yourself, you can skip this chapter. 6.1. PNG color types -------------------- A PNG image can have many color types, ranging from 1-bit color to 64-bit color, as well as palettized color modes. After the zlib decompression and unfiltering in the PNG image is done, the raw pixel data will have that color type and thus a certain amount of bits per pixel. If you want the output raw image after decoding to have another color type, a conversion is done by LodePNG. The PNG specification gives the following color types: 0: greyscale, bit depths 1, 2, 4, 8, 16 2: RGB, bit depths 8 and 16 3: palette, bit depths 1, 2, 4 and 8 4: greyscale with alpha, bit depths 8 and 16 6: RGBA, bit depths 8 and 16 Bit depth is the amount of bits per pixel per color channel. So the total amount of bits per pixel is: amount of channels * bitdepth. 6.2. color conversions ---------------------- As explained in the sections about the encoder and decoder, you can specify color types and bit depths in info_png and info_raw to change the default behaviour. If, when decoding, you want the raw image to be something else than the default, you need to set the color type and bit depth you want in the LodePNGColorMode, or the parameters colortype and bitdepth of the simple decoding function. If, when encoding, you use another color type than the default in the raw input image, you need to specify its color type and bit depth in the LodePNGColorMode of the raw image, or use the parameters colortype and bitdepth of the simple encoding function. If, when encoding, you don't want LodePNG to choose the output PNG color type but control it yourself, you need to set auto_convert in the encoder settings to false, and specify the color type you want in the LodePNGInfo of the encoder (including palette: it can generate a palette if auto_convert is true, otherwise not). If the input and output color type differ (whether user chosen or auto chosen), LodePNG will do a color conversion, which follows the rules below, and may sometimes result in an error. To avoid some confusion: -the decoder converts from PNG to raw image -the encoder converts from raw image to PNG -the colortype and bitdepth in LodePNGColorMode info_raw, are those of the raw image -the colortype and bitdepth in the color field of LodePNGInfo info_png, are those of the PNG -when encoding, the color type in LodePNGInfo is ignored if auto_convert is enabled, it is automatically generated instead -when decoding, the color type in LodePNGInfo is set by the decoder to that of the original PNG image, but it can be ignored since the raw image has the color type you requested instead -if the color type of the LodePNGColorMode and PNG image aren't the same, a conversion between the color types is done if the color types are supported. If it is not supported, an error is returned. If the types are the same, no conversion is done. -even though some conversions aren't supported, LodePNG supports loading PNGs from any colortype and saving PNGs to any colortype, sometimes it just requires preparing the raw image correctly before encoding. -both encoder and decoder use the same color converter. Non supported color conversions: -color to greyscale: no error is thrown, but the result will look ugly because only the red channel is taken -anything to palette when that palette does not have that color in it: in this case an error is thrown Supported color conversions: -anything to 8-bit RGB, 8-bit RGBA, 16-bit RGB, 16-bit RGBA -any grey or grey+alpha, to grey or grey+alpha -anything to a palette, as long as the palette has the requested colors in it -removing alpha channel -higher to smaller bitdepth, and vice versa If you want no color conversion to be done (e.g. for speed or control): -In the encoder, you can make it save a PNG with any color type by giving the raw color mode and LodePNGInfo the same color mode, and setting auto_convert to false. -In the decoder, you can make it store the pixel data in the same color type as the PNG has, by setting the color_convert setting to false. Settings in info_raw are then ignored. The function lodepng_convert does the color conversion. It is available in the interface but normally isn't needed since the encoder and decoder already call it. 6.3. padding bits ----------------- In the PNG file format, if a less than 8-bit per pixel color type is used and the scanlines have a bit amount that isn't a multiple of 8, then padding bits are used so that each scanline starts at a fresh byte. But that is NOT true for the LodePNG raw input and output. The raw input image you give to the encoder, and the raw output image you get from the decoder will NOT have these padding bits, e.g. in the case of a 1-bit image with a width of 7 pixels, the first pixel of the second scanline will the the 8th bit of the first byte, not the first bit of a new byte. 6.4. A note about 16-bits per channel and endianness ---------------------------------------------------- LodePNG uses unsigned char arrays for 16-bit per channel colors too, just like for any other color format. The 16-bit values are stored in big endian (most significant byte first) in these arrays. This is the opposite order of the little endian used by x86 CPU's. LodePNG always uses big endian because the PNG file format does so internally. Conversions to other formats than PNG uses internally are not supported by LodePNG on purpose, there are myriads of formats, including endianness of 16-bit colors, the order in which you store R, G, B and A, and so on. Supporting and converting to/from all that is outside the scope of LodePNG. This may mean that, depending on your use case, you may want to convert the big endian output of LodePNG to little endian with a for loop. This is certainly not always needed, many applications and libraries support big endian 16-bit colors anyway, but it means you cannot simply cast the unsigned char* buffer to an unsigned short* buffer on x86 CPUs. 7. error values --------------- All functions in LodePNG that return an error code, return 0 if everything went OK, or a non-zero code if there was an error. The meaning of the LodePNG error values can be retrieved with the function lodepng_error_text: given the numerical error code, it returns a description of the error in English as a string. Check the implementation of lodepng_error_text to see the meaning of each code. 8. chunks and PNG editing ------------------------- If you want to add extra chunks to a PNG you encode, or use LodePNG for a PNG editor that should follow the rules about handling of unknown chunks, or if your program is able to read other types of chunks than the ones handled by LodePNG, then that's possible with the chunk functions of LodePNG. A PNG chunk has the following layout: 4 bytes length 4 bytes type name length bytes data 4 bytes CRC 8.1. iterating through chunks ----------------------------- If you have a buffer containing the PNG image data, then the first chunk (the IHDR chunk) starts at byte number 8 of that buffer. The first 8 bytes are the signature of the PNG and are not part of a chunk. But if you start at byte 8 then you have a chunk, and can check the following things of it. NOTE: none of these functions check for memory buffer boundaries. To avoid exploits, always make sure the buffer contains all the data of the chunks. When using lodepng_chunk_next, make sure the returned value is within the allocated memory. unsigned lodepng_chunk_length(const unsigned char* chunk): Get the length of the chunk's data. The total chunk length is this length + 12. void lodepng_chunk_type(char type[5], const unsigned char* chunk): unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type): Get the type of the chunk or compare if it's a certain type unsigned char lodepng_chunk_critical(const unsigned char* chunk): unsigned char lodepng_chunk_private(const unsigned char* chunk): unsigned char lodepng_chunk_safetocopy(const unsigned char* chunk): Check if the chunk is critical in the PNG standard (only IHDR, PLTE, IDAT and IEND are). Check if the chunk is private (public chunks are part of the standard, private ones not). Check if the chunk is safe to copy. If it's not, then, when modifying data in a critical chunk, unsafe to copy chunks of the old image may NOT be saved in the new one if your program doesn't handle that type of unknown chunk. unsigned char* lodepng_chunk_data(unsigned char* chunk): const unsigned char* lodepng_chunk_data_const(const unsigned char* chunk): Get a pointer to the start of the data of the chunk. unsigned lodepng_chunk_check_crc(const unsigned char* chunk): void lodepng_chunk_generate_crc(unsigned char* chunk): Check if the crc is correct or generate a correct one. unsigned char* lodepng_chunk_next(unsigned char* chunk): const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk): Iterate to the next chunk. This works if you have a buffer with consecutive chunks. Note that these functions do no boundary checking of the allocated data whatsoever, so make sure there is enough data available in the buffer to be able to go to the next chunk. unsigned lodepng_chunk_append(unsigned char** out, size_t* outlength, const unsigned char* chunk): unsigned lodepng_chunk_create(unsigned char** out, size_t* outlength, unsigned length, const char* type, const unsigned char* data): These functions are used to create new chunks that are appended to the data in *out that has length *outlength. The append function appends an existing chunk to the new data. The create function creates a new chunk with the given parameters and appends it. Type is the 4-letter name of the chunk. 8.2. chunks in info_png ----------------------- The LodePNGInfo struct contains fields with the unknown chunk in it. It has 3 buffers (each with size) to contain 3 types of unknown chunks: the ones that come before the PLTE chunk, the ones that come between the PLTE and the IDAT chunks, and the ones that come after the IDAT chunks. It's necessary to make the distionction between these 3 cases because the PNG standard forces to keep the ordering of unknown chunks compared to the critical chunks, but does not force any other ordering rules. info_png.unknown_chunks_data[0] is the chunks before PLTE info_png.unknown_chunks_data[1] is the chunks after PLTE, before IDAT info_png.unknown_chunks_data[2] is the chunks after IDAT The chunks in these 3 buffers can be iterated through and read by using the same way described in the previous subchapter. When using the decoder to decode a PNG, you can make it store all unknown chunks if you set the option settings.remember_unknown_chunks to 1. By default, this option is off (0). The encoder will always encode unknown chunks that are stored in the info_png. If you need it to add a particular chunk that isn't known by LodePNG, you can use lodepng_chunk_append or lodepng_chunk_create to the chunk data in info_png.unknown_chunks_data[x]. Chunks that are known by LodePNG should not be added in that way. E.g. to make LodePNG add a bKGD chunk, set background_defined to true and add the correct parameters there instead. 9. compiler support ------------------- No libraries other than the current standard C library are needed to compile LodePNG. For the C++ version, only the standard C++ library is needed on top. Add the files lodepng.c(pp) and lodepng.h to your project, include lodepng.h where needed, and your program can read/write PNG files. It is compatible with C90 and up, and C++03 and up. If performance is important, use optimization when compiling! For both the encoder and decoder, this makes a large difference. Make sure that LodePNG is compiled with the same compiler of the same version and with the same settings as the rest of the program, or the interfaces with std::vectors and std::strings in C++ can be incompatible. CHAR_BITS must be 8 or higher, because LodePNG uses unsigned chars for octets. *) gcc and g++ LodePNG is developed in gcc so this compiler is natively supported. It gives no warnings with compiler options "-Wall -Wextra -pedantic -ansi", with gcc and g++ version 4.7.1 on Linux, 32-bit and 64-bit. *) Clang Fully supported and warning-free. *) Mingw The Mingw compiler (a port of gcc for Windows) should be fully supported by LodePNG. *) Visual Studio and Visual C++ Express Edition LodePNG should be warning-free with warning level W4. Two warnings were disabled with pragmas though: warning 4244 about implicit conversions, and warning 4996 where it wants to use a non-standard function fopen_s instead of the standard C fopen. Visual Studio may want "stdafx.h" files to be included in each source file and give an error "unexpected end of file while looking for precompiled header". This is not standard C++ and will not be added to the stock LodePNG. You can disable it for lodepng.cpp only by right clicking it, Properties, C/C++, Precompiled Headers, and set it to Not Using Precompiled Headers there. NOTE: Modern versions of VS should be fully supported, but old versions, e.g. VS6, are not guaranteed to work. *) Compilers on Macintosh LodePNG has been reported to work both with gcc and LLVM for Macintosh, both for C and C++. *) Other Compilers If you encounter problems on any compilers, feel free to let me know and I may try to fix it if the compiler is modern and standards complient. 10. examples ------------ This decoder example shows the most basic usage of LodePNG. More complex examples can be found on the LodePNG website. 10.1. decoder C++ example ------------------------- #include "lodepng.h" #include <iostream> int main(int argc, char *argv[]) { const char* filename = argc > 1 ? argv[1] : "test.png"; //load and decode std::vector<unsigned char> image; unsigned width, height; unsigned error = lodepng::decode(image, width, height, filename); //if there's an error, display it if(error) std::cout << "decoder error " << error << ": " << lodepng_error_text(error) << std::endl; //the pixels are now in the vector "image", 4 bytes per pixel, ordered RGBARGBA..., use it as texture, draw it, ... } 10.2. decoder C example ----------------------- #include "lodepng.h" int main(int argc, char *argv[]) { unsigned error; unsigned char* image; size_t width, height; const char* filename = argc > 1 ? argv[1] : "test.png"; error = lodepng_decode32_file(&image, &width, &height, filename); if(error) printf("decoder error %u: %s\n", error, lodepng_error_text(error)); / * use image here * / free(image); return 0; } 11. state settings reference ---------------------------- A quick reference of some settings to set on the LodePNGState For decoding: state.decoder.zlibsettings.ignore_adler32: ignore ADLER32 checksums state.decoder.zlibsettings.custom_...: use custom inflate function state.decoder.ignore_crc: ignore CRC checksums state.decoder.color_convert: convert internal PNG color to chosen one state.decoder.read_text_chunks: whether to read in text metadata chunks state.decoder.remember_unknown_chunks: whether to read in unknown chunks state.info_raw.colortype: desired color type for decoded image state.info_raw.bitdepth: desired bit depth for decoded image state.info_raw....: more color settings, see struct LodePNGColorMode state.info_png....: no settings for decoder but ouput, see struct LodePNGInfo For encoding: state.encoder.zlibsettings.btype: disable compression by setting it to 0 state.encoder.zlibsettings.use_lz77: use LZ77 in compression state.encoder.zlibsettings.windowsize: tweak LZ77 windowsize state.encoder.zlibsettings.minmatch: tweak min LZ77 length to match state.encoder.zlibsettings.nicematch: tweak LZ77 match where to stop searching state.encoder.zlibsettings.lazymatching: try one more LZ77 matching state.encoder.zlibsettings.custom_...: use custom deflate function state.encoder.auto_convert: choose optimal PNG color type, if 0 uses info_png state.encoder.filter_palette_zero: PNG filter strategy for palette state.encoder.filter_strategy: PNG filter strategy to encode with state.encoder.force_palette: add palette even if not encoding to one state.encoder.add_id: add LodePNG identifier and version as a text chunk state.encoder.text_compression: use compressed text chunks for metadata state.info_raw.colortype: color type of raw input image you provide state.info_raw.bitdepth: bit depth of raw input image you provide state.info_raw: more color settings, see struct LodePNGColorMode state.info_png.color.colortype: desired color type if auto_convert is false state.info_png.color.bitdepth: desired bit depth if auto_convert is false state.info_png.color....: more color settings, see struct LodePNGColorMode state.info_png....: more PNG related settings, see struct LodePNGInfo 12. changes ----------- The version number of LodePNG is the date of the change given in the format yyyymmdd. Some changes aren't backwards compatible. Those are indicated with a (!) symbol. *) 27 nov 2016: grey+alpha auto color model detection bugfix *) 18 apr 2016: Changed qsort to custom stable sort (for platforms w/o qsort). *) 09 apr 2016: Fixed colorkey usage detection, and better file loading (within the limits of pure C90). *) 08 dec 2015: Made load_file function return error if file can't be opened. *) 24 okt 2015: Bugfix with decoding to palette output. *) 18 apr 2015: Boundary PM instead of just package-merge for faster encoding. *) 23 aug 2014: Reduced needless memory usage of decoder. *) 28 jun 2014: Removed fix_png setting, always support palette OOB for simplicity. Made ColorProfile public. *) 09 jun 2014: Faster encoder by fixing hash bug and more zeros optimization. *) 22 dec 2013: Power of two windowsize required for optimization. *) 15 apr 2013: Fixed bug with LAC_ALPHA and color key. *) 25 mar 2013: Added an optional feature to ignore some PNG errors (fix_png). *) 11 mar 2013 (!): Bugfix with custom free. Changed from "my" to "lodepng_" prefix for the custom allocators and made it possible with a new #define to use custom ones in your project without needing to change lodepng's code. *) 28 jan 2013: Bugfix with color key. *) 27 okt 2012: Tweaks in text chunk keyword length error handling. *) 8 okt 2012 (!): Added new filter strategy (entropy) and new auto color mode. (no palette). Better deflate tree encoding. New compression tweak settings. Faster color conversions while decoding. Some internal cleanups. *) 23 sep 2012: Reduced warnings in Visual Studio a little bit. *) 1 sep 2012 (!): Removed #define's for giving custom (de)compression functions and made it work with function pointers instead. *) 23 jun 2012: Added more filter strategies. Made it easier to use custom alloc and free functions and toggle #defines from compiler flags. Small fixes. *) 6 may 2012 (!): Made plugging in custom zlib/deflate functions more flexible. *) 22 apr 2012 (!): Made interface more consistent, renaming a lot. Removed redundant C++ codec classes. Reduced amount of structs. Everything changed, but it is cleaner now imho and functionality remains the same. Also fixed several bugs and shrunk the implementation code. Made new samples. *) 6 nov 2011 (!): By default, the encoder now automatically chooses the best PNG color model and bit depth, based on the amount and type of colors of the raw image. For this, autoLeaveOutAlphaChannel replaced by auto_choose_color. *) 9 okt 2011: simpler hash chain implementation for the encoder. *) 8 sep 2011: lz77 encoder lazy matching instead of greedy matching. *) 23 aug 2011: tweaked the zlib compression parameters after benchmarking. A bug with the PNG filtertype heuristic was fixed, so that it chooses much better ones (it's quite significant). A setting to do an experimental, slow, brute force search for PNG filter types is added. *) 17 aug 2011 (!): changed some C zlib related function names. *) 16 aug 2011: made the code less wide (max 120 characters per line). *) 17 apr 2011: code cleanup. Bugfixes. Convert low to 16-bit per sample colors. *) 21 feb 2011: fixed compiling for C90. Fixed compiling with sections disabled. *) 11 dec 2010: encoding is made faster, based on suggestion by Peter Eastman to optimize long sequences of zeros. *) 13 nov 2010: added LodePNG_InfoColor_hasPaletteAlpha and LodePNG_InfoColor_canHaveAlpha functions for convenience. *) 7 nov 2010: added LodePNG_error_text function to get error code description. *) 30 okt 2010: made decoding slightly faster *) 26 okt 2010: (!) changed some C function and struct names (more consistent). Reorganized the documentation and the declaration order in the header. *) 08 aug 2010: only changed some comments and external samples. *) 05 jul 2010: fixed bug thanks to warnings in the new gcc version. *) 14 mar 2010: fixed bug where too much memory was allocated for char buffers. *) 02 sep 2008: fixed bug where it could create empty tree that linux apps could read by ignoring the problem but windows apps couldn't. *) 06 jun 2008: added more error checks for out of memory cases. *) 26 apr 2008: added a few more checks here and there to ensure more safety. *) 06 mar 2008: crash with encoding of strings fixed *) 02 feb 2008: support for international text chunks added (iTXt) *) 23 jan 2008: small cleanups, and #defines to divide code in sections *) 20 jan 2008: support for unknown chunks allowing using LodePNG for an editor. *) 18 jan 2008: support for tIME and pHYs chunks added to encoder and decoder. *) 17 jan 2008: ability to encode and decode compressed zTXt chunks added Also various fixes, such as in the deflate and the padding bits code. *) 13 jan 2008: Added ability to encode Adam7-interlaced images. Improved filtering code of encoder. *) 07 jan 2008: (!) changed LodePNG to use ISO C90 instead of C++. A C++ wrapper around this provides an interface almost identical to before. Having LodePNG be pure ISO C90 makes it more portable. The C and C++ code are together in these files but it works both for C and C++ compilers. *) 29 dec 2007: (!) changed most integer types to unsigned int + other tweaks *) 30 aug 2007: bug fixed which makes this Borland C++ compatible *) 09 aug 2007: some VS2005 warnings removed again *) 21 jul 2007: deflate code placed in new namespace separate from zlib code *) 08 jun 2007: fixed bug with 2- and 4-bit color, and small interlaced images *) 04 jun 2007: improved support for Visual Studio 2005: crash with accessing invalid std::vector element [0] fixed, and level 3 and 4 warnings removed *) 02 jun 2007: made the encoder add a tag with version by default *) 27 may 2007: zlib and png code separated (but still in the same file), simple encoder/decoder functions added for more simple usage cases *) 19 may 2007: minor fixes, some code cleaning, new error added (error 69), moved some examples from here to lodepng_examples.cpp *) 12 may 2007: palette decoding bug fixed *) 24 apr 2007: changed the license from BSD to the zlib license *) 11 mar 2007: very simple addition: ability to encode bKGD chunks. *) 04 mar 2007: (!) tEXt chunk related fixes, and support for encoding palettized PNG images. Plus little interface change with palette and texts. *) 03 mar 2007: Made it encode dynamic Huffman shorter with repeat codes. Fixed a bug where the end code of a block had length 0 in the Huffman tree. *) 26 feb 2007: Huffman compression with dynamic trees (BTYPE 2) now implemented and supported by the encoder, resulting in smaller PNGs at the output. *) 27 jan 2007: Made the Adler-32 test faster so that a timewaste is gone. *) 24 jan 2007: gave encoder an error interface. Added color conversion from any greyscale type to 8-bit greyscale with or without alpha. *) 21 jan 2007: (!) Totally changed the interface. It allows more color types to convert to and is more uniform. See the manual for how it works now. *) 07 jan 2007: Some cleanup & fixes, and a few changes over the last days: encode/decode custom tEXt chunks, separate classes for zlib & deflate, and at last made the decoder give errors for incorrect Adler32 or Crc. *) 01 jan 2007: Fixed bug with encoding PNGs with less than 8 bits per channel. *) 29 dec 2006: Added support for encoding images without alpha channel, and cleaned out code as well as making certain parts faster. *) 28 dec 2006: Added "Settings" to the encoder. *) 26 dec 2006: The encoder now does LZ77 encoding and produces much smaller files now. Removed some code duplication in the decoder. Fixed little bug in an example. *) 09 dec 2006: (!) Placed output parameters of public functions as first parameter. Fixed a bug of the decoder with 16-bit per color. *) 15 okt 2006: Changed documentation structure *) 09 okt 2006: Encoder class added. It encodes a valid PNG image from the given image buffer, however for now it's not compressed. *) 08 sep 2006: (!) Changed to interface with a Decoder class *) 30 jul 2006: (!) LodePNG_InfoPng , width and height are now retrieved in different way. Renamed decodePNG to decodePNGGeneric. *) 29 jul 2006: (!) Changed the interface: image info is now returned as a struct of type LodePNG::LodePNG_Info, instead of a vector, which was a bit clumsy. *) 28 jul 2006: Cleaned the code and added new error checks. Corrected terminology "deflate" into "inflate". *) 23 jun 2006: Added SDL example in the documentation in the header, this example allows easy debugging by displaying the PNG and its transparency. *) 22 jun 2006: (!) Changed way to obtain error value. Added loadFile function for convenience. Made decodePNG32 faster. *) 21 jun 2006: (!) Changed type of info vector to unsigned. Changed position of palette in info vector. Fixed an important bug that happened on PNGs with an uncompressed block. *) 16 jun 2006: Internally changed unsigned into unsigned where needed, and performed some optimizations. *) 07 jun 2006: (!) Renamed functions to decodePNG and placed them in LodePNG namespace. Changed the order of the parameters. Rewrote the documentation in the header. Renamed files to lodepng.cpp and lodepng.h *) 22 apr 2006: Optimized and improved some code *) 07 sep 2005: (!) Changed to std::vector interface *) 12 aug 2005: Initial release (C++, decoder only) 13. contact information ----------------------- Feel free to contact me with suggestions, problems, comments, ... concerning LodePNG. If you encounter a PNG image that doesn't work properly with this decoder, feel free to send it and I'll use it to find and fix the problem. My email address is (puzzle the account and domain together with an @ symbol): Domain: gmail dot com. Account: lode dot vandevenne. Copyright (c) 2005-2016 Lode Vandevenne */ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/libeg/screen.c������������������������������������������������������������������������0000664�0001750�0001750�00000053436�13141071360�016026� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * libeg/screen.c * Screen handling functions * * Copyright (c) 2006 Christoph Pfisterer * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * * Neither the name of Christoph Pfisterer nor the names of the * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Modifications copyright (c) 2012-2014 Roderick W. Smith * * Modifications distributed under the terms of the GNU General Public * License (GPL) version 3 (GPLv3), or (at your option) any later version. * */ /* * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "libegint.h" #include "../refind/screen.h" #include "../refind/lib.h" #include "../refind/mystrings.h" #include "../include/refit_call_wrapper.h" #include "libeg.h" #include "../include/Handle.h" #include <efiUgaDraw.h> #include <efiConsoleControl.h> #ifndef __MAKEWITH_GNUEFI #define LibLocateProtocol EfiLibLocateProtocol #endif // Console defines and variables static EFI_GUID ConsoleControlProtocolGuid = EFI_CONSOLE_CONTROL_PROTOCOL_GUID; static EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL; static EFI_GUID UgaDrawProtocolGuid = EFI_UGA_DRAW_PROTOCOL_GUID; static EFI_UGA_DRAW_PROTOCOL *UgaDraw = NULL; static EFI_GUID GraphicsOutputProtocolGuid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; static EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput = NULL; static BOOLEAN egHasGraphics = FALSE; static UINTN egScreenWidth = 800; static UINTN egScreenHeight = 600; // // Screen handling // // Make the necessary system calls to identify the current graphics mode. // Stores the results in the file-global variables egScreenWidth, // egScreenHeight, and egHasGraphics. The first two of these will be // unchanged if neither GraphicsOutput nor UgaDraw is a valid pointer. static VOID egDetermineScreenSize(VOID) { EFI_STATUS Status = EFI_SUCCESS; UINT32 UGAWidth, UGAHeight, UGADepth, UGARefreshRate; // get screen size egHasGraphics = FALSE; if (GraphicsOutput != NULL) { egScreenWidth = GraphicsOutput->Mode->Info->HorizontalResolution; egScreenHeight = GraphicsOutput->Mode->Info->VerticalResolution; egHasGraphics = TRUE; } else if (UgaDraw != NULL) { Status = refit_call5_wrapper(UgaDraw->GetMode, UgaDraw, &UGAWidth, &UGAHeight, &UGADepth, &UGARefreshRate); if (EFI_ERROR(Status)) { UgaDraw = NULL; // graphics not available } else { egScreenWidth = UGAWidth; egScreenHeight = UGAHeight; egHasGraphics = TRUE; } } } // static VOID egDetermineScreenSize() VOID egGetScreenSize(OUT UINTN *ScreenWidth, OUT UINTN *ScreenHeight) { egDetermineScreenSize(); if (ScreenWidth != NULL) *ScreenWidth = egScreenWidth; if (ScreenHeight != NULL) *ScreenHeight = egScreenHeight; } VOID egInitScreen(VOID) { EFI_STATUS Status = EFI_SUCCESS; // get protocols Status = LibLocateProtocol(&ConsoleControlProtocolGuid, (VOID **) &ConsoleControl); if (EFI_ERROR(Status)) ConsoleControl = NULL; Status = LibLocateProtocol(&UgaDrawProtocolGuid, (VOID **) &UgaDraw); if (EFI_ERROR(Status)) UgaDraw = NULL; Status = LibLocateProtocol(&GraphicsOutputProtocolGuid, (VOID **) &GraphicsOutput); if (EFI_ERROR(Status)) GraphicsOutput = NULL; egDetermineScreenSize(); } // Convert a graphics mode (in *ModeWidth) to a width and height (returned in // *ModeWidth and *Height, respectively). // Returns TRUE if successful, FALSE if not (invalid mode, typically) BOOLEAN egGetResFromMode(UINTN *ModeWidth, UINTN *Height) { UINTN Size; EFI_STATUS Status; EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info = NULL; if ((ModeWidth != NULL) && (Height != NULL)) { Status = refit_call4_wrapper(GraphicsOutput->QueryMode, GraphicsOutput, *ModeWidth, &Size, &Info); if ((Status == EFI_SUCCESS) && (Info != NULL)) { *ModeWidth = Info->HorizontalResolution; *Height = Info->VerticalResolution; return TRUE; } } return FALSE; } // BOOLEAN egGetResFromMode() // Sets the screen resolution to the specified value, if possible. If *ScreenHeight // is 0 and GOP mode is detected, assume that *ScreenWidth contains a GOP mode // number rather than a horizontal resolution. If the specified resolution is not // valid, displays a warning with the valid modes on GOP (UEFI) systems, or silently // fails on UGA (EFI 1.x) systems. Note that this function attempts to set ANY screen // resolution, even 0x0 or ridiculously large values. // Upon success, returns actual screen resolution in *ScreenWidth and *ScreenHeight. // These values are unchanged upon failure. // Returns TRUE if successful, FALSE if not. BOOLEAN egSetScreenSize(IN OUT UINTN *ScreenWidth, IN OUT UINTN *ScreenHeight) { EFI_STATUS Status = EFI_SUCCESS; EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info; UINTN Size; UINT32 ModeNum = 0, CurrentModeNum; UINT32 UGAWidth, UGAHeight, UGADepth, UGARefreshRate; BOOLEAN ModeSet = FALSE; if ((ScreenWidth == NULL) || (ScreenHeight == NULL)) return FALSE; if (GraphicsOutput != NULL) { // GOP mode (UEFI) CurrentModeNum = GraphicsOutput->Mode->Mode; if (*ScreenHeight == 0) { // User specified a mode number (stored in *ScreenWidth); use it directly ModeNum = (UINT32) *ScreenWidth; if (ModeNum != CurrentModeNum) { ModeSet = TRUE; } else if (egGetResFromMode(ScreenWidth, ScreenHeight) && (refit_call2_wrapper(GraphicsOutput->SetMode, GraphicsOutput, ModeNum) == EFI_SUCCESS)) { ModeSet = TRUE; } // User specified width & height; must find mode... } else { // Do a loop through the modes to see if the specified one is available; // and if so, switch to it.... do { Status = refit_call4_wrapper(GraphicsOutput->QueryMode, GraphicsOutput, ModeNum, &Size, &Info); if ((Status == EFI_SUCCESS) && (Size >= sizeof(*Info) && (Info != NULL)) && (Info->HorizontalResolution == *ScreenWidth) && (Info->VerticalResolution == *ScreenHeight) && ((ModeNum == CurrentModeNum) || (refit_call2_wrapper(GraphicsOutput->SetMode, GraphicsOutput, ModeNum) == EFI_SUCCESS))) { ModeSet = TRUE; } // if } while ((++ModeNum < GraphicsOutput->Mode->MaxMode) && !ModeSet); } // if/else if (ModeSet) { egScreenWidth = *ScreenWidth; egScreenHeight = *ScreenHeight; } else {// If unsuccessful, display an error message for the user.... SwitchToText(FALSE); Print(L"Error setting graphics mode %d x %d; using default mode!\nAvailable modes are:\n", *ScreenWidth, *ScreenHeight); ModeNum = 0; do { Status = refit_call4_wrapper(GraphicsOutput->QueryMode, GraphicsOutput, ModeNum, &Size, &Info); if ((Status == EFI_SUCCESS) && (Info != NULL)) { Print(L"Mode %d: %d x %d\n", ModeNum, Info->HorizontalResolution, Info->VerticalResolution); if (ModeNum == CurrentModeNum) { egScreenWidth = Info->HorizontalResolution; egScreenHeight = Info->VerticalResolution; } // if } // else } while (++ModeNum < GraphicsOutput->Mode->MaxMode); PauseForKey(); SwitchToGraphics(); } // if GOP mode (UEFI) } else if (UgaDraw != NULL) { // UGA mode (EFI 1.x) // Try to use current color depth & refresh rate for new mode. Maybe not the best choice // in all cases, but I don't know how to probe for alternatives.... Status = refit_call5_wrapper(UgaDraw->GetMode, UgaDraw, &UGAWidth, &UGAHeight, &UGADepth, &UGARefreshRate); Status = refit_call5_wrapper(UgaDraw->SetMode, UgaDraw, *ScreenWidth, *ScreenHeight, UGADepth, UGARefreshRate); if (Status == EFI_SUCCESS) { egScreenWidth = *ScreenWidth; egScreenHeight = *ScreenHeight; ModeSet = TRUE; } else { // TODO: Find a list of supported modes and display it. // NOTE: Below doesn't actually appear unless we explicitly switch to text mode. // This is just a placeholder until something better can be done.... Print(L"Error setting graphics mode %d x %d; unsupported mode!\n"); } // if/else } // if/else if UGA mode (EFI 1.x) return (ModeSet); } // BOOLEAN egSetScreenSize() // Set a text mode. // Returns TRUE if the mode actually changed, FALSE otherwise. // Note that a FALSE return value can mean either an error or no change // necessary. BOOLEAN egSetTextMode(UINT32 RequestedMode) { UINTN i = 0, Width, Height; EFI_STATUS Status; BOOLEAN ChangedIt = FALSE; if ((RequestedMode != DONT_CHANGE_TEXT_MODE) && (RequestedMode != ST->ConOut->Mode->Mode)) { Status = refit_call2_wrapper(ST->ConOut->SetMode, ST->ConOut, RequestedMode); if (Status == EFI_SUCCESS) { ChangedIt = TRUE; } else { SwitchToText(FALSE); Print(L"\nError setting text mode %d; available modes are:\n", RequestedMode); do { Status = refit_call4_wrapper(ST->ConOut->QueryMode, ST->ConOut, i, &Width, &Height); if (Status == EFI_SUCCESS) Print(L"Mode %d: %d x %d\n", i, Width, Height); } while (++i < ST->ConOut->Mode->MaxMode); Print(L"Mode %d: Use default mode\n", DONT_CHANGE_TEXT_MODE); PauseForKey(); SwitchToGraphics(); } // if/else successful change } // if need to change mode return ChangedIt; } // BOOLEAN egSetTextMode() CHAR16 * egScreenDescription(VOID) { CHAR16 *GraphicsInfo, *TextInfo = NULL; GraphicsInfo = AllocateZeroPool(256 * sizeof(CHAR16)); if (GraphicsInfo == NULL) return L"memory allocation error"; if (egHasGraphics) { if (GraphicsOutput != NULL) { SPrint(GraphicsInfo, 255, L"Graphics Output (UEFI), %dx%d", egScreenWidth, egScreenHeight); } else if (UgaDraw != NULL) { GraphicsInfo = AllocateZeroPool(256 * sizeof(CHAR16)); SPrint(GraphicsInfo, 255, L"UGA Draw (EFI 1.10), %dx%d", egScreenWidth, egScreenHeight); } else { MyFreePool(GraphicsInfo); MyFreePool(TextInfo); return L"Internal Error"; } if (!AllowGraphicsMode) { // graphics-capable HW, but in text mode TextInfo = AllocateZeroPool(256 * sizeof(CHAR16)); SPrint(TextInfo, 255, L"(in %dx%d text mode)", ConWidth, ConHeight); MergeStrings(&GraphicsInfo, TextInfo, L' '); } } else { SPrint(GraphicsInfo, 255, L"Text-foo console, %dx%d", ConWidth, ConHeight); } MyFreePool(TextInfo); return GraphicsInfo; } BOOLEAN egHasGraphicsMode(VOID) { return egHasGraphics; } BOOLEAN egIsGraphicsModeEnabled(VOID) { EFI_CONSOLE_CONTROL_SCREEN_MODE CurrentMode; if (ConsoleControl != NULL) { refit_call4_wrapper(ConsoleControl->GetMode, ConsoleControl, &CurrentMode, NULL, NULL); return (CurrentMode == EfiConsoleControlScreenGraphics) ? TRUE : FALSE; } return FALSE; } VOID egSetGraphicsModeEnabled(IN BOOLEAN Enable) { EFI_CONSOLE_CONTROL_SCREEN_MODE CurrentMode; EFI_CONSOLE_CONTROL_SCREEN_MODE NewMode; if (ConsoleControl != NULL) { refit_call4_wrapper(ConsoleControl->GetMode, ConsoleControl, &CurrentMode, NULL, NULL); NewMode = Enable ? EfiConsoleControlScreenGraphics : EfiConsoleControlScreenText; if (CurrentMode != NewMode) refit_call2_wrapper(ConsoleControl->SetMode, ConsoleControl, NewMode); } } // // Drawing to the screen // VOID egClearScreen(IN EG_PIXEL *Color) { EFI_UGA_PIXEL FillColor; if (!egHasGraphics) return; if (Color != NULL) { FillColor.Red = Color->r; FillColor.Green = Color->g; FillColor.Blue = Color->b; } else { FillColor.Red = 0x0; FillColor.Green = 0x0; FillColor.Blue = 0x0; } FillColor.Reserved = 0; if (GraphicsOutput != NULL) { // EFI_GRAPHICS_OUTPUT_BLT_PIXEL and EFI_UGA_PIXEL have the same // layout, and the header from TianoCore actually defines them // to be the same type. refit_call10_wrapper(GraphicsOutput->Blt, GraphicsOutput, (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)&FillColor, EfiBltVideoFill, 0, 0, 0, 0, egScreenWidth, egScreenHeight, 0); } else if (UgaDraw != NULL) { refit_call10_wrapper(UgaDraw->Blt, UgaDraw, &FillColor, EfiUgaVideoFill, 0, 0, 0, 0, egScreenWidth, egScreenHeight, 0); } } VOID egDrawImage(IN EG_IMAGE *Image, IN UINTN ScreenPosX, IN UINTN ScreenPosY) { EG_IMAGE *CompImage = NULL; // NOTE: Weird seemingly redundant tests because some placement code can "wrap around" and // send "negative" values, which of course become very large unsigned ints that can then // wrap around AGAIN if values are added to them..... if (!egHasGraphics || ((ScreenPosX + Image->Width) > egScreenWidth) || ((ScreenPosY + Image->Height) > egScreenHeight) || (ScreenPosX > egScreenWidth) || (ScreenPosY > egScreenHeight)) return; if ((GlobalConfig.ScreenBackground == NULL) || ((Image->Width == egScreenWidth) && (Image->Height == egScreenHeight))) { CompImage = Image; } else if (GlobalConfig.ScreenBackground == Image) { CompImage = GlobalConfig.ScreenBackground; } else { CompImage = egCropImage(GlobalConfig.ScreenBackground, ScreenPosX, ScreenPosY, Image->Width, Image->Height); if (CompImage == NULL) { Print(L"Error! Can't crop image in egDrawImage()!\n"); return; } egComposeImage(CompImage, Image, 0, 0); } if (GraphicsOutput != NULL) { refit_call10_wrapper(GraphicsOutput->Blt, GraphicsOutput, (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)CompImage->PixelData, EfiBltBufferToVideo, 0, 0, ScreenPosX, ScreenPosY, CompImage->Width, CompImage->Height, 0); } else if (UgaDraw != NULL) { refit_call10_wrapper(UgaDraw->Blt, UgaDraw, (EFI_UGA_PIXEL *)CompImage->PixelData, EfiUgaBltBufferToVideo, 0, 0, ScreenPosX, ScreenPosY, CompImage->Width, CompImage->Height, 0); } if ((CompImage != GlobalConfig.ScreenBackground) && (CompImage != Image)) egFreeImage(CompImage); } /* VOID egDrawImage() */ // Display an unselected icon on the screen, so that the background image shows // through the transparency areas. The BadgeImage may be NULL, in which case // it's not composited in. VOID egDrawImageWithTransparency(EG_IMAGE *Image, EG_IMAGE *BadgeImage, UINTN XPos, UINTN YPos, UINTN Width, UINTN Height) { EG_IMAGE *Background; Background = egCropImage(GlobalConfig.ScreenBackground, XPos, YPos, Width, Height); if (Background != NULL) { BltImageCompositeBadge(Background, Image, BadgeImage, XPos, YPos); egFreeImage(Background); } } // VOID DrawImageWithTransparency() VOID egDrawImageArea(IN EG_IMAGE *Image, IN UINTN AreaPosX, IN UINTN AreaPosY, IN UINTN AreaWidth, IN UINTN AreaHeight, IN UINTN ScreenPosX, IN UINTN ScreenPosY) { if (!egHasGraphics) return; egRestrictImageArea(Image, AreaPosX, AreaPosY, &AreaWidth, &AreaHeight); if (AreaWidth == 0) return; if (GraphicsOutput != NULL) { refit_call10_wrapper(GraphicsOutput->Blt, GraphicsOutput, (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)Image->PixelData, EfiBltBufferToVideo, AreaPosX, AreaPosY, ScreenPosX, ScreenPosY, AreaWidth, AreaHeight, Image->Width * 4); } else if (UgaDraw != NULL) { refit_call10_wrapper(UgaDraw->Blt, UgaDraw, (EFI_UGA_PIXEL *)Image->PixelData, EfiUgaBltBufferToVideo, AreaPosX, AreaPosY, ScreenPosX, ScreenPosY, AreaWidth, AreaHeight, Image->Width * 4); } } // Display a message in the center of the screen, surrounded by a box of the // specified color. For the moment, uses graphics calls only. (It still works // in text mode on GOP/UEFI systems, but not on UGA/EFI 1.x systems.) VOID egDisplayMessage(IN CHAR16 *Text, EG_PIXEL *BGColor, UINTN PositionCode) { UINTN BoxWidth, BoxHeight; static UINTN Position = 1; EG_IMAGE *Box; if ((Text != NULL) && (BGColor != NULL)) { egMeasureText(Text, &BoxWidth, &BoxHeight); BoxWidth += 14; BoxHeight *= 2; if (BoxWidth > egScreenWidth) BoxWidth = egScreenWidth; Box = egCreateFilledImage(BoxWidth, BoxHeight, FALSE, BGColor); egRenderText(Text, Box, 7, BoxHeight / 4, (BGColor->r + BGColor->g + BGColor->b) / 3); switch (PositionCode) { case CENTER: Position = (egScreenHeight - BoxHeight) / 2; break; case BOTTOM: Position = egScreenHeight - (BoxHeight * 2); break; case TOP: Position = 1; break; default: // NEXTLINE Position += BoxHeight + (BoxHeight / 10); break; } // switch() egDrawImage(Box, (egScreenWidth - BoxWidth) / 2, Position); if ((PositionCode == CENTER) || (Position >= egScreenHeight - (BoxHeight * 5))) Position = 1; } // if non-NULL inputs } // VOID egDisplayMessage() // Copy the current contents of the display into an EG_IMAGE.... // Returns pointer if successful, NULL if not. EG_IMAGE * egCopyScreen(VOID) { return egCopyScreenArea(0, 0, egScreenWidth, egScreenHeight); } // EG_IMAGE * egCopyScreen() // Copy the current contents of the specified display area into an EG_IMAGE.... // Returns pointer if successful, NULL if not. EG_IMAGE * egCopyScreenArea(UINTN XPos, UINTN YPos, UINTN Width, UINTN Height) { EG_IMAGE *Image = NULL; if (!egHasGraphics) return NULL; // allocate a buffer for the screen area Image = egCreateImage(Width, Height, FALSE); if (Image == NULL) { return NULL; } // get full screen image if (GraphicsOutput != NULL) { refit_call10_wrapper(GraphicsOutput->Blt, GraphicsOutput, (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)Image->PixelData, EfiBltVideoToBltBuffer, XPos, YPos, 0, 0, Image->Width, Image->Height, 0); } else if (UgaDraw != NULL) { refit_call10_wrapper(UgaDraw->Blt, UgaDraw, (EFI_UGA_PIXEL *)Image->PixelData, EfiUgaVideoToBltBuffer, XPos, YPos, 0, 0, Image->Width, Image->Height, 0); } return Image; } // EG_IMAGE * egCopyScreenArea() // // Make a screenshot // VOID egScreenShot(VOID) { EFI_STATUS Status; EG_IMAGE *Image; UINT8 *FileData; UINTN FileDataLength; UINTN Index; UINTN ssNum; CHAR16 Filename[80]; EFI_FILE* BaseDir; Image = egCopyScreen(); if (Image == NULL) { Print(L"Error: Unable to take screen shot\n"); goto bailout_wait; } // encode as BMP egEncodeBMP(Image, &FileData, &FileDataLength); egFreeImage(Image); if (FileData == NULL) { Print(L"Error egEncodeBMP returned NULL\n"); goto bailout_wait; } Status = egFindESP(&BaseDir); if (EFI_ERROR(Status)) return; // Search for existing screen shot files; increment number to an unused value... ssNum = 001; do { SPrint(Filename, 80, L"screenshot_%03d.bmp", ssNum++); } while (FileExists(BaseDir, Filename)); // save to file on the ESP Status = egSaveFile(BaseDir, Filename, FileData, FileDataLength); FreePool(FileData); if (CheckError(Status, L"in egSaveFile()")) { goto bailout_wait; } return; // DEBUG: switch to text mode bailout_wait: egSetGraphicsModeEnabled(FALSE); refit_call3_wrapper(BS->WaitForEvent, 1, &ST->ConIn->WaitForKey, &Index); } /* EOF */ ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/libeg/load_bmp.c����������������������������������������������������������������������0000664�0001750�0001750�00000022315�12626644770�016336� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * libeg/load_bmp.c * Loading function for BMP images * * Copyright (c) 2006 Christoph Pfisterer * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * * Neither the name of Christoph Pfisterer nor the names of the * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "libegint.h" // BMP structures #ifdef __MAKEWITH_GNUEFI #pragma pack(1) typedef struct { UINT8 Blue; UINT8 Green; UINT8 Red; UINT8 Reserved; } BMP_COLOR_MAP; typedef struct { CHAR8 CharB; CHAR8 CharM; UINT32 Size; UINT16 Reserved[2]; UINT32 ImageOffset; UINT32 HeaderSize; UINT32 PixelWidth; UINT32 PixelHeight; UINT16 Planes; // Must be 1 UINT16 BitPerPixel; // 1, 4, 8, or 24 UINT32 CompressionType; UINT32 ImageSize; // Compressed image size in bytes UINT32 XPixelsPerMeter; UINT32 YPixelsPerMeter; UINT32 NumberOfColors; UINT32 ImportantColors; } BMP_IMAGE_HEADER; #pragma pack() #endif // // Load BMP image // EG_IMAGE * egDecodeBMP(IN UINT8 *FileData, IN UINTN FileDataLength, IN UINTN IconSize, IN BOOLEAN WantAlpha) { EG_IMAGE *NewImage; BMP_IMAGE_HEADER *BmpHeader; BMP_COLOR_MAP *BmpColorMap; UINTN x, y; UINT8 *ImagePtr; UINT8 *ImagePtrBase; UINTN ImageLineOffset; UINT8 ImageValue = 0, AlphaValue; EG_PIXEL *PixelPtr; UINTN Index, BitIndex; // read and check header if (FileDataLength < sizeof(BMP_IMAGE_HEADER) || FileData == NULL) return NULL; BmpHeader = (BMP_IMAGE_HEADER *) FileData; if (BmpHeader->CharB != 'B' || BmpHeader->CharM != 'M') return NULL; if (BmpHeader->CompressionType != 0) return NULL; if (BmpHeader->BitPerPixel != 1 && BmpHeader->BitPerPixel != 4 && BmpHeader->BitPerPixel != 8 && BmpHeader->BitPerPixel != 24) return NULL; // calculate parameters ImageLineOffset = BmpHeader->PixelWidth; if (BmpHeader->BitPerPixel == 24) ImageLineOffset *= 3; else if (BmpHeader->BitPerPixel == 1) ImageLineOffset = (ImageLineOffset + 7) >> 3; else if (BmpHeader->BitPerPixel == 4) ImageLineOffset = (ImageLineOffset + 1) >> 1; if ((ImageLineOffset % 4) != 0) ImageLineOffset = ImageLineOffset + (4 - (ImageLineOffset % 4)); // check bounds if (BmpHeader->ImageOffset + ImageLineOffset * BmpHeader->PixelHeight > FileDataLength) return NULL; // allocate image structure and buffer NewImage = egCreateImage(BmpHeader->PixelWidth, BmpHeader->PixelHeight, WantAlpha); if (NewImage == NULL) return NULL; AlphaValue = WantAlpha ? 255 : 0; // convert image BmpColorMap = (BMP_COLOR_MAP *)(FileData + sizeof(BMP_IMAGE_HEADER)); ImagePtrBase = FileData + BmpHeader->ImageOffset; for (y = 0; y < BmpHeader->PixelHeight; y++) { ImagePtr = ImagePtrBase; ImagePtrBase += ImageLineOffset; PixelPtr = NewImage->PixelData + (BmpHeader->PixelHeight - 1 - y) * BmpHeader->PixelWidth; switch (BmpHeader->BitPerPixel) { case 1: for (x = 0; x < BmpHeader->PixelWidth; x++) { BitIndex = x & 0x07; if (BitIndex == 0) ImageValue = *ImagePtr++; Index = (ImageValue >> (7 - BitIndex)) & 0x01; PixelPtr->b = BmpColorMap[Index].Blue; PixelPtr->g = BmpColorMap[Index].Green; PixelPtr->r = BmpColorMap[Index].Red; PixelPtr->a = AlphaValue; PixelPtr++; } break; case 4: for (x = 0; x <= BmpHeader->PixelWidth - 2; x += 2) { ImageValue = *ImagePtr++; Index = ImageValue >> 4; PixelPtr->b = BmpColorMap[Index].Blue; PixelPtr->g = BmpColorMap[Index].Green; PixelPtr->r = BmpColorMap[Index].Red; PixelPtr->a = AlphaValue; PixelPtr++; Index = ImageValue & 0x0f; PixelPtr->b = BmpColorMap[Index].Blue; PixelPtr->g = BmpColorMap[Index].Green; PixelPtr->r = BmpColorMap[Index].Red; PixelPtr->a = AlphaValue; PixelPtr++; } if (x < BmpHeader->PixelWidth) { ImageValue = *ImagePtr++; Index = ImageValue >> 4; PixelPtr->b = BmpColorMap[Index].Blue; PixelPtr->g = BmpColorMap[Index].Green; PixelPtr->r = BmpColorMap[Index].Red; PixelPtr->a = AlphaValue; PixelPtr++; } break; case 8: for (x = 0; x < BmpHeader->PixelWidth; x++) { Index = *ImagePtr++; PixelPtr->b = BmpColorMap[Index].Blue; PixelPtr->g = BmpColorMap[Index].Green; PixelPtr->r = BmpColorMap[Index].Red; PixelPtr->a = AlphaValue; PixelPtr++; } break; case 24: for (x = 0; x < BmpHeader->PixelWidth; x++) { PixelPtr->b = *ImagePtr++; PixelPtr->g = *ImagePtr++; PixelPtr->r = *ImagePtr++; PixelPtr->a = AlphaValue; PixelPtr++; } break; } } return NewImage; } // // Save BMP image // VOID egEncodeBMP(IN EG_IMAGE *Image, OUT UINT8 **FileDataReturn, OUT UINTN *FileDataLengthReturn) { BMP_IMAGE_HEADER *BmpHeader; UINT8 *FileData; UINTN FileDataLength; UINT8 *ImagePtr; UINT8 *ImagePtrBase; UINTN ImageLineOffset; EG_PIXEL *PixelPtr; UINTN x, y; ImageLineOffset = Image->Width * 3; if ((ImageLineOffset % 4) != 0) ImageLineOffset = ImageLineOffset + (4 - (ImageLineOffset % 4)); // allocate buffer for file data FileDataLength = sizeof(BMP_IMAGE_HEADER) + Image->Height * ImageLineOffset; FileData = AllocateZeroPool(FileDataLength); if (FileData == NULL) { Print(L"Error allocate %d bytes\n", FileDataLength); *FileDataReturn = NULL; *FileDataLengthReturn = 0; return; } // fill header BmpHeader = (BMP_IMAGE_HEADER *)FileData; BmpHeader->CharB = 'B'; BmpHeader->CharM = 'M'; BmpHeader->Size = FileDataLength; BmpHeader->ImageOffset = sizeof(BMP_IMAGE_HEADER); BmpHeader->HeaderSize = 40; BmpHeader->PixelWidth = Image->Width; BmpHeader->PixelHeight = Image->Height; BmpHeader->Planes = 1; BmpHeader->BitPerPixel = 24; BmpHeader->CompressionType = 0; BmpHeader->XPixelsPerMeter = 0xb13; BmpHeader->YPixelsPerMeter = 0xb13; // fill pixel buffer ImagePtrBase = FileData + BmpHeader->ImageOffset; for (y = 0; y < Image->Height; y++) { ImagePtr = ImagePtrBase; ImagePtrBase += ImageLineOffset; PixelPtr = Image->PixelData + (Image->Height - 1 - y) * Image->Width; for (x = 0; x < Image->Width; x++) { *ImagePtr++ = PixelPtr->b; *ImagePtr++ = PixelPtr->g; *ImagePtr++ = PixelPtr->r; PixelPtr++; } } *FileDataReturn = FileData; *FileDataLengthReturn = FileDataLength; } /* EOF */ �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/libeg/efiUgaDraw.h��������������������������������������������������������������������0000664�0001750�0001750�00000016074�12626644770�016611� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*++ Copyright (c) 2004, Intel Corporation All rights reserved. This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. Module Name: UgaDraw.h Abstract: UGA Draw protocol from the EFI 1.1 specification. Abstraction of a very simple graphics device. --*/ #ifndef __UGA_DRAW_H__ #define __UGA_DRAW_H__ #define EFI_UGA_DRAW_PROTOCOL_GUID \ { \ 0x982c298b, 0xf4fa, 0x41cb, { 0xb8, 0x38, 0x77, 0xaa, 0x68, 0x8f, 0xb8, 0x39 } \ } /* typedef struct _EFI_UGA_DRAW_PROTOCOL EFI_UGA_DRAW_PROTOCOL; */ struct _EFI_UGA_DRAW_PROTOCOL; typedef EFI_STATUS (EFIAPI *EFI_UGA_DRAW_PROTOCOL_GET_MODE) ( IN struct _EFI_UGA_DRAW_PROTOCOL * This, OUT UINT32 *HorizontalResolution, OUT UINT32 *VerticalResolution, OUT UINT32 *ColorDepth, OUT UINT32 *RefreshRate ) /*++ Routine Description: Return the current video mode information. Arguments: This - Protocol instance pointer. HorizontalResolution - Current video horizontal resolution in pixels VerticalResolution - Current video vertical resolution in pixels ColorDepth - Current video color depth in bits per pixel RefreshRate - Current video refresh rate in Hz. Returns: EFI_SUCCESS - Mode information returned. EFI_NOT_STARTED - Video display is not initialized. Call SetMode () EFI_INVALID_PARAMETER - One of the input args was NULL. --*/ ; typedef EFI_STATUS (EFIAPI *EFI_UGA_DRAW_PROTOCOL_SET_MODE) ( IN struct _EFI_UGA_DRAW_PROTOCOL * This, IN UINT32 HorizontalResolution, IN UINT32 VerticalResolution, IN UINT32 ColorDepth, IN UINT32 RefreshRate ) /*++ Routine Description: Return the current video mode information. Arguments: This - Protocol instance pointer. HorizontalResolution - Current video horizontal resolution in pixels VerticalResolution - Current video vertical resolution in pixels ColorDepth - Current video color depth in bits per pixel RefreshRate - Current video refresh rate in Hz. Returns: EFI_SUCCESS - Mode information returned. EFI_NOT_STARTED - Video display is not initialized. Call SetMode () --*/ ; typedef struct { UINT8 Blue; UINT8 Green; UINT8 Red; UINT8 Reserved; } EFI_UGA_PIXEL; typedef union { EFI_UGA_PIXEL Pixel; UINT32 Raw; } EFI_UGA_PIXEL_UNION; typedef enum { EfiUgaVideoFill, EfiUgaVideoToBltBuffer, EfiUgaBltBufferToVideo, EfiUgaVideoToVideo, EfiUgaBltMax } EFI_UGA_BLT_OPERATION; typedef EFI_STATUS (EFIAPI *EFI_UGA_DRAW_PROTOCOL_BLT) ( IN struct _EFI_UGA_DRAW_PROTOCOL * This, IN EFI_UGA_PIXEL * BltBuffer, OPTIONAL IN EFI_UGA_BLT_OPERATION BltOperation, IN UINTN SourceX, IN UINTN SourceY, IN UINTN DestinationX, IN UINTN DestinationY, IN UINTN Width, IN UINTN Height, IN UINTN Delta OPTIONAL ); /*++ Routine Description: The following table defines actions for BltOperations: EfiUgaVideoFill - Write data from the BltBuffer pixel (SourceX, SourceY) directly to every pixel of the video display rectangle (DestinationX, DestinationY) (DestinationX + Width, DestinationY + Height). Only one pixel will be used from the BltBuffer. Delta is NOT used. EfiUgaVideoToBltBuffer - Read data from the video display rectangle (SourceX, SourceY) (SourceX + Width, SourceY + Height) and place it in the BltBuffer rectangle (DestinationX, DestinationY ) (DestinationX + Width, DestinationY + Height). If DestinationX or DestinationY is not zero then Delta must be set to the length in bytes of a row in the BltBuffer. EfiUgaBltBufferToVideo - Write data from the BltBuffer rectangle (SourceX, SourceY) (SourceX + Width, SourceY + Height) directly to the video display rectangle (DestinationX, DestinationY) (DestinationX + Width, DestinationY + Height). If SourceX or SourceY is not zero then Delta must be set to the length in bytes of a row in the BltBuffer. EfiUgaVideoToVideo - Copy from the video display rectangle (SourceX, SourceY) (SourceX + Width, SourceY + Height) .to the video display rectangle (DestinationX, DestinationY) (DestinationX + Width, DestinationY + Height). The BltBuffer and Delta are not used in this mode. Arguments: This - Protocol instance pointer. BltBuffer - Buffer containing data to blit into video buffer. This buffer has a size of Width*Height*sizeof(EFI_UGA_PIXEL) BltOperation - Operation to perform on BlitBuffer and video memory SourceX - X coordinate of source for the BltBuffer. SourceY - Y coordinate of source for the BltBuffer. DestinationX - X coordinate of destination for the BltBuffer. DestinationY - Y coordinate of destination for the BltBuffer. Width - Width of rectangle in BltBuffer in pixels. Height - Hight of rectangle in BltBuffer in pixels. Delta - Returns: EFI_SUCCESS - The Blt operation completed. EFI_INVALID_PARAMETER - BltOperation is not valid. EFI_DEVICE_ERROR - A hardware error occured writting to the video buffer. --*/ ; typedef struct _EFI_UGA_DRAW_PROTOCOL { EFI_UGA_DRAW_PROTOCOL_GET_MODE GetMode; EFI_UGA_DRAW_PROTOCOL_SET_MODE SetMode; EFI_UGA_DRAW_PROTOCOL_BLT Blt; } EFI_UGA_DRAW_PROTOCOL; extern EFI_GUID gEfiUgaDrawProtocolGuid; #endif ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/libeg/libegint.h����������������������������������������������������������������������0000664�0001750�0001750�00000006607�12626644770�016371� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * libeg/libegint.h * EFI graphics library internal header * * Copyright (c) 2006 Christoph Pfisterer * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * * Neither the name of Christoph Pfisterer nor the names of the * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef __LIBEG_LIBEGINT_H__ #define __LIBEG_LIBEGINT_H__ #ifdef __MAKEWITH_GNUEFI #include <efi.h> #include <efilib.h> #else #include "../include/tiano_includes.h" #endif #include "libeg.h" /* types */ typedef EG_IMAGE * (*EG_DECODE_FUNC)(IN UINT8 *FileData, IN UINTN FileDataLength, IN UINTN IconSize, IN BOOLEAN WantAlpha); /* functions */ BOOLEAN egSetScreenSize(IN OUT UINTN *ScreenWidth, IN OUT UINTN *ScreenHeight); VOID egRestrictImageArea(IN EG_IMAGE *Image, IN UINTN AreaPosX, IN UINTN AreaPosY, IN OUT UINTN *AreaWidth, IN OUT UINTN *AreaHeight); VOID egRawCopy(IN OUT EG_PIXEL *CompBasePtr, IN EG_PIXEL *TopBasePtr, IN UINTN Width, IN UINTN Height, IN UINTN CompLineOffset, IN UINTN TopLineOffset); VOID egRawCompose(IN OUT EG_PIXEL *CompBasePtr, IN EG_PIXEL *TopBasePtr, IN UINTN Width, IN UINTN Height, IN UINTN CompLineOffset, IN UINTN TopLineOffset); #define PLPTR(imagevar, colorname) ((UINT8 *) &((imagevar)->PixelData->colorname)) VOID egDecompressIcnsRLE(IN OUT UINT8 **CompData, IN OUT UINTN *CompLen, IN UINT8 *DestPlanePtr, IN UINTN PixelCount); VOID egInsertPlane(IN UINT8 *SrcDataPtr, IN UINT8 *DestPlanePtr, IN UINTN PixelCount); VOID egSetPlane(IN UINT8 *DestPlanePtr, IN UINT8 Value, IN UINTN PixelCount); VOID egCopyPlane(IN UINT8 *SrcPlanePtr, IN UINT8 *DestPlanePtr, IN UINTN PixelCount); EG_IMAGE * egDecodeBMP(IN UINT8 *FileData, IN UINTN FileDataLength, IN UINTN IconSize, IN BOOLEAN WantAlpha); EG_IMAGE * egDecodeICNS(IN UINT8 *FileData, IN UINTN FileDataLength, IN UINTN IconSize, IN BOOLEAN WantAlpha); VOID egEncodeBMP(IN EG_IMAGE *Image, OUT UINT8 **FileData, OUT UINTN *FileDataLength); #endif /* __LIBEG_LIBEGINT_H__ */ /* EOF */ �������������������������������������������������������������������������������������������������������������������������refind-0.11.4/libeg/Makefile������������������������������������������������������������������������0000664�0001750�0001750�00000001263�13323000006�016021� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # libeg/Makefile # Build control file for the libeg library # # This program is licensed under the terms of the GNU GPL, version 3, # or (at your option) any later version. # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. SRCDIR = . VPATH = $(SRCDIR) LOCAL_GNUEFI_CFLAGS = -I$(SRCDIR) -I$(SRCDIR)/../include OBJS = nanojpeg.o nanojpeg_xtra.o screen.o image.o text.o load_bmp.o load_icns.o lodepng.o lodepng_xtra.o TARGET = libeg.a all: $(TARGET) include $(SRCDIR)/../Make.common clean: rm -f $(TARGET) *~ *.so $(OBJS) *.efi *.obj refind_*.txt refind_*.dll *.lib # EOF ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/libeg/efiConsoleControl.h�������������������������������������������������������������0000664�0001750�0001750�00000006570�12626644770�020222� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*++ Copyright (c) 2004, Intel Corporation All rights reserved. This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. Module Name: ConsoleControl.h Abstract: Abstraction of a Text mode or UGA screen --*/ #ifndef __CONSOLE_CONTROL_H__ #define __CONSOLE_CONTROL_H__ #define EFI_CONSOLE_CONTROL_PROTOCOL_GUID \ { 0xf42f7782, 0x12e, 0x4c12, { 0x99, 0x56, 0x49, 0xf9, 0x43, 0x4, 0xf7, 0x21 } } struct _EFI_CONSOLE_CONTROL_PROTOCOL; typedef enum { EfiConsoleControlScreenText, EfiConsoleControlScreenGraphics, EfiConsoleControlScreenMaxValue } EFI_CONSOLE_CONTROL_SCREEN_MODE; typedef EFI_STATUS (EFIAPI *EFI_CONSOLE_CONTROL_PROTOCOL_GET_MODE) ( IN struct _EFI_CONSOLE_CONTROL_PROTOCOL *This, OUT EFI_CONSOLE_CONTROL_SCREEN_MODE *Mode, OUT BOOLEAN *UgaExists, OPTIONAL OUT BOOLEAN *StdInLocked OPTIONAL ) /*++ Routine Description: Return the current video mode information. Also returns info about existence of UGA Draw devices in system, and if the Std In device is locked. All the arguments are optional and only returned if a non NULL pointer is passed in. Arguments: This - Protocol instance pointer. Mode - Are we in text of grahics mode. UgaExists - TRUE if UGA Spliter has found a UGA device StdInLocked - TRUE if StdIn device is keyboard locked Returns: EFI_SUCCESS - Mode information returned. --*/ ; typedef EFI_STATUS (EFIAPI *EFI_CONSOLE_CONTROL_PROTOCOL_SET_MODE) ( IN struct _EFI_CONSOLE_CONTROL_PROTOCOL *This, OUT EFI_CONSOLE_CONTROL_SCREEN_MODE Mode ) /*++ Routine Description: Set the current mode to either text or graphics. Graphics is for Quiet Boot. Arguments: This - Protocol instance pointer. Mode - Mode to set the Returns: EFI_SUCCESS - Mode information returned. --*/ ; typedef EFI_STATUS (EFIAPI *EFI_CONSOLE_CONTROL_PROTOCOL_LOCK_STD_IN) ( IN struct _EFI_CONSOLE_CONTROL_PROTOCOL *This, IN CHAR16 *Password ) /*++ Routine Description: Lock Std In devices until Password is typed. Arguments: This - Protocol instance pointer. Password - Password needed to unlock screen. NULL means unlock keyboard Returns: EFI_SUCCESS - Mode information returned. EFI_DEVICE_ERROR - Std In not locked --*/ ; typedef struct _EFI_CONSOLE_CONTROL_PROTOCOL { EFI_CONSOLE_CONTROL_PROTOCOL_GET_MODE GetMode; EFI_CONSOLE_CONTROL_PROTOCOL_SET_MODE SetMode; EFI_CONSOLE_CONTROL_PROTOCOL_LOCK_STD_IN LockStdIn; } EFI_CONSOLE_CONTROL_PROTOCOL; //extern EFI_GUID gEfiConsoleControlProtocolGuid; #endif ����������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/libeg/image.c�������������������������������������������������������������������������0000664�0001750�0001750�00000060426�13325166033�015634� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * libeg/image.c * Image handling functions * * Copyright (c) 2006 Christoph Pfisterer * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * * Neither the name of Christoph Pfisterer nor the names of the * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Modifications copyright (c) 2012-2018 Roderick W. Smith * * Modifications distributed under the terms of the GNU General Public * License (GPL) version 3 (GPLv3), or (at your option) any later version. * */ /* * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "libegint.h" #include "../refind/global.h" #include "../refind/lib.h" #include "../refind/screen.h" #include "../refind/mystrings.h" #include "../include/refit_call_wrapper.h" #include "lodepng.h" #include "libeg.h" #define MAX_FILE_SIZE (1024*1024*1024) // Multiplier for pseudo-floating-point operations in egScaleImage(). // A value of 4096 should keep us within limits on 32-bit systems, but I've // seen some minor artifacts at this level, so give it a bit more precision // on 64-bit systems.... #if defined(EFIX64) | defined(EFIAARCH64) #define FP_MULTIPLIER (UINTN) 65536 #else #define FP_MULTIPLIER (UINTN) 4096 #endif #ifndef __MAKEWITH_GNUEFI #define LibLocateHandle gBS->LocateHandleBuffer #define LibOpenRoot EfiLibOpenRoot #endif // // Basic image handling // EG_IMAGE * egCreateImage(IN UINTN Width, IN UINTN Height, IN BOOLEAN HasAlpha) { EG_IMAGE *NewImage; NewImage = (EG_IMAGE *) AllocatePool(sizeof(EG_IMAGE)); if (NewImage == NULL) return NULL; NewImage->PixelData = (EG_PIXEL *) AllocatePool(Width * Height * sizeof(EG_PIXEL)); if (NewImage->PixelData == NULL) { egFreeImage(NewImage); return NULL; } NewImage->Width = Width; NewImage->Height = Height; NewImage->HasAlpha = HasAlpha; return NewImage; } EG_IMAGE * egCreateFilledImage(IN UINTN Width, IN UINTN Height, IN BOOLEAN HasAlpha, IN EG_PIXEL *Color) { EG_IMAGE *NewImage; NewImage = egCreateImage(Width, Height, HasAlpha); if (NewImage == NULL) return NULL; egFillImage(NewImage, Color); return NewImage; } EG_IMAGE * egCopyImage(IN EG_IMAGE *Image) { EG_IMAGE *NewImage = NULL; if (Image != NULL) NewImage = egCreateImage(Image->Width, Image->Height, Image->HasAlpha); if (NewImage == NULL) return NULL; CopyMem(NewImage->PixelData, Image->PixelData, Image->Width * Image->Height * sizeof(EG_PIXEL)); return NewImage; } // Returns a smaller image composed of the specified crop area from the larger area. // If the specified area is larger than is in the original, returns NULL. EG_IMAGE * egCropImage(IN EG_IMAGE *Image, IN UINTN StartX, IN UINTN StartY, IN UINTN Width, IN UINTN Height) { EG_IMAGE *NewImage = NULL; UINTN x, y; if (((StartX + Width) > Image->Width) || ((StartY + Height) > Image->Height)) return NULL; NewImage = egCreateImage(Width, Height, Image->HasAlpha); if (NewImage == NULL) return NULL; for (y = 0; y < Height; y++) { for (x = 0; x < Width; x++) { NewImage->PixelData[y * NewImage->Width + x] = Image->PixelData[(y + StartY) * Image->Width + x + StartX]; } } return NewImage; } // EG_IMAGE * egCropImage() // The following function implements a bilinear image scaling algorithm, based on // code presented at http://tech-algorithm.com/articles/bilinear-image-scaling/. // Resize an image; returns pointer to resized image if successful, NULL otherwise. // Calling function is responsible for freeing allocated memory. // NOTE: x_ratio, y_ratio, x_diff, and y_diff should really be float values; // however, I've found that my 32-bit Mac Mini has a buggy EFI (or buggy CPU?), which // causes this function to hang on float-to-UINT8 conversions on some (but not all!) // float values. Therefore, this function uses integer arithmetic but multiplies // all values by FP_MULTIPLIER to achieve something resembling the sort of precision // needed for good results. EG_IMAGE * egScaleImage(IN EG_IMAGE *Image, IN UINTN NewWidth, IN UINTN NewHeight) { EG_IMAGE *NewImage = NULL; EG_PIXEL a, b, c, d; UINTN x, y, Index ; UINTN i, j; UINTN Offset = 0; UINTN x_ratio, y_ratio, x_diff, y_diff; if ((Image == NULL) || (Image->Height == 0) || (Image->Width == 0) || (NewWidth == 0) || (NewHeight == 0)) return NULL; if ((Image->Width == NewWidth) && (Image->Height == NewHeight)) return (egCopyImage(Image)); NewImage = egCreateImage(NewWidth, NewHeight, Image->HasAlpha); if (NewImage == NULL) return NULL; x_ratio = ((Image->Width - 1) * FP_MULTIPLIER) / NewWidth; y_ratio = ((Image->Height - 1) * FP_MULTIPLIER) / NewHeight; for (i = 0; i < NewHeight; i++) { for (j = 0; j < NewWidth; j++) { x = (j * (Image->Width - 1)) / NewWidth; y = (i * (Image->Height - 1)) / NewHeight; x_diff = (x_ratio * j) - x * FP_MULTIPLIER; y_diff = (y_ratio * i) - y * FP_MULTIPLIER; Index = ((y * Image->Width) + x); a = Image->PixelData[Index]; b = Image->PixelData[Index + 1]; c = Image->PixelData[Index + Image->Width]; d = Image->PixelData[Index + Image->Width + 1]; // blue element NewImage->PixelData[Offset].b = ((a.b) * (FP_MULTIPLIER - x_diff) * (FP_MULTIPLIER - y_diff) + (b.b) * (x_diff) * (FP_MULTIPLIER - y_diff) + (c.b) * (y_diff) * (FP_MULTIPLIER - x_diff) + (d.b) * (x_diff * y_diff)) / (FP_MULTIPLIER * FP_MULTIPLIER); // green element NewImage->PixelData[Offset].g = ((a.g) * (FP_MULTIPLIER - x_diff) * (FP_MULTIPLIER - y_diff) + (b.g) * (x_diff) * (FP_MULTIPLIER - y_diff) + (c.g) * (y_diff) * (FP_MULTIPLIER - x_diff) + (d.g) * (x_diff * y_diff)) / (FP_MULTIPLIER * FP_MULTIPLIER); // red element NewImage->PixelData[Offset].r = ((a.r) * (FP_MULTIPLIER - x_diff) * (FP_MULTIPLIER - y_diff) + (b.r) * (x_diff) * (FP_MULTIPLIER - y_diff) + (c.r) * (y_diff) * (FP_MULTIPLIER - x_diff) + (d.r) * (x_diff * y_diff)) / (FP_MULTIPLIER * FP_MULTIPLIER); // alpha element NewImage->PixelData[Offset++].a = ((a.a) * (FP_MULTIPLIER - x_diff) * (FP_MULTIPLIER - y_diff) + (b.a) * (x_diff) * (FP_MULTIPLIER - y_diff) + (c.a) * (y_diff) * (FP_MULTIPLIER - x_diff) + (d.a) * (x_diff * y_diff)) / (FP_MULTIPLIER * FP_MULTIPLIER); } // for (j...) } // for (i...) return NewImage; } // EG_IMAGE * egScaleImage() VOID egFreeImage(IN EG_IMAGE *Image) { if (Image != NULL) { if (Image->PixelData != NULL) FreePool(Image->PixelData); FreePool(Image); } } // // Basic file operations // EFI_STATUS egLoadFile(IN EFI_FILE *BaseDir, IN CHAR16 *FileName, OUT UINT8 **FileData, OUT UINTN *FileDataLength) { EFI_STATUS Status; EFI_FILE_HANDLE FileHandle; EFI_FILE_INFO *FileInfo; UINT64 ReadSize; UINTN BufferSize; UINT8 *Buffer; if ((BaseDir == NULL) || (FileName == NULL)) return EFI_NOT_FOUND; Status = refit_call5_wrapper(BaseDir->Open, BaseDir, &FileHandle, FileName, EFI_FILE_MODE_READ, 0); if (EFI_ERROR(Status)) { return Status; } FileInfo = LibFileInfo(FileHandle); if (FileInfo == NULL) { refit_call1_wrapper(FileHandle->Close, FileHandle); return EFI_NOT_FOUND; } ReadSize = FileInfo->FileSize; if (ReadSize > MAX_FILE_SIZE) ReadSize = MAX_FILE_SIZE; FreePool(FileInfo); BufferSize = (UINTN)ReadSize; // was limited to 1 GB above, so this is safe Buffer = (UINT8 *) AllocatePool(BufferSize); if (Buffer == NULL) { refit_call1_wrapper(FileHandle->Close, FileHandle); return EFI_OUT_OF_RESOURCES; } Status = refit_call3_wrapper(FileHandle->Read, FileHandle, &BufferSize, Buffer); refit_call1_wrapper(FileHandle->Close, FileHandle); if (EFI_ERROR(Status)) { FreePool(Buffer); return Status; } *FileData = Buffer; *FileDataLength = BufferSize; return EFI_SUCCESS; } static EFI_GUID ESPGuid = { 0xc12a7328, 0xf81f, 0x11d2, { 0xba, 0x4b, 0x00, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b } }; EFI_STATUS egFindESP(OUT EFI_FILE_HANDLE *RootDir) { EFI_STATUS Status; UINTN HandleCount = 0; EFI_HANDLE *Handles; Status = LibLocateHandle(ByProtocol, &ESPGuid, NULL, &HandleCount, &Handles); if (!EFI_ERROR(Status) && HandleCount > 0) { *RootDir = LibOpenRoot(Handles[0]); if (*RootDir == NULL) Status = EFI_NOT_FOUND; FreePool(Handles); } return Status; } EFI_STATUS egSaveFile(IN EFI_FILE* BaseDir OPTIONAL, IN CHAR16 *FileName, IN UINT8 *FileData, IN UINTN FileDataLength) { EFI_STATUS Status; EFI_FILE_HANDLE FileHandle; UINTN BufferSize; if (BaseDir == NULL) { Status = egFindESP(&BaseDir); if (EFI_ERROR(Status)) return Status; } Status = refit_call5_wrapper(BaseDir->Open, BaseDir, &FileHandle, FileName, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, 0); if (EFI_ERROR(Status)) return Status; BufferSize = FileDataLength; Status = refit_call3_wrapper(FileHandle->Write, FileHandle, &BufferSize, FileData); refit_call1_wrapper(FileHandle->Close, FileHandle); return Status; } // // Loading images from files and embedded data // // Decode the specified image data. The IconSize parameter is relevant only // for ICNS, for which it selects which ICNS sub-image is decoded. // Returns a pointer to the resulting EG_IMAGE or NULL if decoding failed. static EG_IMAGE * egDecodeAny(IN UINT8 *FileData, IN UINTN FileDataLength, IN UINTN IconSize, IN BOOLEAN WantAlpha) { EG_IMAGE *NewImage = NULL; NewImage = egDecodeICNS(FileData, FileDataLength, IconSize, WantAlpha); if (NewImage == NULL) NewImage = egDecodePNG(FileData, FileDataLength, IconSize, WantAlpha); if (NewImage == NULL) NewImage = egDecodeJPEG(FileData, FileDataLength, IconSize, WantAlpha); if (NewImage == NULL) NewImage = egDecodeBMP(FileData, FileDataLength, IconSize, WantAlpha); return NewImage; } EG_IMAGE * egLoadImage(IN EFI_FILE* BaseDir, IN CHAR16 *FileName, IN BOOLEAN WantAlpha) { EFI_STATUS Status; UINT8 *FileData; UINTN FileDataLength; EG_IMAGE *NewImage; if (BaseDir == NULL || FileName == NULL) return NULL; // load file Status = egLoadFile(BaseDir, FileName, &FileData, &FileDataLength); if (EFI_ERROR(Status)) return NULL; // decode it NewImage = egDecodeAny(FileData, FileDataLength, 128 /* arbitrary value */, WantAlpha); FreePool(FileData); return NewImage; } // Load an icon from (BaseDir)/Path, extracting the icon of size IconSize x IconSize. // Returns a pointer to the image data, or NULL if the icon could not be loaded. EG_IMAGE * egLoadIcon(IN EFI_FILE* BaseDir, IN CHAR16 *Path, IN UINTN IconSize) { EFI_STATUS Status; UINT8 *FileData; UINTN FileDataLength; EG_IMAGE *Image, *NewImage; if (BaseDir == NULL || Path == NULL) return NULL; // load file Status = egLoadFile(BaseDir, Path, &FileData, &FileDataLength); if (EFI_ERROR(Status)) return NULL; // decode it Image = egDecodeAny(FileData, FileDataLength, IconSize, TRUE); FreePool(FileData); if ((Image->Width != IconSize) || (Image->Height != IconSize)) { NewImage = egScaleImage(Image, IconSize, IconSize); if (!NewImage) { Print(L"Warning: Unable to scale icon from %d x %d to %d x %d from '%s'\n", Image->Width, Image->Height, IconSize, IconSize, Path); } egFreeImage(Image); Image = NewImage; } return Image; } // EG_IMAGE *egLoadIcon() // Returns an icon of any type from the specified subdirectory using the specified // base name. All directory references are relative to BaseDir. For instance, if // SubdirName is "myicons" and BaseName is "os_linux", this function will return // an image based on "myicons/os_linux.icns" or "myicons/os_linux.png", in that // order of preference. Returns NULL if no such file is a valid icon file. EG_IMAGE * egLoadIconAnyType(IN EFI_FILE *BaseDir, IN CHAR16 *SubdirName, IN CHAR16 *BaseName, IN UINTN IconSize) { EG_IMAGE *Image = NULL; CHAR16 *Extension; CHAR16 FileName[256]; UINTN i = 0; while (((Extension = FindCommaDelimited(ICON_EXTENSIONS, i++)) != NULL) && (Image == NULL)) { SPrint(FileName, 255, L"%s\\%s.%s", SubdirName, BaseName, Extension); Image = egLoadIcon(BaseDir, FileName, IconSize); MyFreePool(Extension); } // while() return Image; } // EG_IMAGE *egLoadIconAnyType() // Returns an icon with any extension in ICON_EXTENSIONS from either the directory // specified by GlobalConfig.IconsDir or DEFAULT_ICONS_DIR. The input BaseName // should be the icon name without an extension. For instance, if BaseName is // os_linux, GlobalConfig.IconsDir is myicons, DEFAULT_ICONS_DIR is icons, and // ICON_EXTENSIONS is "icns,png", this function will return myicons/os_linux.icns, // myicons/os_linux.png, icons/os_linux.icns, or icons/os_linux.png, in that // order of preference. Returns NULL if no such icon can be found. All file // references are relative to SelfDir. EG_IMAGE * egFindIcon(IN CHAR16 *BaseName, IN UINTN IconSize) { EG_IMAGE *Image = NULL; if (GlobalConfig.IconsDir != NULL) { Image = egLoadIconAnyType(SelfDir, GlobalConfig.IconsDir, BaseName, IconSize); } if (Image == NULL) { Image = egLoadIconAnyType(SelfDir, DEFAULT_ICONS_DIR, BaseName, IconSize); } return Image; } // EG_IMAGE * egFindIcon() EG_IMAGE * egPrepareEmbeddedImage(IN EG_EMBEDDED_IMAGE *EmbeddedImage, IN BOOLEAN WantAlpha) { EG_IMAGE *NewImage; UINT8 *CompData; UINTN CompLen; UINTN PixelCount; // sanity check if (EmbeddedImage->PixelMode > EG_MAX_EIPIXELMODE || (EmbeddedImage->CompressMode != EG_EICOMPMODE_NONE && EmbeddedImage->CompressMode != EG_EICOMPMODE_RLE)) return NULL; // allocate image structure and pixel buffer NewImage = egCreateImage(EmbeddedImage->Width, EmbeddedImage->Height, WantAlpha); if (NewImage == NULL) return NULL; CompData = (UINT8 *)EmbeddedImage->Data; // drop const CompLen = EmbeddedImage->DataLength; PixelCount = EmbeddedImage->Width * EmbeddedImage->Height; // FUTURE: for EG_EICOMPMODE_EFICOMPRESS, decompress whole data block here if (EmbeddedImage->PixelMode == EG_EIPIXELMODE_GRAY || EmbeddedImage->PixelMode == EG_EIPIXELMODE_GRAY_ALPHA) { // copy grayscale plane and expand if (EmbeddedImage->CompressMode == EG_EICOMPMODE_RLE) { egDecompressIcnsRLE(&CompData, &CompLen, PLPTR(NewImage, r), PixelCount); } else { egInsertPlane(CompData, PLPTR(NewImage, r), PixelCount); CompData += PixelCount; } egCopyPlane(PLPTR(NewImage, r), PLPTR(NewImage, g), PixelCount); egCopyPlane(PLPTR(NewImage, r), PLPTR(NewImage, b), PixelCount); } else if (EmbeddedImage->PixelMode == EG_EIPIXELMODE_COLOR || EmbeddedImage->PixelMode == EG_EIPIXELMODE_COLOR_ALPHA) { // copy color planes if (EmbeddedImage->CompressMode == EG_EICOMPMODE_RLE) { egDecompressIcnsRLE(&CompData, &CompLen, PLPTR(NewImage, r), PixelCount); egDecompressIcnsRLE(&CompData, &CompLen, PLPTR(NewImage, g), PixelCount); egDecompressIcnsRLE(&CompData, &CompLen, PLPTR(NewImage, b), PixelCount); } else { egInsertPlane(CompData, PLPTR(NewImage, r), PixelCount); CompData += PixelCount; egInsertPlane(CompData, PLPTR(NewImage, g), PixelCount); CompData += PixelCount; egInsertPlane(CompData, PLPTR(NewImage, b), PixelCount); CompData += PixelCount; } } else { // set color planes to black egSetPlane(PLPTR(NewImage, r), 0, PixelCount); egSetPlane(PLPTR(NewImage, g), 0, PixelCount); egSetPlane(PLPTR(NewImage, b), 0, PixelCount); } if (WantAlpha && (EmbeddedImage->PixelMode == EG_EIPIXELMODE_GRAY_ALPHA || EmbeddedImage->PixelMode == EG_EIPIXELMODE_COLOR_ALPHA || EmbeddedImage->PixelMode == EG_EIPIXELMODE_ALPHA)) { // copy alpha plane if (EmbeddedImage->CompressMode == EG_EICOMPMODE_RLE) { egDecompressIcnsRLE(&CompData, &CompLen, PLPTR(NewImage, a), PixelCount); } else { egInsertPlane(CompData, PLPTR(NewImage, a), PixelCount); CompData += PixelCount; } } else { egSetPlane(PLPTR(NewImage, a), WantAlpha ? 255 : 0, PixelCount); } return NewImage; } // // Compositing // VOID egRestrictImageArea(IN EG_IMAGE *Image, IN UINTN AreaPosX, IN UINTN AreaPosY, IN OUT UINTN *AreaWidth, IN OUT UINTN *AreaHeight) { if (AreaPosX >= Image->Width || AreaPosY >= Image->Height) { // out of bounds, operation has no effect *AreaWidth = 0; *AreaHeight = 0; } else { // calculate affected area if (*AreaWidth > Image->Width - AreaPosX) *AreaWidth = Image->Width - AreaPosX; if (*AreaHeight > Image->Height - AreaPosY) *AreaHeight = Image->Height - AreaPosY; } } VOID egFillImage(IN OUT EG_IMAGE *CompImage, IN EG_PIXEL *Color) { UINTN i; EG_PIXEL FillColor; EG_PIXEL *PixelPtr; FillColor = *Color; if (!CompImage->HasAlpha) FillColor.a = 0; PixelPtr = CompImage->PixelData; for (i = 0; i < CompImage->Width * CompImage->Height; i++, PixelPtr++) *PixelPtr = FillColor; } VOID egFillImageArea(IN OUT EG_IMAGE *CompImage, IN UINTN AreaPosX, IN UINTN AreaPosY, IN UINTN AreaWidth, IN UINTN AreaHeight, IN EG_PIXEL *Color) { UINTN x, y; EG_PIXEL FillColor; EG_PIXEL *PixelPtr; EG_PIXEL *PixelBasePtr; egRestrictImageArea(CompImage, AreaPosX, AreaPosY, &AreaWidth, &AreaHeight); if (AreaWidth > 0) { FillColor = *Color; if (!CompImage->HasAlpha) FillColor.a = 0; PixelBasePtr = CompImage->PixelData + AreaPosY * CompImage->Width + AreaPosX; for (y = 0; y < AreaHeight; y++) { PixelPtr = PixelBasePtr; for (x = 0; x < AreaWidth; x++, PixelPtr++) *PixelPtr = FillColor; PixelBasePtr += CompImage->Width; } } } VOID egRawCopy(IN OUT EG_PIXEL *CompBasePtr, IN EG_PIXEL *TopBasePtr, IN UINTN Width, IN UINTN Height, IN UINTN CompLineOffset, IN UINTN TopLineOffset) { UINTN x, y; EG_PIXEL *TopPtr, *CompPtr; for (y = 0; y < Height; y++) { TopPtr = TopBasePtr; CompPtr = CompBasePtr; for (x = 0; x < Width; x++) { *CompPtr = *TopPtr; TopPtr++, CompPtr++; } TopBasePtr += TopLineOffset; CompBasePtr += CompLineOffset; } } VOID egRawCompose(IN OUT EG_PIXEL *CompBasePtr, IN EG_PIXEL *TopBasePtr, IN UINTN Width, IN UINTN Height, IN UINTN CompLineOffset, IN UINTN TopLineOffset) { UINTN x, y; EG_PIXEL *TopPtr, *CompPtr; UINTN Alpha; UINTN RevAlpha; UINTN Temp; for (y = 0; y < Height; y++) { TopPtr = TopBasePtr; CompPtr = CompBasePtr; for (x = 0; x < Width; x++) { Alpha = TopPtr->a; RevAlpha = 255 - Alpha; Temp = (UINTN)CompPtr->b * RevAlpha + (UINTN)TopPtr->b * Alpha + 0x80; CompPtr->b = (Temp + (Temp >> 8)) >> 8; Temp = (UINTN)CompPtr->g * RevAlpha + (UINTN)TopPtr->g * Alpha + 0x80; CompPtr->g = (Temp + (Temp >> 8)) >> 8; Temp = (UINTN)CompPtr->r * RevAlpha + (UINTN)TopPtr->r * Alpha + 0x80; CompPtr->r = (Temp + (Temp >> 8)) >> 8; /* CompPtr->b = ((UINTN)CompPtr->b * RevAlpha + (UINTN)TopPtr->b * Alpha) / 255; CompPtr->g = ((UINTN)CompPtr->g * RevAlpha + (UINTN)TopPtr->g * Alpha) / 255; CompPtr->r = ((UINTN)CompPtr->r * RevAlpha + (UINTN)TopPtr->r * Alpha) / 255; */ TopPtr++, CompPtr++; } TopBasePtr += TopLineOffset; CompBasePtr += CompLineOffset; } } VOID egComposeImage(IN OUT EG_IMAGE *CompImage, IN EG_IMAGE *TopImage, IN UINTN PosX, IN UINTN PosY) { UINTN CompWidth, CompHeight; CompWidth = TopImage->Width; CompHeight = TopImage->Height; egRestrictImageArea(CompImage, PosX, PosY, &CompWidth, &CompHeight); // compose if (CompWidth > 0) { if (TopImage->HasAlpha) { egRawCompose(CompImage->PixelData + PosY * CompImage->Width + PosX, TopImage->PixelData, CompWidth, CompHeight, CompImage->Width, TopImage->Width); } else { egRawCopy(CompImage->PixelData + PosY * CompImage->Width + PosX, TopImage->PixelData, CompWidth, CompHeight, CompImage->Width, TopImage->Width); } } } /* VOID egComposeImage() */ // // misc internal functions // VOID egInsertPlane(IN UINT8 *SrcDataPtr, IN UINT8 *DestPlanePtr, IN UINTN PixelCount) { UINTN i; for (i = 0; i < PixelCount; i++) { *DestPlanePtr = *SrcDataPtr++; DestPlanePtr += 4; } } VOID egSetPlane(IN UINT8 *DestPlanePtr, IN UINT8 Value, IN UINTN PixelCount) { UINTN i; for (i = 0; i < PixelCount; i++) { *DestPlanePtr = Value; DestPlanePtr += 4; } } VOID egCopyPlane(IN UINT8 *SrcPlanePtr, IN UINT8 *DestPlanePtr, IN UINTN PixelCount) { UINTN i; for (i = 0; i < PixelCount; i++) { *DestPlanePtr = *SrcPlanePtr; DestPlanePtr += 4, SrcPlanePtr += 4; } } /* EOF */ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/libeg/text.c��������������������������������������������������������������������������0000664�0001750�0001750�00000012354�13137356476�015550� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * libeg/text.c * Text drawing functions * * Copyright (c) 2006 Christoph Pfisterer * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * * Neither the name of Christoph Pfisterer nor the names of the * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "libegint.h" #include "../refind/global.h" #include "egemb_font.h" #include "egemb_font_large.h" #define FONT_NUM_CHARS 96 static EG_IMAGE *BaseFontImage = NULL; static EG_IMAGE *DarkFontImage = NULL; static EG_IMAGE *LightFontImage = NULL; static UINTN FontCellWidth = 7; // // Text rendering // static VOID egPrepareFont() { UINTN UGAWidth, UGAHeight; egGetScreenSize(&UGAWidth, &UGAHeight); if (BaseFontImage == NULL) { if (UGAWidth >= HIDPI_MIN) BaseFontImage = egPrepareEmbeddedImage(&egemb_font_large, TRUE); else BaseFontImage = egPrepareEmbeddedImage(&egemb_font, TRUE); } if (BaseFontImage != NULL) FontCellWidth = BaseFontImage->Width / FONT_NUM_CHARS; } // VOID egPrepareFont(); UINTN egGetFontHeight(VOID) { egPrepareFont(); return BaseFontImage->Height; } // UINTN egGetFontHeight() UINTN egGetFontCellWidth(VOID) { return FontCellWidth; } UINTN egComputeTextWidth(IN CHAR16 *Text) { UINTN Width = 0; egPrepareFont(); if (Text != NULL) Width = FontCellWidth * StrLen(Text); return Width; } // UINTN egComputeTextWidth() VOID egMeasureText(IN CHAR16 *Text, OUT UINTN *Width, OUT UINTN *Height) { egPrepareFont(); if (Width != NULL) *Width = StrLen(Text) * FontCellWidth; if (Height != NULL) *Height = BaseFontImage->Height; } VOID egRenderText(IN CHAR16 *Text, IN OUT EG_IMAGE *CompImage, IN UINTN PosX, IN UINTN PosY, IN UINT8 BGBrightness) { EG_IMAGE *FontImage; EG_PIXEL *BufferPtr; EG_PIXEL *FontPixelData; UINTN BufferLineOffset, FontLineOffset; UINTN TextLength; UINTN i, c; egPrepareFont(); // clip the text if (Text) TextLength = StrLen(Text); else TextLength = 0; if (TextLength * FontCellWidth + PosX > CompImage->Width) TextLength = (CompImage->Width - PosX) / FontCellWidth; if (BGBrightness < 128) { if (LightFontImage == NULL) { LightFontImage = egCopyImage(BaseFontImage); if (LightFontImage == NULL) return; for (i = 0; i < (LightFontImage->Width * LightFontImage->Height); i++) { LightFontImage->PixelData[i].r = 255 - LightFontImage->PixelData[i].r; LightFontImage->PixelData[i].g = 255 - LightFontImage->PixelData[i].g; LightFontImage->PixelData[i].b = 255 - LightFontImage->PixelData[i].b; } // for } // if FontImage = LightFontImage; } else { if (DarkFontImage == NULL) DarkFontImage = egCopyImage(BaseFontImage); if (DarkFontImage == NULL) return; FontImage = DarkFontImage; } // if/else // render it BufferPtr = CompImage->PixelData; BufferLineOffset = CompImage->Width; BufferPtr += PosX + PosY * BufferLineOffset; FontPixelData = FontImage->PixelData; FontLineOffset = FontImage->Width; for (i = 0; i < TextLength; i++) { c = Text[i]; if (c < 32 || c >= 127) c = 95; else c -= 32; egRawCompose(BufferPtr, FontPixelData + c * FontCellWidth, FontCellWidth, FontImage->Height, BufferLineOffset, FontLineOffset); BufferPtr += FontCellWidth; } } // Load a font bitmap from the specified file VOID egLoadFont(IN CHAR16 *Filename) { if (BaseFontImage) egFreeImage(BaseFontImage); BaseFontImage = egLoadImage(SelfDir, Filename, TRUE); if (BaseFontImage == NULL) Print(L"Note: Font image file %s is invalid! Using default font!\n"); egPrepareFont(); } // BOOLEAN egLoadFont() /* EOF */ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/libeg/lodepng.c�����������������������������������������������������������������������0000664�0001750�0001750�00000656173�13112662420�016207� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* LodePNG version 20161127 Copyright (c) 2005-2016 Lode Vandevenne This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ /* The manual and changelog are in the header file "lodepng.h" Rename this file to lodepng.cpp to use it for C++, or to lodepng.c to use it for C. */ #include "lodepng.h" #include <limits.h> #include <stdio.h> #include <stdlib.h> #if defined(_MSC_VER) && (_MSC_VER >= 1310) /*Visual Studio: A few warning types are not desired here.*/ #pragma warning( disable : 4244 ) /*implicit conversions: not warned by gcc -Wall -Wextra and requires too much casts*/ #pragma warning( disable : 4996 ) /*VS does not like fopen, but fopen_s is not standard C so unusable here*/ #endif /*_MSC_VER */ const char* LODEPNG_VERSION_STRING = "20161127"; /* This source file is built up in the following large parts. The code sections with the "LODEPNG_COMPILE_" #defines divide this up further in an intermixed way. -Tools for C and common code for PNG and Zlib -C Code for Zlib (huffman, deflate, ...) -C Code for PNG (file format chunks, adam7, PNG filters, color conversions, ...) -The C++ wrapper around all of the above */ /*The malloc, realloc and free functions defined here with "lodepng_" in front of the name, so that you can easily change them to others related to your platform if needed. Everything else in the code calls these. Pass -DLODEPNG_NO_COMPILE_ALLOCATORS to the compiler, or comment out #define LODEPNG_COMPILE_ALLOCATORS in the header, to disable the ones here and define them in your own project's source files without needing to change lodepng source code. Don't forget to remove "static" if you copypaste them from here.*/ #ifdef LODEPNG_COMPILE_ALLOCATORS static void* lodepng_malloc(size_t size) { return malloc(size); } static void* lodepng_realloc(void* ptr, size_t new_size) { return realloc(ptr, new_size); } static void lodepng_free(void* ptr) { free(ptr); } #else /*LODEPNG_COMPILE_ALLOCATORS*/ void* lodepng_malloc(size_t size); void* lodepng_realloc(void* ptr, size_t new_size); void lodepng_free(void* ptr); #endif /*LODEPNG_COMPILE_ALLOCATORS*/ /* ////////////////////////////////////////////////////////////////////////// */ /* ////////////////////////////////////////////////////////////////////////// */ /* // Tools for C, and common code for PNG and Zlib. // */ /* ////////////////////////////////////////////////////////////////////////// */ /* ////////////////////////////////////////////////////////////////////////// */ /* Often in case of an error a value is assigned to a variable and then it breaks out of a loop (to go to the cleanup phase of a function). This macro does that. It makes the error handling code shorter and more readable. Example: if(!uivector_resizev(&frequencies_ll, 286, 0)) ERROR_BREAK(83); */ #define CERROR_BREAK(errorvar, code)\ {\ errorvar = code;\ break;\ } /*version of CERROR_BREAK that assumes the common case where the error variable is named "error"*/ #define ERROR_BREAK(code) CERROR_BREAK(error, code) /*Set error var to the error code, and return it.*/ #define CERROR_RETURN_ERROR(errorvar, code)\ {\ errorvar = code;\ return code;\ } /*Try the code, if it returns error, also return the error.*/ #define CERROR_TRY_RETURN(call)\ {\ unsigned error = call;\ if(error) return error;\ } /*Set error var to the error code, and return from the void function.*/ #define CERROR_RETURN(errorvar, code)\ {\ errorvar = code;\ return;\ } /* About uivector, ucvector and string: -All of them wrap dynamic arrays or text strings in a similar way. -LodePNG was originally written in C++. The vectors replace the std::vectors that were used in the C++ version. -The string tools are made to avoid problems with compilers that declare things like strncat as deprecated. -They're not used in the interface, only internally in this file as static functions. -As with many other structs in this file, the init and cleanup functions serve as ctor and dtor. */ #ifdef LODEPNG_COMPILE_ZLIB /*dynamic vector of unsigned ints*/ typedef struct uivector { unsigned* data; size_t size; /*size in number of unsigned longs*/ size_t allocsize; /*allocated size in bytes*/ } uivector; static void uivector_cleanup(void* p) { ((uivector*)p)->size = ((uivector*)p)->allocsize = 0; lodepng_free(((uivector*)p)->data); ((uivector*)p)->data = NULL; } /*returns 1 if success, 0 if failure ==> nothing done*/ static unsigned uivector_reserve(uivector* p, size_t allocsize) { if(allocsize > p->allocsize) { size_t newsize = (allocsize > p->allocsize * 2) ? allocsize : (allocsize * 3 / 2); void* data = lodepng_realloc(p->data, newsize); if(data) { p->allocsize = newsize; p->data = (unsigned*)data; } else return 0; /*error: not enough memory*/ } return 1; } /*returns 1 if success, 0 if failure ==> nothing done*/ static unsigned uivector_resize(uivector* p, size_t size) { if(!uivector_reserve(p, size * sizeof(unsigned))) return 0; p->size = size; return 1; /*success*/ } /*resize and give all new elements the value*/ static unsigned uivector_resizev(uivector* p, size_t size, unsigned value) { size_t oldsize = p->size, i; if(!uivector_resize(p, size)) return 0; for(i = oldsize; i < size; ++i) p->data[i] = value; return 1; } static void uivector_init(uivector* p) { p->data = NULL; p->size = p->allocsize = 0; } #ifdef LODEPNG_COMPILE_ENCODER /*returns 1 if success, 0 if failure ==> nothing done*/ static unsigned uivector_push_back(uivector* p, unsigned c) { if(!uivector_resize(p, p->size + 1)) return 0; p->data[p->size - 1] = c; return 1; } #endif /*LODEPNG_COMPILE_ENCODER*/ #endif /*LODEPNG_COMPILE_ZLIB*/ /* /////////////////////////////////////////////////////////////////////////// */ /*dynamic vector of unsigned chars*/ typedef struct ucvector { unsigned char* data; size_t size; /*used size*/ size_t allocsize; /*allocated size*/ } ucvector; /*returns 1 if success, 0 if failure ==> nothing done*/ static unsigned ucvector_reserve(ucvector* p, size_t allocsize) { if(allocsize > p->allocsize) { size_t newsize = (allocsize > p->allocsize * 2) ? allocsize : (allocsize * 3 / 2); void* data = lodepng_realloc(p->data, newsize); if(data) { p->allocsize = newsize; p->data = (unsigned char*)data; } else return 0; /*error: not enough memory*/ } return 1; } /*returns 1 if success, 0 if failure ==> nothing done*/ static unsigned ucvector_resize(ucvector* p, size_t size) { if(!ucvector_reserve(p, size * sizeof(unsigned char))) return 0; p->size = size; return 1; /*success*/ } #ifdef LODEPNG_COMPILE_PNG static void ucvector_cleanup(void* p) { ((ucvector*)p)->size = ((ucvector*)p)->allocsize = 0; lodepng_free(((ucvector*)p)->data); ((ucvector*)p)->data = NULL; } static void ucvector_init(ucvector* p) { p->data = NULL; p->size = p->allocsize = 0; } #endif /*LODEPNG_COMPILE_PNG*/ #ifdef LODEPNG_COMPILE_ZLIB /*you can both convert from vector to buffer&size and vica versa. If you use init_buffer to take over a buffer and size, it is not needed to use cleanup*/ static void ucvector_init_buffer(ucvector* p, unsigned char* buffer, size_t size) { p->data = buffer; p->allocsize = p->size = size; } #endif /*LODEPNG_COMPILE_ZLIB*/ #if (defined(LODEPNG_COMPILE_PNG) && defined(LODEPNG_COMPILE_ANCILLARY_CHUNKS)) || defined(LODEPNG_COMPILE_ENCODER) /*returns 1 if success, 0 if failure ==> nothing done*/ static unsigned ucvector_push_back(ucvector* p, unsigned char c) { if(!ucvector_resize(p, p->size + 1)) return 0; p->data[p->size - 1] = c; return 1; } #endif /*defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_ENCODER)*/ /* ////////////////////////////////////////////////////////////////////////// */ #ifdef LODEPNG_COMPILE_PNG #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS /*returns 1 if success, 0 if failure ==> nothing done*/ static unsigned string_resize(char** out, size_t size) { char* data = (char*)lodepng_realloc(*out, size + 1); if(data) { data[size] = 0; /*null termination char*/ *out = data; } return data != 0; } /*init a {char*, size_t} pair for use as string*/ static void string_init(char** out) { *out = NULL; string_resize(out, 0); } /*free the above pair again*/ static void string_cleanup(char** out) { lodepng_free(*out); *out = NULL; } static void string_set(char** out, const char* in) { size_t insize = strlen(in), i; if(string_resize(out, insize)) { for(i = 0; i != insize; ++i) { (*out)[i] = in[i]; } } } #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ #endif /*LODEPNG_COMPILE_PNG*/ /* ////////////////////////////////////////////////////////////////////////// */ unsigned lodepng_read32bitInt(const unsigned char* buffer) { return (unsigned)((buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]); } #if defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_ENCODER) /*buffer must have at least 4 allocated bytes available*/ static void lodepng_set32bitInt(unsigned char* buffer, unsigned value) { buffer[0] = (unsigned char)((value >> 24) & 0xff); buffer[1] = (unsigned char)((value >> 16) & 0xff); buffer[2] = (unsigned char)((value >> 8) & 0xff); buffer[3] = (unsigned char)((value ) & 0xff); } #endif /*defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_ENCODER)*/ #ifdef LODEPNG_COMPILE_ENCODER static void lodepng_add32bitInt(ucvector* buffer, unsigned value) { ucvector_resize(buffer, buffer->size + 4); /*todo: give error if resize failed*/ lodepng_set32bitInt(&buffer->data[buffer->size - 4], value); } #endif /*LODEPNG_COMPILE_ENCODER*/ /* ////////////////////////////////////////////////////////////////////////// */ /* / File IO / */ /* ////////////////////////////////////////////////////////////////////////// */ #ifdef LODEPNG_COMPILE_DISK /* returns negative value on error. This should be pure C compatible, so no fstat. */ static long lodepng_filesize(const char* filename) { FILE* file; long size; file = fopen(filename, "rb"); if(!file) return -1; if(fseek(file, 0, SEEK_END) != 0) { fclose(file); return -1; } size = ftell(file); /* It may give LONG_MAX as directory size, this is invalid for us. */ if(size == LONG_MAX) size = -1; fclose(file); return size; } /* load file into buffer that already has the correct allocated size. Returns error code.*/ static unsigned lodepng_buffer_file(unsigned char* out, size_t size, const char* filename) { FILE* file; size_t readsize; file = fopen(filename, "rb"); if(!file) return 78; readsize = fread(out, 1, size, file); fclose(file); if (readsize != size) return 78; return 0; } unsigned lodepng_load_file(unsigned char** out, size_t* outsize, const char* filename) { long size = lodepng_filesize(filename); if (size < 0) return 78; *outsize = (size_t)size; *out = (unsigned char*)lodepng_malloc((size_t)size); if(!(*out) && size > 0) return 83; /*the above malloc failed*/ return lodepng_buffer_file(*out, (size_t)size, filename); } /*write given buffer to the file, overwriting the file, it doesn't append to it.*/ unsigned lodepng_save_file(const unsigned char* buffer, size_t buffersize, const char* filename) { FILE* file; file = fopen(filename, "wb" ); if(!file) return 79; fwrite((char*)buffer , 1 , buffersize, file); fclose(file); return 0; } #endif /*LODEPNG_COMPILE_DISK*/ /* ////////////////////////////////////////////////////////////////////////// */ /* ////////////////////////////////////////////////////////////////////////// */ /* // End of common code and tools. Begin of Zlib related code. // */ /* ////////////////////////////////////////////////////////////////////////// */ /* ////////////////////////////////////////////////////////////////////////// */ #ifdef LODEPNG_COMPILE_ZLIB #ifdef LODEPNG_COMPILE_ENCODER /*TODO: this ignores potential out of memory errors*/ #define addBitToStream(/*size_t**/ bitpointer, /*ucvector**/ bitstream, /*unsigned char*/ bit)\ {\ /*add a new byte at the end*/\ if(((*bitpointer) & 7) == 0) ucvector_push_back(bitstream, (unsigned char)0);\ /*earlier bit of huffman code is in a lesser significant bit of an earlier byte*/\ (bitstream->data[bitstream->size - 1]) |= (bit << ((*bitpointer) & 0x7));\ ++(*bitpointer);\ } static void addBitsToStream(size_t* bitpointer, ucvector* bitstream, unsigned value, size_t nbits) { size_t i; for(i = 0; i != nbits; ++i) addBitToStream(bitpointer, bitstream, (unsigned char)((value >> i) & 1)); } static void addBitsToStreamReversed(size_t* bitpointer, ucvector* bitstream, unsigned value, size_t nbits) { size_t i; for(i = 0; i != nbits; ++i) addBitToStream(bitpointer, bitstream, (unsigned char)((value >> (nbits - 1 - i)) & 1)); } #endif /*LODEPNG_COMPILE_ENCODER*/ #ifdef LODEPNG_COMPILE_DECODER #define READBIT(bitpointer, bitstream) ((bitstream[bitpointer >> 3] >> (bitpointer & 0x7)) & (unsigned char)1) static unsigned char readBitFromStream(size_t* bitpointer, const unsigned char* bitstream) { unsigned char result = (unsigned char)(READBIT(*bitpointer, bitstream)); ++(*bitpointer); return result; } static unsigned readBitsFromStream(size_t* bitpointer, const unsigned char* bitstream, size_t nbits) { unsigned result = 0, i; for(i = 0; i != nbits; ++i) { result += ((unsigned)READBIT(*bitpointer, bitstream)) << i; ++(*bitpointer); } return result; } #endif /*LODEPNG_COMPILE_DECODER*/ /* ////////////////////////////////////////////////////////////////////////// */ /* / Deflate - Huffman / */ /* ////////////////////////////////////////////////////////////////////////// */ #define FIRST_LENGTH_CODE_INDEX 257 #define LAST_LENGTH_CODE_INDEX 285 /*256 literals, the end code, some length codes, and 2 unused codes*/ #define NUM_DEFLATE_CODE_SYMBOLS 288 /*the distance codes have their own symbols, 30 used, 2 unused*/ #define NUM_DISTANCE_SYMBOLS 32 /*the code length codes. 0-15: code lengths, 16: copy previous 3-6 times, 17: 3-10 zeros, 18: 11-138 zeros*/ #define NUM_CODE_LENGTH_CODES 19 /*the base lengths represented by codes 257-285*/ static const unsigned LENGTHBASE[29] = {3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258}; /*the extra bits used by codes 257-285 (added to base length)*/ static const unsigned LENGTHEXTRA[29] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0}; /*the base backwards distances (the bits of distance codes appear after length codes and use their own huffman tree)*/ static const unsigned DISTANCEBASE[30] = {1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577}; /*the extra bits of backwards distances (added to base)*/ static const unsigned DISTANCEEXTRA[30] = {0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13}; /*the order in which "code length alphabet code lengths" are stored, out of this the huffman tree of the dynamic huffman tree lengths is generated*/ static const unsigned CLCL_ORDER[NUM_CODE_LENGTH_CODES] = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; /* ////////////////////////////////////////////////////////////////////////// */ /* Huffman tree struct, containing multiple representations of the tree */ typedef struct HuffmanTree { unsigned* tree2d; unsigned* tree1d; unsigned* lengths; /*the lengths of the codes of the 1d-tree*/ unsigned maxbitlen; /*maximum number of bits a single code can get*/ unsigned numcodes; /*number of symbols in the alphabet = number of codes*/ } HuffmanTree; /*function used for debug purposes to draw the tree in ascii art with C++*/ /* static void HuffmanTree_draw(HuffmanTree* tree) { std::cout << "tree. length: " << tree->numcodes << " maxbitlen: " << tree->maxbitlen << std::endl; for(size_t i = 0; i != tree->tree1d.size; ++i) { if(tree->lengths.data[i]) std::cout << i << " " << tree->tree1d.data[i] << " " << tree->lengths.data[i] << std::endl; } std::cout << std::endl; }*/ static void HuffmanTree_init(HuffmanTree* tree) { tree->tree2d = 0; tree->tree1d = 0; tree->lengths = 0; } static void HuffmanTree_cleanup(HuffmanTree* tree) { lodepng_free(tree->tree2d); lodepng_free(tree->tree1d); lodepng_free(tree->lengths); } /*the tree representation used by the decoder. return value is error*/ static unsigned HuffmanTree_make2DTree(HuffmanTree* tree) { unsigned nodefilled = 0; /*up to which node it is filled*/ unsigned treepos = 0; /*position in the tree (1 of the numcodes columns)*/ unsigned n, i; tree->tree2d = (unsigned*)lodepng_malloc(tree->numcodes * 2 * sizeof(unsigned)); if(!tree->tree2d) return 83; /*alloc fail*/ /* convert tree1d[] to tree2d[][]. In the 2D array, a value of 32767 means uninited, a value >= numcodes is an address to another bit, a value < numcodes is a code. The 2 rows are the 2 possible bit values (0 or 1), there are as many columns as codes - 1. A good huffman tree has N * 2 - 1 nodes, of which N - 1 are internal nodes. Here, the internal nodes are stored (what their 0 and 1 option point to). There is only memory for such good tree currently, if there are more nodes (due to too long length codes), error 55 will happen */ for(n = 0; n < tree->numcodes * 2; ++n) { tree->tree2d[n] = 32767; /*32767 here means the tree2d isn't filled there yet*/ } for(n = 0; n < tree->numcodes; ++n) /*the codes*/ { for(i = 0; i != tree->lengths[n]; ++i) /*the bits for this code*/ { unsigned char bit = (unsigned char)((tree->tree1d[n] >> (tree->lengths[n] - i - 1)) & 1); /*oversubscribed, see comment in lodepng_error_text*/ if(treepos > 2147483647 || treepos + 2 > tree->numcodes) return 55; if(tree->tree2d[2 * treepos + bit] == 32767) /*not yet filled in*/ { if(i + 1 == tree->lengths[n]) /*last bit*/ { tree->tree2d[2 * treepos + bit] = n; /*put the current code in it*/ treepos = 0; } else { /*put address of the next step in here, first that address has to be found of course (it's just nodefilled + 1)...*/ ++nodefilled; /*addresses encoded with numcodes added to it*/ tree->tree2d[2 * treepos + bit] = nodefilled + tree->numcodes; treepos = nodefilled; } } else treepos = tree->tree2d[2 * treepos + bit] - tree->numcodes; } } for(n = 0; n < tree->numcodes * 2; ++n) { if(tree->tree2d[n] == 32767) tree->tree2d[n] = 0; /*remove possible remaining 32767's*/ } return 0; } /* Second step for the ...makeFromLengths and ...makeFromFrequencies functions. numcodes, lengths and maxbitlen must already be filled in correctly. return value is error. */ static unsigned HuffmanTree_makeFromLengths2(HuffmanTree* tree) { uivector blcount; uivector nextcode; unsigned error = 0; unsigned bits, n; uivector_init(&blcount); uivector_init(&nextcode); tree->tree1d = (unsigned*)lodepng_malloc(tree->numcodes * sizeof(unsigned)); if(!tree->tree1d) error = 83; /*alloc fail*/ if(!uivector_resizev(&blcount, tree->maxbitlen + 1, 0) || !uivector_resizev(&nextcode, tree->maxbitlen + 1, 0)) error = 83; /*alloc fail*/ if(!error) { /*step 1: count number of instances of each code length*/ for(bits = 0; bits != tree->numcodes; ++bits) ++blcount.data[tree->lengths[bits]]; /*step 2: generate the nextcode values*/ for(bits = 1; bits <= tree->maxbitlen; ++bits) { nextcode.data[bits] = (nextcode.data[bits - 1] + blcount.data[bits - 1]) << 1; } /*step 3: generate all the codes*/ for(n = 0; n != tree->numcodes; ++n) { if(tree->lengths[n] != 0) tree->tree1d[n] = nextcode.data[tree->lengths[n]]++; } } uivector_cleanup(&blcount); uivector_cleanup(&nextcode); if(!error) return HuffmanTree_make2DTree(tree); else return error; } /* given the code lengths (as stored in the PNG file), generate the tree as defined by Deflate. maxbitlen is the maximum bits that a code in the tree can have. return value is error. */ static unsigned HuffmanTree_makeFromLengths(HuffmanTree* tree, const unsigned* bitlen, size_t numcodes, unsigned maxbitlen) { unsigned i; tree->lengths = (unsigned*)lodepng_malloc(numcodes * sizeof(unsigned)); if(!tree->lengths) return 83; /*alloc fail*/ for(i = 0; i != numcodes; ++i) tree->lengths[i] = bitlen[i]; tree->numcodes = (unsigned)numcodes; /*number of symbols*/ tree->maxbitlen = maxbitlen; return HuffmanTree_makeFromLengths2(tree); } #ifdef LODEPNG_COMPILE_ENCODER /*BPM: Boundary Package Merge, see "A Fast and Space-Economical Algorithm for Length-Limited Coding", Jyrki Katajainen, Alistair Moffat, Andrew Turpin, 1995.*/ /*chain node for boundary package merge*/ typedef struct BPMNode { int weight; /*the sum of all weights in this chain*/ unsigned index; /*index of this leaf node (called "count" in the paper)*/ struct BPMNode* tail; /*the next nodes in this chain (null if last)*/ int in_use; } BPMNode; /*lists of chains*/ typedef struct BPMLists { /*memory pool*/ unsigned memsize; BPMNode* memory; unsigned numfree; unsigned nextfree; BPMNode** freelist; /*two heads of lookahead chains per list*/ unsigned listsize; BPMNode** chains0; BPMNode** chains1; } BPMLists; /*creates a new chain node with the given parameters, from the memory in the lists */ static BPMNode* bpmnode_create(BPMLists* lists, int weight, unsigned index, BPMNode* tail) { unsigned i; BPMNode* result; /*memory full, so garbage collect*/ if(lists->nextfree >= lists->numfree) { /*mark only those that are in use*/ for(i = 0; i != lists->memsize; ++i) lists->memory[i].in_use = 0; for(i = 0; i != lists->listsize; ++i) { BPMNode* node; for(node = lists->chains0[i]; node != 0; node = node->tail) node->in_use = 1; for(node = lists->chains1[i]; node != 0; node = node->tail) node->in_use = 1; } /*collect those that are free*/ lists->numfree = 0; for(i = 0; i != lists->memsize; ++i) { if(!lists->memory[i].in_use) lists->freelist[lists->numfree++] = &lists->memory[i]; } lists->nextfree = 0; } result = lists->freelist[lists->nextfree++]; result->weight = weight; result->index = index; result->tail = tail; return result; } /*sort the leaves with stable mergesort*/ static void bpmnode_sort(BPMNode* leaves, size_t num) { BPMNode* mem = (BPMNode*)lodepng_malloc(sizeof(*leaves) * num); size_t width, counter = 0; for(width = 1; width < num; width *= 2) { BPMNode* a = (counter & 1) ? mem : leaves; BPMNode* b = (counter & 1) ? leaves : mem; size_t p; for(p = 0; p < num; p += 2 * width) { size_t q = (p + width > num) ? num : (p + width); size_t r = (p + 2 * width > num) ? num : (p + 2 * width); size_t i = p, j = q, k; for(k = p; k < r; k++) { if(i < q && (j >= r || a[i].weight <= a[j].weight)) b[k] = a[i++]; else b[k] = a[j++]; } } counter++; } if(counter & 1) memcpy(leaves, mem, sizeof(*leaves) * num); lodepng_free(mem); } /*Boundary Package Merge step, numpresent is the amount of leaves, and c is the current chain.*/ static void boundaryPM(BPMLists* lists, BPMNode* leaves, size_t numpresent, int c, int num) { unsigned lastindex = lists->chains1[c]->index; if(c == 0) { if(lastindex >= numpresent) return; lists->chains0[c] = lists->chains1[c]; lists->chains1[c] = bpmnode_create(lists, leaves[lastindex].weight, lastindex + 1, 0); } else { /*sum of the weights of the head nodes of the previous lookahead chains.*/ int sum = lists->chains0[c - 1]->weight + lists->chains1[c - 1]->weight; lists->chains0[c] = lists->chains1[c]; if(lastindex < numpresent && sum > leaves[lastindex].weight) { lists->chains1[c] = bpmnode_create(lists, leaves[lastindex].weight, lastindex + 1, lists->chains1[c]->tail); return; } lists->chains1[c] = bpmnode_create(lists, sum, lastindex, lists->chains1[c - 1]); /*in the end we are only interested in the chain of the last list, so no need to recurse if we're at the last one (this gives measurable speedup)*/ if(num + 1 < (int)(2 * numpresent - 2)) { boundaryPM(lists, leaves, numpresent, c - 1, num); boundaryPM(lists, leaves, numpresent, c - 1, num); } } } unsigned lodepng_huffman_code_lengths(unsigned* lengths, const unsigned* frequencies, size_t numcodes, unsigned maxbitlen) { unsigned error = 0; unsigned i; size_t numpresent = 0; /*number of symbols with non-zero frequency*/ BPMNode* leaves; /*the symbols, only those with > 0 frequency*/ if(numcodes == 0) return 80; /*error: a tree of 0 symbols is not supposed to be made*/ if((1u << maxbitlen) < numcodes) return 80; /*error: represent all symbols*/ leaves = (BPMNode*)lodepng_malloc(numcodes * sizeof(*leaves)); if(!leaves) return 83; /*alloc fail*/ for(i = 0; i != numcodes; ++i) { if(frequencies[i] > 0) { leaves[numpresent].weight = (int)frequencies[i]; leaves[numpresent].index = i; ++numpresent; } } for(i = 0; i != numcodes; ++i) lengths[i] = 0; /*ensure at least two present symbols. There should be at least one symbol according to RFC 1951 section 3.2.7. Some decoders incorrectly require two. To make these work as well ensure there are at least two symbols. The Package-Merge code below also doesn't work correctly if there's only one symbol, it'd give it the theoritical 0 bits but in practice zlib wants 1 bit*/ if(numpresent == 0) { lengths[0] = lengths[1] = 1; /*note that for RFC 1951 section 3.2.7, only lengths[0] = 1 is needed*/ } else if(numpresent == 1) { lengths[leaves[0].index] = 1; lengths[leaves[0].index == 0 ? 1 : 0] = 1; } else { BPMLists lists; BPMNode* node; bpmnode_sort(leaves, numpresent); lists.listsize = maxbitlen; lists.memsize = 2 * maxbitlen * (maxbitlen + 1); lists.nextfree = 0; lists.numfree = lists.memsize; lists.memory = (BPMNode*)lodepng_malloc(lists.memsize * sizeof(*lists.memory)); lists.freelist = (BPMNode**)lodepng_malloc(lists.memsize * sizeof(BPMNode*)); lists.chains0 = (BPMNode**)lodepng_malloc(lists.listsize * sizeof(BPMNode*)); lists.chains1 = (BPMNode**)lodepng_malloc(lists.listsize * sizeof(BPMNode*)); if(!lists.memory || !lists.freelist || !lists.chains0 || !lists.chains1) error = 83; /*alloc fail*/ if(!error) { for(i = 0; i != lists.memsize; ++i) lists.freelist[i] = &lists.memory[i]; bpmnode_create(&lists, leaves[0].weight, 1, 0); bpmnode_create(&lists, leaves[1].weight, 2, 0); for(i = 0; i != lists.listsize; ++i) { lists.chains0[i] = &lists.memory[0]; lists.chains1[i] = &lists.memory[1]; } /*each boundaryPM call adds one chain to the last list, and we need 2 * numpresent - 2 chains.*/ for(i = 2; i != 2 * numpresent - 2; ++i) boundaryPM(&lists, leaves, numpresent, (int)maxbitlen - 1, (int)i); for(node = lists.chains1[maxbitlen - 1]; node; node = node->tail) { for(i = 0; i != node->index; ++i) ++lengths[leaves[i].index]; } } lodepng_free(lists.memory); lodepng_free(lists.freelist); lodepng_free(lists.chains0); lodepng_free(lists.chains1); } lodepng_free(leaves); return error; } /*Create the Huffman tree given the symbol frequencies*/ static unsigned HuffmanTree_makeFromFrequencies(HuffmanTree* tree, const unsigned* frequencies, size_t mincodes, size_t numcodes, unsigned maxbitlen) { unsigned error = 0; while(!frequencies[numcodes - 1] && numcodes > mincodes) --numcodes; /*trim zeroes*/ tree->maxbitlen = maxbitlen; tree->numcodes = (unsigned)numcodes; /*number of symbols*/ tree->lengths = (unsigned*)lodepng_realloc(tree->lengths, numcodes * sizeof(unsigned)); if(!tree->lengths) return 83; /*alloc fail*/ /*initialize all lengths to 0*/ memset(tree->lengths, 0, numcodes * sizeof(unsigned)); error = lodepng_huffman_code_lengths(tree->lengths, frequencies, numcodes, maxbitlen); if(!error) error = HuffmanTree_makeFromLengths2(tree); return error; } static unsigned HuffmanTree_getCode(const HuffmanTree* tree, unsigned index) { return tree->tree1d[index]; } static unsigned HuffmanTree_getLength(const HuffmanTree* tree, unsigned index) { return tree->lengths[index]; } #endif /*LODEPNG_COMPILE_ENCODER*/ /*get the literal and length code tree of a deflated block with fixed tree, as per the deflate specification*/ static unsigned generateFixedLitLenTree(HuffmanTree* tree) { unsigned i, error = 0; unsigned* bitlen = (unsigned*)lodepng_malloc(NUM_DEFLATE_CODE_SYMBOLS * sizeof(unsigned)); if(!bitlen) return 83; /*alloc fail*/ /*288 possible codes: 0-255=literals, 256=endcode, 257-285=lengthcodes, 286-287=unused*/ for(i = 0; i <= 143; ++i) bitlen[i] = 8; for(i = 144; i <= 255; ++i) bitlen[i] = 9; for(i = 256; i <= 279; ++i) bitlen[i] = 7; for(i = 280; i <= 287; ++i) bitlen[i] = 8; error = HuffmanTree_makeFromLengths(tree, bitlen, NUM_DEFLATE_CODE_SYMBOLS, 15); lodepng_free(bitlen); return error; } /*get the distance code tree of a deflated block with fixed tree, as specified in the deflate specification*/ static unsigned generateFixedDistanceTree(HuffmanTree* tree) { unsigned i, error = 0; unsigned* bitlen = (unsigned*)lodepng_malloc(NUM_DISTANCE_SYMBOLS * sizeof(unsigned)); if(!bitlen) return 83; /*alloc fail*/ /*there are 32 distance codes, but 30-31 are unused*/ for(i = 0; i != NUM_DISTANCE_SYMBOLS; ++i) bitlen[i] = 5; error = HuffmanTree_makeFromLengths(tree, bitlen, NUM_DISTANCE_SYMBOLS, 15); lodepng_free(bitlen); return error; } #ifdef LODEPNG_COMPILE_DECODER /* returns the code, or (unsigned)(-1) if error happened inbitlength is the length of the complete buffer, in bits (so its byte length times 8) */ static unsigned huffmanDecodeSymbol(const unsigned char* in, size_t* bp, const HuffmanTree* codetree, size_t inbitlength) { unsigned treepos = 0, ct; for(;;) { if(*bp >= inbitlength) return (unsigned)(-1); /*error: end of input memory reached without endcode*/ /* decode the symbol from the tree. The "readBitFromStream" code is inlined in the expression below because this is the biggest bottleneck while decoding */ ct = codetree->tree2d[(treepos << 1) + READBIT(*bp, in)]; ++(*bp); if(ct < codetree->numcodes) return ct; /*the symbol is decoded, return it*/ else treepos = ct - codetree->numcodes; /*symbol not yet decoded, instead move tree position*/ if(treepos >= codetree->numcodes) return (unsigned)(-1); /*error: it appeared outside the codetree*/ } } #endif /*LODEPNG_COMPILE_DECODER*/ #ifdef LODEPNG_COMPILE_DECODER /* ////////////////////////////////////////////////////////////////////////// */ /* / Inflator (Decompressor) / */ /* ////////////////////////////////////////////////////////////////////////// */ /*get the tree of a deflated block with fixed tree, as specified in the deflate specification*/ static void getTreeInflateFixed(HuffmanTree* tree_ll, HuffmanTree* tree_d) { /*TODO: check for out of memory errors*/ generateFixedLitLenTree(tree_ll); generateFixedDistanceTree(tree_d); } /*get the tree of a deflated block with dynamic tree, the tree itself is also Huffman compressed with a known tree*/ static unsigned getTreeInflateDynamic(HuffmanTree* tree_ll, HuffmanTree* tree_d, const unsigned char* in, size_t* bp, size_t inlength) { /*make sure that length values that aren't filled in will be 0, or a wrong tree will be generated*/ unsigned error = 0; unsigned n, HLIT, HDIST, HCLEN, i; size_t inbitlength = inlength * 8; /*see comments in deflateDynamic for explanation of the context and these variables, it is analogous*/ unsigned* bitlen_ll = 0; /*lit,len code lengths*/ unsigned* bitlen_d = 0; /*dist code lengths*/ /*code length code lengths ("clcl"), the bit lengths of the huffman tree used to compress bitlen_ll and bitlen_d*/ unsigned* bitlen_cl = 0; HuffmanTree tree_cl; /*the code tree for code length codes (the huffman tree for compressed huffman trees)*/ if((*bp) + 14 > (inlength << 3)) return 49; /*error: the bit pointer is or will go past the memory*/ /*number of literal/length codes + 257. Unlike the spec, the value 257 is added to it here already*/ HLIT = readBitsFromStream(bp, in, 5) + 257; /*number of distance codes. Unlike the spec, the value 1 is added to it here already*/ HDIST = readBitsFromStream(bp, in, 5) + 1; /*number of code length codes. Unlike the spec, the value 4 is added to it here already*/ HCLEN = readBitsFromStream(bp, in, 4) + 4; if((*bp) + HCLEN * 3 > (inlength << 3)) return 50; /*error: the bit pointer is or will go past the memory*/ HuffmanTree_init(&tree_cl); while(!error) { /*read the code length codes out of 3 * (amount of code length codes) bits*/ bitlen_cl = (unsigned*)lodepng_malloc(NUM_CODE_LENGTH_CODES * sizeof(unsigned)); if(!bitlen_cl) ERROR_BREAK(83 /*alloc fail*/); for(i = 0; i != NUM_CODE_LENGTH_CODES; ++i) { if(i < HCLEN) bitlen_cl[CLCL_ORDER[i]] = readBitsFromStream(bp, in, 3); else bitlen_cl[CLCL_ORDER[i]] = 0; /*if not, it must stay 0*/ } error = HuffmanTree_makeFromLengths(&tree_cl, bitlen_cl, NUM_CODE_LENGTH_CODES, 7); if(error) break; /*now we can use this tree to read the lengths for the tree that this function will return*/ bitlen_ll = (unsigned*)lodepng_malloc(NUM_DEFLATE_CODE_SYMBOLS * sizeof(unsigned)); bitlen_d = (unsigned*)lodepng_malloc(NUM_DISTANCE_SYMBOLS * sizeof(unsigned)); if(!bitlen_ll || !bitlen_d) ERROR_BREAK(83 /*alloc fail*/); for(i = 0; i != NUM_DEFLATE_CODE_SYMBOLS; ++i) bitlen_ll[i] = 0; for(i = 0; i != NUM_DISTANCE_SYMBOLS; ++i) bitlen_d[i] = 0; /*i is the current symbol we're reading in the part that contains the code lengths of lit/len and dist codes*/ i = 0; while(i < HLIT + HDIST) { unsigned code = huffmanDecodeSymbol(in, bp, &tree_cl, inbitlength); if(code <= 15) /*a length code*/ { if(i < HLIT) bitlen_ll[i] = code; else bitlen_d[i - HLIT] = code; ++i; } else if(code == 16) /*repeat previous*/ { unsigned replength = 3; /*read in the 2 bits that indicate repeat length (3-6)*/ unsigned value; /*set value to the previous code*/ if(i == 0) ERROR_BREAK(54); /*can't repeat previous if i is 0*/ if((*bp + 2) > inbitlength) ERROR_BREAK(50); /*error, bit pointer jumps past memory*/ replength += readBitsFromStream(bp, in, 2); if(i < HLIT + 1) value = bitlen_ll[i - 1]; else value = bitlen_d[i - HLIT - 1]; /*repeat this value in the next lengths*/ for(n = 0; n < replength; ++n) { if(i >= HLIT + HDIST) ERROR_BREAK(13); /*error: i is larger than the amount of codes*/ if(i < HLIT) bitlen_ll[i] = value; else bitlen_d[i - HLIT] = value; ++i; } } else if(code == 17) /*repeat "0" 3-10 times*/ { unsigned replength = 3; /*read in the bits that indicate repeat length*/ if((*bp + 3) > inbitlength) ERROR_BREAK(50); /*error, bit pointer jumps past memory*/ replength += readBitsFromStream(bp, in, 3); /*repeat this value in the next lengths*/ for(n = 0; n < replength; ++n) { if(i >= HLIT + HDIST) ERROR_BREAK(14); /*error: i is larger than the amount of codes*/ if(i < HLIT) bitlen_ll[i] = 0; else bitlen_d[i - HLIT] = 0; ++i; } } else if(code == 18) /*repeat "0" 11-138 times*/ { unsigned replength = 11; /*read in the bits that indicate repeat length*/ if((*bp + 7) > inbitlength) ERROR_BREAK(50); /*error, bit pointer jumps past memory*/ replength += readBitsFromStream(bp, in, 7); /*repeat this value in the next lengths*/ for(n = 0; n < replength; ++n) { if(i >= HLIT + HDIST) ERROR_BREAK(15); /*error: i is larger than the amount of codes*/ if(i < HLIT) bitlen_ll[i] = 0; else bitlen_d[i - HLIT] = 0; ++i; } } else /*if(code == (unsigned)(-1))*/ /*huffmanDecodeSymbol returns (unsigned)(-1) in case of error*/ { if(code == (unsigned)(-1)) { /*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol (10=no endcode, 11=wrong jump outside of tree)*/ error = (*bp) > inbitlength ? 10 : 11; } else error = 16; /*unexisting code, this can never happen*/ break; } } if(error) break; if(bitlen_ll[256] == 0) ERROR_BREAK(64); /*the length of the end code 256 must be larger than 0*/ /*now we've finally got HLIT and HDIST, so generate the code trees, and the function is done*/ error = HuffmanTree_makeFromLengths(tree_ll, bitlen_ll, NUM_DEFLATE_CODE_SYMBOLS, 15); if(error) break; error = HuffmanTree_makeFromLengths(tree_d, bitlen_d, NUM_DISTANCE_SYMBOLS, 15); break; /*end of error-while*/ } lodepng_free(bitlen_cl); lodepng_free(bitlen_ll); lodepng_free(bitlen_d); HuffmanTree_cleanup(&tree_cl); return error; } /*inflate a block with dynamic of fixed Huffman tree*/ static unsigned inflateHuffmanBlock(ucvector* out, const unsigned char* in, size_t* bp, size_t* pos, size_t inlength, unsigned btype) { unsigned error = 0; HuffmanTree tree_ll; /*the huffman tree for literal and length codes*/ HuffmanTree tree_d; /*the huffman tree for distance codes*/ size_t inbitlength = inlength * 8; HuffmanTree_init(&tree_ll); HuffmanTree_init(&tree_d); if(btype == 1) getTreeInflateFixed(&tree_ll, &tree_d); else if(btype == 2) error = getTreeInflateDynamic(&tree_ll, &tree_d, in, bp, inlength); while(!error) /*decode all symbols until end reached, breaks at end code*/ { /*code_ll is literal, length or end code*/ unsigned code_ll = huffmanDecodeSymbol(in, bp, &tree_ll, inbitlength); if(code_ll <= 255) /*literal symbol*/ { /*ucvector_push_back would do the same, but for some reason the two lines below run 10% faster*/ if(!ucvector_resize(out, (*pos) + 1)) ERROR_BREAK(83 /*alloc fail*/); out->data[*pos] = (unsigned char)code_ll; ++(*pos); } else if(code_ll >= FIRST_LENGTH_CODE_INDEX && code_ll <= LAST_LENGTH_CODE_INDEX) /*length code*/ { unsigned code_d, distance; unsigned numextrabits_l, numextrabits_d; /*extra bits for length and distance*/ size_t start, forward, backward, length; /*part 1: get length base*/ length = LENGTHBASE[code_ll - FIRST_LENGTH_CODE_INDEX]; /*part 2: get extra bits and add the value of that to length*/ numextrabits_l = LENGTHEXTRA[code_ll - FIRST_LENGTH_CODE_INDEX]; if((*bp + numextrabits_l) > inbitlength) ERROR_BREAK(51); /*error, bit pointer will jump past memory*/ length += readBitsFromStream(bp, in, numextrabits_l); /*part 3: get distance code*/ code_d = huffmanDecodeSymbol(in, bp, &tree_d, inbitlength); if(code_d > 29) { if(code_ll == (unsigned)(-1)) /*huffmanDecodeSymbol returns (unsigned)(-1) in case of error*/ { /*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol (10=no endcode, 11=wrong jump outside of tree)*/ error = (*bp) > inlength * 8 ? 10 : 11; } else error = 18; /*error: invalid distance code (30-31 are never used)*/ break; } distance = DISTANCEBASE[code_d]; /*part 4: get extra bits from distance*/ numextrabits_d = DISTANCEEXTRA[code_d]; if((*bp + numextrabits_d) > inbitlength) ERROR_BREAK(51); /*error, bit pointer will jump past memory*/ distance += readBitsFromStream(bp, in, numextrabits_d); /*part 5: fill in all the out[n] values based on the length and dist*/ start = (*pos); if(distance > start) ERROR_BREAK(52); /*too long backward distance*/ backward = start - distance; if(!ucvector_resize(out, (*pos) + length)) ERROR_BREAK(83 /*alloc fail*/); if (distance < length) { for(forward = 0; forward < length; ++forward) { out->data[(*pos)++] = out->data[backward++]; } } else { memcpy(out->data + *pos, out->data + backward, length); *pos += length; } } else if(code_ll == 256) { break; /*end code, break the loop*/ } else /*if(code == (unsigned)(-1))*/ /*huffmanDecodeSymbol returns (unsigned)(-1) in case of error*/ { /*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol (10=no endcode, 11=wrong jump outside of tree)*/ error = ((*bp) > inlength * 8) ? 10 : 11; break; } } HuffmanTree_cleanup(&tree_ll); HuffmanTree_cleanup(&tree_d); return error; } static unsigned inflateNoCompression(ucvector* out, const unsigned char* in, size_t* bp, size_t* pos, size_t inlength) { size_t p; unsigned LEN, NLEN, n, error = 0; /*go to first boundary of byte*/ while(((*bp) & 0x7) != 0) ++(*bp); p = (*bp) / 8; /*byte position*/ /*read LEN (2 bytes) and NLEN (2 bytes)*/ if(p + 4 >= inlength) return 52; /*error, bit pointer will jump past memory*/ LEN = in[p] + 256u * in[p + 1]; p += 2; NLEN = in[p] + 256u * in[p + 1]; p += 2; /*check if 16-bit NLEN is really the one's complement of LEN*/ if(LEN + NLEN != 65535) return 21; /*error: NLEN is not one's complement of LEN*/ if(!ucvector_resize(out, (*pos) + LEN)) return 83; /*alloc fail*/ /*read the literal data: LEN bytes are now stored in the out buffer*/ if(p + LEN > inlength) return 23; /*error: reading outside of in buffer*/ for(n = 0; n < LEN; ++n) out->data[(*pos)++] = in[p++]; (*bp) = p * 8; return error; } static unsigned lodepng_inflatev(ucvector* out, const unsigned char* in, size_t insize, const LodePNGDecompressSettings* settings) { /*bit pointer in the "in" data, current byte is bp >> 3, current bit is bp & 0x7 (from lsb to msb of the byte)*/ size_t bp = 0; unsigned BFINAL = 0; size_t pos = 0; /*byte position in the out buffer*/ unsigned error = 0; (void)settings; while(!BFINAL) { unsigned BTYPE; if(bp + 2 >= insize * 8) return 52; /*error, bit pointer will jump past memory*/ BFINAL = readBitFromStream(&bp, in); BTYPE = 1u * readBitFromStream(&bp, in); BTYPE += 2u * readBitFromStream(&bp, in); if(BTYPE == 3) return 20; /*error: invalid BTYPE*/ else if(BTYPE == 0) error = inflateNoCompression(out, in, &bp, &pos, insize); /*no compression*/ else error = inflateHuffmanBlock(out, in, &bp, &pos, insize, BTYPE); /*compression, BTYPE 01 or 10*/ if(error) return error; } return error; } unsigned lodepng_inflate(unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize, const LodePNGDecompressSettings* settings) { unsigned error; ucvector v; ucvector_init_buffer(&v, *out, *outsize); error = lodepng_inflatev(&v, in, insize, settings); *out = v.data; *outsize = v.size; return error; } static unsigned inflate(unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize, const LodePNGDecompressSettings* settings) { if(settings->custom_inflate) { return settings->custom_inflate(out, outsize, in, insize, settings); } else { return lodepng_inflate(out, outsize, in, insize, settings); } } #endif /*LODEPNG_COMPILE_DECODER*/ #ifdef LODEPNG_COMPILE_ENCODER /* ////////////////////////////////////////////////////////////////////////// */ /* / Deflator (Compressor) / */ /* ////////////////////////////////////////////////////////////////////////// */ static const size_t MAX_SUPPORTED_DEFLATE_LENGTH = 258; /*bitlen is the size in bits of the code*/ static void addHuffmanSymbol(size_t* bp, ucvector* compressed, unsigned code, unsigned bitlen) { addBitsToStreamReversed(bp, compressed, code, bitlen); } /*search the index in the array, that has the largest value smaller than or equal to the given value, given array must be sorted (if no value is smaller, it returns the size of the given array)*/ static size_t searchCodeIndex(const unsigned* array, size_t array_size, size_t value) { /*binary search (only small gain over linear). TODO: use CPU log2 instruction for getting symbols instead*/ size_t left = 1; size_t right = array_size - 1; while(left <= right) { size_t mid = (left + right) >> 1; if (array[mid] >= value) right = mid - 1; else left = mid + 1; } if(left >= array_size || array[left] > value) left--; return left; } static void addLengthDistance(uivector* values, size_t length, size_t distance) { /*values in encoded vector are those used by deflate: 0-255: literal bytes 256: end 257-285: length/distance pair (length code, followed by extra length bits, distance code, extra distance bits) 286-287: invalid*/ unsigned length_code = (unsigned)searchCodeIndex(LENGTHBASE, 29, length); unsigned extra_length = (unsigned)(length - LENGTHBASE[length_code]); unsigned dist_code = (unsigned)searchCodeIndex(DISTANCEBASE, 30, distance); unsigned extra_distance = (unsigned)(distance - DISTANCEBASE[dist_code]); uivector_push_back(values, length_code + FIRST_LENGTH_CODE_INDEX); uivector_push_back(values, extra_length); uivector_push_back(values, dist_code); uivector_push_back(values, extra_distance); } /*3 bytes of data get encoded into two bytes. The hash cannot use more than 3 bytes as input because 3 is the minimum match length for deflate*/ static const unsigned HASH_NUM_VALUES = 65536; static const unsigned HASH_BIT_MASK = 65535; /*HASH_NUM_VALUES - 1, but C90 does not like that as initializer*/ typedef struct Hash { int* head; /*hash value to head circular pos - can be outdated if went around window*/ /*circular pos to prev circular pos*/ unsigned short* chain; int* val; /*circular pos to hash value*/ /*TODO: do this not only for zeros but for any repeated byte. However for PNG it's always going to be the zeros that dominate, so not important for PNG*/ int* headz; /*similar to head, but for chainz*/ unsigned short* chainz; /*those with same amount of zeros*/ unsigned short* zeros; /*length of zeros streak, used as a second hash chain*/ } Hash; static unsigned hash_init(Hash* hash, unsigned windowsize) { unsigned i; hash->head = (int*)lodepng_malloc(sizeof(int) * HASH_NUM_VALUES); hash->val = (int*)lodepng_malloc(sizeof(int) * windowsize); hash->chain = (unsigned short*)lodepng_malloc(sizeof(unsigned short) * windowsize); hash->zeros = (unsigned short*)lodepng_malloc(sizeof(unsigned short) * windowsize); hash->headz = (int*)lodepng_malloc(sizeof(int) * (MAX_SUPPORTED_DEFLATE_LENGTH + 1)); hash->chainz = (unsigned short*)lodepng_malloc(sizeof(unsigned short) * windowsize); if(!hash->head || !hash->chain || !hash->val || !hash->headz|| !hash->chainz || !hash->zeros) { return 83; /*alloc fail*/ } /*initialize hash table*/ for(i = 0; i != HASH_NUM_VALUES; ++i) hash->head[i] = -1; for(i = 0; i != windowsize; ++i) hash->val[i] = -1; for(i = 0; i != windowsize; ++i) hash->chain[i] = i; /*same value as index indicates uninitialized*/ for(i = 0; i <= MAX_SUPPORTED_DEFLATE_LENGTH; ++i) hash->headz[i] = -1; for(i = 0; i != windowsize; ++i) hash->chainz[i] = i; /*same value as index indicates uninitialized*/ return 0; } static void hash_cleanup(Hash* hash) { lodepng_free(hash->head); lodepng_free(hash->val); lodepng_free(hash->chain); lodepng_free(hash->zeros); lodepng_free(hash->headz); lodepng_free(hash->chainz); } static unsigned getHash(const unsigned char* data, size_t size, size_t pos) { unsigned result = 0; if(pos + 2 < size) { /*A simple shift and xor hash is used. Since the data of PNGs is dominated by zeroes due to the filters, a better hash does not have a significant effect on speed in traversing the chain, and causes more time spend on calculating the hash.*/ result ^= (unsigned)(data[pos + 0] << 0u); result ^= (unsigned)(data[pos + 1] << 4u); result ^= (unsigned)(data[pos + 2] << 8u); } else { size_t amount, i; if(pos >= size) return 0; amount = size - pos; for(i = 0; i != amount; ++i) result ^= (unsigned)(data[pos + i] << (i * 8u)); } return result & HASH_BIT_MASK; } static unsigned countZeros(const unsigned char* data, size_t size, size_t pos) { const unsigned char* start = data + pos; const unsigned char* end = start + MAX_SUPPORTED_DEFLATE_LENGTH; if(end > data + size) end = data + size; data = start; while(data != end && *data == 0) ++data; /*subtracting two addresses returned as 32-bit number (max value is MAX_SUPPORTED_DEFLATE_LENGTH)*/ return (unsigned)(data - start); } /*wpos = pos & (windowsize - 1)*/ static void updateHashChain(Hash* hash, size_t wpos, unsigned hashval, unsigned short numzeros) { hash->val[wpos] = (int)hashval; if(hash->head[hashval] != -1) hash->chain[wpos] = hash->head[hashval]; hash->head[hashval] = wpos; hash->zeros[wpos] = numzeros; if(hash->headz[numzeros] != -1) hash->chainz[wpos] = hash->headz[numzeros]; hash->headz[numzeros] = wpos; } /* LZ77-encode the data. Return value is error code. The input are raw bytes, the output is in the form of unsigned integers with codes representing for example literal bytes, or length/distance pairs. It uses a hash table technique to let it encode faster. When doing LZ77 encoding, a sliding window (of windowsize) is used, and all past bytes in that window can be used as the "dictionary". A brute force search through all possible distances would be slow, and this hash technique is one out of several ways to speed this up. */ static unsigned encodeLZ77(uivector* out, Hash* hash, const unsigned char* in, size_t inpos, size_t insize, unsigned windowsize, unsigned minmatch, unsigned nicematch, unsigned lazymatching) { size_t pos; unsigned i, error = 0; /*for large window lengths, assume the user wants no compression loss. Otherwise, max hash chain length speedup.*/ unsigned maxchainlength = windowsize >= 8192 ? windowsize : windowsize / 8; unsigned maxlazymatch = windowsize >= 8192 ? MAX_SUPPORTED_DEFLATE_LENGTH : 64; unsigned usezeros = 1; /*not sure if setting it to false for windowsize < 8192 is better or worse*/ unsigned numzeros = 0; unsigned offset; /*the offset represents the distance in LZ77 terminology*/ unsigned length; unsigned lazy = 0; unsigned lazylength = 0, lazyoffset = 0; unsigned hashval; unsigned current_offset, current_length; unsigned prev_offset; const unsigned char *lastptr, *foreptr, *backptr; unsigned hashpos; if(windowsize == 0 || windowsize > 32768) return 60; /*error: windowsize smaller/larger than allowed*/ if((windowsize & (windowsize - 1)) != 0) return 90; /*error: must be power of two*/ if(nicematch > MAX_SUPPORTED_DEFLATE_LENGTH) nicematch = MAX_SUPPORTED_DEFLATE_LENGTH; for(pos = inpos; pos < insize; ++pos) { size_t wpos = pos & (windowsize - 1); /*position for in 'circular' hash buffers*/ unsigned chainlength = 0; hashval = getHash(in, insize, pos); if(usezeros && hashval == 0) { if(numzeros == 0) numzeros = countZeros(in, insize, pos); else if(pos + numzeros > insize || in[pos + numzeros - 1] != 0) --numzeros; } else { numzeros = 0; } updateHashChain(hash, wpos, hashval, numzeros); /*the length and offset found for the current position*/ length = 0; offset = 0; hashpos = hash->chain[wpos]; lastptr = &in[insize < pos + MAX_SUPPORTED_DEFLATE_LENGTH ? insize : pos + MAX_SUPPORTED_DEFLATE_LENGTH]; /*search for the longest string*/ prev_offset = 0; for(;;) { if(chainlength++ >= maxchainlength) break; current_offset = hashpos <= wpos ? wpos - hashpos : wpos - hashpos + windowsize; if(current_offset < prev_offset) break; /*stop when went completely around the circular buffer*/ prev_offset = current_offset; if(current_offset > 0) { /*test the next characters*/ foreptr = &in[pos]; backptr = &in[pos - current_offset]; /*common case in PNGs is lots of zeros. Quickly skip over them as a speedup*/ if(numzeros >= 3) { unsigned skip = hash->zeros[hashpos]; if(skip > numzeros) skip = numzeros; backptr += skip; foreptr += skip; } while(foreptr != lastptr && *backptr == *foreptr) /*maximum supported length by deflate is max length*/ { ++backptr; ++foreptr; } current_length = (unsigned)(foreptr - &in[pos]); if(current_length > length) { length = current_length; /*the longest length*/ offset = current_offset; /*the offset that is related to this longest length*/ /*jump out once a length of max length is found (speed gain). This also jumps out if length is MAX_SUPPORTED_DEFLATE_LENGTH*/ if(current_length >= nicematch) break; } } if(hashpos == hash->chain[hashpos]) break; if(numzeros >= 3 && length > numzeros) { hashpos = hash->chainz[hashpos]; if(hash->zeros[hashpos] != numzeros) break; } else { hashpos = hash->chain[hashpos]; /*outdated hash value, happens if particular value was not encountered in whole last window*/ if(hash->val[hashpos] != (int)hashval) break; } } if(lazymatching) { if(!lazy && length >= 3 && length <= maxlazymatch && length < MAX_SUPPORTED_DEFLATE_LENGTH) { lazy = 1; lazylength = length; lazyoffset = offset; continue; /*try the next byte*/ } if(lazy) { lazy = 0; if(pos == 0) ERROR_BREAK(81); if(length > lazylength + 1) { /*push the previous character as literal*/ if(!uivector_push_back(out, in[pos - 1])) ERROR_BREAK(83 /*alloc fail*/); } else { length = lazylength; offset = lazyoffset; hash->head[hashval] = -1; /*the same hashchain update will be done, this ensures no wrong alteration*/ hash->headz[numzeros] = -1; /*idem*/ --pos; } } } if(length >= 3 && offset > windowsize) ERROR_BREAK(86 /*too big (or overflown negative) offset*/); /*encode it as length/distance pair or literal value*/ if(length < 3) /*only lengths of 3 or higher are supported as length/distance pair*/ { if(!uivector_push_back(out, in[pos])) ERROR_BREAK(83 /*alloc fail*/); } else if(length < minmatch || (length == 3 && offset > 4096)) { /*compensate for the fact that longer offsets have more extra bits, a length of only 3 may be not worth it then*/ if(!uivector_push_back(out, in[pos])) ERROR_BREAK(83 /*alloc fail*/); } else { addLengthDistance(out, length, offset); for(i = 1; i < length; ++i) { ++pos; wpos = pos & (windowsize - 1); hashval = getHash(in, insize, pos); if(usezeros && hashval == 0) { if(numzeros == 0) numzeros = countZeros(in, insize, pos); else if(pos + numzeros > insize || in[pos + numzeros - 1] != 0) --numzeros; } else { numzeros = 0; } updateHashChain(hash, wpos, hashval, numzeros); } } } /*end of the loop through each character of input*/ return error; } /* /////////////////////////////////////////////////////////////////////////// */ static unsigned deflateNoCompression(ucvector* out, const unsigned char* data, size_t datasize) { /*non compressed deflate block data: 1 bit BFINAL,2 bits BTYPE,(5 bits): it jumps to start of next byte, 2 bytes LEN, 2 bytes NLEN, LEN bytes literal DATA*/ size_t i, j, numdeflateblocks = (datasize + 65534) / 65535; unsigned datapos = 0; for(i = 0; i != numdeflateblocks; ++i) { unsigned BFINAL, BTYPE, LEN, NLEN; unsigned char firstbyte; BFINAL = (i == numdeflateblocks - 1); BTYPE = 0; firstbyte = (unsigned char)(BFINAL + ((BTYPE & 1) << 1) + ((BTYPE & 2) << 1)); ucvector_push_back(out, firstbyte); LEN = 65535; if(datasize - datapos < 65535) LEN = (unsigned)datasize - datapos; NLEN = 65535 - LEN; ucvector_push_back(out, (unsigned char)(LEN & 255)); ucvector_push_back(out, (unsigned char)(LEN >> 8)); ucvector_push_back(out, (unsigned char)(NLEN & 255)); ucvector_push_back(out, (unsigned char)(NLEN >> 8)); /*Decompressed data*/ for(j = 0; j < 65535 && datapos < datasize; ++j) { ucvector_push_back(out, data[datapos++]); } } return 0; } /* write the lz77-encoded data, which has lit, len and dist codes, to compressed stream using huffman trees. tree_ll: the tree for lit and len codes. tree_d: the tree for distance codes. */ static void writeLZ77data(size_t* bp, ucvector* out, const uivector* lz77_encoded, const HuffmanTree* tree_ll, const HuffmanTree* tree_d) { size_t i = 0; for(i = 0; i != lz77_encoded->size; ++i) { unsigned val = lz77_encoded->data[i]; addHuffmanSymbol(bp, out, HuffmanTree_getCode(tree_ll, val), HuffmanTree_getLength(tree_ll, val)); if(val > 256) /*for a length code, 3 more things have to be added*/ { unsigned length_index = val - FIRST_LENGTH_CODE_INDEX; unsigned n_length_extra_bits = LENGTHEXTRA[length_index]; unsigned length_extra_bits = lz77_encoded->data[++i]; unsigned distance_code = lz77_encoded->data[++i]; unsigned distance_index = distance_code; unsigned n_distance_extra_bits = DISTANCEEXTRA[distance_index]; unsigned distance_extra_bits = lz77_encoded->data[++i]; addBitsToStream(bp, out, length_extra_bits, n_length_extra_bits); addHuffmanSymbol(bp, out, HuffmanTree_getCode(tree_d, distance_code), HuffmanTree_getLength(tree_d, distance_code)); addBitsToStream(bp, out, distance_extra_bits, n_distance_extra_bits); } } } /*Deflate for a block of type "dynamic", that is, with freely, optimally, created huffman trees*/ static unsigned deflateDynamic(ucvector* out, size_t* bp, Hash* hash, const unsigned char* data, size_t datapos, size_t dataend, const LodePNGCompressSettings* settings, unsigned final) { unsigned error = 0; /* A block is compressed as follows: The PNG data is lz77 encoded, resulting in literal bytes and length/distance pairs. This is then huffman compressed with two huffman trees. One huffman tree is used for the lit and len values ("ll"), another huffman tree is used for the dist values ("d"). These two trees are stored using their code lengths, and to compress even more these code lengths are also run-length encoded and huffman compressed. This gives a huffman tree of code lengths "cl". The code lenghts used to describe this third tree are the code length code lengths ("clcl"). */ /*The lz77 encoded data, represented with integers since there will also be length and distance codes in it*/ uivector lz77_encoded; HuffmanTree tree_ll; /*tree for lit,len values*/ HuffmanTree tree_d; /*tree for distance codes*/ HuffmanTree tree_cl; /*tree for encoding the code lengths representing tree_ll and tree_d*/ uivector frequencies_ll; /*frequency of lit,len codes*/ uivector frequencies_d; /*frequency of dist codes*/ uivector frequencies_cl; /*frequency of code length codes*/ uivector bitlen_lld; /*lit,len,dist code lenghts (int bits), literally (without repeat codes).*/ uivector bitlen_lld_e; /*bitlen_lld encoded with repeat codes (this is a rudemtary run length compression)*/ /*bitlen_cl is the code length code lengths ("clcl"). The bit lengths of codes to represent tree_cl (these are written as is in the file, it would be crazy to compress these using yet another huffman tree that needs to be represented by yet another set of code lengths)*/ uivector bitlen_cl; size_t datasize = dataend - datapos; /* Due to the huffman compression of huffman tree representations ("two levels"), there are some anologies: bitlen_lld is to tree_cl what data is to tree_ll and tree_d. bitlen_lld_e is to bitlen_lld what lz77_encoded is to data. bitlen_cl is to bitlen_lld_e what bitlen_lld is to lz77_encoded. */ unsigned BFINAL = final; size_t numcodes_ll, numcodes_d, i; unsigned HLIT, HDIST, HCLEN; uivector_init(&lz77_encoded); HuffmanTree_init(&tree_ll); HuffmanTree_init(&tree_d); HuffmanTree_init(&tree_cl); uivector_init(&frequencies_ll); uivector_init(&frequencies_d); uivector_init(&frequencies_cl); uivector_init(&bitlen_lld); uivector_init(&bitlen_lld_e); uivector_init(&bitlen_cl); /*This while loop never loops due to a break at the end, it is here to allow breaking out of it to the cleanup phase on error conditions.*/ while(!error) { if(settings->use_lz77) { error = encodeLZ77(&lz77_encoded, hash, data, datapos, dataend, settings->windowsize, settings->minmatch, settings->nicematch, settings->lazymatching); if(error) break; } else { if(!uivector_resize(&lz77_encoded, datasize)) ERROR_BREAK(83 /*alloc fail*/); for(i = datapos; i < dataend; ++i) lz77_encoded.data[i - datapos] = data[i]; /*no LZ77, but still will be Huffman compressed*/ } if(!uivector_resizev(&frequencies_ll, 286, 0)) ERROR_BREAK(83 /*alloc fail*/); if(!uivector_resizev(&frequencies_d, 30, 0)) ERROR_BREAK(83 /*alloc fail*/); /*Count the frequencies of lit, len and dist codes*/ for(i = 0; i != lz77_encoded.size; ++i) { unsigned symbol = lz77_encoded.data[i]; ++frequencies_ll.data[symbol]; if(symbol > 256) { unsigned dist = lz77_encoded.data[i + 2]; ++frequencies_d.data[dist]; i += 3; } } frequencies_ll.data[256] = 1; /*there will be exactly 1 end code, at the end of the block*/ /*Make both huffman trees, one for the lit and len codes, one for the dist codes*/ error = HuffmanTree_makeFromFrequencies(&tree_ll, frequencies_ll.data, 257, frequencies_ll.size, 15); if(error) break; /*2, not 1, is chosen for mincodes: some buggy PNG decoders require at least 2 symbols in the dist tree*/ error = HuffmanTree_makeFromFrequencies(&tree_d, frequencies_d.data, 2, frequencies_d.size, 15); if(error) break; numcodes_ll = tree_ll.numcodes; if(numcodes_ll > 286) numcodes_ll = 286; numcodes_d = tree_d.numcodes; if(numcodes_d > 30) numcodes_d = 30; /*store the code lengths of both generated trees in bitlen_lld*/ for(i = 0; i != numcodes_ll; ++i) uivector_push_back(&bitlen_lld, HuffmanTree_getLength(&tree_ll, (unsigned)i)); for(i = 0; i != numcodes_d; ++i) uivector_push_back(&bitlen_lld, HuffmanTree_getLength(&tree_d, (unsigned)i)); /*run-length compress bitlen_ldd into bitlen_lld_e by using repeat codes 16 (copy length 3-6 times), 17 (3-10 zeroes), 18 (11-138 zeroes)*/ for(i = 0; i != (unsigned)bitlen_lld.size; ++i) { unsigned j = 0; /*amount of repititions*/ while(i + j + 1 < (unsigned)bitlen_lld.size && bitlen_lld.data[i + j + 1] == bitlen_lld.data[i]) ++j; if(bitlen_lld.data[i] == 0 && j >= 2) /*repeat code for zeroes*/ { ++j; /*include the first zero*/ if(j <= 10) /*repeat code 17 supports max 10 zeroes*/ { uivector_push_back(&bitlen_lld_e, 17); uivector_push_back(&bitlen_lld_e, j - 3); } else /*repeat code 18 supports max 138 zeroes*/ { if(j > 138) j = 138; uivector_push_back(&bitlen_lld_e, 18); uivector_push_back(&bitlen_lld_e, j - 11); } i += (j - 1); } else if(j >= 3) /*repeat code for value other than zero*/ { size_t k; unsigned num = j / 6, rest = j % 6; uivector_push_back(&bitlen_lld_e, bitlen_lld.data[i]); for(k = 0; k < num; ++k) { uivector_push_back(&bitlen_lld_e, 16); uivector_push_back(&bitlen_lld_e, 6 - 3); } if(rest >= 3) { uivector_push_back(&bitlen_lld_e, 16); uivector_push_back(&bitlen_lld_e, rest - 3); } else j -= rest; i += j; } else /*too short to benefit from repeat code*/ { uivector_push_back(&bitlen_lld_e, bitlen_lld.data[i]); } } /*generate tree_cl, the huffmantree of huffmantrees*/ if(!uivector_resizev(&frequencies_cl, NUM_CODE_LENGTH_CODES, 0)) ERROR_BREAK(83 /*alloc fail*/); for(i = 0; i != bitlen_lld_e.size; ++i) { ++frequencies_cl.data[bitlen_lld_e.data[i]]; /*after a repeat code come the bits that specify the number of repetitions, those don't need to be in the frequencies_cl calculation*/ if(bitlen_lld_e.data[i] >= 16) ++i; } error = HuffmanTree_makeFromFrequencies(&tree_cl, frequencies_cl.data, frequencies_cl.size, frequencies_cl.size, 7); if(error) break; if(!uivector_resize(&bitlen_cl, tree_cl.numcodes)) ERROR_BREAK(83 /*alloc fail*/); for(i = 0; i != tree_cl.numcodes; ++i) { /*lenghts of code length tree is in the order as specified by deflate*/ bitlen_cl.data[i] = HuffmanTree_getLength(&tree_cl, CLCL_ORDER[i]); } while(bitlen_cl.data[bitlen_cl.size - 1] == 0 && bitlen_cl.size > 4) { /*remove zeros at the end, but minimum size must be 4*/ if(!uivector_resize(&bitlen_cl, bitlen_cl.size - 1)) ERROR_BREAK(83 /*alloc fail*/); } if(error) break; /* Write everything into the output After the BFINAL and BTYPE, the dynamic block consists out of the following: - 5 bits HLIT, 5 bits HDIST, 4 bits HCLEN - (HCLEN+4)*3 bits code lengths of code length alphabet - HLIT + 257 code lenghts of lit/length alphabet (encoded using the code length alphabet, + possible repetition codes 16, 17, 18) - HDIST + 1 code lengths of distance alphabet (encoded using the code length alphabet, + possible repetition codes 16, 17, 18) - compressed data - 256 (end code) */ /*Write block type*/ addBitToStream(bp, out, BFINAL); addBitToStream(bp, out, 0); /*first bit of BTYPE "dynamic"*/ addBitToStream(bp, out, 1); /*second bit of BTYPE "dynamic"*/ /*write the HLIT, HDIST and HCLEN values*/ HLIT = (unsigned)(numcodes_ll - 257); HDIST = (unsigned)(numcodes_d - 1); HCLEN = (unsigned)bitlen_cl.size - 4; /*trim zeroes for HCLEN. HLIT and HDIST were already trimmed at tree creation*/ while(!bitlen_cl.data[HCLEN + 4 - 1] && HCLEN > 0) --HCLEN; addBitsToStream(bp, out, HLIT, 5); addBitsToStream(bp, out, HDIST, 5); addBitsToStream(bp, out, HCLEN, 4); /*write the code lenghts of the code length alphabet*/ for(i = 0; i != HCLEN + 4; ++i) addBitsToStream(bp, out, bitlen_cl.data[i], 3); /*write the lenghts of the lit/len AND the dist alphabet*/ for(i = 0; i != bitlen_lld_e.size; ++i) { addHuffmanSymbol(bp, out, HuffmanTree_getCode(&tree_cl, bitlen_lld_e.data[i]), HuffmanTree_getLength(&tree_cl, bitlen_lld_e.data[i])); /*extra bits of repeat codes*/ if(bitlen_lld_e.data[i] == 16) addBitsToStream(bp, out, bitlen_lld_e.data[++i], 2); else if(bitlen_lld_e.data[i] == 17) addBitsToStream(bp, out, bitlen_lld_e.data[++i], 3); else if(bitlen_lld_e.data[i] == 18) addBitsToStream(bp, out, bitlen_lld_e.data[++i], 7); } /*write the compressed data symbols*/ writeLZ77data(bp, out, &lz77_encoded, &tree_ll, &tree_d); /*error: the length of the end code 256 must be larger than 0*/ if(HuffmanTree_getLength(&tree_ll, 256) == 0) ERROR_BREAK(64); /*write the end code*/ addHuffmanSymbol(bp, out, HuffmanTree_getCode(&tree_ll, 256), HuffmanTree_getLength(&tree_ll, 256)); break; /*end of error-while*/ } /*cleanup*/ uivector_cleanup(&lz77_encoded); HuffmanTree_cleanup(&tree_ll); HuffmanTree_cleanup(&tree_d); HuffmanTree_cleanup(&tree_cl); uivector_cleanup(&frequencies_ll); uivector_cleanup(&frequencies_d); uivector_cleanup(&frequencies_cl); uivector_cleanup(&bitlen_lld_e); uivector_cleanup(&bitlen_lld); uivector_cleanup(&bitlen_cl); return error; } static unsigned deflateFixed(ucvector* out, size_t* bp, Hash* hash, const unsigned char* data, size_t datapos, size_t dataend, const LodePNGCompressSettings* settings, unsigned final) { HuffmanTree tree_ll; /*tree for literal values and length codes*/ HuffmanTree tree_d; /*tree for distance codes*/ unsigned BFINAL = final; unsigned error = 0; size_t i; HuffmanTree_init(&tree_ll); HuffmanTree_init(&tree_d); generateFixedLitLenTree(&tree_ll); generateFixedDistanceTree(&tree_d); addBitToStream(bp, out, BFINAL); addBitToStream(bp, out, 1); /*first bit of BTYPE*/ addBitToStream(bp, out, 0); /*second bit of BTYPE*/ if(settings->use_lz77) /*LZ77 encoded*/ { uivector lz77_encoded; uivector_init(&lz77_encoded); error = encodeLZ77(&lz77_encoded, hash, data, datapos, dataend, settings->windowsize, settings->minmatch, settings->nicematch, settings->lazymatching); if(!error) writeLZ77data(bp, out, &lz77_encoded, &tree_ll, &tree_d); uivector_cleanup(&lz77_encoded); } else /*no LZ77, but still will be Huffman compressed*/ { for(i = datapos; i < dataend; ++i) { addHuffmanSymbol(bp, out, HuffmanTree_getCode(&tree_ll, data[i]), HuffmanTree_getLength(&tree_ll, data[i])); } } /*add END code*/ if(!error) addHuffmanSymbol(bp, out, HuffmanTree_getCode(&tree_ll, 256), HuffmanTree_getLength(&tree_ll, 256)); /*cleanup*/ HuffmanTree_cleanup(&tree_ll); HuffmanTree_cleanup(&tree_d); return error; } static unsigned lodepng_deflatev(ucvector* out, const unsigned char* in, size_t insize, const LodePNGCompressSettings* settings) { unsigned error = 0; size_t i, blocksize, numdeflateblocks; size_t bp = 0; /*the bit pointer*/ Hash hash; if(settings->btype > 2) return 61; else if(settings->btype == 0) return deflateNoCompression(out, in, insize); else if(settings->btype == 1) blocksize = insize; else /*if(settings->btype == 2)*/ { /*on PNGs, deflate blocks of 65-262k seem to give most dense encoding*/ blocksize = insize / 8 + 8; if(blocksize < 65536) blocksize = 65536; if(blocksize > 262144) blocksize = 262144; } numdeflateblocks = (insize + blocksize - 1) / blocksize; if(numdeflateblocks == 0) numdeflateblocks = 1; error = hash_init(&hash, settings->windowsize); if(error) return error; for(i = 0; i != numdeflateblocks && !error; ++i) { unsigned final = (i == numdeflateblocks - 1); size_t start = i * blocksize; size_t end = start + blocksize; if(end > insize) end = insize; if(settings->btype == 1) error = deflateFixed(out, &bp, &hash, in, start, end, settings, final); else if(settings->btype == 2) error = deflateDynamic(out, &bp, &hash, in, start, end, settings, final); } hash_cleanup(&hash); return error; } unsigned lodepng_deflate(unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize, const LodePNGCompressSettings* settings) { unsigned error; ucvector v; ucvector_init_buffer(&v, *out, *outsize); error = lodepng_deflatev(&v, in, insize, settings); *out = v.data; *outsize = v.size; return error; } static unsigned deflate(unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize, const LodePNGCompressSettings* settings) { if(settings->custom_deflate) { return settings->custom_deflate(out, outsize, in, insize, settings); } else { return lodepng_deflate(out, outsize, in, insize, settings); } } #endif /*LODEPNG_COMPILE_DECODER*/ /* ////////////////////////////////////////////////////////////////////////// */ /* / Adler32 */ /* ////////////////////////////////////////////////////////////////////////// */ static unsigned update_adler32(unsigned adler, const unsigned char* data, unsigned len) { unsigned s1 = adler & 0xffff; unsigned s2 = (adler >> 16) & 0xffff; while(len > 0) { /*at least 5550 sums can be done before the sums overflow, saving a lot of module divisions*/ unsigned amount = len > 5550 ? 5550 : len; len -= amount; while(amount > 0) { s1 += (*data++); s2 += s1; --amount; } s1 %= 65521; s2 %= 65521; } return (s2 << 16) | s1; } /*Return the adler32 of the bytes data[0..len-1]*/ static unsigned adler32(const unsigned char* data, unsigned len) { return update_adler32(1L, data, len); } /* ////////////////////////////////////////////////////////////////////////// */ /* / Zlib / */ /* ////////////////////////////////////////////////////////////////////////// */ #ifdef LODEPNG_COMPILE_DECODER unsigned lodepng_zlib_decompress(unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize, const LodePNGDecompressSettings* settings) { unsigned error = 0; unsigned CM, CINFO, FDICT; if(insize < 2) return 53; /*error, size of zlib data too small*/ /*read information from zlib header*/ if((in[0] * 256 + in[1]) % 31 != 0) { /*error: 256 * in[0] + in[1] must be a multiple of 31, the FCHECK value is supposed to be made that way*/ return 24; } CM = in[0] & 15; CINFO = (in[0] >> 4) & 15; /*FCHECK = in[1] & 31;*/ /*FCHECK is already tested above*/ FDICT = (in[1] >> 5) & 1; /*FLEVEL = (in[1] >> 6) & 3;*/ /*FLEVEL is not used here*/ if(CM != 8 || CINFO > 7) { /*error: only compression method 8: inflate with sliding window of 32k is supported by the PNG spec*/ return 25; } if(FDICT != 0) { /*error: the specification of PNG says about the zlib stream: "The additional flags shall not specify a preset dictionary."*/ return 26; } error = inflate(out, outsize, in + 2, insize - 2, settings); if(error) return error; if(!settings->ignore_adler32) { unsigned ADLER32 = lodepng_read32bitInt(&in[insize - 4]); unsigned checksum = adler32(*out, (unsigned)(*outsize)); if(checksum != ADLER32) return 58; /*error, adler checksum not correct, data must be corrupted*/ } return 0; /*no error*/ } static unsigned zlib_decompress(unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize, const LodePNGDecompressSettings* settings) { if(settings->custom_zlib) { return settings->custom_zlib(out, outsize, in, insize, settings); } else { return lodepng_zlib_decompress(out, outsize, in, insize, settings); } } #endif /*LODEPNG_COMPILE_DECODER*/ #ifdef LODEPNG_COMPILE_ENCODER unsigned lodepng_zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize, const LodePNGCompressSettings* settings) { /*initially, *out must be NULL and outsize 0, if you just give some random *out that's pointing to a non allocated buffer, this'll crash*/ ucvector outv; size_t i; unsigned error; unsigned char* deflatedata = 0; size_t deflatesize = 0; /*zlib data: 1 byte CMF (CM+CINFO), 1 byte FLG, deflate data, 4 byte ADLER32 checksum of the Decompressed data*/ unsigned CMF = 120; /*0b01111000: CM 8, CINFO 7. With CINFO 7, any window size up to 32768 can be used.*/ unsigned FLEVEL = 0; unsigned FDICT = 0; unsigned CMFFLG = 256 * CMF + FDICT * 32 + FLEVEL * 64; unsigned FCHECK = 31 - CMFFLG % 31; CMFFLG += FCHECK; /*ucvector-controlled version of the output buffer, for dynamic array*/ ucvector_init_buffer(&outv, *out, *outsize); ucvector_push_back(&outv, (unsigned char)(CMFFLG >> 8)); ucvector_push_back(&outv, (unsigned char)(CMFFLG & 255)); error = deflate(&deflatedata, &deflatesize, in, insize, settings); if(!error) { unsigned ADLER32 = adler32(in, (unsigned)insize); for(i = 0; i != deflatesize; ++i) ucvector_push_back(&outv, deflatedata[i]); lodepng_free(deflatedata); lodepng_add32bitInt(&outv, ADLER32); } *out = outv.data; *outsize = outv.size; return error; } /* compress using the default or custom zlib function */ static unsigned zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize, const LodePNGCompressSettings* settings) { if(settings->custom_zlib) { return settings->custom_zlib(out, outsize, in, insize, settings); } else { return lodepng_zlib_compress(out, outsize, in, insize, settings); } } #endif /*LODEPNG_COMPILE_ENCODER*/ #else /*no LODEPNG_COMPILE_ZLIB*/ #ifdef LODEPNG_COMPILE_DECODER static unsigned zlib_decompress(unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize, const LodePNGDecompressSettings* settings) { if(!settings->custom_zlib) return 87; /*no custom zlib function provided */ return settings->custom_zlib(out, outsize, in, insize, settings); } #endif /*LODEPNG_COMPILE_DECODER*/ #ifdef LODEPNG_COMPILE_ENCODER static unsigned zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize, const LodePNGCompressSettings* settings) { if(!settings->custom_zlib) return 87; /*no custom zlib function provided */ return settings->custom_zlib(out, outsize, in, insize, settings); } #endif /*LODEPNG_COMPILE_ENCODER*/ #endif /*LODEPNG_COMPILE_ZLIB*/ /* ////////////////////////////////////////////////////////////////////////// */ #ifdef LODEPNG_COMPILE_ENCODER /*this is a good tradeoff between speed and compression ratio*/ #define DEFAULT_WINDOWSIZE 2048 void lodepng_compress_settings_init(LodePNGCompressSettings* settings) { /*compress with dynamic huffman tree (not in the mathematical sense, just not the predefined one)*/ settings->btype = 2; settings->use_lz77 = 1; settings->windowsize = DEFAULT_WINDOWSIZE; settings->minmatch = 3; settings->nicematch = 128; settings->lazymatching = 1; settings->custom_zlib = 0; settings->custom_deflate = 0; settings->custom_context = 0; } const LodePNGCompressSettings lodepng_default_compress_settings = {2, 1, DEFAULT_WINDOWSIZE, 3, 128, 1, 0, 0, 0}; #endif /*LODEPNG_COMPILE_ENCODER*/ #ifdef LODEPNG_COMPILE_DECODER void lodepng_decompress_settings_init(LodePNGDecompressSettings* settings) { settings->ignore_adler32 = 0; settings->custom_zlib = 0; settings->custom_inflate = 0; settings->custom_context = 0; } const LodePNGDecompressSettings lodepng_default_decompress_settings = {0, 0, 0, 0}; #endif /*LODEPNG_COMPILE_DECODER*/ /* ////////////////////////////////////////////////////////////////////////// */ /* ////////////////////////////////////////////////////////////////////////// */ /* // End of Zlib related code. Begin of PNG related code. // */ /* ////////////////////////////////////////////////////////////////////////// */ /* ////////////////////////////////////////////////////////////////////////// */ #ifdef LODEPNG_COMPILE_PNG /* ////////////////////////////////////////////////////////////////////////// */ /* / CRC32 / */ /* ////////////////////////////////////////////////////////////////////////// */ #ifndef LODEPNG_NO_COMPILE_CRC /* CRC polynomial: 0xedb88320 */ static unsigned lodepng_crc32_table[256] = { 0u, 1996959894u, 3993919788u, 2567524794u, 124634137u, 1886057615u, 3915621685u, 2657392035u, 249268274u, 2044508324u, 3772115230u, 2547177864u, 162941995u, 2125561021u, 3887607047u, 2428444049u, 498536548u, 1789927666u, 4089016648u, 2227061214u, 450548861u, 1843258603u, 4107580753u, 2211677639u, 325883990u, 1684777152u, 4251122042u, 2321926636u, 335633487u, 1661365465u, 4195302755u, 2366115317u, 997073096u, 1281953886u, 3579855332u, 2724688242u, 1006888145u, 1258607687u, 3524101629u, 2768942443u, 901097722u, 1119000684u, 3686517206u, 2898065728u, 853044451u, 1172266101u, 3705015759u, 2882616665u, 651767980u, 1373503546u, 3369554304u, 3218104598u, 565507253u, 1454621731u, 3485111705u, 3099436303u, 671266974u, 1594198024u, 3322730930u, 2970347812u, 795835527u, 1483230225u, 3244367275u, 3060149565u, 1994146192u, 31158534u, 2563907772u, 4023717930u, 1907459465u, 112637215u, 2680153253u, 3904427059u, 2013776290u, 251722036u, 2517215374u, 3775830040u, 2137656763u, 141376813u, 2439277719u, 3865271297u, 1802195444u, 476864866u, 2238001368u, 4066508878u, 1812370925u, 453092731u, 2181625025u, 4111451223u, 1706088902u, 314042704u, 2344532202u, 4240017532u, 1658658271u, 366619977u, 2362670323u, 4224994405u, 1303535960u, 984961486u, 2747007092u, 3569037538u, 1256170817u, 1037604311u, 2765210733u, 3554079995u, 1131014506u, 879679996u, 2909243462u, 3663771856u, 1141124467u, 855842277u, 2852801631u, 3708648649u, 1342533948u, 654459306u, 3188396048u, 3373015174u, 1466479909u, 544179635u, 3110523913u, 3462522015u, 1591671054u, 702138776u, 2966460450u, 3352799412u, 1504918807u, 783551873u, 3082640443u, 3233442989u, 3988292384u, 2596254646u, 62317068u, 1957810842u, 3939845945u, 2647816111u, 81470997u, 1943803523u, 3814918930u, 2489596804u, 225274430u, 2053790376u, 3826175755u, 2466906013u, 167816743u, 2097651377u, 4027552580u, 2265490386u, 503444072u, 1762050814u, 4150417245u, 2154129355u, 426522225u, 1852507879u, 4275313526u, 2312317920u, 282753626u, 1742555852u, 4189708143u, 2394877945u, 397917763u, 1622183637u, 3604390888u, 2714866558u, 953729732u, 1340076626u, 3518719985u, 2797360999u, 1068828381u, 1219638859u, 3624741850u, 2936675148u, 906185462u, 1090812512u, 3747672003u, 2825379669u, 829329135u, 1181335161u, 3412177804u, 3160834842u, 628085408u, 1382605366u, 3423369109u, 3138078467u, 570562233u, 1426400815u, 3317316542u, 2998733608u, 733239954u, 1555261956u, 3268935591u, 3050360625u, 752459403u, 1541320221u, 2607071920u, 3965973030u, 1969922972u, 40735498u, 2617837225u, 3943577151u, 1913087877u, 83908371u, 2512341634u, 3803740692u, 2075208622u, 213261112u, 2463272603u, 3855990285u, 2094854071u, 198958881u, 2262029012u, 4057260610u, 1759359992u, 534414190u, 2176718541u, 4139329115u, 1873836001u, 414664567u, 2282248934u, 4279200368u, 1711684554u, 285281116u, 2405801727u, 4167216745u, 1634467795u, 376229701u, 2685067896u, 3608007406u, 1308918612u, 956543938u, 2808555105u, 3495958263u, 1231636301u, 1047427035u, 2932959818u, 3654703836u, 1088359270u, 936918000u, 2847714899u, 3736837829u, 1202900863u, 817233897u, 3183342108u, 3401237130u, 1404277552u, 615818150u, 3134207493u, 3453421203u, 1423857449u, 601450431u, 3009837614u, 3294710456u, 1567103746u, 711928724u, 3020668471u, 3272380065u, 1510334235u, 755167117u }; /*Return the CRC of the bytes buf[0..len-1].*/ unsigned lodepng_crc32(const unsigned char* data, size_t length) { unsigned r = 0xffffffffu; size_t i; for(i = 0; i < length; ++i) { r = lodepng_crc32_table[(r ^ data[i]) & 0xff] ^ (r >> 8); } return r ^ 0xffffffffu; } #else /* !LODEPNG_NO_COMPILE_CRC */ unsigned lodepng_crc32(const unsigned char* data, size_t length); #endif /* !LODEPNG_NO_COMPILE_CRC */ /* ////////////////////////////////////////////////////////////////////////// */ /* / Reading and writing single bits and bytes from/to stream for LodePNG / */ /* ////////////////////////////////////////////////////////////////////////// */ static unsigned char readBitFromReversedStream(size_t* bitpointer, const unsigned char* bitstream) { unsigned char result = (unsigned char)((bitstream[(*bitpointer) >> 3] >> (7 - ((*bitpointer) & 0x7))) & 1); ++(*bitpointer); return result; } static unsigned readBitsFromReversedStream(size_t* bitpointer, const unsigned char* bitstream, size_t nbits) { unsigned result = 0; size_t i; for(i = 0 ; i < nbits; ++i) { result <<= 1; result |= (unsigned)readBitFromReversedStream(bitpointer, bitstream); } return result; } #ifdef LODEPNG_COMPILE_DECODER static void setBitOfReversedStream0(size_t* bitpointer, unsigned char* bitstream, unsigned char bit) { /*the current bit in bitstream must be 0 for this to work*/ if(bit) { /*earlier bit of huffman code is in a lesser significant bit of an earlier byte*/ bitstream[(*bitpointer) >> 3] |= (bit << (7 - ((*bitpointer) & 0x7))); } ++(*bitpointer); } #endif /*LODEPNG_COMPILE_DECODER*/ static void setBitOfReversedStream(size_t* bitpointer, unsigned char* bitstream, unsigned char bit) { /*the current bit in bitstream may be 0 or 1 for this to work*/ if(bit == 0) bitstream[(*bitpointer) >> 3] &= (unsigned char)(~(1 << (7 - ((*bitpointer) & 0x7)))); else bitstream[(*bitpointer) >> 3] |= (1 << (7 - ((*bitpointer) & 0x7))); ++(*bitpointer); } /* ////////////////////////////////////////////////////////////////////////// */ /* / PNG chunks / */ /* ////////////////////////////////////////////////////////////////////////// */ unsigned lodepng_chunk_length(const unsigned char* chunk) { return lodepng_read32bitInt(&chunk[0]); } void lodepng_chunk_type(char type[5], const unsigned char* chunk) { unsigned i; for(i = 0; i != 4; ++i) type[i] = (char)chunk[4 + i]; type[4] = 0; /*null termination char*/ } unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type) { if(strlen(type) != 4) return 0; return (chunk[4] == type[0] && chunk[5] == type[1] && chunk[6] == type[2] && chunk[7] == type[3]); } unsigned char lodepng_chunk_ancillary(const unsigned char* chunk) { return((chunk[4] & 32) != 0); } unsigned char lodepng_chunk_private(const unsigned char* chunk) { return((chunk[6] & 32) != 0); } unsigned char lodepng_chunk_safetocopy(const unsigned char* chunk) { return((chunk[7] & 32) != 0); } unsigned char* lodepng_chunk_data(unsigned char* chunk) { return &chunk[8]; } const unsigned char* lodepng_chunk_data_const(const unsigned char* chunk) { return &chunk[8]; } unsigned lodepng_chunk_check_crc(const unsigned char* chunk) { unsigned length = lodepng_chunk_length(chunk); unsigned CRC = lodepng_read32bitInt(&chunk[length + 8]); /*the CRC is taken of the data and the 4 chunk type letters, not the length*/ unsigned checksum = lodepng_crc32(&chunk[4], length + 4); if(CRC != checksum) return 1; else return 0; } void lodepng_chunk_generate_crc(unsigned char* chunk) { unsigned length = lodepng_chunk_length(chunk); unsigned CRC = lodepng_crc32(&chunk[4], length + 4); lodepng_set32bitInt(chunk + 8 + length, CRC); } unsigned char* lodepng_chunk_next(unsigned char* chunk) { unsigned total_chunk_length = lodepng_chunk_length(chunk) + 12; return &chunk[total_chunk_length]; } const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk) { unsigned total_chunk_length = lodepng_chunk_length(chunk) + 12; return &chunk[total_chunk_length]; } unsigned lodepng_chunk_append(unsigned char** out, size_t* outlength, const unsigned char* chunk) { unsigned i; unsigned total_chunk_length = lodepng_chunk_length(chunk) + 12; unsigned char *chunk_start, *new_buffer; size_t new_length = (*outlength) + total_chunk_length; if(new_length < total_chunk_length || new_length < (*outlength)) return 77; /*integer overflow happened*/ new_buffer = (unsigned char*)lodepng_realloc(*out, new_length); if(!new_buffer) return 83; /*alloc fail*/ (*out) = new_buffer; (*outlength) = new_length; chunk_start = &(*out)[new_length - total_chunk_length]; for(i = 0; i != total_chunk_length; ++i) chunk_start[i] = chunk[i]; return 0; } unsigned lodepng_chunk_create(unsigned char** out, size_t* outlength, unsigned length, const char* type, const unsigned char* data) { unsigned i; unsigned char *chunk, *new_buffer; size_t new_length = (*outlength) + length + 12; if(new_length < length + 12 || new_length < (*outlength)) return 77; /*integer overflow happened*/ new_buffer = (unsigned char*)lodepng_realloc(*out, new_length); if(!new_buffer) return 83; /*alloc fail*/ (*out) = new_buffer; (*outlength) = new_length; chunk = &(*out)[(*outlength) - length - 12]; /*1: length*/ lodepng_set32bitInt(chunk, (unsigned)length); /*2: chunk name (4 letters)*/ chunk[4] = (unsigned char)type[0]; chunk[5] = (unsigned char)type[1]; chunk[6] = (unsigned char)type[2]; chunk[7] = (unsigned char)type[3]; /*3: the data*/ for(i = 0; i != length; ++i) chunk[8 + i] = data[i]; /*4: CRC (of the chunkname characters and the data)*/ lodepng_chunk_generate_crc(chunk); return 0; } /* ////////////////////////////////////////////////////////////////////////// */ /* / Color types and such / */ /* ////////////////////////////////////////////////////////////////////////// */ /*return type is a LodePNG error code*/ static unsigned checkColorValidity(LodePNGColorType colortype, unsigned bd) /*bd = bitdepth*/ { switch(colortype) { case 0: if(!(bd == 1 || bd == 2 || bd == 4 || bd == 8 || bd == 16)) return 37; break; /*grey*/ case 2: if(!( bd == 8 || bd == 16)) return 37; break; /*RGB*/ case 3: if(!(bd == 1 || bd == 2 || bd == 4 || bd == 8 )) return 37; break; /*palette*/ case 4: if(!( bd == 8 || bd == 16)) return 37; break; /*grey + alpha*/ case 6: if(!( bd == 8 || bd == 16)) return 37; break; /*RGBA*/ default: return 31; } return 0; /*allowed color type / bits combination*/ } static unsigned getNumColorChannels(LodePNGColorType colortype) { switch(colortype) { case 0: return 1; /*grey*/ case 2: return 3; /*RGB*/ case 3: return 1; /*palette*/ case 4: return 2; /*grey + alpha*/ case 6: return 4; /*RGBA*/ } return 0; /*unexisting color type*/ } static unsigned lodepng_get_bpp_lct(LodePNGColorType colortype, unsigned bitdepth) { /*bits per pixel is amount of channels * bits per channel*/ return getNumColorChannels(colortype) * bitdepth; } /* ////////////////////////////////////////////////////////////////////////// */ void lodepng_color_mode_init(LodePNGColorMode* info) { info->key_defined = 0; info->key_r = info->key_g = info->key_b = 0; info->colortype = LCT_RGBA; info->bitdepth = 8; info->palette = 0; info->palettesize = 0; } void lodepng_color_mode_cleanup(LodePNGColorMode* info) { lodepng_palette_clear(info); } unsigned lodepng_color_mode_copy(LodePNGColorMode* dest, const LodePNGColorMode* source) { size_t i; lodepng_color_mode_cleanup(dest); *dest = *source; if(source->palette) { dest->palette = (unsigned char*)lodepng_malloc(1024); if(!dest->palette && source->palettesize) return 83; /*alloc fail*/ for(i = 0; i != source->palettesize * 4; ++i) dest->palette[i] = source->palette[i]; } return 0; } static int lodepng_color_mode_equal(const LodePNGColorMode* a, const LodePNGColorMode* b) { size_t i; if(a->colortype != b->colortype) return 0; if(a->bitdepth != b->bitdepth) return 0; if(a->key_defined != b->key_defined) return 0; if(a->key_defined) { if(a->key_r != b->key_r) return 0; if(a->key_g != b->key_g) return 0; if(a->key_b != b->key_b) return 0; } /*if one of the palette sizes is 0, then we consider it to be the same as the other: it means that e.g. the palette was not given by the user and should be considered the same as the palette inside the PNG.*/ if(1/*a->palettesize != 0 && b->palettesize != 0*/) { if(a->palettesize != b->palettesize) return 0; for(i = 0; i != a->palettesize * 4; ++i) { if(a->palette[i] != b->palette[i]) return 0; } } return 1; } void lodepng_palette_clear(LodePNGColorMode* info) { if(info->palette) lodepng_free(info->palette); info->palette = 0; info->palettesize = 0; } unsigned lodepng_palette_add(LodePNGColorMode* info, unsigned char r, unsigned char g, unsigned char b, unsigned char a) { unsigned char* data; /*the same resize technique as C++ std::vectors is used, and here it's made so that for a palette with the max of 256 colors, it'll have the exact alloc size*/ if(!info->palette) /*allocate palette if empty*/ { /*room for 256 colors with 4 bytes each*/ data = (unsigned char*)lodepng_realloc(info->palette, 1024); if(!data) return 83; /*alloc fail*/ else info->palette = data; } info->palette[4 * info->palettesize + 0] = r; info->palette[4 * info->palettesize + 1] = g; info->palette[4 * info->palettesize + 2] = b; info->palette[4 * info->palettesize + 3] = a; ++info->palettesize; return 0; } unsigned lodepng_get_bpp(const LodePNGColorMode* info) { /*calculate bits per pixel out of colortype and bitdepth*/ return lodepng_get_bpp_lct(info->colortype, info->bitdepth); } unsigned lodepng_get_channels(const LodePNGColorMode* info) { return getNumColorChannels(info->colortype); } unsigned lodepng_is_greyscale_type(const LodePNGColorMode* info) { return info->colortype == LCT_GREY || info->colortype == LCT_GREY_ALPHA; } unsigned lodepng_is_alpha_type(const LodePNGColorMode* info) { return (info->colortype & 4) != 0; /*4 or 6*/ } unsigned lodepng_is_palette_type(const LodePNGColorMode* info) { return info->colortype == LCT_PALETTE; } unsigned lodepng_has_palette_alpha(const LodePNGColorMode* info) { size_t i; for(i = 0; i != info->palettesize; ++i) { if(info->palette[i * 4 + 3] < 255) return 1; } return 0; } unsigned lodepng_can_have_alpha(const LodePNGColorMode* info) { return info->key_defined || lodepng_is_alpha_type(info) || lodepng_has_palette_alpha(info); } size_t lodepng_get_raw_size(unsigned w, unsigned h, const LodePNGColorMode* color) { /*will not overflow for any color type if roughly w * h < 268435455*/ size_t bpp = lodepng_get_bpp(color); size_t n = w * h; return ((n / 8) * bpp) + ((n & 7) * bpp + 7) / 8; } size_t lodepng_get_raw_size_lct(unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth) { /*will not overflow for any color type if roughly w * h < 268435455*/ size_t bpp = lodepng_get_bpp_lct(colortype, bitdepth); size_t n = w * h; return ((n / 8) * bpp) + ((n & 7) * bpp + 7) / 8; } #ifdef LODEPNG_COMPILE_PNG #ifdef LODEPNG_COMPILE_DECODER /*in an idat chunk, each scanline is a multiple of 8 bits, unlike the lodepng output buffer*/ static size_t lodepng_get_raw_size_idat(unsigned w, unsigned h, const LodePNGColorMode* color) { /*will not overflow for any color type if roughly w * h < 268435455*/ size_t bpp = lodepng_get_bpp(color); size_t line = ((w / 8) * bpp) + ((w & 7) * bpp + 7) / 8; return h * line; } #endif /*LODEPNG_COMPILE_DECODER*/ #endif /*LODEPNG_COMPILE_PNG*/ #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS static void LodePNGUnknownChunks_init(LodePNGInfo* info) { unsigned i; for(i = 0; i != 3; ++i) info->unknown_chunks_data[i] = 0; for(i = 0; i != 3; ++i) info->unknown_chunks_size[i] = 0; } static void LodePNGUnknownChunks_cleanup(LodePNGInfo* info) { unsigned i; for(i = 0; i != 3; ++i) lodepng_free(info->unknown_chunks_data[i]); } static unsigned LodePNGUnknownChunks_copy(LodePNGInfo* dest, const LodePNGInfo* src) { unsigned i; LodePNGUnknownChunks_cleanup(dest); for(i = 0; i != 3; ++i) { size_t j; dest->unknown_chunks_size[i] = src->unknown_chunks_size[i]; dest->unknown_chunks_data[i] = (unsigned char*)lodepng_malloc(src->unknown_chunks_size[i]); if(!dest->unknown_chunks_data[i] && dest->unknown_chunks_size[i]) return 83; /*alloc fail*/ for(j = 0; j < src->unknown_chunks_size[i]; ++j) { dest->unknown_chunks_data[i][j] = src->unknown_chunks_data[i][j]; } } return 0; } /******************************************************************************/ static void LodePNGText_init(LodePNGInfo* info) { info->text_num = 0; info->text_keys = NULL; info->text_strings = NULL; } static void LodePNGText_cleanup(LodePNGInfo* info) { size_t i; for(i = 0; i != info->text_num; ++i) { string_cleanup(&info->text_keys[i]); string_cleanup(&info->text_strings[i]); } lodepng_free(info->text_keys); lodepng_free(info->text_strings); } static unsigned LodePNGText_copy(LodePNGInfo* dest, const LodePNGInfo* source) { size_t i = 0; dest->text_keys = 0; dest->text_strings = 0; dest->text_num = 0; for(i = 0; i != source->text_num; ++i) { CERROR_TRY_RETURN(lodepng_add_text(dest, source->text_keys[i], source->text_strings[i])); } return 0; } void lodepng_clear_text(LodePNGInfo* info) { LodePNGText_cleanup(info); } unsigned lodepng_add_text(LodePNGInfo* info, const char* key, const char* str) { char** new_keys = (char**)(lodepng_realloc(info->text_keys, sizeof(char*) * (info->text_num + 1))); char** new_strings = (char**)(lodepng_realloc(info->text_strings, sizeof(char*) * (info->text_num + 1))); if(!new_keys || !new_strings) { lodepng_free(new_keys); lodepng_free(new_strings); return 83; /*alloc fail*/ } ++info->text_num; info->text_keys = new_keys; info->text_strings = new_strings; string_init(&info->text_keys[info->text_num - 1]); string_set(&info->text_keys[info->text_num - 1], key); string_init(&info->text_strings[info->text_num - 1]); string_set(&info->text_strings[info->text_num - 1], str); return 0; } /******************************************************************************/ static void LodePNGIText_init(LodePNGInfo* info) { info->itext_num = 0; info->itext_keys = NULL; info->itext_langtags = NULL; info->itext_transkeys = NULL; info->itext_strings = NULL; } static void LodePNGIText_cleanup(LodePNGInfo* info) { size_t i; for(i = 0; i != info->itext_num; ++i) { string_cleanup(&info->itext_keys[i]); string_cleanup(&info->itext_langtags[i]); string_cleanup(&info->itext_transkeys[i]); string_cleanup(&info->itext_strings[i]); } lodepng_free(info->itext_keys); lodepng_free(info->itext_langtags); lodepng_free(info->itext_transkeys); lodepng_free(info->itext_strings); } static unsigned LodePNGIText_copy(LodePNGInfo* dest, const LodePNGInfo* source) { size_t i = 0; dest->itext_keys = 0; dest->itext_langtags = 0; dest->itext_transkeys = 0; dest->itext_strings = 0; dest->itext_num = 0; for(i = 0; i != source->itext_num; ++i) { CERROR_TRY_RETURN(lodepng_add_itext(dest, source->itext_keys[i], source->itext_langtags[i], source->itext_transkeys[i], source->itext_strings[i])); } return 0; } void lodepng_clear_itext(LodePNGInfo* info) { LodePNGIText_cleanup(info); } unsigned lodepng_add_itext(LodePNGInfo* info, const char* key, const char* langtag, const char* transkey, const char* str) { char** new_keys = (char**)(lodepng_realloc(info->itext_keys, sizeof(char*) * (info->itext_num + 1))); char** new_langtags = (char**)(lodepng_realloc(info->itext_langtags, sizeof(char*) * (info->itext_num + 1))); char** new_transkeys = (char**)(lodepng_realloc(info->itext_transkeys, sizeof(char*) * (info->itext_num + 1))); char** new_strings = (char**)(lodepng_realloc(info->itext_strings, sizeof(char*) * (info->itext_num + 1))); if(!new_keys || !new_langtags || !new_transkeys || !new_strings) { lodepng_free(new_keys); lodepng_free(new_langtags); lodepng_free(new_transkeys); lodepng_free(new_strings); return 83; /*alloc fail*/ } ++info->itext_num; info->itext_keys = new_keys; info->itext_langtags = new_langtags; info->itext_transkeys = new_transkeys; info->itext_strings = new_strings; string_init(&info->itext_keys[info->itext_num - 1]); string_set(&info->itext_keys[info->itext_num - 1], key); string_init(&info->itext_langtags[info->itext_num - 1]); string_set(&info->itext_langtags[info->itext_num - 1], langtag); string_init(&info->itext_transkeys[info->itext_num - 1]); string_set(&info->itext_transkeys[info->itext_num - 1], transkey); string_init(&info->itext_strings[info->itext_num - 1]); string_set(&info->itext_strings[info->itext_num - 1], str); return 0; } #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ void lodepng_info_init(LodePNGInfo* info) { lodepng_color_mode_init(&info->color); info->interlace_method = 0; info->compression_method = 0; info->filter_method = 0; #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS info->background_defined = 0; info->background_r = info->background_g = info->background_b = 0; LodePNGText_init(info); LodePNGIText_init(info); info->time_defined = 0; info->phys_defined = 0; LodePNGUnknownChunks_init(info); #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ } void lodepng_info_cleanup(LodePNGInfo* info) { lodepng_color_mode_cleanup(&info->color); #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS LodePNGText_cleanup(info); LodePNGIText_cleanup(info); LodePNGUnknownChunks_cleanup(info); #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ } unsigned lodepng_info_copy(LodePNGInfo* dest, const LodePNGInfo* source) { lodepng_info_cleanup(dest); *dest = *source; lodepng_color_mode_init(&dest->color); CERROR_TRY_RETURN(lodepng_color_mode_copy(&dest->color, &source->color)); #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS CERROR_TRY_RETURN(LodePNGText_copy(dest, source)); CERROR_TRY_RETURN(LodePNGIText_copy(dest, source)); LodePNGUnknownChunks_init(dest); CERROR_TRY_RETURN(LodePNGUnknownChunks_copy(dest, source)); #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ return 0; } void lodepng_info_swap(LodePNGInfo* a, LodePNGInfo* b) { LodePNGInfo temp = *a; *a = *b; *b = temp; } /* ////////////////////////////////////////////////////////////////////////// */ /*index: bitgroup index, bits: bitgroup size(1, 2 or 4), in: bitgroup value, out: octet array to add bits to*/ static void addColorBits(unsigned char* out, size_t index, unsigned bits, unsigned in) { unsigned m = bits == 1 ? 7 : bits == 2 ? 3 : 1; /*8 / bits - 1*/ /*p = the partial index in the byte, e.g. with 4 palettebits it is 0 for first half or 1 for second half*/ unsigned p = index & m; in &= (1u << bits) - 1u; /*filter out any other bits of the input value*/ in = in << (bits * (m - p)); if(p == 0) out[index * bits / 8] = in; else out[index * bits / 8] |= in; } typedef struct ColorTree ColorTree; /* One node of a color tree This is the data structure used to count the number of unique colors and to get a palette index for a color. It's like an octree, but because the alpha channel is used too, each node has 16 instead of 8 children. */ struct ColorTree { ColorTree* children[16]; /*up to 16 pointers to ColorTree of next level*/ int index; /*the payload. Only has a meaningful value if this is in the last level*/ }; static void color_tree_init(ColorTree* tree) { int i; for(i = 0; i != 16; ++i) tree->children[i] = 0; tree->index = -1; } static void color_tree_cleanup(ColorTree* tree) { int i; for(i = 0; i != 16; ++i) { if(tree->children[i]) { color_tree_cleanup(tree->children[i]); lodepng_free(tree->children[i]); } } } /*returns -1 if color not present, its index otherwise*/ static int color_tree_get(ColorTree* tree, unsigned char r, unsigned char g, unsigned char b, unsigned char a) { int bit = 0; for(bit = 0; bit < 8; ++bit) { int i = 8 * ((r >> bit) & 1) + 4 * ((g >> bit) & 1) + 2 * ((b >> bit) & 1) + 1 * ((a >> bit) & 1); if(!tree->children[i]) return -1; else tree = tree->children[i]; } return tree ? tree->index : -1; } #ifdef LODEPNG_COMPILE_ENCODER static int color_tree_has(ColorTree* tree, unsigned char r, unsigned char g, unsigned char b, unsigned char a) { return color_tree_get(tree, r, g, b, a) >= 0; } #endif /*LODEPNG_COMPILE_ENCODER*/ /*color is not allowed to already exist. Index should be >= 0 (it's signed to be compatible with using -1 for "doesn't exist")*/ static void color_tree_add(ColorTree* tree, unsigned char r, unsigned char g, unsigned char b, unsigned char a, unsigned index) { int bit; for(bit = 0; bit < 8; ++bit) { int i = 8 * ((r >> bit) & 1) + 4 * ((g >> bit) & 1) + 2 * ((b >> bit) & 1) + 1 * ((a >> bit) & 1); if(!tree->children[i]) { tree->children[i] = (ColorTree*)lodepng_malloc(sizeof(ColorTree)); color_tree_init(tree->children[i]); } tree = tree->children[i]; } tree->index = (int)index; } /*put a pixel, given its RGBA color, into image of any color type*/ static unsigned rgba8ToPixel(unsigned char* out, size_t i, const LodePNGColorMode* mode, ColorTree* tree /*for palette*/, unsigned char r, unsigned char g, unsigned char b, unsigned char a) { if(mode->colortype == LCT_GREY) { unsigned char grey = r; /*((unsigned short)r + g + b) / 3*/; if(mode->bitdepth == 8) out[i] = grey; else if(mode->bitdepth == 16) out[i * 2 + 0] = out[i * 2 + 1] = grey; else { /*take the most significant bits of grey*/ grey = (grey >> (8 - mode->bitdepth)) & ((1 << mode->bitdepth) - 1); addColorBits(out, i, mode->bitdepth, grey); } } else if(mode->colortype == LCT_RGB) { if(mode->bitdepth == 8) { out[i * 3 + 0] = r; out[i * 3 + 1] = g; out[i * 3 + 2] = b; } else { out[i * 6 + 0] = out[i * 6 + 1] = r; out[i * 6 + 2] = out[i * 6 + 3] = g; out[i * 6 + 4] = out[i * 6 + 5] = b; } } else if(mode->colortype == LCT_PALETTE) { int index = color_tree_get(tree, r, g, b, a); if(index < 0) return 82; /*color not in palette*/ if(mode->bitdepth == 8) out[i] = index; else addColorBits(out, i, mode->bitdepth, (unsigned)index); } else if(mode->colortype == LCT_GREY_ALPHA) { unsigned char grey = r; /*((unsigned short)r + g + b) / 3*/; if(mode->bitdepth == 8) { out[i * 2 + 0] = grey; out[i * 2 + 1] = a; } else if(mode->bitdepth == 16) { out[i * 4 + 0] = out[i * 4 + 1] = grey; out[i * 4 + 2] = out[i * 4 + 3] = a; } } else if(mode->colortype == LCT_RGBA) { if(mode->bitdepth == 8) { out[i * 4 + 0] = r; out[i * 4 + 1] = g; out[i * 4 + 2] = b; out[i * 4 + 3] = a; } else { out[i * 8 + 0] = out[i * 8 + 1] = r; out[i * 8 + 2] = out[i * 8 + 3] = g; out[i * 8 + 4] = out[i * 8 + 5] = b; out[i * 8 + 6] = out[i * 8 + 7] = a; } } return 0; /*no error*/ } /*put a pixel, given its RGBA16 color, into image of any color 16-bitdepth type*/ static void rgba16ToPixel(unsigned char* out, size_t i, const LodePNGColorMode* mode, unsigned short r, unsigned short g, unsigned short b, unsigned short a) { if(mode->colortype == LCT_GREY) { unsigned short grey = r; /*((unsigned)r + g + b) / 3*/; out[i * 2 + 0] = (grey >> 8) & 255; out[i * 2 + 1] = grey & 255; } else if(mode->colortype == LCT_RGB) { out[i * 6 + 0] = (r >> 8) & 255; out[i * 6 + 1] = r & 255; out[i * 6 + 2] = (g >> 8) & 255; out[i * 6 + 3] = g & 255; out[i * 6 + 4] = (b >> 8) & 255; out[i * 6 + 5] = b & 255; } else if(mode->colortype == LCT_GREY_ALPHA) { unsigned short grey = r; /*((unsigned)r + g + b) / 3*/; out[i * 4 + 0] = (grey >> 8) & 255; out[i * 4 + 1] = grey & 255; out[i * 4 + 2] = (a >> 8) & 255; out[i * 4 + 3] = a & 255; } else if(mode->colortype == LCT_RGBA) { out[i * 8 + 0] = (r >> 8) & 255; out[i * 8 + 1] = r & 255; out[i * 8 + 2] = (g >> 8) & 255; out[i * 8 + 3] = g & 255; out[i * 8 + 4] = (b >> 8) & 255; out[i * 8 + 5] = b & 255; out[i * 8 + 6] = (a >> 8) & 255; out[i * 8 + 7] = a & 255; } } /*Get RGBA8 color of pixel with index i (y * width + x) from the raw image with given color type.*/ static void getPixelColorRGBA8(unsigned char* r, unsigned char* g, unsigned char* b, unsigned char* a, const unsigned char* in, size_t i, const LodePNGColorMode* mode) { if(mode->colortype == LCT_GREY) { if(mode->bitdepth == 8) { *r = *g = *b = in[i]; if(mode->key_defined && *r == mode->key_r) *a = 0; else *a = 255; } else if(mode->bitdepth == 16) { *r = *g = *b = in[i * 2 + 0]; if(mode->key_defined && 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r) *a = 0; else *a = 255; } else { unsigned highest = ((1U << mode->bitdepth) - 1U); /*highest possible value for this bit depth*/ size_t j = i * mode->bitdepth; unsigned value = readBitsFromReversedStream(&j, in, mode->bitdepth); *r = *g = *b = (value * 255) / highest; if(mode->key_defined && value == mode->key_r) *a = 0; else *a = 255; } } else if(mode->colortype == LCT_RGB) { if(mode->bitdepth == 8) { *r = in[i * 3 + 0]; *g = in[i * 3 + 1]; *b = in[i * 3 + 2]; if(mode->key_defined && *r == mode->key_r && *g == mode->key_g && *b == mode->key_b) *a = 0; else *a = 255; } else { *r = in[i * 6 + 0]; *g = in[i * 6 + 2]; *b = in[i * 6 + 4]; if(mode->key_defined && 256U * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r && 256U * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g && 256U * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b) *a = 0; else *a = 255; } } else if(mode->colortype == LCT_PALETTE) { unsigned index; if(mode->bitdepth == 8) index = in[i]; else { size_t j = i * mode->bitdepth; index = readBitsFromReversedStream(&j, in, mode->bitdepth); } if(index >= mode->palettesize) { /*This is an error according to the PNG spec, but common PNG decoders make it black instead. Done here too, slightly faster due to no error handling needed.*/ *r = *g = *b = 0; *a = 255; } else { *r = mode->palette[index * 4 + 0]; *g = mode->palette[index * 4 + 1]; *b = mode->palette[index * 4 + 2]; *a = mode->palette[index * 4 + 3]; } } else if(mode->colortype == LCT_GREY_ALPHA) { if(mode->bitdepth == 8) { *r = *g = *b = in[i * 2 + 0]; *a = in[i * 2 + 1]; } else { *r = *g = *b = in[i * 4 + 0]; *a = in[i * 4 + 2]; } } else if(mode->colortype == LCT_RGBA) { if(mode->bitdepth == 8) { *r = in[i * 4 + 0]; *g = in[i * 4 + 1]; *b = in[i * 4 + 2]; *a = in[i * 4 + 3]; } else { *r = in[i * 8 + 0]; *g = in[i * 8 + 2]; *b = in[i * 8 + 4]; *a = in[i * 8 + 6]; } } } /*Similar to getPixelColorRGBA8, but with all the for loops inside of the color mode test cases, optimized to convert the colors much faster, when converting to RGBA or RGB with 8 bit per cannel. buffer must be RGBA or RGB output with enough memory, if has_alpha is true the output is RGBA. mode has the color mode of the input buffer.*/ static void getPixelColorsRGBA8(unsigned char* buffer, size_t numpixels, unsigned has_alpha, const unsigned char* in, const LodePNGColorMode* mode) { unsigned num_channels = has_alpha ? 4 : 3; size_t i; if(mode->colortype == LCT_GREY) { if(mode->bitdepth == 8) { for(i = 0; i != numpixels; ++i, buffer += num_channels) { buffer[0] = buffer[1] = buffer[2] = in[i]; if(has_alpha) buffer[3] = mode->key_defined && in[i] == mode->key_r ? 0 : 255; } } else if(mode->bitdepth == 16) { for(i = 0; i != numpixels; ++i, buffer += num_channels) { buffer[0] = buffer[1] = buffer[2] = in[i * 2]; if(has_alpha) buffer[3] = mode->key_defined && 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r ? 0 : 255; } } else { unsigned highest = ((1U << mode->bitdepth) - 1U); /*highest possible value for this bit depth*/ size_t j = 0; for(i = 0; i != numpixels; ++i, buffer += num_channels) { unsigned value = readBitsFromReversedStream(&j, in, mode->bitdepth); buffer[0] = buffer[1] = buffer[2] = (value * 255) / highest; if(has_alpha) buffer[3] = mode->key_defined && value == mode->key_r ? 0 : 255; } } } else if(mode->colortype == LCT_RGB) { if(mode->bitdepth == 8) { for(i = 0; i != numpixels; ++i, buffer += num_channels) { buffer[0] = in[i * 3 + 0]; buffer[1] = in[i * 3 + 1]; buffer[2] = in[i * 3 + 2]; if(has_alpha) buffer[3] = mode->key_defined && buffer[0] == mode->key_r && buffer[1]== mode->key_g && buffer[2] == mode->key_b ? 0 : 255; } } else { for(i = 0; i != numpixels; ++i, buffer += num_channels) { buffer[0] = in[i * 6 + 0]; buffer[1] = in[i * 6 + 2]; buffer[2] = in[i * 6 + 4]; if(has_alpha) buffer[3] = mode->key_defined && 256U * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r && 256U * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g && 256U * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b ? 0 : 255; } } } else if(mode->colortype == LCT_PALETTE) { unsigned index; size_t j = 0; for(i = 0; i != numpixels; ++i, buffer += num_channels) { if(mode->bitdepth == 8) index = in[i]; else index = readBitsFromReversedStream(&j, in, mode->bitdepth); if(index >= mode->palettesize) { /*This is an error according to the PNG spec, but most PNG decoders make it black instead. Done here too, slightly faster due to no error handling needed.*/ buffer[0] = buffer[1] = buffer[2] = 0; if(has_alpha) buffer[3] = 255; } else { buffer[0] = mode->palette[index * 4 + 0]; buffer[1] = mode->palette[index * 4 + 1]; buffer[2] = mode->palette[index * 4 + 2]; if(has_alpha) buffer[3] = mode->palette[index * 4 + 3]; } } } else if(mode->colortype == LCT_GREY_ALPHA) { if(mode->bitdepth == 8) { for(i = 0; i != numpixels; ++i, buffer += num_channels) { buffer[0] = buffer[1] = buffer[2] = in[i * 2 + 0]; if(has_alpha) buffer[3] = in[i * 2 + 1]; } } else { for(i = 0; i != numpixels; ++i, buffer += num_channels) { buffer[0] = buffer[1] = buffer[2] = in[i * 4 + 0]; if(has_alpha) buffer[3] = in[i * 4 + 2]; } } } else if(mode->colortype == LCT_RGBA) { if(mode->bitdepth == 8) { for(i = 0; i != numpixels; ++i, buffer += num_channels) { buffer[0] = in[i * 4 + 0]; buffer[1] = in[i * 4 + 1]; buffer[2] = in[i * 4 + 2]; if(has_alpha) buffer[3] = in[i * 4 + 3]; } } else { for(i = 0; i != numpixels; ++i, buffer += num_channels) { buffer[0] = in[i * 8 + 0]; buffer[1] = in[i * 8 + 2]; buffer[2] = in[i * 8 + 4]; if(has_alpha) buffer[3] = in[i * 8 + 6]; } } } } /*Get RGBA16 color of pixel with index i (y * width + x) from the raw image with given color type, but the given color type must be 16-bit itself.*/ static void getPixelColorRGBA16(unsigned short* r, unsigned short* g, unsigned short* b, unsigned short* a, const unsigned char* in, size_t i, const LodePNGColorMode* mode) { if(mode->colortype == LCT_GREY) { *r = *g = *b = 256 * in[i * 2 + 0] + in[i * 2 + 1]; if(mode->key_defined && 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r) *a = 0; else *a = 65535; } else if(mode->colortype == LCT_RGB) { *r = 256u * in[i * 6 + 0] + in[i * 6 + 1]; *g = 256u * in[i * 6 + 2] + in[i * 6 + 3]; *b = 256u * in[i * 6 + 4] + in[i * 6 + 5]; if(mode->key_defined && 256u * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r && 256u * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g && 256u * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b) *a = 0; else *a = 65535; } else if(mode->colortype == LCT_GREY_ALPHA) { *r = *g = *b = 256u * in[i * 4 + 0] + in[i * 4 + 1]; *a = 256u * in[i * 4 + 2] + in[i * 4 + 3]; } else if(mode->colortype == LCT_RGBA) { *r = 256u * in[i * 8 + 0] + in[i * 8 + 1]; *g = 256u * in[i * 8 + 2] + in[i * 8 + 3]; *b = 256u * in[i * 8 + 4] + in[i * 8 + 5]; *a = 256u * in[i * 8 + 6] + in[i * 8 + 7]; } } unsigned lodepng_convert(unsigned char* out, const unsigned char* in, const LodePNGColorMode* mode_out, const LodePNGColorMode* mode_in, unsigned w, unsigned h) { size_t i; ColorTree tree; size_t numpixels = w * h; if(lodepng_color_mode_equal(mode_out, mode_in)) { size_t numbytes = lodepng_get_raw_size(w, h, mode_in); for(i = 0; i != numbytes; ++i) out[i] = in[i]; return 0; } if(mode_out->colortype == LCT_PALETTE) { size_t palettesize = mode_out->palettesize; const unsigned char* palette = mode_out->palette; size_t palsize = 1u << mode_out->bitdepth; /*if the user specified output palette but did not give the values, assume they want the values of the input color type (assuming that one is palette). Note that we never create a new palette ourselves.*/ if(palettesize == 0) { palettesize = mode_in->palettesize; palette = mode_in->palette; } if(palettesize < palsize) palsize = palettesize; color_tree_init(&tree); for(i = 0; i != palsize; ++i) { const unsigned char* p = &palette[i * 4]; color_tree_add(&tree, p[0], p[1], p[2], p[3], i); } } if(mode_in->bitdepth == 16 && mode_out->bitdepth == 16) { for(i = 0; i != numpixels; ++i) { unsigned short r = 0, g = 0, b = 0, a = 0; getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode_in); rgba16ToPixel(out, i, mode_out, r, g, b, a); } } else if(mode_out->bitdepth == 8 && mode_out->colortype == LCT_RGBA) { getPixelColorsRGBA8(out, numpixels, 1, in, mode_in); } else if(mode_out->bitdepth == 8 && mode_out->colortype == LCT_RGB) { getPixelColorsRGBA8(out, numpixels, 0, in, mode_in); } else { unsigned char r = 0, g = 0, b = 0, a = 0; for(i = 0; i != numpixels; ++i) { getPixelColorRGBA8(&r, &g, &b, &a, in, i, mode_in); CERROR_TRY_RETURN(rgba8ToPixel(out, i, mode_out, &tree, r, g, b, a)); } } if(mode_out->colortype == LCT_PALETTE) { color_tree_cleanup(&tree); } return 0; /*no error*/ } #ifdef LODEPNG_COMPILE_ENCODER void lodepng_color_profile_init(LodePNGColorProfile* profile) { profile->colored = 0; profile->key = 0; profile->key_r = profile->key_g = profile->key_b = 0; profile->alpha = 0; profile->numcolors = 0; profile->bits = 1; } /*function used for debug purposes with C++*/ /*void printColorProfile(LodePNGColorProfile* p) { std::cout << "colored: " << (int)p->colored << ", "; std::cout << "key: " << (int)p->key << ", "; std::cout << "key_r: " << (int)p->key_r << ", "; std::cout << "key_g: " << (int)p->key_g << ", "; std::cout << "key_b: " << (int)p->key_b << ", "; std::cout << "alpha: " << (int)p->alpha << ", "; std::cout << "numcolors: " << (int)p->numcolors << ", "; std::cout << "bits: " << (int)p->bits << std::endl; }*/ /*Returns how many bits needed to represent given value (max 8 bit)*/ static unsigned getValueRequiredBits(unsigned char value) { if(value == 0 || value == 255) return 1; /*The scaling of 2-bit and 4-bit values uses multiples of 85 and 17*/ if(value % 17 == 0) return value % 85 == 0 ? 2 : 4; return 8; } /*profile must already have been inited with mode. It's ok to set some parameters of profile to done already.*/ unsigned lodepng_get_color_profile(LodePNGColorProfile* profile, const unsigned char* in, unsigned w, unsigned h, const LodePNGColorMode* mode) { unsigned error = 0; size_t i; ColorTree tree; size_t numpixels = w * h; unsigned colored_done = lodepng_is_greyscale_type(mode) ? 1 : 0; unsigned alpha_done = lodepng_can_have_alpha(mode) ? 0 : 1; unsigned numcolors_done = 0; unsigned bpp = lodepng_get_bpp(mode); unsigned bits_done = bpp == 1 ? 1 : 0; unsigned maxnumcolors = 257; unsigned sixteen = 0; if(bpp <= 8) maxnumcolors = bpp == 1 ? 2 : (bpp == 2 ? 4 : (bpp == 4 ? 16 : 256)); color_tree_init(&tree); /*Check if the 16-bit input is truly 16-bit*/ if(mode->bitdepth == 16) { unsigned short r, g, b, a; for(i = 0; i != numpixels; ++i) { getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode); if((r & 255) != ((r >> 8) & 255) || (g & 255) != ((g >> 8) & 255) || (b & 255) != ((b >> 8) & 255) || (a & 255) != ((a >> 8) & 255)) /*first and second byte differ*/ { sixteen = 1; break; } } } if(sixteen) { unsigned short r = 0, g = 0, b = 0, a = 0; profile->bits = 16; bits_done = numcolors_done = 1; /*counting colors no longer useful, palette doesn't support 16-bit*/ for(i = 0; i != numpixels; ++i) { getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode); if(!colored_done && (r != g || r != b)) { profile->colored = 1; colored_done = 1; } if(!alpha_done) { unsigned matchkey = (r == profile->key_r && g == profile->key_g && b == profile->key_b); if(a != 65535 && (a != 0 || (profile->key && !matchkey))) { profile->alpha = 1; profile->key = 0; alpha_done = 1; } else if(a == 0 && !profile->alpha && !profile->key) { profile->key = 1; profile->key_r = r; profile->key_g = g; profile->key_b = b; } else if(a == 65535 && profile->key && matchkey) { /* Color key cannot be used if an opaque pixel also has that RGB color. */ profile->alpha = 1; profile->key = 0; alpha_done = 1; } } if(alpha_done && numcolors_done && colored_done && bits_done) break; } if(profile->key && !profile->alpha) { for(i = 0; i != numpixels; ++i) { getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode); if(a != 0 && r == profile->key_r && g == profile->key_g && b == profile->key_b) { /* Color key cannot be used if an opaque pixel also has that RGB color. */ profile->alpha = 1; profile->key = 0; alpha_done = 1; } } } } else /* < 16-bit */ { unsigned char r = 0, g = 0, b = 0, a = 0; for(i = 0; i != numpixels; ++i) { getPixelColorRGBA8(&r, &g, &b, &a, in, i, mode); if(!bits_done && profile->bits < 8) { /*only r is checked, < 8 bits is only relevant for greyscale*/ unsigned bits = getValueRequiredBits(r); if(bits > profile->bits) profile->bits = bits; } bits_done = (profile->bits >= bpp); if(!colored_done && (r != g || r != b)) { profile->colored = 1; colored_done = 1; if(profile->bits < 8) profile->bits = 8; /*PNG has no colored modes with less than 8-bit per channel*/ } if(!alpha_done) { unsigned matchkey = (r == profile->key_r && g == profile->key_g && b == profile->key_b); if(a != 255 && (a != 0 || (profile->key && !matchkey))) { profile->alpha = 1; profile->key = 0; alpha_done = 1; if(profile->bits < 8) profile->bits = 8; /*PNG has no alphachannel modes with less than 8-bit per channel*/ } else if(a == 0 && !profile->alpha && !profile->key) { profile->key = 1; profile->key_r = r; profile->key_g = g; profile->key_b = b; } else if(a == 255 && profile->key && matchkey) { /* Color key cannot be used if an opaque pixel also has that RGB color. */ profile->alpha = 1; profile->key = 0; alpha_done = 1; if(profile->bits < 8) profile->bits = 8; /*PNG has no alphachannel modes with less than 8-bit per channel*/ } } if(!numcolors_done) { if(!color_tree_has(&tree, r, g, b, a)) { color_tree_add(&tree, r, g, b, a, profile->numcolors); if(profile->numcolors < 256) { unsigned char* p = profile->palette; unsigned n = profile->numcolors; p[n * 4 + 0] = r; p[n * 4 + 1] = g; p[n * 4 + 2] = b; p[n * 4 + 3] = a; } ++profile->numcolors; numcolors_done = profile->numcolors >= maxnumcolors; } } if(alpha_done && numcolors_done && colored_done && bits_done) break; } if(profile->key && !profile->alpha) { for(i = 0; i != numpixels; ++i) { getPixelColorRGBA8(&r, &g, &b, &a, in, i, mode); if(a != 0 && r == profile->key_r && g == profile->key_g && b == profile->key_b) { /* Color key cannot be used if an opaque pixel also has that RGB color. */ profile->alpha = 1; profile->key = 0; alpha_done = 1; if(profile->bits < 8) profile->bits = 8; /*PNG has no alphachannel modes with less than 8-bit per channel*/ } } } /*make the profile's key always 16-bit for consistency - repeat each byte twice*/ profile->key_r += (profile->key_r << 8); profile->key_g += (profile->key_g << 8); profile->key_b += (profile->key_b << 8); } color_tree_cleanup(&tree); return error; } /*Automatically chooses color type that gives smallest amount of bits in the output image, e.g. grey if there are only greyscale pixels, palette if there are less than 256 colors, ... Updates values of mode with a potentially smaller color model. mode_out should contain the user chosen color model, but will be overwritten with the new chosen one.*/ unsigned lodepng_auto_choose_color(LodePNGColorMode* mode_out, const unsigned char* image, unsigned w, unsigned h, const LodePNGColorMode* mode_in) { LodePNGColorProfile prof; unsigned error = 0; unsigned i, n, palettebits, palette_ok; lodepng_color_profile_init(&prof); error = lodepng_get_color_profile(&prof, image, w, h, mode_in); if(error) return error; mode_out->key_defined = 0; if(prof.key && w * h <= 16) { prof.alpha = 1; /*too few pixels to justify tRNS chunk overhead*/ prof.key = 0; if(prof.bits < 8) prof.bits = 8; /*PNG has no alphachannel modes with less than 8-bit per channel*/ } n = prof.numcolors; palettebits = n <= 2 ? 1 : (n <= 4 ? 2 : (n <= 16 ? 4 : 8)); palette_ok = n <= 256 && prof.bits <= 8; if(w * h < n * 2) palette_ok = 0; /*don't add palette overhead if image has only a few pixels*/ if(!prof.colored && prof.bits <= palettebits) palette_ok = 0; /*grey is less overhead*/ if(palette_ok) { unsigned char* p = prof.palette; lodepng_palette_clear(mode_out); /*remove potential earlier palette*/ for(i = 0; i != prof.numcolors; ++i) { error = lodepng_palette_add(mode_out, p[i * 4 + 0], p[i * 4 + 1], p[i * 4 + 2], p[i * 4 + 3]); if(error) break; } mode_out->colortype = LCT_PALETTE; mode_out->bitdepth = palettebits; if(mode_in->colortype == LCT_PALETTE && mode_in->palettesize >= mode_out->palettesize && mode_in->bitdepth == mode_out->bitdepth) { /*If input should have same palette colors, keep original to preserve its order and prevent conversion*/ lodepng_color_mode_cleanup(mode_out); lodepng_color_mode_copy(mode_out, mode_in); } } else /*8-bit or 16-bit per channel*/ { mode_out->bitdepth = prof.bits; mode_out->colortype = prof.alpha ? (prof.colored ? LCT_RGBA : LCT_GREY_ALPHA) : (prof.colored ? LCT_RGB : LCT_GREY); if(prof.key) { unsigned mask = (1u << mode_out->bitdepth) - 1u; /*profile always uses 16-bit, mask converts it*/ mode_out->key_r = prof.key_r & mask; mode_out->key_g = prof.key_g & mask; mode_out->key_b = prof.key_b & mask; mode_out->key_defined = 1; } } return error; } #endif /* #ifdef LODEPNG_COMPILE_ENCODER */ /* Paeth predicter, used by PNG filter type 4 The parameters are of type short, but should come from unsigned chars, the shorts are only needed to make the paeth calculation correct. */ static unsigned char paethPredictor(short a, short b, short c) { short pa = abs(b - c); short pb = abs(a - c); short pc = abs(a + b - c - c); if(pc < pa && pc < pb) return (unsigned char)c; else if(pb < pa) return (unsigned char)b; else return (unsigned char)a; } /*shared values used by multiple Adam7 related functions*/ static const unsigned ADAM7_IX[7] = { 0, 4, 0, 2, 0, 1, 0 }; /*x start values*/ static const unsigned ADAM7_IY[7] = { 0, 0, 4, 0, 2, 0, 1 }; /*y start values*/ static const unsigned ADAM7_DX[7] = { 8, 8, 4, 4, 2, 2, 1 }; /*x delta values*/ static const unsigned ADAM7_DY[7] = { 8, 8, 8, 4, 4, 2, 2 }; /*y delta values*/ /* Outputs various dimensions and positions in the image related to the Adam7 reduced images. passw: output containing the width of the 7 passes passh: output containing the height of the 7 passes filter_passstart: output containing the index of the start and end of each reduced image with filter bytes padded_passstart output containing the index of the start and end of each reduced image when without filter bytes but with padded scanlines passstart: output containing the index of the start and end of each reduced image without padding between scanlines, but still padding between the images w, h: width and height of non-interlaced image bpp: bits per pixel "padded" is only relevant if bpp is less than 8 and a scanline or image does not end at a full byte */ static void Adam7_getpassvalues(unsigned passw[7], unsigned passh[7], size_t filter_passstart[8], size_t padded_passstart[8], size_t passstart[8], unsigned w, unsigned h, unsigned bpp) { /*the passstart values have 8 values: the 8th one indicates the byte after the end of the 7th (= last) pass*/ unsigned i; /*calculate width and height in pixels of each pass*/ for(i = 0; i != 7; ++i) { passw[i] = (w + ADAM7_DX[i] - ADAM7_IX[i] - 1) / ADAM7_DX[i]; passh[i] = (h + ADAM7_DY[i] - ADAM7_IY[i] - 1) / ADAM7_DY[i]; if(passw[i] == 0) passh[i] = 0; if(passh[i] == 0) passw[i] = 0; } filter_passstart[0] = padded_passstart[0] = passstart[0] = 0; for(i = 0; i != 7; ++i) { /*if passw[i] is 0, it's 0 bytes, not 1 (no filtertype-byte)*/ filter_passstart[i + 1] = filter_passstart[i] + ((passw[i] && passh[i]) ? passh[i] * (1 + (passw[i] * bpp + 7) / 8) : 0); /*bits padded if needed to fill full byte at end of each scanline*/ padded_passstart[i + 1] = padded_passstart[i] + passh[i] * ((passw[i] * bpp + 7) / 8); /*only padded at end of reduced image*/ passstart[i + 1] = passstart[i] + (passh[i] * passw[i] * bpp + 7) / 8; } } #ifdef LODEPNG_COMPILE_DECODER /* ////////////////////////////////////////////////////////////////////////// */ /* / PNG Decoder / */ /* ////////////////////////////////////////////////////////////////////////// */ /*read the information from the header and store it in the LodePNGInfo. return value is error*/ unsigned lodepng_inspect(unsigned* w, unsigned* h, LodePNGState* state, const unsigned char* in, size_t insize) { LodePNGInfo* info = &state->info_png; if(insize == 0 || in == 0) { CERROR_RETURN_ERROR(state->error, 48); /*error: the given data is empty*/ } if(insize < 33) { CERROR_RETURN_ERROR(state->error, 27); /*error: the data length is smaller than the length of a PNG header*/ } /*when decoding a new PNG image, make sure all parameters created after previous decoding are reset*/ lodepng_info_cleanup(info); lodepng_info_init(info); if(in[0] != 137 || in[1] != 80 || in[2] != 78 || in[3] != 71 || in[4] != 13 || in[5] != 10 || in[6] != 26 || in[7] != 10) { CERROR_RETURN_ERROR(state->error, 28); /*error: the first 8 bytes are not the correct PNG signature*/ } if(lodepng_chunk_length(in + 8) != 13) { CERROR_RETURN_ERROR(state->error, 94); /*error: header size must be 13 bytes*/ } if(!lodepng_chunk_type_equals(in + 8, "IHDR")) { CERROR_RETURN_ERROR(state->error, 29); /*error: it doesn't start with a IHDR chunk!*/ } /*read the values given in the header*/ *w = lodepng_read32bitInt(&in[16]); *h = lodepng_read32bitInt(&in[20]); info->color.bitdepth = in[24]; info->color.colortype = (LodePNGColorType)in[25]; info->compression_method = in[26]; info->filter_method = in[27]; info->interlace_method = in[28]; if(*w == 0 || *h == 0) { CERROR_RETURN_ERROR(state->error, 93); } if(!state->decoder.ignore_crc) { unsigned CRC = lodepng_read32bitInt(&in[29]); unsigned checksum = lodepng_crc32(&in[12], 17); if(CRC != checksum) { CERROR_RETURN_ERROR(state->error, 57); /*invalid CRC*/ } } /*error: only compression method 0 is allowed in the specification*/ if(info->compression_method != 0) CERROR_RETURN_ERROR(state->error, 32); /*error: only filter method 0 is allowed in the specification*/ if(info->filter_method != 0) CERROR_RETURN_ERROR(state->error, 33); /*error: only interlace methods 0 and 1 exist in the specification*/ if(info->interlace_method > 1) CERROR_RETURN_ERROR(state->error, 34); state->error = checkColorValidity(info->color.colortype, info->color.bitdepth); return state->error; } static unsigned unfilterScanline(unsigned char* recon, const unsigned char* scanline, const unsigned char* precon, size_t bytewidth, unsigned char filterType, size_t length) { /* For PNG filter method 0 unfilter a PNG image scanline by scanline. when the pixels are smaller than 1 byte, the filter works byte per byte (bytewidth = 1) precon is the previous unfiltered scanline, recon the result, scanline the current one the incoming scanlines do NOT include the filtertype byte, that one is given in the parameter filterType instead recon and scanline MAY be the same memory address! precon must be disjoint. */ size_t i; switch(filterType) { case 0: for(i = 0; i != length; ++i) recon[i] = scanline[i]; break; case 1: for(i = 0; i != bytewidth; ++i) recon[i] = scanline[i]; for(i = bytewidth; i < length; ++i) recon[i] = scanline[i] + recon[i - bytewidth]; break; case 2: if(precon) { for(i = 0; i != length; ++i) recon[i] = scanline[i] + precon[i]; } else { for(i = 0; i != length; ++i) recon[i] = scanline[i]; } break; case 3: if(precon) { for(i = 0; i != bytewidth; ++i) recon[i] = scanline[i] + (precon[i] >> 1); for(i = bytewidth; i < length; ++i) recon[i] = scanline[i] + ((recon[i - bytewidth] + precon[i]) >> 1); } else { for(i = 0; i != bytewidth; ++i) recon[i] = scanline[i]; for(i = bytewidth; i < length; ++i) recon[i] = scanline[i] + (recon[i - bytewidth] >> 1); } break; case 4: if(precon) { for(i = 0; i != bytewidth; ++i) { recon[i] = (scanline[i] + precon[i]); /*paethPredictor(0, precon[i], 0) is always precon[i]*/ } for(i = bytewidth; i < length; ++i) { recon[i] = (scanline[i] + paethPredictor(recon[i - bytewidth], precon[i], precon[i - bytewidth])); } } else { for(i = 0; i != bytewidth; ++i) { recon[i] = scanline[i]; } for(i = bytewidth; i < length; ++i) { /*paethPredictor(recon[i - bytewidth], 0, 0) is always recon[i - bytewidth]*/ recon[i] = (scanline[i] + recon[i - bytewidth]); } } break; default: return 36; /*error: unexisting filter type given*/ } return 0; } static unsigned unfilter(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp) { /* For PNG filter method 0 this function unfilters a single image (e.g. without interlacing this is called once, with Adam7 seven times) out must have enough bytes allocated already, in must have the scanlines + 1 filtertype byte per scanline w and h are image dimensions or dimensions of reduced image, bpp is bits per pixel in and out are allowed to be the same memory address (but aren't the same size since in has the extra filter bytes) */ unsigned y; unsigned char* prevline = 0; /*bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per pixel otherwise*/ size_t bytewidth = (bpp + 7) / 8; size_t linebytes = (w * bpp + 7) / 8; for(y = 0; y < h; ++y) { size_t outindex = linebytes * y; size_t inindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/ unsigned char filterType = in[inindex]; CERROR_TRY_RETURN(unfilterScanline(&out[outindex], &in[inindex + 1], prevline, bytewidth, filterType, linebytes)); prevline = &out[outindex]; } return 0; } /* in: Adam7 interlaced image, with no padding bits between scanlines, but between reduced images so that each reduced image starts at a byte. out: the same pixels, but re-ordered so that they're now a non-interlaced image with size w*h bpp: bits per pixel out has the following size in bits: w * h * bpp. in is possibly bigger due to padding bits between reduced images. out must be big enough AND must be 0 everywhere if bpp < 8 in the current implementation (because that's likely a little bit faster) NOTE: comments about padding bits are only relevant if bpp < 8 */ static void Adam7_deinterlace(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp) { unsigned passw[7], passh[7]; size_t filter_passstart[8], padded_passstart[8], passstart[8]; unsigned i; Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); if(bpp >= 8) { for(i = 0; i != 7; ++i) { unsigned x, y, b; size_t bytewidth = bpp / 8; for(y = 0; y < passh[i]; ++y) for(x = 0; x < passw[i]; ++x) { size_t pixelinstart = passstart[i] + (y * passw[i] + x) * bytewidth; size_t pixeloutstart = ((ADAM7_IY[i] + y * ADAM7_DY[i]) * w + ADAM7_IX[i] + x * ADAM7_DX[i]) * bytewidth; for(b = 0; b < bytewidth; ++b) { out[pixeloutstart + b] = in[pixelinstart + b]; } } } } else /*bpp < 8: Adam7 with pixels < 8 bit is a bit trickier: with bit pointers*/ { for(i = 0; i != 7; ++i) { unsigned x, y, b; unsigned ilinebits = bpp * passw[i]; unsigned olinebits = bpp * w; size_t obp, ibp; /*bit pointers (for out and in buffer)*/ for(y = 0; y < passh[i]; ++y) for(x = 0; x < passw[i]; ++x) { ibp = (8 * passstart[i]) + (y * ilinebits + x * bpp); obp = (ADAM7_IY[i] + y * ADAM7_DY[i]) * olinebits + (ADAM7_IX[i] + x * ADAM7_DX[i]) * bpp; for(b = 0; b < bpp; ++b) { unsigned char bit = readBitFromReversedStream(&ibp, in); /*note that this function assumes the out buffer is completely 0, use setBitOfReversedStream otherwise*/ setBitOfReversedStream0(&obp, out, bit); } } } } } static void removePaddingBits(unsigned char* out, const unsigned char* in, size_t olinebits, size_t ilinebits, unsigned h) { /* After filtering there are still padding bits if scanlines have non multiple of 8 bit amounts. They need to be removed (except at last scanline of (Adam7-reduced) image) before working with pure image buffers for the Adam7 code, the color convert code and the output to the user. in and out are allowed to be the same buffer, in may also be higher but still overlapping; in must have >= ilinebits*h bits, out must have >= olinebits*h bits, olinebits must be <= ilinebits also used to move bits after earlier such operations happened, e.g. in a sequence of reduced images from Adam7 only useful if (ilinebits - olinebits) is a value in the range 1..7 */ unsigned y; size_t diff = ilinebits - olinebits; size_t ibp = 0, obp = 0; /*input and output bit pointers*/ for(y = 0; y < h; ++y) { size_t x; for(x = 0; x < olinebits; ++x) { unsigned char bit = readBitFromReversedStream(&ibp, in); setBitOfReversedStream(&obp, out, bit); } ibp += diff; } } /*out must be buffer big enough to contain full image, and in must contain the full decompressed data from the IDAT chunks (with filter index bytes and possible padding bits) return value is error*/ static unsigned postProcessScanlines(unsigned char* out, unsigned char* in, unsigned w, unsigned h, const LodePNGInfo* info_png) { /* This function converts the filtered-padded-interlaced data into pure 2D image buffer with the PNG's colortype. Steps: *) if no Adam7: 1) unfilter 2) remove padding bits (= posible extra bits per scanline if bpp < 8) *) if adam7: 1) 7x unfilter 2) 7x remove padding bits 3) Adam7_deinterlace NOTE: the in buffer will be overwritten with intermediate data! */ unsigned bpp = lodepng_get_bpp(&info_png->color); if(bpp == 0) return 31; /*error: invalid colortype*/ if(info_png->interlace_method == 0) { if(bpp < 8 && w * bpp != ((w * bpp + 7) / 8) * 8) { CERROR_TRY_RETURN(unfilter(in, in, w, h, bpp)); removePaddingBits(out, in, w * bpp, ((w * bpp + 7) / 8) * 8, h); } /*we can immediately filter into the out buffer, no other steps needed*/ else CERROR_TRY_RETURN(unfilter(out, in, w, h, bpp)); } else /*interlace_method is 1 (Adam7)*/ { unsigned passw[7], passh[7]; size_t filter_passstart[8], padded_passstart[8], passstart[8]; unsigned i; Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); for(i = 0; i != 7; ++i) { CERROR_TRY_RETURN(unfilter(&in[padded_passstart[i]], &in[filter_passstart[i]], passw[i], passh[i], bpp)); /*TODO: possible efficiency improvement: if in this reduced image the bits fit nicely in 1 scanline, move bytes instead of bits or move not at all*/ if(bpp < 8) { /*remove padding bits in scanlines; after this there still may be padding bits between the different reduced images: each reduced image still starts nicely at a byte*/ removePaddingBits(&in[passstart[i]], &in[padded_passstart[i]], passw[i] * bpp, ((passw[i] * bpp + 7) / 8) * 8, passh[i]); } } Adam7_deinterlace(out, in, w, h, bpp); } return 0; } static unsigned readChunk_PLTE(LodePNGColorMode* color, const unsigned char* data, size_t chunkLength) { unsigned pos = 0, i; if(color->palette) lodepng_free(color->palette); color->palettesize = chunkLength / 3; color->palette = (unsigned char*)lodepng_malloc(4 * color->palettesize); if(!color->palette && color->palettesize) { color->palettesize = 0; return 83; /*alloc fail*/ } if(color->palettesize > 256) return 38; /*error: palette too big*/ for(i = 0; i != color->palettesize; ++i) { color->palette[4 * i + 0] = data[pos++]; /*R*/ color->palette[4 * i + 1] = data[pos++]; /*G*/ color->palette[4 * i + 2] = data[pos++]; /*B*/ color->palette[4 * i + 3] = 255; /*alpha*/ } return 0; /* OK */ } static unsigned readChunk_tRNS(LodePNGColorMode* color, const unsigned char* data, size_t chunkLength) { unsigned i; if(color->colortype == LCT_PALETTE) { /*error: more alpha values given than there are palette entries*/ if(chunkLength > color->palettesize) return 38; for(i = 0; i != chunkLength; ++i) color->palette[4 * i + 3] = data[i]; } else if(color->colortype == LCT_GREY) { /*error: this chunk must be 2 bytes for greyscale image*/ if(chunkLength != 2) return 30; color->key_defined = 1; color->key_r = color->key_g = color->key_b = 256u * data[0] + data[1]; } else if(color->colortype == LCT_RGB) { /*error: this chunk must be 6 bytes for RGB image*/ if(chunkLength != 6) return 41; color->key_defined = 1; color->key_r = 256u * data[0] + data[1]; color->key_g = 256u * data[2] + data[3]; color->key_b = 256u * data[4] + data[5]; } else return 42; /*error: tRNS chunk not allowed for other color models*/ return 0; /* OK */ } #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS /*background color chunk (bKGD)*/ static unsigned readChunk_bKGD(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) { if(info->color.colortype == LCT_PALETTE) { /*error: this chunk must be 1 byte for indexed color image*/ if(chunkLength != 1) return 43; info->background_defined = 1; info->background_r = info->background_g = info->background_b = data[0]; } else if(info->color.colortype == LCT_GREY || info->color.colortype == LCT_GREY_ALPHA) { /*error: this chunk must be 2 bytes for greyscale image*/ if(chunkLength != 2) return 44; info->background_defined = 1; info->background_r = info->background_g = info->background_b = 256u * data[0] + data[1]; } else if(info->color.colortype == LCT_RGB || info->color.colortype == LCT_RGBA) { /*error: this chunk must be 6 bytes for greyscale image*/ if(chunkLength != 6) return 45; info->background_defined = 1; info->background_r = 256u * data[0] + data[1]; info->background_g = 256u * data[2] + data[3]; info->background_b = 256u * data[4] + data[5]; } return 0; /* OK */ } /*text chunk (tEXt)*/ static unsigned readChunk_tEXt(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) { unsigned error = 0; char *key = 0, *str = 0; unsigned i; while(!error) /*not really a while loop, only used to break on error*/ { unsigned length, string2_begin; length = 0; while(length < chunkLength && data[length] != 0) ++length; /*even though it's not allowed by the standard, no error is thrown if there's no null termination char, if the text is empty*/ if(length < 1 || length > 79) CERROR_BREAK(error, 89); /*keyword too short or long*/ key = (char*)lodepng_malloc(length + 1); if(!key) CERROR_BREAK(error, 83); /*alloc fail*/ key[length] = 0; for(i = 0; i != length; ++i) key[i] = (char)data[i]; string2_begin = length + 1; /*skip keyword null terminator*/ length = chunkLength < string2_begin ? 0 : chunkLength - string2_begin; str = (char*)lodepng_malloc(length + 1); if(!str) CERROR_BREAK(error, 83); /*alloc fail*/ str[length] = 0; for(i = 0; i != length; ++i) str[i] = (char)data[string2_begin + i]; error = lodepng_add_text(info, key, str); break; } lodepng_free(key); lodepng_free(str); return error; } /*compressed text chunk (zTXt)*/ static unsigned readChunk_zTXt(LodePNGInfo* info, const LodePNGDecompressSettings* zlibsettings, const unsigned char* data, size_t chunkLength) { unsigned error = 0; unsigned i; unsigned length, string2_begin; char *key = 0; ucvector decoded; ucvector_init(&decoded); while(!error) /*not really a while loop, only used to break on error*/ { for(length = 0; length < chunkLength && data[length] != 0; ++length) ; if(length + 2 >= chunkLength) CERROR_BREAK(error, 75); /*no null termination, corrupt?*/ if(length < 1 || length > 79) CERROR_BREAK(error, 89); /*keyword too short or long*/ key = (char*)lodepng_malloc(length + 1); if(!key) CERROR_BREAK(error, 83); /*alloc fail*/ key[length] = 0; for(i = 0; i != length; ++i) key[i] = (char)data[i]; if(data[length + 1] != 0) CERROR_BREAK(error, 72); /*the 0 byte indicating compression must be 0*/ string2_begin = length + 2; if(string2_begin > chunkLength) CERROR_BREAK(error, 75); /*no null termination, corrupt?*/ length = chunkLength - string2_begin; /*will fail if zlib error, e.g. if length is too small*/ error = zlib_decompress(&decoded.data, &decoded.size, (unsigned char*)(&data[string2_begin]), length, zlibsettings); if(error) break; ucvector_push_back(&decoded, 0); error = lodepng_add_text(info, key, (char*)decoded.data); break; } lodepng_free(key); ucvector_cleanup(&decoded); return error; } /*international text chunk (iTXt)*/ static unsigned readChunk_iTXt(LodePNGInfo* info, const LodePNGDecompressSettings* zlibsettings, const unsigned char* data, size_t chunkLength) { unsigned error = 0; unsigned i; unsigned length, begin, compressed; char *key = 0, *langtag = 0, *transkey = 0; ucvector decoded; ucvector_init(&decoded); while(!error) /*not really a while loop, only used to break on error*/ { /*Quick check if the chunk length isn't too small. Even without check it'd still fail with other error checks below if it's too short. This just gives a different error code.*/ if(chunkLength < 5) CERROR_BREAK(error, 30); /*iTXt chunk too short*/ /*read the key*/ for(length = 0; length < chunkLength && data[length] != 0; ++length) ; if(length + 3 >= chunkLength) CERROR_BREAK(error, 75); /*no null termination char, corrupt?*/ if(length < 1 || length > 79) CERROR_BREAK(error, 89); /*keyword too short or long*/ key = (char*)lodepng_malloc(length + 1); if(!key) CERROR_BREAK(error, 83); /*alloc fail*/ key[length] = 0; for(i = 0; i != length; ++i) key[i] = (char)data[i]; /*read the compression method*/ compressed = data[length + 1]; if(data[length + 2] != 0) CERROR_BREAK(error, 72); /*the 0 byte indicating compression must be 0*/ /*even though it's not allowed by the standard, no error is thrown if there's no null termination char, if the text is empty for the next 3 texts*/ /*read the langtag*/ begin = length + 3; length = 0; for(i = begin; i < chunkLength && data[i] != 0; ++i) ++length; langtag = (char*)lodepng_malloc(length + 1); if(!langtag) CERROR_BREAK(error, 83); /*alloc fail*/ langtag[length] = 0; for(i = 0; i != length; ++i) langtag[i] = (char)data[begin + i]; /*read the transkey*/ begin += length + 1; length = 0; for(i = begin; i < chunkLength && data[i] != 0; ++i) ++length; transkey = (char*)lodepng_malloc(length + 1); if(!transkey) CERROR_BREAK(error, 83); /*alloc fail*/ transkey[length] = 0; for(i = 0; i != length; ++i) transkey[i] = (char)data[begin + i]; /*read the actual text*/ begin += length + 1; length = chunkLength < begin ? 0 : chunkLength - begin; if(compressed) { /*will fail if zlib error, e.g. if length is too small*/ error = zlib_decompress(&decoded.data, &decoded.size, (unsigned char*)(&data[begin]), length, zlibsettings); if(error) break; if(decoded.allocsize < decoded.size) decoded.allocsize = decoded.size; ucvector_push_back(&decoded, 0); } else { if(!ucvector_resize(&decoded, length + 1)) CERROR_BREAK(error, 83 /*alloc fail*/); decoded.data[length] = 0; for(i = 0; i != length; ++i) decoded.data[i] = data[begin + i]; } error = lodepng_add_itext(info, key, langtag, transkey, (char*)decoded.data); break; } lodepng_free(key); lodepng_free(langtag); lodepng_free(transkey); ucvector_cleanup(&decoded); return error; } static unsigned readChunk_tIME(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) { if(chunkLength != 7) return 73; /*invalid tIME chunk size*/ info->time_defined = 1; info->time.year = 256u * data[0] + data[1]; info->time.month = data[2]; info->time.day = data[3]; info->time.hour = data[4]; info->time.minute = data[5]; info->time.second = data[6]; return 0; /* OK */ } static unsigned readChunk_pHYs(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) { if(chunkLength != 9) return 74; /*invalid pHYs chunk size*/ info->phys_defined = 1; info->phys_x = 16777216u * data[0] + 65536u * data[1] + 256u * data[2] + data[3]; info->phys_y = 16777216u * data[4] + 65536u * data[5] + 256u * data[6] + data[7]; info->phys_unit = data[8]; return 0; /* OK */ } #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ /*read a PNG, the result will be in the same color type as the PNG (hence "generic")*/ static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h, LodePNGState* state, const unsigned char* in, size_t insize) { unsigned char IEND = 0; const unsigned char* chunk; size_t i; ucvector idat; /*the data from idat chunks*/ ucvector scanlines; size_t predict; size_t numpixels; size_t outsize = 0; /*for unknown chunk order*/ unsigned unknown = 0; #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS unsigned critical_pos = 1; /*1 = after IHDR, 2 = after PLTE, 3 = after IDAT*/ #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ /*provide some proper output values if error will happen*/ *out = 0; state->error = lodepng_inspect(w, h, state, in, insize); /*reads header and resets other parameters in state->info_png*/ if(state->error) return; numpixels = *w * *h; /*multiplication overflow*/ if(*h != 0 && numpixels / *h != *w) CERROR_RETURN(state->error, 92); /*multiplication overflow possible further below. Allows up to 2^31-1 pixel bytes with 16-bit RGBA, the rest is room for filter bytes.*/ if(numpixels > 268435455) CERROR_RETURN(state->error, 92); ucvector_init(&idat); chunk = &in[33]; /*first byte of the first chunk after the header*/ /*loop through the chunks, ignoring unknown chunks and stopping at IEND chunk. IDAT data is put at the start of the in buffer*/ while(!IEND && !state->error) { unsigned chunkLength; const unsigned char* data; /*the data in the chunk*/ /*error: size of the in buffer too small to contain next chunk*/ if((size_t)((chunk - in) + 12) > insize || chunk < in) CERROR_BREAK(state->error, 30); /*length of the data of the chunk, excluding the length bytes, chunk type and CRC bytes*/ chunkLength = lodepng_chunk_length(chunk); /*error: chunk length larger than the max PNG chunk size*/ if(chunkLength > 2147483647) CERROR_BREAK(state->error, 63); if((size_t)((chunk - in) + chunkLength + 12) > insize || (chunk + chunkLength + 12) < in) { CERROR_BREAK(state->error, 64); /*error: size of the in buffer too small to contain next chunk*/ } data = lodepng_chunk_data_const(chunk); /*IDAT chunk, containing compressed image data*/ if(lodepng_chunk_type_equals(chunk, "IDAT")) { size_t oldsize = idat.size; if(!ucvector_resize(&idat, oldsize + chunkLength)) CERROR_BREAK(state->error, 83 /*alloc fail*/); for(i = 0; i != chunkLength; ++i) idat.data[oldsize + i] = data[i]; #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS critical_pos = 3; #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ } /*IEND chunk*/ else if(lodepng_chunk_type_equals(chunk, "IEND")) { IEND = 1; } /*palette chunk (PLTE)*/ else if(lodepng_chunk_type_equals(chunk, "PLTE")) { state->error = readChunk_PLTE(&state->info_png.color, data, chunkLength); if(state->error) break; #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS critical_pos = 2; #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ } /*palette transparency chunk (tRNS)*/ else if(lodepng_chunk_type_equals(chunk, "tRNS")) { state->error = readChunk_tRNS(&state->info_png.color, data, chunkLength); if(state->error) break; } #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS /*background color chunk (bKGD)*/ else if(lodepng_chunk_type_equals(chunk, "bKGD")) { state->error = readChunk_bKGD(&state->info_png, data, chunkLength); if(state->error) break; } /*text chunk (tEXt)*/ else if(lodepng_chunk_type_equals(chunk, "tEXt")) { if(state->decoder.read_text_chunks) { state->error = readChunk_tEXt(&state->info_png, data, chunkLength); if(state->error) break; } } /*compressed text chunk (zTXt)*/ else if(lodepng_chunk_type_equals(chunk, "zTXt")) { if(state->decoder.read_text_chunks) { state->error = readChunk_zTXt(&state->info_png, &state->decoder.zlibsettings, data, chunkLength); if(state->error) break; } } /*international text chunk (iTXt)*/ else if(lodepng_chunk_type_equals(chunk, "iTXt")) { if(state->decoder.read_text_chunks) { state->error = readChunk_iTXt(&state->info_png, &state->decoder.zlibsettings, data, chunkLength); if(state->error) break; } } else if(lodepng_chunk_type_equals(chunk, "tIME")) { state->error = readChunk_tIME(&state->info_png, data, chunkLength); if(state->error) break; } else if(lodepng_chunk_type_equals(chunk, "pHYs")) { state->error = readChunk_pHYs(&state->info_png, data, chunkLength); if(state->error) break; } #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ else /*it's not an implemented chunk type, so ignore it: skip over the data*/ { /*error: unknown critical chunk (5th bit of first byte of chunk type is 0)*/ if(!lodepng_chunk_ancillary(chunk)) CERROR_BREAK(state->error, 69); unknown = 1; #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS if(state->decoder.remember_unknown_chunks) { state->error = lodepng_chunk_append(&state->info_png.unknown_chunks_data[critical_pos - 1], &state->info_png.unknown_chunks_size[critical_pos - 1], chunk); if(state->error) break; } #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ } if(!state->decoder.ignore_crc && !unknown) /*check CRC if wanted, only on known chunk types*/ { if(lodepng_chunk_check_crc(chunk)) CERROR_BREAK(state->error, 57); /*invalid CRC*/ } if(!IEND) chunk = lodepng_chunk_next_const(chunk); } ucvector_init(&scanlines); /*predict output size, to allocate exact size for output buffer to avoid more dynamic allocation. If the decompressed size does not match the prediction, the image must be corrupt.*/ if(state->info_png.interlace_method == 0) { /*The extra *h is added because this are the filter bytes every scanline starts with*/ predict = lodepng_get_raw_size_idat(*w, *h, &state->info_png.color) + *h; } else { /*Adam-7 interlaced: predicted size is the sum of the 7 sub-images sizes*/ const LodePNGColorMode* color = &state->info_png.color; predict = 0; predict += lodepng_get_raw_size_idat((*w + 7) >> 3, (*h + 7) >> 3, color) + ((*h + 7) >> 3); if(*w > 4) predict += lodepng_get_raw_size_idat((*w + 3) >> 3, (*h + 7) >> 3, color) + ((*h + 7) >> 3); predict += lodepng_get_raw_size_idat((*w + 3) >> 2, (*h + 3) >> 3, color) + ((*h + 3) >> 3); if(*w > 2) predict += lodepng_get_raw_size_idat((*w + 1) >> 2, (*h + 3) >> 2, color) + ((*h + 3) >> 2); predict += lodepng_get_raw_size_idat((*w + 1) >> 1, (*h + 1) >> 2, color) + ((*h + 1) >> 2); if(*w > 1) predict += lodepng_get_raw_size_idat((*w + 0) >> 1, (*h + 1) >> 1, color) + ((*h + 1) >> 1); predict += lodepng_get_raw_size_idat((*w + 0), (*h + 0) >> 1, color) + ((*h + 0) >> 1); } if(!state->error && !ucvector_reserve(&scanlines, predict)) state->error = 83; /*alloc fail*/ if(!state->error) { state->error = zlib_decompress(&scanlines.data, &scanlines.size, idat.data, idat.size, &state->decoder.zlibsettings); if(!state->error && scanlines.size != predict) state->error = 91; /*decompressed size doesn't match prediction*/ } ucvector_cleanup(&idat); if(!state->error) { outsize = lodepng_get_raw_size(*w, *h, &state->info_png.color); *out = (unsigned char*)lodepng_malloc(outsize); if(!*out) state->error = 83; /*alloc fail*/ } if(!state->error) { for(i = 0; i < outsize; i++) (*out)[i] = 0; state->error = postProcessScanlines(*out, scanlines.data, *w, *h, &state->info_png); } ucvector_cleanup(&scanlines); } unsigned lodepng_decode(unsigned char** out, unsigned* w, unsigned* h, LodePNGState* state, const unsigned char* in, size_t insize) { *out = 0; decodeGeneric(out, w, h, state, in, insize); if(state->error) return state->error; if(!state->decoder.color_convert || lodepng_color_mode_equal(&state->info_raw, &state->info_png.color)) { /*same color type, no copying or converting of data needed*/ /*store the info_png color settings on the info_raw so that the info_raw still reflects what colortype the raw image has to the end user*/ if(!state->decoder.color_convert) { state->error = lodepng_color_mode_copy(&state->info_raw, &state->info_png.color); if(state->error) return state->error; } } else { /*color conversion needed; sort of copy of the data*/ unsigned char* data = *out; size_t outsize; /*TODO: check if this works according to the statement in the documentation: "The converter can convert from greyscale input color type, to 8-bit greyscale or greyscale with alpha"*/ if(!(state->info_raw.colortype == LCT_RGB || state->info_raw.colortype == LCT_RGBA) && !(state->info_raw.bitdepth == 8)) { return 56; /*unsupported color mode conversion*/ } outsize = lodepng_get_raw_size(*w, *h, &state->info_raw); *out = (unsigned char*)lodepng_malloc(outsize); if(!(*out)) { state->error = 83; /*alloc fail*/ } else state->error = lodepng_convert(*out, data, &state->info_raw, &state->info_png.color, *w, *h); lodepng_free(data); } return state->error; } unsigned lodepng_decode_memory(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, size_t insize, LodePNGColorType colortype, unsigned bitdepth) { unsigned error; LodePNGState state; lodepng_state_init(&state); state.info_raw.colortype = colortype; state.info_raw.bitdepth = bitdepth; error = lodepng_decode(out, w, h, &state, in, insize); lodepng_state_cleanup(&state); return error; } unsigned lodepng_decode32(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, size_t insize) { return lodepng_decode_memory(out, w, h, in, insize, LCT_RGBA, 8); } unsigned lodepng_decode24(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, size_t insize) { return lodepng_decode_memory(out, w, h, in, insize, LCT_RGB, 8); } #ifdef LODEPNG_COMPILE_DISK unsigned lodepng_decode_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename, LodePNGColorType colortype, unsigned bitdepth) { unsigned char* buffer = 0; size_t buffersize; unsigned error; error = lodepng_load_file(&buffer, &buffersize, filename); if(!error) error = lodepng_decode_memory(out, w, h, buffer, buffersize, colortype, bitdepth); lodepng_free(buffer); return error; } unsigned lodepng_decode32_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename) { return lodepng_decode_file(out, w, h, filename, LCT_RGBA, 8); } unsigned lodepng_decode24_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename) { return lodepng_decode_file(out, w, h, filename, LCT_RGB, 8); } #endif /*LODEPNG_COMPILE_DISK*/ void lodepng_decoder_settings_init(LodePNGDecoderSettings* settings) { settings->color_convert = 1; #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS settings->read_text_chunks = 1; settings->remember_unknown_chunks = 0; #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ settings->ignore_crc = 0; lodepng_decompress_settings_init(&settings->zlibsettings); } #endif /*LODEPNG_COMPILE_DECODER*/ #if defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) void lodepng_state_init(LodePNGState* state) { #ifdef LODEPNG_COMPILE_DECODER lodepng_decoder_settings_init(&state->decoder); #endif /*LODEPNG_COMPILE_DECODER*/ #ifdef LODEPNG_COMPILE_ENCODER lodepng_encoder_settings_init(&state->encoder); #endif /*LODEPNG_COMPILE_ENCODER*/ lodepng_color_mode_init(&state->info_raw); lodepng_info_init(&state->info_png); state->error = 1; } void lodepng_state_cleanup(LodePNGState* state) { lodepng_color_mode_cleanup(&state->info_raw); lodepng_info_cleanup(&state->info_png); } void lodepng_state_copy(LodePNGState* dest, const LodePNGState* source) { lodepng_state_cleanup(dest); *dest = *source; lodepng_color_mode_init(&dest->info_raw); lodepng_info_init(&dest->info_png); dest->error = lodepng_color_mode_copy(&dest->info_raw, &source->info_raw); if(dest->error) return; dest->error = lodepng_info_copy(&dest->info_png, &source->info_png); if(dest->error) return; } #endif /* defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) */ #ifdef LODEPNG_COMPILE_ENCODER /* ////////////////////////////////////////////////////////////////////////// */ /* / PNG Encoder / */ /* ////////////////////////////////////////////////////////////////////////// */ /*chunkName must be string of 4 characters*/ static unsigned addChunk(ucvector* out, const char* chunkName, const unsigned char* data, size_t length) { CERROR_TRY_RETURN(lodepng_chunk_create(&out->data, &out->size, (unsigned)length, chunkName, data)); out->allocsize = out->size; /*fix the allocsize again*/ return 0; } static void writeSignature(ucvector* out) { /*8 bytes PNG signature, aka the magic bytes*/ ucvector_push_back(out, 137); ucvector_push_back(out, 80); ucvector_push_back(out, 78); ucvector_push_back(out, 71); ucvector_push_back(out, 13); ucvector_push_back(out, 10); ucvector_push_back(out, 26); ucvector_push_back(out, 10); } static unsigned addChunk_IHDR(ucvector* out, unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth, unsigned interlace_method) { unsigned error = 0; ucvector header; ucvector_init(&header); lodepng_add32bitInt(&header, w); /*width*/ lodepng_add32bitInt(&header, h); /*height*/ ucvector_push_back(&header, (unsigned char)bitdepth); /*bit depth*/ ucvector_push_back(&header, (unsigned char)colortype); /*color type*/ ucvector_push_back(&header, 0); /*compression method*/ ucvector_push_back(&header, 0); /*filter method*/ ucvector_push_back(&header, interlace_method); /*interlace method*/ error = addChunk(out, "IHDR", header.data, header.size); ucvector_cleanup(&header); return error; } static unsigned addChunk_PLTE(ucvector* out, const LodePNGColorMode* info) { unsigned error = 0; size_t i; ucvector PLTE; ucvector_init(&PLTE); for(i = 0; i != info->palettesize * 4; ++i) { /*add all channels except alpha channel*/ if(i % 4 != 3) ucvector_push_back(&PLTE, info->palette[i]); } error = addChunk(out, "PLTE", PLTE.data, PLTE.size); ucvector_cleanup(&PLTE); return error; } static unsigned addChunk_tRNS(ucvector* out, const LodePNGColorMode* info) { unsigned error = 0; size_t i; ucvector tRNS; ucvector_init(&tRNS); if(info->colortype == LCT_PALETTE) { size_t amount = info->palettesize; /*the tail of palette values that all have 255 as alpha, does not have to be encoded*/ for(i = info->palettesize; i != 0; --i) { if(info->palette[4 * (i - 1) + 3] == 255) --amount; else break; } /*add only alpha channel*/ for(i = 0; i != amount; ++i) ucvector_push_back(&tRNS, info->palette[4 * i + 3]); } else if(info->colortype == LCT_GREY) { if(info->key_defined) { ucvector_push_back(&tRNS, (unsigned char)(info->key_r >> 8)); ucvector_push_back(&tRNS, (unsigned char)(info->key_r & 255)); } } else if(info->colortype == LCT_RGB) { if(info->key_defined) { ucvector_push_back(&tRNS, (unsigned char)(info->key_r >> 8)); ucvector_push_back(&tRNS, (unsigned char)(info->key_r & 255)); ucvector_push_back(&tRNS, (unsigned char)(info->key_g >> 8)); ucvector_push_back(&tRNS, (unsigned char)(info->key_g & 255)); ucvector_push_back(&tRNS, (unsigned char)(info->key_b >> 8)); ucvector_push_back(&tRNS, (unsigned char)(info->key_b & 255)); } } error = addChunk(out, "tRNS", tRNS.data, tRNS.size); ucvector_cleanup(&tRNS); return error; } static unsigned addChunk_IDAT(ucvector* out, const unsigned char* data, size_t datasize, LodePNGCompressSettings* zlibsettings) { ucvector zlibdata; unsigned error = 0; /*compress with the Zlib compressor*/ ucvector_init(&zlibdata); error = zlib_compress(&zlibdata.data, &zlibdata.size, data, datasize, zlibsettings); if(!error) error = addChunk(out, "IDAT", zlibdata.data, zlibdata.size); ucvector_cleanup(&zlibdata); return error; } static unsigned addChunk_IEND(ucvector* out) { unsigned error = 0; error = addChunk(out, "IEND", 0, 0); return error; } #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS static unsigned addChunk_tEXt(ucvector* out, const char* keyword, const char* textstring) { unsigned error = 0; size_t i; ucvector text; ucvector_init(&text); for(i = 0; keyword[i] != 0; ++i) ucvector_push_back(&text, (unsigned char)keyword[i]); if(i < 1 || i > 79) return 89; /*error: invalid keyword size*/ ucvector_push_back(&text, 0); /*0 termination char*/ for(i = 0; textstring[i] != 0; ++i) ucvector_push_back(&text, (unsigned char)textstring[i]); error = addChunk(out, "tEXt", text.data, text.size); ucvector_cleanup(&text); return error; } static unsigned addChunk_zTXt(ucvector* out, const char* keyword, const char* textstring, LodePNGCompressSettings* zlibsettings) { unsigned error = 0; ucvector data, compressed; size_t i, textsize = strlen(textstring); ucvector_init(&data); ucvector_init(&compressed); for(i = 0; keyword[i] != 0; ++i) ucvector_push_back(&data, (unsigned char)keyword[i]); if(i < 1 || i > 79) return 89; /*error: invalid keyword size*/ ucvector_push_back(&data, 0); /*0 termination char*/ ucvector_push_back(&data, 0); /*compression method: 0*/ error = zlib_compress(&compressed.data, &compressed.size, (unsigned char*)textstring, textsize, zlibsettings); if(!error) { for(i = 0; i != compressed.size; ++i) ucvector_push_back(&data, compressed.data[i]); error = addChunk(out, "zTXt", data.data, data.size); } ucvector_cleanup(&compressed); ucvector_cleanup(&data); return error; } static unsigned addChunk_iTXt(ucvector* out, unsigned compressed, const char* keyword, const char* langtag, const char* transkey, const char* textstring, LodePNGCompressSettings* zlibsettings) { unsigned error = 0; ucvector data; size_t i, textsize = strlen(textstring); ucvector_init(&data); for(i = 0; keyword[i] != 0; ++i) ucvector_push_back(&data, (unsigned char)keyword[i]); if(i < 1 || i > 79) return 89; /*error: invalid keyword size*/ ucvector_push_back(&data, 0); /*null termination char*/ ucvector_push_back(&data, compressed ? 1 : 0); /*compression flag*/ ucvector_push_back(&data, 0); /*compression method*/ for(i = 0; langtag[i] != 0; ++i) ucvector_push_back(&data, (unsigned char)langtag[i]); ucvector_push_back(&data, 0); /*null termination char*/ for(i = 0; transkey[i] != 0; ++i) ucvector_push_back(&data, (unsigned char)transkey[i]); ucvector_push_back(&data, 0); /*null termination char*/ if(compressed) { ucvector compressed_data; ucvector_init(&compressed_data); error = zlib_compress(&compressed_data.data, &compressed_data.size, (unsigned char*)textstring, textsize, zlibsettings); if(!error) { for(i = 0; i != compressed_data.size; ++i) ucvector_push_back(&data, compressed_data.data[i]); } ucvector_cleanup(&compressed_data); } else /*not compressed*/ { for(i = 0; textstring[i] != 0; ++i) ucvector_push_back(&data, (unsigned char)textstring[i]); } if(!error) error = addChunk(out, "iTXt", data.data, data.size); ucvector_cleanup(&data); return error; } static unsigned addChunk_bKGD(ucvector* out, const LodePNGInfo* info) { unsigned error = 0; ucvector bKGD; ucvector_init(&bKGD); if(info->color.colortype == LCT_GREY || info->color.colortype == LCT_GREY_ALPHA) { ucvector_push_back(&bKGD, (unsigned char)(info->background_r >> 8)); ucvector_push_back(&bKGD, (unsigned char)(info->background_r & 255)); } else if(info->color.colortype == LCT_RGB || info->color.colortype == LCT_RGBA) { ucvector_push_back(&bKGD, (unsigned char)(info->background_r >> 8)); ucvector_push_back(&bKGD, (unsigned char)(info->background_r & 255)); ucvector_push_back(&bKGD, (unsigned char)(info->background_g >> 8)); ucvector_push_back(&bKGD, (unsigned char)(info->background_g & 255)); ucvector_push_back(&bKGD, (unsigned char)(info->background_b >> 8)); ucvector_push_back(&bKGD, (unsigned char)(info->background_b & 255)); } else if(info->color.colortype == LCT_PALETTE) { ucvector_push_back(&bKGD, (unsigned char)(info->background_r & 255)); /*palette index*/ } error = addChunk(out, "bKGD", bKGD.data, bKGD.size); ucvector_cleanup(&bKGD); return error; } static unsigned addChunk_tIME(ucvector* out, const LodePNGTime* time) { unsigned error = 0; unsigned char* data = (unsigned char*)lodepng_malloc(7); if(!data) return 83; /*alloc fail*/ data[0] = (unsigned char)(time->year >> 8); data[1] = (unsigned char)(time->year & 255); data[2] = (unsigned char)time->month; data[3] = (unsigned char)time->day; data[4] = (unsigned char)time->hour; data[5] = (unsigned char)time->minute; data[6] = (unsigned char)time->second; error = addChunk(out, "tIME", data, 7); lodepng_free(data); return error; } static unsigned addChunk_pHYs(ucvector* out, const LodePNGInfo* info) { unsigned error = 0; ucvector data; ucvector_init(&data); lodepng_add32bitInt(&data, info->phys_x); lodepng_add32bitInt(&data, info->phys_y); ucvector_push_back(&data, info->phys_unit); error = addChunk(out, "pHYs", data.data, data.size); ucvector_cleanup(&data); return error; } #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ static void filterScanline(unsigned char* out, const unsigned char* scanline, const unsigned char* prevline, size_t length, size_t bytewidth, unsigned char filterType) { size_t i; switch(filterType) { case 0: /*None*/ for(i = 0; i != length; ++i) out[i] = scanline[i]; break; case 1: /*Sub*/ for(i = 0; i != bytewidth; ++i) out[i] = scanline[i]; for(i = bytewidth; i < length; ++i) out[i] = scanline[i] - scanline[i - bytewidth]; break; case 2: /*Up*/ if(prevline) { for(i = 0; i != length; ++i) out[i] = scanline[i] - prevline[i]; } else { for(i = 0; i != length; ++i) out[i] = scanline[i]; } break; case 3: /*Average*/ if(prevline) { for(i = 0; i != bytewidth; ++i) out[i] = scanline[i] - (prevline[i] >> 1); for(i = bytewidth; i < length; ++i) out[i] = scanline[i] - ((scanline[i - bytewidth] + prevline[i]) >> 1); } else { for(i = 0; i != bytewidth; ++i) out[i] = scanline[i]; for(i = bytewidth; i < length; ++i) out[i] = scanline[i] - (scanline[i - bytewidth] >> 1); } break; case 4: /*Paeth*/ if(prevline) { /*paethPredictor(0, prevline[i], 0) is always prevline[i]*/ for(i = 0; i != bytewidth; ++i) out[i] = (scanline[i] - prevline[i]); for(i = bytewidth; i < length; ++i) { out[i] = (scanline[i] - paethPredictor(scanline[i - bytewidth], prevline[i], prevline[i - bytewidth])); } } else { for(i = 0; i != bytewidth; ++i) out[i] = scanline[i]; /*paethPredictor(scanline[i - bytewidth], 0, 0) is always scanline[i - bytewidth]*/ for(i = bytewidth; i < length; ++i) out[i] = (scanline[i] - scanline[i - bytewidth]); } break; default: return; /*unexisting filter type given*/ } } /* log2 approximation. A slight bit faster than std::log. */ static float flog2(float f) { float result = 0; while(f > 32) { result += 4; f /= 16; } while(f > 2) { ++result; f /= 2; } return result + 1.442695f * (f * f * f / 3 - 3 * f * f / 2 + 3 * f - 1.83333f); } static unsigned filter(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, const LodePNGColorMode* info, const LodePNGEncoderSettings* settings) { /* For PNG filter method 0 out must be a buffer with as size: h + (w * h * bpp + 7) / 8, because there are the scanlines with 1 extra byte per scanline */ unsigned bpp = lodepng_get_bpp(info); /*the width of a scanline in bytes, not including the filter type*/ size_t linebytes = (w * bpp + 7) / 8; /*bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per pixel otherwise*/ size_t bytewidth = (bpp + 7) / 8; const unsigned char* prevline = 0; unsigned x, y; unsigned error = 0; LodePNGFilterStrategy strategy = settings->filter_strategy; /* There is a heuristic called the minimum sum of absolute differences heuristic, suggested by the PNG standard: * If the image type is Palette, or the bit depth is smaller than 8, then do not filter the image (i.e. use fixed filtering, with the filter None). * (The other case) If the image type is Grayscale or RGB (with or without Alpha), and the bit depth is not smaller than 8, then use adaptive filtering heuristic as follows: independently for each row, apply all five filters and select the filter that produces the smallest sum of absolute values per row. This heuristic is used if filter strategy is LFS_MINSUM and filter_palette_zero is true. If filter_palette_zero is true and filter_strategy is not LFS_MINSUM, the above heuristic is followed, but for "the other case", whatever strategy filter_strategy is set to instead of the minimum sum heuristic is used. */ if(settings->filter_palette_zero && (info->colortype == LCT_PALETTE || info->bitdepth < 8)) strategy = LFS_ZERO; if(bpp == 0) return 31; /*error: invalid color type*/ if(strategy == LFS_ZERO) { for(y = 0; y != h; ++y) { size_t outindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/ size_t inindex = linebytes * y; out[outindex] = 0; /*filter type byte*/ filterScanline(&out[outindex + 1], &in[inindex], prevline, linebytes, bytewidth, 0); prevline = &in[inindex]; } } else if(strategy == LFS_MINSUM) { /*adaptive filtering*/ size_t sum[5]; unsigned char* attempt[5]; /*five filtering attempts, one for each filter type*/ size_t smallest = 0; unsigned char type, bestType = 0; for(type = 0; type != 5; ++type) { attempt[type] = (unsigned char*)lodepng_malloc(linebytes); if(!attempt[type]) return 83; /*alloc fail*/ } if(!error) { for(y = 0; y != h; ++y) { /*try the 5 filter types*/ for(type = 0; type != 5; ++type) { filterScanline(attempt[type], &in[y * linebytes], prevline, linebytes, bytewidth, type); /*calculate the sum of the result*/ sum[type] = 0; if(type == 0) { for(x = 0; x != linebytes; ++x) sum[type] += (unsigned char)(attempt[type][x]); } else { for(x = 0; x != linebytes; ++x) { /*For differences, each byte should be treated as signed, values above 127 are negative (converted to signed char). Filtertype 0 isn't a difference though, so use unsigned there. This means filtertype 0 is almost never chosen, but that is justified.*/ unsigned char s = attempt[type][x]; sum[type] += s < 128 ? s : (255U - s); } } /*check if this is smallest sum (or if type == 0 it's the first case so always store the values)*/ if(type == 0 || sum[type] < smallest) { bestType = type; smallest = sum[type]; } } prevline = &in[y * linebytes]; /*now fill the out values*/ out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/ for(x = 0; x != linebytes; ++x) out[y * (linebytes + 1) + 1 + x] = attempt[bestType][x]; } } for(type = 0; type != 5; ++type) lodepng_free(attempt[type]); } else if(strategy == LFS_ENTROPY) { float sum[5]; unsigned char* attempt[5]; /*five filtering attempts, one for each filter type*/ float smallest = 0; unsigned type, bestType = 0; unsigned count[256]; for(type = 0; type != 5; ++type) { attempt[type] = (unsigned char*)lodepng_malloc(linebytes); if(!attempt[type]) return 83; /*alloc fail*/ } for(y = 0; y != h; ++y) { /*try the 5 filter types*/ for(type = 0; type != 5; ++type) { filterScanline(attempt[type], &in[y * linebytes], prevline, linebytes, bytewidth, type); for(x = 0; x != 256; ++x) count[x] = 0; for(x = 0; x != linebytes; ++x) ++count[attempt[type][x]]; ++count[type]; /*the filter type itself is part of the scanline*/ sum[type] = 0; for(x = 0; x != 256; ++x) { float p = count[x] / (float)(linebytes + 1); sum[type] += count[x] == 0 ? 0 : flog2(1 / p) * p; } /*check if this is smallest sum (or if type == 0 it's the first case so always store the values)*/ if(type == 0 || sum[type] < smallest) { bestType = type; smallest = sum[type]; } } prevline = &in[y * linebytes]; /*now fill the out values*/ out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/ for(x = 0; x != linebytes; ++x) out[y * (linebytes + 1) + 1 + x] = attempt[bestType][x]; } for(type = 0; type != 5; ++type) lodepng_free(attempt[type]); } else if(strategy == LFS_PREDEFINED) { for(y = 0; y != h; ++y) { size_t outindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/ size_t inindex = linebytes * y; unsigned char type = settings->predefined_filters[y]; out[outindex] = type; /*filter type byte*/ filterScanline(&out[outindex + 1], &in[inindex], prevline, linebytes, bytewidth, type); prevline = &in[inindex]; } } else if(strategy == LFS_BRUTE_FORCE) { /*brute force filter chooser. deflate the scanline after every filter attempt to see which one deflates best. This is very slow and gives only slightly smaller, sometimes even larger, result*/ size_t size[5]; unsigned char* attempt[5]; /*five filtering attempts, one for each filter type*/ size_t smallest = 0; unsigned type = 0, bestType = 0; unsigned char* dummy; LodePNGCompressSettings zlibsettings = settings->zlibsettings; /*use fixed tree on the attempts so that the tree is not adapted to the filtertype on purpose, to simulate the true case where the tree is the same for the whole image. Sometimes it gives better result with dynamic tree anyway. Using the fixed tree sometimes gives worse, but in rare cases better compression. It does make this a bit less slow, so it's worth doing this.*/ zlibsettings.btype = 1; /*a custom encoder likely doesn't read the btype setting and is optimized for complete PNG images only, so disable it*/ zlibsettings.custom_zlib = 0; zlibsettings.custom_deflate = 0; for(type = 0; type != 5; ++type) { attempt[type] = (unsigned char*)lodepng_malloc(linebytes); if(!attempt[type]) return 83; /*alloc fail*/ } for(y = 0; y != h; ++y) /*try the 5 filter types*/ { for(type = 0; type != 5; ++type) { unsigned testsize = linebytes; /*if(testsize > 8) testsize /= 8;*/ /*it already works good enough by testing a part of the row*/ filterScanline(attempt[type], &in[y * linebytes], prevline, linebytes, bytewidth, type); size[type] = 0; dummy = 0; zlib_compress(&dummy, &size[type], attempt[type], testsize, &zlibsettings); lodepng_free(dummy); /*check if this is smallest size (or if type == 0 it's the first case so always store the values)*/ if(type == 0 || size[type] < smallest) { bestType = type; smallest = size[type]; } } prevline = &in[y * linebytes]; out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/ for(x = 0; x != linebytes; ++x) out[y * (linebytes + 1) + 1 + x] = attempt[bestType][x]; } for(type = 0; type != 5; ++type) lodepng_free(attempt[type]); } else return 88; /* unknown filter strategy */ return error; } static void addPaddingBits(unsigned char* out, const unsigned char* in, size_t olinebits, size_t ilinebits, unsigned h) { /*The opposite of the removePaddingBits function olinebits must be >= ilinebits*/ unsigned y; size_t diff = olinebits - ilinebits; size_t obp = 0, ibp = 0; /*bit pointers*/ for(y = 0; y != h; ++y) { size_t x; for(x = 0; x < ilinebits; ++x) { unsigned char bit = readBitFromReversedStream(&ibp, in); setBitOfReversedStream(&obp, out, bit); } /*obp += diff; --> no, fill in some value in the padding bits too, to avoid "Use of uninitialised value of size ###" warning from valgrind*/ for(x = 0; x != diff; ++x) setBitOfReversedStream(&obp, out, 0); } } /* in: non-interlaced image with size w*h out: the same pixels, but re-ordered according to PNG's Adam7 interlacing, with no padding bits between scanlines, but between reduced images so that each reduced image starts at a byte. bpp: bits per pixel there are no padding bits, not between scanlines, not between reduced images in has the following size in bits: w * h * bpp. out is possibly bigger due to padding bits between reduced images NOTE: comments about padding bits are only relevant if bpp < 8 */ static void Adam7_interlace(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp) { unsigned passw[7], passh[7]; size_t filter_passstart[8], padded_passstart[8], passstart[8]; unsigned i; Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); if(bpp >= 8) { for(i = 0; i != 7; ++i) { unsigned x, y, b; size_t bytewidth = bpp / 8; for(y = 0; y < passh[i]; ++y) for(x = 0; x < passw[i]; ++x) { size_t pixelinstart = ((ADAM7_IY[i] + y * ADAM7_DY[i]) * w + ADAM7_IX[i] + x * ADAM7_DX[i]) * bytewidth; size_t pixeloutstart = passstart[i] + (y * passw[i] + x) * bytewidth; for(b = 0; b < bytewidth; ++b) { out[pixeloutstart + b] = in[pixelinstart + b]; } } } } else /*bpp < 8: Adam7 with pixels < 8 bit is a bit trickier: with bit pointers*/ { for(i = 0; i != 7; ++i) { unsigned x, y, b; unsigned ilinebits = bpp * passw[i]; unsigned olinebits = bpp * w; size_t obp, ibp; /*bit pointers (for out and in buffer)*/ for(y = 0; y < passh[i]; ++y) for(x = 0; x < passw[i]; ++x) { ibp = (ADAM7_IY[i] + y * ADAM7_DY[i]) * olinebits + (ADAM7_IX[i] + x * ADAM7_DX[i]) * bpp; obp = (8 * passstart[i]) + (y * ilinebits + x * bpp); for(b = 0; b < bpp; ++b) { unsigned char bit = readBitFromReversedStream(&ibp, in); setBitOfReversedStream(&obp, out, bit); } } } } } /*out must be buffer big enough to contain uncompressed IDAT chunk data, and in must contain the full image. return value is error**/ static unsigned preProcessScanlines(unsigned char** out, size_t* outsize, const unsigned char* in, unsigned w, unsigned h, const LodePNGInfo* info_png, const LodePNGEncoderSettings* settings) { /* This function converts the pure 2D image with the PNG's colortype, into filtered-padded-interlaced data. Steps: *) if no Adam7: 1) add padding bits (= posible extra bits per scanline if bpp < 8) 2) filter *) if adam7: 1) Adam7_interlace 2) 7x add padding bits 3) 7x filter */ unsigned bpp = lodepng_get_bpp(&info_png->color); unsigned error = 0; if(info_png->interlace_method == 0) { *outsize = h + (h * ((w * bpp + 7) / 8)); /*image size plus an extra byte per scanline + possible padding bits*/ *out = (unsigned char*)lodepng_malloc(*outsize); if(!(*out) && (*outsize)) error = 83; /*alloc fail*/ if(!error) { /*non multiple of 8 bits per scanline, padding bits needed per scanline*/ if(bpp < 8 && w * bpp != ((w * bpp + 7) / 8) * 8) { unsigned char* padded = (unsigned char*)lodepng_malloc(h * ((w * bpp + 7) / 8)); if(!padded) error = 83; /*alloc fail*/ if(!error) { addPaddingBits(padded, in, ((w * bpp + 7) / 8) * 8, w * bpp, h); error = filter(*out, padded, w, h, &info_png->color, settings); } lodepng_free(padded); } else { /*we can immediately filter into the out buffer, no other steps needed*/ error = filter(*out, in, w, h, &info_png->color, settings); } } } else /*interlace_method is 1 (Adam7)*/ { unsigned passw[7], passh[7]; size_t filter_passstart[8], padded_passstart[8], passstart[8]; unsigned char* adam7; Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); *outsize = filter_passstart[7]; /*image size plus an extra byte per scanline + possible padding bits*/ *out = (unsigned char*)lodepng_malloc(*outsize); if(!(*out)) error = 83; /*alloc fail*/ adam7 = (unsigned char*)lodepng_malloc(passstart[7]); if(!adam7 && passstart[7]) error = 83; /*alloc fail*/ if(!error) { unsigned i; Adam7_interlace(adam7, in, w, h, bpp); for(i = 0; i != 7; ++i) { if(bpp < 8) { unsigned char* padded = (unsigned char*)lodepng_malloc(padded_passstart[i + 1] - padded_passstart[i]); if(!padded) ERROR_BREAK(83); /*alloc fail*/ addPaddingBits(padded, &adam7[passstart[i]], ((passw[i] * bpp + 7) / 8) * 8, passw[i] * bpp, passh[i]); error = filter(&(*out)[filter_passstart[i]], padded, passw[i], passh[i], &info_png->color, settings); lodepng_free(padded); } else { error = filter(&(*out)[filter_passstart[i]], &adam7[padded_passstart[i]], passw[i], passh[i], &info_png->color, settings); } if(error) break; } } lodepng_free(adam7); } return error; } /* palette must have 4 * palettesize bytes allocated, and given in format RGBARGBARGBARGBA... returns 0 if the palette is opaque, returns 1 if the palette has a single color with alpha 0 ==> color key returns 2 if the palette is semi-translucent. */ static unsigned getPaletteTranslucency(const unsigned char* palette, size_t palettesize) { size_t i; unsigned key = 0; unsigned r = 0, g = 0, b = 0; /*the value of the color with alpha 0, so long as color keying is possible*/ for(i = 0; i != palettesize; ++i) { if(!key && palette[4 * i + 3] == 0) { r = palette[4 * i + 0]; g = palette[4 * i + 1]; b = palette[4 * i + 2]; key = 1; i = (size_t)(-1); /*restart from beginning, to detect earlier opaque colors with key's value*/ } else if(palette[4 * i + 3] != 255) return 2; /*when key, no opaque RGB may have key's RGB*/ else if(key && r == palette[i * 4 + 0] && g == palette[i * 4 + 1] && b == palette[i * 4 + 2]) return 2; } return key; } #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS static unsigned addUnknownChunks(ucvector* out, unsigned char* data, size_t datasize) { unsigned char* inchunk = data; while((size_t)(inchunk - data) < datasize) { CERROR_TRY_RETURN(lodepng_chunk_append(&out->data, &out->size, inchunk)); out->allocsize = out->size; /*fix the allocsize again*/ inchunk = lodepng_chunk_next(inchunk); } return 0; } #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ unsigned lodepng_encode(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h, LodePNGState* state) { LodePNGInfo info; ucvector outv; unsigned char* data = 0; /*uncompressed version of the IDAT chunk data*/ size_t datasize = 0; /*provide some proper output values if error will happen*/ *out = 0; *outsize = 0; state->error = 0; lodepng_info_init(&info); lodepng_info_copy(&info, &state->info_png); if((info.color.colortype == LCT_PALETTE || state->encoder.force_palette) && (info.color.palettesize == 0 || info.color.palettesize > 256)) { state->error = 68; /*invalid palette size, it is only allowed to be 1-256*/ return state->error; } if(state->encoder.auto_convert) { state->error = lodepng_auto_choose_color(&info.color, image, w, h, &state->info_raw); } if(state->error) return state->error; if(state->encoder.zlibsettings.btype > 2) { CERROR_RETURN_ERROR(state->error, 61); /*error: unexisting btype*/ } if(state->info_png.interlace_method > 1) { CERROR_RETURN_ERROR(state->error, 71); /*error: unexisting interlace mode*/ } state->error = checkColorValidity(info.color.colortype, info.color.bitdepth); if(state->error) return state->error; /*error: unexisting color type given*/ state->error = checkColorValidity(state->info_raw.colortype, state->info_raw.bitdepth); if(state->error) return state->error; /*error: unexisting color type given*/ if(!lodepng_color_mode_equal(&state->info_raw, &info.color)) { unsigned char* converted; size_t size = (w * h * (size_t)lodepng_get_bpp(&info.color) + 7) / 8; converted = (unsigned char*)lodepng_malloc(size); if(!converted && size) state->error = 83; /*alloc fail*/ if(!state->error) { state->error = lodepng_convert(converted, image, &info.color, &state->info_raw, w, h); } if(!state->error) preProcessScanlines(&data, &datasize, converted, w, h, &info, &state->encoder); lodepng_free(converted); } else preProcessScanlines(&data, &datasize, image, w, h, &info, &state->encoder); ucvector_init(&outv); while(!state->error) /*while only executed once, to break on error*/ { #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS size_t i; #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ /*write signature and chunks*/ writeSignature(&outv); /*IHDR*/ addChunk_IHDR(&outv, w, h, info.color.colortype, info.color.bitdepth, info.interlace_method); #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS /*unknown chunks between IHDR and PLTE*/ if(info.unknown_chunks_data[0]) { state->error = addUnknownChunks(&outv, info.unknown_chunks_data[0], info.unknown_chunks_size[0]); if(state->error) break; } #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ /*PLTE*/ if(info.color.colortype == LCT_PALETTE) { addChunk_PLTE(&outv, &info.color); } if(state->encoder.force_palette && (info.color.colortype == LCT_RGB || info.color.colortype == LCT_RGBA)) { addChunk_PLTE(&outv, &info.color); } /*tRNS*/ if(info.color.colortype == LCT_PALETTE && getPaletteTranslucency(info.color.palette, info.color.palettesize) != 0) { addChunk_tRNS(&outv, &info.color); } if((info.color.colortype == LCT_GREY || info.color.colortype == LCT_RGB) && info.color.key_defined) { addChunk_tRNS(&outv, &info.color); } #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS /*bKGD (must come between PLTE and the IDAt chunks*/ if(info.background_defined) addChunk_bKGD(&outv, &info); /*pHYs (must come before the IDAT chunks)*/ if(info.phys_defined) addChunk_pHYs(&outv, &info); /*unknown chunks between PLTE and IDAT*/ if(info.unknown_chunks_data[1]) { state->error = addUnknownChunks(&outv, info.unknown_chunks_data[1], info.unknown_chunks_size[1]); if(state->error) break; } #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ /*IDAT (multiple IDAT chunks must be consecutive)*/ state->error = addChunk_IDAT(&outv, data, datasize, &state->encoder.zlibsettings); if(state->error) break; #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS /*tIME*/ if(info.time_defined) addChunk_tIME(&outv, &info.time); /*tEXt and/or zTXt*/ for(i = 0; i != info.text_num; ++i) { if(strlen(info.text_keys[i]) > 79) { state->error = 66; /*text chunk too large*/ break; } if(strlen(info.text_keys[i]) < 1) { state->error = 67; /*text chunk too small*/ break; } if(state->encoder.text_compression) { addChunk_zTXt(&outv, info.text_keys[i], info.text_strings[i], &state->encoder.zlibsettings); } else { addChunk_tEXt(&outv, info.text_keys[i], info.text_strings[i]); } } /*LodePNG version id in text chunk*/ if(state->encoder.add_id) { unsigned alread_added_id_text = 0; for(i = 0; i != info.text_num; ++i) { if(!strcmp(info.text_keys[i], "LodePNG")) { alread_added_id_text = 1; break; } } if(alread_added_id_text == 0) { addChunk_tEXt(&outv, "LodePNG", LODEPNG_VERSION_STRING); /*it's shorter as tEXt than as zTXt chunk*/ } } /*iTXt*/ for(i = 0; i != info.itext_num; ++i) { if(strlen(info.itext_keys[i]) > 79) { state->error = 66; /*text chunk too large*/ break; } if(strlen(info.itext_keys[i]) < 1) { state->error = 67; /*text chunk too small*/ break; } addChunk_iTXt(&outv, state->encoder.text_compression, info.itext_keys[i], info.itext_langtags[i], info.itext_transkeys[i], info.itext_strings[i], &state->encoder.zlibsettings); } /*unknown chunks between IDAT and IEND*/ if(info.unknown_chunks_data[2]) { state->error = addUnknownChunks(&outv, info.unknown_chunks_data[2], info.unknown_chunks_size[2]); if(state->error) break; } #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ addChunk_IEND(&outv); break; /*this isn't really a while loop; no error happened so break out now!*/ } lodepng_info_cleanup(&info); lodepng_free(data); /*instead of cleaning the vector up, give it to the output*/ *out = outv.data; *outsize = outv.size; return state->error; } unsigned lodepng_encode_memory(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth) { unsigned error; LodePNGState state; lodepng_state_init(&state); state.info_raw.colortype = colortype; state.info_raw.bitdepth = bitdepth; state.info_png.color.colortype = colortype; state.info_png.color.bitdepth = bitdepth; lodepng_encode(out, outsize, image, w, h, &state); error = state.error; lodepng_state_cleanup(&state); return error; } unsigned lodepng_encode32(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h) { return lodepng_encode_memory(out, outsize, image, w, h, LCT_RGBA, 8); } unsigned lodepng_encode24(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h) { return lodepng_encode_memory(out, outsize, image, w, h, LCT_RGB, 8); } #ifdef LODEPNG_COMPILE_DISK unsigned lodepng_encode_file(const char* filename, const unsigned char* image, unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth) { unsigned char* buffer; size_t buffersize; unsigned error = lodepng_encode_memory(&buffer, &buffersize, image, w, h, colortype, bitdepth); if(!error) error = lodepng_save_file(buffer, buffersize, filename); lodepng_free(buffer); return error; } unsigned lodepng_encode32_file(const char* filename, const unsigned char* image, unsigned w, unsigned h) { return lodepng_encode_file(filename, image, w, h, LCT_RGBA, 8); } unsigned lodepng_encode24_file(const char* filename, const unsigned char* image, unsigned w, unsigned h) { return lodepng_encode_file(filename, image, w, h, LCT_RGB, 8); } #endif /*LODEPNG_COMPILE_DISK*/ void lodepng_encoder_settings_init(LodePNGEncoderSettings* settings) { lodepng_compress_settings_init(&settings->zlibsettings); settings->filter_palette_zero = 1; settings->filter_strategy = LFS_MINSUM; settings->auto_convert = 1; settings->force_palette = 0; settings->predefined_filters = 0; #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS settings->add_id = 0; settings->text_compression = 1; #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ } #endif /*LODEPNG_COMPILE_ENCODER*/ #endif /*LODEPNG_COMPILE_PNG*/ #ifdef LODEPNG_COMPILE_ERROR_TEXT /* This returns the description of a numerical error code in English. This is also the documentation of all the error codes. */ const char* lodepng_error_text(unsigned code) { switch(code) { case 0: return "no error, everything went ok"; case 1: return "nothing done yet"; /*the Encoder/Decoder has done nothing yet, error checking makes no sense yet*/ case 10: return "end of input memory reached without huffman end code"; /*while huffman decoding*/ case 11: return "error in code tree made it jump outside of huffman tree"; /*while huffman decoding*/ case 13: return "problem while processing dynamic deflate block"; case 14: return "problem while processing dynamic deflate block"; case 15: return "problem while processing dynamic deflate block"; case 16: return "unexisting code while processing dynamic deflate block"; case 17: return "end of out buffer memory reached while inflating"; case 18: return "invalid distance code while inflating"; case 19: return "end of out buffer memory reached while inflating"; case 20: return "invalid deflate block BTYPE encountered while decoding"; case 21: return "NLEN is not ones complement of LEN in a deflate block"; /*end of out buffer memory reached while inflating: This can happen if the inflated deflate data is longer than the amount of bytes required to fill up all the pixels of the image, given the color depth and image dimensions. Something that doesn't happen in a normal, well encoded, PNG image.*/ case 22: return "end of out buffer memory reached while inflating"; case 23: return "end of in buffer memory reached while inflating"; case 24: return "invalid FCHECK in zlib header"; case 25: return "invalid compression method in zlib header"; case 26: return "FDICT encountered in zlib header while it's not used for PNG"; case 27: return "PNG file is smaller than a PNG header"; /*Checks the magic file header, the first 8 bytes of the PNG file*/ case 28: return "incorrect PNG signature, it's no PNG or corrupted"; case 29: return "first chunk is not the header chunk"; case 30: return "chunk length too large, chunk broken off at end of file"; case 31: return "illegal PNG color type or bpp"; case 32: return "illegal PNG compression method"; case 33: return "illegal PNG filter method"; case 34: return "illegal PNG interlace method"; case 35: return "chunk length of a chunk is too large or the chunk too small"; case 36: return "illegal PNG filter type encountered"; case 37: return "illegal bit depth for this color type given"; case 38: return "the palette is too big"; /*more than 256 colors*/ case 39: return "more palette alpha values given in tRNS chunk than there are colors in the palette"; case 40: return "tRNS chunk has wrong size for greyscale image"; case 41: return "tRNS chunk has wrong size for RGB image"; case 42: return "tRNS chunk appeared while it was not allowed for this color type"; case 43: return "bKGD chunk has wrong size for palette image"; case 44: return "bKGD chunk has wrong size for greyscale image"; case 45: return "bKGD chunk has wrong size for RGB image"; case 48: return "empty input buffer given to decoder. Maybe caused by non-existing file?"; case 49: return "jumped past memory while generating dynamic huffman tree"; case 50: return "jumped past memory while generating dynamic huffman tree"; case 51: return "jumped past memory while inflating huffman block"; case 52: return "jumped past memory while inflating"; case 53: return "size of zlib data too small"; case 54: return "repeat symbol in tree while there was no value symbol yet"; /*jumped past tree while generating huffman tree, this could be when the tree will have more leaves than symbols after generating it out of the given lenghts. They call this an oversubscribed dynamic bit lengths tree in zlib.*/ case 55: return "jumped past tree while generating huffman tree"; case 56: return "given output image colortype or bitdepth not supported for color conversion"; case 57: return "invalid CRC encountered (checking CRC can be disabled)"; case 58: return "invalid ADLER32 encountered (checking ADLER32 can be disabled)"; case 59: return "requested color conversion not supported"; case 60: return "invalid window size given in the settings of the encoder (must be 0-32768)"; case 61: return "invalid BTYPE given in the settings of the encoder (only 0, 1 and 2 are allowed)"; /*LodePNG leaves the choice of RGB to greyscale conversion formula to the user.*/ case 62: return "conversion from color to greyscale not supported"; case 63: return "length of a chunk too long, max allowed for PNG is 2147483647 bytes per chunk"; /*(2^31-1)*/ /*this would result in the inability of a deflated block to ever contain an end code. It must be at least 1.*/ case 64: return "the length of the END symbol 256 in the Huffman tree is 0"; case 66: return "the length of a text chunk keyword given to the encoder is longer than the maximum of 79 bytes"; case 67: return "the length of a text chunk keyword given to the encoder is smaller than the minimum of 1 byte"; case 68: return "tried to encode a PLTE chunk with a palette that has less than 1 or more than 256 colors"; case 69: return "unknown chunk type with 'critical' flag encountered by the decoder"; case 71: return "unexisting interlace mode given to encoder (must be 0 or 1)"; case 72: return "while decoding, unexisting compression method encountering in zTXt or iTXt chunk (it must be 0)"; case 73: return "invalid tIME chunk size"; case 74: return "invalid pHYs chunk size"; /*length could be wrong, or data chopped off*/ case 75: return "no null termination char found while decoding text chunk"; case 76: return "iTXt chunk too short to contain required bytes"; case 77: return "integer overflow in buffer size"; case 78: return "failed to open file for reading"; /*file doesn't exist or couldn't be opened for reading*/ case 79: return "failed to open file for writing"; case 80: return "tried creating a tree of 0 symbols"; case 81: return "lazy matching at pos 0 is impossible"; case 82: return "color conversion to palette requested while a color isn't in palette"; case 83: return "memory allocation failed"; case 84: return "given image too small to contain all pixels to be encoded"; case 86: return "impossible offset in lz77 encoding (internal bug)"; case 87: return "must provide custom zlib function pointer if LODEPNG_COMPILE_ZLIB is not defined"; case 88: return "invalid filter strategy given for LodePNGEncoderSettings.filter_strategy"; case 89: return "text chunk keyword too short or long: must have size 1-79"; /*the windowsize in the LodePNGCompressSettings. Requiring POT(==> & instead of %) makes encoding 12% faster.*/ case 90: return "windowsize must be a power of two"; case 91: return "invalid decompressed idat size"; case 92: return "too many pixels, not supported"; case 93: return "zero width or height is invalid"; case 94: return "header chunk must have a size of 13 bytes"; } return "unknown error code"; } #endif /*LODEPNG_COMPILE_ERROR_TEXT*/ /* ////////////////////////////////////////////////////////////////////////// */ /* ////////////////////////////////////////////////////////////////////////// */ /* // C++ Wrapper // */ /* ////////////////////////////////////////////////////////////////////////// */ /* ////////////////////////////////////////////////////////////////////////// */ #ifdef LODEPNG_COMPILE_CPP namespace lodepng { #ifdef LODEPNG_COMPILE_DISK unsigned load_file(std::vector<unsigned char>& buffer, const std::string& filename) { long size = lodepng_filesize(filename.c_str()); if(size < 0) return 78; buffer.resize((size_t)size); return size == 0 ? 0 : lodepng_buffer_file(&buffer[0], (size_t)size, filename.c_str()); } /*write given buffer to the file, overwriting the file, it doesn't append to it.*/ unsigned save_file(const std::vector<unsigned char>& buffer, const std::string& filename) { return lodepng_save_file(buffer.empty() ? 0 : &buffer[0], buffer.size(), filename.c_str()); } #endif /* LODEPNG_COMPILE_DISK */ #ifdef LODEPNG_COMPILE_ZLIB #ifdef LODEPNG_COMPILE_DECODER unsigned decompress(std::vector<unsigned char>& out, const unsigned char* in, size_t insize, const LodePNGDecompressSettings& settings) { unsigned char* buffer = 0; size_t buffersize = 0; unsigned error = zlib_decompress(&buffer, &buffersize, in, insize, &settings); if(buffer) { out.insert(out.end(), &buffer[0], &buffer[buffersize]); lodepng_free(buffer); } return error; } unsigned decompress(std::vector<unsigned char>& out, const std::vector<unsigned char>& in, const LodePNGDecompressSettings& settings) { return decompress(out, in.empty() ? 0 : &in[0], in.size(), settings); } #endif /* LODEPNG_COMPILE_DECODER */ #ifdef LODEPNG_COMPILE_ENCODER unsigned compress(std::vector<unsigned char>& out, const unsigned char* in, size_t insize, const LodePNGCompressSettings& settings) { unsigned char* buffer = 0; size_t buffersize = 0; unsigned error = zlib_compress(&buffer, &buffersize, in, insize, &settings); if(buffer) { out.insert(out.end(), &buffer[0], &buffer[buffersize]); lodepng_free(buffer); } return error; } unsigned compress(std::vector<unsigned char>& out, const std::vector<unsigned char>& in, const LodePNGCompressSettings& settings) { return compress(out, in.empty() ? 0 : &in[0], in.size(), settings); } #endif /* LODEPNG_COMPILE_ENCODER */ #endif /* LODEPNG_COMPILE_ZLIB */ #ifdef LODEPNG_COMPILE_PNG State::State() { lodepng_state_init(this); } State::State(const State& other) { lodepng_state_init(this); lodepng_state_copy(this, &other); } State::~State() { lodepng_state_cleanup(this); } State& State::operator=(const State& other) { lodepng_state_copy(this, &other); return *this; } #ifdef LODEPNG_COMPILE_DECODER unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h, const unsigned char* in, size_t insize, LodePNGColorType colortype, unsigned bitdepth) { unsigned char* buffer; unsigned error = lodepng_decode_memory(&buffer, &w, &h, in, insize, colortype, bitdepth); if(buffer && !error) { State state; state.info_raw.colortype = colortype; state.info_raw.bitdepth = bitdepth; size_t buffersize = lodepng_get_raw_size(w, h, &state.info_raw); out.insert(out.end(), &buffer[0], &buffer[buffersize]); lodepng_free(buffer); } return error; } unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h, const std::vector<unsigned char>& in, LodePNGColorType colortype, unsigned bitdepth) { return decode(out, w, h, in.empty() ? 0 : &in[0], (unsigned)in.size(), colortype, bitdepth); } unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h, State& state, const unsigned char* in, size_t insize) { unsigned char* buffer = NULL; unsigned error = lodepng_decode(&buffer, &w, &h, &state, in, insize); if(buffer && !error) { size_t buffersize = lodepng_get_raw_size(w, h, &state.info_raw); out.insert(out.end(), &buffer[0], &buffer[buffersize]); } lodepng_free(buffer); return error; } unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h, State& state, const std::vector<unsigned char>& in) { return decode(out, w, h, state, in.empty() ? 0 : &in[0], in.size()); } #ifdef LODEPNG_COMPILE_DISK unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h, const std::string& filename, LodePNGColorType colortype, unsigned bitdepth) { std::vector<unsigned char> buffer; unsigned error = load_file(buffer, filename); if(error) return error; return decode(out, w, h, buffer, colortype, bitdepth); } #endif /* LODEPNG_COMPILE_DECODER */ #endif /* LODEPNG_COMPILE_DISK */ #ifdef LODEPNG_COMPILE_ENCODER unsigned encode(std::vector<unsigned char>& out, const unsigned char* in, unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth) { unsigned char* buffer; size_t buffersize; unsigned error = lodepng_encode_memory(&buffer, &buffersize, in, w, h, colortype, bitdepth); if(buffer) { out.insert(out.end(), &buffer[0], &buffer[buffersize]); lodepng_free(buffer); } return error; } unsigned encode(std::vector<unsigned char>& out, const std::vector<unsigned char>& in, unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth) { if(lodepng_get_raw_size_lct(w, h, colortype, bitdepth) > in.size()) return 84; return encode(out, in.empty() ? 0 : &in[0], w, h, colortype, bitdepth); } unsigned encode(std::vector<unsigned char>& out, const unsigned char* in, unsigned w, unsigned h, State& state) { unsigned char* buffer; size_t buffersize; unsigned error = lodepng_encode(&buffer, &buffersize, in, w, h, &state); if(buffer) { out.insert(out.end(), &buffer[0], &buffer[buffersize]); lodepng_free(buffer); } return error; } unsigned encode(std::vector<unsigned char>& out, const std::vector<unsigned char>& in, unsigned w, unsigned h, State& state) { if(lodepng_get_raw_size(w, h, &state.info_raw) > in.size()) return 84; return encode(out, in.empty() ? 0 : &in[0], w, h, state); } #ifdef LODEPNG_COMPILE_DISK unsigned encode(const std::string& filename, const unsigned char* in, unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth) { std::vector<unsigned char> buffer; unsigned error = encode(buffer, in, w, h, colortype, bitdepth); if(!error) error = save_file(buffer, filename); return error; } unsigned encode(const std::string& filename, const std::vector<unsigned char>& in, unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth) { if(lodepng_get_raw_size_lct(w, h, colortype, bitdepth) > in.size()) return 84; return encode(filename, in.empty() ? 0 : &in[0], w, h, colortype, bitdepth); } #endif /* LODEPNG_COMPILE_DISK */ #endif /* LODEPNG_COMPILE_ENCODER */ #endif /* LODEPNG_COMPILE_PNG */ } /* namespace lodepng */ #endif /*LODEPNG_COMPILE_CPP*/ �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/libeg/load_icns.c���������������������������������������������������������������������0000664�0001750�0001750�00000017404�12626644770�016517� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * libeg/load_icns.c * Loading function for .icns Apple icon images * * Copyright (c) 2006 Christoph Pfisterer * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * * Neither the name of Christoph Pfisterer nor the names of the * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "libegint.h" #define MAX_ICNS_SIZES 4 // // Decompress .icns RLE data // VOID egDecompressIcnsRLE(IN OUT UINT8 **CompData, IN OUT UINTN *CompLen, IN UINT8 *PixelData, IN UINTN PixelCount) { UINT8 *cp; UINT8 *cp_end; UINT8 *pp; UINTN pp_left; UINTN len, i; UINT8 value; // setup variables cp = *CompData; cp_end = cp + *CompLen; pp = PixelData; pp_left = PixelCount; // decode while (cp + 1 < cp_end && pp_left > 0) { len = *cp++; if (len & 0x80) { // compressed data: repeat next byte len -= 125; if (len > pp_left) break; value = *cp++; for (i = 0; i < len; i++) { *pp = value; pp += 4; } } else { // uncompressed data: copy bytes len++; if (len > pp_left || cp + len > cp_end) break; for (i = 0; i < len; i++) { *pp = *cp++; pp += 4; } } pp_left -= len; } if (pp_left > 0) { Print(L" egDecompressIcnsRLE: still need %d bytes of pixel data\n", pp_left); } // record what's left of the compressed data stream *CompData = cp; *CompLen = (UINTN)(cp_end - cp); } // // Load Apple .icns icons // EG_IMAGE * egDecodeICNS(IN UINT8 *FileData, IN UINTN FileDataLength, IN UINTN IconSize, IN BOOLEAN WantAlpha) { EG_IMAGE *NewImage; UINT8 *Ptr, *BufferEnd, *DataPtr, *MaskPtr; UINT32 BlockLen, DataLen, MaskLen; UINTN PixelCount, i; UINT8 *CompData; UINTN CompLen; UINT8 *SrcPtr; EG_PIXEL *DestPtr; UINTN SizesToTry[MAX_ICNS_SIZES + 1] = {IconSize, 128, 48, 32, 16}; UINTN SizeToTry = 0; if (FileDataLength < 8 || FileData == NULL || FileData[0] != 'i' || FileData[1] != 'c' || FileData[2] != 'n' || FileData[3] != 's') { // not an icns file... return NULL; } for (;;) { DataPtr = NULL; DataLen = 0; MaskPtr = NULL; MaskLen = 0; do { IconSize = SizesToTry[SizeToTry]; Ptr = FileData + 8; BufferEnd = FileData + FileDataLength; // iterate over tagged blocks in the file while (Ptr + 8 <= BufferEnd) { BlockLen = ((UINT32)Ptr[4] << 24) + ((UINT32)Ptr[5] << 16) + ((UINT32)Ptr[6] << 8) + (UINT32)Ptr[7]; if (Ptr + BlockLen > BufferEnd) // block continues beyond end of file break; // extract the appropriate blocks for each pixel size if (IconSize == 128) { if (Ptr[0] == 'i' && Ptr[1] == 't' && Ptr[2] == '3' && Ptr[3] == '2') { if (Ptr[8] == 0 && Ptr[9] == 0 && Ptr[10] == 0 && Ptr[11] == 0) { DataPtr = Ptr + 12; DataLen = BlockLen - 12; } } else if (Ptr[0] == 't' && Ptr[1] == '8' && Ptr[2] == 'm' && Ptr[3] == 'k') { MaskPtr = Ptr + 8; MaskLen = BlockLen - 8; } } else if (IconSize == 48) { if (Ptr[0] == 'i' && Ptr[1] == 'h' && Ptr[2] == '3' && Ptr[3] == '2') { DataPtr = Ptr + 8; DataLen = BlockLen - 8; } else if (Ptr[0] == 'h' && Ptr[1] == '8' && Ptr[2] == 'm' && Ptr[3] == 'k') { MaskPtr = Ptr + 8; MaskLen = BlockLen - 8; } } else if (IconSize == 32) { if (Ptr[0] == 'i' && Ptr[1] == 'l' && Ptr[2] == '3' && Ptr[3] == '2') { DataPtr = Ptr + 8; DataLen = BlockLen - 8; } else if (Ptr[0] == 'l' && Ptr[1] == '8' && Ptr[2] == 'm' && Ptr[3] == 'k') { MaskPtr = Ptr + 8; MaskLen = BlockLen - 8; } } else if (IconSize == 16) { if (Ptr[0] == 'i' && Ptr[1] == 's' && Ptr[2] == '3' && Ptr[3] == '2') { DataPtr = Ptr + 8; DataLen = BlockLen - 8; } else if (Ptr[0] == 's' && Ptr[1] == '8' && Ptr[2] == 'm' && Ptr[3] == 'k') { MaskPtr = Ptr + 8; MaskLen = BlockLen - 8; } } Ptr += BlockLen; } } while ((DataPtr == NULL) && (SizeToTry++ < MAX_ICNS_SIZES)); break; } if (DataPtr == NULL) return NULL; // no image found // allocate image structure and buffer NewImage = egCreateImage(IconSize, IconSize, WantAlpha); if (NewImage == NULL) return NULL; PixelCount = IconSize * IconSize; if (DataLen < PixelCount * 3) { // pixel data is compressed, RGB planar CompData = DataPtr; CompLen = DataLen; egDecompressIcnsRLE(&CompData, &CompLen, PLPTR(NewImage, r), PixelCount); egDecompressIcnsRLE(&CompData, &CompLen, PLPTR(NewImage, g), PixelCount); egDecompressIcnsRLE(&CompData, &CompLen, PLPTR(NewImage, b), PixelCount); // possible assertion: CompLen == 0 if (CompLen > 0) { Print(L" egLoadICNSIcon: %d bytes of compressed data left\n", CompLen); } } else { // pixel data is uncompressed, RGB interleaved SrcPtr = DataPtr; DestPtr = NewImage->PixelData; for (i = 0; i < PixelCount; i++, DestPtr++) { DestPtr->r = *SrcPtr++; DestPtr->g = *SrcPtr++; DestPtr->b = *SrcPtr++; } } // add/set alpha plane if (MaskPtr != NULL && MaskLen >= PixelCount && WantAlpha) egInsertPlane(MaskPtr, PLPTR(NewImage, a), PixelCount); else egSetPlane(PLPTR(NewImage, a), WantAlpha ? 255 : 0, PixelCount); // FUTURE: scale to originally requested size if we had to load another size return NewImage; } // EG_IMAGE * egDecodeICNS() /* EOF */ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/libeg/lodepng_xtra.c������������������������������������������������������������������0000664�0001750�0001750�00000010234�13323120507�017222� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Additional functions to support LodePNG for use in rEFInd * * copyright (c) 2013 by by Roderick W. Smith, and distributed * under the terms of the GNU GPL v3, or (at your option) any * later version. * * See http://lodev.org/lodepng/ for the original LodePNG. * */ /* * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "global.h" #include "../refind/screen.h" #include "lodepng.h" // EFI's equivalent of realloc requires the original buffer's size as an // input parameter, which the standard libc realloc does not require. Thus, // I've modified lodepng_malloc() to allocate more memory to store this data, // and lodepng_realloc() can then read it when required. Because the size is // stored at the start of the allocated area, these functions are NOT // interchangeable with the standard EFI functions; memory allocated via // lodepng_malloc() should be freed via lodepng_free(), and myfree() should // NOT be used with memory allocated via AllocatePool() or AllocateZeroPool()! void* lodepng_malloc(size_t size) { void *ptr; ptr = AllocateZeroPool(size + sizeof(size_t)); if (ptr) { *(size_t *) ptr = size; return ((size_t *) ptr) + 1; } else { return NULL; } } // void* lodepng_malloc() void lodepng_free (void *ptr) { if (ptr) { ptr = (void *) (((size_t *) ptr) - 1); FreePool(ptr); } } // void lodepng_free() static size_t report_size(void *ptr) { if (ptr) return * (((size_t *) ptr) - 1); else return 0; } // size_t report_size() void* lodepng_realloc(void *ptr, size_t new_size) { size_t *new_pool; size_t old_size; new_pool = lodepng_malloc(new_size); if (new_pool && ptr) { old_size = report_size(ptr); CopyMem(new_pool, ptr, (old_size < new_size) ? old_size : new_size); } return new_pool; } // lodepng_realloc() // Finds length of ASCII string, which MUST be NULL-terminated. int MyStrlen(const char *InString) { int Length = 0; if (InString) { while (InString[Length] != '\0') Length++; } return Length; } // int MyStrlen() VOID *MyMemSet(VOID *s, int c, size_t n) { SetMem(s, c, n); return s; } VOID *MyMemCpy(void *__restrict __dest, const void *__restrict __src, size_t __n) { CopyMem(__dest, __src, __n); return __dest; } typedef struct _lode_color { UINT8 red; UINT8 green; UINT8 blue; UINT8 alpha; } lode_color; EG_IMAGE * egDecodePNG(IN UINT8 *FileData, IN UINTN FileDataLength, IN UINTN IconSize, IN BOOLEAN WantAlpha) { EG_IMAGE *NewImage = NULL; unsigned Error, Width, Height; EG_PIXEL *PixelData; lode_color *LodeData; UINTN i; Error = lodepng_decode_memory((unsigned char **) &PixelData, &Width, &Height, (unsigned char*) FileData, (size_t) FileDataLength, LCT_RGBA, 8); if (Error) { return NULL; } // allocate image structure and buffer NewImage = egCreateImage(Width, Height, WantAlpha); if ((NewImage == NULL) || (NewImage->Width != Width) || (NewImage->Height != Height)) return NULL; LodeData = (lode_color *) PixelData; // Annoyingly, EFI and LodePNG use different ordering of RGB values in // their pixel data representations, so we've got to adjust them.... for (i = 0; i < (NewImage->Height * NewImage->Width); i++) { NewImage->PixelData[i].r = LodeData[i].red; NewImage->PixelData[i].g = LodeData[i].green; NewImage->PixelData[i].b = LodeData[i].blue; if (WantAlpha) NewImage->PixelData[i].a = LodeData[i].alpha; } lodepng_free(PixelData); return NewImage; } // EG_IMAGE * egDecodePNG() ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/libeg/egemb_font.h��������������������������������������������������������������������0000664�0001750�0001750�00000116126�12626705705�016673� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������static const UINT8 egemb_liberation_mono_regular_14_data[6544] = { 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xd9, 0x00, 0x8e, 0x00, 0x05, 0x14, 0xff, 0x64, 0x02, 0xfe, 0x77, 0x89, 0x00, 0x01, 0x30, 0xb0, 0x93, 0x00, 0x01, 0x88, 0xef, 0x84, 0x00, 0x02, 0x89, 0xc1, 0x01, 0x80, 0x00, 0x02, 0x5f, 0xe2, 0x0d, 0x83, 0x00, 0x01, 0x3b, 0xa7, 0xa5, 0x00, 0x02, 0x03, 0xd9, 0x5b, 0xff, 0x00, 0x04, 0x38, 0xc2, 0xd8, 0xcc, 0x46, 0xff, 0x00, 0xce, 0x00, 0x00, 0x34, 0x80, 0xff, 0x04, 0x8c, 0x00, 0x0c, 0xeb, 0x41, 0x83, 0x00, 0x00, 0x28, 0x80, 0xff, 0x00, 0x94, 0x91, 0x00, 0x02, 0x15, 0xd1, 0x83, 0x89, 0x00, 0x01, 0xbc, 0x80, 0x8f, 0x00, 0x02, 0x18, 0xff, 0x20, 0x88, 0x00, 0x04, 0x5b, 0xd9, 0xf9, 0xf4, 0x74, 0x86, 0x00, 0x01, 0xbc, 0x80, 0x85, 0x00, 0x02, 0x48, 0xff, 0x18, 0x83, 0x00, 0x01, 0xa8, 0xb8, 0x80, 0x00, 0x01, 0x64, 0xd8, 0x83, 0x00, 0x00, 0x2c, 0x80, 0xff, 0x00, 0x08, 0xf2, 0x00, 0x04, 0x10, 0xbb, 0xfb, 0xff, 0x40, 0x80, 0x00, 0x01, 0x60, 0xc4, 0x81, 0x00, 0x03, 0xdc, 0xff, 0xe3, 0x48, 0x9b, 0x00, 0x01, 0x75, 0xdc, 0x81, 0x00, 0x05, 0x05, 0xff, 0x54, 0x00, 0xf2, 0x67, 0x80, 0x00, 0x1c, 0x03, 0xbd, 0x00, 0x00, 0xb9, 0x08, 0x00, 0x36, 0xc5, 0xf4, 0xfd, 0xe5, 0x7c, 0x00, 0x56, 0xcb, 0xcb, 0x46, 0x00, 0x00, 0x6e, 0x92, 0x00, 0x00, 0x66, 0xdf, 0xe5, 0x99, 0x02, 0x81, 0x00, 0x01, 0x79, 0xdf, 0x83, 0x00, 0x02, 0x35, 0xf4, 0x23, 0x82, 0x00, 0x01, 0xb7, 0x96, 0x81, 0x00, 0x05, 0x0f, 0x69, 0x3e, 0x9d, 0x3c, 0x44, 0xa3, 0x00, 0x09, 0x60, 0xd6, 0x02, 0x00, 0x02, 0x88, 0xe9, 0xf7, 0xbc, 0x22, 0x81, 0x00, 0x02, 0x2b, 0xf9, 0x50, 0x80, 0x00, 0x0d, 0x04, 0x8a, 0xe5, 0xf3, 0xc3, 0x38, 0x00, 0x00, 0x0b, 0x97, 0xe7, 0xf4, 0xca, 0x44, 0x82, 0x00, 0x05, 0x42, 0xff, 0x68, 0x00, 0x00, 0x8d, 0x81, 0xff, 0x00, 0xf4, 0x80, 0x00, 0x07, 0x43, 0xd2, 0xf8, 0xd5, 0x4a, 0x00, 0x00, 0xec, 0x82, 0xff, 0x0f, 0x50, 0x00, 0x10, 0xa1, 0xed, 0xf7, 0xc6, 0x3c, 0x00, 0x00, 0x0c, 0x93, 0xe5, 0xf6, 0xb4, 0x1a, 0xa7, 0x00, 0x0e, 0x17, 0xa2, 0xe9, 0xf0, 0xbe, 0x36, 0x00, 0x00, 0x33, 0xd2, 0x2b, 0x00, 0x1c, 0xcf, 0x31, 0x80, 0x00, 0x02, 0xb1, 0xff, 0x23, 0x80, 0x00, 0x18, 0xe4, 0xff, 0xff, 0xf0, 0xc9, 0x50, 0x00, 0x00, 0x01, 0x78, 0xe0, 0xf7, 0xcd, 0x43, 0x00, 0x00, 0xe4, 0xff, 0xfa, 0xdc, 0x89, 0x0b, 0x00, 0x00, 0xe4, 0x82, 0xff, 0x02, 0x64, 0x00, 0xac, 0x82, 0xff, 0x12, 0x6c, 0x00, 0x01, 0x7d, 0xe2, 0xf7, 0xc9, 0x3c, 0x00, 0x00, 0xe4, 0x68, 0x00, 0x00, 0x04, 0xff, 0x48, 0x00, 0xa0, 0x82, 0xff, 0x81, 0x00, 0x0f, 0xb0, 0xff, 0xff, 0xbc, 0x00, 0x00, 0xe4, 0x68, 0x00, 0x00, 0x22, 0xee, 0x74, 0x00, 0x60, 0xec, 0x82, 0x00, 0x0a, 0x20, 0xff, 0xac, 0x00, 0x00, 0x34, 0xff, 0x84, 0x00, 0xe4, 0xd5, 0x80, 0x00, 0x2a, 0xe4, 0x48, 0x00, 0x04, 0x8c, 0xe9, 0xf7, 0xbc, 0x27, 0x00, 0x00, 0xe4, 0xff, 0xff, 0xf5, 0xcf, 0x57, 0x00, 0x00, 0x03, 0x88, 0xe8, 0xf6, 0xb9, 0x23, 0x00, 0x00, 0xe4, 0xff, 0xff, 0xf9, 0xd7, 0x67, 0x00, 0x00, 0x1c, 0xa9, 0xe9, 0xf6, 0xd1, 0x52, 0x00, 0x7c, 0x83, 0xff, 0x03, 0xe0, 0x08, 0xff, 0x48, 0x80, 0x00, 0x03, 0xe0, 0x6c, 0xc4, 0x99, 0x81, 0x00, 0x03, 0x36, 0xff, 0xf1, 0x5b, 0x82, 0x00, 0x0b, 0xf2, 0x70, 0xfa, 0x39, 0x00, 0x00, 0x03, 0xd0, 0x90, 0x75, 0xe2, 0x09, 0x80, 0x00, 0x02, 0x88, 0xd7, 0x05, 0x83, 0xff, 0x0b, 0x94, 0x00, 0x00, 0x34, 0xff, 0x0b, 0x04, 0x02, 0x00, 0x00, 0x75, 0xc3, 0x84, 0x00, 0x03, 0x04, 0x04, 0xa5, 0x94, 0x82, 0x00, 0x02, 0xb3, 0xf4, 0x17, 0x8a, 0x00, 0x02, 0x0e, 0xb8, 0x57, 0x88, 0x00, 0x01, 0xbc, 0x80, 0x8f, 0x00, 0x02, 0x18, 0xff, 0x20, 0x87, 0x00, 0x05, 0x13, 0xf8, 0x83, 0x25, 0x20, 0x15, 0x86, 0x00, 0x01, 0xbc, 0x80, 0x85, 0x00, 0x02, 0x1d, 0x68, 0x09, 0x83, 0x00, 0x01, 0x44, 0x4a, 0x80, 0x00, 0x01, 0x64, 0xd8, 0x83, 0x00, 0x04, 0x01, 0x08, 0x3a, 0xff, 0x08, 0xb9, 0x00, 0x01, 0x3d, 0xac, 0xb4, 0x00, 0x04, 0x74, 0xd3, 0x14, 0x04, 0x01, 0x80, 0x00, 0x01, 0x60, 0xc4, 0x81, 0x00, 0x03, 0x03, 0x07, 0x7c, 0xdb, 0x89, 0x00, 0x05, 0x17, 0xa2, 0xe9, 0xf0, 0xbe, 0x36, 0x89, 0x00, 0x01, 0x6f, 0xd6, 0x82, 0x00, 0x04, 0xf5, 0x44, 0x00, 0xe4, 0x56, 0x80, 0x00, 0x1c, 0x2c, 0x96, 0x00, 0x00, 0xc1, 0x00, 0x00, 0xe4, 0x7a, 0x35, 0xb0, 0x32, 0xef, 0x50, 0xde, 0x1e, 0x34, 0xc9, 0x00, 0x1d, 0xd5, 0x0c, 0x00, 0x17, 0xee, 0x1d, 0x07, 0xd2, 0x48, 0x81, 0x00, 0x01, 0x69, 0xce, 0x83, 0x00, 0x01, 0xb5, 0x97, 0x83, 0x00, 0x02, 0x36, 0xfa, 0x1c, 0x80, 0x00, 0x05, 0x18, 0x91, 0xd9, 0xf2, 0xad, 0x4a, 0x81, 0x00, 0x01, 0x15, 0x2f, 0x9c, 0x00, 0x11, 0x04, 0xdd, 0x57, 0x00, 0x00, 0x75, 0xe6, 0x41, 0x25, 0xa6, 0xd4, 0x02, 0x00, 0x11, 0x5e, 0xe1, 0xf8, 0x50, 0x80, 0x00, 0x0e, 0x81, 0xe0, 0x3c, 0x21, 0x98, 0xec, 0x0c, 0x00, 0x9c, 0xcf, 0x35, 0x1f, 0x8a, 0xf5, 0x11, 0x80, 0x00, 0x07, 0x06, 0xd6, 0xf2, 0x68, 0x00, 0x00, 0x9e, 0x97, 0x80, 0x0c, 0x0b, 0x0b, 0x00, 0x00, 0x25, 0xf0, 0x63, 0x1f, 0x74, 0xec, 0x0d, 0x00, 0x0b, 0x80, 0x0c, 0x11, 0x36, 0xed, 0x15, 0x00, 0xa2, 0xc4, 0x1b, 0x08, 0x78, 0xf2, 0x10, 0x00, 0x9c, 0xd3, 0x33, 0x24, 0xb3, 0xc5, 0x94, 0x00, 0x01, 0x2f, 0x51, 0x85, 0x00, 0x02, 0x20, 0x5b, 0x05, 0x82, 0x00, 0x0a, 0x01, 0xc7, 0xbc, 0x33, 0x26, 0x91, 0xee, 0x12, 0x00, 0xc5, 0x30, 0x80, 0x00, 0x07, 0x47, 0xa9, 0x00, 0x00, 0x10, 0xf7, 0xbc, 0x7b, 0x80, 0x00, 0x19, 0xe4, 0x78, 0x1c, 0x2a, 0x8b, 0xfb, 0x1f, 0x00, 0x74, 0xfa, 0x6c, 0x31, 0x89, 0xf7, 0x2a, 0x00, 0xe4, 0x7d, 0x30, 0x60, 0xe4, 0xc0, 0x02, 0x00, 0xe4, 0x7d, 0x81, 0x24, 0x03, 0x0e, 0x00, 0xac, 0xad, 0x81, 0x24, 0x17, 0x0f, 0x00, 0x78, 0xf7, 0x67, 0x30, 0x90, 0xf3, 0x1d, 0x00, 0xe4, 0x68, 0x00, 0x00, 0x04, 0xff, 0x48, 0x00, 0x16, 0x24, 0x87, 0xdd, 0x24, 0x24, 0x81, 0x00, 0x0f, 0x18, 0x24, 0x9f, 0xbc, 0x00, 0x00, 0xe4, 0x68, 0x00, 0x09, 0xd0, 0xa3, 0x00, 0x00, 0x60, 0xec, 0x82, 0x00, 0x42, 0x20, 0xf9, 0xee, 0x0d, 0x00, 0x8d, 0xf2, 0x84, 0x00, 0xe4, 0xf9, 0x44, 0x00, 0x00, 0xe4, 0x48, 0x00, 0x89, 0xf3, 0x5a, 0x3a, 0xbd, 0xe2, 0x0a, 0x00, 0xe4, 0x78, 0x1c, 0x28, 0x75, 0xfd, 0x42, 0x00, 0x81, 0xf5, 0x5c, 0x3b, 0xc0, 0xdc, 0x07, 0x00, 0xe4, 0x78, 0x1c, 0x25, 0x6c, 0xfd, 0x4b, 0x00, 0xbe, 0xb8, 0x26, 0x16, 0x7a, 0xfb, 0x28, 0x11, 0x24, 0x24, 0x87, 0xdd, 0x24, 0x24, 0x1f, 0x08, 0xff, 0x48, 0x80, 0x00, 0x04, 0xe0, 0x6c, 0x6c, 0xe9, 0x03, 0x80, 0x00, 0x03, 0x89, 0xcf, 0xc9, 0x79, 0x81, 0x00, 0x12, 0x11, 0xff, 0x2c, 0x8a, 0xce, 0x03, 0x00, 0x6d, 0xe4, 0x0d, 0x06, 0xd9, 0x7c, 0x00, 0x00, 0x1f, 0xf7, 0x47, 0x00, 0x81, 0x24, 0x07, 0x54, 0xfb, 0x3e, 0x00, 0x00, 0x34, 0xff, 0x08, 0x81, 0x00, 0x02, 0x0a, 0xe8, 0x46, 0x85, 0x00, 0x01, 0xa4, 0x94, 0x81, 0x00, 0x03, 0x1d, 0xdc, 0x8a, 0x79, 0x98, 0x00, 0x01, 0xbc, 0x80, 0x8f, 0x00, 0x02, 0x18, 0xff, 0x20, 0x87, 0x00, 0x02, 0x39, 0xfd, 0x03, 0x89, 0x00, 0x01, 0xbc, 0x7f, 0x93, 0x00, 0x01, 0x64, 0xd8, 0x85, 0x00, 0x02, 0x34, 0xff, 0x08, 0xad, 0x00, 0x00, 0x01, 0x88, 0x00, 0x01, 0x6f, 0xac, 0xb4, 0x00, 0x01, 0x8f, 0xa1, 0x83, 0x00, 0x01, 0x60, 0xc4, 0x83, 0x00, 0x01, 0x39, 0xf7, 0x88, 0x00, 0x06, 0x01, 0xc7, 0xbc, 0x33, 0x26, 0x91, 0xee, 0x89, 0x00, 0x01, 0x68, 0xcf, 0x82, 0x00, 0x04, 0xe6, 0x35, 0x00, 0xd5, 0x46, 0x80, 0x00, 0x1c, 0x5e, 0x65, 0x00, 0x22, 0xa1, 0x00, 0x13, 0xff, 0x1c, 0x30, 0xb0, 0x00, 0x5e, 0x43, 0xf8, 0x04, 0x19, 0xe4, 0x00, 0xb4, 0x4b, 0x00, 0x00, 0x2c, 0xd6, 0x00, 0x07, 0xd7, 0x41, 0x81, 0x00, 0x01, 0x5a, 0xbe, 0x82, 0x00, 0x02, 0x21, 0xfe, 0x2b, 0x84, 0x00, 0x01, 0xca, 0x81, 0x81, 0x00, 0x03, 0x06, 0xc8, 0xc5, 0x37, 0x82, 0x00, 0x01, 0x50, 0xb4, 0x9c, 0x00, 0x11, 0x65, 0xd3, 0x01, 0x00, 0x00, 0xdb, 0x64, 0x00, 0x00, 0x0b, 0xf7, 0x3e, 0x00, 0xfa, 0xc5, 0x3d, 0xec, 0x50, 0x80, 0x00, 0x0e, 0x9a, 0x5c, 0x00, 0x00, 0x0e, 0xff, 0x36, 0x00, 0x78, 0x35, 0x00, 0x00, 0x0f, 0xff, 0x32, 0x80, 0x00, 0x07, 0x7c, 0x94, 0xd4, 0x68, 0x00, 0x00, 0xaf, 0x7f, 0x83, 0x00, 0x01, 0x93, 0x97, 0x87, 0x00, 0x12, 0xbe, 0x72, 0x00, 0x00, 0xd1, 0x6f, 0x00, 0x00, 0x13, 0xff, 0x31, 0x00, 0xef, 0x51, 0x00, 0x00, 0x14, 0xfe, 0x29, 0x80, 0x00, 0x01, 0x9c, 0xff, 0x83, 0x00, 0x01, 0x9c, 0xff, 0x83, 0x00, 0x05, 0x01, 0x4a, 0xbd, 0xe9, 0x59, 0x30, 0x83, 0xf0, 0x05, 0x8e, 0x1a, 0xc6, 0xe4, 0x76, 0x10, 0x80, 0x00, 0x15, 0x35, 0xfc, 0x13, 0x00, 0x00, 0x01, 0xf5, 0x45, 0x2e, 0xb8, 0x06, 0xa7, 0xc8, 0x7e, 0x9d, 0xd9, 0x01, 0x00, 0x63, 0xc8, 0x58, 0xd2, 0x80, 0x00, 0x09, 0xe4, 0x68, 0x00, 0x00, 0x0c, 0xff, 0x43, 0x01, 0xe6, 0x85, 0x80, 0x00, 0x0c, 0x99, 0x4c, 0x00, 0xe4, 0x68, 0x00, 0x00, 0x21, 0xfb, 0x4c, 0x00, 0xe4, 0x68, 0x83, 0x00, 0x01, 0xac, 0xa0, 0x82, 0x00, 0x02, 0x01, 0xe7, 0x7f, 0x80, 0x00, 0x09, 0xab, 0x42, 0x00, 0xe4, 0x68, 0x00, 0x00, 0x04, 0xff, 0x48, 0x80, 0x00, 0x01, 0x74, 0xd8, 0x85, 0x00, 0x0d, 0x90, 0xbc, 0x00, 0x00, 0xe4, 0x68, 0x00, 0xa3, 0xcb, 0x08, 0x00, 0x00, 0x60, 0xec, 0x82, 0x00, 0x1a, 0x20, 0xf5, 0xb4, 0x5f, 0x02, 0xe3, 0xb2, 0x84, 0x00, 0xe4, 0xb1, 0xb1, 0x00, 0x00, 0xe4, 0x48, 0x06, 0xf2, 0x7a, 0x00, 0x00, 0x16, 0xfc, 0x5f, 0x00, 0xe4, 0x68, 0x80, 0x00, 0x0c, 0xbf, 0x92, 0x04, 0xee, 0x7e, 0x00, 0x00, 0x19, 0xfd, 0x59, 0x00, 0xe4, 0x68, 0x80, 0x00, 0x04, 0xbd, 0x94, 0x00, 0xf8, 0x51, 0x80, 0x00, 0x01, 0x77, 0x2a, 0x80, 0x00, 0x01, 0x74, 0xd8, 0x80, 0x00, 0x02, 0x08, 0xff, 0x48, 0x80, 0x00, 0x04, 0xe0, 0x6c, 0x17, 0xfc, 0x41, 0x80, 0x00, 0x03, 0xdc, 0x76, 0xa4, 0x97, 0x81, 0x00, 0x10, 0x2f, 0xfe, 0x09, 0x0a, 0xe0, 0x6c, 0x16, 0xef, 0x52, 0x00, 0x00, 0x4a, 0xf3, 0x19, 0x00, 0xa8, 0xb1, 0x82, 0x00, 0x02, 0x0a, 0xd7, 0x85, 0x80, 0x00, 0x02, 0x34, 0xff, 0x08, 0x82, 0x00, 0x01, 0x71, 0xc7, 0x85, 0x00, 0x01, 0xa4, 0x94, 0x81, 0x00, 0x04, 0x80, 0x7e, 0x25, 0xdd, 0x01, 0x8f, 0x00, 0x27, 0x13, 0xac, 0xee, 0xf0, 0xb1, 0x17, 0x00, 0x00, 0xbc, 0x88, 0xa8, 0xf5, 0xd8, 0x47, 0x00, 0x00, 0x04, 0x87, 0xe6, 0xf6, 0xc7, 0x3b, 0x00, 0x00, 0x10, 0xaf, 0xf2, 0xdb, 0x5d, 0xff, 0x20, 0x00, 0x05, 0x8e, 0xea, 0xf0, 0xbf, 0x2e, 0x00, 0x10, 0x83, 0xff, 0x12, 0x54, 0x00, 0x0f, 0xac, 0xf0, 0xd6, 0x3c, 0xfe, 0x2f, 0x00, 0xbc, 0x84, 0xa3, 0xf5, 0xde, 0x50, 0x00, 0x00, 0x50, 0x80, 0xff, 0x00, 0x18, 0x80, 0x00, 0x00, 0x4c, 0x80, 0xff, 0x00, 0xb8, 0x80, 0x00, 0x06, 0x64, 0xd8, 0x00, 0x00, 0x54, 0xed, 0x29, 0x80, 0x00, 0x3e, 0x34, 0xff, 0x08, 0x00, 0x00, 0x4c, 0xbc, 0xb2, 0xec, 0x4d, 0xc2, 0xe8, 0x33, 0x00, 0xc0, 0x75, 0xa7, 0xde, 0xe1, 0x55, 0x00, 0x00, 0x05, 0x86, 0xdf, 0xef, 0xbe, 0x2c, 0x00, 0x00, 0xc1, 0x82, 0xb1, 0xe1, 0xd8, 0x48, 0x00, 0x00, 0x11, 0xb1, 0xf2, 0xda, 0x54, 0xff, 0x27, 0x00, 0x41, 0xea, 0x14, 0xb2, 0xf4, 0xff, 0x24, 0x00, 0x04, 0x91, 0xe7, 0xf6, 0xca, 0x3a, 0x00, 0x00, 0xb4, 0x81, 0xff, 0x0c, 0xa0, 0x00, 0x00, 0xbc, 0x80, 0x00, 0x00, 0x10, 0xff, 0x2c, 0x58, 0xf8, 0x0f, 0x80, 0x00, 0x03, 0xa2, 0xbb, 0xc8, 0x6e, 0x81, 0x00, 0x0c, 0x07, 0xfc, 0x37, 0xd9, 0x74, 0x00, 0x00, 0x25, 0xf4, 0x40, 0x57, 0xed, 0x07, 0x80, 0x00, 0x03, 0x8c, 0xbd, 0x00, 0xb8, 0x82, 0xff, 0x00, 0x0c, 0x80, 0x00, 0x01, 0x90, 0xa0, 0x83, 0x00, 0x01, 0x60, 0xc4, 0x83, 0x00, 0x01, 0x38, 0xf8, 0x88, 0x00, 0x06, 0x35, 0xfc, 0x13, 0x00, 0x00, 0x01, 0xf5, 0x89, 0x00, 0x01, 0x62, 0xc9, 0x82, 0x00, 0x12, 0x8b, 0x19, 0x00, 0x80, 0x24, 0x00, 0x38, 0xc8, 0xe7, 0xd3, 0xc8, 0xda, 0xe0, 0xbe, 0x01, 0xe0, 0x90, 0x3b, 0xb0, 0x80, 0x00, 0x05, 0xd5, 0x32, 0x48, 0xc0, 0x57, 0xa8, 0x80, 0x00, 0x04, 0x08, 0xed, 0x5b, 0xca, 0x8d, 0x82, 0x00, 0x01, 0x31, 0x71, 0x82, 0x00, 0x01, 0x61, 0xe6, 0x85, 0x00, 0x01, 0x85, 0xc4, 0x81, 0x00, 0x03, 0x71, 0x88, 0x2e, 0xc8, 0x82, 0x00, 0x01, 0x50, 0xb4, 0x9b, 0x00, 0x07, 0x06, 0xe1, 0x53, 0x00, 0x00, 0x0e, 0xff, 0x2e, 0x80, 0x00, 0x07, 0xcc, 0x71, 0x00, 0x06, 0x00, 0x00, 0xec, 0x50, 0x84, 0x00, 0x02, 0x32, 0xfd, 0x1c, 0x81, 0x00, 0x1a, 0x13, 0x8f, 0xd3, 0x06, 0x00, 0x00, 0x22, 0xdd, 0x0f, 0xd4, 0x68, 0x00, 0x00, 0xc0, 0xaf, 0xc8, 0xe4, 0xb5, 0x29, 0x00, 0x00, 0xd2, 0x78, 0xc0, 0xf6, 0xce, 0x3d, 0x82, 0x00, 0x0e, 0x52, 0xde, 0x05, 0x00, 0x00, 0x7f, 0xc7, 0x1c, 0x07, 0x77, 0xda, 0x06, 0x01, 0xf4, 0x49, 0x80, 0x00, 0x01, 0xf2, 0x59, 0x80, 0x00, 0x01, 0x9c, 0xff, 0x83, 0x00, 0x01, 0x9c, 0xff, 0x81, 0x00, 0x07, 0x08, 0x66, 0xd7, 0xd9, 0x67, 0x08, 0x00, 0x06, 0x83, 0x20, 0x0a, 0x13, 0x00, 0x00, 0x3a, 0xae, 0xf1, 0x92, 0x22, 0x00, 0x04, 0x0a, 0x80, 0x00, 0x1d, 0x1f, 0xfe, 0x2b, 0x6d, 0x70, 0x7d, 0x76, 0x00, 0xce, 0x6b, 0xc8, 0x11, 0x00, 0xbc, 0x78, 0x0e, 0xf8, 0x29, 0x00, 0x00, 0xe4, 0x68, 0x00, 0x03, 0x71, 0xe6, 0x0e, 0x20, 0xff, 0x40, 0x83, 0x00, 0x01, 0xe4, 0x68, 0x80, 0x00, 0x04, 0xc3, 0x8f, 0x00, 0xe4, 0x68, 0x83, 0x00, 0x01, 0xac, 0xa0, 0x82, 0x00, 0x02, 0x20, 0xff, 0x3e, 0x83, 0x00, 0x06, 0xe4, 0x68, 0x00, 0x00, 0x04, 0xff, 0x48, 0x80, 0x00, 0x01, 0x74, 0xd8, 0x85, 0x00, 0x08, 0x90, 0xbc, 0x00, 0x00, 0xe4, 0x68, 0x6d, 0xe7, 0x1c, 0x80, 0x00, 0x01, 0x60, 0xec, 0x82, 0x00, 0x12, 0x20, 0xf7, 0x63, 0xb7, 0x3e, 0xca, 0x98, 0x84, 0x00, 0xe4, 0x57, 0xf5, 0x21, 0x00, 0xe4, 0x48, 0x30, 0xff, 0x34, 0x80, 0x00, 0x04, 0xcc, 0x96, 0x00, 0xe4, 0x68, 0x80, 0x00, 0x04, 0xbf, 0x97, 0x2c, 0xff, 0x37, 0x80, 0x00, 0x04, 0xcf, 0x93, 0x00, 0xe4, 0x68, 0x80, 0x00, 0x05, 0xbc, 0x93, 0x00, 0xd2, 0xb0, 0x11, 0x84, 0x00, 0x01, 0x74, 0xd8, 0x80, 0x00, 0x02, 0x08, 0xff, 0x48, 0x80, 0x00, 0x17, 0xe0, 0x6c, 0x00, 0xbb, 0x95, 0x00, 0x00, 0x30, 0xfe, 0x1f, 0x7f, 0xb6, 0x00, 0x75, 0xd5, 0x00, 0x4c, 0xe2, 0x00, 0x00, 0x4c, 0xef, 0xaf, 0xb3, 0x81, 0x00, 0x04, 0xb5, 0x9e, 0x38, 0xf7, 0x23, 0x82, 0x00, 0x02, 0x98, 0xca, 0x04, 0x80, 0x00, 0x02, 0x34, 0xff, 0x08, 0x82, 0x00, 0x02, 0x08, 0xe6, 0x4b, 0x84, 0x00, 0x01, 0xa4, 0x94, 0x80, 0x00, 0x05, 0x03, 0xe0, 0x1e, 0x00, 0xc1, 0x47, 0x8f, 0x00, 0x2a, 0x9d, 0xc2, 0x15, 0x13, 0xbe, 0x9d, 0x00, 0x00, 0xbc, 0xe9, 0x55, 0x12, 0x83, 0xf1, 0x0b, 0x00, 0x78, 0xdb, 0x31, 0x0e, 0x79, 0xf2, 0x16, 0x00, 0x96, 0xcd, 0x16, 0x16, 0xb7, 0xff, 0x20, 0x00, 0x7d, 0xcd, 0x21, 0x07, 0x78, 0xe6, 0x09, 0x00, 0x08, 0x49, 0xf8, 0x80, 0x08, 0x16, 0x02, 0x00, 0x9a, 0xd2, 0x1c, 0x1e, 0xbb, 0xff, 0x2c, 0x00, 0xbc, 0xe6, 0x54, 0x0c, 0x84, 0xed, 0x05, 0x00, 0x02, 0x08, 0x2a, 0xff, 0x18, 0x80, 0x00, 0x04, 0x02, 0x08, 0x08, 0x87, 0xb8, 0x80, 0x00, 0x05, 0x64, 0xd8, 0x00, 0x34, 0xef, 0x3f, 0x81, 0x00, 0x56, 0x34, 0xff, 0x08, 0x00, 0x00, 0x48, 0xfa, 0x37, 0x89, 0xf3, 0x1b, 0xa1, 0x92, 0x00, 0xbc, 0xe7, 0x33, 0x00, 0x69, 0xf0, 0x06, 0x00, 0x82, 0xd9, 0x27, 0x0a, 0x89, 0xec, 0x0e, 0x00, 0xbc, 0xec, 0x32, 0x00, 0x5d, 0xf5, 0x12, 0x00, 0x97, 0xcb, 0x16, 0x16, 0xb6, 0xff, 0x24, 0x00, 0x17, 0xff, 0xb9, 0x7a, 0x1f, 0x24, 0x07, 0x00, 0x65, 0xcc, 0x18, 0x04, 0x5d, 0xdb, 0x02, 0x00, 0x05, 0x8f, 0xae, 0x08, 0x08, 0x05, 0x00, 0x00, 0xbc, 0x80, 0x00, 0x00, 0x10, 0xff, 0x2c, 0x08, 0xf0, 0x62, 0x00, 0x00, 0x0b, 0xf4, 0x5a, 0xa0, 0x92, 0x81, 0x00, 0x18, 0x2d, 0xfc, 0x08, 0x35, 0xf2, 0x25, 0x01, 0xc3, 0x8a, 0x00, 0x05, 0xe8, 0x57, 0x00, 0x00, 0x03, 0xe7, 0x57, 0x00, 0x02, 0x04, 0x04, 0x06, 0xb9, 0xa7, 0x81, 0x00, 0x01, 0x96, 0x9e, 0x83, 0x00, 0x01, 0x60, 0xc4, 0x83, 0x00, 0x02, 0x36, 0xfb, 0x02, 0x87, 0x00, 0x01, 0x04, 0x0a, 0x80, 0x00, 0x01, 0x1f, 0xfe, 0x89, 0x00, 0x01, 0x5c, 0xc3, 0x8a, 0x00, 0x13, 0xbe, 0x08, 0x00, 0x88, 0x3c, 0x00, 0x00, 0x34, 0xd4, 0xfc, 0xeb, 0x89, 0x20, 0x00, 0x41, 0xcb, 0xc8, 0x46, 0xd7, 0x17, 0x80, 0x00, 0x06, 0x38, 0xe9, 0xda, 0x35, 0x00, 0x46, 0x11, 0x87, 0x00, 0x01, 0x8c, 0xb9, 0x85, 0x00, 0x01, 0x55, 0xef, 0x81, 0x00, 0x03, 0x03, 0x08, 0x00, 0x0c, 0x82, 0x00, 0x01, 0x50, 0xb4, 0x9b, 0x00, 0x0c, 0x6a, 0xd0, 0x01, 0x00, 0x00, 0x22, 0xff, 0x1b, 0x9c, 0xff, 0x00, 0xb8, 0x86, 0x81, 0x00, 0x01, 0xec, 0x50, 0x83, 0x00, 0x02, 0x0a, 0xcb, 0x9e, 0x81, 0x00, 0x03, 0xc9, 0xff, 0xca, 0x1b, 0x80, 0x00, 0x15, 0xb5, 0x58, 0x00, 0xd4, 0x68, 0x00, 0x00, 0xc3, 0xc4, 0x43, 0x31, 0xac, 0xe8, 0x0f, 0x00, 0xef, 0xe3, 0x3d, 0x0e, 0x84, 0xf1, 0x15, 0x81, 0x00, 0x01, 0xca, 0x71, 0x80, 0x00, 0x0e, 0x03, 0xb2, 0xff, 0xff, 0xe7, 0x32, 0x00, 0x00, 0xb1, 0xbd, 0x10, 0x08, 0x7f, 0xfa, 0x6b, 0x80, 0x00, 0x01, 0x1a, 0x2c, 0x83, 0x00, 0x01, 0x1a, 0x2c, 0x80, 0x00, 0x04, 0x23, 0xeb, 0xc3, 0x4f, 0x01, 0x8c, 0x00, 0x03, 0x24, 0x96, 0xf3, 0x75, 0x81, 0x00, 0x1e, 0x1a, 0xce, 0xa1, 0x00, 0x98, 0x43, 0xdd, 0x0f, 0x00, 0xbb, 0x3a, 0xb9, 0x19, 0x18, 0xfc, 0x23, 0x00, 0xb5, 0x82, 0x00, 0x00, 0xe4, 0xf6, 0xf0, 0xfb, 0xea, 0x43, 0x00, 0x36, 0xff, 0x28, 0x83, 0x00, 0x01, 0xe4, 0x68, 0x80, 0x00, 0x04, 0xa5, 0xa9, 0x00, 0xe4, 0xf8, 0x80, 0xf4, 0x04, 0xf0, 0x00, 0x00, 0xac, 0xa0, 0x82, 0x00, 0x02, 0x36, 0xff, 0x28, 0x83, 0x00, 0x01, 0xe4, 0xfd, 0x80, 0xfc, 0x01, 0xff, 0x48, 0x80, 0x00, 0x01, 0x74, 0xd8, 0x85, 0x00, 0x07, 0x90, 0xbc, 0x00, 0x00, 0xe4, 0xa3, 0xfa, 0xa4, 0x81, 0x00, 0x01, 0x60, 0xec, 0x82, 0x00, 0x12, 0x20, 0xf8, 0x11, 0xf3, 0x95, 0x73, 0x98, 0x84, 0x00, 0xe4, 0x44, 0x9f, 0x8c, 0x00, 0xe4, 0x48, 0x46, 0xff, 0x1d, 0x80, 0x00, 0x0c, 0xb5, 0xad, 0x00, 0xe4, 0x68, 0x00, 0x05, 0x5e, 0xfd, 0x43, 0x45, 0xff, 0x1f, 0x80, 0x00, 0x10, 0xb8, 0xab, 0x00, 0xe4, 0x68, 0x00, 0x02, 0x4d, 0xfc, 0x43, 0x00, 0x2e, 0xd2, 0xf8, 0xbe, 0x73, 0x12, 0x81, 0x00, 0x01, 0x74, 0xd8, 0x80, 0x00, 0x02, 0x08, 0xff, 0x48, 0x80, 0x00, 0x11, 0xe0, 0x6c, 0x00, 0x62, 0xe6, 0x02, 0x00, 0x83, 0xc6, 0x00, 0x5a, 0xd4, 0x00, 0xbf, 0xeb, 0x29, 0x6a, 0xbe, 0x80, 0x00, 0x02, 0xb4, 0xfc, 0x1f, 0x81, 0x00, 0x03, 0x25, 0xf7, 0xd9, 0x86, 0x82, 0x00, 0x02, 0x4f, 0xf3, 0x25, 0x81, 0x00, 0x02, 0x34, 0xff, 0x08, 0x83, 0x00, 0x01, 0x6c, 0xcc, 0x84, 0x00, 0x01, 0xa4, 0x94, 0x80, 0x00, 0x05, 0x4c, 0xb9, 0x00, 0x00, 0x5d, 0xae, 0x8f, 0x00, 0x21, 0x0d, 0x0f, 0x00, 0x00, 0x6f, 0xd0, 0x00, 0x00, 0xbc, 0xb5, 0x00, 0x00, 0x07, 0xf5, 0x4c, 0x00, 0xe6, 0x62, 0x00, 0x00, 0x02, 0x5e, 0x1a, 0x00, 0xe7, 0x61, 0x00, 0x00, 0x44, 0xff, 0x20, 0x00, 0xe6, 0x50, 0x80, 0x00, 0x05, 0xe8, 0x50, 0x00, 0x00, 0x44, 0xf8, 0x82, 0x00, 0x0e, 0xe2, 0x69, 0x00, 0x00, 0x4e, 0xff, 0x2c, 0x00, 0xbc, 0xa9, 0x00, 0x00, 0x1c, 0xff, 0x22, 0x80, 0x00, 0x02, 0x24, 0xff, 0x18, 0x83, 0x00, 0x01, 0x84, 0xb8, 0x80, 0x00, 0x04, 0x64, 0xd8, 0x1b, 0xe4, 0x5a, 0x82, 0x00, 0x30, 0x34, 0xff, 0x08, 0x00, 0x00, 0x48, 0xf2, 0x00, 0x65, 0xd7, 0x00, 0x7d, 0xaa, 0x00, 0xbc, 0xa1, 0x00, 0x00, 0x19, 0xff, 0x22, 0x00, 0xe9, 0x64, 0x00, 0x00, 0x09, 0xf4, 0x56, 0x00, 0xbc, 0xad, 0x00, 0x00, 0x02, 0xf0, 0x52, 0x00, 0xe8, 0x60, 0x00, 0x00, 0x44, 0xff, 0x24, 0x00, 0x03, 0xfe, 0xa2, 0x82, 0x00, 0x02, 0x84, 0xbe, 0x05, 0x83, 0x00, 0x01, 0x8c, 0xac, 0x82, 0x00, 0x26, 0xbc, 0x80, 0x00, 0x00, 0x10, 0xff, 0x2c, 0x00, 0x9a, 0xbc, 0x00, 0x00, 0x5c, 0xf0, 0x09, 0x78, 0xb7, 0x00, 0x7a, 0xcb, 0x03, 0x55, 0xdb, 0x00, 0x00, 0x7d, 0xc3, 0x6f, 0xd0, 0x06, 0x00, 0x00, 0x85, 0xb9, 0x00, 0x00, 0x4a, 0xeb, 0x06, 0x81, 0x00, 0x02, 0x80, 0xd5, 0x0b, 0x80, 0x00, 0x02, 0x23, 0xe2, 0x65, 0x83, 0x00, 0x01, 0x60, 0xc4, 0x83, 0x00, 0x0c, 0x0e, 0xed, 0x68, 0x01, 0x00, 0x16, 0xa9, 0xde, 0xbd, 0x68, 0x16, 0x1c, 0x54, 0x81, 0x00, 0x02, 0x1a, 0xce, 0xa1, 0x89, 0x00, 0x01, 0x55, 0xbc, 0x89, 0x00, 0x05, 0x03, 0xc1, 0x00, 0x00, 0xb9, 0x0a, 0x81, 0x00, 0x04, 0x52, 0xd5, 0xb4, 0xf3, 0x3e, 0x80, 0x00, 0x0c, 0x9e, 0x6a, 0xa1, 0xca, 0x91, 0x2a, 0xe9, 0x5e, 0xef, 0x21, 0x00, 0xe0, 0x29, 0x87, 0x00, 0x01, 0x9f, 0xa5, 0x85, 0x00, 0x02, 0x42, 0xfe, 0x03, 0x86, 0x00, 0x07, 0x2f, 0xec, 0xec, 0xf2, 0xfa, 0xec, 0xec, 0x8c, 0x87, 0x00, 0x00, 0xb5, 0x80, 0xfc, 0x00, 0x1b, 0x88, 0x00, 0x02, 0x08, 0xe4, 0x50, 0x80, 0x00, 0x07, 0x22, 0xff, 0x1c, 0x7e, 0xd0, 0x00, 0xbe, 0x85, 0x81, 0x00, 0x01, 0xec, 0x50, 0x82, 0x00, 0x03, 0x10, 0xc4, 0xbe, 0x0a, 0x81, 0x00, 0x0b, 0x20, 0x45, 0xaf, 0xd8, 0x0f, 0x00, 0x52, 0xb9, 0x00, 0x00, 0xd4, 0x68, 0x83, 0x00, 0x0a, 0x09, 0xed, 0x5f, 0x00, 0xf4, 0x79, 0x00, 0x00, 0x03, 0xe8, 0x5f, 0x80, 0x00, 0x02, 0x3c, 0xf4, 0x0e, 0x80, 0x00, 0x0e, 0x96, 0xc0, 0x1e, 0x09, 0x6e, 0xea, 0x15, 0x00, 0x1c, 0xc2, 0xfc, 0xf2, 0x88, 0xda, 0x66, 0x8d, 0x00, 0x03, 0x2f, 0xf7, 0x8a, 0x1b, 0x8d, 0x00, 0x03, 0x05, 0x5d, 0xd7, 0x92, 0x80, 0x00, 0x1f, 0x23, 0xe4, 0x87, 0x02, 0x00, 0xaa, 0x3e, 0xe6, 0x00, 0x00, 0xdb, 0x0c, 0xc6, 0x07, 0x6f, 0xcf, 0x00, 0x00, 0x63, 0xd9, 0x00, 0x00, 0xe4, 0x7b, 0x20, 0x2b, 0x66, 0xef, 0x4e, 0x35, 0xff, 0x2f, 0x83, 0x00, 0x01, 0xe4, 0x68, 0x80, 0x00, 0x04, 0xb0, 0xa6, 0x00, 0xe4, 0x7d, 0x80, 0x24, 0x04, 0x23, 0x00, 0x00, 0xac, 0xfe, 0x81, 0xfc, 0x10, 0x3f, 0x35, 0xff, 0x2f, 0x00, 0xbd, 0xfc, 0xfc, 0x85, 0x00, 0xe4, 0x82, 0x2c, 0x2c, 0x2f, 0xff, 0x48, 0x80, 0x00, 0x01, 0x74, 0xd8, 0x85, 0x00, 0x08, 0x90, 0xbc, 0x00, 0x00, 0xe4, 0xfd, 0x94, 0xff, 0x4a, 0x80, 0x00, 0x01, 0x60, 0xec, 0x82, 0x00, 0x12, 0x20, 0xf8, 0x00, 0xb3, 0xf6, 0x1c, 0x98, 0x84, 0x00, 0xe4, 0x44, 0x32, 0xef, 0x0a, 0xe4, 0x48, 0x46, 0xff, 0x1e, 0x80, 0x00, 0x0c, 0xb7, 0xac, 0x00, 0xe4, 0xf8, 0xf4, 0xfc, 0xed, 0x6a, 0x00, 0x47, 0xff, 0x1b, 0x80, 0x00, 0x08, 0xb4, 0xaa, 0x00, 0xe4, 0xf8, 0xf4, 0xfa, 0xe6, 0x67, 0x81, 0x00, 0x04, 0x2f, 0x78, 0xd7, 0xeb, 0x27, 0x80, 0x00, 0x01, 0x74, 0xd8, 0x80, 0x00, 0x02, 0x08, 0xff, 0x48, 0x80, 0x00, 0x17, 0xe0, 0x6c, 0x00, 0x10, 0xf9, 0x3d, 0x00, 0xd6, 0x6d, 0x00, 0x36, 0xf2, 0x07, 0xeb, 0x90, 0x69, 0x88, 0x99, 0x00, 0x00, 0x0e, 0xe4, 0xf6, 0x5a, 0x82, 0x00, 0x02, 0x91, 0xed, 0x0c, 0x81, 0x00, 0x02, 0x19, 0xeb, 0x62, 0x82, 0x00, 0x02, 0x34, 0xff, 0x08, 0x83, 0x00, 0x02, 0x07, 0xe2, 0x50, 0x83, 0x00, 0x01, 0xa4, 0x94, 0x80, 0x00, 0x06, 0xb2, 0x56, 0x00, 0x00, 0x09, 0xeb, 0x19, 0x8e, 0x00, 0x09, 0x29, 0xaf, 0xdd, 0xe0, 0xed, 0xd8, 0x00, 0x00, 0xbc, 0x8c, 0x80, 0x00, 0x04, 0xdb, 0x67, 0x0c, 0xff, 0x3b, 0x82, 0x00, 0x08, 0x05, 0xfe, 0x40, 0x00, 0x00, 0x21, 0xff, 0x20, 0x0a, 0x83, 0xff, 0x04, 0x70, 0x00, 0x00, 0x44, 0xf8, 0x82, 0x00, 0x0e, 0xfd, 0x49, 0x00, 0x00, 0x1e, 0xff, 0x2c, 0x00, 0xbc, 0x83, 0x00, 0x00, 0x10, 0xff, 0x2c, 0x80, 0x00, 0x02, 0x24, 0xff, 0x18, 0x83, 0x00, 0x01, 0x84, 0xb8, 0x80, 0x00, 0x03, 0x64, 0xe0, 0xcd, 0xb9, 0x83, 0x00, 0x17, 0x34, 0xff, 0x08, 0x00, 0x00, 0x48, 0xe1, 0x00, 0x60, 0xc8, 0x00, 0x78, 0xb0, 0x00, 0xbc, 0x81, 0x00, 0x00, 0x10, 0xff, 0x2c, 0x0c, 0xff, 0x3b, 0x80, 0x00, 0x04, 0xd7, 0x79, 0x00, 0xbc, 0x8a, 0x80, 0x00, 0x0d, 0xd8, 0x6e, 0x05, 0xfe, 0x40, 0x00, 0x00, 0x21, 0xff, 0x24, 0x00, 0x00, 0xfc, 0x54, 0x82, 0x00, 0x05, 0x20, 0xda, 0xec, 0xa5, 0x57, 0x05, 0x80, 0x00, 0x01, 0x8c, 0xac, 0x82, 0x00, 0x1c, 0xbc, 0x80, 0x00, 0x00, 0x10, 0xff, 0x2c, 0x00, 0x3b, 0xfd, 0x18, 0x00, 0xb9, 0x98, 0x00, 0x50, 0xdb, 0x00, 0xd7, 0xc1, 0x3c, 0x7d, 0xb1, 0x00, 0x00, 0x03, 0xc8, 0xf8, 0x2b, 0x80, 0x00, 0x05, 0x1e, 0xfa, 0x1d, 0x00, 0xa9, 0x8c, 0x81, 0x00, 0x02, 0x49, 0xf0, 0x27, 0x80, 0x00, 0x02, 0x6e, 0xff, 0x92, 0x84, 0x00, 0x01, 0x60, 0xc4, 0x84, 0x00, 0x0b, 0x39, 0xf1, 0xd1, 0x00, 0x2f, 0x59, 0x22, 0x4e, 0xaa, 0xee, 0xe7, 0x60, 0x80, 0x00, 0x03, 0x23, 0xe4, 0x87, 0x02, 0x89, 0x00, 0x01, 0x46, 0xa2, 0x88, 0x00, 0x07, 0x7d, 0xd1, 0xe8, 0xc8, 0xc8, 0xf2, 0xc8, 0x86, 0x80, 0x00, 0x13, 0x30, 0xb0, 0x00, 0x92, 0xb9, 0x00, 0x00, 0x42, 0xbd, 0x5d, 0xaa, 0x01, 0xc6, 0xae, 0x8f, 0x00, 0x7f, 0xba, 0x2a, 0xe3, 0x88, 0x00, 0x01, 0x9f, 0xa5, 0x85, 0x00, 0x02, 0x42, 0xfe, 0x03, 0x86, 0x00, 0x07, 0x05, 0x1c, 0x1c, 0x63, 0xbc, 0x1c, 0x1c, 0x10, 0x87, 0x00, 0x00, 0x1f, 0x80, 0x2c, 0x00, 0x04, 0x88, 0x00, 0x01, 0x6f, 0xcd, 0x81, 0x00, 0x02, 0x0d, 0xff, 0x30, 0x80, 0x00, 0x01, 0xd3, 0x6f, 0x81, 0x00, 0x01, 0xec, 0x50, 0x81, 0x00, 0x03, 0x1a, 0xd4, 0xab, 0x08, 0x80, 0x00, 0x0d, 0x01, 0x01, 0x00, 0x00, 0x01, 0xde, 0x6b, 0x0c, 0xda, 0x23, 0x00, 0x00, 0xd4, 0x68, 0x84, 0x00, 0x04, 0xcd, 0x7c, 0x00, 0xe1, 0x6c, 0x80, 0x00, 0x01, 0xcc, 0x76, 0x80, 0x00, 0x01, 0x93, 0xaf, 0x80, 0x00, 0x02, 0x07, 0xfc, 0x42, 0x80, 0x00, 0x01, 0xdc, 0x68, 0x80, 0x00, 0x04, 0x0c, 0x07, 0x04, 0xf4, 0x4a, 0x8e, 0x00, 0x07, 0x2c, 0x9e, 0xf2, 0xa2, 0x2e, 0x00, 0x00, 0x31, 0x83, 0xf4, 0x08, 0x90, 0x00, 0x00, 0x0f, 0x75, 0xe3, 0xc9, 0x58, 0x04, 0x80, 0x00, 0x01, 0xab, 0x9b, 0x80, 0x00, 0x12, 0xac, 0x46, 0xd5, 0x00, 0x1a, 0xdc, 0x00, 0xcd, 0x00, 0xc8, 0xfa, 0xf0, 0xf0, 0xf3, 0xff, 0x31, 0x00, 0xe4, 0x68, 0x80, 0x00, 0x04, 0x89, 0xc6, 0x1b, 0xff, 0x48, 0x80, 0x00, 0x04, 0x07, 0x00, 0x00, 0xe4, 0x68, 0x80, 0x00, 0x04, 0xce, 0x88, 0x00, 0xe4, 0x68, 0x83, 0x00, 0x01, 0xac, 0xb0, 0x81, 0x2c, 0x10, 0x0b, 0x1a, 0xff, 0x48, 0x00, 0x21, 0x2c, 0xcb, 0x88, 0x00, 0xe4, 0x68, 0x00, 0x00, 0x04, 0xff, 0x48, 0x80, 0x00, 0x01, 0x74, 0xd8, 0x85, 0x00, 0x0d, 0x90, 0xbb, 0x00, 0x00, 0xe4, 0x86, 0x00, 0x9a, 0xe7, 0x13, 0x00, 0x00, 0x60, 0xec, 0x82, 0x00, 0x12, 0x20, 0xf8, 0x00, 0x4c, 0x99, 0x00, 0x98, 0x84, 0x00, 0xe4, 0x44, 0x00, 0xc5, 0x67, 0xe1, 0x48, 0x2e, 0xff, 0x35, 0x80, 0x00, 0x0c, 0xce, 0x93, 0x00, 0xe4, 0x7d, 0x24, 0x1d, 0x04, 0x00, 0x00, 0x35, 0xff, 0x2f, 0x80, 0x00, 0x07, 0xc7, 0x93, 0x00, 0xe4, 0x7d, 0x24, 0xb8, 0xa9, 0x84, 0x00, 0x02, 0x07, 0xd1, 0x99, 0x80, 0x00, 0x01, 0x74, 0xd8, 0x80, 0x00, 0x02, 0x04, 0xfe, 0x4d, 0x80, 0x00, 0x18, 0xe8, 0x68, 0x00, 0x00, 0xb2, 0x90, 0x29, 0xfd, 0x18, 0x00, 0x11, 0xff, 0x4d, 0xbc, 0x53, 0xa7, 0xa3, 0x74, 0x00, 0x00, 0x92, 0xbf, 0x5a, 0xe8, 0x10, 0x81, 0x00, 0x01, 0x70, 0xd8, 0x81, 0x00, 0x02, 0x01, 0xba, 0xab, 0x83, 0x00, 0x02, 0x34, 0xff, 0x08, 0x84, 0x00, 0x02, 0x68, 0xd0, 0x01, 0x82, 0x00, 0x06, 0xa4, 0x94, 0x00, 0x00, 0x02, 0x7b, 0x07, 0x80, 0x00, 0x01, 0x56, 0x31, 0x8e, 0x00, 0x09, 0xdb, 0xa4, 0x09, 0x00, 0x6a, 0xd8, 0x00, 0x00, 0xbc, 0x88, 0x80, 0x00, 0x04, 0xd9, 0x6c, 0x0c, 0xff, 0x3c, 0x82, 0x00, 0x0a, 0x05, 0xfe, 0x41, 0x00, 0x00, 0x26, 0xff, 0x20, 0x08, 0xfe, 0x41, 0x84, 0x00, 0x01, 0x44, 0xf8, 0x81, 0x00, 0x0f, 0x01, 0xfe, 0x44, 0x00, 0x00, 0x18, 0xff, 0x2c, 0x00, 0xbc, 0x80, 0x00, 0x00, 0x10, 0xff, 0x2c, 0x80, 0x00, 0x02, 0x24, 0xff, 0x18, 0x83, 0x00, 0x01, 0x84, 0xb8, 0x80, 0x00, 0x04, 0x64, 0xfe, 0x95, 0xf6, 0x44, 0x82, 0x00, 0x17, 0x34, 0xff, 0x08, 0x00, 0x00, 0x48, 0xe0, 0x00, 0x60, 0xc8, 0x00, 0x78, 0xb0, 0x00, 0xbc, 0x80, 0x00, 0x00, 0x10, 0xff, 0x2c, 0x0c, 0xff, 0x3b, 0x80, 0x00, 0x04, 0xd8, 0x6f, 0x00, 0xbc, 0x89, 0x80, 0x00, 0x0d, 0xdc, 0x66, 0x05, 0xfe, 0x41, 0x00, 0x00, 0x26, 0xff, 0x24, 0x00, 0x00, 0xfc, 0x3c, 0x83, 0x00, 0x09, 0x04, 0x44, 0x8d, 0xe5, 0xbf, 0x04, 0x00, 0x00, 0x8c, 0xac, 0x82, 0x00, 0x1c, 0xbc, 0x80, 0x00, 0x00, 0x11, 0xff, 0x2c, 0x00, 0x00, 0xdb, 0x70, 0x18, 0xfc, 0x37, 0x00, 0x28, 0xfb, 0x28, 0xcd, 0x68, 0x84, 0xa3, 0x87, 0x00, 0x00, 0x0e, 0xe1, 0xf2, 0x4f, 0x81, 0x00, 0x04, 0xb2, 0x7d, 0x10, 0xf7, 0x28, 0x80, 0x00, 0x02, 0x20, 0xed, 0x53, 0x81, 0x00, 0x03, 0x10, 0x59, 0xf2, 0x3e, 0x83, 0x00, 0x01, 0x60, 0xc4, 0x83, 0x00, 0x03, 0x03, 0xce, 0x9f, 0x25, 0x89, 0x00, 0x01, 0xab, 0x9b, 0x99, 0x00, 0x1d, 0x5d, 0x62, 0x00, 0x22, 0xa1, 0x00, 0x00, 0x54, 0xaf, 0x00, 0x30, 0xb0, 0x00, 0x5e, 0xce, 0x00, 0x08, 0xd2, 0x24, 0x7c, 0x80, 0x00, 0x9d, 0xc8, 0x7d, 0x00, 0x05, 0xc7, 0xde, 0x81, 0x88, 0x00, 0x01, 0x8c, 0xb9, 0x85, 0x00, 0x01, 0x55, 0xef, 0x8a, 0x00, 0x01, 0x50, 0xb4, 0x93, 0x00, 0x01, 0x1a, 0x2c, 0x81, 0x00, 0x02, 0x09, 0xe7, 0x4c, 0x82, 0x00, 0x06, 0xd8, 0x69, 0x00, 0x00, 0x15, 0xfd, 0x38, 0x81, 0x00, 0x01, 0xec, 0x50, 0x80, 0x00, 0x03, 0x12, 0xd8, 0x96, 0x01, 0x80, 0x00, 0x02, 0x07, 0xf1, 0x49, 0x80, 0x00, 0x03, 0xdb, 0x6e, 0x4b, 0xfb, 0x80, 0xec, 0x12, 0xfc, 0xf4, 0xa2, 0x06, 0xa7, 0x31, 0x00, 0x00, 0x09, 0xef, 0x5c, 0x00, 0xac, 0xa5, 0x00, 0x00, 0x05, 0xec, 0x56, 0x80, 0x00, 0x01, 0xdc, 0x67, 0x80, 0x00, 0x02, 0x06, 0xfb, 0x46, 0x80, 0x00, 0x09, 0xe2, 0x65, 0x00, 0x56, 0x3e, 0x00, 0x00, 0x49, 0xfa, 0x11, 0x80, 0x00, 0x01, 0x1a, 0x2c, 0x83, 0x00, 0x02, 0x1c, 0x3c, 0x13, 0x82, 0x00, 0x05, 0x16, 0x81, 0xe9, 0xba, 0x37, 0x06, 0x83, 0x20, 0x05, 0x13, 0x0e, 0x8d, 0xef, 0xad, 0x3b, 0x83, 0x00, 0x01, 0x57, 0x24, 0x80, 0x00, 0x0a, 0x99, 0x4c, 0xe1, 0x0b, 0x84, 0xbf, 0x3d, 0x93, 0x22, 0xff, 0x3e, 0x80, 0x20, 0x04, 0xc4, 0x88, 0x00, 0xe4, 0x68, 0x80, 0x00, 0x04, 0x8a, 0xcb, 0x00, 0xdb, 0x93, 0x80, 0x00, 0x0c, 0x99, 0x93, 0x00, 0xe4, 0x68, 0x00, 0x00, 0x2b, 0xff, 0x44, 0x00, 0xe4, 0x68, 0x83, 0x00, 0x01, 0xac, 0xa0, 0x83, 0x00, 0x01, 0xdb, 0x95, 0x80, 0x00, 0x09, 0xc0, 0x88, 0x00, 0xe4, 0x68, 0x00, 0x00, 0x04, 0xff, 0x48, 0x80, 0x00, 0x01, 0x74, 0xd8, 0x81, 0x00, 0x11, 0x8b, 0x89, 0x00, 0x00, 0xa4, 0xa3, 0x00, 0x00, 0xe4, 0x68, 0x00, 0x0b, 0xda, 0xaa, 0x00, 0x00, 0x60, 0xec, 0x82, 0x00, 0x01, 0x20, 0xf8, 0x81, 0x00, 0x14, 0x98, 0x84, 0x00, 0xe4, 0x44, 0x00, 0x58, 0xd4, 0xd3, 0x48, 0x05, 0xf0, 0x7b, 0x00, 0x00, 0x16, 0xfc, 0x59, 0x00, 0xe4, 0x68, 0x82, 0x00, 0x12, 0x0b, 0xf9, 0x69, 0x00, 0x00, 0x0a, 0xf7, 0x5f, 0x00, 0xe4, 0x68, 0x00, 0x1f, 0xf3, 0x58, 0x00, 0x38, 0xb9, 0x05, 0x80, 0x00, 0x01, 0xa5, 0xa7, 0x80, 0x00, 0x01, 0x74, 0xd8, 0x81, 0x00, 0x0c, 0xe8, 0x6a, 0x00, 0x00, 0x0e, 0xfc, 0x4f, 0x00, 0x00, 0x59, 0xde, 0x73, 0xbc, 0x80, 0x00, 0x0d, 0xec, 0xa0, 0x7d, 0x16, 0xe1, 0xbb, 0x4f, 0x00, 0x34, 0xf8, 0x2a, 0x00, 0xbf, 0x99, 0x81, 0x00, 0x01, 0x70, 0xd8, 0x81, 0x00, 0x02, 0x73, 0xe3, 0x12, 0x83, 0x00, 0x02, 0x34, 0xff, 0x08, 0x84, 0x00, 0x02, 0x05, 0xe0, 0x55, 0x82, 0x00, 0x01, 0xa4, 0x94, 0x97, 0x00, 0x22, 0x15, 0xff, 0x34, 0x00, 0x00, 0x96, 0xd8, 0x00, 0x00, 0xbc, 0xa9, 0x00, 0x00, 0x07, 0xf4, 0x4e, 0x00, 0xe7, 0x65, 0x00, 0x00, 0x02, 0x79, 0x28, 0x00, 0xea, 0x63, 0x00, 0x00, 0x50, 0xff, 0x20, 0x00, 0xe1, 0x72, 0x80, 0x00, 0x00, 0x20, 0x80, 0x00, 0x01, 0x44, 0xf8, 0x82, 0x00, 0x0e, 0xe7, 0x60, 0x00, 0x00, 0x46, 0xff, 0x2c, 0x00, 0xbc, 0x80, 0x00, 0x00, 0x10, 0xff, 0x2c, 0x80, 0x00, 0x02, 0x24, 0xff, 0x18, 0x83, 0x00, 0x01, 0x84, 0xb8, 0x80, 0x00, 0x05, 0x64, 0xd8, 0x00, 0x72, 0xe3, 0x10, 0x81, 0x00, 0x30, 0x34, 0xff, 0x08, 0x00, 0x00, 0x48, 0xe0, 0x00, 0x60, 0xc8, 0x00, 0x78, 0xb0, 0x00, 0xbc, 0x80, 0x00, 0x00, 0x10, 0xff, 0x2c, 0x00, 0xe8, 0x64, 0x00, 0x00, 0x0a, 0xf5, 0x4b, 0x00, 0xbc, 0xac, 0x00, 0x00, 0x06, 0xf5, 0x4b, 0x00, 0xea, 0x63, 0x00, 0x00, 0x51, 0xff, 0x24, 0x00, 0x00, 0xfc, 0x3c, 0x82, 0x00, 0x0a, 0x05, 0x07, 0x00, 0x00, 0x10, 0xf7, 0x35, 0x00, 0x00, 0x8b, 0xac, 0x82, 0x00, 0x1d, 0xb3, 0x88, 0x00, 0x00, 0x2f, 0xff, 0x2c, 0x00, 0x00, 0x7d, 0xc4, 0x6d, 0xd6, 0x00, 0x00, 0x05, 0xfb, 0x8a, 0x82, 0x22, 0xca, 0xc3, 0x5d, 0x00, 0x00, 0xa1, 0xa5, 0x4e, 0xea, 0x17, 0x80, 0x00, 0x03, 0x48, 0xdd, 0x68, 0xc2, 0x80, 0x00, 0x02, 0x08, 0xcd, 0x8b, 0x84, 0x00, 0x01, 0xa2, 0x95, 0x83, 0x00, 0x01, 0x60, 0xc4, 0x83, 0x00, 0x02, 0x2e, 0xfe, 0x0b, 0x8a, 0x00, 0x01, 0x57, 0x24, 0x8b, 0x00, 0x01, 0x38, 0x61, 0x89, 0x00, 0x1f, 0x8d, 0x33, 0x00, 0x53, 0x6f, 0x00, 0x00, 0x22, 0xf5, 0x70, 0x3c, 0xb1, 0x25, 0xca, 0x8c, 0x00, 0x87, 0x78, 0x00, 0x60, 0x9c, 0x00, 0xba, 0x92, 0xdf, 0x31, 0x17, 0x8d, 0xff, 0x93, 0x16, 0x03, 0x86, 0x00, 0x01, 0x60, 0xe5, 0x85, 0x00, 0x01, 0x85, 0xc3, 0x8a, 0x00, 0x01, 0x50, 0xb4, 0x82, 0x00, 0x02, 0x32, 0xff, 0x85, 0x8b, 0x00, 0x01, 0x9c, 0xff, 0x81, 0x00, 0x01, 0x74, 0xc9, 0x83, 0x00, 0x12, 0x6f, 0xe9, 0x41, 0x26, 0xb0, 0xc9, 0x01, 0x00, 0x0b, 0x0c, 0x0c, 0xec, 0x58, 0x0c, 0x08, 0x00, 0xa7, 0xc3, 0x11, 0x80, 0x10, 0x09, 0x06, 0x00, 0xa5, 0xd5, 0x39, 0x20, 0x7f, 0xf8, 0x28, 0x08, 0x81, 0x1c, 0x17, 0xd8, 0x78, 0x13, 0x00, 0xb5, 0xca, 0x2e, 0x23, 0xa4, 0xe5, 0x0e, 0x00, 0x40, 0xf9, 0x5f, 0x1b, 0x91, 0xe5, 0x0a, 0x00, 0x00, 0x0d, 0xff, 0x39, 0x81, 0x00, 0x0d, 0xb3, 0xc0, 0x1a, 0x06, 0x6b, 0xf5, 0x20, 0x00, 0x84, 0xd7, 0x28, 0x2c, 0xd6, 0x94, 0x81, 0x00, 0x01, 0x9c, 0xff, 0x83, 0x00, 0x02, 0x9d, 0xf8, 0x16, 0x84, 0x00, 0x02, 0x08, 0x64, 0x71, 0x85, 0x00, 0x02, 0x2b, 0x90, 0x21, 0x85, 0x00, 0x01, 0x6c, 0x2d, 0x80, 0x00, 0x09, 0x68, 0x7d, 0x61, 0xc6, 0x59, 0x9e, 0xb5, 0x16, 0x7a, 0xd4, 0x81, 0x00, 0x1c, 0x6d, 0xdf, 0x00, 0xe4, 0x78, 0x1c, 0x24, 0x5a, 0xf1, 0x77, 0x00, 0x5f, 0xfb, 0x70, 0x2d, 0x78, 0xf6, 0x31, 0x00, 0xe4, 0x7b, 0x25, 0x54, 0xe1, 0xbb, 0x00, 0x00, 0xe4, 0x7b, 0x81, 0x20, 0x03, 0x15, 0x00, 0xac, 0xa0, 0x83, 0x00, 0x29, 0x60, 0xfc, 0x6f, 0x2b, 0x4e, 0xe3, 0x85, 0x00, 0xe4, 0x68, 0x00, 0x00, 0x04, 0xff, 0x48, 0x00, 0x14, 0x20, 0x85, 0xdd, 0x20, 0x20, 0x00, 0x00, 0x67, 0xf3, 0x4a, 0x44, 0xf0, 0x5c, 0x00, 0x00, 0xe4, 0x68, 0x00, 0x00, 0x36, 0xfb, 0x5b, 0x00, 0x60, 0xee, 0x81, 0x20, 0x02, 0x10, 0x20, 0xf8, 0x81, 0x00, 0x14, 0x98, 0x84, 0x00, 0xe4, 0x44, 0x00, 0x05, 0xe6, 0xf7, 0x48, 0x00, 0x83, 0xf3, 0x58, 0x36, 0xba, 0xdc, 0x07, 0x00, 0xe4, 0x68, 0x83, 0x00, 0x16, 0xa4, 0xd6, 0x14, 0x00, 0x7d, 0xed, 0x0f, 0x00, 0xe4, 0x68, 0x00, 0x00, 0x6d, 0xed, 0x18, 0x14, 0xec, 0xa5, 0x2c, 0x1d, 0x5b, 0xf7, 0x5a, 0x80, 0x00, 0x01, 0x74, 0xd8, 0x81, 0x00, 0x0c, 0x9b, 0xd8, 0x3e, 0x2f, 0xa1, 0xf0, 0x0e, 0x00, 0x00, 0x0b, 0xf5, 0xd9, 0x64, 0x80, 0x00, 0x0e, 0xc7, 0xea, 0x3c, 0x00, 0xd6, 0xe9, 0x2a, 0x03, 0xce, 0x8b, 0x00, 0x00, 0x2b, 0xf9, 0x39, 0x80, 0x00, 0x01, 0x70, 0xd8, 0x80, 0x00, 0x02, 0x30, 0xf9, 0x62, 0x81, 0x20, 0x05, 0x1c, 0x00, 0x00, 0x34, 0xff, 0x08, 0x85, 0x00, 0x02, 0x64, 0xd4, 0x02, 0x81, 0x00, 0x01, 0xa4, 0x94, 0x97, 0x00, 0x2b, 0x05, 0xf4, 0x67, 0x00, 0x4f, 0xce, 0xe9, 0x02, 0x00, 0xbc, 0xeb, 0x3f, 0x07, 0x7a, 0xf1, 0x0e, 0x00, 0x7a, 0xdc, 0x2f, 0x0b, 0x7a, 0xf2, 0x17, 0x00, 0x9c, 0xd1, 0x20, 0x26, 0xbc, 0xff, 0x20, 0x00, 0x76, 0xe6, 0x33, 0x04, 0x62, 0xf5, 0x16, 0x00, 0x00, 0x44, 0xf8, 0x82, 0x00, 0x16, 0xa3, 0xc5, 0x0e, 0x15, 0xb1, 0xff, 0x2c, 0x00, 0xbc, 0x80, 0x00, 0x00, 0x10, 0xff, 0x2c, 0x00, 0x08, 0x08, 0x2a, 0xff, 0x1f, 0x08, 0x05, 0x81, 0x00, 0x01, 0x84, 0xb8, 0x80, 0x00, 0x3a, 0x64, 0xd8, 0x00, 0x02, 0xc2, 0xa5, 0x00, 0x00, 0x08, 0x08, 0x3a, 0xff, 0x0f, 0x08, 0x05, 0x48, 0xe0, 0x00, 0x60, 0xc8, 0x00, 0x78, 0xb0, 0x00, 0xbc, 0x80, 0x00, 0x00, 0x10, 0xff, 0x2c, 0x00, 0x7f, 0xd9, 0x24, 0x0c, 0x8e, 0xdc, 0x04, 0x00, 0xbc, 0xec, 0x44, 0x07, 0x79, 0xf0, 0x0a, 0x00, 0x9b, 0xd1, 0x20, 0x26, 0xbb, 0xff, 0x24, 0x00, 0x00, 0xfc, 0x3c, 0x82, 0x00, 0x1c, 0xaa, 0x99, 0x0c, 0x01, 0x44, 0xf4, 0x13, 0x00, 0x00, 0x75, 0xdd, 0x27, 0x1d, 0x3b, 0x00, 0x00, 0x8c, 0xc7, 0x06, 0x04, 0x9b, 0xff, 0x2c, 0x00, 0x00, 0x20, 0xf9, 0xc5, 0x75, 0x80, 0x00, 0x0d, 0xd8, 0xe2, 0x37, 0x00, 0xd7, 0xe5, 0x33, 0x00, 0x52, 0xe6, 0x12, 0x00, 0xa2, 0xb3, 0x80, 0x00, 0x03, 0x01, 0xdd, 0xe7, 0x5c, 0x80, 0x00, 0x02, 0x9c, 0xc3, 0x08, 0x80, 0x04, 0x00, 0x01, 0x80, 0x00, 0x01, 0x90, 0xa0, 0x83, 0x00, 0x01, 0x60, 0xc4, 0x83, 0x00, 0x01, 0x38, 0xf8, 0x8b, 0x00, 0x01, 0x6c, 0x2d, 0x8b, 0x00, 0x01, 0x7c, 0xd8, 0x89, 0x00, 0x04, 0xb8, 0x07, 0x00, 0x84, 0x3d, 0x80, 0x00, 0x17, 0x41, 0xc8, 0xf5, 0xfe, 0xe5, 0x92, 0x09, 0x2e, 0xcc, 0x04, 0x00, 0x0b, 0xb7, 0xc0, 0xa7, 0x04, 0x8c, 0xe7, 0xee, 0xac, 0x3e, 0xc7, 0xf2, 0x14, 0x86, 0x00, 0x02, 0x1e, 0xfe, 0x2a, 0x84, 0x00, 0x01, 0xc9, 0x82, 0x91, 0x00, 0x02, 0x6d, 0xfb, 0x1c, 0x8b, 0x00, 0x01, 0x9c, 0xff, 0x80, 0x00, 0x02, 0x0c, 0xea, 0x48, 0x83, 0x00, 0x08, 0x01, 0x84, 0xe9, 0xf6, 0xb4, 0x1b, 0x00, 0x00, 0xec, 0x82, 0xff, 0x02, 0xb8, 0x03, 0xfe, 0x82, 0xff, 0x07, 0x68, 0x00, 0x0d, 0x95, 0xe6, 0xf4, 0xcb, 0x48, 0x83, 0x00, 0x09, 0xd4, 0x68, 0x00, 0x00, 0x13, 0xa3, 0xec, 0xf4, 0xb9, 0x28, 0x80, 0x00, 0x04, 0x5d, 0xde, 0xf4, 0xc1, 0x2b, 0x80, 0x00, 0x02, 0x27, 0xff, 0x20, 0x81, 0x00, 0x0d, 0x14, 0x9d, 0xe7, 0xf2, 0xc7, 0x41, 0x00, 0x00, 0x08, 0xa3, 0xf0, 0xee, 0x94, 0x07, 0x81, 0x00, 0x01, 0x9c, 0xff, 0x83, 0x00, 0x01, 0xd9, 0x9f, 0x9b, 0x00, 0x01, 0xf0, 0x64, 0x80, 0x00, 0x02, 0x1b, 0xd6, 0x03, 0x80, 0x00, 0x03, 0x0a, 0x00, 0xd3, 0x81, 0x81, 0x00, 0x1b, 0x1b, 0xfe, 0x38, 0xe4, 0xff, 0xff, 0xf8, 0xd7, 0x75, 0x02, 0x00, 0x00, 0x66, 0xdb, 0xf8, 0xcd, 0x43, 0x00, 0x00, 0xe4, 0xff, 0xfe, 0xe7, 0x92, 0x0c, 0x00, 0x00, 0xe4, 0x82, 0xff, 0x03, 0xac, 0x00, 0xac, 0xa0, 0x84, 0x00, 0x0f, 0x6b, 0xdf, 0xfa, 0xd7, 0x7b, 0x0a, 0x00, 0xe4, 0x68, 0x00, 0x00, 0x04, 0xff, 0x48, 0x00, 0xa0, 0x82, 0xff, 0x0b, 0x00, 0x00, 0x02, 0x90, 0xec, 0xe9, 0x87, 0x02, 0x00, 0x00, 0xe4, 0x68, 0x80, 0x00, 0x03, 0x7e, 0xef, 0x1c, 0x60, 0x82, 0xff, 0x02, 0x84, 0x20, 0xf8, 0x81, 0x00, 0x14, 0x98, 0x84, 0x00, 0xe4, 0x44, 0x00, 0x00, 0x7e, 0xff, 0x48, 0x00, 0x03, 0x89, 0xea, 0xf7, 0xba, 0x24, 0x00, 0x00, 0xe4, 0x68, 0x83, 0x00, 0x15, 0x15, 0xca, 0xf7, 0xe9, 0xea, 0x45, 0x00, 0x00, 0xe4, 0x68, 0x00, 0x00, 0x02, 0xc5, 0xb3, 0x00, 0x2f, 0xb5, 0xec, 0xf5, 0xd2, 0x65, 0x81, 0x00, 0x01, 0x74, 0xd8, 0x81, 0x00, 0x05, 0x12, 0xa1, 0xe8, 0xf1, 0xc2, 0x35, 0x81, 0x00, 0x02, 0xa8, 0xfa, 0x11, 0x80, 0x00, 0x09, 0xa2, 0xf5, 0x06, 0x00, 0x97, 0xfe, 0x08, 0x70, 0xe4, 0x0c, 0x80, 0x00, 0x06, 0x8d, 0xd3, 0x05, 0x00, 0x00, 0x70, 0xd8, 0x80, 0x00, 0x00, 0x80, 0x83, 0xff, 0x05, 0xe4, 0x00, 0x00, 0x34, 0xff, 0x08, 0x85, 0x00, 0x02, 0x04, 0xdc, 0x5a, 0x81, 0x00, 0x01, 0xa4, 0x94, 0x98, 0x00, 0x25, 0x5f, 0xe7, 0xe0, 0x96, 0x1e, 0xe0, 0xd1, 0x00, 0xc1, 0x80, 0xb2, 0xf5, 0xd6, 0x40, 0x00, 0x00, 0x04, 0x8a, 0xe8, 0xf9, 0xc8, 0x39, 0x00, 0x00, 0x14, 0xb5, 0xf4, 0xd7, 0x47, 0xff, 0x25, 0x00, 0x04, 0x89, 0xe9, 0xf5, 0xc8, 0x3e, 0x80, 0x00, 0x01, 0x44, 0xf8, 0x82, 0x00, 0x0f, 0x16, 0xb8, 0xf2, 0xce, 0x43, 0xff, 0x2a, 0x00, 0xbc, 0x80, 0x00, 0x00, 0x10, 0xff, 0x2c, 0x04, 0x83, 0xff, 0x00, 0xb0, 0x81, 0x00, 0x01, 0x84, 0xb8, 0x80, 0x00, 0x07, 0x64, 0xd8, 0x00, 0x00, 0x22, 0xf4, 0x56, 0x14, 0x83, 0xff, 0x2c, 0xa0, 0x48, 0xe0, 0x00, 0x60, 0xc8, 0x00, 0x78, 0xb0, 0x00, 0xbc, 0x80, 0x00, 0x00, 0x10, 0xff, 0x2c, 0x00, 0x06, 0x93, 0xed, 0xf6, 0xbf, 0x2b, 0x00, 0x00, 0xbc, 0x8e, 0xb1, 0xf5, 0xd8, 0x44, 0x00, 0x00, 0x13, 0xb3, 0xf3, 0xd6, 0x4d, 0xff, 0x24, 0x00, 0x00, 0xfc, 0x3c, 0x82, 0x00, 0x05, 0x17, 0xae, 0xed, 0xf3, 0xcc, 0x47, 0x80, 0x00, 0x0d, 0x15, 0xc2, 0xf8, 0xf0, 0xbd, 0x00, 0x00, 0x1a, 0xc1, 0xe8, 0xcf, 0x46, 0xfa, 0x30, 0x80, 0x00, 0x02, 0xbf, 0xfc, 0x18, 0x80, 0x00, 0x0e, 0xb0, 0xea, 0x02, 0x00, 0x94, 0xfe, 0x0a, 0x17, 0xeb, 0x4d, 0x00, 0x00, 0x10, 0xe5, 0x66, 0x80, 0x00, 0x02, 0x78, 0xee, 0x08, 0x80, 0x00, 0x83, 0xff, 0x00, 0x4c, 0x80, 0x00, 0x01, 0x90, 0xa0, 0x83, 0x00, 0x01, 0x60, 0xc4, 0x83, 0x00, 0x01, 0x38, 0xf8, 0x8b, 0x00, 0x01, 0xf0, 0x64, 0xa3, 0x00, 0x01, 0x24, 0x84, 0x9b, 0x00, 0x01, 0xb3, 0x96, 0x83, 0x00, 0x02, 0x34, 0xfa, 0x1d, 0x91, 0x00, 0x01, 0xa8, 0xab, 0xf3, 0x00, 0x02, 0x16, 0xff, 0x30, 0xa1, 0x00, 0x06, 0x84, 0x9b, 0x0d, 0x02, 0x4f, 0xcc, 0x05, 0xff, 0x00, 0x03, 0x01, 0x42, 0xff, 0x42, 0xc9, 0x00, 0x02, 0x34, 0xff, 0x08, 0x8c, 0x00, 0x01, 0xa4, 0x94, 0xcc, 0x00, 0x02, 0x25, 0xff, 0x11, 0x91, 0x00, 0x01, 0x95, 0xa7, 0xa8, 0x00, 0x01, 0xbc, 0x80, 0x87, 0x00, 0x02, 0x18, 0xff, 0x24, 0xb8, 0x00, 0x01, 0x9a, 0x93, 0x8b, 0x00, 0x01, 0x8d, 0xa3, 0x83, 0x00, 0x01, 0x60, 0xc4, 0x83, 0x00, 0x01, 0x3b, 0xf5, 0xd3, 0x00, 0x02, 0x33, 0xf4, 0x23, 0x82, 0x00, 0x01, 0xb7, 0x97, 0x92, 0x00, 0x01, 0xe3, 0x3e, 0xf3, 0x00, 0x01, 0x52, 0xc1, 0xa2, 0x00, 0x05, 0x01, 0x72, 0xcf, 0xd6, 0x9c, 0x1a, 0xff, 0x00, 0x80, 0x00, 0x03, 0xb8, 0xcb, 0x27, 0x12, 0xc7, 0x00, 0x04, 0x34, 0xff, 0x0b, 0x04, 0x02, 0x88, 0x00, 0x03, 0x04, 0x04, 0xa5, 0x94, 0x86, 0x00, 0x00, 0x05, 0x85, 0xb0, 0x00, 0x4a, 0xb5, 0x00, 0x05, 0x54, 0xe8, 0x28, 0x0a, 0x9b, 0xc9, 0x8e, 0x00, 0x05, 0x10, 0x36, 0x1e, 0x4a, 0xef, 0x63, 0xa8, 0x00, 0x01, 0xbc, 0x80, 0x87, 0x00, 0x02, 0x18, 0xff, 0x24, 0xb6, 0x00, 0x03, 0x0c, 0x55, 0xf4, 0x23, 0x8b, 0x00, 0x04, 0x67, 0xd7, 0x15, 0x04, 0x01, 0x80, 0x00, 0x01, 0x60, 0xc4, 0x81, 0x00, 0x03, 0x03, 0x07, 0x82, 0xcd, 0xd4, 0x00, 0x02, 0x89, 0xc1, 0x01, 0x80, 0x00, 0x02, 0x5f, 0xe2, 0x0e, 0x91, 0x00, 0x01, 0x1e, 0xd1, 0xf4, 0x00, 0x01, 0x58, 0x43, 0xff, 0x00, 0xab, 0x00, 0x03, 0x1c, 0xbd, 0xf6, 0xaf, 0xc7, 0x00, 0x00, 0x34, 0x80, 0xff, 0x00, 0x8c, 0x87, 0x00, 0x00, 0x28, 0x80, 0xff, 0x00, 0x94, 0xc8, 0x00, 0x05, 0x03, 0x8d, 0xea, 0xf2, 0xbc, 0x25, 0x8e, 0x00, 0x05, 0x25, 0xdc, 0xf8, 0xe3, 0x83, 0x02, 0xa8, 0x00, 0x01, 0xbc, 0x80, 0x87, 0x00, 0x02, 0x18, 0xff, 0x24, 0xb6, 0x00, 0x02, 0xcf, 0xe4, 0x53, 0x8c, 0x00, 0x04, 0x09, 0xb3, 0xfb, 0xff, 0x40, 0x80, 0x00, 0x01, 0x60, 0xc4, 0x81, 0x00, 0x03, 0xdc, 0xff, 0xdf, 0x3c, 0x90, 0x00, }; static EG_EMBEDDED_IMAGE egemb_font = { 768, 14, EG_EIPIXELMODE_GRAY_ALPHA, EG_EICOMPMODE_RLE, egemb_liberation_mono_regular_14_data, 6544 }; ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/libeg/nanojpeg_xtra.c�����������������������������������������������������������������0000664�0001750�0001750�00000005451�13323141645�017406� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * libeg/nanojpeg_xtra.c * JPEG image handling functions -- rEFInd interface for NanoJPEG * * copyright (c) 2018 by by Roderick W. Smith, and distributed * under the terms of the GNU GPL v3, or (at your option) any * later version. * * See https://keyj.emphy.de/nanojpeg/ for the original NanoJPEG. * */ /* * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "global.h" #include "../refind/screen.h" // nanojpeg.c is weird; it doubles as both a header file and a .c file, // depending on whether _NJ_INCLUDE_HEADER_ONLY is defined.... #define _NJ_INCLUDE_HEADER_ONLY #include "nanojpeg.c" typedef struct _jpeg_color { UINT8 red; UINT8 green; UINT8 blue; } jpeg_color; // Decode JPEG data into something libeg can use. This function is a wrapper around // various NanoJPEG functions. EG_IMAGE * egDecodeJPEG(IN UINT8 *FileData, IN UINTN FileDataLength, IN UINTN IconSize, IN BOOLEAN WantAlpha) { EG_IMAGE *NewImage = NULL; unsigned Width, Height; jpeg_color *JpegData; UINTN i; nj_result_t Result; if (njInit()) { Result = njDecode((VOID *) FileData, FileDataLength); if (Result != NJ_OK) return NULL; Width = njGetWidth(); Height = njGetHeight(); // allocate image structure and buffer NewImage = egCreateImage(Width, Height, WantAlpha); if ((NewImage == NULL) || (NewImage->Width != Width) || (NewImage->Height != Height)) return NULL; JpegData = (jpeg_color *) njGetImage(); // Annoyingly, EFI and NanoJPEG use different ordering of RGB values in // their pixel data representations, so we've got to adjust them.... for (i = 0; i < (NewImage->Height * NewImage->Width); i++) { NewImage->PixelData[i].r = JpegData[i].red; NewImage->PixelData[i].g = JpegData[i].green; NewImage->PixelData[i].b = JpegData[i].blue; // Note: AFAIK, NanoJPEG doesn't support alpha/transparency, so if we're // asked to do this, set it to be fully opaque. if (WantAlpha) NewImage->PixelData[i].a = 255; } FreePool(JpegData); njDone(); } return NewImage; } // EG_IMAGE * egDecodeJPEG() �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/libeg/libeg.h�������������������������������������������������������������������������0000664�0001750�0001750�00000014451�13323147256�015642� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * libeg/libeg.h * EFI graphics library header for users * * Copyright (c) 2006 Christoph Pfisterer * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * * Neither the name of Christoph Pfisterer nor the names of the * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef __LIBEG_LIBEG_H__ #define __LIBEG_LIBEG_H__ #ifndef __MAKEWITH_GNUEFI #include "../include/tiano_includes.h" #endif /* types */ typedef enum ColorTypes { white, black } Colors; /* This should be compatible with EFI_UGA_PIXEL */ typedef struct { UINT8 b, g, r, a; } EG_PIXEL; // Some colors for EG_IMAGE #define COLOR_LIGHTBLUE {255, 175, 100, 0} #define COLOR_RED {0, 0, 200, 0} typedef struct { UINTN Width; UINTN Height; BOOLEAN HasAlpha; EG_PIXEL *PixelData; } EG_IMAGE; #define EG_EIPIXELMODE_GRAY (0) #define EG_EIPIXELMODE_GRAY_ALPHA (1) #define EG_EIPIXELMODE_COLOR (2) #define EG_EIPIXELMODE_COLOR_ALPHA (3) #define EG_EIPIXELMODE_ALPHA (4) #define EG_MAX_EIPIXELMODE EG_EIPIXELMODE_ALPHA #define EG_EICOMPMODE_NONE (0) #define EG_EICOMPMODE_RLE (1) #define EG_EICOMPMODE_EFICOMPRESS (2) #define ICON_EXTENSIONS L"png,icns,jpg,jpeg,bmp" typedef struct { UINTN Width; UINTN Height; UINTN PixelMode; UINTN CompressMode; const UINT8 *Data; UINTN DataLength; } EG_EMBEDDED_IMAGE; /* functions */ VOID egInitScreen(VOID); BOOLEAN egGetResFromMode(UINTN *ModeWidth, UINTN *Height); VOID egGetScreenSize(OUT UINTN *ScreenWidth, OUT UINTN *ScreenHeight); CHAR16 * egScreenDescription(VOID); BOOLEAN egHasGraphicsMode(VOID); BOOLEAN egIsGraphicsModeEnabled(VOID); VOID egSetGraphicsModeEnabled(IN BOOLEAN Enable); // NOTE: Even when egHasGraphicsMode() returns FALSE, you should // call egSetGraphicsModeEnabled(FALSE) to ensure the system // is running in text mode. egHasGraphicsMode() only determines // if libeg can draw to the screen in graphics mode. EG_IMAGE * egCreateImage(IN UINTN Width, IN UINTN Height, IN BOOLEAN HasAlpha); EG_IMAGE * egCreateFilledImage(IN UINTN Width, IN UINTN Height, IN BOOLEAN HasAlpha, IN EG_PIXEL *Color); EG_IMAGE * egCopyImage(IN EG_IMAGE *Image); EG_IMAGE * egCropImage(IN EG_IMAGE *Image, IN UINTN StartX, IN UINTN StartY, IN UINTN Width, IN UINTN Height); EG_IMAGE * egScaleImage(EG_IMAGE *Image, UINTN NewWidth, UINTN NewHeight); VOID egFreeImage(IN EG_IMAGE *Image); EG_IMAGE * egLoadImage(IN EFI_FILE* BaseDir, IN CHAR16 *FileName, IN BOOLEAN WantAlpha); EG_IMAGE * egLoadIcon(IN EFI_FILE* BaseDir, IN CHAR16 *FileName, IN UINTN IconSize); EG_IMAGE * egLoadIconAnyType(IN EFI_FILE *BaseDir, IN CHAR16 *SubdirName, IN CHAR16 *BaseName, IN UINTN IconSize); EG_IMAGE * egFindIcon(IN CHAR16 *BaseName, IN UINTN IconSize); EG_IMAGE * egPrepareEmbeddedImage(IN EG_EMBEDDED_IMAGE *EmbeddedImage, IN BOOLEAN WantAlpha); EG_IMAGE * egEnsureImageSize(IN EG_IMAGE *Image, IN UINTN Width, IN UINTN Height, IN EG_PIXEL *Color); EFI_STATUS egLoadFile(IN EFI_FILE* BaseDir, IN CHAR16 *FileName, OUT UINT8 **FileData, OUT UINTN *FileDataLength); EFI_STATUS egFindESP(OUT EFI_FILE_HANDLE *RootDir); EFI_STATUS egSaveFile(IN EFI_FILE* BaseDir OPTIONAL, IN CHAR16 *FileName, IN UINT8 *FileData, IN UINTN FileDataLength); VOID egFillImage(IN OUT EG_IMAGE *CompImage, IN EG_PIXEL *Color); VOID egFillImageArea(IN OUT EG_IMAGE *CompImage, IN UINTN AreaPosX, IN UINTN AreaPosY, IN UINTN AreaWidth, IN UINTN AreaHeight, IN EG_PIXEL *Color); VOID egComposeImage(IN OUT EG_IMAGE *CompImage, IN EG_IMAGE *TopImage, IN UINTN PosX, IN UINTN PosY); UINTN egGetFontHeight(VOID); UINTN egGetFontCellWidth(VOID); UINTN egComputeTextWidth(IN CHAR16 *Text); VOID egMeasureText(IN CHAR16 *Text, OUT UINTN *Width, OUT UINTN *Height); VOID egRenderText(IN CHAR16 *Text, IN OUT EG_IMAGE *CompImage, IN UINTN PosX, IN UINTN PosY, IN UINT8 BGBrightness); VOID egLoadFont(IN CHAR16 *Filename); VOID egClearScreen(IN EG_PIXEL *Color); VOID egDrawImage(IN EG_IMAGE *Image, IN UINTN ScreenPosX, IN UINTN ScreenPosY); VOID egDrawImageWithTransparency(EG_IMAGE *Image, EG_IMAGE *BadgeImage, UINTN XPos, UINTN YPos, UINTN Width, UINTN Height); VOID egDrawImageArea(IN EG_IMAGE *Image, IN UINTN AreaPosX, IN UINTN AreaPosY, IN UINTN AreaWidth, IN UINTN AreaHeight, IN UINTN ScreenPosX, IN UINTN ScreenPosY); VOID egDisplayMessage(IN CHAR16 *Text, EG_PIXEL *BGColor, UINTN PositionCode); EG_IMAGE * egCopyScreen(VOID); EG_IMAGE * egCopyScreenArea(UINTN XPos, UINTN YPos, UINTN Width, UINTN Height); VOID egScreenShot(VOID); BOOLEAN egSetTextMode(UINT32 RequestedMode); EG_IMAGE * egDecodePNG(IN UINT8 *FileData, IN UINTN FileDataLength, IN UINTN IconSize, IN BOOLEAN WantAlpha); EG_IMAGE * egDecodeJPEG(IN UINT8 *FileData, IN UINTN FileDataLength, IN UINTN IconSize, IN BOOLEAN WantAlpha); #endif /* __LIBEG_LIBEG_H__ */ /* EOF */ �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/libeg/egemb_font_large.h��������������������������������������������������������������0000664�0001750�0001750�00000313734�13137115532�020040� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������static const UINT8 egemb_liberation_mono_regular_28_data[17128] = { 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xea, 0x00, 0x09, 0x17, 0xff, 0xff, 0x88, 0x00, 0x00, 0x06, 0xff, 0xff, 0xbf, 0x99, 0x00, 0x02, 0x31, 0xff, 0x31, 0xac, 0x00, 0x03, 0x0d, 0xff, 0xff, 0xa2, 0x8c, 0x00, 0x04, 0x03, 0x80, 0xff, 0x7f, 0x02, 0x85, 0x00, 0x03, 0x0d, 0xad, 0xff, 0x58, 0x8d, 0x00, 0x02, 0x42, 0xff, 0x2b, 0xd4, 0x00, 0x03, 0x45, 0xff, 0xa5, 0x05, 0xff, 0x00, 0xff, 0x00, 0x8f, 0x00, 0x07, 0x05, 0x37, 0x7d, 0xaa, 0xc4, 0x91, 0x4d, 0x0e, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xba, 0x00, 0x00, 0x34, 0x84, 0xff, 0x00, 0x09, 0x81, 0x00, 0x03, 0x13, 0xd8, 0xff, 0x23, 0x8c, 0x00, 0x00, 0x28, 0x84, 0xff, 0x00, 0x15, 0xa9, 0x00, 0x03, 0x1e, 0x45, 0x45, 0x1a, 0x98, 0x00, 0x02, 0x40, 0xff, 0xdd, 0xa5, 0x00, 0x03, 0x19, 0xff, 0xff, 0x22, 0x97, 0x00, 0x08, 0x2c, 0x6c, 0xa2, 0xca, 0xff, 0xd8, 0xb1, 0x8b, 0x03, 0x91, 0x00, 0x02, 0x40, 0xff, 0xff, 0x90, 0x00, 0x03, 0x4d, 0xff, 0xff, 0x17, 0x8b, 0x00, 0x03, 0x26, 0xff, 0xff, 0x3b, 0x85, 0x00, 0x02, 0x7c, 0xff, 0x69, 0x8b, 0x00, 0x00, 0x2d, 0x83, 0xff, 0x00, 0x07, 0xff, 0x00, 0xf7, 0x00, 0x02, 0x25, 0x7f, 0xca, 0x80, 0xff, 0x00, 0x45, 0x86, 0x00, 0x02, 0x74, 0xff, 0x4b, 0x86, 0x00, 0x00, 0x70, 0x80, 0xff, 0x02, 0xbd, 0x6c, 0x15, 0xcc, 0x00, 0x03, 0x0f, 0xff, 0xff, 0x76, 0x80, 0x00, 0x02, 0xd8, 0xff, 0xa0, 0x99, 0x00, 0x02, 0x31, 0xff, 0x31, 0xac, 0x00, 0x03, 0x05, 0xff, 0xff, 0x8b, 0x8c, 0x00, 0x03, 0x50, 0xff, 0xb5, 0x0e, 0x87, 0x00, 0x03, 0x22, 0xea, 0xff, 0x30, 0x8c, 0x00, 0x02, 0x3c, 0xff, 0x25, 0xd3, 0x00, 0x03, 0x0c, 0xc4, 0xff, 0x32, 0xff, 0x00, 0xff, 0x00, 0x8f, 0x00, 0x09, 0x18, 0x9f, 0xff, 0x9d, 0x67, 0x5c, 0x88, 0xff, 0xb9, 0x26, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xb9, 0x00, 0x03, 0x34, 0xff, 0xff, 0xa5, 0x81, 0xa3, 0x00, 0x08, 0x82, 0x00, 0x03, 0x54, 0xff, 0x8c, 0x01, 0x8b, 0x00, 0x00, 0x23, 0x81, 0xa3, 0x03, 0xb1, 0xff, 0xff, 0x15, 0x88, 0x00, 0x03, 0x07, 0x45, 0x45, 0x3a, 0x9a, 0x00, 0x04, 0x06, 0x61, 0xff, 0xbb, 0x19, 0x97, 0x00, 0x02, 0x40, 0xff, 0xdd, 0xa5, 0x00, 0x03, 0x19, 0xff, 0xff, 0x22, 0x96, 0x00, 0x00, 0x55, 0x85, 0xff, 0x00, 0x04, 0x91, 0x00, 0x02, 0x40, 0xff, 0xff, 0x90, 0x00, 0x03, 0x4d, 0xff, 0xff, 0x17, 0x8b, 0x00, 0x03, 0x26, 0xff, 0xff, 0x3b, 0x85, 0x00, 0x02, 0x7c, 0xff, 0x69, 0x8b, 0x00, 0x00, 0x29, 0x80, 0xb9, 0x03, 0xc7, 0xff, 0xff, 0x07, 0xff, 0x00, 0xf6, 0x00, 0x07, 0x21, 0xea, 0xff, 0xff, 0xad, 0xa3, 0xa3, 0x3c, 0x86, 0x00, 0x02, 0x74, 0xff, 0x4b, 0x86, 0x00, 0x07, 0x5f, 0xa3, 0xa3, 0xb7, 0xff, 0xff, 0xbb, 0x12, 0xbe, 0x00, 0x02, 0xb3, 0xff, 0x74, 0x87, 0x00, 0x03, 0x07, 0xff, 0xff, 0x68, 0x80, 0x00, 0x02, 0xb1, 0xff, 0x8b, 0x87, 0x00, 0x01, 0x9d, 0x5c, 0x81, 0x00, 0x02, 0x36, 0xff, 0x0b, 0x82, 0x00, 0x0a, 0x06, 0x3c, 0x78, 0xb1, 0xdd, 0xff, 0xdd, 0xb3, 0x78, 0x34, 0x01, 0x81, 0x00, 0x05, 0x2e, 0x81, 0xb7, 0xb3, 0x79, 0x22, 0x83, 0x00, 0x02, 0x52, 0xff, 0x3c, 0x83, 0x00, 0x06, 0x2d, 0x76, 0xb7, 0xca, 0x92, 0x51, 0x0d, 0x89, 0x00, 0x02, 0xd4, 0xff, 0x7a, 0x8b, 0x00, 0x03, 0x20, 0xea, 0xff, 0x2f, 0x89, 0x00, 0x03, 0x54, 0xff, 0xb9, 0x0e, 0x87, 0x00, 0x09, 0x03, 0x1b, 0x00, 0x00, 0x36, 0xff, 0x1e, 0x00, 0x01, 0x1a, 0xd0, 0x00, 0x03, 0x5b, 0xff, 0x89, 0x01, 0x83, 0x00, 0x07, 0x05, 0x3c, 0x7a, 0xb3, 0xd4, 0xab, 0x6e, 0x2b, 0x89, 0x00, 0x03, 0x0c, 0xaa, 0xff, 0x5c, 0x87, 0x00, 0x08, 0x07, 0x40, 0x7f, 0xb9, 0xd8, 0xb3, 0x7d, 0x42, 0x08, 0x85, 0x00, 0x08, 0x0e, 0x4c, 0x87, 0xbd, 0xdd, 0xb9, 0x84, 0x4c, 0x10, 0x8a, 0x00, 0x03, 0x22, 0xea, 0xff, 0x89, 0x83, 0x00, 0x00, 0x0a, 0x87, 0xff, 0x00, 0xaa, 0x85, 0x00, 0x07, 0x0a, 0x49, 0x8d, 0xc2, 0xbb, 0x90, 0x54, 0x0f, 0x83, 0x00, 0x00, 0x92, 0x88, 0xff, 0x00, 0x59, 0x83, 0x00, 0x08, 0x11, 0x4e, 0x89, 0xbd, 0xd8, 0xb1, 0x7a, 0x3f, 0x08, 0x85, 0x00, 0x07, 0x09, 0x43, 0x80, 0xb7, 0xd1, 0xa3, 0x64, 0x20, 0xdb, 0x00, 0x08, 0x19, 0x58, 0x92, 0xc2, 0xd4, 0xaa, 0x74, 0x3c, 0x07, 0x84, 0x00, 0x04, 0x19, 0xc7, 0xc2, 0x31, 0x01, 0x80, 0x00, 0x03, 0x22, 0xab, 0xcd, 0x1b, 0x85, 0x00, 0x04, 0x1c, 0xff, 0xff, 0xea, 0x10, 0x85, 0x00, 0x00, 0x80, 0x82, 0xff, 0x04, 0xd1, 0xad, 0x81, 0x50, 0x18, 0x86, 0x00, 0x07, 0x2a, 0x65, 0x9f, 0xca, 0xc2, 0x8c, 0x4b, 0x0c, 0x83, 0x00, 0x00, 0x80, 0x80, 0xff, 0x05, 0xe3, 0xb7, 0x95, 0x62, 0x32, 0x04, 0x84, 0x00, 0x00, 0x80, 0x88, 0xff, 0x00, 0x80, 0x81, 0x00, 0x00, 0x2d, 0x88, 0xff, 0x00, 0x8d, 0x83, 0x00, 0x08, 0x01, 0x2e, 0x6a, 0xa3, 0xcd, 0xbf, 0x8a, 0x4b, 0x0d, 0x83, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x83, 0x00, 0x03, 0x04, 0xff, 0xff, 0x53, 0x81, 0x00, 0x00, 0x1d, 0x88, 0xff, 0x00, 0x02, 0x85, 0x00, 0x00, 0x31, 0x83, 0xff, 0x00, 0x43, 0x82, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x83, 0x00, 0x04, 0x03, 0x7b, 0xff, 0xd8, 0x24, 0x81, 0x00, 0x02, 0x7c, 0xff, 0x98, 0x89, 0x00, 0x00, 0x1d, 0x80, 0xff, 0x00, 0x18, 0x82, 0x00, 0x00, 0x1e, 0x80, 0xff, 0x00, 0x04, 0x80, 0x00, 0x03, 0x80, 0xff, 0xff, 0x43, 0x83, 0x00, 0x02, 0x80, 0xff, 0x53, 0x83, 0x00, 0x07, 0x04, 0x3b, 0x7a, 0xaf, 0xd1, 0xa6, 0x6d, 0x2d, 0x84, 0x00, 0x00, 0x80, 0x82, 0xff, 0x04, 0xea, 0xb9, 0x8c, 0x56, 0x1a, 0x85, 0x00, 0x07, 0x02, 0x37, 0x77, 0xad, 0xd1, 0xa5, 0x69, 0x28, 0x84, 0x00, 0x00, 0x80, 0x83, 0xff, 0x04, 0xc7, 0x9f, 0x6a, 0x30, 0x02, 0x84, 0x00, 0x08, 0x21, 0x5b, 0x90, 0xbf, 0xdd, 0xbd, 0x8b, 0x55, 0x17, 0x82, 0x00, 0x00, 0xc2, 0x8a, 0xff, 0x06, 0x78, 0x00, 0x00, 0x07, 0xff, 0xff, 0x4d, 0x84, 0x00, 0x08, 0x7c, 0xff, 0x8d, 0x00, 0x00, 0x65, 0xff, 0xd8, 0x0a, 0x86, 0x00, 0x06, 0x23, 0xff, 0xff, 0x3f, 0xaf, 0xff, 0x60, 0x88, 0x00, 0x07, 0x98, 0xff, 0x6f, 0x00, 0x58, 0xff, 0xdd, 0x18, 0x84, 0x00, 0x08, 0x31, 0xff, 0xff, 0x35, 0x00, 0x18, 0xd8, 0xff, 0x59, 0x85, 0x00, 0x06, 0x01, 0x84, 0xff, 0xa8, 0x08, 0x00, 0x00, 0x8a, 0xff, 0x00, 0x13, 0x83, 0x00, 0x03, 0x34, 0xff, 0xff, 0x07, 0x87, 0x00, 0x03, 0x0a, 0xbb, 0xff, 0x35, 0x90, 0x00, 0x03, 0x26, 0xff, 0xff, 0x15, 0x88, 0x00, 0x00, 0x3a, 0x80, 0xff, 0x00, 0x16, 0x9b, 0x00, 0x03, 0x37, 0xcd, 0xb3, 0x16, 0x96, 0x00, 0x02, 0x40, 0xff, 0xdd, 0xa5, 0x00, 0x03, 0x19, 0xff, 0xff, 0x22, 0x95, 0x00, 0x09, 0x17, 0xff, 0xff, 0x90, 0x2a, 0x0f, 0x06, 0x06, 0x07, 0x0f, 0x92, 0x00, 0x02, 0x40, 0xff, 0xff, 0x90, 0x00, 0x03, 0x2b, 0x59, 0x59, 0x0e, 0x8b, 0x00, 0x03, 0x16, 0x59, 0x59, 0x22, 0x85, 0x00, 0x02, 0x7c, 0xff, 0x69, 0x8f, 0x00, 0x03, 0x34, 0xff, 0xff, 0x07, 0xff, 0x00, 0x02, 0x37, 0xff, 0x2f, 0xf3, 0x00, 0x03, 0x8f, 0xff, 0x89, 0x0d, 0x8a, 0x00, 0x02, 0x74, 0xff, 0x4b, 0x8a, 0x00, 0x03, 0x19, 0xb9, 0xff, 0x5c, 0x99, 0x00, 0x08, 0x19, 0x58, 0x92, 0xc2, 0xd4, 0xaa, 0x74, 0x3c, 0x07, 0x99, 0x00, 0x02, 0xa8, 0xff, 0x6f, 0x88, 0x00, 0x02, 0xe3, 0xff, 0x5a, 0x80, 0x00, 0x02, 0x98, 0xff, 0x79, 0x86, 0x00, 0x02, 0x10, 0xff, 0x31, 0x81, 0x00, 0x01, 0x62, 0x92, 0x82, 0x00, 0x16, 0x12, 0x9d, 0xff, 0xff, 0xb3, 0xa5, 0xff, 0xab, 0xd1, 0xff, 0xff, 0x78, 0x05, 0x00, 0x00, 0x2a, 0xff, 0xa2, 0x3b, 0x3f, 0xb7, 0xd4, 0x17, 0x81, 0x00, 0x02, 0x24, 0xff, 0x71, 0x83, 0x00, 0x08, 0x51, 0xff, 0xea, 0x7f, 0x68, 0xa2, 0xff, 0xb1, 0x10, 0x88, 0x00, 0x02, 0xad, 0xff, 0x6a, 0x8a, 0x00, 0x03, 0x02, 0x92, 0xff, 0x74, 0x8a, 0x00, 0x03, 0x06, 0xaa, 0xff, 0x67, 0x87, 0x00, 0x0a, 0x28, 0xff, 0x8a, 0x37, 0x38, 0xff, 0x28, 0x45, 0x9f, 0xe3, 0x0c, 0xce, 0x00, 0x03, 0x18, 0xe3, 0xff, 0x21, 0x83, 0x00, 0x01, 0x0e, 0x91, 0x84, 0xff, 0x01, 0x69, 0x04, 0x86, 0x00, 0x04, 0x22, 0x9c, 0xff, 0xff, 0x5c, 0x86, 0x00, 0x01, 0x17, 0xa2, 0x84, 0xff, 0x01, 0xad, 0x1a, 0x83, 0x00, 0x01, 0x2e, 0xca, 0x84, 0xff, 0x01, 0xca, 0x2c, 0x88, 0x00, 0x04, 0x0a, 0xa8, 0xff, 0xff, 0x89, 0x83, 0x00, 0x03, 0x13, 0xff, 0xff, 0xd1, 0x84, 0xcd, 0x00, 0x9d, 0x84, 0x00, 0x01, 0x21, 0xb3, 0x83, 0xff, 0x01, 0xbb, 0x1e, 0x82, 0x00, 0x00, 0x8a, 0x86, 0xcd, 0x02, 0xea, 0xff, 0x58, 0x82, 0x00, 0x0a, 0x35, 0xd1, 0xff, 0xff, 0xa3, 0x92, 0xb5, 0xff, 0xff, 0xab, 0x1c, 0x83, 0x00, 0x01, 0x1f, 0xaf, 0x84, 0xff, 0x00, 0x4d, 0xb1, 0x00, 0x01, 0x04, 0x05, 0x90, 0x00, 0x00, 0x08, 0x8f, 0x00, 0x01, 0x4e, 0xea, 0x84, 0xff, 0x01, 0xad, 0x1d, 0x82, 0x00, 0x03, 0x08, 0x9f, 0xc7, 0x1b, 0x83, 0x00, 0x03, 0x18, 0xca, 0x8c, 0x01, 0x84, 0x00, 0x04, 0x5a, 0xff, 0xdd, 0xff, 0x47, 0x85, 0x00, 0x00, 0x80, 0x87, 0xff, 0x00, 0x4a, 0x83, 0x00, 0x01, 0x07, 0x76, 0x84, 0xff, 0x01, 0xb7, 0x1f, 0x82, 0x00, 0x00, 0x80, 0x85, 0xff, 0x01, 0xaf, 0x29, 0x83, 0x00, 0x00, 0x80, 0x88, 0xff, 0x00, 0x80, 0x81, 0x00, 0x00, 0x2d, 0x88, 0xff, 0x00, 0x8d, 0x82, 0x00, 0x01, 0x09, 0x80, 0x84, 0xff, 0x01, 0xbf, 0x2a, 0x82, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x83, 0x00, 0x03, 0x04, 0xff, 0xff, 0x53, 0x81, 0x00, 0x00, 0x1d, 0x88, 0xff, 0x00, 0x02, 0x85, 0x00, 0x00, 0x31, 0x83, 0xff, 0x00, 0x43, 0x82, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x83, 0x00, 0x03, 0x63, 0xff, 0xea, 0x30, 0x82, 0x00, 0x02, 0x7c, 0xff, 0x98, 0x89, 0x00, 0x00, 0x1d, 0x80, 0xff, 0x00, 0x53, 0x82, 0x00, 0x00, 0x5d, 0x80, 0xff, 0x00, 0x04, 0x80, 0x00, 0x04, 0x80, 0xff, 0xff, 0xaf, 0x05, 0x82, 0x00, 0x02, 0x80, 0xff, 0x53, 0x82, 0x00, 0x01, 0x12, 0x9a, 0x84, 0xff, 0x01, 0x75, 0x06, 0x82, 0x00, 0x00, 0x80, 0x87, 0xff, 0x00, 0x52, 0x83, 0x00, 0x01, 0x0c, 0x8c, 0x84, 0xff, 0x01, 0x66, 0x03, 0x82, 0x00, 0x00, 0x80, 0x87, 0xff, 0x01, 0x87, 0x0b, 0x81, 0x00, 0x01, 0x01, 0x5f, 0x81, 0xff, 0x00, 0xd8, 0x80, 0xff, 0x01, 0xea, 0x3f, 0x81, 0x00, 0x00, 0xc2, 0x8a, 0xff, 0x06, 0x78, 0x00, 0x00, 0x07, 0xff, 0xff, 0x4d, 0x84, 0x00, 0x08, 0x7c, 0xff, 0x8d, 0x00, 0x00, 0x24, 0xff, 0xff, 0x3a, 0x86, 0x00, 0x06, 0x5f, 0xff, 0xd8, 0x0b, 0x7a, 0xff, 0x7f, 0x87, 0x00, 0x09, 0x01, 0xd4, 0xff, 0x4f, 0x00, 0x06, 0x99, 0xff, 0x89, 0x02, 0x82, 0x00, 0x03, 0x0b, 0xb5, 0xff, 0x6e, 0x80, 0x00, 0x03, 0x4b, 0xff, 0xea, 0x1e, 0x84, 0x00, 0x03, 0x3b, 0xff, 0xff, 0x2a, 0x80, 0x00, 0x8a, 0xff, 0x00, 0x12, 0x83, 0x00, 0x03, 0x34, 0xff, 0xff, 0x07, 0x88, 0x00, 0x03, 0x3f, 0xff, 0xab, 0x06, 0x8f, 0x00, 0x03, 0x26, 0xff, 0xff, 0x15, 0x88, 0x00, 0x04, 0x91, 0xea, 0x4e, 0xff, 0x56, 0x9c, 0x00, 0x03, 0x19, 0x99, 0xab, 0x0f, 0x95, 0x00, 0x02, 0x40, 0xff, 0xdd, 0xa5, 0x00, 0x03, 0x19, 0xff, 0xff, 0x22, 0x95, 0x00, 0x03, 0x3a, 0xff, 0xff, 0x17, 0x98, 0x00, 0x02, 0x40, 0xff, 0xff, 0xae, 0x00, 0x02, 0x7c, 0xff, 0x69, 0x8f, 0x00, 0x03, 0x34, 0xff, 0xff, 0x07, 0xff, 0x00, 0x02, 0x68, 0xff, 0x2f, 0xf2, 0x00, 0x03, 0x0a, 0xff, 0xff, 0x31, 0x8b, 0x00, 0x02, 0x74, 0xff, 0x4b, 0x8b, 0x00, 0x02, 0x55, 0xff, 0x98, 0x98, 0x00, 0x01, 0x4e, 0xea, 0x84, 0xff, 0x01, 0xad, 0x1d, 0x98, 0x00, 0x02, 0x9d, 0xff, 0x68, 0x88, 0x00, 0x02, 0xb5, 0xff, 0x4e, 0x80, 0x00, 0x02, 0x84, 0xff, 0x6a, 0x86, 0x00, 0x02, 0x32, 0xff, 0x10, 0x81, 0x00, 0x01, 0xa6, 0x57, 0x82, 0x00, 0x16, 0x7e, 0xff, 0xab, 0x22, 0x00, 0x31, 0xff, 0x31, 0x03, 0x41, 0xff, 0xff, 0x4d, 0x00, 0x00, 0x7e, 0xff, 0x22, 0x00, 0x00, 0x39, 0xff, 0x58, 0x80, 0x00, 0x03, 0x0a, 0xaa, 0xaf, 0x0c, 0x82, 0x00, 0x09, 0x15, 0xff, 0xcd, 0x1f, 0x00, 0x00, 0x03, 0x74, 0xff, 0x54, 0x88, 0x00, 0x02, 0x95, 0xff, 0x5d, 0x8a, 0x00, 0x03, 0x38, 0xff, 0xea, 0x17, 0x8b, 0x00, 0x03, 0x35, 0xff, 0xff, 0x1c, 0x86, 0x00, 0x02, 0x22, 0x6b, 0xbb, 0x82, 0xff, 0x02, 0xa6, 0x5f, 0x13, 0x87, 0x00, 0x02, 0x33, 0x5f, 0x1f, 0xc1, 0x00, 0x02, 0x76, 0xff, 0x6d, 0x83, 0x00, 0x0b, 0x01, 0x80, 0xff, 0xbd, 0x37, 0x0a, 0x01, 0x0f, 0x4b, 0xea, 0xff, 0x4f, 0x82, 0x00, 0x08, 0x06, 0x14, 0x33, 0x74, 0xff, 0xbd, 0xb1, 0xff, 0x5c, 0x85, 0x00, 0x0c, 0x06, 0xa3, 0xff, 0xbf, 0x3f, 0x11, 0x06, 0x15, 0x4a, 0xd8, 0xff, 0xa2, 0x05, 0x81, 0x00, 0x0c, 0x1b, 0xd8, 0xff, 0x92, 0x2e, 0x0e, 0x05, 0x11, 0x3a, 0xb7, 0xff, 0xc7, 0x0d, 0x87, 0x00, 0x04, 0x6e, 0xff, 0xbf, 0xff, 0x89, 0x83, 0x00, 0x03, 0x1b, 0xff, 0xff, 0x16, 0x8b, 0x00, 0x0b, 0x14, 0xc2, 0xff, 0x88, 0x22, 0x04, 0x06, 0x29, 0xa5, 0xff, 0xa5, 0x05, 0x8a, 0x00, 0x03, 0x14, 0xca, 0xe3, 0x1b, 0x81, 0x00, 0x04, 0x1c, 0xea, 0xff, 0x73, 0x12, 0x80, 0x00, 0x04, 0x1e, 0xa0, 0xff, 0xad, 0x07, 0x81, 0x00, 0x0b, 0x0f, 0xbb, 0xff, 0xaf, 0x31, 0x08, 0x02, 0x1a, 0x77, 0xff, 0xff, 0x35, 0xae, 0x00, 0x03, 0x10, 0x4c, 0xb3, 0x17, 0x90, 0x00, 0x03, 0x36, 0x98, 0x3c, 0x08, 0x8b, 0x00, 0x0c, 0x4a, 0xff, 0xff, 0x83, 0x29, 0x0c, 0x0b, 0x1b, 0x4f, 0xc4, 0xff, 0xb5, 0x0b, 0x81, 0x00, 0x02, 0x4b, 0xff, 0x38, 0x85, 0x00, 0x02, 0x4a, 0xff, 0x29, 0x83, 0x00, 0x06, 0x06, 0xbf, 0xff, 0x50, 0xff, 0x9f, 0x01, 0x84, 0x00, 0x02, 0x80, 0xff, 0x91, 0x80, 0x09, 0x06, 0x0c, 0x19, 0x3c, 0xab, 0xff, 0xff, 0x22, 0x81, 0x00, 0x0c, 0x01, 0x7b, 0xff, 0xff, 0x7b, 0x2a, 0x14, 0x18, 0x47, 0xc7, 0xff, 0xbb, 0x17, 0x81, 0x00, 0x0b, 0x80, 0xff, 0x92, 0x0d, 0x0e, 0x16, 0x2a, 0x5b, 0xcd, 0xff, 0xff, 0x34, 0x82, 0x00, 0x02, 0x80, 0xff, 0x92, 0x86, 0x0d, 0x00, 0x0a, 0x81, 0x00, 0x03, 0x2d, 0xff, 0xff, 0x2d, 0x85, 0x0d, 0x00, 0x0b, 0x81, 0x00, 0x0c, 0x02, 0x84, 0xff, 0xff, 0x72, 0x27, 0x13, 0x1b, 0x3f, 0xb1, 0xff, 0xd4, 0x19, 0x81, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x83, 0x00, 0x03, 0x04, 0xff, 0xff, 0x53, 0x81, 0x00, 0x00, 0x03, 0x81, 0x0d, 0x02, 0xb5, 0xff, 0x70, 0x81, 0x0d, 0x86, 0x00, 0x00, 0x05, 0x80, 0x0d, 0x03, 0x19, 0xff, 0xff, 0x43, 0x82, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x82, 0x00, 0x03, 0x4b, 0xff, 0xff, 0x3e, 0x83, 0x00, 0x02, 0x7c, 0xff, 0x98, 0x89, 0x00, 0x05, 0x1d, 0xff, 0xc2, 0xe3, 0xb7, 0x04, 0x80, 0x00, 0x05, 0x06, 0xc4, 0xbd, 0xff, 0xff, 0x04, 0x80, 0x00, 0x00, 0x80, 0x80, 0xff, 0x00, 0x3b, 0x82, 0x00, 0x02, 0x80, 0xff, 0x53, 0x81, 0x00, 0x0b, 0x06, 0xa0, 0xff, 0xff, 0x5a, 0x1e, 0x13, 0x25, 0x76, 0xff, 0xff, 0x70, 0x82, 0x00, 0x02, 0x80, 0xff, 0x91, 0x80, 0x09, 0x06, 0x0b, 0x16, 0x36, 0x96, 0xff, 0xff, 0x44, 0x81, 0x00, 0x0b, 0x03, 0x8c, 0xff, 0xff, 0x60, 0x1f, 0x13, 0x27, 0x7d, 0xff, 0xff, 0x5c, 0x82, 0x00, 0x02, 0x80, 0xff, 0x91, 0x80, 0x09, 0x06, 0x0a, 0x11, 0x27, 0x6f, 0xff, 0xff, 0x71, 0x81, 0x00, 0x0c, 0x41, 0xff, 0xff, 0x69, 0x1a, 0x03, 0x00, 0x06, 0x2f, 0x9f, 0xff, 0xff, 0x20, 0x80, 0x00, 0x00, 0x0c, 0x82, 0x0d, 0x02, 0xad, 0xff, 0x70, 0x82, 0x0d, 0x06, 0x0a, 0x00, 0x00, 0x07, 0xff, 0xff, 0x4d, 0x84, 0x00, 0x08, 0x7c, 0xff, 0x8d, 0x00, 0x00, 0x01, 0xa3, 0xff, 0x84, 0x85, 0x00, 0x07, 0x05, 0xc2, 0xff, 0x6b, 0x00, 0x57, 0xff, 0xab, 0x87, 0x00, 0x09, 0x0e, 0xff, 0xff, 0x34, 0x00, 0x00, 0x1d, 0xe3, 0xff, 0x42, 0x82, 0x00, 0x03, 0x68, 0xff, 0xaf, 0x0b, 0x80, 0x00, 0x04, 0x04, 0x94, 0xff, 0x90, 0x03, 0x82, 0x00, 0x03, 0x0d, 0xbf, 0xff, 0x67, 0x81, 0x00, 0x86, 0x0d, 0x03, 0x24, 0xd4, 0xff, 0x62, 0x84, 0x00, 0x03, 0x34, 0xff, 0xff, 0x07, 0x88, 0x00, 0x03, 0x04, 0x9d, 0xff, 0x4a, 0x8f, 0x00, 0x03, 0x26, 0xff, 0xff, 0x15, 0x87, 0x00, 0x06, 0x20, 0xff, 0x72, 0x06, 0xbf, 0xbf, 0x06, 0xb7, 0x00, 0x02, 0x40, 0xff, 0xdd, 0xa5, 0x00, 0x03, 0x19, 0xff, 0xff, 0x22, 0x95, 0x00, 0x02, 0x48, 0xff, 0xcd, 0x99, 0x00, 0x02, 0x40, 0xff, 0xff, 0xae, 0x00, 0x02, 0x7c, 0xff, 0x69, 0x8f, 0x00, 0x03, 0x34, 0xff, 0xff, 0x07, 0xfe, 0x00, 0x03, 0x01, 0xb7, 0xff, 0x2f, 0xf2, 0x00, 0x03, 0x11, 0xff, 0xff, 0x21, 0x8b, 0x00, 0x02, 0x74, 0xff, 0x4b, 0x8b, 0x00, 0x02, 0x40, 0xff, 0xaf, 0x97, 0x00, 0x0c, 0x4a, 0xff, 0xff, 0x83, 0x29, 0x0c, 0x0b, 0x1b, 0x4f, 0xc4, 0xff, 0xb5, 0x0b, 0x97, 0x00, 0x02, 0x95, 0xff, 0x63, 0x88, 0x00, 0x02, 0x99, 0xff, 0x43, 0x80, 0x00, 0x02, 0x74, 0xff, 0x5c, 0x86, 0x00, 0x01, 0x5d, 0x9f, 0x81, 0x00, 0x02, 0x12, 0xff, 0x2d, 0x81, 0x00, 0x17, 0x0e, 0xff, 0xff, 0x2e, 0x00, 0x00, 0x31, 0xff, 0x31, 0x00, 0x00, 0x55, 0xff, 0xb7, 0x04, 0x00, 0xbf, 0xff, 0x06, 0x00, 0x00, 0x18, 0xff, 0x82, 0x80, 0x00, 0x02, 0x6a, 0xff, 0x28, 0x83, 0x00, 0x02, 0x34, 0xff, 0x68, 0x81, 0x00, 0x02, 0x32, 0xff, 0x70, 0x88, 0x00, 0x02, 0x81, 0xff, 0x50, 0x89, 0x00, 0x03, 0x01, 0x9a, 0xff, 0x6f, 0x8c, 0x00, 0x03, 0x03, 0xaa, 0xff, 0x68, 0x88, 0x00, 0x05, 0x01, 0x20, 0xc7, 0xff, 0x8f, 0x14, 0x8a, 0x00, 0x02, 0x59, 0xff, 0x34, 0xc0, 0x00, 0x03, 0x27, 0xff, 0xdd, 0x14, 0x83, 0x00, 0x03, 0x2d, 0xff, 0xff, 0x25, 0x82, 0x00, 0x03, 0x49, 0xff, 0xe3, 0x0f, 0x81, 0x00, 0x00, 0xcd, 0x80, 0xff, 0x04, 0x89, 0x1a, 0x92, 0xff, 0x5c, 0x85, 0x00, 0x03, 0x3e, 0xff, 0xff, 0x27, 0x82, 0x00, 0x03, 0x3c, 0xff, 0xff, 0x2a, 0x81, 0x00, 0x03, 0x68, 0xff, 0xab, 0x0a, 0x82, 0x00, 0x03, 0x28, 0xff, 0xff, 0x37, 0x86, 0x00, 0x05, 0x3a, 0xff, 0x6f, 0x63, 0xff, 0x89, 0x83, 0x00, 0x03, 0x25, 0xff, 0xff, 0x0c, 0x8b, 0x00, 0x03, 0x73, 0xff, 0x8b, 0x06, 0x81, 0x00, 0x03, 0x17, 0xb5, 0x81, 0x1c, 0x89, 0x00, 0x03, 0x02, 0x82, 0xff, 0x4f, 0x82, 0x00, 0x03, 0x5b, 0xff, 0xbf, 0x06, 0x82, 0x00, 0x03, 0x26, 0xff, 0xff, 0x30, 0x81, 0x00, 0x03, 0x57, 0xff, 0xea, 0x1b, 0x81, 0x00, 0x04, 0x02, 0x78, 0xff, 0xb1, 0x03, 0x85, 0x00, 0x00, 0x1b, 0x80, 0xff, 0x8a, 0x00, 0x00, 0x1b, 0x80, 0xff, 0x8e, 0x00, 0x05, 0x24, 0x6d, 0xe3, 0xff, 0xea, 0x14, 0x90, 0x00, 0x05, 0x31, 0xff, 0xff, 0xc7, 0x59, 0x18, 0x88, 0x00, 0x04, 0x11, 0xdd, 0xff, 0x6c, 0x01, 0x82, 0x00, 0x03, 0x22, 0xff, 0xff, 0x40, 0x80, 0x00, 0x0e, 0x08, 0xc2, 0x94, 0x00, 0x00, 0x13, 0x6e, 0xc4, 0x96, 0x24, 0x22, 0xff, 0x36, 0xea, 0x63, 0x83, 0x00, 0x06, 0x33, 0xff, 0x9d, 0x07, 0xca, 0xff, 0x22, 0x84, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x83, 0x00, 0x03, 0x1c, 0xff, 0xff, 0x50, 0x81, 0x00, 0x04, 0x33, 0xff, 0xff, 0x66, 0x01, 0x81, 0x00, 0x03, 0x17, 0xbd, 0xff, 0x7c, 0x81, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x82, 0x00, 0x04, 0x15, 0xa0, 0xff, 0xd1, 0x13, 0x81, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x8b, 0x00, 0x03, 0x2d, 0xff, 0xff, 0x22, 0x8a, 0x00, 0x03, 0x38, 0xff, 0xff, 0x5b, 0x82, 0x00, 0x03, 0x13, 0xb3, 0xff, 0x75, 0x81, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x83, 0x00, 0x03, 0x04, 0xff, 0xff, 0x53, 0x86, 0x00, 0x02, 0xb1, 0xff, 0x69, 0x8e, 0x00, 0x03, 0x0d, 0xff, 0xff, 0x43, 0x82, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x81, 0x00, 0x03, 0x35, 0xff, 0xff, 0x4e, 0x84, 0x00, 0x02, 0x7c, 0xff, 0x98, 0x89, 0x00, 0x05, 0x1d, 0xff, 0xad, 0x76, 0xff, 0x2e, 0x80, 0x00, 0x05, 0x35, 0xff, 0x65, 0xff, 0xff, 0x04, 0x80, 0x00, 0x05, 0x80, 0xff, 0x7f, 0xff, 0xa2, 0x02, 0x81, 0x00, 0x02, 0x80, 0xff, 0x53, 0x81, 0x00, 0x03, 0x4d, 0xff, 0xff, 0x3f, 0x82, 0x00, 0x03, 0x6a, 0xff, 0xff, 0x2a, 0x81, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x83, 0x00, 0x04, 0x07, 0x95, 0xff, 0xbf, 0x03, 0x80, 0x00, 0x03, 0x3d, 0xff, 0xff, 0x4b, 0x81, 0x00, 0x04, 0x02, 0x77, 0xff, 0xff, 0x1e, 0x81, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x84, 0x00, 0x03, 0x69, 0xff, 0xff, 0x10, 0x80, 0x00, 0x03, 0x99, 0xff, 0x88, 0x01, 0x82, 0x00, 0x03, 0x12, 0xd1, 0xff, 0x6f, 0x86, 0x00, 0x02, 0xaa, 0xff, 0x69, 0x85, 0x00, 0x03, 0x07, 0xff, 0xff, 0x4d, 0x84, 0x00, 0x02, 0x7c, 0xff, 0x8d, 0x80, 0x00, 0x03, 0x49, 0xff, 0xff, 0x14, 0x84, 0x00, 0x08, 0x2f, 0xff, 0xff, 0x28, 0x00, 0x3b, 0xff, 0xff, 0x06, 0x86, 0x00, 0x03, 0x1f, 0xff, 0xff, 0x1d, 0x80, 0x00, 0x03, 0x4a, 0xff, 0xcd, 0x13, 0x80, 0x00, 0x03, 0x2b, 0xff, 0xff, 0x29, 0x82, 0x00, 0x03, 0x1e, 0xea, 0xff, 0x43, 0x82, 0x00, 0x03, 0x69, 0xff, 0xb5, 0x0b, 0x89, 0x00, 0x04, 0x08, 0x98, 0xff, 0x89, 0x05, 0x84, 0x00, 0x03, 0x34, 0xff, 0xff, 0x07, 0x89, 0x00, 0x03, 0x2d, 0xff, 0xca, 0x0e, 0x8e, 0x00, 0x03, 0x26, 0xff, 0xff, 0x15, 0x87, 0x00, 0x06, 0x66, 0xff, 0x29, 0x00, 0x58, 0xff, 0x38, 0xa8, 0x00, 0x07, 0x1a, 0x5c, 0x96, 0xc7, 0xd4, 0xa3, 0x68, 0x21, 0x84, 0x00, 0x0a, 0x40, 0xff, 0xdd, 0x00, 0x12, 0x5a, 0x9f, 0xd1, 0xaa, 0x63, 0x15, 0x85, 0x00, 0x08, 0x03, 0x34, 0x71, 0xaa, 0xd4, 0xb9, 0x7e, 0x3f, 0x06, 0x85, 0x00, 0x0a, 0x22, 0x70, 0xb3, 0xcd, 0x9c, 0x57, 0x0f, 0x19, 0xff, 0xff, 0x22, 0x83, 0x00, 0x08, 0x05, 0x3a, 0x79, 0xb3, 0xd4, 0xaa, 0x73, 0x32, 0x01, 0x82, 0x00, 0x00, 0x0d, 0x89, 0xff, 0x00, 0x5f, 0x83, 0x00, 0x0a, 0x1d, 0x6a, 0xab, 0xcd, 0x98, 0x4b, 0x08, 0x00, 0xdd, 0xff, 0x31, 0x81, 0x00, 0x0a, 0x40, 0xff, 0xdd, 0x00, 0x10, 0x56, 0x99, 0xcd, 0xb1, 0x6c, 0x1d, 0x84, 0x00, 0x00, 0x5f, 0x83, 0xff, 0x00, 0x17, 0x86, 0x00, 0x00, 0x56, 0x84, 0xff, 0x00, 0x3b, 0x85, 0x00, 0x02, 0x7c, 0xff, 0x69, 0x82, 0x00, 0x03, 0x23, 0xd4, 0xff, 0x56, 0x86, 0x00, 0x03, 0x34, 0xff, 0xff, 0x07, 0x84, 0x00, 0x0d, 0x5b, 0xff, 0x38, 0x18, 0x80, 0xc2, 0x7e, 0x11, 0x00, 0x30, 0x98, 0xcd, 0x80, 0x14, 0x81, 0x00, 0x0a, 0x49, 0xff, 0x84, 0x00, 0x0f, 0x53, 0x96, 0xca, 0xb5, 0x71, 0x21, 0x85, 0x00, 0x08, 0x05, 0x3d, 0x7c, 0xb1, 0xd4, 0xad, 0x76, 0x39, 0x04, 0x83, 0x00, 0x0a, 0x49, 0xff, 0x9f, 0x00, 0x13, 0x5e, 0xa3, 0xd1, 0xa8, 0x62, 0x16, 0x85, 0x00, 0x0a, 0x22, 0x71, 0xb3, 0xca, 0x9a, 0x56, 0x0e, 0x0d, 0xff, 0xff, 0x2a, 0x82, 0x00, 0x0b, 0x52, 0xff, 0x7b, 0x00, 0x00, 0x16, 0x67, 0xb1, 0xea, 0xff, 0xff, 0x24, 0x83, 0x00, 0x08, 0x09, 0x47, 0x83, 0xb9, 0xd4, 0xa6, 0x7c, 0x3a, 0x08, 0x83, 0x00, 0x00, 0x36, 0x87, 0xff, 0x00, 0x22, 0x82, 0x00, 0x02, 0x40, 0xff, 0xdd, 0x83, 0x00, 0x03, 0x0f, 0xff, 0xff, 0x2d, 0x80, 0x00, 0x03, 0x98, 0xff, 0x9f, 0x01, 0x84, 0x00, 0x07, 0x0d, 0xe3, 0xff, 0x5f, 0x00, 0x5f, 0xff, 0x83, 0x87, 0x00, 0x08, 0x01, 0xc7, 0xff, 0x39, 0x00, 0x12, 0xbf, 0xff, 0x58, 0x83, 0x00, 0x09, 0x06, 0x9c, 0xff, 0x7f, 0x02, 0x00, 0x01, 0x9a, 0xff, 0x74, 0x85, 0x00, 0x03, 0x02, 0xa6, 0xff, 0x65, 0x80, 0x00, 0x00, 0x3b, 0x88, 0xff, 0x00, 0x0b, 0x85, 0x00, 0x03, 0x11, 0xff, 0xff, 0x1f, 0x8b, 0x00, 0x02, 0x74, 0xff, 0x4b, 0x8b, 0x00, 0x02, 0x3d, 0xff, 0xb1, 0x96, 0x00, 0x04, 0x11, 0xdd, 0xff, 0x6c, 0x01, 0x82, 0x00, 0x03, 0x22, 0xff, 0xff, 0x40, 0x97, 0x00, 0x02, 0x8c, 0xff, 0x5e, 0x88, 0x00, 0x02, 0x85, 0xff, 0x38, 0x80, 0x00, 0x02, 0x66, 0xff, 0x50, 0x82, 0x00, 0x00, 0x09, 0x80, 0x11, 0x01, 0x9f, 0x6c, 0x81, 0x11, 0x23, 0x3f, 0xff, 0x1e, 0x11, 0x0f, 0x00, 0x00, 0x17, 0xff, 0xff, 0x13, 0x00, 0x00, 0x31, 0xff, 0x31, 0x00, 0x00, 0x15, 0x69, 0x45, 0x0a, 0x00, 0xd4, 0xff, 0x03, 0x00, 0x00, 0x15, 0xff, 0x8b, 0x00, 0x00, 0x35, 0xff, 0x57, 0x84, 0x00, 0x02, 0x34, 0xff, 0x5b, 0x81, 0x00, 0x02, 0x55, 0xff, 0x4f, 0x88, 0x00, 0x02, 0x71, 0xff, 0x45, 0x89, 0x00, 0x03, 0x23, 0xff, 0xff, 0x27, 0x8d, 0x00, 0x03, 0x49, 0xff, 0xdd, 0x0a, 0x88, 0x00, 0x04, 0x5b, 0xff, 0x68, 0xff, 0x2e, 0x8a, 0x00, 0x02, 0x59, 0xff, 0x34, 0xbf, 0x00, 0x03, 0x02, 0x92, 0xff, 0x55, 0x84, 0x00, 0x02, 0x72, 0xff, 0x81, 0x83, 0x00, 0x03, 0x06, 0xcd, 0xff, 0x44, 0x81, 0x00, 0x08, 0xb5, 0x95, 0x5c, 0x28, 0x01, 0x00, 0x92, 0xff, 0x5c, 0x85, 0x00, 0x02, 0x69, 0xea, 0x99, 0x83, 0x00, 0x03, 0x08, 0xff, 0xff, 0x42, 0x81, 0x00, 0x02, 0x32, 0x45, 0x2e, 0x83, 0x00, 0x03, 0x09, 0xff, 0xff, 0x3e, 0x85, 0x00, 0x06, 0x17, 0xcd, 0xa6, 0x0a, 0x63, 0xff, 0x89, 0x83, 0x00, 0x03, 0x2e, 0xff, 0xff, 0x03, 0x8a, 0x00, 0x03, 0x13, 0xff, 0xff, 0x20, 0x92, 0x00, 0x03, 0x43, 0xff, 0x98, 0x05, 0x82, 0x00, 0x02, 0x68, 0xff, 0x8c, 0x83, 0x00, 0x03, 0x0e, 0xff, 0xff, 0x3a, 0x81, 0x00, 0x02, 0xaa, 0xff, 0x68, 0x83, 0x00, 0x03, 0x1a, 0xff, 0xff, 0x29, 0x85, 0x00, 0x00, 0x1b, 0x80, 0xff, 0x8a, 0x00, 0x00, 0x1b, 0x80, 0xff, 0x8b, 0x00, 0x07, 0x08, 0x3d, 0x98, 0xff, 0xff, 0xb9, 0x50, 0x11, 0x80, 0x00, 0x00, 0x36, 0x8a, 0xff, 0x00, 0x17, 0x80, 0x00, 0x07, 0x1d, 0x63, 0xd4, 0xff, 0xff, 0x7e, 0x2e, 0x03, 0x85, 0x00, 0x03, 0x43, 0xff, 0xd4, 0x0a, 0x84, 0x00, 0x02, 0x9d, 0xff, 0x5e, 0x80, 0x00, 0x0e, 0x32, 0xff, 0x38, 0x00, 0x11, 0xb7, 0xab, 0x3f, 0x5d, 0xb9, 0x48, 0xff, 0x0e, 0x81, 0xaa, 0x83, 0x00, 0x06, 0x7e, 0xff, 0x4d, 0x00, 0x65, 0xff, 0x61, 0x84, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x83, 0x00, 0x03, 0x06, 0xff, 0xff, 0x4d, 0x81, 0x00, 0x03, 0x83, 0xff, 0xc7, 0x0b, 0x83, 0x00, 0x03, 0x37, 0xcd, 0x68, 0x08, 0x80, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x83, 0x00, 0x03, 0x1c, 0xff, 0xff, 0x5b, 0x81, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x8b, 0x00, 0x03, 0x2d, 0xff, 0xff, 0x22, 0x8a, 0x00, 0x03, 0x8b, 0xff, 0xbd, 0x07, 0x83, 0x00, 0x02, 0x30, 0x55, 0x27, 0x81, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x83, 0x00, 0x03, 0x04, 0xff, 0xff, 0x53, 0x86, 0x00, 0x02, 0xb1, 0xff, 0x69, 0x8e, 0x00, 0x03, 0x0d, 0xff, 0xff, 0x43, 0x82, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x80, 0x00, 0x03, 0x24, 0xdd, 0xff, 0x60, 0x85, 0x00, 0x02, 0x7c, 0xff, 0x98, 0x89, 0x00, 0x05, 0x1d, 0xff, 0xb3, 0x35, 0xff, 0x76, 0x80, 0x00, 0x05, 0x83, 0xff, 0x31, 0xff, 0xff, 0x04, 0x80, 0x00, 0x05, 0x80, 0xff, 0x43, 0xa6, 0xff, 0x33, 0x81, 0x00, 0x02, 0x80, 0xff, 0x53, 0x80, 0x00, 0x04, 0x03, 0xb1, 0xff, 0x96, 0x01, 0x82, 0x00, 0x03, 0x0f, 0xd8, 0xff, 0x74, 0x81, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x84, 0x00, 0x03, 0x3c, 0xff, 0xff, 0x1b, 0x80, 0x00, 0x03, 0x98, 0xff, 0xaa, 0x03, 0x82, 0x00, 0x03, 0x15, 0xff, 0xff, 0x62, 0x81, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x84, 0x00, 0x03, 0x2d, 0xff, 0xff, 0x25, 0x80, 0x00, 0x02, 0xd8, 0xff, 0x53, 0x84, 0x00, 0x02, 0x42, 0x49, 0x2a, 0x86, 0x00, 0x02, 0xaa, 0xff, 0x69, 0x85, 0x00, 0x03, 0x07, 0xff, 0xff, 0x4d, 0x84, 0x00, 0x02, 0x7c, 0xff, 0x8d, 0x80, 0x00, 0x03, 0x11, 0xea, 0xff, 0x49, 0x84, 0x00, 0x08, 0x70, 0xff, 0xaa, 0x02, 0x00, 0x23, 0xff, 0xff, 0x16, 0x86, 0x00, 0x03, 0x31, 0xff, 0xff, 0x09, 0x80, 0x00, 0x09, 0x03, 0x89, 0xff, 0x7c, 0x01, 0x00, 0x09, 0xab, 0xff, 0x5d, 0x84, 0x00, 0x03, 0x55, 0xff, 0xca, 0x12, 0x80, 0x00, 0x03, 0x28, 0xff, 0xff, 0x32, 0x89, 0x00, 0x04, 0x01, 0x70, 0xff, 0xb3, 0x10, 0x85, 0x00, 0x03, 0x34, 0xff, 0xff, 0x07, 0x8a, 0x00, 0x02, 0x81, 0xff, 0x61, 0x8e, 0x00, 0x03, 0x26, 0xff, 0xff, 0x15, 0x86, 0x00, 0x07, 0x0c, 0xd8, 0xa6, 0x02, 0x00, 0x18, 0xff, 0x90, 0xa7, 0x00, 0x05, 0x39, 0xea, 0xff, 0xea, 0xaf, 0xab, 0x80, 0xff, 0x00, 0x42, 0x83, 0x00, 0x0b, 0x40, 0xff, 0xd4, 0x1c, 0xbb, 0xff, 0xb1, 0xc2, 0xff, 0xff, 0xcd, 0x21, 0x83, 0x00, 0x05, 0x0f, 0x8c, 0xff, 0xff, 0xea, 0xbd, 0x80, 0xff, 0x01, 0xa3, 0x17, 0x83, 0x00, 0x0b, 0x37, 0xff, 0xff, 0xe3, 0x95, 0x98, 0xea, 0xb3, 0x2d, 0xff, 0xff, 0x22, 0x82, 0x00, 0x0a, 0x11, 0x92, 0xff, 0xff, 0xbd, 0x94, 0xc4, 0xff, 0xff, 0x80, 0x08, 0x81, 0x00, 0x00, 0x0c, 0x80, 0xb9, 0x02, 0xcd, 0xff, 0xff, 0x83, 0xb9, 0x00, 0x57, 0x82, 0x00, 0x0b, 0x31, 0xe3, 0xff, 0xff, 0xa0, 0xa0, 0xff, 0x95, 0x14, 0xff, 0xff, 0x2d, 0x81, 0x00, 0x0b, 0x40, 0xff, 0xbf, 0x18, 0xb3, 0xff, 0xb5, 0xd1, 0xff, 0xff, 0xd8, 0x25, 0x83, 0x00, 0x00, 0x57, 0x80, 0xb9, 0x03, 0xc2, 0xff, 0xff, 0x17, 0x86, 0x00, 0x00, 0x4f, 0x82, 0xb9, 0x02, 0xff, 0xff, 0x3b, 0x85, 0x00, 0x02, 0x7c, 0xff, 0x69, 0x81, 0x00, 0x04, 0x19, 0xbf, 0xff, 0x62, 0x01, 0x86, 0x00, 0x03, 0x34, 0xff, 0xff, 0x07, 0x84, 0x00, 0x0d, 0x55, 0xff, 0x46, 0xa6, 0xbf, 0xff, 0xff, 0x72, 0x22, 0xea, 0xbb, 0xff, 0xff, 0x84, 0x81, 0x00, 0x0b, 0x44, 0xff, 0x90, 0x18, 0xaf, 0xff, 0xb5, 0xd1, 0xff, 0xff, 0xe3, 0x2a, 0x83, 0x00, 0x0a, 0x14, 0x9d, 0xff, 0xff, 0xad, 0x8f, 0xb7, 0xff, 0xff, 0x90, 0x0e, 0x82, 0x00, 0x0b, 0x43, 0xff, 0xb5, 0x18, 0xb9, 0xff, 0xb1, 0xc2, 0xff, 0xff, 0xcd, 0x21, 0x83, 0x00, 0x0b, 0x37, 0xff, 0xff, 0xe3, 0x95, 0x99, 0xea, 0xab, 0x28, 0xff, 0xff, 0x25, 0x82, 0x00, 0x05, 0x31, 0xff, 0xca, 0x02, 0x22, 0xd4, 0x82, 0xff, 0x00, 0x24, 0x82, 0x00, 0x0a, 0x14, 0xaa, 0xff, 0xff, 0xaf, 0x94, 0xab, 0xff, 0xff, 0xa5, 0x12, 0x82, 0x00, 0x05, 0x32, 0xb9, 0xbb, 0xff, 0xff, 0xc4, 0x82, 0xb9, 0x00, 0x1f, 0x82, 0x00, 0x02, 0x40, 0xff, 0xdd, 0x83, 0x00, 0x03, 0x0f, 0xff, 0xff, 0x2d, 0x80, 0x00, 0x03, 0x40, 0xff, 0xff, 0x22, 0x84, 0x00, 0x07, 0x43, 0xff, 0xff, 0x1d, 0x00, 0x40, 0xff, 0xbb, 0x87, 0x00, 0x09, 0x11, 0xff, 0xff, 0x20, 0x00, 0x00, 0x2e, 0xff, 0xff, 0x27, 0x82, 0x00, 0x03, 0x5b, 0xff, 0xb5, 0x0e, 0x80, 0x00, 0x03, 0x3d, 0xff, 0xea, 0x12, 0x84, 0x00, 0x03, 0x28, 0xff, 0xff, 0x20, 0x80, 0x00, 0x00, 0x33, 0x85, 0xa3, 0x03, 0xcd, 0xff, 0xff, 0x0a, 0x85, 0x00, 0x03, 0x11, 0xff, 0xff, 0x1f, 0x8b, 0x00, 0x02, 0x74, 0xff, 0x4b, 0x8b, 0x00, 0x02, 0x3d, 0xff, 0xb1, 0x96, 0x00, 0x03, 0x43, 0xff, 0xd4, 0x0a, 0x84, 0x00, 0x02, 0x9d, 0xff, 0x5e, 0x97, 0x00, 0x02, 0x85, 0xff, 0x59, 0x88, 0x00, 0x02, 0x74, 0xff, 0x2e, 0x80, 0x00, 0x02, 0x59, 0xff, 0x45, 0x82, 0x00, 0x00, 0x50, 0x8a, 0xff, 0x0b, 0xaa, 0x00, 0x00, 0x08, 0xff, 0xff, 0x30, 0x00, 0x00, 0x31, 0xff, 0x31, 0x84, 0x00, 0x0c, 0x9d, 0xff, 0x15, 0x00, 0x00, 0x2a, 0xff, 0x6f, 0x00, 0x13, 0xc4, 0x94, 0x05, 0x84, 0x00, 0x09, 0x1d, 0xff, 0x8a, 0x00, 0x00, 0x06, 0x4d, 0xff, 0xa3, 0x0c, 0x88, 0x00, 0x02, 0x63, 0xff, 0x3a, 0x89, 0x00, 0x03, 0x58, 0xff, 0xbf, 0x03, 0x8d, 0x00, 0x03, 0x18, 0xff, 0xff, 0x34, 0x87, 0x00, 0x06, 0x32, 0xff, 0x5f, 0x03, 0x98, 0xbf, 0x12, 0x89, 0x00, 0x02, 0x59, 0xff, 0x34, 0xbf, 0x00, 0x03, 0x39, 0xff, 0xbb, 0x0a, 0x83, 0x00, 0x03, 0x01, 0xc2, 0xff, 0x45, 0x84, 0x00, 0x02, 0x77, 0xff, 0x73, 0x87, 0x00, 0x02, 0x92, 0xff, 0x5c, 0x86, 0x00, 0x01, 0x02, 0x08, 0x83, 0x00, 0x03, 0x0b, 0xff, 0xff, 0x3a, 0x8a, 0x00, 0x03, 0x35, 0xff, 0xea, 0x17, 0x84, 0x00, 0x07, 0x05, 0x90, 0xe3, 0x21, 0x00, 0x63, 0xff, 0x89, 0x83, 0x00, 0x02, 0x39, 0xff, 0xc2, 0x8b, 0x00, 0x02, 0x42, 0xff, 0xa0, 0x92, 0x00, 0x03, 0x17, 0xd4, 0xff, 0x20, 0x83, 0x00, 0x03, 0x40, 0xff, 0xc7, 0x0b, 0x82, 0x00, 0x03, 0x24, 0xff, 0xff, 0x1a, 0x80, 0x00, 0x03, 0x04, 0xff, 0xff, 0x41, 0x84, 0x00, 0x02, 0xb3, 0xff, 0x4f, 0x85, 0x00, 0x00, 0x1b, 0x80, 0xff, 0x8a, 0x00, 0x00, 0x1b, 0x80, 0xff, 0x89, 0x00, 0x07, 0x18, 0x5a, 0xc7, 0xff, 0xff, 0x8f, 0x37, 0x05, 0x82, 0x00, 0x00, 0x36, 0x8a, 0xff, 0x00, 0x17, 0x82, 0x00, 0x07, 0x0c, 0x47, 0xaa, 0xff, 0xff, 0xab, 0x49, 0x0e, 0x83, 0x00, 0x02, 0x2b, 0x45, 0x38, 0x85, 0x00, 0x02, 0xa0, 0xff, 0x58, 0x80, 0x00, 0x0f, 0x6b, 0xff, 0x0c, 0x00, 0x82, 0xc7, 0x14, 0x00, 0x00, 0x74, 0xbf, 0xad, 0x00, 0x55, 0xff, 0x0a, 0x81, 0x00, 0x08, 0x14, 0xff, 0xff, 0x1a, 0x00, 0x2a, 0xff, 0xca, 0x07, 0x83, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x83, 0x00, 0x03, 0x25, 0xff, 0xff, 0x25, 0x80, 0x00, 0x03, 0x0a, 0xff, 0xff, 0x68, 0x84, 0x00, 0x01, 0x03, 0x07, 0x82, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x84, 0x00, 0x03, 0x79, 0xff, 0xb9, 0x01, 0x80, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x8b, 0x00, 0x03, 0x2d, 0xff, 0xff, 0x22, 0x89, 0x00, 0x03, 0x0c, 0xff, 0xff, 0x64, 0x8b, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x83, 0x00, 0x03, 0x04, 0xff, 0xff, 0x53, 0x86, 0x00, 0x02, 0xb1, 0xff, 0x69, 0x8e, 0x00, 0x03, 0x0d, 0xff, 0xff, 0x43, 0x82, 0x00, 0x09, 0x80, 0xff, 0x8d, 0x00, 0x00, 0x18, 0xbf, 0xff, 0x71, 0x02, 0x85, 0x00, 0x02, 0x7c, 0xff, 0x98, 0x89, 0x00, 0x0e, 0x1d, 0xff, 0xb9, 0x0a, 0xdd, 0xea, 0x10, 0x00, 0x16, 0xff, 0x99, 0x17, 0xff, 0xff, 0x04, 0x80, 0x00, 0x06, 0x80, 0xff, 0x47, 0x3e, 0xff, 0x95, 0x01, 0x80, 0x00, 0x02, 0x80, 0xff, 0x53, 0x80, 0x00, 0x03, 0x1d, 0xff, 0xff, 0x4a, 0x84, 0x00, 0x03, 0x79, 0xff, 0xdd, 0x04, 0x80, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x84, 0x00, 0x09, 0x2e, 0xff, 0xff, 0x22, 0x00, 0x00, 0x16, 0xff, 0xff, 0x55, 0x84, 0x00, 0x03, 0x8a, 0xff, 0xbf, 0x01, 0x80, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x84, 0x00, 0x03, 0x37, 0xff, 0xff, 0x21, 0x80, 0x00, 0x02, 0xa0, 0xff, 0x6a, 0x90, 0x00, 0x02, 0xaa, 0xff, 0x69, 0x85, 0x00, 0x03, 0x07, 0xff, 0xff, 0x4d, 0x84, 0x00, 0x02, 0x7c, 0xff, 0x8d, 0x81, 0x00, 0x02, 0x78, 0xff, 0x9f, 0x83, 0x00, 0x09, 0x0b, 0xdd, 0xff, 0x4d, 0x00, 0x00, 0x0e, 0xff, 0xff, 0x29, 0x80, 0x00, 0x02, 0x2e, 0x38, 0x24, 0x80, 0x00, 0x02, 0x45, 0xff, 0xad, 0x82, 0x00, 0x08, 0x15, 0xcd, 0xff, 0x39, 0x00, 0x5f, 0xff, 0x9f, 0x06, 0x84, 0x00, 0x09, 0x06, 0xa0, 0xff, 0x74, 0x00, 0x00, 0x06, 0xa2, 0xff, 0x72, 0x8a, 0x00, 0x03, 0x4b, 0xff, 0xdd, 0x22, 0x86, 0x00, 0x03, 0x34, 0xff, 0xff, 0x07, 0x8a, 0x00, 0x03, 0x1d, 0xff, 0xea, 0x1b, 0x8d, 0x00, 0x03, 0x26, 0xff, 0xff, 0x15, 0x86, 0x00, 0x02, 0x45, 0xff, 0x47, 0x80, 0x00, 0x02, 0x81, 0xff, 0x20, 0xa5, 0x00, 0x0b, 0x0f, 0xd8, 0xff, 0x7b, 0x0f, 0x00, 0x00, 0x0e, 0x72, 0xff, 0xea, 0x15, 0x82, 0x00, 0x0c, 0x40, 0xff, 0xca, 0x95, 0x6a, 0x0f, 0x00, 0x00, 0x26, 0xb7, 0xff, 0xa2, 0x04, 0x81, 0x00, 0x0c, 0x04, 0x91, 0xff, 0xad, 0x2e, 0x05, 0x00, 0x05, 0x31, 0xb5, 0xff, 0xa5, 0x07, 0x81, 0x00, 0x0c, 0x10, 0xd1, 0xff, 0x81, 0x0f, 0x00, 0x00, 0x0c, 0x6d, 0xaa, 0xff, 0xff, 0x22, 0x81, 0x00, 0x04, 0x04, 0x91, 0xff, 0xa2, 0x23, 0x80, 0x00, 0x03, 0x2a, 0xbb, 0xff, 0x70, 0x85, 0x00, 0x02, 0x4b, 0xff, 0xb9, 0x88, 0x00, 0x0c, 0x0c, 0xca, 0xff, 0x8f, 0x14, 0x00, 0x00, 0x18, 0x92, 0x80, 0xff, 0xff, 0x2a, 0x81, 0x00, 0x0b, 0x40, 0xff, 0xb1, 0x92, 0x73, 0x14, 0x00, 0x01, 0x24, 0xbd, 0xff, 0x98, 0x87, 0x00, 0x03, 0x24, 0xff, 0xff, 0x17, 0x8b, 0x00, 0x03, 0x04, 0xff, 0xff, 0x3b, 0x85, 0x00, 0x02, 0x7c, 0xff, 0x69, 0x80, 0x00, 0x04, 0x10, 0xab, 0xff, 0x6f, 0x02, 0x87, 0x00, 0x03, 0x34, 0xff, 0xff, 0x07, 0x84, 0x00, 0x0e, 0x52, 0xff, 0xa0, 0x6c, 0x02, 0x1f, 0xff, 0xdd, 0x8b, 0x3d, 0x00, 0x3c, 0xff, 0xff, 0x0f, 0x80, 0x00, 0x0c, 0x41, 0xff, 0xa5, 0x92, 0x73, 0x14, 0x00, 0x01, 0x24, 0xbd, 0xff, 0x9f, 0x01, 0x81, 0x00, 0x0c, 0x07, 0x9d, 0xff, 0xa5, 0x1f, 0x00, 0x00, 0x01, 0x2a, 0xbf, 0xff, 0x82, 0x01, 0x81, 0x00, 0x0c, 0x41, 0xff, 0xd4, 0x8b, 0x69, 0x0f, 0x00, 0x00, 0x23, 0xaf, 0xff, 0xa8, 0x04, 0x81, 0x00, 0x0c, 0x10, 0xd1, 0xff, 0x80, 0x0e, 0x00, 0x00, 0x0d, 0x71, 0xa6, 0xff, 0xff, 0x24, 0x82, 0x00, 0x0b, 0x1a, 0xff, 0xff, 0x1d, 0xb7, 0xea, 0x64, 0x2e, 0x22, 0x27, 0x36, 0x11, 0x82, 0x00, 0x03, 0x7a, 0xff, 0x81, 0x13, 0x80, 0x00, 0x03, 0x14, 0x7f, 0xff, 0x7d, 0x84, 0x00, 0x03, 0x0d, 0xff, 0xff, 0x2f, 0x88, 0x00, 0x02, 0x40, 0xff, 0xdd, 0x83, 0x00, 0x03, 0x0f, 0xff, 0xff, 0x2d, 0x80, 0x00, 0x03, 0x0b, 0xd8, 0xff, 0x5f, 0x84, 0x00, 0x08, 0x99, 0xff, 0x8d, 0x00, 0x00, 0x26, 0xff, 0xff, 0x0b, 0x86, 0x00, 0x03, 0x26, 0xff, 0xff, 0x0a, 0x80, 0x00, 0x03, 0x5a, 0xff, 0xad, 0x0b, 0x80, 0x00, 0x03, 0x29, 0xff, 0xff, 0x27, 0x81, 0x00, 0x03, 0x07, 0xc4, 0xff, 0x50, 0x84, 0x00, 0x02, 0x6e, 0xff, 0x90, 0x89, 0x00, 0x03, 0x1a, 0xca, 0xff, 0x50, 0x86, 0x00, 0x03, 0x11, 0xff, 0xff, 0x1f, 0x8b, 0x00, 0x02, 0x74, 0xff, 0x4b, 0x8b, 0x00, 0x02, 0x3d, 0xff, 0xb1, 0x96, 0x00, 0x02, 0x2b, 0x45, 0x38, 0x85, 0x00, 0x02, 0xa0, 0xff, 0x58, 0x97, 0x00, 0x02, 0x7e, 0xff, 0x54, 0x88, 0x00, 0x02, 0x41, 0x6d, 0x1a, 0x80, 0x00, 0x02, 0x33, 0x6d, 0x28, 0x82, 0x00, 0x05, 0x17, 0x2a, 0x2a, 0x4e, 0xff, 0x3f, 0x81, 0x2a, 0x04, 0xaa, 0x7b, 0x2a, 0x2a, 0x26, 0x80, 0x00, 0x07, 0x6e, 0xff, 0xbf, 0x30, 0x02, 0x31, 0xff, 0x31, 0x84, 0x00, 0x0b, 0x53, 0xff, 0x6a, 0x0a, 0x0e, 0x85, 0xff, 0x36, 0x02, 0x84, 0xd4, 0x19, 0x85, 0x00, 0x08, 0x02, 0xab, 0xff, 0x2b, 0x49, 0xb3, 0xff, 0x72, 0x0e, 0x89, 0x00, 0x02, 0x38, 0x6d, 0x22, 0x89, 0x00, 0x02, 0x95, 0xff, 0x72, 0x8f, 0x00, 0x02, 0xb5, 0xff, 0x5e, 0x86, 0x00, 0x07, 0x0f, 0xc7, 0xb9, 0x0b, 0x00, 0x26, 0xff, 0x83, 0x89, 0x00, 0x02, 0x59, 0xff, 0x34, 0xbe, 0x00, 0x03, 0x07, 0xb1, 0xff, 0x40, 0x84, 0x00, 0x05, 0x11, 0xff, 0xff, 0x2b, 0x00, 0x0a, 0x80, 0x34, 0x04, 0x00, 0x00, 0x54, 0xff, 0xaf, 0x87, 0x00, 0x02, 0x92, 0xff, 0x5c, 0x8e, 0x00, 0x03, 0x38, 0xff, 0xff, 0x15, 0x87, 0x00, 0x05, 0x08, 0x1d, 0x57, 0xea, 0xff, 0x43, 0x85, 0x00, 0x07, 0x58, 0xff, 0x49, 0x00, 0x00, 0x63, 0xff, 0x89, 0x83, 0x00, 0x0a, 0x44, 0xff, 0x9f, 0x18, 0x5c, 0x9f, 0xd1, 0xbb, 0x84, 0x43, 0x08, 0x83, 0x00, 0x0a, 0x68, 0xff, 0x67, 0x00, 0x30, 0x79, 0xb1, 0xcd, 0x96, 0x52, 0x0f, 0x8a, 0x00, 0x02, 0x7b, 0xff, 0x66, 0x84, 0x00, 0x04, 0x06, 0x96, 0xff, 0x79, 0x13, 0x80, 0x00, 0x03, 0x1f, 0x9c, 0xff, 0x60, 0x81, 0x00, 0x03, 0x04, 0xff, 0xff, 0x48, 0x84, 0x00, 0x02, 0x90, 0xff, 0x71, 0x85, 0x00, 0x00, 0x1b, 0x80, 0xff, 0x8a, 0x00, 0x00, 0x1b, 0x80, 0xff, 0x86, 0x00, 0x07, 0x03, 0x2e, 0x7f, 0xff, 0xff, 0xdd, 0x68, 0x20, 0x86, 0x00, 0x8a, 0x02, 0x85, 0x00, 0x07, 0x03, 0x2e, 0x80, 0xff, 0xff, 0xdd, 0x68, 0x22, 0x8b, 0x00, 0x03, 0x24, 0xff, 0xff, 0x2b, 0x80, 0x00, 0x05, 0xb3, 0x8d, 0x00, 0x23, 0xff, 0x4d, 0x80, 0x00, 0x06, 0x42, 0xff, 0x71, 0x00, 0x3e, 0xff, 0x16, 0x81, 0x00, 0x08, 0x4d, 0xff, 0x94, 0x00, 0x00, 0x04, 0xbd, 0xff, 0x37, 0x83, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x80, 0x00, 0x05, 0x03, 0x10, 0x38, 0xb3, 0xff, 0x63, 0x81, 0x00, 0x03, 0x22, 0xff, 0xff, 0x41, 0x8b, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x84, 0x00, 0x03, 0x43, 0xff, 0xff, 0x16, 0x80, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x8b, 0x00, 0x03, 0x2d, 0xff, 0xff, 0x22, 0x89, 0x00, 0x03, 0x23, 0xff, 0xff, 0x3f, 0x8b, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x83, 0x00, 0x03, 0x04, 0xff, 0xff, 0x53, 0x86, 0x00, 0x02, 0xb1, 0xff, 0x69, 0x8e, 0x00, 0x03, 0x0d, 0xff, 0xff, 0x43, 0x82, 0x00, 0x08, 0x80, 0xff, 0x8d, 0x00, 0x0e, 0xa5, 0xff, 0x83, 0x06, 0x86, 0x00, 0x02, 0x7c, 0xff, 0x98, 0x89, 0x00, 0x0e, 0x1d, 0xff, 0xbf, 0x00, 0x6f, 0xff, 0x47, 0x00, 0x50, 0xff, 0x47, 0x17, 0xff, 0xff, 0x04, 0x80, 0x00, 0x06, 0x80, 0xff, 0x4d, 0x06, 0xb7, 0xff, 0x2b, 0x80, 0x00, 0x02, 0x80, 0xff, 0x53, 0x80, 0x00, 0x03, 0x39, 0xff, 0xff, 0x29, 0x84, 0x00, 0x03, 0x4d, 0xff, 0xff, 0x1a, 0x80, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x84, 0x00, 0x09, 0x48, 0xff, 0xff, 0x12, 0x00, 0x00, 0x30, 0xff, 0xff, 0x30, 0x84, 0x00, 0x03, 0x55, 0xff, 0xff, 0x12, 0x80, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x83, 0x00, 0x04, 0x01, 0x76, 0xff, 0xc7, 0x06, 0x80, 0x00, 0x04, 0x53, 0xff, 0xff, 0x44, 0x06, 0x8e, 0x00, 0x02, 0xaa, 0xff, 0x69, 0x85, 0x00, 0x03, 0x07, 0xff, 0xff, 0x4d, 0x84, 0x00, 0x02, 0x7c, 0xff, 0x8d, 0x81, 0x00, 0x03, 0x30, 0xff, 0xff, 0x1f, 0x82, 0x00, 0x03, 0x3c, 0xff, 0xff, 0x14, 0x80, 0x00, 0x08, 0xc2, 0xff, 0x3d, 0x00, 0x00, 0x06, 0xd8, 0xff, 0x99, 0x80, 0x00, 0x02, 0x5d, 0xff, 0x79, 0x83, 0x00, 0x06, 0x3d, 0xff, 0xbf, 0x37, 0xff, 0xea, 0x1f, 0x86, 0x00, 0x08, 0x25, 0xff, 0xff, 0x30, 0x00, 0x50, 0xff, 0xc2, 0x10, 0x89, 0x00, 0x03, 0x2c, 0xff, 0xff, 0x3e, 0x87, 0x00, 0x03, 0x34, 0xff, 0xff, 0x07, 0x8b, 0x00, 0x02, 0x66, 0xff, 0x7d, 0x8d, 0x00, 0x03, 0x26, 0xff, 0xff, 0x15, 0x85, 0x00, 0x03, 0x02, 0xa5, 0xe3, 0x0f, 0x80, 0x00, 0x02, 0x32, 0xff, 0x65, 0xa5, 0x00, 0x03, 0x3a, 0xff, 0xff, 0x16, 0x81, 0x00, 0x03, 0x0a, 0xe3, 0xff, 0x46, 0x82, 0x00, 0x04, 0x40, 0xff, 0xff, 0x8f, 0x02, 0x81, 0x00, 0x03, 0x30, 0xff, 0xff, 0x2d, 0x81, 0x00, 0x03, 0x3d, 0xff, 0xea, 0x1b, 0x82, 0x00, 0x03, 0x27, 0xff, 0xff, 0x40, 0x81, 0x00, 0x03, 0x4c, 0xff, 0xd8, 0x10, 0x81, 0x00, 0x04, 0x04, 0xa0, 0xff, 0xff, 0x22, 0x81, 0x00, 0x03, 0x3b, 0xff, 0xd4, 0x15, 0x82, 0x00, 0x03, 0x2b, 0xff, 0xff, 0x20, 0x84, 0x00, 0x02, 0x4b, 0xff, 0xb9, 0x88, 0x00, 0x03, 0x43, 0xff, 0xea, 0x16, 0x81, 0x00, 0x04, 0x10, 0xc7, 0xff, 0xff, 0x2a, 0x81, 0x00, 0x04, 0x40, 0xff, 0xff, 0x84, 0x02, 0x81, 0x00, 0x03, 0x41, 0xff, 0xff, 0x14, 0x86, 0x00, 0x03, 0x24, 0xff, 0xff, 0x17, 0x8b, 0x00, 0x03, 0x04, 0xff, 0xff, 0x3b, 0x85, 0x00, 0x09, 0x7c, 0xff, 0x69, 0x00, 0x00, 0x0a, 0x95, 0xff, 0x7c, 0x05, 0x88, 0x00, 0x03, 0x34, 0xff, 0xff, 0x07, 0x84, 0x00, 0x0e, 0x50, 0xff, 0xff, 0x17, 0x00, 0x00, 0xa3, 0xff, 0xaa, 0x01, 0x00, 0x09, 0xff, 0xff, 0x24, 0x80, 0x00, 0x04, 0x40, 0xff, 0xff, 0x84, 0x02, 0x81, 0x00, 0x03, 0x41, 0xff, 0xff, 0x15, 0x81, 0x00, 0x03, 0x43, 0xff, 0xff, 0x1b, 0x82, 0x00, 0x03, 0x33, 0xff, 0xff, 0x29, 0x81, 0x00, 0x04, 0x40, 0xff, 0xff, 0x91, 0x02, 0x81, 0x00, 0x03, 0x2a, 0xff, 0xff, 0x30, 0x81, 0x00, 0x03, 0x4b, 0xff, 0xd8, 0x0e, 0x81, 0x00, 0x04, 0x06, 0xa6, 0xff, 0xff, 0x24, 0x82, 0x00, 0x05, 0x0b, 0xff, 0xff, 0x87, 0xca, 0x25, 0x87, 0x00, 0x03, 0x06, 0xff, 0xff, 0x20, 0x82, 0x00, 0x03, 0x15, 0x6f, 0x56, 0x04, 0x83, 0x00, 0x03, 0x0d, 0xff, 0xff, 0x2f, 0x88, 0x00, 0x02, 0x40, 0xff, 0xdd, 0x83, 0x00, 0x03, 0x0f, 0xff, 0xff, 0x2d, 0x81, 0x00, 0x03, 0x68, 0xff, 0xc4, 0x06, 0x82, 0x00, 0x09, 0x20, 0xff, 0xff, 0x39, 0x00, 0x00, 0x10, 0xff, 0xff, 0x1f, 0x86, 0x00, 0x02, 0x3f, 0xff, 0xaa, 0x81, 0x00, 0x09, 0x05, 0x8f, 0xff, 0x6e, 0x00, 0x00, 0x0b, 0xaf, 0xff, 0x4f, 0x83, 0x00, 0x03, 0x56, 0xff, 0xb7, 0x04, 0x82, 0x00, 0x03, 0x0e, 0xe3, 0xff, 0x39, 0x88, 0x00, 0x04, 0x0c, 0xa6, 0xff, 0x6f, 0x01, 0x86, 0x00, 0x03, 0x11, 0xff, 0xff, 0x1f, 0x8b, 0x00, 0x02, 0x74, 0xff, 0x4b, 0x8b, 0x00, 0x02, 0x3d, 0xff, 0xb1, 0x86, 0x00, 0x06, 0x16, 0x5f, 0x90, 0x92, 0x6b, 0x38, 0x0a, 0x82, 0x00, 0x01, 0x04, 0x0d, 0x89, 0x00, 0x03, 0x24, 0xff, 0xff, 0x2b, 0x97, 0x00, 0x02, 0x78, 0xff, 0x50, 0x99, 0x00, 0x02, 0x46, 0xdd, 0x05, 0x80, 0x00, 0x02, 0x06, 0xe3, 0x41, 0x83, 0x00, 0x08, 0x0e, 0x95, 0xff, 0xff, 0xb5, 0x8b, 0xff, 0x52, 0x0e, 0x83, 0x00, 0x01, 0x08, 0x8a, 0x81, 0xff, 0x04, 0x6c, 0x02, 0x49, 0xff, 0x40, 0x87, 0x00, 0x00, 0x5c, 0x80, 0xff, 0x01, 0x7f, 0x26, 0x99, 0x00, 0x03, 0x06, 0xff, 0xff, 0x49, 0x8f, 0x00, 0x02, 0x71, 0xff, 0x8d, 0x87, 0x00, 0x01, 0x26, 0x2f, 0x80, 0x00, 0x01, 0x48, 0x15, 0x89, 0x00, 0x02, 0x59, 0xff, 0x34, 0xbe, 0x00, 0x03, 0x4d, 0xff, 0x9f, 0x04, 0x84, 0x00, 0x05, 0x1b, 0xff, 0xff, 0x1e, 0x00, 0x1b, 0x80, 0xff, 0x04, 0x00, 0x00, 0x41, 0xff, 0xe3, 0x87, 0x00, 0x02, 0x92, 0xff, 0x5c, 0x8d, 0x00, 0x03, 0x12, 0xbb, 0xff, 0x64, 0x86, 0x00, 0x00, 0x5c, 0x80, 0xff, 0x02, 0xc4, 0x6f, 0x21, 0x85, 0x00, 0x08, 0x29, 0xff, 0x7f, 0x02, 0x00, 0x00, 0x63, 0xff, 0x89, 0x83, 0x00, 0x03, 0x50, 0xff, 0xd1, 0xe3, 0x83, 0xff, 0x01, 0xa8, 0x1c, 0x82, 0x00, 0x0b, 0x8d, 0xff, 0x52, 0x65, 0xff, 0xff, 0xb3, 0xcd, 0xff, 0xff, 0xc2, 0x25, 0x88, 0x00, 0x03, 0x2b, 0xff, 0xd8, 0x11, 0x85, 0x00, 0x0a, 0x09, 0x5f, 0xc7, 0xff, 0xab, 0x98, 0xb9, 0xff, 0xa5, 0x44, 0x01, 0x82, 0x00, 0x02, 0xa6, 0xff, 0x6d, 0x83, 0x00, 0x03, 0x03, 0xbb, 0xff, 0x84, 0x85, 0x00, 0x00, 0x02, 0x80, 0x09, 0x8a, 0x00, 0x00, 0x02, 0x80, 0x09, 0x85, 0x00, 0x06, 0x21, 0xad, 0xff, 0xff, 0xb1, 0x4b, 0x0f, 0xa0, 0x00, 0x06, 0x1a, 0x5e, 0xcd, 0xff, 0xff, 0x92, 0x0d, 0x88, 0x00, 0x03, 0x17, 0xaa, 0xff, 0x79, 0x80, 0x00, 0x06, 0x0b, 0xff, 0x61, 0x00, 0x62, 0xff, 0x16, 0x80, 0x00, 0x06, 0x39, 0xff, 0x4b, 0x00, 0x36, 0xff, 0x1d, 0x80, 0x00, 0x03, 0x02, 0xab, 0xff, 0x44, 0x80, 0x00, 0x02, 0x5d, 0xff, 0x83, 0x83, 0x00, 0x00, 0x80, 0x85, 0xff, 0x01, 0x7d, 0x34, 0x82, 0x00, 0x03, 0x32, 0xff, 0xff, 0x2e, 0x8b, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x84, 0x00, 0x03, 0x2a, 0xff, 0xff, 0x24, 0x80, 0x00, 0x02, 0x80, 0xff, 0x92, 0x85, 0x0b, 0x00, 0x0a, 0x82, 0x00, 0x03, 0x2d, 0xff, 0xff, 0x22, 0x89, 0x00, 0x03, 0x32, 0xff, 0xff, 0x2e, 0x8b, 0x00, 0x00, 0x80, 0x88, 0xff, 0x00, 0x53, 0x86, 0x00, 0x02, 0xb1, 0xff, 0x69, 0x8e, 0x00, 0x03, 0x0d, 0xff, 0xff, 0x43, 0x82, 0x00, 0x07, 0x80, 0xff, 0x8d, 0x06, 0x8c, 0xff, 0xc7, 0x0b, 0x87, 0x00, 0x02, 0x7c, 0xff, 0x98, 0x89, 0x00, 0x0e, 0x1d, 0xff, 0xc2, 0x00, 0x2a, 0xff, 0x95, 0x00, 0xa6, 0xea, 0x10, 0x17, 0xff, 0xff, 0x04, 0x80, 0x00, 0x06, 0x80, 0xff, 0x4d, 0x00, 0x48, 0xff, 0x88, 0x80, 0x00, 0x02, 0x80, 0xff, 0x53, 0x80, 0x00, 0x03, 0x4b, 0xff, 0xff, 0x19, 0x84, 0x00, 0x03, 0x39, 0xff, 0xff, 0x28, 0x80, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x83, 0x00, 0x03, 0x0e, 0xb1, 0xff, 0x91, 0x80, 0x00, 0x03, 0x47, 0xff, 0xff, 0x1d, 0x84, 0x00, 0x03, 0x3e, 0xff, 0xff, 0x24, 0x80, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x81, 0x00, 0x05, 0x06, 0x20, 0x70, 0xff, 0xff, 0x47, 0x81, 0x00, 0x07, 0x08, 0x82, 0xff, 0xff, 0xc2, 0x64, 0x38, 0x16, 0x8b, 0x00, 0x02, 0xaa, 0xff, 0x69, 0x85, 0x00, 0x03, 0x07, 0xff, 0xff, 0x4d, 0x84, 0x00, 0x02, 0x7c, 0xff, 0x8d, 0x81, 0x00, 0x03, 0x05, 0xbb, 0xff, 0x5a, 0x82, 0x00, 0x02, 0x85, 0xff, 0x7f, 0x81, 0x00, 0x05, 0x84, 0xff, 0x55, 0x00, 0x00, 0x29, 0x80, 0xff, 0x05, 0x12, 0x00, 0x00, 0x79, 0xff, 0x56, 0x83, 0x00, 0x01, 0x01, 0x78, 0x80, 0xff, 0x00, 0x4e, 0x88, 0x00, 0x06, 0x60, 0xff, 0xad, 0x22, 0xdd, 0xff, 0x3b, 0x89, 0x00, 0x03, 0x16, 0xc4, 0xff, 0x63, 0x88, 0x00, 0x03, 0x34, 0xff, 0xff, 0x07, 0x8b, 0x00, 0x03, 0x11, 0xd1, 0xff, 0x2b, 0x8c, 0x00, 0x03, 0x26, 0xff, 0xff, 0x15, 0x85, 0x00, 0x02, 0x2a, 0xff, 0x6e, 0x81, 0x00, 0x03, 0x04, 0xb7, 0xd8, 0x0c, 0xa5, 0x00, 0x01, 0x04, 0x10, 0x83, 0x00, 0x02, 0x98, 0xff, 0x5f, 0x82, 0x00, 0x03, 0x40, 0xff, 0xff, 0x36, 0x82, 0x00, 0x03, 0x02, 0xbf, 0xff, 0x5b, 0x81, 0x00, 0x02, 0x89, 0xff, 0x75, 0x83, 0x00, 0x03, 0x01, 0x43, 0x3a, 0x20, 0x81, 0x00, 0x02, 0x89, 0xff, 0x79, 0x83, 0x00, 0x03, 0x49, 0xff, 0xff, 0x22, 0x81, 0x00, 0x02, 0x84, 0xff, 0x68, 0x84, 0x00, 0x02, 0x9f, 0xff, 0x55, 0x84, 0x00, 0x02, 0x4b, 0xff, 0xb9, 0x88, 0x00, 0x02, 0x7a, 0xff, 0x88, 0x83, 0x00, 0x03, 0x59, 0xff, 0xff, 0x2a, 0x81, 0x00, 0x03, 0x40, 0xff, 0xff, 0x28, 0x82, 0x00, 0x03, 0x1a, 0xff, 0xff, 0x26, 0x86, 0x00, 0x03, 0x24, 0xff, 0xff, 0x17, 0x8b, 0x00, 0x03, 0x04, 0xff, 0xff, 0x3b, 0x85, 0x00, 0x08, 0x7c, 0xff, 0x69, 0x00, 0x05, 0x81, 0xff, 0x89, 0x07, 0x89, 0x00, 0x03, 0x34, 0xff, 0xff, 0x07, 0x84, 0x00, 0x02, 0x50, 0xff, 0xb3, 0x80, 0x00, 0x02, 0x7e, 0xff, 0x6b, 0x80, 0x00, 0x02, 0xc7, 0xff, 0x2d, 0x80, 0x00, 0x03, 0x40, 0xff, 0xff, 0x28, 0x82, 0x00, 0x03, 0x1a, 0xff, 0xff, 0x26, 0x81, 0x00, 0x02, 0x91, 0xff, 0x7e, 0x83, 0x00, 0x03, 0x03, 0xb7, 0xff, 0x60, 0x81, 0x00, 0x03, 0x40, 0xff, 0xff, 0x39, 0x82, 0x00, 0x03, 0x01, 0xb9, 0xff, 0x5c, 0x81, 0x00, 0x02, 0x88, 0xff, 0x75, 0x83, 0x00, 0x03, 0x4d, 0xff, 0xff, 0x24, 0x82, 0x00, 0x00, 0x03, 0x80, 0xff, 0x00, 0x3c, 0x88, 0x00, 0x03, 0x0a, 0xff, 0xff, 0x2a, 0x8c, 0x00, 0x03, 0x0d, 0xff, 0xff, 0x2f, 0x88, 0x00, 0x02, 0x40, 0xff, 0xdd, 0x83, 0x00, 0x03, 0x0f, 0xff, 0xff, 0x2d, 0x81, 0x00, 0x03, 0x24, 0xff, 0xff, 0x34, 0x82, 0x00, 0x03, 0x5f, 0xff, 0xc4, 0x07, 0x80, 0x00, 0x08, 0xc4, 0xff, 0x35, 0x00, 0x00, 0x08, 0xa5, 0xaa, 0x7e, 0x80, 0x00, 0x02, 0x5c, 0xff, 0x74, 0x82, 0x00, 0x08, 0x15, 0xc4, 0xff, 0x37, 0x00, 0x6d, 0xff, 0x81, 0x02, 0x83, 0x00, 0x03, 0x14, 0xff, 0xff, 0x33, 0x82, 0x00, 0x03, 0x45, 0xff, 0xc2, 0x06, 0x87, 0x00, 0x04, 0x04, 0x83, 0xff, 0x91, 0x07, 0x87, 0x00, 0x03, 0x19, 0xff, 0xff, 0x1c, 0x8b, 0x00, 0x02, 0x74, 0xff, 0x4b, 0x8b, 0x00, 0x03, 0x3a, 0xff, 0xcd, 0x01, 0x84, 0x00, 0x01, 0x2e, 0xd8, 0x82, 0xff, 0x07, 0xcd, 0x60, 0x24, 0x06, 0x06, 0x29, 0x8c, 0x28, 0x88, 0x00, 0x03, 0x17, 0xaa, 0xff, 0x79, 0x98, 0x00, 0x02, 0x71, 0xff, 0x4b, 0x99, 0x00, 0x01, 0x6f, 0x8b, 0x81, 0x00, 0x02, 0x1e, 0xff, 0x23, 0x84, 0x00, 0x02, 0x06, 0x47, 0xa6, 0x82, 0xff, 0x02, 0x89, 0x3c, 0x04, 0x81, 0x00, 0x0c, 0x02, 0x27, 0x40, 0x3d, 0x20, 0x00, 0x1e, 0xe3, 0x78, 0x01, 0x00, 0x09, 0x07, 0x82, 0x00, 0x01, 0x0a, 0x6e, 0x80, 0xff, 0x00, 0x3c, 0x81, 0x00, 0x02, 0x2d, 0x5f, 0x1f, 0x94, 0x00, 0x03, 0x17, 0xff, 0xff, 0x33, 0x8f, 0x00, 0x02, 0x55, 0xff, 0xbf, 0x94, 0x00, 0x00, 0x35, 0x82, 0xdd, 0x02, 0xea, 0xff, 0xe3, 0x82, 0xdd, 0x00, 0x17, 0xb7, 0x00, 0x03, 0x10, 0xd1, 0xff, 0x2e, 0x85, 0x00, 0x05, 0x22, 0xff, 0xff, 0x19, 0x00, 0x1b, 0x80, 0xff, 0x05, 0x00, 0x00, 0x3c, 0xff, 0xff, 0x06, 0x86, 0x00, 0x02, 0x92, 0xff, 0x5c, 0x8c, 0x00, 0x04, 0x12, 0x9f, 0xff, 0x98, 0x09, 0x86, 0x00, 0x00, 0x5c, 0x80, 0xff, 0x02, 0xbd, 0x75, 0x2d, 0x84, 0x00, 0x03, 0x0e, 0xb5, 0xb9, 0x0f, 0x80, 0x00, 0x02, 0x63, 0xff, 0x89, 0x83, 0x00, 0x0c, 0x5d, 0xff, 0xff, 0x81, 0x28, 0x09, 0x03, 0x13, 0x49, 0xd4, 0xff, 0xb5, 0x0d, 0x81, 0x00, 0x0c, 0xa2, 0xff, 0xaa, 0xd4, 0x46, 0x09, 0x00, 0x03, 0x30, 0xb7, 0xff, 0xc2, 0x10, 0x86, 0x00, 0x03, 0x01, 0x90, 0xff, 0x5e, 0x86, 0x00, 0x02, 0x03, 0x3d, 0x91, 0x82, 0xff, 0x01, 0x7a, 0x32, 0x83, 0x00, 0x03, 0x57, 0xff, 0xea, 0x1a, 0x82, 0x00, 0x03, 0x4d, 0xff, 0xff, 0x92, 0xa2, 0x00, 0x04, 0x36, 0xff, 0x9d, 0x32, 0x04, 0xa4, 0x00, 0x04, 0x0a, 0x43, 0xc4, 0xff, 0x17, 0x87, 0x00, 0x04, 0x36, 0xc2, 0xff, 0x78, 0x07, 0x80, 0x00, 0x05, 0x1e, 0xff, 0x44, 0x00, 0xa8, 0xb1, 0x81, 0x00, 0x06, 0x47, 0xff, 0x2b, 0x00, 0x37, 0xff, 0x1b, 0x80, 0x00, 0x03, 0x29, 0xff, 0xff, 0x10, 0x80, 0x00, 0x03, 0x24, 0xff, 0xff, 0x15, 0x82, 0x00, 0x00, 0x80, 0x85, 0xff, 0x02, 0xc4, 0x6f, 0x22, 0x81, 0x00, 0x03, 0x3a, 0xff, 0xff, 0x28, 0x8b, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x84, 0x00, 0x03, 0x22, 0xff, 0xff, 0x2d, 0x80, 0x00, 0x00, 0x80, 0x87, 0xff, 0x00, 0xc2, 0x82, 0x00, 0x03, 0x2d, 0xff, 0xff, 0x32, 0x85, 0x13, 0x00, 0x09, 0x80, 0x00, 0x03, 0x3a, 0xff, 0xff, 0x28, 0x80, 0x00, 0x00, 0x45, 0x83, 0xff, 0x00, 0x06, 0x80, 0x00, 0x00, 0x80, 0x88, 0xff, 0x00, 0x53, 0x86, 0x00, 0x02, 0xb1, 0xff, 0x69, 0x8e, 0x00, 0x03, 0x0d, 0xff, 0xff, 0x43, 0x82, 0x00, 0x03, 0x80, 0xff, 0x92, 0x72, 0x80, 0xff, 0x00, 0x45, 0x87, 0x00, 0x02, 0x7c, 0xff, 0x98, 0x89, 0x00, 0x0e, 0x1d, 0xff, 0xc2, 0x00, 0x02, 0xab, 0xff, 0x30, 0xff, 0x76, 0x00, 0x17, 0xff, 0xff, 0x04, 0x80, 0x00, 0x0c, 0x80, 0xff, 0x4d, 0x00, 0x0a, 0xc7, 0xff, 0x25, 0x00, 0x00, 0x80, 0xff, 0x53, 0x80, 0x00, 0x03, 0x54, 0xff, 0xff, 0x13, 0x84, 0x00, 0x03, 0x32, 0xff, 0xff, 0x30, 0x80, 0x00, 0x02, 0x80, 0xff, 0x90, 0x80, 0x06, 0x06, 0x07, 0x14, 0x3c, 0xab, 0xff, 0xea, 0x26, 0x80, 0x00, 0x03, 0x50, 0xff, 0xff, 0x15, 0x84, 0x00, 0x03, 0x35, 0xff, 0xff, 0x2c, 0x80, 0x00, 0x00, 0x80, 0x86, 0xff, 0x02, 0xea, 0x4f, 0x01, 0x82, 0x00, 0x02, 0x04, 0x3c, 0x96, 0x81, 0xff, 0x02, 0xaf, 0x59, 0x1b, 0x88, 0x00, 0x02, 0xaa, 0xff, 0x69, 0x85, 0x00, 0x03, 0x07, 0xff, 0xff, 0x4d, 0x84, 0x00, 0x02, 0x7c, 0xff, 0x8d, 0x82, 0x00, 0x03, 0x57, 0xff, 0xbb, 0x04, 0x80, 0x00, 0x03, 0x14, 0xff, 0xff, 0x34, 0x81, 0x00, 0x0e, 0x5f, 0xff, 0x70, 0x00, 0x00, 0x57, 0xff, 0x6f, 0xff, 0x3a, 0x00, 0x00, 0xa0, 0xff, 0x3b, 0x84, 0x00, 0x04, 0x16, 0xff, 0xff, 0xb9, 0x04, 0x88, 0x00, 0x06, 0x09, 0xad, 0xff, 0xdd, 0xff, 0x7f, 0x01, 0x88, 0x00, 0x04, 0x08, 0x9a, 0xff, 0x8a, 0x05, 0x88, 0x00, 0x03, 0x34, 0xff, 0xff, 0x07, 0x8c, 0x00, 0x03, 0x4f, 0xff, 0x9a, 0x03, 0x8b, 0x00, 0x03, 0x26, 0xff, 0xff, 0x15, 0x85, 0x00, 0x02, 0x76, 0xff, 0x26, 0x82, 0x00, 0x02, 0x51, 0xff, 0x45, 0xad, 0x00, 0x02, 0x89, 0xff, 0x66, 0x82, 0x00, 0x03, 0x40, 0xff, 0xff, 0x14, 0x83, 0x00, 0x02, 0x7f, 0xff, 0x80, 0x80, 0x00, 0x03, 0x06, 0xea, 0xff, 0x46, 0x8a, 0x00, 0x03, 0x01, 0xcd, 0xff, 0x51, 0x83, 0x00, 0x03, 0x2a, 0xff, 0xff, 0x22, 0x80, 0x00, 0x03, 0x05, 0xe3, 0xff, 0x44, 0x84, 0x00, 0x02, 0x63, 0xff, 0x81, 0x84, 0x00, 0x02, 0x4b, 0xff, 0xb9, 0x88, 0x00, 0x02, 0xad, 0xff, 0x5c, 0x83, 0x00, 0x03, 0x2b, 0xff, 0xff, 0x2a, 0x81, 0x00, 0x03, 0x40, 0xff, 0xff, 0x08, 0x82, 0x00, 0x03, 0x10, 0xff, 0xff, 0x2c, 0x86, 0x00, 0x03, 0x24, 0xff, 0xff, 0x17, 0x8b, 0x00, 0x03, 0x04, 0xff, 0xff, 0x3b, 0x85, 0x00, 0x07, 0x7c, 0xff, 0x69, 0x02, 0x6e, 0xff, 0x95, 0x0b, 0x8a, 0x00, 0x03, 0x34, 0xff, 0xff, 0x07, 0x84, 0x00, 0x02, 0x50, 0xff, 0x8c, 0x80, 0x00, 0x02, 0x75, 0xff, 0x56, 0x80, 0x00, 0x02, 0xb3, 0xff, 0x31, 0x80, 0x00, 0x03, 0x40, 0xff, 0xff, 0x08, 0x82, 0x00, 0x03, 0x10, 0xff, 0xff, 0x2c, 0x80, 0x00, 0x03, 0x07, 0xea, 0xff, 0x4a, 0x84, 0x00, 0x02, 0x74, 0xff, 0x92, 0x81, 0x00, 0x03, 0x40, 0xff, 0xff, 0x17, 0x83, 0x00, 0x02, 0x7c, 0xff, 0x80, 0x80, 0x00, 0x03, 0x01, 0xca, 0xff, 0x4f, 0x83, 0x00, 0x03, 0x2b, 0xff, 0xff, 0x24, 0x83, 0x00, 0x03, 0xdd, 0xff, 0xb1, 0x03, 0x89, 0x00, 0x04, 0x99, 0xff, 0xc2, 0x3e, 0x0d, 0x8a, 0x00, 0x03, 0x0d, 0xff, 0xff, 0x2f, 0x88, 0x00, 0x02, 0x40, 0xff, 0xdd, 0x83, 0x00, 0x03, 0x0f, 0xff, 0xff, 0x2d, 0x81, 0x00, 0x03, 0x01, 0x9f, 0xff, 0x7d, 0x81, 0x00, 0x03, 0x07, 0xc7, 0xff, 0x5b, 0x81, 0x00, 0x0e, 0x84, 0xff, 0x4e, 0x00, 0x00, 0x30, 0xff, 0xcd, 0xff, 0x11, 0x00, 0x00, 0x82, 0xff, 0x50, 0x83, 0x00, 0x06, 0x32, 0xff, 0xc4, 0x4c, 0xff, 0xb7, 0x10, 0x85, 0x00, 0x02, 0x74, 0xff, 0x84, 0x81, 0x00, 0x03, 0x01, 0xa0, 0xff, 0x57, 0x88, 0x00, 0x03, 0x62, 0xff, 0xb5, 0x11, 0x88, 0x00, 0x03, 0x53, 0xff, 0xc4, 0x06, 0x8b, 0x00, 0x02, 0x74, 0xff, 0x4b, 0x8b, 0x00, 0x03, 0x1b, 0xff, 0xff, 0x2d, 0x84, 0x00, 0x07, 0x48, 0x73, 0x1f, 0x05, 0x0b, 0x27, 0x64, 0xd1, 0x82, 0xff, 0x01, 0xdd, 0x1c, 0x87, 0x00, 0x04, 0x36, 0xc2, 0xff, 0x78, 0x07, 0x98, 0x00, 0x02, 0x6c, 0xff, 0x47, 0x99, 0x00, 0x01, 0xab, 0x5a, 0x81, 0x00, 0x02, 0x3c, 0xff, 0x08, 0x86, 0x00, 0x09, 0x01, 0x1a, 0x5e, 0xff, 0xaa, 0xea, 0xff, 0xff, 0xa0, 0x16, 0x85, 0x00, 0x13, 0x07, 0x9d, 0xb7, 0x0e, 0x41, 0xaf, 0xff, 0xff, 0x9a, 0x2a, 0x00, 0x00, 0x0c, 0x94, 0xff, 0x76, 0x4d, 0xff, 0x99, 0x05, 0x80, 0x00, 0x02, 0x5a, 0xff, 0x3e, 0x94, 0x00, 0x03, 0x22, 0xff, 0xff, 0x25, 0x8f, 0x00, 0x03, 0x43, 0xff, 0xff, 0x04, 0x93, 0x00, 0x00, 0x36, 0x8a, 0xff, 0x00, 0x17, 0x93, 0x00, 0x00, 0x0a, 0x84, 0x17, 0x00, 0x05, 0x98, 0x00, 0x02, 0x66, 0xff, 0x82, 0x86, 0x00, 0x05, 0x22, 0xff, 0xff, 0x19, 0x00, 0x1b, 0x80, 0xff, 0x05, 0x00, 0x00, 0x3c, 0xff, 0xff, 0x06, 0x86, 0x00, 0x02, 0x92, 0xff, 0x5c, 0x8b, 0x00, 0x04, 0x22, 0xb5, 0xff, 0x91, 0x0f, 0x87, 0x00, 0x08, 0x09, 0x0f, 0x1a, 0x31, 0x70, 0xff, 0xff, 0x65, 0x01, 0x81, 0x00, 0x03, 0x01, 0x79, 0xff, 0x2b, 0x81, 0x00, 0x02, 0x63, 0xff, 0x89, 0x83, 0x00, 0x03, 0x1e, 0x2f, 0x2a, 0x01, 0x82, 0x00, 0x03, 0x29, 0xff, 0xff, 0x54, 0x81, 0x00, 0x03, 0xb1, 0xff, 0xff, 0x34, 0x82, 0x00, 0x03, 0x18, 0xe3, 0xff, 0x52, 0x86, 0x00, 0x03, 0x2b, 0xff, 0xff, 0x14, 0x85, 0x00, 0x0c, 0x07, 0x84, 0xff, 0x94, 0x2a, 0x09, 0x02, 0x0d, 0x36, 0xad, 0xff, 0x6b, 0x02, 0x81, 0x00, 0x0c, 0x10, 0xbf, 0xff, 0xbb, 0x34, 0x09, 0x05, 0x1a, 0x61, 0xea, 0x91, 0xff, 0x88, 0xa2, 0x00, 0x05, 0x36, 0xff, 0xea, 0x71, 0x26, 0x01, 0xa2, 0x00, 0x05, 0x05, 0x35, 0x8c, 0xff, 0xff, 0x17, 0x85, 0x00, 0x05, 0x04, 0x66, 0xff, 0xdd, 0x46, 0x01, 0x81, 0x00, 0x05, 0x27, 0xff, 0x36, 0x0b, 0xff, 0x7a, 0x81, 0x00, 0x06, 0x63, 0xff, 0x11, 0x00, 0x3f, 0xff, 0x14, 0x80, 0x00, 0x02, 0x6f, 0xff, 0x7e, 0x81, 0x00, 0x03, 0x02, 0xaf, 0xff, 0x4f, 0x82, 0x00, 0x02, 0x80, 0xff, 0x8f, 0x80, 0x04, 0x06, 0x06, 0x12, 0x26, 0x68, 0xff, 0xff, 0x43, 0x80, 0x00, 0x03, 0x38, 0xff, 0xff, 0x29, 0x8b, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x84, 0x00, 0x03, 0x25, 0xff, 0xff, 0x2a, 0x80, 0x00, 0x00, 0x80, 0x87, 0xff, 0x00, 0xc2, 0x82, 0x00, 0x00, 0x2d, 0x88, 0xff, 0x00, 0x45, 0x80, 0x00, 0x03, 0x38, 0xff, 0xff, 0x29, 0x80, 0x00, 0x00, 0x45, 0x83, 0xff, 0x00, 0x06, 0x80, 0x00, 0x02, 0x80, 0xff, 0x96, 0x83, 0x15, 0x03, 0x18, 0xff, 0xff, 0x53, 0x86, 0x00, 0x02, 0xb1, 0xff, 0x69, 0x8e, 0x00, 0x03, 0x0d, 0xff, 0xff, 0x43, 0x82, 0x00, 0x00, 0x80, 0x80, 0xff, 0x04, 0xa5, 0x99, 0xff, 0xe3, 0x22, 0x86, 0x00, 0x02, 0x7c, 0xff, 0x98, 0x89, 0x00, 0x0e, 0x1d, 0xff, 0xc2, 0x00, 0x00, 0x4d, 0xff, 0xa5, 0xff, 0x2f, 0x00, 0x17, 0xff, 0xff, 0x04, 0x80, 0x00, 0x0c, 0x80, 0xff, 0x4d, 0x00, 0x00, 0x52, 0xff, 0x7b, 0x00, 0x00, 0x80, 0xff, 0x53, 0x80, 0x00, 0x03, 0x54, 0xff, 0xff, 0x14, 0x84, 0x00, 0x03, 0x32, 0xff, 0xff, 0x2e, 0x80, 0x00, 0x00, 0x80, 0x86, 0xff, 0x01, 0xca, 0x32, 0x81, 0x00, 0x03, 0x56, 0xff, 0xff, 0x12, 0x84, 0x00, 0x03, 0x31, 0xff, 0xff, 0x31, 0x80, 0x00, 0x00, 0x80, 0x84, 0xff, 0x02, 0xab, 0x50, 0x17, 0x87, 0x00, 0x03, 0x15, 0x38, 0x65, 0xad, 0x80, 0xff, 0x01, 0x63, 0x05, 0x86, 0x00, 0x02, 0xaa, 0xff, 0x69, 0x85, 0x00, 0x03, 0x07, 0xff, 0xff, 0x4d, 0x84, 0x00, 0x02, 0x7c, 0xff, 0x8d, 0x82, 0x00, 0x03, 0x1b, 0xff, 0xff, 0x2c, 0x80, 0x00, 0x03, 0x49, 0xff, 0xc2, 0x06, 0x81, 0x00, 0x0e, 0x41, 0xff, 0x96, 0x00, 0x00, 0x9d, 0xd8, 0x1e, 0xff, 0x6f, 0x00, 0x02, 0xe3, 0xff, 0x23, 0x84, 0x00, 0x00, 0x5c, 0x80, 0xff, 0x00, 0x38, 0x89, 0x00, 0x04, 0x2d, 0xff, 0xff, 0xd1, 0x14, 0x88, 0x00, 0x04, 0x01, 0x73, 0xff, 0xb3, 0x10, 0x89, 0x00, 0x03, 0x34, 0xff, 0xff, 0x07, 0x8c, 0x00, 0x03, 0x08, 0xb5, 0xff, 0x3e, 0x8b, 0x00, 0x03, 0x26, 0xff, 0xff, 0x15, 0x84, 0x00, 0x03, 0x13, 0xff, 0xa0, 0x01, 0x82, 0x00, 0x03, 0x14, 0xff, 0xa5, 0x02, 0xa4, 0x00, 0x04, 0x05, 0x3a, 0x74, 0x9a, 0xc4, 0x82, 0xff, 0x00, 0x66, 0x82, 0x00, 0x03, 0x40, 0xff, 0xff, 0x05, 0x83, 0x00, 0x02, 0x68, 0xff, 0x96, 0x80, 0x00, 0x03, 0x12, 0xff, 0xff, 0x34, 0x8a, 0x00, 0x03, 0x07, 0xff, 0xff, 0x41, 0x83, 0x00, 0x03, 0x1e, 0xff, 0xff, 0x22, 0x80, 0x00, 0x00, 0x0f, 0x89, 0xff, 0x00, 0xa5, 0x84, 0x00, 0x02, 0x4b, 0xff, 0xb9, 0x88, 0x00, 0x02, 0xea, 0xff, 0x4b, 0x83, 0x00, 0x03, 0x17, 0xff, 0xff, 0x2a, 0x81, 0x00, 0x02, 0x40, 0xff, 0xe3, 0x83, 0x00, 0x03, 0x0f, 0xff, 0xff, 0x2d, 0x86, 0x00, 0x03, 0x24, 0xff, 0xff, 0x17, 0x8b, 0x00, 0x03, 0x04, 0xff, 0xff, 0x3b, 0x85, 0x00, 0x06, 0x7c, 0xff, 0x69, 0x5a, 0xff, 0xff, 0x22, 0x8b, 0x00, 0x03, 0x34, 0xff, 0xff, 0x07, 0x84, 0x00, 0x02, 0x50, 0xff, 0x7c, 0x80, 0x00, 0x02, 0x74, 0xff, 0x50, 0x80, 0x00, 0x02, 0xb1, 0xff, 0x31, 0x80, 0x00, 0x02, 0x40, 0xff, 0xe3, 0x83, 0x00, 0x03, 0x0f, 0xff, 0xff, 0x2d, 0x80, 0x00, 0x03, 0x14, 0xff, 0xff, 0x36, 0x84, 0x00, 0x02, 0x5d, 0xff, 0xb9, 0x81, 0x00, 0x03, 0x40, 0xff, 0xff, 0x07, 0x83, 0x00, 0x02, 0x66, 0xff, 0x98, 0x80, 0x00, 0x03, 0x07, 0xff, 0xff, 0x40, 0x83, 0x00, 0x03, 0x1e, 0xff, 0xff, 0x24, 0x83, 0x00, 0x02, 0xdd, 0xff, 0x63, 0x8a, 0x00, 0x01, 0x1e, 0xbb, 0x80, 0xff, 0x03, 0x92, 0x54, 0x28, 0x04, 0x86, 0x00, 0x03, 0x0d, 0xff, 0xff, 0x2f, 0x88, 0x00, 0x02, 0x40, 0xff, 0xdd, 0x83, 0x00, 0x03, 0x0f, 0xff, 0xff, 0x2d, 0x82, 0x00, 0x03, 0x45, 0xff, 0xff, 0x12, 0x80, 0x00, 0x03, 0x37, 0xff, 0xff, 0x1b, 0x81, 0x00, 0x0e, 0x5d, 0xff, 0x6d, 0x00, 0x00, 0x67, 0xff, 0x4d, 0xff, 0x3c, 0x00, 0x00, 0xbd, 0xff, 0x34, 0x84, 0x00, 0x00, 0x5f, 0x80, 0xff, 0x00, 0x29, 0x86, 0x00, 0x03, 0x28, 0xff, 0xff, 0x1a, 0x80, 0x00, 0x03, 0x25, 0xff, 0xff, 0x17, 0x87, 0x00, 0x03, 0x43, 0xff, 0xd8, 0x21, 0x87, 0x00, 0x04, 0x0d, 0x50, 0xff, 0xff, 0x3b, 0x8c, 0x00, 0x02, 0x74, 0xff, 0x4b, 0x8c, 0x00, 0x04, 0x5e, 0xff, 0xc7, 0x39, 0x06, 0x82, 0x00, 0x00, 0x13, 0x83, 0x00, 0x06, 0x0b, 0x43, 0x8a, 0xcd, 0xbf, 0x71, 0x1d, 0x86, 0x00, 0x05, 0x04, 0x66, 0xff, 0xdd, 0x46, 0x01, 0x99, 0x00, 0x02, 0x66, 0xff, 0x42, 0x95, 0x00, 0x05, 0x04, 0x11, 0x11, 0x1c, 0xff, 0x45, 0x81, 0x11, 0x01, 0x68, 0xa6, 0x80, 0x11, 0x00, 0x06, 0x85, 0x00, 0x08, 0x31, 0xff, 0x31, 0x0a, 0x3f, 0xb3, 0xff, 0xab, 0x06, 0x84, 0x00, 0x13, 0x61, 0xff, 0x2c, 0x33, 0xff, 0x9f, 0x37, 0x3d, 0xbf, 0xd8, 0x16, 0x00, 0x66, 0xff, 0x78, 0x02, 0x01, 0x80, 0xff, 0x51, 0x80, 0x00, 0x02, 0xa2, 0xff, 0x19, 0x94, 0x00, 0x03, 0x28, 0xff, 0xff, 0x1f, 0x8f, 0x00, 0x03, 0x3c, 0xff, 0xff, 0x09, 0x99, 0x00, 0x02, 0x59, 0xff, 0x34, 0x99, 0x00, 0x00, 0x3b, 0x84, 0xff, 0x00, 0x1b, 0x97, 0x00, 0x03, 0x1d, 0xff, 0xff, 0x1e, 0x86, 0x00, 0x03, 0x1b, 0xff, 0xff, 0x1e, 0x84, 0x00, 0x02, 0x43, 0xff, 0xdd, 0x87, 0x00, 0x02, 0x92, 0xff, 0x5c, 0x8a, 0x00, 0x04, 0x3a, 0xdd, 0xff, 0x79, 0x08, 0x8d, 0x00, 0x03, 0x2d, 0xea, 0xff, 0x40, 0x81, 0x00, 0x02, 0x43, 0xff, 0x58, 0x82, 0x00, 0x02, 0x63, 0xff, 0x89, 0x8d, 0x00, 0x02, 0x7e, 0xff, 0xa0, 0x81, 0x00, 0x02, 0x9f, 0xff, 0xa2, 0x84, 0x00, 0x02, 0x70, 0xff, 0x94, 0x86, 0x00, 0x02, 0x79, 0xff, 0x79, 0x86, 0x00, 0x03, 0x58, 0xff, 0xa5, 0x09, 0x82, 0x00, 0x03, 0x15, 0xd8, 0xff, 0x40, 0x82, 0x00, 0x01, 0x24, 0xc2, 0x82, 0xff, 0x04, 0xe3, 0x3f, 0x61, 0xff, 0x78, 0xa2, 0x00, 0x07, 0x0f, 0x57, 0xc2, 0xff, 0xff, 0x9a, 0x3d, 0x08, 0x87, 0x00, 0x8a, 0x02, 0x87, 0x00, 0x07, 0x10, 0x4d, 0xb7, 0xff, 0xff, 0xa8, 0x47, 0x06, 0x85, 0x00, 0x03, 0x6f, 0xff, 0xb1, 0x1e, 0x83, 0x00, 0x05, 0x2e, 0xff, 0x2f, 0x15, 0xff, 0x67, 0x81, 0x00, 0x0c, 0x9d, 0xbb, 0x00, 0x00, 0x50, 0xff, 0x06, 0x00, 0x00, 0x0d, 0xe3, 0xff, 0x3b, 0x82, 0x04, 0x03, 0x58, 0xff, 0xad, 0x02, 0x81, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x84, 0x00, 0x09, 0x47, 0xff, 0xff, 0x1d, 0x00, 0x00, 0x30, 0xff, 0xff, 0x31, 0x8b, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x84, 0x00, 0x03, 0x2f, 0xff, 0xff, 0x21, 0x80, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x8b, 0x00, 0x00, 0x2d, 0x88, 0xff, 0x00, 0x45, 0x80, 0x00, 0x03, 0x2f, 0xff, 0xff, 0x31, 0x80, 0x00, 0x00, 0x0a, 0x80, 0x15, 0x03, 0x52, 0xff, 0xff, 0x06, 0x80, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x83, 0x00, 0x03, 0x04, 0xff, 0xff, 0x53, 0x86, 0x00, 0x02, 0xb1, 0xff, 0x69, 0x8e, 0x00, 0x03, 0x0d, 0xff, 0xff, 0x43, 0x82, 0x00, 0x09, 0x80, 0xff, 0xff, 0xa6, 0x12, 0x17, 0xc7, 0xff, 0xaf, 0x0d, 0x85, 0x00, 0x02, 0x7c, 0xff, 0x98, 0x89, 0x00, 0x0e, 0x1d, 0xff, 0xc2, 0x00, 0x00, 0x13, 0xff, 0xff, 0xbb, 0x04, 0x00, 0x17, 0xff, 0xff, 0x04, 0x80, 0x00, 0x0c, 0x80, 0xff, 0x4d, 0x00, 0x00, 0x0e, 0xd4, 0xff, 0x1e, 0x00, 0x80, 0xff, 0x53, 0x80, 0x00, 0x03, 0x49, 0xff, 0xff, 0x1a, 0x84, 0x00, 0x03, 0x3a, 0xff, 0xff, 0x26, 0x80, 0x00, 0x00, 0x80, 0x83, 0xff, 0x03, 0xb9, 0x88, 0x4b, 0x0e, 0x82, 0x00, 0x03, 0x50, 0xff, 0xff, 0x16, 0x84, 0x00, 0x03, 0x36, 0xff, 0xff, 0x2b, 0x80, 0x00, 0x02, 0x80, 0xff, 0x90, 0x80, 0x07, 0x03, 0x61, 0xff, 0xc7, 0x12, 0x8b, 0x00, 0x05, 0x01, 0x22, 0x6f, 0xff, 0xff, 0x65, 0x86, 0x00, 0x02, 0xaa, 0xff, 0x69, 0x85, 0x00, 0x03, 0x07, 0xff, 0xff, 0x4d, 0x84, 0x00, 0x02, 0x7c, 0xff, 0x8d, 0x83, 0x00, 0x02, 0x8d, 0xff, 0x6e, 0x80, 0x00, 0x02, 0x9f, 0xff, 0x5c, 0x82, 0x00, 0x0e, 0x28, 0xff, 0xd4, 0x01, 0x13, 0xff, 0x7f, 0x01, 0xbf, 0xc7, 0x04, 0x11, 0xff, 0xff, 0x0e, 0x83, 0x00, 0x06, 0x29, 0xff, 0xff, 0x72, 0xff, 0xc7, 0x13, 0x89, 0x00, 0x02, 0xa8, 0xff, 0x6c, 0x89, 0x00, 0x03, 0x4d, 0xff, 0xe3, 0x23, 0x8a, 0x00, 0x03, 0x34, 0xff, 0xff, 0x07, 0x8d, 0x00, 0x03, 0x3b, 0xff, 0xb9, 0x09, 0x8a, 0x00, 0x03, 0x26, 0xff, 0xff, 0x15, 0x84, 0x00, 0x02, 0x52, 0xff, 0x44, 0x84, 0x00, 0x02, 0x79, 0xff, 0x2a, 0xa3, 0x00, 0x0b, 0x0e, 0x94, 0xff, 0xff, 0xc2, 0x80, 0x6f, 0x6d, 0x6d, 0xbb, 0xff, 0x66, 0x82, 0x00, 0x02, 0x40, 0xff, 0xea, 0x84, 0x00, 0x02, 0x61, 0xff, 0xa3, 0x80, 0x00, 0x03, 0x19, 0xff, 0xff, 0x30, 0x8a, 0x00, 0x03, 0x0c, 0xff, 0xff, 0x3c, 0x83, 0x00, 0x03, 0x1b, 0xff, 0xff, 0x22, 0x80, 0x00, 0x03, 0x15, 0xff, 0xff, 0xb7, 0x86, 0xa3, 0x00, 0x91, 0x84, 0x00, 0x02, 0x4b, 0xff, 0xb9, 0x87, 0x00, 0x03, 0x04, 0xff, 0xff, 0x47, 0x83, 0x00, 0x03, 0x11, 0xff, 0xff, 0x2a, 0x81, 0x00, 0x02, 0x40, 0xff, 0xdd, 0x83, 0x00, 0x03, 0x0f, 0xff, 0xff, 0x2d, 0x86, 0x00, 0x03, 0x24, 0xff, 0xff, 0x17, 0x8b, 0x00, 0x03, 0x04, 0xff, 0xff, 0x3b, 0x85, 0x00, 0x02, 0x7c, 0xff, 0xca, 0x80, 0xff, 0x01, 0x87, 0x03, 0x8a, 0x00, 0x03, 0x34, 0xff, 0xff, 0x07, 0x84, 0x00, 0x02, 0x50, 0xff, 0x78, 0x80, 0x00, 0x02, 0x74, 0xff, 0x50, 0x80, 0x00, 0x02, 0xb1, 0xff, 0x31, 0x80, 0x00, 0x02, 0x40, 0xff, 0xdd, 0x83, 0x00, 0x03, 0x0f, 0xff, 0xff, 0x2d, 0x80, 0x00, 0x03, 0x19, 0xff, 0xff, 0x31, 0x84, 0x00, 0x02, 0x55, 0xff, 0xd8, 0x81, 0x00, 0x03, 0x40, 0xff, 0xff, 0x01, 0x83, 0x00, 0x02, 0x61, 0xff, 0xa3, 0x80, 0x00, 0x03, 0x0c, 0xff, 0xff, 0x3c, 0x83, 0x00, 0x03, 0x1b, 0xff, 0xff, 0x24, 0x83, 0x00, 0x02, 0xdd, 0xff, 0x49, 0x8b, 0x00, 0x02, 0x0a, 0x47, 0x9a, 0x81, 0xff, 0x02, 0xb1, 0x48, 0x04, 0x84, 0x00, 0x03, 0x0d, 0xff, 0xff, 0x2f, 0x88, 0x00, 0x02, 0x40, 0xff, 0xdd, 0x83, 0x00, 0x03, 0x0f, 0xff, 0xff, 0x2d, 0x82, 0x00, 0x03, 0x0e, 0xe3, 0xff, 0x49, 0x80, 0x00, 0x02, 0x83, 0xff, 0x88, 0x82, 0x00, 0x0e, 0x3f, 0xff, 0x96, 0x00, 0x04, 0xc2, 0xa2, 0x0e, 0xff, 0x76, 0x00, 0x0e, 0xff, 0xff, 0x1b, 0x84, 0x00, 0x04, 0x21, 0xff, 0xff, 0xad, 0x06, 0x86, 0x00, 0x03, 0x01, 0x9a, 0xff, 0x5b, 0x80, 0x00, 0x02, 0x68, 0xff, 0x7e, 0x87, 0x00, 0x03, 0x29, 0xea, 0xff, 0x37, 0x87, 0x00, 0x04, 0x91, 0xff, 0xff, 0x98, 0x30, 0x8d, 0x00, 0x02, 0x74, 0xff, 0x4b, 0x8c, 0x00, 0x05, 0x01, 0x46, 0xb1, 0xff, 0xff, 0x5f, 0x98, 0x00, 0x03, 0x6f, 0xff, 0xb1, 0x1e, 0x9b, 0x00, 0x02, 0x61, 0xff, 0x3e, 0x95, 0x00, 0x00, 0x22, 0x8b, 0xff, 0x00, 0x2f, 0x85, 0x00, 0x08, 0x31, 0xff, 0x31, 0x00, 0x00, 0x17, 0xc7, 0xff, 0x3d, 0x83, 0x00, 0x19, 0x2e, 0xff, 0x5d, 0x00, 0x85, 0xff, 0x1f, 0x00, 0x00, 0x3f, 0xff, 0x51, 0x13, 0xff, 0xff, 0x19, 0x00, 0x00, 0x13, 0xca, 0xea, 0x26, 0x00, 0x1e, 0xff, 0x9a, 0x95, 0x00, 0x03, 0x28, 0xff, 0xff, 0x1f, 0x8f, 0x00, 0x03, 0x3c, 0xff, 0xff, 0x08, 0x99, 0x00, 0x02, 0x59, 0xff, 0x34, 0x99, 0x00, 0x00, 0x3b, 0x84, 0xff, 0x00, 0x1b, 0x97, 0x00, 0x02, 0x81, 0xff, 0x67, 0x87, 0x00, 0x03, 0x10, 0xff, 0xff, 0x2e, 0x84, 0x00, 0x02, 0x58, 0xff, 0xa6, 0x87, 0x00, 0x02, 0x92, 0xff, 0x5c, 0x88, 0x00, 0x05, 0x03, 0x5b, 0xff, 0xff, 0x50, 0x02, 0x8f, 0x00, 0x02, 0x6f, 0xff, 0x9f, 0x80, 0x00, 0x03, 0x1c, 0xdd, 0x90, 0x05, 0x82, 0x00, 0x02, 0x63, 0xff, 0x89, 0x8d, 0x00, 0x03, 0x50, 0xff, 0xe3, 0x01, 0x80, 0x00, 0x02, 0x82, 0xff, 0x81, 0x84, 0x00, 0x02, 0x4d, 0xff, 0xc2, 0x85, 0x00, 0x03, 0x12, 0xff, 0xff, 0x30, 0x85, 0x00, 0x03, 0x06, 0xd8, 0xff, 0x4a, 0x84, 0x00, 0x02, 0x77, 0xff, 0x89, 0x83, 0x00, 0x0a, 0x0e, 0x50, 0x8b, 0xab, 0x8f, 0x59, 0x19, 0x00, 0x82, 0xff, 0x58, 0xa4, 0x00, 0x07, 0x07, 0x3b, 0x94, 0xff, 0xff, 0xc4, 0x57, 0x16, 0x84, 0x00, 0x00, 0x36, 0x8a, 0xff, 0x00, 0x17, 0x84, 0x00, 0x07, 0x23, 0x6c, 0xe3, 0xff, 0xff, 0x7b, 0x2d, 0x02, 0x86, 0x00, 0x03, 0x2a, 0xff, 0xea, 0x1f, 0x84, 0x00, 0x05, 0x31, 0xff, 0x2d, 0x17, 0xff, 0x62, 0x80, 0x00, 0x06, 0x0d, 0xff, 0x7c, 0x00, 0x00, 0x6f, 0xa2, 0x80, 0x00, 0x00, 0x43, 0x88, 0xff, 0x00, 0x29, 0x81, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x84, 0x00, 0x09, 0x05, 0xd4, 0xff, 0x57, 0x00, 0x00, 0x1d, 0xff, 0xff, 0x45, 0x8b, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x84, 0x00, 0x03, 0x4a, 0xff, 0xff, 0x0d, 0x80, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x8b, 0x00, 0x03, 0x2d, 0xff, 0xff, 0x22, 0x89, 0x00, 0x03, 0x1b, 0xff, 0xff, 0x48, 0x84, 0x00, 0x03, 0x43, 0xff, 0xff, 0x06, 0x80, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x83, 0x00, 0x03, 0x04, 0xff, 0xff, 0x53, 0x86, 0x00, 0x02, 0xb1, 0xff, 0x69, 0x8e, 0x00, 0x03, 0x0d, 0xff, 0xff, 0x43, 0x82, 0x00, 0x0a, 0x80, 0xff, 0xb9, 0x13, 0x00, 0x00, 0x30, 0xff, 0xff, 0x7e, 0x02, 0x84, 0x00, 0x02, 0x7c, 0xff, 0x98, 0x89, 0x00, 0x02, 0x1d, 0xff, 0xc2, 0x80, 0x00, 0x08, 0x7b, 0xff, 0x57, 0x00, 0x00, 0x17, 0xff, 0xff, 0x04, 0x80, 0x00, 0x02, 0x80, 0xff, 0x4d, 0x80, 0x00, 0x06, 0x5d, 0xff, 0x6f, 0x00, 0x7f, 0xff, 0x53, 0x80, 0x00, 0x03, 0x36, 0xff, 0xff, 0x2c, 0x84, 0x00, 0x03, 0x50, 0xff, 0xff, 0x15, 0x80, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x8a, 0x00, 0x03, 0x44, 0xff, 0xff, 0x20, 0x84, 0x00, 0x03, 0x41, 0xff, 0xff, 0x22, 0x80, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x80, 0x00, 0x04, 0x0a, 0xb5, 0xff, 0x7b, 0x01, 0x8d, 0x00, 0x03, 0x5d, 0xff, 0xff, 0x16, 0x85, 0x00, 0x02, 0xaa, 0xff, 0x69, 0x85, 0x00, 0x03, 0x06, 0xff, 0xff, 0x50, 0x84, 0x00, 0x02, 0x82, 0xff, 0x89, 0x83, 0x00, 0x08, 0x3d, 0xff, 0xd8, 0x0a, 0x00, 0x1f, 0xff, 0xff, 0x1e, 0x82, 0x00, 0x0d, 0x13, 0xff, 0xff, 0x0e, 0x3a, 0xff, 0x4b, 0x00, 0x6f, 0xff, 0x20, 0x20, 0xff, 0xc2, 0x83, 0x00, 0x08, 0x0b, 0xaf, 0xff, 0x5d, 0x03, 0x8b, 0xff, 0x82, 0x02, 0x88, 0x00, 0x02, 0xa3, 0xff, 0x69, 0x88, 0x00, 0x03, 0x2e, 0xff, 0xff, 0x3f, 0x8b, 0x00, 0x03, 0x34, 0xff, 0xff, 0x07, 0x8d, 0x00, 0x03, 0x02, 0x96, 0xff, 0x54, 0x8a, 0x00, 0x03, 0x26, 0xff, 0xff, 0x15, 0x83, 0x00, 0x03, 0x05, 0xb9, 0xdd, 0x0d, 0x84, 0x00, 0x02, 0x2d, 0xff, 0x76, 0xa3, 0x00, 0x04, 0x75, 0xff, 0xdd, 0x35, 0x04, 0x81, 0x00, 0x02, 0x89, 0xff, 0x66, 0x82, 0x00, 0x03, 0x40, 0xff, 0xff, 0x02, 0x83, 0x00, 0x02, 0x68, 0xff, 0x95, 0x80, 0x00, 0x03, 0x14, 0xff, 0xff, 0x35, 0x8a, 0x00, 0x03, 0x08, 0xff, 0xff, 0x40, 0x83, 0x00, 0x03, 0x20, 0xff, 0xff, 0x22, 0x80, 0x00, 0x03, 0x0e, 0xff, 0xff, 0x3b, 0x8e, 0x00, 0x02, 0x4b, 0xff, 0xb9, 0x87, 0x00, 0x03, 0x01, 0xff, 0xff, 0x4a, 0x83, 0x00, 0x03, 0x16, 0xff, 0xff, 0x2a, 0x81, 0x00, 0x02, 0x40, 0xff, 0xdd, 0x83, 0x00, 0x03, 0x0f, 0xff, 0xff, 0x2d, 0x86, 0x00, 0x03, 0x24, 0xff, 0xff, 0x17, 0x8b, 0x00, 0x03, 0x04, 0xff, 0xff, 0x3b, 0x85, 0x00, 0x07, 0x7c, 0xff, 0xff, 0x84, 0x2d, 0xd8, 0xff, 0x52, 0x8a, 0x00, 0x03, 0x34, 0xff, 0xff, 0x07, 0x84, 0x00, 0x02, 0x50, 0xff, 0x78, 0x80, 0x00, 0x02, 0x74, 0xff, 0x50, 0x80, 0x00, 0x02, 0xb1, 0xff, 0x31, 0x80, 0x00, 0x02, 0x40, 0xff, 0xdd, 0x83, 0x00, 0x03, 0x0f, 0xff, 0xff, 0x2d, 0x80, 0x00, 0x03, 0x13, 0xff, 0xff, 0x36, 0x84, 0x00, 0x02, 0x5d, 0xff, 0xb5, 0x81, 0x00, 0x03, 0x40, 0xff, 0xff, 0x04, 0x83, 0x00, 0x02, 0x67, 0xff, 0x96, 0x80, 0x00, 0x03, 0x08, 0xff, 0xff, 0x41, 0x83, 0x00, 0x03, 0x22, 0xff, 0xff, 0x24, 0x83, 0x00, 0x02, 0xdd, 0xff, 0x43, 0x8e, 0x00, 0x07, 0x13, 0x37, 0x64, 0xc2, 0xff, 0xff, 0x77, 0x01, 0x83, 0x00, 0x03, 0x0d, 0xff, 0xff, 0x2f, 0x88, 0x00, 0x02, 0x40, 0xff, 0xdd, 0x83, 0x00, 0x03, 0x10, 0xff, 0xff, 0x2d, 0x83, 0x00, 0x08, 0x6e, 0xff, 0xa2, 0x01, 0x00, 0x16, 0xff, 0xff, 0x36, 0x82, 0x00, 0x0e, 0x25, 0xff, 0xdd, 0x02, 0x26, 0xff, 0x56, 0x00, 0x8a, 0xd8, 0x07, 0x23, 0xff, 0xea, 0x06, 0x83, 0x00, 0x05, 0x07, 0x9c, 0xff, 0xd8, 0xff, 0x63, 0x87, 0x00, 0x08, 0x3d, 0xff, 0xc7, 0x08, 0x00, 0x0b, 0xd8, 0xff, 0x2f, 0x86, 0x00, 0x03, 0x17, 0xc2, 0xff, 0x55, 0x88, 0x00, 0x04, 0xa3, 0xff, 0xff, 0x83, 0x26, 0x8d, 0x00, 0x02, 0x74, 0xff, 0x4b, 0x8d, 0x00, 0x04, 0x39, 0x9c, 0xff, 0xff, 0x69, 0x97, 0x00, 0x03, 0x2a, 0xff, 0xea, 0x1f, 0x9c, 0x00, 0x02, 0x56, 0xc2, 0x37, 0x95, 0x00, 0x04, 0x0a, 0x2a, 0x2a, 0x70, 0xbb, 0x81, 0x2a, 0x02, 0x36, 0xff, 0x58, 0x80, 0x2a, 0x05, 0x0e, 0x00, 0x00, 0x02, 0x19, 0x0c, 0x80, 0x00, 0x02, 0x31, 0xff, 0x31, 0x80, 0x00, 0x02, 0x6c, 0xff, 0x65, 0x82, 0x00, 0x0f, 0x0f, 0xb9, 0x99, 0x06, 0x00, 0xd1, 0xff, 0x04, 0x00, 0x00, 0x1e, 0xff, 0x78, 0x2f, 0xff, 0xc4, 0x81, 0x00, 0x06, 0x34, 0xff, 0xb9, 0x16, 0x61, 0xff, 0x43, 0x95, 0x00, 0x03, 0x22, 0xff, 0xff, 0x25, 0x8f, 0x00, 0x03, 0x43, 0xff, 0xff, 0x04, 0x99, 0x00, 0x02, 0x59, 0xff, 0x34, 0xbb, 0x00, 0x03, 0x2e, 0xff, 0xd4, 0x11, 0x88, 0x00, 0x02, 0xbb, 0xff, 0x49, 0x84, 0x00, 0x02, 0x80, 0xff, 0x6c, 0x87, 0x00, 0x02, 0x92, 0xff, 0x5c, 0x87, 0x00, 0x04, 0x06, 0x77, 0xff, 0xc4, 0x2b, 0x86, 0x00, 0x03, 0x09, 0x37, 0x46, 0x1a, 0x84, 0x00, 0x06, 0x4f, 0xff, 0xff, 0x01, 0x00, 0x00, 0x55, 0x8a, 0xff, 0x00, 0x31, 0x8a, 0x00, 0x02, 0x56, 0xff, 0xc7, 0x81, 0x00, 0x02, 0x59, 0xff, 0xa2, 0x84, 0x00, 0x02, 0x50, 0xff, 0xb3, 0x85, 0x00, 0x03, 0x42, 0xff, 0xd8, 0x07, 0x85, 0x00, 0x03, 0x14, 0xff, 0xff, 0x35, 0x84, 0x00, 0x02, 0x5e, 0xff, 0xb5, 0x8a, 0x00, 0x03, 0x06, 0xcd, 0xff, 0x35, 0xa7, 0x00, 0x07, 0x23, 0x6a, 0xe3, 0xff, 0xff, 0x78, 0x2a, 0x01, 0x81, 0x00, 0x00, 0x36, 0x8a, 0xff, 0x00, 0x17, 0x81, 0x00, 0x07, 0x06, 0x38, 0x92, 0xff, 0xff, 0xc2, 0x57, 0x16, 0x89, 0x00, 0x02, 0x5c, 0xff, 0x77, 0x85, 0x00, 0x05, 0x29, 0xff, 0x34, 0x0d, 0xff, 0x6e, 0x80, 0x00, 0x06, 0x3a, 0xff, 0x5a, 0x00, 0x01, 0xb9, 0x61, 0x80, 0x00, 0x00, 0x99, 0x88, 0xff, 0x00, 0x6c, 0x81, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x85, 0x00, 0x08, 0xad, 0xff, 0x71, 0x00, 0x00, 0x06, 0xd8, 0xff, 0x74, 0x85, 0x00, 0x02, 0x3f, 0x26, 0x01, 0x80, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x84, 0x00, 0x02, 0x8b, 0xff, 0xa0, 0x81, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x8b, 0x00, 0x03, 0x2d, 0xff, 0xff, 0x22, 0x89, 0x00, 0x03, 0x05, 0xd1, 0xff, 0x78, 0x84, 0x00, 0x03, 0x43, 0xff, 0xff, 0x06, 0x80, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x83, 0x00, 0x03, 0x04, 0xff, 0xff, 0x53, 0x86, 0x00, 0x02, 0xb1, 0xff, 0x69, 0x87, 0x00, 0x01, 0x09, 0x1d, 0x82, 0x00, 0x03, 0x11, 0xff, 0xff, 0x3f, 0x82, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x81, 0x00, 0x03, 0x54, 0xff, 0xff, 0x50, 0x84, 0x00, 0x02, 0x7c, 0xff, 0x98, 0x89, 0x00, 0x02, 0x1d, 0xff, 0xc2, 0x80, 0x00, 0x08, 0x08, 0x0f, 0x06, 0x00, 0x00, 0x17, 0xff, 0xff, 0x04, 0x80, 0x00, 0x02, 0x80, 0xff, 0x4d, 0x80, 0x00, 0x06, 0x14, 0xea, 0xff, 0x17, 0x7a, 0xff, 0x53, 0x80, 0x00, 0x03, 0x1b, 0xff, 0xff, 0x50, 0x84, 0x00, 0x03, 0x7d, 0xff, 0xc4, 0x01, 0x80, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x8a, 0x00, 0x03, 0x2d, 0xff, 0xff, 0x35, 0x84, 0x00, 0x03, 0x5a, 0xff, 0xff, 0x0f, 0x80, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x81, 0x00, 0x03, 0x33, 0xff, 0xff, 0x3b, 0x83, 0x00, 0x01, 0x01, 0x0a, 0x85, 0x00, 0x03, 0x1b, 0xff, 0xff, 0x32, 0x85, 0x00, 0x02, 0xaa, 0xff, 0x69, 0x85, 0x00, 0x03, 0x01, 0xea, 0xff, 0x5a, 0x84, 0x00, 0x02, 0x98, 0xff, 0x79, 0x83, 0x00, 0x07, 0x0a, 0xd4, 0xff, 0x37, 0x00, 0x57, 0xff, 0x96, 0x83, 0x00, 0x0d, 0x02, 0xd4, 0xff, 0x1b, 0x69, 0xff, 0x22, 0x00, 0x3b, 0xff, 0x47, 0x30, 0xff, 0x84, 0x83, 0x00, 0x08, 0x6b, 0xff, 0xa5, 0x07, 0x00, 0x18, 0xd8, 0xff, 0x45, 0x88, 0x00, 0x02, 0xa3, 0xff, 0x69, 0x87, 0x00, 0x03, 0x18, 0xc7, 0xff, 0x63, 0x8c, 0x00, 0x03, 0x34, 0xff, 0xff, 0x07, 0x8e, 0x00, 0x03, 0x29, 0xff, 0xd8, 0x14, 0x89, 0x00, 0x03, 0x26, 0xff, 0xff, 0x15, 0xb6, 0x00, 0x03, 0x0c, 0xff, 0xff, 0x55, 0x83, 0x00, 0x02, 0xa0, 0xff, 0x66, 0x82, 0x00, 0x03, 0x40, 0xff, 0xff, 0x0c, 0x83, 0x00, 0x02, 0x80, 0xff, 0x7c, 0x80, 0x00, 0x03, 0x06, 0xea, 0xff, 0x49, 0x8a, 0x00, 0x03, 0x01, 0xd4, 0xff, 0x50, 0x83, 0x00, 0x03, 0x32, 0xff, 0xff, 0x22, 0x80, 0x00, 0x03, 0x03, 0xd1, 0xff, 0x50, 0x8e, 0x00, 0x02, 0x4b, 0xff, 0xb9, 0x88, 0x00, 0x02, 0xbb, 0xff, 0x58, 0x83, 0x00, 0x03, 0x28, 0xff, 0xff, 0x2a, 0x81, 0x00, 0x02, 0x40, 0xff, 0xdd, 0x83, 0x00, 0x03, 0x0f, 0xff, 0xff, 0x2d, 0x86, 0x00, 0x03, 0x24, 0xff, 0xff, 0x17, 0x8b, 0x00, 0x03, 0x04, 0xff, 0xff, 0x3b, 0x85, 0x00, 0x08, 0x7c, 0xff, 0x81, 0x03, 0x00, 0x41, 0xff, 0xff, 0x28, 0x89, 0x00, 0x03, 0x34, 0xff, 0xff, 0x07, 0x84, 0x00, 0x02, 0x50, 0xff, 0x78, 0x80, 0x00, 0x02, 0x74, 0xff, 0x50, 0x80, 0x00, 0x02, 0xb1, 0xff, 0x31, 0x80, 0x00, 0x02, 0x40, 0xff, 0xdd, 0x83, 0x00, 0x03, 0x0f, 0xff, 0xff, 0x2d, 0x80, 0x00, 0x03, 0x06, 0xea, 0xff, 0x49, 0x84, 0x00, 0x02, 0x76, 0xff, 0x8b, 0x81, 0x00, 0x03, 0x40, 0xff, 0xff, 0x0e, 0x83, 0x00, 0x02, 0x7c, 0xff, 0x7b, 0x80, 0x00, 0x03, 0x01, 0xd4, 0xff, 0x52, 0x83, 0x00, 0x03, 0x35, 0xff, 0xff, 0x24, 0x83, 0x00, 0x02, 0xdd, 0xff, 0x43, 0x91, 0x00, 0x04, 0x05, 0x4e, 0xff, 0xff, 0x27, 0x83, 0x00, 0x03, 0x0d, 0xff, 0xff, 0x2f, 0x88, 0x00, 0x02, 0x3f, 0xff, 0xe3, 0x83, 0x00, 0x03, 0x19, 0xff, 0xff, 0x2d, 0x83, 0x00, 0x08, 0x28, 0xff, 0xff, 0x22, 0x00, 0x50, 0xff, 0xbf, 0x06, 0x82, 0x00, 0x0d, 0x0f, 0xff, 0xff, 0x0f, 0x5a, 0xff, 0x24, 0x00, 0x49, 0xff, 0x2d, 0x36, 0xff, 0x9c, 0x84, 0x00, 0x06, 0x65, 0xff, 0x92, 0x1e, 0xd4, 0xff, 0x35, 0x86, 0x00, 0x08, 0x07, 0xc2, 0xff, 0x3a, 0x00, 0x41, 0xff, 0xad, 0x03, 0x85, 0x00, 0x04, 0x0b, 0x9f, 0xff, 0x75, 0x02, 0x88, 0x00, 0x05, 0x06, 0x1d, 0x68, 0xff, 0xff, 0x34, 0x8c, 0x00, 0x02, 0x74, 0xff, 0x4b, 0x8c, 0x00, 0x05, 0x58, 0xff, 0xdd, 0x4f, 0x16, 0x04, 0x97, 0x00, 0x02, 0x5c, 0xff, 0x77, 0xbb, 0x00, 0x01, 0x79, 0x77, 0x81, 0x00, 0x02, 0x25, 0xff, 0x1d, 0x82, 0x00, 0x03, 0x02, 0xb3, 0xff, 0x49, 0x80, 0x00, 0x02, 0x31, 0xff, 0x31, 0x80, 0x00, 0x02, 0x67, 0xff, 0x68, 0x81, 0x00, 0x07, 0x01, 0x7a, 0xdd, 0x1c, 0x00, 0x02, 0xff, 0xe3, 0x80, 0x00, 0x05, 0x18, 0xff, 0x83, 0x31, 0xff, 0xc4, 0x82, 0x00, 0x05, 0x50, 0xff, 0xa6, 0xd1, 0xc4, 0x0a, 0x95, 0x00, 0x03, 0x16, 0xff, 0xff, 0x32, 0x8f, 0x00, 0x02, 0x54, 0xff, 0xbd, 0x9a, 0x00, 0x02, 0x59, 0xff, 0x34, 0xac, 0x00, 0x00, 0x02, 0x80, 0x09, 0x87, 0x00, 0x03, 0x04, 0x9f, 0xff, 0x50, 0x89, 0x00, 0x02, 0x6c, 0xff, 0x8c, 0x83, 0x00, 0x03, 0x0c, 0xe3, 0xff, 0x3b, 0x87, 0x00, 0x02, 0x92, 0xff, 0x5c, 0x86, 0x00, 0x04, 0x06, 0x7d, 0xff, 0xaa, 0x1a, 0x87, 0x00, 0x03, 0x0a, 0xea, 0xff, 0x55, 0x84, 0x00, 0x02, 0x65, 0xff, 0xb7, 0x80, 0x00, 0x00, 0x4f, 0x85, 0xb9, 0x0b, 0xd4, 0xff, 0xe3, 0xb9, 0xb9, 0x2e, 0x00, 0x00, 0x0c, 0x5b, 0x75, 0x2a, 0x84, 0x00, 0x02, 0x8f, 0xff, 0x83, 0x81, 0x00, 0x03, 0x2b, 0xff, 0xff, 0x1b, 0x83, 0x00, 0x02, 0x7e, 0xff, 0x7e, 0x85, 0x00, 0x02, 0x80, 0xff, 0x7a, 0x86, 0x00, 0x03, 0x0c, 0xff, 0xff, 0x48, 0x84, 0x00, 0x02, 0x76, 0xff, 0x99, 0x82, 0x00, 0x01, 0x02, 0x0b, 0x83, 0x00, 0x03, 0x36, 0xff, 0xdd, 0x0b, 0x85, 0x00, 0x00, 0x02, 0x80, 0x09, 0x8b, 0x00, 0x03, 0x2f, 0x34, 0x34, 0x20, 0x8b, 0x00, 0x07, 0x0f, 0x4a, 0xad, 0xff, 0xff, 0xa2, 0x41, 0x05, 0x90, 0x00, 0x07, 0x0d, 0x52, 0xbd, 0xff, 0xff, 0x94, 0x3a, 0x07, 0x8b, 0x00, 0x02, 0x15, 0x1d, 0x12, 0x85, 0x00, 0x15, 0x1f, 0xff, 0x42, 0x01, 0xad, 0xa3, 0x00, 0x00, 0x05, 0x99, 0xc2, 0x4a, 0x00, 0x28, 0xff, 0x26, 0x00, 0x00, 0x20, 0xff, 0xff, 0x2f, 0x84, 0x00, 0x03, 0x50, 0xff, 0xd8, 0x0b, 0x80, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x84, 0x00, 0x03, 0x07, 0xdd, 0xff, 0x62, 0x80, 0x00, 0x03, 0x6d, 0xff, 0xd8, 0x10, 0x83, 0x00, 0x03, 0x19, 0xea, 0xff, 0x33, 0x80, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x83, 0x00, 0x03, 0x24, 0xff, 0xff, 0x49, 0x81, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x8b, 0x00, 0x03, 0x2d, 0xff, 0xff, 0x22, 0x8a, 0x00, 0x03, 0x69, 0xff, 0xdd, 0x12, 0x83, 0x00, 0x03, 0x43, 0xff, 0xff, 0x06, 0x80, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x83, 0x00, 0x03, 0x04, 0xff, 0xff, 0x53, 0x86, 0x00, 0x02, 0xb1, 0xff, 0x69, 0x86, 0x00, 0x03, 0x3f, 0xff, 0xff, 0x18, 0x81, 0x00, 0x03, 0x20, 0xff, 0xff, 0x30, 0x82, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x81, 0x00, 0x04, 0x03, 0x7f, 0xff, 0xff, 0x2a, 0x83, 0x00, 0x02, 0x7c, 0xff, 0x98, 0x89, 0x00, 0x02, 0x1d, 0xff, 0xc2, 0x85, 0x00, 0x03, 0x17, 0xff, 0xff, 0x04, 0x80, 0x00, 0x02, 0x80, 0xff, 0x4d, 0x81, 0x00, 0x05, 0x68, 0xff, 0x64, 0x6c, 0xff, 0x53, 0x80, 0x00, 0x04, 0x01, 0xab, 0xff, 0xa2, 0x02, 0x82, 0x00, 0x03, 0x0e, 0xdd, 0xff, 0x65, 0x81, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x8a, 0x00, 0x03, 0x12, 0xff, 0xff, 0x5f, 0x84, 0x00, 0x02, 0x92, 0xff, 0xa6, 0x81, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x82, 0x00, 0x03, 0x79, 0xff, 0xc4, 0x11, 0x81, 0x00, 0x02, 0x60, 0xc2, 0x99, 0x85, 0x00, 0x03, 0x1d, 0xff, 0xff, 0x30, 0x85, 0x00, 0x02, 0xaa, 0xff, 0x69, 0x86, 0x00, 0x02, 0xa3, 0xff, 0x7e, 0x83, 0x00, 0x03, 0x07, 0xdd, 0xff, 0x5b, 0x84, 0x00, 0x06, 0x68, 0xff, 0x74, 0x01, 0xad, 0xff, 0x41, 0x84, 0x00, 0x0c, 0x8f, 0xff, 0x29, 0xb1, 0xc4, 0x03, 0x00, 0x14, 0xff, 0x7b, 0x40, 0xff, 0x5f, 0x82, 0x00, 0x03, 0x34, 0xff, 0xff, 0x26, 0x80, 0x00, 0x03, 0x46, 0xff, 0xd8, 0x1a, 0x87, 0x00, 0x02, 0xa3, 0xff, 0x69, 0x86, 0x00, 0x04, 0x09, 0x9d, 0xff, 0x8b, 0x05, 0x8c, 0x00, 0x03, 0x34, 0xff, 0xff, 0x07, 0x8f, 0x00, 0x02, 0x7b, 0xff, 0x6d, 0x89, 0x00, 0x03, 0x26, 0xff, 0xff, 0x15, 0xb6, 0x00, 0x03, 0x1b, 0xff, 0xff, 0x30, 0x82, 0x00, 0x03, 0x12, 0xff, 0xff, 0x66, 0x82, 0x00, 0x03, 0x40, 0xff, 0xff, 0x27, 0x82, 0x00, 0x03, 0x02, 0xbf, 0xff, 0x57, 0x81, 0x00, 0x02, 0x8c, 0xff, 0x7b, 0x84, 0x00, 0x02, 0x5c, 0x66, 0x3e, 0x81, 0x00, 0x02, 0x8f, 0xff, 0x78, 0x83, 0x00, 0x03, 0x5b, 0xff, 0xff, 0x22, 0x81, 0x00, 0x02, 0x7e, 0xff, 0x8f, 0x84, 0x00, 0x00, 0x02, 0x86, 0x00, 0x02, 0x4b, 0xff, 0xb9, 0x88, 0x00, 0x02, 0x84, 0xff, 0x7c, 0x83, 0x00, 0x03, 0x53, 0xff, 0xff, 0x2a, 0x81, 0x00, 0x02, 0x40, 0xff, 0xdd, 0x83, 0x00, 0x03, 0x0f, 0xff, 0xff, 0x2d, 0x86, 0x00, 0x03, 0x24, 0xff, 0xff, 0x17, 0x8b, 0x00, 0x03, 0x04, 0xff, 0xff, 0x3b, 0x85, 0x00, 0x09, 0x7c, 0xff, 0x69, 0x00, 0x00, 0x01, 0x76, 0xff, 0xb5, 0x0e, 0x88, 0x00, 0x03, 0x34, 0xff, 0xff, 0x07, 0x84, 0x00, 0x02, 0x50, 0xff, 0x78, 0x80, 0x00, 0x02, 0x74, 0xff, 0x50, 0x80, 0x00, 0x02, 0xb1, 0xff, 0x31, 0x80, 0x00, 0x02, 0x40, 0xff, 0xdd, 0x83, 0x00, 0x03, 0x0f, 0xff, 0xff, 0x2d, 0x81, 0x00, 0x02, 0x8d, 0xff, 0x7c, 0x83, 0x00, 0x03, 0x04, 0xbd, 0xff, 0x55, 0x81, 0x00, 0x03, 0x40, 0xff, 0xff, 0x29, 0x82, 0x00, 0x03, 0x01, 0xb9, 0xff, 0x58, 0x81, 0x00, 0x02, 0x8d, 0xff, 0x7c, 0x83, 0x00, 0x03, 0x60, 0xff, 0xff, 0x24, 0x83, 0x00, 0x02, 0xdd, 0xff, 0x43, 0x93, 0x00, 0x02, 0xa0, 0xff, 0x3f, 0x83, 0x00, 0x03, 0x0d, 0xff, 0xff, 0x2f, 0x88, 0x00, 0x03, 0x3a, 0xff, 0xff, 0x06, 0x82, 0x00, 0x03, 0x3a, 0xff, 0xff, 0x2d, 0x83, 0x00, 0x07, 0x02, 0xa8, 0xff, 0x55, 0x01, 0xaa, 0xff, 0x57, 0x84, 0x00, 0x0c, 0xc2, 0xff, 0x1e, 0xad, 0xbb, 0x03, 0x00, 0x1c, 0xff, 0x5d, 0x4d, 0xff, 0x6c, 0x83, 0x00, 0x08, 0x36, 0xff, 0xd1, 0x18, 0x00, 0x3f, 0xff, 0xca, 0x16, 0x86, 0x00, 0x06, 0x55, 0xff, 0x8f, 0x01, 0x9c, 0xff, 0x4b, 0x85, 0x00, 0x04, 0x03, 0x7d, 0xff, 0x96, 0x08, 0x8c, 0x00, 0x03, 0x63, 0xff, 0xbd, 0x06, 0x8b, 0x00, 0x02, 0x74, 0xff, 0x4b, 0x8b, 0x00, 0x03, 0x1a, 0xff, 0xff, 0x39, 0x9a, 0x00, 0x02, 0x15, 0x1d, 0x12, 0xbb, 0x00, 0x01, 0xbd, 0x4d, 0x81, 0x00, 0x02, 0x45, 0xd8, 0x04, 0x83, 0x00, 0x0e, 0x61, 0xff, 0xb7, 0x0f, 0x00, 0x00, 0x31, 0xff, 0x31, 0x00, 0x00, 0x0e, 0xb9, 0xff, 0x46, 0x81, 0x00, 0x02, 0x41, 0xff, 0x45, 0x80, 0x00, 0x0b, 0xbf, 0xff, 0x06, 0x00, 0x00, 0x20, 0xff, 0x71, 0x1b, 0xff, 0xff, 0x1d, 0x81, 0x00, 0x04, 0x01, 0x6f, 0xff, 0xff, 0x58, 0x96, 0x00, 0x03, 0x06, 0xea, 0xff, 0x48, 0x8f, 0x00, 0x02, 0x70, 0xff, 0x8b, 0x9a, 0x00, 0x02, 0x59, 0xff, 0x34, 0x89, 0x00, 0x00, 0x22, 0x80, 0xff, 0x00, 0x1d, 0x9b, 0x00, 0x00, 0x1b, 0x80, 0xff, 0x87, 0x00, 0x03, 0x41, 0xff, 0xb5, 0x08, 0x89, 0x00, 0x03, 0x28, 0xff, 0xff, 0x2b, 0x82, 0x00, 0x03, 0x5b, 0xff, 0xca, 0x09, 0x87, 0x00, 0x02, 0x92, 0xff, 0x5c, 0x85, 0x00, 0x04, 0x02, 0x77, 0xff, 0xa6, 0x10, 0x89, 0x00, 0x03, 0x7c, 0xff, 0xc7, 0x14, 0x82, 0x00, 0x03, 0x12, 0xca, 0xff, 0x69, 0x89, 0x00, 0x02, 0x63, 0xff, 0x89, 0x82, 0x00, 0x04, 0x02, 0xad, 0xff, 0x90, 0x06, 0x82, 0x00, 0x03, 0x32, 0xff, 0xff, 0x3d, 0x81, 0x00, 0x04, 0x04, 0xab, 0xff, 0x79, 0x01, 0x81, 0x00, 0x03, 0x20, 0xff, 0xff, 0x3f, 0x84, 0x00, 0x03, 0x04, 0xd8, 0xff, 0x4c, 0x87, 0x00, 0x03, 0x98, 0xff, 0x91, 0x03, 0x82, 0x00, 0x03, 0x0d, 0xca, 0xff, 0x5b, 0x81, 0x00, 0x03, 0x40, 0xdd, 0xb9, 0x09, 0x81, 0x00, 0x03, 0x0d, 0xaa, 0xff, 0x64, 0x86, 0x00, 0x00, 0x1b, 0x80, 0xff, 0x8a, 0x00, 0x00, 0x0d, 0x80, 0xff, 0x00, 0x2a, 0x8d, 0x00, 0x05, 0x03, 0x30, 0x80, 0xff, 0xff, 0x17, 0x90, 0x00, 0x04, 0x36, 0xff, 0xdd, 0x6a, 0x22, 0x99, 0x00, 0x0e, 0x0a, 0xff, 0x60, 0x00, 0x55, 0xff, 0x3d, 0x15, 0x70, 0x59, 0x8b, 0x6d, 0x1a, 0x9a, 0x80, 0x80, 0x00, 0x03, 0x60, 0xff, 0xbd, 0x05, 0x84, 0x00, 0x03, 0x17, 0xff, 0xff, 0x3f, 0x80, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x84, 0x00, 0x03, 0x49, 0xff, 0xff, 0x35, 0x80, 0x00, 0x04, 0x20, 0xff, 0xff, 0x73, 0x02, 0x81, 0x00, 0x04, 0x0b, 0x9a, 0xff, 0x9a, 0x02, 0x80, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x82, 0x00, 0x04, 0x14, 0xa6, 0xff, 0xb7, 0x0c, 0x81, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x8b, 0x00, 0x03, 0x2d, 0xff, 0xff, 0x22, 0x8a, 0x00, 0x04, 0x1e, 0xff, 0xff, 0x78, 0x03, 0x82, 0x00, 0x03, 0x45, 0xff, 0xff, 0x06, 0x80, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x83, 0x00, 0x03, 0x04, 0xff, 0xff, 0x53, 0x86, 0x00, 0x02, 0xb1, 0xff, 0x69, 0x86, 0x00, 0x03, 0x19, 0xff, 0xff, 0x5c, 0x81, 0x00, 0x03, 0x58, 0xff, 0xff, 0x11, 0x82, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x82, 0x00, 0x04, 0x0d, 0xab, 0xff, 0xbd, 0x12, 0x82, 0x00, 0x02, 0x7c, 0xff, 0x98, 0x89, 0x00, 0x02, 0x1d, 0xff, 0xc2, 0x85, 0x00, 0x03, 0x17, 0xff, 0xff, 0x04, 0x80, 0x00, 0x02, 0x80, 0xff, 0x4d, 0x81, 0x00, 0x05, 0x1b, 0xff, 0xe3, 0x79, 0xff, 0x53, 0x81, 0x00, 0x03, 0x49, 0xff, 0xff, 0x46, 0x82, 0x00, 0x03, 0x64, 0xff, 0xff, 0x20, 0x81, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x8b, 0x00, 0x03, 0x90, 0xff, 0xbf, 0x07, 0x82, 0x00, 0x03, 0x19, 0xff, 0xff, 0x55, 0x81, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x82, 0x00, 0x03, 0x13, 0xcd, 0xff, 0x79, 0x81, 0x00, 0x03, 0x48, 0xff, 0xff, 0x3d, 0x84, 0x00, 0x03, 0x60, 0xff, 0xff, 0x14, 0x85, 0x00, 0x02, 0xaa, 0xff, 0x69, 0x86, 0x00, 0x03, 0x62, 0xff, 0xe3, 0x15, 0x82, 0x00, 0x03, 0x3f, 0xff, 0xff, 0x30, 0x84, 0x00, 0x06, 0x26, 0xff, 0xd8, 0x24, 0xff, 0xdd, 0x0c, 0x84, 0x00, 0x04, 0x66, 0xff, 0x55, 0xff, 0x6e, 0x80, 0x00, 0x04, 0xa2, 0xd1, 0x57, 0xff, 0x41, 0x81, 0x00, 0x03, 0x10, 0xbf, 0xff, 0x5d, 0x81, 0x00, 0x04, 0x02, 0x89, 0xff, 0x92, 0x05, 0x86, 0x00, 0x02, 0xa3, 0xff, 0x69, 0x85, 0x00, 0x04, 0x02, 0x76, 0xff, 0xb5, 0x10, 0x8d, 0x00, 0x03, 0x34, 0xff, 0xff, 0x07, 0x8f, 0x00, 0x03, 0x1a, 0xea, 0xff, 0x21, 0x88, 0x00, 0x03, 0x26, 0xff, 0xff, 0x15, 0xb6, 0x00, 0x03, 0x17, 0xff, 0xff, 0x39, 0x82, 0x00, 0x03, 0x67, 0xff, 0xff, 0x6b, 0x82, 0x00, 0x03, 0x40, 0xff, 0xff, 0x6d, 0x82, 0x00, 0x03, 0x2b, 0xff, 0xff, 0x28, 0x81, 0x00, 0x03, 0x3f, 0xff, 0xff, 0x1d, 0x82, 0x00, 0x03, 0x24, 0xff, 0xff, 0x3a, 0x81, 0x00, 0x03, 0x52, 0xff, 0xdd, 0x10, 0x81, 0x00, 0x04, 0x0c, 0xc2, 0xff, 0xff, 0x22, 0x81, 0x00, 0x03, 0x34, 0xff, 0xff, 0x2c, 0x82, 0x00, 0x03, 0x06, 0x9d, 0x7e, 0x1f, 0x84, 0x00, 0x02, 0x4b, 0xff, 0xb9, 0x88, 0x00, 0x03, 0x4f, 0xff, 0xd8, 0x0d, 0x81, 0x00, 0x04, 0x0d, 0xbd, 0xff, 0xff, 0x2a, 0x81, 0x00, 0x02, 0x40, 0xff, 0xdd, 0x83, 0x00, 0x03, 0x0f, 0xff, 0xff, 0x2d, 0x86, 0x00, 0x03, 0x24, 0xff, 0xff, 0x17, 0x8b, 0x00, 0x03, 0x04, 0xff, 0xff, 0x3b, 0x85, 0x00, 0x02, 0x7c, 0xff, 0x69, 0x80, 0x00, 0x04, 0x0d, 0xb1, 0xff, 0x7d, 0x02, 0x87, 0x00, 0x03, 0x34, 0xff, 0xff, 0x07, 0x84, 0x00, 0x02, 0x50, 0xff, 0x78, 0x80, 0x00, 0x02, 0x74, 0xff, 0x50, 0x80, 0x00, 0x02, 0xb1, 0xff, 0x31, 0x80, 0x00, 0x02, 0x40, 0xff, 0xdd, 0x83, 0x00, 0x03, 0x0f, 0xff, 0xff, 0x2d, 0x81, 0x00, 0x03, 0x3f, 0xff, 0xff, 0x1b, 0x82, 0x00, 0x03, 0x38, 0xff, 0xff, 0x1c, 0x81, 0x00, 0x03, 0x40, 0xff, 0xff, 0x70, 0x82, 0x00, 0x03, 0x28, 0xff, 0xff, 0x2b, 0x81, 0x00, 0x03, 0x50, 0xff, 0xe3, 0x13, 0x81, 0x00, 0x04, 0x0f, 0xc7, 0xff, 0xff, 0x24, 0x83, 0x00, 0x02, 0xdd, 0xff, 0x43, 0x89, 0x00, 0x02, 0x37, 0x8d, 0x5c, 0x83, 0x00, 0x03, 0x01, 0xab, 0xff, 0x32, 0x83, 0x00, 0x03, 0x0a, 0xff, 0xff, 0x40, 0x88, 0x00, 0x03, 0x2a, 0xff, 0xff, 0x22, 0x81, 0x00, 0x04, 0x04, 0x96, 0xff, 0xff, 0x2d, 0x84, 0x00, 0x06, 0x49, 0xff, 0x9d, 0x1d, 0xff, 0xff, 0x18, 0x84, 0x00, 0x0c, 0x82, 0xff, 0x49, 0xff, 0x63, 0x00, 0x00, 0x01, 0xad, 0xa6, 0x63, 0xff, 0x49, 0x82, 0x00, 0x0a, 0x16, 0xca, 0xff, 0x3d, 0x00, 0x00, 0x01, 0x75, 0xff, 0x91, 0x05, 0x85, 0x00, 0x06, 0x14, 0xff, 0xff, 0x45, 0xff, 0xe3, 0x0f, 0x85, 0x00, 0x03, 0x5c, 0xff, 0xb9, 0x13, 0x8d, 0x00, 0x03, 0x1b, 0xff, 0xff, 0x1b, 0x8b, 0x00, 0x02, 0x74, 0xff, 0x4b, 0x8b, 0x00, 0x03, 0x39, 0xff, 0xd4, 0x02, 0xbd, 0x00, 0x02, 0x6c, 0x74, 0x46, 0x97, 0x00, 0x02, 0x13, 0xff, 0x2d, 0x81, 0x00, 0x01, 0x6d, 0x88, 0x84, 0x00, 0x0e, 0x11, 0xbf, 0xff, 0xa0, 0x2c, 0x02, 0x31, 0xff, 0x31, 0x03, 0x28, 0x95, 0xff, 0xc4, 0x0e, 0x80, 0x00, 0x03, 0x19, 0xd4, 0x7e, 0x01, 0x80, 0x00, 0x0c, 0x73, 0xff, 0x28, 0x00, 0x00, 0x4b, 0xff, 0x45, 0x01, 0x8c, 0xff, 0x94, 0x15, 0x80, 0x00, 0x08, 0x1a, 0x94, 0xff, 0xff, 0xc4, 0x31, 0x02, 0x00, 0x02, 0x93, 0x00, 0x02, 0x92, 0xff, 0x71, 0x8f, 0x00, 0x02, 0xb3, 0xff, 0x5c, 0x9a, 0x00, 0x02, 0x59, 0xff, 0x34, 0x89, 0x00, 0x03, 0x4a, 0xff, 0xff, 0x7a, 0x9c, 0x00, 0x00, 0x1b, 0x80, 0xff, 0x86, 0x00, 0x03, 0x0a, 0xbd, 0xff, 0x3c, 0x8b, 0x00, 0x0a, 0x76, 0xff, 0xc4, 0x3c, 0x0c, 0x02, 0x13, 0x57, 0xff, 0xff, 0x3f, 0x88, 0x00, 0x02, 0x92, 0xff, 0x5c, 0x85, 0x00, 0x03, 0x45, 0xff, 0xff, 0x1f, 0x8a, 0x00, 0x0c, 0x1f, 0xdd, 0xff, 0xb1, 0x3a, 0x0d, 0x05, 0x12, 0x39, 0xab, 0xff, 0xe3, 0x1b, 0x89, 0x00, 0x02, 0x63, 0xff, 0x89, 0x83, 0x00, 0x0c, 0x38, 0xff, 0xff, 0x88, 0x25, 0x06, 0x02, 0x13, 0x58, 0xea, 0xff, 0x8d, 0x05, 0x82, 0x00, 0x0b, 0x2f, 0xff, 0xff, 0x6f, 0x17, 0x01, 0x07, 0x3a, 0xc7, 0xff, 0xa0, 0x06, 0x84, 0x00, 0x03, 0x1a, 0xff, 0xff, 0x2e, 0x87, 0x00, 0x04, 0x30, 0xff, 0xff, 0x6f, 0x12, 0x80, 0x00, 0x04, 0x1a, 0x8a, 0xff, 0xca, 0x14, 0x81, 0x00, 0x0b, 0x11, 0xd4, 0xff, 0x85, 0x1d, 0x03, 0x04, 0x29, 0x9d, 0xff, 0xb5, 0x0e, 0x86, 0x00, 0x00, 0x1b, 0x80, 0xff, 0x8a, 0x00, 0x04, 0x30, 0xff, 0xff, 0x91, 0x01, 0x90, 0x00, 0x02, 0x19, 0x5b, 0x14, 0x90, 0x00, 0x02, 0x2b, 0x4a, 0x0f, 0x90, 0x00, 0x02, 0x5f, 0x74, 0x54, 0x86, 0x00, 0x13, 0xa3, 0xa2, 0x00, 0x0b, 0x91, 0xff, 0xff, 0x6f, 0x05, 0x41, 0xff, 0xff, 0x8d, 0x0d, 0x00, 0x00, 0x07, 0xca, 0xff, 0x5a, 0x86, 0x00, 0x02, 0x87, 0xff, 0x91, 0x80, 0x00, 0x02, 0x80, 0xff, 0x91, 0x80, 0x09, 0x07, 0x0a, 0x14, 0x29, 0x6d, 0xff, 0xff, 0x92, 0x05, 0x81, 0x00, 0x0b, 0x56, 0xff, 0xff, 0x85, 0x2d, 0x13, 0x13, 0x35, 0xaf, 0xff, 0xc4, 0x1a, 0x81, 0x00, 0x0b, 0x80, 0xff, 0x94, 0x0f, 0x0f, 0x14, 0x23, 0x52, 0xca, 0xff, 0xe3, 0x2a, 0x82, 0x00, 0x02, 0x80, 0xff, 0x94, 0x87, 0x0f, 0x00, 0x05, 0x80, 0x00, 0x03, 0x2d, 0xff, 0xff, 0x22, 0x8b, 0x00, 0x0c, 0x56, 0xff, 0xff, 0x88, 0x2d, 0x13, 0x13, 0x27, 0x5b, 0xd4, 0xff, 0xff, 0x05, 0x80, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x83, 0x00, 0x03, 0x04, 0xff, 0xff, 0x53, 0x81, 0x00, 0x00, 0x03, 0x81, 0x0f, 0x02, 0xb5, 0xff, 0x72, 0x81, 0x0f, 0x83, 0x00, 0x09, 0x78, 0xff, 0xff, 0x56, 0x19, 0x18, 0x4b, 0xea, 0xff, 0x6f, 0x83, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x83, 0x00, 0x04, 0x20, 0xdd, 0xff, 0x8b, 0x05, 0x81, 0x00, 0x02, 0x7c, 0xff, 0x9d, 0x86, 0x0f, 0x80, 0x00, 0x02, 0x1d, 0xff, 0xc2, 0x85, 0x00, 0x03, 0x17, 0xff, 0xff, 0x04, 0x80, 0x00, 0x02, 0x80, 0xff, 0x4d, 0x82, 0x00, 0x04, 0x76, 0xff, 0xea, 0xff, 0x53, 0x81, 0x00, 0x0b, 0x06, 0x9c, 0xff, 0xff, 0x5b, 0x1c, 0x11, 0x22, 0x6e, 0xff, 0xff, 0x61, 0x82, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x8b, 0x00, 0x03, 0x35, 0xff, 0xff, 0x5c, 0x81, 0x00, 0x04, 0x03, 0x7b, 0xff, 0xdd, 0x13, 0x81, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x83, 0x00, 0x03, 0x45, 0xff, 0xff, 0x3a, 0x80, 0x00, 0x0d, 0x08, 0x9f, 0xff, 0xea, 0x5b, 0x1e, 0x08, 0x04, 0x0e, 0x28, 0x72, 0xff, 0xff, 0x68, 0x86, 0x00, 0x02, 0xaa, 0xff, 0x69, 0x86, 0x00, 0x0c, 0x1c, 0xea, 0xff, 0xa2, 0x31, 0x14, 0x0f, 0x1c, 0x4d, 0xe3, 0xff, 0xa0, 0x04, 0x84, 0x00, 0x05, 0x01, 0xa6, 0xff, 0x8d, 0xff, 0x6e, 0x85, 0x00, 0x04, 0x47, 0xff, 0xa8, 0xff, 0x3a, 0x80, 0x00, 0x04, 0x5a, 0xff, 0xa6, 0xff, 0x29, 0x80, 0x00, 0x04, 0x01, 0x7b, 0xff, 0xa5, 0x07, 0x82, 0x00, 0x03, 0x17, 0xd4, 0xff, 0x53, 0x86, 0x00, 0x02, 0xa3, 0xff, 0x69, 0x85, 0x00, 0x03, 0x50, 0xff, 0xff, 0x35, 0x87, 0x0f, 0x00, 0x0c, 0x83, 0x00, 0x03, 0x34, 0xff, 0xff, 0x07, 0x90, 0x00, 0x03, 0x60, 0xff, 0x8a, 0x01, 0x87, 0x00, 0x03, 0x26, 0xff, 0xff, 0x15, 0xb6, 0x00, 0x0d, 0x02, 0xb5, 0xff, 0x8c, 0x07, 0x00, 0x00, 0x07, 0x5e, 0x8f, 0x6c, 0xff, 0x98, 0x01, 0x81, 0x00, 0x0c, 0x41, 0xff, 0xd1, 0xb5, 0x49, 0x04, 0x00, 0x00, 0x1b, 0xab, 0xff, 0x94, 0x02, 0x81, 0x00, 0x0c, 0x04, 0x95, 0xff, 0xad, 0x2a, 0x03, 0x00, 0x03, 0x2e, 0xb5, 0xff, 0x98, 0x05, 0x81, 0x00, 0x0c, 0x15, 0xe3, 0xff, 0x89, 0x15, 0x00, 0x00, 0x1b, 0x8c, 0x81, 0xff, 0xff, 0x22, 0x81, 0x00, 0x0c, 0x03, 0x87, 0xff, 0xc7, 0x32, 0x02, 0x00, 0x00, 0x1e, 0x87, 0xff, 0xbd, 0x0b, 0x84, 0x00, 0x02, 0x4b, 0xff, 0xb9, 0x88, 0x00, 0x0c, 0x16, 0xea, 0xff, 0x79, 0x0c, 0x00, 0x00, 0x16, 0x8d, 0x79, 0xff, 0xff, 0x2a, 0x81, 0x00, 0x02, 0x40, 0xff, 0xdd, 0x83, 0x00, 0x03, 0x0f, 0xff, 0xff, 0x2d, 0x86, 0x00, 0x03, 0x24, 0xff, 0xff, 0x17, 0x8b, 0x00, 0x03, 0x04, 0xff, 0xff, 0x3b, 0x85, 0x00, 0x02, 0x7c, 0xff, 0x69, 0x81, 0x00, 0x03, 0x28, 0xff, 0xff, 0x49, 0x87, 0x00, 0x03, 0x34, 0xff, 0xff, 0x07, 0x84, 0x00, 0x02, 0x50, 0xff, 0x78, 0x80, 0x00, 0x02, 0x74, 0xff, 0x50, 0x80, 0x00, 0x02, 0xb1, 0xff, 0x31, 0x80, 0x00, 0x02, 0x40, 0xff, 0xdd, 0x83, 0x00, 0x03, 0x0f, 0xff, 0xff, 0x2d, 0x81, 0x00, 0x0b, 0x06, 0x98, 0xff, 0xa2, 0x1c, 0x00, 0x00, 0x01, 0x2f, 0xc7, 0xff, 0x67, 0x82, 0x00, 0x0c, 0x40, 0xff, 0xd8, 0xaf, 0x4d, 0x05, 0x00, 0x00, 0x18, 0xa3, 0xff, 0x9d, 0x03, 0x81, 0x00, 0x0c, 0x14, 0xdd, 0xff, 0x91, 0x17, 0x00, 0x00, 0x1a, 0x8f, 0x7f, 0xff, 0xff, 0x24, 0x83, 0x00, 0x02, 0xdd, 0xff, 0x43, 0x89, 0x00, 0x04, 0x26, 0xff, 0xe3, 0x3f, 0x05, 0x80, 0x00, 0x04, 0x0d, 0x62, 0xff, 0xbb, 0x09, 0x84, 0x00, 0x08, 0xaf, 0xff, 0xa8, 0x23, 0x08, 0x06, 0x0f, 0x1f, 0x31, 0x82, 0x00, 0x0c, 0x0b, 0xd8, 0xff, 0x8a, 0x11, 0x00, 0x00, 0x15, 0x78, 0x79, 0xff, 0xff, 0x2d, 0x84, 0x00, 0x05, 0x10, 0xea, 0xff, 0x69, 0xff, 0x82, 0x85, 0x00, 0x04, 0x5b, 0xff, 0x98, 0xff, 0x2d, 0x80, 0x00, 0x04, 0x5c, 0xff, 0x9d, 0xff, 0x2e, 0x81, 0x00, 0x03, 0x05, 0x90, 0xff, 0x71, 0x81, 0x00, 0x03, 0x0d, 0xb3, 0xff, 0x5d, 0x86, 0x00, 0x04, 0x74, 0xff, 0xdd, 0xff, 0x6d, 0x85, 0x00, 0x03, 0x3e, 0xff, 0xdd, 0x24, 0x8e, 0x00, 0x03, 0x11, 0xff, 0xff, 0x1f, 0x8b, 0x00, 0x02, 0x74, 0xff, 0x4b, 0x8b, 0x00, 0x02, 0x3d, 0xff, 0xb1, 0x9b, 0x00, 0x02, 0x5f, 0x74, 0x54, 0x9d, 0x00, 0x02, 0xc2, 0xff, 0x69, 0x97, 0x00, 0x02, 0x2e, 0xff, 0x11, 0x81, 0x00, 0x01, 0xab, 0x57, 0x85, 0x00, 0x0c, 0x20, 0xb3, 0xff, 0xff, 0xcd, 0xb7, 0xff, 0xbd, 0xe3, 0xff, 0xff, 0xb7, 0x23, 0x80, 0x00, 0x03, 0x05, 0x94, 0xbd, 0x10, 0x81, 0x00, 0x18, 0x20, 0xea, 0xab, 0x3e, 0x49, 0xd4, 0xb3, 0x0c, 0x00, 0x15, 0xaa, 0xff, 0xd8, 0x7d, 0x6b, 0x8c, 0xff, 0xff, 0x60, 0x68, 0xff, 0xff, 0xc4, 0xc2, 0x19, 0x93, 0x00, 0x03, 0x55, 0xff, 0xbf, 0x03, 0x8d, 0x00, 0x03, 0x17, 0xff, 0xff, 0x32, 0xa9, 0x00, 0x03, 0x81, 0xff, 0xff, 0x24, 0x9c, 0x00, 0x00, 0x1b, 0x80, 0xff, 0x86, 0x00, 0x03, 0x57, 0xff, 0x98, 0x03, 0x8b, 0x00, 0x01, 0x0a, 0x87, 0x84, 0xff, 0x01, 0x55, 0x01, 0x82, 0x00, 0x00, 0x8f, 0x82, 0xcd, 0x02, 0xea, 0xff, 0xe3, 0x81, 0xcd, 0x06, 0x3b, 0x00, 0x00, 0x02, 0xc7, 0xff, 0xff, 0x86, 0xdd, 0x00, 0x89, 0x82, 0x00, 0x01, 0x2f, 0xc7, 0x84, 0xff, 0x01, 0xc7, 0x30, 0x8a, 0x00, 0x02, 0x63, 0xff, 0x89, 0x84, 0x00, 0x01, 0x4b, 0xea, 0x84, 0xff, 0x01, 0x82, 0x0d, 0x84, 0x00, 0x04, 0x41, 0xe3, 0xff, 0xff, 0xe3, 0x80, 0xff, 0x01, 0xa2, 0x17, 0x85, 0x00, 0x03, 0x2a, 0xff, 0xff, 0x1f, 0x88, 0x00, 0x0a, 0x43, 0xdd, 0xff, 0xff, 0xa8, 0x92, 0xb1, 0xff, 0xff, 0xbb, 0x26, 0x83, 0x00, 0x04, 0x34, 0xe3, 0xff, 0xff, 0xea, 0x80, 0xff, 0x01, 0xa8, 0x19, 0x87, 0x00, 0x00, 0x1b, 0x80, 0xff, 0x8a, 0x00, 0x03, 0x5b, 0xff, 0xff, 0x31, 0xbd, 0x00, 0x02, 0x9d, 0xff, 0x84, 0x86, 0x00, 0x06, 0x53, 0xff, 0x1d, 0x00, 0x02, 0x1c, 0x14, 0x80, 0x00, 0x02, 0x16, 0x1a, 0x02, 0x80, 0x00, 0x03, 0x38, 0xff, 0xff, 0x1e, 0x86, 0x00, 0x06, 0x39, 0xff, 0xff, 0x1c, 0x00, 0x00, 0x80, 0x87, 0xff, 0x01, 0x85, 0x0f, 0x82, 0x00, 0x02, 0x01, 0x55, 0xea, 0x83, 0xff, 0x01, 0xbb, 0x24, 0x82, 0x00, 0x00, 0x80, 0x85, 0xff, 0x01, 0xb1, 0x28, 0x83, 0x00, 0x00, 0x80, 0x89, 0xff, 0x00, 0x2d, 0x80, 0x00, 0x03, 0x2d, 0xff, 0xff, 0x22, 0x8b, 0x00, 0x01, 0x01, 0x5a, 0x85, 0xff, 0x01, 0x88, 0x21, 0x81, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x83, 0x00, 0x03, 0x04, 0xff, 0xff, 0x53, 0x81, 0x00, 0x00, 0x1d, 0x88, 0xff, 0x00, 0x02, 0x82, 0x00, 0x01, 0x10, 0xa2, 0x83, 0xff, 0x01, 0x99, 0x0d, 0x83, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x84, 0x00, 0x03, 0x3e, 0xff, 0xff, 0x5c, 0x81, 0x00, 0x00, 0x7c, 0x88, 0xff, 0x05, 0x06, 0x00, 0x00, 0x1d, 0xff, 0xc2, 0x85, 0x00, 0x03, 0x17, 0xff, 0xff, 0x04, 0x80, 0x00, 0x02, 0x80, 0xff, 0x4d, 0x82, 0x00, 0x00, 0x22, 0x80, 0xff, 0x00, 0x53, 0x82, 0x00, 0x01, 0x11, 0x96, 0x84, 0xff, 0x01, 0x6a, 0x04, 0x82, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x8b, 0x00, 0x0b, 0x02, 0x7c, 0xff, 0xff, 0x6f, 0x26, 0x19, 0x2d, 0x82, 0xff, 0xff, 0x47, 0x82, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x83, 0x00, 0x04, 0x03, 0x91, 0xff, 0xc4, 0x10, 0x80, 0x00, 0x01, 0x12, 0x90, 0x86, 0xff, 0x01, 0x6c, 0x06, 0x86, 0x00, 0x02, 0xaa, 0xff, 0x69, 0x87, 0x00, 0x01, 0x3f, 0xea, 0x84, 0xff, 0x01, 0xad, 0x1a, 0x86, 0x00, 0x00, 0x4b, 0x80, 0xff, 0x00, 0x2a, 0x85, 0x00, 0x00, 0x2e, 0x80, 0xff, 0x00, 0x12, 0x80, 0x00, 0x00, 0x2b, 0x80, 0xff, 0x00, 0x13, 0x80, 0x00, 0x03, 0x3f, 0xff, 0xff, 0x26, 0x84, 0x00, 0x03, 0x44, 0xff, 0xea, 0x23, 0x85, 0x00, 0x02, 0xa3, 0xff, 0x69, 0x85, 0x00, 0x8b, 0xff, 0x00, 0x84, 0x83, 0x00, 0x03, 0x34, 0xff, 0xff, 0x07, 0x90, 0x00, 0x03, 0x0f, 0xca, 0xff, 0x34, 0x87, 0x00, 0x03, 0x26, 0xff, 0xff, 0x15, 0xb7, 0x00, 0x0d, 0x38, 0xff, 0xff, 0xad, 0x6c, 0x74, 0xc7, 0xa2, 0x13, 0x38, 0xff, 0xff, 0x87, 0x55, 0x80, 0x00, 0x0b, 0x44, 0xff, 0xb1, 0x2a, 0xd8, 0xc4, 0x8c, 0x9a, 0xff, 0xff, 0xbf, 0x1a, 0x83, 0x00, 0x0a, 0x0f, 0x91, 0xff, 0xff, 0xd4, 0xad, 0xe3, 0xff, 0xff, 0x94, 0x11, 0x83, 0x00, 0x00, 0x42, 0x80, 0xff, 0x07, 0xb3, 0xbd, 0xff, 0x99, 0x1a, 0xff, 0xff, 0x22, 0x82, 0x00, 0x0a, 0x0e, 0x8c, 0xff, 0xff, 0xbf, 0x95, 0xbd, 0xff, 0xff, 0xb1, 0x1f, 0x85, 0x00, 0x02, 0x4b, 0xff, 0xb9, 0x89, 0x00, 0x0b, 0x48, 0xff, 0xff, 0xdd, 0x95, 0x9c, 0xff, 0x85, 0x18, 0xff, 0xff, 0x2a, 0x81, 0x00, 0x02, 0x40, 0xff, 0xdd, 0x83, 0x00, 0x03, 0x0f, 0xff, 0xff, 0x2d, 0x80, 0x00, 0x00, 0x05, 0x82, 0xb9, 0x03, 0xc2, 0xff, 0xff, 0xbf, 0x81, 0xb9, 0x00, 0x2e, 0x86, 0x00, 0x03, 0x04, 0xff, 0xff, 0x3b, 0x85, 0x00, 0x02, 0x7c, 0xff, 0x69, 0x82, 0x00, 0x03, 0x54, 0xff, 0xea, 0x22, 0x80, 0x00, 0x00, 0x14, 0x82, 0xb9, 0x03, 0xc7, 0xff, 0xff, 0xbb, 0x81, 0xb9, 0x05, 0x1f, 0x00, 0x00, 0x50, 0xff, 0x78, 0x80, 0x00, 0x02, 0x74, 0xff, 0x50, 0x80, 0x00, 0x02, 0xb1, 0xff, 0x31, 0x80, 0x00, 0x02, 0x40, 0xff, 0xdd, 0x83, 0x00, 0x03, 0x0f, 0xff, 0xff, 0x2d, 0x82, 0x00, 0x0a, 0x13, 0x9c, 0xff, 0xff, 0xa3, 0x8a, 0xb7, 0xff, 0xff, 0x75, 0x06, 0x82, 0x00, 0x0b, 0x40, 0xff, 0xd8, 0x2a, 0xdd, 0xca, 0x8c, 0x99, 0xff, 0xff, 0xc4, 0x1c, 0x83, 0x00, 0x00, 0x40, 0x80, 0xff, 0x07, 0xb5, 0xbd, 0xff, 0x90, 0x22, 0xff, 0xff, 0x24, 0x83, 0x00, 0x02, 0xdd, 0xff, 0x43, 0x8a, 0x00, 0x0a, 0x52, 0xff, 0xff, 0xd8, 0x99, 0x8c, 0xa2, 0xea, 0xff, 0xc4, 0x25, 0x85, 0x00, 0x00, 0x40, 0x84, 0xff, 0x00, 0xaa, 0x83, 0x00, 0x00, 0x4d, 0x80, 0xff, 0x07, 0xb1, 0xb5, 0xff, 0x9d, 0x0f, 0xd8, 0xff, 0x2f, 0x85, 0x00, 0x00, 0x74, 0x80, 0xff, 0x00, 0x32, 0x85, 0x00, 0x04, 0x3d, 0xff, 0xff, 0xd1, 0x06, 0x80, 0x00, 0x00, 0x2a, 0x80, 0xff, 0x00, 0x16, 0x81, 0x00, 0x03, 0x5b, 0xff, 0xad, 0x0b, 0x82, 0x00, 0x03, 0x29, 0xff, 0xff, 0x31, 0x85, 0x00, 0x00, 0x27, 0x80, 0xff, 0x00, 0x25, 0x85, 0x00, 0x02, 0xd1, 0xff, 0xd4, 0x86, 0xa3, 0x00, 0x4c, 0x85, 0x00, 0x03, 0x11, 0xff, 0xff, 0x1f, 0x8b, 0x00, 0x02, 0x74, 0xff, 0x4b, 0x8b, 0x00, 0x02, 0x3d, 0xff, 0xb1, 0x9b, 0x00, 0x02, 0x9d, 0xff, 0x84, 0x9d, 0x00, 0x02, 0xc2, 0xff, 0x69, 0x97, 0x00, 0x01, 0x4f, 0xb9, 0x81, 0x00, 0x02, 0x0e, 0xff, 0x33, 0x86, 0x00, 0x0a, 0x0a, 0x44, 0x7f, 0xb7, 0xe3, 0xff, 0xe3, 0xb5, 0x7f, 0x45, 0x0b, 0x81, 0x00, 0x02, 0x57, 0xff, 0x30, 0x83, 0x00, 0x05, 0x26, 0x7c, 0xb9, 0xaa, 0x6d, 0x16, 0x80, 0x00, 0x0e, 0x09, 0x47, 0x87, 0xbd, 0xd1, 0xa0, 0x5f, 0x1e, 0x00, 0x01, 0x35, 0x87, 0xcd, 0xa8, 0x12, 0x93, 0x00, 0x03, 0x22, 0xff, 0xff, 0x27, 0x8d, 0x00, 0x03, 0x49, 0xff, 0xd8, 0x09, 0xa8, 0x00, 0x03, 0x06, 0xdd, 0xff, 0x88, 0x9d, 0x00, 0x00, 0x1b, 0x80, 0xff, 0x85, 0x00, 0x03, 0x15, 0xdd, 0xff, 0x2a, 0x8d, 0x00, 0x07, 0x03, 0x37, 0x79, 0xb5, 0xd4, 0xa5, 0x66, 0x22, 0x84, 0x00, 0x00, 0x98, 0x89, 0xff, 0x03, 0x3d, 0x00, 0x00, 0x04, 0x89, 0xff, 0x00, 0x8d, 0x83, 0x00, 0x08, 0x0d, 0x49, 0x84, 0xb7, 0xdd, 0xb7, 0x84, 0x4b, 0x0f, 0x8b, 0x00, 0x02, 0x63, 0xff, 0x89, 0x85, 0x00, 0x08, 0x1a, 0x5b, 0x95, 0xc7, 0xd1, 0xa6, 0x6b, 0x2e, 0x01, 0x86, 0x00, 0x07, 0x1a, 0x5d, 0x9d, 0xcd, 0xbb, 0x83, 0x41, 0x06, 0x86, 0x00, 0x03, 0x34, 0xff, 0xff, 0x17, 0x89, 0x00, 0x08, 0x15, 0x54, 0x8c, 0xbd, 0xdd, 0xb5, 0x81, 0x47, 0x0c, 0x85, 0x00, 0x07, 0x19, 0x5d, 0x98, 0xc4, 0xbb, 0x87, 0x45, 0x07, 0x88, 0x00, 0x00, 0x1b, 0x80, 0xff, 0x8a, 0x00, 0x03, 0x9d, 0xff, 0xa0, 0x02, 0xbd, 0x00, 0x02, 0x9d, 0xff, 0x84, 0x86, 0x00, 0x02, 0x1a, 0xff, 0x6f, 0x8a, 0x00, 0x02, 0x87, 0xff, 0x9a, 0x87, 0x00, 0x06, 0x09, 0xd1, 0xff, 0x58, 0x00, 0x00, 0x80, 0x83, 0xff, 0x04, 0xc4, 0x95, 0x62, 0x2a, 0x01, 0x85, 0x00, 0x07, 0x1c, 0x59, 0x96, 0xc2, 0xc7, 0x91, 0x4e, 0x0d, 0x83, 0x00, 0x00, 0x80, 0x81, 0xff, 0x04, 0xd4, 0xa6, 0x74, 0x3c, 0x06, 0x84, 0x00, 0x00, 0x80, 0x89, 0xff, 0x00, 0x2d, 0x80, 0x00, 0x03, 0x2d, 0xff, 0xff, 0x22, 0x8d, 0x00, 0x07, 0x21, 0x62, 0x9f, 0xcd, 0xb3, 0x89, 0x53, 0x21, 0x83, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x83, 0x00, 0x03, 0x04, 0xff, 0xff, 0x53, 0x81, 0x00, 0x00, 0x1d, 0x88, 0xff, 0x00, 0x02, 0x83, 0x00, 0x07, 0x09, 0x4b, 0x91, 0xcd, 0xc7, 0x8d, 0x47, 0x07, 0x84, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x85, 0x00, 0x03, 0x65, 0xff, 0xff, 0x34, 0x80, 0x00, 0x00, 0x7c, 0x88, 0xff, 0x05, 0x06, 0x00, 0x00, 0x1d, 0xff, 0xc2, 0x85, 0x00, 0x03, 0x17, 0xff, 0xff, 0x04, 0x80, 0x00, 0x02, 0x80, 0xff, 0x4d, 0x83, 0x00, 0x03, 0x84, 0xff, 0xff, 0x53, 0x83, 0x00, 0x07, 0x04, 0x3c, 0x7c, 0xb1, 0xd4, 0xa6, 0x69, 0x29, 0x84, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x8c, 0x00, 0x01, 0x09, 0x7a, 0x83, 0xff, 0x01, 0xea, 0x4f, 0x83, 0x00, 0x02, 0x80, 0xff, 0x8d, 0x84, 0x00, 0x03, 0x1e, 0xea, 0xff, 0x78, 0x81, 0x00, 0x09, 0x02, 0x30, 0x68, 0x9a, 0xc7, 0xdd, 0xbb, 0x8c, 0x5b, 0x21, 0x88, 0x00, 0x02, 0xaa, 0xff, 0x69, 0x88, 0x00, 0x08, 0x1c, 0x5d, 0x95, 0xc4, 0xd8, 0xb3, 0x7f, 0x45, 0x0b, 0x87, 0x00, 0x04, 0x12, 0xff, 0xff, 0xaf, 0x02, 0x85, 0x00, 0x03, 0x18, 0xff, 0xff, 0x9c, 0x81, 0x00, 0x0a, 0x08, 0xe3, 0xff, 0xd8, 0x02, 0x00, 0x00, 0x16, 0xd1, 0xff, 0x5d, 0x85, 0x00, 0x04, 0x02, 0x85, 0xff, 0xa5, 0x08, 0x84, 0x00, 0x02, 0xa3, 0xff, 0x69, 0x85, 0x00, 0x8b, 0xff, 0x00, 0x84, 0x83, 0x00, 0x03, 0x34, 0xff, 0xff, 0x07, 0x91, 0x00, 0x03, 0x4a, 0xff, 0xa8, 0x06, 0x86, 0x00, 0x03, 0x26, 0xff, 0xff, 0x15, 0xb8, 0x00, 0x0c, 0x2d, 0x80, 0xc4, 0xc2, 0x90, 0x4b, 0x0b, 0x00, 0x03, 0x5a, 0xb3, 0xd1, 0x75, 0x80, 0x00, 0x0a, 0x4a, 0xff, 0x9a, 0x00, 0x1a, 0x64, 0xa6, 0xd1, 0xa6, 0x5e, 0x11, 0x85, 0x00, 0x08, 0x03, 0x37, 0x74, 0xaa, 0xd4, 0xb9, 0x7c, 0x3a, 0x04, 0x85, 0x00, 0x0a, 0x28, 0x76, 0xb7, 0xca, 0x98, 0x4f, 0x09, 0x07, 0xff, 0xff, 0x26, 0x83, 0x00, 0x08, 0x03, 0x37, 0x76, 0xaf, 0xd8, 0xb9, 0x81, 0x43, 0x08, 0x86, 0x00, 0x02, 0x4b, 0xff, 0xb9, 0x8a, 0x00, 0x0a, 0x2e, 0x7d, 0xbb, 0xc2, 0x8a, 0x41, 0x06, 0x0f, 0xff, 0xff, 0x29, 0x81, 0x00, 0x02, 0x40, 0xff, 0xdd, 0x83, 0x00, 0x03, 0x0f, 0xff, 0xff, 0x2d, 0x80, 0x00, 0x00, 0x06, 0x8a, 0xff, 0x00, 0x31, 0x86, 0x00, 0x03, 0x04, 0xff, 0xff, 0x3b, 0x85, 0x00, 0x02, 0x7c, 0xff, 0x69, 0x82, 0x00, 0x07, 0x04, 0x8c, 0xff, 0xaa, 0x0b, 0x00, 0x00, 0x15, 0x8a, 0xff, 0x05, 0x22, 0x00, 0x00, 0x50, 0xff, 0x78, 0x80, 0x00, 0x02, 0x74, 0xff, 0x50, 0x80, 0x00, 0x02, 0xb1, 0xff, 0x31, 0x80, 0x00, 0x02, 0x40, 0xff, 0xdd, 0x83, 0x00, 0x03, 0x0f, 0xff, 0xff, 0x2d, 0x83, 0x00, 0x08, 0x06, 0x3f, 0x7f, 0xb7, 0xd4, 0xaa, 0x6f, 0x2e, 0x01, 0x83, 0x00, 0x0a, 0x40, 0xff, 0xe3, 0x00, 0x1c, 0x67, 0xaa, 0xd4, 0xa8, 0x60, 0x13, 0x85, 0x00, 0x0a, 0x27, 0x75, 0xb7, 0xca, 0x98, 0x4c, 0x08, 0x19, 0xff, 0xff, 0x24, 0x83, 0x00, 0x02, 0xdd, 0xff, 0x43, 0x8b, 0x00, 0x08, 0x23, 0x63, 0x99, 0xc7, 0xe3, 0xbb, 0x87, 0x4b, 0x0e, 0x87, 0x00, 0x07, 0x32, 0x7f, 0xbf, 0xdd, 0xbd, 0x91, 0x68, 0x3b, 0x84, 0x00, 0x0a, 0x36, 0x83, 0xc2, 0xca, 0x95, 0x4d, 0x0a, 0x00, 0xb5, 0xff, 0x33, 0x85, 0x00, 0x04, 0x2c, 0xff, 0xff, 0xb9, 0x05, 0x85, 0x00, 0x03, 0x24, 0xff, 0xff, 0x70, 0x81, 0x00, 0x04, 0x06, 0xd1, 0xff, 0xd8, 0x03, 0x80, 0x00, 0x03, 0x2d, 0xff, 0xff, 0x26, 0x84, 0x00, 0x03, 0x58, 0xff, 0xc2, 0x13, 0x84, 0x00, 0x04, 0x01, 0x99, 0xff, 0x9a, 0x01, 0x85, 0x00, 0x00, 0xdd, 0x88, 0xff, 0x00, 0x59, 0x85, 0x00, 0x03, 0x11, 0xff, 0xff, 0x1f, 0x8b, 0x00, 0x02, 0x74, 0xff, 0x4b, 0x8b, 0x00, 0x02, 0x3d, 0xff, 0xb1, 0x9b, 0x00, 0x02, 0x9d, 0xff, 0x84, 0xd0, 0x00, 0x02, 0x31, 0xff, 0x31, 0xbc, 0x00, 0x03, 0x01, 0x98, 0xff, 0x6f, 0x8c, 0x00, 0x03, 0x03, 0xaa, 0xff, 0x65, 0xa9, 0x00, 0x03, 0x26, 0xff, 0xff, 0x2c, 0xff, 0x00, 0xf7, 0x00, 0x03, 0x11, 0xff, 0xff, 0x3a, 0xcb, 0x00, 0x02, 0x68, 0xff, 0x37, 0x84, 0x00, 0x01, 0x2a, 0x5f, 0xff, 0x00, 0xff, 0x00, 0x90, 0x00, 0x07, 0x01, 0x2c, 0x68, 0xab, 0xff, 0xff, 0x68, 0x1b, 0xff, 0x00, 0x9e, 0x00, 0x03, 0x34, 0xff, 0xff, 0x07, 0x9e, 0x00, 0x03, 0x26, 0xff, 0xff, 0x15, 0xff, 0x00, 0xa4, 0x00, 0x03, 0x14, 0xff, 0xff, 0x23, 0xa9, 0x00, 0x03, 0x05, 0xff, 0xff, 0x38, 0xd9, 0x00, 0x02, 0x40, 0xff, 0xff, 0x94, 0x00, 0x03, 0x19, 0xff, 0xff, 0x24, 0xfd, 0x00, 0x02, 0x99, 0xff, 0x40, 0x9b, 0x00, 0x03, 0x11, 0xff, 0xff, 0x1f, 0x8b, 0x00, 0x02, 0x74, 0xff, 0x4b, 0x8b, 0x00, 0x02, 0x3d, 0xff, 0xb1, 0xf1, 0x00, 0x02, 0x31, 0xff, 0x31, 0xbd, 0x00, 0x03, 0x36, 0xff, 0xea, 0x17, 0x8b, 0x00, 0x03, 0x34, 0xff, 0xff, 0x1b, 0xa9, 0x00, 0x03, 0x4f, 0xff, 0x96, 0x01, 0xff, 0x00, 0xf7, 0x00, 0x03, 0x34, 0xff, 0xad, 0x05, 0xcb, 0x00, 0x04, 0x0c, 0xa2, 0xe3, 0x43, 0x04, 0x80, 0x00, 0x04, 0x0c, 0x58, 0xff, 0x98, 0x0a, 0xff, 0x00, 0xff, 0x00, 0x92, 0x00, 0x03, 0x20, 0xff, 0xff, 0x4d, 0xff, 0x00, 0x9f, 0x00, 0x03, 0x34, 0xff, 0xff, 0x07, 0x9e, 0x00, 0x03, 0x26, 0xff, 0xff, 0x15, 0x93, 0x00, 0x8d, 0x07, 0x00, 0x06, 0xff, 0x00, 0x03, 0x26, 0xff, 0xff, 0x13, 0xa9, 0x00, 0x03, 0x14, 0xff, 0xff, 0x2c, 0xd9, 0x00, 0x02, 0x40, 0xff, 0xff, 0x94, 0x00, 0x03, 0x19, 0xff, 0xff, 0x24, 0xfc, 0x00, 0x03, 0x29, 0xff, 0xcd, 0x0b, 0x9b, 0x00, 0x03, 0x11, 0xff, 0xff, 0x21, 0x8b, 0x00, 0x02, 0x74, 0xff, 0x4b, 0x8b, 0x00, 0x02, 0x40, 0xff, 0xaf, 0xff, 0x00, 0xb2, 0x00, 0x03, 0x02, 0x92, 0xff, 0x72, 0x8a, 0x00, 0x03, 0x06, 0xa8, 0xff, 0x66, 0xaa, 0x00, 0x02, 0x89, 0xff, 0x34, 0xff, 0x00, 0xf8, 0x00, 0x02, 0x62, 0xff, 0x42, 0xcd, 0x00, 0x0a, 0x14, 0x91, 0xff, 0xb3, 0x6d, 0x60, 0x7d, 0xdd, 0xff, 0x5d, 0x08, 0xff, 0x00, 0xff, 0x00, 0x94, 0x00, 0x03, 0x94, 0xff, 0xbd, 0x12, 0xff, 0x00, 0x9e, 0x00, 0x03, 0x34, 0xff, 0xff, 0x07, 0x9e, 0x00, 0x03, 0x26, 0xff, 0xff, 0x15, 0x92, 0x00, 0x00, 0x07, 0x8d, 0xff, 0x00, 0x98, 0xf7, 0x00, 0x02, 0x68, 0x9a, 0x5f, 0x82, 0x00, 0x02, 0x5f, 0xff, 0xa8, 0xaa, 0x00, 0x03, 0x52, 0xff, 0xea, 0x0e, 0xd9, 0x00, 0x02, 0x40, 0xff, 0xff, 0x94, 0x00, 0x03, 0x19, 0xff, 0xff, 0x24, 0xfb, 0x00, 0x03, 0x06, 0x90, 0xff, 0x58, 0x9c, 0x00, 0x03, 0x0a, 0xff, 0xff, 0x32, 0x8b, 0x00, 0x02, 0x74, 0xff, 0x4b, 0x8b, 0x00, 0x02, 0x55, 0xff, 0x99, 0xff, 0x00, 0xb3, 0x00, 0x03, 0x20, 0xea, 0xff, 0x2e, 0x89, 0x00, 0x03, 0x52, 0xff, 0xbb, 0x0e, 0xa9, 0x00, 0x03, 0x09, 0xea, 0xa5, 0x03, 0xff, 0x00, 0xf8, 0x00, 0x02, 0xaa, 0xbd, 0x07, 0xce, 0x00, 0x07, 0x05, 0x3a, 0x80, 0xb5, 0xc2, 0x90, 0x56, 0x19, 0xff, 0x00, 0xff, 0x00, 0x96, 0x00, 0x07, 0x2a, 0xff, 0xff, 0x9d, 0x2a, 0x08, 0x04, 0x08, 0xff, 0x00, 0x9a, 0x00, 0x03, 0x34, 0xff, 0xff, 0x07, 0x9e, 0x00, 0x03, 0x26, 0xff, 0xff, 0x15, 0x92, 0x00, 0x00, 0x02, 0x8d, 0x1f, 0x00, 0x1b, 0xf7, 0x00, 0x0a, 0x56, 0xff, 0xea, 0x3c, 0x03, 0x00, 0x03, 0x3d, 0xff, 0xff, 0x41, 0xa3, 0x00, 0x09, 0x17, 0x28, 0x13, 0x08, 0x07, 0x18, 0x5c, 0xff, 0xff, 0x64, 0xda, 0x00, 0x02, 0x40, 0xff, 0xff, 0x94, 0x00, 0x03, 0x19, 0xff, 0xff, 0x24, 0xfa, 0x00, 0x04, 0x14, 0x7c, 0xff, 0xb7, 0x0c, 0x9d, 0x00, 0x03, 0x8f, 0xff, 0x89, 0x0d, 0x8a, 0x00, 0x02, 0x74, 0xff, 0x4b, 0x8a, 0x00, 0x03, 0x19, 0xb9, 0xff, 0x5c, 0xff, 0x00, 0xb4, 0x00, 0x03, 0x50, 0xff, 0xb3, 0x0d, 0x87, 0x00, 0x03, 0x21, 0xea, 0xff, 0x30, 0xaa, 0x00, 0x02, 0x2a, 0xff, 0x3d, 0xff, 0x00, 0xf8, 0x00, 0x02, 0x07, 0x53, 0x30, 0xff, 0x00, 0xff, 0x00, 0xf1, 0x00, 0x00, 0x4d, 0x82, 0xff, 0x00, 0x4d, 0xff, 0x00, 0x9a, 0x00, 0x03, 0x34, 0xff, 0xff, 0xa5, 0x81, 0xa3, 0x00, 0x08, 0x94, 0x00, 0x00, 0x23, 0x81, 0xa3, 0x03, 0xb1, 0xff, 0xff, 0x15, 0xff, 0x00, 0x9c, 0x00, 0x0a, 0x09, 0x8c, 0xff, 0xff, 0xc7, 0x9f, 0xdd, 0xff, 0xff, 0x6e, 0x02, 0xa3, 0x00, 0x00, 0x36, 0x84, 0xff, 0x01, 0x87, 0x08, 0xda, 0x00, 0x02, 0x40, 0xff, 0xff, 0x94, 0x00, 0x03, 0x19, 0xff, 0xff, 0x24, 0xf8, 0x00, 0x05, 0x62, 0xb7, 0xff, 0xff, 0xd1, 0x25, 0x9e, 0x00, 0x07, 0x1f, 0xe3, 0xff, 0xff, 0xab, 0xa3, 0xa3, 0x3c, 0x86, 0x00, 0x02, 0x74, 0xff, 0x4b, 0x86, 0x00, 0x07, 0x5f, 0xa3, 0xa3, 0xb7, 0xff, 0xff, 0xb7, 0x11, 0xff, 0x00, 0xb4, 0x00, 0x04, 0x03, 0x80, 0xff, 0x7f, 0x02, 0x85, 0x00, 0x03, 0x0d, 0xad, 0xff, 0x58, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0x9d, 0x00, 0x05, 0x26, 0x6f, 0xa2, 0xad, 0x8d, 0x32, 0xff, 0x00, 0x9a, 0x00, 0x00, 0x34, 0x84, 0xff, 0x00, 0x09, 0x94, 0x00, 0x00, 0x28, 0x84, 0xff, 0x00, 0x15, 0xff, 0x00, 0x9d, 0x00, 0x08, 0x04, 0x37, 0x83, 0xbd, 0xdd, 0xb1, 0x74, 0x31, 0x01, 0xa4, 0x00, 0x08, 0x17, 0x63, 0x92, 0xbf, 0xe3, 0xb7, 0x7c, 0x3a, 0x03, 0xdb, 0x00, 0x02, 0x40, 0xff, 0xff, 0x94, 0x00, 0x03, 0x19, 0xff, 0xff, 0x24, 0xf8, 0x00, 0x04, 0x62, 0xff, 0xbf, 0x70, 0x1a, 0xa0, 0x00, 0x02, 0x22, 0x7c, 0xca, 0x80, 0xff, 0x00, 0x45, 0x86, 0x00, 0x02, 0x74, 0xff, 0x4b, 0x86, 0x00, 0x00, 0x70, 0x80, 0xff, 0x02, 0xbb, 0x68, 0x13, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xef, 0x00, }; static EG_EMBEDDED_IMAGE egemb_font_large = { 1632, 28, EG_EIPIXELMODE_ALPHA, EG_EICOMPMODE_RLE, egemb_liberation_mono_regular_28_data, 17128 }; ������������������������������������refind-0.11.4/libeg/Make.tiano����������������������������������������������������������������������0000664�0001750�0001750�00000001144�13322744524�016313� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # libeg/Make.tiano # Build control file for libeg components of rEFInd, using TianoCore EDK2 # # This program is licensed under the terms of the GNU GPL, version 3, # or (at your option) any later version. # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. include ../Make.common SOURCE_NAMES = image load_bmp load_icns lodepng lodepng_xtra nanojpeg nanojpeg_xtra screen text OBJS = $(SOURCE_NAMES:=.obj) all: $(AR_TARGET) $(AR_TARGET): $(OBJS) $(AR) -cr $(AR_TARGET).lib $(OBJS) clean: make clean ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/COPYING.txt���������������������������������������������������������������������������0000664�0001750�0001750�00000104513�12626644767�015213� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. <one line to give the program's name and a brief idea of what it does.> Copyright (C) <year> <name of author> This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: <program> Copyright (C) <year> <name of author> This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see <http://www.gnu.org/licenses/>. The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read <http://www.gnu.org/philosophy/why-not-lgpl.html>. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/keys/���������������������������������������������������������������������������������0000755�0001750�0001750�00000000000�12650013121�014252� 5����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/keys/centos.crt�����������������������������������������������������������������������0000644�0001750�0001750�00000004046�12633175417�016305� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������-----BEGIN CERTIFICATE----- MIIF2DCCBMCgAwIBAgIQAth8/dxLyW/uz8zPJTA1WTANBgkqhkiG9w0BAQsFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBFViBDb2RlIFNpZ25p bmcgQ0EgKFNIQTIpMB4XDTE0MDYwMzAwMDAwMFoXDTE3MDYwNzEyMDAwMFowgfcx HTAbBgNVBA8MFFByaXZhdGUgT3JnYW5pemF0aW9uMRMwEQYLKwYBBAGCNzwCAQMT AlVTMRkwFwYLKwYBBAGCNzwCAQITCERlbGF3YXJlMRAwDgYDVQQFEwcyOTQ1NDM2 MR4wHAYDVQQJExUxMDAgRWFzdCBEYXZpZSBTdHJlZXQxDjAMBgNVBBETBTI3NjAx MQswCQYDVQQGEwJVUzEXMBUGA1UECBMOTm9ydGggQ2Fyb2xpbmExEDAOBgNVBAcT B1JhbGVpZ2gxFTATBgNVBAoTDFJlZCBIYXQgSW5jLjEVMBMGA1UEAxMMUmVkIEhh dCBJbmMuMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyJOAuVmPBea5 KxWReGdj02KIv9+qojLW6EPA4bCFuRQ8hRwbdLZoZSoDg6rCh7Wg4naSX5FC6uaA FdJ0j7Rqrj/eO5mJzW5KpfsaPAMysFKAfE5oZ3jKMQSlkP+8JK2AmBTj0nIyS6NP mL5tFuD/EExGp043wnWSQOA6EWoZWwS5AOGW5+biojFWwYjq2kVxp9uec2HwSJ8U fH6DSdKZdEeGTKXMhFdphvCFaseRZkJTsKV6Y1LdcaHn/PkL+Wlz6IOYSqF5OpiZ D0ESH5d7kWxRm/XerZMjZ2Y7oNuaMxl8bfMIIlqErD4DyMkZ6lCCz5fAt8mIxsm3 TDYUei9viQIDAQABo4IB6DCCAeQwHwYDVR0jBBgwFoAUj+h+8G0yagAFI8dwl2o6 kP9r6tQwHQYDVR0OBBYEFB/5bdjRsjJyKMBLA6dy27Lbt5sfMC4GA1UdEQQnMCWg IwYIKwYBBQUHCAOgFzAVDBNVUy1ERUxBV0FSRS0yOTQ1NDM2MA4GA1UdDwEB/wQE AwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzB7BgNVHR8EdDByMDegNaAzhjFodHRw Oi8vY3JsMy5kaWdpY2VydC5jb20vRVZDb2RlU2lnbmluZ1NIQTItZzEuY3JsMDeg NaAzhjFodHRwOi8vY3JsNC5kaWdpY2VydC5jb20vRVZDb2RlU2lnbmluZ1NIQTIt ZzEuY3JsMEIGA1UdIAQ7MDkwNwYJYIZIAYb9bAMCMCowKAYIKwYBBQUHAgEWHGh0 dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwfgYIKwYBBQUHAQEEcjBwMCQGCCsG AQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wSAYIKwYBBQUHMAKGPGh0 dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEVWQ29kZVNpZ25pbmdD QS1TSEEyLmNydDAMBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4IBAQBynOz2 SzOBjev7IxtrKQiCx2lv8LoG5MILQJTuepyyoMcbVDJj2arA0W8ZQfClRjUt9qlL fbCbAJyk57NJZRGyTf6oxp/1J5Nz4PFYFPqPodHBXgfi2JefBA6WAdYKGKsE/qtA mYPsv5LAg3AmSkTCLdGuE155WFzD1GhwKEEC44l8QiQ2xHoGJO/EWobBQUvpmxzh 1wu3OcgD/TGJoE+jqm1qKvMqDKLh8BlhuX+RP0f40AGcd+Yf22NkhM0o+3ck9OjS nBVMA8WlbFLvz7DB+r58x4gSxp7cvo5Fvq1mV2g+cUSR7zwNALQBT0U3cMidQlAD ibMnawpjKcS7WsDO -----END CERTIFICATE----- ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/keys/openSUSE-UEFI-CA-Certificate.crt�������������������������������������������������0000664�0001750�0001750�00000003106�12627706157�021704� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������-----BEGIN CERTIFICATE----- MIIEdDCCA1ygAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgTEgMB4GA1UEAwwXb3Bl blNVU0UgU2VjdXJlIEJvb3QgQ0ExCzAJBgNVBAYTAkRFMRIwEAYDVQQHDAlOdXJl bWJlcmcxGTAXBgNVBAoMEG9wZW5TVVNFIFByb2plY3QxITAfBgkqhkiG9w0BCQEW EmJ1aWxkQG9wZW5zdXNlLm9yZzAeFw0xMzA4MjYxNjEyMDdaFw0zNTA3MjIxNjEy MDdaMIGBMSAwHgYDVQQDDBdvcGVuU1VTRSBTZWN1cmUgQm9vdCBDQTELMAkGA1UE BhMCREUxEjAQBgNVBAcMCU51cmVtYmVyZzEZMBcGA1UECgwQb3BlblNVU0UgUHJv amVjdDEhMB8GCSqGSIb3DQEJARYSYnVpbGRAb3BlbnN1c2Uub3JnMIIBIjANBgkq hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3t9hknqk/oPRfTtoDrGn8E6Sk/xHPnAt Tojcmp76M7Sm2w4jwQ2owdVlBIQE/zpIGE85MuTKTvkEnp8PzSBdYaunANil/yt/ vuhHwy9bAsi73o4a6UbThu//iJmQ6xCJuIs/PqgHxlV6btNf/IM8PRbtJsUTc5Kx cB4ilcgAbCV2RvGi2dCwmGgPpy2xDWeJypRK6hLFkVV2f2x6LvkYiZ/49CRD1TVq ywAOLu1L4l0J2BuXcJmeWm+mgaidqVh2fWlxgtO6OpZDm/DaFcZO6cgVuenLx+Rx zuoQG2vEKnABqVK0F94AUs995P0PTQMYspAo1G/Erla8NmBJRotrCwIDAQABo4H0 MIHxMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFGhCYA3iLExHfpW+I9/qlRPl lxdiMIGuBgNVHSMEgaYwgaOAFGhCYA3iLExHfpW+I9/qlRPllxdioYGHpIGEMIGB MSAwHgYDVQQDDBdvcGVuU1VTRSBTZWN1cmUgQm9vdCBDQTELMAkGA1UEBhMCREUx EjAQBgNVBAcMCU51cmVtYmVyZzEZMBcGA1UECgwQb3BlblNVU0UgUHJvamVjdDEh MB8GCSqGSIb3DQEJARYSYnVpbGRAb3BlbnN1c2Uub3JnggEBMA4GA1UdDwEB/wQE AwIBhjANBgkqhkiG9w0BAQsFAAOCAQEAiqOJwo7Z+YIL8zPO6RkXF6NlgM0zrgZR Vim2OId79J38KI6q4FMSDjpgxwbYOmF2O3cI9JSkjHxHOpnYhJsXzCBiLuJ25MY2 DSbpLlM1Cvs6NZNFw5OCwQvzCOlXH1k3qdBsafto6n87r9P3WSeO1MeWc/QMCvc+ 5K9sjMd6bwl59EEf428R+z5ssaB75JK3yvky9d7DsHN947OCXc3sYdz+DD7Gteds LV2Sc//tqmqpm2aeXjptcLAxwM7fLyEQaAyH83egMzEKDxX27jKIxZpTcc0NGqEo idC/9lasSzs2BisBxevl3HKDPZSsKIMT+8FdJ5wT9jJf9h9Ktz5Tig== -----END CERTIFICATE----- ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/keys/openSUSE-UEFI-CA-Certificate-4096.crt��������������������������������������������0000644�0001750�0001750�00000004371�12627706157�022307� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������-----BEGIN CERTIFICATE----- MIIGdDCCBFygAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgTEgMB4GA1UEAwwXb3Bl blNVU0UgU2VjdXJlIEJvb3QgQ0ExCzAJBgNVBAYTAkRFMRIwEAYDVQQHDAlOdXJl bWJlcmcxGTAXBgNVBAoMEG9wZW5TVVNFIFByb2plY3QxITAfBgkqhkiG9w0BCQEW EmJ1aWxkQG9wZW5zdXNlLm9yZzAeFw0xMzAxMjgxNDUzMzBaFw0zNDEyMjQxNDUz MzBaMIGBMSAwHgYDVQQDDBdvcGVuU1VTRSBTZWN1cmUgQm9vdCBDQTELMAkGA1UE BhMCREUxEjAQBgNVBAcMCU51cmVtYmVyZzEZMBcGA1UECgwQb3BlblNVU0UgUHJv amVjdDEhMB8GCSqGSIb3DQEJARYSYnVpbGRAb3BlbnN1c2Uub3JnMIICIjANBgkq hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAuqmSgrdlO0B96sOK5mJj1k4OetzmP6l8 YKdy+HdzN/3bS97vfqIIqb0YCgzmJROSLsXv6WQReuAtKbftgla6R/dOvKU/CxCN z0uCbzuM+gN5Q7pSWifnm81QNDowFpxZlJBFvIP92zh5yWNEGqVzMN0jDjOFxLfh O1sx6W8YBOYzScWrlTKysH6uK79gWenwvh3nmkx+68PV08azmizG6As4IAPDqtd/ w92iLTzjLVGp32wFDhLuDleojjvJgnOGngKa8oRcLlvfh07wKO0urjt8/3HKxcUf RmbSyaLdfP8lOt/mFPpfN4kev9wjqdbIhLIZs6iKbu+hR40QfAR46V8vnPoeIYeM ibsl1mvr0U7O6w7kTQuzW7JmJkCYf7n4HoPBgxTzgjKlsBGY0I+dTvZXozsKuTKx ir/w6WWcdkIWoXJh00Nb9eWqFQr0exG0hwa1o0ESXjv7aJHwg39B6m8MZVppdpmg i0G8pOKtHQZ6OR87YeSUHJ400ocIfYMOAybuB/5rHfC58BvCcjaZwHKTkHlyx28i EXgFyzGMqbWlgmI5RJ8UzaM6rTaieIRSsyGbYrDa89BFMhGmY8xMIeeT8191bLbH CpX7CMW9npoEqslHL67FMI3LXC5fgYKoPwUnj/TlT0gkjVobEXmXZB6sCDQ6BFTg 4dpPIFEjnxsCAwEAAaOB9DCB8TAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSZ DSa38E3ZzmTn0Y79aHtKXeKGpTCBrgYDVR0jBIGmMIGjgBSZDSa38E3ZzmTn0Y79 aHtKXeKGpaGBh6SBhDCBgTEgMB4GA1UEAwwXb3BlblNVU0UgU2VjdXJlIEJvb3Qg Q0ExCzAJBgNVBAYTAkRFMRIwEAYDVQQHDAlOdXJlbWJlcmcxGTAXBgNVBAoMEG9w ZW5TVVNFIFByb2plY3QxITAfBgkqhkiG9w0BCQEWEmJ1aWxkQG9wZW5zdXNlLm9y Z4IBATAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIBAFsmHlxiAGKu Qyx1qb6l7bEWgXAePQfVaaCEH4Mn+oq80kJ67S7s6We8e5QJOgYznk5mDk+PTUC/ phkP3aJRqZAf5UDrQkOHobpk7FFBxZKjZfULPls3H9+Hichw/XJ2/xJwG+Ja6pgD dNO2UaKOjZHCiyZ4ehO7syle/EgQALVwKH4cVq6zIh4xUH4r9WvfdR5vkhhTgM/0 nzzoBnFRnCUpcsLPj10246wVuLQcliZBeKjiV4xqrMe6cXX8crHvZqqJPZ2jMTGD eVIpVES12ZpMT7SbQbcDR1XgjqrL3U9vfcabdqLU60000ALvnDFNN0Sm7xhB+d3c sDIyJMwSfIb9jWApsB/En5uRCM++ruqjyFiqTCORo9gzaocw6gut6WYs2TOrZ2NO Tq4JNAFfCL/z0p8jdz1dJZmqpgFAlltKNNDWV6KlBPUAdxDEbIiuGoYweB+Zxed3 BKdlrKGcH0ewPmzt4vVLCl2yFoODxjVtndXieDt/BWIYltMjqYU1qrrOdISHdeAG A24L/uxiU4Ej2bKKWNYtvrGMNLMUWBTx5afHMQnK9MD8Z6cpjccNaR0Pe9ZCBRGI xyUitlfnU604q1GfYdymiq4mUvSEgy3vbbsVBvcAKElN+hWpAeZbiWc/KcBWKMtp 4aQ0yoLWDFkQNGU0rGazsu3hpOWta6mL -----END CERTIFICATE----- �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/keys/canonical-uefi-ca.der������������������������������������������������������������0000664�0001750�0001750�00000002070�12626644770�020234� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������040 �A$,g0  *H  �01 0 UGB10U Isle of Man10U Douglas10U Canonical Ltd.1402U +Canonical Ltd. Master Certificate Authority0 120412111251Z 420411111251Z01 0 UGB10U Isle of Man10U Douglas10U Canonical Ltd.1402U +Canonical Ltd. Master Certificate Authority0"0  *H ��0 �[:t!]aVr~-LbmHύa'nU=9T@;4y{z-}YϦNڮRLƙ Ngex]8JJz¢!-TA5Wl)PJ~ꙩh;2yh-~Rɛ+hIٕP@[Ųq\Wq@ [-PRkndO[ aZB!ٹTBRrIdzl$p M2ѠWM㯥>C�00U *#eZ&4Zc0U#0 *#eZ&4Zc0U00 U0CU<0:08642http://www.canonical.com/secure-boot-master-ca.crl0  *H  ��?}v+zmRPGwҮW2:UVv Qۚ\?sڔj8m9qtv>V#5UG[AL b s^ֵz~>~f[9HQS1S;upLF=hG}QĚϣ]풻3Qs<r}}˜i9w%Gq'.?_i> fm'wBj ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/keys/openSUSE-UEFI-CA-Certificate.cer�������������������������������������������������0000664�0001750�0001750�00000002170�12627706157�021665� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������0t0\0  *H  �01 0U openSUSE Secure Boot CA1 0 UDE10U Nuremberg10U openSUSE Project1!0 *H  build@opensuse.org0 130826161207Z 350722161207Z01 0U openSUSE Secure Boot CA1 0 UDE10U Nuremberg10U openSUSE Project1!0 *H  build@opensuse.org0"0  *H ��0 �az};hNG>p-Nܚ3# e:HO92N ]a�إ+G/[ȻގFӆ?>Uzn_<=&sp"�l%vFаh- gʔJőUvlz.$C5j�.K] pZoXv}iqӺ:CNqk*pR�R}M(oĮV6`IFk �00U00UhB` ,LG~#b0U#0hB` ,LG~#b01 0U openSUSE Secure Boot CA1 0 UDE10U Nuremberg10U openSUSE Project1!0 *H  build@opensuse.org0U0  *H  ��Ž 3e3QV)8{(S:`:av;w|G:؄ b.v6 &.S5 :5EÓ WY7lih;Y'ǖs >lzo yAo>l{䒷2ðs}㳂]a >Ƶl-]sjf^:mp1/!h w31 2ŚSq (пVK;6+r=(]'2_J>S��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/keys/canonical-uefi-ca.crt������������������������������������������������������������0000664�0001750�0001750�00000002755�12626644770�020264� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������-----BEGIN CERTIFICATE----- MIIENDCCAxygAwIBAgIJALlBJKAYLJJnMA0GCSqGSIb3DQEBCwUAMIGEMQswCQYD VQQGEwJHQjEUMBIGA1UECAwLSXNsZSBvZiBNYW4xEDAOBgNVBAcMB0RvdWdsYXMx FzAVBgNVBAoMDkNhbm9uaWNhbCBMdGQuMTQwMgYDVQQDDCtDYW5vbmljYWwgTHRk LiBNYXN0ZXIgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTEyMDQxMjExMTI1MVoX DTQyMDQxMTExMTI1MVowgYQxCzAJBgNVBAYTAkdCMRQwEgYDVQQIDAtJc2xlIG9m IE1hbjEQMA4GA1UEBwwHRG91Z2xhczEXMBUGA1UECgwOQ2Fub25pY2FsIEx0ZC4x NDAyBgNVBAMMK0Nhbm9uaWNhbCBMdGQuIE1hc3RlciBDZXJ0aWZpY2F0ZSBBdXRo b3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC/WzoWdO4hXa5h 7Z1WrL3e3nLz3X4tTGIPrMBtSAgRz42L+2EfJ8wRbtlVPTlU60A7sbvihTR5yvd7 v7p6yBAtGX2tWc+m1OlOD9quUupMnpDOxpkNTmdleF350dU4Skp6j5OcfxqjhdvO +ov3wqIhLZtUQTUQVxONbLwpBlBKfuqZqWinO8cHGzKeoBmHDnm7aJktfpNS5fbr yZv5K+24aEm82ZVQQFvFsnGq61xX3nH5QArdW6wehC1QGlLW4fNrbpBkT1u06yDk YRDaWvDq5ELXAcT+IR/ZucBUlUKBUnIfSWR6yGwk8QhwC02loDLRoBxXqE3jr6WO BQU+EEOhAgMBAAGjgaYwgaMwHQYDVR0OBBYEFK2RmQvCKrH1FwSMI7ZlWiaONFpj MB8GA1UdIwQYMBaAFK2RmQvCKrH1FwSMI7ZlWiaONFpjMA8GA1UdEwEB/wQFMAMB Af8wCwYDVR0PBAQDAgGGMEMGA1UdHwQ8MDowOKA2oDSGMmh0dHA6Ly93d3cuY2Fu b25pY2FsLmNvbS9zZWN1cmUtYm9vdC1tYXN0ZXItY2EuY3JsMA0GCSqGSIb3DQEB CwUAA4IBAQA/ffZ2pbODtCt60G1SGgODxBKnUJxHkszAlHeC0q5Xs5kE9TI6xlUd B9sSqVb62NR2IOvkw1Hbmlyckj8Yc9qUaqGZOIykiG3B/Dlx0HR2FgM+ViM11VVH WxodQcLTEkzc/64KkpxiChcBnHPgXrH9vNa1GRF6fs0+A35m21uoyTlIUf9T4Zwx U5EbOxB1Axe65oECgJRwTEa3lLA9Fc0fjgLgaAKP+/lHHX2iAcYHUcSazO3dz6Nd 7ZK7vtH95uwfM1FzBL48crB9CPgB/5h9y5zgaTl3JUdxiLGNJ6UuqPc/X4Bplz6p 9JkU284DDgtmxBxtvbgnd8FClL38agq8 -----END CERTIFICATE----- �������������������refind-0.11.4/keys/centos.cer�����������������������������������������������������������������������0000644�0001750�0001750�00000002734�12633175417�016270� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������00|Ko%05Y0  *H  �0l1 0 UUS10U  DigiCert Inc10U www.digicert.com1+0)U"DigiCert EV Code Signing CA (SHA2)0 140603000000Z 170607120000Z010U Private Organization10 +7<US10 +7<Delaware10U294543610U 100 East Davie Street10 U276011 0 UUS10UNorth Carolina10URaleigh10U  Red Hat Inc.10U Red Hat Inc.0"0  *H ��0 �ȓY+xgcbߪ2Cᰅ<the*‡v_Btj?;nJ<2R|Nhgx1$r2KOmLFN7u@:j[�1VEq۞saH|~IҙtGL̄WijǑfBSzcRq is胘Jy:A{lQޭ#gf;ۚ3|m"Z>PϗɈɷL6z/o�00U#0~m2j�#pj:k0UmѲ2r(Kr۲۷0.U'0%#+0 US-DELAWARE-29454360U0U% 0 +0{Ut0r07531http://crl3.digicert.com/EVCodeSigningSHA2-g1.crl07531http://crl4.digicert.com/EVCodeSigningSHA2-g1.crl0BU ;0907 `Hl0*0(+https://www.digicert.com/CPS0~+r0p0$+0http://ocsp.digicert.com0H+0<http://cacerts.digicert.com/DigiCertEVCodeSigningCA-SHA2.crt0 U0�0  *H  ��rK3#k)io @zT2c٪oAF5-K}�IeMƟ'sX^ؗ @쿒p&JD-Ѯ^yX\hp(A|B$6z$ZAK 91Omj** a?Gwcd(w$ҜLťlRϰ|LjƞܾEfWh>qD< �OE7pȝBP'k c)ĻZ������������������������������������refind-0.11.4/keys/SLES-UEFI-CA-Certificate.crt�����������������������������������������������������0000664�0001750�0001750�00000003335�12627706157�021015� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������-----BEGIN CERTIFICATE----- MIIE5TCCA82gAwIBAgIBATANBgkqhkiG9w0BAQsFADCBpjEtMCsGA1UEAwwkU1VT RSBMaW51eCBFbnRlcnByaXNlIFNlY3VyZSBCb290IENBMQswCQYDVQQGEwJERTES MBAGA1UEBwwJTnVyZW1iZXJnMSEwHwYDVQQKDBhTVVNFIExpbnV4IFByb2R1Y3Rz IEdtYkgxEzARBgNVBAsMCkJ1aWxkIFRlYW0xHDAaBgkqhkiG9w0BCQEWDWJ1aWxk QHN1c2UuZGUwHhcNMTMwNDE4MTQzMzQxWhcNMzUwMzE0MTQzMzQxWjCBpjEtMCsG A1UEAwwkU1VTRSBMaW51eCBFbnRlcnByaXNlIFNlY3VyZSBCb290IENBMQswCQYD VQQGEwJERTESMBAGA1UEBwwJTnVyZW1iZXJnMSEwHwYDVQQKDBhTVVNFIExpbnV4 IFByb2R1Y3RzIEdtYkgxEzARBgNVBAsMCkJ1aWxkIFRlYW0xHDAaBgkqhkiG9w0B CQEWDWJ1aWxkQHN1c2UuZGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB AQDN/avXKoT4gcM2NVA1LMfsBPH01sxgS8gTs3SbvfbEP2M+ZlHyfj9ufHZ7cZ1p ISoVm6ql5VbIeZgSNc17Y4y4Nynud1C8t2SP/iZK5YMYHGxdtIfv1zPE+Bo/KZqE WgHg2YFtMXdiKfXBZRTfSh37t0pGO/OQi6K4JioKw55UtQNggePZWDXtsAviT2vv abqLR9+kxdrQ0iWqhWM+LwXbTGkCpg41s8KucLD/JYAxxw05dKPApFDNnz+Ft2L7 e5JtyB4S0u4PlvQBMNHt4hDs0rK4oeHFLbOxHvjF+nloneWhkg9eT0VCfpAYVYz+ whMxuCHerDCdmeFrRGEMQz11AgMBAAGjggEaMIIBFjAPBgNVHRMBAf8EBTADAQH/ MB0GA1UdDgQWBBTsqw1CxFbPdwQ2uXOZOGKWXocmLzCB0wYDVR0jBIHLMIHIgBTs qw1CxFbPdwQ2uXOZOGKWXocmL6GBrKSBqTCBpjEtMCsGA1UEAwwkU1VTRSBMaW51 eCBFbnRlcnByaXNlIFNlY3VyZSBCb290IENBMQswCQYDVQQGEwJERTESMBAGA1UE BwwJTnVyZW1iZXJnMSEwHwYDVQQKDBhTVVNFIExpbnV4IFByb2R1Y3RzIEdtYkgx EzARBgNVBAsMCkJ1aWxkIFRlYW0xHDAaBgkqhkiG9w0BCQEWDWJ1aWxkQHN1c2Uu ZGWCAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4IBAQASviyFhVqU Wc1JUQgXwdljJynTnp0/FQOZJBSe7XdBGPmy91+3ITqrXgyqo/218KISiQl53Qlw pq+cIiGRAia1D7p7wbg7wsg+Trt0zZFXes30wfYq5pjfWadEBAgNCffkBz10TSjL jQrVwW5N+yUJMoq+r843TzV56Huy6LBOVhI5yTz7X7i2rSJYfyQWM8oeHLj8Yl5M rOB9gyTumxB4mOLmSqwKzJiUB0ppGPohdLUSSEKDdo6KSH/GjR7M7uBicwnzwJD3 SVfT9nx9HKF2nXZlHvs5ViQQru3qP1tc6i0eXEnPTYW2+zkZcN0e5iHyozEZHsO0 rvc1p6G0YWtO -----END CERTIFICATE----- ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/keys/refind.cer�����������������������������������������������������������������������0000664�0001750�0001750�00000001477�12626644770�016256� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������0;0# �t RN0  *H �041200U )Roderick W. Smith, rodsmith@rodsbooks.com0 121206213828Z 321201213828Z041200U )Roderick W. Smith, rodsmith@rodsbooks.com0"0  *H ��0 �NuU՛)ux\qva !O;ݟm$Є:t oظgYމ_bIrl{�Ewɷ}&'HHwWC>N[#^xb+SJkmlSeѻɫAw@JIK&vve ?j wye44*ޤ%=]=}||ٖ<fֳ uǐ\<al~� *:?�P0N0U 9Xlu UtJZp0U#0 9Xlu UtJZp0 U00  *H ��F!&ءˏa;="Chsy;F_j7@sagi2IST:>{CO]0S-L} ]~kV zV, %||`%%ƘՍ,ZIgrW[0P׬|$p~?~?-~$5aMKEWzVN�`(v!=3;) ˽Lԏ3vybv$t �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/keys/microsoft-kekca-public.der�������������������������������������������������������0000664�0001750�0001750�00000002754�12626644770�021344� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������00Р a ш�����0  *H  �01 0 UUS10U Washington10URedmond10U Microsoft Corporation1;09U2Microsoft Corporation Third Party Marketplace Root0 110624204129Z 260624205129Z01 0 UUS10U Washington10URedmond10U Microsoft Corporation1*0(U!Microsoft Corporation KEK CA 20110"0  *H ��0 �赊W&&WzD] Jt*mZc2|O 8, 0HPdQȅO /Sjb: C%#pM/$JC ~Gl3*q<% /hvFOܭq*Xy=e;)*rY뮒5_̝vcy@yR{i�O0K0 +7�0UbC͠>g[U{̶_0 +7  �S�u�b�C�A0 U0U00U#0EfRC~XN#U;:"j0\UU0S0QOMKhttp://crl.microsoft.com/pki/crl/products/MicCorThiParMarRoo_2010-10-05.crl0`+T0R0P+0Dhttp://www.microsoft.com/pki/certs/MicCorThiParMarRoo_2010-10-05.crt0  *H  ��Ԅ*<* נRfuz�-vZy7jQ{ddgxΈXd W_iHK2]0x+4VʮA%pkז* K(){|vyo~l{E4Q9^VBwqV̟#˦X~ig~ <νC-j+Z|DR-R�=`3e |N8/ o.9'B)FA;gCYe �Ou;$PA@y-O j'vnRi{E­S076aJi4hl l"yF`!y2`ج"KK}?W5Ou`"Sy֛ATp 5|4r`;y뢲]%o8yi �uk4`\WN62��������������������refind-0.11.4/keys/refind.crt�����������������������������������������������������������������������0000664�0001750�0001750�00000002234�12626644770�016265� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������-----BEGIN CERTIFICATE----- MIIDOzCCAiOgAwIBAgIJAODF7HQMFVJOMA0GCSqGSIb3DQEBBQUAMDQxMjAwBgNV BAMMKVJvZGVyaWNrIFcuIFNtaXRoLCByb2RzbWl0aEByb2RzYm9va3MuY29tMB4X DTEyMTIwNjIxMzgyOFoXDTMyMTIwMTIxMzgyOFowNDEyMDAGA1UEAwwpUm9kZXJp Y2sgVy4gU21pdGgsIHJvZHNtaXRoQHJvZHNib29rcy5jb20wggEiMA0GCSqGSIb3 DQEBAQUAA4IBDwAwggEKAoIBAQCqTnWTvfemH1XP4RqiCITm1Zuvwil1+XhccYx2 YQ23IU/e1Dvdn5xtk6Qk0IQa8pYG8DrQdOQJkItv3PDYuOu0Zx/dHVm93okHBAS1 X2JJcslswHv/hAATs0Xnv3fJt30mJ0ja+KDbSOZ3V0MH+pjBkc/6Pk7xHuOkWwjJ 6iP5nePeD8oGvQcGuwZe9XhiK1NKa23j9WzVU8hl0buhyatBd/xASs9JnUsmEhsG dqasdmWp6QqTvj/QwWoJd7J5zmU0k5SGt5I0kKQGKo/epCU9XdAf5z198J0D6XyP fN3y2ZYTPGb/1rMNdceQXDxhl/ps3n4A/qIKiZW3Ks8cOj+HAgMBAAGjUDBOMB0G A1UdDgQWBBTTDAa9OVimbJh1fwmoCFXhdEpacDAfBgNVHSMEGDAWgBTTDAa9OVim bJh1fwmoCFXhdEpacDAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQCo 9/vhRiG9oMEaJtihy4/pYTs9EiKCQ6ewzcbQaBz7mPXec7h5E4LuxhE7Rl/+1/xq 39X8D7C0mbDyN0Drt3Ovf+hhzWdpkDIQ/7P6SdRTxAXE+/xUOj57jENPXZWV0jDt Uy1MGZN9IKAUXfnPfmv72FYN9XoUVv3d5yy9wSCc/9AlGHx8lGDJ/p7DJSXGmBKO BQV/1Y39GCxaSWdyrcjnV1swUBLO9tesfCRwfoo/rNh+wgK9P+emLbh+jSTL/zW/ Ye1NS0VXD3pWTswA7M7XYOy6KON2vKupFyHhDj3NMzspq8/oDQHLvUzq1I8z99sd it92eWJ2JKoH6nSKDKXq -----END CERTIFICATE----- ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/keys/microsoft-uefica-public.crt������������������������������������������������������0000664�0001750�0001750�00000004163�12626644361�021530� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������-----BEGIN CERTIFICATE----- MIIGEDCCA/igAwIBAgIKYQjTxAAAAAAABDANBgkqhkiG9w0BAQsFADCBkTELMAkG A1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQx HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjE7MDkGA1UEAxMyTWljcm9z b2Z0IENvcnBvcmF0aW9uIFRoaXJkIFBhcnR5IE1hcmtldHBsYWNlIFJvb3QwHhcN MTEwNjI3MjEyMjQ1WhcNMjYwNjI3MjEzMjQ1WjCBgTELMAkGA1UEBhMCVVMxEzAR BgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1p Y3Jvc29mdCBDb3Jwb3JhdGlvbjErMCkGA1UEAxMiTWljcm9zb2Z0IENvcnBvcmF0 aW9uIFVFRkkgQ0EgMjAxMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB AKUIbEzHRQlqSwykwId/BnUMQwFUZOAWfwftkn0LsnO/DArGSkVhoMUWLZbT9Sug +01Jm0GAkDy5VP3mvNGdxKQYin9BilxZg2gyu4xHye5xvCFPmop8/0Q/jY8ysiZI rnW17slMHkoZfuSCmh14d00MsL32D9MW07z6K6VROF31+7rbeALb/+wKG5bVg7gZ E+m2wHtAe+EfKCfJ+u9WXhzmfpR+wPBEsnk55dqyYotNvzhw4mgkFMkzpAg31Vhp XtN87cEEUwjnTrAqh2MIYW9jFVnqsit51wxhZ4pb/V6th3+6hmdPcVgSIgQiIs6L 71RxAM5QNVh2lQjuarGiAdUCAwEAAaOCAXYwggFyMBIGCSsGAQQBgjcVAQQFAgMB AAEwIwYJKwYBBAGCNxUCBBYEFPjBa7d/d1NK8yU3HU6hJnsPIHCAMB0GA1UdDgQW BBQTrb9DCb2CcJyM1U8xbtUimIob1DAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMA QTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBRFZlJD 4X5YEb/WTp4jVQg7OiJqqDBcBgNVHR8EVTBTMFGgT6BNhktodHRwOi8vY3JsLm1p Y3Jvc29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNDb3JUaGlQYXJNYXJSb29f MjAxMC0xMC0wNS5jcmwwYAYIKwYBBQUHAQEEVDBSMFAGCCsGAQUFBzAChkRodHRw Oi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY0NvclRoaVBhck1hclJv b18yMDEwLTEwLTA1LmNydDANBgkqhkiG9w0BAQsFAAOCAgEANQhC/zDMzvd2DK0Q aFg1KUYydid87xJBJ0IbSqptgThIWRNV8+lYNKYWC4KqXa2C2oCDQQaPtB3yA7nz Gl0b8VCQ+bNVhEIoHCC9sq5RFMXArJeVIRyQ2w/8d56Vc5GIyr29UrkFUA3fV56g Ye0N5W0l2UAPF0DIzqNKwk2vmhIdCFSPvce8uSs9SSsfMvxqIWlPm8h+QjT8NgYX i48gQMCzmiV1J83JA6P2XdHnNlR6uVC10xLRB7+7dN/cHo+A1e0Y9C8UFmsv3maM sCPlx4TY7erBM4KtVksYLfFolQfNz/By8K673YaFmCwhTDMr8A9K8GiHtZJVMnWh aoJqPKMlEaTtrdcErsvYQFmghNGVTGKRIhp0HYw9Rw5EpuSwmzQ1sfq2U6gsgeyk BXHInbi66BtEZuRHVA6OVn+znxaYsobQaD6QI7UvXo9QhY3GjYJfQaH0Lg3gmdJs deS2abUhhvoH0fbiTdHarSx3Ux4lMjfHbFJylYaw8TVhahn1sjuBUFamMi3+oon5 QoYnGFWhgspam/gwmFQUpkeWJS/IJuRBlBpcAj/lluOFWzw+P7tHFnJV4iUisdl7 5wMGKqP3HpBGwwAN1hmJ4w41J2IDcRWm79AnoKBZN2D4OJS44Hhw+LpMhoeU9uCu AkXuZcK2o35pFnUHkpv1prxZg1g= -----END CERTIFICATE----- �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/keys/openSUSE-UEFI-CA-Certificate-4096.cer��������������������������������������������0000664�0001750�0001750�00000003170�12627706157�022266� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������0t0\0  *H  �01 0U openSUSE Secure Boot CA1 0 UDE10U Nuremberg10U openSUSE Project1!0 *H  build@opensuse.org0 130128145330Z 341224145330Z01 0U openSUSE Secure Boot CA1 0 UDE10U Nuremberg10U openSUSE Project1!0 *H  build@opensuse.org0"0  *H ��0 �e;@}ÊbcNz?|`rws7K~ %.dz-)VGN? Ko;yCRZ'P4:0YE8ycDs0#3ķ;[1o3Iū2~+`YL~Ƴ, 8 êݢ-<-QlW;ɂs\.[߇N(.;|qFfɢ|%:_7#ȄnG|x_/!%kNM [f&@2ЏNW; 2evBraC[ {A^;hAo eZivAz9;a4҇}&kr6ryro"x1b9Dͣ:6xR!bE2cL!_ul ŽG/0\._?'OH$Zyd4:TO Q#�00U00U &Mdюh{J]↥0U#0 &Mdюh{J]↥01 0U openSUSE Secure Boot CA1 0 UDE10U Nuremberg10U openSUSE Project1!0 *H  build@opensuse.org0U0  *H  ��[&\b�bC,up=i'Bz.g{ :3NfOM@ݢQ@BCdQAŒe >[7߇prvpZtӶQ‹&xz)^H�p(~V"1P~+kuoS<qQ%)rϏ]6&AxWjǺqurf=11yR)TDٚLOAGUOo}ƛvM41M7DAܰ22$|`)ğϾXL#3j0 f,3gcNN 4_ҟ#w=]%@[J4W�wl0xweG>lK ]5mx;b#5tun bS#ٲX-4X1 g) i{B%"WS8Qaܦ&R-m�(IM[g?)V(i4ʂ Y4e4fk��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/keys/fedora-ca.crt��������������������������������������������������������������������0000664�0001750�0001750�00000002331�12626644770�016635� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������-----BEGIN CERTIFICATE----- MIIDaDCCAlCgAwIBAgIFAJl28vQwDQYJKoZIhvcNAQELBQAwIDEeMBwGA1UEAxMV RmVkb3JhIFNlY3VyZSBCb290IENBMB4XDTEyMTIwNzE2MjU1NFoXDTIyMTIwNTE2 MjU1NFowIDEeMBwGA1UEAxMVRmVkb3JhIFNlY3VyZSBCb290IENBMIIBIjANBgkq hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArvX3UoGpXD4r9x1V9FpohC28i3aWhQ0n uBilzcGDsownXSMK0RIKdZii5l0BivTZn/xwvMPEF3sCtRPEUZLgwAV0uS49JHig eXOUwMIrsoKn9KtnSiLzZM3D+QwmAb8b1T05v8n6+15SuaRI+xO/hykKZO8he7we FnuIT/FAK9kiFUdOhPYkHE1TFlqxKbtefX/A1OLVea9ZcwLct0i/ritwwfp0f3n1 7iPQAwWxeRhP/U8v4mMZTXe6wSyLs9kFLtnYtlETv842Z5fkrVhWB6vQjGYSSdyR aLTI6t2cwIHGkVvbEnjb/8GvCBb8cBOXW1eta0SYfh/s7UZmlQ8FVQIDAQABo4Go MIGlME4GCCsGAQUFBwEBBEIwQDA+BggrBgEFBQcwAoYyaHR0cHM6Ly9mZWRvcmFw cm9qZWN0Lm9yZy93aWtpL0ZlYXR1cmVzL1NlY3VyZUJvb3QwHwYDVR0jBBgwFoAU /eMlmcLWHbG/WAczXXsg5M2WO0IwEwYDVR0lBAwwCgYIKwYBBQUHAwMwHQYDVR0O BBYEFP3jJZnC1h2xv1gHM117IOTNljtCMA0GCSqGSIb3DQEBCwUAA4IBAQA3d/A6 QaIcn3E71puVtRXfSrb00VG6DQTanLIj8PM0WY241Jp1dGWAF2E6wZZ/p8Er0xrW YDxxOqTE4zkDAhUSCB9OzZdQ+P9QzLY+A31654J6wme+yQ4RDxYuHqnybv4Eveqe 9Kmz2dRhVwiHxJjYoplk3hVUjVd5FB/6DU1rzZg19QwGvfMx1v4FH2CQth4Q9yTg PPYzUM1EwnEYUb0YMYEeMuHmn/mcAlO05WpB1mW0LvHPs7iCsKOW4iTYg64GW7Mk dE3RpAodCjIbdaKW0Q4+4TDDGOjLU8QLAK1+rchJQe+Xab0TX+/vPNpgBdiS/Npq 6kg/Dj5zd/2miek/ -----END CERTIFICATE----- �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/keys/SLES-UEFI-CA-Certificate.cer�����������������������������������������������������0000664�0001750�0001750�00000002351�12627706157�020773� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������00͠0  *H  �01-0+U $SUSE Linux Enterprise Secure Boot CA1 0 UDE10U Nuremberg1!0U SUSE Linux Products GmbH10U Build Team10 *H   build@suse.de0 130418143341Z 350314143341Z01-0+U $SUSE Linux Enterprise Secure Boot CA1 0 UDE10U Nuremberg1!0U SUSE Linux Products GmbH10U Build Team10 *H   build@suse.de0"0  *H ��0 �*65P5,`Kt?c>fQ~?n|v{qi!*Vy5{c7)wPd&Jl]3?)Zفm1wb)eJJF;󐋢&* ÞT`X5 OkiGߤ%c>/Li5®p%1 9tP͟?b{m0Ҳ-yh塒^OEB~U1!ެ0kDa C=u�00U00U BVw6s8b^&/0U#0Ȁ BVw6s8b^&/01-0+U $SUSE Linux Enterprise Secure Boot CA1 0 UDE10U Nuremberg1!0U SUSE Linux Products GmbH10U Build Team10 *H   build@suse.de0U0  *H  ��,ZYIQc')Ӟ?$wA_!:^  y p"!&{;>Nt͑Wz*YD =tM(ˍ nM% 27O5y{NV9<_"X$3b^L}$xJ ̘Ji!tHBvHƍbs IW|}vve9V$?[\-\IM9p!1ô5akN���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/keys/altlinux.cer���������������������������������������������������������������������0000664�0001750�0001750�00000001377�12626644770�016646� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������00 �ep6,0  *H �010U ALT Linux0 130105181950Z 230103181950Z010U ALT Linux0"0  *H ��0 � ,) qu}ZoC O淤tO5#ZpUDi%7wo,↤ũ2BC ?͉aЕLì+d1_Yшi;: 嗀=ۧ΋p`Va!M=@X7ۍcFCeg H*i_8]nG*wowC16fMy6|*㍓P"p}abjNRO qG?v&5YצP2bK0�P0N0U)'=%?u0U#0)'=%?u0 U00  *H ��uvý<8ŽPu"uM h\2C{C൲gjwn\E^Z"jZhVQA7ܿTTSN5ucdGNH|5j1<G;1OW#WN?eӆ7ˀKM!kV  _oX쏜~H' ~?({=]VH_JKY,FofAC>B=ͣp q~#yB�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/keys/microsoft-pca-public.der���������������������������������������������������������0000664�0001750�0001750�00000002733�12626644770�021026� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������00 avV�����0  *H  �01 0 UUS10U Washington10URedmond10U Microsoft Corporation1200U)Microsoft Root Certificate Authority 20100 111019184142Z 261019185142Z01 0 UUS10U Washington10URedmond10U Microsoft Corporation1.0,U%Microsoft Windows Production PCA 20110"0  *H ��0 � . i�!i33T ҋ8-|byJ?5 pk6u1ݍp7tF([`#,GgQ'rɹ;S5|'# oFn<Aˣ?]jMi%(\6C [''x0[* k"S`,hSIah sD]}T+y5]l+\μ#on&6O'2;A,wTN\ eCmwZ$H�C0?0 +7�0U)9ėx͐O|US0 +7  �S�u�b�C�A0 U0U00U#0Vˏ\bh=[Κ0VUO0M0KIGEhttp://crl.microsoft.com/pki/crl/products/MicRooCerAut_2010-06-23.crl0Z+N0L0J+0>http://www.microsoft.com/pki/certs/MicRooCerAut_2010-06-23.crt0  *H  ��|qQyn9><Rn+?shH4M&1Fay8.Ek( L 6fj@26vZƿӬhbTlP0X|N|sWR!s4ZV ~ ?rSc=1e=BА_TGosNA@_*s!(s9_>\` QfG=*hwLb{Ǻz4KbzJ7-W|=ܸZij:ni!7ށugӓW^)9-Es[zFX^gl5?$5 uVx,Јߺ~,c#!xlX6+̤-@EΊ\k>p* j_Gc 26*pZBYqKW~!<ŹE ŕ]b֠c uw}=EWo3wbY~�������������������������������������refind-0.11.4/keys/fedora-ca.cer��������������������������������������������������������������������0000664�0001750�0001750�00000001554�12626644770�016624� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������0h0P�v0  *H  �0 10UFedora Secure Boot CA0 121207162554Z 221205162554Z0 10UFedora Secure Boot CA0"0  *H ��0 �R\>+UZh-v '']#  u]ٟp{Qt.=$xys+gJ"d &=9^RH) d!{{O@+"GN$MSZ)^}yYsܷH+pty#yOO/cMw,.ضQ6gXVЌfIܑhݜƑ[xp[WkD~FfU�00N+B0@0>+02https://fedoraproject.org/wiki/Features/SecureBoot0U#0%X3]{ ͖;B0U% 0 +0U%X3]{ ͖;B0  *H  ��7w:Aq;֛JQ ڜ#4YԚutea:+`<q:9N͗PP̶>}zzg.naWĘآdTWy Mk͘5 1`$<3PDqQ12SjAe.ϳ$؃[$tMѤ  2u>0S �~IAi_<`ؒjH?>sw?����������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/keys/README.txt�����������������������������������������������������������������������0000664�0001750�0001750�00000007214�12633414746�016001� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������This directory contains known public keys for Linux distributions and from other parties that sign boot loaders and kernels that should be verifiable by shim. I'm providing these keys as a convenience to enable easy installation of keys should you replace your distribution's version of shim with another one and therefore require adding its public key as a machine owner key (MOK). Files come with three extensions. A filename ending in .crt is a certificate file that can be used by sbverify to verify the authenticity of a key, as in: $ sbverify --cert keys/refind.crt refind/refind_x64.efi The .cer and .der filename extensions are equivalent, and are public key files similar to .crt files, but in a different form. The MokManager utility expects its input public keys in this form, so these are the files you would use to add a key to the MOK list maintained by MokManager and used by shim. The files in this directory are, in alphabetical order: - altlinux.cer -- The public key for ALT Linux (http://www.altlinux.com). Taken from the alt-uefi-certs package (http://www.sisyphus.ru/br/srpm/Sisyphus/alt-uefi-certs/spec). - canonical-uefi-ca.crt & canonical-uefi-ca.der -- Canonical's public key, matched to the one used to sign Ubuntu boot loaders and kernels. - centos.crt & centos.cer -- Public keys used to sign CentOS binaries, taken from shim-signed-0.9-2.el7.src.rpm. Note that the binary's centos.crt file was actually in .cer format, and has been renamed appropriately. The centos.crt file included here is transformed from the original file by openssl. Tested booting CentOS 7. - fedora-ca.cer & fedora-ca.crt -- Fedora's public key, matched to the one used used to sign Fedora's shim 0.8 binary. - microsoft-kekca-public.der -- Microsoft's key exchange key (KEK), which is present on most UEFI systems with Secure Boot. The purpose of Microsoft's KEK is to enable Microsoft tools to update Secure Boot variables. There is no reason to add it to your MOK list. - microsoft-pca-public.der -- A Microsoft public key, matched to the one used to sign Microsoft's own boot loader. You might include this key in your MOK list if you replace the keys that came with your computer with your own key but still want to boot Windows. There's no reason to add it to your MOK list if your computer came this key pre-installed and you did not replace the default keys. - microsoft-uefica-public.der -- A Microsoft public key, matched to the one Microsoft uses to sign third-party applications and drivers. If you remove your default keys, adding this one to your MOK list will enable you to launch third-party boot loaders and other tools signed by Microsoft. There's no reason to add it to your MOK list if your computer came this key pre-installed and you did not replace the default keys. - openSUSE-UEFI-CA-Certificate.cer, openSUSE-UEFI-CA-Certificate.crt, openSUSE-UEFI-CA-Certificate-4096.cer, & openSUSE-UEFI-CA-Certificate-4096.crt -- Public keys matched to the ones used to sign OpenSUSE; taken from openSUSE's shim 0.7.318.81ee56d package. - refind.cer & refind.crt -- My own (Roderick W. Smith's) public key, matched to the one used to sign refind_x64.efi and the 64-bit rEFInd drivers. - SLES-UEFI-CA-Certificate.cer & SLES-UEFI-CA-Certificate.crt -- The Public key for SUSE Linux Enterprise Server; taken from openSUSE's shim 0.7.318.81ee56d package. The refind.cer and refind.crt files are my creations and are distributed under the terms of the BSD 2-clause license. The rest of the files are distributed on the assumption that doing so constitutes fair use. Certainly they're all easily obtained on the Internet from other sources. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/keys/microsoft-uefica-public.der������������������������������������������������������0000664�0001750�0001750�00000003024�12626644770�021511� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������00 a�����0  *H  �01 0 UUS10U Washington10URedmond10U Microsoft Corporation1;09U2Microsoft Corporation Third Party Marketplace Root0 110627212245Z 260627213245Z01 0 UUS10U Washington10URedmond10U Microsoft Corporation1+0)U"Microsoft Corporation UEFI CA 20110"0  *H ��0 �lLE jK u CTd} s JEa-+MIA<TѝĤA\Yh2Gq!O|D?2&HuLJ~䂚xwM Ӽ+Q8]x Ճ{@{('V^~~Dy9ڲbM8ph$37Xi^|SN*caocY+y ag[^gOqX"""΋Tq�P5Xvj�v0r0 +7�0# +7kwSJ%7N&{ p0UC pO1n"0 +7  �S�u�b�C�A0 U0U00U#0EfRC~XN#U;:"j0\UU0S0QOMKhttp://crl.microsoft.com/pki/crl/products/MicCorThiParMarRoo_2010-10-05.crl0`+T0R0P+0Dhttp://www.microsoft.com/pki/certs/MicCorThiParMarRoo_2010-10-05.crt0  *H  ��5B0v hX5)F2v'|A'BJm8HYUX4 ]ڀA]PUB( Q!wsʽRP Wa m%@@ΣJMTǼ+=I+2j!iO~B46 @%u']6TzPt/k/f#DŽ3VK-hr݆,!L3+JhU2ujj<%@YѕLb"t=GD䰛45S,qȝDfGTVh>#/^Pƍ_A. lui!Mڭ,wS%27lRr5aj;PV2-B'UZ0TG%/&A\?[<>?GrU%"{*F� 5'bq'Y7`8xpLEe¶~iuYX������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/images/�������������������������������������������������������������������������������0000755�0001750�0001750�00000000000�13325167530�014562� 5����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/images/refind-banner.png��������������������������������������������������������������0000664�0001750�0001750�00000027270�12626644361�020021� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR������@���U]��� pHYs����u85���tIME 0:f;:�� �IDATx}ypםcgzGč>ML78[&ǻk]&[38ێ$&`@ `06a$[s}􌤑$ThsΡnM4M?B$IA$F_'B0UUUUUE1mtTMT ,zH Iƍ(�!p5EQdYR~#E!H ˪ZشI[fXh\CyوyY,IeYdC'shQ鴶lp-ҦMvjXa vf&({?LR#=Pvftv@N)E_�f丳L_[jV`:,˓^~TWbYDyEWD#3V,HmVR3cMXShr$8Qxi}pGO\o<ܵˆ~\jr;Iz -FBǛSuEQ̕'�`6洺7AdYl6V+Xˆ^@t#_"|{7H[E!;B,&va(٘>2"vuI*kaAMMnl0x$ItZ器tX fzU*NZm- vH'OjNe*]Hwo琪F|8g 4TRR>+VË|v]qۭ(js0'SOUDh;jտu,�dRۿΟGQUghZWRwa:Qzz=&RBwK=de`uWT?= <}ÇnpU%*$ٳo{&ych$K]ek`|99&]PU]Q~TR,%IR]'v,ۇBJ{^_X,,ϟ4Pr^lY(Lg9⌢gDb׮]?vwwp\־U;EQFFħRs{f+Z~Kˠt:,[b(ʂRkk)xmĉck0*hA$I]YQdKmrf.eY$Az! "lVOR<<oZWVUK.It-�lR tj] ҿ8<LURM[o{8e 諢(( P(vW_ ]i!dBHxEw(J/_}\xHHMBvuI|%K5iZW$I2 `Sjϗ}2\. yeYł2.QUt:N#}[ؘK,˭X!ʲ|cgو`"s Ei^o<76f֯Y6bZ 4[^;(LkpD!BU՞Ā= |;8n vKѳ rA~ʿ^N[[: >8ݎJګ:MӚϲI$Is*L7ciZOf…g6l8éhfZ|(EQ;d}MMq1ۘ˲4-roV:ghnGZ\!h�EQz{{8Ncz(o}uqd$\.qp$b>m` 'Xo~zMf 4[* 8'nguw?Mf<wU<N'1p` fv )I͓`sgX _NI̓VE^=iߘ{1+2Ln,^eY. & f,|I劬K`M8N|3S S4K%k.'ol5ϯ]\d .\x1 ~谪f`vS΢0b,FQ}p/ʡxBƅ* u-N Ss-_dDWWիWys\`A[)U�NGGG ˙P-E9sFp[&y~VaiƲBOk")I$Yu(S…X;DO?zo~2)7p8E31ft4ͥ,Xb b.zLL\3]<uZhE!e0"aE@u]dTVe >)xT*=#m۶YÇ˓xp8zM'+dY$w9x`2L$Tyh>I E9p@uWx=\5ܕ #6o&d2d892&'ݥ# tTUKgg;El�vo&`ݻwwwwT`UU}!icl]AG۶Y8h۫+j<PjmqcR7S$BQCa!:r~_ HW_}ĉ_kjjt]QM={^j0z-Yv.QL0\Z*EQ ønt:EQ%IŒ DQL~'; I&k`f`Νƿ4Z.,ˎR2gfHM4\MBAkhH@bLqHGFFo<K<O<û/xy;vL*.h k%dccQƱ S<( X5]%aԩ&2puIDQ\TŬ8OE~}rʕ*"Qe@cW*ѝ;槪Sے>eᬪjo^j `wLZ{{7l؀}x2??;vlNS+כiڥKL '* $2D'Oj4p80CYjf `&_#Dn]xXIޢ츕`juB  0Mn(\K-[=!EQofM˲,3FC>_Aw3 r1nƭ6EQ(RގZ^]5VU�T__vm6˲~mZτBɶQw@<\BxRp{Fv?= XqG4 oׯZ n$ /0::j|lxx8ϋw _*be˗P(IJl2O~2{t;I+1,V2~c|Tw7GFG>VڶMps�ܾe˖P(ȳ6MQ!mSfhB&,+<Nqr950znItDt8.;BJ]\4X;lAl޼yɒ%`@:(Ƕon|P(0gyw-WEV\ StZ7vk#H>eN!']tȷC*Zh� n:[lY8b@� �1(L~tQB!Q}B 9lX;` @K48!HӴ(== BkAgXqZjѢEh4B tr* 8+y5{bA[oUћxEUdEd`_OYQgk@J&t5}>a]1|%IF&L{<p8 1)gx>^ DQ,7?D">Iӫ44R֬Yau"W? /|.6EѤQnNfL#aJ +Jzɲ<1Q'Y.Ĭw ځ bBg9].vn�O4HrA[n3NNyT3G8E1@x< : اeڹ6igΜ1;שּׂbH0\UUw#y&+ %D W jN;M B<7=WfЀ== \0*F)i2ˣ`y! 0lfiO)Y`Ujkk!(`k|qP]v涡aҥ@�tDP!Aiia2x<dFgh.\Pr9KUt:e,[gi}}}D"�ZӴ~T&�gU4M34-y<Jw0YFGi B( nl@ �jgϞ5Z[[r|>$b;]r t#"%AAoEl_ŊݩSzE?֟fXHbB!V12f3I=^ʣnw L*J4e2c]= H7�jt5PMM 0NWڀ=1Rrj]B[( :E픃P:v)�nffl ]p02>n2cv;5ߐiW*N$UR "Xa ,].bh2&^/:,tk`Z؁kXZ[+np0v,A_\kR<^'v3/[q%Xir$cQFQIM9`I]nx<Y*ʁ2>>^*L'˝pug>8oTrwnT6GD*]O fhHx p8+V$f)34[?#J5526T tE)1S7¥"2J.IR<7X,&5q~M yR<r\4>޽;I#&xDQwdB7,y`%cbѤL{?]W\4RdJ5Z.6g0XZ8Ja]n0cazMz3)Xx?kf[,zSLl޽hr4 `ƖJo�l̝:Z} -0Ȑ_ JX<~^,[rEɭc3k qaPAHD_Foi T2<uNhgSet4Ld@ 0u}ѢE&إXhQSSu:!Q)�0ca7oN+&b߾:غ58Θ9S}cG{/?en7])3(c2îB۹},y<ɤ͚ J! ]8x&Fi5M3Ebbnjmm=p@yg9vp8>I=)?(//яL&S(DQQ1� _ZqʘsmmÐ$,P6i輘Zt(H$ XTю t+<cb`ʟь DE-BQԆ ֬Y3I@m6"س ÄB'H;B"?9LLLi[ek,(B>_ؽ;cґ#1GwB^Ҩ&{Yl6krCa0ag!w6(GrDGڂQtؚ$TTvjm/^ s۱,OuNg(§5@?;, qV9}tf+>90kΉd2N,rl6{\?~ҿ=::׭;D`uUf/n:8ա0n9Ro %be5ll jV]VF dCڌimmyԤ#mذ=}_ݴiOBKKJY[y8,pӴ`,Лo*#_I=G },e޿H$DoYK4כdx0;֬Y ^/bT˗9.p$)D*0,suu#[_ p$BϗMA֭ӜcBT"!˲ŷl\W1#Fwy+0N\0Fl>oll{ i�2J ^eK.mkkFPZ n nU޹OE|>Hng7obX, B׬kIcB!H$|>O~@ 0BL&ST&ccf[q.n!@!Jɲ0,q¦}:LӒ$A�Gq$IBz �xPx2cmENBT*=Ʈh-d#J1ZEuxR F!+vh8`V``bF l6+A^n{<).q8Hy^UUXlW@:N"<R&I6 g:uϲ$If|%Pv\(]"5FpyV;V8]?W g{4-2Lq'|>XU.P܊D`8hzwpj1Vp)8o`~�srh&Py4 1x*�@g)<ħUz(I#h*'/ɼZ'yA47[kj&OH:tp(Ze,Ys*}�j,Dd C<"{ 05Hw,>d.ja\ (inْZ>=Z,2sp%E*h+ulf9s2ȱ B�|FI )WD*]׍KX6Y,jlv;d:qK%Z-Oc(NFCJJ։ 9G|_ł矯{%ߡCYMKb23d/vZc[S').|oCJY1ܮ\x 36 quxI$Hp:55iC4Mwvfo.?nps˕PЃye@O3n,V~BALt=ݻ)A~;}. :c`@Qx<r<`3F@yA@Eg| Jx/J D+$`)aVS#]v gO#Ƃ**=2zᇇ|o_O=æ4/җ+W^yIk'^OGB{ަ&;BD"AQX@מXe[Φ]fg>Gq\p; T=ÁCDQ|SO٬Ywp83*TUOL <d_cǏbTS{�4jܕ+㍍Ttg p҉LWvWOBVmdLowog_Qm&.5+Za|W$z5+lyc!͂2S)m{#IҥDss1O︣g4r''%)Eכ{!4XWg<]C�Fa褢(~Pe,X0:He9_I SZccr:]tYKI/HGG�='tV։--?&�q\W( @nS#AlbC"Fxn.W4;ܪ_˥qsQd*O#HH˃/ug/[nKo*opt2Y`dV!:7ް{9yRdk+=qkrOﵴH#Sm4 w2 y(Z{$Hjj+|47> ݩŋ|urrmYY|1ٳv*66oڴ!Jz?sd6mh뮆{5I^ ?n3 #K;}4wBfa��KIDAT|b{FQ6I^oӲ<֖[bQe򗶡|$2e i9bڸ1|NC7 `Q"/?=7Oc9]v?K/1uw{/_⸴1si؝ebuZuvl$)wuwv=K}rJڵ1vh!ņΎE4!EQb#kn}g%;w"o@y3qU嗗2unJvY[ƺ_xAy[.j|+wy'vBP*E^{3:}#vkAiEjCW,_~nÆ%Ǐ{RUUS՚{~۸o_ͱc A:Ba^e,Bq?>v=uO=e)5&eGU~O\?Zs{p!ĉm@, '㬖[ŞLh…YOcFGBV>~=#I 6>G{h]cG>eX0?/%pܲe(С%_xZ^ߏ>%>-<8G_k8a"!_:-˲ԩ%/4x?^SSٹg,4NLLDBԧ'?;}>9nիߺD {[o't=tSjX&'Onڽ!4β˗}VfW17޸7^~܃ZB6~˗yԴߤK_ ?lų|I޳]˖zؒ/>ȗz`OsoVc>ϲFG]ǎT a:6FsXooڄjx[o!]?qիGc#݇ uuioz~2A{{Ӣf2*EC!5|aZ/_oZ嚚S32a7niZFBLFcBol:"^sjPmZҥCuuVQ'  }ҳn]EIfoā U#uuI9C+J<y}t6~&a`8ܽx1BW79. x<q+;9iP4- L&/lv42Uy-4zcŊb{X3f(ML r^/>(!\& foq8B2MJ%vl !AUteٕNgN;r�6r "K�Eti0YͲ˥;$=6&1`$b%³BIWK&BirlD <)7qbY!Y,D" BvInl Xr櫻Q8UL$!~f3Xى Dqc1stz BLBx ⷀ<^[<nΝ;]_b 8$ M$}}kz !4PSl4Bx!4РzF-\BqBh]sza K<}}KF-eKBVa /!I342R9v-I6IZz B($Jt(|`B:Q訸x1A|2p"B(v$bdRq8Hg ʼn"BhmVuD28Οx P8$Zp:BH?0\N^Pぼ("JNaCbK5v8mۣQ_{b:N׉s}}LT#>KMs#e˺WJG"9sljK^ 3*bƍm=ujAo/x\߼n_Hz~DUUC#.v8sվ{ LsK._~`ǎ+Ω 2.EQt:nXѺ:^[[d]k2x,jwݱ?u[hvJUP'N?縅 ſ@pf;(J6or! #מ{n4\#Z}b!T]O&ޱ1Pa\rN(v=^SS*Fo{I*29I'MN"]Fwߞv:zSӾ?z].p_Nqw"1TW@ <%=9|Xa6Ywzccy{>MR Bbq(Kӹs+ND./[t:?w6Kj>v8W6o~{6JW>̙ŋBPplxOVuG<vl,DӂI|4 R 'C,|0oW<^pmf&b8̹\?蕦&>oz5v'hԗ#h8B LscgԸȝNN~;~A0s_/oiF"nON'&&2,E ǐiccEPm6NiQ٬2:*dTpwϲ|L&P*$$p8 1,gY9u]$Xjl69, '[,I"85MEH-x ("B6]/ٟ~!˲J,, `a, 49NĂuX,Exre ![cNHK\il:a > G;ϳL,9$v+0Lဟ��2fyi 8A:h,2'n7tKHfb8<m T=%պgons;{~VqrN'Aۭ( NQ^4tʲB )u?�vFCJ7>&5|щ|šx(J j G#RqBL0�@Mo)Rc@�Pr p GpˤE#Wo>ys}7OvX}>y^U>" b '6 |G.6cySfkhgϲ0x>paө@N {Gafc\pD/%7f IS΋7P�1 T,[vp?x1o,^ܳv@4rBgpƼ\"\Y' Ei<GϵuuupynW}>tihkfD2i3$n6]Q-|^p?TBkO3L&l<|9{͖khy<\( p>lo}脩>aƜ$Q僒L|뇘h4UV����IENDB`����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/images/imgprepare.py������������������������������������������������������������������0000775�0001750�0001750�00000006040�12626644770�017305� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/python import sys import Image def enc_backbuffer(backbuffer): compdata = [] if len(backbuffer) == 0: return compdata while len(backbuffer) > 128: compdata.append(127) compdata.extend(backbuffer[0:128]) backbuffer = backbuffer[128:] compdata.append(len(backbuffer)-1) compdata.extend(backbuffer) return compdata def packbits(rawdata): compdata = [] backbuffer = [] while len(rawdata) >= 3: c = rawdata[0] if rawdata[1] == c and rawdata[2] == c: runlength = 3 while runlength < 130 and len(rawdata) > runlength: if rawdata[runlength] == c: runlength = runlength + 1 else: break compdata.extend(enc_backbuffer(backbuffer)) backbuffer = [] compdata.append(runlength + 125) compdata.append(c) rawdata = rawdata[runlength:] else: backbuffer.append(c) rawdata = rawdata[1:] backbuffer.extend(rawdata) compdata.extend(enc_backbuffer(backbuffer)) return compdata for filename in sys.argv[1:]: origimage = Image.open(filename) (width, height) = origimage.size mode = origimage.mode data = origimage.getdata() print "%s: %d x %d %s" % (filename, width, height, mode) basename = filename[:-4] identname = basename.replace("-", "_") planecount = 1 imgmode = 0 rawdata = [] if mode == "RGB" or mode == "RGBA": planes = [ [], [], [] ] for pixcount in range(0, width*height): pixeldata = data[pixcount] planes[0].append(pixeldata[2]) planes[1].append(pixeldata[1]) planes[2].append(pixeldata[0]) if planes[0] == planes[1] and planes[0] == planes[2]: print " encoding as greyscale" planecount = 1 rawdata.extend(planes[0]) if basename[0:4] == "font": print " font detected, using alpha-only mode" imgmode = 1 # invert all values rawdata = map(lambda x: 255-x, rawdata) else: print " encoding as true color" planecount = 3 rawdata.extend(planes[0]) rawdata.extend(planes[1]) rawdata.extend(planes[2]) else: print " Mode not supported!" continue rawlen = len(rawdata) compdata = packbits(rawdata) complen = len(compdata) print " compressed %d to %d" % (rawlen, complen) output = """static UINT8 image_%s_compdata[] = { """ % identname for i in range(0, len(compdata)): output = output + " 0x%02x," % compdata[i] if (i % 12) == 11: output = output + "\n" output = output + """ }; static BUILTIN_IMAGE image_%s = { NULL, %d, %d, %d, %d, image_%s_compdata, %d }; """ % (identname, width, height, imgmode, planecount, identname, len(compdata)) f = file("image_%s.h" % identname, "w") f.write(output) f.close() print "Done!" ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/images/back-selected-big.png����������������������������������������������������������0000644�0001750�0001750�00000010370�12626644361�020523� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR���������F�� 9iCCPPhotoshop ICC profile��HǝwTTϽwz0z.0. Qf� Ml@DEHb!(`HPb0dFJ|yyǽgs{.�$O./ 'z8WGб�x�0Y驾A@$/7z HeOOҬT��_lN:K"N3"$F/JPrb[䥟}Qd[Sl1x{#bG\NoX3I[ql2�$ 8xtr�p/8 pCfq.Knjm͠{r28?.)ɩL^6�g,qm"[Z[Z~Q7%" 3R�`̊j[~�: w!�$E}kyhyRm333: }=#vʉe tqX)I)B>== <8Xȉ9<QDhʸ8Qyl£sy0OZk(�5Hݠ>yP:8p΍Lg kk Ѐ�$t!0V87`ɀ2A. @JPA#h'@8 .: ``a!2D!UH 2 dA>P ECqB**Z:]B=h~L2  5pN:|ó@ QC !H,G6 H9R ]H/r Aw( Q(OTJCm@*QGQ-(j MF+ 6h/*t:].G7Зw7 Xa<1:L1�s3bXyeb~19 vGĩp+5qy^ oó|= ?'Htv`Ba3BDxHxE$Չ�"XA<NB%#ɐI.HtttL&kdy'|V"a$%(Q%.1(B/%$V2G\ i)SjT)aYitttUI [&_E1 BѠPX-z%8CաzQEoYeYUgdGhMEKNІh(/qZYcI˒%srrrBV;rn;)2*\RV** O(W)VSUVQPNUޯ|QyZ⨒RrVeJjU-S=.Kw'+=5%5O5ZZڼzzz# C#VL[cFSUW3WY^OWkN[G;L{vNNC]nnm=C/QM}XB?^Jl`i58`0z)oiaCaa(Ϩ腱qn^O&&I&&LeLWvjo22mN6w7hir2βZP,|-Yt[|[XNYiZE[U[ 3 F15ziw666&6N.YY^|NݎiWk7bO?d?tsxvlppsJp:ę<b+Z&V]=ν}cyOna/e/W Wx+}|a{|Z[=O>�P44077&9$An0;T2421t.54ld+s;# V]=iY9FgM֚k&=%Ō:nc1gcbcfX.}lGv{c)LŖN퉛w/p+/<j$.$%&㒣OdxTԂԑ4i3|o~C:&S@L u[Uo3C3OfIgwdO|;W-wsz 17jl8c͉̈́3+{%lKWr[ $ llGmnacOkE&EEY׾2⫅;K,KhtiN=e²{^-_V^Oo§s]?TWީrjVQ=w}`嚢zԶiו8>k׍ E  <hؤT 7 E7--֢o:}$dwZUQ ۡ΁S+Nuwv}ojȞ)9K8v\ι/]~pq==/]~bS+vWN_zZu}}m?Xo~FM]: ^zmלּ302tw8rx.佤{/gܟ!a#G叕cșQѾ'AOƞӇfܧn>[ly邟~_Y53rW򯎼^{7so}x>|쇊z>yz���bKGD������ pHYs�� �� ����tIME 0$L{��@IDATxAogfH[MGv,]a=;@/=|P-EMr2lŴpzP]=ҕ dIs{ Q)p0w| P�*K1 >4iey[>(.Y6)`=>Q`><,I/?�c3BvkՐW* yn8Ę�! qhTUXbx9d5lfKY4yYYYbI.9k<ޟdizV�6u 4} 88fa-Kӳ,OpaGƄr1}Bs\n~,f=}MB$@n`1hPլ:v\w!<KPW<zt`xհGf{itCi;0xak{0^zcЬ&y_m\C?$e# U jYY!l\tְǏIf<D,BYEpе1 <pս/'7X=SGxVid]@E~=Q殉hyhaf NzH  %@J %@J�)%@J�)RJ�)R�)RH RH  H  %@J  %@J %@J�)RJ�)R�)RH)RH RH  H  %@J %@J�)%@J�)RJ�)R�)RH RH  H  %@J  %@J %@J�)RJ�)R�)RH)RH RH  H � �5kieB:@$jQT/D3e;)| i5wu]@[ؙxY M:][-a@V3jiNz0PZaU�5"4zqL{jGs0PAs`�><^ ! :,gO]Ur<4!_cU3ylFGX BBvS,ir{4Iu=SEY^eizVH,,B\-nfhT53pكe<M~H7K ǹ,Ov_3a+@/@j@BK5}W4\]8w %Xs9#g?ozu&4p TY(נ=_ɳp 'C~X�0wqRק00yZg[YI8uzØCI<" { :/FUAKO@A~%y~g�2eZ@}VS~=Lwo 5|3=m����IENDB`������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/images/txt.pl�������������������������������������������������������������������������0000775�0001750�0001750�00000000124�13325167530�015740� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env perl foreach $i (32..126) { print chr($i); } print "?\n"; exit 0; ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/images/arrow_right.png����������������������������������������������������������������0000664�0001750�0001750�00000002604�12626644361�017630� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR���0���0���W���sBIT|d��� pHYs�� �� B(x���tEXtSoftware�www.inkscape.org<��IDAThՙoTu?Z!B!,UM "+]XӘJƕqр э Qiږ@:mt4(MP3뺸߽{{<=ɝܹw|{eP (V"A7!lpBS]�U* ъ 24:@~e3u>( >())7�BF>=>+~䁜Ԭ9'Whe.~'Ds""sIc3@Fr1Q(⎠ }Z�f hĥƇi!v\fIN W%`YjZjwEF+t1^-r( @4.q"$p`<>ڹe`> z|%aN֊,ax9؊qCOQT5QNnfz2I.0Ӫ0M'`}\!~å v]S B[xϳ"_2<ތLJ t!bT! (]Lo6y#Dk*KLC'#ER(X3N7IpͰ fϧ<U؁h!HP^&v^ xdЊV,K+ۑiar5` ++:Gjg/O'9HP;R($s<\aKdX]BԱ 蠅mxT}V%VqrW1�- IY걳ja]�iLq`qb93F؁v�1�ĘJm�(#3]Vd|9HL;2JEl㓚!G =&ax[*Rc;Ry�Qbܗ-a{Zy?iRJ�a>bIzO^ &/L(q{]7>pT\�3LKT… K`z< nKD]xRuebe�$(mruJyTj)K Kܥ.&t�,3H)8u42X}`L?7yO[~lI#e87^~Td<Yf<$ٔ(cJ% c <k҈4⹿=< SLs:5IC!?UjEҘ99e4^H#TG`tW|g7͚6bOB1U;3ھ7pofXJ�IO^{/����IENDB`����������������������������������������������������������������������������������������������������������������������������refind-0.11.4/images/refind_banner2.bmp�������������������������������������������������������������0000644�0001750�0001750�00000103466�12626644361�020157� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BM6������6���(������@������������m ��m ����������RRR:!<0 JJJiQI5@ A!>2JJJ00xx<C"B!B"B!B! ee��wwcSC#B!B!A B!F$8 ,,9D"B!B!B!B!F#) --eVF%B"B!B!B!C"7)))nn ??ꬬ˿Ӓ˿DDHH躺ϝӒL/B!B!A B!B!C"9 77EE苋Ҿ## QQ常## QQ常77iiݾWWCC##����ψ;;뻻II}}��JJ绻ˆ;;뻻ww WW㮮 ))cc߽UUHH uu ��==sscc߽II}}��JJ绻77iiݾA!A B!B!B!B!;;0,������������22˰cc$$TT""˰cc$$TT������;;칹����''��ɍ!!���� ��??꿿 ��jj99�� ��??꿿PP##PPEE\\၁������99컻 ��jj99@@��ss��������99컻 ��jj99������;;칹I0D"A B!A A C"g+ppp��yy׹¸Ø]]��nn cc�� ``����qq==뼼??��² ��;;쾾,,����JJ66''}}UU``{{55ii��ɠ��JJ66''}}UU``QQ Ĭ��ͩSSEE xxו!!ZZyy��ͩSSEE{{55ii��ɞ��qq==뼼? C#A B!B!B!E#(ZZ����##PP22##PP==��˵��WWww����QQtt��rr33{{WW%%ssccPPVV33}}WWBBʾ33��ll**��__ࡡ//,,tt))eerr22 ��__ࡡԲ%%ssccPPVV㫫==��˵I2F$C#B!B!B!D#g)QQQ έƑmm--��??ꈈTT㽽:: TT㽽:: ??BB����cc޼##``߸::HH//Ȯ##``߸:: ss٬&&ZZZZ⸸å~~&&�� ��ZZZZ⸸HH//Ȯ??F'B"B!A B!B!B! ������22zz׾pp%%WWpp%%WW¬ӵQQ��ĵ qqڔwwGG``88DD鼼HH��00GG``//��''ii PP充99^^]]຺SSZZዋ PP充9988DD鼼HH��00ﻻ¬ӵl[D"B!C"B!C"B!u0PMM##HH蘘ͺ00dd00dd}} ����uu88쿿QQuuff@@ {{ppھee%%@@ {{ww##((JJ ##JJ ##ppھee%%}} ����uu>!C"C"B!B!B!B"G"22[[ᑑϿ``��$$==^^II ooAA88``��pdB"C"C"C"B!C"?444""ъeeKK悂1188PP嬬//%%xxزTT㔔KKaa11889D#B!B!B!A F$A {{{&&SS䯯HH磣kkKK柟**��``ุMM歭zz__ǐ ��||KK柟uiG&B"B!C"B!C";::��//``߅ӣɴĽrr����rrګ��XX��hhhMJJ?629,'6'!7'"9-)<53HHHw=(B"A B!B!B!B!P rrrAA����������������))``//������55��66//WWWI#q.7:<==;85<B!B!B!B!C"? 9(!ŅZZ88KK筭IIhhԠ^\\ c'D"D$C"B!C#C"B!B!B!B!B!B!C"C"C"C#C#{3[[[yyy5&!f)A D#C"B!B!B!B"B!A B!A A B!B!B!B!B!B"E$:eeeYYYIC!A B!A B!A B!B"B!B!A B!A B!A B!A B!C"B!B!6^^^OJI^%D"B!B!B!B!B!B!B!B"B!B"B!C"B!B"B!B!B!B!B"B!B!C"9" NNNQDB4C"C#C"B!C#B"B"C#B"B!A ?>=>>A C#C#C#C"C#C#B!C#>4 QQQwidz0C"B!B!B!B!B!B!C#B!D#R4`BnP~b׉n։pщqqUN/D$A B"C"B!B!B!B!= ```~{r+D"B!B!B!B!B!B"E#=G.s´̲ժԌsgK?C"C"B!C"B!C#:uuuv8"D"B"C"B!B!B!B!B!q)rj½௝Ύx=C"B!C"B!B!C#t0444pd?B!C"C"B!B!C#9Y0"׶ڟI(B!C"B!B!B!A . ```3C!C"B"B!B"B!<<)"ͷܤ:C"B!B!B!B"6gWE$B!B!C"C#B!C">ײБ{@A B!B!B!G%4 fffH+C"B"C"C#B!D#NgggܫbFB"A B!B!B!9555N.B!B!B!C"C#9*$"ĽщqC"C"B!C"B!@ 5#eee���������������EEE@@B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!88mmB!B!B!B!B!B!B!B!)B!B!B!B!B!B!B!B!ʡNNN���������������vvv)))RRRZZZ+++ ������������������������������uE$B!B!C"C"B![$uuuݱF'A B!B!B!B!Brrr���������������llB!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!˟ЎB!B!B!B!B!B!)öö@@B!B!B!B!B!B!Бuuu���������������ddd```���������������///~~~uuu������������������������������������������t^C"C#B!C"C#B!?%̪}e?B!B!B"C"Y$ZZZ������������������B!B!B!B!B!B!..qqyyccHHB!B!B!B!FFBBB!B!B!B!B!BB˟B!B!B!B!B!B!���������������;;;������������������ !!!���������������BBBIII���������������hMD$B!B!B!B!C#0,,۔z<B"B"B!C"[%dcc���������������QQB!B!B!B!B!/»øpp;B!B!ǩB!B!B!B!B!//B!B!B!B!B!IJ���������������������������{{{AAA���������������>>>������������_AC"B"B!B!C#:CCCߡ`DAB!B"A >GGG���������������bbb{{B!B!B!B!B!&&ǩ%%B!TTȩB!B!B!B!B!B!BBB!B!B!B!B!Џ(((���������������+++������������������������������,,,���������������_?B!B!A B!C!v0QQQû䪔O0D#D!5`^^ooo���������������999ɣB!B!B!B!B!B!¸33ŲB!B!B!B!B!B!ɦhhB!B!B!B!B!iiNNN���������������ZZZ������������������������������UUU���������������sssaAB!C"C"C"D"q/TTTƸڱdžopZ{���������������B!B!B!B!B!B!Ưij``66B!B!B!B!B!ЎB!B!B!B!B!CCuuu���������������WWW���������������bbb������������������������������KKKiJC"C"C"C"C"z2HHH���������������22B!B!B!B!B!҈ɣJJ^^B!B!B!B!B!WWĴB!B!B!B!B!���������������%%% ������������///111������������������������������###v\E$B!B!C"C"=555)))���������������yyyYYB!B!B!B!B!__ӅB!B!B!B!B!11ȨB!B!B!B!B!õ���������������@@@������������kkk���������������QQQ������������ɈrE%B!A C"C"B *" RRR333RRR���������������EEEՁB!B!B!B!B!55öB!ƬB!B!B!B!B!B!ʢB!BBB!B!B!B!B!ϑ(((���������������oooxxx���������������������������:::���������������ҠF&C"C"B!B!B!@ sssJHH*x/{{{���������������ȨB!B!B!B!B!B!llB!#B!B!B!B!B!ɣWWB!hhB!B!B!B!B!kkNNN������������������������������YYYTTT���������������;;;ccc���������������kkkұZ<A B!C"B!B!d)FEE```<87?&Lq-?F$G#������������������888B!B!B!B!B!B!ϑõö˞XXB!B!;;B!B!B!B!B!mmijø˟TTB!B!ЎB!B!B!B!B!EErrr������������������LLL���������������555���������������NNN���������������BBBưБy>A B!C"B"= {{{RRR5 t0? @ B!C#C"B!F"���������������11166B!B!B!B!B!B!B!B!B!B!B!B!ccB!B!B!B!B!B!B!B!B!B!B!B!ĴB!B!B!B!B!���������������������,,,bbb:::������������������������������������������欗G'B!C"B!C"E$b'///٬ъqR1B"B"C"C"B!C"C"F"���������������nnn������������TTT^^B!B!B!B!B!B!B!B!B!B!B!B!ҊB!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!÷hhh���������������BBB999������������������������������������������������������������̪˅m?C"C"C"B!D#CMMMλᤏT5B!C"B!B!C"B!F"hhh������������������ooo������ ӅB!B!B!B!B!B!#B!B!B!ɦűB!B!B!B!B!B!B!B!B!AAB!B!B!B!B!ϓQQQ������������������]]]mmm������������������JJJ<<<���������������������������������������ۚN/C"B!C"B!B!?"SSS~d[H'C"B!C"B!C"B!F"zzz```EEE***fffXXX iiiƬB!B!B!B!B!ŲFFB!ΗB!B!B!B!B!Ű÷TTB!==ɦggB!B!B!B!B!mmwww]]]BBB(((ppp444SSS```...������������������������cccϷ}d?C"B!B!B!C#<5 ;;;;31l+B"A B!B!B!C"C"F"#B!B!B!B!B!ǬĴB!HH&&@@B!B!B!B!B!ԄűB!ϑB!ȩЎB!B!B!B!B!GG���������������:::麪V8@A A B!B!B"@ X#ZZZSSS' =B"B!B!B!A B!B!B!F"88B!B!B!B!B!ssffB!//eeB!B!B!B!B!VV̝5B!ŲŲB!B!B!B!B!���������������µ粟M.C"B!A B!A B!F$9; 0">>>[[[rrr~~~~~~wwwbbbF?=,_&D"C#C"B!A B!A B"G'@E"NNB!B!B!B!B!5ՀɦȦϑpp""B!B!88{{B!B!B!B!B!B!uuˠǫ͚ԂAAB!B!B!»B!B!B!B!B!B!ʣ���������������ɷܡ<C"A B!B!B!B!C"C"<5i+U&L#O$^)v09A D#B!C"C"C"A B!B!:T;ٛG$¹B!B!B!B!B!B!B!B!B!B!B!B!B!B!AAEEB!B!B!B!B!B!B!B!B!B!B!B!B!B!B!АB!B!B!B!B!B!AAõ���������������ҳޫC#B"A B!B!B!B!C"C"A C"D"D"C!C!B!B!A C"C"B!B!C"B"B">G)ѳ詓&&B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!IISSB!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!ʡB!B!B!B!B!B!B!B!)nnn ������������������ZZZεޣS4>B!B!B!C"B!B!C"C"B!B!B!B!B!C"B!B!B!C"C"B!C"7Z8-{ZOnnnZZZEEE000999Ʒ붢t[?B!A B!B!B!C"C"A A B!A A B!B!B!B!B!B"C#7mQGܲӒzbEC"AA B!B!B!B!A B!B!A B!B!B"B"E$>B,xsƽӥە||dC">?A B!B!C"A A A B!I'E%@&zΟᥐԏwvZY;K*H'G&J(T4Z:Y;_HŭɬʩȢŞ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/images/refind_banner.bmp��������������������������������������������������������������0000664�0001750�0001750�00000063066�12626644770�020104� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BM6f������6���(������@����������f��m ��m �������������������������00xx���ee��ww���,,���--���nn ??ꬬ˿Ӓ˿DDHH躺ϝӒ���77EE苋Ҿ## QQ常## QQ常77iiݾWWCC##����ψ;;뻻II}}��JJ绻ˆ;;뻻ww WW㮮 ))cc߽UUHH uu ��==sscc߽II}}��JJ绻77iiݾ���������������22˰cc$$TT""˰cc$$TT������;;칹����''��ɍ!!���� ��??꿿 ��jj99�� ��??꿿PP##PPEE\\၁������99컻 ��jj99@@��ss��������99컻 ��jj99������;;칹�����yy׹¸Ø]]��nn cc�� ``����qq==뼼??��² ��;;쾾,,����JJ66''}}UU``{{55ii��ɠ��JJ66''}}UU``QQ Ĭ��ͩSSEE xxו!!ZZyy��ͩSSEE{{55ii��ɞ��qq==뼼���ZZ����##PP22##PP==��˵��WWww����QQtt��rr33{{WW%%ssccPPVV33}}WWBBʾ33��ll**��__ࡡ//,,tt))eerr22 ��__ࡡԲ%%ssccPPVV㫫==��˵��� έƑmm--��??ꈈTT㽽:: TT㽽:: ??BB����cc޼##``߸::HH//Ȯ##``߸:: ss٬&&ZZZZ⸸å~~&&�� ��ZZZZ⸸HH//Ȯ??���������22zz׾pp%%WWpp%%WW¬ӵQQ��ĵ qqڔwwGG``88DD鼼HH��00GG``//��''ii PP充99^^]]຺SSZZዋ PP充9988DD鼼HH��00ﻻ¬ӵ���##HH蘘ͺ00dd00dd}} ����uu88쿿QQuuff@@ {{ppھee%%@@ {{ww##((JJ ##JJ ##ppھee%%}} ����uu���22[[ᑑϿ``��$$==^^II ooAA88``�����""ъeeKK悂1188PP嬬//%%xxزTT㔔KKaa1188���&&SS䯯HH磣kkKK柟**��``ุMM歭zz__ǐ ��||KK柟���::��//``߅ӣɴĽrr����rrګ��XX�����AA����������������))``//������55��66//���ŅZZ88KK筭IIhhԠ���������������������������������������eee���������������EEE@@��������������������������������88mm������������������������������ʡNNN���������������vvv)))RRRZZZ+++ ������������������������������������������������ll��������������������������������˟Ў����������öö@@������������Бuuu���������������ddd```���������������///~~~uuu���������������������������������������������������������������������������..qqyyccHH ������FFBB����������BB˟�������������������������;;;������������������ !!!���������������BBBIII���������������������������������QQ����������»øpp��ǩ����������//����������IJ���������������������������{{{AAA���������������>>>���������������GGG���������������bbb{{����������&&ǩ%%��TTȩ���������� BB����������Џ(((���������������+++������������������������������,,,������������������ooo���������������999ɣ���������� ¸33Ų����������ɦhh����������iiNNN���������������ZZZ������������������������������UUU���������������sss������������������ ����������Ưij``66����������Ў����������CCuuu���������������WWW���������������bbb������������������������������KKK������������������22����������҈ɣJJ^^����������WWĴ�������������������������%%% ������������///111������������������������������###���)))���������������yyyYY����������__Ӆ����������11Ȩ����������õ���������������@@@������������kkk���������������QQQ���������������RRR���������������EEEՁ����������55öƬ���������� ʢ��BB����������ϑ(((���������������oooxxx���������������������������:::������������������{{{���������������Ȩ���������� ll������������ɣWW��hh����������kkNNN������������������������������YYYTTT���������������;;;ccc���������������kkk���������������������888����������ϑõö˞XX��;;����������mmijø˟TT����Ў����������EErrr������������������LLL���������������555���������������NNN���������������BBB������������������11166������������������������cc������������������������Ĵ�������������������������������,,,bbb:::������������������������������������������������������������nnn������������TTT^^������������������������Ҋ��������������������������������÷hhh���������������BBB999���������������������������������������������������������������hhh������������������ooo������ Ӆ��������������ɦű��������������AA����������ϓQQQ������������������]]]mmm������������������JJJ<<<������������������������������������������zzz```EEE***fffXXX iiiƬ����������ŲFF��Η����������Ű÷TT��==ɦgg����������mmwww]]]BBB(((ppp444SSS```...������������������������ccc�������������ǬĴHH&&@@����������Ԅű ϑ��ȩЎ����������GG���������������:::���88����������ssff��//ee����������VV̝��ŲŲ����������������������������NN����������ՀɦȦϑpp""����88{{���������� uuˠǫ͚ԂAA����»����������ʣ������������������¹����������������������������AAEE����������������������������А������������AAõ������������������&&������������������������������IISS������������������������������ ʡ��������������nnn ������������������ZZZ���nnnZZZEEE000999��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/images/refind_banner.odt��������������������������������������������������������������0000664�0001750�0001750�00000021025�12626644770�020101� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PK����j@^2 '���'������mimetypeapplication/vnd.oasis.opendocument.textPK��j@������������ ���content.xmlX[o6~߯T`o2c5v+PP̎"5Cǖ+À!ysw.rn_dGfR&M `Z77ww,y!I[Sa2" h {*m%LT䲡bct|m|چTe=O=;p](MUX 5V/TY)bϙsniru˙T"' kZ rji4рS8$OTM|U&WĮl\|e1="َ֭ z�T=՗QEk&ӣc})e*u.nn^#Ex*p9 i#@dtg4%B(,.FMli mxfF$h# Ĕ&dkbۚJY(Dxَ<\ȁB2ʇ. 8tPI0HMiZ5Nل>6I}uV`A57HB z| h6Jβp(l'~mOJUɣ<l�?q#8&Sbsˎ?n~JZͨt dO'.MXz};㳊 ( C`L@k1q~#T(#f +~F!>:૏ W 7A�zqW`U᠔5TUPJ0g4+]^K +Qb#ҝvd0"\#?'+&/K펲j Itk#`):*z`2{mNt?j=`"/C)Dr OWey?iB~IpOgv?1eN8=YYzB<}4jW _an&n`8Y 4;q?8)1^el3\Y^kux>BkG`q :Y0kQEj \oIJB]tTZh)PKv$����PK���j@O����� ���manifest.rdfAN0E=i tA5I#OqH{{L  ޟq?={:t%OŎ3 ֝kK>&jSQ#iG*J~ aT�<9[H<)H>'0V8JS]oWTj4$PSG -LGM 0ؠf{#S(9-PVT4`]z_=K{YX'Mڇ[.Dg_?z$,-ҾU-`jPK��j@������������ ���styles.xmlZK6W -8Ahl 4^Z,&(ίeڦng�? _zGe2Ɠ`Dʘ%\/OwY//YҘ,)%r1R, qԼ\0,X b!Hi.B2#ZPqJKr/ +=YnY3 Pa )*|/r2’xq2Ȥa4͸3|jjpU55W$'ʘqZނH<?TŊ`fUlփ3b&0yz/{YϜ[ nrCm)=bNanW1ֹLjweh~;ISIdqwE!p Qij WUIŸI7(@gڕW&ղyxYJ m(i^CھjQ\HKJ@Zexҫ5-P YNyGʶAOqLPB\ziʳ e"}i5 FPv+&~?3Q]QCl0:wwoGoH)V]6 \Z=6hMJ)To=ڵ?-8dM /zg�b+$))KvlR Iq[qq8oTq(.)LZ" kDe0G,0s.aA$$*Æ�eo� wty{==im! mVsC9XHGL$ aUNJ [!a򥥨uD9Wsj/!hռvԍ:i} s*2]}M-Pc3H^CgNHoi41!Rꁘե>v %Jx]7 (N-Vs+*oV,c}j5:;һνRnDȲmR/k(IXi_A` ڹ?0ߪem6@(!nᄴ Y*#|z+�]<"yY~f)6[KOm˲VH9Fl8L<N LK6GLnXP!f細c+UAd JT~aYs`FJ+!lMdz24  )< z; AJX'N1])U w0y:bC @VuZ7aŤTx24^K�[PWqZF;hy\{|o*%y U|C'ru&h䒟2&upayL '4W*OT[\^_8p2Efқ?nMыWKiƔ#` '!NRk#[Q}TGX-( %8`Ɇ-1�Ϯ{27"ˠ_+zKb%ч b xdu|jXZz05$ADXXxU_2@@rJ˾C.P0ҏs`|qf_`|90<3{0c|_7=1y Y3?Ƴ0`<c<ggqE8=Bw܃؏Y0&gA'ȗL2QG@a5eL߾IX͛絺opח9ê}~3!)>A^!gn^#yj2C!s_ݫV"oazNU{Mihu=TQopv�O")~*>ꠏ+ ֝vtkj(uE<Q^:Mfwq+F �TJ RY;x2qYhE�1-.3Nի'_j!M1*=uc:WFz?u8=[BE*M'-\v@}PK';c��)��PK����j@A3�������meta.xml<?xml version="1.0" encoding="UTF-8"?> <office:document-meta xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:grddl="http://www.w3.org/2003/g/data-view#" office:version="1.2" grddl:transformation="http://docs.oasis-open.org/office/1.2/xslt/odf2rdf.xsl"><office:meta><meta:creation-date>2012-03-09T16:15:06</meta:creation-date><dc:title>Default</dc:title><meta:editing-duration>PT4M39S</meta:editing-duration><meta:editing-cycles>3</meta:editing-cycles><meta:generator>OpenOffice.org/3.3$Unix OpenOffice.org_project/330m20$Build-9567</meta:generator><meta:initial-creator>Rod Smith</meta:initial-creator><dc:date>2012-03-09T22:40:29</dc:date><dc:creator>Rod Smith</dc:creator><meta:document-statistic meta:table-count="0" meta:image-count="0" meta:object-count="0" meta:page-count="1" meta:paragraph-count="2" meta:word-count="3" meta:character-count="21"/><meta:template xlink:type="simple" xlink:actuate="onRequest" xlink:title="Default" xlink:href="../../../../../.ooo3/user/template/Default.ott" meta:date="2012-03-09T16:15:05"/></office:meta></office:document-meta>PK��j@���������������Thumbnails/thumbnail.png sb``p 8ty .!sΛ(O\FL`GEO|^eZ#I."E ='FlT[9 |~cig׌%?U|g,%oζ͎]*/{^pY V|e׿3m[dkߖ8Kqe<Mc$%6sbN>d$_ɓ޸uC>|,#a'5<h{w•J syZm=E$ip"|[(dI^%us�:&�PK2g����PK���j@�����������'���Configurations2/accelerator/current.xml�PK����j@���������������Configurations2/progressbar/PK����j@���������������Configurations2/floater/PK����j@���������������Configurations2/popupmenu/PK����j@���������������Configurations2/toolpanel/PK����j@���������������Configurations2/menubar/PK����j@���������������Configurations2/toolbar/PK����j@���������������Configurations2/images/Bitmaps/PK����j@���������������Configurations2/statusbar/PK��j@������������ ���settings.xmlZrH}߯pP6)CB 8 50ѴjfdGCf(ӗӧ[+(Qzw24}nqbD ͹c}FKnzMdd ܾ|t3U]Y ._n1qRY.OZѨw(g|~M}!3&UVV/+w{old?@d}slMHekޡzW&{;fr7}Nj[n\&fqPvq8M7akj^LxfY09a(IeTtd[R'}Ƅ>Zys.CXA9Cաǹ6 :MuqyruUTzI%^QnԫחNFc0ʭD&$j7 >!ADr˒F|)eAc{`® L?p=`ET bZtW_\ wv @!AuFc0n~o0r sX�27Q߃L$ R:mlɟ0H^*4T]T[}bOq!~rJ^ a '~!pu撩W9Rԗ(6kG*F qQD);f=}wG(l&2ϊ9=Dq,O|LbiucXe`VJr.QA+mbGT|L)T^F1&*, Qiߌ Ext9ez:+M Y]˰-|glu!RI5䷞3E#\^]zܧWCF_@Ap;|D=ц6 mŁJsV>lܜd x�m5C1Q&68)g"OPeE ݄6꘨J1>hxEhKrүT`$\ GDn,^Дlo]S]Fo9OJ6 ^ =_}B1_T{q |t%V%}M4.vl^){Rvv"hwѦ}l  |Vurv6P/}֋5łp0Eb#[LfBbaoh5C&\v(6'z6dmPm)pSl.wKMj!<iՁO~KF9B ƹݺ'\hD}~d߱#P8Y6MXs?TW#PK{S'�� ��PK��j@���������������META-INF/manifest.xmlMn 9Ŷ2YUVH x `׎mӪ7,V{k?PFcW[VJ-DN߇<Y X9uPZyƩd_ JYq@CqF˒j&7ZI}6`O{|&cJ/i[3M'r`c;-4ï5G{8X $'@d7(NC7.WR8^j .BPn"ĸZ$A.'O/L`<۹޳DJ}jdaG+&>OlܷQϕ!~tPK!F_��$��PK�����j@^2 '���'��������������������mimetypePK���j@v$���� �������������M���content.xmlPK����j@O����� ���������������manifest.rdfPK���j@';c��)�� ���������������styles.xmlPK�����j@A3����������������� ��meta.xmlPK���j@2g�������������������Thumbnails/thumbnail.pngPK����j@�����������'���������������Configurations2/accelerator/current.xmlPK�����j@���������������������������Configurations2/progressbar/PK�����j@���������������������������Configurations2/floater/PK�����j@�������������������������;��Configurations2/popupmenu/PK�����j@�������������������������s��Configurations2/toolpanel/PK�����j@���������������������������Configurations2/menubar/PK�����j@���������������������������Configurations2/toolbar/PK�����j@���������������������������Configurations2/images/Bitmaps/PK�����j@�������������������������T��Configurations2/statusbar/PK���j@{S'�� �� ���������������settings.xmlPK���j@!F_��$�����������������META-INF/manifest.xmlPK������p�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/images/arrow_left.png�����������������������������������������������������������������0000664�0001750�0001750�00000002751�12626644361�017450� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR���0���0���W���sBIT|d��� pHYs�� �� B(x���tEXtSoftware�www.inkscape.org<��fIDAThk\ό*_%VȢvȣn\Yrӆik2y.}Rh B@^Z'~i\QB.TiJH:}sF{#iFJ, ^>{+Egw�^0-<((2W<\6C5e՛я{<{XsW|A?0`I_7 $/9Ce)SrMI[dJ/�Q]Ђj̴ ZR):G= {o:e;{ЅӁQrB@:OO/+:`N h@@d鼌 .8mkۑKO�v JF7F|W)hӶ- $<aOw ]Euӣ, 9ϻ9ŝ|�Kҿ7e¨n8kʆ=F[,f#{ٗbX@e6 7PT o(UMvӰk yW�na΋1nN-讟tK{kw2�i[^uȼiYp rZKh!@zRi3tuEսy'+-F~鼓3 x]egܽp[eC*"]E\@"?g'7Uc,dѤK>To^2YnV9<-첓FnBd͸-_UEY2c”)CwXQO;x`֤sΩ/Zn45G5XKwW՜6�kXѾ?<J OwԜT?X Ӂ'P}%{>pYM2z$םF2c_A5ᶷìI>oPJq ,t% GU3jL@?@�D($ b? -EuIcf\t̉~nD[xpnHmX3ur]䜋.8P덽(k^@:ɪY[ocќIgUV-DR"ϛ!PLՊͲJ�تyQӞUi}d:D3de#{PXVܵՌVsĉog=Bߪ[U<;uϬΛR5FS k#Vἑj9�XnAPG~x $.uJO|l6RG}E3W @&Yeeqm{9#'/di o:.wxĔl$J�j vQ3_G?>)@v%lh(ݓS.nJ'Qw'3 aHaI͓d! m?ז E����IENDB`�����������������������refind-0.11.4/images/refind-banner.svg��������������������������������������������������������������0000664�0001750�0001750�00000034223�12631667061�020026� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" standalone="no"?> <!-- Created with Inkscape (http://www.inkscape.org/) --> <svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="420" height="128" id="svg12874" version="1.1" inkscape:version="0.48.4 r9939" inkscape:export-filename="/home/rodsmith/programming/refind/current/images/banner-refind-white.png" inkscape:export-xdpi="39.483315" inkscape:export-ydpi="39.483315" sodipodi:docname="banner-refind-06-color-allwhite-shadow.svg"> <defs id="defs12876"> <filter id="filter16789" style="color-interpolation-filters:sRGB;" inkscape:label="Drop Shadow"> <feFlood id="feFlood16791" flood-opacity="0.7" flood-color="rgb(0,0,0)" result="flood" /> <feComposite id="feComposite16793" in2="SourceGraphic" in="flood" operator="in" result="composite1" /> <feGaussianBlur id="feGaussianBlur16795" in="composite" stdDeviation="3" result="blur" /> <feOffset id="feOffset16797" dx="3" dy="3" result="offset" /> <feComposite id="feComposite16799" in2="offset" in="SourceGraphic" operator="over" result="composite2" /> </filter> <filter id="filter16801" style="color-interpolation-filters:sRGB;" inkscape:label="Drop Shadow"> <feFlood id="feFlood16803" flood-opacity="0.7" flood-color="rgb(0,0,0)" result="flood" /> <feComposite id="feComposite16805" in2="SourceGraphic" in="flood" operator="in" result="composite1" /> <feGaussianBlur id="feGaussianBlur16807" in="composite" stdDeviation="3" result="blur" /> <feOffset id="feOffset16809" dx="3" dy="3" result="offset" /> <feComposite id="feComposite16811" in2="offset" in="SourceGraphic" operator="over" result="composite2" /> </filter> <filter id="filter16813" style="color-interpolation-filters:sRGB;" inkscape:label="Drop Shadow"> <feFlood id="feFlood16815" flood-opacity="0.7" flood-color="rgb(0,0,0)" result="flood" /> <feComposite id="feComposite16817" in2="SourceGraphic" in="flood" operator="in" result="composite1" /> <feGaussianBlur id="feGaussianBlur16819" in="composite" stdDeviation="3" result="blur" /> <feOffset id="feOffset16821" dx="3" dy="3" result="offset" /> <feComposite id="feComposite16823" in2="offset" in="SourceGraphic" operator="over" result="composite2" /> </filter> </defs> <sodipodi:namedview id="base" pagecolor="#c0c0c0" bordercolor="#666666" borderopacity="1.0" inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:zoom="1.3671875" inkscape:cx="221.54507" inkscape:cy="58.078242" inkscape:current-layer="layer1" showgrid="true" inkscape:document-units="px" inkscape:grid-bbox="true" inkscape:window-width="1108" inkscape:window-height="979" inkscape:window-x="319" inkscape:window-y="25" inkscape:window-maximized="0" /> <metadata id="metadata12879"> <rdf:RDF> <cc:Work rdf:about=""> <dc:format>image/svg+xml</dc:format> <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> <dc:title></dc:title> </cc:Work> </rdf:RDF> </metadata> <g id="layer1" inkscape:label="Layer 1" inkscape:groupmode="layer" transform="translate(0,64)"> <g id="g14396" transform="translate(-3.0027063,-3.0672157)" style="filter:url(#filter16789)"> <path sodipodi:end="6.3137247" sodipodi:start="0.038057173" transform="matrix(0.92479648,0,0,1.0146143,3.6793308,-74.868835)" d="m 114.23105,62.798281 a 7.0144992,5.8831286 0 1 1 0.002,-0.0442 l -7.01122,-0.179639 z" sodipodi:ry="5.8831286" sodipodi:rx="7.0144992" sodipodi:cy="62.57444" sodipodi:cx="107.22163" id="path13770" style="fill:#0000bc;fill-opacity:1;stroke:#0000bc;stroke-opacity:1" sodipodi:type="arc" /> <path inkscape:transform-center-y="-2.717824" inkscape:transform-center-x="2.2822755" transform="matrix(-0.36198059,-1.0983946,1.2009376,-0.52324781,92.632403,-15.195328)" d="M 25.234285,15.542856 13.408625,14.102867 1.5350652,13.13418 8.6949622,3.6128532 15.47065,-6.1856079 20.136412,4.7757081 z" inkscape:randomized="0" inkscape:rounded="0" inkscape:flatsided="false" sodipodi:arg2="1.6720838" sodipodi:arg1="0.62488624" sodipodi:r2="6.6397543" sodipodi:r1="13.753239" sodipodi:cy="7.4971428" sodipodi:cx="14.08" sodipodi:sides="3" id="path13768" style="fill:#0000bc;fill-opacity:1;stroke:#0000bc;stroke-opacity:1" sodipodi:type="star" /> <path sodipodi:end="6.3137247" sodipodi:start="0.038057173" transform="matrix(1.0623728,0,0,1.0939231,-25.695042,-96.297006)" d="m 128.90965,140.02735 a 6.4000001,6.1257143 0 1 1 0.002,-0.046 l -6.39702,-0.18705 z" sodipodi:ry="6.1257143" sodipodi:rx="6.4000001" sodipodi:cy="139.79428" sodipodi:cx="122.51428" id="path13774" style="fill:#0000bc;fill-opacity:1;stroke:#0000bc;stroke-opacity:1" sodipodi:type="arc" /> <rect transform="matrix(0.87626487,-0.48182972,0.50478347,0.86324599,0,0)" y="62.893646" x="54.812462" height="36.635689" width="13.590784" id="rect13772" style="fill:#0000bc;fill-opacity:1;stroke:#0000bc;stroke-width:0.97056359;stroke-opacity:1" /> <path transform="translate(0,-64)" inkscape:connector-curvature="0" id="path14394" d="M 62.24715,93.833652 C 44.041938,92.252582 28.546517,79.385025 23.734015,61.851955 22.501283,57.360822 22.301415,55.744916 22.29782,50.240526 22.294225,44.735665 22.524224,42.859657 23.75127,38.385327 28.007142,22.866603 41.06795,10.600982 56.852864,7.2990704 63.103797,5.9914908 69.776278,6.0487609 75.778578,7.4615104 83.004074,9.1621606 89.298831,12.39401 94.931372,17.294921 l 1.507079,1.311319 -4.873168,4.875923 -4.873169,4.875922 -1.296768,-1.097309 c -6.117882,-5.17688 -14.176954,-7.796403 -21.868196,-7.108048 -6.678051,0.597677 -12.12638,2.835457 -17.21195,7.069426 -8.343558,6.946394 -12.204448,18.453055 -9.850305,29.356991 1.730081,8.013399 6.921261,15.163838 14.115881,19.443507 4.268634,2.539167 8.875228,3.870069 14.059767,4.062041 7.738606,0.286543 14.749025,-2.096311 20.646607,-7.017823 5.644445,-4.710268 9.670531,-12.247325 10.415034,-19.497527 0.08051,-0.784007 0.193121,-1.47221 0.250249,-1.52934 0.13361,-0.133608 13.406277,0.33269 13.643537,0.479329 0.44025,0.27209 -0.49058,6.224421 -1.54774,9.897282 -2.3965,8.326113 -7.67389,16.284899 -14.40898,21.730061 -8.822615,7.132884 -20.238599,10.655628 -31.3921,9.686977 z" style="fill:#0000bc;fill-opacity:1;stroke:#0000bc;stroke-width:0.18285714;stroke-opacity:1" /> </g> <g id="g16653" transform="translate(1.4628571,-2.1942857)" style="filter:url(#filter16801)"> <path d="m 147.4908,-25.683422 0,-0.552 c 0,-3.311997 -1.472,-4.416 -4.14,-4.416 -3.67999,0 -5.612,1.748004 -6.256,5.796 l -5.704,34.6839995 c -0.092,0.5519995 -0.092,1.0120005 -0.092,1.4720005 0,3.035997 1.74801,4.876 4.876,4.876 3.496,0 5.428,-2.116005 6.164,-6.3480005 l 3.036,-17.664 c 1.288,-7.6359925 2.11601,-11.2240005 8.188,-11.8679995 2.3,-0.276 5.06001,0.275998 7.544,-1.288 1.748,-1.103999 2.76,-2.852003 2.76,-4.968 0,-3.311997 -1.932,-4.968 -5.796,-4.968 -4.13999,0 -7.636,1.748003 -10.58,5.244" style="font-size:92px;font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:ITC Benguiat Gothic;-inkscape-font-specification:ITC Benguiat Gothic Bold Italic" id="path16377" inkscape:connector-curvature="0" /> <path d="m 176.97393,4.8605775 3.68,-22.3559995 22.08,0 c 5.70399,0 8.28,-1.748005 8.28,-5.98 0,-3.127997 -1.84001,-4.416 -5.796,-4.416 l -22.816,0 1.38,-7.912 21.804,0 c 5.79599,0 8.648,-1.932005 8.648,-5.98 0,-3.495997 -1.93201,-4.784 -6.072,-4.784 l -25.944,0 c -6.44,0 -8.556,1.472005 -9.476,6.992 l -8.004,47.4719995 c -0.184,0.9199991 -0.184,1.6560008 -0.184,2.3920005 0,4.415995 2.944,5.612 8.832,5.612 l 24.84,0 c 5.05999,0 8.096,-2.576005 8.096,-6.6240005 0,-2.8519971 -2.02401,-4.416 -5.888,-4.416 l -23.46,0" style="font-size:92px;font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#0000bc;fill-opacity:1;stroke:none;font-family:ITC Benguiat Gothic;-inkscape-font-specification:ITC Benguiat Gothic Bold Italic" id="path16379" inkscape:connector-curvature="0" /> <path d="m 232.22424,-17.495422 18.032,0 c 5.704,0 8.372,-1.748005 8.372,-5.98 0,-3.127997 -1.932,-4.416 -5.888,-4.416 l -18.768,0 1.38,-7.912 18.216,0 c 5.79599,0 8.74,-1.932005 8.74,-5.98 0,-3.495997 -1.932,-4.784 -6.072,-4.784 l -22.448,0 c -6.43999,0 -8.556,1.472005 -9.476,6.992 l -8.28,48.8519995 c -0.092,0.6439994 -0.184,1.1960005 -0.184,1.7480005 0,3.311996 1.84,5.06 5.244,5.06 4.048,0 5.796,-2.208005 6.624,-6.8080005 l 4.508,-26.7719995" style="font-size:92px;font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#0000bc;fill-opacity:1;stroke:none;font-family:ITC Benguiat Gothic;-inkscape-font-specification:ITC Benguiat Gothic Bold Italic" id="path16381" inkscape:connector-curvature="0" /> <path d="m 264.01312,9.2765775 c -0.092,0.6439994 -0.184,1.2880005 -0.184,1.8400005 0,3.219996 1.748,4.968 4.876,4.968 4.41599,0 6.164,-2.024005 6.992,-6.8080005 l 8.464,-50.0479995 c 0.092,-0.46 0.092,-0.920001 0.092,-1.38 0,-2.943998 -1.84001,-4.692 -5.244,-4.692 -3.68,0 -5.98,2.116004 -6.624,6.072 l -8.372,50.0479995" style="font-size:92px;font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#0000bc;fill-opacity:1;stroke:none;font-family:ITC Benguiat Gothic;-inkscape-font-specification:ITC Benguiat Gothic Bold Italic" id="path16383" inkscape:connector-curvature="0" /> <path d="m 304.19555,-25.407422 c 0.092,-0.368 0.092,-0.736001 0.092,-1.012 0,-2.759998 -1.748,-4.324 -4.692,-4.324 -3.95599,0 -5.98,1.748004 -6.624,5.888 l -5.796,34.6839995 c -0.092,0.5519995 -0.092,1.0120005 -0.092,1.4720005 0,3.035997 1.84001,4.876 4.968,4.876 3.496,0 5.428,-2.116005 6.164,-6.3480005 l 3.22,-18.952 c 1.288,-7.5439925 5.79601,-11.8679995 12.144,-11.8679995 4.508,0 6.716,2.116004 6.716,6.256 0,0.827999 -0.092,2.392002 -0.46,4.508 l -3.22,20.0559995 c -0.092,0.4599995 -0.092,0.9200005 -0.092,1.3800005 0,2.943997 1.93201,4.876 5.152,4.876 3.404,0 5.428,-2.024005 6.164,-6.2560005 l 3.68,-21.9879995 c 0.276,-1.839999 0.368,-3.680002 0.368,-5.52 0,-7.911993 -5.52001,-13.156 -13.984,-13.156 -4.69199,0 -9.108,1.840003 -13.708,5.428" style="font-size:92px;font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:ITC Benguiat Gothic;-inkscape-font-specification:ITC Benguiat Gothic Bold Italic" id="path16385" inkscape:connector-curvature="0" /> <path d="m 372.51418,-20.531422 -4.232,25.8519995 c -2.668,0.1839999 -4.784,0.184 -6.348,0.184 -8.09599,0 -11.776,-1.8400057 -11.776,-7.544 0,-10.1199895 8.46401,-18.1240005 22.356,-18.4919995 m 1.656,-9.844 -0.736,0 c -8.73999,0 -15.82401,1.656003 -21.068,4.968 -8.83199,5.519994 -14.26,15.088009 -14.26,24.47199955 0,5.97999405 2.392,10.94800345 6.808,13.98400045 3.40399,2.299997 8.64801,2.852 16.1,2.852 l 11.684,0 c 3.31199,0 5.244,-1.840004 5.888,-5.52 l 8.832,-52.624 c 0.092,-0.552 0.092,-1.012001 0.092,-1.472 0,-2.851998 -1.748,-4.416 -4.968,-4.416 -3.312,0 -5.52,1.932003 -6.164,5.428 l -2.208,12.328" style="font-size:92px;font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:ITC Benguiat Gothic;-inkscape-font-specification:ITC Benguiat Gothic Bold Italic" id="path16387" inkscape:connector-curvature="0" /> </g> <text xml:space="preserve" style="font-size:36px;font-style:italic;font-variant:normal;font-weight:600;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#ff0000;fill-opacity:1;stroke:none;font-family:BouganSSi;-inkscape-font-specification:BouganSSi Semi-Bold Italic;filter:url(#filter16813)" x="260.42313" y="49.695934" id="text16353" sodipodi:linespacing="125%"><tspan sodipodi:role="line" id="tspan16355" x="260.42313" y="49.695934">Boot Management</tspan></text> </g> </svg> �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/images/back-selected-small.png��������������������������������������������������������0000644�0001750�0001750�00000007340�12626644361�021075� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR���@���@���iq�� ;iCCPPhotoshop ICC profile��HwTSϽ7PkhRH H.*1 J�"6DTpDQ2(C"QDqpId߼y͛~kg}ֺ�LX Xňg` �l�pBF|،l *?�Y"1�P\8=W%Oɘ4M0J"Y2Vs,[|e92<se'9`2&ctI@o|N6�(.sSdl-c(2-y�H_/XZ.$&\SM07#1ؙYr�fYym";8980m-m(]v^DW~ �emi�]P`/�u}q|^R,g+\Kk)/C_|Rax8t1C^7nfzDp 柇u$/ED˦L L[B@ٹЖX!@~�(* {d+} G͋љς}WL$cGD2QZ4 �E@@�A(q`1D `'u46ptc48.`R0) @Rt CXCP%CBH@Rf[(t� CQhz#0 Zl`O828.p|O×X ?:0FBx$ !i@ڐH[EE1PL ⢖V6QP>U(j MFk�t,:.FW8c1L&ӎ9ƌaX: rbl1 {{{;}#tp8_\<N+UZp'pWpeF|~?!( HB*a-F8KKxA$NpXI<D<O%%QHf$6)$!m!'"" Fdr<YLBn&!'Q*X*(V+(t*\QxW4TT\XxDqH^HQZTtTҴ2UF9T9CyrG,ňCQ((g(cTOeSuFY8 C3Rioh)JJJq)2au;U-UOU&6+yJFީ3}Էw@iikj8tm9ք54#4WhМҪ:TCUMGCc ÓΨd1t5uu%3zzQzzz ,$S:! ,]b6u=2V307n5kB6q7Yf`rc2M3mz 67K112͇-NBLӓleZ-- -,YX[mhmonh}džbhShc󫭙-׶\\߹v}ngnǷcwӞjbȡa1ѱ cmfwB;y9v:Y|KKˣy獹r\]n DnRw]w{}GDŽgAg^^"lgJ)oϻ{ЇSsW7ٷwo)6Z܀怩@}AAA͂E=!pH` wЀŒÖ}  aQѿ`ɂ"""DDIz_xǔHcbW^ӈuc,ܹp<>8"Ey.,X%%Gщ1-9ҀKl.oo/O$&'=JvMޞ<RTT ֥N M۟)=&=qTH 232̳˜\6% 5eCً4ԀD^2S&7:Hr0o`M'}^Z][[`tUЪzW.Z=óik(.,/|.f]OVњ~[E76lۈ(8iMKx%KK+JonW_}ڒe̡lVVܷ(W./scGɎ;PaWQKKZ\]eP}uJHWM{f׻yVUWZn`z}}96F7I~~遈}͎--epu`xlo$A{}g]m\9Օ%>xǥ{=Vs\x ‰N柜>ucKz=s/ol|ϝ?y ^d]ps~:;/;]7|WpQoH!ɻVsnYs}ҽ~4] =>=:`;cܱ'?e~!ańD#G&}'/?^xI֓?+\wx20;5\ӯ_etWf^Qs-mw3+?~O~T/���bKGD������ pHYs�� �� ����tIME) `_��&IDATxk$EM:As+̀+???bަV؃`FB0&:33ë]]e%tJ}{x:x?�{E3` ~]xM7% *`7{ Bxnj ";p7OCO�U0y �d<b͹8!d_8? U* MJ90]`!! =h;~noqbb !qD+g"!`sýC'"`v9j!`FA7H4̉�Sy=3 0n~{e*.;`;F&{$"P~#�a7AŸ[Muߐq-@ }8*ݩsޥ97M"$4(sBDNQY=6<7B紹[8ym,Юuݔw T<BMfU51�Bh_,/<y׻Dސ`3Nȵ&Y06l2r.$H6t鼿*q 7t븴ukt P(]@i.4zJP� (^F/@Jt P(]@i.4zJP� (^F/@J#lM`*q`2]F\  BC]CZwi0޿,Lϊ$7 R'<*rB^sEk.aӑw3iN÷h8@sB /P.sډzp[DNs(yo&;t!"�8ŝxqBRd2if' �`ஈДt:T䡩{�ρrT!&-z("}Zk 8i"B!˂'1GdN EgZ!m !<I7]#G|~Bxn?!yvQ����IENDB`������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/images/mkegemb.py���������������������������������������������������������������������0000775�0001750�0001750�00000011647�13137114160�016551� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env python import sys, os.path import Image def enc_backbuffer(backbuffer): """Helper function for RLE compression, encodes a string of uncompressable data.""" compdata = [] if len(backbuffer) == 0: return compdata while len(backbuffer) > 128: compdata.append(127) compdata.extend(backbuffer[0:128]) backbuffer = backbuffer[128:] compdata.append(len(backbuffer)-1) compdata.extend(backbuffer) return compdata def compress_rle(rawdata): """Compresses the string using a RLE scheme.""" compdata = [] backbuffer = [] while len(rawdata) >= 3: c = rawdata[0] if rawdata[1] == c and rawdata[2] == c: runlength = 3 while runlength < 130 and len(rawdata) > runlength: if rawdata[runlength] == c: runlength = runlength + 1 else: break compdata.extend(enc_backbuffer(backbuffer)) backbuffer = [] compdata.append(runlength + 125) compdata.append(c) rawdata = rawdata[runlength:] else: backbuffer.append(c) rawdata = rawdata[1:] backbuffer.extend(rawdata) compdata.extend(enc_backbuffer(backbuffer)) return compdata def encode_plane(rawdata, planename): """Encodes the data of a single plane.""" rawlen = len(rawdata) compdata = compress_rle(rawdata) complen = len(compdata) print " plane %s: compressed %d to %d (%.1f%%)" % (planename, rawlen, complen, float(complen) / float(rawlen) * 100.0) return compdata ### main loop print "mkegemb 0.1, Copyright (c) 2006 Christoph Pfisterer" planenames = ( "blue", "green", "red", "alpha", "grey" ) for filename in sys.argv[1:]: origimage = Image.open(filename) (width, height) = origimage.size mode = origimage.mode data = origimage.getdata() print "%s: %d x %d %s" % (filename, width, height, mode) (basename, extension) = os.path.splitext(filename) identname = basename.replace("-", "_") # extract image data from PIL object planes = [ [], [], [], [] ] if mode == "RGB": for pixcount in range(0, width*height): pixeldata = data[pixcount] planes[0].append(pixeldata[0]) planes[1].append(pixeldata[1]) planes[2].append(pixeldata[2]) elif mode == "RGBA": for pixcount in range(0, width*height): pixeldata = data[pixcount] planes[0].append(pixeldata[0]) planes[1].append(pixeldata[1]) planes[2].append(pixeldata[2]) planes[3].append(pixeldata[3]) elif mode == "L": for pixcount in range(0, width*height): pixeldata = data[pixcount] planes[0].append(pixeldata) planes[1].append(pixeldata) planes[2].append(pixeldata) else: print " Error: Mode not supported!" continue # special treatment for fonts if basename[0:4] == "font": if planes[0] != planes[1] or planes[0] != planes[2]: print " Error: Font detected, but it is not greyscale!" continue print " font detected, encoding as alpha-only" # invert greyscale values for use as alpha planes[3] = map(lambda x: 255-x, planes[0]) planes[0] = [] planes[1] = [] planes[2] = [] # encode planes imagedata = [] pixelformat = "EG_EIPIXELMODE" if len(planes[0]) > 0 and planes[0] == planes[1] and planes[0] == planes[2]: print " encoding as greyscale" imagedata.extend(encode_plane(planes[0], planenames[4])) pixelformat = pixelformat + "_GRAY" elif len(planes[0]) > 0: print " encoding as true color" imagedata.extend(encode_plane(planes[0], planenames[0])) imagedata.extend(encode_plane(planes[1], planenames[1])) imagedata.extend(encode_plane(planes[2], planenames[2])) pixelformat = pixelformat + "_COLOR" if len(planes[3]) > 0: if reduce(lambda x,y: x+y, planes[3]) == 0: print " skipping alpha plane because it is empty" else: imagedata.extend(encode_plane(planes[3], planenames[3])) pixelformat = pixelformat + "_ALPHA" # generate compilable header file output = "static const UINT8 egemb_%s_data[%d] = {\n" % (identname, len(imagedata)) for i in range(0, len(imagedata)): output = output + " 0x%02x," % imagedata[i] if (i % 12) == 11: output = output + "\n" output = output + "\n};\n" output = output + "static EG_EMBEDDED_IMAGE egemb_%s = { %d, %d, %s, EG_EICOMPMODE_RLE, egemb_%s_data, %d };\n" % (identname, width, height, pixelformat, identname, len(imagedata)) f = file("egemb_%s.h" % identname, "w") f.write(output) f.close() print "Done!" �����������������������������������������������������������������������������������������refind-0.11.4/images/mkeei.py�����������������������������������������������������������������������0000775�0001750�0001750�00000013027�12626644770�016247� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/python import sys import Image def enc_backbuffer(backbuffer): """Helper function for RLE compression, encodes a string of uncompressable data.""" compdata = [] if len(backbuffer) == 0: return compdata while len(backbuffer) > 128: compdata.append(127) compdata.extend(backbuffer[0:128]) backbuffer = backbuffer[128:] compdata.append(len(backbuffer)-1) compdata.extend(backbuffer) return compdata def compress_rle(rawdata): """Compresses the string using a RLE scheme.""" compdata = [] backbuffer = [] while len(rawdata) >= 3: c = rawdata[0] if rawdata[1] == c and rawdata[2] == c: runlength = 3 while runlength < 130 and len(rawdata) > runlength: if rawdata[runlength] == c: runlength = runlength + 1 else: break compdata.extend(enc_backbuffer(backbuffer)) backbuffer = [] compdata.append(runlength + 125) compdata.append(c) rawdata = rawdata[runlength:] else: backbuffer.append(c) rawdata = rawdata[1:] backbuffer.extend(rawdata) compdata.extend(enc_backbuffer(backbuffer)) return compdata def encode_plane(rawdata, identname, planename): """Encodes the data of a single plane.""" rawlen = len(rawdata) compdata = compress_rle(rawdata) complen = len(compdata) print " plane %s: compressed %d to %d (%.1f%%)" % (planename, rawlen, complen, float(complen) / float(rawlen) * 100.0) output = """static const UINT8 eei_%s_planedata_%s[%d] = { """ % (identname, planename, complen) for i in range(0, len(compdata)): output = output + " 0x%02x," % compdata[i] if (i % 12) == 11: output = output + "\n" output = output + """ }; """ return (output, "eei_%s_planedata_%s, %d" % (identname, planename, complen)) ### main loop print "mkeei 0.1, Copyright (c) 2006 Christoph Pfisterer" planenames = ( "blue", "green", "red", "alpha", "grey" ) for filename in sys.argv[1:]: origimage = Image.open(filename) (width, height) = origimage.size mode = origimage.mode data = origimage.getdata() print "%s: %d x %d %s" % (filename, width, height, mode) basename = filename[:-4] # TODO!!!!!! identname = basename.replace("-", "_") planes = [ [], [], [], [] ] if mode == "RGB": for pixcount in range(0, width*height): pixeldata = data[pixcount] planes[0].append(pixeldata[2]) planes[1].append(pixeldata[1]) planes[2].append(pixeldata[0]) elif mode == "RGBA": for pixcount in range(0, width*height): pixeldata = data[pixcount] planes[0].append(pixeldata[2]) planes[1].append(pixeldata[1]) planes[2].append(pixeldata[0]) planes[3].append(pixeldata[3]) elif mode == "L": for pixcount in range(0, width*height): pixeldata = data[pixcount] planes[0].append(pixeldata) planes[1].append(pixeldata) planes[2].append(pixeldata) else: print " Error: Mode not supported!" continue # special treatment for fonts if basename[0:4] == "font": if planes[0] != planes[1] or planes[0] != planes[2]: print " Error: Font detected, but it is not greyscale!" continue print " font detected, encoding as alpha-only" # invert greyscale values for use as alpha planes[3] = map(lambda x: 255-x, planes[0]) planes[0] = [] planes[1] = [] planes[2] = [] # generate optimal output output = "" planeinfo = [ "NULL, 0", "NULL, 0", "NULL, 0", "NULL, 0" ] if len(planes[0]) > 0 and planes[0] == planes[1] and planes[0] == planes[2]: print " encoding as greyscale" (output_part, planeinfo[0]) = encode_plane(planes[0], identname, planenames[4]) output = output + output_part planeinfo[1] = planeinfo[0] planeinfo[2] = planeinfo[0] elif len(planes[0]) > 0: print " encoding as true color" (output_part, planeinfo[0]) = encode_plane(planes[0], identname, planenames[0]) output = output + output_part if planes[1] == planes[0]: print " encoding plane 1 is a copy of plane 0" planeinfo[1] = planeinfo[0] else: (output_part, planeinfo[1]) = encode_plane(planes[1], identname, planenames[1]) output = output + output_part if planes[2] == planes[0]: print " encoding plane 2 is a copy of plane 0" planeinfo[2] = planeinfo[0] elif planes[2] == planes[1]: print " encoding plane 2 is a copy of plane 1" planeinfo[2] = planeinfo[1] else: (output_part, planeinfo[2]) = encode_plane(planes[2], identname, planenames[2]) output = output + output_part if len(planes[3]) > 0: if reduce(lambda x,y: x+y, planes[3]) == 0: print " skipping alpha plane because it is empty" else: (output_part, planeinfo[3]) = encode_plane(planes[3], identname, planenames[3]) output = output + output_part output = output + "static EEI_IMAGE eei_%s = { %d, %d, NULL, {\n" % (identname, width, height) for i in range(0,4): output = output + " { %s },\n" % planeinfo[i] output = output + "} };\n" f = file("eei_%s.h" % identname, "w") f.write(output) f.close() print "Done!" ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/BUILDING.txt��������������������������������������������������������������������������0000664�0001750�0001750�00000063342�13317576760�015277� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Requirements ============ To compile rEFInd, you'll need the following: * A Linux installation. Note that this installation does NOT need to be EFI-based. It can use IA32 (aka x86, i386, or other things), X64 (aka x86-64, AMD64, or EM64T), or AA64 (aka AARCH64 or ARM64), but unless you use a cross-compiler, it must use the same CPU type and bit depth as your EFI implementation. (Normally that means 64-bit X64.) If you don't normally run Linux, you can run it in a VirtualBox or similar virtual machine. (I describe some unsupported non-Linux build options later.) * A standard set of Linux development tools, based on GCC. (I've tried using Clang 3.4 under Ubuntu, with partial success. The main rEFInd binary, gptsync, and some drivers compile successfully; but only gptsync runs normally. The drivers I've tried and the main rEFInd binary crash.) * One of the following: * The TianoCore EDK2/UDK package (https://github.com/tianocore/edk2). This toolkit is available in an unstable development version (EDK2) or in "frozen" forms (UDK2014, UDK2017, UDK2018, and so on); however, the term "EDK2" is often used in reference to the TianoCore toolkit generally. To simplify matters, I officially support only one UDK version at any given moment. Currently (rEFInd 0.11.3), this version is UDK2018; however, I used UDK2017 for rEFInd 0.10.9 through 0.11.2, and UDK2014 unofficially works via a different build procedure (see below), which is now deprecated. * The GNU-EFI package (http://sourceforge.net/projects/gnu-efi/). You can install this from a package called "gnu-efi"; however, rEFInd relies on features that were added sometime between version 3.0s and 3.0u, so I recommend using 3.0u or later. The latest versions of GNU-EFI have abandoned the trailing letter and switched to a more traditional additional number, as in 3.0.4. You should check your GNU-EFI version number; you may need to download the latest source code, compile it, and install it locally. The Makefiles assume a GNU-EFI package installed via a package manager. If you install from source code, you may need to adjust those Makefiles' paths. Of the two toolkits, I prefer to use TianoCore because it produces binaries that are about 5-30KiB smaller than those made by GNU-EFI, and I can easily build 32-bit binaries on my 64-bit Linux installations. Also, I've had problems on a 32-bit Mac Mini with the drivers produced by GNU-EFI hanging the system. (I haven't encountered this problem on UEFI-based PCs.) That said, the TianoCore EDK2 package is much harder to install, so you may prefer to use GNU-EFI unless you have a specific need for the TianoCore toolkit. Also, somewhere between GCC 5.4 and 7.3, problems have appeared that prevent compiling the i386/IA32 binaries via TianoCore. Automated build tools like the OpenSUSE Build Service (OBS) and the Ubuntu Personal Package Archive (PPA) mechanism don't yet support TianoCore. Preparing Your Development Kit ============================== If you're using Linux, GNU-EFI is the easiest way to compile rEFInd. I don't describe GNU-EFI's setup here because it's likely to be fairly easy. If your distribution provides a recent enough version, you should be able to install a package called gnu-efi and be done with it. If not, you'll need to download the source code tarball, build it, and install it. This process is fairly typical of Linux packages. Read the GNU-EFI documentation if you need help. If you're using GNU-EFI, you can skip the rest of this section. You might want to use the TianoCore toolkit if you have problems with GNU-EFI or if you want to build rEFInd on a non-Linux platform. Unfortunately, the TianoCore toolkit is weird by Linux programming standards. It's also quite large -- it's intended as a means to develop a complete EFI firmware implementation, so it contains much more code than is needed to develop standalone EFI applications. I don't know of any Linux distribution packages for it in RPM, Debian package file, or other formats; you MUST install the kit from source code using its own unusual compilation procedure. The installation documentation also omits at least one step and is a bit unclear about others. Here's how to install the toolkit (note that you'll need to be root to do this in the specified location): 1. Download UDK2018 from https://github.com/tianocore/tianocore.github.io/wiki/UDK2018. (If you must use it for some reason, you can download the older UDK2014.SR1.UP1.P1 from https://github.com/tianocore/tianocore.github.io/wiki/UDK2014-Releases instead.) If you want to live on the "bleeding edge," you can use an EDK2 daily release version from https://github.com/tianocore/edk2. This document describes three distinct compilation methods for TianoCore, each of which has compatibility problems with some architectures. Specifically, the "make tiano" target fails with EDK2 and UDK2018 for all architectures; and the "make edk2" and "build" procedures work with EDK2 and UDK2018 for all architectures but require modifications of project files to work with AARCH64. 2. Preparation procedures deviate depending on which development kit you're using. For UDK2018 or an EDK2 daily build, follow these steps: A. Type "cd /usr/local/". B. Unzip the downloaded file (edk2-vUDK2018.zip) in the current directory (/usr/local), or use git to pull down the latest source code. This creates a subdirectory tree called edk2-vUDK2018. C. Type "cd edk2-vUDK2018" to change into the extracted directory. 3. If you're using the older UDK2014, follow these steps: A. Type "mkdir /usr/local/UDK2014". You can use another directory, but the rEFInd Makefile assumes this location. You'll need to edit the TIANOBASE variable in the top-level Makefile if you install somewhere else. B. Type "cd /usr/local/UDK2014". C. Unzip the downloaded file (UDK2014.SR1.UP1.P1.Complete.MyWorkSpace.zip) in the current directory (/usr/local/UDK2014). This creates a handful of files, including a tarball and a couple of .zip files. D. Type "unzip UDK2014.SR1.UP1.MyWorkSpace.zip". This extracts the platform-neutral portion of the development kit. E. Type "cd MyWorkSpace". F. Type "tar xvf ../BaseTools\(Unix\).tar". This extracts the Linux/Unix-specific portions of the toolkit. 4. With any TianoCore version, type "source edksetup.sh BaseTools". This sets up some environment variables, so subsequent steps (NOT including compiling rEFInd or its drivers) must be typed in the shell you use for this step. 5. Edit Conf/target.txt and change the following: - ACTIVE_PLATFORM = MdePkg/MdePkg.dsc - TARGET = RELEASE (DEBUG might work, but I've not tested it). - TARGET_ARCH = X64 (on x86-64; leave this as IA32 on x86 or change it to AARCH64 on ARM64). If you plan to build multiple architectures, you can set this to "IA32 X64" or some other combination. - TOOL_CHAIN_TAG = GCC49 (or other value depending on your GCC version; type "gcc -v" to learn your GCC version number). Note that support for the latest GCC version takes a while to make it into the TianoCore toolkit, so if you're using a very recent GCC, you may need to specify an earlier version and hope for the best or modify Conf/tools_def.txt, as described shortly. - MAX_CONCURRENT_THREAD_NUMBER = {#CPUs + 1}; set this to one more than the number of CPUs in your computer to optimize build time when using the "edk2" targets with UDK2018 or an EDK2 daily build. This setting has no effect when using the "tiano" targets with UDK2014. The TianoCore Makefiles read some of these variables from this file and use them when accessing directories, so be sure to type these entries in the case specified. 6. The documentation refers to editing Conf/tools_def.txt in addition to Conf/target.txt, but doesn't specify what to change in Conf/tools_def.txt. I haven't found it necessary to make any changes in Conf/tools_def.txt EXCEPT for two cases: * When using GCC 4.7 on a Fedora 17 system with the original UDK2014, GCC 4.7 was newer than the most recent GCC that TianoCore supported at that time. With that setup, I found it necessary to change the following line: *_GCC46_X64_ASM_FLAGS = DEF(GCC46_ASM_FLAGS) -m64 -melf_x86_64 to: *_GCC46_X64_ASM_FLAGS = DEF(GCC46_ASM_FLAGS) -m64 Although GCC 4.7 and Fedora 17 are both ancient, something similar may be necessary if you're using a very recent GCC or some other compiler. * When cross-compiling for ARM64 (AARCH64) on an x86-64 system, I needed to edit various entries to point to the cross-compiler rather than the usual compilers. For instance: *_GCC49_AARCH64_CC_PATH = ENV(GCC49_AARCH64_PREFIX)gcc to: *_GCC49_AARCH64_CC_PATH = /usr/bin/aarch64-linux-gnu-gcc Similar changes for other variables in the same block are necessary. 7. Type "make -C BaseTools/Source/C". (This step is not documented on the EDK Web page.) Note that this requires the g++ compiler and UUID development libraries. 8. Type "build" to build the main set of EDK2 files. This process is likely to take a few minutes. This step requires Python 2; if you have Python 3 installed, you may need to adjust the default python for this build (for instance, by typing "eselect python set python2.7" in Gentoo). If you installed in a location other than the one I've specified, you must edit the EDK2BASE (for "make edk2" builds) or TIANOBASE (for the deprecated "make tiano" builds) variable in the top-level Makefile in the rEFInd source package. Once the toolkit is installed, you can build the filesystem drivers or rEFInd, as described below. Compiling rEFInd the Unix/Linux Way =================================== With your development system set up, you can compile rEFInd as follows: 1. Download and uncompress the rEFInd source code archive. (If you're reading this file, you've probably already done this task.) 2. Open a Linux shell prompt 3. Change into the archive's main directory. You should see several files including this BUILDING.txt file and several subdirectories such as "refind", "libeg", "mok", "filesystems", and "include". 4. If you want to build with the TianoCore toolkit and you installed in a location other than the one specified in "Preparing Your Development Kit," you must edit Makefile in the main rEFInd directory: change the EDK2BASE and/or TIANOBASE variables to point to your toolkit's location. The EDK2BASE variable is used with the "edk2" target, which is useful with all versions of TianoCore, with some caveats (described later), and TIANOBASE is used with the "tiano" target (which can be used with UDK2014, but not later versions). 5. Type "make" to build rEFInd and gptsync, or "make fs" to build the filesystem drivers. The Makefile checks for the TianoCore toolkit and tries to use it if it's present. Additional "make" targets enable you to fine-tune how rEFInd is built and what components are built, as described shortly. With any luck, rEFInd will compile without error, leaving the "refind_ia32.efi", "refind_x64.efi", or "refind_aa64.efi" file, depending on your platform, in the "refind" subdirectory. This same step builds the "gptsync_ia32.efi", "gptsync_x64.efi", or "gptsync_aa64.efi" program file, in the "gptsync" subdirectory. If you want to build IA32 binaries on an x86-64 (X64) system and if you're using TianoCore, type "ARCH=ia32 make". (As noted earlier, this facility broke somewhere between GCC 5.4 and GCC 7.3.) Similarly, you can specify "ARCH=aarch64" to cross-compile for ARM64, but this works only if you're using the TianoCore build kit, and only if you set up TianoCore for cross-compiling. If you plan to build multiple architectures, be sure to copy the .efi file for the first build out of the refind subdirectory and type "make clean" before building the second architecture. The top-level rEFInd Makefile supports three toolchains, each of which provides several options to compile a subset of rEFInd's programs. (Note that I specify AMD64/x86-64/X64 filenames in the below for simplicity.) The "make" targets are: * gnuefi -- This target builds refind_x64.efi and gptsync_x64.efi with the GNU-EFI toolkit. * gptsync_gnuefi -- This target builds just the gptsync.efi program with the GNU-EFI toolkit. * fs_gnuefi -- This target builds all the filesystem drivers with the GNU-EFI toolkit. * all_gnuefi -- This target builds everything (refind_x64.efi, gptsync_x64.efi, and the filesystem drivers) with the GNU-EFI toolkit. * tiano -- This deprecated target builds refind_x64.efi and gptsync_x64.efi with the TianoCore toolkit by using custom Makefile rules, bypassing the TianoCore toolkit's "build" command. The result is slightly faster compilation in a more traditional Unix/Linux way; but the compilation rules are fragile and work only with the UDK2014 toolkit. Also, the gptsync_x64.efi program is not built on ARM64/AARCH64 because the build process fails. (As hybrid MBRs are likely to be useless on this platform, the inability to build gptsync_aa64.efi is no great loss.) * gptsync_tiano -- This target works like the preceding one, but builds only gptsync_x64.efi. * fs_tiano -- This target works like the preceding two, but builds the filesystem drivers. * all_tiano -- This target builds refind_x64.efi, gptsync_x64.efi, and the filesystem drivers using custom Makefile rules. * edk2 -- Like the "tiano" target, this one builds with the TianoCore toolkit; but it employs a build method more like that favored by TianoCore. It relies on .dsc, .dec, and .inf files as well as the "build" program that comes with TianoCore. This method works with UDK2014, UDK2018, and the latest (as of July, 2017) EDK2 snapshot. It also works under OS X, if TianoCore is properly prepared. One limitation is that building with UDK2014 for ARM64/AARCH64 requires modifying the .inf files to remove the reference to CompilerIntrinsicsLib. This build method is also a little bit slower than the preceding ones, in part because EVERYTHING is built; narrower targets simply copy fewer of the resulting files from within the TianoCore directory tree. Note that this method, unlike the preceding ones, requires WRITE access to the TianoCore build tree, or at least to the Build and Conf subdirectories of that tree, as well as to the root of the tree. (This method creates a symbolic link of the main rEFInd directory into the root of the TianoCore tree, and the build process creates a subdirectory called Build/Refind to hold temporary files and the final .efi files. The "make" utility then copies these files to the same locations used by the tiano and gnuefi targets.) * gptsync_edk2 -- This target copies just the gptsync_x64.efi binary to its final destination. * fs_edk2 -- This target works like the "edk2" target, but copies only the filesystem drivers to their destination. * all_edk2 -- This target builds and copies everything using the TianoCore-style build process. * all -- This is the default target. It runs the "edk2" target if the EDK2BASE variable points to a valid TianoCore toolkit. If not, it runs the "tiano" target if the TIANOBASE variable points to a valid TianoCore toolkit. If neither of these variables points to a valid TianoCore toolkit, the "gnuefi" target is tried. * gptsync -- This target builds the gptsync_x64.efi program using the same precedence for toolkits as the "all" target. * fs -- This target builds the filesystem drivers using the same precedence for toolkits as the "all" target. * clean -- This target deletes intermediate build files. Note that it deletes intermediate files generated by ALL the build methods (gnuefi, tiano, and edk2). * install -- This target runs the refind-install script with no arguments. If rEFInd doesn't compile correctly, you'll need to track down the source of the problem. Double-check that you've got all the necessary development tools installed, including GCC, make, and either GNU-EFI or TianoCore EDK2. You may also need to adjust the Makefile or Make.common file; or possibly Make* files in code subdirectories. (The main Makefile controls the process for both toolkits, while Make.common holds most common options.) The most likely thing you'll need to change is the path to the various GNU-EFI include files and libraries. Since rEFInd 0.6.2, the default Make.common file includes the following GNU-EFI definitions: EFIINC = /usr/include/efi GNUEFILIB = /usr/lib EFILIB = /usr/lib EFICRT0 = /usr/lib If you've installed GNU-EFI from source code, you may need to add "local" to those paths, as in "/usr/local/include/efi". You might need to change references to "lib" to "lib32" or "lib64" on some systems. Recall that you need at least GNU-EFI version 3.0u to build rEFInd, and some older or behind-the-times distributions might provide out-of-date versions of this package. If you're using TianoCore's EDK2, as noted earlier, you may need to adjust the TIANOBASE or EDKBASE variable in Makefile. Compiling rEFInd the TianoCore Way ================================== If you use TianoCore, you may know that the standard way to build applications under that environment does not follow the typical Unix/Linux development model described above. Instead, the application to be compiled is dropped into the main TianoCore source tree and compiled there using the "build" command. rEFInd can be compiled in this way. I am providing instructions on compiling in this way because it may work better than rEFInd's Makefiles in some cases, especially if you're using a non-Linux platform for development. I've successfully compiled rEFInd 0.10.8 under OS X in this way. (I present details and caveats shortly.) Note that the "edk2" and related Makefile targets use this method behind the scenes. The procedure is: 1. Download and prepare the TianoCore toolkit, as described earlier, under "Preparing Your Development Kit." Note that you will have to adjust this procedure if you're using a non-Linux OS. 2. Change to the directory that holds the BaseTools, MdePkg, ShellPkg, and other directories and files. If you use the UDK2014.SR1.UP1.P1 package noted earlier, this would be the MyWorkSpace directory. 3. Unpack the rEFInd source tarball in the current directory. 4. Rename the rEFInd directory (refind-{version}, where {version} is the version number) to RefindPkg. Alternatively, create a symbolic link called RefindPkg that points to the real directory. 5. Type "source edksetup.sh BaseTools". (You can skip this step if you're using the same login session you used to build the TianoCore toolkit; you need to type this command only if you've logged out and back in again, are using a different window from the one you used to build TianoCore, or have otherwise modified the environment variables set in edksetup.sh.) 6. If you're using UDK2014 AND you're compiling for AARCH64, you must open refind.inf, gptsync.inf, and the .inf files for all the drivers in the filesystems subdirectory and comment out the line that reads "CompilerIntrinsicsLib". This library is needed for later versions of EDK2 but is not present in (and not required for) UDK2014. 7. Type "build -p RefindPkg/RefindPkg.dsc" to build rEFInd. If you've properly configured your TianoCore installation for cross-compiling, you may add "-a {ARCH}", where {ARCH} is an architecture code, to compile for that platform. For instance, "build -a IA32 -p RefindPkg/RefindPkg.dsc" builds for IA32 (32-bit x86), even on another type of computer. The rEFInd package should build, leaving binaries buried ridiculously deep within the directory tree. For instance, on my test build, the rEFInd binaries were at: Build/Refind/RELEASE_GCC49/X64/btrfs.efi Build/Refind/RELEASE_GCC49/X64/ext2.efi Build/Refind/RELEASE_GCC49/X64/ext4.efi Build/Refind/RELEASE_GCC49/X64/gptsync.efi Build/Refind/RELEASE_GCC49/X64/hfs.efi Build/Refind/RELEASE_GCC49/X64/iso9660.efi Build/Refind/RELEASE_GCC49/X64/ntfs.efi Build/Refind/RELEASE_GCC49/X64/refind.efi Build/Refind/RELEASE_GCC49/X64/reiserfs.efi I've tested this procedure under Ubuntu 16.04 with GCC 5.4.0 and under OS X 10.11 with both Clang 7.0.0/XCode 7.1.1 and Clang 8.0.0/XCode 8.1.1. (See below for Mac caveats.) In theory, it might work under Windows, but if you use anything but a GCC- or Clang-derived compiler, there's a good chance you'll run into a compiler-specific code incompatibility. Compiling rEFInd Under OS X =========================== Building under OS X is *NOT SUPPORTED.* I've tested this procedure and it seems to work in minimal testing. My build under OS X required several changes for compilation to succeed: * A relatively recent TianoCore EDK2 from the TianoCore git repository is required; the stable UDK2014 and UDK2015 DO NOT work. I have yet to test with the final release of UDK2017 or UDK2018, but I expect they might work. * Setting up the Mac development environment required following instructions at https://github.com/tianocore/tianocore.github.io/wiki/Xcode, with the caveat that the UnixPkg directory described there is essentially empty; instead, I compiled the BaseTools/Source/C code, as described earlier. (I don't know if this was strictly necessary, but the tools did compile, despite several warnings.) I also skipped installing QEMU. * Instead of "TOOL_CHAIN_TAG = GCC49", I set "TOOL_CHAIN_TAG = XCODE5" in Conf/target.txt. * I had to edit Conf/tools_def.txt and edit the RELEASE_XCODE5_X64_CC_FLAGS line to remove the "-Werror" option. With this option set, the main rEFInd binary and several drivers failed to build. **CAUTION:** The warnings that prevented the rEFInd binary from compiling with "-Werror" intact related to ((sysv_abi)) declarations in mok/mok.h. This makes me think that the resulting binary may be incompatible with Shim, although I've not tested this; my only testing of the binary built under OS X were on systems with Secure Boot disabled or with the Secure Boot system under my complete control and without Shim installed. * I had to edit refind.inf and uncomment the line in the Packages section that reads "StdLib/StdLib.dec". * I've been unable to get the Btrfs driver to build. To adjust the package to omit this driver, edit the RefindPkg.dsc file and remove the line near the bottom that reads "RefindPkg/filesystems/btrfs.inf". Note that if you want to use macOS or Windows to compile rEFInd, you might be able to create a project or Makefile for your non-GCC compiler or use a GCC port, such as MinGW (http://www.mingw.org), along with the procedure described earlier, under "Compiling rEFInd the Unix/Linux Way." You'd probably need to adjust the Makefiles in the latter case. Installing rEFInd ================= With rEFInd compiled, you can install it. The easiest way to do this is with the refind-install script, which works on both Linux and macOS. Alternatively, you can type "make install" to install using this script. Note that this script copies files to the ESP and uses "efibootmgr" (on Linux) or "bless" (on macOS) to add rEFInd to the firmware's boot loader list. The docs/man/refind-install.8 file (and its HTML conversion, docs/refind/refind-install.html) provides more details on this script and its use. If refind-install doesn't work for you or if you prefer to do the job manually, you may. On a UEFI-based system, you'll want to copy files on the ESP as follows: * Create a directory for rEFInd, such as EFI/refind. * Copy refind/refind_ia32.efi or refind_x64.efi to the ESP's EFI/refind directory. * Copy refind.conf-sample to the EFI/refind directory as refind.conf. * Copy the icons subdirectory, including all its files, to EFI/refind. You'll then need to activate rEFInd in your EFI. This can be done with tools such as "efibootmgr" under Linux or "bless" under OS X. See the docs/refind/installing.html file for details. Note to Distribution Maintainers ================================ The refind-install script, and therefore the "install" target in the Makefile, installs the program directly to the ESP and it modifies the *CURRENT COMPUTER's* NVRAM. Thus, you should *NOT* use this target as part of the build process for your binary packages (RPMs, Debian packages, etc.). (Gentoo could use it in an ebuild, though....) You COULD, however, install the files to a directory somewhere (/usr/share/refind or whatever) and then call refind-install as part of the binary package installation process. Placing the files directly in /boot/efi/EFI/{distname}/refind and then having a post-install script call efibootmgr could also work, but this assumes that the ESP is mounted at /boot/efi. Also, Debian packages try to create symbolic links when updating packages, which won't work on an ESP, which should use FAT. For packaging examples, see the refind.spec file and debian subdirectory of the rEFInd source tarball. Adding Support for Network Boot =============================== rEFInd provides EXPERIMENTAL support for booting over the network using iPXE (http://ipxe.org) as a means to receive the payload. In order to enable this feature you'll want to follow these instructions: * cd net/ * make source * make netboot * copy bin/ipxe.efi and bin/ipxe_discover.efi to the EFI volume at EFI/tools/ Note that you may need to install additional development packages, such as libiberty-dev and binutils-dev, in addition to those needed to build rEFInd itself. My own tests show this support to work under optimal conditions; however, architecture (EFI vs. BIOS) detection may not work, and some computers will hang or won't retrieve boot files from the network. For these reasons, this support is disabled by default in rEFInd, and I do not provide iPXE binaries. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/mountesp������������������������������������������������������������������������������0000775�0001750�0001750�00000005004�13340003224�015100� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/bin/bash # # Mac OS X script to locate and mount an EFI System Partition (ESP) # # Usage: # # ./mountesp # # This program is copyright (c) 2015 by Roderick W. Smith # # This program is licensed under the terms of the GNU GPL, version 3, # or (at your option) any later version. # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. # # Revision history: # # 0.9.3 -- Initial release (with rEFInd 0.9.3) # Mount the ESP at /Volumes/ESP or determine its current mount # point. MountOSXESP() { # Identify the ESP. Note: This returns the FIRST ESP found; # if the system has multiple disks, this could be wrong! Temp=$(mount | sed -n -E "/^(\/dev\/disk[0-9]+s[0-9]+) on \/ \(.*$/s//\1/p") if [ $Temp ]; then Temp=$(diskutil list | grep " EFI " | grep -o 'disk.*' | head -n 1) if [ -z $Temp ]; then echo "Warning: root device doesn't have an EFI partition" fi else echo "Warning: root device could not be found" fi if [ -z $Temp ]; then Temp=$(diskutil list | sed -n -E '/^ *[0-9]+:[ ]+EFI EFI[ ]+[0-9.]+ [A-Z]+[ ]+(disk[0-9]+s[0-9]+)$/ { s//\1/p q }' ) if [ -z $Temp ]; then echo "Could not find an EFI partition. Aborting!" exit 1 fi fi Esp=/dev/`echo $Temp` echo "The ESP has been identified as $Esp; attempting to mount it...." # If the ESP is mounted, use its current mount point.... Temp=`df -P | grep "$Esp "` MountPoint=`echo $Temp | cut -f 6- -d ' '` if [[ "$MountPoint" == '' ]] ; then if [[ $UID != 0 ]] ; then echo "You must run this program as root or using sudo! Exiting!" exit 1 fi MountPoint="/Volumes/ESP" mkdir /Volumes/ESP &> /dev/null mount -t msdos "$Esp" $MountPoint # Some systems have HFS+ "ESPs." They shouldn't, but they do. If this is # detected, mount it as such and set appropriate options. if [[ $? != 0 ]] ; then mount -t hfs "$Esp" $MountPoint if [[ $? != 0 ]] ; then echo "Unable to mount ESP!\n" exit 1 fi fi fi echo "The ESP is mounted at $MountPoint" } # MountOSXESP() # # Main part of script.... # case "$OSTYPE" in darwin*) MountOSXESP ;; *) echo "This script is meant to be run under OS X *ONLY*! Exiting!" exit ;; esac ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/fonts/��������������������������������������������������������������������������������0000755�0001750�0001750�00000000000�13325167530�014446� 5����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/fonts/nimbus-mono-28.png��������������������������������������������������������������0000664�0001750�0001750�00000026757�13137112515�017663� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR��`������ĸJ���gAMA�� a��� cHRM��z&���������u0��`��:��pQ<���bKGD�̿���tIME1C-��,IDATxw|Eǿ) H3H)"E| ""tP"Hޕtz =q{ٽK#f{ڀ~~~~~~ 8*1a]??n :~A]F�0,)KbnW?0Wߗ#Wps?E@nW?wu+~E!T?x3Դ8v nfIz_�XҎL*YAD<O 8Zg=VʫO6ɴV/9E2,޼j|mJn ptN GIdR¦B\@'ɑ}j-˸O9Ee!PKw#1MtnD:E~/Wǰ "=\zuɽ9cWs IGA!::P8GW]"` Su3QPk9YQNS$^7󉦂le\f4ys!\ǖGFApC~{\V? A\+(;ԧ'B*,W:*?LlY"xS,%pI`>Y͇ԧ&q& .3T5 Z~\FZ^8uPсjERZB Nv$2'L;rZ2u0Sa3s6:$s%4%ܦ]+t&BWLW4X𺩏<lΐ>~5ӾLv3@,gJB3FQl&3eEyckഺW"mOT"fW)d(LC-@A1}믠FmM0Aw/U R8<d39|jI{c g VB2겐$(A/莥[Jӻ:m,DN)gj$JF#HEA!<ʨmF%O"w''NH!8q,]`&sR9j�JSCОJ<L:kukANR=xLnW!+;oWn?yHa$.<^c -FA= e_pF7g|Ƀ} syU,#82BAg$c!=@A/$]u:Vp9O$0rVanfqn{ƃDs,Lkbv$7nhPR(칏8.dsQh[_Wg\c/iC<$$rn{e\ӥnD2;&aJ7 e L9Єw8biB5`'66{RG`g8%`>%J5 .pDwFF wd'*܊D.2U eԣ8'p5uA4<3Wgw8qQ>23¡ IӎI*(H+-4Nф$zP2Z2TY43xF<A%g4Qdh:"'5S'I8}!@~$N8^'FY q8qjn(( Q 8cuc0~7]x"ncdH,6# LasП969$0]85n.q㟦qFDnW#:cŁ߳ |³0ҳOD_H o趫f׽$X0> kcaRO|7)=28a*ѕn%/AȒ D{~7 AHnuNK֓e yRSݦ\C%b�@`g&}Qôܛp) u^1Z 1܈\.BojE'ld T?Q(:nh Y4#03;=q0s4W%V8枹A s=H$_IT;bYf:5&\Qv ?.-f܊;hiybxFG 6$m`pjEPF  =G.1M h{M*7rN՝XBОXa~CLn;x]?u0%8kRmjf$|7 Lv_$0Q<Hj L-6Gmcd8{LmDӱRKpD>l&&tq6&Yjj8!=2W= 2 yVxy7 G.F$d3?t*^%iH[JAZg#MDk{qPӫǙ"3>u3լl\3`2"?RgTwa;Qڣo=sbݼY 6/Rur!oSBopЌ.<apw\j1Af6^mcaą^%t t$�fӞaA NhG=A>|na#ua'񲰧-s2@ݏpURNx_ShҬ sԿϑb�տKqZwT3O+,y#B3ɚ- J0by$)o0Rxf<M*pv|b翃<~l` Z{E%%ePHG܃" &<ԠQPPhm 0Ee & |lM 4 y&$oOFb�6J"\Olӣ�i&&J,\qRlsjgx' PAcV F d',H�L#=:c I3| ޡ"a`6lRrYJ2$qTrUN�zpFb5ksAZٜ2mi;1%\ ]_c ߁moIbnq&')H.,0!4N$ !ӵm�.)cmhj5eZ*ea]<[`3y |! "i5D2*ks �e~B(X< tΫ7OL/ %.0h(p$cp�\b9H]2e#1D]>h.v8$cJHiem[H?QX4<+$^eI^P}3jKJ|IG^ng g8ͻ~R<vK%>nJPK-6?+İ.b9 3$079O{=,I(XaΜ~zV?u ڕi{v7�جn硥״8Pw^@w2tW4~ig LM,0fGAKH~!dH&dA졹8FzY@ p-#_SΩf AfؚoӒR$BZi37 :I<'9!Y|v.pun88OU۸`l݇nPHd.:X]rc̅&e65`bۡ8Hi%@'v( iN)Y!U`PnO d9AϺKMHK:DuQ /֨+=SAB``%FO`.Me(I:!L>J;ti$ؖ8ssu5euA2D4H9`4ZODQPNغz+j=~ɞrі|O?MyüB~(Sz!k/ "DU9JovЇZ4-N30ØR#lx">Y,?NLe.>It~,hxBF #W3$nv6PR.sA!8$iOc,qZsNWd?Aukb|Bk҉Hcmr=ЏGǫa6qҋj˝ (8i5.XD3":{jA6sԣ2\]G;Յ y(5:5H%NC�N^!rjd e$/NfSY \6jґԞ$QxB2wp@E]_!zc=;,F[l Jp%MGN8%H8BX"l"|@8 Ci>D ^UOcyXB ˣXj>]dnc_ۜu,rE4�ÅDYe^ p\j+5M*'0e" ɔ3 L<oS8s)5J$Y CÒp2VTsM88,ї4ҥ$ɻu GǓp�[ jB tmYhʉ% EhvI ܐ"SYwi-=Q$/”o&OM!0J~v&Aʉ/Eۍ ubo?�Be&ž`V'"]0t/G#�4\CD@wh~c*k b簩Ux֙x0:x ;WPtv1L72y˜% A4o4V ՕQxM1cҹ&UӖPHT}2u$xj/.8@annDU8[01I׶yKS2kR{|,HO],<O.%V<, Ao{ Lख&bLTg1)KM`zpB0Fk1,d Pl|�l;& <G=ǨBW9=(\RFA1t C8B"6!ܷ(C&a>glp'Mx$Yl"'00I<,/UG9˼z.s<Mu0I YA5B|NQS&W4 fP?t8Oq: T-,-k,D37)C:L?k|$ dUyA\׋tru4Kcw7de !0sy&0vF fk3Z}ZȚP"̟ܫI;SHr l&LeG&_ WiGq.5zhI.ٍc={l{;=udߍ[erM< ? )XĘ\dՉXbƔElI l(&03BJ ]WE{t `!"r`9M%; ]Vݸ>Z΅C=zpPӖ&j L99V #]UMREaj#YXXΨS=O!ϪՈL`dXyΜc*W4ǐB qJ^­АhAgҌ#$0uhI1{XB )b~w7OӇgS,4SszkUiv1A ajh,d#>7LankrGu$a\y;T2@(A!لLDv k{{8-b|LI L1NU3 pq&~ 'pSV Co#w}W, B-ەMs6,#0$HJ(UM!'0!%[sTg"$ HB8"hO6!ft ̳eY8ݴ>a�g%O(G4m\#<&[}Sl"WL2| a({@[2 ϰCRj"AעnLC^ ƊK5þ =d\9ylMbwt"Li 0YZ]Iɿrꅡ9 ]xJk�b$D/)IE.n6юl;t> _9b�Q]dt&V*{oBd7|kYHQr1 &c|#qQ+C:`;+(I3-:VGP2wpI�&4^9BZtV@b7Gk Te ٪0?%ӄ6$Do4!BQvвdًk./Yp |0Y{G`l}Ad|2φ2`PRu/B+Ok[ L+\wAʔ\E:䣓T49fHD-sN+W BA_ukN؟Q4.:+(m.dSMӺ=He&0Oks9hebt![ tYDłJ'S:E Db |jЖ#@ R(<F A%Ӥt0 <HM&KOIrFzzXE?$#td%,ڔD,#<PŲIA1!5nː8X'{\#0 r=i„>mNR%.եsK8B*'X$w]9MU*�AgQ""XPsʼnGMyL<F{&0PTE ljٕ 1=$EgmT/}:4cF#3&kՖ&/!$ԫd9/aZ6'}碙~9x.;(&t2t'MK^�GgͦSzג\OeγQ(lb`1% aX C`a&Yc2 aO7ej5U-HrsZu&UegdN]hҪ`>GN`~0B{Zf:+c&0(2 ]+H`G<k<L4|6iw/#_9Qo -֚'4EV=T{zL_RuqMM,PdS2a3$ظoOگpZ㝬 ?FQorΐƠ C녣޲PFJ`Ɣp2.USLYv�[r|C>VM.׃z[*CN`J<rY5ƍ <9l\ QcRR^�>wpǀi,$'[8miXE|fC{'LźaDž<YI]Ale%GCa + xT"="T*RPh:IYa<GsVndTTm;<C$+mւHC=uY2&QRJ^cD�_"u)<F*ͨ^Þ-:zBnxI9~O0 (,IOzZ3'YSv-"`* >V>g(UYj=W28Ndx'ywt-W8nyvw 8+xFGDV <4Q@dM-/Gwp''(`y.IH2wL;1^$eZ8N)W%ΛB;BĘHr'^yQt! ~ʖݍ|J7HV=27=-t]q05د] $nzc\>{޸hy n&&HkuMjEie#L9E Ԕ^-f3@ujbPU0Cx0(=,Z]B s]OQ<ŐjyL"8?"8H2՞y<J>ֱ_$ep\&4L/Ol]$ ;++mͲ#gMZ*_Ԩi Ҙ:k $0m\$'`f9g-X#l3!4 1Ye1ˤ=˓cj'gx&U73CX7ѧpXKWOib$qM,!8(^fBmT̶i z<[ G1Be07L$5yHfA#1>A \<G}?43ZIRd@xVH(:�/14\$4վ4aŚk7lXd*k&ôͭL䬁F0H�$k  .%sD5bS^̾=1{H%,rjsԦ# 4 ҂2Y`Sew~5jI.d-!}Q@# z8̡E 7 X[|C&/5Y,&HWM(g�;@|\[A`lB=]!ZA2I!]"N)bU󠃍L'3aa < ŇH7EenfN{)I ꂕm,bsq<? TAObm4+ka(! !}8n_o=\ѥ5 `,'$KnTd?-<=Qvw6'($2ҋu3|%ui~TD!6l|d0=O<}=I: Y~f Iw1k&B *trM"uaY0)H7Y΅ q}fsNPot'ٰ.wtNv2:qQ;F QV%kj$:Y{ 6Sdif Jkp2B ,}v!S|Z}9d37]Ȗ !Oąuc>&OxCoeV(g 1HaL d-\3IB*D;\Ȫd#Xt#]eiSuqTWb\b�{kBbXѨ(MW˶N9z's,$|p2@HdNI)})e*R�C8._oJ*^" q>ҼEo͝R !*f4 .hj ҴSEh`7p4W/8ܣc`qDXar6p/Ռ mq$1?$,dP`Ƒ/Q"ZEmHڶg;4%#JB=gm b~閡OÏ<EU:&w҈*<n95طK�QH@(CM1^_i3ɱ�nRM6xxԅo!3)K% kU9dplh563qJ7} 9) 滸~4!f{ҏ'BC^f)WLDy(H;qAܧ뫡=Z(^ WXJ/jІR8U2޻18U޽>E`\ 5wN强^APڒd 5L%4 G{@"Q4`Խ-:X,m+lfx&T_rz)0Ju=Hd*OSy w̱t:i." чDCY$fBm\#jq4rw.,IG L~.kF.y&є4N~j݋Vc<ƛea@F%Ztc|+(80җz4f�gMUrw2ӎj ~!EBL Y׺ѕje4dQV[4~pd֊'萪S8)5~4R0Q6~d!2`s)LA["$&a(V˫bag=IC"ՔL0N!N߾+YS4cQJdKf4JK^e KQ^Tcf< Oi4%"ITEH($0LWPʱTȩ!օZ Jϼ55DX �<0\ascg8"tP6(mrB5PP$糋"RA1,aQpw$,xڽ?}$b{I\c%M-ܶyyD&>KNzJYnBG<BR Um?vq"*Yx}(P," tB7Ak,7Z)ĵK/>6ey]qxW2p\vod%+3Đ[VK*l\&6"$xpIDSfRvCA4ɖ>׶DKwVè&sp VSoߩ,B!6O N*s;%N,)ͯ4|K osIM`g;_gZb1@iDwz第q=gs@]}#00man'9NA4VUj6;x]Tv)V2L";c0&M!h h4$lb!n&~;_D"v; L\% A!}(wn/QS?kc2 c�`)Feڶy[\c = 4ߗ<Y2IVԻ&&lcIT1&I,Oe`i6X.1UjJM1tI()HB陷?naWm9x?xϐ4׍լn l0k ?r(Zx0x7|3Dsrr~gӢ[(rDQo :gn?fatc5 %(U L}>I_A͂BuCoD_ŧLa=z#DǭX9ݚrƏ6*pĐRZ#;Ȏ:# 9!0y]]( evn?h'09E~.yd'+]L" W7<MBuȲ79`a5wLw.L:'s9G|?Z0hL&Lq{Z)rp$LjLGKFљ񿎞Mr=p;(&xCM+z\C9[CkHOޡ5Lg~}p7xYHڏ?X5?%AAv%ȫ&Yx\oS|(%Xd= zrw+xM7Et!TN*(CkB IW?eN2DP<@ +yM$2S8D;47aIr???aj:,SzZ|.Rjw\F"6߉;Sx7+~~~~~~?:I���%tEXtdate:create�2017-07-29T10:01:49-04:00f���%tEXtdate:modify�2017-07-29T10:01:49-04:00yJ����IENDB`�����������������refind-0.11.4/fonts/nimbus-mono-14.png��������������������������������������������������������������0000664�0001750�0001750�00000010244�12626644770�017655� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR���������2j���bKGD�̿��� pHYs���H���H�Fk>��IDATxyE.,"bjZFn&)hY "I,n"bY..bB<X[=iVB Hj} m}xwf|gΜ9gΙPjTըhQF+4 Ƈj')O^JBnN>()Ǹ#8D=֩*}@))@+MݽkؐH E.Ke9Eֹjnߕ5?M}P<_|'+zE\Pl0 sVhJM6JNEq.R¨D_9.OP+̍d685䏱 vR?O!9%7&@]S,ZA6=ԭmHy69 g00ڦ#a@OA,* \|1.e(̷IP(^?"\*D 1Z&7:ߝ.1A뻎Bˍ|yH!~kf`CX@;|\ciz0ʼnrsNrT*$ .wdu3E*jL#=DJꚑEK5k�M_IУU| Oܩ( ܤ8OROuZ(2&QRYnc爜cRbl`vH4 L72A\P? 5h18ҋqZgLL\~9>%LŰw(6\MP!OQg5Xf$Of& t*m?k~?oL 5e'z̮MslJY#4= e(Y>! nҩ1kϹ&+zq[Aw)[ImIa:mYz0ޫ5C}MU?@eE\bU<eHʵA~¿N#TF/zb9ũY~#YvY̬ Z7 xqcCd06 0 Nz5 tu!b]ȿ`Lc"DK)[Pf-x0h SCsnzdȢ0}6zYN9Qaes>߾F3[70 F9r!zj~9^(пAo ˱9혐fNsrnDr\m .90WdaG:!>~ !_R5 Ȋ9$#h[4zhSfp~R(Vn%&#2S,3+LfKB}tuiA 2=f^D^#-qde~BPõVck]L UXeb44"\ &g"b<cUhC<~<~=Y1՛\O+ܯT]<{[ ?rs>_�I0%R|M0<K|.ۭPrAYhaVɓA}QNGXPk�j[?~׵Q8wςS]/<BYݽ8)Q/kz@xX͌ ̳&aBS2/u +yaf0<hX<?9&1EJԶ*!H/|_ e}_<V[V*3hZ3=#,-6͂|v{wWc?AgXene* a4+ea>NFgz&'{>:ߘUʓ4 /2I.B;*xc:09<H4_ܮ\ pBFTeZV8))5iA0r* HMԴDFI!\Vf!w8'y�o:sN=MUbS) ^rJCÛԉd~Z;*$ @ )7qZSgkR4#l頷z8Xwg7yJAʹܜP1Ղq�dXhr#v25yFjfԓ,LTBP?E9(PFUh`r<Jõ"VRZXFqg�d,ЈČRE!'",5:δ* @3czUi G޲^3=-{L\PM]jC#Tg*555>ԱӨ/Jez>'^/2$/82/{}qmgA!xkk#rzPM s}�f|Rohm xW4r1 ,gҪ @p665<l1q'q5_䑄) ?> tNN}0'y1 /Jʂ*73.3`vj*7'oz7az*$Rx>Y)Q~G+qPp+ RKYPIK0kHKZe[Y�7(ܬW7w3d<q*"bΧX؝*00LS=Uy앥C ЅRH})<pA}mqUX %gة Z1S;ΡxQ^ } 6/=^ h68"V %lq|E炯0�m,MD 2�쾏ki+x=v[1lnj,kxi9tq[ؚxbs>H8.+br窐pZ' _V =›X0dZw>3n.%y %ë w&NH$xgT| <*og{:H#A][8a\x87J/O] <hg/2?JPi41Ѩγ459wodD`GvqMJP;<M-r_%pWKjIvsl27jv+|=SBp \fs8ce(EǃKYٞ�2Xf�^P,FIAU zv{# s_,{O{ 3c9Y 0'!^nXRInn3s? �H<J0Zd]'t+qK௢Lt8_o9_WGcݥfV~0eމ;=˫Ͼ$Q*sJƶ{uRy"Mdw]-͉Wb_ž t׼OG+ \M0" MXd^nBYRjҸc] C5DuQ抸~[S tu!u'kWQε#C{0Gﭜrur8|['Z9hFgoYi'~evztvj؝P^m+C20cXʽ+%ru(D]t/[u֢(/ 6 TCyyH lSOxz}lu 0z=@,N>zh+1Б<r+k_)X`<NP5Cu]nn6R<醻C_D^N3٘ǽҾWY MxVo뉷C qk%:q.ޡ]k{8[,r-ƹSmZ4&\sy^Km㽁0L<V'.yQ[[斚f1" <jz'4!?Z֬Iy(I^\WMP{Y9OMGK=c~QB�m71!w8g{G{F=o~,|DqE%?-ǂzZrx~^gpZpyWo4ӍG5y/6ozQ]b=nl>j3�)0#C'.{4 V+jT? ͽ]牅țM1G&ܕCH#qEמ!gDU3{"l���%tEXtdate:create�2014-05-13T19:49:21-04:00]���%tEXtdate:modify�2014-05-13T19:49:21-04:00,^M-����IENDB`������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/fonts/mkfont.sh�����������������������������������������������������������������������0000775�0001750�0001750�00000003540�13325167530�016307� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env bash # # copyright (c) 2013 by Roderick W. Smith # # This program is licensed under the terms of the GNU GPL, version 3, # or (at your option) any later version. # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. # Program to generate a PNG file suitable for use as a rEFInd font # To obtain a list of available font names, type: # # convert -list font | less # # The font used MUST be a monospaced font; searching for the string # "Mono" will turn up most suitable candidates. # # Usage: # ./mkfont.sh font-name font-size font-Y-offset bitmap-filename.png # # This script is part of the rEFInd package. Version numbers refer to # the rEFInd version with which the script was released. # # Version history: # # 0.6.6 - Initial release if [[ $# != 4 ]] ; then echo "Usage: $0 font-name font-size y-offset bitmap-filename.png" echo " font-name: Name of font (use 'convert -list font | less' to get list)" echo " NOTE: Font MUST be monospaced!" echo " font-size: Font size in points" echo " y-offset: pixels font is shifted (may be negative)" echo " bitmap-filename.png: output filename" echo "" exit 1 fi Convert=`which convert 2> /dev/null` if [[ ! -x $Convert ]] ; then echo "The 'convert' program is required but could not be found. It's part of the" echo "ImagMagick program, usually installed in the 'imagemagick' package." echo "" exit 1 fi Height=$2 let CellWidth=(${Height}*6+5)/10 #let CellWidth=(${Height}*5)/10 let Width=${CellWidth}*96 echo "Creating ${Width}x${Height} font bitmap...." $Convert -size ${Width}x${Height} xc:transparent -gravity NorthWest -font $1 -pointsize $2 \ -draw "text 0,$3 ' !\"#\$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_\`abcdefghijklmnopqrstuvwxyz{|}~?'" $4 ����������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/fonts/ubuntu-mono-24.png��������������������������������������������������������������0000664�0001750�0001750�00000017711�12626644770�017711� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR��������(N���bKGD�̿��� pHYs���H���H�Fk>�� IDATxwWŵ? R&Hc"Fc< $1ȳ,+ D`X@EzY@@vv[㶙{~, ?9wʽ3g9sRH!RH!RH!RH!RH!RH!RH!ZCC] N@Xw B )Xp¡.>ybyu<@}d5@{@b>B:I* C]RH0gϤQ<~5ϑ|f>)!-ndL]_MB#2ߕ a#htΑ6ůy1&Tiі\ -Jxp1Q 0"͹ >@}ne1nj 9=9);|@y2lf"? e)(c OoPVPFs␵TP< amྑ�g<]I!"r^ nt`&[(%&ަF+!/wry]j?\!nHWQD{=JKI3r=O(JBrDF VS7ݶ vY茰h �!>GF.¢8C?O=B=",T!>Ax."^Ed+֚>|ʖV#<f=Д#" ںҺwЋʇqw @&(MK<g@x=aPofS&c422ߗSָ4zwDKq_Bt>7<p;--`C*6h%Nm%u-\*Ux-P/6~S@ @ xKK]R+_|)e *!TT!kԸϬҐ̥a\0j8}gOV�?J&O�-c9B:9,+6L(w{_f�4NhH �gs$jE� ͮC](EhaH끖y0=8|z!]%AW2h<6[�~3uGN;C1cPАJB`I/D.Cj^Qhk»k轌T2gԛ' lզ8=pa| A(g,Ћ:܈4�c2iIV`> Gp e s#dҝ)+/29 | hE,C½3?Ҟ,z +t^^84B)C@1ԉ~?˹n*bG'  ӥ݂֒<GhAk t,A$\6ĮWK݈4zv" uK0iHW1"Aj <F" "�"ʍV3\L#<f qW|(DP@;!QDy0rDDs @OyE2O4 |W`t}A1riޫ@hD&,R8{h`h!hO_ |غo"6_]ED@S;~l`;B߶&ȮQNUr)fcy;]DM㡵Bm(c~+c*hI1Bg7چG+܃*5NxJN5 8jVZ4zzLF%!)�sغKAf_;*P_抛wU(j},B+"/�\&a߿aK=T\J C̅*Ax!b/>]C�J)h<xU^E�^Uf{;8zتhpr/'jzhH} Cz=fڜ^^a \Lߵm#To|yZ-Q|C18F ldĝtoJi銰 ,7;IJx9,y#}x7y>@禷P>am.چ#1l6wr8zQnDGmiG}pOG`N)(p=(@~: Ջcj&sl*+L� ݚߐ,nB خU$^w)B d0uSi0Քa 0ȧ|"[yWҳ=)pu, v2is(d 0 V q{͌v֑Njq{ F"fqrRL �O=TRl̦Jv1O+@"6rv1N|摐ڪu6נ9쉰kVx6ƱόG~x�"'j7 _sKO݌ Q.�=P;UX>@/3P[)Ϡ; ñToBJrZVcod ьx8%k[Пxz$8aN|5Xp5,t a�h.<]4D&V&İthP"2 u 6¯+m4<1X[G[8,dz$/Q&;ԗ z&\gETf0S8ǔcQp;Qn?[#DRgj kN/!g/7�ԁ2v2e �\tB__yYL E\$΢Dטݏ(1V(_V2eTm@vf0dx RLHV@F%N>>y<4*TP_3uָ% ɻ v/ւm5Zm96UFx= ϯ^1)\=:[l �2Ȯl.BQ̠tb#etd &ˇowC0v^YvjV}E 🼍UDF1xBw+in4rZP&(|YL11ڰn"�&zswKS rS!Sz}0Ja) L�0ڃd.ڳ2W^eǧg\]~r#^3NapDxk*״S's=8aBa%iJbDq�F(2aI}aJTW ף @fb9.Ы>YiC|>4i,B-<ޣ|i}<"LCicqOwG% <J2bkE9<bBb!<?![hOg+%.Bq'GN{ۛ,uL ޵~%A8 nX9(v B{сDbJ#hGy}i,ʍ41,�؆mLϗ�m[͹xjӨ` d u|\ xFq/ayy肰3B_؉nǸ [azt_\AûrpS\m}#Tp"]/"{2<7)ɜuu↮nt F� l7tV~j;\eʤ94~M[iiG%5sr>㴣V(?u8?jm.]^&Y%4�Q+寓DT6OG4rJ$�_wBX4RPOAF p}=(ў؍ ЎɧFӊfUPcziQBM @=qp*Ur{lY%wo+[k?_ٺڣ,է v&Dö^wݩ6]ZCx/LfrY�2 Osўz># sӧbQ͏B]vkt}PM YX@a{((F#MKg's6T;01  Q{.)o_YDʧ]8(CxMJ m ?R0vKC<nZ᭺-f+';W7uJ4JĈif'Ge544W5p Nc1שF`qdӜY!0:ޘA9Jܩ=ϑK9,C/#K+}8/u[khp<Ftn q[C(x',*޺u3B=|5M֨OM͵�sЉr75&G�r�"؞*,ͣlʰ )'Eͷ?8q8bzZG=p:eц>kCBi߀�yF0zWY^,ttQ}+@l i'M�ر護`*'۹ZL)}k?!>txM(ǧ" d]8ʯc<BAUvաay"ݗˌpTEm-j"Jx>#.@4qd"f6"~ {Yz<tbFcf*RZ{t 1ӟ>9h.4 ؅B>]8h[;`}\>@BߤQ y  9Ө# 5kJvo+X.�LFU)P-D+8jb7k(4r +˟"0*(5˓F2oI�*;(S;HDG&BEH{V@i<DP#qW#`!N%)o8[Qa }/ =xO>qҶ6e${٫Zuh*_e߆pNL8+İ "e#k!h^HtF6vh㣳u[{FdZaԎ"$=52v%<A;(d5ӹ*a4]X!@55Pz_ь<U){#v$d}}^P ]嵈1sQΉQNJļ]]aaFc!B[t{3vTnyC, vҀt~LM�pͤ~ʀ+Q_}-V!4]Bcq4n̚]HvFc.<?<vP�:l7V�� UYGW@�͸~XSD1%Б.a!=֓ڌ"jeoŤjm&}�y}"aaػx'8,s #|@#r =&zQk0,ɣ:A"�͡dVQʬZ"|DNq?7P)]hF ^Ћ, prpE? |:؃ء6쏰_ U+`rЙʾ@Q.@?3U+{WßG8q4!KQ B ia%�I�F0^G`~nVQG-@0!0q>SeSw A`-DkU�*EBL*AjW[ j$噂@ck.w6AG,\?^iu96#qt>&2e>qŝђJj]i|L00īs!ȫHJ"M]Vo_;Za6's#԰wޏ EW b &BXC?F41lL<HУ$=c\kpN$tquN/pHX1Fʹ!نn1}ϙ8F4,GxǾA.` |!o4cB8@8/t728qng91vzW0Lidѝ?SA~ dNG~M!B>wІ>dAg4Hf[48>a٢MM][UL�4HFm\}z8~<z!O$")ʃ\IKZr%ލ@AulPIud1[�Jk�g˻EBO?âV#sd`R@:8}Bȡ?4]G{VsB piB_^NPy\Nc2!$�A+ֲ',DDK擬�t!BiM[{ ]t$))ߒmΤӜ<V  )o!|q|@iε)EX@:֜lGU F@{G&3@tWi*Jyv<.ٱi�DXLTF _�-)ʠn CXsʦavSD̦-t|Cn4\ho/vgo֞Ԁ2^譜<Y{c|&+7[kyl wi2 lb}8}^Qdrw}\ \ksUܨʼndD!\AjVE42=%-U\{i$A=t*%� @">2疄{\ u(,G1֞Q"? 7L�.F[.'Y(j[SB5jvrgv<׾UFxi:QHmb+tTr歞2WZՕ�<XE�CwV)xxL؝$k0Ӈʄqӌ葠kW1|Ba0ǹ ;>1o2(mL[/a[<DbO1V  /KxNvqWXZ9yd_๋&L[m8O>jEOfp )j{&[)#fֶ''/�Ad1ET!Y=#YM)IPt!^Ts9+oS0gS,x` )kp:Vxo(ͼؒ|JFRJY G�|}&bE{2 B�'-|G9{>CFgF Twn߫KUeLf2g7ը1Ox u[K(aQ \�w(f 6 /ϯY@ %"> ³l z+M/ӑ˘f*(KgJ(cg2b>!WԸKzuC|zU8&Q Fxu; о4@uZ8m? v8xFt꜂hћRM6M|56Q{ G&TP詢3-#Qzp&^  ÁS(Dx]Ba6Cǝ. !)Q\]lv)!G͝]o$!gc>pë\Cs298'NRZђqmݡOS�@C.bx%tpИa8Pћh8�aG "l4g Mhڡ3ϲ{|ҥpƫO " !2zgt|\?Mk[|i6Y S?Lݡ.!D )^;&'%� 3vQ^  a&ǷC_ ~'9~O <n <uyZ���%tEXtdate:create�2014-05-13T19:31:36-04:00n���%tEXtdate:modify�2014-05-13T19:31:36-04:00&J����IENDB`�������������������������������������������������������refind-0.11.4/fonts/nimbus-mono-12.png��������������������������������������������������������������0000664�0001750�0001750�00000007412�12626644770�017656� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR����� ���t���bKGD�̿��� pHYs���H���H�Fk>��LIDAThy`ŵυ$*- ֥JVJU@ "j d T⊊,E[UAZ\h TK!?2qoa|ǝ33gfΜ9~3bi;DoٮJ K]hU.Rq;M󼒎iѿRJ=7Nk.qd(b<e:Áz/UqŞVa^EZ}_xZQ07Ika.0M6zʔ) K 3ס *ΐt]5& TQ!VJIg^]]qbuʓ!VqsT3j1w:OmO�:FL JeTTW6Z.[ 8,A]TŪn WY;pL6U%&n1:F~g])FIg;ۗdSNsm[&0d該&Ѫ<]OklF~al/[d+HrMPo&\t(nf 3$ON4 p>&z=_GFyaQM\wjfEKPZ+Of%<�<hUQ'rG+)wo.Q{X.7hj`D�|ܯ#0L+ꄤO#33~D餋j=鳟 3,R*?h91a&p-xsRzomR N2ԆHF 9j/dpx2zғׂPW@efHWpp/'̣.aaervYԵfmܐk{PWO9xȨ[9C HIt,v"q}%ߜ2vnILT1FzAj=Y %* 5)g߳ycok>D|7{'ѷ3VNX?{|%XbIhvmڛ.m_5&Slϒ==_q_DZnѓK3avtlGenjhH0W9ɑr,8˸9 ,x7u6NM9U|'ٖyQxTFdhf 8,jF$'aK CLڕ*ZV9^<$C^ CGK.j"ˎ$ڸZ509Phx&>[f I֩?6O C71l[9cҨ8F¨@[U񪿣ިƣn հRc]" o"ogrlb tS f0O}56G(+q58'3cfzǐ2\ԴFf\Km _9 nw 6dp[maNzX.֩ea;j/T#zõ݆,P'Q�}4plq&ǻxA)#04(;:ڙb|GJg P!f23OôP+#)HLݣ|'Q*8Z (U(f75:mnyהhbCy" ;Uw{"s`\lC(kj{іYb>0Lrh(U4T+4oں䇍x|[{O h\ T/H*/ ~l3+ݛEȓ+P642^)&N(Y,կ%."h@Ò$_@k1h)>3N'v{sip6:htT]KLK5ڴ{ȍ2"۰c +|H w\,i> [Qy`˸QA˰\)UC!u]puBz`sd{g)ZWB ]==gk{,C"?i U!)]+ǀ0unS95T}l" 2#Q ,|<=cګ/FoVzϤ;Dٰ'oLOfoL\/j%G N԰%*秄)0]%,&ڒYT&&hg Nu{\ GY%yU,7YO7?ޟ`gVxusgTTptI2;3K \e7UD&<GW�2_GcT0N)xեha7)#CڣT+ kqʡv 4pvazn<Ub@yW{?444yQ?]egWLv rtCkz^sX5Tw`jasicUJ<\Ôq'6`LTB~u|O&SdaJ0|hE:[X;\W8[(7:80pl1{{7#U'JR7-2n:L2 0p-5-dxѥA!w?X mnz%RCE]ڜrۡ2*ou\f*@`~ 2q\d| &HyP3s\PS>fёf5WSEm+W!X,zN(tFT+&)S\z8֧wC@Ub>>pr$vI- ڐ%G#$$4Ø`&715mnS g�u\ Hs8?r7)=Q.,ehjaF%9똺4}V o1H}lU-y"F[FPk]K/h|H#5 d_P(9i&v3%w;b#?(͌T |r(@'TW=p'r^-Ujm.m?cE{?1] W\.-U)9цdQ]7xҫP md8ɨUCsU461_5lS$әnLCx vY eo>䗬eUT,&!CAR ]bx-Z -B֢sJfr>FC;Ūx=*.nJ3|3jQ/3ͯ=ʤZ{UqZ[%\˖DL<"GbmY6S "BF6 EE &XR[ Td]Ec\v$65$-o$Bw|*V"=}mS%l 3Px\/v`Np8{Q`9*i߭ǜ(ݶS `ix#n+ጉ{JM4W^LKU d>TOaۂ5qA+.CE*G*RlX;V:J>VcQCW. S/9=gsʞ}@LO./5hZ[L-',cߋ-t vt}S45Psm9ܛf1wR9Q-{$@>>QMnS,ZTG�ɸ86ut_U! 9)1Ȁ4ȔO:X)Nc>DEk꘤Zr=AAA/mr���%tEXtdate:create�2014-05-13T19:49:16-04:00+���%tEXtdate:modify�2014-05-13T19:49:16-04:00gvt@����IENDB`������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/fonts/ubuntu-mono-14.png��������������������������������������������������������������0000664�0001750�0001750�00000007533�12626644770�017711� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR��������Zf���bKGD�̿��� pHYs���H���H�Fk>��IDATxyUŕo7K " F("H4FhIt"8,hԸ$qQA;(FEDYY\iu]>~{N-TթsN.....‡ ȕNm< X_N7Va}�OmLH|肝m4W?c-8B9[L(F5:'NCAm]*=C*<'Yd>.OTOPS͠$ lCG̲m$<le>d⌽)+lWok5Xje-P2 6$r[LHՃsMEh'x36A'6_`'!fu)Q_1ݫjZj0?6KzA`Yhq|_yƈ"\ uKnwS^R~6SZ NsWu :G٨\8D;/z84޷jj]⅄|,9Jyvjd@,62_XWoQT(iG�/[jN{.7|Z_4YˡD4k )Zwz-JG灶\3ʽz@ 4Wg0cao&*44Wr |'x05,u3$44AaO_<oK| [RWscd@rk(i_!yMXhs/_6ΉC{Ǣ4ϑd.b@6'JUÆG:'xqMAU4ꆮvçrC'[NCu8.raJ{3-i_ GkKw2hл#ӂ˙ȳٔ @U dɑ<Pnw*!VO)-&G:-afh*H+*5Zy"ީnU?j 00OהhL>7A]Xi찫M̓x& n p5hvhgy cӡ_l;J{pXeOceF-gT(|@<iQ6ҋ %+~*_||(Q0ʨY7tK6J]` z#& 5B9mmX|W?CO7,^ζjM皂taɩ6^1 }ɦ&$ 6C'R}2hг^Wkh=hG{,l Ì}$Kh"*5(.6N9nq=^α5%+7bKI/)[h< .ׂўtKwQ_z.qWF`w=짋+/ߚ]>^*@jS] .3UO]{|^Ki_u~l޺XO-$|Ý{eNlMB4 gPBM1qW Y,F8<u1 + -K YP"Eݡ{HX09.o{9_B"`Oh�ˬG_՟D'}4#ܭٰ֭ݪݎV*4WOa!M;a)f-tK9;/UPSM]2f^s#m;ڡ}8saq6.Iz2yz9~ (K!-MӒmbpX*k jͅ>y*<n $G,셤/GYW1) H3WfWu` Z_RcّbE߾ݼ3x]O9r0Ti7gŖNql+L l0%_di&|2x{y/Uҝ.Q.Mh MAsDnՖl\|^+qi%)H<k~Vm*$CAG}K'7 DX 9sZ 1'C;۵, Fml~UzԚ&|7~ɵAIax9lXoS}_[唡,߯Tomit wo9ҸDƾ wY^K""c#C1řkUz'ˀ6͏cuZd^Vgڀ%ލu.NqYC~I',+><rߎ,M,<C 1Bze`Jm{ՙ QSdOe e;K73﯉|kնیn>Id:u("cպ%dEfXoObLH-H4é-4{j�f@9=o(ykmU)jx<܌֛r"@:q{\w3wٰm22 Hޥ/gZĿ[rt-Oị<K4KUaRs@ ގ|t)&9ˀBKCqՅV/R? 7՛m壐k>bol(͎|r|5oQ wuß\/Ͷ9t4evq"M]3Ǐzx&$jnGԬc2/5ٍÕ!d!o9_*F5F@�ko3F^rh\9n3.}R�ծ 9{6 7.! Rä.)3i{}Χt2<|P8ӣu1:xj ?31ͭ>A_k ^euMuyLd{8/1~EzmbkiqoMV{ ha(J2Vwo89L㇌KG]s<e<":s=-K'OdĵaM/ZEM5 2TkHBx1Kl!*M=TiFLM}LQoW<&kD<օGgam%X:CׄOzhU jw̛R[-(g֝XoԭxIֻ{,wDŽF1mOpv165=Nșg+bk10T1\03BxH")ʎB<Wpz )B'S3-~칇<KrcS⣜4I'FO$] YJ,ͤP6Aݛ-r\(W=mbL{! Y8̲VfFagm u5c>¥F1J5C?eTt>Lg3ƿ˽mήGeՀ"WwLI|aGox=1;O>hlqKΜۄOڮ#*5Xchm5^ ?f91:k1M���%tEXtdate:create�2014-05-13T19:30:02-04:008���%tEXtdate:modify�2014-05-13T19:30:02-04:00n����IENDB`���������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/fonts/ubuntu-mono-16.png��������������������������������������������������������������0000664�0001750�0001750�00000010727�12626644770�017712� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR��������� ���bKGD�̿��� pHYs���H���H�Fk>��IDATxy|Eǿ K�þ: n<A� ;dDPQy*s@qE%d%% a [I(էΩ:[P T@*P Tf^=hE¯= THr0.cǹf4K!߾qM'$ڳ"k"vqG`y 9׿~I'JwɤV?1|?y8j,9 'ݬ%,>�sXDCEM ` ? @s, pf)&pXI>GUnO",` d0r%qsW�MgYJKehj9BG4ǯG0Y{ћ]�$g?h;ߧ-qd –~< 8d*PALpgXc�i4RmҀp<K$+R +Nm ?si,[$``'ΑZչӿs6@o~rim]60wWh~ p#[0[�у$JGYב< J_їɕA�eCaД#E&Oy:T-G1uԎtJn2=k&;BMFI4 X@mWc3^`2BH5!F f?:0G42Eh-&X*sYc ԥ<-Cj5O}DJMYLGz0YIԤ k&7J"H~�HF"Ml35i[SV#r9#J(,1nJ;ע(S^0o sϋW�;Dz# uBrSIo;9H%~Uǣ. wVVW�B|A\ENZ +xљde[6+gU$u�[O0CXeKYk�DkNME!;L1䣿`[o #PMҏk1ZM:N@6UFfprI�g/ө &׆QϵrXE60ǕP�e*}_[/i<o]muIsѓNW أ6ŝ_}li/ء,h1T Q~TGrZ�!3RJӘhjG)/ yZntq�' Δ@#I L.#VV&1k%s']f�!\8Q͒j[YI@/7&l;c>0[8I.Jc}=�Hs74�[gq;+d)0$~�xEiB9"JdY| 'ēG$`\2xVAx*Y2c<1Ѥg2G"H죀3?o D0l%|3sZCN/jk%We^֐I!)jK G$M?Ж8Nql=6RjÏ@ ErLߑb@%K䤙X{]vZ.F1Ef(ӛ(CbSb #%e`$򋄱MT HF5$ajjq\,T&E|uݖt5/jA{m<q&jynj@魵Zru|*Iy xdX,`SBŦpX??ޒ>״& d�3_UPL&@(Y!9 ;zec-$2vV�pLޛ̀Ol`->�](p@$ǸÚwjqu25ZkB,l~Pld�^/l%O6Z'g;X⹙`|^Ou+!E@KQչ|n̡A4!extcӐ4Ng.~O()R={~ 0 $A, iNg�xW5J}hF<қ׿-NY P98%Liފ$,%1f( #Q"v(+ziK"ala&%ʭ `J6Bz�Оj뵤[Re6G\rHxx1H/&I{rLmq*d:I"LG"VI)-%Qv9k6DVITK:UA>I(| .Bw#4 C81j+Гzj=<hDaIɰF%s>ezkp3�qv,{T<  `skqkG�~|ߑ !5"arI:U*(`Alq6fWSsxD%^dn4#FVy"ёqC!]![\$,6KsgnXI9ԃCS_rPH%}V(L &^hӷaH%ģ#쉧#Bh�5n$D>�ha;-K:O@& V#D޻5; ڶ?G4D$?Odȣƅa8ә�ȭ$ʨ- Sfdi&{ 59$+P<*Yޟ8R+$rIElx| hr0??tw/Ig#x f4/KvӎmV,Չ0ǵ F3j?4-2IPo.~uD@_fBC$—#U0,FCө!+gT#]bWktΨ pmhc&~(/w^($spɓD?2BjT2MY  d_%/˫g1Ζ)�f(l (h/mZֺi0#Mx4jJ.mf㏦z|}\_Ba*0@>vY=Ru$02\Ie(QQ2?qe!{qXt5٬f},bͿԩ5Xp{e'W.hM�R oߐAid3X,^_4[i8-@abSU ~SnyŃ*pT&Xpѕl5q(}SQb<.c(iL /~Z34e㴎)̗p6q=,PQԤ)tb=\lzx h<_-A|"|Bs&1d1^q\�n 1DR `}LCy{ia( Y<BߓS&$ͶBOE<9<HQL21zXH-cʒ}˧_p.F Hnb@�۴z3yz4JPE8H7c({EJu?/cIgEoD0hc'[+k?C$(_~b#-^u,%<BUˆ"Fy'ǤZz؛*�XXͽRJ1jr}EBZ9*Y 5<�t#C>f"L7kl{~~e2;g8 8u RlH]YIl}PS"Y~C}VO_ãH9 d- zQ.@ �x("mV<*�<+4T؊G;b56\D.@- X$^ i_01د1x$ 8|=@C(S3g|� "Y"hɚCJiut;Iw ȥS�`='j#\- `$pBrD!L4v:%WI%M. >QU;ꗤ�d:d|2yA|@'|s4R@%t Нt E^,!KRr $ >SRߕBv! |y%-.w�%'Nh/[Bx|&߇xm_^ʛڨC;+ 2(W3wٲYGrGstqC%:뎱ohS?0aɆ`ްQײ TXhB8O||ep)HڐBu:Gq_AA T׳j V6@9`&uvac ypw,m'ox5pX;ㄮ$s!$dpA IH���%tEXtdate:create�2014-05-13T19:37:25-04:00���%tEXtdate:modify�2014-05-13T19:37:25-04:00L����IENDB`�����������������������������������������refind-0.11.4/fonts/liberation-mono-regular-14.png��������������������������������������������������0000664�0001750�0001750�00000016410�12626644770�022150� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR���������c{c���gAMA�� a���sRGB���� cHRM��z&���������u0��`��:��pQ<���bKGD������ pHYs���H���H�Fk>��IDATx{VE{awܑ妐X*x{dd("@ji@?/ϰ~Y?2@H/TT$4n!?>339ye^k9sfΜ|3Z�@!fRs`}{&a@㔺'؇-�A9Bݡ: 1HFmz##ഔ݂w^נn%0Ƽg<]v`pm-W{.E|5 =o^_L4vy>5(�So_3 QtpS<}GϣEXh.�^1_)>pr csO5}8"1�N�NάݡUT�o{cT[C<<^w\׋[o#Ң!p )s:+k2jӎ37m[9^ژ{4~ 3CFT~[a~j ih~yhY|ٌ]wx 8:hgp},ƴ x(�eh|WX/ĵ.5Gz 'Vl[f`B!fxe)|SP*ơiow*ߊbpȄ݌~W^jDv`1Q_< R4ƶKY0 Ǚz!ѱdއ@{Zu;g |:3Pl>'�x M:(z@WSe-=ZS9@�'q#Db2�E@)θ )q،S#Gˁ>} F ~l"e&RjAjC¢<%>l�L&�1j2b}L:`%BuXR &?hH t~;?FJű@Gd,l6(A4/ vE]6Z0{R^;|G>4&R A>op_'K(/�^DB~ 43<o>68'͘_�~Mh݌DF$cL*gpg˻&|:Zsa!|yp)Pmﵟf�2݂֎m?DsI6�#!t`/Kϓ}vFo�L2;)O!AuC`72A{3pr> Ҙ]<n!sf,o0 �;v$0 |9/!OCM=?zkcyƈ'sHaȤNX Nk\n#�hoքݗ8 Q}46�HO *~࿐1 �#޸18D H9eýhh K 䶈)<_3LJg&.: 8tFKIH ( ewB!e_Ἡ y+N0u2RTmއ&hN9G Ŭz>nDmQ/3詤n!?𾿎I_OTohA&3ky2BJͷњJ܎"/#bq,˼Y@OM(Nk#G@72yԹP3RCLG^1]E&/Nf�X\Kn| C( ͈o CFѿYD ?/ HhhbX>"HX䕵EַS?STi^3�7ڼK;yQh G mZ{AT[`}4@'l5HPgC0QWdD嫀9Zc#3hEDFq[bD),J�x߲u"06#*':*Zz)Q?h7LgKP~J\:A~K|zPz$zx7y_o ո(ifnZ~n2IRUf_F1sWv{ y 챘mloFrOjT(]svX܆hK<5 L!YNAvy|&%8/|_8A ) -CX`Œݷ h|I>mT6L$~ALy8g�%h]zޅXx _B ByLYsd {8\i�<l!<@F38 @LEB- |-hgNPR#f4'J p.3vG41HaŒ36JSiƸ bB `N;Pb>ri}))?)`Ẩ �؊ {l01޵ȀFʅlp.?9tj ^51�@.hm\*EAG|јA>f>De8�(Ck#�(2|x�)-ϙgYT"(8!O1⟭L(-<F�c;#<ڌM)Cy~l>Df)+bu8Qh@[H7�Atqk6k|;VތʑHLBW-!7!9-|9:24_M.zSGqsPf!C\S-2$o@=z}[MfJ*Z!.EČC^лIBq1VHHy"*&aN4B&ib2s .|6eo$.ޯQB_J~{GQu.f�4@G/_61Yi�G $DEi+z2bj�}L#y.徊htb&9򈠝ÈzVȡDo.lD O\^E~e_ yZmޅSz b^UA\n)}S KAZ&Sݛf� . mmD4�DGy">XKwҦ񯇢ew EQ~!R@OyDM Kgx)Oy hl]AVHEh KzH(!�GTv ETm1QUHXT"z(E $"V!řD dʜ3I~bs4�trSBMH6�ڡ2$n@Fџ%mh>x"j` �EH2&HNS4�d"X|\&EH liwNN$A|Ŀbr24 2QAWVv" sX<y xnM4! yOALXF^["KdDNK 9B: \T2E lm9Dvy1y n͎CS $GƔ2*pB'#)yIS^)u$D/ק0֋c k}G Π8e#qv_‹h;!>0m-'S;qyh 7ۛH�)F rM Z fCCvY\Lt}B^Oyۮ A<BezQeT)hSDim [[7n++#vw%߆һFBo #7<Gi%<pK׷ɘߣhT @4;X@[@m yֻ(Oxf<IB92G|&2 kx[[4VY\jks Gcyʐ-.XNIT7@ߊlE3?i {צUh "Eb EVdxuoA݈g$ģwxe<f#P4}�#>4b2'hiLn2?_?&c RD^fH"y͆#m#RVz#`ZPӐ)yED~mbq hJ пpSgFp#2["e7WUHRD YPD<մe:DFo"z3;=6Uj92FqѼr#:nutzC_?%3Ώ 2ҞJ062ʫg L[HQLe$AЁhGO(f]A"x5F5yNMr̼܏y(t*7Cqj7\ ZPgSfӃfADy?q'h2QRyȻ$.:2d6ϟr;^KRR?"<Cz?#8#(I؊ |`iHsOh !:g/SACfG}shko>' 8uab:2 6܎ !-=`Dg  wB o�4D2b<|/PtD]LbꧥfC�?1 9ћwy0!5�@|0yo@^!Țc 4C,y`b.F R?C~63ud 84GP c'3y߫8ŦKHJAD 6iGfH?g=~5Ć %\diͩY72YQ Q n/@ wgp^rE(D)O)=>ryW%< !LGu]JWҩ^0 ^Etӎ ,0)an|W;EHiYi s?/qmA05hib6+](C+dd]ֿH( p�|}r+ 4!;v!Gjb7`9(jl=Pn|.mp1 09Ndxd\�R2xd|?|`G>hg9u/Eևg&g)!ݐ|\K4 dx$q_ UM&Eu#RN~BdS,h@ R W??J QJN D#NbhbE,'/D�!'M0)*MBi;#Y1Ck�!+zRKWф\Qr6Gs,bKls{ҸĴ V~,"ҕ7]p_ZQF'?yNCHE "FEyR�~<Mͧ H?-h@izn 5Hh<=Y6x'ZÐ{EcS7<f2 n@ |H<^$z >2$OL5fl:"~߲:3E~#xҖdamg-$F`s$̚uq9PnxԾhY%Q9s={Uh!W#yޡ8㲓WN C)a cޯigk'n\<U-O|39H~ߌ?@k.d/A)U޼�7QF?TNE=оTpN="HOvBMSC;zKy_ʌM& w:r"؍""]CD?Yh~;!ޅ|9j.A<^7A<cD,TrSJF\1Wzm{Pt n*<TĻĭD'h=(~w =k:? D[%hҋB8?=7g6F]SoŹdzXEǝm.&3R1{Ay' .\\'cGc"Q/yh03Ȫ*F *4ӑxyrꃬ=dM% k DhXĝ2-) мMtZ⏹�Wn76F o%ܯdO 9ZkM9-Mz)$l ̋D,3ϯB4v'),Nz(sQEt3h&(om;4}6Ap9RC`{Xak`mӿ=?oQZn =nMH*Gf\pCm_<?k7 al,D TV? ߵǿAfMPjx fk{!t9J10wDSrlQ ͢IǀK Crv0[޳flDO*FV#njMhcZ_5cի? fS?LH ɪ xiM}f<+mM-Re^m-AF:$ߟ&*+QZL1>?iF3 v9lB2Oj6$= j:^AO~o3ϲ<N}[dHk8iM?GBˋm<J/Z}n兇qyu8 1^#1*&bҵQn~l볈| 4`CW4+" m4�> šb2 QAp"ZM K'qҜL&CPJ('q"?Y_O?NB` nz)J;SE5J|yc/BgEH!zdw*݇t*Jhߋ6->JӏFh܏TĖvm3J2p&!# deZ `i/uç(<|ԭ�"[Ҁ*+r\90n䃺@:^C|e;QNs?INvۉV���%tEXtdate:create�2013-01-24T19:51:15-05:00oc���%tEXtdate:modify�2013-01-24T19:51:15-05:00����IENDB`��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/fonts/nimbus-mono-24.png��������������������������������������������������������������0000664�0001750�0001750�00000020156�12626644770�017661� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR��@������ꟍ���bKGD�̿��� pHYs���H���H�Fk>��IDATxw|ƿ'BEʕ"U,TQQ(El諗bzEA:PB J g33;$<|`3B!B!B!B!B!B/x\&B!m!BT;ϼ X^&B!9:1X!BQ4p7.@QG]~vRц.tC!""5M۽CxБ;,q'Yo  q@"m%< ЙRN%&A>bЭ|]ǕRJ'6U䝯a- ^}%c^CG29J"m8fI^\OG+2&Jjmd\#vq \"`З#6v'q-E.(%XrQKcpl0nJ%єvS]�<<"R9:FPּ| Tr18F-隹B+%B;ma %¹Yj䘔Vc5Lҟ0k9MVcco qNR7+91Vˡ_=bbY UY!f>cVnfyc\s18G.[xd<A[ry޼x+o ylSLgKiClk.AvB=hǺ ;Ț"y$M,t-AjNޣv (B $gv:?K&y/~ :� 8DӀ= @:Jyy(x9A: s9?~?=Hw?Diҩ+xXd..SX &M%I"iGjYѴ#4Pw'q\!#G}9<Be*(\&UfoрRaOpB*t<q.,'4$L?[R>50¾kXMT"3¹(Z[ءNo,c#7SҴR]9p q 6ҫ9&Z*<('[![LJh Wx*w+L'RS.Ld L2&4Sg?ʷ/yCTŐa}4a}Rܖt#vĐA ܡa,e; HOP%^S',9E^04:ԯ4./@? 5븭@O@;a`PHaߋ�Ȳ[n�3T;F�*1L 510ʥӹ֖͔љ{{#VVi*)]ipA[Ι쥜k_ yʿG3$/5yG?HW {{$i|p8,ђelJ],q\gtLaCBRKl:v֘GVo{xב<z8zXη hvVI@QZky{ <I|:OB ,gco%wYǷ-i!2�rM<f'Y,= Wk OlK52_!}טCve Rva񠌯ߝҾjK  Ĺy zZ 36)Y[I;.L>*\cԧ"\  R*$="2`iLUdo-D([a&!|-gotz jxJiKJm1G{`?PNHy%fh\%p;ɿ[Z;jQ >P #uNGZiseA, tSnSbvrEK@.u,V-@qb%/TAiVǺV$y5]Օd*W=BV[M.O(zueu|)GMCt^R XͿyq#vT'ÏAW &Ɏb@. -U" !O/ hgOhO*ZZdgb"erk;rڅ. b6};1 VPܓƈ`;ZǗk$h"]x[]g"2UѺK2ㅬk/Jm#d%y�Z(;;b(oQEݖE7Ve&Af` yew9ϴQϡ-r?Η>\GK9!O;_B# /gfWdcI[XJo <c1E7=ڙG2p8iڢ>&y2Dô/ѕ*YzVQi{{Z jsuxHO6ߦ+Vm[1d $1xrHj(}i4~f(%\JRn,XEg/'}6:G{).6_bq5\ZNcp8Rjі_8 s{syI<OkOivgf;(>%͙vN,FZXFNGG\C̟6,7S;sZml]KcO1\˂k-3m03YV~Ny 8jIV u^BX 眰M VT�-Hc /ʑ, 2#Vykh8 0Ӓ}ȸۦG8<r򋗀zӨD aEEBX;=LmMzeܯc)t�H#-з=) 8n9R^UR.c'S<@b2W,qL 27{JpbPΪxRyET[TFNSyb/E x͖l*8Cc$p[!ZE@;a9 VL3!jj٥1ܹ^X,)w0_r#Sו*%4$5a~Ov"HKZ&1C\"*,"aa^4__b|*& op5)I[VKv )E ^![zK>~Qg{/+lAIIяIUН]=+Dё=Z㵂n�x8Gn6ғreNYF %""-&|}ոd% ϒV )I0zUYA@)KhGibAF@o0Q>٦ɋQ6KY W'J-lgnN7rVfW\TijNNt4[`>W(]|~,tgyl` ]m{sT�$( m|8#^p/^zq ` ̗lhA9e79 㸖jJ -x43Ӹ] (.3PTFPa7]m_c0š*@ИlFMN FsH2Nv)L$Q<cӕ΢"]I%o{m| ctR$Ya||9465RtdqUmj ,Ew%'Hbḕ {Te�cyd*٤j�d+K:TF <Pr~)>H3<}Ei'MȔqS@)롮IѶSKADSZo#FV5ܔD gœlJP3$}` ]Zkbyr@z;$]û'0p,rK Vڭ 5 /$f[[ 6HfguE1%%#ՠM / $]Lr<CkV FЛv: f Zj>f>D,%b$li�-vP·! G@= g,%9E2Vb"_QM((m Z9jPiU '6p]^90 .'_5mn5K ӟU3é5f9rժir{7LO-hI ١1q'"2Mz& |j'Uk(jZVSrѱxh,f{LI$ZC2i"pu8qmYs Y=ҷ8\Ój!\ɾ< f z3تuMX U4{۞;QdJ杠4zw9 -Tֽ<trY,8yGf1Ƣ .(mGu'<i:B9Ε8ö;`:DKk[ȅs8t`hCsv|/ K@($k %Ў\d]-IAHIr]u8 rP[狰IZ2%ԖujgXkA(4lY7!AUj%&Ѓs4;yLSC-">f'>y|k%JuDS̗z=I...%UAZk5VN}sgN%SZo;a>})$xFSJ61e) fSM~z IvTdz,{]cКp9/Vv_р'!<JqеAM풣Q=WTt;~VP)y~pX97^~f%dz%> P4c+fVȣz9dj#=ךBUd"amv/Lm 18/ `q4)`IH+sTSvħR@& v<Y]q I@:8{l. )),,ShnAgUC5WR*qPCxkhk$# {Q#aqJSH4I#GS=gE CHK0gvzHO}|Eǁ/rJBHsIWu2ZlZdHHgq*[/j) 89,̧�̑("&~ k: 4aRlf�pۖ#eT,jU.^CQ&ٚRZ7Jg;YP/z#W`TgA hB@ @CsJ 2{.>=-;YJ{οH'jQrd"ela 5on@}Py$C~kbKї QH jxI#8jC·8A*j..iJvf aK vb4 _}*'.7}D K+MPe*zqP3B\OcTqTAø}LD[rL a\jf.m: c<آ!)ܢ /sٙ#LP6bLQl!ܖӸ4`%|fҐj<,3RXrbTlJRdE-F=1I$sU_ ҍ8fH !*YFm@hc3�,){YwJlGt"峌EG@Q-H ab�0AүVJ(Iw6IP}TzcL yUrQ_Xk W a/wg^WFh`F>Xe<YL?}b&5jZ{WrN}b  ~&=Pc sCW+};/vg>șD"J:K2RlMblFU1M9}1bAwhdz*K�.8cc?v<nS dT`B*&<=dnYE;A![Z'}  < O@}+@4_X&R޴G�'l'IrOIp#! D{'Im[ It ;N&א,aޑOr= B4`{=Y.٣ᠥ$Aī%|5ɊyI\+HtDH,6 WNJ)P ^8/M4'`s3$vќ� ,Um~)W+NX>XMStd= Թ.fzvZWaq{, [9#pinyNЯ2|^/jЛ70a1|G4o{yCjX&B8o, Gy;21.QtEL".bc�{;7tI<Ӑ(jsq!2V6w MjJӈIi\&i BmxTyR58L%QIU{0pOY@l?__邁a,~c}Qp8Ǿ*ɴY1$�bF+<gRe2[!^d,r1Tc8Xg `0vYlf K@9$[6}٭ %l<c% ,z#SiGY*3#t]t UAE n3(l1?c5(0kl A-]<t SHp;Yd1Ɣ1CȐ6orGIZЏTϐ P "CWe7q1T=/n-=T&5}ʗ/kH"^'JUM.d xl#arL@џ,K~2I53=R,չ,M-5$.�<$r҆4'wA8lcHcF9)~ K@_�B2Yϵ$5h �۔OKISG #}T"#' THNK^>$ԭzr0ra5I䰗ܤ.f ߳&gF )v0ZK9L'4R9D,;D8pOCxP-i>kw='x!YkcG`M^+D>!f)*qV0ВvU,ɼ#QX%Ȳ8/ļ՚sI d% ,jzO8?Ea?9ld!= *kK|5_%<}Yq /"&rHe5 A~5c.!'YHY̷IqX襺d}!�tð618' pC0*?CN3I9rERd79f6]>-i49v&ۈU!l[ޠMNNd D:+9l}lQr4:9<g>,+Auz?|W|@NVXH:,P\АH4|6 9My۽XOey (tQ c97Lj�*1l2YB_<d^Y#8aݕXܣ 9aqP_QP .,N/X[+6¢A,~R <pԏ9ߓY{}f>/�8T RUT()"O7~ >\\Ǫ g/t#**B2e8%c8-Y5~�LCphO6)~QL`]8(Oči/h-ǁ`5C^D0n#FDq)C.pXoPPIMB(Z')d3'l18O N4Tx %:ۇ<GNcRXt)Hu!B}h g u_P3Iz*?؂=HuDe9j[ F a)}pb@wy~!B!B!ǟt���%tEXtdate:create�2014-05-13T19:49:26-04:00���%tEXtdate:modify�2014-05-13T19:49:26-04:00s����IENDB`������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/fonts/ubuntu-mono-28.png��������������������������������������������������������������0000664�0001750�0001750�00000027062�13137112354�017677� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR��`������ĸJ���gAMA�� a��� cHRM��z&���������u0��`��:��pQ<���bKGD�̿���tIME� P��-:IDATxwE%-9HTTx3=9aC<<Q3PQT0( (Ar ,l`5=ivfaYO?v}TÇ>|Ç#H TLJ>|DڑHim7Ç>�0Ƹ&#=q-ikәl:8Qn>|T9mC8ZY8 垸Ods{*<`#elg.Oѹv~FzG9o䲒#4F;>ǎD5L19gE=ޙgv%7>jf  pg0Q˾Bzp:�Uj>|Qm}-Z_Z(t%D0.:b_}}䘏L܄ Y~ҵ1r!r:K*r BK" 4.l\0 oD(' ]bF`N`\sOSrN=I1S'u+/T>Bió'? ):H$f˾k ]B\O>a3a67.fK%d>s-㨕`g {]nclӵYD1% XքgXGy߭U*L%J m,<fpG}XJA=d] vw( H60Ka.(e7huPNsMw2/j_3=9jIɵ."Sb0a׽y9V;v<0W:Y>0hMb5 Fr 3wjjoW>) :9ߊ}0rO su94G"RR[ݍHKY !,�E{p3!JxAaSLB!0ه0@vZw;#{7A8?{w~$`Sj;86p'0�N?RU5/sa"Ŷ>w8B6Hp#5Lud6cl'wےϯ.liT <R%Wc~FLEHpj/Lڄڰe+{ǵ%c]O +-\9,չ]V9Nm !|J[A#Aj spە( |;:s'ZJ۱AVcWFPj>?3 _1 ޵waÙQfllu 'v#!ڑ7iW*B`& Nk;IB}VXc@'0wBg+4RPA>w,kJUoZzS꽯=滪d_7+p.KY!JHEA )BxRh�4)?cLS*Jt:ʞB1cÕTTU!0W"WIZkg^qẢxY݈$<ʼ q5 / %�^9GC<a 9o!̣!0�em A2`X0Ϧ>z@TsVm?�F#Ձc4 !vLTl%0]G{9|ą4Tv܏P#^2(&Bq: C _!lTBl#@i@*7Qpom?<ZqY*YtMM| a;yC#;2A,MaBщ:jf+"ȡ6=z,<D .򽢙 L1j=I`Aqy lBh@ L=l_<Z'0#l"I7+2\ ={$]"&cH3sPM979v/n}M`2(n$Bѻ6^EX$#J h~l4x Ý<M#C`!'0|pGYts7q]{ᣆE`S&�0/B(`0-I!0B!ܥcj4@Xƥeq8O hdC!<K 沔f<^ z8 &7o#fR u4-r&^1]%4*)6}ma[$ � ؎՘ b \ t3ˆ#d'/@=aFD³0K۫H`7G*4z-Xc%0#TrKIM `Yy4٦fYr a!N4s6b @[JL*bc]M*W#00aYD#b);@ߊ"7!#}{*4lpe'd!܂ [9bC(PjC`}ScyȊNm4χj">ODk Y حtgcL1� x!@ x5�@Px#oՒ2�ZB]ڸ-mxw"xH FМ<@#pV2TdLZScofOq_v3< ցe U,w7JzV9?Fk$&-P8Yd bg.ZԘuJeT4(JY淙IO`び8<Ų-;8_Ϋvdy'$1%VUs_J,s@[g3Kub3?z59K<MTB{*S_`^�| 3$Sǀ{#w`([I ^4|FfϒL>']8~"SJ kxA.+Rz!'PIxOsls|sV"W3t2q'j W*w2|*)`%j'_)<j:1V1lObg]N�*.~`E,nz3b֛V>KA9E,柶 X eܥyY$ SXK0!8!`_cX6)cs4[¯Qn~e}zFԯ荐 JtnwfLRj7vh 5 G(h5ӓχDžB>,XPFY,Fʼn@{q 5J9D#(ce0a `|ϻ^;qkh ])`7`m*a初 $CƊϵ-F<QwgP&!kO5ƄНz!>΢(Dl<W@ !FU՗;g# XH_1mՒbVd!<w{=#,0#lèI L;l}[nd"AZҐ >a n!0xBjC X>`Zz)CvZnspYҌ2k-q yJlEVYNG*WVGtp3*@T}lA(a4QjC<aI3DdlaY[g:FQ|.'m To~3z%nu23ͼ>ˬc gHf=B% !!ϣ˵7,eY@^H9*6eT# B4,'WI9noSl"|1ZzuX0K6a"a!/w#'=c>|8Cs יzJL!1R.1)b)'=A:1 ZF($^ nUc8齰snFroy>1V6&R*s<r@3aš'B)q7mV4J-~d%3鑆%FИR` 喬OmSi pVМ #ڸ7IVLaz! }\(zp`3[S`ONCaN7F!N31-t#0ϙb5G`e-ZH·VE'&FXcce t-6TNF%0Ʒx![}g`8ifϒG<#lre`'$8E'0#Df'0,FO) ¢$AIMcbЀz'aICq I>ǘV dӟz4R\G ٤kr]iBMU&H<I[iPIu,^yi؋:O9 nOz ԧ!7O$ͨw7@ Qf%#3@nq!0Ӎ@͵o3ùA!mNGZD}aۉsayDv#۬s(ؼD@똗#ģM`5,"Ulx>< -'ܦr<@W眀@)ζ|";.X˞VlFr\҃O`BZ$D;L%*FtӐm{#ɍ_3D@E LJFzv\ėVT`EB1w޴ [ekHLvb#WG4o bj,?eB&qS "]ů)ܲJL%hZA]J)B)ҎD(g=CilN$bGr_iXW1kVY%?7yj2(;>Cx۬e I"B`: ؃ܻ"[ LGF;`%08A"!!FTUE'0[ފwxch{o@T+za28rn].j4VnۍF`ZnN`nAm-/D(Qߵ=BՀ=lnBio.䞃P�%8XFMv8O`N W /sJQv}Fc/]ZoI#F2z 6=L-^:2M |JW~=vki^BG_.sALL9.(Gx\{۪mN4a7;hHʹϱ4Ob KzVw&X% FIc#PH[mWC Vͨ CA#k>'6g5qI¹̹`O(}]1942 u(t*LړgY&۴_fsv+-,Um)`y +-Ym #FYN;j6EPLĕO_^5u_w N3a߹KD4wމ PZU#0A" +Lb>p̬e3&0bu:)&0Iz l lOO$CV,A[k!SlgpV4DrXE>}ALБ'1s E[\1=Þ*ް{(]V T3>ϜFz.Dtݵ.侎]jsI4s5BT=ӏ1B  m}_Nx�sXnRwKff fפ$ўC4c,]5d-#n3+ KpX1uܿc ԧubVSRn0Ѷ1mƑ7:k $MDs\nim+;%_Ƴ#13cj b 1aeIVAFU:McaM9IMzIƽsvXtq*p(0 YMx2cԴ!0Q [۳'젂\櫰EBm lA >|M1Ni \8piy#D$Nnc߅CDj΅ \s;*h^!0k٪: 0],6v;tOޞ)F(q`O`M/M+i@-Ed7 Y9ژ2 w*:exD'0w#dGQ8c`َN1GWb%yTS{Twm4xoE6!Tr fa 35FVK/12d=99Ͳ,tPQs%B@=ͩ$►P̈́/!j?FsSa-/l".GBd_Ӂ* B3#ӃdDl}>|Te[\gN=дqfHЛ,BZ4gq_3`0!Ƒ $V0Jce#1 b=YtQs6`GmAW_A+@1@%ūB#r8  ܩDƋɪۀcZNe ;#nҀIZa)#5њTr!_}l|PYs)/ RBF޽`ѹm4j%p-e/p圩]mPŊ~:n, odbTi_mGf]5%CurLK`q3]}*" 8k $P A72#YA:b{| J`�)&O uyO;}@E@ ˤ1eiݪ B˸l< zc Y h*H46; KG)rebbO)1 `a.96frCYP8Xb3X@䓤'f- e=I*0*ҩyU#xٲ@7.6!D<LW%, _QD<n6Qmtj9$ad1t#-1f/91 ~1)vROєK[YEoʹI9-.!nKSKjSє4UbLK_Lm%ArcU+j vi|l*!I^޶l+E@f[޸-; \MV+7(g(IH}<X ^0FvD1Ќglk%t#X!GJ3P ^50#aB�8ʱ._}tk} b.>1uC R�CLrg@ w#l.d�9ڛv+-9˛fBl`Kھbw[rXF4BB9vq.z@M+HL3B\A*:AkV:ϳV.KDW2zvOm4lg8k-xds-!2vDpu ez[,ں\mbEu$o^wq+9j h75iAXEP~U x " *-c( �q2hEt@krȾp4݀,378�8ѐКOXm )L/isyIr*YMmڈlX_ Ŭd'JV(g%+YIXA4Cp:(9Â8&B`5 &C I8W940&a?5Z�scktgtw#Pl6c- lpѾr Y8^8\:!NGdqOm)s)ha:M}e:u]Hsm<E{1CFƂ.n|{ݬj뽀BKNThK'텳�3ǷTq\~> >u4]>c�?\`s: Xk|LGbxd &l7-hti<h̠̥' øx FhKYM-Z|u !}AɗGz$ ,jgr"!yEz4CX8aߏPPW@[X*V%HE8nth5g@C*:[X�:lʻUnPMLu 1WB$L5~6eF4sxH(-`K9Q#hϻKθq]F1i te$�a( Y<]BU5A/*bR9}Dc^B1C^f5#F1A w!krh10FEQz29d#C>py�aFꒃ[+(!/?4?r; ٶ#7bPy;;\ƨB\z/"Zbe9R"YE(q[eaz10Fl[@cS@$_\x(x{V8MټD!#^8}=r 1+Ո4GX 9gFsdy!<0!=f#$NŶV(Q~c` Z.DDG$U# f Xzq p!X U,zF:CfEb`klֻ@_#-{ gj󘁁%60D`CxIsh}(f걖pʂ*gn*Ŵ¶W" Fq10>|8!DAcA95,;/to9/*鄔7#`A5F�gS ̉цTBn'ΌbJ3beyaK£4 !>F`sU%&iM t!w=;yhGtR"#d4v:Ki:@L mܲh `A! A(tk 61<v%Pi B'c͊K Z *ѦNDҹidP($`4p k5jZ]ӌ}O+ 8D28eS a#yngrǙ߅dcNI r-™7J47 3}ID #J P YP`[7ɽ϶" PFjY7~º!*p`\#x-z-Ö`n"|"8_s?$ӎ?r' h6CF*jCB0OZqMv'0ABOҐ' ! ҆> dw @}p.I`BiDcPz<ӈLW5%FdrL`!QE;>EOyl@q9@HقA %?0;a,2ejf/Ob/ފX8 Y>|86 UhtQAxA ١hH#rC ʣ䱅 tBxb)s"oQVIOe-bE4sϬ8i ejv0@ge@aab˚h9 ,􈨰tvJd[Kf Pm#v89+5'kWnUˎS=VבN*j|VВ'2SjPޮj#lc;IٙugaPБOj \&\) ?XrUɺK.#TI 6-]K`.E߼! Y"[+V[ZJ717ac8Dr qOFꀞ3+3^n;L15F3-jՠ bdYeCx])lClanưaٞj3 a 0P.ճVo,ʋ~*F-جªBgyXLp94cIvN;.,[To3ڛgWnqȑ#9}V'ʳH`9=g1O'Q-^P$7p ޭqp>|8o0NANe dr3٩ g:4fٚ6~,=MGW|W y�e0B-!i§qֻTG̥B(f:Ӱ\}D|&J)c;SinCRB9|[Dnd'O5-Lp2xcergW|]`X,̴L@%mĖS` ER !<`Cw0\ O*gKCe) sy'6keҹ%@>yM ̿WyɌe%L{N!+FYyN`@Wd0%Q"FXۢ4>c9o'0FOu0E졒},E$^1RzƸ8 -@5SFO%S?Pf}73EUM`Zvp׶*j3ZIxYG=C<CTZiyRK"1֓lrNj@b [FsB`Jr[Š|n*6Y}i/Q֬F1|O?6xe3Wb$0)g+MbSpb*$00)&@!6>�A{"~i#xel*[ l "Wd%0^0̃v=Cqd#@U.f#<?^"ǁB#<R˭hOKЛ?c Uk"0 3eUxD5'3&参"ՠ>8&/]r8JGj_ %mJO9Е ̲Un3Wi>wш2j3B`#lqC}㍯ 8w8B*cNiDzE'0T÷ć?6EeyC  ?\ %젂k9>0#(>U7+\Dy1A<sAs(GX=3&@"{7 ?Rgj}s>0c /ĸ^lx1}4rGHm0`)AG*uEmB19ϣ#Te1ol"7*qFH;q8UְO5?3>JRvW#̴g!% ᣆ䲆{]}$n> n3K?7tKϣH�|i 滦R!'V(ecZ۫j\VG9V3iR Ktdvp w'0Ev1yNÇ>|Ç>|Ç>|���%tEXtdate:create�2017-07-29T10:00:12-04:00V���%tEXtdate:modify�2017-07-29T10:00:12-04:00H����IENDB`������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/fonts/ubuntu-mono-12.png��������������������������������������������������������������0000664�0001750�0001750�00000005650�12626644770�017705� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR��@��� ��� ʃ���bKGD�̿��� pHYs���H���H�Fk>�� IDAThyՕ6ak�.dTa$ rb @c&L*LeDL*2: J؉A(; B/H揾{ޯaU9sνsт-hA ZЂ$O>f֝ral{<wJkI}Ҩ9de S%y8]'"L+=xb%>-6w4x <ƿ}%y PmEG +1<=n̍\*J,+ VȴWobIH]ߪx1bSIQ;:*%OsGsXX̖R#\9;`;1ьØfEXbGmUH}b7g\0oRkeϫ֦@J'T;S1Qp^|&>L1dO}z/ AA*/Oݽ eɒYMz2zKHe`cǻR יJ\bJ`wcT8lI,Y߇D+=o^l#m:<<%NYQ*_ZB4+)`;&fwq0{AZȚmI?e; ? &yLo1;Ok~jMآ]u)/ ݶ0j]WϪPO_y2re_�LěXҏZvow[j^^Uc]X"Gao[ws6TiBxh !Dn>(o\hczh8S9HKvG;;ckeYߧ8\[3A.3Zvl>]`]r}ZuX<[^4 ::vro+WMY"z{hjX$}8r@-&S M[x+l ªu%\fI[+񔹾aM_9roqGtn;k vLB'cA.oXuso|Żaen1!HkwU;* H)mSxEFZ3zg&קD葫eEObxN:P^n =FpaU\:Y}l O 7XO_#Y266|εOr\ v2+i*m&>Fi?UVrJmƐE"uF37BG󬓴,l;DՀJ?1Z]"!Էgd;j0ZSNΑ9�rIh5/ ;8z<+7i|#^hbnT,!UaT)G-Ι48٘\d'mm+*Tw }NY xzbwƚ6 <wWv?BJ0˜hUi"|_; YfaQJ[{heqa}VRr:u֡?(:r7xuYn@. ?\R bVF@"ϣ )CC D,Ήt썘ZΣ ˆ$>x]Pj]lauH&;dǴX.f)CYQڔr)͡眞Xǰy2̔tγ|.'l26o|758ʄsL]k^+Q,ggv@!:Y:7=kq U=uSF0Oh08`Av^WeD6J2̞vC (97.\DоH*]j`H+:)5߻6sws݌<d,h+</<S3A]|5\$YŅy|Mk@7ޤPҍpW|[2$v>[\mTx1? O>{0V& }uk#g\Js(v6 `dEhxfy@ڿ4+Pz%*+8"75N΋SžRK;hP~/i<ε " 4+O ,Hi۬-qUaEfe*Vl0>#x4l#feKoGey#gՎCeq=YP?sm՘E_3Yأ'>n>5vj{|[ ΰ@m¹ƎU9cQbD^l>7wDd~AG<Ud_XAL駏  `1A^PSx% 6:yz\ 93cZ&얡MU*@4>(BGvKm IW98DLSJ%Vk='r"�7 h;N 'geh2;$)C.Z?xdN(;*~ڽqaDlF>B[c}R3=9OϩJpS&qc`Bɷqy)Ήxdn Sh$)(fB{ÏTz덓*,WA R9wI'y-W(:Q K>)i~<�S���%tEXtdate:create�2014-05-13T19:31:20-04:00R���%tEXtdate:modify�2014-05-13T19:31:20-04:00����IENDB`����������������������������������������������������������������������������������������refind-0.11.4/fonts/liberation-mono-regular-12.png��������������������������������������������������0000664�0001750�0001750�00000013640�12626644770�022150� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR����� ���}y���gAMA�� a���sRGB���� cHRM��z&���������u0��`��:��pQ<���bKGD������ pHYs���H���H�Fk>��IDATxyUŵM"6SD$J AQ_1L('0Q`1DbFD@$2Ai6̘߮Uu=ro7AֺsN{{Ӑ;�G.J#AA2+@?L (~*P/Zn[JN�c?ˣ 3^5X p_񱴣ׁ R1V4V%Y Y\ϿJ=cO8x"A4oCcy;y=2Hci:Z Wppo6`p,n_@˄kB"K;VfQP^B!:O)=b0.a zY>7ϋρ2 3{;!.=GefصH%[g5~:kO,}|�:cmac60$v3$V`P ӭby .7NBҚkH`|u}9@<Z;+2^sA'V4vCrȓK=ï夾)=M;ʹ/~d[Z*]+ -m=0 /rA6ʀ~Ha~Ⱦ6G! sH@ yay�??Hv2%@kͬNMc�?E{$orU<kV@M22 l:&][�\aOE$("!]�tIu_2kBFE-\g(,Ɠ㑒u jpa8F.hk} Gn4CJ[VHy4jb  IXZ;? #"]|itcXdbx1xvAB와:l'@dZ�<Xlt=^ z^ee:"_`C:ZCS/.]sFL"[xq$s(~Xe#W#C;X4GAs3DD '[,\kX'y>%e}&HD;ܑ2~!L@'X?Bh3 c~oXd#D]2ez6 -޹&r|-z:TGz2ÓB`28Lb�<j Z)fA8DH'= q"0ʊB]Jxr�Ys;_ B t9kR5{Eۉjȳz6!AT)ȭG D!J@ eeq9q*ރV� J,&*, EVs]p9p7Q d*ԅh!C^ȞȨ<ܻhliI#;“Q6!_5$LRqƞ$H; ^{F@Es&='(w8De-D^=܌HW9Za^o2H1 u<!!-Z LErTj!Ov8Zm,OPp{Ș.h=&#VGBudJ$W;J_!E�QС-E O@[.9##*nCʻ>Ρ[J4\=G"QB4rm'z]nhMc^ٖ hA/Ѽ\ۀы2",~sl9g"ck8E#9}r mL!17/g!B8_^(+?NxOxy-eD$梉(V<PM <?H,#٫6 yp*q< $[HUM@=.G^,]т6c]&`+2 FDڊ}@PN9Z˭-Ы4N+hPxr|D\I^,I .HY?7OFBa 7Is3G¬?526Z{_+T:h2 I1d`UC_[!gY;F@%hMhNN7Lij'1h<!ڟ) {kko-DzoCa=?(hĦwpy_!S~Pפ#GJDo|ǾBZJGx&oo82'' @(C D R+DsdQtj hs4ǻ&Сxa3ZckyA6k{HHg =1"n}D[ANFCC5 o *6@2΍s];E!\Og^?jzK/B+3ug}l ɹ鿼=dQ/DC08]ǍA )Yy_#*̊Т^'5 SCS꿚)(+nX?֐$ Բ7"7X[H'-A־u/q`[]6ʚ_wD^E"8Hȇ{@#[ $K>C2A mhOÏ!)m4a|پ;v~$C,_Q6D M;3"(SޝZG\f#O#¿nFd8: P?nuGpgȳCcw<[}%𑨫QE+;y?VnV'sgGhmBIt<*~NIQJt϶h,"4?6d#q ED@q5А z hk|ImYd0QJ4zճZᶃ񺹔 x&e}~C)YpFvȟaԾ7!99>OLAњ7F,e(QZltc̣Xe}w>!v! R u»Y;!+١:=4!Wؖ# dC/H9C!Rߘt/k_P/xAC)&mN!H '܂(92[#%5hd&oDŽS<(oSow#0>a:Ds`(Z ](FdW VvEua9ì/6Z-ќrki Rx{R8<ǡ n_h׈*֕3ܞC!7F"zXqȓ7p C zµr4Dm"Pa(PH$˻Ž#iI4)&4&X i"vHɟIhF]7y9$kX_ހg>؆Di/CRx2G? s܉P8\S3Vơ>Z|kHެćN$8Gs~og=Ns ЖyqmݍXill/ݻizAvF.$]-GPz~/E$gZ. N@F Z0%dFE2"q.bqrMB|mK'CC@ wȲfsqOcD(#i�R^]5Ͷ?[ !cܣ>wCRKն82"+d84{8#"gXHC;o|D&1 vOq9wb)R'OF sm>J4G"%M|5$ fhn m7"jN~t7 )jV8V#�GE$(q}*@^h۠qv{Bq-&ZJu:K뛱9խ)dDvEh슂{OZ6CeߒL=WDs4 dǧFx V-}DΊH^On9V.9[HA\qr뛤wQ ǽ-Z#eHkuޝo[+DѸ2됟ZQGI&736" # a-#&[}xi68FdEDeZoB3N 82_ESbϞttSAN|:_܀=,ʻHlEFHwV_>{+ o!!6->GBD�Ox7#wkܱ^ TD޹|Te QŠﯸ/ޣ h?(R{2%)GXBªV4wZv!R_Ʌ rVһݘM2jk;p){.R�sz4I~\>hq$?#euRW i֮-A5$8ݳ&աϳ>HM$S5B[(ۖ/JʢyDZfA>4d|H;�S8fN7Gmmuє@k61C$t�" Η"D!RڳѼ_iLD|]쾡TH^Q2*zH>,EzjmHD,f!gh;Z| ^T%;J^p2'H+A`d=Cl2z6 b$/v7Y݃l?r+򿏢z%!B91(s72�F}up!1}VNB:`ף%˯Gq+rnD('&FHEa(b׋ OR!U+ &$nj%:IJ0knO)n p;ZФqʳ!4D>C;|K";7VDъL`W e0<jRWie;)}{Qh:EH<!hIC$rۡEߜH>EGs~ "Tna9-ZqVr05@^K2_S:(g=#|nYH?T(BrcW Wu`plH=g{:u%MxH72)J_ 2C㾄Loy{{E('fǠPZ1^ƠhD PdB{D1tcͫhl;]�ph#C#6oaҴCH}."a%mJi!\+!Lf;Zk͙A#<t^tARdqzw^ޝE:r1+qCjZ:{ζ:jm^Lt]J^ -&?-q#ODQ5P0ULG t�cn="Pf<y[ݲ I/;r!i ?c {;+*J|Gy-?r@v8ОTUEp-,͸Z @r{Ge.腼FU9;VUD^ϐ'{@ju!ՉF9H -AĬ8&䍟S_eF|+k-<̝ !kIy�3|D�+_@N(D{gWW{`+ί*Z*QoDR}x>x@ QU*~G|LрDgX���%tEXtdate:create�2013-01-24T19:59:17-05:00���%tEXtdate:modify�2013-01-24T19:59:17-05:00W����IENDB`������������������������������������������������������������������������������������������������refind-0.11.4/fonts/nimbus-mono-16.png��������������������������������������������������������������0000664�0001750�0001750�00000011710�12626644770�017656� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR��������s ޢ���bKGD�̿��� pHYs���H���H�Fk>�� IDATxytTE?$aM% 8"(*(*>, ˠ*8 f@P% $ $@p;ߏ\*2|?%!:ޭ[wo[" " " " F/v"[L"b*OD-`ܧc1MXtUZHG'j*lc+ѧ+xDZ6w۩/$AQe=뙤P0VHqSƓDKjWr)`=4ҸKC_R!QD& %(_H^1rqr;%xX*N�6hߋ:dqS7([:Q3oPF:3o3'r{9�x 2Ѫ|,"Ia>d-i'I%a<5,ǒY 7Gy>pQJҗ btvSf%�bZة+4V6|!ih*$mS�:94Pf֎˻'L6mQP>*" XGKIL)p7Hp []T=N4"Y,hHCx1e,Y(X9f�P?-k=Eۈ˸xxX$JA1dQZeSSr|EkBXd +L�Cd_VsP.,uHZ:o)XOnꡑ8,ڄB4w!C#tϸʭ @QR6^ .A 'E9Z8YpFxĩJS3h3Ћoґ g4 ߕ-3.mc��3&qb ڟbw`>p# Y!z3N ܒ* )m+C?mT:J|]zO g- '+:d_YZa]]ͧ¸SfS s&Y Rb&Ѝ"{^t ]gF)- `!?; m5..RhK� c,ȕ�'|pKtL=CΔjk 3p !9._F|r?>|vq`0$k,·400_яQ|,iǸqF;P)>TDit4V/4_// @ ߅[ Ɛ[bqSP(O'(E2hL2J0NqXU} }6 Qrk)/ EÍo}H$҈l-l,`+QqUʽRf96IQ|/!0?m&xEc2XE4zYmU-^fWڐU/H2k �D%~^O@ <t�jQ^$ӜRjVBjiKrSÎTkAuG1b$yxY@6ɑAJ(-Tz9 ,ң;M>w+ϘDn�*UX̢ 9xH[Y7! -c.rPY2e)#әqI5�qcZr)[)C>q ƃo:Y�+2YߛZ|E:0,8(+_3�! 5/]=ståpaN8&8mD8ɇ7&sL6A3j9}l3LeY{Qa)짇Fٍex(\- .| g<#XX!$ӋQ;vf=5%\YXH Y<Jap|,c6I�eMY)Gr!o#o 9pKVbRD%4)^4&|{i/tdRE+V:HN_ PrV)mꡓnƫj0tɼ�L"[. x@%v\ !X+,Eg/Ezl~.ʧD^AL# oF_}~j\\Ʒ& m25M4b$Іs: Kr�ZLl}0PBP5c<.\;�lW7nURc&B\ ^jʇYK4Q,K3Mlk;qRۖ29D�74@h1<PR'\Y :Ҍ!TvߔCG/nY B5  FO*c 782GJO1ƴ\ -lzLs#('T<s1I͘Da'p @H -lNEZYh#E7Ԩ biX8\g}K,rjCN=c6WSڊ8<Yc:Dq/+x4#.5G\A1eAC烓Y`tl`.$>&Yw"ZzJ6d4?9^`V;lT9_sz}YGlY„�|8G+Emx\vSHpN(Wj% mF'�TB,AQ#;'pQE=N1ҾSIŤnvsZv2|a)fIIr#S1ĻUudF?Z>W#u">Z2pDdp *->2V[:ymx9$Hmb콥t)�uțKK<yZ& haaI/<_%́^ʲI/OSsp+w3UW=B9ͳO3NIh&34R-5?xHҩC:ڈt~a@'HV}ymfs8["] Ijg!0hueݳס'}AzI*t*r3& ,% ՀSAtg elWbxX*@0aR;mlbv롫bq /6t( #t&.&sYbI4>e#8(RƋP.}Wva`L%52 kk'>pNrzMA$ ճe+Nמּ/m�sQd6aK#s)ѣЎQx /*ۙJM.p40NaTVю-zo){:̢Vg@}�"*S~X':.N|RPBPY-nf~RmBLF4yʱ9 $b=B#R1G~z>`߉e݌OU.Unl%U�ͼ' 'so9p6.[8yHR:25ij1J~L<%hrmt`ԛAM%q68L谸a̡='X#|TR #'afGnBV8gmOfWC0RC]5 DHh)\cxyfej1vRx$ z0Mt ݇MFťY/Q eMWŞ=΂;{ĢFg<H2%ӗY5h-X-+#Yq4co`>!g-U=ddemN@E"ʋܥXXF58P!YП1JmYU Rq9*|,R]hF j]sbu4?7@T(2)fod>Z[h}%$?@a-ޗK!Ԯ-rFFiJq!wcfQ̦Lnz%UDZNBSr ]~BʹIXN/ 2YN2O)):soM JKþ]>;>1֒f^d,{4ǧ>N %<&*g)/%Rn;wS@{ӟs($ VqM1F aj )%kcg3#A1mg#2ҋ#$^|g63k>딟i* )%_$e8(9`˵RDrP琈~xtJ(W=b^*y9[W; 55 398dRx>>.>`$YO){\Ldlb6cqJ$-KW^g._p`:ߒ/e}â\6E1cQg-JqE,čE2bySNP�é"Orc+T-sl1E d7N?ќA�.^E&р+⹫(+EJYuQDnc?򭼪;_(e+eʻm\库dI}͝ �)]Rմ[ |[z ]Ư8کf%]ϯs|ؽ3v~x[/$ $:pگ pk#v!.jkg+q_~}sH:cÈlCaHxZ9VY-~m{aPrD$3X|X�9)4*$GzQl[pBjmar>V늗?^!]x*v "a? 33FEO,,NV e̹�$]*EJ(؋*ٔol8���%tEXtdate:create�2014-05-13T19:52:42-04:00¼���%tEXtdate:modify�2014-05-13T19:52:42-04:00z�����IENDB`��������������������������������������������������������refind-0.11.4/fonts/liberation-mono-regular-24.png��������������������������������������������������0000664�0001750�0001750�00000033252�12626644770�022154� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR��@������;W���gAMA�� a���sRGB���� cHRM��z&���������u0��`��:��pQ<���bKGD������ pHYs���H���H�Fk>��5IDATxw]U?3IHH$ HRQTDB\D ^EpQA@"( I�JG$P zk}nL&<93{ګ- *TPB *TPB *TPB6x.mؠ mY+!kuqJ3Wws|tG%-g~ *a4>YG*TPBKЁۇ{=rtw%D1{u}NvL۷ G�w`*pso&s] +svwLhCc| Vd'KjLNy[e }=3m/m~gf(~^fb�p shKo.+3a*TPUjBpWB ,�M{+a�D=n�OD`Χ!#ϻs'�/Fw?r[uߛsP N�@x鹆{%`'@䌷=a~sVϹ} Obډm;;و;?Ȫsֵ31rl$p'Fֱ/99-QԨ;K9ؕ *pwꇼp�|ގQޚr 8G_.-v""' 6Y>Qn�W]Wn2p g:=㧓a_y's"nZ^):r� iҿ\}EPPy)pWw%h{ ,qy,&tG|)Pu-w<�YS@sD/�!sƶ$p[r`q5-xssӔwOK[9ţRʜs玿 | ԠL,O#'|;RӔ"h/wEE߁dgiEzΡV˻R4n?o͔m\Ɨ99>RfuYԌol +GxA=2BD�7#wsv_.e-ʒ1E9]9/j\{E�~ܮ@<@?l@4涱M^²N軍�H>^\$#T0-.p k&M)ێ$Xu ߓ'}?B$0N7w \ le!e`sS]}D)woF`>u{} SLFcW G<D }-Rnm)r+73u _/>Rvjȫc{^%_?Y r/L&!eR8zWGi'R6F}hq% DX,RL Y$.Cs1e7xfF8CH<, ]R7ɾ wR^FmjD5ԧI{>cUo画(Rϗ5Rx^ﴌ,KxxY ߇t8w6Ԛ%@_?08>!9;Q*$keN4O$I .`Dپ=p u=۱7'љh<?Kݧ]FP3bȗ,ޝ{;p?91~x́M뾑WruImX& znd)) ;7N,z%@ߵ7EWڈV]�]1�)׽Km�EuwjTk&Ps wKw/AfSI0@$ĆV'a/Ḍ-{#m`ZHi}`}ݷ s}~]`/p"r7 uR>V.xFseoɳpP'NiCJ>Ȉ<9Yx,'rCvǞV9\s!y>F}Q ?S}J"n. Q&6~\EXp(~@NWWcSwC4~tN$ F͋4/_඲bjVA,x&86;)$},^ ERE AcHd<0[ &D-\XL?-Y%hL7Qh\k�MmЯ</P W Pvz?=opB-U/+,H?7END/x?L3pcyxη)!@m$; _paHn66zl3c+?vǞvn\o\>16 ٟI9ޮ3WC!@ERz:Vd>݉�]>Ўfƹ"@{ ,:efe%@m+A_Ka.8+}= y$ ys %A2Bu*f* u$"A׆ ֧Y ,iH/<H~o)Xؓj)1L$ݻ?6 q݇ZOqE{)rܼW:RʙeVN#@掗MaҒޭ z;ɻ>)e_+40ml2-> "+my慦 k<Rb>gyS}g!2H-?y'<8X8guǓU<C.E_|S�[!|_!N4$eL9g.)x&h�5ckRW"]D&F5;{w[^B|?X^OǬ~l,rO }/@Dc p/6]EoNç9Ӝ!ukǟ }Ox>)!G @:<ཛG, CwHΘ[i*|�E�<<dҽUnDz<d=6~}w7/!:ӹ ׹2?@yp~h<{�Ѹxqy~4ryHMӛa}n76'o3i):AZwjt DwFqd`t͹}UNh,}/"s!R\N:b49cGzɝa糱c2>H8ٕ .FF2E\i /3$=e,#d9OI'5QoWjɫyrdٞ(Pd;6jv|"9<g$~!0a%$ @cP7}&KK{ATW6éQʪvG;Hi 3°O/PnEwP>۠v6U! j H1?BbW~t"b]-A] | O{-87 g\CG~)ZF4*%Ȼ͂;d|o[,-ǓӃ}ۣ1Ş+(]H�ǯ"X4ڸy "n&Pxr-jקMX@Eh<W탈GsƁHh5XEcjL~<'h)7GGӔsPx+'2tM(j۔sF^Qtsk"#4VO$<U%].Y_'0]s.m|ϗ|6r�2.$8x!%ۆ7e 4gvg?O8 fB�/s 0UDFǹHQ8p166:]]C-O4ܳNWqW{м#'4 [g&j#7뫣٩qld,{U{-Og""^)#`D^) H6 jg#y nO@u Ȗt ~y" jysSss4f>dsPLbny "`1 vu2|bHSy#y~+sgps"=w( pp|[=oGz?߮E4r3eVGxg~H>>7y kǹ:7Aτ?qdy1 q1q4͋o }z~#n< YŽ̦6U䍮|l><b<\oA_Ka!EB F F8\ *bE0)#I<*5@$ٳHU_'J2{J'>GQc؋X`[[CyI\ۼhCo�])Ls' G:7:ј/ N<@0C+:bSy?lP cB׉{=VC>)#U)A/Fe sw^Vi2aV:K9e�]R߽Rοrul h<u;bl4#ш ưU"d"Aq^A9'H{!j^pQE<{(F<@O_\![hh|{Pcl-"9B1je<_~YY9YBǸsޣG4Șk9{~\+=@纎E {y?44췅 c?|+;K%j9veϢ8˭yOyVe!zCwac]2Mjh"ltKdu Y__B">_&jIh8Iռ6w>5Sx"+2@s?&=>gDwlێh�] /x_`cc?w۷2WP >PȨ^hǩ 9̤37 !l.ZLzwFjYfu7/z ̝sv59:fPe),*5xdPƸԏIzG:!g g!6GEM6<\LoBl&=Q߶ ` a^I}| SD֘Q RJk 6[(8T3jT8 EAԆKBQYM?85f~FJ?O6ZAZ_ym蛏FuEɃz onӨ'ioqvri0rlN S}92P\l7`F~XkIzhB)<E&FV?m!N%axaw/#/~?E< CNmLM#`BclK`d!|F_\!@mq]~y]|"yKp_/&DϨ'b)YJlzWA],=cڦ o_|snϡ1e/CwGXNWp_|3**$,'y,L9 7@}<o|EsoٖP,V#m[(zH<72jt{^9fhY;~Bo|hZ퍨_(gKGHa:=# |!SvgZz_uMsLͲ%@)> !KьEs$j#k=8fKӹ̱,$Gv ?^bsQpi$o4ǩeAߏO ?;M<'q͐0 D)orȱ,PW+3 E%@O#WQzBQk9M1cIE` rk@"0Iku*N8+rAakoGkasyI`tn:!Cږ3ȱHѰ, R�{` ܁o7}{_ϹgzD&v=q Bz(h #�5Y4�Ft_{BHo$'{Ұ*Q8vE#$D '`-1erc6&>鞳,)UBJ*Ae ;#Q~>9„0kꫝ+UdWI!JwOiFem#k�M{Nn<ò"@/~Ɠh�|R�]}719JwC#}G-椶_gܯv8BJums)yKote0eGGkۿG3mKZ*$ Tte:h�=7CX69, fDsH#Rsh"C{ KH)28jf1q5'@OHx|4˖�=o(R . eP5r1tܱkϏǔ9KK+Ӯwϸ,= 8t]/ ˊ�Eci[ #GVB.\/4�X&ֽ/g]O:>񜦏+XWrD1Č87F PϞ%=*.&oqurv"Y`{]A0-LvvFpJd٭+?<~09&G^!Nd)1"!s!b"B2T\Fkf t vSl*Mᶮ;ONuz NB\|\9"sox} ;I1AjUd9:)Ws210N<<+1(^(`[u硁=HR+4N nLEߺe*8w}K>6)DcBjs:&P )Иo/e<ߣGsDDܪ]�F87Ō!<mK)iۘDo-W'64~SܺRi_EJKH3]Sp,[Q-4ini/D{ ~y9*6fsѻ6 G~1ψҰ\'b{ً, vjW_?2,B :@axԇ0O6Y$AqOfq:jc2l+aQ4ܶ1(]~h<yW|*$8RtYS!Ƃy.Ecgl3#@F}E~z5dkzN5]7b]pf9"bu38EX{ynrŔvh6<y;F:H~ #9/=mx!C>DQ;߈Htnj(&rˑ''V$mN}*1+w>rxqMKSkGo9lo]WA@Ծ>-)'"n7|I7{_J(y�FxK˚x08-ixo{ƗG[H\ Y( f<%q[H,c5y<,թ ]tLvvU9'Rh6o 1 ,j=w@"冑#XBÇyOdun|ͳ$r6ZV'o19689t=>zl |cߤ\V`4ZkȚ6Ey"« wr25+.Z oy=Vwd� ̚%ʥ<@# mGu-H< PUۉzxHi#j9f<y�uShy.vp 2%ay.ȸNGg 1{c�ذ\QXy} W sjCiD^NCf">Y|3�-RՐ:3a Cub[sAsP(|X4ϭ48,cXPo:O\w=@-+X_hYO$Fl<@yOhMMWbH}iGzN)euX-JHyaډ+6-+PE<A=fc٧/1]K,%h4$[`=/twȗ-yvx�xYr0(C }28s8bGH8Yw"Dlb5yx?j%pHױ˃bPAd[#9LTNS,e'`m4MN;R0D֝'_Ma%k1$ H&,]ًO K+,rl4RM `!)/kWbFCQu|z&[l><~?!�1&[VSmnR: '7",W 4w@V,mTjBi ε6>{2:3}'a_'Bl0 ߇,g)RbJݒ*ļ+O2͛mHGεȃSxJy#K|$^%fZ@Ȍ1:4S zY|CgEq_{ yk|)!y P7TeZs("'N8 d|( Oˑ3_^ѐ;ȉue^od9"ČvcRт4Ȭ-k%GO#Y\j&mIj".ȁhܟ{hCVXK)|~>ƫ;9݉'F7B:$pN,q)k>7ƕvO :"([ݐ!{F"�Z }0cGm ) H=|+U|XPz-jlv<tWW%H(Zfѭ|+dm]Gq$̂AcV[Cd!e' {/rZj=@Mh qw-7&|o%3OpAsY!"mdOBŝmmZyn,ڕx1u*Rz^ns+Ut aH(<I6FY[#Z7DH 1O!%E㶑;xoO9ƞ&sBczlm`-QnXK>g+aamOH -fijȉi߿[/!=<8(K]GN+7쟤ɢ0DlyF_%,z}SS<Bv4|lCe(7KtCHWis>hy9݅{]ٍ8 ܷ#}&EBba\C~V|Y4ׯ6L$q!k<jsG}͐10mqWm̲ 7g5C6,Ox7!oHfڧb0CIQ,/4o>Fs1Hך~?EǡoCG #>w5̀ y@|!l>]Ah!("n53ۛ#N*PU=Hޅ/-wY|VO?xXxo/'q+D;18V0N�uZ |J͢lMdX/GY ͲD۟-qK}Hb9\h$P,+p=?{xZ~'pc̪gx,Ql)N*4cdO$[�/> }Rpˆ!Af|Xs4,\E4ni3y.#9;ׄò%C~ӼgW/rt),e&ސPdk;>2ؿWʔ=%.NzU<@֊, s^H5Qdnl\ڼaY  a0󊴳k9M%vϧivlq| 1IbQoxEB׌CArE4- |Olj=[-BrmK.B�x!p8a:J~A A<!Bci sy_@҂!m9ؔ+PS*`0RY|^ޏ8eS}boxdضkK/7abpǯu =OCcFgEʛ4 ,{2nV>AHta!6gg8 j8z/6R<T/P\xv?3w}WL=ȜN$mc+7*ӚFQ%@z',,:{s*x>Z:E Ы9SZ q;,8ֆ'0 Ёx2&jIUo\^X HW'k IXZkw+G!RS9 @t7J\HՏ܂?~C9y,"/G^Q^UV4RH<gMmg v$tZ-B0Bt#NPtj ἰLnB-ܘP)S[I3z jJ<#x� ^֣vf]ԇÍ Q~ֻڹ):Lz)uQÓ \O:ڎ%>[kf햮eaAUch.EPc/x ZCH:ljS @Ħ5g!iLƟK f`zoȯ9z:llLI?p_~qQ{]J!FQ�Oj$Wrܚ؛P\ݚGu'z" 2whԤǻq;-6o=DV21e}gyHI(-iz(_ǯ~dʹ<n(ܤNfw>>1')r?~8wG}x,%@t~3AO1AQ@[iފ-Lye/~=(4ȁݱ9: Oz/`?f Z4}+p汰F`BƟ[\ENtP`<dR4ޏ^>nCDޕ8fs9Ӷgx!l=_e!N,6ůmf.|?A),\ a̸qzl;yx7,AI*c/ђk'\9>| #?Daf+df|q֌mfQ { 3e~/>;=Љ_T0\*4:!YfR zfP19?I^V(G~�2]AAd=K>Ǝf:!@?A%&&S cx¹ ?>X|)/�P�O.uu;X7d>7c[=H1"+v!~lx1yg#@W~h{ ڎ_d94_-w#nΥv#ނ12}�88 =g ݉_u]#="RDٻB:FQ�o|;V>'?tذg/i(x{69u<3u,;A1-|?E<m]Ԇ@oxY/ζS[> o%517፷Y;Ԧ">oSoE)Nven뻟ʸxYyx ?|8߆HT;z%}[PEBǝ1( Jږj|3)F P"`)]MNAG~%^D4XC^&쫨m܉ĭI]4Bx0"f< &86xexa Jت˲QwP`fV5;MР<R`bmЈHWnT2uQ?&EH-TxF6j}}?<\+diruЇb�/LOZ2#1QAx#Pox01@D̩c<a^/E_<G$`wK-Du iϙ$z3(Hо. r' e б-u9�y=)XYDex%<B7k Iˮ @ZOP?9)73$S4C|xoW~+tp wmMe(Jڳ1GsmE3Ku2oS`pe9y覔ZG|�.נgq*2Ϣv0#}GpGƗ{\?\Fv<kyR|{# ]4w%oPXP:{]/)O6Bn:ZY(DDK>1A_%$GFIWz1N|;}ɨiќ4޹U("pU$ʿS;nu""'NOy9fƎi,b x;麯L/j oHaXޖ%W Xނݻ]@=]C&UŠJz " MQk z!j;p˦X7eЛ g|=[OXsyCea 7{ ]Awߕh.v=A�g!p{TWM]^_B 3lb^+Q>2=yl]{B*TrH6<1+TX1yF5P9>ꤱKubw?H !C4FJ;Z(s8Wa-FpC2c"=Sѿ[U*4Kow?H0cQl{8VPnoE!*$A�mGGي7`xmwt3Agi~>[*!R=2xEшh?|;2| + RQ.'ݍQ *4[lB=CFB =#<}Gj_8b/řXW*|[QIKMEn "E>-,]Vd rPպcݕS}<6G},\p?>UХ)�3_,U*Tлч;J z/#e|:LDy/ /Fn$�Cૈdx_"&ѢQSI;x=s%S6�]-txnG-dsӘrEUF2Yq*˦E=`���%tEXtdate:create�2013-01-24T19:56:47-05:00RWW���%tEXtdate:modify�2013-01-24T19:56:47-05:00# ����IENDB`������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/fonts/liberation-mono-regular-28.png��������������������������������������������������0000664�0001750�0001750�00000032545�13137113472�022150� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR��`������ĸJ���gAMA�� a��� cHRM��z&���������u0��`��:��pQ<���bKGD�̿���tIME y��4mIDATxwTǿ3 # ]((RĵaTvQQ.**QWEQ`YPE齗$7799ef(NnNN="("("(8A D}FϷU<+Sߵ=<νkkLEC}QИqHl):Ӊ"(8֖T"bٙd*SPý'!T9GhKO dElp|6\/C4螗9}dj唚OTE4mS}3sa_QE z N$Ktm(2R@_lDh}O|B'Bzs'c" 6xE(eWCZiהہ\9f,s;@W`:chA b)�O>( =34HKlE-MyZZme=m["w,f S:R8z|v/\Jt ^2B5.oFpq;ߓM|xێ4vh$G%Ƚ4w*'8"Y[+E_h,i}[()"m}34k(,g"тYA.#?n"*HcwTޟmCH] 4um`%Gs&#dJ)bNG5le׸>+< e-;e2 Ǖ9f}C%kTJ zPPeIwqh1b9[n{2)'\Q:^̅A9{ ޹\57H!Utǘ �!O)}.cJZkFl2$諽7}t6�a9x_K^c[o3 j<qa8ȮQ7t 4S-Z`.f&3=$?c&35WGqA%¿"6 }^?)PG؋vK okIK5p8amۑDكNqiHnr}",tL#X<Rq-lkIC? ~g g*TsX~udqǣڛ E2SR.8VE\)�9ʾv%+{Q5[gs7A9q3TvoLhg5ܩID+}(eKBCc6MYl匠}drQGtS(lG`dm-t<Q*9u|GbQc}FjX-{%~tf(0A3 TҖk: gD#q |aMCqmb=grcDt!'04«a~l']Q)L@z J`jyM(Ӄ~!v"|-i_<5M ۶Bd''Ĵ'{Ҋ422N E/{V\7 "=wC;X(?XP8ZKg3?~BOcBYLv#r8cxJ`t"4+E(}P"0@ z}GSCH.b}zRJiO8·p2l|g2͡g�Cnw O `,Iܡ 963#,#ܬI)Dx!EmV l%-iI;q#9><D BMLXtXF22artp-" ( Ӄ, 9[ |m?$yA۱whSD5]iB1w&B` I2m9lCà/q9Q >ZѕAXh02x W enogQP&݈1E3ҵc ASF׶uBF5d F@!vU> 9q ى&B0s74B[]"0E(յD Xrf+VLBȬCa+‡۶>&(˭( b~` Sgszla=V"<y؁axS8 LE:8J9~yڦ'+3Ŝ5 `ߍ oa BMޤ9 _A""i{JNl ]{С<AZ$!a7B0PP萭 fjݵ�R0A8#̵_P6e0X||:4AL g{ smgr<<.r}YnA޴҃lE%0d)DtA`nDl#?B #\acYbKc$0O"gʛlE(އ'0Τ>E˾7sz$3xvCxA\spVD8A,cesy1!ܯ\k$!q^C#r#kkWM0F fKxdIC͹6` I<~bl k)fp4fKɦ4Z--:8H$ќ҅WNY<u~f^U6W Cz)p3}XA? $Xa{C5)6JaFn],# 2XxŻd;M9{QRa!ٔWD{J0 ~�X,S<* eLPT{cwtitg @ Iw6wVC,%#)TS@7G*mϩ{ ! ]YDGXxj*%F7oՍFg7jLs �1"V^/57"/,km"|ڱ}NgDn=ErvBg3=fW_AX e59l-. <̧9]y Xu�)#V|"0)ѣDr?BC0ЯjI�BWuC`s'IBU?:?yOdʹ6 \aJ.Lm/BGV*G?+=T#anBpe̳>3^$ GQE(P>W [.Q =C`h͍mcoTG_K<YbT:>Q7~xo{! >{WTjF^q1~ԔtŇk4sq ƨYX=^A(HsP\y'c![[İR6M`QI*q@a9CiZf,CtdLw2ETl|QحjlSug 1lAXasۑGyB/϶إT#؅6!-%!tV_3a[I`=ӏB9dI"=sRNAH_2mRmSn�md\aRߏC_ێt.p ƨ gI)pȼ<mc{zmM܇_1 1&j[F$7r1 sxfr%0+�eض=D2ĜC huiwZH8ťs:w�$nȓ{4x }PUD !08"^[mz}FEw˓fhx$DƷ{vE0"pI.QG$ QzFGkO`%nr…C`�9u󈢍.Ncؼ~Լ- \`1>'�#Jϡ[@5i϶ቫ:;z Kr aGA 5C<ZS.qtvw#luK>NHK}~mEpM~G( znܰvԔdQlK~m(2j+"dEF]d-v' |zGrY5!SqZM`"<lC3?Ύ|s$RbKѐMИ66](GXizc9+f6!ɧcA>:iyҎR>}liIYl[bJB6^\O@0L!t*r'p;XnhN=&e$?T"*X˧?L{{+oW' r+-hO#\1{"0mDŰݚa O<x!Ò@.TM3.`ʅjM`B'cJ&cõ7#i.iHF26ą\Mįc/s?HGGF&yUhC<h >XL3pccx4z+1mr*3?X:P7L_"r4ÓjExќa["Nه _e= g*>|!skps' J^JƮ~ a � )@u -d#6!ZRg~܏=1t#<}I`:aq)4)4'9\ONqBQ/?jq$�B}IJ_BhAE ծϹ!h EwЄJIJ:NB!+C( Rj/zaFPsËıN| 7íZS𠭅`B߉E2qN0m10T܏]KS$0/khb+2/9۱w#oO%0~_s}l1B1!T$D 1)ueh h/U%e!;g"* æDTҏ6dF_EuyGюTvt?-9wf>faN#B,iA,q"LvlV!/*;~|x/?V9gzHXmzEY9XSɮb�}NQz2BV I>zM["�&0!z߲?4)�.A\hɻ D8^TD G�g&{ë 2,A=N`9&='ICXj(slxs:K>Fug1zAyCfU:1 +پ 0MXPN!l%T|!0Oale_٠5;K'6kaF0jh™f@>lq35'0'k @_ے.2AFIJlF.BCҊ~G1DJyI $Ke(Ě A!pI !wbw&_=N `#k\$Qe68a[0M20SK`_z0L[]FDX$976 #@8z]K@2ۄxr+'D|JZ\I76g�Z#ԎWz[wͱCC52ok9bqhӯa%-H*M߈p̭e.QVH-=p!ѓCRf8Vyľ*] }yʱ-b wX<2\ALd)O�-ߚ/7�wrw"ev![O TY˵ zM/]Ǖ=V/U~-bvp$hviSMGfGff iEz( 0 xV &|o2 d5]i lg7>?I hƫ,WZI+L%ƨVq5{, K9$G3ȶZ1fh 06\d#SyiUãn^eq,pTAPs1^@B<t *c xyR.P6u2DI=U `30ک>F:Ŝ-1AXK3p%|�^OMLބqp �>2@&z6FZ\v^.8QRf-*Ofh+ګU,E[�ygدF|rpU `P~-,Sf `xD_GRog4Zt6V+|k~c9s1T.WU?2AtBvͻ)tPhG3N2էGCxI_qRh}#߁!k<P΢?qG%lu 4p \p_Q@>p @?"'0濚M\"Ё#iXJ>gO&̦H&Yd?n^\i3 C+7@bjcg-1ъK5@T<A<\i8fNlfVp#5Yce#w9\u]x,*½\js=J�p3T0ј;4'h4 bZOGnoM 2"biAcN}`3nX[tRiF Rg(L!1ȚͿ( [TaY6@ 4;籐|k w=�{R^ؤ,~?\<Bxږ~! B*;)Pl1삸Lf _vN{RH!䲑ghMY6J _CM5f}q2Hz1dҒX50 hb锯m`՟CiciДڑ\�!GÅ&##zg *pIvhĭ,b8Ucecm/Xir&4�%SjM,bW"ych Jv>rkƾ3'0#w(Ss v-nlNR Q|~FS@c ͼ%cp a~3x L[UPTxF \Q;T<\Fk-x{=OX;wlRL:s Z)Pr?"\ ntddj\10H6R[#\uĝRq-Yyu qA~^-jC\ԄxQ/Xb* DZʯw? ٭T!, Q}2|v!'a)JGg8}18w/*q:4uΫf"/W781vpv4#Sf<y+DRQWr ;'x1\#Qm42Լ6"ãAGDׇvPNxo֚^/8,0/FH(zSs!'<\Ƞ aw!3l(=Op8]"sw)(q7iF3>B%R.".d`NS1$+p a9(f!g4z B)1tx C<nC ʪw!{{6JKQuNlp\W,`8c'!.>bQ 0s8Y':\ `+n5v!3#|i\Ȃ;"P[2Ao.dK̿:e!C]K>) 2g|?\.dP;yV7kBF'Px6!E#CD'B2aF2eO !�Q<)[c A$C#/ )lc?Sf.9K gV$Fq9qLi&N*f4e<4:b bx0a2Txo<x!d`Sq^ho=L~ڻ;v7pٖ/zcyud7tCk)V)v3ÕF*=-c8lN[H"P8f:n3XYJz֫;iT9}#F-5ejn1?**g} ބA>g߹hG9Bc ˀZw1s3T} 8lF&:L ȱ3F. -d602Da[>+5MlZn O;R28Áb55`6XGxZ,:\J5 /DSGX|8hT98rQT3 c1Fņ`Y `:u~t}r:msك"9ai]#AC~rcKX?a|e҈5 Pf;opKeSBO1Ŵ^ᶚ5p5qG 1|A k9f�DqjLV|\>^.9Жa/3{f cnZ8eӚZk L!갖pnmxH֧&<-@/0듬�z(1fn%w8c oj1v )֊q9ȭpiގIa"_3.6SO nA&w|J=-C#CCέWi}tq]UV`b�4 .n8p cv<GsrkYˆ'CM,dFoN0`"U$E ZaaIdY"~1yߩ+%@�0, H :R=GKN}nVMj�'B9#Yx\w<k�\V@K/m�T]mۜnT)VS0>\K5>*c$pN%Ў0Πe:iI*Tqg70'"Sc!QfıGb49kc4_g->eke-; TgZP˄)> PzuU'S)x At缷mw);vt. �gx&AuC:ЁA߿"[ԣ=ÁO1.@"wϤ3[8J.F@A1 \\KKt>1=]G4>?;3x<qZKbhh X]97B#%5]lq񋶊o8 !+)$x|V46[y,d%baچ0,UC |J>v�JޏPhB 32S\D#gRO),s9 lo5�<`Er;CSQ_^A5t(t21 |ta\v2$ޯey/Vn=7bux4e6ІT2MJ1y45 I*  59~| ]1?}=c(+LD2f'34Pcם\vTLm3`C_E0ҡĉWTOz#6p;JG*("|S:R7Er!rm@{N13i3f 7ƣFiXW}'汌ٷd(Þ >؀sTl8Z8Fpi6glp=%R<7}6ޗ+ҋUVD l9җ5\H,;lMs,�5f,#r~>99wz`KEۀyt"=qO:A�nֹDCmz|Jp>BԁDm腖Y MSjV&Zz|B#x pJ=di6g!zDc`Bjm2G#) !'aeAl(]>5n&!lr8{ITgOL{EЀxC50R�V /#1|Lֲa !sMbW'->}k۰aѤ"ts%?c` ġWTҞtGpc`#&kyY#BFB}?{zZH+ڐ#PŎ4QP6ߣPP*=w.+R P V2 o[YYk߭=8#䄡7|&u}%D}c?q8 {zBpkE:Ǐ/ Tƴc ,~$\(?Pis@=Y?zб}cT8qw܌ 6߸rDB̨tc"#QTFAI}Piܣ;"}m?#<?1z,s,lw49dS5Bȳ %xdu5vqCgQĞz8nW:n"R&lE(-'K֚GxX!l&f_1syȆf#1d^F/'0!6[Swvt #s;QpqsJp:UYJqIG긃☿/PaC40°74VJvGNf~Qq�#T ʩēDB#|}S~ [kt1.%lwB m̐/id*[o~Qhb`5Z +6֨E,@UW.ݹLbz:ә "T;lCyet3 M`XAZè*4|#ד(gR6bvj#'0縖D@fq2]b޼Tō&]ӑx~@}^}<?%,Ҝ:q v79B IgNIvBy둊؂xa@H%P/pVTx\=yΤ'J 13́#0AXgKhl60!v^H:ȔV FQ7!&ay'lj5jayc=K' }I`IBH1 K,WR=%G%<il}ٍӦB:*M8 `Y93 {s2riBgNw$ hC%廉Vs]!|h=d-k52bgd;",BBIF*e|ط,Ç!/k?]u&mr ̂cno l<B" u{3ILZpLG( #7;S cZ^IJ֬ƙi32k!T[kgjD\[/WK>,dg_~v% d ^hr=|Uٺ65g M`$TNDu>'[XXC3Y⏿:U,(w7^Rx |.!0xõo6uhsYU,Gض]yunveI"Rۅ1|C~0qY}ij F͕:?x?2\y/ੳ^an7.1{XGE 4F,w42s8x)!g%TU d1JYgf*T:J 2yyu9 l7.w4B,pUl_Kd"<FThJG`eu=mG)1g[]=Ln~7`~P(fU9kyr(@`"%0"Pv֑X?q>i}yrvr8貖-2۹ƻr[L2qB(y~W9B&`!0^G9y<3vB[1RPMyݘj2HcؒYM]NbՔ\+p~v"T"rp4 qY"| U8C{99 O)tQ~!*ri!4'0PN*3J=Ib6 .)ڋYGU䰒5'6Ij!BrWA[CւrNjQV0B >l6;.G,ם09$SF6kxIq-xMQzv=AzZ1Bsj-h,# R:S'Z }<xft} ćjUc%T:fyCy8J1d.L{AlI>SPi<rt8~EJ a߫%}e"68mA6Vc;|D*2[M," XMV,&Rxfb>ƱL*c%i]ŏSL&oM(?19Z!LѸWc]Hd"ɥ4 eޟP F{yOt>ߙw 5]p##0p6g5<"e9TQ&)XVQD)[y@VֽAӸE;B9Bbu"רIJa;ZqggZh9@<ik ƥ(?% 5)10U50NC2taA5CAV#6AҟBtb؎wNx8XuYO/7mUp( gᯂ~fv[vǜIkE^C.25Qc^A0,EɵFe恾(;Ӆre`PU1r+%)f$hD"^9D{IDO6!d*]0QD1lAͥEq -0͂ 2u<v8y CE;ԟQ Lp^e/ij鈒>3!8/"é>⯌4 DhVCy5tQDHa'#iN( %$QUw40'׺W;z3JS>QSd"55JL?](j]y ‡F@]b0(hK"Ot9챲 EJϱ̊ZJH6fpU,]Ty;%0bͭ\,raKg7C‹nv璫I>G<+kʹ'Ɍ"( %)d>B0Fe[Fpe( 4&VQ@Y,bt# TχljrYƄ?GD9|9RsE`60JfFEQDEQDEQpC8so���%tEXtdate:create�2017-07-29T10:10:02-04:00/���%tEXtdate:modify�2017-07-29T10:10:02-04:00����IENDB`�����������������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/fonts/README.txt����������������������������������������������������������������������0000664�0001750�0001750�00000003555�13137115735�016157� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������This directory contains PNGs built from a few open source fonts: the sans serif Liberation Mono Regular and Ubuntu mono and the serif Nimbus Mono, all in 12-, 14, and 24-point versions. All of these font files have anti-aliasing (aka font smoothing) applied. New fonts can be created on Linux as follows: 1. Type "convert -list font | less" to obtain a list of fonts. Search for monospace fonts. 2. Type "./mkfont.sh {fontname} {point-size} {offset} {filename}", where: * {fontname} is the font's name, as shown in the "convert" output. * {point-size} is the point size, such as 14 or 20. * {offset} is a positive (to shift down) or negative (to shift up) integer value by which the font's vertical position is adjusted when rendered. You'll need to determine this value by trial and error, but in my experience, most fonts require a -1 or -2 value. * {filename} is the output filename for a PNG file. For instance, I used the following command to create the large Liberation Mono font file: "./mkfont.sh Liberation-Mono 28 -2 liberation-mono-regular-28.png" 3. Repeat step #2 as necessary for additional fonts or to try different {offset} values until you find one that works well for you. NOTE TO DEVELOPERS: ------------------- When embedding a font in the rEFInd binary as libeg/egemb_font.h or libeg/egemb_font_large.h, the images/mkegemb.py script is used. This script is likely to complain of an unsupported format on fonts prepared in this way. The solution is: 1. Convert the font to NOT use an alpha layer. (I use xv to load and re-save the font for this purpose.) 2. Rename the font to font.png or font_large.png (or anything else that begins with "font", although then additional editing of the resulting header files will be required). 3. Run mkegemb.py. This causes the script to treat white as if it were alpha transparency. ���������������������������������������������������������������������������������������������������������������������������������������������������refind-0.11.4/README.txt����������������������������������������������������������������������������0000664�0001750�0001750�00000007652�13111706345�015023� 0����������������������������������������������������������������������������������������������������ustar �rodsmith������������������������rodsmith���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Brief Installation Instructions (Binary Package) ================================================ This is rEFInd, an EFI boot manager. The binary package includes the following files and subdirectories: File Description ----------------------------- ----------------------------- refind/refind_ia32.efi The main IA32 rEFInd binary refind/refind_x64.efi The main x86-64 rEFInd binary refind/refind.conf-sample A sample configuration file refind/icons/ Subdirectory containing icons refind/drivers_ia32/ Subdirectory containing IA32 drivers refind/drivers_x64/ Subdirectory containing x86-64 drivers keys/ Subdirectory containing MOKs refind-install Linux/MacOS installation script refind-mkdefault Script to make rEFInd the default mkrlconf A script to create refind_linux.conf mvrefind A script to move a rEFInd installation README.txt This file NEWS.txt A summary of program changes LICENSE.txt The original rEFIt license COPYING.txt The rEFInd license CREDITS.txt Acknowledgments of code sources docs/ Documentation in HTML format The easiest way of installing rEFInd is generally to use the refind-install script; however, you must be running under Linux or OS X to do this. If you're using either of those OSes, simply typing "./refind-install" will generally install rEFInd. If you have problems with this method, though, you'll have to do a manual installation. The refind-install script supports a number of options that you might want to use; consult the docs/refind/installing.html file for details. To install the binary package manually, you must first access your EFI System Partition (ESP). You can then place the files from the refind subdirectory in a subdirectory of the ESP's EFI directory. You may omit the .efi binary for the type of computer you're NOT using, and you may optionally rename the .efi file for the binary you are using. If this is an initial installation, you should rename refind.conf-sample to refind.conf; but if you're replacing an existing installation, you should leave your existing refind.conf intact. The end result might include the following files on the ESP: EFI/refind/refind_x64.efi EFI/refind/refind.conf EFI/refind/icons/ Unfortunately, dropping the files in the ESP is not sufficient; as described in the docs/refind/installing.html file, you must also tell your EFI about rEFInd. Precisely how to do this varies with your OS or, if you choose to do it through the EFI, your EFI implementation. In some cases you may need to rename the EFI/refind directory as EFI/boot, and rename refind_x86.efi to bootx64.efi (or refind_ia32.efi to bootia32.efi on 32-bit systems). Consult the installing.html file for full details. If you want to use any of the filesystem drivers, you must install them, too. Creating a subdirectory of the rEFInd binary directory called drivers_x64 (for x86-64 systems), drivers_ia32 (for x86 systems), or drivers (for any architecture) and copying the drivers you want to this location should do the trick. When you next launch it, rEFInd should load the drivers, giving you access to the relevant filesystems. Brief Installation Instructions (Source Package) ================================================ rEFInd source code can be obtained from https://sourceforge.net/projects/refind/. Consult the BUILDING.txt file in the source code package for build instructions. Once you've built the source code, you can use the refind-install script to install the binaries you've built. Alternatively, you can duplicate the directory tree described above by copying the individual files and the icons directory to the ESP. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������
  • Ext2fs—This driver originated with rEFIt. It's useful for reading Linux kernels from a separate /boot partition, or even from a root (/) filesystem, if you use ext2fs on it. Although it's called an "ext2fs" driver, it also works with ext3fs.
  • Ext4fs—Stefan Agner modified the rEFIt/rEFInd ext2fs driver so that it could handle ext4fs. I'm including this as a separate driver from the ext2fs driver, although the ext4fs version can handle ext2fs and ext3fs, too. Providing both drivers enables easy filesystem separation—for instance, you can use ext2fs on a /boot partition and ext4fs on your root (/) partition, to have the EFI scan only the former. This driver has some limitations and may not work with all ext4 filesystems. Although it supports (as of version 0.10.4) 64-bit pointers, this support is untested on over-16TiB volumes. As of version 0.6.1, this driver supports the meta_bg feature, which can also be used on ext2fs and ext3fs. Thus, it can handle some ext2fs and ext3fs partitions that the ext2fs driver can't handle. You can learn about your ext2/3/4 filesystem features by typing dumpe2fs /dev/sda2 | grep features, changing /dev/sda2 to your filesystem's device.
  • ReiserFS—This driver originated with rEFIt. It can be used in the same way as the ext2fs and ext4fs drivers. Caution: If you use this driver, you should use the notail option in Linux's /etc/fstab file for the partition(s) you want the EFI to read. This is because the driver doesn't properly handle ReiserFS's "tail-packing" feature, so files can seem to be corrupted in EFI if you use this feature, which is disabled by notail. In my tests, this is the fastest of rEFInd's EFI filesystem drivers, so if you find your kernel load times are slow, you might consider moving your kernel to a ReiserFS /boot partition. (Such problems affect a small subset of EFI-based computers.)
  • BtrfsSamuel Liao contributed this driver, which is based on the rEFIt/rEFInd driver framework and algorithms from the GRUB 2.0 Btrfs driver. I've tested this driver with simple one-partition filesystems on several installations, and with a filesystem that spans two physical devices on one (although I've made no attempt to ensure that the driver can actually read files that span both devices). Samuel Liao has used the driver with a compressed Btrfs volume. The driver will handle subvolumes, but you may need to add kernel options if you're booting a Linux kernel directly from a filesystem that uses subvolumes. For instance, when booting Ubuntu from Btrfs, also_scan_dirs + @/boot must be set in refind.conf and rootflags=subvol=@ must be added to the kernel options in refind_linux.conf. Without the first of these options, rEFInd can not locate the kernel; and without the second, the boot fails with a message to the effect that the initial RAM disk could not find /sbin/init. rEFInd 0.10.0 adds @/boot as a standard option to also_scan_dirs, and its refind-install and mkrlconf scripts should pick up the root flags, assuming the system is booted into the regular installation. These additions make it easier to set up rEFInd to work with Btrfs.
  • ISO-9660—This driver originated with rEFIt's author, but he never released a final version. Its code was improved by Oracle for use in its VirtualBox product, and then further modified by the authors of the Clover boot loader. If your firmware doesn't provide its own ISO-9660 driver, this one can be helpful; however, you may need to install it on your hard disk before you can read an optical disc.
  • HFS+—Oracle wrote this driver, apparently with some code taken from open source Apple examples. It was then further modified by the Clover authors. I expect this driver to have limited appeal to most rEFInd users. Macs don't need it, since Apple's EFI implementation provides its own HFS+ driver, and HFS+ isn't normally used on UEFI-based PCs. Some CDs are mastered with both ISO-9660 and HFS+, or even with HFS+ alone, and it's conceivable that an HFS+ driver would be useful when accessing such discs. Also, one unusual feature of this driver is that it can read files from within an Apple LVM setup, which Apple's own EFI HFS+ driver can't do. The upshot of this feature is that if you load this driver on a Mac that uses Apple's LVM, rEFInd is likely to show two OS X boot options. Ordinarily this is pointless, but it could be helpful if your Recovery HD volume becomes damaged. I'm providing the driver mainly because it compiled cleanly with no extra work, aside from providing a Makefile entry for it.
  • NTFS—Samuel Liao contributed this driver, which uses the rEFIt/rEFInd driver framework. Note that this driver is not required to boot Windows with rEFInd, since Windows stores its EFI boot loader on the (FAT) ESP, and the BIOS boot process (generally used when dual-booting on a Mac) relies only on the partition's boot sector, which is read without the benefit of this driver. Reasons to use this driver include:
    • If you want to use Windows to write large files, such as RAM disk images, to be read from EFI.
    • If you have a Mac and NTFS data partitions, loading this driver should exclude those data partitions from the boot menu.
    • If you have a Mac that dual-boots with Windows, using this driver should provide NTFS volume names in the boot menu.