]> code.delx.au - refind/commitdiff
Added remaining main project files
authorsrs5694 <srs5694@users.sourceforge.net>
Sun, 25 Mar 2012 23:17:42 +0000 (19:17 -0400)
committersrs5694 <srs5694@users.sourceforge.net>
Sun, 25 Mar 2012 23:17:42 +0000 (19:17 -0400)
23 files changed:
Make.common [new file with mode: 0644]
include/egemb_arrow_left.h [new file with mode: 0644]
include/egemb_arrow_right.h [new file with mode: 0644]
include/egemb_back_selected_small.h [new file with mode: 0644]
include/egemb_refind_banner.h [new file with mode: 0644]
include/refit_call_wrapper.h [new file with mode: 0644]
include/syslinux_mbr.h [new file with mode: 0644]
mkcdimage [new file with mode: 0755]
mkdistrib [new file with mode: 0755]
refind.conf-sample [new file with mode: 0644]
refind/Makefile [new file with mode: 0644]
refind/config.c [new file with mode: 0644]
refind/config.h [new file with mode: 0644]
refind/global.h [new file with mode: 0644]
refind/icns.c [new file with mode: 0644]
refind/icns.h [new file with mode: 0644]
refind/lib.c [new file with mode: 0644]
refind/lib.h [new file with mode: 0644]
refind/main.c [new file with mode: 0644]
refind/menu.c [new file with mode: 0644]
refind/menu.h [new file with mode: 0644]
refind/screen.c [new file with mode: 0644]
refind/screen.h [new file with mode: 0644]

diff --git a/Make.common b/Make.common
new file mode 100644 (file)
index 0000000..f8eff66
--- /dev/null
@@ -0,0 +1,112 @@
+#
+# Make.common
+# Common make rules for building with gnu-efi
+#
+
+EFIINC          = /usr/include/efi
+GNUEFILIB       = /usr/lib
+EFILIB          = /usr/lib
+EFICRT0         = /usr/lib
+
+HOSTARCH        = $(shell uname -m | sed s,i[3456789]86,ia32,)
+ARCH            := $(HOSTARCH)
+OS             = $(shell uname -s)
+CPPFLAGS        = -I$(EFIINC) -I$(EFIINC)/$(ARCH) -I$(EFIINC)/protocol -DCONFIG_$(ARCH)
+
+OPTIMFLAGS      = -O2 -fno-strict-aliasing
+DEBUGFLAGS      = -Wall
+CFLAGS          = $(ARCH3264) $(OPTIMFLAGS) -fpic -fshort-wchar $(DEBUGFLAGS)
+ASFLAGS         = $(ARCH3264)
+LDFLAGS         = -nostdlib -znocombreloc
+
+prefix          = /usr/bin/
+CC              = $(prefix)gcc
+AS              = $(prefix)as
+LD              = $(prefix)ld
+AR              = $(prefix)ar
+RANLIB          = $(prefix)ranlib
+OBJCOPY         = $(prefix)objcopy
+
+ifeq ($(ARCH),ia64)
+  # EFI specs allows only lower floating point partition to be used
+  CFLAGS       += -frename-registers -mfixed-range=f32-f127
+endif
+
+ifeq ($(ARCH),x86_64)
+  CFLAGS += -DEFI_FUNCTION_WRAPPER
+  CPPFLAGS += -DEFIX64
+
+  ifeq ($(HOSTARCH),ia32)
+    ARCH3264 = -m64
+
+    GNUEFILIB := $(GNUEFILIB)64
+    EFILIB    := $(EFILIB)64
+    EFICRT0   := $(EFICRT0)64
+  endif
+endif
+
+ifeq ($(ARCH),ia32)
+  CPPFLAGS += -DEFI32
+
+  ifeq ($(HOSTARCH),x86_64)
+    ARCH3264 = -m32
+
+    GNUEFILIB := $(GNUEFILIB)32
+    EFILIB    := $(EFILIB)32
+    EFICRT0   := $(EFICRT0)32
+  endif
+endif
+
+
+CRTOBJS         = $(EFICRT0)/crt0-efi-$(ARCH).o
+
+ifneq (,$(findstring FreeBSD,$(OS)))
+ ifeq ($(ARCH),x86_64)
+       LDSCRIPT = $(EFICRT0)/elf_$(ARCH)_fbsd_efi.lds
+ else
+       LDSCRIPT = $(EFICRT0)/elf_$(ARCH)_efi.lds
+ endif
+else
+       LDSCRIPT = $(EFICRT0)/elf_$(ARCH)_efi.lds
+endif
+
+LDFLAGS        += -T $(LDSCRIPT) -shared -Bsymbolic -L$(EFILIB) -L$(GNUEFILIB) $(CRTOBJS)
+LIBS            = -lefi -lgnuefi $(shell $(CC) $(ARCH3264) -print-libgcc-file-name)
+FORMAT          = efi-app-$(ARCH)
+
+
+# general rules
+
+%.o: %.c 
+       $(CC) $(LOCAL_CPPFLAGS) $(CPPFLAGS) $(LOCAL_CFLAGS) $(CFLAGS) -c $< -o $@
+
+# rules for EFI applications
+
+ifneq (,$(filter %.efi,$(TARGET)))
+
+SHLIB_TARGET = $(subst .efi,.so,$(TARGET))
+
+$(SHLIB_TARGET): $(OBJS)
+       $(LD) $(LOCAL_LDFLAGS) $(LDFLAGS) $(OBJS) -o $@ $(LOCAL_LIBS) $(LIBS)
+
+$(TARGET): $(SHLIB_TARGET)
+       $(OBJCOPY) -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel \
+                  -j .rela -j .reloc --target=$(FORMAT) $< $@
+
+endif
+
+# rules for libraries
+
+ifneq (,$(filter %.a,$(TARGET)))
+
+$(TARGET): $(OBJS)
+       $(AR) cq $@ $(OBJS)
+
+endif
+
+# utility rules
+
+clean:
+       rm -f $(TARGET) *~ *.so $(OBJS)
+
+# EOF
diff --git a/include/egemb_arrow_left.h b/include/egemb_arrow_left.h
new file mode 100644 (file)
index 0000000..ba09d8d
--- /dev/null
@@ -0,0 +1,204 @@
+static const UINT8 egemb_arrow_left_data[2407] = {
+ 0xff, 0xff, 0xdc, 0xff, 0x02, 0x00, 0x13, 0x21, 0xa8, 0xff, 0x80, 0x00,
+ 0x02, 0x5e, 0x74, 0x00, 0xa6, 0xff, 0x80, 0x00, 0x03, 0x43, 0xb2, 0x30,
+ 0x00, 0xa5, 0xff, 0x80, 0x00, 0x04, 0x62, 0x9f, 0x8a, 0x00, 0x00, 0xa4,
+ 0xff, 0x08, 0x00, 0x00, 0x09, 0x7a, 0x96, 0x91, 0x56, 0x00, 0x00, 0xa2,
+ 0xff, 0x80, 0x00, 0x07, 0x1d, 0x85, 0x8c, 0x8b, 0x89, 0x53, 0x00, 0x00,
+ 0xa1, 0xff, 0x80, 0x00, 0x08, 0x34, 0x87, 0x85, 0x84, 0x82, 0x81, 0x50,
+ 0x00, 0x00, 0xa0, 0xff, 0x80, 0x00, 0x09, 0x4c, 0x84, 0x7f, 0x7d, 0x7c,
+ 0x7a, 0x79, 0x4d, 0x00, 0x00, 0x9f, 0xff, 0x0d, 0x00, 0x00, 0x07, 0x60,
+ 0x7c, 0x79, 0x76, 0x75, 0x73, 0x72, 0x70, 0x49, 0x00, 0x00, 0x9d, 0xff,
+ 0x80, 0x00, 0x0c, 0x16, 0x69, 0x73, 0x71, 0x70, 0x6e, 0x6d, 0x6b, 0x6a,
+ 0x68, 0x46, 0x00, 0x00, 0x9c, 0xff, 0x80, 0x00, 0x0d, 0x26, 0x6c, 0x6d,
+ 0x6a, 0x69, 0x67, 0x66, 0x64, 0x63, 0x61, 0x60, 0x42, 0x00, 0x00, 0x9b,
+ 0xff, 0x80, 0x00, 0x0e, 0x38, 0x69, 0x66, 0x64, 0x62, 0x61, 0x5f, 0x5e,
+ 0x5c, 0x5b, 0x59, 0x58, 0x3f, 0x00, 0x00, 0x9a, 0xff, 0x12, 0x00, 0x00,
+ 0x05, 0x47, 0x62, 0x5e, 0x5d, 0x5b, 0x5a, 0x58, 0x57, 0x55, 0x54, 0x52,
+ 0x51, 0x4f, 0x3d, 0x00, 0x00, 0x98, 0xff, 0x80, 0x00, 0x11, 0x0e, 0x4d,
+ 0x5a, 0x58, 0x56, 0x55, 0x53, 0x52, 0x50, 0x4f, 0x4d, 0x4c, 0x4a, 0x49,
+ 0x47, 0x3a, 0x00, 0x00, 0x97, 0xff, 0x80, 0x00, 0x12, 0x1a, 0x50, 0x53,
+ 0x51, 0x4f, 0x4e, 0x4c, 0x4b, 0x49, 0x48, 0x46, 0x45, 0x43, 0x42, 0x40,
+ 0x3f, 0x38, 0x00, 0x00, 0x96, 0xff, 0x80, 0x00, 0x13, 0x25, 0x4d, 0x4c,
+ 0x4a, 0x49, 0x47, 0x46, 0x44, 0x43, 0x41, 0x40, 0x3e, 0x3d, 0x3b, 0x3a,
+ 0x38, 0x37, 0x36, 0x00, 0x00, 0x95, 0xff, 0x17, 0x00, 0x00, 0x05, 0x2f,
+ 0x47, 0x45, 0x43, 0x42, 0x40, 0x3f, 0x3d, 0x3c, 0x3a, 0x39, 0x37, 0x36,
+ 0x34, 0x33, 0x31, 0x30, 0x2e, 0x34, 0x00, 0x00, 0x93, 0xff, 0x80, 0x00,
+ 0x16, 0x0a, 0x39, 0x40, 0x3f, 0x3d, 0x3c, 0x3a, 0x38, 0x37, 0x35, 0x34,
+ 0x32, 0x31, 0x2f, 0x2e, 0x2c, 0x2b, 0x29, 0x27, 0x25, 0x32, 0x00, 0x00,
+ 0x92, 0xff, 0x1a, 0x25, 0x08, 0x05, 0x14, 0x39, 0x3a, 0x38, 0x37, 0x34,
+ 0x33, 0x31, 0x30, 0x2e, 0x2d, 0x2b, 0x2a, 0x28, 0x27, 0x25, 0x24, 0x22,
+ 0x20, 0x1f, 0x1d, 0x30, 0x00, 0x00, 0x92, 0xff, 0x10, 0x1d, 0x37, 0x48,
+ 0x39, 0x32, 0x31, 0x31, 0x30, 0x2e, 0x2d, 0x2b, 0x2b, 0x2a, 0x2d, 0x2e,
+ 0x32, 0x31, 0x84, 0x30, 0x02, 0x33, 0x00, 0x00, 0x92, 0xff, 0x0f, 0x3a,
+ 0x5c, 0x5a, 0x0f, 0x00, 0x00, 0x02, 0x04, 0x05, 0x08, 0x0b, 0x0e, 0x0c,
+ 0x09, 0x05, 0x01, 0x85, 0x00, 0x02, 0x0a, 0x00, 0x00, 0x92, 0xff, 0x04,
+ 0x94, 0x33, 0x17, 0x0b, 0x05, 0x90, 0x00, 0x02, 0x0c, 0x00, 0x00, 0x93,
+ 0xff, 0x04, 0xab, 0x02, 0x00, 0x06, 0x0a, 0x8f, 0x00, 0x02, 0x0d, 0x00,
+ 0x00, 0x95, 0xff, 0x03, 0x00, 0x00, 0x05, 0x10, 0x8e, 0x00, 0x02, 0x0f,
+ 0x00, 0x00, 0x96, 0xff, 0x04, 0x00, 0x00, 0x01, 0x00, 0x05, 0x8c, 0x00,
+ 0x02, 0x11, 0x00, 0x00, 0x97, 0xff, 0x80, 0x00, 0x01, 0x0f, 0x09, 0x8b,
+ 0x00, 0x02, 0x12, 0x00, 0x00, 0x98, 0xff, 0x80, 0x00, 0x01, 0x0b, 0x10,
+ 0x8a, 0x00, 0x02, 0x14, 0x00, 0x00, 0x9a, 0xff, 0x03, 0x00, 0x00, 0x07,
+ 0x18, 0x89, 0x00, 0x02, 0x16, 0x00, 0x00, 0x9b, 0xff, 0x04, 0x00, 0x00,
+ 0x01, 0x00, 0x07, 0x87, 0x00, 0x02, 0x17, 0x00, 0x00, 0x9c, 0xff, 0x80,
+ 0x00, 0x01, 0x15, 0x0d, 0x86, 0x00, 0x02, 0x19, 0x00, 0x00, 0x9d, 0xff,
+ 0x80, 0x00, 0x01, 0x0e, 0x17, 0x85, 0x00, 0x02, 0x1b, 0x00, 0x00, 0x9f,
+ 0xff, 0x04, 0x00, 0x00, 0x09, 0x20, 0x01, 0x83, 0x00, 0x02, 0x1d, 0x00,
+ 0x00, 0xa0, 0xff, 0x04, 0x00, 0x00, 0x01, 0x22, 0x09, 0x82, 0x00, 0x02,
+ 0x1e, 0x00, 0x00, 0xa1, 0xff, 0x80, 0x00, 0x01, 0x1b, 0x12, 0x81, 0x00,
+ 0x02, 0x20, 0x00, 0x00, 0xa2, 0xff, 0x80, 0x00, 0x01, 0x13, 0x1d, 0x80,
+ 0x00, 0x02, 0x22, 0x00, 0x00, 0xa4, 0xff, 0x08, 0x00, 0x00, 0x0b, 0x29,
+ 0x01, 0x00, 0x24, 0x00, 0x00, 0xa5, 0xff, 0x07, 0x00, 0x00, 0x02, 0x2b,
+ 0x0b, 0x3c, 0x00, 0x00, 0xa6, 0xff, 0x80, 0x00, 0x03, 0x23, 0x66, 0x0b,
+ 0x00, 0xa7, 0xff, 0x80, 0x00, 0x02, 0x39, 0x24, 0x00, 0xa9, 0xff, 0x02,
+ 0x00, 0x11, 0x0b, 0xff, 0xff, 0xc7, 0xff, 0xff, 0xff, 0xdc, 0xff, 0x02,
+ 0x4d, 0x59, 0x64, 0xa8, 0xff, 0x05, 0x80, 0x4b, 0x4d, 0x8f, 0x9e, 0x49,
+ 0xa6, 0xff, 0x06, 0x4f, 0x4c, 0x4d, 0x7d, 0xd2, 0x6f, 0x47, 0xa5, 0xff,
+ 0x07, 0x49, 0x4d, 0x4d, 0x96, 0xd6, 0xb8, 0x4d, 0x4e, 0xa4, 0xff, 0x08,
+ 0x4d, 0x4d, 0x53, 0xac, 0xd1, 0xce, 0x91, 0x4d, 0x4e, 0xa2, 0xff, 0x0a,
+ 0x80, 0x4b, 0x4d, 0x62, 0xb9, 0xca, 0xc9, 0xc8, 0x91, 0x4d, 0x4e, 0xa1,
+ 0xff, 0x0b, 0x4f, 0x4c, 0x4d, 0x74, 0xc0, 0xc5, 0xc4, 0xc3, 0xc1, 0x8f,
+ 0x4d, 0x4e, 0xa0, 0xff, 0x0c, 0x49, 0x4d, 0x4d, 0x8a, 0xc1, 0xc1, 0xbf,
+ 0xbe, 0xbd, 0xbc, 0x8f, 0x50, 0x4e, 0x9f, 0xff, 0x0d, 0x4d, 0x4d, 0x53,
+ 0x9d, 0xbe, 0xbc, 0xbb, 0xba, 0xb9, 0xb8, 0xb7, 0x8e, 0x54, 0x4e, 0x9d,
+ 0xff, 0x05, 0x80, 0x4b, 0x4d, 0x5e, 0xa8, 0xb8, 0x80, 0xb6, 0x06, 0xb5,
+ 0xb4, 0xb3, 0xb3, 0x8f, 0x59, 0x4e, 0x9c, 0xff, 0x05, 0x4f, 0x4c, 0x4d,
+ 0x6d, 0xad, 0xb3, 0x81, 0xb2, 0x06, 0xb1, 0xb0, 0xb0, 0xaf, 0x90, 0x5e,
+ 0x4e, 0x9b, 0xff, 0x03, 0x4f, 0x4f, 0x51, 0x7f, 0x82, 0xad, 0x00, 0xae,
+ 0x80, 0xad, 0x04, 0xac, 0xac, 0x91, 0x62, 0x4e, 0x9a, 0xff, 0x0a, 0x50,
+ 0x53, 0x58, 0x8d, 0xa8, 0xa7, 0xa8, 0xa9, 0xaa, 0xaa, 0xab, 0x81, 0xaa,
+ 0x03, 0xa9, 0x94, 0x67, 0x4e, 0x98, 0xff, 0x0c, 0x80, 0x51, 0x55, 0x62,
+ 0x93, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa7, 0x81, 0xa8, 0x03,
+ 0xa7, 0x96, 0x6c, 0x4e, 0x97, 0xff, 0x15, 0x4f, 0x56, 0x59, 0x6c, 0x95,
+ 0x9b, 0x9c, 0x9e, 0x9f, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa6, 0xa7,
+ 0xa6, 0xa6, 0x98, 0x6f, 0x4e, 0x96, 0xff, 0x0f, 0x4d, 0x58, 0x5b, 0x71,
+ 0x93, 0x94, 0x96, 0x98, 0x9a, 0x9b, 0x9d, 0x9f, 0xa1, 0xa2, 0xa3, 0xa4,
+ 0x81, 0xa5, 0x02, 0x99, 0x72, 0x4e, 0x95, 0xff, 0x17, 0x55, 0x5a, 0x61,
+ 0x77, 0x8b, 0x8d, 0x8e, 0x91, 0x94, 0x96, 0x99, 0x9b, 0x9c, 0x9f, 0xa1,
+ 0xa2, 0xa3, 0xa4, 0xa5, 0xa5, 0xa4, 0x9c, 0x75, 0x4e, 0x93, 0xff, 0x13,
+ 0x80, 0x56, 0x5f, 0x64, 0x7b, 0x82, 0x85, 0x88, 0x8b, 0x8d, 0x8f, 0x93,
+ 0x96, 0x98, 0x9b, 0x9d, 0x9f, 0xa1, 0xa3, 0xa4, 0x80, 0xa5, 0x02, 0x9f,
+ 0x77, 0x4e, 0x92, 0xff, 0x1a, 0x6d, 0x60, 0x63, 0x68, 0x77, 0x79, 0x7c,
+ 0x7f, 0x82, 0x85, 0x88, 0x8c, 0x8f, 0x92, 0x96, 0x99, 0x9c, 0x9e, 0xa0,
+ 0xa2, 0xa4, 0xa4, 0xa5, 0xa5, 0xa1, 0x7a, 0x4e, 0x92, 0xff, 0x1a, 0x6a,
+ 0x85, 0x86, 0x6f, 0x6e, 0x73, 0x78, 0x7a, 0x7f, 0x82, 0x86, 0x89, 0x8e,
+ 0x94, 0x99, 0x9e, 0xa2, 0xa5, 0xa8, 0xab, 0xac, 0xaf, 0xaf, 0xb1, 0xa5,
+ 0x7d, 0x4e, 0x92, 0xff, 0x1a, 0x80, 0x9d, 0x90, 0x43, 0x3d, 0x44, 0x4d,
+ 0x54, 0x5d, 0x65, 0x6e, 0x76, 0x7a, 0x7e, 0x82, 0x85, 0x8b, 0x90, 0x95,
+ 0x99, 0x9d, 0xa0, 0xa2, 0xa3, 0x97, 0x7f, 0x4e, 0x92, 0xff, 0x1a, 0xb7,
+ 0x82, 0x76, 0x68, 0x48, 0x46, 0x4d, 0x54, 0x5b, 0x62, 0x69, 0x70, 0x77,
+ 0x7d, 0x83, 0x89, 0x8f, 0x95, 0x9a, 0x9f, 0xa3, 0xa6, 0xa9, 0xaa, 0x9c,
+ 0x80, 0x4e, 0x93, 0xff, 0x19, 0xd5, 0x61, 0x6b, 0x6d, 0x5b, 0x4f, 0x56,
+ 0x5d, 0x65, 0x6c, 0x72, 0x79, 0x80, 0x87, 0x8d, 0x93, 0x99, 0x9f, 0xa4,
+ 0xa9, 0xac, 0xaf, 0xb1, 0xa1, 0x84, 0x4e, 0x95, 0xff, 0x17, 0x61, 0x6e,
+ 0x72, 0x6a, 0x58, 0x5f, 0x66, 0x6e, 0x75, 0x7c, 0x83, 0x8a, 0x90, 0x97,
+ 0x9d, 0xa3, 0xa9, 0xae, 0xb2, 0xb6, 0xb8, 0xa5, 0x84, 0x4e, 0x96, 0xff,
+ 0x16, 0x5c, 0x6e, 0x74, 0x6a, 0x65, 0x68, 0x6f, 0x76, 0x7e, 0x85, 0x8c,
+ 0x93, 0x9a, 0xa1, 0xa7, 0xad, 0xb3, 0xb8, 0xbc, 0xbf, 0xaa, 0x86, 0x4e,
+ 0x97, 0xff, 0x15, 0x59, 0x6d, 0x76, 0x7d, 0x72, 0x70, 0x78, 0x7f, 0x86,
+ 0x8e, 0x95, 0x9c, 0xa3, 0xaa, 0xb1, 0xb7, 0xbd, 0xc2, 0xc6, 0xaf, 0x87,
+ 0x4e, 0x98, 0xff, 0x14, 0x80, 0x6c, 0x78, 0x7f, 0x7d, 0x78, 0x80, 0x87,
+ 0x8f, 0x96, 0x9e, 0xa5, 0xac, 0xb3, 0xbb, 0xc1, 0xc7, 0xcc, 0xb3, 0x8a,
+ 0x4e, 0x9a, 0xff, 0x12, 0x68, 0x79, 0x7f, 0x89, 0x80, 0x87, 0x8f, 0x96,
+ 0x9e, 0xa6, 0xad, 0xb5, 0xbc, 0xc4, 0xcb, 0xd1, 0xb7, 0x89, 0x4e, 0x9b,
+ 0xff, 0x11, 0x63, 0x7a, 0x7e, 0x8f, 0x8b, 0x8e, 0x96, 0x9e, 0xa5, 0xad,
+ 0xb5, 0xbc, 0xc4, 0xcc, 0xd3, 0xbb, 0x8a, 0x4e, 0x9c, 0xff, 0x10, 0x59,
+ 0x78, 0x7f, 0x8e, 0x93, 0x94, 0x9c, 0xa4, 0xab, 0xb3, 0xba, 0xc2, 0xc9,
+ 0xd0, 0xb8, 0x8a, 0x4e, 0x9d, 0xff, 0x0f, 0x80, 0x74, 0x80, 0x8c, 0x9a,
+ 0x99, 0xa1, 0xa8, 0xaf, 0xb6, 0xbd, 0xc3, 0xc8, 0xb5, 0x8b, 0x4e, 0x9f,
+ 0xff, 0x0d, 0x72, 0x82, 0x89, 0xa0, 0x9d, 0xa4, 0xab, 0xb1, 0xb7, 0xbc,
+ 0xc0, 0xb2, 0x8c, 0x4e, 0xa0, 0xff, 0x0c, 0x6b, 0x82, 0x86, 0x9f, 0xa2,
+ 0xa5, 0xab, 0xb0, 0xb4, 0xb7, 0xae, 0x8c, 0x4e, 0xa1, 0xff, 0x0b, 0x59,
+ 0x81, 0x85, 0x98, 0xa4, 0xa4, 0xa8, 0xac, 0xae, 0xac, 0x8b, 0x4e, 0xa2,
+ 0xff, 0x0a, 0x80, 0x7e, 0x87, 0x92, 0xa5, 0xa0, 0xa3, 0xa5, 0xa8, 0x8b,
+ 0x4e, 0xa4, 0xff, 0x08, 0x76, 0x87, 0x8d, 0xa5, 0x9a, 0x9c, 0xa5, 0x8b,
+ 0x4e, 0xa5, 0xff, 0x07, 0x70, 0x88, 0x88, 0xa3, 0x98, 0xab, 0x8a, 0x4e,
+ 0xa6, 0xff, 0x06, 0x63, 0x89, 0x86, 0x9b, 0xbd, 0x8e, 0x47, 0xa7, 0xff,
+ 0x05, 0x80, 0x84, 0x87, 0xa4, 0x9e, 0x66, 0xa9, 0xff, 0x02, 0x79, 0x8c,
+ 0x80, 0xff, 0xff, 0xc7, 0xff, 0xff, 0xff, 0xdc, 0xff, 0x02, 0x00, 0x13,
+ 0x21, 0xa8, 0xff, 0x80, 0x00, 0x02, 0x5e, 0x74, 0x00, 0xa6, 0xff, 0x80,
+ 0x00, 0x03, 0x43, 0xb2, 0x30, 0x00, 0xa5, 0xff, 0x80, 0x00, 0x04, 0x62,
+ 0x9f, 0x8a, 0x00, 0x00, 0xa4, 0xff, 0x08, 0x00, 0x00, 0x09, 0x7a, 0x96,
+ 0x91, 0x56, 0x00, 0x00, 0xa2, 0xff, 0x80, 0x00, 0x07, 0x1d, 0x85, 0x8c,
+ 0x8b, 0x89, 0x53, 0x00, 0x00, 0xa1, 0xff, 0x80, 0x00, 0x08, 0x34, 0x87,
+ 0x85, 0x84, 0x82, 0x81, 0x50, 0x00, 0x00, 0xa0, 0xff, 0x80, 0x00, 0x09,
+ 0x4c, 0x84, 0x7f, 0x7d, 0x7c, 0x7a, 0x79, 0x4d, 0x00, 0x00, 0x9f, 0xff,
+ 0x0d, 0x00, 0x00, 0x07, 0x60, 0x7c, 0x79, 0x76, 0x75, 0x73, 0x72, 0x70,
+ 0x49, 0x00, 0x00, 0x9d, 0xff, 0x80, 0x00, 0x0c, 0x16, 0x69, 0x73, 0x71,
+ 0x70, 0x6e, 0x6d, 0x6b, 0x6a, 0x68, 0x46, 0x00, 0x00, 0x9c, 0xff, 0x80,
+ 0x00, 0x0d, 0x26, 0x6c, 0x6d, 0x6a, 0x69, 0x67, 0x66, 0x64, 0x63, 0x61,
+ 0x60, 0x42, 0x00, 0x00, 0x9b, 0xff, 0x80, 0x00, 0x0e, 0x38, 0x69, 0x66,
+ 0x64, 0x62, 0x61, 0x5f, 0x5e, 0x5c, 0x5b, 0x59, 0x58, 0x3f, 0x00, 0x00,
+ 0x9a, 0xff, 0x12, 0x00, 0x00, 0x05, 0x47, 0x62, 0x5e, 0x5d, 0x5b, 0x5a,
+ 0x58, 0x57, 0x55, 0x54, 0x52, 0x51, 0x4f, 0x3d, 0x00, 0x00, 0x98, 0xff,
+ 0x80, 0x00, 0x11, 0x0e, 0x4d, 0x5a, 0x58, 0x56, 0x55, 0x53, 0x52, 0x50,
+ 0x4f, 0x4d, 0x4c, 0x4a, 0x49, 0x47, 0x3a, 0x00, 0x00, 0x97, 0xff, 0x15,
+ 0x00, 0x00, 0x01, 0x1b, 0x50, 0x53, 0x51, 0x4f, 0x4e, 0x4c, 0x4b, 0x49,
+ 0x48, 0x46, 0x45, 0x43, 0x42, 0x40, 0x3f, 0x38, 0x01, 0x00, 0x96, 0xff,
+ 0x16, 0x00, 0x01, 0x01, 0x26, 0x4d, 0x4c, 0x4a, 0x49, 0x47, 0x46, 0x44,
+ 0x43, 0x41, 0x40, 0x3e, 0x3d, 0x3b, 0x3a, 0x38, 0x37, 0x36, 0x01, 0x00,
+ 0x95, 0xff, 0x17, 0x00, 0x01, 0x06, 0x2f, 0x47, 0x45, 0x43, 0x42, 0x40,
+ 0x3f, 0x3d, 0x3c, 0x3a, 0x39, 0x37, 0x36, 0x34, 0x33, 0x31, 0x30, 0x2e,
+ 0x34, 0x01, 0x00, 0x93, 0xff, 0x19, 0x00, 0x02, 0x01, 0x0b, 0x39, 0x40,
+ 0x3f, 0x3d, 0x3c, 0x3a, 0x38, 0x37, 0x35, 0x34, 0x32, 0x31, 0x2f, 0x2e,
+ 0x2c, 0x2b, 0x29, 0x27, 0x25, 0x32, 0x01, 0x00, 0x92, 0xff, 0x1a, 0x25,
+ 0x09, 0x06, 0x15, 0x39, 0x3a, 0x38, 0x37, 0x34, 0x33, 0x31, 0x30, 0x2e,
+ 0x2d, 0x2b, 0x2a, 0x28, 0x27, 0x25, 0x24, 0x22, 0x20, 0x1f, 0x1d, 0x30,
+ 0x01, 0x00, 0x92, 0xff, 0x10, 0x1f, 0x39, 0x49, 0x39, 0x32, 0x31, 0x31,
+ 0x30, 0x2e, 0x2d, 0x2b, 0x2b, 0x2a, 0x2d, 0x2e, 0x32, 0x31, 0x84, 0x30,
+ 0x02, 0x34, 0x02, 0x00, 0x92, 0xff, 0x0f, 0x3c, 0x5d, 0x5b, 0x0f, 0x00,
+ 0x00, 0x02, 0x04, 0x05, 0x08, 0x0b, 0x0e, 0x0c, 0x09, 0x05, 0x01, 0x85,
+ 0x00, 0x02, 0x0b, 0x02, 0x00, 0x92, 0xff, 0x04, 0x94, 0x34, 0x19, 0x0d,
+ 0x05, 0x90, 0x00, 0x02, 0x0d, 0x02, 0x00, 0x93, 0xff, 0x04, 0xab, 0x04,
+ 0x02, 0x08, 0x0a, 0x8f, 0x00, 0x02, 0x0e, 0x02, 0x00, 0x95, 0xff, 0x03,
+ 0x03, 0x02, 0x08, 0x11, 0x8e, 0x00, 0x02, 0x10, 0x03, 0x00, 0x96, 0xff,
+ 0x04, 0x00, 0x02, 0x04, 0x02, 0x05, 0x8c, 0x00, 0x02, 0x12, 0x03, 0x00,
+ 0x97, 0xff, 0x04, 0x00, 0x03, 0x03, 0x11, 0x09, 0x8b, 0x00, 0x02, 0x13,
+ 0x03, 0x00, 0x98, 0xff, 0x04, 0x00, 0x02, 0x03, 0x0e, 0x11, 0x8a, 0x00,
+ 0x02, 0x15, 0x03, 0x00, 0x9a, 0xff, 0x03, 0x02, 0x03, 0x0b, 0x1a, 0x89,
+ 0x00, 0x02, 0x18, 0x04, 0x00, 0x9b, 0xff, 0x04, 0x05, 0x03, 0x05, 0x02,
+ 0x07, 0x87, 0x00, 0x02, 0x19, 0x04, 0x00, 0x9c, 0xff, 0x04, 0x00, 0x03,
+ 0x04, 0x18, 0x0d, 0x86, 0x00, 0x02, 0x1b, 0x04, 0x00, 0x9d, 0xff, 0x04,
+ 0x00, 0x03, 0x04, 0x12, 0x18, 0x85, 0x00, 0x02, 0x1d, 0x04, 0x00, 0x9f,
+ 0xff, 0x04, 0x02, 0x04, 0x0d, 0x22, 0x01, 0x83, 0x00, 0x02, 0x1f, 0x04,
+ 0x00, 0xa0, 0xff, 0x04, 0x05, 0x03, 0x06, 0x25, 0x09, 0x82, 0x00, 0x02,
+ 0x20, 0x05, 0x00, 0xa1, 0xff, 0x04, 0x00, 0x04, 0x05, 0x1e, 0x12, 0x81,
+ 0x00, 0x02, 0x22, 0x05, 0x00, 0xa2, 0xff, 0x04, 0x00, 0x03, 0x05, 0x18,
+ 0x1e, 0x80, 0x00, 0x02, 0x24, 0x05, 0x00, 0xa4, 0xff, 0x08, 0x02, 0x05,
+ 0x10, 0x2b, 0x01, 0x00, 0x26, 0x05, 0x00, 0xa5, 0xff, 0x07, 0x05, 0x04,
+ 0x08, 0x2e, 0x0b, 0x32, 0x06, 0x00, 0xa6, 0xff, 0x06, 0x00, 0x04, 0x06,
+ 0x27, 0x4d, 0x0c, 0x00, 0xa7, 0xff, 0x05, 0x00, 0x03, 0x06, 0x24, 0x17,
+ 0x00, 0xa9, 0xff, 0x02, 0x03, 0x0e, 0x08, 0xff, 0xff, 0xc7, 0xff, 0xff,
+ 0x00, 0xdc, 0x00, 0x02, 0x4f, 0xa1, 0x45, 0xa8, 0x00, 0x05, 0x02, 0x8e,
+ 0xfa, 0xff, 0xee, 0x07, 0xa6, 0x00, 0x01, 0x10, 0xb7, 0x81, 0xff, 0x00,
+ 0x19, 0xa5, 0x00, 0x01, 0x32, 0xd8, 0x82, 0xff, 0x00, 0x1a, 0xa4, 0x00,
+ 0x01, 0x5f, 0xed, 0x83, 0xff, 0x00, 0x1a, 0xa2, 0x00, 0x02, 0x02, 0x8e,
+ 0xfa, 0x84, 0xff, 0x00, 0x1a, 0xa1, 0x00, 0x01, 0x10, 0xb7, 0x86, 0xff,
+ 0x00, 0x1a, 0xa0, 0x00, 0x01, 0x32, 0xd8, 0x87, 0xff, 0x00, 0x1a, 0x9f,
+ 0x00, 0x01, 0x5f, 0xed, 0x88, 0xff, 0x00, 0x1a, 0x9d, 0x00, 0x02, 0x02,
+ 0x8e, 0xfa, 0x89, 0xff, 0x00, 0x1a, 0x9c, 0x00, 0x01, 0x10, 0xb8, 0x8b,
+ 0xff, 0x00, 0x1a, 0x9b, 0x00, 0x01, 0x32, 0xd8, 0x8c, 0xff, 0x00, 0x1a,
+ 0x9a, 0x00, 0x01, 0x5f, 0xed, 0x8d, 0xff, 0x00, 0x1a, 0x98, 0x00, 0x02,
+ 0x02, 0x8e, 0xfa, 0x8e, 0xff, 0x00, 0x1a, 0x97, 0x00, 0x01, 0x10, 0xb9,
+ 0x90, 0xff, 0x00, 0x1a, 0x96, 0x00, 0x01, 0x33, 0xd9, 0x91, 0xff, 0x00,
+ 0x1a, 0x95, 0x00, 0x01, 0x61, 0xee, 0x92, 0xff, 0x00, 0x1a, 0x93, 0x00,
+ 0x02, 0x02, 0x91, 0xfa, 0x93, 0xff, 0x00, 0x1a, 0x92, 0x00, 0x01, 0x07,
+ 0xbd, 0x95, 0xff, 0x00, 0x1a, 0x91, 0x00, 0x01, 0x01, 0x83, 0x96, 0xff,
+ 0x00, 0x1a, 0x91, 0x00, 0x01, 0x02, 0x8c, 0x96, 0xff, 0x00, 0x1a, 0x92,
+ 0x00, 0x01, 0x0e, 0xc7, 0x95, 0xff, 0x00, 0x1a, 0x93, 0x00, 0x02, 0x06,
+ 0x95, 0xfb, 0x93, 0xff, 0x00, 0x1a, 0x95, 0x00, 0x01, 0x65, 0xf0, 0x92,
+ 0xff, 0x00, 0x1a, 0x96, 0x00, 0x01, 0x35, 0xde, 0x91, 0xff, 0x00, 0x1a,
+ 0x97, 0x00, 0x01, 0x11, 0xc1, 0x90, 0xff, 0x00, 0x1a, 0x98, 0x00, 0x02,
+ 0x02, 0x98, 0xfb, 0x8e, 0xff, 0x00, 0x1a, 0x9a, 0x00, 0x01, 0x67, 0xf1,
+ 0x8d, 0xff, 0x00, 0x1a, 0x9b, 0x00, 0x01, 0x36, 0xe0, 0x8c, 0xff, 0x00,
+ 0x1a, 0x9c, 0x00, 0x01, 0x11, 0xc4, 0x8b, 0xff, 0x00, 0x1a, 0x9d, 0x00,
+ 0x02, 0x02, 0x9b, 0xfc, 0x89, 0xff, 0x00, 0x1a, 0x9f, 0x00, 0x01, 0x69,
+ 0xf2, 0x88, 0xff, 0x00, 0x1a, 0xa0, 0x00, 0x01, 0x37, 0xe2, 0x87, 0xff,
+ 0x00, 0x1a, 0xa1, 0x00, 0x01, 0x11, 0xc7, 0x86, 0xff, 0x00, 0x1a, 0xa2,
+ 0x00, 0x02, 0x02, 0x9e, 0xfc, 0x84, 0xff, 0x00, 0x1a, 0xa4, 0x00, 0x01,
+ 0x6c, 0xf4, 0x83, 0xff, 0x00, 0x1a, 0xa5, 0x00, 0x01, 0x38, 0xe5, 0x82,
+ 0xff, 0x00, 0x1a, 0xa6, 0x00, 0x01, 0x12, 0xca, 0x81, 0xff, 0x00, 0x19,
+ 0xa7, 0x00, 0x05, 0x02, 0xa1, 0xfc, 0xff, 0xe5, 0x05, 0xa9, 0x00, 0x02,
+ 0x51, 0x93, 0x43, 0xff, 0x00, 0xc7, 0x00,
+};
+static EG_EMBEDDED_IMAGE egemb_arrow_left = { 48, 48, EG_EIPIXELMODE_COLOR_ALPHA, EG_EICOMPMODE_RLE, egemb_arrow_left_data, 2407 };
diff --git a/include/egemb_arrow_right.h b/include/egemb_arrow_right.h
new file mode 100644 (file)
index 0000000..8843135
--- /dev/null
@@ -0,0 +1,201 @@
+static const UINT8 egemb_arrow_right_data[2373] = {
+ 0xff, 0xff, 0xc8, 0xff, 0x03, 0x00, 0x22, 0x32, 0x00, 0xa9, 0xff, 0x04,
+ 0x00, 0x36, 0x81, 0x00, 0x00, 0xa8, 0xff, 0x05, 0x00, 0x0f, 0xbe, 0x0a,
+ 0x00, 0x00, 0xa7, 0xff, 0x04, 0x00, 0x00, 0xad, 0x93, 0x21, 0x80, 0x00,
+ 0xa5, 0xff, 0x05, 0x00, 0x00, 0x9a, 0x92, 0x95, 0x3a, 0x80, 0x00, 0xa4,
+ 0xff, 0x06, 0x00, 0x00, 0x91, 0x8a, 0x8b, 0x92, 0x57, 0x80, 0x00, 0xa3,
+ 0xff, 0x0a, 0x00, 0x00, 0x8a, 0x82, 0x83, 0x85, 0x88, 0x6c, 0x08, 0x00,
+ 0x00, 0xa2, 0xff, 0x09, 0x00, 0x00, 0x84, 0x79, 0x7b, 0x7c, 0x7f, 0x80,
+ 0x77, 0x19, 0x80, 0x00, 0xa0, 0xff, 0x0a, 0x00, 0x00, 0x7c, 0x71, 0x73,
+ 0x74, 0x76, 0x77, 0x79, 0x79, 0x2d, 0x80, 0x00, 0x9f, 0xff, 0x0b, 0x00,
+ 0x00, 0x74, 0x69, 0x6a, 0x6c, 0x6d, 0x6f, 0x70, 0x73, 0x76, 0x42, 0x80,
+ 0x00, 0x9e, 0xff, 0x0f, 0x00, 0x00, 0x6e, 0x61, 0x62, 0x64, 0x65, 0x67,
+ 0x68, 0x6a, 0x6c, 0x6e, 0x52, 0x07, 0x00, 0x00, 0x9d, 0xff, 0x0e, 0x00,
+ 0x00, 0x67, 0x58, 0x5a, 0x5b, 0x5d, 0x5e, 0x60, 0x61, 0x63, 0x64, 0x67,
+ 0x5b, 0x12, 0x80, 0x00, 0x9b, 0xff, 0x0f, 0x00, 0x00, 0x60, 0x50, 0x52,
+ 0x53, 0x55, 0x56, 0x58, 0x59, 0x5b, 0x5c, 0x5e, 0x60, 0x5d, 0x20, 0x80,
+ 0x00, 0x9a, 0xff, 0x10, 0x00, 0x00, 0x59, 0x48, 0x49, 0x4b, 0x4c, 0x4e,
+ 0x4f, 0x51, 0x52, 0x54, 0x55, 0x57, 0x59, 0x5c, 0x2f, 0x80, 0x00, 0x99,
+ 0xff, 0x14, 0x00, 0x00, 0x52, 0x40, 0x41, 0x43, 0x44, 0x46, 0x47, 0x49,
+ 0x4a, 0x4c, 0x4d, 0x4f, 0x50, 0x52, 0x54, 0x3b, 0x05, 0x00, 0x00, 0x98,
+ 0xff, 0x13, 0x00, 0x01, 0x4d, 0x37, 0x39, 0x3a, 0x3c, 0x3d, 0x3f, 0x40,
+ 0x42, 0x43, 0x45, 0x46, 0x48, 0x49, 0x4b, 0x4d, 0x43, 0x0c, 0x80, 0x00,
+ 0x96, 0xff, 0x14, 0x00, 0x02, 0x45, 0x2e, 0x31, 0x32, 0x34, 0x35, 0x37,
+ 0x38, 0x3a, 0x3b, 0x3d, 0x3e, 0x40, 0x42, 0x43, 0x44, 0x46, 0x43, 0x17,
+ 0x80, 0x00, 0x95, 0xff, 0x15, 0x00, 0x02, 0x3f, 0x26, 0x28, 0x2a, 0x2b,
+ 0x2d, 0x2e, 0x30, 0x31, 0x33, 0x34, 0x36, 0x37, 0x39, 0x3a, 0x3d, 0x3e,
+ 0x40, 0x42, 0x1d, 0x80, 0x00, 0x94, 0xff, 0x19, 0x00, 0x03, 0x39, 0x1e,
+ 0x1f, 0x21, 0x23, 0x25, 0x26, 0x28, 0x29, 0x2b, 0x2c, 0x2e, 0x2f, 0x31,
+ 0x32, 0x34, 0x36, 0x37, 0x39, 0x3a, 0x26, 0x08, 0x06, 0x0b, 0x93, 0xff,
+ 0x02, 0x00, 0x04, 0x43, 0x83, 0x30, 0x11, 0x31, 0x32, 0x2f, 0x2d, 0x2b,
+ 0x2a, 0x2a, 0x2d, 0x2d, 0x2f, 0x30, 0x31, 0x32, 0x34, 0x40, 0x3d, 0x2d,
+ 0x72, 0x92, 0xff, 0x02, 0x00, 0x05, 0x05, 0x85, 0x00, 0x0f, 0x03, 0x06,
+ 0x0a, 0x0d, 0x0d, 0x09, 0x07, 0x04, 0x02, 0x01, 0x00, 0x03, 0x2d, 0x61,
+ 0x56, 0xa6, 0x92, 0xff, 0x02, 0x00, 0x05, 0x05, 0x90, 0x00, 0x03, 0x0c,
+ 0x0c, 0x2a, 0x39, 0x93, 0xff, 0x02, 0x00, 0x06, 0x06, 0x8e, 0x00, 0x04,
+ 0x04, 0x00, 0x01, 0x00, 0x12, 0x94, 0xff, 0x02, 0x00, 0x07, 0x07, 0x8d,
+ 0x00, 0x01, 0x07, 0x0c, 0x80, 0x00, 0x95, 0xff, 0x02, 0x00, 0x08, 0x08,
+ 0x8c, 0x00, 0x01, 0x0d, 0x08, 0x80, 0x00, 0x96, 0xff, 0x02, 0x00, 0x09,
+ 0x09, 0x8b, 0x00, 0x03, 0x14, 0x06, 0x00, 0x00, 0x98, 0xff, 0x02, 0x00,
+ 0x0a, 0x0a, 0x89, 0x00, 0x04, 0x06, 0x00, 0x01, 0x00, 0x00, 0x99, 0xff,
+ 0x02, 0x00, 0x0a, 0x0a, 0x88, 0x00, 0x01, 0x0b, 0x12, 0x80, 0x00, 0x9a,
+ 0xff, 0x02, 0x00, 0x0b, 0x0b, 0x87, 0x00, 0x01, 0x13, 0x0c, 0x80, 0x00,
+ 0x9b, 0xff, 0x02, 0x00, 0x0c, 0x0c, 0x85, 0x00, 0x04, 0x01, 0x1c, 0x08,
+ 0x00, 0x00, 0x9d, 0xff, 0x02, 0x00, 0x0d, 0x0d, 0x84, 0x00, 0x04, 0x08,
+ 0x1e, 0x01, 0x00, 0x00, 0x9e, 0xff, 0x02, 0x00, 0x0e, 0x0e, 0x83, 0x00,
+ 0x01, 0x0f, 0x18, 0x80, 0x00, 0x9f, 0xff, 0x02, 0x00, 0x0f, 0x0f, 0x82,
+ 0x00, 0x01, 0x1a, 0x11, 0x80, 0x00, 0xa0, 0xff, 0x02, 0x00, 0x10, 0x10,
+ 0x80, 0x00, 0x04, 0x01, 0x24, 0x0a, 0x00, 0x00, 0xa2, 0xff, 0x09, 0x00,
+ 0x11, 0x11, 0x00, 0x00, 0x0a, 0x27, 0x01, 0x00, 0x00, 0xa3, 0xff, 0x05,
+ 0x00, 0x11, 0x12, 0x00, 0x14, 0x1f, 0x80, 0x00, 0xa4, 0xff, 0x04, 0x00,
+ 0x12, 0x1f, 0x21, 0x15, 0x80, 0x00, 0xa5, 0xff, 0x05, 0x00, 0x13, 0x59,
+ 0x0c, 0x00, 0x00, 0xa7, 0xff, 0x04, 0x00, 0x0a, 0x3e, 0x00, 0x00, 0xa8,
+ 0xff, 0x03, 0x00, 0x08, 0x1a, 0x00, 0xff, 0xff, 0xda, 0xff, 0xff, 0xff,
+ 0xc8, 0xff, 0x03, 0x60, 0x64, 0x6f, 0x55, 0xa9, 0xff, 0x04, 0x4b, 0x73,
+ 0xa7, 0x4d, 0x49, 0xa8, 0xff, 0x05, 0x4d, 0x57, 0xdd, 0x54, 0x4d, 0x4e,
+ 0xa7, 0xff, 0x07, 0x4d, 0x4d, 0xe2, 0xc2, 0x64, 0x4d, 0x4b, 0x80, 0xa5,
+ 0xff, 0x08, 0x4d, 0x4d, 0xd2, 0xcf, 0xca, 0x78, 0x4d, 0x4c, 0x4f, 0xa4,
+ 0xff, 0x09, 0x4d, 0x4d, 0xcb, 0xc8, 0xca, 0xcc, 0x90, 0x4d, 0x4d, 0x49,
+ 0xa3, 0xff, 0x0a, 0x4d, 0x4d, 0xc6, 0xc2, 0xc3, 0xc5, 0xc7, 0xa4, 0x52,
+ 0x4d, 0x4d, 0xa2, 0xff, 0x0c, 0x4f, 0x4f, 0xc0, 0xbd, 0xbe, 0xbf, 0xc1,
+ 0xc2, 0xb1, 0x61, 0x4d, 0x4b, 0x80, 0xa0, 0xff, 0x0d, 0x53, 0x54, 0xbc,
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xb8, 0x72, 0x4d, 0x4c, 0x4f, 0x9f,
+ 0xff, 0x0e, 0x56, 0x58, 0xb9, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb7, 0xb9,
+ 0xb9, 0x83, 0x4d, 0x4d, 0x49, 0x9e, 0xff, 0x06, 0x59, 0x5d, 0xb5, 0xaf,
+ 0xb0, 0xb1, 0xb2, 0x80, 0xb3, 0x05, 0xb4, 0xb5, 0x95, 0x54, 0x4d, 0x4d,
+ 0x9d, 0xff, 0x06, 0x5d, 0x62, 0xb3, 0xac, 0xad, 0xae, 0xae, 0x83, 0xaf,
+ 0x04, 0xa0, 0x5f, 0x50, 0x4d, 0x80, 0x9b, 0xff, 0x08, 0x60, 0x66, 0xb1,
+ 0xaa, 0xaa, 0xab, 0xab, 0xac, 0xac, 0x80, 0xab, 0x06, 0xaa, 0xaa, 0xa4,
+ 0x6e, 0x54, 0x50, 0x4f, 0x9a, 0xff, 0x04, 0x62, 0x6b, 0xb0, 0xa8, 0xa8,
+ 0x82, 0xa9, 0x09, 0xa8, 0xa7, 0xa6, 0xa5, 0xa5, 0xa3, 0x7b, 0x57, 0x54,
+ 0x4f, 0x99, 0xff, 0x14, 0x67, 0x70, 0xaf, 0xa6, 0xa7, 0xa7, 0xa8, 0xa7,
+ 0xa7, 0xa6, 0xa5, 0xa4, 0xa3, 0xa1, 0xa0, 0x9e, 0x9d, 0x85, 0x5d, 0x57,
+ 0x52, 0x98, 0xff, 0x02, 0x68, 0x72, 0xaf, 0x81, 0xa6, 0x0f, 0xa5, 0xa4,
+ 0xa4, 0xa3, 0xa1, 0xa0, 0x9e, 0x9c, 0x9a, 0x98, 0x97, 0x8a, 0x64, 0x5b,
+ 0x53, 0x80, 0x96, 0xff, 0x17, 0x6a, 0x76, 0xaf, 0xa5, 0xa6, 0xa6, 0xa5,
+ 0xa5, 0xa4, 0xa2, 0xa1, 0x9e, 0x9d, 0x9a, 0x98, 0x97, 0x94, 0x92, 0x90,
+ 0x8a, 0x6c, 0x5d, 0x58, 0x4f, 0x95, 0xff, 0x18, 0x6e, 0x79, 0xb0, 0xa5,
+ 0xa5, 0xa6, 0xa5, 0xa4, 0xa3, 0xa1, 0x9f, 0x9d, 0x9a, 0x98, 0x95, 0x92,
+ 0x8f, 0x8e, 0x8b, 0x88, 0x84, 0x6d, 0x5e, 0x5b, 0x51, 0x94, 0xff, 0x02,
+ 0x6f, 0x7b, 0xb1, 0x80, 0xa6, 0x13, 0xa5, 0xa5, 0xa2, 0xa0, 0x9e, 0x9b,
+ 0x98, 0x95, 0x92, 0x8f, 0x8b, 0x88, 0x86, 0x83, 0x7f, 0x7d, 0x6f, 0x65,
+ 0x63, 0x5c, 0x93, 0xff, 0x1a, 0x72, 0x7f, 0xba, 0xb2, 0xb1, 0xaf, 0xaf,
+ 0xac, 0xa9, 0xa7, 0xa4, 0x9f, 0x9a, 0x95, 0x91, 0x8c, 0x89, 0x85, 0x81,
+ 0x7e, 0x7a, 0x76, 0x73, 0x7d, 0x86, 0x7c, 0x8e, 0x92, 0xff, 0x1a, 0x74,
+ 0x82, 0xa6, 0xa4, 0xa3, 0xa1, 0x9e, 0x9b, 0x97, 0x92, 0x8d, 0x89, 0x85,
+ 0x82, 0x7d, 0x78, 0x6f, 0x67, 0x5f, 0x57, 0x4f, 0x48, 0x43, 0x65, 0x9e,
+ 0x97, 0xb8, 0x92, 0xff, 0x19, 0x75, 0x83, 0xad, 0xab, 0xaa, 0xa7, 0xa4,
+ 0xa1, 0x9c, 0x97, 0x92, 0x8c, 0x86, 0x80, 0x7a, 0x73, 0x6d, 0x66, 0x5f,
+ 0x58, 0x51, 0x4a, 0x5d, 0x70, 0x81, 0x81, 0x93, 0xff, 0x18, 0x77, 0x87,
+ 0xb4, 0xb2, 0xb0, 0xae, 0xab, 0xa6, 0xa1, 0x9c, 0x96, 0x90, 0x8a, 0x83,
+ 0x7d, 0x76, 0x6f, 0x68, 0x61, 0x5a, 0x57, 0x60, 0x6e, 0x68, 0x65, 0x94,
+ 0xff, 0x17, 0x79, 0x88, 0xbb, 0xb9, 0xb7, 0xb4, 0xb0, 0xac, 0xa6, 0xa0,
+ 0x9a, 0x94, 0x8d, 0x86, 0x7f, 0x78, 0x71, 0x6a, 0x63, 0x63, 0x74, 0x70,
+ 0x66, 0x4a, 0x95, 0xff, 0x16, 0x7a, 0x8a, 0xc2, 0xc0, 0xbe, 0xba, 0xb6,
+ 0xb0, 0xaa, 0xa4, 0x9d, 0x96, 0x90, 0x89, 0x81, 0x7a, 0x73, 0x6b, 0x72,
+ 0x78, 0x72, 0x65, 0x80, 0x96, 0xff, 0x14, 0x7c, 0x8c, 0xc9, 0xc7, 0xc4,
+ 0xc0, 0xba, 0xb4, 0xae, 0xa7, 0xa0, 0x99, 0x91, 0x8a, 0x83, 0x7b, 0x75,
+ 0x7f, 0x7a, 0x74, 0x64, 0x98, 0xff, 0x13, 0x7e, 0x8f, 0xd0, 0xcd, 0xca,
+ 0xc4, 0xbe, 0xb7, 0xb0, 0xa9, 0xa1, 0x9a, 0x92, 0x8b, 0x83, 0x80, 0x86,
+ 0x7b, 0x75, 0x60, 0x99, 0xff, 0x12, 0x80, 0x8f, 0xd7, 0xd4, 0xce, 0xc7,
+ 0xc0, 0xb8, 0xb1, 0xaa, 0xa2, 0x9a, 0x93, 0x8b, 0x89, 0x88, 0x7b, 0x73,
+ 0x59, 0x9a, 0xff, 0x11, 0x80, 0x8f, 0xdc, 0xd7, 0xd0, 0xc8, 0xc0, 0xb8,
+ 0xb1, 0xa9, 0xa1, 0x9a, 0x92, 0x92, 0x87, 0x7e, 0x70, 0x80, 0x9b, 0xff,
+ 0x0f, 0x82, 0x91, 0xd6, 0xd2, 0xcc, 0xc5, 0xbe, 0xb6, 0xaf, 0xa7, 0xa0,
+ 0x98, 0x9a, 0x84, 0x7e, 0x6c, 0x9d, 0xff, 0x0e, 0x83, 0x92, 0xcd, 0xca,
+ 0xc6, 0xc0, 0xba, 0xb3, 0xac, 0xa4, 0x9f, 0x9b, 0x82, 0x7f, 0x66, 0x9e,
+ 0xff, 0x0d, 0x86, 0x93, 0xc5, 0xc1, 0xbe, 0xba, 0xb4, 0xae, 0xa7, 0xa4,
+ 0x96, 0x84, 0x7d, 0x59, 0x9f, 0xff, 0x0c, 0x87, 0x94, 0xbd, 0xb8, 0xb6,
+ 0xb2, 0xad, 0xa8, 0xa8, 0x90, 0x85, 0x77, 0x80, 0xa0, 0xff, 0x0a, 0x87,
+ 0x94, 0xb5, 0xaf, 0xad, 0xaa, 0xa6, 0xa8, 0x8b, 0x86, 0x74, 0xa2, 0xff,
+ 0x03, 0x89, 0x93, 0xac, 0xa5, 0x80, 0xa4, 0x02, 0x87, 0x85, 0x6c, 0xa3,
+ 0xff, 0x08, 0x89, 0x93, 0xa4, 0x9c, 0xa2, 0x9b, 0x87, 0x85, 0x59, 0xa4,
+ 0xff, 0x07, 0x8b, 0x94, 0xa1, 0xa1, 0x94, 0x88, 0x7f, 0x80, 0xa5, 0xff,
+ 0x05, 0x8b, 0x92, 0xb7, 0x8e, 0x89, 0x7d, 0xa7, 0xff, 0x04, 0x7e, 0x8d,
+ 0xa6, 0x8a, 0x76, 0xa8, 0xff, 0x03, 0x00, 0x85, 0x8f, 0x69, 0xff, 0xff,
+ 0xda, 0xff, 0xff, 0xff, 0xc8, 0xff, 0x03, 0x00, 0x22, 0x32, 0x00, 0xa9,
+ 0xff, 0x04, 0x00, 0x36, 0x81, 0x00, 0x00, 0xa8, 0xff, 0x05, 0x00, 0x0f,
+ 0xbe, 0x0a, 0x00, 0x00, 0xa7, 0xff, 0x04, 0x00, 0x00, 0xad, 0x93, 0x21,
+ 0x80, 0x00, 0xa5, 0xff, 0x05, 0x00, 0x00, 0x9a, 0x92, 0x95, 0x3a, 0x80,
+ 0x00, 0xa4, 0xff, 0x06, 0x00, 0x00, 0x91, 0x8a, 0x8b, 0x92, 0x57, 0x80,
+ 0x00, 0xa3, 0xff, 0x0a, 0x00, 0x00, 0x8a, 0x82, 0x83, 0x85, 0x88, 0x6c,
+ 0x08, 0x00, 0x00, 0xa2, 0xff, 0x09, 0x00, 0x00, 0x84, 0x79, 0x7b, 0x7c,
+ 0x7f, 0x80, 0x77, 0x19, 0x80, 0x00, 0xa0, 0xff, 0x0a, 0x00, 0x00, 0x7c,
+ 0x71, 0x73, 0x74, 0x76, 0x77, 0x79, 0x79, 0x2d, 0x80, 0x00, 0x9f, 0xff,
+ 0x0b, 0x00, 0x00, 0x74, 0x69, 0x6a, 0x6c, 0x6d, 0x6f, 0x70, 0x73, 0x76,
+ 0x42, 0x80, 0x00, 0x9e, 0xff, 0x0f, 0x00, 0x00, 0x6e, 0x61, 0x62, 0x64,
+ 0x65, 0x67, 0x68, 0x6a, 0x6c, 0x6e, 0x52, 0x07, 0x00, 0x00, 0x9d, 0xff,
+ 0x0e, 0x00, 0x00, 0x67, 0x58, 0x5a, 0x5b, 0x5d, 0x5e, 0x60, 0x61, 0x63,
+ 0x64, 0x67, 0x5b, 0x12, 0x80, 0x00, 0x9b, 0xff, 0x0f, 0x00, 0x00, 0x60,
+ 0x50, 0x52, 0x53, 0x55, 0x56, 0x58, 0x59, 0x5b, 0x5c, 0x5e, 0x60, 0x5d,
+ 0x20, 0x80, 0x00, 0x9a, 0xff, 0x10, 0x00, 0x00, 0x59, 0x48, 0x49, 0x4b,
+ 0x4c, 0x4e, 0x4f, 0x51, 0x52, 0x54, 0x55, 0x57, 0x59, 0x5c, 0x2f, 0x80,
+ 0x00, 0x99, 0xff, 0x14, 0x00, 0x01, 0x52, 0x40, 0x41, 0x43, 0x44, 0x46,
+ 0x47, 0x49, 0x4a, 0x4c, 0x4d, 0x4f, 0x50, 0x52, 0x54, 0x3b, 0x06, 0x00,
+ 0x00, 0x98, 0xff, 0x16, 0x01, 0x02, 0x4d, 0x37, 0x39, 0x3a, 0x3c, 0x3d,
+ 0x3f, 0x40, 0x42, 0x43, 0x45, 0x46, 0x48, 0x49, 0x4b, 0x4d, 0x43, 0x0d,
+ 0x01, 0x00, 0x00, 0x96, 0xff, 0x17, 0x01, 0x03, 0x45, 0x2e, 0x31, 0x32,
+ 0x34, 0x35, 0x37, 0x38, 0x3a, 0x3b, 0x3d, 0x3e, 0x40, 0x42, 0x43, 0x44,
+ 0x46, 0x43, 0x18, 0x01, 0x01, 0x00, 0x95, 0xff, 0x18, 0x01, 0x03, 0x3f,
+ 0x26, 0x28, 0x2a, 0x2b, 0x2d, 0x2e, 0x30, 0x31, 0x33, 0x34, 0x36, 0x37,
+ 0x39, 0x3a, 0x3d, 0x3e, 0x40, 0x42, 0x1e, 0x01, 0x01, 0x00, 0x94, 0xff,
+ 0x19, 0x01, 0x04, 0x39, 0x1e, 0x1f, 0x21, 0x23, 0x25, 0x26, 0x28, 0x29,
+ 0x2b, 0x2c, 0x2e, 0x2f, 0x31, 0x32, 0x34, 0x36, 0x37, 0x39, 0x3a, 0x26,
+ 0x09, 0x07, 0x0b, 0x93, 0xff, 0x02, 0x01, 0x06, 0x43, 0x83, 0x30, 0x11,
+ 0x31, 0x32, 0x2f, 0x2d, 0x2b, 0x2a, 0x2a, 0x2d, 0x2d, 0x2f, 0x30, 0x31,
+ 0x32, 0x34, 0x40, 0x3f, 0x2e, 0x72, 0x92, 0xff, 0x02, 0x01, 0x07, 0x05,
+ 0x85, 0x00, 0x0f, 0x03, 0x06, 0x0a, 0x0d, 0x0d, 0x09, 0x07, 0x04, 0x02,
+ 0x01, 0x00, 0x03, 0x2d, 0x62, 0x57, 0xa6, 0x92, 0xff, 0x02, 0x01, 0x07,
+ 0x05, 0x90, 0x00, 0x03, 0x0d, 0x0e, 0x2c, 0x3c, 0x93, 0xff, 0x02, 0x01,
+ 0x08, 0x06, 0x8e, 0x00, 0x04, 0x04, 0x01, 0x03, 0x02, 0x12, 0x94, 0xff,
+ 0x02, 0x01, 0x0a, 0x07, 0x8d, 0x00, 0x04, 0x07, 0x0e, 0x03, 0x03, 0x00,
+ 0x95, 0xff, 0x02, 0x03, 0x0b, 0x08, 0x8c, 0x00, 0x04, 0x0e, 0x0b, 0x03,
+ 0x02, 0x00, 0x96, 0xff, 0x02, 0x03, 0x0c, 0x09, 0x8b, 0x00, 0x03, 0x15,
+ 0x09, 0x03, 0x03, 0x98, 0xff, 0x02, 0x03, 0x0d, 0x0a, 0x89, 0x00, 0x04,
+ 0x06, 0x02, 0x04, 0x02, 0x00, 0x99, 0xff, 0x02, 0x03, 0x0e, 0x0a, 0x88,
+ 0x00, 0x04, 0x0b, 0x15, 0x04, 0x03, 0x00, 0x9a, 0xff, 0x02, 0x03, 0x0f,
+ 0x0b, 0x87, 0x00, 0x04, 0x14, 0x10, 0x04, 0x02, 0x00, 0x9b, 0xff, 0x02,
+ 0x03, 0x10, 0x0c, 0x85, 0x00, 0x04, 0x01, 0x1e, 0x0c, 0x04, 0x02, 0x9d,
+ 0xff, 0x02, 0x03, 0x11, 0x0d, 0x84, 0x00, 0x04, 0x08, 0x20, 0x05, 0x03,
+ 0x05, 0x9e, 0xff, 0x02, 0x03, 0x12, 0x0e, 0x83, 0x00, 0x04, 0x0f, 0x1b,
+ 0x04, 0x04, 0x00, 0x9f, 0xff, 0x02, 0x03, 0x14, 0x0f, 0x82, 0x00, 0x04,
+ 0x1b, 0x16, 0x05, 0x03, 0x00, 0xa0, 0xff, 0x02, 0x04, 0x15, 0x10, 0x80,
+ 0x00, 0x04, 0x01, 0x26, 0x0f, 0x04, 0x02, 0xa2, 0xff, 0x09, 0x04, 0x16,
+ 0x11, 0x00, 0x00, 0x0a, 0x29, 0x06, 0x04, 0x05, 0xa3, 0xff, 0x08, 0x04,
+ 0x16, 0x12, 0x00, 0x14, 0x22, 0x05, 0x04, 0x00, 0xa4, 0xff, 0x07, 0x04,
+ 0x18, 0x19, 0x22, 0x1a, 0x05, 0x03, 0x00, 0xa5, 0xff, 0x05, 0x04, 0x18,
+ 0x49, 0x12, 0x05, 0x02, 0xa7, 0xff, 0x04, 0x02, 0x0c, 0x25, 0x06, 0x04,
+ 0xa8, 0xff, 0x03, 0x00, 0x08, 0x11, 0x00, 0xff, 0xff, 0xda, 0xff, 0xff,
+ 0x00, 0xc8, 0x00, 0x03, 0x08, 0x87, 0x9a, 0x0f, 0xa9, 0x00, 0x04, 0x7e,
+ 0xff, 0xff, 0xd8, 0x32, 0xa8, 0x00, 0x00, 0xae, 0x80, 0xff, 0x01, 0xed,
+ 0x5e, 0xa7, 0x00, 0x00, 0xaf, 0x81, 0xff, 0x02, 0xfa, 0x8e, 0x02, 0xa5,
+ 0x00, 0x00, 0xaf, 0x83, 0xff, 0x01, 0xb7, 0x10, 0xa4, 0x00, 0x00, 0xaf,
+ 0x84, 0xff, 0x01, 0xd8, 0x32, 0xa3, 0x00, 0x00, 0xaf, 0x85, 0xff, 0x01,
+ 0xed, 0x5f, 0xa2, 0x00, 0x00, 0xaf, 0x86, 0xff, 0x02, 0xfa, 0x8e, 0x02,
+ 0xa0, 0x00, 0x00, 0xaf, 0x88, 0xff, 0x01, 0xb8, 0x10, 0x9f, 0x00, 0x00,
+ 0xaf, 0x89, 0xff, 0x01, 0xd8, 0x32, 0x9e, 0x00, 0x00, 0xaf, 0x8a, 0xff,
+ 0x01, 0xed, 0x5f, 0x9d, 0x00, 0x00, 0xaf, 0x8b, 0xff, 0x02, 0xfa, 0x8e,
+ 0x02, 0x9b, 0x00, 0x00, 0xaf, 0x8d, 0xff, 0x01, 0xb8, 0x10, 0x9a, 0x00,
+ 0x00, 0xaf, 0x8e, 0xff, 0x01, 0xd8, 0x32, 0x99, 0x00, 0x00, 0xb0, 0x8f,
+ 0xff, 0x01, 0xed, 0x60, 0x98, 0x00, 0x00, 0xb1, 0x90, 0xff, 0x02, 0xfa,
+ 0x90, 0x02, 0x96, 0x00, 0x00, 0xb2, 0x92, 0xff, 0x01, 0xbb, 0x10, 0x95,
+ 0x00, 0x00, 0xb2, 0x93, 0xff, 0x01, 0xda, 0x34, 0x94, 0x00, 0x00, 0xb3,
+ 0x94, 0xff, 0x01, 0xef, 0x5d, 0x93, 0x00, 0x00, 0xb4, 0x95, 0xff, 0x01,
+ 0xe6, 0x09, 0x92, 0x00, 0x00, 0xb5, 0x95, 0xff, 0x01, 0xea, 0x0e, 0x92,
+ 0x00, 0x00, 0xb5, 0x94, 0xff, 0x02, 0xf2, 0x6a, 0x02, 0x92, 0x00, 0x00,
+ 0xb6, 0x93, 0xff, 0x02, 0xdd, 0x37, 0x02, 0x93, 0x00, 0x00, 0xb7, 0x92,
+ 0xff, 0x01, 0xc0, 0x11, 0x95, 0x00, 0x00, 0xb7, 0x90, 0xff, 0x02, 0xfb,
+ 0x96, 0x02, 0x96, 0x00, 0x00, 0xb8, 0x8f, 0xff, 0x01, 0xf1, 0x66, 0x98,
+ 0x00, 0x00, 0xb9, 0x8e, 0xff, 0x01, 0xdf, 0x35, 0x99, 0x00, 0x00, 0xba,
+ 0x8d, 0xff, 0x01, 0xc3, 0x11, 0x9a, 0x00, 0x00, 0xbb, 0x8b, 0xff, 0x02,
+ 0xfb, 0x99, 0x02, 0x9b, 0x00, 0x00, 0xbc, 0x8a, 0xff, 0x01, 0xf2, 0x68,
+ 0x9d, 0x00, 0x00, 0xbc, 0x89, 0xff, 0x01, 0xe1, 0x37, 0x9e, 0x00, 0x00,
+ 0xbd, 0x88, 0xff, 0x01, 0xc5, 0x11, 0x9f, 0x00, 0x00, 0xbe, 0x86, 0xff,
+ 0x02, 0xfc, 0x9c, 0x02, 0xa0, 0x00, 0x00, 0xbe, 0x85, 0xff, 0x01, 0xf3,
+ 0x6a, 0xa2, 0x00, 0x00, 0xbf, 0x84, 0xff, 0x01, 0xe4, 0x38, 0xa3, 0x00,
+ 0x00, 0xc0, 0x83, 0xff, 0x01, 0xc8, 0x11, 0xa4, 0x00, 0x00, 0xc1, 0x81,
+ 0xff, 0x02, 0xfc, 0x9f, 0x02, 0xa5, 0x00, 0x00, 0xc1, 0x80, 0xff, 0x01,
+ 0xf4, 0x6c, 0xa7, 0x00, 0x04, 0x73, 0xfe, 0xff, 0xe6, 0x39, 0xa8, 0x00,
+ 0x03, 0x01, 0x86, 0x87, 0x11, 0xff, 0x00, 0xda, 0x00,
+};
+static EG_EMBEDDED_IMAGE egemb_arrow_right = { 48, 48, EG_EIPIXELMODE_COLOR_ALPHA, EG_EICOMPMODE_RLE, egemb_arrow_right_data, 2373 };
diff --git a/include/egemb_back_selected_small.h b/include/egemb_back_selected_small.h
new file mode 100644 (file)
index 0000000..c03d8b7
--- /dev/null
@@ -0,0 +1,129 @@
+static const UINT8 egemb_back_selected_small_data[1503] = {
+ 0x83, 0xbf, 0x02, 0xc8, 0xd2, 0xd6, 0xab, 0xdc, 0x02, 0xd6, 0xd2, 0xc8,
+ 0x87, 0xbf, 0x01, 0xc3, 0xd6, 0x80, 0xdc, 0x04, 0xdb, 0xd7, 0xd5, 0xd3,
+ 0xd1, 0xa1, 0xd0, 0x04, 0xd1, 0xd3, 0xd5, 0xd7, 0xdb, 0x80, 0xdc, 0x01,
+ 0xd6, 0xc3, 0x84, 0xbf, 0x0b, 0xcc, 0xdb, 0xdc, 0xdc, 0xd5, 0xcd, 0xc7,
+ 0xc3, 0xbf, 0xbe, 0xbd, 0xbc, 0x9f, 0xbb, 0x0b, 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc3, 0xc7, 0xcd, 0xd5, 0xdc, 0xdc, 0xdb, 0xcc, 0x82, 0xbf, 0x0c, 0xcf,
+ 0xdc, 0xdc, 0xd7, 0xcc, 0xc3, 0xba, 0xb4, 0xb0, 0xad, 0xac, 0xaa, 0xaa,
+ 0x9f, 0xa9, 0x0c, 0xaa, 0xaa, 0xac, 0xad, 0xb0, 0xb4, 0xba, 0xc3, 0xcc,
+ 0xd7, 0xdc, 0xdc, 0xcf, 0x80, 0xbf, 0x0d, 0xc9, 0xdc, 0xdc, 0xd5, 0xc8,
+ 0xbc, 0xb2, 0xaa, 0xa3, 0x9f, 0x9d, 0x9c, 0x9b, 0x9a, 0x9f, 0x99, 0x1c,
+ 0x9a, 0x9b, 0x9c, 0x9d, 0x9f, 0xa3, 0xaa, 0xb2, 0xbc, 0xc8, 0xd5, 0xdc,
+ 0xdc, 0xc9, 0xbf, 0xc0, 0xd9, 0xdc, 0xd7, 0xc8, 0xb9, 0xad, 0xa3, 0x9b,
+ 0x96, 0x92, 0x90, 0x8e, 0x8e, 0xa1, 0x8d, 0x1b, 0x8e, 0x8e, 0x90, 0x92,
+ 0x96, 0x9b, 0xa3, 0xad, 0xb9, 0xc8, 0xd7, 0xdc, 0xd8, 0xc0, 0xc9, 0xdc,
+ 0xdc, 0xcb, 0xbb, 0xad, 0xa1, 0x97, 0x8f, 0x8a, 0x87, 0x85, 0x84, 0x83,
+ 0xa1, 0x82, 0x1a, 0x83, 0x84, 0x85, 0x87, 0x8a, 0x8f, 0x97, 0xa1, 0xad,
+ 0xbb, 0xcb, 0xdc, 0xdc, 0xc9, 0xd2, 0xdc, 0xd4, 0xc2, 0xb2, 0xa3, 0x97,
+ 0x8d, 0x86, 0x81, 0x7e, 0x7c, 0x7c, 0xa3, 0x7b, 0x18, 0x7c, 0x7c, 0x7e,
+ 0x81, 0x86, 0x8d, 0x97, 0xa3, 0xb2, 0xc2, 0xd4, 0xdc, 0xd2, 0xd8, 0xdc,
+ 0xcc, 0xba, 0xa9, 0x9b, 0x8f, 0x86, 0x7f, 0x7a, 0x78, 0x77, 0x80, 0x76,
+ 0x9f, 0x75, 0x80, 0x76, 0x17, 0x77, 0x78, 0x7a, 0x7f, 0x86, 0x8f, 0x9b,
+ 0xa9, 0xba, 0xcc, 0xdc, 0xd8, 0xda, 0xdb, 0xc6, 0xb4, 0xa3, 0x95, 0x8a,
+ 0x81, 0x7a, 0x76, 0x74, 0x74, 0xa5, 0x73, 0x16, 0x74, 0x74, 0x76, 0x7a,
+ 0x80, 0x8a, 0x95, 0xa3, 0xb4, 0xc6, 0xdb, 0xdb, 0xdc, 0xd7, 0xc3, 0xaf,
+ 0x9f, 0x91, 0x86, 0x7d, 0x78, 0x74, 0x74, 0xa7, 0x73, 0x14, 0x74, 0x74,
+ 0x78, 0x7d, 0x86, 0x91, 0x9f, 0xaf, 0xc2, 0xd7, 0xdc, 0xdc, 0xd4, 0xbf,
+ 0xad, 0x9d, 0x90, 0x85, 0x7c, 0x77, 0x74, 0xa9, 0x73, 0x12, 0x74, 0x77,
+ 0x7c, 0x85, 0x90, 0x9d, 0xad, 0xbf, 0xd4, 0xdc, 0xdc, 0xd3, 0xbe, 0xac,
+ 0x9b, 0x8e, 0x83, 0x7c, 0x76, 0xab, 0x73, 0x11, 0x76, 0x7c, 0x83, 0x8e,
+ 0x9b, 0xab, 0xbe, 0xd3, 0xdc, 0xdc, 0xd1, 0xbc, 0xaa, 0x9b, 0x8d, 0x83,
+ 0x7b, 0x76, 0xab, 0x73, 0x11, 0x76, 0x7b, 0x83, 0x8d, 0x9b, 0xaa, 0xbc,
+ 0xd1, 0xdc, 0xdc, 0xd0, 0xbc, 0xaa, 0x9a, 0x8d, 0x82, 0x7b, 0x76, 0xab,
+ 0x73, 0x11, 0x76, 0x7b, 0x82, 0x8d, 0x9a, 0xaa, 0xbc, 0xd0, 0xdc, 0xdc,
+ 0xd0, 0xbb, 0xa9, 0x99, 0x8d, 0x82, 0x7b, 0x75, 0xab, 0x73, 0x11, 0x75,
+ 0x7b, 0x82, 0x8d, 0x99, 0xa9, 0xbb, 0xd0, 0xdc, 0xdc, 0xd0, 0xbb, 0xa9,
+ 0x99, 0x8d, 0x82, 0x7b, 0x75, 0xab, 0x73, 0x11, 0x75, 0x7b, 0x82, 0x8d,
+ 0x99, 0xa9, 0xbb, 0xd0, 0xdc, 0xdc, 0xd0, 0xbb, 0xa9, 0x99, 0x8d, 0x82,
+ 0x7b, 0x75, 0xab, 0x73, 0x11, 0x75, 0x7b, 0x82, 0x8d, 0x99, 0xa9, 0xbb,
+ 0xd0, 0xdc, 0xdc, 0xd0, 0xbb, 0xa9, 0x99, 0x8d, 0x82, 0x7b, 0x75, 0xab,
+ 0x73, 0x11, 0x75, 0x7b, 0x82, 0x8d, 0x99, 0xa9, 0xbb, 0xd0, 0xdc, 0xdc,
+ 0xd0, 0xbb, 0xa9, 0x99, 0x8d, 0x82, 0x7b, 0x75, 0xab, 0x73, 0x11, 0x75,
+ 0x7b, 0x82, 0x8d, 0x99, 0xa9, 0xbb, 0xd0, 0xdc, 0xdc, 0xd0, 0xbb, 0xa9,
+ 0x99, 0x8d, 0x82, 0x7b, 0x75, 0xab, 0x73, 0x11, 0x75, 0x7b, 0x82, 0x8d,
+ 0x99, 0xa9, 0xbb, 0xd0, 0xdc, 0xdc, 0xd0, 0xbb, 0xa9, 0x99, 0x8d, 0x82,
+ 0x7b, 0x75, 0xab, 0x73, 0x11, 0x75, 0x7b, 0x82, 0x8d, 0x99, 0xa9, 0xbb,
+ 0xd0, 0xdc, 0xdc, 0xd0, 0xbb, 0xa9, 0x99, 0x8d, 0x82, 0x7b, 0x75, 0xab,
+ 0x73, 0x11, 0x75, 0x7b, 0x82, 0x8d, 0x99, 0xa9, 0xbb, 0xd0, 0xdc, 0xdc,
+ 0xd0, 0xbb, 0xa9, 0x99, 0x8d, 0x82, 0x7b, 0x75, 0xab, 0x73, 0x11, 0x75,
+ 0x7b, 0x82, 0x8d, 0x99, 0xa9, 0xbb, 0xd0, 0xdc, 0xdc, 0xd0, 0xbb, 0xa9,
+ 0x99, 0x8d, 0x82, 0x7b, 0x75, 0xab, 0x73, 0x11, 0x75, 0x7b, 0x82, 0x8d,
+ 0x99, 0xa9, 0xbb, 0xd0, 0xdc, 0xdc, 0xd0, 0xbb, 0xa9, 0x99, 0x8d, 0x82,
+ 0x7b, 0x75, 0xab, 0x73, 0x11, 0x75, 0x7b, 0x82, 0x8d, 0x99, 0xa9, 0xbb,
+ 0xd0, 0xdc, 0xdc, 0xd0, 0xbb, 0xa9, 0x99, 0x8d, 0x82, 0x7b, 0x75, 0xab,
+ 0x73, 0x11, 0x75, 0x7b, 0x82, 0x8d, 0x99, 0xa9, 0xbb, 0xd0, 0xdc, 0xdc,
+ 0xd0, 0xbb, 0xa9, 0x99, 0x8d, 0x82, 0x7b, 0x75, 0xab, 0x73, 0x11, 0x75,
+ 0x7b, 0x82, 0x8d, 0x99, 0xa9, 0xbb, 0xd0, 0xdc, 0xdc, 0xd0, 0xbb, 0xa9,
+ 0x99, 0x8d, 0x82, 0x7b, 0x75, 0xab, 0x73, 0x11, 0x75, 0x7b, 0x82, 0x8d,
+ 0x99, 0xa9, 0xbb, 0xd0, 0xdc, 0xdc, 0xd0, 0xbb, 0xa9, 0x99, 0x8d, 0x82,
+ 0x7b, 0x75, 0xab, 0x73, 0x11, 0x75, 0x7b, 0x82, 0x8d, 0x99, 0xa9, 0xbb,
+ 0xd0, 0xdc, 0xdc, 0xd0, 0xbb, 0xa9, 0x99, 0x8d, 0x82, 0x7b, 0x75, 0xab,
+ 0x73, 0x11, 0x75, 0x7b, 0x82, 0x8d, 0x99, 0xa9, 0xbb, 0xd0, 0xdc, 0xdc,
+ 0xd0, 0xbb, 0xa9, 0x99, 0x8d, 0x82, 0x7b, 0x75, 0xab, 0x73, 0x11, 0x75,
+ 0x7b, 0x82, 0x8d, 0x99, 0xa9, 0xbb, 0xd0, 0xdc, 0xdc, 0xd0, 0xbb, 0xa9,
+ 0x99, 0x8d, 0x82, 0x7b, 0x75, 0xab, 0x73, 0x11, 0x75, 0x7b, 0x82, 0x8d,
+ 0x99, 0xa9, 0xbb, 0xd0, 0xdc, 0xdc, 0xd0, 0xbb, 0xa9, 0x99, 0x8d, 0x82,
+ 0x7b, 0x75, 0xab, 0x73, 0x11, 0x75, 0x7b, 0x82, 0x8d, 0x99, 0xa9, 0xbb,
+ 0xd0, 0xdc, 0xdc, 0xd0, 0xbb, 0xa9, 0x99, 0x8d, 0x82, 0x7b, 0x75, 0xab,
+ 0x73, 0x11, 0x75, 0x7b, 0x82, 0x8d, 0x99, 0xa9, 0xbb, 0xd0, 0xdc, 0xdc,
+ 0xd0, 0xbb, 0xa9, 0x99, 0x8d, 0x82, 0x7b, 0x75, 0xab, 0x73, 0x11, 0x75,
+ 0x7b, 0x82, 0x8d, 0x99, 0xa9, 0xbb, 0xd0, 0xdc, 0xdc, 0xd0, 0xbb, 0xa9,
+ 0x99, 0x8d, 0x82, 0x7b, 0x75, 0xab, 0x73, 0x11, 0x75, 0x7b, 0x82, 0x8d,
+ 0x99, 0xa9, 0xbb, 0xd0, 0xdc, 0xdc, 0xd0, 0xbb, 0xa9, 0x99, 0x8d, 0x82,
+ 0x7b, 0x75, 0xab, 0x73, 0x11, 0x75, 0x7b, 0x82, 0x8d, 0x99, 0xa9, 0xbb,
+ 0xd0, 0xdc, 0xdc, 0xd0, 0xbb, 0xa9, 0x99, 0x8d, 0x82, 0x7b, 0x75, 0xab,
+ 0x73, 0x11, 0x75, 0x7b, 0x82, 0x8d, 0x99, 0xa9, 0xbb, 0xd0, 0xdc, 0xdc,
+ 0xd0, 0xbb, 0xa9, 0x99, 0x8d, 0x82, 0x7b, 0x75, 0xab, 0x73, 0x11, 0x75,
+ 0x7b, 0x82, 0x8d, 0x99, 0xa9, 0xbb, 0xd0, 0xdc, 0xdc, 0xd0, 0xbb, 0xa9,
+ 0x99, 0x8d, 0x82, 0x7b, 0x75, 0xab, 0x73, 0x11, 0x75, 0x7b, 0x82, 0x8d,
+ 0x99, 0xa9, 0xbb, 0xd0, 0xdc, 0xdc, 0xd0, 0xbb, 0xa9, 0x99, 0x8d, 0x82,
+ 0x7b, 0x75, 0xab, 0x73, 0x11, 0x75, 0x7b, 0x82, 0x8d, 0x99, 0xa9, 0xbb,
+ 0xd0, 0xdc, 0xdc, 0xd0, 0xbb, 0xa9, 0x99, 0x8d, 0x82, 0x7b, 0x75, 0xab,
+ 0x73, 0x11, 0x75, 0x7b, 0x82, 0x8d, 0x99, 0xa9, 0xbb, 0xd0, 0xdc, 0xdc,
+ 0xd0, 0xbb, 0xa9, 0x99, 0x8d, 0x82, 0x7b, 0x75, 0xab, 0x73, 0x11, 0x75,
+ 0x7b, 0x82, 0x8d, 0x99, 0xa9, 0xbb, 0xd0, 0xdc, 0xdc, 0xd0, 0xbb, 0xa9,
+ 0x99, 0x8d, 0x82, 0x7b, 0x75, 0xab, 0x73, 0x11, 0x75, 0x7b, 0x82, 0x8d,
+ 0x99, 0xa9, 0xbb, 0xd0, 0xdc, 0xdc, 0xd0, 0xbb, 0xa9, 0x99, 0x8d, 0x82,
+ 0x7b, 0x75, 0xab, 0x73, 0x11, 0x75, 0x7b, 0x82, 0x8d, 0x99, 0xa9, 0xbb,
+ 0xd0, 0xdc, 0xdc, 0xd0, 0xbb, 0xa9, 0x99, 0x8d, 0x82, 0x7b, 0x75, 0xab,
+ 0x73, 0x11, 0x75, 0x7b, 0x82, 0x8d, 0x99, 0xa9, 0xbb, 0xd0, 0xdc, 0xdc,
+ 0xd0, 0xbb, 0xa9, 0x99, 0x8d, 0x82, 0x7b, 0x75, 0xab, 0x73, 0x11, 0x75,
+ 0x7b, 0x82, 0x8d, 0x99, 0xa9, 0xbb, 0xd0, 0xdc, 0xdc, 0xd0, 0xbb, 0xa9,
+ 0x99, 0x8d, 0x82, 0x7b, 0x75, 0xab, 0x73, 0x11, 0x75, 0x7b, 0x82, 0x8d,
+ 0x99, 0xa9, 0xbb, 0xd0, 0xdc, 0xdc, 0xd0, 0xbc, 0xaa, 0x9a, 0x8d, 0x82,
+ 0x7b, 0x76, 0xab, 0x73, 0x11, 0x76, 0x7b, 0x82, 0x8d, 0x9a, 0xaa, 0xbc,
+ 0xd0, 0xdc, 0xdc, 0xd1, 0xbc, 0xaa, 0x9b, 0x8d, 0x83, 0x7b, 0x76, 0xab,
+ 0x73, 0x11, 0x76, 0x7b, 0x83, 0x8d, 0x9b, 0xaa, 0xbc, 0xd1, 0xdc, 0xdc,
+ 0xd3, 0xbe, 0xac, 0x9b, 0x8e, 0x83, 0x7c, 0x76, 0xab, 0x73, 0x12, 0x76,
+ 0x7c, 0x83, 0x8e, 0x9b, 0xab, 0xbe, 0xd3, 0xdc, 0xdc, 0xd4, 0xbf, 0xad,
+ 0x9d, 0x90, 0x85, 0x7c, 0x77, 0x74, 0xa9, 0x73, 0x14, 0x74, 0x77, 0x7c,
+ 0x85, 0x90, 0x9d, 0xad, 0xbf, 0xd4, 0xdc, 0xdc, 0xd7, 0xc2, 0xaf, 0x9f,
+ 0x91, 0x86, 0x7d, 0x78, 0x74, 0x74, 0xa7, 0x73, 0x16, 0x74, 0x74, 0x78,
+ 0x7d, 0x86, 0x91, 0x9f, 0xaf, 0xc2, 0xd7, 0xdc, 0xda, 0xdb, 0xc6, 0xb4,
+ 0xa3, 0x95, 0x8a, 0x80, 0x7a, 0x76, 0x74, 0x74, 0xa5, 0x73, 0x17, 0x74,
+ 0x74, 0x76, 0x7a, 0x80, 0x8a, 0x95, 0xa3, 0xb4, 0xc6, 0xdb, 0xdb, 0xd8,
+ 0xdc, 0xcc, 0xba, 0xa9, 0x9b, 0x8f, 0x86, 0x7f, 0x7a, 0x78, 0x77, 0x80,
+ 0x76, 0x9f, 0x75, 0x80, 0x76, 0x18, 0x77, 0x78, 0x7a, 0x7f, 0x86, 0x8f,
+ 0x9b, 0xa9, 0xba, 0xcc, 0xdc, 0xd8, 0xd2, 0xdc, 0xd4, 0xc2, 0xb1, 0xa3,
+ 0x97, 0x8d, 0x86, 0x81, 0x7e, 0x7c, 0x7c, 0xa3, 0x7b, 0x1a, 0x7c, 0x7c,
+ 0x7e, 0x81, 0x86, 0x8d, 0x97, 0xa3, 0xb1, 0xc2, 0xd4, 0xdc, 0xd2, 0xc9,
+ 0xdc, 0xdc, 0xcb, 0xbb, 0xad, 0xa1, 0x97, 0x8f, 0x8a, 0x87, 0x85, 0x84,
+ 0x83, 0xa1, 0x82, 0x1b, 0x83, 0x84, 0x85, 0x86, 0x8a, 0x8f, 0x97, 0xa1,
+ 0xad, 0xbb, 0xcb, 0xdc, 0xdc, 0xc9, 0xc0, 0xd8, 0xdc, 0xd6, 0xc8, 0xb9,
+ 0xad, 0xa3, 0x9b, 0x95, 0x92, 0x90, 0x8e, 0x8e, 0xa1, 0x8d, 0x1c, 0x8e,
+ 0x8e, 0x90, 0x92, 0x95, 0x9b, 0xa3, 0xad, 0xb9, 0xc8, 0xd6, 0xdc, 0xd8,
+ 0xc0, 0xbf, 0xc9, 0xdc, 0xdc, 0xd5, 0xc8, 0xbb, 0xb2, 0xa9, 0xa3, 0x9f,
+ 0x9d, 0x9c, 0x9b, 0x9a, 0x9f, 0x99, 0x0d, 0x9a, 0x9b, 0x9c, 0x9d, 0x9f,
+ 0xa3, 0xa9, 0xb2, 0xbb, 0xc8, 0xd5, 0xdc, 0xdc, 0xc9, 0x80, 0xbf, 0x0c,
+ 0xcf, 0xdc, 0xdc, 0xd7, 0xcc, 0xc2, 0xba, 0xb4, 0xb0, 0xad, 0xac, 0xaa,
+ 0xaa, 0x9f, 0xa9, 0x0c, 0xaa, 0xaa, 0xac, 0xad, 0xb0, 0xb4, 0xba, 0xc2,
+ 0xcc, 0xd7, 0xdc, 0xdc, 0xcf, 0x82, 0xbf, 0x0b, 0xcd, 0xdb, 0xdc, 0xdc,
+ 0xd5, 0xcd, 0xc7, 0xc3, 0xbf, 0xbe, 0xbc, 0xbc, 0x9f, 0xbb, 0x0b, 0xbc,
+ 0xbc, 0xbe, 0xbf, 0xc3, 0xc7, 0xcc, 0xd5, 0xdc, 0xdc, 0xdb, 0xcd, 0x84,
+ 0xbf, 0x01, 0xc3, 0xd6, 0x80, 0xdc, 0x04, 0xdb, 0xd7, 0xd5, 0xd3, 0xd1,
+ 0xa1, 0xd0, 0x04, 0xd1, 0xd3, 0xd5, 0xd7, 0xdb, 0x80, 0xdc, 0x01, 0xd6,
+ 0xc4, 0x87, 0xbf, 0x02, 0xc9, 0xd2, 0xd6, 0xab, 0xdc, 0x02, 0xd6, 0xd2,
+ 0xc9, 0x83, 0xbf,
+};
+static EG_EMBEDDED_IMAGE egemb_back_selected_small = { 64, 64, EG_EIPIXELMODE_GRAY, EG_EICOMPMODE_RLE, egemb_back_selected_small_data, 1503 };
diff --git a/include/egemb_refind_banner.h b/include/egemb_refind_banner.h
new file mode 100644 (file)
index 0000000..7482cbc
--- /dev/null
@@ -0,0 +1,636 @@
+static const UINT8 egemb_refind_banner_data[7592] = {
+ 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0,
+ 0xff, 0xc0, 0xff, 0xc0, 0x8e, 0xc0, 0x08, 0xb2, 0x98, 0x83, 0x6e, 0x5a,
+ 0x45, 0x30, 0x1b, 0x39, 0xa8, 0xc0, 0x00, 0x26, 0x8c, 0x00, 0x00, 0x49,
+ 0x81, 0xc0, 0x00, 0x53, 0x8c, 0x00, 0x03, 0x0d, 0xc0, 0xa1, 0x02, 0x84,
+ 0x00, 0x00, 0x13, 0x9f, 0xc0, 0x01, 0x6e, 0x0b, 0x83, 0x00, 0x00, 0x5a,
+ 0xa8, 0xc0, 0x01, 0xb9, 0x1d, 0x8b, 0x00, 0x00, 0x41, 0x81, 0xc0, 0x01,
+ 0xbf, 0x45, 0x8b, 0x00, 0x03, 0x04, 0xc0, 0xc0, 0x90, 0x83, 0x00, 0x01,
+ 0x41, 0xb5, 0xa0, 0xc0, 0x01, 0xb9, 0x15, 0x82, 0x00, 0x00, 0x82, 0xa9,
+ 0xc0, 0x00, 0x4e, 0x82, 0x00, 0x09, 0x11, 0x80, 0xa6, 0xa6, 0x91, 0x70,
+ 0x22, 0x00, 0x00, 0x38, 0x82, 0xc0, 0x00, 0x7b, 0x82, 0x00, 0x0d, 0x0b,
+ 0x75, 0xa0, 0xab, 0x9a, 0x82, 0x41, 0x04, 0x00, 0x00, 0xbb, 0xc0, 0xbe,
+ 0x07, 0x82, 0x00, 0x00, 0xa3, 0xa2, 0xc0, 0x00, 0x15, 0x82, 0x00, 0x00,
+ 0xaa, 0xa9, 0xc0, 0x00, 0x38, 0x82, 0x00, 0x00, 0x73, 0x82, 0xc0, 0x03,
+ 0xbf, 0x66, 0x00, 0x2f, 0x82, 0xc0, 0x00, 0x65, 0x82, 0x00, 0x00, 0x56,
+ 0x83, 0xc0, 0x05, 0x9d, 0x11, 0x00, 0xb2, 0xc0, 0xb2, 0x82, 0x00, 0x00,
+ 0x1d, 0xa2, 0xc0, 0x00, 0xad, 0x82, 0x00, 0x01, 0x11, 0xbf, 0xa9, 0xc0,
+ 0x00, 0x14, 0x82, 0x00, 0x00, 0xac, 0x80, 0xc0, 0x05, 0xb4, 0x04, 0xc0,
+ 0xc0, 0x48, 0x26, 0x82, 0xc0, 0x00, 0x40, 0x82, 0x00, 0x00, 0x84, 0x80,
+ 0xc0, 0x08, 0xb1, 0x0b, 0xc0, 0xc0, 0x91, 0x00, 0xa9, 0xc0, 0x8e, 0x82,
+ 0x00, 0x00, 0x47, 0xa2, 0xc0, 0x00, 0x85, 0x82, 0x00, 0x00, 0x3a, 0x98,
+ 0xc0, 0x11, 0xb3, 0x95, 0x7a, 0x60, 0x45, 0x2a, 0x0f, 0x66, 0xc0, 0xc0,
+ 0xa4, 0x58, 0x20, 0x0b, 0x69, 0xc0, 0xc0, 0xac, 0x82, 0x00, 0x00, 0x1a,
+ 0x80, 0xc0, 0x06, 0xb2, 0x46, 0x00, 0xc0, 0xc0, 0x97, 0x1d, 0x82, 0xc0,
+ 0x00, 0x18, 0x82, 0x00, 0x0c, 0xb0, 0xc0, 0xc0, 0xb7, 0x54, 0x00, 0xc0,
+ 0xc0, 0xbf, 0x3d, 0xa6, 0xc0, 0x67, 0x82, 0x00, 0x14, 0x6d, 0xc0, 0xc0,
+ 0xaf, 0x91, 0x77, 0x5d, 0x42, 0x28, 0x0e, 0x91, 0xc0, 0xc0, 0xb4, 0x70,
+ 0x34, 0x15, 0x05, 0x17, 0x53, 0xb5, 0x87, 0xc0, 0x04, 0x9d, 0x60, 0x2e,
+ 0x16, 0x08, 0x85, 0x00, 0x00, 0x63, 0x98, 0xc0, 0x00, 0x68, 0x83, 0x00,
+ 0x0a, 0x16, 0xc0, 0x6f, 0x05, 0x00, 0x00, 0x09, 0xb5, 0xc0, 0xc0, 0x85,
+ 0x82, 0x00, 0x0a, 0x08, 0x1d, 0x1d, 0x14, 0x02, 0x00, 0x00, 0xc0, 0xc0,
+ 0xbf, 0xa6, 0x81, 0xc0, 0x00, 0xb1, 0x82, 0x00, 0x06, 0x01, 0x1d, 0x1d,
+ 0x15, 0x04, 0x00, 0x00, 0x83, 0xc0, 0x00, 0x41, 0x82, 0x00, 0x03, 0x93,
+ 0xc0, 0xc0, 0x51, 0x83, 0x00, 0x03, 0x5d, 0xbe, 0x6d, 0x0e, 0x83, 0x00,
+ 0x00, 0x4a, 0x85, 0xc0, 0x01, 0xa7, 0x3c, 0x8a, 0x00, 0x00, 0x8b, 0x99,
+ 0xc0, 0x00, 0x87, 0x82, 0x00, 0x01, 0x05, 0x6e, 0x81, 0x00, 0x00, 0x54,
+ 0x80, 0xc0, 0x00, 0x5e, 0x89, 0x00, 0x85, 0xc0, 0x00, 0x8a, 0x89, 0x00,
+ 0x83, 0xc0, 0x00, 0x1a, 0x81, 0x00, 0x01, 0x01, 0xb7, 0x80, 0xc0, 0x00,
+ 0x68, 0x82, 0x00, 0x01, 0x42, 0x39, 0x85, 0x00, 0x00, 0x0f, 0x84, 0xc0,
+ 0x01, 0x8f, 0x0e, 0x84, 0x00, 0x01, 0x12, 0x02, 0x82, 0x00, 0x00, 0xb2,
+ 0x99, 0xc0, 0x00, 0xb8, 0x82, 0x00, 0x06, 0x02, 0x02, 0x0e, 0x31, 0x14,
+ 0x02, 0xa7, 0x80, 0xc0, 0x00, 0x36, 0x89, 0x00, 0x85, 0xc0, 0x00, 0x63,
+ 0x89, 0x00, 0x82, 0xc0, 0x00, 0xb4, 0x82, 0x00, 0x00, 0x1f, 0x81, 0xc0,
+ 0x00, 0x8b, 0x84, 0x00, 0x02, 0x2c, 0x62, 0x3a, 0x82, 0x00, 0x00, 0x12,
+ 0x83, 0xc0, 0x01, 0x99, 0x06, 0x82, 0x00, 0x04, 0x1b, 0x84, 0xb2, 0xb5,
+ 0x01, 0x81, 0x00, 0x00, 0x1a, 0x9a, 0xc0, 0x00, 0xa2, 0x83, 0x00, 0x04,
+ 0x38, 0xb8, 0xc0, 0xbd, 0x8a, 0x80, 0xc0, 0x01, 0xbf, 0x0f, 0x82, 0x00,
+ 0x06, 0x91, 0xb5, 0xb6, 0x9e, 0x58, 0x02, 0x00, 0x85, 0xc0, 0x00, 0x3b,
+ 0x82, 0x00, 0x06, 0x6d, 0xb3, 0xb8, 0x9f, 0x54, 0x00, 0x00, 0x82, 0xc0,
+ 0x00, 0x8e, 0x82, 0x00, 0x00, 0x45, 0x81, 0xc0, 0x00, 0x72, 0x83, 0x00,
+ 0x03, 0x4c, 0xbe, 0xc0, 0xb2, 0x82, 0x00, 0x00, 0x35, 0x82, 0xc0, 0x01,
+ 0xb2, 0x14, 0x82, 0x00, 0x04, 0x4e, 0xba, 0xc0, 0xc0, 0x8d, 0x82, 0x00,
+ 0x00, 0x42, 0x9a, 0xc0, 0x00, 0x7b, 0x82, 0x00, 0x01, 0x07, 0xaf, 0x84,
+ 0xc0, 0x00, 0xa8, 0x82, 0x00, 0x01, 0x0d, 0xbf, 0x81, 0xc0, 0x01, 0x6c,
+ 0x00, 0x85, 0xc0, 0x00, 0x14, 0x82, 0x00, 0x00, 0xa3, 0x81, 0xc0, 0x01,
+ 0x57, 0x00, 0x82, 0xc0, 0x00, 0x68, 0x82, 0x00, 0x00, 0x6b, 0x81, 0xc0,
+ 0x00, 0x4e, 0x82, 0x00, 0x04, 0x16, 0xbb, 0xc0, 0xc0, 0xa7, 0x82, 0x00,
+ 0x00, 0x59, 0x82, 0xc0, 0x00, 0x54, 0x82, 0x00, 0x01, 0x3b, 0xbe, 0x80,
+ 0xc0, 0x00, 0x63, 0x82, 0x00, 0x00, 0x6b, 0x9a, 0xc0, 0x00, 0x52, 0x82,
+ 0x00, 0x00, 0x45, 0x85, 0xc0, 0x00, 0x81, 0x82, 0x00, 0x00, 0x35, 0x82,
+ 0xc0, 0x01, 0xb6, 0x04, 0x84, 0xc0, 0x00, 0xac, 0x82, 0x00, 0x01, 0x0b,
+ 0xbe, 0x81, 0xc0, 0x01, 0xa2, 0x00, 0x82, 0xc0, 0x00, 0x42, 0x82, 0x00,
+ 0x00, 0x91, 0x81, 0xc0, 0x00, 0x28, 0x82, 0x00, 0x00, 0x6f, 0x80, 0xc0,
+ 0x00, 0x78, 0x82, 0x00, 0x00, 0x8a, 0x81, 0xc0, 0x01, 0xab, 0x04, 0x81,
+ 0x00, 0x01, 0x08, 0xac, 0x81, 0xc0, 0x00, 0x3a, 0x82, 0x00, 0x00, 0x93,
+ 0x9a, 0xc0, 0x00, 0x29, 0x82, 0x00, 0x00, 0x79, 0x85, 0xc0, 0x00, 0x59,
+ 0x82, 0x00, 0x00, 0x5f, 0x83, 0xc0, 0x00, 0xbd, 0x84, 0xc0, 0x00, 0x85,
+ 0x82, 0x00, 0x00, 0x31, 0x82, 0xc0, 0x01, 0xbf, 0xa8, 0x82, 0xc0, 0x00,
+ 0x1a, 0x82, 0x00, 0x00, 0xb5, 0x80, 0xc0, 0x01, 0xbb, 0x05, 0x82, 0x00,
+ 0x00, 0xaf, 0x80, 0xc0, 0x00, 0x40, 0x81, 0x00, 0x01, 0x04, 0xb8, 0x81,
+ 0xc0, 0x00, 0x6b, 0x82, 0x00, 0x00, 0x51, 0x81, 0xc0, 0x01, 0xbf, 0x11,
+ 0x81, 0x00, 0x01, 0x02, 0xb8, 0x99, 0xc0, 0x01, 0xbb, 0x05, 0x82, 0x00,
+ 0x00, 0xa8, 0x85, 0xc0, 0x00, 0x32, 0x82, 0x00, 0x00, 0x88, 0x86, 0xc0,
+ 0x01, 0xa3, 0x4a, 0x80, 0xc0, 0x00, 0x5e, 0x82, 0x00, 0x00, 0x57, 0x88,
+ 0xc0, 0x00, 0xb4, 0x82, 0x00, 0x00, 0x1d, 0x81, 0xc0, 0x00, 0x9b, 0x82,
+ 0x00, 0x00, 0x25, 0x80, 0xc0, 0x01, 0xbc, 0x0b, 0x81, 0x00, 0x00, 0x2f,
+ 0x82, 0xc0, 0x00, 0x31, 0x82, 0x00, 0x00, 0x8f, 0x81, 0xc0, 0x00, 0xa8,
+ 0x82, 0x00, 0x00, 0x23, 0x9a, 0xc0, 0x00, 0x99, 0x82, 0x00, 0x01, 0x10,
+ 0xbf, 0x84, 0xc0, 0x01, 0xbe, 0x0b, 0x82, 0x00, 0x00, 0xaf, 0x85, 0xc0,
+ 0x02, 0xb3, 0x1d, 0x60, 0x80, 0xc0, 0x00, 0x36, 0x82, 0x00, 0x00, 0x7f,
+ 0x88, 0xc0, 0x00, 0x8e, 0x82, 0x00, 0x00, 0x43, 0x81, 0xc0, 0x00, 0x75,
+ 0x82, 0x00, 0x00, 0x57, 0x80, 0xc0, 0x00, 0x91, 0x82, 0x00, 0x00, 0x62,
+ 0x82, 0xc0, 0x00, 0x15, 0x82, 0x00, 0x00, 0xaf, 0x81, 0xc0, 0x00, 0x7f,
+ 0x82, 0x00, 0x00, 0x4b, 0x9a, 0xc0, 0x00, 0x6f, 0x82, 0x00, 0x00, 0x39,
+ 0x85, 0xc0, 0x00, 0xa3, 0x82, 0x00, 0x01, 0x0c, 0xbf, 0x84, 0xc0, 0x07,
+ 0xb8, 0x33, 0x08, 0xb2, 0xc0, 0xc0, 0xbf, 0x0f, 0x82, 0x00, 0x00, 0xa6,
+ 0x88, 0xc0, 0x00, 0x68, 0x82, 0x00, 0x00, 0x69, 0x81, 0xc0, 0x00, 0x4e,
+ 0x82, 0x00, 0x00, 0x81, 0x80, 0xc0, 0x00, 0x5a, 0x82, 0x00, 0x00, 0x8f,
+ 0x82, 0xc0, 0x00, 0x05, 0x82, 0x00, 0x00, 0xb7, 0x81, 0xc0, 0x00, 0x55,
+ 0x82, 0x00, 0x00, 0x73, 0x9a, 0xc0, 0x00, 0x47, 0x82, 0x00, 0x00, 0x62,
+ 0x85, 0xc0, 0x00, 0x7b, 0x82, 0x00, 0x00, 0x26, 0x84, 0xc0, 0x03, 0xa9,
+ 0x25, 0x00, 0x54, 0x80, 0xc0, 0x00, 0xa9, 0x82, 0x00, 0x01, 0x0c, 0xbf,
+ 0x88, 0xc0, 0x00, 0x42, 0x82, 0x00, 0x00, 0x8f, 0x81, 0xc0, 0x00, 0x28,
+ 0x82, 0x00, 0x00, 0xa9, 0x80, 0xc0, 0x00, 0x2b, 0x82, 0x00, 0x00, 0xb4,
+ 0x82, 0xc0, 0x00, 0x14, 0x82, 0x00, 0x00, 0x97, 0x81, 0xc0, 0x00, 0x2c,
+ 0x82, 0x00, 0x00, 0x9c, 0x9a, 0xc0, 0x00, 0x1e, 0x82, 0x00, 0x00, 0x8b,
+ 0x85, 0xc0, 0x00, 0x51, 0x82, 0x00, 0x01, 0x12, 0xbb, 0x81, 0xc0, 0x05,
+ 0xb8, 0x70, 0x10, 0x00, 0x03, 0xa9, 0x80, 0xc0, 0x00, 0x7f, 0x82, 0x00,
+ 0x00, 0x2f, 0x88, 0xc0, 0x01, 0xbf, 0x19, 0x82, 0x00, 0x00, 0xb2, 0x80,
+ 0xc0, 0x01, 0xbb, 0x05, 0x81, 0x00, 0x01, 0x12, 0xbf, 0x80, 0xc0, 0x00,
+ 0x0e, 0x82, 0x00, 0x01, 0x7b, 0xbd, 0x81, 0xc0, 0x00, 0x41, 0x82, 0x00,
+ 0x05, 0x3e, 0xbf, 0xc0, 0xc0, 0xaf, 0x04, 0x81, 0x00, 0x01, 0x06, 0xbc,
+ 0x99, 0xc0, 0x00, 0xb5, 0x83, 0x00, 0x00, 0xb3, 0x84, 0xc0, 0x01, 0xbf,
+ 0x16, 0x83, 0x00, 0x05, 0x2e, 0x71, 0x79, 0x63, 0x48, 0x0d, 0x80, 0x00,
+ 0x00, 0x46, 0x81, 0xc0, 0x00, 0x42, 0x82, 0x00, 0x00, 0x42, 0x88, 0xc0,
+ 0x00, 0x9f, 0x82, 0x00, 0x01, 0x07, 0xbf, 0x80, 0xc0, 0x00, 0x9b, 0x82,
+ 0x00, 0x00, 0x3b, 0x81, 0xc0, 0x00, 0x12, 0x83, 0x00, 0x06, 0x0b, 0x21,
+ 0xb2, 0xc0, 0xc0, 0x97, 0x02, 0x82, 0x00, 0x03, 0x42, 0x97, 0xa7, 0x49,
+ 0x82, 0x00, 0x00, 0x18, 0x9a, 0xc0, 0x00, 0x8e, 0x82, 0x00, 0x00, 0x1d,
+ 0x84, 0xc0, 0x01, 0xbd, 0x6c, 0x8d, 0x00, 0x05, 0x9f, 0xc0, 0xc0, 0xbf,
+ 0x8e, 0x07, 0x82, 0x00, 0x01, 0x13, 0xb6, 0x86, 0xc0, 0x01, 0xb6, 0x40,
+ 0x83, 0x00, 0x00, 0x91, 0x80, 0xc0, 0x00, 0x75, 0x82, 0x00, 0x00, 0x64,
+ 0x81, 0xc0, 0x00, 0x60, 0x82, 0x00, 0x02, 0x2f, 0x7e, 0xbb, 0x81, 0xc0,
+ 0x01, 0x75, 0x05, 0x8b, 0x00, 0x00, 0x88, 0x99, 0xc0, 0x00, 0x65, 0x82,
+ 0x00, 0x00, 0x45, 0x84, 0xc0, 0x00, 0x40, 0x8d, 0x00, 0x00, 0x38, 0x80,
+ 0xc0, 0x00, 0x6d, 0x85, 0x00, 0x00, 0x1a, 0x86, 0xc0, 0x00, 0x13, 0x84,
+ 0x00, 0x04, 0x02, 0xa1, 0xc0, 0xc0, 0x4e, 0x82, 0x00, 0x00, 0x8e, 0x81,
+ 0xc0, 0x05, 0xbe, 0x76, 0x29, 0x10, 0x52, 0xa0, 0x85, 0xc0, 0x05, 0xa4,
+ 0x5a, 0x2b, 0x11, 0x0a, 0x04, 0x87, 0x00, 0x00, 0x92, 0xff, 0xc0, 0xff,
+ 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff,
+ 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xd6, 0xc0, 0x09,
+ 0xc5, 0xd4, 0xe2, 0xec, 0xf6, 0xfd, 0xfe, 0xf8, 0xe7, 0xc6, 0x95, 0xc0,
+ 0x03, 0xce, 0xe7, 0xfa, 0xdd, 0x81, 0xc0, 0x01, 0xd4, 0xca, 0x80, 0xc0,
+ 0x01, 0xc1, 0xca, 0xd1, 0xc0, 0x01, 0xc2, 0xea, 0x86, 0xff, 0x00, 0xf1,
+ 0x92, 0xc0, 0x02, 0xcf, 0xdf, 0xef, 0x80, 0xff, 0x0c, 0xf9, 0xc0, 0xc0,
+ 0xc5, 0xed, 0xff, 0xed, 0xc0, 0xc0, 0xc5, 0xef, 0xfe, 0xcd, 0xd0, 0xc0,
+ 0x0b, 0xec, 0xff, 0xff, 0xef, 0xdf, 0xd3, 0xc9, 0xc4, 0xc1, 0xc5, 0xda,
+ 0xfb, 0x91, 0xc0, 0x13, 0xd5, 0xfe, 0xff, 0xff, 0xf9, 0xda, 0xc7, 0xf7,
+ 0xc0, 0xc7, 0xf6, 0xfa, 0xff, 0xe2, 0xc0, 0xcb, 0xf7, 0xff, 0xfe, 0xce,
+ 0xcf, 0xc0, 0x0c, 0xd2, 0xfe, 0xf3, 0xe4, 0xc5, 0xc0, 0xcb, 0xe7, 0xca,
+ 0xc0, 0xc0, 0xd1, 0xdc, 0x8b, 0xc0, 0x02, 0xc5, 0xe6, 0xcb, 0x80, 0xc0,
+ 0x12, 0xf1, 0xff, 0xfd, 0xe0, 0xc2, 0xc0, 0xd2, 0xe6, 0xc6, 0xf6, 0xd7,
+ 0xe0, 0xfe, 0xc7, 0xd0, 0xfc, 0xff, 0xff, 0xd6, 0xbc, 0xc0, 0x02, 0xc5,
+ 0xe6, 0xcb, 0x93, 0xc0, 0x06, 0xcf, 0xf4, 0xd1, 0xd2, 0xde, 0xe6, 0xd5,
+ 0x8c, 0xc0, 0x01, 0xef, 0xed, 0x81, 0xc0, 0x02, 0xf8, 0xe5, 0xc6, 0x80,
+ 0xc0, 0x0b, 0xef, 0xd1, 0xf3, 0xd8, 0xc4, 0xfa, 0xe3, 0xcf, 0xfc, 0xe6,
+ 0xfc, 0xdf, 0xbd, 0xc0, 0x01, 0xef, 0xed, 0x93, 0xc0, 0x05, 0xc9, 0xfb,
+ 0xf8, 0xef, 0xe1, 0xcf, 0x8b, 0xc0, 0x05, 0xdf, 0xfa, 0xff, 0xff, 0xf9,
+ 0xc5, 0x85, 0xc0, 0x0b, 0xd4, 0xf3, 0xeb, 0xe0, 0xc0, 0xe7, 0xfb, 0xd0,
+ 0xfb, 0xda, 0xea, 0xec, 0xbb, 0xc0, 0x05, 0xdf, 0xfa, 0xff, 0xff, 0xf9,
+ 0xc5, 0x8f, 0xc0, 0x06, 0xcc, 0xf4, 0xfa, 0xfe, 0xe8, 0xcd, 0xc2, 0x82,
+ 0xc0, 0x0f, 0xcf, 0xef, 0xfd, 0xde, 0xc0, 0xc0, 0xcf, 0xef, 0xfd, 0xde,
+ 0xd6, 0xfb, 0xfd, 0xff, 0xff, 0xd8, 0x85, 0xc0, 0x0c, 0xc3, 0xf8, 0xf7,
+ 0xec, 0xc0, 0xd0, 0xff, 0xe4, 0xf8, 0xd8, 0xdd, 0xfa, 0xc5, 0x80, 0xc0,
+ 0x0b, 0xce, 0xea, 0xfb, 0xd7, 0xc0, 0xc0, 0xc3, 0xda, 0xc1, 0xc0, 0xde,
+ 0xf3, 0x80, 0xc0, 0x03, 0xce, 0xea, 0xfb, 0xd7, 0x80, 0xc0, 0x03, 0xc1,
+ 0xd8, 0xf3, 0xf2, 0x81, 0xc0, 0x03, 0xc7, 0xe7, 0xfb, 0xf4, 0x89, 0xc0,
+ 0x11, 0xc7, 0xe7, 0xfb, 0xf4, 0xc0, 0xc0, 0xc3, 0xda, 0xc1, 0xc0, 0xde,
+ 0xf3, 0xd6, 0xfb, 0xfd, 0xff, 0xff, 0xd8, 0x91, 0xc0, 0x00, 0xd2, 0x81,
+ 0xff, 0x14, 0xfe, 0xee, 0xd7, 0xc1, 0xc0, 0xda, 0xfe, 0xf3, 0xe3, 0xf5,
+ 0xc0, 0xda, 0xfe, 0xf3, 0xe3, 0xf5, 0xc2, 0xc7, 0xf8, 0xd3, 0xc4, 0x86,
+ 0xc0, 0x4e, 0xe5, 0xff, 0xf8, 0xc4, 0xc4, 0xf7, 0xfb, 0xf6, 0xda, 0xce,
+ 0xfe, 0xd8, 0xc0, 0xc0, 0xc3, 0xe8, 0xf8, 0xdf, 0xfa, 0xc9, 0xc0, 0xc0,
+ 0xec, 0xe9, 0xc1, 0xe7, 0xff, 0xef, 0xc0, 0xc3, 0xe8, 0xf8, 0xdf, 0xfa,
+ 0xc9, 0xc0, 0xc0, 0xc6, 0xf0, 0xff, 0xf2, 0xdc, 0xf6, 0xc0, 0xc0, 0xd2,
+ 0xfb, 0xe5, 0xd4, 0xec, 0xc0, 0xc4, 0xe0, 0xe0, 0xc2, 0xe4, 0xfa, 0xcb,
+ 0xc0, 0xcf, 0xe1, 0xd2, 0xfb, 0xe5, 0xd4, 0xec, 0xc0, 0xc0, 0xec, 0xe9,
+ 0xc1, 0xe7, 0xff, 0xef, 0xc2, 0xc7, 0xf8, 0xd3, 0xc4, 0x91, 0xc0, 0x18,
+ 0xc3, 0xf8, 0xfb, 0xce, 0xc6, 0xcf, 0xdb, 0xf0, 0xff, 0xea, 0xd2, 0xff,
+ 0xe3, 0xc1, 0xec, 0xfc, 0xd2, 0xff, 0xe3, 0xc1, 0xec, 0xfc, 0xc6, 0xf5,
+ 0xea, 0x87, 0xc0, 0x4d, 0xd1, 0xff, 0xfe, 0xd0, 0xc0, 0xe9, 0xff, 0xff,
+ 0xde, 0xc1, 0xf5, 0xf5, 0xc0, 0xc0, 0xc6, 0xf3, 0xdf, 0xc2, 0xec, 0xfa,
+ 0xc7, 0xc0, 0xd4, 0xf9, 0xc4, 0xe7, 0xf0, 0xfd, 0xc8, 0xc6, 0xf3, 0xdf,
+ 0xc2, 0xec, 0xfa, 0xc7, 0xc0, 0xc5, 0xf6, 0xfb, 0xd9, 0xc6, 0xfa, 0xf2,
+ 0xc0, 0xcf, 0xfe, 0xe1, 0xd5, 0xe2, 0xc3, 0xc9, 0xf7, 0xf8, 0xd6, 0xf2,
+ 0xff, 0xfc, 0xc4, 0xd5, 0xfe, 0xff, 0xfe, 0xe1, 0xd5, 0xe2, 0xc3, 0xc0,
+ 0xd4, 0xf9, 0xc4, 0xe7, 0xf0, 0xfd, 0xc8, 0xc6, 0xf5, 0xea, 0x93, 0xc0,
+ 0x02, 0xe2, 0xff, 0xd0, 0x81, 0xc0, 0x14, 0xca, 0xff, 0xfb, 0xf4, 0xe5,
+ 0xc0, 0xc0, 0xf9, 0xee, 0xf4, 0xe5, 0xc0, 0xc0, 0xf9, 0xf5, 0xeb, 0xff,
+ 0xcd, 0xc0, 0xcb, 0xc4, 0x83, 0xc0, 0x51, 0xc4, 0xf8, 0xff, 0xe3, 0xc0,
+ 0xd8, 0xff, 0xff, 0xe4, 0xc0, 0xd9, 0xff, 0xda, 0xc0, 0xc0, 0xee, 0xd6,
+ 0xc0, 0xe3, 0xfd, 0xd1, 0xc0, 0xca, 0xf3, 0xd9, 0xde, 0xe5, 0xf6, 0xe3,
+ 0xc0, 0xee, 0xd6, 0xc0, 0xe3, 0xfd, 0xd1, 0xc0, 0xca, 0xe9, 0xfa, 0xca,
+ 0xc0, 0xee, 0xff, 0xdc, 0xc0, 0xf1, 0xff, 0xe0, 0xca, 0xc0, 0xd4, 0xef,
+ 0xf1, 0xcb, 0xf6, 0xd9, 0xf2, 0xde, 0xda, 0xef, 0xfa, 0xfc, 0xff, 0xe0,
+ 0xca, 0xc0, 0xd4, 0xc4, 0xf3, 0xd9, 0xde, 0xe5, 0xf6, 0xe3, 0xc7, 0xeb,
+ 0xff, 0xcd, 0xc0, 0xcb, 0xc4, 0x90, 0xc0, 0x1b, 0xf9, 0xff, 0xd7, 0xc2,
+ 0xc3, 0xcd, 0xe0, 0xfb, 0xff, 0xdb, 0xfd, 0xcb, 0xc0, 0xc0, 0xfc, 0xdf,
+ 0xff, 0xcb, 0xc0, 0xc0, 0xfc, 0xdf, 0xff, 0xff, 0xc8, 0xda, 0xeb, 0xc1,
+ 0x83, 0xc0, 0x51, 0xea, 0xff, 0xf6, 0xc2, 0xc4, 0xfc, 0xff, 0xec, 0xc0,
+ 0xc0, 0xf0, 0xff, 0xc7, 0xc0, 0xc2, 0xff, 0xd2, 0xe7, 0xed, 0xf2, 0xd6,
+ 0xe3, 0xe0, 0xfe, 0xd7, 0xed, 0xdd, 0xff, 0xc9, 0xca, 0xff, 0xc9, 0xe7,
+ 0xed, 0xf2, 0xd6, 0xe3, 0xe0, 0xfc, 0xd3, 0xc0, 0xe5, 0xfb, 0xfd, 0xc4,
+ 0xc7, 0xfd, 0xff, 0xcd, 0xc7, 0xe4, 0xe8, 0xfb, 0xd4, 0xf8, 0xd7, 0xce,
+ 0xf4, 0xe2, 0xd7, 0xfd, 0xcf, 0xfd, 0xff, 0xcd, 0xc7, 0xe4, 0xe8, 0xc0,
+ 0xfe, 0xd7, 0xed, 0xdd, 0xff, 0xc9, 0xcb, 0xfc, 0xff, 0xc8, 0xda, 0xeb,
+ 0xc1, 0x90, 0xc0, 0x00, 0xf6, 0x83, 0xff, 0x0e, 0xf7, 0xd4, 0xc0, 0xef,
+ 0xcb, 0xc5, 0xde, 0xf3, 0xe3, 0xf4, 0xcb, 0xc5, 0xde, 0xf3, 0xe3, 0x80,
+ 0xff, 0x01, 0xec, 0xc2, 0x84, 0xc0, 0x2e, 0xf8, 0xff, 0xd0, 0xc0, 0xd0,
+ 0xff, 0xf2, 0xc2, 0xc0, 0xc0, 0xfc, 0xff, 0xc9, 0xd1, 0xf4, 0xff, 0xff,
+ 0xf8, 0xc5, 0xfb, 0xff, 0xea, 0xc0, 0xfa, 0xfb, 0xc6, 0xf6, 0xff, 0xdc,
+ 0xec, 0xf8, 0xff, 0xf8, 0xc5, 0xfb, 0xff, 0xea, 0xc0, 0xf6, 0xc8, 0xe5,
+ 0xf3, 0xe5, 0xe9, 0xe1, 0xd5, 0xf6, 0x80, 0xff, 0x0b, 0xec, 0xc2, 0xfb,
+ 0xff, 0xdc, 0xc0, 0xec, 0xf6, 0xd1, 0xea, 0xff, 0xd9, 0x81, 0xff, 0x09,
+ 0xec, 0xc2, 0xc0, 0xfa, 0xfb, 0xc6, 0xf6, 0xff, 0xdc, 0xec, 0x80, 0xff,
+ 0x01, 0xec, 0xc2, 0x91, 0xc0, 0x06, 0xcb, 0xed, 0xfb, 0xfe, 0xf7, 0xe8,
+ 0xd2, 0x80, 0xc0, 0x0e, 0xc9, 0xf3, 0xfc, 0xe5, 0xc3, 0xc0, 0xc9, 0xf3,
+ 0xfc, 0xe5, 0xc3, 0xc0, 0xed, 0xf9, 0xdd, 0x86, 0xc0, 0x06, 0xe3, 0xe9,
+ 0xc0, 0xc0, 0xc6, 0xf4, 0xc6, 0x80, 0xc0, 0x44, 0xfa, 0xff, 0xff, 0xfa,
+ 0xcf, 0xd3, 0xf7, 0xcb, 0xc0, 0xfd, 0xeb, 0xc1, 0xc0, 0xe7, 0xd6, 0xc0,
+ 0xfd, 0xff, 0xe7, 0xc2, 0xd3, 0xf7, 0xcb, 0xc0, 0xfd, 0xeb, 0xc1, 0xc0,
+ 0xd8, 0xfb, 0xe3, 0xc6, 0xfb, 0xf2, 0xca, 0xc0, 0xd3, 0xf9, 0xf8, 0xdf,
+ 0xc1, 0xc0, 0xe3, 0xe7, 0xc0, 0xc0, 0xfb, 0xd8, 0xc0, 0xfb, 0xff, 0xeb,
+ 0xd9, 0xf9, 0xf8, 0xdf, 0xc1, 0xc0, 0xc0, 0xe7, 0xd6, 0xc0, 0xfd, 0xff,
+ 0xe7, 0xc2, 0xed, 0xf9, 0xdd, 0xb5, 0xc0, 0x01, 0xc1, 0xc1, 0x85, 0xc0,
+ 0x03, 0xdb, 0xfb, 0xea, 0xc7, 0x82, 0xc0, 0x00, 0xcb, 0x83, 0xc0, 0x01,
+ 0xd3, 0xcf, 0x83, 0xc0, 0x00, 0xcb, 0x82, 0xc0, 0x03, 0xc1, 0xe9, 0xe8,
+ 0xc2, 0x89, 0xc0, 0x04, 0xc2, 0xc0, 0xc0, 0xcf, 0xcc, 0x88, 0xc0, 0x01,
+ 0xd3, 0xcf, 0xe1, 0xc0, 0x03, 0xc4, 0xf0, 0xf5, 0xc1, 0xff, 0xc0, 0x03,
+ 0xc1, 0xf1, 0xfe, 0xcd, 0xff, 0xc0, 0x03, 0xc0, 0xde, 0xff, 0xd8, 0xff,
+ 0xc0, 0x03, 0xc0, 0xc0, 0xef, 0xd7, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0,
+ 0xff, 0xc0, 0xff, 0xc0, 0xc8, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0,
+ 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0x8e, 0xc0,
+ 0x08, 0xb2, 0x98, 0x83, 0x6e, 0x5a, 0x45, 0x30, 0x1b, 0x39, 0xa8, 0xc0,
+ 0x00, 0x26, 0x8c, 0x00, 0x00, 0x49, 0x81, 0xc0, 0x00, 0x53, 0x8c, 0x00,
+ 0x03, 0x0d, 0xc0, 0xa1, 0x02, 0x84, 0x00, 0x00, 0x13, 0x9f, 0xc0, 0x01,
+ 0x6e, 0x0b, 0x83, 0x00, 0x00, 0x5a, 0xa8, 0xc0, 0x01, 0xb9, 0x1d, 0x8b,
+ 0x00, 0x00, 0x41, 0x81, 0xc0, 0x01, 0xbf, 0x45, 0x8b, 0x00, 0x03, 0x04,
+ 0xc0, 0xc0, 0x90, 0x83, 0x00, 0x01, 0x41, 0xb5, 0xa0, 0xc0, 0x01, 0xb9,
+ 0x15, 0x82, 0x00, 0x00, 0x82, 0xa9, 0xc0, 0x00, 0x4e, 0x82, 0x00, 0x09,
+ 0x11, 0x80, 0xa6, 0xa6, 0x91, 0x70, 0x22, 0x00, 0x00, 0x38, 0x82, 0xc0,
+ 0x00, 0x7b, 0x82, 0x00, 0x0d, 0x0b, 0x75, 0xa0, 0xab, 0x9a, 0x82, 0x41,
+ 0x04, 0x00, 0x00, 0xbb, 0xc0, 0xbe, 0x07, 0x82, 0x00, 0x00, 0xa3, 0xa2,
+ 0xc0, 0x00, 0x15, 0x82, 0x00, 0x00, 0xaa, 0xa9, 0xc0, 0x00, 0x38, 0x82,
+ 0x00, 0x00, 0x73, 0x82, 0xc0, 0x03, 0xbf, 0x66, 0x00, 0x2f, 0x82, 0xc0,
+ 0x00, 0x65, 0x82, 0x00, 0x00, 0x56, 0x83, 0xc0, 0x05, 0x9d, 0x11, 0x00,
+ 0xb2, 0xc0, 0xb2, 0x82, 0x00, 0x00, 0x1d, 0xa2, 0xc0, 0x00, 0xad, 0x82,
+ 0x00, 0x01, 0x11, 0xbf, 0xa9, 0xc0, 0x00, 0x14, 0x82, 0x00, 0x00, 0xac,
+ 0x80, 0xc0, 0x05, 0xb4, 0x04, 0xc0, 0xc0, 0x48, 0x26, 0x82, 0xc0, 0x00,
+ 0x40, 0x82, 0x00, 0x00, 0x84, 0x80, 0xc0, 0x08, 0xb1, 0x0b, 0xc0, 0xc0,
+ 0x91, 0x00, 0xa9, 0xc0, 0x8e, 0x82, 0x00, 0x00, 0x47, 0xa2, 0xc0, 0x00,
+ 0x85, 0x82, 0x00, 0x00, 0x3a, 0x98, 0xc0, 0x11, 0xb3, 0x95, 0x7a, 0x60,
+ 0x45, 0x2a, 0x0f, 0x66, 0xc0, 0xc0, 0xa4, 0x58, 0x20, 0x0b, 0x69, 0xc0,
+ 0xc0, 0xac, 0x82, 0x00, 0x00, 0x1a, 0x80, 0xc0, 0x06, 0xb2, 0x46, 0x00,
+ 0xc0, 0xc0, 0x97, 0x1d, 0x82, 0xc0, 0x00, 0x18, 0x82, 0x00, 0x0c, 0xb0,
+ 0xc0, 0xc0, 0xb7, 0x54, 0x00, 0xc0, 0xc0, 0xbf, 0x3d, 0xa6, 0xc0, 0x67,
+ 0x82, 0x00, 0x14, 0x6d, 0xc0, 0xc0, 0xaf, 0x91, 0x77, 0x5d, 0x42, 0x28,
+ 0x0e, 0x91, 0xc0, 0xc0, 0xb4, 0x70, 0x34, 0x15, 0x05, 0x17, 0x53, 0xb5,
+ 0x87, 0xc0, 0x04, 0x9d, 0x60, 0x2e, 0x16, 0x08, 0x85, 0x00, 0x00, 0x63,
+ 0x98, 0xc0, 0x00, 0x68, 0x83, 0x00, 0x0a, 0x16, 0xc0, 0x6f, 0x05, 0x00,
+ 0x00, 0x09, 0xb5, 0xc0, 0xc0, 0x85, 0x82, 0x00, 0x0a, 0x08, 0x1d, 0x1d,
+ 0x14, 0x02, 0x00, 0x00, 0xc0, 0xc0, 0xbf, 0xa6, 0x81, 0xc0, 0x00, 0xb1,
+ 0x82, 0x00, 0x06, 0x01, 0x1d, 0x1d, 0x15, 0x04, 0x00, 0x00, 0x83, 0xc0,
+ 0x00, 0x41, 0x82, 0x00, 0x03, 0x93, 0xc0, 0xc0, 0x51, 0x83, 0x00, 0x03,
+ 0x5d, 0xbe, 0x6d, 0x0e, 0x83, 0x00, 0x00, 0x4a, 0x85, 0xc0, 0x01, 0xa7,
+ 0x3c, 0x8a, 0x00, 0x00, 0x8b, 0x99, 0xc0, 0x00, 0x87, 0x82, 0x00, 0x01,
+ 0x05, 0x6e, 0x81, 0x00, 0x00, 0x54, 0x80, 0xc0, 0x00, 0x5e, 0x89, 0x00,
+ 0x85, 0xc0, 0x00, 0x8a, 0x89, 0x00, 0x83, 0xc0, 0x00, 0x1a, 0x81, 0x00,
+ 0x01, 0x01, 0xb7, 0x80, 0xc0, 0x00, 0x68, 0x82, 0x00, 0x01, 0x42, 0x39,
+ 0x85, 0x00, 0x00, 0x0f, 0x84, 0xc0, 0x01, 0x8f, 0x0e, 0x84, 0x00, 0x01,
+ 0x12, 0x02, 0x82, 0x00, 0x00, 0xb2, 0x99, 0xc0, 0x00, 0xb8, 0x82, 0x00,
+ 0x06, 0x02, 0x02, 0x0e, 0x31, 0x14, 0x02, 0xa7, 0x80, 0xc0, 0x00, 0x36,
+ 0x89, 0x00, 0x85, 0xc0, 0x00, 0x63, 0x89, 0x00, 0x82, 0xc0, 0x00, 0xb4,
+ 0x82, 0x00, 0x00, 0x1f, 0x81, 0xc0, 0x00, 0x8b, 0x84, 0x00, 0x02, 0x2c,
+ 0x62, 0x3a, 0x82, 0x00, 0x00, 0x12, 0x83, 0xc0, 0x01, 0x99, 0x06, 0x82,
+ 0x00, 0x04, 0x1b, 0x84, 0xb2, 0xb5, 0x01, 0x81, 0x00, 0x00, 0x1a, 0x9a,
+ 0xc0, 0x00, 0xa2, 0x83, 0x00, 0x04, 0x38, 0xb8, 0xc0, 0xbd, 0x8a, 0x80,
+ 0xc0, 0x01, 0xbf, 0x0f, 0x82, 0x00, 0x06, 0x91, 0xb5, 0xb6, 0x9e, 0x58,
+ 0x02, 0x00, 0x85, 0xc0, 0x00, 0x3b, 0x82, 0x00, 0x06, 0x6d, 0xb3, 0xb8,
+ 0x9f, 0x54, 0x00, 0x00, 0x82, 0xc0, 0x00, 0x8e, 0x82, 0x00, 0x00, 0x45,
+ 0x81, 0xc0, 0x00, 0x72, 0x83, 0x00, 0x03, 0x4c, 0xbe, 0xc0, 0xb2, 0x82,
+ 0x00, 0x00, 0x35, 0x82, 0xc0, 0x01, 0xb2, 0x14, 0x82, 0x00, 0x04, 0x4e,
+ 0xba, 0xc0, 0xc0, 0x8d, 0x82, 0x00, 0x00, 0x42, 0x9a, 0xc0, 0x00, 0x7b,
+ 0x82, 0x00, 0x01, 0x07, 0xaf, 0x84, 0xc0, 0x00, 0xa8, 0x82, 0x00, 0x01,
+ 0x0d, 0xbf, 0x81, 0xc0, 0x01, 0x6c, 0x00, 0x85, 0xc0, 0x00, 0x14, 0x82,
+ 0x00, 0x00, 0xa3, 0x81, 0xc0, 0x01, 0x57, 0x00, 0x82, 0xc0, 0x00, 0x68,
+ 0x82, 0x00, 0x00, 0x6b, 0x81, 0xc0, 0x00, 0x4e, 0x82, 0x00, 0x04, 0x16,
+ 0xbb, 0xc0, 0xc0, 0xa7, 0x82, 0x00, 0x00, 0x59, 0x82, 0xc0, 0x00, 0x54,
+ 0x82, 0x00, 0x01, 0x3b, 0xbe, 0x80, 0xc0, 0x00, 0x63, 0x82, 0x00, 0x00,
+ 0x6b, 0x9a, 0xc0, 0x00, 0x52, 0x82, 0x00, 0x00, 0x45, 0x85, 0xc0, 0x00,
+ 0x81, 0x82, 0x00, 0x00, 0x35, 0x82, 0xc0, 0x01, 0xb6, 0x04, 0x84, 0xc0,
+ 0x00, 0xac, 0x82, 0x00, 0x01, 0x0b, 0xbe, 0x81, 0xc0, 0x01, 0xa2, 0x00,
+ 0x82, 0xc0, 0x00, 0x42, 0x82, 0x00, 0x00, 0x91, 0x81, 0xc0, 0x00, 0x28,
+ 0x82, 0x00, 0x00, 0x6f, 0x80, 0xc0, 0x00, 0x78, 0x82, 0x00, 0x00, 0x8a,
+ 0x81, 0xc0, 0x01, 0xab, 0x04, 0x81, 0x00, 0x01, 0x08, 0xac, 0x81, 0xc0,
+ 0x00, 0x3a, 0x82, 0x00, 0x00, 0x93, 0x9a, 0xc0, 0x00, 0x29, 0x82, 0x00,
+ 0x00, 0x79, 0x85, 0xc0, 0x00, 0x59, 0x82, 0x00, 0x00, 0x5f, 0x83, 0xc0,
+ 0x00, 0xbd, 0x84, 0xc0, 0x00, 0x85, 0x82, 0x00, 0x00, 0x31, 0x82, 0xc0,
+ 0x01, 0xbf, 0xa8, 0x82, 0xc0, 0x00, 0x1a, 0x82, 0x00, 0x00, 0xb5, 0x80,
+ 0xc0, 0x01, 0xbb, 0x05, 0x82, 0x00, 0x00, 0xaf, 0x80, 0xc0, 0x00, 0x40,
+ 0x81, 0x00, 0x01, 0x04, 0xb8, 0x81, 0xc0, 0x00, 0x6b, 0x82, 0x00, 0x00,
+ 0x51, 0x81, 0xc0, 0x01, 0xbf, 0x11, 0x81, 0x00, 0x01, 0x02, 0xb8, 0x99,
+ 0xc0, 0x01, 0xbb, 0x05, 0x82, 0x00, 0x00, 0xa8, 0x85, 0xc0, 0x00, 0x32,
+ 0x82, 0x00, 0x00, 0x88, 0x86, 0xc0, 0x01, 0xa3, 0x4a, 0x80, 0xc0, 0x00,
+ 0x5e, 0x82, 0x00, 0x00, 0x57, 0x88, 0xc0, 0x00, 0xb4, 0x82, 0x00, 0x00,
+ 0x1d, 0x81, 0xc0, 0x00, 0x9b, 0x82, 0x00, 0x00, 0x25, 0x80, 0xc0, 0x01,
+ 0xbc, 0x0b, 0x81, 0x00, 0x00, 0x2f, 0x82, 0xc0, 0x00, 0x31, 0x82, 0x00,
+ 0x00, 0x8f, 0x81, 0xc0, 0x00, 0xa8, 0x82, 0x00, 0x00, 0x23, 0x9a, 0xc0,
+ 0x00, 0x99, 0x82, 0x00, 0x01, 0x10, 0xbf, 0x84, 0xc0, 0x01, 0xbe, 0x0b,
+ 0x82, 0x00, 0x00, 0xaf, 0x85, 0xc0, 0x02, 0xb3, 0x1d, 0x60, 0x80, 0xc0,
+ 0x00, 0x36, 0x82, 0x00, 0x00, 0x7f, 0x88, 0xc0, 0x00, 0x8e, 0x82, 0x00,
+ 0x00, 0x43, 0x81, 0xc0, 0x00, 0x75, 0x82, 0x00, 0x00, 0x57, 0x80, 0xc0,
+ 0x00, 0x91, 0x82, 0x00, 0x00, 0x62, 0x82, 0xc0, 0x00, 0x15, 0x82, 0x00,
+ 0x00, 0xaf, 0x81, 0xc0, 0x00, 0x7f, 0x82, 0x00, 0x00, 0x4b, 0x9a, 0xc0,
+ 0x00, 0x6f, 0x82, 0x00, 0x00, 0x39, 0x85, 0xc0, 0x00, 0xa3, 0x82, 0x00,
+ 0x01, 0x0c, 0xbf, 0x84, 0xc0, 0x07, 0xb8, 0x33, 0x08, 0xb2, 0xc0, 0xc0,
+ 0xbf, 0x0f, 0x82, 0x00, 0x00, 0xa6, 0x88, 0xc0, 0x00, 0x68, 0x82, 0x00,
+ 0x00, 0x69, 0x81, 0xc0, 0x00, 0x4e, 0x82, 0x00, 0x00, 0x81, 0x80, 0xc0,
+ 0x00, 0x5a, 0x82, 0x00, 0x00, 0x8f, 0x82, 0xc0, 0x00, 0x05, 0x82, 0x00,
+ 0x00, 0xb7, 0x81, 0xc0, 0x00, 0x55, 0x82, 0x00, 0x00, 0x73, 0x9a, 0xc0,
+ 0x00, 0x47, 0x82, 0x00, 0x00, 0x62, 0x85, 0xc0, 0x00, 0x7b, 0x82, 0x00,
+ 0x00, 0x26, 0x84, 0xc0, 0x03, 0xa9, 0x25, 0x00, 0x54, 0x80, 0xc0, 0x00,
+ 0xa9, 0x82, 0x00, 0x01, 0x0c, 0xbf, 0x88, 0xc0, 0x00, 0x42, 0x82, 0x00,
+ 0x00, 0x8f, 0x81, 0xc0, 0x00, 0x28, 0x82, 0x00, 0x00, 0xa9, 0x80, 0xc0,
+ 0x00, 0x2b, 0x82, 0x00, 0x00, 0xb4, 0x82, 0xc0, 0x00, 0x14, 0x82, 0x00,
+ 0x00, 0x97, 0x81, 0xc0, 0x00, 0x2c, 0x82, 0x00, 0x00, 0x9c, 0x9a, 0xc0,
+ 0x00, 0x1e, 0x82, 0x00, 0x00, 0x8b, 0x85, 0xc0, 0x00, 0x51, 0x82, 0x00,
+ 0x01, 0x12, 0xbb, 0x81, 0xc0, 0x05, 0xb8, 0x70, 0x10, 0x00, 0x03, 0xa9,
+ 0x80, 0xc0, 0x00, 0x7f, 0x82, 0x00, 0x00, 0x2f, 0x88, 0xc0, 0x01, 0xbf,
+ 0x19, 0x82, 0x00, 0x00, 0xb2, 0x80, 0xc0, 0x01, 0xbb, 0x05, 0x81, 0x00,
+ 0x01, 0x12, 0xbf, 0x80, 0xc0, 0x00, 0x0e, 0x82, 0x00, 0x01, 0x7b, 0xbd,
+ 0x81, 0xc0, 0x00, 0x41, 0x82, 0x00, 0x05, 0x3e, 0xbf, 0xc0, 0xc0, 0xaf,
+ 0x04, 0x81, 0x00, 0x01, 0x06, 0xbc, 0x99, 0xc0, 0x00, 0xb5, 0x83, 0x00,
+ 0x00, 0xb3, 0x84, 0xc0, 0x01, 0xbf, 0x16, 0x83, 0x00, 0x05, 0x2e, 0x71,
+ 0x79, 0x63, 0x48, 0x0d, 0x80, 0x00, 0x00, 0x46, 0x81, 0xc0, 0x00, 0x42,
+ 0x82, 0x00, 0x00, 0x42, 0x88, 0xc0, 0x00, 0x9f, 0x82, 0x00, 0x01, 0x07,
+ 0xbf, 0x80, 0xc0, 0x00, 0x9b, 0x82, 0x00, 0x00, 0x3b, 0x81, 0xc0, 0x00,
+ 0x12, 0x83, 0x00, 0x06, 0x0b, 0x21, 0xb2, 0xc0, 0xc0, 0x97, 0x02, 0x82,
+ 0x00, 0x03, 0x42, 0x97, 0xa7, 0x49, 0x82, 0x00, 0x00, 0x18, 0x9a, 0xc0,
+ 0x00, 0x8e, 0x82, 0x00, 0x00, 0x1d, 0x84, 0xc0, 0x01, 0xbd, 0x6c, 0x8d,
+ 0x00, 0x05, 0x9f, 0xc0, 0xc0, 0xbf, 0x8e, 0x07, 0x82, 0x00, 0x01, 0x13,
+ 0xb6, 0x86, 0xc0, 0x01, 0xb6, 0x40, 0x83, 0x00, 0x00, 0x91, 0x80, 0xc0,
+ 0x00, 0x75, 0x82, 0x00, 0x00, 0x64, 0x81, 0xc0, 0x00, 0x60, 0x82, 0x00,
+ 0x02, 0x2f, 0x7e, 0xbb, 0x81, 0xc0, 0x01, 0x75, 0x05, 0x8b, 0x00, 0x00,
+ 0x88, 0x99, 0xc0, 0x00, 0x65, 0x82, 0x00, 0x00, 0x45, 0x84, 0xc0, 0x00,
+ 0x40, 0x8d, 0x00, 0x00, 0x38, 0x80, 0xc0, 0x00, 0x6d, 0x85, 0x00, 0x00,
+ 0x1a, 0x86, 0xc0, 0x00, 0x13, 0x84, 0x00, 0x04, 0x02, 0xa1, 0xc0, 0xc0,
+ 0x4e, 0x82, 0x00, 0x00, 0x8e, 0x81, 0xc0, 0x05, 0xbe, 0x76, 0x29, 0x10,
+ 0x52, 0xa0, 0x85, 0xc0, 0x05, 0xa4, 0x5a, 0x2b, 0x11, 0x0a, 0x04, 0x87,
+ 0x00, 0x00, 0x92, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff,
+ 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff,
+ 0xc0, 0xff, 0xc0, 0xd6, 0xc0, 0x09, 0xb1, 0x85, 0x5a, 0x38, 0x1b, 0x08,
+ 0x05, 0x16, 0x4b, 0xad, 0x95, 0xc0, 0x03, 0x97, 0x49, 0x10, 0x68, 0x81,
+ 0xc0, 0x01, 0x83, 0xa0, 0x80, 0xc0, 0x01, 0xbe, 0xa1, 0xd1, 0xc0, 0x02,
+ 0xb8, 0x41, 0x01, 0x85, 0x00, 0x00, 0x29, 0x92, 0xc0, 0x02, 0x93, 0x60,
+ 0x2f, 0x80, 0x00, 0x0c, 0x13, 0xc0, 0xc0, 0xb0, 0x35, 0x00, 0x36, 0xc0,
+ 0xc0, 0xb2, 0x2f, 0x03, 0x99, 0xd0, 0xc0, 0x0b, 0x3a, 0x00, 0x01, 0x2f,
+ 0x60, 0x85, 0xa3, 0xb4, 0xbd, 0xb0, 0x72, 0x0e, 0x91, 0xc0, 0x13, 0x7f,
+ 0x02, 0x00, 0x00, 0x14, 0x72, 0xab, 0x18, 0xc0, 0xaa, 0x1b, 0x10, 0x00,
+ 0x58, 0xc0, 0x9d, 0x1a, 0x00, 0x04, 0x97, 0xcf, 0xc0, 0x0c, 0x89, 0x05,
+ 0x26, 0x53, 0xaf, 0xc0, 0x9f, 0x48, 0xa3, 0xc0, 0xc0, 0x8c, 0x6b, 0x8b,
+ 0xc0, 0x02, 0xaf, 0x4b, 0x9f, 0x80, 0xc0, 0x12, 0x2a, 0x00, 0x08, 0x60,
+ 0xb8, 0xc0, 0x89, 0x4d, 0xad, 0x1d, 0x7a, 0x5f, 0x05, 0xab, 0x90, 0x09,
+ 0x00, 0x01, 0x7c, 0xbc, 0xc0, 0x02, 0xaf, 0x4b, 0x9f, 0x8e, 0xc0, 0x01,
+ 0xbf, 0xbe, 0x80, 0xc0, 0x06, 0x91, 0x22, 0x8c, 0x8a, 0x65, 0x4b, 0x82,
+ 0x8c, 0xc0, 0x02, 0x31, 0x38, 0xbf, 0x80, 0xc0, 0x02, 0x14, 0x50, 0xac,
+ 0x80, 0xc0, 0x0b, 0x2f, 0x8e, 0x25, 0x78, 0xb2, 0x0f, 0x54, 0x94, 0x08,
+ 0x4b, 0x08, 0x61, 0xbd, 0xc0, 0x02, 0x31, 0x38, 0xbf, 0x92, 0xc0, 0x06,
+ 0xa3, 0x0e, 0x14, 0x32, 0x5b, 0x91, 0xbf, 0x8a, 0xc0, 0x05, 0x60, 0x0e,
+ 0x01, 0x00, 0x13, 0xb1, 0x85, 0xc0, 0x0b, 0x85, 0x24, 0x3d, 0x5e, 0xc0,
+ 0x49, 0x0c, 0x8f, 0x0e, 0x6f, 0x41, 0x38, 0xbb, 0xc0, 0x05, 0x60, 0x0e,
+ 0x01, 0x00, 0x13, 0xb1, 0x8f, 0xc0, 0x06, 0x9b, 0x23, 0x11, 0x02, 0x48,
+ 0x98, 0xba, 0x82, 0xc0, 0x0f, 0x94, 0x30, 0x08, 0x64, 0xc0, 0xc0, 0x94,
+ 0x30, 0x08, 0x64, 0x7d, 0x0b, 0x06, 0x00, 0x00, 0x75, 0x85, 0xc0, 0x0c,
+ 0xb6, 0x15, 0x19, 0x38, 0xbf, 0x8f, 0x01, 0x51, 0x14, 0x75, 0x66, 0x10,
+ 0xb0, 0x80, 0xc0, 0x0b, 0x96, 0x40, 0x0d, 0x7b, 0xc0, 0xc0, 0xb6, 0x70,
+ 0xbe, 0xc0, 0x65, 0x25, 0x80, 0xc0, 0x03, 0x96, 0x40, 0x0d, 0x7b, 0x80,
+ 0xc0, 0x03, 0xbe, 0x77, 0x23, 0x28, 0x81, 0xc0, 0x03, 0xa9, 0x4a, 0x0d,
+ 0x23, 0x89, 0xc0, 0x11, 0xa9, 0x4a, 0x0d, 0x23, 0xc0, 0xc0, 0xb6, 0x70,
+ 0xbe, 0xc0, 0x65, 0x25, 0x7d, 0x0b, 0x06, 0x00, 0x00, 0x75, 0x91, 0xc0,
+ 0x01, 0x8b, 0x01, 0x80, 0x00, 0x14, 0x05, 0x32, 0x7a, 0xbe, 0xc0, 0x70,
+ 0x02, 0x25, 0x57, 0x1d, 0xc0, 0x70, 0x02, 0x25, 0x57, 0x1d, 0xbb, 0xac,
+ 0x15, 0x86, 0xb5, 0x86, 0xc0, 0x4e, 0x51, 0x00, 0x15, 0xb2, 0xb5, 0x17,
+ 0x0d, 0x1a, 0x71, 0x94, 0x02, 0x77, 0xc0, 0xc0, 0xb7, 0x47, 0x15, 0x60,
+ 0x11, 0xa5, 0xc0, 0xc0, 0x38, 0x44, 0xbc, 0x48, 0x00, 0x30, 0xc0, 0xb7,
+ 0x47, 0x15, 0x60, 0x11, 0xa5, 0xc0, 0xc0, 0xae, 0x2f, 0x00, 0x27, 0x69,
+ 0x1b, 0xc0, 0xc0, 0x8b, 0x0b, 0x50, 0x85, 0x39, 0xc0, 0xb3, 0x5e, 0x5d,
+ 0xba, 0x53, 0x0e, 0x9f, 0xc0, 0x91, 0x5a, 0x8b, 0x0b, 0x50, 0x85, 0x39,
+ 0xc0, 0xc0, 0x38, 0x44, 0xbc, 0x48, 0x00, 0x30, 0xbb, 0xac, 0x15, 0x86,
+ 0xb5, 0x91, 0xc0, 0x18, 0xb6, 0x17, 0x0c, 0x96, 0xad, 0x91, 0x6d, 0x2d,
+ 0x00, 0x3f, 0x88, 0x01, 0x54, 0xbd, 0x3a, 0x09, 0x88, 0x01, 0x54, 0xbd,
+ 0x3a, 0x09, 0xae, 0x1f, 0x3f, 0x87, 0xc0, 0x4d, 0x8e, 0x01, 0x02, 0x91,
+ 0xc0, 0x42, 0x00, 0x00, 0x63, 0xbc, 0x1e, 0x1f, 0xbe, 0xc0, 0xae, 0x23,
+ 0x60, 0xb8, 0x3a, 0x0f, 0xab, 0xc0, 0x82, 0x12, 0xb4, 0x48, 0x2f, 0x06,
+ 0xa6, 0xae, 0x23, 0x60, 0xb8, 0x3a, 0x0f, 0xab, 0xc0, 0xb0, 0x1c, 0x0c,
+ 0x73, 0xac, 0x10, 0x26, 0xc0, 0x94, 0x04, 0x5a, 0x7f, 0x5a, 0xb8, 0xa5,
+ 0x19, 0x17, 0x7e, 0x26, 0x00, 0x0a, 0xb3, 0x7f, 0x05, 0x00, 0x04, 0x5a,
+ 0x7f, 0x5a, 0xb8, 0xc0, 0x82, 0x12, 0xb4, 0x48, 0x2f, 0x06, 0xa6, 0xae,
+ 0x1f, 0x3f, 0x93, 0xc0, 0x02, 0x5a, 0x00, 0x90, 0x81, 0xc0, 0x14, 0xa3,
+ 0x00, 0x0e, 0x23, 0x50, 0xc0, 0xc0, 0x12, 0x32, 0x23, 0x50, 0xc0, 0xc0,
+ 0x12, 0x1d, 0x3d, 0x00, 0x98, 0xc0, 0x9f, 0xb5, 0x83, 0xc0, 0x51, 0xb2,
+ 0x15, 0x00, 0x57, 0xc0, 0x77, 0x00, 0x00, 0x51, 0xc0, 0x74, 0x00, 0x72,
+ 0xc0, 0xc0, 0x33, 0x7b, 0xc0, 0x57, 0x08, 0x8b, 0xc0, 0xa1, 0x25, 0x73,
+ 0x63, 0x50, 0x1b, 0x56, 0xc0, 0x33, 0x7d, 0xc0, 0x57, 0x08, 0x8b, 0xc0,
+ 0xa1, 0x42, 0x11, 0xa2, 0xbe, 0x33, 0x00, 0x6c, 0xc0, 0x2a, 0x00, 0x5f,
+ 0xa1, 0xc0, 0x85, 0x2f, 0x2c, 0x9e, 0x1c, 0x74, 0x29, 0x65, 0x72, 0x32,
+ 0x10, 0x0b, 0x00, 0x5f, 0xa1, 0xc0, 0x85, 0xb2, 0x25, 0x73, 0x63, 0x50,
+ 0x1b, 0x56, 0xab, 0x3d, 0x00, 0x98, 0xc0, 0x9f, 0xb5, 0x90, 0xc0, 0x1b,
+ 0x11, 0x00, 0x79, 0xb9, 0xb8, 0x98, 0x5d, 0x0e, 0x00, 0x6e, 0x06, 0x9d,
+ 0xc0, 0xc0, 0x09, 0x63, 0x00, 0x9d, 0xc0, 0xc0, 0x09, 0x60, 0x00, 0x00,
+ 0xa9, 0x71, 0x3d, 0xbc, 0x83, 0xc0, 0x51, 0x3f, 0x00, 0x1b, 0xb9, 0xb2,
+ 0x0a, 0x00, 0x3b, 0xbe, 0xc0, 0x2c, 0x00, 0xac, 0xc0, 0xb9, 0x00, 0x89,
+ 0x4a, 0x36, 0x27, 0x7d, 0x55, 0x60, 0x02, 0x7b, 0x35, 0x69, 0x00, 0xa5,
+ 0xa0, 0x00, 0xa5, 0x4a, 0x36, 0x27, 0x7d, 0x55, 0x60, 0x08, 0x87, 0xc0,
+ 0x51, 0x0d, 0x08, 0xb3, 0xac, 0x06, 0x00, 0x99, 0xa9, 0x53, 0x45, 0x0b,
+ 0x84, 0x15, 0x78, 0x95, 0x21, 0x5a, 0x79, 0x07, 0x91, 0x06, 0x00, 0x99,
+ 0xa9, 0x53, 0x45, 0xc0, 0x02, 0x7b, 0x35, 0x69, 0x00, 0xa5, 0x9e, 0x08,
+ 0x00, 0xa9, 0x71, 0x3d, 0xbc, 0x90, 0xc0, 0x00, 0x1b, 0x83, 0x00, 0x0e,
+ 0x17, 0x83, 0xc0, 0x32, 0x9f, 0xb0, 0x63, 0x24, 0x54, 0x22, 0x9f, 0xb0,
+ 0x63, 0x24, 0x54, 0x80, 0x00, 0x01, 0x3b, 0xb9, 0x84, 0xc0, 0x2e, 0x17,
+ 0x00, 0x90, 0xc0, 0x91, 0x00, 0x27, 0xb8, 0xc0, 0xc0, 0x08, 0x00, 0xa4,
+ 0x8d, 0x21, 0x00, 0x00, 0x17, 0xb1, 0x0b, 0x00, 0x3f, 0xbf, 0x0e, 0x0c,
+ 0xad, 0x1a, 0x00, 0x6a, 0x39, 0x16, 0x00, 0x17, 0xb1, 0x0b, 0x00, 0x3f,
+ 0xbf, 0x1c, 0xa8, 0x50, 0x23, 0x50, 0x45, 0x5c, 0x81, 0x1b, 0x80, 0x00,
+ 0x0b, 0x39, 0xbb, 0x0c, 0x00, 0x6a, 0xc0, 0x39, 0x1d, 0x8b, 0x40, 0x00,
+ 0x73, 0x81, 0x00, 0x09, 0x39, 0xbb, 0xc0, 0x0e, 0x0c, 0xad, 0x1a, 0x00,
+ 0x6a, 0x39, 0x80, 0x00, 0x01, 0x3b, 0xb9, 0x91, 0xc0, 0x19, 0x9d, 0x37,
+ 0x0e, 0x04, 0x17, 0x45, 0x8b, 0xbe, 0xc0, 0xc0, 0xa4, 0x23, 0x0a, 0x51,
+ 0xb8, 0xc0, 0xa4, 0x23, 0x0a, 0x51, 0xb8, 0xc0, 0x37, 0x12, 0x69, 0xbe,
+ 0x85, 0xc0, 0x06, 0x57, 0x43, 0xc0, 0xc0, 0xaf, 0x23, 0xae, 0x80, 0xc0,
+ 0x45, 0x0e, 0x00, 0x00, 0x11, 0x93, 0x88, 0x19, 0x9e, 0xc0, 0x05, 0x3b,
+ 0xbb, 0xc0, 0x49, 0x7d, 0xc0, 0x08, 0x00, 0x4a, 0xbb, 0x88, 0x19, 0x9e,
+ 0xc0, 0x05, 0x3b, 0xbb, 0xc0, 0x77, 0x0c, 0x57, 0xae, 0x0d, 0x29, 0xa3,
+ 0xc0, 0x85, 0x11, 0x14, 0x63, 0xbd, 0xc0, 0x55, 0x48, 0xc0, 0xc0, 0x0c,
+ 0x75, 0xc0, 0x0c, 0x00, 0x3d, 0x73, 0x11, 0x14, 0x63, 0xbd, 0xc0, 0xc0,
+ 0x49, 0x7d, 0xc0, 0x08, 0x00, 0x4a, 0xbb, 0x37, 0x12, 0x69, 0xbe, 0xb4,
+ 0xc0, 0x01, 0xbe, 0xbd, 0x85, 0xc0, 0x03, 0x6e, 0x0b, 0x3f, 0xac, 0x82,
+ 0xc0, 0x01, 0x9d, 0xbf, 0x82, 0xc0, 0x01, 0x88, 0x92, 0x83, 0xc0, 0x01,
+ 0x9d, 0xbf, 0x81, 0xc0, 0x03, 0xbb, 0x44, 0x48, 0xba, 0x89, 0xc0, 0x04,
+ 0xb8, 0xc0, 0xc0, 0x93, 0x9d, 0x88, 0xc0, 0x01, 0x88, 0x92, 0xe1, 0xc0,
+ 0x03, 0xb4, 0x2d, 0x1f, 0xbb, 0xff, 0xc0, 0x03, 0xbb, 0x2c, 0x05, 0x9a,
+ 0xff, 0xc0, 0x03, 0xc0, 0x65, 0x00, 0x77, 0xff, 0xc0, 0x03, 0xc0, 0xc0,
+ 0x30, 0x78, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0,
+ 0xc8, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0,
+ 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0x8e, 0xc0, 0x08, 0xb2, 0x98, 0x83,
+ 0x6e, 0x5a, 0x45, 0x30, 0x1b, 0x39, 0xa8, 0xc0, 0x00, 0xf3, 0x8c, 0xff,
+ 0x00, 0xe7, 0x81, 0xc0, 0x00, 0xe4, 0x8c, 0xff, 0x03, 0xfb, 0xc0, 0xca,
+ 0xfe, 0x84, 0xff, 0x00, 0xf9, 0x9f, 0xc0, 0x01, 0x6e, 0x0b, 0x83, 0x00,
+ 0x00, 0x5a, 0xa8, 0xc0, 0x01, 0xc2, 0xf6, 0x8b, 0xff, 0x00, 0xea, 0x82,
+ 0xc0, 0x00, 0xe9, 0x8b, 0xff, 0x03, 0xfe, 0xc0, 0xc0, 0xd0, 0x83, 0xff,
+ 0x01, 0xea, 0xc3, 0xa0, 0xc0, 0x01, 0xb9, 0x15, 0x82, 0x00, 0x00, 0x82,
+ 0xa9, 0xc0, 0x00, 0xe5, 0x82, 0xff, 0x09, 0xf9, 0xd5, 0xc9, 0xc8, 0xcf,
+ 0xda, 0xf4, 0xff, 0xff, 0xed, 0x82, 0xc0, 0x00, 0xd6, 0x82, 0xff, 0x0d,
+ 0xfb, 0xd9, 0xcb, 0xc7, 0xcd, 0xd4, 0xea, 0xfe, 0xff, 0xff, 0xc2, 0xc0,
+ 0xc0, 0xfd, 0x82, 0xff, 0x00, 0xca, 0xa2, 0xc0, 0x00, 0x15, 0x82, 0x00,
+ 0x00, 0xaa, 0xa9, 0xc0, 0x00, 0xec, 0x82, 0xff, 0x00, 0xd9, 0x83, 0xc0,
+ 0x02, 0xde, 0xff, 0xf0, 0x82, 0xc0, 0x00, 0xde, 0x82, 0xff, 0x00, 0xe3,
+ 0x83, 0xc0, 0x05, 0xcc, 0xfa, 0xff, 0xc5, 0xc0, 0xc5, 0x82, 0xff, 0x00,
+ 0xf5, 0xa2, 0xc0, 0x00, 0xad, 0x82, 0x00, 0x01, 0x11, 0xbf, 0xa9, 0xc0,
+ 0x00, 0xf9, 0x82, 0xff, 0x00, 0xc7, 0x80, 0xc0, 0x05, 0xc4, 0xfe, 0xc0,
+ 0xc0, 0xe8, 0xf2, 0x82, 0xc0, 0x00, 0xea, 0x82, 0xff, 0x00, 0xd4, 0x80,
+ 0xc0, 0x08, 0xc5, 0xfb, 0xc0, 0xc0, 0xcf, 0xff, 0xc8, 0xc0, 0xd0, 0x82,
+ 0xff, 0x00, 0xe8, 0xa2, 0xc0, 0x00, 0x85, 0x82, 0x00, 0x00, 0x3a, 0x98,
+ 0xc0, 0x11, 0xb3, 0x95, 0x7a, 0x60, 0x45, 0x2a, 0x0f, 0x66, 0xc0, 0xc0,
+ 0xa4, 0x58, 0x20, 0x0b, 0x69, 0xc0, 0xc0, 0xc6, 0x82, 0xff, 0x00, 0xf6,
+ 0x80, 0xc0, 0x06, 0xc5, 0xe8, 0xff, 0xc0, 0xc0, 0xce, 0xf5, 0x82, 0xc0,
+ 0x00, 0xf7, 0x82, 0xff, 0x05, 0xc5, 0xc0, 0xc0, 0xc3, 0xe4, 0xff, 0x80,
+ 0xc0, 0x03, 0xeb, 0xc9, 0xc0, 0xdd, 0x82, 0xff, 0x14, 0xdb, 0xc0, 0xc0,
+ 0xaf, 0x91, 0x77, 0x5d, 0x42, 0x28, 0x0e, 0x91, 0xc0, 0xc0, 0xb4, 0x70,
+ 0x34, 0x15, 0x05, 0x17, 0x53, 0xb5, 0x87, 0xc0, 0x04, 0x9d, 0x60, 0x2e,
+ 0x16, 0x08, 0x85, 0x00, 0x00, 0x63, 0x98, 0xc0, 0x00, 0x68, 0x83, 0x00,
+ 0x0a, 0x16, 0xc0, 0x6f, 0x05, 0x00, 0x00, 0x09, 0xb5, 0xc0, 0xc0, 0xd3,
+ 0x82, 0xff, 0x06, 0xfd, 0xf5, 0xf6, 0xf9, 0xfe, 0xff, 0xff, 0x80, 0xc0,
+ 0x00, 0xc9, 0x81, 0xc0, 0x00, 0xc5, 0x83, 0xff, 0x05, 0xf5, 0xf6, 0xf8,
+ 0xfe, 0xff, 0xff, 0x83, 0xc0, 0x00, 0xea, 0x82, 0xff, 0x03, 0xcf, 0xc0,
+ 0xc0, 0x51, 0x83, 0x00, 0x03, 0x5d, 0xbe, 0x6d, 0x0e, 0x83, 0x00, 0x00,
+ 0x4a, 0x85, 0xc0, 0x01, 0xa7, 0x3c, 0x8a, 0x00, 0x00, 0x8b, 0x99, 0xc0,
+ 0x00, 0x87, 0x82, 0x00, 0x01, 0x05, 0x6e, 0x81, 0x00, 0x00, 0x54, 0x80,
+ 0xc0, 0x00, 0xe0, 0x89, 0xff, 0x85, 0xc0, 0x00, 0xd2, 0x89, 0xff, 0x83,
+ 0xc0, 0x00, 0xf6, 0x82, 0xff, 0x00, 0xc3, 0x80, 0xc0, 0x00, 0x68, 0x82,
+ 0x00, 0x01, 0x42, 0x39, 0x85, 0x00, 0x00, 0x0f, 0x84, 0xc0, 0x01, 0x8f,
+ 0x0e, 0x84, 0x00, 0x01, 0x12, 0x02, 0x82, 0x00, 0x00, 0xb2, 0x99, 0xc0,
+ 0x00, 0xb8, 0x82, 0x00, 0x06, 0x02, 0x02, 0x0e, 0x31, 0x14, 0x02, 0xa7,
+ 0x80, 0xc0, 0x00, 0xed, 0x89, 0xff, 0x85, 0xc0, 0x00, 0xdf, 0x89, 0xff,
+ 0x82, 0xc0, 0x00, 0xc4, 0x82, 0xff, 0x00, 0xf5, 0x81, 0xc0, 0x00, 0x8b,
+ 0x84, 0x00, 0x02, 0x2c, 0x62, 0x3a, 0x82, 0x00, 0x00, 0x12, 0x83, 0xc0,
+ 0x01, 0x99, 0x06, 0x82, 0x00, 0x04, 0x1b, 0x84, 0xb2, 0xb5, 0x01, 0x81,
+ 0x00, 0x00, 0x1a, 0x9a, 0xc0, 0x00, 0xa2, 0x83, 0x00, 0x04, 0x38, 0xb8,
+ 0xc0, 0xbd, 0x8a, 0x81, 0xc0, 0x00, 0xfa, 0x82, 0xff, 0x06, 0xcf, 0xc3,
+ 0xc3, 0xcb, 0xe2, 0xfe, 0xff, 0x85, 0xc0, 0x00, 0xec, 0x82, 0xff, 0x06,
+ 0xdb, 0xc4, 0xc3, 0xcb, 0xe4, 0xff, 0xff, 0x82, 0xc0, 0x00, 0xd0, 0x82,
+ 0xff, 0x00, 0xe9, 0x81, 0xc0, 0x00, 0x72, 0x83, 0x00, 0x03, 0x4c, 0xbe,
+ 0xc0, 0xb2, 0x82, 0x00, 0x00, 0x35, 0x82, 0xc0, 0x01, 0xb2, 0x14, 0x82,
+ 0x00, 0x04, 0x4e, 0xba, 0xc0, 0xc0, 0x8d, 0x82, 0x00, 0x00, 0x42, 0x9a,
+ 0xc0, 0x00, 0x7b, 0x82, 0x00, 0x01, 0x07, 0xaf, 0x84, 0xc0, 0x00, 0xc8,
+ 0x82, 0xff, 0x00, 0xfb, 0x82, 0xc0, 0x01, 0xdc, 0xff, 0x85, 0xc0, 0x00,
+ 0xf9, 0x82, 0xff, 0x00, 0xc9, 0x81, 0xc0, 0x01, 0xe2, 0xff, 0x82, 0xc0,
+ 0x00, 0xdd, 0x82, 0xff, 0x00, 0xdc, 0x81, 0xc0, 0x00, 0x4e, 0x82, 0x00,
+ 0x04, 0x16, 0xbb, 0xc0, 0xc0, 0xa7, 0x82, 0x00, 0x00, 0x59, 0x82, 0xc0,
+ 0x00, 0x54, 0x82, 0x00, 0x01, 0x3b, 0xbe, 0x80, 0xc0, 0x00, 0x63, 0x82,
+ 0x00, 0x00, 0x6b, 0x9a, 0xc0, 0x00, 0x52, 0x82, 0x00, 0x00, 0x45, 0x85,
+ 0xc0, 0x00, 0xd5, 0x82, 0xff, 0x00, 0xed, 0x82, 0xc0, 0x01, 0xc3, 0xfe,
+ 0x84, 0xc0, 0x00, 0xc6, 0x82, 0xff, 0x00, 0xfc, 0x82, 0xc0, 0x01, 0xca,
+ 0xff, 0x82, 0xc0, 0x00, 0xe9, 0x82, 0xff, 0x00, 0xcf, 0x81, 0xc0, 0x00,
+ 0x28, 0x82, 0x00, 0x00, 0x6f, 0x80, 0xc0, 0x00, 0x78, 0x82, 0x00, 0x00,
+ 0x8a, 0x81, 0xc0, 0x01, 0xab, 0x04, 0x81, 0x00, 0x01, 0x08, 0xac, 0x81,
+ 0xc0, 0x00, 0x3a, 0x82, 0x00, 0x00, 0x93, 0x9a, 0xc0, 0x00, 0x29, 0x82,
+ 0x00, 0x00, 0x79, 0x85, 0xc0, 0x00, 0xe2, 0x82, 0xff, 0x00, 0xe0, 0x83,
+ 0xc0, 0x00, 0xc1, 0x84, 0xc0, 0x00, 0xd3, 0x82, 0xff, 0x00, 0xef, 0x83,
+ 0xc0, 0x00, 0xc8, 0x82, 0xc0, 0x00, 0xf6, 0x82, 0xff, 0x00, 0xc3, 0x80,
+ 0xc0, 0x01, 0xbb, 0x05, 0x82, 0x00, 0x00, 0xaf, 0x80, 0xc0, 0x00, 0x40,
+ 0x81, 0x00, 0x01, 0x04, 0xb8, 0x81, 0xc0, 0x00, 0x6b, 0x82, 0x00, 0x00,
+ 0x51, 0x81, 0xc0, 0x01, 0xbf, 0x11, 0x81, 0x00, 0x01, 0x02, 0xb8, 0x99,
+ 0xc0, 0x01, 0xbb, 0x05, 0x82, 0x00, 0x00, 0xa8, 0x85, 0xc0, 0x00, 0xef,
+ 0x82, 0xff, 0x00, 0xd2, 0x86, 0xc0, 0x01, 0xc9, 0xe7, 0x80, 0xc0, 0x00,
+ 0xe0, 0x82, 0xff, 0x00, 0xe2, 0x88, 0xc0, 0x00, 0xc4, 0x82, 0xff, 0x00,
+ 0xf6, 0x81, 0xc0, 0x00, 0x9b, 0x82, 0x00, 0x00, 0x25, 0x80, 0xc0, 0x01,
+ 0xbc, 0x0b, 0x81, 0x00, 0x00, 0x2f, 0x82, 0xc0, 0x00, 0x31, 0x82, 0x00,
+ 0x00, 0x8f, 0x81, 0xc0, 0x00, 0xa8, 0x82, 0x00, 0x00, 0x23, 0x9a, 0xc0,
+ 0x00, 0x99, 0x82, 0x00, 0x01, 0x10, 0xbf, 0x85, 0xc0, 0x00, 0xfc, 0x82,
+ 0xff, 0x00, 0xc6, 0x85, 0xc0, 0x02, 0xc4, 0xf6, 0xdf, 0x80, 0xc0, 0x00,
+ 0xed, 0x82, 0xff, 0x00, 0xd5, 0x88, 0xc0, 0x00, 0xd0, 0x82, 0xff, 0x00,
+ 0xe9, 0x81, 0xc0, 0x00, 0x75, 0x82, 0x00, 0x00, 0x57, 0x80, 0xc0, 0x00,
+ 0x91, 0x82, 0x00, 0x00, 0x62, 0x82, 0xc0, 0x00, 0x15, 0x82, 0x00, 0x00,
+ 0xaf, 0x81, 0xc0, 0x00, 0x7f, 0x82, 0x00, 0x00, 0x4b, 0x9a, 0xc0, 0x00,
+ 0x6f, 0x82, 0x00, 0x00, 0x39, 0x85, 0xc0, 0x00, 0xc9, 0x82, 0xff, 0x00,
+ 0xfb, 0x85, 0xc0, 0x03, 0xc2, 0xee, 0xfd, 0xc5, 0x80, 0xc0, 0x00, 0xfa,
+ 0x82, 0xff, 0x00, 0xc9, 0x88, 0xc0, 0x00, 0xdd, 0x82, 0xff, 0x00, 0xdd,
+ 0x81, 0xc0, 0x00, 0x4e, 0x82, 0x00, 0x00, 0x81, 0x80, 0xc0, 0x00, 0x5a,
+ 0x82, 0x00, 0x00, 0x8f, 0x82, 0xc0, 0x00, 0x05, 0x82, 0x00, 0x00, 0xb7,
+ 0x81, 0xc0, 0x00, 0x55, 0x82, 0x00, 0x00, 0x73, 0x9a, 0xc0, 0x00, 0x47,
+ 0x82, 0x00, 0x00, 0x62, 0x85, 0xc0, 0x00, 0xd6, 0x82, 0xff, 0x00, 0xf2,
+ 0x84, 0xc0, 0x03, 0xc7, 0xf3, 0xff, 0xe4, 0x80, 0xc0, 0x00, 0xc8, 0x82,
+ 0xff, 0x00, 0xfb, 0x89, 0xc0, 0x00, 0xe9, 0x82, 0xff, 0x00, 0xd0, 0x81,
+ 0xc0, 0x00, 0x28, 0x82, 0x00, 0x00, 0xa9, 0x80, 0xc0, 0x00, 0x2b, 0x82,
+ 0x00, 0x00, 0xb4, 0x82, 0xc0, 0x00, 0x14, 0x82, 0x00, 0x00, 0x97, 0x81,
+ 0xc0, 0x00, 0x2c, 0x82, 0x00, 0x00, 0x9c, 0x9a, 0xc0, 0x00, 0x1e, 0x82,
+ 0x00, 0x00, 0x8b, 0x85, 0xc0, 0x00, 0xe4, 0x82, 0xff, 0x01, 0xf9, 0xc2,
+ 0x81, 0xc0, 0x05, 0xc3, 0xda, 0xfa, 0xff, 0xfe, 0xc7, 0x80, 0xc0, 0x00,
+ 0xd5, 0x82, 0xff, 0x00, 0xef, 0x89, 0xc0, 0x00, 0xf7, 0x82, 0xff, 0x00,
+ 0xc4, 0x80, 0xc0, 0x01, 0xbb, 0x05, 0x81, 0x00, 0x01, 0x12, 0xbf, 0x80,
+ 0xc0, 0x00, 0x0e, 0x82, 0x00, 0x01, 0x7b, 0xbd, 0x81, 0xc0, 0x00, 0x41,
+ 0x82, 0x00, 0x05, 0x3e, 0xbf, 0xc0, 0xc0, 0xaf, 0x04, 0x81, 0x00, 0x01,
+ 0x06, 0xbc, 0x99, 0xc0, 0x00, 0xb5, 0x83, 0x00, 0x00, 0xb3, 0x85, 0xc0,
+ 0x00, 0xf8, 0x83, 0xff, 0x05, 0xf0, 0xda, 0xd7, 0xdf, 0xe8, 0xfb, 0x80,
+ 0xff, 0x00, 0xe8, 0x81, 0xc0, 0x00, 0xe9, 0x82, 0xff, 0x00, 0xe9, 0x88,
+ 0xc0, 0x00, 0xcb, 0x82, 0xff, 0x00, 0xfd, 0x81, 0xc0, 0x00, 0x9b, 0x82,
+ 0x00, 0x00, 0x3b, 0x81, 0xc0, 0x00, 0x12, 0x83, 0x00, 0x06, 0x0b, 0x21,
+ 0xb2, 0xc0, 0xc0, 0x97, 0x02, 0x82, 0x00, 0x03, 0x42, 0x97, 0xa7, 0x49,
+ 0x82, 0x00, 0x00, 0x18, 0x9a, 0xc0, 0x00, 0x8e, 0x82, 0x00, 0x00, 0x1d,
+ 0x84, 0xc0, 0x01, 0xc1, 0xdb, 0x8d, 0xff, 0x00, 0xcb, 0x80, 0xc0, 0x01,
+ 0xd0, 0xfd, 0x82, 0xff, 0x01, 0xf9, 0xc3, 0x86, 0xc0, 0x01, 0xc3, 0xea,
+ 0x83, 0xff, 0x00, 0xd0, 0x80, 0xc0, 0x00, 0x75, 0x82, 0x00, 0x00, 0x64,
+ 0x81, 0xc0, 0x00, 0x60, 0x82, 0x00, 0x02, 0x2f, 0x7e, 0xbb, 0x81, 0xc0,
+ 0x01, 0x75, 0x05, 0x8b, 0x00, 0x00, 0x88, 0x99, 0xc0, 0x00, 0x65, 0x82,
+ 0x00, 0x00, 0x45, 0x84, 0xc0, 0x00, 0xea, 0x8d, 0xff, 0x00, 0xec, 0x80,
+ 0xc0, 0x00, 0xdb, 0x85, 0xff, 0x00, 0xf7, 0x86, 0xc0, 0x00, 0xf9, 0x84,
+ 0xff, 0x04, 0xfe, 0xca, 0xc0, 0xc0, 0x4e, 0x82, 0x00, 0x00, 0x8e, 0x81,
+ 0xc0, 0x05, 0xbe, 0x76, 0x29, 0x10, 0x52, 0xa0, 0x85, 0xc0, 0x05, 0xa4,
+ 0x5a, 0x2b, 0x11, 0x0a, 0x04, 0x87, 0x00, 0x00, 0x92, 0xff, 0xc0, 0xff,
+ 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff,
+ 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xd6, 0xc0, 0x09,
+ 0xb1, 0x85, 0x5a, 0x38, 0x1b, 0x08, 0x05, 0x16, 0x4b, 0xad, 0x95, 0xc0,
+ 0x03, 0x97, 0x49, 0x10, 0x68, 0x81, 0xc0, 0x01, 0x83, 0xa0, 0x80, 0xc0,
+ 0x01, 0xbe, 0xa1, 0xd1, 0xc0, 0x02, 0xb8, 0x41, 0x01, 0x85, 0x00, 0x00,
+ 0x29, 0x92, 0xc0, 0x02, 0x93, 0x60, 0x2f, 0x80, 0x00, 0x0c, 0x13, 0xc0,
+ 0xc0, 0xb0, 0x35, 0x00, 0x36, 0xc0, 0xc0, 0xb2, 0x2f, 0x03, 0x99, 0xd0,
+ 0xc0, 0x0b, 0x3a, 0x00, 0x01, 0x2f, 0x60, 0x85, 0xa3, 0xb4, 0xbd, 0xb0,
+ 0x72, 0x0e, 0x91, 0xc0, 0x13, 0x7f, 0x02, 0x00, 0x00, 0x14, 0x72, 0xab,
+ 0x18, 0xc0, 0xaa, 0x1b, 0x10, 0x00, 0x58, 0xc0, 0x9d, 0x1a, 0x00, 0x04,
+ 0x97, 0xcf, 0xc0, 0x0c, 0x89, 0x05, 0x26, 0x53, 0xaf, 0xc0, 0x9f, 0x48,
+ 0xa3, 0xc0, 0xc0, 0x8c, 0x6b, 0x8b, 0xc0, 0x02, 0xaf, 0x4b, 0x9f, 0x80,
+ 0xc0, 0x12, 0x2a, 0x00, 0x08, 0x60, 0xb8, 0xc0, 0x89, 0x4d, 0xad, 0x1d,
+ 0x7a, 0x5f, 0x05, 0xab, 0x90, 0x09, 0x00, 0x01, 0x7c, 0xbc, 0xc0, 0x02,
+ 0xaf, 0x4b, 0x9f, 0x8e, 0xc0, 0x01, 0xbf, 0xbe, 0x80, 0xc0, 0x06, 0x91,
+ 0x22, 0x8c, 0x8a, 0x65, 0x4b, 0x82, 0x8c, 0xc0, 0x02, 0x31, 0x38, 0xbf,
+ 0x80, 0xc0, 0x02, 0x14, 0x50, 0xac, 0x80, 0xc0, 0x0b, 0x2f, 0x8e, 0x25,
+ 0x78, 0xb2, 0x0f, 0x54, 0x94, 0x08, 0x4b, 0x08, 0x61, 0xbd, 0xc0, 0x02,
+ 0x31, 0x38, 0xbf, 0x92, 0xc0, 0x06, 0xa3, 0x0e, 0x14, 0x32, 0x5b, 0x91,
+ 0xbf, 0x8a, 0xc0, 0x05, 0x60, 0x0e, 0x01, 0x00, 0x13, 0xb1, 0x85, 0xc0,
+ 0x0b, 0x85, 0x24, 0x3d, 0x5e, 0xc0, 0x49, 0x0c, 0x8f, 0x0e, 0x6f, 0x41,
+ 0x38, 0xbb, 0xc0, 0x05, 0x60, 0x0e, 0x01, 0x00, 0x13, 0xb1, 0x8f, 0xc0,
+ 0x06, 0x9b, 0x23, 0x11, 0x02, 0x48, 0x98, 0xba, 0x82, 0xc0, 0x0f, 0x94,
+ 0x30, 0x08, 0x64, 0xc0, 0xc0, 0x94, 0x30, 0x08, 0x64, 0x7d, 0x0b, 0x06,
+ 0x00, 0x00, 0x75, 0x85, 0xc0, 0x0c, 0xb6, 0x15, 0x19, 0x38, 0xbf, 0x8f,
+ 0x01, 0x51, 0x14, 0x75, 0x66, 0x10, 0xb0, 0x80, 0xc0, 0x0b, 0x96, 0x40,
+ 0x0d, 0x7b, 0xc0, 0xc0, 0xb6, 0x70, 0xbe, 0xc0, 0x65, 0x25, 0x80, 0xc0,
+ 0x03, 0x96, 0x40, 0x0d, 0x7b, 0x80, 0xc0, 0x03, 0xbe, 0x77, 0x23, 0x28,
+ 0x81, 0xc0, 0x03, 0xa9, 0x4a, 0x0d, 0x23, 0x89, 0xc0, 0x11, 0xa9, 0x4a,
+ 0x0d, 0x23, 0xc0, 0xc0, 0xb6, 0x70, 0xbe, 0xc0, 0x65, 0x25, 0x7d, 0x0b,
+ 0x06, 0x00, 0x00, 0x75, 0x91, 0xc0, 0x01, 0x8b, 0x01, 0x80, 0x00, 0x14,
+ 0x05, 0x32, 0x7a, 0xbe, 0xc0, 0x70, 0x02, 0x25, 0x57, 0x1d, 0xc0, 0x70,
+ 0x02, 0x25, 0x57, 0x1d, 0xbb, 0xac, 0x15, 0x86, 0xb5, 0x86, 0xc0, 0x4e,
+ 0x51, 0x00, 0x15, 0xb2, 0xb5, 0x17, 0x0d, 0x1a, 0x71, 0x94, 0x02, 0x77,
+ 0xc0, 0xc0, 0xb7, 0x47, 0x15, 0x60, 0x11, 0xa5, 0xc0, 0xc0, 0x38, 0x44,
+ 0xbc, 0x48, 0x00, 0x30, 0xc0, 0xb7, 0x47, 0x15, 0x60, 0x11, 0xa5, 0xc0,
+ 0xc0, 0xae, 0x2f, 0x00, 0x27, 0x69, 0x1b, 0xc0, 0xc0, 0x8b, 0x0b, 0x50,
+ 0x85, 0x39, 0xc0, 0xb3, 0x5e, 0x5d, 0xba, 0x53, 0x0e, 0x9f, 0xc0, 0x91,
+ 0x5a, 0x8b, 0x0b, 0x50, 0x85, 0x39, 0xc0, 0xc0, 0x38, 0x44, 0xbc, 0x48,
+ 0x00, 0x30, 0xbb, 0xac, 0x15, 0x86, 0xb5, 0x91, 0xc0, 0x18, 0xb6, 0x17,
+ 0x0c, 0x96, 0xad, 0x91, 0x6d, 0x2d, 0x00, 0x3f, 0x88, 0x01, 0x54, 0xbd,
+ 0x3a, 0x09, 0x88, 0x01, 0x54, 0xbd, 0x3a, 0x09, 0xae, 0x1f, 0x3f, 0x87,
+ 0xc0, 0x4d, 0x8e, 0x01, 0x02, 0x91, 0xc0, 0x42, 0x00, 0x00, 0x63, 0xbc,
+ 0x1e, 0x1f, 0xbe, 0xc0, 0xae, 0x23, 0x60, 0xb8, 0x3a, 0x0f, 0xab, 0xc0,
+ 0x82, 0x12, 0xb4, 0x48, 0x2f, 0x06, 0xa6, 0xae, 0x23, 0x60, 0xb8, 0x3a,
+ 0x0f, 0xab, 0xc0, 0xb0, 0x1c, 0x0c, 0x73, 0xac, 0x10, 0x26, 0xc0, 0x94,
+ 0x04, 0x5a, 0x7f, 0x5a, 0xb8, 0xa5, 0x19, 0x17, 0x7e, 0x26, 0x00, 0x0a,
+ 0xb3, 0x7f, 0x05, 0x00, 0x04, 0x5a, 0x7f, 0x5a, 0xb8, 0xc0, 0x82, 0x12,
+ 0xb4, 0x48, 0x2f, 0x06, 0xa6, 0xae, 0x1f, 0x3f, 0x93, 0xc0, 0x02, 0x5a,
+ 0x00, 0x90, 0x81, 0xc0, 0x14, 0xa3, 0x00, 0x0e, 0x23, 0x50, 0xc0, 0xc0,
+ 0x12, 0x32, 0x23, 0x50, 0xc0, 0xc0, 0x12, 0x1d, 0x3d, 0x00, 0x98, 0xc0,
+ 0x9f, 0xb5, 0x83, 0xc0, 0x51, 0xb2, 0x15, 0x00, 0x57, 0xc0, 0x77, 0x00,
+ 0x00, 0x51, 0xc0, 0x74, 0x00, 0x72, 0xc0, 0xc0, 0x33, 0x7b, 0xc0, 0x57,
+ 0x08, 0x8b, 0xc0, 0xa1, 0x25, 0x73, 0x63, 0x50, 0x1b, 0x56, 0xc0, 0x33,
+ 0x7d, 0xc0, 0x57, 0x08, 0x8b, 0xc0, 0xa1, 0x42, 0x11, 0xa2, 0xbe, 0x33,
+ 0x00, 0x6c, 0xc0, 0x2a, 0x00, 0x5f, 0xa1, 0xc0, 0x85, 0x2f, 0x2c, 0x9e,
+ 0x1c, 0x74, 0x29, 0x65, 0x72, 0x32, 0x10, 0x0b, 0x00, 0x5f, 0xa1, 0xc0,
+ 0x85, 0xb2, 0x25, 0x73, 0x63, 0x50, 0x1b, 0x56, 0xab, 0x3d, 0x00, 0x98,
+ 0xc0, 0x9f, 0xb5, 0x90, 0xc0, 0x1b, 0x11, 0x00, 0x79, 0xb9, 0xb8, 0x98,
+ 0x5d, 0x0e, 0x00, 0x6e, 0x06, 0x9d, 0xc0, 0xc0, 0x09, 0x63, 0x00, 0x9d,
+ 0xc0, 0xc0, 0x09, 0x60, 0x00, 0x00, 0xa9, 0x71, 0x3d, 0xbc, 0x83, 0xc0,
+ 0x51, 0x3f, 0x00, 0x1b, 0xb9, 0xb2, 0x0a, 0x00, 0x3b, 0xbe, 0xc0, 0x2c,
+ 0x00, 0xac, 0xc0, 0xb9, 0x00, 0x89, 0x4a, 0x36, 0x27, 0x7d, 0x55, 0x60,
+ 0x02, 0x7b, 0x35, 0x69, 0x00, 0xa5, 0xa0, 0x00, 0xa5, 0x4a, 0x36, 0x27,
+ 0x7d, 0x55, 0x60, 0x08, 0x87, 0xc0, 0x51, 0x0d, 0x08, 0xb3, 0xac, 0x06,
+ 0x00, 0x99, 0xa9, 0x53, 0x45, 0x0b, 0x84, 0x15, 0x78, 0x95, 0x21, 0x5a,
+ 0x79, 0x07, 0x91, 0x06, 0x00, 0x99, 0xa9, 0x53, 0x45, 0xc0, 0x02, 0x7b,
+ 0x35, 0x69, 0x00, 0xa5, 0x9e, 0x08, 0x00, 0xa9, 0x71, 0x3d, 0xbc, 0x90,
+ 0xc0, 0x00, 0x1b, 0x83, 0x00, 0x0e, 0x17, 0x83, 0xc0, 0x32, 0x9f, 0xb0,
+ 0x63, 0x24, 0x54, 0x22, 0x9f, 0xb0, 0x63, 0x24, 0x54, 0x80, 0x00, 0x01,
+ 0x3b, 0xb9, 0x84, 0xc0, 0x2e, 0x17, 0x00, 0x90, 0xc0, 0x91, 0x00, 0x27,
+ 0xb8, 0xc0, 0xc0, 0x08, 0x00, 0xa4, 0x8d, 0x21, 0x00, 0x00, 0x17, 0xb1,
+ 0x0b, 0x00, 0x3f, 0xbf, 0x0e, 0x0c, 0xad, 0x1a, 0x00, 0x6a, 0x39, 0x16,
+ 0x00, 0x17, 0xb1, 0x0b, 0x00, 0x3f, 0xbf, 0x1c, 0xa8, 0x50, 0x23, 0x50,
+ 0x45, 0x5c, 0x81, 0x1b, 0x80, 0x00, 0x0b, 0x39, 0xbb, 0x0c, 0x00, 0x6a,
+ 0xc0, 0x39, 0x1d, 0x8b, 0x40, 0x00, 0x73, 0x81, 0x00, 0x09, 0x39, 0xbb,
+ 0xc0, 0x0e, 0x0c, 0xad, 0x1a, 0x00, 0x6a, 0x39, 0x80, 0x00, 0x01, 0x3b,
+ 0xb9, 0x91, 0xc0, 0x19, 0x9d, 0x37, 0x0e, 0x04, 0x17, 0x45, 0x8b, 0xbe,
+ 0xc0, 0xc0, 0xa4, 0x23, 0x0a, 0x51, 0xb8, 0xc0, 0xa4, 0x23, 0x0a, 0x51,
+ 0xb8, 0xc0, 0x37, 0x12, 0x69, 0xbe, 0x85, 0xc0, 0x06, 0x57, 0x43, 0xc0,
+ 0xc0, 0xaf, 0x23, 0xae, 0x80, 0xc0, 0x45, 0x0e, 0x00, 0x00, 0x11, 0x93,
+ 0x88, 0x19, 0x9e, 0xc0, 0x05, 0x3b, 0xbb, 0xc0, 0x49, 0x7d, 0xc0, 0x08,
+ 0x00, 0x4a, 0xbb, 0x88, 0x19, 0x9e, 0xc0, 0x05, 0x3b, 0xbb, 0xc0, 0x77,
+ 0x0c, 0x57, 0xae, 0x0d, 0x29, 0xa3, 0xc0, 0x85, 0x11, 0x14, 0x63, 0xbd,
+ 0xc0, 0x55, 0x48, 0xc0, 0xc0, 0x0c, 0x75, 0xc0, 0x0c, 0x00, 0x3d, 0x73,
+ 0x11, 0x14, 0x63, 0xbd, 0xc0, 0xc0, 0x49, 0x7d, 0xc0, 0x08, 0x00, 0x4a,
+ 0xbb, 0x37, 0x12, 0x69, 0xbe, 0xb4, 0xc0, 0x01, 0xbe, 0xbd, 0x85, 0xc0,
+ 0x03, 0x6e, 0x0b, 0x3f, 0xac, 0x82, 0xc0, 0x01, 0x9d, 0xbf, 0x82, 0xc0,
+ 0x01, 0x88, 0x92, 0x83, 0xc0, 0x01, 0x9d, 0xbf, 0x81, 0xc0, 0x03, 0xbb,
+ 0x44, 0x48, 0xba, 0x89, 0xc0, 0x04, 0xb8, 0xc0, 0xc0, 0x93, 0x9d, 0x88,
+ 0xc0, 0x01, 0x88, 0x92, 0xe1, 0xc0, 0x03, 0xb4, 0x2d, 0x1f, 0xbb, 0xff,
+ 0xc0, 0x03, 0xbb, 0x2c, 0x05, 0x9a, 0xff, 0xc0, 0x03, 0xc0, 0x65, 0x00,
+ 0x77, 0xff, 0xc0, 0x03, 0xc0, 0xc0, 0x30, 0x78, 0xff, 0xc0, 0xff, 0xc0,
+ 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xc8, 0xc0,
+};
+static EG_EMBEDDED_IMAGE egemb_refind_banner = { 135, 64, EG_EIPIXELMODE_COLOR, EG_EICOMPMODE_RLE, egemb_refind_banner_data, 7592 };
diff --git a/include/refit_call_wrapper.h b/include/refit_call_wrapper.h
new file mode 100644 (file)
index 0000000..9b1f5c1
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef __REFIT_CALL_WRAPPER_H__
+#define __REFIT_CALL_WRAPPER_H__
+
+#ifdef EFIX64
+# 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
+
+#endif /* !__REFIT_CALL_WRAPPER_H__ */
+
diff --git a/include/syslinux_mbr.h b/include/syslinux_mbr.h
new file mode 100644 (file)
index 0000000..1c33e11
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * 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 */
diff --git a/mkcdimage b/mkcdimage
new file mode 100755 (executable)
index 0000000..613ab62
--- /dev/null
+++ b/mkcdimage
@@ -0,0 +1,58 @@
+#!/bin/bash
+#
+# Script to create a bootable CD image file containing rEFInd.
+# Usage:
+#
+#   ./mkcdimage {version}
+#
+# where {version} is the rEFInd version number.
+#
+# This script relies on the mcopy utility.
+#
+# The script creates an image file from the binary package
+# stored in ../snapshots/{version}/refind-bin-{version}.zip
+# The resulting CD image file is stored in
+# ../snapshots/{version}/refind-cd-{version}.iso
+
+StartDir=`pwd`
+Version=$1
+
+# Unzip the binary archive file....
+cd ../snapshots/$Version
+rm -rf temp
+mkdir temp
+cd temp
+unzip ../refind-bin-$Version.zip
+
+# Create hard links to the files so that they'll be suitable for an
+# EFI-boot CD...
+mkdir -p refind-bin-$Version/EFI/boot
+cd refind-bin-$Version/EFI/boot
+ln ../../refind/refind_ia32.efi ./bootia32.efi
+ln ../../refind/refind_x64.efi ./bootx64.efi
+ln ../../refind/refind.conf-sample ./refind.conf
+mkdir icons
+cd icons
+ln ../../../refind/icons/* ./
+cd ../../..
+
+# Get the size of the binaries to go in the El Torito image in kB
+ToritoSize=`du -s EFI | cut -f 1`
+let ToritoSize=($ToritoSize)/28
+let ToritoSize=($ToritoSize)*32
+
+# Prepare a FAT filesystem image and populate it with the
+# EFI boot files....
+dd if=/dev/zero of=refind-bin-$Version.img bs=1024 count=$ToritoSize
+mkdosfs -n "rEFInd.ET" refind-bin-$Version.img
+mcopy -irefind-bin-$Version.img -s EFI ::/
+
+# Make the ISO-9660 image file....
+mkisofs -A "Bootable rEFInd" -V "rEFInd $Version" -volset "rEFInd $Version" \
+    -J -r -v -x ./lost+found -o ../../refind-cd-$Version.iso \
+    -b refind-bin-$Version.img -c boot.cat -no-emul-boot -boot-load-size 4 \
+    -eltorito-alt-boot -efi-boot refind-bin-$Version.img \
+    -no-emul-boot ./
+
+cd ../../
+rm -r temp/
diff --git a/mkdistrib b/mkdistrib
new file mode 100755 (executable)
index 0000000..fd64376
--- /dev/null
+++ b/mkdistrib
@@ -0,0 +1,37 @@
+#!/bin/bash
+#
+# Script to prepare source code and binary distribution files of rEFInd.
+# By Rod Smith, 3/11/2012
+#
+# Usage: ./mkdistrib version
+# where "version" is a version number
+# MUST be run from an x86-64 system, on which the current IA32 build
+# (refind_ia32.efi) is already present in the same directory as this script
+
+
+StartDir=`pwd`
+
+make clean
+
+# Prepare a place and copy files there....
+mkdir -p ../snapshots/$1/refind-$1/icons
+cp --preserve=timestamps icons/*icns ../snapshots/$1/refind-$1/icons/
+cp -a docs images include libeg refind NEWS.txt BUILDING.txt COPYING.txt LICENSE.txt README.txt Make.common Makefile refind.conf-sample ../snapshots/$1/refind-$1
+
+# Go there are prepare a souce code zip file....
+cd ../snapshots/$1/
+zip -9r refind-src-$1.zip refind-$1
+
+# Build the source code into a binary
+cd refind-$1
+make
+mkdir -p refind-bin-$1/refind
+cp -a icons refind-bin-$1/refind/
+cp --preserve=timestamps refind.conf-sample refind-bin-$1/refind/
+cp refind/refind.efi refind-bin-$1/refind/refind_x64.efi
+cp $StartDir/refind_ia32.efi refind-bin-$1/refind/
+cp -a COPYING.txt LICENSE.txt README.txt docs refind-bin-$1
+zip -9r ../refind-bin-$1.zip refind-bin-$1
+cd ..
+rm -r refind-$1
+cd $StartDir
diff --git a/refind.conf-sample b/refind.conf-sample
new file mode 100644 (file)
index 0000000..06ecaa9
--- /dev/null
@@ -0,0 +1,163 @@
+#
+# 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).
+#
+timeout 20
+
+# Disable menu options for increased security. These are intended for a lab
+# environment where the administrator doesn't want users to mess with the
+# operating system. List the names for the options you want to hide from
+# the boot menu. Currently supported:
+#  shell       - remove the EFI shell
+#  tools       - remove all EFI tools (shell and gptsync)
+#  singleuser  - remove the submenu options to boot Mac OS X in single-user
+#                 or verbose modes
+#  hwtest      - remove the submenu option to run Apple Hardware Test
+#  all         - all of the above
+#
+#disable shell singleuser
+#disable all
+
+# 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.
+#
+#banner hostname.bmp
+
+# 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.
+#
+# Like the banner option above, these options take a filename of
+# an uncompressed BMP image file.
+#
+#selection_big   selection-big.bmp
+#selection_small selection-small.bmp
+
+# Hide various user interface elements. Here you can list the names of
+# interface elements to hide. Currently supported:
+#  banner    - the rEFInd title banner
+#  shell     - the EFI shell icon
+#  tools     - all EFI tools (shell and gptsync)
+#  funcs     - built-in functions (about, restart)
+#    ('tools' and 'funcs' together hide the complete second row of icons.)
+#  label     - text label in the menu
+#  badges    - all volume badges (same as 'hidebadges all'); this setting
+#               is not recommended because it won't let you distinguish
+#               installed OSes and bootable CDs/DVDs.
+#  all       - all of the above, except for 'badges'
+#
+# Note: The 'shell' and 'tools' options are equivalent to the 'disable'
+# options with the same names.
+#
+#hideui tools funcs hdbadges
+#hideui all
+
+# Use text mode only. When enabled, this option forces rEFInd into text mode.
+#
+#textonly
+
+# Which types of boot loaders to search:
+#  internal      - internal EFI disk-based boot loaders
+#  external      - external EFI disk-based boot loaders
+#  optical       - EFI optical discs (CD, DVD, etc.)
+#  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
+# Default is internal,external,optical
+scanfor internal,external,optical
+
+# Set the default menu selection.  The available arguments match the
+# keyboard accelerators available within rEFInd.  You may select the default
+# loader using a one-character abbreviation for the OS name ("M" = Mac OS X,
+# "L" = Linux, "W" = Windows).  You may also specify a digit between 1 and
+# 9, in which case the Nth loader in the menu will be the default.  You can
+# also select a rEFInd tool entry ("S" = EFI Shell, "P" = Partitioning Tool,
+# "U" = shutdown).  This is intended as a quick fix to change the default
+# boot choice until full configurability arrives.
+#
+#default_selection 1
+
+# 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:
+#
+#  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.3 kernel with its new EFI boot stub
+# support. This includes Linux-specific boot options and specification
+# of an initial RAM disk. Note uses of Linux-style forward slashes,
+# even in the initrd specification. Also note that a leading slash is
+# optional in file specifications.
+menuentry Linux {
+       loader EFI/Linux/bzImage-3.3.0-rc7
+       initrd EFI/Linux/initrd-3.3.0.img
+       icon EFI/refind/icons/os_linux.icns
+       options "ro root=UUID=5f96cafa-e0a7-4057-b18f-fa709db5b837"
+       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/refined/icons/os_linux.icns
+       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
+}
+
+# EOF
diff --git a/refind/Makefile b/refind/Makefile
new file mode 100644 (file)
index 0000000..4c40c48
--- /dev/null
@@ -0,0 +1,30 @@
+#
+# refind/Makefile
+# Build control file for the rEFInd boot menu
+#
+
+SRCDIR = .
+
+VPATH = $(SRCDIR)
+
+ifeq ($(ARCH),ia32)
+  LIBEG = build32
+endif
+
+ifeq ($(ARCH),x86_64)
+  LIBEG = build64
+endif
+
+LOCAL_CPPFLAGS  = -I$(SRCDIR) -I$(SRCDIR)/../include -I$(SRCDIR)/../libeg -DDEBIAN_VERSION="L\"$(DEBVER)\""
+LOCAL_LDFLAGS   = -L$(SRCDIR)/../libeg/$(LIBEG)
+LOCAL_LIBS      = -leg
+
+OBJS            = main.o config.o menu.o screen.o icns.o lib.o
+TARGET          = refind.efi
+
+all: $(TARGET)
+
+include $(SRCDIR)/../Make.common
+
+# EOF
+# DO NOT DELETE
diff --git a/refind/config.c b/refind/config.c
new file mode 100644 (file)
index 0000000..b89e365
--- /dev/null
@@ -0,0 +1,612 @@
+/*
+ * refit/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 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"
+#include "lib.h"
+#include "icns.h"
+#include "menu.h"
+#include "config.h"
+#include "screen.h"
+#include "refit_call_wrapper.h"
+
+// constants
+
+#define CONFIG_FILE_NAME        L"refind.conf"
+#define LINUX_OPTIONS_FILENAME  L"linux.conf"
+#define MAXCONFIGFILESIZE       (128*1024)
+
+#define ENCODING_ISO8859_1  (0)
+#define ENCODING_UTF8       (1)
+#define ENCODING_UTF16_LE   (2)
+
+static REFIT_MENU_ENTRY MenuEntryReturn   = { L"Return to Main Menu", TAG_RETURN, 0, 0, 0, NULL, NULL, NULL };
+
+//
+// read a file into a buffer
+//
+
+static EFI_STATUS ReadFile(IN EFI_FILE_HANDLE BaseDir, CHAR16 *FileName, REFIT_FILE *File)
+{
+    EFI_STATUS      Status;
+    EFI_FILE_HANDLE FileHandle;
+    EFI_FILE_INFO   *FileInfo;
+    UINT64          ReadSize;
+
+    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);
+    if (CheckError(Status, L"while loading the configuration file"))
+        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;
+    if (ReadSize > MAXCONFIGFILESIZE)
+        ReadSize = MAXCONFIGFILESIZE;
+    FreePool(FileInfo);
+    
+    File->BufferSize = (UINTN)ReadSize;   // was limited to a few K before, so this is safe
+    File->Buffer = AllocatePool(File->BufferSize);
+    Status = refit_call3_wrapper(FileHandle->Read, FileHandle, &File->BufferSize, File->Buffer);
+    if (CheckError(Status, L"while loading the configuration file")) {
+        FreePool(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;
+}
+
+//
+// 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
+            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 (*p && *p != '"' && ((*p != ' ' && *p != '\t' && *p != '=' && *p != '#' && *p != ',') || IsQuoted)) {
+               if ((*p == '/') && !IsQuoted) // Switch Unix-style to DOS-style directory separators
+                  *p = '\\';
+               p++;
+            } // if
+            if (*p == '"')
+               IsQuoted = !IsQuoted;
+            if (*p == 0 || *p == '#')
+                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) {
+        return;
+    }
+    if (TokenCount > 2) {
+        return;
+    }
+    *Value = Atoi(TokenList[1]);
+}
+
+//
+// handle a parameter with a single string argument
+//
+
+static VOID HandleString(IN CHAR16 **TokenList, IN UINTN TokenCount, OUT CHAR16 **Value)
+{
+    if (TokenCount < 2) {
+        return;
+    }
+    if (TokenCount > 2) {
+        return;
+    }
+    *Value = StrDuplicate(TokenList[1]);
+}
+
+//
+// read config file
+//
+
+VOID ReadConfig(VOID)
+{
+    EFI_STATUS      Status;
+    REFIT_FILE      File;
+    CHAR16          **TokenList;
+    CHAR16          *FlagName;
+    UINTN           TokenCount, i;
+
+    if (!FileExists(SelfDir, CONFIG_FILE_NAME)) {
+        Print(L"Configuration file missing!\n");
+        return;
+    }
+
+    Status = ReadFile(SelfDir, CONFIG_FILE_NAME, &File);
+    if (EFI_ERROR(Status))
+        return;
+
+    for (;;) {
+        TokenCount = ReadTokenLine(&File, &TokenList);
+        if (TokenCount == 0)
+            break;
+        
+        if (StriCmp(TokenList[0], L"timeout") == 0) {
+            HandleInt(TokenList, TokenCount, &(GlobalConfig.Timeout));
+            
+        } else if (StriCmp(TokenList[0], L"disable") == 0) {
+            for (i = 1; i < TokenCount; i++) {
+                FlagName = TokenList[i];
+                if (StriCmp(FlagName, L"shell") == 0) {
+                    GlobalConfig.DisableFlags |= DISABLE_FLAG_SHELL;
+                } else if (StriCmp(FlagName, L"tools") == 0) {
+                    GlobalConfig.DisableFlags |= DISABLE_FLAG_TOOLS;
+                } else if (StriCmp(FlagName, L"singleuser") == 0) {
+                    GlobalConfig.DisableFlags |= DISABLE_FLAG_SINGLEUSER;
+                } else if (StriCmp(FlagName, L"hwtest") == 0) {
+                    GlobalConfig.DisableFlags |= DISABLE_FLAG_HWTEST;
+                } else if (StriCmp(FlagName, L"all") == 0) {
+                    GlobalConfig.DisableFlags = DISABLE_ALL;
+                } else {
+                    Print(L" unknown disable flag: '%s'\n", FlagName);
+                }
+            }
+
+        } else if (StriCmp(TokenList[0], L"scanfor") == 0) {
+           for (i = 0; i < NUM_SCAN_OPTIONS; i++) {
+              if (i < TokenCount)
+                 GlobalConfig.ScanFor[i] = TokenList[i][0];
+              else
+                 GlobalConfig.ScanFor[i] = ' ';
+           }
+        } else if (StriCmp(TokenList[0], L"hideui") == 0) {
+            for (i = 1; i < TokenCount; i++) {
+                FlagName = TokenList[i];
+                if (StriCmp(FlagName, L"banner") == 0) {
+                    GlobalConfig.HideUIFlags |= HIDEUI_FLAG_BANNER;
+                } else if (StriCmp(FlagName, L"shell") == 0) {
+                    GlobalConfig.DisableFlags |= DISABLE_FLAG_SHELL;
+                } else if (StriCmp(FlagName, L"tools") == 0) {
+                    GlobalConfig.DisableFlags |= DISABLE_FLAG_TOOLS;
+                } else if (StriCmp(FlagName, L"funcs") == 0) {
+                    GlobalConfig.HideUIFlags |= HIDEUI_FLAG_FUNCS;
+                } else if (StriCmp(FlagName, L"label") == 0) {
+                    GlobalConfig.HideUIFlags |= HIDEUI_FLAG_LABEL;
+                } else if (StriCmp(FlagName, L"all") == 0) {
+                    GlobalConfig.HideUIFlags = HIDEUI_ALL;
+                    GlobalConfig.DisableFlags |= DISABLE_FLAG_SHELL | DISABLE_FLAG_TOOLS;
+                } else {
+                    Print(L" unknown hideui flag: '%s'\n", FlagName);
+                }
+            }
+            
+        } else if (StriCmp(TokenList[0], L"banner") == 0) {
+            HandleString(TokenList, TokenCount, &(GlobalConfig.BannerFileName));
+
+        } else if (StriCmp(TokenList[0], L"selection_small") == 0) {
+            HandleString(TokenList, TokenCount, &(GlobalConfig.SelectionSmallFileName));
+
+        } else if (StriCmp(TokenList[0], L"selection_big") == 0) {
+            HandleString(TokenList, TokenCount, &(GlobalConfig.SelectionBigFileName));
+
+        } else if (StriCmp(TokenList[0], L"default_selection") == 0) {
+            HandleString(TokenList, TokenCount, &(GlobalConfig.DefaultSelection));
+            
+        } else if (StriCmp(TokenList[0], L"textonly") == 0) {
+            GlobalConfig.TextOnly = TRUE;
+
+        } else if ((StriCmp(TokenList[0], L"}") == 0) || (StriCmp(TokenList[0], L"loader") == 0) ||
+                   (StriCmp(TokenList[0], L"icon") == 0) || (StriCmp(TokenList[0], L"options") == 0)) {
+           // Do nothing; handled by ScanUserConfigured()
+        }
+
+        FreeTokenLine(&TokenList, &TokenCount);
+    }
+
+    FreePool(File.Buffer);
+} /* 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) && (StriCmp(TokenList[0], L"}") != 0)) {
+      if ((StriCmp(TokenList[0], L"loader") == 0) && (TokenCount > 1)) { // set the boot loader filename
+         if (SubEntry->LoaderPath != NULL)
+            FreePool(SubEntry->LoaderPath);
+         SubEntry->LoaderPath = StrDuplicate(TokenList[1]);
+         SubEntry->DevicePath = FileDevicePath(Volume->DeviceHandle, SubEntry->LoaderPath);
+      } else if (StriCmp(TokenList[0], L"initrd") == 0) {
+         if (SubEntry->InitrdPath != NULL)
+            FreePool(SubEntry->InitrdPath);
+         SubEntry->InitrdPath = NULL;
+         if (TokenCount > 1) {
+            SubEntry->InitrdPath = StrDuplicate(TokenList[1]);
+         }
+      } else if (StriCmp(TokenList[0], L"options") == 0) {
+         if (SubEntry->LoadOptions != NULL)
+            FreePool(SubEntry->LoadOptions);
+         SubEntry->LoadOptions = NULL;
+         if (TokenCount > 1) {
+            SubEntry->LoadOptions = StrDuplicate(TokenList[1]);
+         } // if/else
+      } else if ((StriCmp(TokenList[0], L"add_options") == 0) && (TokenCount > 1)) {
+         MergeStrings(&SubEntry->LoadOptions, TokenList[1], L' ');
+      } else if ((StriCmp(TokenList[0], L"graphics") == 0) && (TokenCount > 1)) {
+         SubEntry->UseGraphicsMode = (StriCmp(TokenList[1], L"on") == 0);
+      } else if (StriCmp(TokenList[0], L"disabled") == 0) {
+         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);
+      FreePool(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 loaders.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;
+
+   // prepare the menu entry
+   Entry = InitializeLoaderEntry(NULL);
+   if (Entry == NULL)
+      return NULL;
+
+   Entry->Title           = StrDuplicate(Title);
+   Entry->me.Title        = PoolPrint(L"Boot %s from %s", (Title != NULL) ? Title : L"Unknown", Volume->VolName);
+   Entry->me.Row          = 0;
+   Entry->me.BadgeImage   = Volume->VolBadgeImage;
+   Entry->VolName         = Volume->VolName;
+
+   // 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) && (StriCmp(TokenList[0], L"}") != 0)) {
+      if ((StriCmp(TokenList[0], L"loader") == 0) && (TokenCount > 1)) { // set the boot loader filename
+         Entry->LoaderPath = StrDuplicate(TokenList[1]);
+         Entry->DevicePath = FileDevicePath(Volume->DeviceHandle, Entry->LoaderPath);
+         SetLoaderDefaults(Entry, TokenList[1], Volume);
+         FreePool(Entry->LoadOptions);
+         Entry->LoadOptions = NULL; // Discard default options, if any
+         DefaultsSet = TRUE;
+      } else if ((StriCmp(TokenList[0], L"icon") == 0) && (TokenCount > 1)) {
+         FreePool(Entry->me.Image);
+         Entry->me.Image = LoadIcns(Volume->RootDir, TokenList[1], 128);
+         if (Entry->me.Image == NULL) {
+            Entry->me.Image = DummyImage(128);
+         }
+      } else if ((StriCmp(TokenList[0], L"initrd") == 0) && (TokenCount > 1)) {
+         if (Entry->InitrdPath)
+            FreePool(Entry->InitrdPath);
+         Entry->InitrdPath = StrDuplicate(TokenList[1]);
+      } else if ((StriCmp(TokenList[0], L"options") == 0) && (TokenCount > 1)) {
+         if (Entry->LoadOptions)
+            FreePool(Entry->LoadOptions);
+         Entry->LoadOptions = StrDuplicate(TokenList[1]);
+      } else if ((StriCmp(TokenList[0], L"ostype") == 0) && (TokenCount > 1)) {
+         if (TokenCount > 1) {
+            Entry->OSType = TokenList[1][0];
+         }
+      } else if ((StriCmp(TokenList[0], L"graphics") == 0) && (TokenCount > 1)) {
+         Entry->UseGraphicsMode = (StriCmp(TokenList[1], L"on") == 0);
+      } else if (StriCmp(TokenList[0], L"disabled") == 0) {
+         Entry->Enabled = FALSE;
+      } else if ((StriCmp(TokenList[0], L"submenuentry") == 0) && (TokenCount > 1)) {
+         AddSubmenu(Entry, File, Volume, 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);
+      FreePool(Entry->InitrdPath);
+      Entry->InitrdPath = NULL;
+   } // if
+
+   if (!DefaultsSet)
+      SetLoaderDefaults(Entry, L"\\EFI\\BOOT\\nemo.efi", Volume); // user included no entry; use bogus one
+
+   return(Entry);
+} // static VOID AddStanzaEntries()
+
+// Read the user-configured loaders file, loaders.conf, and add or delete
+// entries based on the contents of that file....
+VOID ScanUserConfigured(VOID)
+{
+   EFI_STATUS        Status;
+   REFIT_FILE        File;
+   REFIT_VOLUME      *Volume;
+   CHAR16            **TokenList;
+   CHAR16            *Title = NULL;
+   UINTN             TokenCount;
+   LOADER_ENTRY      *Entry;
+
+   if (FileExists(SelfDir, CONFIG_FILE_NAME)) {
+      Status = ReadFile(SelfDir, CONFIG_FILE_NAME, &File);
+      if (EFI_ERROR(Status))
+         return;
+
+      Volume = SelfVolume;
+      // TODO: Figure out how to set volumes (on per-image basis, preferably)
+
+      while ((TokenCount = ReadTokenLine(&File, &TokenList)) > 0) {
+         if ((StriCmp(TokenList[0], L"menuentry") == 0) && (TokenCount > 1)) {
+            Title = StrDuplicate(TokenList[1]);
+            Entry = AddStanzaEntries(&File, Volume, TokenList[1]);
+            if (Entry->Enabled) {
+               if (Entry->me.SubScreen == NULL)
+                  GenerateSubScreen(Entry, Volume);
+               AddPreparedLoaderEntry(Entry);
+            } else {
+               FreePool(Entry);
+            } // if/else
+            FreePool(Title);
+         } // if
+         FreeTokenLine(&TokenList, &TokenCount);
+      } // while()
+   } // if()
+} // VOID ScanUserConfigured()
+
+// 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 the name
+// LINUX_OPTIONS_FILENAME within that directory and loads it.
+// 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 = NULL;
+   REFIT_FILE   *File = NULL;
+   EFI_STATUS   Status;
+   
+   OptionsFilename = FindPath(LoaderPath);
+   MergeStrings(&OptionsFilename, LINUX_OPTIONS_FILENAME, L'\\');
+   if (FileExists(Volume->RootDir, OptionsFilename)) {
+      File = AllocateZeroPool(sizeof(REFIT_FILE));
+      Status = ReadFile(Volume->RootDir, OptionsFilename, File);
+      if (CheckError(Status, L"while loading the Linux options file"))
+         File = NULL;
+   }
+   if (OptionsFilename != NULL)
+      FreePool(OptionsFilename);
+   return (File);
+} // static REFIT_FILE * FindLinuxOptionsFile()
+
+// 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);
+   }
+   return Options;
+} // static CHAR16 * GetOptionsFile()
+
diff --git a/refind/config.h b/refind/config.h
new file mode 100644 (file)
index 0000000..6e32ea8
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * 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 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_
+
+#include "efi.h"
+#include "global.h"
+
+//
+// config module
+//
+
+typedef struct {
+    UINT8   *Buffer;
+    UINTN   BufferSize;
+    UINTN   Encoding;
+    CHAR8   *Current8Ptr;
+    CHAR8   *End8Ptr;
+    CHAR16  *Current16Ptr;
+    CHAR16  *End16Ptr;
+} REFIT_FILE;
+
+#define DISABLE_FLAG_SHELL      (0x0001)
+#define DISABLE_FLAG_TOOLS      (0x0002)
+#define DISABLE_FLAG_SINGLEUSER (0x0004)
+#define DISABLE_FLAG_HWTEST     (0x0008)
+#define DISABLE_ALL             ((0xffff))
+
+#define HIDEUI_FLAG_BANNER      (0x0001)
+#define HIDEUI_FLAG_FUNCS       (0x0002)
+#define HIDEUI_FLAG_LABEL       (0x0004)
+#define HIDEUI_ALL              (0xffff)
+
+VOID ReadConfig(VOID);
+VOID ScanUserConfigured(VOID);
+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 */
diff --git a/refind/global.h b/refind/global.h
new file mode 100644 (file)
index 0000000..dccac51
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * 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 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_
+
+#include "efi.h"
+#include "efilib.h"
+
+#include "libeg.h"
+
+#define REFIT_DEBUG (0)
+
+#define TAG_ABOUT    (1)
+#define TAG_RESET    (2)
+#define TAG_SHUTDOWN (3)
+#define TAG_TOOL     (4)
+#define TAG_LOADER   (5)
+#define TAG_LEGACY   (6)
+
+#define NUM_SCAN_OPTIONS 10
+
+//
+// global definitions
+//
+
+// global types
+
+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;
+   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;
+} 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;
+} REFIT_MENU_SCREEN;
+
+typedef struct {
+   REFIT_MENU_ENTRY me;
+   CHAR16           *Title;
+   CHAR16           *LoaderPath;
+   CHAR16           *VolName;
+   EFI_DEVICE_PATH  *DevicePath;
+   BOOLEAN          UseGraphicsMode;
+   BOOLEAN          Enabled;
+   CHAR16           *LoadOptions;
+   CHAR16           *InitrdPath; // Linux stub loader only
+   CHAR8            OSType;
+} LOADER_ENTRY;
+
+typedef struct {
+   REFIT_MENU_ENTRY me;
+   REFIT_VOLUME     *Volume;
+   CHAR16           *LoadOptions;
+   BOOLEAN          Enabled;
+} LEGACY_ENTRY;
+
+typedef struct {
+   BOOLEAN     TextOnly;
+   UINTN       Timeout;
+   UINTN       DisableFlags;
+   UINTN       HideUIFlags;
+   BOOLEAN     Quiet;
+   CHAR16      *BannerFileName;
+   CHAR16      *SelectionSmallFileName;
+   CHAR16      *SelectionBigFileName;
+   CHAR16      *DefaultSelection;
+   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;
+
+LOADER_ENTRY *InitializeLoaderEntry(IN LOADER_ENTRY *Entry);
+REFIT_MENU_SCREEN *InitializeSubScreen(IN LOADER_ENTRY *Entry);
+VOID GenerateSubScreen(LOADER_ENTRY *Entry, IN REFIT_VOLUME *Volume);
+LOADER_ENTRY * MakeGenericLoaderEntry(VOID);
+LOADER_ENTRY * AddLoaderEntry(IN CHAR16 *LoaderPath, IN CHAR16 *LoaderTitle, IN REFIT_VOLUME *Volume);
+VOID SetLoaderDefaults(LOADER_ENTRY *Entry, CHAR16 *LoaderPath, IN REFIT_VOLUME *Volume);
+LOADER_ENTRY * AddPreparedLoaderEntry(LOADER_ENTRY *Entry);
+
+#endif
+
+/* EOF */
diff --git a/refind/icns.c b/refind/icns.c
new file mode 100644 (file)
index 0000000..54a3ea7
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * 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"
+
+//
+// well-known icons
+//
+
+typedef struct {
+    EG_IMAGE    *Image;
+    CHAR16      *Path;
+    UINTN       PixelSize;
+} BUILTIN_ICON;
+
+BUILTIN_ICON BuiltinIconTable[BUILTIN_ICON_COUNT] = {
+    { NULL, L"icons\\func_about.icns", 48 },
+    { NULL, L"icons\\func_reset.icns", 48 },
+    { NULL, L"icons\\func_shutdown.icns", 48 },
+    { NULL, L"icons\\tool_shell.icns", 48 },
+    { NULL, L"icons\\tool_part.icns", 48 },
+    { NULL, L"icons\\tool_rescue.icns", 48 },
+    { NULL, L"icons\\vol_internal.icns", 32 },
+    { NULL, L"icons\\vol_external.icns", 32 },
+    { NULL, L"icons\\vol_optical.icns", 32 },
+};
+
+EG_IMAGE * BuiltinIcon(IN UINTN Id)
+{
+    if (Id >= BUILTIN_ICON_COUNT)
+        return NULL;
+    
+    if (BuiltinIconTable[Id].Image == NULL)
+        BuiltinIconTable[Id].Image = LoadIcnsFallback(SelfDir, BuiltinIconTable[Id].Path, BuiltinIconTable[Id].PixelSize);
+    
+    return BuiltinIconTable[Id].Image;
+}
+
+//
+// Load an icon for an operating system
+//
+
+EG_IMAGE * LoadOSIcon(IN CHAR16 *OSIconName OPTIONAL, IN CHAR16 *FallbackIconName, BOOLEAN BootLogo)
+{
+    EG_IMAGE        *Image;
+    CHAR16          CutoutName[16];
+    CHAR16          FileName[256];
+    UINTN           StartIndex, Index, NextIndex;
+
+    if (GlobalConfig.TextOnly)      // skip loading if it's not used anyway
+        return NULL;
+    Image = NULL;
+
+    // try the names from OSIconName
+    for (StartIndex = 0; OSIconName != NULL && OSIconName[StartIndex]; StartIndex = NextIndex) {
+        // find the next name in the list
+        NextIndex = 0;
+        for (Index = StartIndex; OSIconName[Index]; Index++) {
+            if (OSIconName[Index] == ',') {
+                NextIndex = Index + 1;
+                break;
+            }
+        }
+        if (OSIconName[Index] == 0)
+            NextIndex = Index;
+        
+        // construct full path
+        if (Index > StartIndex + 15)   // prevent buffer overflow
+            continue;
+        CopyMem(CutoutName, OSIconName + StartIndex, (Index - StartIndex) * sizeof(CHAR16));
+        CutoutName[Index - StartIndex] = 0;
+        SPrint(FileName, 255, L"icons\\%s_%s.icns",
+               BootLogo ? L"boot" : L"os", CutoutName);
+        
+        // try to load it
+        Image = egLoadIcon(SelfDir, FileName, 128);
+        if (Image != NULL)
+            return Image;
+    }
+
+    // try the fallback name
+    SPrint(FileName, 255, L"icons\\%s_%s.icns",
+           BootLogo ? L"boot" : L"os", FallbackIconName);
+    Image = egLoadIcon(SelfDir, FileName, 128);
+    if (Image != NULL)
+        return Image;
+    
+    // try the fallback name with os_ instead of boot_
+    if (BootLogo)
+        return LoadOSIcon(NULL, FallbackIconName, FALSE);
+    
+    return DummyImage(128);
+}
+
+//
+// Load an image from a .icns file
+//
+
+EG_IMAGE * LoadIcns(IN EFI_FILE_HANDLE BaseDir, IN CHAR16 *FileName, IN UINTN PixelSize)
+{
+    if (GlobalConfig.TextOnly)      // skip loading if it's not used anyway
+        return NULL;
+    return egLoadIcon(BaseDir, FileName, PixelSize);
+}
+
+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;
+}
+
+EG_IMAGE * LoadIcnsFallback(IN EFI_FILE_HANDLE BaseDir, IN CHAR16 *FileName, IN UINTN PixelSize)
+{
+    EG_IMAGE *Image;
+    if (GlobalConfig.TextOnly)      // skip loading if it's not used anyway
+        return NULL;
+
+    Image = LoadIcns(BaseDir, FileName, PixelSize);
+    if (Image == NULL) {
+        Image = DummyImage(PixelSize);
+    }
+    return Image;
+}
diff --git a/refind/icns.h b/refind/icns.h
new file mode 100644 (file)
index 0000000..eb3370c
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * 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 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 * LoadIcns(IN EFI_FILE_HANDLE BaseDir, IN CHAR16 *FileName, IN UINTN PixelSize);
+EG_IMAGE * LoadIcnsFallback(IN EFI_FILE_HANDLE BaseDir, IN CHAR16 *FileName, IN UINTN PixelSize);
+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_TOOL_SHELL     (3)
+#define BUILTIN_ICON_TOOL_PART      (4)
+#define BUILTIN_ICON_TOOL_RESCUE    (5)
+#define BUILTIN_ICON_VOL_INTERNAL   (6)
+#define BUILTIN_ICON_VOL_EXTERNAL   (7)
+#define BUILTIN_ICON_VOL_OPTICAL    (8)
+#define BUILTIN_ICON_COUNT          (9)
+
+#endif
+
+/* EOF */
diff --git a/refind/lib.c b/refind/lib.c
new file mode 100644 (file)
index 0000000..1e4be18
--- /dev/null
@@ -0,0 +1,1129 @@
+/*
+ * refit/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 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"
+#include "lib.h"
+#include "icns.h"
+#include "screen.h"
+#include "refit_call_wrapper.h"
+
+// 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;
+
+// Maximum size for disk sectors
+#define SECTOR_SIZE 4096
+
+// functions
+
+static EFI_STATUS FinishInitRefitLib(VOID);
+
+static VOID UninitVolumes(VOID);
+
+//
+// self recognition stuff
+//
+
+EFI_STATUS InitRefitLib(IN EFI_HANDLE ImageHandle)
+{
+    EFI_STATUS  Status;
+    CHAR16      *DevicePathAsString;
+    CHAR16      BaseDirectory[256];
+    UINTN       i;
+    
+    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);
+    if (DevicePathAsString != NULL) {
+        StrCpy(BaseDirectory, DevicePathAsString);
+        FreePool(DevicePathAsString);
+        for (i = StrLen(BaseDirectory); i > 0 && BaseDirectory[i] != '\\'; i--) ;
+        BaseDirectory[i] = 0;
+    } else
+        BaseDirectory[0] = 0;
+    SelfDirPath = StrDuplicate(BaseDirectory);
+    
+    return FinishInitRefitLib();
+}
+
+// called before running external programs to close open file handles
+VOID UninitRefitLib(VOID)
+{
+    UninitVolumes();
+    
+    if (SelfDir != NULL) {
+        refit_call1_wrapper(SelfDir->Close, SelfDir);
+        SelfDir = NULL;
+    }
+    
+    if (SelfRootDir != NULL) {
+        refit_call1_wrapper(SelfRootDir->Close, SelfRootDir);
+        SelfRootDir = NULL;
+    }
+}
+
+// called after running external programs to re-open file handles
+EFI_STATUS ReinitRefitLib(VOID)
+{
+    ReinitVolumes();
+    
+    if (SelfVolume != NULL && SelfVolume->RootDir != NULL)
+        SelfRootDir = SelfVolume->RootDir;
+    
+    return FinishInitRefitLib();
+}
+
+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;
+}
+
+//
+// list functions
+//
+
+VOID CreateList(OUT VOID ***ListPtr, OUT UINTN *ElementCount, IN UINTN InitialElementCount)
+{
+    UINTN AllocateCount;
+    
+    *ElementCount = InitialElementCount;
+    if (*ElementCount > 0) {
+        AllocateCount = (*ElementCount + 7) & ~7;   // next multiple of 8
+        *ListPtr = AllocatePool(sizeof(VOID *) * AllocateCount);
+    } else {
+        *ListPtr = NULL;
+    }
+}
+
+VOID AddListElement(IN OUT VOID ***ListPtr, IN OUT UINTN *ElementCount, IN VOID *NewElement)
+{
+    UINTN AllocateCount;
+
+    if ((*ElementCount & 7) == 0) {
+        AllocateCount = *ElementCount + 8;
+        if (*ElementCount == 0)
+            *ListPtr = AllocatePool(sizeof(VOID *) * AllocateCount);
+        else
+            *ListPtr = ReallocatePool(*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) {
+        for (i = 0; i < *ElementCount; i++) {
+            // TODO: call a user-provided routine for each element here
+            FreePool((*ListPtr)[i]);
+        }
+        FreePool(*ListPtr);
+    }
+}
+
+//
+// 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;
+
+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);
+    }
+    FreePool(Handles);
+    
+    if (HardcodedPathList) {
+        for (HardcodedIndex = 0; HardcodedPathList[HardcodedIndex] && PathCount < MaxPaths; HardcodedIndex++)
+            PathList[PathCount++] = HardcodedPathList[HardcodedIndex];
+    }
+    PathList[PathCount] = NULL;
+}
+
+//
+// volume functions
+//
+
+static VOID ScanVolumeBootcode(IN OUT REFIT_VOLUME *Volume, OUT BOOLEAN *Bootable)
+{
+    EFI_STATUS              Status;
+    UINT8                   SectorBuffer[SECTOR_SIZE];
+    UINTN                   i;
+    MBR_PARTITION_INFO      *MbrTable;
+    BOOLEAN                 MbrTableFound;
+    
+    Volume->HasBootCode = FALSE;
+    Volume->OSIconName = NULL;
+    Volume->OSName = NULL;
+    *Bootable = FALSE;
+    
+    if (Volume->BlockIO == NULL)
+        return;
+    if (Volume->BlockIO->Media->BlockSize > SECTOR_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, SECTOR_SIZE, SectorBuffer);
+    if (!EFI_ERROR(Status)) {
+        
+        if (*((UINT16 *)(SectorBuffer + 510)) == 0xaa55 && SectorBuffer[0] != 0) {
+            *Bootable = TRUE;
+            Volume->HasBootCode = TRUE;
+        }
+        
+        // detect specific boot codes
+        if (CompareMem(SectorBuffer + 2, "LILO", 4) == 0 ||
+            CompareMem(SectorBuffer + 6, "LILO", 4) == 0 ||
+            CompareMem(SectorBuffer + 3, "SYSLINUX", 8) == 0 ||
+            FindMem(SectorBuffer, SECTOR_SIZE, "ISOLINUX", 8) >= 0) {
+            Volume->HasBootCode = TRUE;
+            Volume->OSIconName = L"linux";
+            Volume->OSName = L"Linux";
+            
+        } else if (FindMem(SectorBuffer, 512, "Geom\0Hard Disk\0Read\0 Error", 26) >= 0) {   // GRUB
+            Volume->HasBootCode = TRUE;
+            Volume->OSIconName = L"grub,linux";
+            Volume->OSName = L"Linux";
+            
+        } else if ((*((UINT32 *)(SectorBuffer + 502)) == 0 &&
+                    *((UINT32 *)(SectorBuffer + 506)) == 50000 &&
+                    *((UINT16 *)(SectorBuffer + 510)) == 0xaa55) ||
+                    FindMem(SectorBuffer, SECTOR_SIZE, "Starting the BTX loader", 23) >= 0) {
+            Volume->HasBootCode = TRUE;
+            Volume->OSIconName = L"freebsd";
+            Volume->OSName = L"FreeBSD";
+            
+        } else if (FindMem(SectorBuffer, 512, "!Loading", 8) >= 0 ||
+                   FindMem(SectorBuffer, SECTOR_SIZE, "/cdboot\0/CDBOOT\0", 16) >= 0) {
+            Volume->HasBootCode = TRUE;
+            Volume->OSIconName = L"openbsd";
+            Volume->OSName = L"OpenBSD";
+            
+        } else if (FindMem(SectorBuffer, 512, "Not a bootxx image", 18) >= 0 ||
+                   *((UINT32 *)(SectorBuffer + 1028)) == 0x7886b6d1) {
+            Volume->HasBootCode = TRUE;
+            Volume->OSIconName = L"netbsd";
+            Volume->OSName = L"NetBSD";
+            
+        } else if (FindMem(SectorBuffer, SECTOR_SIZE, "NTLDR", 5) >= 0) {
+            Volume->HasBootCode = TRUE;
+            Volume->OSIconName = L"win";
+            Volume->OSName = L"Windows";
+            
+        } else if (FindMem(SectorBuffer, SECTOR_SIZE, "BOOTMGR", 7) >= 0) {
+            Volume->HasBootCode = TRUE;
+            Volume->OSIconName = L"winvista,win";
+            Volume->OSName = L"Windows";
+            
+        } else if (FindMem(SectorBuffer, 512, "CPUBOOT SYS", 11) >= 0 ||
+                   FindMem(SectorBuffer, 512, "KERNEL  SYS", 11) >= 0) {
+            Volume->HasBootCode = TRUE;
+            Volume->OSIconName = L"freedos";
+            Volume->OSName = L"FreeDOS";
+            
+        } else if (FindMem(SectorBuffer, 512, "OS2LDR", 6) >= 0 ||
+                   FindMem(SectorBuffer, 512, "OS2BOOT", 7) >= 0) {
+            Volume->HasBootCode = TRUE;
+            Volume->OSIconName = L"ecomstation";
+            Volume->OSName = L"eComStation";
+            
+        } else if (FindMem(SectorBuffer, 512, "Be Boot Loader", 14) >= 0) {
+            Volume->HasBootCode = TRUE;
+            Volume->OSIconName = L"beos";
+            Volume->OSName = L"BeOS";
+            
+        } else if (FindMem(SectorBuffer, 512, "yT Boot Loader", 14) >= 0) {
+            Volume->HasBootCode = TRUE;
+            Volume->OSIconName = L"zeta,beos";
+            Volume->OSName = L"ZETA";
+            
+        } else if (FindMem(SectorBuffer, 512, "\x04" "beos\x06" "system\x05" "zbeos", 18) >= 0 ||
+                   FindMem(SectorBuffer, 512, "\x06" "system\x0c" "haiku_loader", 20) >= 0) {
+            Volume->HasBootCode = TRUE;
+            Volume->OSIconName = L"haiku,beos";
+            Volume->OSName = L"Haiku";
+
+        }
+        
+        // NOTE: If you add an operating system with a name that starts with 'W' or 'L', you
+        //  need to fix AddLegacyEntry in main.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
+        
+        if (FindMem(SectorBuffer, 512, "Non-system disk", 15) >= 0)   // dummy FAT boot sector
+            Volume->HasBootCode = FALSE;
+        
+        // check for MBR partition table
+        if (*((UINT16 *)(SectorBuffer + 510)) == 0xaa55) {
+            MbrTableFound = FALSE;
+            MbrTable = (MBR_PARTITION_INFO *)(SectorBuffer + 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
+    }
+}
+
+// default volume icon based on disk kind
+static VOID ScanVolumeDefaultIcon(IN OUT REFIT_VOLUME *Volume)
+{
+    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;
+    } // switch()
+}
+
+static VOID ScanVolume(IN OUT REFIT_VOLUME *Volume)
+{
+    EFI_STATUS              Status;
+    EFI_DEVICE_PATH         *DevicePath, *NextDevicePath;
+    EFI_DEVICE_PATH         *DiskDevicePath, *RemainingDevicePath;
+    EFI_HANDLE              WholeDiskHandle;
+    UINTN                   PartialLength;
+    EFI_FILE_SYSTEM_INFO    *FileSystemInfoPtr;
+    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) == 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;
+            //Print(L"  * looking at %s\n", DevicePathToStr(RemainingDevicePath));
+            Status = refit_call3_wrapper(BS->LocateDevicePath, &BlockIoProtocol, &RemainingDevicePath, &WholeDiskHandle);
+            //Print(L"  * remaining: %s\n", DevicePathToStr(RemainingDevicePath));
+            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;
+    }
+    
+    // default volume icon based on disk kind
+    ScanVolumeDefaultIcon(Volume);
+    
+    // open the root directory of the volume
+    Volume->RootDir = LibOpenRoot(Volume->DeviceHandle);
+    if (Volume->RootDir == NULL) {
+        return;
+    }
+    
+    // get volume name
+    FileSystemInfoPtr = LibFileSystemInfo(Volume->RootDir);
+    if (FileSystemInfoPtr != NULL) {
+        Volume->VolName = StrDuplicate(FileSystemInfoPtr->VolumeLabel);
+        FreePool(FileSystemInfoPtr);
+    }
+
+    // TODO: if no official volume name is found or it is empty, use something else, e.g.:
+    //   - name from bytes 3 to 10 of the boot sector
+    //   - partition number
+    //   - name derived from file system type or partition type
+
+    // get custom volume icon if present
+    if (FileExists(Volume->RootDir, L".VolumeIcon.icns"))
+        Volume->VolBadgeImage = LoadIcns(Volume->RootDir, L".VolumeIcon.icns", 32);
+}
+
+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 = PoolPrint(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;
+                
+                ScanVolumeDefaultIcon(Volume);
+                
+                AddListElement((VOID ***) &Volumes, &VolumesCount, Volume);
+                
+            }
+        }
+    }
+}
+
+VOID ScanVolumes(VOID)
+{
+    EFI_STATUS              Status;
+    UINTN                   HandleCount = 0;
+    UINTN                   HandleIndex;
+    EFI_HANDLE              *Handles;
+    REFIT_VOLUME            *Volume, *WholeDiskVolume;
+    UINTN                   VolumeIndex, VolumeIndex2;
+    MBR_PARTITION_INFO      *MbrTable;
+    UINTN                   PartitionIndex;
+    UINT8                   *SectorBuffer1, *SectorBuffer2;
+    UINTN                   SectorSum, i;
+
+    FreePool(Volumes);
+    Volumes = NULL;
+    VolumesCount = 0;
+
+    // get all filesystem handles
+    Status = LibLocateHandle(ByProtocol, &BlockIoProtocol, NULL, &HandleCount, &Handles);
+    // was: &FileSystemProtocol
+    if (Status == EFI_NOT_FOUND)
+        return;  // no filesystems. strange, but true...
+    if (CheckError(Status, L"while listing all file systems"))
+        return;
+
+    // first pass: collect information about all handles
+    for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
+        Volume = AllocateZeroPool(sizeof(REFIT_VOLUME));
+        Volume->DeviceHandle = Handles[HandleIndex];
+        ScanVolume(Volume);
+
+        AddListElement((VOID ***) &Volumes, &VolumesCount, Volume);
+
+        if (Volume->DeviceHandle == SelfLoadedImage->DeviceHandle)
+            SelfVolume = Volume;
+    }
+    FreePool(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 = PoolPrint(L"Partition %d", PartitionIndex + 1);
+                break;
+            }
+            
+            FreePool(SectorBuffer1);
+            FreePool(SectorBuffer2);
+        }
+        
+    }
+} /* VOID ScanVolumes() */
+
+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 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");
+        }
+    }
+}
+
+//
+// file and dir functions
+//
+
+BOOLEAN FileExists(IN EFI_FILE *BaseDir, IN CHAR16 *RelativePath)
+{
+    EFI_STATUS         Status;
+    EFI_FILE_HANDLE    TestFile;
+
+    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 = ReallocatePool(Buffer, LastBufferSize, BufferSize);
+            LastBufferSize = BufferSize;
+        }
+        if (EFI_ERROR(Status)) {
+            FreePool(Buffer);
+            break;
+        }
+        
+        // check for end of listing
+        if (BufferSize == 0) {    // end of directory listing
+            FreePool(Buffer);
+            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;
+}
+
+BOOLEAN DirIterNext(IN OUT REFIT_DIR_ITER *DirIter, IN UINTN FilterMode, IN CHAR16 *FilePattern OPTIONAL,
+                    OUT EFI_FILE_INFO **DirEntry)
+{
+    if (DirIter->LastFileInfo != NULL) {
+        FreePool(DirIter->LastFileInfo);
+        DirIter->LastFileInfo = NULL;
+    }
+    
+    if (EFI_ERROR(DirIter->LastStatus))
+        return FALSE;   // stop iteration
+    
+    for (;;) {
+        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))
+                break;
+            if (MetaiMatch(DirIter->LastFileInfo->FileName, FilePattern))
+                break;
+            // else continue loop
+        } else
+            break;
+    }
+    
+    *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)
+        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;
+}
+
+VOID ReplaceExtension(IN OUT CHAR16 *Path, IN CHAR16 *Extension)
+{
+    UINTN i;
+    
+    for (i = StrLen(Path); i >= 0; i--) {
+        if (Path[i] == '.') {
+            Path[i] = 0;
+            break;
+        }
+        if (Path[i] == '\\' || Path[i] == '/')
+            break;
+    }
+    StrCat(Path, Extension);
+}
+
+//
+// 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;
+}
+
+// Performs a case-insensitive search of BigStr for SmallStr.
+// Returns TRUE if found, FALSE if not.
+BOOLEAN StriSubCmp(IN CHAR16 *SmallStr, IN CHAR16 *BigStr) {
+   CHAR16 *SmallCopy, *BigCopy;
+   BOOLEAN Found = FALSE;
+   UINTN StartPoint = 0, NumCompares = 0, SmallLen = 0;
+
+   if ((SmallStr != NULL) && (BigStr != NULL) && (StrLen(BigStr) >= StrLen(SmallStr))) {
+      SmallCopy = StrDuplicate(SmallStr);
+      BigCopy = StrDuplicate(BigStr);
+      StrLwr(SmallCopy);
+      StrLwr(BigCopy);
+      SmallLen = StrLen(SmallCopy);
+      NumCompares = StrLen(BigCopy) - SmallLen + 1;
+      while ((!Found) && (StartPoint < NumCompares)) {
+         Found = (StrnCmp(SmallCopy, &BigCopy[StartPoint++], SmallLen) == 0);
+      } // while
+      FreePool(SmallCopy);
+      FreePool(BigCopy);
+   } // if
+   
+   return (Found);
+} // BOOLEAN StriSubCmp()
+
+// 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). 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));
+   NewString[0] = 0;
+   if (NewString != NULL) {
+      if (*First != NULL) {
+         StrCat(NewString, *First);
+         if (AddChar) {
+            NewString[Length1] = AddChar;
+            NewString[Length1 + 1] = 0;
+         } // if (AddChar)
+      } // if (First != NULL)
+      if (First != NULL)
+         StrCat(NewString, Second);
+      FreePool(*First);
+      *First = NewString;
+   } else {
+      Print(L"Error! Unable to allocate memory in MergeStrings()!\n");
+   } // if/else
+} // static CHAR16* MergeStrings()
+
+// 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;
+   
+   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'.
+CHAR16 *FindPath(IN CHAR16* FullPath) {
+   UINTN i, LastBackslash = 0;
+   CHAR16 *PathOnly;
+
+   for (i = 0; i < StrLen(FullPath); i++) {
+      if (FullPath[i] == '\\')
+         LastBackslash = i;
+   } // for
+   PathOnly = StrDuplicate(FullPath);
+   PathOnly[LastBackslash] = 0;
+   return (PathOnly);
+}
+
+// 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". If InString contains no digits,
+// the return value is NULL.
+CHAR16 *FindNumbers(IN CHAR16 *InString) {
+   UINTN i, StartOfElement, EndOfElement = 0, InLength, CopyLength;
+   CHAR16 *Found = NULL;
+   
+   InLength = StartOfElement = StrLen(InString);
+   // Find start & end of target element
+   for (i = 0; i < InLength; i++) {
+      if ((InString[i] >= '0') && (InString[i] <= '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()
diff --git a/refind/lib.h b/refind/lib.h
new file mode 100644 (file)
index 0000000..9d8263f
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * 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 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_
+
+#include "efi.h"
+#include "efilib.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 IS_EXTENDED_PART_TYPE(type) ((type) == 0x05 || (type) == 0x0f || (type) == 0x85)
+
+EFI_STATUS InitRefitLib(IN EFI_HANDLE ImageHandle);
+VOID UninitRefitLib(VOID);
+EFI_STATUS ReinitRefitLib(VOID);
+
+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 /*, IN Callback*/);
+
+VOID ExtractLegacyLoaderPaths(EFI_DEVICE_PATH **PathList, UINTN MaxPaths, EFI_DEVICE_PATH **HardcodedPathList);
+
+VOID ScanVolumes(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);
+VOID ReplaceExtension(IN OUT CHAR16 *Path, IN CHAR16 *Extension);
+
+INTN FindMem(IN VOID *Buffer, IN UINTN BufferLength, IN VOID *SearchString, IN UINTN SearchStringLength);
+VOID ReinitVolumes(VOID);
+
+BOOLEAN StriSubCmp(IN CHAR16 *TargetStr, IN CHAR16 *BigStr);
+VOID MergeStrings(IN OUT CHAR16 **First, IN CHAR16 *Second, CHAR16 AddChar);
+CHAR16 *FindLastDirName(IN CHAR16 *Path);
+CHAR16 *FindPath(IN CHAR16* FullPath);
+CHAR16 *FindNumbers(IN CHAR16 *InString);
+
+#endif
\ No newline at end of file
diff --git a/refind/main.c b/refind/main.c
new file mode 100644 (file)
index 0000000..b1839c9
--- /dev/null
@@ -0,0 +1,1373 @@
+/*
+ * 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 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"
+#include "config.h"
+#include "screen.h"
+#include "lib.h"
+#include "icns.h"
+#include "menu.h"
+#include "refit_call_wrapper.h"
+#include "../include/syslinux_mbr.h"
+
+// 
+// variables
+
+#define MACOSX_LOADER_PATH      L"\\System\\Library\\CoreServices\\boot.efi"
+
+static REFIT_MENU_ENTRY MenuEntryAbout    = { L"About rEFInd", TAG_ABOUT, 1, 0, 'A', NULL, NULL, NULL };
+static REFIT_MENU_ENTRY MenuEntryReset    = { L"Restart Computer", TAG_RESET, 1, 0, 'R', NULL, NULL, NULL };
+static REFIT_MENU_ENTRY MenuEntryShutdown = { L"Shut Down Computer", TAG_SHUTDOWN, 1, 0, 'U', NULL, NULL, NULL };
+static REFIT_MENU_ENTRY MenuEntryReturn   = { L"Return to Main Menu", TAG_RETURN, 0, 0, 0, NULL, NULL, NULL };
+
+static REFIT_MENU_SCREEN MainMenu       = { L"Main Menu", NULL, 0, NULL, 0, NULL, 0, L"Automatic boot" };
+static REFIT_MENU_SCREEN AboutMenu      = { L"About", NULL, 0, NULL, 0, NULL, 0, NULL };
+
+REFIT_CONFIG        GlobalConfig = { FALSE, 20, 0, 0, FALSE, NULL, NULL, NULL, NULL };
+
+//
+// misc functions
+//
+
+static VOID AboutrEFInd(VOID)
+{
+    if (AboutMenu.EntryCount == 0) {
+        AboutMenu.TitleImage = BuiltinIcon(BUILTIN_ICON_FUNC_ABOUT);
+        AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.2.2");
+        AddMenuInfoLine(&AboutMenu, L"");
+        AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2006-2010 Christoph Pfisterer");
+        AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2012 Roderick W. Smith");
+        AddMenuInfoLine(&AboutMenu, L"Portions Copyright (c) Intel Corporation and others");
+        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, L" Platform: x86 (32 bit)");
+#elif defined(EFIX64)
+        AddMenuInfoLine(&AboutMenu, L" Platform: x86_64 (64 bit)");
+#else
+        AddMenuInfoLine(&AboutMenu, L" Platform: unknown");
+#endif
+        AddMenuInfoLine(&AboutMenu, PoolPrint(L" Firmware: %s %d.%02d",
+            ST->FirmwareVendor, ST->FirmwareRevision >> 16, ST->FirmwareRevision & ((1 << 16) - 1)));
+        AddMenuInfoLine(&AboutMenu, PoolPrint(L" Screen Output: %s", egScreenDescription()));
+        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 EFI_STATUS StartEFIImageList(IN EFI_DEVICE_PATH **DevicePaths,
+                                    IN CHAR16 *LoadOptions, IN CHAR16 *LoadOptionsPrefix,
+                                    IN CHAR16 *ImageTitle,
+                                    OUT UINTN *ErrorInStep)
+{
+    EFI_STATUS              Status, ReturnStatus;
+    EFI_HANDLE              ChildImageHandle;
+    EFI_LOADED_IMAGE        *ChildLoadedImage;
+    UINTN                   DevicePathIndex;
+    CHAR16                  ErrorInfo[256];
+    CHAR16                  *FullLoadOptions = NULL;
+
+    Print(L"Starting %s\n", ImageTitle);
+    if (ErrorInStep != NULL)
+        *ErrorInStep = 0;
+
+    // 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;
+    }
+    SPrint(ErrorInfo, 255, L"while loading %s", ImageTitle);
+    if (CheckError(Status, ErrorInfo)) {
+        if (ErrorInStep != NULL)
+            *ErrorInStep = 1;
+        goto bailout;
+    }
+
+    // set load options
+    if (LoadOptions != NULL) {
+      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;
+        }
+        
+        if (LoadOptionsPrefix != NULL) {
+            FullLoadOptions = PoolPrint(L"%s %s ", LoadOptionsPrefix, LoadOptions);
+            // NOTE: That last space is also added by the EFI shell and seems to be significant
+            //  when passing options to Apple's boot.efi...
+            LoadOptions = FullLoadOptions;
+        }
+        // NOTE: We also include the terminating null in the length for safety.
+        ChildLoadedImage->LoadOptions = (VOID *)LoadOptions;
+        ChildLoadedImage->LoadOptionsSize = ((UINT32)StrLen(LoadOptions) + 1) * sizeof(CHAR16);
+        Print(L"Using load options '%s'\n", LoadOptions);
+    }
+
+    // close open file handles
+    UninitRefitLib();
+
+    // turn control over to the image
+    // TODO: (optionally) re-enable the EFI watchdog timer!
+    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;
+    }
+    
+    // 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:
+    if (FullLoadOptions != NULL)
+        FreePool(FullLoadOptions);
+    return ReturnStatus;
+} /* static EFI_STATUS StartEFIImageList() */
+
+static EFI_STATUS StartEFIImage(IN EFI_DEVICE_PATH *DevicePath,
+                                IN CHAR16 *LoadOptions, IN CHAR16 *LoadOptionsPrefix,
+                                IN CHAR16 *ImageTitle,
+                                OUT UINTN *ErrorInStep)
+{
+    EFI_DEVICE_PATH *DevicePaths[2];
+    
+    DevicePaths[0] = DevicePath;
+    DevicePaths[1] = NULL;
+    return StartEFIImageList(DevicePaths, LoadOptions, LoadOptionsPrefix, ImageTitle, ErrorInStep);
+} /* static EFI_STATUS StartEFIImage() */
+
+//
+// EFI OS loader functions
+//
+
+static VOID StartLoader(IN LOADER_ENTRY *Entry)
+{
+    BeginExternalScreen(Entry->UseGraphicsMode, L"Booting OS");
+    StartEFIImage(Entry->DevicePath, Entry->LoadOptions,
+                  Basename(Entry->LoaderPath), Basename(Entry->LoaderPath), NULL);
+    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;
+// however, initmine-3.3.0.img might match. (FindInitrd() returns the first match it
+// finds). Thus, care should be taken to avoid placing duplicate matching files in
+// the kernel's directory.
+// 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;
+   REFIT_DIR_ITER      DirIter;
+   EFI_FILE_INFO       *DirEntry;
+
+   FileName = Basename(LoaderPath);
+   KernelVersion = FindNumbers(FileName);
+   Path = FindPath(LoaderPath);
+
+   DirIterOpen(Volume->RootDir, Path, &DirIter);
+   while ((DirIterNext(&DirIter, 2, L"init*", &DirEntry)) && (InitrdName == NULL)) {
+      InitrdVersion = FindNumbers(DirEntry->FileName);
+      if (KernelVersion != NULL) {
+//         if (StriSubCmp(KernelVersion, DirEntry->FileName)) {
+            if (StriCmp(InitrdVersion, KernelVersion) == 0)
+               InitrdName = PoolPrint(L"%s\\%s", Path, DirEntry->FileName);
+//         } // if match found
+      } else {
+         if (InitrdVersion == NULL)
+            InitrdName = PoolPrint(L"%s\\%s", Path, DirEntry->FileName);
+      } // if/else
+      if (InitrdVersion != NULL)
+         FreePool(InitrdVersion);
+   } // while
+   DirIterClose(&DirIter);
+
+   // Note: Don't FreePool(FileName), since Basename returns a pointer WITHIN the string it's passed.
+   FreePool(KernelVersion);
+   FreePool(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 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      = StrDuplicate(Entry->LoaderPath);
+         NewEntry->VolName         = StrDuplicate(Entry->VolName);
+         NewEntry->DevicePath      = Entry->DevicePath;
+         NewEntry->UseGraphicsMode = Entry->UseGraphicsMode;
+         NewEntry->LoadOptions     = StrDuplicate(Entry->LoadOptions);
+         NewEntry->InitrdPath      = StrDuplicate(Entry->InitrdPath);
+      }
+   } // if
+   return (NewEntry);
+} // LOADER_ENTRY *InitializeLoaderEntry()
+
+// 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, *Temp;
+   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 = PoolPrint(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 = L"Boot using default options";
+//            SubEntry->me.Title = (Entry->OSType == 'M') ? L"Boot Mac OS X" : PoolPrint(L"Run %s", FileName);
+            if ((SubEntry->InitrdPath != NULL) && (StrLen(SubEntry->InitrdPath) > 0) && (!StriSubCmp(L"initrd", SubEntry->LoadOptions))) {
+               Temp = PoolPrint(L"initrd=%s", SubEntry->InitrdPath);
+               MergeStrings(&SubEntry->LoadOptions, Temp, L' ');
+               FreePool(Temp);
+            } // if
+            AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry);
+         } // if (SubEntry != NULL)
+      } // 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) {
+   REFIT_MENU_SCREEN  *SubScreen;
+   LOADER_ENTRY       *SubEntry;
+   CHAR16             *FileName, *InitrdOption = NULL, *Temp;
+   CHAR16             DiagsFileName[256];
+   REFIT_FILE         *File;
+   UINTN              TokenCount;
+   CHAR16             **TokenList;
+
+   FileName = Basename(Entry->LoaderPath);
+   // create the submenu
+   if (StrLen(Entry->Title) == 0) {
+      FreePool(Entry->Title);
+      Entry->Title = NULL;
+   }
+   SubScreen = InitializeSubScreen(Entry);
+   
+   // loader-specific submenu entries
+   if (Entry->OSType == 'M') {          // entries for Mac OS X
+#if defined(EFIX64)
+      SubEntry = InitializeLoaderEntry(Entry);
+      if (SubEntry != NULL) {
+         SubEntry->me.Title        = L"Boot Mac OS X with a 64-bit kernel";
+         SubEntry->LoadOptions     = L"arch=x86_64";
+         AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry);
+      } // if
+
+      SubEntry = InitializeLoaderEntry(Entry);
+      if (SubEntry != NULL) {
+         SubEntry->me.Title        = L"Boot Mac OS X with a 32-bit kernel";
+         SubEntry->LoadOptions     = L"arch=i386";
+         AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry);
+      } // if
+#endif
+
+      if (!(GlobalConfig.DisableFlags & DISABLE_FLAG_SINGLEUSER)) {
+         SubEntry = InitializeLoaderEntry(Entry);
+         if (SubEntry != NULL) {
+            SubEntry->me.Title        = L"Boot Mac OS X 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 Mac OS X 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 Mac OS X 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 Mac OS X in single user mode";
+            SubEntry->UseGraphicsMode = FALSE;
+            SubEntry->LoadOptions     = L"-v -s";
+            AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry);
+         } // if
+      } // not single-user
+
+      // check for Apple hardware diagnostics
+      StrCpy(DiagsFileName, L"\\System\\Library\\CoreServices\\.diagnostics\\diags.efi");
+      if (FileExists(Volume->RootDir, DiagsFileName) && !(GlobalConfig.DisableFlags & DISABLE_FLAG_HWTEST)) {
+         SubEntry = InitializeLoaderEntry(Entry);
+         if (SubEntry != NULL) {
+            SubEntry->me.Title        = L"Run Apple Hardware Test";
+            FreePool(SubEntry->LoaderPath);
+            SubEntry->LoaderPath      = StrDuplicate(DiagsFileName);
+            SubEntry->DevicePath      = FileDevicePath(Volume->DeviceHandle, SubEntry->LoaderPath);
+            SubEntry->UseGraphicsMode = TRUE;
+            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) {
+         if ((Temp = FindInitrd(Entry->LoaderPath, Volume)) != NULL)
+            InitrdOption = PoolPrint(L"initrd=%s", Temp);
+         TokenCount = ReadTokenLine(File, &TokenList); // read and discard first entry, since it's
+         FreeTokenLine(&TokenList, &TokenCount);       // set up by InitializeSubScreen(), earlier....
+         while ((TokenCount = ReadTokenLine(File, &TokenList)) > 1) {
+            SubEntry = InitializeLoaderEntry(Entry);
+            SubEntry->me.Title = StrDuplicate(TokenList[0]);
+            if (SubEntry->LoadOptions != NULL)
+               FreePool(SubEntry->LoadOptions);
+            SubEntry->LoadOptions = StrDuplicate(TokenList[1]);
+            MergeStrings(&SubEntry->LoadOptions, InitrdOption, L' ');
+            FreeTokenLine(&TokenList, &TokenCount);
+            AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry);
+         } // while
+         if (InitrdOption)
+            FreePool(InitrdOption);
+         if (Temp)
+            FreePool(Temp);
+         FreePool(File);
+      } // if Linux options file exists
+
+   } else if (Entry->OSType == 'E') {   // entries for ELILO
+      SubEntry = InitializeLoaderEntry(Entry);
+      if (SubEntry != NULL) {
+         SubEntry->me.Title        = PoolPrint(L"Run %s in interactive mode", FileName);
+         SubEntry->LoadOptions     = L"-p";
+         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->UseGraphicsMode = TRUE;
+         SubEntry->LoadOptions     = L"-d 0 i17";
+         AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry);
+      }
+
+      SubEntry = InitializeLoaderEntry(Entry);
+      if (SubEntry != NULL) {
+         SubEntry->me.Title        = L"Boot Linux for a 20\" iMac (*)";
+         SubEntry->UseGraphicsMode = TRUE;
+         SubEntry->LoadOptions     = L"-d 0 i20";
+         AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry);
+      }
+
+      SubEntry = InitializeLoaderEntry(Entry);
+      if (SubEntry != NULL) {
+         SubEntry->me.Title        = L"Boot Linux for a Mac Mini (*)";
+         SubEntry->UseGraphicsMode = TRUE;
+         SubEntry->LoadOptions     = L"-d 0 mini";
+         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";
+           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";
+           AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry);
+        }
+
+        SubEntry = InitializeLoaderEntry(Entry);
+        if (SubEntry != NULL) {
+           SubEntry->me.Title        = PoolPrint(L"Run %s in text mode", FileName);
+           SubEntry->UseGraphicsMode = FALSE;
+           SubEntry->LoadOptions     = L"-v";
+           AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry);
+        }
+   } // entries for xom.efi
+   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, *InitrdOption = NULL;
+
+   Options = GetFirstOptionsFromFile(LoaderPath, Volume);
+   InitrdName = FindInitrd(LoaderPath, Volume);
+   if (InitrdName != NULL)
+      InitrdOption = PoolPrint(L"initrd=%s", InitrdName);
+   MergeStrings(&Options, InitrdOption, ' ');
+   if (InitrdOption != NULL)
+      FreePool(InitrdOption);
+   if (InitrdName != NULL)
+      FreePool(InitrdName);
+   return (Options);
+} // static CHAR16 * GetMainLinuxOptions()
+
+// 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, IN REFIT_VOLUME *Volume) {
+   CHAR16          IconFileName[256];
+   CHAR16          *FileName, *OSIconName = NULL, *Temp;
+   CHAR16          ShortcutLetter = 0;
+
+   FileName = Basename(LoaderPath);
+   
+   // locate a custom icon for the loader
+   StrCpy(IconFileName, LoaderPath);
+   ReplaceExtension(IconFileName, L".icns");
+   if (FileExists(Volume->RootDir, IconFileName)) {
+      Entry->me.Image = LoadIcns(Volume->RootDir, IconFileName, 128);
+   } // if
+   
+   Temp = FindLastDirName(LoaderPath);
+   MergeStrings(&OSIconName, Temp, L',');
+   FreePool(Temp);
+   if (OSIconName != NULL) {
+      ShortcutLetter = OSIconName[0];
+   }
+
+   // detect specific loaders
+   if (StriSubCmp(L"bzImage", LoaderPath) || StriSubCmp(L"vmlinuz", LoaderPath)) {
+      MergeStrings(&OSIconName, L"linux", L',');
+      Entry->OSType = 'L';
+      if (ShortcutLetter == 0)
+         ShortcutLetter = 'L';
+      Entry->LoadOptions = GetMainLinuxOptions(LoaderPath, Volume);
+   } else if (StriSubCmp(L"refit", LoaderPath)) {
+      MergeStrings(&OSIconName, L"refit", L',');
+      Entry->OSType = 'R';
+      ShortcutLetter = 'R';
+   } else if (StriCmp(LoaderPath, MACOSX_LOADER_PATH) == 0) {
+      MergeStrings(&OSIconName, L"mac", L',');
+      Entry->UseGraphicsMode = TRUE;
+      Entry->OSType = 'M';
+      ShortcutLetter = 'M';
+   } else if (StriCmp(FileName, L"diags.efi") == 0) {
+      MergeStrings(&OSIconName, L"hwtest", L',');
+   } else if (StriCmp(FileName, L"e.efi") == 0 || StriCmp(FileName, L"elilo.efi") == 0) {
+      MergeStrings(&OSIconName, L"elilo,linux", L',');
+      Entry->OSType = 'E';
+      if (ShortcutLetter == 0)
+         ShortcutLetter = 'L';
+   } else if (StriCmp(FileName, L"cdboot.efi") == 0 ||
+              StriCmp(FileName, L"bootmgr.efi") == 0 ||
+              StriCmp(FileName, L"Bootmgfw.efi") == 0) {
+      MergeStrings(&OSIconName, L"win", L',');
+      Entry->OSType = 'W';
+      ShortcutLetter = 'W';
+   } else if (StriCmp(FileName, L"xom.efi") == 0) {
+      MergeStrings(&OSIconName, L"xom,win", L',');
+      Entry->UseGraphicsMode = TRUE;
+      Entry->OSType = 'X';
+      ShortcutLetter = 'W';
+   }
+
+   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);
+} // VOID SetLoaderDefaults()
+      
+// Add a specified EFI boot loader to the list, using automatic settings
+// for icons, options, etc.
+LOADER_ENTRY * AddLoaderEntry(IN CHAR16 *LoaderPath, IN CHAR16 *LoaderTitle, IN REFIT_VOLUME *Volume) {
+   LOADER_ENTRY      *Entry;
+
+   Entry = InitializeLoaderEntry(NULL);
+   if (Entry != NULL) {
+      Entry->Title = StrDuplicate(LoaderTitle);
+      Entry->me.Title = PoolPrint(L"Boot %s from %s", (LoaderTitle != NULL) ? LoaderTitle : LoaderPath + 1, Volume->VolName);
+      Entry->me.Row = 0;
+      Entry->me.BadgeImage = Volume->VolBadgeImage;
+      Entry->LoaderPath = StrDuplicate(LoaderPath);
+      Entry->VolName = Volume->VolName;
+      Entry->DevicePath = FileDevicePath(Volume->DeviceHandle, Entry->LoaderPath);
+      SetLoaderDefaults(Entry, LoaderPath, Volume);
+      GenerateSubScreen(Entry, Volume);
+      AddMenuEntry(&MainMenu, (REFIT_MENU_ENTRY *)Entry);
+   }
+   
+   return(Entry);
+} // LOADER_ENTRY * AddLoaderEntry()
+
+// Scan an individual directory for EFI boot loader files and, if found,
+// add them to the list.
+static VOID ScanLoaderDir(IN REFIT_VOLUME *Volume, IN CHAR16 *Path)
+{
+    EFI_STATUS              Status;
+    REFIT_DIR_ITER          DirIter;
+    EFI_FILE_INFO           *DirEntry;
+    CHAR16                  FileName[256];
+
+    // Note: SelfDirPath includes a leading backslash ('\'), but Path
+    // doesn't, so we rejigger the string to compensate....
+    if (!SelfDirPath || !Path || ((StriCmp(Path, &SelfDirPath[1]) == 0) && Volume != SelfVolume) ||
+        (StriCmp(Path, &SelfDirPath[1]) != 0)) {
+       // look through contents of the directory
+       DirIterOpen(Volume->RootDir, Path, &DirIter);
+       while (DirIterNext(&DirIter, 2, L"*.efi", &DirEntry)) {
+          if (DirEntry->FileName[0] == '.' ||
+              StriCmp(DirEntry->FileName, L"TextMode.efi") == 0 ||
+              StriCmp(DirEntry->FileName, L"ebounce.efi") == 0 ||
+              StriCmp(DirEntry->FileName, L"GraphicsConsole.efi") == 0)
+                continue;   // skip this
+
+          if (Path)
+                SPrint(FileName, 255, L"\\%s\\%s", Path, DirEntry->FileName);
+          else
+                SPrint(FileName, 255, L"\\%s", DirEntry->FileName);
+          AddLoaderEntry(FileName, NULL, Volume);
+       }
+       Status = DirIterClose(&DirIter);
+       if (Status != EFI_NOT_FOUND) {
+          if (Path)
+                SPrint(FileName, 255, L"while scanning the %s directory", Path);
+          else
+                StrCpy(FileName, L"while scanning the root directory");
+          CheckError(Status, FileName);
+       } // if (Status != EFI_NOT_FOUND)
+    } // if not scanning our own directory
+} /* static VOID ScanLoaderDir() */
+
+static VOID ScanEfiFiles(REFIT_VOLUME *Volume) {
+   EFI_STATUS              Status;
+   REFIT_DIR_ITER          EfiDirIter;
+   EFI_FILE_INFO           *EfiDirEntry;
+   CHAR16                  FileName[256];
+//   LOADER_ENTRY            *Entry;
+
+   if ((Volume->RootDir != NULL) && (Volume->VolName != NULL)) {
+      // check for Mac OS X boot loader
+      StrCpy(FileName, MACOSX_LOADER_PATH);
+      if (FileExists(Volume->RootDir, FileName)) {
+         AddLoaderEntry(FileName, L"Mac OS X", Volume);
+      }
+
+      // check for XOM
+      StrCpy(FileName, L"\\System\\Library\\CoreServices\\xom.efi");
+      if (FileExists(Volume->RootDir, FileName)) {
+         AddLoaderEntry(FileName, L"Windows XP (XoM)", Volume);
+      }
+
+      // check for Microsoft boot loader/menu
+      StrCpy(FileName, L"\\EFI\\Microsoft\\Boot\\Bootmgfw.efi");
+      if (FileExists(Volume->RootDir, FileName)) {
+         AddLoaderEntry(FileName, L"Microsoft EFI boot", Volume);
+      }
+
+      // scan the root directory for EFI executables
+      ScanLoaderDir(Volume, NULL);
+      // scan the elilo directory (as used on gimli's first Live CD)
+      ScanLoaderDir(Volume, L"elilo");
+      // scan the boot directory
+      ScanLoaderDir(Volume, L"boot");
+
+      // scan subdirectories of the EFI directory (as per the standard)
+      DirIterOpen(Volume->RootDir, L"EFI", &EfiDirIter);
+      while (DirIterNext(&EfiDirIter, 1, NULL, &EfiDirEntry)) {
+         if (StriCmp(EfiDirEntry->FileName, L"TOOLS") == 0 || EfiDirEntry->FileName[0] == '.')
+            continue;   // skip this, doesn't contain boot loaders
+         SPrint(FileName, 255, L"EFI\\%s", EfiDirEntry->FileName);
+         ScanLoaderDir(Volume, FileName);
+      } // while()
+      Status = DirIterClose(&EfiDirIter);
+      if (Status != EFI_NOT_FOUND)
+         CheckError(Status, L"while scanning the EFI directory");
+   } // 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()
+
+//
+// legacy boot functions
+//
+
+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() */
+
+// 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)
+
+static VOID StartLegacy(IN LEGACY_ENTRY *Entry)
+{
+    EFI_STATUS          Status;
+    EG_IMAGE            *BootLogoImage;
+    UINTN               ErrorInStep = 0;
+    EFI_DEVICE_PATH     *DiscoveredPathList[MAX_DISCOVERED_PATHS];
+
+    BeginExternalScreen(TRUE, L"Booting Legacy OS");
+
+    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);
+
+    ExtractLegacyLoaderPaths(DiscoveredPathList, MAX_DISCOVERED_PATHS, LegacyLoaderList);
+
+    Status = StartEFIImageList(DiscoveredPathList, Entry->LoadOptions, NULL, L"legacy loader", &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() */
+
+static LEGACY_ENTRY * AddLegacyEntry(IN CHAR16 *LoaderTitle, IN REFIT_VOLUME *Volume)
+{
+    LEGACY_ENTRY            *Entry, *SubEntry;
+    REFIT_MENU_SCREEN       *SubScreen;
+    CHAR16                  *VolDesc;
+    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";
+
+    // prepare the menu entry
+    Entry = AllocateZeroPool(sizeof(LEGACY_ENTRY));
+    Entry->me.Title        = PoolPrint(L"Boot %s from %s", LoaderTitle, VolDesc);
+    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 = PoolPrint(L"Boot Options for %s on %s", LoaderTitle, VolDesc);
+    SubScreen->TitleImage = Entry->me.Image;
+
+    // default entry
+    SubEntry = AllocateZeroPool(sizeof(LEGACY_ENTRY));
+    SubEntry->me.Title        = PoolPrint(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() */
+
+static VOID ScanLegacyVolume(REFIT_VOLUME *Volume, UINTN VolumeIndex) {
+   UINTN VolumeIndex2;
+   BOOLEAN ShowVolume, HideIfOthersFound;
+
+   ShowVolume = FALSE;
+   HideIfOthersFound = FALSE;
+   if (Volume->IsAppleLegacy) {
+      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....
+static VOID ScanLegacyDisc(VOID)
+{
+   UINTN                   VolumeIndex;
+   REFIT_VOLUME            *Volume;
+
+   for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) {
+      Volume = Volumes[VolumeIndex];
+      if (Volume->DiskKind == DISK_KIND_OPTICAL)
+         ScanLegacyVolume(Volume, VolumeIndex);
+   } // for
+} /* static VOID ScanLegacyDisc() */
+
+// Scan internal hard disks for legacy (BIOS) boot code
+// and add anything found to the list....
+static VOID ScanLegacyInternal(VOID)
+{
+    UINTN                   VolumeIndex;
+    REFIT_VOLUME            *Volume;
+
+    for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) {
+        Volume = Volumes[VolumeIndex];
+        if (Volume->DiskKind == DISK_KIND_INTERNAL)
+            ScanLegacyVolume(Volume, VolumeIndex);
+    } // for
+} /* static VOID ScanLegacyInternal() */
+
+// Scan external disks for legacy (BIOS) boot code
+// and add anything found to the list....
+static VOID ScanLegacyExternal(VOID)
+{
+   UINTN                   VolumeIndex;
+   REFIT_VOLUME            *Volume;
+
+   for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) {
+      Volume = Volumes[VolumeIndex];
+      if (Volume->DiskKind == DISK_KIND_EXTERNAL)
+         ScanLegacyVolume(Volume, VolumeIndex);
+   } // for
+} /* static VOID ScanLegacyExternal() */
+
+//
+// pre-boot tool functions
+//
+
+static VOID StartTool(IN LOADER_ENTRY *Entry)
+{
+    BeginExternalScreen(Entry->UseGraphicsMode, Entry->me.Title + 6);  // assumes "Start <title>" as assigned below
+    StartEFIImage(Entry->DevicePath, Entry->LoadOptions, Basename(Entry->LoaderPath),
+                  Basename(Entry->LoaderPath), NULL);
+    FinishExternalScreen();
+} /* static VOID StartTool() */
+
+static LOADER_ENTRY * AddToolEntry(IN CHAR16 *LoaderPath, IN CHAR16 *LoaderTitle, IN EG_IMAGE *Image,
+                                   IN CHAR16 ShortcutLetter, IN BOOLEAN UseGraphicsMode)
+{
+    LOADER_ENTRY *Entry;
+
+    Entry = AllocateZeroPool(sizeof(LOADER_ENTRY));
+
+    Entry->me.Title = PoolPrint(L"Start %s", LoaderTitle);
+    Entry->me.Tag = TAG_TOOL;
+    Entry->me.Row = 1;
+    Entry->me.ShortcutLetter = ShortcutLetter;
+    Entry->me.Image = Image;
+    Entry->LoaderPath = StrDuplicate(LoaderPath);
+    Entry->DevicePath = FileDevicePath(SelfLoadedImage->DeviceHandle, Entry->LoaderPath);
+    Entry->UseGraphicsMode = UseGraphicsMode;
+
+    AddMenuEntry(&MainMenu, (REFIT_MENU_ENTRY *)Entry);
+    return Entry;
+} /* static LOADER_ENTRY * AddToolEntry() */
+
+static VOID ScanTool(VOID)
+{
+    CHAR16                  FileName[256];
+    LOADER_ENTRY            *Entry;
+
+    if (GlobalConfig.DisableFlags & DISABLE_FLAG_TOOLS)
+        return;
+
+    // look for the EFI shell
+    if (!(GlobalConfig.DisableFlags & DISABLE_FLAG_SHELL)) {
+        SPrint(FileName, 255, L"%s\\apps\\shell.efi", SelfDirPath);
+        if (FileExists(SelfRootDir, FileName)) {
+            AddToolEntry(FileName, L"EFI Shell", BuiltinIcon(BUILTIN_ICON_TOOL_SHELL), 'E', FALSE);
+        } else {
+            StrCpy(FileName, L"\\efi\\tools\\shell.efi");
+            if (FileExists(SelfRootDir, FileName)) {
+                AddToolEntry(FileName, L"EFI Shell", BuiltinIcon(BUILTIN_ICON_TOOL_SHELL), 'E', FALSE);
+            }
+        }
+    }
+
+    // look for the GPT/MBR sync tool
+    StrCpy(FileName, L"\\efi\\tools\\gptsync.efi");
+    if (FileExists(SelfRootDir, FileName)) {
+        AddToolEntry(FileName, L"Make Hybrid MBR", BuiltinIcon(BUILTIN_ICON_TOOL_PART), 'P', FALSE);
+    }
+
+    // look for rescue Linux
+    StrCpy(FileName, L"\\efi\\rescue\\elilo.efi");
+    if (SelfVolume != NULL && FileExists(SelfRootDir, FileName)) {
+        Entry = AddToolEntry(FileName, L"Rescue Linux", BuiltinIcon(BUILTIN_ICON_TOOL_RESCUE), '0', FALSE);
+        
+        if (UGAWidth == 1440 && UGAHeight == 900)
+            Entry->LoadOptions = L"-d 0 i17";
+        else if (UGAWidth == 1680 && UGAHeight == 1050)
+            Entry->LoadOptions = L"-d 0 i20";
+        else
+            Entry->LoadOptions = L"-d 0 mini";
+    }
+}
+
+
+#ifdef DEBIAN_ENABLE_EFI110
+//
+// pre-boot driver functions
+//
+
+static VOID ScanDriverDir(IN CHAR16 *Path)
+{
+    EFI_STATUS              Status;
+    REFIT_DIR_ITER          DirIter;
+    EFI_FILE_INFO           *DirEntry;
+    CHAR16                  FileName[256];
+    
+    // look through contents of the directory
+    DirIterOpen(SelfRootDir, Path, &DirIter);
+    while (DirIterNext(&DirIter, 2, L"*.EFI", &DirEntry)) {
+        if (DirEntry->FileName[0] == '.')
+            continue;   // skip this
+        
+        SPrint(FileName, 255, L"%s\\%s", Path, DirEntry->FileName);
+        Status = StartEFIImage(FileDevicePath(SelfLoadedImage->DeviceHandle, FileName),
+                               L"", DirEntry->FileName, DirEntry->FileName, NULL);
+    }
+    Status = DirIterClose(&DirIter);
+    if (Status != EFI_NOT_FOUND) {
+        SPrint(FileName, 255, L"while scanning the %s directory", Path);
+        CheckError(Status, FileName);
+    }
+}
+
+static 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;
+            }
+            
+            if (!Parent) {
+                if (HandleType[Index] & EFI_HANDLE_TYPE_DEVICE_HANDLE) {
+                    Status = refit_call4_wrapper(BS->ConnectController,
+                                                 AllHandleBuffer[Index],
+                                                 NULL,
+                                                 NULL,
+                                                 TRUE);
+                }
+            }
+        }
+        
+        FreePool (HandleBuffer);
+        FreePool (HandleType);
+    }
+    
+Done:
+    FreePool (AllHandleBuffer);
+    return Status;
+}
+
+static VOID LoadDrivers(VOID)
+{
+    CHAR16                  DirName[256];
+
+    // load drivers from /efi/refind/drivers
+    SPrint(DirName, 255, L"%s\\drivers", SelfDirPath);
+    ScanDriverDir(DirName);
+
+    // load drivers from /efi/tools/drivers
+    ScanDriverDir(L"\\efi\\tools\\drivers");
+
+    // connect all devices
+    ConnectAllDriversToAllControllers();
+}
+#endif /* DEBIAN_ENABLE_EFI110 */
+
+static VOID ScanForBootloaders(VOID) {
+   UINTN i;
+
+   ScanVolumes();
+   // Commented-out below: Was part of an attempt to get rEFInd to
+   // re-scan disk devices on pressing Esc; but doesn't work (yet), so
+   // removed....
+//     MainMenu.Title = StrDuplicate(L"Main Menu 2");
+//     MainMenu.TitleImage = NULL;
+//     MainMenu.InfoLineCount = 0;
+//     MainMenu.InfoLines = NULL;
+//     MainMenu.EntryCount = 0;
+//     MainMenu.Entries = NULL;
+//     MainMenu.TimeoutSeconds = 20;
+//     MainMenu.TimeoutText = StrDuplicate(L"Automatic boot");
+   //    DebugPause();
+
+   // 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();
+            break;
+         case 'e': case 'E':
+            ScanExternal();
+            break;
+         case 'i': case 'I':
+            ScanInternal();
+            break;
+         case 'o': case 'O':
+            ScanOptical();
+            break;
+      } // switch()
+   } // for
+   ScanTool();
+
+   // fixed other menu entries
+   if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_FUNCS)) {
+      MenuEntryAbout.Image = BuiltinIcon(BUILTIN_ICON_FUNC_ABOUT);
+      AddMenuEntry(&MainMenu, &MenuEntryAbout);
+   }
+   if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_FUNCS) || MainMenu.EntryCount == 0) {
+      MenuEntryShutdown.Image = BuiltinIcon(BUILTIN_ICON_FUNC_SHUTDOWN);
+      AddMenuEntry(&MainMenu, &MenuEntryShutdown);
+      MenuEntryReset.Image = BuiltinIcon(BUILTIN_ICON_FUNC_RESET);
+      AddMenuEntry(&MainMenu, &MenuEntryReset);
+   }
+   
+   // 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()
+
+//
+// main entry point
+//
+
+EFI_STATUS
+EFIAPI
+efi_main (IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable)
+{
+    EFI_STATUS Status;
+    BOOLEAN MainLoopRunning = TRUE;
+    REFIT_MENU_ENTRY *ChosenEntry;
+    UINTN MenuExit;
+
+    // bootstrap
+    InitializeLib(ImageHandle, SystemTable);
+    InitScreen();
+    Status = InitRefitLib(ImageHandle);
+    if (EFI_ERROR(Status))
+        return Status;
+
+    // read configuration
+    CopyMem(GlobalConfig.ScanFor, "ieo       ", NUM_SCAN_OPTIONS);
+    ReadConfig();
+    MainMenu.TimeoutSeconds = GlobalConfig.Timeout;
+
+    // disable EFI watchdog timer
+    refit_call4_wrapper(BS->SetWatchdogTimer, 0x0000, 0x0000, 0x0000, NULL);
+
+    // further bootstrap (now with config available)
+    SetupScreen();
+#ifdef DEBIAN_ENABLE_EFI110
+    LoadDrivers();
+#endif /* DEBIAN_ENABLE_EFI110 */
+    ScanForBootloaders();
+
+    while (MainLoopRunning) {
+        MenuExit = RunMainMenu(&MainMenu, GlobalConfig.DefaultSelection, &ChosenEntry);
+        
+        // We don't allow exiting the main menu with the Escape key.
+        if (MenuExit == MENU_EXIT_ESCAPE) {
+           // Commented-out below: Was part of an attempt to get rEFInd to
+           // re-scan disk devices on pressing Esc; but doesn't work (yet), so
+           // removed....
+//             ReadConfig();
+//             ScanForBootloaders();
+//             SetupScreen();
+            continue;
+        }
+        
+        switch (ChosenEntry->Tag) {
+            
+            case TAG_RESET:    // Restart
+                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);
+                break;
+                
+            case TAG_LEGACY:   // Boot legacy OS
+                StartLegacy((LEGACY_ENTRY *)ChosenEntry);
+                break;
+                
+            case TAG_TOOL:     // Start a EFI tool
+                StartTool((LOADER_ENTRY *)ChosenEntry);
+                break;
+                
+        }
+    }
+
+    // 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() */
diff --git a/refind/menu.c b/refind/menu.c
new file mode 100644 (file)
index 0000000..aedeb22
--- /dev/null
@@ -0,0 +1,852 @@
+/*
+ * 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 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"
+#include "screen.h"
+#include "lib.h"
+#include "menu.h"
+#include "config.h"
+#include "libeg.h"
+#include "refit_call_wrapper.h"
+
+#include "egemb_back_selected_small.h"
+#include "egemb_arrow_left.h"
+#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)
+
+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 };
+
+#define TEXT_YMARGIN (2)
+#define TEXT_XMARGIN (8)
+#define TEXT_LINE_HEIGHT (FONT_CELL_HEIGHT + TEXT_YMARGIN * 2)
+#define TITLEICON_SPACING (16)
+
+#define ROW0_TILESIZE (144)
+#define ROW1_TILESIZE (64)
+#define TILE_XSPACING (8)
+#define TILE_YSPACING (16)
+
+// Alignment values for PaintIcon()
+#define ALIGN_RIGHT 1
+#define ALIGN_LEFT 0
+
+static EG_IMAGE *SelectionImages[4] = { NULL, NULL, NULL, NULL };
+static EG_PIXEL SelectionBackgroundPixel = { 0xff, 0xff, 0xff, 0 };
+static EG_IMAGE *TextBuffer = NULL;
+
+// Used in MainMenuStyle(), but must be persistent....
+UINTN row0PosX = 0, row0PosXRunning = 0, row1PosY = 0, row0Loaders = 0;
+
+//
+// Graphics helper functions
+//
+
+static VOID InitSelection(VOID)
+{
+    UINTN       x, y, src_x, src_y;
+    EG_PIXEL    *DestPtr, *SrcPtr;
+    
+    if (!AllowGraphicsMode)
+        return;
+    if (SelectionImages[0] != NULL)
+        return;
+    
+    // load small selection image
+    if (GlobalConfig.SelectionSmallFileName != NULL) {
+        SelectionImages[2] = egLoadImage(SelfDir, GlobalConfig.SelectionSmallFileName, FALSE);
+    }
+    if (SelectionImages[2] == NULL)
+        SelectionImages[2] = egPrepareEmbeddedImage(&egemb_back_selected_small, FALSE);
+    SelectionImages[2] = egEnsureImageSize(SelectionImages[2],
+                                           ROW1_TILESIZE, ROW1_TILESIZE, &MenuBackgroundPixel);
+    if (SelectionImages[2] == NULL)
+        return;
+    
+    // load big selection image
+    if (GlobalConfig.SelectionBigFileName != NULL) {
+        SelectionImages[0] = egLoadImage(SelfDir, GlobalConfig.SelectionBigFileName, FALSE);
+        SelectionImages[0] = egEnsureImageSize(SelectionImages[0],
+                                               ROW0_TILESIZE, ROW0_TILESIZE, &MenuBackgroundPixel);
+    }
+    if (SelectionImages[0] == NULL) {
+        // calculate big selection image from small one
+        
+        SelectionImages[0] = egCreateImage(ROW0_TILESIZE, ROW0_TILESIZE, FALSE);
+        if (SelectionImages[0] == NULL) {
+            egFreeImage(SelectionImages[2]);
+            SelectionImages[2] = NULL;
+            return;
+        }
+        
+        DestPtr = SelectionImages[0]->PixelData;
+        SrcPtr  = SelectionImages[2]->PixelData;
+        for (y = 0; y < ROW0_TILESIZE; y++) {
+            if (y < (ROW1_TILESIZE >> 1))
+                src_y = y;
+            else if (y < (ROW0_TILESIZE - (ROW1_TILESIZE >> 1)))
+                src_y = (ROW1_TILESIZE >> 1);
+            else
+                src_y = y - (ROW0_TILESIZE - ROW1_TILESIZE);
+            
+            for (x = 0; x < ROW0_TILESIZE; x++) {
+                if (x < (ROW1_TILESIZE >> 1))
+                    src_x = x;
+                else if (x < (ROW0_TILESIZE - (ROW1_TILESIZE >> 1)))
+                    src_x = (ROW1_TILESIZE >> 1);
+                else
+                    src_x = x - (ROW0_TILESIZE - ROW1_TILESIZE);
+                
+                *DestPtr++ = SrcPtr[src_y * ROW1_TILESIZE + src_x];
+            }
+        }
+    }
+    
+    // non-selected background images
+    SelectionImages[1] = egCreateFilledImage(ROW0_TILESIZE, ROW0_TILESIZE, FALSE, &MenuBackgroundPixel);
+    SelectionImages[3] = egCreateFilledImage(ROW1_TILESIZE, ROW1_TILESIZE, FALSE, &MenuBackgroundPixel);
+}
+
+//
+// Scrolling functions
+//
+
+static VOID InitScroll(OUT SCROLL_STATE *State, IN UINTN ItemCount, IN UINTN VisibleSpace)
+{
+    State->LastSelection = State->CurrentSelection = 0;
+    State->MaxIndex = (INTN)ItemCount - 1;
+    State->FirstVisible = 0;
+    if (VisibleSpace == 0)
+       State->MaxVisible = UGAWidth / (ROW0_TILESIZE + TILE_XSPACING) - 1;
+    else
+        State->MaxVisible = (INTN)VisibleSpace;
+    State->PaintAll = TRUE;
+    State->PaintSelection = FALSE;
+
+    State->LastVisible = State->FirstVisible + State->MaxVisible - 1;
+}
+
+static VOID UpdateScroll(IN OUT SCROLL_STATE *State, IN UINTN Movement)
+{
+    State->LastSelection = State->CurrentSelection;
+    
+    switch (Movement) {
+        case SCROLL_LINE_UP:
+            if (State->CurrentSelection > 0) {
+                State->CurrentSelection --;
+            }
+            break;
+            
+        case SCROLL_LINE_DOWN:
+            if (State->CurrentSelection < State->MaxIndex) {
+                State->CurrentSelection ++;
+            }
+            break;
+
+        // TODO: Better handling of SCROLL_PAGE_UP & SCROLL_PAGE_DOWN
+        case SCROLL_PAGE_UP:
+        case SCROLL_FIRST:
+           if (State->CurrentSelection > 0) {
+              State->PaintAll = TRUE;
+              State->CurrentSelection = 0;
+           }
+           break;
+
+        case SCROLL_PAGE_DOWN:
+        case SCROLL_LAST:
+           if (State->CurrentSelection < State->MaxIndex) {
+              State->PaintAll = TRUE;
+              State->CurrentSelection = State->MaxIndex;
+           }
+           break;
+
+        case SCROLL_NONE:
+            break;
+            
+    }
+    
+    if (!State->PaintAll && State->CurrentSelection != State->LastSelection)
+        State->PaintSelection = TRUE;
+    State->LastVisible = State->FirstVisible + State->MaxVisible - 1;
+}
+
+//
+// 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);
+}
+
+VOID FreeMenu(IN REFIT_MENU_SCREEN *Screen)
+{
+    if (Screen->Entries)
+        FreePool(Screen->Entries);
+}
+
+static INTN FindMenuShortcutEntry(IN REFIT_MENU_SCREEN *Screen, IN CHAR16 *Shortcut)
+{
+    UINTN i;
+
+    if (Shortcut == NULL)
+       return (-1);
+
+    if (StrLen(Shortcut) == 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]) {
+                  return i;
+               } // if
+         } // for
+      } // if
+    } else if (StrLen(Shortcut) > 1) {
+       for (i = 0; i < Screen->EntryCount; i++) {
+          if (StriSubCmp(Shortcut, Screen->Entries[i]->Title))
+             return i;
+       } // for
+    }
+    return -1;
+}
+
+//
+// generic menu function
+//
+
+static UINTN RunGenericMenu(IN REFIT_MENU_SCREEN *Screen, IN MENU_STYLE_FUNC StyleFunc, IN INTN DefaultEntryIndex, OUT REFIT_MENU_ENTRY **ChosenEntry)
+{
+    SCROLL_STATE State;
+    EFI_STATUS Status;
+    EFI_INPUT_KEY key;
+    UINTN index;
+    INTN ShortcutEntry;
+    BOOLEAN HaveTimeout = FALSE;
+    UINTN TimeoutCountdown = 0;
+    CHAR16 *TimeoutMessage;
+    CHAR16 KeyAsString[2];
+    UINTN MenuExit;
+    
+    if (Screen->TimeoutSeconds > 0) {
+        HaveTimeout = TRUE;
+        TimeoutCountdown = Screen->TimeoutSeconds * 10;
+    }
+    MenuExit = 0;
+
+    StyleFunc(Screen, &State, MENU_FUNCTION_INIT, NULL);
+    // override the starting selection with the default index, if any
+    if (DefaultEntryIndex >= 0 && DefaultEntryIndex <= State.MaxIndex) {
+        State.CurrentSelection = DefaultEntryIndex;
+        UpdateScroll(&State, SCROLL_NONE);
+    }
+    
+    while (!MenuExit) {
+        // update the screen
+        if (State.PaintAll) {
+            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 (HaveTimeout) {
+            TimeoutMessage = PoolPrint(L"%s in %d seconds", Screen->TimeoutText, (TimeoutCountdown + 5) / 10);
+            StyleFunc(Screen, &State, MENU_FUNCTION_PAINT_TIMEOUT, TimeoutMessage);
+            FreePool(TimeoutMessage);
+        }
+
+        // read key press (and wait for it if applicable)
+        Status = refit_call2_wrapper(ST->ConIn->ReadKeyStroke, ST->ConIn, &key);
+        if (Status == EFI_NOT_READY) {
+            if (HaveTimeout && TimeoutCountdown == 0) {
+                // timeout expired
+                MenuExit = MENU_EXIT_TIMEOUT;
+                break;
+            } else if (HaveTimeout) {
+                refit_call1_wrapper(BS->Stall, 100000);
+                TimeoutCountdown--;
+            } else
+                refit_call3_wrapper(BS->WaitForEvent, 1, &ST->ConIn->WaitForKey, &index);
+            continue;
+        }
+        if (HaveTimeout) {
+            // the user pressed a key, cancel the timeout
+            StyleFunc(Screen, &State, MENU_FUNCTION_PAINT_TIMEOUT, L"");
+            HaveTimeout = FALSE;
+        }
+
+        // react to key press
+        switch (key.ScanCode) {
+            case SCAN_UP:
+            case SCAN_LEFT:
+                UpdateScroll(&State, SCROLL_LINE_UP);
+                break;
+            case SCAN_DOWN:
+            case SCAN_RIGHT:
+                UpdateScroll(&State, SCROLL_LINE_DOWN);
+                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_F10:
+                egScreenShot();
+                break;
+        }
+        switch (key.UnicodeChar) {
+            case CHAR_LINEFEED:
+            case CHAR_CARRIAGE_RETURN:
+            case ' ':
+                MenuExit = MENU_EXIT_ENTER;
+                break;
+            case '+':
+                MenuExit = MENU_EXIT_DETAILS;
+                break;
+            default:
+                KeyAsString[0] = key.UnicodeChar;
+                KeyAsString[1] = 0;
+                ShortcutEntry = FindMenuShortcutEntry(Screen, KeyAsString);
+                if (ShortcutEntry >= 0) {
+                    State.CurrentSelection = ShortcutEntry;
+                    MenuExit = MENU_EXIT_ENTER;
+                }
+                break;
+        }
+    }
+    
+    StyleFunc(Screen, &State, MENU_FUNCTION_CLEANUP, NULL);
+    
+    if (ChosenEntry)
+        *ChosenEntry = Screen->Entries[State.CurrentSelection];
+    return MenuExit;
+} /* static UINTN RunGenericMenu( */
+
+//
+// text-mode generic style
+//
+
+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;
+    
+    switch (Function) {
+        
+        case MENU_FUNCTION_INIT:
+            // vertical layout
+            MenuPosY = 4;
+            if (Screen->InfoLineCount > 0)
+                MenuPosY += Screen->InfoLineCount + 1;
+            MenuHeight = ConHeight - MenuPosY;
+            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;
+            }
+            if (MenuWidth > ConWidth - 6)
+                MenuWidth = ConWidth - 6;
+            
+            // prepare strings for display
+            DisplayStrings = AllocatePool(sizeof(CHAR16 *) * Screen->EntryCount);
+            for (i = 0; i <= State->MaxIndex; i++)
+                DisplayStrings[i] = PoolPrint(L" %-.*s ", MenuWidth, Screen->Entries[i]->Title);
+            // TODO: shorten strings that are too long (PoolPrint doesn't do that...)
+            // TODO: use more elaborate techniques for shortening too long strings (ellipses in the middle)
+            // TODO: account for double-width characters
+                
+            // initial painting
+            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]);
+                }
+            }
+            
+            break;
+            
+        case MENU_FUNCTION_CLEANUP:
+            // release temporary memory
+            for (i = 0; i <= State->MaxIndex; i++)
+                FreePool(DisplayStrings[i]);
+            FreePool(DisplayStrings);
+            break;
+            
+        case MENU_FUNCTION_PAINT_ALL:
+            // paint the whole screen (initially and after scrolling)
+            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" ");
+            break;
+            
+        case MENU_FUNCTION_PAINT_SELECTION:
+            // redraw selection cursor
+            refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 2, MenuPosY + (State->LastSelection - State->FirstVisible));
+            refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_CHOICE_BASIC);
+            refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, DisplayStrings[State->LastSelection]);
+            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 - 1);
+                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 - 1);
+                TimeoutMessage = PoolPrint(L"%s  ", ParamText);
+                refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, TimeoutMessage);
+                FreePool(TimeoutMessage);
+            }
+            break;
+
+    }
+}
+
+//
+// graphical generic style
+//
+
+
+static VOID DrawMenuText(IN CHAR16 *Text, IN UINTN SelectedWidth, IN UINTN XPos, IN UINTN YPos)
+{
+//    Print(L"Entering DrawMenuText(); Text is '%s', SelectedWidth is %d, XPos is %d, YPos is %d\n",
+//          Text, SelectedWidth, XPos, YPos);
+    if (TextBuffer == NULL)
+        TextBuffer = egCreateImage(LAYOUT_TEXT_WIDTH, TEXT_LINE_HEIGHT, FALSE);
+
+    egFillImage(TextBuffer, &MenuBackgroundPixel);
+    if (SelectedWidth > 0) {
+        // draw selection bar background
+        egFillImageArea(TextBuffer, 0, 0, SelectedWidth, TextBuffer->Height,
+                        &SelectionBackgroundPixel);
+    }
+    
+    // render the text
+    egRenderText(Text, TextBuffer, TEXT_XMARGIN, TEXT_YMARGIN);
+    BltImage(TextBuffer, XPos, YPos);
+}
+
+// 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 MenuWidth, EntriesPosX, EntriesPosY, TimeoutPosY;
+
+    switch (Function) {
+        
+        case MENU_FUNCTION_INIT:
+            InitScroll(State, Screen->EntryCount, 0);
+
+            // determine width of the menu
+            MenuWidth = 20;  // minimum
+            for (i = 0; i < (INTN)Screen->InfoLineCount; i++) {
+                ItemWidth = StrLen(Screen->InfoLines[i]);
+                if (MenuWidth < ItemWidth)
+                    MenuWidth = ItemWidth;
+            }
+            for (i = 0; i <= State->MaxIndex; i++) {
+                ItemWidth = StrLen(Screen->Entries[i]->Title);
+                if (MenuWidth < ItemWidth)
+                    MenuWidth = ItemWidth;
+            }
+            MenuWidth = TEXT_XMARGIN * 2 + MenuWidth * FONT_CELL_WIDTH;
+            if (MenuWidth > LAYOUT_TEXT_WIDTH)
+                MenuWidth = LAYOUT_TEXT_WIDTH;
+
+            if (Screen->TitleImage)
+                EntriesPosX = (UGAWidth + (Screen->TitleImage->Width + TITLEICON_SPACING) - MenuWidth) >> 1;
+            else
+                EntriesPosX = (UGAWidth - MenuWidth) >> 1;
+            EntriesPosY = ((UGAHeight - LAYOUT_TOTAL_HEIGHT) >> 1) + LAYOUT_BANNER_YOFFSET + TEXT_LINE_HEIGHT * 2;
+            TimeoutPosY = EntriesPosY + (Screen->EntryCount + 1) * TEXT_LINE_HEIGHT;
+
+            // initial painting
+            SwitchToGraphicsAndClear();
+            egMeasureText(Screen->Title, &ItemWidth, NULL);
+            DrawMenuText(Screen->Title, 0, ((UGAWidth - ItemWidth) >> 1) - TEXT_XMARGIN, EntriesPosY - TEXT_LINE_HEIGHT * 2);
+            if (Screen->TitleImage)
+                BltImageAlpha(Screen->TitleImage,
+                              EntriesPosX - (Screen->TitleImage->Width + TITLEICON_SPACING), EntriesPosY,
+                              &MenuBackgroundPixel);
+            if (Screen->InfoLineCount > 0) {
+                for (i = 0; i < (INTN)Screen->InfoLineCount; i++) {
+                    DrawMenuText(Screen->InfoLines[i], 0, EntriesPosX, EntriesPosY);
+                    EntriesPosY += TEXT_LINE_HEIGHT;
+                }
+                EntriesPosY += TEXT_LINE_HEIGHT;  // also add a blank line
+            }
+
+            break;
+
+        case MENU_FUNCTION_CLEANUP:
+            // nothing to do
+            break;
+            
+        case MENU_FUNCTION_PAINT_ALL:
+            for (i = 0; i <= State->MaxIndex; i++) {
+                DrawMenuText(Screen->Entries[i]->Title, (i == State->CurrentSelection) ? MenuWidth : 0,
+                             EntriesPosX, EntriesPosY + i * TEXT_LINE_HEIGHT);
+            }
+            break;
+            
+        case MENU_FUNCTION_PAINT_SELECTION:
+            // redraw selection cursor
+            DrawMenuText(Screen->Entries[State->LastSelection]->Title, 0,
+                         EntriesPosX, EntriesPosY + State->LastSelection * TEXT_LINE_HEIGHT);
+            DrawMenuText(Screen->Entries[State->CurrentSelection]->Title, MenuWidth,
+                         EntriesPosX, EntriesPosY + State->CurrentSelection * TEXT_LINE_HEIGHT);
+            break;
+            
+        case MENU_FUNCTION_PAINT_TIMEOUT:
+            DrawMenuText(ParamText, 0, EntriesPosX, TimeoutPosY);
+            break;
+            
+    }
+}
+
+//
+// graphical main menu style
+//
+
+static VOID DrawMainMenuEntry(REFIT_MENU_ENTRY *Entry, BOOLEAN selected, UINTN XPos, UINTN YPos)
+{
+    UINTN ImageNum;
+
+    ImageNum = ((Entry->Row == 0) ? 0 : 2) + (selected ? 0 : 1);
+    if (SelectionImages != NULL)
+        BltImageCompositeBadge(SelectionImages[ImageNum],
+                               Entry->Image, Entry->BadgeImage, XPos, YPos);
+}
+
+static VOID DrawMainMenuText(IN CHAR16 *Text, IN UINTN XPos, IN UINTN YPos)
+{
+    UINTN TextWidth, TextPosX;
+
+    if (TextBuffer == NULL)
+        TextBuffer = egCreateImage(LAYOUT_TEXT_WIDTH, TEXT_LINE_HEIGHT, FALSE);
+
+    egFillImage(TextBuffer, &MenuBackgroundPixel);
+
+    // render the text
+    egMeasureText(Text, &TextWidth, NULL);
+    if (TextWidth > TextBuffer->Width)
+       TextPosX = 0;
+    else
+       TextPosX = (TextBuffer->Width - TextWidth) / 2;
+    egRenderText(Text, TextBuffer, TextPosX, 0);
+//    egRenderText(Text, TextBuffer, (TextBuffer->Width - TextWidth) >> 1, 0);
+    BltImage(TextBuffer, XPos, YPos);
+}
+
+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) {
+      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;
+      } // Scroll forward
+      if (State->CurrentSelection < State->FirstVisible) {
+         State->FirstVisible = State->CurrentSelection;
+         State->LastVisible = State->CurrentSelection + State->MaxVisible - 1;
+      } // Scroll backward
+   }
+   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))
+      DrawMainMenuText(Screen->Entries[State->CurrentSelection]->Title,
+                       (UGAWidth - LAYOUT_TEXT_WIDTH) >> 1, textPosY);
+} // 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) {
+   if ((State->CurrentSelection < State->LastVisible) && (State->CurrentSelection >= State->FirstVisible)) {
+      DrawMainMenuEntry(Screen->Entries[State->LastSelection], FALSE,
+                        itemPosX[State->LastSelection - State->FirstVisible],
+                        (Screen->Entries[State->LastSelection]->Row == 0) ? row0PosY : row1PosY);
+      DrawMainMenuEntry(Screen->Entries[State->CurrentSelection], TRUE,
+                        itemPosX[State->CurrentSelection - State->FirstVisible],
+                        (Screen->Entries[State->CurrentSelection]->Row == 0) ? row0PosY : row1PosY);
+      if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_LABEL))
+         DrawMainMenuText(Screen->Entries[State->CurrentSelection]->Title,
+                          (UGAWidth - LAYOUT_TEXT_WIDTH) >> 1, textPosY);
+   } else {
+      MainMenuStyle(Screen, State, MENU_FUNCTION_PAINT_ALL, NULL);
+   }
+} // static VOID MoveSelection(VOID)
+
+// Display an 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;
+
+   if (FileExists(SelfDir, ExternalFilename))
+      Icon = egLoadIcon(SelfDir, ExternalFilename, 48);
+   if (Icon == NULL)
+      Icon = egPrepareEmbeddedImage(BuiltInIcon, TRUE);
+   if (Icon != NULL) {
+      if (Alignment == ALIGN_RIGHT)
+         PosX -= Icon->Width;
+      BltImageAlpha(Icon, PosX, PosY - (Icon->Height / 2), &MenuBackgroundPixel);
+   }
+} // static VOID PaintArrow()
+
+// 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;
+    extern UINTN row0PosX, row0PosXRunning, row1PosY, row0Loaders;
+    UINTN row0Count, row1Count, row1PosX, row1PosXRunning;
+    static UINTN *itemPosX;
+    static UINTN row0PosY, textPosY;
+
+    switch (Function) {
+        
+        case MENU_FUNCTION_INIT:
+            InitScroll(State, Screen->EntryCount, 0);
+            
+            // 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 - (ROW0_TILESIZE + TILE_XSPACING) * row0Count) >> 1;
+            row0PosY = ((UGAHeight - LAYOUT_TOTAL_HEIGHT) >> 1) + LAYOUT_BANNER_YOFFSET;
+            row1PosX = (UGAWidth + TILE_XSPACING - (ROW1_TILESIZE + TILE_XSPACING) * row1Count) >> 1;
+            row1PosY = row0PosY + ROW0_TILESIZE + TILE_YSPACING;
+            if (row1Count > 0)
+                textPosY = row1PosY + ROW1_TILESIZE + 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 += ROW0_TILESIZE + TILE_XSPACING;
+                } else {
+                    itemPosX[i] = row1PosXRunning;
+                    row1PosXRunning += ROW1_TILESIZE + TILE_XSPACING;
+                }
+            }
+            // initial painting
+            InitSelection();
+            SwitchToGraphicsAndClear();
+            break;
+            
+        case MENU_FUNCTION_CLEANUP:
+            FreePool(itemPosX);
+            break;
+            
+        case MENU_FUNCTION_PAINT_ALL:
+            BltClearScreen(TRUE);
+            PaintAll(Screen, State, itemPosX, row0PosY, row1PosY, textPosY);
+            // 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)
+               PaintIcon(&egemb_arrow_left, L"icons\\arrow_left.icns", row0PosX - TILE_XSPACING,
+                         row0PosY + (ROW0_TILESIZE / 2), ALIGN_RIGHT);
+            if (State->LastVisible < (row0Loaders - 1))
+               PaintIcon(&egemb_arrow_right, L"icons\\arrow_right.icns",
+                         (UGAWidth + (ROW0_TILESIZE + TILE_XSPACING) * State->MaxVisible) / 2 + TILE_XSPACING,
+                         row0PosY + (ROW0_TILESIZE / 2), ALIGN_LEFT);
+            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))
+                DrawMainMenuText(ParamText, (UGAWidth - LAYOUT_TEXT_WIDTH) >> 1, textPosY + TEXT_LINE_HEIGHT);
+            break;
+            
+    }
+}
+
+//
+// user-callable dispatcher functions
+//
+
+UINTN RunMenu(IN REFIT_MENU_SCREEN *Screen, OUT REFIT_MENU_ENTRY **ChosenEntry)
+{
+    MENU_STYLE_FUNC Style = TextMenuStyle;
+    
+    if (AllowGraphicsMode)
+        Style = GraphicsMenuStyle;
+    
+    return RunGenericMenu(Screen, Style, -1, ChosenEntry);
+}
+
+UINTN RunMainMenu(IN REFIT_MENU_SCREEN *Screen, IN CHAR16* DefaultSelection, OUT REFIT_MENU_ENTRY **ChosenEntry)
+{
+    MENU_STYLE_FUNC Style = TextMenuStyle;
+    MENU_STYLE_FUNC MainStyle = TextMenuStyle;
+    REFIT_MENU_ENTRY *TempChosenEntry;
+    UINTN MenuExit = 0;
+    UINTN DefaultEntryIndex = -1;
+
+    if (DefaultSelection != NULL) {
+        // Find a menu entry whose shortcut is the first character of DefaultSelection, or
+        // whose 
+        DefaultEntryIndex = FindMenuShortcutEntry(Screen, DefaultSelection);
+        // If that didn't work, should we scan more characters?  For now, no.
+    }
+
+    if (AllowGraphicsMode) {
+        Style = GraphicsMenuStyle;
+        MainStyle = MainMenuStyle;
+    }
+
+    while (!MenuExit) {
+        MenuExit = RunGenericMenu(Screen, MainStyle, DefaultEntryIndex, &TempChosenEntry);
+        Screen->TimeoutSeconds = 0;
+
+        if (MenuExit == MENU_EXIT_DETAILS && TempChosenEntry->SubScreen != NULL) {
+            MenuExit = RunGenericMenu(TempChosenEntry->SubScreen, Style, -1, &TempChosenEntry);
+            if (MenuExit == MENU_EXIT_ESCAPE || TempChosenEntry->Tag == TAG_RETURN)
+                MenuExit = 0;
+        }
+    }
+
+    if (ChosenEntry)
+        *ChosenEntry = TempChosenEntry;
+    return MenuExit;
+} /* UINTN RunMainMenu() */
diff --git a/refind/menu.h b/refind/menu.h
new file mode 100644 (file)
index 0000000..b0cb514
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * 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_
+
+#include "efi.h"
+#include "efilib.h"
+
+#include "libeg.h"
+
+//
+// menu module
+//
+
+#define MENU_EXIT_ENTER   (1)
+#define MENU_EXIT_ESCAPE  (2)
+#define MENU_EXIT_DETAILS (3)
+#define MENU_EXIT_TIMEOUT (4)
+
+#define TAG_RETURN       (99)
+
+// scrolling definitions
+
+typedef struct {
+   INTN CurrentSelection, LastSelection, MaxIndex;
+   INTN FirstVisible, LastVisible, MaxVisible;
+   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)
+
+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);
+VOID FreeMenu(IN REFIT_MENU_SCREEN *Screen);
+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);
+UINTN RunMainMenu(IN REFIT_MENU_SCREEN *Screen, IN CHAR16* DefaultSelection, OUT REFIT_MENU_ENTRY **ChosenEntry);
+
+#endif
+
+/* EOF */
diff --git a/refind/screen.c b/refind/screen.c
new file mode 100644 (file)
index 0000000..fe57a23
--- /dev/null
@@ -0,0 +1,452 @@
+/*
+ * refit/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.
+ */
+
+#include "global.h"
+#include "screen.h"
+#include "config.h"
+#include "refit_call_wrapper.h"
+
+#include "egemb_refind_banner.h"
+
+// Console defines and variables
+
+UINTN ConWidth;
+UINTN ConHeight;
+CHAR16 *BlankLine;
+
+static VOID SwitchToText(IN BOOLEAN CursorEnabled);
+static VOID SwitchToGraphics(VOID);
+static VOID DrawScreenHeader(IN CHAR16 *Title);
+
+// UGA defines and variables
+
+UINTN UGAWidth;
+UINTN UGAHeight;
+BOOLEAN AllowGraphicsMode;
+
+EG_PIXEL StdBackgroundPixel  = { 0xbf, 0xbf, 0xbf, 0 };
+EG_PIXEL MenuBackgroundPixel = { 0xbf, 0xbf, 0xbf, 0 };
+
+static BOOLEAN GraphicsScreenDirty;
+
+// general defines and variables
+
+static BOOLEAN haveError = FALSE;
+
+//
+// Screen initialization and switching
+//
+
+VOID InitScreen(VOID)
+{
+    UINTN i;
+    
+    // initialize libeg
+    egInitScreen();
+    
+    if (egHasGraphicsMode()) {
+        egGetScreenSize(&UGAWidth, &UGAHeight);
+        AllowGraphicsMode = TRUE;
+    } else {
+        AllowGraphicsMode = FALSE;
+        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;
+    }
+    
+    // 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;
+    
+    // show the banner (even when in graphics mode)
+    DrawScreenHeader(L"Initializing...");
+}
+
+VOID SetupScreen(VOID)
+{
+    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)
+        SwitchToGraphics();
+        BltClearScreen(TRUE);
+    }
+}
+
+static VOID SwitchToText(IN BOOLEAN CursorEnabled)
+{
+    egSetGraphicsModeEnabled(FALSE);
+    refit_call2_wrapper(ST->ConOut->EnableCursor, ST->ConOut, CursorEnabled);
+}
+
+static 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) {
+        SwitchToText(FALSE);
+        PauseForKey();
+    }
+    
+    // reset error flag
+    haveError = FALSE;
+}
+
+VOID BeginExternalScreen(IN BOOLEAN UseGraphicsMode, IN CHAR16 *Title)
+{
+    if (!AllowGraphicsMode)
+        UseGraphicsMode = FALSE;
+    
+    if (UseGraphicsMode) {
+        SwitchToGraphics();
+        BltClearScreen(FALSE);
+    }
+    
+    // show the header
+    DrawScreenHeader(Title);
+    
+    if (!UseGraphicsMode)
+        SwitchToText(TRUE);
+    
+    // reset error flag
+    haveError = FALSE;
+}
+
+VOID FinishExternalScreen(VOID)
+{
+    // make sure we clean up later
+    GraphicsScreenDirty = TRUE;
+    
+    if (haveError) {
+        SwitchToText(FALSE);
+        PauseForKey();
+    }
+    
+    // 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);
+}
+
+static VOID DrawScreenHeader(IN CHAR16 *Title)
+{
+    UINTN y;
+
+    // clear to black background
+    refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BASIC);
+    refit_call1_wrapper(ST->ConOut->ClearScreen, ST->ConOut);
+
+    // 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
+//
+
+static 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;
+}
+
+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");
+}
+
+#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 ErrorName[64];
+    
+    if (!EFI_ERROR(Status))
+        return FALSE;
+    
+    StatusToString(ErrorName, Status);
+    refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_ERROR);
+    Print(L"Fatal Error: %s %s\n", ErrorName, where);
+    refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BASIC);
+    haveError = TRUE;
+    
+    //BS->Exit(ImageHandle, ExitStatus, ExitDataSize, ExitData);
+    
+    return TRUE;
+}
+
+BOOLEAN CheckError(IN EFI_STATUS Status, IN CHAR16 *where)
+{
+    CHAR16 ErrorName[64];
+    
+    if (!EFI_ERROR(Status))
+        return FALSE;
+    
+    StatusToString(ErrorName, Status);
+    refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_ERROR);
+    Print(L"Error: %s %s\n", ErrorName, where);
+    refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BASIC);
+    haveError = TRUE;
+    
+    return TRUE;
+}
+
+//
+// Graphics functions
+//
+
+VOID SwitchToGraphicsAndClear(VOID)
+{
+    SwitchToGraphics();
+    if (GraphicsScreenDirty)
+        BltClearScreen(TRUE);
+}
+
+VOID BltClearScreen(IN BOOLEAN ShowBanner)
+{
+    static EG_IMAGE *Banner = NULL;
+
+    if (ShowBanner && !(GlobalConfig.HideUIFlags & HIDEUI_FLAG_BANNER)) {
+        // load banner on first call
+        if (Banner == NULL) {
+            if (GlobalConfig.BannerFileName == NULL)
+                Banner = egPrepareEmbeddedImage(&egemb_refind_banner, FALSE);
+            else
+                Banner = egLoadImage(SelfDir, GlobalConfig.BannerFileName, FALSE);
+            if (Banner != NULL)
+                MenuBackgroundPixel = Banner->PixelData[0];
+        }
+        
+        // clear and draw banner
+        egClearScreen(&MenuBackgroundPixel);
+        if (Banner != NULL)
+            BltImage(Banner, (UGAWidth - Banner->Width) >> 1,
+                     ((UGAHeight - LAYOUT_TOTAL_HEIGHT) >> 1) + LAYOUT_BANNER_HEIGHT - Banner->Height);
+        
+    } else {
+        // clear to standard background color
+        egClearScreen(&StdBackgroundPixel);
+    }
+    
+    GraphicsScreenDirty = FALSE;
+}
+
+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, TotalHeight, 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
+     egDrawImage(CompImage, XPos, YPos);
+     egFreeImage(CompImage);
+     GraphicsScreenDirty = TRUE;
+}
diff --git a/refind/screen.h b/refind/screen.h
new file mode 100644 (file)
index 0000000..1b2dfa6
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * 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_
+
+#include "efi.h"
+#include "efilib.h"
+
+#include "libeg.h"
+
+//
+// screen module
+//
+
+#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_TOTAL_HEIGHT (368)
+#define LAYOUT_BANNER_HEIGHT (32)
+#define LAYOUT_BANNER_YOFFSET (LAYOUT_BANNER_HEIGHT + 32)
+
+#define FONT_CELL_WIDTH (7)
+#define FONT_CELL_HEIGHT (12)
+
+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);
+#if REFIT_DEBUG > 0
+VOID DebugPause(VOID);
+#else
+#define DebugPause()
+#endif
+VOID EndlessIdleLoop(VOID);
+VOID PauseForKey(VOID);
+
+BOOLEAN CheckFatalError(IN EFI_STATUS Status, IN CHAR16 *where);
+BOOLEAN CheckError(IN EFI_STATUS Status, IN CHAR16 *where);
+
+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