]> code.delx.au - refind/commitdiff
Merge remote-tracking branch 'tianon/master'
authorsrs5694 <srs5694@users.sourceforge.net>
Thu, 3 Dec 2015 01:34:06 +0000 (20:34 -0500)
committersrs5694 <srs5694@users.sourceforge.net>
Thu, 3 Dec 2015 01:34:06 +0000 (20:34 -0500)
Conflicts:
debian/control
debian/copyright

427 files changed:
BUILDING.txt [new file with mode: 0644]
COPYING.txt [new file with mode: 0644]
CREDITS.txt [new file with mode: 0644]
EfiLib/BdsConnect.c [new file with mode: 0644]
EfiLib/BdsHelper.c [new file with mode: 0644]
EfiLib/BdsHelper.h [new file with mode: 0644]
EfiLib/BdsTianoCore.c [new file with mode: 0644]
EfiLib/BmLib.c [new file with mode: 0644]
EfiLib/DevicePath.c [new file with mode: 0644]
EfiLib/DevicePathUtilities.h [new file with mode: 0644]
EfiLib/GenericBdsLib.h [new file with mode: 0644]
EfiLib/LegacyBios.h [new file with mode: 0644]
EfiLib/Make.tiano [new file with mode: 0644]
EfiLib/Makefile [new file with mode: 0644]
EfiLib/Platform.h [new file with mode: 0644]
EfiLib/gnuefi-helper.c [new file with mode: 0644]
EfiLib/gnuefi-helper.h [new file with mode: 0644]
EfiLib/legacy.c [new file with mode: 0644]
EfiLib/legacy.h [new file with mode: 0644]
LICENSE.txt [new file with mode: 0644]
Make.common [new file with mode: 0644]
Make.tiano [new file with mode: 0644]
Makefile [new file with mode: 0644]
NEWS.txt [new file with mode: 0644]
README.txt [new file with mode: 0644]
banners/refind_banner-alpha.png [new file with mode: 0644]
banners/refind_banner.png [new file with mode: 0644]
banners/refind_banner.svg [new file with mode: 0644]
debian/control
debian/copyright
debian/debinstall [new file with mode: 0755]
debian/postinst [new file with mode: 0755]
docs/Styles/styles.css [new file with mode: 0644]
docs/man/mkrlconf.8 [new file with mode: 0644]
docs/man/mvrefind.8 [new file with mode: 0644]
docs/man/refind-install.8 [new file with mode: 0644]
docs/refind/FDL-1.3.txt [new file with mode: 0644]
docs/refind/HashTool1.png [new file with mode: 0644]
docs/refind/HashTool2.png [new file with mode: 0644]
docs/refind/MokManager1.png [new file with mode: 0644]
docs/refind/MokManager2.png [new file with mode: 0644]
docs/refind/about.png [new file with mode: 0644]
docs/refind/about.svg [new file with mode: 0644]
docs/refind/automatic-submenu.png [new file with mode: 0644]
docs/refind/bootmode.html [new file with mode: 0644]
docs/refind/configfile.html [new file with mode: 0644]
docs/refind/drivers.html [new file with mode: 0644]
docs/refind/editor.png [new file with mode: 0644]
docs/refind/features.html [new file with mode: 0644]
docs/refind/func_csr_rotate.png [new file with mode: 0644]
docs/refind/getting.html [new file with mode: 0644]
docs/refind/index.html [new file with mode: 0644]
docs/refind/installing.html [new file with mode: 0644]
docs/refind/linux.html [new file with mode: 0644]
docs/refind/manual-submenu.png [new file with mode: 0644]
docs/refind/os_legacy.png [new file with mode: 0644]
docs/refind/refind-background-snowy.png [new file with mode: 0644]
docs/refind/refind-background.png [new file with mode: 0644]
docs/refind/refind.png [new file with mode: 0644]
docs/refind/revisions.html [new file with mode: 0644]
docs/refind/secureboot.html [new file with mode: 0644]
docs/refind/sip.html [new file with mode: 0644]
docs/refind/startup-disk.png [new file with mode: 0644]
docs/refind/submenu.png [new file with mode: 0644]
docs/refind/themes.html [new file with mode: 0644]
docs/refind/todo.html [new file with mode: 0644]
docs/refind/using.html [new file with mode: 0644]
docs/refind/windows-gpt.png [new file with mode: 0644]
docs/refind/yosemite.html [new file with mode: 0644]
filesystems/AutoGen.c [new file with mode: 0644]
filesystems/AutoGen.h [new file with mode: 0644]
filesystems/Doxyfile [new file with mode: 0644]
filesystems/LICENSE.txt [new file with mode: 0644]
filesystems/LICENSE_GPL.txt [new file with mode: 0644]
filesystems/Make.gnuefi [new file with mode: 0644]
filesystems/Make.tiano [new file with mode: 0644]
filesystems/Makefile [new file with mode: 0644]
filesystems/crc32c.c [new file with mode: 0644]
filesystems/design.dox [new file with mode: 0644]
filesystems/edk2/ComponentName.h [new file with mode: 0644]
filesystems/edk2/DriverBinding.h [new file with mode: 0644]
filesystems/fsw_base.h [new file with mode: 0644]
filesystems/fsw_btrfs.c [new file with mode: 0644]
filesystems/fsw_core.c [new file with mode: 0644]
filesystems/fsw_core.h [new file with mode: 0644]
filesystems/fsw_efi.c [new file with mode: 0644]
filesystems/fsw_efi.h [new file with mode: 0644]
filesystems/fsw_efi_base.h [new file with mode: 0644]
filesystems/fsw_efi_edk2_base.h [new file with mode: 0644]
filesystems/fsw_efi_lib.c [new file with mode: 0644]
filesystems/fsw_ext2.c [new file with mode: 0644]
filesystems/fsw_ext2.h [new file with mode: 0644]
filesystems/fsw_ext2_disk.h [new file with mode: 0644]
filesystems/fsw_ext4.c [new file with mode: 0644]
filesystems/fsw_ext4.h [new file with mode: 0644]
filesystems/fsw_ext4_disk.h [new file with mode: 0644]
filesystems/fsw_hfs.c [new file with mode: 0644]
filesystems/fsw_hfs.h [new file with mode: 0644]
filesystems/fsw_iso9660.c [new file with mode: 0644]
filesystems/fsw_iso9660.h [new file with mode: 0644]
filesystems/fsw_lib.c [new file with mode: 0644]
filesystems/fsw_ntfs.c [new file with mode: 0644]
filesystems/fsw_reiserfs.c [new file with mode: 0644]
filesystems/fsw_reiserfs.h [new file with mode: 0644]
filesystems/fsw_reiserfs_disk.h [new file with mode: 0644]
filesystems/fsw_strfunc.h [new file with mode: 0644]
filesystems/gzio.c [new file with mode: 0644]
filesystems/hfs_format.h [new file with mode: 0644]
filesystems/lzoconf.h [new file with mode: 0644]
filesystems/lzodefs.h [new file with mode: 0644]
filesystems/minilzo.c [new file with mode: 0644]
filesystems/minilzo.h [new file with mode: 0644]
filesystems/scandisk.c [new file with mode: 0644]
filesystems/test/Makefile [new file with mode: 0644]
filesystems/test/README [new file with mode: 0644]
filesystems/test/fsw_posix.c [new file with mode: 0644]
filesystems/test/fsw_posix.h [new file with mode: 0644]
filesystems/test/fsw_posix_base.h [new file with mode: 0644]
filesystems/test/lslr.c [new file with mode: 0644]
filesystems/test/lsroot.c [new file with mode: 0644]
fonts/README.txt [new file with mode: 0644]
fonts/liberation-mono-regular-12.png [new file with mode: 0644]
fonts/liberation-mono-regular-14.png [new file with mode: 0644]
fonts/liberation-mono-regular-24.png [new file with mode: 0644]
fonts/mkfont.sh [new file with mode: 0755]
fonts/nimbus-mono-12.png [new file with mode: 0644]
fonts/nimbus-mono-14.png [new file with mode: 0644]
fonts/nimbus-mono-16.png [new file with mode: 0644]
fonts/nimbus-mono-24.png [new file with mode: 0644]
fonts/ubuntu-mono-12.png [new file with mode: 0644]
fonts/ubuntu-mono-14.png [new file with mode: 0644]
fonts/ubuntu-mono-16.png [new file with mode: 0644]
fonts/ubuntu-mono-24.png [new file with mode: 0644]
gptsync/AutoGen.c [new file with mode: 0644]
gptsync/AutoGen.h [new file with mode: 0644]
gptsync/Make.gnuefi [new file with mode: 0644]
gptsync/Make.tiano [new file with mode: 0644]
gptsync/Make.unix [new file with mode: 0644]
gptsync/Makefile [new file with mode: 0644]
gptsync/README.txt [new file with mode: 0644]
gptsync/gptsync.8 [new file with mode: 0644]
gptsync/gptsync.c [new file with mode: 0644]
gptsync/gptsync.h [new file with mode: 0644]
gptsync/gptsync.mak [new file with mode: 0644]
gptsync/lib.c [new file with mode: 0644]
gptsync/os_efi.c [new file with mode: 0644]
gptsync/os_unix.c [new file with mode: 0644]
gptsync/showpart.c [new file with mode: 0644]
icons/README [new file with mode: 0644]
icons/arrow_left.png [new file with mode: 0644]
icons/arrow_right.png [new file with mode: 0644]
icons/boot_linux.png [new file with mode: 0644]
icons/boot_win.png [new file with mode: 0644]
icons/func_about.png [new file with mode: 0644]
icons/func_csr_rotate.png [new file with mode: 0644]
icons/func_exit.png [new file with mode: 0644]
icons/func_firmware.png [new file with mode: 0644]
icons/func_reset.png [new file with mode: 0644]
icons/func_shutdown.png [new file with mode: 0644]
icons/licenses/cc-3.0.txt [new file with mode: 0644]
icons/licenses/gpl-2.0.txt [new file with mode: 0644]
icons/licenses/lgpl-3.0.txt [new file with mode: 0644]
icons/os_arch.png [new file with mode: 0644]
icons/os_centos.png [new file with mode: 0644]
icons/os_chakra.png [new file with mode: 0644]
icons/os_chrome.png [new file with mode: 0644]
icons/os_clover.png [new file with mode: 0644]
icons/os_crunchbang.png [new file with mode: 0644]
icons/os_debian.png [new file with mode: 0644]
icons/os_elementary.png [new file with mode: 0644]
icons/os_fedora.png [new file with mode: 0644]
icons/os_freebsd.png [new file with mode: 0644]
icons/os_frugalware.png [new file with mode: 0644]
icons/os_gentoo.png [new file with mode: 0644]
icons/os_gummiboot.png [new file with mode: 0644]
icons/os_haiku.png [new file with mode: 0644]
icons/os_hwtest.png [new file with mode: 0644]
icons/os_kubuntu.png [new file with mode: 0644]
icons/os_legacy.png [new file with mode: 0644]
icons/os_linux.png [new file with mode: 0644]
icons/os_linuxmint.png [new file with mode: 0644]
icons/os_lubuntu.png [new file with mode: 0644]
icons/os_mac.png [new file with mode: 0644]
icons/os_mageia.png [new file with mode: 0644]
icons/os_mandriva.png [new file with mode: 0644]
icons/os_netbsd.png [new file with mode: 0644]
icons/os_network.png [new file with mode: 0644]
icons/os_opensuse.png [new file with mode: 0644]
icons/os_redhat.png [new file with mode: 0644]
icons/os_refind.png [new file with mode: 0644]
icons/os_refit.png [new file with mode: 0644]
icons/os_slackware.png [new file with mode: 0644]
icons/os_suse.png [new file with mode: 0644]
icons/os_ubuntu.png [new file with mode: 0644]
icons/os_unknown.png [new file with mode: 0644]
icons/os_win.png [new file with mode: 0644]
icons/os_win8.png [new file with mode: 0644]
icons/os_xubuntu.png [new file with mode: 0644]
icons/svg/boot_win.svg [new file with mode: 0644]
icons/svg/func_csr_rotate.svg [new file with mode: 0644]
icons/svg/os_clover.svg [new file with mode: 0644]
icons/svg/os_debian.svg [new file with mode: 0644]
icons/svg/os_elementary.svg [new file with mode: 0644]
icons/svg/os_gummiboot.svg [new file with mode: 0644]
icons/svg/os_haiku.svg [new file with mode: 0644]
icons/svg/os_legacy.svg [new file with mode: 0644]
icons/svg/os_mac.svg [new file with mode: 0644]
icons/svg/os_netbsd.svg [new file with mode: 0644]
icons/svg/os_redhat.svg [new file with mode: 0644]
icons/svg/os_refind.svg [new file with mode: 0644]
icons/svg/os_refit.svg [new file with mode: 0644]
icons/svg/os_win.svg [new file with mode: 0644]
icons/svg/tool_memtest.svg [new file with mode: 0644]
icons/tool_apple_rescue.png [new file with mode: 0644]
icons/tool_memtest.png [new file with mode: 0644]
icons/tool_mok_tool.png [new file with mode: 0644]
icons/tool_netboot.png [new file with mode: 0644]
icons/tool_part.png [new file with mode: 0644]
icons/tool_rescue.png [new file with mode: 0644]
icons/tool_shell.png [new file with mode: 0644]
icons/tool_windows_rescue.png [new file with mode: 0644]
icons/transparent.png [new file with mode: 0644]
icons/vol_external.png [new file with mode: 0644]
icons/vol_internal.png [new file with mode: 0644]
icons/vol_net.png [new file with mode: 0644]
icons/vol_optical.png [new file with mode: 0644]
images/back-normal-big.png [new file with mode: 0644]
images/back-normal-small.png [new file with mode: 0644]
images/back-selected-big.png [new file with mode: 0644]
images/back-selected-small.png [new file with mode: 0644]
images/font.png [new file with mode: 0644]
images/imgprepare.py [new file with mode: 0755]
images/linux-bootlogo.png [new file with mode: 0644]
images/mkeei.py [new file with mode: 0755]
images/mkegemb.py [new file with mode: 0755]
images/refind_banner.bmp [new file with mode: 0644]
images/refind_banner.odt [new file with mode: 0644]
images/txt.pl [new file with mode: 0755]
images/windows-bootlogo.png [new file with mode: 0644]
include/Bmp.h [new file with mode: 0644]
include/Handle.h [new file with mode: 0644]
include/PeImage.h [new file with mode: 0644]
include/PeImage2.h [new file with mode: 0644]
include/RemovableMedia.h [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_big.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]
include/tiano_includes.h [new file with mode: 0644]
keys/README.txt [new file with mode: 0644]
keys/SLES-UEFI-CA-Certificate.cer [new file with mode: 0644]
keys/SLES-UEFI-CA-Certificate.crt [new file with mode: 0644]
keys/altlinux.cer [new file with mode: 0644]
keys/canonical-uefi-ca.crt [new file with mode: 0644]
keys/canonical-uefi-ca.der [new file with mode: 0644]
keys/fedora-ca.cer [new file with mode: 0644]
keys/fedora-ca.crt [new file with mode: 0644]
keys/microsoft-kekca-public.der [new file with mode: 0644]
keys/microsoft-pca-public.der [new file with mode: 0644]
keys/microsoft-uefica-public.der [new file with mode: 0644]
keys/openSUSE-UEFI-CA-Certificate-4096.cer [new file with mode: 0644]
keys/openSUSE-UEFI-CA-Certificate-4096.crt [new file with mode: 0644]
keys/openSUSE-UEFI-CA-Certificate.cer [new file with mode: 0644]
keys/openSUSE-UEFI-CA-Certificate.crt [new file with mode: 0644]
keys/refind.cer [new file with mode: 0644]
keys/refind.crt [new file with mode: 0644]
libeg/Make.tiano [new file with mode: 0644]
libeg/Makefile [new file with mode: 0644]
libeg/efiConsoleControl.h [new file with mode: 0644]
libeg/efiUgaDraw.h [new file with mode: 0644]
libeg/egemb_font.h [new file with mode: 0644]
libeg/image.c [new file with mode: 0644]
libeg/libeg.h [new file with mode: 0644]
libeg/libegint.h [new file with mode: 0644]
libeg/load_bmp.c [new file with mode: 0644]
libeg/load_icns.c [new file with mode: 0644]
libeg/lodepng.c [new file with mode: 0644]
libeg/lodepng.h [new file with mode: 0644]
libeg/lodepng_xtra.c [new file with mode: 0644]
libeg/screen.c [new file with mode: 0644]
libeg/text.c [new file with mode: 0644]
mkcdimage [new file with mode: 0755]
mkdistrib [new file with mode: 0755]
mkrlconf [new file with mode: 0755]
mok/COPYING [new file with mode: 0644]
mok/Make.tiano [new file with mode: 0644]
mok/Makefile [new file with mode: 0644]
mok/guid.c [new file with mode: 0644]
mok/guid.h [new file with mode: 0644]
mok/mok.c [new file with mode: 0644]
mok/mok.h [new file with mode: 0644]
mok/security_policy.c [new file with mode: 0644]
mok/security_policy.h [new file with mode: 0644]
mok/simple_file.c [new file with mode: 0644]
mok/simple_file.h [new file with mode: 0644]
mountesp [new file with mode: 0755]
mvrefind [new file with mode: 0755]
net/Makefile [new file with mode: 0644]
net/discovery/Makefile.housekeeping [new file with mode: 0644]
net/discovery/console.h [new file with mode: 0644]
net/discovery/efi_discovery_prefix.c [new file with mode: 0644]
old-banners/refind.svg [new file with mode: 0644]
old-banners/refind_blue.png [new file with mode: 0644]
old-banners/refind_lighter.png [new file with mode: 0644]
old-banners/refind_metal.png [new file with mode: 0644]
old-banners/refind_original.png [new file with mode: 0644]
refind-alt.spec [new file with mode: 0644]
refind-install [new file with mode: 0755]
refind.conf-sample [new file with mode: 0644]
refind.inf [new file with mode: 0644]
refind.spec [new file with mode: 0644]
refind/AutoGen.c [new file with mode: 0644]
refind/AutoGen.h [new file with mode: 0644]
refind/Make.tiano [new file with mode: 0644]
refind/Makefile [new file with mode: 0644]
refind/apple.c [new file with mode: 0644]
refind/apple.h [new file with mode: 0644]
refind/config.c [new file with mode: 0644]
refind/config.h [new file with mode: 0644]
refind/crc32.c [new file with mode: 0644]
refind/crc32.h [new file with mode: 0644]
refind/driver_support.c [new file with mode: 0644]
refind/driver_support.h [new file with mode: 0644]
refind/global.h [new file with mode: 0644]
refind/gpt.c [new file with mode: 0644]
refind/gpt.h [new file with mode: 0644]
refind/icns.c [new file with mode: 0644]
refind/icns.h [new file with mode: 0644]
refind/legacy.c [new file with mode: 0644]
refind/legacy.h [new file with mode: 0644]
refind/lib.c [new file with mode: 0644]
refind/lib.h [new file with mode: 0644]
refind/line_edit.c [new file with mode: 0644]
refind/line_edit.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/mystrings.c [new file with mode: 0644]
refind/mystrings.h [new file with mode: 0644]
refind/screen.c [new file with mode: 0644]
refind/screen.h [new file with mode: 0644]
themes/snowy/README.txt [new file with mode: 0644]
themes/snowy/snowy/README [new file with mode: 0644]
themes/snowy/snowy/arrow_left.png [new file with mode: 0644]
themes/snowy/snowy/arrow_right.png [new file with mode: 0644]
themes/snowy/snowy/banner-snowy.png [new file with mode: 0644]
themes/snowy/snowy/boot_linux.png [new file with mode: 0644]
themes/snowy/snowy/boot_win.png [new file with mode: 0644]
themes/snowy/snowy/func_about.png [new file with mode: 0644]
themes/snowy/snowy/func_csr_rotate.png [new file with mode: 0644]
themes/snowy/snowy/func_exit.png [new file with mode: 0644]
themes/snowy/snowy/func_firmware.png [new file with mode: 0644]
themes/snowy/snowy/func_reset.png [new file with mode: 0644]
themes/snowy/snowy/func_shutdown.png [new file with mode: 0644]
themes/snowy/snowy/licenses/cc-3.0.txt [new file with mode: 0644]
themes/snowy/snowy/licenses/lgpl-3.0.txt [new file with mode: 0644]
themes/snowy/snowy/os_arch.png [new file with mode: 0644]
themes/snowy/snowy/os_centos.png [new file with mode: 0644]
themes/snowy/snowy/os_chakra.png [new file with mode: 0644]
themes/snowy/snowy/os_chrome.png [new file with mode: 0644]
themes/snowy/snowy/os_clover.png [new file with mode: 0644]
themes/snowy/snowy/os_crunchbang.png [new file with mode: 0644]
themes/snowy/snowy/os_debian.png [new file with mode: 0644]
themes/snowy/snowy/os_elementary.png [new file with mode: 0644]
themes/snowy/snowy/os_fedora.png [new file with mode: 0644]
themes/snowy/snowy/os_freebsd.png [new file with mode: 0644]
themes/snowy/snowy/os_frugalware.png [new file with mode: 0644]
themes/snowy/snowy/os_gentoo.png [new file with mode: 0644]
themes/snowy/snowy/os_gummiboot.png [new file with mode: 0644]
themes/snowy/snowy/os_haiku.png [new file with mode: 0644]
themes/snowy/snowy/os_hwtest.png [new file with mode: 0644]
themes/snowy/snowy/os_kubuntu.png [new file with mode: 0644]
themes/snowy/snowy/os_legacy.png [new file with mode: 0644]
themes/snowy/snowy/os_linux.png [new file with mode: 0644]
themes/snowy/snowy/os_linuxmint.png [new file with mode: 0644]
themes/snowy/snowy/os_lubuntu.png [new file with mode: 0644]
themes/snowy/snowy/os_mac.png [new file with mode: 0644]
themes/snowy/snowy/os_mageia.png [new file with mode: 0644]
themes/snowy/snowy/os_mandriva.png [new file with mode: 0644]
themes/snowy/snowy/os_netbsd.png [new file with mode: 0644]
themes/snowy/snowy/os_network.png [new file with mode: 0644]
themes/snowy/snowy/os_opensuse.png [new file with mode: 0644]
themes/snowy/snowy/os_redhat.png [new file with mode: 0644]
themes/snowy/snowy/os_refind.png [new file with mode: 0644]
themes/snowy/snowy/os_refit.png [new file with mode: 0644]
themes/snowy/snowy/os_slackware.png [new file with mode: 0644]
themes/snowy/snowy/os_suse.png [new file with mode: 0644]
themes/snowy/snowy/os_ubuntu.png [new file with mode: 0644]
themes/snowy/snowy/os_unknown.png [new file with mode: 0644]
themes/snowy/snowy/os_win.png [new file with mode: 0644]
themes/snowy/snowy/os_win8.png [new file with mode: 0644]
themes/snowy/snowy/os_xubuntu.png [new file with mode: 0644]
themes/snowy/snowy/svg/arrow_left.svg [new file with mode: 0644]
themes/snowy/snowy/svg/arrow_right.svg [new file with mode: 0644]
themes/snowy/snowy/svg/boot_win.svg [new file with mode: 0644]
themes/snowy/snowy/svg/func_csr_rotate.svg [new file with mode: 0644]
themes/snowy/snowy/svg/os_clover.svg [new file with mode: 0644]
themes/snowy/snowy/svg/os_debian.svg [new file with mode: 0644]
themes/snowy/snowy/svg/os_elementary.svg [new file with mode: 0644]
themes/snowy/snowy/svg/os_gummiboot.svg [new file with mode: 0644]
themes/snowy/snowy/svg/os_haiku.svg [new file with mode: 0644]
themes/snowy/snowy/svg/os_legacy.svg [new file with mode: 0644]
themes/snowy/snowy/svg/os_mac.svg [new file with mode: 0644]
themes/snowy/snowy/svg/os_netbsd.svg [new file with mode: 0644]
themes/snowy/snowy/svg/os_redhat.svg [new file with mode: 0644]
themes/snowy/snowy/svg/os_refind.svg [new file with mode: 0644]
themes/snowy/snowy/svg/os_refit.svg [new file with mode: 0644]
themes/snowy/snowy/svg/os_win.svg [new file with mode: 0644]
themes/snowy/snowy/svg/tool_apple_rescue.svg [new file with mode: 0644]
themes/snowy/snowy/svg/tool_memtest.svg [new file with mode: 0644]
themes/snowy/snowy/svg/tool_rescue.png [new file with mode: 0644]
themes/snowy/snowy/tool_apple_rescue.png [new file with mode: 0644]
themes/snowy/snowy/tool_memtest.png [new file with mode: 0644]
themes/snowy/snowy/tool_mok_tool.png [new file with mode: 0644]
themes/snowy/snowy/tool_netboot.png [new file with mode: 0644]
themes/snowy/snowy/tool_part.png [new file with mode: 0644]
themes/snowy/snowy/tool_rescue.png [new file with mode: 0644]
themes/snowy/snowy/tool_shell.png [new file with mode: 0644]
themes/snowy/snowy/tool_windows_rescue.png [new file with mode: 0644]
themes/snowy/snowy/transparent.png [new file with mode: 0644]
themes/snowy/snowy/vol_external.png [new file with mode: 0644]
themes/snowy/snowy/vol_internal.png [new file with mode: 0644]
themes/snowy/snowy/vol_net.png [new file with mode: 0644]
themes/snowy/snowy/vol_optical.png [new file with mode: 0644]

diff --git a/BUILDING.txt b/BUILDING.txt
new file mode 100644 (file)
index 0000000..4f65193
--- /dev/null
@@ -0,0 +1,321 @@
+Requirements
+============
+
+To compile rEFInd, you'll need the following:
+
+* A Linux installation. Note that this installation does NOT need to be
+  EFI-based. It can be 32- or 64-bit, but unless you use a cross-compiler
+  (which I've not tested), it must be the appropriate bit width for your
+  EFI implementation. (Normally that means 64-bit.) If you don't normally
+  run Linux, you can run it in a VirtualBox or similar virtual machine. (I
+  describe some unsupported non-Linux build options shortly.)
+
+* A standard set of Linux development tools, based on GCC.
+
+* One of the following:
+
+  * The TianoCore EDK2 package
+    (http://sourceforge.net/projects/tianocore/). I initially used the
+    UDK2010 package and others in that series, but beginning with rEFInd
+    0.8.2, I've been using UDK2014
+    (http://sourceforge.net/apps/mediawiki/tianocore/index.php?title=UDK2014).
+    All of the UDK release are "frozen," rather than the main EDK2
+    development branch, which is changing as the developers add features,
+    fix bugs, and so on. See below for TianoCore setup instructions.
+
+  * The GNU-EFI package (http://sourceforge.net/projects/gnu-efi/). You can
+    install this from a package called "gnu-efi"; however, rEFInd relies on
+    features that were added sometime between version 3.0s and 3.0u, so I
+    recommend using 3.0u (or conceivably later). You should check your
+    GNU-EFI version number; you may need to download the latest source
+    code, compile it, and install it locally. The Makefiles assume a
+    GNU-EFI package installed via a package manager. If you install from
+    source code, you may need to adjust those Makefiles' paths.
+
+Of the two toolkits, I prefer to use TianoCore because it produces binaries
+that are about 20-30KiB smaller than those made by GNU-EFI, and I can
+easily build 32-bit binaries on my 64-bit Linux installations. Also, I've
+had problems on a 32-bit Mac Mini with the drivers produced by GNU-EFI
+hanging the system if I try to load more than one of them. (I haven't
+encountered this problem on UEFI-based PCs.) That said, the TianoCore EDK2
+package is much harder to install, so you may prefer to use GNU-EFI unless
+you have a specific need for the TianoCore toolkit. Automated build tools
+like the OpenSUSE Build Service (OBS) and the Ubuntu Personal Package
+Archive (PPA) mechanism don't yet support TianoCore.
+
+It's possible to use a non-Linux platform to compile rEFInd. To the best of
+my knowledge, the rEFInd code doesn't rely on anything Linux-specific in
+its build requirements, and GNU-EFI's Sourceforge page indicates that it
+works under Windows and OS X, too; however, my one attempt to compile
+GNU-EFI under OS X failed. I've received one report that rEFInd compiles
+successfully with Clang and the TianoCore toolkit under OS X by adding the
+refind.inf file to a .dsc file that you use for your own projects. You can
+find brief instructions here (note that this is not my documentation):
+
+https://github.com/snarez/refind-edk2
+
+Under Windows, you would need to either create a project or Makefile for
+your non-GCC compiler or use a GCC port, such as MinGW
+(http://www.mingw.org). You'd probably need to adjust the Makefiles in the
+latter case. A procedure similar to that used under OS X might work using
+GCC or Microsoft's C compiler, but I haven't tested this.
+
+
+Preparing Your Development Kit
+==============================
+
+If you're using Linux, GNU-EFI is the easiest way to compile rEFInd. I
+don't describe GNU-EFI's setup here because it's likely to be fairly easy.
+If your distribution provides a recent enough version, you should be able
+to install a package called gnu-efi and be done with it. If not, you'll
+need to download the source code tarball, build it, and install it. This
+process is fairly typical of Linux packages. Read the GNU-EFI documentation
+if you need help. If you're using GNU-EFI, you can skip the rest of this
+section.
+
+You might also want to use the TianoCore toolkit if you have problems with
+GNU-EFI or if you want to build rEFInd on a non-Linux platform.
+Unfortunately, the TianoCore toolkit is weird by Linux programming
+standards. It's also quite large -- it's intended as a means to develop a
+complete EFI firmware implementation, so it contains much more code than is
+needed to develop standalone EFI applications. I don't know of any Linux
+distribution packages for it in RPM, Debian package file, or other formats;
+you MUST install the kit from source code using its own unusual compilation
+procedure. The installation documentation also omits at least one step and
+is a bit unclear about others. Here's how I installed the toolkit:
+
+1) Download UDK2014.SR1.UP1.P1 from
+   https://sourceforge.net/apps/mediawiki/tianocore/index.php?title=UDK2014.
+
+2) Type "mkdir /usr/local/UDK2014". You can use another directory, but the
+   Makefile for rEFInd's EFI drivers assumes this location. You'll need to
+   edit the EDK2BASE line in the Make.tiano file if you install somewhere
+   else.
+
+3) Type "cd /usr/local/UDK2014".
+
+4) Unzip the downloaded file (UDK2014.SR1.UP1.P1.Complete.MyWorkSpace.zip)
+   in the current directory (/usr/local/UDK2014). This creates a handful of
+   files, including a tarball and a couple of .zip files.
+
+5) Type "unzip UDK2014.SR1.UP1.MyWorkSpace.zip". This extracts the
+   platform-neutral portion of the development kit.
+
+6) Type "cd MyWorkSpace".
+
+7) Type "tar xvf ../BaseTools\(Unix\).tar". This extracts the
+   Linux/Unix-specific portions of the toolkit.
+
+8) Follow the build instructions at
+   https://sourceforge.net/apps/mediawiki/tianocore/index.php?title=Using_EDK_II_with_Native_GCC_4.4;
+   however, a few changes are required, as detailed below....
+
+9) Type "source edksetup.sh BaseTools". This sets up some environment
+   variables, so subsequent steps (NOT including compiling the rEFInd EFI
+   drivers) must be typed in the shell you use for this step.
+
+10) Edit Conf/target.txt and change the following:
+    - ACTIVE_PLATFORM = MdePkg/MdePkg.dsc
+    - TARGET = RELEASE (DEBUG might work, but I've not tested it).
+    - TARGET_ARCH = X64 (on x86-64; leave this as IA32 on x86). If you plan
+      to build both architectures on an x86-64 system, you can set this to
+      "IA32 X64".
+    - TOOL_CHAIN_TAG = GCC46 (or other value depending on your GCC version;
+      type "gcc -v" to learn your GCC version number). Note that GCC 4.7
+      and 4.8 don't have their own entries, so use GCC46 for them.
+    The TianoCore Makefiles read some of these variables from this file
+    and use them when accessing directories, so be sure to type these
+    entries in the case specified.
+
+11) The documentation refers to editing Conf/tools_def.txt in addition to
+    Conf/target.txt, but doesn't specify what to change in
+    Conf/tools_def.txt. I haven't found it necessary to make any changes in
+    Conf/tools_def.txt EXCEPT when using GCC 4.7 on a Fedora 17 system.
+    (I haven't used GCC 4.7 on other platforms, so this may well be
+    necessary on other systems, too.) With that setup, I found it
+    necessary to change the following line:
+    *_GCC46_X64_ASM_FLAGS            = DEF(GCC46_ASM_FLAGS) -m64 -melf_x86_64
+    to:
+    *_GCC46_X64_ASM_FLAGS            = DEF(GCC46_ASM_FLAGS) -m64
+
+12) Type "make -C /usr/local/UDK2014/MyWorkSpace/BaseTools/Source/C".
+    (This step is not documented on the EDK Web page.) Note that this
+    requires the g++ compiler and UUID development libraries.
+    
+13) Type "build" to build the main set of EDK2 files. This process is
+    likely to take a few minutes. This step requires Python 2; if you have
+    Python 3 installed, you may need to adjust the default python for this
+    build (for instance, by typing "eselect python set python2.7" in
+    Gentoo).
+
+If you installed in a location other than the one I've specified, you must
+edit the EDK2BASE variable in the Make.tiano and filesystems/Make.tiano
+files in the rEFInd source package. Once the toolkit is installed, you can
+build the filesystem drivers or rEFInd, as described below.
+
+
+Compiling rEFInd
+================
+
+With your development system set up, you can compile rEFInd as follows:
+
+1) Download and uncompress the rEFInd source code archive. (If you're
+   reading this file, you've probably already done this task.)
+
+2) Open a Linux shell prompt
+
+3) Change into the archive's main directory. You should see several files
+   including this BUILDING.txt file and several subdirectories such as
+   "refind", "libeg", "mok", "filesystems", and "include".
+
+4) Type "make gnuefi" to build with GNU-EFI, or either "make" alone or
+   "make tiano" to build with TianoCore EDK2. With any luck, rEFInd will
+   compile without error, leaving the "refind_ia32.efi" or "refind_x64.efi"
+   file, depending on your platform, in the "refind" subdirectory. This same
+   step builds the "gptsync_x64.efi" or "gptsync_ia32.efi" program file, in
+   the "gptsync" subdirectory. If you want to build IA32 binaries on an
+   x86-64 (X64) system, type "ARCH=ia32 make". This works only if you're
+   using the TianoCore build kit, and only if you set TARGET_ARCH to either
+   "IA32" or "IA32 X64" in target.txt when you set up the TianoCore toolkit.
+   If you plan to build both architectures, be sure to copy the .efi file
+   for the first build out of the refind subdirectory before building the
+   second architecture.
+
+5) The default build process does NOT build the filesystem drivers. If you
+   want to build them, you must type "make fs" in the main rEFInd source
+   directory to build with the TianoCore EDK2, or "make fs_gnuefi" to build
+   with GNU-EFI. (Typing "ARCH=ia32 make fs" builds IA32 filesystem drivers
+   on an x86-64 system, provided TianoCore is properly configured, as
+   described earlier.) The result is filesystem drivers in the filesystems
+   subdirectory, and also copies placed in the drivers_{arch} subdirectory.
+
+If rEFInd doesn't compile correctly, you'll need to track down the source
+of the problem. Double-check that you've got all the necessary development
+tools installed, including GCC, make, and either GNU-EFI or TianoCore EDK2.
+You may also need to adjust the Makefile, Make.common file, or Make.tiano
+file for your system. (The main Makefile controls the process for both
+toolkits, while Make.common holds GNU-EFI options and Make.tiano holds
+TianoCore options.) The most likely thing you'll need to change is the path
+to the various GNU-EFI include files and libraries. Since rEFInd 0.6.2, the
+default Make.common file includes the following definitions:
+
+EFIINC          = /usr/include/efi
+GNUEFILIB       = /usr/lib
+EFILIB          = /usr/lib
+EFICRT0         = /usr/lib
+
+If you've installed GNU-EFI from source code, you may need to add "local"
+to those paths, as in "/usr/local/include/efi". You might need to change
+references to "lib" to "lib32" or "lib64" on some systems. Recall that you
+need at least GNU-EFI version 3.0l to build rEFInd, and until very
+recently, most distributions provided out-of-date versions of this package.
+
+If you're using TianoCore's EDK2, as noted earlier, you may need to adjust
+the EDK2BASE variable in Make.tiano and filesystems/Make.tiano.
+
+When I tried to compile rEFInd under Ubuntu 12.04 (i386) using GNU-EFI,
+even with a locally-compiled GNU-EFI 3.0p or 3.0q, I got errors like this:
+
+main.o: In function `StartLegacy.isra.0':
+main.c:(.text+0x8b1): undefined reference to `__stack_chk_fail_local'
+lib.o: In function `ScanVolumeBootcode.part.3':
+lib.c:(.text+0xf2f): undefined reference to `__stack_chk_fail_local'
+lib.o: In function `ScanExtendedPartition.isra.4':
+
+The solution was to recompile GNU-EFI with the -fno-stack-protector GCC
+flag. In GNU-EFI, this can be added to the CFLAGS line in Make.defaults.
+
+
+Installing rEFInd
+=================
+
+With rEFInd compiled, you can install it. The easiest way to do this is
+with the refind-install script, which works on both Linux and Mac OS X.
+Alternatively, you can type "make install" to install using this script.
+Note that this script copies files to the ESP and uses "efibootmgr" (on
+Linux) or "bless" (on OS X) to add rEFInd to the firmware's boot loader
+list. The docs/refind/installing.html file provides more details on this
+script and its use.
+
+If refind-install doesn't work for you or if you prefer to do the job
+manually, you may. On a UEFI-based system, you'll want to copy files on the
+ESP as follows:
+
+* Create a directory for rEFInd, such as EFI/refind.
+* Copy refind/refind_ia32.efi or refind_x64.efi to the ESP's EFI/refind
+  directory.
+* Copy refind.conf-sample to the EFI/refind directory as refind.conf.
+* Copy the icons subdirectory, including all its files, to EFI/refind.
+
+You'll then need to activate rEFInd in your EFI. This can be done with
+tools such as "efibootmgr" under Linux or "bless" under OS X. See the
+docs/refind/installing.html file for details.
+
+
+Note to Distribution Maintainers
+================================
+
+The refind-install script, and therefore the "install" target in the
+Makefile, installs the program directly to the ESP and it modifies the
+*CURRENT COMPUTER's* NVRAM. Thus, you should *NOT* use this target as part
+of the build process for your binary packages (RPMs, Debian packages,
+etc.). (Gentoo could use it in an ebuild, though....) You COULD, however,
+install the files to a directory somewhere (/usr/share/refind or whatever)
+and then call refind-install as part of the binary package installation
+process. Placing the files directly in /boot/efi/EFI/{distname}/refind and
+then having a post-install script call efibootmgr is probably the better
+way to go, but this assumes that the ESP is mounted at /boot/efi.
+
+
+Compiling the EFI Filesystem Drivers
+====================================
+
+To build all the drivers, you can type "make fs" or "make fs_gnuefi" from
+the main directory, which builds the drivers and places copies in both the
+filesystems and drivers_{arch} subdirectories. If you want to build just
+one driver, you can change into the "filesystems" directory and type "make
+{fsname}" or "make {fsname}_gnuefi", where {fsname} is a filesystem name --
+"ext2", "ext4", "reiserfs", "iso9660", or "hfs". In all cases, the build
+target that appends "_gnuefi" builds with GNU-EFI and the one that doesn't
+builds with TianoCore.
+
+To install drivers, you can type "make install" in the "filesystems"
+directory. This copies all the drivers to the
+"/boot/efi/EFI/refind/drivers" directory. Alternatively, you can copy the
+files you want manually. The refind-install script includes an optional
+"--drivers" option that will install the drivers along with the main rEFInd
+program, but to the drivers_{arch} subdirectory of the main rEFInd
+installation directory.
+
+*CAUTION:* Install drivers for your system's architecture *ONLY*.
+Installing drivers for the wrong architecture causes some systems to hang
+at boot time. This risk can be minimized by including the architecture code
+in the drivers subdirectory name (drivers_x64 or drivers_ia32).
+
+The drivers all rely on filesystem wrapper code created by rEFIt's author,
+Christoph Pfisterer. Most of the drivers seem to have passed through
+Oracle's VirtualBox project (https://www.virtualbox.org) and the Clover
+boot loader project (https://sourceforge.net/projects/cloverefiboot/),
+which I used as the source for this build.
+
+Adding Support for Network Boot
+===============================
+
+rEFInd provides EXPERIMENTAL support for booting over the network using
+iPXE (http://ipxe.org) as a means to receive the payload. In order to
+enable this feature you'll want to follow these instructions:
+
+* cd net/
+* make source
+* make netboot
+* copy bin/ipxe.efi and bin/ipxe_discover.efi to the EFI volume at EFI/tools/
+
+Note that you may need to install additional development packages, such as
+libiberty-dev and binutils-dev, in addition to those needed to build rEFInd
+itself.
+
+My own tests show this support to work under optimal conditions; however,
+architecture (EFI vs. BIOS) detection may not work, and some computers will
+hang or won't retrieve boot files from the network. For these reasons, this
+support is disabled by default in rEFInd, and I do not provide iPXE
+binaries.
diff --git a/COPYING.txt b/COPYING.txt
new file mode 100644 (file)
index 0000000..94a9ed0
--- /dev/null
@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/CREDITS.txt b/CREDITS.txt
new file mode 100644 (file)
index 0000000..1200d44
--- /dev/null
@@ -0,0 +1,95 @@
+Although I (Roderick W. Smith) am releasing rEFInd in its current form, the
+program is not the work of a single person. Others have contributed to the
+program, both in its original version (rEFIt) and by providing features
+I've incorporated into the current version. Specifically:
+
+Program (C source code) files:
+------------------------------
+
+* Christoph Pfisterer was the original author of rEFIt. See its Web page,
+  http://refit.sourceforge.net, for this version of the program. Christoph
+  has therefore contributed more to rEFInd than anybody else, myself
+  included; my changes are comparatively small additions to the original
+  rEFIt base.
+
+* The Debian project has made a version of rEFIt available that
+  incorporates a number of patches, all attributed to Julien BLACHE
+  (jblache@debian.org), to enable it to build properly on a Linux system.
+  It was this version of rEFIt that I used as a starting point for creating
+  rEFInd. See http://packages.debian.org/sid/refit for this version of the
+  program.
+
+* The filesystem drivers released with version 0.4.0 rely on a filesystem
+  wrapper created by Christoph Phisterer. They then passed through Oracle's
+  VirtualBox (https://www.virtualbox.org) and the Clover boot loader
+  project (https://sourceforge.net/projects/cloverefiboot/). The
+  filesystem-specific code comes from various sources, including Apple,
+  the Linux kernel, and Christoph Pfisterer.
+
+* Assorted support code is borrowed from the TianoCore EDK2
+  (https://sourceforge.net/projects/tianocore/), which is the reference
+  implementation for EFI.
+
+* Dave Vasilevsky (dave@vasilevsky.ca) contributed the disk-ejection
+  code.
+
+* John Bressler (jrb1327@gmail.com) contributed the code to boot BIOS-based
+  OSes on UEFI-based PCs.
+
+* The code for editing boot options (cursor_left(), cursor_right(), and
+  line_edit() in screen.c) is taken from gummiboot
+  (http://freedesktop.org/wiki/Software/gummiboot).
+
+* Stefan Agner (stefan@agner.ch) turned the original ext2fs/ext3fs driver
+  into one that can read ext4fs.
+
+* Samuel Liao ported the GRUB 2 Btrfs and NTFS code into EFI drivers and
+  contributed them to this project, along with several miscellaneous
+  improvements.
+
+* Emerson Barcelos (emerson_freitas@yahoo.com.br) wrote the code for
+  enabling Intel VMX support (the enable_and_lock_vmx token in
+  refind.conf).
+
+* Rohan Sehgal (rohan.sehgal.su@gmail.com) wrote code to help rEFInd
+  detect network boot options and launch them, with the help of the
+  external ipxe.efi and ipxe_discover.efi programs.
+
+* Matthew J. Garrett (mjg@redhat.com) wrote the shim boot loader upon which
+  rEFInd relies for its Secure Boot functionality. I took a few shim
+  functions to help out on the rEFInd side, too; see the mok/mok.c source
+  code file.
+
+* James Bottomley (James.Bottomley@HansenPartnership.com) wrote the
+  Linux Foundation's PreBootloader, which is an alternative to shim. I've
+  found that much of its code is also useful in implementing Secure Boot
+  functionality in rEFInd. Most of the files in the mok subdirectory are
+  based on Bottomley's PreBootloader code.
+
+* The PNG support, in the files libeg/lodepng.c and libeg/lodepng.h, is a
+  slightly modified version of LodePNG (http://lodev.org/lodepng/) by Lode
+  Vandevenne. (The libeg/lodepng_xtra.c file provides some necessary
+  ancillary and interface functions written by me.)
+
+Icons and graphics:
+-------------------
+
+* Most icons are derived from the AwOken icon set, version 2.5, by
+  Alessandro Roncone (aka alecive); see
+  http://alecive.deviantart.com/art/AwOken-163570862. Many of these icons
+  have been scaled or altered in color from their original forms.
+
+* The Debian icon is based on the SVG available from
+  https://commons.wikimedia.org/wiki/File:Debian-OpenLogo.svg. I modified
+  it to fit the general style set by the AwOken icons.
+
+* The Elementary OS icon is based on the SVG available from
+  https://commons.wikimedia.org/wiki/File:Elementary_logo.svg. I modified
+  it to fit the general style set by the AwOken icons.
+
+* Erik Kemperman provided the original (pre-0.9.3) rEFInd icon, which is a
+  combination of the common refresh/reload icon and the search/find icon.
+  For version 0.9.3, I created a new icon from Erik's basic design concept,
+  but to match the AwOken flat-with-drop-shadow style.
+
+* Additional icons were created by me.
diff --git a/EfiLib/BdsConnect.c b/EfiLib/BdsConnect.c
new file mode 100644 (file)
index 0000000..5e36412
--- /dev/null
@@ -0,0 +1,270 @@
+/** @file\r
+  BDS Lib functions which relate with connect the device\r
+\r
+Copyright (c) 2004 - 2008, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "Platform.h"\r
+\r
+\r
+EFI_STATUS ScanDeviceHandles(EFI_HANDLE ControllerHandle,\r
+                             UINTN *HandleCount,\r
+                             EFI_HANDLE **HandleBuffer,\r
+                             UINT32 **HandleType)\r
+{\r
+  EFI_STATUS                          Status;\r
+  UINTN                               HandleIndex;\r
+  EFI_GUID                            **ProtocolGuidArray;\r
+  UINTN                               ArrayCount;\r
+  UINTN                               ProtocolIndex;\r
+  EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfo;\r
+  UINTN                               OpenInfoCount;\r
+  UINTN                               OpenInfoIndex;\r
+  UINTN                               ChildIndex;\r
+\r
+  *HandleCount  = 0;\r
+  *HandleBuffer = NULL;\r
+  *HandleType   = NULL;\r
+\r
+  //\r
+  // Retrieve the list of all handles from the handle database\r
+  //\r
+  Status = gBS->LocateHandleBuffer (AllHandles, NULL, NULL, HandleCount, HandleBuffer);\r
+  if (EFI_ERROR (Status)) goto Error;\r
+\r
+  *HandleType = AllocatePool (*HandleCount * sizeof (UINT32));\r
+  if (*HandleType == NULL) goto Error;\r
+\r
+  for (HandleIndex = 0; HandleIndex < *HandleCount; HandleIndex++) {\r
+    (*HandleType)[HandleIndex] = EFI_HANDLE_TYPE_UNKNOWN;\r
+    //\r
+    // Retrieve the list of all the protocols on each handle\r
+    //\r
+    Status = gBS->ProtocolsPerHandle (\r
+                  (*HandleBuffer)[HandleIndex],\r
+                  &ProtocolGuidArray,\r
+                  &ArrayCount\r
+                  );\r
+    if (!EFI_ERROR (Status)) {      \r
+      for (ProtocolIndex = 0; ProtocolIndex < ArrayCount; ProtocolIndex++) \r
+      {\r
+\r
+        if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiLoadedImageProtocolGuid))\r
+        {\r
+          (*HandleType)[HandleIndex] |= EFI_HANDLE_TYPE_IMAGE_HANDLE;\r
+        }\r
+\r
+        if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiDriverBindingProtocolGuid))\r
+        {\r
+          (*HandleType)[HandleIndex] |= EFI_HANDLE_TYPE_DRIVER_BINDING_HANDLE;\r
+        }\r
+\r
+        if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiDriverConfigurationProtocolGuid)) \r
+        {\r
+          (*HandleType)[HandleIndex] |= EFI_HANDLE_TYPE_DRIVER_CONFIGURATION_HANDLE;\r
+        }\r
+\r
+        if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiDriverDiagnosticsProtocolGuid)) \r
+        {\r
+          (*HandleType)[HandleIndex] |= EFI_HANDLE_TYPE_DRIVER_DIAGNOSTICS_HANDLE;\r
+        }\r
+\r
+        if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiComponentName2ProtocolGuid)) \r
+        {\r
+          (*HandleType)[HandleIndex] |= EFI_HANDLE_TYPE_COMPONENT_NAME_HANDLE;\r
+        }\r
+\r
+        if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiComponentNameProtocolGuid) ) \r
+        {\r
+          (*HandleType)[HandleIndex] |= EFI_HANDLE_TYPE_COMPONENT_NAME_HANDLE;\r
+        }\r
+\r
+        if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiDevicePathProtocolGuid)) \r
+        {\r
+          (*HandleType)[HandleIndex] |= EFI_HANDLE_TYPE_DEVICE_HANDLE;\r
+        }\r
+\r
+        //\r
+        // Retrieve the list of agents that have opened each protocol\r
+        //\r
+        Status = gBS->OpenProtocolInformation (\r
+                                               (*HandleBuffer)[HandleIndex],\r
+                                               ProtocolGuidArray[ProtocolIndex],\r
+                                               &OpenInfo,\r
+                                               &OpenInfoCount\r
+                                               );\r
+        if (!EFI_ERROR (Status)) {\r
+\r
+          for (OpenInfoIndex = 0; OpenInfoIndex < OpenInfoCount; OpenInfoIndex++) {\r
+\r
+            if (OpenInfo[OpenInfoIndex].ControllerHandle == ControllerHandle)\r
+            {\r
+              if ((OpenInfo[OpenInfoIndex].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) == EFI_OPEN_PROTOCOL_BY_DRIVER) \r
+              {\r
+                for (ChildIndex = 0; ChildIndex < *HandleCount; ChildIndex++) \r
+                {\r
+                  if ((*HandleBuffer)[ChildIndex] == OpenInfo[OpenInfoIndex].AgentHandle) \r
+                  {\r
+                    (*HandleType)[ChildIndex] |= EFI_HANDLE_TYPE_DEVICE_DRIVER;\r
+                  }\r
+                }\r
+              }\r
+\r
+              if ((OpenInfo[OpenInfoIndex].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) == EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER)\r
+              {\r
+                (*HandleType)[HandleIndex] |= EFI_HANDLE_TYPE_PARENT_HANDLE;\r
+                for (ChildIndex = 0; ChildIndex < *HandleCount; ChildIndex++) \r
+                {\r
+                  if ((*HandleBuffer)[ChildIndex] == OpenInfo[OpenInfoIndex].AgentHandle) \r
+                  {\r
+                    (*HandleType)[ChildIndex] |= EFI_HANDLE_TYPE_BUS_DRIVER;\r
+                  }\r
+                }\r
+              }\r
+            }\r
+          }\r
+\r
+          FreePool (OpenInfo);\r
+        }\r
+      }\r
+\r
+      FreePool (ProtocolGuidArray);\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+\r
+Error:\r
+  if (*HandleType != NULL) {\r
+    FreePool (*HandleType);\r
+  }\r
+\r
+  if (*HandleBuffer != NULL) {\r
+    FreePool (*HandleBuffer);\r
+  }\r
+\r
+  *HandleCount  = 0;\r
+  *HandleBuffer = NULL;\r
+  *HandleType   = NULL;\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+\r
+EFI_STATUS BdsLibConnectMostlyAllEfi()\r
+{\r
+       EFI_STATUS                              Status;\r
+       UINTN             AllHandleCount;\r
+       EFI_HANDLE                              *AllHandleBuffer;\r
+       UINTN             Index;\r
+       UINTN             HandleCount;\r
+       EFI_HANDLE                              *HandleBuffer;\r
+       UINT32            *HandleType;\r
+       UINTN             HandleIndex;\r
+       BOOLEAN           Parent;\r
+       BOOLEAN           Device;\r
+       EFI_PCI_IO_PROTOCOL*    PciIo;\r
+       PCI_TYPE00                              Pci;\r
+  \r
+  \r
+       Status = gBS->LocateHandleBuffer (AllHandles, NULL, NULL, &AllHandleCount, &AllHandleBuffer);\r
+       if (CheckError(Status, L"locating handle buffer")) \r
+               return Status;\r
+  \r
+       for (Index = 0; Index < AllHandleCount; Index++) \r
+       {\r
+               Status = ScanDeviceHandles(AllHandleBuffer[Index], &HandleCount, &HandleBuffer, &HandleType);\r
+    \r
+               if (EFI_ERROR (Status))\r
+                       goto Done;\r
+    \r
+               Device = TRUE;\r
+               \r
+               if (HandleType[Index] & EFI_HANDLE_TYPE_DRIVER_BINDING_HANDLE)\r
+                       Device = FALSE;\r
+               if (HandleType[Index] & EFI_HANDLE_TYPE_IMAGE_HANDLE)\r
+                       Device = FALSE;\r
+    \r
+               if (Device) \r
+               {                                       \r
+                       Parent = FALSE;\r
+                       for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) \r
+                       {\r
+                               if (HandleType[HandleIndex] & EFI_HANDLE_TYPE_PARENT_HANDLE)\r
+                                       Parent = TRUE;\r
+                       }\r
+      \r
+                       if (!Parent) \r
+                       {\r
+                               if (HandleType[Index] & EFI_HANDLE_TYPE_DEVICE_HANDLE) \r
+                               {\r
+                                       Status = gBS->HandleProtocol (AllHandleBuffer[Index], &gEfiPciIoProtocolGuid, (VOID*)&PciIo);\r
+                                       if (!EFI_ERROR (Status)) \r
+                                       {\r
+                                               Status = PciIo->Pci.Read (PciIo,EfiPciIoWidthUint32, 0, sizeof (Pci) / sizeof (UINT32), &Pci);\r
+                                               if (!EFI_ERROR (Status))\r
+                                               {\r
+                                                       if(IS_PCI_VGA(&Pci)==TRUE)\r
+                                                       {\r
+                                                               gBS->DisconnectController(AllHandleBuffer[Index], NULL, NULL);\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                                       Status = gBS->ConnectController(AllHandleBuffer[Index], NULL, NULL, TRUE);\r
+                               }\r
+                       }\r
+               }\r
+    \r
+               FreePool (HandleBuffer);\r
+               FreePool (HandleType);\r
+       }\r
+  \r
+Done:\r
+       FreePool (AllHandleBuffer);\r
+       return Status;\r
+}\r
+\r
+\r
+\r
+/**\r
+  Connects all drivers to all controllers.\r
+  This function make sure all the current system driver will manage\r
+  the correspoinding controllers if have. And at the same time, make\r
+  sure all the system controllers have driver to manage it if have.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+BdsLibConnectAllDriversToAllControllers (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  do {\r
+    //\r
+    // Connect All EFI 1.10 drivers following EFI 1.10 algorithm\r
+    //\r
+    //BdsLibConnectAllEfi ();\r
+    BdsLibConnectMostlyAllEfi ();\r
+\r
+    //\r
+    // Check to see if it's possible to dispatch an more DXE drivers.\r
+    // The BdsLibConnectAllEfi () may have made new DXE drivers show up.\r
+    // If anything is Dispatched Status == EFI_SUCCESS and we will try\r
+    // the connect again.\r
+    //\r
+    Status = gDS->Dispatch ();\r
+\r
+  } while (!EFI_ERROR (Status));\r
+\r
+}\r
diff --git a/EfiLib/BdsHelper.c b/EfiLib/BdsHelper.c
new file mode 100644 (file)
index 0000000..a890f7d
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * EfiLib/BdsHelper.c
+ * Functions to call legacy BIOS API.
+ *
+ */
+/**
+
+Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "BdsHelper.h"
+#include "legacy.h"
+#include "mystrings.h"
+#include "../refind/screen.h"
+#include "../refind/lib.h"
+#include "../include/refit_call_wrapper.h"
+
+EFI_GUID gEfiLegacyBootProtocolGuid     = { 0xdb9a1e3d, 0x45cb, 0x4abb, { 0x85, 0x3b, 0xe5, 0x38, 0x7f, 0xdb, 0x2e, 0x2d }};
+
+/**
+    Internal helper function.
+
+    Update the BBS Table so that devices of DeviceType have their boot priority
+    updated to a high/bootable value.
+
+    See "DeviceType values" in 
+    http://www.intel.com/content/dam/doc/reference-guide/efi-compatibility-support-module-specification-v097.pdf
+
+    NOTE: This function should probably be refactored! Currently, all devices of
+    type are enabled. This should be updated so that only a specific device is
+    enabled. The wrong device could boot if there are multiple targets of the same
+    type.
+
+    @param DeviceType   The device type that we wish to enable
+**/
+VOID UpdateBbsTable (BDS_COMMON_OPTION *Option) {
+   UINT16  Idx;
+   EFI_LEGACY_BIOS_PROTOCOL  *LegacyBios;
+   EFI_STATUS                Status;
+   UINT16                       HddCount = 0;
+   HDD_INFO                     *HddInfo = NULL; 
+   UINT16                       BbsCount = 0; 
+   BBS_TABLE                 *LocalBbsTable = NULL;
+   BBS_BBS_DEVICE_PATH       *OptionBBS;
+   CHAR16                    Desc[100];
+
+   Status = refit_call3_wrapper(gBS->LocateProtocol, &gEfiLegacyBootProtocolGuid, NULL, (VOID **) &LegacyBios);
+   if (EFI_ERROR (Status) || (Option == NULL)) {
+      return;
+   }
+
+   OptionBBS = (BBS_BBS_DEVICE_PATH *) Option->DevicePath;
+   Status = refit_call5_wrapper(LegacyBios->GetBbsInfo, LegacyBios, &HddCount, &HddInfo, &BbsCount, &LocalBbsTable);
+
+//    Print (L"\n");
+//    Print (L" NO  Prio bb/dd/ff cl/sc Type Stat segm:offs\n");
+//    Print (L"=============================================\n");
+
+   for (Idx = 0; Idx < BbsCount; Idx++) {
+      if(LocalBbsTable[Idx].DeviceType == 0) {
+         continue;
+      }
+
+      BdsBuildLegacyDevNameString (&LocalBbsTable[Idx], Idx, sizeof (Desc), Desc);
+
+      // Set devices of a particular type to BootPriority of 0 or 1. 0 is the highest priority.
+      if (LocalBbsTable[Idx].DeviceType == OptionBBS->DeviceType) {
+         if (MyStriCmp(Desc, Option->Description)) {
+            // This entry exactly matches what we're looking for; make it highest priority
+            LocalBbsTable[Idx].BootPriority = 0;
+         } else {
+            // This entry doesn't exactly match, but is the right disk type; make it a bit lower
+            // in priority. Done mainly as a fallback in case of string-matching weirdness.
+            LocalBbsTable[Idx].BootPriority = 1;
+         } // if/else
+      } else if (LocalBbsTable[Idx].BootPriority <= 1) {
+         // Something's got a high enough boot priority to interfere with booting
+         // our chosen entry, so bump it down a bit....
+         LocalBbsTable[Idx].BootPriority = 2;
+      } // if/else if
+
+//          Print (
+//            L" %02x: %04x %02x/%02x/%02x %02x/%02x %04x %04x %04x:%04x\n",
+//            (UINTN) Idx,
+//            (UINTN) LocalBbsTable[Idx].BootPriority,
+//            (UINTN) LocalBbsTable[Idx].Bus,
+//            (UINTN) LocalBbsTable[Idx].Device,
+//            (UINTN) LocalBbsTable[Idx].Function,
+//            (UINTN) LocalBbsTable[Idx].Class,
+//            (UINTN) LocalBbsTable[Idx].SubClass,
+//            (UINTN) LocalBbsTable[Idx].DeviceType,
+//            (UINTN) * (UINT16 *) &LocalBbsTable[Idx].StatusFlags,
+//            (UINTN) LocalBbsTable[Idx].BootHandlerSegment,
+//            (UINTN) LocalBbsTable[Idx].BootHandlerOffset,
+//            (UINTN) ((LocalBbsTable[Idx].MfgStringSegment << 4) + LocalBbsTable[Idx].MfgStringOffset),
+//            (UINTN) ((LocalBbsTable[Idx].DescStringSegment << 4) + LocalBbsTable[Idx].DescStringOffset)
+//            );
+//          Print(L"%s\n", Desc);
+
+   } // for
+//    PauseForKey();
+}
+
+/**
+    Boot the legacy system with the boot option
+
+    @param  Option                 The legacy boot option which have BBS device path
+
+    @retval EFI_UNSUPPORTED        There is no legacybios protocol, do not support
+                                 legacy boot.
+    @retval EFI_STATUS             Return the status of LegacyBios->LegacyBoot ().
+
+**/
+EFI_STATUS
+BdsLibDoLegacyBoot (
+  IN  BDS_COMMON_OPTION           *Option
+  )
+{
+    EFI_STATUS                Status;
+    EFI_LEGACY_BIOS_PROTOCOL  *LegacyBios;
+
+    Status = refit_call3_wrapper(gBS->LocateProtocol, &gEfiLegacyBootProtocolGuid, NULL, (VOID **) &LegacyBios);
+    if (EFI_ERROR (Status)) {
+      return EFI_UNSUPPORTED;
+    }
+
+    UpdateBbsTable(Option);
+
+    return refit_call4_wrapper(LegacyBios->LegacyBoot, LegacyBios, (BBS_BBS_DEVICE_PATH *) Option->DevicePath,
+                                  Option->LoadOptionsSize, Option->LoadOptions);
+}
diff --git a/EfiLib/BdsHelper.h b/EfiLib/BdsHelper.h
new file mode 100644 (file)
index 0000000..20344a1
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * EfiLib/BdsHelper.c
+ * Functions to call legacy BIOS API.
+ *
+ */
+/**
+
+Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifdef __MAKEWITH_TIANO
+#include "../include/tiano_includes.h"
+#else
+#include "gnuefi-helper.h"
+#include "GenericBdsLib.h"
+#endif
+
+#ifndef _BDS_HELPER_H_
+#define _BDS_HELPER_H_
+
+
+/**
+  Boot the legacy system with the boot option
+
+  @param  Option                 The legacy boot option which have BBS device path
+
+  @retval EFI_UNSUPPORTED        There is no legacybios protocol, do not support
+                                 legacy boot.
+  @retval EFI_STATUS             Return the status of LegacyBios->LegacyBoot ().
+
+**/
+EFI_STATUS
+BdsLibDoLegacyBoot (
+  IN  BDS_COMMON_OPTION           *Option
+  );
+
+EFI_STATUS BdsConnectDevicePath  (  IN EFI_DEVICE_PATH_PROTOCOL *    DevicePath,
+                                    OUT EFI_HANDLE *     Handle,
+                                    OUT EFI_DEVICE_PATH_PROTOCOL **     RemainingDevicePath
+);
+
+#endif //_BDS_HELPER_H_
diff --git a/EfiLib/BdsTianoCore.c b/EfiLib/BdsTianoCore.c
new file mode 100644 (file)
index 0000000..271758d
--- /dev/null
@@ -0,0 +1,331 @@
+/** @file
+  BDS Lib functions which relate with create or process the boot option.
+
+Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifdef __MAKEWITH_TIANO
+#include "../include/tiano_includes.h"
+#else
+#include "BdsHelper.h"
+#include "gnuefi-helper.h"
+#endif
+#include "../include/refit_call_wrapper.h"
+
+EFI_GUID EfiDevicePathProtocolGuid = { 0x09576E91, 0x6D3F, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
+
+/**
+  This function will create all handles associate with every device
+  path node. If the handle associate with one device path node can not
+  be created success, then still give one chance to do the dispatch,
+  which load the missing drivers if possible.
+
+  @param  DevicePathToConnect   The device path which will be connected, it can be
+                                a multi-instance device path
+
+  @retval EFI_SUCCESS           All handles associate with every device path  node
+                                have been created
+  @retval EFI_OUT_OF_RESOURCES  There is no resource to create new handles
+  @retval EFI_NOT_FOUND         Create the handle associate with one device  path
+                                node failed
+
+**/
+EFI_STATUS
+BdsLibConnectDevicePath (
+  IN EFI_DEVICE_PATH_PROTOCOL  *DevicePathToConnect
+  )
+{
+  EFI_STATUS                Status;
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
+  EFI_DEVICE_PATH_PROTOCOL  *CopyOfDevicePath;
+  EFI_DEVICE_PATH_PROTOCOL  *Instance;
+  EFI_DEVICE_PATH_PROTOCOL  *RemainingDevicePath;
+  EFI_DEVICE_PATH_PROTOCOL  *Next;
+  EFI_HANDLE                Handle;
+  EFI_HANDLE                PreviousHandle;
+  UINTN                     Size;
+
+  if (DevicePathToConnect == NULL) {
+    return EFI_SUCCESS;
+  }
+
+  DevicePath        = DuplicateDevicePath (DevicePathToConnect);
+  if (DevicePath == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+  CopyOfDevicePath  = DevicePath;
+
+  do {
+    //
+    // The outer loop handles multi instance device paths.
+    // Only console variables contain multiple instance device paths.
+    //
+    // After this call DevicePath points to the next Instance
+    //
+    Instance  = GetNextDevicePathInstance (&DevicePath, &Size);
+    if (Instance == NULL) {
+      FreePool (CopyOfDevicePath);
+      return EFI_OUT_OF_RESOURCES;
+    }
+
+    Next      = Instance;
+    while (!IsDevicePathEndType (Next)) {
+      Next = NextDevicePathNode (Next);
+    }
+
+    SetDevicePathEndNode (Next);
+
+    //
+    // Start the real work of connect with RemainingDevicePath
+    //
+    PreviousHandle = NULL;
+    do {
+      //
+      // Find the handle that best matches the Device Path. If it is only a
+      // partial match the remaining part of the device path is returned in
+      // RemainingDevicePath.
+      //
+      RemainingDevicePath = Instance;
+      Status              = refit_call3_wrapper(gBS->LocateDevicePath, &EfiDevicePathProtocolGuid, &RemainingDevicePath, &Handle);
+
+      if (!EFI_ERROR (Status)) {
+#ifdef __MAKEWITH_TIANO
+         if (Handle == PreviousHandle) {
+          //
+          // If no forward progress is made try invoking the Dispatcher.
+          // A new FV may have been added to the system an new drivers
+          // may now be found.
+          // Status == EFI_SUCCESS means a driver was dispatched
+          // Status == EFI_NOT_FOUND means no new drivers were dispatched
+          //
+          Status = gDS->Dispatch ();
+        }
+#endif
+
+        if (!EFI_ERROR (Status)) {
+          PreviousHandle = Handle;
+          //
+          // Connect all drivers that apply to Handle and RemainingDevicePath,
+          // the Recursive flag is FALSE so only one level will be expanded.
+          //
+          // Do not check the connect status here, if the connect controller fail,
+          // then still give the chance to do dispatch, because partial
+          // RemainingDevicepath may be in the new FV
+          //
+          // 1. If the connect fail, RemainingDevicepath and handle will not
+          //    change, so next time will do the dispatch, then dispatch's status
+          //    will take effect
+          // 2. If the connect success, the RemainingDevicepath and handle will
+          //    change, then avoid the dispatch, we have chance to continue the
+          //    next connection
+          //
+          refit_call4_wrapper(gBS->ConnectController, Handle, NULL, RemainingDevicePath, FALSE);
+        }
+      }
+      //
+      // Loop until RemainingDevicePath is an empty device path
+      //
+    } while (!EFI_ERROR (Status) && !IsDevicePathEnd (RemainingDevicePath));
+
+  } while (DevicePath != NULL);
+
+  if (CopyOfDevicePath != NULL) {
+    FreePool (CopyOfDevicePath);
+  }
+  //
+  // All handle with DevicePath exists in the handle database
+  //
+  return Status;
+}
+
+/**
+  Build the boot#### or driver#### option from the VariableName, the
+  build boot#### or driver#### will also be linked to BdsCommonOptionList.
+
+  @param  BdsCommonOptionList   The header of the boot#### or driver#### option
+                                link list
+  @param  VariableName          EFI Variable name indicate if it is boot#### or
+                                driver####
+
+  @retval BDS_COMMON_OPTION     Get the option just been created
+  @retval NULL                  Failed to get the new option
+
+**/
+BDS_COMMON_OPTION *
+BdsLibVariableToOption (
+  IN OUT LIST_ENTRY                   *BdsCommonOptionList,
+  IN  CHAR16                          *VariableName
+  )
+{
+  UINT32                    Attribute;
+  UINT16                    FilePathSize;
+  UINT8                     *Variable;
+  UINT8                     *TempPtr;
+  UINTN                     VariableSize;
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
+  BDS_COMMON_OPTION         *Option;
+  VOID                      *LoadOptions;
+  UINT32                    LoadOptionsSize;
+  CHAR16                    *Description;
+  UINT8                     NumOff;
+  EFI_GUID EfiGlobalVariableGuid     = { 0x8BE4DF61, 0x93CA, 0x11D2, { 0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C }};
+
+  //
+  // Read the variable. We will never free this data.
+  //
+  Variable = BdsLibGetVariableAndSize (
+              VariableName,
+              &EfiGlobalVariableGuid,
+              &VariableSize
+              );
+  if (Variable == NULL) {
+    return NULL;
+  }
+  //
+  // Notes: careful defined the variable of Boot#### or
+  // Driver####, consider use some macro to abstract the code
+  //
+  //
+  // Get the option attribute
+  //
+  TempPtr   =  Variable;
+  Attribute =  *(UINT32 *) Variable;
+  TempPtr   += sizeof (UINT32);
+
+  //
+  // Get the option's device path size
+  //
+  FilePathSize =  *(UINT16 *) TempPtr;
+  TempPtr      += sizeof (UINT16);
+
+  //
+  // Get the option's description string
+  //
+  Description = (CHAR16 *) TempPtr;
+
+  //
+  // Get the option's description string size
+  //
+  TempPtr     += StrSize ((CHAR16 *) TempPtr);
+
+  //
+  // Get the option's device path
+  //
+  DevicePath =  (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
+  TempPtr    += FilePathSize;
+
+  LoadOptions     = TempPtr;
+  LoadOptionsSize = (UINT32) (VariableSize - (UINTN) (TempPtr - Variable));
+
+  //
+  // The Console variables may have multiple device paths, so make
+  // an Entry for each one.
+  //
+  Option = AllocateZeroPool (sizeof (BDS_COMMON_OPTION));
+  if (Option == NULL) {
+    return NULL;
+  }
+
+  Option->Signature   = BDS_LOAD_OPTION_SIGNATURE;
+  Option->DevicePath  = AllocateZeroPool (GetDevicePathSize (DevicePath));
+  ASSERT(Option->DevicePath != NULL);
+  CopyMem (Option->DevicePath, DevicePath, GetDevicePathSize (DevicePath));
+
+  Option->Attribute   = Attribute;
+  Option->Description = AllocateZeroPool (StrSize (Description));
+  ASSERT(Option->Description != NULL);
+  CopyMem (Option->Description, Description, StrSize (Description));
+
+  Option->LoadOptions = AllocateZeroPool (LoadOptionsSize);
+  ASSERT(Option->LoadOptions != NULL);
+  CopyMem (Option->LoadOptions, LoadOptions, LoadOptionsSize);
+  Option->LoadOptionsSize = LoadOptionsSize;
+
+  //
+  // Get the value from VariableName Unicode string
+  // since the ISO standard assumes ASCII equivalent abbreviations, we can be safe in converting this
+  // Unicode stream to ASCII without any loss in meaning.
+  //
+  if (*VariableName == 'B') {
+    NumOff = (UINT8) (sizeof (L"Boot") / sizeof(CHAR16) - 1);
+    Option->BootCurrent = (UINT16) ((VariableName[NumOff]  -'0') * 0x1000);
+    Option->BootCurrent = (UINT16) (Option->BootCurrent + ((VariableName[NumOff+1]-'0') * 0x100));
+    Option->BootCurrent = (UINT16) (Option->BootCurrent +  ((VariableName[NumOff+2]-'0') * 0x10));
+    Option->BootCurrent = (UINT16) (Option->BootCurrent + ((VariableName[NumOff+3]-'0')));
+  }
+  //
+  // Insert active entry to BdsDeviceList
+  //
+  if ((Option->Attribute & LOAD_OPTION_ACTIVE) == LOAD_OPTION_ACTIVE) {
+    InsertTailList (BdsCommonOptionList, &Option->Link);
+    FreePool (Variable);
+    return Option;
+  }
+
+  FreePool (Variable);
+  FreePool (Option);
+  return NULL;
+
+}
+
+
+/**
+  Read the EFI variable (VendorGuid/Name) and return a dynamically allocated
+  buffer, and the size of the buffer. If failure return NULL.
+
+  @param  Name                  String part of EFI variable name
+  @param  VendorGuid            GUID part of EFI variable name
+  @param  VariableSize          Returns the size of the EFI variable that was read
+
+  @return                       Dynamically allocated memory that contains a copy of the EFI variable
+                                Caller is responsible freeing the buffer.
+  @retval NULL                  Variable was not read
+
+**/
+VOID *
+BdsLibGetVariableAndSize (
+  IN  CHAR16              *Name,
+  IN  EFI_GUID            *VendorGuid,
+  OUT UINTN               *VariableSize
+  )
+{
+  EFI_STATUS  Status;
+  UINTN       BufferSize;
+  VOID        *Buffer;
+
+  Buffer = NULL;
+
+  //
+  // Pass in a zero size buffer to find the required buffer size.
+  //
+  BufferSize  = 0;
+  Status      = refit_call5_wrapper(gRT->GetVariable, Name, VendorGuid, NULL, &BufferSize, Buffer);
+  if (Status == EFI_BUFFER_TOO_SMALL) {
+    //
+    // Allocate the buffer to return
+    //
+    Buffer = AllocateZeroPool (BufferSize);
+    if (Buffer == NULL) {
+      return NULL;
+    }
+    //
+    // Read variable into the allocated buffer.
+    //
+    Status = refit_call5_wrapper(gRT->GetVariable, Name, VendorGuid, NULL, &BufferSize, Buffer);
+    if (EFI_ERROR (Status)) {
+      BufferSize = 0;
+    }
+  }
+
+  *VariableSize = BufferSize;
+  return Buffer;
+}
+
diff --git a/EfiLib/BmLib.c b/EfiLib/BmLib.c
new file mode 100644 (file)
index 0000000..99598b8
--- /dev/null
@@ -0,0 +1,203 @@
+/** @file\r
+  Utility routines used by boot maintenance modules.\r
+\r
+Copyright (c) 2004 - 2009, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifdef __MAKEWITH_TIANO\r
+#include "Platform.h"\r
+#else\r
+#include "gnuefi-helper.h"\r
+#endif\r
+#include "../include/refit_call_wrapper.h"\r
+\r
+/**\r
+\r
+  Find the first instance of this Protocol\r
+  in the system and return it's interface.\r
+\r
+\r
+  @param ProtocolGuid    Provides the protocol to search for\r
+  @param Interface       On return, a pointer to the first interface\r
+                         that matches ProtocolGuid\r
+\r
+  @retval  EFI_SUCCESS      A protocol instance matching ProtocolGuid was found\r
+  @retval  EFI_NOT_FOUND    No protocol instances were found that match ProtocolGuid\r
+\r
+**/\r
+EFI_STATUS\r
+EfiLibLocateProtocol (\r
+  IN  EFI_GUID    *ProtocolGuid,\r
+  OUT VOID        **Interface\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  Status = refit_call3_wrapper(gBS->LocateProtocol,\r
+                  ProtocolGuid,\r
+                  NULL,\r
+                  (VOID **) Interface\r
+                  );\r
+  return Status;\r
+}\r
+\r
+/**\r
+\r
+  Function opens and returns a file handle to the root directory of a volume.\r
+\r
+  @param DeviceHandle    A handle for a device\r
+\r
+  @return A valid file handle or NULL is returned\r
+\r
+**/\r
+EFI_FILE_HANDLE\r
+EfiLibOpenRoot (\r
+  IN EFI_HANDLE                   DeviceHandle\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume;\r
+  EFI_FILE_HANDLE                 File;\r
+\r
+  File = NULL;\r
+\r
+  //\r
+  // File the file system interface to the device\r
+  //\r
+  Status = refit_call3_wrapper(gBS->HandleProtocol,\r
+                  DeviceHandle,\r
+                  &gEfiSimpleFileSystemProtocolGuid,\r
+                  (VOID **) &Volume\r
+                  );\r
+\r
+  //\r
+  // Open the root directory of the volume\r
+  //\r
+  if (!EFI_ERROR (Status)) {\r
+    Status = Volume->OpenVolume (\r
+                      Volume,\r
+                      &File\r
+                      );\r
+  }\r
+  //\r
+  // Done\r
+  //\r
+  return EFI_ERROR (Status) ? NULL : File;\r
+}\r
+\r
+/**\r
+  Duplicate a string.\r
+\r
+  @param Src             The source.\r
+\r
+  @return A new string which is duplicated copy of the source.\r
+  @retval NULL If there is not enough memory.\r
+\r
+**/\r
+CHAR16 *\r
+EfiStrDuplicate (\r
+  IN CHAR16   *Src\r
+                                )\r
+{\r
+  CHAR16  *Dest;\r
+  UINTN   Size;\r
+\r
+  Size  = StrSize (Src); //at least 2bytes\r
+  Dest  = AllocateZeroPool (Size);\r
+  if (Dest != NULL) {\r
+    CopyMem (Dest, Src, Size);\r
+  }\r
+\r
+  return Dest;\r
+}\r
+\r
+/**\r
+\r
+  Function gets the file information from an open file descriptor, and stores it\r
+  in a buffer allocated from pool.\r
+\r
+  @param FHand           File Handle.\r
+\r
+  @return                A pointer to a buffer with file information or NULL is returned\r
+\r
+**/\r
+EFI_FILE_INFO *\r
+EfiLibFileInfo (\r
+  IN EFI_FILE_HANDLE      FHand\r
+  )\r
+{\r
+  EFI_STATUS    Status;\r
+  EFI_FILE_INFO *FileInfo = NULL;\r
+  UINTN         Size = 0;\r
+  \r
+  Status = FHand->GetInfo (FHand, &gEfiFileInfoGuid, &Size, FileInfo);\r
+  if (Status == EFI_BUFFER_TOO_SMALL) {\r
+    FileInfo = AllocateZeroPool (Size);\r
+    Status = FHand->GetInfo (FHand, &gEfiFileInfoGuid, &Size, FileInfo);\r
+  }\r
+  \r
+  return EFI_ERROR(Status)?NULL:FileInfo;\r
+}\r
+\r
+EFI_FILE_SYSTEM_INFO *\r
+EfiLibFileSystemInfo (\r
+                IN EFI_FILE_HANDLE      FHand\r
+                )\r
+{\r
+  EFI_STATUS    Status;\r
+  EFI_FILE_SYSTEM_INFO *FileSystemInfo = NULL;\r
+  UINTN         Size = 0;\r
+\r
+  Status = FHand->GetInfo (FHand, &gEfiFileSystemInfoGuid, &Size, FileSystemInfo);\r
+  if (Status == EFI_BUFFER_TOO_SMALL) {\r
+    FileSystemInfo = AllocateZeroPool (Size);\r
+    Status = FHand->GetInfo (FHand, &gEfiFileSystemInfoGuid, &Size, FileSystemInfo);\r
+  }\r
+\r
+  return EFI_ERROR(Status)?NULL:FileSystemInfo;\r
+}\r
+\r
+/**\r
+  Adjusts the size of a previously allocated buffer.\r
+\r
+\r
+  @param OldPool         - A pointer to the buffer whose size is being adjusted.\r
+  @param OldSize         - The size of the current buffer.\r
+  @param NewSize         - The size of the new buffer.\r
+\r
+  @return   The newly allocated buffer.\r
+  @retval   NULL  Allocation failed.\r
+\r
+**/\r
+VOID *\r
+EfiReallocatePool (\r
+  IN VOID                 *OldPool,\r
+  IN UINTN                OldSize,\r
+  IN UINTN                NewSize\r
+  )\r
+{\r
+  VOID  *NewPool;\r
+\r
+  NewPool = NULL;\r
+  if (NewSize != 0) {\r
+    NewPool = AllocateZeroPool (NewSize);\r
+  }\r
+\r
+  if (OldPool != NULL) {\r
+    if (NewPool != NULL) {\r
+      CopyMem (NewPool, OldPool, OldSize < NewSize ? OldSize : NewSize);\r
+    }\r
+\r
+    FreePool (OldPool);\r
+  }\r
+\r
+  return NewPool;\r
+}\r
diff --git a/EfiLib/DevicePath.c b/EfiLib/DevicePath.c
new file mode 100644 (file)
index 0000000..bfaf1c6
--- /dev/null
@@ -0,0 +1,1575 @@
+/** @file\r
+  BDS internal function define the default device path string, it can be\r
+  replaced by platform device path.\r
+\r
+Copyright (c) 2004 - 2009, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "Platform.h"\r
+\r
+/**\r
+  Concatenates a formatted unicode string to allocated pool.\r
+  The caller must free the resulting buffer.\r
+\r
+  @param  Str      Tracks the allocated pool, size in use, and amount of pool allocated.\r
+  @param  Fmt      The format string\r
+  @param  ...      The data will be printed.\r
+\r
+  @return Allocated buffer with the formatted string printed in it.\r
+          The caller must free the allocated buffer.\r
+          The buffer allocation is not packed.\r
+\r
+**/\r
+\r
+CHAR16 *\r
+EFIAPI\r
+CatPrint (\r
+  IN OUT POOL_PRINT   *Str,\r
+  IN CHAR16           *Fmt,\r
+  ...\r
+  )\r
+{\r
+  UINT16  *AppendStr;\r
+  VA_LIST Args;\r
+  UINTN   StringSize;\r
+\r
+  AppendStr = AllocateZeroPool (0x1000);\r
+  if (AppendStr == NULL) {\r
+    return Str->Str;\r
+  }\r
+\r
+  VA_START (Args, Fmt);\r
+  UnicodeVSPrint (AppendStr, 0x1000, Fmt, Args);\r
+  VA_END (Args);\r
+  if (NULL == Str->Str) {\r
+        StringSize   = StrSize (AppendStr);\r
+    Str->Str  = AllocateZeroPool (StringSize);\r
+    ASSERT (Str->Str != NULL);\r
+  } else {\r
+        StringSize = StrSize (AppendStr);\r
+        StringSize += (StrSize (Str->Str) - sizeof (UINT16));\r
+\r
+    Str->Str = EfiReallocatePool (\r
+                                       Str->Str,                  \r
+                                   StrSize (Str->Str),\r
+                                       StringSize                \r
+                );\r
+    ASSERT (Str->Str != NULL);\r
+  }\r
+\r
+  Str->Maxlen = MAX_CHAR * sizeof (UINT16);\r
+  if (StringSize < Str->Maxlen) {\r
+    StrCat (Str->Str, AppendStr);\r
+    Str->Len = StringSize - sizeof (UINT16);\r
+  }\r
+\r
+  FreePool (AppendStr);\r
+  return Str->Str;\r
+}\r
+\r
+/**\r
+  Convert Device Path to a Unicode string for printing.\r
+\r
+  @param Str             The buffer holding the output string.\r
+                         This buffer contains the length of the\r
+                         string and the maixmum length reserved\r
+                         for the string buffer.\r
+  @param DevPath         The device path.\r
+\r
+**/\r
+VOID\r
+DevPathPci (\r
+  IN OUT POOL_PRINT       *Str,\r
+  IN VOID                 *DevPath\r
+  )\r
+{\r
+  PCI_DEVICE_PATH *Pci;\r
+\r
+  Pci = DevPath;\r
+  CatPrint (Str, L"Pci(%x|%x)", (UINTN) Pci->Device, (UINTN) Pci->Function);\r
+}\r
+\r
+/**\r
+  Convert Device Path to a Unicode string for printing.\r
+\r
+  @param Str             The buffer holding the output string.\r
+                         This buffer contains the length of the\r
+                         string and the maixmum length reserved\r
+                         for the string buffer.\r
+  @param DevPath         The device path.\r
+\r
+**/\r
+VOID\r
+DevPathPccard (\r
+  IN OUT POOL_PRINT       *Str,\r
+  IN VOID                 *DevPath\r
+  )\r
+{\r
+  PCCARD_DEVICE_PATH  *Pccard;\r
+\r
+  Pccard = DevPath;\r
+  CatPrint (Str, L"Pcmcia(Function%x)", (UINTN) Pccard->FunctionNumber);\r
+}\r
+\r
+/**\r
+  Convert Device Path to a Unicode string for printing.\r
+\r
+  @param Str             The buffer holding the output string.\r
+                         This buffer contains the length of the\r
+                         string and the maixmum length reserved\r
+                         for the string buffer.\r
+  @param DevPath         The device path.\r
+\r
+**/\r
+VOID\r
+DevPathMemMap (\r
+  IN OUT POOL_PRINT       *Str,\r
+  IN VOID                 *DevPath\r
+  )\r
+{\r
+  MEMMAP_DEVICE_PATH  *MemMap;\r
+\r
+  MemMap = DevPath;\r
+  CatPrint (\r
+    Str,\r
+    L"MemMap(%d:%lx-%lx)",\r
+    (UINTN) MemMap->MemoryType,\r
+    MemMap->StartingAddress,\r
+    MemMap->EndingAddress\r
+    );\r
+}\r
+\r
+/**\r
+  Convert Device Path to a Unicode string for printing.\r
+\r
+  @param Str             The buffer holding the output string.\r
+                         This buffer contains the length of the\r
+                         string and the maixmum length reserved\r
+                         for the string buffer.\r
+  @param DevPath         The device path.\r
+\r
+**/\r
+VOID\r
+DevPathController (\r
+  IN OUT POOL_PRINT       *Str,\r
+  IN VOID                 *DevPath\r
+  )\r
+{\r
+  CONTROLLER_DEVICE_PATH  *Controller;\r
+\r
+  Controller = DevPath;\r
+  CatPrint (Str, L"Ctrl(%d)", (UINTN) Controller->ControllerNumber);\r
+}\r
+\r
+\r
+/**\r
+  Convert Vendor device path to device name.\r
+\r
+  @param  Str      The buffer store device name\r
+  @param  DevPath  Pointer to vendor device path\r
+\r
+**/\r
+VOID\r
+DevPathVendor (\r
+  IN OUT POOL_PRINT       *Str,\r
+  IN VOID                 *DevPath\r
+  )\r
+{\r
+  VENDOR_DEVICE_PATH  *Vendor;\r
+  CHAR16              *Type;\r
+  UINTN               DataLength;\r
+  UINTN               Index;\r
+//  UINT32              FlowControlMap;\r
+\r
+  UINT16              Info;\r
+\r
+  Vendor  = DevPath;\r
+\r
+  switch (DevicePathType (&Vendor->Header)) {\r
+  case HARDWARE_DEVICE_PATH:\r
+    Type = L"Hw";\r
+    break;\r
+\r
+  case MESSAGING_DEVICE_PATH:\r
+    Type = L"Msg";\r
+/*               \r
+    if (CompareGuid (&Vendor->Guid, &gEfiPcAnsiGuid)) {\r
+      CatPrint (Str, L"VenPcAnsi()");\r
+      return ;\r
+    } else if (CompareGuid (&Vendor->Guid, &gEfiVT100Guid)) {\r
+      CatPrint (Str, L"VenVt100()");\r
+      return ;\r
+    } else if (CompareGuid (&Vendor->Guid, &gEfiVT100PlusGuid)) {\r
+      CatPrint (Str, L"VenVt100Plus()");\r
+      return ;\r
+    } else if (CompareGuid (&Vendor->Guid, &gEfiVTUTF8Guid)) {\r
+      CatPrint (Str, L"VenUft8()");\r
+      return ;\r
+    } else if (CompareGuid (&Vendor->Guid, &gEfiUartDevicePathGuid     )) {\r
+      FlowControlMap = (((UART_FLOW_CONTROL_DEVICE_PATH *) Vendor)->FlowControlMap);\r
+      switch (FlowControlMap & 0x00000003) {\r
+      case 0:\r
+        CatPrint (Str, L"UartFlowCtrl(%s)", L"None");\r
+        break;\r
+\r
+      case 1:\r
+        CatPrint (Str, L"UartFlowCtrl(%s)", L"Hardware");\r
+        break;\r
+\r
+      case 2:\r
+        CatPrint (Str, L"UartFlowCtrl(%s)", L"XonXoff");\r
+        break;\r
+\r
+      default:\r
+        break;\r
+      }\r
+\r
+      return ;\r
+\r
+    } else\r
+ */\r
+    if (CompareGuid (&Vendor->Guid, &gEfiSasDevicePathGuid)) {\r
+      CatPrint (\r
+        Str,\r
+        L"SAS(%lx,%lx,%x,",\r
+        ((SAS_DEVICE_PATH *) Vendor)->SasAddress,\r
+        ((SAS_DEVICE_PATH *) Vendor)->Lun,\r
+        (UINTN) ((SAS_DEVICE_PATH *) Vendor)->RelativeTargetPort\r
+        );\r
+      Info = (((SAS_DEVICE_PATH *) Vendor)->DeviceTopology);\r
+      if ((Info & 0x0f) == 0) {\r
+        CatPrint (Str, L"NoTopology,0,0,0,");\r
+      } else if (((Info & 0x0f) == 1) || ((Info & 0x0f) == 2)) {\r
+        CatPrint (\r
+          Str,\r
+          L"%s,%s,%s,",\r
+          ((Info & (0x1 << 4)) != 0) ? L"SATA" : L"SAS",\r
+          ((Info & (0x1 << 5)) != 0) ? L"External" : L"Internal",\r
+          ((Info & (0x1 << 6)) != 0) ? L"Expanded" : L"Direct"\r
+          );\r
+        if ((Info & 0x0f) == 1) {\r
+          CatPrint (Str, L"0,");\r
+        } else {\r
+          CatPrint (Str, L"%x,", (UINTN) ((Info >> 8) & 0xff));\r
+        }\r
+      } else {\r
+        CatPrint (Str, L"0,0,0,0,");\r
+      }\r
+\r
+      CatPrint (Str, L"%x)", (UINTN) ((SAS_DEVICE_PATH *) Vendor)->Reserved);\r
+      return ;\r
+\r
+    } else if (CompareGuid (&Vendor->Guid, &gEfiDebugPortProtocolGuid)) {\r
+      CatPrint (Str, L"DebugPort()");\r
+      return ;\r
+    }\r
+    break;\r
+\r
+  case MEDIA_DEVICE_PATH:\r
+    Type = L"Media";\r
+    break;\r
+\r
+  default:\r
+    Type = L"?";\r
+    break;\r
+  }\r
+\r
+  CatPrint (Str, L"Ven%s(%g", Type, &Vendor->Guid);\r
+  DataLength = DevicePathNodeLength (&Vendor->Header) - sizeof (VENDOR_DEVICE_PATH);\r
+  if (DataLength > 0) {\r
+    CatPrint (Str, L",");\r
+    for (Index = 0; Index < DataLength; Index++) {\r
+      CatPrint (Str, L"%02x", (UINTN) ((VENDOR_DEVICE_PATH_WITH_DATA *) Vendor)->VendorDefinedData[Index]);\r
+    }\r
+  }\r
+  CatPrint (Str, L")");\r
+}\r
+\r
+/**\r
+  Convert Device Path to a Unicode string for printing.\r
+\r
+  @param Str             The buffer holding the output string.\r
+                         This buffer contains the length of the\r
+                         string and the maixmum length reserved\r
+                         for the string buffer.\r
+  @param DevPath         The device path.\r
+\r
+**/\r
+VOID\r
+DevPathAcpi (\r
+  IN OUT POOL_PRINT       *Str,\r
+  IN VOID                 *DevPath\r
+  )\r
+{\r
+  ACPI_HID_DEVICE_PATH  *Acpi;\r
+\r
+  Acpi = DevPath;\r
+  if ((Acpi->HID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) {\r
+    CatPrint (Str, L"Acpi(PNP%04x,%x)", (UINTN)  EISA_ID_TO_NUM (Acpi->HID), (UINTN) Acpi->UID);\r
+  } else {\r
+    CatPrint (Str, L"Acpi(%08x,%x)", (UINTN) Acpi->HID, (UINTN) Acpi->UID);\r
+  }\r
+}\r
+\r
+/**\r
+  Convert Device Path to a Unicode string for printing.\r
+\r
+  @param Str             The buffer holding the output string.\r
+                         This buffer contains the length of the\r
+                         string and the maixmum length reserved\r
+                         for the string buffer.\r
+  @param DevPath         The device path.\r
+\r
+**/\r
+VOID\r
+DevPathExtendedAcpi (\r
+  IN OUT POOL_PRINT       *Str,\r
+  IN VOID                 *DevPath\r
+  )\r
+{\r
+  ACPI_EXTENDED_HID_DEVICE_PATH   *ExtendedAcpi;\r
+  \r
+  //\r
+  // Index for HID, UID and CID strings, 0 for non-exist\r
+  //\r
+  UINT16                          HIDSTRIdx;\r
+  UINT16                          UIDSTRIdx;\r
+  UINT16                          CIDSTRIdx;\r
+  UINT16                          Index;\r
+  UINT16                          Length;\r
+  UINT16                          Anchor;\r
+  CHAR8                           *AsChar8Array;\r
+\r
+  HIDSTRIdx    = 0;\r
+  UIDSTRIdx    = 0;\r
+  CIDSTRIdx    = 0;\r
+  ExtendedAcpi = DevPath;\r
+  Length       = (UINT16) DevicePathNodeLength ((EFI_DEVICE_PATH_PROTOCOL *) ExtendedAcpi);\r
+\r
+  AsChar8Array = (CHAR8 *) ExtendedAcpi;\r
+\r
+  //\r
+  // find HIDSTR\r
+  //\r
+  Anchor = 16;\r
+  for (Index = Anchor; Index < Length && AsChar8Array[Index] != '\0'; Index++) {\r
+    ;\r
+  }\r
+  if (Index > Anchor) {\r
+    HIDSTRIdx = Anchor;\r
+  }\r
+  //\r
+  // find UIDSTR\r
+  //\r
+  Anchor = (UINT16) (Index + 1);\r
+  for (Index = Anchor; Index < Length && AsChar8Array[Index] != '\0'; Index++) {\r
+    ;\r
+  }\r
+  if (Index > Anchor) {\r
+    UIDSTRIdx = Anchor;\r
+  }\r
+  //\r
+  // find CIDSTR\r
+  //\r
+  Anchor = (UINT16) (Index + 1);\r
+  for (Index = Anchor; Index < Length && AsChar8Array[Index] != '\0'; Index++) {\r
+    ;\r
+  }\r
+  if (Index > Anchor) {\r
+    CIDSTRIdx = Anchor;\r
+  }\r
+\r
+  if (HIDSTRIdx == 0 && CIDSTRIdx == 0 && ExtendedAcpi->UID == 0) {\r
+    CatPrint (Str, L"AcpiExp(");\r
+    if ((ExtendedAcpi->HID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) {\r
+      CatPrint (Str, L"PNP%04x,", (UINTN) EISA_ID_TO_NUM (ExtendedAcpi->HID));\r
+    } else {\r
+      CatPrint (Str, L"%08x,", (UINTN) ExtendedAcpi->HID);\r
+    }\r
+    if ((ExtendedAcpi->CID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) {\r
+      CatPrint (Str, L"PNP%04x,", (UINTN)  EISA_ID_TO_NUM (ExtendedAcpi->CID));\r
+    } else {\r
+      CatPrint (Str, L"%08x,", (UINTN)  ExtendedAcpi->CID);\r
+    }\r
+    if (UIDSTRIdx != 0) {\r
+      CatPrint (Str, L"%a)", AsChar8Array + UIDSTRIdx);\r
+    } else {\r
+      CatPrint (Str, L"\"\")");\r
+    }\r
+  } else {\r
+    CatPrint (Str, L"AcpiEx(");\r
+    if ((ExtendedAcpi->HID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) {\r
+      CatPrint (Str, L"PNP%04x,", (UINTN)  EISA_ID_TO_NUM (ExtendedAcpi->HID));\r
+    } else {\r
+      CatPrint (Str, L"%08x,", (UINTN) ExtendedAcpi->HID);\r
+    }\r
+    if ((ExtendedAcpi->CID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) {\r
+      CatPrint (Str, L"PNP%04x,", (UINTN) EISA_ID_TO_NUM (ExtendedAcpi->CID));\r
+    } else {\r
+      CatPrint (Str, L"%08x,", (UINTN) ExtendedAcpi->CID);\r
+    }\r
+    CatPrint (Str, L"%x,", (UINTN) ExtendedAcpi->UID);\r
+\r
+    if (HIDSTRIdx != 0) {\r
+      CatPrint (Str, L"%a,", AsChar8Array + HIDSTRIdx);\r
+    } else {\r
+      CatPrint (Str, L"\"\",");\r
+    }\r
+    if (CIDSTRIdx != 0) {\r
+      CatPrint (Str, L"%a,", AsChar8Array + CIDSTRIdx);\r
+    } else {\r
+      CatPrint (Str, L"\"\",");\r
+    }\r
+    if (UIDSTRIdx != 0) {\r
+      CatPrint (Str, L"%a)", AsChar8Array + UIDSTRIdx);\r
+    } else {\r
+      CatPrint (Str, L"\"\")");\r
+    }\r
+  }\r
+\r
+}\r
+\r
+/**\r
+  Convert Device Path to a Unicode string for printing.\r
+\r
+  @param Str             The buffer holding the output string.\r
+                         This buffer contains the length of the\r
+                         string and the maixmum length reserved\r
+                         for the string buffer.\r
+  @param DevPath         The device path.\r
+\r
+**/\r
+VOID\r
+DevPathAdrAcpi (\r
+  IN OUT POOL_PRINT       *Str,\r
+  IN VOID                 *DevPath\r
+  )\r
+{\r
+  ACPI_ADR_DEVICE_PATH    *AcpiAdr;\r
+  UINT16                  Index;\r
+  UINT16                  Length;\r
+  UINT16                  AdditionalAdrCount;\r
+\r
+  AcpiAdr            = DevPath;\r
+  Length             = (UINT16) DevicePathNodeLength ((EFI_DEVICE_PATH_PROTOCOL *) AcpiAdr);\r
+  AdditionalAdrCount = (UINT16) ((Length - 8) / 4);\r
+\r
+  CatPrint (Str, L"AcpiAdr(%x", (UINTN) AcpiAdr->ADR);\r
+  for (Index = 0; Index < AdditionalAdrCount; Index++) {\r
+    CatPrint (Str, L",%x", (UINTN) *(UINT32 *) ((UINT8 *) AcpiAdr + 8 + Index * 4));\r
+  }\r
+  CatPrint (Str, L")");\r
+}\r
+\r
+/**\r
+  Convert Device Path to a Unicode string for printing.\r
+\r
+  @param Str             The buffer holding the output string.\r
+                         This buffer contains the length of the\r
+                         string and the maixmum length reserved\r
+                         for the string buffer.\r
+  @param DevPath         The device path.\r
+\r
+**/\r
+VOID\r
+DevPathAtapi (\r
+  IN OUT POOL_PRINT       *Str,\r
+  IN VOID                 *DevPath\r
+  )\r
+{\r
+  ATAPI_DEVICE_PATH *Atapi;\r
+\r
+  Atapi = DevPath;\r
+  CatPrint (\r
+    Str,\r
+    L"Ata(%s,%s)",\r
+    (Atapi->PrimarySecondary != 0)? L"Secondary" : L"Primary",\r
+    (Atapi->SlaveMaster != 0)? L"Slave" : L"Master"\r
+    );\r
+}\r
+\r
+/**\r
+  Convert Device Path to a Unicode string for printing.\r
+\r
+  @param Str             The buffer holding the output string.\r
+                         This buffer contains the length of the\r
+                         string and the maixmum length reserved\r
+                         for the string buffer.\r
+  @param DevPath         The device path.\r
+\r
+**/\r
+VOID\r
+DevPathScsi (\r
+  IN OUT POOL_PRINT       *Str,\r
+  IN VOID                 *DevPath\r
+  )\r
+{\r
+  SCSI_DEVICE_PATH  *Scsi;\r
+\r
+  Scsi = DevPath;\r
+  CatPrint (Str, L"Scsi(Pun%x,Lun%x)", (UINTN) Scsi->Pun, (UINTN) Scsi->Lun);\r
+}\r
+\r
+/**\r
+  Convert Device Path to a Unicode string for printing.\r
+\r
+  @param Str             The buffer holding the output string.\r
+                         This buffer contains the length of the\r
+                         string and the maixmum length reserved\r
+                         for the string buffer.\r
+  @param DevPath         The device path.\r
+\r
+**/\r
+VOID\r
+DevPathFibre (\r
+  IN OUT POOL_PRINT       *Str,\r
+  IN VOID                 *DevPath\r
+  )\r
+{\r
+  FIBRECHANNEL_DEVICE_PATH  *Fibre;\r
+\r
+  Fibre = DevPath;\r
+  CatPrint (Str, L"Fibre(Wwn%lx,Lun%x)", Fibre->WWN, Fibre->Lun);\r
+}\r
+\r
+/**\r
+  Convert Device Path to a Unicode string for printing.\r
+\r
+  @param Str             The buffer holding the output string.\r
+                         This buffer contains the length of the\r
+                         string and the maixmum length reserved\r
+                         for the string buffer.\r
+  @param DevPath         The device path.\r
+\r
+**/\r
+VOID\r
+DevPath1394 (\r
+  IN OUT POOL_PRINT       *Str,\r
+  IN VOID                 *DevPath\r
+  )\r
+{\r
+  F1394_DEVICE_PATH *F1394Path;\r
+\r
+  F1394Path = DevPath;\r
+  CatPrint (Str, L"1394(%lx)", &F1394Path->Guid);\r
+}\r
+\r
+/**\r
+  Convert Device Path to a Unicode string for printing.\r
+\r
+  @param Str             The buffer holding the output string.\r
+                         This buffer contains the length of the\r
+                         string and the maixmum length reserved\r
+                         for the string buffer.\r
+  @param DevPath         The device path.\r
+\r
+**/\r
+VOID\r
+DevPathUsb (\r
+  IN OUT POOL_PRINT       *Str,\r
+  IN VOID                 *DevPath\r
+  )\r
+{\r
+  USB_DEVICE_PATH *Usb;\r
+\r
+  Usb = DevPath;\r
+  CatPrint (Str, L"Usb(%x,%x)", (UINTN) Usb->ParentPortNumber, (UINTN) Usb->InterfaceNumber);\r
+}\r
+\r
+/**\r
+  Convert Device Path to a Unicode string for printing.\r
+\r
+  @param Str             The buffer holding the output string.\r
+                         This buffer contains the length of the\r
+                         string and the maixmum length reserved\r
+                         for the string buffer.\r
+  @param DevPath         The device path.\r
+\r
+**/\r
+VOID\r
+DevPathUsbWWID (\r
+  IN OUT POOL_PRINT       *Str,\r
+  IN VOID                 *DevPath\r
+  )\r
+{\r
+  USB_WWID_DEVICE_PATH  *UsbWWId;\r
+\r
+  UsbWWId = DevPath;\r
+  CatPrint (\r
+    Str,\r
+    L"UsbWwid(%x,%x,%x,\"WWID\")",\r
+    (UINTN) UsbWWId->VendorId,\r
+    (UINTN) UsbWWId->ProductId,\r
+    (UINTN) UsbWWId->InterfaceNumber\r
+    );\r
+}\r
+\r
+/**\r
+  Convert Device Path to a Unicode string for printing.\r
+\r
+  @param Str             The buffer holding the output string.\r
+                         This buffer contains the length of the\r
+                         string and the maixmum length reserved\r
+                         for the string buffer.\r
+  @param DevPath         The device path.\r
+\r
+**/\r
+VOID\r
+DevPathLogicalUnit (\r
+  IN OUT POOL_PRINT       *Str,\r
+  IN VOID                 *DevPath\r
+  )\r
+{\r
+  DEVICE_LOGICAL_UNIT_DEVICE_PATH *LogicalUnit;\r
+\r
+  LogicalUnit = DevPath;\r
+  CatPrint (Str, L"Unit(%x)", (UINTN) LogicalUnit->Lun);\r
+}\r
+\r
+/**\r
+  Convert Device Path to a Unicode string for printing.\r
+\r
+  @param Str             The buffer holding the output string.\r
+                         This buffer contains the length of the\r
+                         string and the maixmum length reserved\r
+                         for the string buffer.\r
+  @param DevPath         The device path.\r
+\r
+**/\r
+VOID\r
+DevPathUsbClass (\r
+  IN OUT POOL_PRINT       *Str,\r
+  IN VOID                 *DevPath\r
+  )\r
+{\r
+  USB_CLASS_DEVICE_PATH *UsbClass;\r
+\r
+  UsbClass = DevPath;\r
+  CatPrint (\r
+    Str,\r
+    L"Usb Class(%x,%x,%x,%x,%x)",\r
+    (UINTN) UsbClass->VendorId,\r
+    (UINTN) UsbClass->ProductId,\r
+    (UINTN) UsbClass->DeviceClass,\r
+    (UINTN) UsbClass->DeviceSubClass,\r
+    (UINTN) UsbClass->DeviceProtocol\r
+    );\r
+}\r
+\r
+/**\r
+  Convert Device Path to a Unicode string for printing.\r
+\r
+  @param Str             The buffer holding the output string.\r
+                         This buffer contains the length of the\r
+                         string and the maixmum length reserved\r
+                         for the string buffer.\r
+  @param DevPath         The device path.\r
+\r
+**/\r
+VOID\r
+DevPathSata (\r
+  IN OUT POOL_PRINT       *Str,\r
+  IN VOID                 *DevPath\r
+  )\r
+{\r
+  SATA_DEVICE_PATH *Sata;\r
+\r
+  Sata = DevPath;\r
+  if ((Sata->PortMultiplierPortNumber & SATA_HBA_DIRECT_CONNECT_FLAG) != 0) {\r
+    CatPrint (\r
+      Str,\r
+      L"Sata(%x,%x)",\r
+      (UINTN) Sata->HBAPortNumber,\r
+      (UINTN) Sata->Lun\r
+      );\r
+  } else {\r
+    CatPrint (\r
+      Str,\r
+      L"Sata(%x,%x,%x)",\r
+      (UINTN) Sata->HBAPortNumber,\r
+      (UINTN) Sata->PortMultiplierPortNumber,\r
+      (UINTN) Sata->Lun\r
+      );\r
+  }\r
+}\r
+\r
+/**\r
+  Convert Device Path to a Unicode string for printing.\r
+\r
+  @param Str             The buffer holding the output string.\r
+                         This buffer contains the length of the\r
+                         string and the maixmum length reserved\r
+                         for the string buffer.\r
+  @param DevPath         The device path.\r
+\r
+**/\r
+VOID\r
+DevPathI2O (\r
+  IN OUT POOL_PRINT       *Str,\r
+  IN VOID                 *DevPath\r
+  )\r
+{\r
+  I2O_DEVICE_PATH *I2OPath;\r
+\r
+  I2OPath = DevPath;\r
+  CatPrint (Str, L"I2O(%x)", (UINTN) I2OPath->Tid);\r
+}\r
+\r
+/**\r
+  Convert Device Path to a Unicode string for printing.\r
+\r
+  @param Str             The buffer holding the output string.\r
+                         This buffer contains the length of the\r
+                         string and the maixmum length reserved\r
+                         for the string buffer.\r
+  @param DevPath         The device path.\r
+\r
+**/\r
+VOID\r
+DevPathMacAddr (\r
+  IN OUT POOL_PRINT       *Str,\r
+  IN VOID                 *DevPath\r
+  )\r
+{\r
+  MAC_ADDR_DEVICE_PATH  *MACDevPath;\r
+  UINTN                 HwAddressSize;\r
+  UINTN                 Index;\r
+\r
+  MACDevPath           = DevPath;\r
+\r
+  HwAddressSize = sizeof (EFI_MAC_ADDRESS);\r
+  if (MACDevPath->IfType == 0x01 || MACDevPath->IfType == 0x00) {\r
+    HwAddressSize = 6;\r
+  }\r
+\r
+  CatPrint (Str, L"Mac(");\r
+\r
+  for (Index = 0; Index < HwAddressSize; Index++) {\r
+    CatPrint (Str, L"%02x", (UINTN) MACDevPath->MacAddress.Addr[Index]);\r
+  }\r
+\r
+  CatPrint (Str, L")");\r
+}\r
+\r
+/**\r
+  Convert Device Path to a Unicode string for printing.\r
+\r
+  @param Str             The buffer holding the output string.\r
+                         This buffer contains the length of the\r
+                         string and the maixmum length reserved\r
+                         for the string buffer.\r
+  @param DevPath         The device path.\r
+\r
+**/\r
+VOID\r
+DevPathIPv4 (\r
+  IN OUT POOL_PRINT       *Str,\r
+  IN VOID                 *DevPath\r
+  )\r
+{\r
+  IPv4_DEVICE_PATH  *IPDevPath;\r
+\r
+  IPDevPath = DevPath;\r
+  CatPrint (\r
+    Str,\r
+    L"IPv4(%d.%d.%d.%d:%d)",\r
+    (UINTN) IPDevPath->RemoteIpAddress.Addr[0],\r
+    (UINTN) IPDevPath->RemoteIpAddress.Addr[1],\r
+    (UINTN) IPDevPath->RemoteIpAddress.Addr[2],\r
+    (UINTN) IPDevPath->RemoteIpAddress.Addr[3],\r
+    (UINTN) IPDevPath->RemotePort\r
+    );\r
+}\r
+\r
+/**\r
+  Convert Device Path to a Unicode string for printing.\r
+\r
+  @param Str             The buffer holding the output string.\r
+                         This buffer contains the length of the\r
+                         string and the maixmum length reserved\r
+                         for the string buffer.\r
+  @param DevPath         The device path.\r
+\r
+**/\r
+VOID\r
+DevPathIPv6 (\r
+  IN OUT POOL_PRINT       *Str,\r
+  IN VOID                 *DevPath\r
+  )\r
+{\r
+  IPv6_DEVICE_PATH  *IPv6DevPath;\r
+\r
+  IPv6DevPath = DevPath;\r
+  CatPrint (\r
+    Str,\r
+    L"IPv6(%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x)",\r
+    (UINTN) IPv6DevPath->RemoteIpAddress.Addr[0],\r
+    (UINTN) IPv6DevPath->RemoteIpAddress.Addr[1],\r
+    (UINTN) IPv6DevPath->RemoteIpAddress.Addr[2],\r
+    (UINTN) IPv6DevPath->RemoteIpAddress.Addr[3],\r
+    (UINTN) IPv6DevPath->RemoteIpAddress.Addr[4],\r
+    (UINTN) IPv6DevPath->RemoteIpAddress.Addr[5],\r
+    (UINTN) IPv6DevPath->RemoteIpAddress.Addr[6],\r
+    (UINTN) IPv6DevPath->RemoteIpAddress.Addr[7],\r
+    (UINTN) IPv6DevPath->RemoteIpAddress.Addr[8],\r
+    (UINTN) IPv6DevPath->RemoteIpAddress.Addr[9],\r
+    (UINTN) IPv6DevPath->RemoteIpAddress.Addr[10],\r
+    (UINTN) IPv6DevPath->RemoteIpAddress.Addr[11],\r
+    (UINTN) IPv6DevPath->RemoteIpAddress.Addr[12],\r
+    (UINTN) IPv6DevPath->RemoteIpAddress.Addr[13],\r
+    (UINTN) IPv6DevPath->RemoteIpAddress.Addr[14],\r
+    (UINTN) IPv6DevPath->RemoteIpAddress.Addr[15]\r
+    );\r
+}\r
+\r
+/**\r
+  Convert Device Path to a Unicode string for printing.\r
+\r
+  @param Str             The buffer holding the output string.\r
+                         This buffer contains the length of the\r
+                         string and the maixmum length reserved\r
+                         for the string buffer.\r
+  @param DevPath         The device path.\r
+\r
+**/\r
+VOID\r
+DevPathInfiniBand (\r
+  IN OUT POOL_PRINT       *Str,\r
+  IN VOID                 *DevPath\r
+  )\r
+{\r
+  INFINIBAND_DEVICE_PATH  *InfiniBand;\r
+\r
+  InfiniBand = DevPath;\r
+  CatPrint (\r
+    Str,\r
+    L"Infiniband(%x,%g,%lx,%lx,%lx)",\r
+    (UINTN) InfiniBand->ResourceFlags,\r
+    InfiniBand->PortGid,\r
+    InfiniBand->ServiceId,\r
+    InfiniBand->TargetPortId,\r
+    InfiniBand->DeviceId\r
+    );\r
+}\r
+\r
+/**\r
+  Convert Device Path to a Unicode string for printing.\r
+\r
+  @param Str             The buffer holding the output string.\r
+                         This buffer contains the length of the\r
+                         string and the maixmum length reserved\r
+                         for the string buffer.\r
+  @param DevPath         The device path.\r
+\r
+**/\r
+VOID\r
+DevPathUart (\r
+  IN OUT POOL_PRINT       *Str,\r
+  IN VOID                 *DevPath\r
+  )\r
+{\r
+  UART_DEVICE_PATH  *Uart;\r
+  CHAR8             Parity;\r
+\r
+  Uart = DevPath;\r
+  switch (Uart->Parity) {\r
+  case 0:\r
+    Parity = 'D';\r
+    break;\r
+\r
+  case 1:\r
+    Parity = 'N';\r
+    break;\r
+\r
+  case 2:\r
+    Parity = 'E';\r
+    break;\r
+\r
+  case 3:\r
+    Parity = 'O';\r
+    break;\r
+\r
+  case 4:\r
+    Parity = 'M';\r
+    break;\r
+\r
+  case 5:\r
+    Parity = 'S';\r
+    break;\r
+\r
+  default:\r
+    Parity = 'x';\r
+    break;\r
+  }\r
+\r
+  if (Uart->BaudRate == 0) {\r
+    CatPrint (Str, L"Uart(DEFAULT,%c,", Parity);\r
+  } else {\r
+    CatPrint (Str, L"Uart(%ld,%c,", Uart->BaudRate, Parity);\r
+  }\r
+\r
+  if (Uart->DataBits == 0) {\r
+    CatPrint (Str, L"D,");\r
+  } else {\r
+    CatPrint (Str, L"%d,", (UINTN) Uart->DataBits);\r
+  }\r
+\r
+  switch (Uart->StopBits) {\r
+  case 0:\r
+    CatPrint (Str, L"D)");\r
+    break;\r
+\r
+  case 1:\r
+    CatPrint (Str, L"1)");\r
+    break;\r
+\r
+  case 2:\r
+    CatPrint (Str, L"1.5)");\r
+    break;\r
+\r
+  case 3:\r
+    CatPrint (Str, L"2)");\r
+    break;\r
+\r
+  default:\r
+    CatPrint (Str, L"x)");\r
+    break;\r
+  }\r
+}\r
+\r
+/**\r
+  Convert Device Path to a Unicode string for printing.\r
+\r
+  @param Str             The buffer holding the output string.\r
+                         This buffer contains the length of the\r
+                         string and the maixmum length reserved\r
+                         for the string buffer.\r
+  @param DevPath         The device path.\r
+\r
+**/\r
+VOID\r
+DevPathiSCSI (\r
+  IN OUT POOL_PRINT       *Str,\r
+  IN VOID                 *DevPath\r
+  )\r
+{\r
+  ISCSI_DEVICE_PATH_WITH_NAME *IScsi;\r
+  UINT16                      Options;\r
+\r
+  IScsi = DevPath;\r
+  CatPrint (\r
+    Str,\r
+    L"iSCSI(%a,%x,%lx,",\r
+    IScsi->TargetName,\r
+    (UINTN) IScsi->TargetPortalGroupTag,\r
+    IScsi->Lun\r
+    );\r
+\r
+  Options = IScsi->LoginOption;\r
+  CatPrint (Str, L"%s,", (((Options >> 1) & 0x0001) != 0) ? L"CRC32C" : L"None");\r
+  CatPrint (Str, L"%s,", (((Options >> 3) & 0x0001) != 0) ? L"CRC32C" : L"None");\r
+  if (((Options >> 11) & 0x0001) != 0) {\r
+    CatPrint (Str, L"%s,", L"None");\r
+  } else if (((Options >> 12) & 0x0001) != 0) {\r
+    CatPrint (Str, L"%s,", L"CHAP_UNI");\r
+  } else {\r
+    CatPrint (Str, L"%s,", L"CHAP_BI");\r
+\r
+  }\r
+\r
+  CatPrint (Str, L"%s)", (IScsi->NetworkProtocol == 0) ? L"TCP" : L"reserved");\r
+}\r
+\r
+/**\r
+  Convert Device Path to a Unicode string for printing.\r
+\r
+  @param Str             The buffer holding the output string.\r
+                         This buffer contains the length of the\r
+                         string and the maixmum length reserved\r
+                         for the string buffer.\r
+  @param DevPath         The device path.\r
+\r
+**/\r
+VOID\r
+DevPathVlan (\r
+  IN OUT POOL_PRINT       *Str,\r
+  IN VOID                 *DevPath\r
+  )\r
+{\r
+  VLAN_DEVICE_PATH  *Vlan;\r
+\r
+  Vlan = DevPath;\r
+  CatPrint (Str, L"Vlan(%d)", (UINTN) Vlan->VlanId);\r
+}\r
+\r
+/**\r
+  Convert Device Path to a Unicode string for printing.\r
+\r
+  @param Str             The buffer holding the output string.\r
+                         This buffer contains the length of the\r
+                         string and the maixmum length reserved\r
+                         for the string buffer.\r
+  @param DevPath         The device path.\r
+\r
+**/\r
+VOID\r
+DevPathHardDrive (\r
+  IN OUT POOL_PRINT       *Str,\r
+  IN VOID                 *DevPath\r
+  )\r
+{\r
+  HARDDRIVE_DEVICE_PATH *Hd;\r
+\r
+  Hd = DevPath;\r
+  switch (Hd->SignatureType) {\r
+  case SIGNATURE_TYPE_MBR:\r
+    CatPrint (\r
+      Str,\r
+      L"HD(Part%d,Sig%08x)",\r
+      (UINTN) Hd->PartitionNumber,\r
+      (UINTN) *((UINT32 *) (&(Hd->Signature[0])))\r
+      );\r
+    break;\r
+\r
+  case SIGNATURE_TYPE_GUID:\r
+    CatPrint (\r
+      Str,\r
+      L"HD(Part%d,Sig%g)",\r
+      (UINTN) Hd->PartitionNumber,\r
+      (EFI_GUID *) &(Hd->Signature[0])\r
+      );\r
+    break;\r
+\r
+  default:\r
+    CatPrint (\r
+      Str,\r
+      L"HD(Part%d,MBRType=%02x,SigType=%02x)",\r
+      (UINTN) Hd->PartitionNumber,\r
+      (UINTN) Hd->MBRType,\r
+      (UINTN) Hd->SignatureType\r
+      );\r
+    break;\r
+  }\r
+}\r
+\r
+/**\r
+  Convert Device Path to a Unicode string for printing.\r
+\r
+  @param Str             The buffer holding the output string.\r
+                         This buffer contains the length of the\r
+                         string and the maixmum length reserved\r
+                         for the string buffer.\r
+  @param DevPath         The device path.\r
+\r
+**/\r
+VOID\r
+DevPathCDROM (\r
+  IN OUT POOL_PRINT       *Str,\r
+  IN VOID                 *DevPath\r
+  )\r
+{\r
+  CDROM_DEVICE_PATH *Cd;\r
+\r
+  Cd = DevPath;\r
+  CatPrint (Str, L"CDROM(Entry%x)", (UINTN) Cd->BootEntry);\r
+}\r
+\r
+/**\r
+  Convert Device Path to a Unicode string for printing.\r
+\r
+  @param Str             The buffer holding the output string.\r
+                         This buffer contains the length of the\r
+                         string and the maixmum length reserved\r
+                         for the string buffer.\r
+  @param DevPath         The device path.\r
+\r
+**/\r
+VOID\r
+DevPathFilePath (\r
+  IN OUT POOL_PRINT       *Str,\r
+  IN VOID                 *DevPath\r
+  )\r
+{\r
+  FILEPATH_DEVICE_PATH  *Fp;\r
+\r
+  Fp = DevPath;\r
+  CatPrint (Str, L"%s", Fp->PathName);\r
+}\r
+\r
+/**\r
+  Convert Device Path to a Unicode string for printing.\r
+\r
+  @param Str             The buffer holding the output string.\r
+                         This buffer contains the length of the\r
+                         string and the maixmum length reserved\r
+                         for the string buffer.\r
+  @param DevPath         The device path.\r
+\r
+**/\r
+VOID\r
+DevPathMediaProtocol (\r
+  IN OUT POOL_PRINT       *Str,\r
+  IN VOID                 *DevPath\r
+  )\r
+{\r
+  MEDIA_PROTOCOL_DEVICE_PATH  *MediaProt;\r
+\r
+  MediaProt = DevPath;\r
+  CatPrint (Str, L"Media(%g)", &MediaProt->Protocol);\r
+}\r
+\r
+/**\r
+  Convert Device Path to a Unicode string for printing.\r
+\r
+  @param Str             The buffer holding the output string.\r
+                         This buffer contains the length of the\r
+                         string and the maixmum length reserved\r
+                         for the string buffer.\r
+  @param DevPath         The device path.\r
+\r
+**/\r
+VOID\r
+DevPathFvFilePath (\r
+  IN OUT POOL_PRINT       *Str,\r
+  IN VOID                 *DevPath\r
+  )\r
+{\r
+  MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvFilePath;\r
+\r
+  FvFilePath = DevPath;\r
+  CatPrint (Str, L"%g", &FvFilePath->FvFileName);\r
+}\r
+\r
+/**\r
+  Convert Device Path to a Unicode string for printing.\r
+\r
+  @param Str             The buffer holding the output string.\r
+                         This buffer contains the length of the\r
+                         string and the maixmum length reserved\r
+                         for the string buffer.\r
+  @param DevPath         The device path.\r
+\r
+**/\r
+VOID\r
+MyDevPathRelativeOffsetRange (\r
+  IN OUT POOL_PRINT       *Str,\r
+  IN VOID                 *DevPath\r
+  )\r
+{\r
+  MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH *Offset;\r
+\r
+  Offset = DevPath;\r
+  CatPrint (\r
+    Str,\r
+    L"Offset(%lx,%lx)",\r
+    Offset->StartingOffset,\r
+    Offset->EndingOffset\r
+    );\r
+}\r
+\r
+/**\r
+  Convert Device Path to a Unicode string for printing.\r
+\r
+  @param Str             The buffer holding the output string.\r
+                         This buffer contains the length of the\r
+                         string and the maixmum length reserved\r
+                         for the string buffer.\r
+  @param DevPath         The device path.\r
+\r
+**/\r
+VOID\r
+DevPathBssBss (\r
+  IN OUT POOL_PRINT       *Str,\r
+  IN VOID                 *DevPath\r
+  )\r
+{\r
+  BBS_BBS_DEVICE_PATH *Bbs;\r
+  CHAR16              *Type;\r
+\r
+  Bbs = DevPath;\r
+  switch (Bbs->DeviceType) {\r
+  case BBS_TYPE_FLOPPY:\r
+    Type = L"Floppy";\r
+    break;\r
+\r
+  case BBS_TYPE_HARDDRIVE:\r
+    Type = L"Harddrive";\r
+    break;\r
+\r
+  case BBS_TYPE_CDROM:\r
+    Type = L"CDROM";\r
+    break;\r
+\r
+  case BBS_TYPE_PCMCIA:\r
+    Type = L"PCMCIA";\r
+    break;\r
+\r
+  case BBS_TYPE_USB:\r
+    Type = L"Usb";\r
+    break;\r
+\r
+  case BBS_TYPE_EMBEDDED_NETWORK:\r
+    Type = L"Net";\r
+    break;\r
+\r
+  case BBS_TYPE_BEV:\r
+    Type = L"BEV";\r
+    break;\r
+\r
+  default:\r
+    Type = L"?";\r
+    break;\r
+  }\r
+  CatPrint (Str, L"Legacy-%s", Type);\r
+}\r
+\r
+/**\r
+  Convert Device Path to a Unicode string for printing.\r
+\r
+  @param Str             The buffer holding the output string.\r
+                         This buffer contains the length of the\r
+                         string and the maixmum length reserved\r
+                         for the string buffer.\r
+  @param DevPath         The device path.\r
+\r
+**/\r
+VOID\r
+DevPathEndInstance (\r
+  IN OUT POOL_PRINT       *Str,\r
+  IN VOID                 *DevPath\r
+  )\r
+{\r
+  CatPrint (Str, L",");\r
+}\r
+\r
+/**\r
+  Convert Device Path to a Unicode string for printing.\r
+\r
+  @param Str             The buffer holding the output string.\r
+                         This buffer contains the length of the\r
+                         string and the maixmum length reserved\r
+                         for the string buffer.\r
+  @param DevPath         The device path.\r
+\r
+**/\r
+VOID\r
+DevPathNodeUnknown (\r
+  IN OUT POOL_PRINT       *Str,\r
+  IN VOID                 *DevPath\r
+  )\r
+{\r
+  CatPrint (Str, L"?");\r
+}\r
+/**\r
+  Convert Device Path to a Unicode string for printing.\r
+\r
+  @param Str             The buffer holding the output string.\r
+                         This buffer contains the length of the\r
+                         string and the maximum length reserved\r
+                         for the string buffer.\r
+  @param DevPath         The device path.\r
+\r
+**/\r
+VOID\r
+DevPathFvPath (\r
+  IN OUT POOL_PRINT       *Str,\r
+  IN VOID                 *DevPath\r
+  )\r
+{\r
+  MEDIA_FW_VOL_DEVICE_PATH *FvPath;\r
+\r
+  FvPath = DevPath;\r
+  CatPrint (Str, L"Fv(%g)", &FvPath->FvName);\r
+}\r
+\r
+DEVICE_PATH_STRING_TABLE  DevPathTable[] = {\r
+  {\r
+    HARDWARE_DEVICE_PATH,\r
+    HW_PCI_DP,\r
+    DevPathPci\r
+  },\r
+  {\r
+    HARDWARE_DEVICE_PATH,\r
+    HW_PCCARD_DP,\r
+    DevPathPccard\r
+  },\r
+  {\r
+    HARDWARE_DEVICE_PATH,\r
+    HW_MEMMAP_DP,\r
+    DevPathMemMap\r
+  },\r
+  {\r
+    HARDWARE_DEVICE_PATH,\r
+    HW_VENDOR_DP,\r
+    DevPathVendor\r
+  },\r
+  {\r
+    HARDWARE_DEVICE_PATH,\r
+    HW_CONTROLLER_DP,\r
+    DevPathController\r
+  },\r
+  {\r
+    ACPI_DEVICE_PATH,\r
+    ACPI_DP,\r
+    DevPathAcpi\r
+  },\r
+  {\r
+    ACPI_DEVICE_PATH,\r
+    ACPI_EXTENDED_DP,\r
+    DevPathExtendedAcpi\r
+  },\r
+  {\r
+    ACPI_DEVICE_PATH,\r
+    ACPI_ADR_DP,\r
+    DevPathAdrAcpi\r
+  },\r
+  {\r
+    MESSAGING_DEVICE_PATH,\r
+    MSG_ATAPI_DP,\r
+    DevPathAtapi\r
+  },\r
+  {\r
+    MESSAGING_DEVICE_PATH,\r
+    MSG_SCSI_DP,\r
+    DevPathScsi\r
+  },\r
+  {\r
+    MESSAGING_DEVICE_PATH,\r
+    MSG_FIBRECHANNEL_DP,\r
+    DevPathFibre\r
+  },\r
+  {\r
+    MESSAGING_DEVICE_PATH,\r
+    MSG_1394_DP,\r
+    DevPath1394\r
+  },\r
+  {\r
+    MESSAGING_DEVICE_PATH,\r
+    MSG_USB_DP,\r
+    DevPathUsb\r
+  },\r
+  {\r
+    MESSAGING_DEVICE_PATH,\r
+    MSG_USB_WWID_DP,\r
+    DevPathUsbWWID\r
+  },\r
+  {\r
+    MESSAGING_DEVICE_PATH,\r
+    MSG_DEVICE_LOGICAL_UNIT_DP,\r
+    DevPathLogicalUnit\r
+  },\r
+  {\r
+    MESSAGING_DEVICE_PATH,\r
+    MSG_USB_CLASS_DP,\r
+    DevPathUsbClass\r
+  },\r
+  {\r
+    MESSAGING_DEVICE_PATH,\r
+    MSG_SATA_DP,\r
+    DevPathSata\r
+  },\r
+  {\r
+    MESSAGING_DEVICE_PATH,\r
+    MSG_I2O_DP,\r
+    DevPathI2O\r
+  },\r
+  {\r
+    MESSAGING_DEVICE_PATH,\r
+    MSG_MAC_ADDR_DP,\r
+    DevPathMacAddr\r
+  },\r
+  {\r
+    MESSAGING_DEVICE_PATH,\r
+    MSG_IPv4_DP,\r
+    DevPathIPv4\r
+  },\r
+  {\r
+    MESSAGING_DEVICE_PATH,\r
+    MSG_IPv6_DP,\r
+    DevPathIPv6\r
+  },\r
+  {\r
+    MESSAGING_DEVICE_PATH,\r
+    MSG_INFINIBAND_DP,\r
+    DevPathInfiniBand\r
+  },\r
+  {\r
+    MESSAGING_DEVICE_PATH,\r
+    MSG_UART_DP,\r
+    DevPathUart\r
+  },\r
+  {\r
+    MESSAGING_DEVICE_PATH,\r
+    MSG_VENDOR_DP,\r
+    DevPathVendor\r
+  },\r
+  {\r
+    MESSAGING_DEVICE_PATH,\r
+    MSG_ISCSI_DP,\r
+    DevPathiSCSI\r
+  },\r
+  {\r
+    MESSAGING_DEVICE_PATH,\r
+    MSG_VLAN_DP,\r
+    DevPathVlan\r
+  },\r
+  {\r
+    MEDIA_DEVICE_PATH,\r
+    MEDIA_HARDDRIVE_DP,\r
+    DevPathHardDrive\r
+  },\r
+  {\r
+    MEDIA_DEVICE_PATH,\r
+    MEDIA_CDROM_DP,\r
+    DevPathCDROM\r
+  },\r
+  {\r
+    MEDIA_DEVICE_PATH,\r
+    MEDIA_VENDOR_DP,\r
+    DevPathVendor\r
+  },\r
+  {\r
+    MEDIA_DEVICE_PATH,\r
+    MEDIA_FILEPATH_DP,\r
+    DevPathFilePath\r
+  },\r
+  {\r
+    MEDIA_DEVICE_PATH,\r
+    MEDIA_PROTOCOL_DP,\r
+    DevPathMediaProtocol\r
+  },\r
+  {\r
+    MEDIA_DEVICE_PATH,\r
+    MEDIA_PIWG_FW_VOL_DP,\r
+    DevPathFvPath,\r
+  },\r
+  {\r
+    MEDIA_DEVICE_PATH,\r
+    MEDIA_PIWG_FW_FILE_DP,\r
+    DevPathFvFilePath\r
+  },\r
+  {\r
+    MEDIA_DEVICE_PATH,\r
+    MEDIA_RELATIVE_OFFSET_RANGE_DP,\r
+    MyDevPathRelativeOffsetRange,\r
+  },\r
+  {\r
+    BBS_DEVICE_PATH,\r
+    BBS_BBS_DP,\r
+    DevPathBssBss\r
+  },\r
+  {\r
+    END_DEVICE_PATH_TYPE,\r
+    END_INSTANCE_DEVICE_PATH_SUBTYPE,\r
+    DevPathEndInstance\r
+  },\r
+  {\r
+    0,\r
+    0,\r
+    NULL\r
+  }\r
+};\r
+\r
+\r
+/**\r
+  This function converts an input device structure to a Unicode string.\r
+\r
+  @param DevPath                  A pointer to the device path structure.\r
+\r
+  @return A new allocated Unicode string that represents the device path.\r
+\r
+**/\r
+CHAR16 *\r
+EFIAPI\r
+DevicePathToStr (\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *DevPath\r
+  )\r
+{\r
+  POOL_PRINT                Str;\r
+  EFI_DEVICE_PATH_PROTOCOL  *DevPathNode;\r
+  VOID (*DumpNode) (POOL_PRINT *, VOID *);\r
+\r
+  UINTN Index;\r
+  UINTN NewSize;\r
+\r
+  EFI_STATUS                       Status;\r
+  CHAR16                           *ToText;\r
+  EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *DevPathToText;\r
+\r
+  ZeroMem (&Str, sizeof (Str));\r
+\r
+  if (DevPath == NULL) {\r
+    goto Done;\r
+  }\r
+\r
+  Status = gBS->LocateProtocol (\r
+                  &gEfiDevicePathToTextProtocolGuid,\r
+                  NULL,\r
+                  (VOID **) &DevPathToText\r
+                  );\r
+  if (!EFI_ERROR (Status)) {\r
+    ToText = DevPathToText->ConvertDevicePathToText (\r
+                              DevPath,\r
+                              FALSE,\r
+                              TRUE\r
+                              );\r
+    ASSERT (ToText != NULL);\r
+    return ToText;\r
+  }\r
+\r
+  //\r
+  // Process each device path node\r
+  //\r
+  DevPathNode = DevPath;\r
+  while (!IsDevicePathEnd (DevPathNode)) {\r
+    //\r
+    // Find the handler to dump this device path node\r
+    //\r
+    DumpNode = NULL;\r
+    for (Index = 0; DevPathTable[Index].Function != NULL; Index += 1) {\r
+\r
+      if (DevicePathType (DevPathNode) == DevPathTable[Index].Type &&\r
+          DevicePathSubType (DevPathNode) == DevPathTable[Index].SubType\r
+          ) {\r
+        DumpNode = DevPathTable[Index].Function;\r
+        break;\r
+      }\r
+    }\r
+    //\r
+    // If not found, use a generic function\r
+    //\r
+    if (!DumpNode) {\r
+      DumpNode = DevPathNodeUnknown;\r
+    }\r
+    //\r
+    //  Put a path seperator in if needed\r
+    //\r
+    if ((Str.Len != 0) && (DumpNode != DevPathEndInstance)) {\r
+      CatPrint (&Str, L"/");\r
+    }\r
+    //\r
+    // Print this node of the device path\r
+    //\r
+    DumpNode (&Str, DevPathNode);\r
+\r
+    //\r
+    // Next device path node\r
+    //\r
+    DevPathNode = NextDevicePathNode (DevPathNode);\r
+  }\r
+\r
+Done:\r
+  NewSize = (Str.Len + 1) * sizeof (CHAR16);\r
+  Str.Str = EfiReallocatePool (Str.Str, NewSize, NewSize);\r
+  ASSERT (Str.Str != NULL);\r
+  Str.Str[Str.Len] = 0;\r
+  return Str.Str;\r
+}\r
diff --git a/EfiLib/DevicePathUtilities.h b/EfiLib/DevicePathUtilities.h
new file mode 100644 (file)
index 0000000..b559671
--- /dev/null
@@ -0,0 +1,233 @@
+/*++\r
+\r
+Copyright (c) 2006 - 2007, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials                          \r
+are licensed and made available under the terms and conditions of the BSD License         \r
+which accompanies this distribution.  The full text of the license may be found at        \r
+http://opensource.org/licenses/bsd-license.php                                            \r
+                                                                                          \r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
+\r
+Module Name:\r
+\r
+  DevicePathUtilities.h\r
+\r
+Abstract:\r
+\r
+--*/\r
+\r
+#ifndef _DEVICE_PATH_UTILITIES_PROTOCOL_H_\r
+#define _DEVICE_PATH_UTILITIES_PROTOCOL_H_\r
+\r
+//\r
+// Device Path Utilities protocol\r
+//\r
+#define EFI_DEVICE_PATH_UTILITIES_PROTOCOL_GUID \\r
+  { \\r
+    0x379be4e, 0xd706, 0x437d, {0xb0, 0x37, 0xed, 0xb8, 0x2f, 0xb7, 0x72, 0xa4}  \\r
+  }\r
+\r
+typedef\r
+UINTN\r
+EFIAPI\r
+(EFIAPI *EFI_DEVICE_PATH_UTILS_GET_DEVICE_PATH_SIZE) (\r
+  IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+    Returns the size of the device path, in bytes.\r
+\r
+  Arguments:\r
+    DevicePath  -   Points to the start of the EFI device path.\r
+\r
+  Returns:\r
+    Size        -   Size of the specified device path, in bytes, including the end-of-path tag.\r
+\r
+--*/\r
+;\r
+\r
+typedef\r
+EFI_DEVICE_PATH_PROTOCOL*\r
+EFIAPI\r
+(EFIAPI *EFI_DEVICE_PATH_UTILS_DUP_DEVICE_PATH) (\r
+  IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+    Create a duplicate of the specified path.\r
+\r
+  Arguments:\r
+    DevicePath  -   Points to the source EFI device path.\r
+\r
+  Returns:\r
+    Pointer     -   A pointer to the duplicate device path.\r
+    NULL        -   Insufficient memory.\r
+\r
+--*/\r
+;\r
+\r
+typedef\r
+EFI_DEVICE_PATH_PROTOCOL*\r
+EFIAPI\r
+(EFIAPI *EFI_DEVICE_PATH_UTILS_APPEND_PATH) (\r
+  IN CONST EFI_DEVICE_PATH_PROTOCOL *Src1,\r
+  IN CONST EFI_DEVICE_PATH_PROTOCOL *Src2\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+    Create a new path by appending the second device path to the first.\r
+\r
+  Arguments:\r
+    Src1      -   Points to the first device path. If NULL, then it is ignored.\r
+    Src2      -   Points to the second device path. If NULL, then it is ignored.\r
+\r
+  Returns:\r
+    Pointer   -   A pointer to the newly created device path.\r
+    NULL      -   Memory could not be allocated\r
+                  or either DevicePath or DeviceNode is NULL.\r
+\r
+--*/\r
+;\r
+\r
+typedef\r
+EFI_DEVICE_PATH_PROTOCOL*\r
+EFIAPI\r
+(EFIAPI *EFI_DEVICE_PATH_UTILS_APPEND_NODE) (\r
+  IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
+  IN CONST EFI_DEVICE_PATH_PROTOCOL *DeviceNode\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+    Creates a new path by appending the device node to the device path.\r
+\r
+  Arguments:\r
+    DevicePath   -   Points to the device path.\r
+    DeviceNode   -   Points to the device node.\r
+\r
+  Returns:\r
+    Pointer      -   A pointer to the allocated device node.\r
+    NULL         -   Memory could not be allocated\r
+                     or either DevicePath or DeviceNode is NULL.\r
+\r
+--*/\r
+;\r
+\r
+typedef\r
+EFI_DEVICE_PATH_PROTOCOL*\r
+EFIAPI\r
+(EFIAPI *EFI_DEVICE_PATH_UTILS_APPEND_INSTANCE) (\r
+  IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
+  IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePathInstance\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+    Creates a new path by appending the specified device path instance to the specified device path.\r
+\r
+  Arguments:\r
+    DevicePath           -   Points to the device path. If NULL, then ignored.\r
+    DevicePathInstance   -   Points to the device path instance.\r
+\r
+  Returns:\r
+    Pointer              -   A pointer to the newly created device path\r
+    NULL                 -   Memory could not be allocated or DevicePathInstance is NULL.\r
+\r
+--*/\r
+;\r
+\r
+typedef\r
+EFI_DEVICE_PATH_PROTOCOL*\r
+EFIAPI\r
+(EFIAPI *EFI_DEVICE_PATH_UTILS_GET_NEXT_INSTANCE) (\r
+  IN  OUT EFI_DEVICE_PATH_PROTOCOL  **DevicePathInstance,\r
+  OUT UINTN                         *DevicePathInstanceSize\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+    Creates a copy of the current device path instance and returns a pointer to the next device path instance.\r
+\r
+  Arguments:\r
+    DevicePathInstance       -   On input, this holds the pointer to the current device path\r
+                                 instance. On output, this holds the pointer to the next\r
+                                 device path instance or NULL if there are no more device\r
+                                 path instances in the device path.\r
+    DevicePathInstanceSize   -   On output, this holds the size of the device path instance,\r
+                                 in bytes or zero, if DevicePathInstance is zero.\r
+\r
+  Returns:\r
+    Pointer                  -   A pointer to the copy of the current device path instance.\r
+    NULL                     -   DevicePathInstace was NULL on entry or there was insufficient memory.\r
+\r
+--*/\r
+;\r
+\r
+typedef\r
+BOOLEAN\r
+EFIAPI\r
+(EFIAPI *EFI_DEVICE_PATH_UTILS_IS_MULTI_INSTANCE) (\r
+  IN CONST EFI_DEVICE_PATH_PROTOCOL         *DevicePath\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+    Returns whether a device path is multi-instance.\r
+\r
+  Arguments:\r
+    DevicePath  -   Points to the device path. If NULL, then ignored.\r
+\r
+  Returns:\r
+    TRUE        -   The device path has more than one instance\r
+    FALSE       -   The device path is empty or contains only a single instance.\r
+\r
+--*/\r
+;\r
+\r
+typedef\r
+EFI_DEVICE_PATH_PROTOCOL*\r
+EFIAPI\r
+(EFIAPI *EFI_DEVICE_PATH_UTILS_CREATE_NODE) (\r
+  IN UINT8                          NodeType,\r
+  IN UINT8                          NodeSubType,\r
+  IN UINT16                         NodeLength\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+    Creates a device node\r
+\r
+  Arguments:\r
+    NodeType     -    NodeType is the device node type (EFI_DEVICE_PATH.Type) for\r
+                      the new device node.\r
+    NodeSubType  -    NodeSubType is the device node sub-type\r
+                      EFI_DEVICE_PATH.SubType) for the new device node.\r
+    NodeLength   -    NodeLength is the length of the device node\r
+                      (EFI_DEVICE_PATH.Length) for the new device node.\r
+\r
+  Returns:\r
+    Pointer      -    A pointer to the newly created device node.\r
+    NULL         -    NodeLength is less than\r
+                      the size of the header or there was insufficient memory.\r
+\r
+--*/\r
+;\r
+\r
+typedef struct {\r
+  EFI_DEVICE_PATH_UTILS_GET_DEVICE_PATH_SIZE GetDevicePathSize;\r
+  EFI_DEVICE_PATH_UTILS_DUP_DEVICE_PATH      DuplicateDevicePath;\r
+  EFI_DEVICE_PATH_UTILS_APPEND_PATH          AppendDevicePath;\r
+  EFI_DEVICE_PATH_UTILS_APPEND_NODE          AppendDeviceNode;\r
+  EFI_DEVICE_PATH_UTILS_APPEND_INSTANCE      AppendDevicePathInstance;\r
+  EFI_DEVICE_PATH_UTILS_GET_NEXT_INSTANCE    GetNextDevicePathInstance;\r
+  EFI_DEVICE_PATH_UTILS_IS_MULTI_INSTANCE    IsDevicePathMultiInstance;\r
+  EFI_DEVICE_PATH_UTILS_CREATE_NODE          CreateDeviceNode;\r
+} EFI_DEVICE_PATH_UTILITIES_PROTOCOL;\r
+\r
+extern EFI_GUID gEfiDevicePathUtilitiesProtocolGuid;\r
+\r
+#endif\r
diff --git a/EfiLib/GenericBdsLib.h b/EfiLib/GenericBdsLib.h
new file mode 100644 (file)
index 0000000..be4325b
--- /dev/null
@@ -0,0 +1,1001 @@
+/** @file\r
+  Generic BDS library defines general interfaces for a BDS driver, including:\r
+    1) BDS boot policy interface.\r
+    2) BDS boot device connect interface.\r
+    3) BDS Misc interfaces for mainting boot variable, ouput string.\r
+\r
+Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials are licensed and made available under \r
+the terms and conditions of the BSD License that accompanies this distribution.  \r
+The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php.                                          \r
+    \r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _GENERIC_BDS_LIB_H_\r
+#define _GENERIC_BDS_LIB_H_\r
+\r
+#ifdef __MAKEWITH_GNUEFI\r
+#include "gnuefi-helper.h"\r
+#endif\r
+\r
+//#include <Protocol/UserManager.h>\r
+\r
+///\r
+/// Constants which are variable names used to access variables.\r
+///\r
+#define VAR_LEGACY_DEV_ORDER L"LegacyDevOrder"\r
+\r
+///\r
+/// Data structures and defines.\r
+///\r
+#define FRONT_PAGE_QUESTION_ID  0x0000\r
+#define FRONT_PAGE_DATA_WIDTH   0x01\r
+\r
+///\r
+/// ConnectType\r
+///\r
+#define CONSOLE_OUT 0x00000001\r
+#define STD_ERROR   0x00000002\r
+#define CONSOLE_IN  0x00000004\r
+#define CONSOLE_ALL (CONSOLE_OUT | CONSOLE_IN | STD_ERROR)\r
+\r
+///\r
+/// Load Option Attributes\r
+///\r
+#define LOAD_OPTION_ACTIVE              0x00000001\r
+#define LOAD_OPTION_FORCE_RECONNECT     0x00000002\r
+\r
+#define LOAD_OPTION_HIDDEN              0x00000008\r
+#define LOAD_OPTION_CATEGORY            0x00001F00\r
+\r
+#define LOAD_OPTION_CATEGORY_BOOT       0x00000000\r
+#define LOAD_OPTION_CATEGORY_APP        0x00000100\r
+\r
+#define EFI_BOOT_OPTION_SUPPORT_KEY     0x00000001\r
+#define EFI_BOOT_OPTION_SUPPORT_APP     0x00000002\r
+\r
+#define IS_LOAD_OPTION_TYPE(_c, _Mask)  (BOOLEAN) (((_c) & (_Mask)) != 0)\r
+\r
+///\r
+/// Define the maximum characters that will be accepted.\r
+///\r
+#define MAX_CHAR            480\r
+#define MAX_CHAR_SIZE       (MAX_CHAR * 2)\r
+\r
+///\r
+/// Define maximum characters for boot option variable "BootXXXX".\r
+///\r
+#define BOOT_OPTION_MAX_CHAR 10\r
+\r
+//\r
+// This data structure is the part of BDS_CONNECT_ENTRY\r
+//\r
+#ifdef __MAKEWITH_TIANO\r
+#define BDS_LOAD_OPTION_SIGNATURE SIGNATURE_32 ('B', 'd', 'C', 'O')\r
+#else\r
+#define BDS_LOAD_OPTION_SIGNATURE EFI_SIGNATURE_32 ('B', 'd', 'C', 'O')\r
+#endif\r
+\r
+typedef struct {\r
+\r
+  UINTN                     Signature;\r
+  LIST_ENTRY                Link;\r
+\r
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
+\r
+  CHAR16                    *OptionName;\r
+  UINTN                     OptionNumber;\r
+  UINT16                    BootCurrent;\r
+  UINT32                    Attribute;\r
+  CHAR16                    *Description;\r
+  VOID                      *LoadOptions;\r
+  UINT32                    LoadOptionsSize;\r
+  CHAR16                    *StatusString;\r
+\r
+} BDS_COMMON_OPTION;\r
+\r
+typedef struct {\r
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
+  UINTN                     ConnectType;\r
+} BDS_CONSOLE_CONNECT_ENTRY;\r
+\r
+//\r
+// Bds boot related lib functions\r
+//\r
+/**\r
+  Boot from the UEFI spec defined "BootNext" variable.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+BdsLibBootNext (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Process the boot option according to the UEFI specification. The legacy boot option device path includes BBS_DEVICE_PATH.\r
+\r
+  @param  Option                 The boot option to be processed.\r
+  @param  DevicePath             The device path describing where to load the\r
+                                 boot image or the legcy BBS device path to boot\r
+                                 the legacy OS.\r
+  @param  ExitDataSize           The size of exit data.\r
+  @param  ExitData               Data returned when Boot image failed.\r
+\r
+  @retval EFI_SUCCESS            Boot from the input boot option succeeded.\r
+  @retval EFI_NOT_FOUND          The Device Path is not found in the system.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BdsLibBootViaBootOption (\r
+  IN  BDS_COMMON_OPTION             * Option,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL      * DevicePath,\r
+  OUT UINTN                         *ExitDataSize,\r
+  OUT CHAR16                        **ExitData OPTIONAL\r
+  );\r
+\r
+\r
+/**\r
+  This function will enumerate all possible boot devices in the system, and\r
+  automatically create boot options for Network, Shell, Removable BlockIo, \r
+  and Non-BlockIo Simplefile devices. \r
+  \r
+  BDS separates EFI boot options into six types:\r
+  1. Network - The boot option points to the SimpleNetworkProtocol device. \r
+               Bds will try to automatically create this type of boot option during enumeration.\r
+  2. Shell   - The boot option points to internal flash shell. \r
+               Bds will try to automatically create this type of boot option during enumeration.\r
+  3. Removable BlockIo      - The boot option points to a removable media\r
+                              device, such as a USB flash drive or DVD drive.\r
+                              These devices should contain a *removable* blockIo\r
+                              protocol in their device handle.\r
+                              Bds will try to automatically create this type boot option \r
+                              when enumerate.\r
+  4. Fixed BlockIo          - The boot option points to a Fixed blockIo device, \r
+                              such as a hard disk.\r
+                              These devices should contain a *fixed* blockIo\r
+                              protocol in their device handle.\r
+                              BDS will skip fixed blockIo devices, and not\r
+                              automatically create boot option for them. But BDS \r
+                              will help to delete those fixed blockIo boot options, \r
+                              whose description rules conflict with other auto-created\r
+                              boot options.\r
+  5. Non-BlockIo Simplefile - The boot option points to a device whose handle \r
+                              has SimpleFileSystem Protocol, but has no blockio\r
+                              protocol. These devices do not offer blockIo\r
+                              protocol, but BDS still can get the \r
+                              \EFI\BOOT\boot{machinename}.EFI by SimpleFileSystem\r
+                              Protocol.\r
+  6. File    - The boot option points to a file. These boot options are usually \r
+               created by the user, either manually or with an OS loader. BDS will not delete or modify\r
+               these boot options.        \r
+    \r
+  This function will enumerate all possible boot devices in the system, and\r
+  automatically create boot options for Network, Shell, Removable BlockIo, \r
+  and Non-BlockIo Simplefile devices.\r
+  It will excute once every boot.\r
+  \r
+  @param  BdsBootOptionList      The header of the linked list that indexed all\r
+                                 current boot options.\r
+\r
+  @retval EFI_SUCCESS            Finished all the boot device enumerations and \r
+                                 created the boot option based on the boot device.\r
+\r
+  @retval EFI_OUT_OF_RESOURCES   Failed to enumerate the boot device and create \r
+                                 the boot option list.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BdsLibEnumerateAllBootOption (\r
+  IN OUT LIST_ENTRY          *BdsBootOptionList\r
+  );\r
+\r
+/**\r
+  Build the boot option with the handle parsed in.\r
+\r
+  @param  Handle                 The handle representing the device path for which \r
+                                 to create a boot option.\r
+  @param  BdsBootOptionList      The header of the link list that indexed all\r
+                                 current boot options.\r
+  @param  String                 The description of the boot option.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+BdsLibBuildOptionFromHandle (\r
+  IN  EFI_HANDLE                 Handle,\r
+  IN  LIST_ENTRY                 *BdsBootOptionList,\r
+  IN  CHAR16                     *String\r
+  );\r
+\r
+\r
+/**\r
+  Build the on flash shell boot option with the handle parsed in.\r
+\r
+  @param  Handle                 The handle which present the device path to create\r
+                                 the on flash shell boot option.\r
+  @param  BdsBootOptionList      The header of the link list that indexed all\r
+                                 current boot options.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+BdsLibBuildOptionFromShell (\r
+  IN EFI_HANDLE                  Handle,\r
+  IN OUT LIST_ENTRY              *BdsBootOptionList\r
+  );\r
+\r
+\r
+/**\r
+  The function will go through the driver option link list, and then load and start\r
+  every driver to which the driver option device path points.\r
+\r
+  @param  BdsDriverLists        The header of the current driver option link list.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+BdsLibLoadDrivers (\r
+  IN LIST_ENTRY                   *BdsDriverLists\r
+  );\r
+\r
+\r
+/**\r
+  This function processes BootOrder or DriverOrder variables, by calling\r
+\r
+  BdsLibVariableToOption () for each UINT16 in the variables.\r
+\r
+  @param  BdsCommonOptionList   The header of the option list base on the variable\r
+                                VariableName.\r
+  @param  VariableName          An EFI Variable name indicate the BootOrder or\r
+                                DriverOrder.\r
+\r
+  @retval EFI_SUCCESS           Successfully created the boot option or driver option\r
+                                list.\r
+  @retval EFI_OUT_OF_RESOURCES  Failed to get the boot option or the driver option list.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BdsLibBuildOptionFromVar (\r
+  IN  LIST_ENTRY                      *BdsCommonOptionList,\r
+  IN  CHAR16                          *VariableName\r
+  );\r
+\r
+/**\r
+  This function reads the EFI variable (VendorGuid/Name) and returns a dynamically allocated\r
+  buffer and the size of the buffer. If it fails, return NULL.\r
+\r
+  @param  Name                  The string part of the  EFI variable name.\r
+  @param  VendorGuid            The GUID part of the EFI variable name.\r
+  @param  VariableSize          Returns the size of the EFI variable that was read.\r
+\r
+  @return                       Dynamically allocated memory that contains a copy \r
+                                of the EFI variable. The caller is responsible for \r
+                                freeing the buffer.\r
+  @retval NULL                  The variable was not read.\r
+\r
+**/\r
+VOID *\r
+BdsLibGetVariableAndSize (\r
+  IN  CHAR16              *Name,\r
+  IN  EFI_GUID            *VendorGuid,\r
+  OUT UINTN               *VariableSize\r
+  );\r
+\r
+\r
+/**\r
+  This function prints a series of strings.\r
+\r
+  @param  ConOut                A pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.\r
+  @param  ...                   A variable argument list containing a series of\r
+                                strings, the last string must be NULL.\r
+\r
+  @retval EFI_SUCCESS           Successfully printed out the string using ConOut.\r
+  @retval EFI_STATUS            Return the status of the ConOut->OutputString ().\r
+\r
+**/\r
+// EFI_STATUS\r
+// EFIAPI\r
+// BdsLibOutputStrings (\r
+//   IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL   *ConOut,\r
+//   ...\r
+//   );\r
+\r
+/**\r
+  Build the boot#### or driver#### option from the VariableName. The\r
+  build boot#### or driver#### will also be linked to BdsCommonOptionList.\r
+\r
+  @param  BdsCommonOptionList   The header of the boot#### or driver#### option\r
+                                link list.\r
+  @param  VariableName          EFI Variable name, indicates if it is boot#### or\r
+                                driver####.\r
+\r
+  @retval BDS_COMMON_OPTION     The option that was created.\r
+  @retval NULL                  Failed to get the new option.\r
+\r
+**/\r
+BDS_COMMON_OPTION *\r
+BdsLibVariableToOption (\r
+  IN OUT LIST_ENTRY                   *BdsCommonOptionList,\r
+  IN  CHAR16                          *VariableName\r
+  );\r
+\r
+\r
+/**\r
+  This function creates all handles associated with the given device\r
+  path node. If the handle associated with one device path node cannot\r
+  be created, then it tries to execute the dispatch to load the missing drivers.  \r
+\r
+  @param  DevicePathToConnect   The device path to be connected. Can be\r
+                                a multi-instance device path.\r
+\r
+  @retval EFI_SUCCESS           All handles associates with every device path node\r
+                                were created.\r
+  @retval EFI_OUT_OF_RESOURCES  Not enough resources to create new handles.\r
+  @retval EFI_NOT_FOUND         At least one handle could not be created.\r
+\r
+**/\r
+EFI_STATUS\r
+BdsLibConnectDevicePath (\r
+  IN EFI_DEVICE_PATH_PROTOCOL  *DevicePathToConnect\r
+  );\r
+\r
+\r
+//\r
+// Bds connect and disconnect driver lib funcions\r
+//\r
+/**\r
+ This function connects all system drivers with the corresponding controllers. \r
+\r
+ **/\r
+VOID\r
+EFIAPI\r
+BdsLibConnectAllDriversToAllControllers (\r
+   VOID\r
+);\r
+\r
+/**\r
+  This function will connect console device based on the console\r
+  device variable ConIn, ConOut and ErrOut.\r
+\r
+  @retval EFI_SUCCESS              At least one of the ConIn and ConOut devices have\r
+                                   been connected.\r
+  @retval EFI_STATUS               Return the status of BdsLibConnectConsoleVariable ().\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BdsLibConnectAllDefaultConsoles (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  This function updates the console variable based on ConVarName. It can\r
+  add or remove one specific console device path from the variable\r
+\r
+  @param  ConVarName               The console-related variable name: ConIn, ConOut,\r
+                                   ErrOut.\r
+  @param  CustomizedConDevicePath  The console device path to be added to\r
+                                   the console variable ConVarName. Cannot be multi-instance.\r
+  @param  ExclusiveDevicePath      The console device path to be removed\r
+                                   from the console variable ConVarName. Cannot be multi-instance.\r
+\r
+  @retval EFI_UNSUPPORTED          The added device path is the same as a removed one.\r
+  @retval EFI_SUCCESS              Successfully added or removed the device path from the\r
+                                   console variable.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BdsLibUpdateConsoleVariable (\r
+  IN  CHAR16                    *ConVarName,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL  *CustomizedConDevicePath,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL  *ExclusiveDevicePath\r
+  );\r
+\r
+/**\r
+  Connect the console device base on the variable ConVarName. If\r
+  ConVarName is a multi-instance device path, and at least one\r
+  instance connects successfully, then this function\r
+  will return success.\r
+\r
+  @param  ConVarName               The console related variable name: ConIn, ConOut,\r
+                                   ErrOut.\r
+\r
+  @retval EFI_NOT_FOUND            No console devices were connected successfully\r
+  @retval EFI_SUCCESS              Connected at least one instance of the console\r
+                                   device path based on the variable ConVarName.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BdsLibConnectConsoleVariable (\r
+  IN  CHAR16                 *ConVarName\r
+  );\r
+\r
+//\r
+// Bds device path related lib functions\r
+//\r
+/**\r
+  Delete the instance in Multi that overlaps with Single. \r
+\r
+  @param  Multi                 A pointer to a multi-instance device path data\r
+                                structure.\r
+  @param  Single                A pointer to a single-instance device path data\r
+                                structure.\r
+\r
+  @return This function removes the device path instances in Multi that overlap\r
+          Single, and returns the resulting device path. If there is no\r
+          remaining device path as a result, this function will return NULL.\r
+\r
+**/\r
+EFI_DEVICE_PATH_PROTOCOL *\r
+EFIAPI\r
+BdsLibDelPartMatchInstance (\r
+  IN     EFI_DEVICE_PATH_PROTOCOL  *Multi,\r
+  IN     EFI_DEVICE_PATH_PROTOCOL  *Single\r
+  );\r
+\r
+/**\r
+  This function compares a device path data structure to that of all the nodes of a\r
+  second device path instance.\r
+\r
+  @param  Multi                 A pointer to a multi-instance device path data\r
+                                structure.\r
+  @param  Single                A pointer to a single-instance device path data\r
+                                structure.\r
+\r
+  @retval TRUE                  If the Single device path is contained within a \r
+                                Multi device path.\r
+  @retval FALSE                 The Single device path is not contained within a \r
+                                Multi device path.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+BdsLibMatchDevicePaths (\r
+  IN  EFI_DEVICE_PATH_PROTOCOL  *Multi,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL  *Single\r
+  );\r
+\r
+/**\r
+  This function converts an input device structure to a Unicode string.\r
+\r
+  @param DevPath                  A pointer to the device path structure.\r
+\r
+  @return A newly allocated Unicode string that represents the device path.\r
+\r
+**/\r
+CHAR16 *\r
+EFIAPI\r
+DevicePathToStr (\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *DevPath\r
+  );\r
+\r
+#ifdef __MAKEWITH_TIANO\r
+//\r
+// Internal definitions\r
+//\r
+typedef struct {\r
+  CHAR16  *Str;\r
+  UINTN   Len;\r
+  UINTN   Maxlen;\r
+} POOL_PRINT;\r
+#endif\r
+\r
+typedef\r
+VOID\r
+(*DEV_PATH_FUNCTION) (\r
+  IN OUT POOL_PRINT       *Str,\r
+  IN VOID                 *DevPath\r
+  );\r
+\r
+typedef struct {\r
+  UINT8             Type;\r
+  UINT8             SubType;\r
+  DEV_PATH_FUNCTION Function;\r
+} DEVICE_PATH_STRING_TABLE;\r
+\r
+typedef struct {\r
+  EFI_DEVICE_PATH_PROTOCOL  Header;\r
+  EFI_GUID                  Guid;\r
+  UINT8                     VendorDefinedData[1];\r
+} VENDOR_DEVICE_PATH_WITH_DATA;\r
+\r
+typedef struct {\r
+  EFI_DEVICE_PATH_PROTOCOL  Header;\r
+  UINT16                    NetworkProtocol;\r
+  UINT16                    LoginOption;\r
+  UINT64                    Lun;\r
+  UINT16                    TargetPortalGroupTag;\r
+  CHAR16                    TargetName[1];\r
+} ISCSI_DEVICE_PATH_WITH_NAME;\r
+\r
+//\r
+// BBS support macros and functions\r
+//\r
+\r
+#if defined(MDE_CPU_IA32) || defined(MDE_CPU_X64)\r
+#define REFRESH_LEGACY_BOOT_OPTIONS \\r
+        BdsDeleteAllInvalidLegacyBootOptions ();\\r
+        BdsAddNonExistingLegacyBootOptions (); \\r
+        BdsUpdateLegacyDevOrder ()\r
+#else\r
+#define REFRESH_LEGACY_BOOT_OPTIONS\r
+#endif\r
+\r
+/**\r
+  Delete all the invalid legacy boot options.\r
+\r
+  @retval EFI_SUCCESS             All invalid legacy boot options are deleted.\r
+  @retval EFI_OUT_OF_RESOURCES    Failed to allocate necessary memory.\r
+  @retval EFI_NOT_FOUND           Failed to retrieve variable of boot order.\r
+\r
+**/\r
+EFI_STATUS\r
+BdsDeleteAllInvalidLegacyBootOptions (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Add the legacy boot options from BBS table if they do not exist.\r
+\r
+  @retval EFI_SUCCESS          The boot options were added successfully, \r
+                               or they are already in boot options.\r
+  @retval EFI_NOT_FOUND        No legacy boot options is found.\r
+  @retval EFI_OUT_OF_RESOURCE  No enough memory.\r
+  @return Other value          LegacyBoot options are not added.\r
+**/\r
+EFI_STATUS\r
+BdsAddNonExistingLegacyBootOptions (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Add the legacy boot devices from BBS table into \r
+  the legacy device boot order.\r
+\r
+  @retval EFI_SUCCESS           The boot devices were added successfully.\r
+  @retval EFI_NOT_FOUND         The legacy boot devices are not found.\r
+  @retval EFI_OUT_OF_RESOURCES  Memory or storage is not enough.\r
+  @retval EFI_DEVICE_ERROR      Failed to add the legacy device boot order into EFI variable\r
+                                because of a hardware error.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BdsUpdateLegacyDevOrder (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Refresh the boot priority for BBS entries based on boot option entry and boot order.\r
+\r
+  @param  Entry             The boot option is to be checked for a refreshed BBS table.\r
+  \r
+  @retval EFI_SUCCESS           The boot priority for BBS entries refreshed successfully.\r
+  @retval EFI_NOT_FOUND         BBS entries can't be found.\r
+  @retval EFI_OUT_OF_RESOURCES  Failed to get the legacy device boot order.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BdsRefreshBbsTableForBoot (\r
+  IN BDS_COMMON_OPTION        *Entry\r
+  );\r
+\r
+/**\r
+  Delete the Boot Option from EFI Variable. The Boot Order Arrray\r
+  is also updated.\r
+\r
+  @param OptionNumber    The number of Boot options wanting to be deleted.\r
+  @param BootOrder       The Boot Order array.\r
+  @param BootOrderSize   The size of the Boot Order Array.\r
+\r
+  @retval  EFI_SUCCESS           The Boot Option Variable was found and removed.\r
+  @retval  EFI_UNSUPPORTED       The Boot Option Variable store was inaccessible.\r
+  @retval  EFI_NOT_FOUND         The Boot Option Variable was not found.\r
+**/\r
+EFI_STATUS\r
+BdsDeleteBootOption (\r
+  IN UINTN                       OptionNumber,\r
+  IN OUT UINT16                  *BootOrder,\r
+  IN OUT UINTN                   *BootOrderSize\r
+  );\r
+\r
+//\r
+//The interface functions related to the Setup Browser Reset Reminder feature\r
+//\r
+/**\r
+  Enable the setup browser reset reminder feature.\r
+  This routine is used in a platform tip. If the platform policy needs the feature, use the routine to enable it.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+EnableResetReminderFeature (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Disable the setup browser reset reminder feature.\r
+  This routine is used in a platform tip. If the platform policy does not want the feature, use the routine to disable it.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+DisableResetReminderFeature (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Record the info that a reset is required.\r
+  A module boolean variable is used to record whether a reset is required.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+EnableResetRequired (\r
+  VOID\r
+  );\r
+\r
+\r
+/**\r
+  Record the info that no reset is required.\r
+  A module boolean variable is used to record whether a reset is required.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+DisableResetRequired (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Check whether platform policy enables the reset reminder feature. The default is enabled.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+IsResetReminderFeatureEnable (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Check if the user changed any option setting that needs a system reset to be effective.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+IsResetRequired (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Check whether a reset is needed, and finish the reset reminder feature.\r
+  If a reset is needed, pop up a menu to notice user, and finish the feature\r
+  according to the user selection.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+SetupResetReminder (\r
+  VOID\r
+  );\r
+\r
+\r
+///\r
+/// Define the boot type with which to classify the boot option type.\r
+/// Different boot option types could have different boot behaviors.\r
+/// Use their device path node (Type + SubType) as the type value.\r
+/// The boot type here can be added according to requirements.\r
+///\r
+\r
+///\r
+/// ACPI boot type. For ACPI devices, using sub-types to distinguish devices is not allowed, so hardcode their values.\r
+///\r
+#define  BDS_EFI_ACPI_FLOPPY_BOOT         0x0201\r
+///\r
+/// Message boot type\r
+/// If a device path of boot option only points to a message node, the boot option is a message boot type.\r
+///\r
+#define  BDS_EFI_MESSAGE_ATAPI_BOOT       0x0301 // Type 03; Sub-Type 01\r
+#define  BDS_EFI_MESSAGE_SCSI_BOOT        0x0302 // Type 03; Sub-Type 02\r
+#define  BDS_EFI_MESSAGE_USB_DEVICE_BOOT  0x0305 // Type 03; Sub-Type 05\r
+#define  BDS_EFI_MESSAGE_SATA_BOOT        0x0312 // Type 03; Sub-Type 18\r
+#define  BDS_EFI_MESSAGE_MAC_BOOT         0x030b // Type 03; Sub-Type 11\r
+#define  BDS_EFI_MESSAGE_MISC_BOOT        0x03FF\r
+\r
+///\r
+/// Media boot type\r
+/// If a device path of boot option contains a media node, the boot option is media boot type.\r
+///\r
+#define  BDS_EFI_MEDIA_HD_BOOT            0x0401 // Type 04; Sub-Type 01\r
+#define  BDS_EFI_MEDIA_CDROM_BOOT         0x0402 // Type 04; Sub-Type 02\r
+///\r
+/// BBS boot type\r
+/// If a device path of boot option contains a BBS node, the boot option is BBS boot type.\r
+///\r
+#define  BDS_LEGACY_BBS_BOOT              0x0501 //  Type 05; Sub-Type 01\r
+\r
+#define  BDS_EFI_UNSUPPORT                0xFFFF\r
+\r
+/**\r
+  Check whether an instance in BlockIoDevicePath has the same partition node as the HardDriveDevicePath device path.\r
+\r
+  @param  BlockIoDevicePath      Multi device path instances to check.\r
+  @param  HardDriveDevicePath    A device path starting with a hard drive media\r
+                                 device path.\r
+\r
+  @retval TRUE                   There is a matched device path instance.\r
+  @retval FALSE                  There is no matched device path instance.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+MatchPartitionDevicePathNode (\r
+  IN  EFI_DEVICE_PATH_PROTOCOL   *BlockIoDevicePath,\r
+  IN  HARDDRIVE_DEVICE_PATH      *HardDriveDevicePath\r
+  );\r
+\r
+\r
+/**\r
+  Expand a device path that starts with a hard drive media device path node to be a\r
+  full device path that includes the full hardware path to the device. This function enables the device to boot. \r
+  To avoid requiring a connect on every boot, the front match is saved in a variable (the part point\r
+  to the partition node. E.g. ACPI() /PCI()/ATA()/Partition() ).\r
+  All successful history device paths\r
+  that point to the front part of the partition node will be saved.\r
+\r
+  @param  HardDriveDevicePath    EFI Device Path to boot, if it starts with a hard\r
+                                 drive media device path.\r
+  @return A Pointer to the full device path, or NULL if a valid Hard Drive devic path\r
+          cannot be found.\r
+\r
+**/\r
+EFI_DEVICE_PATH_PROTOCOL *\r
+EFIAPI\r
+BdsExpandPartitionPartialDevicePathToFull (\r
+  IN  HARDDRIVE_DEVICE_PATH      *HardDriveDevicePath\r
+  );\r
+  \r
+/**\r
+  Return the bootable media handle.\r
+  First, check whether the device is connected.\r
+  Second, check whether the device path points to a device that supports SimpleFileSystemProtocol.\r
+  Third, detect the the default boot file in the Media, and return the removable Media handle.\r
+\r
+  @param  DevicePath             The Device Path to a  bootable device.\r
+\r
+  @return  The bootable media handle. If the media on the DevicePath is not bootable, NULL will return.\r
+\r
+**/\r
+EFI_HANDLE\r
+EFIAPI\r
+BdsLibGetBootableHandle (\r
+  IN  EFI_DEVICE_PATH_PROTOCOL      *DevicePath\r
+  );\r
+  \r
+\r
+/**\r
+  Checks whether the Device path in a boot option points to a valid bootable device, and if the device\r
+  is ready to boot now.\r
+\r
+  @param  DevPath     The Device path in a boot option.\r
+  @param  CheckMedia  If TRUE, check whether the device is ready to boot now.\r
+\r
+  @retval TRUE        The Device path is valid.\r
+  @retval FALSE       The Device path is invalid.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+BdsLibIsValidEFIBootOptDevicePath (\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *DevPath,\r
+  IN BOOLEAN                      CheckMedia\r
+  );\r
+\r
+/**\r
+  Checks whether the Device path in a boot option points to a valid bootable device, and if the device\r
+  is ready to boot now.\r
+  If Description is not NULL and the device path points to a fixed BlockIo\r
+  device, this function checks whether the description conflicts with other auto-created\r
+  boot options.\r
+\r
+  @param  DevPath     The Device path in a boot option.\r
+  @param  CheckMedia  If TRUE, checks if the device is ready to boot now.\r
+  @param  Description The description of a boot option.\r
+\r
+  @retval TRUE        The Device path is valid.\r
+  @retval FALSE       The Device path is invalid.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+BdsLibIsValidEFIBootOptDevicePathExt (\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *DevPath,\r
+  IN BOOLEAN                      CheckMedia,\r
+  IN CHAR16                       *Description\r
+  );\r
+\r
+/**\r
+  For a bootable Device path, return its boot type.\r
+\r
+  @param  DevicePath                      The bootable device Path to check.\r
+\r
+  @retval BDS_EFI_MEDIA_HD_BOOT           The given device path contains MEDIA_DEVICE_PATH type device path node,\r
+                                          whose subtype is MEDIA_HARDDRIVE_DP.  \r
+  @retval BDS_EFI_MEDIA_CDROM_BOOT        If given device path contains MEDIA_DEVICE_PATH type device path node, \r
+                                          whose subtype is MEDIA_CDROM_DP.  \r
+  @retval BDS_EFI_ACPI_FLOPPY_BOOT        A given device path contains ACPI_DEVICE_PATH type device path node,                                          \r
+                                          whose HID is floppy device.  \r
+  @retval BDS_EFI_MESSAGE_ATAPI_BOOT      A given device path contains MESSAGING_DEVICE_PATH type device path node, \r
+                                          and its last device path node's subtype is MSG_ATAPI_DP.  \r
+  @retval BDS_EFI_MESSAGE_SCSI_BOOT       A given device path contains MESSAGING_DEVICE_PATH type device path node,\r
+                                          and its last device path node's subtype is MSG_SCSI_DP. \r
+  @retval BDS_EFI_MESSAGE_USB_DEVICE_BOOT A given device path contains MESSAGING_DEVICE_PATH type device path node, \r
+                                          and its last device path node's subtype is MSG_USB_DP.\r
+  @retval BDS_EFI_MESSAGE_MISC_BOOT       The device path does not contain any media device path node, and  \r
+                                          its last device path node points to a message device path node.  \r
+  @retval BDS_LEGACY_BBS_BOOT             A given device path contains BBS_DEVICE_PATH type device path node. \r
+  @retval BDS_EFI_UNSUPPORT               An EFI Removable BlockIO device path does not point to a media and message device.   \r
+\r
+  **/\r
+UINT32\r
+EFIAPI\r
+BdsGetBootTypeFromDevicePath (\r
+  IN  EFI_DEVICE_PATH_PROTOCOL     *DevicePath\r
+  );\r
+\r
+\r
+/**\r
+  This routine registers a function to adjust the different types of memory page numbers\r
+  just before booting, and saves the updated info into the variable for the next boot to use.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+BdsLibSaveMemoryTypeInformation (\r
+  VOID\r
+  );\r
+  \r
+/**\r
+  Identify a user and, if authenticated, returns the current user profile handle.\r
+\r
+  @param[out]  User           Points to the user profile handle.\r
+  \r
+  @retval EFI_SUCCESS         The user is successfully identified, or user identification\r
+                              is not supported.\r
+  @retval EFI_ACCESS_DENIED   The user was not successfully identified.\r
+\r
+**/\r
+// EFI_STATUS\r
+// EFIAPI\r
+// BdsLibUserIdentify (\r
+//   OUT EFI_USER_PROFILE_HANDLE         *User\r
+//   );  \r
+\r
+/**\r
+  This function checks if a Fv file device path is valid, according to a file GUID. If it is invalid,\r
+  it tries to return the valid device path.\r
+  FV address maybe changes for memory layout adjust from time to time, use this funciton\r
+  could promise the Fv file device path is right.\r
+\r
+  @param  DevicePath             On input, the Fv file device path to check. On\r
+                                 output, the updated valid Fv file device path\r
+  @param  FileGuid               the Fv file GUID.\r
+\r
+  @retval EFI_INVALID_PARAMETER  The input DevicePath or FileGuid is invalid.\r
+  @retval EFI_UNSUPPORTED        The input DevicePath does not contain an Fv file\r
+                                 GUID at all.\r
+  @retval EFI_ALREADY_STARTED    The input DevicePath has pointed to the Fv file and is\r
+                                 valid.\r
+  @retval EFI_SUCCESS            Successfully updated the invalid DevicePath\r
+                                 and returned the updated device path in DevicePath.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BdsLibUpdateFvFileDevicePath (\r
+  IN  OUT EFI_DEVICE_PATH_PROTOCOL      ** DevicePath,\r
+  IN  EFI_GUID                          *FileGuid\r
+  );\r
+\r
+\r
+/**\r
+  Connect the specific USB device that matches the RemainingDevicePath,\r
+  and whose bus is determined by Host Controller (Uhci or Ehci).\r
+\r
+  @param  HostControllerPI      Uhci (0x00) or Ehci (0x20) or Both uhci and ehci\r
+                                (0xFF).\r
+  @param  RemainingDevicePath   A short-form device path that starts with the first\r
+                                element being a USB WWID or a USB Class device\r
+                                path.\r
+\r
+  @retval EFI_SUCCESS           The specific Usb device is connected successfully.\r
+  @retval EFI_INVALID_PARAMETER Invalid HostControllerPi (not 0x00, 0x20 or 0xFF) \r
+                                or RemainingDevicePath is not the USB class device path.\r
+  @retval EFI_NOT_FOUND         The device specified by device path is not found.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BdsLibConnectUsbDevByShortFormDP(\r
+  IN UINT8                      HostControllerPI,\r
+  IN EFI_DEVICE_PATH_PROTOCOL   *RemainingDevicePath\r
+  );\r
+  \r
+\r
+//\r
+// The implementation of this function is provided by Platform code.\r
+//\r
+/**\r
+  Convert Vendor device path to a device name.\r
+\r
+  @param  Str      The buffer storing device name.\r
+  @param  DevPath  The pointer to vendor device path.\r
+\r
+**/\r
+VOID\r
+DevPathVendor (\r
+  IN OUT POOL_PRINT       *Str,\r
+  IN VOID                 *DevPath\r
+  );\r
+\r
+/**\r
+  Concatenates a formatted unicode string to an allocated pool.\r
+  The caller must free the resulting buffer.\r
+\r
+  @param  Str      Tracks the allocated pool, size in use, and amount of pool allocated.\r
+  @param  Fmt      The format string.\r
+  @param  ...      The data will be printed.\r
+\r
+  @return Allocated buffer with the formatted string printed in it.\r
+          The caller must free the allocated buffer.\r
+          The buffer allocation is not packed.\r
+\r
+**/\r
+\r
+CHAR16 *\r
+EFIAPI\r
+CatPrint (\r
+  IN OUT POOL_PRINT   *Str,\r
+  IN CHAR16           *Fmt,\r
+  ...\r
+  );\r
+\r
+/**\r
+  Use SystemTable ConOut to stop video based Simple Text Out consoles from going\r
+  to the video device. Put up LogoFile on every video device that is a console.\r
+\r
+  @param[in]  LogoFile   The file name of logo to display on the center of the screen.\r
+\r
+  @retval EFI_SUCCESS     ConsoleControl has been flipped to graphics and logo displayed.\r
+  @retval EFI_UNSUPPORTED Logo not found.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EnableQuietBoot (\r
+  IN  EFI_GUID  *LogoFile\r
+  );\r
+\r
+\r
+/**\r
+  Use SystemTable ConOut to turn on video based Simple Text Out consoles. The \r
+  Simple Text Out screens will now be synced up with all non-video output devices.\r
+\r
+  @retval EFI_SUCCESS     UGA devices are back in text mode and synced up.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DisableQuietBoot (\r
+  VOID\r
+  );\r
+\r
+#endif\r
+\r
diff --git a/EfiLib/LegacyBios.h b/EfiLib/LegacyBios.h
new file mode 100644 (file)
index 0000000..88f5980
--- /dev/null
@@ -0,0 +1,1498 @@
+/** @file\r
+  The EFI Legacy BIOS Protocol is used to abstract legacy Option ROM usage\r
+  under EFI and Legacy OS boot.  This file also includes all the related\r
+  COMPATIBILIY16 structures and defintions.\r
+\r
+  Note: The names for EFI_IA32_REGISTER_SET elements were picked to follow\r
+  well known naming conventions.\r
+\r
+  Thunk is the code that switches from 32-bit protected environment into the 16-bit real-mode\r
+       environment. Reverse thunk is the code that does the opposite.\r
+\r
+Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials are licensed and made available under \r
+the terms and conditions of the BSD License that accompanies this distribution.  \r
+The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php.                                          \r
+    \r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+  @par Revision Reference:\r
+  This protocol is defined in Framework for EFI Compatibility Support Module spec\r
+  Version 0.97.\r
+\r
+**/\r
+\r
+#ifndef _EFI_LEGACY_BIOS_H_\r
+#define _EFI_LEGACY_BIOS_H_\r
+\r
+///\r
+/// \r
+///\r
+#pragma pack(1)\r
+\r
+typedef UINT8                       SERIAL_MODE;\r
+typedef UINT8                       PARALLEL_MODE;\r
+\r
+#define EFI_COMPATIBILITY16_TABLE_SIGNATURE SIGNATURE_32 ('I', 'F', 'E', '$')\r
+\r
+///\r
+/// There is a table located within the traditional BIOS in either the 0xF000:xxxx or 0xE000:xxxx\r
+/// physical address range. It is located on a 16-byte boundary and provides the physical address of the\r
+/// entry point for the Compatibility16 functions. These functions provide the platform-specific\r
+/// information that is required by the generic EfiCompatibility code. The functions are invoked via\r
+/// thunking by using EFI_LEGACY_BIOS_PROTOCOL.FarCall86() with the 32-bit physical\r
+/// entry point.\r
+///\r
+typedef struct {\r
+  ///\r
+  /// The string "$EFI" denotes the start of the EfiCompatibility table. Byte 0 is "I," byte\r
+  /// 1 is "F," byte 2 is "E," and byte 3 is "$" and is normally accessed as a DWORD or UINT32.\r
+  ///\r
+  UINT32                            Signature;\r
+  \r
+  ///\r
+  /// The value required such that byte checksum of TableLength equals zero.\r
+  ///\r
+  UINT8                             TableChecksum;\r
+  \r
+  ///\r
+  /// The length of this table.\r
+  ///\r
+  UINT8                             TableLength;\r
+  \r
+  ///\r
+  /// The major EFI revision for which this table was generated.\r
+  /// \r
+  UINT8                             EfiMajorRevision;\r
+  \r
+  ///\r
+  /// The minor EFI revision for which this table was generated.\r
+  ///\r
+  UINT8                             EfiMinorRevision;\r
+  \r
+  ///\r
+  /// The major revision of this table.\r
+  ///\r
+  UINT8                             TableMajorRevision;\r
+  \r
+  ///\r
+  /// The minor revision of this table.\r
+  ///\r
+  UINT8                             TableMinorRevision;\r
+  \r
+  ///\r
+  /// Reserved for future usage.\r
+  ///\r
+  UINT16                            Reserved;\r
+  \r
+  ///\r
+  /// The segment of the entry point within the traditional BIOS for Compatibility16 functions.\r
+  ///\r
+  UINT16                            Compatibility16CallSegment;\r
+  \r
+  ///\r
+  /// The offset of the entry point within the traditional BIOS for Compatibility16 functions.\r
+  ///\r
+  UINT16                            Compatibility16CallOffset;\r
+  \r
+  ///\r
+  /// The segment of the entry point within the traditional BIOS for EfiCompatibility \r
+  /// to invoke the PnP installation check.\r
+  ///\r
+  UINT16                            PnPInstallationCheckSegment;\r
+  \r
+  ///\r
+  /// The Offset of the entry point within the traditional BIOS for EfiCompatibility \r
+  /// to invoke the PnP installation check.\r
+  ///\r
+  UINT16                            PnPInstallationCheckOffset;\r
+  \r
+  ///\r
+  /// EFI system resources table. Type EFI_SYSTEM_TABLE is defined in the IntelPlatform \r
+  ///Innovation Framework for EFI Driver Execution Environment Core Interface Specification (DXE CIS).\r
+  ///\r
+  UINT32                            EfiSystemTable; \r
+  \r
+  ///\r
+  /// The address of an OEM-provided identifier string. The string is null terminated.\r
+  ///\r
+  UINT32                            OemIdStringPointer;\r
+  \r
+  ///\r
+  /// The 32-bit physical address where ACPI RSD PTR is stored within the traditional\r
+  /// BIOS. The remained of the ACPI tables are located at their EFI addresses. The size\r
+  /// reserved is the maximum for ACPI 2.0. The EfiCompatibility will fill in the ACPI\r
+  /// RSD PTR with either the ACPI 1.0b or 2.0 values.\r
+  ///\r
+  UINT32                            AcpiRsdPtrPointer;\r
+  \r
+  ///\r
+  /// The OEM revision number. Usage is undefined but provided for OEM module usage.\r
+  ///\r
+  UINT16                            OemRevision;\r
+  \r
+  ///\r
+  /// The 32-bit physical address where INT15 E820 data is stored within the traditional\r
+  /// BIOS. The EfiCompatibility code will fill in the E820Pointer value and copy the\r
+  /// data to the indicated area.\r
+  ///\r
+  UINT32                            E820Pointer;\r
+  \r
+  ///\r
+  /// The length of the E820 data and is filled in by the EfiCompatibility code.\r
+  ///\r
+  UINT32                            E820Length;\r
+  \r
+  ///\r
+  /// The 32-bit physical address where the $PIR table is stored in the traditional BIOS.\r
+  /// The EfiCompatibility code will fill in the IrqRoutingTablePointer value and\r
+  /// copy the data to the indicated area.\r
+  ///\r
+  UINT32                            IrqRoutingTablePointer;\r
+  \r
+  ///\r
+  /// The length of the $PIR table and is filled in by the EfiCompatibility code.\r
+  ///\r
+  UINT32                            IrqRoutingTableLength;\r
+  \r
+  ///\r
+  /// The 32-bit physical address where the MP table is stored in the traditional BIOS.\r
+  /// The EfiCompatibility code will fill in the MpTablePtr value and copy the data \r
+  /// to the indicated area.\r
+  ///\r
+  UINT32                            MpTablePtr;\r
+  \r
+  ///\r
+  /// The length of the MP table and is filled in by the EfiCompatibility code.\r
+  ///\r
+  UINT32                            MpTableLength;\r
+  \r
+  ///\r
+  /// The segment of the OEM-specific INT table/code.\r
+  /// \r
+  UINT16                            OemIntSegment;\r
+  \r
+  ///\r
+  /// The offset of the OEM-specific INT table/code.\r
+  ///\r
+  UINT16                            OemIntOffset;\r
+  \r
+  ///\r
+  /// The segment of the OEM-specific 32-bit table/code.\r
+  ///\r
+  UINT16                            Oem32Segment;\r
+  \r
+  ///\r
+  /// The offset of the OEM-specific 32-bit table/code.\r
+  ///\r
+  UINT16                            Oem32Offset;\r
+  \r
+  ///\r
+  /// The segment of the OEM-specific 16-bit table/code.\r
+  ///\r
+  UINT16                            Oem16Segment;\r
+  \r
+  ///\r
+  /// The offset of the OEM-specific 16-bit table/code.\r
+  ///\r
+  UINT16                            Oem16Offset;\r
+  \r
+  ///\r
+  /// The segment of the TPM binary passed to 16-bit CSM.\r
+  ///\r
+  UINT16                            TpmSegment;\r
+  \r
+  ///\r
+  /// The offset of the TPM binary passed to 16-bit CSM.\r
+  ///\r
+  UINT16                            TpmOffset;\r
+  \r
+  ///\r
+  /// A pointer to a string identifying the independent BIOS vendor.\r
+  ///\r
+  UINT32                            IbvPointer;\r
+  \r
+  ///\r
+  /// This field is NULL for all systems not supporting PCI Express. This field is the base\r
+  /// value of the start of the PCI Express memory-mapped configuration registers and\r
+  /// must be filled in prior to EfiCompatibility code issuing the Compatibility16 function\r
+  /// Compatibility16InitializeYourself().\r
+  /// Compatibility16InitializeYourself() is defined in Compatability16\r
+  /// Functions.\r
+  ///\r
+  UINT32                            PciExpressBase;\r
+  \r
+  ///\r
+  /// Maximum PCI bus number assigned.\r
+  ///\r
+  UINT8                             LastPciBus;\r
+} EFI_COMPATIBILITY16_TABLE;\r
+\r
+///\r
+/// Functions provided by the CSM binary which communicate between the EfiCompatibility \r
+/// and Compatability16 code.\r
+///\r
+/// Inconsistent with the specification here: \r
+/// The member's name started with "Compatibility16" [defined in Intel Framework \r
+/// Compatibility Support Module Specification / 0.97 version] \r
+/// has been changed to "Legacy16" since keeping backward compatible.\r
+///\r
+typedef enum {\r
+  ///\r
+  /// Causes the Compatibility16 code to do any internal initialization required.\r
+  /// Input:\r
+  ///   AX = Compatibility16InitializeYourself\r
+  ///   ES:BX = Pointer to EFI_TO_COMPATIBILITY16_INIT_TABLE\r
+  /// Return:\r
+  ///   AX = Return Status codes\r
+  ///\r
+  Legacy16InitializeYourself    = 0x0000,\r
+  \r
+  ///\r
+  /// Causes the Compatibility16 BIOS to perform any drive number translations to match the boot sequence.\r
+  /// Input:\r
+  ///   AX = Compatibility16UpdateBbs\r
+  ///   ES:BX = Pointer to EFI_TO_COMPATIBILITY16_BOOT_TABLE\r
+  /// Return:\r
+  ///   AX = Returned status codes\r
+  ///\r
+  Legacy16UpdateBbs             = 0x0001,\r
+  \r
+  ///\r
+  /// Allows the Compatibility16 code to perform any final actions before booting. The Compatibility16\r
+  /// code is read/write.\r
+  /// Input:\r
+  ///   AX = Compatibility16PrepareToBoot\r
+  ///   ES:BX = Pointer to EFI_TO_COMPATIBILITY16_BOOT_TABLE structure  \r
+  /// Return:\r
+  ///   AX = Returned status codes\r
+  ///\r
+  Legacy16PrepareToBoot         = 0x0002,\r
+  \r
+  ///\r
+  /// Causes the Compatibility16 BIOS to boot. The Compatibility16 code is Read/Only.\r
+  /// Input:\r
+  ///   AX = Compatibility16Boot\r
+  /// Output:\r
+  ///   AX = Returned status codes\r
+  ///\r
+  Legacy16Boot                  = 0x0003,\r
+  \r
+  ///\r
+  /// Allows the Compatibility16 code to get the last device from which a boot was attempted. This is\r
+  /// stored in CMOS and is the priority number of the last attempted boot device.\r
+  /// Input:\r
+  ///   AX = Compatibility16RetrieveLastBootDevice\r
+  /// Output:\r
+  ///   AX = Returned status codes\r
+  ///   BX = Priority number of the boot device.\r
+  ///\r
+  Legacy16RetrieveLastBootDevice = 0x0004,\r
+  \r
+  ///\r
+  /// Allows the Compatibility16 code rehook INT13, INT18, and/or INT19 after dispatching a legacy OpROM.\r
+  /// Input:\r
+  ///   AX = Compatibility16DispatchOprom\r
+  ///   ES:BX = Pointer to EFI_DISPATCH_OPROM_TABLE\r
+  /// Output:\r
+  ///   AX = Returned status codes\r
+  ///   BX = Number of non-BBS-compliant devices found. Equals 0 if BBS compliant.\r
+  ///\r
+  Legacy16DispatchOprom         = 0x0005,\r
+  \r
+  ///\r
+  /// Finds a free area in the 0xFxxxx or 0xExxxx region of the specified length and returns the address\r
+  /// of that region.\r
+  /// Input:\r
+  ///   AX = Compatibility16GetTableAddress\r
+  ///   BX = Allocation region\r
+  ///       00 = Allocate from either 0xE0000 or 0xF0000 64 KB blocks.\r
+  ///       Bit 0 = 1 Allocate from 0xF0000 64 KB block\r
+  ///       Bit 1 = 1 Allocate from 0xE0000 64 KB block\r
+  ///   CX = Requested length in bytes.\r
+  ///   DX = Required address alignment. Bit mapped. First non-zero bit from the right is the alignment.\r
+  /// Output:\r
+  ///   AX = Returned status codes\r
+  ///   DS:BX = Address of the region\r
+  ///\r
+  Legacy16GetTableAddress       = 0x0006,\r
+  \r
+  ///\r
+  /// Enables the EfiCompatibility module to do any nonstandard processing of keyboard LEDs or state.\r
+  /// Input:\r
+  ///   AX = Compatibility16SetKeyboardLeds\r
+  ///   CL = LED status.\r
+  ///     Bit 0  Scroll Lock 0 = Off\r
+  ///     Bit 1  NumLock\r
+  ///     Bit 2  Caps Lock\r
+  /// Output:\r
+  ///     AX = Returned status codes\r
+  ///\r
+  Legacy16SetKeyboardLeds       = 0x0007,\r
+  \r
+  ///\r
+  /// Enables the EfiCompatibility module to install an interrupt handler for PCI mass media devices that\r
+  /// do not have an OpROM associated with them. An example is SATA.\r
+  /// Input:\r
+  ///   AX = Compatibility16InstallPciHandler\r
+  ///   ES:BX = Pointer to EFI_LEGACY_INSTALL_PCI_HANDLER structure\r
+  /// Output:\r
+  ///   AX = Returned status codes\r
+  ///\r
+  Legacy16InstallPciHandler     = 0x0008\r
+} EFI_COMPATIBILITY_FUNCTIONS;\r
+\r
+\r
+///\r
+/// EFI_DISPATCH_OPROM_TABLE\r
+///\r
+typedef struct {\r
+  UINT16  PnPInstallationCheckSegment;  ///< A pointer to the PnpInstallationCheck data structure.\r
+  UINT16  PnPInstallationCheckOffset;   ///< A pointer to the PnpInstallationCheck data structure.\r
+  UINT16  OpromSegment;                 ///< The segment where the OpROM was placed. Offset is assumed to be 3.\r
+  UINT8   PciBus;                       ///< The PCI bus.\r
+  UINT8   PciDeviceFunction;            ///< The PCI device * 0x08 | PCI function.\r
+  UINT8   NumberBbsEntries;             ///< The number of valid BBS table entries upon entry and exit. The IBV code may\r
+                                        ///< increase this number, if BBS-compliant devices also hook INTs in order to force the\r
+                                        ///< OpROM BIOS Setup to be executed.\r
+  UINT32  BbsTablePointer;              ///< A pointer to the BBS table.\r
+  UINT16  RuntimeSegment;               ///< The segment where the OpROM can be relocated to. If this value is 0x0000, this\r
+                                        ///< means that the relocation of this run time code is not supported.\r
+                                        ///< Inconsistent with specification here: \r
+                                        ///< The member's name "OpromDestinationSegment" [defined in Intel Framework Compatibility Support Module Specification / 0.97 version] \r
+                                        ///< has been changed to "RuntimeSegment" since keeping backward compatible.\r
+\r
+} EFI_DISPATCH_OPROM_TABLE;\r
+\r
+///\r
+/// EFI_TO_COMPATIBILITY16_INIT_TABLE\r
+///\r
+typedef struct {\r
+  ///\r
+  /// Starting address of memory under 1 MB. The ending address is assumed to be 640 KB or 0x9FFFF.\r
+  ///\r
+  UINT32                            BiosLessThan1MB;\r
+  \r
+  ///\r
+  /// The starting address of the high memory block.\r
+  ///\r
+  UINT32                            HiPmmMemory;\r
+  \r
+  ///\r
+  /// The length of high memory block.\r
+  ///\r
+  UINT32                            HiPmmMemorySizeInBytes;\r
+  \r
+  ///\r
+  /// The segment of the reverse thunk call code.\r
+  ///\r
+  UINT16                            ReverseThunkCallSegment;\r
+  \r
+  ///\r
+  /// The offset of the reverse thunk call code.\r
+  ///\r
+  UINT16                            ReverseThunkCallOffset;\r
+  \r
+  ///\r
+  /// The number of E820 entries copied to the Compatibility16 BIOS.\r
+  ///\r
+  UINT32                            NumberE820Entries;\r
+  \r
+  ///\r
+  /// The amount of usable memory above 1 MB, e.g., E820 type 1 memory.\r
+  ///\r
+  UINT32                            OsMemoryAbove1Mb;\r
+  \r
+  ///\r
+  /// The start of thunk code in main memory. Memory cannot be used by BIOS or PMM.\r
+  ///\r
+  UINT32                            ThunkStart;\r
+  \r
+  ///\r
+  /// The size of the thunk code.\r
+  ///\r
+  UINT32                            ThunkSizeInBytes;\r
+  \r
+  ///\r
+  /// Starting address of memory under 1 MB.\r
+  ///\r
+  UINT32                            LowPmmMemory;\r
+  \r
+  ///\r
+  /// The length of low Memory block.\r
+  ///\r
+  UINT32                            LowPmmMemorySizeInBytes;\r
+} EFI_TO_COMPATIBILITY16_INIT_TABLE;\r
+\r
+///\r
+/// DEVICE_PRODUCER_SERIAL.\r
+///\r
+typedef struct {\r
+  UINT16                            Address;    ///< I/O address assigned to the serial port.\r
+  UINT8                             Irq;        ///< IRQ assigned to the serial port.\r
+  SERIAL_MODE                       Mode;       ///< Mode of serial port. Values are defined below.\r
+} DEVICE_PRODUCER_SERIAL;\r
+\r
+///\r
+/// DEVICE_PRODUCER_SERIAL's modes.\r
+///@{\r
+#define DEVICE_SERIAL_MODE_NORMAL               0x00\r
+#define DEVICE_SERIAL_MODE_IRDA                 0x01\r
+#define DEVICE_SERIAL_MODE_ASK_IR               0x02\r
+#define DEVICE_SERIAL_MODE_DUPLEX_HALF          0x00\r
+#define DEVICE_SERIAL_MODE_DUPLEX_FULL          0x10\r
+///@)\r
+\r
+///\r
+/// DEVICE_PRODUCER_PARALLEL.\r
+///\r
+typedef struct {\r
+  UINT16                            Address;  ///< I/O address assigned to the parallel port.\r
+  UINT8                             Irq;      ///< IRQ assigned to the parallel port.\r
+  UINT8                             Dma;      ///< DMA assigned to the parallel port.\r
+  PARALLEL_MODE                     Mode;     ///< Mode of the parallel port. Values are defined below.\r
+} DEVICE_PRODUCER_PARALLEL;\r
+\r
+///\r
+/// DEVICE_PRODUCER_PARALLEL's modes.\r
+///@{\r
+#define DEVICE_PARALLEL_MODE_MODE_OUTPUT_ONLY   0x00\r
+#define DEVICE_PARALLEL_MODE_MODE_BIDIRECTIONAL 0x01\r
+#define DEVICE_PARALLEL_MODE_MODE_EPP           0x02\r
+#define DEVICE_PARALLEL_MODE_MODE_ECP           0x03\r
+///@}\r
+\r
+///\r
+/// DEVICE_PRODUCER_FLOPPY\r
+///\r
+typedef struct {\r
+  UINT16                            Address;          ///< I/O address assigned to the floppy.\r
+  UINT8                             Irq;              ///< IRQ assigned to the floppy.\r
+  UINT8                             Dma;              ///< DMA assigned to the floppy.\r
+  UINT8                             NumberOfFloppy;   ///< Number of floppies in the system.\r
+} DEVICE_PRODUCER_FLOPPY;\r
+\r
+///\r
+/// LEGACY_DEVICE_FLAGS\r
+///\r
+typedef struct {\r
+  UINT32                            A20Kybd : 1;      ///< A20 controller by keyboard controller.\r
+  UINT32                            A20Port90 : 1;    ///< A20 controlled by port 0x92.\r
+  UINT32                            Reserved : 30;    ///< Reserved for future usage.\r
+} LEGACY_DEVICE_FLAGS;\r
+\r
+///\r
+/// DEVICE_PRODUCER_DATA_HEADER\r
+///\r
+typedef struct {\r
+  DEVICE_PRODUCER_SERIAL            Serial[4];      ///< Data for serial port x. Type DEVICE_PRODUCER_SERIAL is defined below.\r
+  DEVICE_PRODUCER_PARALLEL          Parallel[3];    ///< Data for parallel port x. Type DEVICE_PRODUCER_PARALLEL is defined below.\r
+  DEVICE_PRODUCER_FLOPPY            Floppy;         ///< Data for floppy. Type DEVICE_PRODUCER_FLOPPY is defined below.\r
+  UINT8                             MousePresent;   ///< Flag to indicate if mouse is present.\r
+  LEGACY_DEVICE_FLAGS               Flags;          ///< Miscellaneous Boolean state information passed to CSM.\r
+} DEVICE_PRODUCER_DATA_HEADER;\r
+\r
+///\r
+/// ATAPI_IDENTIFY\r
+///\r
+typedef struct {\r
+  UINT16                            Raw[256];     ///< Raw data from the IDE IdentifyDrive command.\r
+} ATAPI_IDENTIFY;\r
+\r
+///\r
+/// HDD_INFO\r
+///\r
+typedef struct {\r
+  ///\r
+  /// Status of IDE device. Values are defined below. There is one HDD_INFO structure\r
+  /// per IDE controller. The IdentifyDrive is per drive. Index 0 is master and index\r
+  /// 1 is slave.\r
+  ///\r
+  UINT16                            Status;   \r
+  \r
+  ///\r
+  /// PCI bus of IDE controller.\r
+  ///\r
+  UINT32                            Bus;\r
+  \r
+  ///\r
+  /// PCI device of IDE controller.\r
+  ///\r
+  UINT32                            Device;\r
+  \r
+  ///\r
+  /// PCI function of IDE controller.\r
+  ///\r
+  UINT32                            Function;\r
+  \r
+  ///\r
+  /// Command ports base address.\r
+  ///\r
+  UINT16                            CommandBaseAddress;\r
+  \r
+  ///\r
+  /// Control ports base address.\r
+  ///\r
+  UINT16                            ControlBaseAddress;\r
+  \r
+  ///\r
+  /// Bus master address.\r
+  ///\r
+  UINT16                            BusMasterAddress;\r
+  \r
+  UINT8                             HddIrq;\r
+  \r
+  ///\r
+  /// Data that identifies the drive data; one per possible attached drive.\r
+  ///\r
+  ATAPI_IDENTIFY                    IdentifyDrive[2];\r
+} HDD_INFO;\r
+\r
+///\r
+/// HDD_INFO status bits\r
+///\r
+#define HDD_PRIMARY               0x01\r
+#define HDD_SECONDARY             0x02\r
+#define HDD_MASTER_ATAPI_CDROM    0x04\r
+#define HDD_SLAVE_ATAPI_CDROM     0x08\r
+#define HDD_MASTER_IDE            0x20\r
+#define HDD_SLAVE_IDE             0x40\r
+#define HDD_MASTER_ATAPI_ZIPDISK  0x10\r
+#define HDD_SLAVE_ATAPI_ZIPDISK   0x80\r
+\r
+///\r
+/// BBS_STATUS_FLAGS;\.\r
+///\r
+typedef struct {\r
+  UINT16                            OldPosition : 4;    ///< Prior priority.\r
+  UINT16                            Reserved1 : 4;      ///< Reserved for future use.\r
+  UINT16                            Enabled : 1;        ///< If 0, ignore this entry.\r
+  UINT16                            Failed : 1;         ///< 0 = Not known if boot failure occurred.\r
+                                                        ///< 1 = Boot attempted failed.\r
+  \r
+  ///\r
+  /// State of media present.\r
+  ///   00 = No bootable media is present in the device.\r
+  ///   01 = Unknown if a bootable media present.\r
+  ///   10 = Media is present and appears bootable.\r
+  ///   11 = Reserved.\r
+  ///\r
+  UINT16                            MediaPresent : 2;\r
+  UINT16                            Reserved2 : 4;      ///< Reserved for future use.\r
+} BBS_STATUS_FLAGS;\r
+\r
+///\r
+/// BBS_TABLE, device type values & boot priority values.\r
+///\r
+typedef struct {\r
+  ///\r
+  /// The boot priority for this boot device. Values are defined below.\r
+  ///\r
+  UINT16                            BootPriority;\r
+  \r
+  ///\r
+  /// The PCI bus for this boot device.\r
+  ///\r
+  UINT32                            Bus;\r
+  \r
+  ///\r
+  /// The PCI device for this boot device.\r
+  ///\r
+  UINT32                            Device;\r
+  \r
+  ///\r
+  /// The PCI function for the boot device.\r
+  ///\r
+  UINT32                            Function;\r
+  \r
+  ///\r
+  /// The PCI class for this boot device.\r
+  ///\r
+  UINT8                             Class;\r
+  \r
+  ///\r
+  /// The PCI Subclass for this boot device.\r
+  ///\r
+  UINT8                             SubClass;\r
+  \r
+  ///\r
+  /// Segment:offset address of an ASCIIZ description string describing the manufacturer.\r
+  ///\r
+  UINT16                            MfgStringOffset;\r
+  \r
+  ///\r
+  /// Segment:offset address of an ASCIIZ description string describing the manufacturer.\r
+  ///  \r
+  UINT16                            MfgStringSegment;\r
+  \r
+  ///\r
+  /// BBS device type. BBS device types are defined below.\r
+  ///\r
+  UINT16                            DeviceType;\r
+  \r
+  ///\r
+  /// Status of this boot device. Type BBS_STATUS_FLAGS is defined below.\r
+  ///\r
+  BBS_STATUS_FLAGS                  StatusFlags;\r
+  \r
+  ///\r
+  /// Segment:Offset address of boot loader for IPL devices or install INT13 handler for\r
+  /// BCV devices.\r
+  ///\r
+  UINT16                            BootHandlerOffset;\r
+  \r
+  ///\r
+  /// Segment:Offset address of boot loader for IPL devices or install INT13 handler for\r
+  /// BCV devices.\r
+  ///  \r
+  UINT16                            BootHandlerSegment;\r
+  \r
+  ///\r
+  /// Segment:offset address of an ASCIIZ description string describing this device.\r
+  ///\r
+  UINT16                            DescStringOffset;\r
+\r
+  ///\r
+  /// Segment:offset address of an ASCIIZ description string describing this device.\r
+  ///\r
+  UINT16                            DescStringSegment;\r
+  \r
+  ///\r
+  /// Reserved.\r
+  ///\r
+  UINT32                            InitPerReserved;\r
+  \r
+  ///\r
+  /// The use of these fields is IBV dependent. They can be used to flag that an OpROM\r
+  /// has hooked the specified IRQ. The OpROM may be BBS compliant as some SCSI\r
+  /// BBS-compliant OpROMs also hook IRQ vectors in order to run their BIOS Setup\r
+  ///\r
+  UINT32                            AdditionalIrq13Handler;\r
+  \r
+  ///\r
+  /// The use of these fields is IBV dependent. They can be used to flag that an OpROM\r
+  /// has hooked the specified IRQ. The OpROM may be BBS compliant as some SCSI\r
+  /// BBS-compliant OpROMs also hook IRQ vectors in order to run their BIOS Setup\r
+  ///  \r
+  UINT32                            AdditionalIrq18Handler;\r
+  \r
+  ///\r
+  /// The use of these fields is IBV dependent. They can be used to flag that an OpROM\r
+  /// has hooked the specified IRQ. The OpROM may be BBS compliant as some SCSI\r
+  /// BBS-compliant OpROMs also hook IRQ vectors in order to run their BIOS Setup\r
+  ///  \r
+  UINT32                            AdditionalIrq19Handler;\r
+  \r
+  ///\r
+  /// The use of these fields is IBV dependent. They can be used to flag that an OpROM\r
+  /// has hooked the specified IRQ. The OpROM may be BBS compliant as some SCSI\r
+  /// BBS-compliant OpROMs also hook IRQ vectors in order to run their BIOS Setup\r
+  ///  \r
+  UINT32                            AdditionalIrq40Handler;\r
+  UINT8                             AssignedDriveNumber;\r
+  UINT32                            AdditionalIrq41Handler;\r
+  UINT32                            AdditionalIrq46Handler;\r
+  UINT32                            IBV1;\r
+  UINT32                            IBV2;\r
+} BBS_TABLE;\r
+\r
+///\r
+/// BBS device type values\r
+///@{\r
+#define BBS_FLOPPY              0x01\r
+#define BBS_HARDDISK            0x02\r
+#define BBS_CDROM               0x03\r
+#define BBS_PCMCIA              0x04\r
+#define BBS_USB                 0x05\r
+#define BBS_EMBED_NETWORK       0x06\r
+#define BBS_BEV_DEVICE          0x80\r
+#define BBS_UNKNOWN             0xff\r
+///@}\r
+\r
+///\r
+/// BBS boot priority values\r
+///@{\r
+#define BBS_DO_NOT_BOOT_FROM    0xFFFC\r
+#define BBS_LOWEST_PRIORITY     0xFFFD\r
+#define BBS_UNPRIORITIZED_ENTRY 0xFFFE\r
+#define BBS_IGNORE_ENTRY        0xFFFF\r
+///@}\r
+\r
+///\r
+/// SMM_ATTRIBUTES\r
+///\r
+typedef struct {\r
+  ///\r
+  /// Access mechanism used to generate the soft SMI. Defined types are below. The other\r
+  /// values are reserved for future usage.\r
+  ///\r
+  UINT16                            Type : 3;\r
+  \r
+  ///\r
+  /// The size of "port" in bits. Defined values are below.\r
+  ///\r
+  UINT16                            PortGranularity : 3;\r
+  \r
+  ///\r
+  /// The size of data in bits. Defined values are below.\r
+  ///\r
+  UINT16                            DataGranularity : 3;\r
+  \r
+  ///\r
+  /// Reserved for future use.\r
+  ///\r
+  UINT16                            Reserved : 7;\r
+} SMM_ATTRIBUTES;\r
+\r
+///\r
+/// SMM_ATTRIBUTES type values.\r
+///@{\r
+#define STANDARD_IO       0x00\r
+#define STANDARD_MEMORY   0x01\r
+///@}\r
+\r
+///\r
+/// SMM_ATTRIBUTES port size constants.\r
+///@{\r
+#define PORT_SIZE_8       0x00\r
+#define PORT_SIZE_16      0x01\r
+#define PORT_SIZE_32      0x02\r
+#define PORT_SIZE_64      0x03\r
+///@}\r
+\r
+///\r
+/// SMM_ATTRIBUTES data size constants.\r
+///@{\r
+#define DATA_SIZE_8       0x00\r
+#define DATA_SIZE_16      0x01\r
+#define DATA_SIZE_32      0x02\r
+#define DATA_SIZE_64      0x03\r
+///@}\r
+\r
+///\r
+/// SMM_FUNCTION & relating constants.\r
+///\r
+typedef struct {\r
+  UINT16                            Function : 15;\r
+  UINT16                            Owner : 1;\r
+} SMM_FUNCTION;\r
+\r
+///\r
+/// SMM_FUNCTION Function constants.\r
+///@{\r
+#define INT15_D042        0x0000\r
+#define GET_USB_BOOT_INFO 0x0001\r
+#define DMI_PNP_50_57     0x0002\r
+///@}\r
+\r
+///\r
+/// SMM_FUNCTION Owner constants.\r
+///@{\r
+#define STANDARD_OWNER    0x0\r
+#define OEM_OWNER         0x1\r
+///@}\r
+\r
+///\r
+/// This structure assumes both port and data sizes are 1. SmmAttribute must be\r
+/// properly to reflect that assumption.\r
+///\r
+typedef struct {\r
+  ///\r
+  /// Describes the access mechanism, SmmPort, and SmmData sizes. Type\r
+  /// SMM_ATTRIBUTES is defined below.\r
+  ///\r
+  SMM_ATTRIBUTES                    SmmAttributes;\r
+  \r
+  ///\r
+  /// Function Soft SMI is to perform. Type SMM_FUNCTION is defined below.\r
+  ///\r
+  SMM_FUNCTION                      SmmFunction;\r
+  \r
+  ///\r
+  /// SmmPort size depends upon SmmAttributes and ranges from2 bytes to 16 bytes.\r
+  ///\r
+  UINT8                             SmmPort;\r
+  \r
+  ///\r
+  /// SmmData size depends upon SmmAttributes and ranges from2 bytes to 16 bytes.\r
+  ///\r
+  UINT8                             SmmData;\r
+} SMM_ENTRY;\r
+\r
+///\r
+/// SMM_TABLE\r
+///\r
+typedef struct {\r
+  UINT16                            NumSmmEntries;    ///< Number of entries represented by SmmEntry.\r
+  SMM_ENTRY                         SmmEntry;         ///< One entry per function. Type SMM_ENTRY is defined below.\r
+} SMM_TABLE;\r
+\r
+///\r
+/// UDC_ATTRIBUTES\r
+///\r
+typedef struct {\r
+  ///\r
+  /// This bit set indicates that the ServiceAreaData is valid.\r
+  ///\r
+  UINT8                             DirectoryServiceValidity : 1;\r
+  \r
+  ///\r
+  /// This bit set indicates to use the Reserve Area Boot Code Address (RACBA) only if\r
+  /// DirectoryServiceValidity is 0.\r
+  ///\r
+  UINT8                             RabcaUsedFlag : 1;\r
+  \r
+  ///\r
+  /// This bit set indicates to execute hard disk diagnostics.\r
+  ///\r
+  UINT8                             ExecuteHddDiagnosticsFlag : 1;\r
+  \r
+  ///\r
+  /// Reserved for future use. Set to 0.\r
+  ///\r
+  UINT8                             Reserved : 5;\r
+} UDC_ATTRIBUTES;\r
+\r
+///\r
+/// UD_TABLE\r
+///\r
+typedef struct {\r
+  ///\r
+  /// This field contains the bit-mapped attributes of the PARTIES information. Type\r
+  /// UDC_ATTRIBUTES is defined below.\r
+  ///\r
+  UDC_ATTRIBUTES                    Attributes;\r
+  \r
+  ///\r
+  /// This field contains the zero-based device on which the selected\r
+  /// ServiceDataArea is present. It is 0 for master and 1 for the slave device.  \r
+  ///\r
+  UINT8                             DeviceNumber;\r
+  \r
+  ///\r
+  /// This field contains the zero-based index into the BbsTable for the parent device.\r
+  /// This index allows the user to reference the parent device information such as PCI\r
+  /// bus, device function.\r
+  ///\r
+  UINT8                             BbsTableEntryNumberForParentDevice;\r
+  \r
+  ///\r
+  /// This field contains the zero-based index into the BbsTable for the boot entry.\r
+  ///\r
+  UINT8                             BbsTableEntryNumberForBoot;\r
+  \r
+  ///\r
+  /// This field contains the zero-based index into the BbsTable for the HDD diagnostics entry.\r
+  ///\r
+  UINT8                             BbsTableEntryNumberForHddDiag;\r
+  \r
+  ///\r
+  /// The raw Beer data.\r
+  ///\r
+  UINT8                             BeerData[128];\r
+  \r
+  ///\r
+  /// The raw data of selected service area.\r
+  ///\r
+  UINT8                             ServiceAreaData[64];\r
+} UD_TABLE;\r
+\r
+#define EFI_TO_LEGACY_MAJOR_VERSION 0x02\r
+#define EFI_TO_LEGACY_MINOR_VERSION 0x00\r
+#define MAX_IDE_CONTROLLER          8\r
+\r
+///\r
+/// EFI_TO_COMPATIBILITY16_BOOT_TABLE\r
+///\r
+typedef struct {\r
+  UINT16                            MajorVersion;                 ///< The EfiCompatibility major version number.\r
+  UINT16                            MinorVersion;                 ///< The EfiCompatibility minor version number.\r
+  UINT32                            AcpiTable;                    ///< The location of the RSDT ACPI table. < 4G range.\r
+  UINT32                            SmbiosTable;                  ///< The location of the SMBIOS table in EFI memory. < 4G range.\r
+  UINT32                            SmbiosTableLength;\r
+  //\r
+  // Legacy SIO state\r
+  //\r
+  DEVICE_PRODUCER_DATA_HEADER       SioData;                      ///< Standard traditional device information.\r
+  UINT16                            DevicePathType;               ///< The default boot type.\r
+  UINT16                            PciIrqMask;                   ///< Mask of which IRQs have been assigned to PCI.\r
+  UINT32                            NumberE820Entries;            ///< Number of E820 entries. The number can change from the\r
+                                                                  ///< Compatibility16InitializeYourself() function.\r
+  //\r
+  // Controller & Drive Identify[2] per controller information\r
+  //\r
+  HDD_INFO                          HddInfo[MAX_IDE_CONTROLLER];  ///< Hard disk drive information, including raw Identify Drive data.\r
+  UINT32                            NumberBbsEntries;             ///< Number of entries in the BBS table\r
+  UINT32                            BbsTable;                     ///< A pointer to the BBS table. Type BBS_TABLE is defined below.\r
+  UINT32                            SmmTable;                     ///< A pointer to the SMM table. Type SMM_TABLE is defined below.\r
+  UINT32                            OsMemoryAbove1Mb;             ///< The amount of usable memory above 1 MB, i.e. E820 type 1 memory. This value can\r
+                                                                  ///< differ from the value in EFI_TO_COMPATIBILITY16_INIT_TABLE as more\r
+                                                                  ///< memory may have been discovered.\r
+  UINT32                            UnconventionalDeviceTable;    ///< Information to boot off an unconventional device like a PARTIES partition. Type\r
+                                                                  ///< UD_TABLE is defined below.\r
+} EFI_TO_COMPATIBILITY16_BOOT_TABLE;\r
+\r
+///\r
+/// EFI_LEGACY_INSTALL_PCI_HANDLER\r
+///\r
+typedef struct {\r
+  UINT8                             PciBus;             ///< The PCI bus of the device.\r
+  UINT8                             PciDeviceFun;       ///< The PCI device in bits 7:3 and function in bits 2:0.\r
+  UINT8                             PciSegment;         ///< The PCI segment of the device.\r
+  UINT8                             PciClass;           ///< The PCI class code of the device.\r
+  UINT8                             PciSubclass;        ///< The PCI subclass code of the device.\r
+  UINT8                             PciInterface;       ///< The PCI interface code of the device.\r
+  //\r
+  // Primary section\r
+  //\r
+  UINT8                             PrimaryIrq;         ///< The primary device IRQ.\r
+  UINT8                             PrimaryReserved;    ///< Reserved.\r
+  UINT16                            PrimaryControl;     ///< The primary device control I/O base.\r
+  UINT16                            PrimaryBase;        ///< The primary device I/O base.\r
+  UINT16                            PrimaryBusMaster;   ///< The primary device bus master I/O base.\r
+  //\r
+  // Secondary Section\r
+  //\r
+  UINT8                             SecondaryIrq;       ///< The secondary device IRQ.\r
+  UINT8                             SecondaryReserved;  ///< Reserved.\r
+  UINT16                            SecondaryControl;   ///< The secondary device control I/O base.\r
+  UINT16                            SecondaryBase;      ///< The secondary device I/O base.\r
+  UINT16                            SecondaryBusMaster; ///< The secondary device bus master I/O base.\r
+} EFI_LEGACY_INSTALL_PCI_HANDLER;\r
+\r
+//\r
+// Restore default pack value\r
+//\r
+#pragma pack()\r
+\r
+#define EFI_LEGACY_BIOS_PROTOCOL_GUID \\r
+  { \\r
+    0xdb9a1e3d, 0x45cb, 0x4abb, {0x85, 0x3b, 0xe5, 0x38, 0x7f, 0xdb, 0x2e, 0x2d } \\r
+  }\r
+\r
+typedef struct _EFI_LEGACY_BIOS_PROTOCOL EFI_LEGACY_BIOS_PROTOCOL;\r
+\r
+///\r
+/// Flags returned by CheckPciRom().\r
+///\r
+#define NO_ROM            0x00\r
+#define ROM_FOUND         0x01\r
+#define VALID_LEGACY_ROM  0x02\r
+#define ROM_WITH_CONFIG   0x04     ///< Not defined in the Framework CSM Specification.\r
+\r
+///\r
+/// The following macros do not appear in the Framework CSM Specification and \r
+/// are kept for backward compatibility only.  They convert 32-bit address (_Adr) \r
+/// to Segment:Offset 16-bit form.\r
+///\r
+///@{\r
+#define EFI_SEGMENT(_Adr)     (UINT16) ((UINT16) (((UINTN) (_Adr)) >> 4) & 0xf000)\r
+#define EFI_OFFSET(_Adr)      (UINT16) (((UINT16) ((UINTN) (_Adr))) & 0xffff)\r
+///@}\r
+\r
+#define CARRY_FLAG            0x01\r
+\r
+///\r
+/// EFI_EFLAGS_REG\r
+///\r
+typedef struct {\r
+  UINT32 CF:1;\r
+  UINT32 Reserved1:1;\r
+  UINT32 PF:1;\r
+  UINT32 Reserved2:1;\r
+  UINT32 AF:1;\r
+  UINT32 Reserved3:1;\r
+  UINT32 ZF:1;\r
+  UINT32 SF:1;\r
+  UINT32 TF:1;\r
+  UINT32 IF:1;\r
+  UINT32 DF:1;\r
+  UINT32 OF:1;\r
+  UINT32 IOPL:2;\r
+  UINT32 NT:1;\r
+  UINT32 Reserved4:2;\r
+  UINT32 VM:1;\r
+  UINT32 Reserved5:14;\r
+} EFI_EFLAGS_REG;\r
+\r
+///\r
+/// EFI_DWORD_REGS\r
+///\r
+typedef struct {\r
+    UINT32           EAX;\r
+    UINT32           EBX;\r
+    UINT32           ECX;\r
+    UINT32           EDX;\r
+    UINT32           ESI;\r
+    UINT32           EDI;\r
+    EFI_EFLAGS_REG   EFlags;\r
+    UINT16           ES;\r
+    UINT16           CS;\r
+    UINT16           SS;\r
+    UINT16           DS;\r
+    UINT16           FS;\r
+    UINT16           GS;\r
+    UINT32           EBP;\r
+    UINT32           ESP;\r
+} EFI_DWORD_REGS;\r
+\r
+///\r
+/// EFI_FLAGS_REG\r
+///\r
+typedef struct {\r
+  UINT16     CF:1;\r
+  UINT16     Reserved1:1;\r
+  UINT16     PF:1;\r
+  UINT16     Reserved2:1;\r
+  UINT16     AF:1;\r
+  UINT16     Reserved3:1;\r
+  UINT16     ZF:1;\r
+  UINT16     SF:1;\r
+  UINT16     TF:1;\r
+  UINT16     IF:1;\r
+  UINT16     DF:1;\r
+  UINT16     OF:1;\r
+  UINT16     IOPL:2;\r
+  UINT16     NT:1;\r
+  UINT16     Reserved4:1;\r
+} EFI_FLAGS_REG;\r
+\r
+///\r
+/// EFI_WORD_REGS\r
+///\r
+typedef struct {\r
+    UINT16           AX;\r
+    UINT16           ReservedAX;\r
+    UINT16           BX;\r
+    UINT16           ReservedBX;\r
+    UINT16           CX;\r
+    UINT16           ReservedCX;\r
+    UINT16           DX;\r
+    UINT16           ReservedDX;\r
+    UINT16           SI;\r
+    UINT16           ReservedSI;\r
+    UINT16           DI;\r
+    UINT16           ReservedDI;\r
+    EFI_FLAGS_REG    Flags;\r
+    UINT16           ReservedFlags;\r
+    UINT16           ES;\r
+    UINT16           CS;\r
+    UINT16           SS;\r
+    UINT16           DS;\r
+    UINT16           FS;\r
+    UINT16           GS;\r
+    UINT16           BP;\r
+    UINT16           ReservedBP;\r
+    UINT16           SP;\r
+    UINT16           ReservedSP;\r
+} EFI_WORD_REGS;\r
+\r
+///\r
+/// EFI_BYTE_REGS\r
+///\r
+typedef struct {\r
+    UINT8   AL, AH;\r
+    UINT16  ReservedAX;\r
+    UINT8   BL, BH;\r
+    UINT16  ReservedBX;\r
+    UINT8   CL, CH;\r
+    UINT16  ReservedCX;\r
+    UINT8   DL, DH;\r
+    UINT16  ReservedDX;\r
+} EFI_BYTE_REGS;\r
+\r
+///\r
+/// EFI_IA32_REGISTER_SET\r
+///\r
+typedef union {\r
+  EFI_DWORD_REGS  E;\r
+  EFI_WORD_REGS   X;\r
+  EFI_BYTE_REGS   H;\r
+} EFI_IA32_REGISTER_SET;\r
+\r
+/**\r
+  Thunk to 16-bit real mode and execute a software interrupt with a vector\r
+  of BiosInt. Regs will contain the 16-bit register context on entry and\r
+  exit.\r
+\r
+  @param[in]     This      The protocol instance pointer.\r
+  @param[in]     BiosInt   The processor interrupt vector to invoke.\r
+  @param[in,out] Reg       Register contexted passed into (and returned) from thunk to\r
+                           16-bit mode.\r
+\r
+  @retval TRUE                Thunk completed with no BIOS errors in the target code. See Regs for status.  \r
+  @retval FALSE                  There was a BIOS error in the target code.\r
+**/\r
+typedef\r
+BOOLEAN\r
+(EFIAPI *EFI_LEGACY_BIOS_INT86)(\r
+  IN     EFI_LEGACY_BIOS_PROTOCOL  *This,\r
+  IN     UINT8                     BiosInt,\r
+  IN OUT EFI_IA32_REGISTER_SET     *Regs\r
+  );\r
+\r
+/**\r
+  Thunk to 16-bit real mode and call Segment:Offset. Regs will contain the\r
+  16-bit register context on entry and exit. Arguments can be passed on\r
+  the Stack argument\r
+\r
+  @param[in] This        The protocol instance pointer.\r
+  @param[in] Segment     The segemnt of 16-bit mode call.\r
+  @param[in] Offset      The offset of 16-bit mdoe call.\r
+  @param[in] Reg         Register contexted passed into (and returned) from thunk to\r
+                         16-bit mode.\r
+  @param[in] Stack       The caller allocated stack used to pass arguments.\r
+  @param[in] StackSize   The size of Stack in bytes.\r
+\r
+  @retval FALSE                 Thunk completed with no BIOS errors in the target code.                                See Regs for status.  @retval TRUE                  There was a BIOS error in the target code.\r
+**/\r
+typedef\r
+BOOLEAN\r
+(EFIAPI *EFI_LEGACY_BIOS_FARCALL86)(\r
+  IN EFI_LEGACY_BIOS_PROTOCOL  *This,\r
+  IN UINT16                    Segment,\r
+  IN UINT16                    Offset,\r
+  IN EFI_IA32_REGISTER_SET     *Regs,\r
+  IN VOID                      *Stack,\r
+  IN UINTN                     StackSize\r
+  );\r
+\r
+/**\r
+  Test to see if a legacy PCI ROM exists for this device. Optionally return\r
+  the Legacy ROM instance for this PCI device.\r
+\r
+  @param[in]  This        The protocol instance pointer.\r
+  @param[in]  PciHandle   The PCI PC-AT OPROM from this devices ROM BAR will be loaded\r
+  @param[out] RomImage    Return the legacy PCI ROM for this device.\r
+  @param[out] RomSize     The size of ROM Image.\r
+  @param[out] Flags       Indicates if ROM found and if PC-AT. Multiple bits can be set as follows:\r
+                            - 00 = No ROM.\r
+                            - 01 = ROM Found.\r
+                            - 02 = ROM is a valid legacy ROM.\r
+\r
+  @retval EFI_SUCCESS       The Legacy Option ROM availible for this device\r
+  @retval EFI_UNSUPPORTED   The Legacy Option ROM is not supported.\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *EFI_LEGACY_BIOS_CHECK_ROM)(\r
+  IN  EFI_LEGACY_BIOS_PROTOCOL  *This,\r
+  IN  EFI_HANDLE                PciHandle,\r
+  OUT VOID                      **RomImage, OPTIONAL\r
+  OUT UINTN                     *RomSize, OPTIONAL\r
+  OUT UINTN                     *Flags\r
+  );\r
+\r
+/**\r
+  Load a legacy PC-AT OPROM on the PciHandle device. Return information\r
+  about how many disks were added by the OPROM and the shadow address and\r
+  size. DiskStart & DiskEnd are INT 13h drive letters. Thus 0x80 is C:\r
+\r
+  @param[in]  This               The protocol instance pointer.\r
+  @param[in]  PciHandle          The PCI PC-AT OPROM from this devices ROM BAR will be loaded.\r
+                                 This value is NULL if RomImage is non-NULL. This is the normal\r
+                                 case.\r
+  @param[in]  RomImage           A PCI PC-AT ROM image. This argument is non-NULL if there is\r
+                                 no hardware associated with the ROM and thus no PciHandle,\r
+                                 otherwise is must be NULL.\r
+                                 Example is PXE base code.\r
+  @param[out] Flags              The type of ROM discovered. Multiple bits can be set, as follows:\r
+                                   - 00 = No ROM.\r
+                                   - 01 = ROM found.\r
+                                   - 02 = ROM is a valid legacy ROM.\r
+  @param[out] DiskStart          The disk number of first device hooked by the ROM. If DiskStart\r
+                                 is the same as DiskEnd no disked were hooked.\r
+  @param[out] DiskEnd            disk number of the last device hooked by the ROM.\r
+  @param[out] RomShadowAddress   Shadow address of PC-AT ROM.\r
+  @param[out] RomShadowSize      Size of RomShadowAddress in bytes.\r
+\r
+  @retval EFI_SUCCESS             Thunk completed, see Regs for status.\r
+  @retval EFI_INVALID_PARAMETER   PciHandle not found\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *EFI_LEGACY_BIOS_INSTALL_ROM)(\r
+  IN  EFI_LEGACY_BIOS_PROTOCOL  *This,\r
+  IN  EFI_HANDLE                PciHandle,\r
+  IN  VOID                      **RomImage,\r
+  OUT UINTN                     *Flags,\r
+  OUT UINT8                     *DiskStart, OPTIONAL\r
+  OUT UINT8                     *DiskEnd, OPTIONAL\r
+  OUT VOID                      **RomShadowAddress, OPTIONAL\r
+  OUT UINT32                    *ShadowedRomSize OPTIONAL\r
+  );\r
+\r
+/**\r
+  This function attempts to traditionally boot the specified BootOption. If the EFI context has\r
+  been compromised, this function will not return. This procedure is not used for loading an EFI-aware\r
+  OS off a traditional device. The following actions occur:\r
+  - Get EFI SMBIOS data structures, convert them to a traditional format, and copy to\r
+    Compatibility16.\r
+  - Get a pointer to ACPI data structures and copy the Compatibility16 RSD PTR to F0000 block.\r
+  - Find the traditional SMI handler from a firmware volume and register the traditional SMI\r
+    handler with the EFI SMI handler.\r
+  - Build onboard IDE information and pass this information to the Compatibility16 code.\r
+  - Make sure all PCI Interrupt Line registers are programmed to match 8259.\r
+  - Reconfigure SIO devices from EFI mode (polled) into traditional mode (interrupt driven).\r
+  - Shadow all PCI ROMs.\r
+  - Set up BDA and EBDA standard areas before the legacy boot.\r
+  - Construct the Compatibility16 boot memory map and pass it to the Compatibility16 code.\r
+  - Invoke the Compatibility16 table function Compatibility16PrepareToBoot(). This\r
+    invocation causes a thunk into the Compatibility16 code, which sets all appropriate internal\r
+    data structures. The boot device list is a parameter.\r
+  - Invoke the Compatibility16 Table function Compatibility16Boot(). This invocation\r
+    causes a thunk into the Compatibility16 code, which does an INT19.\r
+  - If the Compatibility16Boot() function returns, then the boot failed in a graceful\r
+    manner--meaning that the EFI code is still valid. An ungraceful boot failure causes a reset because the state\r
+    of EFI code is unknown.\r
+\r
+  @param[in] This             The protocol instance pointer.\r
+  @param[in] BootOption       The EFI Device Path from BootXXXX variable.\r
+  @param[in] LoadOptionSize   The size of LoadOption in size.\r
+  @param[in] LoadOption       LThe oadOption from BootXXXX variable.\r
+\r
+  @retval EFI_DEVICE_ERROR      Failed to boot from any boot device and memory is uncorrupted.                                Note: This function normally does not returns. It will either boot the                                OS or reset the system if memory has been "corrupted" by loading                                a boot sector and passing control to it.\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *EFI_LEGACY_BIOS_BOOT)(\r
+  IN EFI_LEGACY_BIOS_PROTOCOL  *This,\r
+  IN BBS_BBS_DEVICE_PATH       *BootOption,\r
+  IN UINT32                    LoadOptionsSize,\r
+  IN VOID                      *LoadOptions\r
+  );\r
+\r
+/**\r
+  This function takes the Leds input parameter and sets/resets the BDA accordingly. \r
+  Leds is also passed to Compatibility16 code, in case any special processing is required. \r
+  This function is normally called from EFI Setup drivers that handle user-selectable\r
+  keyboard options such as boot with NUM LOCK on/off. This function does not\r
+  touch the keyboard or keyboard LEDs but only the BDA.\r
+\r
+  @param[in] This   The protocol instance pointer.\r
+  @param[in] Leds   The status of current Scroll, Num & Cap lock LEDS:\r
+                      - Bit 0 is Scroll Lock 0 = Not locked.\r
+                      - Bit 1 is Num Lock.\r
+                      - Bit 2 is Caps Lock.\r
+\r
+  @retval EFI_SUCCESS   The BDA was updated successfully.\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *EFI_LEGACY_BIOS_UPDATE_KEYBOARD_LED_STATUS)(\r
+  IN EFI_LEGACY_BIOS_PROTOCOL  *This,\r
+  IN UINT8                     Leds\r
+  );\r
+\r
+/**\r
+  Retrieve legacy BBS info and assign boot priority.\r
+\r
+  @param[in]     This       The protocol instance pointer.\r
+  @param[out]    HddCount   The number of HDD_INFO structures.\r
+  @param[out]    HddInfo    Onboard IDE controller information.\r
+  @param[out]    BbsCount   The number of BBS_TABLE structures.\r
+  @param[in,out] BbsTable   Points to List of BBS_TABLE.\r
+\r
+  @retval EFI_SUCCESS   Tables were returned.\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *EFI_LEGACY_BIOS_GET_BBS_INFO)(\r
+  IN     EFI_LEGACY_BIOS_PROTOCOL  *This,\r
+  OUT    UINT16                    *HddCount,\r
+  OUT    HDD_INFO                  **HddInfo,\r
+  OUT    UINT16                    *BbsCount,\r
+  IN OUT BBS_TABLE                 **BbsTable\r
+  );\r
+\r
+/**\r
+  Assign drive number to legacy HDD drives prior to booting an EFI\r
+  aware OS so the OS can access drives without an EFI driver.\r
+\r
+  @param[in]  This       The protocol instance pointer.\r
+  @param[out] BbsCount   The number of BBS_TABLE structures\r
+  @param[out] BbsTable   List of BBS entries\r
+\r
+  @retval EFI_SUCCESS   Drive numbers assigned.\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *EFI_LEGACY_BIOS_PREPARE_TO_BOOT_EFI)(\r
+  IN  EFI_LEGACY_BIOS_PROTOCOL  *This,\r
+  OUT UINT16                    *BbsCount,\r
+  OUT BBS_TABLE                 **BbsTable\r
+  );\r
+\r
+/**\r
+  To boot from an unconventional device like parties and/or execute\r
+  HDD diagnostics.\r
+\r
+  @param[in]  This              The protocol instance pointer.\r
+  @param[in]  Attributes        How to interpret the other input parameters.\r
+  @param[in]  BbsEntry          The 0-based index into the BbsTable for the parent\r
+                                device.\r
+  @param[in]  BeerData          A pointer to the 128 bytes of ram BEER data.\r
+  @param[in]  ServiceAreaData   A pointer to the 64 bytes of raw Service Area data. The\r
+                                caller must provide a pointer to the specific Service\r
+                                Area and not the start all Service Areas.\r
+\r
+  @retval EFI_INVALID_PARAMETER   If error. Does NOT return if no error.\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *EFI_LEGACY_BIOS_BOOT_UNCONVENTIONAL_DEVICE)(\r
+  IN EFI_LEGACY_BIOS_PROTOCOL  *This,\r
+  IN UDC_ATTRIBUTES            Attributes,\r
+  IN UINTN                     BbsEntry,\r
+  IN VOID                      *BeerData,\r
+  IN VOID                      *ServiceAreaData\r
+  );\r
+\r
+/**\r
+  Shadow all legacy16 OPROMs that haven't been shadowed.\r
+  Warning: Use this with caution. This routine disconnects all EFI\r
+  drivers. If used externally, then  the caller must re-connect EFI\r
+  drivers.\r
+  \r
+  @param[in]  This   The protocol instance pointer.\r
+  \r
+  @retval EFI_SUCCESS   OPROMs were shadowed.\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *EFI_LEGACY_BIOS_SHADOW_ALL_LEGACY_OPROMS)(\r
+  IN EFI_LEGACY_BIOS_PROTOCOL  *This\r
+  );\r
+\r
+/**\r
+  Get a region from the LegacyBios for S3 usage.\r
+\r
+  @param[in]  This                  The protocol instance pointer.\r
+  @param[in]  LegacyMemorySize      The size of required region.\r
+  @param[in]  Region                The region to use.\r
+                                    00 = Either 0xE0000 or 0xF0000 block.\r
+                                      - Bit0 = 1 0xF0000 block.\r
+                                      - Bit1 = 1 0xE0000 block.\r
+  @param[in]  Alignment             Address alignment. Bit mapped. The first non-zero\r
+                                    bit from right is alignment.\r
+  @param[out] LegacyMemoryAddress   The Region Assigned\r
+\r
+  @retval EFI_SUCCESS           The Region was assigned.\r
+  @retval EFI_ACCESS_DENIED     The function was previously invoked.\r
+  @retval Other                 The Region was not assigned.\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *EFI_LEGACY_BIOS_GET_LEGACY_REGION)(\r
+  IN  EFI_LEGACY_BIOS_PROTOCOL  *This,\r
+  IN  UINTN                     LegacyMemorySize,\r
+  IN  UINTN                     Region,\r
+  IN  UINTN                     Alignment,\r
+  OUT VOID                      **LegacyMemoryAddress\r
+  );\r
+\r
+/**\r
+  Get a region from the LegacyBios for Tiano usage. Can only be invoked once.\r
+\r
+  @param[in]  This                        The protocol instance pointer.\r
+  @param[in]  LegacyMemorySize            The size of data to copy.\r
+  @param[in]  LegacyMemoryAddress         The Legacy Region destination address.\r
+                                          Note: must be in region assigned by\r
+                                          LegacyBiosGetLegacyRegion.\r
+  @param[in]  LegacyMemorySourceAddress   The source of the data to copy.\r
+\r
+  @retval EFI_SUCCESS           The Region assigned.\r
+  @retval EFI_ACCESS_DENIED     Destination was outside an assigned region.\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *EFI_LEGACY_BIOS_COPY_LEGACY_REGION)(\r
+  IN EFI_LEGACY_BIOS_PROTOCOL  *This,\r
+  IN UINTN                     LegacyMemorySize,\r
+  IN VOID                      *LegacyMemoryAddress,\r
+  IN VOID                      *LegacyMemorySourceAddress\r
+  );\r
+\r
+///\r
+/// Abstracts the traditional BIOS from the rest of EFI. The LegacyBoot()\r
+/// member function allows the BDS to support booting a traditional OS.\r
+/// EFI thunks drivers that make EFI bindings for BIOS INT services use\r
+/// all the other member functions.\r
+///\r
+struct _EFI_LEGACY_BIOS_PROTOCOL {\r
+  ///\r
+  /// Performs traditional software INT. See the Int86() function description.\r
+  ///\r
+  EFI_LEGACY_BIOS_INT86                       Int86;\r
+  \r
+  ///\r
+  /// Performs a far call into Compatibility16 or traditional OpROM code.\r
+  ///\r
+  EFI_LEGACY_BIOS_FARCALL86                   FarCall86;\r
+  \r
+  ///\r
+  /// Checks if a traditional OpROM exists for this device.\r
+  ///\r
+  EFI_LEGACY_BIOS_CHECK_ROM                   CheckPciRom;\r
+  \r
+  ///\r
+  /// Loads a traditional OpROM in traditional OpROM address space.\r
+  ///\r
+  EFI_LEGACY_BIOS_INSTALL_ROM                 InstallPciRom;\r
+  \r
+  ///\r
+  /// Boots a traditional OS.\r
+  ///\r
+  EFI_LEGACY_BIOS_BOOT                        LegacyBoot;\r
+  \r
+  ///\r
+  /// Updates BDA to reflect the current EFI keyboard LED status.\r
+  ///\r
+  EFI_LEGACY_BIOS_UPDATE_KEYBOARD_LED_STATUS  UpdateKeyboardLedStatus;\r
+  \r
+  ///\r
+  /// Allows an external agent, such as BIOS Setup, to get the BBS data.\r
+  ///\r
+  EFI_LEGACY_BIOS_GET_BBS_INFO                GetBbsInfo;\r
+  \r
+  ///\r
+  /// Causes all legacy OpROMs to be shadowed.\r
+  ///\r
+  EFI_LEGACY_BIOS_SHADOW_ALL_LEGACY_OPROMS    ShadowAllLegacyOproms;\r
+  \r
+  ///\r
+  /// Performs all actions prior to boot. Used when booting an EFI-aware OS\r
+  /// rather than a legacy OS.  \r
+  ///\r
+  EFI_LEGACY_BIOS_PREPARE_TO_BOOT_EFI         PrepareToBootEfi;\r
+  \r
+  ///\r
+  /// Allows EFI to reserve an area in the 0xE0000 or 0xF0000 block.\r
+  ///\r
+  EFI_LEGACY_BIOS_GET_LEGACY_REGION           GetLegacyRegion;\r
+  \r
+  ///\r
+  /// Allows EFI to copy data to the area specified by GetLegacyRegion.\r
+  ///\r
+  EFI_LEGACY_BIOS_COPY_LEGACY_REGION          CopyLegacyRegion;\r
+  \r
+  ///\r
+  /// Allows the user to boot off an unconventional device such as a PARTIES partition.\r
+  ///\r
+  EFI_LEGACY_BIOS_BOOT_UNCONVENTIONAL_DEVICE  BootUnconventionalDevice;\r
+};\r
+\r
+extern EFI_GUID gEfiLegacyBiosProtocolGuid;\r
+\r
+#endif\r
diff --git a/EfiLib/Make.tiano b/EfiLib/Make.tiano
new file mode 100644 (file)
index 0000000..3be7522
--- /dev/null
@@ -0,0 +1,24 @@
+#
+# EfiLib/Make.tiano
+# Build control file for EfiLib components of rEFInd, using TianoCore EDK2
+#
+
+# This program is licensed under the terms of the GNU GPL, version 3,
+# or (at your option) any later version.
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+include ../Make.tiano
+
+SOURCE_NAMES     = legacy BmLib BdsConnect DevicePath BdsHelper BdsTianoCore
+OBJS             = $(SOURCE_NAMES:=.obj)
+#DRIVERNAME      = ext2
+#BUILDME          = $(DRIVERNAME)_$(FILENAME_CODE).efi
+
+all: $(AR_TARGET)
+
+$(AR_TARGET): $(OBJS)
+       $(AR) -cr $(AR_TARGET).lib $(OBJS)
+
+clean:
+       rm -f $(OBJS) *~ *.lib
diff --git a/EfiLib/Makefile b/EfiLib/Makefile
new file mode 100644 (file)
index 0000000..00e6f58
--- /dev/null
@@ -0,0 +1,24 @@
+#
+# EfiLib/Makefile
+#
+
+# This program is licensed under the terms of the GNU GPL, version 3,
+# or (at your option) any later version.
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+SRCDIR = .
+
+VPATH = $(SRCDIR)
+
+LOCAL_CPPFLAGS  = -I$(SRCDIR) -I$(SRCDIR)/../include
+
+OBJS            = gnuefi-helper.o legacy.o BdsHelper.o BdsTianoCore.o
+TARGET          = libEfiLib.a
+
+all: $(TARGET)
+
+include $(SRCDIR)/../Make.common
+
+clean:
+       rm -f *.o *.obj *~ *.lib *.a
diff --git a/EfiLib/Platform.h b/EfiLib/Platform.h
new file mode 100644 (file)
index 0000000..3924ac3
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+Headers collection for procedures
+*/
+/**
+
+Copyright (c) 2004 - 2008, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __REFIT_PLATFORM_H__
+#define __REFIT_PLATFORM_H__
+
+
+#include <Uefi.h>
+
+#include <Guid/Acpi.h>
+#include <Guid/EventGroup.h>
+#include <Guid/SmBios.h>
+#include <Guid/Mps.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/HiiLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PerformanceLib.h>
+#include <Library/PeCoffGetEntryPointLib.h>
+#include <Library/TimerLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiRuntimeLib.h>
+
+#include <Framework/FrameworkInternalFormRepresentation.h>
+
+#include <IndustryStandard/Acpi10.h>
+#include <IndustryStandard/Acpi20.h>
+
+#include <Protocol/Cpu.h>
+#include <Protocol/CpuIo.h>
+#include <Protocol/DataHub.h>
+#include <Protocol/DevicePathToText.h>
+#include <Protocol/FrameworkHii.h>
+#include <Protocol/Smbios.h>
+#include <Protocol/VariableWrite.h>
+#include <Protocol/Variable.h>
+
+#include "../include/Bmp.h"
+#include "efiConsoleControl.h"
+#include "EfiLib/GenericBdsLib.h"
+
+#include "../refind/global.h"
+
+#define EFI_HANDLE_TYPE_UNKNOWN                     0x000
+#define EFI_HANDLE_TYPE_IMAGE_HANDLE                0x001
+#define EFI_HANDLE_TYPE_DRIVER_BINDING_HANDLE       0x002
+#define EFI_HANDLE_TYPE_DEVICE_DRIVER               0x004
+#define EFI_HANDLE_TYPE_BUS_DRIVER                  0x008
+#define EFI_HANDLE_TYPE_DRIVER_CONFIGURATION_HANDLE 0x010
+#define EFI_HANDLE_TYPE_DRIVER_DIAGNOSTICS_HANDLE   0x020
+#define EFI_HANDLE_TYPE_COMPONENT_NAME_HANDLE       0x040
+#define EFI_HANDLE_TYPE_DEVICE_HANDLE               0x080
+#define EFI_HANDLE_TYPE_PARENT_HANDLE               0x100
+#define EFI_HANDLE_TYPE_CONTROLLER_HANDLE           0x200
+#define EFI_HANDLE_TYPE_CHILD_HANDLE                0x400
+
+EFI_STATUS  EFIAPI InitializeConsoleSim (VOID);
+
+#endif
diff --git a/EfiLib/gnuefi-helper.c b/EfiLib/gnuefi-helper.c
new file mode 100644 (file)
index 0000000..d4f269d
--- /dev/null
@@ -0,0 +1,315 @@
+/*
+ * EfiLib/gnuefi-helper.c
+ * GNU-EFI support functions
+ *
+ * Borrowed from the TianoCore EDK II, with modifications by Rod Smith
+ *
+ * Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>
+ * This program and the accompanying materials
+ * are licensed and made available under the terms and conditions of the BSD License
+ * which accompanies this distribution.  The full text of the license may be found at
+ * http://opensource.org/licenses/bsd-license.php
+ * 
+ * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ *
+ */
+
+#include "gnuefi-helper.h"
+#include "DevicePathUtilities.h"
+#include "refit_call_wrapper.h"
+#include "LegacyBios.h"
+
+EFI_GUID gEfiDevicePathUtilitiesProtocolGuid = { 0x09576E91, 0x6D3F, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
+EFI_GUID gEfiGlobalVariableGuid = { 0x8BE4DF61, 0x93CA, 0x11D2, { 0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C }};
+EFI_GUID gEfiLegacyBiosProtocolGuid = { 0xdb9a1e3d, 0x45cb, 0x4abb, { 0x85, 0x3b, 0xe5, 0x38, 0x7f, 0xdb, 0x2e, 0x2d }};
+
+/**
+  Convert a Null-terminated Unicode string to a Null-terminated 
+  ASCII string and returns the ASCII string.
+
+  This function converts the content of the Unicode string Source 
+  to the ASCII string Destination by copying the lower 8 bits of 
+  each Unicode character. It returns Destination. The function terminates 
+  the ASCII string Destination  by appending a Null-terminator character 
+  at the end. The caller is responsible to make sure Destination points 
+  to a buffer with size equal or greater than (StrLen (Source) + 1) in bytes.
+
+  If Destination is NULL, then ASSERT().
+  If Source is NULL, then ASSERT().
+  If Source is not aligned on a 16-bit boundary, then ASSERT().
+  If Source and Destination overlap, then ASSERT().
+
+  If any Unicode characters in Source contain non-zero value in 
+  the upper 8 bits, then ASSERT().
+
+  If PcdMaximumUnicodeStringLength is not zero, and Source contains 
+  more than PcdMaximumUnicodeStringLength Unicode characters not including 
+  the Null-terminator, then ASSERT().
+
+  If PcdMaximumAsciiStringLength is not zero, and Source contains more 
+  than PcdMaximumAsciiStringLength Unicode characters not including the 
+  Null-terminator, then ASSERT().
+
+  @param  Source        Pointer to a Null-terminated Unicode string.
+  @param  Destination   Pointer to a Null-terminated ASCII string.
+
+  @reture Destination
+
+**/
+CHAR8 *
+UnicodeStrToAsciiStr (
+  IN      CHAR16              *Source,
+  OUT     CHAR8               *Destination
+  )
+{
+  ASSERT (Destination != NULL);
+  ASSERT (Source != NULL);
+  ASSERT (((UINTN) Source & 0x01) == 0);
+
+  //
+  // Source and Destination should not overlap
+  //
+  ASSERT ((UINTN) ((CHAR16 *) Destination -  Source) > StrLen (Source));
+  ASSERT ((UINTN) ((CHAR8 *) Source - Destination) > StrLen (Source));
+
+//   //
+//   // If PcdMaximumUnicodeStringLength is not zero,
+//   // length of Source should not more than PcdMaximumUnicodeStringLength
+//   //
+//   if (PcdGet32 (PcdMaximumUnicodeStringLength) != 0) {
+//     ASSERT (StrLen (Source) < PcdGet32 (PcdMaximumUnicodeStringLength));
+//   }
+
+  while (*Source != '\0') {
+    //
+    // If any Unicode characters in Source contain 
+    // non-zero value in the upper 8 bits, then ASSERT().
+    //
+    ASSERT (*Source < 0x100);
+    *(Destination++) = (CHAR8) *(Source++);
+  }
+
+  *Destination = '\0';
+
+  return Destination;
+}
+
+/**
+  Returns the length of a Null-terminated ASCII string.
+
+  This function returns the number of ASCII characters in the Null-terminated
+  ASCII string specified by String.
+
+  If String is NULL, then ASSERT().
+  If PcdMaximumAsciiStringLength is not zero and String contains more than
+  PcdMaximumAsciiStringLength ASCII characters not including the Null-terminator,
+  then ASSERT().
+
+  @param  String  Pointer to a Null-terminated ASCII string.
+
+  @return The length of String.
+
+**/
+UINTN
+AsciiStrLen (
+  IN      CONST CHAR8               *String
+  )
+{
+  UINTN                             Length;
+
+  ASSERT (String != NULL);
+
+  for (Length = 0; *String != '\0'; String++, Length++) {
+//     //
+//     // If PcdMaximumUnicodeStringLength is not zero,
+//     // length should not more than PcdMaximumUnicodeStringLength
+//     //
+//     if (PcdGet32 (PcdMaximumAsciiStringLength) != 0) {
+//       ASSERT (Length < PcdGet32 (PcdMaximumAsciiStringLength));
+//     }
+  }
+  return Length;
+}
+
+/**
+  Determine whether a given device path is valid.
+  If DevicePath is NULL, then ASSERT().
+
+  @param  DevicePath  A pointer to a device path data structure.
+  @param  MaxSize     The maximum size of the device path data structure.
+
+  @retval TRUE        DevicePath is valid.
+  @retval FALSE       The length of any node node in the DevicePath is less
+                      than sizeof (EFI_DEVICE_PATH_PROTOCOL).
+  @retval FALSE       If MaxSize is not zero, the size of the DevicePath
+                      exceeds MaxSize.
+  @retval FALSE       If PcdMaximumDevicePathNodeCount is not zero, the node
+                      count of the DevicePath exceeds PcdMaximumDevicePathNodeCount.
+**/
+BOOLEAN
+EFIAPI
+IsDevicePathValid (
+  IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+  IN       UINTN                    MaxSize
+  )
+{
+  UINTN Count;
+  UINTN Size;
+  UINTN NodeLength;
+
+  ASSERT (DevicePath != NULL);
+
+  for (Count = 0, Size = 0; !IsDevicePathEnd (DevicePath); DevicePath = NextDevicePathNode (DevicePath)) {
+    NodeLength = DevicePathNodeLength (DevicePath);
+    if (NodeLength < sizeof (EFI_DEVICE_PATH_PROTOCOL)) {
+      return FALSE;
+    }
+
+    if (MaxSize > 0) {
+      Size += NodeLength;
+      if (Size + END_DEVICE_PATH_LENGTH > MaxSize) {
+        return FALSE;
+      }
+    }
+
+//     if (PcdGet32 (PcdMaximumDevicePathNodeCount) > 0) {
+//       Count++;
+//       if (Count >= PcdGet32 (PcdMaximumDevicePathNodeCount)) {
+//         return FALSE;
+//       }
+//     }
+  }
+
+  //
+  // Only return TRUE when the End Device Path node is valid.
+  //
+  return (BOOLEAN) (DevicePathNodeLength (DevicePath) == END_DEVICE_PATH_LENGTH);
+}
+
+/**
+  Returns the size of a device path in bytes.
+
+  This function returns the size, in bytes, of the device path data structure 
+  specified by DevicePath including the end of device path node.
+  If DevicePath is NULL or invalid, then 0 is returned.
+
+  @param  DevicePath  A pointer to a device path data structure.
+
+  @retval 0           If DevicePath is NULL or invalid.
+  @retval Others      The size of a device path in bytes.
+
+**/
+UINTN
+EFIAPI
+GetDevicePathSize (
+  IN CONST EFI_DEVICE_PATH_PROTOCOL  *DevicePath
+  )
+{
+  CONST EFI_DEVICE_PATH_PROTOCOL  *Start;
+
+  if (DevicePath == NULL) {
+    return 0;
+  }
+
+  if (!IsDevicePathValid (DevicePath, 0)) {
+    return 0;
+  }
+
+  //
+  // Search for the end of the device path structure
+  //
+  Start = DevicePath;
+  while (!IsDevicePathEnd (DevicePath)) {
+    DevicePath = NextDevicePathNode (DevicePath);
+  }
+
+  //
+  // Compute the size and add back in the size of the end device path structure
+  //
+  return ((UINTN) DevicePath - (UINTN) Start) + DevicePathNodeLength (DevicePath);
+}
+
+/**
+  Creates a copy of the current device path instance and returns a pointer to the next device path
+  instance.
+
+  This function creates a copy of the current device path instance. It also updates 
+  DevicePath to point to the next device path instance in the device path (or NULL 
+  if no more) and updates Size to hold the size of the device path instance copy.
+  If DevicePath is NULL, then NULL is returned.
+  If DevicePath points to a invalid device path, then NULL is returned.
+  If there is not enough memory to allocate space for the new device path, then 
+  NULL is returned.  
+  The memory is allocated from EFI boot services memory. It is the responsibility 
+  of the caller to free the memory allocated.
+  If Size is NULL, then ASSERT().
+  @param  DevicePath                 On input, this holds the pointer to the current 
+                                     device path instance. On output, this holds 
+                                     the pointer to the next device path instance 
+                                     or NULL if there are no more device path
+                                     instances in the device path pointer to a 
+                                     device path data structure.
+  @param  Size                       On output, this holds the size of the device 
+                                     path instance, in bytes or zero, if DevicePath 
+                                     is NULL.
+
+  @return A pointer to the current device path instance.
+
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+EFIAPI
+GetNextDevicePathInstance (
+  IN OUT EFI_DEVICE_PATH_PROTOCOL    **DevicePath,
+  OUT UINTN                          *Size
+  )
+{
+  EFI_DEVICE_PATH_PROTOCOL  *DevPath;
+  EFI_DEVICE_PATH_PROTOCOL  *ReturnValue;
+  UINT8                     Temp;
+
+  ASSERT (Size != NULL);
+
+  if (DevicePath == NULL || *DevicePath == NULL) {
+    *Size = 0;
+    return NULL;
+  }
+
+  if (!IsDevicePathValid (*DevicePath, 0)) {
+    return NULL;
+  }
+
+  //
+  // Find the end of the device path instance
+  //
+  DevPath = *DevicePath;
+  while (!IsDevicePathEndType (DevPath)) {
+    DevPath = NextDevicePathNode (DevPath);
+  }
+
+  //
+  // Compute the size of the device path instance
+  //
+  *Size = ((UINTN) DevPath - (UINTN) (*DevicePath)) + sizeof (EFI_DEVICE_PATH_PROTOCOL);
+  //
+  // Make a copy and return the device path instance
+  //
+  Temp              = DevPath->SubType;
+  DevPath->SubType  = END_ENTIRE_DEVICE_PATH_SUBTYPE;
+  ReturnValue       = DuplicateDevicePath (*DevicePath);
+  DevPath->SubType  = Temp;
+
+  //
+  // If DevPath is the end of an entire device path, then another instance
+  // does not follow, so *DevicePath is set to NULL.
+  //
+  if (DevicePathSubType (DevPath) == END_ENTIRE_DEVICE_PATH_SUBTYPE) {
+    *DevicePath = NULL;
+  } else {
+    *DevicePath = NextDevicePathNode (DevPath);
+  }
+
+  return ReturnValue;
+}
diff --git a/EfiLib/gnuefi-helper.h b/EfiLib/gnuefi-helper.h
new file mode 100644 (file)
index 0000000..694988a
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * EfiLib/gnuefi-helper.h
+ * Header file for GNU-EFI support in legacy boot code
+ *
+ * Borrowed from the TianoCore EDK II, with modifications by Rod Smith
+ *
+ * Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>
+ * This program and the accompanying materials
+ * are licensed and made available under the terms and conditions of the BSD License
+ * which accompanies this distribution.  The full text of the license may be found at
+ * http://opensource.org/licenses/bsd-license.php
+ * 
+ * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ *
+ */
+/*
+ * THIS FILE SHOULD NOT BE INCLUDED WHEN COMPILING UNDER TIANOCORE'S TOOLKIT!
+ */
+
+#ifndef __EFILIB_GNUEFI_H
+#define __EFILIB_GNUEFI_H
+
+#include "efi.h"
+#include "efilib.h"
+
+#define EFI_DEVICE_PATH_PROTOCOL EFI_DEVICE_PATH
+#define UnicodeSPrint SPrint
+#define gRT RT
+#define gBS BS
+#ifndef CONST
+#define CONST
+#endif
+#define ASSERT_EFI_ERROR(status)  ASSERT(!EFI_ERROR(status))
+
+CHAR8 *
+UnicodeStrToAsciiStr (
+   IN       CHAR16              *Source,
+   OUT      CHAR8               *Destination
+);
+
+UINTN
+AsciiStrLen (
+   IN      CONST CHAR8               *String
+);
+
+UINTN
+EFIAPI
+GetDevicePathSize (
+   IN CONST EFI_DEVICE_PATH_PROTOCOL  *DevicePath
+);
+
+EFI_DEVICE_PATH_PROTOCOL *
+EFIAPI
+GetNextDevicePathInstance (
+   IN OUT EFI_DEVICE_PATH_PROTOCOL    **DevicePath,
+   OUT UINTN                          *Size
+);
+
+#endif
diff --git a/EfiLib/legacy.c b/EfiLib/legacy.c
new file mode 100644 (file)
index 0000000..3e5edee
--- /dev/null
@@ -0,0 +1,1089 @@
+/*
+ * EfiLib/legacy.c
+ * CSM/legacy boot support functions
+ * 
+ * Taken from Tianocore source code (mostly IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/BBSsupport.c)
+ *
+ * Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>
+ * This program and the accompanying materials
+ * are licensed and made available under the terms and conditions of the BSD License
+ * which accompanies this distribution.  The full text of the license may be found at
+ * http://opensource.org/licenses/bsd-license.php
+ * 
+ * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ *
+ */
+
+#ifdef __MAKEWITH_GNUEFI
+#include "efi.h"
+#include "efilib.h"
+#include "gnuefi-helper.h"
+#define EFI_DEVICE_PATH_PROTOCOL EFI_DEVICE_PATH
+#define EfiReallocatePool ReallocatePool
+#define EfiLibLocateProtocol LibLocateProtocol
+#else
+#include "../include/tiano_includes.h"
+#endif
+#include "legacy.h"
+#include "GenericBdsLib.h"
+#include "../refind/global.h"
+#include "../include/refit_call_wrapper.h"
+
+BOOT_OPTION_BBS_MAPPING  *mBootOptionBbsMapping     = NULL;
+UINTN                    mBootOptionBbsMappingCount = 0;
+
+extern EFI_DEVICE_PATH EndDevicePath[];
+extern EFI_GUID gEfiLegacyBiosProtocolGuid;
+EFI_GUID gEfiLegacyDevOrderVariableGuid     = { 0xa56074db, 0x65fe, 0x45f7, {0xbd, 0x21, 0x2d, 0x2b, 0xdd, 0x8e, 0x96, 0x52 }};
+
+/**
+
+  Translate the first n characters of an Ascii string to
+  Unicode characters. The count n is indicated by parameter
+  Size. If Size is greater than the length of string, then
+  the entire string is translated.
+
+
+  @param AStr               Pointer to input Ascii string.
+  @param Size               The number of characters to translate.
+  @param UStr               Pointer to output Unicode string buffer.
+
+**/
+VOID
+AsciiToUnicodeSize (
+  IN UINT8              *AStr,
+  IN UINTN              Size,
+  OUT UINT16            *UStr
+  )
+{
+  UINTN Idx;
+
+  Idx = 0;
+  while (AStr[Idx] != 0) {
+    UStr[Idx] = (CHAR16) AStr[Idx];
+    if (Idx == Size) {
+      break;
+    }
+
+    Idx++;
+  }
+  UStr[Idx] = 0;
+}
+
+/**
+  Build Legacy Device Name String according.
+
+  @param CurBBSEntry     BBS Table.
+  @param Index           Index.
+  @param BufSize         The buffer size.
+  @param BootString      The output string.
+
+**/
+VOID
+BdsBuildLegacyDevNameString (
+  IN  BBS_TABLE                 *CurBBSEntry,
+  IN  UINTN                     Index,
+  IN  UINTN                     BufSize,
+  OUT CHAR16                    *BootString
+  )
+{
+  CHAR16  *Fmt;
+  CHAR16  *Type;
+  UINT8   *StringDesc;
+  CHAR16  Temp[80];
+
+  switch (Index) {
+  //
+  // Primary Master
+  //
+  case 1:
+    Fmt = L"Primary Master %s";
+    break;
+
+ //
+ // Primary Slave
+ //
+  case 2:
+    Fmt = L"Primary Slave %s";
+    break;
+
+  //
+  // Secondary Master
+  //
+  case 3:
+    Fmt = L"Secondary Master %s";
+    break;
+
+  //
+  // Secondary Slave
+  //
+  case 4:
+    Fmt = L"Secondary Slave %s";
+    break;
+
+  default:
+    Fmt = L"%s";
+    break;
+  }
+
+  switch (CurBBSEntry->DeviceType) {
+  case BBS_FLOPPY:
+    Type = L"Floppy";
+    break;
+
+  case BBS_HARDDISK:
+    Type = L"Harddisk";
+    break;
+
+  case BBS_CDROM:
+    Type = L"CDROM";
+    break;
+
+  case BBS_PCMCIA:
+    Type = L"PCMCIAe";
+    break;
+
+  case BBS_USB:
+    Type = L"USB";
+    break;
+
+  case BBS_EMBED_NETWORK:
+    Type = L"Network";
+    break;
+
+  case BBS_BEV_DEVICE:
+    Type = L"BEVe";
+    break;
+
+  case BBS_UNKNOWN:
+  default:
+    Type = L"Unknown";
+    break;
+  }
+  //
+  // If current BBS entry has its description then use it.
+  //
+  StringDesc = (UINT8 *) (UINTN) ((CurBBSEntry->DescStringSegment << 4) + CurBBSEntry->DescStringOffset);
+  if (NULL != StringDesc) {
+    //
+    // Only get fisrt 32 characters, this is suggested by BBS spec
+    //
+    AsciiToUnicodeSize (StringDesc, 32, Temp);
+    Fmt   = L"%s";
+    Type  = Temp;
+  }
+
+  //
+  // BbsTable 16 entries are for onboard IDE.
+  // Set description string for SATA harddisks, Harddisk 0 ~ Harddisk 11
+  //
+  if (Index >= 5 && Index <= 16 && (CurBBSEntry->DeviceType == BBS_HARDDISK || CurBBSEntry->DeviceType == BBS_CDROM)) {
+    Fmt = L"%s %d";
+    UnicodeSPrint (BootString, BufSize, Fmt, Type, Index - 5);
+  } else {
+    UnicodeSPrint (BootString, BufSize, Fmt, Type);
+  }
+}
+
+/**
+  Check if the boot option is a legacy one.
+
+  @param BootOptionVar   The boot option data payload.
+  @param BbsEntry        The BBS Table.
+  @param BbsIndex        The table index.
+
+  @retval TRUE           It is a legacy boot option.
+  @retval FALSE          It is not a legacy boot option.
+
+**/
+BOOLEAN
+BdsIsLegacyBootOption (
+  IN UINT8                 *BootOptionVar,
+  OUT BBS_TABLE            **BbsEntry,
+  OUT UINT16               *BbsIndex
+  )
+{
+  UINT8                     *Ptr;
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
+  BOOLEAN                   Ret;
+  UINT16                    DevPathLen;
+
+  Ptr = BootOptionVar;
+  Ptr += sizeof (UINT32);
+  DevPathLen = *(UINT16 *) Ptr;
+  Ptr += sizeof (UINT16);
+  Ptr += StrSize ((UINT16 *) Ptr);
+  DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr;
+  if ((BBS_DEVICE_PATH == DevicePath->Type) && (BBS_BBS_DP == DevicePath->SubType)) {
+    Ptr += DevPathLen;
+    *BbsEntry = (BBS_TABLE *) Ptr;
+    Ptr += sizeof (BBS_TABLE);
+    *BbsIndex = *(UINT16 *) Ptr;
+    Ret       = TRUE;
+  } else {
+    *BbsEntry = NULL;
+    Ret       = FALSE;
+  }
+
+  return Ret;
+}
+
+/**
+  Find all legacy boot option by device type.
+
+  @param BootOrder       The boot order array.
+  @param BootOptionNum   The number of boot option.
+  @param DevType         Device type.
+  @param DevName         Device name.
+  @param Attribute       The boot option attribute.
+  @param BbsIndex        The BBS table index.
+  @param OptionNumber    The boot option index.
+
+  @retval TRUE           The Legacy boot option is found.
+  @retval FALSE          The legacy boot option is not found.
+
+**/
+BOOLEAN
+BdsFindLegacyBootOptionByDevTypeAndName (
+  IN UINT16                 *BootOrder,
+  IN UINTN                  BootOptionNum,
+  IN UINT16                 DevType,
+  IN CHAR16                 *DevName,
+  OUT UINT32                *Attribute,
+  OUT UINT16                *BbsIndex,
+  OUT UINT16                *OptionNumber
+  )
+{
+  UINTN     Index;
+  CHAR16    BootOption[10];
+  UINTN     BootOptionSize;
+  UINT8     *BootOptionVar;
+  BBS_TABLE *BbsEntry;
+  BOOLEAN   Found;
+
+  BbsEntry  = NULL;
+  Found     = FALSE;
+
+  if (NULL == BootOrder) {
+    return Found;
+  }
+
+  //
+  // Loop all boot option from variable
+  //
+  for (Index = 0; Index < BootOptionNum; Index++) {
+    UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", (UINTN) BootOrder[Index]);
+    BootOptionVar = BdsLibGetVariableAndSize (
+                      BootOption,
+                      &gEfiGlobalVariableGuid,
+                      &BootOptionSize
+                      );
+    if (NULL == BootOptionVar) {
+       continue;
+    }
+
+    //
+    // Skip Non-legacy boot option
+    //
+    if (!BdsIsLegacyBootOption (BootOptionVar, &BbsEntry, BbsIndex)) {
+      FreePool (BootOptionVar);
+      continue;
+    }
+
+    if (
+        (BbsEntry->DeviceType != DevType) ||
+        (StrCmp (DevName, (CHAR16*)(BootOptionVar + sizeof (UINT32) + sizeof (UINT16))) != 0)
+       ) {
+      FreePool (BootOptionVar);
+      continue;
+    }
+
+    *Attribute    = *(UINT32 *) BootOptionVar;
+    *OptionNumber = BootOrder[Index];
+    Found         = TRUE;
+    FreePool (BootOptionVar);
+    break;
+  }
+
+  return Found;
+}
+
+/**
+
+  Create a legacy boot option for the specified entry of
+  BBS table, save it as variable, and append it to the boot
+  order list.
+
+
+  @param CurrentBbsEntry    Pointer to current BBS table.
+  @param CurrentBbsDevPath  Pointer to the Device Path Protocol instance of BBS
+  @param Index              Index of the specified entry in BBS table.
+  @param BootOrderList      On input, the original boot order list.
+                            On output, the new boot order list attached with the
+                            created node.
+  @param BootOrderListSize  On input, the original size of boot order list.
+                            On output, the size of new boot order list.
+
+  @retval  EFI_SUCCESS             Boot Option successfully created.
+  @retval  EFI_OUT_OF_RESOURCES    Fail to allocate necessary memory.
+  @retval  Other                   Error occurs while setting variable.
+
+**/
+EFI_STATUS
+BdsCreateLegacyBootOption (
+  IN BBS_TABLE                        *CurrentBbsEntry,
+  IN EFI_DEVICE_PATH_PROTOCOL         *CurrentBbsDevPath,
+  IN UINTN                            Index,
+  IN OUT UINT16                       **BootOrderList,
+  IN OUT UINTN                        *BootOrderListSize
+  )
+{
+  EFI_STATUS           Status;
+  UINT16               CurrentBootOptionNo;
+  UINT16               BootString[10];
+  CHAR16               BootDesc[100];
+  CHAR8                HelpString[100];
+  UINT16               *NewBootOrderList;
+  UINTN                BufferSize;
+  UINTN                StringLen;
+  VOID                 *Buffer;
+  UINT8                *Ptr;
+  UINT16               CurrentBbsDevPathSize;
+  UINTN                BootOrderIndex;
+  UINTN                BootOrderLastIndex;
+  UINTN                ArrayIndex;
+  BOOLEAN              IndexNotFound;
+  BBS_BBS_DEVICE_PATH  *NewBbsDevPathNode;
+
+  if ((*BootOrderList) == NULL) {
+    CurrentBootOptionNo = 0;
+  } else {
+    for (ArrayIndex = 0; ArrayIndex < (UINTN) (*BootOrderListSize / sizeof (UINT16)); ArrayIndex++) {
+      IndexNotFound = TRUE;
+      for (BootOrderIndex = 0; BootOrderIndex < (UINTN) (*BootOrderListSize / sizeof (UINT16)); BootOrderIndex++) {
+        if ((*BootOrderList)[BootOrderIndex] == ArrayIndex) {
+          IndexNotFound = FALSE;
+          break;
+        }
+      }
+
+      if (!IndexNotFound) {
+        continue;
+      } else {
+        break;
+      }
+    }
+
+    CurrentBootOptionNo = (UINT16) ArrayIndex;
+  }
+
+  UnicodeSPrint (
+    BootString,
+    sizeof (BootString),
+    L"Boot%04x",
+    CurrentBootOptionNo
+    );
+
+  BdsBuildLegacyDevNameString (CurrentBbsEntry, Index, sizeof (BootDesc), BootDesc);
+
+  //
+  // Create new BBS device path node with description string
+  //
+  UnicodeStrToAsciiStr (BootDesc, HelpString);
+
+  StringLen = AsciiStrLen (HelpString);
+  NewBbsDevPathNode = AllocateZeroPool (sizeof (BBS_BBS_DEVICE_PATH) + StringLen);
+  if (NewBbsDevPathNode == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+  CopyMem (NewBbsDevPathNode, CurrentBbsDevPath, sizeof (BBS_BBS_DEVICE_PATH));
+  CopyMem (NewBbsDevPathNode->String, HelpString, StringLen + 1);
+  SetDevicePathNodeLength (&(NewBbsDevPathNode->Header), sizeof (BBS_BBS_DEVICE_PATH) + StringLen);
+
+  //
+  // Create entire new CurrentBbsDevPath with end node
+  //
+  CurrentBbsDevPath = AppendDevicePathNode (
+                        EndDevicePath,
+                        (EFI_DEVICE_PATH_PROTOCOL *) NewBbsDevPathNode
+                        );
+   if (CurrentBbsDevPath == NULL) {
+    FreePool (NewBbsDevPathNode);
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  CurrentBbsDevPathSize = (UINT16) (GetDevicePathSize (CurrentBbsDevPath));
+
+  BufferSize = sizeof (UINT32) +
+    sizeof (UINT16) +
+    StrSize (BootDesc) +
+    CurrentBbsDevPathSize +
+    sizeof (BBS_TABLE) +
+    sizeof (UINT16);
+
+  Buffer = AllocateZeroPool (BufferSize);
+  if (Buffer == NULL) {
+    FreePool (NewBbsDevPathNode);
+    FreePool (CurrentBbsDevPath);
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  Ptr               = (UINT8 *) Buffer;
+
+  *((UINT32 *) Ptr) = LOAD_OPTION_ACTIVE;
+  Ptr += sizeof (UINT32);
+
+  *((UINT16 *) Ptr) = CurrentBbsDevPathSize;
+  Ptr += sizeof (UINT16);
+
+  CopyMem (
+    Ptr,
+    BootDesc,
+    StrSize (BootDesc)
+    );
+  Ptr += StrSize (BootDesc);
+
+  CopyMem (
+    Ptr,
+    CurrentBbsDevPath,
+    CurrentBbsDevPathSize
+    );
+  Ptr += CurrentBbsDevPathSize;
+
+  CopyMem (
+    Ptr,
+    CurrentBbsEntry,
+    sizeof (BBS_TABLE)
+    );
+
+  Ptr += sizeof (BBS_TABLE);
+  *((UINT16 *) Ptr) = (UINT16) Index;
+
+  Status = refit_call5_wrapper(gRT->SetVariable,
+                  BootString,
+                  &gEfiGlobalVariableGuid,
+                  VAR_FLAG,
+                  BufferSize,
+                  Buffer
+                  );
+
+  FreePool (Buffer);
+  
+  Buffer = NULL;
+
+  NewBootOrderList = AllocateZeroPool (*BootOrderListSize + sizeof (UINT16));
+  if (NULL == NewBootOrderList) {
+    FreePool (NewBbsDevPathNode);
+    FreePool (CurrentBbsDevPath);
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  if (*BootOrderList != NULL) {
+    CopyMem (NewBootOrderList, *BootOrderList, *BootOrderListSize);
+    FreePool (*BootOrderList);
+  }
+
+  BootOrderLastIndex                    = (UINTN) (*BootOrderListSize / sizeof (UINT16));
+  NewBootOrderList[BootOrderLastIndex]  = CurrentBootOptionNo;
+  *BootOrderListSize += sizeof (UINT16);
+  *BootOrderList = NewBootOrderList;
+
+  FreePool (NewBbsDevPathNode);
+  FreePool (CurrentBbsDevPath);
+  return Status;
+}
+
+/**
+  Create a legacy boot option.
+
+  @param BbsItem         The BBS Table entry.
+  @param Index           Index of the specified entry in BBS table.
+  @param BootOrderList   The boot order list.
+  @param BootOrderListSize The size of boot order list.
+
+  @retval EFI_OUT_OF_RESOURCE  No enough memory.
+  @retval EFI_SUCCESS          The function complete successfully.
+  @return Other value if the legacy boot option is not created.
+
+**/
+EFI_STATUS
+BdsCreateOneLegacyBootOption (
+  IN BBS_TABLE              *BbsItem,
+  IN UINTN                  Index,
+  IN OUT UINT16             **BootOrderList,
+  IN OUT UINTN              *BootOrderListSize
+  )
+{
+  BBS_BBS_DEVICE_PATH       BbsDevPathNode;
+  EFI_STATUS                Status;
+  EFI_DEVICE_PATH_PROTOCOL  *DevPath;
+
+  DevPath                       = NULL;
+
+  //
+  // Create device path node.
+  //
+  BbsDevPathNode.Header.Type    = BBS_DEVICE_PATH;
+  BbsDevPathNode.Header.SubType = BBS_BBS_DP;
+  SetDevicePathNodeLength (&BbsDevPathNode.Header, sizeof (BBS_BBS_DEVICE_PATH));
+  BbsDevPathNode.DeviceType = BbsItem->DeviceType;
+  CopyMem (&BbsDevPathNode.StatusFlag, &BbsItem->StatusFlags, sizeof (UINT16));
+
+  DevPath = AppendDevicePathNode (
+              EndDevicePath,
+              (EFI_DEVICE_PATH_PROTOCOL *) &BbsDevPathNode
+              );
+  if (NULL == DevPath) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  Status = BdsCreateLegacyBootOption (
+            BbsItem,
+            DevPath,
+            Index,
+            BootOrderList,
+            BootOrderListSize
+            );
+  BbsItem->BootPriority = 0x00;
+
+  FreePool (DevPath);
+
+  return Status;
+}
+
+/**
+  Group the legacy boot options in the BootOption.
+
+  The routine assumes the boot options in the beginning that covers all the device 
+  types are ordered properly and re-position the following boot options just after
+  the corresponding boot options with the same device type.
+  For example:
+  1. Input  = [Harddisk1 CdRom2 Efi1 Harddisk0 CdRom0 CdRom1 Harddisk2 Efi0]
+     Assuming [Harddisk1 CdRom2 Efi1] is ordered properly
+     Output = [Harddisk1 Harddisk0 Harddisk2 CdRom2 CdRom0 CdRom1 Efi1 Efi0]
+
+  2. Input  = [Efi1 Efi0 CdRom1 Harddisk0 Harddisk1 Harddisk2 CdRom0 CdRom2]
+     Assuming [Efi1 Efi0 CdRom1 Harddisk0] is ordered properly
+     Output = [Efi1 Efi0 CdRom1 CdRom0 CdRom2 Harddisk0 Harddisk1 Harddisk2]
+
+  @param BootOption      Pointer to buffer containing Boot Option Numbers
+  @param BootOptionCount Count of the Boot Option Numbers
+**/
+VOID
+GroupMultipleLegacyBootOption4SameType (
+  UINT16                   *BootOption,
+  UINTN                    BootOptionCount
+  )
+{
+  UINTN                    DeviceTypeIndex[7];
+  UINTN                    Index;
+  UINTN                    MappingIndex;
+  UINTN                    *NextIndex;
+  UINT16                   OptionNumber;
+  UINTN                    DeviceIndex;
+
+  SetMem (DeviceTypeIndex, sizeof (DeviceTypeIndex), 0xFF);
+
+  for (Index = 0; Index < BootOptionCount; Index++) {
+
+    //
+    // Find the DeviceType
+    //
+    for (MappingIndex = 0; MappingIndex < mBootOptionBbsMappingCount; MappingIndex++) {
+      if (mBootOptionBbsMapping[MappingIndex].BootOptionNumber == BootOption[Index]) {
+        break;
+      }
+    }
+    if (MappingIndex == mBootOptionBbsMappingCount) {
+      //
+      // Is not a legacy boot option
+      //
+      continue;
+    }
+
+    ASSERT ((mBootOptionBbsMapping[MappingIndex].BbsType & 0xF) < 
+             sizeof (DeviceTypeIndex) / sizeof (DeviceTypeIndex[0]));
+    NextIndex = &DeviceTypeIndex[mBootOptionBbsMapping[MappingIndex].BbsType & 0xF];
+    if (*NextIndex == (UINTN) -1) {
+      //
+      // *NextIndex is the index in BootOption to put the next Option Number for the same type
+      //
+      *NextIndex = Index + 1;
+    } else {
+      //
+      // insert the current boot option before *NextIndex, causing [*Next .. Index] shift right one position
+      //
+      OptionNumber = BootOption[Index];
+      CopyMem (&BootOption[*NextIndex + 1], &BootOption[*NextIndex], (Index - *NextIndex) * sizeof (UINT16));
+      BootOption[*NextIndex] = OptionNumber;
+
+      //
+      // Update the DeviceTypeIndex array to reflect the right shift operation
+      //
+      for (DeviceIndex = 0; DeviceIndex < sizeof (DeviceTypeIndex) / sizeof (DeviceTypeIndex[0]); DeviceIndex++) {
+        if (DeviceTypeIndex[DeviceIndex] != (UINTN) -1 && DeviceTypeIndex[DeviceIndex] >= *NextIndex) {
+          DeviceTypeIndex[DeviceIndex]++;
+        }
+      }
+    }
+  }
+}
+
+/**
+  Function returns the value of the specified variable.
+
+
+  @param Name            A Null-terminated Unicode string that is
+                         the name of the vendor's variable.
+  @param VendorGuid      A unique identifier for the vendor.
+
+  @return               The payload of the variable.
+  @retval NULL          If the variable can't be read.
+
+**/
+VOID *
+EfiLibGetVariable (
+  IN CHAR16               *Name,
+  IN EFI_GUID             *VendorGuid
+  )
+{
+  UINTN VarSize;
+
+  return BdsLibGetVariableAndSize (Name, VendorGuid, &VarSize);
+}
+
+/**
+  Function deletes the variable specified by VarName and VarGuid.
+
+  @param VarName           A Null-terminated Unicode string that is
+                           the name of the vendor's variable.
+
+  @param VarGuid           A unique identifier for the vendor.
+
+  @retval  EFI_SUCCESS           The variable was found and removed
+  @retval  EFI_UNSUPPORTED       The variable store was inaccessible
+  @retval  EFI_OUT_OF_RESOURCES  The temporary buffer was not available
+  @retval  EFI_NOT_FOUND         The variable was not found
+
+**/
+EFI_STATUS
+EfiLibDeleteVariable (
+  IN CHAR16   *VarName,
+  IN EFI_GUID *VarGuid
+  )
+{
+  VOID        *VarBuf;
+  EFI_STATUS  Status;
+
+  VarBuf  = EfiLibGetVariable (VarName, VarGuid);
+  Status  = EFI_NOT_FOUND;
+
+  if (VarBuf != NULL) {
+    //
+    // Delete variable from Storage
+    //
+    Status = refit_call5_wrapper(gRT->SetVariable, VarName, VarGuid, VAR_FLAG, 0, NULL);
+    ASSERT (!EFI_ERROR (Status));
+    FreePool (VarBuf);
+  }
+
+  return Status;
+}
+
+/**
+  Add the legacy boot options from BBS table if they do not exist.
+
+  @retval EFI_SUCCESS          The boot options are added successfully 
+                               or they are already in boot options.
+  @retval EFI_NOT_FOUND        No legacy boot options is found.
+  @retval EFI_OUT_OF_RESOURCE  No enough memory.
+  @return Other value          LegacyBoot options are not added.
+**/
+EFI_STATUS
+BdsAddNonExistingLegacyBootOptions (
+  VOID
+  )
+{
+  UINT16                    *BootOrder;
+  UINTN                     BootOrderSize;
+  EFI_STATUS                Status;
+  CHAR16                    Desc[100];
+  UINT16                    HddCount;
+  UINT16                    BbsCount;
+  HDD_INFO                  *LocalHddInfo;
+  BBS_TABLE                 *LocalBbsTable;
+  UINT16                    BbsIndex;
+  EFI_LEGACY_BIOS_PROTOCOL  *LegacyBios;
+  UINT16                    Index;
+  UINT32                    Attribute;
+  UINT16                    OptionNumber;
+  BOOLEAN                   Exist;
+
+  HddCount      = 0;
+  BbsCount      = 0;
+  LocalHddInfo  = NULL;
+  LocalBbsTable = NULL;
+
+  Status        = EfiLibLocateProtocol (&gEfiLegacyBiosProtocolGuid, (VOID **) &LegacyBios);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  if (mBootOptionBbsMapping != NULL) {
+    FreePool (mBootOptionBbsMapping);
+
+    mBootOptionBbsMapping      = NULL;
+    mBootOptionBbsMappingCount = 0;
+  }
+
+  refit_call5_wrapper(LegacyBios->GetBbsInfo,
+                LegacyBios,
+                &HddCount,
+                &LocalHddInfo,
+                &BbsCount,
+                &LocalBbsTable
+                );
+
+  BootOrder = BdsLibGetVariableAndSize (
+                L"BootOrder",
+                &gEfiGlobalVariableGuid,
+                &BootOrderSize
+                );
+  if (BootOrder == NULL) {
+    BootOrderSize = 0;
+  }
+
+  for (Index = 0; Index < BbsCount; Index++) {
+    if ((LocalBbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) ||
+        (LocalBbsTable[Index].BootPriority == BBS_DO_NOT_BOOT_FROM)
+        ) {
+      continue;
+    }
+
+    BdsBuildLegacyDevNameString (&LocalBbsTable[Index], Index, sizeof (Desc), Desc);
+
+    Exist = BdsFindLegacyBootOptionByDevTypeAndName (
+              BootOrder,
+              BootOrderSize / sizeof (UINT16),
+              LocalBbsTable[Index].DeviceType,
+              Desc,
+              &Attribute,
+              &BbsIndex,
+              &OptionNumber
+              );
+    if (!Exist) {
+      //
+      // Not found such type of legacy device in boot options or we found but it's disabled
+      // so we have to create one and put it to the tail of boot order list
+      //
+      Status = BdsCreateOneLegacyBootOption (
+                &LocalBbsTable[Index],
+                Index,
+                &BootOrder,
+                &BootOrderSize
+                );
+      if (EFI_ERROR (Status)) {
+        break;
+      }
+      BbsIndex     = Index;
+      OptionNumber = BootOrder[BootOrderSize / sizeof (UINT16) - 1];
+    }
+
+    ASSERT (BbsIndex == Index);
+    //
+    // Save the BbsIndex
+    //
+    mBootOptionBbsMapping = EfiReallocatePool (
+                              mBootOptionBbsMapping,
+                              mBootOptionBbsMappingCount * sizeof (BOOT_OPTION_BBS_MAPPING),
+                              (mBootOptionBbsMappingCount + 1) * sizeof (BOOT_OPTION_BBS_MAPPING)
+                              );
+    ASSERT (mBootOptionBbsMapping != NULL);
+    mBootOptionBbsMapping[mBootOptionBbsMappingCount].BootOptionNumber = OptionNumber;
+    mBootOptionBbsMapping[mBootOptionBbsMappingCount].BbsIndex         = Index;
+    mBootOptionBbsMapping[mBootOptionBbsMappingCount].BbsType          = LocalBbsTable[Index].DeviceType;
+    mBootOptionBbsMappingCount ++;
+  }
+
+  //
+  // Group the Boot Option Number in BootOrder for the same type devices
+  //
+  GroupMultipleLegacyBootOption4SameType (
+    BootOrder,
+    BootOrderSize / sizeof (UINT16)
+    );
+
+  if (BootOrderSize > 0) {
+    Status = refit_call5_wrapper(gRT->SetVariable,
+                    L"BootOrder",
+                    &gEfiGlobalVariableGuid,
+                    VAR_FLAG,
+                    BootOrderSize,
+                    BootOrder
+                    );
+  } else {
+    EfiLibDeleteVariable (L"BootOrder", &gEfiGlobalVariableGuid);
+  }
+
+  if (BootOrder != NULL) {
+    FreePool (BootOrder);
+  }
+
+  return Status;
+}
+
+/**
+  Deletete the Boot Option from EFI Variable. The Boot Order Arrray
+  is also updated.
+
+  @param OptionNumber    The number of Boot option want to be deleted.
+  @param BootOrder       The Boot Order array.
+  @param BootOrderSize   The size of the Boot Order Array.
+
+  @retval  EFI_SUCCESS           The Boot Option Variable was found and removed
+  @retval  EFI_UNSUPPORTED       The Boot Option Variable store was inaccessible
+  @retval  EFI_NOT_FOUND         The Boot Option Variable was not found
+**/
+EFI_STATUS
+BdsDeleteBootOption (
+  IN UINTN                       OptionNumber,
+  IN OUT UINT16                  *BootOrder,
+  IN OUT UINTN                   *BootOrderSize
+  )
+{
+  UINT16      BootOption[100];
+  UINTN       Index;
+  EFI_STATUS  Status;
+  UINTN       Index2Del;
+
+  Status    = EFI_SUCCESS;
+  Index2Del = 0;
+
+  UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", OptionNumber);
+  Status = EfiLibDeleteVariable (BootOption, &gEfiGlobalVariableGuid);
+
+  //
+  // adjust boot order array
+  //
+  for (Index = 0; Index < *BootOrderSize / sizeof (UINT16); Index++) {
+    if (BootOrder[Index] == OptionNumber) {
+      Index2Del = Index;
+      break;
+    }
+  }
+
+  if (Index != *BootOrderSize / sizeof (UINT16)) {
+    for (Index = 0; Index < *BootOrderSize / sizeof (UINT16) - 1; Index++) {
+      if (Index >= Index2Del) {
+        BootOrder[Index] = BootOrder[Index + 1];
+      }
+    }
+
+    *BootOrderSize -= sizeof (UINT16);
+  }
+
+  return Status;
+
+}
+
+/**
+  Delete all the invalid legacy boot options.
+
+  @retval EFI_SUCCESS             All invalide legacy boot options are deleted.
+  @retval EFI_OUT_OF_RESOURCES    Fail to allocate necessary memory.
+  @retval EFI_NOT_FOUND           Fail to retrive variable of boot order.
+**/
+EFI_STATUS
+BdsDeleteAllInvalidLegacyBootOptions (
+  VOID
+  )
+{
+  UINT16                    *BootOrder;
+  UINT8                     *BootOptionVar;
+  UINTN                     BootOrderSize;
+  UINTN                     BootOptionSize;
+  EFI_STATUS                Status;
+  UINT16                    HddCount;
+  UINT16                    BbsCount;
+  HDD_INFO                  *LocalHddInfo;
+  BBS_TABLE                 *LocalBbsTable;
+  BBS_TABLE                 *BbsEntry;
+  UINT16                    BbsIndex;
+  EFI_LEGACY_BIOS_PROTOCOL  *LegacyBios;
+  UINTN                     Index;
+  UINT16                    BootOption[10];
+  UINT16                    BootDesc[100];
+  BOOLEAN                   DescStringMatch;
+
+  Status        = EFI_SUCCESS;
+  BootOrder     = NULL;
+  BootOrderSize = 0;
+  HddCount      = 0;
+  BbsCount      = 0;
+  LocalHddInfo  = NULL;
+  LocalBbsTable = NULL;
+  BbsEntry      = NULL;
+
+  Status        = EfiLibLocateProtocol (&gEfiLegacyBiosProtocolGuid, (VOID **) &LegacyBios);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  refit_call5_wrapper(LegacyBios->GetBbsInfo,
+                LegacyBios,
+                &HddCount,
+                &LocalHddInfo,
+                &BbsCount,
+                &LocalBbsTable
+                );
+
+  BootOrder = BdsLibGetVariableAndSize (
+                L"BootOrder",
+                &gEfiGlobalVariableGuid,
+                &BootOrderSize
+                );
+  if (BootOrder == NULL) {
+    BootOrderSize = 0;
+  }
+
+  Index = 0;
+  while (Index < BootOrderSize / sizeof (UINT16)) {
+    UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);
+    BootOptionVar = BdsLibGetVariableAndSize (
+                      BootOption,
+                      &gEfiGlobalVariableGuid,
+                      &BootOptionSize
+                      );
+    if (NULL == BootOptionVar) {
+      BootOptionSize = 0;
+      Status = refit_call5_wrapper(gRT->GetVariable,
+                      BootOption,
+                      &gEfiGlobalVariableGuid,
+                      NULL,
+                      &BootOptionSize,
+                      BootOptionVar
+                      );
+      if (Status == EFI_NOT_FOUND) {
+        //
+        // Update BootOrder
+        //
+        BdsDeleteBootOption (
+          BootOrder[Index],
+          BootOrder,
+          &BootOrderSize
+          );
+        continue;
+      } else {
+        FreePool (BootOrder);
+        return EFI_OUT_OF_RESOURCES;
+      }
+    }
+
+    //
+    // Skip Non-Legacy boot option
+    //
+    if (!BdsIsLegacyBootOption (BootOptionVar, &BbsEntry, &BbsIndex)) {
+      if (BootOptionVar!= NULL) {
+        FreePool (BootOptionVar);
+      }
+      Index++;
+      continue;
+    }
+
+    if (BbsIndex < BbsCount) {
+      //
+      // Check if BBS Description String is changed
+      //
+      DescStringMatch = FALSE;
+      BdsBuildLegacyDevNameString (
+        &LocalBbsTable[BbsIndex],
+        BbsIndex,
+        sizeof (BootDesc),
+        BootDesc
+        );
+
+      if (StrCmp (BootDesc, (UINT16*)(BootOptionVar + sizeof (UINT32) + sizeof (UINT16))) == 0) {
+        DescStringMatch = TRUE;
+      }
+
+      if (!((LocalBbsTable[BbsIndex].BootPriority == BBS_IGNORE_ENTRY) ||
+            (LocalBbsTable[BbsIndex].BootPriority == BBS_DO_NOT_BOOT_FROM)) &&
+          (LocalBbsTable[BbsIndex].DeviceType == BbsEntry->DeviceType) &&
+          DescStringMatch) {
+        Index++;
+        continue;
+      }
+    }
+
+    if (BootOptionVar != NULL) {
+      FreePool (BootOptionVar);
+    }
+    //
+    // should delete
+    //
+    BdsDeleteBootOption (
+      BootOrder[Index],
+      BootOrder,
+      &BootOrderSize
+      );
+  }
+
+  //
+  // Adjust the number of boot options.
+  //
+  if (BootOrderSize != 0) {
+    Status = refit_call5_wrapper(gRT->SetVariable,
+                    L"BootOrder",
+                    &gEfiGlobalVariableGuid,
+                    VAR_FLAG,
+                    BootOrderSize,
+                    BootOrder
+                    );
+  } else {
+    EfiLibDeleteVariable (L"BootOrder", &gEfiGlobalVariableGuid);
+  }
+
+  if (BootOrder != NULL) {
+    FreePool (BootOrder);
+  }
+
+  return Status;
+}
+
+/**
+  Fill the device order buffer.
+
+  @param BbsTable        The BBS table.
+  @param BbsType         The BBS Type.
+  @param BbsCount        The BBS Count.
+  @param Buf             device order buffer.
+
+  @return The device order buffer.
+
+**/
+UINT16 *
+BdsFillDevOrderBuf (
+  IN BBS_TABLE                    *BbsTable,
+  IN BBS_TYPE                     BbsType,
+  IN UINTN                        BbsCount,
+  OUT UINT16                      *Buf
+  )
+{
+  UINTN Index;
+
+  for (Index = 0; Index < BbsCount; Index++) {
+    if (BbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) {
+      continue;
+    }
+
+    if (BbsTable[Index].DeviceType != BbsType) {
+      continue;
+    }
+
+    *Buf = (UINT16) (Index & 0xFF);
+    Buf++;
+  }
+
+  return Buf;
+}
diff --git a/EfiLib/legacy.h b/EfiLib/legacy.h
new file mode 100644 (file)
index 0000000..3384f48
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * EfiLib/legacy.h
+ * CSM/legacy boot support functions
+ * 
+ * Taken from Tianocore source code (mostly IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/BBSsupport.c)
+ *
+ * Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>
+ * This program and the accompanying materials
+ * are licensed and made available under the terms and conditions of the BSD License
+ * which accompanies this distribution.  The full text of the license may be found at
+ * http://opensource.org/licenses/bsd-license.php
+ * 
+ * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ *
+ */
+
+#include "LegacyBios.h"
+
+#ifndef __LEGACY_H_
+#define __LEGACY_H_
+
+#define BBS_MEDIA_PRESENT        0x0800
+#define BBS_MEDIA_MAYBE_PRESENT  0x0400
+
+typedef UINT8 BBS_TYPE;
+
+#define VAR_FLAG  EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE
+
+#pragma pack(1)
+///
+/// For each legacy boot option in BBS table, a corresponding Boot#### variables is created.
+/// The structure saves the mapping relationship between #### and the index in the BBS table.
+///
+typedef struct {
+   UINT16    BootOptionNumber;
+   UINT16    BbsIndex;
+   UINT16    BbsType;
+} BOOT_OPTION_BBS_MAPPING;
+#pragma pack()
+
+#pragma pack(1)
+typedef struct {
+   BBS_TYPE  BbsType;
+   ///
+   /// Length = sizeof (UINT16) + sizeof (Data)
+   ///
+   UINT16    Length;
+   UINT16    Data[1];
+} LEGACY_DEV_ORDER_ENTRY;
+#pragma pack()
+
+EFI_STATUS
+BdsAddNonExistingLegacyBootOptions (
+   VOID
+);
+
+/**
+  Delete all the invalid legacy boot options.
+
+  @retval EFI_SUCCESS             All invalide legacy boot options are deleted.
+  @retval EFI_OUT_OF_RESOURCES    Fail to allocate necessary memory.
+  @retval EFI_NOT_FOUND           Fail to retrive variable of boot order.
+**/
+EFI_STATUS
+BdsDeleteAllInvalidLegacyBootOptions (
+  VOID
+  );
+
+BOOLEAN
+BdsIsLegacyBootOption (
+   IN UINT8                 *BootOptionVar,
+   OUT BBS_TABLE            **BbsEntry,
+   OUT UINT16               *BbsIndex
+);
+
+VOID
+BdsBuildLegacyDevNameString (
+   IN  BBS_TABLE                 *CurBBSEntry,
+   IN  UINTN                     Index,
+   IN  UINTN                     BufSize,
+   OUT CHAR16                    *BootString
+);
+
+#endif
\ No newline at end of file
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644 (file)
index 0000000..de04544
--- /dev/null
@@ -0,0 +1,53 @@
+
+ rEFIt License
+===============
+
+Copyright (c) 2006 Christoph Pfisterer
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the
+   distribution.
+
+ * Neither the name of Christoph Pfisterer nor the names of the
+   contributors may be used to endorse or promote products derived
+   from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+ Additional Notice
+===================
+
+Parts of the file system driver sub-projects are covered by the GNU
+GPL instead. See the LICENSE.txt files in the fs_ext2 and fsw
+directories for more information.
+
+
+ Additional Additional Notice
+=============================
+
+The preceding license terms apply to the original rEFIt program.
+Modifications to the program made in forking the project as rEFInd are
+covered by the GNU GPL, version 3. See the file COPYING.txt for details of
+the GPLv3 license. The rEFInd documentation (HTML files) are covered by the
+GNU FDL, version 1.3. See the file FDL-1.3.txt in the documentation
+directory for details of the FDL license.
diff --git a/Make.common b/Make.common
new file mode 100644 (file)
index 0000000..96eb50f
--- /dev/null
@@ -0,0 +1,131 @@
+#
+# Make.common
+# Common make rules for building with gnu-efi
+#
+
+# This program is licensed under the terms of the GNU GPL, version 3,
+# or (at your option) any later version.
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+EFIINC          = /usr/include/efi
+GNUEFILIB       = /usr/lib
+EFILIB          = /usr/lib
+EFICRT0         = /usr/lib
+
+# Comment out above and uncomment below if using locally-compiled GNU-EFI....
+#EFIINC          = /usr/local/include/efi
+#GNUEFILIB       = /usr/local/lib
+#EFILIB          = /usr/local/lib
+#EFICRT0         = /usr/local/lib
+
+HOSTARCH        = $(shell uname -m | sed s,i[3456789]86,ia32,)
+ARCH            := $(HOSTARCH)
+OS             = $(shell uname -s)
+CPPFLAGS        = -I$(EFIINC) -I$(EFIINC)/$(ARCH) -I$(EFIINC)/protocol -I../include -I../refind -I../libeg -DCONFIG_$(ARCH) -D__MAKEWITH_GNUEFI
+
+OPTIMFLAGS      = -O2 -fno-strict-aliasing
+DEBUGFLAGS      = -Wall
+#CFLAGS          = $(ARCH3264) $(OPTIMFLAGS) -fpic -fshort-wchar $(DEBUGFLAGS)
+CFLAGS          = $(ARCH3264) $(OPTIMFLAGS) -fno-stack-protector -fpic -fshort-wchar $(DEBUGFLAGS)
+ASFLAGS         = $(ARCH3264)
+LDFLAGS         = -nostdlib
+DRV_LDFLAGS     =
+
+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
+
+FORMAT          = --target=efi-app-$(ARCH)
+FORMAT_DRIVER   = --target=efi-bsdrv-$(ARCH)
+
+ifeq ($(ARCH),x86_64)
+  CFLAGS += -DEFI_FUNCTION_WRAPPER -mno-red-zone 
+  CPPFLAGS += -DEFIX64
+  LDFLAGS += -znocombreloc -zdefs
+
+  ifeq ($(HOSTARCH),ia32)
+    ARCH3264 = -m64
+
+    GNUEFILIB := $(GNUEFILIB)64
+    EFILIB    := $(EFILIB)64
+    EFICRT0   := $(EFICRT0)64
+  endif
+endif
+
+ifeq ($(ARCH),ia32)
+  CPPFLAGS += -DEFI32 -malign-double
+  LDFLAGS += -znocombreloc -zdefs
+
+  ifeq ($(HOSTARCH),x86_64)
+    ARCH3264 = -m32
+
+    GNUEFILIB := $(GNUEFILIB)32
+    EFILIB    := $(EFILIB)32
+    EFICRT0   := $(EFICRT0)32
+  endif
+endif
+
+ifeq ($(ARCH), aarch64)
+  CFLAGS += -fno-stack-check -g -fno-merge-constants -ffreestanding -fno-stack-check 
+  CPPFLAGS += -DEFIAARCH64
+  FORMAT          = -O binary
+  FORMAT_DRIVER   = -O binary
+  LDFLAGS         += --defsym=EFI_SUBSYSTEM=0xa --warn-common --no-undefined --fatal-warnings
+  DRV_LDFLAGS     += --defsym=EFI_SUBSYSTEM=0xb --warn-common --no-undefined --fatal-warnings
+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)
+DRV_LDFLAGS    += -T $(LDSCRIPT) -shared -Bsymbolic -L$(EFILIB) -L$(GNUEFILIB) $(CRTOBJS)
+LIBS            = -lefi -lgnuefi $(shell $(CC) $(ARCH3264) -print-libgcc-file-name)
+
+
+# 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))
+
+endif
+
+# rules for libraries
+
+ifneq (,$(filter %.a,$(TARGET)))
+
+$(TARGET): $(OBJS)
+       $(AR) cq $@ $(OBJS)
+
+endif
+
+# utility rules
+
+clean:
+       rm -f $(TARGET) *~ *.so $(OBJS) *.efi *.obj refind_*.txt refind_*.dll *.lib
+
+# EOF
diff --git a/Make.tiano b/Make.tiano
new file mode 100644 (file)
index 0000000..84fba95
--- /dev/null
@@ -0,0 +1,77 @@
+#
+# Make.tiano
+# Common Makefile options for rEFInd using TianoCore EDK2
+#
+
+# This program is licensed under the terms of the GNU GPL, version 3,
+# or (at your option) any later version.
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+HOSTARCH        = $(shell uname -m | sed s,i[3456789]86,ia32,)
+ARCH            ?= $(HOSTARCH)
+
+# Note: IA64 options are untested; taken from Debian's rEFIt package.
+ifeq ($(ARCH),ia64)
+  # EFI specs allows only lower floating point partition to be used
+  ARCH_C_CFLAGS  = -frename-registers -mfixed-range=f32-f127
+  # TODO: Add ARCHDIR and FILENAME_CODE as appropriate
+endif
+
+ifeq ($(ARCH),ia32)
+  ARCH_C_FLAGS = -m32 -DEFI32 -malign-double
+  ARCHDIR = Ia32
+  UC_ARCH = IA32
+  FILENAME_CODE = ia32
+  LD_CODE = elf_i386
+endif
+
+ifeq ($(ARCH),x86_64)
+  ARCH_C_FLAGS = "-DEFIAPI=__attribute__((ms_abi))" -DEFIX64 -mcmodel=large -m64 -mno-red-zone 
+  ARCHDIR = X64
+  UC_ARCH = X64
+  FILENAME_CODE = x64
+  LD_CODE = elf_x86_64
+endif
+
+ifeq ($(ARCH),aarch64)
+  ARCH_C_FLAGS = -DEFIAARCH64 -mcmodel=large
+  ARCHDIR = AArch64
+  UC_ARCH = AARCH64
+  FILENAME_CODE = aa64
+  LD_CODE = aarch64elf
+endif
+
+#EDK2BASE = /usr/local/UDK2014/MyWorkSpace
+#EDK2BASE = /usr/local/EDK2/tianocore-edk2
+#ENTRYPOINT=_ModuleEntryPoint
+ENTRYPOINT=efi_main
+
+# Below file defines TARGET (RELEASE or DEBUG) and TOOL_CHAIN_TAG (GCC44, GCC45, GCC46, or GCC47)
+include $(EDK2BASE)/Conf/target.txt
+
+INCLUDE_DIRS    = -I $(EDK2BASE)/MdePkg \
+                  -I $(EDK2BASE)/MdePkg/Include \
+                 -I $(EDK2BASE)/MdeModulePkg/ \
+                  -I $(EDK2BASE)/MdeModulePkg/Include \
+                  -I $(EDK2BASE)/IntelFrameworkPkg/Include \
+                  -I $(EDK2BASE)/MdePkg/Include/$(ARCHDIR) \
+                 -I .. \
+                 -I ../refind \
+                 -I ../libeg \
+                 -I ../include \
+                 -I ../mok
+
+OPTIMFLAGS      += -fno-strict-aliasing -Wno-address -Os
+DEBUGFLAGS      = -Wall -Wno-missing-braces -Wno-array-bounds -ffunction-sections -fdata-sections
+CFLAGS          = $(OPTIMFLAGS) -g -fshort-wchar -fno-stack-protector $(DEBUGFLAGS) -c
+
+LDSCRIPT = $(EDK2BASE)/BaseTools/Scripts/gcc4.4-ld-script
+
+LDFLAGS         = -nostdlib -n -q --gc-sections --script=$(EDK2BASE)/BaseTools/Scripts/gcc4.4-ld-script \
+                  --entry $(ENTRYPOINT) -u $(ENTRYPOINT) -m $(LD_CODE)
+
+%.obj: %.c
+       $(CC) $(ARCH_C_FLAGS) $(CFLAGS) $(INCLUDE_DIRS) -DNO_BUILTIN_VA_FUNCS -D__MAKEWITH_TIANO -c $< -o $@
+
+
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..2292c51
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,94 @@
+# Makefile for rEFInd
+
+# This program is licensed under the terms of the GNU GPL, version 3,
+# or (at your option) any later version.
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+CXXFLAGS=-O2 -fpic -D_REENTRANT -D_GNU_SOURCE -Wall -g
+NAMES=refind
+SRCS=$(NAMES:=.c)
+OBJS=$(NAMES:=.o)
+HEADERS=$(NAMES:=.h)
+LOADER_DIR=refind
+FS_DIR=filesystems
+LIBEG_DIR=libeg
+MOK_DIR=mok
+GPTSYNC_DIR=gptsync
+EFILIB_DIR=EfiLib
+
+export EDK2BASE        = /usr/local/UDK2014/MyWorkSpace
+export GENFW           = $(EDK2BASE)/BaseTools/Source/C/bin/GenFw
+export prefix          = /usr/bin/
+ifeq ($(ARCH),aarch64)
+  export CC            = $(prefix)aarch64-linux-gnu-gcc
+  export AS            = $(prefix)aarch64-linux-gnu-as
+  export LD            = $(prefix)aarch64-linux-gnu-ld
+  export AR            = $(prefix)aarch64-linux-gnu-ar
+  export RANLIB        = $(prefix)aarch64-linux-gnu-ranlib
+  export OBJCOPY       = $(prefix)aarch64-linux-gnu-objcopy
+else
+  export CC            = $(prefix)gcc
+  export AS            = $(prefix)as
+  export LD            = $(prefix)ld
+  export AR            = $(prefix)ar
+  export RANLIB        = $(prefix)ranlib
+  export OBJCOPY       = $(prefix)objcopy
+endif
+
+# Build rEFInd, including libeg
+all:   tiano
+
+gnuefi:
+       +make -C $(LIBEG_DIR)
+       +make -C $(MOK_DIR)
+       +make -C $(EFILIB_DIR)
+       +make -C $(LOADER_DIR)
+       +make -C $(GPTSYNC_DIR) gnuefi
+#      +make -C $(FS_DIR) all_gnuefi
+
+fs:
+       +make -C $(FS_DIR)
+
+fs_gnuefi:
+       +make -C $(FS_DIR) all_gnuefi
+
+tiano:
+       +make AR_TARGET=EfiLib -C $(EFILIB_DIR) -f Make.tiano
+       +make AR_TARGET=libeg -C $(LIBEG_DIR) -f Make.tiano
+       +make AR_TARGET=mok -C $(MOK_DIR) -f Make.tiano
+       +make BUILDME=refind DLL_TARGET=refind -C $(LOADER_DIR) -f Make.tiano
+ifneq ($(ARCH),aarch64)
+       +make -C $(GPTSYNC_DIR) -f Make.tiano
+endif
+#      +make -C $(FS_DIR)
+
+gptsync:
+       +make -C $(GPTSYNC_DIR) -f Make.tiano
+
+gptsync_gnuefi:
+       +make -C $(GPTSYNC_DIR) gnuefi
+
+clean:
+       make -C $(LIBEG_DIR) clean
+       make -C $(MOK_DIR) clean
+       make -C $(LOADER_DIR) clean
+       make -C $(EFILIB_DIR) clean
+       make -C $(FS_DIR) clean
+       make -C $(GPTSYNC_DIR) clean
+       rm -f include/*~
+
+# NOTE TO DISTRIBUTION MAINTAINERS:
+# The "install" target installs the program directly to the ESP
+# and it modifies the *CURRENT COMPUTER's* NVRAM. Thus, you should
+# *NOT* use this target as part of the build process for your
+# binary packages (RPMs, Debian packages, etc.). (Gentoo could
+# use it in an ebuild, though....) You COULD, however, copy the
+# files to a directory somewhere (/usr/share/refind or whatever)
+# and then call refind-install as part of the binary package
+# installation process.
+
+install:
+       ./refind-install
+
+# DO NOT DELETE
diff --git a/NEWS.txt b/NEWS.txt
new file mode 100644 (file)
index 0000000..73ecbce
--- /dev/null
+++ b/NEWS.txt
@@ -0,0 +1,1749 @@
+0.10.1 (??/??/201?):
+--------------------
+
+- Removed Luxi Sans Mono font, since I discovered it was not open source;
+  and changed the default font from Nimbus Mono to Liberation Mono.
+
+- Added support for compiling rEFInd for ARM64 (aka AARCH64 or aa64). This
+  works with both GNU-EFI and Tianocore UDK2014.SP1.P1. This support is
+  currently poorly tested. In particular, I used QEMU on an x86-64 computer
+  to create a virtualized ARM64 environment; I've not yet tested on a real
+  computer. I couldn't get QEMU to create a video card, so I used a serial
+  terminal, which means that the graphics features are untested -- I ran
+  rEFInd with "textonly" uncommented in refind.conf. I've tested the ext4fs
+  driver but no other drivers, although they all compile. (So does gptsync,
+  although it's unlikely to be useful on ARM64.) Some rEFInd features are
+  meaningless on ARM64, such as BIOS-mode boot support, anything geared
+  toward Macs (csr_values/csr_rotate, spoof_osx_version, etc.), and
+  enable_and_lock_vmx.
+
+- Fixed bug that caused rEFInd to fail to scan EFI boot loaders on
+  removable media when rEFInd itself was launched from the fallback
+  filename.
+
+- Moved detailed descriptions of refind-install from installing.html to
+  a refind-install man page. To keep this information Web-accessible, I've
+  also created HTML versions of the three man pages and linked them into
+  the HTML documentation.
+
+- Updated LodePNG to latest version (20151024).
+
+- Fixed bugs in mkrlconf and in refind-install that could cause some kernel
+  options to be excluded from refind_linux.conf. There were two trouble
+  conditions:
+  - Previously, these scripts assumed that the first option in
+    /proc/cmdline was the kernel's filename, but this isn't always the
+    case. (In particular, when gummiboot launches the kernel, this is not
+    true. It might be an incorrect assumption in some other cases, too.)
+    The fix involves checking for likely signs of a kernel filename before
+    discarding this first option.
+  - These scripts cut the "initrd=*" option from /proc/cmdline, but the
+    call to "sed" was overzealous and cut until the end of input. This
+    usually worked, since the initrd= option was usually last on the line;
+    but if it wasn't, any options following initrd= would be lost.
+
+- Added "kernel*" as a matching pattern for Linux kernels, since this is
+  what Gentoo uses by default.
+
+- The refind-install script can now be run as a symbolic link in Linux.
+  This enables creating a /usr/sbin/refind-install link in Linux packages,
+  with the binaries stashed wherever the package system likes them. This
+  feature does NOT work in OS X, but there's relatively little need for it
+  there.
+
+0.10.0 (11/8/2015):
+-------------------
+
+- Fixed bug that caused refind-install to not unmount the ESP when it
+  should under OS X.
+
+- Modified refind-install and mkrlconf scripts to use /proc/cmdline as
+  source for default boot options EXCEPT when refind-install receives the
+  --root option. In that case, refind-install continues to use
+  /etc/default/grub as the source of default options. The idea behind this
+  change is that it's more reliable to get boot options from /proc/cmdline
+  when the targeted system is the one that's booted; but --root would be
+  used from emergency disks or live CDs, in which case the current boot
+  options would be completely wrong, so extracting boot options from GRUB
+  files is the best bet for getting close to the right options.
+
+- Added "@/boot" to default also_scan_dirs setting. This makes kernels
+  show up on Btrfs volumes under Ubuntu (and perhaps others), at least when
+  the Btrfs driver is loaded.
+
+- Added new System Integrity Protection (SIP) rotation feature for Macs
+  running OS X 10.11 or later. This feature is disabled by default, except
+  on CD-R and USB flash drive images, on which it's enabled. To enable it,
+  you must make TWO changes to refind.conf: Uncomment the new "csr_values"
+  item and add "csr_rotate" to the "showtools" line (uncommenting it, too,
+  if it's commented out). If desired, you can set more values on
+  "csr_values"; these are comma-delimited one-byte hexadecimal values that
+  define various SIP states.  When SIP/CSR rotation is activated, a new
+  shield icon appears among the tools. Selecting it causes the next defined
+  value to be set and a confirmation message to appear for three seconds.
+
+- Added display of current System Integrity Protection (SIP) mode to
+  "About" display.
+
+- Added mountesp script for OS X to (you guessed it!) mount the ESP.
+
+- Renamed support scripts: install.sh to refind-install, mvrefind.sh to
+  mvrefind, and mkrlconf.sh to mkrlconf.
+
+- New icons! The old ones were getting to be a jumbled mess of styles,
+  particularly for OS tags. I used the AwOken icon set
+  (http://alecive.deviantart.com/art/AwOken-163570862) for the core icons,
+  then expanded from there by creating my own icons and modifying icons for
+  Debian and Elementary OS. I'm also trying to keep better track of
+  copyrights and licenses on icons. Between that and some icons being for
+  OSes that probably see very little use (FreeDOS and eComstation, for
+  instance), a few OS icons have been lost. If you prefer the old icons,
+  you can continue to use them by upgrading rEFInd, renaming icons-backup
+  to something else (say, icons-classic), and then adding an "icons" line
+  in refind.conf to point to the old icons directory.
+
+- Changed from .zip to .tar.gz as source code archive format. I did this
+  because Linux is the only officially-supported build platform, and
+  tarballs are a more natural fit to a Linux environment. I'm leaving .zip,
+  .deb, and .rpm files as the formats for binary packages.
+
+- Added detection of System Integrity Protection (SIP; aka "rootless") mode
+  to OS X portion of install.sh script. When detected, and if no existing
+  rEFInd installation is found, the script now prints a warning and brief
+  instructions of how to enter the Recovery mode to install rEFInd and
+  suggests aborting the installation. (The user can override and attempt
+  installation anyhow.) If SIP is detected along with an existing rEFInd
+  installation, the script moderates the warning and explains that an
+  update of a working rEFInd will probably succeed, but that re-installing
+  to fix a broken rEFInd will probably fail.
+
+- Added new "spoof_osx_version" token, which takes an OS X version number
+  (such as "10.9") as an option. This feature, when enabled, causes rEFInd
+  to tell a Mac's firmware that the specified version of OS X is being
+  launched. This option is usually unnecessary, but it can help properly
+  initialize some hardware -- particularly secondary video devices. OTOH,
+  on some Macs it can cause hardware (notably keyboards and mice) to become
+  unresponsive, so you should not use this option unnecessarily.
+
+- Worked around an EFI bug that affected my 32-bit Mac Mini: That system
+  seems to have a broken EFI, or possibly a buggy CPU, that causes some
+  (but not all) conversions from floating-point to integer numbers to hang
+  the computer. Such operations were performed only in rEFInd's
+  graphics-resizing code, and so would manifest only when icons or
+  background images were resized. My fix eliminates the use of
+  floating-point operations in the affected function, which eliminates the
+  crashes. There may be some degradation in the quality of resized images,
+  though, particularly on 32-bit systems. (64-bit systems use larger
+  integers, which enable greater precision in my floating-point
+  workaround.)
+
+- Under OS X, install.sh can now be run from the recovery system. This may
+  help work around OS X 10.11's problems with System Integrity Protection,
+  since it should be possible to reboot into the recovery system to install
+  rEFInd without disabling SIP for the main installation, even for just one
+  boot.
+
+0.9.2 (9/19/2015):
+------------------
+
+- Added "--keepname" option to install.sh. This option causes install.sh
+  to keep refind_x64.efi named as such rather than rename it as grubx64.efi
+  when using Shim. This option is meaningful only if the --shim option is
+  also used. This option passes the refind_x64.efi filename as an option to
+  Shim, which overrides the default filename of grubx64.efi. A big caveat:
+  Only Shim 0.7 and later supports this feature. (Shim 0.4 also works if a
+  refind_x64.efi is referred to as "\refind_x64.efi" on the command line,
+  but the need for a leading backslash to refer to a file in the same
+  directory as Shim is so confusing and wrong that I cannot in good
+  conscience support it.) I've not seen signed Shim binaries between 0.4
+  and 0.7, so I don't know if any of them might work.
+
+- Implemented a workaround for a bug in Shim 0.8 that prevented
+  authentication of more than one binary. If any filesystem drivers were
+  installed, the first one would be verified, leaving rEFInd unable to
+  launch anything else unless it was signed by a key in the computer's main
+  Secure Boot db list.
+
+0.9.1 (9/13/2015):
+------------------
+
+- When rEFInd identifies the root (/) partition via the Freedesktop.org
+  Discoverable Partitions Specification, it now checks two of the
+  partition's attributes, as per the DPS (see
+  http://www.freedesktop.org/wiki/Specifications/DiscoverablePartitionsSpec/):
+  - The partition's read-only attribute determines whether to pass a "rw"
+    or "ro" option to the kernel.
+  - If the partition's do-not-automount flag is set, rEFInd will not pass
+    it as a "root=" option to the kernel. This flag can be used to remove
+    all but one partition from consideration as a root (/) partition if a
+    system has more than one with the correct type code.
+
+- Improved Freedesktop.org Discoverable Partitions Specification support:
+  Previously, if no refind_linux.conf file was present but an /etc/fstab
+  file was found, rEFInd ignored the Discoverable Partitions Specification
+  filesystem-type codes. This was fine if /etc/fstab contained a valid "/"
+  filesystem specification, but if that was absent, the result was no
+  "root=" specification being present. Under these circumstances
+  (refind_linux.conf absent, /etc/fstab present but lacking a "/" entry),
+  rEFInd now tries to identify a device to specify as "root=" via the
+  Discoverable Partitions Specification.
+
+- Fixed bug that caused "Found match!" and a prompt to press a key to
+  continue to be printed if any partition used the Freedesktop.org
+  Discoverable Partitions Specification root-partition GUID. (This
+  was leftover debugging/testing code that I somehow missed deleting.)
+
+- Added icon for Elementary OS.
+
+- Added /etc/lsb-release to files scanned for clues about the Linux
+  distribution. This file differentiates Mint and Elementary OS from Ubuntu
+  better than does /etc/os-release, and may also help with other
+  closely-related distributions.
+
+- Improvements to handling of case-insensitive string comparisons. These
+  are buggy on some EFIs, and such bugs affect things like dont_scan_*
+  blacklists, removal of rEFInd's own directory from scanning, matching of
+  keyword names in refind.conf, and even loading of icons. I've replaced
+  many calls to problematic functions with safer calls, which should help a
+  lot. There may still be problems on some systems with some computers,
+  though; as far as I can tell, the bugs are buried deep in some EFI
+  firmware, so I can only replace some of the most direct calls to
+  potentially buggy system calls.
+
+0.9.0 (7/26/2015):
+------------------
+
+- New icon for Kali Linux, submitted by Francesco D'Eugenio.
+
+- Minor code changes to ensure that rEFInd compiles with GCC 5.1. (Tested
+  with GNU-EFI on a Fedora 22 system; not yet tested with the TianoCore
+  EDK2.)
+
+- Added new "fold_linux_kernels" token to refind.conf. This option, when
+  active (the default) "folds" all Linux kernels in a directory into a
+  single entry on the rEFInd menu. The kernel with the most recent time
+  stamp is launched by default. To launch another kernel, you must press F2
+  or Insert; additional kernels appear as options on the first kernel's
+  submenu. To see the pre-0.9.0 behavior, you must set "fold_linux_kernels
+  false" (or one of its synonyms, "off" or "0"). The point of this option
+  is to help de-clutter the rEFInd main menu.
+
+- Added new Linux root (/) partition auto-discovery feature, based on
+  Freedesktop.org's Discoverable Partitions Spec (DPS)
+  (http://www.freedesktop.org/wiki/Specifications/DiscoverablePartitionsSpec/):
+  If no refind_linux.conf file or /etc/fstab file is found, and if a
+  partition with the correct DPS type code for the system architecture is
+  found, rEFInd adds "ro root=/dev/disk/by-partuuid/{GUID}" to the kernel
+  options. This will not help on LVM setups, and will get it right for only
+  one installation on systems with multiple Linux installations, but it may
+  help some users, if/when the DPS type codes become more common.
+
+- Fixed bug that caused a rEFInd crash if an empty refind_linux.conf
+  file was encountered.
+
+- The mkrlconf.sh script now checks the OS on which it's running, which
+  should help avoid confusion or problems by users who mistakenly run it
+  under OS X.
+
+- rEFInd now skips checking for various BIOS-mode boot sector signatures
+  when running on a UEFI-based PC; these checks are run only on Macs. This
+  may reduce startup time on systems with many partitions.
+
+- Fixed Debian debinstall script to work correctly on IA32 systems. It had
+  a bug that caused filesystem drivers and gptsync to not be packaged for
+  IA32.
+
+- Modified Debian postinst file to call install.sh with --localkeys option
+  if sbsign and openssl are available, even when NOT in Secure Boot mode or
+  if shim is not detected. This helps with my Ubuntu PPA when using custom
+  Secure Boot keys, since the PPA is delivered unsigned. (Users will have
+  to have added their own local keys to their firmware's db.) For
+  consistency, I've made the same change to the RPM .spec file.
+
+0.8.7 (3/1/2015):
+-----------------
+
+- Fixed install.sh bug that caused inappropriate installation under the
+  name bootx64.efi (or bootia32.efi) under Linux, with a failure to update
+  the boot entries in NVRAM, has been fixed.
+
+- Added identification of XFS as filesystem type in volume descriptions.
+
+- More fixes to filesystem type detection code. Previous version sometimes
+  identified FAT or NTFS (or anything with a boot loader) as a whole-disk
+  device rather than the correct filesystem type.
+
+- Added protections to the code to reduce the risk of crashes that might
+  occur when dereferencing NULL pointers in various situations.
+
+- I'm deprecating the use of filesystem numbers (as in "fs0:") because
+  they're unreliable -- filesystem numbers can change between boots and
+  might not be the same as those used in an EFI shell or other program.
+  Sooner or later I'll remove code supporting this feature. In the
+  meantime, if it doesn't work for you, please switch to using filesystem
+  labels, partition labels, or partition GUIDs.
+
+- Added detection of FreeBSD's BIOS-mode GPT boot loader. Previously,
+  rEFInd could detect FreeBSD's BIOS-mode MBR boot loader, which gave
+  FreeBSD an appropriate icon on Macs; but the BIOS-mode GPT boot loader
+  code is different, so some recent FreeBSD installations showed up with
+  generic grey diamond icons. This change creates FreeBSD icons instead.
+
+- Added "Secure Boot [active|inactive]" notice to "about" menu for x86
+  (32-bit) systems, since there are now a few 32-bit UEFI systems that
+  support Secure Boot. (AFAIK, these are mostly tablets and convertibles
+  such as the ASUS T100.)
+
+- Added KeyTool.efi and KeyTool-signed.efi to list of MOK managers. KeyTool
+  is the "super-deluxe" Secure Boot key and hash manager provided as part
+  of the efitools package.
+
+- Fixed more instances of "invalid parameter" errors on some EFIs.
+
+- Improved Secure Boot detection in install.sh.
+
+- install.sh should no longer complain when copying Shim or MokManager over
+  itself.
+
+0.8.6 (2/8/2015):
+-----------------
+
+- Removed special case of ignoring an HFS+ name of "HFS+ volume", since the
+  old rEFInd HFS+ driver that produced this name for all HFS+ volumes has
+  long since been updated to deliver a real name.
+
+- Addition of new Windows 8 OS icon. On Macs and for BIOS/legacy boots, the
+  new icon is now used for Windows Vista, 7, and 8, while the old one is
+  used for earlier versions of Windows. For EFI-mode boots, the new icon is
+  used universally.
+
+- If the NTFS driver is loaded, rEFInd now scans NTFS volumes on Macs for
+  the presence of Windows boot files, and removes any NTFS volume that
+  lacks such files from the BIOS/legacy boot list. This should help
+  unclutter the display on Macs that contain NTFS data partitions.
+
+- Fixed bug that caused misidentification of both whole disks and NTFS
+  volumes as being FAT. (This bug affected the identification of devices
+  and locations in the rEFInd menu, not actual access to devices.)
+
+- Code refactoring to clear out legacy-boot functions from the
+  ever-expanding refind/main.c file.
+
+- Added new "badges" option to the "hideui" token in refind.conf. This
+  option hides the device-type badges associated with the OS boot options.
+
+- Reverted rEFIt commit r472, introduced in rEFInd 0.8.5 to support more
+  BMP images because I've received bug reports that it's causing existing
+  selection images to fail to load.
+
+- Fixed install.sh bug that caused misidentification of installation
+  directory under OS X if an already-mounted ESP has spaces in its path.
+
+- Fixed Mac-specific install.sh bug that could cause misidentification of
+  the ESP on disks with partition numbers of 10 or above.
+
+
+0.8.5 (2/1/2015):
+-----------------
+
+- Added NTFS EFI filesystem driver.
+
+- Minor improvements to filesystem driver framework code.
+
+- Changes to 
+
+- Fixed bug in Btrfs driver's address reference.
+
+- Improved install.sh to make it smarter about figuring out where to
+  install on Macs. Specifically, this version now upgrades existing
+  installations, if found (as it always has under Linux), rather than
+  blindly install to EFI/BOOT; it installs to EFI/refind if not existing
+  installation is found; it installs using the --shortform option to bless,
+  which seems to eliminate the 30-second delay problem; and it can handle
+  an HFS+ ESP, which it treats as a separate HFS+ volume (as if the user
+  had used --ownhfs). These changes do not affect behavior under Linux.
+
+- Added missing check of architecture type for several tools.
+
+- Applied rEFIt commit r472, which adds support for BMP images with negative
+  height fields, indicating that the image is NOT vertically flipped. This
+  commit and r467 were not incorporated in the original rEFInd because I
+  forked it from a Debian rEFIt package that had been patched to build
+  under GNU-EFI, and was apparently based on a slightly earlier version.
+
+- Applied rEFIt commit r467, which improves Mac handling of legacy boots
+  from other than the first hard disk.
+
+
+0.8.4 (12/8/2014):
+------------------
+
+- Tweaked default for dont_scan_volumes: Removed "Recovery HD". This change
+  better suits the needs of OS X 10.10 ("Yosemite") installations, but may
+  result in some stray Recovery HD entries on some Macs.
+
+- Updated icons for Fedora and Ubuntu and added an icon for Xubuntu.
+
+- Added new configuration option, "enable_and_lock_vmx", which sets an
+  Intel CPU feature that's required for some types of virtualization to
+  work. Most EFIs enable setting this feature in their own setup utilities,
+  but some (such as most Macs) don't.
+
+- If rEFInd can't locate an icons directory (either the default or one
+  specified by the icons_dir token), the program switches to text-only
+  mode.
+
+- If a loader contains the string "grub" and no other clue to the loader's
+  OS association exists, search for os_grub.{png|icns} (which is not
+  provided with rEFInd) or os_linux.{png|icns}. (Previous versions provided
+  a generic loader icon for GRUB.)
+
+- Fixed bug that caused dont_scan_files to not work with special-case
+  boot loaders (for OS X and Windows) when specifying the complete path to
+  the loader (e.g., EFI/Microsoft/Boot/bootmgfw.efi).
+
+- Added support for the iPXE network boot tool (see BUILDING.txt for
+  building and basic use instructions).
+
+0.8.3 (7/6/2014):
+-----------------
+
+- Added new feature: Setting "timeout = -1" in refind.conf causes rEFInd to
+  immediately boot the default option UNLESS a keypress is in the buffer
+  when rEFInd launches. In that case, if the keypress corresponds to a
+  shortcut key, the associated boot loader is launched; or if not, the menu
+  is displayed.
+
+- Added new icons for Clover boot loader and for Mythbuntu Linux
+  distribution.
+
+- rEFInd now displays the partition's label, when one is available, when
+  offering a BIOS-mode boot option for a partition with no filesystem
+  driver. This works only on Macs doing BIOS-mode booting.
+
+- Removed GPLv2 code from the FSW core files. This was done because the
+  Btrfs driver is derived from the GRUB Btrfs driver, which is licensed
+  under the GPLv3. Ironically, the GPLv2 and GPLv3 are incompatible
+  licenses, so ensuring that the Btrfs driver doesn't rely on GPLv2 code
+  was legally necessary. In most cases, I reverted to the original rEFIt
+  code, although I kept my own cache code; since I wrote it, I can
+  change its license to a BSD license.
+
+- Fixed bug that caused rEFInd to unload drivers immediately after loading
+  them. This didn't affect rEFInd's own drivers because they didn't include
+  the unload hooks, but it did affect some other drivers.
+
+- Changed default scan_all_linux_kernels setting from "false" to "true",
+  and commented the option out in refind.conf-sample. This should not
+  affect most people, since refind.conf-sample had this option commented
+  out, and most rEFInd users either use it that way or don't have Linux
+  kernels installed at all. I've made this change because I want rEFInd to
+  "do the right thing" by default in as many cases as possible. For a while
+  now, rEFInd has been excluding non-bootable files from its menu, and most
+  kernels "in the wild" now include the EFI stub. Thus, enabling this
+  support by default seems worthwhile. If you prefer to not scan Linux
+  kernels by default, simply uncomment the "scan_all_linux_kernels" line
+  and ensure it's set to "false".
+
+0.8.2.1 (6/8/2014):
+-------------------
+
+- Removed stray bit of debugging code that caused a prompt to press a
+  key to appear at rEFInd startup.
+
+0.8.2 (6/8/2014):
+-----------------
+
+- Changed behavior when default_selection is not set: It now boots the
+  previously-booted loader, assuming it's still available; if not, rEFInd
+  boots the first loader (as it does now). Behavior is unchanged if
+  default_selection is set. Note that this behavior depends on the ability
+  of rEFInd to store an EFI variable in NVRAM. It therefore fails on
+  systems with flaky NVRAM storage. You can view the previously-booted
+  loader in the
+  /sys/firmware/efi/efivars/PreviousBoot-36d08fa7-cf0b-42f5-8f14-68df73ed3740
+  variable under Linux.
+
+- Added icon for Mageia Linux (os_mageia.png).
+
+- Fixed bug that could misidentify a not-quite-GUID as a GUID in a
+  manual boot stanza's "volume" line.
+
+- I've updated my personal build system, and therefore the rEFInd Makefiles
+  and related files, to use TianoCore UDK2014 rather than UDK2010.
+
+- Added "deep_uefi_legacy_scan" token. When not set (the default), rEFInd
+  does not modify EFI NVRAM settings when scanning for BIOS-mode boot
+  loaders on UEFI-based (non-Mac) computers. Some computers require
+  uncommenting this setting for rEFInd to reliably detect some BIOS-mode
+  boot devices. Passing "0", "off", or "false" as an option resets it to
+  the default value (useful in a loaded secondary configuration file to
+  override a setting in the main file).
+
+0.8.1 (5/15/2014):
+------------------
+
+- Fixed bug that could cause rEFInd to fail to detect boot loaders stored
+  on the root directory of a partition.
+
+- Added two new bitmap fonts to those distributed with rEFInd: Ubuntu Mono
+  and Nimbus Mono. Both come in 12-, 14-, 16-, and 24-point sizes.
+
+- Messages about pauses for scanning and re-scanning of boot loaders are
+  now suppressed when doing an initial delayed scan when scan_delay is 1
+  second.
+
+- Improved centering of legacy boot option descriptions on some systems'
+  screens.
+
+- Fixed bug that could cause a BIOS-mode boot to boot from an inappropriate
+  device if that device had an innately high boot priority (as set by the
+  firmware).
+
+- Changed icons from ICNS to PNG form. There are several reasons to do
+  this, all of them minor; but together they're enough to warrant a change.
+  PNG is more common, and therefore more accessible to most users --
+  particularly those who don't use OS X. The PNG files are smaller than
+  their ICNS equivalents. PNG supports a wider range of sizes (although I'm
+  not now using anything that ICNS doesn't support, I might in the future).
+  The icon-scaling support added a few versions ago makes ICNS's support
+  for multiple icon sizes relatively unimportant.
+
+- Reversed order of search for icons by extension: rEFInd now searches
+  for PNG files before ICNS files, rather than the other way around. This
+  makes it possible to override a volume icon for rEFInd by giving it the
+  name .VolumeIcon.png, even when a .VolumeIcon.icns file exists on the
+  volume and is used by OS X.
+
+- Fixed bug that caused .VolumeIcon.icns to take higher-than-intended
+  precedence in icon setting for OS X.
+
+- Chainloading to BIOS-mode boot loaders now works on UEFI-based PCs when
+  rEFInd is built with GNU-EFI, not just when built with Tianocore.
+
+0.8.0 (5/4/2014):
+-----------------
+
+- The "dont_scan_volumes" parameter now also works with legacy-boot
+  volumes. Unlike with EFI volumes, where the option you pass must exactly
+  match an entire volume name, when applied to legacy-boot volumes, it
+  matches any part of the description that appears beneath the item when
+  you select it in the rEFInd main menu.
+
+- Can now boot in legacy mode from second (and probably later) hard disks!
+
+- rEFInd now limits the length of the firmware name string shown in the
+  system information screen to 65 characters. This is done because at least
+  one EFI presents a longer string by default, and this causes the entire
+  information display to come up empty on 800x600 displays.
+
+- rEFInd now uses the partition's name (as stored in the GPT data
+  structures) as a fallback for the filesystem's name if the latter can't
+  be found. Exceptions are if the partition name is one of three generic
+  names used by GPT fdisk: "Microsoft basic data", "Linux filesystem", or
+  "Apple HFS/HFS+". These are ignored in favor of the descriptive fallback
+  (e.g., "20 GiB Btrfs volume")
+
+- It's now possible to specify a volume by partition GUID number in a
+  manual boot stanza. This should be more reliable (albeit also more
+  awkward) than using a filesystem number (such as fs0: or fs1:).
+
+- Fixed memory-allocation bug that could cause error message displays,
+  and possibly hangs, when re-scanning boot loaders.
+
+0.7.9 (4/20/2014):
+------------------
+
+- Attempt to fix rEFInd perpetually re-scanning after ejecting a disc on
+  some Macs.
+
+- Added check to remove redundant (or non-functional if Secure Boot is
+  active) kernel entries for Ubuntu, which is now including two versions of
+  kernels, one signed and the other unsigned.
+
+- Fixed bug in install.sh that could cause it to display error messages
+  if the dmraid utility was not installed.
+
+- The HFS+ driver now reports a correct volume name.
+
+- Fixed some EFI filesystem driver bugs that could cause lockups under
+  some circumstances. These bugs could affect any of the filesystem
+  drivers.
+
+- Added "gdisk" option to the "showtools" configuration file token. When
+  active, this adds gdisk.efi or gdisk_{arch}.efi, if present in the
+  EFI\tools directory, to the tools row.
+
+- Fixed mistaken identification of the MOK utility as the "MOK utility
+  utility."
+
+
+0.7.8 (3/9/2014):
+-----------------
+
+- Added "debian" directory to source, which facilitates creation of Debian
+  packages. Packages built in this way are built with GNU-EFI and don't run
+  any post-installation script, so although the rEFInd binaries are on the
+  hard disk, they aren't installed to be bootable; you must manually run
+  install.sh. Also, at least on Ubuntu, the Make.common file's /usr/lib64
+  references must be changed to /usr/lib. This is more of a proof of
+  concept and a "leg up" for distribution maintainers than anything else.
+
+- Two new options, big_icon_size and small_icon_size, set the size of
+  the first-row OS icons and of the second-row tool icons, respectively.
+  The big_icon_size option also indirectly sets the size of disk-type
+  badges; they're 1/4 the size of the big icons. Default values are 128 and
+  48, respectively, to match the actual icon files provided with rEFInd. If
+  the icon you're using is of a different size than you've specified,
+  rEFInd scales it. For best quality, you should both provide icons drawn
+  to the right size and set the icon sizes in refind.conf.
+
+- rEFInd now automatically scales icons to fit the standard icon sizes.
+  This won't have any effect with the icons that come with rEFInd, but it
+  can help if you want to use another icon, since you needn't scale it in a
+  graphics program before using it. Note that rEFInd uses bitmap icons, so
+  scaling by a huge amount (say, a 16x16 icon to fit the standard 128x128
+  OS icon) is not likely to look good.
+
+- Added new option, banner_scale, that tells rEFInd how to handle banners:
+  Set to "noscale" (the default), banners are not scaled, although they'll
+  be cropped if they're too big for the display. This is the same as the
+  behavior in previous versions. Set to "fillscreen", rEFInd now scales the
+  banner image (larger or smaller) to fill the display.
+
+- Adjusted the post-installation script in refind.spec (used to generate
+  RPMs, and therefore also indirectly Debian packages) to search for
+  existing shim program files under the filesnames shim.efi and shimx64.efi
+  rather than just shim.efi. Ubuntu uses shimx64.efi, so Debian packages
+  were failing to detect Ubuntu's shim in previous versions. (Note,
+  however, that Ubuntu's early shim 0.1 is unsuitable for use with rEFInd
+  The newer 0.4 version that's in the repositories now should work fine;
+  it's only when installing on an older system that's NOT been updated that
+  problems might arise.
+
+0.7.7 (1/3/2014):
+-----------------
+
+- Can now specify complete paths, optionally including volumes, in
+  dont_scan_files.
+
+- Added shimx64.efi to the default dont_scan_files list.
+
+- Added windows_recovery_files token, to specify what program(s) launch a
+  Windows recovery utility; and the "windows_recovery" option to
+  "showtools," to control whether or not to display the Windows recovery
+  utility on the second row of icons.
+
+- The use_graphics_for, also_scan_dirs, dont_scan_dirs, dont_scan_files,
+  and scan_driver_dirs tokens in refind.conf now support "+" as the first
+  option, which causes the remaining options to be added to the default
+  value rather than replacing that value. (This has no practical effect for
+  scan_driver_dirs, though, since it has a null default value.)
+
+- Added support for specifying the configuration file at program launch,
+  via the "-c" parameter, as in "refind_x64.efi -c foo.conf" to use the
+  foo.conf file as the main configuration file.
+
+- Scans of ext2/3/4fs and ReiserFS partitions now omit partitions with
+  duplicate filesystem UUIDs. These are likely parts of RAID arrays and so
+  would have the same boot loaders or kernels as the first one with a given
+  UUID.
+
+- Added feature in install.sh: Script now tries to locate and mount an ESP
+  in Linux, if it's currently unmounted.
+
+- Fixed bug in mkrlconf.sh and install.sh that caused a stray line break
+  and PARTUUID= specification to appear in generated refind_linux.conf file
+  under some circumstances.
+
+0.7.6 (12/15/2013):
+-------------------
+
+- Added support for multiple "default_selection" targets. These MUST be
+  comma-separated AND enclosed in quotes, as in:
+  default_selection "fred,ginger"
+  This example will launch "fred" by default if it's available; and if
+  it's not, rEFInd will attempt to launch "ginger" as the default.
+
+- Added support for time-sensitive "default_selection" setting. This token
+  may now have either one or three options. If one, it's interpreted as it
+  has been in the past, as setting a default that's independent of times.
+  If you follow this default by two times, however, those are interpreted
+  as the start and end times (in 24-hour format) for a default setting. For
+  instance, "default_selection foo 8:00 17:00" causes foo to be the default
+  from 8:00 (AM) to 17:00 (aka 5:00 PM). You can include multiple
+  "default_selection" lines to set different defaults for a variety of
+  times. If they're in conflict, the last one takes precedence. Note that
+  times are hardware clock's native value, which may be local time or UTC,
+  depending on your computer.
+
+- Added support for a blank-screen startup: Set "screensaver -1" and the
+  screen saver will be initialized when rEFInd starts. If you set a low
+  "timeout" value, the result will be a boot straight to the default OS
+  unless you hit a key soon after rEFInd starts. Once you hit a key, the
+  screensaver will be disabled.
+
+- Added --ownhfs {target} option to install.sh. This option causes rEFInd
+  to install to an HFS+ partition in a way that's more consistent with the
+  way the Mac's native boot loader is installed. Note that you should NOT
+  install to an already-bootable partition with this option, since it will
+  overwrite the existing boot loader, which would render OS X unbootable.
+
+0.7.5 (11/10/2013):
+-------------------
+
+- Fixed bug that caused unbootable exFAT partitions to show up as
+  bootable on Macs with BIOS/CSM/legacy boot options enabled.
+
+- Fixed bug in install.sh that caused installs to the ESP on recent
+  versions of OS X to fail.
+
+- Fixed bug that caused rEFInd to hang on some Macs when multiple EFI
+  drivers were present.
+
+- Fixed bug that caused clear to default gray screen when launching OSes
+  with 'use_graphics_for' enabled, even when the rEFInd background is not
+  gray. Now rEFInd clears to the same background color used in its menu.
+  When launching OS X, though, the OS X boot loader will itself clear to
+  gray a second or so later; and when launching Linux, it will clear to
+  black a second or so later.
+
+0.7.4.1 (8/25/2013):
+--------------------
+
+- My initial 0.7.4 release broke legacy-boot ability on Macs, so I quickly
+  released this version using the original 0.7.4 filenames to fix the
+  problem.
+
+0.7.4 (8/25/2013):
+------------------
+
+- Fixed options passing to loader to include loader's filename as the first
+  option. This omission had no effect on most boot loaders, but caused
+  VMware's mboot64.efi to fail.
+
+- Added support for memtest86 as second-row option. Program must be
+  stored in EFI/tools, EFI/tools/memtest, EFI/tools/memtest86, EFI/memtest,
+  or EFI/memtest86; and must use the name memtest86.efi, memtest86_x64.efi,
+  memtest86x64.efi, or bootx64.efi (changing "x64" to "ia32" on IA-32
+  systems). The memtest86 program is scanned for when the "showtools"
+  option includes the "memtest" or "memtest86" token, which it does by
+  default.
+
+- Added space to end of "Boot %s from %s" string; enables adding a space
+  to the end of the "default_selection" item (in quotes) to set a default
+  that matches a volume name that's identical to another one except for
+  extra characters at the end of the non-wanted volume's name.
+
+- Fixed bug that could cause rEFInd to hang when launching boot loaders
+  under some conditions. (Launching from Firewire drives on Macs is the
+  known case, but there may be others.)
+
+0.7.3 (8/7/2013):
+-----------------
+
+- Fixed bug that caused missing media-type badges on BIOS-mode boot
+  loaders on Macs.
+
+- Fixed bug that caused failure when launching BIOS-mode OSes on Macs.
+
+0.7.2 (8/6/2013):
+-----------------
+
+- Fixed bug that caused display glitches in the final entry on the first
+  row of icons if the second row of icons was empty.
+
+- Fixed bug that could cause incorrect scanning or even a rEFInd crash when
+  using volume specification in also_scan_dirs token.
+
+- Added protection against loading invalid drivers and other EFI programs.
+  (Some EFIs crash when attempting to load such drivers and programs.)
+
+- Added PreLoader.efi and shim-fedora.efi to default dont_scan_files list;
+  it's now "shim.efi, shim-fedora.efi, PreLoader.efi, TextMode.efi,
+  ebounce.efi, GraphicsConsole.efi, MokManager.efi, HashTool.efi,
+  HashTool-signed.efi".
+
+- Added icon for Funtoo Linux.
+
+- Fixed reading of volume badges from user-specified icons directory, which
+  was broken.
+
+- Fixed handling of /.VolumeBadge.icns (or /.VolumeBadge.png) files, which
+  was broken.
+
+0.7.1 (7/8/2013):
+-----------------
+
+- Fixed build problem with recent development versions of EDK2.
+
+- Added scan for Boot Repair's backup of the Windows boot loader
+  (bkpbootmgfw.efi). If found, give separate entries for it and for
+  bootmgfw.efi, each with its own descriptive text label.
+
+- Fixed also_scan_dirs; used to have bug that caused it to ignore
+  volume specification, if present.
+
+- Fixed bug in driver cache that caused Btrfs driver to hang sometimes.
+
+0.7.0 (6/27/2013):
+------------------
+
+- Added Btrfs signature to rEFInd, so that it can identify the filesystem
+  type for volumes that lack labels.
+
+- Changed some critical filesystem driver pointers from 32-bit to 64-bit.
+  This *SHOULD* enable use of over-2TiB filesystems (for those filesystems
+  that support such large volumes). This capability is largely untested,
+  though.
+
+- Added a cache to the filesystem driver core, and therefore to all the
+  filesystem drivers. This cache greatly improves performance in
+  VirtualBox, and offers modest performance improvements on a few "real"
+  computers. The most dramatic improvement is on ext2/3fs under VirtualBox:
+  Loading a kernel and initrd used to take ~200 seconds on my system, but
+  now takes ~3 seconds! On most "real" hardware, the improvement is much
+  less dramatic -- an improvement of a second or less, presumably because
+  of cacheing within the EFI or on the hard disk itself.
+
+- Filter boot loaders based on a test of their validity; keeps out Linux
+  kernels without EFI stub loader code, loaders for the wrong architecture,
+  non-EFI loaders, etc.
+
+- New Btrfs driver, contributed by Samuel Liao based on GRUB 2.00 Btrfs
+  code.
+
+0.6.12 (6/18/2013):
+-------------------
+
+- Changed the 64-bit EFI shell included in the CD-R and USB flash drive
+  images to a version 2 shell that should support the "bcfg" command.
+
+- Added support for PreBootloader to refind.spec's built-in installation
+  script.
+
+- Added support for the Linux Foundation's PreLoader to install.sh. It's
+  treated just like shim, including using the --shim option (or, now,
+  --preloader); but it searches for and copies HashTool.efi rather than
+  MokManager.efi, and filenames are adjusted appropriately.
+
+- Added code to determine Linux root filesystem from /etc/fstab file, if
+  it's on the same partition as the kernel and if the refind_linux.conf
+  file is not available. This enables rEFInd to boot Linux without any
+  rEFInd-specific configuration files on some (but not all) systems.
+
+0.6.11 (5/13/2013):
+-------------------
+
+- New feature: rEFInd now ignores symbolic links to files on filesystems
+  that support them. This prevents the "vmlinuz" symbolic link that some
+  distributions create in the root directory from appearing in the loader
+  list. Note that this does NOT affect symbolic links to directories.
+
+- Added icons for Lubuntu and Kubuntu.
+
+- Improved the install.sh script so that it does a better job dealing with
+  directory names that contain spaces.
+
+- rEFInd now tries to guess the Linux distribution type based on the kernel
+  filename (Fedora and RHEL only) or the "ID" or "NAME" variables in
+  /etc/os-release on the kernel's partition. None of these is guaranteed to
+  work. A fallback of the Tux penguin icon remains in place in case rEFInd
+  can't find anything substantive enough for a guess.
+
+- Added "EFI\opensuse" to the locations searched for MOK utilities, since
+  OpenSUSE now uses that name.
+
+- Renamed "Reboot to Firmware User Interface" to "Reboot to Computer Setup
+  Utility" in menu.
+
+- Fixed bug in gptsync that caused it to hang if the disk had too few GPT
+  partitions to fill the MBR.
+
+0.6.10 (5/5/2013):
+------------------
+
+- Added support for "screensaver" token. If set to a positive integer, this
+  causes the screen to blank after the specified number of seconds of
+  inactivity. Pressing most keys (unfortunately NOT including Shift, Alt,
+  or Ctrl) will restore the display and restart the screen saver timeout.
+
+- Added icon for ChromeOS (os_chrome.icns in the icons subdirectory).
+  ChromeBooks reportedly boots using the fallback filename, but if a user
+  wants to install rEFInd on a ChromeBook, renaming the original EFI/BOOT
+  directory to EFI/chrome and then installing rEFInd in the fallback
+  filename will bring up this new icon for ChromeOS.
+
+- Added new option to reboot the computer into the firmware's user
+  interface. This option is active by default, or can be set via the
+  "firmware" option to the "showtools" token in refind.conf. It works
+  on only some computers, though; older computers lack this feature, and
+  when rEFInd is told to use this feature on such computers, the directive
+  is quietly ignored.
+
+- Upgraded LodePNG library from version 20121216 to 20130415 and
+  restructured rEFInd-specific modifications to simplify future upgrades.
+
+- Replaced hexadecimal error code with description if an error is
+  encountered when saving a screen shot.
+
+- Enable multiple screen shots: Rather than naming all screen shots
+  "screenshot.bmp", the name is now "screenshot_###.bmp", where "###" is a
+  sequence number, starting with "001".
+
+0.6.9 (4/25/2013):
+------------------
+
+- Modified default banner to include the new rEFInd icon, provided by Erik
+  Kemperman.
+
+- Worked around a suspected firmware bug that caused rEFInd 0.6.6 to 0.6.8
+  to hang at startup on some systems (DUET and some Macs).
+
+- Modified rEFInd to search for gptsync under the names gptsync.efi and
+  gptsync_{arch}.efi, where {arch} is ia32 or x64. (Previous versions
+  searched only for gptsync.efi.)
+
+- Added gptsync program from rEFIt project, but with some changes to
+  improve flexibility and make it less likely that UEFI users will
+  accidentally trash their systems.
+
+- Changed timeout code so that the timeout continues if the keyboard is
+  disconnected. This can help in booting a headless server or a system with
+  a bluetooth or other keyboard that's not recognized by the EFI.
+
+0.6.8 (3/18/2013):
+------------------
+
+- Added workaround for presumed EFI bug that was causing "Invalid
+  Parameter" errors when scanning for boot loaders on some computers.
+
+- Added search for an EFI shell called shell.efi in the root directory
+  (previously this name was only accepted in EFI\tools).
+
+- Fixed bug in install.sh that caused it to fail on some systems (Fedora
+  18, for instance) because of a problem identifying the ESP.
+
+- Fixed bug that caused icons named after boot loaders to not be used.
+
+0.6.7 (2/3/2013):
+-----------------
+
+- Added a more explicit error message summarizing options when a launch of
+  a program results in a Secure Boot failure.
+
+- Changed MOK tool detection to scan all volumes, not just the rEFInd
+  home volume. This is desirable because the Linux Foundation's HashTool
+  can only scan its own volume, making it desirable to place copies of this
+  program on every volume that holds EFI boot loader binaries.
+
+- Added support for launching the Linux Foundation HashTool as a means of
+  managing MOKs (or MOK hashes, at any rate).
+
+- Fixed bug that caused rEFInd to present an entry for itself as a
+  Microsoft OS if it was launched as EFI/Microsoft/Boot/bootmgfw.efi.
+
+- Fixed bug that caused dont_scan_volumes option to be added to
+  also_scan_dirs list.
+
+- Fixed dont_scan_volumes so that it works with OS X boot loaders.
+
+- Fixed broken mixing of PNG and ICNS icons when using a user-specified
+  icons directory -- previously, an ICNS file in the default directory
+  would override a PNG file in the user-specified directory.
+
+0.6.6 (1/26/2013):
+------------------
+
+- rEFInd now ignores the fallback boot loader (EFI/BOOT/bootx64.efi or
+  EFI/BOOT/bootia32.efi) if it's identical to another boot loader on
+  the same volume. This is intended to help unclutter the display on
+  systems that run Windows, since Windows tends to duplicate its own boot
+  loader under the fallback name.
+
+- Added new "font" token to refind.conf, which enables specifying a font in
+  the form of a PNG file. This file must contain monospace glyphs for the
+  95 characters from ASCII 32 to 126 (space through tilde), inclusive, plus
+  a glyph to be displayed for characters outside of this range, for a total
+  of 96 glyphs.
+
+- Replaced the old font (inherited from rEFInd) with an anti-aliased
+  version of Luxi Mono Regular 14 point.
+
+- Fixed bug that caused rEFInd to ignore manual boot stanzas in files
+  included via the "include" token in refind.conf.
+
+- Fixed bug that caused ASSERT error on some systems (and conceivably a
+  crash on startup on some) when default_selection line in refind.conf was
+  commented out or empty.
+
+- Fixed bug that caused "Binary is whitelisted" message to persist on
+  screen after loading MOK-signed drivers in Secure Boot mode.
+
+- Fixed bug that caused rEFInd to ignore the "icon" token in refind.conf
+  manual boot stanzas.
+
+- Fixed bug in install.sh that caused the script to fail to update
+  drivers when rEFInd was installed in EFI/BOOT/.
+
+0.6.5 (1/16/2013):
+------------------
+
+- Improved text color support: rEFInd now uses black text against light
+  backgrounds and white text against dark backgrounds.
+
+- Added support for PNGs as banners, icons, and selectors.
+
+- Added icon for ALT Linux.
+
+- Added "safemode" option to "hideui" token, to hide option to boot into
+  safe mode for OS X ("-v -x" option to boot.efi).
+
+- Added icon for Haiku (os_haiku.icns).
+
+- Enable transparency of icons & main-menu text when the banner icon is
+  sized to cover these areas.
+
+- Fixed bug that could cause rEFInd to crash if fed a banner image that's
+  too big. Note that "too big" can be substantially smaller than the screen
+  resolution!
+
+0.6.4 (1/8/2013):
+-----------------
+
+- Revised install.sh to copy ext2fs driver, rather than ext4fs driver, for
+  ext2/3 filesystems. This can help keep non-functional entries from links
+  from /vmlinuz to /boot/vmlinuz out of the menu if the system uses ext4fs
+  on root and ext2fs or ext3fs on /boot.
+
+- Fixed a couple of memory management bugs that cause rEFInd to hang at
+  startup on some systems.
+
+0.6.3 (1/6/2013):
+-----------------
+
+- Added the ability to specify a volume name or number in the
+  "dont_scan_dirs" and "also_scan_dirs" tokens.
+
+- Fixed a bug that caused removable EFI media to not appear in scan lists
+  if rEFInd was installed as EFI/BOOT/boot{arch}.efi on a hard disk.
+
+- Modified ISO-9660 driver so that it can handle discs with other than
+  2048-byte sectors. This makes it useful for reading "hybrid ISO" images
+  burned to USB flash disks.
+
+- New mvrefind.sh script to move a rEFInd installation between a standard
+  location (typically EFI/refind) and one of the fallback locations
+  (EFI/BOOT or EFI/Microsoft/Boot). It can also do more exotic locations.
+
+- The install.sh script now installs to EFI/BOOT/bootx64.efi or
+  EFI/Microsoft/Boot/bootmgfw.efi if it's run in BIOS mode. This is
+  intended to give some chance of producing a bootable installation should
+  a user accidentally install Linux in EFI mode and then install rEFInd
+  from that installation.
+
+- The install.sh script now tries to find an existing rEFInd installation
+  and upgrade it, even if it's in EFI/BOOT or EFI/Microsoft/Boot rather
+  than in EFI/refind.
+
+- New "--yes" option to install.sh to help with unattended or automated
+  installations (as from an RPM or Debian package).
+
+0.6.2 (12/30/2012):
+-------------------
+
+- Inclusion of a sample refind.spec file for the benefit of RPM
+  distribution maintainers who might want to include rEFInd. It's a bit
+  rough, but it gets you a good chunk of the way there....
+
+- The EFI filesystem drivers can now be built with the GNU-EFI toolkit as
+  well as with the TianoCore EDK2. See the BUILDING.txt file for details on
+  how to build them with either toolkit. This improvement doesn't affect
+  users of my binary packages, but it should make it easier for Linux
+  distributions to adopt rEFInd into their package systems.
+
+- Tweaked refind.inf file for better build results using "native" TianoCore
+  EDK2 build process (vs. the Makefile-based build process that I use under
+  Linux). This won't affect those who use my binary builds or build under
+  Linux with the "make" command.
+
+- Fixed bug that prevented Secure Boot launches from working when rEFInd
+  was built with GNU-EFI rather than the TianoCore EDK2.
+
+- Substantial reworking of Secure Boot code, based on James Bottomley's
+  PreLoader program. This new code eliminates the limitation of launching
+  just one driver in Secure Boot mode and is likely to be more reliable
+  with future or obscure boot loaders. It should also work with non-x86-64
+  systems, although this relies on a platform-specific shim program, which
+  to date exists only for x86-64. The basic features are the same as before
+  -- rEFInd relies on shim for authentication functions and will launch
+  programs that are signed by Secure Boot keys, shim keys, or MOKs.
+
+- Altered default for "textmode" option (when it's commented out) to not
+  adjust the text mode at all. (Prior versions set it to mode 0 by
+  default.)
+
+0.6.1 (12/21/2012):
+-------------------
+
+- Added "--root" option to install.sh, to enable installation of rEFInd
+  to something other than the currently-running OS. This is intended for
+  use on emergency discs.
+
+- Thanks to Stefan Agner, the ext4fs driver now supports the "meta_bg"
+  filesystem feature, which distributes metadata throughout the disk. This
+  feature isn't used by default, but can be set at filesystem creation time
+  by passing the "-O meta_bg,^resize_inode" option to mke2fs. (Using
+  "^resize_inode" is necessary because meta_bg is incompatible with
+  resize_inode, which IS used by default.) This feature can be used on
+  ext3fs and ext2fs as well as on ext4fs, so the ext4fs driver can now
+  handle some ext3fs and ext2fs partitions that the ext2fs driver can't
+  handle.
+
+- Fixed some screen resolution-setting bugs.
+
+- Added the "words" that make up a filesystem's label (delimited by spaces,
+  dashes, or underscores) to the list of bases used to search for OS icons.
+  For instance, if the filesystem's label is "Arch", rEFInd searches for
+  os_Arch.icns; if it's "Fedora 17", it searches for os_Fedora.icns and
+  os_17.icns; and if it's "NEW_GENTOO", it searches for os_NEW.icns and
+  os_GENTOO.icns.
+
+- Refined hints displays to be more context-sensitive, particularly in text
+  mode.
+
+- Instead of displaying a blank filesystem label when a filesystem has
+  none, rEFInd now displays the size and/or type of the filesystem, as in
+  "boot EFI\foo\bar.efi from 200 MiB ext3 volume" rather than "boot
+  EFI\foo\bar.efi from".
+
+- Fixed a bug that caused the screen to clear after displaying an error
+  message but before displaying the "Hit any key to continue" message when
+  a boot loader launch failed.
+
+0.6.0 (12/16/2012):
+-------------------
+
+- Fixed a memory allocation bug that could cause a program crash when
+  specifying certain values with the "also_scan_dirs", "dont_scan_volumes",
+  "dont_scan_dirs", "dont_scan_files", and "scan_driver_dirs" refind.conf
+  options.
+
+- Modified Linux kernel initrd-finding code so that if an initrd is
+  specified in refind_linux.conf, rEFInd will not add any initrd it finds.
+  This enables an override of the default initrd, and is likely to be
+  particularly helpful to Arch Linux users.
+
+- Added ext4fs driver!
+
+- Made "boot" the default value for "also_scan_dirs".
+
+- Added identifying screen header to line editor.
+
+- Fixed bug that caused rEFInd's display to be mis-sized upon return
+  from a program that set the resolution itself.
+
+- Adjusted "resolution" refind.conf parameter so that it can accept EITHER
+  a resolution as width and height OR a single digit as a UEFI mode number
+  (which is system-specific). This is done because some systems present the
+  same mode twice in their mode lists, perhaps varying in refresh rate,
+  monitor output, or some other salient characteristics; specifying the
+  mode number enables selecting the higher-numbered mode, whereas using
+  horizontal and vertical resolution values selects the lowest-numbered
+  mode.
+
+- Added "textmode" refind.conf parameter to set the text mode used in
+  text-only displays, and for the line editor and boot-time handoff
+  display even in graphics mode.
+
+- Fixed bug that caused tools (shell, etc.) to launch when they were
+  highlighted and F2 or Insert was pressed.
+
+- Added "editor" option to the "hideui" token in refind.conf, which
+  disables the boot options editor.
+
+- Added hints text to rEFInd main menu and sub-menus. This can be disabled
+  by setting the new "hints" option to the "hideui" token in refind.conf.
+
+- Added "boot with minimal options" entry to refind_linux.conf file
+  generated by install.sh. This entry boots without the options extracted
+  from the /etc/default/grub file.
+
+- Added keys subdirectory to main distribution, to hold public Secure
+  Boot/shim keys from known sources.
+
+- Changed install.sh --drivers option to --alldrivers, added new
+  --nodrivers option, and made the default on Linux to install the one
+  driver that's used on /boot (or the root filesystem if /boot isn't a
+  separate partition). Of course, this won't install a non-existent driver,
+  and it also won't work properly if run from an emergency disk unless you
+  mount a separate /boot partition at that location.
+
+- Fixed bug in install.sh that prevented creation of refind_linux.conf file
+  on Linux systems.
+
+0.5.1.1 (12/12/2012):
+---------------------
+
+- Fixed bug in install.sh that prevented it from working on OS X.
+
+0.5.1 (12/11/2012):
+-------------------
+
+- Added support for "0" options to "textonly" and "scan_all_linux_kernels"
+  to reverse the usual meaning of these tokens. This is useful for
+  including these options in a secondary configuration file called with the
+  new "include" token to override a setting set in the main file.
+
+- Added "include" token for refind.conf, to enable including a secondary
+  configuration file from a primary one.
+
+- Modified install.sh so that it creates a simple refind_linux.conf file in
+  /boot, if that file doesn't already exist and if install.sh is run from
+  Linux. If that directory happens to be on a FAT, HFS+, ext2fs, ext3fs, or
+  ReiserFS volume, and if the necessary drivers are installed, the result
+  is that rEFInd will detect the Linux installation with no further
+  configuration on many systems. (Some may still require tweaking of kernel
+  options, though; for instance, adding "dolvm" on Gentoo systems that use
+  LVM.)
+
+- Added --shim and --localkeys options to install.sh to help simplify setup
+  on systems with Secure Boot active.
+
+- Fixed (maybe) bug that caused resolution options to not be displayed on
+  recent Macs with GOP graphics when specifying an invalid resolution in
+  refind.conf.
+
+- Fixed bug that caused some programs (EFI shells, in particular) to hang
+  when launching on some systems (DUET, in particular).
+
+- Implemented a fix to enable ELILO to launch with Secure Boot active.
+  This fix might help with some other boot loaders in Secure Boot mode,
+  too, but I don't know of any specifics.
+
+0.5.0 (12/6/2012):
+------------------
+
+- Added the ability to include quote marks ('"') in refind.conf and
+  refind_linux.conf tokens by doubling them up, as in:
+  "ro root=/dev/sda4 some_value=""this is it"""
+  This example results in the following string being passed as an
+  option:
+  ro root=/dev/sda4 some_value="this is it"
+
+- Changed refind.conf-sample to uncomment the scan_all_linux_kernels
+  option by default. If this option is deleted or commented out, the
+  program default remains to not scan all Linux kernels; but with
+  increasing numbers of distributions shipping with kernels that include
+  EFI stub loader support, setting the configuration file default to scan
+  for them makes sense.
+
+- Modified the "resolution" token so that it affects text mode as well
+  as graphics mode. On my systems, though, the actual text area is still
+  restricted to an 80x25 area. (This seems to be a firmware limitation; my
+  EFI shells are also so limited.)
+
+- Fixed a bug that caused the options line editor to blank out lines that
+  were not actually edited.
+
+- Added support for using Matthew Garrett's Shim program and its Machine
+  Owner Keys (MOKs) to extend Secure Boot capabilities. If rEFInd is
+  launched from Shim on a computer with Secure Boot active, rEFInd will
+  launch programs signed with either a standard UEFI Secure Boot key or a
+  MOK. For the moment, this feature works only on x86-64 systems.
+
+- Added new "dont_scan_files" (aka "don't_scan_files") token for
+  refind.conf. The effect is similar to dont_scan_dirs, but it creates a
+  blacklist of filenames within directories rather than directory names.
+  I'm initially using it to place shim.efi and MokManager.efi in the
+  blacklist to keep these programs out of the OS list. (MokManager.efi is
+  scanned separately as a tool; see below.) I've moved checks for
+  ebounce.efi, GraphicsConsole.efi, and TextMode.efi to this list. (These
+  three had previously been blacklisted by hard-coding in ScanLoaderDir().)
+
+- Added the directory from which rEFInd launched to dont_scan_dirs. This
+  works around a bug in which rEFInd would show itself as a bogus Windows
+  entry if it's installed as EFI/Microsoft/boot/bootmgfw.efi.
+
+- Added support for launching MokManager.efi for managing the Machine Owner
+  Keys (MOKs) maintained by the shim boot loader developed by Fedora and
+  SUSE. This program is scanned and presented as a second-row tool.
+
+- Added support for Apple's Recovery HD partition: If it's detected, a new
+  icon appears on the second row. This icon can be removed by explicitly
+  setting the "showtools" option in refind.conf and excluding the
+  "apple_recovery" option from that line.
+
+- Fixed bug that caused text-mode ("textonly" refind.conf option enabled)
+  menu entries to be right-aligned rather than left-aligned when rEFInd was
+  compiled with the TianoCore EDK2.
+
+- Added "--usedefault {devicename}" and "--drivers" options to the
+  install.sh script and changed the "esp" option to "--esp". 
+
+0.4.7 (11/6/2012):
+------------------
+
+- Added an icon for gummiboot.
+
+- Added a boot option editor: Pressing the Insert or F2 key from a boot
+  tag's options menu opens a simple text-mode line editor on which the boot
+  options may be edited for a one-time boot with altered options.
+
+- Modified the "scan_delay" feature to delay and then perform a re-scan,
+  which may work better than the first attempt at this feature (which I'm
+  told isn't working as planned).
+
+- Modified rEFInd to add a space after the command-line options only when
+  launching Mac OS X. On some early Macs, the extra space (which had been
+  present by default, as a carryover from rEFIt) causes problems when
+  booting Linux kernels from FAT partitions.
+
+0.4.6 (10/6/2012):
+------------------
+
+- Fixed some minor memory management issues.
+
+- Added new "scan_delay" feature to impose a delay before scanning
+  for disks.
+
+- Changed default "scanfor" option from internal-external-optical to either
+  internal-external-optical-manual (for non-Macs) or
+  internal-hdbios-external-biosexternal-optical-cd-manual (for Macs). I've
+  done this for two reasons:
+  - Many Mac users have been confused by the fact that rEFInd needs
+    reconfiguration to detect Windows (or Linux installed in BIOS mode),
+    since rEFIt scans BIOS devices by default. Adding the BIOS options as
+    default for them should help them.
+  - Adding the "manual" option enables users to simply add manual boot
+    stanzas and have them work, which is more intuitive. Adding the
+    "manual" option will have no effect unless manual stanzas are created
+    or uncommented, so this part of the change won't affect users' working
+    default configurations.
+
+- Added new legacy (BIOS) boot support for UEFI-based PCs.
+
+0.4.5 (8/12/2012):
+------------------
+
+- Fixed bug that caused a failure to boot BIOS-based OSes on Macs.
+
+- Fixed bug in install.sh that caused it to fail to detect rEFItBlesser.
+
+0.4.4 (6/23/2012):
+------------------
+
+- Fixed bug that caused filesystem labels to be corrupted by rEFInd on
+  32-bit systems.
+
+- Fixed bug that caused filesystem labels to be truncated in the drivers
+  on 32-bit systems.
+
+- Fixed bug in use_graphics_for option parsing that caused most options
+  to set graphics mode for OS X and/or Linux but not other boot
+  loaders/OSes.
+
+- Tweaked install script to better isolate the ESP under OS X.
+
+0.4.3 (6/21/2012):
+------------------
+
+- rEFInd now supports compilation using the TianoCore UDK2010/EDK2
+  development kit in addition to GNU-EFI.
+
+- Added new "use_graphics_for" option to control which OSes to boot in
+  graphics mode. (This effect lasts for a fraction of a second on most
+  systems, since the boot loader that rEFInd launches is likely to set
+  graphics or text mode itself.)
+
+- Graphics-mode booting now clears the screen to the current rEFInd
+  background color (rather than black) and does NOT display boot messages.
+  The intent is for a smoother transition when booting OS X, or perhaps
+  other OSes that don't display boot loader messages. In practice, this
+  effect will be tiny for many OSes, since the boot loader generally clears
+  the screen within a fraction of a second of being launched; but the
+  "flicker" of a rEFInd message in that time can sometimes be distracting.
+
+- Filesystem drivers now work on EFI 1.x systems, such as Macs.
+
+- Removed "linux.conf" as a valid alternative name for "refind_linux.conf"
+  for holding Linux kernel options. The kernel developers plan to use
+  "linux.conf" themselves.
+
+0.4.2 (6/3/2012):
+-----------------
+
+- Added a message to install.sh when run on Macs to remind users to update
+  the "scanfor" line in refind.conf if they need to boot BIOS-based OSes
+  via rEFInd.
+
+- Modified install.sh script to be smarter about running efibootmgr on
+  Linux. It now uses the whole path to the rEFInd binary as a key to
+  determine whether an existing entry exists, rather than just the filename
+  portion. If an entry exists and is the first entry in the boot order, the
+  script does nothing to the NVRAM entries. If such an entry exists but is
+  not the default, the script deletes that entry and creates a new one
+  (implicitly making it the first in the boot order). If such an entry does
+  not exist, the script creates a new one (again, making it the first in
+  the boot order).
+
+- Added "dont_scan_dirs" configuration file option, which adds directories
+  to a "blacklist" of directories that are NOT scanned for boot loaders.
+
+0.4.1 (5/25/2012):
+------------------
+
+- Added "scanning for new boot loaders" message to the re-scan function
+  (hitting Esc at the main menu). It usually flashes up too quickly to
+  be of importance, but if the scan function takes a while because of
+  access to a CD that must be spun up, it should make it clear that the
+  system hasn't hung.
+
+- Modified install.sh script to detect rEFItBlesser on Macs, and if
+  present, to ask the user if it should be removed.
+
+- Cleaned up the Make.common file for the filesystem drivers.
+
+- Changed HFS+ driver to return volume label of "HFS+ volume" rather than
+  an empty label. (The driver doesn't currently read the real volume
+  label.)
+
+- Fixed bug that could cause rEFInd to appear in its own menu after
+  running a shell and then re-scanning for boot loaders.
+
+0.4.0 (5/20/2012):
+------------------
+
+- Inclusion of drivers for ISO-9660, HFS+, ReiserFS, and ext2fs. Most of
+  these drivers originated with rEFIt, although the HFS+ driver seems to
+  have come from Oracle's VirtualBox, with some files from Apple. I hadn't
+  included these drivers previously because the build process proved
+  challenging. As it is, they don't work on my Mac Mini, I suspect because
+  the build process with the UDK2010 development kit may not work with the
+  EFI 1.x that Apple uses.
+
+- Addition of support for drivers in the "drivers_{arch}" subdirectory of
+  the main rEFInd binary directory (e.g., "drivers_x64" or "drivers_ia32").
+  Drivers may continue to be placed in the "drivers" subdirectory.
+
+- Added new feature to eject CDs (and other removable media): Press F12 to
+  eject all such media. This function works only on some Macs, though (it
+  relies on an Apple-specific EFI extension, and this extension isn't even
+  implemented on all Macs, much less on UEFI-based PCs).
+
+- Fixed a problem that could cause GRUB 2 to fail to read its configuration
+  file when launched from rEFInd.
+
+0.3.5 (5/15/2012):
+------------------
+
+- Removed the GRUB 2 detection "reciped" added with 0.3.2, since I've
+  received reports that it's not working as intended.
+
+- Added re-scan feature: Press the Esc key to have rEFInd re-read its 
+  configuration file, tell the EFI to scan for new filesystems, and re-scan
+  those filesystems for boot loaders. The main purpose is to enable
+  scanning a new removable medium that you insert after launching rEFInd;
+  however, it can also be used to immediately implement changes to the
+  configuration file or new drivers you load from an EFI shell.
+
+- Fixed a bug that could cause the scroll-right arrow to be replaced by the
+  scroll-left arrow under some circumstances.
+
+0.3.4 (5/9/2012):
+-----------------
+
+- Added new configuration file option: "icons_dir", which sets the name
+  of the subdirectory in which icons are found. See the documentation or
+  sample configuration file for a full description.
+
+- Modified Makefile to generate rEFInd binary that includes architecture
+  code -- refind_ia32.efi or refind_x64.efi, rather than the generic
+  refind.efi. This is done mainly to help the install.sh script. The
+  program can be named anything you like on the disk. (The generic name
+  refind.efi is used on unknown architectures.)
+
+- Improved install.sh script: Fixed bug on OS X 10.7 and enable it to be
+  used after building from source code (or via new "make install" Makefile
+  target).
+
+- Improved screen redraws to produce less flicker when moving among the
+  second-row tags or to the last tag on the first row.
+
+0.3.3 (5/6/2012):
+-----------------
+
+- Improved menu navigation:
+  - In graphics mode, left & right arrow keys move left & right, while up &
+    down arrows move between rows.
+  - Page Up and Page Down now move through chunks of visible tags (in both
+    text & graphics modes), jumping from one row to another only when at
+    the edge of the row. In text mode, the "rows" are broken down as in
+    graphics mode, but they aren't visibly distinguished on the screen.
+
+- Improved text-mode use: rEFInd now displays the proper number of entries
+  when first started in text mode and scrolling is done sensibly when too
+  many entries exist to fit on the screen.
+
+0.3.2 (5/4/2012):
+-----------------
+
+- Added the install.sh script to install rEFInd on Linux and Mac OS X
+  systems. This script must be run as root (or via sudo). It requires
+  no options, but on Mac OS X, passing it the "esp" option causes it
+  to install rEFInd on the computer's ESP rather than the default of the
+  currently OS X boot partition. (Under Linux, the default is to install to
+  the ESP.) Note that there may be some unusual cases in which this script
+  will fail to work.
+
+- Does a better job of clearing the screen when launching OSes in text
+  mode.
+
+- Added detection "recipe" for GRUB 2's BIOS Boot Partition.
+
+- Fixed bogus detection of ESPs created by Linux's mkdosfs utility or
+  Windows as  bootable partitions when "scanfor" includes BIOS scanning
+  options.
+
+
+0.3.1 (4/27/2012):
+------------------
+
+- Fixed bug that caused spurious "Unsupported while scanning the root
+  directory" messages under some conitions on Macs.
+
+- Modified loader scanning code to sort boot loader entries within a
+  directory by modification time, so that the most recently-modified loader
+  is first among those in a given directory. Thus, if you specify a
+  directory name (or volume name, for loaders stored in the root directory
+  of a volume) as the default_selection, the most recent of those loaders
+  will be the default. This is intended to help with Linux kernel
+  maintenance when using the EFI stub loader; set up this way, the most
+  recent kernel copied to your kernel directory will be the default,
+  obviating the need to adjust the refind.conf file when adding a new
+  kernel. If you want to change the default among those in the default
+  directory, you can use "touch" to adjust the modification timestamp.
+
+- Tweaked code to find loader-specific .icns file so that it finds files
+  for Linux kernels without .efi extensions. In this case, files should be
+  named the same as the kernels they match, but with .icns extensions. For
+  instance, bzImage-3.3.2 should have an icon called bzImage-3.3.2.icns.
+  (The old code would have looked for an icon called bzImage-3.3.icns.)
+
+- Eliminated bogus OS loader tags for filenames that end in ".icns" when
+  the scan_all_linux_kernels option is set.
+
+0.3.0 (4/22/2012):
+------------------
+
+- I'm officially upgrading this project's status from "alpha" to "beta" and
+  giving it a bump from 0.2.x to 0.3.0. This doesn't reflect any major
+  milestone with this version; rather, it reflects my sense that rEFInd has
+  been "out there" for a while, and although I've gotten bug reports,
+  they've been minor and/or have been fixed. The program still has known
+  bugs, but my impression is that it is, overall, usable by ordinary users.
+
+- Added "resolution" option to refind.conf, which enables setting the video
+  resolution. To use it, pass two numeric values, as in "resolution 1024
+  768" to use a 1024x768 video mode. Note that not all modes are supported.
+  If you specify a non-supported video mode on a UEFI system, a message
+  appears listing the supported video modes and you must then press a key
+  to continue, using the default video mode (usually 800x600).
+  Unfortunately, I don't know the calls to get a list of supported video
+  modes on older EFI 1.x systems (including Macs), so on Macs setting an
+  incorrect video mode silently fails (you keep using the default mode).
+  This makes changing your video mode a hit-or-miss proposition on Macs.
+  CAUTION: It's possible to set a legal video mode that your monitor can't
+  handle, in which case you'll get a blank display until you boot an OS
+  that resets the video mode.
+
+- Fixed (maybe) a bug that caused rEFInd to crash when returning from an
+  EFI shell or other programs on Macs, particularly when rEFInd used
+  graphical mode. I'm not 100% sure this bug is squashed because I still
+  don't understand the cause and I only have one Mac for testing. See
+  comments in the ReinitRefitLib() function in refit/lib.c for more
+  details.
+
+- Added new refind.conf option: scan_all_linux_kernels, which causes Linux
+  kernels that lack ".efi" extensions to be included in scans for EFI boot
+  loaders. This may help integration with Linux distributions that don't
+  give their kernels such names by default. Beware, though: It can detect
+  unwanted files, such as older non-stub-loader kernels or .icns files used
+  to give kernels with .efi extensions custom icons.
+
+- Improved EFI boot loader detection on boards with Gigabyte's Hybrid EFI,
+  and perhaps other EFIs with a buggy StriCmp() function. Files with both
+  ".efi" and ".EFI" extensions should now be detected as boot loaders.
+
+- Fixed a bug that caused rEFInd to fail to scan for drivers if the
+  filesystem driver didn't set a volume name (that is, if the relevant
+  field was set to NULL rather than even an empty string). In such
+  situations, rEFInd now reports the volume name as "Unknown".
+
+0.2.7 (4/19/2012):
+------------------
+
+- After much trial and tribulation, I've overcome a GNU-EFI limitation and
+  enabled rEFInd to load EFI drivers. This feature was present in the
+  original build of rEFIt but was removed in the versions that could
+  compile under Linux, but now it's back -- and still being compiled under
+  Linux! To use it, you should place your drivers in a convenient directory
+  on the ESP (or whatever partition you use to launch rEFInd) and add a
+  "scan_driver_dirs" entry to refind.conf to tell rEFInd where to look. (As
+  always, you should specify the driver directory relative to the root of
+  the filesystem.) Note that you can't launch drivers from another
+  filesystem; they must be on the same volume that holds rEFInd. Those who
+  compile from source code should note that implementing this feature
+  necessitated using a more recent version of the GNU-EFI library. I'm
+  currently using version 3.0p, and version 3.0i does NOT work. I don't
+  know where the change occurred, but you may need to upgrade your GNU-EFI
+  installation.
+
+- Fixed bug that caused rEFInd to show up in its own menu sometimes.
+
+- Added new refind.conf token: also_scan_dirs. When scanning volumes for
+  EFI boot loaders, rEFInd always scans the root directory and every
+  subdirectory of the /EFI directory, but it doesn't recurse into these
+  directories. The also_scan_dirs token adds more directories to the scan
+  list. It defaults to "elilo,boot", but you can set it to any directory or
+  directories you like.
+
+0.2.6 (4/14/2012):
+------------------
+
+- Added "volume" keyword to configuration file's stanza options. This
+  option changes the volume from which subsequent files (specified by
+  "loader" and "icon") are loaded. You pass "volume" the name/label of the
+  FILESYSTEM you want to use (not the GPT partition name), or a number
+  followed by a colon (e.g., "1:"). The former should reliably identify a
+  filesystem, assuming the name is unique. The latter assigns numbers based
+  on the order in which they're scanned, which may not be as reliable but
+  should work when a volume is unnamed.
+
+- Fixed bug in 0.2.5 that caused failure of Linux initial RAM disk
+  mapping on some (but not all) systems. Affected computers include at
+  least some Intel motherboards, maybe others.
+
+0.2.5 (4/9/2012):
+-----------------
+
+- Fixed bug that caused an inability to associate initial RAM disks with
+  Linux kernels stored in a volume's root directory.
+
+- Volume badges (that override default badges) are now stored in
+  .VolumeBadge.icns. Although undocumented, rEFInd formerly loaded custom
+  volume badges from .VolumeIcon.icns. This carryover from rEFIt was a
+  confusing name, given the next (new) feature, so I've changed and
+  documented the name....
+
+- Added ability to set a default icon for a loader stored in the root
+  directory of a volume: The icon is stored in .VolumeIcon.icns. This icon
+  is also used for Mac OS X volumes booted from the standard location.
+
+- Fixed bug that caused icons to drop back to generic icons when rEFInd
+  was launched in certain ways (such as from an EFI shell in rEFInd's
+  directory) on certain systems.
+
+- Fixed bug that caused "unknown disable flag" to be shown (very briefly)
+  instead of "unknown hideui flag" when an improper hideui flag was set.
+
+0.2.4 (4/5/2012):
+-----------------
+
+- Created new refind.conf entry: "showtools". This entry takes options of
+  "shell", "gptsync", "about", "exit", "reboot", and "shutdown". This
+  option is in some respects an affirmative version of portions of the old
+  "disable" and "hideui" options; however, it enables users to specify the
+  order in which these options appear on the screen. Also, the "exit"
+  option is new; it terminates the program. The effect is usually to return
+  to whatever tool launched it or to launch a default OS; however, this is
+  somewhat unpredictable. The default therefore omits the "exit" option, as
+  well as "gptsync", which has always been dangerous (but necessary on most
+  MacOS/Windows dual-boot setups on Macs). As part of this reconfiguration,
+  I've eliminated the "rescue Linux" option, which always seemed pointless
+  to me.
+
+- Folded "disable" and "hideui" refind.conf entries into one ("disable"),
+  and reduced the number of options to six: "banner", "label",
+  "singleuser", "hwtest", "arrows", and "all". ("arrows" is new and
+  disables the scroll arrows when a system has too many tags to display
+  simultaneously.)
+
+- Added max_tags option to the refind.conf file, enabling users to reduce
+  the maximum number of OS loader tags that can be displayed at once.
+
+- Updated rEFIt icon, based on the 128x128 volume label from the rEFIt CD
+  image.
+
+- Added x86 and x86-64 EFI shells to the CD image version of the binary,
+  but NOT to the binary zip file. The logic is that the CD image is more
+  likely to be used directly as an emergency disc and so may need this
+  feature, even though the source isn't part of the rEFInd project. (The
+  source is readily available from the TianoCore project.)
+
+- EFI shells may now be stored at /shellx64.efi for x86-64 systems or at
+  /shellia32.efi for x86 systems. The /EFI/tools/shell.efi name is also
+  recognized; however, if both files are present, two EFI shell icons will
+  appear on the main menu. The /efi/{refind-path/apps/shell.efi filename,
+  which was never officially documented but worked as a carryover from
+  rEFIt, is no longer valid.
+
+0.2.3 (3/26/2012):
+------------------
+
+- Fixed (maybe) a bug that caused hangs when launching a second program
+  after returning from a first. There are some weird system-to-system
+  differences, though, and this fix causes (apparently harmless) error
+  messages about "(re)opening our installation volume" on at least one
+  system (a 32-bit Mac Mini). I'm committing this change because, imperfect
+  though it is, it's preferable to the earlier version, at least on my
+  small sample of computers.
+
+- Because of news that the Linux kernel developers are planning to use the
+  filename linux.conf to hold Linux kernel configuration data for EFI
+  booting, I'm transitioning rEFInd away from that name and to
+  refind_linux.conf to avoid a conflict. This version can use either name,
+  with refind_linux.conf taking precedence if both are present.
+
+- Added logo for Arch Linux.
+
+0.2.2 (3/23/2012):
+------------------
+
+- Fixed bug that caused program failure when Linux kernels with EFI stub
+  support were detected with no associated version numbers. rEFInd now
+  permits automatic linking of *ONE* versionless kernel to *ONE*
+  versionless initrd file.
+
+- Fixed bug that caused program hangs when a boot loader filename or label
+  was too long. Such names are now properly truncated and program execution
+  continues.
+
+- Fixed bug that caused no text to appear in submenus on UEFI systems with
+  small screens (800x600). NOTE: Problem still occurs on screens smaller
+  than this, but such systems are very rare.
+
+0.2.1 (3/19/2012):
+------------------
+
+- Added ability to set a "default_selection" that's a title or a substring
+  of one -- the name given to a stanza in a "menuentry" or the boot
+  loader's filename, in most cases, although "Mac OS X", "Windows XP
+  (XoM)", and "Microsoft EFI boot" are also titles.
+
+- Added support for semi-automatic scans of Linux kernels with EFI stub
+  loader support. The program auto-detects matching initial RAM disk files
+  and loads additional options from the "linux.conf" file in the same
+  directory as the kernel.
+
+- Added support for "submenuentry" keyword and associated sub-stanza
+  entries in refind.conf file.
+
+- Renamed icons/os_mint.icns to icons/os_linuxmint.icns to match the
+  filename Linux Mint ACTUALLY uses for its ESP boot loader directory.
+
+
+0.2.0 (3/14/2012):
+------------------
+
+- Initial public release
diff --git a/README.txt b/README.txt
new file mode 100644 (file)
index 0000000..4f86cb6
--- /dev/null
@@ -0,0 +1,71 @@
+Brief Installation Instructions (Binary Package)
+================================================
+
+This is rEFInd, an EFI boot manager. The binary package includes the
+following files and subdirectories:
+
+   File                             Description
+   -----------------------------    -----------------------------
+   refind/refind_ia32.efi           The main IA32 rEFInd binary
+   refind/refind_x64.efi            The main x86-64 rEFInd binary
+   refind/refind.conf-sample        A sample configuration file
+   refind/icons/                    Subdirectory containing icons
+   refind/drivers_ia32/             Subdirectory containing IA32 drivers
+   refind/drivers_x64/              Subdirectory containing x86-64 drivers
+   keys/                            Subdirectory containing MOKs
+   refind-install                   Linux/MacOS installation script
+   mkrlconf                         A script to create refind_linux.conf
+   mvrefind                         A script to move a rEFInd installation
+   README.txt                       This file
+   NEWS.txt                         A summary of program changes
+   LICENSE.txt                      The original rEFIt license
+   COPYING.txt                      The rEFInd license
+   CREDITS.txt                      Acknowledgments of code sources
+   docs/                            Documentation in HTML format
+
+The easiest way of installing rEFInd is generally to use the refind-install
+script; however, you must be running under Linux or OS X to do this. If
+you're using either of those OSes, simply typing "./refind-install" will
+generally install rEFInd. If you have problems with this method, though,
+you'll have to do a manual installation. The refind-install script supports
+a number of options that you might want to use; consult the
+docs/refind/installing.html file for details.
+
+To install the binary package manually, you must first access your EFI
+System Partition (ESP). You can then place the files from the refind
+subdirectory in a subdirectory of the ESP's EFI directory. You may omit the
+.efi binary for the type of computer you're NOT using, and you may
+optionally rename the .efi file for the binary you are using. If this is an
+initial installation, you should rename refind.conf-sample to refind.conf;
+but if you're replacing an existing installation, you should leave your
+existing refind.conf intact. The end result might include the following
+files on the ESP:
+
+ EFI/refind/refind_x64.efi
+ EFI/refind/refind.conf
+ EFI/refind/icons/
+
+Unfortunately, dropping the files in the ESP is not sufficient; as
+described in the docs/refind/installing.html file, you must also tell your
+EFI about rEFInd. Precisely how to do this varies with your OS or, if you
+choose to do it through the EFI, your EFI implementation. In some cases you
+may need to rename the EFI/refind directory as EFI/boot, and rename
+refind_x86.efi to bootx64.efi (or refind_ia32.efi to bootia32.efi on 32-bit
+systems). Consult the installing.html file for full details.
+
+If you want to use any of the filesystem drivers, you must install them,
+too. Creating a subdirectory of the rEFInd binary directory called
+drivers_x64 (for x86-64 systems), drivers_ia32 (for x86 systems), or
+drivers (for any architecture) and copying the drivers you want to this
+location should do the trick. When you next launch it, rEFInd should load
+the drivers, giving you access to the relevant filesystems.
+
+Brief Installation Instructions (Source Package)
+================================================
+
+rEFInd source code can be obtained from
+https://sourceforge.net/projects/refind/. Consult the BUILDING.txt file in
+the source code package for build instructions. Once  you've built the
+source code, you can use the refind-install script to install the binaries
+you've built. Alternatively, you can duplicate the directory tree described
+above by copying the individual files and the icons directory to the ESP.
diff --git a/banners/refind_banner-alpha.png b/banners/refind_banner-alpha.png
new file mode 100644 (file)
index 0000000..ba6ce0d
Binary files /dev/null and b/banners/refind_banner-alpha.png differ
diff --git a/banners/refind_banner.png b/banners/refind_banner.png
new file mode 100644 (file)
index 0000000..11b2438
Binary files /dev/null and b/banners/refind_banner.png differ
diff --git a/banners/refind_banner.svg b/banners/refind_banner.svg
new file mode 100644 (file)
index 0000000..d56fe78
--- /dev/null
@@ -0,0 +1,264 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="420"
+   height="128"
+   id="svg12874"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   inkscape:export-filename="/home/rodsmith/programming/refind/current/images/banner-refind-white.png"
+   inkscape:export-xdpi="39.483315"
+   inkscape:export-ydpi="39.483315"
+   sodipodi:docname="banner-refind-06-color-allwhite-shadow.svg">
+  <defs
+     id="defs12876">
+    <filter
+       id="filter16789"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood16791"
+         flood-opacity="0.7"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite16793"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur16795"
+         in="composite"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset16797"
+         dx="3"
+         dy="3"
+         result="offset" />
+      <feComposite
+         id="feComposite16799"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+    <filter
+       id="filter16801"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood16803"
+         flood-opacity="0.7"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite16805"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur16807"
+         in="composite"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset16809"
+         dx="3"
+         dy="3"
+         result="offset" />
+      <feComposite
+         id="feComposite16811"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+    <filter
+       id="filter16813"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood16815"
+         flood-opacity="0.7"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite16817"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur16819"
+         in="composite"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset16821"
+         dx="3"
+         dy="3"
+         result="offset" />
+      <feComposite
+         id="feComposite16823"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#c0c0c0"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="1.3671875"
+     inkscape:cx="221.54507"
+     inkscape:cy="58.078242"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:document-units="px"
+     inkscape:grid-bbox="true"
+     inkscape:window-width="1108"
+     inkscape:window-height="979"
+     inkscape:window-x="319"
+     inkscape:window-y="25"
+     inkscape:window-maximized="0" />
+  <metadata
+     id="metadata12879">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     transform="translate(0,64)">
+    <g
+       id="g14396"
+       transform="translate(-3.0027063,-3.0672157)"
+       style="filter:url(#filter16789)">
+      <path
+         sodipodi:end="6.3137247"
+         sodipodi:start="0.038057173"
+         transform="matrix(0.92479648,0,0,1.0146143,3.6793308,-74.868835)"
+         d="m 114.23105,62.798281 a 7.0144992,5.8831286 0 1 1 0.002,-0.0442 l -7.01122,-0.179639 z"
+         sodipodi:ry="5.8831286"
+         sodipodi:rx="7.0144992"
+         sodipodi:cy="62.57444"
+         sodipodi:cx="107.22163"
+         id="path13770"
+         style="fill:#0000bc;fill-opacity:1;stroke:#0000bc;stroke-opacity:1"
+         sodipodi:type="arc" />
+      <path
+         inkscape:transform-center-y="-2.717824"
+         inkscape:transform-center-x="2.2822755"
+         transform="matrix(-0.36198059,-1.0983946,1.2009376,-0.52324781,92.632403,-15.195328)"
+         d="M 25.234285,15.542856 13.408625,14.102867 1.5350652,13.13418 8.6949622,3.6128532 15.47065,-6.1856079 20.136412,4.7757081 z"
+         inkscape:randomized="0"
+         inkscape:rounded="0"
+         inkscape:flatsided="false"
+         sodipodi:arg2="1.6720838"
+         sodipodi:arg1="0.62488624"
+         sodipodi:r2="6.6397543"
+         sodipodi:r1="13.753239"
+         sodipodi:cy="7.4971428"
+         sodipodi:cx="14.08"
+         sodipodi:sides="3"
+         id="path13768"
+         style="fill:#0000bc;fill-opacity:1;stroke:#0000bc;stroke-opacity:1"
+         sodipodi:type="star" />
+      <path
+         sodipodi:end="6.3137247"
+         sodipodi:start="0.038057173"
+         transform="matrix(1.0623728,0,0,1.0939231,-25.695042,-96.297006)"
+         d="m 128.90965,140.02735 a 6.4000001,6.1257143 0 1 1 0.002,-0.046 l -6.39702,-0.18705 z"
+         sodipodi:ry="6.1257143"
+         sodipodi:rx="6.4000001"
+         sodipodi:cy="139.79428"
+         sodipodi:cx="122.51428"
+         id="path13774"
+         style="fill:#0000bc;fill-opacity:1;stroke:#0000bc;stroke-opacity:1"
+         sodipodi:type="arc" />
+      <rect
+         transform="matrix(0.87626487,-0.48182972,0.50478347,0.86324599,0,0)"
+         y="62.893646"
+         x="54.812462"
+         height="36.635689"
+         width="13.590784"
+         id="rect13772"
+         style="fill:#0000bc;fill-opacity:1;stroke:#0000bc;stroke-width:0.97056359;stroke-opacity:1" />
+      <path
+         transform="translate(0,-64)"
+         inkscape:connector-curvature="0"
+         id="path14394"
+         d="M 62.24715,93.833652 C 44.041938,92.252582 28.546517,79.385025 23.734015,61.851955 22.501283,57.360822 22.301415,55.744916 22.29782,50.240526 22.294225,44.735665 22.524224,42.859657 23.75127,38.385327 28.007142,22.866603 41.06795,10.600982 56.852864,7.2990704 63.103797,5.9914908 69.776278,6.0487609 75.778578,7.4615104 83.004074,9.1621606 89.298831,12.39401 94.931372,17.294921 l 1.507079,1.311319 -4.873168,4.875923 -4.873169,4.875922 -1.296768,-1.097309 c -6.117882,-5.17688 -14.176954,-7.796403 -21.868196,-7.108048 -6.678051,0.597677 -12.12638,2.835457 -17.21195,7.069426 -8.343558,6.946394 -12.204448,18.453055 -9.850305,29.356991 1.730081,8.013399 6.921261,15.163838 14.115881,19.443507 4.268634,2.539167 8.875228,3.870069 14.059767,4.062041 7.738606,0.286543 14.749025,-2.096311 20.646607,-7.017823 5.644445,-4.710268 9.670531,-12.247325 10.415034,-19.497527 0.08051,-0.784007 0.193121,-1.47221 0.250249,-1.52934 0.13361,-0.133608 13.406277,0.33269 13.643537,0.479329 0.44025,0.27209 -0.49058,6.224421 -1.54774,9.897282 -2.3965,8.326113 -7.67389,16.284899 -14.40898,21.730061 -8.822615,7.132884 -20.238599,10.655628 -31.3921,9.686977 z"
+         style="fill:#0000bc;fill-opacity:1;stroke:#0000bc;stroke-width:0.18285714;stroke-opacity:1" />
+    </g>
+    <g
+       id="g16653"
+       transform="translate(1.4628571,-2.1942857)"
+       style="filter:url(#filter16801)">
+      <path
+         d="m 147.4908,-25.683422 0,-0.552 c 0,-3.311997 -1.472,-4.416 -4.14,-4.416 -3.67999,0 -5.612,1.748004 -6.256,5.796 l -5.704,34.6839995 c -0.092,0.5519995 -0.092,1.0120005 -0.092,1.4720005 0,3.035997 1.74801,4.876 4.876,4.876 3.496,0 5.428,-2.116005 6.164,-6.3480005 l 3.036,-17.664 c 1.288,-7.6359925 2.11601,-11.2240005 8.188,-11.8679995 2.3,-0.276 5.06001,0.275998 7.544,-1.288 1.748,-1.103999 2.76,-2.852003 2.76,-4.968 0,-3.311997 -1.932,-4.968 -5.796,-4.968 -4.13999,0 -7.636,1.748003 -10.58,5.244"
+         style="font-size:92px;font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:ITC Benguiat Gothic;-inkscape-font-specification:ITC Benguiat Gothic Bold Italic"
+         id="path16377"
+         inkscape:connector-curvature="0" />
+      <path
+         d="m 176.97393,4.8605775 3.68,-22.3559995 22.08,0 c 5.70399,0 8.28,-1.748005 8.28,-5.98 0,-3.127997 -1.84001,-4.416 -5.796,-4.416 l -22.816,0 1.38,-7.912 21.804,0 c 5.79599,0 8.648,-1.932005 8.648,-5.98 0,-3.495997 -1.93201,-4.784 -6.072,-4.784 l -25.944,0 c -6.44,0 -8.556,1.472005 -9.476,6.992 l -8.004,47.4719995 c -0.184,0.9199991 -0.184,1.6560008 -0.184,2.3920005 0,4.415995 2.944,5.612 8.832,5.612 l 24.84,0 c 5.05999,0 8.096,-2.576005 8.096,-6.6240005 0,-2.8519971 -2.02401,-4.416 -5.888,-4.416 l -23.46,0"
+         style="font-size:92px;font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#0000bc;fill-opacity:1;stroke:none;font-family:ITC Benguiat Gothic;-inkscape-font-specification:ITC Benguiat Gothic Bold Italic"
+         id="path16379"
+         inkscape:connector-curvature="0" />
+      <path
+         d="m 232.22424,-17.495422 18.032,0 c 5.704,0 8.372,-1.748005 8.372,-5.98 0,-3.127997 -1.932,-4.416 -5.888,-4.416 l -18.768,0 1.38,-7.912 18.216,0 c 5.79599,0 8.74,-1.932005 8.74,-5.98 0,-3.495997 -1.932,-4.784 -6.072,-4.784 l -22.448,0 c -6.43999,0 -8.556,1.472005 -9.476,6.992 l -8.28,48.8519995 c -0.092,0.6439994 -0.184,1.1960005 -0.184,1.7480005 0,3.311996 1.84,5.06 5.244,5.06 4.048,0 5.796,-2.208005 6.624,-6.8080005 l 4.508,-26.7719995"
+         style="font-size:92px;font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#0000bc;fill-opacity:1;stroke:none;font-family:ITC Benguiat Gothic;-inkscape-font-specification:ITC Benguiat Gothic Bold Italic"
+         id="path16381"
+         inkscape:connector-curvature="0" />
+      <path
+         d="m 264.01312,9.2765775 c -0.092,0.6439994 -0.184,1.2880005 -0.184,1.8400005 0,3.219996 1.748,4.968 4.876,4.968 4.41599,0 6.164,-2.024005 6.992,-6.8080005 l 8.464,-50.0479995 c 0.092,-0.46 0.092,-0.920001 0.092,-1.38 0,-2.943998 -1.84001,-4.692 -5.244,-4.692 -3.68,0 -5.98,2.116004 -6.624,6.072 l -8.372,50.0479995"
+         style="font-size:92px;font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#0000bc;fill-opacity:1;stroke:none;font-family:ITC Benguiat Gothic;-inkscape-font-specification:ITC Benguiat Gothic Bold Italic"
+         id="path16383"
+         inkscape:connector-curvature="0" />
+      <path
+         d="m 304.19555,-25.407422 c 0.092,-0.368 0.092,-0.736001 0.092,-1.012 0,-2.759998 -1.748,-4.324 -4.692,-4.324 -3.95599,0 -5.98,1.748004 -6.624,5.888 l -5.796,34.6839995 c -0.092,0.5519995 -0.092,1.0120005 -0.092,1.4720005 0,3.035997 1.84001,4.876 4.968,4.876 3.496,0 5.428,-2.116005 6.164,-6.3480005 l 3.22,-18.952 c 1.288,-7.5439925 5.79601,-11.8679995 12.144,-11.8679995 4.508,0 6.716,2.116004 6.716,6.256 0,0.827999 -0.092,2.392002 -0.46,4.508 l -3.22,20.0559995 c -0.092,0.4599995 -0.092,0.9200005 -0.092,1.3800005 0,2.943997 1.93201,4.876 5.152,4.876 3.404,0 5.428,-2.024005 6.164,-6.2560005 l 3.68,-21.9879995 c 0.276,-1.839999 0.368,-3.680002 0.368,-5.52 0,-7.911993 -5.52001,-13.156 -13.984,-13.156 -4.69199,0 -9.108,1.840003 -13.708,5.428"
+         style="font-size:92px;font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:ITC Benguiat Gothic;-inkscape-font-specification:ITC Benguiat Gothic Bold Italic"
+         id="path16385"
+         inkscape:connector-curvature="0" />
+      <path
+         d="m 372.51418,-20.531422 -4.232,25.8519995 c -2.668,0.1839999 -4.784,0.184 -6.348,0.184 -8.09599,0 -11.776,-1.8400057 -11.776,-7.544 0,-10.1199895 8.46401,-18.1240005 22.356,-18.4919995 m 1.656,-9.844 -0.736,0 c -8.73999,0 -15.82401,1.656003 -21.068,4.968 -8.83199,5.519994 -14.26,15.088009 -14.26,24.47199955 0,5.97999405 2.392,10.94800345 6.808,13.98400045 3.40399,2.299997 8.64801,2.852 16.1,2.852 l 11.684,0 c 3.31199,0 5.244,-1.840004 5.888,-5.52 l 8.832,-52.624 c 0.092,-0.552 0.092,-1.012001 0.092,-1.472 0,-2.851998 -1.748,-4.416 -4.968,-4.416 -3.312,0 -5.52,1.932003 -6.164,5.428 l -2.208,12.328"
+         style="font-size:92px;font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:ITC Benguiat Gothic;-inkscape-font-specification:ITC Benguiat Gothic Bold Italic"
+         id="path16387"
+         inkscape:connector-curvature="0" />
+    </g>
+    <text
+       xml:space="preserve"
+       style="font-size:36px;font-style:italic;font-variant:normal;font-weight:600;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#ff0000;fill-opacity:1;stroke:none;font-family:BouganSSi;-inkscape-font-specification:BouganSSi Semi-Bold Italic;filter:url(#filter16813)"
+       x="260.42313"
+       y="49.695934"
+       id="text16353"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan16355"
+         x="260.42313"
+         y="49.695934">Boot Management</tspan></text>
+  </g>
+</svg>
index 7ca3fa4dc3d5b6dfc95d8b672643b05c92417df0..fe66d1c7abe16b5b38ab1df153c75ffc262dcb92 100644 (file)
@@ -10,7 +10,7 @@ Vcs-Browser: https://anonscm.debian.org/cgit/collab-maint/refind.git
 Vcs-Git: git://anonscm.debian.org/collab-maint/refind.git
 
 Package: refind
-Architecture: amd64 arm64 i386
+Architecture: amd64 i386 arm64
 Depends: efibootmgr, openssl, parted, ${misc:Depends}
 Description: boot manager for EFI-based computers
  A graphical boot manager for EFI- and UEFI-based computers, such as all
index b233c331b46b301dcef4946ae5d86248639fb977..2074ea18fd8604ddf6b3b048b5945104abb6232e 100644 (file)
@@ -72,15 +72,9 @@ Copyright: 2012 Harald Hoyer <harald@redhat.com>
 License: LGPL-2.1+
 
 Files: EfiLib/*
-Copyright: 2004-2011 Intel Corp.
+Copyright: 2004-2014 Intel Corp.
 License: BSD-2-clause
 
-Files: EfiLib/BdsHelper.[ch]
-       EfiLib/Platform.h
-Copyright: ????
-License: ????
-Comment: In style of TianoCore; Google to find source
-
 Files: libeg/lodepng.[ch]
 Copyright: 2005-2015 Lode Vandevenne
 License: zlib
@@ -332,7 +326,73 @@ Copyright: 2010,2011 Canonical Ltd.
 License: UFL-1
 Comment: PNG bitmap derived from TrueType font
 
+Files: banners/*
+Copyright: 2015 Roderick W. Smith
+License: LGPLv3+ or Creative Commons Attribution-Share Alike 3.0 (CC-SA 3.0)
+
+Files: fonts/liberation*
+Copyright: 2010 Google & 2012 Red Hat
+License: SIL-1.10
+Comment: PNG bitmap derived from TrueType font;
+         liberation-mono-regular-14.png embedded in rEFInd binary
+
+Files: fonts/mkfont.sh
+Copyright: 2013 Roderick W. Smith
+License: GPL-3+
+
+Files: fonts/nimbus*
+Copyright: 1984, 1996, 2009 URW Studio
+License: GPL-2
+Comment: PNG bitmap derived from PostScript font
+
+Files: fonts/ubuntu*
+Copyright: 2010,2011 Canonical Ltd.
+License: UFL-1 (Ubuntu Font License)
+Comment: PNG bitmap derived from TrueType font
+
+Files: keys/altlinux.cer
+Copyright: 2013 Alt Linux
+License: Public-Domain
+Comment: RPM spec file at
+        http://www.sisyphus.ru/br/srpm/Sisyphus/alt-uefi-certs/spec claims
+        "public domain" as the license.
+
+Files: keys/canonical-uefi-ca.*
+Copyright: ??? ???
+License: BSD-2-Clause
+Comment: Debian package at https://launchpad.net/ubuntu/+source/shim claims
+         copyright by Red Hat and Intel, but that's clearly meant to refer
+        to the bulk of Shim, not to Canonical's public key. The .crt file
+        is derived from the .der file. I'm pinging the package's
+        maintainer for clarification.
+
+Files: keys/fedora-ca.c*
+Copyright: 2012 Red Hat, Inc.
+License: BSD-2-Clause
+Comment: The .cer file is taken from the Fedora RPM for shim 0.8. The
+         .crt file was created from that by using openssl.
+
+Files: keys/microsoft-kekca-public.der
+       keys/microsoft-pca-public.der
+       keys/microsoft-uefica-public.crt
+       keys/microsoft-uefica-public.der
+Copyright: ??? ???
+License: ???
+
+Files: keys/openSUSE*
+       keys/SLES*
+Copyright: 2015 SUSE LINUX Products GmbH
+License: BSD-2-Clause
+Comment: .crt files are original; .der files are converted from original
+         .crt files by openssl. Taken from openSUSE shim
+        0.7.318.81ee561d-7.2 RPM package.
+
+Files: keys/refind.*
+Copyright: 2012 Roderick W. Smith
+License: BSD-2-Clause
+
 Files: docs/*
+       */README*
 Copyright: 2012-2015 Roderick W. Smith
 License: GFDL-1.3
 
diff --git a/debian/debinstall b/debian/debinstall
new file mode 100755 (executable)
index 0000000..75fed9e
--- /dev/null
@@ -0,0 +1,70 @@
+#!/bin/bash
+
+BUILD_ROOT=$1
+KEYDIR=/mnt/refind
+
+UNAMEARCH=`uname -m`
+if [[ $UNAMEARCH == "x86_64" ]] ; then
+   EFIARCH=x64
+elif [[ $UNAMEARCH == "i686" || $UNAMEARCH == "i586" || $UNAMEARCH == "i486" || $UNAMEARCH == "i386" ]] ; then
+   EFIARCH=ia32
+else
+   EFIARCH=$UNAMEARCH
+fi
+
+rm -rf $BUILD_ROOT
+mkdir -p $BUILD_ROOT/usr/share/refind/refind/
+
+# Copy the rEFInd binaries (rEFInd proper and drivers) to /usr/share/refind,
+# including signing the binaries if sbsign is installed and a $KEYDIR/refind.key file
+# is available
+declare SBSign=`which sbsign 2> /dev/null`
+if [[ -f $KEYDIR/refind.key && -x $SBSign ]] ; then
+   $SBSign --key $KEYDIR/refind.key --cert $KEYDIR/refind.crt --output $BUILD_ROOT/usr/share/refind/refind/refind_$EFIARCH.efi refind/refind_$EFIARCH.efi
+   mkdir -p $BUILD_ROOT/usr/share/refind/refind/drivers_$EFIARCH
+   for File in `ls drivers_$EFIARCH/*_$EFIARCH.efi` ; do
+      $SBSign --key $KEYDIR/refind.key --cert $KEYDIR/refind.crt --output $BUILD_ROOT/usr/share/refind/refind/$File $File
+   done
+   mkdir -p $BUILD_ROOT/usr/share/refind/refind/tools_$EFIARCH
+   $SBSign --key $KEYDIR/refind.key --cert $KEYDIR/refind.crt --output $BUILD_ROOT/usr/share/refind/refind/tools_$EFIARCH/gptsync_$EFIARCH.efi gptsync/gptsync_$EFIARCH.efi
+else
+   install -Dp -m0644 refind/refind*.efi $BUILD_ROOT/usr/share/refind/refind/
+   mkdir -p $BUILD_ROOT/usr/share/refind/refind/drivers_$EFIARCH
+   cp -a drivers_$EFIARCH/* $BUILD_ROOT/usr/share/refind/refind/drivers_$EFIARCH/
+   mkdir -p $BUILD_ROOT/usr/share/refind/refind/tools_$EFIARCH
+   install -Dp -m0644 gptsync/gptsync_$EFIARCH.efi $BUILD_ROOT/usr/share/refind/refind/tools_$EFIARCH/gptsync_$EFIARCH.efi
+fi
+
+# Copy configuration and support files to /usr/share/refind
+install -Dp -m0644 refind.conf-sample $BUILD_ROOT/usr/share/refind/refind/
+cp -a icons $BUILD_ROOT/usr/share/refind/refind/
+rm -rf $BUILD_ROOT/usr/share/refind/refind/icons/svg
+install -Dp -m0755 refind-install $BUILD_ROOT/usr/share/refind/
+
+# Copy documentation to /usr/share/doc/refind
+mkdir -p $BUILD_ROOT/usr/share/doc/refind
+cp -a docs/Styles $BUILD_ROOT/usr/share/doc/refind/
+cp -a docs/refind $BUILD_ROOT/usr/share/doc/refind/
+install -Dp -m0644 NEWS.txt COPYING.txt LICENSE.txt README.txt CREDITS.txt $BUILD_ROOT/usr/share/doc/refind
+
+# Copy man pages to /usr/share/man/man8
+mkdir -p $BUILD_ROOT/usr/share/man/man8
+install -Dp -m0644 docs/man/mvrefind.8 $BUILD_ROOT/usr/share/man/man8
+install -Dp -m0644 docs/man/mkrlconf.8 $BUILD_ROOT/usr/share/man/man8
+install -Dp -m0644 docs/man/refind-install.8 $BUILD_ROOT/usr/share/man/man8
+
+# Copy keys to /etc/refind.d/keys
+mkdir -p $BUILD_ROOT/etc/refind.d/keys
+install -Dp -m0644 keys/* $BUILD_ROOT/etc/refind.d/keys
+
+# Copy scripts to /usr/sbin
+mkdir -p $BUILD_ROOT/usr/sbin
+install -Dp -m0755 mkrlconf $BUILD_ROOT/usr/sbin/
+install -Dp -m0755 mvrefind $BUILD_ROOT/usr/sbin/
+ln -sr refind-install $BUILD_ROOT/usr/sbin
+
+# Copy banners and fonts to /usr/share/refind
+cp -a banners $BUILD_ROOT/usr/share/refind/
+cp -a fonts $BUILD_ROOT/usr/share/refind/
+
+echo "*** Exiting debinstall! ***"
\ No newline at end of file
diff --git a/debian/postinst b/debian/postinst
new file mode 100755 (executable)
index 0000000..af73308
--- /dev/null
@@ -0,0 +1,50 @@
+#!/bin/bash
+# Post-installation script (run on USER'S system after installing the
+# main rEFInd package)
+
+set -e
+
+# Remove any existing NVRAM entry for rEFInd, to avoid creating a duplicate.
+ExistingEntry=`efibootmgr | grep "rEFInd Boot Manager" | cut -c 5-8`
+if [[ -n $ExistingEntry ]] ; then
+   efibootmgr --bootnum $ExistingEntry --delete-bootnum &> /dev/null
+fi
+
+cd /usr/share/refind
+
+if [[ -f /sys/firmware/efi/vars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c/data ]] ; then
+   IsSecureBoot=`od -An -t u1 /sys/firmware/efi/vars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c/data | tr -d '[[:space:]]'`
+else
+   IsSecureBoot="0"
+fi
+# Note: Two find operations for ShimFile favors shim over PreLoader -- if both are
+# present, the script uses shim rather than PreLoader.
+declare ShimFile=`find /boot -name shim\.efi -o -name shimx64\.efi -o -name PreLoader\.efi 2> /dev/null | head -n 1`
+if [[ ! -n $ShimFile ]] ; then
+   declare ShimFile=`find /boot -name PreLoader\.efi 2> /dev/null | head -n 1`
+fi
+declare SBSign=`which sbsign 2> /dev/null`
+declare OpenSSL=`which openssl 2> /dev/null`
+
+# Run the rEFInd installation script. Do so with the --shim option
+# if Secure Boot mode is suspected and if a shim program can be
+# found, or without it if not. If a shim installation is attempted
+# and the sbsign and openssl programs can be found, do the install
+# using a local signing key. Note that this option is undesirable
+# for a distribution, since it would then require the user to
+# enroll an extra MOK. I'm including it here because I'm NOT a
+# distribution maintainer, and I want to encourage users to use
+# their own local keys.
+if [[ $IsSecureBoot == "1" && -n $ShimFile ]] ; then
+   if [[ -n $SBSign && -n $OpenSSL ]] ; then
+      ./refind-install --shim $ShimFile --localkeys --yes
+   else
+      ./refind-install --shim $ShimFile --yes
+   fi
+else
+   if [[ -n $SBSign && -n $OpenSSL ]] ; then
+      ./refind-install --localkeys --yes
+   else
+      ./refind-install --yes
+   fi
+fi
diff --git a/docs/Styles/styles.css b/docs/Styles/styles.css
new file mode 100644 (file)
index 0000000..9ecadda
--- /dev/null
@@ -0,0 +1,88 @@
+body {
+    color:black;
+    background-color:white;
+    text-align:left;
+/*    font-family:"Georgia",serif; */
+}
+
+p {
+/*    text-indent:50px; */
+}
+
+li {
+    margin-top: 1em;
+    margin-bottom: 1em;
+}
+
+h1,h2,h3,h4 {
+    text-align:center;
+    font-family:"Bitstream Vera Sans", "Verdana", "Helvetica", "Arial", sans-serif;
+}
+
+.userinput {
+    font-weight:bold;
+    font-family:monospace;
+}
+
+.variable {
+    font-style: italic;
+}
+
+.listing {
+    font-family:monospace;
+    margin: 0px;
+    padding: 6px;
+    border: 1px solid;
+    max-width:100%;
+    width: 50em;
+    overflow-x:auto;
+    text-align: left;
+    background-color:#EEE;
+    white-space:pre;
+}
+
+.quote {
+    width: 90%;
+    float: center;
+    padding: 2px;
+    margin: 10px;
+    background-color: #EEEEEE;
+}
+
+.highlight {
+    background: #888888;
+}
+
+.sidebar {
+    width: 45%;
+    float: right;
+    padding: 5px;
+    border:5px solid gray;
+    margin:10px;
+    background-color:#EEE;
+}
+
+.navbar {
+    width: 40%;
+    float: none;
+    padding: 5px;
+    border: 5px solid gray;
+    margin: 10px;
+    background-color:#EEE;
+}
+
+.subhead {
+    font-family:"Verdana", "Trebuchet", "Helvetica", sans-serif;
+    font-size:150%;
+    font-weight:bold;
+    text-align:center;
+}
+
+.left {
+    text-align:left;
+}
+
+.tight {
+    margin-top: 0.25em;
+    margin-bottom: 0.5em;
+}
diff --git a/docs/man/mkrlconf.8 b/docs/man/mkrlconf.8
new file mode 100644 (file)
index 0000000..dbbfbc2
--- /dev/null
@@ -0,0 +1,52 @@
+.\" Copyright 2015 Roderick W. Smith (rodsmith@rodsbooks.com)
+.\" May be distributed under the GNU Free Documentation License version 1.3 or
+any later version
+.TH "MKRLCONF" "8" "0.10.0" "Roderick W. Smith" "rEFInd Manual"
+.SH "NAME"
+mkrlconf \- Create a Linux kernel configuration file for rEFInd
+.SH "SYNOPSIS"
+.BI "mkrlconf "
+[ \-\-force ]
+
+.SH "DESCRIPTION"
+
+To boot a Linux kernel directly, rEFInd must normally pass system-specific
+parameters to help the kernel locate its initial RAM disk (initrd) file,
+the installation's root filesystem, and so on. rEFInd stores this
+information in a file called \fIrefind_linux.conf\fR, which is stored in
+the same directory as the kernel(s) to which it applies. The \fImkrlconf\fR
+script creates this configuration file in \fI/boot\fR, using the current
+boot options (from \fI/proc/cmdline\fR) to populate
+\fI/boot/refind_linux.conf\fR with boot options that are probably (but not
+certainly) correct.
+
+The file created in this way has three lines, which correspond to three
+entries on the rEFInd suboptions menu. The first entry boots using the
+options found in \fI/proc/cmdline\fR. The second entry boots using the same
+options as the first, but with \fBsingle\fR added. The third entry boots
+with minimal options of \fBro root={CURRENT_ROOT_DEVICE}\fR, where
+\fB{CURRENT_ROOT_DEVICE}\fR identifies the current root (\fI/\fR)
+filesystem. Users may manually edit the \fIrefind_linux.conf\fR file to
+suit their needs, of course.
+
+.SH "OPTIONS"
+
+.TP
+.B \-\-force
+Ordinarily, if \fImkrlconf\fR finds an existing
+\fI/boot/refind_linux.conf\fR file, it refuses to replace it. The
+\fB\-\-force\fR option causes \fImkrlconf\fR to replace the existing file
+in favor of one it generates.
+
+.SH "AUTHORS"
+Primary author: Roderick W. Smith (rodsmith@rodsbooks.com)
+
+.SH "SEE ALSO"
+\fBmvrefind (8)\fR,
+\fBrefind-install (8)\fR
+
+\fIhttp://www.rodsbooks.com/refind/\fR
+
+.SH "AVAILABILITY"
+The \fBmkrlconf\fR command is part of the \fIrEFInd\fR package and is
+available from Roderick W. Smith.
diff --git a/docs/man/mvrefind.8 b/docs/man/mvrefind.8
new file mode 100644 (file)
index 0000000..86bcb24
--- /dev/null
@@ -0,0 +1,99 @@
+.\" Copyright 2015 Roderick W. Smith (rodsmith@rodsbooks.com)
+.\" May be distributed under the GNU Free Documentation License version 1.3 or
+any later version
+.TH "MVREFIND" "8" "0.10.0" "Roderick W. Smith" "rEFInd Manual"
+.SH "NAME"
+mvrefind \- Move a rEFInd installation from one location to another
+.SH "SYNOPSIS"
+.BI "mvrefind \fISOURCE DEST\fR"
+
+.SH "DESCRIPTION"
+
+Move a rEFInd installation from \fISOURCE\fR to \fIDEST\fR, where both
+\fISOURCE\fR and \fIDEST\fR are directories on the EFI System Partition
+(ESP), with \fISOURCE\fR containing a working rEFInd installation. This
+operation entails taking several actions:
+
+.TP 
+.B *
+Renaming the \fISOURCE\fR directory to \fIDEST\fR.
+
+.TP 
+.B *
+Renaming the rEFInd binary to a suitable value given the new destination.
+For instance, if \fIDEST\fR is EFI/BOOT on the EFI System Partition (ESP),
+the rEFInd binary should be \fIbootx64.efi\fR (or something similar but
+with a different architecture code).
+
+.TP 
+.B *
+Altering the computer's NVRAM entries to point to rEFInd at its new
+location.
+
+.TP
+.B *
+If Shim is detected, renaming operations and NVRAM entry pointers are
+adjusted appropriately.
+
+.TP
+.B *
+If the \fIDEST\fR exists, its contents are preserved.
+
+.PP
+
+Broadly speaking, \fImvrefind\fR understands three types of locations for
+both \fISOURCE\fR and \fIDEST\fR, relative to the root of the ESP:
+
+.TP
+.B *
+\fBEFI/BOOT\fR -- The \fIbootx64.efi\fR (or similar for other
+architectures) filename in this location is the "fallback filename," which
+is used by removable boot media and as a boot loader of last resort on hard
+disks. Some EFIs can't remember their normal boot entries, and on them,
+rEFInd must be installed here (or as the Windows boot loader). When this
+directory is the \fIDEST\fR and it already exists, the existing
+\fIEFI/BOOT\fR is backed up to \fIEFI/BOOT\-rEFIndBackup\fR; and if the
+\fISOURCE\fR is \fIEFI/BOOT\fR and \fIEFI/BOOT\-rEFIndBackup\fR exists, it
+is renamed to \fIEFI/BOOT\fR after rEFInd is moved to its destination.
+
+.TP
+.B *
+\fBEFI/Microsoft/boot\fR -- The \fIbootmgfw.efi\fR file in this location
+normally holds the Windows boot loader. Machines with broken EFIs may
+refuse to accept or remember proper boot entries and will instead boot this
+entry in preference to all others. In such cases, using rEFInd requires
+moving the Microsoft boot loader elsewhere and replacing it with rEFInd.
+When this directory is the \fIDEST\fR, \fImvrefind\fR moves the original
+\fIbootmgfw.efi\fR file down one level (to \fIEFI/Microsoft\fR) and stores
+\fIrefind_x64.efi\fR (or Shim) in that location. When moving from
+\fIEFI/Microsoft/boot\fR, this process is reversed.
+
+.TP
+.B *
+\fBAnything else\fR -- Any other \fISOURCE\fR or \fIDEST\fR location is
+treated as a regular rEFInd installation, with a proper NVRAM entry created
+by \fIefibootmgr\fR.
+
+.PP 
+
+\fImvrefind\fR attempts to identify the ESP and refuses to move between the
+ESP and any other partition. When it does move files, it moves the main
+rEFInd binary, the \fIrefind.conf\fR file, any identified Shim binary, and
+the \fIicons\fR, \fIicons\-backup\fR, \fIdrivers_*\fR, and \fIkeys\fR
+subdirectories. If other rEFInd files or directories are present in
+\fISOURCE\fR (such as a custom theme/icons directory), they will not be
+moved. If \fISOURCE\fR is empty after the specified files and
+subdirectories are moved, \fISOURCE\fR will be deleted.
+
+.SH "AUTHORS"
+Primary author: Roderick W. Smith (rodsmith@rodsbooks.com)
+
+.SH "SEE ALSO"
+\fBmkrlconf (8)\fR,
+\fBrefind-install (8)\fR
+
+\fIhttp://www.rodsbooks.com/refind/\fR
+
+.SH "AVAILABILITY"
+The \fBmvrefind\fR command is part of the \fIrEFInd\fR package and is
+available from Roderick W. Smith.
diff --git a/docs/man/refind-install.8 b/docs/man/refind-install.8
new file mode 100644 (file)
index 0000000..201cd6c
--- /dev/null
@@ -0,0 +1,272 @@
+.\" Copyright 2015 Roderick W. Smith (rodsmith@rodsbooks.com)
+.\" May be distributed under the GNU Free Documentation License version 1.3 or
+any later version
+.TH "REFIND-INSTALL" "8" "0.10.0" "Roderick W. Smith" "rEFInd Manual"
+.SH "NAME"
+refind-install \- Install rEFInd to the ESP and create an NVRAM entry
+.SH "SYNOPSIS"
+.BI "refind-install "
+[--notesp | --usedefault \fIdevice-file\fR | --root \fImount-point\fR |
+--ownhfs \fIdevice-file\fR ] [--keepname ] [--nodrivers | --alldrivers]
+[--shim \fIshim-filename\fR] [--localkeys] [--yes]
+
+
+.SH "DESCRIPTION"
+
+To be useful, the rEFInd boot manager must be installed to the computer's
+EFI System Partition (ESP) or other EFI-accessible location. In most cases,
+an NVRAM entry describing rEFInd's location must also be created. These
+steps can be performed manually; however, the \fBrefind-install\fR command
+provides an automated way to perform these tasks under both Linux and OS X.
+The exact behavior and options vary depending on the OS, however.
+
+Some details that can affect how the script runs include the following:
+
+.TP
+.B *
+If you run the script as an ordinary user, it attempts to acquire
+\fBroot\fR privileges by using the \fBsudo\fR command. This works on Mac OS
+X and some Linux installations (such as under Ubuntu or if you've added
+yourself to the \fBsudo\fR users list), but on some Linux installations
+this will fail. On such systems, you should run \fBrefind\-install\fR as
+root.
+
+.TP
+.B *
+Under OS X, you can run the script with a mouse by opening a Terminal
+session and then dragging\-and\-dropping the \fBrefind\-install\fR file to
+the Terminal window. You'll need to press the Return or Enter key to run
+the script.
+
+.TP
+.B *
+If you're using OS X 10.7's Whole Disk Encryption (WDE) feature, or the
+loogical volumes feature in OS X 10.10, you must install rEFInd to the ESP
+or to a separate HFS+ partition. The default in rEFInd 0.8.4 and later is
+to install to the ESP. If you prefer to use a separate HFS+ volume, the
+\fB\-\-ownhfs \fIdevice-file\fR option to \fBrefind\-install\fR is required.
+
+.TP
+.B *
+If you're not using WDE or logical volumes, you can install rEFInd to the
+OS X root (/) partition by using the \-\-notesp option to
+\fBrefind\-install\fR. Using this option is recommended when upgrading from
+a working rEFInd installation in this location.
+
+.TP
+.B *
+If you're replacing rEFIt with rEFInd on a Mac, there's a chance that
+\fBrefind\-install\fR will warn you about the presence of a program called
+\fB/Library/StartupItems/rEFItBlesser\fR and ask if you want to delete it.
+This program is designed to keep rEFIt set as the boot manager by
+automatically re\-blessing it if the default boot manager changes. This is
+obviously undesirable if you install rEFInd as your primary boot manager,
+so it's generally best to remove this program. If you prefer to keep your
+options open, you can answer \fBN\fR when \fBrefind\-install\fR asks if you
+want to delete rEFItBlesser, and instead manually copy it elsewhere. If you
+subsequently decide to go back to using rEFIt as your primary boot manager,
+you can restore rEFItBlesser to its place.
+
+.TP
+.B *
+If you intend to boot BIOS-based OSes on a UEFI-based PC, you must edit the
+\fBrefind.conf\fR file's \fBscanfor\fR line to enable the relevant
+searches. This is not necessary on Macs, though; because of the popularity
+of dual boots with Windows on Macs, the BIOS/legacy scans are enabled by
+default on Macs.
+
+.TP
+.B *
+On Linux, \fBrefind\-install\fR checks the filesystem type of the
+\fB/boot\fR directory and, if a matching filesystem driver is available,
+installs it. Note that the "\fB/boot\fR directory" may be on a separate
+partition or it may be part of your root (\fB/\fR) filesystem, in which
+case the driver for your root filesystem is installed. This feature is
+unlikely to work properly from an emergency system, although it might if
+you have a separate \fB/boot\fR partition and if you mount that partition
+at \fB/boot\fR in your emergency system, and the ESP at \fB/boot/efi\fR.
+
+.TP
+.B *
+On OS X, \fBrefind\-install\fR checks your partition tables for signs of a
+Linux installation. If such a sign is found, the script installs the EFI
+filesystem driver for the Linux ext4 filesystem. This will enable rEFInd to
+read your Linux kernel if it's on an ext2, ext3, or ext4 filesystem. Note
+that some configurations will require a \fB/boot/refind_linux.conf\fR file,
+which can be reliably generated only under Linux. (The \fBmkrlconf\fR
+script that comes with rEFInd will do this job once you've booted Linux.)
+In the meantime, you can launch GRUB from rEFInd or press F2 or Insert
+twice after highlighting the Linux option in rEFInd. This will enable you
+to enter a \fBroot=\fI/dev/whatever\fR specification, where
+\fI/dev/whatever\fR is the device identifier of your Linux root (\fB/\fR)
+filesystem.
+
+.TP
+.B *
+If you run \fBrefind\-install\fR on Linux and if
+\fB/boot/refind_linux.conf\fR doesn't already exist, \fBrefind\-install\fR
+creates this file and populates it with a few sample entries. If
+\fB/boot\fR is on a FAT partition (or HFS+ on a Mac), or if it's on an
+ext2fs, ext3fs, ext4fs, ReiserFS, Btrfs, or HFS+ partition and you install
+an appropriate driver, the result is that rEFInd will detect your kernel
+and will probably boot it correctly. Some systems will require manual
+tweaking to \fBrefind_linux.conf\fR, though -- for instance, to add
+\fBdolvm\fR to the boot options on Gentoo systems that use LVM.
+
+.TP
+.B *
+If you pass the \fB\-\-shim\fR option to the script (along with a filename
+for a Shim binary), the script sets up for a Secure Boot configuration via
+Shim. By default, this causes the rEFInd binary to be renamed as
+\fBgrubx64.efi\fR. Recent versions of Shim support passing the name of the
+follow-on program to Shim via a parameter, though. If you want to use this
+feature, you can pass the \fB\-\-keepname\fR option to
+\fBrefind\-install\fR.
+
+.PP
+
+After you run \fBrefind\-install\fR, you should peruse the script's output
+to ensure that everything looks OK. \fBrefind\-install\fR displays error
+messages when it encounters errors, such as if the ESP is mounted read-only
+or if you run out of disk space. You may need to correct such problems
+manually and re\-run the script. In some cases you may need to fall back on
+manual installation, which gives you better control over details such as
+which partition to use for installation.
+
+.SH "OPTIONS"
+
+.TP
+.B \-\-notesp
+This option, which is valid only under OS X, tells \fBrefind-install\fR to
+install rEFInd to the OS X root partition rather than to the ESP. This
+behavior was the default in rEFInd 0.8.3 and earlier, so you may want to
+use it when upgrading installations of that version, unless you used
+\-\-esp (which is now the default behavior, although the \-\-esp option no
+longer exists) or \-\-ownhfs. You may also want to use \-\-notesp on new
+installations if you're sure you're not using whole\-disk encryption or
+logical volumes.
+
+.TP
+.B \-\-usedefault \fIdevice-file\fR
+You can install rEFInd to a disk using the default/fallback filename of
+\fBEFI/BOOT/bootx64.efi\fR (as well as \fBEFI/BOOT/bootia32.efi\fR and
+\fBEFI/BOOT/bootaa64.efi\fR, if the IA\-32 and ARM64
+builds are available) using this option. The device\-file should be an
+unmounted ESP, or at least a FAT partition, as in \fB\-\-usedefault
+/dev/sdc1\fR. Your computer's NVRAM entries will not be modified when
+installing in this way. The intent is that you can create a bootable USB
+flash drive or install rEFInd on a computer that tends to "forget" its
+NVRAM settings with this option. This option is mutually exclusive with
+\-\-notesp and \-\-root.
+
+.TP
+.B \-\-ownhfs \fIdevice-file\fR
+This option should be used only under OS X. It's used to install rEFInd to
+an HFS+ volume other than a standard Mac boot volume. The result should be
+that rEFInd will show up in the Mac's own boot manager. More importantly,
+suspend\-to\-RAM operations may work correctly. Note that this option
+requires an HFS+ volume that is not currently an OS X boot volume. This can
+be a data volume or a dedicated rEFInd partition. The ESP might also work,
+if it's converted to use HFS+; however, HFS+ is a non\-standard filesystem
+for an ESP, and so is not recommended.
+
+.TP
+.B \-\-root \fImount-point\fR
+This option is intended to help install rEFInd from a "live CD" or other
+emergency system. To use it, you should mount your regular installation at
+\fI/mount\-point\fR, including your /boot directory (if it's separate) at
+\fI/mount\-point\fR/boot and (on Linux) your ESP at that location or at
+\fI/mount\-point\fR/boot/efi. The \fBrefind\-install\fR script then
+installs rEFInd to the appropriate location -- on Linux,
+\fI/mount\-point\fR/boot/EFI/refind or
+\fI/mount\-point\fR/boot/efi/EFI/refind, depending on where you've mounted
+your ESP. Under OS X, this option is useful only in conjunction with
+\-\-notesp, in which case rEFInd will install to
+\fI/mount\-point\fR/EFI/refind. The script also adds an entry to your NVRAM
+for rEFInd at this location. You cannot use this option with
+\-\-usedefault. Note that this option is not needed when doing a dual-boot
+Linux/OS X installation; just install normally in OS X.
+
+.TP
+.B \-\-nodrivers
+Ordinarily \fBrefind\-install\fR attempts to install the driver required to
+read /boot on Linux. This attempt works only if you're using ext2fs,
+ext3fs, ext4fs, ReiserFS, or Btrfs on the relevant partition. If you want
+to forego this driver installation, pass the \-\-nodrivers option. This
+option is implicit when you use \-\-usedefault.
+
+.TP
+.B \-\-alldrivers
+When you specify this option, \fBrefind\-install\fR copies all the driver
+files for your architecture. You may want to remove unused driver files
+after you use this option. Note that some computers hang or fail to work
+with any drivers if you use this option, so use it with caution.
+
+.TP
+.B \-\-shim \fIshim\-filename\fR or \fB\-\-preloader \fIpreloader\-filename\fR\fB
+If you pass this option to \fBrefind\-install\fR, the script will copy the
+specified shim program file to the target directory, copy the
+MokManager.efi file from the shim program file's directory to the target
+directory, copy the 64-bit version of rEFInd as grubx64.efi, and register
+shim with the firmware. (If you also specify \-\-usedefault, the NVRAM
+registration is skipped. If you also use \-\-keepname, the renaming to
+grubx64.efi is skipped.) When the target file is identified as PreLoader,
+much the same thing happens, but \fBrefind\-install\fR copies HashTool.efi
+instead of MokManager.efi and copies rEFInd as loader.efi rather than as
+grubx64.efi. The intent is to simplify rEFInd installation on a computer
+that uses Secure Boot; when so set up, rEFInd will boot in Secure Boot
+mode, with one caveat: The first time you boot, MokManager/HashTool will
+launch, and you must use it to locate and install a public key or register
+rEFInd as a trusted application. The rEFInd public key file will be located
+in the rEFInd directory's keys subdirectory under the name refind.cer.
+
+.TP
+.B \-\-localkeys
+This option tells \fBrefind\-install\fR to generate a new Machine Owner Key
+(MOK), store it in /etc/refind.d/keys as refind_local.*, and re-sign all
+the 64-bit rEFInd binaries with this key before installing them. This is
+the preferable way to install rEFInd in Secure Boot mode, since it means
+your binaries will be signed locally rather than with my own key, which is
+used to sign many other users' binaries; however, this method requires that
+both the \fBopenssl\fR and \fBsbsign\fR binaries be installed. The former
+is readily available in most distributions' repositories, but the latter is
+not, so this option is not the default.
+
+.TP
+.B \-\-keepname
+This option is useful only in conjunction with \-\-shim. It tells
+\fBrefind\-install\fR to keep rEFInd's regular filename (typically
+refind_x64.efi) when used with shim, rather than rename the binary to
+grubx64.efi. This change cuts down on the chance of confusion because of
+filename issues; however, this feature requires that shim be launched with
+a command-line parameter that points to the rEFInd binary under its real
+name. versions of shim prior to 0.7 do not properly support this feature.
+(Version 0.4 supports it but with a buggy interpretation of the follow-on
+loader specification.) If your NVRAM variables become corrupted or are
+forgotten, this feature may make rEFInd harder to launch. This option is
+incompatible with \-\-usedefault and is unavailable when run under OS X or
+without the \-\-shim option. If the script discovers an existing rEFInd
+installation under EFI/BOOT or EFI/Microsoft/Boot and no other rEFInd
+installation when this option is used, it will abort.
+
+.TP
+.B \-\-yes
+This option causes the script to assume a \fBY\fR input to every yes/no
+prompt that can be generated under certain conditions, such as if you
+specify \-\-shim but \fBrefind\-install\fR detects no evidence of a Secure
+Boot installation. This option is intended mainly for use by scripts such
+as those that might be used as part of an installation via an RPM or Debian
+package.
+
+.SH "AUTHORS"
+Primary author: Roderick W. Smith (rodsmith@rodsbooks.com)
+
+.SH "SEE ALSO"
+\fBmkrlconf (8)\fR,
+\fBmvrefind (8)\fR
+
+\fIhttp://www.rodsbooks.com/refind/\fR
+
+.SH "AVAILABILITY"
+The \fBrefind\-install\fR command is part of the \fIrEFInd\fR package and is
+available from Roderick W. Smith.
diff --git a/docs/refind/FDL-1.3.txt b/docs/refind/FDL-1.3.txt
new file mode 100644 (file)
index 0000000..2f7e03c
--- /dev/null
@@ -0,0 +1,451 @@
+
+                GNU Free Documentation License
+                 Version 1.3, 3 November 2008
+
+
+ Copyright (C) 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc.
+     <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+0. PREAMBLE
+
+The purpose of this License is to make a manual, textbook, or other
+functional and useful document "free" in the sense of freedom: to
+assure everyone the effective freedom to copy and redistribute it,
+with or without modifying it, either commercially or noncommercially.
+Secondarily, this License preserves for the author and publisher a way
+to get credit for their work, while not being considered responsible
+for modifications made by others.
+
+This License is a kind of "copyleft", which means that derivative
+works of the document must themselves be free in the same sense.  It
+complements the GNU General Public License, which is a copyleft
+license designed for free software.
+
+We have designed this License in order to use it for manuals for free
+software, because free software needs free documentation: a free
+program should come with manuals providing the same freedoms that the
+software does.  But this License is not limited to software manuals;
+it can be used for any textual work, regardless of subject matter or
+whether it is published as a printed book.  We recommend this License
+principally for works whose purpose is instruction or reference.
+
+
+1. APPLICABILITY AND DEFINITIONS
+
+This License applies to any manual or other work, in any medium, that
+contains a notice placed by the copyright holder saying it can be
+distributed under the terms of this License.  Such a notice grants a
+world-wide, royalty-free license, unlimited in duration, to use that
+work under the conditions stated herein.  The "Document", below,
+refers to any such manual or work.  Any member of the public is a
+licensee, and is addressed as "you".  You accept the license if you
+copy, modify or distribute the work in a way requiring permission
+under copyright law.
+
+A "Modified Version" of the Document means any work containing the
+Document or a portion of it, either copied verbatim, or with
+modifications and/or translated into another language.
+
+A "Secondary Section" is a named appendix or a front-matter section of
+the Document that deals exclusively with the relationship of the
+publishers or authors of the Document to the Document's overall
+subject (or to related matters) and contains nothing that could fall
+directly within that overall subject.  (Thus, if the Document is in
+part a textbook of mathematics, a Secondary Section may not explain
+any mathematics.)  The relationship could be a matter of historical
+connection with the subject or with related matters, or of legal,
+commercial, philosophical, ethical or political position regarding
+them.
+
+The "Invariant Sections" are certain Secondary Sections whose titles
+are designated, as being those of Invariant Sections, in the notice
+that says that the Document is released under this License.  If a
+section does not fit the above definition of Secondary then it is not
+allowed to be designated as Invariant.  The Document may contain zero
+Invariant Sections.  If the Document does not identify any Invariant
+Sections then there are none.
+
+The "Cover Texts" are certain short passages of text that are listed,
+as Front-Cover Texts or Back-Cover Texts, in the notice that says that
+the Document is released under this License.  A Front-Cover Text may
+be at most 5 words, and a Back-Cover Text may be at most 25 words.
+
+A "Transparent" copy of the Document means a machine-readable copy,
+represented in a format whose specification is available to the
+general public, that is suitable for revising the document
+straightforwardly with generic text editors or (for images composed of
+pixels) generic paint programs or (for drawings) some widely available
+drawing editor, and that is suitable for input to text formatters or
+for automatic translation to a variety of formats suitable for input
+to text formatters.  A copy made in an otherwise Transparent file
+format whose markup, or absence of markup, has been arranged to thwart
+or discourage subsequent modification by readers is not Transparent.
+An image format is not Transparent if used for any substantial amount
+of text.  A copy that is not "Transparent" is called "Opaque".
+
+Examples of suitable formats for Transparent copies include plain
+ASCII without markup, Texinfo input format, LaTeX input format, SGML
+or XML using a publicly available DTD, and standard-conforming simple
+HTML, PostScript or PDF designed for human modification.  Examples of
+transparent image formats include PNG, XCF and JPG.  Opaque formats
+include proprietary formats that can be read and edited only by
+proprietary word processors, SGML or XML for which the DTD and/or
+processing tools are not generally available, and the
+machine-generated HTML, PostScript or PDF produced by some word
+processors for output purposes only.
+
+The "Title Page" means, for a printed book, the title page itself,
+plus such following pages as are needed to hold, legibly, the material
+this License requires to appear in the title page.  For works in
+formats which do not have any title page as such, "Title Page" means
+the text near the most prominent appearance of the work's title,
+preceding the beginning of the body of the text.
+
+The "publisher" means any person or entity that distributes copies of
+the Document to the public.
+
+A section "Entitled XYZ" means a named subunit of the Document whose
+title either is precisely XYZ or contains XYZ in parentheses following
+text that translates XYZ in another language.  (Here XYZ stands for a
+specific section name mentioned below, such as "Acknowledgements",
+"Dedications", "Endorsements", or "History".)  To "Preserve the Title"
+of such a section when you modify the Document means that it remains a
+section "Entitled XYZ" according to this definition.
+
+The Document may include Warranty Disclaimers next to the notice which
+states that this License applies to the Document.  These Warranty
+Disclaimers are considered to be included by reference in this
+License, but only as regards disclaiming warranties: any other
+implication that these Warranty Disclaimers may have is void and has
+no effect on the meaning of this License.
+
+2. VERBATIM COPYING
+
+You may copy and distribute the Document in any medium, either
+commercially or noncommercially, provided that this License, the
+copyright notices, and the license notice saying this License applies
+to the Document are reproduced in all copies, and that you add no
+other conditions whatsoever to those of this License.  You may not use
+technical measures to obstruct or control the reading or further
+copying of the copies you make or distribute.  However, you may accept
+compensation in exchange for copies.  If you distribute a large enough
+number of copies you must also follow the conditions in section 3.
+
+You may also lend copies, under the same conditions stated above, and
+you may publicly display copies.
+
+
+3. COPYING IN QUANTITY
+
+If you publish printed copies (or copies in media that commonly have
+printed covers) of the Document, numbering more than 100, and the
+Document's license notice requires Cover Texts, you must enclose the
+copies in covers that carry, clearly and legibly, all these Cover
+Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on
+the back cover.  Both covers must also clearly and legibly identify
+you as the publisher of these copies.  The front cover must present
+the full title with all words of the title equally prominent and
+visible.  You may add other material on the covers in addition.
+Copying with changes limited to the covers, as long as they preserve
+the title of the Document and satisfy these conditions, can be treated
+as verbatim copying in other respects.
+
+If the required texts for either cover are too voluminous to fit
+legibly, you should put the first ones listed (as many as fit
+reasonably) on the actual cover, and continue the rest onto adjacent
+pages.
+
+If you publish or distribute Opaque copies of the Document numbering
+more than 100, you must either include a machine-readable Transparent
+copy along with each Opaque copy, or state in or with each Opaque copy
+a computer-network location from which the general network-using
+public has access to download using public-standard network protocols
+a complete Transparent copy of the Document, free of added material.
+If you use the latter option, you must take reasonably prudent steps,
+when you begin distribution of Opaque copies in quantity, to ensure
+that this Transparent copy will remain thus accessible at the stated
+location until at least one year after the last time you distribute an
+Opaque copy (directly or through your agents or retailers) of that
+edition to the public.
+
+It is requested, but not required, that you contact the authors of the
+Document well before redistributing any large number of copies, to
+give them a chance to provide you with an updated version of the
+Document.
+
+
+4. MODIFICATIONS
+
+You may copy and distribute a Modified Version of the Document under
+the conditions of sections 2 and 3 above, provided that you release
+the Modified Version under precisely this License, with the Modified
+Version filling the role of the Document, thus licensing distribution
+and modification of the Modified Version to whoever possesses a copy
+of it.  In addition, you must do these things in the Modified Version:
+
+A. Use in the Title Page (and on the covers, if any) a title distinct
+   from that of the Document, and from those of previous versions
+   (which should, if there were any, be listed in the History section
+   of the Document).  You may use the same title as a previous version
+   if the original publisher of that version gives permission.
+B. List on the Title Page, as authors, one or more persons or entities
+   responsible for authorship of the modifications in the Modified
+   Version, together with at least five of the principal authors of the
+   Document (all of its principal authors, if it has fewer than five),
+   unless they release you from this requirement.
+C. State on the Title page the name of the publisher of the
+   Modified Version, as the publisher.
+D. Preserve all the copyright notices of the Document.
+E. Add an appropriate copyright notice for your modifications
+   adjacent to the other copyright notices.
+F. Include, immediately after the copyright notices, a license notice
+   giving the public permission to use the Modified Version under the
+   terms of this License, in the form shown in the Addendum below.
+G. Preserve in that license notice the full lists of Invariant Sections
+   and required Cover Texts given in the Document's license notice.
+H. Include an unaltered copy of this License.
+I. Preserve the section Entitled "History", Preserve its Title, and add
+   to it an item stating at least the title, year, new authors, and
+   publisher of the Modified Version as given on the Title Page.  If
+   there is no section Entitled "History" in the Document, create one
+   stating the title, year, authors, and publisher of the Document as
+   given on its Title Page, then add an item describing the Modified
+   Version as stated in the previous sentence.
+J. Preserve the network location, if any, given in the Document for
+   public access to a Transparent copy of the Document, and likewise
+   the network locations given in the Document for previous versions
+   it was based on.  These may be placed in the "History" section.
+   You may omit a network location for a work that was published at
+   least four years before the Document itself, or if the original
+   publisher of the version it refers to gives permission.
+K. For any section Entitled "Acknowledgements" or "Dedications",
+   Preserve the Title of the section, and preserve in the section all
+   the substance and tone of each of the contributor acknowledgements
+   and/or dedications given therein.
+L. Preserve all the Invariant Sections of the Document,
+   unaltered in their text and in their titles.  Section numbers
+   or the equivalent are not considered part of the section titles.
+M. Delete any section Entitled "Endorsements".  Such a section
+   may not be included in the Modified Version.
+N. Do not retitle any existing section to be Entitled "Endorsements"
+   or to conflict in title with any Invariant Section.
+O. Preserve any Warranty Disclaimers.
+
+If the Modified Version includes new front-matter sections or
+appendices that qualify as Secondary Sections and contain no material
+copied from the Document, you may at your option designate some or all
+of these sections as invariant.  To do this, add their titles to the
+list of Invariant Sections in the Modified Version's license notice.
+These titles must be distinct from any other section titles.
+
+You may add a section Entitled "Endorsements", provided it contains
+nothing but endorsements of your Modified Version by various
+parties--for example, statements of peer review or that the text has
+been approved by an organization as the authoritative definition of a
+standard.
+
+You may add a passage of up to five words as a Front-Cover Text, and a
+passage of up to 25 words as a Back-Cover Text, to the end of the list
+of Cover Texts in the Modified Version.  Only one passage of
+Front-Cover Text and one of Back-Cover Text may be added by (or
+through arrangements made by) any one entity.  If the Document already
+includes a cover text for the same cover, previously added by you or
+by arrangement made by the same entity you are acting on behalf of,
+you may not add another; but you may replace the old one, on explicit
+permission from the previous publisher that added the old one.
+
+The author(s) and publisher(s) of the Document do not by this License
+give permission to use their names for publicity for or to assert or
+imply endorsement of any Modified Version.
+
+
+5. COMBINING DOCUMENTS
+
+You may combine the Document with other documents released under this
+License, under the terms defined in section 4 above for modified
+versions, provided that you include in the combination all of the
+Invariant Sections of all of the original documents, unmodified, and
+list them all as Invariant Sections of your combined work in its
+license notice, and that you preserve all their Warranty Disclaimers.
+
+The combined work need only contain one copy of this License, and
+multiple identical Invariant Sections may be replaced with a single
+copy.  If there are multiple Invariant Sections with the same name but
+different contents, make the title of each such section unique by
+adding at the end of it, in parentheses, the name of the original
+author or publisher of that section if known, or else a unique number.
+Make the same adjustment to the section titles in the list of
+Invariant Sections in the license notice of the combined work.
+
+In the combination, you must combine any sections Entitled "History"
+in the various original documents, forming one section Entitled
+"History"; likewise combine any sections Entitled "Acknowledgements",
+and any sections Entitled "Dedications".  You must delete all sections
+Entitled "Endorsements".
+
+
+6. COLLECTIONS OF DOCUMENTS
+
+You may make a collection consisting of the Document and other
+documents released under this License, and replace the individual
+copies of this License in the various documents with a single copy
+that is included in the collection, provided that you follow the rules
+of this License for verbatim copying of each of the documents in all
+other respects.
+
+You may extract a single document from such a collection, and
+distribute it individually under this License, provided you insert a
+copy of this License into the extracted document, and follow this
+License in all other respects regarding verbatim copying of that
+document.
+
+
+7. AGGREGATION WITH INDEPENDENT WORKS
+
+A compilation of the Document or its derivatives with other separate
+and independent documents or works, in or on a volume of a storage or
+distribution medium, is called an "aggregate" if the copyright
+resulting from the compilation is not used to limit the legal rights
+of the compilation's users beyond what the individual works permit.
+When the Document is included in an aggregate, this License does not
+apply to the other works in the aggregate which are not themselves
+derivative works of the Document.
+
+If the Cover Text requirement of section 3 is applicable to these
+copies of the Document, then if the Document is less than one half of
+the entire aggregate, the Document's Cover Texts may be placed on
+covers that bracket the Document within the aggregate, or the
+electronic equivalent of covers if the Document is in electronic form.
+Otherwise they must appear on printed covers that bracket the whole
+aggregate.
+
+
+8. TRANSLATION
+
+Translation is considered a kind of modification, so you may
+distribute translations of the Document under the terms of section 4.
+Replacing Invariant Sections with translations requires special
+permission from their copyright holders, but you may include
+translations of some or all Invariant Sections in addition to the
+original versions of these Invariant Sections.  You may include a
+translation of this License, and all the license notices in the
+Document, and any Warranty Disclaimers, provided that you also include
+the original English version of this License and the original versions
+of those notices and disclaimers.  In case of a disagreement between
+the translation and the original version of this License or a notice
+or disclaimer, the original version will prevail.
+
+If a section in the Document is Entitled "Acknowledgements",
+"Dedications", or "History", the requirement (section 4) to Preserve
+its Title (section 1) will typically require changing the actual
+title.
+
+
+9. TERMINATION
+
+You may not copy, modify, sublicense, or distribute the Document
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense, or distribute it is void, and
+will automatically terminate your rights under this License.
+
+However, if you cease all violation of this License, then your license
+from a particular copyright holder is reinstated (a) provisionally,
+unless and until the copyright holder explicitly and finally
+terminates your license, and (b) permanently, if the copyright holder
+fails to notify you of the violation by some reasonable means prior to
+60 days after the cessation.
+
+Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, receipt of a copy of some or all of the same material does
+not give you any rights to use it.
+
+
+10. FUTURE REVISIONS OF THIS LICENSE
+
+The Free Software Foundation may publish new, revised versions of the
+GNU Free Documentation License from time to time.  Such new versions
+will be similar in spirit to the present version, but may differ in
+detail to address new problems or concerns.  See
+http://www.gnu.org/copyleft/.
+
+Each version of the License is given a distinguishing version number.
+If the Document specifies that a particular numbered version of this
+License "or any later version" applies to it, you have the option of
+following the terms and conditions either of that specified version or
+of any later version that has been published (not as a draft) by the
+Free Software Foundation.  If the Document does not specify a version
+number of this License, you may choose any version ever published (not
+as a draft) by the Free Software Foundation.  If the Document
+specifies that a proxy can decide which future versions of this
+License can be used, that proxy's public statement of acceptance of a
+version permanently authorizes you to choose that version for the
+Document.
+
+11. RELICENSING
+
+"Massive Multiauthor Collaboration Site" (or "MMC Site") means any
+World Wide Web server that publishes copyrightable works and also
+provides prominent facilities for anybody to edit those works.  A
+public wiki that anybody can edit is an example of such a server.  A
+"Massive Multiauthor Collaboration" (or "MMC") contained in the site
+means any set of copyrightable works thus published on the MMC site.
+
+"CC-BY-SA" means the Creative Commons Attribution-Share Alike 3.0 
+license published by Creative Commons Corporation, a not-for-profit 
+corporation with a principal place of business in San Francisco, 
+California, as well as future copyleft versions of that license 
+published by that same organization.
+
+"Incorporate" means to publish or republish a Document, in whole or in 
+part, as part of another Document.
+
+An MMC is "eligible for relicensing" if it is licensed under this 
+License, and if all works that were first published under this License 
+somewhere other than this MMC, and subsequently incorporated in whole or 
+in part into the MMC, (1) had no cover texts or invariant sections, and 
+(2) were thus incorporated prior to November 1, 2008.
+
+The operator of an MMC Site may republish an MMC contained in the site
+under CC-BY-SA on the same site at any time before August 1, 2009,
+provided the MMC is eligible for relicensing.
+
+
+ADDENDUM: How to use this License for your documents
+
+To use this License in a document you have written, include a copy of
+the License in the document and put the following copyright and
+license notices just after the title page:
+
+    Copyright (c)  YEAR  YOUR NAME.
+    Permission is granted to copy, distribute and/or modify this document
+    under the terms of the GNU Free Documentation License, Version 1.3
+    or any later version published by the Free Software Foundation;
+    with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
+    A copy of the license is included in the section entitled "GNU
+    Free Documentation License".
+
+If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts,
+replace the "with...Texts." line with this:
+
+    with the Invariant Sections being LIST THEIR TITLES, with the
+    Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST.
+
+If you have Invariant Sections without Cover Texts, or some other
+combination of the three, merge those two alternatives to suit the
+situation.
+
+If your document contains nontrivial examples of program code, we
+recommend releasing these examples in parallel under your choice of
+free software license, such as the GNU General Public License,
+to permit their use in free software.
diff --git a/docs/refind/HashTool1.png b/docs/refind/HashTool1.png
new file mode 100644 (file)
index 0000000..75d1ae6
Binary files /dev/null and b/docs/refind/HashTool1.png differ
diff --git a/docs/refind/HashTool2.png b/docs/refind/HashTool2.png
new file mode 100644 (file)
index 0000000..dc52550
Binary files /dev/null and b/docs/refind/HashTool2.png differ
diff --git a/docs/refind/MokManager1.png b/docs/refind/MokManager1.png
new file mode 100644 (file)
index 0000000..89d28cd
Binary files /dev/null and b/docs/refind/MokManager1.png differ
diff --git a/docs/refind/MokManager2.png b/docs/refind/MokManager2.png
new file mode 100644 (file)
index 0000000..740eb99
Binary files /dev/null and b/docs/refind/MokManager2.png differ
diff --git a/docs/refind/about.png b/docs/refind/about.png
new file mode 100644 (file)
index 0000000..378c59f
Binary files /dev/null and b/docs/refind/about.png differ
diff --git a/docs/refind/about.svg b/docs/refind/about.svg
new file mode 100644 (file)
index 0000000..47b2b8b
--- /dev/null
@@ -0,0 +1,972 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   width="525"
+   height="559"
+   sodipodi:docname="about.svg"
+   inkscape:export-filename="/home/rodsmith/programming/refind/current/docs/refind/about.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90">
+  <metadata
+     id="metadata8">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs6" />
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1190"
+     inkscape:window-height="936"
+     id="namedview4"
+     showgrid="false"
+     inkscape:zoom="1.1941123"
+     inkscape:cx="118.45995"
+     inkscape:cy="279.5"
+     inkscape:window-x="0"
+     inkscape:window-y="0"
+     inkscape:window-maximized="0"
+     inkscape:current-layer="svg2" />
+  <image
+     width="525"
+     height="559"
+     xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAg0AAAIvCAIAAAB4Hn/+AAAAA3NCSVQICAjb4U/gAAAgAElEQVR4
+nOydeXhV1bn/1x7OPM8nJwNJSAIJgwwhjAqKIoN0umK1Wq3F2uq9tmptte31V20tt63trVbbWgdU
+UISrTDKEGRkiIiAIMgYykJDxnJx52Pvs4ffHMtvDycnOCaPA+3l4eMg+a6+99s7h/e71vu96F3Hg
+wAEEAAAAAL1AXu4BAAAAAF9rQCcAAAAAOUAnAAAAADlAJwAAAAA5QCcAAAAAOUAnAAAAADlAJwAA
+AAA5QCcAAAAAOUAnAAAAADlAJwAAAAA5QCcAAAAAOUAnAAAAADlAJwAAAAA5QCcAAAAAOUAnAAAA
+ADlAJwAAAAA5QCcAAAAAOejLPQDgMiOejSAIgiBIPyKESJIkCIIkSfyPVC732AEAuBSATlyjYA3A
+ksDzPM/zHMexbLKtTWht5f1+3u9HWi2yWvmcHNLpJJVKWoKiKIqisHgghEAwAODqBnTiWkSaN3Ac
+l0wmW1vZjRu5jz8mGhrIWIxAiE79YhAE0mp5lytZWRmdPFkYMECFUSgUNE1L8wzUrT3dZ4F4AMBV
+AnHgwIHLPQbg0iE5l5LJZDDIbtzI7NwpHDhAM0xWp9O0UF6eGDeOnTyZtNu1Go1GqVQqFAo8sZBc
+VeCbAoCrCdCJawisEDzPMwyzalXi9deFri7q3LqyWNg77wxNnUobjUaNRoOlguf5Tz7hxowhKIrC
+R7B+XEpS5zTyZKNh2fR2JWphz/u6Eu8CuGSATlwr4DhEMpns7Iy/9BK7aROdtUXNDEGgqqrA978f
+LygwabVaiqLefZdbtIhYsoTRatV4qoHDGBfoDnoFWz1pNpO9cc846Untrc+u5PuRupI+/TqYY/y6
+kDb5k5yHANATiE9cE+BoBMuyO3dGX3pJbGq6AL93UUS7d5tPntTccYd34sTQ+vXGFSvUCIkHDvgr
+KjQkSeLoxcW2PlKshed5KVmrz7PwwHBAXsrjQt1qKooix3GSPe1vP6mZY7g3/DS+DuYYjyqZTEYi
+EY7j1Go1RVFKpRKnJ4BUABkBnbj6wTaLYZj582MLFyKWvZC+IJ9P9corOR99FGhsVMZiJEJo375E
+bi6r0WhUKhVFnaNfK0ukSVJLC3PiBOv384mEIIqC/FkkSeTlocGDSY1GqVarsZVE3Q+KZdna2sTp
+08lAQEgm5XojiC/70WqVOLaP1QKPKh5nPvmEqa/nxowR8vNp3ODSaGdv4Bvs7Oz885//vGvXLkEQ
+Ro4c+eSTTxqNRq1We8nmf8AVB+jEVQ62WSzLrl4de+stxPN9WAGaZm02r8EQIghaEKh4XOn3W+Nx
+jcwpSiVfV2dgmC+/S8eOqadM8ZrNZo7jlEol9rpcsPtJAd8aw7Dz5sXWrRN5nuzXulGlUvzNb7pG
+j9biEAu2711diSeeSBw8iBCiEMpK5Gha+PnP/ddfr8H9IIQEQairi/3kJ6zfTyBE/etf1COP+G+5
+RYXN8eUK70sq+Oabb27duhUf3L1796ZNm2688Uac8XzZpzvA1xPQiasZKbVp//7Yyy/LiYTV2pab
+25qTEyosDBoMCunNVxTFZPLE6dPq48dtx47lhsO6tBNpOsHzIsd9JSR+vyIWi7Esm6UL6JzBOrFs
+WXzNGoRQv60byxIrV4qFhT5sIhUKRTKZ/N//jR082L/5FseRq1ej8nIvRVFSP++8g0XiS9atI0eO
+9GIPD0VRF0875REEwefzrVixIvVgbW3tqFGj9Ho9nlddrrEBX2dAJ65msJ+9pYWZN48PhzO/HavV
+0WHDvhg1qslkMhqNRq22ELsgFAoFdrVzHDdgAFtZGQ8GD3/8sX7nzgHR6JdqQdMJhM4SCYRQPE4n
+EgmWZbFr/uLdGpbALVu4LF/8e9LZSYZCIZPJpNVqSZJMJNiamnMxkV1dX/aj0+kIgvD7mfXrz2oQ
+Col+v99gMBgMBqVSeW6jPU+wrB49epRl2dTjarU6Ho/jeAyIBJAR0ImrFmxJo1H2D39gzpzJYEkJ
+QigsPD5+/Im8PI3VWmixWPR6vVarxWvocFYrNi4cxzEME41GXa7wiBEnly51nTzppmkGIZQmEgih
+ZJL2eomCApbjODyluHh+J4Zhjxw59xBIaWmzIJCCICCEeJ4/cYINh88leFNWdkYKoQuCcOIEy7Jn
+jUqvDyYSCemBnPOAzxmsATzPnzhxIu0js9l8WYYEXEGATlydSM7oBQvin32WWSSqqnaMHu1zOp0O
+h8NqtRoMBq1Wq1AopOwdqStc2MNoNBqNRp0u4HC0/f3vdFubiWUVPXtOJDT19fohQ5hkMnlhzWKq
+5OBRNTVxDNM/y05RgtXqdTq9xcXBMWNErTZHqVQSBCEIQm0tn32Eg6J4q9XrdPqKi4OVlYJO51Gp
+VARB8DxfV8enTXEslqA0+OxVU8pb7c/9yfXG83xdXd3Zd0FZrVYcvv76ZO4CXzdAJ65aBEFIJNgN
+GzJ/Onz4vqqqQE5Ontvtttlser1eo9FIkczUWKsoijRNC4KAUydFUZw/X9vRoWPZzF8eUSRrax2J
+hI9l2f6GstMWQKSOIfUgdogJglBXJ6RZ9oED944dexDfTsbsHRxFUCqVOp3ObDbbbDadTkdRFMdx
+DQ3pkjZmzJrBg716vV6lUqXFeKV+tFqtxWLB/dA0nUwm6+vTU6Ss1iBNa9LUN+Od9vxIumXUTyOe
+2gPO0OU4rr6+PrWN0WhMLcECIgFkBHTi6gTXblq7lmlpyTCZKC09dP31Z3JyPLm5uTabDRuLtJUE
+EtgokySJze4LLyh37VInEnLv3YGANh5vZhimX/OJ1DUH+Lp4PPhFWHJh4elO99sxn/Yddjiidrvd
+4XAYjUY8UUi7HXwjCoVCrVZrNBpJA1iWbWxMt5IeD+N0Ou12u16vVygUKMVS9+wHx6hZlj19Ov3h
+OBwJpdKUVuBEWl2Bb0rqWTouCAIef2rhxT5Nedo6QcnjlEwmo9HomTNnUhubzWYce8c60fcvCbgm
+AZ24CsGmIZlMZpxMWCztU6YcdTrz3G633W43Go14sZVMvmZ3QJv/1a+Se/ZQLNuHqYrHleEwyzBf
+uZ6ysW44f7exsfHgwYMjRoyw2WzYeIVCoUOHDh05csTpdFZWVtrtdjxgnudPn07v1umMmc1mh8Nh
+sVh6TgIwJEkqUqAoCutTU9NZhpKiki4Xb7FYXC4Xjj+nWlL8uHr2w/N8UxN1dj+c3c7gbCLcQ/cq
+jdoDBw5UVFQUFhZiS43dVh0dHSdOnDh16pTBYCgoKCgoKDCZTDizAI+ht9+U2F0DGA8DTyDwPwKB
+QGtra88gtsViwStI5L8AwDUO6MRVCE5S2rs3cehQhslERcUJu92GX5MNBkOfIiH1GY2KkycLWm2i
+rk6IRIRYjGRZmmWVoph+YiKhOn1aN3Dgl6HsbAaMReJnP/vZnj17EEIURb300ktWq/Xtt99et26d
+NCmhKOpvf/tbcXGxTqfjOK6hIW3qg4zGqCCYeJ5KJgnJx5PSgFAoEEl+OVmR3tNFUYxGuY6Osx6X
+wRASRVoQaI4jk0kitSuCIFQqRFEk7kRazCyKYjDI+/1n9WM0BlUqJU41xm3i8fjcuXNra2txgx/8
+4AezZs1SKpWbNm1avHhxZ2dn6ukqleq22267/fbbLRaLTqeTfl89n6G01ppl2X379q1fv76pqamr
+q8vn83Ecl/HJ2+12LD+wwg6QAXTiagPbC47j1q3jRTHdk2CxeIcP77RYCi0WiyQS2TgcCILQ64mp
+U8mRIxNdXV3BYDASiba3ky0tqsZGU2enOR5XMQydSKhFkeR5xfHjjhtuYKRsS/kpBdaJHTt2YJFA
+CPE8v3Llytra2rS4K8/za9asueeeexBCgiC2tKjO7ge9887t8jdC02JREXvzzZFZsxR6vR4bekEQ
+6uuFtMcVCNhee+3bvfWj1QolJcztt8crK9V6vR6vPMf9pIVMzGa/tG8HQRAcx23cuFESCYTQxo0b
+TSbT8uXLT58+3fNCDMMsXbp0586dzz77bF5eniiKeDVfaqhDSlvo7OxctWrV2rVrW1pa5J8Dxm63
+S2tlsmkPXJuATlyF4PnE0aMZJhNlZccsFjMWCRyTyP4tkqIolUplNpsVCoXRaGQYJj8/ybIsw8QT
+CT/DMIGA2NioratzeL3GaFRHkkl0dgi6t9FiL9myZctSj69PW4PQTTgcjkQiWq22tZXiuH5bN44j
+amtVzc3Udde15OV9eVOCIPQMdcgTi5EHD2qiUaGoyIfLNykUim6dOAubLSJVB8l4py0tLX//+9/l
+n1J7e/sbb7zx8MMPS6WiUmtJ4cTlN95445133ult6tATiqIcDodUGR78TkBvgE5cbeBXy7Y2rqUl
+/f88QYgDB/oNBjcuICFZh2y6xdFU7PFXqVR8N8lkEjs6WJZlGGbQIJZhQoIQUKlUer0lYyQ545g5
+jjt58mSfw6Bpury8HDtYGhrOfeVEPE4fPx41myM4SYnn+fr6czGRjY3qrq4GrVaLV+rxPF9fn27u
+bbawUqnBoQWsE6dOnUptkGWof8+ePQcPHhw7dqyUmYa6H10wGHzuuee2bdvWr8Hj/AUpcAIiAfQG
+6MRViCAIR49yPJ/+y9Xrgw4HwovppNybLMFGBDupcKpranoSFgy2G47jaJrW6XTSlEXe6SQIQigU
+8vl8MgNQqVS5ubljxowpLi7GOa89g9jZo9EwJlOQ4yxSZlEml0/feDw+nNYl0TPZyemMKZUmPAlA
+CJ05cyaRSGTszWq12mw2s9nMMEx9fX04HE5rcPTo0fLycik/DSHEcVxbW9vjjz8ur7JardZgMLS3
+t6ceTEt2Ap0AegN04qpCMt+RSIbosdkcVKlU55zfIjk60i6HX2kpiuI4tGcP4jhqzBhGSgHKRo14
+nk97xcbY7fbBgwcXFhaazWa1Wq3VavV6vd1uN5vNSqWyqSn7sX+FwRB0ubqqqloNBh0eYfeSvX7M
+TghCsFj8bnfgpptaNBq79HbPcVxzc1qyU9JqTUpL3AVBSFvBgFGpVGPGjBk2bBgOGpEkGYvFFi5c
+2NramtrszJkzkUiEYRhJ3hKJxDPPPJNRJLRabUVFhdvtdrlcWq22q6vr3XffTW2QluyU/e0D1xqg
+E1choiiybAZXhtEYkhzl5/z+mHpW6uKGf/2L2bFDbGlREoTo8ZDTpsVnzRKxWmB/S2+Xw0rT0NCQ
+dtxqtd56660ulwuvFVer1VgqNBqNWq3mOK65OS3ZSZg69f90OrVaraZpBUlmSIfValmDAWk0GqPR
+iFdF4Nf8cJj3+dKSlNrHj9+q0Wh6rtcjSdJkYjQaUqfTmUxWaYUdQigYFP3+s3TRZAqoVErpmfdc
+6YYQoihq6tSpZWVlTqfTYrHg4rUMw0ybNu3tt99ObRmNRvF0TVo398Ybb3z22WdpHdI0PXTo0MrK
+SvzocIeBQCCtmd1uVyqVoBNAn4BOXG1gs5txv2uSpC54+WisE7t2JVasEPH+EwgRp0+rly5FJSXt
+gwcTOM+nt1mFtAqsp06Ul5e73e7c3FyHw4Gj7lh1cDQ4GIy0tqbXUMrL41wundVqxa/kPRcM4iAw
+XkSt1+t1Op0UfE5LdjKbuwYMIJ1OE3bypPaGQzU0TeMVdrjeCU3THMfV1XEIKc7uJ4ADxdhNlFER
+hw0bVlJS4vF43G43fsdHCCUSiUGDBqW1lCJDOKVt3759CxYsSGvjcDhuuumm3Nxcu92OdQJXHqyp
+qenZMnVVBwD0BujEVYgoihSVwe/EskrUyyad53wh7HSaPz8Zi51ltf1+9aZNpNsdyGYDHJ7ne6aE
+FhcX22w2XH4KG2JJb1iWPXMGpeX1GI0Bi8XidrudTqf0gp+GtGZCWhxHEATDMD2TlOz2iMViycnJ
+sdlseEohfYSfHt2NtEROFMVegthK3AYhJAhC2p1SFHXdddfZ7XZ8p3jhtyiKePl3GlKtWbxOYuHC
+hWkxcLVaffPNNxcUFOTk5GAHHR48wzBpwQmKovB8ApKdgD4BnbgKIQhCpcrwf55hlCjrnZ+zBCfw
+dHRk+CiZjMViRJ8bUWA/e3Nzc+pBXDEJVx7EvibpjR5X9ciUfho2GAwmk8lqtfamE9ga4lK4+N/Y
+gdPTvjudUZPJhAtA4VUmaf3gHtL66VkhymaLqFQ6aS03x3FplTOwY81isUjL6LCbDmcxpfVmNpux
+4gqCcObMmb1796aN6oYbbsjPz8/Nzc3JycEigSdMPM+nXRfPky77FnvAFQHoxFUIQRCaTBvQJRJK
+XMghmzXS2YBdRolEMlO5J7GkpJHn8/tcPCEIQjQa9Xq9qcfdbjdONlWr1VKRc9SdQsrzfF1dT4sc
+TQ1g9NxyNdVxlHpcEISelZ1croRabcVV1rHt7q0fKbYvCEJjY/pzcLniSqUFT1wQQi0tLczZPsH8
+/Hy8L0XqxAtrYc+1clItE1EUV6xYkfZsi4qKBg0a5HA4cJwDe9Xwyj5BENJ6g2QnIHtAJ6428Ott
+cTEiCJRmor1eazCIJKnIpuySPNjKHzrEhcPpThKtNmY0JiV3k8yFBEFoaGhIM3k5OTnY4mf0WQmC
+0NiY3o/DEVWpHLi9NGPoc/z4FtKSnWiatVi41EKqffaGJfPMmbN0gqZZiyUpxQAEQUhbXo4Qcjqd
+OFqOm0lXEUWxqUdGl8PhwKEOnuf379+f9ml+fr7JZLLZbHjnJSmbSxTFnvqEAyG4DYgEIA/Er64q
+pNiDx0M4nWzapxynPHzYEovFpMTK8/E+ScGJTz7J0InBEJRiADJhUtxJT+vpcrnUanXGFePdyx3S
+HEGi3Z6QIsZZettxVz0rMpnNfpwIlKXvHvfj9/OBwFn9mEwB3I+kEz2D2E6nE6dypd5pRl+cVqvV
+6XS4N0EQ0uINCKG8vDw8NcHuJmlGlTEZFwexIdkJyAbQiasQvA/zwIEZ6jecOGGNRqN4X9Lz9D51
+L9Rgt23LMCs1GqPY0Et1jTL2gF/DG8+eHeAQK14qnGb08SmJBNfenpbsFNJoqHNI+RUE4dSp9Adl
+NgclG5plb92VP87CYgnKJzupVCpcr1d6SvhaWIDTIgomk0lahxEIBGKxWOqnarXaarVqNBqpDT6O
+f0296UR/l1sC1ybwFbnawMFVhUJRWZlBJ5qacvfvp8PhcCKROJ/95sTu7ak//JD1ejN8i/LzOySd
+kLezPVOAjEYjtncZjb4gCI2NPM+fdRAvIZTSikRZ0u4iU6jjqySlPs2o5LzqGQy3WELSfCLjnVos
+Fnyhnpa9vb09Ho+nNZZa9lwMIQiCtBFhmqxmVGKbzZb6hGFKAcgAOnEVghP8r7+eNJvTXU+iiLZu
+HeDz+cPhMMuy2Pt0DpfA1qe5ObFkSYavkE4XGjLEJ1MEu0c/ZzlYZDbP6bbs6TMhszkoVfaW1qCl
+Ia08wOqYsnQjY5KSKvt37d76cTiiqf1wHNczmCxNm1Lte8YZQOocKy8vLy2hi2VZr9ebdr9Yy5PJ
+ZFqoAyo7Af0C4thXG1J2v8GgHjUqtmWLMq1Be7t55crA97/flWrEs3c+SOaVYZh//jPZ1ZXhKzRg
+QKPBoMc6IRU3zdiVIAixWCzN1d7b5jnSpXu+uZtMAeyricfjxNnbw0mPBd9maolv1EuSktMZVyqt
+0qZA2TyWjElTTmcUJzvhx3vmzJm0YLLNZksLEkgC1jOSgZc74MErFIrCwsK0ch2rV6/2eDwmk4mm
+aVwrECc7xeNx+W3sQCcAeUAnrkKwNVSr1XPmhD/5hE9bAYcQqqkZYLM1fPvbPmyeVCoVStmEWQbJ
+Usfj8ddei23fnuH7o1LFR49uNJlysildjl0xaXMa+RBrxlp7tbUDvV5SpVIplYgkEz3PIgiUkyNe
+d504apTCYPjSid+9/VxaklLCYuH75ZPpnhWlJU0lLBZB6idjspNk+lN1GvfWc+Ghy+WSJgGiKJaU
+lKTpRCAQeP7550tKSgYPHmy1Wo1GI0KIYRifz5dWeRAvCoFkJyBLQCeuTnCIIj9fM3VqYNUqW9qn
+okisWVOg1Z6eMcOLENLr9akbFsnEnMXurQ7mz4+98w6d0WVVUfGFx6Mym804OafPZKeMKUC9hVi7
+k53SR9je7umR/pOBZcvQXXd1zZkTt1gs2EnV1cWHQmfZd4sliLd4y9LvhIck3w9eGdfTlSSZ/jR7
+LQhCmqcIryaR5hMIocrKynXr1vUcTG1tbeomSBmByk5Av4D4xFUIfgVWKBQ6ne473xFzcmI923Ac
+tXjxgNdfp1paOoPBYDQaZRgGL8hKdd9LQVrs8WcYpq0t+swzsbffziwSZrOvquoMLo6NF0XLOJ1w
+z2k6QdM03gE7Y05qt1E+9/ebrVtVPp8vGo3iMH5jY8913X6ZKHpGRFHs2Y/d/lU/uE3aFAHXhpIC
+GKnJTni5dWpjKZKBjTtFUWPHjr3uuuvO4QkghBwOB+4NnE5ANoBOXJ3grCeVSuVyGR9+OGA0Ztjw
+QBTJ7dtdv/udcdWqYEdHRyAQkFJmk8mkFA5NJpMMwyQSiUgkunJl6Cc/YbdsySwSNJ244YY9LpcV
+77ydzX55oiiGQqHUI0VFRXhBtczbrkqVnoGaPRpNDJfmxorIMOl3MnRoM14HnmVRdHwXsVjPfppw
+P1L1pzTnD97lO6P/RxRFlj0rB6G0tBQvPJTiE1qt9uGHH87Pz+/HzSOEEDIajS6XC6+xgGQnIBtA
+J65OpOxYvV4/bJjxRz/qVKuTGVuePm149VX3Y49p3n47fPx4R1dXVyAQCIVCeHvRcDgcCoUOHAi+
++WbovvvYP/2Jbm3t7V1eHD16/+DBpMPhwJOJLPfLq6ysTP1x9OjRJpOpt9PxfU2YkKkcbhZQFD9h
+wgmpW4IgrruO0Gq/mgo4HJ3FxQIuYy4zGerJ8OFIpfpKKlyuzqIiUeoHX7Gqqir1RiorKw0Gg3Sn
+qb2RJDl27FjpR41GM3LkSJwujHUCx59yc3N/85vfTJ482WAwZP8QRo0aZTKZ9Hp9NlnLAIAQon7y
+k59c7jEAFwVpbTZJkjYbr9X6Dh3SC0LmN4NwWHH4sLa6Wr1uHdqxg9u3j/34Y27zZra6mn/rLWLJ
+Enr/fioUknurKC//YsqU1pycnJycHLzgK5vFB4IgWK3WYDDo9XqdTuf1119/3XXXOZ1Oq9WKK6dm
+9DtVVMT0eq9O10VRcYIQlMqEStXHH7M5VFDQMmPGwbIyJS6kqtVqKYpCSLDZQoFAIpEQ3e6uGTOO
+FRSYcX2kPpN6pSGJokgQvF7v9/mSyaSQm+u99dZjBQWW1H6kO+3s7PR4PDfccMOQIUPcbrdUtTB1
+/QTP8x6PJxQKRSKR4uLim266qaioCFcMxPVfcSkRvBPtoEGDqqqqPB4P3rccRzKwO0t1Nk6ns6qq
+aty4cW63G2+/Aa4nIBuIAwcOXO4xABcLbFVZlo1EIj6fb+lS5oMPci9QodizrlNRsX/q1Kbc3Nzc
+3Fyn04n3POjTyOJNFKLRqM/n8/l8kUiEIAiDwWC32y0WC64lnqY0+Hai0WhXV5ff7w8Gg/F4HPvH
+5IeIfTV6vd5sNtvtdpPJpNFoCIJIJBLYdvv9/mQyqVKprFYrbpCN3wx1m/V4PB4IBDo7OwOBAMuy
+eHW01A/OT029U5IkcTFaSbGkO+V5Hv/KvF5vV1dXIpHAAiANW1rdjSNGsVgMz/+i0Wg8Hsc+Q2ml
+SOpQsbcK14DC2yvBemwgGyDf6WpG8j7pdDpRFL/1rU6WbV6/3pVIZNjb4NygKHbo0L0TJrS63Xlu
+txtbnywTafBCB2xSVSpVIpEgCEKtVkv5V5nSWwmaprVaLUmSGo3GYrFgs9jTJqadhXOFVSqVTqeT
+Nu5G3ZUzSJI0GAw8z2NLKmVqZfmijUNBuB+j0ZixH+lO1Wp1IpEgSVKtVkuFxFMvhH9lWq3Wbrdr
+tVqWZfF6CDxLSG2MdRT3bDKZGIbByQgcx4ndu5dLOcf4CeCeZZ4wAPQEdOIqB1sopVKp1+tFUbzj
+Du+QIaeWLzcfO+Y+/4kFTTMqVWz48DqLxeNwOGw2Gw5fZ2lhJRkjSVKpVGJDL62Dy9gJvh2EEHa5
+SDuAYmuYcW25FIrAJhXbSqlQOUIIu8jw88E61K+FBbgZRVE4MmwwGARBkIyytFQQ/xawovR5p7gZ
+1hI8KjwfSh2V5FfEmUupW91lLFKCurdpknZYAo8TkCWgE1c/qVJBEMTIkcq8vM6dO/0bN+Z2dhrP
+tU+eJHmOU/G84osvRg0aFMLZOFnGrtPGhu0XQkgQBGz7JBvX25QCpWzu1l+klFypN7x5XEbbmv1d
+4Ics0wZb52x6kyZAWV4aIZRNYwA4N+C7dU2ArQl2lOPw5q23+keMaFyzRr9njycWU2XfFU3HESI4
+Ts3z2EtOnjxZEAodll7q+5VnKa3dw2WIsO3Gkwz8+nzO77y9yYzkkMHOGal2HkIIT03wHkEyc5qr
+CfG89yABrgUg3+laIfUtValUqtVqjUZVVpaorGw2GLwEwcTjdDKpQCiD1aCopNnc5fE08zwdjxsE
+Ia0CnbKjgx45MiTtjpC9VOAgsPmDD4b/+McDFiwoeO8928aNIUHw5eYSZ29Qmv2d9vS6pGVM8Txv
+WrFi6E9+UjtjBk9R+EKiKCYZZuh3v6v/9NOm8eNFUcxys6MrEclNlzp5uirvFLggwHziGiLVyYPV
+QqfTmc1mpzM4eXIgGj3T3s6fOaPy+ZTJJEJIREggScJojOXlBfR6RNP08eOh6uqRLJv+tWlqshw8
+2GkyBfvlesJ2KplM0k1NJMfFDAYqmTSfPl310kvrNJrgxIlEygbUWd4jlgE8M0DdkV5pPFICmGPl
+SiqRoD7+ODB+vMlkwp4uw/r1utOnOZ73er0mkwlPNa6+ZWipa+yxo0/KK7vK7hS4UIBOXFsQKWCp
+0Gq1BoMhHo8nEgmPJz5kCItzZrCdRUikKJ1CYcZLGfLy2CNHIrW15hdZlJMAACAASURBVLRuEwnV
+qlV5FRUtqZs8ZykVPM/TLS0IocXf/36zzTZl27Ybtm/P+fjjg0OH4kUAePPO1Fvo2Yn0b57n+Uik
+4oEHuoYOPfnII3jmJA0GX46sr7ccPowQ0n/2Wf3gwdIl8t95ByGka2/3+XwUReH8op6XSB1D9gPr
+2UDm095mQigTvXXb27lYJNS7dg144YWG737Xe8stUo2pjP0DAOjEtYjk0sGRAJwtyvN8MpnEm1Lg
+PCIp00Z632QYZu7cwLx52lAoPWDb0WFat67rjjuCeGfmLJ022HBrOjoQQj6DQSDJhuLiG7ZvJ2Ox
+eDwu7ZDRLVpf6Zx0eprzhOd5orFRf/Jke3Gx3+83Go0994lzrFmDG7uOHt0ZDOJlBJY9e0x1dQgh
+muOElpa4wYDFMnX5G0oxvlKHqR+lXqin40v6W+ZTlOIOStPajDF26VzcrdQs7Smhs6WCZVnD8eP6
+U6dCDBMKhQwGA/5lXa1+NuA8AZ24RiG692PAbiiFQiEFeNPy7lPNB8uygwYRI0dGtm2zpnXI8+Tu
+3c7rr6/rc9uJNERR1HR2sipVXKtViOLIzz9HCDUVFEhR5WQyKaUn4dFKWxJhu48HjAfJcZymsREh
+5NVqQ6EQzkHCd0cQBN63J3fzZlaliiuVnra2ZCAQM5tVKtWI995DCHXabA6fT9PayhYVYZXCZ0kP
+JHVChhCSklDxETw21B0STztL0k487DQ9wA0QQtLW5dJvJ9VNJP1ScD9Ed74vLl0uXVTyMUodSvld
+2NdHNjUhhFpVqlgwiJ8SZEwBvQHfjGua1LdR1Et4E6W8O+P1aD/8YeexY/H2dk1ab36/4f/+z/7Q
+Q/7U6kzyUiGKosCyWp+PVyjmLFqU09pqDoW+KC//bNQoW/fWqvpDhywff0x3dQUHDGiZMYM2GHBh
+IlEUVV984fjoI4XXG8rPPzN9uqjXG48ezVm1CiFkPXGifMmShjvvTOr1eFqA5yX63bu1nZ2fjxrF
+MsyYw4fddXVRt1v9+efOw4dPDR7cbDBM9vnMXV14ZziGYZRffGHdtYv2+cJ5eWemTHHv3q1vb6+/
+5x51NJq7cqW/tJSMREzHjnUNHeqbMEGp1eIUW/3+/ZY9e6hAIFRcfGby5AEbN1Is23znnfixGPbu
+tX72GRkKhYqKzkyZUrR6taDVtn7jGyRJ6k+dcm7frvB6g0VFLdOn0zqdQqEw796tP3TIW1pq37NH
+oKimyZNZq7Vo7Vo6mWyvqgpfd51CraYoStHaatuwQd3cHMnJOXPrrchup2nasWWLpqGhedIk97Zt
+IkE0T52acDrdW7faP/sMIVSwfXu0vt77ne/0d2khcE0BOgEgdLbrI6MfXHJraDQam80wbVr4vfdU
+HNdzvyDrsWMn9PpAamHw3i6KX3IVHR2EKNIsW378OD5eUld33aefNt56K8uyngULKt55B3UPqWDl
+yi3/8z9Kp1Oj0XiWLi3797/JbpdU4YoV1b/9be7Wrbl79iCESo8cKTp+/PDttxsYBi9HRwhxHJdb
+XY0Q+nzkSHVLy5jDhwvq6/eNGFG2bBlCaPukSebTpxFC1mCwnecTicTgxYvLFi9GoshqNMp4PH/F
+CkUiQbPs7hkzck+cKF64MGEwqMNhhFDxhx+evOGGA488otFohv3jHwXV1QghVqMpisdzPvzQ0toa
+sdkO3HyzRq0e9dJL+Vu2IIQEiiJ53rV2revkyZaKigNjx5Zt3z76jTdInucpqoDn81av3vrss5TV
+WrxmTd62bUUEQYgiQqho9WpWq9WEQgih4mXLdj70UNtNN3mOHx89b54iFhNomuS4AStXbvnNb5jC
+wuH/93/W48c9K1bgcZYtWvT+X/86YNkyc1MTQmjMzp11gwefmTULO9lgSgFkBL4WQDq9WXYipQbt
+N74Rr6mJ1dXp09rEYpqlS3MHDuzENeb6DGiLoqhqbUUIHRo+fP2YMSqWHdDWNnn37tmrVy8sLla3
+tla8807EbN51661tTuek9euLjh8vXrDg4A9/6PL5yv79b0an23Xrrc25ueM2biw7fLhi4cKtc+Yo
+GxoGHTr0vz/6Ee9227tLISGEBEEQAgH3rl1Bm625qEhvMKDq6sLGxiMNDUUHDzYWFTUXFCgSCYSQ
+LRBIJpOmTz4pe++9ttLSHd/8ZnteXt7x47PeeEPBsm0eT0dHh6exESGUUKlW/cd/IFH89rvvFuze
+vfU//iPn4MGC6urTw4fX3Habz+Eo/vzzGW+/TYiiz2j0er2Vn3ySv2XL6eHDd02f3mW1VuzaNXnl
+SoRQu1YbP3Zs5Pz5SZVqyQMPtFmtEz/6aOJHHxUsXnxgzhzFmTMIocMjR+4ZO3bi1q1lx47FFIr3
+586lKequ114rWbPmyODBt77wAh2Pr/zBD44NHFh+8OA33n9/yPz56x95BD/e/ZWVJ8rLx2/bVnb4
+sHvTpkVz5z4wb15Uo/nXvfcabDbnhfjaAFcxUAIM6AdE99Jug8Fw330RrTZDrfLWVtO2bYTf78c1
+6VJDHalIsVxlWxtCqMPjCefmhgcPPjp16seTJyOEij7/3FNTg0Txk0mT9g4f3pqbu+W22xBCrhMn
+AoGA7aOPSJ7fP2HCp6NGteXkbP7mNxFBuOvrAwyjDQZ5igq4XLTFolarcQEMHBKwbtpEM8zRMWMU
+SmUyLy9kseS1tEzatAmJ4vZJk2iaZjwehJAtGEwmk4XbtiGEPpoxo9njQRR1ZsiQ48OHI4R8RmMk
+EsH2t3rWrBMlJScHDWouKFAyTMTnG7B1q0gQ62+7rc1uJxSKutGjG0tKEEKden0oFCrcsUMkiHXf
+/GaL283rdAenTm0pKEAIdWq1nr17aY4LGAwDd+2auGYNHQohhDxffBEMBrVeb9BsXjp7dpPbXVta
+ihDaPGlSXV5eY2FhTK+n43HtoUMGrzei1zsOH5704Yf2hoaESpV/4kSos1MXDp8uLNwweXKzx7Nv
+3DiEEBUMRhhGG4sFTCbBaFSYTFJe2cX51gBXPDCfAPoBnlLgbNrhw3VDhsT27DGlteE4xbZtOVVV
+jak7HGScUnyZoNnRgRAKW616vR7nSmkpCiFEMIw+GEQI1btcCCGVSqXQ6RBCSZqOx+PatjaEUGNu
+LkEQarVaybIiQhxFJZNJUyAQNBo1Wq1er5fGgBDiOC5n/XpEEEcrK7F+tJaUDNqzZ9jRo005OXUD
+B5q1WtFkEgnC3NXFsqy5rY1VqZpycpQkqdFoSJIU1WqEUJfBwHGcvqsLIRSw23HJbjXHiQQRIghL
+e7vfavXq9TqK0mq1CCFBqcRnJZNJo8/ndbn8Op2WpnU6HUIoZjaj06c7jcaCtjaEkCAI9s5O/Lxq
+i4sTej2fSOiDwcbCQhLX+2NZhFDMbler1RqVShOLddrt2o4OhBBLEJb2doqiCISacnMRQsbWViSK
+PosFF080EARCKKHTGQMBhFDQasU1AbPfLAS4NgGdAPqHJBV6vf6BBzrq69Veb3rZD6/XuGyZ6Yc/
+9ONld7heSEYbJOlE0GwmCEJJkp6GhutqahBCp/Py8ERk8LFjO4uLaYRGf/QRQqi5qEgUxYDZjBAq
+PXy4qayMQmjU9u2EKDYVFNCiaAiHGwoLVSoV3hcPr/zgeZ5uaLAePdpSUhKy23UajVar9Q4ZMmjP
+HoTQ5vHjVSoVrqIatVgMfj/BskGj0dXSkn/8ePuIESRJqll20N69CKGAxUKSpMnvFwkiZrPh/C5t
+NBrT6wmSDBmNOa2tttZWprSUIAhDV1fRkSMIoYDZTJKk32bLbWoydXVxOh1JkppQqOjwYYSQ32TS
+MwxCqNNsfnPWLKVSObCjoysnR9Dr7aEQIYphi0WtVmu1WnMigRBKuFx6vd7EsiTPR41Gn8WCEOIo
+6tVvfpNWqXLDYUGjiVgsA+vrEUIhiwVX4TUxDEIortebAwGEUNhqxWVoswkmAdcyoBNAvyEIAle6
+9niMEydGPvxQIYpnOTBFkThwwN3QcFSv10sbFvU2pdC0tyOEvvHeewJN68NhVSKBEDpRXl47bFgg
+J2f83r3X79xZduqUJpEw+v1Rg2H3lCkqlerUpEljtm6t/OSTAfX1NM9bvN6ERrPjxhttsRghihG7
+HW8lLblTeJ53VVcjhI5WVeH5kE6nC44ahd56q8PlOj18uM1gwNtmRF0ufVeXLRQ6UFlZduzY7e+8
+c/LAAV6vL927V5lIIISCJhNFUcZAIGIwUBqNWq3WqlT6QKC1oEChUHxeVZWzcuV9r756YsQIlSAU
+79+Pg89Bi0WpVH5+4425b799zyuvHB89WiUIpXv2UDyPEAqYzWGX65adO4fX1j61YEFErx94+rTP
+bl/0i1844nGEUNhuV6vVarXa7PUKFJV0ODRqta2zEyEUdjjai4rO5OTktrY+89ZbrU7noLo6Rql8
+69FH7bEYQijqcOBzLcEgQijkcFjb2hBCUZsNPyWoHQvIA/EJoN+kTinuvFPMy4v3bJNIqF5+uczv
+90ejUZkoBUJI29mJELL4/bbOTiSKbR7PpttuW/X97xuNRnHw4DUPPhiyWFytrYZAoLGoaOFDD5FW
+q8lkIoqKNj76aMBud7S3m32+5oKCtx96iHc43N1uGY1Gk7rRkMjzOZs2cSpVY1WVRqPBu1CIxcUx
+i+Wz6dOtNpvZbMaqFnO7EULuWOzMqFEbb7+dUygGHzgwZOfOjpycY+XlCKGow6HVaIyBQKT7KuZQ
+iOT5iNut0+lOTp368axZlCgO2727bO/extLShqIihFDc5dLpdC2TJm373vdojhu9devQbdva3O6w
+wcDSdMJopByOFQ891Jqb6/L7BzY1dbpc6++6izYYrJEIQijhcuHpkcnrjZrNap1OrVZbu7oQQjG3
+W28yrf3Rj04OHmyIRAafOhU0mzd++9usx2OLRBBCrMeDq/kavV6EUDw31xaNSn1muVkIcC0D+9kB
+5wIOLTAMEwgENm3q+uc/7YlE+txUpUr+1399MWqUJycnR9rENLUHnucTiUQgEOjo6AgGg8lkEiGE
+q3xjHwvelCIajQptbTGC4NVq7D8xGo00TTMMEwqFuNbWBEGwSiV2NOFKG6Io4o2D8BQBIYR3iAsG
+g3izOaPRiDdswNvAkSSp0+lw3fVIJBIKhfCmSaIoJllW3dYWVSoTajWWOjwdwWv3aJrGzn2WZWOx
+GC6XJAgCE4spW1oiOh2jUOCzcCRAoVAkEolQKKRoaYkSBBkOP/rSSycKCxfff7/dbtfpdMlkkvf7
++WSS1Wo1Gg2Or+D1hvjdHz92fIMKhYJhmEQigS+RTCYTgQAZicT0ejyBkOqc44cjimIsFovFYrg9
+3sAK70aOF09cgm8OcCUCfifgXCBSdsqbMCG2fn388GFDyuciQSCWpY8eVQ0eHGNZVloknNYDtrMO
+h0Or1WKdwDMVbOZomuZ5XqfTxQ0GbTJJEAS20XjvT47jVCpVTKfDH2F1weYbW3AcwcbJTjRNq9Vq
+hBA2uFLnBEHgDVCxFRZFUa/X0zSdTCalhdOM2UzzvEEQiO79giSrirO/cM12vKcQXhfNsmzCbKa6
+d2PF4qdUKivmz3fu2HGisvKzkSPNgcCN1dUIoS+GDdPr9SaTyWg0EgSRMJs5jiO6K8DjUQmCgEud
+49XUqLvyOd4UDz9PjuMSRmMymTQhhO8X+9yI7j02RFHExR+xTuB9kKTF85fmmwNciYBOAOcOtulG
+o/FHP+r4+c91PC+9kBKiiChK0GiiPK9MLTiRihTnoChKr9fjIk5S9QtsBwVBwHMIbNOxmcbWH1t8
+XJlKOiv1pThtTbi0iht3TnSXrpJOx4qCL4FnBggXFuzelEKqvSEVDpFKcaQ51vCytbSzRFFsnzo1
+f82akdXVI6urccvDQ4bUTpxoMxoNBoO0Ayt+XD3vCHeSWu0j9cFiVcMXlYp5SCfic/FuepJOkN37
+CZ7nNwG4ugGdAM4RaUqhVquLigwjR0b279fy/FffKIMhPHBghKLsvcVIsXXGapFWFy+1hlLqp5Ld
+l+oa4ddt/BFKWVKe1gkeKu5KqqSEuu0pSileIpVUksYpLfVI7TD1LojuYlPSR9hBlGrQsZ8tXl6+
+5W9/M27f7jhyJKLR1JWW1o0YYdbrcXRESuFNq/sk3ZE0HpSyHFL6SJKB1NtJGyQ6e7299ChgPgHI
+APEJ4LzAJZgikUhbW8df/kIfP66NxVQUJRgM4VtuOTBqlLagoMDtdhsMhrT4hERv8e00s5jlRxmb
+9bxWWqQkrWXPbtNMc88L9baWEKVIF8/zDMPgMEk0GmVZliAInI+bGiS4SCZbGkbG4wAgA+gEcF5g
+88eybCgU8nq9x44FPv+cUKvDRUVhi0XvcrmcTqfZbMa+cjBJAHAlAn4n4Lwguit54GQhlUpVXBxm
+WYqibFqt1mQy4YwjSM8HgCsXmE8AAAAAckCeAwAAACAH6AQAAAAgB+gEAAAAIAfoBAAAACAH6AQA
+AAAgB+gEAAAAIAfoBAAAACAH6AQAAAAgB+gEAAAAIAfoBAAAACAH6AQAAAAgB+gEAAAAIAfoBAAA
+ACAH6AQAAAAgB+gEAAAAIAfoBAAAACAH6AQAAAAgB+gEAAAAIAfoBAAAACAH6AQAAAAgB+gEAAAA
+IAfoBAAAACAH6AQAAAAgB+gEAAAAIAfoBAAAACAH6AQAAAAgB+gEAAAAIAfoBAAAACAH6AQAAAAg
+B+gEAAAAIAfoBAAAACAH6AQAAAAgB+gEAAAAIAfoBAAAACAH6AQAAAAgB+gEAAAAIAfoBAAAACAH
+6AQAAAAgB+gEAAAAIAfoBAAAACAH6AQAAAAgB+gEAAAAIAfoBAAAACAH6AQAAAAgB+gEAAAAIAfo
+BAAAACAH6AQAAAAgB+gEAAAAIAfoBAAAACAH6AQAAAAgB+gEAAAAIAfoBAAAACAH6AQAAAAgB+gE
+AAAAIAfoBAAAACAH6AQAAAAgB+gEAAAAIAfoBAAAACAH6AQAAAAgB+gEAAAAIAfoBAAAACAH6AQA
+AAAgB+gEAAAAIAfoBAAAACAH6ARwxTNv3rxx48YxDIN/fPnll8eMGfP0009f3lEBwFUD6ARwZSOK
+4q5duxKJxP79+/GR//qv/xo1atSF6r+mpmbEiBHhcPhCdQgAVxygE8CVTUNDg9Pp9Hg8O3fuvNxj
+AYCrE9AJ4MqmpqZm/Pjx48aNq6mpSfto165dd91118033/zBBx/gI8lk8uWXX549e/a0adP+8z//
+8/Tp0wih119/vaqq6sknn8Rtbr755hEjRrS0tJw4caKqquqnP/0pQuimm26qqqqaOHHiJbwzAPi6
+ADoBXNns3LlzwoQJ48ePr6+vb2lpkY6fPHly8eLFP/vZz771rW8999xzp06dQgi98MILGzZsmD9/
+fnV1dWlp6f333x+LxR544IGxY8dKJz7//PP4H2VlZZ9++unf//53hNCWLVs+/fTTnlIEANcCoBPA
+FUw8Hq+rqxs8eHBVVRVBEKl2PJFI4Pj2Qw89ZDQaN23aFI/HlyxZcvfddzscDoqiHnzwwVAotGbN
+mss4fgC4IgCdAK5gPv3001GjRpEkaTKZysvLU3Vi6NChOp0OIURRlNvtbm9vb2pq4jiusLAQN9Bq
+tS6Xq66u7rKMHACuIOjLPQAAOHdqamp27do1Y8YMhFAoFKqvr2dZVqlUpjVjGMZkMp3PhURRPJ/T
+AeCKBuYTwJVKe3v7J598smrVqurq6urq6tdeey0ej0vZsRLhcLi1tbW0tDQvL4+m6cbGRnw8Go22
+t7cXFRUhhFQqVSgUwscPHjyYejpBEAihYDB40e8HAL6ugE4AVyqxWCwnJ8doNOIfy8vLnU6n5HoK
+BoMtLS1NTU3/8z//Y7fbb7nlFq1We8cddyxatMjr9QqC8OqrrxoMhlmzZiGEioqKjhw5EgqFdu7c
+uXz58tSr2O12hNCuXbtaW1vff//9eDx+ae8SAC4/oBPAlcpvf/vbgwcPvv766/jHxx9/3O/3L168
+GP+4ffv2mTNn3nXXXZFIZP78+QqFAiH02GOPTZky5d57750+fXptbe2bb76JYxh33XVXcXHx7Nmz
+165dixNkv/e97+F+SktLZ8+e/de//vWee+45fPgwRVGX4VYB4LJCHDhw4HKPAQAAAPj6AvMJAAAA
+QA7QCQAAAEAO0AkAAABADtAJAAAAQA7QCQAAAEAO0AkAAABADtAJAAAAQA7QCQAAAEAO0AkAAABA
+DtAJAAAAQA7QCQAAAEAO0AkAAABADtAJAAAAQA7QCQAAAEAO0AkAAABADtAJAAAAQA7QCQAAAEAO
+0AkAAABADtAJAAAAQA7QCQAAAEAO0AkAAABADtAJAAAAQA7QCQAAAEAO0AkAAABADvpyD+BrxLvv
+vjt//nyfz+d0OimKQggFAoE33niD47gnn3zS5/NRFGU2mxFCgiDk5eW98cYb3/ve9/x+fzgcjsVi
+LpcLIfTMM8+MHTu2z2t973vfa2lpCQQCq1atys/Pz9hm7ty5+/btczqdb7zxRn5+fktLy7333hsO
+h3fv3n1B7xstW7bsd7/73dq1az0ez4XtGSG0YsWKRYsWRSKR0aNH/+pXv9JqtfLtvV7vRx99tHXr
+1qeeeir1yfS3n/62BwCgNy7ifEIQiGSSZFmSZUmOIwSBuHjXuiDcfffdf/nLXxBCb731VnV1dXV1
+9c0334wQGj58eHV19ciRI6dPn46PL1myBJ+yaNGi6urq++67z+Vy4Y+yEQl84t///nf5Ns888wxC
+6He/+x02lx6P55e//OWcOXPO4xYzY7Vahw0bplQqL3jP1dXVzz///Lx585YvXx6NRh999FFRFHtr
+3NTUdO+99959992bN2+uqanhOO7c+jmH9gAAyHDh5xMdHeqWFo3XqwoGFdEoxXEkQkipFLRa3mxm
+HQ7G44nZbOwFv+7FICcnR6VS9TxO03RFRcXFvnp+fn5+fv7OnTvHjRuHj9TU1MyYMeOCX2jKlClT
+pky54N2Kojh//vw5c+aUlJQghB577LHZs2cfOXJkyJAhGdsbjcZnn322sLDwxIkTu3btOud++tse
+AAB5LphOCIK4b59t9267369kWZLnM88eaFpUKASHIzFhgnf48MCFunq/eOWVV1555RWE0Le//e3J
+kye/+OKL8Xj8wQcf/M53vpPW8uGHH87Yg16v//nPf95b/y+++OKbb7558803f+tb33rxxRe9Xu8v
+f/lLbN8FQZg/f/6qVava2toMBkOfQ500aVJNTc0TTzyBEBJFcf/+/b/+9a/xv9esWfPuu+/6fD6D
+wfDII49MmTJF5r68Xu8f/vCH/fv3i6Ko1+uvv/76p556CiE0ffp0QRASiUQoFNq3bx/2tiGEksnk
+v//97/Xr1zMMU1pa+uSTTxYUFMjcV0ZaWlpqa2sfe+wx/GN+fr7L5dq6dWtv9tpkMplMpvPvp7/t
+AQCQ5wL4nRiG2L/f/Kc/DV2+PL+lRROPU72JBEKI44h4nDp9Wrd48YC//nXwsWNGjrvU/qhvfOMb
+r7/+enl5+eHDh99+++25c+cOGzbs1KlTac3+9Kc/ZTx9//79GzZskOl/7ty548ePP3Xq1OLFi59+
++ulx48b98Y9/FAQBIfTaa68tWrToqaeeWr169c9+9rM+hzpx4sT6+vqWlhaEUG1tbWFhIZ7fLFu2
+7J///Ofzzz+/YcOGRx555IknnmhtbZW5rxdffDGZTK5evXrr1q1/+tOfqqurcf/r1q3bsGHD008/
+nXbdF154YcOGDfPnz6+uri4tLb3//vtjsZjMfWWkra0NIeRwOKQjdru9vb29z7s+z34u1HUBAMCc
+73yirk67ebOnvl4n34wgEEEghJAoIslR7POpFiwoGjQoNG1aa05O4jxHkj0ej8fj8RiNxoaGhldf
+fdVsNhsMhmPHjkkNfvCDH1AUFQqFnnzyydQT161b98knn8Tj8TvvvFOmf71er1KpwuHwc889Zzab
+A4FAdXW11+u1WCwLFix48MEHx48fjxAaMGBAn0OtrKxUKpU1NTVz5sypqamZNGkSQkgUxX/9618/
+/OEP8/LyEEJTpkzR6/U7duy44447eruvjo6OZDJJEARJkkOHDr3nnntkLhqPx5csWfKLX/wCm9oH
+H3zw3XffXbNmzZw5czLel9PpzNhPIBBACKUGkHU6nd/v7/OuMVJEob/9nOd1AQBI47x0YutW59at
+7mwmBFptkygeFARBqRwUjZbx/FcfHT9ubGjQ33Zb8+jRl/p/8oQJE3D+0uTJkydPniwdf+uttzwe
+z7e+9a209tOnT//tb3+7bt26hoaGPjsfMWIE7txutyOEGIZpbW2NRqPl5eXZj1CtVldWVko68eyz
+zyKE/H6/1+t97bXXFi5ciJsJgtDV1SVzX/fff/9///d/T5s27YYbbrjlllvmzp0rc9GmpiaO4woL
+C/GPWq3W5XLV1dX1dl+99YObRaNR6Ug0GsVZYf2iv/1cqOsCAIA5R51gWWHzZveOHTl9tiRJlJf3
+kVa7kqIUPM/HYmsRuiUS+XZq+hPDkEuXFiQS1PjxXvJrs6JjxYoVGY9Pnz793DrE77n9TSuaOHHi
+yy+/HAwGg8Fgbm4uQoimaYTQI4880jOg0hvjxo1bs2bNunXrtm7d+stf/jI/P/+1117Dhv7i4Xa7
+EUKdnZ1lZWX4iNfrxXOpbJDmE/3t5zyvCwBAGudolTdtcm/f3odI4P/mAwpqS0r2jR49ZuLEiRMn
+ThwxYkRh4R67fQXRYxKydq1n166La7n6y6FDh95///0L1Rt+pa2vr8c/njx5MpuzJk6cGI/HX3nl
+laqqKnzEaDTm5eXt3Lkz+0vPmzdPEIRvfvObL7zwwvLlyxsbG3fs2NFb47y8PJqmGxsb8Y/RaLS9
+vb2oqCj7y2E8Hk9ZWdmnn36Kf2xubm5vb7/xxhulBm1tbU1Nh612GAAAIABJREFUTTIzknPrp8/2
+AAD0i3PRiQ0bnHgmgYMNvf3BlA06UFFRUVJSkpeXN2DAgPLy8vLycovlCEJCWntBIFavzv3sM8sF
+vL3zxO/3Z+NiyhKXyzV8+PAdO3YIgrB3797ly5dnc9aAAQNyc3OXLFmCgxOYRx99dMuWLf/617+a
+m5ubmpqWLVu2f/9+mU727dv34Ycftre3i6IYiUQQQjhnNCNarfaOO+5YtGiR1+sVBOHVV181GAyz
+Zs3K+ka/hCCI+++//4MPPqitrU0kEn/729+qqqpS84l/+tOfzp49+/jx4xe2nz7bAwDQL4gDBw5k
+31oQhGPH1O+9NzjLJCWCQPfcs6OkRC05W7Anfc+eUzU1D/B8BpVSqfgf//jkRQ1rL1y4cOHChX6/
+nyRJnIj55ptv5ubmvvbaa//+9785jlMoFARBIIR4nr/zzjtvvfXWJ554Qmo/d+7c7373u7ir7373
+u36/PxqNxuNx7Mb5/e9/v3nz5hUrVhAE8eSTT37nO9+58847jx07ZrPZNm/e3NTU9Ktf/crr9V5/
+/fXTp0+fO3euw+HYuHGj/IDnzZu3cuXK7du3py7mqKmpefXVV0+ePEnT9PDhwx9//PGdO3dmvC+E
+0KJFi9asWXP69GmKoux2+3333Td79mx0dl6sw+EgCOL2229/8MEHk8nkP/7xjw0bNnAcV1JS8uST
+Tw4YMGDevHm93ZfM4JcuXfruu+/GYrExY8akrYu+4447Tpw4sWDBguHDhyOEvvjii8cffxwhlEwm
+/X6/1WrFHjacXZZ9P31eFwCAftEPnRBFMRTi3nlncHOzPvsL3Hhj87RpvpROUCIR37GD27p1Um+n
+VFQE77qrgYaSIgAAAF8D+uF3EkVx/35bv0QCIbRzh6e29qusWYJALS36jz8eJ3PKkSOmuro+Em0B
+AACAS0O2L+2iKAYC8Y8+Gt7fMjlskpw/v2TSpM6KiiBJiidP6rdvdzFMH/q0Zk1eWVkfbmsAAADg
+EtAPndi715NIUOdwDVFEO3Y4duxw9N20m/Z29aFDhmHDwudwOQAAAOACkpXfCU8mDhy4pCuVPv44
+8ypfAAAA4FKSlU7wPH/mjDIcVn6Zw4qQiJdH4D+9QBAiTSdJMk7TyZ6rJfqkvV3t9Z7L9AUAAAC4
+gGTld2JZtrnZiCuEI/SVNohn/4ghCKSgwzr9cVE8aTJ1xGJ+tdoUDueHwxMEISf78AbDUM3NGrs9
+ku0JAAAAwEWgb50QRTGRSLa3G7PZaEivb9dp31ep6ywWjU6nUqvVBKFNJMLB4Mft7dUs+2wolJul
+VPA80dGhEYQQ+fUp5QEAAHDtkZVOxGJMMNi3sSYIpFYfG1AYtdtHWa0mh0OlVCoQQslkMhAINDQ0
+nDz5l2TyL7FYVt4kUUSBAM3zCGQCAADgMtK3TgiCkEiwgqDocx4giigYvP7IkQk8TyoUwk03tY8f
+7xNFURRFs9ms1WqTSaqr65QolmU5uGiU4jhBoQChAAAAuGz0bYIFQWDZJEFmNQlgWTIcVsRiVDCo
+wEX98J4HSqXSbrd7PB6Foh/LrJNJxPOwrTEAAMDlJCu/E8dxAi/0d4Udz4scx+ESPQRB0DSt1WoU
+in6kMImiKLNdGgAAAHAJyOrtXhB4juP627XFkhDP1hZRpDnO0h+9kU28BQAAAC4+WemEKCKeZ/s7
+nxgwoD71R0EQkkkxENAjEaHsllMoFTwEsQEAAC4v2WQxESoVpdWy/e06Pz9CpKyvEwShra2Q40ix
+r40rpD8mcwKqxgIAAFxe+tYJkiRVKlKtbulXv3Y7Y7Uy0tIHURRZlm1ocGU/KaEo0WiMwuIJAACA
+y0tWOqFWq222dopKZjkPQAgVFNSq1WppPiGKYiIRaWiwZdmDKCKS5JxOP+gEAADA5SUrv5NarbbZ
+fBTFZBlUFgQ0cKBP2hUOIcTz/KlTdobpR7KTwcC4XDHQCQAAgMtLtjphNKosllOIyC6uYGLN5phC
+ocA94MzaU6dys59MIIRKS5t0Oh1xDhUEAQAAgAtHVm/rCoXCZDINHrwimRSzsfIOh9dsVqcGJ+Lx
+6OnTluxFgiT5oUM/S52RAAAAAJeFrHSCpmmLxaLR6EtKPuqzMUEgtzuk031l4gVBaGmhI5F+pC6N
+HPmpxWKXZiQAAADA5SIrnSBJUq/Xu91uu32bWh3uYzZAiHp9UqFQpgYn4nFCFDPNDESERJSaKYsQ
+sli6Bg2qMxiMEJwAAAC47GRriBUKhdvtdjj0VusaUZTzPhFI1OspOmXhA8dxDJPkeUIQ0Fd/RCR0
+b3mEUmpziEgoK9vr8dg0GvUFvVMAAADgXMhWJ0iSNBgMAwYMKCs75HSekl0GQSBEpa2wo8hmtdpL
+kgmSTBBElCC6ZxLSBnkiEkUkCGj4sEPDhvnMZjNMJgAAAL4O9CNmoFQq3W53KFTc2fmPaHRuJDI0
+Y7NkkmhqMo8dG5WOUBSl0aJBg/7Z2akTRT4ebxOEP3R2Gnqe63R+MXjwLrd7kEql6u+dAAAAABeD
+fryzEwSh1+sLCwtLS4vy8+fr9V/05nr69FNHXZ1ROlGlUnk8niFDiseM0Q8dajab7/b5dD3PstoO
+VVZuKSoqNBovRWTi9OnTjz766PTp02fOnPnjH/94w4YNF/uKEsuWLRsxYkRLSx9L3F9//fWqqqon
+nnjiAl56375906ZN++c//ynf7Pjx4zNnzvzzn/+cZb3eZcuWzZ07d+bMmTfeeOOPfvSj48ePSx+t
+WLHijjvumDlz5tNPPx2Lxfo87vP5fv3rX8+ePXvWrFm/+MUvGhsbL+x1vV7vBx988J//+Z9NTU2p
+XfXWvjd6fn/O+feV5ffhQtHfca5du3b69OkjRoy48cYbp02bdsMNN/z6179OJBJSg1WrVs2cOXPS
+pEkzZsz44x//KB2/xPcFXDz6Z45JkjSbzWVlZWVleXl5r9jtJzPWc2VZ8sUXS5Yu9bS0qAMBKhxW
+UpRLFKuOHbt7zZqHjh0by/Np1xVKSr4YP666oqLIarXSF7+oU1NT09133+10OpctW7Z8+fLy8vLP
+P//8Yl9Uwmq1Dhs2TKlUyjd74IEHJkyY0NunNTU1I0aMCIfD2V93//79jzzyyO9///uHH35YvuWg
+QYOWLl165MiR5557LpueFyxYMHPmzNWrV69bt85gMPz0pz9lGAYhVF1d/fzzz8+bN2/58uXRaPTR
+Rx/FJYR7O97V1XX33Xfr9folS5YsXry4vb29ubn5Ql23qanp3nvvvfvuuzdv3lxTU5NaArm38fRG
+xu+P/O9Lhiy/D5hz+L2n0d9xzpw58/3330cIPfvssxs2bHjllVeqq6s/+OAD/CnDML/73e9mzpy5
+bdu2xYsXb9++XTrxEt8XcPHot0Wmadput1dUVNA03dT0IkFUhUL/EY9rCQKl/c/assWxZYtDpRIQ
+QoKAkhyJQxZSMxzC0Ou73O6Nw4Y1DRw42OVyXRqP05tvvmkymZ566ik8cRk9evSRI0cuwXUxU6ZM
+mTJlyiW7HIbn+f/3//7fXXfdNXbs2GzaazSaP/zhD7Nnz54zZ055eXmf7adOnUqSpEqluu++++67
+777a2tohQ4bMnz9/zpw5JSUlCKHHHnts9uzZR44cqaioyHh8yJAh7733HkVR0u+lsrJSo9FcqOvm
+5eU9++yzhYWFJ06c2LVrl9SDKIq9jae3i17Y789l+T6cMxUVFaWlpdL9dnZ2JpPJiRMnUhRlMpnW
+rl0rtbyy7guQ4Vze3BUKhd1upyhKrVYTxCG/f08k8t36+okKRbpUIIQY5qupQ+qHBIFYViwt3Zyb
+uz0/3zlw4BCbzZblq8f5s3Hjxjn/n73zj4cq+x//GUNTfld+RFT0u7WaVGIRNjshVJR+KUmyW6lI
+qC299dva3ajelCzJm83uVsqPkQoVH1Gy227aJSn64ccwqDE0NfP943zf8541c4+5Y6TNef7RI2fO
+vO6555w7595z7z3PpUuFs1s2NjY2NjYAAB6Pd+rUqStXrnR3d0+cODE0NHTMmDGHDx9OT093dXV1
+dnY+duxYc3Pzl19+uWTJkj179mRmZqqpqQUGBrq7u6empsbFxQkEgtWrV588eRIAsHjxYltb25iY
+GC6Xu2HDBnd3d0dHRz6f39XV1dHRUV5eTqX+/4VMGhsbIyMj79+/T6PR1NXV2Wz2mDFj4uPj4adF
+RUUxMTEsFiskJMTJyamqqsrLy+vdu3cAgM8//5xCoSgpKRUXF6N3+datW8+ePVuyZEmP9MLCwoSE
+hIaGhmHDhpmYmBw+fFj40ejRo21sbOLi4o4dO4YO/u2336qr//+ZxubmZgCAhobGixcvqqurAwMD
+YbqhoaGurm5BQYGmpqbE9E8++eTy5csLFiwQtsuWLVvkuN3NmzdraGiIByHKjxgniPoPpEd7nTx5
+kmx/YLFYBw8erKioEAgEqqqqNjY2YWFhiHYn1W+JyomualGoVKqKigoAwMLCAl6W+fn5wdqIi4ub
+OXOmvPZLIBBkZ2enpqa2tLSoqakFBATY2dkh6pNsful3eZAj4wyPkpLSyJEj4Y9abW3t8+c/jhhx
+vr5+VVvbJAplKI+nhHiNWlHxjYJCl6Zm1cSJ6erqGmPHTjQwMFBXV38P000QDofz6tUrAwMD8Y+i
+o6Nv3bqVmJg4YsSI48eP+/j4ZGZmbt26tbq6+tGjR5cuXQoPD79z586BAwdmzJgRERFx+/btL774
+Ana4VatWVVVVOTg4jB8/ftasWd99992DBw+ePHni6+t748aNmpoaAEBubi4A4OrVqzt27BDd7o4d
+O1RVVbOzs9vb29esWePh4eHg4AA/qqmpOXfu3J49e3788ccjR47Mnz9/0qRJZWVlxcXFmzZtys/P
+V1OT8ESAOA8ePBg3bpyenp5oYlFR0bZt2yIjIxkMxtOnT1esWNHjW+bm5rGxsQKBAP1iPDwTBwAI
+BIKsrKyxY8caGBjcu3cPAKCtrS3MpqWl1djY2NDQIDH9zZs3jY2NOjo6Bw8eLCkpUVZW9vb2XrBg
+gby2SxSEqDxE+RH9B0hqLzc3N7L9ISYmhsfjZWVlKSsrV1ZWbtq0KSwsDNHupPrt+PHjJZZTypuC
+3d3ddXV1sM/fvn27vr7e1dU1MTHR1NRUmEde+3XhwoUffvghPj7ewMCgsLAwODg4MzMTUZ9k82Ok
+RPafZiqVqq6uTqPRhg8frqen9/z58yFD/vP6tVJXl15Hh9Hbt+M4HBVVVWVFxSEAAB6v+/XrTg2N
+14qKzzQ0no4c2aCpOWzUqMl6enojRowYOnTo+3wKtq2tDQAgfmrJ5XLT09N37NgBfzI2bNiQmpqa
+nZ29dOlSJSUlNpu9d+/eYcOGTZ48OTEx8dq1a/7+/i4uLhcvXgwMDFRSUuJyuffu3duzZ4+ioqK+
+vr66uvqTJ0/i4+M1NTXV1NT+/PNPovK0trbev3//1KlTNBpNR0fHzc3tzp07fn5+8NNXr14dOHBA
+U1Ozra2NyWSyWCwdHR0Z9vrJkyfiX0xMTLSyspo/fz4AYOzYsaKHOkRXV5fD4bS2to4cOVKaraSl
+pd29ezclJYVCocB6VlZWFn6qoqLCZrOJ0lksFixSaGhoaGhoSUnJli1b9PT0zMzM5LLdHl8R3oGQ
+Mr8Qov4DEW8vfX19Uv0BANDU1MTj8aBb3sTExMvLC5GZbL+F44Rs/YrL5cbExKirq7u5ufWauY/7
+JRAI4uLi1q1bB4dkOzs7VVXVW7dueXp6SqxPsvllKP+gpU+n8HCJQB0dHXV1dT09vdbW1ubm5tbW
+1tevb3ZyC7u47/h8PoUCKBQKhaKgqEhVURmipkYbPnzEyJFTtLS0NDQ0aDQalUp9z4s4aWlpAQDa
+29t7pNfX1799+3bcuHHwT2VlZV1d3cePH8M/TUxM4Fy5goKCrq4uPN90c3NLSkoqLi62s7PLz8+f
+O3eu6FXRZ599pqmpCQCwtbW1tbUlKg/8ivCLPWqDTqfDILDY8D6tDLBYLPHf+pqaGuFEBIVCOXXq
+VI8McNMtLS3SjBOXLl1KSEiIjY01MjISfpfD+d8T0hwOR1dXlygdTmXY2dnNmzcPAGBjY0On07Oy
+sszMzGxtbeG8hJDQ0FBXV1dS2yUqNtn8RP0HgmgvKfsDAMDHx2f37t3w4aIvvvjC19cXkVmGfosu
+JxF79+5VVVU1NTVNSUmR7T4iqf2Cpw6nT59OSUmBKXw+v7W1VZihR322traSyi9D+QctcpjqUVBQ
+UFZWHjp06PDhw0ePHs3lcl+/ft3Z2dnV1fXmzRs+n6+goKCkpESj0ZSVlVVUVFRUVIYNGwbX+BuQ
+Zf5oNNrIkSNra2t7z0oAl8uFp5NGRkaffPJJZmamnZ0dvNKXIZq6urq1tfXZs2enTZvGYrEuXbrk
+7+8v5XfRj+WIoq+v//z58x6JSkpKaPN5S0sLAGD06NG9xs/Ozo6Ojj516tSkSZNgyqhRowAAzc3N
+whQWi2VpaUmUDi9Px44dK4ypo6MDj/Mff/yxx+aEp/PSb7dHBGHVSZlfSN/7T69YWFhkZ2fn5uYW
+FBSEhIQYGhqePn0a/qD3KDwphP1WNiIiIubOnSvz1wHJ/YJnTgEBAVLeSCCbHyM9cpvtgc+cqKur
+6+jojBs3bvLkySYmJjP+i4mJydSpU42MjPT09OBlhIKCwgCuBevi4pKdnd3jHMrAwEBRUVH4wD6H
+w2lsbISnqKJ0dHS8fPly4sSJ8E83N7cbN25UVVW1tLRMmTJFtvLs27fv7t27ixcvDgoKWrt27aJF
+i3r9Cqw9orNaccaMGSP+JPukSZPu3LmD+NF5+fKljo4OPNNHUF1dfejQoZMnTwp/agEA+vr6cOoZ
+/vns2bPGxkZ7e3uidAqF8tlnn4m+A9HU1ASHDX0xYJFIbZeo8GTzA4L+I0cOHTrE5/MXLlwYHR19
+8eLFp0+f3rp1C34k3u6y9dsBgdR+qaurGxgYFBUVSRmcbH6M9Mj5rgCceVRUVBRePaipqcFrCBqN
+pqSkNLDDg5DVq1dTqdSgoKC6urru7u7S0tLY2FhlZWVPT8+0tDQWi8Xn8+Pj49XU1IT3Udvb21+8
+eFFfX3/48GFtbe0vvvgCpjs6OgIAQkNDnZ2dZd61o0ePOjs7p6enJyYmurm5SRMHnoWVlJS8fPny
+559/5nK56Pz29vZNTU1//PGHaKK/v//Dhw8PHz5cW1v7/Pnz8+fP9/jtu3r1qrm5OTpyd3d3cHDw
+p59+2tnZWfFf6uvrKRSKj4/PL7/8Ul1d3dXVdfToUXNz82nTphGlAwC8vb2vXLlSWFgoEAhKS0sr
+KyvFH9CSebtEccjmBwT9B11LpCgvL798+XJjY6NAIHj9+jUQuWMv3u6y9dsBgdR+AQC2bduWn58f
+Fxf37Nmz+vr6CxcuVFRUIOKTzY+REsqvv/460GUYGJqbm7/99ttff/21s7PTxMRk3bp1s2fP5vF4
+//73v/Py8t6+fTthwoTQ0FB4Puvv7//HH38oKiq+e/fOzMxs165do0aNev78OZyQCQ4Ovn79em5u
+LpzUTklJSUlJYbPZCgoK8DI/KSkJ5hR9XlBbW5tCoSxZsmTDhg2RkZGiUysGBgbHjx+/fv16fHw8
+hUIJDQ11d3dfvnz5n3/+OXLkyOvXrwMABAJBeHh4Xl4efL5w165dvT5VHBYWBgAQfWMWAHDnzp0T
+J05UV1crKSnR6fSoqChhnF9//XX9+vXp6enwzicR5eXl4hPNy5Yt27lzJwDg/PnzqampnZ2ds2fP
+3rlzp/B2MVH6rVu34uLimpqa9PX1t2/fPn36dHlt948//ggKCgIA8Hg8NpstfKMTvopPVB4ixPvP
+b7/9JrG91q5dS7Y/pKWlZWdn19XVUalULS0tb29v4c0Yie1Oqt8mJCQg+pU4WVlZ0dHRLBYLzgR8
+//33Jib/f80eR0dHHo/X0tKiqak5ZMiQ6dOnR0VFyXG/AADFxcXx8fGPHj1SVFQ0NTUNCgoqKioi
+qk8Z8mOkYfCOE6Tw9/fX0dHZv3+/xE8fPHhw7Ngx8ZvAUtLe3u7n5xcYGGhpaSkQCJ49e7Z8+fLV
+q1d/+eWXfSiyBBoaGtatW+fu7u7j4yN8pJ2Ihw8fbtmyxc/Pz9PTU77FwLw30P0Wg5ESvCarHMjJ
+yRGeFslAWVnZo0ePhg8fzufzOzs7a2pq3rx5g3jJS2ZGjRp15syZv/76a8+ePeicpaWlX3/9dUhI
+CB4kMBgMvp7ondjY2DNnzlCpVE1NzfDwcNEnYRoaGtasWcNms9XU1JKTkw0NDWWI39nZ+c033xQV
+FXG5XEVFRUNDw2XLlvVl4OmVN2/eoCep3rx5g6Wz/3QQ/RaDIQUeJzAYDAaDAs87YTAYDAYFHicw
+GAwGgwKPExgMBoNBMXjHCeyzQ/AefHYSvXKIOP263ba2NvrfQSzLkZOTY2VlNWvWLCcnJxsbGw8P
+j9LSUmlqCQCwcuVKOzs7Op3ew6ZHCin7T0pKypw5cwICAqQMu2jRIktLS9EX06Kjo2fOnClDCXk8
+XlRU1IIFCxwcHFxcXGJiYqT51gAeFxg0g3ScwD47dM5+9dkhvHJEcfp7uwAAdXX1JBF6LMAuirOz
+s6enp7GxMZPJLCwsnDRpUkhICI/Hk6ai0tLSepV59IqU/Wf16tWkNEEeHh7W1tYzZsxoaWmBp02b
+Nm0SLi9IirS0tMLCwtTU1GvXroWFhcFlxntF4n6J93OZvYEYmRmk44TQR6asrEyj0WbOnCnU3bwH
+7OzsUlJSRJc/ew/I5rPLyMh4+PChNPlFvXKNjY3V1dWinjgajRYYGFhWVlZZWamurh4REZGbm7tt
+2zZp4ryf7SopKc0QYejQodLsNZVKnT9/fnt7O5RYvB/6qf+MGjUKriZ7+/btsLCwN2/eNDU1IdbN
+RVBRUWFmZgYXZ509e7aU3xqQ4wIjDYN0nLh69SqDwRD1kcElWnk83okTJ1xdXRkMxqZNm+rq6gAA
+hw8fptPpe/bsKSkpWbFihYODA5QD79mzh06n29jYXLhwAQCQmppqbW1tZWV18uRJOHcRERFRWFi4
+ePFiR0dHmMfR0REuqkyn00UXym5sbAwKCnJwcFiwYMGKFSscHR03bNgg/LSoqGjp0qX29vZMJhMA
+UFVVZW5uDl1vn3/+ubm5uZWVVa+7jPDZeXl5OTg4uLq6whUvhAh9dr0GR3jlhMtDCT1xGhoaRkZG
+El/OkBjnPWy3L7DZbBUVFX19fUDQfwAAfD4/ISFh4cKFc+bMgWuHQKBeacWKFQwGw8PDo7CwEAAg
+Q/8ByHYEAKSmps6ePdvKyio9PZ1oR0aNGgVHu6qqKgBAbW1tQ0MDXEyXLGpqavfu3YMODxqNBgvv
+6ek5b968K1euMBiM/Pz85ORkW1tbuMsS96vXft7juMD0H4NxnED77PLy8hITE5lM5sSJE318fDo7
+O7du3WpmZib0gq1Zs+bAgQM1NTURERHa2tqurq5Cn928efOOHDni5uaWkJAwderUBw8eJCcn+/r6
+fvrpp0J/WV5envjr0Dt27Ojq6srOzk5KSmKz2R4eHsJDXegds7CwOHLkCJ/Ph4ubwumL/Px86ALr
+da8RPrvVq1dfvXr1+PHj8KAVxdzcvLy8vNdVrCdMmAAHXVGvHFlPHFGc97BdAEBHR8e8efO8vb1T
+U1PRa60LEQgEtbW1ycnJGzZsgOugSOw/AIDTp0+npaWFhYVlZWWJLj5/4cKF2NjYqKiovLy8gICA
+4ODgly9fytB/em1H6LTPyclZtmwZ0e7o6emxWKx37949evRo9uzZjx49amhokO16Yv369VQq1cPD
+g8lk8vl8KMBYvXp1V1dXaWmplZVVbGzs8+fPp0+fDheVkrhf6H4uflzIUE6MlAzGcQLts1u1apW2
+tjaVSt2wYUNHR0d2draysrKSklJXV9fevXunTp3q5eWlqal57do1BQUFFxeXnJwcODcNfXaWlpb6
++vqzZs1SV1dvb28/evSoi4uLi4sLYl4L+uy8vb1FfXbCdaGhd8zU1NTJyam9vR1K32QA7bOjUCho
+n52UW4FeuejoaBm8ckRx3sN2NTQ0ysrKcnJy1qxZc/r06fDw8F63+PjxYwaD4e7uPmXKFG9vb0Dc
+f3g83tmzZ729vS0tLbW1tYWCDehf8/Ly6uFfI9t/QG/tmJmZefHixdjYWPTF2YgRIxQUFJqbm9vb
+22fNmlVdXS3z9cTYsWPPnTtnZ2e3a9cuPz8/OEirqqpyOJy1a9dOnTq1vr5+y5YtU6ZMaWpqkiE+
+kN9xgZGGwThOyNdn19bWBk9z0D47hHrovfnsxE3aNTU1QmcG2mcnzSak8coNHz6cbBwAgK2trfXf
+yczMlON2oTKLRqPNmzcvJCQkJyfnyZMn6EIaGxtfvXp1+fLld+7cgY1C1H9evnzJ4XCmTp3aI4LQ
+1+b0XxD+NbS6CtGONTU1e/fuXbJkSa8SEdixq6qq1NTUxo8fD68nZBsnAADKysrh4eHp6ektLS2e
+np7Pnj0DAIwYMWLMmDFwMFNVVVVSUpItOJDfcYGRBjn47P5xYJ+dkAHx2fX4Yo9dEI8D+tln1wO4
+knltba00j/p4eXmlp6dnZWV5eHgQ5YHXN+KPJ8nRv4Zox/Hjxzs7O4eHh48ZM0a0SiUyatSooqKi
+iRMnTpgw4dGjRxQKRbZx4vfff//0008BAJMmTTp16pSjo+PNmzf19PRkvjkkm78PIy8G4/UEwD67
+/zIgPjuycUA/++wAAFVVVcJ7obCW0PdFhIwePZrBYCQnJ/P5fKL+A6f4hecljx49gv+Ro38N3Y4b
+N26cNWtWQEAAvNWPYNSoUTdv3pwwYYKBgQGbza6urha9P9HQ0FBfXy/NmbvoSxva2trKysojRoyQ
+bld6QrafY/qDQTpOYJ8dZEB8dmTj9Pd2AQANDQ3Z2dn8XSCkAAAgAElEQVTv3r1raWmJjo62srIS
+etZ6xdvbu66uLj8/n6j/6Orqmpqa3rp1i8/n37179+LFi8Lvysu/hm5HBQWFw4cPKysrb9myBd1P
+9PT0Ghoa4NMBRkZGXC5X9PngLVu2uLq69vryIwCgs7MzIyOju7ubz+cnJSUNHTpU5tVqyfZzTH8w
+eNeLxT47yPv32RF55Q4fPoyI03/bzcvL++233/71r3+1tbUNHTrUzs5u8+bNiEuorKysQ4cOdXd3
+Ozs7QwWQv7//b7/9dvv2baL+U19fv3PnThaLZWNj4+jo6Ovrq62tffXqVUDSv0bUfyS2Y3p6+okT
+JwQCwYEDBxgMxvnz5/fv36+hoXHjxg2iXfvll18OHjx4+/ZtGo22e/fu6upq0edoPT09q6qqzp49
+K/68gygPHz68d+/elStX6urqaDTa+PHjg4KCJkyYsG7duoqKiv3793O53CNHjhw7dqyysjI+Pv7O
+nTuI/RLv52fPniXl48P0ncE7TpAC++wwGMygZZDOO8kX7LMbVEj/lDAG83GAryd6B/vsMBjMYAaP
+ExgMBoNBgeedMBgMBoMCjxMYDAaDQYHHCQwGg8GgGIzjRE5OjqOjI51Ot7e3h6sZ79q1q6urS+4b
+ktLPJV+wpw8BWU/fypUrnZycrK2tzczM4BJM0qvrpAGxTjgRA9i+8mJAjgs0cvEM9uBj8u4NxnHC
+2dn5559/BgBERETk5eWdPHmSyWRCpYQMILxyUnrH5Aj29KFzkvX0paWlMZlMb29vXV1dJpPJZDJ7
+tTyRKj/ROuFEDGz7kuKDOi56pe+ewY/buzcY1wHswbRp0yZOnFhZWSn3yHZ2dqTEk31H6OmDVoaZ
+M2f2x34R8f73F8jq6XN1dV26dKn4Gq4fOAPbvvJiQPoJpi/gcQIAAKhUKlyngcfjnTp16sqVK93d
+3RMnTgwNDR0zZszJkydPnjwJAFi8eLGtrW1MTAyXy92wYYOJiYmXlxecLvj8888pFIqSkhJcY1x0
+HYLy8nLhy88S48fExCQlJTk4OCxatCgmJobFYoWEhDg5OQEAWCzWwYMHKyoqBAIBXLcArr1BxNWr
+V5cuXSrq6bOxsSHa7uHDh9PT011dXZ2dnY8dO9bc3Pzll18uWbJkz549mZmZampqgYGB7u7uqamp
+cXFxAoFg9erVEuvB3d2daH8bGxsjIyPv379Po9HU1dXZbPaYMWPi4+Php0VFRaL7W1VVRVSfCBCe
+voSEhIaGhmHDhpmYmBw+fFj4kdDTJ9spJFF7IcovEAiys7NTU1NbWlrU1NQCAgJk+6Ek1b5E/fav
+v/6S2O5k47i7u8NlPO7du/fq1StFRUU/P7+VK1ci6kFexwUREsuDiMPn8xMTEzMzMxsaGsRX3RdH
+Yjl77bc9+jkg6A+Ieib7OyB3BuO8Uw+6u7vr6urggqMSfWREfjGEb4toPkFifF9fX0tLS4l+rpiY
+GB6Pl5WVVVBQEBkZifY7Yk+fEHl5+iRC1F6I8kv01pHdLtn2JWovonYnGwcAUFJSMmTIkNTU1MLC
+QhcXl5iYGIFA8B6OCyIklgcRh8gzSITEcsrg3SPrMST1O9AfDPZxgsvlHj16VF1d3c3NjchHJoNf
+jGhbEuOrqqrSaDSJfq6mpqbOzk4KhaKgoAAvXxDxsadPiNw9faIg2ksiRN46stsl275E7UXU7jL0
+/yVLluzYsWP48OFUKnX27Nnd3d0yrOcqw3FBhMTyEMUh8gySLSf6W+LblcFjSOp3oD8Y1PNOe/fu
+VVVVNTU1TUlJodFoVVVVCJ8d+LtfzNbWluzm0L48iX4uHx+f3bt3w0divvjiC/HlUUWRr6cvKSmp
+uLjYzs4O7elD1MN78/SNHDmyR2JNTY1wJgrt6RP/rpRIX36hty4lJQWm9PDWSYls7QsI2ku83WWL
+k5ycfPPmTTabLfOK3zIcFwiIyiMeh8gzKFs5iRDfbq/9QbyeSf0O9AeDepyIiIiYO3euXEL1k2/L
+wsIiOzs7Nze3oKAgJCTE0NDw9OnTsMOJgz19QuTo6ZMN0fLLy1vX9/YlQtjuZImIiHjw4EFkZOS0
+adOKioq2bNnSI8N79tD1Wh5RiDyDfUGa/ZWhP5D6HegPBvu8kyhS+ux6IL1vS4b4hw4d4vP5Cxcu
+jI6Ovnjx4tOnT9HzFdjTB5GXp08GxMsvR29dX9qXCGG7yxCnpKTE1dXVxMREQUGhx52Dfj0uZCiP
+OESeQdnKKf3+ytAfyP4OyB08TvwPtM+OCOl9WzLELy8vv3z5cmNjo0AgeP36NQAA7VnDnj6IXDx9
+siGx/PLy1snQvkSIt7sMcXR0dO7fvw+fBImJiem1HiQiW/nJlkcchGdQhnKS6rdk+wPZ3wG5MxjX
+i83KyoqOjmaxWBoaGjQa7fvvvzcxMYEfSfSRIfx0gMArR+Tnkhj/0KFDGRkZEv1caWlp2dnZdXV1
+VCpVS0vL29u71/XGsacP0ndPHwBg2bJlbDabw+FwuVz4Q7B///7r168TtRei/OLeOn19/YULFxJ5
+3Prevoj2ktjugHz/r6io2LdvH5vNNjY2trKyOn78uL6+fk5ODlE9yOu4IKocieWxtrYmioPwDEqE
+6DiSuL9o7x4pj6EMvwPyZTCOExgh2NM3OEG3OwbTAzzvhCEEe/owGAzA1xODGezpG5wg2h2DkQge
+JzAYDAaDAs87YTAYDAYFHicwGAwGgwKPExgMBoNBMRjHiSNHjlhYWMyZM2fevHmOjo4hISFwUSMh
+/e3b6hH/xIkTs2fPll5W0xf6w9v1PuOL8jH5wkiRmZnp7OxsbW3t5OTU460RaZBvveXl5fn4+DAY
+DDc3t+3bt7948eLbb781NzeHb1EAAH766ac5c+asXLkyNjbW3Nzc0tIyISEBABAVFTVnzhz4Oiep
++EQ+ypycHCcnpzlz5lhaWjo5OT148KDXwl+9enXNmjVOTk7z5s3bvHlzXV0dOj/aP/gBevrkxWAc
+J8LCwmxtbc3Nza9fv3727Nm2trZly5bBxV4gpHxbMvjXesTfvHmzmZkZqV2QbbtAHt6ugYrf374w
+2erz/dPd3b1v3z5nZ+cbN26cO3fu5s2b6Pz9Wm8//fRTeHi4r69vbm5uUlLSkydPWCxWcHDwjBkz
+4uLi4BJbnp6eM2fOjIyM3Lhx44wZMxwcHNavXw8A2LFjx8yZMxMTE8nGJ/JROjs7M5nMmTNnOjg4
+MJlMaZ7ArqmpsbW1zc7OzsjI6Ojo+Prrr9H50f7BD9DTJy8G4zghio6OzrfffsvlclNTU4WJdnZ2
+KSkp/bfMVn/Hx3zENDc383g8KysrKpWqoaEhPG1//3R3d8fFxa1du9ba2lpBQWHkyJEzZsxQUlKC
+n9bX11+6dKn/4gvpi49SR0dn0qRJCgoKampqixcvfvDggZSWcol8xMf1oF4vFqKurm5lZXX79u1N
+mzYR+bYk+qSIPFYILxVRfEhJSYmoXywhISE+Pt7e3j4yMhIA4ODgwGKxcnJyXr9+TdabRsrbRbTd
+n3/+mawXjKy3S2J55OULI9pfsh46ovKfO3eupaUlJCTku+++CwsLq6+vT0xMjIiIsLOzI+sjk+hN
+AwBYWFjAk3Q/Pz9otYuLi5s5c+aA1Ft5eTmbzWYwGMKU3bt3C/9vbW0dHx/v4uJCo9EQe4oAHV8U
+oY9SInDxGHE/Y3FxsWiXa2tr09DQ6PV9fokgjmuJXkWJ9SyD11JensReGezXExA9PT3oFyO6rpTo
+kyLyWMngfQMAPHr06Ny5c1u3bl20aBH0i61fv17U+RwVFQX/I4M3jZS3i2i7MnjByHq7JCIvX5gM
+8UmVf/Xq1V1dXaWlpVZWVrGxsc+fP58+fTpczIesj0yiNw0AcPv2bbhcXWJiYllZWVlZGdEg8R7q
+raGhAQDQwyQoZMOGDS0tLXCCSDbQ8YWI+iglsmPHDnE/IzwHgrx79660tPTs2bMBAQGyFZXouCby
+KkqsZxm8lnLxJEoDHicAAEBNTQ29viMpn5Rs/ruurq5Dhw5ZWFh89dVX6urq165dI7sXRJ4sst4u
+Ish6wWTwdsmA9L4wspHJll9VVZXD4axdu3bq1Kn19fVbtmyZMmVKU1MTINl/ZPOmkaXv9cZmsxUV
+FaHsSBx9fX0PD48ffviBw+HIVkJ0fIioj5Ioj7ifsaKiQvgW+ubNmz/77DN/f/958+Y5OzvLVlQi
+JHoVieqZrNdSXv1cGvC8EwAAtLW1wSVRiZDNJ0XKf2diYgKvnalU6qhRo3o8giUNRJ4sst4uNNJ7
+wWTwdsmlPPLyx5Etf0FBwYgRI8aMGVNaWjp27FhVVVXhZDqp/iObN40sfa83LS2tt2/fcjgcFRWV
+Fy9e+Pr6vnr1KjQ0VLg0i5+fX0ZGRlpaGlEEtNWn1/g9fJSIUD38jLa2tsKpoRMnTvD5/CdPnhw+
+fHjdunVnzpyR441oiV5FdD1L77WUVz+XBjxOAABAfX09nP8loleflHy9Xd3d3VL6xaTxpt2/fx/I
+29slCpEXTF4eN1H6yRcmMb4McYhWjhpwH1l/1Btc8vrp06fTpk3T19dnMpnm5ubwnB2ipaW1fPny
+5ORk4SWmhoYGnECDcDgcxOVCr/Gl8VEmJCSsX7++h58xKChINI+CgoKxsfGuXbsWL158+/ZteTku
+AYFXUV4+O3jEyff4IgLPOwEWi3X79u2FCxci8iB8UmT9a73y6tUroVeORqN1dHTAdPhzL0R6bxpZ
+bxd6u+IQxZejxw30sy9MYnw5lp+Uj0yOfjfQn/VGp9P19fXRep9169YJBALhqwz6+vqPHz+Ggxaf
+z2ez2fDcWeb4vZKVlQX/I/QztrW1CW9mREREwLsg4L8/371a8Egh0asoL5+dfI8vNIN9nHjx4kVg
+YKCpqSl63gPhkyLrXyNC1C+mpaUFvXJGRkaVlZUdHR1FRUU9DhjpvWlkvV3o7YqDiC8vjxvR/hIh
+w3b71UNHykcmR78b0X4RQWp/FRUVt27deuHCheTkZDiTLv4jq6GhsXr1auGfLi4utbW1ubm5AoEg
+IyPD3NwcsXavNPGlR+hnFK3JFy9e/Prrr3w+//Xr19HR0VpaWjK8yYSAyKsoL5+dHI8vNINxvdhD
+hw5dunRJIBAoKysrKytbW1sHBQUNHToUEHvZED4pcY9Veno6We+bv79/aWkpAEBVVVXUL9ba2rp9
++/bHjx9bWVm5urp+9dVXmpqa8KkJ6b1pRkZGZL1dErfLYDBk8IKR8nYh6LsvDH1KLn19EpV/3bp1
+FRUV+/fv53K5R44cOXbsWGVlZXx8/J07d8j6yIi8aY6Ojjwer6WlRVNTc8iQIdOnTxc+jTZQ9VZS
+UpKYmPjnn3/SaDRLS8tNmzalpKT89NNPU6dOPXv2LADg9evXCxYs+M9//gNXp8/JyTl58mR3d7eZ
+mdnu3bt7VZSLx797965EH2V8fHxCQgKPx6NQKPDiAAAwcuRI4dNBwcHB+fn5eXl5whm/o0ePFhQU
+dHZ28vn8Tz/9dOvWrcbGxkQl6e7uJvIPEh3XgNirKF7PP/74owxeS7LtJRuDcZzAYDAYjPQM9nkn
+DAaDwaDB4wQGg8FgUOBxAoPBYDAo8DiBwWAwGBR4nMBgMBgMCjxOYDAYDAYFHicwGAwGgwKPExgM
+BoNBgccJDAaDwaDA4wQGg8FgUOBxAoPBYDAo8DiBwWAwGBR4nMBgMBgMCjxOYDAYDAYFHicwGAwG
+gwKPExgMBoNBgccJDAaDwaDA4wQGg8FgUOBxAoPBYDAo8DiBwWAwGBR4nMBgMBgMCjxOYDAYDAYF
+HicwGAwGgwKPExgMBoNBMRjHiZycHCsrq1mzZjk5OdnY2Hh4eJSWlvbHhi5cuECn01+8eNEfwTEY
+DOb9MBjHCWdnZ09PT2NjYyaTWVhYOGnSpJCQEB6PJ/cNjRgx4tNPPx0yZIjcI2MwGMx7YzCOE6JQ
+qdT58+e3t7c3NDTIPbidnV1KSoqWlpbcI2MwGMx7Y7CPEwAANputoqKir6+fkJBgbm4eGhoK0x0c
+HOCsUUxMDJ1ODw4OLioqWrp0qb29PZPJBAAQpQMAHB0dGQzG3Llz6XT6u3fvYCIif2NjY1BQkIOD
+w4IFC1asWOHo6LhhwwZEmXk83okTJ1xdXRkMxqZNm+rq6tDxIZ6ennQ6/f79+3KtPwwG85EzqMcJ
+gUBQW1ubnJy8YcMGKpW6fv36OXPmCD+NioqC//H19bW0tKypqTl37tyePXssLCyOHDnC5/OJ0gEA
+ubm5eXl5e/bsEd0cIv+OHTu6urqys7OTkpLYbLaHh8fOnTsRJY+Ojs7Ly0tMTGQymRMnTvTx8ens
+7ETEx2AwGJkZvOPE48ePGQyGu7v7lClTvL29ETlVVVVpNNqrV68OHDhgamrq5OTU3t7OYrGI0snG
+aW1tvX//vre3N41G09HRcXNzu3PnjpGREVEcLpebnp6+atUqbW1tKpW6YcOGjo6O7OzsXstz7Nix
+zMzMyZMny1ZjGAxmcDJ4xwljY+OrV68uX778zp073d3dvean0+mampoAAHi/QfgVonTp4ygqKgIA
+4L8AAAqFgo5QX1//9u3bcePGwT+VlZV1dXUfP37ca3lGjRplaGhIo9F63VkMBoMRMnjHCYiXlxeb
+zc7KyhrAMqirq1tbW589e5bL5dbX11+6dMnJyWkAy4PBYDCiDPZxYvTo0QwGIzk5Gc7j02i0jo4O
++NH7vN+7b9++u3fvLl68OCgoaO3atYsWLUJkNjAwUFRUfPr0KfyTw+E0NjYi5qmENDQ01NfXS3Px
+hMFgMEIG+zgBAPD29q6rq8vPzwcAGBkZVVZWdnR0FBUVXbx48b2V4ejRo87Ozunp6YmJiW5ubuip
+J2VlZU9Pz7S0NBaLxefz4+Pj1dTUFixY0OtWtmzZ4urq+tdff8mv4BgM5uOH8uuvvw50Gd43WVlZ
+hw4d6u7udnZ23r9/PwDA39//t99+u337dmtr6/bt2x8/fmxlZeXq6vrVV19pamoyGIyMjAwKhRIa
+Guru7r58+fI///xz5MiR8+bNk5h+/fp1R0dHPp/f1dXV0dGhra1NoVCWLFnCYrGI8kdGRv7444/C
+EhoYGBw/fhxxicDj8f7973/n5eW9fft2woQJoaGhY8eOPXToEFF8+C1PT8+qqqqzZ8+ampr2dyVj
+MJiPhsE4TnxotLe3+/n5BQYGWlpaCgSCZ8+eLV++fPXq1V9++eVAFw2DwWAG5bxTa2vrQBfhb5SV
+lT169Gj48OF8Pr+zs7OmpubNmzeffPLJQJcLg8FgAMDXEx8CnZ2d33zzTVFREZfLVVRUNDQ0XLZs
+maur60CXC4PBYADA4wQGg8Fg0AzGeScMBoPBSA8eJzAYDAaDAo8TGAwGg0GhONAF+IBITU1NTExs
+aWnR0dGhUqkAgLa2th9++OHt27ehoaEtLS1UKhUuncTn8w0MDH744YeVK1ey2exXr151dnbq6uoC
+AP71r3+JLjorSk5OzsGDB7u7u7W1tV+/fq2joxMSEkKUWRouXLiwb9++nJwcfX39/shPChaLVVhY
+WFBQEBYWZmhoKHP+jIyMtLS0169fz5w5c+fOncrKynIvKgaDIQUeJ/7HqlWrpk2b5uPjc+bMGfhL
+ChcGNzU1ZTKZ/v7++vr6e/fuBQC0tbVt374dAJCWlgYAOH369IULF3rIHsRxdnaurq4uLi7+6aef
+3r17t3v37pCQkGvXrikpKclWYLK+vH7y69XX13/99deNjY3GxsYlJSVv376VOT+TyYyKikpOTjY0
+NNy5c+e2bdtOnTrV68KIGAymX8HjBAo9PT2Jq6sqKipOmzatL5GhR4/JZDY0NEhz9i0ROzs7Ozu7
+/ssvJerq6hEREePGjauqqiopKZE5v0AgSExMXLp06YQJEwAAgYGBrq6ulZWV+FUSDGZgweMEio0b
+N0pMV1VVhdcTfUHo0QMACASC7Ozs1NTUlpYWNTW1gIAAOzs7uJiHmppaYGCgu7t7ampqXFycQCAo
+Li4WXRekvLwczpIBAFgs1sGDBysqKgQCgaqqqo2NTVhYGACAKD+Pxzt16tSVK1e6u7snTpwYGho6
+ZsyYmJiYpKQkBweHRYsWxcTEsFiskJAQxBK2GhoaGhoa0u84Uf4XL15UV1cHBgbCPw0NDXV1dQsK
+CvA4gcEMLPg+NiGRkZES0ysqKvLy8voSuYdHDwBw4cKF2NjYqKiovLy8gICA4ODgly9f7tixQ1tb
+29XV1d3dHQCwatWqefPmwVJJ9OUBAGJiYng8XlZWVkFBQWRkpHAqjCj/B+XFg4pybW1tYYqWllZj
+Y2N/bxeDwaDB44QE1q5d6+TkdPny5R7pubm5Tk5OgYGBQimQDIh79AQCQVxcnJeXl4GBAQDAzs5O
+VVX11q1bCgoKLi4uOTk5PB4PAMDlcisqKiwtLRHBm5qaOjs7KRSKgoKCiYmJl5cXIrPMXjw0AoFA
+2rr4e/62tjYAgOiNaxUVFTabTSoaBoORO3ickMCZM2eYTKboiS3E0dGRyWTCmRyZEffosdlsFot1
++vRpp//C5/PhIlRubm5tbW3FxcUAgPz8fFtbW+GUkUR8fHzq6uoYDMbOnTvz8/N9fX0RmWX24vUT
+cHMcDkeYwuFwhg8f3t/bxWAwaPD9CUIyMjIkpjs6OvY9uJeXV3p6elZWloeHBzSeBgQEwPklUYyM
+jD755JPMzEw7O7vMzMygoCB0WAsLi+zs7Nzc3IKCgpCQEENDw9OnT8Mf+veGzNcTo0aNAgA0NzdP
+mjQJprBYLPT1EwaDeQ/g6wkUv//++88//9wfkUU9eurq6gYGBkVFRRJzurm53bhxo6qqqq2tTfgD
+SsShQ4f4fP7ChQujo6MvXrz49OnTW7duEWWW2YtHFik9evr6+pMmTSorK4N/Pnv2rLGx0d7eXu7l
+wWAwpMDjBAo2m/3kyZN+Ci7q0du2bVt+fn5cXNyzZ8/q6+svXLhQUVEBs8HLl9DQUGmMdeXl5Zcv
+X25sbBQIBK9fvwYAwGdMJSKzF48sUnr0KBSKj4/PL7/8Ul1d3dXVdfToUXNz8z4+f4zBYPoOXi/2
+f5w+ffrUqVNv375VUlKC73a9e/du+fLl8+fPDw4OZrPZCgoKGhoavr6+y5Ytg19ZtmwZm83mcDhc
+LhdO7+zfv5/oFWuERw8AUFxcHB8f/+jRI0VFRVNT06CgIOGpfXBwcH5+fl5ennAGSaIvb8OGDWlp
+adnZ2XV1dVQqVUtLy9vbG65PTpRfNi9eD/744w84Icbj8dhs9ogRI+BMmvCpsB4ePXT+8+fPp6am
+dnZ2zp49G7+PjcF8COBxAoPBYDAo8LzT++ND8+hhMBiMNOBx4v0xYsSIgS4CBoPBkAaPExgMBoNB
+gccJDAaDwaDA4wQGg8FgUOBxAoPBYDAo8DjxP3JychwdHel0ur29PYPBmDt37q5du7q6ugAAjo6O
+MIVOp797966PG8rMzHR2dra2tnZycjpy5Ig8yi5nBALBmTNnXFxcGAzGqlWr7t69K/yopaVl165d
+rq6uCxYs2LFjh/B1biLQ+dPS0uh0+v3796UsWHl5OYPBiI2NlWP8EydOzJ49W3wxXSEXLlyg0+kv
+XrzotXh//fWXs7PzN99808fldXk8XlRU1IIFCxwcHFxcXGJiYvoSrZ9ITU21t7en0+mOjo4ODg6O
+jo4XLlx4nwWQvl0+ju0OIHic+B/Ozs5wlY6IiIi8vLyTJ08ymcxffvkFEK/LjaC4uJhOp7969apH
+end39759+5ydnW/cuHHu3LmbN2/KcRfkxYULFy5fvnz69OkrV664urpu3boVjpetra2rVq1SVVVN
+T08/d+5cY2Pjs2fPEHHQ+VksVkpKCnzJThoqKioCAgL2798v9ILIJf7mzZvNzMwQGSR6ACW27+TJ
+k8+fP19ZWXngwAEpd0oiaWlphYWFqamp165dCwsLy83N7Uu0fmLVqlXh4eEAgEuXLl27ds3FxeXA
+gQNNTU2yRSM6XhD0k5+x1/L063Y/TPA4Qci0adMmTpxYWVkp37DNzc08Hs/KyopKpWpoaOTk5Mg3
+vly4ffv2J598oqenR6FQbGxsOBxOc3MzAODHH3+kUqlhYWHKyspqamqzZs0aNmwYIg46/3fffbdu
+3Topta/v3r0LDw9fsWKF6OvucoyPwM7OLiUlRcrlFIcNG3bw4MGMjIyHDx/KvMWKigozMzO4gO7s
+2bNljvM+mTt3Lp/Pr6ure29bJNUuH8F2BxA8TqCgUqkqKiqIDFVVVbt373Z2draxsbG3t4e67Kqq
+KnNz8y1btgAAPv/8c3NzcysrK5jfwsJi0aJFAAA/Pz9zc3Nzc/Py8nIAAI/HO3HihKurK4PB2LRp
+EzzYTp48SafT6XR6REREYWHh4sWL4aW9p6fnvHnzrly5wmAw8vPzk5OTbW1tCwsLhaXy9PSUZjJn
+9+7d5ubmZmZmWVlZAIDCwsI5c+bY2toCACZPnpyXlwcXFLl27ZqhoeHo0aMBAJcvX54/f76Cwv/v
+Nlu2bEGfiSPyl5aW1tXVeXh4oAsp5NatW8+ePVuyZEk/xQcAlJSUrFixwsHBAV5EAoL5RkT7QkaP
+Hm1jYxMXF9cjvpTtAgBQU1O7d+8edG/QaDThfI5AIMjKylqxYgWDwfDw8BBt9MLCQi8vLwcHB1dX
+1507dwIAEhISzM3NQ0NDYQYHBwc4W0LUr9DxewWWVk9PDxD0Z6L0XutTHIntEhMTQ6fTg4ODi4qK
+li5dam9vL/R0STxOieoNUR6J242MjKTT6TY2NrAOU1NTra2t4Vf6Up8fFHicIKS7u7uurg69RGtJ
+ScmQIUNSU1MLCwvhPLJAIICLnh47dgwAkJ+fX1ZWBgUSAIDbt29fvHgRAJCYmFhWVlZWVjZz5kxA
+4JVzc3NLSEiYOnXqgwcPkpOTfX19P/3005qamnFK82QAACAASURBVNWrV3d1dZWWllpZWcXGxj5/
+/nz69OlEiy8hOHDgALTj6erqAgAmTpw4fvx4eH2zZs2aGTNmbNy48eDBg//5z39OnDihoKDw5s2b
+xsZGHR2dgwcPuri4eHp6ZmdnI+Ij8vN4vMjIyK+//lr4E98rDx48GDduHPwZ6o/4jx49Onfu3Nat
+WxctWnTgwIGamhpAMN+IaF8h8AyA7BLrQtavX0+lUj08PJhMJp/PF14kSfQeAgCKioq2bdu2evXq
+q1evHj9+HP4erV+/XvTaKyoqCv6HqF8h4vdKY2NjfHy8u7s7PJ+Q2J+J0qWpzx5IbBeEh1HicUpU
+b4jySNwuwjspc31+aOBxQjJcLvfo0aPq6upubm6IbEuWLNmxY8fw4cOpVOrs2bO7u7u5XK4M25Lo
+ldPX1581a5a6unp7e/vRo0ddXFxcXFzU1dVVVVU5HM7atWunTp1aX1+/ZcuWKVOmiM4LHzt2LDMz
+c/Lkyb1u2t7efsmSJTt37mSxWOHh4eHh4fD6SUFBQUVFxcLC4uLFi6qqqnCKHyrtEhMTLSwsMjIy
+AgICdu/efe/ePaLgiPxnz56dPXs2qbVgnzx5oqOj03/xu7q6Dh06ZGFh8dVXX6mrq1+7dk3674qj
+q6vL4XB6rNQifbuMHTv23LlzdnZ2u3bt8vPzg/JXIu8hACAxMdHKymr+/PkUCmXs2LFwvUUiiPoV
+Ij4aFxeX+fPnv3379quvvgLE/Zkovdf4UoLwMBIdp6TqjQgi76TM9fkBgj1FEti7d6+qqqqpqWlK
+SgqNRkNnTk5OvnnzJpvNlmGEgKC9cgCAzz77DE5V29ra2traFhQUjBgxYsyYMaWlpWPHjlVVVe0x
+BQ+FP1Kyffv2ioqKpUuX+vn5TZkyBSbu37+fw+HExsZWVVVt27Zt7dq1ycnJcAixs7ObN28eAMDG
+xoZOp2dlZRFNPRHlHzVq1IULF86dOyd9IQEALBZr5MiR/RffxMQEBqRSqaNGjeqjlxu2V0tLi2iZ
+SbWLsrJyeHj48uXLQ0JCPD09U1NTlZWVofcwJSUF5hF6D2tqaoQzchQK5dSpU9Jsoke/am1tJYqP
+Jisri8PhREVFrVixIi0tra2tTWJ/7rWfywUiD6PE41S2ehPHzc0tKSmpuLjYzs5O6J2UuT4/QPA4
+IYGIiIi5c+dKmfPBgweRkZHTpk0rKiqCc5qiyDzzgAYuey4vFBUVoVUb/snlcnNycr7//nsFBYUp
+U6YkJyc7OTlduXJl7dq1NBpt7Nixwi/q6Ogg+r26urrE/Ddv3mxoaHBychJuzt/ff86cOdHR0YhC
+6uvrP3/+vP/ii9Ld3a2hoSFNTqL2bWlpAQDASRgZ+P333z/99FMAwKRJk06dOuXo6Hjz5k0XFxdA
+4D1UUlJ6+/atbNsSgvAq9sqIESP27t1rbW19+fJlKY8difTT8UJ0nPZab1KWR6J3si/1+aGB5536
+RElJiaurq4mJiYKCQo9H5uHPbnt7e69B5O6Vk9IfB/nuu++++OKL4ODg77//HqqEOBwOj8cbOnQo
+zKCrq6ulpcXhcCgUymeffSaqG2pqahL9me4BUX5XV9fMzMyf/guNRjt48ODu3bvR5RwzZkyPJ9bl
+G1/Iq1evXr58OXHiRHQ2dPu+fPlSR0enx0MQ0rdLQECA8P/a2trKysojRoxAeA8nTZp0584d8R81
+Go3W0dEB/9/r/XO0V7FXhg4dqqam1tHRQdSf0f1c+uNFBoiOU6J6k6E84t7JPtbnBwUeJ/qEjo7O
+/fv34R3vHi9DwcvekpKSly9f/vzzz4hZKbl75aT0xwEACgoKamtr165du2TJEhsbm9DQUChcmjFj
+xsmTJ9va2gQCAZPJZLPZDAYDAODt7X3lypXCwkKBQFBaWlpZWdnjAaQeSMyvoqKiL4KCgoKWllav
+Txna29s3NTX98ccf/RS/vb39xYsX9fX1hw8f1tLS+uKLL9D50e179epVc3PzHl+Rvl06OzszMjK6
+u7v5fH5SUtLQoUOhJ5zIe+jv7//w4cPDhw/X1tY+f/78/PnzcDQyMjKqrKzs6OgoKiqCD1CgQXgV
+0Qj7yfTp04n6M7qfS3+8yADRcUpUbzKUR6J3Uub6/NDAnqL/kZWVFR0dzWKxNDQ0aDTa999/b2Ji
+AgDo7u5euHChRB9cRUXFvn372Gy2sbGxlZXV8ePH9fX14SNDAoEgPDw8Ly9PVVXVxsZm165dQ4YM
+cXR05PF4LS0tmpqaQ4YMmT59OnwKRaJXLiUlJSUlRejRAwAkJSWNHj163bp1FRUV+/fv53K5R44c
+OXbsWGVlZXx8/J07d+CO9PDHERETE5Oamjp06FD4rp+bm1tdXZ2GhsaNGzdaWlpiYmLgc7F6enob
+N24UPjlz69atuLi4pqYmfX397du3T58+HV2riPwbNmx48uRJU1OTpqbmkiVLNm/ejA4VFhYGAOjx
+Brtc4vv7+5eWlgIAVFVVzczMdu3aBe8lEHkAAUH7wmi//vrr+vXr09PTx48fL7oV2C4///wz+mLl
+4cOH9+7du3LlSl1dHY1GGz9+fFBQkNBfS+Q9vHPnzokTJ6qrq5WUlOh0elRU1JAhQ1pbW7dv3/74
+8WMrKytXV9evvvpKU1PT19dXYr9Cxxfn22+/zczMbG9v19bW7u7uVlZW9vDwWL9+PYVCkdifAUE/
+h9EQ9SmOxHZhsVhEHkbEcSqx3ojKg+gPQJJ3klR9fsjgcQLTV6ytrSWmy/2Ku6GhYd26de7u7j4+
+PlQqVb7B5cXDhw+3bNni5+fn6enZ46NXr17Z2treunUL/VIOBvOhgccJTF8hWuhGX19f7ttqamqK
+iopSUlI6dOiQ3IP3ndLS0sjIyK+++kritFVUVBSPx9u1a9f7LxgG0xfwOIH55/HmzZsPc3WdN2/e
+KCkpET2N9ujRI2NjY+lf/cNgPhDwOIHBYDAYFPjUBoPBYDAo8DiBwWAwGBR4nMBgMBgMCjxO/I1/
+hEcMALBy5UonJydra2szMzMnJycnJyf4+P/A0k+eL4Rn8MOkv31ncoy/cuVKOzs7Op1eX18vr/gI
+P6DMXkiJ5UQg7j3MyMjw9PR0dnbes2cPXLwWAV0M+H4cUbq8PIYfLHic+Bty9IjJ4OeSnrS0NCaT
+6e3traury2QymUym6ArS7788EOm9b6RAeAZlQF71MIC+MznGT0tLgwtoyzE+wg8ogxcSIrGcRIh7
+D5lMZlRU1KFDhy5evMjhcLZt24ZeuOmoCAcPHlRVVYUL2hOly8tj+MGC1wH8G/9Ej9iHg52dnZ2d
+XX9vpZ88g3Kkv+vhnx6/XxH3HgoEgsTExKVLl8J32gMDA11dXSsrKz/55BOiIPb29sL/R0dHe3t7
+w/fzidLBfz2Grq6uS5cunTp1an/s2gCCx4m/IfSIDR8+XOgR27NnT2ZmppqaWmBgoLu7e2pqalxc
+nEAgKC4uZrFYBw8erKioEAgE8P3+sLCwqqoqLy8veFn9+eefUygUJSUlqDoRCATZ2dmpqaktLS1q
+amoBAQF2dnaenp4tLS0hISHfffddWFhYfX19YmJiREQE2WM1JiYmKSnJwcFh0aJFMTExLBYrJCTE
+ycmJbHkAAI2NjZGRkffv36fRaOrq6mw2e8yYMWZmZidPngQALF682NbWNiYmhsvlbtiwwd3dXXQ9
+g/LycviyNNF2EfUp5Z5Cz+DJkyeJysPj8U6dOnXlypXu7u6JEyeGhoaOGTNGhnoAABQWFiYkJDQ0
+NAwbNszExOTw4cOIOBLrAQAgsTxE7YXYcaL4EvshIg6fz09MTMzMzGxoaFBTU5M5Plwe5t69e69e
+vVJUVPTz81u5cqUwWklJybFjx5qbm7/88kv0OmBE9U9UTgTi3sMXL15UV1cHBgbCPw0NDXV1dQsK
+Cn788Ue4gsi+fftcXFwKCwtDQ0OHDh1648YN4Xerq6uhx77HViSmCz2G0l/6/FPA805/Q6JHLCIi
+QtxXBVcZiomJ4fF4WVlZBQUFkZGR0LOI8GFJ9FvJy09H5PMiWx4AwI4dO7q6urKzs5OSkthstoeH
+x86dOxEeNFLeN0R9SoPQM4goD1lvGilPHFnfGVF5EP41IojiS+yHCE6fPp2WlhYWFpaVlbV161aZ
+4xN54gCBH5AIovonKicCce9hQ0MDAEBbW1uYoqWl1djYiPA5iu74pk2bxCU0ROl99Bh+sOBx4m9I
+9IiJ+6ru3bsH1+9samqC5gYFBQUTExMvLy9EcCK/Va9+OilB+LxIlae1tfX+/fve3t40Gk1HR8fN
+ze3OnTtGRkZEHjSy5UTUZ6+IegaJykPWmyYvTxyizBLLQ7a9EJDqhzwe7+zZs97e3paWltra2oiV
+4XuNj/A5Su8HJKp/GcoJJHkP29raAADKysrCFBUVFWjzJvI5Qn7//fenT59+/vnnPTZBlA4IPIYf
+AXjeqSfiHjEDA4Mevqq5c+dCCYmPj8/u3bvhIxxffPGFr68vIjKbzZbot9LW1kb76UhB5POSvjxw
+1+C/QJITqYcHTYZCEtUnGiLPYI/yVFVVkfKmEdUDkJPvDO1xk769EJDqhy9fvuRwOKTm0BHxiXyO
+0vsBiepfhnICSd5DWL0cDkeYwuFw4DUEIPA5QuLi4pYvXy6+zgpROiDwGH4E4HHib0j0iK1cubKH
+r0p4CWxhYZGdnZ2bm1tQUBASEmJoaHj69GnRVYVFr0CJ/FYFBQXy9dMhkKY8AABra+uzZ89OmzaN
+xWJdunTJ399fjtsFYv4vKacUpPcMkioPoh7k5Tvrb3rth6LA82tSjzMRxe/V5whB+wGJ6h+Klcg+
+diXuPYS3mpubm6E+CADAYrFEr197+BwhDx48+L//+7/w8PAe8YnSIX30GH6w4HmnvyHRIwb/FPqq
+WlpahOcdhw4d4vP5CxcujI6Ovnjx4tOnT4WedHEf1sD6rUiVZ9++fXfv3l28eHFQUNDatWsXLVok
+x+1CJNanXCDrTZPBEycxjmzlkQuIfigOPJWura2Ffz569Ejm+Aifo5Be/YBE9S9DOYEk76G+vj68
+pQT/fPbsWWNjo/DJJXGfI6SgoMDIyEhcaU6UDpHoMfwIwOPE3yDyiAERX5Wzs7Pw1KO8vPzy5cuN
+jY0CgeD169cAAKFPRqIPawD9VqTKc/ToUWdn5/T09MTERDc3t75c7hB5wSTWp1yQwZtG1hOH2C+y
+5ZELiH4ojq6urqmp6a1bt/h8/t27d6Xx3BHFR/gcSfkBJda/DOUEkryHFArFx8fnl19+qa6u7urq
+Onr0qLm5+bRp0wCBzxF+q6SkROLpC1E6RKLH8CMArxf7P4g8Ys+fP4cXksHBwdevX8/NzRVObqal
+pWVnZ9fV1VGpVC0tLW9vb1dXV/gRkZ9L3G+1f/9+tJ9OnGXLlrHZbA6HAzWlAID9+/dfv36dyOdF
+qjxGRkaRkZE//vijcHMGBgbHjx8vKioi8qCR8r41NzcT1adEiDyDRL4/IJM3jZQnjigOUT1ILM+h
+Q4cQ7SURoviIfiiR+vp6ePPWxsbG0dHR19dXW1v76tWrZOMTeeIk+gERXkii+icqJ2LXAIH38Pz5
+86mpqZ2dnbNnz965c6eysjLC59jR0WFra+vl5bV9+3bRIETpECKP4UcAHidI8ODBg2PHjsl2M/Mf
+RHt7u5+fX2BgoKWlpUAgePbs2fLly1evXv3ll1/Kd0ODpD4x75kB8R4iPIYfAXjeiQQ5OTno07SP
+g7KyskePHg0fPpzP53d2dtbU1Lx58wbx8qrMDJL6xLxnRo0adebMmb/++kuGBUJko7S09Ouvv4ZP
+SL6fLb5n8PWEVDQ0NKxZs4bNZqupqSUnJxsaGg50ifqRzs7Ob775pqioiMvlKioqGhoaLlu2TL4/
+6IOqPjEDxXvzHqI9hh8BeJzAYDAYDAo874TBYDAYFHicwGAwGAwKPE5gMBgMBgUeJ/7H/fv3nZyc
+zM3NLS0toSRu/vz5okvZ9LenbKCA67XJtrIQRGZPmTgsFuuXX37ZtGmTlOYyovyk/GUYDAYBHif+
+h6mpKZPJnDFjhqOjI5TEpaeni2bob0/ZgCAQCEpKSrq6uvryZrjMnjJR6uvr16xZs2rVquvXrxcX
+F6MXVkLnJ+svw2AwCPA6gCgUFRXh+/2Qf7Tniwi4DvO7d++KioosLCwGsCTq6uoRERHjxo2rqqoq
+KSmROb8M/jIMBoMAX0+gUFVVhS/oS5xXOXnyJHSpR0REFBYWLl682NHR8cKFC56envPmzbty5QqD
+wcjPz09OTra1tS0sLFy2bNmcOXPKy8uF8aOjo2fOnAkAqKqq2r17t7Ozs42Njb29fVpaGiI+AEAg
+EGRlZa1YsYLBYHh4eEB/jhBPT086nQ6X2+yV4uJiS0tLCwsLoWzn8OHDdDp9z549JSUlK1ascHBw
+gDJqonQE6HL2QENDw8jISPqH0InyQ3+ZcJkdob9MyrAYDKYHeJwgpKKiIi8vD/5f4rwKkU+NyE/n
+4eExYcKEmTNnlpWVLV68mMvl+vn5wbWOJXrBEL42Iv+XDBQVFX322WeWlpa1tbXw1svWrVvNzMwe
+PXp06dKl8PDwNWvWQB8ZUToiuBzLKT1E/rL+3i4G87GCxwkJ5ObmOjk5BQYGIuQ2AAAinxqRn87Y
+2Pjx48d8Pr+0tPTp06e///57bW0tXGxOoheMKD7CvwY5duxYZmbm5MmTe91TLpf7+PHjKVOmmJub
+UygUeEmhrKyspKTU1dW1d+/eqVOnenl5aWpqXrt2jSidKHiv5URD9o6CMD/CX4bBYGQA35+QgKOj
+4969e3Nzc588eSJN/h4+tYKCAol+OmNjYy6X29jYeP/+/Xnz5t27d09fX9/Y2BgGIfKCicdvbW0l
+8q9BiBbHF6esrMzMzAyutzp16tTi4uKlS5fCj0xMTKAeXEFBQVdXV3g+TpQuDsIT16+g/WUYDIYs
+eJwgBAoSZEPiJPvw4cM1NDT+/PPPd+/eWVlZ5eTkcLnc6dOnAwCk9IJBEP41shQXF5eUlDg5OQEA
+Ojo6amtrJS6Jw+VyJfrIiNLlUk6Zryd69ZdhMBhS4Hmn9weFQhk/fvzly5c/+eSTGTNm3L9//6+/
+/oLzTtJ4wYT06sVraGior6/v9X2IxsbG27dvZ2ZmwoeAT58+zeVyxZ+O7ejokOgjI0qXvpxkkXK/
+0P4yDAZDFjxOvFeMjY1v3LhhZmY2ZsyYYcOGVVRUwKVSEV4wiaC9eFu2bHF1dRWVOEqks7NTT09P
+XV0d/jl16lQdHR3hU0+iPjJtbW2hj4woXYZykkXK/UL4yzAYjAzgeaf/cf/+/eDgYDab/euvvxYX
+F/v6+i5btgx+JPR8wf9DD9ewYcOgTw3mB//1qaWkpLS2tmZlZQEAampq4Ef37t0DABgbG/P5/Bkz
+ZlAolBkzZjx58gROzuzevXvfvn3z5883NjZ2cXE5fvz4kiVLVqxYITE+AMDBweHf//53fHz8f/7z
+H+j/mjFjBtn93bt3b3V1dUJCwvr16wEAQUFBbDb73LlzQUFBAIDy8vIVK1a8e/fOzMwsMTER3mKR
+mC7qKROtnw0bNpAq5x9//AE3zePxAAB+fn6wcoRPnUmf38nJqbOzMzQ0FPrL9u/f/xGv+YzB9Dd4
+XXGMBPz9/XV0dPbv3y9lOgaD+YjB804YDAaDQYHHCUxPYmNjKyoqrl275uTkJLoeBlE6BoP5uMHz
+ThgMBoNBga8nMBgMBoMCjxMYDAaDQYHHCQwGg8GgwOPE3+DxeFFRUQsWLHBwcIDrtg50iQj56aef
+oK/t66+/7ujoGOjikCYvL8/Hx4fBYLi5uW3fvl2OlsCEhARzc/Pg4GCiDP3qJfxntUt5eTmDwYiN
+jQUAxMbGQpljQkICACAqKmrOnDmOjo6pqanz5s2j0+kMBgN6Hi0tLSsrKxH+x5UrVzo5OVlbW5uZ
+mcGPSktLAQB//fWXs7PzN9980+uiA72C9h6mpaVJXFpfPJ2U9/DVq1f79u1zdXVdsGDBt99+K6rG
+IorzcXgV8TjxN9LS0goLC1NTU69duxYWFpabmzvQJZJMampqYmLi0aNHMzIyVFRU1q9fD981Q1Bc
+XEyn01+9etXHTcslzk8//RQeHu7r65ubm5uUlPTkyRMWi9XHgglZv379Z599hsjQf17Cf1a7VFRU
+BAQE7N+/f+PGjQCAjRs3zpgxw8HBAb53uWPHjpkzZyYmJq5aterbb78FAJw5cwYu8eLg4ACQ/se0
+tDQmk+nt7a2rqws/mjNnDgBg8uTJ58+fr6ysPHDggMx72qv3kMVipaSkwJcu0emkvIcCgSA0NPTN
+mzcZGRlnz569d++e8EUiojgfjVcRjxN/o6KiwszMDC44Onv27IEujmS4XO6pU6c2b948evToIUOG
+7Nix48WLF1euXBnocklLd3d3XFzc2rVrra2tFRQURo4cOWPGDOH73u8BOzu7lJQULS0t+Yb9Z7XL
+u3fvwsPDV6xYAX/BSaGnp0ej0cTTe/gfJTJs2LCDBw9mZGQ8fPiQ7HYh0GOYm5u7bds2iRm+++67
+devWifeoHumi3kMajRYYGFhWVlZZWUm03SdPnvzf//2fr68vlUodOXJkSEhIZmZmU1MTURyy8T9k
+8DjxN9TU1O7duwddBTQaDcrjIIWFhV5eXg4ODq6urjt37gQy+eYkpsfExNDp9ODg4KKioqVLl9rb
+2zOZTEQhi4qKOjo65s6dC/9UUlKytLTMysqC8y2hoaEw3cHBAc6uVFVVmZubwzVoP//8c3Nzcysr
+K0DspyMbR4iUHr3y8nI2m81gMIQpu3fvnjp1KqI+Jfr+evXridenRC8hUfsCAFgsVmBgoJ2dna2t
+7YIFC44cOfJPbBeJ3Lp169mzZ0uWLOk1pzgbN24cP368eLrQ/4hm9OjRNjY2cXFxMmwa9OY9LC0t
+raur8/Dw6DWdyHu4e/duc3NzMzMzuPROYWHhnDlzbG1tnz59CkT8V5MnT4YuGaI4H5NXEY8Tf2P9
++vVUKtXDw4PJZPL5fChaAAAUFRVt27Zt9erVV69ePX78OPx9l8E3JzHd19fX0tKypqbm3Llze/bs
+sbCwOHLkCGIC9/nz58rKysL1+wAAurq6z58/X79+vei5YVRUFPwPXDz12LFjAID8/PyysjK4WhSR
+n45sHLJA35yenl6PdER9SvT9of16EutTopcQELQvACAmJobH42VlZRUUFERGRqLH739Wuzx48GDc
+uHHirdArkZGREtNF/Y+9Ym5uXl5eLvdJGB6PFxkZ+fXXXysoKPSaTuQ9PHDgANxH6CyZOHHi+PHj
+c3Jy4AVoc3MzzFxbWwsAaGxsJIrzMXkV8TjxN8aOHXvu3Dk7O7tdu3b5+fkJGzUxMdHKymr+/PkU
+CmXs2LGmpqaA2GdH5HEjSldVVaXRaK9evTpw4ICpqamTk1N7eztivr6lpUVFRUU0RU1NTYb5fbJ+
+ul6R0qPHZrMVFRWFY7AQovoEBL4/dPmlr09A0L4AgKamps7OTgqFoqCgYGJi4uXlhQjywbaLRJ48
+eaKjo0PqK2vXrnVycrp8+XKPdCn9j6Lo6upyOBy5SKtEB5uzZ8/Onj1bfO5LYjrCe2hvb79kyZKd
+O3eyWKzw8PDw8HAVFZWpU6caGxufPn26q6vr+fPn0dHRSkpKnZ2dRHE+Jq8iHid6oqysHB4enp6e
+3tLS4unp+ezZMwBATU3NlClTYAYKhXLq1CnRr4j65vz9/YUeN6f/Aj1uROkwCJ1Oh0HgaQvCsjBy
+5MjXr1+LpnA4HJln26X30/XKqFGjDA0NJc5ci6KlpfX27Vvom3vx4gV8MCYzM1OYoUd9wsTk5GT4
+FE14eLg05Ze+PgFx+/r4+NTV1TEYjJ07d+bn58OHeYj4YNtFIiwWS01NDZ2nx/k+vI8teoIMgfex
+w8LCpN/6/2vv3gOhzPfHgX+GYST33FMuyVkdaWhDK0ubREtXS0VXyqmNNtmUE226b3YXSW5HYTmV
+s4hcYruhVTZptV3WJbdaZJiwDDEzvz+e35mvwzwfMyLk/fpLH898rk/znufzPOZNLE1LS4vgLxnS
+n3/+mZKSsnv3bgHL+eY9lJeXJ37et2+fvLz8F198sWTJEuLcEBUVPXv2bHt7+4oVK7755pvdu3ez
+2WwVFRWyevD1TyzwveL/4/Hjx3PnzkUI6enpRUZG2tra5ufnb9iwQUxMbPBjFWTI8rgRT0m+ex46
+DQ0NFovV1tbGyyX3+vVr4hplSPgrfXx+OsHrwSO+Gr22tnbOnDnq6urZ2dkmJib454IEzPcneP8H
+IFtfMzOzzMzMnJycW7du7d+/f8aMGdHR0WRv/RNrXdTV1V+9ejWgUFZWtv+zm52dnYMv+9LS0vhW
+KFT+RyJCEGfCO+INOT8/v7GxkUjOiBBisVgeHh6mpqZmZmZ8y7/++muEzXtIpVKJq0leyfTp08PC
+woifX758yeFwNDQ0yPInfkh5FeF64n94enryflZSUpKUlFRQUEAI6enp/frrrwL+JyTL4zZS+d0W
+LVokKytbUFBA/JPNZhcVFdnb2yOEaDQa75n9AfeTidO9ra2NrNr++emGV4+A+ebodLq6unpqair+
+sP4Eyfc3ZH49DLL1PXHiBIfDWblyZXBwcGpqam1tLW/aBxu368LXzJkzB/8Fibq6+osXL4h54HA4
+TCaT+FA8wOPHj5OTkwVsiK+GhgZlZeUB23QCnj9kHBwcMjIyrvwXjUY7fvz4oUOHyMrxeQ+/++67
+pUuX+vj4fP/997zUWB4eHrzTLzs7W0VFxdTUlKyeDymvIsSJ/9HV1ZWWltbT08PhcC5cuCAhIUHE
+fw8Pj2fPnp08ebK6uvrVq1c//fQT/mwmy+M2IvndJCQkduzYcfbs2fr6+rdv3wYHB6uqqhKPD2lr
+az99+rS9vb2wsHDAGzHxKbioqKihoSE5R/hxQAAAIABJREFUOZnFYhHlfPPTDaMeJHC+OSqVumfP
+npSUlLi4OOLOwZB/dYXJ9ydUfj0yZOtbUlKSnp7e1NTE5XKJPSVdXV2ySsbtuvC1ePHi169f//77
+7/0L7e3tq6urc3JyuFxuWlqaiYkJ38eKmExmTU0Nvn68vLw83oNAPAKeP2SmTp2q3o+IiIiioqKi
+oiJZOSbv4a1bt6qrq7ds2eLo6GhhYeHr60vMZ11dXVlZGYfDyc/Pj42N3b17N5VKJavnQ8qrCN8X
++3+ePXv28OHD69ev19XV0Wi0WbNmeXt7894Xfv3117CwsIqKCjExMTqdfubMmcuXLxP55kRERIht
+AV6+OYTQ3bt3o6KiKisriTxu3t7eRCrsweX//ve/09LSKBSKr6/vmjVr1q1b9/z582nTpt24cQPT
+28uXL1+5cqWrq8vY2PjAgQPEXnNra+u+fftevHhhbm7u4OCwc+dOOTk54ukdLpcbEBCQm5srJSVl
+YWHh5+cnLi7u4eHx+++/U6lUIj+dn58fcbEsbD1El5ycnMrLy+Pj43n3gTGKiopiY2OfP39Oo9EW
+Llz45Zdf5uXlkc1naWlpYGAgk8nU0dExNzc/e/asurp6VlYW3/7HxMRERUXxnU9eXsL29nYlJSVe
+3j2+6ysuLp6UlJSZmVlXVycqKqqoqLh582YHBwf8uMbhupAh7igMeNg3KysrIiKip6fH2Nj40KFD
+U6dOjY6OjoyM7OvrExMTI8IGm81et27dsmXLiPyPxHr1z//o7OzMZDI7OztZLBYRwI4ePcp7WOvR
+o0fu7u6XL18e8HAtcf4kJyfjLwr75zFkMpkKCgoD8h7u2LGjpqbm9evXcnJyjo6OvDsTfMt/+umn
+xMREIu/hwYMHJSUlQ0JCEhMTJSQk8vPzEUIrVqyoq6uTlZW9c+dOWFhYQUFBS0uLpqbmxo0brays
+eL0aXA++fGKBODGpTfT8dBO9/2Tez7gaGxu3bdu2Zs2arVu3ioqKjmpbPM+ePfPy8tq+fbuTk9OA
+X3V0dFhaWhYUFAzYjwJjDvadAJikVFVVL168+Mcffwz+g5JRcv/+/X/+85/79+8fHCQQQhEREY6O
+jhAkxiG4npi8wsPDL168KCoqKicnFxAQMOGexJjo/Sfz/sf19u3b0fi2K74N8TavBqusrNTR0Rnw
+J3JgPIA4AQAAAAdCNwAAAByIEwAAAHAgTgAAAMCBOAEAAAAH4gQAAAAciBMAAABwIE4AAADAgTgB
+AAAAB+IEAAAAHIgTAAAAcCBOAAAAwIE4AQAAAAfiBAAAAByIEwAAAHAgTgAAAMCBOAEAAAAH4gQA
+AAAciBMAAABwIE4AAADAgTgBAAAAB+IEAAAAHOpYd2AMJCYmxsTEMJlMVVXVvr4+KpW6Y8eONWvW
+DPnClJSUwMDArKwsdXV1osTW1pbD4XR3d7e3t5eUlIiKio5Ghwe3y1dMTExUVNSnn34aFBQkSLUn
+T57My8uj0Wh//fVXZ2eniooKQqilpaW4uFiodoenrq7u+++/f/78uYiIyIwZM9auXWtjYzPirfSX
+mJgYGxvb0tKirKxMrNSbN2/+9a9/paenp6WlcblcKSkpMTExQ0PDffv2qaioJCYmhoWFsdlsPz+/
+ZcuW2dnZdXV1BQYG2trapqSkZGZmNjQ0sFgsXV1dHx+fv/3tb6PaeQDG0GS8nnBxcQkICEAIXb16
+9eeff7a3tz927Njr16+HfKGCgsLcuXPFxcV5JTk5Obm5uf7+/oMPvnv3Lp1O7+joePcOD26Xb/3u
+7u6ffPKJUDWfPHkyOzt769atioqK2dnZ2dnZRLTAtDsi6uvrXVxclJWVU1JSUlNT9fX1f/vttxFv
+ZQAXFxcigl68eJEYrLW1NULowIEDlpaWJiYmN27ciI+Pf/PmjbOz85s3b1xcXGxtbY2MjFatWiUh
+IUGn07/55htbW1uEUHx8/PLly69du5aTkyMtLe3l5dXT0zPa/QdgrEzGODHAp59+yuFw6urqhjzS
+ysoqISFBUVHxPfTqPbQ7depUKnXgBaWcnNxot4sQunDhgqys7IEDByQlJWk02vz582VkZEa8lSGp
+qanRaLT+JcrKykFBQSwWKzExsX/5zz//zGaz7ezseCVLliwRERGh0WibN29uamqqqKh4T50G4L2b
+jPtOAzCZTISQmpoasW+zePHi06dPI4Ssra0ZDAax6yLU/lJ5ebmrqyubzUYIffbZZxQKRUxM7O7d
+u2THOzs719TUhIeHz58/nygJDg5OSEgoKSnh2+6Q9RcWFoaEhDAYjP379/d/axvAy8trcGFCQgIi
+308rLy+Pj49/+PBhR0cHlUrdvn37hg0bQkJCLly4YG1tvWrVqgHt9vb2RkZGXr9+vaenZ/bs2b6+
+vjNnzkQI5eXlffHFFyIi//9jioWFhYWFBdnxERERERERCKHVq1dbWlqGhISwWCxiq5DL5WZmZiYm
+Jra0tEhLS3t6elpZWWGWZoBdu3YNLpSRkTE3N793796XX35JlLS1tYWFhUVFRVEoFKIkKCiIF9ia
+m5sRQrKysoK3C8DEMtmvJ5qamqKiotasWTN9+nR3d3dTU1Per86cOcP7GbO/NJienl5xcXFoaChC
+6ObNm8XFxZgggRBau3atrq7u/Pnzi4uLV69ezWKxtm/frqenR9Yuvv6qqqpLly75+/ubmZmdOnWK
+w+EINBH/i2y8RUVF4uLiiYmJt2/ftre3DwkJ4XK5bm5uCxcu5NtucHBwbm5ubGxsdnb27Nmzt27d
+2tXV1dnZ2dHRoaGhMbhdvsevWLEiJiZGX1//yZMncXFxbm5uc+fOraqqQgilpKSEh4efOXMmNzfX
+09PTx8enoaFBwDESnwb4UlNT619PUFDQ5s2b++/I6erqEkGOy+Veu3ZNU1OT73AA+DBM6jhhb2+/
+bNmyvr6+nTt3jmE3dHR0Xrx4weFw7t+/X1tb+/jx4+rqam1t7eHV1tHRcezYMUNDQzs7u7a2NgaD
+MYJddXR0/Prrr+Xl5UVFRRcsWNDT08NisaSkpGg02uB2WSzW5cuXXVxclJSUREVFd+zY0d7enpmZ
++ebNG8TvAzjZ8erq6h9//LGMjExbW9sPP/xgb29vb28vIyPD5XLPnz/v6upKvEdbWVlJSUkVFBQM
+OYotW7bY2dmlp6eTHSAtLc1isYifm5qaMjIyeJc+AyQlJT148CA4OJh3qQHAh2dS7ztdu3ats7Pz
+zJkz69evT0pKUlZWHpNu6OjosFispqamsrKyJUuWPHz4UF1dXUdHZ3i10el04h4DcV9hxO+vxsXF
+5efnM5lM3jspWbtv3rzp6+vT0tIiDpCUlFRRUXnx4sWKFSsQQm1tbQNqrq+v53s874BPPvmEaMLS
+0tLS0rK1tZXBYERHRxN7ZQghDofT2to65BAuXryorq6+atUqsgPevHnDu3pQUVExNzc/ffq0sbEx
+sWnGc/Xq1ZiYmPDw8GEHdQAmhEkdJxBCCgoKhw8fXrRoUXp6uru7+4jXz+VyhzxGXl5eVlb2+fPn
+bDbb3Nw8KyuLxWLNmzdvpOofQUeOHHny5Mnp06fnzJlTWFjI9w7HkGg02rRp06qrq9+xM8RNeE9P
+T0GeaR4sLS2N7Ff19fX9Q4KXl1dxcfHBgwfj4uJ4d/4zMzODg4MjIyOJHUIAPmCTet+JICEhIS0t
+3d7ejhCi0WjEDwihsrKyd6mW2IgY/KmZ75GzZs1KT0//+9//bmRkVFZW9scffwz5EVXw+kdQUVGR
+g4ODgYGBiIjIkHc+NDQ0qFRqbW0t8c/Ozs6mpiZiXPb29pmZmQOudTDH8yUjI6OhoVFYWDjs4Tx+
+/Dg5OXlAIYPBuHfv3sqVK3klNBrt1KlTFRUV58+fJ0oqKipOnDgREREBQQJMBpM9TnC53OzsbCaT
+SXx+19bWfvr0aXt7e2FhYWpq6rvUTGy/FBUVNTQ0JCcnD9ilGUBHR+fOnTvEzsaUKVNKS0tnzJgx
+gvWPFGVl5bKysp6enrq6upCQEPzBkpKSTk5OSUlJDAaDw+FERUVJS0t//vnnCKGNGzeKiop6e3vX
+1dX19PTcv38/PDwcczyZr7766ubNm+fPn3/58mV9fX1KSkppaangw2EymTU1Nf1L/vzzz7179xoa
+GlpaWvYvnzVrlre3d2xsbElJSU9Pj4+Pz9y5c7u6ukr/q76+XvB2AZhYKI8ePRrrPrxvQUFBGRkZ
+bW1tSkpKPT09kpKSa9eudXd3p1Aora2t+/bte/Hihbm5uYODw86dO+Xk5G7fvt3/OVElJSUKheLo
+6Lh58+aVK1cOLt+xYwdCiMvlBgQE5ObmSklJWVhY+Pn5Yf5gLSkp6dtvv719+7acnJy3t3dNTU1K
+Sgr63+dTh6w/Pj6eeHbT19d3zZo169ate/78+bRp027cuEHWbllZmY+PT2dnJ4vFUlRUtLKy8vPz
+w7RbWloaGBjIZDJ1dHTMzc3Pnj2rrq6+aNGitLQ0vu329vaeO3cuNze3r69PV1fX19dXU1OTaLq5
+uTkoKOjRo0ddXV0GBgbbtm1bsGAB3+MTEhISEhKYTKaIiAhx9/vChQvTp08n6rl7925UVFRlZSWV
+SjU0NPT29ia7BImOjo6MjOzr6xMTEyOuxths9rp163p7e69evcrlciUlJSUlJRctWuTt7S0hIZGQ
+kBAWFsbhcLZt27Zz5879+/fn5ubSaLTw8HA3N7cBlTs7Ox88eFDQUxCACWUyxgkAAACCm+z7TgAA
+APAgTgAAAMCBOAEAAAAH4gQAAAAciBMAAABwIE4AAADAgTgBAAAAB+IEAAAAHIgTAAAAcCBOAAAA
+wIE4AQAAAAfiBAAAAByIEwAAAHAgTgAAAMCBOAEAAAAH4gQAAAAciBMAAABwIE4AAADAgTgBAAAA
+B+IEAAAAHIgTAAAAcCBOAAAAwIE4AQAAAAfiBAAAAJzJGCfKysrs7OxMTEwWLlxoZ2dnZ2e3bNky
+Nze3se7XiElJSaHT6X/++aeAx2dkZCxfvnzRokV2dnanTp0a1b4JQtj+T1AxMTEmJiY+Pj6jVH9i
+YuKSJUvodLqNjQ1xni9cuPDp06eY83/Dhg12dnaLFi0yNjYmfnX//n1B2tqwYYOVlRWdTq+vryc7
+ZtWqVQsXLiwtLeWVBAcHz58/n+z4sLCwBQsW+Pv7CzNonElyXo2GyRgnDA0Ns7OzjYyMbG1ts7Oz
+s7OzL1++PNadGkkKCgpz584VFxcX5OCenp7AwMDly5ffuXPn0qVL+fn5o909wt27d+l0ekdHx+Bf
+CdX/iWLweN3d3T/55JPRa9HFxSUoKAghdPHiReI8t7a2RtjzPykpKTs7e/PmzSoqKsSvTE1NBWkr
+KSkpNDQUf8zatWsXLVpkZGTU0tKSm5uLEPryyy+1tLTIjt+9e7exsbFgYxUI3/MKcx4CHupYd2Bc
+oFKpc+bMGetejBgrKysrKysBD25ubu7t7TU3NxcVFZWVlc3KyhrNrglEqP4DwampqdFotMHl7+f8
+V1VVzcvLQwjdu3fP39/fysqqublZRUVltNvlgfNq2CBOIISQlJTUvn37EEK9vb2RkZHXr1/v6emZ
+PXu2r6/vzJkzIyIiIiIiEEKrV6+2tLQMCQlhsVg7duxYs2YN39qcnJxaWlr279//3XffHThwoL6+
+PjY29siRI1ZWVsLWz+VyMzMzExMTW1papKWlPT098Se6ra0th8Pp7u5ub28vKSkRFRVFCIWEhFy4
+cMHa2nrVqlUhISEMBmP//v12dnYIITMzs76+PoTQ9u3bRUREEELnz5+fP3++UP28dOkS2XjLy8vj
+4+MfPnzY0dFBpVK3b9++YcOG8vJyV1dXNpuNEPrss88oFIqYmNjdu3fJ+k+2LphxCYvBYBw/fry0
+tJTL5UpJSVlYWBw4cAAhRDb/Qq0LZryEwsLCAf0Xqn7Bz89du3bxrYF3/vOFmWcOhxMbG5uRkdHY
+2CgtLU1WA0FVVbWxsZGYEIRQdXX1X3/9paqqOuR4i4qKQkNDm5ub//GPfzg6OmKaIFtHvucVZl3w
+/XFyciJObENDQ/yQPxiTcd9pgNLSUuIqGCEUHBycm5sbGxubnZ09e/bsrVu3dnV1rVixIiYmRl9f
+/8mTJ3FxcW5ubnPnzq2qqiKrcOPGjd3d3ffv3zc3Nw8PD3/16tW8efNu3LgxjPpTUlLCw8PPnDmT
+m5vr6enp4+PT0NCAGUtOTk5ubu6ALV03N7eFCxdWVVVdunTJ39/fzMzs1KlTHA4HIXTv3r3U1FSE
+UGxsbHFxcXFxMbFfLFQ/MeMtKioSFxdPTEy8ffu2vb19SEgIl8vV09MrLi4mtilu3rxZXFzMe9Pk
+23+y/mDGJayQkJDe3t5r167dunXr9OnT2dnZRDnZ/Au1LpjxIoT49l+o+gU8P0+fPs335f3Pf74w
+8xwdHZ2UlHTgwIFr167t2bMHUwlCSE1NjcFgsNnsysrKBQsWVFZWNjY2EtcTmPFWVlZeunRpz549
+q1atOnbsGOb/HSJfR77nFWZdhP1/98Gb1HEiJyfHzs5u7969L168QAixWKzLly+7uLgoKSmJioru
+2LGjvb09MzNTXV39448/lpGRaWtr++GHH+zt7e3t7WVkZMiqlZKS6uzs3LJli76+fn19vZeX10cf
+ffT69Wth6+dyuefPn3d1ddXQ0EAIWVlZSUlJFRQUCDtMKSkpGo3W0dFx7NgxQ0NDOzu7trY2BoNB
+dryw/SQbL0LI0dHx66+/lpeXFxUVXbBgQU9PD4vFErb/ZP0RdlwYr1+/7urqolAoIiIiBgYGrq6u
+CCGy+R+pdSEM7r+w9Q95fm7ZssXOzi49PX3ACwec/2TI5rm3tzc+Pn7z5s0LFy5UUlLS1NTEj1RB
+QUFERKS5ubmtre3jjz+uqKhobGxUVVXFj7e7u/vEiRNmZmY7d+6UkZH5+eefMU3wXUdhDTn/oaGh
+GRkZf/vb34ZR+QQ1qfedbG1tDx8+nJOTU1NTgxCqr6/v6+vj3ViTlJRUUVHp/1/ok08+kZOTQwhZ
+WlpaWlpialZQUJg5c+b9+/c1NTWlpKTExMSGUX9rayuDwYiOjk5ISCAO4HA4ra2twxssnU4nKldU
+VEQI9fT0kB0pbD9v3brFd7yEuLi4/Px8JpM5jAghSH8EHxfG1q1bDx06ZGNj8+mnny5dupR4+IfJ
+ZPKdf7Ly4Y1ucP+HXT/Z+Xnx4kV1dfVVq1YNOH7A+S9sPxsaGjo7O/X19QUbKBIREVFRUSkvL5eW
+lp41a1ZKSoqampqBgQF+vAYGBlOnTkUIiYqKqqqqNjU1YZrgu47CGnL+ib2ySWVSxwmCra3tiNdJ
+oVDevRIqlYoQ8vT0JLsRMn6QjffIkSNPnjw5ffr0nDlzCgsLvby8BhzA5XJHv3dDMzMzy8zMzMnJ
+uXXr1v79+2fMmBEdHU08GDN4/tvb2/mWC0KQ8Y7SuqelpfEtH/b5/+bNG4SQUI+lqaqqFhYWzp49
+W1dXt7KykkKhqKqqCj7enp4eWVlZzAF815EIbHj912UC/b97byb1vtMAGhoaVCq1traW+GdnZ2dT
+U5O2tvZY1S8jI6OhoVFYWDhSHRDQCM5DUVGRg4ODgYGBiIjIgDsHRGhpa2sbvf40NjbW19cLcoVx
+4sQJDoezcuXK4ODg1NTU2tragoICsvkf3roIPt7RW/fHjx8nJyePVG3ErYXq6mrin5WVlUO+RFVV
+NT8/X1dXV0NDg8lkVlRUqKioCDjejo6OhoaG2bNnY47hu474agevy5D9Efy8+mBAnPg/kpKSTk5O
+SUlJDAaDw+FERUVJS0t//vnnY1j/V199dfPmzfPnz798+bK+vj4lJaX/nymNkhGcB2Vl5bKysp6e
+nrq6upCQkP6/Ij7lFRUVNTQ0JCcnY3alht0fLy8vBweHP/74Y8gjS0pK0tPTm5qauFzuX3/9hRDS
+1dVF5PM/jHURfLzDq18QTCZTkC0mAamoqBgaGhYUFHA4nAcPHhAPROCpqak1Njbq6uqKiIhoa2uz
+WCwJCQmEHW9bW9uff/5ZX19/8uRJRUXFpUuXYuonW0cMvuuCn3/Bz6sPBuXRo0dj3Yf3rayszMfH
+h8lkioiIyMrKurm5OTs7E7/q7e09d+5cbm5uX1+frq6ur6+vpqZmQkJCQkIC73iE0IULF6ZPn05W
+/7Zt20pLS48ePcpisU6dOhUaGvr06dOoqKhff/11GPXfvXs3KiqqsrKSSqUaGhp6e3tjPkr3f/5P
+SUmJQqE4OjoyGIy0tDQKheLr67tmzZp169Y9f/582rRpN27csLW17e3tbWlpkZOTExcXnzdv3pkz
+Z4SdB8x4S0tLAwMDmUymjo6Oubn52bNn1dXViT/R4HK5AQEBubm5xPOLfn5+4uLifPu/Y8cOvv05
+ceIE2biI2SCeX0xOTsZ/CEUIJSUlZWZm1tXViYqKKioqbt682cHBAT//Qq0L3/HGx8dHRUWR9V/w
++snWJTo6OjIysq+vT0xMjPjUzGaz161bt2zZMrLz39nZmclkdnZ2slgs4g306NGjN27cIJvn+vr6
+gwcPMhgMCwsLW1tbNzc3JSUl4o8k+PrPf/5z/Pjxe/fu0Wi0Q4cOVVRU8P7Ej+94PTw8iD8Il5KS
+MjY29vPzw98bIFtHsvOK77oQO2mY+Z+Ez8VOxjgBJomOjg5LS8uCggLiRigAYHhg3wl8sCIiIhwd
+HSFIAPCO4Hkn8MFavXq1jo7OWPcCgAkP4gT4YA15DxMAIAjYdwIAAIADcQIAAAAOxAkAAAA4kzFO
+jHYeMcF98803YWFhgpePH4LkLxupfGQJCQmmpqaenp7vWM/oecf1IssnOIz8a/h1Gf/nFRifJmOc
+wOcRI8tvNeJ5r1pbW/Py8tatWydg+bgiSP6ykcpHtnHjxvGcXuYd1wuTT3AYef0w6zIhziswPsHz
+TmMmOTl58eLFg7+kjKwcjE/vuF6YfIIjm38NziswbJPxeoKnsLDwiy++WLx4MZHPpLy83MTEhPhO
+088++8zExMTc3BxTfvLkSTqd7u/vX1RUtH79emtr6//85z/963dycqLT6WVlZYObfvv27ZUrV1xc
+XDDlzs7OpqamJSUlvN8SeeeFLScbfkREBJ1Op9PpR44cuX379urVq21tbVNSUhBCvb29YWFhDg4O
+NjY2X375ZV1dHfESDocTExOzcuVKU1NTb29vXlUMBmPv3r1WVlaWlpaff/55/80ThNDg+SGrn6yc
+JzExccGCBebm5sT3PeDb5ev27duurq7W1tYODg4HDx7EtOvk5LRkyZLr16/b2NjcvHkzLi7O0tLy
+9u3b/Wvrv16Y+eRyudeuXVu/fr2Njc3atWt5lZiZmRFf9719+3YTExMTExNi+WxtbYkvx6bT6UTC
+NYRQSEgInU738fEZcN5i1oVvPwEQ1uSNE4Pzc5HltyIr37Nnj7GxcWVl5dWrVwMCAjZt2jRkvi2e
+69eva2lpDf7u/v7la9eu1dXVnT9/fnFx8erVq1ks1vbt2/X09IQtJ+sDJg8a3/xxiDx/GVkeMUSS
+j4ysfrJyHkVFxTlz5mRlZRFfSYRpl6/CwsKvvvpq48aNeXl5Z8+e5b1f820Xk6eP73oNIy8hWT5B
+YfMSDplXjux8A0AQkzdOvHseNElJSTExse7u7sOHD+vr67u6usrJyfXPt0WW94rL5SYkJAz+cDeg
+XEdH58WLFxwO5/79+7W1tY8fP66urtbW1ha2nKz/ZHnQyPLHYfKXYfKIDc5HRlY/WTmvqoyMjNTU
+1PDwcF4SAmHzl8XGxpqbmy9btoxCoWhqahLf44bJl0eWp4/veo1VXsIh88qRnW8ACGjy3p8YkTxo
+CCEDA4MpU6ag/6br6p9vi+y7LR88eNDZ2Tl463lAuY6ODovFampqKisrW7JkycOHD9XV1XV0dIQt
+H3IIA/KglZeX880fh8lfhskjNjgfGVl+OnzeuqqqqsOHD3/77bf9v69J2PxlVVVVjo6OxM8UCiUy
+MhKR58tTVFTE5OlD5Ov4nvMSDplXjqyfAAho8sYJPLK8Y/h8ZCwWC59vi5CYmLhhwwYRkYEXcwPK
+5eXlZWVlnz9/zmazzc3Ns7KyWCzWvHnzhC0XbMRDw+QvEzCP2JD5yDBmzZq1fPnygICAmTNn8jbT
+hM1fJiYm1tfXJ3ij+LyEZOs4wGjnRxsyr5yA/QSADJw6A5HlHRsyH1l7e/uAfFt8817V19eXlJQM
+TlY8uJxCocyaNSs9Pf3vf/+7kZFRWVnZH3/8oa2tLWw5vj+DkeWPw+QvEySPGC8fGVn9Q+at27Vr
+18cff+zp6dnc3CxIu4PHq6en9+uvvw4I9sPLl0e2joONdl5CfF45wfsJABmIEwOR5R0jK++fb0tJ
+Sal/vi2+ea+SkpJWrlw5+Muu+Zbr6OjcuXPH2Nh45syZU6ZMKS0tnTFjxjDKMf0ZjCx/HCZ/GSaP
+2OB8ZGT1D5m3TkRE5OTJk5KSkl5eXsT84/OXDR6vh4fHs2fPTp48WV1d/erVq59++qmnp2d4+fLI
+1pGvUc1LiM8rJ1Q/AeBrMu47xcTE/PLLLxQKJSUlZc2aNYGBgQihLVu2EI+yzJ4928HB4bvvvouM
+jLSwsFi5ciXxKrLykpKS9evXs9lsY2Pj2NjYAVvYA3R0dGRkZPByeA1ZrqOjw+FwjIyMKBSKkZFR
+TU0NsYkhbDlfvDxojx49Ip7g4uXR27t3r7i4+KZNm4j8cRcuXCDeaI4fP37w4MHly5dbWFh89dVX
+bm5u27Zty8vLW7t2bXp6elhYGJFH7MiRI3PnziVayc/Pz8/PJ/KR8eaHrH6+5QkJCbdv3+Zyubm5
+uTY2Nq6urkePHrW1tb1z5w6mXb7mzZsXFRUVFhbm4uIiJiZGp9OJfGdk7ba2tl67dg0hVFVVRUzR
+w4cPydYLM5/W1tbnzp2Lior68cfyu8ImAAAIHElEQVQfifxoRkZGCCEinyBCyMvLq38+QV7+NeJn
+Xl5CsvOWbF3IzisAhAL57N6Jh4eHsrLy0aNHBTw+Li6urKzsu+++E7AcjE8TZb0mSj/BOAf7Tu8P
+m83+97//PfjZTbJyMD5NlPWaKP0E45/oP/7xj7Huw0QVHh6ek5NTU1Pz008/zZo1q/+dAL6am5un
+TJlCPLwvSDkYnybKek2UfoLxD/adAAAA4MC+EwAAAByIEwAAAHAgTgAAAMCBOAEAAAAH4gQAAAAc
+iBMAAABwIE4AAADAgTgBAAAAB+IEAAAAHIgTAAAAcCBOAAAAwIE4AQAAAAfiBAAAAByIEwAAAHAg
+TgAAAMCBOAEAAAAH4gQAAAAciBMAAABwIE4AAADAoY51B0bRvHnzxroLAAAwLvz222/Dfi1cTwAA
+AMCZjHEiMTFRVlZWXFxcS0tLXl7ewMDgxo0bY92pUfTpp59SKJT+Y7S0tJw6deqQL4yJiaFQKDU1
+Ne+5XQDAuDIZ44SLi8vOnTvnzJlTU1PT3NxsaGjo7Oz89u1b/KtycnIoFMqbN2/eTydHsN3AwECE
+0PXr14l/trW1/fLLL6tXrx7yhUpKSqampjQa7T23CwAYVyZjnOiPSqU6Ozu3tLTU19ePdV9G0bRp
+03jv1z///DOFQhHkVStXrrx3756amtp7bhcAMK5M9jiBEGIwGDIyMpqamgghLpebkJAwf/58DQ0N
+AwODq1evIoR+++03CQkJBwcHhJCKioqEhISsrCxC6MSJExISEuvWrSPqUVNTI3ZpvvnmGwqFQqFQ
+3N3dr169qq+vr6mpGRMTc+DAAQqF4ujomJWVZWhoqKysnJSUhOkYWbsIobdv3/7zn/+cPXu2hoaG
+nZ1dRUUFfoyWlpZPnjxpaGhACGVnZ1tYWPCa2LRpk7a2try8vLKycmhoKFGuqampoaGhoKBAoVD6
++vqIQmH7j2mX7zyT1U82z/imAQAjZVLHCS6X+/z58zNnzvj7+1OpVIRQdHR0QEBAcnLyy5cvT5w4
+8cUXX9TW1s6bN6+7uzsjIwMh1NTU1N3d3dbWhhDy8/Oztrbm1ZacnEz8sGXLllu3bhkbGz948CAo
+KMjPz8/U1PT3338/ePCgjY3N06dPz507FxkZuXTpUk9PTzabTdY9snYRQvv3709OTr5z505NTY2h
+oaGFhcVff/2FGam8vPyCBQvy8vK4XG5BQQHv/TovL09CQqK4uLi5uXnjxo0HDhzgcrkIodra2pcv
+X0ZFRfWvRNj+Y9rlO89k9ZPNMwDg/Zi8ceLp06caGhpz5swxMjLy8fFBCHG53MOHD+/du1dHRwch
+tGLFCllZ2czMTGFr1tLSsrKykpeXb2lpSU1N3bhx48aNGxUUFGRlZadMmcJkMuPi4hYuXLh+/frW
+1tbGxkZh6+/s7AwPD9+zZ4+6ujqVSvX392cymT/++CP+VTY2NtevX3/8+LGenp6EhARR6OHh8cMP
+PygpKVGp1MWLF7NYrM7OTrIahtf/we2SzfNIzQ8AYGRN3jgxZ86cV69e7d69+9atW93d3Qih5ubm
+xsbGY8eOaf0Xm81ubm4edhPLli1TVFRECDk4OAQEBBCF5ubmRKGqqipCiMViCVttVVVVb2/vRx99
+RPxTSkpKQ0Pj6dOn+FfZ2Njk5eVlZWUtX768f/mZM2cWLFigpaW1detWQVoXtv+D28XP87vPDwBg
+ZE3eOEHYu3dvc3NzfHw8QkhMTAwhdPz48Zr/am1tPXz4cP/jiW2Z969/u8Prg4mJSXd3d2hoqJ2d
+Ha/Q3d09Pj7+3LlzVVVVFy5cGIGOCtCuIPMMABg/Jnuc0NbWdnJyCgoKYrPZ8vLyOjo62dnZfI8k
+ntVpbW3tXyghIcFkMomfi4qKRqOHg9udNWuWmJhYeXk58c+Ojo6XL1/q6+vj6xETE/vss89kZWW1
+tLR4hbm5uZs2bTIxMREVFeVwOCPfe37t4ueZr/cwzwAAMpM9TiCEvv7664qKirS0NITQt99+m5qa
+evjw4RcvXlRVVUVHRxcWFhKHEY+H5ubm1tbWRkREEPv4+vr6Dx48YDKZ2dnZ//rXv0aje4PblZKS
+2rlzZ0hISGNjI5vNDgwMlJOTc3V1HbKqXbt2HTp0qH/J9OnT7927193dXVFR4evrOxr959suZp75
+eg/zDAAgQ3n06NFY92G0kH2/U0JCwq5du7q7uzds2BAXF4cQWrp06S+//EK89efk5Bw9evTx48fi
+4uJmZmZBQUHEnQAul7t169YrV67IyMh8/vnn4eHhNBrt9evXa9euffbsma2t7aZNm4gbEgcPHvz+
++++bm5tFRUUVFBQQQgUFBdra2rt27YqNjaVQKGfPnnV3dzc2Ni4tLVVRUcHfquXb7tu3b/39/a9c
+udLb22tgYBAaGqqnp0dWw6JFix4+fFhUVMSbEDU1tba2tq6ursLCwu3btzMYDH19fTs7Oz8/Py0t
+rerqak1NTTab3dXVxWQy1dXVKRSKh4dHQ0ODUP3HtMt3nkNDQ8nq5zvP73LrCIDJ5l2+32kyxgkA
+AJhs4HsAhfP69eux7gIAAEwYkzFOKCsrj3UXAABgwpiMcQIAAIDgIE4AAADA+ZDz2b3LfRsAAAAE
+uJ4AAACAA3ECAAAADsQJAAAAOBAnAAAA4ECcAAAAgANxAgAAAA7ECQAAADgQJwAAAOBAnAAAAIAD
+cQIAAAAOxAkAAAA4ECcAAADgQJwAAACAA3ECAAAADsQJAAAAOBAnAAAA4ECcAAAAgPP/AJqRiwZc
+EFGMAAAAAElFTkSuQmCC
+"
+     id="image10"
+     x="0"
+     y="0" />
+  <rect
+     style="fill:#ffff00;fill-opacity:0.16818182;stroke:#ff0000;stroke-width:2;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+     id="rect2987"
+     width="381.05719"
+     height="20.119629"
+     x="82.896263"
+     y="359.67828" />
+</svg>
diff --git a/docs/refind/automatic-submenu.png b/docs/refind/automatic-submenu.png
new file mode 100644 (file)
index 0000000..c839d50
Binary files /dev/null and b/docs/refind/automatic-submenu.png differ
diff --git a/docs/refind/bootmode.html b/docs/refind/bootmode.html
new file mode 100644 (file)
index 0000000..e596b6f
--- /dev/null
@@ -0,0 +1,275 @@
+<?xml version="1.0" encoding="utf-8" standalone="no"?>\r
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"\r
+  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">\r
+\r
+<html xmlns="http://www.w3.org/1999/xhtml">\r
+<head>\r
+  <title>The rEFInd Boot Manager: What's Your Boot Mode?</title>\r
+  <link href="../Styles/styles.css" rel="stylesheet" type="text/css" />\r
+</head>\r
+\r
+<meta name="viewport" content="width=device-width, initial-scale=1">\r
+\r
+<body>\r
+  <h1>The rEFInd Boot Manager:<br />What's Your Boot Mode?</h1>\r
+\r
+  <p class="subhead">by Roderick W. Smith, <a\r
+href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.com</a></p>\r
+\r
+<p>Originally written: 3/14/2012; last Web page update:\r
+11/8/2015, referencing rEFInd 0.10.0</p>\r
+\r
+\r
+<p>This Web page is provided free of charge and with no annoying outside ads; however, I did take time to prepare it, and Web hosting does cost money. If you find this Web page useful, please consider making a small donation to help keep this site up and running. Thanks!</p>\r
+\r
+<table border="1">\r
+<tr>\r
+<td>Donate $1.00</td>\r
+<td>Donate $2.50</td>\r
+<td>Donate $5.00</td>\r
+<td>Donate $10.00</td>\r
+<td>Donate $20.00</td>\r
+<td>Donate another value</td>\r
+</tr>\r
+<tr>\r
+\r
+<td>\r
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">\r
+<input type="hidden" name="cmd" value="_donations">\r
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">\r
+<input type="hidden" name="lc" value="US">\r
+<input type="hidden" name="no_note" value="0">\r
+<input type="hidden" name="currency_code" value="USD">\r
+<input type="hidden" name="amount" value="1.00">\r
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">\r
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">\r
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">\r
+</form>\r
+</td>\r
+\r
+<td>\r
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">\r
+<input type="hidden" name="cmd" value="_donations">\r
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">\r
+<input type="hidden" name="lc" value="US">\r
+<input type="hidden" name="no_note" value="0">\r
+<input type="hidden" name="currency_code" value="USD">\r
+<input type="hidden" name="amount" value="2.50">\r
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">\r
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">\r
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">\r
+</form>\r
+</td>\r
+\r
+\r
+<td>\r
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">\r
+<input type="hidden" name="cmd" value="_donations">\r
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">\r
+<input type="hidden" name="lc" value="US">\r
+<input type="hidden" name="no_note" value="0">\r
+<input type="hidden" name="currency_code" value="USD">\r
+<input type="hidden" name="amount" value="5.00">\r
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">\r
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">\r
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">\r
+</form>\r
+</td>\r
+\r
+<td>\r
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">\r
+<input type="hidden" name="cmd" value="_donations">\r
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">\r
+<input type="hidden" name="lc" value="US">\r
+<input type="hidden" name="no_note" value="0">\r
+<input type="hidden" name="currency_code" value="USD">\r
+<input type="hidden" name="amount" value="10.00">\r
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">\r
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">\r
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">\r
+</form>\r
+</td>\r
+\r
+<td>\r
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">\r
+<input type="hidden" name="cmd" value="_donations">\r
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">\r
+<input type="hidden" name="lc" value="US">\r
+<input type="hidden" name="no_note" value="0">\r
+<input type="hidden" name="currency_code" value="USD">\r
+<input type="hidden" name="amount" value="20.00">\r
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">\r
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">\r
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">\r
+</form>\r
+</td>\r
+\r
+<td>\r
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">\r
+<input type="hidden" name="cmd" value="_donations">\r
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">\r
+<input type="hidden" name="lc" value="US">\r
+<input type="hidden" name="no_note" value="0">\r
+<input type="hidden" name="currency_code" value="USD">\r
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">\r
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">\r
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">\r
+</form>\r
+</td></tr>\r
+</table>\r
+\r
+<hr />\r
+\r
+<p>This page is part of the documentation for the rEFInd boot manager. If a Web search has brought you here, you may want to start at the <a href="index.html">main page.</a></p>\r
+\r
+<hr />\r
+\r
+<div style="float:right; width:55%">\r
+\r
+<p>Before you invest time in downloading and trying to install rEFInd, you may want to verify that you can actually use the program at all. rEFInd is useful only on EFI-based computers, not older BIOS-based computers. In fact, most EFI-based <i>x</i>86-64 computers provide a Compatibility Support Module (CSM), which is essentially a BIOS emulation mode. Some EFI implementations are in fact built atop a conventional BIOS, and retain BIOS's boot abilities via this underlying code. Thus, it's possible that you're currently booting a modern EFI-capable computer in BIOS mode.</p>\r
+\r
+</div>\r
+\r
+<div class="navbar">\r
+\r
+<h4 class="tight">Contents</h4>\r
+\r
+<ul>\r
+\r
+<li class="tight"><a href="#identifying">Identifying Your Hardware's Capabilities</li>\r
+\r
+<li class="tight"><a href="#linux">Identifying Your Linux Boot Mode</a></li>\r
+\r
+<li class="tight"><a href="#windows">Identifying Your Windows Boot Mode</a></li>\r
+\r
+</ul>\r
+\r
+</div>\r
+\r
+<p>Unfortunately, determining which mode you're using can be tricky; the clues are subtle or hidden in ways that require specialized knowledge to extract. This page will help you figure it out. I first present general information on identifying your hardware's capabilities. I then describe ways to identify your current boot mode in both Linux and Windows.</p>\r
+\r
+<a name="identifying">\r
+<h2>Identifying Your Hardware's Capabilities</h2>\r
+</a>\r
+\r
+<p>Let's get the easy case out of the way: If you have a Macintosh with an Intel CPU, it's got EFI capabilities, and you'll be able to use rEFInd. Earlier Macs with PowerPC CPUs use OpenFirmware, and rEFInd can't be used with them. If your computer shipped new with Windows 8 or later, it almost certainly supports EFI; Microsoft requires that computers that bear a Windows 8 logo support EFI, and boot in EFI mode.</p>\r
+\r
+<p>For everything else, it can be harder to tell. Your best bet is to locate a PDF version of your computer's or motherboard's manual and search it for the string <i>EFI</i>. Checking your firmware's options via the firmware setup utility (typically access by pressing Del, F2, F10, or F12 at boot time) is also worth doing, but you'll need to check every option yourself. Most EFI-enabled PCs include at least one reference to an option you can set; however, manuals and firmware setup tools often don't make a big deal of this feature, particularly on boards with relatively primitive EFI support. For instance, the manual for a Gigabyte GA-78LMT-S2P motherboard includes the following paragraph, on p. 28:</p>\r
+\r
+<div class="quote">\r
+<ul>\r
+<li><b>EFI CD/DVD Boot Option</b><br/>Set this item to <b>EFI</b> if you want to install the operating system to a hard drive larger than 2.2 TB. Make sure the operating system to be installed supports booting from a GPT partition, such as Windows 7 64-bit and Windows Server 2003 64-bit. <b>Auto</b> lets the BIOS automatically configure this setting depending on the hard drive you install. (Default: Auto)</li>\r
+</ul>\r
+</div>\r
+\r
+<p>A casual reader might easily overlook this option, or misinterpret it to mean that the feature is much less important than it is. In fact, this particular motherboard offers very poor control over its EFI vs. BIOS booting features. (See <a href="http://www.rodsbooks.com/gb-hybrid-efi/">my Web page on this EFI implementation</a> for details.)</p>\r
+\r
+<p>Some manuals omit even mention of EFI, and instead refer to "legacy boot" or some similar term, referring to BIOS-style booting. The firmware for my ASUS P8H77-I motherboard uses the technical term <i>CSM,</i> which of course will be baffling to the uninitiated. (I referred to it earlier. It's the <i>Compatibility Support Module</i>&mdash;in other words, the BIOS support code.) Such references may imply that the firmware supports EFI booting if the "legacy boot" mode is disabled or restricted in some way.</p>\r
+\r
+<p>Understated EFI features often indicate a slapdash approach to EFI. Such systems sometimes implement EFI as a layer atop a conventional BIOS. More modern EFIs, though, completely replace the BIOS. Some manufacturers, such as ASUS and its sibling ASRock, are now actively promoting their more advanced EFI implementations. Such products often come with flashy new GUIs in their firmware.</p>\r
+\r
+<p>Positive identification of EFI support in your firmware does <i>not</i> guarantee that your current OSes are booting in EFI mode. (Mac OS X booting on a Mac is an exception to this rule, though.) For that, you'll need to run some tests in your running OSes.</p>\r
+\r
+<a name="linux">\r
+<h2>Identifying Your Linux Boot Mode</h2>\r
+</a>\r
+\r
+<p>Identifying your boot mode in Linux is relatively straightforward. The simplest way is to check for the presence of a <tt>/sys/firmware/efi</tt> directory. The mere existence of this directory indicates that the computer has booted in EFI mode. Its absence suggests a BIOS-mode boot&mdash;but see below for an important caveat.</p>\r
+\r
+<p>Another test, which produces more detailed information about the EFI implementation, is to check the kernel ring buffer for references to EFI. You can do this as follows:</p>\r
+\r
+<ol>\r
+\r
+<li>Launch a terminal program in GUI mode, or log in using text mode.</li>\r
+\r
+<li>Type <b><tt>dmesg | grep -i EFI</tt></b>.\r
+\r
+</ol>\r
+\r
+<p>The result on a BIOS-based computer should be few or no lines of output. On an EFI-based computer, though, the output will be extensive:</p>\r
+\r
+<pre class="listing">\r
+[    0.000000] efi: EFI v2.31 by INSYDE Corp.\r
+[    0.000000] efi:  ACPI=0x9cffe000  ACPI 2.0=0x9cffe014  SMBIOS=0x9cebef98 \r
+[    0.000000] efi: mem00: type=3, attr=0xf, range=[0x0000000000000000-0x0000000000001000) (0MB)\r
+[    0.000000] efi: mem01: type=2, attr=0xf, range=[0x0000000000001000-0x0000000000008000) (0MB)\r
+...\r
+[    0.000000] efi: mem62: type=11, attr=0x8000000000000001, range=[0x00000000ff980000-0x0000000100000000) (6MB)\r
+[    0.000000] ACPI: UEFI 000000009cffc000 00236 (v01 LENOVO CB-01    00000001 ACPI 00040000)\r
+[    0.632723] efifb: probing for efifb\r
+[    0.634127] efifb: framebuffer at 0xa0000000, mapped to 0xffffc90021780000, using 8100k, total 8100k\r
+[    0.634129] efifb: mode is 1920x1080x32, linelength=7680, pages=1\r
+[    0.634130] efifb: scrolling: redraw\r
+[    0.634132] efifb: Truecolor: size=8:8:8:8, shift=24:16:8:0\r
+[    0.644648] fb0: EFI VGA frame buffer device\r
+[    0.754748] EFI Variables Facility v0.08 2004-May-17\r
+[    1.305636] fb: conflicting fb hw usage inteldrmfb vs EFI VGA - removing generic driver\r
+</pre>\r
+\r
+<p>I've actually cut quite a few lines from this output; there are a total of 62 <tt>EFI: mem<i>##</i></tt> lines on this computer. (Another of my computers has 148 such lines!) A BIOS-based computer will lack most or all of these lines, and certainly the <tt>EFI: mem<i>##</i></tt> lines. I've heard of some BIOS-based computers that produce the <tt>EFI Variables Facility</tt> line, though.</p>\r
+\r
+<p>One caveat exists to these tests: It's possible to boot Linux in EFI mode but disable the EFI features that create the <tt>/sys/firmware/efi</tt> directory and the copious EFI output in <tt>dmesg</tt>. This can happen because your kernel was compiled without EFI support or because you've added the <tt>noefi</tt> line to your existing BIOS boot loader configuration. Some of these features will also be absent if the <tt>efivars</tt> driver is not built into the kernel and is not loaded as a module. Typing <tt class="userinput">modprobe efivars</tt> should load this module, so you might try that before concluding you've booted in BIOS mode. To the best of my knowledge, no major Linux distribution ships with EFI support disabled in any of these ways, so chances are your tests won't mislead you to thinking you're using BIOS mode unless you've recompiled your kernel or deliberately added a <tt>noefi</tt> parameter to your boot loader configuration.</p>\r
+\r
+<a name="windows">\r
+<h2>Identifying Your Windows Boot Mode</h2>\r
+</a>\r
+\r
+<!-- NOTE: I have serious doubts about this method's reliability, so I'm commenting it out for now....\r
+\r
+<p>The easiest way to determine your boot mode in Windows is probably to use the <tt>bcdedit</tt> program to examine your boot loader configuration. To do so, launch an administrative Command Prompt (by right-clicking a Command Prompt icon and selecting Run As Administrator from the context menu) and then type <tt class="userinput">bcdedit</tt> in the window. The result will include two blocks of information, on the boot manager and the boot loader. The latter is more diagnostic. On an EFI-booted system, it will resemble the following:</p>\r
+\r
+<pre class="listing">Windows Boot Loader\r
+-------------------\r
+identifier              {current}\r
+device                  partition=C:\r
+path                    \Windows\system32\winload.efi\r
+description             Windows 7 Home Premium (recovered)\r
+locale                  en-US\r
+recoverysequence        {2844aaae-9978-11e0-a381-afc0564c0e08}\r
+recoveryenabled         Yes\r
+osdevice                partition=C:\r
+systemroot              \Windows\r
+resumeobject            {3aa4c728-9935-11e0-9f12-806e6f6e6963}</pre>\r
+\r
+<p>The important part is the value of the <tt>path</tt> line. Note that it identifies an EFI executable&mdash;<tt>\Windows\system32\winload.efi</tt>. On a BIOS-based computer, by contrast, this line refers to <tt>\Windows\system32\winload.exe</tt>&mdash;a standard Windows <tt>.exe</tt> file, not an EFI <tt>.efi</tt> file.</p>\r
+-->\r
+\r
+<p>The most reliable way I know of to identify your boot mode is to examine your partitions. Microsoft has tied use of the GUID Partition Table (GPT) to EFI booting. If you've booted from a GPT disk, then you <i>must</i> be using EFI, and if you've booted from a Master Boot Record (MBR) disk, you <i>must</i> have booted in BIOS mode. Therefore, you can check your partition table type as a proxy for your boot mode. To do this in Windows 7, follow these steps:</p>\r
+\r
+<ol>\r
+\r
+<li>Open the Control Panel.</li>\r
+\r
+<li>Click System and Security.</li>\r
+\r
+<li>Click Create and Format Hard Disk Partitions under Administrative Tools. The Disk Management window should open.</li>\r
+\r
+<li>Right-click on Disk 0 on the left side of the bottom pane of the window. A context menu should appear.</li>\r
+\r
+<li>Click Properties in the context menu. A Properties dialog box should open.</li>\r
+\r
+<li>Select the Volumes tab. The result should resemble the below figure. The Partition Style item identifies the partition table type&mdash;GPT in this example.</li>\r
+\r
+</ol>\r
+\r
+    <br /><img src="windows-gpt.png" align="center" width="414"\r
+    height="461" alt="Under Windows, you can use the disk's partition table\r
+    type to determine your boot mode." border=2> <br />\r
+\r
+<p>An important caveat with this method is that you must examine your boot disk. It's possible to use GPT on a data disk even on a BIOS-based computer, or to use an MBR data disk even on an EFI-based computer. Thus, if you examine the wrong disk, you can be led to an incorrect conclusion about your computer's boot mode.</p>\r
+\r
+<hr />\r
+\r
+<p>copyright &copy; 2012&ndash;2015 by Roderick W. Smith</p>\r
+\r
+<p>This document is licensed under the terms of the <a href="FDL-1.3.txt">GNU Free Documentation License (FDL), version 1.3.</a></p>\r
+\r
+<p>If you have problems with or comments about this Web page, please e-mail me at <a href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.com.</a> Thanks.</p>\r
+\r
+<p><a href="index.html">Go to the main rEFInd page</a></p>\r
+\r
+<p><a href="using.html">Learn how to use rEFInd</a></p>\r
+\r
+  <p><a href="http://www.rodsbooks.com/">Return</a> to my main Web page.</p>\r
+</body>\r
+</html>\r
diff --git a/docs/refind/configfile.html b/docs/refind/configfile.html
new file mode 100644 (file)
index 0000000..9ec8cb5
--- /dev/null
@@ -0,0 +1,664 @@
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>The rEFInd Boot Manager: Configuring the Boot Manager</title>
+  <link href="../Styles/styles.css" rel="stylesheet" type="text/css" />
+</head>
+
+<meta name="viewport" content="width=device-width, initial-scale=1">
+
+<body>
+  <h1>The rEFInd Boot Manager:<br />Configuring the Boot Manager</h1>
+
+  <p class="subhead">by Roderick W. Smith, <a
+href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.com</a></p>
+
+<p>Originally written: 3/14/2012; last Web page update:
+11/8/2015, referencing rEFInd 0.10.0</p>
+
+
+<p>This Web page is provided free of charge and with no annoying outside ads; however, I did take time to prepare it, and Web hosting does cost money. If you find this Web page useful, please consider making a small donation to help keep this site up and running. Thanks!</p>
+
+<table border="1">
+<tr>
+<td>Donate $1.00</td>
+<td>Donate $2.50</td>
+<td>Donate $5.00</td>
+<td>Donate $10.00</td>
+<td>Donate $20.00</td>
+<td>Donate another value</td>
+</tr>
+<tr>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="1.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="2.50">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="5.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="10.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="20.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td></tr>
+</table>
+
+<hr />
+
+<p>This page is part of the documentation for the rEFInd boot manager. If a Web search has brought you here, you may want to start at the <a href="index.html">main page.</a></p>
+
+<hr />
+
+<div style="float:right; width:55%">
+
+<p>Many casual users will be able to use rEFInd without making changes to its settings; in its default configuration, the boot manager automatically detects all the EFI boot loader programs you have on your EFI System Partition (ESP) (or your OS X boot partition, in the case of Macs) in conventional locations and displays icons for them. On Macs, rEFInd also presents legacy BIOS boot options by default. Sometimes, though, you may want to tweak rEFInd's configuration. Sometimes you can obtain your desired results by adjusting the filenames of your boot loaders. Other times, you can edit rEFInd's configuration file, <tt>refind.conf</tt>, which resides in the same directory as its binary file (<tt>refind_x64.efi</tt> or whatever you've renamed it).</p>
+
+</div>
+
+<div class="navbar">
+
+<h4 class="tight">Contents</h4>
+
+<ul>
+
+<li class="tight"><a href="#hiding">Hiding and Displaying EFI Boot Loaders</li>
+
+<li class="tight"><a href="#icons">Setting OS Icons</li>
+
+<li class="tight"><a href="#adjusting">Adjusting the Global Configuration</a></li>
+
+<li class="tight"><a href="#stanzas">Creating Manual Boot Stanzas</a></li>
+
+<li class="tight"><a href="#submenu">Creating Submenu Entries</a></li>
+
+<li class="tight"><a href="#default">Adjusting the Default Boot Option</a></li>
+
+</ul>
+
+</div>
+
+<p>Broadly speaking, rEFInd's configuration file is broken down into two sections: <i>global options</i> and <i>OS stanzas.</i> The global options section sets options that apply globally&mdash;to set the timeout period, enable graphics or text mode, and so on. OS stanzas are optional, but if present, they enable you to add new boot options or replace the auto-detected options with customized ones. Both sections include configuration lines and comment lines, the latter being denoted by a leading hash mark (<tt>#</tt>). rEFInd ignores comment lines, so you can add explanatory text. The default configuration file includes numerous comments explaining each of the options.</p>
+
+<a name="hiding">
+<h2>Hiding and Displaying EFI Boot Loaders</h2>
+</a>
+
+<p class="sidebar">ESPs use the FAT filesystem, which is case-insensitive. Unfortunately, at least one EFI implementation (Gigabyte's <a href="http://www.rodsbooks.com/gb-hybrid-efi/">Hybrid EFI</a>) contains a bug that causes string comparisons that should be case-insensitive to actually be done in a case-sensitive way. This can cause files that are present to appear to be missing. rEFInd includes code to work around this bug in some situations, but not in all of them. If boot loaders appear to be missing, try changing the case on their filenames or on the <tt>EFI</tt> directory in the ESP. (It's coded as uppercase in rEFInd; but EFI loader filename extensions are coded as lowercase <tt>.efi</tt>. I made these choices because they seem to be the most common uses on real-world installations.)</p>
+
+<p>Before delving into the configuration file, you should be aware of what you can do by renaming files. By default, rEFInd scans all the filesystems it can read for boot loaders. It scans most of the subdirectories of the <tt>EFI</tt> directory on every filesystem it can access for files with names that end in <tt>.efi</tt>. (rEFInd gives special treatment to the <tt>tools</tt> subdirectory, where it looks for system tools rather than boot loaders.)</p>
+
+<p>If you're like me, you may sometimes want to hide a boot loader from rEFInd's menu for a brief period&mdash;say, because you're testing a variety of configurations but you don't want them all to clutter the menu at once. You might also want to hide a boot loader if you want to override its default settings using a custom entry in <tt>refind.conf</tt> and you don't want an automatic search to duplicate that entry. You can easily hide a boot loader by removing or changing its <tt>.efi</tt> filename extension&mdash;for instance, changing <tt>grub.efi</tt> to <tt>grub</tt>.</p>
+
+<p>Another way to hide a boot loader is to move it into rEFInd's own directory. In order to keep rEFInd from showing up in its own menu, it ignores boot loaders in its own directory. This obviously includes the rEFInd binary file itself, but also anything else you might store there.</p>
+
+<p>You can also use the <tt>dont_scan_volumes</tt>, <tt>dont_scan_dirs</tt>, and <tt>dont_scan_files</tt> tokens in <tt>refind.conf</tt> to hide entire volumes, directories, and individual files, respectively. Note that <tt>dont_scan_volumes</tt> works with both EFI and legacy scans, whereas the other two options make sense for hiding only EFI-mode boot loaders.</p>
+
+<a name="icons">
+<h2>Setting OS Icons</h2>
+</a>
+
+<p>In addition to hiding boot loaders, you can adjust their icons. You can do this in any of seven ways for auto-detected boot loaders:</p>
+
+<ul>
+
+<li>You can name an icon file after your boot loader, but with an extension of <tt>.icns</tt> or <tt>.png</tt> for ICNS-format and PNG-format icons, respectively. For instance, if you're using <tt class="variable">loader</tt><tt>.efi</tt>, you would name the icon file <tt class="variable">loader</tt><tt>.icns</tt>. (If you use the <tt>scan_all_linux_kernels</tt> option, you can give an icon for a Linux kernel without a <tt>.efi</tt> extension a name based on the kernel name but with a <tt>.icns</tt> or <tt>.png</tt> extension&mdash;for instance, <tt>bzImage-3.13.6.png</tt> will serve as the icon for the <tt>bzImage-3.13.6</tt> kernel.) These icon files should be in <a href="http://en.wikipedia.org/wiki/Apple_Icon_Image_format">Apple's ICNS</a> or <a href="http://en.wikipedia.org/wiki/Portable_Network_Graphics">Portable Network Graphics (PNG)</a> format, depending on the filename extension.</li>
+
+<li>If you're booting OS X from its standard boot loader, or if you place a boot loader file for any OS in the root directory of a partition, you can create a file called <tt>.VolumeIcon.icns</tt> or <tt>.VolumeIcon.png</tt> that holds an icon file. OS X uses the <tt>.VolumeIcon.icns</tt> file for its volume icons, so rEFInd picks up these icons automatically, provided they include appropriate bitmaps.</li>
+
+<li>You can place a boot loader in a directory with a name that matches one of rEFInd's standard icons, which take names of the form <tt>os_<tt class="variable">name</tt>.icns</tt> or <tt>os_<tt class="variable">name</tt>.png</tt>. To use such an icon, you would place the boot loader in the directory called <tt class="variable">name</tt>.</li>
+
+<li>You can give the filesystem from which the boot loader is loaded a name that matches the OS name component of the icon filename. For instance, if you call your boot filesystem <tt>CentOS</tt>, it matches the <tt>os_centos.icns</tt> icon. This match is performed on a word-by-word basis within the name, with "words" being delimited by spaces, dashes (<tt>-</tt>), and underscores (<tt>_</tt>). Thus, a volume called <tt>Debian-boot</tt> will match <tt>os_debian.icns</tt> or <tt>os_boot.icns</tt>.</li>
+
+<li>You can give the GPT partition from which the boot loader is loaded a name that matches the OS name component of the icon filename. This works much like the previous method, except that you'd use a tool like <tt>gdisk</tt> or <tt>parted</tt> to set the partition's name, rather than <tt>tune2fs</tt> or GParted to set the filesystem's name.</li>
+
+<li>rEFInd attempts to guess the Linux distribution based on data in the <tt>/etc/os-release</tt> file. This file will only be accessible if a separate <tt>/boot</tt> partition is <i>not</i> used, though. Manually adjusting the <tt>os-release</tt> file to change an OS icon in rEFInd is <i>not</i> recommended.</li>
+
+<li>Certain boot loaders have hard-coded icons associated with them. For instance, filenames beginning with <tt>vmlinuz</tt> or <tt>bzImage</tt> acquire Linux "Tux" icon and the <tt>bootmgfw.efi</tt> loader acquires a Windows icon. Fedora and Red Hat kernels can be identified by the presence of <tt>.fc</tt> or <tt>.el</tt> strings in their filenames, and so acquire suitable icons automatically. For the most part, these are the associations you want to overcome with the preceding rules, but sometimes renaming a boot loader to a more conventional name is the better approach. Renaming a locally-compiled kernel so that it acquires a Fedora or Red Hat icon is reasonable, but I don't recommend renaming precompiled kernels unless you also manually copy them to the ESP.</li>
+
+</ul>
+
+<p>As a special case, rEFInd assigns icons to the Windows and OS X boot loaders based on their conventional locations, so they get suitable icons even if they don't follow these rules.</p>
+
+<p>In addition to the main OS tag icon, you can set the <i>badge</i> icon for a volume by creating a file called <tt>.VolumeBadge.icns</tt> or <tt>.VolumeBadge.png</tt> in the root directory of a partition. If present, it replaces the disk-type icons that are overlaid on the main OS icon. If you use this feature, the badge is applied to all the boot loaders read from the disk, not just those stored in the root directory or the Apple boot loader location. You could use this feature to set a custom badge for different specific disks or to help differentiate multiple OS X installations on one computer. If you don't want any badges, you can add the <tt>badges</tt> option to <tt>hideui</tt> in <tt>refind.conf</tt>. Alternatively, or to hide just certain types of badges, you can replace the four badge icons in the rEFInd <tt>icons</tt> subdirectory (<tt>vol_external.png</tt>, <tt>vol_internal.png</tt>, <tt>vol_optical.png</tt>, and <tt>vol_net.png</tt>) with a completely transparent badge. The <tt>transparent.png</tt> file in the rEFInd <tt>icons</tt> directory may be used for this purpose.</p>
+
+<p>The default icon sizes are 128x128 pixels for OS icons, 48x48 pixels for the second-row tools, and 32x32 pixels for badges. You can change the sizes of the big OS icons and the small tool icons with the <tt>big_icon_size</tt> and <tt>small_icon_size</tt> tokens in <tt>refind.conf</tt>, as noted in <a href="#table1">Table 1.</a> The size of the disk-type badges is 1/4 the size of OS icons.</p>
+
+<a name="adjusting">
+<h2>Adjusting the Global Configuration</h2>
+</a>
+
+<p class="sidebar">You can tell rEFInd to use any configuration filename by passing <tt>-c <tt class="variable">filename</tt></tt> as an option, as in <tt>refind_x64.efi -c myrefind.conf</tt> to use <tt>myrefind.conf</tt> in rEFInd's main directory. You can specify a configuration file in another directory, but to do so, you <i>must</i> use backslashes as directory separators, as in <tt>-c \EFI\other\refind.conf</tt>. This feature is intended for users who want to have rEFInd appear in its own menu, with the version launched in this way behaving differently from the original&mdash;for instance, to have a secondary rEFInd that provides boot options hidden by the main one. In this scenario, the default <tt>refind.conf</tt> would have a <a href="#stanzas">manual boot stanza</a> defining the new rEFInd instance, including its <tt>-c</tt> option.</p>
+
+<p>You can adjust many of rEFInd's options by editing its configuration file, which is called <tt>refind.conf</tt>. You must first find this file, though. It is located in the rEFInd directory. On a UEFI-based PC, this directory will be located on the <a href="http://en.wikipedia.org/wiki/EFI_System_partition">EFI System Partition (ESP),</a> which can be in any number of places:</p>
+
+<ul>
+
+<li>Under Linux, the ESP is usually mounted at <tt>/boot/efi</tt>, although some users, particularly in Arch and Gentoo, prefer to mount the ESP at <tt>/boot</tt>.</li>
+
+<li>Under OS X, the ESP is not mounted by default, so you must mount it yourself to access it. Since 0.9.3, rEFInd has provided a script called <tt>mountesp</tt>, which locates and mounts the ESP. Open a Terminal and type <tt class="userinput">sudo mountesp</tt> to mount the ESP. The program should tell you where it's mounted the ESP. It will remain mounted until you manually unmount it or until you reboot.</li>
+
+<li>Under Windows, the ESP is not mounted by default. You can do so manually by opening an Administrator Command Prompt window and typing <tt class="userinput">mountvol S: /S</tt> to mount it at <tt>S:</tt>. (You can change the drive letter if you like.) Note that you will be able to access the ESP only from this Administrator Command Prompt window.</li>
+
+</ul>
+
+<p>As a further twist, on Macs rEFInd can exist on its own partition or on the main OS X partition, depending on the version of rEFInd you've installed and the options you passed to the installation script. rEFInd has installed to the ESP by default since version 0.8.4. rEFInd typically lives on the ESP in the <tt>EFI/refind</tt> directory, or sometimes in <tt>EFI/BOOT</tt> or elsewhere. Thus, the rEFInd configuration file might be <tt>/boot/efi/EFI/refind/refind.conf</tt>, <tt>/boot/EFI/BOOT/refind.conf</tt>, <tt>/Volumes/ESP/EFI/refind/refind.conf</tt>, <tt>S:\EFI\refind\refind.conf</tt>, or something else, depending on your OS and mount point.</p>
+
+<p>You can use any text editor you like to edit <tt>refind.conf</tt>, but be sure it saves the file in plain ASCII text, not in a word processing format. (In theory, a UTF-16 encoding should also work, but this has been poorly tested.) Note that the EFI shell includes its own editor. If you need to make a change before you launch an OS, you can launch a shell, change to the rEFInd directory, and type <b><tt>edit refind.conf</tt></b> to edit the file. This EFI editor is quite primitive, but it gets the job done. After editing, you'll need to reboot or re-launch rEFInd for rEFInd to read the changed configuration file.</p>
+
+<p>Global configuration file options consist of a name token followed by one or more parameters, as in:</p>
+
+<pre class="listing">
+timeout 20
+</pre>
+
+<p>This example's name token is <tt>timeout</tt> and its parameter is <tt>20</tt>. The net effect of this line is to set the timeout period to 20 seconds&mdash;rEFInd will wait 20 seconds before launching the default boot loader. Some options can take multiple parameters. These may be separated by commas, spaces, or tabs. The global options are summarized in the Table 1.</p>
+
+<table border="1" cellpadding="1" cellspacing="2" summary="Table 1: Global options in <tt>refind.conf</tt>"><a name="table1"><caption><b>Table 1: Global options in <tt>refind.conf</tt></b></caption></a>
+<tr>
+   <th>Token</th>
+   <th>Possible parameters</th>
+   <th>Explanation</th>
+</tr>
+<tr>
+   <td><tt>timeout</tt></td>
+   <td>numeric value</td>
+   <td>Sets the timeout period in seconds. If <tt>0</tt>, the timeout is disabled&mdash;rEFInd waits indefinitely for user input. If <tt>-1</tt>, rEFInd will normally boot immediately to the default selection; however, if a shortcut key (for instance, <tt>W</tt> for Windows) is pressed, that system will boot instead. If any other key is pressed, the menu will show with no timeout.</td>
+</tr>
+<tr>
+   <td><tt>screensaver</tt></td>
+   <td>numeric value</td>
+   <td>Sets the number of seconds of inactivity before the screen blanks to prevent burn-in. The display returns after most keypresses (unfortunately, not including modifiers such as Shift, Control, Alt, or Option). The default is <tt>0</tt>, which disables this feature. Setting this token to <tt>-1</tt> causes a blank display until the <tt>timeout</tt> value passes or you press a key.</td>
+</tr>
+<tr>
+   <td><tt>hideui</tt></td>
+   <td><tt>banner</tt>, <tt>label</tt>, <tt>singleuser</tt>, <tt>safemode</tt>, <tt>hwtest</tt>, <tt>arrows</tt>, <tt>hints</tt>, <tt>editor</tt>, <tt>badges</tt>, or <tt>all</tt></td>
+   <td>Removes the specified user interface features. <tt>banner</tt> removes the banner graphic or background image, <tt>label</tt> removes the text description of each tag and the countdown timer, <tt>singleuser</tt> removes the single-user option from the OS X sub-menu, <tt>safemode</tt> removes the option to boot to safe mode from the OS X sub-menu, <tt>hwtest</tt> removes the Macintosh hardware test option, <tt>arrows</tt> removes the arrows to the right or left of the OS tags when rEFInd finds too many OSes to display simultaneously, <tt>hints</tt> removes the brief description of what basic keypresses do, <tt>editor</tt> disables the options editor, <tt>badges</tt> removes the device-type badges from the OS tags, and <tt>all</tt> removes all of these features. You can specify multiple parameters with this option. The default is to set none of these values.</td>
+</tr>
+<tr>
+   <td><tt>icons_dir</tt></td>
+   <td>directory name</td>
+   <td>Specifies a directory in which custom icons may be found. This directory should contain files with the same names as the files in the standard <tt>icons</tt> directory. The directory name is specified relative to the directory in which the rEFInd binary resides. The standard <tt>icons</tt> directory is searched if an icon can't be found in the one specified by <tt>icons_dir</tt>, so you can use this location to redefine just some icons. Note that if no icons directory is found (either <tt>icons</tt> or one specified by <tt>icons_dir</tt>), rEFInd switches to text-only mode, as if <tt>textonly</tt> had been specified.</td>
+</tr>
+<tr>
+   <td><tt>banner</tt></td>
+   <td>filename</td>
+   <td>Specifies a custom banner file to replace the rEFInd banner image. The file should be a BMP or PNG image with a color depth of 24, 8, 4, or 1 bits. The file path is relative to the directory where the rEFInd binary is stored.</td>
+</tr>
+<tr>
+   <td><tt>banner_scale</tt></td>
+   <td><tt>noscale</tt> or <tt>fillscreen</tt></td>
+   <td>Tells rEFInd whether to display banner images pixel-for-pixel (<tt>noscale</tt>) or to scale banner images to fill the screen (<tt>fillscreen</tt>). The former is the default.</td>
+</tr>
+<tr>
+   <td><tt>big_icon_size</tt></td>
+   <td>numeric value (at least <tt>32</tt>)</td>
+   <td>Sets the size of big icons (those used for OSes on the first row). All icons are square, so only one value is specified. If icon files don't contain images of the specified size, the available images are scaled to this size. The disk-type badge size is set indirectly by this token; badges are 1/4 the size of big icons. The default value is <tt>128<tt>.</td>
+</tr>
+<tr>
+   <td><tt>small_icon_size</tt></td>
+   <td>numeric value (at least <tt>32</tt>)</td>
+   <td>Sets the size of small icons (those used for tools on the second row). All icons are square, so only one value is specified. If icon files don't contain images of the specified size, the available images are scaled to this size. The default value is <tt>128<tt>.</td>
+</tr>
+<tr>
+   <td><tt>selection_big</tt></td>
+   <td>filename</td>
+   <td>Specifies a graphics file that can be used to highlight the OS selection icons. This should be a 144x144 image in BMP format, stored in rEFInd's main directory.</td>
+</tr>
+<tr>
+   <td><tt>selection_small</tt></td>
+   <td>filename</td>
+   <td>Like <tt>selection_big</tt>, this sets an alternate highlight graphic, but for the smaller utility tags on the second row. This should be a 64x64 image in BMP format, stored in rEFInd's main directory.</td>
+</tr>
+<tr>
+   <td><tt>showtools</tt></td>
+   <td><tt>shell</tt>, <tt>memtest</tt>, <tt>gdisk</tt>, <tt>gptsync</tt>, <tt>apple_recovery</tt>, <tt>csr_rotate</tt>, <tt>mok_tool</tt>, <tt>netboot</tt>, <tt>about</tt>, <tt>exit</tt>, <tt>shutdown</tt>, <tt>reboot</tt>, and <tt>firmware</tt></td>
+   <td>Specifies which tool tags to display on the second row. <tt>shell</tt> launches an EFI shell, <tt>memtest</tt> (or <tt>memtest86</tt>) launches the <a href="http://www.memtest86.com/download.htm">Memtest86</a> program, <tt>gdisk</tt> launches the partitioning tool of the same name, <tt>gptsync</tt> launches a tool that creates a hybrid MBR, <tt>apple_recovery</tt> boots the OS X Recovery HD, <tt>csr_rotate</tt> rotates through System Integrity Protection (SIP) values specified by <tt>csr_values</tt>, <tt>windows_recovery</tt> boots a Windows recovery tool, <tt>mok_tool</tt> launches a tool to manage Machine Owner Keys (MOKs) on systems with Secure Boot active, <tt>netboot</tt> launches the network boot tool (iPXE), <tt>about</tt> displays information about rEFInd, <tt>exit</tt> terminates rEFInd, <tt>shutdown</tt> shuts down the computer (or reboots it, on some UEFI PCs), <tt>reboot</tt> reboots the computer, and <tt>firmware</tt> reboots the computer into the computer's own setup utility. The tags appear in the order in which you specify them. The default is <tt>shell, memtest, gdisk, apple_recovery, mok_tool, about, shutdown, reboot, firmware</tt>. Note that the <tt>shell</tt>, <tt>memtest</tt>, <tt>apple_recovery</tt>, and <tt>mok_tool</tt> options all require the presence of programs not included with rEFInd. The <tt>gptsync</tt> option requires use of a like-named program which, although it ships with rEFInd 0.6.9 and later, is not installed by default except under OS X. See the <a href="installing.html#addons">"Installing Additional Components"</a> section of the <a href="installing.html">Installing rEFInd</a> page for pointers to the shell, Memtest86, and <tt>gptsync</tt> programs. The <tt>apple_recovery</tt> option will appear only if you've got an Apple Recovery HD partition (which has a boot loader called <tt>com.apple.recovery.boot/boot.efi</tt>). The <tt>firmware</tt> option works only on computers that support this option; on other computers, the option is quietly ignored. See the <a href="secureboot.html">Secure Boot</a> page for information on Secure Boot and MOK management.</td>
+</tr>
+<tr>
+   <td><tt>font</tt></td>
+   <td>font (PNG) filename</td>
+   <td>You can change the font that rEFInd uses in graphics mode by specifying the font file with this token. The font file should exist in rEFInd's main directory and must be a PNG-format graphics file holding glyphs for all the characters between ASCII 32 (space) through 126 (tilde, <tt>~</tt>), plus a glyph used for all characters outside of this range. See the <a href="themes.html">Theming rEFInd</a> page for more details.</td>
+</tr>
+<tr>
+   <td><tt>textonly</tt></td>
+   <td>none or one of <tt>true</tt>, <tt>on</tt>, <tt>1</tt>, <tt>false</tt>, <tt>off</tt>, or <tt>0</tt></td>
+   <td>rEFInd defaults to a graphical mode; however, if you prefer to do without the flashy graphics, you can run it in text mode by including this option (alone or with <tt>true</tt>, <tt>on</tt>, or <tt>1</tt>). Passing <tt>false</tt>, <tt>off</tt>, or <tt>0</tt> causes graphics mode to be used. (This could be useful if you want to override a text-mode setting in an included secondary configuration file.) Text-only mode is implicitly set if rEFInd cannot find either a subdirectory called <tt>icons</tt> or a subdirectory named by <tt>icons_dir</tt>.</td>
+</tr>
+<tr>
+   <td><tt>textmode</tt></td>
+   <td>text mode number</td>
+   <td>Sets the text-mode video resolution to be used in conjunction with <tt>textonly</tt> or for the line editor and program-launch screens. This option takes a single-digit code. Mode <tt>0</tt> is guaranteed to be present and should be 80x25. Mode <tt>1</tt> is supposed to be either invalid or 80x50, but some systems use this number for something else. Higher values are system-specific. Mode <tt>1024</tt> is a rEFInd-specific code that means to <i>not</i> set any mode at all; rEFInd instead uses whatever mode was set when it launched. If you set this option to an invalid value, rEFInd pauses during startup to tell you of that fact. Note that setting <tt>textmode</tt> can sometimes force your graphics-mode resolution to a higher value than you specify in <tt>resolution</tt>. On Linux, the <tt>/sys/class/graphics/fb0/modes</tt> file holds available modes, but it may not be the same set of modes that EFI provides.</td>
+</tr>
+<tr>
+   <td><tt>resolution</tt></td>
+   <td>one or two integer values</td>
+   <td>Sets the video resolution used by rEFInd; takes <i>either</i> a width and a height <i>or</i> a single UEFI video mode number as options. For instance, <tt>resolution 1024 768</tt> sets the resolution to 1024x768. On UEFI systems, <tt>resolution 1</tt> sets video mode 1, the resolution of which varies from system to system. If you set a resolution that doesn't work on a UEFI-based system, rEFInd displays a message along with a list of valid modes. On an system built around EFI 1.<i>x</i> (such as a Mac), setting an incorrect resolution fails silently; you'll get the system's default resolution. You'll also get the system's default resolution if you set both resolution values to <tt>0</tt> or if you pass anything but two numbers. (Note that passing a resolution with an <tt>x</tt>, as in <tt>1024x768</tt>, will be interpreted as <i>one</i> option and so will cause the default resolution to be used.) If you get a higher resolution than you request, try commenting out or changing the <tt>textmode</tt> value, since it can force the system to use a higher graphics resolution than you specify with <tt>resolution</tt>. Also, be aware that it is possible to set a valid resolution for your video card that's invalid for your monitor. If you do this, your monitor will go blank until you've booted an OS that resets the video mode.</td>
+</tr>
+<tr>
+   <td><tt>use_graphics_for</tt></td>
+   <td><tt>osx</tt>, <tt>linux</tt>, <tt>elilo</tt>, <tt>grub</tt>, and <tt>windows</tt></td>
+   <td>Ordinarily, rEFInd clears the screen and displays basic boot information when launching any OS but Mac OS X. For OS X, the default behavior is to clear the screen to the default background color and display no information. You can specify the simpler Mac-style behavior by specifying the OSes or boot loaders you want to work this way with this option. (OSes that should use text-mode displays should be omitted from this list.) Note that this option doesn't affect what the boot loader does; it may display graphics, text, or nothing at all. Thus, the effect of this option is likely to last for just a fraction of a second. On at least one firmware (used on some Gigabyte boards), setting <tt>use_graphics_for linux</tt> is required to avoid a system hang when launching Linux via its EFI stub loader. To add to the default list, specify <tt>+</tt> as the first option, as in <tt>use_graphics_for + windows</tt>.</td>
+</tr>
+<tr>
+   <td><tt>scan_driver_dirs</tt></td>
+   <td>directory path(s)</td>
+   <td>Scans the specified directory or directories for EFI driver files. If rEFInd discovers <tt>.efi</tt> files in those directories, they're loaded and activated as drivers. This option sets directories to scan <i>in addition to</i> the <tt>drivers</tt> and <tt>drivers_<i>arch</i></tt> subdirectories of the rEFInd installation directory, which are always scanned, if present.</td>
+</tr>
+<tr>
+   <td><tt>scanfor</tt></td>
+   <td><tt>internal</tt>, <tt>external</tt>, <tt>optical</tt>, <tt>netboot</tt>, <tt>hdbios</tt>, <tt>biosexternal</tt>, <tt>cd</tt>, and <tt>manual</tt></td>
+   <td>Tells rEFInd what methods to use to locate boot loaders. The <tt>internal</tt>, <tt>external</tt>, and <tt>optical</tt> parameters tell rEFInd to scan for EFI boot loaders on internal, external, and optical (CD, DVD, and Blu-ray) devices, respectively. The <tt>netboot</tt> option relies on the presence of the <tt>ipxe.efi</tt> and <tt>ipxe_discover.efi</tt> program files in the <tt>EFI/tools</tt> directory to assist with network (Preboot Execution Environment, or PXE) booting. Note that <tt>netboot</tt> is experimental. See the <tt>BUILDING.txt</tt> file for information on building the necessary binaries. The <tt>hdbios</tt>, <tt>biosexternal</tt>, and <tt>cd</tt> parameters are similar, but scan for BIOS boot loaders. (Note that the BIOS options scan more thoroughly and actively on Macs than on UEFI-based PCs; for the latter, only options in the firmware's boot list are scanned, as described on the <a href="using.html">Using rEFInd</a> page.) The <tt>manual</tt> parameter tells rEFInd to scan the configuration file for manual settings. You can specify multiple parameters to have the program scan for multiple boot loader types. When you do so, the order determines the order in which the boot loaders appear in the menu. The default is <tt>internal, external, optical, manual</tt> on most systems, but <tt>internal, hdbios, external, biosexternal, optical, cd, manual</tt> on Macs.</td>
+</tr>
+<tr>
+   <td><tt>uefi_deep_legacy_scan</tt></td>
+   <td>none or one of <tt>true</tt>, <tt>on</tt>, <tt>1</tt>, <tt>false</tt>, <tt>off</tt>, or <tt>0</tt></td>
+   <td>Tells rEFInd how aggressively to scan for BIOS/CSM/legacy boot loaders on UEFI-based PCs. Ordinarily or if this option is set to <tt>false</tt>, <tt>off</tt>, or <tt>0</tt>, rEFInd presents only those options that were available in the NVRAM when it launched. When uncommented with no option or with <tt>true</tt>, <tt>on</tt>, or <tt>1</tt> set, rEFInd adds every possible BIOS-mode boot device (of types specified by <tt>scanfor</tt>) as a BIOS/CSM/legacy boot option. This latter behavior is sometimes required to detect USB flash drives or hard disks beyond the first one.</td>
+</tr>
+<tr>
+   <td><tt>scan_delay</tt></td>
+   <td>numeric (integer) value</td>
+   <td>Imposes a delay before rEFInd scans for disk devices. Ordinarily this is not necessary, but on some systems, some disks (particularly external drives and optical discs) can take a few seconds to become available. If some of your disks don't appear when rEFInd starts but they <i>do</i> appear when you press the Esc key to re-scan, try uncommenting this option and setting it to a modest value, such as <tt>2</tt>, <tt>5</tt>, or even <tt>10</tt>. The default is <tt>0</tt>.</td>
+</tr>
+<tr>
+   <td><tt>also_scan_dirs</tt></td>
+   <td>directory path(s)</td>
+   <td>Adds the specified directory or directories to the directory list that rEFInd scans for EFI boot loaders when <tt>scanfor</tt> includes the <tt>internal</tt>, <tt>external</tt>, or <tt>optical</tt> options. Directories are specified relative to the filesystem's root directory. You may precede a directory path with a volume name and colon, as in <tt>somevol:/extra/path</tt>, to restrict the extra scan to a single volume. A volume number, preceded by <tt>fs</tt>, can be used for volumes that lack names, as in <tt>fs1:/extra/path</tt>. (<i>This usage is deprecated.</i>) If you don't specify a volume name or number, this option is applied to <i>all</i> the filesystems that rEFInd scans. If a specified directory doesn't exist, rEFInd ignores it (no error results). The default value is <tt>boot</tt>, which is useful for locating Linux kernels when you have an EFI driver for your Linux root (<tt>/</tt>) filesystem. To add to, rather than replace, the default value, specify <tt>+</tt> as the first item in the list, as in <tt>also_scan_dirs +,loaders</tt>.</td>
+</tr>
+<tr>
+   <td><tt>dont_scan_volumes</tt> or <tt>don't_scan_volumes</tt></td>
+   <td>filesystem or partition label(s)</td>
+   <td>Adds the specified volume or volumes to a volume "blacklist"&mdash;these filesystems are <i>not</i> scanned for EFI boot loaders. This may be useful to keep unwanted EFI boot entries, such as for a Macintosh recovery partition, from appearing on the main list of boot loaders. The default value is <tt>LRS_ESP</tt>, to keep the Lenovo Windows recovery volume from appearing. (This volume should get its own tools icon instead&mdash;see the <tt>showtools</tt> token.) You can use <tt>dont_scan_volumes</tt> to hide disks or partitions from legacy-mode scans, too. In this case, you can enter any part of the description that appears beneath the icons to hide entries that include the string you specify.</td>
+</tr>
+<tr>
+   <td><tt>dont_scan_dirs</tt> or <tt>don't_scan_dirs</tt></td>
+   <td>directory path(s)</td>
+   <td>Adds the specified directory or directories to a directory "blacklist"&mdash;these directories are <i>not</i> scanned for boot loaders. You may optionally precede a directory path with a volume name and a colon to limit the blacklist to that volume; otherwise all volumes are affected. For instance, <tt>EFI/BOOT</tt> prevents scanning the <tt>EFI/BOOT</tt> directory on <i>all</i> volumes, whereas <tt>ESP:EFI/BOOT</tt> blocks scans of <tt>EFI/BOOT</tt> on the volume called <tt>ESP</tt> but not on other volumes. You can use a filesystem number, as in <tt>fs0</tt>, in place of a volume name. (<i>The use of filesystem numbers is deprecated.</i>) This token may be useful to keep duplicate boot loaders out of the menu; or to keep drivers or utilities out of the boot menu, if you've stored them in a subdirectory of <tt>EFI</tt>. This option takes precedence over <tt>also_scan_dirs</tt>; if a directory appears in both lists, it will <i>not</i> be scanned. To add directories to the default list rather than replace the list, specify <tt>+</tt> as the first option, as in <tt>dont_scan_dirs + EFI/dontscan</tt>. The default for this token is <tt>EFI/tools, EFI/tools/memtest86, EFI/tools/memtest, EFI/memtest86, EFI/memtest, com.apple.recovery.boot</tt>.</td>
+</tr>
+<tr>
+   <td><tt>dont_scan_files</tt> or <tt>don't_scan_files</tt></td>
+   <td>filename(s)</td>
+   <td>Adds the specified filename or filenames to a filename "blacklist"&mdash;these files are <i>not</i> included as boot loader options even if they're found on the disk. This is useful to exclude support programs (such as <tt>shim.efi</tt> and <tt>MokManager.efi</tt>) and drivers from your OS list. The default value is <tt>shim.efi, shim-fedora.efi, shimx64.efi, PreLoader.efi, TextMode.efi, ebounce.efi, GraphicsConsole.efi, MokManager.efi, HashTool.efi, HashTool-signed.efi</tt>. You can add a pathname and even a volume specification, as in <tt>ESP:/EFI/BOOT/backup.efi, /boot/vmlinuz-bad</tt>, to block the boot loaders only in those specified locations. To add files to the default list rather than replace the list, specify <tt>+</tt> as the first option, as in <tt>dont_scan_files + badloader.efi</tt>.</td>
+</tr>
+<tr>
+   <td><tt>windows_recovery_files</tt></td>
+   <td>filename(s)</td>
+   <td>Adds the specified filename or filenames to list that will be recognized as Windows recovery tools and presented as such on the second row, if <tt>windows_recovery</tt> is among the options to <tt>showtools</tt>. The filename must include a complete path and may optionally include a filesystem label, as in <tt>LRS_EFI:\EFI\Microsoft\Boot\LrsBootmgr.efi</tt>. Whatever you specify here is added to the <tt>dont_scan_files</tt> list. The default value is <tt>EFI\Microsoft\Boot\LrsBootmgr.efi</tt>. If you specify <tt>+</tt> as the first option, the following options will be added to the default rather than replace it.</td>
+</tr>
+<tr>
+   <td><tt>scan_all_linux_kernels</tt></td>
+   <td>none or one of <tt>true</tt>, <tt>on</tt>, <tt>1</tt>, <tt>false</tt>, <tt>off</tt>, or <tt>0</tt></td>
+   <td>When uncommented or set to <tt>true</tt>, <tt>on</tt>, or <tt>1</tt>, causes rEFInd to add Linux kernels (files with names that begin with <tt>vmlinuz</tt> or <tt>bzImage</tt>) to the list of EFI boot loaders, even if they lack <tt>.efi</tt> filename extensions. This simplifies use of rEFInd on most Linux distributions, which usually provide kernels with EFI stub loader support but don't give those kernels names that end in <tt>.efi</tt>. Of course, the kernels must still be stored on a filesystem that rEFInd can read, and in a directory that it scans. (<a href="drivers.html">Drivers</a> and the <tt>also_scan_dirs</tt> options can help with those issues.) As of version 0.8.3, this option is enabled by default; to disable this feature, you must uncomment this token and set it to <tt>false</tt> or one of its synonyms (<tt>off</tt> or <tt>0</tt>).</td>
+</tr>
+<tr>
+   <td><tt>fold_linux_kernels</tt></td>
+   <td>none or one of <tt>true</tt>, <tt>on</tt>, <tt>1</tt>, <tt>false</tt>, <tt>off</tt>, or <tt>0</tt></td>
+   <td>When uncommented or set to <tt>true</tt>, <tt>on</tt>, or <tt>1</tt>, causes rEFInd to "fold" all Linux kernels in a given directory into a single main-menu icon. Selecting that icon launches the most recent kernel. To launch an older kernel, you must press F2 or Insert; older kernels appear on the resulting submenu display. (You can type, as <tt>root</tt>, <tt class="userinput">touch /boot/vmlinuz-{whatever}</tt>, to make <tt>/boot/vmlinuz-{whatever}</tt> your default kernel in a directory.) If you prefer to see all your kernels in the main menu, set this option to <tt>false</tt>, <tt>off</tt>, or <tt>0</tt>. Note that this option is new with version 0.9.0, which changes the default behavior; earlier versions of rEFInd behaved as if <tt>fold_linux_kernels false</tt> was set.</td>
+</tr>
+<tr>
+   <td><tt>max_tags</tt></td>
+   <td>numeric (integer) value</td>
+   <td>Limits the number of tags that rEFInd will display at one time. If rEFInd discovers more loaders than this value, they're shown in a scrolling list. The default value is <tt>0</tt>, which imposes no limit.</td>
+</tr>
+<tr>
+   <td><tt>default_selection</tt></td>
+   <td>a substring of a boot loader's title, or a numeric position; optionally followed by two times in <tt class="variable">HH:MM</tt> format</td>
+   <td>Sets the default boot OS based on the loader's title, which appears in the main menu beneath the icons when you select the loader. You can enter any substring of the title as the <tt>default_selection</tt>, so long as it's two or more characters in length. It's best to use a unique substring, since rEFInd stops searching when it finds the first match. Because rEFInd sorts entries within a directory in descending order by file modification time, if you specify a directory (or volume name, for loaders in a partition's root directory) as the <tt>default_selection</tt>, the newest loader in that directory will be the default. One-character entries are matched against the first character of the title, except for digits, which refer to the numeric order of the boot loader entries. If you specify a comma-delimited list of names <i><b>in quotation marks,</b></i> rEFInd will search on these in turn until it finds a match. For instance, <tt>default_selection "alpha,beta"</tt> will launch <tt>alpha</tt> if it's available, and <tt>beta</tt> if <tt>alpha</tt> is not available but <tt>beta</tt> is. If the <i>first</i> item in such a list is a plus sign (<tt>+</tt>), that refers to the item that rEFInd launched the last time it ran. You may optionally follow the match string by two times, in 24-hour format, in which case the entry applies only between those two times. For instance, <tt>default_selection Safety 1:30 2:30</tt> boots the entry called <tt>Safety</tt> by default between the hours of 1:30 and 2:30. These times are specified in whatever format the motherboard clock uses (local time or UTC). If the first value is larger than the second, as in <tt>23:00 1:00</tt>, it is interpreted as crossing midnight&mdash;11:00 PM to 1:00 AM in this example. The last <tt>default_selection</tt> setting takes precedence over preceding ones <i>if</i> the time value matches. Thus, you can set a main <tt>default_selection</tt> without a time specification and then set one or more others to override the main setting at specific times. If you do not specify a <tt>default_selection</tt>, rEFInd attempts to boot the previously-booted entry, or the first entry if there's no record of that or if the previously-booted entry can't be found.</td>
+</tr>
+<tr>
+   <td><tt>enable_and_lock_vmx</tt></td>
+   <td>none or one of <tt>true</tt>, <tt>on</tt>, <tt>1</tt>, <tt>false</tt>, <tt>off</tt>, or <tt>0</tt></td>
+   <td>When set to <tt>true</tt> or a synonym, enable the CPU's VMX bit and lock the MSR. This configuration is necessary for some hypervisors (notably Microsoft's Hyper-V) to function properly. Activating it on other CPUs will, at best, have no effect, and could conceivably crash the computer, so enable it at your own risk! If your firmware supports activating these features, you should use it instead; this option is provided for users whose firmware does not provide this functionality. (Many Macs lack this configurability, for instance.) The default is <tt>false</tt>.</td>
+</tr>
+<tr>
+   <td><tt>spoof_osx_version</tt></td>
+   <td>string (<tt>10.9</tt> suggested)</td>
+   <td>On some Macs, this option causes rEFInd to tell the firmware that the specified version of OS X is being launched, even when another OS is selected. The effect is that the firmware may initialize hardware differently, which may have beneficial (or detrimental) results. If your Mac's video output isn't working normally, this option may help. On the other hand, keyboards and mice are known to sometimes stop functioning if this option is used, so you shouldn't use it unnecessarily. This option has no effect on non-Apple hardware. The default is to not use this feature.</td>
+</tr>
+<tr>
+   <td><tt>csr_values</tt></td>
+   <td>List of hexadecimal values</td>
+   <td>Specifies values that may be set via the <tt>csr_rotate</tt> tool for Apple's System Integrity Protection (SIP). SIP stores values in NVRAM to set restrictions on what users (even <tt>root</tt>) may do in OS X 10.11. If you want to be able to control these restrictions in rEFInd, you must set the values you want to use here <i>and</i> set <tt>csr_rotate</tt> on the <tt>showtools</tt> line (which must also be uncommented). Note that values are specified in hexadecimal, with no leading <tt>0x</tt> or other hexadecimal indicator. SIP is described in more detail on many Web sites, such as <a href="http://osxarena.com/2015/10/guide-details-apples-system-integrity-protection-sip-for-hackintosh/">here</a> and <a href="http://www.idelta.info/archives/sip-rootless-internal-in-el-capitan/">here.</a></td>
+</tr>
+<tr>
+   <td><tt>include</tt></td>
+   <td>filename</td>
+   <td>Includes the specified file into the current configuration file. Essentially, the included file replaces the <tt>include</tt> line, so positioning of this token is important if the included file includes options that contradict those in the main file. The included file must reside in the same directory as the rEFInd binary and the main configuration file. This option is valid only in the main configuration file; included files may not include third-tier configuration files.</td>
+</tr>
+</table>
+
+<p>As an example of rEFInd configuration, consider the following <tt>refind.conf</tt> file:</p>
+
+<pre class="listing">
+# Sample refind.conf file
+timeout 5
+banner custom.bmp
+scan_driver_dirs drivers,EFI/tools/drivers
+scanfor manual,external,optical
+default_selection elilo
+</pre>
+
+<p>This example sets a timeout of 5 seconds; loads a custom graphic file called <tt>custom.bmp</tt> from the directory in which the rEFInd binary resides; scans the <tt>drivers</tt> and <tt>EFI/tools/drivers</tt> directories for EFI drivers; uses manual boot loader configuration but also scans for external EFI boot loaders and EFI boot loaders on optical discs; and sets the default boot loader to the first loader found that includes the string <tt>elilo</tt>. Of course, since this file specifies use of manual boot loader configuration, it's not complete; you'll need to add at least one OS stanza to be able to boot from anything but an external disk or optical drive, as described shortly.</p>
+
+<a name="stanzas">
+<h2>Creating Manual Boot Stanzas</h2>
+</a>
+
+<p class="sidebar"><b>Note:</b> Don't create manual boot stanzas unless you need to do so! Many people try to create them when rEFInd's auto-detection mechanisms will do the job just as well and with less hassle and chance of error. (Note that you can pass kernel options to a Linux kernel in the <tt>/boot/refind_linux.conf</tt> file; see the <a href="linux.html">Methods of Booting Linux</a> page for details.) Efforts to create manual boot stanzas when auto-detection can do the job just create pointless work for yourself!</p>
+
+<p>Manual boot stanzas in rEFInd are similar to those in GRUB Legacy, GRUB 2, or ELILO. You can use them to add EFI boot loaders to those that are auto-detected. rEFInd does not yet support manual boot stanzas for BIOS-mode boot loaders. You also cannot modify the auto-detected options; if you just want to tweak one OS's configuration, you have several options:</p>
+
+<ul>
+
+<li>You can use the <tt>dont_scan_volumes</tt>, <tt>dont_scan_dirs</tt>, or <tt>dont_scan_files</tt> options in <tt>refind.conf</tt> to hide the tag you want to modify, then create a manual boot stanza to replace it.</li>
+
+<li>You can move or rename the boot loader file for the boot loader you want to tweak.</li>
+
+<li>You can disable all auto-detection options and add manual configurations for all your boot loaders, even those that work fine when auto-detected.</li>
+
+<li>You can put up with having duplicate tags in your OS list.</li>
+
+</ul>
+
+<p>Each OS stanza begins with the keyword <tt>menuentry</tt>, a name for the entry, and an open curly brace (<tt>{</tt>). Subsequent lines constitute the bulk of the stanza, which concludes with a line containing nothing but a close curly brace (<tt>}</tt>). Table 2 summarizes the keywords that you can include in a stanza.</p>
+
+<table border="1" cellpadding="1" cellspacing="2" summary="Table 2: OS stanza definitions in <tt>refind.conf</tt>"><a name="table2"><caption><b>Table 2: OS stanza definitions in <tt>refind.conf</tt></b></caption></a>
+<tr>
+   <th>Token</th>
+   <th>Possible parameters</th>
+   <th>Explanation</th>
+</tr>
+<tr>
+   <td><tt>menuentry</tt></td>
+   <td>name for the entry</td>
+   <td>Sets the name that's displayed along with the icon for this entry. If the name should contain a space, it <i>must</i> be enclosed in quotes. Following the name, an open curly brace (<tt>{</tt>) ends the <tt>menuentry</tt> line.</td>
+</tr>
+<tr>
+   <td><tt>volume</tt></td>
+   <td>filesystem label, partition label, GUID value, or filesystem number</td>
+   <td>Sets the volume that's used for subsequent file accesses (by <tt>icon</tt> and <tt>loader</tt>, and by implication by <tt>initrd</tt> if <tt>loader</tt> follows <tt>volume</tt>). You pass this token a filesystem's label, a partition's label, a partition's GUID, or a volume number. A filesystem or partition label is typically displayed under the volume's icon in file managers and rEFInd displays it on its menu at the end of the boot prompt string. If this label isn't unique, the first volume with the specified label is used. The matching is nominally case-insensitive, but on some EFIs it's case-sensitive. If a filesystem has no label, you can use a partition GUID number. You can also use a volume number followed by a colon, such as <tt>0:</tt> to refer to the first filesystem or <tt>1:</tt> to refer to the second. The assignment of numbers is arbitrary and may not be consistent across boots, though. It might change if you insert an optical disc or plug in a USB flash drive, for instance. If this option is not set, the volume defaults to the one from which rEFInd launched.</td>
+</tr>
+<tr>
+   <td><tt>loader</tt></td>
+   <td>filename</td>
+   <td>Sets the filename for the boot loader. You may use either Unix-style slashes (<tt>/</tt>) or Windows/EFI-style backslashes (<tt>\</tt>) to separate directory elements. In either case, the references are to files on the ESP from which rEFInd launched or to the one identified by a preceding <tt>volume</tt> token. The filename is specified as a path relative to the root of the filesystem, so if the file is in a directory, you must include its complete path, as in <tt>\EFI\myloader\loader.efi</tt>. This option should normally be the first in the body of an OS stanza; if it's not, some other options may be ignored. An exception is if you want to boot a loader from a volume other than the one on which rEFInd resides, in which case <tt>volume</tt> should precede <tt>loader</tt>.</td>
+</tr>
+<tr>
+   <td><tt>initrd</tt></td>
+   <td>filename</td>
+   <td>Sets the filename for a Linux kernel's initial RAM disk (initrd). This option is useful only when booting a Linux kernel that includes an <a href="http://www.rodsbooks.com/efi-bootloaders/efistub.html">EFI stub loader</a>, which enables you to boot a kernel without the benefit of a separate boot loader. When booted in this way, though, you must normally pass an initrd filename to the boot loader. You must specify the complete EFI path to the initrd file with this option, as in <tt>initrd EFI/linux/initrd-3.3.0-rc7.img</tt>. You'll also have to use the <tt>options</tt> line to pass the Linux root filesystem, and perhaps other options (as in <tt>options "root=/dev/sda4 ro"</tt>). The initial RAM disk file must reside on the same volume as the kernel.</td>
+</tr>
+<tr>
+   <td><tt>icon</tt></td>
+   <td>filename</td>
+   <td>Sets the filename for an icon for the menu. If you omit this item, a default icon will be used, based on rEFInd's auto-detection algorithms. The filename should be a complete path from the root of the current directory, not relative to the default icons subdirectory or the one set via <tt>icons_dir</tt>.</td>
+</tr>
+<tr>
+   <td><tt>ostype</tt></td>
+   <td><tt>MacOS</tt>, <tt>Linux</tt>, <tt>ELILO</tt>, <tt>Windows</tt>, <tt>XOM</tt></td>
+   <td>Determines the options that are available on a sub-menu obtained by pressing the Insert key with an OS selected in the main menu. If you omit this option, rEFInd selects options using an auto-detection algorithm. Note that this option is case-sensitive.</td>
+</tr>
+<tr>
+   <td><tt>graphics</tt></td>
+   <td><tt>on</tt> or <tt>off</tt></td>
+   <td>Enables or disables a graphical boot mode. This option has an effect only on Macintoshes; UEFI PCs seem to be unaffected by it.</td>
+</tr>
+<tr>
+   <td><tt>options</tt></td>
+   <td>options passed to the boot loader</td>
+   <td>Pass arbitrary options to your boot loader with this line. Note that if the option string should contain spaces (as it often should) or characters that should not be modified by rEFInd's option parser (such as slashes or commas), it <i>must</i> be enclosed in quotes. If you must include quotes in an option, you can double them up, as in <tt>my_opt=""with quotes""</tt>, which passes <tt>my_opt="with quotes"</tt> as an option.</td>
+</tr>
+<tr>
+   <td><tt>disabled</tt></td>
+   <td>none</td>
+   <td>Disable an entry. This is often easier than commenting out an entire entry if you want to temporarily disable it.</td>
+</tr>
+<tr>
+   <td><tt>submenuentry</tt></td>
+   <td>submenu entry name and tokens</td>
+   <td>This keyword identifies a submenu entry, as described in more detail shortly.</td>
+</tr>
+</table>
+
+<p>As an example, consider the following entries:</p>
+
+<pre class="listing">
+menuentry "Ubuntu" {
+    loader /EFI/ubuntu/grubx64.efi
+    disabled
+}
+
+menuentry Arch {
+    icon /EFI/refind/icons/os_arch.png
+    volume ARCHBOOT
+    loader /vmlinuz-linux
+    initrd /initramfs-linux.img
+    options "root=/dev/sda3 ro"
+}
+
+menuentry "Windows via shell script" {
+    icon \EFI\refind\icons\os_win.png
+    loader \EFI\tools\shell.efi
+    options "fs0:\EFI\tools\launch_windows.nsh"
+}
+</pre>
+
+<p>This example sets up three entries: one for Ubuntu, one for Arch Linux, and one to launch a shell script. Note that the final entry uses different directory separators from the first two, simply to demonstrate the fact that it's possible. (The form of directory separators in <tt>options</tt> lines is important, though, because the program being launched may expect a particular directory separator character.) The Ubuntu entry sets no icon, since rEFInd will note that the boot loader is stored in the <tt>ubuntu</tt> directory, and it will automatically find the appropriate Ubuntu icon (<tt>os_ubuntu.png</tt>). This entire entry is, however, disabled, so no matching icon will appear when you reboot unless you first comment out or delete the <tt>disabled</tt> line.</p>
+
+<p class="sidebar"><b>Tip:</b> Under Linux, you can learn a filesystem's label by using <tt>blkid</tt>, as in <tt class="userinput">blkid /dev/sda1</tt>. The filesystem's label, if set, is identified by the keyword <tt>LABEL</tt> in the output. Some versions also return the partition's label and partition GUID (referred to as <tt>PARTUUID</tt> by <tt>blkid</tt>). You can obtain the partition's name and unique GUID using <tt>sgdisk</tt>, as in <tt class="userinput">sgdisk -i 1 /dev/sda</tt> to find the data on <tt>/dev/sda1</tt>.</p>
+
+<p>The Arch entry begins with an icon specification to be sure that the icon is loaded from the same volume as rEFInd. (If the icon were stored on the same filesystem as the kernel, you'd place the <tt>icon</tt> line after the <tt>volume</tt> line.) This entry uses the <tt>volume</tt> token to tell rEFInd to load the kernel and initial RAM disk file from the filesystem or partition called <tt>ARCHBOOT</tt>. It passes the filename for an initial RAM disk using the <tt>initrd</tt> line and free-form options using the <tt>options</tt> line.</p>
+
+<p>The <tt>Windows via shell script</tt> entry may seem puzzling, but its purpose is to launch an OS (Windows in this case) after performing additional pre-boot initialization, which is handled by an EFI shell script. This works because you can pass the name of a shell script to an EFI shell&mdash;the script is named on the stanza's <tt>options</tt> line, using EFI file notation. The shell script, in turn, does whatever it needs to do and then launches the OS's boot loader:</p>
+
+<pre class="listing">mm 0003003E 8 -pci
+fs0:\EFI\Microsoft\Boot\bootmgfw.efi</pre>
+
+<p>This example writes data to the computer's PCI bus via the EFI shell's <tt>mm</tt> command and then launches Windows. Chances are you won't need to engage in such operations, and I do <i>not</i> recommend you try this exact example unless you know what you're doing! This command was required to activate the video hardware prior to booting Windows on a computer of a person with whom I corresponded, but such needs are rare. (Using the <tt>spoof_osx_version</tt> option in rEFInd 0.9.3 and later may also help with some such problems, at least on Macs.) Another example of a similar approach can be found in <a href="http://forum.techinferno.com/diy-e-gpu-projects/printfriendly2367.htm">this forum thread.</a> A few pointers on finding addresses for your hardware can be found <a href="http://forum.techinferno.com/diy-e-gpu-projects/2367-macbook-pro-retina-15-gtx-560-ti-%40-th05-8.html#post36199">in this post.</a></p>
+
+<p>You can combine these OS stanzas with the global <tt>refind.conf</tt> options presented earlier. The result would contain just two entries on the rEFInd boot menu (for Arch and Windows, since the Ubuntu entry is disabled), unless rEFInd found other boot options on an external or optical disk.</p>
+
+<a name="submenu">
+<h2>Creating Submenu Entries</h2>
+</a>
+
+<p>As described on the <a href="using.html">Using rEFInd</a> page, rEFInd can present a menu of options for certain loader tags when you press the Insert, F2, or + key. rEFInd does this automatically when it detects Mac OS X or ELILO boot loaders, when you set the OS type via the <tt>ostype</tt> option, or when booting a Linux kernel directly. The Mac OS X boot loader, in particular, accepts various options that you can use to boot in various ways.</p>
+
+<p>Sometimes, you might want to create your own custom submenu entries, and rEFInd enables you to do this. To create a custom submenu, you use the <tt>submenuentry</tt> keyword <i>inside</i> a <tt>menuentry</tt> stanza. Normally, you'll set the submenu definitions <i>after</i> you've set the main menu options, since the submenu options take the main menu options as defult, and so the main options must be set first. Like a <tt>menuentry</tt> stanza, a <tt>submenuentry</tt> definition begins with the keyword, the name of the item, and an open curly brace (<tt>{</tt>). It continues until a close curly brace (<tt>}</tt>). A submenu definition can use the keywords described in <a href="#table3">Table 3.</a> Except as otherwise noted, using an option of a given name completely overrides the setting in the main stanza.</p>
+
+<table border="1" cellpadding="1" cellspacing="2" summary="Table 3: Submenu keywords in <tt>refind.conf</tt>"><a name="table3"><caption><b>Table 3: Submenu keywords in <tt>refind.conf</tt></b></caption></a>
+<tr>
+   <th>Token</th>
+   <th>Possible parameters</th>
+   <th>Explanation</th>
+</tr>
+<tr>
+   <td><tt>submenuentry</tt></td>
+   <td>name for the entry</td>
+   <td>Sets the name that's displayed for this entry on the submenu page. If the name should contain a space, it <i>must</i> be enclosed in quotes. Following the name, an open curly brace (<tt>{</tt>) ends the <tt>submenuentry</tt> line.</td>
+</tr>
+<tr>
+   <td><tt>loader</tt></td>
+   <td>filename</td>
+   <td>Sets the filename for the boot loader, as described in <a href="#table2">Table 2.</a> Note that the loader is read from whatever filesystem is specified by the main stanza's <tt>volume</tt> option, provided that option precedes the submenu definition.</td>
+</tr>
+<tr>
+   <td><tt>initrd</tt></td>
+   <td>filename</td>
+   <td>Sets the filename for a Linux kernel's initial RAM disk (initrd), as described in <a href="#table2">Table 2.</a> If you want to eliminate the initrd specification, you should use this keyword alone, with no options. You might do this because your main entry is for a Linux kernel with EFI stub support and this submenu entry launches ELILO, which sets the initrd in its own configuration file.</td>
+</tr>
+<tr>
+   <td><tt>graphics</tt></td>
+   <td><tt>on</tt> or <tt>off</tt></td>
+   <td>Enables or disables a graphical boot mode, as described in <a href="#table2">Table 2.</a></td>
+</tr>
+<tr>
+   <td><tt>options</tt></td>
+   <td>options passed to the boot loader</td>
+   <td>Pass arbitrary options to your boot loader with this line, as described in <a href="#table2">Table 2.</a> As with <tt>initrd</tt>, you can eliminate all options by passing this keyword alone on a line.</td>
+</tr>
+<tr>
+   <td><tt>add_options</tt></td>
+   <td>options passed to the boot loader</td>
+   <td>This token works just like <tt>options</tt>, except that instead of <i>replacing</i> the default options, it causes the specified options to be <i>added to</i> those specified in the main stanza listing's <tt>options</tt> line.</td>
+</tr>
+<tr>
+   <td><tt>disabled</tt></td>
+   <td>none</td>
+   <td>Disable a submenu entry. This is often easier than commenting out an entire entry if you want to temporarily disable it.</td>
+</tr>
+</table>
+
+<p>The following menu entry illustrates the use of submenu entries. This is a variant of the second entry presented earlier:</p>
+
+<pre class="listing">
+menuentry Arch {
+    icon /EFI/refind/icons/os_arch.png
+    loader /vmlinuz-linux
+    initrd /initramfs-linux.img
+    options "root=/dev/sda3 ro"
+    submenuentry "single-user mode" {
+        add_options "single"
+    }
+    submenuentry "Use fallback initrd" {
+        initrd /initramfs-linux-fallback.img
+    }
+    submenuentry "boot via SYSLINUX" {
+        loader \EFI\syslinux\syslinux.efi
+       initrd
+       options
+    }
+}
+</pre>
+
+<p>The main menu item for this entry won't look different with the submenus defined than without them; but if you press the F2 or Insert key, you'll see the submenu items:</p>
+
+    <br /><center><img src="manual-submenu.png" align="center" width="406"
+    height="214" alt="Manually defining submenus enables you to customize
+    your boot options." border=2></center><br />
+
+<p>The main menu item appears at the top of the list&mdash;<tt>Boot using default options</tt>. The three submenus defined in this example's configuration file appear next, enabling you to launch in single-user mode, boot the standard kernel with the fallback initrd file, or boot via SYSLINUX, respectively. Submenus also include an item called <tt>Return to Main Menu</tt> that does just as it says. (Alternatively, you can return to the main menu by pressing the Esc key.)</p>
+
+<p>This example illustrates some of the things you can do with submenu entries:</p>
+
+<ul>
+
+<li>You can add kernel options when booting via the EFI stub loader&mdash;to launch single-user mode, to add graphical boot options, or what have you.</li>
+
+<li>You can remove options. Note the empty <tt>initrd</tt> and <tt>options</tt> lines in the SYSLINUX entry, for example; these empty lines override the default entries, which are carried over to submenu entries by default.</li>
+
+<li>You can change kernel options when booting via the EFI stub loader&mdash;to <i>remove</i> graphical boot options, to boot to a different root device, and so on.</li>
+
+<li>You can change your kernel and/or initial RAM disk when booting via the EFI stub loader.</li>
+
+<li>You can give users a choice of boot loaders. In this example, the main option boots via the kernel stub loader, but the submenu gives users the chance to boot via SYSLINUX instead. In fact, you could even boot two entirely different OSes from manually-defined submenu entries, although that could be confusing.</li>
+
+</ul>
+
+<a name="default">
+<h2>Adjusting the Default Boot Option</h2>
+</a>
+
+<p>Just before launching an OS, rEFInd stores the description in the EFI variable <tt>PreviousBoot</tt> with a GUID of 36d08fa7-cf0b-42f5-8f14-68df73ed3740. The next time rEFInd launches, it reads that same variable and sets the default boot loader to that value, if it's still available and if the first item in <tt>default_selection</tt> in the <tt>refind.conf</tt> file is a plus sign (<tt>+</tt>).</p>
+
+<p>Under Linux, the variable that rEFInd uses to store this information is accessible as <tt>/sys/firmware/efi/efivars/PreviousBoot-36d08fa7-cf0b-42f5-8f14-68df73ed3740</tt>. Thus, you can back up this value, modify it, and write it back out to adjust your next-booted OS. Getting this string just right can be a bit tricky, though, and if the kernel doesn't like its format, it will not let you modify the variable. If you try to modify the variable, be aware that it's stored in UTF-16 format. As with the <tt>default_selection</tt> token in <tt>refind.conf</tt>, you can enter any substring that uniquely identifies the entry you want to boot.</p>
+
+<p>In principle, you should be able to use a similar procedure to force rEFInd to boot another OS by default in any other OS that supports writing EFI runtime variables. Unfortunately, I don't know the mechanisms used for this task in Windows, OS X, FreeBSD, or any other OS.</p>
+
+<p>If you want to consistently boot a particular OS by default and ignore the previous boot, you can use <tt>default_selection</tt>, but <i>omit</i> the <tt>+</tt> at the start of the line.</p>
+
+<p></p>
+
+<p></p>
+
+<p></p>
+
+<hr />
+
+<p>copyright &copy; 2012&ndash;2015 by Roderick W. Smith</p>
+
+<p>This document is licensed under the terms of the <a href="FDL-1.3.txt">GNU Free Documentation License (FDL), version 1.3.</a></p>
+
+<p>If you have problems with or comments about this Web page, please e-mail me at <a href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.com.</a> Thanks.</p>
+
+<p><a href="index.html">Go to the main rEFInd page</a></p>
+
+<p><a href="linux.html">Learn about how to use EFI drivers with rEFInd</a></p>
+
+  <p><a href="http://www.rodsbooks.com/">Return</a> to my main Web page.</p>
+</body>
+</html>
diff --git a/docs/refind/drivers.html b/docs/refind/drivers.html
new file mode 100644 (file)
index 0000000..c961b34
--- /dev/null
@@ -0,0 +1,390 @@
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>The rEFInd Boot Manager: Using EFI Drivers</title>
+  <link href="../Styles/styles.css" rel="stylesheet" type="text/css" />
+</head>
+
+<meta name="viewport" content="width=device-width, initial-scale=1">
+
+<body>
+  <h1>The rEFInd Boot Manager:<br />Using EFI Drivers</h1>
+
+  <p class="subhead">by Roderick W. Smith, <a
+href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.com</a></p>
+
+<p>Originally written: 4/19/2012; last Web page update:
+11/8/2015, referencing rEFInd 0.10.0</p>
+
+
+<p>This Web page is provided free of charge and with no annoying outside ads; however, I did take time to prepare it, and Web hosting does cost money. If you find this Web page useful, please consider making a small donation to help keep this site up and running. Thanks!</p>
+
+<table border="1">
+<tr>
+<td>Donate $1.00</td>
+<td>Donate $2.50</td>
+<td>Donate $5.00</td>
+<td>Donate $10.00</td>
+<td>Donate $20.00</td>
+<td>Donate another value</td>
+</tr>
+<tr>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="1.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="2.50">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="5.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="10.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="20.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td></tr>
+</table>
+
+<hr />
+
+<p>This page is part of the documentation for the rEFInd boot manager. If a Web search has brought you here, you may want to start at the <a href="index.html">main page.</a></p>
+
+<hr />
+
+<div style="float:right; width:55%">
+
+<p>Beginning with version 0.2.7, rEFInd has been able to load EFI drivers, and as of version 0.4.0, it has shipped with some EFI filesystem drivers. Although EFI implementations should be able to load drivers prior to rEFInd's launch, in my experience, most EFI implementations offer such poor control over EFI driver loading that they can't be counted on to do this. Thus, if you want to use EFI drivers, rEFInd's ability to do so can be useful. This page tells you why you might want to use drivers, how you can install and use rEFInd's own drivers, where you can go to find other drivers, and provides tips on a few specific drivers.</p>
+
+</div>
+
+<div class="navbar">
+
+<h4 class="tight">Contents</h4>
+
+<ul>
+
+<li class="tight"><a href="#why">Why Should You Use Drivers?</li>
+
+<li class="tight"><a href="#using">Using rEFInd's EFI Drivers</a></li>
+
+<li class="tight"><a href="#finding">Finding Additional Drivers</a></li>
+
+<li class="tight"><a href="#notes">Notes on Specific Drivers</a></li>
+
+</ul>
+
+</div>
+
+<br/>
+<a name="why">
+<h2>Why Should You Use EFI Drivers?</h2>
+</a>
+
+<p>EFI supports drivers, which can activate hardware or filesystems in the pre-boot environment. At the moment, EFI drivers are few and far between; but you can or might want to use them for various reasons:</p>
+
+<ul>
+
+<!-- <p class="sidebar"><b>Tip:</b> Some Linux installation media come as <i>hybrid ISO</i> files, which can be written to either optical discs or USB flash drives for installation. Some of these media, though, are useless for installing to EFI systems from USB flash drives&mdash;unless your computer supports ISO-9660 on non-optical media. rEFInd's ISO-9660 driver provides this support. To use such a hybrid image from USB flash drive, you must boot using rEFInd on another disk that has the ISO-9660 driver installed. rEFInd should then provide an option to boot from the USB flash drive. I cannot guarantee that the installer will boot at this point, but it might.</p> -->
+
+<li>You can load a filesystem driver to gain access to files on a filesystem other than FAT (or HFS+ on Macs or ISO-9660 on some systems). This is most likely to be useful on a Linux installation, since a filesystem driver can enable you to store a Linux kernel with EFI stub loader or for use by ELILO on a Linux-native filesystem if your EFI System Partition (ESP) is getting crowded.</li>
+
+<li>You can load a driver for a plug-in disk controller to give the EFI access to its disks. Note that this is <i>not</i> required if you place your boot loader (and perhaps your OS kernel) on another disk, or if the plug-in disk controller includes EFI-capable firmware. It could be handy, perhaps in conjunction with a filesystem driver, to enable the EFI to read a boot loader or kernel from a disk on a plug-in controller, though.</li>
+
+<li>You can load a driver for a plug-in network card to enable the computer to boot from the network, or to access the network without booting an OS. Note that rEFInd does not currently support network boots itself, though.</li>
+
+<li>You can load a video card driver to set an appropriate video mode or to support a plug-in card that lacks EFI support in ts own firmware.</li>
+
+</ul>
+
+<p>Note that most of these uses are theoretical, at least to me; I don't know of any specific examples of EFI drivers (available as separate files) for disk controller hardware, network cards, or video cards. Such drivers are often embedded in the firmware of the devices themselves, and should be loaded automatically by the EFI. Chances are good that a few such drivers are available, unknown to me, and more may become available in the future. If you happen to have a device and need support for it under EFI, searching for drivers is certainly worth doing.</p>
+
+<p>To the best of my knowledge, the best reason to want EFI driver support in rEFInd is to provide access to filesystems. Although EFI filesystem driver choices are currently somewhat limited, those that are available can help to improve your installation and configuration options, particularly if you've found yourself "boxed in" by awkward installation or bugs, such as the dinky ESP that Ubuntu creates by default or the bug that prevents a Linux kernel with <a href="http://www.rodsbooks.com/efi-bootloaders/efistub.html">EFI stub loader support</a> from booting from the ESP of at least some Macs.</p>
+
+<p>As a side note, using an ISO-9660 driver can theoretically help you keep the size of a custom Linux boot CD/DVD down to a reasonable value. This is because EFI systems normally boot from optical discs by reading a FAT image file in El Torito format and treating that file as an ESP. If you need to store the kernel both in that file and directly in the ISO-9660 filesystem (to maintain bootability on BIOS systems), that can represent an unwanted extra space requirement. Placing rEFInd and an ISO-9660 driver in the FAT image file should enable you to store the kernel on the disc only once. Unfortunately, this doesn't work in practice. When the ISO-9660 driver is loaded from the El Torito image, the driver discovers that the optical disc is in use and refuses to access it. It's possible to use EFI shell commands to give the ISO-9660 driver access to the shell device, but this causes the El Torito access to go away, which means that anything loaded from the El Torito image (such as rEFInd) is likely to malfunction. Also, some EFI implementations include ISO-9660 drivers, so you might not need a separate ISO-9660 driver if you're building a disc for a particular computer.</p>
+
+<a name="using">
+<h2>Using rEFInd's EFI Drivers</h2>
+</a>
+
+<p class="sidebar"><b>Note:</b> If you want to use the drivers with a Mac, be sure to use at least version 0.4.3. Earlier versions were incompatible with the Mac's EFI 1.x firmware. Alternatively, you can use the drivers that came with <a href="http://refit.sourceforge.net">rEFIt,</a> which work on Macs.</p>
+
+<p>Since version 0.4.0, rEFInd has shipped with a small collection of read-only EFI filesystem drivers. These are:</p>
+
+<ul>
+
+<li><b>ReiserFS</b>&mdash;This driver originated with rEFIt. It's useful
+    for reading Linux kernels from a separate <tt>/boot</tt> partition, or
+    even from a root (<tt>/</tt>) filesystem, if you use ReiserFS on it.
+    <b>Caution:</b> If you use this driver, you should use the
+    <tt>notail</tt> option in Linux's <tt>/etc/fstab</tt> file for the
+    partition(s) you want the EFI to read. This is because the driver
+    doesn't properly handle ReiserFS's "tail-packing" feature, so files can
+    seem to be corrupted in EFI if you use this feature, which is disabled
+    by <tt>notail</tt>.</li>
+
+<li><b>Ext2fs</b>&mdash;This driver also originated with rEFIt. It can be
+    used in the same way as the ReiserFS driver. Although it's called an
+    "ext2fs" driver, it also works with ext3fs.</li>
+
+<li><b>Ext4fs</b>&mdash;Stefan Agner <a
+    href="https://github.com/falstaff84/rEFInd">modified the rEFIt/rEFInd
+    ext2fs driver</a> so that it could handle ext4fs. I'm including this as
+    a separate driver from the ext2fs driver, although the ext4fs version
+    can handle ext2fs and ext3fs, too. Providing both drivers enables
+    easy filesystem separation&mdash;for instance, you can use ext2fs on a
+    <tt>/boot</tt> partition and ext4fs on your root (<tt>/</tt>)
+    partition, to have the EFI scan only the former. This driver has some
+    limitations. Most notably, for various reasons it maxes out at 16TiB
+    and won't mount any ext4 filesystem that's larger than this. As of
+    version 0.6.1, this driver supports the <tt>meta_bg</tt> feature, which
+    can also be used on ext2fs and ext3fs. Thus, it can handle some ext2fs
+    and ext3fs partitions that the ext2fs driver can't handle. You can
+    learn about your ext2/3/4 filesystem features by typing <tt
+    class="userinput">dumpe2fs <i>/dev/sda2</i> | grep features</tt>,
+    changing <tt class="userinput"><i>/dev/sda2</i></tt> to your
+    filesystem's device.</li>
+
+<li><b>Btrfs</b>&mdash;</b>Samuel Liao contributed this driver, which is
+    based on the rEFIt/rEFInd driver framework and algorithms from the GRUB
+    2.0 Btrfs driver. I've tested this driver with a simple one-partition
+    filesystem and with a filesystem that spans two physical devices
+    (although I've made no attempt to ensure that the driver can actually
+    read files written to both devices). Samuel Liao has used the driver
+    with a compressed Btrfs volume. The driver will handle subvolumes, but
+    you may need to add kernel options if you're booting a Linux kernel
+    directly from a filesystem that uses subvolumes. For instance, on a
+    test installation of Ubuntu 14.04 alpha on such a system, I needed to
+    set <tt>also_scan_dirs + @/boot</tt> in <tt>refind.conf</tt> and add
+    <tt>rootflags=subvol=@</tt> to the kernel options in my
+    <tt>refind_linux.conf</tt> file. Without the first of these options,
+    rEFInd could not locate my kernel; and without the second, the boot
+    failed with a message to the effect that the initial RAM disk could not
+    find <tt>/sbin/init</tt>. rEFInd 0.10.0 adds <tt>@/boot</tt> as a
+    standard option to <tt>also_scan_dirs</tt>, and its
+    <tt>refind-install</tt> and <tt>mkrlconf</tt> scripts should pick up
+    the root flags, assuming the system is booted into the regular
+    installation. These additions make it easier to set up rEFInd to work
+    with Btrfs.</li>
+
+<li><b>ISO-9660</b>&mdash;This driver originated with rEFIt's author, but
+    he never released a final version. Its code was improved by Oracle for
+    use in its VirtualBox product, and then further modified by the authors
+    of the <a
+    href="https://sourceforge.net/projects/cloverefiboot/">Clover</a> boot
+    loader. If your firmware doesn't provide its own ISO-9660 driver, this
+    one can be helpful; however, you may need to install it on your hard
+    disk before you can read an optical disc.</li>
+
+<li><b>HFS+</b>&mdash;Oracle wrote this driver, apparently with some code
+    taken from open source Apple examples. It was then further modified by
+    the Clover authors. I expect this driver to have limited appeal to most
+    rEFInd users. Macs don't need it, since Apple's EFI implementation
+    provides its own HFS+ driver, and HFS+ isn't normally used on
+    UEFI-based PCs. Some CDs are mastered with both ISO-9660 and HFS+, or
+    even with HFS+ alone, and it's conceivable that an HFS+ driver would be
+    useful when accessing such discs. Also, one unusual feature of this
+    driver is that it can read files from within an Apple LVM setup, which
+    Apple's own EFI HFS+ driver can't do. The upshot of this feature is
+    that if you load this driver on a Mac that uses Apple's LVM, rEFInd is
+    likely to show two OS X boot options. Ordinarily this is pointless, but
+    it could be helpful if your Recovery HD volume becomes damaged. I'm
+    providing the driver mainly because it compiled cleanly with no extra
+    work, aside from providing a Makefile entry for it.</li>
+
+<p class="sidebar"><b>Warning:</b> I've received multiple reports of system hangs when using the NTFS driver; however, I've been unable to replicate the problem. (The problem is probably triggered either by interactions with specific EFIs or by unique features of the "problem" NTFS volumes.) I therefore recommend avoiding it unless it's absolutely necessary. I've added a couple of checks to the driver code in rEFInd 0.9.1 that <i>may</i> fix this problem, but these checks may also have no effect.</p>
+
+<li><b>NTFS</b>&mdash;Samuel Liao contributed this driver, which uses the
+    rEFIt/rEFInd driver framework. Note that this driver is
+    <i><b>not</b></i> required to boot Windows with rEFInd, since Windows
+    stores its EFI boot loader on the (FAT) ESP, and the BIOS boot process
+    (generally used when dual-booting on a Mac) relies only on the
+    partition's boot sector, which is read without the benefit of this
+    driver. Reasons to use this driver include:
+    <ul>
+    <li>If you want to store large boot files to be read from EFI, such as
+        RAM disk images, from Windows.</li>
+    <li>If you have a Mac and NTFS data partitions, loading this driver
+        should exclude those data partitions from the boot menu.</li>
+    <li>If you have a Mac that dual-boots with Windows, using this driver
+        should provide NTFS volume names in the boot menu.</li>
+    </ul>
+    </li>
+
+</ul>
+
+<p>All of these drivers rely on filesystem wrapper code written by rEFIt's author, Christoph Phisterer.</p>
+
+<p class="sidebar"><b>Note:</b> rEFInd's <tt>refind-install</tt> script, when run from Linux, installs the driver required to read the <tt>/boot</tt> directory. Under OS X, the <tt>refind-install</tt> script installs the ext4fs driver if the script detects a Linux partition&mdash;but you might need to change this driver if you use another filesystem. The script installs all the available drivers if you pass it the <tt>--alldrivers</tt> option. (I do <i>not</i> recommend using this feature except for creating general-purpose USB flash drives with rEFInd, since having too many drivers can cause various problems.) See the <a href="installing.html">Installing rEFInd</a> page for details.</p>
+
+<p>If you want to use one or more of these drivers, you can install them from the rEFInd binary package from the <tt>refind/drivers_<tt class="variable">arch</tt></tt> directory, where <tt class="variable">arch</tt> is a CPU architecture code&mdash;<tt>x64</tt> or <tt>ia32</tt>. The files are named after the filesystems they handle, such as <tt>ext4_x64.efi</tt> for the 64-bit ext4fs driver. You should copy the files for the filesystems you want to use to the <tt>drivers</tt> or <tt>drivers_<tt class="variable">arch</tt></tt> subdirectory of the main rEFInd installation directory. (You may need to create this subdirectory.) Be careful to install drivers only for your own architecture. Attempting to load drivers for the wrong CPU type will cause a small delay at best, or may cause the computer to crash at worst. I've placed rEFInd's drivers in directories that are named to minimize this risk, but you should exercise care when copying driver files.</p>
+
+<p class="sidebar"><b>Warning:</b> <i>Do not</i> place EFI program files in your driver directories! Unfortunately, EFI uses the same <tt>.efi</tt> filename extension to identify both EFI program files and EFI drivers. Therefore, rEFInd can't distinguish between the two prior to loading them, and if you place program files in a drivers directory, rEFInd will run the EFI program file when it does its driver scan.</p>
+
+<p>When you reboot after installing drivers, rEFInd should automatically detect and use the drivers you install. There's likely to be an extra delay, typically from one to five seconds, as rEFInd loads the drivers and tells the EFI to detect the filesystems they handle. For this reason, and because of the possibility of drivers harboring bugs, I recommend installing only those drivers that you need. If you like, you can install drivers you don't plan on using to some other directory, such as <tt>/drivers</tt> on the ESP's root. You can then load these drivers manually with the EFI shell's <tt>load</tt> command if the need arises in the future. You can then tell the shell to re-assign drive identifiers with <tt>map -r</tt>:</p>
+
+<pre class="listing">
+fs0: <tt class="userinput">load btrfs_x64.efi</tt>
+fs0: <tt class="userinput">map -r</tt>
+</pre>
+
+<a name="finding">
+<h2>Finding Additional EFI Drivers</h2>
+</a>
+
+<p>As already noted, I know of no EFI drivers for EFI hardware, aside from those that are built into motherboards' EFI implementations. I do, however, know of a few EFI filesystem drivers, in addition to those provided with rEFInd:</p>
+
+<ul>
+
+<li><b><a href="http://efi.akeo.ie">Pete Batard's efifs drivers</a></b>&mdash;This project is an EFI driver wrapper around GRUB 2's filesystem drivers. Once compiled, the result is that GRUB 2's drivers become standalone EFI filesystem drivers, loadable independently or by rEFInd. (rEFInd version 0.8.3 or later is required.) At present (driver version 0.7; January 2015), several drivers, including NTFS, exFAT, ext2fs, ReiserFS, Btrfs, JFS, and XFS, are usable, albeit with some caveats. Some drivers are slow, and they hang on some computers, such as one of my Macs. I have no doubt that these drivers will improve rapidly in usability in the near future. Note that the ext2fs driver from this set works with ext3fs and ext4fs, too. In addition to the main link, you can check the <a href="https://github.com/pbatard/efifs">github repository</a> for the source code.</li>
+
+<li><b><a href="http://refit.sourceforge.net">rEFIt's ext2fs and ReiserFS drivers</a></b>&mdash;You can gain read-only access to ext2fs, ext3fs, and ReiserFS volumes with these drivers, originally written by Christoph Pfisterer. You can use the binaries in the <tt>refit-bin-0.14/efi/tools/drivers</tt> directory of the binary package directly on a Mac. On a UEFI-based PC, though, you'll need to break the Mac-style "fat" binary into its 32- and 64-bit components. You can use my <a href="http://www.rodsbooks.com/thin/index.html"><tt>thin</tt></a> program for this job. As a practical matter, there's no advantage to using these drivers over rEFInd's drivers, since the latter are updated versions of the former.</li>
+
+<li><b><a href="https://sourceforge.net/projects/cloverefiboot/">Clover EFI's ISO-9660, ext2fs, ext4fs, and HFS+ drivers</a></b>&mdash;This project is an offshoot of TianoCore, the main UEFI project. It's primarily a Hackintosh boot loader, but it includes drivers for <a href="http://cloverefiboot.svn.sourceforge.net/viewvc/cloverefiboot/VBoxFsDxe/">ISO-9660, ext2fs, ext4fs, and HFS+;</a> however, building them requires a fair amount of expertise. These drivers served as a starting point for rEFInd's drivers, except for the ext4fs driver, which the Clover developers based on rEFInd's ext4fs driver. Thus, as with the rEFIt drivers, there's likely to be no advantage to using the Clover drivers over the rEFInd drivers.</li>
+
+<li><b><a href="http://www.osx86.net/view/2571-clover_v2_r384__efi_bootloader_pkg_+_gpt_efi_tools.html">Clover's EFI Tools package</a></b>&mdash;This osx86.net thread includes links to a package called <tt>         EFI_Tools_Clover_v2_r1888_EN.zip</tt>, which holds an OS X application (a directory with a <tt>.app</tt> extension, as seen from other platforms) with a number of drivers in the <tt>Contents/Resources/EFI/drivers64</tt> directory (and an equivalent for 32-bit binaries). Some of these, such as keyboard drivers, are unlikely to be useful unless your system is badly broken as delivered. Three that caught my eye, however, are <tt>VBoxExt2-64.efi</tt>, <tt>VBoxIso9600-64.efi</tt>, and <tt>NTFS-64.efi</tt>. The first two of those are presumably variants on rEFInd's drivers, but the NTFS driver is not. I don't know this driver's provenance, so I'm reluctant to recommend its use, but it bears mentioning.</li>
+
+<li><b><a href="https://www.virtualbox.org/browser/vbox/trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe">VirtualBox's HFS+ and ISO-9660 drivers</a></b>&mdash;These drivers are available in source code form, and come with VirtualBox binaries. I've not attempted to compile them myself, but I've seen a report that suggests they may include assumptions that require use of <a href="http://www.mingw.org/">MinGW,</a> a GCC-based compiler for Windows (and cross-compiler to build Windows executables under Linux). I don't know of a source for binaries suitable for use on EFI-based computers; if you want to use them, you'll need to figure out how to compile them yourself. As noted earlier, rEFInd's drivers are closely related to these.</li>
+
+<li><b>Ext2Pkg</b>&mdash;This driver, based on <a href="https://bitbucket.org/alinrus/ext2pkg">bitbucket</a> and with a backup on <a href="https://github.com/the-ridikulus-rat/Tianocore_Ext2Pkg">github,</a> appears to be an ext2fs/ext3fs driver built independently of the driver written by Christoph Pfisterer. The linked-to sites provide access to source code via <tt>git</tt> but do not provide binaries. When I built binaries, they failed to work. Under VirtualBox, the driver loaded but then hung when I tried to access an ext2 filesystem. On a 32-bit Mac Mini, I got error messages when I tried to access an ext2 filesystem. As I write, the code was last updated in March of 2012. If you check the project and it's been updated more recently, it might be worth trying. Otherwise, I can't recommend this driver. I mention it here only in case it improves in the future.</li>
+
+<li><b>Paragon's UFSD</b>&mdash;According to <a href="http://blog.paragon-software.com/?p=2951">this blog post,</a> Paragon Software has ported its <a href="http://www.paragon-software.com/technologies/ufsd.html">Universal File System Drivers (UFSD)</a> to EFI, providing "transparent access to NTFS, HFS+, ExFAT, and ExtFS" (sic). The entry doesn't provide any download links, and it's unclear if the product is (or will be) available for free or on a pay basis. I haven't tried these drivers, so I can't comment on their quality.</li>
+
+</ul>
+
+<p>The rEFIt, Clover, and VirtualBox drivers are related, and all of them
+have fed into rEFInd's drivers. Specific versions can have their own
+quirks, though. For instance, the Clover (and I suspect VirtualBox) drivers
+don't return volume labels, which causes rEFInd to display loaders on those
+volumes as being on a disk called <tt>Unknown</tt>. (I fixed that bug for
+rEFInd's version, and it wasn't present in the original rEFIt drivers.)
+Most of these drivers also suffer from speed problems on some computers.
+This is worst with the ext2fs drivers under VirtualBox; on my main
+computer, that combination takes 3 minutes to load a Linux kernel and
+initial RAM disk file! Most real computers don't suffer nearly so badly,
+but some can take an extra five seconds or so to boot a kernel. I've fixed
+the speed problems in rEFInd's drivers as of version 0.7.0.</p>
+
+<p>Driver availability could increase in the future. If you know of
+additional EFI drivers, please <a href="mailto:rodsmith@rodsbooks.com">tell
+me about them,</a> so I can share the information here. Likewise if you
+know of a source for other EFI drivers&mdash;say, for a video card or disk
+controller card.</p>
+
+<p>Once you've obtained an EFI driver, you can install it in rEFInd just as you would install rEFInd's own drivers, as described earlier.</p>
+
+<a name="notes">
+<h2>Notes on Specific Drivers</h2>
+</a>
+
+<p>I've tested several of the drivers described on this page on a handful
+of systems. The Pfisterer ext2fs driver (from any source) works on both
+ext2fs and ext3fs, but not on ext4fs&mdash;but Agner's derivative ext4fs
+driver handles ext4fs, so that's not a problem. The ReiserFS driver is
+obviously useful only on ReiserFS partitions. (Reiser4 is not supported, as
+far as I know.) The Btrfs driver is the newest of the Linux filesystem
+drivers included with rEFInd, and so I've tested it the least, but it's
+worked for me on several test systems. Given that ext2fs, ext3fs, and
+ReiserFS are getting a bit on in age by Linux standards, you might do well
+to use them on a separate Linux <tt>/boot</tt> partition; however, if
+you're willing to use ext3fs, ext4fs, Btrfs, or ReiserFS on your root
+(<tt>/</tt>) filesystem, you can use the EFI drivers to read your kernel
+from it. Note that this assumes you use conventional partitions; to the
+best of my knowledge, there's no EFI driver for Linux's Logical Volume
+Manager (LVM) or Redundant Array of Independent Disks (RAID)
+configurations, so the EFI can't access filesystems stored in these
+ways.</p>
+
+<p>As noted earlier, rEFInd's drivers prior to version 0.7.0, as well as related drivers from rEFIt, Clover, and VirtualBox, suffer from speed problems. These problems are mostly minor, adding a second or two to boot times; but on some computers, the speed problems can be dramatic, boosting kernel-load times up to as much as three minutes (under VirtualBox). If you run into excessive boot times with such a driver, try switching to the latest rEFInd driver instead. You might also try Pete Batard's efifs drivers.</p>
+
+<p>Although ext2fs, ext3fs, ext4fs, and ReiserFS are all case-sensitive, these drivers treat them in a case-insensitive way. Symbolic links work; however, rEFInd 0.6.11 and later ignore symbolic links, since many distributions use them in a way that creates redundant or non-functional entries in the rEFInd menu. You should be able to use hard links if you want to use a single kernel file in multiple ways (say for two distributions).</p>
+
+</ul>
+
+<hr />
+
+<p>copyright &copy; 2012&ndash;2015 by Roderick W. Smith</p>
+
+<p>This document is licensed under the terms of the <a href="FDL-1.3.txt">GNU Free Documentation License (FDL), version 1.3.</a></p>
+
+<p>If you have problems with or comments about this Web page, please e-mail me at <a href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.com.</a> Thanks.</p>
+
+<p><a href="index.html">Go to the main rEFInd page</a></p>
+
+<p><a href="linux.html">Learn about how to adjust rEFInd's appearance</a></p>
+
+  <p><a href="http://www.rodsbooks.com/">Return</a> to my main Web page.</p>
+</body>
+</html>
diff --git a/docs/refind/editor.png b/docs/refind/editor.png
new file mode 100644 (file)
index 0000000..58c782c
Binary files /dev/null and b/docs/refind/editor.png differ
diff --git a/docs/refind/features.html b/docs/refind/features.html
new file mode 100644 (file)
index 0000000..213adfc
--- /dev/null
@@ -0,0 +1,265 @@
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>The rEFInd Boot Manager: rEFInd Features</title>
+  <link href="../Styles/styles.css" rel="stylesheet" type="text/css" />
+</head>
+
+<meta name="viewport" content="width=device-width, initial-scale=1">
+
+<body>
+  <h1>The rEFInd Boot Manager:<br />rEFInd Features</h1>
+
+<p class="subhead">by Roderick W. Smith, <a
+href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.com</a></p>
+
+<p>Originally written: 3/14/2012; last Web page update:
+11/8/2015, referencing rEFInd 0.10.0</p>
+
+<p>This Web page is provided free of charge and with no annoying outside ads; however, I did take time to prepare it, and Web hosting does cost money. If you find this Web page useful, please consider making a small donation to help keep this site up and running. Thanks!</p>
+
+<table border="1">
+<tr>
+<td>Donate $1.00</td>
+<td>Donate $2.50</td>
+<td>Donate $5.00</td>
+<td>Donate $10.00</td>
+<td>Donate $20.00</td>
+<td>Donate another value</td>
+</tr>
+<tr>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="1.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="2.50">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="5.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="10.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="20.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td></tr>
+</table>
+
+<hr />
+
+<p>This page is part of the documentation for the rEFInd boot manager. If a Web search has brought you here, you may want to start at the <a href="index.html">main page.</a></p>
+
+<hr />
+
+<p>rEFInd is a fork of the <a href="http://refit.sourceforge.net">rEFIt</a> boot manager. As such, it has many features in common with rEFIt. These include the following:</p>
+
+<ul>
+
+<li>Support for both text-mode and graphical operation.</li>
+
+<li>Auto-detection of EFI and BIOS boot loaders.</li>
+
+<li>User-configurable graphics and icons&mdash;you can set your own background, set new icons, and so on.</li>
+
+<li>Launch EFI boot loaders.</li>
+
+<li>Launch legacy (BIOS) boot loaders on Macs. (rEFInd also supports legacy boots on some UEFI PCs; see below.)</li>
+
+<li>Launch options for an external EFI shell or disk partitioner. (See the <a href="installing.html">Installing rEFInd</a> section for information on how to obtain and install these components.)</li>
+
+<li>Provide the <tt>gptsync</tt> utility for creating hybrid MBRs. Note that rEFInd's version of <tt>gptsync</tt> is significantly updated compared to rEFIt's. Also, this tool should be used only on Macs that dual-boot with a BIOS-based OS, such as Windows; or <i>very</i> rarely on other computers.</li>
+
+<li>Set OS-specific boot options, such as to launch Mac OS X with verbose text-mode debug messages.</li>
+
+<li>Load EFI drivers for filesystems or hardware devices not supported natively by your firmware. (This feature is absent in some builds of rEFIt and in rEFInd prior to version 0.2.7.)</li>
+
+<li>Inclusion of drivers for the Linux ReiserFS and ext2 filesystems in the
+    main package. (These drivers are absent from rEFInd prior to version
+    0.4.0. See below concerning drivers for additional filesystems.)</li>
+
+</ul>
+
+<p>rEFInd expands on rEFIt by providing features that improve on or go beyond those of rEFIt, such as:</p>
+
+<ul>
+
+<li>Bug fixes, focusing on those that have bothered me personally.</li>
+
+<li>The ability to specify a configuration file to use at program launch
+    time via the <tt>-c <tt class="variable">filename</tt></tt>
+    command-line option.</li>
+
+<li>User-configurable methods of detecting boot loaders:
+
+    <ul>
+    <li>Auto-detection of EFI boot loaders, independently on internal hard disks, external hard disks, optical discs, and network boot loaders.</li>
+    <li>Auto-detection of legacy BIOS boot loaders, independently on internal hard disks, external hard disks, and optical discs.</li>
+    <li>Manually via the configuration file</li>
+    </ul>
+
+    You can select which of these methods to use to construct the rEFInd main boot menu. Although rEFIt supports auto-detection, it does not support manual configuration; and rEFIt's options to enable, disable, and prioritize individual boot loader detection methods are primitive compared to those in rEFInd.</li>
+
+<li>Beginning with rEFInd 0.8.4, <i>experimental</i> network boot loader support via the <a href="http://ipxe.org">iPXE</a> EFI binaries. When activated, rEFInd should add a network-boot option to its menu when a suitable network boot server is available.</li>
+
+<li>Support for launching legacy BIOS boot loaders on UEFI PCs with
+suitable CSM support (as of version 0.4.6, with significant improvements in
+version 0.8.0). Note that some UEFI PCs,
+such as those with Gigabyte's Hybrid EFI, lack a usable CSM.</li>
+
+<li>Improved flexibility in setting the default OS to boot. rEFInd enables specifying the default by any substring in the description. You can also specify multiple defaults, so that if the first isn't available, another will take its place (which is useful when using removable disks). You can also add time specifications to set a default to be used only during certain hours of the day. If no default loader is set, rEFInd defaults to the last-booted loader.</li>
+
+<li>Support for partition names or GUID values as fallbacks for filesystem labels in certain configuration file settings. Partition names may be shown as values to be displayed as part of the descriptive text for boot tags on the main menu, too, if a filesystem has no label.</li>
+
+<li>The ability to fine-tune options passed to EFI boot loaders, via manual configuration.</li>
+
+<li>An option editor to enable you to edit the options passed to an EFI boot loader on a per-boot basis.</li>
+
+<li>The ability to specify additional directories to scan for boot loaders and drivers (as of version 0.2.7).</li>
+
+<li>The ability to specify volumes and directories to <i>not</i> be scanned for boot loaders, even if they would ordinarily be scanned (as of version 0.6.0 for volumes and 0.4.2 for directories).</li>
+
+<li>The ability to re-scan boot loaders, to assist when changing removable media or after making a change to the configuration file with an EFI shell (as of version 0.3.5).</li>
+
+<li>A configurable delay before scanning for boot loaders, for systems on which there's a delay before disks become available (as of version 0.4.6).</li>
+
+<li>The ability to specify an additional icon storage directory, to assist in efforts to customize rEFInd's appearance (as of version 0.3.4).</li>
+
+<li>Support for icons, selection backgrounds, and banner graphics in PNG format, in addition to the ICNS and BMP formats supported by rEFIt.</li>
+
+<li>Support for full-screen banner images.</li>
+
+<li>Support for scaling icons, to adjust icon size for users with high-resolution displays, poor eyesight, or simply for personal preference reasons.</li>
+
+<li>The ability to set the screen's graphics resolution, within limits imposed by the EFI (as of rEFInd 0.3.0). Similarly, as of version 0.6.0, you can specify the text-mode resolution.</li>
+
+<li>Proper handling of more OS options than can fit on the screen. (rEFIt displays an empty list in graphical mode when it detects too many OSes.)</li>
+
+<li>Additional OS icons (most of which are Linux distributions, at least so far). This can make it easier to find a specific distribution in the boot list if you've installed multiple Linux distributions.</li>
+
+<li>Beginning with version 0.6.6, support for loading user-defined fonts, in the form of PNG files containing ASCII characters 32 through 126 plus a glyph to be used for values outside that range.</li>
+
+<li>The ability to auto-detect Linux initial RAM disk files and to read Linux kernel options from a <tt>refind_linux.conf</tt> file. These features support (nearly) automatic handling of Linux kernels with embedded EFI stub loader support (a new feature with Linux 3.3.0).</li>
+
+<li>The ability to "fold" multiple Linux kernels into a single entry in the main menu. Additional kernels appear as options in the submenu. This feature is enabled by default, but can be disabled by setting <tt>fold_linux_kernels false</tt> in <tt>refind.conf</tt>.</li>
+
+<li>In the absence of a <tt>refind_linux.conf</tt> file, the ability to pass minimal Linux boot options to a kernel based on the contents of <tt>/etc/fstab</tt>. This is limited to cases in which the kernel resides on the Linux root (<tt>/</tt>) filesystem, though, and it won't work if the installation requires any unusual options.</li>
+
+<li>As of rEFInd 0.9.0, if a Linux root (<tt>/</tt>) filesystem is identified by the type code specified by the <a href="http://www.freedesktop.org/wiki/Specifications/DiscoverablePartitionsSpec/">Discoverable Partitions Specification (DPS)</a> and the root filesystem cannot be identified via <tt>refind_linux.conf</tt> or <tt>/etc/fstab</tt>, rEFInd passes a kernel <tt>root=</tt> identifier based on the identified DPS root (<tt>/</tt>) type code.</li>
+
+<li>Fixes to display problems on many UEFI-based PCs.</li>
+
+<li>Beginning with version 0.6.10, a screen saver feature, activated by the <tt>screensaver <tt class="variable">seconds</tt></tt> token in <tt>refind.conf</tt>: Set <tt class="variable">seconds</tt> to the number of seconds before the screen will blank to prevent burn-in.</li>
+
+<li>Workarounds to file detection bugs in at least one type of UEFI firmware.</li>
+
+<li>Improved detection of itself, to keep rEFInd out of its own boot menu.</li>
+
+<li>Detection of a fallback boot loader (<tt>EFI/BOOT/bootx64.efi</tt> or <tt>EFI/BOOT/bootia32.efi</tt>) that's redundant with another boot loader, to keep the fallback boot loader out of menus when it's unnecessary.</li>
+
+<li>An "exit" option (disabled by default), so that you can return to whatever shell or boot manager you used to launch rEFInd, should this ability be desirable. (This feature first appeared in rEFInd 0.2.4.)</li>
+
+<li>Drivers for ISO-9660, NTFS, HFS+, ext4fs, and Btrfs, which are not included in rEFIt. The ISO-9660 driver is based on code from the rEFIt project, but was never completed by its original author. It was completed by Oracle for VirtualBox. The ext4fs driver is derived from the rEFIt ext2fs driver, and the Btrfs and NTFS drivers are derived from the rEFIt and GRUB 2.0 driver code.</li>
+
+<li>Beginning with version 0.5.0, the ability to "talk" to the <a href="http://mjg59.dreamwidth.org/20303.html">shim boot loader</a> to validate binaries supported by shim or its machine owner key (MOK) list when booting with Secure Boot active.</li>
+
+<li>The <tt>gptsync</tt> utility, included with rEFInd 0.6.9 and later, has safety checks to prevent creating a fresh hybrid MBR if the MBR side has been adjusted without adjusting the GPT side&mdash;a common source of problems. This update also prioritizes partition inclusion in the hybrid MBR, which can help on disks that have many partitions. OTOH, as of rEFInd 0.6.9, this version of <tt>gptsync</tt> is relatively untested.</li>
+
+<li>The ability to set the VMX bit on certain Intel CPUs. This feature is necessary for certain virtualization tools, such as Hyper-V, and not all EFIs enable users to set it.</li>
+
+<li>Beginning with version 0.10.0, the ability to spoof the booting of OS X when booting non-Apple OSes. This changes the way a Mac's EFI initializes hardware, which can get secondary video chipsets working on some Macs. This feature is controlled via the <tt>spoof_osx_version</tt> token in <tt>refind.conf</tt>.</li>
+
+<li>Beginning with version 0.10.0, the ability to adjust Apple System Integrity Protection (SIP; aka "rootless" or "CSR") settings. These settings control what features are off-limits even to <tt>root</tt> in OS X 10.11 (El Capitan) and later. To use this feature, you must set specific CSR values on <tt>refind.conf</tt>'s <tt>csr_values</tt> line <i>and</i> add <tt>csr_rotate</tt> to the <tt>showtools</tt> line.</li>
+
+</ul>
+
+<p>On the flip side, at least for Mac users, rEFInd comes with less sophisticated Mac installation tools than does rEFIt, in favor of more OS-agnostic packaging.</p>
+
+<p>If these features sound useful, then read on and try rEFInd. If not, you may need to look elsewhere. My <a href="http://www.rodsbooks.com/efi-bootloaders/index.html">Managing EFI Boot Loaders for Linux</a> page may be useful to you in this case.</p>
+
+<hr />
+
+<p>copyright &copy; 2012&ndash;2015 by Roderick W. Smith</p>
+
+<p>This document is licensed under the terms of the <a href="FDL-1.3.txt">GNU Free Documentation License (FDL), version 1.3.</a></p>
+
+<p>If you have problems with or comments about this Web page, please e-mail me at <a href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.com.</a> Thanks.</p>
+
+<p><a href="index.html">Go to the main rEFInd page</a></p>
+
+<p><a href="getting.html">Learn how to obtain rEFInd</a></p>
+
+  <p><a href="http://www.rodsbooks.com/">Return</a> to my main Web page.</p>
+</body>
+</html>
diff --git a/docs/refind/func_csr_rotate.png b/docs/refind/func_csr_rotate.png
new file mode 100644 (file)
index 0000000..75fa419
Binary files /dev/null and b/docs/refind/func_csr_rotate.png differ
diff --git a/docs/refind/getting.html b/docs/refind/getting.html
new file mode 100644 (file)
index 0000000..a154f0a
--- /dev/null
@@ -0,0 +1,310 @@
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>The rEFInd Boot Manager: Getting rEFInd</title>
+  <link href="../Styles/styles.css" rel="stylesheet" type="text/css" />
+</head>
+
+<meta name="viewport" content="width=device-width, initial-scale=1">
+
+<body>
+  <h1>The rEFInd Boot Manager:<br />Getting rEFInd</h1>
+
+  <p class="subhead">by Roderick W. Smith, <a
+href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.com</a></p>
+
+<p>Originally written: 3/14/2012; last Web page update:
+11/8/2015, referencing rEFInd 0.10.0</p>
+
+<p>This Web page is provided free of charge and with no annoying outside ads; however, I did take time to prepare it, and Web hosting does cost money. If you find this Web page useful, please consider making a small donation to help keep this site up and running. Thanks!</p>
+
+<table border="1">
+<tr>
+<td>Donate $1.00</td>
+<td>Donate $2.50</td>
+<td>Donate $5.00</td>
+<td>Donate $10.00</td>
+<td>Donate $20.00</td>
+<td>Donate another value</td>
+</tr>
+<tr>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="1.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="2.50">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="5.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="10.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="20.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td></tr>
+</table>
+
+<hr />
+
+<p>This page is part of the documentation for the rEFInd boot manager. If a Web search has brought you here, you may want to start at the <a href="index.html">main page.</a></p>
+
+<hr />
+
+<p><b>Note:</b> I consider rEFInd to be <i>beta-quality software!</i> I'm discovering bugs (old and new) and fixing them every few days. That said, rEFInd is a usable program in its current form on many systems. If you have problems, feel free to drop me a line.</p>
+
+<h2>Getting rEFInd from Sourceforge</h2>
+
+<p>You can find the rEFInd source code and binary packages at <a href="http://www.sourceforge.net/projects/refind/">its SourceForge page.</a> Note that rEFInd is OS-independent&mdash;it runs before the OS, so you download the same binary package for any OS. You can obtain rEFInd in several different forms:</p>
+
+<ul>
+
+<li><b><a
+    href="http://sourceforge.net/projects/refind/files/0.10.0/refind-bin-0.10.0.zip/download">A
+    binary zip file</a></b>&mdash;Download this if you want to install
+    rEFInd and/or its filesystem drivers on an <i>x</i>86 or <i>x</i>86-64
+    computer and have no need to test rEFInd first by booting it on an
+    optical disc. This zip file package includes both <i>x</i>86 (aka IA32)
+    and <i>x</i>86-64 (aka <i>x</i>64, AMD64, or EM64T) versions of rEFInd.
+    Which you install depends on your architecture, as described on the <a
+    href="installing.html">Installing rEFInd</a> page. Some users of Arch
+    Linux have reported problems booting some specific Arch Linux kernels
+    with rEFInd and some other tools. For them, a <a
+    href="http://sourceforge.net/projects/refind/files/0.10.0/refind-bin-gnuefi-0.10.0.zip/download">variant
+    package</a> exists in which the <i>x</i>86-64 binary was compiled with
+    GNU-EFI rather than the usual TianoCore EDK2. This change helps some
+    users with this problem.</li>
+
+<li><b><a
+    href="http://sourceforge.net/projects/refind/files/0.10.0/refind-0.10.0-1.x86_64.rpm/download">A
+    binary RPM file</a></b>&mdash;If you use an RPM-based <i>x</i>86-64
+    Linux system such as Fedora or openSUSE, you can install the binary RPM
+    package rather than use the binary zip file. (I don't provide an
+    equivalent 32-bit package.) This package runs the
+    <tt>refind-install</tt> script (described on the <a
+    href="installing.html">Installing rEFInd</a> page) as part of the
+    installation process. Distribution maintainers can examine the
+    <tt>refind.spec</tt> file in the source package and tweak it to their
+    needs. The <a
+    href="http://sourceforge.net/projects/refind/files/0.10.0/refind-0.10.0-1.src.rpm/download">source
+    RPM file</a> might or might not build on your system as-is; it relies
+    on assumptions about the locations of the GNU-EFI development
+    files.</li>
+
+<li><b><a
+    href="http://sourceforge.net/projects/refind/files/0.10.0/refind_0.10.0-1_amd64.deb/download">A
+    binary Debian package</a></b>&mdash;If you use an <i>x</i>86-64 version
+    of Debian, Ubuntu, Mint, or another Debian-based distribution, you can
+    install from this package, which was converted from the binary RPM
+    package using <tt>alien</tt>. Note that an <a href="#ppa">Ubuntu
+    PPA</a> is available, which may install more smoothly and will cause
+    rEFInd to automatically update with other packages.</li>
+
+<p class="sidebar"><b>Note:</b> At the moment, neither the bootable CD-R image file nor the bootable USB flash drive image file supports booting with Secure Boot active. The x86-64 version of the <a href="http://en.altlinux.org/Rescue">ALT Linux Rescue disc</a> uses a Secure Boot-enabled rEFInd, though, so you may find that useful in some situations.</p>
+
+<li><b><a
+    href="http://sourceforge.net/projects/refind/files/0.10.0/refind-cd-0.10.0.zip/download">A
+    CD-R image file</a></b>&mdash;This download contains the same files as
+    the binary zip file, but you can burn it to a CD-R to test rEFInd
+    (and its filesystem drivers) without installing it first. (It boots on
+    UEFI PCs, but fails on some older Macs.) If you like it, you can then
+    copy the files from the CD-R to your hard disk. The files are named in
+    such a way that the disc should boot on either 64-bit (<i>x</i>86-64)
+    or 32-bit (<i>x</i>86) EFI computers. I've included an open source EFI
+    shell program on this disc that's not included in the binary zip file,
+    so that you can access an EFI shell from a bootable disc even if you
+    don't have an EFI shell available from your regular hard disk. This can
+    be an extremely valuable diagnostic tool if you know how to use an EFI
+    shell.</li>
+
+<p class="sidebar"><b>Tip:</b> If you want to make your own bootable USB
+flash drive, download the binary zip file or CD-R image file, prepare a USB
+flash drive with a FAT32 partition, and then use the
+<tt>refind-install</tt> program's <tt>--usedefault</tt> option, and perhaps
+the <tt>--alldrivers</tt> option, as in <tt class="userinput">bash
+refind-install --usedefault /dev/sdd1 --alldrivers</tt> to install to the
+first partition on <tt>/dev/sdd</tt>. This procedure should work even on a
+BIOS-booted computer.</p>
+
+<li><b><a
+    href="http://sourceforge.net/projects/refind/files/0.10.0/refind-flashdrive-0.10.0.zip/download">A
+    USB flash drive image file</a></b>&mdash;Although you     can create
+    your own rEFInd USB flash drive, you may find it easier to download
+    this version and copy it to your USB drive with <tt>dd</tt> or some
+    other low-level disk copying utility.</li>
+
+<li><b><a
+    href="http://sourceforge.net/projects/refind/files/0.10.0/refind-src-0.10.0.tar.gz/download">A
+    source code tarball</a></b>&mdash;This is useful if you want to compile
+    the software locally. Note that I use Linux with the <a
+    href="https://sourceforge.net/projects/tianocore/">TianoCore EFI
+    Development Kit 2 (EDK2)</a> to build my binary packages (above),
+    although the <a
+    href="http://sourceforge.net/projects/gnu-efi">GNU-EFI</a> development
+    tools are also supported, and are used in building the Ubuntu PPA.</li>
+
+<li><b><a href="https://sourceforge.net/p/refind/code">Source code via
+    git</a></b>&mdash;If you want to peruse the source code in your Web
+    browser or get the very latest version (including pre-release bug fixes
+    and updates), you can use the Sourceforge git repository. This access
+    method is most useful to programmers, or at least to those who are
+    familiar with programming tools. If you need to ask "what's git?", this
+    is probably not the best way for you to obtain rEFInd.</li>
+
+</ul>
+
+<p>If you're using a platform other than <i>x</i>86 or <i>x</i>86-64, you can give rEFInd a try; however, you'll need to build it from source code yourself or track down a binary from another source. (Perhaps by the time you read this it will be included in Linux distributions built for unusual CPUs.)</p>
+
+<p>To extract the files from the zip file images I've provided, you'll need a tool such as <tt>unzip</tt>, which is included with Linux and Mac OS X. Numerous Windows utilities also support this format, such as <a href="http://www.pkware.com/software/pkzip/">PKZIP</a> and <a href="http://www.7-zip.org/">7-Zip.</a></p>
+
+<p>You should be able to create a bootable USB flash drive from either the binary zip file or the CD-R image file; just treat the flash drive as if it were a hard disk and install rEFInd as described on the <a href="installing.html">installation page.</a> Using the fallback boot loader name of <tt>EFI/boot/bootx64.efi</tt> is likely to be the most useful way to install rEFInd to a removable medium.</p>
+
+<h2>Getting rEFInd from Your OS's Repositories</h2>
+
+<p>I know of a small number of pre-packaged versions of rEFInd, either in official OS repositories or in ancillary repositories:</p>
+
+<ul>
+
+<li><a name="ppa"><b>Ubuntu</b></a>&mdash;Although an official Ubuntu
+    package isn't available, I've created a <a
+    href="https://launchpad.net/~rodsmith/+archive/refind">rEFInd PPA</a>
+    for Ubuntu. To use it, open a Terminal window and type <tt
+    class="userinput">sudo apt-add-repository ppa:rodsmith/refind</tt>,
+    then <tt class="userinput">sudo apt-get update</tt>. You can then type
+    <tt class="userinput">sudo apt-get install refind</tt> to install the
+    package. Thereafter, the rEFInd version will update along with your
+    other software. This package is built with GNU-EFI and is not signed
+    with a Secure Boot key; however, the install script (which launches
+    automatically when you install the package) should sign the binary with
+    a locally-generated key if it detects that your system uses Secure
+    Boot. Thus, if you've previously installed one of my binaries on a
+    Secure Boot system and added its key as a MOK, you'll have to add your
+    local key when you reboot.</li>
+
+<li><b>Arch Linux</b>&mdash;You can obtain rEFInd from the Arch
+    repositories, in both a stable version (the <tt>refind-efi</tt> package
+    installable via <tt>pacman</tt>) and an experimental release built from
+    rEFInd's git repository in the Arch User Repository (AUR), under the
+    name <tt>refind-efi-git</tt>. The git release is likely to include
+    pre-release bug fixes and new features, but those features may be
+    poorly tested or undocumented.</li>
+
+<li><b>ALT Linux</b>&mdash;This RPM-based distribution is experimenting
+    with using rEFInd on EFI-based computers. As I write, the ALT
+    developers haven't yet nailed down booting from an optical disc (it's a
+    tricky and delicate task, especially when preparing a "hybrid" image),
+    but they're working on the problem. They have an RPM of rEFInd; see <a
+    href="http://packages.altlinux.org/en/Sisyphus/srpms/refind">this
+    page</a> for details.</li>
+
+<li><b>Gentoo Linux</b>&mdash;An official ebuild of rEFInd is available;
+    see <a
+    href="https://packages.gentoo.org/packages/sys-boot/refind">here</a>
+    for details and <a href="https://wiki.gentoo.org/wiki/Refind">here</a>
+    for Gentoo's official rEFInd documentation.</a></li>
+
+<li><b>Slackware</b>&mdash;As far as I know, an official rEFInd package is
+    not available as part of Slackware; however, a <a
+    href="http://slackbuilds.org/repository/14.1/system/refind/?search=refind">Slackware
+    package from SlackBuilds</a> is available.</li>
+
+<li><b><a href="http://distro.ibiblio.org/fatdog/web/">Fat
+    Dog</a></b>&mdash;This variant of Puppy Linux uses a combination of
+    rEFInd and GRUB 2 to boot its installation medium in EFI mode and
+    provides a rEFInd package in its repository set.</li>
+
+<li><b>The <a href="http://nixos.org/nixpkgs/">Nix Packages
+    collection</a></b>&mdash;This site creates packages for a number of
+    OSes using its own packaging system.</li>
+
+</ul>
+
+<p>To the best of my knowledge, no other Linux distribution yet includes rEFInd in its repositories. That's likely to change in time. If you hear of rEFInd being included in an OS's official package set, feel free to <a href="mailto:rodsmith@rodsbooks.com">drop me a line.</a></p>
+
+<hr />
+
+<p>copyright &copy; 2012&ndash;2015 by Roderick W. Smith</p>
+
+<p>This document is licensed under the terms of the <a href="FDL-1.3.txt">GNU Free Documentation License (FDL), version 1.3.</a></p>
+
+<p>If you have problems with or comments about this Web page, please e-mail me at <a href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.com.</a> Thanks.</p>
+
+<p><a href="index.html">Go to the main rEFInd page</a></p>
+
+<p><a href="installing.html">Learn how to install rEFInd</a></p>
+
+  <p><a href="http://www.rodsbooks.com/">Return</a> to my main Web page.</p>
+</body>
+</html>
diff --git a/docs/refind/index.html b/docs/refind/index.html
new file mode 100644 (file)
index 0000000..1d7ebe0
--- /dev/null
@@ -0,0 +1,277 @@
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>The rEFInd Boot Manager</title>
+  <link href="../Styles/styles.css" rel="stylesheet" type="text/css" />
+</head>
+
+<meta name="viewport" content="width=device-width, initial-scale=1">
+
+<body>
+  <h1>The rEFInd Boot Manager</h1>
+
+  <p class="subhead">by Roderick W. Smith, <a
+href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.com</a></p>
+
+<p>Originally written: 3/14/2012; last Web page update:
+11/8/2015, referencing rEFInd 0.10.0</p>
+
+
+<p>This Web page is provided free of charge and with no annoying outside ads; however, I did take time to prepare it, and Web hosting does cost money. If you find this Web page useful, please consider making a small donation to help keep this site up and running. Thanks!</p>
+
+<table border="1">
+<tr>
+<td>Donate $1.00</td>
+<td>Donate $2.50</td>
+<td>Donate $5.00</td>
+<td>Donate $10.00</td>
+<td>Donate $20.00</td>
+<td>Donate another value</td>
+</tr>
+<tr>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="1.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="2.50">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="5.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="10.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="20.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td></tr>
+</table>
+
+<hr />
+
+<h2>Introduction</h2>
+
+<p>This page describes rEFInd, my fork of the <a href="http://refit.sourceforge.net">rEFIt</a> boot manager for computers based on the <a href="http://en.wikipedia.org/wiki/Unified_Extensible_Firmware_Interface">Extensible Firmware Interface (EFI) and Unified EFI (UEFI).</a> Like rEFIt, rEFInd is a <i>boot manager,</i> meaning that it presents a menu of options to the user when the computer first starts up, as shown below. rEFInd is not a <i>boot loader,</i> which is a program that loads an OS kernel and hands off control to it. (Since version 3.3.0, the Linux kernel has included a built-in boot loader, though, so this distinction is rather artificial these days, at least for Linux.) Many popular boot managers, such as <a href="http://www.gnu.org/software/grub/">the Grand Unified Bootloader (GRUB),</a> are also boot loaders, which can blur the distinction in many users' minds. All EFI-capable OSes include boot loaders, so this limitation isn't a problem. If you're using Linux, you should be aware that several EFI boot loaders are available, so choosing between them can be a challenge. In fact, the Linux kernel can function as an EFI boot loader for itself, which gives rEFInd characteristics similar to a boot loader for Linux. See <a href="http://www.rodsbooks.com/efi-bootloaders/index.html">my Web page on this topic</a> for more information.</p>
+
+    <br /><center><img src="refind.png" align="center" width="750"
+    height="558" alt="rEFInd presents a graphical menu for selecting your
+    boot OS." border=2> </center><br />
+
+<div style="float:right; width:55%">
+
+<p>In theory, EFI implementations should provide boot managers. Unfortunately, in practice these boot managers are often so poor as to be useless. The worst I've personally encountered is on <a href="http://www.rodsbooks.com/gb-hybrid-efi/">Gigabyte's Hybrid EFI,</a> which provides you with no boot options whatsoever, beyond choosing the boot device (hard disk vs. optical disc, for instance). I've heard of others that are just as bad. For this reason, a good EFI boot manager&mdash;either standalone or as part of a boot loader&mdash;is a practical necessity for multi-booting on an EFI computer. That's where rEFInd comes into play.</p>
+
+<p>I decided to fork the earlier rEFIt project because, although rEFIt is a useful program, it's got several important limitations, such as poor control over the boot loader detection process and an ability to display at most a handful of boot loader entries on its main screen. Christoph Pfisterer, rEFIt's author, stopped updating rEFIt with version 0.14, which was released in March of 2010. Since I forked rEFIt to rEFInd, Christoph has begun pointing rEFIt users to rEFInd as a successor project.</p>
+
+<p>As already noted, rEFInd is a boot manager for EFI and UEFI computers. (I use "EFI" to refer to either version unless the distinction is important.) You're likely to benefit from it on computers that boot multiple OSes, such as two or more of Linux, Mac OS X, and Windows. You will <i>not</i> find rEFInd useful on older BIOS-based computers or on systems with other types of firmware, such as older PowerPC-based Macs. Prior to mid-2011, few computers outside of Intel-based Macs used EFI; but starting in 2011, computer manufacturers began adopting UEFI in droves, so most computers bought since then use EFI. Even so, many modern PCs support both EFI-style booting and BIOS-style booting, the latter via a BIOS compatibility mode that's known as the <i>Compatibility Support Module (CSM).</i> Thus, you may be using BIOS-style booting on an EFI-based computer. If you're unsure which boot method your computer uses, check the first of the subsections, <a href="bootmode.html">What's Your Boot Mode</a>.</p>
+
+<p>Subsequent sections of this document are on separate pages. Be aware that you probably don't need to read them all; just skip to the sections that interest you:</p>
+
+<p><b>Note:</b> I consider rEFInd to be <i>beta-quality software!</i> That said, rEFInd is a usable program in its current form on many systems. If you have problems, feel free to drop me a line.</p>
+
+</div>
+
+<div class="navbar">
+
+<h4 class="tight">Contents</h4>
+
+<ul>
+
+<li class="tight"><a href="bootmode.html">What's Your Boot Mode?</a>&mdash;Information to help you determine whether you're using EFI or BIOS booting</li>
+
+<li class="tight"><a href="features.html">rEFInd Features</a>&mdash;An overview of rEFInd's features</li>
+
+<li class="tight"><a href="getting.html">Getting rEFInd</a>&mdash;Links to download rEFInd</li>
+
+<li class="tight"><a href="installing.html">Installing rEFInd</a>&mdash;Instructions for installing rEFInd, using Linux, OS X, and Windows</li>
+
+<li class="tight"><a href="yosemite.html">rEFInd and OS X 10.10 (Yosemite)</a>&mdash;Apple's latest OS X makes some changes that require your attention (this subpage is rendered obsolete by rEFInd 0.8.4 and later</li>
+
+<li class="tight"><a href="sip.html">rEFInd and System Integrity Protection</a>&mdash;How to install rEFInd on Macs running OS X 10.11 (El Capitan)</a>
+
+<li class="tight"><a href="using.html">Using rEFInd</a>&mdash;Basic usage instructions for the boot loader</li>
+
+<li class="tight"><a href="configfile.html">Configuring the Boot Manager</a>&mdash;For advanced users, information on customizing a rEFInd installation</li>
+
+<li class="tight"><a href="drivers.html">Using EFI Drivers</a>&mdash;Why and how to have rEFInd launch EFI drivers</li>
+
+<li class="tight"><a href="themes.html">Theming rEFind</a>&mdash;Information on third-party themes for rEFInd</li>
+
+<li class="tight"><a href="linux.html">Options for Booting Linux</a>&mdash;Methods of booting Linux, particularly with the EFI stub loader (distribution maintainers should read this!)</li>
+
+<li class="tight"><a href="secureboot.html">Managing Secure Boot</a>&mdash;Some pointers on using rEFInd on a computer with Secure Boot active</li>
+
+<li class="tight"><a href="revisions.html">Revisions</a>&mdash;Information on the history of rEFInd releases</li>
+
+<li class="tight"><a href="todo.html">The Future of rEFInd</a>&mdash;Current bugs that need squashing and features that I hope to one day add</a></li>
+
+<hr />
+
+<li class="tight">Manual (man) pages for rEFInd support scripts:
+
+  <ul>
+
+  <li><a href="mkrlconf.html"><tt>mkrlconf</tt></a>&mdash;This Linux-only tool creates a <tt>/boot/refind_linux.conf</tt> file to hold Linux kernel options.</li>
+
+  <li><a href="mvrefind.html"><tt>mvrefind</tt></a>&mdash;This Linux-only script moves a rEFInd installation from one location to another on the EFI System Partition (ESP).</li>
+
+  <li><a href="refind-install.html"><tt>refind-install</tt></a>&mdash;This Linux and OS X script installs rEFInd with minimal fuss.</li>
+
+</ul></li>
+
+</ul>
+
+</div>
+
+<a name="references">
+<h2>References and Additional Information</h2>
+</a>
+
+<ul>
+
+<li><b>Informational Web pages</b>
+
+<ul>
+
+<li><a href="http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/efi-boot-process.html">The EFI Boot Process</a> describes, in broad strokes, how EFI systems boot.</li>
+
+<li><a href="https://lkml.org/lkml/2011/10/17/81">A Linux kernel mailing list thread</a> describing the new EFI stub loader that was introduced in the Linux 3.3 kernel series.</li>
+
+<li>The <a href="https://wiki.archlinux.org/index.php/Unified_Extensible_Firmware_Interface">Arch Linux UEFI wiki page</a> has a great deal of information on UEFI and Linux.</li>
+
+<li>My own <a href="http://www.rodsbooks.com/efi-bootloaders/">EFI Boot Loaders for Linux</a> page provides information on installing and configuring several common Linux EFI boot loaders and boot managers.</li>
+
+<li><a href="http://www.rodsbooks.com/linux-uefi/">My Linux on UEFI: A Quick Installation Guide</a> page provides helpful tips on how to install Linux on EFI-based systems.</li>
+
+<li>Phoenix Technologies maintains a <a href="http://wiki.phoenix.com/wiki/index.php/Main_Page">wiki on EFI topics,</a> including <a href="http://wiki.phoenix.com/wiki/index.php/Category:UEFI_2.0">information on many EFI system calls</a> useful to programmers.</li>
+
+<li>Matthew J. Garrett, the developer of the shim boot loader to manage Secure Boot, maintains <a href="http://mjg59.dreamwidth.org/">a blog</a> in which he often writes about EFI issues.</li>
+
+<li>Adam Williamson has written a good <a href="https://www.happyassassin.net/2014/01/25/uefi-boot-how-does-that-actually-work-then/">summary of what EFI is and how it works.</a></li>
+
+<li>J. A. Watson has a <a href="http://www.zdnet.com/the-refind-boot-loader-for-uefi-systems-7000010275/">review of rEFInd on an HP laptop</a> on ZDNet. He had serious problems because of the HP's UEFI bugs, but finally got it to work.</li>
+
+<li>James Jesudason has a tutorial on installing Ubuntu 13.04 beta on a Macbook Retina Pro on <a href="http://randomtutor.blogspot.com/2013_02_01_archive.html">this blog page.</a> I'd recommend using a Linux filesystem driver to read the kernel directly from a Linux filesystem rather than copy the kernel to the OS X partition as in the tutorial, but either method will work.</li>
+
+<li><a href="http://sdnalloh.com/converting-win7-from-mbr-to-gpt/">This blog post</a> describes how to convert Windows from BIOS-mode to EFI-mode booting. This task is rarely necessary, but when you need it, you <i>really</i> need it.</li>
+
+<li>If you're interested in developing EFI software yourself, my <a href="http://www.rodsbooks.com/efi-programming/">Programming for EFI</a> can help you get started.</li>
+
+</ul></li> <!-- Informational Web pages -->
+
+<li><b>Additional programs</b>
+
+<ul>
+
+<li><a href="http://refit.sourceforge.net">The official rEFIt Web page</a></li>
+
+<li><a href="http://freedesktop.org/wiki/Software/gummiboot">The official gummiboot Web page</a></li>
+
+<li><a href="http://elilo.sourceforge.net/">The official ELILO Web page</a></li>
+
+<li><a href="http://www.gnu.org/software/grub/">The official GRUB Web page</a></li>
+
+<li><a href="http://www.rodsbooks.com/gdisk/">The official GPT fdisk partitioning software Web page</a></li>
+
+<li>The <a href="http://sourceforge.net/projects/cloverefiboot/">Clover</a> boot loader is a Hackintosh boot loader that incorporates, among other things, its own unique forks of rEFIt and of DUET (a <a href="http://sourceforge.net/apps/mediawiki/tianocore/index.php?title=Welcome">TianoCore</a> tool to boot UEFI on BIOS-based computers).</li>
+
+<li>Pete Batard's <a href="https://github.com/pbatard/efifs">efifs</a> project aims to port GRUB's filesystem drivers to function as standalone EFI filesystem drivers. It's currently a work in progress but shows great promise, and several drivers are usable for limited purposes today.</li>
+
+</ul></li> <!-- Additional programs -->
+
+<li><b>Communications</b>
+
+<ul>
+
+<li>The <a href="https://sourceforge.net/p/refind/discussion/">rEFInd discussion forum on Sourceforge</a> provides a way to discuss rEFInd with other users or with me.</li>
+
+<li>You can <a href="mailto:rodsmith@rodsbooks.com">e-mail me</a> with queries or bug reports.</li>
+
+<li><a href="http://forums.macrumors.com/showthread.php?t=696523">This thread</a> on MacRumors details efforts to boot Windows 7 and Windows 8 in EFI mode, rather than using Boot Camp, on 64-bit Macs. It can be done with some models, but is difficult, particularly for Windows 7. Be aware that the thread is long and has many false leads.</li>
+
+</ul></li>
+
+</ul>
+
+<hr />
+
+<p>copyright &copy; 2012&ndash;2015 by Roderick W. Smith</p>
+
+<p>This document is licensed under the terms of the <a href="FDL-1.3.txt">GNU Free Documentation License (FDL), version 1.3.</a></p>
+
+<p>If you have problems with or comments about this Web page, please e-mail me at <a href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.com.</a> Thanks.</p>
+
+  <p><a href="http://www.rodsbooks.com/">Return</a> to my main Web page.</p>
+</body>
+</html>
diff --git a/docs/refind/installing.html b/docs/refind/installing.html
new file mode 100644 (file)
index 0000000..f32308c
--- /dev/null
@@ -0,0 +1,1103 @@
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>The rEFInd Boot Manager: Installing rEFInd</title>
+  <link href="../Styles/styles.css" rel="stylesheet" type="text/css" />
+</head>
+
+<meta name="viewport" content="width=device-width, initial-scale=1">
+
+<body>
+  <h1>The rEFInd Boot Manager:<br />Installing rEFInd</h1>
+
+<p class="subhead">by Roderick W. Smith, <a
+href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.com</a></p>
+
+<p>Originally written: 3/14/2012; last Web page update:
+11/8/2015, referencing rEFInd 0.10.0</p>
+
+
+<p>This Web page is provided free of charge and with no annoying outside ads; however, I did take time to prepare it, and Web hosting does cost money. If you find this Web page useful, please consider making a small donation to help keep this site up and running. Thanks!</p>
+
+<table border="1">
+<tr>
+<td>Donate $1.00</td>
+<td>Donate $2.50</td>
+<td>Donate $5.00</td>
+<td>Donate $10.00</td>
+<td>Donate $20.00</td>
+<td>Donate another value</td>
+</tr>
+<tr>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="1.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="2.50">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="5.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="10.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="20.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td></tr>
+</table>
+
+<hr />
+
+<p>This page is part of the documentation for the rEFInd boot manager. If a Web search has brought you here, you may want to start at the <a href="index.html">main page.</a></p>
+
+<hr />
+
+<div style="float:right; width:55%">
+
+<p><b>Don't be scared by the length of this page!</b> Only portions of this page apply to any given user, and most people can install rEFInd from an RPM or Debian package in a matter of seconds or by using the <tt>refind-install</tt> script in minute or two.</p>
+
+<p>Once you've obtained a rEFInd binary file, as described on <a href="getting.html">the preceding page,</a> you must install it to your computer's EFI System Partition (ESP) (or conceivably to some other location). The details of how you do this depend on your OS and your computer (UEFI-based PC vs. Macintosh). The upcoming sections provide details. See the Contents sidebar to the left for links to specific installation procedures. For most Linux users, an RPM or Debian package is the best way to go. If your Linux system doesn't support these formats, though, or if you're running OS X, using the <tt>refind-install</tt> script can be a good way to go. If you're using Windows, you'll have to install manually.</p>
+
+<p class="sidebar" style="width:95%"><b>Important:</b> A rEFInd zip file, when uncompressed, creates a directory called <tt>refind-<i>version</i></tt>, where <tt><i>version</i></tt> is the version number. This directory includes a subdirectory called <tt>refind</tt> that holds the rEFInd binary along with another that holds documentation, as well as miscellaneous files in <tt>refind-<i>version</i></tt> itself. When I refer to "the <tt>refind</tt> directory" on this page, I mean the directory with that precise name, not the <tt>refind-<i>version</i></tt> directory that is its parent.</p>
+
+</div>
+
+<div class="navbar">
+
+<h4 class="tight">Contents</h4>
+
+<ul class="tight">
+
+<li class="tight"><a href="#packagefile">Installing rEFInd using an RPM or Debian package file</a></li>
+
+<li class="tight"><a href="#installsh">Installing rEFInd Using <tt>refind-install</tt> under Linux or Mac OS X</a>
+
+<li class="tight"><a href="#manual">Installing rEFInd Manually</a>
+
+   <ul>
+
+   <li class="tight"><a href="#linux">Installing rEFInd Manually Using Linux</a></li>
+
+   <li class="tight"><a href="#osx">Installing rEFInd Manually Using Mac OS X</a></li>
+
+   <li class="tight"><a href="#windows">Installing rEFInd Manually Using Windows</a></li>
+
+   <li class="tight"><a href="#efishell">Installing rEFInd Manually Using an EFI Shell</a></ul></li>
+
+<li class="tight"><a href="#naming">Alternative Naming Options</a>
+
+   <ul>
+
+   <li class="tight"><a href="#mvrefind">Using <tt>mvrefind</tt></li>
+
+   <li class="tight"><a href="#manual_renaming">Renaming Files Manually</li>
+
+   </ul></li>
+
+<li class="tight"><a href="#upgrading">Upgrading rEFInd</a></li>
+
+<li class="tight"><a href="#addons">Installing Additional Components</a></li>
+
+<li class="tight"><a href="#sluggish">Fixing a  Macintosh Boot</a>
+
+   <ul>
+
+   <li class="tight"><a href="#shortform">Using the <tt>--shortform</tt> Option</a></li>
+
+   <li class="tight"><a href="#fallback">Using the Fallback Filename</a></li>
+
+   <li class="tight"><a href="#moving">Moving rEFInd to an HFS+ Volume</a></li>
+
+   <li class="tight"><a href="#clearing">Clearing the NVRAM Entries</a></li>
+
+   <li class="tight"><a href="#wakeprobs">Fixing Wake Problems</a></li>
+
+   <li class="tight"><a href="#nolinux">Fixing a Failure to Find Linux</a></li>
+
+   </ul></li>
+
+<li class="tight"><a href="#winprob">Fixing Windows Boot Problems</a></li>
+
+<li class="tight"><a href="#uninstalling">Uninstalling rEFInd</a>
+
+   <ul>
+
+   <li class="tight"><a href="#uinst_linux">Uninstalling rEFInd from Linux</a></li>
+
+   <li class="tight"><a href="#uinst_osx">Uninstalling rEFInd from OS X</a></li>
+
+   <li class="tight"><a href="#uinst_windows">Uninstalling rEFInd from Windows</a></li>
+
+   <li class="tight"><a href="#post_uninst">Post-Uninstallation Activity (UEFI-Based PCs)</a></li>
+
+</ul></ul></li>
+
+</div>
+
+<a name="packagefile">
+<h2>Installing rEFInd Using an RPM or Debian Package File</h2>
+</a>
+
+<p>I provide RPM and Debian package files for rEFInd; and starting with version 0.8.1, I'm maintaining an Ubuntu PPA for rEFInd. If you have a working RPM-based or Debian-based Linux installation that boots in EFI mode, using one of these files is likely to be the easiest way to install rEFInd: You need only download the file and issue an appropriate installation command. In some cases, double-clicking the package in your file manager will install it. If that doesn't work, a command like the following will install the RPM on an RPM-based system:</p>
+
+<pre class="listing"># <tt class="userinput">rpm -Uvh refind-0.10.0-1.x86_64.rpm</tt></pre>
+
+<p>On a Debian-based system, the equivalent command is:</p>
+
+<pre class="listing"># <tt class="userinput">dpkg -i refind_0.10.0-1_amd64.deb</tt></pre>
+
+<p>Either command produces output similar to that described for <a href="#installsh">using the <tt>refind-install</tt> script,</a> so you can check it for error messages and other signs of trouble. The package file installs rEFInd and registers it with the EFI to be the default boot loader. The script that runs as part of the installation process tries to determine if you're using Secure Boot, and if so it will try to configure rEFInd to launch using shim; however, this won't work correctly on all systems. Ubuntu 12.10 users who are booting with Secure Boot active should be wary, since the resulting installation will probably try to use Ubuntu's version of shim, which won't work correctly with rEFInd. The shim program provided with more recent versions of Ubuntu should work correctly.</p>
+
+<a name="ppa">
+<p>If you're using Ubuntu, you should be able to install the PPA as follows:</p></a>
+
+<pre class="listing">$ <tt class="userinput">sudo apt-add-repository ppa:rodsmith/refind</tt>
+$ <tt class="userinput">sudo apt-get update</tt>
+$ <tt class="userinput">sudo apt-get install refind</tt></pre></pre>
+
+<p>The PPA version will update automatically with your other software, which you might or might not want to have happen. It's also built with GNU-EFI rather than with TianoCore. This last detail <i>should</i> have no practical effects, but it might be important if you've got a buggy EFI or if there's some undiscovered rEFInd bug that interacts with the build environment.</p>
+
+<p>Since version 0.6.3, the installation script makes an attempt to install rEFInd in a bootable way even if you run the script from a BIOS-mode boot, and therefore the RPM and Debian packages do the same. I cannot guarantee that this will work, though, and even if it does, some of the tricks that <tt>refind-install</tt> uses might not persist for long. You might therefore want to use <tt><a href="#mvrefind">mvrefind</a></tt> to move your rEFInd installation to another name after you boot Linux for the first time from rEFInd.</p>
+
+<p>Since version 0.6.2-2, my package files have installed the rEFInd binaries to <tt>/usr/share/refind-<tt class="variable">version</tt></tt>, the documentation to <tt>/usr/share/doc/refind-<tt class="variable">version</tt></tt>, and a few miscellaneous files elsewhere. (The PPA package omits the version number from the file paths.) Upon installation, the package runs the <tt>refind-install</tt> script to copy the files to the ESP. This enables you to re-install rEFInd after the fact by running <tt>refind-install</tt>, should some other tool or OS wipe the ESP or should the installation go awry. In such cases you can <a href="#installsh">use <tt>refind-install</tt></a> or <a href="#manual">install manually.</a></p>
+
+<a name="installsh">
+<h2>Installing rEFInd Using <tt>refind-install</tt> under Linux or Mac OS X</h2>
+
+<p class="sidebar"><b>Note:</b> If you're using a Macintosh, it's best to install rEFInd from OS X, if possible. In the past, the Mac's firmware was quirky enough that the Linux tools didn't always work reliably. The matter seems to have improved with recent versions of Linux tools, but I can't guarantee success if you use Linux for this task. There is one significant issue with OS X 10.11, though (see the next Warning sidebar).</p>
+
+<p>If you're using Linux or Mac OS X, the easiest way to install rEFInd is to use the <tt>refind-install</tt> script. This script automatically copies rEFInd's files to your ESP or other target location and makes changes to your firmware's NVRAM settings so that rEFInd will start the next time you boot. If you've booted to OS X or in non-Secure-Boot EFI mode to Linux on a UEFI-based PC, <tt>refind-install</tt> will probably do the right thing, so you can get by with the quick instructions. If your setup is unusual, if your computer uses Secure Boot, or if you want to create a USB flash drive with rEFInd on it, you should read the <a href="#extra_installsh">extra instructions</a> for this utility.</p>
+
+<p class="sidebar"><b>Warning:</b> OS X 10.11 ("El Capitan") implements a new feature called System Integrity Protection (SIP; aka "rootless" or "CSR"). When enabled, SIP prevents the final step of rEFInd installation&mdash;registering the boot loader with the firmware. Thus, to install rEFInd, you must either disable SIP or perform the installation from something other than your regular OS X installation. The <a href="sip.html">rEFInd and System Integrity Protection</a> page of this document describes the options.</p>
+
+<p>By default, the <tt>refind-install</tt> script installs rEFInd to your disk's ESP. Under Mac OS X, you can instead install rEFInd to your current OS X boot partition by passing the script the <tt>--notesp</tt> option, or to a non-boot HFS+ partition by using the <tt>--ownhfs <tt class="variable">devicefile</tt></tt> option. Under either OS, you can install to something other than the currently-running OS by using the <tt>--root <tt class="variable">/mountpoint</tt></tt> option. (See <a href="#table1">Table 1</a> for details.)</p>
+
+<p>Under Linux, <tt>refind-install</tt> will be most reliable if your ESP is already mounted at <tt>/boot</tt> or <tt>/boot/efi</tt>, as described in more detail in the <a href="#linux">Installing rEFInd Manually Using Linux</a> section. (If you installed Linux in EFI mode, chances are your ESP is properly mounted.) If your ESP is not so mounted, <tt>refind-install</tt> will attempt to locate and mount an ESP, but this action is not guaranteed to work correctly. If you run <tt>refind-install</tt> from a BIOS/legacy-mode boot, particularly on a computer that also runs Windows, you should be aware that the tricks the script uses to install itself from BIOS mode are rather delicate. You can convert to a more conventional configuration using the <a href="#mvrefind"><tt>mvrefind</tt> script</a> after you've booted in EFI mode.</p>
+
+<p>Prior to version 0.8.4, <tt>refind-install</tt> installed rEFInd to the OS X root partition by default. I changed this because the default configuration for OS X 10.10 ("Yosemite") makes this placement unusable. Instead, <tt>refind-install</tt> now installs to the ESP under OS X, just as it does under Linux. <i>If you're upgrading a working install of rEFInd to the OS X root partition, it's best to pass the <tt>--notesp</tt> option to <tt>refind-install</tt>.</i> This option is described in more detail shortly.</p>
+
+<p>A sample run under Linux looks something like this:</p>
+
+<pre class="listing">
+# <tt class="userinput">./refind-install</tt>
+Installing rEFInd on Linux....
+ESP was found at /boot/efi using vfat
+Installing driver for ext4 (ext4_x64.efi)
+Copied rEFInd binary files
+
+Copying sample configuration file as refind.conf; edit this file to configure
+rEFInd.
+
+
+Installation has completed successfully.</pre>
+
+<p>The output under OS X is a bit different:</p>
+
+<pre class="listing">
+$ <tt class="userinput">./refind-install</tt>
+Not running as root; attempting to elevate privileges via sudo....
+Password:
+Installing rEFInd on OS X....
+Installing rEFInd to the partition mounted at /Volumes/ESP
+Found suspected Linux partition(s); installing ext4fs driver.
+Installing driver for ext4 (ext4_ia32.efi)
+Copied rEFInd binary files
+
+Copying sample configuration file as refind.conf; edit this file to configure
+rEFInd.
+
+
+WARNING: If you have an Advanced Format disk, *DO NOT* attempt to check the
+bless status with 'bless --info', since this is known to cause disk corruption
+on some systems!!
+
+
+Installation has completed successfully.
+
+Unmounting install dir</pre>
+
+<p>In either case, the details of the output differ depending on your existing configuration and how you ran the program. Unless you see an obvious warning or error, you shouldn't be concerned about minor deviations from these examples. If you run into such a situation, or if you want to install in an unusual way, read on....</p>
+
+<p>Note that the change to an ESP location for rEFInd with version 0.8.4 means that, if you upgrade rEFInd from an earlier version, you may notice a rEFInd boot option in the rEFInd menu. This option will boot the old version of rEFInd (or the new one, if something went wrong and the old version continues to boot). You can rid yourself of the unwanted boot menu by deleting the old files or by using <tt>dont_scan_dirs</tt> or <tt>dont_scan_files</tt> in <tt>refind.conf</tt>. Before you do this, you should use rEFInd to identify the unwanted files&mdash;the filename and volume identifier appear under the icons when you highlight the option. You can then locate and delete them from within OS X. Before you delete the old files, though, you may want to copy over any changes you've made to the rEFInd configuration, icons, and other support files.</p>
+
+<p>The <tt>refind-install</tt> script supports a number of options that can affect how it operates. For information on these options, consult the script's man page: Type <tt class="userinput">man refind-install</tt> if you installed rEFInd via an RPM or Debian package; or read it in <a href="refind-install.html">HTML form.</a></p>
+
+<a name="manual">
+<h2>Installing rEFInd Manually</h2>
+</a>
+
+<p>Sometimes the <tt>refind-install</tt> script just won't do the job, or you may need to install using an OS that it doesn't support, such as Windows. In these cases, you'll have to install rEFInd the old-fashioned way, using file-copying commands and utilities to add the program to your EFI's boot loader list. I describe how to do this with <a href="#linux">Linux</a>, <a href="#osx">OS X</a>, <a href="#windows">Windows</a>, and <a href="#efishell">the EFI shell.</a></p>
+
+<a name="linux">
+<h3>Installing rEFInd Manually Using Linux</h3>
+</a>
+
+<p>On a UEFI-based PC, you'll normally install rEFInd to the ESP, which is usually mounted at <tt>/boot/efi</tt>. You can verify that this is the case by using the <tt>df</tt> command:</p>
+
+<pre class="listing">
+$ <b>df /boot/efi</b>
+Filesystem     1K-blocks  Used Available Use% Mounted on
+/dev/sda1         191284 16604    174681   9% /boot/efi
+</pre>
+
+<p class="sidebar"><b>Note:</b> If you're running Linux on a Mac, I recommend you install rEFInd under OS X. The Mac's boot process deviates a bit from EFI standards, and older versions of <tt>efibootmgr</tt> didn't always work properly on Macs. This problem seems to have gone away with more recent versions of <tt>efibootmgr</tt>, but using OS X may still be more reliable. On the other hand, Apple's new (as of OS X 10.11) System Integrity Protection (SIP) feature blocks the use of <tt>bless</tt> under OS X and so prevents rEFInd installation. The <a href="sip.html">rEFInd and System Integrity Protection</a> page of this document covers how to overcome SIP and install rEFInd. One of these methods is to do the job from Linux.</p>
+
+<p>This example shows that <tt>/dev/sda1</tt> is mounted at <tt>/boot/efi</tt>, which is a typical configuration. (The ESP can be on another disk or partition, but <tt>/dev/sda1</tt> is the most common place for an ESP.) If your output shows <tt>/boot</tt> or <tt>/</tt> under the <tt>Mounted on</tt> column, then your ESP isn't mounted. (An exception is if you're mounting the ESP at <tt>/boot</tt>. This is an unusual configuration. If you're using it, you can proceed, making suitable adjustments to subsequent commands.) If you get a <tt>df: `/boot/efi': No such file or directory</tt> error message, then the <tt>/boot/efi</tt> directory doesn't even exist. In such cases, you may need to jump through some extra hoops, as described on my <a href="http://www.rodsbooks.com/efi-bootloaders/installation.html">EFI Boot Loader Installation</a> page.</p>
+
+<p>Assuming the ESP is mounted at <tt>/boot/efi</tt>, you can install the rEFInd files as follows (you must be <tt>root</tt> to issue these commands, or precede each of them with <tt><b>sudo</b></tt>):</p>
+
+<ol>
+
+<li>Type <tt><b>cp -r refind /boot/efi/EFI/</b></tt> from the <tt>refind-<i>version</i></tt> directory in which the <tt>refind</tt> directory exists. This copies all the files that rEFInd needs to work. Note that this includes <i>all</i> of rEFInd's drivers. This command also copies the rEFInd binaries as signed by me; if you prefer to re-sign the binaries yourself, you'll have to do so before or during the copy operation, as described on the <a href="secureboot.html">Managing Secure Boot</a> page.</li>
+
+<li>Type <tt><b>cd /boot/efi/EFI/refind</b></tt> to change into rEFInd's new directory on the ESP.</li>
+
+<li>Type <tt><b>rm refind_ia32.efi</b></tt> to remove the IA32 binary if you're using an <i>x</i>86-64 (64-bit) system; or type <tt><b>rm refind_x64.efi</b></tt> to remove the <i>x</i>86-64 binary if you're using an <i>x</i>86 (32-bit) system. (Note that you must keep the version that's the correct bit width for your EFI; if you've installed a 32-bit Linux on a 64-bit PC with a 64-bit EFI, you'd keep <tt>refind_x64.efi</tt>.</li>
+
+<li>Optionally, type <tt class="userinput">rm -r drivers_ia32</tt> to remove the <i>x</i>86 drivers from an <i>x</i>86-64 system, or <tt class="userinput">rm -r drivers_x64</tt> to remove the <i>x</i>86-64 drivers from a 32-bit <i>x</i>86 system. You may also want to remove some or all of the drivers for the architecture you are using. If you don't need them, they'll slow down the start process, and worse, loading unnecessary drivers can cause some systems to hang or interfere with the drivers you do need. See the <a href="drivers.html">page on drivers</a> for more on this topic.</li>
+
+<li>Rename the configuration file by typing <tt><b>mv refind.conf-sample refind.conf</b></tt>. Consult the <a href="configfile.html">Editing the rEFInd Configuration File</a> page for information on how to adjust your options.</li>
+
+<p class="sidebar"><b>Weird:</b> A <a href="http://mjg59.dreamwidth.org/20187.html">bug exists</a> in some Lenovo computers (and perhaps in some others, too) that causes the firmware's boot manager to refuse to boot any boot loader that doesn't have the name <tt>Windows Boot Manager</tt> or <tt>Red Hat Enterprise Linux</tt>. If you have such a system, you must pass one of those names (in quotes) rather than <tt>rEFInd</tt> to <tt>efibootmgr</tt> via its <tt>-L</tt> option. This bug was reported to Lenovo in mid-November 2012, and by late 2013, at least some Lenovos were mercifully free of this bug.</p>
+
+<a name="efibootmgr">
+<li>On a UEFI-based system, type <tt><b>efibootmgr -c -l \\EFI\\refind\\refind_x64.efi -L rEFInd</b></tt> to add rEFInd to your EFI's list of available boot loaders, which it stores in NVRAM. Adjust the path to the binary as required if you install somewhere else. You may also need to include additional options if your ESP isn't on <tt>/dev/sda1</tt> or if your configuration is otherwise unusual; consult the <tt>efibootmgr</tt> man page for details. You may need to install this program on some systems; it's a standard part of most distributions' repositories. Also, if you're installing in Secure Boot mode, you must normally register <tt>shim.efi</tt> rather than the rEFInd binary, and rename <tt>refind_x64.efi</tt> to <tt>grubx64.efi</tt>. Shim 0.7 and later enables you to keep rEFInd's usual name by adding a <tt>-u "shim.efi refind_x64.efi"</tt> option to your <tt>efibootmgr</tt> command line, though. Change the filenames to the ones used by your actual Shim and rEFInd binaries, respectively.</li>
+</a>
+
+<li>If other boot loaders are already installed, you can use <tt>efibootmgr</tt> to adjust their boot order. For instance, <b><tt>efibootmgr -o 3,7,2</tt></b> sets the firmware to try boot loader #3 first, followed by #7, followed by #2. (The program should have displayed a list of boot loaders when you added yours in the preceding step.) Place rEFInd's number first to set it as the default boot program.</li>
+
+</ol>
+
+<p>Note the use of doubled-up backslashes (<tt>\\</tt>) rather than forward slashes (<tt>/</tt>) in the directory separators when using <tt>efibootmgr</tt>. This command will work on most systems that are already booted into EFI mode; however, it won't work if you're booted in BIOS mode. You may also need to add options if your ESP is in some unusual location or if your system is unusual in some way. Consult the <tt>efibootmgr</tt> man page if you need help.</p>
+
+<p>On some systems, <tt>efibootmgr</tt> won't do what you expect. On such systems, you may have better luck renaming the rEFInd files, as described in the <a href="#naming">Alternative Naming Options</a> section.</p>
+
+<a name="osx">
+<h3>Installing rEFInd Manually Using Mac OS X</h3>
+</a>
+
+<p class="sidebar"><b>Warning:</b> OS X 10.11 ("El Capitan") implements a new feature called System Integrity Protection (SIP; aka "rootless" or "CSR"). When enabled, SIP prevents the final step of rEFInd installation&mdash;registering the boot loader with the firmware. Thus, to install rEFInd, you must either disable SIP or perform the installation from something other than your regular OS X installation. The <a href="sip.html">rEFInd and System Integrity Protection</a> page of this document describes the options. If you're an advanced enough user to be considering a manual rEFInd installation procedure, doing the job from the Recovery HD environment may be your best option.</p>
+
+<p>Before installing rEFInd on a Mac, you must determine whether it uses a 32-bit or 64-bit EFI implementation. Most Intel-based Macs have 64-bit EFIs, so you should use the <tt>refind_x64.efi</tt> file with them; but very early Intel-based Macs have 32-bit EFIs (and sometimes 32-bit CPUs), which require the <tt>refind_ia32.efi</tt> file. You can determine whether your Mac needs the <i>x</i>86-64 or IA32 build by typing the following command in a Mac Terminal window:</p>
+
+<pre class="listing">
+$ <b>ioreg -l -p IODeviceTree | grep firmware-abi</b>
+</pre>
+
+<p>The result should include either <tt>EFI32</tt> or <tt>EFI64</tt>, indicating that you should use the <tt>refind_ia32.efi</tt> or <tt>refind_x64.efi</tt> binary, respectively.</p>
+
+<p>You should also be aware of your OS X version and installation options. If you used whole-disk encryption (WDE) or a logical volume for installation, you <i>cannot</i> install to the OS X root partition; you <i>must</i> install to the ESP or to a separate HFS+ partition. WDE became an option with OS X 10.7 and logical volumes are the default in OS X 10.10. If in doubt, proceed with an installation to the ESP or to a separate HFS+ partition.</p>
+
+<p class="sidebar"><b>Warning:</b> Numerous rEFIt bug reports indicate disk corruption problems on disks over about 500 GiB. <a href="https://sourceforge.net/tracker/?func=detail&aid=3218104&group_id=161917&atid=821764">This</a> report on the problem, and particularly the post by mic-marchen, suggests that the problem is related to a bug in OS X's <tt>bless</tt> utility, and particularly its <tt>--info</tt> option, that causes it to corrupt data on disks with 4 KiB sectors. These <i>Advanced Format</i> disks are becoming increasingly common, particularly at larger disk sizes. Therefore, I <i>strongly</i> recommend that you <i>not</i> type <tt class="userinput">sudo bless --info</tt> to check the status of your installation if you have such a disk, or even if you suspect you might have such a disk. (I've seen Advanced Format disks as small as 320 GB.)</p>
+
+<p>The procedure for installing rEFInd on a Mac is similar to that for installing it under Linux, except that you must use the <tt>bless</tt> utility rather than <tt>efibootmgr</tt> to register the program with the firmware. Also, you'll probably have to mount your ESP manually, since that's not done by default under OS X. To be precise, you should follow these steps:</p>
+
+<ol>
+
+<li>Open a Terminal window in which you'll type the following
+    commands.</li>
+
+<li>If you want to install rEFInd on your ESP, you must first mount it. The
+    easy way to do this is to use the <tt>mountesp</tt> script that comes
+    with rEFInd. When you run it, the script should tell you where the ESP
+    was mounted. You can do the job manually by typing <b><tt>mkdir
+    /Volumes/ESP</tt></b> followed by <b><tt>sudo mount -t msdos
+    /dev/disk0s1 /Volumes/ESP</tt></b>. Note that you may need to change
+    <tt>/dev/disk0s1</tt> to something else if your ESP is at an unusual
+    location. Type <tt class="userinput">diskutil list</tt> or use a tool
+    such as my <a href="http://www.rodsbooks.com/gdisk/">GPT fdisk
+    (<tt>gdisk</tt>)</a> to examine your partition table to find your ESP
+    if necessary.</li>
+
+<li>Type <b><tt>sudo mkdir -p /Volumes/ESP/efi/refind</tt></b> to create a
+    suitable directory for rEFInd. If you want to place rEFInd on the OS X
+    root partition, you should adjust the pathname appropriately, as in
+    <tt>/efi/refind</tt>. Alternatively, you can use the Finder to create
+    the directory.</li>
+
+<li>Copy the files in the <tt>refind</tt> subdirectory of the rEFInd binary
+    package to the like-named directory you've just created. You can do
+    this in the Finder or by typing <b><tt>sudo cp -r refind/*
+    /Volumes/ESP/efi/refind/</tt></b> in your Terminal window after
+    changing into the rEFInd package's main directory.</li>
+
+<li>Remove the file for the version of rEFInd you're not using, as in
+    <b><tt>sudo rm Volumes/esp/efi/refind/refind_ia32.efi</tt></b> on a Mac
+    with a 64-bit EFI or <b><tt>sudo rm
+    /Volumes/ESP/efi/refind/refind_x64.efi</tt></b> on a Mac with a 32-bit
+    EFI.</li>
+
+<li>Optionally, remove the drivers directory for the architecture you're
+    not using&mdash;<tt>/Volumes/ESP/efi/refind/drivers_ia32</tt> or
+    <tt>/Volumes/ESP/efi/refind/drivers_x64</tt>, as appropriate. You may
+    also want to remove some or all of the drivers for the architecture you
+    are using; if you don't need them, they'll slow down the start process.
+    See the <a href="drivers.html">page on drivers</a> for more on this
+    topic. Note that Apple's firmware includes its own HFS+ driver, so the
+    HFS+ driver provided with rEFInd is useless on Macs.</li>
+
+<li>If this is your first installation, type <b><tt>sudo mv
+    /Volumes/ESP/efi/refind/refind.conf-sample
+    /Volumes/ESP/efi/refind/refind.conf</tt></b> (adjusting the path as
+    necessary) to rename the sample configuration file so that it will
+    serve as a real configuration file. (Again, you can do this with the
+    Finder, if you prefer.)</li>
+
+<li>"Bless" rEFInd by typing one of the following two commands:
+    <ul>
+    <li>If you're installing rEFInd on the ESP, type <tt
+       class="userinput">sudo bless --mount /Volumes/ESP --setBoot --file
+       /Volumes/ESP/efi/refind/refind_x64.efi --shortform</tt>, adjusting
+       the mount point and exact path to the file as appropriate for your
+       installation.</li>
+    <li>If you're installing rEFInd to an ordinary HFS+ volume, type <tt
+       class="userinput">sudo bless --setBoot --folder /efi/refind --file
+       /efi/refind/refind_x64.efi</tt>. (Adjust the path and filename as
+       necessary if you're placing rEFInd somewhere else or using the
+       32-bit version.)</li>
+    </ul>
+    This is the step that's likely to fail if your system is booted
+    with SIP active.</li>
+
+<li>If you don't want to reboot immediately after installing rEFInd, you
+    may optionally unmount the ESP by typing <tt class="userinput">sudo
+    umount /dev/disk0s1</tt> or <tt class="userinput">sudo umount
+    /Volumes/ESP</tt>. This step isn't strictly required, but if you want
+    to keep the ESP out of your directory tree, it can be useful.</li>
+
+</ol>
+
+<p>When you reboot, your Mac should bring up the rEFInd menu, and should continue to do so thereafter. If you make changes that break this association, you can re-run the <tt>bless</tt> command (if necessary, restoring the rEFInd files first). This might be necessary after installing system updates from Apple or if you upgrade rEFInd to a newer version.</p>
+
+<p>If you're replacing rEFIt, you may discover that rEFInd works on the first boot, but the system reverts back to rEFIt or a direct boot to OS X on the second boot. To fix this problem, you can remove the rEFItBlesser program, which is located at <tt>/Library/StartupItems/rEFItBlesser</tt>. This program attempts to keep rEFIt set as the default boot loader, but it also has the purpose of protecting the computer from launching the wrong OS after waking from sleep. If you want that protection, my suggestion is to install rEFIt and rEFItBlesser and then replace the <tt>refit.efi</tt> file with <tt>refind_x64.efi</tt> or <tt>refind_ia32.efi</tt> (renaming it to <tt>refit.efi</tt>). Used in this way, rEFInd will still look for its own configuration file, <tt>refind.conf</tt>, so you'll need to move it but <i>not</i> rename it. If you don't move the icons from the rEFInd package, your icons will continue to look like rEFIt icons, and you'll be missing the new icons for specific Linux distributions that rEFInd provides. One final caveat: It's conceivable that rEFItBlesser is what's causing filesystem corruption for some users, so if you've been having this problem with rEFIt, it might be worth disabling this program and not using it with rEFInd.</p>
+
+<p>If you want to remove rEFInd from your system, you can delete its files. The Mac will revert to booting using whatever standard boot loader it can find. Alternatively, you can use <tt>bless</tt> to bless another EFI boot loader. The GUI Startup Disk utility in System Preferences provides a simplified interface that enables you to select which OS X installation to boot, but it doesn't look for non-Apple boot loaders, so you can't use it to enable rEFInd.</p>
+
+<a name="windows">
+<h3>Installing rEFInd Manually Using Windows</h3>
+</a>
+
+<p class="sidebar"><b>Warning:</b> Windows 8 implements a fast shutdown feature that helps speed up shutdown and startup operations on a single-boot computer. Unfortunately, this feature can cause filesystem corruption if it's used on a multi-boot computer. You can disable the feature by launching an Administrator Command Prompt window and typing <tt class="userinput">powercfg /h off</tt> in it.</p>
+
+<p>I know relatively little about Windows EFI management tools; however, I do know that at least two relevant tools exist: the standard <tt>bcdedit</tt> and the third-party <i>EasyUEFI.</i></p>
+
+<p>The <a href="http://www.easyuefi.com/index-us.html">EasyUEFI tool</a> is a free (as in beer) GUI tool for managing EFI boot programs. I've only tried it once, and it seemed fairly intuitive and easy to use, but I don't have detailed instructions on how to use it. If you want to use EasyUEFI, you'll have to use it in place of <tt>bcdedit</tt> at the end of the following procedure.</p>
+
+<p class="sidebar"><b>Caution:</b> I've received reports that Windows 10 has made changes that make the following instructions not work. If you're using this OS, until I have a chance to investigate and update these instructions, your best bet may be to install rEFInd using a Linux live disk, such as an Ubuntu installation disk in its "try before installing" mode.</p>
+
+<p>Attempt this method of installation only on a UEFI-based PC; this method will not work on Windows that's installed on a Mac in BIOS/CSM/legacy mode. To install rEFInd under Windows, you must first find a way to access the ESP, which Windows normally hides from view. One way to accomplish this goal, and to proceed forward once the ESP is accessible, is as follows:</p>
+
+<ol>
+
+<li>Locate Command Prompt in the Start menu, right-click it, and select Run as Administrator. This action opens a Command Prompt window with administrative privileges.</li>
+
+<li>Type <b><tt>mountvol S: /S</tt></b> in the Administrator Command Prompt window. This makes the ESP accessible as drive <tt>S:</tt> from that window. (You can use a drive identifier other than <tt>S:</tt> if you like.)</li>
+
+<li>Change into the main rEFInd package directory, so that the <tt>refind</tt> subdirectory is visible when you type <b><tt>dir</tt></b>.</li>
+
+<li>Type <b><tt>xcopy /E refind S:\EFI\refind\</tt></b> to copy the <tt>refind</tt> directory tree to the ESP's <tt>EFI</tt> directory. If you omit the trailing backslash from this command, <tt>xcopy</tt> will ask if you want to create the <tt>refind</tt> directory. Tell it to do so.</li>
+
+<li>Type <b><tt>S:</tt></b> to change to the ESP.</li>
+
+<li>Type <b><tt>cd EFI\refind</tt></b> to change into the <tt>refind</tt> subdirectory</li>
+
+<li>You may want to selectively delete some of the drivers in the <tt>drivers_x64</tt> or <tt>drivers_ia32</tt> directory, depending on your architecture and needs. Unnecessary drivers will slow the rEFInd start process, and can even cause the drivers you need to not work or cause a system crash. See the <a href="drivers.html">page on drivers</a> for more on this topic.</li>
+
+<li>Type <b><tt>rename refind.conf-sample refind.conf</tt></b> to rename rEFInd's configuration file.</li>
+
+<p class="sidebar"><b>Note:</b> I've heard from a couple of Windows 10 users that the <tt>bcdedit</tt> commands described here don't work. I don't yet know if this is a coincidence or if Microsoft has changed <tt>bcdedit</tt> in such a way that these instructions no longer apply. If you run into this problem, either try using EasyUEFI or use another installation method, such as the <a href="#linux">Linux method</a> from a Linux emergency boot disc.</p>
+
+<li>Type <b><tt>bcdedit /set {bootmgr} path \EFI\refind\refind_x64.efi</tt></b> to set rEFInd as the default EFI boot program. Note that <tt>{bootmgr}</tt> is entered as such; that's not a notation for a variable. Also, change <tt>refind_x64.efi</tt> to <tt>refind_ia32.efi</tt> on systems with 32-bit EFIs. Such computers are rare, and most of them are tablets. Check your Windows bit depth to determine which binary you should use.</li>
+
+<li>If you like, type <b><tt>bcdedit /set {bootmgr} description "<i>rEFInd description</i>"</tt></b> to set a description (change <tt><i>rEFInd description</i></tt> as you see fit).</li>
+
+</ol>
+
+<p>At this point, when you reboot, rEFInd should appear as your new default boot program. If it doesn't work for you, you have several other options, such as:</p>
+
+<ul>
+
+<li>You can rename files on the ESP. as described later, in <a href="#naming">Alternative Naming Options.</a></li>
+
+<li>You can boot from an optical disc into an emergency OS to do the job. Ubuntu, for instance, provides an EFI-bootable installer with a "try before installation" mode. You'll need to type <b><tt>sudo apt-get install efibootmgr</tt></b> to install <tt>efibootmgr</tt>, but you can then use that program as described <a href="#efibootmgr">earlier</a>. (If you're using Ubuntu, you'll need to precede the command with <b><tt>sudo</tt></b>. If you use an Ubuntu image, you can install rEFInd <a href="#ppa">via its PPA,</a> which is an easy way to do the job. (In fact, the rEFInd PPA depends on the <tt>efibootmgr</tt> package, so you shouldn't need to manually install it.) The PPA approach may even be easier than installing from Windows using its tools, at least if you're familiar with Linux and have an Ubuntu desktop image handy.</li>
+
+<li>You may be able to use rEFInd's bootable CD image to use rEFInd to boot an OS that's been installed but rendered inoperable because of changes to your boot order. You can then use <tt>efibootmgr</tt>, <tt>bless</tt>, or some other tool to restore rEFInd as the default boot loader.</li>
+
+</ul>
+
+<a name="efishell">
+<h3>Installing rEFInd Manually Using an EFI Shell</h3>
+</a>
+
+<p class="sidebar"><b>Warning:</b> Do not attempt to use the procedure described in this section on a Macintosh. Macs have a strange EFI implementation that does not use the EFI variables that this procedure manipulates. Therefore, chances are this procedure simply won't work. It's conceivable that this procedure will actually cause problems, but I'm not curious enough to try it and risk damaging my Mac!</p>
+
+<p>If you can't currently boot any OS (say, because a firmware update has wiped your NVRAM entries), you may find it convenient to install rEFInd using an EFI version 2 shell. Unfortunately, the <tt>bcfg</tt> command described here is not available in the EFI version 1 shell, and the version 2 shell is unusable on many firmware implementations prior to 2.3.1. Thus, this procedure won't work for all systems.</p>
+
+<p>In addition to emergency situations, using <tt>bcfg</tt> can be desirable if <tt>efibootmgr</tt> or other OS-hosted tools don't do the job. This happens under VirtualBox, for instance. An alternative in such cases can be to use <a href="#naming">alternative names for rEFInd.</a></p>
+
+<p>To begin, you must have a way to launch your shell. Unfortunately, this can pose a dilemma, since without rEFInd or some other boot manager, many EFI implementations lack the means to launch a shell. Some will do so, though, if the shell is stored as <tt>shellx64.efi</tt> (for <i>x</i>86-64) or <tt>shellia32.efi</tt> (for <i>x</i>86) in the root directory of the ESP. Thus, you can try copying your shell file there. You can obtain EFI 2 shells here:</p>
+
+<ul>
+
+<li><a href="https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2/ShellBinPkg/UefiShell/X64/Shell.efi"><i>x</i>86-64 (64-bit) shell 2</a></li>
+
+<li><a href="https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2/ShellBinPkg/UefiShell/Ia32/Shell.efi"><i>x</i>86 (32-bit) shell 2</a></li>
+
+<li><a href="http://dl.dropbox.com/u/17629062/Shell2.zip">Alternate <i>x</i>86-64 (64-bit) shell 2 for older EFIs</a></li>
+
+</ul>
+
+<p>Note that the IA32 shell included in rEFInd's CD-R image version is a version 1 shell, so you can't use it for this purpose. You can, however, copy rEFInd's files from the CD-R. You can even launch the version 1 shell included with rEFInd and then use that to launch a version 2 shell. The <i>x</i>86-64 shell on the CD-R is the alternate shell, which should work on any <i>x</i>86-64 computer. Once you've booted the shell, you can proceed as follows:</p>
+
+<ol>
+
+<li>If you haven't installed rEFInd previously, unpack its zip file to a
+    FAT partition. This can be the ESP itself or another partition, such as
+    a USB flash drive. If you're simply repairing a lost NVRAM entry, you
+    needn't move your existing rEFInd files.</li>
+
+<li>Identify your filesystems, which are labelled with the form <tt>fs<tt
+    style="variable">n</tt>:</tt>, as in <tt>fs0:</tt> for the first
+    filesystem, <tt>fs1:</tt> for the second, and so on. Type the
+    filesystem number followed by the Enter key to begin using it. You can
+    then type <tt class="userinput">ls</tt> or <tt
+    class="userinput">dir</tt> to see the contents of the filesystem.
+    Chances are your ESP will be <tt>fs0:</tt>, but it could be something
+    else. (The following steps assume your ESP is <tt>fs0:</tt>; you'll
+    need to adjust them if it's not.) If rEFInd's source files are on
+    another device, you must identify it, too.</li>
+
+<p class="sidebar"><b>Note:</b> Skip ahead to step #12 if you're merely re-activating an already-installed rEFInd binary. If an entry exists but it's no longer the primary one, you can skip ahead to step #14.</p>
+
+<li>If necessary, create a directory for rEFInd by typing <tt
+    class="userinput">mkdir fs0:\EFI\refind</tt>. (If the <tt>fs0:\EFI</tt>
+    directory doesn't already exist, you must create it first,
+    though.)</li>
+
+<li>Change to the directory in which rEFInd's files exist.</li>
+
+<li>Type <tt class="userinput">cp refind_x64.efi fs0:\EFI\refind</tt> to
+    copy the rEFInd binary file. (Adjust the name if you're using a 32-bit
+    computer.)</li>
+
+<li>Type <tt class="userinput">cp refind.conf-sample
+    fs0:\EFI\refind\refind.conf</tt> to copy and rename the sample rEFInd
+    configuration file.</li>
+
+<li>Type <tt class="userinput">cp -r icons fs0:\EFI\refind\</tt> to copy
+    rEFInd's icons.</li>
+
+<li>Optionally, type <tt class="userinput">cp -r drivers_x64
+    fs0:\EFI\refind\</tt> to copy rEFInd's 64-bit drivers. (You could
+    instead copy the 32-bit drivers or limit yourself to just the drivers
+    you need, of course.)</li>
+
+<li>Type <tt class="userinput">fs0:</tt>, if necessary, to change to the
+    ESP.</li>
+
+<li>Type <tt class="userinput">cd \EFI\refind</tt> to change to rEFInd's
+    installation directory.</li>
+
+<li>If you want to edit rEFInd's options, type <tt class="userinput">edit
+    refind.conf</tt> and use the shell's built-in text editor to do so.
+    Press F2 followed by the Enter key to save your changes and F3 to
+    exit.</li>
+
+<li>Type <tt class="userinput">bcfg boot dump -b</tt> to see a list of
+    existing NVRAM entries. Pay attention to their numbers (labelled
+    <tt>Option:</tt> and <tt>Variable:</tt>, with the latter number
+    preceded by the string <tt>Boot</tt>, as in <tt>Boot0007</tt>). You'll
+    want to create a boot entry for rEFInd using a number that's not in
+    use.</li>
+
+<li>Type <tt class="userinput">bcfg boot add 3
+    fs0:\EFI\refind\refind_x64.efi "rEFInd"</tt>, adjusting the number
+    (<tt>3</tt> in this example), filesystem (<tt>fs0:</tt>), and filename
+    (<tt>\EFI\refind\refind_x64.efi</tt>) as necessary for your system. If
+    you're used to Linux, be sure to use backslashes (<tt>\</tt>), not
+    Linux-style forward slashes (<tt>/</tt>), as directory separators. Note
+    that some shells may ignore the number you entered and use another one,
+    so watch for this possibility.</li>
+
+<li>Type <tt class="userinput">bcfg boot mv <i>3</i> 0</tt>, substituting
+    the option number for the entry you created for <tt
+    class="variable">3</tt>. This moves rEFInd to the top of the boot
+    order.</li>
+
+<li>Type <tt class="userinput">reset</tt> to reboot the computer.</li>
+
+</ol>
+
+<p>With any luck, rEFInd will start up at this point. If not, you can check your settings using a shell or an emergency system for your OS of choice. In an EFI shell, you might type <tt class="userinput">bcfg boot dump -b</tt> to view your boot loader entries and verify that rEFInd appears at the top of the list. Be sure to check the pathname for typos. If you continue to have problems, you might look into giving rEFInd a <a href="#naming">fallback filename</a> that your firmware will recognize.</p>
+
+<a name="naming">
+<h2>Alternative Naming Options</h2>
+</a>
+
+<p>Some EFI implementations do a poor job of honoring the boot options set via Linux's <tt>efibootmgr</tt> or other tools. You may also lack access to such utilities, such as if you must install rEFInd in Windows. In such cases, you may need to change the boot loader's name so that the EFI will see it as the default boot loader. rEFInd should then boot when your NVRAM lacks information on specific boot loaders to use. Broadly speaking, there are two alternative names that are most useful:</p>
+<ul>
+
+<li><tt class="userinput">EFI/BOOT/boot<i>arch</i>.efi</tt>&mdash;This name
+    is the official EFI fallback filename. It's most commonly used on
+    bootable removable disks, but it can be used on hard disks. It's
+    typically used only if no NVRAM entry points to a valid boot
+    loader.</li>
+
+<li><tt class="userinput">EFI/Microsoft/Boot/bootmgfw.efi</tt>&mdash;This
+    filename has no official special standing in the EFI specification, but
+    as a practical matter, many EFI implementations use it as a fallback
+    boot loader in addition to or instead of
+    <tt>EFI/BOOT/boot<i>arch</i>.efi</tt>. In fact, some give it such a
+    high precedence that you can't boot anything that's not given this
+    name!
+
+</ul>
+
+<p>If you need to use one of these names, or something more exotic, you can do so in either of two ways: You can <a href="#mvrefind">use the <tt>mvrefind</tt> script</a> to move your installation in one step, or you can <a href="#manual_renaming">move and rename your files manually.</a></p>
+
+<a name="mvrefind">
+<h3>Using <tt>mvrefind</tt></h3>
+</a>
+
+<p>The easiest way to move a rEFInd installation, at least in Linux, is to use the <tt>mvrefind</tt> script. If you installed from one of my RPM or Debian packages, this script should be installed in <tt>/usr/sbin</tt>, so you can use it like a regular Linux command; otherwise you'll need to install it to your path yourself or type its complete path. Either way, it works much like the Linux <tt>mv</tt> command, but you pass it the directory in which a rEFInd installation appears and a target location:</p>
+
+<pre class="listing">
+# <tt class="userinput">mvrefind /boot/efi/EFI/BOOT /boot/efi/EFI/refind</tt>
+</pre>
+
+<p>This example moves rEFInd from <tt>/boot/efi/EFI/BOOT</tt> to <tt>/boot/efi/EFI/refind</tt>. It differs from <tt>mv</tt> in several ways:
+
+<ul>
+
+<li>The script renames rEFInd in a way that's sensitive to its source and
+    destination directories&mdash;for instance, <tt>mvrefind</tt> knows
+    that rEFInd (or shim, for Secure Boot installations) must be called
+    <tt>bootx64.efi</tt> on a 64-bit installation in
+    <tt>/boot/efi/EFI/BOOT</tt>, so it looks for rEFInd under that name
+    when copying from this directory, or it renames rEFInd to that name
+    when copying to it.</li>
+
+<li>The script creates a new NVRAM entry for rEFInd when it copies to any
+    location but <tt>EFI/BOOT</tt> or <tt>EFI/Microsoft/Boot</tt>. It
+    refuses to copy to such locations if it's not run from an EFI-mode
+    boot.</li>
+
+<li>The script knows enough to back up existing boot loaders stored in
+    <tt>EFI/BOOT</tt> or <tt>EFI/Microsoft/Boot</tt> when copying to these
+    locations. For the former location, the script backs up
+    <tt>EFI/BOOT</tt> as <tt>EFI/BOOT-rEFIndBackup</tt>; for the latter, it
+    moves <tt>EFI/Microsoft/Boot/bootmgfw.efi</tt> to
+    <tt>EFI/Microsoft/bootmgfw.efi</tt>.</li>
+
+</ul>
+
+<p>The <tt>mvrefind</tt> script is likely to be useful in resolving boot problems&mdash;if your system won't boot, you can try copying the installation to <tt>/boot/efi/EFI/BOOT</tt>, <tt>/boot/efi/EFI/Microsoft/Boot</tt>, and <tt>/boot/efi/EFI/refind</tt> in turn, testing the boot process after each attempt. (These filenames all assume your ESP is mounted at <tt>/boot/efi</tt>.) You could also copy a BIOS-mode install from <tt>/boot/efi/EFI/BOOT</tt> or <tt>/boot/efi/EFI/Microsoft/Boot</tt> to <tt>/boot/efi/EFI/refind</tt> to make it more robust against Windows repairs (assuming your firmware isn't broken).</p>
+
+<a name="manual_renaming">
+<h3>Renaming Files Manually</h3>
+</a>
+
+<p>You can move and rename rEFInd manually from any OS by following these steps:</p>
+<ol>
+
+<li>Access your ESP, as described in earlier sections.</li>
+
+<li>Look for an existing directory called <tt>EFI/BOOT</tt> or <tt>EFI/Microsoft/Boot</tt>. If neither of these directories exist, skip the next step. (Note that FAT is case-insensitive, so the name may vary in case.)</li>
+
+<li>Rename the existing directory or boot loader file to something else. For <tt>EFI/BOOT</tt>, try renaming it to <tt>EFI/Oldboot</tt>. For <tt>EFI/Microsoft/Boot</tt>, move or rename the <tt>bootmgfw.efi</tt> file it contains. For instance, you can move it to <tt>EFI/Microsoft</tt>. This will keep the boot loader accessible to rEFInd's menu, while preventing the firmware from launching it automatically.</li>
+
+<li>Rename/move your <tt>EFI/refind</tt> directory to <tt>EFI/BOOT</tt>. If you're working from <tt>EFI/Microsoft/Boot</tt>, you should move the contents of your rEFInd directory to <tt>EFI/Microsoft/Boot</tt>.</li>
+
+<li>Rename <tt>EFI/BOOT/refind_x64.efi</tt> to the name of the boot loader it's replacing&mdash;it should become <tt>EFI/BOOT/bootx64.efi</tt> or <tt>EFI/Microsoft/Boot/bootmgfw.efi</tt>.</li>
+
+</ol>
+
+<p>When you reboot, rEFInd should come up. With any luck, it will detect your old boot loader as an option, if one was installed before.</p>
+
+<a name="upgrading">
+<h2>Upgrading rEFInd</h2>
+</a>
+
+<p>If you've installed an earlier version of rEFInd, you can upgrade a bit more easily than you can install directly:</p>
+
+<ul>
+
+<li>On a UEFI-based PC, under any OS, you should be able to replace your
+    old rEFInd file with the new one. Make sure that the new rEFInd has the
+    same name as the old one, and that it's for the correct CPU type. Since
+    UEFI launches boot programs by filename, a simple file replacement will
+    suffice to launch the new version. If the new version includes new
+    icons, you may want to copy some or all of them.</li>
+
+<li>On a Mac, you can copy over the old rEFInd binary file <i>from
+    Linux</i> and it will usually work, provided you copy <i>directly</i>
+    over the old file (rather than rename or delete the old file and then
+    copy the new one in its place). The same caveats about icons as apply
+    to UEFI-based PCs apply in this case. This method requires an extra
+    step in Mac OS X, though....</li>
+
+<li>In OS X, if you copy over the original file with the new one, you'll
+    probably have to re-bless it to make it work.</li>
+
+<li>Under Linux or OS X, you can re-run the <tt>refind-install</tt> script. In
+    most cases this works fine, but you'll end up with a duplicate of the
+    icons directory (<tt>icons-backup</tt>, which holds the original icons,
+    whereas <tt>icons</tt> holds the icons from the new package). Normally
+    this just wastes some disk space; but if you've customized your icons,
+    you'll need to copy your altered icons back. Under Linux, versions
+    0.6.2 and later of <tt>refind-install</tt> search for rEFInd in several
+    locations on the ESP, and will upgrade whatever is found. The same is
+    true with versions 0.8.5 and later under OS X when installing to the
+    ESP. If you install to a location other than the ESP under OS X, be
+    sure to include the same option to <tt>refind-install</tt>
+    (<tt>--notesp</tt> or <tt>--ownhfs</tt>) to replace the original rather
+    than create a new installation to the ESP.</li>
+
+<li>Under an RPM- or Debian-based Linux distribution, you can use your
+    package system to install a newer version of the RPM or Debian package
+    that I provide. This will upgrade the files in your Linux filesystem
+    and re-run the <tt>refind-install</tt> script, so as with the previous
+    options, you'll waste a little disk space on duplicated icons, but the
+    process should otherwise work quite well.</li>
+
+<li>If you installed using my Ubuntu PPA or a package provided by an OS
+    distribution (such as the packages that ship with Arch and ALT Linux),
+    performing a system update will probably update rEFInd, too. Depending
+    on how the package was created, though, this update might or might not
+    install the update to the ESP; you might need to manually re-run the
+    installation script. Consult your distribution's documentation for
+    details. My Ubuntu PPA will automatically run <tt>refind-install</tt> after
+    the package is installed.</li>
+
+</ul>
+
+<p>In all cases, if the new version includes new or altered configuration file options, you may need to manually update your configuration file. Alternatively, if you've used the default configuration file, you can replace your working <tt>refind.conf</tt> with <tt>refind.conf-sample</tt> from the rEFInd zip file. (When using <tt>refind-install</tt>, this file will be copied to rEFInd's installation directory under its original name, so you can rename it within that directory to replace the old file.)</p>
+
+<p>If you're upgrading to rEFInd from rEFIt, you can simply run the <tt>refind-install</tt> script as described earlier or perform a manual installation. Once installed, rEFInd will take over boot manager duties. You'll still be able to launch rEFIt from rEFInd; a rEFIt icon will appear in rEFInd's menu. You can eliminate this option by removing the rEFIt files, which normally reside in <tt>/EFI/refit</tt>.</p>
+
+<a name="addons">
+<h2>Installing Additional Components</h2>
+</a>
+
+<p>rEFInd includes the ability to launch any EFI program; however, rEFInd detects only certain programs. These include boot loaders in traditional locations and a handful of other programs. To launch most of these other programs, you must download and install them separately from rEFInd:</p>
+
+<ul>
+
+<li><b><a
+    href="http://tianocore.git.sourceforge.net/git/gitweb.cgi?p=tianocore/edk2;a=blob_plain;f=EdkShellBinPkg/FullShell/X64/Shell_Full.efi;hb=HEAD"><tt>shell.efi</tt></a></b>&mdash;This
+    file, placed in the ESP's <tt>EFI/tools</tt> directory, adds the
+    ability to launch a text-mode EFI shell from rEFInd. Note that the
+    download link is to a 64-bit binary that must be renamed before rEFInd
+    will recognize it. Additional shell download links appear on the <a
+    href="https://wiki.archlinux.org/index.php/Unified_Extensible_Firmware_Interface#UEFI_Shell_download_links">Arch
+    Linux wiki,</a> and on other sites; try a Web search if the shell you
+    find doesn't work to your satisfaction.</li>
+
+<li><b><a
+    href="http://www.memtest86.com/download.htm">Memtest86</a></b>&mdash;This
+    is a popular tool for performing basic hardware tests, and especially
+    memory tests. rEFInd recognizes this program when it is stored in the
+    <tt>EFI/tools</tt>, <tt>EFI/tools/memtest</tt>,
+    <tt>EFI/tools/memtest86</tt>, <tt>EFI/memtest</tt>, or
+    <tt>EFI/memtest86</tt> directory, with a program filename of
+    <tt>memtest86.efi</tt>, <tt>memtest86_x64.efi</tt>,
+    <tt>memtest86x64.efi</tt>, or <tt>bootx64.efi</tt>. (Change
+    <tt>x64</tt> to <tt>ia32</tt> on IA-32 systems.) Be sure to download
+    the EFI version of the program. If you get the USB flash drive version,
+    you should mount the flash drive's ESP (partition 2) and copy the
+    <tt>EFI/BOOT</tt> directory to your own ESP's
+    <tt>EFI/tools/memtest</tt> or other Memtest86 directory name, as just
+    specified. rEFInd should then recognize it, provided the
+    <tt>showtools</tt> line includes the <tt>memtest</tt> or
+    <tt>memtest86</tt> token.</li>
+
+<li><b><tt>gptsync.efi</tt> or <tt>gptsync_<tt
+    class="variable">arch</tt>.efi</tt></b>&mdash;This program creates a <a
+    href="http://www.rodsbooks.com/gdisk/hybrid.html">hybrid MBR</a> from
+    your regular GPT disk. A hybrid MBR is a dangerous hack that enables
+    Windows and OS X to coexist on a Macintosh disk. If you're using a
+    UEFI-based PC, a hybrid MBR is likely to be useless at best, so you
+    shouldn't create one, and it's safest to not install
+    <tt>gptsync.efi</tt>. If you're using a hybrid MBR to enable
+    dual-booting Windows and OS X on a Mac, though, placing this program
+    file in the ESP's or Mac boot partition's <tt>EFI/tools</tt> directory
+    will enable you to regenerate your hybrid MBR should some other tool
+    convert the MBR to a standard protective MBR. You can obtain the file
+    from the <a href="http://refit.sourceforge.net">original rEFIt
+    package,</a> or beginning with rEFInd 0.6.9, an updated version is
+    included in the rEFInd package. The rEFInd version of <tt>gptsync_<tt
+    class="variable">arch</tt>.efi</tt> uses a more sophisticated algorithm
+    for determining what GPT partitions to duplicate in the MBR and it
+    includes additional safeguards to minimize the risk of damage should
+    you run the program on a disk that might have been damaged. The
+    original rEFIt version of the program usually goes by the filename
+    <tt>gptsync.efi</tt>, whereas the updated rEFInd version ships with an
+    architecture code, as in <tt>gptsync_x64.efi</tt> or
+    <tt>gptsync_ia32.efi</tt>. The rEFInd <tt>refind-install</tt> script
+    installs <tt>gptsync_<tt class="variable">arch</tt>.efi</tt> when run
+    under OS X, but not when run on Linux. In addition to installing the
+    program, you must edit <tt>refind.conf</tt>, uncomment the
+    <tt>showtools</tt> line, and add <tt>gptsync</tt> to its list of
+    options.</li>
+
+<li><b>Drivers</b>&mdash;You can install drivers to extend the capabilities
+    of the EFI. rEFInd ships with filesystem drivers for ext2fs, ext4fs, and
+    ReiserFS, which can enable you to boot a Linux kernel with EFI stub
+    support from an ext2fs, ext3fs, ext4fs, or ReiserFS partition. (rEFInd also
+    provides ISO-9660 and HFS+ drivers.) You can find additional drivers
+    from other sources, although they're still on the scarce side. See the
+    <a href="drivers.html">Using EFI Drivers</a> page for more on this
+    topic.</li>
+
+<li><b>Secure Boot files</b>&mdash;If you're running on a system that
+    supports Secure Boot, chances are you'll need extra support files, such
+    as <tt>shim.efi</tt> and <tt>MokManager.efi</tt>. I describe these in
+    detail on the <a href="secureboot.html">Managing Secure Boot</a>
+    page.</li>
+
+<li><b><a href="http://ipxe.org/">iPXE</a></b>&mdash;This tool provides the
+    ability to boot a computer from a network server. Consult the
+    <tt>BUILDING.txt</tt> file in the rEFInd source code package for
+    information on building and installing these tools. You must also
+    activate rEFInd's support by adding the <tt>netboot</tt> option to the
+    <tt>scanfor</tt> and/or <tt>showtools</tt> lines in
+    <tt>refind.conf</tt>. <i>Network-boot/iPXE support is currently
+    experimental;</i> I recommend that only developers or those who are
+    willing to use "bleeding-edge" software try it. Once activated, rEFInd
+    will present a new menu item for booting from the network server.
+    rEFInd itself will normally be installed locally. (You can deliver
+    rEFInd as a network-boot image, but that image will be able to boot
+    only OSes on the local disk.)</li>
+
+</ul>
+
+<p>I've seen links to other versions of these tools from time to time on the Web, so if you try one of these programs and it crashes or behaves strangely, try performing a Web search; you may turn up something that works better for you than the one to which I've linked.</p>
+
+<a name="sluggish">
+<h2>Fixing Macintosh Boot Problems</h2>
+</a>
+
+<p>I've received a few reports of a sluggish boot process (a delay of about 30 seconds before starting rEFInd) on some Macs after installing rEFInd, as well as some other Mac-specific peculiarities. I've been unable to replicate thess problems myself, and their true causes remains mysterious to me. I have found several possible solutions, though: <a href="#shortform">Using the <tt>--shortform</tt> option,</a> <a href="#fallback">using the fallback filename,</a> <a href="#moving">moving rEFInd to an HFS+ volume,</a> <a href="#clearing">clearing NVRAM entries,</a> <a href="#wakeprobs">fixing wake problems,</a> and <a href="#nolinux">fixing a failure to find Linux.</a></p>
+
+<a name="shortform">
+<h3>Using the <tt>--shortform</tt> Option</h3>
+</a>
+
+<p>Prior to version 0.8.5, these instructions and the <tt>refind-install</tt> script omitted the <tt>--shortform</tt> option from the <tt>bless</tt> command when installing rEFInd to the ESP. A rEFInd user, however, discovered that using the option eliminated the 30-second delay, so it is now the default with 0.8.5's <tt>refind-install</tt>, and is specified in the instructions. If you installed rEFInd 0.8.4 or earlier, you may want to re-install or re-<tt>bless</tt> rEFInd using this option.</p>
+
+<p>There is one caveat, though: The <tt>man</tt> page for <tt>bless</tt> notes that <tt>--shortform</tt> notes that its use can come "at the expense of boot time performance." Thus, it's not clear to me that this option might not actually <i>create</i> problems on some computers. (It's eliminated the boot delay on my 2014 MacBook Air and has no detrimental effect on an old 32-bit Mac Mini that's never had a boot delay problem, though.) Thus, if you have problems with rEFInd 0.8.5 or later, you might try running <tt>bless</tt>, as described in <a href="#osx">Installing rEFInd Manually Using OS X's</a> step 8, but <i>omit</i> the <tt>--shortform</tt> option.</p>
+
+<a name="fallback">
+<h3>Using the Fallback Filename</h3>
+</a>
+
+<p>I've received a few reports that installing rEFInd to the ESP using the fallback filename (<tt>EFI/BOOT/bootx64.efi</tt> on most systems, or <tt>EFI/BOOT/bootia32.efi</tt> on very old Macs) can work around a sluggish boot problem. In fact, version 0.8.4's <tt>refind-install</tt> script copied the rEFInd binary to this name when run under OS X. (Version 0.8.5 switches to using <tt>--shortform</tt> with the more conventional <tt>EFI/refind/refind_x64.efi</tt> or <tt>EFI/refind/refind_ia32.efi</tt> name, as just noted.) If you installed to a name other than <tt>EFI/BOOT/BOOT<tt class="variable">{ARCH}</tt></tt>, either manually or by using the 0.8.5 or later <tt>refind-install</tt>, renaming (and re-<tt>bless</tt>ing) the installation is worth trying.</p>
+
+<a name="moving">
+<h3>Moving rEFInd to an HFS+ Volume</h3>
+</a>
+
+<p>Most of the reports of sluggish Macintosh boots I've seen note that the user installed rEFInd to the ESP rather than to the OS X root partition. Some users have reported that re-installing rEFInd to the OS X root partition clears up the problem. This is obviously a straightforward solution to the problem, if it works. (This location is not an option when using WDE or OS X logical volumes.) Note that rEFInd can launch boot loaders that are stored on any partition that the EFI can read no matter where it's installed; therefore, you'll still be able to launch boot loaders stored on the ESP (or elsewhere) if you install it in this way.</p>
+
+<p>A variant of this solution is to create a small (~100MiB) HFS+ volume to be used exclusively by rEFInd. You can then install rEFInd to that volume with the <tt>--ownhfs</tt> option to <tt>refind-install</tt>, as in <tt class="userinput">./refind-install --ownhfs /dev/disk0s6</tt> if the volume is <tt>/dev/disk0s6</tt>. This approach has the advantage that it can be managed via OS X's own Startup Disk tool in System Preferences.</p>
+
+<p>The biggest drawback to storing rEFInd on an HFS+ volume is that you won't be able to edit the rEFInd configuration file or move rEFInd-related binaries from an EFI shell if you install it in this way, since Apple's HFS+ driver for EFI is read-only. (The same is true of rEFInd's HFS+ driver, so it won't help you overcome this limitation.) You may also be limited in making changes to your rEFInd configuration from Linux or other OSes, too, since Linux's HFS+ drivers disable write support by default on volumes with an active journal. You can force write access by using the <tt>force</tt> option to <tt>mount</tt>; however, this procedure is noted as being risky in the Linux HFS+ documentation, so I don't recommend doing this on a regular basis on the OS X boot volume. This isn't as risky if you use a dedicated HFS+ rEFInd partition, though. You could even mount it as the Linux <tt>/boot</tt> partition, in which case it would also hold the Linux kernel and related files.</p>
+
+<p>A variant of this solution is suggested in <a href="http://www.sparxeng.com/blog/software/fixing-slow-boot-on-a-triple-boot-mountain-lion-mac">this blog post,</a> which recommends placing rEFInd on an HFS+ volume on the first SATA channel. (In the blogger's case, that channel used to hold an optical drive, but that drive was replaced by a hard disk.)</p>
+
+<a name="clearing">
+<h3>Clearing the NVRAM Entries</h3>
+</a>
+
+<p>Another possible solution is documented in <a href="http://ubuntuforums.org/showpost.php?p=12256273&postcount=200">a Web forum post.</a> Be aware, though, that this procedure involves using the <tt>efibootmgr</tt> utility on Macs, which has been known to damage the firmware on some Macs. Other reports indicate that this problem has been fixed with 3.3.0 and later kernels. Thus, I present this information cautiously and with a strong "use at your own risk" warning. If you care to proceed, I recommend you update your Linux kernel to the latest possible version and then proceed as follows:</p>
+
+<ol>
+
+<li>Boot into Linux.</li>
+
+<li>Type <tt class="userinput">efibootmgr</tt> as <tt>root</tt> to obtain a list of your boot loader entries. Each entry includes a boot number, as in <tt>Boot0003</tt> or <tt>Boot0027</tt>.</li>
+
+<li>Remove all of the boot loader entries <i>except</i> rEFInd's by using <tt>efibootmgr</tt>'s <tt>-b <tt class="variable">bootnum</tt></tt> option to specify the boot entry and <tt>-B</tt> to delete it. For instance, typing <tt class="userinput">efibootmgr -b 0027 -B</tt> as <tt>root</tt> deletes boot entry <tt>Boot0027</tt>. Issue a separate <tt>efibootmgr</tt> command for each boot entry.</li>
+
+<li>Re-install rEFInd using the install script. It's unclear from the original post if this meant installing from Linux or from OS X.</li>
+
+</ol>
+
+<a name="wakeprobs">
+<h3>Fixing Wake Problems</h3>
+</a>
+
+<p>Some people have reported that installing rEFInd causes problems with resuming from a suspended OS X session. I know of two workarounds to such problems:</p>
+
+<ul>
+
+<li>Install rEFInd to an HFS+ volume using the <tt>--ownhfs</tt> option to <tt>refind-install</tt>. Unfortunately, this solution requires either creating a small HFS+ volume for rEFInd or using an already-existing non-bootable HFS+ volume (if you've got one for data storage, for example).</li>
+
+<li>Type <tt class="userinput">sudo pmset -a autopoweroff 0</tt> in a Terminal window. This solution is likely to work if sleep operations work normally up to a point, but fail after about three hours.</li>
+
+</ul>
+
+<p>I've recently acquired a 2014 MacBook Air, but I haven't yet had the chance to try to reproduce this problem and find a workaround. It's on my to-do list, though.</p>
+
+<a name="nolinux">
+<h3>Fixing a Failure to Find Linux</h3>
+</a>
+
+<p>Some users report that rEFInd doesn't detect Linux, or won't boot it when it is found. Broadly speaking, there are two common causes of this problem:</p>
+
+<ul>
+
+<li><b>A malfunctioning BIOS/legacy boot</b>&mdash;If you installed Linux in BIOS/legacy mode, as most online documentation suggests, it could be that your <a href="http://www.rodsbooks.com/gdisk/hybrid.html">hybrid MBR</a> is missing or damaged. The usual symptom of this problem is that rEFInd shows a generic Linux penguin icon and that selecting it produces a message to the effect that a bootable OS could not be found. As hybrid MBRs are ugly and dangerous, I recommend avoiding them if possible, so my preferred solution to this problem is to set up EFI filesystem drivers and boot that way; however, fixing the hybrid MBR may be an easier solution. This is especially true if you installed a 32-bit version of Linux on a 64-bit Mac (or a 64-bit version on a rare Mac with a 64-bit CPU but a 32-bit EFI).</li>
+
+<li><b>EFI filesystem driver problems</b>&mdash;Ideally, rEFInd should be able to load and run your Linux kernel directly, but this approach normally requires you to have a working EFI driver for the filesystem that holds your Linux kernel. This won't always be the case; and even if it is installed, there can be interference from other drivers, so you may need to <i>remove</i> the drivers that you don't use. If drivers are the root of your problem, you won't see any Linux options, or you'll see the one penguin icon (as above) with no others that point to your Linux kernel(s).</li>
+
+</ul>
+
+<p>If you suspect that your hybrid MBR is damaged, you can try re-creating it with my <a href="http://www.rodsbooks.com/gdisk/">GPT fdisk (<tt>gdisk</tt>)</a> program. The GPT fdisk <a href="http://www.rodsbooks.com/gdisk/hybrid.html">hybrid MBR documentation</a> covers this procedure in detail. You can run <tt>gdisk</tt> from either OS X or Linux, although you may need to install it, particularly in OS X.</p>
+
+<p>If you suspect driver problems, you'll need to mount your ESP (as described in the <a href="#osx">manual OS X installation instructions</a>), locate the rEFInd <tt>drivers_x64</tt> directory, and adjust its contents. Make sure you have a driver for the filesystem that holds your Linux kernel. If you don't know what filesystem this is, it's probably ext4fs. rEFInd ships with several filesystem drivers, including one for ext4fs. You should also remove unnecessary filesystem drivers. I've seen several reports of one driver interfering with others' operation. The biggest culprit seems to be the HFS+ driver when used on Macs.</p>
+
+<p></p>
+
+<a name="winprob">
+<h2>Fixing Windows Boot Problems</h2>
+</a>
+
+<p>Most Windows boot problems are best addressed on Windows-specific sites, so I recommend you make the rounds of Windows forums to solve such problems. There is one that deserves mention here, though: If you accidentally erase the Windows boot loader file, <tt>EFI/Microsoft/Boot/bootmgfw.efi</tt>, you won't be able to boot Windows. The simplest solution is to restore this file from a backup you prepared ahead of time. If you don't have such a backup, though, you can restore it as follows:</p>
+
+<ol>
+
+<li>Boot from an emergency Windows recovery disk. If you don't have one, you can prepare one from a working Windows system as described <a href="http://windows.microsoft.com/en-us/windows7/create-a-system-repair-disc">here.</a></li>
+
+<li>Type <tt class="userinput">diskpart</tt> to enter the Windows disk-partitioning tool.</li>
+
+<li>In <tt>diskpart</tt>, type <tt class="userinput">sel disk 0</tt> followed by <tt>list vol</tt>. You should see a set of partitions. This step is intended to help you identify your ESP, which will probably be the only FAT32 partition on the disk. (If you have multiple disks, you may need to try again with <tt class="userinput">sel disk 1</tt> or higher.) Note the volume number of your ESP.</li>
+
+<li>Type <tt class="userinput">sel vol 1</tt>, changing <tt>1</tt> to whatever the ESP's volume number is.</li>
+
+<li>Type <tt class="userinput">assign letter=S:</tt> to assign the ESP a Windows disk identifier of <tt>S:</tt>. (You can use another letter if you prefer.)</li>
+
+<li>Type <tt class="userinput">exit</tt> to exit from <tt>diskutil</tt>.</li>
+
+<li>Type <tt class="userinput">cd /d s:\EFI\Microsoft\Boot\</tt> to change into the Windows boot loader directory. (If this directory doesn't exist, you may need to create it first with <tt>mkdir</tt>. If rEFInd or some other boot loader occupies this directory, back it up first.</li>
+
+<li>Type <tt class="userinput">bootrec /fixboot</tt>.</li>
+
+<li>Type <tt class="userinput">bcdboot c:\Windows /s s: /f ALL</tt>. Note that this command should set the Windows boot loader as the default. Omit <tt>/f ALL</tt> if you don't want to adjust the EFI's default boot program.</li>
+
+<li>Reboot and hope it works! If the computer boots straight to Windows and you want to use rEFInd, use <tt>bcdedit</tt> in Windows, as described in step 9 of the <a href="#windows">Installing rEFInd Manually Using Windows</a> section of this page.</li>
+
+</ol>
+
+<p>For more information, see <a href="http://superuser.com/questions/460762/how-can-i-repair-the-windows-8-efi-bootloader">this SuperUser question and answer.</a></p>
+
+<a name="uninstalling">
+<h2>Uninstalling rEFInd</h2>
+</a>
+
+<p>If you decide you don't want to keep rEFInd, you can uninstall it. Doing so is a matter of removing the rEFInd files from your ESP (or from your OS X boot partition, if you installed the program there). The exact details of how to do this vary from one OS to another, though; and in some cases there are alternatives to completely uninstalling rEFInd that are easier to implement.</p>
+
+<a name="uinst_linux">
+<h3>Uninstalling rEFInd from Linux</h3>
+</a>
+
+<p>In Linux, a command like the following, typed as <tt>root</tt>, should remove rEFInd:</p>
+
+<pre class="listing">
+# <tt class="userinput">rm -r /boot/efi/EFI/refind</tt>
+</pre>
+
+<p>You must type this command as <tt>root</tt> (or use <tt>sudo</tt> in some environments, such as under Ubuntu). This example assumes that your ESP is mounted at <tt>/boot/efi</tt> and that rEFInd is installed in <tt>EFI/refind</tt> on that partition. If you've mounted your ESP elsewhere, or installed rEFInd elsewhere, you should adjust the command appropriately.</p>
+
+<p>If you installed via an RPM or Debian package in Linux, using your package manager will remove the package files, but not the files that the installer places on your ESP. Thus, you must uninstall those files manually, as just described. To complete the job, you'll also have to remove <tt>/boot/refind_linux.conf</tt>, and perhaps the <tt>/etc/refind.d</tt> directory.</p>
+
+<a name="uinst_osx">
+<h3>Uninstalling rEFInd from OS X</h3>
+</a>
+
+<p>The easiest way to restore the standard OS X boot loader on a Mac is not to uninstall rEFInd; it's to bypass it. This can be accomplished with the Startup Disk item in the System Preferences panel:</p>
+
+    <br /><center><img src="startup-disk.png" align="center" width="668"
+    height="355" alt="The OS X Startup Disk tool enables you to reset a Mac
+    to use the standard OS X boot loader." border=2> </center><br />
+
+<p>Select your startup disk (<i>Macintosh HD OS X, 10.10.1</i> in this example) and then click Restart. The computer should reboot into OS X, bypassing rEFInd.</p>
+
+<p>I recommend stopping here, because the procedure for completely removing rEFInd from a Mac depends on your installation method and tends to be challenging for many Mac users, who are unfamiliar with the necessary command-line tools. Basically, you must reverse the steps described earlier, in <a href="#osx">Installing rEFInd Manually Using Mac OS X:</a></p>
+
+<ol>
+
+<li>You must first determine where rEFInd is installed. This can be any of
+    several locations:
+
+    <ul>
+
+    <li>If you installed rEFInd 0.8.3 or earlier with the default options,
+       or if you used the <tt>--notesp</tt> option with rEFInd 0.8.4 or
+       later, it will be <tt>/EFI/refind</tt> on your main partition</li>
+
+    <li>If you installed rEFInd 0.8.4 or later with the default options, or
+       if you used the <tt>--esp</tt> option with rEFInd 0.8.3 or earlier,
+       it will be in <tt>EFI/refind</tt> or <tt>EFI/BOOT</tt> on the
+       ESP.</li>
+
+    <li>If you used the <tt>--ownhfs</tt> option to <tt>refind-install</tt>,
+       rEFInd will be in the <tt>System/Library/CoreServices</tt>
+       directory on the volume you specified.</li>
+
+    <li>If you installed rEFInd manually, it will be wherever you put
+        it.</li>
+
+    <li>In all cases, there could be duplicate (inactive) rEFInd files in
+       unexpected places. This is particularly true if you tried
+       installing rEFInd multiple times, each with different options to
+       <tt>refind-install</tt>. Thus, if you delete rEFInd and it still comes
+       up, you may have deleted the wrong files. (Note that dragging files
+       to the Trash may have no effect, though&mdash;at least, not until
+       you empty the Trash.)</li>
+
+    </ul>
+
+<li>If necessary, mount the ESP or rEFInd-specific HFS+ volume, as
+    described in <a href="#osx">Installing rEFInd Manually Using Mac OS
+    X.</a> (The <tt>mountesp</tt> script that comes with rEFInd will handle
+    this task.)</li>
+
+<li>Verify that rEFInd is installed in the directory noted in step #1. If a
+    <tt>refind.conf</tt> file is present, rEFInd is almost certainly
+    installed in that directory. If not, it's not rEFInd there and you
+    should <i>not</i> proceed. <b><i>Be extra cautious about deleting the
+    <tt>System/Library/CoreServices</tt> directory,</i></b> since that's
+    the default location of the OS X boot loader! <i>Never</i> delete this
+    directory from your OS X root (<tt>/</tt>) partition, only from the
+    partition you specified to <tt>refind-install</tt> using the
+    <tt>--ownhfs</tt> option.</li>
+
+<li>Once you've identified the rEFInd directory, delete it, or at least the
+    rEFInd boot file. This file may be called <tt>refind_x64.efi</tt>,
+    <tt>bootx64.efi</tt>, <tt>boot.efi</tt>, or conceivably something else.
+    You may need to use <tt>sudo rm</tt> at the command line to accomplish
+    this task, as in <tt class="userinput">sudo rm -r
+    /Volumes/ESP/EFI/refind</tt>.</li>
+
+</ol>
+
+<a name="uinst_windows">
+<h3>Uninstalling rEFInd from Windows</h3>
+</a>
+
+<p>From Windows, you must reverse the directions for <a href="#windows">installing in Windows</a>&mdash;type <tt class="userinput">mountvol S: /S</tt> to mount your ESP as <tt>S:</tt>, then navigate to the <tt>S:\EFI</tt> directory and delete the <tt>refind</tt> subdirectory.</p>
+
+<a name="post_uninst">
+<h3>Post-Uninstallation Activity (UEFI-Based PCs)</h3>
+</a>
+
+<p>On a UEFI-based PC, when the computer boots and cannot find the rEFInd files, it should move on to the next boot loader in its list. In my experience, some EFI firmware implementations remove boot loaders they can't find from their NVRAM lists, so nothing else will be required, provided you have another working boot loader in your firmware's list. If your firmware doesn't automatically clean up its NVRAM entries, rEFInd's entry will do little harm; however, you can delete it with the <tt>efibootmgr</tt> utility in Linux:</p>
+
+<pre class="listing">
+# <tt class="userinput">efibootmgr --verbose</tt>
+Timeout: 10 seconds
+BootOrder: 0000,0007
+Boot0000* rEFInd       HD(2,1b8,64000,f1b7598e-baa8-16ea-4ef6-3ff3b606ac1e)File(\EFI\refind\refind_x64.efi)
+Boot0007* CD/DVD Drive BIOS(3,0,00)PATA: HP DVD Writer 1040r     .
+# <tt class="userinput">efibootmgr --delete-bootnum --bootnum 0000</tt>
+Timeout: 10 seconds
+BootOrder: 0007
+Boot0007* CD/DVD Drive</pre>
+
+<p>This example shows use of <tt>efibootmgr</tt>'s <tt>--verbose</tt> (<tt>-v</tt>) option to display boot programs so as to identify which one is rEFInd, followed by <tt>--delete-bootnum</tt> (<tt>-B</tt>) to delete a boot program and <tt>--bootnum</tt> (<tt>-b</tt>) to identify which one to delete. Of course, in this example there's not much else left, so you'd presumably want to install another boot program at this point! If you already have another one installed, you may want to check the <tt>BootOrder</tt> line to determine which one will take precedence when you reboot. If you don't like what it shows, you can adjust it with the <tt>--bootorder</tt> (<tt>-o</tt>) option; consult <tt>efibootmgr</tt>'s <tt>man</tt> page for details.</p>
+
+<p>If you're not using Linux, you may be able to find a utility that serves
+a similar function. Under Windows, the <tt>bcdedit</tt> command, described
+in the <a href="#windows">section on installing rEFInd under Windows,</a>
+may work, although I've not attempted this.</p>
+
+<hr />
+
+<p>copyright &copy; 2012&ndash;2015 by Roderick W. Smith</p>
+
+<p>This document is licensed under the terms of the <a href="FDL-1.3.txt">GNU Free Documentation License (FDL), version 1.3.</a></p>
+
+<p>If you have problems with or comments about this Web page, please e-mail me at <a href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.com.</a> Thanks.</p>
+
+<p><a href="index.html">Go to the main rEFInd page</a></p>
+
+<p><a href="yosemite.html">Comments on rEFInd and OS X 10.10 (Yosemite)</a></p>
+
+  <p><a href="http://www.rodsbooks.com/">Return</a> to my main Web page.</p>
+</body>
+</html>
diff --git a/docs/refind/linux.html b/docs/refind/linux.html
new file mode 100644 (file)
index 0000000..2741837
--- /dev/null
@@ -0,0 +1,504 @@
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>The rEFInd Boot Manager: Methods of Booting Linux</title>
+  <link href="../Styles/styles.css" rel="stylesheet" type="text/css" />
+</head>
+
+<meta name="viewport" content="width=device-width, initial-scale=1">
+
+<body>
+<h1>The rEFInd Boot Manager:<br />Methods of Booting Linux</h1>
+
+<p class="subhead">by Roderick W. Smith, <a
+href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.com</a></p>
+
+<p>Originally written: 3/19/2012; last Web page update:
+11/8/2015, referencing rEFInd 0.10.0</p>
+
+
+<p>This Web page is provided free of charge and with no annoying outside ads; however, I did take time to prepare it, and Web hosting does cost money. If you find this Web page useful, please consider making a small donation to help keep this site up and running. Thanks!</p>
+
+<table border="1">
+<tr>
+<td>Donate $1.00</td>
+<td>Donate $2.50</td>
+<td>Donate $5.00</td>
+<td>Donate $10.00</td>
+<td>Donate $20.00</td>
+<td>Donate another value</td>
+</tr>
+<tr>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="1.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="2.50">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="5.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="10.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="20.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td></tr>
+</table>
+
+<hr />
+
+<p>This page is part of the documentation for the rEFInd boot manager. If a Web search has brought you here, you may want to start at the <a href="index.html">main page.</a></p>
+
+<hr />
+
+<div style="float:right; width:55%">
+
+<p>Windows and Mac OS X both provide relatively simple EFI boot loader programs. Launch them, and if they're launched from the correct locations and have the correct files in place, they'll boot their respective OSes. This makes rEFInd's job easy; it just locates the boot loader program files and runs them.</p>
+
+</div>
+
+<div class="navbar">
+
+<h4 class="tight">Contents</h4>
+
+<ul>
+
+<li class="tight"><a href="#traditional">Using a Traditional Linux Boot Loader</li>
+
+<li class="tight"><a href="#quickstart">Using the EFI Stub Loader: Three Configuration Options</a>
+
+<ul>
+
+<li class="tight"><a href="#easiest">For Those With Foresight or Luck: The Easiest Method</a></li>
+
+<li class="tight"><a href="#testing">Preparing a Test Configuration</a></li>
+
+<li class="tight"><a href="#reconfigure">If You Need to Reconfigure Your Partitions....</a></li>
+
+</ul></li>
+
+<li class="tight"><a href="#efistub">EFI Stub Loader Support Technical Details</a></li>
+
+</ul>
+
+</div>
+
+<p>Under Linux, by contrast, things can get complicated. As detailed on my <a href="http://www.rodsbooks.com/efi-bootloaders/index.html">Managing EFI Boot Loaders for Linux</a> page, several different EFI boot loaders for Linux exist, and all of them require configuration. If you're lucky, your distribution will have set up a Linux boot loader in a sensible way, in which case rEFInd should detect it and it will work as easily as a Windows or Mac OS X boot loader. If you're not lucky, though, you may need to configure it further. rEFInd offers options to help out with this task. Naturally, rEFInd supports <a href="#traditional">traditional Linux boot loaders.</a> It works even better with the Linux EFI stub loader, so I provide <a href="#quickstart">instructions on starting with it.</a> For those interested in manual configuration, I also provide <a href="#efistub">detailed instructions</a> on how the EFI stub support works and how to configure it.</p>
+
+<a name="traditional">
+<h2>Using a Traditional Linux Boot Loader</h2>
+</a>
+
+<p>I consider <a href="http://www.rodsbooks.com/efi-bootloaders/elilo.html">ELILO</a>, <a href="http://www.rodsbooks.com/efi-bootloaders/grub_legacy.html">GRUB Legacy</a>, <a href="http://www.rodsbooks.com/efi-bootloaders/grub2.html">GRUB 2</a>, and <a href="http://www.rodsbooks.com/efi-bootloaders/syslinux.html">SYSLINUX</a> to be traditional Linux boot loaders. These programs all exist independent of the Linux kernel, but they can load a kernel and hand off control to it. All four programs have their own configuration files that reside in the same directory as the boot loader itself (or optionally elsewhere, in the case of GRUB 2).</p>
+
+<p>Ordinarily, rEFInd will detect these traditional boot loaders and provide main menu entries for them. If the boot loader exists in a directory with a name that matches a Linux distribution's icon filename, you'll automatically get a distribution-specific icon to refer to the boot loader.</p>
+
+<p>If you prefer, you can disable automatic scanning and create an entry in <tt>refind.conf</tt> for your distribution, as described on the <a href="configfile.html">Configuring the Boot Manager</a> page. This method is harder to set up but can be preferable if you want to customize your options.</p>
+
+<a name="quickstart">
+<h2>Using the EFI Stub Loader: Three Configuration Options</h2>
+</a>
+
+<p>The EFI stub loader is basic and reliable, but it requires some setup to use it on some computers. It also requires that you run a kernel with the same bit width as your EFI. In most cases, this means running a 64-bit kernel, since 32-bit EFI-based computers are so rare. I describe three methods of using the EFI stub loader: an <a href="#easiest">easiest method</a> for those with compatible partition and filesystem layouts, a <a href="#testing">quick test configuration</a> for those without such a layout, and <a href="#reconfigure">a long-term setup</a> for those without the ideal setup.</p>
+
+<a name="easiest">
+<h3>For Those With Foresight or Luck: The Easiest Method</h3>
+</a>
+
+<p>This method requires that your <tt>/boot</tt> directory, whether it's on a separate partition or is a regular directory in your root (<tt>/</tt>) filesystem, be readable by the EFI. At the moment, all EFI implementations can read FAT and Macs can read HFS+. By using <a href="drivers.html">drivers,</a> you can make any EFI read HFS+, ISO-9660, ReiserFS, ext2fs, ext3fs, ext4fs, Btrfs, or other filesystems. Thus, if you use any of these filesystems on a regular partition (not an LVM or RAID configuration) that holds your kernels in <tt>/boot</tt>, you qualify for this easy method. The default partition layouts used by Ubuntu, Fedora, and many other distributions qualify, because they use one of these filesystems (usually ext4fs) in a normal partition or on a separate <tt>/boot</tt> partition. You must also have a 3.3.0 or later Linux kernel with EFI stub support, of course.</p>
+
+<p>If you installed rEFInd 0.6.0 or later with its <tt>refind-install</tt> (formerly <tt>install.sh</tt>) script from your regular Linux installation, chances are everything's set up; you should be able to reboot and see your Linux kernels as boot options. If you installed manually, from OS X, or from an emergency system, though, you may need to do a couple of things manually:
+
+<ul>
+
+<li>Copy the relevant driver file for your filesystem and architecture to
+    the <tt>drivers</tt> or <tt>drivers_<tt class="variable">arch</tt></tt>
+    subdirectory of the rEFInd installation directory on the EFI System
+    Partition (ESP). You may need to create this subdirectory, too.</li>
+
+<li>Create a <tt>refind_linux.conf</tt> file in your <tt>/boot</tt>
+    directory. The <tt>mkrlconf</tt> script that comes with rEFInd
+    should do this job, or you can do it manually as described <a
+    href="#efistub">later.</a> Starting with version 0.6.12, rEFInd can
+    create minimal boot options from <tt>/etc/fstab</tt>, if <tt>/boot</tt>
+    is <i>not</i> a separate partition, so a <tt>refind_linux.conf</tt>
+    file may not be strictly necessary. Version 0.9.0 also adds the ability
+    to identify the root (<tt>/</tt>) partition via the <a
+    href="http://www.freedesktop.org/wiki/Specifications/DiscoverablePartitionsSpec/">Discoverable
+    Partitions Spec,</a> if your disk uses the appropriate type codes. A
+    <tt>refind_linux.conf</tt> file remains desirable, though, and is
+    necessary in some situations.</li>
+
+</ul>
+
+<p>When you reboot, you should see rEFInd options for your Linux kernels. If they work, your job is done, although you might want to apply some of the tweaks described in the <a href="#reconfigure">maintenance-free setup</a> section. If you have problems, you may need to adjust the <tt>refind_linux.conf</tt> file, as described in the <a href="#efistub">detailed configuration section.</a></p>
+
+<a name="testing">
+<h3>Preparing a Test Configuration</h3>
+</a>
+
+<p>If you're not sure you want to use the EFI stub loader in the long term, you can perform a fairly quick initial test of it. This procedure assumes that you have access to a 3.3.0 or later Linux kernel with EFI stub support compiled into it. (Fedora since version 17, Ubuntu since 12.10, and most other distributions ship with such kernels.) Creating this configuration poses no risk to your current boot options, provided you don't accidentally delete existing files. The procedure for a quick test is:</p>
+
+<ol>
+
+<li>Copy your kernel file (<tt>vmlinuz-*</tt>) and matching initial RAM
+    disk file (<tt>init*</tt>) from <tt>/boot</tt> to a subdirectory of
+    <tt>EFI</tt> on your ESP. Your distribution's directory there should
+    work fine. For instance, typing <tt class="userinput">cp
+    /boot/vmlinuz-4.2.5-300.fc23.x86_64
+    /boot/initramfs-4.2.5-300.fc23.x86_64.img /boot/efi/EFI/fedora</tt> might
+    do the trick on a Fedora system, although you'll probably have to
+    adjust the version numbers. Note that the filename forms vary from one
+    distribution to another, so don't worry if yours look different from
+    these. Be sure that you match up the correct files by version number,
+    though.</li>
+
+<li>Copy the <tt>/boot/refind_linux.conf</tt> file to the same directory to
+    which you copied your kernel. If this file doesn't exist, create it by
+    running (as <tt>root</tt>) the <tt>mkrlconf</tt> script that came
+    with rEFInd. This step may not be strictly necessary if <tt>/boot</tt>
+    is an ordinary directory on your root (<tt>/</tt>) partition.</li>
+
+<li>Reboot. You should now see a new entry for launching the Linux kernel
+    that you copied. Try the option. If it works, great. If not, you may
+    need to adjust your <tt>refind_linux.conf</tt> file. See the <a
+    href="#efistub">detailed configuration section</a> for a description of
+    this file's format. If the kernel begins to boot but complains that it
+    couldn't find its root filesystem, double-check the version numbers on
+    your kernel and initial RAM disk file, and check the <tt>root=</tt>
+    option in <tt>refind_linux.conf</tt>.</li>
+
+</ol>
+
+<p>You can continue to boot your computer with this type of configuration; however, the drawback is that you'll need to copy your kernel whenever it's updated. This can be a hassle. A better way is to configure you system so that the EFI, and therefore rEFInd, can read your Linux <tt>/boot</tt> directory, where most Linux distributions place their kernels.</p>
+
+<a name="reconfigure">
+<h3>If You Need to Reconfigure Your Partitions....</h3>
+</a>
+
+<p>If your <tt>/boot</tt> directory happens to be on an XFS or JFS partition that the EFI can't read, or it's tucked away in an LVM or RAID configuration that the EFI can't read, you won't be able to use the <a href="#easiest">easiest solution.</a> Fortunately, this problem can be overcome with relatively little fuss. Several variant procedures are possible, but I begin by describing one that will almost always work, although it's got some important caveats (described at the end). You should perform the following steps as <tt>root</tt>, or precede each of these commands with <tt>sudo</tt>:</p>
+
+<ol>
+
+<li>Begin with your ESP mounted at <tt>/boot/efi</tt>, which is the most
+    common location. If it's not mounted there, type <tt
+    class="userinput">mount /dev/sda1 /boot/efi</tt> to do so (adjusting
+    <tt>/dev/sda1</tt>, if necessary), or mount it elsewhere and adjust the
+    paths in the following procedure as necessary.</li>
+
+<li>Check the size of the ESP by typing <tt class="userinput">df -h
+    /boot/efi</tt>. The ESP must be large enough to hold several Linux
+    kernels and initial RAM disk files&mdash;100MiB at a bare minimum, and
+    preferably 200&ndash;500MiB.</li>
+
+<li>Check your <tt>/boot</tt> directory to be sure it contains no links or
+    other files that rely on Unix/Linux-style permissions or ownership. If
+    it does, don't proceed, or at least research these files further to
+    determine if you can work around the need for such permissions and
+    ownership.</li>
+
+<li>Type <tt class="userinput">cp -r /boot/* /boot/efi</tt>. You'll see an
+    error message about being unable to copy <tt>/boot/efi</tt> into
+    itself. Ignore this.</li>
+
+<li>Type <tt class="userinput">umount /boot/efi</tt>.</li>
+
+<li>Edit <tt>/etc/fstab</tt> and change the mount point for
+    <tt>/boot/efi</tt> to <tt>/boot</tt>. If the ESP isn't present in
+    <tt>/etc/fstab</tt>, you must create an entry for it, with a mount
+    point of <tt>/boot</tt>.</li>
+
+<li>Type <tt class="userinput">mount -a</tt> to re-mount everything,
+    including <tt>/boot</tt>. Check that your normal <tt>/boot</tt> files
+    are all present, along with the new <tt>/boot/EFI</tt> directory, which
+    holds what used to be <tt>/boot/efi/EFI</tt>. If something seems to be
+    missing (other than <tt>/boot/efi</tt> with a lowercase <tt>efi</tt>),
+    then you should try to correct the problem.</li>
+
+<li>If it doesn't already exist, create a file called
+    <tt>/boot/refind_linux.conf</tt> and populate it with kernel options,
+    as described <a href="#refind_linux">later.</a> If this file doesn't
+    already exist, the easiest way to create it is to run the
+    <tt>mkrlconf</tt> script that comes with rEFInd 0.5.1 and
+    later.</li>
+
+<li>Check your <tt>refind.conf</tt> file (presumably in
+    <tt>/boot/EFI/refind</tt>) to be sure that the
+    <tt>scan_all_linux_kernels</tt> line is uncommented. If it's not,
+    uncomment that line.</li>
+
+<li>Optionally, type <tt class="userinput">cp
+    /boot/EFI/refind/icons/os_<i>name</i>.icns /boot/.VolumeIcon.icns</tt>
+    to give loaders in <tt>/boot</tt> an icon for your distribution.</li>
+
+<li>Reboot to test that this configuration works.</li>
+
+</ol>
+
+<p>Recall that in step #4, you <i>copied</i> the contents of <tt>/boot</tt> (as a safety measure), but you did not move them. Therefore, you ended up with two copies of your kernels and other <tt>/boot</tt> directory contents, with one copy hiding the other when you mounted the ESP at <tt>/boot</tt>. Once you've booted successfully and are sure all is working well, you can recover some disk space by unmounting <tt>/boot</tt> and deleting the contents of the underlying <tt>/boot</tt> directory on your root (<tt>/</tt>) filesystem. Be sure that the <tt>/boot</tt> partition is unmounted before you do this, though! Also, be sure to leave the <tt>/boot</tt> directory itself in place, even if it has no contents; the directory is needed as a mount point for the <tt>/boot</tt> partition. Note that GRUB 2 may stop working if you delete its files from the root filesystem's <tt>/boot/grub</tt> directory, so if you want to keep GRUB around, you should re-install it with the separate <tt>/boot</tt> partition mounted.</p>
+
+<p>Once this task is done, updates to your kernel will automatically be stored in the root directory of your ESP, where rEFInd will automatically detect them. Thus, the boot configuration becomes maintenance-free. The procedure as just described has some drawbacks, though. By placing your kernels in the root directory of your ESP, you render them vulnerable to any other OS with which you might be dual-booting. Your ESP must also be large enough to hold all your kernels. If you dual-boot with multiple Linux distributions, they might conceivably overwrite each others' kernels, and distinguishing one from another becomes more difficult.</p>
+
+<p>For these reasons, a variant of this procedure is desirable on some systems. Most of the steps are similar, but in this variant, you create a separate <tt>/boot</tt> partition that's independent of the ESP. This partition can use FAT, HFS+, ReiserFS, ext2fs, ext3fs, ext4fs, or Btrfs; but if you use any of the last six filesystems (five on Macs), you must install the matching EFI filesystem driver that ships with rEFInd. Creating the filesystem will normally require you to shrink an existing partition by a suitable amount (200&ndash;500MiB). Mount your new <tt>/boot</tt> partition at a temporary location, copy or move the current <tt>/boot</tt> files into it, unmount it, and add it to <tt>/etc/fstab</tt> as <tt>/boot</tt>.</p>
+
+<p>If your distribution already uses a separate <tt>/boot</tt> partition, but if it uses XFS or some other unsuitable filesystem, you can back it up, create a fresh FAT, HFS+, ReiserFS, Btrfs, ext2, ext3, or ext4 filesystem on it, and restore the original files. You'll probably need to adjust the UUID value in <tt>/etc/fstab</tt> to ensure that the computer mounts the new filesystem when you boot. If you use a separate non-ESP <tt>/boot</tt> partition, you'll probably want to continue mounting the ESP at <tt>/boot/efi</tt>.</p>
+
+<a name="efistub">
+<h2>EFI Stub Loader Support Technical Details</h2>
+</a>
+
+<p>The Linux <a href="http://www.rodsbooks.com/efi-bootloaders/efistub.html">EFI stub loader</a> is a way to turn a Linux kernel into an EFI application. In a sense, the kernel becomes its own boot loader. This approach to booting Linux is very elegant in some ways, but as described on the page to which I just linked, it has its disadvantages, too. One challenge to booting in this way is that modern Linux installations typically require that the kernel be passed a number of options at boot time. These tell the kernel where the Linux root (<tt>/</tt>) filesystem is, where the initial RAM disk is, and so on. Without these options, Linux won't boot. These options are impossible for a generic boot loader to guess without a little help. It's possible to build a kernel with a default set of options, but this is rather limiting. Thus, rEFInd provides configuration options to help.</p>
+
+<p>With all versions of rEFInd, you can create manual boot loader stanzas
+in the <tt>refind.conf</tt> file to identify a Linux kernel and to pass it
+all the options it needs. This approach is effective and flexible, but it
+requires editing a single configuration file for all the OSes you want to
+define in this way. If a computer boots two different Linux distributions,
+and if both were to support rEFInd, problems might arise as each one tries
+to modify its own rEFInd configuration; or the one that controls rEFInd
+might set inappropriate options for another distribution. This is a problem
+that's been a minor annoyance for years under BIOS, since the same
+potential for poor configuration applies to LILO, GRUB Legacy, and GRUB 2
+on BIOS. The most reliable solution under BIOS is to chainload one boot
+loader to another. The same solution is possible under EFI, but rEFInd
+offers another possibility.</p>
+
+<p>rEFInd supports semi-automatic Linux EFI stub loader detection. This
+feature works as part of the standard boot loader scan operation, but it
+extends it as follows:</p>
+
+<ol>
+
+<li>rEFInd looks for boot loaders whose names include the strings
+    <tt>bzImage</tt> or <tt>vmlinuz</tt>. For instance,
+    <tt>bzImage-3.19.0.efi</tt> or <tt>vmlinuz-4.2.0</tt> would match, and
+    trigger subsequent steps in this procedure. The
+    <tt>scan_all_linux_kernels</tt> option in <tt>refind.conf</tt> controls
+    the scanning for kernels whose names do not end in <tt>.efi</tt>; if
+    this option is set to <tt>false</tt>, kernel filenames must end in
+    <tt>.efi</tt> to be picked up by rEFInd. This option is set to
+    <tt>true</tt> by default, but you can change it if you don't want to
+    scan all Linux kernels.</li>
+
+<li>If a file's name ends in <tt>.efi.signed</tt>, any other file with an
+    otherwise-identical name that <i>lacks</i> this extension is excluded.
+    This peculiar rule exists because Ubuntu delivers two
+    copies of every kernel, one with and one without this extension. The
+    one with the extension is signed with a Secure Boot key; the one
+    without it is not so signed. Thus, if both files are present, the one
+    without the key won't boot on a computer with Secure Boot active, and
+    either will boot if Secure Boot is inactive. Thus, rEFInd excludes the
+    redundant (unsigned) file in order to help keep the list of boot
+    options manageable.</li>
+
+<p class="sidebar">A kernel whose filename lacks a version string matches an initial RAM disk that also lacks a version string in its filename. Note that you can reliably use only <i>one</i> kernel and initial RAM disk per directory that lack version numbers in their filenames.</p>
+
+<li>rEFInd looks for an initial RAM disk in the same directory as the
+    kernel file. A matching initial RAM disk has a name that begins with
+    <tt>init</tt> and that includes the same version string as the kernel.
+    The version string is defined as the part of the filename from the
+    first digit to the last digit, inclusive. Note that the version string
+    can include non-digits. For instance, the version string for
+    <tt>bzImage-3.19.0.efi</tt> is <tt>3.19.0</tt>, which matches
+    <tt>initramfs-3.19.0.bz</tt>; and
+    <tt>vmlinuz-4.2.5-300.fc23.x86_64</tt>'s version string is
+    <tt>4.2.5-300.fc23.x86_64</tt>, which matches
+    <tt>initrd-4.2.5-300.fc23.x86_64.img</tt>. Many other matches are
+    possible. If an initial RAM disk is identified, rEFInd passes a
+    suitable <tt>initrd=</tt> option to the kernel when it boots.</li>
+
+<li>rEFInd looks for a file called <tt>refind_linux.conf</tt> in the same
+    directory as the kernel file. It consists of a series of lines,
+    each of which consists of a label followed by a series of kernel
+    options. The first line sets default options, and subsequent lines set
+    options that are accessible from the main menu tag's submenu screen. If
+    you installed rEFInd with the <tt>refind-install</tt>
+    script, that script created a sample <tt>refind_linux.conf</tt> file,
+    customized for your computer, in <tt>/boot</tt>. This file will work
+    without changes on many installations, but you may need to tweak it for
+    some.</li>
+
+<li>If rEFInd can't find a <tt>refind_linux.conf</tt> file in the directory
+    that holds the kernel, the program looks for a file called
+    <tt>/etc/fstab</tt> on the partition that holds the kernel. If this
+    standard Linux file is present, rEFInd uses it to identify the root
+    (<tt>/</tt>) filesystem and creates two sets of Linux kernel boot
+    options: One set launches the kernel normally, but with minimal
+    options, and the other set launches the kernel into single-user mode.
+    This step can get a computer to boot without any rEFInd-specific
+    configuration files, aside from <tt>refind.conf</tt> in rEFInd's own
+    directory, but only if <tt>/boot</tt> is not a separate partition. The
+    intent is to facilitate the use of rEFInd as an emergency boot manager
+    or to help users who must install rEFInd from OS X or Windows. Note
+    that rEFInd uses <tt>/etc/fstab</tt> only if <tt>refind_linux.conf</tt>
+    is <i>not</i> found.</li>
+
+<li>If rEFInd can't find a <tt>refind_linux.conf</tt> file or an
+    <tt>/etc/fstab</tt> file, it tries to identify the Linux root
+    (<tt>/</tt> filesystem by looking for a partition with a GUID type code
+    matching that specified for the root (<tt>/</tt>) filesystem in the <a
+    href="http://www.freedesktop.org/wiki/Specifications/DiscoverablePartitionsSpec/">Freedesktop.org
+    Discoverable Partitions Specification.</a> These type codes are as yet
+    seldom used, but if and when they become common, they should help a lot
+    for situations similar to those of the preceding case, but when a
+    separate <tt>/boot</tt> partition is used.</li>
+
+</ol>
+
+<p>The intent of this system is that distribution maintainers can place their kernels, initial RAM disks, and a <tt>refind_linux.conf</tt> file in their own subdirectories on the ESP, on EFI-accessible <tt>/boot</tt> partitions, or in <tt>/boot</tt> directories on EFI-accessible Linux root (<tt>/</tt>) partitions. rEFInd will detect these kernels and create one main menu entry for each directory that holds kernels; or if <tt>fold_linux_kernels</tt> is set to <tt>false</tt>, one menu entry for each kernel. Each entry will implement as many options as there are lines in the <tt>refind_linux.conf</tt> file (multiplied by the number of kernels, if <tt>fold_linux_kernels</tt> is <tt>true</tt>). In this way, two or more distributions can each maintain their boot loader entries, without being too concerned about who maintains rEFInd as a whole.</p>
+
+<p>As an example, consider the following (partial) file listing:</p>
+
+<pre class="listing">
+$ <b>ls -l /boot/vmlin*</b>
+total 17943
+-rw-r--r-- 1 root root 5271984 Aug  7 10:18 /boot/vmlinuz-3.16.7-24-default
+-rw-r--r-- 1 root root 5271536 Oct 23 17:25 /boot/vmlinuz-3.16.7-29-default
+</pre>
+
+<p>When rEFInd scans this directory, it will discover two kernels in <tt>/boot</tt>. Assuming <tt>fold_linux_kernels</tt> is its default of <tt>true</tt>, rEFInd will create one main-menu tag for these two kernels. A <tt>refind_linux.conf</tt> file in this directory should contain a list of labels and options:</p>
+
+<a name="refind_linux">
+<pre class="listing">
+"Boot with standard options"  "ro root=UUID=084f544a-7559-4d4b-938a-b920f59edc7e splash=silent quiet showopts "
+"Boot to single-user mode"    "ro root=UUID=084f544a-7559-4d4b-938a-b920f59edc7e splash=silent quiet showopts single"
+"Boot with minimal options"   "ro root=UUID=084f544a-7559-4d4b-938a-b920f59edc7e"
+# This line is a comment
+</pre>
+</a>
+
+<p>Ordinarily, both fields in this file must be enclosed in quotes. If you have to pass an option that includes quotes, you can do so by doubling up on them, as in <tt>"root=/dev/sdb9 my_opt=""this is it"""</tt>, which passes <tt>root=/dev/sdb9 my_opt="this is it"</tt> to the shell. You can include as much white space as you like between options. You can also place comments in the file, or remove an option by commenting it out with a leading hash mark (<tt>#</tt>), as in the fourth line in this example.</p>
+
+<p>In the preceding example, the first line sets the options that rEFInd passes to the kernel by default (along with the name of the discovered initrd file, since its version string matches that of the kernel). The next two lines set options that you can obtain by pressing Insert, F2, or + on the main menu, as shown here:</p>
+
+    <br /><center><img src="automatic-submenu.png" align="center"
+    width="622" height="210" alt="rEFInd can load Linux boot options from
+    a refind_linux.conf file in the Linux kernel's directory."
+    border=2></center><br />
+
+<p>Note that in this example, the default kernel (the one with the most recent time stamp) appears first on the list, with the labels specified in <tt>refind_linux.conf</tt>. Subsequent kernels (just one in this example) appear below it, with the same labels preceded by the kernel filename. If you were to set <tt>fold_linux_kernels false</tt>, each kernel would get its own entry on the main menu, and each one's submenu would enable options for launching it alone.</p>
+
+<p>To assist in initial configuration, rEFInd's <tt>refind-install</tt> script creates a sample <tt>refind_linux.conf</tt> file in <tt>/boot</tt>. This sample file defines three entries, the first two of which use the default GRUB options defined in <tt>/etc/default/grub</tt> and the last of which uses minimal options. The first entry boots normally and the second boots into single-user mode. If you want to create a new file, you can use the <tt>mkrlconf</tt> script that comes with rEFInd. If you pass it the <tt>--force</tt> option, it will overwrite the existing <tt>/boot/refind_linux.conf</tt> file; otherwise it will create the file only if one doesn't already exist.</p>
+
+<p>From a user's perspective, the submenus defined in this way work just like submenus defined via the <tt>submenuentry</tt> options in <tt>refind.conf</tt>, or like the submenus that rEFInd creates automatically for Mac OS X or ELILO. There are, however, limitations in what you can accomplish with this method:</p>
+
+<ul>
+
+<li>Your kernels must be compiled with EFI stub loader support. (This is
+    almost always true of distribution-provided kernels these days.)</li>
+
+<li>You can't set a submenu option to boot via a different boot loader,
+    such as ELILO or GRUB; all the submenu options apply to a single boot
+    loader&mdash;that is, a single kernel. (rEFInd will still detect other
+    boot loaders and provide separate main-menu tags for them,
+    though.) Folded kernel entries are an exception to this rule.</li>
+
+<li>All the kernels in a given directory use the same
+    <tt>refind_linux.conf</tt> file. If you need to set different options
+    for different kernels, you'll need to place those kernels in different
+    directories.</li>
+
+<li>You must place your kernels in a directory other than the one that
+    holds the main rEFInd <tt>.efi</tt> file. This is because rEFInd does
+    not scan its own directory for boot loaders.</li>
+
+</ul>
+
+<p>Ordinarily, a kernel booted in this way must reside on the ESP, or at least on another FAT partition. On a Macintosh, though, you can use HFS+ to house your kernel files. In fact, that may be necessary; my Mac Mini hangs when I try to boot a Linux kernel via an EFI stub loader from the computer's ESP, but it works fine when booting from an HFS+ partition. If you use <a href="drivers.html">EFI drivers,</a> though, you can place your kernel on any filesystem for which an EFI driver exists. This list is currently good (ext2fs/ext3fs, ext4fs, ReiserFS, Btrfs, ISO-9660, HFS+, and NTFS in rEFInd, plus more from other sources), so chances are you'll be able to use this method to boot your kernel from your root (<tt>/</tt>) partition or from a <tt>/boot</tt> partition.</p>
+
+<p>rEFInd sorts boot loader entries <i>within each directory</i> by time stamp, so that the most recent entry comes first. Thus, if you specify a directory name (or a volume label, for loaders stored in a volume's root directory) as the <tt>default_selection</tt>, rEFInd will make the most recent loader in the directory the default. This can obviate the need to adjust this configuration parameter when you add a new kernel; chances are you want the most recently-added kernel to be the default, and rEFInd makes it so when you set the <tt>default_selection</tt> in this way. If you <i>don't</i> want the latest kernel to become the default, you can use <tt>touch</tt> to give the desired kernel (or other boot loader) in the directory a more recent time stamp, or you can set <tt>default_selection</tt> to a value that uniquely identifies your desired default loader. One caveat you should keep in mind is that the EFI and Windows interpret the hardware clock as local time, whereas Mac OS X uses <a href="http://en.wikipedia.org/wiki/Coordinated_Universal_Time">Coordinated Universal Time (UTC)</a>. Linux can work either way. Thus, time stamps for boot loaders can be skewed by several hours depending on the environment in which they were created or last modified.</p>
+
+<p class="sidebar"><b>Tip for distribution maintainers:</b> If you maintain an <tt>EFI/<tt class="variable">distname</tt></tt> directory for your kernels, you can place your version of rEFInd in a directory called <tt>EFI/<tt class="variable">distname</tt>/refind</tt>. This will avoid collisions with duplicate rEFInd installations from other distributions.</p>
+
+<p>On the whole, auto-detecting kernels and passing boot options using <tt>refind_linux.conf</tt> has a lot going for it. For distribution maintainers, if you place your Linux kernel files (with EFI stub support) on the ESP, with suitable filenames, matching initial RAM disk files, and a <tt>refind_linux.conf</tt> file, then rEFInd should detect your files, even if the user installs another distribution with another rEFInd that takes over from yours. (If the user, or this other rEFInd installation, disables auto-detection, this won't work.)</p>
+
+<p>For end users, this method is simpler than maintaining manual configurations in <tt>refind.conf</tt> (or equivalents for ELILO or GRUB). To install a new kernel, you need only copy it and its initial RAM disk, under suitable names, to a scanned directory on the ESP. There's no need to touch any configuration file, provided you've already set up <tt>refind_linux.conf</tt> in your kernel's directory. You will, however, have to adjust <tt>refind_linux.conf</tt> if you make certain changes, such as if your root directory identifier changes.</p>
+
+<hr/>
+
+<p>copyright &copy; 2012&ndash;2015 by Roderick W. Smith</p>
+
+<p>This document is licensed under the terms of the <a href="FDL-1.3.txt">GNU Free Documentation License (FDL), version 1.3.</a></p>
+
+<p>If you have problems with or comments about this Web page, please e-mail me at <a href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.com.</a> Thanks.</p>
+
+<p><a href="index.html">Go to the main rEFInd page</a></p>
+
+<p><a href="secureboot.html">Learn how to manage Secure Boot</a></p>
+
+  <p><a href="http://www.rodsbooks.com/">Return</a> to my main Web page.</p>
+</body>
+</html>
diff --git a/docs/refind/manual-submenu.png b/docs/refind/manual-submenu.png
new file mode 100644 (file)
index 0000000..f04e398
Binary files /dev/null and b/docs/refind/manual-submenu.png differ
diff --git a/docs/refind/os_legacy.png b/docs/refind/os_legacy.png
new file mode 100644 (file)
index 0000000..74d0abc
Binary files /dev/null and b/docs/refind/os_legacy.png differ
diff --git a/docs/refind/refind-background-snowy.png b/docs/refind/refind-background-snowy.png
new file mode 100644 (file)
index 0000000..b8c7815
Binary files /dev/null and b/docs/refind/refind-background-snowy.png differ
diff --git a/docs/refind/refind-background.png b/docs/refind/refind-background.png
new file mode 100644 (file)
index 0000000..2150410
Binary files /dev/null and b/docs/refind/refind-background.png differ
diff --git a/docs/refind/refind.png b/docs/refind/refind.png
new file mode 100644 (file)
index 0000000..bfc7884
Binary files /dev/null and b/docs/refind/refind.png differ
diff --git a/docs/refind/revisions.html b/docs/refind/revisions.html
new file mode 100644 (file)
index 0000000..dea6b1e
--- /dev/null
@@ -0,0 +1,349 @@
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>The rEFInd Boot Manager: Revisions</title>
+  <link href="../Styles/styles.css" rel="stylesheet" type="text/css" />
+</head>
+
+<meta name="viewport" content="width=device-width, initial-scale=1">
+
+<body>
+<h1>The rEFInd Boot Manager:<br />Revisions</h1>
+
+<p class="subhead">by Roderick W. Smith, <a
+href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.com</a></p>
+
+<p>Last Web page update: 11/8/2015</p>
+
+<p>This Web page is provided free of charge and with no annoying outside ads; however, I did take time to prepare it, and Web hosting does cost money. If you find this Web page useful, please consider making a small donation to help keep this site up and running. Thanks!</p>
+
+<table border="1">
+<tr>
+<td>Donate $1.00</td>
+<td>Donate $2.50</td>
+<td>Donate $5.00</td>
+<td>Donate $10.00</td>
+<td>Donate $20.00</td>
+<td>Donate another value</td>
+</tr>
+<tr>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="1.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="2.50">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="5.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="10.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="20.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td></tr>
+</table>
+
+<hr />
+
+<p>This page is part of the documentation for the rEFInd boot manager. If a Web search has brought you here, you may want to start at the <a href="index.html">main page.</a></p>
+
+<hr />
+
+<p>The following summarizes changes in rEFInd's public releases:</p>
+
+<ul>
+
+<li><b>0.10.0 (11/8/2015)</b>&mdash;I've given this version an extra-large version number bump because of some highly user-visible changes, especially for Mac users. Changes include:
+
+  <ul>
+
+  <li>I've swapped out the old icons for new ones. I've replaced the old
+      icons because the OS icons were becoming a hopeless mish-mash of
+      styles and because I wanted to consolidate the icon collection to use
+      a more limited set of original sources for record-keeping purposes.
+      If you prefer the old icons, you can continue to use them. After
+      upgrading, rename <tt>icons-backup</tt> to something else (say,
+      <tt>icons-classic</tt>) and add a line to <tt>refind.conf</tt> to
+      reference the new directory, as in <tt>icons_dir
+      icons-classic</tt>.</li>
+
+  <li>A new feature, <tt>spoof_osx_version</tt>, causes rEFInd to tell a
+      Mac that it's about to launch OS X. This alters how some Macs
+      initialize hardware, which can make secondary video chipsets work on
+      some Macs. See the comments in <tt>refind.conf-sample</tt> or on the
+      <a href="using.html">Using rEFInd</a> page for details. This feature
+      has no effect on UEFI-based PCs.</li>
+
+  <li>Another new feature enables you to adjust a Mac's System Integrity
+      Protection (SIP) settings from within rEFInd. To use this feature,
+      you must adjust two lines in <tt>refind.conf</tt>: The new
+      <tt>csr_values</tt> line sets hexadecimal values through which you
+      can rotate using a new second-row tag that's activated by the new
+      <tt>scanfor</tt> line option of <tt>csr_rotate</tt>. Thus, you must
+      add or change both the <tt>scanfor</tt> and <tt>csr_values</tt>
+      lines. See the new <a href="sip.html">rEFInd and System Integrity
+      Protection</a> page for information on how to use this new feature.
+      Although this feature can work on UEFI-based PCs if they contain the
+      necessary NVRAM variable, such systems are unlikely to have this
+      variable, and it's unlikely to be useful even if it's present.</li>
+
+  <li>If the SIP NVRAM variable is set, rEFInd now displays its current
+      value in the About screen.</li>
+
+  <li>I've renamed several support scripts: <tt>install.sh</tt> to
+      <tt>refind-install</tt>, <tt>mvrefind.sh</tt> to <tt>mvrefind</tt>,
+      and <tt>mkrlconf.sh</tt> to <tt>mkrlconf</tt>. I've also added man
+      pages for <tt>mvrefind</tt> and <tt>mkrlconf</tt>.</li>
+
+  <li>Under OS X, <tt>refind-install</tt> now checks the machine's SIP
+      status and warns the user if it's active. To help with such
+      installations, the script can also now be run from a boot of the
+      Recovery HD.</li>
+
+  <li>Under Linux, <tt>refind-install</tt> and <tt>mkrlconf</tt> now use
+      <tt>/proc/cmdline</tt> as a source for the default boot options for
+      Linux kernels, rather than trying to extract them from GRUB
+      configuration files&mdash;<i>except</i> when the <tt>--root</tt>
+      option is used, in which case the script continues to use the GRUB
+      configuration files as a source of boot options. This change should
+      help rEFInd pick up exotic boot options that GRUB computes at boot
+      time, such as Btrfs subvolume options.</li>
+
+  <li>I've added a new script, called <tt>mountesp</tt>, which mounts the
+      ESP on Macs, using the same algorithm used by
+      <tt>refind-install</tt>. This should help Mac users who want to edit
+      their rEFInd configurations.</li>
+
+  <li>I've changed the default <tt>also_scan_dirs</tt> setting from
+      <tt>boot</tt> to <tt>boot,@/boot</tt>. This change helps rEFInd pick
+      up kernels from Btrfs volumes.</li>
+
+  <li>I've changed from <tt>.zip</tt> to a tarball (<tt>.tar.gz</tt>) as
+      the file format for the source code package. This change simply
+      reflects the fact that Linux is the only supported build environment
+      for rEFInd, and tarballs are more in line with that platform than are
+      <tt>.zip</tt> files. The primary binary file format remains a
+      <tt>.zip</tt> file, with Debian packages and RPMs also
+      available.</li>
+
+  <li>My 32-bit Mac Mini suffered from a bug that caused rEFInd's
+      icon-resizing code to hang in a conversion from floating-point to
+      integer values. I've therefore adjusted the icon-resizing code to
+      avoid doing floating-point computations. This change has a drawback,
+      though: It causes some images to acquire artifacts when resized,
+      particularly on 32-bit systems. If you run into such a problem, you
+      should scale your icon(s) or banner/background image so that it does
+      not need to be resized. Sorry, but between a system crash and minor
+      graphics artifacts, the graphics artifacts are the lesser of two
+      evils.</li>
+
+  </ul></li>
+
+<li><b>0.9.2 (9/19/2015)</b>&mdash;Soon after releasing 0.9.1, I started receiving bug reports about problems with it and Shim 0.8. (See <a href="https://sourceforge.net/p/refind/discussion/general/thread/2c248b11/?limit=25#1324">this thread</a> for one such report.) It turns out that the problem was not a new bug in rEFInd, but rather a change from Shim 0.7 to Shim 0.8 that made it next to useless with rEFInd. Specifically, Shim 0.8 now de-registers itself from the EFI after a follow-on program launches another one. This is done to avoid problems in a boot path in which Shim launches <tt>fallback.efi</tt>, which in turn launches <i>another</i> Shim. This creates a new problem, though: rEFInd can validate just one binary before it's "cut off" from Shim. Since rEFInd's drivers are binaries, if you use a single driver, that means that you won't be able to launch anything that requires validation via Shim. I quickly discovered a workaround, which I've implemented in this release. I consider this a "band-aid" patch, though, because it relies on a quirk of Shim's logic to bypass its de-registration. As such, the workaround in this release may break with a future Shim. A true fix will take longer to develop. I want to release this workaround version to head off further problems in the near term, though. This version also introduces a new feature, which is also Shim-related: Since version 0.7, Shim has supported launching binaries other than <tt>grubx64.efi</tt> by passing them on the command line. (Actually, Shim 0.4 supported this, but it required a broken path specification.) I've added support for this feature to <tt>install.sh</tt>: Adding the <tt>--keepname</tt> option to install.sh causes the script to preserve rEFInd's regular filename and to register the approprirate follow-on parameters to have Shim launch rEFInd by that name. This works, but is likely to be more delicate than using the default Shim follow-on name of <tt>grubx64.efi</tt>. The advantage, of course, is that rEFInd needn't "lie" about its name, which makes for less confusion in filenames. For the moment, the RPM and Debian packages I build do <i>not</i> use this new naming feature, since I can't be sure what version of Shim might be picked up. These changes do not affect users who do not use Secure Boot.</li>
+
+<li><b>0.9.1 (9/13/2015)</b>&mdash;This version has improved the Discoverable Partitions Specification (DPS) support in a number of ways that should make it more reliable when <tt>/etc/fstab</tt> omits references to the root (<tt>/</tt>) partition or when the GPT read-only or do-not-automount options are used to control these features. A stray DPS-related debugging print command has also been removed. I've improved rEFInd's ability to guess the Linux distribution by having it examine <tt>/etc/lsb-release</tt> as well as <tt>/etc/os_release</tt>, and I've added an icon for Elementary OS. Finally, I've made improvements to rEFInd's handling of case-insensitive string comparisons, which were buggy on some EFIs, particularly when rEFInd was compiled with GNU-EFI. rEFInd is still at the mercy of the EFI and support libraries, but many problem cases should now be resolved.</li>
+
+<li><b>0.9.0 (7/26/2015</b>&mdash;This version gets a bump up to 0.9.0 mainly because of a highly user-visible new feature: <i>kernel folding.</i> With kernel folding active, multiple Linux kernels in a single directory appear as just one main-menu entry, which launches the most recent kernel (by file timestamp) by default. Older kernels appear on the first one's submenu (accessed by hitting F2 or Insert). You can disable this new feature by setting <tt>fold_linux_kernels false</tt> in <tt>refind.conf</tt>. Another new feature is support for the <a href="http://www.freedesktop.org/wiki/Specifications/DiscoverablePartitionsSpec/">Discoverable Partitions Spec,</a> which enables rEFInd to locate the Linux root (<tt>/</tt>) partition without a <tt>refind_linux.conf</tt> or <tt>/etc/fstab</tt> entry. I know of no distribution that automatically sets up its partitions in this way, but if and when this starts to happen, rEFInd will be ready. Other changes are relatively minor: The Debian <tt>postinst</tt> script now calls <tt>install.sh</tt> with <tt>--localkeys</tt> if <tt>sbsign</tt> and <tt>openssl</tt> are available, which helps if using the Ubuntu PPA on a system with custom Secure Boot keys; I've fixed a packaging bug that prevented IA32 versions of filesystem drivers and <tt>gptsync</tt> to not be built in the PPA; <tt>mkrlconf.sh</tt> now refuses to run under OS X; rEFInd now skips checking for BIOS-mode boot code on UEFI-based PCs, which should speed it up a little; I've fixed a bug that caused rEFInd to crash if it found an existing but empty <tt>refind_linux.conf</tt> file; I've made minor code changes to enable rEFInd to build under GCC 5.1; and I've added a new icon for Kali Linux (provided by Francesco D'Eugenio).</li>
+
+<li><b>0.8.7 (3/1/2015)</b>&mdash;This release provides bug fixes and refinements to existing features. Several changes should reduce the odds of rEFInd crashing because of assorted problems. Other changes improve Secure Boot handling, including improved Secure Boot detection in <tt>install.sh</tt>, recognition of <tt>KeyTool.efi</tt> and <tt>KeyTool-signed.efi</tt> as MOK manager utilities, and reporting of Secure Boot status for <i>x</i>86 (IA-32) systems in the rEFInd information screen. Filesystem detection is improved (again), and XFS has been added as a known filesystem. Detection of FreeBSD's BIOS-mode boot loader is improved, which should give more Mac users the right OS icon when booting FreeBSD in BIOS mode. A bug in <tt>install.sh</tt> that caused inappropriate installation to the filename <tt>bootx64.efi</tt> or <tt>bootia32.efi</tt>, and failure to update the computer's boot list, has been squashed. Finally, I'm <i><b>deprecating</b></i> the use of <tt>fs<tt class="variable">x</tt>:</tt> notation for referring to filesystems. The numbering of filesystems is simply unreliable, and better alternatives (the use of partition GUIDs, partition names, and filesystem names) have been added in previous releases. The <tt>fs<tt class="variable">x</tt>:</tt> code remains in rEFInd, and if it's working for you, you can continue to use it; but sooner or later I'll remove that code, so you're advised to change your manual boot stanzas and other options that use it before that happens.</li>
+
+<li><b>0.8.6 (2/8/2015)</b>&mdash;Most (but not all) of this release's changes focus on Windows dual-booting and Mac-specific issues. There's a new Windows 8 icon, which is now used by default as the Windows icon, although the old icon remains available and is used for Windows XP and earlier boots on Macs. If the NTFS driver is loaded, rEFInd will now exclude non-bootable NTFS volumes from the Mac boot list (this change does not affect UEFI-based PCs). A bug that caused misidentification of whole disks and NTFS volumes as being FAT has been fixed (again, this problem affected Macs, not PCs). A couple of Mac-specific <tt>install.sh</tt> bugs have been fixed, resulting in more reliable identification of the ESP and of the installation directory. Previous versions ignored a volume name of "HFS+ volume" because that name was produced by earlier versions of the rEFInd HFS+ driver for all HFS+ volumes; but the current HFS+ driver produces a real volume name, so I've removed that special case from the code. I've removed the r472 rEFIt commit, introduced in 0.8.5, because it was causing some BMP files to fail to load. Finally, the <tt>hideui</tt> token in <tt>refind.conf</tt> now accepts a value of <tt>badges</tt>, which has the effect of hiding the disk-type badges associated with OS launch icons.</li>
+
+<li><b>0.8.5 (2/1/2015)</b>&mdash;The biggest single change with this version is a new NTFS driver contributed by Samuel Liao, who also contributed the Btrfs driver. Samuel also contributed some miscellaneous driver fixes and a change to the way the keyboard is handled, which improves responsiveness on some systems. This version also improves the way <tt>install.sh</tt> works under OS X. In particular, it tweaks the <tt>bless</tt> command in a way that may eliminate startup delays and it does a better job of detecting and replacing existing rEFInd installations (on the ESP), rather than blindly writing to <tt>EFI/BOOT</tt>. Finally, this version applies <a href="https://sourceforge.net/p/refit/code/commit_browser">commits from late in rEFIt's history:</a> r467, which improves handling of BIOS/legacy boots from the second and subsequent disks on Macs; and r472, which enables handling BMP images that are not vertically flipped. These commits were not present in rEFInd from the start because the starting point for rEFInd was a Debian source package taken from a slightly earlier version.</li>
+
+<li><b>0.8.4 (12/8/2014)</b>&mdash;OS X 10.10 ("Yosemite") made changes that necessitated alterations to both rEFInd's <tt>install.sh</tt> script and rEFInd defaults. Specifically, Yosemite now uses a form of <a href="http://en.wikipedia.org/wiki/Logical_volume_management">logical volume management (LVM)</a> that makes installing rEFInd to the OS X root directory impossible, so the default location is changed to the ESP. Changes to the default for <tt>dont_scan_volumes</tt> are necessary to make the new location for the OS X boot loader show up. Another big change is in the new (but <i>experimental</i>) support for network booting, with the help of iPXE. See the <tt>BUILDING.txt</tt> file in the source package for details on how to build and install the necessary files. A new option for <tt>refind.conf</tt>, <tt>enable_and_lock_vmx</tt>, sets the VMX bit on Intel CPUs, which is necessary for booting some hypervisors, such as Hyper-V. This feature can be set on many computers' EFIs, but some, such as Macs, lack this ability. (<i>Do not</i> set this option on AMD CPUs or older Intel CPUs that lack this feature, though!) If rEFInd can't find its icons directory, it now drops back to text mode. A bug in <tt>dont_scan_files</tt> has been fixed, enabling you to specify a complete path to certain special-case boot loaders to omit them from scans. Finally, I've updated the icons for Fedora and Ubuntu and added an icon for Xubuntu.</li>
+
+<li><b>0.8.3 (7/6/2014)</b>&mdash;This version introduces a number of minor bug fixes and feature improvements. The most user-visible of these are that on Macs, rEFInd now displays a partition's label for BIOS-bootable OSes on filesystems that rEFInd can't read; and you can now pass <tt>timeout = -1</tt> in <tt>refind.conf</tt> to have rEFInd boot the default OS immediately <i>unless</i> there's a keypress when rEFInd loads, in which case that keypress is read as a shortcut key. A change that's less likely to be noticed is that the default setting for <tt>scan_all_linux_kernels</tt> is now <tt>true</tt>. Since this option had been uncommented in the sample configuration file, this change will not affect most people. I've fixed a bug that caused rEFInd to unload drivers as soon as they were loaded. This didn't affect rEFInd's drivers because they ignored the relevant EFI calls; but this was preventing some other drivers from working. I've added two new icons, one for Mythbuntu and the other for the Clover boot manager. Finally, I've removed Oracle's GPLv2 code from the core filesystem driver code, since it was incompatible with the GPLv3 used by the Btrfs driver. This change <i>shouldn't</i> affect the operation of the drivers, but there's a slim chance that it will.</li>
+
+<li><b>0.8.2 (6/8/2014)</b>&mdash;I've continued to refine the UEFI BIOS-mode boot code with this version; it now uses the BIOS-mode boot entries provided by the firmware by default, and actively scans for new entries only if the <tt>deep_uefi_legacy_scan</tt> token is present in <tt>refind.conf</tt>. This change is motivated by reports I've received of BIOS-mode boot entries multiplying on some systems; however, a deep scan is required to detect the second and subsequent disks on other computers. A second important change is that the default selection is now the last-booted item rather than the first item in the list. You can still set a fixed default via the <tt>default_selection</tt> token, and in fact if you provide a list that begins with <tt>+</tt>, the default will be the previously-booted item unless it can't be found, in which case the subsequent items in the list will be tried. Minor changes include the addition of an icon for Mageia Linux, a minor bug fix in GUID-parsing code, and an update of my personal build system from TianoCore UDK2010.SR1.UP1.P1 to UDK2014. This last item will affect anybody else who uses TianoCore to build rEFInd, since some default paths have changed, so you may need to update yourself or adjust the path in <tt>Make.tiano</tt>.</li>
+
+<li><b>0.8.1 (5/15/2014)</b>&mdash;The biggest code change in this version is that rEFInd's UEFI-style BIOS-mode boot code now works when rEFInd is built with GNU-EFI as well as when built with Tianocore. This change won't affect users of my binary builds, which have long been made with Tianocore, but if your distribution builds rEFInd with GNU-EFI, it might interest you. Some user-noticeable bug fixes include a fix to a bug that could cause rEFInd to omit boot loaders on a partition's root directory, a fix to a bug that caused <tt>.VolumeIcon.icns</tt> to take a higher-than-intended precedence on OS X boot volumes, a fix to a bug that could cause a BIOS-mode boot from the wrong device in UEFI mode, and improved centering of BIOS-mode boot descriptions on the screen. Other changes include two new optional bitmap fonts (Ubuntu Mono and Nimbus Mono), omission of messages about scanning of boot loaders when <tt>scan_delay</tt> is set to <tt>1</tt>, a change to the search order for icons (PNG files now override ICNS files), and a conversion of all the icons in the icons directory from ICNS to PNG format. Note that this last change may necessitate changing manual boot stanzas if you refer to icons in the default icon directory, depending on how you upgrade rEFInd.</li>
+
+<li><b>0.8.0 (5/4/2014)</b>&mdash;The biggest changes with this version relate to BIOS/CSM/legacy support, particularly on UEFI-based PCs. This version can now boot from the second (or later) hard disk on such computers, and is more likely to be able to cope with removable disks. On both Macs and PCs, you can also now use <tt>dont_scan_volumes</tt> to remove a legacy-boot option from the boot list, so long as it has a unique name (as shown in rEFInd's main menu when you highlight the option). This version also introduces the ability to use partition names and partition GUIDs to refer to devices (in <tt>dont_scan_volumes</tt>, displayed in the rEFInd menu, and so on). Note that partition names are stored in GPT data structures. These are different from filesystem names, which are stored in filesystem data structures. rEFInd now limits the length of the firmware identity string shown in the "About" screen, to prevent problems with the string overrunning the space available on an 800x600 display. Finally, I've fixed a memory-allocation bug that caused error message displays on some systems when re-scanning boot loaders. This bug might conceivably have caused some systems to hang when re-scanning, too.</li>
+
+<li><b>0.7.9 (4/20/2014)</b>&mdash;This version includes a number of bug fixes: <tt>install.sh</tt> no longer displays error messages if the <tt>dmraid</tt> utility isn't available; the HFS+ driver now reports a correct volume name; filesystem driver bugs that could cause lockups have been fixed; a redundant "utility" in the MOK utility's description has been removed; and an (as-yet untested) attempt to fix a continuous-rescanning problem after ejecting a disc on some computers has been implemented. In addition, rEFInd now removes redundant kernel entries on Ubuntu systems to keep the menu uncluttered and a new <tt>gdisk</tt> option has been added to the <tt>showtools</tt> item. (An EFI version of my <a href="http://www.rodsbooks.com/gdisk/"><tt>gdisk</tt></a> utility can be built with the help of the <a href="https://sourceforge.net/projects/uefigptfdisk/?source=directory">UEFI GPT fdisk</a> library.)</li>
+
+<li><b>0.7.8 (3/9/2014</b>&mdash;This version emphasizes changes to icon and banner graphics handling. Internally, rEFInd can now scale graphics, which previous versions could not do. To make use of this feature, three new <tt>refind.conf</tt> tokens now exist: <tt>big_icon_size</tt> and <tt>small_icon_size</tt> set the sizes of big (first-row OS) and small (second-row tool) icons; and <tt>banner_scale</tt> tells rEFInd to draw banners to a 1:1 scale (<tt>noscale</tt>, the default) or to scale the banner to fill the screen (<tt>fillscreen</tt>). See <a href="configfile.html#table1">Table 1 on the configuration page of this document</a> for more on these new options. I've also adjusted the post-installation script used by the RPM and Debian packages to search for existing Shim programs called <tt>shimx64.efi</tt>, not just <tt>shim.efi</tt> (as had been done before). This should help when installing a package on distributions that use the <tt>shimx64.efi</tt> filename, such as Ubuntu. Finally, I'm providing a preliminary set of Debian packaging files, which may help distribution maintainers to adopt rEFInd.</li>
+
+<li><b>0.7.7 (1/3/2014)</b>&mdash;A new configuration file token, <tt>windows_recovery_files</tt>, leads this list of changes; you can use it to specify files that boot Windows recovery tools. If you include the <tt>windows_recovery</tt> option on the <tt>showtools</tt> line, these files will then be represented by a small Windows recovery badge on the second row rather than as a full-sized OS loader, thus reducing clutter and making the purpose of this loader clearer. You can also now specify a complete path to <tt>dont_scan_files</tt> items, including a volume specifier. The <tt>use_graphics_for</tt>, <tt>also_scan_dirs</tt>, <tt>dont_scan_dirs</tt>, <tt>dont_scan_files</tt>, <tt>scan_driver_dirs</tt>, and <tt>windows_recovery_files</tt> tokens can all now accept <tt>+</tt> as their first option, which causes subsequent list items to be added to their defaults rather than replacing them. The configuration file can now be specified at program launch by passing a <tt>-c</tt> option, as in <tt>-c myconf.conf</tt>; you can use this feature to set up a manual boot stanza that launches rEFInd with modified boot options. Scans of ext2/3/4fs and ReiserFS partitions now omit partitions with filesystem UUIDs that have already been seen. This is an effort to reduce clutter from such partitions that are components of RAID 1 arrays. The <tt>install.sh</tt> script now attempts to locate and mount an unmounted ESP when run under Linux. Finally, I've fixed a bug in both <tt>install.sh</tt> and <tt>mkrlconf.sh</tt> that caused the generated <tt>refind_linux.conf</tt> file to contain a stray line break and unnecessary <tt>PARTUUID=</tt> specification on some systems.</li>
+
+<li><b>0.7.6 (12/15/2013)</b>&mdash;The biggest changes in this version relate to the <tt>default_selection</tt> setting. You can now provide multiple default selections by listing them <i>within quotes</i> and separated by commas, as in <tt>default_selection "ubuntu,fedora"</tt> which boots <tt>ubuntu</tt> if it's present and <tt>fedora</tt> if <tt>ubuntu</tt> is not present but <tt>fedora</tt> is. This should be helpful with removable disks. You can also include two times, in 24-hour format, following a <tt>default_selection</tt> specification, as in <tt>default_selection Maintenance 1:00 2:00</tt>, which boots <tt>Maintenance</tt> by default between 1:00 and 2:00. If another <tt>default_selection</tt> without a time specification preceded this line, the earlier one will still apply at other times. Another change to the main program is that you can now set <tt>screensaver -1</tt> to have rEFInd come up with its screen blanked. You'll probably want to combine this with a short <tt>timeout</tt> value to have rEFInd boot your default OS quickly unless you press a key first. Finally, I've added a new option to the <tt>install.sh</tt> script: <tt>--ownhfs <i>target_partition</i></tt>. This option is valid only under OS X. It installs rEFInd to an HFS+ volume that does <i><b>not</b></i> currently hold an OS X installation. The installation method differs from the usual rEFInd installation in that the result looks to the firmware more like an OS X installation. This makes rEFInd appear as an option in the firmware's own boot manager and it may help suspend-to-RAM operations.</li>
+
+<li><b>0.7.5 (11/10/2013)</b>&mdash;This version fixes a few bugs, the most important of which is one that caused some Macs to hang when multiple EFI drivers were present. Another squashed bug caused the screen to clear to the default gray rather than the actual background color when launching OSes in graphics mode. rEFInd no longer shows all exFAT partitions as being bootable on Macs when legacy boot options are enabled; now such partitions only show up as bootable if rEFInd spots a known boot loader installed on them. Finally, I've fixed a bug that caused <tt>install.sh</tt> to fail when installing to the ESP with recent versions of OS X.</li>
+
+<li><b>0.7.4 (8/25/2013)</b>&mdash;This version fixes problems in booting VMware's <tt>mboot64.efi</tt> boot loader and when launching boot loaders from some types of Mac drives. These fixes might improve matters for other boot loaders, too. I've also added a space to the end of the <tt>Boot <i>X</i> from <i>Y</i></tt> description, which means you can use <tt><i>Y</i></tt> in the <tt>default_selection</tt> field even if another entry contains the same <tt><i>Y</i></tt> string, but with something added. To do this, you must enclose <tt><i>Y</i></tt> in quotes and add a space to its end, as in <tt>default_selection "Bit "</tt>, which sets the first boot loader on the <tt>Bit</tt> volume as the default, even if you also have a disk called <tt>Bitten</tt>. Finally, this version adds explicit support for the new EFI version of <a href="http://www.memtest86.com/download.htm">Memtest86.</a> See the <a href="installing.html#addons">"Installing Additional Components"</a> section of the <a href="installing.html">Installing rEFInd</a> page for details on this support.</li>
+
+<li><b>0.7.3 (8/7/2013)</b>&mdash;This version fixes a bug that caused boot failures when launching BIOS-mode OSes on Macs. It also fixes a bug that caused such OSes' disk-type icons to disappear.</li>
+
+<li><b>0.7.2 (8/6/2013)</b>&mdash;This version primarily fixes a number of minor bugs: A display glitch when the second row of icons is empty; improper scanning when a volume specification was used in <tt>also_scan_dirs</tt>; improper reading of volume badges from user-specific icons directory or from <tt>.VolumeBadge.icns</tt> files. Also, This version adds protection against loading invalid files as drivers, which can crash some EFIs, adds an icon for Funtoo Linux, and adds <tt>PreLoader.efi</tt> and <tt>shim-fedora.efi</tt> to the default <tt>dont_scan_files</tt> list.</li>
+
+<li><b>0.7.1 (7/8/2013)</b>&mdash;The most important improvement to this version is a bug fix to the filesystem drivers. In version 0.7.0, drivers could hang the system (the Btrfs driver in particular generated problem reports, although the bug could theoretically affect any driver). Version 0.7.1 fixes this problem. I've also fixed a build problem with development versions of the TianoCore EDK2. In rEFInd proper, I've added a scan for <tt>EFI/Microsoft/Boot/bkpbootmgfw.efi</tt>, which is how recent versions of Ubuntu's Boot Repair utility rename the Windows boot loader. This change enables rEFInd to launch Windows even on systems that have been "repaired" by this overzealous tool. I've also fixed a bug that caused volume specifications in <tt>also_scan_dirs</tt> tokens to be ignored.</li>
+
+<li><b>0.7.0 (6/27/2013)</b>&mdash;Improvements to the filesystem drivers dominate this version. The biggest change is a new Btrfs driver, created by Samuel Liao and based in part on the GRUB 2.0 Btrfs support. The drivers also now include a read cache to improve their speed. This has only a tiny effect on most computers, but on some it can speed boot times by a few seconds, and under VirtualBox the effect is dramatic&mdash;the ext2fs driver goes from a sluggish three <i>minutes</i> to load a kernel and initrd to three <i>seconds</i>. I've also changed some critical filesystem driver pointers from 32-bit to 64-bit, which may enable some of them to work with larger filesystems, although this isn't yet tested. The main rEFInd binary sports only two changes: It can now identify Btrfs volumes as such for labelling purposes and it can now filter out invalid loaders (those for the wrong architecture or Linux kernels that lack EFI stub loader support, for instance).</li>
+
+<li><b>0.6.12 (6/18/2013)</b>&mdash;This version changes relatively little code, but it adds one feature that will simplify rEFInd installation for some users: The program can now deduce minimal Linux boot options based on an <tt>/etc/fstab</tt> file <i>if</i> that file is on the same partition as the kernel (in other words, if you do <i>not</i> use a separate <tt>/boot</tt> partition). Put another way, <tt>refind_linux.conf</tt> is no longer required for some installations, although it's still desirable. If you're already using rEFInd, this isn't likely to be important, but it can help when you're just starting out. In addition, this version adds support for the Linux Foundation's PreBootloader in the <tt>install.sh</tt> script. I've also changed the default 64-bit shell included on the CD-R and USB flash drive images to a modified version 2 shell, so as to enable use of the <tt>bcfg</tt> command to help install rEFInd (or make other changes to the firmware's boot manager configuration).</li>
+
+<li><b>0.6.11 (5/13/2013)</b>&mdash;Two new features may have a noticeable affect for many users: First, rEFInd now ignores symbolic links on filesystems that support them. I've implemented this change because I've been receiving too many reports from users who want to remove redundant or non-functional Linux boot entries caused by symbolic links created by distributions. Although this is possible by editing the <tt>dont_scan_dirs</tt> or <tt>dont_scan_files</tt> options in <tt>refind.conf</tt>, telling users how to do this has become tedious. If you <i>want</i> to use links to create multiple entries for one kernel or boot loader, use hard links instead of symbolic links. The second major user-visible change is that rEFInd now tries to guess the distribution type based on the naming of the kernel file (effective only for Fedora and RHEL) or the contents of the <tt>/etc/os-release</tt> file (effective only if the installation does <i>not</i> have a separate </tt>/boot</tt> partition or if <tt>/etc/os-release</tt> is copied to that location on the partition that holds the kernel). There are several other minor cosmetic issues that some users may notice, including icons for Lubuntu and Kubuntu and a change in the name of the "Reboot to Firmware User Interface" option to "Reboot to Computer Setup Utility." I've also fixed a bug in <tt>gptsync</tt> that could cause it to hang if the disk had too few GPT partitions. Finally, I've improved the <tt>install.sh</tt> script so that it works better from a path with directory names that include spaces.</li>
+
+<li><b>0.6.10 (5/5/2013)</b>&mdash;This version adds a number of minor improvements: The ability to create multiple screen shots under a sequence of names rather than using just one name; a new screen saver feature, activated by the <tt>screensaver</tt> token in <tt>refind.conf</tt>; and an option to reboot the computer into the firmware's setup utility on computers that support this feature. I've also added an OS for ChromeOS (<tt>os_chrome.icns</tt>), and I've updated the LodePNG library to the latest version, which might improve rendering of some PNG files.</li>
+
+<li><b>0.6.9 (4/25/2013)</b>&mdash;The most visible change to this version is to the rEFInd banner image, which now includes an icon provided by Erik Kemperman. The biggest change with this version is the inclusion of an updated version of <tt>gptsync</tt>, which is popular on Macs as a means of maintaining the <a href="http://www.rodsbooks.com/gdisk/hybrid.html">hybrid MBR</a> that's required to boot Windows in BIOS mode on that platform. Because hybrid MBRs are ugly and dangerous, though, the rEFInd <tt>install.sh</tt> script installs the program only under OS X, and even then it must be activated by uncommending the <tt>scanfor</tt> line in <tt>refind.conf</tt> and adding <tt>gptsync</tt> to its options list. If you want to use <tt>gptsync</tt> on a PC, you can, but you'll need to copy the program file manually to the ESP's <tt>EFI/tools</tt> directory. Other changes with this version include working around a suspected firmware bug that can cause hangs when rEFInd starts on some systems and changing the timeout code so that rEFInd will launch its default OS even if the computer is started without a keyboard.</li>
+
+<li><b>0.6.8 (3/18/2013)</b>&mdash;This version fixes a few obscure bugs but adds only one minor new feature. Most notably, it fixes a problem that caused "Invalid Parameter" errors to appear when scanning for boot loaders on some systems; fixes a bug that caused icons defined in files named after boot loaders to not appear; and fixes a bug in the <tt>install.sh</tt> script that caused the script to fail on some systems. It also enables you to name a shell <tt>shell.efi</tt> in the root directory (previously only <tt>shell_<i>arch</i>.efi</tt> worked in the root directory, although <tt>shell.efi</tt> worked in the <tt>EFI/tools</tt> directory).</li>
+
+<li><b>0.6.7 (2/3/2013)</b>&mdash;This version fixes a few bugs and adds some minor features relating to Secure Boot. Bug fixes include keeping rEFInd out of its own menu when it's launched as <tt>EFI/Microsoft/Boot/bootmgfw.efi</tt>; keeping the <tt>dont_scan_volumes</tt> option out of the <tt>also_scan_dirs</tt> list; a fix for <tt>dont_scan_volumes</tt> so that it applies to the OS X boot loader; and a fix for a bug that caused PNG files in a user-specified icons directory to be ignored if an ICNS file was available in the standard icons directory. New features include support for the Linux Foundation's <tt>HashTool.efi</tt> as a MOK utility, scanning for MOK utilities on all volumes, and a more verbose error message when a Secure Boot authentication failure occurs.</li>
+
+<li><b>0.6.6 (1/26/2013)</b>&mdash;This version includes two new features and a number of minor bug fixes. The first new feature is support for changing rEFInd's font via the <tt>font</tt> token in <tt>refind.conf</tt>. You're limited to monospace fonts that are encoded as PNG files; you can't use variable-width fonts or normal font files like TrueType fonts. The fonts support only ASCII characters. See the <a href="themes.html#fonts">fonts section on the Theming rEFInd page</a> for details. I've also changed the default font to a slightly larger one that's anti-aliased. The second new feature is that rEFInd now detects when the <tt>EFI/BOOT/bootx64.efi</tt> (or <tt>EFI/BOOT/bootia32.efi</tt> on 32-bit systems) boot loader is a duplicate of another boot loader, and automatically excludes it from the OS list. This is useful on systems that boot with Windows, since Windows tends to install its boot loader twice, once using the <tt>EFI/BOOT/bootx64.efi</tt> filename. Bug fixes are described in the <tt>NEWS.txt</tt> file, and include fixes for bugs that prevented manual boot stanzas in included configuration files from being detected; that caused an <tt>ASSERT</tt> error to appear on the screen on some systems if <tt>default_selection</tt> was not set; the caused <tt>Binary is whitelisted</tt> messages to persist on the screen when loading signed EFI drivers with Secure Boot active; that caused rEFInd to ignore <tt>icon</tt> tokens in <tt>refind.conf</tt> manual boot stanzas; and that caused the <tt>install.sh</tt> script to fail to update drivers when rEFInd was installed to <tt>EFI/BOOT</tt>.</li>
+
+<li><b>0.6.5 (1/16/2013)</b>&mdash;Most of this version's changes relate to icon, graphics, and theming features. The biggest code change is in support for PNG files for banners, icons, and selection backgrounds. I've also fixed bugs that prevented large banners from being used; you can now use banners as big as the screen (or bigger, but they'll be cropped), as illustrated on the <a href="themes.html">Theming rEFInd</a> page. The text color also now automatically switches between black and white depending on the background over which it's displayed. If you don't use these features, you're likely to notice some changes in where certain elements are displayed. Most obviously, the banner appears higher on the screen than it did previously, so as to minimize the chance of overlap with text displays such as the information screen. These text displays should appear correctly even on tiny 640x480 displays (they were blank on such small displays in the past). I've added icons for <a href="https://www.haiku-os.org/">Haiku</a> and <a href="http://www.altlinux.com/">ALT Linux.</a> Finally, the only non-graphics development is the addition of a "safe mode" boot option for OS X, which you can disable by adding <tt>safemode</tt> to the <tt>hideui</tt> option in <tt>refind.conf</tt>.</li>
+
+<li><b>0.6.4 (1/8/2013)</b>&mdash;Bug fixes motivate this release; it corrects a couple of memory management bugs in 0.6.3 that cause rEFInd to hang at startup on some computers (unfortunately not on any of mine, so I missed this). I've also made a small change to the <tt>install.sh</tt> script so that it installs the ext2fs driver rather than the ext4fs driver if the script detects that a Linux kernel is on an ext2fs or ext3fs partition. This can keep rEFInd from scanning ext4fs partitions and picking up non-functional symbolic links to vmlinuz on such partitions.</li>
+
+<li><b>0.6.3 (1/6/2013)</b>&mdash;The installation script and related tools see the biggest changes in this version of the program. The <tt>install.sh</tt> script can now detect a rEFInd installation in <tt>EFI/BOOT</tt> or <tt>EFI/Microsoft/Boot</tt> and update it rather than install to the default location of <tt>EFI/refind</tt>. It will also install to one of these fallback locations if it's run in BIOS mode, thus helping users who want to get a BIOS-mode install of Linux running on an EFI-based computer. A new <tt>mvrefind.sh</tt> script can move the installation between these three locations (or more exotic locations). Outside of scripts, the <tt>dont_scan_dirs</tt> and <tt>also_scan_dirs</tt> tokens can now accept volume specifications, as in <tt>myvol:EFI/bogus</tt> to not scan (or scan) the <tt>EFI/bogus</tt> directory on the <tt>myvol</tt> volume. I've also fixed a bug that caused rEFInd to ignore default boot loaders on removable disks if rEFInd was installed using the fallback filename. I've also modified the ISO-9660 driver so that it works with ISO-9660 images written to non-optical media. This may help with getting "hybrid ISO" images written to USB flash drives to boot.</li>
+
+<li><b>0.6.2 (12/30/2012)</b>&mdash;This version's biggest changes are "behind-the-scenes" improvements. Specifically, I've completely re-worked the shim/MOK Secure Boot code, based largely on an approach used by James Bottomley in his PreLoader boot loader. This fixes some bugs, such as the inability to launch more than one EFI boot loader in Secure Boot mode. The EFI filesystem drivers can now be built with GNU-EFI, which may help distribution maintainers. I'm also providing RPM packages of rEFInd, although I recommend installing from the binary zip file. Finally, I've changed rEFInd's default text-mode setting behavior to not adjust the text mode. (Recent previous versions forced the system to use text mode 0, which cuased problems on some systems.)</li>
+
+<li><b>0.6.1 (12/21/2012)</b>&mdash;(Mayan apocalypse edition!) This version features a number of refinements and minor bug fixes. The <tt>install.sh</tt> script now includes a new <tt>--root</tt> option to enable easier installation of rEFInd to a regular OS installation from an emergency disc. The ext4fs driver now supports the <tt>meta_bg</tt> filesystem feature. I've fixed a number of obscure display resolution-setting bugs and a bug that caused the screen to clear after displaying certain error messages but before prompting you to continue. Instead of displaying a blank filesystem label as the "from" location for a boot loader, rEFInd now describes the filesystem by its type (FAT, ext4fs, etc.) and/or size. rEFInd also now uses the filesystem label as a hint about what type of icon to display for a boot loader.</li>
+
+<li><b>0.6.0 (12/16/2012)</b>&mdash;The donation of a working ext4fs driver from Stefan Agner has prompted another big jump in the rEFInd version number, since this driver will greatly simplify installation on many systems: You may be able to simply run the <tt>install.sh</tt> script to get a working rEFInd that boots your Linux kernels directly, bypassing GRUB or ELILO. Other improvements in this version include bug fixes and minor changes to <tt>install.sh</tt>, the addition of hint text to the rEFInd main menu, the ability to disable the options editor via the <tt>editor</tt> option to <tt>hideui</tt> in <tt>refind.conf</tt>, a new <tt>textmode</tt> option to <tt>refind.conf</tt> to set the size of the text-mode display, a change to the code that adds your initial RAM disk to the boot options so that if you specify one manually (via <tt>refind_linux.conf</tt>), it will take precedence, and assorted obscure bug fixes. The <tt>NEWS.txt</tt> file goes into more details about many of these changes, as do the relevant pages of this HTML documentation.</li>
+
+<li><b>0.5.1.1 (12/12/2012)</b>&mdash;This is a micro-update to fix a bug in the <tt>install.sh</tt> script that prevented it from working under OS X. Aside from that, and a few small documentation changes, this version changes nothing in rEFInd.</li>
+
+<li><b>0.5.1 (12/11/2012)</b>&mdash;The most important changes to this version are to the <tt>install.sh</tt> script. It now supports two options, <tt>--shim</tt> and <tt>--localkeys</tt>, to aid in installation on a Secure Boot system. See the <a href="installing.html">Installing rEFInd</a> and <a href="secureboot.html">Managing Secure Boot</a> pages for details. The script also now creates a sample <tt>/boot/refind_linux.conf</tt> file to assist in setting up boots via the Linux EFI stub loader. All of these <tt>install.sh</tt> improvements work only in Linux. A separate <tt>mkrlconf.sh</tt> script creates a <tt>/boot/refind_linux.conf</tt> file if it doesn't exist, for help in post-installation configuration. In rEFInd itself, I've fixed the bug that caused ELILO to be unable to locate its configuration file when launched in Secure Boot mode and fixed a couple of more obscure bugs. I've also added an <tt>include</tt> token to <tt>refind.conf</tt>, to enable you to create a secondary configuration file (say, one managed by scripts while leaving the main file untouched; or one dedicated to manual boot stanzas).</li>
+
+<li><b>0.5.0 (12/6/2012)</b>&mdash;I've focused on adding support for Matthew J. Garrett's shim program to this version of rEFInd; with this support, rEFInd is capable of launching Linux kernels and other programs signed with a suitable key while the computer is in Secure Boot mode. This initial release, however, requires significant manual configuration and has some known bugs and limitations. See the <a href="secureboot.html">Managing Secure Boot</a> page for details. Beyond this major new feature, this version includes several more minor improvements. These include a change to the <tt>resolution</tt> token so that it applies to text mode as well as to graphics mode; a bug fix that caused the line editor to blank out lines that were left unedited; a new <tt>dont_scan_files</tt> option to blacklist boot programs by filename; support for launching MokManager and Apple's Recovery HD partitions via tools (2nd-row) icons; new <tt>--usedefault</tt> and <tt>--drivers</tt> options to the <tt>install.sh</tt> script; a change of the <tt>esp</tt> installation script option to <tt>--esp</tt>; and the ability to use quote marks inside option strings by doubling them up.</li>
+
+<li><b>0.4.7 (11/6/2012)</b>&mdash;The most important new feature in this version is a boot options editor. From rEFInd's main menu, press Insert or F2 to see the options menu. Select one of the options and press Insert or F2 again and the screen switches to a text-mode display in which you can edit the options that will be passed to the boot loader. A second new feature is a new icon for <a href="http://freedesktop.org/wiki/Software/gummiboot">gummiboot,</a> which is another EFI boot manager. This version also alters the behavior of the <tt>scan_delay</tt> option, since I've been told that the previous version didn't work; the new one does. Finally, this version omits the space that followed boot options when booting most OSes. This behavior was inherited from rEFIt; a comment in the source code indicates it's needed by OS X, but I've been told it causes boot failures when launching Linux on some Macs. Thus, rEFInd now adds this space only when booting Mac OS X.</li>
+
+<li><b>0.4.6 (10/6/2012)</b>&mdash;Thanks to contributor John Bressler, rEFInd can now boot legacy (BIOS) boot loaders on many UEFI PCs. (Previously, rEFInd could do this only on Macs.) Other changes include a new <tt>scan_delay</tt> option that inserts a delay between rEFInd starting and disk scans (to help detect disks that are slow to appear to the firmware) and a change in the default <tt>scanfor</tt> value so that legacy OSes are detected by default on Macs (but not on PCs). I've also fixed some memory management problems that caused error messages to appear on some systems when rEFInd was compiled with the TianoCore EDK2 toolkit. Finally, I'm now using the TianoCore toolkit to make my primary binary builds, since the new UEFI legacy boot support requires the TianoCore environment. (rEFInd still builds with GNU-EFI, but it doesn't support booting legacy OSes on UEFI systems when built in this way.)</li>
+
+<li><b>0.4.5 (8/12/2012)</b>&mdash;This version fixes a couple of Mac-related bugs. The most important is that version 0.4.3 and 0.4.4 couldn't boot BIOS-based (aka CSM or Boot Camp) OS installations; 0.4.5 restores this important feature. The second bug is in the <tt>install.sh</tt> script, which would often fail to detect rEFItBlesser, thus leaving it enabled and causing rEFInd to fail to start after the first reboot into OS X.</li>
+
+<li><b>0.4.4 (6/23/2012)</b>&mdash;This is a bug-fix release. Most importantly, it fixes a bug in the new <tt>use_graphics_for</tt> feature; in 0.4.3, the options were set incorrectly (they just happened to work as expected on my main test configuration). I've also fixed problems with volume names in the 32-bit versions of both the drivers and the TianoCore EDK2 build of rEFInd itself. Finally, I've tweaked the <tt>install.sh</tt> script to do a better job of identifying the computer's ESP under OS X.</li>
+
+<li><b>0.4.3 (6/21/2012)</b>&mdash;The major user-visible change to this version is the addition of the <tt>use_graphics_for</tt> option, which enables you to specify the OSes that rEFInd launches in graphics mode vs. text mode. This effect is tiny on most systems, but can be important on some, as noted on the <a href="configfile.html">"Configuring the Boot Manager"</a> page. There's also a change to the way graphics-mode boots are handled, to make for a slightly smoother visual transition. This version also fixes the incompatibility between the drivers and the firmware used by Macs (and probably other EFI 1.x systems). I've removed <tt>linux.conf</tt> as a valid alternative name for the <tt>refind_linux.conf</tt> file, so if you're still using the old name, now is the time to rename it! The biggest change is behind the scenes, though: I've added support for compiling rEFInd using the TianoCore EDK2, as well as the GNU-EFI toolkit that I've used up to this point. I have no intention of removing GNU-EFI support, but there's a chance that the TianoCore toolkit will help in implementing some future features or in debugging some problems. You can download either version from the <a href="http://www.rodsbooks.com/refind/getting.html">downloads page.</a></li>
+
+<li><b>0.4.2 (6/3/2012)</b>&mdash;I've added a new <tt>dont_scan_dirs</tt> option to the configuration file, enabling creation of a directory-scanning "blacklist." See the <a href="configfile.html">"Configuring the Boot Manager"</a> page for details. This version also makes a couple of changes to the <tt>install.sh</tt> script. The first is a reminder for Mac users to update <tt>refind.conf</tt> if they need to boot BIOS-based OSes. The second change makes the script a bit smarter about updating NVRAM settings when run from Linux; it now attempts to make itself the default boot loader if an entry for rEFInd already exists but isn't the default. I've made this change in response to problem reports from users; apparently some distributions' GRUB update scripts make GRUB the default boot loader under all circumstances, which causes rEFInd to be taken out of the picture after a GRUB update. The previous <tt>install.sh</tt> code wouldn't add rEFInd back to the "top spot" after this happened, but the new code should do the trick. (Although re-installing rEFInd is overkill in this case, it's something many users would logically try.)</li>
+
+<li><b>0.4.1 (5/25/2012)</b>&mdash;This version provides a number of small bug fixes and improvements: When re-scanning (initiated by pressing Esc in the main menu), a message that re-scanning is occurring appears on the screen; I've fixed a bug that could cause rEFInd to appear as an option in its own menu after running a shell program and re-scanning; the <tt>install.sh</tt> script now checks for, and optionally deletes, the rEFItBlesser program when run under OS X; and the HFS+ driver now returns a volume label of <tt>HFS+ volume</tt>, rather than nothing at all (unlike other drivers, the HFS+ driver can't yet return the volume's true label).</li>
+
+<li><b>0.4.0 (5/20/2012)</b>&mdash;I've bumped up this version number more than usual to reflect the addition of four filesystem drivers (for ext2fs, ReiserFS, HFS+, and ISO-9660) to the rEFInd package. These drivers originate with the original rEFIt, VirtualBox, and Clover boot loader projects. You can learn more on the <a href="drivers.html">drivers page.</a> To facilitate inclusion of drivers on the CD image, rEFInd also now supports reading drivers from architecture-specific subdirectories&mdash;<tt>drivers_x64</tt> and <tt>drivers_ia32</tt> for <i>x</i>86-64 and <i>x</i>86 systems, respectively. This version also adds the ability to eject removable media on some Macs (this won't work on UEFI-based PCs, unfortunately). Finally, this version fixes a problem that could cause GRUB 2 to be unable to read its configuration file in some settings when launched from rEFInd.</li>
+
+<li><b>0.3.5 (5/15/2012)</b>&mdash;This version's biggest new feature is the ability to re-scan for boot loaders after launching the program. This is done by pressing the Esc key, which causes rEFInd to re-read its configuration file, to tell the EFI to reconnect all disks, and to do a fresh scan of all disks for loaders. This is useful if you insert a removable disk after starting the computer, if rEFInd starts before a disk has fully settled, if you make a change to the configuration file, or if you manually load a driver. This version also fixes a minor bug that could cause the scroll-right arrow to be replaced with a left-pointing arrow under some circumstances; and I've removed the scan for a BIOS Boot Partition that I added in 0.3.2, since I'm told it isn't launching correctly. (BIOS-mode GRUB 2 can still be launched on Macs from its boot code in the MBR.)</li>
+
+<li><b>0.3.4 (5/9/2012)</b>&mdash;The biggest change to this version is the addition of the <tt>icons_dir</tt> configuration file token, which enables you to specify a directory that holds icons that override those in the default <tt>icons</tt> subdirectory. See the <a href="themes.html">Theming rEFInd</a> and <a href="configfile.html">Configuring the Boot Manager</a> pages for details. This version also reduces flicker when moving your selection around the screen and modifies the <tt>install.sh</tt> script so that it can be used directly after building rEFInd from source code. Related to this, building from source now creates a binary that includes an architecture code&mdash;<tt>refind_ia32.efi</tt> or <tt>refind_x64.efi</tt> rather than <tt>refind.efi</tt>.</li>
+
+<li><b>0.3.3 (5/6/2012)</b>&mdash;I've focused on user interface improvements for this release. The biggest improvement is in the text-mode interface, which suffered from assorted display glitches in previous releases. These have now been fixed, so the text-mode interface should be more usable. I've also fine-tuned the use of keyboard keys, particularly in graphical mode. The up and down arrow keys now move between the two rows of the display, and Page Up and Page Down scroll the first row if it's too big for the display. (They'll also move between rows, but only when at the end of the first row or the start of the second.) Returning from a failed loader or a tool or built-in function now renders that tag as the currently-selected item, rather than setting the default loader as active, as happened with previous versions.</li>
+
+<li><b>0.3.2 (5/4/2012)</b>&mdash;rEFInd's core functionality changes very little with this version; I've tweaked the detection of BIOS-mode boot loaders to keep unbootable FAT partitions created under Linux and Windows out of the boot list, while adding detection of GRUB BIOS Boot Partitions to the list. I've also made a change that improves screen-clearing when launching EFI utilities and OSes in text mode. The major change to this version is the addition of a new Linux/OS X installation script, <tt>install.sh</tt>. In most cases, this makes it possible to install rEFInd simply by typing <tt class="userinput">./install.sh</tt> from the rEFInd package directory; however, you should see the <a href="installing.html">Installing rEFInd</a> page for details. In some cases, manual installation may still be required. Also, you may prefer to copy over the old rEFInd program file with the new one when upgrading.</li>
+
+<li><b>0.3.1 (4/27/2012)</b>&mdash;You'll find a few minor enhancements and bug fixes in this version, none of which affect the configuration files. rEFInd now sorts its boot loader entries <i>within each directory</i> by date, with the newest items first. The intent is that you can specify a directory name as the <tt>default_selection</tt> and the most recent boot loader in that directory will become the default. This may obviate the need to adjust the default after adding a new Linux kernel with EFI stub loader support. I've also improved the handling of <tt>.icns</tt> files for Linux kernels that lack <tt>.efi</tt> extensions; loader-specific icons for these kernels should now take the name of the kernel plus <tt>.icns</tt>&mdash;for instance, <tt>vmlinuz-0.3.2.icns</tt> for <tt>vmlinuz-0.3.2</tt>. rEFInd also now hides all <tt>.icns</tt> files from the boot loader list. Finally, this version fixes a bug, introduced in version 0.3.0, that could cause spurious <tt>Unsupported while scanning the root directory</tt> errors under some conditions on Macs.</li>
+
+<li><b>0.3.0 (4/22/2012)</b>&mdash;This version marks the official transition from alpha to beta status for rEFInd. This isn't because of any important objective milestone being passed; it's just that rEFInd has been used by many people who have reported no show-stopping bugs, so I'm now confident that rEFInd is stable enough for general use. That's not to say it's perfect; it still has numerous <a href="todo.html">known bugs and limitations.</a> That's why it's still beta. To get down to specifics, this version adds two new configuration file tokens: <tt>resolution</tt>, which sets the screen resolution; and <tt>scan_all_linux_kernels</tt>, which adds Linux kernel files to the boot loader list even if they lack <tt>.efi</tt> filename extensions. See the <a href="configfile.html">Configuring the Boot Manager</a> page for details on these new options. I've also fixed some bugs: One that sometimes caused Macs to crash when returning from the EFI shell or other programs; another that caused rEFInd to fail to scan filesystems if the filesystem driver didn't return a volume name; and a third that caused rEFInd to fail to detect boot loaders depending on the case of the filename on some EFIs (this is really a workaround for an EFI implementation bug). The first of these is a <i>very</i> tentative fix and it could have negative effects on some systems (non-Mac EFI 1.x systems or Macs that weren't affected by the bug in other recent releases), so be sure to <a href="mailto:rodsmith@rodsbooks.com">contact me</a> if rEFInd crashes or otherwise misbehaves after you use an EFI shell.</li>
+
+<li><b>0.2.7 (4/19/2012)</b>&mdash;I've added two new tokens to the <tt>refind.conf</tt> file, with associated new functionality. The new <tt>scan_driver_dirs</tt> option tells rEFInd where to scan for EFI drivers, in addition to the default of the <tt>drivers</tt> subdirectory of the rEFInd installation directory. For more on EFI drivers, see <a href="drivers.html">Using EFI Drivers.</a> Note that previous versions of rEFInd couldn't load drivers at all, although they could make use of hardware and filesystems activated by drivers loaded before rEFInd launched. The second new token is <tt>also_scan_dirs</tt>, which adds arbitrary directories to the list that rEFInd scans for boot loaders. (Without this option, rEFInd scans each volume's boot directory and every subdirectory of the <tt>/EFI</tt> directory, with the exception of <tt>/EFI/tools</tt> and rEFInd's own directory.) This version also fixes a minor bug that caused rEFInd to sometimes include itself in the list of OS options. Finally, if you build rEFInd yourself, you should be aware that it now requires a newer version of the GNU-EFI library than it required in the past. See the <tt>BUILDING.txt</tt> file, included in the source code package, for details.</li>
+
+<li><b>0.2.6 (4/14/2012)</b>&mdash;This version provides one bug fix and one new feature. The bug was introduced in version 0.2.5 and prevents rEFInd from identifying a Linux initial RAM disk file on some (but not all) EFI implementations. The new feature is the <tt>volume</tt> stanza token, which enables you to manually load a boot program from a filesystem other than the one from which rEFInd launched. You can specify a volume either by its label (as in <tt>volume KERNELS</tt> to load from the volume with a filesystem name <tt>KERNELS</tt>) or by number followed by a colon (as in <tt>volume 0:</tt> for the first filesystem or <tt>volume 1:</tt> for the second). See the <a href="configfile.html">Configuring the Boot Manager</a> page for more on this new feature.</li>
+
+<li><b>0.2.5 (4/9/2012)</b>&mdash;Icon-handling improvements are key in this version. I've fixed a bug that caused icons to be replaced with ugly "not-found" default icons when rEFInd was launched in certain ways. I've also added support for <tt>.VolumeIcon.icns</tt> and <tt>.VolumeBadge.icns</tt> files to set loader tags and disk-type badges, respectively. (See the <a href="configfile.html">configuration page</a> for details.) I've also fixed a bug that prevented rEFInd from finding the correct initial RAM disk for Linux kernels stored in the root directory of a partition.</li>
+
+<li><b>0.2.4 (4/5/2012)</b>&mdash;This version adds support for a new location for EFI shells (<tt>shell<tt class="variable">arch</tt>.efi</tt> in the ESP's root directory. It also adds two new <tt>refind.conf</tt> options: <tt>showtools</tt> and <tt>max_tags</tt>, and removes another one (<tt>disable</tt>). The options available in <tt>hideui</tt> are now essentially a combination of what <tt>disable</tt> and <tt>hideui</tt> did, minus functionality now present in <tt>showtools</tt>. I made these changes to reduce redundancy and to increase flexibility. See the <a href="configfile.html">Configuring the Boot Manager</a> page for details.</li>
+
+<li><b>0.2.3 (3/26/2012)</b>&mdash;I've changed the Linux kernel configuration filename from <tt>linux.conf</tt> to <tt>refind_linux.conf</tt> with this version, to avoid a name collision with a planned future Linux kernel ability to read its options from a file called <tt>linux.conf</tt>. This version also includes a tentative bug fix for a problem that caused rEFInd to hang upon launching the second program (say, a boot loader after using a shell) on some systems; but on some computers, this fix causes an (apparently harmless) error message about "(re)opening our installation volume" upon returning from the first program. I've also added a logo for Arch Linux.</li>
+
+<li><b>0.2.2 (3/23/2012)</b>&mdash;This version fixes three bugs: One caused submenus to not appear on systems with screens of 800x600 or smaller; another caused rEFInd to hang when boot loader names were too long; and the third caused the program to fail when Linux kernels and their initial RAM disk files lacked version numbers.</li>
+
+<li><b>0.2.1 (3/19/2012)</b>&mdash;This version adds the ability to auto-scan Linux kernels with EFI stub loader support, provided a suitable <tt>linux.conf</tt> file exists in the kernel's directory. It also adds support for manual specification of submenus in <tt>refind.conf</tt>.</li>
+
+<li><b>0.2.0 (3/14/2012)</b>&mdash;This is the program's initial public release. It's based on rEFIt 0.14 plus a large number of patches taken from Debian's Linux-compilable rEFIt package. I then added UEFI-specific fixes, support for OS definition stanzas in the configuration file, a scrolling icon list on the main menu, and other minor improvements. This release has quite a few <a href="todo.html">known bugs and limitations.</a></li>
+
+</ul>
+
+<hr />
+
+<p>copyright &copy; 2012&ndash;2015 by Roderick W. Smith</p>
+
+<p>This document is licensed under the terms of the <a href="FDL-1.3.txt">GNU Free Documentation License (FDL), version 1.3.</a></p>
+
+<p>If you have problems with or comments about this Web page, please e-mail me at <a href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.com.</a> Thanks.</p>
+
+<p><a href="index.html">Go to the main rEFInd page</a></p>
+
+<p><a href="todo.html">Learn about problems with and the future of rEFInd</a></p>
+
+  <p><a href="http://www.rodsbooks.com/">Return</a> to my main Web page.</p>
+</body>
+</html>
diff --git a/docs/refind/secureboot.html b/docs/refind/secureboot.html
new file mode 100644 (file)
index 0000000..ef8b7c0
--- /dev/null
@@ -0,0 +1,547 @@
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>The rEFInd Boot Manager: Managing Secure Boot</title>
+  <link href="../Styles/styles.css" rel="stylesheet" type="text/css" />
+</head>
+
+<meta name="viewport" content="width=device-width, initial-scale=1">
+
+<body>
+  <h1>The rEFInd Boot Manager:<br />Managing Secure Boot</h1>
+
+  <p class="subhead">by Roderick W. Smith, <a
+href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.com</a></p>
+
+<p>Originally written: 11/13/2012; last Web page update:
+11/8/2015, referencing rEFInd 0.10.0</p>
+
+
+<p>This Web page is provided free of charge and with no annoying outside ads; however, I did take time to prepare it, and Web hosting does cost money. If you find this Web page useful, please consider making a small donation to help keep this site up and running. Thanks!</p>
+
+<table border="1">
+<tr>
+<td>Donate $1.00</td>
+<td>Donate $2.50</td>
+<td>Donate $5.00</td>
+<td>Donate $10.00</td>
+<td>Donate $20.00</td>
+<td>Donate another value</td>
+</tr>
+<tr>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="1.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="2.50">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="5.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="10.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="20.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td></tr>
+</table>
+
+<hr />
+
+<p>This page is part of the documentation for the rEFInd boot manager. If a Web search has brought you here, you may want to start at the <a href="index.html">main page.</a></p>
+
+<hr />
+
+<p class="sidebar"><b>Note:</b> My <a href="http://www.rodsbooks.com/efi-bootloaders/">Managing EFI Boot Loaders for Linux</a> Web page includes a much more detailed description of Secure Boot in two of its subpages. Consult <a href="http://www.rodsbooks.com/efi-bootloaders/secureboot.html">Dealing with Secure Boot</a> for more information on disabling Secure Boot, using Shim, and using PreLoader; and read <a href="http://www.rodsbooks.com/efi-bootloaders/controlling-sb.html">Controlling Secure Boot</a> for more information on using your own keys instead of or in addition to those that came with your computer.</p>
+
+<div class="navbar">
+
+<h4 class="tight">Contents</h4>
+
+<ul>
+
+<li class="tight"><a href="#basic">Basic Issues</li>
+
+<li class="tight"><a href="#shim">Using rEFInd with Shim</a></li>
+    <ul>
+    <li class="tight"><a href="#installation">Installing Shim and rEFInd</a></li>
+    <li class="tight"><a href="#mok">Managing Your MOKs</a></li>
+    </ul>
+
+<li class="tight"><a href="#preloader">Using rEFInd with PreLoader</a></li>
+
+<li class="tight"><a href="#caveats">Secure Boot Caveats</a></li>
+
+</ul>
+
+</div>
+
+<p class="sidebar"><b>Note:</b> Macs don't (yet?) support Secure Boot, but
+as of version 10.11 ("El Capitan"), OS X uses its own new security feature,
+<i>System Integrity Protection (SIP),</i> which creates its own set of
+hoops through which rEFInd users must jump. See the <a
+href="sip.html">rEFInd and System Integrity Protection</a> page for
+details.</p>
+
+<p>If you're using a computer that supports Secure Boot, you may run into extra complications. This feature is intended to make it difficult for malware to insert itself early into the computer's boot process. Unfortunately, it also complicates multi-boot configurations such as those that rEFInd is intended to manage. This page describes some <a href="#basic">Secure Boot basics</a> and two specific ways of using rEFInd with Secure Boot: <a href="#shim">Using the Shim program</a> and <a href="#preloader">using the PreLoader program.</a> (My separate <a href="http://www.rodsbooks.com/efi-bootloaders/secureboot.html">EFI Boot Loaders for Linux page on Secure Boot</a> covers the additional topics of disabling Secure Boot and adding keys to the firmware's own set of keys.) This page concludes with a look at <a href="#caveats">known bugs and limitations</a> in rEFInd's Secure Boot features.</p>
+
+<a name="basic">
+<h2>Basic Issues</h2>
+</a>
+
+<p class="sidebar"><b>Note:</b> You don't <i>have to</i> use Secure Boot.
+If you don't want it, you can <a
+href="http://www.rodsbooks.com/efi-bootloaders/secureboot.html#disable">disable
+it,</a> at least on <i>x</i>86-64 PCs. If an ARM-based computer ships with
+Windows 8, this isn't an option for it. Unfortunately, the Shim and PreLoader programs described on this page currently support only <i>x</i>86-64, not <i>x</i>86 or ARM.</p>
+
+<p>Through 2012, it became obvious that Secure Boot would be a feature that was controlled, to a large extent, by Microsoft. This is because Microsoft requires that non-server computers that display Windows 8 logos ship with Secure Boot enabled. As a practical matter, this also means that such computers ship with Microsoft's keys in their firmware. In the absence of an industry-standard body to manage the signing of Secure Boot keys, this means that Microsoft's key is the only one that's more-or-less guaranteed to be installed on the computer, thus blocking the ability to boot any OS that lacks a boot path through Microsoft's signing key.</p>
+
+<p>Fortunately, Microsoft will sign third-party binaries with their key&mdash;or more precisely, with a key that Microsoft uses to sign third-party binaries. (Microsoft uses another key to sign its own binaries, and some devices, such as the Microsoft Surface tablet, lack the third-party Microsoft key.) A payment of $99 to Verisign enables a software distributor to sign as many binaries as desired. Red Hat (Fedora), Novell (SUSE), and Canonical (Ubuntu) are all using this system to enable their boot loaders to run. Unfortunately, using a third-party signing service is an awkward solution for open source software. In fact, for this very reason two separate programs exist that shift the Secure Boot "train" from Microsoft's proprietary "track" to one that's more friendly to open source authors. Both of these programs (Shim and PreLoader) are available in binary form signed by Microsoft's key. Shim enables the computer to launch binaries that are signed by a key that's built into it or that the user adds to a list known as the Machine Owner Key (MOK) list. PreLoader enables the computer to launch binaries that the user has explicitly identified as being OK. Distributions beginning with Ubuntu 12.10 (and 12.04.2), Fedora 18, and OpenSUSE 12.3 use Shim, although the Ubuntu initially shipped with an early version of Shim that's useless for launching rEFInd. (Current versions of Ubuntu ship with more flexible versions of Shim.) PreLoader is used by some smaller and more specialized distributions, such as Arch Linux. You can switch from one to the other if you like, no matter what your distribution uses by default.</p>
+
+<p>There are three ways to sign a binary that will get it launched on a computer that uses Shim:</p>
+
+<ul>
+
+<li><b>Secure Boot keys</b>&mdash;These keys are managed by the EFI
+    firmware. In a default configuration, Microsoft is the only party
+    that's more-or-less guaranteed to be able to sign boot loaders with
+    these keys; however, it's possible to <a
+    href="http://www.rodsbooks.com/efi-bootloaders/secureboot.html#add_keys">replace
+    Microsoft's keys with your own,</a> in order to take full control of
+    Secure Boot on your computer. The trouble is that this process is
+    tedious and varies in details from one computer to another. It's worth
+    noting that many, but not all, computers ship with Canonical's key,
+    which can help slightly when booting Ubuntu; if your computer is so
+    equipped, you can use any Shim you like and not worry about adding
+    Canonical's key to your MOK list, although you must still add a MOK key
+    for rEFInd itself.</li>
+
+<li><b>Shim's built-in keys</b>&mdash;It's possible, but not necessary, to
+    compile Shim with a built-in public key. Its private counterpart can
+    then be used to sign binaries. In practice, this key type is limited in
+    utility; it's likely to be used by distribution maintainers to sign
+    their own version of GRUB and the Linux kernels that it launches,
+    nothing more. On the plus side, Shim's keys require little or no
+    maintenance by users. One potential complication is that if you swap
+    out one Shim binary for another, its built-in key may change, which
+    means that the replacement Shim might no longer launch its follow-on
+    boot loader or kernels linked to the first Shim.</li>
+
+<li><b>MOKs</b>&mdash;Versions 0.2 and later of Shim support MOKs, which
+    give you the ability to add your own keys to the computer. If you want
+    to install multiple Linux distributions in Secure Boot mode, MOKs are
+    likely to be helpful. They're vital if you want to launch kernels you
+    compile yourself or use boot managers or boot loaders other than those
+    provided by your distribution.</li>
+
+</ul>
+
+<p>All three key types are the same in form&mdash;Shim's built-in keys and MOKs are both generated using the same tools used to generate Secure Boot keys. The keys can be generated with the common <tt>openssl</tt> program, but signing EFI binaries requires either of two rarer programs: <tt>sbsign</tt> or <tt>pesign</tt>. If you use Shim with a distribution that doesn't support Secure Boot, you'll need to either sign the kernels yourself, which can be a hassle, or launch the kernels by way of a boot loader that doesn't check for signatures, such as ELILO.</p>
+
+<p class="sidebar">Shim's author is working on merging it and PreLoader. Thus, future versions of Shim may provide the advantages of both programs.</p>
+
+<p>PreLoader is easier to set up on a distribution that doesn't support Shim because PreLoader doesn't rely on keys; instead, you tell it which binaries you trust and it will let you launch them. This works well on a system with boot managers, boot loaders, and kernels that seldom change. It's not a good solution for distribution maintainers, though, because it requires that users manually add binaries to PreLoader's list of approved binaries when the OS is installed and every time those binaries change. Also, PreLoader relies on a helper program, HashTool, to enroll hashes. (This is Geek for "tell the computer that a binary is OK.") Unfortunately, the initial (and, as far as I know, only signed) HashTool can enroll hashes only from the partition from which it was launched, so if you want to use rEFInd to launch Linux kernels directly, it's easiest if you mount your EFI System Partition (ESP) at <tt>/boot</tt> in Linux or copy your kernels to the ESP. Another approach is to copy <tt>HashTool.efi</tt> to the partition that holds your kernel and rename it to almost anything else. rEFInd will then treat it like an OS boot loader and create a menu entry for it, enabling you to launch it as needed.</p>
+
+<p>Beginning with version 0.5.0, rEFInd can communicate with the Shim system to authenticate boot loaders. If a boot loader has been signed by a valid UEFI Secure Boot key, a valid Shim key, or a valid MOK, rEFInd will launch it. rEFInd will also launch unsigned boot loaders or those with invalid signatures <i>if</i> Secure Boot is disabled in or unsupported by the firmware. (If that's your situation, you needn't bother reading this page.) PreLoader is designed in such a way that it requires no explicit support in rEFInd to work.</p>
+
+<p>My binary builds of rEFInd version 0.5.0 and later ship signed with my own keys, and I provide the public version of this key with the rEFInd package. This can help simplify setup, since you needn't generate your own keys to get rEFInd working. The rEFInd PPA for Ubuntu ships unsigned binaries, but the installation script that runs automatically when the package is installed signs the binaries with a local key as it installs them. In either case, if you lack public keys for the boot loaders that rEFInd launches, you'll need to sign your boot loaders, as described in the <a href="#mok">Managing Your MOKs</a> section.</p>
+
+<a name="shim">
+<h2>Using rEFInd with Shim</h2>
+</a>
+
+<p>Because several major distributions support Shim, I describe it first. You may need to adjust the rEFInd installation process to get it working with Shim, especially if you're not using a distribution that uses this software. In addition to installing Shim, you should know how to manage your MOKs, so I describe this topic, too. If you don't want to use Shim, you can skip ahead to <a href="#preloader">the section on PreLoader.</a></p>
+
+<a name="installation">
+<h3>Installing Shim and rEFInd</h3>
+</a>
+
+<p class="sidebar"><b>Note:</b> rEFInd's <tt>refind-install</tt> script attempts to identify whether your computer was booted with Secure Boot active and, if it was, to locate existing Shim binaries and make use of whatever it finds. Thus, you may not need to explicitly set up Shim after you install rEFInd, although you will probably have to enroll rEFInd's key in your MOK list, as described shortly.</p>
+
+<p>A working Secure Boot installation of rEFInd involves at least three programs, and probably four or more, each of which must be installed in a specific way:</p>
+
+<ul>
+
+<li><b>Shim</b>&mdash;You can use any version of Shim you like. In many cases, one will already be installed on your computer from your distribution, called <tt>shim.efi</tt> or <tt>shimx64.efi</tt> in the distribution's directory on the ESP. If so, it's probably best to use that version, since its built-in key will handle your distribution's kernels. If you don't currently have a Shim installed, you can copy one from another computer, copy the file from a distribution installation disc, or download a version of Shim 0.2 (old, but still usable) signed with Microsoft's Secure Boot key <a href="http://www.codon.org.uk/~mjg59/shim-signed/">here.</a> This version (created by Shim's developer, former Red Hat employee Matthew J. Garrett) includes a Shim key that's used by nothing but the <tt>MokManager.efi</tt> program that also ships with the program. No matter what version of Shim you use, you must enroll rEFInd's MOK. Ubuntu 12.10 and 13.04 ship with an earlier version of Shim (0.1) that doesn't support MOKs; avoid Shim 0.1 for use with rEFInd. You should install Shim just as you would install other EFI boot loaders, as described <a href="http://www.rodsbooks.com/efi-bootloaders/installation.html">here.</a> For use in launching rEFInd, it makes sense to install <tt>shim.efi</tt> in <tt>EFI/refind</tt> on your ESP, although of course this detail is up to you.</li>
+
+<li><b>MokManager</b>&mdash;This program is included with Shim 0.2 and later. It presents a user interface for managing MOKs, and it's launched by Shim if Shim can't find its default boot loader (generally <tt>grubx64.efi</tt>) or if that program isn't properly signed. In principle, this program could be signed with a Secure Boot key or a MOK, but such binaries are usually signed by Shim keys. This program should reside in the same directory as <tt>shim.efi</tt>, under the name <tt>MokManager.efi</tt>. Although you could theoretically do without MokManager, in practice you'll need it at least temporarily to install the MOK with which rEFInd is signed.</li>
+
+<li><b>rEFInd</b>&mdash;Naturally, you need rEFInd. Because Shim is hard-coded to launch a program called <tt>grubx64.efi</tt>, you must install rEFInd using that name and to the same directory in which <tt>shim.efi</tt> resides. In theory, rEFInd could be signed with a Secure Boot key, a Shim key, or a MOK; however, because Microsoft won't sign binaries distributed under the GPLv3, I can't distribute a version of rEFInd signed with Microsoft's Secure Boot key; and as I don't have access to the private Shim keys used by any distribution, I can't distribute a rEFInd binary signed by them. (If distributions begin including rEFInd in their package sets, though, such distribution-provided binaries could be signed with the distributions' Shim keys.) Thus, rEFInd will normally be signed by a MOK. Beginning with version 0.5.0, rEFInd binaries that I provide are signed by me. Beginning with version 0.5.1, the installation script provides an option to sign the rEFInd binary with your own key, provided the necessary support software is installed.</li>
+
+<li><b>Your boot loaders and kernels</b>&mdash;Your OS boot loaders, and perhaps your Linux kernels, must be signed. They can be signed with any of the three key types. Indeed, your system may have a mix of all three types&mdash;a Windows 8 boot loader will most likely be signed with Microsoft's Secure Boot key, GRUB and kernels provided by most distributions will be signed with their own Shim keys, and if you use your own locally-compiled kernel or a boot loader from an unusual source you may need to sign it with a MOK. Aside from signing, these files can be installed in exactly the same way as if your computer were not using Secure Boot.</li>
+
+</ul>
+
+<p>If you've installed a distribution that provides Shim and can boot it with Secure Boot active, and if you then install rEFInd using the RPM file that I provide or by running <tt>refind-install</tt>, chances are you'll end up with a working rEFInd that will start up the first time, with one caveat: You'll have to use MokManager to add rEFInd's MOK to your MOK list, as described shortly. If you don't already have a working copy of Shim on your ESP, your task is more complex. Broadly speaking, the procedure should be something like this:</p>
+
+<ol>
+
+<li>Boot the computer. This can be a challenge in and of itself. You may
+    need to use a Secure Boot&ndash;enabled Linux emergency disc,
+    temporarily disable Secure Boot, or do the work from Windows.</li>
+
+<li><a href="getting.html">Download rEFInd</a> in binary form (the binary
+    zip or CD-R image file). If you download the binary zip file, unzip it;
+    if you get the CD-R image file, burn it to a CD-R and mount it.</li>
+
+<li>Download Shim from <a
+    href="http://www.codon.org.uk/~mjg59/shim-signed/">Matthew J. Garrett's
+    download site</a> or from your distribution. (Don't use an early 0.1
+    version, though; as noted earlier, it's inadequate for use with
+    rEFInd.)</li>
+
+<p class="sidebar"><b>Tip:</b> If you're running Linux, you can save some effort by using the <tt>refind-install</tt> script with its <tt>--shim <tt class="variable">/path/to/shim.efi</tt></tt> option rather than installing manually, as in steps 4&ndash;6 of this procedure. If you've installed <tt>openssl</tt> and <tt>sbsign</tt>, using <tt>--localkeys</tt> will generate local signing keys and re-sign the rEFInd binaries with your own key, too. You can then use <tt>sbsign</tt> and the keys in <tt>/etc/refind.d/keys</tt> to sign your kernels or boot loaders.</p>
+
+<li>Copy the <tt>shim.efi</tt> and <tt>MokManager.efi</tt> binaries to the
+    directory you intend to use for rEFInd&mdash;for instance,
+    <tt>EFI/refind</tt> on the ESP.</li>
+
+<li>Follow the installation instructions for rEFInd on the <a
+    href="installing.html">Installing rEFInd</a> page; however, you should
+    normally give rEFInd the filename <tt>grubx64.efi</tt> and register
+    <tt>shim.efi</tt> with the EFI by using <tt>efibootmgr</tt> in Linux or
+    <tt>bcdedit</tt> in Windows. Be sure that rEFInd (as
+    <tt>grubx64.efi</tt>), <tt>shim.efi</tt>, and <tt>MokManager.efi</tt>
+    all reside in the same directory. If you're using Shim 0.7 or later and
+    installing it under Linux, you may optionally keep rEFInd's
+    <tt>refind_x64.efi</tt> name; but you must then tell Shim to use rEFInd
+    by passing an additional <tt>-u "shim.efi refind_x64.efi"</tt> option
+    to <tt>efibootmgr</tt>. Change the filenames to the actual filenames
+    used by Shim and rEFInd, respectively.</li>
+
+<li>Copy the <tt>refind.cer</tt> file from the rEFInd package to your ESP,
+    ideally to a location with few other files. (The rEFInd installation
+    directory should work fine.)</li>
+
+<li>Reboot. With any luck, you'll see a simple text-mode user interface
+    with a label of <tt>Shim UEFI key management</tt>. This is the
+    MokManager program, which Shim launched when rEFInd failed verification
+    because its key is not yet enrolled.</li>
+
+<li>Press your down arrow key and press Enter to select <tt>Enroll key from
+    disk</tt>. The screen will clear and prompt you to select a key, as
+    shown here:
+
+    <br /><img src="MokManager1.png" align="CENTER" width="676"
+    height="186" alt="MokManager's user interface is crude but effective."
+    border=2> <br />
+
+    This user interface was used in early versions of MokManager, but
+    somewhere between versions 0.4 and 0.7, the user interface received an
+    upgrade. If you've got a more recent version, it will look more like
+    this:
+
+    <br /><img src="MokManager2.png" align="CENTER" width="800"
+    height="345" alt="Recent versions of MokManager provide a somewhat more
+    user-friendly user interface." border=2> <br /> </li>
+
+<li>Each of the lines with a long awkward string represents a disk
+    partition. Select one and you'll see a list of files. Continue
+    selecting subdirectories until you find the <tt>refind.cer</tt> file
+    you copied to the ESP earlier. (Note that in the early user interface
+    the long lines can wrap and hide valid entries on the next line, so you
+    may need to select a disk whose entry is masked by another one!)</li>
+
+<li>Select <tt>refind.cer</tt>. You can type <tt class="userinput">1</tt>
+    to view the certificate's details if you like, or skip that and type
+    <tt class="userinput">0</tt> to enroll the key.</li>
+
+<li>Back out of any directories you entered and return to the MokManager
+    main menu.</li>
+
+<li>Select <tt>Continue boot</tt> at the main menu.</li>
+
+</ol>
+
+<p>At this point the computer may boot into its default OS, reboot, or perhaps even hang. When you reboot it, though, rEFInd should start up in Secure Boot mode. (You can verify this by selecting the <i>About rEFInd</i> tool in the main menu. Check the <i>Platform</i> item in the resulting screen; it should verify that Secure Boot is active.) You should now be able to launch any boot loader signed with a key recognized by the firmware or by Shim (including any MOKs you've enrolled). If you want to manage keys in the future, rEFInd displays a new icon in the second (tools) row you can use to launch MokManager. (This icon appears by default if MokManager is installed, but if you edit <tt>showtools</tt> in <tt>refind.conf</tt>, you must be sure to include <tt>mok_tool</tt> as an option in order to gain access to it.)</p>
+
+<p>If you're using rEFInd to boot multiple Linux versions, chances are you'll need to add the keys for the distributions whose Shim you're not using as MOKs. rEFInd ships with a selection of such keys and copies them to the <tt>keys</tt> subdirectory of the rEFInd installation directory on the ESP as a convenience. Note that you must enroll keys with <tt>.cer</tt> or <tt>.der</tt> filename extensions. Although <tt>.crt</tt> files contain the same information, their format is different and they cannot be used by MokManager.</p>
+
+<a name="mok">
+<h3>Managing Your MOKs</h3>
+</a>
+
+<p>The preceding instructions provided the basics of getting rEFInd up and running, including using MokManager to enroll a MOK on your computer. If you need to sign binaries, though, you'll have to use additional tools. The OpenSSL package provides the cryptographic tools necessary, but actually signing EFI binaries requires additional software. Two packages for this are available: <tt>sbsigntool</tt> and <tt>pesign</tt>. Both are available in binary form from <a href="https://build.opensuse.org/project/show?project=home%3Ajejb1%3AUEFI">this OpenSUSE Build Service (OBS)</a> repository, and many distributions ship with at least one of them. The following procedure uses <tt>sbsigntool</tt>. To sign your own binaries, follow these steps (you can skip the first five steps if you've successfully used <tt>refind-install</tt>'s <tt>--localkeys</tt> option):</p>
+
+<ol>
+
+<li>If it's not already installed, install OpenSSL on your computer. (It
+    normally comes in a package called <tt>openssl</tt>.)</li>
+
+<li>If you did <i>not</i> re-sign your rEFInd binaries with
+    <tt>refind-install</tt>'s <tt>--localkeys</tt> option, type the
+    following two commands to generate your public and private keys:
+
+<pre class="listing">
+$ <tt class="userinput">openssl req -new -x509 -newkey rsa:2048 -keyout refind_local.key \
+  -out refind_local.crt -nodes -days 3650 -subj "/CN=Your Name/"</tt>
+$ <tt class="userinput">openssl x509 -in refind_local.crt -out refind_local.cer -outform DER</tt>
+</pre>
+
+    Change <tt>Your Name</tt> to your own name or other identifying
+    characteristics, and adjust the certificate's time span (set via
+    <tt>-days</tt>) as you see fit. If you omit the <tt>-nodes</tt> option,
+    the program will prompt you for a passphrase for added security.
+    Remember this, since you'll need it to sign your binaries. The result
+    is a private key file (<tt>refind_local.key</tt>), which is highly
+    sensitive since it's required to sign binaries, and two public keys
+    (<tt>refind_local.crt</tt> and <tt>refind_local.cer</tt>), which can be
+    used to verify signed binaries' authenticity. The two public key files
+    are equivalent, but are used by different
+    tools&mdash;<tt>sbsigntool</tt> uses <tt>refind_local.crt</tt> to sign
+    binaries, but MokManager uses <tt>refind_local.cer</tt> to enroll the
+    key. If you used <tt>refind-install</tt>'s <tt>--localkeys</tt> option,
+    this step is unnecessary, since these keys have already been created
+    and are stored in <tt>/etc/refind.d/keys/</tt>.</li>
+
+<li>Copy the three key files to a secure location and adjust permissions
+    such that only you can read <tt>refind_local.key</tt>. You'll need
+    these keys to sign future binaries, so don't discard them.</li>
+
+<li>Copy the <tt>refind_local.cer</tt> file to your ESP, ideally to a
+    location with few other files. (MokManager's user interface becomes
+    unreliable when browsing directories with lots of files.)</li>
+
+<li>Download and install the <tt>sbsigntool</tt> package. Binary links for
+    various distributions are available from the <a
+    href="https://build.opensuse.org/package/show?package=sbsigntools&project=home%3Ajejb1%3AUEFI">OpenSUSE
+    Build Service</a>, or you can obtain the source code by typing <tt
+    class="userinput">git clone
+    git://kernel.ubuntu.com/jk/sbsigntool</tt>.</li>
+
+<li>Sign your binary by typing <tt class="userinput">sbsign --key
+    refind_local.key --cert refind_local.crt --output <tt
+    class="variable">binary-signed.efi binary.efi</tt></tt>, adjusting the
+    paths to the keys and the binary names.</li>
+
+<li>Copy your signed binary to a suitable location on the ESP for rEFInd to
+    locate it. Be sure to include any support files that it needs,
+    too.</li>
+
+<li>Check your <tt>refind.conf</tt> file to ensure that the
+    <tt>showtools</tt> option is either commented out or includes
+    <tt>mok_tool</tt> among its options.</li>
+
+<li>Reboot. You can try launching the boot loader you just installed, but
+    chances are it will generate an <tt>Access Denied</tt> message. For it
+    to work, you must launch MokManager using the tool that rEFInd presents
+    on its second row. You can then enroll your <tt>refind_local.cer</tt>
+    key just as you enrolled the <tt>refind.cer</tt> key.</li>
+
+</ol>
+
+<p>At this point you should be able to launch the binaries you've signed. Unfortunately, there can still be problems; see the upcoming section, <a href="#caveats">Secure Boot Caveats,</a> for information on them. Alternatively, you can try using PreLoader rather than Shim.</p>
+
+<a name="preloader">
+<h2>Using rEFInd with PreLoader</h2>
+</a>
+
+<p>If you want to use Secure Boot with a distribution that doesn't come with Shim but the preceding description exhausts you, take heart: PreLoader is easier to set up and use for your situation! Unfortunately, it's still not as easy to use as not using Secure Boot at all, and it's got some drawbacks, but it may represent an acceptable middle ground. To get started, proceed as follows:</p>
+
+<ol>
+
+<li>Boot the computer. As with Shim, this can be a challenge; you may need
+    to boot with Secure Boot disabled, use a Secure Boot&ndash;enabled live
+    CD, or do the installation from Windows.</li>
+
+<li><a href="getting.html">Download rEFInd</a> in binary form (the binary
+    zip or CD-R image file). If you download the binary zip file, unzip it;
+    if you get the CD-R image file, burn it to a CD-R and mount it.</li>
+
+<li>Download PreLoader from <a
+    href="http://blog.hansenpartnership.com/linux-foundation-secure-boot-system-released/">its
+    release page</a> or by clicking the following links. Be sure to get
+    both the <tt><a
+    href="http://blog.hansenpartnership.com/wp-uploads/2013/PreLoader.efi">PreLoader.efi</a></tt>
+    and <tt><a
+    href="http://blog.hansenpartnership.com/wp-uploads/2013/HashTool.efi">HashTool.efi</a></tt>
+    files.</li>
+
+<li>Copy the <tt>PreLoader.efi</tt> and <tt>HashTool.efi</tt> binaries to
+    the directory you intend to use for rEFInd&mdash;for instance,
+    <tt>EFI/refind</tt> on the ESP.</li>
+
+<li>Follow the installation instructions for rEFInd on the <a
+    href="installing.html">Installing rEFInd</a> page; however, give rEFInd
+    the filename <tt>loader.efi</tt> and register <tt>PreLoader.efi</tt>
+    with the EFI by using <tt>efibootmgr</tt> in Linux or <tt>bcdedit</tt>
+    in Windows. Be sure that rEFInd (as <tt>loader.efi</tt>),
+    <tt>PreLoader.efi</tt>, and <tt>HashTool.efi</tt> all reside in the
+    same directory.</li>
+
+<li>Reboot. With any luck, you'll see HashTool appear with a warning
+    message stating that it was unable to launch <tt>loader.efi</tt> and
+    declaring that it will launch <tt>HashTool.efi</tt>. Press the Enter
+    key to continue.</li>
+
+<li>HashTool should now appear. It should give you three or four options,
+    including <tt>Enroll Hash</tt>, as shown here. Select this option</li>
+
+    <br /><img src="HashTool1.png" align="CENTER" width="641" height="459"
+    alt="HashTool provide a somewhat nicer user interface than
+    MokManager's." border=2> <br />
+
+<li>You can now select the binary you want to authorize. You should first
+    select <tt>loader.efi</tt>, since that's rEFInd. The program presents
+    the hash (a very long number) and asks for confirmation. Be sure to
+    select <tt>Yes</tt>.</li>
+
+    <br /><img src="HashTool2.png" align="CENTER" width="638" height="455"
+    alt="Be sure to select the right binary when you enroll its hash."
+    border=2> <br />
+
+<p class="sidebar"><b>Note:</b> Unfortunately, the initial version of HashTool's file selector can't change filesystems. Thus, if you want to boot a Linux kernel using rEFInd and PreLoader, you'll need to copy the kernel to the ESP, at least temporarily. Alternatively, as noted earlier, you can copy <tt>HashTool.efi</tt> to the directory that holds the kernels or to another directory on that partition that rEFInd scans&mdash;but be sure to rename <tt>HashTool.efi</tt> or rEFInd will ignore it. You'll then see a boot loader entry for HashTool. More recent versions of HashTool can access multiple partitions, but I have yet to find a pre-signed version, so if you want to use it, you'll need to compile it yourself and then register its hash with an earlier version (or with Secure Boot temporarily disabled).</p>
+
+<li>Repeat the preceding two steps for any additional binaries you might
+    want to enroll. These include any EFI filesystem drivers you're using,
+    any boot loaders you're launching from rEFInd (other than those that
+    are already signed, such as Microsoft's boot loader), and possibly your
+    Linux kernel.</li>
+
+<li>At the HashTool main menu, select <tt>Exit</tt>. rEFInd should
+    launch.</li>
+
+</ol>
+
+<p>If you did everything right, rEFInd should now launch follow-on boot loaders and kernels, including both programs signed with the platform's Secure Boot keys and binaries that you've authorized with HashTool. If you need to authorize additional programs, you can do so from rEFInd by using the MOK utility tool icon that launches <tt>HashTool.efi</tt> from the second row of icons. (This icon should appear by default, but if you uncomment the <tt>showtools</tt> token in <tt>refind.conf</tt>, be sure that <tt>mok_tool</tt> is present among the options.)</p>
+
+<p>Although PreLoader is easier to set up than Shim, particularly if you need to launch programs or kernels that aren't already signed, it suffers from the problem that you must register every new program you install, including Linux kernels if you launch them directly from rEFInd. This need can be a hassle if you update your kernels frequently, and every new registration chews up a little space in your NVRAM. Nonetheless, PreLoader can be a good Secure Boot solution for many users or if you want to build a portable Linux installation that you can use on any computer with minimal fuss.</p>
+
+<a name="caveats">
+<h2>Secure Boot Caveats</h2>
+</a>
+
+<p>rEFInd's Secure Boot originated with version 0.5.0 of the program, and was revamped for version 0.6.2, both released in late 2012. It's worked well for myself and several others with whom I've corresponded; but you might still run into problems. Some issues you might encounter include the following:</p>
+
+<ul>
+
+<li>rEFInd uses the same EFI "hooks" as PreLoader. This method, however, is
+    part of an optional EFI subsystem, so in theory some EFIs might not
+    support it. For months, I knew of no such implementation, but <a
+    href="http://superuser.com/questions/615142/uefi-failed-to-install-override-security-policy">this
+    SuperUser question</a> indicates that at least one such implementation
+    exists. Subsequent discussions on the site imply that the computer
+    doesn't support Secure Boot at all. The bottom line: If you encounter
+    the error message <tt>Failed to install override security policy,</tt>
+    try removing PreLoader from your boot path.</li>
+
+<li>Under certain circumstances, the time required to launch a boot loader
+    can increase. This is unlikely to be noticeable for the average small
+    boot loader, but could be significant for larger boot loaders on slow
+    filesystems, such as Linux kernels on ext2fs, ext3fs, or ReiserFS
+    partitions.</li>
+
+<li>rEFInd's own Secure Boot support is theoretically able to work on
+    non-<i>x</i>86-64 platforms; however, to the best of my knowledge, Shim
+    and PreLoader both work only on <i>x</i>86-64, and rEFInd is dependent
+    upon these tools. In principle, you should be able to <a
+    href="http://www.rodsbooks.com/efi-bootloaders/secureboot.html#add_keys">replace
+    your computer's standard Secure Boot keys</a> to use Secure Boot on
+    these platforms with rEFInd, but this approach will require either
+    built-in key-modification tools in the computer's setup utility or a
+    build of <tt>LockDown.efi</tt> for your platform. I've not tested this
+    approach on <i>x</i>86 or ARM, so I can't say whether it would actually
+    work.</li>
+
+<li>In theory, signing Microsoft's boot loader with a MOK should work. This
+    might be handy if you want to replace your computer's built-in keys
+    with your own but still boot Windows&mdash;but be aware that if Windows
+    replaces its boot loader, it will then stop working.</li>
+
+</ul>
+
+<p>If you launch a boot loader or other program from rEFInd that relies on the EFI's standard program-launching code, that program should take advantage of Shim and its MOKs. For instance, if you launch <a href="http://freedesktop.org/wiki/Software/gummiboot">gummiboot</a> from rEFInd (and rEFInd from Shim), gummiboot should be able to launch Shim/MOK-signed Linux kernels. This is not currently true if you launch gummiboot directly from Shim. (You can launch gummiboot from PreLoader and it should work, though, because of technical differences between how Shim and PreLoader work.)</p>
+
+<p>My focus in testing rEFInd's Secure Boot capabilities has been on getting Linux kernels with EFI stub loaders to launch correctly. I've done some minimal testing with GRUB 2, though. I've also tested some self-signed binaries, such as an EFI shell and MokManager. (The EFI shell launches, but will not itself launch anything that's not been signed with a UEFI Secure Boot key. This of course limits its utility.)</p>
+
+<p>Some of the awkwardness of using rEFInd with Secure Boot is due to the need to manage MOKs (either keys with Shim or hashes with PreLoader). Such problems would evaporate if you could get a copy of rEFInd signed with your distribution's Secure Boot key. Thus, if you're annoyed by such problems, try filing a feature request with your distribution maintainer to have them include rEFInd (and sign it!) with their official package set.</p>
+
+<hr />
+
+<p>copyright &copy; 2012&ndash;2015 by Roderick W. Smith</p>
+
+<p>This document is licensed under the terms of the <a href="FDL-1.3.txt">GNU Free Documentation License (FDL), version 1.3.</a></p>
+
+<p>If you have problems with or comments about this Web page, please e-mail me at <a href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.com.</a> Thanks.</p>
+
+<p><a href="index.html">Go to the main rEFInd page</a></p>
+
+<p><a href="revisions.html">Learn about rEFInd's history</a></p>
+
+
+  <p><a href="http://www.rodsbooks.com/">Return</a> to my main Web page.</p>
+</body>
+</html>
diff --git a/docs/refind/sip.html b/docs/refind/sip.html
new file mode 100644 (file)
index 0000000..296d829
--- /dev/null
@@ -0,0 +1,339 @@
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>The rEFInd Boot Manager: rEFInd and System Integrity Protection</title>
+  <link href="../Styles/styles.css" rel="stylesheet" type="text/css" />
+</head>
+
+<meta name="viewport" content="width=device-width, initial-scale=1">
+
+<body>
+  <h1>The rEFInd Boot Manager:<br />rEFInd and System Integrity Protection</h1>
+
+<p class="subhead">by Roderick W. Smith, <a
+href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.com</a></p>
+
+<p>Originally written: 11/8/2015; last Web page update:
+11/17/2015, referencing rEFInd 0.10.0</p>
+
+
+<p>This Web page is provided free of charge and with no annoying outside ads; however, I did take time to prepare it, and Web hosting does cost money. If you find this Web page useful, please consider making a small donation to help keep this site up and running. Thanks!</p>
+
+<table border="1">
+<tr>
+<td>Donate $1.00</td>
+<td>Donate $2.50</td>
+<td>Donate $5.00</td>
+<td>Donate $10.00</td>
+<td>Donate $20.00</td>
+<td>Donate another value</td>
+</tr>
+<tr>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="1.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="2.50">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="5.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="10.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="20.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td></tr>
+</table>
+
+<hr />
+
+<p>This page is part of the documentation for the rEFInd boot manager. If a Web search has brought you here, you may want to start at the <a href="index.html">main page.</a></p>
+
+<hr />
+
+<div style="float:right; width:55%">
+
+<p>Apple's OS X 10.11 (aka <i>El Capitan</i>) includes a new feature, known as System Integrity Protection (SIP), aka "rootless" mode. This feature is causing some consternation for advanced users, because it restricts what you can do with your computer, even as <tt>root</tt>. This page is dedicated to this new feature, including basic information on why SIP exists, how to install rEFInd on a computer with SIP enabled, and how to use rEFInd to manage SIP. Note that if you've come here for help installing rEFInd on a Mac with SIP enabled, you can click to one of the methods in the "Contents" box to the left of this paragraph. I recommend trying Recovery mode first; but if you have reason to try another method, you can do so.</p>
+
+</div>
+
+<div class="navbar">
+
+<h4 class="tight">Contents</h4>
+
+<ul>
+
+<li class="tight"><a href="#what_is">What Is SIP?</li>
+
+<li class="tight"><a href="#sip_enabled">Installing rEFInd with SIP Enabled</a>
+
+  <ul>
+
+  <li class="tight"><a href="#recovery">Using Recovery Mode</a></li>
+
+  <li class="tight"><a href="#disable">Disabling SIP</a>
+  <ul>
+
+  <li class="tight"><a href="#disable_in_osx">Disabling SIP with Recovery HD</a></li>
+
+  <li class="tight"><a href="#disable_in_refind">Disabling SIP with rEFInd</a></li>
+
+  </ul></li>
+
+  <li class="tight"><a href="#another">Using Another OS</a></li>
+
+  </ul></li>
+
+<li class="tight"><a href="#refind_manage">Using rEFInd to Manage SIP</a></li>
+
+<li class="tight"><a href="#conclusion">Conclusion</a></li>
+
+</ul>
+
+</div>
+
+<a name="what_is">
+<h2>What Is SIP?</h2>
+</a>
+
+<p>To understand SIP, you should first know that Unix-like systems, including OS X, have traditionally provided a model of security in which ordinary users can read and write their own files (word processor documents, their own digital photos, etc.), but cannot write to system files (programs, system configuration files, etc.)&mdash;and users cannot even read some system files. This system security model has worked well for decades on traditional Unix systems, which have been administered by computer professionals and used by individuals with less experience. For administrative tasks, the <tt>root</tt> account is used. On Macs, this access is generally granted by the <tt>sudo</tt> command or by various GUI tools. Most Macs, in contrast to traditional Unix mainframes and minicomputers from the 20th century, are single-user computers that are administered by their users. Such people often lack the knowledge of the professional system administrators who have traditionally managed Unix systems; but they must still perform system administration tasks such as installing new software and configuring network settings. OS X has always provided some measure of security by requiring users to enter their passwords before performing these dangerous tasks, and by providing GUI tools to help guide users through these tasks in a way that minimizes the risk of damage.</p>
+
+<p>Apple has apparently decided that these safeguards are no longer sufficient, at least for certain tasks, such as writing files to certain system directories and installing boot loaders. I won't try to speak for Apple or explain their motivations, but the result of Apple's decisions is SIP. With SIP active, as is the default, OS X 10.11 limits your ability to perform some of these administrative tasks. You can still install and remove most third-party programs, configure your network, and so on; but some critical directories can no longer be written, even as <tt>root</tt>, and some utilities cannot be used in certain ways, even as <tt>root</tt>. These restrictions impact rEFInd because one of the affected tools, a command called <tt>bless</tt>, is required to tell the Mac to boot rEFInd rather than to boot OS X directly.</p>
+
+<a name="sip_enabled">
+<h2>Installing rEFInd with SIP Enabled</h2>
+</a>
+
+<p>The end result of SIP is that rEFInd cannot be installed under OS X 10.11 in the way described on the <a href="installing.html">Installing rEFInd</a> page&mdash;at least, not without first booting into <a href="#recovery">Recovery mode,</a> in which SIP restrictions are ignored; or <a href="#disable">disabling SIP</a> (either temporarily or permanently). This page covers these two options in more detail, as well as a third: <a href="#another">Using another OS</a> to install rEFInd.</p>
+
+<a name="recovery">
+<h3>Using Recovery Mode</h3>
+</a>
+
+<p>Unless you've deleted it, the Recovery HD partition should be present on your Mac as a way to perform emergency recovery operations. The nature of this tool means that SIP cannot be enabled when using it, so you can install rEFInd from a boot to this partition. The trouble is that this installation is not a full-fledged OS X system, so you may have trouble using it if you're not comfortable with such a bare-bones environment. Nontheless, it is arguably the best way to install rEFInd on a Mac that runs OS X 10.11. To do so, follow these steps:</p>
+
+<ol>
+
+<li><a href="getting.html">Download the rEFInd binary <tt>.zip</tt> file</a> and unpack it. You can unpack it on your regular hard disk or on a USB flash drive. Pay attention to where it's located, though; you'll need to find it later. Pay attention to both the name of the volume and the <i>complete</i> path to the directory in which it's stored. (Your home directory is normally <tt>/Users/<tt class="variable">yourname</tt></tt>, where <tt class="variable">yourname</tt> is your username. Your Desktop is normally <tt>/Users/<tt class="variable">yourname</tt>/Desktop</tt>.</li>
+
+<li>Reboot the computer.</li>
+
+<li>At the startup chime, hold down the Command+R key combination. The computer should launch into the Recovery system. This is a very bare system, with only a window providing a way to launch a handful of utilities and a menu bar. You must use the latter.</li>
+
+<li>Select Utilities -&gt; Terminal from the menu bar. A Terminal window should open.</li>
+
+<li>If you unpacked rEFInd on a USB flash drive, insert it and wait for its access light (if it has one) to stop blinking.</li>
+
+<li>Increase the size of the Terminal a bit. (This just makes its output more legible, since the next step produces long lines.)</li>
+
+<li>Type <tt class="userinput">df -h</tt> in the Terminal. This produces a list of partitions that are mounted. Locate the one on which you unpacked the rEFInd files. It will normally be <tt>/Volumes/<tt class="variable">Somename</tt></tt>, where <tt class="variable">Somename</tt> is the volume's name.</li>
+
+<li>In the Terminal, use <tt>cd</tt> to change to the directory where the rEFInd files you unpacked earlier are stored. For instance, on my MacBook, I would type <tt class="userinput">cd /Volumes/Macintosh\ HD/Users/rodsmith/Destkop/refind-0.10.0</tt>. Note that if any element of this path includes a space, you must either enclose the <i>entire path</i> in quotes or precede the space with a backslash (<tt>\</tt>), as in this example's <tt>Macintosh\ HD</tt> volume name.</li>
+
+<li>Type <tt class="userinput">ls</tt> to verify that <tt>refind-install</tt> is present in this directory.</li>
+
+<li>Type <tt class="userinput">./refind-install</tt> to run the installation script. It should run normally, as described on the <a href="installing.html">Installing rEFInd</a> page. You can add options, if you like, as described on that page. Alternatively, you can perform a manual installation, also as described on that page.</li>
+
+<li>Reboot.</li>
+
+</ol>
+
+<p>At this point, rEFInd should come up and enable you to boot into OS X and any other OS(es) that are already installed. You should not need to perform these steps again unless OS X re-installs its own boot loader or a subsequent OS installation overrides the default boot option. You can install an updated rEFInd and it should install correctly, provided you're installing it to the EFI System Partition (ESP). The <tt>refind-install</tt> script may complain about a failure, but because you're overwriting one rEFInd binary with another one, it should continue to boot. (If you installed rEFInd to an HFS+ partition, though, replacing the original file will require using <tt>bless</tt> to tell the firmware about the change, so updating such an installation probably won't work with SIP active.)</p>
+
+<a name="disable">
+<h3>Disabling SIP</h3>
+</a>
+
+<p>Another option is to disable SIP for your regular boot. This is a viable option if you're an expert who needs regular access to tools with which SIP interferes, such as low-level disk utilities. Regular users should probably avoid this option unless the preceding procedure does not work&mdash;and in that case, you should disable SIP temporarily and then re-enable it when you've finished installing rEFInd. On this page, I describe two methods of disabling SIP: <a href="#disable_in_osx">using OS X's Recovery HD system</a> and <a href="#disable_in_refind">using rEFInd on CD-R or USB flash drive.</a></p>
+
+<a name="disable_in_osx">
+<h4>Disabling SIP with Recovery HD</h4>
+</a>
+
+<p>You can use the Recovery HD, as in the previous procedure, to disable SIP. To do so, boot it and launch a Terminal window, as described in the previous section. Instead of locating and running the <tt>refind-install</tt> script, though, you should type:</p>
+
+<pre class="listing"># <tt class="userinput">csrutil disable</tt></pre>
+
+<p>This command will disable SIP for all OSes that honor this setting. (In theory, multiple versions of OS X might be installed on a single computer, and all of them that support SIP should honor the SIP settings. To the best of my knowledge, no non-Apple OS honors SIP settings, although that could change.)</p>
+
+<p>Once you've typed this command, you can reboot the computer. When you return to your regular OS X installation, SIP should be disabled and rEFInd should install normally, as described on the <a href="installing.html">Installing rEFInd</a> page. You will also be able to use disk partitioning tools like my <a href="http://www.rodsbooks.com/gdisk/">GPT fdisk,</a> write to directories that are normally off-limits, and so on. Note that disabling SIP does <i>not</i> disable normal Unix-style protections&mdash;you'll still need to use <tt>sudo</tt> (or enter your password in a GUI dialog box) to acquire <tt>root</tt> privileges to perform these system-administration tasks. You'll be no less safe with SIP disabled under OS X 10.11 than you would be with OS X 10.10 or earlier; you simply won't have its added protections against user error or malicious software.</p>
+
+<p>If you want to re-enable SIP, you can do so in exactly the way you disabled it, except that you should type <tt class="userinput">csrutil enable</tt> rather than <tt class="userinput">csrutil disable</tt> in the Recovery environment.</p>
+
+<a name="disable_in_refind">
+<h4>Disabling SIP with rEFInd</h4>
+</a>
+
+<p>As described later on this page, rEFInd 0.10.0 provides SIP control features, but they're disabled by default&mdash;except on the USB flash drive and CD-R images available from the <a href="http://www.rodsbooks.com/refind/getting.html">rEFInd downloads page.</a> On these images, the SIP control features are enabled, and can toggle between the two main modes you can set via <tt class="userinput">csrutil enable</tt> and <tt class="userinput">csrutil disable</tt> in the Recovery HD system. Thus, to disable SIP to install rEFInd, you can:</p>
+
+<ol>
+
+<li>Download the USB flash drive or CD-R version of rEFInd, as suitable for your computer.</li>
+
+<li>Prepare a boot medium. With the CD-R image, you can use your favorite disc-burning software. With the USB flash drive image, you can use <tt>dd</tt> to copy the image to a blank disk, as in <tt class="userinput">dd if=refind-flashdrive-0.10.0.img of=/dev/disk3</tt> to write the image to <tt>/dev/disk3</tt>. <b>Any existing data on the target disk will be destroyed!</b> For this reason, it's <b><i>imperative</i></b> that you specify the correct target (<tt>of=</tt>) disk; if you accidentally point this command to your regular hard disk, recovery will be difficult!</li>
+
+<li>Reboot and hold down the Option (or Alt) key to see the Mac's built-in boot manager.</li>
+
+<li>Select your external boot medium to boot to rEFInd.</li>
+
+<li>Use the SIP "shield" icon on the second row to toggle between SIP settings, as described in more detail in <a href="#refind_manage">Using rEFInd to Manage SIP.</a></li>
+
+</ol>
+
+<p>Once you install rEFInd, you can leave SIP enabled, enable your newly-installed rEFInd's SIP features and use them to disable SIP, or boot again from your external rEFInd to disable SIP.</p>
+
+<p>This procedure has the advantage of being a bit quicker than using the Recovery HD&mdash;at least, if you've already got rEFInd 0.10.0 or later on an external medium. It will also work if your Recovery HD installation is missing or broken. On the other hand, it's probably easier to boot to the Recovery HD once or twice than to download and prepare a rEFInd boot medium. Also, some Macs are a little flaky when it comes to booting from external media, so you may have trouble booting in this way. Finally, if you don't already have rEFInd on an external medium and if you don't have an optical drive, writing a USB flash drive with <tt>dd</tt> carries a small risk of accidentally trashing your hard disk, particularly if you're unfamiliar with disk devices and <tt>dd</tt>.</p>
+
+<a name="another">
+<h3>Using Another OS</h3>
+</a>
+
+<p>A final option for installing rEFInd on a Mac that runs with SIP enabled is to do the installation using another OS. This other OS could be an OS that's already installed or an emergency boot disk, such as an <a href="http://www.ubuntu.com">Ubuntu</a> installation/recovery system.</p>
+
+<p>If you follow this path, you'll need to know something about how to boot and use your non-Apple OS. The options are quite varied, so I can't provide every detail; however, I do have a few tips:</p>
+
+<ul>
+
+<li>If you've already installed another OS but can't boot it because of an upgrade to OS X 10.11, you can use rEFInd on CD-R or USB flash drive to boot to your other OS. You can download images for both media from the <a href="getting.html">rEFInd downloads page.</a> Prepare a boot medium, insert it in your computer, reboot, and hold down the Option (or Alt) key. The Mac's built-in boot menu should appear, enabling you to boot rEFInd from the removable disk. It should then let you boot your already-installed OS, whereupon you can follow the <a href="installing.html">regular rEFInd installation instructions</a> for that OS.</li>
+
+<li>It's imperative that your rEFInd installation occur in an <i>EFI-mode boot!</i> Many Windows installations on Macs, in particular, are done in BIOS/CSM/legacy mode, and so cannot be used for installing rEFInd. rEFInd can boot most Linux installations in EFI mode (as above), but if a BIOS-mode GRUB is installed, you might accidentally boot it. See the <a href="bootmode.html">What's Your Boot Mode?</a> page for information on how to determine your boot mode.</li>
+
+<li>You can use many Linux distributions' installers to run a minimal Linux system that you can use for installing rEFInd. This can be a useful trick even if you don't intend to run Linux normally. An <a href="http://www.ubuntu.com">Ubuntu</a> image can be useful for this. You should insert the boot medium and hold down Option (or Alt) while booting to launch the installer, but be sure to pick the option to "try Ubuntu before installing" (or a similar option for other Linux distributions). You may need to install the <tt>efibootmgr</tt> package to install rEFInd. (Typing <tt class="userinput">sudo apt-get install efibootmgr</tt> should do this in Ubuntu.)</li>
+
+</ul>
+
+<p>I've tested this method of installing rEFInd on my MacBook Air (purchased in late 2014) and on my first-generation 32-bit Mac Mini, but I can't promise it will work on all Macs&mdash;or even on a Mac that's identical to one of mine but with a configuration that's different from mine. My preference is to install rEFInd under OS X on Macs, because Apple likes to do things differently from everybody else, and so a Mac's firmware might not react in the usual way to tools like <tt>efibootmgr</tt> in Linux or <tt>bcdedit</tt> in Windows.</p>
+
+<a name="refind_manage">
+<h2>Using rEFInd to Manage SIP</h2>
+</a>
+
+<p>Once rEFInd is installed, you can use it to manage SIP features; however, the rEFInd features needed to do this are disabled by default. You must uncomment or add two lines to your <tt>refind.conf</tt> file:</p>
+
+<p class="sidebar"><b>Note:</b> Apple code samples and technical discussions are filled with the acronym "CSR." I don't know for what this acronym stands, but as it appears to be used in preference to "SIP" or "rootless" when referring to specific values, I used it in the <tt>refind.conf</tt> files token names.</p>
+
+<ul>
+
+<li><tt class="userinput">showtools</tt>&mdash;This line specifies tools that appear on the second row of icons in rEFInd. The new tool for managing SIP is called <tt>csr_rotate</tt>, so you must uncomment <tt>showtools</tt> and add this option, or create a new <tt>showtools</tt> line.</li>
+
+<li><tt class="userinput">csr_values</tt>&mdash;This line lists the hexadecimal values through which you can rotate once <tt>csr_rotate</tt> is active on the <tt>showtools</tt> line. The trick to this token is selecting appropriate options. Several sites, such as <a href="http://www.idelta.info/archives/sip-rootless-internal-in-el-capitan/">this one</a> and <a href="http://osxarena.com/2015/10/guide-details-apples-system-integrity-protection-sip-for-hackintosh/">this one,</a> describe the meanings of the various options, but often not in much detail. Apple's own <tt>csrutil</tt> command sets values of 77 (disabled) or 10 (enabled). Note also that you specify hexadecimal values on this line, but without a leading <tt>0x</tt> or other hexadecimal-notation indicator. If you specify gibberish values, or hexadecimal values higher than those used by SIP, rEFInd ignores the bad entries. Thus, if some of your values are being ignored, you should check your <tt>csr_values</tt> line for typos.</li>
+
+</ul>
+
+<p>Note that <i><b>both</b></i> of these options must be set appropriately. If either of them is missing or misconfigured, rEFInd will not display the new SIP tool. A typical configuration using these features might look like this:</p>
+
+<pre class="listing">showtools shell,memtest,gdisk,csr_rotate,apple_recovery,windows_recovery,about,shutdown,reboot
+csr_values 10,77</pre>
+
+    <img src="func_csr_rotate.png" align="right" width="48" height="48"
+    alt="The SIP rotation tool rotates through all the CSR values you set"
+    border=2 background="gray"/>
+
+<p>Once these options are set and you reboot into rEFInd, you should see a new shield icon on the second row, as shown at the right. When you select this tool, rEFInd identifies the next available CSR value from the list you specified and switches to that mode, rotating back to the start of the list once the end is reached. To confirm that the SIP mode has changed, rEFInd displays, for three seconds, a message identifying the new mode.</p>
+
+<p>Whether or not you've enabled these SIP features in <tt>refind.conf</tt>, rEFInd displays the current SIP status on its "About" page:</p>
+
+    <br /><center><img src="about.png" align="center" width="525"
+    height="559" alt="rEFInd presents a graphical menu for selecting your
+    boot OS." border=2> </center><br />
+
+<p>Note the line that reads "System Integrity Protection is disabled (0x77)" (highlighted in this screen shot). This line will be updated whenever you use the CSR rotation tool, so if you've specified a large number of values and have forgotten where you are in your rotation, you can use the About screen to figure it out.</p>
+
+<p>Both the summary on the About page and the CSR rotation tool depend on the presence of the <tt>csr-active-config</tt> NVRAM variable, which is where this information is stored. Thus, these features will not be present on older Macs that have not seen the presence of an OS X version that sets this variable. Likewise, you probably won't see the SIP summary in About or be able to set these values via <tt>csr_rotate</tt> and <tt>csr_values</tt> on a UEFI-based PC. (You could always create the variable on such a system in some other way, in which case rEFInd would let you adjust it, but it would have no effect on any OS except OS X.)</p>
+
+<p>I provide these features in rEFInd as a convenience for developers and other advanced users who have a need to adjust their SIP settings. Using rEFInd for this purpose is much faster than booting into the OS X Recovery system to make these adjustments. I discourage others from playing with these settings, since changing them inappropriately could cause problems; that's why they're not enabled by default.</p>
+
+<a name="conclusion">
+<h2>Conclusion</h2>
+</a>
+
+<p>Although the goal of increased security is a good one, SIP is causing problems for intermediate and advanced users. The good news is that the process to install rEFInd on a system that runs OS X 10.11, although more complex than it used to be, is not an impossible one. Furthermore, once you've done it, you shouldn't have to do it again for a while. (An update to OS X's boot loader is entirely possible, though. If nothing else, the next major OS X update may require re-installing rEFInd.) For advanced users, rEFInd can adjust SIP settings, which can be helpful if you occasionally want to do something that require greater-than-typical privileges.</p>
+
+<hr />
+
+<p>copyright &copy; 2015 by Roderick W. Smith</p>
+
+<p>This document is licensed under the terms of the <a href="FDL-1.3.txt">GNU Free Documentation License (FDL), version 1.3.</a></p>
+
+<p>If you have problems with or comments about this Web page, please e-mail me at <a href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.com.</a> Thanks.</p>
+
+<p><a href="index.html">Go to the main rEFInd page</a></p>
+
+<p><a href="using.html">Learn how to use rEFInd</a></p>
+
+  <p><a href="http://www.rodsbooks.com/">Return</a> to my main Web page.</p>
+</body>
+</html>
diff --git a/docs/refind/startup-disk.png b/docs/refind/startup-disk.png
new file mode 100644 (file)
index 0000000..19ac11f
Binary files /dev/null and b/docs/refind/startup-disk.png differ
diff --git a/docs/refind/submenu.png b/docs/refind/submenu.png
new file mode 100644 (file)
index 0000000..5d31f81
Binary files /dev/null and b/docs/refind/submenu.png differ
diff --git a/docs/refind/themes.html b/docs/refind/themes.html
new file mode 100644 (file)
index 0000000..ce4f3ca
--- /dev/null
@@ -0,0 +1,382 @@
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>The rEFInd Boot Manager: Theming rEFInd</title>
+  <link href="../Styles/styles.css" rel="stylesheet" type="text/css" />
+</head>
+
+<meta name="viewport" content="width=device-width, initial-scale=1">
+
+<body>
+  <h1>The rEFInd Boot Manager:<br />Theming rEFInd</h1>
+
+  <p class="subhead">by Roderick W. Smith, <a
+href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.com</a></p>
+
+<p>Originally written: 4/19/2012; last Web page update:
+11/8/2015, referencing rEFInd 0.10.0</p>
+
+
+<p>This Web page is provided free of charge and with no annoying outside ads; however, I did take time to prepare it, and Web hosting does cost money. If you find this Web page useful, please consider making a small donation to help keep this site up and running. Thanks!</p>
+
+<table border="1">
+<tr>
+<td>Donate $1.00</td>
+<td>Donate $2.50</td>
+<td>Donate $5.00</td>
+<td>Donate $10.00</td>
+<td>Donate $20.00</td>
+<td>Donate another value</td>
+</tr>
+<tr>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="1.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="2.50">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="5.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="10.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="20.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td></tr>
+</table>
+
+<hr />
+
+<p>This page is part of the documentation for the rEFInd boot manager. If a Web search has brought you here, you may want to start at the <a href="index.html">main page.</a></p>
+
+<hr />
+
+<div style="float:right; width:55%">
+
+<p>rEFInd relies on both built-in and external graphical elements in its user interface, and all of these elements can be replaced by user-specified files. This fact makes rEFInd's "look and feel" highly adjustable even by non-programmers. This page will help you get started in making such changes to each of the major sets of features: banners and backgrounds, icons, icon selection backgrounds, and fonts. I conclude this page with pointers to a few themes that users have created for rEFInd.</p>
+
+</div>
+
+<div class="navbar">
+
+<h4 class="tight">Contents</h4>
+
+<ul>
+
+<li class="tight"><a href="#basics">Theming Basics</li>
+
+<li class="tight"><a href="#banners">Banner and Backgrounds</a></li>
+
+<li class="tight"><a href="#icons">Icons</a></li>
+
+<li class="tight"><a href="#icon_backgrounds">Icon Selection Backgrounds</a></li>
+
+<li class="tight"><a href="#fonts">Fonts</a></li>
+
+<li class="tight"><a href="#known_themes">Known Themes</a></li>
+
+</ul>
+
+</div>
+
+<a name="basics">
+<h2>Theming Basics</h2>
+</a>
+
+<p>Broadly speaking, rEFInd's graphical elements fall into four categories:</p>
+
+<ul>
+
+<li><b>Banners and backgrounds</b>&mdash;A <i>banner</i> is a logo or small graphical element that rEFInd displays horizontally centered in the top half of the screen. The rest of the screen is filled with a solid color derived from the color used in the top-left pixel of the banner image. rEFInd includes a built-in banner image that's used if you don't specify another image with the <tt>banner</tt> token in <tt>refind.conf</tt>. A <i>background</i> is simply a banner image that fills the screen.</li>
+
+<li><b>Icons</b>&mdash;rEFInd uses icons for its OSes and utilities. The vast majority of these icons are loaded from disk files and so are easily replaced without adjusting the <tt>refind.conf</tt> file. Alternatively, you can specify a new icons directory with the <tt>icons_dir</tt> token in <tt>refind.conf</tt>.</li>
+
+<li><b>Icon selection backgrounds</b>&mdash;When an icon is selected, it's merged with a slightly larger selection icon, which you can change by specifying a new file with the <tt>selection_big</tt> and <tt>selection_small</tt> tokens in <tt>refind.conf</tt>.</li>
+
+<li><b>fonts</b>&mdash;rEFInd uses a 14-point monospaced sans serif font by default. If you don't like this font, you can change it to another monospaced font by using the <tt>font</tt> token in <tt>refind.conf</tt>; however, the font file is a simple PNG image of the font's characters, which limits rEFInd's font capabilities.</li>
+
+</ul>
+
+<p>Of course, not all of these elements are likely to be included in all themes. You might want to change just one or two elements&mdash;say, to add an icon for your OS or to change the banner or background.</p>
+
+<a name="banners">
+<h2>Banners and Backgrounds</h2>
+</a>
+
+<p>You can create a new background image and logo by placing a PNG or BMP file in rEFInd's main directory and passing its filename to rEFInd with the <tt>banner</tt> option in <tt>refind.conf</tt>. If the image is smaller than the screen, the color in the top-left pixel of the image will be used for the rest of the display. This pixel's color is also used as the background color for submenu text, even for full-screen backgrounds. Using a full-screen background image can produce a dramatically different "look" for rEFInd:</p>
+
+    <br /><center><img src="refind-background.png" align="center"
+    width="750" height="563" alt="rEFInd provides extensive theming
+    options." border=2> </center><br />
+
+<p class="sidebar"><b>Tip:</b> If you use a laptop, you can create a banner or background that includes your contact information. If you lose your laptop and it's found by an honest person, this should facilitate your getting it back. Setting <tt>timeout 0</tt> in <tt>refind.conf</tt> will ensure that the message remains on the screen indefinitely.</p>
+
+<p>Note that in this example, the text immediately below the icons is white, whereas the hint text at the bottom of the screen is black. The text color is determined by the brightness of the background; rEFInd uses black text against light backgrounds and light text against dark backgrounds. This adjustment is done on a line-by-line basis, so it copes better with horizontal lines than with vertical lines.</p>
+
+<p>If you want to use a full-screen background but also include the rEFInd logo, you can merge the two in a graphics editor by including the <tt>refind_banner-alpha.png</tt> or <tt>refind-banner.svg</tt> image from the <tt>banners</tt> subdirectory of the rEFInd package in your background.</p>
+
+<p>Beginning with rEFInd 0.7.8, it's possible to stretch or shrink any image to fill the screen. To do so, you should use the <tt>banner_scale</tt> option in <tt>refind.conf</tt>: Set it to <tt>noscale</tt> (the default) to use small banners as such or to crop larger images; or set it to <tt>fillscreen</tt> to adjust your banner's size to exactly fill the screen. This should be particularly handy for theme developers who want to use a full-screen background image, since you can now do this with just one image file.</p>
+
+<a name="icons">
+<h2>Icons</h2>
+</a>
+
+<p class="sidebar">Prior to version 0.10.0, rEFInd's icons came from a variety of sources&mdash;mostly from the <a href="http://deviantdark.deviantart.com/art/Oxygen-Refit-70199755">Oxygen Refit</a> package, with OS icons from rEFIt and assorted other sources. If you prefer these icons to the new ones, you can pull them out of a rEFInd 0.9.2 (or earlier) package</p>
+
+<p>The core icons in rEFInd 0.10.0 and later come from the <a
+href="http://alecive.deviantart.com/art/AwOken-163570862">AwOken 2.5 icon
+set,</a> with additional icons created by me, and a few others taken from
+other sources. (The details are documented in the <tt>README</tt> file in
+the <tt>icons</tt> subdirectory.) These icons have a "flat" appearance, but
+with drop shadows to provide a type of depth. Most of the individual icons
+use just one color, aside from the drop shadow. Of course, the point of
+themes is that you might get bored with, or simply not like, the default
+graphics, so you can change them.</p>
+
+<p>As described on various other pages of this document, rEFInd relies on icon files located in its <tt>icons</tt> subdirectory, and occasionally elsewhere, to define its overall appearance. You can adjust rEFInd's icons in a few ways:</p>
+
+<ul>
+
+<li>You can create new icons, place them in a subdirectory of rEFInd's main directory, and tell the program to use the new icons by setting the <tt>icons_dir</tt> token in <tt>refind.conf</tt>. This will affect the appearance of the OS tags, the utility tags, and so on. The names of these icons should match those in the <tt>icons</tt> subdirectory (although you can substitute ICNS for PNG files, with a suitable filename change), and are fairly self-explanatory. The default size for OS tags is 128x128 pixels, tags for 2nd-row utilities are ordinarily 48x48 pixels, and drive-type badges are 32x32 pixels by default. If an icon is missing from the directory specified by <tt>icons_dir</tt>, rEFInd falls back to the icon from the standard <tt>icons</tt> subdirectory; thus, you can replace just a subset of the standard icons. rEFInd can use icons in either Apple's <a href="http://en.wikipedia.org/wiki/Apple_Icon_Image">icon image (ICNS)</a> or <a href="http://en.wikipedia.org/wiki/Portable_Network_Graphics">Portable Network Graphics (PNG)</a> format. PNG files are easier to generate on most platforms. You can generate ICNS files in various Apple programs or by using the <a href="http://icns.sourceforge.net/">libicns</a> library (and in particular its <tt>png2icns</tt> program) in Linux.</li>
+
+<li>You can do as above, but place your new icons in the default <tt>icons</tt> subdirectory. This method is discouraged because using the <tt>refind-install</tt> script to upgrade rEFInd will replace your customized icons.</li>
+
+<li>You can customize the appearance of an individual boot loader by placing an ICNS or PNG file in its directory with the same name as the boot loader but with a <tt>.icns</tt> or <tt>.png</tt> extension. For instance, if your boot loader program is <tt>elilo.efi</tt>, you can create a custom icon by naming it <tt>elilo.png</tt>.</li>
+
+<li>You can provide an icon for boot loaders stored in the root directory of a filesystem by placing a file called <tt>.VolumeIcon.icns</tt> or <tt>.VolumeIcon.png</tt> in that volume's root.</li>
+
+<li>You can set a custom badge (the icon that identifies the disk type) by creating a file called <tt>.VolumeBadge.icns</tt> or <tt>.VolumeBadge.png</tt> in that volume's root. This setting applies to all the boot loaders found on this volume, even if they're in subdirectories.</li>
+
+<li>You can adjust the sizes of icons by using the <tt>big_icon_size</tt> and <tt>small_icon_size</tt> tokens in <tt>refind.conf</tt>. These tokens adjust the size of the first-row OS and second-row tool icons, respectively. The <tt>big_icon_size</tt> option also indirectly sets the disk-type badge size; badges have sides that 1/4 the size of OS icons. The icons provided with rEFInd are 128x128 for OS icons, 48x48 for tools, and 32x32 for badges. The <tt>big_icon_size</tt> and <tt>small_icon_size</tt> tokens cause these icons to be scaled to the desired value; however, for best results you should replace your the default icons with ones generated natively in the desired size. (PNG and ICNS are both bitmap formats, and so will be degraded by scaling operations.) Because ICNS is limited in the sizes it supports, you're better off using PNG if you want to create larger icons.</li>
+
+</ul>
+
+<p>As an example of what the combination of icons and backgrounds can do, consider my own <a href="https://sourceforge.net/projects/refind/files/themes/">Snowy theme,</a> showing the same boot options as the preceding image:</p>
+
+    <br /><center><img src="refind-background-snowy.png" align="center"
+    width="750" height="563" alt="The Snowy theme uses predominantly white
+    icons and a background image to match its name" border=2>
+    </center><br />
+
+<a name="icon_backgrounds">
+<h2>Icon Selection Backgrounds</h2>
+</a>
+
+<p>rEFInd identifies the current selection by displaying a partially-transparent icon "between" the OS or tool icon and the background image. The default icon works reasonably well on both solid and image backgrounds, but if you like, you can customize it by creating new icons in PNG or in Microsoft's <a href="http://en.wikipedia.org/wiki/BMP_file_format">BMP format.</a> You should create both 144x144 and 64x64 images and tell rEFInd about them by using the <tt>selection_big</tt> and <tt>selection_small</tt> tokens, respectively, in <tt>refind.conf</tt>. (If you scale your icons, you may want to adjust the selection tile images appropriately. The big image is 9/8 the size of its matching icons, while the small tile is 4/3 the size of its icons.) If you omit the large icon, rEFInd will stretch the small icon to fit the larger space; if you omit the small icon, rEFInd will use the default small icon. Because BMP doesn't support transparency (alpha channels), you must use the PNG format if you want your selection background to show the underlying image beneath it. (You can create the illusion of transparency on a solid background by matching the colors, though.)</p>
+
+<a name="fonts">
+<h2>Fonts</h2>
+</a>
+
+<p>rEFInd's default font is a 14-point (12-point in 0.6.5 and earlier) serif monospaced font. I also include a handful of alternatives in the <tt>fonts</tt> subdirectory. rEFInd's font support is extremely rudimentary, though; it reads a PNG file that holds the glyphs from ASCII 32 (space) through ASCII 126 (tilde, <tt>~</tt>), plus a glyph that's displayed for all characters outside of this range. Thus, rEFInd can't currently display non-ASCII characters or use proportional (variable-width) fonts. You can change the font from one monospaced font to another and change the font size, though.</p>
+
+<p>If you want to create your own fonts, you can do so. If you're using Linux, the <tt>mkfont.sh</tt> script in the <tt>fonts</tt> subdirectory will convert an installed <i>monospace</i> font into a suitable format. (This script works properly for most fonts, but if a font is unusually thin or wide, you will have to adjust the <tt>let CellWidth=</tt> line near the end of the file.) You can use it like this:</p>
+
+<pre class="listing">
+$ <tt class="userinput">./mkfont.sh Liberation-Mono-Italic 14 -1 liberation-mono-italic-14.png</tt>
+</pre>
+
+<p>The result is a PNG file, <tt>liberation-mono-italic-14.png</tt>, that you can copy to your rEFInd directory and load with the <tt>font</tt> token in <tt>refind.conf</tt>, as in:</p>
+
+<pre class="listing">font liberation-mono-italic-14.png</pre>
+
+<p>The <tt>mkfont.sh</tt> script takes four arguments:</p>
+
+<ul>
+
+<li><b>The font name</b>&mdash;Type <tt class="userinput">convert -list font | less</tt> to obtain a list of fonts available on your computer. Note, however, that rEFInd requires <i>monospaced</i> (fixed-width) fonts, and most of the fonts installed on most computers are variable-width.</li>
+
+<li><b>The font size in points</b></li>
+
+<li><b>A y offset</b>&mdash;Many fonts require an adjustment up (negative values), or occasionally down (positive values) to fit in the PNG image area. You'll have to use trial and error to get this to work.</li>
+
+<li><b>The output filename</b></li>
+
+</ul>
+
+<p>I recommend checking the PNG file in a graphics program like <tt>eog</tt> before using it. Note that the font files should have an alpha layer, which many graphics programs display as a gray-and-white checkered background.</p>
+
+<p>If you're not using Linux, or if you want to use some other method of
+generating fonts, you can do so. The font files must be in PNG format (the
+BMP format doesn't support an alpha layer, which is required for proper
+transparency). They must contain glyphs for the 95 characters between ASCII
+32 (space) and ASCII 126 (tilde, ~), inclusive, plus a 96th glyph that
+rEFInd displays for out-of-range characters. To work properly, the
+characters must be evenly spaced and the PNG image must be a multiple
+of 96 pixels wide, with divisions at appropriate points. In theory, you
+should be able to take a screen shot of a program displaying the relevant
+characters and then crop it to suit your needs. In practice, this is likely
+to be tedious.</p>
+
+<a name="known_themes">
+<h2>Known Themes</h2>
+</a>
+
+<p>In addition to this default icon set, I've received word of a few other rEFInd themes:</p>
+
+<ul>
+
+<li><a href="https://sourceforge.net/projects/refind/files/themes/">Snowy</a> is my own theme. It's built from (mostly) white variants of rEFInd's standard icons and includes a photo of a snowy field as a background image. It's shown earlier on this page.</li>
+
+<li><a href="http://ecto-plazm.deviantart.com/art/rEFInd-Icon-Theme-296571397">ecto-plazm's theme</a> was one of the first independent themes to be created for rEFInd.</li>
+
+<li><a href="http://opendesktop.org/content/show.php?content=153267">The Gris Theme</a> (also available as an <a href="https://aur.archlinux.org/packages.php?ID=61917">Arch Linux package</a>) uses a minimalistic white-on-gray design:</li>
+
+    <br /><center><a
+    href="http://opendesktop.org/content/show.php?content=153267"><img
+    src="http://opendesktop.org/CONTENT/content-pre1/153267-1.gif"
+    align="center" width="750" alt="Gris uses a minimalistic white-on-gray
+    color scheme" border=2> </a></center><br />
+
+<li><a href="http://www.turnerharris.com/themes/refind.theme.mac.zip">The Mac theme</a> was created by Wesley Turner-Harris. See <a href="http://www.turnerharris.com/my-themes/">Wesley's Web site</a> if you want to contact the creator of this theme.</li>
+
+<li>Evan Purkhiser's <a href="https://github.com/EvanPurkhiser/rEFInd-minimal-theme">Minimal theme</a> uses black icons on a gray background of varied brightness, as shown here:</li>
+
+    <br /><center><a
+    href="https://github.com/EvanPurkhiser/rEFInd-minimal"><img
+    src="https://camo.githubusercontent.com/999cff82d4bea54f222e165d647b5df597f45b86/687474703a2f2f692e696d6775722e636f6d2f33624d473655372e706e67"
+    align="center" width="750" alt="Minimal uses flat icons and a subtly-graded background" border=2> </a></center><br />
+
+<li>Sean Gibbons' <a href="http://sdbinwiiexe.deviantart.com/art/rEFInd-Next-Theme-407754566">rEFInd Next</a> theme is "inspired by both iOS 7 and Windows 8 interfaces." It includes both a background image and a number of OS icons.</li>
+
+    <br /><center><a
+    href="http://sdbinwiiexe.deviantart.com/art/rEFInd-Next-Theme-407754566"><img
+    src="http://orig15.deviantart.net/5db2/f/2013/290/b/d/refind_next_theme_by_sdbinwiiexe-d6qrlfq.png"
+    align="center" width="750" alt="rEFInd Next uses simple white icons against green artwork" border=2> </a></center><br />
+
+<li>Zhu Qunying has created a <a href="http://zhu-qy.blogspot.com/2014/02/a-slackware-banner-logo-for-refind-boot.html">Slackware-themed banner logo</a> for rEFInd. Although it's not a full theme, I thought I'd mention and show it here:</li>
+
+    <br /><center><a
+    href="http://zhu-qy.blogspot.com/2014/02/a-slackware-banner-logo-for-refind-boot.html"><img
+    src="http://1.bp.blogspot.com/-2XOoqzKg25s/Uwedh5shvdI/AAAAAAAAAfo/GJpMSXlhBv8/s400/swlogo.png"
+    align="center" alt="If you use Slackware, this banner may interest you" border=2> </a></center><br />
+
+<li>naymlezwun has created an <a href="http://naymlezwun.deviantart.com/art/rEFInd-OS-X-Theme-469807750">OS X theme</a> for rEFInd.</li>
+
+    <br /><center><a
+    href="http://naymlezwun.deviantart.com/art/rEFInd-OS-X-Theme-469807750"><img
+    src="http://pre11.deviantart.net/6da5/th/pre/f/2014/202/9/e/refind_os_x_theme_by_naymlezwun-d7rplza.png"
+    align="center" width="750" alt="the rEFInd OS X theme uses Mac-like icons" border=2> </a></center><br />
+
+<li>jamaladdeen on deviantART has created another <a href="http://jamaladdeen.deviantart.com/art/rEFInd-OSX-Standard-Theme-1-0-492876132?ga_submit_new=10%253A1415269035&ga_type=edit&ga_changes=1&ga_recent=1">OS X theme</a> that resembles the OS X environment.</li>
+
+    <br /><center><a
+    href="http://jamaladdeen.deviantart.com/art/rEFInd-OSX-Standard-Theme-1-0-492876132?ga_submit_new=10%253A1415269035&ga_type=edit&ga_changes=1&ga_recent=1"><img
+    src="http://orig06.deviantart.net/6a20/f/2014/310/3/5/refind_osx_standard_theme_1_0_by_jamaladdeen-d85g1no.png"
+    align="center" width="750" alt="Another OS X-like theme" border=2> </a></center><br />
+
+<li>Brian Lechthaler has created an <a href="http://sta.sh/0raifz8774v">alternative rEFInd banner:</a>
+
+    <br /><center><a href="http://sta.sh/0raifz8774v"><img
+    src="http://orig10.deviantart.net/2799/f/2015/013/2/c/refind_banner_by_brianlechthaler-d8dt90h.png"
+    align="center" alt="An alternative simple banner for rEFInd" border=2>
+    </a></center><br />
+
+<li>User munlik has created a theme called <a href="http://munlik.deviantart.com/art/rEFInd-boot-manager-theme-Regular-theme-512091944">Regular-theme</a> on Deviantart.</li>
+
+    <br /><center><a
+    href="http://munlik.deviantart.com/art/Regular-rEFInd-theme-512091944"><img
+    src="http://orig08.deviantart.net/44bd/f/2015/277/2/d/regular__refind__theme_by_munlik-d8gvwo8.png"
+    align="center" width="750" alt="A clean theme with a light background"
+    border=2> </a></center><br />
+
+<li>Nitrofurano has posted <a href="http://opendesktop.org/content/show.php?content=169069">a 1970s-inspired theme</a> on opendesktop.org.</li>
+
+    <br /><center><a
+    href="http://opendesktop.org/content/show.php?content=169069"><img
+    src="http://opendesktop.org/CONTENT/content-pre1/169069-1.png"
+    align="center" width="750" alt="Like disco and John Travolta? Maybe
+    this theme is for you!" border=2> </a></center><br />
+
+</ul>
+
+<p>If you've created or discovered another rEFInd theme, please <a href="mailto:rodsmith@rodsbooks.com">tell me about it</a> so that I can provide a link to it from this page.</p>
+
+<hr />
+
+<p>copyright &copy; 2012&ndash;2015 by Roderick W. Smith</p>
+
+<p>This document is licensed under the terms of the <a href="FDL-1.3.txt">GNU Free Documentation License (FDL), version 1.3.</a></p>
+
+<p>If you have problems with or comments about this Web page, please e-mail me at <a href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.com.</a> Thanks.</p>
+
+<p><a href="index.html">Go to the main rEFInd page</a></p>
+
+<p><a href="linux.html">Learn about methods of booting Linux with rEFInd</a></p>
+
+  <p><a href="http://www.rodsbooks.com/">Return</a> to my main Web page.</p>
+</body>
+</html>
diff --git a/docs/refind/todo.html b/docs/refind/todo.html
new file mode 100644 (file)
index 0000000..e8e2dd8
--- /dev/null
@@ -0,0 +1,445 @@
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>The rEFInd Boot Manager: The Future of rEFInd</title>
+  <link href="../Styles/styles.css" rel="stylesheet" type="text/css" />
+</head>
+
+<meta name="viewport" content="width=device-width, initial-scale=1">
+
+<body>
+  <h1>The rEFInd Boot Manager:<br />The Future of rEFInd</h1>
+
+  <p class="subhead">by Roderick W. Smith, <a
+href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.com</a></p>
+
+<p>Originally written: 3/14/2012; last Web page update:
+11/8/2015, referencing rEFInd 0.10.0</p>
+
+
+<p>This Web page is provided free of charge and with no annoying outside ads; however, I did take time to prepare it, and Web hosting does cost money. If you find this Web page useful, please consider making a small donation to help keep this site up and running. Thanks!</p>
+
+<table border="1">
+<tr>
+<td>Donate $1.00</td>
+<td>Donate $2.50</td>
+<td>Donate $5.00</td>
+<td>Donate $10.00</td>
+<td>Donate $20.00</td>
+<td>Donate another value</td>
+</tr>
+<tr>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="1.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="2.50">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="5.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="10.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="20.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td></tr>
+</table>
+
+<hr />
+
+<p>This page is part of the documentation for the rEFInd boot manager. If a Web search has brought you here, you may want to start at the <a href="index.html">main page.</a></p>
+
+<hr />
+
+<p>rEFInd is far from perfect. It's based on rEFIt, which has a <a href="https://sourceforge.net/tracker/?group_id=161917&atid=821764">list of active bugs</a> on its project page on Sourceforge. I have not studied this bug list in detail for rEFInd's first release, although I've probably fixed a few of those bugs because I encountered them myself. Other bugs I may never fix because I lack the necessary hardware for testing.</p>
+
+<p>This page exists to document some of rEFInd's known bugs and limitations, as well as features I hope to add in the future. Some of the items on this list are things that you may be able to help with, so if you'd like to contribute, feel free to drop me a line!</p>
+
+<p>The following list groups things that need to be done into broad categories. In some cases, there's some ambiguity about how an item might best be classified. Without further ado, then:</p>
+
+<ul>
+
+<li><b>Tasks with which non-programmers can help:</b>
+
+    <ul>
+
+    <li>Testing! rEFIt was complex enough that changes such as the ones
+       I've made have the potential to disrupt the program's operation in
+       unexpected ways. Since the initial 0.2.0 release, I've continued to
+       add features to rEFInd, and every new feature is another way for
+       bugs to get into the program. I can only test on a handful of
+       systems with a limited number of configurations. Therefore, if you
+       try rEFInd and run into bugs, please report them to me!</li>
+
+    <li>rEFIt's original design, and hence rEFInd's design, enables easy
+       theming by replacing icon files. If you'd like to design a new
+       theme for rEFInd, feel free to submit it. I might or might not
+       replace the icons it uses now (most of which come from the Oxygen
+       Icons package), but I may provide links to themes on this Web site
+       (or even host them on the project's Sourceforge page). For more
+       information on designing themes for rEFInd, see the <a
+       href="themes.html">Theming rEFInd</a> page.</li>
+
+    </ul></li> <!-- Non-programmer help -->
+
+<li><b>Improvements to existing features:</b>
+
+    <ul>
+
+    <li>As described in reference to version 0.9.2 on the <a
+       href="revisions.html">Revisions</a> page, rEFInd includes a
+       delicate and hackish workaround to a problem introduced by Shim
+       0.8. Developing a better solution to that problem is a high
+       priority.</li>
+
+    <li>The support for booting legacy (BIOS) OSes on UEFI-based PCs
+       currently has a number of limitations. Most importantly, it works
+       off of the list of boot devices stored in the computer's NVRAM. I'd
+       prefer to have it scan disks and partitions, as the Mac's legacy
+       boot support does. Also, the UEFI legacy boot code presents empty
+       optical drives and uses generic icons rather than OS-specific
+       icons.</li>
+
+    <li>rEFInd's <tt>Makefile</tt>s and, to a lesser extent, C code,
+       support <i>x</i>86, <i>x</i>86-64, and ARM64 CPUs. EFI is also
+       available for Itanium (IA-64) and ARM32 CPUs, so I'd like to add
+       this support.</li>
+
+    <li>Currently, rEFInd can detect whether it's compiled for <i>x</i>86,
+       <i>x</i>86-64, or ARM64 systems and displays this information in
+       its "About" screen (<tt>AboutrEFInd()</tt> in <tt>main.c</tt>). I'd
+       like to add detection for Itanium and 32-bit ARM systems, but I
+       have no way to test such changes.</li>
+
+    <li>Further to the preceding, rEFInd's GPT-scanning code (used to
+       extract partition names) includes assumptions about byte order, and
+       so will work only on little-endian CPUs such as the x86 and
+       x86-64.</li>
+
+    <li>A way to set the color of the font would be useful for theming
+        purposes.</li>
+
+    <li>The program's font features could be greatly improved by enabling
+       use of a standard font format, by enabling use of non-ASCII
+       characters, and by enabling use of variable-width as well as
+       monospace fonts.</li>
+
+    <li>The <tt>default_selection</tt> might be expanded to support some
+       form of specification of disk types, as in a special entry for any
+       optical disk or any external disk, no matter what its name is.</li>
+
+    <li>It would be useful to be able to specify paths to boot loaders
+       and/or initial RAM disks relative to the rEFInd directory (or the
+       boot loader's directory, in the case of initrds).</li>
+
+    <li>Currently the background for certain subscreens (such as the
+       information page or submenu listings) is a solid color based on the
+       upper-left corner of the screen. Having an option to support a
+       transparent background is desirable to some users.</li>
+
+    <li>When delivering rEFInd as a boot loader from a network server,
+       rEFInd is limited to its default options and can boot only local
+       OSes, not network OSes. The cause is that the server delivers a
+       single file, so rEFInd is divorced from its configuration and
+       support files.</li>
+
+    <li>A way to identify specific Windows versions and present unique
+       icons or change the text is desirable. Currently, a crude
+       distinction of XP and earlier vs. Vista and later is possible for
+       BIOS-booting on Macs, but no such distinction is made for EFI-mode
+       booting, and nothing finer-grained is attempted. Improvements will
+       probably require identifying unique features of each version's boot
+       loader files or boot sector code.</li>
+
+</ul></li> <!-- Improvements -->
+
+<li><b>Known bugs that need squashing:</b>
+
+    <ul>
+
+    <li>I've been receiving reports of blank screens when using rEFInd on
+       some recent Mac models. I've investigated this with the help of one
+       user, and I suspect that Apple has made changes to its firmware
+       that are likely to affect just about any EFI program. I don't have
+       a definitive solution, but at least one user has reported that
+       removing rEFInd's drivers has caused the problem to go into
+       remission.</li>
+
+    <li>Some EFIs have bugs that cause the allegedly case-insensitive
+       <tt>StriCmp()</tt> function to perform a case-sensitive comparison.
+       This causes any number of bugs in file matching. For instance:
+       Changing the case of icon filename extensions (or various other
+       parts of icon filenames) causes icons to be replaced by ugly
+       "generic" ones; and rEFInd sometimes appears in its own menu (the
+       firmware sometimes returns an all-caps version of the filename, but
+       other times returns the filename with the correct case, causing a
+       mismatch if the path includes lowercase elements). This problem is
+       worse when compiling rEFInd with GNU-EFI than with Tianocore.
+       Version 0.9.1 has made improvements on this score, but some issues
+       may continue to lurk.</li>
+
+    <li>The Shutdown option works correctly on Macs, but not on many UEFI-based
+       PCs. On such systems, Shutdown reboots the computer. This should be
+       fixed.</li>
+
+    <li>The media-ejection feature (F12) should be extended to work on
+       UEFI-based PCs and early Macs. At the moment, it relies on an
+       Apple-specific EFI extension, and I know of no standard EFI way to
+       do it.</li>
+
+    <li>A couple of Mac users have reported that the brightness-adjustment
+       features in Windows don't work when Windows is booted via rEFInd,
+       but that these features do work when Windows is booted via the
+       Mac's built-in boot manager. Unfortunately, I have no idea what
+       causes this problem, I have no Windows installation on my one
+       (elderly) Mac, and I have no way to debug it. Therefore, it's
+       unlikely that I'll be able to fix this problem myself; but if you
+       have the equipment and skill to do so, I'd be interested in
+       receiving a patch.</li>
+
+    <li>If you use a true MBR disk on a Mac to boot Windows or some other
+       BIOS-only OS, and if that disk has an extended partition, bogus
+       additional BIOS/legacy-bootable options may appear in the rEFInd
+       menu. The reason appears to be a bug in the handling of
+       extended/logical partitions in the <tt>refind/lib.c</tt> file, but
+       I haven't fully tracked it down.</li>
+
+    <li>The re-scan feature occasionally produces odd results, such as
+       ignoring new media or keeping old media that have been ejected.
+       This should be investigated and fixed.</li>
+
+    <li>The "scanning for new boot loaders" message that appears during the
+       re-scan feature is primitive. Some sort of dynamic icon would be
+       nice, but perhaps impractical, given the single-tasking nature of
+       EFI.</li>
+
+    <li>On my Mac Mini, launching a shell, returning, and performing a
+       re-scan causes the system to be unable to launch the shell again. I
+       have not observed this behavior on UEFI-based PCs. It seems to be
+       caused by a truncated DevicePath to the shell, which includes the
+       shell's pathname but not the device identifier.</li>
+
+    <li>When specifying a volume by name in <tt>dont_scan_dirs</tt>,
+       slashes are converted to backslashes in the specification but not
+       in the actual volume name read from disk. Thus, you can't specify a
+       volume by name if it includes a slash (as in <tt>Fedora
+       /boot</tt>). Workarounds are to rename the volume to omit the slash
+       and to use a filesystem number rather than a volume label.</li>
+
+    <li>The code is in need of review to search for memory leaks and
+       similar problems.</li>
+
+    <li>If the user has a Linux software RAID 1 array with Btrfs, HFS+,
+        or FAT filesystem, rEFInd will detect kernels or boot loaders in
+       RAID 1 twice. Checks to prevent this with ext2/3/4fs and ReiserFS
+       already exist; these checks could be expanded to block such
+       duplication with more filesystems.</li>
+
+    <li>Some Macs experience problems with waking up from suspend states
+       when rEFInd is installed. Unfortunately, I lack the hardware to
+       test and experiment with this (my only Intel-based Mac doesn't
+       exhibit this problem), so I can't fix this myself. <a
+       href="apple.stackexchange.com/questions/91139/why-does-my-mbp-sleep-on-mountain-lion-and-often-not-wake-up/91150#91150">Using
+       <tt>pmset</tt> to disable the <tt>autopoweroff</tt> option</a> is
+       <a
+       href="http://apple.stackexchange.com/questions/91529/macbook-air-not-waking-up-from-suspend-sleep-with-refind-boot-manager-installed">claimed
+       by some</a> to at least partially fix the problem, though. Using
+       the <tt>--ownhfs</tt> installation option may also help in some
+       cases.</li>
+
+    <li>If you activate BIOS-mode support on UEFI-based PCs, you may find
+       multiple copies of the BIOS-mode loaders added to your firmware's
+       boot manager. Only one copy shows up in rEFInd, though.</li>
+
+    </ul></li> <!-- Known bugs -->
+
+<li><b>New features I'd like to add:</b>
+
+    <ul>
+
+    <li>There's currently no way to create a manual boot stanza for a
+       BIOS-booted OS. This isn't a big priority for me personally, but I
+       can see how it could be for some people.</li>
+
+    <li>I'd like to find a way to enable users to enter customizations for
+       boot options and then save them to the <tt>refind.conf</tt> file.
+       One possible way to implement this would be to have manual boot
+       stanzas override auto-detected boot loader definitions for the same
+       boot loader file.</li>
+
+    <li>Along similar lines, some users have asked for a way to take
+       detected boot programs and create a set of manual boot stanzas for
+       them, so that they can be modified manually.</li>
+
+    <li>Support for touchscreens and/or configurable buttons for rEFInd's
+       actions would enable use of rEFInd on tablet computers that lack
+       complete keyboards.</li>
+
+    <li>The ability to rotate the display for users who rotate their
+       monitors or who use tablets would be helpful.</li>
+
+    <li>GRUB provides a configuration-file command called <tt>outb</tt>
+       that enables manipulating hardware registers. Something similar,
+       via the <tt>mm</tt> command, can be done in the EFI shell. I'd like
+       to add such a feature to rEFInd, since it enables doing things like
+       disabling one or another video output on Macs with two video
+       cards.</li>
+
+    <li>I have thoughts about creating an EFI configuration tool and
+       information utility&mdash;something to tell you about your hard
+       disks, enable you to manage MOKs, adjust boot loader priority in
+       the NVRAM, and so on. This would be useful in system maintenance
+       and in recovering from boot problems.</li>
+
+    <li>An installation tool for the EFI environment would be useful.
+        A simple EFI shell script might work, but because this function
+       requires access to the <tt>bcfg</tt> command, this would work
+       only from a version 2 shell or if <tt>bcfg</tt> were implemented
+       as a standalone program. Another alternative would be a program
+       written in C.</li>
+
+    <li>It should be possible to override specific auto-detected boot
+       loader settings&mdash;say, to disable one specific boot loader or
+       change its icon.</li>
+
+    <li>A GUI configuration tool for host OSes (Linux, OS X, Windows, etc.)
+       would be nice, but it's low on my personal priority list. If you'd
+       like to contribute, I prefer something written in a cross-platform
+       GUI toolkit, so that a single code base can be used on any of the
+       major OSes.</li>
+
+    </ul></li> <!-- New features -->
+
+<li><b>Improvements to the EFI drivers:</b>
+
+    <ul>
+
+    <li>Drivers for additional filesystems are desirable. Only XFS and JFS
+       are missing from the major Linux filesystems. UDF would also be a
+       welcome addition, as might drivers for other OSes (say, for the
+       BSDs, especially if BSD developers create a boot loader similar to
+       Linux's EFI stub loader). Also along these lines, adding drivers
+       for Linux LVM and RAID setups would be useful.</li>
+
+    <li>This may not be possible, or it may require a new driver, but a way
+       to have the drivers access files (like a Linux loopback mount) is
+       desirable.</li>
+
+    <li>When built with the GNU-EFI package, an attempt to load more than
+        one driver on my 32-bit Mac Mini causes the computer to hang. I do
+       <i>not</i> have this problem with 64-bit drivers on my UEFI-based
+       computers. I don't know if this is a 32-bit issue or a Mac issue.
+       This is <i>not</i> relevant if you're using my binary package,
+       since I build it with the TianoCore EDK2, and the drivers built in
+       that way don't exhibit this bug.</li>
+
+    </ul></li> <!-- Drivers -->
+
+<li><b>Improvements to <tt>gptsync</tt>, <tt>refind-install</tt>, or other
+    support tools:</b>
+
+    <ul>
+
+    <li>The <tt>gptsync</tt> program can return misleading error codes
+       under some circumstances, such as when it makes no changes to the
+       partition table. Fix this.</li>
+
+    <li>rEFInd's support for network booting is primitive and relies on the
+       external iPXE package. In my own testing, iPXE retrieves the
+       BIOS-mode boot loader from some servers that offer both, which
+       makes it useless on those networks.</li>
+
+    <li>A Mac-specific package is highly desirable.</li>
+
+    </ul></li>
+
+</ul>
+
+<hr />
+
+<p>copyright &copy; 2012&ndash;2015 by Roderick W. Smith</p>
+
+<p>This document is licensed under the terms of the <a href="FDL-1.3.txt">GNU Free Documentation License (FDL), version 1.3.</a></p>
+
+<p>If you have problems with or comments about this Web page, please e-mail me at <a href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.com.</a> Thanks.</p>
+
+<p><a href="index.html">Go to the main rEFInd page</a></p>
+
+<p><a href="using.html">Learn about problems with and the future of rEFInd</a></p>
+
+  <p><a href="http://www.rodsbooks.com/">Return</a> to my main Web page.</p>
+</body>
+</html>
diff --git a/docs/refind/using.html b/docs/refind/using.html
new file mode 100644 (file)
index 0000000..dc4a5f0
--- /dev/null
@@ -0,0 +1,399 @@
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>The rEFInd Boot Manager: Using rEFInd</title>
+  <link href="../Styles/styles.css" rel="stylesheet" type="text/css" />
+</head>
+
+<meta name="viewport" content="width=device-width, initial-scale=1">
+
+<body>
+  <h1>The rEFInd Boot Manager:<br />Using rEFInd</h1>
+
+  <p class="subhead">by Roderick W. Smith, <a
+href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.com</a></p>
+
+<p>Originally written: 3/14/2012; last Web page update:
+11/8/2015, referencing rEFInd 0.10.0</p>
+
+
+<p>This Web page is provided free of charge and with no annoying outside ads; however, I did take time to prepare it, and Web hosting does cost money. If you find this Web page useful, please consider making a small donation to help keep this site up and running. Thanks!</p>
+
+<table border="1">
+<tr>
+<td>Donate $1.00</td>
+<td>Donate $2.50</td>
+<td>Donate $5.00</td>
+<td>Donate $10.00</td>
+<td>Donate $20.00</td>
+<td>Donate another value</td>
+</tr>
+<tr>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="1.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="2.50">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="5.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="10.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="20.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td></tr>
+</table>
+
+<hr />
+
+<p>This page is part of the documentation for the rEFInd boot manager. If a Web search has brought you here, you may want to start at the <a href="index.html">main page.</a></p>
+
+<hr />
+
+<div style="float:right; width:55%">
+
+<p>For the most part, rEFInd is easy to use; just use your keyboard's arrow keys to select the OS you want to boot or the utility you want to launch and press the Enter key. A few details aren't entirely intuitive, though, so this page describes them.</p>
+
+</div>
+
+<div class="navbar">
+
+<h4 class="tight">Contents</h4>
+
+<ul>
+
+<li class="tight"><a href="#basic">Using Basic rEFInd Features</a></li>
+
+<li class="tight"><a href="#boot_options">Adjusting Boot Options</a></li>
+
+<li class="tight"><a href="#keyboard">Using Keyboard Shortcuts</a></li>
+
+<li class="tight"><a href="#legacy">Booting Legacy OSes</a></li>
+
+<li class="tight"><a href="#delays">Reducing Startup Delays</a></li>
+
+</ul>
+
+</div>
+
+<a name="basic">
+<h2>Using Basic rEFInd Features</h2>
+</a>
+
+<p>With rEFInd in place and added to your firmware's list of boot utilities, you can reboot your computer. Depending on your configuration, rEFInd may come up immediately or you may need to select it from your firmware's boot options or reconfigure your firmware to present rEFInd automatically. Unfortunately, I can't offer much specific advice on this score, since EFI implementations differ so much in their user interfaces.</p>
+
+<p>Assuming rEFInd starts up correctly, you should see its main screen, which resembles the following:</p>
+
+    <br /><center><img src="refind.png" align="center" width="750"
+    height="558" alt="rEFInd presents a GUI menu for selecting your boot
+    OS." border=2 /></center> <br />
+
+<p>If you don't press a key before the timeout expires, the default boot loader will launch. (The timeout is shown beneath the description line until you press a key.) This is normally the item that you launched the last time rEFInd ran, but you can adjust the default by editing the configuration file. (In this example, it's the Ubuntu Linux loader, which is further identified by text as <i>EFI\ubuntu\grubx64.efi from ESP</i>.)</p>
+
+<p>This display is dominated by the central set of OS <i>tags</i> (icons), which in this example includes tags for an unknown Linux distribution, Ubuntu, OS X, and Windows. All but the first of these are on hard disks, but the unknown Linux boot loader is on an optical disc, as revealed by the small icons (known as <i>badges</i>) in the lower-right corner of the OS icons.</p>
+
+<p>In this example, the Ubuntu tag is selected. You can move the selection left by pressing the left arrow key and right by pressing the right arrow key. If your system has many boot loaders, an arrow icon will appear to the right and/or left of the boot loader list, indicating that the boot loader list will scroll when you move off the edge. (Such an arrow is visible to the right in the sample screen.) You can scroll the list by one line full of icons by using the Page Up or Page Down keys to move left and right, respectively. Moving past the final selection or using the down arrow key moves the selection to the second row of small tags, which launch ancillary programs or perform special actions. If you've moved the selection cursor to the second row, pressing the up arrow key or scrolling past the left edge of the second row moves the cursor to the top row. In this figure, these eight tags are present:</p>
+
+<ul>
+
+<li>Launch the EFI shell</li>
+
+<li>Launch the tool to partition a disk (<tt>gptsync</tt> or
+    <tt>gdisk</tt>)</li>
+
+<li>Launch a memory-testing utility</li>
+
+<li>Launch a tool to edit Secure Boot keys (<tt>MokManager</tt>,
+    <tt>HashTool</tt>, or <tt>KeyTool</tt>)
+
+<li>Launch a Windows recovery utility</li>
+
+<li>Produce an information page</li>
+
+<li>Reboot the computer</li>
+
+<li>Exit from rEFInd</li>
+
+</ul>
+
+<p>By default, the options to display an information page, shutdown the computer, and reboot the computer are present. Options to launch a shell, launch <tt>gdisk</tt>, launch a memory test utility, launch the Apple recovery utility, launch the Windows recovery utility, and launch a Secure Boot key management utility will also appear automatically if these utilities are installed. A tag to reboot into the firmware appears if your firmware supports this feature. Options to launch the hybrid MBR tool (<tt>gptsync</tt>) and to exit from rEFInd are not displayed by default; you must edit the configuration file to enable these features, or to disable those that are displayed by default if you don't want them.</p>
+
+<p>To launch an OS or utility, you should select its tag and then press the Enter key or the space bar.</p>
+
+<p class="sidebar"><b>Note:</b>On UEFI-based PCs, rEFInd defaults to scanning for EFI, but <i>not</i> for BIOS, boot loaders. If you want to launch BIOS-mode OSes from rEFInd, you must edit the <tt>scanfor</tt> line in <tt>refind.conf</tt>, as described on the <a href="configfile.html">Configuring the Boot Manager</a> page. On Macs, rEFInd scans for BIOS-based OSes by default, since such configurations are a common way to launch Windows on Macs.</p>
+
+<p>Ordinarily, rEFInd displays tags for OSes it finds on internal hard disks, external hard disks (including USB flash drives, CF disks, and so on), and optical discs. Sometimes, though, the firmware hasn't had time to fully examine these devices by the time rEFInd starts; or you might only insert or plug in the media after rEFInd appears. In these cases, you can press the Esc key to have rEFInd re-read its configuration file and re-scan your media for boot loaders. This action can take a few seconds to complete, so be patient. You can also use this feature to detect OSes if you launch a shell and use it to load a driver or edit the <tt>refind.conf</tt> file. If you regularly need to press Esc, you might look into the <tt>scan_delay</tt> configuration file option, described on the <a href="configfile.html">Configuring the Boot Manager</a> page.</p>
+
+<p>On some computers, the firmware doesn't mount external USB media unless you adjust a firmware option or use the EFI's own boot manager prior to launching rEFInd. If you don't see external media appear in rEFInd's list, consult your computer's manual or examine its firmware to locate a relevant option. This option is often called <i>fast boot</i> or something similar; when enabled, the computer doesn't activate most USB devices because doing so takes a second or two.</p>
+
+<a name="boot_options">
+<h2>Adjusting Boot Options</h2>
+</a>
+
+<p>If you press the Insert, F2, or + key, rEFInd will show a menu that may hold additional options, depending on the OS type. (OS X and Linux are most likely to hold interesting options on their submenus.) The following figure shows the submenu for Mac OS X. You can use this menu much like the main menu; move the cursor to select the option you want to use, then press the Enter key to launch the boot loader with the selected options. Press the Esc key or select <tt>Return to Main Menu</tt> to return to the main menu. (See the <a href="linux.html">Methods of Booting Linux</a> page for information on what you might see on a Linux submenu page.)</p>
+
+    <br /><center><img src="submenu.png" align="center" width="499"
+    height="228" alt="rEFInd submenus enable you to set session-specific
+    options." border=2></center> <br />
+
+<p>From the options submenu, you can press the Insert, F2, or + key again to edit your boot loader options. You're most likely to want to do this when booting Linux via its EFI stub loader, since you can then enter arbitrary kernel options. A simple text-mode line editor opens (shown below), enabling you to move a cursor back and forth in the line with your arrow keys, delete text, and type in new text. If you want to boot with your edited options, press the Enter key. If you decide you picked the wrong entry, press the Esc key. Note that long option lists, as shown in the figure, scroll off the edge of the screen. Moving the cursor past the screen edge scrolls the entire line of text.</p>
+
+    <br /><center><img src="editor.png" align="center" width="646"
+    height="486" alt="You can edit options passed to the boot loader on a
+    single-boot basis." border=2></center> <br />
+
+<p>If your computer supports Secure Boot, you may find that some of your OSes and tools won't work; they'll produce <tt>Secure Boot validation failure</tt> error messages. You can overcome this problem by creating a signing key, signing your binaries with it, and adding the public version of that key to your machine owner key (MOK) list. This process is described on the <a href="secureboot.html">Managing Secure Boot</a> page.</p>
+
+<a name="keyboard">
+<h2>Using Keyboard Shortcuts</h2>
+</a>
+
+<p>Although most rEFInd features can be activated via fairly obvious keyboard actions, some are not obvious. <a href="#table1">Table 1</a> summarizes the keystrokes that rEFInd accepts, and the action that each keystroke invokes.</p>
+
+<table border="1" cellpadding="1" cellspacing="2" summary="Table 1: rEFInd Keyboard Shortcuts"><a name="table1"><caption><b>Table 1: rEFInd Keyboard Shortcuts</b></caption></a>
+<tr>
+   <th>Keystroke</th>
+   <th>Explanation</th>
+</tr>
+<tr>
+   <td><i>left arrow</i></td>
+   <td>Moves the selection one icon to the left (or up the list in text mode)</td>
+</tr>
+<tr>
+   <td><i>right arrow</i></td>
+   <td>Moves the selection one icon to the right (or down the list in text mode)</td>
+</tr>
+<tr>
+   <td><i>up arrow</i></td>
+   <td>Moves the selection from the utilities row to the OS row (in text mode, moves up one entry)</td>
+</tr>
+<tr>
+   <td><i>down arrow</i></td>
+   <td>Moves the selection from the OS row to the utilities row (in text mode, moves down one entry)</td>
+</tr>
+<tr>
+   <td><i>Page Up</i></td>
+   <td>Scrolls the visible set of tags to the left (or up in text mode)</td>
+</tr>
+<tr>
+   <td><i>Page Down</i></td>
+   <td>Scrolls the visible set of tags to the right (or down in text mode)</td>
+</tr>
+<tr>
+   <td><i>Home</i></td>
+   <td>Moves the selection to the first item on the OS row</td>
+</tr>
+<tr>
+   <td><i>End</i></td>
+   <td>Moves the selection to the last item on the utilities row</td>
+</tr>
+<tr>
+   <td><i>Esc</i></td>
+   <td>Returns from a sub-menu; on the main screen, re-reads the configuration file and re-scans for boot loaders</td>
+</tr>
+<tr>
+   <td><i>Insert</i>, <i>F2</i>, or <i>+</i></td>
+   <td>From the main menu, opens the selection's submenu, which is most useful with Mac OS X, ELILO, and Linux kernels with EFI stub loader support; in a submenu, opens a line editor enabling editing of boot options</td>
+</tr>
+<tr>
+   <td><i>F10</i></td>
+   <td>Saves an image of the current screen in the file <tt>screenshot_<tt class="variable">###</tt>.bmp</tt>, where <tt class="variable">###</tt> is a sequence number starting with <tt>001</tt>, in the EFI System Partition's (ESP's) root directory</td>
+</tr>
+<tr>
+   <td><i>F12</i> or (on some keyboards) <i>Eject</i></td>
+   <td>Ejects removable media. This feature only works on some Macs, not on UEFI-based PCs.</td>
+</tr>
+<tr>
+   <td><i>Enter</i> or <i>spacebar</i></td>
+   <td>Launches the currently-selected OS, utility, or built-in feature</td>
+</tr>
+<tr>
+   <td><i>1</i> through <i>9</i></td>
+   <td>Launches the specified boot loader by number</td>
+</tr>
+<tr>
+   <td><i>A</i></td>
+   <td>Displays the "About rEFInd" information</td>
+</tr>
+<tr>
+   <td><i>E</i></td>
+   <td>Launches the first instance of ELILO in the boot list</td>
+</tr>
+<tr>
+   <td><i>G</i></td>
+   <td>Launches the first instance of GRUB in the boot list</td>
+</tr>
+<tr>
+   <td><i>L</i></td>
+   <td>Launches the first Linux kernel in the boot list</td>
+</tr>
+<tr>
+   <td><i>M</i></td>
+   <td>Launches the first Mac OS boot loader in the boot list</td>
+</tr>
+<tr>
+   <td><i>P</i></td>
+   <td>Launches <tt>gptsync</tt></td>
+</tr>
+<tr>
+   <td><i>S</i></td>
+   <td>Launches an EFI shell, if available</td>
+</tr>
+<tr>
+   <td><i>U</i></td>
+   <td>Shuts down the computer (but note that this is buggy and reboots most UEFI-based PCs)</td>
+</tr>
+<tr>
+   <td><i>W</i></td>
+   <td>Launches the first Windows boot loader</td>
+</tr>
+<tr>
+   <td>Other letters</td>
+   <td>Launch OSes whose names begin with those letters, as described below</td>
+</tr>
+</table>
+
+<p class="sidebar"><b>Note:</b> If you set <tt>timeout = -1</tt> in <tt>refind.conf</tt>, rEFInd will immediately launch the default OS <i>unless</i> you press a key as rEFInd launches. In that case, if the key you pressed is a valid shortcut key, rEFInd will launch the associated entry. If not, rEFInd will show you its main menu.</p>
+
+<p>rEFInd assigns shortcut letters to most OS entries based on the first letter of the directory in which the OS's boot loader is stored. For instance, if you have a boot loader called <tt>/EFI/debian/elilo.efi</tt>, rEFInd attempts to assign it a shortcut letter of <i>D</i>. rEFInd overrides this default for Mac OS X, Windows, and for Linux's GRUB, ELILO, and EFI stub boot loaders if the distribution can't be more precisely identified, as noted in the preceding table. This method works well for many installations, but it can produce conflicts. For instance, if you have a Macintosh that holds both Mac OS X and Mandriva, both OSes would normally use the <tt>M</tt> shortcut key. In practice, which works depends on the order in which rEFInd detects the OSes.</p>
+
+<a name="legacy">
+<h2>Booting Legacy OSes</h2>
+</a>
+
+<p>Sometimes it's necessary to boot a legacy (BIOS-based) OS on an EFI computer. This is especially true on Macs, since this has been the usual method of dual-booting OS X and Windows. (Since the release of Windows 8, though, booting Windows in EFI mode on Macs has become both more practical and more common.) In the past, many Linux distributions installed more easily in BIOS mode on Macs, but many Linux distributions now favor native EFI-mode installation on Macs. (See my <a href="http://www.rodsbooks.com/ubuntu-efi/">EFI-Booting Ubuntu on a Mac</a> page for an in-depth look at this topic.)</p>
+
+<p>On UEFI-based PCs, booting some OSes in EFI mode and others in BIOS mode is less often necessary, since it's usually easy to install all your OSes in BIOS mode. If you have a working EFI-mode OS installation, though, and if you want to install an OS that lacks EFI-mode boot support, you may need to boot in both modes. Most of the BSDs (FreeBSD being a notable exception), Haiku, DOS, Windows XP and earlier, and many more obscure OSes still lack EFI support and so must be booted in BIOS mode. You might also want to boot a BIOS-mode emergency recovery CD, such as <a href="http://partedmagic.com">Parted Magic</a> or <a href="http://www.sysresccd.org">System Rescue CD.</a> Note, however, that EFI-mode support is being added to OSes. It's possible that some of those I've mentioned here will support EFI-mode booting by the time you read this!</p>
+
+<p>To help out when you need to boot in BIOS mode, rEFInd supports booting legacy OSes; however, the details vary between Macs and UEFI PCs. Also, be aware that some UEFI PCs lack the Compatibility Support Module (CSM) that's required for this feature to work. This is true even of some computers that can boot BIOS-based OSes natively. This can happen because the firmware is basically a BIOS with a UEFI implementation tacked on top of it; such systems rely on the native BIOS to boot, and may not provide a way for EFI applications to access the BIOS features via CSM mechanisms. If you have such a computer and if you enable a legacy boot option in the configuration file, rEFInd notifies you of its inability to present legacy boot options when it starts up.</p>
+
+<p>The <tt>scanfor</tt> option, described on the <a href="configfile.html">Configuring the Boot Manager</a> page, controls rEFInd's detection of legacy OSes. On Macs, the default is to scan for such OSes, since a common boot scenario on Macs is dual-booting OS X and Windows, and of course BIOS support is required for this. On UEFI PCs, rEFInd defaults to <i>not</i> scanning for legacy OSes; thus, you must edit the <tt>scanfor</tt> item in the configuration file if you want to boot a legacy OS on a UEFI PC.</p>
+
+    <img src="os_legacy.png" align="right" width="128" height="128"
+    alt="The legacy OS icon is identical for all OSes on UEFI-based PCs."
+    border=2 background="gray"/>
+
+<p>On Macs, rEFInd uses a flexible scanning algorithm inherited from rEFIt. This procedure detects most legacy OSes on most disks, although it can sometimes miss an OS. This scanning algorithm can often identify the legacy OS you've installed and present a suitable icon. On UEFI PCs, rEFInd relies on the computer's NVRAM settings to determine which legacy boot loaders to scan, but rEFInd does tell the firmware to find every BIOS-mode boot option and add it to its NVRAM list. On most UEFI PCs, at least one hard disk and your optical drive appear as options. On one computer I tested (a Lenovo laptop), the internal hard disk appears in the rEFInd menu as a removable disk. If you have multiple hard disks, you may need to uncomment the <tt>uefi_deep_legacy_scan</tt> option to get entries for booting all of your disks. If you opt to scan for BIOS-mode optical disks (<tt>scanfor cd</tt>) on UEFI-based PCs, an icon will appear whether or not your drive holds a CD. The UEFI scanning procedure is also incapable of detecting the OS type, so you'll see a generic legacy OS icon, as shown at the right.</p>
+
+<p>On both PCs and Macs, if you see non-functional legacy boot options, you can remove them by using the <tt>dont_scan_volumes</tt> token in <tt>refind.conf</tt>: Add any substring from the description that appears when you highlight the non-functional option to the set of options to have rEFInd ignore that entry. (Note that you must provide a complete volume name when excluding EFI volumes from scanning. The legacy-mode exclusion operation is more flexible in this regard.)</p>
+
+<a name="delays">
+<h2>Reducing Startup Delays</h2>
+</a>
+
+<p>You may discover that rEFInd takes a while to appear on the screen compared to other boot managers and boot loaders. Ultimately, the reason is that rEFInd is doing more&mdash;it's reading more filesystems, scanning for bootable files, and so on. In most cases, rEFInd takes just a second or two longer than other boot loaders, but I've heard of (and seen) much longer delays on computers that are configured sub-optimally. Some things you can do to reduce these delays include:</p>
+
+<ul>
+
+<li><b>Remove unnecessary drivers</b>&mdash;Simply loading a driver takes a certain amount of time, and if a filesystem driver finds a filesystem to read, rEFInd will spend time scanning that filesystem for bootable files. If there are no such files, or if you're not using them, then this is wasted time. Thus, you should check the <tt>drivers</tt>, <tt>drivers_x64</tt>, or other architecture-specific drivers subdirectory to be sure it doesn't hold unnecessary drivers.</li>
+
+<li><b>Use FAT for <tt>/boot</tt></b>&mdash;This tip is a corollary of the preceding one. If you use rEFInd to boot the Linux kernel directly, and if you rely on a driver to read the Linux kernel, then you'll have to live with the time to load the driver and to scan at least one extra filesystem. If you mount your ESP at <tt>/boot</tt>, or even if you create a separate FAT <tt>/boot</tt> partition, you'll save a little time. Note, however, that most Linux distributions don't allow you to install to a system with a FAT <tt>/boot</tt> partition, so you may need to set this up after doing your initial installation. If you see symbolic links in <tt>/boot</tt>, be wary; your distribution may rely upon them, and because FAT doesn't support symbolic links, this action may cause problems when upgrading kernels. On Macs, you can use HFS+ for this purpose, since Apple's EFI implementation includes an HFS+ driver.</li>
+
+<li><b>Minimize the number of scanned filesystems</b>&mdash;There's overhead associated with every additional filesystem rEFInd scans. Thus, if you have, say, separate ext4fs root (<tt>/</tt>), <tt>/boot</tt>, <tt>/usr</tt>, <tt>/home</tt>, and <tt>/var</tt> filesystems, and if you install rEFInd's ext4fs driver, rEFInd will end up scanning at least six filesystems (counting the FAT ESP), although only one of those has Linux kernels. You can use FAT for <tt>/boot</tt> and remove the ext4fs driver to speed up the boot process, as just described; but if you prefer to avoid the downsides of that action, you can switch <tt>/boot</tt> to some other filesystem, such as ext2fs or ReiserFS. This plan will reduce the number of filesystems to be scanned and improve boot time. Alternatively, if you re-install Linux, you can reduce the number of partitions or use LVM (which rEFInd can't read) for all of your filesystems except for <tt>/boot</tt>.</li>
+
+<li><b>Use a speedier filesystem</b>&mdash;In my tests, rEFInd's ReiserFS driver is the fastest and ext2fs is the slowest, with Btrfs and ext4fs falling in-between these two. The difference is trivial on some computers but it's noticeable on others. Filesystem speed differences are more likely to be noticeable in the time it takes to boot the OS; rEFInd's own startup time is less likely to be affected by a filesystem change.</li>
+
+<li><b>Use a speedier driver</b>&mdash;rEFInd 0.7.0 introduced a read-ahead cache in its filesystem drivers, which greatly improved their speed on some systems. If you're using an older driver, try using a newer one. Pete Batard's <a href="https://github.com/pbatard/efifs">efifs drivers</a> are an alternative to rEFInd's drivers. The efifs drivers are still very new and rapidly changing. My initial impression is that some of them are quite speedy, but others are very slow.</li>
+
+<li><b>Delete or move files and directories</b>&mdash;By default, rEFInd scans the root (<tt>/</tt>) directory, <tt>/boot</tt>, and most subdirectories of <tt>/EFI</tt> on every partition that it scans. If these locations exist but contain no bootable files, they'll just slow rEFInd down. Likewise, if you use <tt>dont_scan_files</tt> to keep unused boot loaders out of the menu, rEFInd will still do much of the work of scanning those files. In all of these cases, deleting or moving the directories or files that are being scanned but that don't contain bootable options you want to see can speed things up.</li>
+
+<li><b>Use the <tt>also_scan_dirs</tt> option sparingly</b>&mdash;Using <tt>also_scan_dirs</tt> is useful in some situations, but it does add to rEFInd's task list. Use it only if you must.</li>
+
+<li><b>Reduce the <tt>scanfor</tt> list</b>&mdash;Removing items from the <tt>scanfor</tt> list in <tt>refind.conf</tt> can speed things up a bit. This is especially true on Macs, which scan for BIOS-mode boot loaders by default. If you never boot a Mac in BIOS mode, try uncommending <tt>scanfor</tt> and ensure that the <tt>hdbios</tt>, <tt>biosexternal</tt>, and <tt>cd</tt> options are <i>not</i> present. The <tt>external</tt> and <tt>optical</tt> items won't add delays <i>unless</i> the relevant media are inserted, which brings us to....</li>
+
+<li><b>Don't boot with removable media attached (unless you intend to boot from them)</b>&mdash;If you insert an optical disc into your drive or plug in a removable device like a USB flash drive, rEFInd will attempt to scan it. This will slow down rEFInd's startup process, so you shouldn't make a habit of booting with such media inserted. In fact, there's another reason not to boot with external media attached: If such a medium is infected with malware, and if your firmware is configured to boot from external media first, you'll end up running the malware, possibly infecting your computer.</li>
+
+</ul>
+
+<p>I hope these tips will help you to overcome any speed problems you're experiencing. As I said, rEFInd is reasonably fast on many computers, so you might not run into problems in the first place. If you do, though, reducing rEFInd's workload can help.</p>
+
+<hr />
+
+<p>copyright &copy; 2012&ndash;2015 by Roderick W. Smith</p>
+
+<p>This document is licensed under the terms of the <a href="FDL-1.3.txt">GNU Free Documentation License (FDL), version 1.3.</a></p>
+
+<p>If you have problems with or comments about this Web page, please e-mail me at <a href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.com.</a> Thanks.</p>
+
+<p><a href="index.html">Go to the main rEFInd page</a></p>
+
+<p><a href="configfile.html">Learn how to Configure rEFInd</a></p>
+
+  <p><a href="http://www.rodsbooks.com/">Return</a> to my main Web page.</p>
+</body>
+</html>
diff --git a/docs/refind/windows-gpt.png b/docs/refind/windows-gpt.png
new file mode 100644 (file)
index 0000000..4c7ce06
Binary files /dev/null and b/docs/refind/windows-gpt.png differ
diff --git a/docs/refind/yosemite.html b/docs/refind/yosemite.html
new file mode 100644 (file)
index 0000000..850d6ca
--- /dev/null
@@ -0,0 +1,183 @@
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>The rEFInd Boot Manager: rEFInd and Yosemite</title>
+  <link href="../Styles/styles.css" rel="stylesheet" type="text/css" />
+</head>
+
+<meta name="viewport" content="width=device-width, initial-scale=1">
+
+<body>
+  <h1>The rEFInd Boot Manager:<br />rEFInd and Yosemite</h1>
+
+<p class="subhead">by Roderick W. Smith, <a
+href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.com</a></p>
+
+<p>Originally written: 10/20/2014; last Web page update:
+12/8/2014, referencing rEFInd 0.8.4</p>
+
+
+<p>This Web page is provided free of charge and with no annoying outside ads; however, I did take time to prepare it, and Web hosting does cost money. If you find this Web page useful, please consider making a small donation to help keep this site up and running. Thanks!</p>
+
+<table border="1">
+<tr>
+<td>Donate $1.00</td>
+<td>Donate $2.50</td>
+<td>Donate $5.00</td>
+<td>Donate $10.00</td>
+<td>Donate $20.00</td>
+<td>Donate another value</td>
+</tr>
+<tr>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="1.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="2.50">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="5.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="10.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="amount" value="20.00">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td>
+
+<td>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_donations">
+<input type="hidden" name="business" value="rodsmith@rodsbooks.com">
+<input type="hidden" name="lc" value="US">
+<input type="hidden" name="no_note" value="0">
+<input type="hidden" name="currency_code" value="USD">
+<input type="hidden" name="item_name" value="rEFInd Boot Manager">
+<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest">
+<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+</form>
+</td></tr>
+</table>
+
+<hr />
+
+<p><b>This page is largely obsolete, as of rEFInd 0.8.4. This version of rEFInd makes changes to both its <tt>install.sh</tt> script and default options to make rEFInd better able to cope with OS X 10.10 without the changes to procedure described herein. I'm leaving this page in place for the benefit of those who might be running earlier versions of rEFInd with Yosemite, as well as for general educational purposes. Most readers can skip it.</b></p>
+
+<hr />
+
+<p>This page is part of the documentation for the rEFInd boot manager. If a Web search has brought you here, you may want to start at the <a href="index.html">main page.</a></p>
+
+<hr />
+
+<p>Recently, Apple released OS X 10.10 (aka <i>Yosemite</i>), and I've been getting e-mails with problem reports. Unfortunately, my only Mac is an ancient 32-bit model that can't run the latest version, so I can't investigate the cause of the problems myself; however, I think I understand most of what's going on. There are two main problems.</p>
+
+<p>First, Yosemite now uses a type of <a href="http://en.wikipedia.org/wiki/Logical_volume_management">logical volume management (LVM).</a> The EFI built into the computer can't read from LVM, so an installation of rEFInd on the OS X root (<tt>/</tt>) partition, which is the default when you install rEFInd 0.8.3 and earlier using <tt>install.sh</tt>, is rendered useless.</p>
+
+<p>Second, Apple seems to be placing its <i>standard</i> boot loader for this type of configuration on the <tt>Recovery HD</tt> volume, which had previously been used for (as the name suggests) recovery tools (and also for the regular boot loader when the main partition was encrypted). Because I'd gotten many complaints about the recovery system showing up in the main menu list, I coded rEFInd to ignore the contents of this volume by default. Thus, fixing the first problem results in rEFInd working but not detecting the Yosemite installation. Thanks, Apple, for making it to distinguish between your recovery boot loader and your regular boot loader!</p>
+
+<p>Version 0.8.4 of rEFInd changes both <tt>install.sh</tt> and the rEFInd defaults to bypass these problems. Thus, rEFInd 0.8.4 <i>should</i> work fine when installed from OS X 10.10 using <tt>install.sh</tt> and its default options. If you continue to have problems or if you want to use Yosemite with an earlier version of rEFInd, you can fix the problems manually:</p>
+
+<ol>
+
+<li>Boot to OS X, using whatever means are available to you. Holding Option (or Alt) while powering up will normally give you Apple's own boot manager, which should enable you to boot to OS X. If your rEFInd installation is currently starting but is not showing an OS X option, skip to step #7; but if rEFInd isn't starting, follow steps #2&ndash;7.</li>
+
+<li>If you've made changes to <tt>/EFI/refind/refind.conf</tt>, back it up.</li>
+
+<li>Remove the <tt>/EFI/refind</tt> directory tree; it's useless now, and its presence may cause confusion.</li>
+
+<li>Re-install rEFInd, as described in the <a href="installing.html">Installing rEFInd page;</a> but if you install version 0.8.3 or earlier, be sure to use the <tt>--esp</tt> or <tt>--ownhfs <tt class="variable">device-file</tt></tt> option. The latter is preferable, but requires either a dedicated partition for rEFInd or an HFS+ data partition that is currently <i>not</i> bootable. If you install rEFInd 0.8.4 or later, there's no need to specify <tt>--esp</tt> (as that is effectively now the default). You may use <tt>--ownhfs <tt class="variable">device-file</tt></tt>, if you like.</li>
+
+<li>Ensure that the partition to which you've installed rEFInd is mounted. The details depend on how you installed it:</li>
+
+<ul>
+
+<li>If you installed rEFInd to your ESP, typing <tt class="userinput">mkdir /Volumes/esp</tt> followed by <tt class="userinput">sudo mount -t msdos /dev/disk0s1 /Volumes/esp</tt> will probably work, although in some cases your ESP won't be <tt>/dev/disk0s1</tt>, so you may need to change this detail. </li>
+
+<li>If you used the <tt>--ownhfs <tt class="variable">device-file</tt></tt> installation option, the target partition should already be mounted, normally somewhere under <tt>/Volume</tt>. If not, locate it and mount it with Disk Utility or <tt>mount</tt>.</li>
+
+</ul>
+
+<li>If you backed up your <tt>refind.conf</tt> file, you can copy it over your new <tt>refind.conf</tt> file. You should copy the file to either <tt>/Volumes/esp/EFI/refind/</tt> (if you mounted the ESP at <tt>/Volumes/esp</tt> and installed there) or to <tt>/Volumes/<tt class="variable">Mountpoint</tt>/System/Library/CoreServices/</tt> (if you used a dedicated HFS+ volume; note that <tt class="variable">Mountpoint</tt> will be the name of the volume).</li>
+
+<li>Edit your new <tt>refind.conf</tt> file, which should be located as described in the previous step. In your favorite editor, locate the <tt>dont_scan_volumes</tt> line, which is commented out with a <tt>#</tt> symbol at the start of the line by default. Uncomment this line and <i>remove</i> the <tt>"Recovery HD"</tt> item from the line. Some users report that they need to enter one or two dummy entries, as in <tt>dont_scan_volumes foo,bar</tt>, to get it to work.</li>
+
+</ol>
+
+<p>With these changes made, you should be able to reboot into rEFInd and see entries for both OS X and whatever other OSes you've installed. It's possible that you'll see two entries for OS X, though, one of which will boot to a recovery system and one of which will boot to the regular installation. If you can identify a difference in their descriptions, you may be able to use the <tt>dont_scan_volumes</tt>, <tt>dont_scan_dirs</tt>, or <tt>dont_scan_files</tt> options in <tt>refind.conf</tt> to remove the recovery option from the main list. (You should still see a recovery entry as a second-line option.)</p>
+
+<p>An entirely different approach to fixing this problem is to force Yosemite to install <i>without</i> using LVM. I don't have a specific procedure for doing this, though; you should do a Web search or ask on a Mac-specific Web forum.</p>
+
+<hr />
+
+<p>copyright &copy; 2014 by Roderick W. Smith</p>
+
+<p>This document is licensed under the terms of the <a href="FDL-1.3.txt">GNU Free Documentation License (FDL), version 1.3.</a></p>
+
+<p>If you have problems with or comments about this Web page, please e-mail me at <a href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.com.</a> Thanks.</p>
+
+<p><a href="index.html">Go to the main rEFInd page</a></p>
+
+<p><a href="sip.html">rEFInd and System Integrity Protection</a></p>
+
+  <p><a href="http://www.rodsbooks.com/">Return</a> to my main Web page.</p>
+</body>
+</html>
diff --git a/filesystems/AutoGen.c b/filesystems/AutoGen.c
new file mode 100644 (file)
index 0000000..894b438
--- /dev/null
@@ -0,0 +1,233 @@
+/**
+  DO NOT EDIT
+  FILE auto-generated
+  Module name:
+    AutoGen.c
+  Abstract:       Auto-generated AutoGen.c for building module or library.
+**/
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+
+// Guids
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiFileInfoGuid = { 0x09576E92, 0x6D3F, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiFileSystemInfoGuid = { 0x09576E93, 0x6D3F, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiFileSystemVolumeLabelInfoIdGuid = { 0xDB47D7D3, 0xFE81, 0x11D3, { 0x9A, 0x35, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiMdePkgTokenSpaceGuid = { 0x914AEBE7, 0x4635, 0x459b, { 0xAA, 0x1C, 0x11, 0xE2, 0x19, 0xB0, 0x3A, 0x10 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiEventReadyToBootGuid = { 0x7CE88FB3, 0x4BD7, 0x4679, { 0x87, 0xA8, 0xA8, 0xD8, 0xDE, 0xE5, 0x0D, 0x2B }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiEventLegacyBootGuid = { 0x2A571201, 0x4966, 0x47F6, { 0x8B, 0x86, 0xF3, 0x1E, 0x41, 0xF3, 0x2F, 0x10 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiGlobalVariableGuid = { 0x8BE4DF61, 0x93CA, 0x11D2, { 0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C }};
+
+// Protocols
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDiskIoProtocolGuid = { 0xCE345171, 0xBA0B, 0x11D2, { 0x8E, 0x4F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiBlockIoProtocolGuid = { 0x964E5B21, 0x6459, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSimpleFileSystemProtocolGuid = { 0x964E5B22, 0x6459, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiUnicodeCollationProtocolGuid = { 0x1D85CD7F, 0xF43D, 0x11D2, { 0x9A, 0x0C, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiUnicodeCollation2ProtocolGuid = {0xa4c751fc, 0x23ae, 0x4c3e, { 0x92, 0xe9, 0x49, 0x64, 0xcf, 0x63, 0xf3, 0x49 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gMsgLogProtocolGuid = {0x511CE018, 0x0018, 0x4002, {0x20, 0x12, 0x17, 0x38, 0x05, 0x01, 0x02, 0x03 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDevicePathProtocolGuid = { 0x09576E91, 0x6D3F, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverBindingProtocolGuid = { 0x18A031AB, 0xB443, 0x4D1A, { 0xA5, 0xC0, 0x0C, 0x09, 0x26, 0x1E, 0x9F, 0x71 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSimpleTextOutProtocolGuid = { 0x387477C2, 0x69C7, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiGraphicsOutputProtocolGuid = { 0x9042A9DE, 0x23DC, 0x4A38, { 0x96, 0xFB, 0x7A, 0xDE, 0xD0, 0x80, 0x51, 0x6A }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiHiiFontProtocolGuid = {0xe9ca4775, 0x8657, 0x47fc, {0x97, 0xe7, 0x7e, 0xd6, 0x5a, 0x08, 0x43, 0x24}};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiUgaDrawProtocolGuid = { 0x982C298B, 0xF4FA, 0x41CB, { 0xB8, 0x38, 0x77, 0xAA, 0x68, 0x8F, 0xB8, 0x39 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiComponentNameProtocolGuid = { 0x107A772C, 0xD5E1, 0x11D4, { 0x9A, 0x46, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiComponentName2ProtocolGuid = { 0x6A7A5CFF, 0xE8D9, 0x4F70, { 0xBA, 0xDA, 0x75, 0xAB, 0x30, 0x25, 0xCE, 0x14 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverConfigurationProtocolGuid = { 0x107A772B, 0xD5E1, 0x11D4, { 0x9A, 0x46, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverConfiguration2ProtocolGuid = { 0xBFD7DC1D, 0x24F1, 0x40D9, { 0x82, 0xE7, 0x2E, 0x09, 0xBB, 0x6B, 0x4E, 0xBE }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverDiagnosticsProtocolGuid = { 0x0784924F, 0xE296, 0x11D4, { 0x9A, 0x49, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverDiagnostics2ProtocolGuid = { 0x4D330321, 0x025F, 0x4AAC, { 0x90, 0xD8, 0x5E, 0xD9, 0x00, 0x17, 0x3B, 0x63 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiLoadedImageProtocolGuid = { 0x5B1B31A1, 0x9562, 0x11D2, { 0x8E, 0x3F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
+
+// Definition of PCDs used in this module
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdUefiVariableDefaultLang[5] = {101, 110, 103, 0 };
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdUefiVariableDefaultPlatformLang[7] = {101, 110, 45, 85, 83, 0 };
+
+// Definition of PCDs used in libraries
+
+#define _PCD_TOKEN_PcdDebugPrintErrorLevel  5U
+#define _PCD_VALUE_PcdDebugPrintErrorLevel  0x80000000U
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdDebugPrintErrorLevel = _PCD_VALUE_PcdDebugPrintErrorLevel;
+extern const  UINT32  _gPcd_FixedAtBuild_PcdDebugPrintErrorLevel;
+#define _PCD_GET_MODE_32_PcdDebugPrintErrorLevel  _gPcd_FixedAtBuild_PcdDebugPrintErrorLevel
+//#define _PCD_SET_MODE_32_PcdDebugPrintErrorLevel  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdDebugClearMemoryValue  10U
+#define _PCD_VALUE_PcdDebugClearMemoryValue  0xAFU
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdDebugClearMemoryValue = _PCD_VALUE_PcdDebugClearMemoryValue;
+extern const  UINT8  _gPcd_FixedAtBuild_PcdDebugClearMemoryValue;
+#define _PCD_GET_MODE_8_PcdDebugClearMemoryValue  _gPcd_FixedAtBuild_PcdDebugClearMemoryValue
+//#define _PCD_SET_MODE_8_PcdDebugClearMemoryValue  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdDebugPropertyMask  11U
+#define _PCD_VALUE_PcdDebugPropertyMask  0x0fU
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdDebugPropertyMask = _PCD_VALUE_PcdDebugPropertyMask;
+extern const  UINT8  _gPcd_FixedAtBuild_PcdDebugPropertyMask;
+#define _PCD_GET_MODE_8_PcdDebugPropertyMask  _gPcd_FixedAtBuild_PcdDebugPropertyMask
+//#define _PCD_SET_MODE_8_PcdDebugPropertyMask  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdMaximumLinkedListLength  6U
+#define _PCD_VALUE_PcdMaximumLinkedListLength  1000000U
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdMaximumLinkedListLength = _PCD_VALUE_PcdMaximumLinkedListLength;
+extern const  UINT32  _gPcd_FixedAtBuild_PcdMaximumLinkedListLength;
+#define _PCD_GET_MODE_32_PcdMaximumLinkedListLength  _gPcd_FixedAtBuild_PcdMaximumLinkedListLength
+//#define _PCD_SET_MODE_32_PcdMaximumLinkedListLength  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdMaximumAsciiStringLength  7U
+#define _PCD_VALUE_PcdMaximumAsciiStringLength  1000000U
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdMaximumAsciiStringLength = _PCD_VALUE_PcdMaximumAsciiStringLength;
+extern const  UINT32  _gPcd_FixedAtBuild_PcdMaximumAsciiStringLength;
+#define _PCD_GET_MODE_32_PcdMaximumAsciiStringLength  _gPcd_FixedAtBuild_PcdMaximumAsciiStringLength
+//#define _PCD_SET_MODE_32_PcdMaximumAsciiStringLength  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdMaximumUnicodeStringLength  8U
+#define _PCD_VALUE_PcdMaximumUnicodeStringLength  1000000U
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdMaximumUnicodeStringLength = _PCD_VALUE_PcdMaximumUnicodeStringLength;
+extern const  UINT32  _gPcd_FixedAtBuild_PcdMaximumUnicodeStringLength;
+#define _PCD_GET_MODE_32_PcdMaximumUnicodeStringLength  _gPcd_FixedAtBuild_PcdMaximumUnicodeStringLength
+//#define _PCD_SET_MODE_32_PcdMaximumUnicodeStringLength  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdVerifyNodeInList  9U
+#define _PCD_VALUE_PcdVerifyNodeInList  ((BOOLEAN)0U)
+GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdVerifyNodeInList = _PCD_VALUE_PcdVerifyNodeInList;
+extern const  BOOLEAN  _gPcd_FixedAtBuild_PcdVerifyNodeInList;
+#define _PCD_GET_MODE_BOOL_PcdVerifyNodeInList  _gPcd_FixedAtBuild_PcdVerifyNodeInList
+//#define _PCD_SET_MODE_BOOL_PcdVerifyNodeInList  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdDriverDiagnosticsDisable  12U
+#define _PCD_VALUE_PcdDriverDiagnosticsDisable  ((BOOLEAN)0U)
+GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdDriverDiagnosticsDisable = _PCD_VALUE_PcdDriverDiagnosticsDisable;
+extern const  BOOLEAN  _gPcd_FixedAtBuild_PcdDriverDiagnosticsDisable;
+#define _PCD_GET_MODE_BOOL_PcdDriverDiagnosticsDisable  _gPcd_FixedAtBuild_PcdDriverDiagnosticsDisable
+//#define _PCD_SET_MODE_BOOL_PcdDriverDiagnosticsDisable  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdComponentNameDisable  13U
+#define _PCD_VALUE_PcdComponentNameDisable  ((BOOLEAN)0U)
+GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdComponentNameDisable = _PCD_VALUE_PcdComponentNameDisable;
+extern const  BOOLEAN  _gPcd_FixedAtBuild_PcdComponentNameDisable;
+#define _PCD_GET_MODE_BOOL_PcdComponentNameDisable  _gPcd_FixedAtBuild_PcdComponentNameDisable
+//#define _PCD_SET_MODE_BOOL_PcdComponentNameDisable  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdDriverDiagnostics2Disable  14U
+#define _PCD_VALUE_PcdDriverDiagnostics2Disable  ((BOOLEAN)1U)
+GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdDriverDiagnostics2Disable = _PCD_VALUE_PcdDriverDiagnostics2Disable;
+extern const  BOOLEAN  _gPcd_FixedAtBuild_PcdDriverDiagnostics2Disable;
+#define _PCD_GET_MODE_BOOL_PcdDriverDiagnostics2Disable  _gPcd_FixedAtBuild_PcdDriverDiagnostics2Disable
+//#define _PCD_SET_MODE_BOOL_PcdDriverDiagnostics2Disable  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdComponentName2Disable  15U
+#define _PCD_VALUE_PcdComponentName2Disable  ((BOOLEAN)1U)
+GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdComponentName2Disable = _PCD_VALUE_PcdComponentName2Disable;
+extern const  BOOLEAN  _gPcd_FixedAtBuild_PcdComponentName2Disable;
+#define _PCD_GET_MODE_BOOL_PcdComponentName2Disable  _gPcd_FixedAtBuild_PcdComponentName2Disable
+//#define _PCD_SET_MODE_BOOL_PcdComponentName2Disable  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdUgaConsumeSupport  16U
+#define _PCD_VALUE_PcdUgaConsumeSupport  ((BOOLEAN)1U)
+GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdUgaConsumeSupport = _PCD_VALUE_PcdUgaConsumeSupport;
+extern const  BOOLEAN  _gPcd_FixedAtBuild_PcdUgaConsumeSupport;
+#define _PCD_GET_MODE_BOOL_PcdUgaConsumeSupport  _gPcd_FixedAtBuild_PcdUgaConsumeSupport
+//#define _PCD_SET_MODE_BOOL_PcdUgaConsumeSupport  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdUefiLibMaxPrintBufferSize  17U
+#define _PCD_VALUE_PcdUefiLibMaxPrintBufferSize  320U
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdUefiLibMaxPrintBufferSize = _PCD_VALUE_PcdUefiLibMaxPrintBufferSize;
+extern const  UINT32  _gPcd_FixedAtBuild_PcdUefiLibMaxPrintBufferSize;
+#define _PCD_GET_MODE_32_PcdUefiLibMaxPrintBufferSize  _gPcd_FixedAtBuild_PcdUefiLibMaxPrintBufferSize
+//#define _PCD_SET_MODE_32_PcdUefiLibMaxPrintBufferSize  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+
+EFI_STATUS
+EFIAPI
+UefiBootServicesTableLibConstructor (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  );
+
+EFI_STATUS
+EFIAPI
+UefiRuntimeServicesTableLibConstructor (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  );
+
+EFI_STATUS
+EFIAPI
+UefiLibConstructor (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  );
+
+
+VOID
+EFIAPI
+ProcessLibraryConstructorList (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS  Status;
+
+  Status = UefiBootServicesTableLibConstructor (ImageHandle, SystemTable);
+  ASSERT_EFI_ERROR (Status);
+
+  Status = UefiRuntimeServicesTableLibConstructor (ImageHandle, SystemTable);
+  ASSERT_EFI_ERROR (Status);
+
+  Status = UefiLibConstructor (ImageHandle, SystemTable);
+  ASSERT_EFI_ERROR (Status);
+
+}
+
+
+
+VOID
+EFIAPI
+ProcessLibraryDestructorList (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+
+}
+
+//const UINT32 _gUefiDriverRevision = 0x00020000U;
+const UINT32 _gUefiDriverRevision = 0x00010000U;
+const UINT32 _gDxeRevision = 0x00000000U;
+
+
+EFI_STATUS
+EFIAPI
+ProcessModuleEntryPointList (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+
+{
+  return fsw_efi_main (ImageHandle, SystemTable);
+}
+
+VOID
+EFIAPI
+ExitDriver (
+  IN EFI_STATUS  Status
+  )
+{
+  if (EFI_ERROR (Status)) {
+    ProcessLibraryDestructorList (gImageHandle, gST);
+  }
+  gBS->Exit (gImageHandle, Status, 0, NULL);
+}
+
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gDriverUnloadImageCount = 0U;
+
+EFI_STATUS
+EFIAPI
+ProcessModuleUnloadList (
+  IN EFI_HANDLE        ImageHandle
+  )
+{
+  return EFI_SUCCESS;
+}
diff --git a/filesystems/AutoGen.h b/filesystems/AutoGen.h
new file mode 100644 (file)
index 0000000..28080cf
--- /dev/null
@@ -0,0 +1,54 @@
+/**
+  DO NOT EDIT
+  FILE auto-generated
+  Module name:
+    AutoGen.h
+  Abstract:       Auto-generated AutoGen.h for building module or library.
+**/
+
+#ifndef _AUTOGENH_B34E5765_2E02_4DAF_867F_7F40BE6FC33D
+#define _AUTOGENH_B34E5765_2E02_4DAF_867F_7F40BE6FC33D
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <Base.h>
+#include <Uefi.h>
+#include <Library/PcdLib.h>
+
+// Definition of PCDs used in this module
+
+#define _PCD_TOKEN_PcdUefiVariableDefaultLang  18U
+#define _PCD_PATCHABLE_PcdUefiVariableDefaultLang_SIZE 5
+#define _PCD_VALUE_PcdUefiVariableDefaultLang  _gPcd_FixedAtBuild_PcdUefiVariableDefaultLang
+extern const UINT8 _gPcd_FixedAtBuild_PcdUefiVariableDefaultLang[5];
+#define _PCD_GET_MODE_PTR_PcdUefiVariableDefaultLang  _gPcd_FixedAtBuild_PcdUefiVariableDefaultLang
+//#define _PCD_SET_MODE_PTR_PcdUefiVariableDefaultLang  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdUefiVariableDefaultPlatformLang  19U
+#define _PCD_PATCHABLE_PcdUefiVariableDefaultPlatformLang_SIZE 7
+#define _PCD_VALUE_PcdUefiVariableDefaultPlatformLang  _gPcd_FixedAtBuild_PcdUefiVariableDefaultPlatformLang
+extern const UINT8 _gPcd_FixedAtBuild_PcdUefiVariableDefaultPlatformLang[7];
+#define _PCD_GET_MODE_PTR_PcdUefiVariableDefaultPlatformLang  _gPcd_FixedAtBuild_PcdUefiVariableDefaultPlatformLang
+//#define _PCD_SET_MODE_PTR_PcdUefiVariableDefaultPlatformLang  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+// Definition of PCDs used in libraries is in AutoGen.c
+
+
+EFI_STATUS
+EFIAPI
+fsw_efi_main (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  );
+
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/filesystems/Doxyfile b/filesystems/Doxyfile
new file mode 100644 (file)
index 0000000..15f4a3f
--- /dev/null
@@ -0,0 +1,277 @@
+# Doxyfile 1.4.7
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+PROJECT_NAME           = "File System Wrapper"
+PROJECT_NUMBER         = 0.1
+OUTPUT_DIRECTORY       = doc
+CREATE_SUBDIRS         = NO
+OUTPUT_LANGUAGE        = English
+USE_WINDOWS_ENCODING   = NO
+BRIEF_MEMBER_DESC      = YES
+REPEAT_BRIEF           = YES
+ABBREVIATE_BRIEF       = "The $name class" \
+                         "The $name widget" \
+                         "The $name file" \
+                         is \
+                         provides \
+                         specifies \
+                         contains \
+                         represents \
+                         a \
+                         an \
+                         the
+ALWAYS_DETAILED_SEC    = NO
+INLINE_INHERITED_MEMB  = NO
+FULL_PATH_NAMES        = YES
+STRIP_FROM_PATH        = 
+STRIP_FROM_INC_PATH    = 
+SHORT_NAMES            = NO
+JAVADOC_AUTOBRIEF      = YES
+MULTILINE_CPP_IS_BRIEF = NO
+DETAILS_AT_TOP         = NO
+INHERIT_DOCS           = YES
+SEPARATE_MEMBER_PAGES  = NO
+TAB_SIZE               = 8
+ALIASES                = 
+OPTIMIZE_OUTPUT_FOR_C  = YES
+OPTIMIZE_OUTPUT_JAVA   = NO
+BUILTIN_STL_SUPPORT    = NO
+DISTRIBUTE_GROUP_DOC   = NO
+SUBGROUPING            = YES
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+EXTRACT_ALL            = YES
+EXTRACT_PRIVATE        = YES
+EXTRACT_STATIC         = YES
+EXTRACT_LOCAL_CLASSES  = YES
+EXTRACT_LOCAL_METHODS  = NO
+HIDE_UNDOC_MEMBERS     = NO
+HIDE_UNDOC_CLASSES     = NO
+HIDE_FRIEND_COMPOUNDS  = NO
+HIDE_IN_BODY_DOCS      = NO
+INTERNAL_DOCS          = NO
+CASE_SENSE_NAMES       = NO
+HIDE_SCOPE_NAMES       = NO
+SHOW_INCLUDE_FILES     = YES
+INLINE_INFO            = YES
+SORT_MEMBER_DOCS       = YES
+SORT_BRIEF_DOCS        = NO
+SORT_BY_SCOPE_NAME     = NO
+GENERATE_TODOLIST      = YES
+GENERATE_TESTLIST      = YES
+GENERATE_BUGLIST       = YES
+GENERATE_DEPRECATEDLIST= YES
+ENABLED_SECTIONS       = 
+MAX_INITIALIZER_LINES  = 30
+SHOW_USED_FILES        = YES
+SHOW_DIRECTORIES       = NO
+FILE_VERSION_FILTER    = 
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET                  = NO
+WARNINGS               = YES
+WARN_IF_UNDOCUMENTED   = YES
+WARN_IF_DOC_ERROR      = YES
+WARN_NO_PARAMDOC       = NO
+WARN_FORMAT            = "$file:$line: $text"
+WARN_LOGFILE           = 
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+#INPUT                  = /Users/chrisp/efi_toolkit/refit/fsw
+INPUT                  = .
+FILE_PATTERNS          = *.c \
+                         *.cc \
+                         *.cxx \
+                         *.cpp \
+                         *.c++ \
+                         *.d \
+                         *.java \
+                         *.ii \
+                         *.ixx \
+                         *.ipp \
+                         *.i++ \
+                         *.inl \
+                         *.h \
+                         *.hh \
+                         *.hxx \
+                         *.hpp \
+                         *.h++ \
+                         *.idl \
+                         *.odl \
+                         *.cs \
+                         *.php \
+                         *.php3 \
+                         *.inc \
+                         *.m \
+                         *.mm \
+                         *.dox \
+                         *.py \
+                         *.C \
+                         *.CC \
+                         *.C++ \
+                         *.II \
+                         *.I++ \
+                         *.H \
+                         *.HH \
+                         *.H++ \
+                         *.CS \
+                         *.PHP \
+                         *.PHP3 \
+                         *.M \
+                         *.MM \
+                         *.PY
+RECURSIVE              = NO
+EXCLUDE                = 
+EXCLUDE_SYMLINKS       = NO
+EXCLUDE_PATTERNS       = 
+EXAMPLE_PATH           = 
+EXAMPLE_PATTERNS       = *
+EXAMPLE_RECURSIVE      = NO
+IMAGE_PATH             = 
+INPUT_FILTER           = 
+FILTER_PATTERNS        = 
+FILTER_SOURCE_FILES    = NO
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+SOURCE_BROWSER         = YES
+INLINE_SOURCES         = NO
+STRIP_CODE_COMMENTS    = YES
+REFERENCED_BY_RELATION = YES
+REFERENCES_RELATION    = YES
+REFERENCES_LINK_SOURCE = YES
+USE_HTAGS              = NO
+VERBATIM_HEADERS       = YES
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+ALPHABETICAL_INDEX     = NO
+COLS_IN_ALPHA_INDEX    = 5
+IGNORE_PREFIX          = 
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+GENERATE_HTML          = YES
+HTML_OUTPUT            = html
+HTML_FILE_EXTENSION    = .html
+HTML_HEADER            = 
+HTML_FOOTER            = 
+HTML_STYLESHEET        = 
+HTML_ALIGN_MEMBERS     = YES
+GENERATE_HTMLHELP      = NO
+CHM_FILE               = 
+HHC_LOCATION           = 
+GENERATE_CHI           = NO
+BINARY_TOC             = NO
+TOC_EXPAND             = NO
+DISABLE_INDEX          = NO
+ENUM_VALUES_PER_LINE   = 4
+GENERATE_TREEVIEW      = NO
+TREEVIEW_WIDTH         = 250
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+GENERATE_LATEX         = NO
+LATEX_OUTPUT           = latex
+LATEX_CMD_NAME         = latex
+MAKEINDEX_CMD_NAME     = makeindex
+COMPACT_LATEX          = NO
+PAPER_TYPE             = a4wide
+EXTRA_PACKAGES         = 
+LATEX_HEADER           = 
+PDF_HYPERLINKS         = NO
+USE_PDFLATEX           = NO
+LATEX_BATCHMODE        = NO
+LATEX_HIDE_INDICES     = NO
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+GENERATE_RTF           = NO
+RTF_OUTPUT             = rtf
+COMPACT_RTF            = NO
+RTF_HYPERLINKS         = NO
+RTF_STYLESHEET_FILE    = 
+RTF_EXTENSIONS_FILE    = 
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+GENERATE_MAN           = NO
+MAN_OUTPUT             = man
+MAN_EXTENSION          = .3
+MAN_LINKS              = NO
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+GENERATE_XML           = NO
+XML_OUTPUT             = xml
+XML_SCHEMA             = 
+XML_DTD                = 
+XML_PROGRAMLISTING     = YES
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+GENERATE_AUTOGEN_DEF   = NO
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+GENERATE_PERLMOD       = NO
+PERLMOD_LATEX          = NO
+PERLMOD_PRETTY         = YES
+PERLMOD_MAKEVAR_PREFIX = 
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor   
+#---------------------------------------------------------------------------
+ENABLE_PREPROCESSING   = YES
+MACRO_EXPANSION        = YES
+EXPAND_ONLY_PREDEF     = NO
+SEARCH_INCLUDES        = YES
+INCLUDE_PATH           = 
+INCLUDE_FILE_PATTERNS  = 
+PREDEFINED             = HOST_EFI HOST_POSIX
+EXPAND_AS_DEFINED      = VOLSTRUCTNAME \
+                         DNODESTRUCTNAME
+SKIP_FUNCTION_MACROS   = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references   
+#---------------------------------------------------------------------------
+TAGFILES               = 
+GENERATE_TAGFILE       = 
+ALLEXTERNALS           = NO
+EXTERNAL_GROUPS        = YES
+PERL_PATH              = /usr/bin/perl
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool   
+#---------------------------------------------------------------------------
+CLASS_DIAGRAMS         = NO
+HIDE_UNDOC_RELATIONS   = YES
+HAVE_DOT               = YES
+CLASS_GRAPH            = YES
+COLLABORATION_GRAPH    = YES
+GROUP_GRAPHS           = YES
+UML_LOOK               = NO
+TEMPLATE_RELATIONS     = NO
+INCLUDE_GRAPH          = YES
+INCLUDED_BY_GRAPH      = YES
+CALL_GRAPH             = NO
+CALLER_GRAPH           = NO
+GRAPHICAL_HIERARCHY    = YES
+DIRECTORY_GRAPH        = YES
+DOT_IMAGE_FORMAT       = png
+DOT_PATH               = /Applications/Graphviz.app/Contents/MacOS
+DOTFILE_DIRS           = 
+MAX_DOT_GRAPH_WIDTH    = 1024
+MAX_DOT_GRAPH_HEIGHT   = 1024
+MAX_DOT_GRAPH_DEPTH    = 1000
+DOT_TRANSPARENT        = YES
+DOT_MULTI_TARGETS      = NO
+GENERATE_LEGEND        = YES
+DOT_CLEANUP            = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine   
+#---------------------------------------------------------------------------
+SEARCHENGINE           = NO
diff --git a/filesystems/LICENSE.txt b/filesystems/LICENSE.txt
new file mode 100644 (file)
index 0000000..cdeae2b
--- /dev/null
@@ -0,0 +1,47 @@
+Licensing for the filesystem drivers is complex. Three different licenses
+apply to various parts of the code:
+
+* Christoph Pfisterer's original file system wrapper (FSW) code is covered
+  by a BSD-style license. Many of the source files with names that take the
+  form fsw_*.[ch] are so licensed, but this is NOT generally true of
+  filesystem-specific files (e.g., fsw_ext2.c or fsw_btrfs.c).
+
+* Certain filesystem drivers are licensed under the GPLv2, either because
+  they borrow code from the Linux kernel or because a developer (typically
+  Oracle) applied the GPLv2 license to them. This is true of the ext2fs,
+  ext4fs, ReiserFS, HFS+, and ISO-9660 drivers.
+
+* At least one filesystem driver (Btrfs) uses code taken from GRUB, and so
+  uses the GPLv3 (or later) license.
+
+Note that the GPLv2 and GPLv3 are, ironically, not compatible licenses.
+Thus, code from GPLv2 and GPLv3 projects should not be mixed. The BSD
+license used by Pfisterer's original code is compatible with both versions
+of the GPL, so the fact that both GPLv2 and GPLv3 drivers is built upon it
+is OK. If you intend to contribute to this project's drivers or use the
+code yourself, please keep this fact in mind.
+
+The below was written by Christoph Pfisterer with respect to his original
+code:
+
+ File System Wrapper License
+=============================
+
+The various parts of the File System Wrapper source code come from
+different sources and may carry different licenses. Here's a quick
+account of the situation:
+
+ * The core code was written from scratch and is covered by a
+   BSD-style license.
+
+ * The EFI host driver was written from scratch, possibly using code
+   from the TianoCore project and Intel's EFI Application Toolkit. It
+   is covered by a BSD-style license.
+
+ * The ext2 and reiserfs file system drivers use definitions from the
+   Linux kernel source. The actual code was written from scratch,
+   using multiple sources for reference. These drivers are covered by
+   the GNU GPL.
+
+For more details, see each file's boilerplate comment. The full text
+of the GNU GPL is in the file LICENSE_GPL.txt.
diff --git a/filesystems/LICENSE_GPL.txt b/filesystems/LICENSE_GPL.txt
new file mode 100644 (file)
index 0000000..d60c31a
--- /dev/null
@@ -0,0 +1,340 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year  name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/filesystems/Make.gnuefi b/filesystems/Make.gnuefi
new file mode 100644 (file)
index 0000000..1203bdc
--- /dev/null
@@ -0,0 +1,67 @@
+#
+# filesystems/Make.gnuefi
+# Build control file for the EFI drivers, as built with GNU-EFI
+#
+
+# This program is licensed under the terms of the GNU GPL, version 3,
+# or (at your option) any later version.
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+SRCDIR = .
+
+VPATH = $(SRCDIR)
+
+HOSTARCH        = $(shell uname -m | sed s,i[3456789]86,ia32,)
+ARCH            ?= $(HOSTARCH)
+
+# Note: IA64 options are untested; taken from Debian's rEFIt package.
+ifeq ($(ARCH),ia64)
+  # EFI specs allows only lower floating point partition to be used
+  ARCH_C_CFLAGS  = -frename-registers -mfixed-range=f32-f127
+  # TODO: Add FILENAME_CODE as appropriate
+endif
+
+ifeq ($(ARCH),ia32)
+  LIBEG = build32
+  ARCH_C_FLAGS = -m32 -malign-double
+  FILENAME_CODE = ia32
+  LD_CODE = elf_i386
+endif
+
+ifeq ($(ARCH),x86_64)
+  LIBEG = build64
+  ARCH_C_FLAGS = "-DEFIAPI=__attribute__((ms_abi))" -m64
+  FILENAME_CODE = x64
+  LD_CODE = elf_x86_64
+endif
+
+ifeq ($(ARCH),aarch64)
+  LIBEG = build64
+  ARCH_C_FLAGS = 
+  FILENAME_CODE = aa64
+  LD_CODE = elf_aarch64
+  FORMAT_DRIVER = -O binary
+endif
+
+LOCAL_CPPFLAGS   = -DFSTYPE=$(DRIVERNAME) $(ARCH_C_FLAGS) -I$(SRCDIR) -I$(SRCDIR)/../include -I$(SRCDIR)/../libeg
+
+OBJS            = fsw_core.o fsw_efi.o fsw_efi_lib.o fsw_lib.o fsw_$(DRIVERNAME).o
+TARGET          = $(DRIVERNAME)_$(FILENAME_CODE).efi
+
+all: $(TARGET)
+
+include $(SRCDIR)/../Make.common
+
+$(SHLIB_TARGET): $(OBJS)
+       $(LD) $(LOCAL_LDFLAGS) $(DRV_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 .rel.* -j .rela.* -j .rel* -j .rela* \
+                  -j .reloc $(FORMAT_DRIVER) $< $@
+       chmod a-x $(TARGET)
+       mkdir -p ../drivers_$(FILENAME_CODE)
+       cp $(TARGET) ../drivers_$(FILENAME_CODE)
+
+# EOF
diff --git a/filesystems/Make.tiano b/filesystems/Make.tiano
new file mode 100644 (file)
index 0000000..b435c9d
--- /dev/null
@@ -0,0 +1,120 @@
+#
+# filesystems/Make.common
+# Build control file for rEFInd's EFI filesystem drivers
+#
+
+# This program is licensed under the terms of the GNU GPL, version 3,
+# or (at your option) any later version.
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+HOSTARCH        = $(shell uname -m | sed s,i[3456789]86,ia32,)
+ARCH            ?= $(HOSTARCH)
+
+# Note: IA64 options are untested; taken from Debian's rEFIt package.
+ifeq ($(ARCH),ia64)
+  # EFI specs allows only lower floating point partition to be used
+  ARCH_C_CFLAGS  = -frename-registers -mfixed-range=f32-f127
+  # TODO: Add ARCHDIR and FILENAME_CODE as appropriate
+endif
+
+ifeq ($(ARCH),ia32)
+  ARCH_C_FLAGS = -m32 -malign-double -g
+  ARCHDIR = Ia32
+  UC_ARCH = IA32
+  FILENAME_CODE = ia32
+  LD_CODE = elf_i386
+endif
+
+ifeq ($(ARCH),x86_64)
+  ARCH_C_FLAGS = "-DEFIAPI=__attribute__((ms_abi))" -mcmodel=large -m64 -mno-red-zone
+  ARCHDIR = X64
+  UC_ARCH = X64
+  FILENAME_CODE = x64
+  LD_CODE = elf_x86_64
+endif
+
+ifeq ($(ARCH),aarch64)
+  ARCH_C_FLAGS = -DEFIAARCH64 -mcmodel=large
+  ARCHDIR = AArch64
+  UC_ARCH = AARCH64
+  FILENAME_CODE = aa64
+  LD_CODE = aarch64elf
+endif
+
+EDK2BASE = /usr/local/UDK2014/MyWorkSpace
+#EDK2BASE = /usr/local/edk2
+
+# Below file defines TARGET (RELEASE or DEBUG) and TOOL_CHAIN_TAG (GCC44, GCC45, or GCC46)
+include $(EDK2BASE)/Conf/target.txt
+
+EFILIB          = $(EDK2BASE)/Build/Mde/$(TARGET)_$(TOOL_CHAIN_TAG)/$(UC_ARCH)/MdePkg/Library
+ALL_EFILIBS     = $(EFILIB)/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib/OUTPUT/BaseDebugPrintErrorLevelLib.lib \
+                 $(EFILIB)/BasePrintLib/BasePrintLib/OUTPUT/BasePrintLib.lib \
+                 $(EFILIB)/BasePcdLibNull/BasePcdLibNull/OUTPUT/BasePcdLibNull.lib \
+                 $(EFILIB)/UefiDebugLibConOut/UefiDebugLibConOut/OUTPUT/UefiDebugLibConOut.lib \
+                 $(EFILIB)/BaseLib/BaseLib/OUTPUT/BaseLib.lib \
+                 $(EFILIB)/BaseMemoryLib/BaseMemoryLib/OUTPUT/BaseMemoryLib.lib \
+                 $(EFILIB)/UefiBootServicesTableLib/UefiBootServicesTableLib/OUTPUT/UefiBootServicesTableLib.lib \
+                 $(EFILIB)/UefiMemoryAllocationLib/UefiMemoryAllocationLib/OUTPUT/UefiMemoryAllocationLib.lib \
+                 $(EFILIB)/UefiDevicePathLib/UefiDevicePathLib/OUTPUT/UefiDevicePathLib.lib \
+                 $(EFILIB)/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib/OUTPUT/UefiRuntimeServicesTableLib.lib \
+                 $(EFILIB)/UefiLib/UefiLib/OUTPUT/UefiLib.lib \
+                 $(EFILIB)/UefiDriverEntryPoint/UefiDriverEntryPoint/OUTPUT/UefiDriverEntryPoint.lib
+
+ifeq ($(ARCH),aarch64)
+  ALL_EFILIBS +=  $(EFILIB)/BaseStackCheckLib/BaseStackCheckLib/OUTPUT/BaseStackCheckLib.lib
+endif
+
+INCLUDE_DIRS    = -I $(EDK2BASE)/MdePkg \
+                  -I $(EDK2BASE)/MdePkg/Include \
+                  -I $(EDK2BASE)/MdePkg/Include/$(ARCHDIR) \
+                 -I $(EDK2BASE)/EdkCompatibilityPkg/Foundation/Framework/Include \
+                 -I $(EDK2BASE)/EdkCompatibilityPkg/Foundation/Library/Dxe/Include
+
+FSW_NAMES       = fsw_efi fsw_core fsw_efi_lib fsw_lib AutoGen
+OBJS            = $(FSW_NAMES:=.obj)
+#DRIVERNAME      = ext2
+BUILDME          = $(DRIVERNAME)_$(FILENAME_CODE).efi
+
+OPTIMFLAGS      = -fno-strict-aliasing -Wno-address -Os
+DEBUGFLAGS      = -Wall -Wno-missing-braces -Wno-array-bounds -ffunction-sections -fdata-sections
+CFLAGS          = $(OPTIMFLAGS) -g -fshort-wchar -fno-stack-protector $(DEBUGFLAGS) -c -include AutoGen.h -DHOST_EFI_EDK2
+
+prefix          ?= /usr/bin/
+CC              ?= $(prefix)gcc
+AS              ?= $(prefix)as
+LD              ?= $(prefix)ld
+AR              ?= $(prefix)ar
+RANLIB          ?= $(prefix)ranlib
+OBJCOPY         ?= $(prefix)objcopy
+GENFW           ?= $(EDK2BASE)/BaseTools/Source/C/bin/GenFw
+
+
+LDSCRIPT = $(EDK2BASE)/BaseTools/Scripts/gcc4.4-ld-script
+
+LDFLAGS         = -nostdlib -n -q --gc-sections --script=$(EDK2BASE)/BaseTools/Scripts/gcc4.4-ld-script \
+                  --entry _ModuleEntryPoint -u _ModuleEntryPoint -m $(LD_CODE)
+
+%.obj: %.c
+       $(CC) $(ARCH_C_FLAGS) $(CFLAGS) $(INCLUDE_DIRS) -DFSTYPE=$(DRIVERNAME) -DNO_BUILTIN_VA_FUNCS -c $< -o $@
+
+ifneq (,$(filter %.efi,$(BUILDME)))
+
+DLL_TARGET = $(subst .efi,.dll,$(BUILDME))
+
+all: $(BUILDME)
+
+$(DLL_TARGET): $(OBJS) fsw_$(DRIVERNAME).obj
+       $(LD) -o $(DRIVERNAME)_$(FILENAME_CODE).dll $(LDFLAGS) --start-group $(ALL_EFILIBS) $(OBJS) fsw_$(DRIVERNAME).obj --end-group
+
+$(BUILDME): $(DLL_TARGET)
+       $(OBJCOPY) --strip-unneeded -R .eh_frame $(DLL_TARGET)
+       $(GENFW) -e UEFI_DRIVER -o $(BUILDME) $(DLL_TARGET)
+#      $(OBJCOPY) -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel \
+#                 -j .rela -j .reloc --rename-section .data=.hii --target=efi-bsdrv-$(ARCH) $< $@
+       mkdir -p ../drivers_$(FILENAME_CODE)
+       cp $(BUILDME) ../drivers_$(FILENAME_CODE)
+
+endif
+
diff --git a/filesystems/Makefile b/filesystems/Makefile
new file mode 100644 (file)
index 0000000..563b52f
--- /dev/null
@@ -0,0 +1,105 @@
+# meta-Makefile for rEFInd filesystem drivers
+#
+# Most of the functionality is in Make.tiano; this Makefile merely
+# deletes critical temporary files and calls Make.tiano with the
+# name of the driver to be built. This is done because of a dependency
+# in the fsw_efi.c file on the filesystem type; this file must be
+# recompiled for each new filesystem built.
+
+# This program is licensed under the terms of the GNU GPL, version 3,
+# or (at your option) any later version.
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+INSTALL_DIR = /boot/efi/EFI/refind/drivers
+
+FILESYSTEMS = ext2 ext4 reiserfs iso9660 hfs btrfs ntfs
+FILESYSTEMS_GNUEFI = ext2_gnuefi ext4_gnuefi reiserfs_gnuefi iso9660_gnuefi hfs_gnuefi btrfs_gnuefi ntfs_gnuefi
+TEXTFILES = $(FILESYSTEMS:=*.txt)
+
+# Build the drivers with TianoCore EDK2.....
+
+all:   $(FILESYSTEMS)
+
+xfs:
+       rm -f fsw_efi.obj
+       +make DRIVERNAME=xfs -f Make.tiano
+
+ext2:
+       rm -f fsw_efi.obj
+       +make DRIVERNAME=ext2 -f Make.tiano
+
+ext4:
+       rm -f fsw_efi.obj
+       +make DRIVERNAME=ext4 -f Make.tiano
+
+reiserfs:
+       rm -f fsw_efi.obj
+       +make DRIVERNAME=reiserfs -f Make.tiano
+
+iso9660:
+       rm -f fsw_efi.obj
+       +make DRIVERNAME=iso9660 -f Make.tiano
+
+hfs:
+       rm -f fsw_efi.obj
+       +make DRIVERNAME=hfs -f Make.tiano
+
+btrfs:
+       rm -f fsw_efi.obj
+       +make DRIVERNAME=btrfs -f Make.tiano
+
+ntfs:
+       rm -f fsw_efi.obj
+       +make DRIVERNAME=ntfs -f Make.tiano
+
+# Build the drivers with GNU-EFI....
+
+gnuefi: $(FILESYSTEMS_GNUEFI)
+
+all_gnuefi:    $(FILESYSTEMS_GNUEFI)
+
+xfs_gnuefi:
+       rm -f fsw_efi.o
+       +make DRIVERNAME=xfs -f Make.gnuefi
+
+ext2_gnuefi:
+       rm -f fsw_efi.o
+       +make DRIVERNAME=ext2 -f Make.gnuefi
+
+ext4_gnuefi:
+       rm -f fsw_efi.o
+       +make DRIVERNAME=ext4 -f Make.gnuefi
+
+reiserfs_gnuefi:
+       rm -f fsw_efi.o
+       +make DRIVERNAME=reiserfs -f Make.gnuefi
+
+iso9660_gnuefi:
+       rm -f fsw_efi.o
+       +make DRIVERNAME=iso9660 -f Make.gnuefi
+
+hfs_gnuefi:
+       rm -f fsw_efi.o
+       +make DRIVERNAME=hfs -f Make.gnuefi
+
+btrfs_gnuefi:
+       rm -f fsw_efi.o
+       +make DRIVERNAME=btrfs -f Make.gnuefi
+
+ntfs_gnuefi:
+       rm -f fsw_efi.o
+       +make DRIVERNAME=ntfs -f Make.gnuefi
+
+# utility rules
+
+clean:
+       rm -f *~ *.bak *.o *.obj *.so *.efi *.dll err.txt $(TEXTFILES)
+       +make -C test clean
+
+
+install:
+       mkdir -p $(INSTALL_DIR)
+       cp *.efi $(INSTALL_DIR)
+
+# DO NOT DELETE
diff --git a/filesystems/crc32c.c b/filesystems/crc32c.c
new file mode 100644 (file)
index 0000000..ec10d25
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * this file take from grub 2.0
+ * for btrfs UEFI driver
+ */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+static uint32_t crc32c_table [256];
+
+static void
+init_crc32c_table (void)
+{
+  auto uint32_t reflect (uint32_t ref, int len);
+  uint32_t reflect (uint32_t ref, int len)
+    {
+      uint32_t result = 0;
+      int i;
+
+      for (i = 1; i <= len; i++)
+        {
+          if (ref & 1)
+            result |= 1 << (len - i);
+          ref >>= 1;
+        }
+
+      return result;
+    }
+
+  static int crc32c_table_inited;
+  if(crc32c_table_inited)
+         return;
+  crc32c_table_inited = 1;
+
+  uint32_t polynomial = 0x1edc6f41;
+  int i, j;
+
+  for(i = 0; i < 256; i++)
+    {
+      crc32c_table[i] = reflect(i, 8) << 24;
+      for (j = 0; j < 8; j++)
+        crc32c_table[i] = (crc32c_table[i] << 1) ^
+            (crc32c_table[i] & (1 << 31) ? polynomial : 0);
+      crc32c_table[i] = reflect(crc32c_table[i], 32);
+    }
+}
+
+uint32_t
+grub_getcrc32c (uint32_t crc, const void *buf, int size)
+{
+  int i;
+  const uint8_t *data = buf;
+
+  if (! crc32c_table[1])
+    init_crc32c_table ();
+
+  crc^= 0xffffffff;
+
+  for (i = 0; i < size; i++)
+    {
+      crc = (crc >> 8) ^ crc32c_table[(crc & 0xFF) ^ *data];
+      data++;
+    }
+
+  return crc ^ 0xffffffff;
+}
diff --git a/filesystems/design.dox b/filesystems/design.dox
new file mode 100644 (file)
index 0000000..df7baf1
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * \file design.dox
+ * Documentation title page with design information
+ */
+
+
+/**
+\mainpage File System Wrapper Documentation
+
+Welcome to the documentation for FSW. This doxygen-generated documentation
+is intended for developers that either want to integrate FSW into their
+own project or want to write additional file system drivers.
+
+\section goals Design Goals
+
+File System Wrapper wants to provide reusable, read-only file system drivers
+for a range of common file systems. Reusability is achieved through a common
+abstraction layer (called the "core"), which serves as the API for the host
+environment driver. Once the required glue code is written for a host
+environment, that host has access to all file system types implemented by FSW,
+with no code to be written per file system type.
+
+Why read-only? There are a range of reasons why FSW only provides read-only
+access:
+
+- Read-only drivers are much easier to write than read-write drivers.
+- Write access isn't easily abstracted in an OS-independent way because
+  of more delicate buffer I/O handling requirements and features like
+  journalling.
+- There is no risk of destroying data on the disk.
+- Having read access is much better than having no access at all.
+  (Read-only drivers for several file systems can be written in the time
+  it would take to develop a read-write driver for just one file system.)
+- Boot loaders only need read access in most cases.
+
+\section model Object and Data Model
+
+\subsection main_objects Main Objects
+
+There are three main "objects" that FSW works with: volume, dnode, and shandle.
+
+The fsw_volume structure keeps the information that applies to a file
+system volume as a whole. Most importantly, it keeps pointers to the host driver
+and file system driver dispatch tables, which are used by the core to call
+the appropriate functions.
+
+The fsw_dnode structure represents a "directory node", that is any file-like
+object in the file system: regular files, directories, symbolic links as well
+as special files like device nodes. When compared with Unix-style file systems,
+a dnode is very similar to an inode, but it retains some essential information
+from the directory: the canonical name and the parent directory. FSW requires that
+a dnode is uniquely identified by an integer number (currently 32 bit in size).
+Inode numbers can be used for this purpose, non-Unix file systems will have to
+come up with a unique number in some way.
+
+The fsw_shandle structure is used to access file data ("storage handle").
+A dnode only represents the file as such and doesn't offer access to its data.
+An shandle is linked to a certain dnode, but there may be several shandles per
+dnode. The shandle stores a file position pointer (byte offset) that can be changed
+at will. With the current design, an shandle is also used for directory iteration,
+even if the file system stores directory information in a central tree structure.
+
+\subsection disk_access Disk Data Access
+
+Data on the disk is accessed in blocks, addressed by a sequential number starting
+at zero. The block size to use can be set by the file system driver. FSW supports
+two separate block sizes: the "physical block size" is used when accessing the disk,
+the "logical block size" is used when accessing a file's data. For most file
+systems, these two are identical, but there may be some where the file allocation
+block size is larger than the sector or block size used to store metadata. (FAT
+comes to mind as an example.)
+
+For accessing the actual file data, the file system driver doesn't handle the
+disk I/O, but merely returns information about the mapping from file logical
+blocks to disk physical blocks in the fsw_extent structure. This allows host OS
+buffer mechanisms to be used for file data. In special cases, like tail-packing,
+fragments or compressed file systems, the file system driver can return file data
+in an allocated buffer.
+
+\subsection data_hooks Data Extension Hooks
+
+File system specific data can be stored by extending the fsw_volume and fsw_dnode
+structures. The core code uses the structure sizes stored in the fsw_fstype_table
+to allocate memory for these structures. The fsw_shandle and fsw_extent structures
+are not designed to be extended.
+
+Host specific data must be stored in separate structures private to the host
+environment driver. The fsw_volume structure provides a host_data variable to
+store a pointer. The fsw_dnode structure has no such field, because it is assumed
+that all actions regarding dnodes are initiated on the host side and so the
+host-specific private structure is known.
+
+\section callconv Calling Conventions
+
+All functions that can fail return a status code in a fsw_status_t. This type is an
+integer. A boolean test yields true if there was an error and false if the function
+executed successfully, i.e. success is signalled by a 0 return value.
+
+Functions that return data do so either by filling a structure passed in by the caller,
+or by allocating a structure on the heap and returning a pointer through a
+double-indirect parameter. A returned object pointer is the last parameter in the
+parameter list.
+
+(More to be written about specific conventions for dnodes, shandles, strings.)
+
+*/
diff --git a/filesystems/edk2/ComponentName.h b/filesystems/edk2/ComponentName.h
new file mode 100644 (file)
index 0000000..a4c3749
--- /dev/null
@@ -0,0 +1,129 @@
+/** @file\r
+  EFI Component Name Protocol as defined in the EFI 1.1 specification.\r
+  This protocol is used to retrieve user readable names of EFI Drivers \r
+  and controllers managed by EFI Drivers.\r
+\r
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials are licensed and made available under \r
+the terms and conditions of the BSD License that accompanies this distribution.  \r
+The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php.                                          \r
+    \r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef __EFI_COMPONENT_NAME_H__\r
+#define __EFI_COMPONENT_NAME_H__\r
+\r
+///\r
+/// The global ID for the Component Name Protocol.\r
+///\r
+#define EFI_COMPONENT_NAME_PROTOCOL_GUID \\r
+  { \\r
+    0x107a772c, 0xd5e1, 0x11d4, {0x9a, 0x46, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \\r
+  }\r
+\r
+typedef struct _EFI_COMPONENT_NAME_PROTOCOL  EFI_COMPONENT_NAME_PROTOCOL;\r
+\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user-readable name of the EFI Driver.\r
+\r
+  @param  This       A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.\r
+  @param  Language   A pointer to a three-character ISO 639-2 language identifier.\r
+                     This is the language of the driver name that that the caller\r
+                     is requesting, and it must match one of the languages specified\r
+                     in SupportedLanguages.  The number of languages supported by a\r
+                     driver is up to the driver writer.\r
+  @param  DriverName A pointer to the Unicode string to return.  This Unicode string\r
+                     is the name of the driver specified by This in the language\r
+                     specified by Language.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by This\r
+                                and the language specified by Language was returned\r
+                                in DriverName.\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support the\r
+                                language specified by Language.\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFI_FUNCTION EFIAPI *EFI_COMPONENT_NAME_GET_DRIVER_NAME)(\r
+  IN EFI_COMPONENT_NAME_PROTOCOL           *This,\r
+  IN  CHAR8                                *Language,\r
+  OUT CHAR16                               **DriverName\r
+  );\r
+\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the controller\r
+  that is being managed by an EFI Driver.\r
+\r
+  @param  This             A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.\r
+  @param  ControllerHandle The handle of a controller that the driver specified by\r
+                           This is managing.  This handle specifies the controller\r
+                           whose name is to be returned.\r
+  @param  ChildHandle      The handle of the child controller to retrieve the name\r
+                           of.  This is an optional parameter that may be NULL.  It\r
+                           will be NULL for device drivers.  It will also be NULL\r
+                           for a bus drivers that wish to retrieve the name of the\r
+                           bus controller.  It will not be NULL for a bus driver\r
+                           that wishes to retrieve the name of a child controller.\r
+  @param  Language         A pointer to a three character ISO 639-2 language\r
+                           identifier.  This is the language of the controller name\r
+                           that the caller is requesting, and it must match one\r
+                           of the languages specified in SupportedLanguages.  The\r
+                           number of languages supported by a driver is up to the\r
+                           driver writer.\r
+  @param  ControllerName   A pointer to the Unicode string to return.  This Unicode\r
+                           string is the name of the controller specified by\r
+                           ControllerHandle and ChildHandle in the language specified\r
+                           by Language, from the point of view of the driver specified\r
+                           by This.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the user-readable name in the\r
+                                language specified by Language for the driver\r
+                                specified by This was returned in DriverName.\r
+  @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.\r
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid EFI_HANDLE.\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently managing\r
+                                the controller specified by ControllerHandle and\r
+                                ChildHandle.\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support the\r
+                                language specified by Language.\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFI_FUNCTION EFIAPI *EFI_COMPONENT_NAME_GET_CONTROLLER_NAME)(\r
+  IN EFI_COMPONENT_NAME_PROTOCOL                              *This,\r
+  IN  EFI_HANDLE                                              ControllerHandle,\r
+  IN  EFI_HANDLE                                              ChildHandle        OPTIONAL,\r
+  IN  CHAR8                                                   *Language,\r
+  OUT CHAR16                                                  **ControllerName\r
+  );\r
+\r
+///\r
+/// This protocol is used to retrieve user readable names of drivers \r
+/// and controllers managed by UEFI Drivers.\r
+///\r
+struct _EFI_COMPONENT_NAME_PROTOCOL {\r
+  EFI_COMPONENT_NAME_GET_DRIVER_NAME      GetDriverName;\r
+  EFI_COMPONENT_NAME_GET_CONTROLLER_NAME  GetControllerName;\r
+  ///\r
+  /// A Null-terminated ASCII string that contains one or more\r
+  /// ISO 639-2 language codes. This is the list of language codes\r
+  /// that this protocol supports.  \r
+  ///\r
+  CHAR8                                   *SupportedLanguages;\r
+};\r
+\r
+extern EFI_GUID gEfiComponentNameProtocolGuid;\r
+\r
+#endif\r
diff --git a/filesystems/edk2/DriverBinding.h b/filesystems/edk2/DriverBinding.h
new file mode 100644 (file)
index 0000000..fdb16c5
--- /dev/null
@@ -0,0 +1,181 @@
+/*++\r
+\r
+Copyright (c) 2004, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials                          \r
+are licensed and made available under the terms and conditions of the BSD License         \r
+which accompanies this distribution.  The full text of the license may be found at        \r
+http://opensource.org/licenses/bsd-license.php                                            \r
+                                                                                          \r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
+\r
+Module Name:\r
+\r
+    DriverBinding.h\r
+    \r
+Abstract:\r
+\r
+    EFI ControllerHandle Driver Protocol\r
+\r
+Revision History\r
+\r
+--*/\r
+\r
+#ifndef _EFI_DRIVER_BINDING_H_\r
+#define _EFI_DRIVER_BINDING_H_\r
+\r
+#include <efidevp.h>\r
+\r
+//\r
+// Global ID for the ControllerHandle Driver Protocol\r
+//\r
+#define EFI_DRIVER_BINDING_PROTOCOL_GUID \\r
+  { \\r
+    0x18a031ab, 0xb443, 0x4d1a, {0xa5, 0xc0, 0xc, 0x9, 0x26, 0x1e, 0x9f, 0x71} \\r
+  }\r
+\r
+#define EFI_FORWARD_DECLARATION(x) typedef struct _##x x\r
+\r
+EFI_FORWARD_DECLARATION (EFI_DRIVER_BINDING_PROTOCOL);\r
+\r
+///\r
+/// Device Path protocol.\r
+///\r
+#define EFI_DEVICE_PATH_PROTOCOL_GUID \\r
+  { \\r
+    0x9576e91, 0x6d3f, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \\r
+  }\r
+\r
+// Begin included from DevicePath.h....\r
+\r
+///\r
+/// Device Path guid definition for backward-compatible with EFI1.1.\r
+///\r
+//#define DEVICE_PATH_PROTOCOL  EFI_DEVICE_PATH_PROTOCOL_GUID\r
+\r
+#pragma pack(1)\r
+\r
+/**\r
+  This protocol can be used on any device handle to obtain generic path/location\r
+  information concerning the physical device or logical device. If the handle does\r
+  not logically map to a physical device, the handle may not necessarily support\r
+  the device path protocol. The device path describes the location of the device\r
+  the handle is for. The size of the Device Path can be determined from the structures\r
+  that make up the Device Path.\r
+**/\r
+typedef struct {\r
+  UINT8 Type;       ///< 0x01 Hardware Device Path.\r
+                    ///< 0x02 ACPI Device Path.\r
+                    ///< 0x03 Messaging Device Path.\r
+                    ///< 0x04 Media Device Path.\r
+                    ///< 0x05 BIOS Boot Specification Device Path.\r
+                    ///< 0x7F End of Hardware Device Path.\r
+\r
+  UINT8 SubType;    ///< Varies by Type\r
+                    ///< 0xFF End Entire Device Path, or\r
+                    ///< 0x01 End This Instance of a Device Path and start a new\r
+                    ///< Device Path.\r
+\r
+  UINT8 Length[2];  ///< Specific Device Path data. Type and Sub-Type define\r
+                    ///< type of data. Size of data is included in Length.\r
+\r
+} EFI_DEVICE_PATH_PROTOCOL;\r
+\r
+#pragma pack()\r
+\r
+// End included from DevicePath.h\r
+\r
+typedef\r
+EFI_STATUS\r
+(EFI_FUNCTION EFIAPI *EFI_DRIVER_BINDING_SUPPORTED) (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL            * This,\r
+  IN EFI_HANDLE                             ControllerHandle,\r
+  IN EFI_DEVICE_PATH_PROTOCOL               * RemainingDevicePath OPTIONAL\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+    Test to see if this driver supports ControllerHandle. \r
+\r
+  Arguments:\r
+    This                - Protocol instance pointer.\r
+    ControllerHandle    - Handle of device to test\r
+    RemainingDevicePath - Optional parameter use to pick a specific child \r
+                          device to start.\r
+\r
+  Returns:\r
+    EFI_SUCCESS         - This driver supports this device\r
+    EFI_ALREADY_STARTED - This driver is already running on this device\r
+    other               - This driver does not support this device\r
+\r
+--*/\r
+;\r
+\r
+typedef\r
+EFI_STATUS\r
+(EFI_FUNCTION EFIAPI *EFI_DRIVER_BINDING_START) (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL            * This,\r
+  IN EFI_HANDLE                             ControllerHandle,\r
+  IN EFI_DEVICE_PATH_PROTOCOL               * RemainingDevicePath OPTIONAL\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+    Start this driver on ControllerHandle.\r
+\r
+  Arguments:\r
+    This                - Protocol instance pointer.\r
+    ControllerHandle    - Handle of device to bind driver to\r
+    RemainingDevicePath - Optional parameter use to pick a specific child \r
+                          device to start.\r
+\r
+  Returns:\r
+    EFI_SUCCESS         - This driver is added to ControllerHandle\r
+    EFI_ALREADY_STARTED - This driver is already running on ControllerHandle\r
+    other               - This driver does not support this device\r
+\r
+--*/\r
+;\r
+\r
+typedef\r
+EFI_STATUS\r
+(EFI_FUNCTION EFIAPI *EFI_DRIVER_BINDING_STOP) (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL            * This,\r
+  IN  EFI_HANDLE                            ControllerHandle,\r
+  IN  UINTN                                 NumberOfChildren,\r
+  IN  EFI_HANDLE                            * ChildHandleBuffer\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+    Stop this driver on ControllerHandle.\r
+\r
+  Arguments:\r
+    This              - Protocol instance pointer.\r
+    ControllerHandle  - Handle of device to stop driver on \r
+    NumberOfChildren  - Number of Handles in ChildHandleBuffer. If number of \r
+                        children is zero stop the entire bus driver.\r
+    ChildHandleBuffer - List of Child Handles to Stop.\r
+\r
+  Returns:\r
+    EFI_SUCCESS         - This driver is removed ControllerHandle\r
+    other               - This driver was not removed from this device\r
+\r
+--*/\r
+;\r
+\r
+//\r
+// Interface structure for the ControllerHandle Driver Protocol\r
+//\r
+struct _EFI_DRIVER_BINDING_PROTOCOL {\r
+  EFI_DRIVER_BINDING_SUPPORTED  Supported;\r
+  EFI_DRIVER_BINDING_START      Start;\r
+  EFI_DRIVER_BINDING_STOP       Stop;\r
+  UINT32                        Version;\r
+  EFI_HANDLE                    ImageHandle;\r
+  EFI_HANDLE                    DriverBindingHandle;\r
+};\r
+\r
+extern EFI_GUID gEfiDriverBindingProtocolGuid;\r
+\r
+#endif\r
diff --git a/filesystems/fsw_base.h b/filesystems/fsw_base.h
new file mode 100644 (file)
index 0000000..2f6dc5f
--- /dev/null
@@ -0,0 +1,162 @@
+/**
+ * \file fsw_base.h
+ * Base definitions switch.
+ */
+
+/*-
+ * This code is based on:
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _FSW_BASE_H_
+#define _FSW_BASE_H_
+
+#ifdef HOST_EFI_EDK2
+#define HOST_EFI
+#endif
+
+#ifdef HOST_EFI
+#include "fsw_efi_base.h"
+#endif
+
+#ifdef HOST_POSIX
+#include "test/fsw_posix_base.h"
+#endif
+
+#ifndef FSW_DEBUG_LEVEL
+/**
+ * Global debugging level. Can be set locally for the scope of a single
+ * file by defining the macro before fsw_base.h is included.
+ */
+#define FSW_DEBUG_LEVEL 1
+#endif
+
+// message printing
+
+#if FSW_DEBUG_LEVEL >= 1
+#define FSW_MSG_ASSERT(params) FSW_MSGFUNC params
+#else
+#define FSW_MSG_ASSERT(params)
+#endif
+
+#if FSW_DEBUG_LEVEL >= 2
+#define FSW_MSG_DEBUG(params) FSW_MSGFUNC params
+#else
+#define FSW_MSG_DEBUG(params)
+#endif
+
+#if FSW_DEBUG_LEVEL >= 3
+#define FSW_MSG_DEBUGV(params) FSW_MSGFUNC params
+#else
+#define FSW_MSG_DEBUGV(params)
+#endif
+
+
+// Documentation for system-dependent defines
+
+/**
+ * \typedef fsw_s8
+ * Signed 8-bit integer.
+ */
+
+/**
+ * \typedef fsw_u8
+ * Unsigned 8-bit integer.
+ */
+
+/**
+ * \typedef fsw_s16
+ * Signed 16-bit integer.
+ */
+
+/**
+ * \typedef fsw_u16
+ * Unsigned 16-bit integer.
+ */
+
+/**
+ * \typedef fsw_s32
+ * Signed 32-bit integer.
+ */
+
+/**
+ * \typedef fsw_u32
+ * Unsigned 32-bit integer.
+ */
+
+/**
+ * \typedef fsw_s64
+ * Signed 64-bit integer.
+ */
+
+/**
+ * \typedef fsw_u64
+ * Unsigned 64-bit integer.
+ */
+
+
+/**
+ * \def fsw_alloc(size,ptrptr)
+ * Allocate memory on the heap. This function or macro allocates \a size
+ * bytes of memory using host-specific methods. The address of the
+ * allocated memory block is stored into the pointer variable pointed
+ * to by \a ptrptr. A status code is returned; FSW_SUCCESS if the block
+ * was allocated or FSW_OUT_OF_MEMORY if there is not enough memory
+ * to allocated the requested block.
+ */
+
+/**
+ * \def fsw_free(ptr)
+ * Release allocated memory. This function or macro returns an allocated
+ * memory block to the heap for reuse. Does not return a status.
+ */
+
+/**
+ * \def fsw_memcpy(dest,src,size)
+ * Copies a block of memory from \a src to \a dest. The two memory blocks
+ * must not overlap, or the result of the operation will be undefined.
+ * Does not return a status.
+ */
+
+/**
+ * \def fsw_memeq(dest,src,size)
+ * Compares two blocks of memory for equality. Returns boolean true if the
+ * memory blocks are equal, boolean false if they are different.
+ */
+
+/**
+ * \def fsw_memzero(dest,size)
+ * Initializes a block of memory with zeros. Does not return a status.
+ */
+
+
+#endif
diff --git a/filesystems/fsw_btrfs.c b/filesystems/fsw_btrfs.c
new file mode 100644 (file)
index 0000000..566be85
--- /dev/null
@@ -0,0 +1,1880 @@
+/*
+ * fsw_btrfs.c:
+ * btrfs UEFI driver
+ * by Samuel Liao
+ * Copyright (c) 2013  Tencent, Inc.
+ *
+ * This driver base on grub 2.0 btrfs implementation.
+ */
+
+/* btrfs.c - B-tree file system.  */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2010  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+//#define DPRINT(x...)  Print(x)
+
+#include "fsw_core.h"
+#define uint8_t fsw_u8
+#define uint16_t fsw_u16
+#define uint32_t fsw_u32
+#define uint64_t fsw_u64
+#define int64_t fsw_s64
+#define int32_t fsw_s32
+
+#ifndef DPRINT
+#define DPRINT(x...)    /* */
+#endif
+
+/* no single io/element size over 2G */
+#define fsw_size_t int
+#define fsw_ssize_t int
+/* never zip over 2G, 32bit is enough */
+#define grub_off_t int32_t
+#define grub_size_t int32_t
+#define grub_ssize_t int32_t
+#include "crc32c.c"
+#include "gzio.c"
+#define MINILZO_CFG_SKIP_LZO_PTR 1
+#define MINILZO_CFG_SKIP_LZO_UTIL 1
+#define MINILZO_CFG_SKIP_LZO_STRING 1
+#define MINILZO_CFG_SKIP_LZO_INIT 1
+#define MINILZO_CFG_SKIP_LZO1X_DECOMPRESS 1
+#define MINILZO_CFG_SKIP_LZO1X_1_COMPRESS 1
+#define MINILZO_CFG_SKIP_LZO_STRING 1
+#include "minilzo.c"
+#include "scandisk.c"
+
+#define BTRFS_DEFAULT_BLOCK_SIZE 4096
+#define BTRFS_INITIAL_BCACHE_SIZE 1024
+#define GRUB_BTRFS_SIGNATURE "_BHRfS_M"
+
+/* From http://www.oberhumer.com/opensource/lzo/lzofaq.php
+ * LZO will expand incompressible data by a little amount. I still haven't
+ * computed the exact values, but I suggest using these formulas for
+ * a worst-case expansion calculation:
+ *
+ * output_block_size = input_block_size + (input_block_size / 16) + 64 + 3
+ *  */
+#define GRUB_BTRFS_LZO_BLOCK_SIZE 4096
+#define GRUB_BTRFS_LZO_BLOCK_MAX_CSIZE (GRUB_BTRFS_LZO_BLOCK_SIZE + \
+        (GRUB_BTRFS_LZO_BLOCK_SIZE / 16) + 64 + 3)
+
+/*
+ * on disk struct has prefix 'btrfs_', little endian
+ * on memory struct has prefix 'fsw_btrfs_'
+ */
+typedef uint8_t btrfs_checksum_t[0x20];
+typedef uint32_t btrfs_uuid_t[4];
+
+struct btrfs_device
+{
+    uint64_t device_id;
+    uint64_t size;
+    uint8_t dummy[0x62 - 0x10];
+} __attribute__ ((__packed__));
+
+struct btrfs_superblock
+{
+    btrfs_checksum_t checksum;
+    btrfs_uuid_t uuid;
+    uint8_t dummy[0x10];
+    uint8_t signature[sizeof (GRUB_BTRFS_SIGNATURE) - 1];
+    uint64_t generation;
+    uint64_t root_tree;
+    uint64_t chunk_tree;
+    uint8_t dummy2[0x10];
+    uint64_t total_bytes;
+    uint64_t bytes_used;
+    uint64_t root_dir_objectid;
+#define BTRFS_MAX_NUM_DEVICES   0x10000
+    uint64_t num_devices;
+    uint32_t sectorsize;
+    uint32_t nodesize;
+
+    uint8_t dummy3[0x31];
+    struct btrfs_device this_device;
+    char label[0x100];
+    uint8_t dummy4[0x100];
+    uint8_t bootstrap_mapping[0x800];
+} __attribute__ ((__packed__));
+
+struct btrfs_header
+{
+    btrfs_checksum_t checksum;
+    btrfs_uuid_t uuid;
+    uint8_t dummy[0x30];
+    uint32_t nitems;
+    uint8_t level;
+} __attribute__ ((__packed__));
+
+struct fsw_btrfs_device_desc
+{
+    struct fsw_volume * dev;
+    uint64_t id;
+};
+
+struct fsw_btrfs_volume
+{
+    struct fsw_volume g;            //!< Generic volume structure
+
+    /* superblock shadows */
+    uint8_t bootstrap_mapping[0x800];
+    btrfs_uuid_t uuid;
+    uint64_t total_bytes;
+    uint64_t bytes_used;
+    uint64_t chunk_tree;
+    uint64_t root_tree;
+    uint64_t top_tree; /* top volume tree */
+    unsigned num_devices;
+    unsigned sectorshift;
+    unsigned sectorsize;
+    int is_master;
+
+    struct fsw_btrfs_device_desc *devices_attached;
+    unsigned n_devices_attached;
+    unsigned n_devices_allocated;
+
+    /* Cached extent data.  */
+    uint64_t extstart;
+    uint64_t extend;
+    uint64_t extino;
+    uint64_t exttree;
+    uint32_t extsize;
+    struct btrfs_extent_data *extent;
+};
+
+enum
+{
+    GRUB_BTRFS_ITEM_TYPE_INODE_ITEM = 0x01,
+    GRUB_BTRFS_ITEM_TYPE_INODE_REF = 0x0c,
+    GRUB_BTRFS_ITEM_TYPE_DIR_ITEM = 0x54,
+    GRUB_BTRFS_ITEM_TYPE_EXTENT_ITEM = 0x6c,
+    GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM = 0x84,
+    GRUB_BTRFS_ITEM_TYPE_DEVICE = 0xd8,
+    GRUB_BTRFS_ITEM_TYPE_CHUNK = 0xe4
+};
+
+struct btrfs_key
+{
+    uint64_t object_id;
+    uint8_t type;
+    uint64_t offset;
+} __attribute__ ((__packed__));
+
+struct btrfs_chunk_item
+{
+    uint64_t size;
+    uint64_t dummy;
+    uint64_t stripe_length;
+    uint64_t type;
+#define GRUB_BTRFS_CHUNK_TYPE_BITS_DONTCARE 0x07
+#define GRUB_BTRFS_CHUNK_TYPE_SINGLE        0x00
+#define GRUB_BTRFS_CHUNK_TYPE_RAID0         0x08
+#define GRUB_BTRFS_CHUNK_TYPE_RAID1         0x10
+#define GRUB_BTRFS_CHUNK_TYPE_DUPLICATED    0x20
+#define GRUB_BTRFS_CHUNK_TYPE_RAID10        0x40
+    uint8_t dummy2[0xc];
+    uint16_t nstripes;
+    uint16_t nsubstripes;
+} __attribute__ ((__packed__));
+
+struct btrfs_chunk_stripe
+{
+    uint64_t device_id;
+    uint64_t offset;
+    btrfs_uuid_t device_uuid;
+} __attribute__ ((__packed__));
+
+struct btrfs_leaf_node
+{
+    struct btrfs_key key;
+    uint32_t offset;
+    uint32_t size;
+} __attribute__ ((__packed__));
+
+struct btrfs_internal_node
+{
+    struct btrfs_key key;
+    uint64_t addr;
+    uint64_t dummy;
+} __attribute__ ((__packed__));
+
+struct btrfs_dir_item
+{
+    struct btrfs_key key;
+    uint64_t transid;
+    uint16_t m;
+    uint16_t n;
+#define GRUB_BTRFS_DIR_ITEM_TYPE_REGULAR 1
+#define GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY 2
+#define GRUB_BTRFS_DIR_ITEM_TYPE_SYMLINK 7
+    uint8_t type;
+    char name[0];
+} __attribute__ ((__packed__));
+
+struct fsw_btrfs_leaf_descriptor
+{
+    unsigned depth;
+    unsigned allocated;
+    struct
+    {
+        uint64_t addr;
+        unsigned iter;
+        unsigned maxiter;
+        int leaf;
+    } *data;
+};
+
+struct btrfs_root_item
+{
+    uint8_t dummy[0xb0];
+    uint64_t tree;
+    uint64_t inode;
+} __attribute__ ((__packed__));
+
+struct btrfs_time
+{
+    int64_t sec;
+    uint32_t nanosec;
+} __attribute__ ((__packed__));
+
+struct btrfs_inode
+{
+    uint64_t gen_id;
+    uint64_t trans_id;
+    uint64_t size;
+    uint64_t nbytes;
+    uint64_t block_group;
+    uint32_t nlink;
+    uint32_t uid;
+    uint32_t gid;
+    uint32_t mode;
+    uint64_t rdev;
+    uint64_t flags;
+
+    uint64_t seq;
+
+    uint64_t reserved[4];
+    struct btrfs_time atime;
+    struct btrfs_time ctime;
+    struct btrfs_time mtime;
+    struct btrfs_time otime;
+} __attribute__ ((__packed__));
+
+struct fsw_btrfs_dnode {
+    struct fsw_dnode g;              //!< Generic dnode structure
+    struct btrfs_inode *raw;    //!< Full raw inode structure
+};
+
+struct btrfs_extent_data
+{
+    uint64_t dummy;
+    uint64_t size;
+    uint8_t compression;
+    uint8_t encryption;
+    uint16_t encoding;
+    uint8_t type;
+    union
+    {
+        char inl[0];
+        struct
+        {
+            uint64_t laddr;
+            uint64_t compressed_size;
+            uint64_t offset;
+            uint64_t filled;
+        };
+    };
+} __attribute__ ((__packed__));
+
+#define GRUB_BTRFS_EXTENT_INLINE 0
+#define GRUB_BTRFS_EXTENT_REGULAR 1
+
+#define GRUB_BTRFS_COMPRESSION_NONE 0
+#define GRUB_BTRFS_COMPRESSION_ZLIB 1
+#define GRUB_BTRFS_COMPRESSION_LZO  2
+
+#define GRUB_BTRFS_OBJECT_ID_CHUNK 0x100
+
+struct fsw_btrfs_uuid_list {
+    struct fsw_btrfs_volume *master;
+    struct fsw_btrfs_uuid_list *next;
+};
+
+static int uuid_eq(btrfs_uuid_t u1, btrfs_uuid_t u2) {
+    return u1[0]==u2[0] && u1[1]==u2[1] && u1[2]==u2[2] && u1[3]==u2[3];
+}
+
+static struct fsw_btrfs_uuid_list *master_uuid_list = NULL;
+
+static int master_uuid_add(struct fsw_btrfs_volume *vol, struct fsw_btrfs_volume **master_out) {
+    struct fsw_btrfs_uuid_list *l;
+
+    for (l = master_uuid_list; l; l=l->next)
+        if(uuid_eq(l->master->uuid, vol->uuid)) {
+            if(master_out)
+                *master_out = l->master;
+            return 0;
+        }
+
+    l = AllocatePool(sizeof(struct fsw_btrfs_uuid_list));
+    l->master = vol;
+    l->next = master_uuid_list;
+    master_uuid_list = l;
+    return 1;
+}
+
+static void master_uuid_remove(struct fsw_btrfs_volume *vol) {
+    struct fsw_btrfs_uuid_list **lp;
+
+    for (lp = &master_uuid_list; *lp; lp=&(*lp)->next)
+        if((*lp)->master == vol) {
+            struct fsw_btrfs_uuid_list *n = *lp;
+            *lp = n->next;
+            FreePool(n);
+            break;
+        }
+}
+
+static fsw_status_t btrfs_set_superblock_info(struct fsw_btrfs_volume *vol, struct btrfs_superblock *sb)
+{
+    int i;
+    vol->uuid[0] = sb->uuid[0];
+    vol->uuid[1] = sb->uuid[1];
+    vol->uuid[2] = sb->uuid[2];
+    vol->uuid[3] = sb->uuid[3];
+    vol->chunk_tree = sb->chunk_tree;
+    vol->root_tree = sb->root_tree;
+    vol->total_bytes = fsw_u64_le_swap(sb->total_bytes);
+    vol->bytes_used = fsw_u64_le_swap(sb->bytes_used);
+
+    vol->sectorshift = 0;
+    vol->sectorsize = fsw_u32_le_swap(sb->sectorsize);
+    for(i=9; i<20; i++) {
+        if((1UL<<i) == vol->sectorsize) {
+            vol->sectorshift = i;
+            break;
+        }
+    }
+    if(fsw_u64_le_swap(sb->num_devices) > BTRFS_MAX_NUM_DEVICES)
+        vol->num_devices = BTRFS_MAX_NUM_DEVICES;
+    else
+        vol->num_devices = fsw_u64_le_swap(sb->num_devices);
+    fsw_memcpy(vol->bootstrap_mapping, sb->bootstrap_mapping, sizeof(vol->bootstrap_mapping));
+    return FSW_SUCCESS;
+}
+
+static uint64_t superblock_pos[4] = {
+    64 / 4,
+    64 * 1024 / 4,
+    256 * 1048576 / 4,
+    1048576ULL * 1048576ULL / 4
+};
+
+static fsw_status_t fsw_btrfs_read_logical(struct fsw_btrfs_volume *vol,
+        uint64_t addr, void *buf, fsw_size_t size, int rdepth, int cache_level);
+
+static fsw_status_t btrfs_read_superblock (struct fsw_volume *vol, struct btrfs_superblock *sb_out)
+{
+    unsigned i;
+    uint64_t total_blocks = 1024;
+    fsw_status_t err = FSW_SUCCESS;
+
+    fsw_set_blocksize(vol, BTRFS_DEFAULT_BLOCK_SIZE, BTRFS_DEFAULT_BLOCK_SIZE);
+    for (i = 0; i < 4; i++)
+    {
+        uint8_t *buffer;
+        struct btrfs_superblock *sb;
+
+        /* Don't try additional superblocks beyond device size.  */
+        if (total_blocks <= superblock_pos[i])
+            break;
+
+        err = fsw_block_get(vol, superblock_pos[i], 0, (void **)&buffer);
+        if (err) {
+            fsw_block_release(vol, superblock_pos[i], buffer);
+            break;
+        }
+
+        sb = (struct btrfs_superblock *)buffer;
+        if (!fsw_memeq (sb->signature, GRUB_BTRFS_SIGNATURE,
+                    sizeof (GRUB_BTRFS_SIGNATURE) - 1))
+        {
+            fsw_block_release(vol, superblock_pos[i], buffer);
+            break;
+        }
+        if (i == 0 || fsw_u64_le_swap (sb->generation) > fsw_u64_le_swap (sb_out->generation))
+        {
+            fsw_memcpy (sb_out, sb, sizeof (*sb));
+            total_blocks = fsw_u64_le_swap (sb->this_device.size) >> 12;
+        }
+        fsw_block_release(vol, superblock_pos[i], buffer);
+    }
+
+    if ((err == FSW_UNSUPPORTED || !err) && i == 0)
+        return FSW_UNSUPPORTED;
+
+    if (err == FSW_UNSUPPORTED)
+        err = FSW_SUCCESS;
+
+    if(err == 0)
+        DPRINT(L"btrfs: UUID: %08x-%08x-%08x-%08x device id: %d\n",
+                sb_out->uuid[0], sb_out->uuid[1], sb_out->uuid[2], sb_out->uuid[3],
+                sb_out->this_device.device_id);
+    return err;
+}
+
+static int key_cmp (const struct btrfs_key *a, const struct btrfs_key *b)
+{
+    if (fsw_u64_le_swap (a->object_id) < fsw_u64_le_swap (b->object_id))
+        return -1;
+    if (fsw_u64_le_swap (a->object_id) > fsw_u64_le_swap (b->object_id))
+        return +1;
+
+    if (a->type < b->type)
+        return -1;
+    if (a->type > b->type)
+        return +1;
+
+    if (fsw_u64_le_swap (a->offset) < fsw_u64_le_swap (b->offset))
+        return -1;
+    if (fsw_u64_le_swap (a->offset) > fsw_u64_le_swap (b->offset))
+        return +1;
+    return 0;
+}
+
+static void free_iterator (struct fsw_btrfs_leaf_descriptor *desc)
+{
+    fsw_free (desc->data);
+}
+
+static fsw_status_t save_ref (struct fsw_btrfs_leaf_descriptor *desc,
+        uint64_t addr, unsigned i, unsigned m, int l)
+{
+    desc->depth++;
+    if (desc->allocated < desc->depth)
+    {
+        void *newdata;
+        int oldsize = sizeof (desc->data[0]) * desc->allocated;
+        desc->allocated *= 2;
+        newdata = AllocatePool (sizeof (desc->data[0]) * desc->allocated);
+        if (!newdata)
+            return FSW_OUT_OF_MEMORY;
+        fsw_memcpy(newdata, desc->data, oldsize);
+        FreePool(desc->data);
+        desc->data = newdata;
+    }
+    desc->data[desc->depth - 1].addr = addr;
+    desc->data[desc->depth - 1].iter = i;
+    desc->data[desc->depth - 1].maxiter = m;
+    desc->data[desc->depth - 1].leaf = l;
+    return FSW_SUCCESS;
+}
+
+static int next (struct fsw_btrfs_volume *vol,
+        struct fsw_btrfs_leaf_descriptor *desc,
+        uint64_t * outaddr, fsw_size_t * outsize,
+        struct btrfs_key *key_out)
+{
+    fsw_status_t err;
+    struct btrfs_leaf_node leaf;
+
+    for (; desc->depth > 0; desc->depth--)
+    {
+        desc->data[desc->depth - 1].iter++;
+        if (desc->data[desc->depth - 1].iter
+                < desc->data[desc->depth - 1].maxiter)
+            break;
+    }
+    if (desc->depth == 0)
+        return 0;
+    while (!desc->data[desc->depth - 1].leaf)
+    {
+        struct btrfs_internal_node node;
+        struct btrfs_header head;
+        fsw_memzero(&node, sizeof(node));
+
+        err = fsw_btrfs_read_logical (vol, desc->data[desc->depth - 1].iter
+                * sizeof (node)
+                + sizeof (struct btrfs_header)
+                + desc->data[desc->depth - 1].addr,
+                &node, sizeof (node), 0, 1);
+        if (err)
+            return -err;
+
+        err = fsw_btrfs_read_logical (vol, fsw_u64_le_swap (node.addr),
+                &head, sizeof (head), 0, 1);
+        if (err)
+            return -err;
+
+        save_ref (desc, fsw_u64_le_swap (node.addr), 0,
+                fsw_u32_le_swap (head.nitems), !head.level);
+    }
+    err = fsw_btrfs_read_logical (vol, desc->data[desc->depth - 1].iter
+            * sizeof (leaf)
+            + sizeof (struct btrfs_header)
+            + desc->data[desc->depth - 1].addr, &leaf,
+            sizeof (leaf), 0, 1);
+    if (err)
+        return -err;
+    *outsize = fsw_u32_le_swap (leaf.size);
+    *outaddr = desc->data[desc->depth - 1].addr + sizeof (struct btrfs_header)
+        + fsw_u32_le_swap (leaf.offset);
+    *key_out = leaf.key;
+    return 1;
+}
+
+#define depth2cache(x)  ((x) >= 4 ? 1 : 5-(x))
+static fsw_status_t lower_bound (struct fsw_btrfs_volume *vol,
+        const struct btrfs_key *key_in,
+        struct btrfs_key *key_out,
+        uint64_t root,
+        uint64_t *outaddr, fsw_size_t *outsize,
+        struct fsw_btrfs_leaf_descriptor *desc,
+        int rdepth)
+{
+    uint64_t addr = fsw_u64_le_swap (root);
+    int depth = -1;
+
+    if (desc)
+    {
+        desc->allocated = 16;
+        desc->depth = 0;
+        desc->data = AllocatePool (sizeof (desc->data[0]) * desc->allocated);
+        if (!desc->data)
+            return FSW_OUT_OF_MEMORY;
+    }
+
+    /* > 2 would work as well but be robust and allow a bit more just in case.
+    */
+    if (rdepth > 10)
+        return FSW_VOLUME_CORRUPTED;
+
+    DPRINT (L"btrfs: retrieving %lx %x %lx\n",
+            key_in->object_id, key_in->type, key_in->offset);
+
+    while (1)
+    {
+        fsw_status_t err;
+        struct btrfs_header head;
+        fsw_memzero(&head, sizeof(head));
+
+reiter:
+        depth++;
+        /* FIXME: preread few nodes into buffer. */
+        err = fsw_btrfs_read_logical (vol, addr, &head, sizeof (head),
+                rdepth + 1, depth2cache(rdepth));
+        if (err)
+            return err;
+        addr += sizeof (head);
+        if (head.level)
+        {
+            unsigned i;
+            struct btrfs_internal_node node, node_last;
+            int have_last = 0;
+            fsw_memzero (&node_last, sizeof (node_last));
+            for (i = 0; i < fsw_u32_le_swap (head.nitems); i++)
+            {
+                err = fsw_btrfs_read_logical (vol, addr + i * sizeof (node),
+                        &node, sizeof (node), rdepth + 1, depth2cache(rdepth));
+                if (err)
+                    return err;
+
+                DPRINT (L"btrfs: internal node (depth %d) %lx %x %lx\n", depth,
+                        node.key.object_id, node.key.type,
+                        node.key.offset);
+
+                if (key_cmp (&node.key, key_in) == 0)
+                {
+                    err = FSW_SUCCESS;
+                    if (desc)
+                        err = save_ref (desc, addr - sizeof (head), i,
+                                fsw_u32_le_swap (head.nitems), 0);
+                    if (err)
+                        return err;
+                    addr = fsw_u64_le_swap (node.addr);
+                    goto reiter;
+                }
+                if (key_cmp (&node.key, key_in) > 0)
+                    break;
+                node_last = node;
+                have_last = 1;
+            }
+            if (have_last)
+            {
+                err = FSW_SUCCESS;
+                if (desc)
+                    err = save_ref (desc, addr - sizeof (head), i - 1,
+                            fsw_u32_le_swap (head.nitems), 0);
+                if (err)
+                    return err;
+                addr = fsw_u64_le_swap (node_last.addr);
+                goto reiter;
+            }
+            *outsize = 0;
+            *outaddr = 0;
+            fsw_memzero (key_out, sizeof (*key_out));
+            if (desc)
+                return save_ref (desc, addr - sizeof (head), -1,
+                        fsw_u32_le_swap (head.nitems), 0);
+            return FSW_SUCCESS;
+        }
+        {
+            unsigned i;
+            struct btrfs_leaf_node leaf, leaf_last;
+            int have_last = 0;
+            for (i = 0; i < fsw_u32_le_swap (head.nitems); i++)
+            {
+                err = fsw_btrfs_read_logical (vol, addr + i * sizeof (leaf),
+                        &leaf, sizeof (leaf), rdepth + 1, depth2cache(rdepth));
+                if (err)
+                    return err;
+
+                DPRINT (L"btrfs: leaf (depth %d) %lx %x %lx\n", depth,
+                        leaf.key.object_id, leaf.key.type, leaf.key.offset);
+
+                if (key_cmp (&leaf.key, key_in) == 0)
+                {
+                    fsw_memcpy (key_out, &leaf.key, sizeof (*key_out));
+                    *outsize = fsw_u32_le_swap (leaf.size);
+                    *outaddr = addr + fsw_u32_le_swap (leaf.offset);
+                    if (desc)
+                        return save_ref (desc, addr - sizeof (head), i,
+                                fsw_u32_le_swap (head.nitems), 1);
+                    return FSW_SUCCESS;
+                }
+
+                if (key_cmp (&leaf.key, key_in) > 0)
+                    break;
+
+                have_last = 1;
+                leaf_last = leaf;
+            }
+
+            if (have_last)
+            {
+                fsw_memcpy (key_out, &leaf_last.key, sizeof (*key_out));
+                *outsize = fsw_u32_le_swap (leaf_last.size);
+                *outaddr = addr + fsw_u32_le_swap (leaf_last.offset);
+                if (desc)
+                    return save_ref (desc, addr - sizeof (head), i - 1,
+                            fsw_u32_le_swap (head.nitems), 1);
+                return FSW_SUCCESS;
+            }
+            *outsize = 0;
+            *outaddr = 0;
+            fsw_memzero (key_out, sizeof (*key_out));
+            if (desc)
+                return save_ref (desc, addr - sizeof (head), -1,
+                        fsw_u32_le_swap (head.nitems), 1);
+            return FSW_SUCCESS;
+        }
+    }
+}
+
+static int btrfs_add_multi_device(struct fsw_btrfs_volume *master, struct fsw_volume *slave, struct btrfs_superblock *sb)
+{
+    int i;
+    for( i = 0; i < master->n_devices_attached; i++)
+        if(sb->this_device.device_id == master->devices_attached[i].id)
+            return FSW_UNSUPPORTED;
+
+    slave = clone_dummy_volume(slave);
+    if(slave == NULL)
+            return FSW_OUT_OF_MEMORY;
+    fsw_set_blocksize(slave, master->sectorsize, master->sectorsize);
+    slave->bcache_size = BTRFS_INITIAL_BCACHE_SIZE;
+
+    master->devices_attached[i].id = sb->this_device.device_id;
+    master->devices_attached[i].dev = slave;
+    master->n_devices_attached++;
+
+    DPRINT(L"Found slave %d\n", sb->this_device.device_id);
+    return FSW_SUCCESS;
+}
+
+static int scan_disks_hook(struct fsw_volume *volg, struct fsw_volume *slave) {
+    struct fsw_btrfs_volume *vol = (struct fsw_btrfs_volume *)volg;
+    struct btrfs_superblock sb;
+    fsw_status_t err;
+
+    if(vol->n_devices_attached >= vol->n_devices_allocated)
+        return FSW_UNSUPPORTED;
+
+    err = btrfs_read_superblock(slave, &sb);
+    if(err)
+        return FSW_UNSUPPORTED;
+
+    if(!uuid_eq(vol->uuid, sb.uuid))
+        return FSW_UNSUPPORTED;
+
+    return btrfs_add_multi_device(vol, slave, &sb);
+}
+
+static struct fsw_volume *
+find_device (struct fsw_btrfs_volume *vol, uint64_t id, int do_rescan) {
+    int i;
+
+    do {
+        for (i = 0; i < vol->n_devices_attached; i++)
+            if (id == vol->devices_attached[i].id)
+                return vol->devices_attached[i].dev;
+    } while(vol->n_devices_attached < vol->n_devices_allocated &&
+            do_rescan-- > 0 &&
+            scan_disks(scan_disks_hook, &vol->g) > 0);
+    DPRINT(L"sub device %d not found\n", id);
+    return NULL;
+}
+
+static fsw_status_t fsw_btrfs_read_logical (struct fsw_btrfs_volume *vol, uint64_t addr,
+        void *buf, fsw_size_t size, int rdepth, int cache_level)
+{
+    while (size > 0)
+    {
+        uint8_t *ptr;
+        struct btrfs_key *key;
+        struct btrfs_chunk_item *chunk;
+        uint64_t csize;
+        fsw_status_t err = 0;
+        struct btrfs_key key_out;
+        int challoc = 0;
+        struct btrfs_key key_in;
+        fsw_size_t chsize;
+        uint64_t chaddr;
+
+        for (ptr = vol->bootstrap_mapping; ptr < vol->bootstrap_mapping + sizeof (vol->bootstrap_mapping) - sizeof (struct btrfs_key);)
+        {
+            key = (struct btrfs_key *) ptr;
+            if (key->type != GRUB_BTRFS_ITEM_TYPE_CHUNK)
+                break;
+            chunk = (struct btrfs_chunk_item *) (key + 1);
+            if (fsw_u64_le_swap (key->offset) <= addr
+                    && addr < fsw_u64_le_swap (key->offset)
+                    + fsw_u64_le_swap (chunk->size))
+            {
+                goto chunk_found;
+            }
+            ptr += sizeof (*key) + sizeof (*chunk)
+                + sizeof (struct btrfs_chunk_stripe)
+                * fsw_u16_le_swap (chunk->nstripes);
+        }
+
+        key_in.object_id = fsw_u64_le_swap (GRUB_BTRFS_OBJECT_ID_CHUNK);
+        key_in.type = GRUB_BTRFS_ITEM_TYPE_CHUNK;
+        key_in.offset = fsw_u64_le_swap (addr);
+        err = lower_bound (vol, &key_in, &key_out, vol->chunk_tree, &chaddr, &chsize, NULL, rdepth);
+        if (err)
+            return err;
+        key = &key_out;
+        if (key->type != GRUB_BTRFS_ITEM_TYPE_CHUNK
+                || !(fsw_u64_le_swap (key->offset) <= addr))
+        {
+            return FSW_VOLUME_CORRUPTED;
+        }
+        // "couldn't find the chunk descriptor");
+
+        chunk = AllocatePool (chsize);
+        if (!chunk) {
+            return FSW_OUT_OF_MEMORY;
+        }
+
+        challoc = 1;
+        err = fsw_btrfs_read_logical (vol, chaddr, chunk, chsize, rdepth, cache_level < 5 ? cache_level+1 : 5);
+        if (err)
+        {
+            if(chunk)
+                FreePool (chunk);
+            return err;
+        }
+
+chunk_found:
+        {
+#ifdef __MAKEWITH_GNUEFI
+#define UINTREM UINTN
+#else
+#undef DivU64x32
+#define DivU64x32 DivU64x32Remainder
+#define UINTREM UINT32
+#endif
+            UINTREM stripen;
+            UINTREM stripe_offset;
+            uint64_t off = addr - fsw_u64_le_swap (key->offset);
+            unsigned redundancy = 1;
+            unsigned i, j;
+
+            if (fsw_u64_le_swap (chunk->size) <= off)
+            {
+                return FSW_VOLUME_CORRUPTED;
+                //"couldn't find the chunk descriptor");
+            }
+
+            DPRINT(L"btrfs chunk 0x%lx+0xlx %d stripes (%d substripes) of %lx\n",
+                    fsw_u64_le_swap (key->offset),
+                    fsw_u64_le_swap (chunk->size),
+                    fsw_u16_le_swap (chunk->nstripes),
+                    fsw_u16_le_swap (chunk->nsubstripes),
+                    fsw_u64_le_swap (chunk->stripe_length));
+
+            /* gnu-efi has no DivU64x64Remainder, limited to DivU64x32 */
+            switch (fsw_u64_le_swap (chunk->type)
+                    & ~GRUB_BTRFS_CHUNK_TYPE_BITS_DONTCARE)
+            {
+                case GRUB_BTRFS_CHUNK_TYPE_SINGLE:
+                    {
+                        uint64_t stripe_length;
+
+                        stripe_length = DivU64x32 (fsw_u64_le_swap (chunk->size),
+                                fsw_u16_le_swap (chunk->nstripes), NULL);
+
+                        if(stripe_length > 1UL<<30)
+                            return FSW_VOLUME_CORRUPTED;
+
+                        stripen = DivU64x32 (off, (uint32_t)stripe_length, &stripe_offset);
+                        csize = (stripen + 1) * stripe_length - off;
+                        DPRINT(L"read_logical %d chunk_found single csize=%d\n", __LINE__, csize);
+                        break;
+                    }
+                case GRUB_BTRFS_CHUNK_TYPE_DUPLICATED:
+                case GRUB_BTRFS_CHUNK_TYPE_RAID1:
+                    {
+                        stripen = 0;
+                        stripe_offset = off;
+                        csize = fsw_u64_le_swap (chunk->size) - off;
+                        redundancy = 2;
+                        DPRINT(L"read_logical %d chunk_found dup/raid1 off=%lx csize=%d\n", __LINE__, stripe_offset, csize);
+                        break;
+                    }
+                case GRUB_BTRFS_CHUNK_TYPE_RAID0:
+                    {
+                        uint64_t stripe_length = fsw_u64_le_swap (chunk->stripe_length);
+                        uint64_t middle, high;
+                        UINTREM low;
+
+                        if(stripe_length > 1UL<<30)
+                            return FSW_VOLUME_CORRUPTED;
+
+                        middle = DivU64x32 (off, (uint32_t)stripe_length, &low);
+
+                        high = DivU64x32 (middle, fsw_u16_le_swap (chunk->nstripes), &stripen);
+                        stripe_offset =
+                            low + fsw_u64_le_swap (chunk->stripe_length) * high;
+                        csize = fsw_u64_le_swap (chunk->stripe_length) - low;
+                        DPRINT(L"read_logical %d chunk_found raid0 csize=%d\n", __LINE__, csize);
+                        break;
+                    }
+                case GRUB_BTRFS_CHUNK_TYPE_RAID10:
+                    {
+                        uint64_t stripe_length = fsw_u64_le_swap (chunk->stripe_length);
+                        uint64_t middle, high;
+                        UINTREM low;
+
+                        if(stripe_length > 1UL<<30)
+                            return FSW_VOLUME_CORRUPTED;
+
+                        middle = DivU64x32 (off, stripe_length, &low);
+
+                        high = DivU64x32 (middle,
+                                fsw_u16_le_swap (chunk->nstripes)
+                                / fsw_u16_le_swap (chunk->nsubstripes),
+                                &stripen);
+                        stripen *= fsw_u16_le_swap (chunk->nsubstripes);
+                        redundancy = fsw_u16_le_swap (chunk->nsubstripes);
+                        stripe_offset = low + fsw_u64_le_swap (chunk->stripe_length)
+                            * high;
+                        csize = fsw_u64_le_swap (chunk->stripe_length) - low;
+                        DPRINT(L"read_logical %d chunk_found raid01 csize=%d\n", __LINE__, csize);
+                        break;
+                    }
+                default:
+                    DPRINT (L"btrfs: unsupported RAID\n");
+                    return FSW_UNSUPPORTED;
+            }
+            if (csize == 0)
+                //"couldn't find the chunk descriptor");
+                return FSW_VOLUME_CORRUPTED;
+
+            if (csize > (uint64_t) size)
+                csize = size;
+
+            for (j = 0; j < 2; j++)
+            {
+                for (i = 0; i < redundancy; i++)
+                {
+                    struct btrfs_chunk_stripe *stripe;
+                    uint64_t paddr;
+                    struct fsw_volume *dev;
+
+                    stripe = (struct btrfs_chunk_stripe *) (chunk + 1);
+                    /* Right now the redundancy handling is easy.
+                       With RAID5-like it will be more difficult.  */
+                    stripe += stripen + i;
+
+                    paddr = fsw_u64_le_swap (stripe->offset) + stripe_offset;
+
+                    DPRINT (L"btrfs: chunk 0x%lx+0x%lx (%d stripes (%d substripes) of %lx) stripe %lx maps to 0x%lx\n",
+                            fsw_u64_le_swap (key->offset),
+                            fsw_u64_le_swap (chunk->size),
+                            fsw_u16_le_swap (chunk->nstripes),
+                            fsw_u16_le_swap (chunk->nsubstripes),
+                            fsw_u64_le_swap (chunk->stripe_length),
+                            stripen, stripe->offset);
+                    DPRINT (L"btrfs: reading paddr 0x%lx for laddr 0x%lx\n", paddr, addr);
+
+                    dev = find_device (vol, stripe->device_id, j);
+                    if (!dev)
+                    {
+                        err = FSW_VOLUME_CORRUPTED;
+                        continue;
+                    }
+
+                    uint32_t off = paddr & (vol->sectorsize - 1);
+                    paddr >>= vol->sectorshift;
+                    uint64_t n = 0;
+                    while(n < csize) {
+                        char *buffer;
+                        err = fsw_block_get(dev, paddr, cache_level, (void **)&buffer);
+                        if(err)
+                            break;
+                        int s = vol->sectorsize - off;
+                        if(s > csize - n)
+                            s = csize - n;
+                        fsw_memcpy(buf+n, buffer+off, s);
+                        fsw_block_release(dev, paddr, (void *)buffer);
+
+                        n += s;
+                        off = 0;
+                        paddr++;
+                    }
+                    DPRINT (L"read logical: err %d csize %d got %d\n",
+                                    err, csize, n);
+                    if(n>=csize)
+                        break;
+                }
+                if (i != redundancy)
+                    break;
+            }
+            if (err)
+                return err;
+        }
+        size -= csize;
+        buf = (uint8_t *) buf + csize;
+        addr += csize;
+        if (challoc && chunk)
+            FreePool (chunk);
+    }
+    return FSW_SUCCESS;
+}
+
+static fsw_status_t fsw_btrfs_get_default_root(struct fsw_btrfs_volume *vol, uint64_t root_dir_objectid);
+static fsw_status_t fsw_btrfs_volume_mount(struct fsw_volume *volg) {
+    struct btrfs_superblock sblock;
+    struct fsw_btrfs_volume *vol = (struct fsw_btrfs_volume *)volg;
+    struct fsw_btrfs_volume *master_out = NULL;
+    struct fsw_string s;
+    fsw_status_t err;
+    int i;
+
+    init_crc32c_table();
+    fsw_memzero((char *)vol+sizeof(*volg), sizeof(*vol)-sizeof(*volg));
+
+    err = btrfs_read_superblock (volg, &sblock);
+    if (err)
+        return err;
+
+    btrfs_set_superblock_info(vol, &sblock);
+
+    if(vol->sectorshift == 0)
+        return FSW_UNSUPPORTED;
+
+    if(vol->num_devices >= BTRFS_MAX_NUM_DEVICES)
+        return FSW_UNSUPPORTED;
+
+    vol->is_master = master_uuid_add(vol, &master_out);
+    /* already mounted via other device */
+    if(vol->is_master == 0) {
+#define FAKE_LABEL "btrfs.multi.device"
+        s.type = FSW_STRING_TYPE_UTF8;
+        s.size = s.len = sizeof(FAKE_LABEL)-1;
+        s.data = FAKE_LABEL;
+        err = fsw_strdup_coerce(&volg->label, volg->host_string_type, &s);
+        if (err)
+            return err;
+        btrfs_add_multi_device(master_out, volg, &sblock);
+        /* create fake root */
+        return fsw_dnode_create_root_with_tree(volg, 0, 0, &volg->root);
+    }
+
+    fsw_set_blocksize(volg, vol->sectorsize, vol->sectorsize);
+    vol->g.bcache_size = BTRFS_INITIAL_BCACHE_SIZE;
+    vol->n_devices_allocated = vol->num_devices;
+    vol->devices_attached = AllocatePool (sizeof (vol->devices_attached[0])
+            * vol->n_devices_allocated);
+    if (!vol->devices_attached)
+        return FSW_OUT_OF_MEMORY;
+
+    vol->n_devices_attached = 1;
+    vol->devices_attached[0].dev = volg;
+    vol->devices_attached[0].id = sblock.this_device.device_id;
+
+    for (i = 0; i < 0x100; i++)
+        if (sblock.label[i] == 0)
+            break;
+
+    s.type = FSW_STRING_TYPE_UTF8;
+    s.size = s.len = i;
+    s.data = sblock.label;
+    err = fsw_strdup_coerce(&volg->label, volg->host_string_type, &s);
+    if (err) {
+        FreePool (vol->devices_attached);
+        vol->devices_attached = NULL;
+        return err;
+    }
+
+    err = fsw_btrfs_get_default_root(vol, sblock.root_dir_objectid);
+    if (err) {
+        DPRINT(L"root not found\n");
+        FreePool (vol->devices_attached);
+        vol->devices_attached = NULL;
+        return err;
+    }
+
+    return FSW_SUCCESS;
+}
+
+static void fsw_btrfs_volume_free(struct fsw_volume *volg)
+{
+    unsigned i;
+    struct fsw_btrfs_volume *vol = (struct fsw_btrfs_volume *)volg;
+
+    if (vol==NULL)
+        return;
+
+    if (vol->is_master)
+        master_uuid_remove(vol);
+
+    /* The device 0 is closed one layer upper.  */
+    for (i = 1; i < vol->n_devices_attached; i++)
+        fsw_unmount (vol->devices_attached[i].dev);
+    if(vol->devices_attached)
+        FreePool (vol->devices_attached);
+    if(vol->extent)
+        FreePool (vol->extent);
+}
+
+static fsw_status_t fsw_btrfs_volume_stat(struct fsw_volume *volg, struct fsw_volume_stat *sb)
+{
+    struct fsw_btrfs_volume *vol = (struct fsw_btrfs_volume *)volg;
+    sb->total_bytes = vol->total_bytes;
+    sb->free_bytes  = vol->bytes_used;
+    return FSW_SUCCESS;
+}
+
+static fsw_status_t fsw_btrfs_read_inode (struct fsw_btrfs_volume *vol,
+        struct btrfs_inode *inode, uint64_t num,
+        uint64_t tree)
+{
+    struct btrfs_key key_in, key_out;
+    uint64_t elemaddr;
+    fsw_size_t elemsize;
+    fsw_status_t err;
+
+    key_in.object_id = num;
+    key_in.type = GRUB_BTRFS_ITEM_TYPE_INODE_ITEM;
+    key_in.offset = 0;
+
+    err = lower_bound (vol, &key_in, &key_out, tree, &elemaddr, &elemsize, NULL, 0);
+    if (err)
+        return err;
+    if (num != key_out.object_id
+            || key_out.type != GRUB_BTRFS_ITEM_TYPE_INODE_ITEM)
+        return FSW_NOT_FOUND;
+
+    return fsw_btrfs_read_logical (vol, elemaddr, inode, sizeof (*inode), 0, 2);
+}
+
+static fsw_status_t fsw_btrfs_dnode_fill(struct fsw_volume *volg, struct fsw_dnode *dnog)
+{
+    struct fsw_btrfs_volume *vol = (struct fsw_btrfs_volume *)volg;
+    struct fsw_btrfs_dnode *dno = (struct fsw_btrfs_dnode *)dnog;
+    fsw_status_t    err;
+    uint32_t mode;
+
+    /* slave device got empty root */
+    if (!vol->is_master) {
+        dno->g.size = 0;
+        dno->g.type = FSW_DNODE_TYPE_DIR;
+        return FSW_SUCCESS;
+    }
+
+    if (dno->raw)
+        return FSW_SUCCESS;
+
+    dno->raw = AllocatePool(sizeof(struct btrfs_inode));
+    if(dno->raw == NULL)
+        return FSW_OUT_OF_MEMORY;
+
+    err = fsw_btrfs_read_inode(vol, dno->raw, dno->g.dnode_id, dno->g.tree_id);
+    if (err) {
+        FreePool(dno->raw);
+        dno->raw = NULL;
+        return err;
+    }
+
+    // get info from the inode
+    dno->g.size = fsw_u64_le_swap(dno->raw->size);
+    // TODO: check docs for 64-bit sized files
+    mode = fsw_u32_le_swap(dno->raw->mode);
+    if (S_ISREG(mode))
+        dno->g.type = FSW_DNODE_TYPE_FILE;
+    else if (S_ISDIR(mode))
+        dno->g.type = FSW_DNODE_TYPE_DIR;
+    else if (S_ISLNK(mode))
+        dno->g.type = FSW_DNODE_TYPE_SYMLINK;
+    else
+        dno->g.type = FSW_DNODE_TYPE_SPECIAL;
+
+    return FSW_SUCCESS;
+}
+
+static void fsw_btrfs_dnode_free(struct fsw_volume *volg, struct fsw_dnode *dnog)
+{
+    struct fsw_btrfs_dnode *dno = (struct fsw_btrfs_dnode *)dnog;
+    if (dno->raw)
+        FreePool(dno->raw);
+}
+
+static fsw_status_t fsw_btrfs_dnode_stat(struct fsw_volume *volg, struct fsw_dnode *dnog, struct fsw_dnode_stat *sb)
+{
+    struct fsw_btrfs_dnode *dno = (struct fsw_btrfs_dnode *)dnog;
+
+    /* slave device got empty root */
+    if(dno->raw == NULL) {
+        sb->used_bytes = 0;
+        fsw_store_time_posix(sb, FSW_DNODE_STAT_CTIME, 0);
+        fsw_store_time_posix(sb, FSW_DNODE_STAT_ATIME, 0);
+        fsw_store_time_posix(sb, FSW_DNODE_STAT_MTIME, 0);
+        return FSW_SUCCESS;
+    }
+    sb->used_bytes = fsw_u64_le_swap(dno->raw->nbytes);
+    fsw_store_time_posix(sb, FSW_DNODE_STAT_ATIME,
+            fsw_u64_le_swap(dno->raw->atime.sec));
+    fsw_store_time_posix(sb, FSW_DNODE_STAT_CTIME,
+            fsw_u64_le_swap(dno->raw->ctime.sec));
+    fsw_store_time_posix(sb, FSW_DNODE_STAT_MTIME,
+            fsw_u64_le_swap(dno->raw->mtime.sec));
+    fsw_store_attr_posix(sb, fsw_u32_le_swap(dno->raw->mode));
+
+    return FSW_SUCCESS;
+}
+
+static fsw_ssize_t grub_btrfs_lzo_decompress(char *ibuf, fsw_size_t isize, grub_off_t off,
+        char *obuf, fsw_size_t osize)
+{
+    uint32_t total_size, cblock_size;
+    fsw_size_t ret = 0;
+    unsigned char buf[GRUB_BTRFS_LZO_BLOCK_SIZE];
+    char *ibuf0 = ibuf;
+
+#define fsw_get_unaligned32(x) (*(uint32_t *)(x))
+    total_size = fsw_u32_le_swap (fsw_get_unaligned32(ibuf));
+    ibuf += sizeof (total_size);
+
+    if (isize < total_size)
+        return -1;
+
+    /* Jump forward to first block with requested data.  */
+    while (off >= GRUB_BTRFS_LZO_BLOCK_SIZE)
+    {
+        /* Don't let following uint32_t cross the page boundary.  */
+        if (((ibuf - ibuf0) & 0xffc) == 0xffc)
+            ibuf = ((ibuf - ibuf0 + 3) & ~3) + ibuf0;
+
+        cblock_size = fsw_u32_le_swap (fsw_get_unaligned32 (ibuf));
+        ibuf += sizeof (cblock_size);
+
+        if (cblock_size > GRUB_BTRFS_LZO_BLOCK_MAX_CSIZE)
+            return -1;
+
+        off -= GRUB_BTRFS_LZO_BLOCK_SIZE;
+        ibuf += cblock_size;
+    }
+
+    while (osize > 0)
+    {
+        lzo_uint usize = GRUB_BTRFS_LZO_BLOCK_SIZE;
+
+        /* Don't let following uint32_t cross the page boundary.  */
+        if (((ibuf - ibuf0) & 0xffc) == 0xffc)
+            ibuf = ((ibuf - ibuf0 + 3) & ~3) + ibuf0;
+
+        cblock_size = fsw_u32_le_swap (fsw_get_unaligned32 (ibuf));
+        ibuf += sizeof (cblock_size);
+
+        if (cblock_size > GRUB_BTRFS_LZO_BLOCK_MAX_CSIZE)
+            return -1;
+
+        /* Block partially filled with requested data.  */
+        if (off > 0 || osize < GRUB_BTRFS_LZO_BLOCK_SIZE)
+        {
+            fsw_size_t to_copy = GRUB_BTRFS_LZO_BLOCK_SIZE - off;
+
+            if (to_copy > osize)
+                to_copy = osize;
+
+            if (lzo1x_decompress_safe ((lzo_bytep)ibuf, cblock_size, (lzo_bytep)buf, &usize, NULL) != 0)
+                return -1;
+
+            if (to_copy > usize)
+                to_copy = usize;
+            fsw_memcpy(obuf, buf + off, to_copy);
+
+            osize -= to_copy;
+            ret += to_copy;
+            obuf += to_copy;
+            ibuf += cblock_size;
+            off = 0;
+            continue;
+        }
+
+        /* Decompress whole block directly to output buffer.  */
+        if (lzo1x_decompress_safe ((lzo_bytep)ibuf, cblock_size, (lzo_bytep)obuf, &usize, NULL) != 0)
+            return -1;
+
+        osize -= usize;
+        ret += usize;
+        obuf += usize;
+        ibuf += cblock_size;
+    }
+
+    return ret;
+}
+
+static fsw_status_t fsw_btrfs_get_extent(struct fsw_volume *volg, struct fsw_dnode *dnog,
+        struct fsw_extent *extent)
+{
+    struct fsw_btrfs_volume *vol = (struct fsw_btrfs_volume *)volg;
+    uint64_t ino = dnog->dnode_id;
+    uint64_t tree = dnog->tree_id;
+    uint64_t pos0 = extent->log_start << vol->sectorshift;
+    extent->type = FSW_EXTENT_TYPE_INVALID;
+    extent->log_count = 1;
+    uint64_t pos = pos0;
+    fsw_size_t csize;
+    fsw_status_t err;
+    uint64_t extoff;
+    char *buf = NULL;
+    uint64_t count;
+
+    /* slave device got empty root */
+    if (!vol->is_master)
+        return FSW_NOT_FOUND;
+
+    if (!vol->extent || vol->extstart > pos || vol->extino != ino
+            || vol->exttree != tree || vol->extend <= pos)
+    {
+        struct btrfs_key key_in, key_out;
+        uint64_t elemaddr;
+        fsw_size_t elemsize;
+
+        if(vol->extent) {
+            FreePool (vol->extent);
+            vol->extent = NULL;
+        }
+        key_in.object_id = ino;
+        key_in.type = GRUB_BTRFS_ITEM_TYPE_EXTENT_ITEM;
+        key_in.offset = fsw_u64_le_swap (pos);
+        err = lower_bound (vol, &key_in, &key_out, tree, &elemaddr, &elemsize, NULL, 0);
+        if (err)
+            return FSW_VOLUME_CORRUPTED;
+        if (key_out.object_id != ino
+                || key_out.type != GRUB_BTRFS_ITEM_TYPE_EXTENT_ITEM)
+        {
+            return FSW_VOLUME_CORRUPTED;
+        }
+        if ((fsw_ssize_t) elemsize < ((char *) &vol->extent->inl
+                    - (char *) vol->extent))
+        {
+            return FSW_VOLUME_CORRUPTED;
+        }
+        vol->extstart = fsw_u64_le_swap (key_out.offset);
+        vol->extsize = elemsize;
+        vol->extent = AllocatePool (elemsize);
+        vol->extino = ino;
+        vol->exttree = tree;
+        if (!vol->extent)
+            return FSW_OUT_OF_MEMORY;
+
+        err = fsw_btrfs_read_logical (vol, elemaddr, vol->extent, elemsize, 0, 1);
+        if (err)
+            return err;
+
+        vol->extend = vol->extstart + fsw_u64_le_swap (vol->extent->size);
+        if (vol->extent->type == GRUB_BTRFS_EXTENT_REGULAR
+                && (char *) vol->extent + elemsize
+                >= (char *) &vol->extent->filled + sizeof (vol->extent->filled))
+            vol->extend =
+                vol->extstart + fsw_u64_le_swap (vol->extent->filled);
+
+        DPRINT (L"btrfs: %lx +0x%lx\n", fsw_u64_le_swap (key_out.offset), fsw_u64_le_swap (vol->extent->size));
+        if (vol->extend <= pos)
+        {
+            return FSW_VOLUME_CORRUPTED;
+        }
+    }
+
+    csize = vol->extend - pos;
+    extoff = pos - vol->extstart;
+
+    if (vol->extent->encryption ||vol->extent->encoding)
+    {
+        return FSW_UNSUPPORTED;
+    }
+
+    switch(vol->extent->compression) {
+        case GRUB_BTRFS_COMPRESSION_LZO:
+        case GRUB_BTRFS_COMPRESSION_ZLIB:
+        case GRUB_BTRFS_COMPRESSION_NONE:
+            break;
+        default:
+            return FSW_UNSUPPORTED;
+    }
+
+    count = ( csize + vol->sectorsize - 1) >> vol->sectorshift;
+    switch (vol->extent->type)
+    {
+        case GRUB_BTRFS_EXTENT_INLINE:
+            buf = AllocatePool( count << vol->sectorshift);
+            if(!buf)
+                return FSW_OUT_OF_MEMORY;
+            if (vol->extent->compression == GRUB_BTRFS_COMPRESSION_ZLIB)
+            {
+                if (grub_zlib_decompress (vol->extent->inl, vol->extsize -
+                            ((uint8_t *) vol->extent->inl
+                             - (uint8_t *) vol->extent),
+                            extoff, buf, csize)
+                        != (fsw_ssize_t) csize)
+                {
+                    FreePool(buf);
+                    return FSW_VOLUME_CORRUPTED;
+                }
+            }
+            else if (vol->extent->compression == GRUB_BTRFS_COMPRESSION_LZO)
+            {
+                if (grub_btrfs_lzo_decompress(vol->extent->inl, vol->extsize -
+                            ((uint8_t *) vol->extent->inl
+                             - (uint8_t *) vol->extent),
+                            extoff, buf, csize)
+                        != (fsw_ssize_t) csize)
+                {
+                    FreePool(buf);
+                    return -FSW_VOLUME_CORRUPTED;
+                }
+            }
+            else
+                fsw_memcpy (buf, vol->extent->inl + extoff, csize);
+            break;
+
+        case GRUB_BTRFS_EXTENT_REGULAR:
+            if (!vol->extent->laddr)
+                break;
+
+            if (vol->extent->compression == GRUB_BTRFS_COMPRESSION_NONE)
+            {
+                if( count > 64 ) {
+                    count = 64;
+                    csize = count << vol->sectorshift;
+                }
+                buf = AllocatePool( count << vol->sectorshift);
+                if(!buf)
+                    return FSW_OUT_OF_MEMORY;
+                err = fsw_btrfs_read_logical (vol,
+                        fsw_u64_le_swap (vol->extent->laddr)
+                        + fsw_u64_le_swap (vol->extent->offset)
+                        + extoff, buf, csize, 0, 0);
+                if (err) {
+                    FreePool(buf);
+                    return err;
+                }
+                break;
+            }
+            if (vol->extent->compression != GRUB_BTRFS_COMPRESSION_NONE)
+            {
+                char *tmp;
+                uint64_t zsize;
+                fsw_ssize_t ret;
+
+                zsize = fsw_u64_le_swap (vol->extent->compressed_size);
+                tmp = AllocatePool (zsize);
+                if (!tmp)
+                    return -FSW_OUT_OF_MEMORY;
+                err = fsw_btrfs_read_logical (vol, fsw_u64_le_swap (vol->extent->laddr), tmp, zsize, 0, 0);
+                if (err)
+                {
+                    FreePool (tmp);
+                    return -FSW_VOLUME_CORRUPTED;
+                }
+
+                buf = AllocatePool( count << vol->sectorshift);
+                if(!buf) {
+                    FreePool(tmp);
+                    return FSW_OUT_OF_MEMORY;
+                }
+
+                if (vol->extent->compression == GRUB_BTRFS_COMPRESSION_ZLIB)
+                {
+                    ret = grub_zlib_decompress (tmp, zsize, extoff
+                            + fsw_u64_le_swap (vol->extent->offset),
+                            buf, csize);
+                }
+                else if (vol->extent->compression == GRUB_BTRFS_COMPRESSION_LZO)
+                    ret = grub_btrfs_lzo_decompress (tmp, zsize, extoff
+                            + fsw_u64_le_swap (vol->extent->offset),
+                            buf, csize);
+                else
+                    ret = -1;
+
+                FreePool (tmp);
+
+                if (ret != (fsw_ssize_t) csize) {
+                    FreePool(tmp);
+                    return -FSW_VOLUME_CORRUPTED;
+                }
+
+                break;
+            }
+            break;
+        default:
+            return -FSW_VOLUME_CORRUPTED;
+    }
+
+    extent->log_count = count;
+    if(buf) {
+        if(csize < (count << vol->sectorshift))
+            fsw_memzero( buf + csize, (count << vol->sectorshift) - csize);
+        extent->buffer = buf;
+        extent->type = FSW_EXTENT_TYPE_BUFFER;
+    } else {
+        extent->buffer = NULL;
+        extent->type = FSW_EXTENT_TYPE_SPARSE;
+    }
+    return FSW_SUCCESS;
+}
+
+static fsw_status_t fsw_btrfs_readlink(struct fsw_volume *volg, struct fsw_dnode *dnog,
+        struct fsw_string *link_target)
+{
+    struct fsw_btrfs_volume *vol = (struct fsw_btrfs_volume *)volg;
+    struct fsw_btrfs_dnode *dno = (struct fsw_btrfs_dnode *)dnog;
+    int i;
+    fsw_status_t    status;
+    struct fsw_string s;
+    char *tmp;
+
+    if (dno->g.size > FSW_PATH_MAX)
+        return FSW_VOLUME_CORRUPTED;
+
+    tmp = AllocatePool(dno->g.size);
+    if(!tmp)
+        return FSW_OUT_OF_MEMORY;
+
+    i = 0;
+    do {
+        struct fsw_extent extent;
+        int size;
+        extent.log_start = i;
+        status = fsw_btrfs_get_extent(volg, dnog, &extent);
+        if(status || extent.type != FSW_EXTENT_TYPE_BUFFER) {
+            FreePool(tmp);
+            if(extent.buffer)
+                FreePool(extent.buffer);
+            return FSW_VOLUME_CORRUPTED;
+        }
+        size = extent.log_count << vol->sectorshift;
+        if(size > (dno->g.size - (i<<vol->sectorshift)))
+            size = dno->g.size - (i<<vol->sectorshift);
+        fsw_memcpy(tmp + (i<<vol->sectorshift), extent.buffer, size);
+        FreePool(extent.buffer);
+        i += extent.log_count;
+    } while( (i << vol->sectorshift) < dno->g.size);
+
+    s.type = FSW_STRING_TYPE_UTF8;
+    s.size = s.len = (int)dno->g.size;
+    s.data = tmp;
+    status = fsw_strdup_coerce(link_target, volg->host_string_type, &s);
+    FreePool(tmp);
+
+    return FSW_SUCCESS;
+}
+
+static fsw_status_t fsw_btrfs_lookup_dir_item(struct fsw_btrfs_volume *vol,
+        uint64_t tree_id, uint64_t object_id,
+        struct fsw_string *lookup_name,
+        struct btrfs_dir_item **direl_buf,
+        struct btrfs_dir_item **direl_out
+        )
+{
+    uint64_t elemaddr;
+    fsw_size_t elemsize;
+    fsw_size_t allocated = 0;
+    struct btrfs_key key;
+    struct btrfs_key key_out;
+    struct btrfs_dir_item *cdirel;
+    fsw_status_t err;
+
+    *direl_buf = NULL;
+
+    key.object_id = object_id;
+    key.type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM;
+    key.offset = fsw_u64_le_swap (~grub_getcrc32c (1, lookup_name->data, lookup_name->size));
+
+    err = lower_bound (vol, &key, &key_out, tree_id, &elemaddr, &elemsize, NULL, 0);
+    if (err)
+        return err;
+
+    if (key_cmp (&key, &key_out) != 0)
+        return FSW_NOT_FOUND;
+
+    if (elemsize > allocated)
+    {
+        allocated = 2 * elemsize;
+        if(*direl_buf)
+            FreePool (*direl_buf);
+        *direl_buf = AllocatePool (allocated + 1);
+        if (!*direl_buf)
+            return FSW_OUT_OF_MEMORY;
+    }
+
+    err = fsw_btrfs_read_logical (vol, elemaddr, *direl_buf, elemsize, 0, 1);
+    if (err)
+        return err;
+
+    for (cdirel = *direl_buf;
+            (uint8_t *) cdirel - (uint8_t *) *direl_buf < (fsw_ssize_t) elemsize;
+            cdirel = (void *) ((uint8_t *) (*direl_buf + 1)
+                + fsw_u16_le_swap (cdirel->n)
+                + fsw_u16_le_swap (cdirel->m)))
+    {
+        if (lookup_name->size == fsw_u16_le_swap (cdirel->n)
+                && fsw_memeq (cdirel->name, lookup_name->data, lookup_name->size))
+            break;
+    }
+    if ((uint8_t *) cdirel - (uint8_t *) *direl_buf >= (fsw_ssize_t) elemsize)
+        return FSW_NOT_FOUND;
+
+    *direl_out = cdirel;
+    return FSW_SUCCESS;
+}
+
+static fsw_status_t fsw_btrfs_get_root_tree(
+        struct fsw_btrfs_volume *vol,
+        struct btrfs_key *key_in,
+        uint64_t *tree_out)
+{
+    fsw_status_t err;
+    struct btrfs_root_item ri;
+    struct btrfs_key key_out;
+    uint64_t elemaddr;
+    fsw_size_t elemsize;
+
+    err = lower_bound (vol, key_in, &key_out, vol->root_tree, &elemaddr, &elemsize, NULL, 0);
+    if (err)
+        return err;
+
+    if (key_in->object_id != key_out.object_id || key_in->type != key_out.type)
+        return FSW_NOT_FOUND;
+
+    err = fsw_btrfs_read_logical (vol, elemaddr, &ri, sizeof (ri), 0, 1);
+    if (err)
+        return err;
+
+    *tree_out = ri.tree;
+    return FSW_SUCCESS;
+}
+
+static fsw_status_t fsw_btrfs_get_sub_dnode(
+        struct fsw_btrfs_volume *vol,
+        struct fsw_btrfs_dnode *dno,
+        struct btrfs_dir_item *cdirel,
+        struct fsw_string *name,
+        struct fsw_dnode **child_dno_out)
+{
+    fsw_status_t err;
+    int child_type;
+    uint64_t tree_id = dno->g.tree_id;
+    uint64_t child_id;
+
+    switch (cdirel->key.type)
+    {
+        case GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM:
+            err = fsw_btrfs_get_root_tree (vol, &cdirel->key, &tree_id);
+            if (err)
+                return err;
+
+            child_type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY;
+            child_id = fsw_u64_le_swap(GRUB_BTRFS_OBJECT_ID_CHUNK);
+            break;
+        case GRUB_BTRFS_ITEM_TYPE_INODE_ITEM:
+            child_type = cdirel->type;
+            child_id = cdirel->key.object_id;
+            break;
+
+        default:
+            DPRINT (L"btrfs: unrecognised object type 0x%x", cdirel->key.type);
+            return FSW_VOLUME_CORRUPTED;
+    }
+
+    switch(child_type) {
+        case GRUB_BTRFS_DIR_ITEM_TYPE_REGULAR:
+            child_type = FSW_DNODE_TYPE_FILE;
+            break;
+        case GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY:
+            child_type = FSW_DNODE_TYPE_DIR;
+            break;
+        case GRUB_BTRFS_DIR_ITEM_TYPE_SYMLINK:
+            child_type = FSW_DNODE_TYPE_SYMLINK;
+            break;
+        default:
+            child_type = FSW_DNODE_TYPE_SPECIAL;
+            break;
+    }
+    return fsw_dnode_create_with_tree(&dno->g, tree_id, child_id, child_type, name, child_dno_out);
+}
+
+static fsw_status_t fsw_btrfs_dir_lookup(struct fsw_volume *volg, struct fsw_dnode *dnog,
+        struct fsw_string *lookup_name, struct fsw_dnode **child_dno_out)
+{
+    struct fsw_btrfs_volume *vol = (struct fsw_btrfs_volume *)volg;
+    struct fsw_btrfs_dnode *dno = (struct fsw_btrfs_dnode *)dnog;
+    fsw_status_t err;
+    struct fsw_string s;
+
+    *child_dno_out = NULL;
+
+    /* slave device got empty root */
+    if (!vol->is_master)
+        return FSW_NOT_FOUND;
+
+    err = fsw_strdup_coerce(&s, FSW_STRING_TYPE_UTF8, lookup_name);
+    if(err)
+        return err;
+
+    /* treat '...' under root as top root */
+    if(dnog == volg->root && s.size == 3 && ((char *)s.data)[0]=='.' && ((char *)s.data)[1]=='.' && ((char *)s.data)[2]=='.')
+    {
+        fsw_strfree (&s);
+        if(dnog->tree_id == vol->top_tree) {
+            fsw_dnode_retain(dnog);
+            *child_dno_out = dnog;
+            return FSW_SUCCESS;
+        }
+        return fsw_dnode_create_with_tree(dnog,
+                vol->top_tree, fsw_u64_le_swap(GRUB_BTRFS_OBJECT_ID_CHUNK),
+                FSW_DNODE_TYPE_DIR, lookup_name, child_dno_out);
+    }
+    struct btrfs_dir_item *direl=NULL, *cdirel;
+    err = fsw_btrfs_lookup_dir_item(vol, dnog->tree_id, dnog->dnode_id, &s, &direl, &cdirel);
+    if(!err)
+        err = fsw_btrfs_get_sub_dnode(vol, dno, cdirel, lookup_name, child_dno_out);
+    if(direl)
+        FreePool (direl);
+    fsw_strfree (&s);
+    return err;
+}
+
+static fsw_status_t fsw_btrfs_get_default_root(struct fsw_btrfs_volume *vol, uint64_t root_dir_objectid)
+{
+    fsw_status_t err;
+    struct fsw_string s;
+    struct btrfs_dir_item *direl=NULL, *cdirel;
+    uint64_t default_tree_id = 0;
+    struct btrfs_key top_root_key;
+
+    /* Get to top tree id */
+    top_root_key.object_id = fsw_u64_le_swap(5UL);
+    top_root_key.type = GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM;
+    top_root_key.offset = -1LL;
+    err = fsw_btrfs_get_root_tree (vol, &top_root_key, &vol->top_tree);
+    if (err)
+        return err;
+
+    s.type = FSW_STRING_TYPE_UTF8;
+    s.data = "default";
+    s.size = 7;
+    err = fsw_btrfs_lookup_dir_item(vol, vol->root_tree, root_dir_objectid, &s, &direl, &cdirel);
+
+    /* if "default" is failed or invalid, use top tree */
+    if (err || /* failed */
+            cdirel->type != GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY || /* not dir */
+            cdirel->key.type != GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM || /* not tree */
+            cdirel->key.object_id == fsw_u64_le_swap(5UL) || /* same as top */
+            (err = fsw_btrfs_get_root_tree (vol, &cdirel->key, &default_tree_id)))
+        default_tree_id = vol->top_tree;
+
+    if (!err)
+        err = fsw_dnode_create_root_with_tree(&vol->g, default_tree_id,
+                fsw_u64_le_swap (GRUB_BTRFS_OBJECT_ID_CHUNK), &vol->g.root);
+    if (direl)
+        FreePool (direl);
+    return err;
+}
+
+static fsw_status_t fsw_btrfs_dir_read(struct fsw_volume *volg, struct fsw_dnode *dnog,
+        struct fsw_shandle *shand, struct fsw_dnode **child_dno_out)
+{
+    struct fsw_btrfs_volume *vol = (struct fsw_btrfs_volume *)volg;
+    struct fsw_btrfs_dnode *dno = (struct fsw_btrfs_dnode *)dnog;
+    fsw_status_t err;
+
+    struct btrfs_key key_in, key_out;
+    uint64_t elemaddr;
+    fsw_size_t elemsize;
+    fsw_size_t allocated = 0;
+    struct btrfs_dir_item *direl = NULL;
+    struct fsw_btrfs_leaf_descriptor desc;
+    int r = 0;
+    uint64_t tree = dnog->tree_id;
+
+    /* slave device got empty root */
+    if (!vol->is_master)
+        return FSW_NOT_FOUND;
+
+    key_in.object_id = dnog->dnode_id;
+    key_in.type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM;
+    key_in.offset = shand->pos;
+
+    if((int64_t)key_in.offset == -1LL)
+    {
+        return FSW_NOT_FOUND;
+    }
+
+    err = lower_bound (vol, &key_in, &key_out, tree, &elemaddr, &elemsize, &desc, 0);
+    if (err) {
+        return err;
+    }
+
+    DPRINT(L"key_in %lx:%x:%lx out %lx:%x:%lx elem %lx+%lx\n",
+            key_in.object_id, key_in.type, key_in.offset,
+            key_out.object_id, key_out.type, key_out.offset,
+            elemaddr, elemsize);
+    if (key_out.type != GRUB_BTRFS_ITEM_TYPE_DIR_ITEM ||
+            key_out.object_id != key_in.object_id)
+    {
+        r = next (vol, &desc, &elemaddr, &elemsize, &key_out);
+        if (r <= 0)
+            goto out;
+        DPRINT(L"next out %lx:%x:%lx\n",
+                key_out.object_id, key_out.type, key_out.offset, elemaddr, elemsize);
+    }
+    if (key_out.type == GRUB_BTRFS_ITEM_TYPE_DIR_ITEM &&
+            key_out.object_id == key_in.object_id &&
+            fsw_u64_le_swap(key_out.offset) <= fsw_u64_le_swap(key_in.offset))
+    {
+        r = next (vol, &desc, &elemaddr, &elemsize, &key_out);
+        if (r <= 0)
+            goto out;
+        DPRINT(L"next out %lx:%x:%lx\n",
+                key_out.object_id, key_out.type, key_out.offset, elemaddr, elemsize);
+    }
+
+    do
+    {
+        struct btrfs_dir_item *cdirel;
+        if (key_out.type != GRUB_BTRFS_ITEM_TYPE_DIR_ITEM ||
+                key_out.object_id != key_in.object_id)
+        {
+            r = 0;
+            break;
+        }
+        if (elemsize > allocated)
+        {
+            allocated = 2 * elemsize;
+            if(direl)
+                FreePool (direl);
+            direl = AllocatePool (allocated + 1);
+            if (!direl)
+            {
+                r = -FSW_OUT_OF_MEMORY;
+                break;
+            }
+        }
+
+        err = fsw_btrfs_read_logical (vol, elemaddr, direl, elemsize, 0, 1);
+        if (err)
+        {
+            r = -err;
+            break;
+        }
+
+        for (cdirel = direl;
+                (uint8_t *) cdirel - (uint8_t *) direl
+                < (fsw_ssize_t) elemsize;
+                cdirel = (void *) ((uint8_t *) (direl + 1)
+                    + fsw_u16_le_swap (cdirel->n)
+                    + fsw_u16_le_swap (cdirel->m)))
+        {
+            struct fsw_string s;
+            s.type = FSW_STRING_TYPE_UTF8;
+            s.size = s.len = fsw_u16_le_swap (cdirel->n);
+            s.data = cdirel->name;
+            DPRINT(L"item key %lx:%x%lx, type %lx, namelen=%lx\n",
+                    cdirel->key.object_id, cdirel->key.type, cdirel->key.offset, cdirel->type, s.size);
+            if(!err) {
+                err = fsw_btrfs_get_sub_dnode(vol, dno, cdirel, &s, child_dno_out);
+                if(direl)
+                    FreePool (direl);
+                free_iterator (&desc);
+                shand->pos = key_out.offset;
+                return FSW_SUCCESS;
+            }
+        }
+        r = next (vol, &desc, &elemaddr, &elemsize, &key_out);
+        DPRINT(L"next2 out %lx:%x:%lx\n",
+                key_out.object_id, key_out.type, key_out.offset, elemaddr, elemsize);
+    }
+    while (r > 0);
+
+out:
+    if(direl)
+        FreePool (direl);
+    free_iterator (&desc);
+
+    r = r < 0 ? -r : FSW_NOT_FOUND;
+    return r;
+}
+
+//
+// Dispatch Table
+//
+
+struct fsw_fstype_table   FSW_FSTYPE_TABLE_NAME(btrfs) = {
+    { FSW_STRING_TYPE_UTF8, 5, 5, "btrfs" },
+    sizeof(struct fsw_btrfs_volume),
+    sizeof(struct fsw_btrfs_dnode),
+
+    fsw_btrfs_volume_mount,
+    fsw_btrfs_volume_free,
+    fsw_btrfs_volume_stat,
+    fsw_btrfs_dnode_fill,
+    fsw_btrfs_dnode_free,
+    fsw_btrfs_dnode_stat,
+    fsw_btrfs_get_extent,
+    fsw_btrfs_dir_lookup,
+    fsw_btrfs_dir_read,
+    fsw_btrfs_readlink,
+};
+
diff --git a/filesystems/fsw_core.c b/filesystems/fsw_core.c
new file mode 100644 (file)
index 0000000..1ecb75f
--- /dev/null
@@ -0,0 +1,964 @@
+/* $Id: fsw_core.c 29125 2010-05-06 09:43:05Z vboxsync $ */
+/** @file
+ * fsw_core.c - Core file system wrapper abstraction layer code.
+ */
+
+/*-
+ * This code is based on:
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsw_core.h"
+
+
+// functions
+
+static void fsw_blockcache_free(struct fsw_volume *vol);
+
+#define MAX_CACHE_LEVEL (5)
+
+
+/**
+ * Mount a volume with a given file system driver. This function is called by the
+ * host driver to make a volume accessible. The file system driver to use is specified
+ * by a pointer to its dispatch table. The file system driver will look at the
+ * data on the volume to determine if it can read the format. If the volume is found
+ * unsuitable, FSW_UNSUPPORTED is returned.
+ *
+ * If this function returns FSW_SUCCESS, *vol_out points at a valid volume data
+ * structure. The caller must release it later by calling fsw_unmount.
+ *
+ * If this function returns an error status, the caller only needs to clean up its
+ * own buffers that may have been allocated through the read_block interface.
+ */
+
+fsw_status_t fsw_mount(void *host_data,
+                       struct fsw_host_table *host_table,
+                       struct fsw_fstype_table *fstype_table,
+                       struct fsw_volume **vol_out)
+{
+    fsw_status_t    status;
+    struct fsw_volume *vol;
+
+    // allocate memory for the structure
+    status = fsw_alloc_zero(fstype_table->volume_struct_size, (void **)&vol);
+    if (status)
+        return status;
+
+    // initialize fields
+    vol->phys_blocksize = 512;
+    vol->log_blocksize  = 512;
+    vol->label.type     = FSW_STRING_TYPE_EMPTY;
+    vol->host_data      = host_data;
+    vol->host_table     = host_table;
+    vol->fstype_table   = fstype_table;
+    vol->host_string_type = host_table->native_string_type;
+
+    // let the fs driver mount the file system
+    status = vol->fstype_table->volume_mount(vol);
+    if (status)
+        goto errorexit;
+
+    // TODO: anything else?
+
+    *vol_out = vol;
+    return FSW_SUCCESS;
+
+errorexit:
+    fsw_unmount(vol);
+    return status;
+}
+
+/**
+ * Unmount a volume by releasing all memory associated with it. This function is
+ * called by the host driver when a volume is no longer needed. It is also called
+ * by the core after a failed mount to clean up any allocated memory.
+ *
+ * Note that all dnodes must have been released before calling this function.
+ */
+
+void fsw_unmount(struct fsw_volume *vol)
+{
+    if (vol->root)
+        fsw_dnode_release(vol->root);
+    // TODO: check that no other dnodes are still around
+
+    vol->fstype_table->volume_free(vol);
+
+    fsw_blockcache_free(vol);
+    fsw_strfree(&vol->label);
+    fsw_free(vol);
+}
+
+/**
+ * Get in-depth information on the volume. This function can be called by the host
+ * driver to get additional information on the volume.
+ */
+
+fsw_status_t fsw_volume_stat(struct fsw_volume *vol, struct fsw_volume_stat *sb)
+{
+    return vol->fstype_table->volume_stat(vol, sb);
+}
+
+/**
+ * Set the physical and logical block sizes of the volume. This functions is called by
+ * the file system driver to announce the block sizes it wants to use for accessing
+ * the disk (physical) and for addressing file contents (logical).
+ * Usually both sizes will be the same but there may be file systems that need to access
+ * metadata at a smaller block size than the allocation unit for files.
+ *
+ * Calling this function causes the block cache to be dropped. All pointers returned
+ * from fsw_block_get become invalid. This function should only be called while
+ * mounting the file system, not as a part of file access operations.
+ *
+ * Both sizes are measured in bytes, must be powers of 2, and must not be smaller
+ * than 512 bytes. The logical block size cannot be smaller than the physical block size.
+ */
+
+void fsw_set_blocksize(struct fsw_volume *vol, fsw_u32 phys_blocksize, fsw_u32 log_blocksize)
+{
+    // TODO: Check the sizes. Both must be powers of 2. log_blocksize must not be smaller than
+    //  phys_blocksize.
+
+    // drop core block cache if present
+    fsw_blockcache_free(vol);
+
+    // signal host driver to drop caches etc.
+    vol->host_table->change_blocksize(vol,
+                                      vol->phys_blocksize, vol->log_blocksize,
+                                      phys_blocksize, log_blocksize);
+
+    vol->phys_blocksize = phys_blocksize;
+    vol->log_blocksize = log_blocksize;
+}
+
+/**
+ * Get a block of data from the disk. This function is called by the file system driver
+ * or by core functions. It calls through to the host driver's device access routine.
+ * Given a physical block number, it reads the block into memory (or fetches it from the
+ * block cache) and returns the address of the memory buffer. The caller should provide
+ * an indication of how important the block is in the cache_level parameter. Blocks with
+ * a low level are purged first. Some suggestions for cache levels:
+ *
+ *  - 0: File data
+ *  - 1: Directory data, symlink data
+ *  - 2: File system metadata
+ *  - 3..5: File system metadata with a high rate of access
+ *
+ * If this function returns successfully, the returned data pointer is valid until the
+ * caller calls fsw_block_release.
+ */
+
+fsw_status_t fsw_block_get(struct VOLSTRUCTNAME *vol, fsw_u64 phys_bno, fsw_u32 cache_level, void **buffer_out)
+{
+    fsw_status_t    status;
+    fsw_u32         i, discard_level, new_bcache_size;
+    struct fsw_blockcache *new_bcache;
+
+    // TODO: allow the host driver to do its own caching; just call through if
+    //  the appropriate function pointers are set
+
+    if (cache_level > MAX_CACHE_LEVEL)
+        cache_level = MAX_CACHE_LEVEL;
+
+    if (vol->bcache_size > 0 && vol->bcache == NULL) {
+        /* driver set the initial cache size */
+        status = fsw_alloc(vol->bcache_size * sizeof(struct fsw_blockcache), &vol->bcache);
+        if(status)
+            return status;
+        for (i = 0; i < vol->bcache_size; i++) {
+            vol->bcache[i].refcount = 0;
+            vol->bcache[i].cache_level = 0;
+            vol->bcache[i].phys_bno = (fsw_u64)FSW_INVALID_BNO;
+            vol->bcache[i].data = NULL;
+        }
+        i = 0;
+        goto miss;
+    }
+
+    // check block cache
+    for (i = 0; i < vol->bcache_size; i++) {
+        if (vol->bcache[i].phys_bno == phys_bno) {
+            // cache hit!
+            if (vol->bcache[i].cache_level < cache_level)
+                vol->bcache[i].cache_level = cache_level;  // promote the entry
+            vol->bcache[i].refcount++;
+            *buffer_out = vol->bcache[i].data;
+            return FSW_SUCCESS;
+        }
+    }
+
+    // find a free entry in the cache table
+    for (i = 0; i < vol->bcache_size; i++) {
+        if (vol->bcache[i].phys_bno == (fsw_u64)FSW_INVALID_BNO)
+            break;
+    }
+    if (i >= vol->bcache_size) {
+        for (discard_level = 0; discard_level <= MAX_CACHE_LEVEL; discard_level++) {
+            for (i = 0; i < vol->bcache_size; i++) {
+                if (vol->bcache[i].refcount == 0 && vol->bcache[i].cache_level <= discard_level)
+                    break;
+            }
+            if (i < vol->bcache_size)
+                break;
+        }
+    }
+    if (i >= vol->bcache_size) {
+        // enlarge / create the cache
+        if (vol->bcache_size < 16)
+            new_bcache_size = 16;
+        else
+            new_bcache_size = vol->bcache_size << 1;
+        status = fsw_alloc(new_bcache_size * sizeof(struct fsw_blockcache), &new_bcache);
+        if (status)
+            return status;
+        if (vol->bcache_size > 0)
+            fsw_memcpy(new_bcache, vol->bcache, vol->bcache_size * sizeof(struct fsw_blockcache));
+        for (i = vol->bcache_size; i < new_bcache_size; i++) {
+            new_bcache[i].refcount = 0;
+            new_bcache[i].cache_level = 0;
+            new_bcache[i].phys_bno = (fsw_u64)FSW_INVALID_BNO;
+            new_bcache[i].data = NULL;
+        }
+        i = vol->bcache_size;
+
+        // switch caches
+        if (vol->bcache != NULL)
+            fsw_free(vol->bcache);
+        vol->bcache = new_bcache;
+        vol->bcache_size = new_bcache_size;
+    }
+    vol->bcache[i].phys_bno = (fsw_u64)FSW_INVALID_BNO;
+miss:
+
+    // read the data
+    if (vol->bcache[i].data == NULL) {
+        status = fsw_alloc(vol->phys_blocksize, &vol->bcache[i].data);
+        if (status)
+            return status;
+    }
+    status = vol->host_table->read_block(vol, phys_bno, vol->bcache[i].data);
+    if (status)
+        return status;
+
+    vol->bcache[i].phys_bno = phys_bno;
+    vol->bcache[i].cache_level = cache_level;
+    vol->bcache[i].refcount = 1;
+    *buffer_out = vol->bcache[i].data;
+    return FSW_SUCCESS;
+}
+
+/**
+ * Releases a disk block. This function must be called to release disk blocks returned
+ * from fsw_block_get.
+ */
+
+void fsw_block_release(struct VOLSTRUCTNAME *vol, fsw_u64 phys_bno, void *buffer)
+{
+    fsw_u32 i;
+
+    // TODO: allow the host driver to do its own caching; just call through if
+    //  the appropriate function pointers are set
+
+    // update block cache
+    for (i = 0; i < vol->bcache_size; i++) {
+        if (vol->bcache[i].phys_bno == phys_bno && vol->bcache[i].refcount > 0)
+            vol->bcache[i].refcount--;
+    }
+}
+
+/**
+ * Release the block cache. Called internally when changing block sizes and when
+ * unmounting the volume. It frees all data occupied by the generic block cache.
+ */
+
+static void fsw_blockcache_free(struct fsw_volume *vol)
+{
+    fsw_u32 i;
+
+    for (i = 0; i < vol->bcache_size; i++) {
+        if (vol->bcache[i].data != NULL)
+            fsw_free(vol->bcache[i].data);
+    }
+    if (vol->bcache != NULL) {
+        fsw_free(vol->bcache);
+        vol->bcache = NULL;
+    }
+    vol->bcache_size = 0;
+}
+
+/**
+ * Add a new dnode to the list of known dnodes. This internal function is used when a
+ * dnode is created to add it to the dnode list that is used to search for existing
+ * dnodes by id.
+ */
+
+static void fsw_dnode_register(struct fsw_volume *vol, struct fsw_dnode *dno)
+{
+    dno->next = vol->dnode_head;
+    if (vol->dnode_head != NULL)
+        vol->dnode_head->prev = dno;
+    dno->prev = NULL;
+    vol->dnode_head = dno;
+}
+
+/**
+ * Create a dnode representing the root directory. This function is called by the file system
+ * driver while mounting the file system. The root directory is special because it has no parent
+ * dnode, its name is defined to be empty, and its type is also fixed. Otherwise, this functions
+ * behaves in the same way as fsw_dnode_create.
+ */
+
+fsw_status_t fsw_dnode_create_root_with_tree(struct fsw_volume *vol, fsw_u64 tree_id, fsw_u64 dnode_id, struct fsw_dnode **dno_out)
+{
+    fsw_status_t    status;
+    struct fsw_dnode *dno;
+
+    // allocate memory for the structure
+    status = fsw_alloc_zero(vol->fstype_table->dnode_struct_size, (void **)&dno);
+    if (status)
+        return status;
+
+    // fill the structure
+    dno->vol = vol;
+    dno->parent = NULL;
+    dno->tree_id = tree_id;
+    dno->dnode_id = dnode_id;
+    dno->type = FSW_DNODE_TYPE_DIR;
+    dno->refcount = 1;
+    dno->name.type = FSW_STRING_TYPE_EMPTY;
+    // TODO: instead, call a function to create an empty string in the native string type
+
+    fsw_dnode_register(vol, dno);
+
+    *dno_out = dno;
+    return FSW_SUCCESS;
+}
+
+fsw_status_t fsw_dnode_create_root(struct fsw_volume *vol, fsw_u64 dnode_id, struct fsw_dnode **dno_out)
+{
+       return fsw_dnode_create_root_with_tree( vol, 0, dnode_id, dno_out);
+}
+/**
+ * Create a new dnode representing a file system object. This function is called by
+ * the file system driver in response to directory lookup or read requests. Note that
+ * if there already is a dnode with the given dnode_id on record, then no new object
+ * is created. Instead, the existing dnode is returned and its reference count
+ * increased. All other parameters are ignored in this case.
+ *
+ * The type passed into this function may be FSW_DNODE_TYPE_UNKNOWN. It is sufficient
+ * to fill the type field during the dnode_fill call.
+ *
+ * The name parameter must describe a string with the object's name. A copy will be
+ * stored in the dnode structure for future reference. The name will not be used to
+ * shortcut directory lookups, but may be used to reconstruct paths.
+ *
+ * If the function returns successfully, *dno_out contains a pointer to the dnode
+ * that must be released by the caller with fsw_dnode_release.
+ */
+
+fsw_status_t fsw_dnode_create_with_tree(struct fsw_dnode *parent_dno, fsw_u64 tree_id, fsw_u64 dnode_id, int type,
+                              struct fsw_string *name, struct fsw_dnode **dno_out)
+{
+    fsw_status_t    status;
+    struct fsw_volume *vol = parent_dno->vol;
+    struct fsw_dnode *dno;
+
+    // check if we already have a dnode with the same id
+    for (dno = vol->dnode_head; dno; dno = dno->next) {
+        if (dno->dnode_id == dnode_id && dno->tree_id == tree_id) {
+            fsw_dnode_retain(dno);
+            *dno_out = dno;
+            return FSW_SUCCESS;
+        }
+    }
+
+    // allocate memory for the structure
+    status = fsw_alloc_zero(vol->fstype_table->dnode_struct_size, (void **)&dno);
+    if (status)
+        return status;
+
+    // fill the structure
+    dno->vol = vol;
+    dno->parent = parent_dno;
+    fsw_dnode_retain(dno->parent);
+    dno->tree_id = tree_id;
+    dno->dnode_id = dnode_id;
+    dno->type = type;
+    dno->refcount = 1;
+    status = fsw_strdup_coerce(&dno->name, vol->host_table->native_string_type, name);
+    if (status) {
+        fsw_free(dno);
+        return status;
+    }
+
+    fsw_dnode_register(vol, dno);
+
+    *dno_out = dno;
+    return FSW_SUCCESS;
+}
+
+fsw_status_t fsw_dnode_create(struct fsw_dnode *parent_dno, fsw_u64 dnode_id, int type,
+                              struct fsw_string *name, struct fsw_dnode **dno_out)
+{
+       return fsw_dnode_create_with_tree(parent_dno, 0, dnode_id, type, name, dno_out);
+}
+
+/**
+ * Increases the reference count of a dnode. This must be balanced with
+ * fsw_dnode_release calls. Note that some dnode functions return a retained
+ * dnode pointer to their caller.
+ */
+
+void fsw_dnode_retain(struct fsw_dnode *dno)
+{
+    dno->refcount++;
+}
+
+/**
+ * Release a dnode pointer, deallocating it if this was the last reference.
+ * This function decrements the reference counter of the dnode. If the counter
+ * reaches zero, the dnode is freed. Since the parent dnode is released
+ * during that process, this function may cause it to be freed, too.
+ */
+
+void fsw_dnode_release(struct fsw_dnode *dno)
+{
+    struct fsw_volume *vol = dno->vol;
+    struct fsw_dnode *parent_dno;
+
+    dno->refcount--;
+
+    if (dno->refcount == 0) {
+        parent_dno = dno->parent;
+
+        // de-register from volume's list
+        if (dno->next)
+            dno->next->prev = dno->prev;
+        if (dno->prev)
+            dno->prev->next = dno->next;
+        if (vol->dnode_head == dno)
+            vol->dnode_head = dno->next;
+
+        // run fstype-specific cleanup
+        vol->fstype_table->dnode_free(vol, dno);
+
+        fsw_strfree(&dno->name);
+        fsw_free(dno);
+
+        // release our pointer to the parent, possibly deallocating it, too
+        if (parent_dno)
+            fsw_dnode_release(parent_dno);
+    }
+}
+
+/**
+ * Get full information about a dnode from disk. This function is called by the host
+ * driver as well as by the core functions. Some file systems defer reading full
+ * information on a dnode until it is actually needed (i.e. separation between
+ * directory and inode information). This function makes sure that all information
+ * is available in the dnode structure. The following fields may not have a correct
+ * value until fsw_dnode_fill has been called:
+ *
+ * type, size
+ */
+
+fsw_status_t fsw_dnode_fill(struct fsw_dnode *dno)
+{
+    // TODO: check a flag right here, call fstype's dnode_fill only once per dnode
+
+    return dno->vol->fstype_table->dnode_fill(dno->vol, dno);
+}
+
+/**
+ * Get extended information about a dnode. This function can be called by the host
+ * driver to get a full compliment of information about a dnode in addition to the
+ * fields of the fsw_dnode structure itself.
+ *
+ * Some data requires host-specific conversion to be useful (i.e. timestamps) and
+ * will be passed to callback functions instead of being written into the structure.
+ * These callbacks must be filled in by the caller.
+ */
+
+fsw_status_t fsw_dnode_stat(struct fsw_dnode *dno, struct fsw_dnode_stat *sb)
+{
+    fsw_status_t    status;
+
+    status = fsw_dnode_fill(dno);
+    if (status)
+        return status;
+
+    sb->used_bytes = 0;
+    status = dno->vol->fstype_table->dnode_stat(dno->vol, dno, sb);
+    if (!status && !sb->used_bytes)
+        sb->used_bytes = FSW_U64_DIV(dno->size + dno->vol->log_blocksize - 1, dno->vol->log_blocksize);
+    return status;
+}
+
+/**
+ * Lookup a directory entry by name. This function is called by the host driver.
+ * Given a directory dnode and a file name, it looks up the named entry in the
+ * directory.
+ *
+ * If the dnode is not a directory, the call will fail. The caller is responsible for
+ * resolving symbolic links before calling this function.
+ *
+ * If the function returns FSW_SUCCESS, *child_dno_out points to the requested directory
+ * entry. The caller must call fsw_dnode_release on it.
+ */
+
+fsw_status_t fsw_dnode_lookup(struct fsw_dnode *dno,
+                              struct fsw_string *lookup_name, struct fsw_dnode **child_dno_out)
+{
+    fsw_status_t    status;
+
+    status = fsw_dnode_fill(dno);
+    if (status)
+        return status;
+    if (dno->type != FSW_DNODE_TYPE_DIR)
+        return FSW_UNSUPPORTED;
+
+    return dno->vol->fstype_table->dir_lookup(dno->vol, dno, lookup_name, child_dno_out);
+}
+
+/**
+ * Find a file system object by path. This function is called by the host driver.
+ * Given a directory dnode and a relative or absolute path, it walks the directory
+ * tree until it finds the target dnode. If an intermediate node turns out to be
+ * a symlink, it is resolved automatically. If the target node is a symlink, it
+ * is not resolved.
+ *
+ * If the function returns FSW_SUCCESS, *child_dno_out points to the requested directory
+ * entry. The caller must call fsw_dnode_release on it.
+ */
+
+fsw_status_t fsw_dnode_lookup_path(struct fsw_dnode *dno,
+                                   struct fsw_string *lookup_path, char separator,
+                                   struct fsw_dnode **child_dno_out)
+{
+    fsw_status_t    status;
+    struct fsw_volume *vol = dno->vol;
+    struct fsw_dnode *child_dno = NULL;
+    struct fsw_string lookup_name;
+    struct fsw_string remaining_path;
+    int             root_if_empty;
+
+    remaining_path = *lookup_path;
+    fsw_dnode_retain(dno);
+
+    // loop over the path
+    for (root_if_empty = 1; fsw_strlen(&remaining_path) > 0; root_if_empty = 0) {
+        // parse next path component
+        fsw_strsplit(&lookup_name, &remaining_path, separator);
+
+        FSW_MSG_DEBUG((FSW_MSGSTR("fsw_dnode_lookup_path: split into %d '%s' and %d '%s'\n"),
+                       lookup_name.len, lookup_name.data,
+                       remaining_path.len, remaining_path.data));
+
+        if (fsw_strlen(&lookup_name) == 0) {        // empty path component
+            if (root_if_empty)
+                child_dno = vol->root;
+            else
+                child_dno = dno;
+            fsw_dnode_retain(child_dno);
+
+        } else {
+            // do an actual directory lookup
+
+            // ensure we have full information
+            status = fsw_dnode_fill(dno);
+            if (status)
+                goto errorexit;
+
+            // resolve symlink if necessary
+            if (dno->type == FSW_DNODE_TYPE_SYMLINK) {
+                status = fsw_dnode_resolve(dno, &child_dno);
+                if (status)
+                    goto errorexit;
+
+                // symlink target becomes the new dno
+                fsw_dnode_release(dno);
+                dno = child_dno;   // is already retained
+                child_dno = NULL;
+
+                // ensure we have full information
+                status = fsw_dnode_fill(dno);
+                if (status)
+                    goto errorexit;
+            }
+
+            // make sure we operate on a directory
+            if (dno->type != FSW_DNODE_TYPE_DIR) {
+                return FSW_UNSUPPORTED;
+                goto errorexit;
+            }
+
+            // check special paths
+            if (fsw_streq_cstr(&lookup_name, ".")) {    // self directory
+                child_dno = dno;
+                fsw_dnode_retain(child_dno);
+
+            } else if (fsw_streq_cstr(&lookup_name, "..")) {   // parent directory
+                if (dno->parent == NULL) {
+                    // We cannot go up from the root directory. Caution: Certain apps like the EFI shell
+                    // rely on this behaviour!
+                    status = FSW_NOT_FOUND;
+                    goto errorexit;
+                }
+                child_dno = dno->parent;
+                fsw_dnode_retain(child_dno);
+
+            } else {
+                // do an actual lookup
+                status = vol->fstype_table->dir_lookup(vol, dno, &lookup_name, &child_dno);
+                if (status)
+                    goto errorexit;
+            }
+        }
+
+        // child_dno becomes the new dno
+        fsw_dnode_release(dno);
+        dno = child_dno;   // is already retained
+        child_dno = NULL;
+
+        FSW_MSG_DEBUG((FSW_MSGSTR("fsw_dnode_lookup_path: now at inode %d\n"), dno->dnode_id));
+    }
+
+    *child_dno_out = dno;
+    return FSW_SUCCESS;
+
+errorexit:
+    FSW_MSG_DEBUG((FSW_MSGSTR("fsw_dnode_lookup_path: leaving with error %d\n"), status));
+    fsw_dnode_release(dno);
+    if (child_dno != NULL)
+        fsw_dnode_release(child_dno);
+    return status;
+}
+
+/**
+ * Get the next directory item in sequential order. This function is called by the
+ * host driver to read the complete contents of a directory in sequential (file system
+ * defined) order. Calling this function returns the next entry. Iteration state is
+ * kept by a shandle on the directory's dnode. The caller must set up the shandle
+ * when starting the iteration.
+ *
+ * When the end of the directory is reached, this function returns FSW_NOT_FOUND.
+ * If the function returns FSW_SUCCESS, *child_dno_out points to the next directory
+ * entry. The caller must call fsw_dnode_release on it.
+ */
+
+fsw_status_t fsw_dnode_dir_read(struct fsw_shandle *shand, struct fsw_dnode **child_dno_out)
+{
+    fsw_status_t    status;
+    struct fsw_dnode *dno = shand->dnode;
+    fsw_u64         saved_pos;
+
+    if (dno->type != FSW_DNODE_TYPE_DIR)
+        return FSW_UNSUPPORTED;
+
+    saved_pos = shand->pos;
+    status = dno->vol->fstype_table->dir_read(dno->vol, dno, shand, child_dno_out);
+    if (status)
+        shand->pos = saved_pos;
+    return status;
+}
+
+/**
+ * Read the target path of a symbolic link. This function is called by the host driver
+ * to read the "content" of a symbolic link, that is the relative or absolute path
+ * it points to.
+ *
+ * If the function returns FSW_SUCCESS, the string handle provided by the caller is
+ * filled with a string in the host's preferred encoding. The caller is responsible
+ * for calling fsw_strfree on the string.
+ */
+
+fsw_status_t fsw_dnode_readlink(struct fsw_dnode *dno, struct fsw_string *target_name)
+{
+    fsw_status_t    status;
+
+    status = fsw_dnode_fill(dno);
+    if (status)
+        return status;
+    if (dno->type != FSW_DNODE_TYPE_SYMLINK)
+        return FSW_UNSUPPORTED;
+
+    return dno->vol->fstype_table->readlink(dno->vol, dno, target_name);
+}
+
+/**
+ * Read the target path of a symbolic link by accessing file data. This function can
+ * be called by the file system driver if the file system stores the target path
+ * as normal file data. This function will open an shandle, read the whole content
+ * of the file into a buffer, and build a string from that. Currently the encoding
+ * for the string is fixed as FSW_STRING_TYPE_ISO88591.
+ *
+ * If the function returns FSW_SUCCESS, the string handle provided by the caller is
+ * filled with a string in the host's preferred encoding. The caller is responsible
+ * for calling fsw_strfree on the string.
+ */
+
+fsw_status_t fsw_dnode_readlink_data(struct fsw_dnode *dno, struct fsw_string *link_target)
+{
+    fsw_status_t    status;
+    struct fsw_shandle shand;
+    fsw_u32         buffer_size;
+    char            buffer[FSW_PATH_MAX];
+
+    struct fsw_string s;
+
+    if (dno->size > FSW_PATH_MAX)
+        return FSW_VOLUME_CORRUPTED;
+
+    s.type = FSW_STRING_TYPE_ISO88591;
+    s.size = s.len = (int)dno->size;
+    s.data = buffer;
+
+    // open shandle and read the data
+    status = fsw_shandle_open(dno, &shand);
+    if (status)
+        return status;
+    buffer_size = (fsw_u32)s.size;
+    status = fsw_shandle_read(&shand, &buffer_size, buffer);
+    fsw_shandle_close(&shand);
+    if (status)
+        return status;
+    if ((int)buffer_size < s.size)
+        return FSW_VOLUME_CORRUPTED;
+
+    status = fsw_strdup_coerce(link_target, dno->vol->host_string_type, &s);
+    return status;
+}
+
+/**
+ * Resolve a symbolic link. This function can be called by the host driver to make
+ * sure the a dnode is fully resolved instead of pointing at a symlink. If the dnode
+ * passed in is not a symlink, it is returned unmodified.
+ *
+ * Note that absolute paths will be resolved relative to the root directory of the
+ * volume. If the host is an operating system with its own VFS layer, it should
+ * resolve symlinks on its own.
+ *
+ * If the function returns FSW_SUCCESS, *target_dno_out points at a dnode that is
+ * not a symlink. The caller is responsible for calling fsw_dnode_release on it.
+ */
+
+fsw_status_t fsw_dnode_resolve(struct fsw_dnode *dno, struct fsw_dnode **target_dno_out)
+{
+    fsw_status_t    status;
+    struct fsw_string target_name;
+    struct fsw_dnode *target_dno;
+    /* Linux kernel max link count is 40 */
+    int link_count = 40;
+
+    fsw_dnode_retain(dno);
+
+    while (--link_count > 0) {
+        // get full information
+        status = fsw_dnode_fill(dno);
+        if (status)
+            goto errorexit;
+        if (dno->type != FSW_DNODE_TYPE_SYMLINK) {
+            // found a non-symlink target, return it
+            *target_dno_out = dno;
+            return FSW_SUCCESS;
+        }
+        if (dno->parent == NULL) {    // safety measure, cannot happen in theory
+            status = FSW_NOT_FOUND;
+            goto errorexit;
+        }
+
+        // read the link's target
+        status = fsw_dnode_readlink(dno, &target_name);
+        if (status)
+            goto errorexit;
+
+        // resolve it
+        status = fsw_dnode_lookup_path(dno->parent, &target_name, '/', &target_dno);
+        fsw_strfree(&target_name);
+        if (status)
+            goto errorexit;
+
+        // target_dno becomes the new dno
+        fsw_dnode_release(dno);
+        dno = target_dno;   // is already retained
+    }
+    if(link_count == 0)
+      status = FSW_NOT_FOUND;
+
+errorexit:
+    fsw_dnode_release(dno);
+    return status;
+}
+
+/**
+ * Set up a shandle (storage handle) to access a file's data. This function is called
+ * by the host driver and by the core when they need to access a file's data. It is also
+ * used in accessing the raw data of directories and symlinks if the file system uses
+ * the same mechanisms for storing the data of those items.
+ *
+ * The storage for the fsw_shandle structure is provided by the caller. The dnode and pos
+ * fields may be accessed, pos may also be written to to set the file pointer. The file's
+ * data size is available as shand->dnode->size.
+ *
+ * If this function returns FSW_SUCCESS, the caller must call fsw_shandle_close to release
+ * the dnode reference held by the shandle.
+ */
+
+fsw_status_t fsw_shandle_open(struct fsw_dnode *dno, struct fsw_shandle *shand)
+{
+    fsw_status_t    status;
+    struct fsw_volume *vol = dno->vol;
+
+    // read full dnode information into memory
+    status = vol->fstype_table->dnode_fill(vol, dno);
+    if (status)
+        return status;
+
+    // setup shandle
+    fsw_dnode_retain(dno);
+
+    shand->dnode = dno;
+    shand->pos = 0;
+    shand->extent.type = FSW_EXTENT_TYPE_INVALID;
+
+    return FSW_SUCCESS;
+}
+
+/**
+ * Close a shandle after accessing the dnode's data. This function is called by the host
+ * driver or core functions when they are finished with accessing a file's data. It
+ * releases the dnode reference and frees any buffers associated with the shandle itself.
+ * The dnode is only released if this was the last reference using it.
+ */
+
+void fsw_shandle_close(struct fsw_shandle *shand)
+{
+    if (shand->extent.type == FSW_EXTENT_TYPE_BUFFER)
+        fsw_free(shand->extent.buffer);
+    fsw_dnode_release(shand->dnode);
+}
+
+/**
+ * Read data from a shandle (storage handle for a dnode). This function is called by the
+ * host driver or internally when data is read from a file. TODO: more
+ */
+
+fsw_status_t fsw_shandle_read(struct fsw_shandle *shand, fsw_u32 *buffer_size_inout, void *buffer_in)
+{
+    fsw_status_t    status;
+    struct fsw_dnode *dno = shand->dnode;
+    struct fsw_volume *vol = dno->vol;
+    fsw_u8          *buffer, *block_buffer;
+    fsw_u64         buflen, copylen, pos;
+    fsw_u64         log_bno, pos_in_extent, phys_bno, pos_in_physblock;
+    fsw_u32         cache_level;
+
+    if (shand->pos >= dno->size) {   // already at EOF
+        *buffer_size_inout = 0;
+        return FSW_SUCCESS;
+    }
+
+    // initialize vars
+    buffer = buffer_in;
+    buflen = *buffer_size_inout;
+    pos = (fsw_u32)shand->pos;
+    cache_level = (dno->type != FSW_DNODE_TYPE_FILE) ? 1 : 0;
+    // restrict read to file size
+    if (buflen > dno->size - pos)
+        buflen = (fsw_u32)(dno->size - pos);
+
+    while (buflen > 0) {
+        // get extent for the current logical block
+        log_bno = FSW_U64_DIV(pos, vol->log_blocksize);
+        if (shand->extent.type == FSW_EXTENT_TYPE_INVALID ||
+            log_bno < shand->extent.log_start ||
+            log_bno >= shand->extent.log_start + shand->extent.log_count) {
+
+            if (shand->extent.type == FSW_EXTENT_TYPE_BUFFER)
+                fsw_free(shand->extent.buffer);
+
+            // ask the file system for the proper extent
+            shand->extent.log_start = log_bno;
+            status = vol->fstype_table->get_extent(vol, dno, &shand->extent);
+            if (status) {
+                shand->extent.type = FSW_EXTENT_TYPE_INVALID;
+                return status;
+            }
+        }
+
+        pos_in_extent = pos - shand->extent.log_start * vol->log_blocksize;
+
+        // dispatch by extent type
+        if (shand->extent.type == FSW_EXTENT_TYPE_PHYSBLOCK) {
+            // convert to physical block number and offset
+            phys_bno = shand->extent.phys_start + FSW_U64_DIV(pos_in_extent, vol->phys_blocksize);
+            pos_in_physblock = pos_in_extent & (vol->phys_blocksize - 1);
+            copylen = vol->phys_blocksize - pos_in_physblock;
+            if (copylen > buflen)
+                copylen = buflen;
+
+            // get one physical block
+            status = fsw_block_get(vol, phys_bno, cache_level, (void **)&block_buffer);
+            if (status)
+                return status;
+
+            // copy data from it
+            fsw_memcpy(buffer, block_buffer + pos_in_physblock, copylen);
+            fsw_block_release(vol, phys_bno, block_buffer);
+
+        } else if (shand->extent.type == FSW_EXTENT_TYPE_BUFFER) {
+            copylen = shand->extent.log_count * vol->log_blocksize - pos_in_extent;
+            if (copylen > buflen)
+                copylen = buflen;
+            fsw_memcpy(buffer, (fsw_u8 *)shand->extent.buffer + pos_in_extent, copylen);
+
+        } else {   // _SPARSE or _INVALID
+            copylen = shand->extent.log_count * vol->log_blocksize - pos_in_extent;
+            if (copylen > buflen)
+                copylen = buflen;
+            fsw_memzero(buffer, copylen);
+
+        }
+
+        buffer += copylen;
+        buflen -= copylen;
+        pos    += copylen;
+    }
+
+    *buffer_size_inout = (fsw_u32)(pos - shand->pos);
+    shand->pos = pos;
+
+    return FSW_SUCCESS;
+}
+
+// EOF
diff --git a/filesystems/fsw_core.h b/filesystems/fsw_core.h
new file mode 100644 (file)
index 0000000..6e76665
--- /dev/null
@@ -0,0 +1,524 @@
+/**
+ * \file fsw_core.h
+ * Core file system wrapper abstraction layer header.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ * Portions Copyright (c) The Regents of the University of California.
+ * Portions Copyright (c) UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _FSW_CORE_H_
+#define _FSW_CORE_H_
+
+#include "fsw_base.h"
+#ifdef __MAKEWITH_GNUEFI
+#include "fsw_efi_base.h"
+#endif
+
+/** Maximum size for a path, specifically symlink target paths. */
+#define FSW_PATH_MAX (4096)
+
+/** Helper macro for token concatenation. */
+#define FSW_CONCAT3(a,b,c) a##b##c
+/** Expands to the name of a fstype dispatch table (fsw_fstype_table) for a named file system type. */
+#define FSW_FSTYPE_TABLE_NAME(t) FSW_CONCAT3(fsw_,t,_table)
+
+/** Indicates that the block cache entry is empty. */
+#define FSW_INVALID_BNO 0xFFFFFFFFFFFFFFFF
+
+
+//
+// Byte-swapping macros
+//
+
+
+/**
+ * \name Byte Order Macros
+ * Implements big endian vs. little endian awareness and conversion.
+ */
+/*@{*/
+
+typedef fsw_u16             fsw_u16_le;
+typedef fsw_u16             fsw_u16_be;
+typedef fsw_u32             fsw_u32_le;
+typedef fsw_u32             fsw_u32_be;
+typedef fsw_u64             fsw_u64_le;
+typedef fsw_u64             fsw_u64_be;
+
+#define FSW_SWAPVALUE_U16(v) ((((fsw_u16)(v) & 0xff00) >> 8) | \
+                              (((fsw_u16)(v) & 0x00ff) << 8))
+#define FSW_SWAPVALUE_U32(v) ((((fsw_u32)(v) & 0xff000000UL) >> 24) | \
+                              (((fsw_u32)(v) & 0x00ff0000UL) >> 8)  | \
+                              (((fsw_u32)(v) & 0x0000ff00UL) << 8)  | \
+                              (((fsw_u32)(v) & 0x000000ffUL) << 24))
+#define FSW_SWAPVALUE_U64(v) ((((fsw_u64)(v) & 0xff00000000000000ULL) >> 56) | \
+                              (((fsw_u64)(v) & 0x00ff000000000000ULL) >> 40) | \
+                              (((fsw_u64)(v) & 0x0000ff0000000000ULL) >> 24) | \
+                              (((fsw_u64)(v) & 0x000000ff00000000ULL) >> 8)  | \
+                              (((fsw_u64)(v) & 0x00000000ff000000ULL) << 8)  | \
+                              (((fsw_u64)(v) & 0x0000000000ff0000ULL) << 24) | \
+                              (((fsw_u64)(v) & 0x000000000000ff00ULL) << 40) | \
+                              (((fsw_u64)(v) & 0x00000000000000ffULL) << 56))
+
+#ifdef FSW_LITTLE_ENDIAN
+
+#define fsw_u16_le_swap(v) (v)
+#define fsw_u16_be_swap(v) FSW_SWAPVALUE_U16(v)
+#define fsw_u32_le_swap(v) (v)
+#define fsw_u32_be_swap(v) FSW_SWAPVALUE_U32(v)
+#define fsw_u64_le_swap(v) (v)
+#define fsw_u64_be_swap(v) FSW_SWAPVALUE_U64(v)
+
+#define fsw_u16_le_sip(var)
+#define fsw_u16_be_sip(var) (var = FSW_SWAPVALUE_U16(var))
+#define fsw_u32_le_sip(var)
+#define fsw_u32_be_sip(var) (var = FSW_SWAPVALUE_U32(var))
+#define fsw_u64_le_sip(var)
+#define fsw_u64_be_sip(var) (var = FSW_SWAPVALUE_U64(var))
+
+#else
+#ifdef FSW_BIG_ENDIAN
+
+#define fsw_u16_le_swap(v) FSW_SWAPVALUE_U16(v)
+#define fsw_u16_be_swap(v) (v)
+#define fsw_u32_le_swap(v) FSW_SWAPVALUE_U32(v)
+#define fsw_u32_be_swap(v) (v)
+#define fsw_u64_le_swap(v) FSW_SWAPVALUE_U64(v)
+#define fsw_u64_be_swap(v) (v)
+
+#define fsw_u16_le_sip(var) (var = FSW_SWAPVALUE_U16(var))
+#define fsw_u16_be_sip(var)
+#define fsw_u32_le_sip(var) (var = FSW_SWAPVALUE_U32(var))
+#define fsw_u32_be_sip(var)
+#define fsw_u64_le_sip(var) (var = FSW_SWAPVALUE_U64(var))
+#define fsw_u64_be_sip(var)
+
+#else
+#fail Neither FSW_BIG_ENDIAN nor FSW_LITTLE_ENDIAN are defined
+#endif
+#endif
+
+/*@}*/
+
+
+//
+// The following evil hack avoids a lot of casts between generic and fstype-specific
+// structures.
+//
+
+#ifndef VOLSTRUCTNAME
+#define VOLSTRUCTNAME fsw_volume
+#else
+struct VOLSTRUCTNAME;
+#endif
+#ifndef DNODESTRUCTNAME
+#define DNODESTRUCTNAME fsw_dnode
+#else
+struct DNODESTRUCTNAME;
+#endif
+
+
+/**
+ * Status code type, returned from all functions that can fail.
+ */
+typedef int fsw_status_t;
+
+/**
+ * Possible status codes.
+ */
+enum {
+    FSW_SUCCESS,
+    FSW_OUT_OF_MEMORY,
+    FSW_IO_ERROR,
+    FSW_UNSUPPORTED,
+    FSW_NOT_FOUND,
+    FSW_VOLUME_CORRUPTED,
+    FSW_UNKNOWN_ERROR
+};
+
+
+/**
+ * Core: A string with explicit length and encoding information.
+ */
+
+struct fsw_string {
+    int         type;               //!< Encoding of the string - empty, ISO-8859-1, UTF8, UTF16
+    int         len;                //!< Length in characters
+    int         size;               //!< Total data size in bytes
+    void        *data;              //!< Data pointer (may be NULL if type is EMPTY or len is zero)
+};
+
+/**
+ * Possible string types / encodings. In the case of FSW_STRING_TYPE_EMPTY,
+ * all other members of the fsw_string structure may be invalid.
+ */
+enum {
+    FSW_STRING_TYPE_EMPTY,
+    FSW_STRING_TYPE_ISO88591,
+    FSW_STRING_TYPE_UTF8,
+    FSW_STRING_TYPE_UTF16,
+    FSW_STRING_TYPE_UTF16_SWAPPED
+};
+
+#ifdef FSW_LITTLE_ENDIAN
+#define FSW_STRING_TYPE_UTF16_LE FSW_STRING_TYPE_UTF16
+#define FSW_STRING_TYPE_UTF16_BE FSW_STRING_TYPE_UTF16_SWAPPED
+#else
+#define FSW_STRING_TYPE_UTF16_LE FSW_STRING_TYPE_UTF16_SWAPPED
+#define FSW_STRING_TYPE_UTF16_BE FSW_STRING_TYPE_UTF16
+#endif
+
+/** Static initializer for an empty string. */
+#define FSW_STRING_INIT { FSW_STRING_TYPE_EMPTY, 0, 0, NULL }
+
+
+/* forward declarations */
+
+struct fsw_dnode;
+struct fsw_host_table;
+struct fsw_fstype_table;
+
+struct fsw_blockcache {
+    fsw_u32     refcount;           //!< Reference count
+    fsw_u32     cache_level;        //!< Level of importance of this block
+    fsw_u64     phys_bno;           //!< Physical block number
+    void        *data;              //!< Block data buffer
+};
+
+/**
+ * Core: Represents a mounted volume.
+ */
+
+struct fsw_volume {
+    fsw_u32     phys_blocksize;     //!< Block size for disk access / file system structures
+    fsw_u32     log_blocksize;      //!< Block size for logical file data
+
+    struct DNODESTRUCTNAME *root;   //!< Root directory dnode
+    struct fsw_string label;        //!< Volume label
+
+    struct fsw_dnode *dnode_head;   //!< List of all dnodes allocated for this volume
+
+    struct fsw_blockcache *bcache;  //!< Array of block cache entries
+    fsw_u32     bcache_size;        //!< Number of entries in the block cache array
+
+    void        *host_data;         //!< Hook for a host-specific data structure
+    struct fsw_host_table *host_table;      //!< Dispatch table for host-specific functions
+    struct fsw_fstype_table *fstype_table;  //!< Dispatch table for file system specific functions
+    int         host_string_type;   //!< String type used by the host environment
+};
+
+/**
+ * Core: Represents a "directory node" - a file, directory, symlink, whatever.
+ */
+
+struct fsw_dnode {
+    fsw_u32     refcount;           //!< Reference count
+
+    struct VOLSTRUCTNAME *vol;      //!< The volume this dnode belongs to
+    struct DNODESTRUCTNAME *parent; //!< Parent directory dnode
+    struct fsw_string name;         //!< Name of this item in the parent directory
+
+    fsw_u64     tree_id;            //!< Unique id number (usually the btrfs subvolume)
+    fsw_u64     dnode_id;           //!< Unique id number (usually the inode number)
+    int         type;               //!< Type of the dnode - file, dir, symlink, special
+    fsw_u64     size;               //!< Data size in bytes
+
+    struct fsw_dnode *next;         //!< Doubly-linked list of all dnodes: previous dnode
+    struct fsw_dnode *prev;         //!< Doubly-linked list of all dnodes: next dnode
+};
+
+/**
+ * Possible dnode types. FSW_DNODE_TYPE_UNKNOWN may only be used before
+ * fsw_dnode_fill has been called on the dnode.
+ */
+enum {
+    FSW_DNODE_TYPE_UNKNOWN,
+    FSW_DNODE_TYPE_FILE,
+    FSW_DNODE_TYPE_DIR,
+    FSW_DNODE_TYPE_SYMLINK,
+    FSW_DNODE_TYPE_SPECIAL
+};
+
+/**
+ * Core: Stores the mapping of a region of a file to the data on disk.
+ */
+
+struct fsw_extent {
+    fsw_u32     type;               //!< Type of extent specification
+    fsw_u64     log_start;          //!< Starting logical block number
+    fsw_u32     log_count;          //!< Logical block count
+    fsw_u64     phys_start;         //!< Starting physical block number (for FSW_EXTENT_TYPE_PHYSBLOCK only)
+    void        *buffer;            //!< Allocated buffer pointer (for FSW_EXTENT_TYPE_BUFFER only)
+};
+
+/**
+ * Possible extent representation types. FSW_EXTENT_TYPE_INVALID is for shandle's
+ * internal use only, it must not be returned from a get_extent function.
+ */
+enum {
+    FSW_EXTENT_TYPE_INVALID,
+    FSW_EXTENT_TYPE_SPARSE,
+    FSW_EXTENT_TYPE_PHYSBLOCK,
+    FSW_EXTENT_TYPE_BUFFER
+};
+
+/**
+ * Core: An access structure to a dnode's raw data. There can be multiple
+ * shandles per dnode, each of them has its own position pointer.
+ */
+
+struct fsw_shandle {
+    struct fsw_dnode *dnode;        //!< The dnode this handle reads data from
+
+    fsw_u64     pos;                //!< Current file pointer in bytes
+    struct fsw_extent extent;       //!< Current extent
+};
+
+/**
+ * Core: Used in gathering detailed information on a volume.
+ */
+
+struct fsw_volume_stat {
+    fsw_u64     total_bytes;        //!< Total size of data area size in bytes
+    fsw_u64     free_bytes;         //!< Bytes still available for storing file data
+};
+
+/**
+ * Core: Used in gathering detailed information on a dnode.
+ */
+
+struct fsw_dnode_stat {
+    fsw_u64     used_bytes;         //!< Bytes actually used by the file on disk
+    void        *host_data;         //!< Hook for a host-specific data structure
+};
+
+/**
+ * Type of the timestamp passed into store_time_posix.
+ */
+enum {
+    FSW_DNODE_STAT_CTIME,
+    FSW_DNODE_STAT_MTIME,
+    FSW_DNODE_STAT_ATIME
+};
+
+/**
+ * Core: Function table for a host environment.
+ */
+
+struct fsw_host_table
+{
+    int         native_string_type; //!< String type used by the host environment
+
+    void         EFIAPI (*change_blocksize)(struct fsw_volume *vol,
+                                     fsw_u32 old_phys_blocksize, fsw_u32 old_log_blocksize,
+                                     fsw_u32 new_phys_blocksize, fsw_u32 new_log_blocksize);
+    fsw_status_t EFIAPI (*read_block)(struct fsw_volume *vol, fsw_u64 phys_bno, void *buffer);
+};
+
+/**
+ * Core: Function table for a file system driver.
+ */
+
+struct fsw_fstype_table
+{
+    struct fsw_string name;         //!< String giving the name of the file system
+    fsw_u32     volume_struct_size; //!< Size for allocating the fsw_volume structure
+    fsw_u32     dnode_struct_size;  //!< Size for allocating the fsw_dnode structure
+
+    fsw_status_t (*volume_mount)(struct VOLSTRUCTNAME *vol);
+    void         (*volume_free)(struct VOLSTRUCTNAME *vol);
+    fsw_status_t (*volume_stat)(struct VOLSTRUCTNAME *vol, struct fsw_volume_stat *sb);
+
+    fsw_status_t (*dnode_fill)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno);
+    void         (*dnode_free)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno);
+    fsw_status_t (*dnode_stat)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno,
+                               struct fsw_dnode_stat *sb);
+    fsw_status_t (*get_extent)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno,
+                               struct fsw_extent *extent);
+
+    fsw_status_t (*dir_lookup)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno,
+                               struct fsw_string *lookup_name, struct DNODESTRUCTNAME **child_dno);
+    fsw_status_t (*dir_read)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno,
+                             struct fsw_shandle *shand, struct DNODESTRUCTNAME **child_dno);
+    fsw_status_t (*readlink)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno,
+                             struct fsw_string *link_target);
+};
+
+
+/**
+ * \name Volume Functions
+ */
+/*@{*/
+
+fsw_status_t fsw_mount(void *host_data,
+                       struct fsw_host_table *host_table,
+                       struct fsw_fstype_table *fstype_table,
+                       struct fsw_volume **vol_out);
+void         fsw_unmount(struct fsw_volume *vol);
+fsw_status_t fsw_volume_stat(struct fsw_volume *vol, struct fsw_volume_stat *sb);
+
+void         fsw_set_blocksize(struct VOLSTRUCTNAME *vol, fsw_u32 phys_blocksize, fsw_u32 log_blocksize);
+fsw_status_t fsw_block_get(struct VOLSTRUCTNAME *vol, fsw_u64 phys_bno, fsw_u32 cache_level, void **buffer_out);
+void         fsw_block_release(struct VOLSTRUCTNAME *vol, fsw_u64 phys_bno, void *buffer);
+
+/*@}*/
+
+
+/**
+ * \name dnode Functions
+ */
+/*@{*/
+
+fsw_status_t fsw_dnode_create_root(struct VOLSTRUCTNAME *vol, fsw_u64 dnode_id, struct DNODESTRUCTNAME **dno_out);
+fsw_status_t fsw_dnode_create(struct DNODESTRUCTNAME *parent_dno, fsw_u64 dnode_id, int type,
+                              struct fsw_string *name, struct DNODESTRUCTNAME **dno_out);
+fsw_status_t fsw_dnode_create_root_with_tree(struct VOLSTRUCTNAME *vol, fsw_u64 tree_id, fsw_u64 dnode_id, struct DNODESTRUCTNAME **dno_out);
+fsw_status_t fsw_dnode_create_with_tree(struct DNODESTRUCTNAME *parent_dno, fsw_u64 tree_id, fsw_u64 dnode_id, int type,
+                              struct fsw_string *name, struct DNODESTRUCTNAME **dno_out);
+void         fsw_dnode_retain(struct fsw_dnode *dno);
+void         fsw_dnode_release(struct fsw_dnode *dno);
+
+fsw_status_t fsw_dnode_fill(struct fsw_dnode *dno);
+fsw_status_t fsw_dnode_stat(struct fsw_dnode *dno, struct fsw_dnode_stat *sb);
+
+fsw_status_t fsw_dnode_lookup(struct fsw_dnode *dno,
+                              struct fsw_string *lookup_name, struct fsw_dnode **child_dno_out);
+fsw_status_t fsw_dnode_lookup_path(struct fsw_dnode *dno,
+                                   struct fsw_string *lookup_path, char separator,
+                                   struct fsw_dnode **child_dno_out);
+fsw_status_t fsw_dnode_dir_read(struct fsw_shandle *shand, struct fsw_dnode **child_dno_out);
+fsw_status_t fsw_dnode_readlink(struct fsw_dnode *dno, struct fsw_string *link_target);
+fsw_status_t fsw_dnode_readlink_data(struct DNODESTRUCTNAME *dno, struct fsw_string *link_target);
+fsw_status_t fsw_dnode_resolve(struct fsw_dnode *dno, struct fsw_dnode **target_dno_out);
+void fsw_store_time_posix(struct fsw_dnode_stat *sb, int which, fsw_u32 posix_time);
+void fsw_store_attr_posix(struct fsw_dnode_stat *sb, fsw_u16 posix_mode);
+void fsw_store_attr_efi(struct fsw_dnode_stat *sb, fsw_u16 attr);
+
+/*@}*/
+
+
+/**
+ * \name shandle Functions
+ */
+/*@{*/
+
+fsw_status_t fsw_shandle_open(struct DNODESTRUCTNAME *dno, struct fsw_shandle *shand);
+void         fsw_shandle_close(struct fsw_shandle *shand);
+fsw_status_t fsw_shandle_read(struct fsw_shandle *shand, fsw_u32 *buffer_size_inout, void *buffer);
+
+/*@}*/
+
+
+/**
+ * \name Memory Functions
+ */
+/*@{*/
+
+fsw_status_t fsw_alloc_zero(int len, void **ptr_out);
+fsw_status_t fsw_memdup(void **dest_out, void *src, int len);
+
+/*@}*/
+
+
+/**
+ * \name String Functions
+ */
+/*@{*/
+
+int          fsw_strlen(struct fsw_string *s);
+int          fsw_streq(struct fsw_string *s1, struct fsw_string *s2);
+int          fsw_streq_cstr(struct fsw_string *s1, const char *s2);
+fsw_status_t fsw_strdup_coerce(struct fsw_string *dest, int type, struct fsw_string *src);
+void         fsw_strsplit(struct fsw_string *lookup_name, struct fsw_string *buffer, char separator);
+
+void         fsw_strfree(struct fsw_string *s);
+
+/*@}*/
+
+
+/**
+ * \name Posix Mode Macros
+ * These macros can be used globally to test fields and bits in
+ * Posix-style modes.
+ *
+ * Taken from FreeBSD sys/stat.h.
+ */
+/*@{*/
+#ifndef S_IRWXU
+
+#define        S_ISUID 0004000                 /* set user id on execution */
+#define        S_ISGID 0002000                 /* set group id on execution */
+#define        S_ISTXT 0001000                 /* sticky bit */
+
+#define        S_IRWXU 0000700                 /* RWX mask for owner */
+#define        S_IRUSR 0000400                 /* R for owner */
+#define        S_IWUSR 0000200                 /* W for owner */
+#define        S_IXUSR 0000100                 /* X for owner */
+
+#define        S_IRWXG 0000070                 /* RWX mask for group */
+#define        S_IRGRP 0000040                 /* R for group */
+#define        S_IWGRP 0000020                 /* W for group */
+#define        S_IXGRP 0000010                 /* X for group */
+
+#define        S_IRWXO 0000007                 /* RWX mask for other */
+#define        S_IROTH 0000004                 /* R for other */
+#define        S_IWOTH 0000002                 /* W for other */
+#define        S_IXOTH 0000001                 /* X for other */
+
+#define        S_IFMT   0170000                /* type of file mask */
+#define        S_IFIFO  0010000                /* named pipe (fifo) */
+#define        S_IFCHR  0020000                /* character special */
+#define        S_IFDIR  0040000                /* directory */
+#define        S_IFBLK  0060000                /* block special */
+#define        S_IFREG  0100000                /* regular */
+#define        S_IFLNK  0120000                /* symbolic link */
+#define        S_IFSOCK 0140000                /* socket */
+#define        S_ISVTX  0001000                /* save swapped text even after use */
+#define        S_IFWHT  0160000                /* whiteout */
+
+#define        S_ISDIR(m)      (((m) & 0170000) == 0040000)    /* directory */
+#define        S_ISCHR(m)      (((m) & 0170000) == 0020000)    /* char special */
+#define        S_ISBLK(m)      (((m) & 0170000) == 0060000)    /* block special */
+#define        S_ISREG(m)      (((m) & 0170000) == 0100000)    /* regular file */
+#define        S_ISFIFO(m)     (((m) & 0170000) == 0010000)    /* fifo or socket */
+#define        S_ISLNK(m)      (((m) & 0170000) == 0120000)    /* symbolic link */
+#define        S_ISSOCK(m)     (((m) & 0170000) == 0140000)    /* socket */
+#define        S_ISWHT(m)      (((m) & 0170000) == 0160000)    /* whiteout */
+
+#define S_BLKSIZE      512             /* block size used in the stat struct */
+
+#endif
+/*@}*/
+
+
+#endif
diff --git a/filesystems/fsw_efi.c b/filesystems/fsw_efi.c
new file mode 100644 (file)
index 0000000..0a9c24e
--- /dev/null
@@ -0,0 +1,1187 @@
+/**
+ * \file fsw_efi.c
+ * EFI host environment code.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Changes by Roderick Smith are licensed under the preceding terms.
+ */
+
+#include "fsw_efi.h"
+#include "fsw_core.h"
+#ifdef __MAKEWITH_GNUEFI
+#include "edk2/DriverBinding.h"
+#include "edk2/ComponentName.h"
+#endif
+#include "../include/refit_call_wrapper.h"
+
+#define DEBUG_LEVEL 0
+
+#ifndef FSTYPE
+/** The file system type name to use. */
+#define FSTYPE ext2
+#endif
+
+#ifdef __MAKEWITH_GNUEFI
+
+#define EFI_DISK_IO_PROTOCOL_GUID \
+  { \
+    0xce345171, 0xba0b, 0x11d2, {0x8e, 0x4f, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \
+  }
+
+#define EFI_BLOCK_IO_PROTOCOL_GUID \
+  { \
+    0x964e5b21, 0x6459, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \
+  }
+
+EFI_GUID gEfiDriverBindingProtocolGuid = EFI_DRIVER_BINDING_PROTOCOL_GUID;
+EFI_GUID gEfiComponentNameProtocolGuid = EFI_COMPONENT_NAME_PROTOCOL_GUID;
+EFI_GUID gEfiDiskIoProtocolGuid = EFI_DISK_IO_PROTOCOL_GUID;
+EFI_GUID gEfiBlockIoProtocolGuid = EFI_BLOCK_IO_PROTOCOL_GUID;
+EFI_GUID gEfiFileInfoGuid = EFI_FILE_INFO_ID;
+EFI_GUID gEfiFileSystemInfoGuid = EFI_FILE_SYSTEM_INFO_ID;
+EFI_GUID gEfiFileSystemVolumeLabelInfoIdGuid = EFI_FILE_SYSTEM_VOLUME_LABEL_INFO_ID;
+#define gEfiSimpleFileSystemProtocolGuid FileSystemProtocol
+#endif
+
+/** Helper macro for stringification. */
+#define FSW_EFI_STRINGIFY(x) #x
+/** Expands to the EFI driver name given the file system type name. */
+#define FSW_EFI_DRIVER_NAME(t) L"rEFInd 0.9.1 " FSW_EFI_STRINGIFY(t) L" File System Driver"
+
+// function prototypes
+
+EFI_STATUS EFIAPI fsw_efi_DriverBinding_Supported(IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+                                                  IN EFI_HANDLE                   ControllerHandle,
+                                                  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath);
+EFI_STATUS EFIAPI fsw_efi_DriverBinding_Start(IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+                                              IN EFI_HANDLE                   ControllerHandle,
+                                              IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath);
+EFI_STATUS EFIAPI fsw_efi_DriverBinding_Stop(IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
+                                             IN  EFI_HANDLE                   ControllerHandle,
+                                             IN  UINTN                        NumberOfChildren,
+                                             IN  EFI_HANDLE                   *ChildHandleBuffer);
+
+EFI_STATUS EFIAPI fsw_efi_ComponentName_GetDriverName(IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
+                                                      IN  CHAR8                        *Language,
+                                                      OUT CHAR16                       **DriverName);
+EFI_STATUS EFIAPI fsw_efi_ComponentName_GetControllerName(IN  EFI_COMPONENT_NAME_PROTOCOL    *This,
+                                                          IN  EFI_HANDLE                     ControllerHandle,
+                                                          IN  EFI_HANDLE                     ChildHandle  OPTIONAL,
+                                                          IN  CHAR8                          *Language,
+                                                          OUT CHAR16                         **ControllerName);
+
+void EFIAPI fsw_efi_change_blocksize(struct fsw_volume *vol,
+                              fsw_u32 old_phys_blocksize, fsw_u32 old_log_blocksize,
+                              fsw_u32 new_phys_blocksize, fsw_u32 new_log_blocksize);
+fsw_status_t EFIAPI fsw_efi_read_block(struct fsw_volume *vol, fsw_u64 phys_bno, void *buffer);
+
+EFI_STATUS fsw_efi_map_status(fsw_status_t fsw_status, FSW_VOLUME_DATA *Volume);
+
+EFI_STATUS EFIAPI fsw_efi_FileSystem_OpenVolume(IN EFI_FILE_IO_INTERFACE *This,
+                                                OUT EFI_FILE **Root);
+EFI_STATUS fsw_efi_dnode_to_FileHandle(IN struct fsw_dnode *dno,
+                                       OUT EFI_FILE **NewFileHandle);
+
+EFI_STATUS fsw_efi_file_read(IN FSW_FILE_DATA *File,
+                             IN OUT UINTN *BufferSize,
+                             OUT VOID *Buffer);
+EFI_STATUS fsw_efi_file_getpos(IN FSW_FILE_DATA *File,
+                               OUT UINT64 *Position);
+EFI_STATUS fsw_efi_file_setpos(IN FSW_FILE_DATA *File,
+                               IN UINT64 Position);
+
+EFI_STATUS fsw_efi_dir_open(IN FSW_FILE_DATA *File,
+                            OUT EFI_FILE **NewHandle,
+                            IN CHAR16 *FileName,
+                            IN UINT64 OpenMode,
+                            IN UINT64 Attributes);
+EFI_STATUS fsw_efi_dir_read(IN FSW_FILE_DATA *File,
+                            IN OUT UINTN *BufferSize,
+                            OUT VOID *Buffer);
+EFI_STATUS fsw_efi_dir_setpos(IN FSW_FILE_DATA *File,
+                              IN UINT64 Position);
+
+EFI_STATUS fsw_efi_dnode_getinfo(IN FSW_FILE_DATA *File,
+                                 IN EFI_GUID *InformationType,
+                                 IN OUT UINTN *BufferSize,
+                                 OUT VOID *Buffer);
+EFI_STATUS fsw_efi_dnode_fill_FileInfo(IN FSW_VOLUME_DATA *Volume,
+                                       IN struct fsw_dnode *dno,
+                                       IN OUT UINTN *BufferSize,
+                                       OUT VOID *Buffer);
+
+/**
+ * Structure for holding disk cache data.
+ */
+
+#define CACHE_SIZE 131072 /* 128KiB */
+struct cache_data {
+   fsw_u8            *Cache;
+   fsw_u64           CacheStart;
+   BOOLEAN           CacheValid;
+   FSW_VOLUME_DATA   *Volume; // NOTE: Do not deallocate; copied here to ID volume
+};
+
+#define NUM_CACHES 2 /* Don't increase without modifying fsw_efi_read_block() */
+static struct cache_data    Caches[NUM_CACHES];
+static int LastRead = -1;
+
+/**
+ * Interface structure for the EFI Driver Binding protocol.
+ */
+
+EFI_DRIVER_BINDING_PROTOCOL fsw_efi_DriverBinding_table = {
+    fsw_efi_DriverBinding_Supported,
+    fsw_efi_DriverBinding_Start,
+    fsw_efi_DriverBinding_Stop,
+    0x10,
+    NULL,
+    NULL
+};
+
+/**
+ * Interface structure for the EFI Component Name protocol.
+ */
+
+EFI_COMPONENT_NAME_PROTOCOL fsw_efi_ComponentName_table = {
+    fsw_efi_ComponentName_GetDriverName,
+    fsw_efi_ComponentName_GetControllerName,
+    (CHAR8*) "eng"
+};
+
+/**
+ * Dispatch table for our FSW host driver.
+ */
+
+struct fsw_host_table   fsw_efi_host_table = {
+    FSW_STRING_TYPE_UTF16,
+
+    fsw_efi_change_blocksize,
+    fsw_efi_read_block
+};
+
+extern struct fsw_fstype_table   FSW_FSTYPE_TABLE_NAME(FSTYPE);
+
+
+static VOID EFIAPI fsw_efi_clear_cache(VOID) {
+   int i;
+
+   // clear the cache
+   for (i = 0; i < NUM_CACHES; i++) {
+      if (Caches[i].Cache != NULL) {
+         FreePool(Caches[i].Cache);
+         Caches[i].Cache = NULL;
+      } // if
+            Caches[i].CacheStart = 0;
+            Caches[i].CacheValid = FALSE;
+            Caches[i].Volume = NULL;
+   }
+   LastRead = -1;
+} // VOID EFIAPI fsw_efi_clear_cache();
+
+/**
+ * Image entry point. Installs the Driver Binding and Component Name protocols
+ * on the image's handle. Actually mounting a file system is initiated through
+ * the Driver Binding protocol at the firmware's request.
+ */
+EFI_STATUS EFIAPI fsw_efi_main(IN EFI_HANDLE         ImageHandle,
+                               IN EFI_SYSTEM_TABLE   *SystemTable)
+{
+    EFI_STATUS  Status;
+
+#ifndef HOST_EFI_EDK2
+    // Not available in EDK2 toolkit
+    InitializeLib(ImageHandle, SystemTable);
+#endif
+
+    // complete Driver Binding protocol instance
+    fsw_efi_DriverBinding_table.ImageHandle          = ImageHandle;
+    fsw_efi_DriverBinding_table.DriverBindingHandle  = ImageHandle;
+    // install Driver Binding protocol
+    Status = refit_call4_wrapper(BS->InstallProtocolInterface, &fsw_efi_DriverBinding_table.DriverBindingHandle,
+                                          &gEfiDriverBindingProtocolGuid,
+                                          EFI_NATIVE_INTERFACE,
+                                          &fsw_efi_DriverBinding_table);
+    if (EFI_ERROR (Status)) {
+        return Status;
+    }
+
+    // install Component Name protocol
+    Status = refit_call4_wrapper(BS->InstallProtocolInterface, &fsw_efi_DriverBinding_table.DriverBindingHandle,
+                                          &gEfiComponentNameProtocolGuid,
+                                          EFI_NATIVE_INTERFACE,
+                                          &fsw_efi_ComponentName_table);
+    if (EFI_ERROR (Status)) {
+        return Status;
+    }
+
+//     OverrideFunctions();
+//   Msg = NULL;
+//   msgCursor = NULL;
+//   Status = BS->LocateProtocol(&gMsgLogProtocolGuid, NULL, (VOID **) &Msg);
+//   if (!EFI_ERROR(Status) && (Msg != NULL)) {
+//     msgCursor = Msg->Cursor;
+//     BootLog("MsgLog installed into VBoxFs\n");
+//   }
+
+    return EFI_SUCCESS;
+}
+
+#ifdef __MAKEWITH_GNUEFI
+EFI_DRIVER_ENTRY_POINT(fsw_efi_main)
+#endif
+
+/**
+ * Driver Binding EFI protocol, Supported function. This function is called by EFI
+ * to test if this driver can handle a certain device. Our implementation only checks
+ * if the device is a disk (i.e. that it supports the Block I/O and Disk I/O protocols)
+ * and implicitly checks if the disk is already in use by another driver.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_DriverBinding_Supported(IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+                                                  IN EFI_HANDLE                   ControllerHandle,
+                                                  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath)
+{
+    EFI_STATUS          Status;
+    EFI_DISK_IO         *DiskIo;
+
+    // we check for both DiskIO and BlockIO protocols
+
+    // first, open DiskIO
+    Status = refit_call6_wrapper(BS->OpenProtocol, ControllerHandle,
+                              &gEfiDiskIoProtocolGuid,
+                              (VOID **) &DiskIo,
+                              This->DriverBindingHandle,
+                              ControllerHandle,
+                              EFI_OPEN_PROTOCOL_BY_DRIVER);
+    if (EFI_ERROR(Status))
+        return Status;
+
+    // we were just checking, close it again
+    refit_call4_wrapper(BS->CloseProtocol, ControllerHandle,
+                      &gEfiDiskIoProtocolGuid,
+                      This->DriverBindingHandle,
+                      ControllerHandle);
+
+    // next, check BlockIO without actually opening it
+    Status = refit_call6_wrapper(BS->OpenProtocol, ControllerHandle,
+                              &gEfiBlockIoProtocolGuid,
+                              NULL,
+                              This->DriverBindingHandle,
+                              ControllerHandle,
+                              EFI_OPEN_PROTOCOL_TEST_PROTOCOL);
+    return Status;
+}
+
+/**
+ * Driver Binding EFI protocol, Start function. This function is called by EFI
+ * to start driving the given device. It is still possible at this point to
+ * return EFI_UNSUPPORTED, and in fact we will do so if the file system driver
+ * cannot find the superblock signature (or equivalent) that it expects.
+ *
+ * This function allocates memory for a per-volume structure, opens the
+ * required protocols (just Disk I/O in our case, Block I/O is only looked
+ * at to get the MediaId field), and lets the FSW core mount the file system.
+ * If successful, an EFI Simple File System protocol is exported on the
+ * device handle.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_DriverBinding_Start(IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+                                              IN EFI_HANDLE                   ControllerHandle,
+                                              IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath)
+{
+    EFI_STATUS          Status;
+    EFI_BLOCK_IO        *BlockIo;
+    EFI_DISK_IO         *DiskIo;
+    FSW_VOLUME_DATA     *Volume;
+
+#if DEBUG_LEVEL
+    Print(L"fsw_efi_DriverBinding_Start\n");
+#endif
+
+    // open consumed protocols
+    Status = refit_call6_wrapper(BS->OpenProtocol, ControllerHandle,
+                              &gEfiBlockIoProtocolGuid,
+                              (VOID **) &BlockIo,
+                              This->DriverBindingHandle,
+                              ControllerHandle,
+                              EFI_OPEN_PROTOCOL_GET_PROTOCOL);   // NOTE: we only want to look at the MediaId
+    if (EFI_ERROR(Status)) {
+//        Print(L"Fsw ERROR: OpenProtocol(BlockIo) returned %x\n", Status);
+        return Status;
+    }
+
+    Status = refit_call6_wrapper(BS->OpenProtocol, ControllerHandle,
+                              &gEfiDiskIoProtocolGuid,
+                              (VOID **) &DiskIo,
+                              This->DriverBindingHandle,
+                              ControllerHandle,
+                              EFI_OPEN_PROTOCOL_BY_DRIVER);
+    if (EFI_ERROR(Status)) {
+        Print(L"Fsw ERROR: OpenProtocol(DiskIo) returned %x\n", Status);
+        return Status;
+    }
+
+    // allocate volume structure
+    Volume = AllocateZeroPool(sizeof(FSW_VOLUME_DATA));
+    Volume->Signature       = FSW_VOLUME_DATA_SIGNATURE;
+    Volume->Handle          = ControllerHandle;
+    Volume->DiskIo          = DiskIo;
+    Volume->MediaId         = BlockIo->Media->MediaId;
+    Volume->LastIOStatus    = EFI_SUCCESS;
+
+    // mount the filesystem
+    Status = fsw_efi_map_status(fsw_mount(Volume, &fsw_efi_host_table,
+                                          &FSW_FSTYPE_TABLE_NAME(FSTYPE), &Volume->vol),
+                                Volume);
+
+    if (!EFI_ERROR(Status)) {
+        // register the SimpleFileSystem protocol
+        Volume->FileSystem.Revision     = EFI_FILE_IO_INTERFACE_REVISION;
+        Volume->FileSystem.OpenVolume   = fsw_efi_FileSystem_OpenVolume;
+        Status = refit_call4_wrapper(BS->InstallMultipleProtocolInterfaces, &ControllerHandle,
+                                                       &gEfiSimpleFileSystemProtocolGuid,
+                                                       &Volume->FileSystem,
+                                                       NULL);
+        if (EFI_ERROR(Status)) {
+//            Print(L"Fsw ERROR: InstallMultipleProtocolInterfaces returned %x\n", Status);
+        }
+    }
+
+    // on errors, close the opened protocols
+    if (EFI_ERROR(Status)) {
+        if (Volume->vol != NULL)
+            fsw_unmount(Volume->vol);
+        FreePool(Volume);
+
+        refit_call4_wrapper(BS->CloseProtocol, ControllerHandle,
+                          &gEfiDiskIoProtocolGuid,
+                          This->DriverBindingHandle,
+                          ControllerHandle);
+    }
+    return Status;
+}
+
+/**
+ * Driver Binding EFI protocol, Stop function. This function is called by EFI
+ * to stop the driver on the given device. This translates to an unmount
+ * call for the FSW core.
+ *
+ * We assume that all file handles on the volume have been closed before
+ * the driver is stopped. At least with the EFI shell, that is actually the
+ * case; it closes all file handles between commands.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_DriverBinding_Stop(IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
+                                             IN  EFI_HANDLE                   ControllerHandle,
+                                             IN  UINTN                        NumberOfChildren,
+                                             IN  EFI_HANDLE                   *ChildHandleBuffer)
+{
+    EFI_STATUS          Status;
+    EFI_FILE_IO_INTERFACE *FileSystem;
+    FSW_VOLUME_DATA     *Volume;
+
+#if DEBUG_LEVEL
+    Print(L"fsw_efi_DriverBinding_Stop\n");
+#endif
+
+    // get the installed SimpleFileSystem interface
+    Status = refit_call6_wrapper(BS->OpenProtocol, ControllerHandle,
+                              &gEfiSimpleFileSystemProtocolGuid,
+                              (VOID **) &FileSystem,
+                              This->DriverBindingHandle,
+                              ControllerHandle,
+                              EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+    if (EFI_ERROR(Status))
+        return EFI_UNSUPPORTED;
+
+    // get private data structure
+    Volume = FSW_VOLUME_FROM_FILE_SYSTEM(FileSystem);
+
+    // uninstall Simple File System protocol
+    Status = refit_call4_wrapper(BS->UninstallMultipleProtocolInterfaces, ControllerHandle,
+                                                     &gEfiSimpleFileSystemProtocolGuid, &Volume->FileSystem,
+                                                     NULL);
+    if (EFI_ERROR(Status)) {
+ //       Print(L"Fsw ERROR: UninstallMultipleProtocolInterfaces returned %x\n", Status);
+        return Status;
+    }
+#if DEBUG_LEVEL
+    Print(L"fsw_efi_DriverBinding_Stop: protocol uninstalled successfully\n");
+#endif
+
+    // release private data structure
+    if (Volume->vol != NULL)
+        fsw_unmount(Volume->vol);
+    FreePool(Volume);
+
+    // close the consumed protocols
+    Status = refit_call4_wrapper(BS->CloseProtocol, ControllerHandle,
+                               &gEfiDiskIoProtocolGuid,
+                               This->DriverBindingHandle,
+                               ControllerHandle);
+
+    // clear the cache
+    fsw_efi_clear_cache();
+
+    return Status;
+}
+
+/**
+ * Component Name EFI protocol, GetDriverName function. Used by the EFI
+ * environment to inquire the name of this driver. The name returned is
+ * based on the file system type actually used in compilation.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_ComponentName_GetDriverName(IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
+                                                      IN  CHAR8                        *Language,
+                                                      OUT CHAR16                       **DriverName)
+{
+    if (Language == NULL || DriverName == NULL)
+        return EFI_INVALID_PARAMETER;
+
+    if (Language[0] == 'e' && Language[1] == 'n' && Language[2] == 'g' && Language[3] == 0) {
+        *DriverName = FSW_EFI_DRIVER_NAME(FSTYPE);
+        return EFI_SUCCESS;
+    }
+    return EFI_UNSUPPORTED;
+}
+
+/**
+ * Component Name EFI protocol, GetControllerName function. Not implemented
+ * because this is not a "bus" driver in the sense of the EFI Driver Model.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_ComponentName_GetControllerName(IN  EFI_COMPONENT_NAME_PROTOCOL    *This,
+                                                          IN  EFI_HANDLE                     ControllerHandle,
+                                                          IN  EFI_HANDLE                     ChildHandle  OPTIONAL,
+                                                          IN  CHAR8                          *Language,
+                                                          OUT CHAR16                         **ControllerName)
+{
+    return EFI_UNSUPPORTED;
+}
+
+/**
+ * FSW interface function for block size changes. This function is called by the FSW core
+ * when the file system driver changes the block sizes for the volume.
+ */
+
+void EFIAPI fsw_efi_change_blocksize(struct fsw_volume *vol,
+                              fsw_u32 old_phys_blocksize, fsw_u32 old_log_blocksize,
+                              fsw_u32 new_phys_blocksize, fsw_u32 new_log_blocksize)
+{
+    // nothing to do
+}
+
+/**
+ * FSW interface function to read data blocks. This function is called by the FSW core
+ * to read a block of data from the device. The buffer is allocated by the core code.
+ * Two caches are maintained, so as to improve performance on some systems. (VirtualBox
+ * is particularly susceptible to performance problems with an uncached driver -- the
+ * ext2 driver can take 200 seconds to load a Linux kernel under VirtualBox, whereas
+ * the time is more like 3 seconds with a cache!) Two independent caches are maintained
+ * because the ext2fs driver tends to alternate between accessing two parts of the
+ * disk.
+ */
+
+fsw_status_t EFIAPI fsw_efi_read_block(struct fsw_volume *vol, fsw_u64 phys_bno, void *buffer) {
+   int              i, ReadCache = -1;
+   FSW_VOLUME_DATA  *Volume = (FSW_VOLUME_DATA *)vol->host_data;
+   EFI_STATUS       Status = EFI_SUCCESS;
+   BOOLEAN          ReadOneBlock = FALSE;
+   UINT64           StartRead = (UINT64) phys_bno * (UINT64) vol->phys_blocksize;
+
+   if (buffer == NULL)
+      return (fsw_status_t) EFI_BAD_BUFFER_SIZE;
+
+   // Initialize static data structures, if necessary....
+   if (LastRead < 0) {
+      fsw_efi_clear_cache();
+   } // if
+
+   // Look for a cache hit on the current query....
+   i = 0;
+   do {
+      if ((Caches[i].Volume == Volume) &&
+          (Caches[i].CacheValid == TRUE) &&
+          (StartRead >= Caches[i].CacheStart) &&
+          ((StartRead + vol->phys_blocksize) <= (Caches[i].CacheStart + CACHE_SIZE))) {
+         ReadCache = i;
+      }
+      i++;
+   } while ((i < NUM_CACHES) && (ReadCache < 0));
+
+   // No cache hit found; load new cache and pass it on....
+   if (ReadCache < 0) {
+      if (LastRead == -1)
+         LastRead = 1;
+      ReadCache = 1 - LastRead; // NOTE: If NUM_CACHES > 2, this must become more complex
+      Caches[ReadCache].CacheValid = FALSE;
+      if (Caches[ReadCache].Cache == NULL)
+         Caches[ReadCache].Cache = AllocatePool(CACHE_SIZE);
+      if (Caches[ReadCache].Cache != NULL) {
+         // TODO: Below call hangs on my 32-bit Mac Mini when compiled with GNU-EFI.
+         // The same binary is fine under VirtualBox, and the same call is fine when
+         // compiled with Tianocore. Further clue: Omitting "Status =" avoids the
+         // hang but produces a failure to mount the filesystem, even when the same
+         // change is made to later similar call. Calling Volume->DiskIo->ReadDisk()
+         // directly (without refit_call5_wrapper()) changes nothing. FIGURE THIS OUT!
+         Status = refit_call5_wrapper(Volume->DiskIo->ReadDisk, Volume->DiskIo, Volume->MediaId,
+                                      StartRead, (UINTN) CACHE_SIZE, (VOID*) Caches[ReadCache].Cache);
+         if (!EFI_ERROR(Status)) {
+            Caches[ReadCache].CacheStart = StartRead;
+            Caches[ReadCache].CacheValid = TRUE;
+            Caches[ReadCache].Volume = Volume;
+            LastRead = ReadCache;
+         } else {
+            ReadOneBlock = TRUE;
+         }
+      } else {
+         ReadOneBlock = TRUE;
+      } // if cache memory allocated
+   } // if (ReadCache < 0)
+
+   if (Caches[ReadCache].Cache != NULL && Caches[ReadCache].CacheValid == TRUE && vol->phys_blocksize > 0) {
+      CopyMem(buffer, &Caches[ReadCache].Cache[StartRead - Caches[ReadCache].CacheStart], vol->phys_blocksize);
+   } else {
+      ReadOneBlock = TRUE;
+   }
+
+   if (ReadOneBlock) { // Something's failed, so try a simple disk read of one block....
+      Status = refit_call5_wrapper(Volume->DiskIo->ReadDisk, Volume->DiskIo, Volume->MediaId,
+                                   phys_bno * vol->phys_blocksize,
+                                   (UINTN) vol->phys_blocksize,
+                                   (VOID*) buffer);
+   }
+   Volume->LastIOStatus = Status;
+
+   return Status;
+} // fsw_status_t *fsw_efi_read_block()
+
+/**
+ * Map FSW status codes to EFI status codes. The FSW_IO_ERROR code is only produced
+ * by fsw_efi_read_block, so we map it back to the EFI status code remembered from
+ * the last I/O operation.
+ */
+
+EFI_STATUS fsw_efi_map_status(fsw_status_t fsw_status, FSW_VOLUME_DATA *Volume)
+{
+    switch (fsw_status) {
+        case FSW_SUCCESS:
+            return EFI_SUCCESS;
+        case FSW_OUT_OF_MEMORY:
+            return EFI_VOLUME_CORRUPTED;
+        case FSW_IO_ERROR:
+            return Volume->LastIOStatus;
+        case FSW_UNSUPPORTED:
+            return EFI_UNSUPPORTED;
+        case FSW_NOT_FOUND:
+            return EFI_NOT_FOUND;
+        case FSW_VOLUME_CORRUPTED:
+            return EFI_VOLUME_CORRUPTED;
+        default:
+            return EFI_DEVICE_ERROR;
+    }
+}
+
+/**
+ * File System EFI protocol, OpenVolume function. Creates a file handle for
+ * the root directory and returns it. Note that this function may be called
+ * multiple times and returns a new file handle each time. Each returned
+ * handle is closed by the client using it.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileSystem_OpenVolume(IN EFI_FILE_IO_INTERFACE *This,
+                                                OUT EFI_FILE **Root)
+{
+    EFI_STATUS          Status;
+    FSW_VOLUME_DATA     *Volume = FSW_VOLUME_FROM_FILE_SYSTEM(This);
+
+#if DEBUG_LEVEL
+    Print(L"fsw_efi_FileSystem_OpenVolume\n");
+#endif
+
+    fsw_efi_clear_cache();
+    Status = fsw_efi_dnode_to_FileHandle(Volume->vol->root, Root);
+
+    return Status;
+}
+
+/**
+ * File Handle EFI protocol, Open function. Dispatches the call
+ * based on the kind of file handle.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileHandle_Open(IN EFI_FILE *This,
+                                          OUT EFI_FILE **NewHandle,
+                                          IN CHAR16 *FileName,
+                                          IN UINT64 OpenMode,
+                                          IN UINT64 Attributes)
+{
+    FSW_FILE_DATA      *File = FSW_FILE_FROM_FILE_HANDLE(This);
+
+    if (File->Type == FSW_EFI_FILE_TYPE_DIR)
+        return fsw_efi_dir_open(File, NewHandle, FileName, OpenMode, Attributes);
+    // not supported for regular files
+    return EFI_UNSUPPORTED;
+}
+
+/**
+ * File Handle EFI protocol, Close function. Closes the FSW shandle
+ * and frees the memory used for the structure.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileHandle_Close(IN EFI_FILE *This)
+{
+    FSW_FILE_DATA      *File = FSW_FILE_FROM_FILE_HANDLE(This);
+
+#if DEBUG_LEVEL
+    Print(L"fsw_efi_FileHandle_Close\n");
+#endif
+
+    fsw_shandle_close(&File->shand);
+    FreePool(File);
+
+    return EFI_SUCCESS;
+}
+
+/**
+ * File Handle EFI protocol, Delete function. Calls through to Close
+ * and returns a warning because this driver is read-only.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileHandle_Delete(IN EFI_FILE *This)
+{
+    EFI_STATUS          Status;
+
+    Status = refit_call1_wrapper(This->Close, This);
+    if (Status == EFI_SUCCESS) {
+        // this driver is read-only
+        Status = EFI_WARN_DELETE_FAILURE;
+    }
+
+    return Status;
+}
+
+/**
+ * File Handle EFI protocol, Read function. Dispatches the call
+ * based on the kind of file handle.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileHandle_Read(IN EFI_FILE *This,
+                                          IN OUT UINTN *BufferSize,
+                                          OUT VOID *Buffer)
+{
+    FSW_FILE_DATA      *File = FSW_FILE_FROM_FILE_HANDLE(This);
+
+    if (File->Type == FSW_EFI_FILE_TYPE_FILE)
+        return fsw_efi_file_read(File, BufferSize, Buffer);
+    else if (File->Type == FSW_EFI_FILE_TYPE_DIR)
+        return fsw_efi_dir_read(File, BufferSize, Buffer);
+    return EFI_UNSUPPORTED;
+}
+
+/**
+ * File Handle EFI protocol, Write function. Returns unsupported status
+ * because this driver is read-only.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileHandle_Write(IN EFI_FILE *This,
+                                           IN OUT UINTN *BufferSize,
+                                           IN VOID *Buffer)
+{
+    // this driver is read-only
+    return EFI_WRITE_PROTECTED;
+}
+
+/**
+ * File Handle EFI protocol, GetPosition function. Dispatches the call
+ * based on the kind of file handle.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileHandle_GetPosition(IN EFI_FILE *This,
+                                                 OUT UINT64 *Position)
+{
+    FSW_FILE_DATA      *File = FSW_FILE_FROM_FILE_HANDLE(This);
+
+    if (File->Type == FSW_EFI_FILE_TYPE_FILE)
+        return fsw_efi_file_getpos(File, Position);
+    // not defined for directories
+    return EFI_UNSUPPORTED;
+}
+
+/**
+ * File Handle EFI protocol, SetPosition function. Dispatches the call
+ * based on the kind of file handle.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileHandle_SetPosition(IN EFI_FILE *This,
+                                                 IN UINT64 Position)
+{
+    FSW_FILE_DATA      *File = FSW_FILE_FROM_FILE_HANDLE(This);
+
+    if (File->Type == FSW_EFI_FILE_TYPE_FILE)
+        return fsw_efi_file_setpos(File, Position);
+    else if (File->Type == FSW_EFI_FILE_TYPE_DIR)
+        return fsw_efi_dir_setpos(File, Position);
+    return EFI_UNSUPPORTED;
+}
+
+/**
+ * File Handle EFI protocol, GetInfo function. Dispatches to the common
+ * function implementing this.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileHandle_GetInfo(IN EFI_FILE *This,
+                                             IN EFI_GUID *InformationType,
+                                             IN OUT UINTN *BufferSize,
+                                             OUT VOID *Buffer)
+{
+    FSW_FILE_DATA      *File = FSW_FILE_FROM_FILE_HANDLE(This);
+
+    return fsw_efi_dnode_getinfo(File, InformationType, BufferSize, Buffer);
+}
+
+/**
+ * File Handle EFI protocol, SetInfo function. Returns unsupported status
+ * because this driver is read-only.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileHandle_SetInfo(IN EFI_FILE *This,
+                                             IN EFI_GUID *InformationType,
+                                             IN UINTN BufferSize,
+                                             IN VOID *Buffer)
+{
+    // this driver is read-only
+    return EFI_WRITE_PROTECTED;
+}
+
+/**
+ * File Handle EFI protocol, Flush function. Returns unsupported status
+ * because this driver is read-only.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileHandle_Flush(IN EFI_FILE *This)
+{
+    // this driver is read-only
+    return EFI_WRITE_PROTECTED;
+}
+
+/**
+ * Set up a file handle for a dnode. This function allocates a data structure
+ * for a file handle, opens a FSW shandle and populates the EFI_FILE structure
+ * with the interface functions.
+ */
+
+EFI_STATUS fsw_efi_dnode_to_FileHandle(IN struct fsw_dnode *dno,
+                                       OUT EFI_FILE **NewFileHandle)
+{
+    EFI_STATUS          Status;
+    FSW_FILE_DATA       *File;
+
+    // make sure the dnode has complete info
+    Status = fsw_efi_map_status(fsw_dnode_fill(dno), (FSW_VOLUME_DATA *)dno->vol->host_data);
+    if (EFI_ERROR(Status))
+        return Status;
+
+    // check type
+    if (dno->type != FSW_DNODE_TYPE_FILE && dno->type != FSW_DNODE_TYPE_DIR)
+        return EFI_UNSUPPORTED;
+
+    // allocate file structure
+    File = AllocateZeroPool(sizeof(FSW_FILE_DATA));
+    File->Signature = FSW_FILE_DATA_SIGNATURE;
+    if (dno->type == FSW_DNODE_TYPE_FILE)
+        File->Type = FSW_EFI_FILE_TYPE_FILE;
+    else if (dno->type == FSW_DNODE_TYPE_DIR)
+        File->Type = FSW_EFI_FILE_TYPE_DIR;
+
+    // open shandle
+    Status = fsw_efi_map_status(fsw_shandle_open(dno, &File->shand),
+                                (FSW_VOLUME_DATA *)dno->vol->host_data);
+    if (EFI_ERROR(Status)) {
+        FreePool(File);
+        return Status;
+    }
+
+    // populate the file handle
+    File->FileHandle.Revision    = EFI_FILE_HANDLE_REVISION;
+    File->FileHandle.Open        = fsw_efi_FileHandle_Open;
+    File->FileHandle.Close       = fsw_efi_FileHandle_Close;
+    File->FileHandle.Delete      = fsw_efi_FileHandle_Delete;
+    File->FileHandle.Read        = fsw_efi_FileHandle_Read;
+    File->FileHandle.Write       = fsw_efi_FileHandle_Write;
+    File->FileHandle.GetPosition = fsw_efi_FileHandle_GetPosition;
+    File->FileHandle.SetPosition = fsw_efi_FileHandle_SetPosition;
+    File->FileHandle.GetInfo     = fsw_efi_FileHandle_GetInfo;
+    File->FileHandle.SetInfo     = fsw_efi_FileHandle_SetInfo;
+    File->FileHandle.Flush       = fsw_efi_FileHandle_Flush;
+
+    *NewFileHandle = &File->FileHandle;
+    return EFI_SUCCESS;
+}
+
+/**
+ * Data read function for regular files. Calls through to fsw_shandle_read.
+ */
+
+EFI_STATUS fsw_efi_file_read(IN FSW_FILE_DATA *File,
+                             IN OUT UINTN *BufferSize,
+                             OUT VOID *Buffer)
+{
+    EFI_STATUS          Status;
+    fsw_u32             buffer_size;
+
+#if DEBUG_LEVEL
+    Print(L"fsw_efi_file_read %d bytes\n", *BufferSize);
+#endif
+
+    buffer_size = (fsw_u32)*BufferSize;
+    Status = fsw_efi_map_status(fsw_shandle_read(&File->shand, &buffer_size, Buffer),
+                                (FSW_VOLUME_DATA *)File->shand.dnode->vol->host_data);
+    *BufferSize = buffer_size;
+
+    return Status;
+}
+
+/**
+ * Get file position for regular files.
+ */
+
+EFI_STATUS fsw_efi_file_getpos(IN FSW_FILE_DATA *File,
+                               OUT UINT64 *Position)
+{
+    *Position = File->shand.pos;
+    return EFI_SUCCESS;
+}
+
+/**
+ * Set file position for regular files. EFI specifies the all-ones value
+ * to be a special value for the end of the file.
+ */
+
+EFI_STATUS fsw_efi_file_setpos(IN FSW_FILE_DATA *File, IN UINT64 Position)
+{
+    if (Position == 0xFFFFFFFFFFFFFFFFULL)
+        File->shand.pos = File->shand.dnode->size;
+    else
+        File->shand.pos = Position;
+    return EFI_SUCCESS;
+}
+
+/**
+ * Open function used to open new file handles relative to a directory.
+ * In EFI, the "open file" function is implemented by directory file handles
+ * and is passed a relative or volume-absolute path to the file or directory
+ * to open. We use fsw_dnode_lookup_path to find the node plus an additional
+ * call to fsw_dnode_resolve because EFI has no concept of symbolic links.
+ */
+
+EFI_STATUS fsw_efi_dir_open(IN FSW_FILE_DATA *File,
+                            OUT EFI_FILE **NewHandle,
+                            IN CHAR16 *FileName,
+                            IN UINT64 OpenMode,
+                            IN UINT64 Attributes)
+{
+    EFI_STATUS          Status;
+    FSW_VOLUME_DATA     *Volume = (FSW_VOLUME_DATA *)File->shand.dnode->vol->host_data;
+    struct fsw_dnode    *dno;
+    struct fsw_dnode    *target_dno;
+    struct fsw_string   lookup_path;
+
+#if DEBUG_LEVEL
+    Print(L"fsw_efi_dir_open: '%s'\n", FileName);
+#endif
+
+    if (OpenMode != EFI_FILE_MODE_READ)
+        return EFI_WRITE_PROTECTED;
+
+    lookup_path.type = FSW_STRING_TYPE_UTF16;
+    lookup_path.len  = (int)StrLen(FileName);
+    lookup_path.size = lookup_path.len * sizeof(fsw_u16);
+    lookup_path.data = FileName;
+
+    // resolve the path (symlinks along the way are automatically resolved)
+    Status = fsw_efi_map_status(fsw_dnode_lookup_path(File->shand.dnode, &lookup_path, '\\', &dno), Volume);
+    if (EFI_ERROR(Status))
+        return Status;
+
+    // if the final node is a symlink, also resolve it
+    Status = fsw_efi_map_status(fsw_dnode_resolve(dno, &target_dno), Volume);
+    fsw_dnode_release(dno);
+    if (EFI_ERROR(Status))
+        return Status;
+    dno = target_dno;
+
+    // make a new EFI handle for the target dnode
+    Status = fsw_efi_dnode_to_FileHandle(dno, NewHandle);
+    fsw_dnode_release(dno);
+    return Status;
+}
+
+/**
+ * Read function for directories. A file handle read on a directory retrieves
+ * the next directory entry.
+ */
+
+EFI_STATUS fsw_efi_dir_read(IN FSW_FILE_DATA *File,
+                            IN OUT UINTN *BufferSize,
+                            OUT VOID *Buffer)
+{
+    EFI_STATUS          Status;
+    FSW_VOLUME_DATA     *Volume = (FSW_VOLUME_DATA *)File->shand.dnode->vol->host_data;
+    struct fsw_dnode    *dno;
+
+#if DEBUG_LEVEL
+    Print(L"fsw_efi_dir_read...\n");
+#endif
+
+    // read the next entry
+    Status = fsw_efi_map_status(fsw_dnode_dir_read(&File->shand, &dno), Volume);
+    if (Status == EFI_NOT_FOUND) {
+        // end of directory
+        *BufferSize = 0;
+#if DEBUG_LEVEL
+        Print(L"...no more entries\n");
+#endif
+        return EFI_SUCCESS;
+    }
+    if (EFI_ERROR(Status))
+        return Status;
+
+    // get info into buffer
+    Status = fsw_efi_dnode_fill_FileInfo(Volume, dno, BufferSize, Buffer);
+    fsw_dnode_release(dno);
+    return Status;
+}
+
+/**
+ * Set file position for directories. The only allowed set position operation
+ * for directories is to rewind the directory completely by setting the
+ * position to zero.
+ */
+
+EFI_STATUS fsw_efi_dir_setpos(IN FSW_FILE_DATA *File, IN UINT64 Position)
+{
+    if (Position == 0) {
+        File->shand.pos = 0;
+        return EFI_SUCCESS;
+    } else {
+        // directories can only rewind to the start
+        return EFI_UNSUPPORTED;
+    }
+}
+
+/**
+ * Get file or volume information. This function implements the GetInfo call
+ * for all file handles. Control is dispatched according to the type of information
+ * requested by the caller.
+ */
+
+EFI_STATUS fsw_efi_dnode_getinfo(IN FSW_FILE_DATA *File,
+                                 IN EFI_GUID *InformationType,
+                                 IN OUT UINTN *BufferSize,
+                                 OUT VOID *Buffer)
+{
+    EFI_STATUS            Status;
+    FSW_VOLUME_DATA       *Volume = (FSW_VOLUME_DATA *)File->shand.dnode->vol->host_data;
+    EFI_FILE_SYSTEM_INFO  *FSInfo;
+    UINTN                 RequiredSize;
+    struct fsw_volume_stat vsb;
+
+
+    if (CompareGuid(InformationType, &gEfiFileInfoGuid)) {
+#if DEBUG_LEVEL
+        Print(L"fsw_efi_dnode_getinfo: FILE_INFO\n");
+#endif
+
+        Status = fsw_efi_dnode_fill_FileInfo(Volume, File->shand.dnode, BufferSize, Buffer);
+
+    } else if (CompareGuid(InformationType, &gEfiFileSystemInfoGuid)) {
+#if DEBUG_LEVEL
+        Print(L"fsw_efi_dnode_getinfo: FILE_SYSTEM_INFO\n");
+#endif
+
+        // check buffer size
+        RequiredSize = SIZE_OF_EFI_FILE_SYSTEM_INFO + fsw_efi_strsize(&Volume->vol->label);
+        if (*BufferSize < RequiredSize) {
+            *BufferSize = RequiredSize;
+            return EFI_BUFFER_TOO_SMALL;
+        }
+
+        // fill structure
+        FSInfo = (EFI_FILE_SYSTEM_INFO *)Buffer;
+        FSInfo->Size        = RequiredSize;
+        FSInfo->ReadOnly    = TRUE;
+        FSInfo->BlockSize   = Volume->vol->log_blocksize;
+        fsw_efi_strcpy(FSInfo->VolumeLabel, &Volume->vol->label);
+
+        // get the missing info from the fs driver
+        ZeroMem(&vsb, sizeof(struct fsw_volume_stat));
+        Status = fsw_efi_map_status(fsw_volume_stat(Volume->vol, &vsb), Volume);
+        if (EFI_ERROR(Status))
+            return Status;
+        FSInfo->VolumeSize  = vsb.total_bytes;
+        FSInfo->FreeSpace   = vsb.free_bytes;
+
+        // prepare for return
+        *BufferSize = RequiredSize;
+        Status = EFI_SUCCESS;
+
+    } else if (CompareGuid(InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {
+#if DEBUG_LEVEL
+        Print(L"fsw_efi_dnode_getinfo: FILE_SYSTEM_VOLUME_LABEL\n");
+#endif
+
+        // check buffer size
+        RequiredSize = SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL_INFO + fsw_efi_strsize(&Volume->vol->label);
+        if (*BufferSize < RequiredSize) {
+            *BufferSize = RequiredSize;
+            return EFI_BUFFER_TOO_SMALL;
+        }
+
+        // copy volume label
+        fsw_efi_strcpy(((EFI_FILE_SYSTEM_VOLUME_LABEL_INFO *)Buffer)->VolumeLabel, &Volume->vol->label);
+
+        // prepare for return
+        *BufferSize = RequiredSize;
+        Status = EFI_SUCCESS;
+
+    } else {
+        Status = EFI_UNSUPPORTED;
+    }
+
+    return Status;
+}
+
+/**
+ * Time mapping callback for the fsw_dnode_stat call. This function converts
+ * a Posix style timestamp into an EFI_TIME structure and writes it to the
+ * appropriate member of the EFI_FILE_INFO structure that we're filling.
+ */
+
+void fsw_store_time_posix(struct fsw_dnode_stat *sb, int which, fsw_u32 posix_time)
+{
+    EFI_FILE_INFO       *FileInfo = (EFI_FILE_INFO *)sb->host_data;
+
+    if (which == FSW_DNODE_STAT_CTIME)
+        fsw_efi_decode_time(&FileInfo->CreateTime,       posix_time);
+    else if (which == FSW_DNODE_STAT_MTIME)
+        fsw_efi_decode_time(&FileInfo->ModificationTime, posix_time);
+    else if (which == FSW_DNODE_STAT_ATIME)
+        fsw_efi_decode_time(&FileInfo->LastAccessTime,   posix_time);
+}
+
+/**
+ * Mode mapping callback for the fsw_dnode_stat call. This function looks at
+ * the Posix mode passed by the file system driver and makes appropriate
+ * adjustments to the EFI_FILE_INFO structure that we're filling.
+ */
+
+void fsw_store_attr_posix(struct fsw_dnode_stat *sb, fsw_u16 posix_mode)
+{
+    EFI_FILE_INFO       *FileInfo = (EFI_FILE_INFO *)sb->host_data;
+
+    if ((posix_mode & S_IWUSR) == 0)
+        FileInfo->Attribute |= EFI_FILE_READ_ONLY;
+}
+
+void fsw_store_attr_efi(struct fsw_dnode_stat *sb, fsw_u16 attr)
+{
+    EFI_FILE_INFO       *FileInfo = (EFI_FILE_INFO *)sb->host_data;
+
+    FileInfo->Attribute |= attr;
+}
+
+/**
+ * Common function to fill an EFI_FILE_INFO with information about a dnode.
+ */
+
+EFI_STATUS fsw_efi_dnode_fill_FileInfo(IN FSW_VOLUME_DATA *Volume,
+                                       IN struct fsw_dnode *dno,
+                                       IN OUT UINTN *BufferSize,
+                                       OUT VOID *Buffer)
+{
+    EFI_STATUS          Status;
+    EFI_FILE_INFO       *FileInfo;
+    UINTN               RequiredSize;
+    struct fsw_dnode_stat sb;
+
+    // make sure the dnode has complete info
+    Status = fsw_efi_map_status(fsw_dnode_fill(dno), Volume);
+    if (EFI_ERROR(Status))
+        return Status;
+
+    // TODO: check/assert that the dno's name is in UTF16
+
+    // check buffer size
+    RequiredSize = SIZE_OF_EFI_FILE_INFO + fsw_efi_strsize(&dno->name);
+    if (*BufferSize < RequiredSize) {
+        // TODO: wind back the directory in this case
+
+#if DEBUG_LEVEL
+        Print(L"...BUFFER TOO SMALL\n");
+#endif
+        *BufferSize = RequiredSize;
+        return EFI_BUFFER_TOO_SMALL;
+    }
+
+    // fill structure
+    ZeroMem(Buffer, RequiredSize);
+    FileInfo = (EFI_FILE_INFO *)Buffer;
+    FileInfo->Size = RequiredSize;
+    FileInfo->FileSize          = dno->size;
+    FileInfo->Attribute         = 0;
+    if (dno->type == FSW_DNODE_TYPE_DIR)
+        FileInfo->Attribute    |= EFI_FILE_DIRECTORY;
+    fsw_efi_strcpy(FileInfo->FileName, &dno->name);
+
+    // get the missing info from the fs driver
+    ZeroMem(&sb, sizeof(struct fsw_dnode_stat));
+    sb.host_data = FileInfo;
+    Status = fsw_efi_map_status(fsw_dnode_stat(dno, &sb), Volume);
+    if (EFI_ERROR(Status))
+        return Status;
+    FileInfo->PhysicalSize      = sb.used_bytes;
+
+    // prepare for return
+    *BufferSize = RequiredSize;
+#if DEBUG_LEVEL
+    Print(L"...returning '%s'\n", FileInfo->FileName);
+#endif
+    return EFI_SUCCESS;
+}
+
+// EOF
diff --git a/filesystems/fsw_efi.h b/filesystems/fsw_efi.h
new file mode 100644 (file)
index 0000000..bc9dac3
--- /dev/null
@@ -0,0 +1,105 @@
+/**
+ * \file fsw_efi.h
+ * EFI host environment header.
+*/
+
+/*-
+  * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _FSW_EFI_H_
+#define _FSW_EFI_H_
+
+#include "fsw_core.h"
+
+#ifdef __MAKEWITH_GNUEFI
+#define CompareGuid(a, b) CompareGuid(a, b)==0
+#endif
+
+/**
+ * EFI Host: Private per-volume structure.
+ */
+
+typedef struct {
+    UINT64                      Signature;      //!< Used to identify this structure
+
+    EFI_FILE_IO_INTERFACE       FileSystem;     //!< Published EFI protocol interface structure
+
+    EFI_HANDLE                  Handle;         //!< The device handle the protocol is attached to
+    EFI_DISK_IO                 *DiskIo;        //!< The Disk I/O protocol we use for disk access
+    UINT32                      MediaId;        //!< The media ID from the Block I/O protocol
+    EFI_STATUS                  LastIOStatus;   //!< Last status from Disk I/O
+
+    struct fsw_volume           *vol;           //!< FSW volume structure
+
+} FSW_VOLUME_DATA;
+
+/** Signature for the volume structure. */
+#define FSW_VOLUME_DATA_SIGNATURE  EFI_SIGNATURE_32 ('f', 's', 'w', 'V')
+/** Access macro for the volume structure. */
+#define FSW_VOLUME_FROM_FILE_SYSTEM(a)  CR (a, FSW_VOLUME_DATA, FileSystem, FSW_VOLUME_DATA_SIGNATURE)
+
+/**
+ * EFI Host: Private structure for a EFI_FILE interface.
+ */
+
+typedef struct {
+    UINT64                      Signature;      //!< Used to identify this structure
+
+    EFI_FILE                    FileHandle;     //!< Published EFI protocol interface structure
+
+    UINT64                       Type;           //!< File type used for dispatching
+    struct fsw_shandle          shand;          //!< FSW handle for this file
+
+} FSW_FILE_DATA;
+
+/** File type: regular file. */
+#define FSW_EFI_FILE_TYPE_FILE  (0)
+/** File type: directory. */
+#define FSW_EFI_FILE_TYPE_DIR   (1)
+
+/** Signature for the file handle structure. */
+#define FSW_FILE_DATA_SIGNATURE    EFI_SIGNATURE_32 ('f', 's', 'w', 'F')
+/** Access macro for the file handle structure. */
+#define FSW_FILE_FROM_FILE_HANDLE(a)  CR (a, FSW_FILE_DATA, FileHandle, FSW_FILE_DATA_SIGNATURE)
+
+
+//
+// Library functions
+//
+
+VOID fsw_efi_decode_time(OUT EFI_TIME *EfiTime, IN UINT32 UnixTime);
+
+UINTN fsw_efi_strsize(struct fsw_string *s);
+VOID fsw_efi_strcpy(CHAR16 *Dest, struct fsw_string *src);
+
+
+#endif
diff --git a/filesystems/fsw_efi_base.h b/filesystems/fsw_efi_base.h
new file mode 100644 (file)
index 0000000..f9d732d
--- /dev/null
@@ -0,0 +1,87 @@
+/**
+ * \file fsw_efi_base.h
+ * Base definitions for the EFI host environment.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _FSW_EFI_BASE_H_
+#define _FSW_EFI_BASE_H_
+
+// If its EDK2 EFI Toolkit
+#ifdef HOST_EFI_EDK2
+#include "fsw_efi_edk2_base.h"
+#else
+// Intel EFI Toolkit
+#include <efi.h>
+#include <efilib.h>
+#endif
+
+#define FSW_LITTLE_ENDIAN (1)
+
+
+// types, reuse EFI types
+
+typedef INT8    fsw_s8;
+typedef UINT8   fsw_u8;
+typedef INT16   fsw_s16;
+typedef UINT16  fsw_u16;
+typedef INT32   fsw_s32;
+typedef UINT32  fsw_u32;
+typedef INT64   fsw_s64;
+typedef UINT64  fsw_u64;
+
+
+// allocation functions
+
+#define fsw_alloc(size, ptrptr) (((*(ptrptr) = AllocatePool(size)) == NULL) ? FSW_OUT_OF_MEMORY : FSW_SUCCESS)
+#define fsw_free(ptr) FreePool(ptr)
+
+// memory functions
+
+#define fsw_memzero(dest,size) ZeroMem(dest,size)
+#define fsw_memcpy(dest,src,size) CopyMem(dest,src,size)
+#define fsw_memeq(p1,p2,size) (CompareMem(p1,p2,size) == 0)
+
+// message printing
+
+#define FSW_MSGSTR(s) L##s
+#define FSW_MSGFUNC Print
+
+// 64-bit hooks
+
+#define FSW_U64_SHR(val,shiftbits) RShiftU64((val), (shiftbits))
+#define FSW_U64_DIV(val,divisor) DivU64x32((val), (divisor), NULL)
+
+
+#endif
diff --git a/filesystems/fsw_efi_edk2_base.h b/filesystems/fsw_efi_edk2_base.h
new file mode 100644 (file)
index 0000000..ca14eb2
--- /dev/null
@@ -0,0 +1,76 @@
+/**
+ * \file fsw_efi_edk2_base.h
+ * Base definitions for the EDK EFI Toolkit environment.
+ */
+/*
+ * Copyright (c) 2012 Stefan Agner
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _FSW_EFI_EDK2_BASE_H_
+#define _FSW_EFI_EDK2_BASE_H_
+/*
+ * Here is common declarations for EDK<->EDK2 compatibility
+ */
+# include <Base.h>
+# include <Uefi.h>
+# include <Library/DebugLib.h>
+# include <Library/BaseLib.h>
+# include <Protocol/DriverBinding.h>
+# include <Library/BaseMemoryLib.h>
+# include <Library/UefiRuntimeServicesTableLib.h>
+# include <Library/UefiDriverEntryPoint.h>
+# include <Library/UefiBootServicesTableLib.h>
+# include <Library/MemoryAllocationLib.h>
+# include <Library/DevicePathLib.h>
+# include <Protocol/DevicePathFromText.h>
+# include <Protocol/DevicePathToText.h>
+# include <Protocol/DebugPort.h>
+# include <Protocol/DebugSupport.h>
+# include <Library/PrintLib.h>
+# include <Library/UefiLib.h>
+# include <Protocol/SimpleFileSystem.h>
+# include <Protocol/BlockIo.h>
+# include <Protocol/DiskIo.h>
+# include <Guid/FileSystemInfo.h>
+# include <Guid/FileInfo.h>
+# include <Guid/FileSystemVolumeLabelInfo.h>
+# include <Protocol/ComponentName.h>
+
+# define BS gBS
+
+# define EFI_FILE_HANDLE_REVISION EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION
+# define SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL_INFO  SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL
+# define EFI_FILE_SYSTEM_VOLUME_LABEL_INFO EFI_FILE_SYSTEM_VOLUME_LABEL
+# define EFI_SIGNATURE_32(a, b, c, d) SIGNATURE_32(a, b, c, d)
+# define DivU64x32(x,y,z) DivU64x32((x),(y))
+
+
+#endif
diff --git a/filesystems/fsw_efi_lib.c b/filesystems/fsw_efi_lib.c
new file mode 100644 (file)
index 0000000..31f7c2f
--- /dev/null
@@ -0,0 +1,129 @@
+/**
+ * \file fsw_efi_lib.c
+ * EFI host environment library functions.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsw_efi.h"
+
+
+//
+// time conversion
+//
+// Adopted from public domain code in FreeBSD libc.
+//
+
+#define SECSPERMIN      60
+#define MINSPERHOUR     60
+#define HOURSPERDAY     24
+#define DAYSPERWEEK     7
+#define DAYSPERNYEAR    365
+#define DAYSPERLYEAR    366
+#define SECSPERHOUR     (SECSPERMIN * MINSPERHOUR)
+#define SECSPERDAY      ((long) SECSPERHOUR * HOURSPERDAY)
+#define MONSPERYEAR     12
+
+#define EPOCH_YEAR      1970
+#define EPOCH_WDAY      TM_THURSDAY
+
+#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
+#define LEAPS_THRU_END_OF(y)    ((y) / 4 - (y) / 100 + (y) / 400)
+
+static const int mon_lengths[2][MONSPERYEAR] = {
+    { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
+    { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
+};
+static const int year_lengths[2] = {
+    DAYSPERNYEAR, DAYSPERLYEAR
+};
+
+VOID fsw_efi_decode_time(OUT EFI_TIME *EfiTime, IN UINT32 UnixTime)
+{
+    long        days, rem;
+    int         y, newy, yleap;
+    const int   *ip;
+
+    ZeroMem(EfiTime, sizeof(EFI_TIME));
+
+    days = UnixTime / SECSPERDAY;
+    rem = UnixTime % SECSPERDAY;
+
+    EfiTime->Hour = (UINT8) (rem / SECSPERHOUR);
+    rem = rem % SECSPERHOUR;
+    EfiTime->Minute = (UINT8) (rem / SECSPERMIN);
+    EfiTime->Second = (UINT8) (rem % SECSPERMIN);
+
+    y = EPOCH_YEAR;
+    while (days < 0 || days >= (long) year_lengths[yleap = isleap(y)]) {
+        newy = y + days / DAYSPERNYEAR;
+        if (days < 0)
+            --newy;
+        days -= (newy - y) * DAYSPERNYEAR +
+            LEAPS_THRU_END_OF(newy - 1) -
+            LEAPS_THRU_END_OF(y - 1);
+        y = newy;
+    }
+    EfiTime->Year = (UINT16)y;
+    ip = mon_lengths[yleap];
+    for (EfiTime->Month = 0; days >= (long) ip[EfiTime->Month]; ++(EfiTime->Month))
+        days = days - (long) ip[EfiTime->Month];
+    EfiTime->Month++;  // adjust range to EFI conventions
+    EfiTime->Day = (UINT8) (days + 1);
+}
+
+//
+// String functions, used for file and volume info
+//
+
+UINTN fsw_efi_strsize(struct fsw_string *s)
+{
+    if (s->type == FSW_STRING_TYPE_EMPTY)
+        return sizeof(CHAR16);
+    return (s->len + 1) * sizeof(CHAR16);
+}
+
+VOID fsw_efi_strcpy(CHAR16 *Dest, struct fsw_string *src)
+{
+    if (src->type == FSW_STRING_TYPE_EMPTY | src->size == 0) {
+        Dest[0] = 0;
+    } else if (src->type == FSW_STRING_TYPE_UTF16) {
+        CopyMem(Dest, src->data, src->size);
+        Dest[src->len] = 0;
+    } else {
+        // TODO: coerce, recurse
+        Dest[0] = 0;
+    }
+}
+
+// EOF
diff --git a/filesystems/fsw_ext2.c b/filesystems/fsw_ext2.c
new file mode 100644 (file)
index 0000000..4a0acf3
--- /dev/null
@@ -0,0 +1,558 @@
+/**
+ * \file fsw_ext2.c
+ * ext2 file system driver code.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include "fsw_ext2.h"
+
+
+// functions
+
+static fsw_status_t fsw_ext2_volume_mount(struct fsw_ext2_volume *vol);
+static void         fsw_ext2_volume_free(struct fsw_ext2_volume *vol);
+static fsw_status_t fsw_ext2_volume_stat(struct fsw_ext2_volume *vol, struct fsw_volume_stat *sb);
+
+static fsw_status_t fsw_ext2_dnode_fill(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno);
+static void         fsw_ext2_dnode_free(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno);
+static fsw_status_t fsw_ext2_dnode_stat(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno,
+                                        struct fsw_dnode_stat *sb);
+static fsw_status_t fsw_ext2_get_extent(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno,
+                                        struct fsw_extent *extent);
+
+static fsw_status_t fsw_ext2_dir_lookup(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno,
+                                        struct fsw_string *lookup_name, struct fsw_ext2_dnode **child_dno);
+static fsw_status_t fsw_ext2_dir_read(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno,
+                                      struct fsw_shandle *shand, struct fsw_ext2_dnode **child_dno);
+static fsw_status_t fsw_ext2_read_dentry(struct fsw_shandle *shand, struct ext2_dir_entry *entry);
+
+static fsw_status_t fsw_ext2_readlink(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno,
+                                      struct fsw_string *link);
+
+//
+// Dispatch Table
+//
+
+struct fsw_fstype_table   FSW_FSTYPE_TABLE_NAME(ext2) = {
+    { FSW_STRING_TYPE_ISO88591, 4, 4, "ext2" },
+    sizeof(struct fsw_ext2_volume),
+    sizeof(struct fsw_ext2_dnode),
+
+    fsw_ext2_volume_mount,
+    fsw_ext2_volume_free,
+    fsw_ext2_volume_stat,
+    fsw_ext2_dnode_fill,
+    fsw_ext2_dnode_free,
+    fsw_ext2_dnode_stat,
+    fsw_ext2_get_extent,
+    fsw_ext2_dir_lookup,
+    fsw_ext2_dir_read,
+    fsw_ext2_readlink,
+};
+
+/**
+ * Mount an ext2 volume. Reads the superblock and constructs the
+ * root directory dnode.
+ */
+
+static fsw_status_t fsw_ext2_volume_mount(struct fsw_ext2_volume *vol)
+{
+    fsw_status_t    status;
+    void            *buffer;
+    fsw_u32         blocksize;
+    fsw_u32         groupcnt, groupno, gdesc_per_block, gdesc_bno, gdesc_index;
+    struct ext2_group_desc *gdesc;
+    int             i;
+    struct fsw_string s;
+
+    // allocate memory to keep the superblock around
+    status = fsw_alloc(sizeof(struct ext2_super_block), &vol->sb);
+    if (status)
+        return status;
+
+    // read the superblock into its buffer
+    fsw_set_blocksize(vol, EXT2_SUPERBLOCK_BLOCKSIZE, EXT2_SUPERBLOCK_BLOCKSIZE);
+    status = fsw_block_get(vol, EXT2_SUPERBLOCK_BLOCKNO, 0, &buffer);
+    if (status)
+        return status;
+    fsw_memcpy(vol->sb, buffer, sizeof(struct ext2_super_block));
+    fsw_block_release(vol, EXT2_SUPERBLOCK_BLOCKNO, buffer);
+
+    // check the superblock
+    if (vol->sb->s_magic != EXT2_SUPER_MAGIC)
+        return FSW_UNSUPPORTED;
+    if (vol->sb->s_rev_level != EXT2_GOOD_OLD_REV &&
+        vol->sb->s_rev_level != EXT2_DYNAMIC_REV)
+        return FSW_UNSUPPORTED;
+    if (vol->sb->s_rev_level == EXT2_DYNAMIC_REV &&
+        (vol->sb->s_feature_incompat & ~(EXT2_FEATURE_INCOMPAT_FILETYPE | EXT3_FEATURE_INCOMPAT_RECOVER)))
+        return FSW_UNSUPPORTED;
+
+    /*
+     if (vol->sb->s_rev_level == EXT2_DYNAMIC_REV &&
+         (vol->sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER))
+     Print(L"Ext2 WARNING: This ext3 file system needs recovery, trying to use it anyway.\n");
+     */
+
+    // set real blocksize
+    blocksize = EXT2_BLOCK_SIZE(vol->sb);
+    fsw_set_blocksize(vol, blocksize, blocksize);
+
+    // get other info from superblock
+    vol->ind_bcnt = EXT2_ADDR_PER_BLOCK(vol->sb);
+    vol->dind_bcnt = vol->ind_bcnt * vol->ind_bcnt;
+    vol->inode_size = EXT2_INODE_SIZE(vol->sb);
+
+    for (i = 0; i < 16; i++)
+        if (vol->sb->s_volume_name[i] == 0)
+            break;
+    s.type = FSW_STRING_TYPE_ISO88591;
+    s.size = s.len = i;
+    s.data = vol->sb->s_volume_name;
+    status = fsw_strdup_coerce(&vol->g.label, vol->g.host_string_type, &s);
+    if (status)
+        return status;
+
+    // read the group descriptors to get inode table offsets
+    groupcnt = ((vol->sb->s_inodes_count - 2) / vol->sb->s_inodes_per_group) + 1;
+    gdesc_per_block = (vol->g.phys_blocksize / sizeof(struct ext2_group_desc));
+
+    status = fsw_alloc(sizeof(fsw_u32) * groupcnt, &vol->inotab_bno);
+    if (status)
+        return status;
+    for (groupno = 0; groupno < groupcnt; groupno++) {
+        // get the block group descriptor
+        gdesc_bno = (vol->sb->s_first_data_block + 1) + groupno / gdesc_per_block;
+        gdesc_index = groupno % gdesc_per_block;
+        status = fsw_block_get(vol, gdesc_bno, 1, (void **)&buffer);
+        if (status)
+            return status;
+        gdesc = ((struct ext2_group_desc *)(buffer)) + gdesc_index;
+        vol->inotab_bno[groupno] = gdesc->bg_inode_table;
+        fsw_block_release(vol, gdesc_bno, buffer);
+    }
+
+    // setup the root dnode
+    status = fsw_dnode_create_root(vol, EXT2_ROOT_INO, &vol->g.root);
+    if (status)
+        return status;
+
+    FSW_MSG_DEBUG((FSW_MSGSTR("fsw_ext2_volume_mount: success, blocksize %d\n"), blocksize));
+
+    return FSW_SUCCESS;
+}
+
+/**
+ * Free the volume data structure. Called by the core after an unmount or after
+ * an unsuccessful mount to release the memory used by the file system type specific
+ * part of the volume structure.
+ */
+
+static void fsw_ext2_volume_free(struct fsw_ext2_volume *vol)
+{
+    if (vol->sb)
+        fsw_free(vol->sb);
+    if (vol->inotab_bno)
+        fsw_free(vol->inotab_bno);
+}
+
+/**
+ * Get in-depth information on a volume.
+ */
+
+static fsw_status_t fsw_ext2_volume_stat(struct fsw_ext2_volume *vol, struct fsw_volume_stat *sb)
+{
+    sb->total_bytes = (fsw_u64)vol->sb->s_blocks_count      * vol->g.log_blocksize;
+    sb->free_bytes  = (fsw_u64)vol->sb->s_free_blocks_count * vol->g.log_blocksize;
+    return FSW_SUCCESS;
+}
+
+/**
+ * Get full information on a dnode from disk. This function is called by the core
+ * whenever it needs to access fields in the dnode structure that may not
+ * be filled immediately upon creation of the dnode. In the case of ext2, we
+ * delay fetching of the inode structure until dnode_fill is called. The size and
+ * type fields are invalid until this function has been called.
+ */
+
+static fsw_status_t fsw_ext2_dnode_fill(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno)
+{
+    fsw_status_t    status;
+    fsw_u32         groupno, ino_in_group, ino_bno, ino_index;
+    fsw_u8          *buffer;
+
+    if (dno->raw)
+        return FSW_SUCCESS;
+
+    FSW_MSG_DEBUG((FSW_MSGSTR("fsw_ext2_dnode_fill: inode %d\n"), dno->g.dnode_id));
+
+    // read the inode block
+    groupno = (fsw_u32) (dno->g.dnode_id - 1) / vol->sb->s_inodes_per_group;
+    ino_in_group = (fsw_u32) (dno->g.dnode_id - 1) % vol->sb->s_inodes_per_group;
+    ino_bno = vol->inotab_bno[groupno] +
+        ino_in_group / (vol->g.phys_blocksize / vol->inode_size);
+    ino_index = ino_in_group % (vol->g.phys_blocksize / vol->inode_size);
+    status = fsw_block_get(vol, ino_bno, 2, (void **)&buffer);
+    if (status)
+        return status;
+
+    // keep our inode around
+    status = fsw_memdup((void **)&dno->raw, buffer + ino_index * vol->inode_size, vol->inode_size);
+    fsw_block_release(vol, ino_bno, buffer);
+    if (status)
+        return status;
+
+    // get info from the inode
+    dno->g.size = dno->raw->i_size;
+    // TODO: check docs for 64-bit sized files
+    if (S_ISREG(dno->raw->i_mode))
+        dno->g.type = FSW_DNODE_TYPE_FILE;
+    else if (S_ISDIR(dno->raw->i_mode))
+        dno->g.type = FSW_DNODE_TYPE_DIR;
+    else if (S_ISLNK(dno->raw->i_mode))
+        dno->g.type = FSW_DNODE_TYPE_SYMLINK;
+    else
+        dno->g.type = FSW_DNODE_TYPE_SPECIAL;
+
+    return FSW_SUCCESS;
+}
+
+/**
+ * Free the dnode data structure. Called by the core when deallocating a dnode
+ * structure to release the memory used by the file system type specific part
+ * of the dnode structure.
+ */
+
+static void fsw_ext2_dnode_free(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno)
+{
+    if (dno->raw)
+        fsw_free(dno->raw);
+}
+
+/**
+ * Get in-depth information on a dnode. The core makes sure that fsw_ext2_dnode_fill
+ * has been called on the dnode before this function is called. Note that some
+ * data is not directly stored into the structure, but passed to a host-specific
+ * callback that converts it to the host-specific format.
+ */
+
+static fsw_status_t fsw_ext2_dnode_stat(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno,
+                                        struct fsw_dnode_stat *sb)
+{
+    sb->used_bytes = dno->raw->i_blocks * 512;   // very, very strange...
+    fsw_store_time_posix(sb, FSW_DNODE_STAT_CTIME, dno->raw->i_ctime);
+    fsw_store_time_posix(sb, FSW_DNODE_STAT_ATIME, dno->raw->i_atime);
+    fsw_store_time_posix(sb, FSW_DNODE_STAT_MTIME, dno->raw->i_mtime);
+    fsw_store_attr_posix(sb, dno->raw->i_mode);
+
+    return FSW_SUCCESS;
+}
+
+/**
+ * Retrieve file data mapping information. This function is called by the core when
+ * fsw_shandle_read needs to know where on the disk the required piece of the file's
+ * data can be found. The core makes sure that fsw_ext2_dnode_fill has been called
+ * on the dnode before. Our task here is to get the physical disk block number for
+ * the requested logical block number.
+ *
+ * The ext2 file system does not use extents, but stores a list of block numbers
+ * using the usual direct, indirect, double-indirect, triple-indirect scheme. To
+ * optimize access, this function checks if the following file blocks are mapped
+ * to consecutive disk blocks and returns a combined extent if possible.
+ */
+
+static fsw_status_t fsw_ext2_get_extent(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno,
+                                        struct fsw_extent *extent)
+{
+    fsw_status_t    status;
+    fsw_u32         bno, release_bno, buf_bcnt, file_bcnt;
+    fsw_u32         *buffer;
+    int             path[5], i;
+
+    // Preconditions: The caller has checked that the requested logical block
+    //  is within the file's size. The dnode has complete information, i.e.
+    //  fsw_ext2_dnode_read_info was called successfully on it.
+
+    extent->type = FSW_EXTENT_TYPE_PHYSBLOCK;
+    extent->log_count = 1;
+    bno = extent->log_start;
+
+    // try direct block pointers in the inode
+    if (bno < EXT2_NDIR_BLOCKS) {
+        path[0] = bno;
+        path[1] = -1;
+    } else {
+        bno -= EXT2_NDIR_BLOCKS;
+
+        // try indirect block
+        if (bno < vol->ind_bcnt) {
+            path[0] = EXT2_IND_BLOCK;
+            path[1] = bno;
+            path[2] = -1;
+        } else {
+            bno -= vol->ind_bcnt;
+
+            // try double-indirect block
+            if (bno < vol->dind_bcnt) {
+                path[0] = EXT2_DIND_BLOCK;
+                path[1] = bno / vol->ind_bcnt;
+                path[2] = bno % vol->ind_bcnt;
+                path[3] = -1;
+            } else {
+                bno -= vol->dind_bcnt;
+
+                // use the triple-indirect block
+                path[0] = EXT2_TIND_BLOCK;
+                path[1] = bno / vol->dind_bcnt;
+                path[2] = (bno / vol->ind_bcnt) % vol->ind_bcnt;
+                path[3] = bno % vol->ind_bcnt;
+                path[4] = -1;
+            }
+        }
+    }
+
+    // follow the indirection path
+    buffer = dno->raw->i_block;
+    buf_bcnt = EXT2_NDIR_BLOCKS;
+    release_bno = 0;
+    for (i = 0; ; i++) {
+        bno = buffer[path[i]];
+        if (bno == 0) {
+            extent->type = FSW_EXTENT_TYPE_SPARSE;
+            if (release_bno)
+                fsw_block_release(vol, release_bno, buffer);
+            return FSW_SUCCESS;
+        }
+        if (path[i+1] < 0)
+            break;
+
+        if (release_bno)
+            fsw_block_release(vol, release_bno, buffer);
+        status = fsw_block_get(vol, bno, 1, (void **)&buffer);
+        if (status)
+            return status;
+        release_bno = bno;
+        buf_bcnt = vol->ind_bcnt;
+    }
+    extent->phys_start = bno;
+
+    // check if the following blocks can be aggregated into one extent
+    file_bcnt = (fsw_u32)((dno->g.size + vol->g.log_blocksize - 1) & (vol->g.log_blocksize - 1));
+    while (path[i]           + extent->log_count < buf_bcnt &&    // indirect block has more block pointers
+           extent->log_start + extent->log_count < file_bcnt) {   // file has more blocks
+        if (buffer[path[i] + extent->log_count] == buffer[path[i] + extent->log_count - 1] + 1)
+            extent->log_count++;
+        else
+            break;
+    }
+
+    if (release_bno)
+        fsw_block_release(vol, release_bno, buffer);
+    return FSW_SUCCESS;
+}
+
+/**
+ * Lookup a directory's child dnode by name. This function is called on a directory
+ * to retrieve the directory entry with the given name. A dnode is constructed for
+ * this entry and returned. The core makes sure that fsw_ext2_dnode_fill has been called
+ * and the dnode is actually a directory.
+ */
+
+static fsw_status_t fsw_ext2_dir_lookup(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno,
+                                        struct fsw_string *lookup_name, struct fsw_ext2_dnode **child_dno_out)
+{
+    fsw_status_t    status;
+    struct fsw_shandle shand;
+    fsw_u32         child_ino;
+    struct ext2_dir_entry entry;
+    struct fsw_string entry_name;
+
+    // Preconditions: The caller has checked that dno is a directory node.
+
+    entry_name.type = FSW_STRING_TYPE_ISO88591;
+
+    // setup handle to read the directory
+    status = fsw_shandle_open(dno, &shand);
+    if (status)
+        return status;
+
+    // scan the directory for the file
+    child_ino = 0;
+    while (child_ino == 0) {
+        // read next entry
+        status = fsw_ext2_read_dentry(&shand, &entry);
+        if (status)
+            goto errorexit;
+        if (entry.inode == 0) {
+            // end of directory reached
+            status = FSW_NOT_FOUND;
+            goto errorexit;
+        }
+
+        // compare name
+        entry_name.len = entry_name.size = entry.name_len;
+        entry_name.data = entry.name;
+        if (fsw_streq(lookup_name, &entry_name)) {
+            child_ino = entry.inode;
+            break;
+        }
+    }
+
+    // setup a dnode for the child item
+    status = fsw_dnode_create(dno, child_ino, FSW_DNODE_TYPE_UNKNOWN, &entry_name, child_dno_out);
+
+errorexit:
+    fsw_shandle_close(&shand);
+    return status;
+}
+
+/**
+ * Get the next directory entry when reading a directory. This function is called during
+ * directory iteration to retrieve the next directory entry. A dnode is constructed for
+ * the entry and returned. The core makes sure that fsw_ext2_dnode_fill has been called
+ * and the dnode is actually a directory. The shandle provided by the caller is used to
+ * record the position in the directory between calls.
+ */
+
+static fsw_status_t fsw_ext2_dir_read(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno,
+                                      struct fsw_shandle *shand, struct fsw_ext2_dnode **child_dno_out)
+{
+    fsw_status_t    status;
+    struct ext2_dir_entry entry;
+    struct fsw_string entry_name;
+
+    // Preconditions: The caller has checked that dno is a directory node. The caller
+    //  has opened a storage handle to the directory's storage and keeps it around between
+    //  calls.
+
+    while (1) {
+        // read next entry
+        status = fsw_ext2_read_dentry(shand, &entry);
+        if (status)
+            return status;
+        if (entry.inode == 0)   // end of directory
+            return FSW_NOT_FOUND;
+
+        // skip . and ..
+        if ((entry.name_len == 1 && entry.name[0] == '.') ||
+            (entry.name_len == 2 && entry.name[0] == '.' && entry.name[1] == '.'))
+            continue;
+        break;
+    }
+
+    // setup name
+    entry_name.type = FSW_STRING_TYPE_ISO88591;
+    entry_name.len = entry_name.size = entry.name_len;
+    entry_name.data = entry.name;
+
+    // setup a dnode for the child item
+    status = fsw_dnode_create(dno, entry.inode, FSW_DNODE_TYPE_UNKNOWN, &entry_name, child_dno_out);
+
+    return status;
+}
+
+/**
+ * Read a directory entry from the directory's raw data. This internal function is used
+ * to read a raw ext2 directory entry into memory. The shandle's position pointer is adjusted
+ * to point to the next entry.
+ */
+
+static fsw_status_t fsw_ext2_read_dentry(struct fsw_shandle *shand, struct ext2_dir_entry *entry)
+{
+    fsw_status_t    status;
+    fsw_u32         buffer_size;
+
+    while (1) {
+        // read dir_entry header (fixed length)
+        buffer_size = 8;
+        status = fsw_shandle_read(shand, &buffer_size, entry);
+        if (status)
+            return status;
+
+        if (buffer_size < 8 || entry->rec_len == 0) {
+            // end of directory reached
+            entry->inode = 0;
+            return FSW_SUCCESS;
+        }
+        if (entry->rec_len < 8)
+            return FSW_VOLUME_CORRUPTED;
+        if (entry->inode != 0) {
+            // this entry is used
+            if (entry->rec_len < 8 + entry->name_len)
+                return FSW_VOLUME_CORRUPTED;
+            break;
+        }
+
+        // valid, but unused entry, skip it
+        shand->pos += entry->rec_len - 8;
+    }
+
+    // read file name (variable length)
+    buffer_size = entry->name_len;
+    status = fsw_shandle_read(shand, &buffer_size, entry->name);
+    if (status)
+        return status;
+    if (buffer_size < entry->name_len)
+        return FSW_VOLUME_CORRUPTED;
+
+    // skip any remaining padding
+    shand->pos += entry->rec_len - (8 + entry->name_len);
+
+    return FSW_SUCCESS;
+}
+
+/**
+ * Get the target path of a symbolic link. This function is called when a symbolic
+ * link needs to be resolved. The core makes sure that the fsw_ext2_dnode_fill has been
+ * called on the dnode and that it really is a symlink.
+ *
+ * For ext2, the target path can be stored inline in the inode structure (in the space
+ * otherwise occupied by the block pointers) or in the inode's data. There is no flag
+ * indicating this, only the number of blocks entry (i_blocks) can be used as an
+ * indication. The check used here comes from the Linux kernel.
+ */
+
+static fsw_status_t fsw_ext2_readlink(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno,
+                                      struct fsw_string *link_target)
+{
+    fsw_status_t    status;
+    int             ea_blocks;
+    struct fsw_string s;
+
+    if (dno->g.size > FSW_PATH_MAX)
+        return FSW_VOLUME_CORRUPTED;
+
+    ea_blocks = dno->raw->i_file_acl ? (vol->g.log_blocksize >> 9) : 0;
+
+    if (dno->raw->i_blocks - ea_blocks == 0) {
+        // "fast" symlink, path is stored inside the inode
+        s.type = FSW_STRING_TYPE_ISO88591;
+        s.size = s.len = (int)dno->g.size;
+        s.data = dno->raw->i_block;
+        status = fsw_strdup_coerce(link_target, vol->g.host_string_type, &s);
+    } else {
+        // "slow" symlink, path is stored in normal inode data
+        status = fsw_dnode_readlink_data(dno, link_target);
+    }
+
+    return status;
+}
+
+// EOF
diff --git a/filesystems/fsw_ext2.h b/filesystems/fsw_ext2.h
new file mode 100644 (file)
index 0000000..13b4caa
--- /dev/null
@@ -0,0 +1,65 @@
+/**
+ * \file fsw_ext2.h
+ * ext2 file system driver header.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifndef _FSW_EXT2_H_
+#define _FSW_EXT2_H_
+
+#define VOLSTRUCTNAME fsw_ext2_volume
+#define DNODESTRUCTNAME fsw_ext2_dnode
+#include "fsw_core.h"
+
+#include "fsw_ext2_disk.h"
+
+
+//! Block size to be used when reading the ext2 superblock.
+#define EXT2_SUPERBLOCK_BLOCKSIZE  1024
+//! Block number where the (master copy of the) ext2 superblock resides.
+#define EXT2_SUPERBLOCK_BLOCKNO       1
+
+
+/**
+ * ext2: Volume structure with ext2-specific data.
+ */
+
+struct fsw_ext2_volume {
+    struct fsw_volume g;            //!< Generic volume structure
+    
+    struct ext2_super_block *sb;    //!< Full raw ext2 superblock structure
+    fsw_u32     *inotab_bno;        //!< Block numbers of the inode tables
+    fsw_u32     ind_bcnt;           //!< Number of blocks addressable through an indirect block
+    fsw_u32     dind_bcnt;          //!< Number of blocks addressable through a double-indirect block
+    fsw_u32     inode_size;         //!< Size of inode structure in bytes
+};
+
+/**
+ * ext2: Dnode structure with ext2-specific data.
+ */
+
+struct fsw_ext2_dnode {
+    struct fsw_dnode g;             //!< Generic dnode structure
+    
+    struct ext2_inode *raw;         //!< Full raw inode structure
+};
+
+
+#endif
diff --git a/filesystems/fsw_ext2_disk.h b/filesystems/fsw_ext2_disk.h
new file mode 100644 (file)
index 0000000..759c9bc
--- /dev/null
@@ -0,0 +1,367 @@
+/**
+ * \file fsw_ext2_disk.h
+ * ext2 file system on-disk structures.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ * Portions Copyright (c) 1991-2006 by various Linux kernel contributors
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifndef _FSW_EXT2_DISK_H_
+#define _FSW_EXT2_DISK_H_
+
+// types
+
+typedef fsw_s8  __s8;
+typedef fsw_u8  __u8;
+typedef fsw_s16 __s16;
+typedef fsw_u16 __u16;
+typedef fsw_s32 __s32;
+typedef fsw_u32 __u32;
+typedef fsw_s64 __s64;
+typedef fsw_u64 __u64;
+
+typedef __u16   __le16;
+typedef __u32   __le32;
+typedef __u64   __le64;
+
+//
+// from Linux kernel, include/linux/ext2_fs.h
+//
+
+/*
+ * Special inode numbers
+ */
+#define EXT2_BAD_INO             1      /* Bad blocks inode */
+#define EXT2_ROOT_INO            2      /* Root inode */
+#define EXT2_BOOT_LOADER_INO     5      /* Boot loader inode */
+#define EXT2_UNDEL_DIR_INO       6      /* Undelete directory inode */
+
+/*
+ * The second extended file system magic number
+ */
+#define EXT2_SUPER_MAGIC        0xEF53
+
+/*
+ * Macro-instructions used to manage several block sizes
+ */
+#define EXT2_MIN_BLOCK_SIZE             1024
+#define EXT2_MAX_BLOCK_SIZE             4096
+#define EXT2_MIN_BLOCK_LOG_SIZE           10
+#define EXT2_BLOCK_SIZE(s)              (EXT2_MIN_BLOCK_SIZE << (s)->s_log_block_size)
+#define EXT2_ADDR_PER_BLOCK(s)          (EXT2_BLOCK_SIZE(s) / sizeof (__u32))
+#define EXT2_BLOCK_SIZE_BITS(s)         ((s)->s_log_block_size + 10)
+#define EXT2_INODE_SIZE(s)      (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \
+                                 EXT2_GOOD_OLD_INODE_SIZE : \
+                                 (s)->s_inode_size)
+#define EXT2_FIRST_INO(s)       (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \
+                                 EXT2_GOOD_OLD_FIRST_INO : \
+                                 (s)->s_first_ino)
+
+/*
+ * Structure of a blocks group descriptor
+ */
+struct ext2_group_desc
+{
+    __le32  bg_block_bitmap;        /* Blocks bitmap block */
+    __le32  bg_inode_bitmap;        /* Inodes bitmap block */
+    __le32  bg_inode_table;         /* Inodes table block */
+    __le16  bg_free_blocks_count;   /* Free blocks count */
+    __le16  bg_free_inodes_count;   /* Free inodes count */
+    __le16  bg_used_dirs_count;     /* Directories count */
+    __le16  bg_pad;
+    __le32  bg_reserved[3];
+};
+
+/*
+ * Macro-instructions used to manage group descriptors
+ */
+#define EXT2_BLOCKS_PER_GROUP(s)       ((s)->s_blocks_per_group)
+#define EXT2_DESC_PER_BLOCK(s)         (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc))
+#define EXT2_INODES_PER_GROUP(s)       ((s)->s_inodes_per_group)
+
+/*
+ * Constants relative to the data blocks
+ */
+#define EXT2_NDIR_BLOCKS                12
+#define EXT2_IND_BLOCK                  EXT2_NDIR_BLOCKS
+#define EXT2_DIND_BLOCK                 (EXT2_IND_BLOCK + 1)
+#define EXT2_TIND_BLOCK                 (EXT2_DIND_BLOCK + 1)
+#define EXT2_N_BLOCKS                   (EXT2_TIND_BLOCK + 1)
+
+/*
+ * Inode flags
+ */
+#define EXT2_SECRM_FL                   0x00000001 /* Secure deletion */
+#define EXT2_UNRM_FL                    0x00000002 /* Undelete */
+#define EXT2_COMPR_FL                   0x00000004 /* Compress file */
+#define EXT2_SYNC_FL                    0x00000008 /* Synchronous updates */
+#define EXT2_IMMUTABLE_FL               0x00000010 /* Immutable file */
+#define EXT2_APPEND_FL                  0x00000020 /* writes to file may only append */
+#define EXT2_NODUMP_FL                  0x00000040 /* do not dump file */
+#define EXT2_NOATIME_FL                 0x00000080 /* do not update atime */
+/* Reserved for compression usage... */
+#define EXT2_DIRTY_FL                   0x00000100
+#define EXT2_COMPRBLK_FL                0x00000200 /* One or more compressed clusters */
+#define EXT2_NOCOMP_FL                  0x00000400 /* Don't compress */
+#define EXT2_ECOMPR_FL                  0x00000800 /* Compression error */
+/* End compression flags --- maybe not all used */      
+#define EXT2_BTREE_FL                   0x00001000 /* btree format dir */
+#define EXT2_INDEX_FL                   0x00001000 /* hash-indexed directory */
+#define EXT2_IMAGIC_FL                  0x00002000 /* AFS directory */
+#define EXT2_JOURNAL_DATA_FL            0x00004000 /* Reserved for ext3 */
+#define EXT2_NOTAIL_FL                  0x00008000 /* file tail should not be merged */
+#define EXT2_DIRSYNC_FL                 0x00010000 /* dirsync behaviour (directories only) */
+#define EXT2_TOPDIR_FL                  0x00020000 /* Top of directory hierarchies*/
+#define EXT2_RESERVED_FL                0x80000000 /* reserved for ext2 lib */
+
+#define EXT2_FL_USER_VISIBLE            0x0003DFFF /* User visible flags */
+#define EXT2_FL_USER_MODIFIABLE         0x000380FF /* User modifiable flags */
+
+/*
+ * Structure of an inode on the disk
+ */
+struct ext2_inode {
+    __le16  i_mode;         /* 0: File mode */
+    __le16  i_uid;          /* 2: Low 16 bits of Owner Uid */
+    __le32  i_size;         /* 4: Size in bytes */
+    __le32  i_atime;        /* 8: Access time */
+    __le32  i_ctime;        /* 12: Creation time */
+    __le32  i_mtime;        /* 16: Modification time */
+    __le32  i_dtime;        /* 20: Deletion Time */
+    __le16  i_gid;          /* 24: Low 16 bits of Group Id */
+    __le16  i_links_count;  /* 26: Links count */
+    __le32  i_blocks;       /* 28: Blocks count */
+    __le32  i_flags;        /* 32: File flags */
+    union {
+        struct {
+            __le32  l_i_reserved1;
+        } linux1;
+        struct {
+            __le32  h_i_translator;
+        } hurd1;
+        struct {
+            __le32  m_i_reserved1;
+        } masix1;
+    } osd1;                         /* 36: OS dependent 1 */
+    __le32  i_block[EXT2_N_BLOCKS];/* 40: Pointers to blocks */
+    __le32  i_generation;   /* 100: File version (for NFS) */
+    __le32  i_file_acl;     /* 104: File ACL */
+    __le32  i_dir_acl;      /* 108: Directory ACL */
+    __le32  i_faddr;        /* 112: Fragment address */
+    union {
+        struct {
+            __u8    l_i_frag;       /* 116: Fragment number */
+            __u8    l_i_fsize;      /* 117: Fragment size */
+            __u16   i_pad1;
+            __le16  l_i_uid_high;   /* 120: these 2 fields    */
+            __le16  l_i_gid_high;   /* 122: were reserved2[0] */
+            __u32   l_i_reserved2;
+        } linux2;
+        struct {
+            __u8    h_i_frag;       /* Fragment number */
+            __u8    h_i_fsize;      /* Fragment size */
+            __le16  h_i_mode_high;
+            __le16  h_i_uid_high;
+            __le16  h_i_gid_high;
+            __le32  h_i_author;
+        } hurd2;
+        struct {
+            __u8    m_i_frag;       /* Fragment number */
+            __u8    m_i_fsize;      /* Fragment size */
+            __u16   m_pad1;
+            __u32   m_i_reserved2[2];
+        } masix2;
+    } osd2;                         /* OS dependent 2 */
+};
+
+#define i_size_high     i_dir_acl
+
+/*
+ * Structure of the super block
+ */
+struct ext2_super_block {
+    __le32  s_inodes_count;         /* Inodes count */
+    __le32  s_blocks_count;         /* Blocks count */
+    __le32  s_r_blocks_count;       /* Reserved blocks count */
+    __le32  s_free_blocks_count;    /* Free blocks count */
+    __le32  s_free_inodes_count;    /* Free inodes count */
+    __le32  s_first_data_block;     /* First Data Block */
+    __le32  s_log_block_size;       /* Block size */
+    __le32  s_log_frag_size;        /* Fragment size */
+    __le32  s_blocks_per_group;     /* # Blocks per group */
+    __le32  s_frags_per_group;      /* # Fragments per group */
+    __le32  s_inodes_per_group;     /* # Inodes per group */
+    __le32  s_mtime;                /* Mount time */
+    __le32  s_wtime;                /* Write time */
+    __le16  s_mnt_count;            /* Mount count */
+    __le16  s_max_mnt_count;        /* Maximal mount count */
+    __le16  s_magic;                /* Magic signature */
+    __le16  s_state;                /* File system state */
+    __le16  s_errors;               /* Behaviour when detecting errors */
+    __le16  s_minor_rev_level;      /* minor revision level */
+    __le32  s_lastcheck;            /* time of last check */
+    __le32  s_checkinterval;        /* max. time between checks */
+    __le32  s_creator_os;           /* OS */
+    __le32  s_rev_level;            /* Revision level */
+    __le16  s_def_resuid;           /* Default uid for reserved blocks */
+    __le16  s_def_resgid;           /* Default gid for reserved blocks */
+    /*
+     * These fields are for EXT2_DYNAMIC_REV superblocks only.
+     *
+     * Note: the difference between the compatible feature set and
+     * the incompatible feature set is that if there is a bit set
+     * in the incompatible feature set that the kernel doesn't
+     * know about, it should refuse to mount the filesystem.
+     * 
+     * e2fsck's requirements are more strict; if it doesn't know
+     * about a feature in either the compatible or incompatible
+     * feature set, it must abort and not try to meddle with
+     * things it doesn't understand...
+     */
+    __le32  s_first_ino;            /* First non-reserved inode */
+    __le16  s_inode_size;           /* size of inode structure */
+    __le16  s_block_group_nr;       /* block group # of this superblock */
+    __le32  s_feature_compat;       /* compatible feature set */
+    __le32  s_feature_incompat;     /* incompatible feature set */
+    __le32  s_feature_ro_compat;    /* readonly-compatible feature set */
+    __u8    s_uuid[16];             /* 128-bit uuid for volume */
+    char    s_volume_name[16];      /* volume name */
+    char    s_last_mounted[64];     /* directory where last mounted */
+    __le32  s_algorithm_usage_bitmap; /* For compression */
+    /*
+     * Performance hints.  Directory preallocation should only
+     * happen if the EXT2_COMPAT_PREALLOC flag is on.
+     */
+    __u8    s_prealloc_blocks;      /* Nr of blocks to try to preallocate*/
+    __u8    s_prealloc_dir_blocks;  /* Nr to preallocate for dirs */
+    __u16   s_padding1;
+    /*
+     * Journaling support valid if EXT3_FEATURE_COMPAT_HAS_JOURNAL set.
+     */
+    __u8    s_journal_uuid[16];     /* uuid of journal superblock */
+    __u32   s_journal_inum;         /* inode number of journal file */
+    __u32   s_journal_dev;          /* device number of journal file */
+    __u32   s_last_orphan;          /* start of list of inodes to delete */
+    __u32   s_hash_seed[4];         /* HTREE hash seed */
+    __u8    s_def_hash_version;     /* Default hash version to use */
+    __u8    s_reserved_char_pad;
+    __u16   s_reserved_word_pad;
+    __le32  s_default_mount_opts;
+    __le32  s_first_meta_bg;        /* First metablock block group */
+    __u32   s_reserved[190];        /* Padding to the end of the block */
+};
+
+/*
+ * Revision levels
+ */
+#define EXT2_GOOD_OLD_REV       0       /* The good old (original) format */
+#define EXT2_DYNAMIC_REV        1       /* V2 format w/ dynamic inode sizes */
+
+#define EXT2_CURRENT_REV        EXT2_GOOD_OLD_REV
+#define EXT2_MAX_SUPP_REV       EXT2_DYNAMIC_REV
+
+#define EXT2_GOOD_OLD_INODE_SIZE 128
+
+/*
+ * Feature set definitions
+ */
+
+#define EXT2_HAS_COMPAT_FEATURE(sb,mask)                        \
+        ( EXT2_SB(sb)->s_es->s_feature_compat & cpu_to_le32(mask) )
+#define EXT2_HAS_RO_COMPAT_FEATURE(sb,mask)                     \
+        ( EXT2_SB(sb)->s_es->s_feature_ro_compat & cpu_to_le32(mask) )
+#define EXT2_HAS_INCOMPAT_FEATURE(sb,mask)                      \
+        ( EXT2_SB(sb)->s_es->s_feature_incompat & cpu_to_le32(mask) )
+#define EXT2_SET_COMPAT_FEATURE(sb,mask)                        \
+        EXT2_SB(sb)->s_es->s_feature_compat |= cpu_to_le32(mask)
+#define EXT2_SET_RO_COMPAT_FEATURE(sb,mask)                     \
+        EXT2_SB(sb)->s_es->s_feature_ro_compat |= cpu_to_le32(mask)
+#define EXT2_SET_INCOMPAT_FEATURE(sb,mask)                      \
+        EXT2_SB(sb)->s_es->s_feature_incompat |= cpu_to_le32(mask)
+#define EXT2_CLEAR_COMPAT_FEATURE(sb,mask)                      \
+        EXT2_SB(sb)->s_es->s_feature_compat &= ~cpu_to_le32(mask)
+#define EXT2_CLEAR_RO_COMPAT_FEATURE(sb,mask)                   \
+        EXT2_SB(sb)->s_es->s_feature_ro_compat &= ~cpu_to_le32(mask)
+#define EXT2_CLEAR_INCOMPAT_FEATURE(sb,mask)                    \
+        EXT2_SB(sb)->s_es->s_feature_incompat &= ~cpu_to_le32(mask)
+
+#define EXT2_FEATURE_COMPAT_DIR_PREALLOC        0x0001
+#define EXT2_FEATURE_COMPAT_IMAGIC_INODES       0x0002
+#define EXT3_FEATURE_COMPAT_HAS_JOURNAL         0x0004
+#define EXT2_FEATURE_COMPAT_EXT_ATTR            0x0008
+#define EXT2_FEATURE_COMPAT_RESIZE_INO          0x0010
+#define EXT2_FEATURE_COMPAT_DIR_INDEX           0x0020
+#define EXT2_FEATURE_COMPAT_ANY                 0xffffffff
+
+#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER     0x0001
+#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE       0x0002
+#define EXT2_FEATURE_RO_COMPAT_BTREE_DIR        0x0004
+#define EXT2_FEATURE_RO_COMPAT_ANY              0xffffffff
+
+#define EXT2_FEATURE_INCOMPAT_COMPRESSION       0x0001
+#define EXT2_FEATURE_INCOMPAT_FILETYPE          0x0002
+#define EXT3_FEATURE_INCOMPAT_RECOVER           0x0004
+#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV       0x0008
+#define EXT2_FEATURE_INCOMPAT_META_BG           0x0010
+#define EXT2_FEATURE_INCOMPAT_ANY               0xffffffff
+
+/*
+#define EXT2_FEATURE_COMPAT_SUPP        EXT2_FEATURE_COMPAT_EXT_ATTR
+#define EXT2_FEATURE_INCOMPAT_SUPP      (EXT2_FEATURE_INCOMPAT_FILETYPE| \
+                                         EXT2_FEATURE_INCOMPAT_META_BG)
+#define EXT2_FEATURE_RO_COMPAT_SUPP     (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
+                                         EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
+                                         EXT2_FEATURE_RO_COMPAT_BTREE_DIR)
+#define EXT2_FEATURE_RO_COMPAT_UNSUPPORTED      ~EXT2_FEATURE_RO_COMPAT_SUPP
+#define EXT2_FEATURE_INCOMPAT_UNSUPPORTED       ~EXT2_FEATURE_INCOMPAT_SUPP
+*/
+
+/*
+ * Structure of a directory entry
+ */
+#define EXT2_NAME_LEN 255
+
+struct ext2_dir_entry {
+    __le32  inode;                  /* Inode number */
+    __le16  rec_len;                /* Directory entry length */
+    __u8    name_len;               /* Name length */
+    __u8    file_type;
+    char    name[EXT2_NAME_LEN];    /* File name */
+};
+// NOTE: The original Linux kernel header defines ext2_dir_entry with the original
+//  layout and ext2_dir_entry_2 with the revised layout. We simply use the revised one.
+
+/*
+ * Ext2 directory file types.  Only the low 3 bits are used.  The
+ * other bits are reserved for now.
+ */
+enum {
+    EXT2_FT_UNKNOWN,
+    EXT2_FT_REG_FILE,
+    EXT2_FT_DIR,
+    EXT2_FT_CHRDEV,
+    EXT2_FT_BLKDEV,
+    EXT2_FT_FIFO,
+    EXT2_FT_SOCK,
+    EXT2_FT_SYMLINK,
+    EXT2_FT_MAX
+};
+
+
+#endif
diff --git a/filesystems/fsw_ext4.c b/filesystems/fsw_ext4.c
new file mode 100644 (file)
index 0000000..2cf009b
--- /dev/null
@@ -0,0 +1,729 @@
+/**
+ * \file fsw_ext4.c
+ * ext4 file system driver code.
+ */
+
+/*-
+ * Copyright (c) 2012 Stefan Agner
+ * Portions Copyright (c) 2006 Christoph Pfisterer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include "fsw_ext4.h"
+
+
+// functions
+
+static fsw_status_t fsw_ext4_volume_mount(struct fsw_ext4_volume *vol);
+static void         fsw_ext4_volume_free(struct fsw_ext4_volume *vol);
+static fsw_status_t fsw_ext4_volume_stat(struct fsw_ext4_volume *vol, struct fsw_volume_stat *sb);
+
+static fsw_status_t fsw_ext4_dnode_fill(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno);
+static void         fsw_ext4_dnode_free(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno);
+static fsw_status_t fsw_ext4_dnode_stat(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno,
+                                        struct fsw_dnode_stat *sb);
+static fsw_status_t fsw_ext4_get_extent(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno,
+                                        struct fsw_extent *extent);
+static fsw_status_t fsw_ext4_get_by_blkaddr(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno,
+                                        struct fsw_extent *extent);
+static fsw_status_t fsw_ext4_get_by_extent(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno,
+                                        struct fsw_extent *extent);
+
+static fsw_status_t fsw_ext4_dir_lookup(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno,
+                                        struct fsw_string *lookup_name, struct fsw_ext4_dnode **child_dno);
+static fsw_status_t fsw_ext4_dir_read(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno,
+                                      struct fsw_shandle *shand, struct fsw_ext4_dnode **child_dno);
+static fsw_status_t fsw_ext4_read_dentry(struct fsw_shandle *shand, struct ext4_dir_entry *entry);
+
+static fsw_status_t fsw_ext4_readlink(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno,
+                                      struct fsw_string *link);
+
+//
+// Dispatch Table
+//
+
+struct fsw_fstype_table   FSW_FSTYPE_TABLE_NAME(ext4) = {
+    { FSW_STRING_TYPE_ISO88591, 4, 4, "ext4" },
+    sizeof(struct fsw_ext4_volume),
+    sizeof(struct fsw_ext4_dnode),
+
+    fsw_ext4_volume_mount,
+    fsw_ext4_volume_free,
+    fsw_ext4_volume_stat,
+    fsw_ext4_dnode_fill,
+    fsw_ext4_dnode_free,
+    fsw_ext4_dnode_stat,
+    fsw_ext4_get_extent,
+    fsw_ext4_dir_lookup,
+    fsw_ext4_dir_read,
+    fsw_ext4_readlink,
+};
+
+
+static __inline int test_root(fsw_u32 a, int b)
+{
+        fsw_u32 num = b;
+
+        while (a > num)
+                num *= b;
+        return num == a;
+}
+
+static int fsw_ext4_group_sparse(fsw_u32 group)
+{
+        if (group <= 1)
+                return 1;
+        if (!(group & 1))
+                return 0;
+        return (test_root(group, 7) || test_root(group, 5) ||
+                test_root(group, 3));
+}
+
+/* calculate the first block number of the group */
+static __inline fsw_u32
+fsw_ext4_group_first_block_no(struct ext4_super_block *sb, fsw_u32 group_no)
+{
+        return group_no * (fsw_u32)EXT4_BLOCKS_PER_GROUP(sb) +
+                sb->s_first_data_block;
+}
+
+/**
+ * Mount an ext4 volume. Reads the superblock and constructs the
+ * root directory dnode.
+ */
+
+static fsw_status_t fsw_ext4_volume_mount(struct fsw_ext4_volume *vol)
+{
+    fsw_status_t    status;
+    void            *buffer;
+    fsw_u32         blocksize;
+    fsw_u32         groupcnt, groupno, gdesc_per_block, gdesc_bno, gdesc_index, metabg_of_gdesc;
+    struct ext4_group_desc *gdesc;
+    int             i;
+    struct fsw_string s;
+
+    // allocate memory to keep the superblock around
+    status = fsw_alloc(sizeof(struct ext4_super_block), &vol->sb);
+    if (status)
+        return status;
+
+    // read the superblock into its buffer
+    fsw_set_blocksize(vol, EXT4_SUPERBLOCK_BLOCKSIZE, EXT4_SUPERBLOCK_BLOCKSIZE);
+    status = fsw_block_get(vol, EXT4_SUPERBLOCK_BLOCKNO, 0, &buffer);
+    if (status)
+        return status;
+    fsw_memcpy(vol->sb, buffer, sizeof(struct ext4_super_block));
+    fsw_block_release(vol, EXT4_SUPERBLOCK_BLOCKNO, buffer);
+
+    // check the superblock
+    if (vol->sb->s_magic != EXT4_SUPER_MAGIC)
+        return FSW_UNSUPPORTED;
+    if (vol->sb->s_rev_level != EXT4_GOOD_OLD_REV &&
+        vol->sb->s_rev_level != EXT4_DYNAMIC_REV)
+        return FSW_UNSUPPORTED;
+
+    FSW_MSG_DEBUG((FSW_MSGSTR("fsw_ext4_volume_mount: Incompat flag %x\n"), vol->sb->s_feature_incompat));
+
+    if (vol->sb->s_rev_level == EXT4_DYNAMIC_REV &&
+        (vol->sb->s_feature_incompat & ~(EXT4_FEATURE_INCOMPAT_FILETYPE | EXT4_FEATURE_INCOMPAT_RECOVER |
+                                         EXT4_FEATURE_INCOMPAT_EXTENTS | EXT4_FEATURE_INCOMPAT_FLEX_BG |
+                                         EXT4_FEATURE_INCOMPAT_META_BG)))
+        return FSW_UNSUPPORTED;
+
+    if (vol->sb->s_rev_level == EXT4_DYNAMIC_REV &&
+        (vol->sb->s_feature_incompat & EXT4_FEATURE_INCOMPAT_RECOVER))
+    {
+        FSW_MSG_DEBUG((FSW_MSGSTR("fsw_ext4_volume_mount: This ext3 file system needs recovery\n")));
+        // Print(L"Ext4 WARNING: This file system needs recovery, trying to use it anyway.\n");
+    }
+
+    blocksize = EXT4_BLOCK_SIZE(vol->sb);
+    if (blocksize < EXT4_MIN_BLOCK_SIZE || blocksize > EXT4_MAX_BLOCK_SIZE)
+        return FSW_UNSUPPORTED;
+
+    // set real blocksize
+    fsw_set_blocksize(vol, blocksize, blocksize);
+
+    // get other info from superblock
+    vol->ind_bcnt = EXT4_ADDR_PER_BLOCK(vol->sb);
+    vol->dind_bcnt = vol->ind_bcnt * vol->ind_bcnt;
+    vol->inode_size = vol->sb->s_inode_size;//EXT4_INODE_SIZE(vol->sb);
+
+    for (i = 0; i < 16; i++)
+        if (vol->sb->s_volume_name[i] == 0)
+            break;
+    s.type = FSW_STRING_TYPE_ISO88591;
+    s.size = s.len = i;
+    s.data = vol->sb->s_volume_name;
+    status = fsw_strdup_coerce(&vol->g.label, vol->g.host_string_type, &s);
+    if (status)
+        return status;
+
+    // size of group descriptor depends on feature....
+    if (!(vol->sb->s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT)) {
+        // Default minimal group descriptor size... (this might not be set in old ext2 filesystems, therefor set it!)
+        vol->sb->s_desc_size = EXT4_MIN_DESC_SIZE;
+    }
+
+    // Calculate group descriptor count the way the kernel does it...
+    groupcnt = (vol->sb->s_blocks_count_lo - vol->sb->s_first_data_block + 
+                vol->sb->s_blocks_per_group - 1) / vol->sb->s_blocks_per_group;
+
+    // Descriptors in one block... s_desc_size needs to be set! (Usually 128 since normal block 
+    // descriptors are 32 byte and block size is 4096)
+    gdesc_per_block = EXT4_DESC_PER_BLOCK(vol->sb);
+    
+    // Read the group descriptors to get inode table offsets
+    status = fsw_alloc(sizeof(fsw_u32) * groupcnt, &vol->inotab_bno);
+    if (status)
+        return status;
+
+    // Loop through all block group descriptors in order to get inode table locations
+    for (groupno = 0; groupno < groupcnt; groupno++) {
+
+        // Calculate the block number which contains the block group descriptor we look for
+        if(vol->sb->s_feature_incompat & EXT4_FEATURE_INCOMPAT_META_BG && groupno >= vol->sb->s_first_meta_bg)
+        {
+            // If option meta_bg is set, the block group descriptor is in meta block group...
+            metabg_of_gdesc = (fsw_u32)(groupno / gdesc_per_block) * gdesc_per_block;
+            gdesc_bno = fsw_ext4_group_first_block_no(vol->sb, metabg_of_gdesc);
+            // We need to know if the block group in questition has a super block, if yes, the 
+            // block group descriptors are in the next block number
+            if(!(vol->sb->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER) || fsw_ext4_group_sparse(metabg_of_gdesc))
+                gdesc_bno += 1;
+        }
+        else
+        {
+            // All group descriptors follow the super block (+1)
+            gdesc_bno = (vol->sb->s_first_data_block + 1) + groupno / gdesc_per_block;
+        }
+        gdesc_index = groupno % gdesc_per_block;
+
+        // Get block if necessary...
+        status = fsw_block_get(vol, gdesc_bno, 1, (void **)&buffer);
+        if (status)
+            return status;
+
+        // Get group descriptor table and block number of inode table...
+        gdesc = (struct ext4_group_desc *)((char *)buffer + gdesc_index * vol->sb->s_desc_size);
+        vol->inotab_bno[groupno] = gdesc->bg_inode_table_lo;
+
+        fsw_block_release(vol, gdesc_bno, buffer);
+    }
+
+    // setup the root dnode
+    status = fsw_dnode_create_root(vol, EXT4_ROOT_INO, &vol->g.root);
+    if (status)
+        return status;
+
+    FSW_MSG_DEBUG((FSW_MSGSTR("fsw_ext4_volume_mount: success, blocksize %d\n"), blocksize));
+
+    return FSW_SUCCESS;
+}
+
+/**
+ * Free the volume data structure. Called by the core after an unmount or after
+ * an unsuccessful mount to release the memory used by the file system type specific
+ * part of the volume structure.
+ */
+
+static void fsw_ext4_volume_free(struct fsw_ext4_volume *vol)
+{
+    if (vol->sb)
+        fsw_free(vol->sb);
+    if (vol->inotab_bno)
+        fsw_free(vol->inotab_bno);
+}
+
+/**
+ * Get in-depth information on a volume.
+ */
+
+static fsw_status_t fsw_ext4_volume_stat(struct fsw_ext4_volume *vol, struct fsw_volume_stat *sb)
+{
+    sb->total_bytes = (fsw_u64)vol->sb->s_blocks_count_lo * vol->g.log_blocksize;
+    sb->free_bytes  = (fsw_u64)vol->sb->s_free_blocks_count_lo * vol->g.log_blocksize;
+    return FSW_SUCCESS;
+}
+
+/**
+ * Get full information on a dnode from disk. This function is called by the core
+ * whenever it needs to access fields in the dnode structure that may not
+ * be filled immediately upon creation of the dnode. In the case of ext4, we
+ * delay fetching of the inode structure until dnode_fill is called. The size and
+ * type fields are invalid until this function has been called.
+ */
+
+static fsw_status_t fsw_ext4_dnode_fill(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno)
+{
+    fsw_status_t    status;
+    fsw_u32         groupno, ino_in_group, ino_bno, ino_index;
+    fsw_u8          *buffer;
+
+    if (dno->raw)
+        return FSW_SUCCESS;
+
+
+    // read the inode block
+    groupno = (fsw_u32) (dno->g.dnode_id - 1) / vol->sb->s_inodes_per_group;
+    ino_in_group = (fsw_u32) (dno->g.dnode_id - 1) % vol->sb->s_inodes_per_group;
+    ino_bno = vol->inotab_bno[groupno] +
+        ino_in_group / (vol->g.phys_blocksize / vol->inode_size);
+    ino_index = ino_in_group % (vol->g.phys_blocksize / vol->inode_size);
+    status = fsw_block_get(vol, ino_bno, 2, (void **)&buffer);
+
+    if (status)
+        return status;
+
+    // keep our inode around
+    status = fsw_memdup((void **)&dno->raw, buffer + ino_index * vol->inode_size, vol->inode_size);
+    fsw_block_release(vol, ino_bno, buffer);
+    if (status)
+        return status;
+
+    // get info from the inode
+    dno->g.size = dno->raw->i_size_lo; // TODO: check docs for 64-bit sized files
+
+    if (S_ISREG(dno->raw->i_mode))
+        dno->g.type = FSW_DNODE_TYPE_FILE;
+    else if (S_ISDIR(dno->raw->i_mode))
+        dno->g.type = FSW_DNODE_TYPE_DIR;
+    else if (S_ISLNK(dno->raw->i_mode))
+        dno->g.type = FSW_DNODE_TYPE_SYMLINK;
+    else
+        dno->g.type = FSW_DNODE_TYPE_SPECIAL;
+
+    FSW_MSG_DEBUG((FSW_MSGSTR("fsw_ext4_dnode_fill: inode flags %x\n"), dno->raw->i_flags));
+    FSW_MSG_DEBUG((FSW_MSGSTR("fsw_ext4_dnode_fill: i_mode %x\n"), dno->raw->i_mode));
+    return FSW_SUCCESS;
+}
+
+/**
+ * Free the dnode data structure. Called by the core when deallocating a dnode
+ * structure to release the memory used by the file system type specific part
+ * of the dnode structure.
+ */
+
+static void fsw_ext4_dnode_free(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno)
+{
+    if (dno->raw)
+        fsw_free(dno->raw);
+}
+
+/**
+ * Get in-depth information on a dnode. The core makes sure that fsw_ext4_dnode_fill
+ * has been called on the dnode before this function is called. Note that some
+ * data is not directly stored into the structure, but passed to a host-specific
+ * callback that converts it to the host-specific format.
+ */
+
+static fsw_status_t fsw_ext4_dnode_stat(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno,
+                                        struct fsw_dnode_stat *sb)
+{
+    sb->used_bytes = dno->raw->i_blocks_lo * EXT4_BLOCK_SIZE(vol->sb);   // very, very strange...
+    fsw_store_time_posix(sb, FSW_DNODE_STAT_CTIME, dno->raw->i_ctime);
+    fsw_store_time_posix(sb, FSW_DNODE_STAT_ATIME, dno->raw->i_atime);
+    fsw_store_time_posix(sb, FSW_DNODE_STAT_MTIME, dno->raw->i_mtime);
+    fsw_store_attr_posix(sb, dno->raw->i_mode);
+
+    return FSW_SUCCESS;
+}
+
+/**
+ * Retrieve file data mapping information. This function is called by the core when
+ * fsw_shandle_read needs to know where on the disk the required piece of the file's
+ * data can be found. The core makes sure that fsw_ext4_dnode_fill has been called
+ * on the dnode before. Our task here is to get the physical disk block number for
+ * the requested logical block number.
+ *
+ * The ext4 file system usually uses extents do to store those disk block numbers.
+ * However, since ext4 is backward compatible, depending on inode flags the old direct
+ * and indirect addressing scheme can still be in place...
+ */
+
+static fsw_status_t fsw_ext4_get_extent(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno,
+                                        struct fsw_extent *extent)
+{
+    // Preconditions: The caller has checked that the requested logical block
+    //  is within the file's size. The dnode has complete information, i.e.
+    //  fsw_ext4_dnode_read_info was called successfully on it.
+    FSW_MSG_DEBUG((FSW_MSGSTR("fsw_ext4_get_extent: inode %d, block %d\n"), dno->g.dnode_id, extent->log_start));
+    extent->type = FSW_EXTENT_TYPE_PHYSBLOCK;
+    extent->log_count = 1;
+
+    if(dno->raw->i_flags & 1 << EXT4_INODE_EXTENTS)
+    {
+       FSW_MSG_DEBUG((FSW_MSGSTR("fsw_ext4_get_extent: inode %d uses extents\n"), dno->g.dnode_id));
+       return fsw_ext4_get_by_extent(vol, dno, extent);
+    }
+    else
+    {
+       FSW_MSG_DEBUG((FSW_MSGSTR("fsw_ext4_get_extent: inode %d uses direct/indirect block addressing\n"),
+           dno->g.dnode_id));
+       return fsw_ext4_get_by_blkaddr(vol, dno, extent);
+    }
+}
+
+/**
+ * New ext4 extents...
+ */
+static fsw_status_t fsw_ext4_get_by_extent(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno,
+                                        struct fsw_extent *extent)
+{
+    fsw_status_t  status;
+    fsw_u32       bno, buf_offset;
+    int           ext_cnt;
+    void          *buffer;
+
+    struct ext4_extent_header  *ext4_extent_header;
+    struct ext4_extent_idx     *ext4_extent_idx;
+    struct ext4_extent         *ext4_extent;
+
+    // Logical block requested by core...
+    bno = extent->log_start;
+
+    // First buffer is the i_block field from inode...
+    buffer = (void *)dno->raw->i_block;
+    buf_offset = 0;
+    while(1) {
+        ext4_extent_header = (struct ext4_extent_header *)((char *)buffer + buf_offset);
+        buf_offset += sizeof(struct ext4_extent_header);
+        FSW_MSG_DEBUG((FSW_MSGSTR("fsw_ext4_get_by_extent: extent header with %d entries\n"), 
+                      ext4_extent_header->eh_entries));
+        if(ext4_extent_header->eh_magic != EXT4_EXT_MAGIC)
+            return FSW_VOLUME_CORRUPTED;
+
+        for(ext_cnt = 0;ext_cnt < ext4_extent_header->eh_entries;ext_cnt++)
+        {
+            if(ext4_extent_header->eh_depth == 0)
+            {
+                // Leaf node, the header follows actual extents
+                ext4_extent = (struct ext4_extent *)((char *)buffer + buf_offset);
+                buf_offset += sizeof(struct ext4_extent);
+                FSW_MSG_DEBUG((FSW_MSGSTR("fsw_ext4_get_by_extent: extent node cover %d...\n"), ext4_extent->ee_block));
+
+                // Is the requested block in this extent?
+                if(bno >= ext4_extent->ee_block && bno < ext4_extent->ee_block + ext4_extent->ee_len)
+                {
+                    extent->phys_start = ext4_extent->ee_start_lo + (bno - ext4_extent->ee_block);
+                    extent->log_count = ext4_extent->ee_len - (bno - ext4_extent->ee_block);
+                    return FSW_SUCCESS;
+                }
+            }
+            else
+            {
+                FSW_MSG_DEBUG((FSW_MSGSTR("fsw_ext4_get_by_extent: index extents, depth %d\n"), 
+                          ext4_extent_header->eh_depth));
+                ext4_extent_idx = (struct ext4_extent_idx *)((char *)buffer + buf_offset);
+                buf_offset += sizeof(struct ext4_extent_idx);
+
+                FSW_MSG_DEBUG((FSW_MSGSTR("fsw_ext4_get_by_extent: index node covers block %d...\n"),
+                          ext4_extent_idx->ei_block));
+                if(bno >= ext4_extent_idx->ei_block)
+                {
+                    // Follow extent tree...
+                    status = fsw_block_get(vol, ext4_extent_idx->ei_leaf_lo, 1, (void **)&buffer);
+                    if (status)
+                        return status;
+                    buf_offset = 0;
+                    break;
+                }
+            }
+        }
+    }
+
+    return FSW_NOT_FOUND;
+}
+
+/**
+ * The ext2/ext3 file system does not use extents, but stores a list of block numbers
+ * using the usual direct, indirect, double-indirect, triple-indirect scheme. To
+ * optimize access, this function checks if the following file blocks are mapped
+ * to consecutive disk blocks and returns a combined extent if possible.
+ */
+static fsw_status_t fsw_ext4_get_by_blkaddr(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno,
+                                        struct fsw_extent *extent)
+{
+    fsw_status_t    status;
+    fsw_u32         bno, release_bno, buf_bcnt, file_bcnt;
+    int             path[5], i;
+    fsw_u32         *buffer;
+    bno = extent->log_start;
+
+    // try direct block pointers in the inode
+    if (bno < EXT4_NDIR_BLOCKS) {
+        path[0] = bno;
+        path[1] = -1;
+    } else {
+        bno -= EXT4_NDIR_BLOCKS;
+
+        // try indirect block
+        if (bno < vol->ind_bcnt) {
+            path[0] = EXT4_IND_BLOCK;
+            path[1] = bno;
+            path[2] = -1;
+        } else {
+            bno -= vol->ind_bcnt;
+
+            // try double-indirect block
+            if (bno < vol->dind_bcnt) {
+                path[0] = EXT4_DIND_BLOCK;
+                path[1] = bno / vol->ind_bcnt;
+                path[2] = bno % vol->ind_bcnt;
+                path[3] = -1;
+            } else {
+                bno -= vol->dind_bcnt;
+
+                // use the triple-indirect block
+                path[0] = EXT4_TIND_BLOCK;
+                path[1] = bno / vol->dind_bcnt;
+                path[2] = (bno / vol->ind_bcnt) % vol->ind_bcnt;
+                path[3] = bno % vol->ind_bcnt;
+                path[4] = -1;
+            }
+        }
+    }
+    
+    // follow the indirection path
+    buffer = dno->raw->i_block;
+    buf_bcnt = EXT4_NDIR_BLOCKS;
+    release_bno = 0;
+    for (i = 0; ; i++) {
+        bno = buffer[path[i]];
+        if (bno == 0) {
+            extent->type = FSW_EXTENT_TYPE_SPARSE;
+            if (release_bno)
+                fsw_block_release(vol, release_bno, buffer);
+            return FSW_SUCCESS;
+        }
+        if (path[i+1] < 0)
+            break;
+
+        if (release_bno)
+            fsw_block_release(vol, release_bno, buffer);
+        status = fsw_block_get(vol, bno, 1, (void **)&buffer);
+        if (status)
+            return status;
+        release_bno = bno;
+        buf_bcnt = vol->ind_bcnt;
+    }
+    extent->phys_start = bno;
+
+    // check if the following blocks can be aggregated into one extent
+    file_bcnt = (fsw_u32)((dno->g.size + vol->g.log_blocksize - 1) & (vol->g.log_blocksize - 1));
+    while (path[i]           + extent->log_count < buf_bcnt &&    // indirect block has more block pointers
+           extent->log_start + extent->log_count < file_bcnt) {   // file has more blocks
+        if (buffer[path[i] + extent->log_count] == buffer[path[i] + extent->log_count - 1] + 1)
+            extent->log_count++;
+        else
+            break;
+    }
+
+    if (release_bno)
+        fsw_block_release(vol, release_bno, buffer);
+    return FSW_SUCCESS;
+}
+
+/**
+ * Lookup a directory's child dnode by name. This function is called on a directory
+ * to retrieve the directory entry with the given name. A dnode is constructed for
+ * this entry and returned. The core makes sure that fsw_ext4_dnode_fill has been called
+ * and the dnode is actually a directory.
+ */
+
+static fsw_status_t fsw_ext4_dir_lookup(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno,
+                                        struct fsw_string *lookup_name, struct fsw_ext4_dnode **child_dno_out)
+{
+    fsw_status_t    status;
+    struct fsw_shandle shand;
+    fsw_u32         child_ino;
+    struct ext4_dir_entry entry;
+    struct fsw_string entry_name;
+
+    // Preconditions: The caller has checked that dno is a directory node.
+
+    entry_name.type = FSW_STRING_TYPE_ISO88591;
+
+    // setup handle to read the directory
+    status = fsw_shandle_open(dno, &shand);
+    if (status)
+        return status;
+
+    // scan the directory for the file
+    child_ino = 0;
+    while (child_ino == 0) {
+        // read next entry
+        status = fsw_ext4_read_dentry(&shand, &entry);
+        if (status)
+            goto errorexit;
+        if (entry.inode == 0) {
+            // end of directory reached
+            status = FSW_NOT_FOUND;
+            goto errorexit;
+        }
+
+        // compare name
+        entry_name.len = entry_name.size = entry.name_len;
+        entry_name.data = entry.name;
+        if (fsw_streq(lookup_name, &entry_name)) {
+            child_ino = entry.inode;
+            break;
+        }
+    }
+
+    // setup a dnode for the child item
+    status = fsw_dnode_create(dno, child_ino, FSW_DNODE_TYPE_UNKNOWN, &entry_name, child_dno_out);
+
+errorexit:
+    fsw_shandle_close(&shand);
+    return status;
+}
+
+/**
+ * Get the next directory entry when reading a directory. This function is called during
+ * directory iteration to retrieve the next directory entry. A dnode is constructed for
+ * the entry and returned. The core makes sure that fsw_ext4_dnode_fill has been called
+ * and the dnode is actually a directory. The shandle provided by the caller is used to
+ * record the position in the directory between calls.
+ */
+
+static fsw_status_t fsw_ext4_dir_read(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno,
+                                      struct fsw_shandle *shand, struct fsw_ext4_dnode **child_dno_out)
+{
+    fsw_status_t    status;
+    struct ext4_dir_entry entry;
+    struct fsw_string entry_name;
+
+    // Preconditions: The caller has checked that dno is a directory node. The caller
+    //  has opened a storage handle to the directory's storage and keeps it around between
+    //  calls.
+    FSW_MSG_DEBUG((FSW_MSGSTR("fsw_ext4_dir_read: started reading dir\n")));
+
+    while (1) {
+        // read next entry
+        status = fsw_ext4_read_dentry(shand, &entry);
+        if (status)
+            return status;
+        if (entry.inode == 0)   // end of directory
+            return FSW_NOT_FOUND;
+
+        // skip . and ..
+        if ((entry.name_len == 1 && entry.name[0] == '.') ||
+            (entry.name_len == 2 && entry.name[0] == '.' && entry.name[1] == '.'))
+            continue;
+        break;
+    }
+
+    // setup name
+    entry_name.type = FSW_STRING_TYPE_ISO88591;
+    entry_name.len = entry_name.size = entry.name_len;
+    entry_name.data = entry.name;
+
+    // setup a dnode for the child item
+    status = fsw_dnode_create(dno, entry.inode, FSW_DNODE_TYPE_UNKNOWN, &entry_name, child_dno_out);
+
+    return status;
+}
+
+/**
+ * Read a directory entry from the directory's raw data. This internal function is used
+ * to read a raw ext2 directory entry into memory. The shandle's position pointer is adjusted
+ * to point to the next entry.
+ */
+
+static fsw_status_t fsw_ext4_read_dentry(struct fsw_shandle *shand, struct ext4_dir_entry *entry)
+{
+    fsw_status_t    status;
+    fsw_u32         buffer_size;
+
+    while (1) {
+        // read dir_entry header (fixed length)
+        buffer_size = 8;
+        status = fsw_shandle_read(shand, &buffer_size, entry);
+        if (status)
+            return status;
+
+        if (buffer_size < 8 || entry->rec_len == 0) {
+            // end of directory reached
+            entry->inode = 0;
+            return FSW_SUCCESS;
+        }
+        if (entry->rec_len < 8)
+            return FSW_VOLUME_CORRUPTED;
+        if (entry->inode != 0) {
+            // this entry is used
+            if (entry->rec_len < 8 + entry->name_len)
+                return FSW_VOLUME_CORRUPTED;
+            break;
+        }
+
+        // valid, but unused entry, skip it
+        shand->pos += entry->rec_len - 8;
+    }
+
+    // read file name (variable length)
+    buffer_size = entry->name_len;
+    status = fsw_shandle_read(shand, &buffer_size, entry->name);
+    if (status)
+        return status;
+    if (buffer_size < entry->name_len)
+        return FSW_VOLUME_CORRUPTED;
+
+    // skip any remaining padding
+    shand->pos += entry->rec_len - (8 + entry->name_len);
+
+    return FSW_SUCCESS;
+}
+
+/**
+ * Get the target path of a symbolic link. This function is called when a symbolic
+ * link needs to be resolved. The core makes sure that the fsw_ext4_dnode_fill has been
+ * called on the dnode and that it really is a symlink.
+ *
+ * For ext4, the target path can be stored inline in the inode structure (in the space
+ * otherwise occupied by the block pointers) or in the inode's data. There is no flag
+ * indicating this, only the number of blocks entry (i_blocks) can be used as an
+ * indication. The check used here comes from the Linux kernel.
+ */
+
+static fsw_status_t fsw_ext4_readlink(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno,
+                                      struct fsw_string *link_target)
+{
+    fsw_status_t    status;
+    int             ea_blocks;
+    struct fsw_string s;
+
+    if (dno->g.size > FSW_PATH_MAX)
+        return FSW_VOLUME_CORRUPTED;
+
+    /* Linux kernels ext4_inode_is_fast_symlink... */
+    ea_blocks = dno->raw->i_file_acl_lo ? (vol->g.log_blocksize >> 9) : 0;
+
+    if (dno->raw->i_blocks_lo - ea_blocks == 0) {
+        // "fast" symlink, path is stored inside the inode
+        s.type = FSW_STRING_TYPE_ISO88591;
+        s.size = s.len = (int)dno->g.size;
+        s.data = dno->raw->i_block;
+        status = fsw_strdup_coerce(link_target, vol->g.host_string_type, &s);
+    } else {
+        // "slow" symlink, path is stored in normal inode data
+        status = fsw_dnode_readlink_data(dno, link_target);
+    }
+
+    return status;
+}
+
+// EOF
diff --git a/filesystems/fsw_ext4.h b/filesystems/fsw_ext4.h
new file mode 100644 (file)
index 0000000..df7ad35
--- /dev/null
@@ -0,0 +1,66 @@
+/**
+ * \file fsw_ext4.h
+ * ext4 file system driver header.
+ */
+
+/*-
+ * Copyright (c) 2012 Stefan Agner
+ * Portions Copyright (c) 2006 Christoph Pfisterer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifndef _FSW_EXT4_H_
+#define _FSW_EXT4_H_
+
+#define VOLSTRUCTNAME fsw_ext4_volume
+#define DNODESTRUCTNAME fsw_ext4_dnode
+#include "fsw_core.h"
+
+#include "fsw_ext4_disk.h"
+
+
+//! Block size to be used when reading the ext4 superblock.
+#define EXT4_SUPERBLOCK_BLOCKSIZE  1024
+//! Block number where the (master copy of the) ext4 superblock resides.
+#define EXT4_SUPERBLOCK_BLOCKNO       1
+
+
+/**
+ * ext4: Volume structure with ext2-specific data.
+ */
+
+struct fsw_ext4_volume {
+    struct fsw_volume g;            //!< Generic volume structure
+    
+    struct ext4_super_block *sb;    //!< Full raw ext2 superblock structure
+    fsw_u32     *inotab_bno;        //!< Block numbers of the inode tables
+    fsw_u32     ind_bcnt;           //!< Number of blocks addressable through an indirect block
+    fsw_u32     dind_bcnt;          //!< Number of blocks addressable through a double-indirect block
+    fsw_u32     inode_size;         //!< Size of inode structure in bytes
+};
+
+/**
+ * ext2: Dnode structure with ext2-specific data.
+ */
+
+struct fsw_ext4_dnode {
+    struct fsw_dnode g;             //!< Generic dnode structure
+    
+    struct ext4_inode *raw;         //!< Full raw inode structure
+};
+
+
+#endif
diff --git a/filesystems/fsw_ext4_disk.h b/filesystems/fsw_ext4_disk.h
new file mode 100644 (file)
index 0000000..2bf3a4e
--- /dev/null
@@ -0,0 +1,500 @@
+/**
+ * \file fsw_ext4_disk.h
+ * ext4 file system on-disk structures.
+ */
+
+/*-
+ * Copyright (c) 2012 Stefan Agner
+ * Portions Copyright (c) 2006 Christoph Pfisterer
+ * Portions Copyright (c) 1991-2012 by various Linux kernel contributors
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifndef _FSW_EXT4_DISK_H_
+#define _FSW_EXT4_DISK_H_
+
+// types
+
+typedef fsw_s8  __s8;
+typedef fsw_u8  __u8;
+typedef fsw_s16 __s16;
+typedef fsw_u16 __u16;
+typedef fsw_s32 __s32;
+typedef fsw_u32 __u32;
+typedef fsw_s64 __s64;
+typedef fsw_u64 __u64;
+
+typedef __u16   __le16;
+typedef __u32   __le32;
+typedef __u64   __le64;
+
+//
+// from Linux kernel, fs/ext4/ext4.h
+//
+
+/*
+ * Special inode numbers
+ */
+#define        EXT4_BAD_INO             1      /* Bad blocks inode */
+#define EXT4_ROOT_INO           2      /* Root inode */
+#define EXT4_USR_QUOTA_INO      3      /* User quota inode */
+#define EXT4_GRP_QUOTA_INO      4      /* Group quota inode */
+#define EXT4_BOOT_LOADER_INO    5      /* Boot loader inode */
+#define EXT4_UNDEL_DIR_INO      6      /* Undelete directory inode */
+#define EXT4_RESIZE_INO                 7      /* Reserved group descriptors inode */
+#define EXT4_JOURNAL_INO        8      /* Journal inode */
+
+/*
+ * The second extended file system magic number
+ */
+#define EXT4_SUPER_MAGIC        0xEF53
+
+/*
+ * Macro-instructions used to manage several block sizes
+ */
+#define EXT4_MIN_BLOCK_SIZE             1024
+#define EXT4_MAX_BLOCK_SIZE             4096
+#define EXT4_MIN_BLOCK_LOG_SIZE           10
+#define EXT4_BLOCK_SIZE(s)              (EXT4_MIN_BLOCK_SIZE << (s)->s_log_block_size)
+#define EXT4_ADDR_PER_BLOCK(s)          (EXT4_BLOCK_SIZE(s) / sizeof (__u32))
+#define EXT4_BLOCK_SIZE_BITS(s)         ((s)->s_log_block_size + 10)
+#define EXT4_INODE_SIZE(s)      (((s)->s_rev_level == EXT4_GOOD_OLD_REV) ? \
+                                 EXT4_GOOD_OLD_INODE_SIZE : \
+                                 (s)->s_inode_size)
+
+/*
+ * Structure of a blocks group descriptor
+ */
+struct ext4_group_desc
+{
+       __le32  bg_block_bitmap_lo;     /* Blocks bitmap block */
+       __le32  bg_inode_bitmap_lo;     /* Inodes bitmap block */
+       __le32  bg_inode_table_lo;      /* Inodes table block */
+       __le16  bg_free_blocks_count_lo;/* Free blocks count */
+       __le16  bg_free_inodes_count_lo;/* Free inodes count */
+       __le16  bg_used_dirs_count_lo;  /* Directories count */
+       __le16  bg_flags;               /* EXT4_BG_flags (INODE_UNINIT, etc) */
+       __le32  bg_exclude_bitmap_lo;   /* Exclude bitmap for snapshots */
+       __le16  bg_block_bitmap_csum_lo;/* crc32c(s_uuid+grp_num+bbitmap) LE */
+       __le16  bg_inode_bitmap_csum_lo;/* crc32c(s_uuid+grp_num+ibitmap) LE */
+       __le16  bg_itable_unused_lo;    /* Unused inodes count */
+       __le16  bg_checksum;            /* crc16(sb_uuid+group+desc) */
+       __le32  bg_block_bitmap_hi;     /* Blocks bitmap block MSB */
+       __le32  bg_inode_bitmap_hi;     /* Inodes bitmap block MSB */
+       __le32  bg_inode_table_hi;      /* Inodes table block MSB */
+       __le16  bg_free_blocks_count_hi;/* Free blocks count MSB */
+       __le16  bg_free_inodes_count_hi;/* Free inodes count MSB */
+       __le16  bg_used_dirs_count_hi;  /* Directories count MSB */
+       __le16  bg_itable_unused_hi;    /* Unused inodes count MSB */
+       __le32  bg_exclude_bitmap_hi;   /* Exclude bitmap block MSB */
+       __le16  bg_block_bitmap_csum_hi;/* crc32c(s_uuid+grp_num+bbitmap) BE */
+       __le16  bg_inode_bitmap_csum_hi;/* crc32c(s_uuid+grp_num+ibitmap) BE */
+       __u32   bg_reserved;
+};
+
+
+/*
+ * Macro-instructions used to manage group descriptors
+ */
+#define EXT4_MIN_DESC_SIZE              32
+#define EXT4_MIN_DESC_SIZE_64BIT        64
+#define EXT4_MAX_DESC_SIZE              EXT4_MIN_BLOCK_SIZE
+#define EXT4_DESC_SIZE(s)              ((s)->s_desc_size)
+#define EXT4_BLOCKS_PER_GROUP(s)       ((s)->s_blocks_per_group)
+#define EXT4_DESC_PER_BLOCK(s)         (EXT4_BLOCK_SIZE(s) / EXT4_DESC_SIZE(s))
+#define EXT4_INODES_PER_GROUP(s)       ((s)->s_inodes_per_group)
+
+/*
+ * Constants relative to the data blocks
+ */
+#define EXT4_NDIR_BLOCKS                12
+#define EXT4_IND_BLOCK                  EXT4_NDIR_BLOCKS
+#define EXT4_DIND_BLOCK                 (EXT4_IND_BLOCK + 1)
+#define EXT4_TIND_BLOCK                 (EXT4_DIND_BLOCK + 1)
+#define EXT4_N_BLOCKS                   (EXT4_TIND_BLOCK + 1)
+
+/*
+ * Inode flags
+ */
+#define EXT4_SECRM_FL                   0x00000001 /* Secure deletion */
+#define EXT4_UNRM_FL                    0x00000002 /* Undelete */
+#define EXT4_COMPR_FL                   0x00000004 /* Compress file */
+#define EXT4_SYNC_FL                    0x00000008 /* Synchronous updates */
+#define EXT4_IMMUTABLE_FL               0x00000010 /* Immutable file */
+#define EXT4_APPEND_FL                  0x00000020 /* writes to file may only append */
+#define EXT4_NODUMP_FL                  0x00000040 /* do not dump file */
+#define EXT4_NOATIME_FL                 0x00000080 /* do not update atime */
+/* Reserved for compression usage... */
+#define EXT4_DIRTY_FL                   0x00000100
+#define EXT4_COMPRBLK_FL                0x00000200 /* One or more compressed clusters */
+#define EXT4_NOCOMP_FL                  0x00000400 /* Don't compress */
+#define EXT4_ECOMPR_FL                  0x00000800 /* Compression error */
+/* End compression flags --- maybe not all used */      
+#define EXT4_INDEX_FL                   0x00001000 /* hash-indexed directory */
+#define EXT4_IMAGIC_FL                  0x00002000 /* AFS directory */
+#define EXT4_JOURNAL_DATA_FL            0x00004000 /* Reserved for ext3 */
+#define EXT4_NOTAIL_FL                  0x00008000 /* file tail should not be merged */
+#define EXT4_DIRSYNC_FL                 0x00010000 /* dirsync behaviour (directories only) */
+#define EXT4_TOPDIR_FL                  0x00020000 /* Top of directory hierarchies*/
+#define EXT4_HUGE_FILE_FL               0x00040000 /* Set to each huge file */
+#define EXT4_EXTENTS_FL                 0x00080000 /* Inode uses extents */
+#define EXT4_EA_INODE_FL                0x00200000 /* Inode used for large EA */
+#define EXT4_EOFBLOCKS_FL               0x00400000 /* Blocks allocated beyond EOF */
+#define EXT4_RESERVED_FL                0x80000000 /* reserved for ext4 lib */
+
+#define EXT4_FL_USER_VISIBLE           0x004BDFFF /* User visible flags */
+#define EXT4_FL_USER_MODIFIABLE                0x004B80FF /* User modifiable flags */
+
+
+/*
+ * Structure of an inode on the disk
+ */
+struct ext4_inode {
+       __le16  i_mode;         /* File mode */
+       __le16  i_uid;          /* Low 16 bits of Owner Uid */
+       __le32  i_size_lo;      /* Size in bytes */
+       __le32  i_atime;        /* Access time */
+       __le32  i_ctime;        /* Inode Change time */
+       __le32  i_mtime;        /* Modification time */
+       __le32  i_dtime;        /* Deletion Time */
+       __le16  i_gid;          /* Low 16 bits of Group Id */
+       __le16  i_links_count;  /* Links count */
+       __le32  i_blocks_lo;    /* Blocks count */
+       __le32  i_flags;        /* File flags */
+       union {
+               struct {
+                       __le32  l_i_version;
+               } linux1;
+               struct {
+                       __u32  h_i_translator;
+               } hurd1;
+               struct {
+                       __u32  m_i_reserved1;
+               } masix1;
+       } osd1;                         /* OS dependent 1 */
+       __le32  i_block[EXT4_N_BLOCKS];/* Pointers to blocks */
+       __le32  i_generation;   /* File version (for NFS) */
+       __le32  i_file_acl_lo;  /* File ACL */
+       __le32  i_size_high;
+       __le32  i_obso_faddr;   /* Obsoleted fragment address */
+       union {
+               struct {
+                       __le16  l_i_blocks_high; /* were l_i_reserved1 */
+                       __le16  l_i_file_acl_high;
+                       __le16  l_i_uid_high;   /* these 2 fields */
+                       __le16  l_i_gid_high;   /* were reserved2[0] */
+                       __le16  l_i_checksum_lo;/* crc32c(uuid+inum+inode) LE */
+                       __le16  l_i_reserved;
+               } linux2;
+               struct {
+                       __le16  h_i_reserved1;  /* Obsoleted fragment number/size which are removed in ext4 */
+                       __u16   h_i_mode_high;
+                       __u16   h_i_uid_high;
+                       __u16   h_i_gid_high;
+                       __u32   h_i_author;
+               } hurd2;
+               struct {
+                       __le16  h_i_reserved1;  /* Obsoleted fragment number/size which are removed in ext4 */
+                       __le16  m_i_file_acl_high;
+                       __u32   m_i_reserved2[2];
+               } masix2;
+       } osd2;                         /* OS dependent 2 */
+       __le16  i_extra_isize;
+       __le16  i_checksum_hi;  /* crc32c(uuid+inum+inode) BE */
+       __le32  i_ctime_extra;  /* extra Change time      (nsec << 2 | epoch) */
+       __le32  i_mtime_extra;  /* extra Modification time(nsec << 2 | epoch) */
+       __le32  i_atime_extra;  /* extra Access time      (nsec << 2 | epoch) */
+       __le32  i_crtime;       /* File Creation time */
+       __le32  i_crtime_extra; /* extra FileCreationtime (nsec << 2 | epoch) */
+       __le32  i_version_hi;   /* high 32 bits for 64-bit version */
+};
+
+
+/*
+ * Inode flags used for atomic set/get
+ */
+enum {
+       EXT4_INODE_SECRM        = 0,    /* Secure deletion */
+       EXT4_INODE_UNRM         = 1,    /* Undelete */
+       EXT4_INODE_COMPR        = 2,    /* Compress file */
+       EXT4_INODE_SYNC         = 3,    /* Synchronous updates */
+       EXT4_INODE_IMMUTABLE    = 4,    /* Immutable file */
+       EXT4_INODE_APPEND       = 5,    /* writes to file may only append */
+       EXT4_INODE_NODUMP       = 6,    /* do not dump file */
+       EXT4_INODE_NOATIME      = 7,    /* do not update atime */
+/* Reserved for compression usage... */
+       EXT4_INODE_DIRTY        = 8,
+       EXT4_INODE_COMPRBLK     = 9,    /* One or more compressed clusters */
+       EXT4_INODE_NOCOMPR      = 10,   /* Don't compress */
+       EXT4_INODE_ECOMPR       = 11,   /* Compression error */
+/* End compression flags --- maybe not all used */
+       EXT4_INODE_INDEX        = 12,   /* hash-indexed directory */
+       EXT4_INODE_IMAGIC       = 13,   /* AFS directory */
+       EXT4_INODE_JOURNAL_DATA = 14,   /* file data should be journaled */
+       EXT4_INODE_NOTAIL       = 15,   /* file tail should not be merged */
+       EXT4_INODE_DIRSYNC      = 16,   /* dirsync behaviour (directories only) */
+       EXT4_INODE_TOPDIR       = 17,   /* Top of directory hierarchies*/
+       EXT4_INODE_HUGE_FILE    = 18,   /* Set to each huge file */
+       EXT4_INODE_EXTENTS      = 19,   /* Inode uses extents */
+       EXT4_INODE_EA_INODE     = 21,   /* Inode used for large EA */
+       EXT4_INODE_EOFBLOCKS    = 22,   /* Blocks allocated beyond EOF */
+       EXT4_INODE_RESERVED     = 31,   /* reserved for ext4 lib */
+};
+
+/*
+ * Structure of the super block
+ */
+struct ext4_super_block {
+/*00*/ __le32  s_inodes_count;         /* Inodes count */
+       __le32  s_blocks_count_lo;      /* Blocks count */
+       __le32  s_r_blocks_count_lo;    /* Reserved blocks count */
+       __le32  s_free_blocks_count_lo; /* Free blocks count */
+/*10*/ __le32  s_free_inodes_count;    /* Free inodes count */
+       __le32  s_first_data_block;     /* First Data Block */
+       __le32  s_log_block_size;       /* Block size */
+       __le32  s_log_cluster_size;     /* Allocation cluster size */
+/*20*/ __le32  s_blocks_per_group;     /* # Blocks per group */
+       __le32  s_clusters_per_group;   /* # Clusters per group */
+       __le32  s_inodes_per_group;     /* # Inodes per group */
+       __le32  s_mtime;                /* Mount time */
+/*30*/ __le32  s_wtime;                /* Write time */
+       __le16  s_mnt_count;            /* Mount count */
+       __le16  s_max_mnt_count;        /* Maximal mount count */
+       __le16  s_magic;                /* Magic signature */
+       __le16  s_state;                /* File system state */
+       __le16  s_errors;               /* Behaviour when detecting errors */
+       __le16  s_minor_rev_level;      /* minor revision level */
+/*40*/ __le32  s_lastcheck;            /* time of last check */
+       __le32  s_checkinterval;        /* max. time between checks */
+       __le32  s_creator_os;           /* OS */
+       __le32  s_rev_level;            /* Revision level */
+/*50*/ __le16  s_def_resuid;           /* Default uid for reserved blocks */
+       __le16  s_def_resgid;           /* Default gid for reserved blocks */
+       /*
+        * These fields are for EXT4_DYNAMIC_REV superblocks only.
+        *
+        * Note: the difference between the compatible feature set and
+        * the incompatible feature set is that if there is a bit set
+        * in the incompatible feature set that the kernel doesn't
+        * know about, it should refuse to mount the filesystem.
+        *
+        * e2fsck's requirements are more strict; if it doesn't know
+        * about a feature in either the compatible or incompatible
+        * feature set, it must abort and not try to meddle with
+        * things it doesn't understand...
+        */
+       __le32  s_first_ino;            /* First non-reserved inode */
+       __le16  s_inode_size;           /* size of inode structure */
+       __le16  s_block_group_nr;       /* block group # of this superblock */
+       __le32  s_feature_compat;       /* compatible feature set */
+/*60*/ __le32  s_feature_incompat;     /* incompatible feature set */
+       __le32  s_feature_ro_compat;    /* readonly-compatible feature set */
+/*68*/ __u8    s_uuid[16];             /* 128-bit uuid for volume */
+/*78*/ char    s_volume_name[16];      /* volume name */
+/*88*/ char    s_last_mounted[64];     /* directory where last mounted */
+/*C8*/ __le32  s_algorithm_usage_bitmap; /* For compression */
+       /*
+        * Performance hints.  Directory preallocation should only
+        * happen if the EXT4_FEATURE_COMPAT_DIR_PREALLOC flag is on.
+        */
+       __u8    s_prealloc_blocks;      /* Nr of blocks to try to preallocate*/
+       __u8    s_prealloc_dir_blocks;  /* Nr to preallocate for dirs */
+       __le16  s_reserved_gdt_blocks;  /* Per group desc for online growth */
+       /*
+        * Journaling support valid if EXT4_FEATURE_COMPAT_HAS_JOURNAL set.
+        */
+/*D0*/ __u8    s_journal_uuid[16];     /* uuid of journal superblock */
+/*E0*/ __le32  s_journal_inum;         /* inode number of journal file */
+       __le32  s_journal_dev;          /* device number of journal file */
+       __le32  s_last_orphan;          /* start of list of inodes to delete */
+       __le32  s_hash_seed[4];         /* HTREE hash seed */
+       __u8    s_def_hash_version;     /* Default hash version to use */
+       __u8    s_jnl_backup_type;
+       __le16  s_desc_size;            /* size of group descriptor */
+/*100*/        __le32  s_default_mount_opts;
+       __le32  s_first_meta_bg;        /* First metablock block group */
+       __le32  s_mkfs_time;            /* When the filesystem was created */
+       __le32  s_jnl_blocks[17];       /* Backup of the journal inode */
+       /* 64bit support valid if EXT4_FEATURE_COMPAT_64BIT */
+/*150*/        __le32  s_blocks_count_hi;      /* Blocks count */
+       __le32  s_r_blocks_count_hi;    /* Reserved blocks count */
+       __le32  s_free_blocks_count_hi; /* Free blocks count */
+       __le16  s_min_extra_isize;      /* All inodes have at least # bytes */
+       __le16  s_want_extra_isize;     /* New inodes should reserve # bytes */
+       __le32  s_flags;                /* Miscellaneous flags */
+       __le16  s_raid_stride;          /* RAID stride */
+       __le16  s_mmp_update_interval;  /* # seconds to wait in MMP checking */
+       __le64  s_mmp_block;            /* Block for multi-mount protection */
+       __le32  s_raid_stripe_width;    /* blocks on all data disks (N*stride)*/
+       __u8    s_log_groups_per_flex;  /* FLEX_BG group size */
+       __u8    s_checksum_type;        /* metadata checksum algorithm used */
+       __le16  s_reserved_pad;
+       __le64  s_kbytes_written;       /* nr of lifetime kilobytes written */
+       __le32  s_snapshot_inum;        /* Inode number of active snapshot */
+       __le32  s_snapshot_id;          /* sequential ID of active snapshot */
+       __le64  s_snapshot_r_blocks_count; /* reserved blocks for active
+                                             snapshot's future use */
+       __le32  s_snapshot_list;        /* inode number of the head of the
+                                          on-disk snapshot list */
+#define EXT4_S_ERR_START offsetof(struct ext4_super_block, s_error_count)
+       __le32  s_error_count;          /* number of fs errors */
+       __le32  s_first_error_time;     /* first time an error happened */
+       __le32  s_first_error_ino;      /* inode involved in first error */
+       __le64  s_first_error_block;    /* block involved of first error */
+       __u8    s_first_error_func[32]; /* function where the error happened */
+       __le32  s_first_error_line;     /* line number where error happened */
+       __le32  s_last_error_time;      /* most recent time of an error */
+       __le32  s_last_error_ino;       /* inode involved in last error */
+       __le32  s_last_error_line;      /* line number where error happened */
+       __le64  s_last_error_block;     /* block involved of last error */
+       __u8    s_last_error_func[32];  /* function where the error happened */
+#define EXT4_S_ERR_END offsetof(struct ext4_super_block, s_mount_opts)
+       __u8    s_mount_opts[64];
+       __le32  s_usr_quota_inum;       /* inode for tracking user quota */
+       __le32  s_grp_quota_inum;       /* inode for tracking group quota */
+       __le32  s_overhead_clusters;    /* overhead blocks/clusters in fs */
+       __le32  s_reserved[108];        /* Padding to the end of the block */
+       __le32  s_checksum;             /* crc32c(superblock) */
+};
+
+/*
+ * Revision levels
+ */
+#define EXT4_GOOD_OLD_REV       0       /* The good old (original) format */
+#define EXT4_DYNAMIC_REV        1       /* V2 format w/ dynamic inode sizes */
+
+#define EXT4_CURRENT_REV        EXT4_GOOD_OLD_REV
+#define EXT4_MAX_SUPP_REV       EXT4_DYNAMIC_REV
+
+#define EXT4_GOOD_OLD_INODE_SIZE 128
+
+/*
+ * Feature set definitions (only the once we need for read support)
+ */
+#define EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER     0x0001
+
+#define EXT4_FEATURE_INCOMPAT_COMPRESSION      0x0001
+#define EXT4_FEATURE_INCOMPAT_FILETYPE         0x0002
+#define EXT4_FEATURE_INCOMPAT_RECOVER          0x0004 /* Needs recovery */
+#define EXT4_FEATURE_INCOMPAT_JOURNAL_DEV      0x0008 /* Journal device */
+#define EXT4_FEATURE_INCOMPAT_META_BG          0x0010
+#define EXT4_FEATURE_INCOMPAT_EXTENTS          0x0040 /* extents support */
+#define EXT4_FEATURE_INCOMPAT_64BIT            0x0080
+#define EXT4_FEATURE_INCOMPAT_MMP               0x0100
+#define EXT4_FEATURE_INCOMPAT_FLEX_BG          0x0200
+#define EXT4_FEATURE_INCOMPAT_EA_INODE         0x0400 /* EA in inode */
+#define EXT4_FEATURE_INCOMPAT_DIRDATA          0x1000 /* data in dirent */
+#define EXT4_FEATURE_INCOMPAT_BG_USE_META_CSUM 0x2000 /* use crc32c for bg */
+#define EXT4_FEATURE_INCOMPAT_LARGEDIR         0x4000 /* >2GB or 3-lvl htree */
+#define EXT4_FEATURE_INCOMPAT_INLINEDATA       0x8000 /* data in inode */
+
+#define EXT4_FEATURE_INCOMPAT_SUPP     (EXT4_FEATURE_INCOMPAT_FILETYPE| \
+                                        EXT4_FEATURE_INCOMPAT_RECOVER| \
+                                        EXT4_FEATURE_INCOMPAT_META_BG| \
+                                        EXT4_FEATURE_INCOMPAT_EXTENTS| \
+                                        EXT4_FEATURE_INCOMPAT_64BIT| \
+                                        EXT4_FEATURE_INCOMPAT_FLEX_BG| \
+                                        EXT4_FEATURE_INCOMPAT_MMP)
+
+/*
+ * Structure of a directory entry
+ */
+#define EXT4_NAME_LEN 255
+
+struct ext4_dir_entry {
+    __le32  inode;                  /* Inode number */
+    __le16  rec_len;                /* Directory entry length */
+    __u8    name_len;               /* Name length */
+    __u8    file_type;
+    char    name[EXT4_NAME_LEN];    /* File name */
+};
+// NOTE: The original Linux kernel header defines ext4_dir_entry with the original
+//  layout and ext4_dir_entry_2 with the revised layout. We simply use the revised one.
+
+/*
+ * Ext2 directory file types.  Only the low 3 bits are used.  The
+ * other bits are reserved for now.
+ */
+enum {
+    EXT4_FT_UNKNOWN,
+    EXT4_FT_REG_FILE,
+    EXT4_FT_DIR,
+    EXT4_FT_CHRDEV,
+    EXT4_FT_BLKDEV,
+    EXT4_FT_FIFO,
+    EXT4_FT_SOCK,
+    EXT4_FT_SYMLINK,
+    EXT4_FT_MAX
+};
+
+/*
+ * ext4_inode has i_block array (60 bytes total).
+ * The first 12 bytes store ext4_extent_header;
+ * the remainder stores an array of ext4_extent.
+ * For non-inode extent blocks, ext4_extent_tail
+ * follows the array.
+ */
+
+/*
+ * This is the extent tail on-disk structure.
+ * All other extent structures are 12 bytes long.  It turns out that
+ * block_size % 12 >= 4 for at least all powers of 2 greater than 512, which
+ * covers all valid ext4 block sizes.  Therefore, this tail structure can be
+ * crammed into the end of the block without having to rebalance the tree.
+ */
+struct ext4_extent_tail {
+       __le32  et_checksum;    /* crc32c(uuid+inum+extent_block) */
+};
+
+/*
+ * This is the extent on-disk structure.
+ * It's used at the bottom of the tree.
+ */
+struct ext4_extent {
+       __le32  ee_block;       /* first logical block extent covers */
+       __le16  ee_len;         /* number of blocks covered by extent */
+       __le16  ee_start_hi;    /* high 16 bits of physical block */
+       __le32  ee_start_lo;    /* low 32 bits of physical block */
+};
+
+/*
+ * This is index on-disk structure.
+ * It's used at all the levels except the bottom.
+ */
+struct ext4_extent_idx {
+       __le32  ei_block;       /* index covers logical blocks from 'block' */
+       __le32  ei_leaf_lo;     /* pointer to the physical block of the next *
+                                * level. leaf or next index could be there */
+       __le16  ei_leaf_hi;     /* high 16 bits of physical block */
+       __u16   ei_unused;
+};
+
+
+/*
+ * Each block (leaves and indexes), even inode-stored has header.
+ */
+struct ext4_extent_header {
+       __le16  eh_magic;       /* probably will support different formats */
+       __le16  eh_entries;     /* number of valid entries */
+       __le16  eh_max;         /* capacity of store in entries */
+       __le16  eh_depth;       /* has tree real underlying blocks? */
+       __le32  eh_generation;  /* generation of the tree */
+};
+
+#define EXT4_EXT_MAGIC         (0xf30a)
+
+
+#endif
diff --git a/filesystems/fsw_hfs.c b/filesystems/fsw_hfs.c
new file mode 100644 (file)
index 0000000..d5c8ed5
--- /dev/null
@@ -0,0 +1,1371 @@
+/* $Id: fsw_hfs.c 33540 2010-10-28 09:27:05Z vboxsync $ */
+/** @file
+ * fsw_hfs.c - HFS file system driver code, see
+ *
+ *   http://developer.apple.com/technotes/tn/tn1150.html
+ *
+ * Current limitations:
+ *  - Doesn't support permissions
+ *  - Complete Unicode case-insensitiveness disabled (large tables)
+ *  - No links
+ *  - Only supports pure HFS+ (i.e. no HFS, or HFS+ embedded to HFS)
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include "fsw_hfs.h"
+
+#ifdef HOST_POSIX
+#define DPRINT(x) printf(x)
+#define DPRINT2(x,y) printf(x,y)
+#define BP(msg)    do { printf("ERROR: %s", msg); asm("int3"); } while (0)
+#else
+#define CONCAT(x,y) x##y
+#define DPRINT(x) Print(CONCAT(L,x))
+#define DPRINT2(x,y) Print(CONCAT(L,x), y)
+#define BP(msg) DPRINT(msg)
+#endif
+
+// functions
+#if 0
+void dump_str(fsw_u16* p, fsw_u32 len, int swap)
+{
+    int i;
+
+    for (i=0; i<len; i++)
+    {
+        fprintf(stderr, "%c", swap ? be16_to_cpu(p[i]) : p[i]);
+    }
+    fprintf(stderr, "\n");
+}
+#endif
+
+static fsw_status_t fsw_hfs_volume_mount(struct fsw_hfs_volume *vol);
+static void         fsw_hfs_volume_free(struct fsw_hfs_volume *vol);
+static fsw_status_t fsw_hfs_volume_stat(struct fsw_hfs_volume *vol, struct fsw_volume_stat *sb);
+
+static fsw_status_t fsw_hfs_dnode_fill(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno);
+static void         fsw_hfs_dnode_free(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno);
+static fsw_status_t fsw_hfs_dnode_stat(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno,
+                                           struct fsw_dnode_stat *sb);
+static fsw_status_t fsw_hfs_get_extent(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno,
+                                           struct fsw_extent *extent);
+
+static fsw_status_t fsw_hfs_dir_lookup(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno,
+                                           struct fsw_string *lookup_name, struct fsw_hfs_dnode **child_dno);
+static fsw_status_t fsw_hfs_dir_read(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno,
+                                         struct fsw_shandle *shand, struct fsw_hfs_dnode **child_dno);
+#if 0
+static fsw_status_t fsw_hfs_read_dirrec(struct fsw_shandle *shand, struct hfs_dirrec_buffer *dirrec_buffer);
+#endif
+
+static fsw_status_t fsw_hfs_readlink(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno,
+                                         struct fsw_string *link);
+
+//
+// Dispatch Table
+//
+
+struct fsw_fstype_table   FSW_FSTYPE_TABLE_NAME(hfs) = {
+    { FSW_STRING_TYPE_ISO88591, 4, 4, "hfs" },
+    sizeof(struct fsw_hfs_volume),
+    sizeof(struct fsw_hfs_dnode),
+
+    fsw_hfs_volume_mount, // volume open
+    fsw_hfs_volume_free,  // volume close
+    fsw_hfs_volume_stat,  // volume info: total_bytes, free_bytes
+    fsw_hfs_dnode_fill,   //return FSW_SUCCESS;
+    fsw_hfs_dnode_free,          // empty
+    fsw_hfs_dnode_stat,         //size and times
+    fsw_hfs_get_extent,         // get the physical disk block number for the requested logical block number
+    fsw_hfs_dir_lookup,  //retrieve the directory entry with the given name
+    fsw_hfs_dir_read,  // next directory entry when reading a directory
+    fsw_hfs_readlink,   // return FSW_UNSUPPORTED;
+};
+
+static const fsw_u16 fsw_latin_case_fold[] =
+{
+    /* 0 */ 0xFFFF, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+    /* 1 */ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+    /* 2 */ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+    /* 3 */ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+    /* 4 */ 0x0040, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+    /* 5 */ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+    /* 6 */ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+    /* 7 */ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+    /* 8 */ 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F,
+    /* 9 */ 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F,
+    /* A */ 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+    /* B */ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
+    /* C */ 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00E6, 0x00C7, 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
+    /* D */ 0x00F0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, 0x00F8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00FE, 0x00DF,
+    /* E */ 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
+    /* F */ 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF,
+};
+
+static fsw_u16 fsw_to_lower(fsw_u16 ch)
+{
+
+    if (ch < 0x0100)
+        return fsw_latin_case_fold[ch];
+
+    return ch;
+}
+
+static fsw_s32
+fsw_hfs_read_block (struct fsw_hfs_dnode    * dno,
+                    fsw_u32                   log_bno,
+                    fsw_u32                   off,
+                    fsw_s32                   len,
+                    fsw_u8                  * buf)
+{
+    fsw_status_t          status;
+    struct fsw_extent     extent;
+    fsw_u32               phys_bno;
+    fsw_u8*                 buffer;
+
+    extent.log_start = log_bno;
+    status = fsw_hfs_get_extent(dno->g.vol, dno, &extent);
+    if (status)
+        return status;
+
+    phys_bno = extent.phys_start;
+  //Slice - increase cache level from 0 to 3
+    status = fsw_block_get(dno->g.vol, phys_bno, 3, (void **)&buffer);
+    if (status)
+        return status;
+
+    fsw_memcpy(buf, buffer + off, len);
+
+    fsw_block_release(dno->g.vol, phys_bno, buffer);
+
+    return FSW_SUCCESS;
+
+}
+
+/* Read data from HFS file. */
+static fsw_s32
+fsw_hfs_read_file (struct fsw_hfs_dnode    * dno,
+                   fsw_u64                   pos,
+                   fsw_s32                   len,
+                   fsw_u8                  * buf)
+{
+
+    fsw_status_t          status;
+    fsw_u32               log_bno;
+    fsw_u32               block_size_bits = dno->g.vol->block_size_shift;
+    fsw_u32               block_size = (1 << block_size_bits);
+    fsw_u32               block_size_mask = block_size - 1;
+    fsw_s32               read = 0;
+
+    while (len > 0)
+    {
+        fsw_u32 off = (fsw_u32)(pos & block_size_mask);
+        fsw_s32 next_len = len;
+
+        log_bno = (fsw_u32)RShiftU64(pos, block_size_bits);
+
+        if (   next_len >= 0
+            && (fsw_u32)next_len >  block_size)
+            next_len = block_size;
+        status = fsw_hfs_read_block(dno, log_bno, off, next_len, buf);
+        if (status)
+            return -1;
+        buf  += next_len;
+        pos  += next_len;
+        len  -= next_len;
+        read += next_len;
+    }
+
+    return read;
+}
+
+
+static fsw_s32
+fsw_hfs_compute_shift(fsw_u32 size)
+{
+    fsw_s32 i;
+
+    for (i=0; i<32; i++)
+    {
+        if ((size >> i) == 0)
+            return i - 1;
+    }
+
+//    BP("BUG\n");
+    return 0;
+}
+
+/**
+ * Mount an HFS+ volume. Reads the superblock and constructs the
+ * root directory dnode.
+ */
+//algo from Chameleon
+/*
+void
+HFSGetDescription(CICell ih, char *str, long strMaxLen)
+{
+  
+  UInt16 nodeSize;
+  UInt32 firstLeafNode;
+  long long dirIndex;
+  char *name;
+  long flags, time;
+  
+  if (HFSInitPartition(ih) == -1)  { return; }
+  
+  // Fill some crucial data structures by side effect. 
+  dirIndex = 0;
+  HFSGetDirEntry(ih, "/", &dirIndex, &name, &flags, &time, 0, 0);
+  
+  // Now we can loook up the volume name node. 
+  nodeSize = be16_to_cpu(gBTHeaders[kBTreeCatalog]->nodeSize);
+  firstLeafNode = SWAP_BE32(gBTHeaders[kBTreeCatalog]->firstLeafNode);
+  
+  dirIndex = (long long) firstLeafNode * nodeSize;
+  
+  GetCatalogEntry(&dirIndex, &name, &flags, &time, 0, 0);
+  
+  strncpy(str, name, strMaxLen);
+  str[strMaxLen] = '\0';
+}
+*/
+
+
+static fsw_status_t fsw_hfs_volume_mount(struct fsw_hfs_volume *vol)
+{
+    fsw_status_t              status, rv;
+    void                      *buffer = NULL;
+    HFSPlusVolumeHeader       *voldesc;
+    fsw_u32                   blockno;
+    struct fsw_string         s;
+    HFSMasterDirectoryBlock*  mdb;
+    fsw_u32 firstLeafNum;
+    fsw_u64 catfOffset;
+    fsw_u8 cbuff[sizeof (BTNodeDescriptor) + sizeof (HFSPlusCatalogKey)];
+
+    rv = FSW_UNSUPPORTED;
+
+    vol->primary_voldesc = NULL;
+    fsw_set_blocksize(vol, HFS_BLOCKSIZE, HFS_BLOCKSIZE);
+    blockno = HFS_SUPERBLOCK_BLOCKNO;
+
+#define CHECK(s)         \
+        if (status)  {   \
+            rv = status; \
+            break;       \
+        }
+
+    vol->emb_block_off = 0;
+    vol->hfs_kind = 0;
+    do {
+        fsw_u16       signature;
+        BTHeaderRec   tree_header;
+        fsw_s32       r;
+        fsw_u32       block_size;
+
+        status = fsw_block_get(vol, blockno, 0, &buffer);
+        CHECK(status);
+        voldesc = (HFSPlusVolumeHeader *)buffer;
+        mdb = (HFSMasterDirectoryBlock*)buffer;
+        signature = be16_to_cpu(voldesc->signature);
+
+        if ((signature == kHFSPlusSigWord) || (signature == kHFSXSigWord)) //H+ or HX
+        {
+            if (vol->hfs_kind == 0)
+            {
+//                DPRINT("found HFS+\n");
+                vol->hfs_kind = FSW_HFS_PLUS;
+            }
+        }
+        else if (signature == kHFSSigWord) // 'BD'
+        {
+            if (be16_to_cpu(mdb->drEmbedSigWord) == kHFSPlusSigWord)
+            {
+                DPRINT("found HFS+ inside HFS, untested\n");
+                vol->hfs_kind = FSW_HFS_PLUS_EMB;
+                vol->emb_block_off = be32_to_cpu(mdb->drEmbedExtent.startBlock);
+                blockno += vol->emb_block_off;
+                /* retry */
+                continue;
+            }
+            else
+            {
+                DPRINT("found plain HFS, unsupported\n");
+                vol->hfs_kind = FSW_HFS_PLAIN;
+            }
+            rv = FSW_UNSUPPORTED;
+            break;
+        }
+        else
+        {
+            rv = FSW_UNSUPPORTED;
+            break;
+        }
+
+        status = fsw_memdup((void **)&vol->primary_voldesc, voldesc,
+                            sizeof(*voldesc));
+        CHECK(status);
+
+
+        block_size = be32_to_cpu(voldesc->blockSize);
+        vol->block_size_shift = fsw_hfs_compute_shift(block_size);
+
+        fsw_block_release(vol, blockno, buffer);
+        buffer = NULL;
+        voldesc = NULL;
+        fsw_set_blocksize(vol, block_size, block_size);
+
+        /* set default/fallback volume name */
+        s.type = FSW_STRING_TYPE_ISO88591;
+        s.size = s.len = kHFSMaxVolumeNameChars;
+        s.data = "HFS+ volume";
+        status = fsw_strdup_coerce(&vol->g.label, vol->g.host_string_type, &s);
+        CHECK(status);
+
+        /* Setup catalog dnode */
+        status = fsw_dnode_create_root(vol, kHFSCatalogFileID, &vol->catalog_tree.file);
+        CHECK(status);
+        fsw_memcpy (vol->catalog_tree.file->extents,
+                    vol->primary_voldesc->catalogFile.extents,
+                    sizeof vol->catalog_tree.file->extents);
+        vol->catalog_tree.file->g.size =
+                be64_to_cpu(vol->primary_voldesc->catalogFile.logicalSize);
+
+        /* Setup extents overflow file */
+        status = fsw_dnode_create_root(vol, kHFSExtentsFileID, &vol->extents_tree.file);
+        fsw_memcpy (vol->extents_tree.file->extents,
+                    vol->primary_voldesc->extentsFile.extents,
+                    sizeof vol->extents_tree.file->extents);
+        vol->extents_tree.file->g.size =
+                be64_to_cpu(vol->primary_voldesc->extentsFile.logicalSize);
+
+        /* Setup the root dnode */
+        status = fsw_dnode_create_root(vol, kHFSRootFolderID, &vol->g.root);
+        CHECK(status);
+
+        /*
+         * Read catalog file, we know that first record is in the first node, right after
+         * the node descriptor.
+         */
+        r = fsw_hfs_read_file(vol->catalog_tree.file,
+                              sizeof (BTNodeDescriptor),
+                              sizeof (BTHeaderRec), (fsw_u8 *) &tree_header);
+        if (r <= 0)
+        {
+            status = FSW_VOLUME_CORRUPTED;
+            break;
+        }
+        vol->case_sensitive =
+                (signature == kHFSXSigWord) &&
+                (tree_header.keyCompareType == kHFSBinaryCompare);
+        vol->catalog_tree.root_node = be32_to_cpu (tree_header.rootNode);
+        vol->catalog_tree.node_size = be16_to_cpu (tree_header.nodeSize);
+
+        //nms42
+        /* Take Volume Name before tree_header overwritten */
+        firstLeafNum = be32_to_cpu(tree_header.firstLeafNode);
+        catfOffset = firstLeafNum * vol->catalog_tree.node_size;
+
+        r = fsw_hfs_read_file(vol->catalog_tree.file, catfOffset, sizeof (cbuff), cbuff);
+
+        if (r == sizeof (cbuff))
+        {
+           BTNodeDescriptor* btnd;
+           HFSPlusCatalogKey* ck;
+
+           btnd = (BTNodeDescriptor*) cbuff;
+           ck = (HFSPlusCatalogKey*) (cbuff + sizeof(BTNodeDescriptor));
+           if (btnd->kind == kBTLeafNode && be32_to_cpu (ck->parentID) == kHFSRootParentID)
+           {
+              struct fsw_string vn;
+
+              vn.type = FSW_STRING_TYPE_UTF16_BE;
+              vn.len = be16_to_cpu (ck->nodeName.length);
+              vn.size = vn.len * sizeof (fsw_u16);
+              vn.data = ck->nodeName.unicode;
+              fsw_strfree (&vol->g.label);
+              status = fsw_strdup_coerce(&vol->g.label, vol->g.host_string_type, &vn);
+              CHECK(status);
+           } // if
+        } // if
+
+        /* Read extents overflow file */
+        r = fsw_hfs_read_file(vol->extents_tree.file,
+                              sizeof (BTNodeDescriptor),
+                              sizeof (BTHeaderRec), (fsw_u8 *) &tree_header);
+        if (r <= 0)
+        {
+            status = FSW_VOLUME_CORRUPTED;
+            break;
+        }
+
+        vol->extents_tree.root_node = be32_to_cpu (tree_header.rootNode);
+        vol->extents_tree.node_size = be16_to_cpu (tree_header.nodeSize);
+
+        rv = FSW_SUCCESS;
+    } while (0);
+
+#undef CHECK
+
+
+    if (buffer != NULL)
+        fsw_block_release(vol, blockno, buffer);
+
+    return rv;
+}
+//Here is a method to obtain Volume label from Apple
+//how to implement it?
+/*
+UInt16 nodeSize;
+UInt32 firstLeafNode;
+long long dirIndex;
+char *name;
+long flags, time;
+ char              *nodeBuf, *testKey, *entry;
+
+
+if (HFSInitPartition(ih) == -1)  { return; }
+
+// Fill some crucial data structures by side effect. 
+dirIndex = 0;
+HFSGetDirEntry(ih, "/", &dirIndex, &name, &flags, &time, 0, 0);
+
+// Now we can loook up the volume name node.
+nodeSize = SWAP_BE16(gBTHeaders[kBTreeCatalog]->nodeSize);
+firstLeafNode = SWAP_BE32(gBTHeaders[kBTreeCatalog]->firstLeafNode);
+
+dirIndex = (long long) firstLeafNode * nodeSize;
+ index   = (long) (*dirIndex % nodeSize); == 0
+ curNode = (long) (*dirIndex / nodeSize); == firstLeafNode
+
+//GetCatalogEntry(&dirIndex, &name, &flags, &time, 0, 0);
+ // Read the BTree node and get the record for index.
+ ReadExtent(extent, extentSize, kHFSCatalogFileID,
+ (long long) curNode * nodeSize, nodeSize, nodeBuf, 1);
+ GetBTreeRecord(index, nodeBuf, nodeSize, &testKey, &entry);
+ utf_encodestr(((HFSPlusCatalogKey *)testKey)->nodeName.unicode,
+ SWAP_BE16(((HFSPlusCatalogKey *)testKey)->nodeName.length),
+ (u_int8_t *)gTempStr, 256, OSBigEndian);
+ *name = gTempStr; 
+
+strncpy(str, name, strMaxLen);
+str[strMaxLen] = '\0';
+*/
+
+/**
+ * Free the volume data structure. Called by the core after an unmount or after
+ * an unsuccessful mount to release the memory used by the file system type specific
+ * part of the volume structure.
+ */
+
+static void fsw_hfs_volume_free(struct fsw_hfs_volume *vol)
+{
+    if (vol->primary_voldesc)
+    {
+        fsw_free(vol->primary_voldesc);
+        vol->primary_voldesc = NULL;
+    }
+}
+
+/**
+ * Get in-depth information on a volume.
+ */
+
+static fsw_status_t fsw_hfs_volume_stat(struct fsw_hfs_volume *vol, struct fsw_volume_stat *sb)
+{
+    sb->total_bytes = be32_to_cpu(vol->primary_voldesc->totalBlocks) << vol->block_size_shift;
+    sb->free_bytes = be32_to_cpu(vol->primary_voldesc->freeBlocks) << vol->block_size_shift;
+    return FSW_SUCCESS;
+}
+
+/**
+ * Get full information on a dnode from disk. This function is called by the core
+ * whenever it needs to access fields in the dnode structure that may not
+ * be filled immediately upon creation of the dnode.
+ */
+
+static fsw_status_t fsw_hfs_dnode_fill(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno)
+{
+    return FSW_SUCCESS;
+}
+
+/**
+ * Free the dnode data structure. Called by the core when deallocating a dnode
+ * structure to release the memory used by the file system type specific part
+ * of the dnode structure.
+ */
+
+static void fsw_hfs_dnode_free(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno)
+{
+}
+
+static fsw_u32 mac_to_posix(fsw_u32 mac_time)
+{
+  /* Mac time is 1904 year based */
+  return mac_time ?  mac_time - 2082844800 : 0;
+}
+
+/**
+ * Get in-depth information on a dnode. The core makes sure that fsw_hfs_dnode_fill
+ * has been called on the dnode before this function is called. Note that some
+ * data is not directly stored into the structure, but passed to a host-specific
+ * callback that converts it to the host-specific format.
+ */
+
+static fsw_status_t fsw_hfs_dnode_stat(struct fsw_hfs_volume *vol,
+                                       struct fsw_hfs_dnode  *dno,
+                                       struct fsw_dnode_stat *sb)
+{
+  sb->used_bytes = dno->used_bytes;
+  fsw_store_time_posix(sb, FSW_DNODE_STAT_CTIME, mac_to_posix(dno->ctime));
+  fsw_store_time_posix(sb, FSW_DNODE_STAT_MTIME, mac_to_posix(dno->mtime));
+  fsw_store_time_posix(sb, FSW_DNODE_STAT_ATIME, 0);
+  fsw_store_attr_posix(sb, 0700);
+
+  return FSW_SUCCESS;
+}
+
+static int
+fsw_hfs_find_block(HFSPlusExtentRecord * exts,
+                   fsw_u32             * lbno,
+                   fsw_u32             * pbno)
+{
+    int i;
+    fsw_u32 cur_lbno = *lbno;
+
+    for (i = 0; i < 8; i++)
+    {
+        fsw_u32 start = be32_to_cpu ((*exts)[i].startBlock);
+        fsw_u32 count = be32_to_cpu ((*exts)[i].blockCount);
+
+        if (cur_lbno < count)
+        {
+            *pbno = start + cur_lbno;
+            return 1;
+        }
+
+        cur_lbno -= count;
+    }
+
+    *lbno = cur_lbno;
+
+    return 0;
+}
+
+/* Find record offset, numbering starts from the end */
+static fsw_u32
+fsw_hfs_btree_recoffset (struct fsw_hfs_btree * btree,
+                         BTNodeDescriptor     * node,
+                         fsw_u32                index)
+{
+  fsw_u8 *cnode = (fsw_u8 *) node;
+  fsw_u16 *recptr;
+  recptr = (fsw_u16 *) (cnode+btree->node_size - index * 2 - 2);
+  return be16_to_cpu(*recptr);
+}
+
+/* Pointer to the key inside node */
+static BTreeKey *
+fsw_hfs_btree_rec (struct fsw_hfs_btree   * btree,
+                   BTNodeDescriptor       * node,
+                   fsw_u32                  index)
+{
+  fsw_u8 *cnode = (fsw_u8 *) node;
+  fsw_u32 offset;
+  offset = fsw_hfs_btree_recoffset (btree, node, index);
+  return (BTreeKey *) (cnode + offset);
+}
+
+
+static fsw_status_t
+fsw_hfs_btree_search (struct fsw_hfs_btree * btree,
+                      BTreeKey             * key,
+                      int (*compare_keys) (BTreeKey* key1, BTreeKey* key2),
+                      BTNodeDescriptor    ** result,
+                      fsw_u32              * key_offset)
+{
+    BTNodeDescriptor* node;
+    fsw_u32 currnode;
+    fsw_u32 rec;
+    fsw_status_t status;
+    fsw_u8* buffer = NULL;
+
+    currnode = btree->root_node;
+    status = fsw_alloc(btree->node_size, &buffer);
+    if (status)
+        return status;
+    node = (BTNodeDescriptor*)buffer;
+
+    while (1)
+    {
+        int cmp = 0;
+        int match;
+        fsw_u32 count;
+
+    readnode:
+        match = 0;
+        /* Read a node.  */
+        if (fsw_hfs_read_file (btree->file,
+                               (fsw_u64)currnode * btree->node_size,
+                               btree->node_size, buffer) <= 0)
+        {
+            status = FSW_VOLUME_CORRUPTED;
+            break;
+        }
+
+        if (be16_to_cpu(*(fsw_u16*)(buffer + btree->node_size - 2)) != sizeof(BTNodeDescriptor))
+            BP("corrupted node\n");
+
+        count = be16_to_cpu (node->numRecords);
+
+#if 1
+        for (rec = 0; rec < count; rec++)
+        {
+             BTreeKey *currkey;
+
+             currkey = fsw_hfs_btree_rec (btree, node, rec);
+             cmp = compare_keys (currkey, key);
+             //fprintf(stderr, "rec=%d cmp=%d kind=%d \n", rec, cmp, node->kind);
+
+             /* Leaf node. */
+             if (node->kind == kBTLeafNode)
+             {
+               if (cmp == 0)
+               {
+                 /* Found!  */
+                 *result = node;
+                 *key_offset = rec;
+
+                 status = FSW_SUCCESS;
+                 goto done;
+               }
+             }
+             else if (node->kind == kBTIndexNode)
+             {
+                 fsw_u32 *pointer;
+
+                 if (cmp > 0)
+                     break;
+
+                 pointer = (fsw_u32 *) ((char *) currkey
+                                        + be16_to_cpu (currkey->length16)
+                                        + 2);
+                 currnode = be32_to_cpu (*pointer);
+                 match = 1;
+             }
+        }
+
+        if (node->kind == kBTLeafNode && cmp < 0 && node->fLink)
+        {
+            currnode = be32_to_cpu(node->fLink);
+            goto readnode;
+        }
+        else if (!match)
+        {
+            status = FSW_NOT_FOUND;
+            break;
+        }
+#else
+         /* Perform binary search */
+         fsw_u32 lower = 0;
+         fsw_u32 upper = count - 1;
+         fsw_s32 cmp = -1;
+         BTreeKey *currkey = NULL;
+
+         if (count == 0)
+         {
+             status = FSW_NOT_FOUND;
+             goto done;
+         }
+
+         while (lower <= upper)
+         {
+             fsw_u32 index = (lower + upper) / 2;
+
+             currkey = fsw_hfs_btree_rec (btree, node, index);
+
+             cmp = compare_keys (currkey, key);
+             if (cmp < 0)  upper = index - 1;
+             if (cmp > 0)  lower = index + 1;
+             if (cmp == 0)
+             {
+                 /* Found!  */
+                 *result = node;
+                 *key_offset = rec;
+
+                 status = FSW_SUCCESS;
+                 goto done;
+             }
+         }
+
+         if (cmp < 0)
+             currkey = fsw_hfs_btree_rec (btree, node, upper);
+
+         if (node->kind == kBTIndexNode && currkey)
+         {
+             fsw_u32 *pointer;
+
+             pointer = (fsw_u32 *) ((char *) currkey
+                                    + be16_to_cpu (currkey->length16)
+                                    + 2);
+             currnode = be32_to_cpu (*pointer);
+         }
+         else
+         {
+             status = FSW_NOT_FOUND;
+             break;
+         }
+#endif
+    }
+
+
+  done:
+    if (buffer != NULL && status != FSW_SUCCESS)
+        fsw_free(buffer);
+
+    return status;
+}
+typedef struct
+{
+    fsw_u32                 id;
+    fsw_u32                 type;
+    struct fsw_string     * name;
+    fsw_u64                 size;
+    fsw_u64                 used;
+    fsw_u32                 ctime;
+    fsw_u32                 mtime;
+    HFSPlusExtentRecord     extents;
+} file_info_t;
+
+typedef struct
+{
+    fsw_u32                 cur_pos; /* current position */
+    fsw_u32                 parent;
+    struct fsw_hfs_volume * vol;
+
+    struct fsw_shandle *    shandle; /* this one track iterator's state */
+    file_info_t             file_info;
+} visitor_parameter_t;
+
+static int
+fsw_hfs_btree_visit_node(BTreeKey *record, void* param)
+{
+    visitor_parameter_t* vp = (visitor_parameter_t*)param;
+    fsw_u8* base = (fsw_u8*)record->rawData + be16_to_cpu(record->length16) + 2;
+    fsw_u16 rec_type =  be16_to_cpu(*(fsw_u16*)base);
+    struct HFSPlusCatalogKey* cat_key = (HFSPlusCatalogKey*)record;
+    fsw_u16   name_len;
+    fsw_u16   *name_ptr;
+    fsw_u32   i;
+    struct fsw_string * file_name;
+
+    if (be32_to_cpu(cat_key->parentID) != vp->parent)
+        return -1;
+
+    /* not smth we care about */
+    if (vp->shandle->pos != vp->cur_pos++)
+        return 0;
+
+    switch (rec_type)
+    {
+        case kHFSPlusFolderRecord:
+        {
+            HFSPlusCatalogFolder* folder_info = (HFSPlusCatalogFolder*)base;
+
+            vp->file_info.id = be32_to_cpu(folder_info->folderID);
+            vp->file_info.type = FSW_DNODE_TYPE_DIR;
+            vp->file_info.size = be32_to_cpu(folder_info->valence);
+            vp->file_info.used = be32_to_cpu(folder_info->valence);
+            vp->file_info.ctime = be32_to_cpu(folder_info->createDate);
+            vp->file_info.mtime = be32_to_cpu(folder_info->contentModDate);
+            break;
+        }
+        case kHFSPlusFileRecord:
+        {
+            HFSPlusCatalogFile* file_info = (HFSPlusCatalogFile*)base;
+
+            vp->file_info.id = be32_to_cpu(file_info->fileID);
+            vp->file_info.type = FSW_DNODE_TYPE_FILE;
+            vp->file_info.size = be64_to_cpu(file_info->dataFork.logicalSize);
+            vp->file_info.used = LShiftU64(be32_to_cpu(file_info->dataFork.totalBlocks),
+                                           vp->vol->block_size_shift);
+            vp->file_info.ctime = be32_to_cpu(file_info->createDate);
+            vp->file_info.mtime = be32_to_cpu(file_info->contentModDate);
+            fsw_memcpy(&vp->file_info.extents, &file_info->dataFork.extents,
+                       sizeof vp->file_info.extents);
+            break;
+        }
+        case kHFSPlusFolderThreadRecord:
+        case kHFSPlusFileThreadRecord:
+        {
+            vp->shandle->pos++;
+            return 0;
+        }
+        default:
+            BP("unknown file type\n");
+            vp->file_info.type = FSW_DNODE_TYPE_UNKNOWN;
+            break;
+    }
+
+    name_len = be16_to_cpu(cat_key->nodeName.length);
+
+    file_name =  vp->file_info.name;
+    file_name->len = name_len;
+    fsw_memdup(&file_name->data, &cat_key->nodeName.unicode[0], 2*name_len);
+    file_name->size = 2*name_len;
+    file_name->type = FSW_STRING_TYPE_UTF16;
+    name_ptr = (fsw_u16*)file_name->data;
+    for (i=0; i<name_len; i++)
+    {
+        name_ptr[i] = be16_to_cpu(name_ptr[i]);
+    }
+    vp->shandle->pos++;
+
+    return 1;
+}
+
+static fsw_status_t
+fsw_hfs_btree_iterate_node (struct fsw_hfs_btree * btree,
+                            BTNodeDescriptor     * first_node,
+                            fsw_u32                first_rec,
+                            int                    (*callback) (BTreeKey *record, void* param),
+                            void                  * param)
+{
+  fsw_status_t status;
+  /* We modify node, so make a copy */
+  BTNodeDescriptor*     node = first_node;
+  fsw_u8* buffer = NULL;
+
+  status = fsw_alloc(btree->node_size, &buffer);
+  if (status)
+      return status;
+
+  while (1)
+  {
+      fsw_u32 i;
+      fsw_u32 count =  be16_to_cpu(node->numRecords);
+      fsw_u32 next_node;
+
+      /* Iterate over all records in this node.  */
+      for (i = first_rec; i < count; i++)
+      {
+          int rv = callback(fsw_hfs_btree_rec (btree, node, i), param);
+
+          switch (rv)
+          {
+              case 1:
+                  status = FSW_SUCCESS;
+                  goto done;
+              case -1:
+                  status = FSW_NOT_FOUND;
+                  goto done;
+          }
+          /* if callback returned 0 - continue */
+      }
+
+      next_node = be32_to_cpu(node->fLink);
+
+      if (!next_node)
+      {
+          status = FSW_NOT_FOUND;
+          break;
+      }
+
+      if (fsw_hfs_read_file (btree->file,
+                             next_node * btree->node_size,
+                             btree->node_size, buffer) <= 0)
+      {
+          status = FSW_VOLUME_CORRUPTED;
+          return 1;
+      }
+
+      node = (BTNodeDescriptor*)buffer;
+      first_rec = 0;
+  }
+ done:
+  if (buffer)
+      fsw_free(buffer);
+
+  return status;
+}
+
+#if 0
+void deb(fsw_u16* p, int len, int swap)
+{
+    int i;
+    for (i=0; i<len; i++)
+    {
+      printf("%c", swap ?  be16_to_cpu(p[i]) : p[i]);
+    }
+    printf("\n");
+}
+#endif
+
+static int
+fsw_hfs_cmp_extkey(BTreeKey* key1, BTreeKey* key2)
+{
+    HFSPlusExtentKey* ekey1 = (HFSPlusExtentKey*)key1;
+    HFSPlusExtentKey* ekey2 = (HFSPlusExtentKey*)key2;
+    int result;
+
+    /* First key is read from the FS data, second is in-memory in CPU endianess */
+    result = be32_to_cpu(ekey1->fileID) - ekey2->fileID;
+
+    if (result)
+        return result;
+
+    result = ekey1->forkType - ekey2->forkType;
+
+    if (result)
+        return result;
+
+    result = be32_to_cpu(ekey1->startBlock) - ekey2->startBlock;
+    return result;
+}
+
+static int
+fsw_hfs_cmp_catkey (BTreeKey *key1, BTreeKey *key2)
+{
+  HFSPlusCatalogKey *ckey1 = (HFSPlusCatalogKey*)key1;
+  HFSPlusCatalogKey *ckey2 = (HFSPlusCatalogKey*)key2;
+
+  int      apos, bpos, lc;
+  fsw_u16  ac, bc;
+  fsw_u32  parentId1;
+  int      key1Len;
+  fsw_u16 *p1;
+  fsw_u16 *p2;
+
+  parentId1 = be32_to_cpu(ckey1->parentID);
+
+  if (parentId1 > ckey2->parentID)
+      return 1;
+  if (parentId1 < ckey2->parentID)
+      return -1;
+
+  p1 = &ckey1->nodeName.unicode[0];
+  p2 = &ckey2->nodeName.unicode[0];
+  key1Len = be16_to_cpu (ckey1->nodeName.length);
+  apos = bpos = 0;
+
+  while(1)
+  {
+    /* get next valid character from ckey1 */
+    for (lc = 0; lc == 0 && apos < key1Len; apos++) {
+      ac = be16_to_cpu(p1[apos]);
+      lc = ac;
+    };
+    ac = (fsw_u16)lc;
+
+    /* get next valid character from ckey2 */
+    for (lc = 0; lc == 0 && bpos < ckey2->nodeName.length; bpos++) {
+      bc = p2[bpos];
+      lc = bc;
+    };
+    bc = (fsw_u16)lc;
+
+    if (ac != bc || (ac == 0  && bc == 0))
+      return ac - bc;
+  }
+}
+
+static int
+fsw_hfs_cmpi_catkey (BTreeKey *key1, BTreeKey *key2)
+{
+  HFSPlusCatalogKey *ckey1 = (HFSPlusCatalogKey*)key1;
+  HFSPlusCatalogKey *ckey2 = (HFSPlusCatalogKey*)key2;
+
+  int      apos, bpos, lc;
+  fsw_u16  ac, bc;
+  fsw_u32  parentId1;
+  int      key1Len;
+  fsw_u16 *p1;
+  fsw_u16 *p2;
+
+  parentId1 = be32_to_cpu(ckey1->parentID);
+
+  if (parentId1 > ckey2->parentID)
+      return 1;
+  if (parentId1 < ckey2->parentID)
+      return -1;
+
+  key1Len = be16_to_cpu (ckey1->nodeName.length);
+
+  if (key1Len == 0 && ckey2->nodeName.length == 0)
+      return 0;
+
+  p1 = &ckey1->nodeName.unicode[0];
+  p2 = &ckey2->nodeName.unicode[0];
+
+  apos = bpos = 0;
+
+  while(1)
+  {
+    /* get next valid character from ckey1 */
+    for (lc = 0; lc == 0 && apos < key1Len; apos++) {
+      ac = be16_to_cpu(p1[apos]);
+      lc = ac ? fsw_to_lower(ac) : 0;
+    };
+    ac = (fsw_u16)lc;
+
+    /* get next valid character from ckey2 */
+    for (lc = 0; lc == 0 && bpos < ckey2->nodeName.length; bpos++) {
+      bc = p2[bpos];
+      lc = bc ? fsw_to_lower(bc) : 0;
+    };
+    bc = (fsw_u16)lc;
+
+    if (ac != bc || (ac == 0  && bc == 0))
+      return ac - bc;
+  }
+}
+
+/**
+ * Retrieve file data mapping information. This function is called by the core when
+ * fsw_shandle_read needs to know where on the disk the required piece of the file's
+ * data can be found. The core makes sure that fsw_hfs_dnode_fill has been called
+ * on the dnode before. Our task here is to get the physical disk block number for
+ * the requested logical block number.
+ */
+
+static fsw_status_t fsw_hfs_get_extent(struct fsw_hfs_volume * vol,
+                                       struct fsw_hfs_dnode  * dno,
+                                       struct fsw_extent     * extent)
+{
+    fsw_status_t         status;
+    fsw_u32              lbno;
+    HFSPlusExtentRecord  *exts;
+    BTNodeDescriptor     *node = NULL;
+
+    extent->type = FSW_EXTENT_TYPE_PHYSBLOCK;
+    extent->log_count = 1;
+    lbno = extent->log_start;
+
+    /* we only care about data forks atm, do we? */
+    exts = &dno->extents;
+
+    while (1)
+    {
+        struct HFSPlusExtentKey* key;
+        struct HFSPlusExtentKey  overflowkey;
+        fsw_u32                  ptr;
+        fsw_u32                  phys_bno;
+
+        if (fsw_hfs_find_block(exts, &lbno, &phys_bno))
+        {
+            extent->phys_start = phys_bno + vol->emb_block_off;
+            status = FSW_SUCCESS;
+            break;
+        }
+
+
+        /* Find appropriate overflow record */
+        overflowkey.fileID = dno->g.dnode_id;
+        overflowkey.startBlock = extent->log_start - lbno;
+
+        if (node != NULL)
+        {
+            fsw_free(node);
+            node = NULL;
+        }
+
+        status = fsw_hfs_btree_search (&vol->extents_tree,
+                                       (BTreeKey*)&overflowkey,
+                                       fsw_hfs_cmp_extkey,
+                                       &node, &ptr);
+        if (status)
+            break;
+
+        key = (struct HFSPlusExtentKey *)
+                fsw_hfs_btree_rec (&vol->extents_tree, node, ptr);
+        exts = (HFSPlusExtentRecord*) (key + 1);
+    }
+
+    if (node != NULL)
+        fsw_free(node);
+
+    return status;
+}
+
+static const fsw_u16* g_blacklist[] =
+{
+    //L"AppleIntelCPUPowerManagement.kext",
+    NULL
+};
+
+
+//#define HFS_FILE_INJECTION
+
+#ifdef HFS_FILE_INJECTION
+static struct
+{
+  const fsw_u16* path;
+  const fsw_u16* name;
+} g_injectList[] =
+{
+  {
+    L"/System/Library/Extensions",
+    L"ApplePS2Controller.kext"
+  },
+  {
+    NULL,
+    NULL
+  }
+};
+#endif
+
+static fsw_status_t
+create_hfs_dnode(struct fsw_hfs_dnode  * dno,
+                 file_info_t           * file_info,
+                 struct fsw_hfs_dnode ** child_dno_out)
+{
+    fsw_status_t           status;
+    struct fsw_hfs_dnode * baby;
+
+    status = fsw_dnode_create(dno, file_info->id, file_info->type,
+                              file_info->name, &baby);
+    if (status)
+        return status;
+
+    baby->g.size = file_info->size;
+    baby->used_bytes = file_info->used;
+    baby->ctime = file_info->ctime;
+    baby->mtime = file_info->mtime;
+
+
+    /* Fill-in extents info */
+    if (file_info->type == FSW_DNODE_TYPE_FILE)
+    {
+        fsw_memcpy(baby->extents, &file_info->extents, sizeof file_info->extents);
+    }
+
+    *child_dno_out = baby;
+
+    return FSW_SUCCESS;
+}
+
+
+/**
+ * Lookup a directory's child dnode by name. This function is called on a directory
+ * to retrieve the directory entry with the given name. A dnode is constructed for
+ * this entry and returned. The core makes sure that fsw_hfs_dnode_fill has been called
+ * and the dnode is actually a directory.
+ */
+
+static fsw_status_t fsw_hfs_dir_lookup(struct fsw_hfs_volume * vol,
+                                       struct fsw_hfs_dnode  * dno,
+                                       struct fsw_string     * lookup_name,
+                                       struct fsw_hfs_dnode ** child_dno_out)
+{
+    fsw_status_t               status;
+    struct HFSPlusCatalogKey   catkey;
+    fsw_u32                    ptr;
+    fsw_u16                    rec_type;
+    BTNodeDescriptor *         node = NULL;
+    struct fsw_string          rec_name;
+    int                        free_data = 0, i;
+    HFSPlusCatalogKey*         file_key;
+    file_info_t                file_info;
+    fsw_u8*                    base;
+
+
+    fsw_memzero(&file_info, sizeof file_info);
+    file_info.name = &rec_name;
+
+    catkey.parentID = dno->g.dnode_id;
+    catkey.nodeName.length = (fsw_u16)lookup_name->len;
+
+    /* no need to allocate anything */
+    if (lookup_name->type == FSW_STRING_TYPE_UTF16)
+    {
+        fsw_memcpy(catkey.nodeName.unicode, lookup_name->data, lookup_name->size);
+        rec_name = *lookup_name;
+    } else
+    {
+        status = fsw_strdup_coerce(&rec_name, FSW_STRING_TYPE_UTF16, lookup_name);
+        /* nothing allocated so far */
+        if (status)
+            goto done;
+        free_data = 1;
+        fsw_memcpy(catkey.nodeName.unicode, rec_name.data, rec_name.size);
+    }
+
+    /* Dirty hack: blacklisting of certain files on FS driver level */
+    for (i = 0; g_blacklist[i]; i++)
+    {
+        if (fsw_memeq(g_blacklist[i], catkey.nodeName.unicode, catkey.nodeName.length*2))
+        {
+            DPRINT2("Blacklisted %s\n", g_blacklist[i]);
+            status = FSW_NOT_FOUND;
+            goto done;
+        }
+    }
+
+#ifdef HFS_FILE_INJECTION
+    if (fsw_hfs_inject(vol,
+                       dno,
+                       catkey.nodeName.unicode,
+                       catkey.nodeName.length,
+                       &file_info))
+    {
+        status = FSW_SUCCESS;
+        goto create;
+    }
+#endif
+
+    catkey.keyLength = (fsw_u16)(5 + rec_name.size);
+
+    status = fsw_hfs_btree_search (&vol->catalog_tree,
+                                   (BTreeKey*)&catkey,
+                                   vol->case_sensitive ?
+                                       fsw_hfs_cmp_catkey : fsw_hfs_cmpi_catkey,
+                                   &node, &ptr);
+    if (status)
+        goto done;
+
+    file_key = (HFSPlusCatalogKey *)fsw_hfs_btree_rec (&vol->catalog_tree, node, ptr);
+    /* for plain HFS "-(keySize & 1)" would be needed */
+    base = (fsw_u8*)file_key + be16_to_cpu(file_key->keyLength) + 2;
+    rec_type =  be16_to_cpu(*(fsw_u16*)base);
+
+    /** @todo: read additional info */
+    switch (rec_type)
+    {
+        case kHFSPlusFolderRecord:
+        {
+            HFSPlusCatalogFolder* info = (HFSPlusCatalogFolder*)base;
+
+            file_info.id = be32_to_cpu(info->folderID);
+            file_info.type = FSW_DNODE_TYPE_DIR;
+            /* @todo: return number of elements, maybe use smth else */
+            file_info.size = be32_to_cpu(info->valence);
+            file_info.used = be32_to_cpu(info->valence);
+            file_info.ctime = be32_to_cpu(info->createDate);
+            file_info.mtime = be32_to_cpu(info->contentModDate);
+            break;
+        }
+        case kHFSPlusFileRecord:
+        {
+            HFSPlusCatalogFile* info = (HFSPlusCatalogFile*)base;
+
+            file_info.id = be32_to_cpu(info->fileID);
+            file_info.type = FSW_DNODE_TYPE_FILE;
+            file_info.size = be64_to_cpu(info->dataFork.logicalSize);
+            file_info.used = LShiftU64(be32_to_cpu(info->dataFork.totalBlocks), vol->block_size_shift);
+            file_info.ctime = be32_to_cpu(info->createDate);
+            file_info.mtime = be32_to_cpu(info->contentModDate);
+            fsw_memcpy(&file_info.extents, &info->dataFork.extents,
+                       sizeof file_info.extents);
+            break;
+        }
+        default:
+            BP("unknown file type\n");
+            file_info.type = FSW_DNODE_TYPE_UNKNOWN;
+
+            break;
+    }
+#ifdef HFS_FILE_INJECTION
+create:
+#endif
+    status = create_hfs_dnode(dno, &file_info, child_dno_out);
+    if (status)
+        goto done;
+
+done:
+
+    if (node != NULL)
+        fsw_free(node);
+
+    if (free_data)
+        fsw_strfree(&rec_name);
+
+    return status;
+}
+
+/**
+ * Get the next directory entry when reading a directory. This function is called during
+ * directory iteration to retrieve the next directory entry. A dnode is constructed for
+ * the entry and returned. The core makes sure that fsw_hfs_dnode_fill has been called
+ * and the dnode is actually a directory. The shandle provided by the caller is used to
+ * record the position in the directory between calls.
+ */
+
+static fsw_status_t fsw_hfs_dir_read(struct fsw_hfs_volume *vol,
+                                     struct fsw_hfs_dnode  *dno,
+                                     struct fsw_shandle    *shand,
+                                     struct fsw_hfs_dnode  **child_dno_out)
+{
+    fsw_status_t               status;
+    struct HFSPlusCatalogKey   catkey;
+    fsw_u32                    ptr;
+    BTNodeDescriptor *         node = NULL;
+
+    visitor_parameter_t        param;
+    struct fsw_string          rec_name;
+
+    catkey.parentID = dno->g.dnode_id;
+    catkey.nodeName.length = 0;
+
+    fsw_memzero(&param, sizeof(param));
+
+    rec_name.type = FSW_STRING_TYPE_EMPTY;
+    param.file_info.name = &rec_name;
+
+    status = fsw_hfs_btree_search (&vol->catalog_tree,
+                                   (BTreeKey*)&catkey,
+                                   vol->case_sensitive ?
+                                       fsw_hfs_cmp_catkey : fsw_hfs_cmpi_catkey,
+                                   &node, &ptr);
+    if (status)
+        goto done;
+
+    /* Iterator updates shand state */
+    param.vol = vol;
+    param.shandle = shand;
+    param.parent = dno->g.dnode_id;
+    param.cur_pos = 0;
+    status = fsw_hfs_btree_iterate_node (&vol->catalog_tree,
+                                         node,
+                                         ptr,
+                                         fsw_hfs_btree_visit_node,
+                                         &param);
+    if (status)
+      goto done;
+
+    status = create_hfs_dnode(dno, &param.file_info, child_dno_out);
+
+    if (status)
+        goto done;
+
+ done:
+    fsw_strfree(&rec_name);
+
+    return status;
+}
+
+/**
+ * Get the target path of a symbolic link. This function is called when a symbolic
+ * link needs to be resolved. The core makes sure that the fsw_hfs_dnode_fill has been
+ * called on the dnode and that it really is a symlink.
+ *
+ */
+static fsw_status_t fsw_hfs_readlink(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno,
+                                     struct fsw_string *link_target)
+{
+    return FSW_UNSUPPORTED;
+}
+
+// EOF
diff --git a/filesystems/fsw_hfs.h b/filesystems/fsw_hfs.h
new file mode 100644 (file)
index 0000000..6d63643
--- /dev/null
@@ -0,0 +1,192 @@
+/* $Id: fsw_hfs.h 29125 2010-05-06 09:43:05Z vboxsync $ */
+/** @file
+ * fsw_hfs.h - HFS file system driver header.
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef _FSW_HFS_H_
+#define _FSW_HFS_H_
+
+#define VOLSTRUCTNAME fsw_hfs_volume
+#define DNODESTRUCTNAME fsw_hfs_dnode
+
+#include "fsw_core.h"
+
+
+//! Block size for HFS volumes.
+#define HFS_BLOCKSIZE            512
+
+//! Block number where the HFS superblock resides.
+#define HFS_SUPERBLOCK_BLOCKNO   2
+
+/* Make world look Applish enough for the system header describing HFS layout  */
+#define __APPLE_API_PRIVATE
+#define __APPLE_API_UNSTABLE
+
+#define u_int8_t  fsw_u8
+#define u_int16_t fsw_u16
+#define u_int32_t fsw_u32
+#define u_int64_t fsw_u64
+#define int8_t    fsw_s8
+#define int16_t   fsw_s16
+#define int32_t   fsw_s32
+#define int64_t   fsw_s64
+
+#include "hfs_format.h"
+
+#undef u_int8_t
+#undef u_int16_t
+#undef u_int32_t
+#undef u_int64_t
+#undef int8_t
+#undef int16_t
+#undef int32_t
+#undef int64_t
+
+#pragma pack(1)
+#ifdef _MSC_VER
+/* vasily: disable warning for non-standard anonymous struct/union
+ * declarations
+ */
+# pragma warning (disable:4201)
+# define inline __inline
+#endif
+
+struct hfs_dirrec {
+    fsw_u8      _dummy;
+};
+
+struct fsw_hfs_key
+{
+  union
+  {
+    struct HFSPlusExtentKey  ext_key;
+    struct HFSPlusCatalogKey cat_key;
+    fsw_u16                  key_len; /* Length is at the beginning of all keys */
+  };
+};
+
+#pragma pack()
+
+typedef enum {
+    /* Regular HFS */
+    FSW_HFS_PLAIN = 0,
+    /* HFS+ */
+    FSW_HFS_PLUS,
+    /* HFS+ embedded to HFS */
+    FSW_HFS_PLUS_EMB
+} fsw_hfs_kind;
+
+/**
+ * HFS: Dnode structure with HFS-specific data.
+ */
+
+struct fsw_hfs_dnode
+{
+  struct fsw_dnode          g;          //!< Generic dnode structure
+  HFSPlusExtentRecord       extents;
+  fsw_u32                   ctime;
+  fsw_u32                   mtime;
+  fsw_u64                   used_bytes;
+};
+
+/**
+ * HFS: In-memory B-tree structure.
+ */
+struct fsw_hfs_btree
+{
+    fsw_u32                  root_node;
+    fsw_u32                  node_size;
+    struct fsw_hfs_dnode*    file;
+};
+
+
+/**
+ * HFS: In-memory volume structure with HFS-specific data.
+ */
+
+struct fsw_hfs_volume
+{
+    struct fsw_volume            g;            //!< Generic volume structure
+
+    struct HFSPlusVolumeHeader   *primary_voldesc;  //!< Volume Descriptor
+    struct fsw_hfs_btree          catalog_tree;     // Catalog tree
+    struct fsw_hfs_btree          extents_tree;     // Extents overflow tree
+    struct fsw_hfs_dnode          root_file;
+    int                           case_sensitive;
+    fsw_u32                       block_size_shift;
+    fsw_hfs_kind                  hfs_kind;
+    fsw_u32                       emb_block_off;
+};
+
+/* Endianess swappers */
+static inline fsw_u16
+swab16(fsw_u16 x)
+{
+    return (x<<8 | ((x & 0xff00)>>8));
+}
+
+static inline fsw_u32
+swab32(fsw_u32 x)
+{
+    return x<<24 | x>>24 |
+            (x & (fsw_u32)0x0000ff00UL)<<8 |
+            (x & (fsw_u32)0x00ff0000UL)>>8;
+}
+
+
+static inline fsw_u64
+swab64(fsw_u64 x)
+{
+    return x<<56 | x>>56 |
+            (x & (fsw_u64)0x000000000000ff00ULL)<<40 |
+            (x & (fsw_u64)0x0000000000ff0000ULL)<<24 |
+            (x & (fsw_u64)0x00000000ff000000ULL)<< 8 |
+            (x & (fsw_u64)0x000000ff00000000ULL)>> 8 |
+            (x & (fsw_u64)0x0000ff0000000000ULL)>>24 |
+            (x & (fsw_u64)0x00ff000000000000ULL)>>40;
+}
+
+static inline fsw_u16
+be16_to_cpu(fsw_u16 x)
+{
+    return swab16(x);
+}
+
+static inline fsw_u16
+cpu_to_be16(fsw_u16 x)
+{
+    return swab16(x);
+}
+
+
+static inline fsw_u32
+cpu_to_be32(fsw_u32 x)
+{
+    return swab32(x);
+}
+
+static inline fsw_u32
+be32_to_cpu(fsw_u32 x)
+{
+    return swab32(x);
+}
+
+static inline fsw_u64
+be64_to_cpu(fsw_u64 x)
+{
+    return swab64(x);
+}
+
+#endif
diff --git a/filesystems/fsw_iso9660.c b/filesystems/fsw_iso9660.c
new file mode 100644 (file)
index 0000000..9962cb7
--- /dev/null
@@ -0,0 +1,701 @@
+/* $Id: fsw_iso9660.c 33540 2010-10-28 09:27:05Z vboxsync $ */
+/** @file
+ * fsw_iso9660.c - ISO9660 file system driver code.
+ *
+ * Current limitations:
+ *  - Files must be in one extent (i.e. Level 2)
+ *  - No Joliet or Rock Ridge extensions
+ *  - No interleaving
+ *  - inode number generation strategy fails on volumes > 2 GB
+ *  - No blocksizes != 2048
+ *  - No High Sierra or anything else != 'CD001'
+ *  - No volume sets with directories pointing at other volumes
+ *  - No extended attribute records
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/*-
+ * This code is based on:
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsw_iso9660.h"
+//#include <Protocol/MsgLog.h>
+
+#ifndef DEBUG_ISO
+#define DEBUG_ISO 1
+#endif
+
+#if DEBUG_ISO == 2
+#define DBG(x...)      AsciiPrint(x)
+#elif DEBUG_ISO == 1
+#define DBG(x...)      BootLog(x)
+#else
+#define DBG(x...)
+#endif
+
+//#define MsgLog(x...) if(msgCursor){AsciiSPrint(msgCursor, BOOTER_LOG_SIZE, x); while(*msgCursor){msgCursor++;}}
+
+// extern CHAR8     *msgCursor;
+// extern MESSAGE_LOG_PROTOCOL *Msg;
+// functions
+
+static fsw_status_t fsw_iso9660_volume_mount(struct fsw_iso9660_volume *vol);
+static void         fsw_iso9660_volume_free(struct fsw_iso9660_volume *vol);
+static fsw_status_t fsw_iso9660_volume_stat(struct fsw_iso9660_volume *vol, struct fsw_volume_stat *sb);
+
+static fsw_status_t fsw_iso9660_dnode_fill(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno);
+static void         fsw_iso9660_dnode_free(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno);
+static fsw_status_t fsw_iso9660_dnode_stat(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
+                                           struct fsw_dnode_stat *sb);
+static fsw_status_t fsw_iso9660_get_extent(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
+                                           struct fsw_extent *extent);
+
+static fsw_status_t fsw_iso9660_dir_lookup(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
+                                           struct fsw_string *lookup_name, struct fsw_iso9660_dnode **child_dno);
+static fsw_status_t fsw_iso9660_dir_read(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
+                                         struct fsw_shandle *shand, struct fsw_iso9660_dnode **child_dno);
+static fsw_status_t fsw_iso9660_read_dirrec(struct fsw_iso9660_volume *vol, struct fsw_shandle *shand, struct iso9660_dirrec_buffer *dirrec_buffer);
+
+static fsw_status_t fsw_iso9660_readlink(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
+                                         struct fsw_string *link);
+
+static fsw_status_t rr_find_sp(struct iso9660_dirrec *dirrec, struct fsw_rock_ridge_susp_sp **psp);
+static fsw_status_t rr_find_nm(struct fsw_iso9660_volume *vol, struct iso9660_dirrec *dirrec, int off, struct fsw_string *str);
+static fsw_status_t rr_read_ce(struct fsw_iso9660_volume *vol, union fsw_rock_ridge_susp_ce *ce, fsw_u8 *begin);
+//static void dump_dirrec(struct iso9660_dirrec *dirrec);
+//
+// Dispatch Table
+//
+
+struct fsw_fstype_table   FSW_FSTYPE_TABLE_NAME(iso9660) = {
+    { FSW_STRING_TYPE_ISO88591, 4, 4, "iso9660" },
+    sizeof(struct fsw_iso9660_volume),
+    sizeof(struct fsw_iso9660_dnode),
+
+    fsw_iso9660_volume_mount,
+    fsw_iso9660_volume_free,
+    fsw_iso9660_volume_stat,
+    fsw_iso9660_dnode_fill,
+    fsw_iso9660_dnode_free,
+    fsw_iso9660_dnode_stat,
+    fsw_iso9660_get_extent,
+    fsw_iso9660_dir_lookup,
+    fsw_iso9660_dir_read,
+    fsw_iso9660_readlink,
+};
+
+static fsw_status_t rr_find_sp(struct iso9660_dirrec *dirrec, struct fsw_rock_ridge_susp_sp **psp)
+{
+    fsw_u8 *r;
+    int off = 0;
+    struct fsw_rock_ridge_susp_sp *sp;
+    r = (fsw_u8 *)((fsw_u8 *)dirrec + sizeof(*dirrec) + dirrec->file_identifier_length);
+    off = (int)(r - (fsw_u8 *)dirrec);
+    while(off < dirrec->dirrec_length)
+    {
+        if (*r == 'S')
+        {
+            sp = (struct fsw_rock_ridge_susp_sp *)r;
+            if(    sp->e.sig[0] == 'S'
+                && sp->e.sig[1] == 'P'
+                && sp->magic[0] == 0xbe
+                && sp->magic[1] == 0xef)
+            {
+                *psp = sp;
+                return FSW_SUCCESS;
+            }
+        }
+        r++;
+        off = (int)(r - (fsw_u8 *)dirrec);
+    }
+    *psp = NULL;
+    return FSW_NOT_FOUND;
+}
+
+static fsw_status_t rr_find_nm(struct fsw_iso9660_volume *vol, struct iso9660_dirrec *dirrec, int off, struct fsw_string *str)
+{
+    fsw_u8 *r, *begin;
+    int fCe = 0;
+    struct fsw_rock_ridge_susp_nm *nm;
+    int limit = dirrec->dirrec_length;
+    begin = (fsw_u8 *)dirrec;
+    r = (fsw_u8 *)dirrec + off;
+    str->data = NULL;
+    str->len = 0;
+    str->size = 0;
+    str->type = 0;
+    while(off < limit)
+    {
+        if (r[0] == 'C' && r[1] == 'E' && r[2] == 28)
+        {
+            int rc;
+            int ce_off;
+            union fsw_rock_ridge_susp_ce *ce;
+            if (fCe == 0)
+                fsw_alloc_zero(ISO9660_BLOCKSIZE, (void *)&begin);
+            fCe = 1;
+        //    DEBUG((DEBUG_WARN, "%a:%d we found CE before NM or its continuation\n", __FILE__, __LINE__));
+            ce = (union fsw_rock_ridge_susp_ce *)r;
+            limit = ISOINT(ce->X.len);
+            ce_off = ISOINT(ce->X.offset);
+            rc = rr_read_ce(vol, ce, begin);
+            if (rc != FSW_SUCCESS)
+            {
+                fsw_free(begin);
+                return rc;
+            }
+            begin += ce_off;
+            r = begin;
+        }
+        if (r[0] == 'N' && r[1] == 'M')
+        {
+            nm = (struct fsw_rock_ridge_susp_nm *)r;
+            if(    nm->e.sig[0] == 'N'
+                && nm->e.sig[1] == 'M')
+            {
+                int len = 0;
+                fsw_u8 *tmp = NULL;
+                if (nm->flags & RR_NM_CURR)
+                {
+                     fsw_memdup(str->data, ".", 1);
+                     str->len = 1;
+                     goto done;
+                }
+                if (nm->flags & RR_NM_PARE)
+                {
+                     fsw_memdup(str->data, "..", 2);
+                     str->len = 2;
+                     goto done;
+                }
+                len = nm->e.len - sizeof(struct fsw_rock_ridge_susp_nm) + 1;
+                fsw_alloc_zero(str->len + len, (void **)&tmp);
+                if (str->data != NULL)
+                {
+                    fsw_memcpy(tmp, str->data, str->len);
+                    fsw_free(str->data);
+                }
+           //     DEBUG((DEBUG_INFO, "dst:%p src:%p len:%d\n", tmp + str->len, &nm->name[0], len));
+                fsw_memcpy(tmp + str->len, &nm->name[0], len);
+                str->data = tmp;
+                str->len += len;
+
+                if ((nm->flags & RR_NM_CONT) == 0);
+                    goto done;
+            }
+        }
+        r++;
+        off = (int)(r - (fsw_u8 *)begin);
+    }
+    if(fCe == 1)
+        fsw_free(begin);
+    return FSW_NOT_FOUND;
+done:
+    str->type = FSW_STRING_TYPE_ISO88591;
+    str->size = str->len;
+    if(fCe == 1)
+        fsw_free(begin);
+    return FSW_SUCCESS;
+}
+
+static fsw_status_t rr_read_ce(struct fsw_iso9660_volume *vol, union fsw_rock_ridge_susp_ce *ce, fsw_u8 *begin)
+{
+    int rc;
+//    int i;
+//    fsw_u8 *r = begin + ISOINT(ce->X.offset);
+//    int len = ISOINT(ce->X.len);
+    rc = vol->g.host_table->read_block(&vol->g, ISOINT(ce->X.block_loc), begin);
+    if (rc != FSW_SUCCESS)
+        return rc;
+/*    for (i = 0; i < len; ++i)
+    {
+        DEBUG((DEBUG_INFO, "%d: (%d:%x)%c ", i, r[i], r[i], r[i]));
+    }*/
+    return FSW_SUCCESS;
+}
+/*
+static void dump_dirrec(struct iso9660_dirrec *dirrec)
+{
+    int i;
+    fsw_u8 *r = (fsw_u8 *)dirrec + dirrec->file_identifier_length;
+    int len = dirrec->dirrec_length;
+    for (i = dirrec->file_identifier_length; i < len; ++i)
+    {
+        DEBUG((DEBUG_INFO, "%d: (%d:%x)%c ", i, r[i], r[i], r[i]));
+    }
+}*/
+/**
+ * Mount an ISO9660 volume. Reads the superblock and constructs the
+ * root directory dnode.
+ */
+
+static fsw_status_t fsw_iso9660_volume_mount(struct fsw_iso9660_volume *vol)
+{
+    fsw_status_t    status;
+    void            *buffer;
+    fsw_u32         blockno;
+    struct iso9660_volume_descriptor *voldesc;
+    struct iso9660_primary_volume_descriptor *pvoldesc;
+    fsw_u32         voldesc_type;
+    int             i;
+    struct fsw_string s;
+    struct iso9660_dirrec rootdir;
+    int sua_pos;
+    char *sig;
+    struct fsw_rock_ridge_susp_entry *entry;
+
+    // read through the Volume Descriptor Set
+    fsw_set_blocksize(vol, ISO9660_BLOCKSIZE, ISO9660_BLOCKSIZE);
+    blockno = ISO9660_SUPERBLOCK_BLOCKNO;
+
+    do {
+//      DBG("iso9660: check blockno=%d\n", blockno);
+        status = fsw_block_get(vol, blockno, 0, &buffer);
+        if (status)
+            return status;
+
+        voldesc = (struct iso9660_volume_descriptor *)buffer;
+        voldesc_type = voldesc->volume_descriptor_type;
+        if (fsw_memeq(voldesc->standard_identifier, "CD001", 5)) {
+            // descriptor follows ISO 9660 standard
+            if (voldesc_type == 1 && voldesc->volume_descriptor_version == 1) {
+                // suitable Primary Volume Descriptor found
+//              DBG("iso9660: suitable Primary Volume Descriptor found\n");
+                if (vol->primary_voldesc) {
+                    fsw_free(vol->primary_voldesc);
+                    vol->primary_voldesc = NULL;
+                }
+                status = fsw_memdup((void **)&vol->primary_voldesc, voldesc, ISO9660_BLOCKSIZE);
+            }
+        } else if (!fsw_memeq(voldesc->standard_identifier, "CD", 2)) {
+            // completely alien standard identifier, stop reading
+            voldesc_type = 255;
+        }
+
+        fsw_block_release(vol, blockno, buffer);
+        blockno++;
+    } while (!status && voldesc_type != 255);
+    if (status)
+        return status;
+
+    // get information from Primary Volume Descriptor
+    if (vol->primary_voldesc == NULL)
+        return FSW_UNSUPPORTED;
+    pvoldesc = vol->primary_voldesc;
+//     if (ISOINT(pvoldesc->logical_block_size) != 2048)
+//         return FSW_UNSUPPORTED;
+
+    // get volume name
+    for (i = 32; i > 0; i--)
+        if (pvoldesc->volume_identifier[i-1] != ' ')
+            break;
+    s.type = FSW_STRING_TYPE_ISO88591;
+    s.size = s.len = i;
+    s.data = pvoldesc->volume_identifier;
+    status = fsw_strdup_coerce(&vol->g.label, vol->g.host_string_type, &s);
+    if (status)
+        return status;
+
+    // setup the root dnode
+    status = fsw_dnode_create_root(vol, ISO9660_SUPERBLOCK_BLOCKNO << ISO9660_BLOCKSIZE_BITS, &vol->g.root);
+    if (status)
+        return status;
+    fsw_memcpy(&vol->g.root->dirrec, &pvoldesc->root_directory, sizeof(struct iso9660_dirrec));
+
+    if (   pvoldesc->escape[0] == 0x25
+        && pvoldesc->escape[1] == 0x2f
+        && (   pvoldesc->escape[2] == 0x40
+            || pvoldesc->escape[2] == 0x43
+            || pvoldesc->escape[2] == 0x45))
+    {
+ //       FSW_MSG_DEBUG((FSW_MSGSTR("fsw_iso9660_volume_mount: success (joliet!!!)\n")));
+//      DBG("fsw_iso9660_volume_mount: success (joliet!!!)\n");
+        vol->fJoliet = 1;
+    }
+
+
+    rootdir = pvoldesc->root_directory;
+    sua_pos = (sizeof(struct iso9660_dirrec)) + rootdir.file_identifier_length + (rootdir.file_identifier_length % 2) - 2;
+    //int sua_size = rootdir.dirrec_length - rootdir.file_identifier_length;
+    //FSW_MSG_DEBUG((FSW_MSGSTR("fsw_iso9660_volume_mount: success (SUA(pos:%x, sz:%d)!!!)\n"), sua_pos, sua_size));
+
+#if 1
+    status = fsw_block_get(vol, ISOINT(rootdir.extent_location), 0, &buffer);
+    sig = (char *)buffer + sua_pos;
+    entry = (struct fsw_rock_ridge_susp_entry *)sig;
+    if (   entry->sig[0] == 'S'
+        && entry->sig[1] == 'P')
+    {
+        struct fsw_rock_ridge_susp_sp *sp = (struct fsw_rock_ridge_susp_sp *)entry;
+        if (sp->magic[0] == 0xbe && sp->magic[1] == 0xef)
+        {
+            vol->fRockRidge = 1;
+        } else {
+ //           FSW_MSG_DEBUG((FSW_MSGSTR("fsw_iso9660_volume_mount: SP magic isn't valid\n")));
+//          DBG("fsw_iso9660_volume_mount: SP magic isn't valid\n");
+        }
+    }
+#endif
+    // release volume descriptors
+    fsw_free(vol->primary_voldesc);
+    vol->primary_voldesc = NULL;
+
+
+//    FSW_MSG_DEBUG((FSW_MSGSTR("fsw_iso9660_volume_mount: success\n")));
+//  DBG("fsw_iso9660_volume_mount: success\n");
+
+    return FSW_SUCCESS;
+}
+
+/**
+ * Free the volume data structure. Called by the core after an unmount or after
+ * an unsuccessful mount to release the memory used by the file system type specific
+ * part of the volume structure.
+ */
+
+static void fsw_iso9660_volume_free(struct fsw_iso9660_volume *vol)
+{
+    if (vol->primary_voldesc)
+        fsw_free(vol->primary_voldesc);
+}
+
+/**
+ * Get in-depth information on a volume.
+ */
+
+static fsw_status_t fsw_iso9660_volume_stat(struct fsw_iso9660_volume *vol, struct fsw_volume_stat *sb)
+{
+    sb->total_bytes = 0; //(fsw_u64)vol->sb->s_blocks_count      * vol->g.log_blocksize;
+    sb->free_bytes  = 0;
+    return FSW_SUCCESS;
+}
+
+/**
+ * Get full information on a dnode from disk. This function is called by the core
+ * whenever it needs to access fields in the dnode structure that may not
+ * be filled immediately upon creation of the dnode. In the case of iso9660, we
+ * delay fetching of the inode structure until dnode_fill is called. The size and
+ * type fields are invalid until this function has been called.
+ */
+
+static fsw_status_t fsw_iso9660_dnode_fill(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno)
+{
+    // get info from the directory record
+    dno->g.size = ISOINT(dno->dirrec.data_length);
+    if (dno->dirrec.file_flags & 0x02)
+        dno->g.type = FSW_DNODE_TYPE_DIR;
+    else
+        dno->g.type = FSW_DNODE_TYPE_FILE;
+
+    return FSW_SUCCESS;
+}
+
+/**
+ * Free the dnode data structure. Called by the core when deallocating a dnode
+ * structure to release the memory used by the file system type specific part
+ * of the dnode structure.
+ */
+
+static void fsw_iso9660_dnode_free(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno)
+{
+}
+
+/**
+ * Get in-depth information on a dnode. The core makes sure that fsw_iso9660_dnode_fill
+ * has been called on the dnode before this function is called. Note that some
+ * data is not directly stored into the structure, but passed to a host-specific
+ * callback that converts it to the host-specific format.
+ */
+
+static fsw_status_t fsw_iso9660_dnode_stat(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
+                                           struct fsw_dnode_stat *sb)
+{
+    sb->used_bytes = (dno->g.size + (ISO9660_BLOCKSIZE-1)) & ~(ISO9660_BLOCKSIZE-1);
+    /*
+    fsw_store_time_posix(sb, FSW_DNODE_STAT_CTIME, dno->raw->i_ctime);
+    fsw_store_time_posix(sb, FSW_DNODE_STAT_ATIME, dno->raw->i_atime);
+    fsw_store_time_posix(sb, FSW_DNODE_STAT_MTIME, dno->raw->i_mtime);
+    fsw_store_attr_posix(sb, dno->raw->i_mode);
+    */
+
+    return FSW_SUCCESS;
+}
+
+/**
+ * Retrieve file data mapping information. This function is called by the core when
+ * fsw_shandle_read needs to know where on the disk the required piece of the file's
+ * data can be found. The core makes sure that fsw_iso9660_dnode_fill has been called
+ * on the dnode before. Our task here is to get the physical disk block number for
+ * the requested logical block number.
+ */
+
+static fsw_status_t fsw_iso9660_get_extent(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
+                                           struct fsw_extent *extent)
+{
+    // Preconditions: The caller has checked that the requested logical block
+    //  is within the file's size. The dnode has complete information, i.e.
+    //  fsw_iso9660_dnode_read_info was called successfully on it.
+
+    extent->type = FSW_EXTENT_TYPE_PHYSBLOCK;
+    extent->phys_start = ISOINT(dno->dirrec.extent_location);
+    extent->log_start = 0;
+    extent->log_count = (ISOINT(dno->dirrec.data_length) + (ISO9660_BLOCKSIZE-1)) >> ISO9660_BLOCKSIZE_BITS;
+    return FSW_SUCCESS;
+}
+
+/**
+ * Lookup a directory's child dnode by name. This function is called on a directory
+ * to retrieve the directory entry with the given name. A dnode is constructed for
+ * this entry and returned. The core makes sure that fsw_iso9660_dnode_fill has been called
+ * and the dnode is actually a directory.
+ */
+
+static fsw_status_t fsw_iso9660_dir_lookup(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
+                                           struct fsw_string *lookup_name, struct fsw_iso9660_dnode **child_dno_out)
+{
+    fsw_status_t    status;
+    struct fsw_shandle shand;
+    struct iso9660_dirrec_buffer dirrec_buffer;
+    struct iso9660_dirrec *dirrec = &dirrec_buffer.dirrec;
+
+    // Preconditions: The caller has checked that dno is a directory node.
+
+    // setup handle to read the directory
+    status = fsw_shandle_open(dno, &shand);
+    if (status)
+        return status;
+
+    // scan the directory for the file
+    while (1) {
+        // read next entry
+        status = fsw_iso9660_read_dirrec(vol, &shand, &dirrec_buffer);
+        if (status)
+            goto errorexit;
+        if (dirrec->dirrec_length == 0) {
+            // end of directory reached
+            status = FSW_NOT_FOUND;
+            goto errorexit;
+        }
+
+        // skip . and ..
+        if (dirrec->file_identifier_length == 1 &&
+            (dirrec->file_identifier[0] == 0 || dirrec->file_identifier[0] == 1))
+            continue;
+
+        // compare name
+        if (fsw_streq(lookup_name, &dirrec_buffer.name))  // TODO: compare case-insensitively
+            break;
+    }
+
+    // setup a dnode for the child item
+    status = fsw_dnode_create(dno, dirrec_buffer.ino, FSW_DNODE_TYPE_UNKNOWN, &dirrec_buffer.name, child_dno_out);
+    if (status == FSW_SUCCESS)
+        fsw_memcpy(&(*child_dno_out)->dirrec, dirrec, sizeof(struct iso9660_dirrec));
+
+errorexit:
+    fsw_shandle_close(&shand);
+    return status;
+}
+
+/**
+ * Get the next directory entry when reading a directory. This function is called during
+ * directory iteration to retrieve the next directory entry. A dnode is constructed for
+ * the entry and returned. The core makes sure that fsw_iso9660_dnode_fill has been called
+ * and the dnode is actually a directory. The shandle provided by the caller is used to
+ * record the position in the directory between calls.
+ */
+
+static fsw_status_t fsw_iso9660_dir_read(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
+                                         struct fsw_shandle *shand, struct fsw_iso9660_dnode **child_dno_out)
+{
+    fsw_status_t    status;
+    struct iso9660_dirrec_buffer dirrec_buffer;
+    struct iso9660_dirrec *dirrec = &dirrec_buffer.dirrec;
+
+    // Preconditions: The caller has checked that dno is a directory node. The caller
+    //  has opened a storage handle to the directory's storage and keeps it around between
+    //  calls.
+    /* (vasily) directory nodes are 4096 bytes that is two logical blocks so read dir operation
+     * should read both blocks.
+     */
+
+    while (1) {
+        // read next entry
+        if (shand->pos >= dno->g.size)
+            return FSW_NOT_FOUND; // end of directory
+        status = fsw_iso9660_read_dirrec(vol, shand, &dirrec_buffer);
+        if (status)
+            return status;
+        if (dirrec->dirrec_length == 0)
+        {
+            // try the next block
+            shand->pos =(shand->pos & ~(vol->g.log_blocksize - 1)) + vol->g.log_blocksize;
+            continue;
+        }
+
+        // skip . and ..
+        if (dirrec->file_identifier_length == 1 &&
+            (dirrec->file_identifier[0] == 0 || dirrec->file_identifier[0] == 1))
+            continue;
+        break;
+    }
+
+    // setup a dnode for the child item
+    status = fsw_dnode_create(dno, dirrec_buffer.ino, FSW_DNODE_TYPE_UNKNOWN, &dirrec_buffer.name, child_dno_out);
+    if (status == FSW_SUCCESS)
+        fsw_memcpy(&(*child_dno_out)->dirrec, dirrec, sizeof(struct iso9660_dirrec));
+
+    return status;
+}
+
+/**
+ * Read a directory entry from the directory's raw data. This internal function is used
+ * to read a raw iso9660 directory entry into memory. The shandle's position pointer is adjusted
+ * to point to the next entry.
+ */
+
+static fsw_status_t fsw_iso9660_read_dirrec(struct fsw_iso9660_volume *vol, struct fsw_shandle *shand, struct iso9660_dirrec_buffer *dirrec_buffer)
+{
+    fsw_status_t    status;
+    fsw_u32         i, buffer_size, remaining_size, name_len;
+    struct fsw_rock_ridge_susp_sp *sp = NULL;
+    struct iso9660_dirrec *dirrec = &dirrec_buffer->dirrec;
+    int sp_off;
+    int rc;
+
+    dirrec_buffer->ino = (ISOINT(((struct fsw_iso9660_dnode *)shand->dnode)->dirrec.extent_location)
+                          << ISO9660_BLOCKSIZE_BITS)
+        + (fsw_u32)shand->pos;
+
+    // read fixed size part of directory record
+    buffer_size = 33;
+    status = fsw_shandle_read(shand, &buffer_size, dirrec);
+    if (status)
+    {
+    //    DEBUG((DEBUG_INFO, "%a:%d \n", __FILE__, __LINE__));
+        return status;
+    }
+
+    if (buffer_size < 33 || dirrec->dirrec_length == 0) {
+        // end of directory reached
+        fsw_u8 *r;
+        r = (fsw_u8 *)dirrec;
+ //       DEBUG((DEBUG_INFO, "%a:%d bs:%d dl:%d\n", __FILE__, __LINE__, buffer_size, dirrec->dirrec_length));
+        for(i = 0; i < buffer_size; ++i)
+        {
+            DEBUG((DEBUG_INFO, "r[%d]:%c", i, r[i]));
+        }
+        dirrec->dirrec_length = 0;
+        return FSW_SUCCESS;
+    }
+    if (dirrec->dirrec_length < 33 ||
+        dirrec->dirrec_length < 33 + dirrec->file_identifier_length)
+        return FSW_VOLUME_CORRUPTED;
+
+//    DEBUG((DEBUG_INFO, "%a:%d, dirrec_length: %d\n", __FILE__, __LINE__, dirrec->dirrec_length));
+
+    // read variable size part of directory record
+    buffer_size = remaining_size = dirrec->dirrec_length - 33;
+    status = fsw_shandle_read(shand, &buffer_size, dirrec->file_identifier);
+    if (status)
+        return status;
+    if (buffer_size < remaining_size)
+        return FSW_VOLUME_CORRUPTED;
+
+//     dump_dirrec(dirrec);
+     if (vol->fRockRidge)
+     {
+         sp_off = sizeof(*dirrec) + dirrec->file_identifier_length;
+         rc = rr_find_sp(dirrec, &sp);
+         if (   rc == FSW_SUCCESS
+             && sp != NULL)
+         {
+            sp_off = (fsw_u8 *)&sp[1] - (fsw_u8*)dirrec + sp->skip;
+         }
+         rc = rr_find_nm(vol, dirrec, sp_off,  &dirrec_buffer->name);
+         if (rc == FSW_SUCCESS)
+            return FSW_SUCCESS;
+    }
+
+    // setup name
+    name_len = dirrec->file_identifier_length;
+    for (i = name_len - 1; i > 0; i--) {
+        if (dirrec->file_identifier[i] == ';') {
+            name_len = i;   // cut the ISO9660 version number off
+            break;
+        }
+    }
+    if (name_len > 0 && dirrec->file_identifier[name_len-1] == '.')
+        name_len--;   // also cut the extension separator if the extension is empty
+    dirrec_buffer->name.type = FSW_STRING_TYPE_ISO88591;
+    dirrec_buffer->name.len = dirrec_buffer->name.size = name_len;
+    dirrec_buffer->name.data = dirrec->file_identifier;
+//    DEBUG((DEBUG_INFO, "%a:%d: dirrec_buffer->name.data:%a\n", __FILE__, __LINE__, dirrec_buffer->name.data));
+    return FSW_SUCCESS;
+}
+
+/**
+ * Get the target path of a symbolic link. This function is called when a symbolic
+ * link needs to be resolved. The core makes sure that the fsw_iso9660_dnode_fill has been
+ * called on the dnode and that it really is a symlink.
+ *
+ * For iso9660, the target path can be stored inline in the inode structure (in the space
+ * otherwise occupied by the block pointers) or in the inode's data. There is no flag
+ * indicating this, only the number of blocks entry (i_blocks) can be used as an
+ * indication. The check used here comes from the Linux kernel.
+ */
+
+static fsw_status_t fsw_iso9660_readlink(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
+                                         struct fsw_string *link_target)
+{
+    fsw_status_t    status;
+
+    if (dno->g.size > FSW_PATH_MAX)
+        return FSW_VOLUME_CORRUPTED;
+
+    status = fsw_dnode_readlink_data(dno, link_target);
+
+    return status;
+}
+
+// EOF
diff --git a/filesystems/fsw_iso9660.h b/filesystems/fsw_iso9660.h
new file mode 100644 (file)
index 0000000..c1dd94b
--- /dev/null
@@ -0,0 +1,206 @@
+/* $Id: fsw_iso9660.h 29125 2010-05-06 09:43:05Z vboxsync $ */
+/** @file
+ * fsw_iso9660.h - ISO9660 file system driver header.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _FSW_ISO9660_H_
+#define _FSW_ISO9660_H_
+
+#define VOLSTRUCTNAME fsw_iso9660_volume
+#define DNODESTRUCTNAME fsw_iso9660_dnode
+#include "fsw_core.h"
+
+
+//! Block size for ISO9660 volumes.
+#define ISO9660_BLOCKSIZE          2048
+#define ISO9660_BLOCKSIZE_BITS       11
+//! Block number where the ISO9660 superblock resides.
+#define ISO9660_SUPERBLOCK_BLOCKNO   16
+//Slice - we already have shifted blockIO by 16
+//but we should use ParentBlockIo
+//#define ISO9660_SUPERBLOCK_BLOCKNO   0
+
+#pragma pack(1)
+
+typedef struct {
+    fsw_u16     lsb;
+    fsw_u16     msb;
+} iso9660_u16;
+
+typedef struct {
+    fsw_u32     lsb;
+    fsw_u32     msb;
+} iso9660_u32;
+
+#define ISOINT(lsbmsbvalue) ((lsbmsbvalue).lsb)
+
+struct iso9660_dirrec {
+    fsw_u8      dirrec_length;
+    fsw_u8      ear_length;
+    iso9660_u32 extent_location;
+    iso9660_u32 data_length;
+    fsw_u8      recording_datetime[7];
+    fsw_u8      file_flags;
+    fsw_u8      file_unit_size;
+    fsw_u8      interleave_gap_size;
+    iso9660_u16 volume_sequence_number;
+    fsw_u8      file_identifier_length;
+    char        file_identifier[1];
+};
+//#if sizeof(struct fsw_iso9660_dirrec) != 34
+//#fail Structure fsw_iso9660_dirrec has wrong size
+//#endif
+
+struct iso9660_volume_descriptor {
+    fsw_u8      volume_descriptor_type;
+    char        standard_identifier[5];
+    fsw_u8      volume_descriptor_version;
+};
+
+struct iso9660_primary_volume_descriptor {
+    fsw_u8      volume_descriptor_type;
+    char        standard_identifier[5];
+    fsw_u8      volume_descriptor_version;
+    fsw_u8      unused1;
+    char        system_identifier[32];
+    char        volume_identifier[32];
+    fsw_u8      unused2[8];
+    iso9660_u32 volume_space_size;
+    fsw_u8      unused3[4];
+    fsw_u8      escape[3];
+    fsw_u8      unused4[25];
+    iso9660_u16 volume_set_size;
+    iso9660_u16 volume_sequence_number;
+    iso9660_u16 logical_block_size;
+    iso9660_u32 path_table_size;
+    fsw_u32     location_type_l_path_table;
+    fsw_u32     location_optional_type_l_path_table;
+    fsw_u32     location_type_m_path_table;
+    fsw_u32     location_optional_type_m_path_table;
+    struct iso9660_dirrec root_directory;
+    char        volume_set_identifier[128];
+    char        publisher_identifier[128];
+    char        data_preparer_identifier[128];
+    char        application_identifier[128];
+    char        copyright_file_identifier[37];
+    char        abstract_file_identifier[37];
+    char        bibliographic_file_identifier[37];
+    char        volume_creation_datetime[17];
+    char        volume_modification_datetime[17];
+    char        volume_expiration_datetime[17];
+    char        volume_effective_datetime[17];
+    fsw_u8      file_structure_version;
+    fsw_u8      reserved1;
+    fsw_u8      application_use[512];
+    fsw_u8      reserved2[653];
+};
+//#if sizeof(struct fsw_iso9660_volume_descriptor) != 2048
+//#fail Structure fsw_iso9660_volume_descriptor has wrong size
+//#endif
+
+#pragma pack()
+
+struct iso9660_dirrec_buffer {
+    fsw_u32     ino;
+    struct fsw_string name;
+    struct iso9660_dirrec dirrec;
+    char        dirrec_buffer[222];
+};
+
+
+/**
+ * ISO9660: Volume structure with ISO9660-specific data.
+ */
+
+struct fsw_iso9660_volume {
+    struct fsw_volume g;            //!< Generic volume structure
+    /*Note: don't move g!*/
+    int fJoliet;
+    /*Joliet specific fields*/
+    int fRockRidge;
+    /*Rock Ridge specific fields*/
+    int rr_susp_skip;
+
+    struct iso9660_primary_volume_descriptor *primary_voldesc;  //!< Full Primary Volume Descriptor
+};
+
+/**
+ * ISO9660: Dnode structure with ISO9660-specific data.
+ */
+
+struct fsw_iso9660_dnode {
+    struct fsw_dnode g;             //!< Generic dnode structure
+
+    struct iso9660_dirrec dirrec;   //!< Fixed part of the directory record (i.e. w/o name)
+};
+
+
+struct fsw_rock_ridge_susp_entry
+{
+    fsw_u8  sig[2];
+    fsw_u8  len;
+    fsw_u8  ver;
+};
+
+struct fsw_rock_ridge_susp_sp
+{
+    struct fsw_rock_ridge_susp_entry e;
+    fsw_u8  magic[2];
+    fsw_u8  skip;
+};
+
+struct fsw_rock_ridge_susp_nm
+{
+    struct fsw_rock_ridge_susp_entry e;
+    fsw_u8  flags;
+    fsw_u8  name[1];
+};
+
+#define RR_NM_CONT (1<<0)
+#define RR_NM_CURR (1<<1)
+#define RR_NM_PARE (1<<2)
+
+union fsw_rock_ridge_susp_ce
+{
+    struct X{
+        struct fsw_rock_ridge_susp_entry e;
+        iso9660_u32 block_loc;
+        iso9660_u32 offset;
+        iso9660_u32 len;
+    } X;
+    fsw_u8 raw[28];
+};
+
+#endif
diff --git a/filesystems/fsw_lib.c b/filesystems/fsw_lib.c
new file mode 100644 (file)
index 0000000..7da60be
--- /dev/null
@@ -0,0 +1,294 @@
+/**
+ * \file fsw_lib.c
+ * Core file system wrapper library functions.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsw_core.h"
+
+/* Include generated string encoding specific functions */
+#include "fsw_strfunc.h"
+
+
+/**
+ * Allocate memory and clear it.
+ */
+
+fsw_status_t fsw_alloc_zero(int len, void **ptr_out)
+{
+    fsw_status_t status;
+
+    status = fsw_alloc(len, ptr_out);
+    if (status)
+        return status;
+    fsw_memzero(*ptr_out, len);
+    return FSW_SUCCESS;
+}
+
+/**
+ * Duplicate a piece of data.
+ */
+
+fsw_status_t fsw_memdup(void **dest_out, void *src, int len)
+{
+    fsw_status_t status;
+
+    status = fsw_alloc(len, dest_out);
+    if (status)
+        return status;
+    fsw_memcpy(*dest_out, src, len);
+    return FSW_SUCCESS;
+}
+
+/**
+ * Get the length of a string. Returns the number of characters in the string.
+ */
+
+int fsw_strlen(struct fsw_string *s)
+{
+    if (s->type == FSW_STRING_TYPE_EMPTY)
+        return 0;
+    return s->len;
+}
+
+/**
+ * Compare two strings for equality. The two strings are compared, taking their
+ * encoding into account. If they are considered equal, boolean true is returned.
+ * Otherwise, boolean false is returned.
+ */
+
+int fsw_streq(struct fsw_string *s1, struct fsw_string *s2)
+{
+    struct fsw_string temp_s;
+
+    // handle empty strings
+    if (s1->type == FSW_STRING_TYPE_EMPTY) {
+        temp_s.type = FSW_STRING_TYPE_ISO88591;
+        temp_s.size = temp_s.len = 0;
+        temp_s.data = NULL;
+        return fsw_streq(&temp_s, s2);
+    }
+    if (s2->type == FSW_STRING_TYPE_EMPTY) {
+        temp_s.type = FSW_STRING_TYPE_ISO88591;
+        temp_s.size = temp_s.len = 0;
+        temp_s.data = NULL;
+        return fsw_streq(s1, &temp_s);
+    }
+
+    // check length (count of chars)
+    if (s1->len != s2->len)
+        return 0;
+    if (s1->len == 0)   // both strings are empty
+        return 1;
+
+    if (s1->type == s2->type) {
+        // same type, do a dumb memory compare
+        if (s1->size != s2->size)
+            return 0;
+        return fsw_memeq(s1->data, s2->data, s1->size);
+    }
+
+    // dispatch to type-specific functions
+    #define STREQ_DISPATCH(type1, type2) \
+      if (s1->type == FSW_STRING_TYPE_##type1 && s2->type == FSW_STRING_TYPE_##type2) \
+        return fsw_streq_##type1##_##type2(s1->data, s2->data, s1->len); \
+      if (s2->type == FSW_STRING_TYPE_##type1 && s1->type == FSW_STRING_TYPE_##type2) \
+        return fsw_streq_##type1##_##type2(s2->data, s1->data, s1->len);
+    STREQ_DISPATCH(ISO88591, UTF8);
+    STREQ_DISPATCH(ISO88591, UTF16);
+    STREQ_DISPATCH(ISO88591, UTF16_SWAPPED);
+    STREQ_DISPATCH(UTF8, UTF16);
+    STREQ_DISPATCH(UTF8, UTF16_SWAPPED);
+    STREQ_DISPATCH(UTF16, UTF16_SWAPPED);
+
+    // final fallback
+    return 0;
+}
+
+/**
+ * Compare a string with a C string constant. This sets up a string descriptor
+ * for the string constant (second argument) and runs fsw_streq on the two
+ * strings. Currently the C string is interpreted as ISO 8859-1.
+ * Returns boolean true if the strings are considered equal, boolean false otherwise.
+ */
+
+int fsw_streq_cstr(struct fsw_string *s1, const char *s2)
+{
+    struct fsw_string temp_s;
+    int i;
+
+    for (i = 0; s2[i]; i++)
+        ;
+
+    temp_s.type = FSW_STRING_TYPE_ISO88591;
+    temp_s.size = temp_s.len = i;
+    temp_s.data = (char *)s2;
+
+    return fsw_streq(s1, &temp_s);
+}
+
+/**
+ * Creates a duplicate of a string, converting it to the given encoding during the copy.
+ * If the function returns FSW_SUCCESS, the caller must free the string later with
+ * fsw_strfree.
+ */
+
+fsw_status_t fsw_strdup_coerce(struct fsw_string *dest, int type, struct fsw_string *src)
+{
+    fsw_status_t    status;
+
+    if (src->type == FSW_STRING_TYPE_EMPTY || src->len == 0) {
+        dest->type = type;
+        dest->size = dest->len = 0;
+        dest->data = NULL;
+        return FSW_SUCCESS;
+    }
+
+    if (src->type == type) {
+        dest->type = type;
+        dest->len  = src->len;
+        dest->size = src->size;
+        status = fsw_alloc(dest->size, &dest->data);
+        if (status)
+            return status;
+
+        fsw_memcpy(dest->data, src->data, dest->size);
+        return FSW_SUCCESS;
+    }
+
+    // dispatch to type-specific functions
+    #define STRCOERCE_DISPATCH(type1, type2) \
+      if (src->type == FSW_STRING_TYPE_##type1 && type == FSW_STRING_TYPE_##type2) \
+        return fsw_strcoerce_##type1##_##type2(src->data, src->len, dest);
+    STRCOERCE_DISPATCH(UTF8, ISO88591);
+    STRCOERCE_DISPATCH(UTF16, ISO88591);
+    STRCOERCE_DISPATCH(UTF16_SWAPPED, ISO88591);
+    STRCOERCE_DISPATCH(ISO88591, UTF8);
+    STRCOERCE_DISPATCH(UTF16, UTF8);
+    STRCOERCE_DISPATCH(UTF16_SWAPPED, UTF8);
+    STRCOERCE_DISPATCH(ISO88591, UTF16);
+    STRCOERCE_DISPATCH(UTF8, UTF16);
+    STRCOERCE_DISPATCH(UTF16_SWAPPED, UTF16);
+
+    return FSW_UNSUPPORTED;
+}
+
+/**
+ * Splits a string at the first occurence of the separator character.
+ * The buffer string is searched for the separator character. If it is found, the
+ * element string descriptor is filled to point at the part of the buffer string
+ * before the separator. The buffer string itself is adjusted to point at the
+ * remaining part of the string (without the separator).
+ *
+ * If the separator is not found in the buffer string, then element is changed to
+ * point at the whole buffer string, and the buffer string itself is changed into
+ * an empty string.
+ *
+ * This function only manipulates the pointers and lengths in the two string descriptors,
+ * it does not change the actual string. If the buffer string is dynamically allocated,
+ * you must make a copy of it so that you can release it later.
+ */
+
+void fsw_strsplit(struct fsw_string *element, struct fsw_string *buffer, char separator)
+{
+    int i, maxlen;
+
+    if (buffer->type == FSW_STRING_TYPE_EMPTY || buffer->len == 0) {
+        element->type = FSW_STRING_TYPE_EMPTY;
+        return;
+    }
+
+    maxlen = buffer->len;
+    *element = *buffer;
+
+    if (buffer->type == FSW_STRING_TYPE_ISO88591) {
+        fsw_u8 *p;
+
+        p = (fsw_u8 *)element->data;
+        for (i = 0; i < maxlen; i++, p++) {
+            if (*p == separator) {
+                buffer->data = p + 1;
+                buffer->len -= i + 1;
+                break;
+            }
+        }
+        element->len = i;
+        if (i == maxlen) {
+            buffer->data = p;
+            buffer->len -= i;
+        }
+
+        element->size = element->len;
+        buffer->size  = buffer->len;
+
+    } else if (buffer->type == FSW_STRING_TYPE_UTF16) {
+        fsw_u16 *p;
+
+        p = (fsw_u16 *)element->data;
+        for (i = 0; i < maxlen; i++, p++) {
+            if (*p == separator) {
+                buffer->data = p + 1;
+                buffer->len -= i + 1;
+                break;
+            }
+        }
+        element->len = i;
+        if (i == maxlen) {
+            buffer->data = p;
+            buffer->len -= i;
+        }
+
+        element->size = element->len * sizeof(fsw_u16);
+        buffer->size  = buffer->len  * sizeof(fsw_u16);
+
+    } else {
+        // fallback
+        buffer->type = FSW_STRING_TYPE_EMPTY;
+    }
+
+    // TODO: support UTF8 and UTF16_SWAPPED
+}
+
+/**
+ * Frees the memory used by a string returned from fsw_strdup_coerce.
+ */
+
+void fsw_strfree(struct fsw_string *s)
+{
+    if (s->type != FSW_STRING_TYPE_EMPTY && s->data)
+        fsw_free(s->data);
+    s->type = FSW_STRING_TYPE_EMPTY;
+}
+
+// EOF
diff --git a/filesystems/fsw_ntfs.c b/filesystems/fsw_ntfs.c
new file mode 100644 (file)
index 0000000..2fda530
--- /dev/null
@@ -0,0 +1,1538 @@
+/**
+ * \file fsw_ntfs.c
+ * ntfs file system driver code.
+ * Copyright (C) 2015 by Samuel Liao
+ */
+
+/*-
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include "fsw_core.h"
+
+#define Print(x...)    /* */
+
+static inline fsw_u8 GETU8(fsw_u8 *buf, int pos)
+{
+    return buf[pos];
+}
+
+static inline fsw_u16 GETU16(fsw_u8 *buf, int pos)
+{
+    return fsw_u16_le_swap(*(fsw_u16 *)(buf+pos));
+}
+
+static inline fsw_u32 GETU32(fsw_u8 *buf, int pos)
+{
+    return fsw_u32_le_swap(*(fsw_u32 *)(buf+pos));
+}
+
+static inline fsw_u64 GETU64(fsw_u8 *buf, int pos)
+{
+    return fsw_u64_le_swap(*(fsw_u64 *)(buf+pos));
+}
+
+#define MFTMASK  ((1ULL<<48) - 1)
+#define BADMFT (~0ULL)
+#define MFTNO_MFT      0
+#define MFTNO_VOLUME   3
+#define MFTNO_ROOT     5
+#define MFTNO_UPCASE   10
+#define MFTNO_META     16
+#define BADVCN (~0ULL)
+
+#define AT_STANDARD_INFORMATION        0x10
+#define AT_ATTRIBUTE_LIST      0x20
+#define AT_FILENAME            0x30    /* UNUSED */
+#define AT_VOLUME_NAME         0x60
+#define AT_VOLUME_INFORMATION  0x70    /* UNUSED */
+#define AT_DATA                        0x80
+#define AT_INDEX_ROOT          0x90
+#define AT_INDEX_ALLOCATION    0xa0
+#define AT_BITMAP              0xb0
+#define AT_REPARSE_POINT       0xc0
+
+#define ATTRMASK       0xFFFF
+#define ATTRBITS       16
+/* $I30 is LE, we can't use L"$I30" */
+#define NAME_I30       "$\0I\0003\0000\0"
+#define AT_I30         0x40000
+
+static const fsw_u16 upcase[0x80] =
+{
+    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+    0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+    0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+    0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+    0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+    0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+};
+
+struct extent_slot
+{
+    fsw_u64 vcn;
+    fsw_u64 lcn;
+    fsw_u64 cnt;
+};
+
+struct extent_map
+{
+    /*
+     * we build mft extent table instead use generic code, to prevent
+     * read_mft recursive or dead loop.
+     * While mft has too many fragments, it need AT_ATTRIBUTE_LIST for extra
+     * data, the AT_ATTRIBUTE_LIST parsing code need call read_mft again.
+     */
+    struct extent_slot *extent;
+    int total;
+    int used;
+};
+
+struct ntfs_mft
+{
+    fsw_u64 mftno;             /* current MFT no */
+    fsw_u8 *buf;               /* current MFT record data */
+    fsw_u8 *atlst;             /* AT_ATTRIBUTE_LIST data */
+    int atlen;                 /* AT_ATTRIBUTE_LIST size */
+};
+
+struct ntfs_attr
+{
+    fsw_u64 emftno;            /* MFT no of emft */
+    fsw_u8 *emft;              /* cached extend MFT record */
+    fsw_u8 *ptr;               /* current attribute data */
+    int len;                   /* current attribute size */
+    int type;                  /* current attribute type */
+};
+
+struct fsw_ntfs_volume
+{
+    struct fsw_volume g;
+    struct extent_map extmap;  /* MFT extent map */
+    fsw_u64 totalbytes;                /* volume size */
+    const fsw_u16 *upcase;     /* upcase map for non-ascii */
+    int upcount;               /* upcase map size */
+
+    fsw_u8 sctbits;            /* sector size */
+    fsw_u8 clbits;             /* cluster size */
+    fsw_u8 mftbits;            /* MFT record size */
+    fsw_u8 idxbits;            /* unused index size, use AT_INDEX_ROOT instead */
+};
+
+struct fsw_ntfs_dnode
+{
+    struct fsw_dnode g;
+    struct ntfs_mft mft;
+    struct ntfs_attr attr;     /* AT_INDEX_ALLOCATION:$I30/AT_DATA */
+    fsw_u8 *idxroot;           /* AT_INDEX_ROOT:$I30 */
+    fsw_u8 *idxbmp;            /* AT_BITMAP:$I30 */
+    unsigned int embeded:1;    /* embeded AT_DATA */
+    unsigned int has_idxtree:1;        /* valid AT_INDEX_ALLOCATION:$I30 */
+    unsigned int compressed:1; /* compressed AT_DATA */
+    unsigned int unreadable:1; /* unreadable/encrypted AT_DATA */
+    unsigned int cpfull:1;     /* in-compressable chunk */
+    unsigned int cpzero:1;     /* empty chunk */
+    unsigned int cperror:1;    /* decompress error */
+    unsigned int islink:1;     /* is symlink: AT_REPARSE_POINT */
+    int idxsz;                 /* size of index block */
+    int rootsz;                        /* size of idxroot: AT_INDEX_ROOT:$I30 */
+    int bmpsz;                 /* size of idxbmp: AT_BITMAP:$I30 */
+    struct extent_slot cext;   /* cached extent */
+    fsw_u64 fsize;             /* logical file size */
+    fsw_u64 finited;           /* initialized file size */
+    fsw_u64 cvcn;              /* vcn of compress chunk: cbuf */
+    fsw_u64 clcn[16];          /* cluster map of compress chunk */
+    fsw_u8 *cbuf;              /* compress chunk/index block/symlink target */
+};
+
+static fsw_status_t fixup(fsw_u8 *record, char *magic, int sectorsize, int size)
+{
+    int off, cnt, i;
+    fsw_u16 val;
+
+    if(*(int *)record != *(int *)magic)
+       return FSW_VOLUME_CORRUPTED;
+
+    off = GETU16(record, 4);
+    cnt = GETU16(record, 6);
+    if(size && sectorsize*(cnt-1) != size)
+       return FSW_VOLUME_CORRUPTED;
+    val = GETU16(record, off);
+    for(i=1; i<cnt; i++) {
+       if(GETU16(record, i*sectorsize-2)!=val)
+           return FSW_VOLUME_CORRUPTED;
+
+       *(fsw_u16 *)(record+i*sectorsize-2) = *(fsw_u16 *)(record+off+i*2);
+    }
+    return FSW_SUCCESS;
+}
+
+/* only supported attribute name is $I30 */
+static fsw_status_t find_attribute_direct(fsw_u8 *mft, int mftsize, int type, fsw_u8 **outptr, int *outlen)
+{
+    int namelen;
+    fsw_u32 n;
+
+    if(GETU32(mft, 0x18) < mftsize)
+       mftsize = GETU32(mft, 0x18);
+    mftsize -= GETU16(mft, 0x14);
+    mft += GETU16(mft, 0x14);
+
+    namelen = type>>ATTRBITS;
+    type &= ATTRMASK;
+
+    for(n = 0; mftsize >= 8; mft += n, mftsize -= n) {
+       int t = GETU32(mft, 0);
+       n = GETU32(mft, 4);
+       if( t==0 || (t+1)==0 || t==0xffff || n<24 || mftsize<n)
+           break;
+
+       fsw_u8 ns = GETU8(mft, 9);
+       fsw_u8 *nm = mft + GETU8(mft, 10);
+       if(type==t && namelen==ns && (ns==0 || fsw_memeq(NAME_I30, nm, ns*2))) {
+           if(outptr) *outptr = mft;
+           if(outlen) *outlen = n;
+           return FSW_SUCCESS;
+       }
+    }
+    return FSW_NOT_FOUND;
+}
+
+/* only supported attribute name is $I30 */
+static fsw_status_t find_attrlist_direct(fsw_u8 *atlst, int atlen, int type, fsw_u64 vcn, fsw_u64 *out, int *pos)
+{
+    fsw_u64 mftno = BADMFT;
+    int namelen;
+
+    namelen = type>>ATTRBITS;
+    type &= ATTRMASK;
+
+    while( *pos + 0x18 <= atlen) {
+       int off = *pos;
+       fsw_u32 t = GETU32(atlst, off);
+       fsw_u32 n = GETU16(atlst, off+4);
+
+       *pos = off + n;
+       if(t==0 || (t+1)==0 || t==0xffff || n < 0x18 || *pos > atlen)
+           break;
+
+       fsw_u8 ns = GETU8(atlst, off+6);
+       fsw_u8 *nm = atlst + off + GETU8(atlst, off+7);
+       if( type == t && namelen==ns && (ns==0 || fsw_memeq(NAME_I30, nm, ns*2))) {
+           fsw_u64 avcn = GETU64(atlst, off+8);
+           if(vcn < avcn) {
+               if(mftno == BADMFT)
+                   return FSW_NOT_FOUND;
+               *out = mftno;
+               return FSW_SUCCESS;
+           }
+           if(vcn == avcn) {
+               *out = GETU64(atlst, off+0x10) & MFTMASK;
+               return FSW_SUCCESS;
+           }
+           mftno = GETU64(atlst, off+0x10) & MFTMASK;
+       }
+    }
+    return FSW_NOT_FOUND;
+}
+
+static fsw_status_t get_extent(fsw_u8 **rlep, int *rlenp, fsw_u64 *lcnp, fsw_u64 *lenp, fsw_u64 *pos)
+{
+    fsw_u8 *rle = *rlep;
+    fsw_u8 *rle_end = rle + *rlenp;
+    int f = *rle++;
+    fsw_u64 m = 1;
+    fsw_u64 c = 0;
+    fsw_u64 v = 0;
+
+    int n = f & 0xf;
+    if(n==0) return FSW_NOT_FOUND;
+
+    if(rle + n > rle_end) return FSW_VOLUME_CORRUPTED;
+
+    while(--n >= 0) {
+       c += m * (*rle++);
+       m <<= 8;
+    }
+
+    n = f >> 4;
+    if(n==0) {
+       /* LCN 0 as sparse, due to we don't need $Boot */
+       *lcnp = 0;
+       *lenp = c;
+    } else {
+       if(rle + n > rle_end) return FSW_VOLUME_CORRUPTED;
+
+       m = 1;
+       while(--n >= 0) {
+           v += m * (*rle++);
+           m <<= 8;
+       }
+
+       *pos += v;
+       if(v & (m>>1))
+           *pos -= m;
+
+       *lcnp = *pos;
+       *lenp = c;
+    }
+    *rlenp -= rle - *rlep;
+    *rlep = rle;
+    return FSW_SUCCESS;
+}
+
+static inline int attribute_ondisk(fsw_u8 *ptr, int len)
+{
+    return GETU8(ptr, 8);
+}
+
+static inline int attribute_compressed(fsw_u8 *ptr, int len)
+{
+    return (GETU8(ptr, 12) & 0xFF) == 1;
+}
+
+static inline int attribute_compressed_future(fsw_u8 *ptr, int len)
+{
+    return (GETU8(ptr, 12) & 0xFF) > 1;
+}
+
+static inline int attribute_sparse(fsw_u8 *ptr, int len)
+{
+    return GETU8(ptr, 12) & 0x8000;
+}
+
+static inline int attribute_encrypted(fsw_u8 *ptr, int len)
+{
+    return GETU8(ptr, 12) & 0x4000;
+}
+
+static void attribute_get_embeded(fsw_u8 *ptr, int len, fsw_u8 **outp, int *outlenp)
+{
+    int off = GETU16(ptr, 0x14);
+    int olen = GETU16(ptr, 0x10);
+    if(olen + off > len)
+       olen = len - off;
+    *outp = ptr + off;
+    *outlenp = olen;
+}
+
+static void attribute_get_rle(fsw_u8 *ptr, int len, fsw_u8 **outp, int *outlenp)
+{
+    int off = GETU16(ptr, 0x20);
+    int olen = len - off;
+    *outp = ptr + off;
+    *outlenp = olen;
+}
+
+static inline int attribute_rle_offset(fsw_u8 *ptr, int len)
+{
+    return GETU16(ptr, 0x20);
+}
+
+static inline fsw_u64 attribute_size(fsw_u8 *ptr, int len)
+{
+    return GETU8(ptr, 8) ? GETU64(ptr, 0x30) : GETU16(ptr, 0x10);
+}
+
+static inline fsw_u64 attribute_inited_size(fsw_u8 *ptr, int len)
+{
+    return GETU8(ptr, 8) ? GETU64(ptr, 0x38) : GETU16(ptr, 0x10);
+}
+
+static inline int attribute_has_vcn(fsw_u8 *ptr, int len, fsw_u64 vcn) {
+    if(GETU8(ptr, 8)==0)
+       return 1;
+    return vcn >= GETU64(ptr, 0x10) && vcn <= GETU64(ptr, 0x18);
+}
+
+static inline fsw_u64 attribute_first_vcn(fsw_u8 *ptr, int len)
+{
+    return GETU8(ptr, 8) ? GETU64(ptr, 0x10) : 0;
+}
+
+static inline fsw_u64 attribute_last_vcn(fsw_u8 *ptr, int len)
+{
+    return GETU8(ptr, 8) ? GETU64(ptr, 0x18) : 0;
+}
+
+static fsw_status_t read_attribute_direct(struct fsw_ntfs_volume *vol, fsw_u8 *ptr, int len, fsw_u8 **optrp, int *olenp)
+{
+    int olen;
+
+    if(attribute_ondisk(ptr, len) == 0) {
+       /* EMBEDED DATA */
+       attribute_get_embeded(ptr, len, &ptr, &len);
+       *olenp = len;
+       if(optrp) {
+           *optrp = AllocatePool(len);
+           fsw_memcpy(*optrp, ptr, len);
+       }
+       return FSW_SUCCESS;
+    }
+
+    olen = attribute_size(ptr, len);
+    *olenp = olen;
+    if(!optrp)
+       return FSW_SUCCESS;
+
+    fsw_u8 *buf = AllocatePool(olen);
+    fsw_memzero(buf, olen);
+    *optrp = buf;
+
+    attribute_get_rle(ptr, len, &ptr, &len);
+
+    fsw_u64 pos = 0;
+    int clustersize = 1<<vol->clbits;
+    fsw_u64 lcn, cnt;
+
+    while(len > 0 && get_extent(&ptr, &len, &lcn, &cnt, &pos)==FSW_SUCCESS) {
+       if(lcn) {
+           for(; cnt>0; lcn++, cnt--) {
+               fsw_u8 *block;
+               if (fsw_block_get(&vol->g, lcn, 0, (void **)&block) != FSW_SUCCESS)
+               {
+                   FreePool(*optrp);
+                   *optrp = NULL;
+                   *olenp = 0;
+                   return FSW_VOLUME_CORRUPTED;
+               }
+               fsw_memcpy(buf, block, clustersize > olen ? olen : clustersize);
+               fsw_block_release(&vol->g, lcn, block);
+
+               buf += clustersize;
+               olen -= clustersize;
+           }
+       } else {
+           buf += cnt << vol->clbits;
+           olen -= cnt << vol->clbits;
+       }
+    }
+    return FSW_SUCCESS;
+}
+
+static void init_mft(struct fsw_ntfs_volume *vol, struct ntfs_mft *mft, fsw_u64 mftno)
+{
+    mft->mftno = mftno;
+    mft->buf = AllocatePool(1<<vol->mftbits);
+    mft->atlst = NULL;
+    mft->atlen = 0;
+}
+
+static void free_mft(struct ntfs_mft *mft)
+{
+    if(mft->buf) FreePool(mft->buf);
+    if(mft->atlst) FreePool(mft->atlst);
+}
+
+static fsw_status_t load_atlist(struct fsw_ntfs_volume *vol, struct ntfs_mft *mft)
+{
+    fsw_u8 *ptr;
+    int len;
+    fsw_status_t err = find_attribute_direct(mft->buf, 1<<vol->mftbits, AT_ATTRIBUTE_LIST, &ptr, &len);
+    if(err != FSW_SUCCESS)
+       return err;
+    return read_attribute_direct(vol, ptr, len, &mft->atlst, &mft->atlen);
+}
+
+static fsw_status_t read_mft(struct fsw_ntfs_volume *vol, fsw_u8 *mft, fsw_u64 mftno)
+{
+    int l = 0;
+    int r = vol->extmap.used - 1;
+    int m;
+    fsw_u64 vcn = (mftno << vol->mftbits) >> vol->clbits;
+    struct extent_slot *e = vol->extmap.extent;
+
+    while(l <= r) {
+       m = (l+r)/2;
+       if(vcn < e[m].vcn) {
+           r = m - 1;
+       } else if(vcn >= e[m].vcn + e[m].cnt) {
+           l = m + 1;
+       } else if(vol->mftbits <= vol->clbits) {
+           fsw_u64 lcn = e[m].lcn + (vcn - e[m].vcn);
+           int offset = (mftno << vol->mftbits) & ((1<<vol->clbits)-1);
+           fsw_u8 *buffer;
+           fsw_status_t err;
+
+           if(e[m].lcn + 1 == 0)
+               return FSW_VOLUME_CORRUPTED;
+
+           if ((err = fsw_block_get(&vol->g, lcn, 0, (void **)&buffer)) != FSW_SUCCESS)
+               return FSW_VOLUME_CORRUPTED;
+
+           fsw_memcpy(mft, buffer+offset, 1<<vol->mftbits);
+           fsw_block_release(&vol->g, lcn, buffer);
+           return fixup(mft, "FILE", 1<<vol->sctbits, 1<<vol->mftbits);
+       } else {
+           fsw_u8 *p = mft;
+           fsw_u64 lcn = e[m].lcn + (vcn - e[m].vcn);
+           fsw_u64 ecnt = e[m].cnt - (vcn - e[m].vcn);
+           int count = 1 << (vol->mftbits - vol->clbits);
+           fsw_status_t err;
+
+           if(e[m].lcn + 1 == 0)
+               return FSW_VOLUME_CORRUPTED;
+           while(count-- > 0) {
+               fsw_u8 *buffer;
+               if ((err = fsw_block_get(&vol->g, lcn, 0, (void **)&buffer)) != FSW_SUCCESS)
+                   return FSW_VOLUME_CORRUPTED;
+               fsw_memcpy(p, buffer, 1<<vol->clbits);
+               fsw_block_release(&vol->g, lcn, buffer);
+
+               p += 1<<vol->clbits;
+               ecnt--;
+               vcn++;
+               if(count==0) break;
+               if(ecnt > 0) {
+                   lcn++;
+               } else if(++m >= vol->extmap.used || e[m].vcn != vcn) {
+                   return FSW_VOLUME_CORRUPTED;
+               } else {
+                   lcn = e[m].lcn;
+                   ecnt = e[m].cnt;
+               }
+           }
+           return fixup(mft, "FILE", 1<<vol->sctbits, 1<<vol->mftbits);
+       }
+    }
+    return FSW_NOT_FOUND;
+}
+
+static void init_attr(struct fsw_ntfs_volume *vol, struct ntfs_attr *attr, int type)
+{
+    fsw_memzero(attr, sizeof(*attr));
+    attr->type = type;
+    attr->emftno = BADMFT;
+}
+
+static void free_attr(struct ntfs_attr *attr)
+{
+    if(attr->emft) FreePool(attr->emft);
+}
+
+static fsw_status_t find_attribute(struct fsw_ntfs_volume *vol, struct ntfs_mft *mft, struct ntfs_attr *attr, fsw_u64 vcn)
+{
+    fsw_u8 *buf = mft->buf;
+    if(mft->atlst && mft->atlen) {
+       fsw_status_t err;
+       fsw_u64 mftno;
+       int pos = 0;
+
+       err = find_attrlist_direct(mft->atlst, mft->atlen, attr->type, vcn, &mftno, &pos);
+       if(err != FSW_SUCCESS)
+           return err;
+
+       if(mftno == mft->mftno) {
+           buf = mft->buf;
+       } else if(mftno == attr->emftno && attr->emft) {
+           buf = attr->emft;
+       } else {
+           attr->emftno = BADMFT;
+           err = read_mft(vol, attr->emft, mftno);
+           if(err != FSW_SUCCESS)
+               return err;
+           attr->emftno = mftno;
+           buf = attr->emft;
+       }
+    }
+    return find_attribute_direct(buf, 1<<vol->mftbits, attr->type, &attr->ptr, &attr->len);
+}
+
+static fsw_status_t read_small_attribute(struct fsw_ntfs_volume *vol, struct ntfs_mft *mft, int type, fsw_u8 **optrp, int *olenp)
+{
+    fsw_status_t err;
+    struct ntfs_attr attr;
+
+    init_attr(vol, &attr, type);
+    err = find_attribute(vol, mft, &attr, 0);
+    if(err == FSW_SUCCESS)
+       err = read_attribute_direct(vol, attr.ptr, attr.len, optrp, olenp);
+    free_attr(&attr);
+    return err;
+}
+
+static void add_single_mft_map(struct fsw_ntfs_volume *vol, fsw_u8 *mft)
+{
+    fsw_u8 *ptr;
+    int len;
+
+    if(find_attribute_direct(mft, 1<<vol->mftbits, AT_DATA, &ptr, &len)!=FSW_SUCCESS)
+       return;
+
+    if(attribute_ondisk(ptr, len) == 0)
+       return;
+
+    fsw_u64 vcn = GETU64(ptr, 0x10);
+    int off = GETU16(ptr, 0x20);
+    ptr += off;
+    len -= off;
+
+    fsw_u64 pos = 0;
+    fsw_u64 lcn, cnt;
+
+    while(len > 0 && get_extent(&ptr, &len, &lcn, &cnt, &pos)==FSW_SUCCESS) {
+       if(lcn) {
+           int u = vol->extmap.used;
+           if(u >= vol->extmap.total) {
+               vol->extmap.total = vol->extmap.extent ? u*2 : 16;
+               struct extent_slot *e = AllocatePool(vol->extmap.total * sizeof(struct extent_slot));
+               if(vol->extmap.extent) {
+                   fsw_memcpy(e, vol->extmap.extent, u*sizeof(struct extent_slot));
+                   FreePool(vol->extmap.extent);
+               }
+               vol->extmap.extent = e;
+           }
+           vol->extmap.extent[u].vcn = vcn;
+           vol->extmap.extent[u].lcn = lcn;
+           vol->extmap.extent[u].cnt = cnt;
+           vol->extmap.used++;
+       }
+       vcn += cnt;
+    }
+}
+
+static void add_mft_map(struct fsw_ntfs_volume *vol, struct ntfs_mft *mft)
+{
+    load_atlist(vol, mft);
+    add_single_mft_map(vol, mft->buf);
+    if(mft->atlst == NULL) return;
+
+    fsw_u64 mftno;
+    int pos = 0;
+
+    fsw_u8 *emft = AllocatePool(1<<vol->mftbits);
+    while(find_attrlist_direct(mft->atlst, mft->atlen, AT_DATA, 0, &mftno, &pos) == FSW_SUCCESS) {
+       if(mftno == 0) continue;
+       if(read_mft(vol, emft, mftno)==FSW_SUCCESS)
+           add_single_mft_map(vol, emft);
+    }
+    FreePool(emft);
+}
+
+static int tobits(fsw_u32 val)
+{
+    return 31 - __builtin_clz(val);
+}
+
+static fsw_status_t fsw_ntfs_volume_mount(struct fsw_volume *volg)
+{
+    struct fsw_ntfs_volume *vol = (struct fsw_ntfs_volume *)volg;
+    fsw_status_t err;
+    fsw_u8 *buffer;
+    int sector_size;
+    int cluster_size;
+    signed char tmp;
+    fsw_u64 mft_start[2];
+    struct ntfs_mft mft0;
+
+    fsw_memzero((char *)vol+sizeof(*volg), sizeof(*vol)-sizeof(*volg));
+    fsw_set_blocksize(volg, 512, 512);
+    if ((err = fsw_block_get(volg, 0, 0, (void **)&buffer)) != FSW_SUCCESS)
+       return FSW_UNSUPPORTED;
+
+    if (!fsw_memeq(buffer+3, "NTFS    ", 8))
+       return FSW_UNSUPPORTED;
+
+    sector_size = GETU16(buffer, 0xB);
+    if(sector_size==0 || (sector_size & (sector_size-1)) || sector_size < 0x100 || sector_size > 0x1000)
+       return FSW_UNSUPPORTED;
+
+    vol->sctbits = tobits(sector_size);
+    vol->totalbytes = GETU64(buffer, 0x28) << vol->sctbits;
+    Print(L"NTFS size=%ld M\n", vol->totalbytes>>20);
+
+    cluster_size = GETU8(buffer, 0xD) * sector_size;
+    if(cluster_size==0 || (cluster_size & (cluster_size-1)) || cluster_size > 0x10000)
+       return FSW_UNSUPPORTED;
+
+    vol->clbits = tobits(cluster_size);
+
+    tmp = GETU8(buffer, 0x40);
+    if(tmp > 0)
+       vol->mftbits = vol->clbits + tobits(tmp);
+    else
+       vol->mftbits = -tmp;
+
+    if(vol->mftbits < vol->sctbits || vol->mftbits > 16)
+       return FSW_UNSUPPORTED;
+
+    tmp = GETU8(buffer, 0x44);
+    if(tmp > 0)
+       vol->idxbits = vol->clbits + tobits(tmp);
+    else
+       vol->idxbits = -tmp;
+
+    if(vol->idxbits < vol->sctbits || vol->idxbits > 16)
+       return FSW_UNSUPPORTED;
+
+    mft_start[0] = GETU64(buffer, 0x30);
+    mft_start[1] = GETU64(buffer, 0x38);
+
+    fsw_block_release(volg, 0, (void *)buffer);
+    fsw_set_blocksize(volg, cluster_size, cluster_size);
+
+    init_mft(vol, &mft0, MFTNO_MFT);
+    for(tmp=0; tmp<2; tmp++) {
+       fsw_u8 *ptr = mft0.buf;
+       int len = 1 << vol->mftbits;
+       fsw_u64 lcn = mft_start[tmp];
+       while(len > 0) {
+           if ((err = fsw_block_get(volg, lcn, 0, (void **)&buffer)) != FSW_SUCCESS)
+           {
+               free_mft(&mft0);
+               return FSW_UNSUPPORTED;
+           }
+           int n = vol->mftbits < vol->clbits ? (1<<vol->mftbits) : cluster_size;
+           fsw_memcpy(ptr, buffer, n);
+           fsw_block_release(volg, lcn, (void *)buffer);
+           ptr += n;
+           len -= n;
+           lcn++;
+       }
+       err = fixup(mft0.buf, "FILE", sector_size, 1<<vol->mftbits);
+       if(err != FSW_SUCCESS)
+           return err;
+    }
+
+    add_mft_map(vol, &mft0);
+
+    {
+    int i;
+    for(i=0; i<vol->extmap.used; i++)
+       Print(L"extent %d: vcn=%lx lcn=%lx len=%lx\n",
+               i,
+               vol->extmap.extent[i].vcn,
+               vol->extmap.extent[i].lcn,
+               vol->extmap.extent[i].cnt);
+    }
+
+    free_mft(&mft0);
+
+    /* load $Volume name */
+    init_mft(vol, &mft0, MFTNO_VOLUME);
+    fsw_u8 *ptr;
+    int len;
+    if(read_mft(vol, mft0.buf, MFTNO_VOLUME)==FSW_SUCCESS &&
+           find_attribute_direct(mft0.buf, 1<<vol->mftbits, AT_VOLUME_NAME, &ptr, &len)==FSW_SUCCESS &&
+           GETU8(ptr, 8)==0)
+    {
+       struct fsw_string s;
+       s.type = FSW_STRING_TYPE_UTF16_LE;
+       s.size = GETU16(ptr, 0x10);
+       s.len = s.size / 2;
+       s.data = ptr + GETU16(ptr, 0x14);
+       Print(L"Volume name [%.*ls]\n", s.len, s.data);
+       err = fsw_strdup_coerce(&volg->label, volg->host_string_type, &s);
+    }
+    free_mft(&mft0);
+
+    err = fsw_dnode_create_root(volg, MFTNO_ROOT, &volg->root);
+    if (err)
+       return err;
+
+    return FSW_SUCCESS;
+}
+
+static void fsw_ntfs_volume_free(struct fsw_volume *volg)
+{
+    struct fsw_ntfs_volume *vol = (struct fsw_ntfs_volume *)volg;
+    if(vol->extmap.extent)
+       FreePool(vol->extmap.extent);
+    if(vol->upcase && vol->upcase != upcase)
+       FreePool((void *)vol->upcase);
+}
+
+static fsw_status_t fsw_ntfs_volume_stat(struct fsw_volume *volg, struct fsw_volume_stat *sb)
+{
+    struct fsw_ntfs_volume *vol = (struct fsw_ntfs_volume *)volg;
+    sb->total_bytes = vol->totalbytes;
+    /* reading through cluster bitmap is too costly */
+    sb->free_bytes  = 0;
+    return FSW_SUCCESS;
+}
+
+static fsw_status_t fsw_ntfs_dnode_fill(struct fsw_volume *volg, struct fsw_dnode *dnog)
+{
+    struct fsw_ntfs_volume *vol = (struct fsw_ntfs_volume *)volg;
+    struct fsw_ntfs_dnode *dno = (struct fsw_ntfs_dnode *)dnog;
+    fsw_status_t err;
+    int len;
+
+    fsw_memzero((char *)dno+sizeof(*dnog), sizeof(*dno)-sizeof(*dnog));
+    init_mft(vol, &dno->mft, dno->g.dnode_id);
+    err = read_mft(vol, dno->mft.buf, dno->g.dnode_id);
+    if(err != FSW_SUCCESS)
+       return err;
+
+    len = GETU8(dno->mft.buf, 22);
+    if( (len & 1) == 0 )
+       return FSW_NOT_FOUND;
+
+    load_atlist(vol, &dno->mft);
+
+    if(read_small_attribute(vol, &dno->mft, AT_REPARSE_POINT, &dno->cbuf, &len)==FSW_SUCCESS) {
+       switch(GETU32(dno->cbuf, 0)) {
+           case 0xa0000003:
+           case 0xa000000c:
+               dno->g.size = len;
+               dno->g.type = FSW_DNODE_TYPE_SYMLINK;
+               dno->islink = 1;
+               dno->fsize = len;
+               return FSW_SUCCESS;
+           default:
+               FreePool(dno->cbuf);
+               dno->cbuf = NULL;
+       };
+    }
+
+    if( (len & 2) ) {
+       dno->g.type = FSW_DNODE_TYPE_DIR;
+       /* $INDEX_ROOT:$I30 must present */
+       err = read_small_attribute(vol, &dno->mft, AT_INDEX_ROOT|AT_I30, &dno->idxroot, &dno->rootsz);
+       if(err != FSW_SUCCESS)
+       {
+           Print(L"dno_fill INDEX_ROOT:$I30 error %d\n", err);
+           return err;
+       }
+
+       dno->idxsz = GETU32(dno->idxroot, 8);
+       if(dno->idxsz == 0)
+           dno->idxsz = 1<<vol->idxbits;
+
+       /* $Bitmap:$I30 is optional */
+       err = read_small_attribute(vol, &dno->mft, AT_BITMAP|AT_I30, &dno->idxbmp, &dno->bmpsz);
+       if(err != FSW_SUCCESS && err != FSW_NOT_FOUND)
+       {
+           Print(L"dno_fill $Bitmap:$I30 error %d\n", err);
+           return err;
+       }
+
+       /* $INDEX_ALLOCATION:$I30 is optional */
+       init_attr(vol, &dno->attr, AT_INDEX_ALLOCATION|AT_I30);
+       err = find_attribute(vol, &dno->mft, &dno->attr, 0);
+       if(err == FSW_SUCCESS) {
+           dno->has_idxtree = 1;
+           dno->fsize = attribute_size(dno->attr.ptr, dno->attr.len);
+           dno->finited = dno->fsize;
+       } else if(err != FSW_NOT_FOUND) {
+           Print(L"dno_fill $INDEX_ALLOCATION:$I30 error %d\n", err);
+           return err;
+       }
+
+    } else {
+       dno->g.type = FSW_DNODE_TYPE_FILE;
+       init_attr(vol, &dno->attr, AT_DATA);
+       err = find_attribute(vol, &dno->mft, &dno->attr, 0);
+       if(err != FSW_SUCCESS)
+       {
+           Print(L"dno_fill AT_DATA error %d\n", err);
+           return err;
+       }
+       dno->embeded = !attribute_ondisk(dno->attr.ptr, dno->attr.len);
+       dno->fsize = attribute_size(dno->attr.ptr, dno->attr.len);
+       dno->finited = attribute_inited_size(dno->attr.ptr, dno->attr.len);
+       if(attribute_encrypted(dno->attr.ptr, dno->attr.len))
+           dno->unreadable = 1;
+       else if(attribute_compressed_future(dno->attr.ptr, dno->attr.len))
+           dno->unreadable = 1;
+       else if(attribute_compressed(dno->attr.ptr, dno->attr.len))
+           dno->compressed = 1;
+       dno->cvcn = BADVCN;
+       dno->g.size = dno->fsize;
+    }
+    return FSW_SUCCESS;
+}
+
+static void fsw_ntfs_dnode_free(struct fsw_volume *vol, struct fsw_dnode *dnog)
+{
+    struct fsw_ntfs_dnode *dno = (struct fsw_ntfs_dnode *)dnog;
+    free_mft(&dno->mft);
+    free_attr(&dno->attr);
+    if(dno->idxroot)
+       FreePool(dno->idxroot);
+    if(dno->idxbmp)
+       FreePool(dno->idxbmp);
+    if(dno->cbuf)
+       FreePool(dno->cbuf);
+}
+
+static fsw_u32 get_ntfs_time(fsw_u8 *buf, int pos)
+{
+    fsw_u64 t = GETU64(buf, pos);
+    t = FSW_U64_DIV(t, 10000000);
+    t -= 134774ULL * 86400;
+    return t;
+}
+
+static fsw_status_t fsw_ntfs_dnode_stat(struct fsw_volume *volg, struct fsw_dnode *dnog, struct fsw_dnode_stat *sb)
+{
+    struct fsw_ntfs_volume *vol = (struct fsw_ntfs_volume *)volg;
+    struct fsw_ntfs_dnode *dno = (struct fsw_ntfs_dnode *)dnog;
+    fsw_status_t err;
+    fsw_u16 attr;
+    fsw_u8 *ptr;
+    int len;
+
+    err = find_attribute_direct(dno->mft.buf, 1<<vol->mftbits, AT_STANDARD_INFORMATION, &ptr, &len);
+
+    if(err != FSW_SUCCESS || GETU8(ptr, 8))
+       return err;
+
+    ptr += GETU16(ptr, 0x14);
+    attr = GETU8(ptr, 0x20); /* only lower 8 of 32 bit is used */
+    attr &= EFI_FILE_READ_ONLY | EFI_FILE_HIDDEN | EFI_FILE_SYSTEM | EFI_FILE_ARCHIVE;
+    /* add DIR again if symlink */
+    if(GETU8(dno->mft.buf, 22) & 2)
+       attr |= EFI_FILE_DIRECTORY;
+
+    fsw_store_attr_efi(sb, attr);
+    sb->used_bytes = dno->fsize;
+    fsw_store_time_posix(sb, FSW_DNODE_STAT_ATIME, get_ntfs_time(ptr, 24));
+    fsw_store_time_posix(sb, FSW_DNODE_STAT_CTIME, get_ntfs_time(ptr, 8));
+    fsw_store_time_posix(sb, FSW_DNODE_STAT_MTIME, get_ntfs_time(ptr, 16));
+
+    return FSW_SUCCESS;
+}
+
+static fsw_status_t fsw_ntfs_dnode_get_lcn(struct fsw_ntfs_volume *vol, struct fsw_ntfs_dnode *dno, fsw_u64 vcn, fsw_u64 *lcnp)
+{
+    fsw_status_t err;
+    if(vcn >= dno->cext.vcn && vcn < dno->cext.vcn+dno->cext.cnt) {
+       *lcnp = dno->cext.lcn + vcn - dno->cext.vcn;
+       return FSW_SUCCESS;
+    }
+    if(!attribute_has_vcn(dno->attr.ptr, dno->attr.len, vcn)) {
+       err = find_attribute(vol, &dno->mft, &dno->attr, vcn);
+       if( err != FSW_SUCCESS )
+           return err;
+       if(!attribute_has_vcn(dno->attr.ptr, dno->attr.len, vcn))
+           return FSW_VOLUME_CORRUPTED;
+    }
+    fsw_u8 *ptr = dno->attr.ptr;
+    int len = dno->attr.len;
+    fsw_u64 pos = 0;
+    fsw_u64 lcn, cnt;
+    fsw_u64 svcn = attribute_first_vcn(ptr, len);
+    fsw_u64 evcn = attribute_last_vcn(ptr, len) + 1;
+    int off = GETU16(ptr, 0x20);
+    ptr += off;
+    len -= off;
+    while(len > 0 && get_extent(&ptr, &len, &lcn, &cnt, &pos)==FSW_SUCCESS) {
+       if(vcn >= svcn && vcn < svcn+cnt) {
+           dno->cext.vcn = svcn;
+           dno->cext.lcn = lcn;
+           dno->cext.cnt = cnt;
+           if(lcn == 0)
+               return FSW_NOT_FOUND;
+           *lcnp = lcn + vcn - svcn;
+           return FSW_SUCCESS;
+       }
+       svcn += cnt;
+       if(svcn >= evcn)
+           break;
+    }
+    return FSW_NOT_FOUND;
+}
+
+static int fsw_ntfs_read_buffer(struct fsw_ntfs_volume *vol, struct fsw_ntfs_dnode *dno, fsw_u8 *buf, fsw_u64 offset, int size)
+{
+    if(dno->embeded) {
+       fsw_u8 *ptr;
+       int len;
+       attribute_get_embeded(dno->attr.ptr, dno->attr.len, &ptr, &len);
+       if(size > len)
+           size = len;
+       fsw_memcpy(buf, ptr, size);
+       return size;
+    }
+
+    if(!dno->attr.ptr || !dno->attr.len) {
+       Print(L"BAD--------: attr.ptr %p attr.len %x cleared\n", dno->attr.ptr, dno->attr.len);
+       if(find_attribute(vol, &dno->mft, &dno->attr, 0) != FSW_SUCCESS)
+           return 0;
+    }
+
+    if(offset >= dno->fsize)
+       return 0;
+    if(offset + size >= dno->fsize)
+       size = dno->fsize - offset;
+
+    if(offset >= dno->finited) {
+       fsw_memzero(buf, size);
+       return size;
+    }
+
+    int ret = 0;
+    int zsize = 0;
+    if(offset + size >= dno->finited) {
+       zsize = offset + size - dno->finited;
+       size = dno->finited - offset;
+    }
+
+    fsw_u64 vcn = offset >> vol->clbits;
+    int boff = offset & ((1<<vol->clbits)-1);
+    fsw_u64 lcn = 0;
+
+    while(size > 0) {
+       fsw_u8 *block;
+       fsw_status_t err;
+       int bsz;
+
+       err = fsw_ntfs_dnode_get_lcn(vol, dno, vcn, &lcn);
+       if (err != FSW_SUCCESS) break;
+
+       err = fsw_block_get(&vol->g, lcn, 0, (void **)&block);
+       if (err != FSW_SUCCESS) break;
+
+       bsz = (1<<vol->clbits) - boff;
+       if(bsz > size)
+           bsz = size;
+
+       fsw_memcpy(buf, block+boff, bsz);
+       fsw_block_release(&vol->g, lcn, block);
+
+       ret += bsz;
+       buf += bsz;
+       size -= bsz;
+       boff = 0;
+    }
+    if(size==0 && zsize > 0) {
+       fsw_memzero(buf, zsize);
+       ret += zsize;
+    }
+    return ret;
+}
+
+static fsw_status_t fsw_ntfs_get_extent_embeded(struct fsw_ntfs_volume *vol, struct fsw_ntfs_dnode *dno, struct fsw_extent *extent)
+{
+    if(extent->log_start > 0)
+       return FSW_NOT_FOUND;
+    extent->log_count = 1;
+    extent->buffer = AllocatePool(1<<vol->clbits);
+    fsw_u8 *ptr;
+    int len;
+    attribute_get_embeded(dno->attr.ptr, dno->attr.len, &ptr, &len);
+    if(len > (1<<vol->clbits))
+       len = 1<<vol->clbits;
+    fsw_memcpy(extent->buffer, ptr, len);
+    extent->type = FSW_EXTENT_TYPE_BUFFER;
+    return FSW_SUCCESS;
+}
+
+static int ntfs_decomp_1page(fsw_u8 *src, int slen, fsw_u8 *dst) {
+    int soff = 0;
+    int doff = 0;
+    while(soff < slen) {
+       int j;
+       int tag = src[soff++];
+       for(j = 0; j < 8 && soff < slen; j++) {
+           if(tag & (1<<j)){
+               int len;
+               int back;
+               int bits;
+
+               if(!doff || soff + 2 > slen)
+                   return -1;
+               len = GETU16(src, soff); soff += 2;
+               bits = __builtin_clz((doff-1)>>3)-19;
+               back = (len >> bits) + 1;
+               len = (len & ((1<<bits)-1)) + 3;
+               if(doff < back || doff + len > 0x1000)
+                   return -1;
+               while(len-- > 0) {
+                   dst[doff] = dst[doff-back];
+                   doff++;
+               }
+           } else {
+               if(doff >= 0x1000)
+                   return -1;
+               dst[doff++] = src[soff++];
+           }
+       }
+    }
+    return doff;
+}
+
+static int ntfs_decomp(fsw_u8 *src, int slen, fsw_u8 *dst, int npage) {
+    fsw_u8 *se = src + slen;
+    fsw_u8 *de = dst + (npage<<12);
+    int i;
+    for(i=0; i<npage; i++) {
+       fsw_u16 slen = GETU16(src, 0);
+       int comp = slen & 0x8000;
+       slen = (slen&0xfff)+1;
+       src += 2;
+
+       if(src + slen > se || dst + 0x1000 > de)
+           return -1;
+
+       if(!comp) {
+           fsw_memcpy(dst, src, slen);
+           if(slen < 0x1000)
+               fsw_memzero(dst+slen, 0x1000-slen);
+       } else if(slen == 1) {
+           fsw_memzero(dst, 0x1000);
+       } else {
+           int dlen = ntfs_decomp_1page(src, slen, dst);
+           if(dlen < 0)
+               return -1;
+           if(dlen < 0x1000)
+               fsw_memzero(dst+dlen, 0x1000-dlen);
+       }
+       src += slen;
+       dst += 0x1000;
+    }
+    return 0;
+}
+
+static fsw_status_t fsw_ntfs_get_extent_compressed(struct fsw_ntfs_volume *vol, struct fsw_ntfs_dnode *dno, struct fsw_extent *extent)
+{
+    if(vol->clbits > 16)
+       return FSW_VOLUME_CORRUPTED;
+
+    if((extent->log_start << vol->clbits) > dno->fsize)
+       return FSW_NOT_FOUND;
+
+    int i;
+    fsw_u64 vcn = extent->log_start & ~15;
+
+    if(vcn == dno->cvcn)
+       goto hit;
+    dno->cvcn = vcn;
+    dno->cperror = 0;
+    dno->cpfull = 0;
+    dno->cpzero = 0;
+
+    for(i=0; i<16; i++) {
+       fsw_status_t err;
+       err = fsw_ntfs_dnode_get_lcn(vol, dno, vcn+i, &dno->clcn[i]);
+       if(err == FSW_NOT_FOUND) {
+           break;
+       } else if(err != FSW_SUCCESS) {
+           Print(L"BAD LCN\n");
+           dno->cperror = 1;
+           return FSW_VOLUME_CORRUPTED;
+       }
+    }
+    if(i == 0)
+       dno->cpzero = 1;
+    else if(i==16)
+       dno->cpfull = 1;
+    else {
+       if(dno->cbuf == NULL)
+           dno->cbuf = AllocatePool(16<<vol->clbits);
+       fsw_u8 *src = AllocatePool(i << vol->clbits);
+       int b;
+       for(b=0; b<i; b++) {
+           char *block;
+           if (fsw_block_get(&vol->g, dno->clcn[b], 0, (void **)&block) != FSW_SUCCESS) {
+               dno->cperror = 1;
+               Print(L"Read ERROR at block %d\n", i);
+               break;
+           }
+           fsw_memcpy(src+(b<<vol->clbits), block, 1<<vol->clbits);
+           fsw_block_release(&vol->g, dno->clcn[b], block);
+       }
+
+       if(dno->fsize >= ((vcn+16)<<vol->clbits))
+           b = 16<<vol->clbits>>12;
+       else
+           b = (dno->fsize - (vcn << vol->clbits) + 0xfff)>>12;
+       if(!dno->cperror && ntfs_decomp(src, i<<vol->clbits, dno->cbuf, b) < 0)
+           dno->cperror = 1;
+       FreePool(src);
+    }
+hit:
+    if(dno->cperror)
+       return FSW_VOLUME_CORRUPTED;
+    i = extent->log_start - vcn;
+    if(dno->cpfull) {
+       fsw_u64 lcn = dno->clcn[i];
+       extent->phys_start = lcn;
+       extent->log_count = 1;
+       extent->type = FSW_EXTENT_TYPE_PHYSBLOCK;
+       for(i++, lcn++; i<16 && lcn==dno->clcn[i]; i++, lcn++)
+               extent->log_count++;
+    } else if(dno->cpzero) {
+       extent->log_count = 16 - i;
+       extent->buffer = NULL;
+       extent->type = FSW_EXTENT_TYPE_SPARSE;
+    } else {
+       extent->log_count = 1;
+       extent->buffer = AllocatePool(1<<vol->clbits);
+       fsw_memcpy(extent->buffer, dno->cbuf + (i<<vol->clbits), 1<<vol->clbits);
+       extent->type = FSW_EXTENT_TYPE_BUFFER;
+    }
+    return FSW_SUCCESS;
+}
+
+static fsw_status_t fsw_ntfs_get_extent_sparse(struct fsw_ntfs_volume *vol, struct fsw_ntfs_dnode *dno, struct fsw_extent *extent)
+{
+    fsw_status_t err;
+
+    if((extent->log_start << vol->clbits) > dno->fsize)
+       return FSW_NOT_FOUND;
+    if((extent->log_start << vol->clbits) > dno->finited)
+    {
+       extent->log_count = 1;
+       extent->buffer = NULL;
+       extent->type = FSW_EXTENT_TYPE_SPARSE;
+       return FSW_SUCCESS;
+    }
+    fsw_u64 lcn;
+    err = fsw_ntfs_dnode_get_lcn(vol, dno, extent->log_start, &lcn);
+    if(err == FSW_NOT_FOUND) {
+       extent->log_count = 1;
+       extent->buffer = NULL;
+       extent->type = FSW_EXTENT_TYPE_SPARSE;
+       return FSW_SUCCESS;
+    }
+    if(err != FSW_SUCCESS)
+       return err;
+    extent->phys_start = lcn;
+    extent->log_count = 1;
+    if(extent->log_start >= dno->cext.vcn && extent->log_start < dno->cext.vcn+dno->cext.cnt)
+       extent->log_count = dno->cext.cnt + extent->log_start - dno->cext.vcn;
+    extent->type = FSW_EXTENT_TYPE_PHYSBLOCK;
+    return FSW_SUCCESS;
+}
+
+static fsw_status_t fsw_ntfs_get_extent(struct fsw_volume *volg, struct fsw_dnode *dnog, struct fsw_extent *extent)
+{
+    struct fsw_ntfs_volume *vol = (struct fsw_ntfs_volume *)volg;
+    struct fsw_ntfs_dnode *dno = (struct fsw_ntfs_dnode *)dnog;
+
+    if(dno->unreadable)
+       return FSW_UNSUPPORTED;
+    if(dno->embeded)
+       return fsw_ntfs_get_extent_embeded(vol, dno, extent);
+    if(dno->compressed)
+       return fsw_ntfs_get_extent_compressed(vol, dno, extent);
+    return fsw_ntfs_get_extent_sparse(vol, dno, extent);
+}
+
+static fsw_status_t load_upcase(struct fsw_ntfs_volume *vol)
+{
+    fsw_status_t err;
+    struct ntfs_mft mft;
+    init_mft(vol, &mft, MFTNO_UPCASE);
+    err = read_mft(vol, mft.buf, MFTNO_UPCASE);
+    if(err == FSW_SUCCESS) {
+       if((err = read_small_attribute(vol, &mft, AT_DATA, (fsw_u8 **)&vol->upcase, &vol->upcount))==FSW_SUCCESS) {
+           vol->upcount /= 2;
+#ifndef FSW_LITTLE_ENDIAN
+           int i;
+           for( i=0; i<vol->upcount; i++)
+               vol->upcase[i] = fsw_u16_le_swap(vol->upcase[i]);
+#endif
+       }
+    }
+    free_mft(&mft);
+    return err;
+}
+
+static int ntfs_filename_cmp(struct fsw_ntfs_volume *vol, fsw_u8 *p1, int s1, fsw_u8 *p2, int s2)
+{
+    while(s1 > 0 && s2 > 0) {
+       fsw_u16 c1 = GETU16(p1,0);
+       fsw_u16 c2 = GETU16(p2,0);
+       if(c1 < 0x80 || c2 < 0x80) {
+           if(c1 < 0x80) c1 = upcase[c1];
+           if(c2 < 0x80) c2 = upcase[c2];
+       } else {
+           /*
+            * Only load upcase table if both char is international.
+            * We assume international char never upcased to ASCII.
+            */
+           if(!vol->upcase) {
+               load_upcase(vol);
+               if(!vol->upcase) {
+                   /* use raw value & prevent load again */
+                   vol->upcase = upcase;
+                   vol->upcount = 0;
+               }
+           }
+           if(c1 < vol->upcount) c1 = vol->upcase[c1];
+           if(c2 < vol->upcount) c2 = vol->upcase[c2];
+       }
+       if(c1 < c2)
+           return -1;
+       if(c1 > c2)
+           return 1;
+       p1+=2;
+       p2+=2;
+       s1--;
+       s2--;
+    }
+    if(s1 < s2)
+       return -1;
+    if(s1 > s2)
+       return 1;
+    return 0;
+}
+
+static fsw_status_t fsw_ntfs_create_subnode(struct fsw_ntfs_dnode *dno, fsw_u8 *buf, struct fsw_dnode **child_dno)
+{
+    fsw_u64 mftno = GETU64(buf, 0) & MFTMASK;
+    if(mftno < MFTNO_META)
+       return FSW_NOT_FOUND;
+
+    int type = GETU32(buf, 0x48) & 0x10000000 ? FSW_DNODE_TYPE_DIR: FSW_DNODE_TYPE_FILE;
+    struct fsw_string s;
+    s.type = FSW_STRING_TYPE_UTF16_LE;
+    s.len = GETU8(buf, 0x50);
+    s.size = s.len * 2;
+    s.data = buf + 0x52;
+
+    return fsw_dnode_create(&dno->g, mftno, type, &s, child_dno);
+}
+
+static fsw_u8 *fsw_ntfs_read_index_block(struct fsw_ntfs_volume *vol, struct fsw_ntfs_dnode *dno, fsw_u64 block)
+{
+    if(dno->cbuf==NULL)
+       dno->cbuf = AllocatePool(dno->idxsz);
+    else if(block == dno->cvcn)
+       return dno->cbuf;
+
+    dno->cvcn = 0;
+    if(fsw_ntfs_read_buffer(vol, dno, dno->cbuf, (block-1)*dno->idxsz, dno->idxsz) != dno->idxsz)
+       return NULL;
+    if(fixup(dno->cbuf, "INDX", 1<<vol->sctbits, dno->idxsz) != FSW_SUCCESS)
+       return NULL;
+
+    dno->cvcn = block;
+    return dno->cbuf;
+}
+
+static fsw_status_t fsw_ntfs_dir_lookup(struct fsw_volume *volg, struct fsw_dnode *dnog, struct fsw_string *lookup_name, struct fsw_dnode **child_dno)
+{
+    struct fsw_ntfs_volume *vol = (struct fsw_ntfs_volume *)volg;
+    struct fsw_ntfs_dnode *dno = (struct fsw_ntfs_dnode *)dnog;
+    int depth = 0;
+    struct fsw_string s;
+    fsw_u8 *buf;
+    int len;
+    int off;
+    fsw_status_t err;
+    fsw_u64 block;
+
+    *child_dno = NULL;
+    err = fsw_strdup_coerce(&s, FSW_STRING_TYPE_UTF16_LE, lookup_name);
+    if(err)
+       return err;
+
+    /* start from AT_INDEX_ROOT */
+    buf = dno->idxroot + 16;
+    len = dno->rootsz - 16;
+    if(len < 0x18)
+       goto notfound;
+
+    while(depth < 10) {
+       /* real index size */
+       if(GETU32(buf, 4) < len)
+           len = GETU32(buf, 4);
+
+       /* skip index header */
+       off = GETU32(buf, 0);
+       if(off >= len)
+           goto notfound;
+
+       block = 0;
+       while(off + 0x18 <= len) {
+           int flag = GETU8(buf, off+12);
+           int next = off + GETU16(buf, off+8);
+           int cmp;
+
+           if(flag & 2) {
+               /* the end of index entry */
+               cmp = -1;
+               Print(L"depth %d len %x off %x flag %x next %x cmp %d\n", depth, len, off, flag, next, cmp);
+           } else {
+               int nlen = GETU8(buf, off+0x50);
+               fsw_u8 *name = buf+off+0x52;
+               cmp = ntfs_filename_cmp(vol, s.data, s.len, name, nlen);
+               Print(L"depth %d len %x off %x flag %x next %x cmp %d name %d[%.*ls]\n", depth, len, off, flag, next, cmp, nlen, nlen, name);
+           }
+
+           if(cmp == 0) {
+               fsw_strfree(&s);
+               return fsw_ntfs_create_subnode(dno, buf+off, child_dno);
+           } else if(cmp < 0) {
+               if(!(flag & 1) || !dno->has_idxtree)
+                   goto notfound;
+               block = GETU64(buf, next-8) + 1;
+               break;
+           } else { /* cmp > 0 */
+               off = next;
+           }
+       }
+       if(!block)
+           break;
+
+       if(!(buf = fsw_ntfs_read_index_block(vol, dno, block)))
+           break;
+       buf += 24;
+       len = dno->idxsz - 24;
+       depth++;
+    }
+
+notfound:
+    fsw_strfree(&s);
+    return FSW_NOT_FOUND;
+}
+
+static inline void set_shand_pos( struct fsw_shandle *shand, int block, int off)
+{
+    shand->pos = (((fsw_u64)block) << 32) + off;
+}
+
+static inline int test_idxbmp(struct fsw_ntfs_dnode *dno, int block)
+{
+    int mask;
+    if(dno->idxbmp==NULL)
+       return 1;
+    block--;
+    mask = 1 << (block & 7);
+    block >>= 3;
+    if(block > dno->bmpsz)
+       return 0;
+    return dno->idxbmp[block] & mask;
+}
+
+#define shand_pos(x,y) (((fsw_u64)(x)<<32)|(y))
+static fsw_status_t fsw_ntfs_dir_read(struct fsw_volume *volg, struct fsw_dnode *dnog, struct fsw_shandle *shand, struct fsw_dnode **child_dno)
+{
+    struct fsw_ntfs_volume *vol = (struct fsw_ntfs_volume *)volg;
+    struct fsw_ntfs_dnode *dno = (struct fsw_ntfs_dnode *)dnog;
+    /*
+     * high 32 bit: index block#
+     *                 0 --> index root
+     *                 >0 --> vcn+1
+     * low 32 bit: index offset
+     */
+    int off = shand->pos & 0xFFFFFFFF;
+    int block = shand->pos >> 32;
+    int mblocks;
+
+    mblocks = FSW_U64_DIV(dno->fsize, dno->idxsz);
+
+    while(block <= mblocks) {
+       fsw_u8 *buf;
+       int len;
+       if(block == 0) {
+           /* AT_INDEX_ROOT */
+           buf = dno->idxroot + 16;
+           len = dno->rootsz - 16;
+           if(len < 0x18)
+               goto miss;
+       } else if(!test_idxbmp(dno, block) || !(buf = fsw_ntfs_read_index_block(vol, dno, block)))
+       {
+           /* unused or bad index block */
+           goto miss;
+       } else {
+           /* AT_INDEX_ALLOCATION block */
+           buf += 24;
+           len = dno->idxsz - 24;
+       }
+       if(GETU32(buf, 4) < len)
+           len = GETU32(buf, 4);
+       if(off == 0)
+           off = GETU32(buf, 0);
+       Print(L"block %d len %x off %x\n", block, len, off);
+       while(off + 0x18 <= len) {
+           int flag = GETU8(buf, off+12);
+           if(flag & 2) break;
+           int next = off + GETU16(buf, off+8);
+           Print(L"flag %x next %x nt %x [%.*ls]\n", flag, next, GETU8(buf, off+0x51), GETU8(buf, off+0x50), buf+off+0x52);
+           if((GETU8(buf, off+0x51) != 2)) {
+               /* LONG FILE NAME */
+               fsw_status_t err = fsw_ntfs_create_subnode(dno, buf+off, child_dno);
+               if(err != FSW_NOT_FOUND) {
+                   set_shand_pos(shand, block, next);
+                   return err;
+               }
+               // skip internal MFT record
+           }
+           off = next;
+       }
+miss:
+       if(!dno->has_idxtree)
+           break;
+       block++;
+       off = 0;
+    }
+    set_shand_pos(shand, mblocks+1, 0);
+    return FSW_NOT_FOUND;
+}
+
+static fsw_status_t fsw_ntfs_readlink(struct fsw_volume *volg, struct fsw_dnode *dnog, struct fsw_string *link)
+{
+    struct fsw_ntfs_dnode *dno = (struct fsw_ntfs_dnode *)dnog;
+    fsw_u8 *name;
+    int i;
+    int len;
+
+    if(!dno->islink)
+       return FSW_UNSUPPORTED;
+
+    name = dno->cbuf + 0x10 + GETU16(dno->cbuf, 8);
+    len = GETU16(dno->cbuf, 10);
+    if(GETU32(dno->cbuf, 0) == 0xa000000c)
+       name += 4;
+
+    for(i=0; i<len; i+=2)
+       if(GETU16(name, i)=='\\')
+           *(fsw_u16 *)(name+i) = fsw_u16_le_swap('/');
+
+    if(len > 6 && GETU16(name,0)=='/' && GETU16(name,2)=='?' &&
+           GETU16(name,4)=='?' && GETU16(name,6)=='/' &&
+           GETU16(name,10)==':' && GETU16(name,12)=='/' &&
+           (GETU16(name,8)|0x20)>='a' && (GETU16(name,8)|0x20)<='z')
+    {
+       len -= 12;
+       name += 12;
+    }
+    struct fsw_string s;
+    s.type = FSW_STRING_TYPE_UTF16_LE;
+    s.size = len;
+    s.len = len/2;
+    s.data = name;
+    return fsw_strdup_coerce(link, volg->host_string_type, &s);
+}
+
+//
+// Dispatch Table
+//
+
+struct fsw_fstype_table   FSW_FSTYPE_TABLE_NAME(ntfs) = {
+    { FSW_STRING_TYPE_UTF8, 4, 4, "ntfs" },
+    sizeof(struct fsw_ntfs_volume),
+    sizeof(struct fsw_ntfs_dnode),
+
+    fsw_ntfs_volume_mount,
+    fsw_ntfs_volume_free,
+    fsw_ntfs_volume_stat,
+    fsw_ntfs_dnode_fill,
+    fsw_ntfs_dnode_free,
+    fsw_ntfs_dnode_stat,
+    fsw_ntfs_get_extent,
+    fsw_ntfs_dir_lookup,
+    fsw_ntfs_dir_read,
+    fsw_ntfs_readlink,
+};
+
+// EOF
diff --git a/filesystems/fsw_reiserfs.c b/filesystems/fsw_reiserfs.c
new file mode 100644 (file)
index 0000000..79978e5
--- /dev/null
@@ -0,0 +1,872 @@
+/**
+ * \file fsw_reiserfs.c
+ * ReiserFS file system driver code.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include "fsw_reiserfs.h"
+
+
+// functions
+
+static fsw_status_t fsw_reiserfs_volume_mount(struct fsw_reiserfs_volume *vol);
+static void         fsw_reiserfs_volume_free(struct fsw_reiserfs_volume *vol);
+static fsw_status_t fsw_reiserfs_volume_stat(struct fsw_reiserfs_volume *vol, struct fsw_volume_stat *sb);
+
+static fsw_status_t fsw_reiserfs_dnode_fill(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno);
+static void         fsw_reiserfs_dnode_free(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno);
+static fsw_status_t fsw_reiserfs_dnode_stat(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno,
+                                        struct fsw_dnode_stat *sb);
+static fsw_status_t fsw_reiserfs_get_extent(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno,
+                                        struct fsw_extent *extent);
+
+static fsw_status_t fsw_reiserfs_dir_lookup(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno,
+                                        struct fsw_string *lookup_name, struct fsw_reiserfs_dnode **child_dno);
+static fsw_status_t fsw_reiserfs_dir_read(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno,
+                                      struct fsw_shandle *shand, struct fsw_reiserfs_dnode **child_dno);
+
+static fsw_status_t fsw_reiserfs_readlink(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno,
+                                      struct fsw_string *link);
+
+static fsw_status_t fsw_reiserfs_item_search(struct fsw_reiserfs_volume *vol,
+                                             fsw_u32 dir_id, fsw_u32 objectid, fsw_u64 offset,
+                                             struct fsw_reiserfs_item *item);
+static fsw_status_t fsw_reiserfs_item_next(struct fsw_reiserfs_volume *vol,
+                                           struct fsw_reiserfs_item *item);
+static void fsw_reiserfs_item_release(struct fsw_reiserfs_volume *vol,
+                                      struct fsw_reiserfs_item *item);
+
+//
+// Dispatch Table
+//
+
+struct fsw_fstype_table   FSW_FSTYPE_TABLE_NAME(reiserfs) = {
+    { FSW_STRING_TYPE_ISO88591, 8, 8, "reiserfs" },
+    sizeof(struct fsw_reiserfs_volume),
+    sizeof(struct fsw_reiserfs_dnode),
+
+    fsw_reiserfs_volume_mount,
+    fsw_reiserfs_volume_free,
+    fsw_reiserfs_volume_stat,
+    fsw_reiserfs_dnode_fill,
+    fsw_reiserfs_dnode_free,
+    fsw_reiserfs_dnode_stat,
+    fsw_reiserfs_get_extent,
+    fsw_reiserfs_dir_lookup,
+    fsw_reiserfs_dir_read,
+    fsw_reiserfs_readlink,
+};
+
+// misc data
+
+static fsw_u32  superblock_offsets[3] = {
+    REISERFS_DISK_OFFSET_IN_BYTES     >> REISERFS_SUPERBLOCK_BLOCKSIZEBITS,
+    REISERFS_OLD_DISK_OFFSET_IN_BYTES >> REISERFS_SUPERBLOCK_BLOCKSIZEBITS,
+    0
+};
+
+/**
+ * Mount an reiserfs volume. Reads the superblock and constructs the
+ * root directory dnode.
+ */
+
+static fsw_status_t fsw_reiserfs_volume_mount(struct fsw_reiserfs_volume *vol)
+{
+    fsw_status_t    status;
+    void            *buffer;
+    fsw_u32         blocksize;
+    int             i;
+    struct fsw_string s;
+
+    // allocate memory to keep the superblock around
+    status = fsw_alloc(sizeof(struct reiserfs_super_block), &vol->sb);
+    if (status)
+        return status;
+
+    // read the superblock into its buffer
+    fsw_set_blocksize(vol, REISERFS_SUPERBLOCK_BLOCKSIZE, REISERFS_SUPERBLOCK_BLOCKSIZE);
+    for (i = 0; superblock_offsets[i]; i++) {
+        status = fsw_block_get(vol, superblock_offsets[i], 0, &buffer);
+        if (status)
+            return status;
+        fsw_memcpy(vol->sb, buffer, sizeof(struct reiserfs_super_block));
+        fsw_block_release(vol, superblock_offsets[i], buffer);
+
+        // check for one of the magic strings
+        if (fsw_memeq(vol->sb->s_v1.s_magic,
+                      REISERFS_SUPER_MAGIC_STRING, 8)) {
+            vol->version = REISERFS_VERSION_1;
+            break;
+        } else if (fsw_memeq(vol->sb->s_v1.s_magic,
+                             REISER2FS_SUPER_MAGIC_STRING, 9)) {
+            vol->version = REISERFS_VERSION_2;
+            break;
+        } else if (fsw_memeq(vol->sb->s_v1.s_magic,
+                             REISER2FS_JR_SUPER_MAGIC_STRING, 9)) {
+            vol->version = vol->sb->s_v1.s_version;
+            if (vol->version == REISERFS_VERSION_1 || vol->version == REISERFS_VERSION_2)
+                break;
+        }
+    }
+    if (superblock_offsets[i] == 0)
+        return FSW_UNSUPPORTED;
+
+    // check the superblock
+    if (vol->sb->s_v1.s_root_block == -1)   // unfinished 'reiserfsck --rebuild-tree'
+        return FSW_VOLUME_CORRUPTED;
+
+    /*
+    if (vol->sb->s_rev_level != EXT2_GOOD_OLD_REV &&
+        vol->sb->s_rev_level != EXT2_DYNAMIC_REV)
+        return FSW_UNSUPPORTED;
+    if (vol->sb->s_rev_level == EXT2_DYNAMIC_REV &&
+        (vol->sb->s_feature_incompat & ~(EXT2_FEATURE_INCOMPAT_FILETYPE | EXT3_FEATURE_INCOMPAT_RECOVER)))
+        return FSW_UNSUPPORTED;
+    */
+
+    // set real blocksize
+    blocksize = vol->sb->s_v1.s_blocksize;
+    fsw_set_blocksize(vol, blocksize, blocksize);
+
+    // get other info from superblock
+    /*
+    vol->ind_bcnt = EXT2_ADDR_PER_BLOCK(vol->sb);
+    vol->dind_bcnt = vol->ind_bcnt * vol->ind_bcnt;
+    vol->inode_size = EXT2_INODE_SIZE(vol->sb);
+    */
+
+    for (i = 0; i < 16; i++)
+        if (vol->sb->s_label[i] == 0)
+            break;
+    s.type = FSW_STRING_TYPE_ISO88591;
+    s.size = s.len = i;
+    s.data = vol->sb->s_label;
+    status = fsw_strdup_coerce(&vol->g.label, vol->g.host_string_type, &s);
+    if (status)
+        return status;
+
+    // setup the root dnode
+    status = fsw_dnode_create_root(vol, REISERFS_ROOT_OBJECTID, &vol->g.root);
+    if (status)
+        return status;
+    vol->g.root->dir_id = REISERFS_ROOT_PARENT_OBJECTID;
+
+    FSW_MSG_DEBUG((FSW_MSGSTR("fsw_reiserfs_volume_mount: success, blocksize %d tree height %d\n"),
+                   blocksize, vol->sb->s_v1.s_tree_height));
+
+    return FSW_SUCCESS;
+}
+
+/**
+ * Free the volume data structure. Called by the core after an unmount or after
+ * an unsuccessful mount to release the memory used by the file system type specific
+ * part of the volume structure.
+ */
+
+static void fsw_reiserfs_volume_free(struct fsw_reiserfs_volume *vol)
+{
+    if (vol->sb)
+        fsw_free(vol->sb);
+}
+
+/**
+ * Get in-depth information on a volume.
+ */
+
+static fsw_status_t fsw_reiserfs_volume_stat(struct fsw_reiserfs_volume *vol, struct fsw_volume_stat *sb)
+{
+    sb->total_bytes = (fsw_u64)vol->sb->s_v1.s_block_count * vol->g.log_blocksize;
+    sb->free_bytes  = (fsw_u64)vol->sb->s_v1.s_free_blocks * vol->g.log_blocksize;
+    return FSW_SUCCESS;
+}
+
+/**
+ * Get full information on a dnode from disk. This function is called by the core
+ * whenever it needs to access fields in the dnode structure that may not
+ * be filled immediately upon creation of the dnode. In the case of reiserfs, we
+ * delay fetching of the stat data until dnode_fill is called. The size and
+ * type fields are invalid until this function has been called.
+ */
+
+static fsw_status_t fsw_reiserfs_dnode_fill(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno)
+{
+    fsw_status_t    status;
+    fsw_u32         item_len, mode;
+    struct fsw_reiserfs_item item;
+
+    if (dno->sd_v1 || dno->sd_v2)
+        return FSW_SUCCESS;
+
+    FSW_MSG_DEBUG((FSW_MSGSTR("fsw_reiserfs_dnode_fill: object %d/%d\n"), dno->dir_id, dno->g.dnode_id));
+
+    // find stat data item in reiserfs tree
+    status = fsw_reiserfs_item_search(vol, dno->dir_id, dno->g.dnode_id, 0, &item);
+    if (status == FSW_NOT_FOUND) {
+        FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_dnode_fill: cannot find stat_data for object %d/%d\n"),
+                        dno->dir_id, dno->g.dnode_id));
+        return FSW_VOLUME_CORRUPTED;
+    }
+    if (status)
+        return status;
+    if (item.item_offset != 0) {
+        FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_dnode_fill: got item that's not stat_data\n")));
+        fsw_reiserfs_item_release(vol, &item);
+        return FSW_VOLUME_CORRUPTED;
+    }
+    item_len = item.ih.ih_item_len;
+
+    // get data in appropriate version
+    if (item.ih.ih_version == KEY_FORMAT_3_5 && item_len == SD_V1_SIZE) {
+        // have stat_data_v1 structure
+        status = fsw_memdup((void **)&dno->sd_v1, item.item_data, item_len);
+        fsw_reiserfs_item_release(vol, &item);
+        if (status)
+            return status;
+
+        // get info from the inode
+        dno->g.size = dno->sd_v1->sd_size;
+        mode = dno->sd_v1->sd_mode;
+
+    } else if (item.ih.ih_version == KEY_FORMAT_3_6 && item_len == SD_V2_SIZE) {
+        // have stat_data_v2 structure
+        status = fsw_memdup((void **)&dno->sd_v2, item.item_data, item_len);
+        fsw_reiserfs_item_release(vol, &item);
+        if (status)
+            return status;
+
+        // get info from the inode
+        dno->g.size = dno->sd_v2->sd_size;
+        mode = dno->sd_v2->sd_mode;
+
+    } else {
+        FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_dnode_fill: version %d(%d) and size %d(%d) not recognized for stat_data\n"),
+                        item.ih.ih_version, KEY_FORMAT_3_6, item_len, SD_V2_SIZE));
+        fsw_reiserfs_item_release(vol, &item);
+        return FSW_VOLUME_CORRUPTED;
+    }
+
+    // get node type from mode field
+    if (S_ISREG(mode))
+        dno->g.type = FSW_DNODE_TYPE_FILE;
+    else if (S_ISDIR(mode))
+        dno->g.type = FSW_DNODE_TYPE_DIR;
+    else if (S_ISLNK(mode))
+        dno->g.type = FSW_DNODE_TYPE_SYMLINK;
+    else
+        dno->g.type = FSW_DNODE_TYPE_SPECIAL;
+
+    return FSW_SUCCESS;
+}
+
+/**
+ * Free the dnode data structure. Called by the core when deallocating a dnode
+ * structure to release the memory used by the file system type specific part
+ * of the dnode structure.
+ */
+
+static void fsw_reiserfs_dnode_free(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno)
+{
+    if (dno->sd_v1)
+        fsw_free(dno->sd_v1);
+    if (dno->sd_v2)
+        fsw_free(dno->sd_v2);
+}
+
+/**
+ * Get in-depth information on a dnode. The core makes sure that fsw_reiserfs_dnode_fill
+ * has been called on the dnode before this function is called. Note that some
+ * data is not directly stored into the structure, but passed to a host-specific
+ * callback that converts it to the host-specific format.
+ */
+
+static fsw_status_t fsw_reiserfs_dnode_stat(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno,
+                                            struct fsw_dnode_stat *sb)
+{
+    if (dno->sd_v1) {
+        if (dno->g.type == FSW_DNODE_TYPE_SPECIAL)
+            sb->used_bytes = 0;
+        else
+            sb->used_bytes = dno->sd_v1->u.sd_blocks * vol->g.log_blocksize;
+        fsw_store_time_posix(sb, FSW_DNODE_STAT_CTIME, dno->sd_v1->sd_ctime);
+        fsw_store_time_posix(sb, FSW_DNODE_STAT_ATIME, dno->sd_v1->sd_atime);
+        fsw_store_time_posix(sb, FSW_DNODE_STAT_MTIME, dno->sd_v1->sd_mtime);
+        fsw_store_attr_posix(sb, dno->sd_v1->sd_mode);
+    } else if (dno->sd_v2) {
+        sb->used_bytes = dno->sd_v2->sd_blocks * vol->g.log_blocksize;
+        fsw_store_time_posix(sb, FSW_DNODE_STAT_CTIME, dno->sd_v2->sd_ctime);
+        fsw_store_time_posix(sb, FSW_DNODE_STAT_ATIME, dno->sd_v2->sd_atime);
+        fsw_store_time_posix(sb, FSW_DNODE_STAT_MTIME, dno->sd_v2->sd_mtime);
+        fsw_store_attr_posix(sb, dno->sd_v2->sd_mode);
+    }
+
+    return FSW_SUCCESS;
+}
+
+/**
+ * Retrieve file data mapping information. This function is called by the core when
+ * fsw_shandle_read needs to know where on the disk the required piece of the file's
+ * data can be found. The core makes sure that fsw_reiserfs_dnode_fill has been called
+ * on the dnode before. Our task here is to get the physical disk block number for
+ * the requested logical block number.
+ */
+
+static fsw_status_t fsw_reiserfs_get_extent(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno,
+                                            struct fsw_extent *extent)
+{
+    fsw_status_t    status;
+    fsw_u64         search_offset, intra_offset;
+    struct fsw_reiserfs_item item;
+    fsw_u32         intra_bno, nr_item;
+
+    // Preconditions: The caller has checked that the requested logical block
+    //  is within the file's size. The dnode has complete information, i.e.
+    //  fsw_reiserfs_dnode_read_info was called successfully on it.
+
+    FSW_MSG_DEBUG((FSW_MSGSTR("fsw_reiserfs_get_extent: mapping block %d of object %d/%d\n"),
+                   extent->log_start, dno->dir_id, dno->g.dnode_id));
+
+    extent->type = FSW_EXTENT_TYPE_SPARSE;
+    extent->log_count = 1;
+
+    // get the item for the requested block
+    search_offset = (fsw_u64)extent->log_start * vol->g.log_blocksize + 1;
+    status = fsw_reiserfs_item_search(vol, dno->dir_id, dno->g.dnode_id, search_offset, &item);
+    if (status)
+        return status;
+    if (item.item_offset == 0) {
+        fsw_reiserfs_item_release(vol, &item);
+        return FSW_SUCCESS;       // no data items found, assume all-sparse file
+    }
+    intra_offset = search_offset - item.item_offset;
+
+    // check the kind of block
+    if (item.item_type == TYPE_INDIRECT || item.item_type == V1_INDIRECT_UNIQUENESS) {
+        // indirect item, contains block numbers
+
+        if (intra_offset & (vol->g.log_blocksize - 1)) {
+            FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_get_extent: intra_offset not block-aligned for indirect block\n")));
+            goto bail;
+        }
+        intra_bno = (fsw_u32)FSW_U64_DIV(intra_offset, vol->g.log_blocksize);
+        nr_item = item.ih.ih_item_len / sizeof(fsw_u32);
+        if (intra_bno >= nr_item) {
+            FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_get_extent: indirect block too small\n")));
+            goto bail;
+        }
+        extent->type = FSW_EXTENT_TYPE_PHYSBLOCK;
+        extent->phys_start = ((fsw_u32 *)item.item_data)[intra_bno];
+
+        // TODO: check if the following blocks can be aggregated into one extent
+
+        fsw_reiserfs_item_release(vol, &item);
+        return FSW_SUCCESS;
+
+    } else if (item.item_type == TYPE_DIRECT || item.item_type == V1_DIRECT_UNIQUENESS) {
+        // direct item, contains file data
+
+        // TODO: Check if direct items always start on block boundaries. If not, we may have
+        //  to do extra work here.
+
+        if (intra_offset != 0) {
+            FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_get_extent: intra_offset not aligned for direct block\n")));
+            goto bail;
+        }
+
+        extent->type = FSW_EXTENT_TYPE_BUFFER;
+        status = fsw_memdup(&extent->buffer, item.item_data, item.ih.ih_item_len);
+        fsw_reiserfs_item_release(vol, &item);
+        if (status)
+            return status;
+
+        return FSW_SUCCESS;
+
+    }
+
+bail:
+    fsw_reiserfs_item_release(vol, &item);
+    return FSW_VOLUME_CORRUPTED;
+
+    /*    
+    // check if the following blocks can be aggregated into one extent
+    file_bcnt = (fsw_u32)((dno->g.size + vol->g.log_blocksize - 1) & (vol->g.log_blocksize - 1));
+    while (path[i]           + extent->log_count < buf_bcnt &&    // indirect block has more block pointers
+           extent->log_start + extent->log_count < file_bcnt) {   // file has more blocks
+        if (buffer[path[i] + extent->log_count] == buffer[path[i] + extent->log_count - 1] + 1)
+            extent->log_count++;
+        else
+            break;
+    }
+    */
+}
+
+/**
+ * Lookup a directory's child dnode by name. This function is called on a directory
+ * to retrieve the directory entry with the given name. A dnode is constructed for
+ * this entry and returned. The core makes sure that fsw_reiserfs_dnode_fill has been called
+ * and the dnode is actually a directory.
+ */
+
+static fsw_status_t fsw_reiserfs_dir_lookup(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno,
+                                            struct fsw_string *lookup_name, struct fsw_reiserfs_dnode **child_dno_out)
+{
+    fsw_status_t    status;
+    struct fsw_reiserfs_item item;
+    fsw_u32         nr_item, i, name_offset, next_name_offset, name_len;
+    fsw_u32         child_dir_id;
+    struct reiserfs_de_head *dhead;
+    struct fsw_string entry_name;
+
+    // Preconditions: The caller has checked that dno is a directory node.
+
+    // BIG TODOS: Use the hash function to start with the item containing the entry.
+    //  Use binary search within the item.
+
+    entry_name.type = FSW_STRING_TYPE_ISO88591;
+
+    // get the item for that position
+    status = fsw_reiserfs_item_search(vol, dno->dir_id, dno->g.dnode_id, FIRST_ITEM_OFFSET, &item);
+    if (status)
+        return status;
+    if (item.item_offset == 0) {
+        fsw_reiserfs_item_release(vol, &item);
+        return FSW_NOT_FOUND;       // empty directory or something
+    }
+
+    for(;;) {
+
+        // search the directory item
+        dhead = (struct reiserfs_de_head *)item.item_data;
+        nr_item = item.ih.u.ih_entry_count;
+        next_name_offset = item.ih.ih_item_len;
+        for (i = 0; i < nr_item; i++, dhead++, next_name_offset = name_offset) {
+            // get the name
+            name_offset = dhead->deh_location;
+            name_len = next_name_offset - name_offset;
+            while (name_len > 0 && item.item_data[name_offset + name_len - 1] == 0)
+                name_len--;
+
+            entry_name.len = entry_name.size = name_len;
+            entry_name.data = item.item_data + name_offset;
+
+            // compare name
+            if (fsw_streq(lookup_name, &entry_name)) {
+                // found the entry we're looking for!
+
+                // setup a dnode for the child item
+                status = fsw_dnode_create(dno, dhead->deh_objectid, FSW_DNODE_TYPE_UNKNOWN, &entry_name, child_dno_out);
+                child_dir_id = dhead->deh_dir_id;
+                fsw_reiserfs_item_release(vol, &item);
+                if (status)
+                    return status;
+                (*child_dno_out)->dir_id = child_dir_id;
+
+                return FSW_SUCCESS;
+            }
+        }
+
+        // We didn't find the next directory entry in this item. Look for the next
+        // item of the directory.
+
+        status = fsw_reiserfs_item_next(vol, &item);
+        if (status)
+            return status;
+
+    }
+}
+
+/**
+ * Get the next directory entry when reading a directory. This function is called during
+ * directory iteration to retrieve the next directory entry. A dnode is constructed for
+ * the entry and returned. The core makes sure that fsw_reiserfs_dnode_fill has been called
+ * and the dnode is actually a directory. The shandle provided by the caller is used to
+ * record the position in the directory between calls.
+ */
+
+static fsw_status_t fsw_reiserfs_dir_read(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno,
+                                          struct fsw_shandle *shand, struct fsw_reiserfs_dnode **child_dno_out)
+{
+    fsw_status_t    status;
+    struct fsw_reiserfs_item item;
+    fsw_u32         nr_item, i, name_offset, next_name_offset, name_len;
+    fsw_u32         child_dir_id;
+    struct reiserfs_de_head *dhead;
+    struct fsw_string entry_name;
+
+    // Preconditions: The caller has checked that dno is a directory node. The caller
+    //  has opened a storage handle to the directory's storage and keeps it around between
+    //  calls.
+
+    // BIG TODOS: Use binary search within the item.
+
+    // adjust pointer to first entry if necessary
+    if (shand->pos == 0)
+        shand->pos = FIRST_ITEM_OFFSET;
+
+    // get the item for that position
+    status = fsw_reiserfs_item_search(vol, dno->dir_id, dno->g.dnode_id, shand->pos, &item);
+    if (status)
+        return status;
+    if (item.item_offset == 0) {
+        fsw_reiserfs_item_release(vol, &item);
+        return FSW_NOT_FOUND;       // empty directory or something
+    }
+
+    for(;;) {
+
+        // search the directory item
+        dhead = (struct reiserfs_de_head *)item.item_data;
+        nr_item = item.ih.u.ih_entry_count;
+        for (i = 0; i < nr_item; i++, dhead++) {
+            if (dhead->deh_offset < shand->pos)
+                continue;  // not yet past the last entry returned
+            if (dhead->deh_offset == DOT_OFFSET || dhead->deh_offset == DOT_DOT_OFFSET)
+                continue;  // never report . or ..
+
+            // get the name
+            name_offset = dhead->deh_location;
+            if (i == 0)
+                next_name_offset = item.ih.ih_item_len;
+            else
+                next_name_offset = dhead[-1].deh_location;
+            name_len = next_name_offset - name_offset;
+            while (name_len > 0 && item.item_data[name_offset + name_len - 1] == 0)
+                name_len--;
+
+            entry_name.type = FSW_STRING_TYPE_ISO88591;
+            entry_name.len = entry_name.size = name_len;
+            entry_name.data = item.item_data + name_offset;
+
+            if (fsw_streq_cstr(&entry_name, ".reiserfs_priv"))
+                continue;  // never report this special file
+
+            // found the next entry!
+            shand->pos = dhead->deh_offset + 1;
+
+            // setup a dnode for the child item
+            status = fsw_dnode_create(dno, dhead->deh_objectid, FSW_DNODE_TYPE_UNKNOWN, &entry_name, child_dno_out);
+            child_dir_id = dhead->deh_dir_id;
+            fsw_reiserfs_item_release(vol, &item);
+            if (status)
+                return status;
+            (*child_dno_out)->dir_id = child_dir_id;
+
+            return FSW_SUCCESS;
+        }
+
+        // We didn't find the next directory entry in this item. Look for the next
+        // item of the directory.
+
+        status = fsw_reiserfs_item_next(vol, &item);
+        if (status)
+            return status;
+
+    }
+}
+
+/**
+ * Get the target path of a symbolic link. This function is called when a symbolic
+ * link needs to be resolved. The core makes sure that the fsw_reiserfs_dnode_fill has been
+ * called on the dnode and that it really is a symlink.
+ */
+
+static fsw_status_t fsw_reiserfs_readlink(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno,
+                                          struct fsw_string *link_target)
+{
+    return fsw_dnode_readlink_data(dno, link_target);
+}
+
+/**
+ * Compare an on-disk tree key against the search key.
+ */
+
+static int fsw_reiserfs_compare_key(struct reiserfs_key *key,
+                                    fsw_u32 dir_id, fsw_u32 objectid, fsw_u64 offset)
+{
+    fsw_u32 key_type;
+    fsw_u64 key_offset;
+
+    if (key->k_dir_id > dir_id)
+        return FIRST_GREATER;
+    if (key->k_dir_id < dir_id)
+        return SECOND_GREATER;
+
+    if (key->k_objectid > objectid)
+        return FIRST_GREATER;
+    if (key->k_objectid < objectid)
+        return SECOND_GREATER;
+
+    // determine format of the on-disk key
+    key_type = (fsw_u32)FSW_U64_SHR(key->u.k_offset_v2.v, 60);
+    if (key_type != TYPE_DIRECT && key_type != TYPE_INDIRECT && key_type != TYPE_DIRENTRY) {
+        // detected 3.5 format (_v1)
+        key_offset = key->u.k_offset_v1.k_offset;
+    } else {
+        // detected 3.6 format (_v2)
+        key_offset = key->u.k_offset_v2.v & (~0ULL >> 4);
+    }
+    if (key_offset > offset)
+        return FIRST_GREATER;
+    if (key_offset < offset)
+        return SECOND_GREATER;
+    return KEYS_IDENTICAL;
+}
+
+/**
+ * Find an item by key in the reiserfs tree.
+ */
+
+static fsw_status_t fsw_reiserfs_item_search(struct fsw_reiserfs_volume *vol,
+                                            fsw_u32 dir_id, fsw_u32 objectid, fsw_u64 offset,
+                                            struct fsw_reiserfs_item *item)
+{
+    fsw_status_t    status;
+    int             comp_result;
+    fsw_u32         tree_bno, next_tree_bno, tree_level, nr_item, i;
+    fsw_u8          *buffer;
+    struct block_head *bhead;
+    struct reiserfs_key *key;
+    struct item_head *ihead;
+
+    FSW_MSG_DEBUG((FSW_MSGSTR("fsw_reiserfs_item_search: searching %d/%d/%lld\n"), dir_id, objectid, offset));
+
+    // BIG TODOS: Use binary search within the item.
+    //  Remember tree path for "get next item" function.
+
+    item->valid = 0;
+    item->block_bno = 0;
+
+    // walk the tree
+    tree_bno = vol->sb->s_v1.s_root_block;
+    for (tree_level = vol->sb->s_v1.s_tree_height - 1; ; tree_level--) {
+
+        // get the current tree block into memory
+        status = fsw_block_get(vol, tree_bno, tree_level, (void **)&buffer);
+        if (status)
+            return status;
+        bhead = (struct block_head *)buffer;
+        if (bhead->blk_level != tree_level) {
+            FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_item_search: tree block %d has not expected level %d\n"), tree_bno, tree_level));
+            fsw_block_release(vol, tree_bno, buffer);
+            return FSW_VOLUME_CORRUPTED;
+        }
+        nr_item = bhead->blk_nr_item;
+        FSW_MSG_DEBUGV((FSW_MSGSTR("fsw_reiserfs_item_search: visiting block %d level %d items %d\n"), tree_bno, tree_level, nr_item));
+        item->path_bno[tree_level] = tree_bno;
+
+        // check if we have reached a leaf block
+        if (tree_level == DISK_LEAF_NODE_LEVEL)
+            break;
+
+        // search internal node block, look for the path to follow
+        key = (struct reiserfs_key *)(buffer + BLKH_SIZE);
+        for (i = 0; i < nr_item; i++, key++) {
+            if (fsw_reiserfs_compare_key(key, dir_id, objectid, offset) == FIRST_GREATER)
+                break;
+        }
+        item->path_index[tree_level] = i;
+        next_tree_bno = ((struct disk_child *)(buffer + BLKH_SIZE + nr_item * KEY_SIZE))[i].dc_block_number;
+        fsw_block_release(vol, tree_bno, buffer);
+        tree_bno = next_tree_bno;
+    }
+
+    // search leaf node block, look for our data
+    ihead = (struct item_head *)(buffer + BLKH_SIZE);
+    for (i = 0; i < nr_item; i++, ihead++) {
+        comp_result = fsw_reiserfs_compare_key(&ihead->ih_key, dir_id, objectid, offset);
+        if (comp_result == KEYS_IDENTICAL)
+            break;
+        if (comp_result == FIRST_GREATER) {
+            // Current key is greater than the search key. Use the last key before this
+            // one as the preliminary result.
+            if (i == 0) {
+                fsw_block_release(vol, tree_bno, buffer);
+                return FSW_NOT_FOUND;
+            }
+            i--, ihead--;
+            break;
+        }
+    }
+    if (i >= nr_item) {
+        // Go back to the last key, it was smaller than the search key.
+        // NOTE: The first key of the next leaf block is guaranteed to be greater than
+        //  our search key.
+        i--, ihead--;
+    }
+    item->path_index[tree_level] = i;
+    // Since we may have a key that is smaller than the search key, verify that
+    // it is for the same object.
+    if (ihead->ih_key.k_dir_id != dir_id || ihead->ih_key.k_objectid != objectid) {
+        fsw_block_release(vol, tree_bno, buffer);
+        return FSW_NOT_FOUND;   // Found no key for this object at all
+    }
+
+    // return results
+    fsw_memcpy(&item->ih, ihead, sizeof(struct item_head));
+    item->item_type = (fsw_u32)FSW_U64_SHR(ihead->ih_key.u.k_offset_v2.v, 60);
+    if (item->item_type != TYPE_DIRECT &&
+        item->item_type != TYPE_INDIRECT &&
+        item->item_type != TYPE_DIRENTRY) {
+        // 3.5 format (_v1)
+        item->item_type = ihead->ih_key.u.k_offset_v1.k_uniqueness;
+        item->item_offset = ihead->ih_key.u.k_offset_v1.k_offset;
+    } else {
+        // 3.6 format (_v2)
+        item->item_offset = ihead->ih_key.u.k_offset_v2.v & (~0ULL >> 4);
+    }
+    item->item_data = buffer + ihead->ih_item_location;
+    item->valid = 1;
+
+    // add information for block release
+    item->block_bno = tree_bno;
+    item->block_buffer = buffer;
+
+    FSW_MSG_DEBUG((FSW_MSGSTR("fsw_reiserfs_item_search: found %d/%d/%lld (%d)\n"),
+                   ihead->ih_key.k_dir_id, ihead->ih_key.k_objectid, item->item_offset, item->item_type));
+    return FSW_SUCCESS;
+}
+
+/**
+ * Find the next item in the reiserfs tree for an already-found item.
+ */
+
+static fsw_status_t fsw_reiserfs_item_next(struct fsw_reiserfs_volume *vol,
+                                          struct fsw_reiserfs_item *item)
+{
+    fsw_status_t    status;
+    fsw_u32         dir_id, objectid;
+    fsw_u32         tree_bno, next_tree_bno, tree_level, nr_item, nr_ptr_item;
+    fsw_u8          *buffer;
+    struct block_head *bhead;
+    struct item_head *ihead;
+
+    if (!item->valid)
+        return FSW_NOT_FOUND;
+    fsw_reiserfs_item_release(vol, item);   // TODO: maybe delay this and/or use the cached block!
+
+    dir_id = item->ih.ih_key.k_dir_id;
+    objectid = item->ih.ih_key.k_objectid;
+
+    FSW_MSG_DEBUG((FSW_MSGSTR("fsw_reiserfs_item_next: next for %d/%d/%lld\n"), dir_id, objectid, item->item_offset));
+
+    // find a node that has more items, moving up until we find one
+
+    for (tree_level = DISK_LEAF_NODE_LEVEL; tree_level < vol->sb->s_v1.s_tree_height; tree_level++) {
+
+        // get the current tree block into memory
+        tree_bno = item->path_bno[tree_level];
+        status = fsw_block_get(vol, tree_bno, tree_level, (void **)&buffer);
+        if (status)
+            return status;
+        bhead = (struct block_head *)buffer;
+        if (bhead->blk_level != tree_level) {
+            FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_item_next: tree block %d has not expected level %d\n"), tree_bno, tree_level));
+            fsw_block_release(vol, tree_bno, buffer);
+            return FSW_VOLUME_CORRUPTED;
+        }
+        nr_item = bhead->blk_nr_item;
+        FSW_MSG_DEBUGV((FSW_MSGSTR("fsw_reiserfs_item_next: visiting block %d level %d items %d\n"), tree_bno, tree_level, nr_item));
+
+        nr_ptr_item = nr_item + ((tree_level > DISK_LEAF_NODE_LEVEL) ? 1 : 0);  // internal nodes have (nr_item) keys and (nr_item+1) pointers
+        item->path_index[tree_level]++;
+        if (item->path_index[tree_level] >= nr_ptr_item) {
+            item->path_index[tree_level] = 0;
+            fsw_block_release(vol, tree_bno, buffer);
+            continue;  // this node doesn't have any more items, move up one level
+        }
+
+        // we have a new path to follow, move down to the leaf node again
+        while (tree_level > DISK_LEAF_NODE_LEVEL) {
+            // get next pointer from current block
+            next_tree_bno = ((struct disk_child *)(buffer + BLKH_SIZE + nr_item * KEY_SIZE))[item->path_index[tree_level]].dc_block_number;
+            fsw_block_release(vol, tree_bno, buffer);
+            tree_bno = next_tree_bno;
+            tree_level--;
+
+            // get the current tree block into memory
+            status = fsw_block_get(vol, tree_bno, tree_level, (void **)&buffer);
+            if (status)
+                return status;
+            bhead = (struct block_head *)buffer;
+            if (bhead->blk_level != tree_level) {
+                FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_item_next: tree block %d has not expected level %d\n"), tree_bno, tree_level));
+                fsw_block_release(vol, tree_bno, buffer);
+                return FSW_VOLUME_CORRUPTED;
+            }
+            nr_item = bhead->blk_nr_item;
+            FSW_MSG_DEBUGV((FSW_MSGSTR("fsw_reiserfs_item_next: visiting block %d level %d items %d\n"), tree_bno, tree_level, nr_item));
+            item->path_bno[tree_level] = tree_bno;
+        }
+
+        // get the item from the leaf node
+        ihead = ((struct item_head *)(buffer + BLKH_SIZE)) + item->path_index[tree_level];
+
+        // We now have the item that follows the previous one in the tree. Check that it
+        // belongs to the same object.
+        if (ihead->ih_key.k_dir_id != dir_id || ihead->ih_key.k_objectid != objectid) {
+            fsw_block_release(vol, tree_bno, buffer);
+            return FSW_NOT_FOUND;   // Found no next key for this object
+        }
+
+        // return results
+        fsw_memcpy(&item->ih, ihead, sizeof(struct item_head));
+        item->item_type = (fsw_u32)FSW_U64_SHR(ihead->ih_key.u.k_offset_v2.v, 60);
+        if (item->item_type != TYPE_DIRECT &&
+            item->item_type != TYPE_INDIRECT &&
+            item->item_type != TYPE_DIRENTRY) {
+            // 3.5 format (_v1)
+            item->item_type = ihead->ih_key.u.k_offset_v1.k_uniqueness;
+            item->item_offset = ihead->ih_key.u.k_offset_v1.k_offset;
+        } else {
+            // 3.6 format (_v2)
+            item->item_offset = ihead->ih_key.u.k_offset_v2.v & (~0ULL >> 4);
+        }
+        item->item_data = buffer + ihead->ih_item_location;
+        item->valid = 1;
+
+        // add information for block release
+        item->block_bno = tree_bno;
+        item->block_buffer = buffer;
+
+        FSW_MSG_DEBUG((FSW_MSGSTR("fsw_reiserfs_item_next: found %d/%d/%lld (%d)\n"),
+                       ihead->ih_key.k_dir_id, ihead->ih_key.k_objectid, item->item_offset, item->item_type));
+        return FSW_SUCCESS;
+    }
+
+    // we went to the highest level node and there still were no more items...
+    return FSW_NOT_FOUND;
+}
+
+/**
+ * Release the disk block still referenced by an item search result.
+ */
+
+static void fsw_reiserfs_item_release(struct fsw_reiserfs_volume *vol,
+                                      struct fsw_reiserfs_item *item)
+{
+    if (!item->valid)
+        return;
+
+    if (item->block_bno > 0) {
+        fsw_block_release(vol, item->block_bno, item->block_buffer);
+        item->block_bno = 0;
+    }
+}
+
+// EOF
diff --git a/filesystems/fsw_reiserfs.h b/filesystems/fsw_reiserfs.h
new file mode 100644 (file)
index 0000000..cbb1ea9
--- /dev/null
@@ -0,0 +1,88 @@
+/**
+ * \file fsw_reiserfs.h
+ * ReiserFS file system driver header.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifndef _FSW_REISERFS_H_
+#define _FSW_REISERFS_H_
+
+#define VOLSTRUCTNAME fsw_reiserfs_volume
+#define DNODESTRUCTNAME fsw_reiserfs_dnode
+#include "fsw_core.h"
+
+#include "fsw_reiserfs_disk.h"
+
+
+//! Block size (in shift bits) to be used when reading the reiserfs superblock.
+#define REISERFS_SUPERBLOCK_BLOCKSIZEBITS  12
+//! Block size (in bytes) to be used when reading the reiserfs superblock.
+#define REISERFS_SUPERBLOCK_BLOCKSIZE  (1<<REISERFS_SUPERBLOCK_BLOCKSIZEBITS)
+
+
+/**
+ * ReiserFS: Results from a tree search.
+ */
+
+struct fsw_reiserfs_item {
+    int valid;
+    
+    // the found item
+    struct item_head ih;
+    fsw_u64 item_offset;
+    fsw_u32 item_type;
+    
+    fsw_u8 *item_data;
+    
+    // path information
+    fsw_u32 path_bno[MAX_HEIGHT];
+    fsw_u32 path_index[MAX_HEIGHT];
+    
+    // block release information
+    fsw_u32 block_bno;
+    void *block_buffer;
+};
+
+
+/**
+ * ReiserFS: Volume structure with reiserfs-specific data.
+ */
+
+struct fsw_reiserfs_volume {
+    struct fsw_volume g;            //!< Generic volume structure
+    
+    struct reiserfs_super_block *sb;  //!< Full raw reiserfs superblock structure
+    int version;                    //!< Flag for 3.5 or 3.6 format
+};
+
+/**
+ * ReiserFS: Dnode structure with reiserfs-specific data.
+ */
+
+struct fsw_reiserfs_dnode {
+    struct fsw_dnode g;             //!< Generic dnode structure
+    
+    fsw_u32 dir_id;                 //!< Locality ID for the reiserfs tree (parent dir id)
+    struct stat_data_v1 *sd_v1;     //!< Full stat_data, version 1
+    struct stat_data *sd_v2;        //!< Full stat_data, version 2
+};
+
+
+#endif
diff --git a/filesystems/fsw_reiserfs_disk.h b/filesystems/fsw_reiserfs_disk.h
new file mode 100644 (file)
index 0000000..885a2e0
--- /dev/null
@@ -0,0 +1,1677 @@
+/**
+ * \file fsw_reiserfs_disk.h
+ * ReiserFS file system on-disk structures.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ * Portions Copyright (c) 1991-2006 by various Linux kernel contributors
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifndef _FSW_REISERFS_DISK_H_
+#define _FSW_REISERFS_DISK_H_
+
+// types
+
+typedef fsw_s8  __s8;
+typedef fsw_u8  __u8;
+typedef fsw_s16 __s16;
+typedef fsw_u16 __u16;
+typedef fsw_s32 __s32;
+typedef fsw_u32 __u32;
+typedef fsw_s64 __s64;
+typedef fsw_u64 __u64;
+
+typedef __u16   __le16;
+typedef __u32   __le32;
+typedef __u64   __le64;
+
+#define le16_to_cpu(x) (x)
+#define cpu_to_le16(x) (x)
+#define le32_to_cpu(x) (x)
+#define cpu_to_le32(x) (x)
+#define le64_to_cpu(x) (x)
+#define cpu_to_le64(x) (x)
+
+#ifdef __GCC__
+#define ATTR_PACKED __attribute__ ((__packed__))
+#else
+#define ATTR_PACKED
+#endif
+
+#pragma pack(1)
+
+//
+// from Linux kernel, include/linux/reiserfs_fs.h
+//
+
+
+
+/*
+ * Disk Data Structures
+ */
+
+/***************************************************************************/
+/*                             SUPER BLOCK                                 */
+/***************************************************************************/
+
+/*
+ * Structure of super block on disk, a version of which in RAM is often accessed as REISERFS_SB(s)->s_rs
+ * the version in RAM is part of a larger structure containing fields never written to disk.
+ */
+#define UNSET_HASH 0           // read_super will guess about, what hash names
+                    // in directories were sorted with
+#define TEA_HASH  1
+#define YURA_HASH 2
+#define R5_HASH   3
+#define DEFAULT_HASH R5_HASH
+
+struct journal_params {
+       __le32 jp_journal_1st_block;    /* where does journal start from on its
+                                        * device */
+       __le32 jp_journal_dev;  /* journal device st_rdev */
+       __le32 jp_journal_size; /* size of the journal */
+       __le32 jp_journal_trans_max;    /* max number of blocks in a transaction. */
+       __le32 jp_journal_magic;        /* random value made on fs creation (this
+                                        * was sb_journal_block_count) */
+       __le32 jp_journal_max_batch;    /* max number of blocks to batch into a
+                                        * trans */
+       __le32 jp_journal_max_commit_age;       /* in seconds, how old can an async
+                                                * commit be */
+       __le32 jp_journal_max_trans_age;        /* in seconds, how old can a transaction
+                                                * be */
+};
+
+/* this is the super from 3.5.X, where X >= 10 */
+struct reiserfs_super_block_v1 {
+       __le32 s_block_count;   /* blocks count         */
+       __le32 s_free_blocks;   /* free blocks count    */
+       __le32 s_root_block;    /* root block number    */
+       struct journal_params s_journal;
+       __le16 s_blocksize;     /* block size */
+       __le16 s_oid_maxsize;   /* max size of object id array, see
+                                * get_objectid() commentary  */
+       __le16 s_oid_cursize;   /* current size of object id array */
+       __le16 s_umount_state;  /* this is set to 1 when filesystem was
+                                * umounted, to 2 - when not */
+       char s_magic[10];       /* reiserfs magic string indicates that
+                                * file system is reiserfs:
+                                * "ReIsErFs" or "ReIsEr2Fs" or "ReIsEr3Fs" */
+       __le16 s_fs_state;      /* it is set to used by fsck to mark which
+                                * phase of rebuilding is done */
+       __le32 s_hash_function_code;    /* indicate, what hash function is being use
+                                        * to sort names in a directory*/
+       __le16 s_tree_height;   /* height of disk tree */
+       __le16 s_bmap_nr;       /* amount of bitmap blocks needed to address
+                                * each block of file system */
+       __le16 s_version;       /* this field is only reliable on filesystem
+                                * with non-standard journal */
+       __le16 s_reserved_for_journal;  /* size in blocks of journal area on main
+                                        * device, we need to keep after
+                                        * making fs with non-standard journal */
+} ATTR_PACKED;
+
+#define SB_SIZE_V1 (sizeof(struct reiserfs_super_block_v1))
+
+/* this is the on disk super block */
+struct reiserfs_super_block {
+       struct reiserfs_super_block_v1 s_v1;
+       __le32 s_inode_generation;
+       __le32 s_flags;         /* Right now used only by inode-attributes, if enabled */
+       unsigned char s_uuid[16];       /* filesystem unique identifier */
+       unsigned char s_label[16];      /* filesystem volume label */
+       char s_unused[88];      /* zero filled by mkreiserfs and
+                                * reiserfs_convert_objectid_map_v1()
+                                * so any additions must be updated
+                                * there as well. */
+} ATTR_PACKED;
+
+#define SB_SIZE (sizeof(struct reiserfs_super_block))
+
+#define REISERFS_VERSION_1 0
+#define REISERFS_VERSION_2 2
+
+// on-disk super block fields converted to cpu form
+#define SB_DISK_SUPER_BLOCK(s) (REISERFS_SB(s)->s_rs)
+#define SB_V1_DISK_SUPER_BLOCK(s) (&(SB_DISK_SUPER_BLOCK(s)->s_v1))
+#define SB_BLOCKSIZE(s) \
+        le32_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_blocksize))
+#define SB_BLOCK_COUNT(s) \
+        le32_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_block_count))
+#define SB_FREE_BLOCKS(s) \
+        le32_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_free_blocks))
+#define SB_REISERFS_MAGIC(s) \
+        (SB_V1_DISK_SUPER_BLOCK(s)->s_magic)
+#define SB_ROOT_BLOCK(s) \
+        le32_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_root_block))
+#define SB_TREE_HEIGHT(s) \
+        le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_tree_height))
+#define SB_REISERFS_STATE(s) \
+        le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_umount_state))
+#define SB_VERSION(s) le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_version))
+#define SB_BMAP_NR(s) le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_bmap_nr))
+
+#define SB_ONDISK_JP(s) (&SB_V1_DISK_SUPER_BLOCK(s)->s_journal)
+#define SB_ONDISK_JOURNAL_SIZE(s) \
+         le32_to_cpu ((SB_ONDISK_JP(s)->jp_journal_size))
+#define SB_ONDISK_JOURNAL_1st_BLOCK(s) \
+         le32_to_cpu ((SB_ONDISK_JP(s)->jp_journal_1st_block))
+#define SB_ONDISK_JOURNAL_DEVICE(s) \
+         le32_to_cpu ((SB_ONDISK_JP(s)->jp_journal_dev))
+#define SB_ONDISK_RESERVED_FOR_JOURNAL(s) \
+         le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_reserved_for_journal))
+
+#define is_block_in_log_or_reserved_area(s, block) \
+         block >= SB_JOURNAL_1st_RESERVED_BLOCK(s) \
+         && block < SB_JOURNAL_1st_RESERVED_BLOCK(s) +  \
+         ((!is_reiserfs_jr(SB_DISK_SUPER_BLOCK(s)) ? \
+         SB_ONDISK_JOURNAL_SIZE(s) + 1 : SB_ONDISK_RESERVED_FOR_JOURNAL(s)))
+
+                               /* used by gcc */
+#define REISERFS_SUPER_MAGIC 0x52654973
+                               /* used by file system utilities that
+                                  look at the superblock, etc. */
+#define REISERFS_SUPER_MAGIC_STRING "ReIsErFs"
+#define REISER2FS_SUPER_MAGIC_STRING "ReIsEr2Fs"
+#define REISER2FS_JR_SUPER_MAGIC_STRING "ReIsEr3Fs"
+
+/* ReiserFS leaves the first 64k unused, so that partition labels have
+   enough space.  If someone wants to write a fancy bootloader that
+   needs more than 64k, let us know, and this will be increased in size.
+   This number must be larger than than the largest block size on any
+   platform, or code will break.  -Hans */
+#define REISERFS_DISK_OFFSET_IN_BYTES (64 * 1024)
+#define REISERFS_FIRST_BLOCK unused_define
+#define REISERFS_JOURNAL_OFFSET_IN_BYTES REISERFS_DISK_OFFSET_IN_BYTES
+
+/* the spot for the super in versions 3.5 - 3.5.10 (inclusive) */
+#define REISERFS_OLD_DISK_OFFSET_IN_BYTES (8 * 1024)
+
+// reiserfs internal error code (used by search_by_key adn fix_nodes))
+#define CARRY_ON      0
+#define REPEAT_SEARCH -1
+#define IO_ERROR      -2
+#define NO_DISK_SPACE -3
+#define NO_BALANCING_NEEDED  (-4)
+#define NO_MORE_UNUSED_CONTIGUOUS_BLOCKS (-5)
+#define QUOTA_EXCEEDED -6
+
+typedef __u32 b_blocknr_t;
+typedef __le32 unp_t;
+
+struct unfm_nodeinfo {
+       unp_t unfm_nodenum;
+       unsigned short unfm_freespace;
+};
+
+/* there are two formats of keys: 3.5 and 3.6
+ */
+#define KEY_FORMAT_3_5 0
+#define KEY_FORMAT_3_6 1
+
+/* there are two stat datas */
+#define STAT_DATA_V1 0
+#define STAT_DATA_V2 1
+
+
+
+/** this says about version of key of all items (but stat data) the
+    object consists of */
+#define get_inode_item_key_version( inode )                                    \
+    ((REISERFS_I(inode)->i_flags & i_item_key_version_mask) ? KEY_FORMAT_3_6 : KEY_FORMAT_3_5)
+
+#define set_inode_item_key_version( inode, version )                           \
+         ({ if((version)==KEY_FORMAT_3_6)                                      \
+                REISERFS_I(inode)->i_flags |= i_item_key_version_mask;      \
+            else                                                               \
+                REISERFS_I(inode)->i_flags &= ~i_item_key_version_mask; })
+
+#define get_inode_sd_version(inode)                                            \
+    ((REISERFS_I(inode)->i_flags & i_stat_data_version_mask) ? STAT_DATA_V2 : STAT_DATA_V1)
+
+#define set_inode_sd_version(inode, version)                                   \
+         ({ if((version)==STAT_DATA_V2)                                        \
+                REISERFS_I(inode)->i_flags |= i_stat_data_version_mask;     \
+            else                                                               \
+                REISERFS_I(inode)->i_flags &= ~i_stat_data_version_mask; })
+
+/* This is an aggressive tail suppression policy, I am hoping it
+   improves our benchmarks. The principle behind it is that percentage
+   space saving is what matters, not absolute space saving.  This is
+   non-intuitive, but it helps to understand it if you consider that the
+   cost to access 4 blocks is not much more than the cost to access 1
+   block, if you have to do a seek and rotate.  A tail risks a
+   non-linear disk access that is significant as a percentage of total
+   time cost for a 4 block file and saves an amount of space that is
+   less significant as a percentage of space, or so goes the hypothesis.
+   -Hans */
+#define STORE_TAIL_IN_UNFM_S1(n_file_size,n_tail_size,n_block_size) \
+(\
+  (!(n_tail_size)) || \
+  (((n_tail_size) > MAX_DIRECT_ITEM_LEN(n_block_size)) || \
+   ( (n_file_size) >= (n_block_size) * 4 ) || \
+   ( ( (n_file_size) >= (n_block_size) * 3 ) && \
+     ( (n_tail_size) >=   (MAX_DIRECT_ITEM_LEN(n_block_size))/4) ) || \
+   ( ( (n_file_size) >= (n_block_size) * 2 ) && \
+     ( (n_tail_size) >=   (MAX_DIRECT_ITEM_LEN(n_block_size))/2) ) || \
+   ( ( (n_file_size) >= (n_block_size) ) && \
+     ( (n_tail_size) >=   (MAX_DIRECT_ITEM_LEN(n_block_size) * 3)/4) ) ) \
+)
+
+/* Another strategy for tails, this one means only create a tail if all the
+   file would fit into one DIRECT item.
+   Primary intention for this one is to increase performance by decreasing
+   seeking.
+*/
+#define STORE_TAIL_IN_UNFM_S2(n_file_size,n_tail_size,n_block_size) \
+(\
+  (!(n_tail_size)) || \
+  (((n_file_size) > MAX_DIRECT_ITEM_LEN(n_block_size)) ) \
+)
+
+/*
+ * values for s_umount_state field
+ */
+#define REISERFS_VALID_FS    1
+#define REISERFS_ERROR_FS    2
+
+//
+// there are 5 item types currently
+//
+#define TYPE_STAT_DATA 0
+#define TYPE_INDIRECT 1
+#define TYPE_DIRECT 2
+#define TYPE_DIRENTRY 3
+#define TYPE_MAXTYPE 3
+#define TYPE_ANY 15            // FIXME: comment is required
+
+/***************************************************************************/
+/*                       KEY & ITEM HEAD                                   */
+/***************************************************************************/
+
+//
+// directories use this key as well as old files
+//
+struct offset_v1 {
+       __le32 k_offset;
+       __le32 k_uniqueness;
+} ATTR_PACKED;
+
+struct offset_v2 {
+       __le64 v;
+} ATTR_PACKED;
+
+/*
+static inline __u16 offset_v2_k_type(const struct offset_v2 *v2)
+{
+       __u8 type = le64_to_cpu(v2->v) >> 60;
+       return (type <= TYPE_MAXTYPE) ? type : TYPE_ANY;
+}
+
+static inline loff_t offset_v2_k_offset(const struct offset_v2 *v2)
+{
+       return le64_to_cpu(v2->v) & (~0ULL >> 4);
+}
+*/
+
+/* Key of an item determines its location in the S+tree, and
+   is composed of 4 components */
+struct reiserfs_key {
+       __le32 k_dir_id;        /* packing locality: by default parent
+                                  directory object id */
+       __le32 k_objectid;      /* object identifier */
+       union {
+               struct offset_v1 k_offset_v1;
+               struct offset_v2 k_offset_v2;
+       } ATTR_PACKED u;
+} ATTR_PACKED;
+
+struct in_core_key {
+       __u32 k_dir_id;         /* packing locality: by default parent
+                                  directory object id */
+       __u32 k_objectid;       /* object identifier */
+       __u64 k_offset;
+       __u8 k_type;
+};
+
+struct cpu_key {
+       struct in_core_key on_disk_key;
+       int version;
+       int key_length;         /* 3 in all cases but direct2indirect and
+                                  indirect2direct conversion */
+};
+
+/* Our function for comparing keys can compare keys of different
+   lengths.  It takes as a parameter the length of the keys it is to
+   compare.  These defines are used in determining what is to be passed
+   to it as that parameter. */
+#define REISERFS_FULL_KEY_LEN     4
+#define REISERFS_SHORT_KEY_LEN    2
+
+/* The result of the key compare */
+#define FIRST_GREATER 1
+#define SECOND_GREATER -1
+#define KEYS_IDENTICAL 0
+#define KEY_FOUND 1
+#define KEY_NOT_FOUND 0
+
+#define KEY_SIZE (sizeof(struct reiserfs_key))
+#define SHORT_KEY_SIZE (sizeof (__u32) + sizeof (__u32))
+
+/* return values for search_by_key and clones */
+#define ITEM_FOUND 1
+#define ITEM_NOT_FOUND 0
+#define ENTRY_FOUND 1
+#define ENTRY_NOT_FOUND 0
+#define DIRECTORY_NOT_FOUND -1
+#define REGULAR_FILE_FOUND -2
+#define DIRECTORY_FOUND -3
+#define BYTE_FOUND 1
+#define BYTE_NOT_FOUND 0
+#define FILE_NOT_FOUND -1
+
+#define POSITION_FOUND 1
+#define POSITION_NOT_FOUND 0
+
+// return values for reiserfs_find_entry and search_by_entry_key
+#define NAME_FOUND 1
+#define NAME_NOT_FOUND 0
+#define GOTO_PREVIOUS_ITEM 2
+#define NAME_FOUND_INVISIBLE 3
+
+/*  Everything in the filesystem is stored as a set of items.  The
+    item head contains the key of the item, its free space (for
+    indirect items) and specifies the location of the item itself
+    within the block.  */
+
+struct item_head {
+       /* Everything in the tree is found by searching for it based on
+        * its key.*/
+       struct reiserfs_key ih_key;
+       union {
+               /* The free space in the last unformatted node of an
+                  indirect item if this is an indirect item.  This
+                  equals 0xFFFF iff this is a direct item or stat data
+                  item. Note that the key, not this field, is used to
+                  determine the item type, and thus which field this
+                  union contains. */
+               __le16 ih_free_space_reserved;
+               /* Iff this is a directory item, this field equals the
+                  number of directory entries in the directory item. */
+               __le16 ih_entry_count;
+       } ATTR_PACKED u;
+       __le16 ih_item_len;     /* total size of the item body */
+       __le16 ih_item_location;        /* an offset to the item body
+                                        * within the block */
+       __le16 ih_version;      /* 0 for all old items, 2 for new
+                                  ones. Highest bit is set by fsck
+                                  temporary, cleaned after all
+                                  done */
+} ATTR_PACKED;
+/* size of item header     */
+#define IH_SIZE (sizeof(struct item_head))
+
+#define ih_free_space(ih)            le16_to_cpu((ih)->u.ih_free_space_reserved)
+#define ih_version(ih)               le16_to_cpu((ih)->ih_version)
+#define ih_entry_count(ih)           le16_to_cpu((ih)->u.ih_entry_count)
+#define ih_location(ih)              le16_to_cpu((ih)->ih_item_location)
+#define ih_item_len(ih)              le16_to_cpu((ih)->ih_item_len)
+
+#define unreachable_item(ih) (ih_version(ih) & (1 << 15))
+
+#define get_ih_free_space(ih) (ih_version (ih) == KEY_FORMAT_3_6 ? 0 : ih_free_space (ih))
+
+/* these operate on indirect items, where you've got an array of ints
+** at a possibly unaligned location.  These are a noop on ia32
+** 
+** p is the array of __u32, i is the index into the array, v is the value
+** to store there.
+*/
+#define get_block_num(p, i) le32_to_cpu(get_unaligned((p) + (i)))
+
+//
+// in old version uniqueness field shows key type
+//
+#define V1_SD_UNIQUENESS 0
+#define V1_INDIRECT_UNIQUENESS 0xfffffffe
+#define V1_DIRECT_UNIQUENESS 0xffffffff
+#define V1_DIRENTRY_UNIQUENESS 500
+#define V1_ANY_UNIQUENESS 555  // FIXME: comment is required
+
+//
+// here are conversion routines
+//
+/*
+static inline int uniqueness2type(__u32 uniqueness)
+{
+       switch ((int)uniqueness) {
+       case V1_SD_UNIQUENESS:
+               return TYPE_STAT_DATA;
+       case V1_INDIRECT_UNIQUENESS:
+               return TYPE_INDIRECT;
+       case V1_DIRECT_UNIQUENESS:
+               return TYPE_DIRECT;
+       case V1_DIRENTRY_UNIQUENESS:
+               return TYPE_DIRENTRY;
+       default:
+               reiserfs_warning(NULL, "vs-500: unknown uniqueness %d",
+                                uniqueness);
+       case V1_ANY_UNIQUENESS:
+               return TYPE_ANY;
+       }
+}
+
+static inline __u32 type2uniqueness(int type)
+{
+       switch (type) {
+       case TYPE_STAT_DATA:
+               return V1_SD_UNIQUENESS;
+       case TYPE_INDIRECT:
+               return V1_INDIRECT_UNIQUENESS;
+       case TYPE_DIRECT:
+               return V1_DIRECT_UNIQUENESS;
+       case TYPE_DIRENTRY:
+               return V1_DIRENTRY_UNIQUENESS;
+       default:
+               reiserfs_warning(NULL, "vs-501: unknown type %d", type);
+       case TYPE_ANY:
+               return V1_ANY_UNIQUENESS;
+       }
+}
+*/
+
+//
+// key is pointer to on disk key which is stored in le, result is cpu,
+// there is no way to get version of object from key, so, provide
+// version to these defines
+//
+/*
+static inline loff_t le_key_k_offset(int version,
+                                    const struct reiserfs_key *key)
+{
+       return (version == KEY_FORMAT_3_5) ?
+           le32_to_cpu(key->u.k_offset_v1.k_offset) :
+           offset_v2_k_offset(&(key->u.k_offset_v2));
+}
+
+static inline loff_t le_ih_k_offset(const struct item_head *ih)
+{
+       return le_key_k_offset(ih_version(ih), &(ih->ih_key));
+}
+
+static inline loff_t le_key_k_type(int version, const struct reiserfs_key *key)
+{
+       return (version == KEY_FORMAT_3_5) ?
+           uniqueness2type(le32_to_cpu(key->u.k_offset_v1.k_uniqueness)) :
+           offset_v2_k_type(&(key->u.k_offset_v2));
+}
+
+static inline loff_t le_ih_k_type(const struct item_head *ih)
+{
+       return le_key_k_type(ih_version(ih), &(ih->ih_key));
+}
+*/
+
+#define is_direntry_le_key(version,key) (le_key_k_type (version, key) == TYPE_DIRENTRY)
+#define is_direct_le_key(version,key) (le_key_k_type (version, key) == TYPE_DIRECT)
+#define is_indirect_le_key(version,key) (le_key_k_type (version, key) == TYPE_INDIRECT)
+#define is_statdata_le_key(version,key) (le_key_k_type (version, key) == TYPE_STAT_DATA)
+
+//
+// item header has version.
+//
+#define is_direntry_le_ih(ih) is_direntry_le_key (ih_version (ih), &((ih)->ih_key))
+#define is_direct_le_ih(ih) is_direct_le_key (ih_version (ih), &((ih)->ih_key))
+#define is_indirect_le_ih(ih) is_indirect_le_key (ih_version(ih), &((ih)->ih_key))
+#define is_statdata_le_ih(ih) is_statdata_le_key (ih_version (ih), &((ih)->ih_key))
+
+//
+// key is pointer to cpu key, result is cpu
+//
+/*
+static inline loff_t cpu_key_k_offset(const struct cpu_key *key)
+{
+       return key->on_disk_key.k_offset;
+}
+
+static inline loff_t cpu_key_k_type(const struct cpu_key *key)
+{
+       return key->on_disk_key.k_type;
+}
+
+static inline void cpu_key_k_offset_dec(struct cpu_key *key)
+{
+       key->on_disk_key.k_offset--;
+}
+*/
+
+#define is_direntry_cpu_key(key) (cpu_key_k_type (key) == TYPE_DIRENTRY)
+#define is_direct_cpu_key(key) (cpu_key_k_type (key) == TYPE_DIRECT)
+#define is_indirect_cpu_key(key) (cpu_key_k_type (key) == TYPE_INDIRECT)
+#define is_statdata_cpu_key(key) (cpu_key_k_type (key) == TYPE_STAT_DATA)
+
+/* are these used ? */
+#define is_direntry_cpu_ih(ih) (is_direntry_cpu_key (&((ih)->ih_key)))
+#define is_direct_cpu_ih(ih) (is_direct_cpu_key (&((ih)->ih_key)))
+#define is_indirect_cpu_ih(ih) (is_indirect_cpu_key (&((ih)->ih_key)))
+#define is_statdata_cpu_ih(ih) (is_statdata_cpu_key (&((ih)->ih_key)))
+
+#define I_K_KEY_IN_ITEM(p_s_ih, p_s_key, n_blocksize) \
+    ( ! COMP_SHORT_KEYS(p_s_ih, p_s_key) && \
+          I_OFF_BYTE_IN_ITEM(p_s_ih, k_offset (p_s_key), n_blocksize) )
+
+/* maximal length of item */
+#define MAX_ITEM_LEN(block_size) (block_size - BLKH_SIZE - IH_SIZE)
+#define MIN_ITEM_LEN 1
+
+/* object identifier for root dir */
+#define REISERFS_ROOT_OBJECTID 2
+#define REISERFS_ROOT_PARENT_OBJECTID 1
+
+/* 
+ * Picture represents a leaf of the S+tree
+ *  ______________________________________________________
+ * |      |  Array of     |                   |           |
+ * |Block |  Object-Item  |      F r e e      |  Objects- |
+ * | head |  Headers      |     S p a c e     |   Items   |
+ * |______|_______________|___________________|___________|
+ */
+
+/* Header of a disk block.  More precisely, header of a formatted leaf
+   or internal node, and not the header of an unformatted node. */
+struct block_head {
+       __le16 blk_level;       /* Level of a block in the tree. */
+       __le16 blk_nr_item;     /* Number of keys/items in a block. */
+       __le16 blk_free_space;  /* Block free space in bytes. */
+       __le16 blk_reserved;
+       /* dump this in v4/planA */
+       struct reiserfs_key blk_right_delim_key;        /* kept only for compatibility */
+};
+
+#define BLKH_SIZE                     (sizeof(struct block_head))
+#define blkh_level(p_blkh)            (le16_to_cpu((p_blkh)->blk_level))
+#define blkh_nr_item(p_blkh)          (le16_to_cpu((p_blkh)->blk_nr_item))
+#define blkh_free_space(p_blkh)       (le16_to_cpu((p_blkh)->blk_free_space))
+#define blkh_reserved(p_blkh)         (le16_to_cpu((p_blkh)->blk_reserved))
+#define blkh_right_delim_key(p_blkh)  ((p_blkh)->blk_right_delim_key)
+
+/*
+ * values for blk_level field of the struct block_head
+ */
+
+#define FREE_LEVEL 0           /* when node gets removed from the tree its
+                                  blk_level is set to FREE_LEVEL. It is then
+                                  used to see whether the node is still in the
+                                  tree */
+
+#define DISK_LEAF_NODE_LEVEL  1        /* Leaf node level. */
+
+/* Given the buffer head of a formatted node, resolve to the block head of that node. */
+#define B_BLK_HEAD(p_s_bh)            ((struct block_head *)((p_s_bh)->b_data))
+/* Number of items that are in buffer. */
+#define B_NR_ITEMS(p_s_bh)            (blkh_nr_item(B_BLK_HEAD(p_s_bh)))
+#define B_LEVEL(p_s_bh)               (blkh_level(B_BLK_HEAD(p_s_bh)))
+#define B_FREE_SPACE(p_s_bh)          (blkh_free_space(B_BLK_HEAD(p_s_bh)))
+
+/* Get right delimiting key. -- little endian */
+#define B_PRIGHT_DELIM_KEY(p_s_bh)   (&(blk_right_delim_key(B_BLK_HEAD(p_s_bh))
+
+/* Does the buffer contain a disk leaf. */
+#define B_IS_ITEMS_LEVEL(p_s_bh)     (B_LEVEL(p_s_bh) == DISK_LEAF_NODE_LEVEL)
+
+/* Does the buffer contain a disk internal node */
+#define B_IS_KEYS_LEVEL(p_s_bh)      (B_LEVEL(p_s_bh) > DISK_LEAF_NODE_LEVEL \
+                                            && B_LEVEL(p_s_bh) <= MAX_HEIGHT)
+
+/***************************************************************************/
+/*                             STAT DATA                                   */
+/***************************************************************************/
+
+//
+// old stat data is 32 bytes long. We are going to distinguish new one by
+// different size
+//
+struct stat_data_v1 {
+       __le16 sd_mode;         /* file type, permissions */
+       __le16 sd_nlink;        /* number of hard links */
+       __le16 sd_uid;          /* owner */
+       __le16 sd_gid;          /* group */
+       __le32 sd_size;         /* file size */
+       __le32 sd_atime;        /* time of last access */
+       __le32 sd_mtime;        /* time file was last modified  */
+       __le32 sd_ctime;        /* time inode (stat data) was last changed (except changes to sd_atime and sd_mtime) */
+       union {
+               __le32 sd_rdev;
+               __le32 sd_blocks;       /* number of blocks file uses */
+       } ATTR_PACKED u;
+       __le32 sd_first_direct_byte;    /* first byte of file which is stored
+                                          in a direct item: except that if it
+                                          equals 1 it is a symlink and if it
+                                          equals ~(__u32)0 there is no
+                                          direct item.  The existence of this
+                                          field really grates on me. Let's
+                                          replace it with a macro based on
+                                          sd_size and our tail suppression
+                                          policy.  Someday.  -Hans */
+} ATTR_PACKED;
+
+#define SD_V1_SIZE              (sizeof(struct stat_data_v1))
+#define stat_data_v1(ih)        (ih_version (ih) == KEY_FORMAT_3_5)
+#define sd_v1_mode(sdp)         (le16_to_cpu((sdp)->sd_mode))
+#define set_sd_v1_mode(sdp,v)   ((sdp)->sd_mode = cpu_to_le16(v))
+#define sd_v1_nlink(sdp)        (le16_to_cpu((sdp)->sd_nlink))
+#define set_sd_v1_nlink(sdp,v)  ((sdp)->sd_nlink = cpu_to_le16(v))
+#define sd_v1_uid(sdp)          (le16_to_cpu((sdp)->sd_uid))
+#define set_sd_v1_uid(sdp,v)    ((sdp)->sd_uid = cpu_to_le16(v))
+#define sd_v1_gid(sdp)          (le16_to_cpu((sdp)->sd_gid))
+#define set_sd_v1_gid(sdp,v)    ((sdp)->sd_gid = cpu_to_le16(v))
+#define sd_v1_size(sdp)         (le32_to_cpu((sdp)->sd_size))
+#define set_sd_v1_size(sdp,v)   ((sdp)->sd_size = cpu_to_le32(v))
+#define sd_v1_atime(sdp)        (le32_to_cpu((sdp)->sd_atime))
+#define set_sd_v1_atime(sdp,v)  ((sdp)->sd_atime = cpu_to_le32(v))
+#define sd_v1_mtime(sdp)        (le32_to_cpu((sdp)->sd_mtime))
+#define set_sd_v1_mtime(sdp,v)  ((sdp)->sd_mtime = cpu_to_le32(v))
+#define sd_v1_ctime(sdp)        (le32_to_cpu((sdp)->sd_ctime))
+#define set_sd_v1_ctime(sdp,v)  ((sdp)->sd_ctime = cpu_to_le32(v))
+#define sd_v1_rdev(sdp)         (le32_to_cpu((sdp)->u.sd_rdev))
+#define set_sd_v1_rdev(sdp,v)   ((sdp)->u.sd_rdev = cpu_to_le32(v))
+#define sd_v1_blocks(sdp)       (le32_to_cpu((sdp)->u.sd_blocks))
+#define set_sd_v1_blocks(sdp,v) ((sdp)->u.sd_blocks = cpu_to_le32(v))
+#define sd_v1_first_direct_byte(sdp) \
+                                (le32_to_cpu((sdp)->sd_first_direct_byte))
+#define set_sd_v1_first_direct_byte(sdp,v) \
+                                ((sdp)->sd_first_direct_byte = cpu_to_le32(v))
+
+/*
+#include <linux/ext2_fs.h>
+*/
+
+/* inode flags stored in sd_attrs (nee sd_reserved) */
+
+/* we want common flags to have the same values as in ext2,
+   so chattr(1) will work without problems */
+#define REISERFS_IMMUTABLE_FL EXT2_IMMUTABLE_FL
+#define REISERFS_APPEND_FL    EXT2_APPEND_FL
+#define REISERFS_SYNC_FL      EXT2_SYNC_FL
+#define REISERFS_NOATIME_FL   EXT2_NOATIME_FL
+#define REISERFS_NODUMP_FL    EXT2_NODUMP_FL
+#define REISERFS_SECRM_FL     EXT2_SECRM_FL
+#define REISERFS_UNRM_FL      EXT2_UNRM_FL
+#define REISERFS_COMPR_FL     EXT2_COMPR_FL
+#define REISERFS_NOTAIL_FL    EXT2_NOTAIL_FL
+
+/* persistent flags that file inherits from the parent directory */
+#define REISERFS_INHERIT_MASK ( REISERFS_IMMUTABLE_FL |        \
+                               REISERFS_SYNC_FL |      \
+                               REISERFS_NOATIME_FL |   \
+                               REISERFS_NODUMP_FL |    \
+                               REISERFS_SECRM_FL |     \
+                               REISERFS_COMPR_FL |     \
+                               REISERFS_NOTAIL_FL )
+
+/* Stat Data on disk (reiserfs version of UFS disk inode minus the
+   address blocks) */
+struct stat_data {
+       __le16 sd_mode;         /* file type, permissions */
+       __le16 sd_attrs;        /* persistent inode flags */
+       __le32 sd_nlink;        /* number of hard links */
+       __le64 sd_size;         /* file size */
+       __le32 sd_uid;          /* owner */
+       __le32 sd_gid;          /* group */
+       __le32 sd_atime;        /* time of last access */
+       __le32 sd_mtime;        /* time file was last modified  */
+       __le32 sd_ctime;        /* time inode (stat data) was last changed (except changes to sd_atime and sd_mtime) */
+       __le32 sd_blocks;
+       union {
+               __le32 sd_rdev;
+               __le32 sd_generation;
+               //__le32 sd_first_direct_byte;
+               /* first byte of file which is stored in a
+                  direct item: except that if it equals 1
+                  it is a symlink and if it equals
+                  ~(__u32)0 there is no direct item.  The
+                  existence of this field really grates
+                  on me. Let's replace it with a macro
+                  based on sd_size and our tail
+                  suppression policy? */
+       } ATTR_PACKED u;
+} ATTR_PACKED;
+//
+// this is 44 bytes long
+//
+#define SD_SIZE (sizeof(struct stat_data))
+#define SD_V2_SIZE              SD_SIZE
+#define stat_data_v2(ih)        (ih_version (ih) == KEY_FORMAT_3_6)
+#define sd_v2_mode(sdp)         (le16_to_cpu((sdp)->sd_mode))
+#define set_sd_v2_mode(sdp,v)   ((sdp)->sd_mode = cpu_to_le16(v))
+/* sd_reserved */
+/* set_sd_reserved */
+#define sd_v2_nlink(sdp)        (le32_to_cpu((sdp)->sd_nlink))
+#define set_sd_v2_nlink(sdp,v)  ((sdp)->sd_nlink = cpu_to_le32(v))
+#define sd_v2_size(sdp)         (le64_to_cpu((sdp)->sd_size))
+#define set_sd_v2_size(sdp,v)   ((sdp)->sd_size = cpu_to_le64(v))
+#define sd_v2_uid(sdp)          (le32_to_cpu((sdp)->sd_uid))
+#define set_sd_v2_uid(sdp,v)    ((sdp)->sd_uid = cpu_to_le32(v))
+#define sd_v2_gid(sdp)          (le32_to_cpu((sdp)->sd_gid))
+#define set_sd_v2_gid(sdp,v)    ((sdp)->sd_gid = cpu_to_le32(v))
+#define sd_v2_atime(sdp)        (le32_to_cpu((sdp)->sd_atime))
+#define set_sd_v2_atime(sdp,v)  ((sdp)->sd_atime = cpu_to_le32(v))
+#define sd_v2_mtime(sdp)        (le32_to_cpu((sdp)->sd_mtime))
+#define set_sd_v2_mtime(sdp,v)  ((sdp)->sd_mtime = cpu_to_le32(v))
+#define sd_v2_ctime(sdp)        (le32_to_cpu((sdp)->sd_ctime))
+#define set_sd_v2_ctime(sdp,v)  ((sdp)->sd_ctime = cpu_to_le32(v))
+#define sd_v2_blocks(sdp)       (le32_to_cpu((sdp)->sd_blocks))
+#define set_sd_v2_blocks(sdp,v) ((sdp)->sd_blocks = cpu_to_le32(v))
+#define sd_v2_rdev(sdp)         (le32_to_cpu((sdp)->u.sd_rdev))
+#define set_sd_v2_rdev(sdp,v)   ((sdp)->u.sd_rdev = cpu_to_le32(v))
+#define sd_v2_generation(sdp)   (le32_to_cpu((sdp)->u.sd_generation))
+#define set_sd_v2_generation(sdp,v) ((sdp)->u.sd_generation = cpu_to_le32(v))
+#define sd_v2_attrs(sdp)         (le16_to_cpu((sdp)->sd_attrs))
+#define set_sd_v2_attrs(sdp,v)   ((sdp)->sd_attrs = cpu_to_le16(v))
+
+/***************************************************************************/
+/*                      DIRECTORY STRUCTURE                                */
+/***************************************************************************/
+/* 
+   Picture represents the structure of directory items
+   ________________________________________________
+   |  Array of     |   |     |        |       |   |
+   | directory     |N-1| N-2 | ....   |   1st |0th|
+   | entry headers |   |     |        |       |   |
+   |_______________|___|_____|________|_______|___|
+                    <----   directory entries         ------>
+
+ First directory item has k_offset component 1. We store "." and ".."
+ in one item, always, we never split "." and ".." into differing
+ items.  This makes, among other things, the code for removing
+ directories simpler. */
+#define SD_OFFSET  0
+#define SD_UNIQUENESS 0
+#define DOT_OFFSET 1
+#define DOT_DOT_OFFSET 2
+#define DIRENTRY_UNIQUENESS 500
+
+/* */
+#define FIRST_ITEM_OFFSET 1
+
+/*
+   Q: How to get key of object pointed to by entry from entry?  
+
+   A: Each directory entry has its header. This header has deh_dir_id and deh_objectid fields, those are key
+      of object, entry points to */
+
+/* NOT IMPLEMENTED:   
+   Directory will someday contain stat data of object */
+
+struct reiserfs_de_head {
+       __le32 deh_offset;      /* third component of the directory entry key */
+       __le32 deh_dir_id;      /* objectid of the parent directory of the object, that is referenced
+                                  by directory entry */
+       __le32 deh_objectid;    /* objectid of the object, that is referenced by directory entry */
+       __le16 deh_location;    /* offset of name in the whole item */
+       __le16 deh_state;       /* whether 1) entry contains stat data (for future), and 2) whether
+                                  entry is hidden (unlinked) */
+} ATTR_PACKED;
+#define DEH_SIZE                  sizeof(struct reiserfs_de_head)
+#define deh_offset(p_deh)         (le32_to_cpu((p_deh)->deh_offset))
+#define deh_dir_id(p_deh)         (le32_to_cpu((p_deh)->deh_dir_id))
+#define deh_objectid(p_deh)       (le32_to_cpu((p_deh)->deh_objectid))
+#define deh_location(p_deh)       (le16_to_cpu((p_deh)->deh_location))
+#define deh_state(p_deh)          (le16_to_cpu((p_deh)->deh_state))
+
+#define put_deh_offset(p_deh,v)   ((p_deh)->deh_offset = cpu_to_le32((v)))
+#define put_deh_dir_id(p_deh,v)   ((p_deh)->deh_dir_id = cpu_to_le32((v)))
+#define put_deh_objectid(p_deh,v) ((p_deh)->deh_objectid = cpu_to_le32((v)))
+#define put_deh_location(p_deh,v) ((p_deh)->deh_location = cpu_to_le16((v)))
+#define put_deh_state(p_deh,v)    ((p_deh)->deh_state = cpu_to_le16((v)))
+
+/* empty directory contains two entries "." and ".." and their headers */
+#define EMPTY_DIR_SIZE \
+(DEH_SIZE * 2 + ROUND_UP (strlen (".")) + ROUND_UP (strlen ("..")))
+
+/* old format directories have this size when empty */
+#define EMPTY_DIR_SIZE_V1 (DEH_SIZE * 2 + 3)
+
+#define DEH_Statdata 0         /* not used now */
+#define DEH_Visible 2
+
+/* 64 bit systems (and the S/390) need to be aligned explicitly -jdm */
+#if BITS_PER_LONG == 64 || defined(__s390__) || defined(__hppa__)
+#   define ADDR_UNALIGNED_BITS  (3)
+#endif
+
+/* These are only used to manipulate deh_state.
+ * Because of this, we'll use the ext2_ bit routines,
+ * since they are little endian */
+#ifdef ADDR_UNALIGNED_BITS
+
+#   define aligned_address(addr)           ((void *)((long)(addr) & ~((1UL << ADDR_UNALIGNED_BITS) - 1)))
+#   define unaligned_offset(addr)          (((int)((long)(addr) & ((1 << ADDR_UNALIGNED_BITS) - 1))) << 3)
+
+#   define set_bit_unaligned(nr, addr)     ext2_set_bit((nr) + unaligned_offset(addr), aligned_address(addr))
+#   define clear_bit_unaligned(nr, addr)   ext2_clear_bit((nr) + unaligned_offset(addr), aligned_address(addr))
+#   define test_bit_unaligned(nr, addr)    ext2_test_bit((nr) + unaligned_offset(addr), aligned_address(addr))
+
+#else
+
+#   define set_bit_unaligned(nr, addr)     ext2_set_bit(nr, addr)
+#   define clear_bit_unaligned(nr, addr)   ext2_clear_bit(nr, addr)
+#   define test_bit_unaligned(nr, addr)    ext2_test_bit(nr, addr)
+
+#endif
+
+#define mark_de_with_sd(deh)        set_bit_unaligned (DEH_Statdata, &((deh)->deh_state))
+#define mark_de_without_sd(deh)     clear_bit_unaligned (DEH_Statdata, &((deh)->deh_state))
+#define mark_de_visible(deh)       set_bit_unaligned (DEH_Visible, &((deh)->deh_state))
+#define mark_de_hidden(deh)        clear_bit_unaligned (DEH_Visible, &((deh)->deh_state))
+
+#define de_with_sd(deh)                    test_bit_unaligned (DEH_Statdata, &((deh)->deh_state))
+#define de_visible(deh)                    test_bit_unaligned (DEH_Visible, &((deh)->deh_state))
+#define de_hidden(deh)             !test_bit_unaligned (DEH_Visible, &((deh)->deh_state))
+
+/*
+extern void make_empty_dir_item_v1(char *body, __le32 dirid, __le32 objid,
+                                  __le32 par_dirid, __le32 par_objid);
+extern void make_empty_dir_item(char *body, __le32 dirid, __le32 objid,
+                               __le32 par_dirid, __le32 par_objid);
+*/
+
+/* array of the entry headers */
+ /* get item body */
+#define B_I_PITEM(bh,ih) ( (bh)->b_data + ih_location(ih) )
+#define B_I_DEH(bh,ih) ((struct reiserfs_de_head *)(B_I_PITEM(bh,ih)))
+
+/* length of the directory entry in directory item. This define
+   calculates length of i-th directory entry using directory entry
+   locations from dir entry head. When it calculates length of 0-th
+   directory entry, it uses length of whole item in place of entry
+   location of the non-existent following entry in the calculation.
+   See picture above.*/
+/*
+#define I_DEH_N_ENTRY_LENGTH(ih,deh,i) \
+((i) ? (deh_location((deh)-1) - deh_location((deh))) : (ih_item_len((ih)) - deh_location((deh))))
+*/
+/*
+static inline int entry_length(const struct buffer_head *bh,
+                              const struct item_head *ih, int pos_in_item)
+{
+       struct reiserfs_de_head *deh;
+
+       deh = B_I_DEH(bh, ih) + pos_in_item;
+       if (pos_in_item)
+               return deh_location(deh - 1) - deh_location(deh);
+
+       return ih_item_len(ih) - deh_location(deh);
+}
+*/
+
+/* number of entries in the directory item, depends on ENTRY_COUNT being at the start of directory dynamic data. */
+#define I_ENTRY_COUNT(ih) (ih_entry_count((ih)))
+
+/* name by bh, ih and entry_num */
+#define B_I_E_NAME(bh,ih,entry_num) ((char *)(bh->b_data + ih_location(ih) + deh_location(B_I_DEH(bh,ih)+(entry_num))))
+
+// two entries per block (at least)
+#define REISERFS_MAX_NAME(block_size) 255
+
+/* this structure is used for operations on directory entries. It is
+   not a disk structure. */
+/* When reiserfs_find_entry or search_by_entry_key find directory
+   entry, they return filled reiserfs_dir_entry structure */
+struct reiserfs_dir_entry {
+       struct buffer_head *de_bh;
+       int de_item_num;
+       struct item_head *de_ih;
+       int de_entry_num;
+       struct reiserfs_de_head *de_deh;
+       int de_entrylen;
+       int de_namelen;
+       char *de_name;
+       unsigned long *de_gen_number_bit_string;
+
+       __u32 de_dir_id;
+       __u32 de_objectid;
+
+       struct cpu_key de_entry_key;
+};
+
+/* these defines are useful when a particular member of a reiserfs_dir_entry is needed */
+
+/* pointer to file name, stored in entry */
+#define B_I_DEH_ENTRY_FILE_NAME(bh,ih,deh) (B_I_PITEM (bh, ih) + deh_location(deh))
+
+/* length of name */
+#define I_DEH_N_ENTRY_FILE_NAME_LENGTH(ih,deh,entry_num) \
+(I_DEH_N_ENTRY_LENGTH (ih, deh, entry_num) - (de_with_sd (deh) ? SD_SIZE : 0))
+
+/* hash value occupies bits from 7 up to 30 */
+#define GET_HASH_VALUE(offset) ((offset) & 0x7fffff80LL)
+/* generation number occupies 7 bits starting from 0 up to 6 */
+#define GET_GENERATION_NUMBER(offset) ((offset) & 0x7fLL)
+#define MAX_GENERATION_NUMBER  127
+
+#define SET_GENERATION_NUMBER(offset,gen_number) (GET_HASH_VALUE(offset)|(gen_number))
+
+/*
+ * Picture represents an internal node of the reiserfs tree
+ *  ______________________________________________________
+ * |      |  Array of     |  Array of         |  Free     |
+ * |block |    keys       |  pointers         | space     |
+ * | head |      N        |      N+1          |           |
+ * |______|_______________|___________________|___________|
+ */
+
+/***************************************************************************/
+/*                      DISK CHILD                                         */
+/***************************************************************************/
+/* Disk child pointer: The pointer from an internal node of the tree
+   to a node that is on disk. */
+struct disk_child {
+       __le32 dc_block_number; /* Disk child's block number. */
+       __le16 dc_size;         /* Disk child's used space.   */
+       __le16 dc_reserved;
+};
+
+#define DC_SIZE (sizeof(struct disk_child))
+#define dc_block_number(dc_p)  (le32_to_cpu((dc_p)->dc_block_number))
+#define dc_size(dc_p)          (le16_to_cpu((dc_p)->dc_size))
+
+/* Get disk child by buffer header and position in the tree node. */
+#define B_N_CHILD(p_s_bh,n_pos)  ((struct disk_child *)\
+((p_s_bh)->b_data+BLKH_SIZE+B_NR_ITEMS(p_s_bh)*KEY_SIZE+DC_SIZE*(n_pos)))
+
+/* Get disk child number by buffer header and position in the tree node. */
+#define B_N_CHILD_NUM(p_s_bh,n_pos) (dc_block_number(B_N_CHILD(p_s_bh,n_pos)))
+#define PUT_B_N_CHILD_NUM(p_s_bh,n_pos, val) (put_dc_block_number(B_N_CHILD(p_s_bh,n_pos), val ))
+
+ /* maximal value of field child_size in structure disk_child */
+ /* child size is the combined size of all items and their headers */
+#define MAX_CHILD_SIZE(bh) ((int)( (bh)->b_size - BLKH_SIZE ))
+
+/* amount of used space in buffer (not including block head) */
+#define B_CHILD_SIZE(cur) (MAX_CHILD_SIZE(cur)-(B_FREE_SPACE(cur)))
+
+/* max and min number of keys in internal node */
+#define MAX_NR_KEY(bh) ( (MAX_CHILD_SIZE(bh)-DC_SIZE)/(KEY_SIZE+DC_SIZE) )
+#define MIN_NR_KEY(bh)    (MAX_NR_KEY(bh)/2)
+
+/***************************************************************************/
+/*                      PATH STRUCTURES AND DEFINES                        */
+/***************************************************************************/
+
+/* Search_by_key fills up the path from the root to the leaf as it descends the tree looking for the
+   key.  It uses reiserfs_bread to try to find buffers in the cache given their block number.  If it
+   does not find them in the cache it reads them from disk.  For each node search_by_key finds using
+   reiserfs_bread it then uses bin_search to look through that node.  bin_search will find the
+   position of the block_number of the next node if it is looking through an internal node.  If it
+   is looking through a leaf node bin_search will find the position of the item which has key either
+   equal to given key, or which is the maximal key less than the given key. */
+
+struct path_element {
+       struct buffer_head *pe_buffer;  /* Pointer to the buffer at the path in the tree. */
+       int pe_position;        /* Position in the tree node which is placed in the */
+       /* buffer above.                                  */
+};
+
+#define MAX_HEIGHT 5           /* maximal height of a tree. don't change this without changing JOURNAL_PER_BALANCE_CNT */
+#define EXTENDED_MAX_HEIGHT         7  /* Must be equals MAX_HEIGHT + FIRST_PATH_ELEMENT_OFFSET */
+#define FIRST_PATH_ELEMENT_OFFSET   2  /* Must be equal to at least 2. */
+
+#define ILLEGAL_PATH_ELEMENT_OFFSET 1  /* Must be equal to FIRST_PATH_ELEMENT_OFFSET - 1 */
+#define MAX_FEB_SIZE 6         /* this MUST be MAX_HEIGHT + 1. See about FEB below */
+
+/* We need to keep track of who the ancestors of nodes are.  When we
+   perform a search we record which nodes were visited while
+   descending the tree looking for the node we searched for. This list
+   of nodes is called the path.  This information is used while
+   performing balancing.  Note that this path information may become
+   invalid, and this means we must check it when using it to see if it
+   is still valid. You'll need to read search_by_key and the comments
+   in it, especially about decrement_counters_in_path(), to understand
+   this structure.  
+
+Paths make the code so much harder to work with and debug.... An
+enormous number of bugs are due to them, and trying to write or modify
+code that uses them just makes my head hurt.  They are based on an
+excessive effort to avoid disturbing the precious VFS code.:-( The
+gods only know how we are going to SMP the code that uses them.
+znodes are the way! */
+
+#define PATH_READA     0x1     /* do read ahead */
+#define PATH_READA_BACK 0x2    /* read backwards */
+
+struct path {
+       int path_length;        /* Length of the array above.   */
+       int reada;
+       struct path_element path_elements[EXTENDED_MAX_HEIGHT]; /* Array of the path elements.  */
+       int pos_in_item;
+};
+
+#define pos_in_item(path) ((path)->pos_in_item)
+
+#define INITIALIZE_PATH(var) \
+struct path var = {.path_length = ILLEGAL_PATH_ELEMENT_OFFSET, .reada = 0,}
+
+/* Get path element by path and path position. */
+#define PATH_OFFSET_PELEMENT(p_s_path,n_offset)  ((p_s_path)->path_elements +(n_offset))
+
+/* Get buffer header at the path by path and path position. */
+#define PATH_OFFSET_PBUFFER(p_s_path,n_offset)   (PATH_OFFSET_PELEMENT(p_s_path,n_offset)->pe_buffer)
+
+/* Get position in the element at the path by path and path position. */
+#define PATH_OFFSET_POSITION(p_s_path,n_offset) (PATH_OFFSET_PELEMENT(p_s_path,n_offset)->pe_position)
+
+#define PATH_PLAST_BUFFER(p_s_path) (PATH_OFFSET_PBUFFER((p_s_path), (p_s_path)->path_length))
+                               /* you know, to the person who didn't
+                                  write this the macro name does not
+                                  at first suggest what it does.
+                                  Maybe POSITION_FROM_PATH_END? Or
+                                  maybe we should just focus on
+                                  dumping paths... -Hans */
+#define PATH_LAST_POSITION(p_s_path) (PATH_OFFSET_POSITION((p_s_path), (p_s_path)->path_length))
+
+#define PATH_PITEM_HEAD(p_s_path)    B_N_PITEM_HEAD(PATH_PLAST_BUFFER(p_s_path),PATH_LAST_POSITION(p_s_path))
+
+/* in do_balance leaf has h == 0 in contrast with path structure,
+   where root has level == 0. That is why we need these defines */
+#define PATH_H_PBUFFER(p_s_path, h) PATH_OFFSET_PBUFFER (p_s_path, p_s_path->path_length - (h))        /* tb->S[h] */
+#define PATH_H_PPARENT(path, h) PATH_H_PBUFFER (path, (h) + 1) /* tb->F[h] or tb->S[0]->b_parent */
+#define PATH_H_POSITION(path, h) PATH_OFFSET_POSITION (path, path->path_length - (h))
+#define PATH_H_B_ITEM_ORDER(path, h) PATH_H_POSITION(path, h + 1)      /* tb->S[h]->b_item_order */
+
+#define PATH_H_PATH_OFFSET(p_s_path, n_h) ((p_s_path)->path_length - (n_h))
+
+#define get_last_bh(path) PATH_PLAST_BUFFER(path)
+#define get_ih(path) PATH_PITEM_HEAD(path)
+#define get_item_pos(path) PATH_LAST_POSITION(path)
+#define get_item(path) ((void *)B_N_PITEM(PATH_PLAST_BUFFER(path), PATH_LAST_POSITION (path)))
+#define item_moved(ih,path) comp_items(ih, path)
+#define path_changed(ih,path) comp_items (ih, path)
+
+/***************************************************************************/
+/*                       MISC                                              */
+/***************************************************************************/
+
+/* Size of pointer to the unformatted node. */
+#define UNFM_P_SIZE (sizeof(unp_t))
+#define UNFM_P_SHIFT 2
+
+// in in-core inode key is stored on le form
+#define INODE_PKEY(inode) ((struct reiserfs_key *)(REISERFS_I(inode)->i_key))
+
+#define MAX_UL_INT 0xffffffff
+#define MAX_INT    0x7ffffff
+#define MAX_US_INT 0xffff
+
+// reiserfs version 2 has max offset 60 bits. Version 1 - 32 bit offset
+#define U32_MAX (~(__u32)0)
+
+/*
+static inline loff_t max_reiserfs_offset(struct inode *inode)
+{
+       if (get_inode_item_key_version(inode) == KEY_FORMAT_3_5)
+               return (loff_t) U32_MAX;
+
+       return (loff_t) ((~(__u64) 0) >> 4);
+}
+*/
+
+/*#define MAX_KEY_UNIQUENESS   MAX_UL_INT*/
+#define MAX_KEY_OBJECTID       MAX_UL_INT
+
+#define MAX_B_NUM  MAX_UL_INT
+#define MAX_FC_NUM MAX_US_INT
+
+/* the purpose is to detect overflow of an unsigned short */
+#define REISERFS_LINK_MAX (MAX_US_INT - 1000)
+
+/* The following defines are used in reiserfs_insert_item and reiserfs_append_item  */
+#define REISERFS_KERNEL_MEM            0       /* reiserfs kernel memory mode  */
+#define REISERFS_USER_MEM              1       /* reiserfs user memory mode            */
+
+#define fs_generation(s) (REISERFS_SB(s)->s_generation_counter)
+#define get_generation(s) atomic_read (&fs_generation(s))
+#define FILESYSTEM_CHANGED_TB(tb)  (get_generation((tb)->tb_sb) != (tb)->fs_gen)
+#define __fs_changed(gen,s) (gen != get_generation (s))
+#define fs_changed(gen,s) ({cond_resched(); __fs_changed(gen, s);})
+
+/***************************************************************************/
+/*                  FIXATE NODES                                           */
+/***************************************************************************/
+
+#define VI_TYPE_LEFT_MERGEABLE 1
+#define VI_TYPE_RIGHT_MERGEABLE 2
+
+/* To make any changes in the tree we always first find node, that
+   contains item to be changed/deleted or place to insert a new
+   item. We call this node S. To do balancing we need to decide what
+   we will shift to left/right neighbor, or to a new node, where new
+   item will be etc. To make this analysis simpler we build virtual
+   node. Virtual node is an array of items, that will replace items of
+   node S. (For instance if we are going to delete an item, virtual
+   node does not contain it). Virtual node keeps information about
+   item sizes and types, mergeability of first and last items, sizes
+   of all entries in directory item. We use this array of items when
+   calculating what we can shift to neighbors and how many nodes we
+   have to have if we do not any shiftings, if we shift to left/right
+   neighbor or to both. */
+struct virtual_item {
+       int vi_index;           // index in the array of item operations
+       unsigned short vi_type; // left/right mergeability
+       unsigned short vi_item_len;     /* length of item that it will have after balancing */
+       struct item_head *vi_ih;
+       const char *vi_item;    // body of item (old or new)
+       const void *vi_new_data;        // 0 always but paste mode
+       void *vi_uarea;         // item specific area
+};
+
+struct virtual_node {
+       char *vn_free_ptr;      /* this is a pointer to the free space in the buffer */
+       unsigned short vn_nr_item;      /* number of items in virtual node */
+       short vn_size;          /* size of node , that node would have if it has unlimited size and no balancing is performed */
+       short vn_mode;          /* mode of balancing (paste, insert, delete, cut) */
+       short vn_affected_item_num;
+       short vn_pos_in_item;
+       struct item_head *vn_ins_ih;    /* item header of inserted item, 0 for other modes */
+       const void *vn_data;
+       struct virtual_item *vn_vi;     /* array of items (including a new one, excluding item to be deleted) */
+};
+
+/* used by directory items when creating virtual nodes */
+struct direntry_uarea {
+       int flags;
+       __u16 entry_count;
+       __u16 entry_sizes[1];
+} ATTR_PACKED;
+
+/***************************************************************************/
+/*                  TREE BALANCE                                           */
+/***************************************************************************/
+
+/* This temporary structure is used in tree balance algorithms, and
+   constructed as we go to the extent that its various parts are
+   needed.  It contains arrays of nodes that can potentially be
+   involved in the balancing of node S, and parameters that define how
+   each of the nodes must be balanced.  Note that in these algorithms
+   for balancing the worst case is to need to balance the current node
+   S and the left and right neighbors and all of their parents plus
+   create a new node.  We implement S1 balancing for the leaf nodes
+   and S0 balancing for the internal nodes (S1 and S0 are defined in
+   our papers.)*/
+
+#define MAX_FREE_BLOCK 7       /* size of the array of buffers to free at end of do_balance */
+
+/* maximum number of FEB blocknrs on a single level */
+#define MAX_AMOUNT_NEEDED 2
+
+/* someday somebody will prefix every field in this struct with tb_ */
+struct tree_balance {
+       int tb_mode;
+       int need_balance_dirty;
+       struct super_block *tb_sb;
+       struct reiserfs_transaction_handle *transaction_handle;
+       struct path *tb_path;
+       struct buffer_head *L[MAX_HEIGHT];      /* array of left neighbors of nodes in the path */
+       struct buffer_head *R[MAX_HEIGHT];      /* array of right neighbors of nodes in the path */
+       struct buffer_head *FL[MAX_HEIGHT];     /* array of fathers of the left  neighbors      */
+       struct buffer_head *FR[MAX_HEIGHT];     /* array of fathers of the right neighbors      */
+       struct buffer_head *CFL[MAX_HEIGHT];    /* array of common parents of center node and its left neighbor  */
+       struct buffer_head *CFR[MAX_HEIGHT];    /* array of common parents of center node and its right neighbor */
+
+       struct buffer_head *FEB[MAX_FEB_SIZE];  /* array of empty buffers. Number of buffers in array equals
+                                                  cur_blknum. */
+       struct buffer_head *used[MAX_FEB_SIZE];
+       struct buffer_head *thrown[MAX_FEB_SIZE];
+       int lnum[MAX_HEIGHT];   /* array of number of items which must be
+                                  shifted to the left in order to balance the
+                                  current node; for leaves includes item that
+                                  will be partially shifted; for internal
+                                  nodes, it is the number of child pointers
+                                  rather than items. It includes the new item
+                                  being created. The code sometimes subtracts
+                                  one to get the number of wholly shifted
+                                  items for other purposes. */
+       int rnum[MAX_HEIGHT];   /* substitute right for left in comment above */
+       int lkey[MAX_HEIGHT];   /* array indexed by height h mapping the key delimiting L[h] and
+                                  S[h] to its item number within the node CFL[h] */
+       int rkey[MAX_HEIGHT];   /* substitute r for l in comment above */
+       int insert_size[MAX_HEIGHT];    /* the number of bytes by we are trying to add or remove from
+                                          S[h]. A negative value means removing.  */
+       int blknum[MAX_HEIGHT]; /* number of nodes that will replace node S[h] after
+                                  balancing on the level h of the tree.  If 0 then S is
+                                  being deleted, if 1 then S is remaining and no new nodes
+                                  are being created, if 2 or 3 then 1 or 2 new nodes is
+                                  being created */
+
+       /* fields that are used only for balancing leaves of the tree */
+       int cur_blknum;         /* number of empty blocks having been already allocated                 */
+       int s0num;              /* number of items that fall into left most  node when S[0] splits     */
+       int s1num;              /* number of items that fall into first  new node when S[0] splits     */
+       int s2num;              /* number of items that fall into second new node when S[0] splits     */
+       int lbytes;             /* number of bytes which can flow to the left neighbor from the        left    */
+       /* most liquid item that cannot be shifted from S[0] entirely         */
+       /* if -1 then nothing will be partially shifted */
+       int rbytes;             /* number of bytes which will flow to the right neighbor from the right        */
+       /* most liquid item that cannot be shifted from S[0] entirely         */
+       /* if -1 then nothing will be partially shifted                           */
+       int s1bytes;            /* number of bytes which flow to the first  new node when S[0] splits   */
+       /* note: if S[0] splits into 3 nodes, then items do not need to be cut  */
+       int s2bytes;
+       struct buffer_head *buf_to_free[MAX_FREE_BLOCK];        /* buffers which are to be freed after do_balance finishes by unfix_nodes */
+       char *vn_buf;           /* kmalloced memory. Used to create
+                                  virtual node and keep map of
+                                  dirtied bitmap blocks */
+       int vn_buf_size;        /* size of the vn_buf */
+       struct virtual_node *tb_vn;     /* VN starts after bitmap of bitmap blocks */
+
+       int fs_gen;             /* saved value of `reiserfs_generation' counter
+                                  see FILESYSTEM_CHANGED() macro in reiserfs_fs.h */
+#ifdef DISPLACE_NEW_PACKING_LOCALITIES
+       struct in_core_key key; /* key pointer, to pass to block allocator or
+                                  another low-level subsystem */
+#endif
+};
+
+/* These are modes of balancing */
+
+/* When inserting an item. */
+#define M_INSERT       'i'
+/* When inserting into (directories only) or appending onto an already
+   existant item. */
+#define M_PASTE                'p'
+/* When deleting an item. */
+#define M_DELETE       'd'
+/* When truncating an item or removing an entry from a (directory) item. */
+#define M_CUT          'c'
+
+/* used when balancing on leaf level skipped (in reiserfsck) */
+#define M_INTERNAL     'n'
+
+/* When further balancing is not needed, then do_balance does not need
+   to be called. */
+#define M_SKIP_BALANCING               's'
+#define M_CONVERT      'v'
+
+/* modes of leaf_move_items */
+#define LEAF_FROM_S_TO_L 0
+#define LEAF_FROM_S_TO_R 1
+#define LEAF_FROM_R_TO_L 2
+#define LEAF_FROM_L_TO_R 3
+#define LEAF_FROM_S_TO_SNEW 4
+
+#define FIRST_TO_LAST 0
+#define LAST_TO_FIRST 1
+
+/* used in do_balance for passing parent of node information that has
+   been gotten from tb struct */
+struct buffer_info {
+       struct tree_balance *tb;
+       struct buffer_head *bi_bh;
+       struct buffer_head *bi_parent;
+       int bi_position;
+};
+
+/* there are 4 types of items: stat data, directory item, indirect, direct.
++-------------------+------------+--------------+------------+
+|                  |  k_offset  | k_uniqueness | mergeable? |
++-------------------+------------+--------------+------------+
+|     stat data     |  0        |      0       |   no       |
++-------------------+------------+--------------+------------+
+| 1st directory item| DOT_OFFSET |DIRENTRY_UNIQUENESS|   no       | 
+| non 1st directory | hash value |              |   yes      |
+|     item          |            |              |            |
++-------------------+------------+--------------+------------+
+| indirect item     | offset + 1 |TYPE_INDIRECT |   if this is not the first indirect item of the object
++-------------------+------------+--------------+------------+
+| direct item       | offset + 1 |TYPE_DIRECT   | if not this is not the first direct item of the object
++-------------------+------------+--------------+------------+
+*/
+
+struct item_operations {
+       int (*bytes_number) (struct item_head * ih, int block_size);
+       void (*decrement_key) (struct cpu_key *);
+       int (*is_left_mergeable) (struct reiserfs_key * ih,
+                                 unsigned long bsize);
+       void (*print_item) (struct item_head *, char *item);
+       void (*check_item) (struct item_head *, char *item);
+
+       int (*create_vi) (struct virtual_node * vn, struct virtual_item * vi,
+                         int is_affected, int insert_size);
+       int (*check_left) (struct virtual_item * vi, int free,
+                          int start_skip, int end_skip);
+       int (*check_right) (struct virtual_item * vi, int free);
+       int (*part_size) (struct virtual_item * vi, int from, int to);
+       int (*unit_num) (struct virtual_item * vi);
+       void (*print_vi) (struct virtual_item * vi);
+};
+
+extern struct item_operations *item_ops[TYPE_ANY + 1];
+
+#define op_bytes_number(ih,bsize)                    item_ops[le_ih_k_type (ih)]->bytes_number (ih, bsize)
+#define op_is_left_mergeable(key,bsize)              item_ops[le_key_k_type (le_key_version (key), key)]->is_left_mergeable (key, bsize)
+#define op_print_item(ih,item)                       item_ops[le_ih_k_type (ih)]->print_item (ih, item)
+#define op_check_item(ih,item)                       item_ops[le_ih_k_type (ih)]->check_item (ih, item)
+#define op_create_vi(vn,vi,is_affected,insert_size)  item_ops[le_ih_k_type ((vi)->vi_ih)]->create_vi (vn,vi,is_affected,insert_size)
+#define op_check_left(vi,free,start_skip,end_skip) item_ops[(vi)->vi_index]->check_left (vi, free, start_skip, end_skip)
+#define op_check_right(vi,free)                      item_ops[(vi)->vi_index]->check_right (vi, free)
+#define op_part_size(vi,from,to)                     item_ops[(vi)->vi_index]->part_size (vi, from, to)
+#define op_unit_num(vi)                                     item_ops[(vi)->vi_index]->unit_num (vi)
+#define op_print_vi(vi)                              item_ops[(vi)->vi_index]->print_vi (vi)
+
+#define COMP_SHORT_KEYS comp_short_keys
+
+/* number of blocks pointed to by the indirect item */
+#define I_UNFM_NUM(p_s_ih)     ( ih_item_len(p_s_ih) / UNFM_P_SIZE )
+
+/* the used space within the unformatted node corresponding to pos within the item pointed to by ih */
+#define I_POS_UNFM_SIZE(ih,pos,size) (((pos) == I_UNFM_NUM(ih) - 1 ) ? (size) - ih_free_space(ih) : (size))
+
+/* number of bytes contained by the direct item or the unformatted nodes the indirect item points to */
+
+/* get the item header */
+#define B_N_PITEM_HEAD(bh,item_num) ( (struct item_head * )((bh)->b_data + BLKH_SIZE) + (item_num) )
+
+/* get key */
+#define B_N_PDELIM_KEY(bh,item_num) ( (struct reiserfs_key * )((bh)->b_data + BLKH_SIZE) + (item_num) )
+
+/* get the key */
+#define B_N_PKEY(bh,item_num) ( &(B_N_PITEM_HEAD(bh,item_num)->ih_key) )
+
+/* get item body */
+#define B_N_PITEM(bh,item_num) ( (bh)->b_data + ih_location(B_N_PITEM_HEAD((bh),(item_num))))
+
+/* get the stat data by the buffer header and the item order */
+#define B_N_STAT_DATA(bh,nr) \
+( (struct stat_data *)((bh)->b_data + ih_location(B_N_PITEM_HEAD((bh),(nr))) ) )
+
+    /* following defines use reiserfs buffer header and item header */
+
+/* get stat-data */
+#define B_I_STAT_DATA(bh, ih) ( (struct stat_data * )((bh)->b_data + ih_location(ih)) )
+
+// this is 3976 for size==4096
+#define MAX_DIRECT_ITEM_LEN(size) ((size) - BLKH_SIZE - 2*IH_SIZE - SD_SIZE - UNFM_P_SIZE)
+
+/* indirect items consist of entries which contain blocknrs, pos
+   indicates which entry, and B_I_POS_UNFM_POINTER resolves to the
+   blocknr contained by the entry pos points to */
+#define B_I_POS_UNFM_POINTER(bh,ih,pos) le32_to_cpu(*(((unp_t *)B_I_PITEM(bh,ih)) + (pos)))
+#define PUT_B_I_POS_UNFM_POINTER(bh,ih,pos, val) do {*(((unp_t *)B_I_PITEM(bh,ih)) + (pos)) = cpu_to_le32(val); } while (0)
+
+struct reiserfs_iget_args {
+       __u32 objectid;
+       __u32 dirid;
+};
+
+/***************************************************************************/
+/*                    FUNCTION DECLARATIONS                                */
+/***************************************************************************/
+
+/*#ifdef __KERNEL__*/
+#define get_journal_desc_magic(bh) (bh->b_data + bh->b_size - 12)
+
+#define journal_trans_half(blocksize) \
+       ((blocksize - sizeof (struct reiserfs_journal_desc) + sizeof (__u32) - 12) / sizeof (__u32))
+
+/* journal.c see journal.c for all the comments here */
+
+/* first block written in a commit.  */
+struct reiserfs_journal_desc {
+       __le32 j_trans_id;      /* id of commit */
+       __le32 j_len;           /* length of commit. len +1 is the commit block */
+       __le32 j_mount_id;      /* mount id of this trans */
+       __le32 j_realblock[1];  /* real locations for each block */
+};
+
+#define get_desc_trans_id(d)   le32_to_cpu((d)->j_trans_id)
+#define get_desc_trans_len(d)  le32_to_cpu((d)->j_len)
+#define get_desc_mount_id(d)   le32_to_cpu((d)->j_mount_id)
+
+#define set_desc_trans_id(d,val)       do { (d)->j_trans_id = cpu_to_le32 (val); } while (0)
+#define set_desc_trans_len(d,val)      do { (d)->j_len = cpu_to_le32 (val); } while (0)
+#define set_desc_mount_id(d,val)       do { (d)->j_mount_id = cpu_to_le32 (val); } while (0)
+
+/* last block written in a commit */
+struct reiserfs_journal_commit {
+       __le32 j_trans_id;      /* must match j_trans_id from the desc block */
+       __le32 j_len;           /* ditto */
+       __le32 j_realblock[1];  /* real locations for each block */
+};
+
+#define get_commit_trans_id(c) le32_to_cpu((c)->j_trans_id)
+#define get_commit_trans_len(c)        le32_to_cpu((c)->j_len)
+#define get_commit_mount_id(c) le32_to_cpu((c)->j_mount_id)
+
+#define set_commit_trans_id(c,val)     do { (c)->j_trans_id = cpu_to_le32 (val); } while (0)
+#define set_commit_trans_len(c,val)    do { (c)->j_len = cpu_to_le32 (val); } while (0)
+
+/* this header block gets written whenever a transaction is considered fully flushed, and is more recent than the
+** last fully flushed transaction.  fully flushed means all the log blocks and all the real blocks are on disk,
+** and this transaction does not need to be replayed.
+*/
+struct reiserfs_journal_header {
+       __le32 j_last_flush_trans_id;   /* id of last fully flushed transaction */
+       __le32 j_first_unflushed_offset;        /* offset in the log of where to start replay after a crash */
+       __le32 j_mount_id;
+       /* 12 */ struct journal_params jh_journal;
+};
+
+/* biggest tunable defines are right here */
+#define JOURNAL_BLOCK_COUNT 8192       /* number of blocks in the journal */
+#define JOURNAL_TRANS_MAX_DEFAULT 1024 /* biggest possible single transaction, don't change for now (8/3/99) */
+#define JOURNAL_TRANS_MIN_DEFAULT 256
+#define JOURNAL_MAX_BATCH_DEFAULT   900        /* max blocks to batch into one transaction, don't make this any bigger than 900 */
+#define JOURNAL_MIN_RATIO 2
+#define JOURNAL_MAX_COMMIT_AGE 30
+#define JOURNAL_MAX_TRANS_AGE 30
+#define JOURNAL_PER_BALANCE_CNT (3 * (MAX_HEIGHT-2) + 9)
+#ifdef CONFIG_QUOTA
+/* We need to update data and inode (atime) */
+#define REISERFS_QUOTA_TRANS_BLOCKS(s) (REISERFS_SB(s)->s_mount_opt & (1<<REISERFS_QUOTA) ? 2 : 0)
+/* 1 balancing, 1 bitmap, 1 data per write + stat data update */
+#define REISERFS_QUOTA_INIT_BLOCKS(s) (REISERFS_SB(s)->s_mount_opt & (1<<REISERFS_QUOTA) ? \
+(DQUOT_INIT_ALLOC*(JOURNAL_PER_BALANCE_CNT+2)+DQUOT_INIT_REWRITE+1) : 0)
+/* same as with INIT */
+#define REISERFS_QUOTA_DEL_BLOCKS(s) (REISERFS_SB(s)->s_mount_opt & (1<<REISERFS_QUOTA) ? \
+(DQUOT_DEL_ALLOC*(JOURNAL_PER_BALANCE_CNT+2)+DQUOT_DEL_REWRITE+1) : 0)
+#else
+#define REISERFS_QUOTA_TRANS_BLOCKS(s) 0
+#define REISERFS_QUOTA_INIT_BLOCKS(s) 0
+#define REISERFS_QUOTA_DEL_BLOCKS(s) 0
+#endif
+
+/* both of these can be as low as 1, or as high as you want.  The min is the
+** number of 4k bitmap nodes preallocated on mount. New nodes are allocated
+** as needed, and released when transactions are committed.  On release, if 
+** the current number of nodes is > max, the node is freed, otherwise, 
+** it is put on a free list for faster use later.
+*/
+#define REISERFS_MIN_BITMAP_NODES 10
+#define REISERFS_MAX_BITMAP_NODES 100
+
+#define JBH_HASH_SHIFT 13      /* these are based on journal hash size of 8192 */
+#define JBH_HASH_MASK 8191
+
+#define _jhashfn(sb,block)     \
+       (((unsigned long)sb>>L1_CACHE_SHIFT) ^ \
+        (((block)<<(JBH_HASH_SHIFT - 6)) ^ ((block) >> 13) ^ ((block) << (JBH_HASH_SHIFT - 12))))
+#define journal_hash(t,sb,block) ((t)[_jhashfn((sb),(block)) & JBH_HASH_MASK])
+
+// We need these to make journal.c code more readable
+#define journal_find_get_block(s, block) __find_get_block(SB_JOURNAL(s)->j_dev_bd, block, s->s_blocksize)
+#define journal_getblk(s, block) __getblk(SB_JOURNAL(s)->j_dev_bd, block, s->s_blocksize)
+#define journal_bread(s, block) __bread(SB_JOURNAL(s)->j_dev_bd, block, s->s_blocksize)
+
+//enum reiserfs_bh_state_bits {
+//     BH_JDirty = BH_PrivateStart,    /* buffer is in current transaction */
+//     BH_JDirty_wait,
+//     BH_JNew,                /* disk block was taken off free list before
+//                              * being in a finished transaction, or
+//                              * written to disk. Can be reused immed. */
+//     BH_JPrepared,
+//     BH_JRestore_dirty,
+//     BH_JTest,               // debugging only will go away
+//};
+
+/*
+BUFFER_FNS(JDirty, journaled);
+TAS_BUFFER_FNS(JDirty, journaled);
+BUFFER_FNS(JDirty_wait, journal_dirty);
+TAS_BUFFER_FNS(JDirty_wait, journal_dirty);
+BUFFER_FNS(JNew, journal_new);
+TAS_BUFFER_FNS(JNew, journal_new);
+BUFFER_FNS(JPrepared, journal_prepared);
+TAS_BUFFER_FNS(JPrepared, journal_prepared);
+BUFFER_FNS(JRestore_dirty, journal_restore_dirty);
+TAS_BUFFER_FNS(JRestore_dirty, journal_restore_dirty);
+BUFFER_FNS(JTest, journal_test);
+TAS_BUFFER_FNS(JTest, journal_test);
+*/
+
+/*
+** transaction handle which is passed around for all journal calls
+*/
+struct reiserfs_transaction_handle {
+       struct super_block *t_super;    /* super for this FS when journal_begin was
+                                          called. saves calls to reiserfs_get_super
+                                          also used by nested transactions to make
+                                          sure they are nesting on the right FS
+                                          _must_ be first in the handle
+                                        */
+       int t_refcount;
+       int t_blocks_logged;    /* number of blocks this writer has logged */
+       int t_blocks_allocated; /* number of blocks this writer allocated */
+       unsigned long t_trans_id;       /* sanity check, equals the current trans id */
+       void *t_handle_save;    /* save existing current->journal_info */
+       unsigned displace_new_blocks:1; /* if new block allocation occurres, that block
+                                          should be displaced from others */
+       //struct list_head t_list;
+};
+
+/* used to keep track of ordered and tail writes, attached to the buffer
+ * head through b_journal_head.
+ */
+struct reiserfs_jh {
+       struct reiserfs_journal_list *jl;
+       struct buffer_head *bh;
+       //struct list_head list;
+};
+
+//
+// get key version from on disk key - kludge
+//
+/*
+static inline int le_key_version(const struct reiserfs_key *key)
+{
+       int type;
+
+       type = offset_v2_k_type(&(key->u.k_offset_v2));
+       if (type != TYPE_DIRECT && type != TYPE_INDIRECT
+           && type != TYPE_DIRENTRY)
+               return KEY_FORMAT_3_5;
+
+       return KEY_FORMAT_3_6;
+
+}
+
+static inline void copy_key(struct reiserfs_key *to,
+                           const struct reiserfs_key *from)
+{
+       memcpy(to, from, KEY_SIZE);
+}
+*/
+
+#define i_block_size(inode) ((inode)->i_sb->s_blocksize)
+#define file_size(inode) ((inode)->i_size)
+#define tail_size(inode) (file_size (inode) & (i_block_size (inode) - 1))
+
+#define tail_has_to_be_packed(inode) (have_large_tails ((inode)->i_sb)?\
+!STORE_TAIL_IN_UNFM_S1(file_size (inode), tail_size(inode), inode->i_sb->s_blocksize):have_small_tails ((inode)->i_sb)?!STORE_TAIL_IN_UNFM_S2(file_size (inode), tail_size(inode), inode->i_sb->s_blocksize):0 )
+
+/* inode.c */
+/* args for the create parameter of reiserfs_get_block */
+#define GET_BLOCK_NO_CREATE 0  /* don't create new blocks or convert tails */
+#define GET_BLOCK_CREATE 1     /* add anything you need to find block */
+#define GET_BLOCK_NO_HOLE 2    /* return -ENOENT for file holes */
+#define GET_BLOCK_READ_DIRECT 4        /* read the tail if indirect item not found */
+#define GET_BLOCK_NO_IMUX     8        /* i_mutex is not held, don't preallocate */
+#define GET_BLOCK_NO_DANGLE   16       /* don't leave any transactions running */
+
+/* bitmap.c */
+
+/* structure contains hints for block allocator, and it is a container for
+ * arguments, such as node, search path, transaction_handle, etc. */
+struct __reiserfs_blocknr_hint {
+       struct inode *inode;    /* inode passed to allocator, if we allocate unf. nodes */
+       long block;             /* file offset, in blocks */
+       struct in_core_key key;
+       struct path *path;      /* search path, used by allocator to deternine search_start by
+                                * various ways */
+       struct reiserfs_transaction_handle *th; /* transaction handle is needed to log super blocks and
+                                                * bitmap blocks changes  */
+       b_blocknr_t beg, end;
+       b_blocknr_t search_start;       /* a field used to transfer search start value (block number)
+                                        * between different block allocator procedures
+                                        * (determine_search_start() and others) */
+       int prealloc_size;      /* is set in determine_prealloc_size() function, used by underlayed
+                                * function that do actual allocation */
+
+       unsigned formatted_node:1;      /* the allocator uses different polices for getting disk space for
+                                        * formatted/unformatted blocks with/without preallocation */
+       unsigned preallocate:1;
+};
+
+typedef struct __reiserfs_blocknr_hint reiserfs_blocknr_hint_t;
+
+/* hashes.c */
+__u32 keyed_hash(const signed char *msg, int len);
+__u32 yura_hash(const signed char *msg, int len);
+__u32 r5_hash(const signed char *msg, int len);
+
+/* the ext2 bit routines adjust for big or little endian as
+** appropriate for the arch, so in our laziness we use them rather
+** than using the bit routines they call more directly.  These
+** routines must be used when changing on disk bitmaps.  */
+#define reiserfs_test_and_set_le_bit   ext2_set_bit
+#define reiserfs_test_and_clear_le_bit ext2_clear_bit
+#define reiserfs_test_le_bit           ext2_test_bit
+#define reiserfs_find_next_zero_le_bit ext2_find_next_zero_bit
+
+/* sometimes reiserfs_truncate may require to allocate few new blocks
+   to perform indirect2direct conversion. People probably used to
+   think, that truncate should work without problems on a filesystem
+   without free disk space. They may complain that they can not
+   truncate due to lack of free disk space. This spare space allows us
+   to not worry about it. 500 is probably too much, but it should be
+   absolutely safe */
+#define SPARE_SPACE 500
+
+/* ioctl's command */
+#define REISERFS_IOC_UNPACK            _IOW(0xCD,1,long)
+/* define following flags to be the same as in ext2, so that chattr(1),
+   lsattr(1) will work with us. */
+#define REISERFS_IOC_GETFLAGS          EXT2_IOC_GETFLAGS
+#define REISERFS_IOC_SETFLAGS          EXT2_IOC_SETFLAGS
+#define REISERFS_IOC_GETVERSION                EXT2_IOC_GETVERSION
+#define REISERFS_IOC_SETVERSION                EXT2_IOC_SETVERSION
+
+
+
+#pragma pack()
+
+
+#endif
diff --git a/filesystems/fsw_strfunc.h b/filesystems/fsw_strfunc.h
new file mode 100644 (file)
index 0000000..2639997
--- /dev/null
@@ -0,0 +1,453 @@
+/* fsw_strfunc.h generated by mk_fsw_strfunc.py */
+
+static int fsw_streq_ISO88591_UTF8(void *s1data, void *s2data, int len)
+{
+    int i;
+    fsw_u8 *p1 = (fsw_u8 *)s1data;
+    fsw_u8 *p2 = (fsw_u8 *)s2data;
+    fsw_u32 c1, c2;
+    
+    for (i = 0; i < len; i++) {
+        c1 = *p1++;
+        c2 = *p2++;
+        if ((c2 & 0xe0) == 0xc0) {
+            c2 = ((c2 & 0x1f) << 6) | (*p2++ & 0x3f);
+        } else if ((c2 & 0xf0) == 0xe0) {
+            c2 = ((c2 & 0x0f) << 12) | ((*p2++ & 0x3f) << 6);
+            c2 |= (*p2++ & 0x3f);
+        } else if ((c2 & 0xf8) == 0xf0) {
+            c2 = ((c2 & 0x07) << 18) | ((*p2++ & 0x3f) << 12);
+            c2 |= ((*p2++ & 0x3f) << 6);
+            c2 |= (*p2++ & 0x3f);
+        }
+        if (c1 != c2)
+            return 0;
+    }
+    return 1;
+}
+
+static int fsw_streq_ISO88591_UTF16(void *s1data, void *s2data, int len)
+{
+    int i;
+    fsw_u8 *p1 = (fsw_u8 *)s1data;
+    fsw_u16 *p2 = (fsw_u16 *)s2data;
+    fsw_u32 c1, c2;
+    
+    for (i = 0; i < len; i++) {
+        c1 = *p1++;
+        c2 = *p2++;
+        if (c1 != c2)
+            return 0;
+    }
+    return 1;
+}
+
+static int fsw_streq_ISO88591_UTF16_SWAPPED(void *s1data, void *s2data, int len)
+{
+    int i;
+    fsw_u8 *p1 = (fsw_u8 *)s1data;
+    fsw_u16 *p2 = (fsw_u16 *)s2data;
+    fsw_u32 c1, c2;
+    
+    for (i = 0; i < len; i++) {
+        c1 = *p1++;
+        c2 = *p2++; c2 = FSW_SWAPVALUE_U16(c2);
+        if (c1 != c2)
+            return 0;
+    }
+    return 1;
+}
+
+static int fsw_streq_UTF8_UTF16(void *s1data, void *s2data, int len)
+{
+    int i;
+    fsw_u8 *p1 = (fsw_u8 *)s1data;
+    fsw_u16 *p2 = (fsw_u16 *)s2data;
+    fsw_u32 c1, c2;
+    
+    for (i = 0; i < len; i++) {
+        c1 = *p1++;
+        if ((c1 & 0xe0) == 0xc0) {
+            c1 = ((c1 & 0x1f) << 6) | (*p1++ & 0x3f);
+        } else if ((c1 & 0xf0) == 0xe0) {
+            c1 = ((c1 & 0x0f) << 12) | ((*p1++ & 0x3f) << 6);
+            c1 |= (*p1++ & 0x3f);
+        } else if ((c1 & 0xf8) == 0xf0) {
+            c1 = ((c1 & 0x07) << 18) | ((*p1++ & 0x3f) << 12);
+            c1 |= ((*p1++ & 0x3f) << 6);
+            c1 |= (*p1++ & 0x3f);
+        }
+        c2 = *p2++;
+        if (c1 != c2)
+            return 0;
+    }
+    return 1;
+}
+
+static int fsw_streq_UTF8_UTF16_SWAPPED(void *s1data, void *s2data, int len)
+{
+    int i;
+    fsw_u8 *p1 = (fsw_u8 *)s1data;
+    fsw_u16 *p2 = (fsw_u16 *)s2data;
+    fsw_u32 c1, c2;
+    
+    for (i = 0; i < len; i++) {
+        c1 = *p1++;
+        if ((c1 & 0xe0) == 0xc0) {
+            c1 = ((c1 & 0x1f) << 6) | (*p1++ & 0x3f);
+        } else if ((c1 & 0xf0) == 0xe0) {
+            c1 = ((c1 & 0x0f) << 12) | ((*p1++ & 0x3f) << 6);
+            c1 |= (*p1++ & 0x3f);
+        } else if ((c1 & 0xf8) == 0xf0) {
+            c1 = ((c1 & 0x07) << 18) | ((*p1++ & 0x3f) << 12);
+            c1 |= ((*p1++ & 0x3f) << 6);
+            c1 |= (*p1++ & 0x3f);
+        }
+        c2 = *p2++; c2 = FSW_SWAPVALUE_U16(c2);
+        if (c1 != c2)
+            return 0;
+    }
+    return 1;
+}
+
+static int fsw_streq_UTF16_UTF16_SWAPPED(void *s1data, void *s2data, int len)
+{
+    int i;
+    fsw_u16 *p1 = (fsw_u16 *)s1data;
+    fsw_u16 *p2 = (fsw_u16 *)s2data;
+    fsw_u32 c1, c2;
+    
+    for (i = 0; i < len; i++) {
+        c1 = *p1++;
+        c2 = *p2++; c2 = FSW_SWAPVALUE_U16(c2);
+        if (c1 != c2)
+            return 0;
+    }
+    return 1;
+}
+
+static fsw_status_t fsw_strcoerce_UTF8_ISO88591(void *srcdata, int srclen, struct fsw_string *dest)
+{
+    fsw_status_t    status;
+    int             i;
+    fsw_u8       *sp;
+    fsw_u8       *dp;
+    fsw_u32         c;
+    
+    dest->type = FSW_STRING_TYPE_ISO88591;
+    dest->len  = srclen;
+    dest->size = srclen * sizeof(fsw_u8);
+    status = fsw_alloc(dest->size, &dest->data);
+    if (status)
+        return status;
+    
+    sp = (fsw_u8 *)srcdata;
+    dp = (fsw_u8 *)dest->data;
+    for (i = 0; i < srclen; i++) {
+        c = *sp++;
+        if ((c & 0xe0) == 0xc0) {
+            c = ((c & 0x1f) << 6) | (*sp++ & 0x3f);
+        } else if ((c & 0xf0) == 0xe0) {
+            c = ((c & 0x0f) << 12) | ((*sp++ & 0x3f) << 6);
+            c |= (*sp++ & 0x3f);
+        } else if ((c & 0xf8) == 0xf0) {
+            c = ((c & 0x07) << 18) | ((*sp++ & 0x3f) << 12);
+            c |= ((*sp++ & 0x3f) << 6);
+            c |= (*sp++ & 0x3f);
+        }
+        *dp++ = (fsw_u8)c;
+    }
+    return FSW_SUCCESS;
+}
+
+static fsw_status_t fsw_strcoerce_UTF16_ISO88591(void *srcdata, int srclen, struct fsw_string *dest)
+{
+    fsw_status_t    status;
+    int             i;
+    fsw_u16       *sp;
+    fsw_u8       *dp;
+    fsw_u32         c;
+    
+    dest->type = FSW_STRING_TYPE_ISO88591;
+    dest->len  = srclen;
+    dest->size = srclen * sizeof(fsw_u8);
+    status = fsw_alloc(dest->size, &dest->data);
+    if (status)
+        return status;
+    
+    sp = (fsw_u16 *)srcdata;
+    dp = (fsw_u8 *)dest->data;
+    for (i = 0; i < srclen; i++) {
+        c = *sp++;
+        *dp++ = (fsw_u8)c;
+    }
+    return FSW_SUCCESS;
+}
+
+static fsw_status_t fsw_strcoerce_UTF16_SWAPPED_ISO88591(void *srcdata, int srclen, struct fsw_string *dest)
+{
+    fsw_status_t    status;
+    int             i;
+    fsw_u16       *sp;
+    fsw_u8       *dp;
+    fsw_u32         c;
+    
+    dest->type = FSW_STRING_TYPE_ISO88591;
+    dest->len  = srclen;
+    dest->size = srclen * sizeof(fsw_u8);
+    status = fsw_alloc(dest->size, &dest->data);
+    if (status)
+        return status;
+    
+    sp = (fsw_u16 *)srcdata;
+    dp = (fsw_u8 *)dest->data;
+    for (i = 0; i < srclen; i++) {
+        c = *sp++; c = FSW_SWAPVALUE_U16(c);
+        *dp++ = (fsw_u8)c;
+    }
+    return FSW_SUCCESS;
+}
+
+static fsw_status_t fsw_strcoerce_ISO88591_UTF16(void *srcdata, int srclen, struct fsw_string *dest)
+{
+    fsw_status_t    status;
+    int             i;
+    fsw_u8       *sp;
+    fsw_u16       *dp;
+    fsw_u32         c;
+    
+    dest->type = FSW_STRING_TYPE_UTF16;
+    dest->len  = srclen;
+    dest->size = srclen * sizeof(fsw_u16);
+    status = fsw_alloc(dest->size, &dest->data);
+    if (status)
+        return status;
+    
+    sp = (fsw_u8 *)srcdata;
+    dp = (fsw_u16 *)dest->data;
+    for (i = 0; i < srclen; i++) {
+        c = *sp++;
+        *dp++ = (fsw_u16)c;
+    }
+    return FSW_SUCCESS;
+}
+
+static fsw_status_t fsw_strcoerce_UTF8_UTF16(void *srcdata, int srclen, struct fsw_string *dest)
+{
+    fsw_status_t    status;
+    int             i;
+    fsw_u8       *sp;
+    fsw_u16       *dp;
+    fsw_u32         c;
+    
+    dest->type = FSW_STRING_TYPE_UTF16;
+    dest->len  = srclen;
+    dest->size = srclen * sizeof(fsw_u16);
+    status = fsw_alloc(dest->size, &dest->data);
+    if (status)
+        return status;
+    
+    sp = (fsw_u8 *)srcdata;
+    dp = (fsw_u16 *)dest->data;
+    for (i = 0; i < srclen; i++) {
+        c = *sp++;
+        if ((c & 0xe0) == 0xc0) {
+            c = ((c & 0x1f) << 6) | (*sp++ & 0x3f);
+        } else if ((c & 0xf0) == 0xe0) {
+            c = ((c & 0x0f) << 12) | ((*sp++ & 0x3f) << 6);
+            c |= (*sp++ & 0x3f);
+        } else if ((c & 0xf8) == 0xf0) {
+            c = ((c & 0x07) << 18) | ((*sp++ & 0x3f) << 12);
+            c |= ((*sp++ & 0x3f) << 6);
+            c |= (*sp++ & 0x3f);
+        }
+        *dp++ = (fsw_u16)c;
+    }
+    return FSW_SUCCESS;
+}
+
+static fsw_status_t fsw_strcoerce_UTF16_SWAPPED_UTF16(void *srcdata, int srclen, struct fsw_string *dest)
+{
+    fsw_status_t    status;
+    int             i;
+    fsw_u16       *sp;
+    fsw_u16       *dp;
+    fsw_u32         c;
+    
+    dest->type = FSW_STRING_TYPE_UTF16;
+    dest->len  = srclen;
+    dest->size = srclen * sizeof(fsw_u16);
+    status = fsw_alloc(dest->size, &dest->data);
+    if (status)
+        return status;
+    
+    sp = (fsw_u16 *)srcdata;
+    dp = (fsw_u16 *)dest->data;
+    for (i = 0; i < srclen; i++) {
+        c = *sp++; c = FSW_SWAPVALUE_U16(c);
+        *dp++ = (fsw_u16)c;
+    }
+    return FSW_SUCCESS;
+}
+
+static fsw_status_t fsw_strcoerce_ISO88591_UTF8(void *srcdata, int srclen, struct fsw_string *dest)
+{
+    fsw_status_t    status;
+    int             i, destsize;
+    fsw_u8       *sp;
+    fsw_u8       *dp;
+    fsw_u32         c;
+    
+    sp = (fsw_u8 *)srcdata;
+    destsize = 0;
+    for (i = 0; i < srclen; i++) {
+        c = *sp++;
+        
+        if (c < 0x000080)
+            destsize++;
+        else if (c < 0x000800)
+            destsize += 2;
+        else if (c < 0x010000)
+            destsize += 3;
+        else
+            destsize += 4;
+    }
+    
+    dest->type = FSW_STRING_TYPE_UTF8;
+    dest->len  = srclen;
+    dest->size = destsize;
+    status = fsw_alloc(dest->size, &dest->data);
+    if (status)
+        return status;
+    
+    sp = (fsw_u8 *)srcdata;
+    dp = (fsw_u8 *)dest->data;
+    for (i = 0; i < srclen; i++) {
+        c = *sp++;
+        
+        if (c < 0x000080) {
+            *dp++ = (fsw_u8)c;
+        } else if (c < 0x000800) {
+            *dp++ = (fsw_u8)(0xc0 | ((c >> 6) & 0x1f));
+            *dp++ = (fsw_u8)(0x80 | (c & 0x3f));
+        } else if (c < 0x010000) {
+            *dp++ = (fsw_u8)(0xe0 | ((c >> 12) & 0x0f));
+            *dp++ = (fsw_u8)(0x80 | ((c >> 6) & 0x3f));
+            *dp++ = (fsw_u8)(0x80 | (c & 0x3f));
+        } else {
+            *dp++ = (fsw_u8)(0xf0 | ((c >> 18) & 0x07));
+            *dp++ = (fsw_u8)(0x80 | ((c >> 12) & 0x3f));
+            *dp++ = (fsw_u8)(0x80 | ((c >> 6) & 0x3f));
+            *dp++ = (fsw_u8)(0x80 | (c & 0x3f));
+        }
+    }
+    return FSW_SUCCESS;
+}
+
+static fsw_status_t fsw_strcoerce_UTF16_UTF8(void *srcdata, int srclen, struct fsw_string *dest)
+{
+    fsw_status_t    status;
+    int             i, destsize;
+    fsw_u16       *sp;
+    fsw_u8       *dp;
+    fsw_u32         c;
+    
+    sp = (fsw_u16 *)srcdata;
+    destsize = 0;
+    for (i = 0; i < srclen; i++) {
+        c = *sp++;
+        
+        if (c < 0x000080)
+            destsize++;
+        else if (c < 0x000800)
+            destsize += 2;
+        else if (c < 0x010000)
+            destsize += 3;
+        else
+            destsize += 4;
+    }
+    
+    dest->type = FSW_STRING_TYPE_UTF8;
+    dest->len  = srclen;
+    dest->size = destsize;
+    status = fsw_alloc(dest->size, &dest->data);
+    if (status)
+        return status;
+    
+    sp = (fsw_u16 *)srcdata;
+    dp = (fsw_u8 *)dest->data;
+    for (i = 0; i < srclen; i++) {
+        c = *sp++;
+        
+        if (c < 0x000080) {
+            *dp++ = (fsw_u8)c;
+        } else if (c < 0x000800) {
+            *dp++ = (fsw_u8)(0xc0 | ((c >> 6) & 0x1f));
+            *dp++ = (fsw_u8)(0x80 | (c & 0x3f));
+        } else if (c < 0x010000) {
+            *dp++ = (fsw_u8)(0xe0 | ((c >> 12) & 0x0f));
+            *dp++ = (fsw_u8)(0x80 | ((c >> 6) & 0x3f));
+            *dp++ = (fsw_u8)(0x80 | (c & 0x3f));
+        } else {
+            *dp++ = (fsw_u8)(0xf0 | ((c >> 18) & 0x07));
+            *dp++ = (fsw_u8)(0x80 | ((c >> 12) & 0x3f));
+            *dp++ = (fsw_u8)(0x80 | ((c >> 6) & 0x3f));
+            *dp++ = (fsw_u8)(0x80 | (c & 0x3f));
+        }
+    }
+    return FSW_SUCCESS;
+}
+
+static fsw_status_t fsw_strcoerce_UTF16_SWAPPED_UTF8(void *srcdata, int srclen, struct fsw_string *dest)
+{
+    fsw_status_t    status;
+    int             i, destsize;
+    fsw_u16       *sp;
+    fsw_u8       *dp;
+    fsw_u32         c;
+    
+    sp = (fsw_u16 *)srcdata;
+    destsize = 0;
+    for (i = 0; i < srclen; i++) {
+        c = *sp++; c = FSW_SWAPVALUE_U16(c);
+        
+        if (c < 0x000080)
+            destsize++;
+        else if (c < 0x000800)
+            destsize += 2;
+        else if (c < 0x010000)
+            destsize += 3;
+        else
+            destsize += 4;
+    }
+    
+    dest->type = FSW_STRING_TYPE_UTF8;
+    dest->len  = srclen;
+    dest->size = destsize;
+    status = fsw_alloc(dest->size, &dest->data);
+    if (status)
+        return status;
+    
+    sp = (fsw_u16 *)srcdata;
+    dp = (fsw_u8 *)dest->data;
+    for (i = 0; i < srclen; i++) {
+        c = *sp++; c = FSW_SWAPVALUE_U16(c);
+        
+        if (c < 0x000080) {
+            *dp++ = (fsw_u8)c;
+        } else if (c < 0x000800) {
+            *dp++ = (fsw_u8)(0xc0 | ((c >> 6) & 0x1f));
+            *dp++ = (fsw_u8)(0x80 | (c & 0x3f));
+        } else if (c < 0x010000) {
+            *dp++ = (fsw_u8)(0xe0 | ((c >> 12) & 0x0f));
+            *dp++ = (fsw_u8)(0x80 | ((c >> 6) & 0x3f));
+            *dp++ = (fsw_u8)(0x80 | (c & 0x3f));
+        } else {
+            *dp++ = (fsw_u8)(0xf0 | ((c >> 18) & 0x07));
+            *dp++ = (fsw_u8)(0x80 | ((c >> 12) & 0x3f));
+            *dp++ = (fsw_u8)(0x80 | ((c >> 6) & 0x3f));
+            *dp++ = (fsw_u8)(0x80 | (c & 0x3f));
+        }
+    }
+    return FSW_SUCCESS;
+}
diff --git a/filesystems/gzio.c b/filesystems/gzio.c
new file mode 100644 (file)
index 0000000..9377660
--- /dev/null
@@ -0,0 +1,1111 @@
+/*
+ * this file take from grub 2.0
+ * for btrfs UEFI driver
+ */
+
+/* gzio.c - decompression support for gzip */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 1999,2005,2006,2007,2009  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Most of this file was originally the source file "inflate.c", written
+ * by Mark Adler.  It has been very heavily modified.  In particular, the
+ * original would run through the whole file at once, and this version can
+ * be stopped and restarted on any boundary during the decompression process.
+ *
+ * The license and header comments that file are included here.
+ */
+
+/* inflate.c -- Not copyrighted 1992 by Mark Adler
+   version c10p1, 10 January 1993 */
+
+/* You can do whatever you like with this source file, though I would
+   prefer that if you modify it and redistribute it that you include
+   comments to that effect with your name and the date.  Thank you.
+ */
+
+#if 0
+#include <grub/err.h>
+#include <grub/types.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/fs.h>
+#include <grub/file.h>
+#include <grub/dl.h>
+#include <grub/deflate.h>
+#include <grub/i18n.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+#endif
+
+/*
+ *  Window Size
+ *
+ *  This must be a power of two, and at least 32K for zip's deflate method
+ */
+
+#define WSIZE   0x8000
+
+
+#define INBUFSIZ  0x2000
+
+/* The state stored in filesystem-specific data.  */
+struct grub_gzio
+{
+  int err;
+  /* If input is in memory following fields are used instead of file.  */
+  int mem_input_size, mem_input_off;
+  uint8_t *mem_input;
+  /* The offset at which the data starts in the underlying file.  */
+  int data_offset;
+  /* The type of current block.  */
+  int block_type;
+  /* The length of current block.  */
+  int block_len;
+  /* The flag of the last block.  */
+  int last_block;
+  /* The flag of codes.  */
+  int code_state;
+  /* The length of a copy.  */
+  unsigned inflate_n;
+  /* The index of a copy.  */
+  unsigned inflate_d;
+  /* The input buffer.  */
+  uint8_t inbuf[INBUFSIZ];
+  int inbuf_d;
+  /* The bit buffer.  */
+  unsigned long bb;
+  /* The bits in the bit buffer.  */
+  unsigned bk;
+  /* The sliding window in uncompressed data.  */
+  uint8_t slide[WSIZE];
+  /* Current position in the slide.  */
+  unsigned wp;
+  /* The literal/length code table.  */
+  struct huft *tl;
+  /* The distance code table.  */
+  struct huft *td;
+  /* The lookup bits for the literal/length code table. */
+  int bl;
+  /* The lookup bits for the distance code table.  */
+  int bd;
+  /* The original offset value.  */
+  int saved_offset;
+};
+typedef struct grub_gzio *grub_gzio_t;
+
+/* Function prototypes */
+static void initialize_tables (grub_gzio_t);
+
+/* Little-Endian defines for the 2-byte magic numbers for gzip files.  */
+#define GZIP_MAGIC      grub_le_to_cpu16 (0x8B1F)
+#define OLD_GZIP_MAGIC  grub_le_to_cpu16 (0x9E1F)
+
+/* Compression methods (see algorithm.doc) */
+#define STORED      0
+#define COMPRESSED  1
+//#define PACKED      2
+#define LZHED       3
+/* methods 4 to 7 reserved */
+#define DEFLATED    8
+#define MAX_METHODS 9
+
+/* gzip flag byte */
+#define ASCII_FLAG   0x01       /* bit 0 set: file probably ascii text */
+#define CONTINUATION 0x02       /* bit 1 set: continuation of multi-part gzip file */
+#define EXTRA_FIELD  0x04       /* bit 2 set: extra field present */
+#define ORIG_NAME    0x08       /* bit 3 set: original file name present */
+#define COMMENT      0x10       /* bit 4 set: file comment present */
+#define ENCRYPTED    0x20       /* bit 5 set: file is encrypted */
+#define RESERVED     0xC0       /* bit 6,7:   reserved */
+
+#define UNSUPPORTED_FLAGS       (CONTINUATION | ENCRYPTED | RESERVED)
+
+/* inflate block codes */
+#define INFLATE_STORED  0
+#define INFLATE_FIXED   1
+#define INFLATE_DYNAMIC 2
+
+typedef unsigned char uch;
+typedef unsigned short ush;
+typedef unsigned long ulg;
+
+/* Huffman code lookup table entry--this entry is four bytes for machines
+   that have 16-bit pointers (e.g. PC's in the small or medium model).
+   Valid extra bits are 0..13.  e == 15 is EOB (end of block), e == 16
+   means that v is a literal, 16 < e < 32 means that v is a pointer to
+   the next table, which codes e - 16 bits, and lastly e == 99 indicates
+   an unused code.  If a code with e == 99 is looked up, this implies an
+   error in the data. */
+struct huft
+{
+  uch e;                        /* number of extra bits or operation */
+  uch b;                        /* number of bits in this code or subcode */
+  union
+    {
+      ush n;                    /* literal, length base, or distance base */
+      struct huft *t;           /* pointer to next level of table */
+    }
+  v;
+};
+
+
+/* The inflate algorithm uses a sliding 32K byte window on the uncompressed
+   stream to find repeated byte strings.  This is implemented here as a
+   circular buffer.  The index is updated simply by incrementing and then
+   and'ing with 0x7fff (32K-1). */
+/* It is left to other modules to supply the 32K area.  It is assumed
+   to be usable as if it were declared "uch slide[32768];" or as just
+   "uch *slide;" and then malloc'ed in the latter case.  The definition
+   must be in unzip.h, included above. */
+
+
+/* Tables for deflate from PKZIP's appnote.txt. */
+static unsigned bitorder[] =
+{                               /* Order of the bit length code lengths */
+  16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+static ush cplens[] =
+{                               /* Copy lengths for literal codes 257..285 */
+  3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+  35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+        /* note: see note #13 above about the 258 in this list. */
+static ush cplext[] =
+{                               /* Extra bits for literal codes 257..285 */
+  0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+  3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99};       /* 99==invalid */
+static ush cpdist[] =
+{                               /* Copy offsets for distance codes 0..29 */
+  1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+  257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+  8193, 12289, 16385, 24577};
+static ush cpdext[] =
+{                               /* Extra bits for distance codes */
+  0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+  7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+  12, 12, 13, 13};
+
+
+/*
+   Huffman code decoding is performed using a multi-level table lookup.
+   The fastest way to decode is to simply build a lookup table whose
+   size is determined by the longest code.  However, the time it takes
+   to build this table can also be a factor if the data being decoded
+   is not very long.  The most common codes are necessarily the
+   shortest codes, so those codes dominate the decoding time, and hence
+   the speed.  The idea is you can have a shorter table that decodes the
+   shorter, more probable codes, and then point to subsidiary tables for
+   the longer codes.  The time it costs to decode the longer codes is
+   then traded against the time it takes to make longer tables.
+
+   This results of this trade are in the variables lbits and dbits
+   below.  lbits is the number of bits the first level table for literal/
+   length codes can decode in one step, and dbits is the same thing for
+   the distance codes.  Subsequent tables are also less than or equal to
+   those sizes.  These values may be adjusted either when all of the
+   codes are shorter than that, in which case the longest code length in
+   bits is used, or when the shortest code is *longer* than the requested
+   table size, in which case the length of the shortest code in bits is
+   used.
+
+   There are two different values for the two tables, since they code a
+   different number of possibilities each.  The literal/length table
+   codes 286 possible values, or in a flat code, a little over eight
+   bits.  The distance table codes 30 possible values, or a little less
+   than five bits, flat.  The optimum values for speed end up being
+   about one bit more than those, so lbits is 8+1 and dbits is 5+1.
+   The optimum values may differ though from machine to machine, and
+   possibly even between compilers.  Your mileage may vary.
+ */
+
+
+static int lbits = 9;           /* bits in base literal/length lookup table */
+static int dbits = 6;           /* bits in base distance lookup table */
+
+
+/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */
+#define BMAX 16                 /* maximum bit length of any code (16 for explode) */
+#define N_MAX 288               /* maximum number of codes in any set */
+
+
+/* Macros for inflate() bit peeking and grabbing.
+   The usage is:
+
+        NEEDBITS(j)
+        x = b & mask_bits[j];
+        DUMPBITS(j)
+
+   where NEEDBITS makes sure that b has at least j bits in it, and
+   DUMPBITS removes the bits from b.  The macros use the variable k
+   for the number of bits in b.  Normally, b and k are register
+   variables for speed, and are initialized at the beginning of a
+   routine that uses these macros from a global bit buffer and count.
+
+   If we assume that EOB will be the longest code, then we will never
+   ask for bits with NEEDBITS that are beyond the end of the stream.
+   So, NEEDBITS should not read any more bytes than are needed to
+   meet the request.  Then no bytes need to be "returned" to the buffer
+   at the end of the last block.
+
+   However, this assumption is not true for fixed blocks--the EOB code
+   is 7 bits, but the other literal/length codes can be 8 or 9 bits.
+   (The EOB code is shorter than other codes because fixed blocks are
+   generally short.  So, while a block always has an EOB, many other
+   literal/length codes have a significantly lower probability of
+   showing up at all.)  However, by making the first table have a
+   lookup of seven bits, the EOB code will be found in that first
+   lookup, and so will not require that too many bits be pulled from
+   the stream.
+ */
+
+static ush mask_bits[] =
+{
+  0x0000,
+  0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
+  0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
+};
+
+#pragma GCC diagnostic ignored "-Wunsafe-loop-optimizations"
+
+#define NEEDBITS(n) do {while(k<(n)){b|=((ulg)get_byte(gzio))<<k;k+=8;}} while (0)
+#define DUMPBITS(n) do {b>>=(n);k-=(n);} while (0)
+
+static int
+get_byte (grub_gzio_t gzio)
+{
+      if (gzio->mem_input_off < gzio->mem_input_size)
+        return gzio->mem_input[gzio->mem_input_off++];
+      return 0;
+}
+
+static void
+gzio_seek (grub_gzio_t gzio, grub_off_t off)
+{
+      if (off > gzio->mem_input_size)
+        gzio->err = -1;
+      else
+        gzio->mem_input_off = off;
+}
+
+/* more function prototypes */
+static int huft_build (unsigned *, unsigned, unsigned, ush *, ush *,
+                       struct huft **, int *);
+static int huft_free (struct huft *);
+static int inflate_codes_in_window (grub_gzio_t);
+
+
+/* Given a list of code lengths and a maximum table size, make a set of
+   tables to decode that set of codes.  Return zero on success, one if
+   the given code set is incomplete (the tables are still built in this
+   case), two if the input is invalid (all zero length codes or an
+   oversubscribed set of lengths), and three if not enough memory. */
+
+static int
+huft_build (unsigned *b,        /* code lengths in bits (all assumed <= BMAX) */
+            unsigned n,         /* number of codes (assumed <= N_MAX) */
+            unsigned s,         /* number of simple-valued codes (0..s-1) */
+            ush * d,            /* list of base values for non-simple codes */
+            ush * e,            /* list of extra bits for non-simple codes */
+            struct huft **t,    /* result: starting table */
+            int *m)             /* maximum lookup bits, returns actual */
+{
+  unsigned a;                   /* counter for codes of length k */
+  unsigned c[BMAX + 1];         /* bit length count table */
+  unsigned f;                   /* i repeats in table every f entries */
+  int g;                        /* maximum code length */
+  int h;                        /* table level */
+  register unsigned i;          /* counter, current code */
+  register unsigned j;          /* counter */
+  register int k;               /* number of bits in current code */
+  int l;                        /* bits per table (returned in m) */
+  register unsigned *p;         /* pointer into c[], b[], or v[] */
+  register struct huft *q;      /* points to current table */
+  struct huft r;                /* table entry for structure assignment */
+  struct huft *u[BMAX];         /* table stack */
+  unsigned v[N_MAX];            /* values in order of bit length */
+  register int w;               /* bits before this table == (l * h) */
+  unsigned x[BMAX + 1];         /* bit offsets, then code stack */
+  unsigned *xp;                 /* pointer into x */
+  int y;                        /* number of dummy codes added */
+  unsigned z;                   /* number of entries in current table */
+
+  /* Generate counts for each bit length */
+  fsw_memzero ((char *) c, sizeof (c));
+  p = b;
+  i = n;
+  do
+    {
+      c[*p]++;                  /* assume all entries <= BMAX */
+      p++;                      /* Can't combine with above line (Solaris bug) */
+    }
+  while (--i);
+  if (c[0] == n)                /* null input--all zero length codes */
+    {
+      *t = (struct huft *) NULL;
+      *m = 0;
+      return 0;
+    }
+
+  /* Find minimum and maximum length, bound *m by those */
+  l = *m;
+  for (j = 1; j <= BMAX; j++)
+    if (c[j])
+      break;
+  k = j;                        /* minimum code length */
+  if ((unsigned) l < j)
+    l = j;
+  for (i = BMAX; i; i--)
+    if (c[i])
+      break;
+  g = i;                        /* maximum code length */
+  if ((unsigned) l > i)
+    l = i;
+  *m = l;
+
+  /* Adjust last length count to fill out codes, if needed */
+  for (y = 1 << j; j < i; j++, y <<= 1)
+    if ((y -= c[j]) < 0)
+      return 2;                 /* bad input: more codes than bits */
+  if ((y -= c[i]) < 0)
+    return 2;
+  c[i] += y;
+
+  /* Generate starting offsets into the value table for each length */
+  x[1] = j = 0;
+  p = c + 1;
+  xp = x + 2;
+  while (--i)
+    {                           /* note that i == g from above */
+      *xp++ = (j += *p++);
+    }
+
+  /* Make a table of values in order of bit lengths */
+  p = b;
+  i = 0;
+  do
+    {
+      if ((j = *p++) != 0)
+        v[x[j]++] = i;
+    }
+  while (++i < n);
+
+  /* Generate the Huffman codes and for each, make the table entries */
+  x[0] = i = 0;                 /* first Huffman code is zero */
+  p = v;                        /* grab values in bit order */
+  h = -1;                       /* no tables yet--level -1 */
+  w = -l;                       /* bits decoded == (l * h) */
+  u[0] = (struct huft *) NULL;  /* just to keep compilers happy */
+  q = (struct huft *) NULL;     /* ditto */
+  z = 0;                        /* ditto */
+
+  /* go through the bit lengths (k already is bits in shortest code) */
+  for (; k <= g; k++)
+    {
+      a = c[k];
+      while (a--)
+        {
+          /* here i is the Huffman code of length k bits for value *p */
+          /* make tables up to required level */
+          while (k > w + l)
+            {
+              h++;
+              w += l;           /* previous table always l bits */
+
+              /* compute minimum size table less than or equal to l bits */
+              z = (z = (unsigned) (g - w)) > (unsigned) l ? (unsigned) l : z;   /* upper limit on table size */
+              if ((f = 1 << (j = k - w)) > a + 1)       /* try a k-w bit table */
+                {               /* too few codes for k-w bit table */
+                  f -= a + 1;   /* deduct codes from patterns left */
+                  xp = c + k;
+                  while (++j < z)       /* try smaller tables up to z bits */
+                    {
+                      if ((f <<= 1) <= *++xp)
+                        break;  /* enough codes to use up j bits */
+                      f -= *xp; /* else deduct codes from patterns */
+                    }
+                }
+              z = 1 << j;       /* table entries for j-bit table */
+
+              /* allocate and link in new table */
+              q = (struct huft *) AllocatePool ((z + 1) * sizeof (struct huft));
+              if (! q)
+                {
+                  if (h)
+                    huft_free (u[0]);
+                  return 3;
+                }
+
+              *t = q + 1;       /* link to list for huft_free() */
+              *(t = &(q->v.t)) = (struct huft *) NULL;
+              u[h] = ++q;       /* table starts after link */
+
+              /* connect to last table, if there is one */
+              if (h)
+                {
+                  x[h] = i;     /* save pattern for backing up */
+                  r.b = (uch) l;        /* bits to dump before this table */
+                  r.e = (uch) (16 + j);         /* bits in this table */
+                  r.v.t = q;    /* pointer to this table */
+                  j = i >> (w - l);     /* (get around Turbo C bug) */
+                  u[h - 1][j] = r;      /* connect to last table */
+                }
+            }
+
+          /* set up table entry in r */
+          r.b = (uch) (k - w);
+          if (p >= v + n)
+            r.e = 99;           /* out of values--invalid code */
+          else if (*p < s)
+            {
+              r.e = (uch) (*p < 256 ? 16 : 15);         /* 256 is end-of-block code */
+              r.v.n = (ush) (*p);       /* simple code is just the value */
+              p++;              /* one compiler does not like *p++ */
+            }
+          else
+            {
+              r.e = (uch) e[*p - s];    /* non-simple--look up in lists */
+              r.v.n = d[*p++ - s];
+            }
+
+          /* fill code-like entries with r */
+          f = 1 << (k - w);
+          for (j = i >> w; j < z; j += f)
+            q[j] = r;
+
+          /* backwards increment the k-bit code i */
+          for (j = 1 << (k - 1); i & j; j >>= 1)
+            i ^= j;
+          i ^= j;
+
+          /* backup over finished tables */
+          while ((i & ((1 << w) - 1)) != x[h])
+            {
+              h--;              /* don't need to update q */
+              w -= l;
+            }
+        }
+    }
+
+  /* Return true (1) if we were given an incomplete table */
+  return y != 0 && g != 1;
+}
+
+
+/* Free the malloc'ed tables built by huft_build(), which makes a linked
+   list of the tables it made, with the links in a dummy first entry of
+   each table.  */
+static int
+huft_free (struct huft *t)
+{
+  register struct huft *p, *q;
+
+
+  /* Go through linked list, freeing from the malloced (t[-1]) address. */
+  p = t;
+  while (p != (struct huft *) NULL)
+    {
+      q = (--p)->v.t;
+      FreePool ((char *) p);
+      p = q;
+    }
+  return 0;
+}
+
+
+/*
+ *  inflate (decompress) the codes in a deflated (compressed) block.
+ *  Return an error code or zero if it all goes ok.
+ */
+
+static int
+inflate_codes_in_window (grub_gzio_t gzio)
+{
+  register unsigned e;          /* table entry flag/number of extra bits */
+  unsigned n, d;                /* length and index for copy */
+  unsigned w;                   /* current window position */
+  struct huft *t;               /* pointer to table entry */
+  unsigned ml, md;              /* masks for bl and bd bits */
+  register ulg b;               /* bit buffer */
+  register unsigned k;          /* number of bits in bit buffer */
+
+  /* make local copies of globals */
+  d = gzio->inflate_d;
+  n = gzio->inflate_n;
+  b = gzio->bb;                 /* initialize bit buffer */
+  k = gzio->bk;
+  w = gzio->wp;                 /* initialize window position */
+
+  /* inflate the coded data */
+  ml = mask_bits[gzio->bl];             /* precompute masks for speed */
+  md = mask_bits[gzio->bd];
+  for (;;)                      /* do until end of block */
+    {
+      if (! gzio->code_state)
+        {
+          NEEDBITS ((unsigned) gzio->bl);
+          if ((e = (t = gzio->tl + ((unsigned) b & ml))->e) > 16)
+            do
+              {
+                if (e == 99)
+                  {
+                    gzio->err = -1;
+                    return 1;
+                  }
+                DUMPBITS (t->b);
+                e -= 16;
+                NEEDBITS (e);
+              }
+            while ((e = (t = t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16);
+          DUMPBITS (t->b);
+
+          if (e == 16)          /* then it's a literal */
+            {
+              gzio->slide[w++] = (uch) t->v.n;
+              if (w == WSIZE)
+                break;
+            }
+          else
+            /* it's an EOB or a length */
+            {
+              /* exit if end of block */
+              if (e == 15)
+                {
+                  gzio->block_len = 0;
+                  break;
+                }
+
+              /* get length of block to copy */
+              NEEDBITS (e);
+              n = t->v.n + ((unsigned) b & mask_bits[e]);
+              DUMPBITS (e);
+
+              /* decode distance of block to copy */
+              NEEDBITS ((unsigned) gzio->bd);
+              if ((e = (t = gzio->td + ((unsigned) b & md))->e) > 16)
+                do
+                  {
+                    if (e == 99)
+                      {
+                        gzio->err = -1;
+                        return 1;
+                      }
+                    DUMPBITS (t->b);
+                    e -= 16;
+                    NEEDBITS (e);
+                  }
+                while ((e = (t = t->v.t + ((unsigned) b & mask_bits[e]))->e)
+                       > 16);
+              DUMPBITS (t->b);
+              NEEDBITS (e);
+              d = w - t->v.n - ((unsigned) b & mask_bits[e]);
+              DUMPBITS (e);
+              gzio->code_state++;
+            }
+        }
+
+      if (gzio->code_state)
+        {
+          /* do the copy */
+          do
+            {
+              n -= (e = (e = WSIZE - ((d &= WSIZE - 1) > w ? d : w)) > n ? n
+                    : e);
+
+              if (w - d >= e)
+                {
+                  fsw_memcpy (gzio->slide + w, gzio->slide + d, e);
+                  w += e;
+                  d += e;
+                }
+              else
+                /* purposefully use the overlap for extra copies here!! */
+                {
+                  while (e--)
+                    gzio->slide[w++] = gzio->slide[d++];
+                }
+
+              if (w == WSIZE)
+                break;
+            }
+          while (n);
+
+          if (! n)
+            gzio->code_state--;
+
+          /* did we break from the loop too soon? */
+          if (w == WSIZE)
+            break;
+        }
+    }
+
+  /* restore the globals from the locals */
+  gzio->inflate_d = d;
+  gzio->inflate_n = n;
+  gzio->wp = w;                 /* restore global window pointer */
+  gzio->bb = b;                 /* restore global bit buffer */
+  gzio->bk = k;
+
+  return ! gzio->block_len;
+}
+
+
+/* get header for an inflated type 0 (stored) block. */
+
+static void
+init_stored_block (grub_gzio_t gzio)
+{
+  register ulg b;               /* bit buffer */
+  register unsigned k;          /* number of bits in bit buffer */
+
+  /* make local copies of globals */
+  b = gzio->bb;                 /* initialize bit buffer */
+  k = gzio->bk;
+
+  /* go to byte boundary */
+  DUMPBITS (k & 7);
+
+  /* get the length and its complement */
+  NEEDBITS (16);
+  gzio->block_len = ((unsigned) b & 0xffff);
+  DUMPBITS (16);
+  NEEDBITS (16);
+  if (gzio->block_len != (int) ((~b) & 0xffff))
+    gzio->err = -1;
+  DUMPBITS (16);
+
+  /* restore global variables */
+  gzio->bb = b;
+  gzio->bk = k;
+}
+
+
+/* get header for an inflated type 1 (fixed Huffman codes) block.  We should
+   either replace this with a custom decoder, or at least precompute the
+   Huffman tables. */
+
+static void
+init_fixed_block (grub_gzio_t gzio)
+{
+  int i;                        /* temporary variable */
+  unsigned l[288];              /* length list for huft_build */
+
+  /* set up literal table */
+  for (i = 0; i < 144; i++)
+    l[i] = 8;
+  for (; i < 256; i++)
+    l[i] = 9;
+  for (; i < 280; i++)
+    l[i] = 7;
+  for (; i < 288; i++)          /* make a complete, but wrong code set */
+    l[i] = 8;
+  gzio->bl = 7;
+  if (huft_build (l, 288, 257, cplens, cplext, &gzio->tl, &gzio->bl) != 0)
+    {
+        gzio->err = -1;
+      return;
+    }
+
+  /* set up distance table */
+  for (i = 0; i < 30; i++)      /* make an incomplete code set */
+    l[i] = 5;
+  gzio->bd = 5;
+  if (huft_build (l, 30, 0, cpdist, cpdext, &gzio->td, &gzio->bd) > 1)
+    {
+        gzio->err = -1;
+      huft_free (gzio->tl);
+      gzio->tl = 0;
+      return;
+    }
+
+  /* indicate we're now working on a block */
+  gzio->code_state = 0;
+  gzio->block_len++;
+}
+
+
+/* get header for an inflated type 2 (dynamic Huffman codes) block. */
+
+static void
+init_dynamic_block (grub_gzio_t gzio)
+{
+  int i;                        /* temporary variables */
+  unsigned j;
+  unsigned l;                   /* last length */
+  unsigned m;                   /* mask for bit lengths table */
+  unsigned n;                   /* number of lengths to get */
+  unsigned nb;                  /* number of bit length codes */
+  unsigned nl;                  /* number of literal/length codes */
+  unsigned nd;                  /* number of distance codes */
+  unsigned ll[286 + 30];        /* literal/length and distance code lengths */
+  register ulg b;               /* bit buffer */
+  register unsigned k;          /* number of bits in bit buffer */
+
+  /* make local bit buffer */
+  b = gzio->bb;
+  k = gzio->bk;
+
+  /* read in table lengths */
+  NEEDBITS (5);
+  nl = 257 + ((unsigned) b & 0x1f);     /* number of literal/length codes */
+  DUMPBITS (5);
+  NEEDBITS (5);
+  nd = 1 + ((unsigned) b & 0x1f);       /* number of distance codes */
+  DUMPBITS (5);
+  NEEDBITS (4);
+  nb = 4 + ((unsigned) b & 0xf);        /* number of bit length codes */
+  DUMPBITS (4);
+  if (nl > 286 || nd > 30)
+    {
+      gzio->err = -1;
+      return;
+    }
+
+  /* read in bit-length-code lengths */
+  for (j = 0; j < nb; j++)
+    {
+      NEEDBITS (3);
+      ll[bitorder[j]] = (unsigned) b & 7;
+      DUMPBITS (3);
+    }
+  for (; j < 19; j++)
+    ll[bitorder[j]] = 0;
+
+  /* build decoding table for trees--single level, 7 bit lookup */
+  gzio->bl = 7;
+  if (huft_build (ll, 19, 19, NULL, NULL, &gzio->tl, &gzio->bl) != 0)
+    {
+      gzio->err = -1;
+      return;
+    }
+
+  /* read in literal and distance code lengths */
+  n = nl + nd;
+  m = mask_bits[gzio->bl];
+  i = l = 0;
+  while ((unsigned) i < n)
+    {
+      NEEDBITS ((unsigned) gzio->bl);
+      j = (gzio->td = gzio->tl + ((unsigned) b & m))->b;
+      DUMPBITS (j);
+      j = gzio->td->v.n;
+      if (j < 16)               /* length of code in bits (0..15) */
+        ll[i++] = l = j;        /* save last length in l */
+      else if (j == 16)         /* repeat last length 3 to 6 times */
+        {
+          NEEDBITS (2);
+          j = 3 + ((unsigned) b & 3);
+          DUMPBITS (2);
+          if ((unsigned) i + j > n)
+            {
+            gzio->err = -1;
+              return;
+            }
+          while (j--)
+            ll[i++] = l;
+        }
+      else if (j == 17)         /* 3 to 10 zero length codes */
+        {
+          NEEDBITS (3);
+          j = 3 + ((unsigned) b & 7);
+          DUMPBITS (3);
+          if ((unsigned) i + j > n)
+            {
+              gzio->err = -1;
+              return;
+            }
+          while (j--)
+            ll[i++] = 0;
+          l = 0;
+        }
+      else
+        /* j == 18: 11 to 138 zero length codes */
+        {
+          NEEDBITS (7);
+          j = 11 + ((unsigned) b & 0x7f);
+          DUMPBITS (7);
+          if ((unsigned) i + j > n)
+            {
+              gzio->err = -1;
+              return;
+            }
+          while (j--)
+            ll[i++] = 0;
+          l = 0;
+        }
+    }
+
+  /* free decoding table for trees */
+  huft_free (gzio->tl);
+  gzio->td = 0;
+  gzio->tl = 0;
+
+  /* restore the global bit buffer */
+  gzio->bb = b;
+  gzio->bk = k;
+
+  /* build the decoding tables for literal/length and distance codes */
+  gzio->bl = lbits;
+  if (huft_build (ll, nl, 257, cplens, cplext, &gzio->tl, &gzio->bl) != 0)
+    {
+      gzio->err = -1;
+      return;
+    }
+  gzio->bd = dbits;
+  if (huft_build (ll + nl, nd, 0, cpdist, cpdext, &gzio->td, &gzio->bd) != 0)
+    {
+      huft_free (gzio->tl);
+      gzio->tl = 0;
+      gzio->err = -1;
+      return;
+    }
+
+  /* indicate we're now working on a block */
+  gzio->code_state = 0;
+  gzio->block_len++;
+}
+
+
+static void
+get_new_block (grub_gzio_t gzio)
+{
+  register ulg b;               /* bit buffer */
+  register unsigned k;          /* number of bits in bit buffer */
+
+  /* make local bit buffer */
+  b = gzio->bb;
+  k = gzio->bk;
+
+  /* read in last block bit */
+  NEEDBITS (1);
+  gzio->last_block = (int) b & 1;
+  DUMPBITS (1);
+
+  /* read in block type */
+  NEEDBITS (2);
+  gzio->block_type = (unsigned) b & 3;
+  DUMPBITS (2);
+
+  /* restore the global bit buffer */
+  gzio->bb = b;
+  gzio->bk = k;
+
+  switch (gzio->block_type)
+    {
+    case INFLATE_STORED:
+      init_stored_block (gzio);
+      break;
+    case INFLATE_FIXED:
+      init_fixed_block (gzio);
+      break;
+    case INFLATE_DYNAMIC:
+      init_dynamic_block (gzio);
+      break;
+    default:
+      break;
+    }
+}
+
+
+static void
+inflate_window (grub_gzio_t gzio)
+{
+  /* initialize window */
+  gzio->wp = 0;
+
+  /*
+   *  Main decompression loop.
+   */
+
+  while (gzio->wp < WSIZE && !gzio->err)
+    {
+      if (! gzio->block_len)
+        {
+          if (gzio->last_block)
+            break;
+
+          get_new_block (gzio);
+        }
+
+      if (gzio->block_type > INFLATE_DYNAMIC)
+        gzio->err = -1;
+
+      if (gzio->err)
+        return;
+
+      /*
+       *  Expand stored block here.
+       */
+      if (gzio->block_type == INFLATE_STORED)
+        {
+          int w = gzio->wp;
+
+          /*
+           *  This is basically a glorified pass-through
+           */
+
+          while (gzio->block_len && w < WSIZE && !gzio->err)
+            {
+              gzio->slide[w++] = get_byte (gzio);
+              gzio->block_len--;
+            }
+
+          gzio->wp = w;
+
+          continue;
+        }
+
+      /*
+       *  Expand other kind of block.
+       */
+
+      if (inflate_codes_in_window (gzio))
+        {
+          huft_free (gzio->tl);
+          huft_free (gzio->td);
+          gzio->tl = 0;
+          gzio->td = 0;
+        }
+    }
+
+  gzio->saved_offset += WSIZE;
+
+  /* XXX do CRC calculation here! */
+}
+
+
+static void
+initialize_tables (grub_gzio_t gzio)
+{
+  gzio->saved_offset = 0;
+  gzio_seek (gzio, gzio->data_offset);
+
+  /* Initialize the bit buffer.  */
+  gzio->bk = 0;
+  gzio->bb = 0;
+
+  /* Reset partial decompression code.  */
+  gzio->last_block = 0;
+  gzio->block_len = 0;
+
+  /* Reset memory allocation stuff.  */
+  huft_free (gzio->tl);
+  huft_free (gzio->td);
+}
+
+
+static int
+test_zlib_header (grub_gzio_t gzio)
+{
+  uint8_t cmf, flg;
+  
+  cmf = get_byte (gzio);
+  flg = get_byte (gzio);
+
+  /* Check that compression method is DEFLATE.  */
+  if ((cmf & 0xf) != DEFLATED)
+    {
+      return 0;
+    }
+
+  if ((cmf * 256 + flg) % 31)
+    {
+      return 0;
+    }
+
+  /* Dictionary isn't supported.  */
+  if (flg & 0x20)
+    {
+      return 0;
+    }
+
+  gzio->data_offset = 2;
+  initialize_tables (gzio);
+
+  return 1;
+}
+
+static grub_ssize_t
+grub_gzio_read_real (grub_gzio_t gzio, grub_off_t offset,
+                     char *buf, grub_size_t len)
+{
+  grub_ssize_t ret = 0;
+
+  /* Do we reset decompression to the beginning of the file?  */
+  if (gzio->saved_offset > offset + WSIZE)
+    initialize_tables (gzio);
+
+  /*
+   *  This loop operates upon uncompressed data only.  The only
+   *  special thing it does is to make sure the decompression
+   *  window is within the range of data it needs.
+   */
+
+  while (len > 0 && !gzio->err)
+    {
+      register grub_size_t size;
+      register char *srcaddr;
+
+      while (offset >= gzio->saved_offset)
+        inflate_window (gzio);
+
+      srcaddr = (char *) ((offset & (WSIZE - 1)) + gzio->slide);
+      size = gzio->saved_offset - offset;
+      if (size > len)
+        size = len;
+
+      fsw_memcpy (buf, srcaddr, size);
+
+      buf += size;
+      len -= size;
+      ret += size;
+      offset += size;
+    }
+
+  if (gzio->err)
+    ret = -1;
+
+  return ret;
+}
+
+grub_ssize_t
+grub_zlib_decompress (char *inbuf, grub_size_t insize, grub_off_t off,
+                      char *outbuf, grub_size_t outsize)
+{
+  grub_gzio_t gzio = 0;
+  grub_ssize_t ret;
+
+  gzio = AllocatePool (sizeof (*gzio));
+  if (! gzio)
+    return -1;
+  fsw_memzero(gzio, sizeof(*gzio));
+  gzio->mem_input = (uint8_t *) inbuf;
+  gzio->mem_input_size = insize;
+  gzio->mem_input_off = 0;
+
+  if (!test_zlib_header (gzio))
+    {
+      FreePool (gzio);
+      return -1;
+    }
+
+  ret = grub_gzio_read_real (gzio, off, outbuf, outsize);
+  FreePool (gzio);
+
+  /* FIXME: Check Adler.  */
+  return ret;
+}
+
diff --git a/filesystems/hfs_format.h b/filesystems/hfs_format.h
new file mode 100644 (file)
index 0000000..c36272f
--- /dev/null
@@ -0,0 +1,812 @@
+/* $Id: hfs_format.h 33540 2010-10-28 09:27:05Z vboxsync $ */
+/** @file
+ * hfs_format.h
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/*
+ * This code is based on:
+ *
+ * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+#ifndef __HFS_FORMAT__
+#define __HFS_FORMAT__
+
+// #if !defined(HOST_EFI_EDK2) && !defined(HOST_POSIX)
+// // Only available on Mac? and Intel EFI Toolkit?
+// #include <sys/types.h>
+// #include <sys/appleapiopts.h>
+// #endif
+
+#ifdef _MSC_VER
+# pragma pack(push,2)
+# define HFS_ALIGNMENT
+#else
+#define HFS_ALIGNMENT __attribute__((aligned(2), packed))
+#endif
+
+/*
+ * hfs_format.c
+ *
+ * This file describes the on-disk format for HFS and HFS Plus volumes.
+ * The HFS Plus volume format is described in detail in Apple Technote 1150.
+ *
+ * http://developer.apple.com/technotes/tn/tn1150.html
+ *
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* some on-disk hfs structures have 68K alignment (misaligned) */
+
+/* Signatures used to differentiate between HFS and HFS Plus volumes */
+enum {
+       kHFSSigWord             = 0x4244,       /* 'BD' in ASCII */
+       kHFSPlusSigWord         = 0x482B,       /* 'H+' in ASCII */
+       kHFSXSigWord            = 0x4858,       /* 'HX' in ASCII */
+
+       kHFSPlusVersion         = 0x0004,       /* 'H+' volumes are version 4 only */
+       kHFSXVersion            = 0x0005,       /* 'HX' volumes start with version 5 */
+
+       kHFSPlusMountVersion    = 0x31302E30,   /* '10.0' for Mac OS X */
+       kHFSJMountVersion       = 0x4846534a,   /* 'HFSJ' for journaled HFS+ on OS X */
+       kFSKMountVersion        = 0x46534b21    /* 'FSK!' for failed journal replay */
+};
+
+
+#ifdef __APPLE_API_PRIVATE
+/*
+ * Mac OS X has two special directories on HFS+ volumes for hardlinked files
+ * and hardlinked directories as well as for open-unlinked files.
+ *
+ * These directories and their contents are not exported from the filesystem
+ * under Mac OS X.
+ */
+#define HFSPLUSMETADATAFOLDER       "\xE2\x90\x80\xE2\x90\x80\xE2\x90\x80\xE2\x90\x80HFS+ Private Data"
+#define HFSPLUS_DIR_METADATA_FOLDER ".HFS+ Private Directory Data\xd"
+
+/*
+ * Files in the "HFS+ Private Data" folder have one of the following prefixes
+ * followed by a decimal number (no leading zeros) for the file ID.
+ *
+ * Note: Earlier version of Mac OS X used a 32 bit random number for the link
+ * ref number instead of the file id.
+ *
+ * e.g.  iNode7182000 and temp3296
+ */
+#define HFS_INODE_PREFIX       "iNode"
+#define HFS_DELETE_PREFIX      "temp"
+
+/*
+ * Files in the ".HFS+ Private Directory Data" folder have the following
+ * prefix followed by a decimal number (no leading zeros) for the file ID.
+ *
+ * e.g. dir_555
+ */
+#define HFS_DIRINODE_PREFIX    "dir_"
+
+/*
+ * Hardlink inodes save the head of the link chain in
+ * an extended attribute named FIRST_LINK_XATTR_NAME.
+ * The attribute data is the decimal value in ASCII
+ * of the cnid for the first link in the chain.
+ *
+ * This extended attribute is private (i.e. its not
+ * exported in the getxattr/listxattr POSIX APIs).
+ */
+#define FIRST_LINK_XATTR_NAME  "com.apple.system.hfs.firstlink"
+#define FIRST_LINK_XATTR_REC_SIZE (sizeof(HFSPlusAttrData) - 2 + 12)
+
+#endif /* __APPLE_API_PRIVATE */
+
+/*
+ * Indirect link files (hard links) have the following type/creator.
+ */
+enum {
+       kHardLinkFileType = 0x686C6E6B,  /* 'hlnk' */
+       kHFSPlusCreator   = 0x6866732B   /* 'hfs+' */
+};
+
+
+/*
+ *     File type and creator for symbolic links
+ */
+enum {
+      kSymLinkFileType  = 0x736C6E6B, /* 'slnk' */
+      kSymLinkCreator   = 0x72686170  /* 'rhap' */
+};
+
+
+#ifndef _HFSUNISTR255_DEFINED_
+#define _HFSUNISTR255_DEFINED_
+/* Unicode strings are used for HFS Plus file and folder names */
+struct HFSUniStr255 {
+       u_int16_t       length;         /* number of unicode characters */
+       u_int16_t       unicode[255];   /* unicode characters */
+} HFS_ALIGNMENT;
+typedef struct HFSUniStr255 HFSUniStr255;
+typedef const HFSUniStr255 *ConstHFSUniStr255Param;
+#endif /* _HFSUNISTR255_DEFINED_ */
+
+enum {
+       kHFSMaxVolumeNameChars          = 27,
+       kHFSMaxFileNameChars            = 31,
+       kHFSPlusMaxFileNameChars        = 255
+};
+
+
+/* Extent overflow file data structures */
+
+/* HFS Extent key */
+struct HFSExtentKey {
+       u_int8_t        keyLength;      /* length of key, excluding this field */
+       u_int8_t        forkType;       /* 0 = data fork, FF = resource fork */
+       u_int32_t       fileID;         /* file ID */
+       u_int16_t       startBlock;     /* first file allocation block number in this extent */
+} HFS_ALIGNMENT;
+typedef struct HFSExtentKey HFSExtentKey;
+
+/* HFS Plus Extent key */
+struct HFSPlusExtentKey {
+       u_int16_t       keyLength;              /* length of key, excluding this field */
+       u_int8_t        forkType;               /* 0 = data fork, FF = resource fork */
+       u_int8_t        pad;                    /* make the other fields align on 32-bit boundary */
+       u_int32_t       fileID;                 /* file ID */
+       u_int32_t       startBlock;             /* first file allocation block number in this extent */
+} HFS_ALIGNMENT;
+typedef struct HFSPlusExtentKey HFSPlusExtentKey;
+
+/* Number of extent descriptors per extent record */
+enum {
+       kHFSExtentDensity       = 3,
+       kHFSPlusExtentDensity   = 8
+};
+
+/* HFS extent descriptor */
+struct HFSExtentDescriptor {
+       u_int16_t       startBlock;             /* first allocation block */
+       u_int16_t       blockCount;             /* number of allocation blocks */
+} HFS_ALIGNMENT;
+typedef struct HFSExtentDescriptor HFSExtentDescriptor;
+
+/* HFS Plus extent descriptor */
+struct HFSPlusExtentDescriptor {
+       u_int32_t       startBlock;             /* first allocation block */
+       u_int32_t       blockCount;             /* number of allocation blocks */
+} HFS_ALIGNMENT;
+typedef struct HFSPlusExtentDescriptor HFSPlusExtentDescriptor;
+
+/* HFS extent record */
+typedef HFSExtentDescriptor HFSExtentRecord[3];
+
+/* HFS Plus extent record */
+typedef HFSPlusExtentDescriptor HFSPlusExtentRecord[8];
+
+
+/* Finder information */
+struct FndrFileInfo {
+       u_int32_t       fdType;         /* file type */
+       u_int32_t       fdCreator;      /* file creator */
+       u_int16_t       fdFlags;        /* Finder flags */
+       struct {
+           int16_t     v;              /* file's location */
+           int16_t     h;
+       } fdLocation;
+       int16_t opaque;
+} HFS_ALIGNMENT;
+typedef struct FndrFileInfo FndrFileInfo;
+
+struct FndrDirInfo {
+       struct {                        /* folder's window rectangle */
+           int16_t     top;
+           int16_t     left;
+           int16_t     bottom;
+           int16_t     right;
+       } frRect;
+       unsigned short  frFlags;        /* Finder flags */
+       struct {
+           u_int16_t   v;              /* folder's location */
+           u_int16_t   h;
+       } frLocation;
+       int16_t opaque;
+} HFS_ALIGNMENT;
+typedef struct FndrDirInfo FndrDirInfo;
+
+struct FndrOpaqueInfo {
+       int8_t opaque[16];
+} HFS_ALIGNMENT;
+typedef struct FndrOpaqueInfo FndrOpaqueInfo;
+
+
+/* HFS Plus Fork data info - 80 bytes */
+struct HFSPlusForkData {
+       u_int64_t               logicalSize;    /* fork's logical size in bytes */
+       u_int32_t               clumpSize;      /* fork's clump size in bytes */
+       u_int32_t               totalBlocks;    /* total blocks used by this fork */
+       HFSPlusExtentRecord     extents;        /* initial set of extents */
+} HFS_ALIGNMENT;
+typedef struct HFSPlusForkData HFSPlusForkData;
+
+
+/* Mac OS X has 16 bytes worth of "BSD" info.
+ *
+ * Note:  Mac OS 9 implementations and applications
+ * should preserve, but not change, this information.
+ */
+struct HFSPlusBSDInfo {
+       u_int32_t       ownerID;        /* user-id of owner or hard link chain previous link */
+       u_int32_t       groupID;        /* group-id of owner or hard link chain next link */
+       u_int8_t        adminFlags;     /* super-user changeable flags */
+       u_int8_t        ownerFlags;     /* owner changeable flags */
+       u_int16_t       fileMode;       /* file type and permission bits */
+       union {
+           u_int32_t   iNodeNum;       /* indirect node number (hard links only) */
+           u_int32_t   linkCount;      /* links that refer to this indirect node */
+           u_int32_t   rawDevice;      /* special file device (FBLK and FCHR only) */
+       } special;
+} HFS_ALIGNMENT;
+typedef struct HFSPlusBSDInfo HFSPlusBSDInfo;
+
+/*
+ * Hardlink "links" resolve to an inode
+ * and the actual uid/gid comes from that
+ * inode.
+ *
+ * We repurpose the links's uid/gid fields
+ * for the hardlink link chain. The chain
+ * consists of a doubly linked list of file
+ * ids.
+ */
+
+#define hl_firstLinkID     reserved1         /* Valid only if HasLinkChain flag is set (indirect nodes only) */
+
+#define hl_prevLinkID      bsdInfo.ownerID   /* Valid only if HasLinkChain flag is set */
+#define hl_nextLinkID      bsdInfo.groupID   /* Valid only if HasLinkChain flag is set */
+
+#define hl_linkReference   bsdInfo.special.iNodeNum
+#define hl_linkCount       bsdInfo.special.linkCount
+
+
+/* Catalog file data structures */
+
+enum {
+       kHFSRootParentID                = 1,    /* Parent ID of the root folder */
+       kHFSRootFolderID                = 2,    /* Folder ID of the root folder */
+       kHFSExtentsFileID               = 3,    /* File ID of the extents file */
+       kHFSCatalogFileID               = 4,    /* File ID of the catalog file */
+       kHFSBadBlockFileID              = 5,    /* File ID of the bad allocation block file */
+       kHFSAllocationFileID            = 6,    /* File ID of the allocation file (HFS Plus only) */
+       kHFSStartupFileID               = 7,    /* File ID of the startup file (HFS Plus only) */
+       kHFSAttributesFileID            = 8,    /* File ID of the attribute file (HFS Plus only) */
+       kHFSAttributeDataFileID         = 13,   /* Used in Mac OS X runtime for extent based attributes */
+                                               /* kHFSAttributeDataFileID is never stored on disk. */
+       kHFSRepairCatalogFileID         = 14,   /* Used when rebuilding Catalog B-tree */
+       kHFSBogusExtentFileID           = 15,   /* Used for exchanging extents in extents file */
+       kHFSFirstUserCatalogNodeID      = 16
+};
+
+/* HFS catalog key */
+struct HFSCatalogKey {
+       u_int8_t        keyLength;              /* key length (in bytes) */
+       u_int8_t        reserved;               /* reserved (set to zero) */
+       u_int32_t       parentID;               /* parent folder ID */
+       u_int8_t        nodeName[kHFSMaxFileNameChars + 1]; /* catalog node name */
+} HFS_ALIGNMENT;
+typedef struct HFSCatalogKey HFSCatalogKey;
+
+/* HFS Plus catalog key */
+struct HFSPlusCatalogKey {
+       u_int16_t               keyLength;      /* key length (in bytes) */
+       u_int32_t               parentID;       /* parent folder ID */
+       HFSUniStr255            nodeName;       /* catalog node name */
+} HFS_ALIGNMENT;
+typedef struct HFSPlusCatalogKey HFSPlusCatalogKey;
+
+/* Catalog record types */
+enum {
+       /* HFS Catalog Records */
+       kHFSFolderRecord                = 0x0100,       /* Folder record */
+       kHFSFileRecord                  = 0x0200,       /* File record */
+       kHFSFolderThreadRecord          = 0x0300,       /* Folder thread record */
+       kHFSFileThreadRecord            = 0x0400,       /* File thread record */
+
+       /* HFS Plus Catalog Records */
+       kHFSPlusFolderRecord            = 1,            /* Folder record */
+       kHFSPlusFileRecord              = 2,            /* File record */
+       kHFSPlusFolderThreadRecord      = 3,            /* Folder thread record */
+       kHFSPlusFileThreadRecord        = 4             /* File thread record */
+};
+
+
+/* Catalog file record flags */
+enum {
+       kHFSFileLockedBit       = 0x0000,       /* file is locked and cannot be written to */
+       kHFSFileLockedMask      = 0x0001,
+
+       kHFSThreadExistsBit     = 0x0001,       /* a file thread record exists for this file */
+       kHFSThreadExistsMask    = 0x0002,
+
+       kHFSHasAttributesBit    = 0x0002,       /* object has extended attributes */
+       kHFSHasAttributesMask   = 0x0004,
+
+       kHFSHasSecurityBit      = 0x0003,       /* object has security data (ACLs) */
+       kHFSHasSecurityMask     = 0x0008,
+
+       kHFSHasFolderCountBit   = 0x0004,       /* only for HFSX, folder maintains a separate sub-folder count */
+       kHFSHasFolderCountMask  = 0x0010,       /* (sum of folder records and directory hard links) */
+
+       kHFSHasLinkChainBit     = 0x0005,       /* has hardlink chain (inode or link) */
+       kHFSHasLinkChainMask    = 0x0020,
+
+       kHFSHasChildLinkBit     = 0x0006,       /* folder has a child that's a dir link */
+       kHFSHasChildLinkMask    = 0x0040
+};
+
+
+/* HFS catalog folder record - 70 bytes */
+struct HFSCatalogFolder {
+       int16_t         recordType;             /* == kHFSFolderRecord */
+       u_int16_t               flags;                  /* folder flags */
+       u_int16_t               valence;                /* folder valence */
+       u_int32_t               folderID;               /* folder ID */
+       u_int32_t               createDate;             /* date and time of creation */
+       u_int32_t               modifyDate;             /* date and time of last modification */
+       u_int32_t               backupDate;             /* date and time of last backup */
+       FndrDirInfo             userInfo;               /* Finder information */
+       FndrOpaqueInfo          finderInfo;             /* additional Finder information */
+       u_int32_t               reserved[4];            /* reserved - initialized as zero */
+} HFS_ALIGNMENT;
+typedef struct HFSCatalogFolder HFSCatalogFolder;
+
+/* HFS Plus catalog folder record - 88 bytes */
+struct HFSPlusCatalogFolder {
+       int16_t         recordType;             /* == kHFSPlusFolderRecord */
+       u_int16_t               flags;                  /* file flags */
+       u_int32_t               valence;                /* folder's item count */
+       u_int32_t               folderID;               /* folder ID */
+       u_int32_t               createDate;             /* date and time of creation */
+       u_int32_t               contentModDate;         /* date and time of last content modification */
+       u_int32_t               attributeModDate;       /* date and time of last attribute modification */
+       u_int32_t               accessDate;             /* date and time of last access (MacOS X only) */
+       u_int32_t               backupDate;             /* date and time of last backup */
+       HFSPlusBSDInfo          bsdInfo;                /* permissions (for MacOS X) */
+       FndrDirInfo             userInfo;               /* Finder information */
+       FndrOpaqueInfo          finderInfo;             /* additional Finder information */
+       u_int32_t               textEncoding;           /* hint for name conversions */
+       u_int32_t               folderCount;            /* number of enclosed folders, active when HasFolderCount is set */
+} HFS_ALIGNMENT;
+typedef struct HFSPlusCatalogFolder HFSPlusCatalogFolder;
+
+/* HFS catalog file record - 102 bytes */
+struct HFSCatalogFile {
+       int16_t         recordType;             /* == kHFSFileRecord */
+       u_int8_t                flags;                  /* file flags */
+       int8_t                  fileType;               /* file type (unused ?) */
+       FndrFileInfo            userInfo;               /* Finder information */
+       u_int32_t               fileID;                 /* file ID */
+       u_int16_t               dataStartBlock;         /* not used - set to zero */
+       int32_t         dataLogicalSize;        /* logical EOF of data fork */
+       int32_t         dataPhysicalSize;       /* physical EOF of data fork */
+       u_int16_t               rsrcStartBlock;         /* not used - set to zero */
+       int32_t                 rsrcLogicalSize;        /* logical EOF of resource fork */
+       int32_t                 rsrcPhysicalSize;       /* physical EOF of resource fork */
+       u_int32_t               createDate;             /* date and time of creation */
+       u_int32_t               modifyDate;             /* date and time of last modification */
+       u_int32_t               backupDate;             /* date and time of last backup */
+       FndrOpaqueInfo          finderInfo;             /* additional Finder information */
+       u_int16_t               clumpSize;              /* file clump size (not used) */
+       HFSExtentRecord         dataExtents;            /* first data fork extent record */
+       HFSExtentRecord         rsrcExtents;            /* first resource fork extent record */
+       u_int32_t               reserved;               /* reserved - initialized as zero */
+} HFS_ALIGNMENT;
+typedef struct HFSCatalogFile HFSCatalogFile;
+
+/* HFS Plus catalog file record - 248 bytes */
+struct HFSPlusCatalogFile {
+       int16_t         recordType;             /* == kHFSPlusFileRecord */
+       u_int16_t               flags;                  /* file flags */
+       u_int32_t               reserved1;              /* reserved - initialized as zero */
+       u_int32_t               fileID;                 /* file ID */
+       u_int32_t               createDate;             /* date and time of creation */
+       u_int32_t               contentModDate;         /* date and time of last content modification */
+       u_int32_t               attributeModDate;       /* date and time of last attribute modification */
+       u_int32_t               accessDate;             /* date and time of last access (MacOS X only) */
+       u_int32_t               backupDate;             /* date and time of last backup */
+       HFSPlusBSDInfo          bsdInfo;                /* permissions (for MacOS X) */
+       FndrFileInfo            userInfo;               /* Finder information */
+       FndrOpaqueInfo          finderInfo;             /* additional Finder information */
+       u_int32_t               textEncoding;           /* hint for name conversions */
+       u_int32_t               reserved2;              /* reserved - initialized as zero */
+
+       /* Note: these start on double long (64 bit) boundary */
+       HFSPlusForkData dataFork;               /* size and block data for data fork */
+       HFSPlusForkData resourceFork;           /* size and block data for resource fork */
+} HFS_ALIGNMENT;
+typedef struct HFSPlusCatalogFile HFSPlusCatalogFile;
+
+/* HFS catalog thread record - 46 bytes */
+struct HFSCatalogThread {
+       int16_t recordType;             /* == kHFSFolderThreadRecord or kHFSFileThreadRecord */
+       int32_t reserved[2];            /* reserved - initialized as zero */
+       u_int32_t       parentID;               /* parent ID for this catalog node */
+       u_int8_t        nodeName[kHFSMaxFileNameChars + 1]; /* name of this catalog node */
+} HFS_ALIGNMENT;
+typedef struct HFSCatalogThread HFSCatalogThread;
+
+/* HFS Plus catalog thread record -- 264 bytes */
+struct HFSPlusCatalogThread {
+       int16_t recordType;             /* == kHFSPlusFolderThreadRecord or kHFSPlusFileThreadRecord */
+       int16_t reserved;               /* reserved - initialized as zero */
+       u_int32_t       parentID;               /* parent ID for this catalog node */
+       HFSUniStr255    nodeName;               /* name of this catalog node (variable length) */
+} HFS_ALIGNMENT;
+typedef struct HFSPlusCatalogThread HFSPlusCatalogThread;
+
+#ifdef __APPLE_API_UNSTABLE
+/*
+       These are the types of records in the attribute B-tree.  The values were
+       chosen so that they wouldn't conflict with the catalog record types.
+*/
+enum {
+       kHFSPlusAttrInlineData  = 0x10,   /* attributes whose data fits in a b-tree node */
+       kHFSPlusAttrForkData    = 0x20,   /* extent based attributes (data lives in extents) */
+       kHFSPlusAttrExtents     = 0x30    /* overflow extents for large attributes */
+};
+
+
+/*
+       HFSPlusAttrForkData
+       For larger attributes, whose value is stored in allocation blocks.
+       If the attribute has more than 8 extents, there will be additional
+       records (of type HFSPlusAttrExtents) for this attribute.
+*/
+struct HFSPlusAttrForkData {
+       u_int32_t       recordType;             /* == kHFSPlusAttrForkData*/
+       u_int32_t       reserved;
+       HFSPlusForkData theFork;                /* size and first extents of value*/
+} HFS_ALIGNMENT;
+typedef struct HFSPlusAttrForkData HFSPlusAttrForkData;
+
+/*
+       HFSPlusAttrExtents
+       This record contains information about overflow extents for large,
+       fragmented attributes.
+*/
+struct HFSPlusAttrExtents {
+       u_int32_t               recordType;     /* == kHFSPlusAttrExtents*/
+       u_int32_t               reserved;
+       HFSPlusExtentRecord     extents;        /* additional extents*/
+} HFS_ALIGNMENT;
+typedef struct HFSPlusAttrExtents HFSPlusAttrExtents;
+
+/*
+ * Attributes B-tree Data Record
+ *
+ * For small attributes, whose entire value is stored
+ * within a single B-tree record.
+ */
+struct HFSPlusAttrData {
+       u_int32_t    recordType;   /* == kHFSPlusAttrInlineData */
+       u_int32_t    reserved[2];
+       u_int32_t    attrSize;     /* size of attribute data in bytes */
+       u_int8_t     attrData[2];  /* variable length */
+} HFS_ALIGNMENT;
+typedef struct HFSPlusAttrData HFSPlusAttrData;
+
+
+/* HFSPlusAttrInlineData is obsolete use HFSPlusAttrData instead */
+struct HFSPlusAttrInlineData {
+       u_int32_t       recordType;
+       u_int32_t       reserved;
+       u_int32_t       logicalSize;
+       u_int8_t        userData[2];
+} HFS_ALIGNMENT;
+typedef struct HFSPlusAttrInlineData HFSPlusAttrInlineData;
+
+
+/*     A generic Attribute Record*/
+union HFSPlusAttrRecord {
+       u_int32_t               recordType;
+       HFSPlusAttrInlineData   inlineData;   /* NOT USED */
+       HFSPlusAttrData attrData;
+       HFSPlusAttrForkData     forkData;
+       HFSPlusAttrExtents      overflowExtents;
+};
+typedef union HFSPlusAttrRecord HFSPlusAttrRecord;
+
+/* Attribute key */
+enum { kHFSMaxAttrNameLen = 127 };
+struct HFSPlusAttrKey {
+       u_int16_t     keyLength;       /* key length (in bytes) */
+       u_int16_t     pad;             /* set to zero */
+       u_int32_t     fileID;          /* file associated with attribute */
+       u_int32_t     startBlock;      /* first allocation block number for extents */
+       u_int16_t     attrNameLen;     /* number of unicode characters */
+       u_int16_t     attrName[kHFSMaxAttrNameLen];   /* attribute name (Unicode) */
+} HFS_ALIGNMENT;
+typedef struct HFSPlusAttrKey HFSPlusAttrKey;
+
+#define kHFSPlusAttrKeyMaximumLength   (sizeof(HFSPlusAttrKey) - sizeof(u_int16_t))
+#define kHFSPlusAttrKeyMinimumLength   (kHFSPlusAttrKeyMaximumLength - kHFSMaxAttrNameLen*sizeof(u_int16_t))
+
+#endif /* __APPLE_API_UNSTABLE */
+
+
+/* Key and node lengths */
+enum {
+       kHFSPlusExtentKeyMaximumLength = sizeof(HFSPlusExtentKey) - sizeof(u_int16_t),
+       kHFSExtentKeyMaximumLength      = sizeof(HFSExtentKey) - sizeof(u_int8_t),
+       kHFSPlusCatalogKeyMaximumLength = sizeof(HFSPlusCatalogKey) - sizeof(u_int16_t),
+       kHFSPlusCatalogKeyMinimumLength = kHFSPlusCatalogKeyMaximumLength - sizeof(HFSUniStr255) + sizeof(u_int16_t),
+       kHFSCatalogKeyMaximumLength     = sizeof(HFSCatalogKey) - sizeof(u_int8_t),
+       kHFSCatalogKeyMinimumLength     = kHFSCatalogKeyMaximumLength - (kHFSMaxFileNameChars + 1) + sizeof(u_int8_t),
+       kHFSPlusCatalogMinNodeSize      = 4096,
+       kHFSPlusExtentMinNodeSize       = 512,
+       kHFSPlusAttrMinNodeSize         = 4096
+};
+
+/* HFS and HFS Plus volume attribute bits */
+enum {
+                                                       /* Bits 0-6 are reserved (always cleared by MountVol call) */
+       kHFSVolumeHardwareLockBit       = 7,            /* volume is locked by hardware */
+       kHFSVolumeUnmountedBit          = 8,            /* volume was successfully unmounted */
+       kHFSVolumeSparedBlocksBit       = 9,            /* volume has bad blocks spared */
+       kHFSVolumeNoCacheRequiredBit = 10,              /* don't cache volume blocks (i.e. RAM or ROM disk) */
+       kHFSBootVolumeInconsistentBit = 11,             /* boot volume is inconsistent (System 7.6 and later) */
+       kHFSCatalogNodeIDsReusedBit = 12,
+       kHFSVolumeJournaledBit = 13,                    /* this volume has a journal on it */
+       kHFSVolumeInconsistentBit = 14,                 /* serious inconsistencies detected at runtime */
+       kHFSVolumeSoftwareLockBit       = 15,           /* volume is locked by software */
+
+       kHFSVolumeHardwareLockMask      = 1 << kHFSVolumeHardwareLockBit,
+       kHFSVolumeUnmountedMask         = 1 << kHFSVolumeUnmountedBit,
+       kHFSVolumeSparedBlocksMask      = 1 << kHFSVolumeSparedBlocksBit,
+       kHFSVolumeNoCacheRequiredMask = 1 << kHFSVolumeNoCacheRequiredBit,
+       kHFSBootVolumeInconsistentMask = 1 << kHFSBootVolumeInconsistentBit,
+       kHFSCatalogNodeIDsReusedMask = 1 << kHFSCatalogNodeIDsReusedBit,
+       kHFSVolumeJournaledMask = 1 << kHFSVolumeJournaledBit,
+       kHFSVolumeInconsistentMask = 1 << kHFSVolumeInconsistentBit,
+       kHFSVolumeSoftwareLockMask      = 1 << kHFSVolumeSoftwareLockBit,
+       kHFSMDBAttributesMask           = 0x8380
+};
+
+/* HFS Master Directory Block - 162 bytes */
+/* Stored at sector #2 (3rd sector) and second-to-last sector. */
+struct HFSMasterDirectoryBlock {
+       u_int16_t               drSigWord;      /* == kHFSSigWord = 0x4244 = 'BD' or 'H+' or 'HX'*/
+       u_int32_t               drCrDate;       /* date and time of volume creation */
+       u_int32_t               drLsMod;        /* date and time of last modification */
+       u_int16_t               drAtrb;         /* volume attributes */
+       u_int16_t               drNmFls;        /* number of files in root folder */
+       u_int16_t               drVBMSt;        /* first block of volume bitmap */
+       u_int16_t               drAllocPtr;     /* start of next allocation search */
+       u_int16_t               drNmAlBlks;     /* number of allocation blocks in volume */
+       u_int32_t               drAlBlkSiz;     /* size (in bytes) of allocation blocks */
+       u_int32_t               drClpSiz;       /* default clump size */
+       u_int16_t               drAlBlSt;       /* first allocation block in volume */
+       u_int32_t               drNxtCNID;      /* next unused catalog node ID */
+       u_int16_t               drFreeBks;      /* number of unused allocation blocks */
+       u_int8_t                drVN[kHFSMaxVolumeNameChars + 1];  /* volume name */
+       u_int32_t               drVolBkUp;      /* date and time of last backup */
+       u_int16_t               drVSeqNum;      /* volume backup sequence number */
+       u_int32_t               drWrCnt;        /* volume write count */
+       u_int32_t               drXTClpSiz;     /* clump size for extents overflow file */
+       u_int32_t               drCTClpSiz;     /* clump size for catalog file */
+       u_int16_t               drNmRtDirs;     /* number of directories in root folder */
+       u_int32_t               drFilCnt;       /* number of files in volume */
+       u_int32_t               drDirCnt;       /* number of directories in volume */
+       u_int32_t               drFndrInfo[8];  /* information used by the Finder */
+       u_int16_t               drEmbedSigWord; /* embedded volume signature (formerly drVCSize) */
+       HFSExtentDescriptor     drEmbedExtent;  /* embedded volume location and size (formerly drVBMCSize and drCtlCSize) */
+       u_int32_t               drXTFlSize;     /* size of extents overflow file */
+       HFSExtentRecord         drXTExtRec;     /* extent record for extents overflow file */
+       u_int32_t               drCTFlSize;     /* size of catalog file */
+       HFSExtentRecord drCTExtRec;     /* extent record for catalog file */
+} HFS_ALIGNMENT;
+typedef struct HFSMasterDirectoryBlock HFSMasterDirectoryBlock;
+
+
+#ifdef __APPLE_API_UNSTABLE
+#define SET_HFS_TEXT_ENCODING(hint)  \
+       (0x656e6300 | ((hint) & 0xff))
+#define GET_HFS_TEXT_ENCODING(hint)  \
+       (((hint) & 0xffffff00) == 0x656e6300 ? (hint) & 0x000000ff : 0xffffffffU)
+#endif /* __APPLE_API_UNSTABLE */
+
+  /*
+   48 2B 00 04 80 00 20 00 48 46 53 4A 00 AD 7E 98  //H+ HFSJ
+   C9 12 D3 9E CB 84 F3 1D 00 00 00 00 C9 26 31 A8
+   00 12 1D 9D 00 03 66 B9 00 00 10 00 01 A1 2C CF
+   00 44 67 DF 01 35 EB A8 00 01 00 00 00 01 00 00
+   10 8B 1C EA 08 E4 9C 1B 00 00 00 00 02 00 00 8B
+   00 00 02 E7 10 3F CB 93 00 00 00 00 00 00 00 00
+   00 00 00 00 00 00 02 E7 6A 45 F3 37 EF 97 E9 A6
+   00 00 00 00 00 34 30 00 00 00 00 00 00 00 03 43
+   00 00 00 01 00 00 03 43 00 00 00 00 00 00 00 00
+   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+   00 00 00 00 00 70 00 00 00 70 00 00 00 00 07 00
+   00 00 13 45 00 00 07 00 00 00 00 00 00 00 00 00
+   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+   00 00 00 00 2A F8 00 00 01 90 00 00 00 02 AF 80
+   00 01 AA 55 00 01 90 00 00 14 5A C7 00 00 19 00
+   00 3D E4 E3 00 00 19 00 00 95 44 F7 00 00 19 00
+   00 9D 3B 18 00 00 32 00 00 E3 58 1C 00 00 19 00
+   00 48 1C 72 00 00 19 00 00 BB 6A 05 00 00 19 00
+   00 00 00 00 06 40 00 00 01 90 00 00 00 00 64 00
+   00 06 80 00 00 00 19 00 00 38 2A 2F 00 00 19 00
+   00 38 DB 2C 00 00 19 00 00 A6 A2 1F 00 00 19 00
+   */  
+  
+
+/* HFS Plus Volume Header - 512 bytes */
+/* Stored at sector #2 (3rd sector) and second-to-last sector. */
+struct HFSPlusVolumeHeader {
+       u_int16_t       signature;              /* == kHFSPlusSigWord */
+       u_int16_t       version;                /* == kHFSPlusVersion */
+       u_int32_t       attributes;             /* volume attributes */
+       u_int32_t       lastMountedVersion;     /* implementation version which last mounted volume */
+       u_int32_t       journalInfoBlock;       /* block addr of journal info (if volume is journaled, zero otherwise) */
+
+       u_int32_t       createDate;             /* date and time of volume creation */
+       u_int32_t       modifyDate;             /* date and time of last modification */
+       u_int32_t       backupDate;             /* date and time of last backup */
+       u_int32_t       checkedDate;            /* date and time of last disk check */
+
+       u_int32_t       fileCount;              /* number of files in volume */
+       u_int32_t       folderCount;            /* number of directories in volume */
+
+       u_int32_t       blockSize;              /* size (in bytes) of allocation blocks */
+       u_int32_t       totalBlocks;            /* number of allocation blocks in volume (includes this header and VBM*/
+       u_int32_t       freeBlocks;             /* number of unused allocation blocks */
+
+       u_int32_t       nextAllocation;         /* start of next allocation search */
+       u_int32_t       rsrcClumpSize;          /* default resource fork clump size */
+       u_int32_t       dataClumpSize;          /* default data fork clump size */
+       u_int32_t       nextCatalogID;          /* next unused catalog node ID */
+
+       u_int32_t       writeCount;             /* volume write count */
+       u_int64_t       encodingsBitmap;        /* which encodings have been use  on this volume */
+
+       u_int8_t        finderInfo[32];         /* information used by the Finder */
+
+       HFSPlusForkData  allocationFile;        /* allocation bitmap file */
+       HFSPlusForkData  extentsFile;           /* extents B-tree file */
+       HFSPlusForkData  catalogFile;           /* catalog B-tree file */
+       HFSPlusForkData  attributesFile;        /* extended attributes B-tree file */
+       HFSPlusForkData  startupFile;           /* boot file (secondary loader) */
+} HFS_ALIGNMENT;
+typedef struct HFSPlusVolumeHeader HFSPlusVolumeHeader;
+
+
+/* B-tree structures */
+
+enum BTreeKeyLimits{
+       kMaxKeyLength   = 520
+};
+
+union BTreeKey{
+       u_int8_t        length8;
+       u_int16_t       length16;
+       u_int8_t        rawData [kMaxKeyLength+2];
+};
+typedef union BTreeKey BTreeKey;
+
+/* BTNodeDescriptor -- Every B-tree node starts with these fields. */
+struct BTNodeDescriptor {
+       u_int32_t       fLink;                  /* next node at this level*/
+       u_int32_t       bLink;                  /* previous node at this level*/
+       int8_t          kind;                   /* kind of node (leaf, index, header, map)*/
+       u_int8_t        height;                 /* zero for header, map; child is one more than parent*/
+       u_int16_t       numRecords;             /* number of records in this node*/
+       u_int16_t       reserved;               /* reserved - initialized as zero */
+} HFS_ALIGNMENT;
+typedef struct BTNodeDescriptor BTNodeDescriptor;
+
+/* Constants for BTNodeDescriptor kind */
+enum {
+       kBTLeafNode     = -1,
+       kBTIndexNode    = 0,
+       kBTHeaderNode   = 1,
+       kBTMapNode      = 2
+};
+
+/* BTHeaderRec -- The first record of a B-tree header node */
+struct BTHeaderRec {
+       u_int16_t       treeDepth;              /* maximum height (usually leaf nodes) */
+       u_int32_t       rootNode;               /* node number of root node */
+       u_int32_t       leafRecords;            /* number of leaf records in all leaf nodes */
+       u_int32_t       firstLeafNode;          /* node number of first leaf node */
+       u_int32_t       lastLeafNode;           /* node number of last leaf node */
+       u_int16_t       nodeSize;               /* size of a node, in bytes */
+       u_int16_t       maxKeyLength;           /* reserved */
+       u_int32_t       totalNodes;             /* total number of nodes in tree */
+       u_int32_t       freeNodes;              /* number of unused (free) nodes in tree */
+       u_int16_t       reserved1;              /* unused */
+       u_int32_t       clumpSize;              /* reserved */
+       u_int8_t        btreeType;              /* reserved */
+       u_int8_t        keyCompareType;         /* Key string Comparison Type */
+       u_int32_t       attributes;             /* persistent attributes about the tree */
+       u_int32_t       reserved3[16];          /* reserved */
+} HFS_ALIGNMENT;
+typedef struct BTHeaderRec BTHeaderRec;
+
+/* Constants for BTHeaderRec attributes */
+enum {
+       kBTBadCloseMask          = 0x00000001,  /* reserved */
+       kBTBigKeysMask           = 0x00000002,  /* key length field is 16 bits */
+       kBTVariableIndexKeysMask = 0x00000004   /* keys in index nodes are variable length */
+};
+
+
+/* Catalog Key Name Comparison Type */
+enum {
+       kHFSCaseFolding   = 0xCF,  /* case folding (case-insensitive) */
+       kHFSBinaryCompare = 0xBC  /* binary compare (case-sensitive) */
+};
+
+/* JournalInfoBlock - Structure that describes where our journal lives */
+struct JournalInfoBlock {
+       u_int32_t       flags;
+       u_int32_t       device_signature[8];  // signature used to locate our device.
+       u_int64_t       offset;               // byte offset to the journal on the device
+       u_int64_t       size;                 // size in bytes of the journal
+       u_int32_t       reserved[32];
+} HFS_ALIGNMENT;
+typedef struct JournalInfoBlock JournalInfoBlock;
+
+enum {
+    kJIJournalInFSMask          = 0x00000001,
+    kJIJournalOnOtherDeviceMask = 0x00000002,
+    kJIJournalNeedInitMask      = 0x00000004
+};
+
+
+#ifdef __cplusplus
+}
+#endif
+#ifdef _MSC_VER
+# pragma pack(pop)
+#endif
+
+#endif /* __HFS_FORMAT__ */
diff --git a/filesystems/lzoconf.h b/filesystems/lzoconf.h
new file mode 100644 (file)
index 0000000..bcd96b4
--- /dev/null
@@ -0,0 +1,451 @@
+/*
+ * this file take from grub 2.0
+ * for btrfs UEFI driver
+ */
+
+/* lzoconf.h -- configuration of the LZO data compression library
+
+   This file is part of the LZO real-time data compression library.
+
+   Copyright (C) 2011 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2010 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2009 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
+   All Rights Reserved.
+
+   The LZO library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   The LZO library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with the LZO library; see the file COPYING.
+   If not, write to the Free Software Foundation, Inc.,
+   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+   Markus F.X.J. Oberhumer
+   <markus@oberhumer.com>
+   http://www.oberhumer.com/opensource/lzo/
+ */
+
+
+#ifndef __LZOCONF_H_INCLUDED
+#define __LZOCONF_H_INCLUDED 1
+
+#define LZO_VERSION             0x2050
+#define LZO_VERSION_STRING      "2.05"
+#define LZO_VERSION_DATE        "Apr 23 2011"
+
+/* internal Autoconf configuration file - only used when building LZO */
+#if defined(LZO_HAVE_CONFIG_H)
+#  include <config.h>
+#endif
+#include <limits.h>
+#include <stddef.h>
+
+
+/***********************************************************************
+// LZO requires a conforming <limits.h>
+************************************************************************/
+
+#if !defined(CHAR_BIT) || (CHAR_BIT != 8)
+#  error "invalid CHAR_BIT"
+#endif
+#if !defined(UCHAR_MAX) || !defined(UINT_MAX) || !defined(ULONG_MAX)
+#  error "check your compiler installation"
+#endif
+#if (USHRT_MAX < 1) || (UINT_MAX < 1) || (ULONG_MAX < 1)
+#  error "your limits.h macros are broken"
+#endif
+
+/* get OS and architecture defines */
+#ifndef __LZODEFS_H_INCLUDED
+#include "lzodefs.h"
+#endif
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/***********************************************************************
+// some core defines
+************************************************************************/
+
+#if !defined(LZO_UINT32_C)
+#  if (UINT_MAX < LZO_0xffffffffL)
+#    define LZO_UINT32_C(c)     c ## UL
+#  else
+#    define LZO_UINT32_C(c)     ((c) + 0U)
+#  endif
+#endif
+
+/* memory checkers */
+#if !defined(__LZO_CHECKER)
+#  if defined(__BOUNDS_CHECKING_ON)
+#    define __LZO_CHECKER       1
+#  elif defined(__CHECKER__)
+#    define __LZO_CHECKER       1
+#  elif defined(__INSURE__)
+#    define __LZO_CHECKER       1
+#  elif defined(__PURIFY__)
+#    define __LZO_CHECKER       1
+#  endif
+#endif
+
+
+/***********************************************************************
+// integral and pointer types
+************************************************************************/
+
+/* lzo_uint should match size_t */
+#if !defined(LZO_UINT_MAX)
+#  if defined(LZO_ABI_LLP64) /* WIN64 */
+#    if defined(LZO_OS_WIN64)
+     typedef unsigned __int64   lzo_uint;
+     typedef __int64            lzo_int;
+#    else
+     typedef unsigned long long lzo_uint;
+     typedef long long          lzo_int;
+#    endif
+#    define LZO_UINT_MAX        0xffffffffffffffffull
+#    define LZO_INT_MAX         9223372036854775807LL
+#    define LZO_INT_MIN         (-1LL - LZO_INT_MAX)
+#  elif defined(LZO_ABI_IP32L64) /* MIPS R5900 */
+     typedef unsigned int       lzo_uint;
+     typedef int                lzo_int;
+#    define LZO_UINT_MAX        UINT_MAX
+#    define LZO_INT_MAX         INT_MAX
+#    define LZO_INT_MIN         INT_MIN
+#  elif (ULONG_MAX >= LZO_0xffffffffL)
+     typedef unsigned long      lzo_uint;
+     typedef long               lzo_int;
+#    define LZO_UINT_MAX        ULONG_MAX
+#    define LZO_INT_MAX         LONG_MAX
+#    define LZO_INT_MIN         LONG_MIN
+#  else
+#    error "lzo_uint"
+#  endif
+#endif
+
+/* Integral types with 32 bits or more. */
+#if !defined(LZO_UINT32_MAX)
+#  if (UINT_MAX >= LZO_0xffffffffL)
+     typedef unsigned int       lzo_uint32;
+     typedef int                lzo_int32;
+#    define LZO_UINT32_MAX      UINT_MAX
+#    define LZO_INT32_MAX       INT_MAX
+#    define LZO_INT32_MIN       INT_MIN
+#  elif (ULONG_MAX >= LZO_0xffffffffL)
+     typedef unsigned long      lzo_uint32;
+     typedef long               lzo_int32;
+#    define LZO_UINT32_MAX      ULONG_MAX
+#    define LZO_INT32_MAX       LONG_MAX
+#    define LZO_INT32_MIN       LONG_MIN
+#  else
+#    error "lzo_uint32"
+#  endif
+#endif
+
+/* Integral types with exactly 64 bits. */
+#if !defined(LZO_UINT64_MAX)
+#  if (LZO_UINT_MAX >= LZO_0xffffffffL)
+#   if ((((LZO_UINT_MAX) >> 31) >> 31) == 3)
+#    define lzo_uint64          lzo_uint
+#    define lzo_int64           lzo_int
+#    define LZO_UINT64_MAX      LZO_UINT_MAX
+#    define LZO_INT64_MAX       LZO_INT_MAX
+#    define LZO_INT64_MIN       LZO_INT_MIN
+#   endif
+#  elif (ULONG_MAX >= LZO_0xffffffffL)
+#   if ((((ULONG_MAX) >> 31) >> 31) == 3)
+     typedef unsigned long      lzo_uint64;
+     typedef long               lzo_int64;
+#    define LZO_UINT64_MAX      ULONG_MAX
+#    define LZO_INT64_MAX       LONG_MAX
+#    define LZO_INT64_MIN       LONG_MIN
+#   endif
+#  endif
+#endif
+
+/* The larger type of lzo_uint and lzo_uint32. */
+#if (LZO_UINT_MAX >= LZO_UINT32_MAX)
+#  define lzo_xint              lzo_uint
+#else
+#  define lzo_xint              lzo_uint32
+#endif
+
+/* Memory model that allows to access memory at offsets of lzo_uint. */
+#if !defined(__LZO_MMODEL)
+#  if (LZO_UINT_MAX <= UINT_MAX)
+#    define __LZO_MMODEL        /*empty*/
+#  elif defined(LZO_HAVE_MM_HUGE_PTR)
+#    define __LZO_MMODEL_HUGE   1
+#    define __LZO_MMODEL        __huge
+#  else
+#    define __LZO_MMODEL        /*empty*/
+#  endif
+#endif
+
+/* no typedef here because of const-pointer issues */
+#define lzo_bytep               unsigned char __LZO_MMODEL *
+#define lzo_charp               char __LZO_MMODEL *
+#define lzo_voidp               void __LZO_MMODEL *
+#define lzo_shortp              short __LZO_MMODEL *
+#define lzo_ushortp             unsigned short __LZO_MMODEL *
+#define lzo_uint32p             lzo_uint32 __LZO_MMODEL *
+#define lzo_int32p              lzo_int32 __LZO_MMODEL *
+#if defined(LZO_UINT64_MAX)
+#define lzo_uint64p             lzo_uint64 __LZO_MMODEL *
+#define lzo_int64p              lzo_int64 __LZO_MMODEL *
+#endif
+#define lzo_uintp               lzo_uint __LZO_MMODEL *
+#define lzo_intp                lzo_int __LZO_MMODEL *
+#define lzo_xintp               lzo_xint __LZO_MMODEL *
+#define lzo_voidpp              lzo_voidp __LZO_MMODEL *
+#define lzo_bytepp              lzo_bytep __LZO_MMODEL *
+/* deprecated - use 'lzo_bytep' instead of 'lzo_byte *' */
+#define lzo_byte                unsigned char __LZO_MMODEL
+
+typedef int lzo_bool;
+
+
+/***********************************************************************
+// function types
+************************************************************************/
+
+/* name mangling */
+#if !defined(__LZO_EXTERN_C)
+#  ifdef __cplusplus
+#    define __LZO_EXTERN_C      extern "C"
+#  else
+#    define __LZO_EXTERN_C      extern
+#  endif
+#endif
+
+/* calling convention */
+#if !defined(__LZO_CDECL)
+#  define __LZO_CDECL           __lzo_cdecl
+#endif
+
+/* DLL export information */
+#if !defined(__LZO_EXPORT1)
+#  define __LZO_EXPORT1         /*empty*/
+#endif
+#if !defined(__LZO_EXPORT2)
+#  define __LZO_EXPORT2         /*empty*/
+#endif
+
+/* __cdecl calling convention for public C and assembly functions */
+#if !defined(LZO_PUBLIC)
+#  define LZO_PUBLIC(_rettype)  __LZO_EXPORT1 _rettype __LZO_EXPORT2 __LZO_CDECL
+#endif
+#if !defined(LZO_EXTERN)
+#  define LZO_EXTERN(_rettype)  __LZO_EXTERN_C LZO_PUBLIC(_rettype)
+#endif
+#if !defined(LZO_PRIVATE)
+#  define LZO_PRIVATE(_rettype) static _rettype __LZO_CDECL
+#endif
+
+/* function types */
+typedef int
+(__LZO_CDECL *lzo_compress_t)   ( const lzo_bytep src, lzo_uint  src_len,
+                                        lzo_bytep dst, lzo_uintp dst_len,
+                                        lzo_voidp wrkmem );
+
+typedef int
+(__LZO_CDECL *lzo_decompress_t) ( const lzo_bytep src, lzo_uint  src_len,
+                                        lzo_bytep dst, lzo_uintp dst_len,
+                                        lzo_voidp wrkmem );
+
+typedef int
+(__LZO_CDECL *lzo_optimize_t)   (       lzo_bytep src, lzo_uint  src_len,
+                                        lzo_bytep dst, lzo_uintp dst_len,
+                                        lzo_voidp wrkmem );
+
+typedef int
+(__LZO_CDECL *lzo_compress_dict_t)(const lzo_bytep src, lzo_uint  src_len,
+                                         lzo_bytep dst, lzo_uintp dst_len,
+                                         lzo_voidp wrkmem,
+                                   const lzo_bytep dict, lzo_uint dict_len );
+
+typedef int
+(__LZO_CDECL *lzo_decompress_dict_t)(const lzo_bytep src, lzo_uint  src_len,
+                                           lzo_bytep dst, lzo_uintp dst_len,
+                                           lzo_voidp wrkmem,
+                                     const lzo_bytep dict, lzo_uint dict_len );
+
+
+/* Callback interface. Currently only the progress indicator ("nprogress")
+ * is used, but this may change in a future release. */
+
+struct lzo_callback_t;
+typedef struct lzo_callback_t lzo_callback_t;
+#define lzo_callback_p lzo_callback_t __LZO_MMODEL *
+
+/* malloc & free function types */
+typedef lzo_voidp (__LZO_CDECL *lzo_alloc_func_t)
+    (lzo_callback_p self, lzo_uint items, lzo_uint size);
+typedef void      (__LZO_CDECL *lzo_free_func_t)
+    (lzo_callback_p self, lzo_voidp ptr);
+
+/* a progress indicator callback function */
+typedef void (__LZO_CDECL *lzo_progress_func_t)
+    (lzo_callback_p, lzo_uint, lzo_uint, int);
+
+struct lzo_callback_t
+{
+    /* custom allocators (set to 0 to disable) */
+    lzo_alloc_func_t nalloc;                /* [not used right now] */
+    lzo_free_func_t nfree;                  /* [not used right now] */
+
+    /* a progress indicator callback function (set to 0 to disable) */
+    lzo_progress_func_t nprogress;
+
+    /* NOTE: the first parameter "self" of the nalloc/nfree/nprogress
+     * callbacks points back to this struct, so you are free to store
+     * some extra info in the following variables. */
+    lzo_voidp user1;
+    lzo_xint user2;
+    lzo_xint user3;
+};
+
+
+/***********************************************************************
+// error codes and prototypes
+************************************************************************/
+
+/* Error codes for the compression/decompression functions. Negative
+ * values are errors, positive values will be used for special but
+ * normal events.
+ */
+#define LZO_E_OK                    0
+#define LZO_E_ERROR                 (-1)
+#define LZO_E_OUT_OF_MEMORY         (-2)    /* [lzo_alloc_func_t failure] */
+#define LZO_E_NOT_COMPRESSIBLE      (-3)    /* [not used right now] */
+#define LZO_E_INPUT_OVERRUN         (-4)
+#define LZO_E_OUTPUT_OVERRUN        (-5)
+#define LZO_E_LOOKBEHIND_OVERRUN    (-6)
+#define LZO_E_EOF_NOT_FOUND         (-7)
+#define LZO_E_INPUT_NOT_CONSUMED    (-8)
+#define LZO_E_NOT_YET_IMPLEMENTED   (-9)    /* [not used right now] */
+#define LZO_E_INVALID_ARGUMENT      (-10)
+
+
+#ifndef lzo_sizeof_dict_t
+#  define lzo_sizeof_dict_t     ((unsigned)sizeof(lzo_bytep))
+#endif
+
+/* lzo_init() should be the first function you call.
+ * Check the return code !
+ *
+ * lzo_init() is a macro to allow checking that the library and the
+ * compiler's view of various types are consistent.
+ */
+#define lzo_init() __lzo_init_v2(LZO_VERSION,(int)sizeof(short),(int)sizeof(int),\
+    (int)sizeof(long),(int)sizeof(lzo_uint32),(int)sizeof(lzo_uint),\
+    (int)lzo_sizeof_dict_t,(int)sizeof(char *),(int)sizeof(lzo_voidp),\
+    (int)sizeof(lzo_callback_t))
+LZO_EXTERN(int) __lzo_init_v2(unsigned,int,int,int,int,int,int,int,int,int);
+
+/* version functions (useful for shared libraries) */
+LZO_EXTERN(unsigned) lzo_version(void);
+LZO_EXTERN(const char *) lzo_version_string(void);
+LZO_EXTERN(const char *) lzo_version_date(void);
+LZO_EXTERN(const lzo_charp) _lzo_version_string(void);
+LZO_EXTERN(const lzo_charp) _lzo_version_date(void);
+
+/* string functions */
+LZO_EXTERN(int)
+    lzo_memcmp(const lzo_voidp a, const lzo_voidp b, lzo_uint len);
+LZO_EXTERN(lzo_voidp)
+    lzo_memcpy(lzo_voidp dst, const lzo_voidp src, lzo_uint len);
+LZO_EXTERN(lzo_voidp)
+    lzo_memmove(lzo_voidp dst, const lzo_voidp src, lzo_uint len);
+LZO_EXTERN(lzo_voidp)
+    lzo_memset(lzo_voidp buf, int c, lzo_uint len);
+
+/* checksum functions */
+LZO_EXTERN(lzo_uint32)
+    lzo_adler32(lzo_uint32 c, const lzo_bytep buf, lzo_uint len);
+LZO_EXTERN(lzo_uint32)
+    lzo_crc32(lzo_uint32 c, const lzo_bytep buf, lzo_uint len);
+LZO_EXTERN(const lzo_uint32p)
+    lzo_get_crc32_table(void);
+
+/* misc. */
+LZO_EXTERN(int) _lzo_config_check(void);
+typedef union { lzo_bytep p; lzo_uint u; } __lzo_pu_u;
+typedef union { lzo_bytep p; lzo_uint32 u32; } __lzo_pu32_u;
+typedef union { void *vp; lzo_bytep bp; lzo_uint u; lzo_uint32 u32; unsigned long l; } lzo_align_t;
+
+/* align a char pointer on a boundary that is a multiple of 'size' */
+LZO_EXTERN(unsigned) __lzo_align_gap(const lzo_voidp p, lzo_uint size);
+#define LZO_PTR_ALIGN_UP(p,size) \
+    ((p) + (lzo_uint) __lzo_align_gap((const lzo_voidp)(p),(lzo_uint)(size)))
+
+
+/***********************************************************************
+// deprecated macros - only for backward compatibility with LZO v1.xx
+************************************************************************/
+
+#if defined(LZO_CFG_COMPAT)
+
+#define __LZOCONF_H 1
+
+#if defined(LZO_ARCH_I086)
+#  define __LZO_i386 1
+#elif defined(LZO_ARCH_I386)
+#  define __LZO_i386 1
+#endif
+
+#if defined(LZO_OS_DOS16)
+#  define __LZO_DOS 1
+#  define __LZO_DOS16 1
+#elif defined(LZO_OS_DOS32)
+#  define __LZO_DOS 1
+#elif defined(LZO_OS_WIN16)
+#  define __LZO_WIN 1
+#  define __LZO_WIN16 1
+#elif defined(LZO_OS_WIN32)
+#  define __LZO_WIN 1
+#endif
+
+#define __LZO_CMODEL            /*empty*/
+#define __LZO_DMODEL            /*empty*/
+#define __LZO_ENTRY             __LZO_CDECL
+#define LZO_EXTERN_CDECL        LZO_EXTERN
+#define LZO_ALIGN               LZO_PTR_ALIGN_UP
+
+#define lzo_compress_asm_t      lzo_compress_t
+#define lzo_decompress_asm_t    lzo_decompress_t
+
+#endif /* LZO_CFG_COMPAT */
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* already included */
+
+
+/* vim:set ts=4 et: */
diff --git a/filesystems/lzodefs.h b/filesystems/lzodefs.h
new file mode 100644 (file)
index 0000000..0ddd5b2
--- /dev/null
@@ -0,0 +1,1857 @@
+/*
+ * this file take from grub 2.0
+ * for btrfs UEFI driver
+ */
+
+/* lzodefs.h -- architecture, OS and compiler specific defines
+
+   This file is part of the LZO real-time data compression library.
+
+   Copyright (C) 2011 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2010 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2009 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
+   All Rights Reserved.
+
+   The LZO library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   The LZO library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with the LZO library; see the file COPYING.
+   If not, write to the Free Software Foundation, Inc.,
+   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+   Markus F.X.J. Oberhumer
+   <markus@oberhumer.com>
+   http://www.oberhumer.com/opensource/lzo/
+ */
+
+
+#ifndef __LZODEFS_H_INCLUDED
+#define __LZODEFS_H_INCLUDED 1
+
+#if defined(__CYGWIN32__) && !defined(__CYGWIN__)
+#  define __CYGWIN__ __CYGWIN32__
+#endif
+#if defined(__IBMCPP__) && !defined(__IBMC__)
+#  define __IBMC__ __IBMCPP__
+#endif
+#if defined(__ICL) && defined(_WIN32) && !defined(__INTEL_COMPILER)
+#  define __INTEL_COMPILER __ICL
+#endif
+#if 1 && defined(__INTERIX) && defined(__GNUC__) && !defined(_ALL_SOURCE)
+#  define _ALL_SOURCE 1
+#endif
+#if defined(__mips__) && defined(__R5900__)
+#  if !defined(__LONG_MAX__)
+#    define __LONG_MAX__ 9223372036854775807L
+#  endif
+#endif
+#if defined(__INTEL_COMPILER) && defined(__linux__)
+#  pragma warning(disable: 193)
+#endif
+#if defined(__KEIL__) && defined(__C166__)
+#  pragma warning disable = 322
+#elif 0 && defined(__C251__)
+#  pragma warning disable = 322
+#endif
+#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__MWERKS__)
+#  if (_MSC_VER >= 1300)
+#    pragma warning(disable: 4668)
+#  endif
+#endif
+#if 0 && defined(__WATCOMC__)
+#  if (__WATCOMC__ >= 1050) && (__WATCOMC__ < 1060)
+#    pragma warning 203 9
+#  endif
+#endif
+#if defined(__BORLANDC__) && defined(__MSDOS__) && !defined(__FLAT__)
+#  pragma option -h
+#endif
+#if 0
+#define LZO_0xffffL             0xfffful
+#define LZO_0xffffffffL         0xfffffffful
+#else
+#define LZO_0xffffL             65535ul
+#define LZO_0xffffffffL         4294967295ul
+#endif
+#if (LZO_0xffffL == LZO_0xffffffffL)
+#  error "your preprocessor is broken 1"
+#endif
+#if (16ul * 16384ul != 262144ul)
+#  error "your preprocessor is broken 2"
+#endif
+#if 0
+#if (32767 >= 4294967295ul)
+#  error "your preprocessor is broken 3"
+#endif
+#if (65535u >= 4294967295ul)
+#  error "your preprocessor is broken 4"
+#endif
+#endif
+#if (UINT_MAX == LZO_0xffffL)
+#if defined(__ZTC__) && defined(__I86__) && !defined(__OS2__)
+#  if !defined(MSDOS)
+#    define MSDOS 1
+#  endif
+#  if !defined(_MSDOS)
+#    define _MSDOS 1
+#  endif
+#elif 0 && defined(__VERSION) && defined(MB_LEN_MAX)
+#  if (__VERSION == 520) && (MB_LEN_MAX == 1)
+#    if !defined(__AZTEC_C__)
+#      define __AZTEC_C__ __VERSION
+#    endif
+#    if !defined(__DOS__)
+#      define __DOS__ 1
+#    endif
+#  endif
+#endif
+#endif
+#if defined(_MSC_VER) && defined(M_I86HM) && (UINT_MAX == LZO_0xffffL)
+#  define ptrdiff_t long
+#  define _PTRDIFF_T_DEFINED 1
+#endif
+#if (UINT_MAX == LZO_0xffffL)
+#  undef __LZO_RENAME_A
+#  undef __LZO_RENAME_B
+#  if defined(__AZTEC_C__) && defined(__DOS__)
+#    define __LZO_RENAME_A 1
+#  elif defined(_MSC_VER) && defined(MSDOS)
+#    if (_MSC_VER < 600)
+#      define __LZO_RENAME_A 1
+#    elif (_MSC_VER < 700)
+#      define __LZO_RENAME_B 1
+#    endif
+#  elif defined(__TSC__) && defined(__OS2__)
+#    define __LZO_RENAME_A 1
+#  elif defined(__MSDOS__) && defined(__TURBOC__) && (__TURBOC__ < 0x0410)
+#    define __LZO_RENAME_A 1
+#  elif defined(__PACIFIC__) && defined(DOS)
+#    if !defined(__far)
+#      define __far far
+#    endif
+#    if !defined(__near)
+#      define __near near
+#    endif
+#  endif
+#  if defined(__LZO_RENAME_A)
+#    if !defined(__cdecl)
+#      define __cdecl cdecl
+#    endif
+#    if !defined(__far)
+#      define __far far
+#    endif
+#    if !defined(__huge)
+#      define __huge huge
+#    endif
+#    if !defined(__near)
+#      define __near near
+#    endif
+#    if !defined(__pascal)
+#      define __pascal pascal
+#    endif
+#    if !defined(__huge)
+#      define __huge huge
+#    endif
+#  elif defined(__LZO_RENAME_B)
+#    if !defined(__cdecl)
+#      define __cdecl _cdecl
+#    endif
+#    if !defined(__far)
+#      define __far _far
+#    endif
+#    if !defined(__huge)
+#      define __huge _huge
+#    endif
+#    if !defined(__near)
+#      define __near _near
+#    endif
+#    if !defined(__pascal)
+#      define __pascal _pascal
+#    endif
+#  elif (defined(__PUREC__) || defined(__TURBOC__)) && defined(__TOS__)
+#    if !defined(__cdecl)
+#      define __cdecl cdecl
+#    endif
+#    if !defined(__pascal)
+#      define __pascal pascal
+#    endif
+#  endif
+#  undef __LZO_RENAME_A
+#  undef __LZO_RENAME_B
+#endif
+#if (UINT_MAX == LZO_0xffffL)
+#if defined(__AZTEC_C__) && defined(__DOS__)
+#  define LZO_BROKEN_CDECL_ALT_SYNTAX 1
+#elif defined(_MSC_VER) && defined(MSDOS)
+#  if (_MSC_VER < 600)
+#    define LZO_BROKEN_INTEGRAL_CONSTANTS 1
+#  endif
+#  if (_MSC_VER < 700)
+#    define LZO_BROKEN_INTEGRAL_PROMOTION 1
+#    define LZO_BROKEN_SIZEOF 1
+#  endif
+#elif defined(__PACIFIC__) && defined(DOS)
+#  define LZO_BROKEN_INTEGRAL_CONSTANTS 1
+#elif defined(__TURBOC__) && defined(__MSDOS__)
+#  if (__TURBOC__ < 0x0150)
+#    define LZO_BROKEN_CDECL_ALT_SYNTAX 1
+#    define LZO_BROKEN_INTEGRAL_CONSTANTS 1
+#    define LZO_BROKEN_INTEGRAL_PROMOTION 1
+#  endif
+#  if (__TURBOC__ < 0x0200)
+#    define LZO_BROKEN_SIZEOF 1
+#  endif
+#  if (__TURBOC__ < 0x0400) && defined(__cplusplus)
+#    define LZO_BROKEN_CDECL_ALT_SYNTAX 1
+#  endif
+#elif (defined(__PUREC__) || defined(__TURBOC__)) && defined(__TOS__)
+#  define LZO_BROKEN_CDECL_ALT_SYNTAX 1
+#  define LZO_BROKEN_SIZEOF 1
+#endif
+#endif
+#if defined(__WATCOMC__) && (__WATCOMC__ < 900)
+#  define LZO_BROKEN_INTEGRAL_CONSTANTS 1
+#endif
+#if defined(_CRAY) && defined(_CRAY1)
+#  define LZO_BROKEN_SIGNED_RIGHT_SHIFT 1
+#endif
+#define LZO_PP_STRINGIZE(x)             #x
+#define LZO_PP_MACRO_EXPAND(x)          LZO_PP_STRINGIZE(x)
+#define LZO_PP_CONCAT2(a,b)             a ## b
+#define LZO_PP_CONCAT3(a,b,c)           a ## b ## c
+#define LZO_PP_CONCAT4(a,b,c,d)         a ## b ## c ## d
+#define LZO_PP_CONCAT5(a,b,c,d,e)       a ## b ## c ## d ## e
+#define LZO_PP_ECONCAT2(a,b)            LZO_PP_CONCAT2(a,b)
+#define LZO_PP_ECONCAT3(a,b,c)          LZO_PP_CONCAT3(a,b,c)
+#define LZO_PP_ECONCAT4(a,b,c,d)        LZO_PP_CONCAT4(a,b,c,d)
+#define LZO_PP_ECONCAT5(a,b,c,d,e)      LZO_PP_CONCAT5(a,b,c,d,e)
+#if 1
+#define LZO_CPP_STRINGIZE(x)            #x
+#define LZO_CPP_MACRO_EXPAND(x)         LZO_CPP_STRINGIZE(x)
+#define LZO_CPP_CONCAT2(a,b)            a ## b
+#define LZO_CPP_CONCAT3(a,b,c)          a ## b ## c
+#define LZO_CPP_CONCAT4(a,b,c,d)        a ## b ## c ## d
+#define LZO_CPP_CONCAT5(a,b,c,d,e)      a ## b ## c ## d ## e
+#define LZO_CPP_ECONCAT2(a,b)           LZO_CPP_CONCAT2(a,b)
+#define LZO_CPP_ECONCAT3(a,b,c)         LZO_CPP_CONCAT3(a,b,c)
+#define LZO_CPP_ECONCAT4(a,b,c,d)       LZO_CPP_CONCAT4(a,b,c,d)
+#define LZO_CPP_ECONCAT5(a,b,c,d,e)     LZO_CPP_CONCAT5(a,b,c,d,e)
+#endif
+#define __LZO_MASK_GEN(o,b)     (((((o) << ((b)-1)) - (o)) << 1) + (o))
+#if 1 && defined(__cplusplus)
+#  if !defined(__STDC_CONSTANT_MACROS)
+#    define __STDC_CONSTANT_MACROS 1
+#  endif
+#  if !defined(__STDC_LIMIT_MACROS)
+#    define __STDC_LIMIT_MACROS 1
+#  endif
+#endif
+#if defined(__cplusplus)
+#  define LZO_EXTERN_C extern "C"
+#else
+#  define LZO_EXTERN_C extern
+#endif
+#if !defined(__LZO_OS_OVERRIDE)
+#if (LZO_OS_FREESTANDING)
+#  define LZO_INFO_OS           "freestanding"
+#elif (LZO_OS_EMBEDDED)
+#  define LZO_INFO_OS           "embedded"
+#elif 1 && defined(__IAR_SYSTEMS_ICC__)
+#  define LZO_OS_EMBEDDED       1
+#  define LZO_INFO_OS           "embedded"
+#elif defined(__CYGWIN__) && defined(__GNUC__)
+#  define LZO_OS_CYGWIN         1
+#  define LZO_INFO_OS           "cygwin"
+#elif defined(__EMX__) && defined(__GNUC__)
+#  define LZO_OS_EMX            1
+#  define LZO_INFO_OS           "emx"
+#elif defined(__BEOS__)
+#  define LZO_OS_BEOS           1
+#  define LZO_INFO_OS           "beos"
+#elif defined(__Lynx__)
+#  define LZO_OS_LYNXOS         1
+#  define LZO_INFO_OS           "lynxos"
+#elif defined(__OS400__)
+#  define LZO_OS_OS400          1
+#  define LZO_INFO_OS           "os400"
+#elif defined(__QNX__)
+#  define LZO_OS_QNX            1
+#  define LZO_INFO_OS           "qnx"
+#elif defined(__BORLANDC__) && defined(__DPMI32__) && (__BORLANDC__ >= 0x0460)
+#  define LZO_OS_DOS32          1
+#  define LZO_INFO_OS           "dos32"
+#elif defined(__BORLANDC__) && defined(__DPMI16__)
+#  define LZO_OS_DOS16          1
+#  define LZO_INFO_OS           "dos16"
+#elif defined(__ZTC__) && defined(DOS386)
+#  define LZO_OS_DOS32          1
+#  define LZO_INFO_OS           "dos32"
+#elif defined(__OS2__) || defined(__OS2V2__)
+#  if (UINT_MAX == LZO_0xffffL)
+#    define LZO_OS_OS216        1
+#    define LZO_INFO_OS         "os216"
+#  elif (UINT_MAX == LZO_0xffffffffL)
+#    define LZO_OS_OS2          1
+#    define LZO_INFO_OS         "os2"
+#  else
+#    error "check your limits.h header"
+#  endif
+#elif defined(__WIN64__) || defined(_WIN64) || defined(WIN64)
+#  define LZO_OS_WIN64          1
+#  define LZO_INFO_OS           "win64"
+#elif defined(__WIN32__) || defined(_WIN32) || defined(WIN32) || defined(__WINDOWS_386__)
+#  define LZO_OS_WIN32          1
+#  define LZO_INFO_OS           "win32"
+#elif defined(__MWERKS__) && defined(__INTEL__)
+#  define LZO_OS_WIN32          1
+#  define LZO_INFO_OS           "win32"
+#elif defined(__WINDOWS__) || defined(_WINDOWS) || defined(_Windows)
+#  if (UINT_MAX == LZO_0xffffL)
+#    define LZO_OS_WIN16        1
+#    define LZO_INFO_OS         "win16"
+#  elif (UINT_MAX == LZO_0xffffffffL)
+#    define LZO_OS_WIN32        1
+#    define LZO_INFO_OS         "win32"
+#  else
+#    error "check your limits.h header"
+#  endif
+#elif defined(__DOS__) || defined(__MSDOS__) || defined(_MSDOS) || defined(MSDOS) || (defined(__PACIFIC__) && defined(DOS))
+#  if (UINT_MAX == LZO_0xffffL)
+#    define LZO_OS_DOS16        1
+#    define LZO_INFO_OS         "dos16"
+#  elif (UINT_MAX == LZO_0xffffffffL)
+#    define LZO_OS_DOS32        1
+#    define LZO_INFO_OS         "dos32"
+#  else
+#    error "check your limits.h header"
+#  endif
+#elif defined(__WATCOMC__)
+#  if defined(__NT__) && (UINT_MAX == LZO_0xffffL)
+#    define LZO_OS_DOS16        1
+#    define LZO_INFO_OS         "dos16"
+#  elif defined(__NT__) && (__WATCOMC__ < 1100)
+#    define LZO_OS_WIN32        1
+#    define LZO_INFO_OS         "win32"
+#  elif defined(__linux__) || defined(__LINUX__)
+#    define LZO_OS_POSIX        1
+#    define LZO_INFO_OS         "posix"
+#  else
+#    error "please specify a target using the -bt compiler option"
+#  endif
+#elif defined(__palmos__)
+#  define LZO_OS_PALMOS         1
+#  define LZO_INFO_OS           "palmos"
+#elif defined(__TOS__) || defined(__atarist__)
+#  define LZO_OS_TOS            1
+#  define LZO_INFO_OS           "tos"
+#elif defined(macintosh) && !defined(__ppc__)
+#  define LZO_OS_MACCLASSIC     1
+#  define LZO_INFO_OS           "macclassic"
+#elif defined(__VMS)
+#  define LZO_OS_VMS            1
+#  define LZO_INFO_OS           "vms"
+#elif ((defined(__mips__) && defined(__R5900__)) || defined(__MIPS_PSX2__))
+#  define LZO_OS_CONSOLE        1
+#  define LZO_OS_CONSOLE_PS2    1
+#  define LZO_INFO_OS           "console"
+#  define LZO_INFO_OS_CONSOLE   "ps2"
+#elif (defined(__mips__) && defined(__psp__))
+#  define LZO_OS_CONSOLE        1
+#  define LZO_OS_CONSOLE_PSP    1
+#  define LZO_INFO_OS           "console"
+#  define LZO_INFO_OS_CONSOLE   "psp"
+#else
+#  define LZO_OS_POSIX          1
+#  define LZO_INFO_OS           "posix"
+#endif
+#if (LZO_OS_POSIX)
+#  if defined(_AIX) || defined(__AIX__) || defined(__aix__)
+#    define LZO_OS_POSIX_AIX        1
+#    define LZO_INFO_OS_POSIX       "aix"
+#  elif defined(__FreeBSD__)
+#    define LZO_OS_POSIX_FREEBSD    1
+#    define LZO_INFO_OS_POSIX       "freebsd"
+#  elif defined(__hpux__) || defined(__hpux)
+#    define LZO_OS_POSIX_HPUX       1
+#    define LZO_INFO_OS_POSIX       "hpux"
+#  elif defined(__INTERIX)
+#    define LZO_OS_POSIX_INTERIX    1
+#    define LZO_INFO_OS_POSIX       "interix"
+#  elif defined(__IRIX__) || defined(__irix__)
+#    define LZO_OS_POSIX_IRIX       1
+#    define LZO_INFO_OS_POSIX       "irix"
+#  elif defined(__linux__) || defined(__linux) || defined(__LINUX__)
+#    define LZO_OS_POSIX_LINUX      1
+#    define LZO_INFO_OS_POSIX       "linux"
+#  elif defined(__APPLE__) || defined(__MACOS__)
+#    define LZO_OS_POSIX_MACOSX     1
+#    define LZO_INFO_OS_POSIX       "macosx"
+#  elif defined(__minix__) || defined(__minix)
+#    define LZO_OS_POSIX_MINIX      1
+#    define LZO_INFO_OS_POSIX       "minix"
+#  elif defined(__NetBSD__)
+#    define LZO_OS_POSIX_NETBSD     1
+#    define LZO_INFO_OS_POSIX       "netbsd"
+#  elif defined(__OpenBSD__)
+#    define LZO_OS_POSIX_OPENBSD    1
+#    define LZO_INFO_OS_POSIX       "openbsd"
+#  elif defined(__osf__)
+#    define LZO_OS_POSIX_OSF        1
+#    define LZO_INFO_OS_POSIX       "osf"
+#  elif defined(__solaris__) || defined(__sun)
+#    if defined(__SVR4) || defined(__svr4__)
+#      define LZO_OS_POSIX_SOLARIS  1
+#      define LZO_INFO_OS_POSIX     "solaris"
+#    else
+#      define LZO_OS_POSIX_SUNOS    1
+#      define LZO_INFO_OS_POSIX     "sunos"
+#    endif
+#  elif defined(__ultrix__) || defined(__ultrix)
+#    define LZO_OS_POSIX_ULTRIX     1
+#    define LZO_INFO_OS_POSIX       "ultrix"
+#  elif defined(_UNICOS)
+#    define LZO_OS_POSIX_UNICOS     1
+#    define LZO_INFO_OS_POSIX       "unicos"
+#  else
+#    define LZO_OS_POSIX_UNKNOWN    1
+#    define LZO_INFO_OS_POSIX       "unknown"
+#  endif
+#endif
+#endif
+#if (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16)
+#  if (UINT_MAX != LZO_0xffffL)
+#    error "this should not happen"
+#  endif
+#  if (ULONG_MAX != LZO_0xffffffffL)
+#    error "this should not happen"
+#  endif
+#endif
+#if (LZO_OS_DOS32 || LZO_OS_OS2 || LZO_OS_WIN32 || LZO_OS_WIN64)
+#  if (UINT_MAX != LZO_0xffffffffL)
+#    error "this should not happen"
+#  endif
+#  if (ULONG_MAX != LZO_0xffffffffL)
+#    error "this should not happen"
+#  endif
+#endif
+#if defined(CIL) && defined(_GNUCC) && defined(__GNUC__)
+#  define LZO_CC_CILLY          1
+#  define LZO_INFO_CC           "Cilly"
+#  if defined(__CILLY__)
+#    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(__CILLY__)
+#  else
+#    define LZO_INFO_CCVER      "unknown"
+#  endif
+#elif 0 && defined(SDCC) && defined(__VERSION__) && !defined(__GNUC__)
+#  define LZO_CC_SDCC           1
+#  define LZO_INFO_CC           "sdcc"
+#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(SDCC)
+#elif defined(__PATHSCALE__) && defined(__PATHCC_PATCHLEVEL__)
+#  define LZO_CC_PATHSCALE      (__PATHCC__ * 0x10000L + __PATHCC_MINOR__ * 0x100 + __PATHCC_PATCHLEVEL__)
+#  define LZO_INFO_CC           "Pathscale C"
+#  define LZO_INFO_CCVER        __PATHSCALE__
+#elif defined(__INTEL_COMPILER)
+#  define LZO_CC_INTELC         1
+#  define LZO_INFO_CC           "Intel C"
+#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__INTEL_COMPILER)
+#  if defined(_WIN32) || defined(_WIN64)
+#    define LZO_CC_SYNTAX_MSC 1
+#  else
+#    define LZO_CC_SYNTAX_GNUC 1
+#  endif
+#elif defined(__POCC__) && defined(_WIN32)
+#  define LZO_CC_PELLESC        1
+#  define LZO_INFO_CC           "Pelles C"
+#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__POCC__)
+#elif defined(__clang__) && defined(__llvm__) && defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__)
+#  if defined(__GNUC_PATCHLEVEL__)
+#    define LZO_CC_CLANG_GNUC   (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__)
+#  else
+#    define LZO_CC_CLANG_GNUC   (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100)
+#  endif
+#  if defined(__clang_major__) && defined(__clang_minor__) && defined(__clang_patchlevel__)
+#    define LZO_CC_CLANG_CLANG  (__clang_major__ * 0x10000L + __clang_minor__ * 0x100 + __clang_patchlevel__)
+#  else
+#    define LZO_CC_CLANG_CLANG  0x010000L
+#  endif
+#  define LZO_CC_CLANG          LZO_CC_CLANG_GNUC
+#  define LZO_INFO_CC           "clang"
+#  define LZO_INFO_CCVER        __VERSION__
+#elif defined(__llvm__) && defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__)
+#  if defined(__GNUC_PATCHLEVEL__)
+#    define LZO_CC_LLVM_GNUC    (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__)
+#  else
+#    define LZO_CC_LLVM_GNUC    (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100)
+#  endif
+#  define LZO_CC_LLVM           LZO_CC_LLVM_GNUC
+#  define LZO_INFO_CC           "llvm-gcc"
+#  define LZO_INFO_CCVER        __VERSION__
+#elif defined(__GNUC__) && defined(__VERSION__)
+#  if defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)
+#    define LZO_CC_GNUC         (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__)
+#  elif defined(__GNUC_MINOR__)
+#    define LZO_CC_GNUC         (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100)
+#  else
+#    define LZO_CC_GNUC         (__GNUC__ * 0x10000L)
+#  endif
+#  define LZO_INFO_CC           "gcc"
+#  define LZO_INFO_CCVER        __VERSION__
+#elif defined(__ACK__) && defined(_ACK)
+#  define LZO_CC_ACK            1
+#  define LZO_INFO_CC           "Amsterdam Compiler Kit C"
+#  define LZO_INFO_CCVER        "unknown"
+#elif defined(__AZTEC_C__)
+#  define LZO_CC_AZTECC         1
+#  define LZO_INFO_CC           "Aztec C"
+#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__AZTEC_C__)
+#elif defined(__CODEGEARC__)
+#  define LZO_CC_CODEGEARC      1
+#  define LZO_INFO_CC           "CodeGear C"
+#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__CODEGEARC__)
+#elif defined(__BORLANDC__)
+#  define LZO_CC_BORLANDC       1
+#  define LZO_INFO_CC           "Borland C"
+#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__BORLANDC__)
+#elif defined(_CRAYC) && defined(_RELEASE)
+#  define LZO_CC_CRAYC          1
+#  define LZO_INFO_CC           "Cray C"
+#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(_RELEASE)
+#elif defined(__DMC__) && defined(__SC__)
+#  define LZO_CC_DMC            1
+#  define LZO_INFO_CC           "Digital Mars C"
+#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__DMC__)
+#elif defined(__DECC)
+#  define LZO_CC_DECC           1
+#  define LZO_INFO_CC           "DEC C"
+#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__DECC)
+#elif defined(__HIGHC__)
+#  define LZO_CC_HIGHC          1
+#  define LZO_INFO_CC           "MetaWare High C"
+#  define LZO_INFO_CCVER        "unknown"
+#elif defined(__IAR_SYSTEMS_ICC__)
+#  define LZO_CC_IARC           1
+#  define LZO_INFO_CC           "IAR C"
+#  if defined(__VER__)
+#    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(__VER__)
+#  else
+#    define LZO_INFO_CCVER      "unknown"
+#  endif
+#elif defined(__IBMC__)
+#  define LZO_CC_IBMC           1
+#  define LZO_INFO_CC           "IBM C"
+#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__IBMC__)
+#elif defined(__KEIL__) && defined(__C166__)
+#  define LZO_CC_KEILC          1
+#  define LZO_INFO_CC           "Keil C"
+#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__C166__)
+#elif defined(__LCC__) && defined(_WIN32) && defined(__LCCOPTIMLEVEL)
+#  define LZO_CC_LCCWIN32       1
+#  define LZO_INFO_CC           "lcc-win32"
+#  define LZO_INFO_CCVER        "unknown"
+#elif defined(__LCC__)
+#  define LZO_CC_LCC            1
+#  define LZO_INFO_CC           "lcc"
+#  if defined(__LCC_VERSION__)
+#    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(__LCC_VERSION__)
+#  else
+#    define LZO_INFO_CCVER      "unknown"
+#  endif
+#elif defined(_MSC_VER)
+#  define LZO_CC_MSC            1
+#  define LZO_INFO_CC           "Microsoft C"
+#  if defined(_MSC_FULL_VER)
+#    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(_MSC_VER) "." LZO_PP_MACRO_EXPAND(_MSC_FULL_VER)
+#  else
+#    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(_MSC_VER)
+#  endif
+#elif defined(__MWERKS__)
+#  define LZO_CC_MWERKS         1
+#  define LZO_INFO_CC           "Metrowerks C"
+#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__MWERKS__)
+#elif (defined(__NDPC__) || defined(__NDPX__)) && defined(__i386)
+#  define LZO_CC_NDPC           1
+#  define LZO_INFO_CC           "Microway NDP C"
+#  define LZO_INFO_CCVER        "unknown"
+#elif defined(__PACIFIC__)
+#  define LZO_CC_PACIFICC       1
+#  define LZO_INFO_CC           "Pacific C"
+#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__PACIFIC__)
+#elif defined(__PGI) && (defined(__linux__) || defined(__WIN32__))
+#  define LZO_CC_PGI            1
+#  define LZO_INFO_CC           "Portland Group PGI C"
+#  define LZO_INFO_CCVER        "unknown"
+#elif defined(__PUREC__) && defined(__TOS__)
+#  define LZO_CC_PUREC          1
+#  define LZO_INFO_CC           "Pure C"
+#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__PUREC__)
+#elif defined(__SC__) && defined(__ZTC__)
+#  define LZO_CC_SYMANTECC      1
+#  define LZO_INFO_CC           "Symantec C"
+#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__SC__)
+#elif defined(__SUNPRO_C)
+#  define LZO_INFO_CC           "SunPro C"
+#  if ((__SUNPRO_C)+0 > 0)
+#    define LZO_CC_SUNPROC      __SUNPRO_C
+#    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(__SUNPRO_C)
+#  else
+#    define LZO_CC_SUNPROC      1
+#    define LZO_INFO_CCVER      "unknown"
+#  endif
+#elif defined(__SUNPRO_CC)
+#  define LZO_INFO_CC           "SunPro C"
+#  if ((__SUNPRO_CC)+0 > 0)
+#    define LZO_CC_SUNPROC      __SUNPRO_CC
+#    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(__SUNPRO_CC)
+#  else
+#    define LZO_CC_SUNPROC      1
+#    define LZO_INFO_CCVER      "unknown"
+#  endif
+#elif defined(__TINYC__)
+#  define LZO_CC_TINYC          1
+#  define LZO_INFO_CC           "Tiny C"
+#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__TINYC__)
+#elif defined(__TSC__)
+#  define LZO_CC_TOPSPEEDC      1
+#  define LZO_INFO_CC           "TopSpeed C"
+#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__TSC__)
+#elif defined(__WATCOMC__)
+#  define LZO_CC_WATCOMC        1
+#  define LZO_INFO_CC           "Watcom C"
+#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__WATCOMC__)
+#elif defined(__TURBOC__)
+#  define LZO_CC_TURBOC         1
+#  define LZO_INFO_CC           "Turbo C"
+#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__TURBOC__)
+#elif defined(__ZTC__)
+#  define LZO_CC_ZORTECHC       1
+#  define LZO_INFO_CC           "Zortech C"
+#  if (__ZTC__ == 0x310)
+#    define LZO_INFO_CCVER      "0x310"
+#  else
+#    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(__ZTC__)
+#  endif
+#else
+#  define LZO_CC_UNKNOWN        1
+#  define LZO_INFO_CC           "unknown"
+#  define LZO_INFO_CCVER        "unknown"
+#endif
+#if 0 && (LZO_CC_MSC && (_MSC_VER >= 1200)) && !defined(_MSC_FULL_VER)
+#  error "LZO_CC_MSC: _MSC_FULL_VER is not defined"
+#endif
+#if !defined(__LZO_ARCH_OVERRIDE) && !(LZO_ARCH_GENERIC) && defined(_CRAY)
+#  if (UINT_MAX > LZO_0xffffffffL) && defined(_CRAY)
+#    if defined(_CRAYMPP) || defined(_CRAYT3D) || defined(_CRAYT3E)
+#      define LZO_ARCH_CRAY_MPP     1
+#    elif defined(_CRAY1)
+#      define LZO_ARCH_CRAY_PVP     1
+#    endif
+#  endif
+#endif
+#if !defined(__LZO_ARCH_OVERRIDE)
+#if (LZO_ARCH_GENERIC)
+#  define LZO_INFO_ARCH             "generic"
+#elif (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16)
+#  define LZO_ARCH_I086             1
+#  define LZO_ARCH_IA16             1
+#  define LZO_INFO_ARCH             "i086"
+#elif defined(__alpha__) || defined(__alpha) || defined(_M_ALPHA)
+#  define LZO_ARCH_ALPHA            1
+#  define LZO_INFO_ARCH             "alpha"
+#elif (LZO_ARCH_CRAY_MPP) && (defined(_CRAYT3D) || defined(_CRAYT3E))
+#  define LZO_ARCH_ALPHA            1
+#  define LZO_INFO_ARCH             "alpha"
+#elif defined(__amd64__) || defined(__x86_64__) || defined(_M_AMD64)
+#  define LZO_ARCH_AMD64            1
+#  define LZO_INFO_ARCH             "amd64"
+#elif defined(__thumb__) || (defined(_M_ARM) && defined(_M_THUMB))
+#  define LZO_ARCH_ARM              1
+#  define LZO_ARCH_ARM_THUMB        1
+#  define LZO_INFO_ARCH             "arm_thumb"
+#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCARM__)
+#  define LZO_ARCH_ARM              1
+#  if defined(__CPU_MODE__) && ((__CPU_MODE__)+0 == 1)
+#    define LZO_ARCH_ARM_THUMB      1
+#    define LZO_INFO_ARCH           "arm_thumb"
+#  elif defined(__CPU_MODE__) && ((__CPU_MODE__)+0 == 2)
+#    define LZO_INFO_ARCH           "arm"
+#  else
+#    define LZO_INFO_ARCH           "arm"
+#  endif
+#elif defined(__arm__) || defined(_M_ARM)
+#  define LZO_ARCH_ARM              1
+#  define LZO_INFO_ARCH             "arm"
+#elif (UINT_MAX <= LZO_0xffffL) && defined(__AVR__)
+#  define LZO_ARCH_AVR              1
+#  define LZO_INFO_ARCH             "avr"
+#elif defined(__avr32__) || defined(__AVR32__)
+#  define LZO_ARCH_AVR32            1
+#  define LZO_INFO_ARCH             "avr32"
+#elif defined(__bfin__)
+#  define LZO_ARCH_BLACKFIN         1
+#  define LZO_INFO_ARCH             "blackfin"
+#elif (UINT_MAX == LZO_0xffffL) && defined(__C166__)
+#  define LZO_ARCH_C166             1
+#  define LZO_INFO_ARCH             "c166"
+#elif defined(__cris__)
+#  define LZO_ARCH_CRIS             1
+#  define LZO_INFO_ARCH             "cris"
+#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCEZ80__)
+#  define LZO_ARCH_EZ80             1
+#  define LZO_INFO_ARCH             "ez80"
+#elif defined(__H8300__) || defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__)
+#  define LZO_ARCH_H8300            1
+#  define LZO_INFO_ARCH             "h8300"
+#elif defined(__hppa__) || defined(__hppa)
+#  define LZO_ARCH_HPPA             1
+#  define LZO_INFO_ARCH             "hppa"
+#elif defined(__386__) || defined(__i386__) || defined(__i386) || defined(_M_IX86) || defined(_M_I386)
+#  define LZO_ARCH_I386             1
+#  define LZO_ARCH_IA32             1
+#  define LZO_INFO_ARCH             "i386"
+#elif (LZO_CC_ZORTECHC && defined(__I86__))
+#  define LZO_ARCH_I386             1
+#  define LZO_ARCH_IA32             1
+#  define LZO_INFO_ARCH             "i386"
+#elif (LZO_OS_DOS32 && LZO_CC_HIGHC) && defined(_I386)
+#  define LZO_ARCH_I386             1
+#  define LZO_ARCH_IA32             1
+#  define LZO_INFO_ARCH             "i386"
+#elif defined(__ia64__) || defined(__ia64) || defined(_M_IA64)
+#  define LZO_ARCH_IA64             1
+#  define LZO_INFO_ARCH             "ia64"
+#elif (UINT_MAX == LZO_0xffffL) && defined(__m32c__)
+#  define LZO_ARCH_M16C             1
+#  define LZO_INFO_ARCH             "m16c"
+#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCM16C__)
+#  define LZO_ARCH_M16C             1
+#  define LZO_INFO_ARCH             "m16c"
+#elif defined(__m32r__)
+#  define LZO_ARCH_M32R             1
+#  define LZO_INFO_ARCH             "m32r"
+#elif (LZO_OS_TOS) || defined(__m68k__) || defined(__m68000__) || defined(__mc68000__) || defined(__mc68020__) || defined(_M_M68K)
+#  define LZO_ARCH_M68K             1
+#  define LZO_INFO_ARCH             "m68k"
+#elif (UINT_MAX == LZO_0xffffL) && defined(__C251__)
+#  define LZO_ARCH_MCS251           1
+#  define LZO_INFO_ARCH             "mcs251"
+#elif (UINT_MAX == LZO_0xffffL) && defined(__C51__)
+#  define LZO_ARCH_MCS51            1
+#  define LZO_INFO_ARCH             "mcs51"
+#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICC8051__)
+#  define LZO_ARCH_MCS51            1
+#  define LZO_INFO_ARCH             "mcs51"
+#elif defined(__mips__) || defined(__mips) || defined(_MIPS_ARCH) || defined(_M_MRX000)
+#  define LZO_ARCH_MIPS             1
+#  define LZO_INFO_ARCH             "mips"
+#elif (UINT_MAX == LZO_0xffffL) && defined(__MSP430__)
+#  define LZO_ARCH_MSP430           1
+#  define LZO_INFO_ARCH             "msp430"
+#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICC430__)
+#  define LZO_ARCH_MSP430           1
+#  define LZO_INFO_ARCH             "msp430"
+#elif defined(__powerpc__) || defined(__powerpc) || defined(__ppc__) || defined(__PPC__) || defined(_M_PPC) || defined(_ARCH_PPC) || defined(_ARCH_PWR)
+#  define LZO_ARCH_POWERPC          1
+#  define LZO_INFO_ARCH             "powerpc"
+#elif defined(__s390__) || defined(__s390) || defined(__s390x__) || defined(__s390x)
+#  define LZO_ARCH_S390             1
+#  define LZO_INFO_ARCH             "s390"
+#elif defined(__sh__) || defined(_M_SH)
+#  define LZO_ARCH_SH               1
+#  define LZO_INFO_ARCH             "sh"
+#elif defined(__sparc__) || defined(__sparc) || defined(__sparcv8)
+#  define LZO_ARCH_SPARC            1
+#  define LZO_INFO_ARCH             "sparc"
+#elif defined(__SPU__)
+#  define LZO_ARCH_SPU              1
+#  define LZO_INFO_ARCH             "spu"
+#elif (UINT_MAX == LZO_0xffffL) && defined(__z80)
+#  define LZO_ARCH_Z80              1
+#  define LZO_INFO_ARCH             "z80"
+#elif (LZO_ARCH_CRAY_PVP)
+#  if defined(_CRAYSV1)
+#    define LZO_ARCH_CRAY_SV1       1
+#    define LZO_INFO_ARCH           "cray_sv1"
+#  elif (_ADDR64)
+#    define LZO_ARCH_CRAY_T90       1
+#    define LZO_INFO_ARCH           "cray_t90"
+#  elif (_ADDR32)
+#    define LZO_ARCH_CRAY_YMP       1
+#    define LZO_INFO_ARCH           "cray_ymp"
+#  else
+#    define LZO_ARCH_CRAY_XMP       1
+#    define LZO_INFO_ARCH           "cray_xmp"
+#  endif
+#else
+#  define LZO_ARCH_UNKNOWN          1
+#  define LZO_INFO_ARCH             "unknown"
+#endif
+#endif
+#if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_DOS32 || LZO_OS_OS2)
+#  error "FIXME - missing define for CPU architecture"
+#endif
+#if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_WIN32)
+#  error "FIXME - missing WIN32 define for CPU architecture"
+#endif
+#if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_WIN64)
+#  error "FIXME - missing WIN64 define for CPU architecture"
+#endif
+#if (LZO_OS_OS216 || LZO_OS_WIN16)
+#  define LZO_ARCH_I086PM           1
+#  define LZO_ARCH_IA16PM           1
+#elif 1 && (LZO_OS_DOS16 && defined(BLX286))
+#  define LZO_ARCH_I086PM           1
+#  define LZO_ARCH_IA16PM           1
+#elif 1 && (LZO_OS_DOS16 && defined(DOSX286))
+#  define LZO_ARCH_I086PM           1
+#  define LZO_ARCH_IA16PM           1
+#elif 1 && (LZO_OS_DOS16 && LZO_CC_BORLANDC && defined(__DPMI16__))
+#  define LZO_ARCH_I086PM           1
+#  define LZO_ARCH_IA16PM           1
+#endif
+#if (LZO_ARCH_ARM_THUMB) && !(LZO_ARCH_ARM)
+#  error "this should not happen"
+#endif
+#if (LZO_ARCH_I086PM) && !(LZO_ARCH_I086)
+#  error "this should not happen"
+#endif
+#if (LZO_ARCH_I086)
+#  if (UINT_MAX != LZO_0xffffL)
+#    error "this should not happen"
+#  endif
+#  if (ULONG_MAX != LZO_0xffffffffL)
+#    error "this should not happen"
+#  endif
+#endif
+#if (LZO_ARCH_I386)
+#  if (UINT_MAX != LZO_0xffffL) && defined(__i386_int16__)
+#    error "this should not happen"
+#  endif
+#  if (UINT_MAX != LZO_0xffffffffL) && !defined(__i386_int16__)
+#    error "this should not happen"
+#  endif
+#  if (ULONG_MAX != LZO_0xffffffffL)
+#    error "this should not happen"
+#  endif
+#endif
+#if !defined(__LZO_MM_OVERRIDE)
+#if (LZO_ARCH_I086)
+#if (UINT_MAX != LZO_0xffffL)
+#  error "this should not happen"
+#endif
+#if defined(__TINY__) || defined(M_I86TM) || defined(_M_I86TM)
+#  define LZO_MM_TINY           1
+#elif defined(__HUGE__) || defined(_HUGE_) || defined(M_I86HM) || defined(_M_I86HM)
+#  define LZO_MM_HUGE           1
+#elif defined(__SMALL__) || defined(M_I86SM) || defined(_M_I86SM) || defined(SMALL_MODEL)
+#  define LZO_MM_SMALL          1
+#elif defined(__MEDIUM__) || defined(M_I86MM) || defined(_M_I86MM)
+#  define LZO_MM_MEDIUM         1
+#elif defined(__COMPACT__) || defined(M_I86CM) || defined(_M_I86CM)
+#  define LZO_MM_COMPACT        1
+#elif defined(__LARGE__) || defined(M_I86LM) || defined(_M_I86LM) || defined(LARGE_MODEL)
+#  define LZO_MM_LARGE          1
+#elif (LZO_CC_AZTECC)
+#  if defined(_LARGE_CODE) && defined(_LARGE_DATA)
+#    define LZO_MM_LARGE        1
+#  elif defined(_LARGE_CODE)
+#    define LZO_MM_MEDIUM       1
+#  elif defined(_LARGE_DATA)
+#    define LZO_MM_COMPACT      1
+#  else
+#    define LZO_MM_SMALL        1
+#  endif
+#elif (LZO_CC_ZORTECHC && defined(__VCM__))
+#  define LZO_MM_LARGE          1
+#else
+#  error "unknown memory model"
+#endif
+#if (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16)
+#define LZO_HAVE_MM_HUGE_PTR        1
+#define LZO_HAVE_MM_HUGE_ARRAY      1
+#if (LZO_MM_TINY)
+#  undef LZO_HAVE_MM_HUGE_ARRAY
+#endif
+#if (LZO_CC_AZTECC || LZO_CC_PACIFICC || LZO_CC_ZORTECHC)
+#  undef LZO_HAVE_MM_HUGE_PTR
+#  undef LZO_HAVE_MM_HUGE_ARRAY
+#elif (LZO_CC_DMC || LZO_CC_SYMANTECC)
+#  undef LZO_HAVE_MM_HUGE_ARRAY
+#elif (LZO_CC_MSC && defined(_QC))
+#  undef LZO_HAVE_MM_HUGE_ARRAY
+#  if (_MSC_VER < 600)
+#    undef LZO_HAVE_MM_HUGE_PTR
+#  endif
+#elif (LZO_CC_TURBOC && (__TURBOC__ < 0x0295))
+#  undef LZO_HAVE_MM_HUGE_ARRAY
+#endif
+#if (LZO_ARCH_I086PM) && !(LZO_HAVE_MM_HUGE_PTR)
+#  if (LZO_OS_DOS16)
+#    error "this should not happen"
+#  elif (LZO_CC_ZORTECHC)
+#  else
+#    error "this should not happen"
+#  endif
+#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+#if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0200))
+   extern void __near __cdecl _AHSHIFT(void);
+#  define LZO_MM_AHSHIFT      ((unsigned) _AHSHIFT)
+#elif (LZO_CC_DMC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC)
+   extern void __near __cdecl _AHSHIFT(void);
+#  define LZO_MM_AHSHIFT      ((unsigned) _AHSHIFT)
+#elif (LZO_CC_MSC || LZO_CC_TOPSPEEDC)
+   extern void __near __cdecl _AHSHIFT(void);
+#  define LZO_MM_AHSHIFT      ((unsigned) _AHSHIFT)
+#elif (LZO_CC_TURBOC && (__TURBOC__ >= 0x0295))
+   extern void __near __cdecl _AHSHIFT(void);
+#  define LZO_MM_AHSHIFT      ((unsigned) _AHSHIFT)
+#elif ((LZO_CC_AZTECC || LZO_CC_PACIFICC || LZO_CC_TURBOC) && LZO_OS_DOS16)
+#  define LZO_MM_AHSHIFT      12
+#elif (LZO_CC_WATCOMC)
+   extern unsigned char _HShift;
+#  define LZO_MM_AHSHIFT      ((unsigned) _HShift)
+#else
+#  error "FIXME - implement LZO_MM_AHSHIFT"
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+#elif (LZO_ARCH_C166)
+#if !defined(__MODEL__)
+#  error "FIXME - C166 __MODEL__"
+#elif ((__MODEL__) == 0)
+#  define LZO_MM_SMALL          1
+#elif ((__MODEL__) == 1)
+#  define LZO_MM_SMALL          1
+#elif ((__MODEL__) == 2)
+#  define LZO_MM_LARGE          1
+#elif ((__MODEL__) == 3)
+#  define LZO_MM_TINY           1
+#elif ((__MODEL__) == 4)
+#  define LZO_MM_XTINY          1
+#elif ((__MODEL__) == 5)
+#  define LZO_MM_XSMALL         1
+#else
+#  error "FIXME - C166 __MODEL__"
+#endif
+#elif (LZO_ARCH_MCS251)
+#if !defined(__MODEL__)
+#  error "FIXME - MCS251 __MODEL__"
+#elif ((__MODEL__) == 0)
+#  define LZO_MM_SMALL          1
+#elif ((__MODEL__) == 2)
+#  define LZO_MM_LARGE          1
+#elif ((__MODEL__) == 3)
+#  define LZO_MM_TINY           1
+#elif ((__MODEL__) == 4)
+#  define LZO_MM_XTINY          1
+#elif ((__MODEL__) == 5)
+#  define LZO_MM_XSMALL         1
+#else
+#  error "FIXME - MCS251 __MODEL__"
+#endif
+#elif (LZO_ARCH_MCS51)
+#if !defined(__MODEL__)
+#  error "FIXME - MCS51 __MODEL__"
+#elif ((__MODEL__) == 1)
+#  define LZO_MM_SMALL          1
+#elif ((__MODEL__) == 2)
+#  define LZO_MM_LARGE          1
+#elif ((__MODEL__) == 3)
+#  define LZO_MM_TINY           1
+#elif ((__MODEL__) == 4)
+#  define LZO_MM_XTINY          1
+#elif ((__MODEL__) == 5)
+#  define LZO_MM_XSMALL         1
+#else
+#  error "FIXME - MCS51 __MODEL__"
+#endif
+#elif (LZO_ARCH_CRAY_PVP)
+#  define LZO_MM_PVP            1
+#else
+#  define LZO_MM_FLAT           1
+#endif
+#if (LZO_MM_COMPACT)
+#  define LZO_INFO_MM           "compact"
+#elif (LZO_MM_FLAT)
+#  define LZO_INFO_MM           "flat"
+#elif (LZO_MM_HUGE)
+#  define LZO_INFO_MM           "huge"
+#elif (LZO_MM_LARGE)
+#  define LZO_INFO_MM           "large"
+#elif (LZO_MM_MEDIUM)
+#  define LZO_INFO_MM           "medium"
+#elif (LZO_MM_PVP)
+#  define LZO_INFO_MM           "pvp"
+#elif (LZO_MM_SMALL)
+#  define LZO_INFO_MM           "small"
+#elif (LZO_MM_TINY)
+#  define LZO_INFO_MM           "tiny"
+#else
+#  error "unknown memory model"
+#endif
+#endif
+#if defined(SIZEOF_SHORT)
+#  define LZO_SIZEOF_SHORT          (SIZEOF_SHORT)
+#endif
+#if defined(SIZEOF_INT)
+#  define LZO_SIZEOF_INT            (SIZEOF_INT)
+#endif
+#if defined(SIZEOF_LONG)
+#  define LZO_SIZEOF_LONG           (SIZEOF_LONG)
+#endif
+#if defined(SIZEOF_LONG_LONG)
+#  define LZO_SIZEOF_LONG_LONG      (SIZEOF_LONG_LONG)
+#endif
+#if defined(SIZEOF___INT16)
+#  define LZO_SIZEOF___INT16        (SIZEOF___INT16)
+#endif
+#if defined(SIZEOF___INT32)
+#  define LZO_SIZEOF___INT32        (SIZEOF___INT32)
+#endif
+#if defined(SIZEOF___INT64)
+#  define LZO_SIZEOF___INT64        (SIZEOF___INT64)
+#endif
+#if defined(SIZEOF_VOID_P)
+#  define LZO_SIZEOF_VOID_P         (SIZEOF_VOID_P)
+#endif
+#if defined(SIZEOF_SIZE_T)
+#  define LZO_SIZEOF_SIZE_T         (SIZEOF_SIZE_T)
+#endif
+#if defined(SIZEOF_PTRDIFF_T)
+#  define LZO_SIZEOF_PTRDIFF_T      (SIZEOF_PTRDIFF_T)
+#endif
+#define __LZO_LSR(x,b)    (((x)+0ul) >> (b))
+#if !defined(LZO_SIZEOF_SHORT)
+#  if (LZO_ARCH_CRAY_PVP)
+#    define LZO_SIZEOF_SHORT        8
+#  elif (USHRT_MAX == LZO_0xffffL)
+#    define LZO_SIZEOF_SHORT        2
+#  elif (__LZO_LSR(USHRT_MAX,7) == 1)
+#    define LZO_SIZEOF_SHORT        1
+#  elif (__LZO_LSR(USHRT_MAX,15) == 1)
+#    define LZO_SIZEOF_SHORT        2
+#  elif (__LZO_LSR(USHRT_MAX,31) == 1)
+#    define LZO_SIZEOF_SHORT        4
+#  elif (__LZO_LSR(USHRT_MAX,63) == 1)
+#    define LZO_SIZEOF_SHORT        8
+#  elif (__LZO_LSR(USHRT_MAX,127) == 1)
+#    define LZO_SIZEOF_SHORT        16
+#  else
+#    error "LZO_SIZEOF_SHORT"
+#  endif
+#endif
+#if !defined(LZO_SIZEOF_INT)
+#  if (LZO_ARCH_CRAY_PVP)
+#    define LZO_SIZEOF_INT          8
+#  elif (UINT_MAX == LZO_0xffffL)
+#    define LZO_SIZEOF_INT          2
+#  elif (UINT_MAX == LZO_0xffffffffL)
+#    define LZO_SIZEOF_INT          4
+#  elif (__LZO_LSR(UINT_MAX,7) == 1)
+#    define LZO_SIZEOF_INT          1
+#  elif (__LZO_LSR(UINT_MAX,15) == 1)
+#    define LZO_SIZEOF_INT          2
+#  elif (__LZO_LSR(UINT_MAX,31) == 1)
+#    define LZO_SIZEOF_INT          4
+#  elif (__LZO_LSR(UINT_MAX,63) == 1)
+#    define LZO_SIZEOF_INT          8
+#  elif (__LZO_LSR(UINT_MAX,127) == 1)
+#    define LZO_SIZEOF_INT          16
+#  else
+#    error "LZO_SIZEOF_INT"
+#  endif
+#endif
+#if !defined(LZO_SIZEOF_LONG)
+#  if (ULONG_MAX == LZO_0xffffffffL)
+#    define LZO_SIZEOF_LONG         4
+#  elif (__LZO_LSR(ULONG_MAX,7) == 1)
+#    define LZO_SIZEOF_LONG         1
+#  elif (__LZO_LSR(ULONG_MAX,15) == 1)
+#    define LZO_SIZEOF_LONG         2
+#  elif (__LZO_LSR(ULONG_MAX,31) == 1)
+#    define LZO_SIZEOF_LONG         4
+#  elif (__LZO_LSR(ULONG_MAX,63) == 1)
+#    define LZO_SIZEOF_LONG         8
+#  elif (__LZO_LSR(ULONG_MAX,127) == 1)
+#    define LZO_SIZEOF_LONG         16
+#  else
+#    error "LZO_SIZEOF_LONG"
+#  endif
+#endif
+#if !defined(LZO_SIZEOF_LONG_LONG) && !defined(LZO_SIZEOF___INT64)
+#if (LZO_SIZEOF_LONG > 0 && LZO_SIZEOF_LONG < 8)
+#  if defined(__LONG_MAX__) && defined(__LONG_LONG_MAX__)
+#    if (LZO_CC_GNUC >= 0x030300ul)
+#      if ((__LONG_MAX__)+0 == (__LONG_LONG_MAX__)+0)
+#        define LZO_SIZEOF_LONG_LONG      LZO_SIZEOF_LONG
+#      elif (__LZO_LSR(__LONG_LONG_MAX__,30) == 1)
+#        define LZO_SIZEOF_LONG_LONG      4
+#      endif
+#    endif
+#  endif
+#endif
+#endif
+#if !defined(LZO_SIZEOF_LONG_LONG) && !defined(LZO_SIZEOF___INT64)
+#if (LZO_SIZEOF_LONG > 0 && LZO_SIZEOF_LONG < 8)
+#if (LZO_ARCH_I086 && LZO_CC_DMC)
+#elif (LZO_CC_CILLY) && defined(__GNUC__)
+#  define LZO_SIZEOF_LONG_LONG      8
+#elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#  define LZO_SIZEOF_LONG_LONG      8
+#elif ((LZO_OS_WIN32 || LZO_OS_WIN64 || defined(_WIN32)) && LZO_CC_MSC && (_MSC_VER >= 1400))
+#  define LZO_SIZEOF_LONG_LONG      8
+#elif (LZO_OS_WIN64 || defined(_WIN64))
+#  define LZO_SIZEOF___INT64        8
+#elif (LZO_ARCH_I386 && (LZO_CC_DMC))
+#  define LZO_SIZEOF_LONG_LONG      8
+#elif (LZO_ARCH_I386 && (LZO_CC_SYMANTECC && (__SC__ >= 0x700)))
+#  define LZO_SIZEOF_LONG_LONG      8
+#elif (LZO_ARCH_I386 && (LZO_CC_INTELC && defined(__linux__)))
+#  define LZO_SIZEOF_LONG_LONG      8
+#elif (LZO_ARCH_I386 && (LZO_CC_MWERKS || LZO_CC_PELLESC || LZO_CC_PGI || LZO_CC_SUNPROC))
+#  define LZO_SIZEOF_LONG_LONG      8
+#elif (LZO_ARCH_I386 && (LZO_CC_INTELC || LZO_CC_MSC))
+#  define LZO_SIZEOF___INT64        8
+#elif ((LZO_OS_WIN32 || defined(_WIN32)) && (LZO_CC_MSC))
+#  define LZO_SIZEOF___INT64        8
+#elif (LZO_ARCH_I386 && (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0520)))
+#  define LZO_SIZEOF___INT64        8
+#elif (LZO_ARCH_I386 && (LZO_CC_WATCOMC && (__WATCOMC__ >= 1100)))
+#  define LZO_SIZEOF___INT64        8
+#elif (LZO_CC_WATCOMC && defined(_INTEGRAL_MAX_BITS) && (_INTEGRAL_MAX_BITS == 64))
+#  define LZO_SIZEOF___INT64        8
+#elif (LZO_OS_OS400 || defined(__OS400__)) && defined(__LLP64_IFC__)
+#  define LZO_SIZEOF_LONG_LONG      8
+#elif (defined(__vms) || defined(__VMS)) && (__INITIAL_POINTER_SIZE+0 == 64)
+#  define LZO_SIZEOF_LONG_LONG      8
+#elif (LZO_CC_SDCC) && (LZO_SIZEOF_INT == 2)
+#elif 1 && defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
+#  define LZO_SIZEOF_LONG_LONG      8
+#endif
+#endif
+#endif
+#if defined(__cplusplus) && (LZO_CC_GNUC)
+#  if (LZO_CC_GNUC < 0x020800ul)
+#    undef LZO_SIZEOF_LONG_LONG
+#  endif
+#endif
+#if (LZO_CFG_NO_LONG_LONG) || defined(__NO_LONG_LONG)
+#  undef LZO_SIZEOF_LONG_LONG
+#endif
+#if !defined(LZO_SIZEOF_VOID_P)
+#if (LZO_ARCH_I086)
+#  define __LZO_WORDSIZE            2
+#  if (LZO_MM_TINY || LZO_MM_SMALL || LZO_MM_MEDIUM)
+#    define LZO_SIZEOF_VOID_P       2
+#  elif (LZO_MM_COMPACT || LZO_MM_LARGE || LZO_MM_HUGE)
+#    define LZO_SIZEOF_VOID_P       4
+#  else
+#    error "LZO_MM"
+#  endif
+#elif (LZO_ARCH_AVR || LZO_ARCH_Z80)
+#  define __LZO_WORDSIZE            1
+#  define LZO_SIZEOF_VOID_P         2
+#elif (LZO_ARCH_C166 || LZO_ARCH_MCS51 || LZO_ARCH_MCS251 || LZO_ARCH_MSP430)
+#  define LZO_SIZEOF_VOID_P         2
+#elif (LZO_ARCH_H8300)
+#  if defined(__NORMAL_MODE__)
+#    define __LZO_WORDSIZE          4
+#    define LZO_SIZEOF_VOID_P       2
+#  elif defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__)
+#    define __LZO_WORDSIZE          4
+#    define LZO_SIZEOF_VOID_P       4
+#  else
+#    define __LZO_WORDSIZE          2
+#    define LZO_SIZEOF_VOID_P       2
+#  endif
+#  if (LZO_CC_GNUC && (LZO_CC_GNUC < 0x040000ul)) && (LZO_SIZEOF_INT == 4)
+#    define LZO_SIZEOF_SIZE_T       LZO_SIZEOF_INT
+#    define LZO_SIZEOF_PTRDIFF_T    LZO_SIZEOF_INT
+#  endif
+#elif (LZO_ARCH_M16C)
+#  define __LZO_WORDSIZE            2
+#  if defined(__m32c_cpu__) || defined(__m32cm_cpu__)
+#    define LZO_SIZEOF_VOID_P       4
+#  else
+#    define LZO_SIZEOF_VOID_P       2
+#  endif
+#elif (LZO_SIZEOF_LONG == 8) && ((defined(__mips__) && defined(__R5900__)) || defined(__MIPS_PSX2__))
+#  define __LZO_WORDSIZE            8
+#  define LZO_SIZEOF_VOID_P         4
+#elif defined(__LLP64__) || defined(__LLP64) || defined(_LLP64) || defined(_WIN64)
+#  define __LZO_WORDSIZE            8
+#  define LZO_SIZEOF_VOID_P         8
+#elif (LZO_OS_OS400 || defined(__OS400__)) && defined(__LLP64_IFC__)
+#  define LZO_SIZEOF_VOID_P         LZO_SIZEOF_LONG
+#  define LZO_SIZEOF_SIZE_T         LZO_SIZEOF_LONG
+#  define LZO_SIZEOF_PTRDIFF_T      LZO_SIZEOF_LONG
+#elif (LZO_OS_OS400 || defined(__OS400__))
+#  define __LZO_WORDSIZE            LZO_SIZEOF_LONG
+#  define LZO_SIZEOF_VOID_P         16
+#  define LZO_SIZEOF_SIZE_T         LZO_SIZEOF_LONG
+#  define LZO_SIZEOF_PTRDIFF_T      LZO_SIZEOF_LONG
+#elif (defined(__vms) || defined(__VMS)) && (__INITIAL_POINTER_SIZE+0 == 64)
+#  define LZO_SIZEOF_VOID_P         8
+#  define LZO_SIZEOF_SIZE_T         LZO_SIZEOF_LONG
+#  define LZO_SIZEOF_PTRDIFF_T      LZO_SIZEOF_LONG
+#elif (LZO_ARCH_SPU)
+# if 0
+#  define __LZO_WORDSIZE            16
+# endif
+#  define LZO_SIZEOF_VOID_P         4
+#else
+#  define LZO_SIZEOF_VOID_P         LZO_SIZEOF_LONG
+#endif
+#endif
+#if !defined(LZO_WORDSIZE)
+#  if defined(__LZO_WORDSIZE)
+#    define LZO_WORDSIZE            __LZO_WORDSIZE
+#  else
+#    define LZO_WORDSIZE            LZO_SIZEOF_VOID_P
+#  endif
+#endif
+#if !defined(LZO_SIZEOF_SIZE_T)
+#if (LZO_ARCH_I086 || LZO_ARCH_M16C)
+#  define LZO_SIZEOF_SIZE_T         2
+#else
+#  define LZO_SIZEOF_SIZE_T         LZO_SIZEOF_VOID_P
+#endif
+#endif
+#if !defined(LZO_SIZEOF_PTRDIFF_T)
+#if (LZO_ARCH_I086)
+#  if (LZO_MM_TINY || LZO_MM_SMALL || LZO_MM_MEDIUM || LZO_MM_HUGE)
+#    define LZO_SIZEOF_PTRDIFF_T    LZO_SIZEOF_VOID_P
+#  elif (LZO_MM_COMPACT || LZO_MM_LARGE)
+#    if (LZO_CC_BORLANDC || LZO_CC_TURBOC)
+#      define LZO_SIZEOF_PTRDIFF_T  4
+#    else
+#      define LZO_SIZEOF_PTRDIFF_T  2
+#    endif
+#  else
+#    error "LZO_MM"
+#  endif
+#else
+#  define LZO_SIZEOF_PTRDIFF_T      LZO_SIZEOF_SIZE_T
+#endif
+#endif
+#if (LZO_ABI_NEUTRAL_ENDIAN)
+#  undef LZO_ABI_BIG_ENDIAN
+#  undef LZO_ABI_LITTLE_ENDIAN
+#elif !(LZO_ABI_BIG_ENDIAN) && !(LZO_ABI_LITTLE_ENDIAN)
+#if (LZO_ARCH_ALPHA) && (LZO_ARCH_CRAY_MPP)
+#  define LZO_ABI_BIG_ENDIAN        1
+#elif (LZO_ARCH_IA64) && (LZO_OS_POSIX_LINUX || LZO_OS_WIN64)
+#  define LZO_ABI_LITTLE_ENDIAN     1
+#elif (LZO_ARCH_ALPHA || LZO_ARCH_AMD64 || LZO_ARCH_BLACKFIN || LZO_ARCH_CRIS || LZO_ARCH_I086 || LZO_ARCH_I386 || LZO_ARCH_MSP430)
+#  define LZO_ABI_LITTLE_ENDIAN     1
+#elif (LZO_ARCH_AVR32 || LZO_ARCH_M68K || LZO_ARCH_S390)
+#  define LZO_ABI_BIG_ENDIAN        1
+#elif 1 && defined(__IAR_SYSTEMS_ICC__) && defined(__LITTLE_ENDIAN__)
+#  if (__LITTLE_ENDIAN__ == 1)
+#    define LZO_ABI_LITTLE_ENDIAN   1
+#  else
+#    define LZO_ABI_BIG_ENDIAN      1
+#  endif
+#elif 1 && defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__)
+#  define LZO_ABI_BIG_ENDIAN        1
+#elif 1 && defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__)
+#  define LZO_ABI_LITTLE_ENDIAN     1
+#elif 1 && (LZO_ARCH_ARM) && defined(__ARMEB__) && !defined(__ARMEL__)
+#  define LZO_ABI_BIG_ENDIAN        1
+#elif 1 && (LZO_ARCH_ARM) && defined(__ARMEL__) && !defined(__ARMEB__)
+#  define LZO_ABI_LITTLE_ENDIAN     1
+#elif 1 && (LZO_ARCH_MIPS) && defined(__MIPSEB__) && !defined(__MIPSEL__)
+#  define LZO_ABI_BIG_ENDIAN        1
+#elif 1 && (LZO_ARCH_MIPS) && defined(__MIPSEL__) && !defined(__MIPSEB__)
+#  define LZO_ABI_LITTLE_ENDIAN     1
+#endif
+#endif
+#if (LZO_ABI_BIG_ENDIAN) && (LZO_ABI_LITTLE_ENDIAN)
+#  error "this should not happen"
+#endif
+#if (LZO_ABI_BIG_ENDIAN)
+#  define LZO_INFO_ABI_ENDIAN       "be"
+#elif (LZO_ABI_LITTLE_ENDIAN)
+#  define LZO_INFO_ABI_ENDIAN       "le"
+#elif (LZO_ABI_NEUTRAL_ENDIAN)
+#  define LZO_INFO_ABI_ENDIAN       "neutral"
+#endif
+#if (LZO_SIZEOF_INT == 1 && LZO_SIZEOF_LONG == 2 && LZO_SIZEOF_VOID_P == 2)
+#  define LZO_ABI_I8LP16         1
+#  define LZO_INFO_ABI_PM       "i8lp16"
+#elif (LZO_SIZEOF_INT == 2 && LZO_SIZEOF_LONG == 2 && LZO_SIZEOF_VOID_P == 2)
+#  define LZO_ABI_ILP16         1
+#  define LZO_INFO_ABI_PM       "ilp16"
+#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 4 && LZO_SIZEOF_VOID_P == 4)
+#  define LZO_ABI_ILP32         1
+#  define LZO_INFO_ABI_PM       "ilp32"
+#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 4 && LZO_SIZEOF_VOID_P == 8 && LZO_SIZEOF_SIZE_T == 8)
+#  define LZO_ABI_LLP64         1
+#  define LZO_INFO_ABI_PM       "llp64"
+#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 8)
+#  define LZO_ABI_LP64          1
+#  define LZO_INFO_ABI_PM       "lp64"
+#elif (LZO_SIZEOF_INT == 8 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 8)
+#  define LZO_ABI_ILP64         1
+#  define LZO_INFO_ABI_PM       "ilp64"
+#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 4)
+#  define LZO_ABI_IP32L64       1
+#  define LZO_INFO_ABI_PM       "ip32l64"
+#endif
+#if !defined(__LZO_LIBC_OVERRIDE)
+#if (LZO_LIBC_NAKED)
+#  define LZO_INFO_LIBC         "naked"
+#elif (LZO_LIBC_FREESTANDING)
+#  define LZO_INFO_LIBC         "freestanding"
+#elif (LZO_LIBC_MOSTLY_FREESTANDING)
+#  define LZO_INFO_LIBC         "mfreestanding"
+#elif (LZO_LIBC_ISOC90)
+#  define LZO_INFO_LIBC         "isoc90"
+#elif (LZO_LIBC_ISOC99)
+#  define LZO_INFO_LIBC         "isoc99"
+#elif defined(__dietlibc__)
+#  define LZO_LIBC_DIETLIBC     1
+#  define LZO_INFO_LIBC         "dietlibc"
+#elif defined(_NEWLIB_VERSION)
+#  define LZO_LIBC_NEWLIB       1
+#  define LZO_INFO_LIBC         "newlib"
+#elif defined(__UCLIBC__) && defined(__UCLIBC_MAJOR__) && defined(__UCLIBC_MINOR__)
+#  if defined(__UCLIBC_SUBLEVEL__)
+#    define LZO_LIBC_UCLIBC     (__UCLIBC_MAJOR__ * 0x10000L + __UCLIBC_MINOR__ * 0x100 + __UCLIBC_SUBLEVEL__)
+#  else
+#    define LZO_LIBC_UCLIBC     0x00090bL
+#  endif
+#  define LZO_INFO_LIBC         "uclibc"
+#elif defined(__GLIBC__) && defined(__GLIBC_MINOR__)
+#  define LZO_LIBC_GLIBC        (__GLIBC__ * 0x10000L + __GLIBC_MINOR__ * 0x100)
+#  define LZO_INFO_LIBC         "glibc"
+#elif (LZO_CC_MWERKS) && defined(__MSL__)
+#  define LZO_LIBC_MSL          __MSL__
+#  define LZO_INFO_LIBC         "msl"
+#elif 1 && defined(__IAR_SYSTEMS_ICC__)
+#  define LZO_LIBC_ISOC90       1
+#  define LZO_INFO_LIBC         "isoc90"
+#else
+#  define LZO_LIBC_DEFAULT      1
+#  define LZO_INFO_LIBC         "default"
+#endif
+#endif
+#if !defined(__lzo_gnuc_extension__)
+#if (LZO_CC_GNUC >= 0x020800ul)
+#  define __lzo_gnuc_extension__    __extension__
+#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#  define __lzo_gnuc_extension__    __extension__
+#else
+#  define __lzo_gnuc_extension__    /*empty*/
+#endif
+#endif
+#if !defined(__lzo_ua_volatile)
+#  define __lzo_ua_volatile     volatile
+#endif
+#if !defined(__lzo_alignof)
+#if (LZO_CC_CILLY || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI)
+#  define __lzo_alignof(e)      __alignof__(e)
+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 700))
+#  define __lzo_alignof(e)      __alignof__(e)
+#elif (LZO_CC_MSC && (_MSC_VER >= 1300))
+#  define __lzo_alignof(e)      __alignof(e)
+#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100))
+#  define __lzo_alignof(e)      __alignof__(e)
+#endif
+#endif
+#if defined(__lzo_alignof)
+#  define __lzo_HAVE_alignof 1
+#endif
+#if !defined(__lzo_constructor)
+#if (LZO_CC_GNUC >= 0x030400ul)
+#  define __lzo_constructor     __attribute__((__constructor__,__used__))
+#elif (LZO_CC_GNUC >= 0x020700ul)
+#  define __lzo_constructor     __attribute__((__constructor__))
+#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#  define __lzo_constructor     __attribute__((__constructor__))
+#endif
+#endif
+#if defined(__lzo_constructor)
+#  define __lzo_HAVE_constructor 1
+#endif
+#if !defined(__lzo_destructor)
+#if (LZO_CC_GNUC >= 0x030400ul)
+#  define __lzo_destructor      __attribute__((__destructor__,__used__))
+#elif (LZO_CC_GNUC >= 0x020700ul)
+#  define __lzo_destructor      __attribute__((__destructor__))
+#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#  define __lzo_destructor      __attribute__((__destructor__))
+#endif
+#endif
+#if defined(__lzo_destructor)
+#  define __lzo_HAVE_destructor 1
+#endif
+#if (__lzo_HAVE_destructor) && !(__lzo_HAVE_constructor)
+#  error "this should not happen"
+#endif
+#if !defined(__lzo_inline)
+#if (LZO_CC_TURBOC && (__TURBOC__ <= 0x0295))
+#elif defined(__cplusplus)
+#  define __lzo_inline          inline
+#elif (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0550))
+#  define __lzo_inline          __inline
+#elif (LZO_CC_CILLY || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI)
+#  define __lzo_inline          __inline__
+#elif (LZO_CC_DMC)
+#  define __lzo_inline          __inline
+#elif (LZO_CC_INTELC)
+#  define __lzo_inline          __inline
+#elif (LZO_CC_MWERKS && (__MWERKS__ >= 0x2405))
+#  define __lzo_inline          __inline
+#elif (LZO_CC_MSC && (_MSC_VER >= 900))
+#  define __lzo_inline          __inline
+#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100))
+#  define __lzo_inline          __inline__
+#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
+#  define __lzo_inline          inline
+#endif
+#endif
+#if defined(__lzo_inline)
+#  define __lzo_HAVE_inline 1
+#else
+#  define __lzo_inline          /*empty*/
+#endif
+#if !defined(__lzo_forceinline)
+#if (LZO_CC_GNUC >= 0x030200ul)
+#  define __lzo_forceinline     __inline__ __attribute__((__always_inline__))
+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC)
+#  define __lzo_forceinline     __forceinline
+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC)
+#  define __lzo_forceinline     __inline__ __attribute__((__always_inline__))
+#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#  define __lzo_forceinline     __inline__ __attribute__((__always_inline__))
+#elif (LZO_CC_MSC && (_MSC_VER >= 1200))
+#  define __lzo_forceinline     __forceinline
+#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100))
+#  define __lzo_forceinline     __inline__ __attribute__((__always_inline__))
+#endif
+#endif
+#if defined(__lzo_forceinline)
+#  define __lzo_HAVE_forceinline 1
+#else
+#  define __lzo_forceinline     /*empty*/
+#endif
+#if !defined(__lzo_noinline)
+#if 1 && (LZO_ARCH_I386) && (LZO_CC_GNUC >= 0x040000ul) && (LZO_CC_GNUC < 0x040003ul)
+#  define __lzo_noinline        __attribute__((__noinline__,__used__))
+#elif (LZO_CC_GNUC >= 0x030200ul)
+#  define __lzo_noinline        __attribute__((__noinline__))
+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_MSC)
+#  define __lzo_noinline        __declspec(noinline)
+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC)
+#  define __lzo_noinline        __attribute__((__noinline__))
+#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#  define __lzo_noinline        __attribute__((__noinline__))
+#elif (LZO_CC_MSC && (_MSC_VER >= 1300))
+#  define __lzo_noinline        __declspec(noinline)
+#elif (LZO_CC_MWERKS && (__MWERKS__ >= 0x3200) && (LZO_OS_WIN32 || LZO_OS_WIN64))
+#  if defined(__cplusplus)
+#  else
+#    define __lzo_noinline      __declspec(noinline)
+#  endif
+#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100))
+#  define __lzo_noinline        __attribute__((__noinline__))
+#endif
+#endif
+#if defined(__lzo_noinline)
+#  define __lzo_HAVE_noinline 1
+#else
+#  define __lzo_noinline        /*empty*/
+#endif
+#if (__lzo_HAVE_forceinline || __lzo_HAVE_noinline) && !(__lzo_HAVE_inline)
+#  error "this should not happen"
+#endif
+#if !defined(__lzo_noreturn)
+#if (LZO_CC_GNUC >= 0x020700ul)
+#  define __lzo_noreturn        __attribute__((__noreturn__))
+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC)
+#  define __lzo_noreturn        __declspec(noreturn)
+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_GNUC)
+#  define __lzo_noreturn        __attribute__((__noreturn__))
+#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#  define __lzo_noreturn        __attribute__((__noreturn__))
+#elif (LZO_CC_MSC && (_MSC_VER >= 1200))
+#  define __lzo_noreturn        __declspec(noreturn)
+#endif
+#endif
+#if defined(__lzo_noreturn)
+#  define __lzo_HAVE_noreturn 1
+#else
+#  define __lzo_noreturn        /*empty*/
+#endif
+#if !defined(__lzo_nothrow)
+#if (LZO_CC_GNUC >= 0x030300ul)
+#  define __lzo_nothrow         __attribute__((__nothrow__))
+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC) && defined(__cplusplus)
+#  define __lzo_nothrow         __declspec(nothrow)
+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 900) && LZO_CC_SYNTAX_GNUC)
+#  define __lzo_nothrow         __attribute__((__nothrow__))
+#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#  define __lzo_nothrow         __attribute__((__nothrow__))
+#elif (LZO_CC_MSC && (_MSC_VER >= 1200)) && defined(__cplusplus)
+#  define __lzo_nothrow         __declspec(nothrow)
+#endif
+#endif
+#if defined(__lzo_nothrow)
+#  define __lzo_HAVE_nothrow 1
+#else
+#  define __lzo_nothrow         /*empty*/
+#endif
+#if !defined(__lzo_restrict)
+#if (LZO_CC_GNUC >= 0x030400ul)
+#  define __lzo_restrict        __restrict__
+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_GNUC)
+#  define __lzo_restrict        __restrict__
+#elif (LZO_CC_CLANG || LZO_CC_LLVM)
+#  define __lzo_restrict        __restrict__
+#elif (LZO_CC_MSC && (_MSC_VER >= 1400))
+#  define __lzo_restrict        __restrict
+#endif
+#endif
+#if defined(__lzo_restrict)
+#  define __lzo_HAVE_restrict 1
+#else
+#  define __lzo_restrict        /*empty*/
+#endif
+#if !defined(__lzo_likely) && !defined(__lzo_unlikely)
+#if (LZO_CC_GNUC >= 0x030200ul)
+#  define __lzo_likely(e)       (__builtin_expect(!!(e),1))
+#  define __lzo_unlikely(e)     (__builtin_expect(!!(e),0))
+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800))
+#  define __lzo_likely(e)       (__builtin_expect(!!(e),1))
+#  define __lzo_unlikely(e)     (__builtin_expect(!!(e),0))
+#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#  define __lzo_likely(e)       (__builtin_expect(!!(e),1))
+#  define __lzo_unlikely(e)     (__builtin_expect(!!(e),0))
+#endif
+#endif
+#if defined(__lzo_likely)
+#  define __lzo_HAVE_likely 1
+#else
+#  define __lzo_likely(e)       (e)
+#endif
+#if defined(__lzo_unlikely)
+#  define __lzo_HAVE_unlikely 1
+#else
+#  define __lzo_unlikely(e)     (e)
+#endif
+#if !defined(LZO_UNUSED)
+#  if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0600))
+#    define LZO_UNUSED(var)         ((void) &var)
+#  elif (LZO_CC_BORLANDC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PELLESC || LZO_CC_TURBOC)
+#    define LZO_UNUSED(var)         if (&var) ; else
+#  elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#    define LZO_UNUSED(var)         ((void) var)
+#  elif (LZO_CC_MSC && (_MSC_VER < 900))
+#    define LZO_UNUSED(var)         if (&var) ; else
+#  elif (LZO_CC_KEILC)
+#    define LZO_UNUSED(var)         {extern int __lzo_unused[1-2*!(sizeof(var)>0)];}
+#  elif (LZO_CC_PACIFICC)
+#    define LZO_UNUSED(var)         ((void) sizeof(var))
+#  elif (LZO_CC_WATCOMC) && defined(__cplusplus)
+#    define LZO_UNUSED(var)         ((void) var)
+#  else
+#    define LZO_UNUSED(var)         ((void) &var)
+#  endif
+#endif
+#if !defined(LZO_UNUSED_FUNC)
+#  if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0600))
+#    define LZO_UNUSED_FUNC(func)   ((void) func)
+#  elif (LZO_CC_BORLANDC || LZO_CC_NDPC || LZO_CC_TURBOC)
+#    define LZO_UNUSED_FUNC(func)   if (func) ; else
+#  elif (LZO_CC_CLANG || LZO_CC_LLVM)
+#    define LZO_UNUSED_FUNC(func)   ((void) &func)
+#  elif (LZO_CC_MSC && (_MSC_VER < 900))
+#    define LZO_UNUSED_FUNC(func)   if (func) ; else
+#  elif (LZO_CC_MSC)
+#    define LZO_UNUSED_FUNC(func)   ((void) &func)
+#  elif (LZO_CC_KEILC || LZO_CC_PELLESC)
+#    define LZO_UNUSED_FUNC(func)   {extern int __lzo_unused[1-2*!(sizeof((int)func)>0)];}
+#  else
+#    define LZO_UNUSED_FUNC(func)   ((void) func)
+#  endif
+#endif
+#if !defined(LZO_UNUSED_LABEL)
+#  if (LZO_CC_WATCOMC) && defined(__cplusplus)
+#    define LZO_UNUSED_LABEL(l)     switch(0) case 1:goto l
+#  elif (LZO_CC_CLANG || LZO_CC_INTELC || LZO_CC_WATCOMC)
+#    define LZO_UNUSED_LABEL(l)     if (0) goto l
+#  else
+#    define LZO_UNUSED_LABEL(l)     switch(0) case 1:goto l
+#  endif
+#endif
+#if !defined(LZO_DEFINE_UNINITIALIZED_VAR)
+#  if 0
+#    define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init)  type var
+#  elif 0 && (LZO_CC_GNUC)
+#    define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init)  type var = var
+#  else
+#    define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init)  type var = init
+#  endif
+#endif
+#if !defined(LZO_UNCONST_CAST)
+#  if 0 && defined(__cplusplus)
+#    define LZO_UNCONST_CAST(t,e)   (const_cast<t> (e))
+#  elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#    define LZO_UNCONST_CAST(t,e)   ((t) ((void *) ((char *) ((lzo_uintptr_t) ((const void *) (e))))))
+#  else
+#    define LZO_UNCONST_CAST(t,e)   ((t) ((void *) ((char *) ((const void *) (e)))))
+#  endif
+#endif
+#if !defined(LZO_COMPILE_TIME_ASSERT_HEADER)
+#  if (LZO_CC_AZTECC || LZO_CC_ZORTECHC)
+#    define LZO_COMPILE_TIME_ASSERT_HEADER(e)  extern int __lzo_cta[1-!(e)];
+#  elif (LZO_CC_DMC || LZO_CC_SYMANTECC)
+#    define LZO_COMPILE_TIME_ASSERT_HEADER(e)  extern int __lzo_cta[1u-2*!(e)];
+#  elif (LZO_CC_TURBOC && (__TURBOC__ == 0x0295))
+#    define LZO_COMPILE_TIME_ASSERT_HEADER(e)  extern int __lzo_cta[1-!(e)];
+#  else
+#    define LZO_COMPILE_TIME_ASSERT_HEADER(e)  extern int __lzo_cta[1-2*!(e)];
+#  endif
+#endif
+#if !defined(LZO_COMPILE_TIME_ASSERT)
+#  if (LZO_CC_AZTECC)
+#    define LZO_COMPILE_TIME_ASSERT(e)  {typedef int __lzo_cta_t[1-!(e)];}
+#  elif (LZO_CC_DMC || LZO_CC_PACIFICC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC)
+#    define LZO_COMPILE_TIME_ASSERT(e)  switch(0) case 1:case !(e):break;
+#  elif (LZO_CC_MSC && (_MSC_VER < 900))
+#    define LZO_COMPILE_TIME_ASSERT(e)  switch(0) case 1:case !(e):break;
+#  elif (LZO_CC_TURBOC && (__TURBOC__ == 0x0295))
+#    define LZO_COMPILE_TIME_ASSERT(e)  switch(0) case 1:case !(e):break;
+#  else
+#    define LZO_COMPILE_TIME_ASSERT(e)  {typedef int __lzo_cta_t[1-2*!(e)];}
+#  endif
+#endif
+#if (LZO_ARCH_I086 || LZO_ARCH_I386) && (LZO_OS_DOS16 || LZO_OS_DOS32 || LZO_OS_OS2 || LZO_OS_OS216 || LZO_OS_WIN16 || LZO_OS_WIN32 || LZO_OS_WIN64)
+#  if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC)
+#  elif (LZO_CC_DMC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC)
+#    define __lzo_cdecl                 __cdecl
+#    define __lzo_cdecl_atexit          /*empty*/
+#    define __lzo_cdecl_main            __cdecl
+#    if (LZO_OS_OS2 && (LZO_CC_DMC || LZO_CC_SYMANTECC))
+#      define __lzo_cdecl_qsort         __pascal
+#    elif (LZO_OS_OS2 && (LZO_CC_ZORTECHC))
+#      define __lzo_cdecl_qsort         _stdcall
+#    else
+#      define __lzo_cdecl_qsort         __cdecl
+#    endif
+#  elif (LZO_CC_WATCOMC)
+#    define __lzo_cdecl                 __cdecl
+#  else
+#    define __lzo_cdecl                 __cdecl
+#    define __lzo_cdecl_atexit          __cdecl
+#    define __lzo_cdecl_main            __cdecl
+#    define __lzo_cdecl_qsort           __cdecl
+#  endif
+#  if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC || LZO_CC_WATCOMC)
+#  elif (LZO_OS_OS2 && (LZO_CC_DMC || LZO_CC_SYMANTECC))
+#    define __lzo_cdecl_sighandler      __pascal
+#  elif (LZO_OS_OS2 && (LZO_CC_ZORTECHC))
+#    define __lzo_cdecl_sighandler      _stdcall
+#  elif (LZO_CC_MSC && (_MSC_VER >= 1400)) && defined(_M_CEE_PURE)
+#    define __lzo_cdecl_sighandler      __clrcall
+#  elif (LZO_CC_MSC && (_MSC_VER >= 600 && _MSC_VER < 700))
+#    if defined(_DLL)
+#      define __lzo_cdecl_sighandler    _far _cdecl _loadds
+#    elif defined(_MT)
+#      define __lzo_cdecl_sighandler    _far _cdecl
+#    else
+#      define __lzo_cdecl_sighandler    _cdecl
+#    endif
+#  else
+#    define __lzo_cdecl_sighandler      __cdecl
+#  endif
+#elif (LZO_ARCH_I386) && (LZO_CC_WATCOMC)
+#  define __lzo_cdecl                   __cdecl
+#elif (LZO_ARCH_M68K && LZO_OS_TOS && (LZO_CC_PUREC || LZO_CC_TURBOC))
+#  define __lzo_cdecl                   cdecl
+#endif
+#if !defined(__lzo_cdecl)
+#  define __lzo_cdecl                   /*empty*/
+#endif
+#if !defined(__lzo_cdecl_atexit)
+#  define __lzo_cdecl_atexit            /*empty*/
+#endif
+#if !defined(__lzo_cdecl_main)
+#  define __lzo_cdecl_main              /*empty*/
+#endif
+#if !defined(__lzo_cdecl_qsort)
+#  define __lzo_cdecl_qsort             /*empty*/
+#endif
+#if !defined(__lzo_cdecl_sighandler)
+#  define __lzo_cdecl_sighandler        /*empty*/
+#endif
+#if !defined(__lzo_cdecl_va)
+#  define __lzo_cdecl_va                __lzo_cdecl
+#endif
+#if !(LZO_CFG_NO_WINDOWS_H)
+#if (LZO_OS_CYGWIN || (LZO_OS_EMX && defined(__RSXNT__)) || LZO_OS_WIN32 || LZO_OS_WIN64)
+#  if (LZO_CC_WATCOMC && (__WATCOMC__ < 1000))
+#  elif (LZO_OS_WIN32 && LZO_CC_GNUC) && defined(__PW32__)
+#  elif ((LZO_OS_CYGWIN || defined(__MINGW32__)) && (LZO_CC_GNUC && (LZO_CC_GNUC < 0x025f00ul)))
+#  else
+#    define LZO_HAVE_WINDOWS_H 1
+#  endif
+#endif
+#endif
+#if (LZO_ARCH_ALPHA)
+#  define LZO_OPT_AVOID_UINT_INDEX  1
+#  define LZO_OPT_AVOID_SHORT       1
+#  define LZO_OPT_AVOID_USHORT      1
+#elif (LZO_ARCH_AMD64)
+#  define LZO_OPT_AVOID_INT_INDEX   1
+#  define LZO_OPT_AVOID_UINT_INDEX  1
+#  define LZO_OPT_UNALIGNED16       1
+#  define LZO_OPT_UNALIGNED32       1
+#  define LZO_OPT_UNALIGNED64       1
+#elif (LZO_ARCH_ARM && LZO_ARCH_ARM_THUMB)
+#elif (LZO_ARCH_ARM)
+#  define LZO_OPT_AVOID_SHORT       1
+#  define LZO_OPT_AVOID_USHORT      1
+#elif (LZO_ARCH_CRIS)
+#  define LZO_OPT_UNALIGNED16       1
+#  define LZO_OPT_UNALIGNED32       1
+#elif (LZO_ARCH_I386)
+#  define LZO_OPT_UNALIGNED16       1
+#  define LZO_OPT_UNALIGNED32       1
+#elif (LZO_ARCH_IA64)
+#  define LZO_OPT_AVOID_INT_INDEX   1
+#  define LZO_OPT_AVOID_UINT_INDEX  1
+#  define LZO_OPT_PREFER_POSTINC    1
+#elif (LZO_ARCH_M68K)
+#  define LZO_OPT_PREFER_POSTINC    1
+#  define LZO_OPT_PREFER_PREDEC     1
+#  if defined(__mc68020__) && !defined(__mcoldfire__)
+#    define LZO_OPT_UNALIGNED16     1
+#    define LZO_OPT_UNALIGNED32     1
+#  endif
+#elif (LZO_ARCH_MIPS)
+#  define LZO_OPT_AVOID_UINT_INDEX  1
+#elif (LZO_ARCH_POWERPC)
+#  define LZO_OPT_PREFER_PREINC     1
+#  define LZO_OPT_PREFER_PREDEC     1
+#  if (LZO_ABI_BIG_ENDIAN)
+#    define LZO_OPT_UNALIGNED16     1
+#    define LZO_OPT_UNALIGNED32     1
+#  endif
+#elif (LZO_ARCH_S390)
+#  define LZO_OPT_UNALIGNED16       1
+#  define LZO_OPT_UNALIGNED32       1
+#  if (LZO_SIZEOF_SIZE_T == 8)
+#    define LZO_OPT_UNALIGNED64     1
+#  endif
+#elif (LZO_ARCH_SH)
+#  define LZO_OPT_PREFER_POSTINC    1
+#  define LZO_OPT_PREFER_PREDEC     1
+#endif
+#ifndef LZO_CFG_NO_INLINE_ASM
+#if (LZO_CC_LLVM)
+#  define LZO_CFG_NO_INLINE_ASM 1
+#endif
+#endif
+#ifndef LZO_CFG_NO_UNALIGNED
+#if (LZO_ABI_NEUTRAL_ENDIAN) || (LZO_ARCH_GENERIC)
+#  define LZO_CFG_NO_UNALIGNED 1
+#endif
+#endif
+#if (LZO_CFG_NO_UNALIGNED)
+#  undef LZO_OPT_UNALIGNED16
+#  undef LZO_OPT_UNALIGNED32
+#  undef LZO_OPT_UNALIGNED64
+#endif
+#if (LZO_CFG_NO_INLINE_ASM)
+#elif (LZO_ARCH_I386 && (LZO_OS_DOS32 || LZO_OS_WIN32) && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC))
+#  define LZO_ASM_SYNTAX_MSC 1
+#elif (LZO_OS_WIN64 && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC))
+#elif (LZO_ARCH_I386 && LZO_CC_GNUC && (LZO_CC_GNUC == 0x011f00ul))
+#elif (LZO_ARCH_I386 && (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE))
+#  define LZO_ASM_SYNTAX_GNUC 1
+#elif (LZO_ARCH_AMD64 && (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE))
+#  define LZO_ASM_SYNTAX_GNUC 1
+#endif
+#if (LZO_ASM_SYNTAX_GNUC)
+#if (LZO_ARCH_I386 && LZO_CC_GNUC && (LZO_CC_GNUC < 0x020000ul))
+#  define __LZO_ASM_CLOBBER         "ax"
+#elif (LZO_CC_INTELC)
+#  define __LZO_ASM_CLOBBER         "memory"
+#else
+#  define __LZO_ASM_CLOBBER         "cc", "memory"
+#endif
+#endif
+#if defined(__LZO_INFOSTR_MM)
+#elif (LZO_MM_FLAT) && (defined(__LZO_INFOSTR_PM) || defined(LZO_INFO_ABI_PM))
+#  define __LZO_INFOSTR_MM          ""
+#elif defined(LZO_INFO_MM)
+#  define __LZO_INFOSTR_MM          "." LZO_INFO_MM
+#else
+#  define __LZO_INFOSTR_MM          ""
+#endif
+#if defined(__LZO_INFOSTR_PM)
+#elif defined(LZO_INFO_ABI_PM)
+#  define __LZO_INFOSTR_PM          "." LZO_INFO_ABI_PM
+#else
+#  define __LZO_INFOSTR_PM          ""
+#endif
+#if defined(__LZO_INFOSTR_ENDIAN)
+#elif defined(LZO_INFO_ABI_ENDIAN)
+#  define __LZO_INFOSTR_ENDIAN      "." LZO_INFO_ABI_ENDIAN
+#else
+#  define __LZO_INFOSTR_ENDIAN      ""
+#endif
+#if defined(__LZO_INFOSTR_OSNAME)
+#elif defined(LZO_INFO_OS_CONSOLE)
+#  define __LZO_INFOSTR_OSNAME      LZO_INFO_OS "." LZO_INFO_OS_CONSOLE
+#elif defined(LZO_INFO_OS_POSIX)
+#  define __LZO_INFOSTR_OSNAME      LZO_INFO_OS "." LZO_INFO_OS_POSIX
+#else
+#  define __LZO_INFOSTR_OSNAME      LZO_INFO_OS
+#endif
+#if defined(__LZO_INFOSTR_LIBC)
+#elif defined(LZO_INFO_LIBC)
+#  define __LZO_INFOSTR_LIBC        "." LZO_INFO_LIBC
+#else
+#  define __LZO_INFOSTR_LIBC        ""
+#endif
+#if defined(__LZO_INFOSTR_CCVER)
+#elif defined(LZO_INFO_CCVER)
+#  define __LZO_INFOSTR_CCVER       " " LZO_INFO_CCVER
+#else
+#  define __LZO_INFOSTR_CCVER       ""
+#endif
+#define LZO_INFO_STRING \
+    LZO_INFO_ARCH __LZO_INFOSTR_MM __LZO_INFOSTR_PM __LZO_INFOSTR_ENDIAN \
+    " " __LZO_INFOSTR_OSNAME __LZO_INFOSTR_LIBC " " LZO_INFO_CC __LZO_INFOSTR_CCVER
+
+#endif /* already included */
+
+/* vim:set ts=4 et: */
diff --git a/filesystems/minilzo.c b/filesystems/minilzo.c
new file mode 100644 (file)
index 0000000..c8ae5d2
--- /dev/null
@@ -0,0 +1,4567 @@
+/*
+ * this file take from grub 2.0
+ * for btrfs UEFI driver
+ */
+
+/* minilzo.c -- mini subset of the LZO real-time data compression library
+
+   This file is part of the LZO real-time data compression library.
+
+   Copyright (C) 2011 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2010 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2009 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
+   All Rights Reserved.
+
+   The LZO library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   The LZO library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with the LZO library; see the file COPYING.
+   If not, write to the Free Software Foundation, Inc.,
+   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+   Markus F.X.J. Oberhumer
+   <markus@oberhumer.com>
+   http://www.oberhumer.com/opensource/lzo/
+ */
+
+/*
+ * NOTE:
+ *   the full LZO package can be found at
+ *   http://www.oberhumer.com/opensource/lzo/
+ */
+
+#define __LZO_IN_MINILZO 1
+
+#if defined(LZO_CFG_FREESTANDING)
+#  undef MINILZO_HAVE_CONFIG_H
+#  define LZO_LIBC_FREESTANDING 1
+#  define LZO_OS_FREESTANDING 1
+#endif
+
+#ifdef MINILZO_HAVE_CONFIG_H
+#  include <config.h>
+#endif
+#include <limits.h>
+#include <stddef.h>
+#if defined(MINILZO_CFG_USE_INTERNAL_LZODEFS)
+
+#ifndef __LZODEFS_H_INCLUDED
+#define __LZODEFS_H_INCLUDED 1
+
+#if defined(__CYGWIN32__) && !defined(__CYGWIN__)
+#  define __CYGWIN__ __CYGWIN32__
+#endif
+#if defined(__IBMCPP__) && !defined(__IBMC__)
+#  define __IBMC__ __IBMCPP__
+#endif
+#if defined(__ICL) && defined(_WIN32) && !defined(__INTEL_COMPILER)
+#  define __INTEL_COMPILER __ICL
+#endif
+#if 1 && defined(__INTERIX) && defined(__GNUC__) && !defined(_ALL_SOURCE)
+#  define _ALL_SOURCE 1
+#endif
+#if defined(__mips__) && defined(__R5900__)
+#  if !defined(__LONG_MAX__)
+#    define __LONG_MAX__ 9223372036854775807L
+#  endif
+#endif
+#if defined(__INTEL_COMPILER) && defined(__linux__)
+#  pragma warning(disable: 193)
+#endif
+#if defined(__KEIL__) && defined(__C166__)
+#  pragma warning disable = 322
+#elif 0 && defined(__C251__)
+#  pragma warning disable = 322
+#endif
+#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__MWERKS__)
+#  if (_MSC_VER >= 1300)
+#    pragma warning(disable: 4668)
+#  endif
+#endif
+#if 0 && defined(__WATCOMC__)
+#  if (__WATCOMC__ >= 1050) && (__WATCOMC__ < 1060)
+#    pragma warning 203 9
+#  endif
+#endif
+#if defined(__BORLANDC__) && defined(__MSDOS__) && !defined(__FLAT__)
+#  pragma option -h
+#endif
+#if 0
+#define LZO_0xffffL             0xfffful
+#define LZO_0xffffffffL         0xfffffffful
+#else
+#define LZO_0xffffL             65535ul
+#define LZO_0xffffffffL         4294967295ul
+#endif
+#if (LZO_0xffffL == LZO_0xffffffffL)
+#  error "your preprocessor is broken 1"
+#endif
+#if (16ul * 16384ul != 262144ul)
+#  error "your preprocessor is broken 2"
+#endif
+#if 0
+#if (32767 >= 4294967295ul)
+#  error "your preprocessor is broken 3"
+#endif
+#if (65535u >= 4294967295ul)
+#  error "your preprocessor is broken 4"
+#endif
+#endif
+#if (UINT_MAX == LZO_0xffffL)
+#if defined(__ZTC__) && defined(__I86__) && !defined(__OS2__)
+#  if !defined(MSDOS)
+#    define MSDOS 1
+#  endif
+#  if !defined(_MSDOS)
+#    define _MSDOS 1
+#  endif
+#elif 0 && defined(__VERSION) && defined(MB_LEN_MAX)
+#  if (__VERSION == 520) && (MB_LEN_MAX == 1)
+#    if !defined(__AZTEC_C__)
+#      define __AZTEC_C__ __VERSION
+#    endif
+#    if !defined(__DOS__)
+#      define __DOS__ 1
+#    endif
+#  endif
+#endif
+#endif
+#if defined(_MSC_VER) && defined(M_I86HM) && (UINT_MAX == LZO_0xffffL)
+#  define ptrdiff_t long
+#  define _PTRDIFF_T_DEFINED 1
+#endif
+#if (UINT_MAX == LZO_0xffffL)
+#  undef __LZO_RENAME_A
+#  undef __LZO_RENAME_B
+#  if defined(__AZTEC_C__) && defined(__DOS__)
+#    define __LZO_RENAME_A 1
+#  elif defined(_MSC_VER) && defined(MSDOS)
+#    if (_MSC_VER < 600)
+#      define __LZO_RENAME_A 1
+#    elif (_MSC_VER < 700)
+#      define __LZO_RENAME_B 1
+#    endif
+#  elif defined(__TSC__) && defined(__OS2__)
+#    define __LZO_RENAME_A 1
+#  elif defined(__MSDOS__) && defined(__TURBOC__) && (__TURBOC__ < 0x0410)
+#    define __LZO_RENAME_A 1
+#  elif defined(__PACIFIC__) && defined(DOS)
+#    if !defined(__far)
+#      define __far far
+#    endif
+#    if !defined(__near)
+#      define __near near
+#    endif
+#  endif
+#  if defined(__LZO_RENAME_A)
+#    if !defined(__cdecl)
+#      define __cdecl cdecl
+#    endif
+#    if !defined(__far)
+#      define __far far
+#    endif
+#    if !defined(__huge)
+#      define __huge huge
+#    endif
+#    if !defined(__near)
+#      define __near near
+#    endif
+#    if !defined(__pascal)
+#      define __pascal pascal
+#    endif
+#    if !defined(__huge)
+#      define __huge huge
+#    endif
+#  elif defined(__LZO_RENAME_B)
+#    if !defined(__cdecl)
+#      define __cdecl _cdecl
+#    endif
+#    if !defined(__far)
+#      define __far _far
+#    endif
+#    if !defined(__huge)
+#      define __huge _huge
+#    endif
+#    if !defined(__near)
+#      define __near _near
+#    endif
+#    if !defined(__pascal)
+#      define __pascal _pascal
+#    endif
+#  elif (defined(__PUREC__) || defined(__TURBOC__)) && defined(__TOS__)
+#    if !defined(__cdecl)
+#      define __cdecl cdecl
+#    endif
+#    if !defined(__pascal)
+#      define __pascal pascal
+#    endif
+#  endif
+#  undef __LZO_RENAME_A
+#  undef __LZO_RENAME_B
+#endif
+#if (UINT_MAX == LZO_0xffffL)
+#if defined(__AZTEC_C__) && defined(__DOS__)
+#  define LZO_BROKEN_CDECL_ALT_SYNTAX 1
+#elif defined(_MSC_VER) && defined(MSDOS)
+#  if (_MSC_VER < 600)
+#    define LZO_BROKEN_INTEGRAL_CONSTANTS 1
+#  endif
+#  if (_MSC_VER < 700)
+#    define LZO_BROKEN_INTEGRAL_PROMOTION 1
+#    define LZO_BROKEN_SIZEOF 1
+#  endif
+#elif defined(__PACIFIC__) && defined(DOS)
+#  define LZO_BROKEN_INTEGRAL_CONSTANTS 1
+#elif defined(__TURBOC__) && defined(__MSDOS__)
+#  if (__TURBOC__ < 0x0150)
+#    define LZO_BROKEN_CDECL_ALT_SYNTAX 1
+#    define LZO_BROKEN_INTEGRAL_CONSTANTS 1
+#    define LZO_BROKEN_INTEGRAL_PROMOTION 1
+#  endif
+#  if (__TURBOC__ < 0x0200)
+#    define LZO_BROKEN_SIZEOF 1
+#  endif
+#  if (__TURBOC__ < 0x0400) && defined(__cplusplus)
+#    define LZO_BROKEN_CDECL_ALT_SYNTAX 1
+#  endif
+#elif (defined(__PUREC__) || defined(__TURBOC__)) && defined(__TOS__)
+#  define LZO_BROKEN_CDECL_ALT_SYNTAX 1
+#  define LZO_BROKEN_SIZEOF 1
+#endif
+#endif
+#if defined(__WATCOMC__) && (__WATCOMC__ < 900)
+#  define LZO_BROKEN_INTEGRAL_CONSTANTS 1
+#endif
+#if defined(_CRAY) && defined(_CRAY1)
+#  define LZO_BROKEN_SIGNED_RIGHT_SHIFT 1
+#endif
+#define LZO_PP_STRINGIZE(x)             #x
+#define LZO_PP_MACRO_EXPAND(x)          LZO_PP_STRINGIZE(x)
+#define LZO_PP_CONCAT2(a,b)             a ## b
+#define LZO_PP_CONCAT3(a,b,c)           a ## b ## c
+#define LZO_PP_CONCAT4(a,b,c,d)         a ## b ## c ## d
+#define LZO_PP_CONCAT5(a,b,c,d,e)       a ## b ## c ## d ## e
+#define LZO_PP_ECONCAT2(a,b)            LZO_PP_CONCAT2(a,b)
+#define LZO_PP_ECONCAT3(a,b,c)          LZO_PP_CONCAT3(a,b,c)
+#define LZO_PP_ECONCAT4(a,b,c,d)        LZO_PP_CONCAT4(a,b,c,d)
+#define LZO_PP_ECONCAT5(a,b,c,d,e)      LZO_PP_CONCAT5(a,b,c,d,e)
+#if 1
+#define LZO_CPP_STRINGIZE(x)            #x
+#define LZO_CPP_MACRO_EXPAND(x)         LZO_CPP_STRINGIZE(x)
+#define LZO_CPP_CONCAT2(a,b)            a ## b
+#define LZO_CPP_CONCAT3(a,b,c)          a ## b ## c
+#define LZO_CPP_CONCAT4(a,b,c,d)        a ## b ## c ## d
+#define LZO_CPP_CONCAT5(a,b,c,d,e)      a ## b ## c ## d ## e
+#define LZO_CPP_ECONCAT2(a,b)           LZO_CPP_CONCAT2(a,b)
+#define LZO_CPP_ECONCAT3(a,b,c)         LZO_CPP_CONCAT3(a,b,c)
+#define LZO_CPP_ECONCAT4(a,b,c,d)       LZO_CPP_CONCAT4(a,b,c,d)
+#define LZO_CPP_ECONCAT5(a,b,c,d,e)     LZO_CPP_CONCAT5(a,b,c,d,e)
+#endif
+#define __LZO_MASK_GEN(o,b)     (((((o) << ((b)-1)) - (o)) << 1) + (o))
+#if 1 && defined(__cplusplus)
+#  if !defined(__STDC_CONSTANT_MACROS)
+#    define __STDC_CONSTANT_MACROS 1
+#  endif
+#  if !defined(__STDC_LIMIT_MACROS)
+#    define __STDC_LIMIT_MACROS 1
+#  endif
+#endif
+#if defined(__cplusplus)
+#  define LZO_EXTERN_C extern "C"
+#else
+#  define LZO_EXTERN_C extern
+#endif
+#if !defined(__LZO_OS_OVERRIDE)
+#if (LZO_OS_FREESTANDING)
+#  define LZO_INFO_OS           "freestanding"
+#elif (LZO_OS_EMBEDDED)
+#  define LZO_INFO_OS           "embedded"
+#elif 1 && defined(__IAR_SYSTEMS_ICC__)
+#  define LZO_OS_EMBEDDED       1
+#  define LZO_INFO_OS           "embedded"
+#elif defined(__CYGWIN__) && defined(__GNUC__)
+#  define LZO_OS_CYGWIN         1
+#  define LZO_INFO_OS           "cygwin"
+#elif defined(__EMX__) && defined(__GNUC__)
+#  define LZO_OS_EMX            1
+#  define LZO_INFO_OS           "emx"
+#elif defined(__BEOS__)
+#  define LZO_OS_BEOS           1
+#  define LZO_INFO_OS           "beos"
+#elif defined(__Lynx__)
+#  define LZO_OS_LYNXOS         1
+#  define LZO_INFO_OS           "lynxos"
+#elif defined(__OS400__)
+#  define LZO_OS_OS400          1
+#  define LZO_INFO_OS           "os400"
+#elif defined(__QNX__)
+#  define LZO_OS_QNX            1
+#  define LZO_INFO_OS           "qnx"
+#elif defined(__BORLANDC__) && defined(__DPMI32__) && (__BORLANDC__ >= 0x0460)
+#  define LZO_OS_DOS32          1
+#  define LZO_INFO_OS           "dos32"
+#elif defined(__BORLANDC__) && defined(__DPMI16__)
+#  define LZO_OS_DOS16          1
+#  define LZO_INFO_OS           "dos16"
+#elif defined(__ZTC__) && defined(DOS386)
+#  define LZO_OS_DOS32          1
+#  define LZO_INFO_OS           "dos32"
+#elif defined(__OS2__) || defined(__OS2V2__)
+#  if (UINT_MAX == LZO_0xffffL)
+#    define LZO_OS_OS216        1
+#    define LZO_INFO_OS         "os216"
+#  elif (UINT_MAX == LZO_0xffffffffL)
+#    define LZO_OS_OS2          1
+#    define LZO_INFO_OS         "os2"
+#  else
+#    error "check your limits.h header"
+#  endif
+#elif defined(__WIN64__) || defined(_WIN64) || defined(WIN64)
+#  define LZO_OS_WIN64          1
+#  define LZO_INFO_OS           "win64"
+#elif defined(__WIN32__) || defined(_WIN32) || defined(WIN32) || defined(__WINDOWS_386__)
+#  define LZO_OS_WIN32          1
+#  define LZO_INFO_OS           "win32"
+#elif defined(__MWERKS__) && defined(__INTEL__)
+#  define LZO_OS_WIN32          1
+#  define LZO_INFO_OS           "win32"
+#elif defined(__WINDOWS__) || defined(_WINDOWS) || defined(_Windows)
+#  if (UINT_MAX == LZO_0xffffL)
+#    define LZO_OS_WIN16        1
+#    define LZO_INFO_OS         "win16"
+#  elif (UINT_MAX == LZO_0xffffffffL)
+#    define LZO_OS_WIN32        1
+#    define LZO_INFO_OS         "win32"
+#  else
+#    error "check your limits.h header"
+#  endif
+#elif defined(__DOS__) || defined(__MSDOS__) || defined(_MSDOS) || defined(MSDOS) || (defined(__PACIFIC__) && defined(DOS))
+#  if (UINT_MAX == LZO_0xffffL)
+#    define LZO_OS_DOS16        1
+#    define LZO_INFO_OS         "dos16"
+#  elif (UINT_MAX == LZO_0xffffffffL)
+#    define LZO_OS_DOS32        1
+#    define LZO_INFO_OS         "dos32"
+#  else
+#    error "check your limits.h header"
+#  endif
+#elif defined(__WATCOMC__)
+#  if defined(__NT__) && (UINT_MAX == LZO_0xffffL)
+#    define LZO_OS_DOS16        1
+#    define LZO_INFO_OS         "dos16"
+#  elif defined(__NT__) && (__WATCOMC__ < 1100)
+#    define LZO_OS_WIN32        1
+#    define LZO_INFO_OS         "win32"
+#  elif defined(__linux__) || defined(__LINUX__)
+#    define LZO_OS_POSIX        1
+#    define LZO_INFO_OS         "posix"
+#  else
+#    error "please specify a target using the -bt compiler option"
+#  endif
+#elif defined(__palmos__)
+#  define LZO_OS_PALMOS         1
+#  define LZO_INFO_OS           "palmos"
+#elif defined(__TOS__) || defined(__atarist__)
+#  define LZO_OS_TOS            1
+#  define LZO_INFO_OS           "tos"
+#elif defined(macintosh) && !defined(__ppc__)
+#  define LZO_OS_MACCLASSIC     1
+#  define LZO_INFO_OS           "macclassic"
+#elif defined(__VMS)
+#  define LZO_OS_VMS            1
+#  define LZO_INFO_OS           "vms"
+#elif ((defined(__mips__) && defined(__R5900__)) || defined(__MIPS_PSX2__))
+#  define LZO_OS_CONSOLE        1
+#  define LZO_OS_CONSOLE_PS2    1
+#  define LZO_INFO_OS           "console"
+#  define LZO_INFO_OS_CONSOLE   "ps2"
+#elif (defined(__mips__) && defined(__psp__))
+#  define LZO_OS_CONSOLE        1
+#  define LZO_OS_CONSOLE_PSP    1
+#  define LZO_INFO_OS           "console"
+#  define LZO_INFO_OS_CONSOLE   "psp"
+#else
+#  define LZO_OS_POSIX          1
+#  define LZO_INFO_OS           "posix"
+#endif
+#if (LZO_OS_POSIX)
+#  if defined(_AIX) || defined(__AIX__) || defined(__aix__)
+#    define LZO_OS_POSIX_AIX        1
+#    define LZO_INFO_OS_POSIX       "aix"
+#  elif defined(__FreeBSD__)
+#    define LZO_OS_POSIX_FREEBSD    1
+#    define LZO_INFO_OS_POSIX       "freebsd"
+#  elif defined(__hpux__) || defined(__hpux)
+#    define LZO_OS_POSIX_HPUX       1
+#    define LZO_INFO_OS_POSIX       "hpux"
+#  elif defined(__INTERIX)
+#    define LZO_OS_POSIX_INTERIX    1
+#    define LZO_INFO_OS_POSIX       "interix"
+#  elif defined(__IRIX__) || defined(__irix__)
+#    define LZO_OS_POSIX_IRIX       1
+#    define LZO_INFO_OS_POSIX       "irix"
+#  elif defined(__linux__) || defined(__linux) || defined(__LINUX__)
+#    define LZO_OS_POSIX_LINUX      1
+#    define LZO_INFO_OS_POSIX       "linux"
+#  elif defined(__APPLE__) || defined(__MACOS__)
+#    define LZO_OS_POSIX_MACOSX     1
+#    define LZO_INFO_OS_POSIX       "macosx"
+#  elif defined(__minix__) || defined(__minix)
+#    define LZO_OS_POSIX_MINIX      1
+#    define LZO_INFO_OS_POSIX       "minix"
+#  elif defined(__NetBSD__)
+#    define LZO_OS_POSIX_NETBSD     1
+#    define LZO_INFO_OS_POSIX       "netbsd"
+#  elif defined(__OpenBSD__)
+#    define LZO_OS_POSIX_OPENBSD    1
+#    define LZO_INFO_OS_POSIX       "openbsd"
+#  elif defined(__osf__)
+#    define LZO_OS_POSIX_OSF        1
+#    define LZO_INFO_OS_POSIX       "osf"
+#  elif defined(__solaris__) || defined(__sun)
+#    if defined(__SVR4) || defined(__svr4__)
+#      define LZO_OS_POSIX_SOLARIS  1
+#      define LZO_INFO_OS_POSIX     "solaris"
+#    else
+#      define LZO_OS_POSIX_SUNOS    1
+#      define LZO_INFO_OS_POSIX     "sunos"
+#    endif
+#  elif defined(__ultrix__) || defined(__ultrix)
+#    define LZO_OS_POSIX_ULTRIX     1
+#    define LZO_INFO_OS_POSIX       "ultrix"
+#  elif defined(_UNICOS)
+#    define LZO_OS_POSIX_UNICOS     1
+#    define LZO_INFO_OS_POSIX       "unicos"
+#  else
+#    define LZO_OS_POSIX_UNKNOWN    1
+#    define LZO_INFO_OS_POSIX       "unknown"
+#  endif
+#endif
+#endif
+#if (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16)
+#  if (UINT_MAX != LZO_0xffffL)
+#    error "this should not happen"
+#  endif
+#  if (ULONG_MAX != LZO_0xffffffffL)
+#    error "this should not happen"
+#  endif
+#endif
+#if (LZO_OS_DOS32 || LZO_OS_OS2 || LZO_OS_WIN32 || LZO_OS_WIN64)
+#  if (UINT_MAX != LZO_0xffffffffL)
+#    error "this should not happen"
+#  endif
+#  if (ULONG_MAX != LZO_0xffffffffL)
+#    error "this should not happen"
+#  endif
+#endif
+#if defined(CIL) && defined(_GNUCC) && defined(__GNUC__)
+#  define LZO_CC_CILLY          1
+#  define LZO_INFO_CC           "Cilly"
+#  if defined(__CILLY__)
+#    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(__CILLY__)
+#  else
+#    define LZO_INFO_CCVER      "unknown"
+#  endif
+#elif 0 && defined(SDCC) && defined(__VERSION__) && !defined(__GNUC__)
+#  define LZO_CC_SDCC           1
+#  define LZO_INFO_CC           "sdcc"
+#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(SDCC)
+#elif defined(__PATHSCALE__) && defined(__PATHCC_PATCHLEVEL__)
+#  define LZO_CC_PATHSCALE      (__PATHCC__ * 0x10000L + __PATHCC_MINOR__ * 0x100 + __PATHCC_PATCHLEVEL__)
+#  define LZO_INFO_CC           "Pathscale C"
+#  define LZO_INFO_CCVER        __PATHSCALE__
+#elif defined(__INTEL_COMPILER)
+#  define LZO_CC_INTELC         1
+#  define LZO_INFO_CC           "Intel C"
+#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__INTEL_COMPILER)
+#  if defined(_WIN32) || defined(_WIN64)
+#    define LZO_CC_SYNTAX_MSC 1
+#  else
+#    define LZO_CC_SYNTAX_GNUC 1
+#  endif
+#elif defined(__POCC__) && defined(_WIN32)
+#  define LZO_CC_PELLESC        1
+#  define LZO_INFO_CC           "Pelles C"
+#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__POCC__)
+#elif defined(__clang__) && defined(__llvm__) && defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__)
+#  if defined(__GNUC_PATCHLEVEL__)
+#    define LZO_CC_CLANG_GNUC   (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__)
+#  else
+#    define LZO_CC_CLANG_GNUC   (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100)
+#  endif
+#  if defined(__clang_major__) && defined(__clang_minor__) && defined(__clang_patchlevel__)
+#    define LZO_CC_CLANG_CLANG  (__clang_major__ * 0x10000L + __clang_minor__ * 0x100 + __clang_patchlevel__)
+#  else
+#    define LZO_CC_CLANG_CLANG  0x010000L
+#  endif
+#  define LZO_CC_CLANG          LZO_CC_CLANG_GNUC
+#  define LZO_INFO_CC           "clang"
+#  define LZO_INFO_CCVER        __VERSION__
+#elif defined(__llvm__) && defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__)
+#  if defined(__GNUC_PATCHLEVEL__)
+#    define LZO_CC_LLVM_GNUC    (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__)
+#  else
+#    define LZO_CC_LLVM_GNUC    (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100)
+#  endif
+#  define LZO_CC_LLVM           LZO_CC_LLVM_GNUC
+#  define LZO_INFO_CC           "llvm-gcc"
+#  define LZO_INFO_CCVER        __VERSION__
+#elif defined(__GNUC__) && defined(__VERSION__)
+#  if defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)
+#    define LZO_CC_GNUC         (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__)
+#  elif defined(__GNUC_MINOR__)
+#    define LZO_CC_GNUC         (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100)
+#  else
+#    define LZO_CC_GNUC         (__GNUC__ * 0x10000L)
+#  endif
+#  define LZO_INFO_CC           "gcc"
+#  define LZO_INFO_CCVER        __VERSION__
+#elif defined(__ACK__) && defined(_ACK)
+#  define LZO_CC_ACK            1
+#  define LZO_INFO_CC           "Amsterdam Compiler Kit C"
+#  define LZO_INFO_CCVER        "unknown"
+#elif defined(__AZTEC_C__)
+#  define LZO_CC_AZTECC         1
+#  define LZO_INFO_CC           "Aztec C"
+#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__AZTEC_C__)
+#elif defined(__CODEGEARC__)
+#  define LZO_CC_CODEGEARC      1
+#  define LZO_INFO_CC           "CodeGear C"
+#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__CODEGEARC__)
+#elif defined(__BORLANDC__)
+#  define LZO_CC_BORLANDC       1
+#  define LZO_INFO_CC           "Borland C"
+#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__BORLANDC__)
+#elif defined(_CRAYC) && defined(_RELEASE)
+#  define LZO_CC_CRAYC          1
+#  define LZO_INFO_CC           "Cray C"
+#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(_RELEASE)
+#elif defined(__DMC__) && defined(__SC__)
+#  define LZO_CC_DMC            1
+#  define LZO_INFO_CC           "Digital Mars C"
+#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__DMC__)
+#elif defined(__DECC)
+#  define LZO_CC_DECC           1
+#  define LZO_INFO_CC           "DEC C"
+#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__DECC)
+#elif defined(__HIGHC__)
+#  define LZO_CC_HIGHC          1
+#  define LZO_INFO_CC           "MetaWare High C"
+#  define LZO_INFO_CCVER        "unknown"
+#elif defined(__IAR_SYSTEMS_ICC__)
+#  define LZO_CC_IARC           1
+#  define LZO_INFO_CC           "IAR C"
+#  if defined(__VER__)
+#    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(__VER__)
+#  else
+#    define LZO_INFO_CCVER      "unknown"
+#  endif
+#elif defined(__IBMC__)
+#  define LZO_CC_IBMC           1
+#  define LZO_INFO_CC           "IBM C"
+#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__IBMC__)
+#elif defined(__KEIL__) && defined(__C166__)
+#  define LZO_CC_KEILC          1
+#  define LZO_INFO_CC           "Keil C"
+#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__C166__)
+#elif defined(__LCC__) && defined(_WIN32) && defined(__LCCOPTIMLEVEL)
+#  define LZO_CC_LCCWIN32       1
+#  define LZO_INFO_CC           "lcc-win32"
+#  define LZO_INFO_CCVER        "unknown"
+#elif defined(__LCC__)
+#  define LZO_CC_LCC            1
+#  define LZO_INFO_CC           "lcc"
+#  if defined(__LCC_VERSION__)
+#    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(__LCC_VERSION__)
+#  else
+#    define LZO_INFO_CCVER      "unknown"
+#  endif
+#elif defined(_MSC_VER)
+#  define LZO_CC_MSC            1
+#  define LZO_INFO_CC           "Microsoft C"
+#  if defined(_MSC_FULL_VER)
+#    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(_MSC_VER) "." LZO_PP_MACRO_EXPAND(_MSC_FULL_VER)
+#  else
+#    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(_MSC_VER)
+#  endif
+#elif defined(__MWERKS__)
+#  define LZO_CC_MWERKS         1
+#  define LZO_INFO_CC           "Metrowerks C"
+#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__MWERKS__)
+#elif (defined(__NDPC__) || defined(__NDPX__)) && defined(__i386)
+#  define LZO_CC_NDPC           1
+#  define LZO_INFO_CC           "Microway NDP C"
+#  define LZO_INFO_CCVER        "unknown"
+#elif defined(__PACIFIC__)
+#  define LZO_CC_PACIFICC       1
+#  define LZO_INFO_CC           "Pacific C"
+#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__PACIFIC__)
+#elif defined(__PGI) && (defined(__linux__) || defined(__WIN32__))
+#  define LZO_CC_PGI            1
+#  define LZO_INFO_CC           "Portland Group PGI C"
+#  define LZO_INFO_CCVER        "unknown"
+#elif defined(__PUREC__) && defined(__TOS__)
+#  define LZO_CC_PUREC          1
+#  define LZO_INFO_CC           "Pure C"
+#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__PUREC__)
+#elif defined(__SC__) && defined(__ZTC__)
+#  define LZO_CC_SYMANTECC      1
+#  define LZO_INFO_CC           "Symantec C"
+#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__SC__)
+#elif defined(__SUNPRO_C)
+#  define LZO_INFO_CC           "SunPro C"
+#  if ((__SUNPRO_C)+0 > 0)
+#    define LZO_CC_SUNPROC      __SUNPRO_C
+#    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(__SUNPRO_C)
+#  else
+#    define LZO_CC_SUNPROC      1
+#    define LZO_INFO_CCVER      "unknown"
+#  endif
+#elif defined(__SUNPRO_CC)
+#  define LZO_INFO_CC           "SunPro C"
+#  if ((__SUNPRO_CC)+0 > 0)
+#    define LZO_CC_SUNPROC      __SUNPRO_CC
+#    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(__SUNPRO_CC)
+#  else
+#    define LZO_CC_SUNPROC      1
+#    define LZO_INFO_CCVER      "unknown"
+#  endif
+#elif defined(__TINYC__)
+#  define LZO_CC_TINYC          1
+#  define LZO_INFO_CC           "Tiny C"
+#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__TINYC__)
+#elif defined(__TSC__)
+#  define LZO_CC_TOPSPEEDC      1
+#  define LZO_INFO_CC           "TopSpeed C"
+#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__TSC__)
+#elif defined(__WATCOMC__)
+#  define LZO_CC_WATCOMC        1
+#  define LZO_INFO_CC           "Watcom C"
+#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__WATCOMC__)
+#elif defined(__TURBOC__)
+#  define LZO_CC_TURBOC         1
+#  define LZO_INFO_CC           "Turbo C"
+#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__TURBOC__)
+#elif defined(__ZTC__)
+#  define LZO_CC_ZORTECHC       1
+#  define LZO_INFO_CC           "Zortech C"
+#  if (__ZTC__ == 0x310)
+#    define LZO_INFO_CCVER      "0x310"
+#  else
+#    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(__ZTC__)
+#  endif
+#else
+#  define LZO_CC_UNKNOWN        1
+#  define LZO_INFO_CC           "unknown"
+#  define LZO_INFO_CCVER        "unknown"
+#endif
+#if 0 && (LZO_CC_MSC && (_MSC_VER >= 1200)) && !defined(_MSC_FULL_VER)
+#  error "LZO_CC_MSC: _MSC_FULL_VER is not defined"
+#endif
+#if !defined(__LZO_ARCH_OVERRIDE) && !(LZO_ARCH_GENERIC) && defined(_CRAY)
+#  if (UINT_MAX > LZO_0xffffffffL) && defined(_CRAY)
+#    if defined(_CRAYMPP) || defined(_CRAYT3D) || defined(_CRAYT3E)
+#      define LZO_ARCH_CRAY_MPP     1
+#    elif defined(_CRAY1)
+#      define LZO_ARCH_CRAY_PVP     1
+#    endif
+#  endif
+#endif
+#if !defined(__LZO_ARCH_OVERRIDE)
+#if (LZO_ARCH_GENERIC)
+#  define LZO_INFO_ARCH             "generic"
+#elif (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16)
+#  define LZO_ARCH_I086             1
+#  define LZO_ARCH_IA16             1
+#  define LZO_INFO_ARCH             "i086"
+#elif defined(__alpha__) || defined(__alpha) || defined(_M_ALPHA)
+#  define LZO_ARCH_ALPHA            1
+#  define LZO_INFO_ARCH             "alpha"
+#elif (LZO_ARCH_CRAY_MPP) && (defined(_CRAYT3D) || defined(_CRAYT3E))
+#  define LZO_ARCH_ALPHA            1
+#  define LZO_INFO_ARCH             "alpha"
+#elif defined(__amd64__) || defined(__x86_64__) || defined(_M_AMD64)
+#  define LZO_ARCH_AMD64            1
+#  define LZO_INFO_ARCH             "amd64"
+#elif defined(__thumb__) || (defined(_M_ARM) && defined(_M_THUMB))
+#  define LZO_ARCH_ARM              1
+#  define LZO_ARCH_ARM_THUMB        1
+#  define LZO_INFO_ARCH             "arm_thumb"
+#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCARM__)
+#  define LZO_ARCH_ARM              1
+#  if defined(__CPU_MODE__) && ((__CPU_MODE__)+0 == 1)
+#    define LZO_ARCH_ARM_THUMB      1
+#    define LZO_INFO_ARCH           "arm_thumb"
+#  elif defined(__CPU_MODE__) && ((__CPU_MODE__)+0 == 2)
+#    define LZO_INFO_ARCH           "arm"
+#  else
+#    define LZO_INFO_ARCH           "arm"
+#  endif
+#elif defined(__arm__) || defined(_M_ARM)
+#  define LZO_ARCH_ARM              1
+#  define LZO_INFO_ARCH             "arm"
+#elif (UINT_MAX <= LZO_0xffffL) && defined(__AVR__)
+#  define LZO_ARCH_AVR              1
+#  define LZO_INFO_ARCH             "avr"
+#elif defined(__avr32__) || defined(__AVR32__)
+#  define LZO_ARCH_AVR32            1
+#  define LZO_INFO_ARCH             "avr32"
+#elif defined(__bfin__)
+#  define LZO_ARCH_BLACKFIN         1
+#  define LZO_INFO_ARCH             "blackfin"
+#elif (UINT_MAX == LZO_0xffffL) && defined(__C166__)
+#  define LZO_ARCH_C166             1
+#  define LZO_INFO_ARCH             "c166"
+#elif defined(__cris__)
+#  define LZO_ARCH_CRIS             1
+#  define LZO_INFO_ARCH             "cris"
+#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCEZ80__)
+#  define LZO_ARCH_EZ80             1
+#  define LZO_INFO_ARCH             "ez80"
+#elif defined(__H8300__) || defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__)
+#  define LZO_ARCH_H8300            1
+#  define LZO_INFO_ARCH             "h8300"
+#elif defined(__hppa__) || defined(__hppa)
+#  define LZO_ARCH_HPPA             1
+#  define LZO_INFO_ARCH             "hppa"
+#elif defined(__386__) || defined(__i386__) || defined(__i386) || defined(_M_IX86) || defined(_M_I386)
+#  define LZO_ARCH_I386             1
+#  define LZO_ARCH_IA32             1
+#  define LZO_INFO_ARCH             "i386"
+#elif (LZO_CC_ZORTECHC && defined(__I86__))
+#  define LZO_ARCH_I386             1
+#  define LZO_ARCH_IA32             1
+#  define LZO_INFO_ARCH             "i386"
+#elif (LZO_OS_DOS32 && LZO_CC_HIGHC) && defined(_I386)
+#  define LZO_ARCH_I386             1
+#  define LZO_ARCH_IA32             1
+#  define LZO_INFO_ARCH             "i386"
+#elif defined(__ia64__) || defined(__ia64) || defined(_M_IA64)
+#  define LZO_ARCH_IA64             1
+#  define LZO_INFO_ARCH             "ia64"
+#elif (UINT_MAX == LZO_0xffffL) && defined(__m32c__)
+#  define LZO_ARCH_M16C             1
+#  define LZO_INFO_ARCH             "m16c"
+#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCM16C__)
+#  define LZO_ARCH_M16C             1
+#  define LZO_INFO_ARCH             "m16c"
+#elif defined(__m32r__)
+#  define LZO_ARCH_M32R             1
+#  define LZO_INFO_ARCH             "m32r"
+#elif (LZO_OS_TOS) || defined(__m68k__) || defined(__m68000__) || defined(__mc68000__) || defined(__mc68020__) || defined(_M_M68K)
+#  define LZO_ARCH_M68K             1
+#  define LZO_INFO_ARCH             "m68k"
+#elif (UINT_MAX == LZO_0xffffL) && defined(__C251__)
+#  define LZO_ARCH_MCS251           1
+#  define LZO_INFO_ARCH             "mcs251"
+#elif (UINT_MAX == LZO_0xffffL) && defined(__C51__)
+#  define LZO_ARCH_MCS51            1
+#  define LZO_INFO_ARCH             "mcs51"
+#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICC8051__)
+#  define LZO_ARCH_MCS51            1
+#  define LZO_INFO_ARCH             "mcs51"
+#elif defined(__mips__) || defined(__mips) || defined(_MIPS_ARCH) || defined(_M_MRX000)
+#  define LZO_ARCH_MIPS             1
+#  define LZO_INFO_ARCH             "mips"
+#elif (UINT_MAX == LZO_0xffffL) && defined(__MSP430__)
+#  define LZO_ARCH_MSP430           1
+#  define LZO_INFO_ARCH             "msp430"
+#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICC430__)
+#  define LZO_ARCH_MSP430           1
+#  define LZO_INFO_ARCH             "msp430"
+#elif defined(__powerpc__) || defined(__powerpc) || defined(__ppc__) || defined(__PPC__) || defined(_M_PPC) || defined(_ARCH_PPC) || defined(_ARCH_PWR)
+#  define LZO_ARCH_POWERPC          1
+#  define LZO_INFO_ARCH             "powerpc"
+#elif defined(__s390__) || defined(__s390) || defined(__s390x__) || defined(__s390x)
+#  define LZO_ARCH_S390             1
+#  define LZO_INFO_ARCH             "s390"
+#elif defined(__sh__) || defined(_M_SH)
+#  define LZO_ARCH_SH               1
+#  define LZO_INFO_ARCH             "sh"
+#elif defined(__sparc__) || defined(__sparc) || defined(__sparcv8)
+#  define LZO_ARCH_SPARC            1
+#  define LZO_INFO_ARCH             "sparc"
+#elif defined(__SPU__)
+#  define LZO_ARCH_SPU              1
+#  define LZO_INFO_ARCH             "spu"
+#elif (UINT_MAX == LZO_0xffffL) && defined(__z80)
+#  define LZO_ARCH_Z80              1
+#  define LZO_INFO_ARCH             "z80"
+#elif (LZO_ARCH_CRAY_PVP)
+#  if defined(_CRAYSV1)
+#    define LZO_ARCH_CRAY_SV1       1
+#    define LZO_INFO_ARCH           "cray_sv1"
+#  elif (_ADDR64)
+#    define LZO_ARCH_CRAY_T90       1
+#    define LZO_INFO_ARCH           "cray_t90"
+#  elif (_ADDR32)
+#    define LZO_ARCH_CRAY_YMP       1
+#    define LZO_INFO_ARCH           "cray_ymp"
+#  else
+#    define LZO_ARCH_CRAY_XMP       1
+#    define LZO_INFO_ARCH           "cray_xmp"
+#  endif
+#else
+#  define LZO_ARCH_UNKNOWN          1
+#  define LZO_INFO_ARCH             "unknown"
+#endif
+#endif
+#if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_DOS32 || LZO_OS_OS2)
+#  error "FIXME - missing define for CPU architecture"
+#endif
+#if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_WIN32)
+#  error "FIXME - missing WIN32 define for CPU architecture"
+#endif
+#if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_WIN64)
+#  error "FIXME - missing WIN64 define for CPU architecture"
+#endif
+#if (LZO_OS_OS216 || LZO_OS_WIN16)
+#  define LZO_ARCH_I086PM           1
+#  define LZO_ARCH_IA16PM           1
+#elif 1 && (LZO_OS_DOS16 && defined(BLX286))
+#  define LZO_ARCH_I086PM           1
+#  define LZO_ARCH_IA16PM           1
+#elif 1 && (LZO_OS_DOS16 && defined(DOSX286))
+#  define LZO_ARCH_I086PM           1
+#  define LZO_ARCH_IA16PM           1
+#elif 1 && (LZO_OS_DOS16 && LZO_CC_BORLANDC && defined(__DPMI16__))
+#  define LZO_ARCH_I086PM           1
+#  define LZO_ARCH_IA16PM           1
+#endif
+#if (LZO_ARCH_ARM_THUMB) && !(LZO_ARCH_ARM)
+#  error "this should not happen"
+#endif
+#if (LZO_ARCH_I086PM) && !(LZO_ARCH_I086)
+#  error "this should not happen"
+#endif
+#if (LZO_ARCH_I086)
+#  if (UINT_MAX != LZO_0xffffL)
+#    error "this should not happen"
+#  endif
+#  if (ULONG_MAX != LZO_0xffffffffL)
+#    error "this should not happen"
+#  endif
+#endif
+#if (LZO_ARCH_I386)
+#  if (UINT_MAX != LZO_0xffffL) && defined(__i386_int16__)
+#    error "this should not happen"
+#  endif
+#  if (UINT_MAX != LZO_0xffffffffL) && !defined(__i386_int16__)
+#    error "this should not happen"
+#  endif
+#  if (ULONG_MAX != LZO_0xffffffffL)
+#    error "this should not happen"
+#  endif
+#endif
+#if !defined(__LZO_MM_OVERRIDE)
+#if (LZO_ARCH_I086)
+#if (UINT_MAX != LZO_0xffffL)
+#  error "this should not happen"
+#endif
+#if defined(__TINY__) || defined(M_I86TM) || defined(_M_I86TM)
+#  define LZO_MM_TINY           1
+#elif defined(__HUGE__) || defined(_HUGE_) || defined(M_I86HM) || defined(_M_I86HM)
+#  define LZO_MM_HUGE           1
+#elif defined(__SMALL__) || defined(M_I86SM) || defined(_M_I86SM) || defined(SMALL_MODEL)
+#  define LZO_MM_SMALL          1
+#elif defined(__MEDIUM__) || defined(M_I86MM) || defined(_M_I86MM)
+#  define LZO_MM_MEDIUM         1
+#elif defined(__COMPACT__) || defined(M_I86CM) || defined(_M_I86CM)
+#  define LZO_MM_COMPACT        1
+#elif defined(__LARGE__) || defined(M_I86LM) || defined(_M_I86LM) || defined(LARGE_MODEL)
+#  define LZO_MM_LARGE          1
+#elif (LZO_CC_AZTECC)
+#  if defined(_LARGE_CODE) && defined(_LARGE_DATA)
+#    define LZO_MM_LARGE        1
+#  elif defined(_LARGE_CODE)
+#    define LZO_MM_MEDIUM       1
+#  elif defined(_LARGE_DATA)
+#    define LZO_MM_COMPACT      1
+#  else
+#    define LZO_MM_SMALL        1
+#  endif
+#elif (LZO_CC_ZORTECHC && defined(__VCM__))
+#  define LZO_MM_LARGE          1
+#else
+#  error "unknown memory model"
+#endif
+#if (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16)
+#define LZO_HAVE_MM_HUGE_PTR        1
+#define LZO_HAVE_MM_HUGE_ARRAY      1
+#if (LZO_MM_TINY)
+#  undef LZO_HAVE_MM_HUGE_ARRAY
+#endif
+#if (LZO_CC_AZTECC || LZO_CC_PACIFICC || LZO_CC_ZORTECHC)
+#  undef LZO_HAVE_MM_HUGE_PTR
+#  undef LZO_HAVE_MM_HUGE_ARRAY
+#elif (LZO_CC_DMC || LZO_CC_SYMANTECC)
+#  undef LZO_HAVE_MM_HUGE_ARRAY
+#elif (LZO_CC_MSC && defined(_QC))
+#  undef LZO_HAVE_MM_HUGE_ARRAY
+#  if (_MSC_VER < 600)
+#    undef LZO_HAVE_MM_HUGE_PTR
+#  endif
+#elif (LZO_CC_TURBOC && (__TURBOC__ < 0x0295))
+#  undef LZO_HAVE_MM_HUGE_ARRAY
+#endif
+#if (LZO_ARCH_I086PM) && !(LZO_HAVE_MM_HUGE_PTR)
+#  if (LZO_OS_DOS16)
+#    error "this should not happen"
+#  elif (LZO_CC_ZORTECHC)
+#  else
+#    error "this should not happen"
+#  endif
+#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+#if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0200))
+   extern void __near __cdecl _AHSHIFT(void);
+#  define LZO_MM_AHSHIFT      ((unsigned) _AHSHIFT)
+#elif (LZO_CC_DMC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC)
+   extern void __near __cdecl _AHSHIFT(void);
+#  define LZO_MM_AHSHIFT      ((unsigned) _AHSHIFT)
+#elif (LZO_CC_MSC || LZO_CC_TOPSPEEDC)
+   extern void __near __cdecl _AHSHIFT(void);
+#  define LZO_MM_AHSHIFT      ((unsigned) _AHSHIFT)
+#elif (LZO_CC_TURBOC && (__TURBOC__ >= 0x0295))
+   extern void __near __cdecl _AHSHIFT(void);
+#  define LZO_MM_AHSHIFT      ((unsigned) _AHSHIFT)
+#elif ((LZO_CC_AZTECC || LZO_CC_PACIFICC || LZO_CC_TURBOC) && LZO_OS_DOS16)
+#  define LZO_MM_AHSHIFT      12
+#elif (LZO_CC_WATCOMC)
+   extern unsigned char _HShift;
+#  define LZO_MM_AHSHIFT      ((unsigned) _HShift)
+#else
+#  error "FIXME - implement LZO_MM_AHSHIFT"
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+#elif (LZO_ARCH_C166)
+#if !defined(__MODEL__)
+#  error "FIXME - C166 __MODEL__"
+#elif ((__MODEL__) == 0)
+#  define LZO_MM_SMALL          1
+#elif ((__MODEL__) == 1)
+#  define LZO_MM_SMALL          1
+#elif ((__MODEL__) == 2)
+#  define LZO_MM_LARGE          1
+#elif ((__MODEL__) == 3)
+#  define LZO_MM_TINY           1
+#elif ((__MODEL__) == 4)
+#  define LZO_MM_XTINY          1
+#elif ((__MODEL__) == 5)
+#  define LZO_MM_XSMALL         1
+#else
+#  error "FIXME - C166 __MODEL__"
+#endif
+#elif (LZO_ARCH_MCS251)
+#if !defined(__MODEL__)
+#  error "FIXME - MCS251 __MODEL__"
+#elif ((__MODEL__) == 0)
+#  define LZO_MM_SMALL          1
+#elif ((__MODEL__) == 2)
+#  define LZO_MM_LARGE          1
+#elif ((__MODEL__) == 3)
+#  define LZO_MM_TINY           1
+#elif ((__MODEL__) == 4)
+#  define LZO_MM_XTINY          1
+#elif ((__MODEL__) == 5)
+#  define LZO_MM_XSMALL         1
+#else
+#  error "FIXME - MCS251 __MODEL__"
+#endif
+#elif (LZO_ARCH_MCS51)
+#if !defined(__MODEL__)
+#  error "FIXME - MCS51 __MODEL__"
+#elif ((__MODEL__) == 1)
+#  define LZO_MM_SMALL          1
+#elif ((__MODEL__) == 2)
+#  define LZO_MM_LARGE          1
+#elif ((__MODEL__) == 3)
+#  define LZO_MM_TINY           1
+#elif ((__MODEL__) == 4)
+#  define LZO_MM_XTINY          1
+#elif ((__MODEL__) == 5)
+#  define LZO_MM_XSMALL         1
+#else
+#  error "FIXME - MCS51 __MODEL__"
+#endif
+#elif (LZO_ARCH_CRAY_PVP)
+#  define LZO_MM_PVP            1
+#else
+#  define LZO_MM_FLAT           1
+#endif
+#if (LZO_MM_COMPACT)
+#  define LZO_INFO_MM           "compact"
+#elif (LZO_MM_FLAT)
+#  define LZO_INFO_MM           "flat"
+#elif (LZO_MM_HUGE)
+#  define LZO_INFO_MM           "huge"
+#elif (LZO_MM_LARGE)
+#  define LZO_INFO_MM           "large"
+#elif (LZO_MM_MEDIUM)
+#  define LZO_INFO_MM           "medium"
+#elif (LZO_MM_PVP)
+#  define LZO_INFO_MM           "pvp"
+#elif (LZO_MM_SMALL)
+#  define LZO_INFO_MM           "small"
+#elif (LZO_MM_TINY)
+#  define LZO_INFO_MM           "tiny"
+#else
+#  error "unknown memory model"
+#endif
+#endif
+#if defined(SIZEOF_SHORT)
+#  define LZO_SIZEOF_SHORT          (SIZEOF_SHORT)
+#endif
+#if defined(SIZEOF_INT)
+#  define LZO_SIZEOF_INT            (SIZEOF_INT)
+#endif
+#if defined(SIZEOF_LONG)
+#  define LZO_SIZEOF_LONG           (SIZEOF_LONG)
+#endif
+#if defined(SIZEOF_LONG_LONG)
+#  define LZO_SIZEOF_LONG_LONG      (SIZEOF_LONG_LONG)
+#endif
+#if defined(SIZEOF___INT16)
+#  define LZO_SIZEOF___INT16        (SIZEOF___INT16)
+#endif
+#if defined(SIZEOF___INT32)
+#  define LZO_SIZEOF___INT32        (SIZEOF___INT32)
+#endif
+#if defined(SIZEOF___INT64)
+#  define LZO_SIZEOF___INT64        (SIZEOF___INT64)
+#endif
+#if defined(SIZEOF_VOID_P)
+#  define LZO_SIZEOF_VOID_P         (SIZEOF_VOID_P)
+#endif
+#if defined(SIZEOF_SIZE_T)
+#  define LZO_SIZEOF_SIZE_T         (SIZEOF_SIZE_T)
+#endif
+#if defined(SIZEOF_PTRDIFF_T)
+#  define LZO_SIZEOF_PTRDIFF_T      (SIZEOF_PTRDIFF_T)
+#endif
+#define __LZO_LSR(x,b)    (((x)+0ul) >> (b))
+#if !defined(LZO_SIZEOF_SHORT)
+#  if (LZO_ARCH_CRAY_PVP)
+#    define LZO_SIZEOF_SHORT        8
+#  elif (USHRT_MAX == LZO_0xffffL)
+#    define LZO_SIZEOF_SHORT        2
+#  elif (__LZO_LSR(USHRT_MAX,7) == 1)
+#    define LZO_SIZEOF_SHORT        1
+#  elif (__LZO_LSR(USHRT_MAX,15) == 1)
+#    define LZO_SIZEOF_SHORT        2
+#  elif (__LZO_LSR(USHRT_MAX,31) == 1)
+#    define LZO_SIZEOF_SHORT        4
+#  elif (__LZO_LSR(USHRT_MAX,63) == 1)
+#    define LZO_SIZEOF_SHORT        8
+#  elif (__LZO_LSR(USHRT_MAX,127) == 1)
+#    define LZO_SIZEOF_SHORT        16
+#  else
+#    error "LZO_SIZEOF_SHORT"
+#  endif
+#endif
+#if !defined(LZO_SIZEOF_INT)
+#  if (LZO_ARCH_CRAY_PVP)
+#    define LZO_SIZEOF_INT          8
+#  elif (UINT_MAX == LZO_0xffffL)
+#    define LZO_SIZEOF_INT          2
+#  elif (UINT_MAX == LZO_0xffffffffL)
+#    define LZO_SIZEOF_INT          4
+#  elif (__LZO_LSR(UINT_MAX,7) == 1)
+#    define LZO_SIZEOF_INT          1
+#  elif (__LZO_LSR(UINT_MAX,15) == 1)
+#    define LZO_SIZEOF_INT          2
+#  elif (__LZO_LSR(UINT_MAX,31) == 1)
+#    define LZO_SIZEOF_INT          4
+#  elif (__LZO_LSR(UINT_MAX,63) == 1)
+#    define LZO_SIZEOF_INT          8
+#  elif (__LZO_LSR(UINT_MAX,127) == 1)
+#    define LZO_SIZEOF_INT          16
+#  else
+#    error "LZO_SIZEOF_INT"
+#  endif
+#endif
+#if !defined(LZO_SIZEOF_LONG)
+#  if (ULONG_MAX == LZO_0xffffffffL)
+#    define LZO_SIZEOF_LONG         4
+#  elif (__LZO_LSR(ULONG_MAX,7) == 1)
+#    define LZO_SIZEOF_LONG         1
+#  elif (__LZO_LSR(ULONG_MAX,15) == 1)
+#    define LZO_SIZEOF_LONG         2
+#  elif (__LZO_LSR(ULONG_MAX,31) == 1)
+#    define LZO_SIZEOF_LONG         4
+#  elif (__LZO_LSR(ULONG_MAX,63) == 1)
+#    define LZO_SIZEOF_LONG         8
+#  elif (__LZO_LSR(ULONG_MAX,127) == 1)
+#    define LZO_SIZEOF_LONG         16
+#  else
+#    error "LZO_SIZEOF_LONG"
+#  endif
+#endif
+#if !defined(LZO_SIZEOF_LONG_LONG) && !defined(LZO_SIZEOF___INT64)
+#if (LZO_SIZEOF_LONG > 0 && LZO_SIZEOF_LONG < 8)
+#  if defined(__LONG_MAX__) && defined(__LONG_LONG_MAX__)
+#    if (LZO_CC_GNUC >= 0x030300ul)
+#      if ((__LONG_MAX__)+0 == (__LONG_LONG_MAX__)+0)
+#        define LZO_SIZEOF_LONG_LONG      LZO_SIZEOF_LONG
+#      elif (__LZO_LSR(__LONG_LONG_MAX__,30) == 1)
+#        define LZO_SIZEOF_LONG_LONG      4
+#      endif
+#    endif
+#  endif
+#endif
+#endif
+#if !defined(LZO_SIZEOF_LONG_LONG) && !defined(LZO_SIZEOF___INT64)
+#if (LZO_SIZEOF_LONG > 0 && LZO_SIZEOF_LONG < 8)
+#if (LZO_ARCH_I086 && LZO_CC_DMC)
+#elif (LZO_CC_CILLY) && defined(__GNUC__)
+#  define LZO_SIZEOF_LONG_LONG      8
+#elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#  define LZO_SIZEOF_LONG_LONG      8
+#elif ((LZO_OS_WIN32 || LZO_OS_WIN64 || defined(_WIN32)) && LZO_CC_MSC && (_MSC_VER >= 1400))
+#  define LZO_SIZEOF_LONG_LONG      8
+#elif (LZO_OS_WIN64 || defined(_WIN64))
+#  define LZO_SIZEOF___INT64        8
+#elif (LZO_ARCH_I386 && (LZO_CC_DMC))
+#  define LZO_SIZEOF_LONG_LONG      8
+#elif (LZO_ARCH_I386 && (LZO_CC_SYMANTECC && (__SC__ >= 0x700)))
+#  define LZO_SIZEOF_LONG_LONG      8
+#elif (LZO_ARCH_I386 && (LZO_CC_INTELC && defined(__linux__)))
+#  define LZO_SIZEOF_LONG_LONG      8
+#elif (LZO_ARCH_I386 && (LZO_CC_MWERKS || LZO_CC_PELLESC || LZO_CC_PGI || LZO_CC_SUNPROC))
+#  define LZO_SIZEOF_LONG_LONG      8
+#elif (LZO_ARCH_I386 && (LZO_CC_INTELC || LZO_CC_MSC))
+#  define LZO_SIZEOF___INT64        8
+#elif ((LZO_OS_WIN32 || defined(_WIN32)) && (LZO_CC_MSC))
+#  define LZO_SIZEOF___INT64        8
+#elif (LZO_ARCH_I386 && (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0520)))
+#  define LZO_SIZEOF___INT64        8
+#elif (LZO_ARCH_I386 && (LZO_CC_WATCOMC && (__WATCOMC__ >= 1100)))
+#  define LZO_SIZEOF___INT64        8
+#elif (LZO_CC_WATCOMC && defined(_INTEGRAL_MAX_BITS) && (_INTEGRAL_MAX_BITS == 64))
+#  define LZO_SIZEOF___INT64        8
+#elif (LZO_OS_OS400 || defined(__OS400__)) && defined(__LLP64_IFC__)
+#  define LZO_SIZEOF_LONG_LONG      8
+#elif (defined(__vms) || defined(__VMS)) && (__INITIAL_POINTER_SIZE+0 == 64)
+#  define LZO_SIZEOF_LONG_LONG      8
+#elif (LZO_CC_SDCC) && (LZO_SIZEOF_INT == 2)
+#elif 1 && defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
+#  define LZO_SIZEOF_LONG_LONG      8
+#endif
+#endif
+#endif
+#if defined(__cplusplus) && (LZO_CC_GNUC)
+#  if (LZO_CC_GNUC < 0x020800ul)
+#    undef LZO_SIZEOF_LONG_LONG
+#  endif
+#endif
+#if (LZO_CFG_NO_LONG_LONG) || defined(__NO_LONG_LONG)
+#  undef LZO_SIZEOF_LONG_LONG
+#endif
+#if !defined(LZO_SIZEOF_VOID_P)
+#if (LZO_ARCH_I086)
+#  define __LZO_WORDSIZE            2
+#  if (LZO_MM_TINY || LZO_MM_SMALL || LZO_MM_MEDIUM)
+#    define LZO_SIZEOF_VOID_P       2
+#  elif (LZO_MM_COMPACT || LZO_MM_LARGE || LZO_MM_HUGE)
+#    define LZO_SIZEOF_VOID_P       4
+#  else
+#    error "LZO_MM"
+#  endif
+#elif (LZO_ARCH_AVR || LZO_ARCH_Z80)
+#  define __LZO_WORDSIZE            1
+#  define LZO_SIZEOF_VOID_P         2
+#elif (LZO_ARCH_C166 || LZO_ARCH_MCS51 || LZO_ARCH_MCS251 || LZO_ARCH_MSP430)
+#  define LZO_SIZEOF_VOID_P         2
+#elif (LZO_ARCH_H8300)
+#  if defined(__NORMAL_MODE__)
+#    define __LZO_WORDSIZE          4
+#    define LZO_SIZEOF_VOID_P       2
+#  elif defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__)
+#    define __LZO_WORDSIZE          4
+#    define LZO_SIZEOF_VOID_P       4
+#  else
+#    define __LZO_WORDSIZE          2
+#    define LZO_SIZEOF_VOID_P       2
+#  endif
+#  if (LZO_CC_GNUC && (LZO_CC_GNUC < 0x040000ul)) && (LZO_SIZEOF_INT == 4)
+#    define LZO_SIZEOF_SIZE_T       LZO_SIZEOF_INT
+#    define LZO_SIZEOF_PTRDIFF_T    LZO_SIZEOF_INT
+#  endif
+#elif (LZO_ARCH_M16C)
+#  define __LZO_WORDSIZE            2
+#  if defined(__m32c_cpu__) || defined(__m32cm_cpu__)
+#    define LZO_SIZEOF_VOID_P       4
+#  else
+#    define LZO_SIZEOF_VOID_P       2
+#  endif
+#elif (LZO_SIZEOF_LONG == 8) && ((defined(__mips__) && defined(__R5900__)) || defined(__MIPS_PSX2__))
+#  define __LZO_WORDSIZE            8
+#  define LZO_SIZEOF_VOID_P         4
+#elif defined(__LLP64__) || defined(__LLP64) || defined(_LLP64) || defined(_WIN64)
+#  define __LZO_WORDSIZE            8
+#  define LZO_SIZEOF_VOID_P         8
+#elif (LZO_OS_OS400 || defined(__OS400__)) && defined(__LLP64_IFC__)
+#  define LZO_SIZEOF_VOID_P         LZO_SIZEOF_LONG
+#  define LZO_SIZEOF_SIZE_T         LZO_SIZEOF_LONG
+#  define LZO_SIZEOF_PTRDIFF_T      LZO_SIZEOF_LONG
+#elif (LZO_OS_OS400 || defined(__OS400__))
+#  define __LZO_WORDSIZE            LZO_SIZEOF_LONG
+#  define LZO_SIZEOF_VOID_P         16
+#  define LZO_SIZEOF_SIZE_T         LZO_SIZEOF_LONG
+#  define LZO_SIZEOF_PTRDIFF_T      LZO_SIZEOF_LONG
+#elif (defined(__vms) || defined(__VMS)) && (__INITIAL_POINTER_SIZE+0 == 64)
+#  define LZO_SIZEOF_VOID_P         8
+#  define LZO_SIZEOF_SIZE_T         LZO_SIZEOF_LONG
+#  define LZO_SIZEOF_PTRDIFF_T      LZO_SIZEOF_LONG
+#elif (LZO_ARCH_SPU)
+# if 0
+#  define __LZO_WORDSIZE            16
+# endif
+#  define LZO_SIZEOF_VOID_P         4
+#else
+#  define LZO_SIZEOF_VOID_P         LZO_SIZEOF_LONG
+#endif
+#endif
+#if !defined(LZO_WORDSIZE)
+#  if defined(__LZO_WORDSIZE)
+#    define LZO_WORDSIZE            __LZO_WORDSIZE
+#  else
+#    define LZO_WORDSIZE            LZO_SIZEOF_VOID_P
+#  endif
+#endif
+#if !defined(LZO_SIZEOF_SIZE_T)
+#if (LZO_ARCH_I086 || LZO_ARCH_M16C)
+#  define LZO_SIZEOF_SIZE_T         2
+#else
+#  define LZO_SIZEOF_SIZE_T         LZO_SIZEOF_VOID_P
+#endif
+#endif
+#if !defined(LZO_SIZEOF_PTRDIFF_T)
+#if (LZO_ARCH_I086)
+#  if (LZO_MM_TINY || LZO_MM_SMALL || LZO_MM_MEDIUM || LZO_MM_HUGE)
+#    define LZO_SIZEOF_PTRDIFF_T    LZO_SIZEOF_VOID_P
+#  elif (LZO_MM_COMPACT || LZO_MM_LARGE)
+#    if (LZO_CC_BORLANDC || LZO_CC_TURBOC)
+#      define LZO_SIZEOF_PTRDIFF_T  4
+#    else
+#      define LZO_SIZEOF_PTRDIFF_T  2
+#    endif
+#  else
+#    error "LZO_MM"
+#  endif
+#else
+#  define LZO_SIZEOF_PTRDIFF_T      LZO_SIZEOF_SIZE_T
+#endif
+#endif
+#if (LZO_ABI_NEUTRAL_ENDIAN)
+#  undef LZO_ABI_BIG_ENDIAN
+#  undef LZO_ABI_LITTLE_ENDIAN
+#elif !(LZO_ABI_BIG_ENDIAN) && !(LZO_ABI_LITTLE_ENDIAN)
+#if (LZO_ARCH_ALPHA) && (LZO_ARCH_CRAY_MPP)
+#  define LZO_ABI_BIG_ENDIAN        1
+#elif (LZO_ARCH_IA64) && (LZO_OS_POSIX_LINUX || LZO_OS_WIN64)
+#  define LZO_ABI_LITTLE_ENDIAN     1
+#elif (LZO_ARCH_ALPHA || LZO_ARCH_AMD64 || LZO_ARCH_BLACKFIN || LZO_ARCH_CRIS || LZO_ARCH_I086 || LZO_ARCH_I386 || LZO_ARCH_MSP430)
+#  define LZO_ABI_LITTLE_ENDIAN     1
+#elif (LZO_ARCH_AVR32 || LZO_ARCH_M68K || LZO_ARCH_S390)
+#  define LZO_ABI_BIG_ENDIAN        1
+#elif 1 && defined(__IAR_SYSTEMS_ICC__) && defined(__LITTLE_ENDIAN__)
+#  if (__LITTLE_ENDIAN__ == 1)
+#    define LZO_ABI_LITTLE_ENDIAN   1
+#  else
+#    define LZO_ABI_BIG_ENDIAN      1
+#  endif
+#elif 1 && defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__)
+#  define LZO_ABI_BIG_ENDIAN        1
+#elif 1 && defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__)
+#  define LZO_ABI_LITTLE_ENDIAN     1
+#elif 1 && (LZO_ARCH_ARM) && defined(__ARMEB__) && !defined(__ARMEL__)
+#  define LZO_ABI_BIG_ENDIAN        1
+#elif 1 && (LZO_ARCH_ARM) && defined(__ARMEL__) && !defined(__ARMEB__)
+#  define LZO_ABI_LITTLE_ENDIAN     1
+#elif 1 && (LZO_ARCH_MIPS) && defined(__MIPSEB__) && !defined(__MIPSEL__)
+#  define LZO_ABI_BIG_ENDIAN        1
+#elif 1 && (LZO_ARCH_MIPS) && defined(__MIPSEL__) && !defined(__MIPSEB__)
+#  define LZO_ABI_LITTLE_ENDIAN     1
+#endif
+#endif
+#if (LZO_ABI_BIG_ENDIAN) && (LZO_ABI_LITTLE_ENDIAN)
+#  error "this should not happen"
+#endif
+#if (LZO_ABI_BIG_ENDIAN)
+#  define LZO_INFO_ABI_ENDIAN       "be"
+#elif (LZO_ABI_LITTLE_ENDIAN)
+#  define LZO_INFO_ABI_ENDIAN       "le"
+#elif (LZO_ABI_NEUTRAL_ENDIAN)
+#  define LZO_INFO_ABI_ENDIAN       "neutral"
+#endif
+#if (LZO_SIZEOF_INT == 1 && LZO_SIZEOF_LONG == 2 && LZO_SIZEOF_VOID_P == 2)
+#  define LZO_ABI_I8LP16         1
+#  define LZO_INFO_ABI_PM       "i8lp16"
+#elif (LZO_SIZEOF_INT == 2 && LZO_SIZEOF_LONG == 2 && LZO_SIZEOF_VOID_P == 2)
+#  define LZO_ABI_ILP16         1
+#  define LZO_INFO_ABI_PM       "ilp16"
+#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 4 && LZO_SIZEOF_VOID_P == 4)
+#  define LZO_ABI_ILP32         1
+#  define LZO_INFO_ABI_PM       "ilp32"
+#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 4 && LZO_SIZEOF_VOID_P == 8 && LZO_SIZEOF_SIZE_T == 8)
+#  define LZO_ABI_LLP64         1
+#  define LZO_INFO_ABI_PM       "llp64"
+#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 8)
+#  define LZO_ABI_LP64          1
+#  define LZO_INFO_ABI_PM       "lp64"
+#elif (LZO_SIZEOF_INT == 8 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 8)
+#  define LZO_ABI_ILP64         1
+#  define LZO_INFO_ABI_PM       "ilp64"
+#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 4)
+#  define LZO_ABI_IP32L64       1
+#  define LZO_INFO_ABI_PM       "ip32l64"
+#endif
+#if !defined(__LZO_LIBC_OVERRIDE)
+#if (LZO_LIBC_NAKED)
+#  define LZO_INFO_LIBC         "naked"
+#elif (LZO_LIBC_FREESTANDING)
+#  define LZO_INFO_LIBC         "freestanding"
+#elif (LZO_LIBC_MOSTLY_FREESTANDING)
+#  define LZO_INFO_LIBC         "mfreestanding"
+#elif (LZO_LIBC_ISOC90)
+#  define LZO_INFO_LIBC         "isoc90"
+#elif (LZO_LIBC_ISOC99)
+#  define LZO_INFO_LIBC         "isoc99"
+#elif defined(__dietlibc__)
+#  define LZO_LIBC_DIETLIBC     1
+#  define LZO_INFO_LIBC         "dietlibc"
+#elif defined(_NEWLIB_VERSION)
+#  define LZO_LIBC_NEWLIB       1
+#  define LZO_INFO_LIBC         "newlib"
+#elif defined(__UCLIBC__) && defined(__UCLIBC_MAJOR__) && defined(__UCLIBC_MINOR__)
+#  if defined(__UCLIBC_SUBLEVEL__)
+#    define LZO_LIBC_UCLIBC     (__UCLIBC_MAJOR__ * 0x10000L + __UCLIBC_MINOR__ * 0x100 + __UCLIBC_SUBLEVEL__)
+#  else
+#    define LZO_LIBC_UCLIBC     0x00090bL
+#  endif
+#  define LZO_INFO_LIBC         "uclibc"
+#elif defined(__GLIBC__) && defined(__GLIBC_MINOR__)
+#  define LZO_LIBC_GLIBC        (__GLIBC__ * 0x10000L + __GLIBC_MINOR__ * 0x100)
+#  define LZO_INFO_LIBC         "glibc"
+#elif (LZO_CC_MWERKS) && defined(__MSL__)
+#  define LZO_LIBC_MSL          __MSL__
+#  define LZO_INFO_LIBC         "msl"
+#elif 1 && defined(__IAR_SYSTEMS_ICC__)
+#  define LZO_LIBC_ISOC90       1
+#  define LZO_INFO_LIBC         "isoc90"
+#else
+#  define LZO_LIBC_DEFAULT      1
+#  define LZO_INFO_LIBC         "default"
+#endif
+#endif
+#if !defined(__lzo_gnuc_extension__)
+#if (LZO_CC_GNUC >= 0x020800ul)
+#  define __lzo_gnuc_extension__    __extension__
+#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#  define __lzo_gnuc_extension__    __extension__
+#else
+#  define __lzo_gnuc_extension__    /*empty*/
+#endif
+#endif
+#if !defined(__lzo_ua_volatile)
+#  define __lzo_ua_volatile     volatile
+#endif
+#if !defined(__lzo_alignof)
+#if (LZO_CC_CILLY || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI)
+#  define __lzo_alignof(e)      __alignof__(e)
+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 700))
+#  define __lzo_alignof(e)      __alignof__(e)
+#elif (LZO_CC_MSC && (_MSC_VER >= 1300))
+#  define __lzo_alignof(e)      __alignof(e)
+#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100))
+#  define __lzo_alignof(e)      __alignof__(e)
+#endif
+#endif
+#if defined(__lzo_alignof)
+#  define __lzo_HAVE_alignof 1
+#endif
+#if !defined(__lzo_constructor)
+#if (LZO_CC_GNUC >= 0x030400ul)
+#  define __lzo_constructor     __attribute__((__constructor__,__used__))
+#elif (LZO_CC_GNUC >= 0x020700ul)
+#  define __lzo_constructor     __attribute__((__constructor__))
+#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#  define __lzo_constructor     __attribute__((__constructor__))
+#endif
+#endif
+#if defined(__lzo_constructor)
+#  define __lzo_HAVE_constructor 1
+#endif
+#if !defined(__lzo_destructor)
+#if (LZO_CC_GNUC >= 0x030400ul)
+#  define __lzo_destructor      __attribute__((__destructor__,__used__))
+#elif (LZO_CC_GNUC >= 0x020700ul)
+#  define __lzo_destructor      __attribute__((__destructor__))
+#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#  define __lzo_destructor      __attribute__((__destructor__))
+#endif
+#endif
+#if defined(__lzo_destructor)
+#  define __lzo_HAVE_destructor 1
+#endif
+#if (__lzo_HAVE_destructor) && !(__lzo_HAVE_constructor)
+#  error "this should not happen"
+#endif
+#if !defined(__lzo_inline)
+#if (LZO_CC_TURBOC && (__TURBOC__ <= 0x0295))
+#elif defined(__cplusplus)
+#  define __lzo_inline          inline
+#elif (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0550))
+#  define __lzo_inline          __inline
+#elif (LZO_CC_CILLY || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI)
+#  define __lzo_inline          __inline__
+#elif (LZO_CC_DMC)
+#  define __lzo_inline          __inline
+#elif (LZO_CC_INTELC)
+#  define __lzo_inline          __inline
+#elif (LZO_CC_MWERKS && (__MWERKS__ >= 0x2405))
+#  define __lzo_inline          __inline
+#elif (LZO_CC_MSC && (_MSC_VER >= 900))
+#  define __lzo_inline          __inline
+#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100))
+#  define __lzo_inline          __inline__
+#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
+#  define __lzo_inline          inline
+#endif
+#endif
+#if defined(__lzo_inline)
+#  define __lzo_HAVE_inline 1
+#else
+#  define __lzo_inline          /*empty*/
+#endif
+#if !defined(__lzo_forceinline)
+#if (LZO_CC_GNUC >= 0x030200ul)
+#  define __lzo_forceinline     __inline__ __attribute__((__always_inline__))
+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC)
+#  define __lzo_forceinline     __forceinline
+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC)
+#  define __lzo_forceinline     __inline__ __attribute__((__always_inline__))
+#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#  define __lzo_forceinline     __inline__ __attribute__((__always_inline__))
+#elif (LZO_CC_MSC && (_MSC_VER >= 1200))
+#  define __lzo_forceinline     __forceinline
+#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100))
+#  define __lzo_forceinline     __inline__ __attribute__((__always_inline__))
+#endif
+#endif
+#if defined(__lzo_forceinline)
+#  define __lzo_HAVE_forceinline 1
+#else
+#  define __lzo_forceinline     /*empty*/
+#endif
+#if !defined(__lzo_noinline)
+#if 1 && (LZO_ARCH_I386) && (LZO_CC_GNUC >= 0x040000ul) && (LZO_CC_GNUC < 0x040003ul)
+#  define __lzo_noinline        __attribute__((__noinline__,__used__))
+#elif (LZO_CC_GNUC >= 0x030200ul)
+#  define __lzo_noinline        __attribute__((__noinline__))
+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_MSC)
+#  define __lzo_noinline        __declspec(noinline)
+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC)
+#  define __lzo_noinline        __attribute__((__noinline__))
+#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#  define __lzo_noinline        __attribute__((__noinline__))
+#elif (LZO_CC_MSC && (_MSC_VER >= 1300))
+#  define __lzo_noinline        __declspec(noinline)
+#elif (LZO_CC_MWERKS && (__MWERKS__ >= 0x3200) && (LZO_OS_WIN32 || LZO_OS_WIN64))
+#  if defined(__cplusplus)
+#  else
+#    define __lzo_noinline      __declspec(noinline)
+#  endif
+#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100))
+#  define __lzo_noinline        __attribute__((__noinline__))
+#endif
+#endif
+#if defined(__lzo_noinline)
+#  define __lzo_HAVE_noinline 1
+#else
+#  define __lzo_noinline        /*empty*/
+#endif
+#if (__lzo_HAVE_forceinline || __lzo_HAVE_noinline) && !(__lzo_HAVE_inline)
+#  error "this should not happen"
+#endif
+#if !defined(__lzo_noreturn)
+#if (LZO_CC_GNUC >= 0x020700ul)
+#  define __lzo_noreturn        __attribute__((__noreturn__))
+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC)
+#  define __lzo_noreturn        __declspec(noreturn)
+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_GNUC)
+#  define __lzo_noreturn        __attribute__((__noreturn__))
+#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#  define __lzo_noreturn        __attribute__((__noreturn__))
+#elif (LZO_CC_MSC && (_MSC_VER >= 1200))
+#  define __lzo_noreturn        __declspec(noreturn)
+#endif
+#endif
+#if defined(__lzo_noreturn)
+#  define __lzo_HAVE_noreturn 1
+#else
+#  define __lzo_noreturn        /*empty*/
+#endif
+#if !defined(__lzo_nothrow)
+#if (LZO_CC_GNUC >= 0x030300ul)
+#  define __lzo_nothrow         __attribute__((__nothrow__))
+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC) && defined(__cplusplus)
+#  define __lzo_nothrow         __declspec(nothrow)
+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 900) && LZO_CC_SYNTAX_GNUC)
+#  define __lzo_nothrow         __attribute__((__nothrow__))
+#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#  define __lzo_nothrow         __attribute__((__nothrow__))
+#elif (LZO_CC_MSC && (_MSC_VER >= 1200)) && defined(__cplusplus)
+#  define __lzo_nothrow         __declspec(nothrow)
+#endif
+#endif
+#if defined(__lzo_nothrow)
+#  define __lzo_HAVE_nothrow 1
+#else
+#  define __lzo_nothrow         /*empty*/
+#endif
+#if !defined(__lzo_restrict)
+#if (LZO_CC_GNUC >= 0x030400ul)
+#  define __lzo_restrict        __restrict__
+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_GNUC)
+#  define __lzo_restrict        __restrict__
+#elif (LZO_CC_CLANG || LZO_CC_LLVM)
+#  define __lzo_restrict        __restrict__
+#elif (LZO_CC_MSC && (_MSC_VER >= 1400))
+#  define __lzo_restrict        __restrict
+#endif
+#endif
+#if defined(__lzo_restrict)
+#  define __lzo_HAVE_restrict 1
+#else
+#  define __lzo_restrict        /*empty*/
+#endif
+#if !defined(__lzo_likely) && !defined(__lzo_unlikely)
+#if (LZO_CC_GNUC >= 0x030200ul)
+#  define __lzo_likely(e)       (__builtin_expect(!!(e),1))
+#  define __lzo_unlikely(e)     (__builtin_expect(!!(e),0))
+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800))
+#  define __lzo_likely(e)       (__builtin_expect(!!(e),1))
+#  define __lzo_unlikely(e)     (__builtin_expect(!!(e),0))
+#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#  define __lzo_likely(e)       (__builtin_expect(!!(e),1))
+#  define __lzo_unlikely(e)     (__builtin_expect(!!(e),0))
+#endif
+#endif
+#if defined(__lzo_likely)
+#  define __lzo_HAVE_likely 1
+#else
+#  define __lzo_likely(e)       (e)
+#endif
+#if defined(__lzo_unlikely)
+#  define __lzo_HAVE_unlikely 1
+#else
+#  define __lzo_unlikely(e)     (e)
+#endif
+#if !defined(LZO_UNUSED)
+#  if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0600))
+#    define LZO_UNUSED(var)         ((void) &var)
+#  elif (LZO_CC_BORLANDC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PELLESC || LZO_CC_TURBOC)
+#    define LZO_UNUSED(var)         if (&var) ; else
+#  elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#    define LZO_UNUSED(var)         ((void) var)
+#  elif (LZO_CC_MSC && (_MSC_VER < 900))
+#    define LZO_UNUSED(var)         if (&var) ; else
+#  elif (LZO_CC_KEILC)
+#    define LZO_UNUSED(var)         {extern int __lzo_unused[1-2*!(sizeof(var)>0)];}
+#  elif (LZO_CC_PACIFICC)
+#    define LZO_UNUSED(var)         ((void) sizeof(var))
+#  elif (LZO_CC_WATCOMC) && defined(__cplusplus)
+#    define LZO_UNUSED(var)         ((void) var)
+#  else
+#    define LZO_UNUSED(var)         ((void) &var)
+#  endif
+#endif
+#if !defined(LZO_UNUSED_FUNC)
+#  if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0600))
+#    define LZO_UNUSED_FUNC(func)   ((void) func)
+#  elif (LZO_CC_BORLANDC || LZO_CC_NDPC || LZO_CC_TURBOC)
+#    define LZO_UNUSED_FUNC(func)   if (func) ; else
+#  elif (LZO_CC_CLANG || LZO_CC_LLVM)
+#    define LZO_UNUSED_FUNC(func)   ((void) &func)
+#  elif (LZO_CC_MSC && (_MSC_VER < 900))
+#    define LZO_UNUSED_FUNC(func)   if (func) ; else
+#  elif (LZO_CC_MSC)
+#    define LZO_UNUSED_FUNC(func)   ((void) &func)
+#  elif (LZO_CC_KEILC || LZO_CC_PELLESC)
+#    define LZO_UNUSED_FUNC(func)   {extern int __lzo_unused[1-2*!(sizeof((int)func)>0)];}
+#  else
+#    define LZO_UNUSED_FUNC(func)   ((void) func)
+#  endif
+#endif
+#if !defined(LZO_UNUSED_LABEL)
+#  if (LZO_CC_WATCOMC) && defined(__cplusplus)
+#    define LZO_UNUSED_LABEL(l)     switch(0) case 1:goto l
+#  elif (LZO_CC_CLANG || LZO_CC_INTELC || LZO_CC_WATCOMC)
+#    define LZO_UNUSED_LABEL(l)     if (0) goto l
+#  else
+#    define LZO_UNUSED_LABEL(l)     switch(0) case 1:goto l
+#  endif
+#endif
+#if !defined(LZO_DEFINE_UNINITIALIZED_VAR)
+#  if 0
+#    define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init)  type var
+#  elif 0 && (LZO_CC_GNUC)
+#    define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init)  type var = var
+#  else
+#    define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init)  type var = init
+#  endif
+#endif
+#if !defined(LZO_UNCONST_CAST)
+#  if 0 && defined(__cplusplus)
+#    define LZO_UNCONST_CAST(t,e)   (const_cast<t> (e))
+#  elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#    define LZO_UNCONST_CAST(t,e)   ((t) ((void *) ((char *) ((lzo_uintptr_t) ((const void *) (e))))))
+#  else
+#    define LZO_UNCONST_CAST(t,e)   ((t) ((void *) ((char *) ((const void *) (e)))))
+#  endif
+#endif
+#if !defined(LZO_COMPILE_TIME_ASSERT_HEADER)
+#  if (LZO_CC_AZTECC || LZO_CC_ZORTECHC)
+#    define LZO_COMPILE_TIME_ASSERT_HEADER(e)  extern int __lzo_cta[1-!(e)];
+#  elif (LZO_CC_DMC || LZO_CC_SYMANTECC)
+#    define LZO_COMPILE_TIME_ASSERT_HEADER(e)  extern int __lzo_cta[1u-2*!(e)];
+#  elif (LZO_CC_TURBOC && (__TURBOC__ == 0x0295))
+#    define LZO_COMPILE_TIME_ASSERT_HEADER(e)  extern int __lzo_cta[1-!(e)];
+#  else
+#    define LZO_COMPILE_TIME_ASSERT_HEADER(e)  extern int __lzo_cta[1-2*!(e)];
+#  endif
+#endif
+#if !defined(LZO_COMPILE_TIME_ASSERT)
+#  if (LZO_CC_AZTECC)
+#    define LZO_COMPILE_TIME_ASSERT(e)  {typedef int __lzo_cta_t[1-!(e)];}
+#  elif (LZO_CC_DMC || LZO_CC_PACIFICC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC)
+#    define LZO_COMPILE_TIME_ASSERT(e)  switch(0) case 1:case !(e):break;
+#  elif (LZO_CC_MSC && (_MSC_VER < 900))
+#    define LZO_COMPILE_TIME_ASSERT(e)  switch(0) case 1:case !(e):break;
+#  elif (LZO_CC_TURBOC && (__TURBOC__ == 0x0295))
+#    define LZO_COMPILE_TIME_ASSERT(e)  switch(0) case 1:case !(e):break;
+#  else
+#    define LZO_COMPILE_TIME_ASSERT(e)  {typedef int __lzo_cta_t[1-2*!(e)];}
+#  endif
+#endif
+#if (LZO_ARCH_I086 || LZO_ARCH_I386) && (LZO_OS_DOS16 || LZO_OS_DOS32 || LZO_OS_OS2 || LZO_OS_OS216 || LZO_OS_WIN16 || LZO_OS_WIN32 || LZO_OS_WIN64)
+#  if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC)
+#  elif (LZO_CC_DMC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC)
+#    define __lzo_cdecl                 __cdecl
+#    define __lzo_cdecl_atexit          /*empty*/
+#    define __lzo_cdecl_main            __cdecl
+#    if (LZO_OS_OS2 && (LZO_CC_DMC || LZO_CC_SYMANTECC))
+#      define __lzo_cdecl_qsort         __pascal
+#    elif (LZO_OS_OS2 && (LZO_CC_ZORTECHC))
+#      define __lzo_cdecl_qsort         _stdcall
+#    else
+#      define __lzo_cdecl_qsort         __cdecl
+#    endif
+#  elif (LZO_CC_WATCOMC)
+#    define __lzo_cdecl                 __cdecl
+#  else
+#    define __lzo_cdecl                 __cdecl
+#    define __lzo_cdecl_atexit          __cdecl
+#    define __lzo_cdecl_main            __cdecl
+#    define __lzo_cdecl_qsort           __cdecl
+#  endif
+#  if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC || LZO_CC_WATCOMC)
+#  elif (LZO_OS_OS2 && (LZO_CC_DMC || LZO_CC_SYMANTECC))
+#    define __lzo_cdecl_sighandler      __pascal
+#  elif (LZO_OS_OS2 && (LZO_CC_ZORTECHC))
+#    define __lzo_cdecl_sighandler      _stdcall
+#  elif (LZO_CC_MSC && (_MSC_VER >= 1400)) && defined(_M_CEE_PURE)
+#    define __lzo_cdecl_sighandler      __clrcall
+#  elif (LZO_CC_MSC && (_MSC_VER >= 600 && _MSC_VER < 700))
+#    if defined(_DLL)
+#      define __lzo_cdecl_sighandler    _far _cdecl _loadds
+#    elif defined(_MT)
+#      define __lzo_cdecl_sighandler    _far _cdecl
+#    else
+#      define __lzo_cdecl_sighandler    _cdecl
+#    endif
+#  else
+#    define __lzo_cdecl_sighandler      __cdecl
+#  endif
+#elif (LZO_ARCH_I386) && (LZO_CC_WATCOMC)
+#  define __lzo_cdecl                   __cdecl
+#elif (LZO_ARCH_M68K && LZO_OS_TOS && (LZO_CC_PUREC || LZO_CC_TURBOC))
+#  define __lzo_cdecl                   cdecl
+#endif
+#if !defined(__lzo_cdecl)
+#  define __lzo_cdecl                   /*empty*/
+#endif
+#if !defined(__lzo_cdecl_atexit)
+#  define __lzo_cdecl_atexit            /*empty*/
+#endif
+#if !defined(__lzo_cdecl_main)
+#  define __lzo_cdecl_main              /*empty*/
+#endif
+#if !defined(__lzo_cdecl_qsort)
+#  define __lzo_cdecl_qsort             /*empty*/
+#endif
+#if !defined(__lzo_cdecl_sighandler)
+#  define __lzo_cdecl_sighandler        /*empty*/
+#endif
+#if !defined(__lzo_cdecl_va)
+#  define __lzo_cdecl_va                __lzo_cdecl
+#endif
+#if !(LZO_CFG_NO_WINDOWS_H)
+#if (LZO_OS_CYGWIN || (LZO_OS_EMX && defined(__RSXNT__)) || LZO_OS_WIN32 || LZO_OS_WIN64)
+#  if (LZO_CC_WATCOMC && (__WATCOMC__ < 1000))
+#  elif (LZO_OS_WIN32 && LZO_CC_GNUC) && defined(__PW32__)
+#  elif ((LZO_OS_CYGWIN || defined(__MINGW32__)) && (LZO_CC_GNUC && (LZO_CC_GNUC < 0x025f00ul)))
+#  else
+#    define LZO_HAVE_WINDOWS_H 1
+#  endif
+#endif
+#endif
+#if (LZO_ARCH_ALPHA)
+#  define LZO_OPT_AVOID_UINT_INDEX  1
+#  define LZO_OPT_AVOID_SHORT       1
+#  define LZO_OPT_AVOID_USHORT      1
+#elif (LZO_ARCH_AMD64)
+#  define LZO_OPT_AVOID_INT_INDEX   1
+#  define LZO_OPT_AVOID_UINT_INDEX  1
+#  define LZO_OPT_UNALIGNED16       1
+#  define LZO_OPT_UNALIGNED32       1
+#  define LZO_OPT_UNALIGNED64       1
+#elif (LZO_ARCH_ARM && LZO_ARCH_ARM_THUMB)
+#elif (LZO_ARCH_ARM)
+#  define LZO_OPT_AVOID_SHORT       1
+#  define LZO_OPT_AVOID_USHORT      1
+#elif (LZO_ARCH_CRIS)
+#  define LZO_OPT_UNALIGNED16       1
+#  define LZO_OPT_UNALIGNED32       1
+#elif (LZO_ARCH_I386)
+#  define LZO_OPT_UNALIGNED16       1
+#  define LZO_OPT_UNALIGNED32       1
+#elif (LZO_ARCH_IA64)
+#  define LZO_OPT_AVOID_INT_INDEX   1
+#  define LZO_OPT_AVOID_UINT_INDEX  1
+#  define LZO_OPT_PREFER_POSTINC    1
+#elif (LZO_ARCH_M68K)
+#  define LZO_OPT_PREFER_POSTINC    1
+#  define LZO_OPT_PREFER_PREDEC     1
+#  if defined(__mc68020__) && !defined(__mcoldfire__)
+#    define LZO_OPT_UNALIGNED16     1
+#    define LZO_OPT_UNALIGNED32     1
+#  endif
+#elif (LZO_ARCH_MIPS)
+#  define LZO_OPT_AVOID_UINT_INDEX  1
+#elif (LZO_ARCH_POWERPC)
+#  define LZO_OPT_PREFER_PREINC     1
+#  define LZO_OPT_PREFER_PREDEC     1
+#  if (LZO_ABI_BIG_ENDIAN)
+#    define LZO_OPT_UNALIGNED16     1
+#    define LZO_OPT_UNALIGNED32     1
+#  endif
+#elif (LZO_ARCH_S390)
+#  define LZO_OPT_UNALIGNED16       1
+#  define LZO_OPT_UNALIGNED32       1
+#  if (LZO_SIZEOF_SIZE_T == 8)
+#    define LZO_OPT_UNALIGNED64     1
+#  endif
+#elif (LZO_ARCH_SH)
+#  define LZO_OPT_PREFER_POSTINC    1
+#  define LZO_OPT_PREFER_PREDEC     1
+#endif
+#ifndef LZO_CFG_NO_INLINE_ASM
+#if (LZO_CC_LLVM)
+#  define LZO_CFG_NO_INLINE_ASM 1
+#endif
+#endif
+#ifndef LZO_CFG_NO_UNALIGNED
+#if (LZO_ABI_NEUTRAL_ENDIAN) || (LZO_ARCH_GENERIC)
+#  define LZO_CFG_NO_UNALIGNED 1
+#endif
+#endif
+#if (LZO_CFG_NO_UNALIGNED)
+#  undef LZO_OPT_UNALIGNED16
+#  undef LZO_OPT_UNALIGNED32
+#  undef LZO_OPT_UNALIGNED64
+#endif
+#if (LZO_CFG_NO_INLINE_ASM)
+#elif (LZO_ARCH_I386 && (LZO_OS_DOS32 || LZO_OS_WIN32) && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC))
+#  define LZO_ASM_SYNTAX_MSC 1
+#elif (LZO_OS_WIN64 && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC))
+#elif (LZO_ARCH_I386 && LZO_CC_GNUC && (LZO_CC_GNUC == 0x011f00ul))
+#elif (LZO_ARCH_I386 && (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE))
+#  define LZO_ASM_SYNTAX_GNUC 1
+#elif (LZO_ARCH_AMD64 && (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE))
+#  define LZO_ASM_SYNTAX_GNUC 1
+#endif
+#if (LZO_ASM_SYNTAX_GNUC)
+#if (LZO_ARCH_I386 && LZO_CC_GNUC && (LZO_CC_GNUC < 0x020000ul))
+#  define __LZO_ASM_CLOBBER         "ax"
+#elif (LZO_CC_INTELC)
+#  define __LZO_ASM_CLOBBER         "memory"
+#else
+#  define __LZO_ASM_CLOBBER         "cc", "memory"
+#endif
+#endif
+#if defined(__LZO_INFOSTR_MM)
+#elif (LZO_MM_FLAT) && (defined(__LZO_INFOSTR_PM) || defined(LZO_INFO_ABI_PM))
+#  define __LZO_INFOSTR_MM          ""
+#elif defined(LZO_INFO_MM)
+#  define __LZO_INFOSTR_MM          "." LZO_INFO_MM
+#else
+#  define __LZO_INFOSTR_MM          ""
+#endif
+#if defined(__LZO_INFOSTR_PM)
+#elif defined(LZO_INFO_ABI_PM)
+#  define __LZO_INFOSTR_PM          "." LZO_INFO_ABI_PM
+#else
+#  define __LZO_INFOSTR_PM          ""
+#endif
+#if defined(__LZO_INFOSTR_ENDIAN)
+#elif defined(LZO_INFO_ABI_ENDIAN)
+#  define __LZO_INFOSTR_ENDIAN      "." LZO_INFO_ABI_ENDIAN
+#else
+#  define __LZO_INFOSTR_ENDIAN      ""
+#endif
+#if defined(__LZO_INFOSTR_OSNAME)
+#elif defined(LZO_INFO_OS_CONSOLE)
+#  define __LZO_INFOSTR_OSNAME      LZO_INFO_OS "." LZO_INFO_OS_CONSOLE
+#elif defined(LZO_INFO_OS_POSIX)
+#  define __LZO_INFOSTR_OSNAME      LZO_INFO_OS "." LZO_INFO_OS_POSIX
+#else
+#  define __LZO_INFOSTR_OSNAME      LZO_INFO_OS
+#endif
+#if defined(__LZO_INFOSTR_LIBC)
+#elif defined(LZO_INFO_LIBC)
+#  define __LZO_INFOSTR_LIBC        "." LZO_INFO_LIBC
+#else
+#  define __LZO_INFOSTR_LIBC        ""
+#endif
+#if defined(__LZO_INFOSTR_CCVER)
+#elif defined(LZO_INFO_CCVER)
+#  define __LZO_INFOSTR_CCVER       " " LZO_INFO_CCVER
+#else
+#  define __LZO_INFOSTR_CCVER       ""
+#endif
+#define LZO_INFO_STRING \
+    LZO_INFO_ARCH __LZO_INFOSTR_MM __LZO_INFOSTR_PM __LZO_INFOSTR_ENDIAN \
+    " " __LZO_INFOSTR_OSNAME __LZO_INFOSTR_LIBC " " LZO_INFO_CC __LZO_INFOSTR_CCVER
+
+#endif
+
+#endif
+
+#undef LZO_HAVE_CONFIG_H
+#include "minilzo.h"
+
+#if !defined(MINILZO_VERSION) || (MINILZO_VERSION != 0x2050)
+#  error "version mismatch in miniLZO source files"
+#endif
+
+#ifdef MINILZO_HAVE_CONFIG_H
+#  define LZO_HAVE_CONFIG_H 1
+#endif
+
+#ifndef __LZO_CONF_H
+#define __LZO_CONF_H 1
+
+#if !defined(__LZO_IN_MINILZO)
+#if (LZO_CFG_FREESTANDING)
+#  define LZO_LIBC_FREESTANDING 1
+#  define LZO_OS_FREESTANDING 1
+#  define ACC_LIBC_FREESTANDING 1
+#  define ACC_OS_FREESTANDING 1
+#endif
+#if (LZO_CFG_NO_UNALIGNED)
+#  define ACC_CFG_NO_UNALIGNED 1
+#endif
+#if (LZO_ARCH_GENERIC)
+#  define ACC_ARCH_GENERIC 1
+#endif
+#if (LZO_ABI_NEUTRAL_ENDIAN)
+#  define ACC_ABI_NEUTRAL_ENDIAN 1
+#endif
+#if (LZO_HAVE_CONFIG_H)
+#  define ACC_CONFIG_NO_HEADER 1
+#endif
+#if defined(LZO_CFG_EXTRA_CONFIG_HEADER)
+#  include LZO_CFG_EXTRA_CONFIG_HEADER
+#endif
+#if defined(__LZOCONF_H) || defined(__LZOCONF_H_INCLUDED)
+#  error "include this file first"
+#endif
+#include "lzo/lzoconf.h"
+#endif
+
+#if (LZO_VERSION < 0x02000) || !defined(__LZOCONF_H_INCLUDED)
+#  error "version mismatch"
+#endif
+
+#if (LZO_CC_BORLANDC && LZO_ARCH_I086)
+#  pragma option -h
+#endif
+
+#if (LZO_CC_MSC && (_MSC_VER >= 1000))
+#  pragma warning(disable: 4127 4701)
+#endif
+#if (LZO_CC_MSC && (_MSC_VER >= 1300))
+#  pragma warning(disable: 4820)
+#  pragma warning(disable: 4514 4710 4711)
+#endif
+
+#if (LZO_CC_SUNPROC)
+#if !defined(__cplusplus)
+#  pragma error_messages(off,E_END_OF_LOOP_CODE_NOT_REACHED)
+#  pragma error_messages(off,E_LOOP_NOT_ENTERED_AT_TOP)
+#  pragma error_messages(off,E_STATEMENT_NOT_REACHED)
+#endif
+#endif
+
+#if (__LZO_MMODEL_HUGE) && !(LZO_HAVE_MM_HUGE_PTR)
+#  error "this should not happen - check defines for __huge"
+#endif
+
+#if defined(__LZO_IN_MINILZO) || defined(LZO_CFG_FREESTANDING)
+#elif (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16)
+#  define ACC_WANT_ACC_INCD_H 1
+#  define ACC_WANT_ACC_INCE_H 1
+#  define ACC_WANT_ACC_INCI_H 1
+#elif 1
+#  include <string.h>
+#else
+#  define ACC_WANT_ACC_INCD_H 1
+#endif
+
+#if (LZO_ARCH_I086)
+#  define ACC_MM_AHSHIFT        LZO_MM_AHSHIFT
+#  define ACC_PTR_FP_OFF(x)     (((const unsigned __far*)&(x))[0])
+#  define ACC_PTR_FP_SEG(x)     (((const unsigned __far*)&(x))[1])
+#  define ACC_PTR_MK_FP(s,o)    ((void __far*)(((unsigned long)(s)<<16)+(unsigned)(o)))
+#endif
+
+#if !defined(lzo_uintptr_t)
+#  if defined(__LZO_MMODEL_HUGE)
+#    define lzo_uintptr_t       unsigned long
+#  elif 1 && defined(LZO_OS_OS400) && (LZO_SIZEOF_VOID_P == 16)
+#    define __LZO_UINTPTR_T_IS_POINTER 1
+     typedef char*              lzo_uintptr_t;
+#    define lzo_uintptr_t       lzo_uintptr_t
+#  elif (LZO_SIZEOF_SIZE_T == LZO_SIZEOF_VOID_P)
+#    define lzo_uintptr_t       size_t
+#  elif (LZO_SIZEOF_LONG == LZO_SIZEOF_VOID_P)
+#    define lzo_uintptr_t       unsigned long
+#  elif (LZO_SIZEOF_INT == LZO_SIZEOF_VOID_P)
+#    define lzo_uintptr_t       unsigned int
+#  elif (LZO_SIZEOF_LONG_LONG == LZO_SIZEOF_VOID_P)
+#    define lzo_uintptr_t       unsigned long long
+#  else
+#    define lzo_uintptr_t       size_t
+#  endif
+#endif
+LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uintptr_t) >= sizeof(lzo_voidp))
+
+#if 1 && !defined(LZO_CFG_FREESTANDING)
+#if 1 && !defined(HAVE_STRING_H)
+#define HAVE_STRING_H 1
+#endif
+#if 1 && !defined(HAVE_MEMCMP)
+#define HAVE_MEMCMP 1
+#endif
+#if 1 && !defined(HAVE_MEMCPY)
+#define HAVE_MEMCPY 1
+#endif
+#if 1 && !defined(HAVE_MEMMOVE)
+#define HAVE_MEMMOVE 1
+#endif
+#if 1 && !defined(HAVE_MEMSET)
+#define HAVE_MEMSET 1
+#endif
+#endif
+
+#if 1 && defined(HAVE_STRING_H)
+#include <string.h>
+#endif
+
+#if (LZO_CFG_FREESTANDING)
+#  undef HAVE_MEMCMP
+#  undef HAVE_MEMCPY
+#  undef HAVE_MEMMOVE
+#  undef HAVE_MEMSET
+#endif
+
+#if !(HAVE_MEMCMP)
+#  undef memcmp
+#  define memcmp(a,b,c)         lzo_memcmp(a,b,c)
+#elif !(__LZO_MMODEL_HUGE)
+#  undef lzo_memcmp
+#  define lzo_memcmp(a,b,c)     memcmp(a,b,c)
+#endif
+#if !(HAVE_MEMCPY)
+#  undef memcpy
+#  define memcpy(a,b,c)         lzo_memcpy(a,b,c)
+#elif !(__LZO_MMODEL_HUGE)
+#  undef lzo_memcpy
+#  define lzo_memcpy(a,b,c)     memcpy(a,b,c)
+#endif
+#if !(HAVE_MEMMOVE)
+#  undef memmove
+#  define memmove(a,b,c)        lzo_memmove(a,b,c)
+#elif !(__LZO_MMODEL_HUGE)
+#  undef lzo_memmove
+#  define lzo_memmove(a,b,c)    memmove(a,b,c)
+#endif
+#if !(HAVE_MEMSET)
+#  undef memset
+#  define memset(a,b,c)         lzo_memset(a,b,c)
+#elif !(__LZO_MMODEL_HUGE)
+#  undef lzo_memset
+#  define lzo_memset(a,b,c)     memset(a,b,c)
+#endif
+
+#undef NDEBUG
+#if (LZO_CFG_FREESTANDING)
+#  undef LZO_DEBUG
+#  define NDEBUG 1
+#  undef assert
+#  define assert(e) ((void)0)
+#else
+#  if !defined(LZO_DEBUG)
+#    define NDEBUG 1
+#  endif
+#  include <assert.h>
+#endif
+
+#if 0 && defined(__BOUNDS_CHECKING_ON)
+#  include <unchecked.h>
+#else
+#  define BOUNDS_CHECKING_OFF_DURING(stmt)      stmt
+#  define BOUNDS_CHECKING_OFF_IN_EXPR(expr)     (expr)
+#endif
+
+#if !defined(__lzo_inline)
+#  define __lzo_inline              /*empty*/
+#endif
+#if !defined(__lzo_forceinline)
+#  define __lzo_forceinline         /*empty*/
+#endif
+#if !defined(__lzo_noinline)
+#  define __lzo_noinline            /*empty*/
+#endif
+
+#if (LZO_CFG_PGO)
+#  undef __acc_likely
+#  undef __acc_unlikely
+#  undef __lzo_likely
+#  undef __lzo_unlikely
+#  define __acc_likely(e)       (e)
+#  define __acc_unlikely(e)     (e)
+#  define __lzo_likely(e)       (e)
+#  define __lzo_unlikely(e)     (e)
+#endif
+
+#if 1
+#  define LZO_BYTE(x)       ((unsigned char) (x))
+#else
+#  define LZO_BYTE(x)       ((unsigned char) ((x) & 0xff))
+#endif
+
+#define LZO_MAX(a,b)        ((a) >= (b) ? (a) : (b))
+#define LZO_MIN(a,b)        ((a) <= (b) ? (a) : (b))
+#define LZO_MAX3(a,b,c)     ((a) >= (b) ? LZO_MAX(a,c) : LZO_MAX(b,c))
+#define LZO_MIN3(a,b,c)     ((a) <= (b) ? LZO_MIN(a,c) : LZO_MIN(b,c))
+
+#define lzo_sizeof(type)    ((lzo_uint) (sizeof(type)))
+
+#define LZO_HIGH(array)     ((lzo_uint) (sizeof(array)/sizeof(*(array))))
+
+#define LZO_SIZE(bits)      (1u << (bits))
+#define LZO_MASK(bits)      (LZO_SIZE(bits) - 1)
+
+#define LZO_LSIZE(bits)     (1ul << (bits))
+#define LZO_LMASK(bits)     (LZO_LSIZE(bits) - 1)
+
+#define LZO_USIZE(bits)     ((lzo_uint) 1 << (bits))
+#define LZO_UMASK(bits)     (LZO_USIZE(bits) - 1)
+
+#if !defined(DMUL)
+#if 0
+
+#  define DMUL(a,b) ((lzo_xint) ((lzo_uint32)(a) * (lzo_uint32)(b)))
+#else
+#  define DMUL(a,b) ((lzo_xint) ((a) * (b)))
+#endif
+#endif
+
+#if 1 && (LZO_ARCH_AMD64 || LZO_ARCH_I386 || LZO_ARCH_POWERPC)
+#  if (LZO_SIZEOF_SHORT == 2)
+#    define LZO_UNALIGNED_OK_2 1
+#  endif
+#  if (LZO_SIZEOF_INT == 4)
+#    define LZO_UNALIGNED_OK_4 1
+#  endif
+#endif
+#if 1 && (LZO_ARCH_AMD64)
+#  if defined(LZO_UINT64_MAX)
+#    define LZO_UNALIGNED_OK_8 1
+#  endif
+#endif
+#if (LZO_CFG_NO_UNALIGNED)
+#  undef LZO_UNALIGNED_OK_2
+#  undef LZO_UNALIGNED_OK_4
+#  undef LZO_UNALIGNED_OK_8
+#endif
+
+#undef UA_GET16
+#undef UA_SET16
+#undef UA_COPY16
+#undef UA_GET32
+#undef UA_SET32
+#undef UA_COPY32
+#undef UA_GET64
+#undef UA_SET64
+#undef UA_COPY64
+#if defined(LZO_UNALIGNED_OK_2)
+   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(unsigned short) == 2)
+#  if 1 && defined(ACC_UA_COPY16)
+#    define UA_GET16        ACC_UA_GET16
+#    define UA_SET16        ACC_UA_SET16
+#    define UA_COPY16       ACC_UA_COPY16
+#  else
+#    define UA_GET16(p)     (* (__lzo_ua_volatile const lzo_ushortp) (__lzo_ua_volatile const lzo_voidp) (p))
+#    define UA_SET16(p,v)   ((* (__lzo_ua_volatile lzo_ushortp) (__lzo_ua_volatile lzo_voidp) (p)) = (unsigned short) (v))
+#    define UA_COPY16(d,s)  UA_SET16(d, UA_GET16(s))
+#  endif
+#endif
+#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
+   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint32) == 4)
+#  if 1 && defined(ACC_UA_COPY32)
+#    define UA_GET32        ACC_UA_GET32
+#    define UA_SET32        ACC_UA_SET32
+#    define UA_COPY32       ACC_UA_COPY32
+#  else
+#    define UA_GET32(p)     (* (__lzo_ua_volatile const lzo_uint32p) (__lzo_ua_volatile const lzo_voidp) (p))
+#    define UA_SET32(p,v)   ((* (__lzo_ua_volatile lzo_uint32p) (__lzo_ua_volatile lzo_voidp) (p)) = (lzo_uint32) (v))
+#    define UA_COPY32(d,s)  UA_SET32(d, UA_GET32(s))
+#  endif
+#endif
+#if defined(LZO_UNALIGNED_OK_8)
+   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint64) == 8)
+#  if 1 && defined(ACC_UA_COPY64)
+#    define UA_GET64        ACC_UA_GET64
+#    define UA_SET64        ACC_UA_SET64
+#    define UA_COPY64       ACC_UA_COPY64
+#  else
+#    define UA_GET64(p)     (* (__lzo_ua_volatile const lzo_uint64p) (__lzo_ua_volatile const lzo_voidp) (p))
+#    define UA_SET64(p,v)   ((* (__lzo_ua_volatile lzo_uint64p) (__lzo_ua_volatile lzo_voidp) (p)) = (lzo_uint64) (v))
+#    define UA_COPY64(d,s)  UA_SET64(d, UA_GET64(s))
+#  endif
+#endif
+
+#define MEMCPY8_DS(dest,src,len) \
+    lzo_memcpy(dest,src,len); dest += len; src += len
+
+#define BZERO8_PTR(s,l,n) \
+    lzo_memset((lzo_voidp)(s),0,(lzo_uint)(l)*(n))
+
+#define MEMCPY_DS(dest,src,len) \
+    do *dest++ = *src++; while (--len > 0)
+
+LZO_EXTERN(const lzo_bytep) lzo_copyright(void);
+
+#ifndef __LZO_PTR_H
+#define __LZO_PTR_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if !defined(lzo_uintptr_t)
+#  if (__LZO_MMODEL_HUGE)
+#    define lzo_uintptr_t   unsigned long
+#  else
+#    define lzo_uintptr_t   acc_uintptr_t
+#    ifdef __ACC_INTPTR_T_IS_POINTER
+#      define __LZO_UINTPTR_T_IS_POINTER 1
+#    endif
+#  endif
+#endif
+
+#if (LZO_ARCH_I086)
+#define PTR(a)              ((lzo_bytep) (a))
+#define PTR_ALIGNED_4(a)    ((ACC_PTR_FP_OFF(a) & 3) == 0)
+#define PTR_ALIGNED2_4(a,b) (((ACC_PTR_FP_OFF(a) | ACC_PTR_FP_OFF(b)) & 3) == 0)
+#elif (LZO_MM_PVP)
+#define PTR(a)              ((lzo_bytep) (a))
+#define PTR_ALIGNED_8(a)    ((((lzo_uintptr_t)(a)) >> 61) == 0)
+#define PTR_ALIGNED2_8(a,b) ((((lzo_uintptr_t)(a)|(lzo_uintptr_t)(b)) >> 61) == 0)
+#else
+#define PTR(a)              ((lzo_uintptr_t) (a))
+#define PTR_LINEAR(a)       PTR(a)
+#define PTR_ALIGNED_4(a)    ((PTR_LINEAR(a) & 3) == 0)
+#define PTR_ALIGNED_8(a)    ((PTR_LINEAR(a) & 7) == 0)
+#define PTR_ALIGNED2_4(a,b) (((PTR_LINEAR(a) | PTR_LINEAR(b)) & 3) == 0)
+#define PTR_ALIGNED2_8(a,b) (((PTR_LINEAR(a) | PTR_LINEAR(b)) & 7) == 0)
+#endif
+
+#define PTR_LT(a,b)         (PTR(a) < PTR(b))
+#define PTR_GE(a,b)         (PTR(a) >= PTR(b))
+#define PTR_DIFF(a,b)       (PTR(a) - PTR(b))
+#define pd(a,b)             ((lzo_uint) ((a)-(b)))
+
+LZO_EXTERN(lzo_uintptr_t)
+__lzo_ptr_linear(const lzo_voidp ptr);
+
+typedef union
+{
+    char            a_char;
+    unsigned char   a_uchar;
+    short           a_short;
+    unsigned short  a_ushort;
+    int             a_int;
+    unsigned int    a_uint;
+    long            a_long;
+    unsigned long   a_ulong;
+    lzo_int         a_lzo_int;
+    lzo_uint        a_lzo_uint;
+    lzo_int32       a_lzo_int32;
+    lzo_uint32      a_lzo_uint32;
+#if defined(LZO_UINT64_MAX)
+    lzo_int64       a_lzo_int64;
+    lzo_uint64      a_lzo_uint64;
+#endif
+    ptrdiff_t       a_ptrdiff_t;
+    lzo_uintptr_t   a_lzo_uintptr_t;
+    lzo_voidp       a_lzo_voidp;
+    void *          a_void_p;
+    lzo_bytep       a_lzo_bytep;
+    lzo_bytepp      a_lzo_bytepp;
+    lzo_uintp       a_lzo_uintp;
+    lzo_uint *      a_lzo_uint_p;
+    lzo_uint32p     a_lzo_uint32p;
+    lzo_uint32 *    a_lzo_uint32_p;
+    unsigned char * a_uchar_p;
+    char *          a_char_p;
+}
+lzo_full_align_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+#ifndef LZO_DETERMINISTIC
+#define LZO_DETERMINISTIC 1
+#endif
+
+#ifndef LZO_DICT_USE_PTR
+#define LZO_DICT_USE_PTR 1
+#if 0 && (LZO_ARCH_I086)
+#  undef LZO_DICT_USE_PTR
+#  define LZO_DICT_USE_PTR 0
+#endif
+#endif
+
+#if (LZO_DICT_USE_PTR)
+#  define lzo_dict_t    const lzo_bytep
+#  define lzo_dict_p    lzo_dict_t __LZO_MMODEL *
+#else
+#  define lzo_dict_t    lzo_uint
+#  define lzo_dict_p    lzo_dict_t __LZO_MMODEL *
+#endif
+
+#endif
+
+#if !defined(MINILZO_CFG_SKIP_LZO_PTR)
+
+LZO_PUBLIC(lzo_uintptr_t)
+__lzo_ptr_linear(const lzo_voidp ptr)
+{
+    lzo_uintptr_t p;
+
+#if (LZO_ARCH_I086)
+    p = (((lzo_uintptr_t)(ACC_PTR_FP_SEG(ptr))) << (16 - ACC_MM_AHSHIFT)) + (ACC_PTR_FP_OFF(ptr));
+#elif (LZO_MM_PVP)
+    p = (lzo_uintptr_t) (ptr);
+    p = (p << 3) | (p >> 61);
+#else
+    p = (lzo_uintptr_t) PTR_LINEAR(ptr);
+#endif
+
+    return p;
+}
+
+LZO_PUBLIC(unsigned)
+__lzo_align_gap(const lzo_voidp ptr, lzo_uint size)
+{
+#if defined(__LZO_UINTPTR_T_IS_POINTER)
+    size_t n = (size_t) ptr;
+    n = (((n + size - 1) / size) * size) - n;
+#else
+    lzo_uintptr_t p, n;
+    p = __lzo_ptr_linear(ptr);
+    n = (((p + size - 1) / size) * size) - p;
+#endif
+
+    assert(size > 0);
+    assert((long)n >= 0);
+    assert(n <= size);
+    return (unsigned)n;
+}
+
+#endif
+#if !defined(MINILZO_CFG_SKIP_LZO_UTIL)
+
+/* If you use the LZO library in a product, I would appreciate that you
+ * keep this copyright string in the executable of your product.
+ */
+
+static const char __lzo_copyright[] =
+#if !defined(__LZO_IN_MINLZO)
+    LZO_VERSION_STRING;
+#else
+    "\r\n\n"
+    "LZO data compression library.\n"
+    "$Copyright: LZO Copyright (C) 1996-2011 Markus Franz Xaver Johannes Oberhumer\n"
+    "<markus@oberhumer.com>\n"
+    "http://www.oberhumer.com $\n\n"
+    "$Id: LZO version: v" LZO_VERSION_STRING ", " LZO_VERSION_DATE " $\n"
+    "$Info: " LZO_INFO_STRING " $\n";
+#endif
+
+LZO_PUBLIC(const lzo_bytep)
+lzo_copyright(void)
+{
+#if (LZO_OS_DOS16 && LZO_CC_TURBOC)
+    return (lzo_voidp) __lzo_copyright;
+#else
+    return (const lzo_bytep) __lzo_copyright;
+#endif
+}
+
+LZO_PUBLIC(unsigned)
+lzo_version(void)
+{
+    return LZO_VERSION;
+}
+
+LZO_PUBLIC(const char *)
+lzo_version_string(void)
+{
+    return LZO_VERSION_STRING;
+}
+
+LZO_PUBLIC(const char *)
+lzo_version_date(void)
+{
+    return LZO_VERSION_DATE;
+}
+
+LZO_PUBLIC(const lzo_charp)
+_lzo_version_string(void)
+{
+    return LZO_VERSION_STRING;
+}
+
+LZO_PUBLIC(const lzo_charp)
+_lzo_version_date(void)
+{
+    return LZO_VERSION_DATE;
+}
+
+#define LZO_BASE 65521u
+#define LZO_NMAX 5552
+
+#define LZO_DO1(buf,i)  s1 += buf[i]; s2 += s1
+#define LZO_DO2(buf,i)  LZO_DO1(buf,i); LZO_DO1(buf,i+1);
+#define LZO_DO4(buf,i)  LZO_DO2(buf,i); LZO_DO2(buf,i+2);
+#define LZO_DO8(buf,i)  LZO_DO4(buf,i); LZO_DO4(buf,i+4);
+#define LZO_DO16(buf,i) LZO_DO8(buf,i); LZO_DO8(buf,i+8);
+
+LZO_PUBLIC(lzo_uint32)
+lzo_adler32(lzo_uint32 adler, const lzo_bytep buf, lzo_uint len)
+{
+    lzo_uint32 s1 = adler & 0xffff;
+    lzo_uint32 s2 = (adler >> 16) & 0xffff;
+    unsigned k;
+
+    if (buf == NULL)
+        return 1;
+
+    while (len > 0)
+    {
+        k = len < LZO_NMAX ? (unsigned) len : LZO_NMAX;
+        len -= k;
+        if (k >= 16) do
+        {
+            LZO_DO16(buf,0);
+            buf += 16;
+            k -= 16;
+        } while (k >= 16);
+        if (k != 0) do
+        {
+            s1 += *buf++;
+            s2 += s1;
+        } while (--k > 0);
+        s1 %= LZO_BASE;
+        s2 %= LZO_BASE;
+    }
+    return (s2 << 16) | s1;
+}
+
+#undef LZO_DO1
+#undef LZO_DO2
+#undef LZO_DO4
+#undef LZO_DO8
+#undef LZO_DO16
+
+#endif
+#if !defined(MINILZO_CFG_SKIP_LZO_STRING)
+#undef lzo_memcmp
+#undef lzo_memcpy
+#undef lzo_memmove
+#undef lzo_memset
+#if !defined(__LZO_MMODEL_HUGE)
+#  undef LZO_HAVE_MM_HUGE_PTR
+#endif
+#define lzo_hsize_t             lzo_uint
+#define lzo_hvoid_p             lzo_voidp
+#define lzo_hbyte_p             lzo_bytep
+#define LZOLIB_PUBLIC(r,f)      LZO_PUBLIC(r) f
+#define lzo_hmemcmp             lzo_memcmp
+#define lzo_hmemcpy             lzo_memcpy
+#define lzo_hmemmove            lzo_memmove
+#define lzo_hmemset             lzo_memset
+#define __LZOLIB_HMEMCPY_CH_INCLUDED 1
+#if !defined(LZOLIB_PUBLIC)
+#  define LZOLIB_PUBLIC(r,f)    r __LZOLIB_FUNCNAME(f)
+#endif
+LZOLIB_PUBLIC(int, lzo_hmemcmp) (const lzo_hvoid_p s1, const lzo_hvoid_p s2, lzo_hsize_t len)
+{
+#if (LZO_HAVE_MM_HUGE_PTR) || !(HAVE_MEMCMP)
+    const lzo_hbyte_p p1 = (const lzo_hbyte_p) s1;
+    const lzo_hbyte_p p2 = (const lzo_hbyte_p) s2;
+    if __lzo_likely(len > 0) do
+    {
+        int d = *p1 - *p2;
+        if (d != 0)
+            return d;
+        p1++; p2++;
+    } while __lzo_likely(--len > 0);
+    return 0;
+#else
+    return memcmp(s1, s2, len);
+#endif
+}
+LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemcpy) (lzo_hvoid_p dest, const lzo_hvoid_p src, lzo_hsize_t len)
+{
+#if (LZO_HAVE_MM_HUGE_PTR) || !(HAVE_MEMCPY)
+    lzo_hbyte_p p1 = (lzo_hbyte_p) dest;
+    const lzo_hbyte_p p2 = (const lzo_hbyte_p) src;
+    if (!(len > 0) || p1 == p2)
+        return dest;
+    do
+        *p1++ = *p2++;
+    while __lzo_likely(--len > 0);
+    return dest;
+#else
+    return memcpy(dest, src, len);
+#endif
+}
+LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemmove) (lzo_hvoid_p dest, const lzo_hvoid_p src, lzo_hsize_t len)
+{
+#if (LZO_HAVE_MM_HUGE_PTR) || !(HAVE_MEMMOVE)
+    lzo_hbyte_p p1 = (lzo_hbyte_p) dest;
+    const lzo_hbyte_p p2 = (const lzo_hbyte_p) src;
+    if (!(len > 0) || p1 == p2)
+        return dest;
+    if (p1 < p2)
+    {
+        do
+            *p1++ = *p2++;
+        while __lzo_likely(--len > 0);
+    }
+    else
+    {
+        p1 += len;
+        p2 += len;
+        do
+            *--p1 = *--p2;
+        while __lzo_likely(--len > 0);
+    }
+    return dest;
+#else
+    return memmove(dest, src, len);
+#endif
+}
+LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemset) (lzo_hvoid_p s, int c, lzo_hsize_t len)
+{
+#if (LZO_HAVE_MM_HUGE_PTR) || !(HAVE_MEMSET)
+    lzo_hbyte_p p = (lzo_hbyte_p) s;
+    if __lzo_likely(len > 0) do
+        *p++ = (unsigned char) c;
+    while __lzo_likely(--len > 0);
+    return s;
+#else
+    return memset(s, c, len);
+#endif
+}
+#undef LZOLIB_PUBLIC
+#endif
+#if !defined(MINILZO_CFG_SKIP_LZO_INIT)
+
+#if !defined(__LZO_IN_MINILZO)
+
+#define ACC_WANT_ACC_CHK_CH 1
+#undef ACCCHK_ASSERT
+
+    ACCCHK_ASSERT_IS_SIGNED_T(lzo_int)
+    ACCCHK_ASSERT_IS_UNSIGNED_T(lzo_uint)
+
+    ACCCHK_ASSERT_IS_SIGNED_T(lzo_int32)
+    ACCCHK_ASSERT_IS_UNSIGNED_T(lzo_uint32)
+    ACCCHK_ASSERT((LZO_UINT32_C(1) << (int)(8*sizeof(LZO_UINT32_C(1))-1)) > 0)
+    ACCCHK_ASSERT(sizeof(lzo_uint32) >= 4)
+#if defined(LZO_UINT64_MAX)
+    ACCCHK_ASSERT(sizeof(lzo_uint64) == 8)
+    ACCCHK_ASSERT_IS_SIGNED_T(lzo_int64)
+    ACCCHK_ASSERT_IS_UNSIGNED_T(lzo_uint64)
+#endif
+
+#if !defined(__LZO_UINTPTR_T_IS_POINTER)
+    ACCCHK_ASSERT_IS_UNSIGNED_T(lzo_uintptr_t)
+#endif
+    ACCCHK_ASSERT(sizeof(lzo_uintptr_t) >= sizeof(lzo_voidp))
+
+    ACCCHK_ASSERT_IS_UNSIGNED_T(lzo_xint)
+    ACCCHK_ASSERT(sizeof(lzo_xint) >= sizeof(lzo_uint32))
+    ACCCHK_ASSERT(sizeof(lzo_xint) >= sizeof(lzo_uint))
+    ACCCHK_ASSERT(sizeof(lzo_xint) == sizeof(lzo_uint32) || sizeof(lzo_xint) == sizeof(lzo_uint))
+
+#endif
+#undef ACCCHK_ASSERT
+
+#if 0
+#define WANT_lzo_bitops_clz32 1
+#define WANT_lzo_bitops_clz64 1
+#endif
+#define WANT_lzo_bitops_ctz32 1
+#define WANT_lzo_bitops_ctz64 1
+
+#if (defined(_WIN32) || defined(_WIN64)) && ((LZO_CC_INTELC && (__INTEL_COMPILER >= 1000)) || (LZO_CC_MSC && (_MSC_VER >= 1400)))
+#include <intrin.h>
+#if !defined(lzo_bitops_clz32) && defined(WANT_lzo_bitops_clz32) && 0
+#pragma intrinsic(_BitScanReverse)
+static __lzo_inline unsigned lzo_bitops_clz32(lzo_uint32 v)
+{
+    unsigned long r;
+    (void) _BitScanReverse(&r, v);
+    return (unsigned) r;
+}
+#define lzo_bitops_clz32 lzo_bitops_clz32
+#endif
+#if !defined(lzo_bitops_clz64) && defined(WANT_lzo_bitops_clz64) && defined(LZO_UINT64_MAX) && 0
+#pragma intrinsic(_BitScanReverse64)
+static __lzo_inline unsigned lzo_bitops_clz64(lzo_uint64 v)
+{
+    unsigned long r;
+    (void) _BitScanReverse64(&r, v);
+    return (unsigned) r;
+}
+#define lzo_bitops_clz64 lzo_bitops_clz64
+#endif
+#if !defined(lzo_bitops_ctz32) && defined(WANT_lzo_bitops_ctz32)
+#pragma intrinsic(_BitScanForward)
+static __lzo_inline unsigned lzo_bitops_ctz32(lzo_uint32 v)
+{
+    unsigned long r;
+    (void) _BitScanForward(&r, v);
+    return (unsigned) r;
+}
+#define lzo_bitops_ctz32 lzo_bitops_ctz32
+#endif
+#if !defined(lzo_bitops_ctz64) && defined(WANT_lzo_bitops_ctz64) && defined(LZO_UINT64_MAX)
+#pragma intrinsic(_BitScanForward64)
+static __lzo_inline unsigned lzo_bitops_ctz64(lzo_uint64 v)
+{
+    unsigned long r;
+    (void) _BitScanForward64(&r, v);
+    return (unsigned) r;
+}
+#define lzo_bitops_ctz64 lzo_bitops_ctz64
+#endif
+
+#elif (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x030400ul) || (LZO_CC_INTELC && (__INTEL_COMPILER >= 1000)) || LZO_CC_LLVM)
+#if !defined(lzo_bitops_clz32) && defined(WANT_lzo_bitops_clz32)
+#define lzo_bitops_clz32(v) ((unsigned) __builtin_clz(v))
+#endif
+#if !defined(lzo_bitops_clz64) && defined(WANT_lzo_bitops_clz64) && defined(LZO_UINT64_MAX)
+#define lzo_bitops_clz64(v) ((unsigned) __builtin_clzll(v))
+#endif
+#if !defined(lzo_bitops_ctz32) && defined(WANT_lzo_bitops_ctz32)
+#define lzo_bitops_ctz32(v) ((unsigned) __builtin_ctz(v))
+#endif
+#if !defined(lzo_bitops_ctz64) && defined(WANT_lzo_bitops_ctz64) && defined(LZO_UINT64_MAX)
+#define lzo_bitops_ctz64(v) ((unsigned) __builtin_ctzll(v))
+#endif
+#if !defined(lzo_bitops_popcount32) && defined(WANT_lzo_bitops_popcount32)
+#define lzo_bitops_popcount32(v) ((unsigned) __builtin_popcount(v))
+#endif
+#if !defined(lzo_bitops_popcount32) && defined(WANT_lzo_bitops_popcount64) && defined(LZO_UINT64_MAX)
+#define lzo_bitops_popcount64(v) ((unsigned) __builtin_popcountll(v))
+#endif
+#endif
+
+#if 0
+#define u2p(ptr,off) ((lzo_voidp) (((lzo_bytep)(lzo_voidp)(ptr)) + (off)))
+#else
+static __lzo_noinline lzo_voidp u2p(lzo_voidp ptr, lzo_uint off)
+{
+    return (lzo_voidp) ((lzo_bytep) ptr + off);
+}
+#endif
+
+LZO_PUBLIC(int)
+_lzo_config_check(void)
+{
+    lzo_bool r = 1;
+    union {
+        lzo_xint a[2]; unsigned char b[2*LZO_MAX(8,sizeof(lzo_xint))];
+#if defined(LZO_UNALIGNED_OK_8)
+        lzo_uint64 c[2];
+#endif
+        unsigned short x[2]; lzo_uint32 y[2]; lzo_uint z[2];
+    } u;
+    lzo_voidp p;
+
+    u.a[0] = u.a[1] = 0;
+    p = u2p(&u, 0);
+    r &= ((* (lzo_bytep) p) == 0);
+#if !defined(LZO_CFG_NO_CONFIG_CHECK)
+#if defined(LZO_ABI_BIG_ENDIAN)
+    u.a[0] = u.a[1] = 0; u.b[sizeof(lzo_uint) - 1] = 128;
+    p = u2p(&u, 0);
+    r &= ((* (lzo_uintp) p) == 128);
+#endif
+#if defined(LZO_ABI_LITTLE_ENDIAN)
+    u.a[0] = u.a[1] = 0; u.b[0] = 128;
+    p = u2p(&u, 0);
+    r &= ((* (lzo_uintp) p) == 128);
+#endif
+#if defined(LZO_UNALIGNED_OK_2)
+    u.a[0] = u.a[1] = 0;
+    u.b[0] = 1; u.b[sizeof(unsigned short) + 1] = 2;
+    p = u2p(&u, 1);
+    r &= ((* (lzo_ushortp) p) == 0);
+#endif
+#if defined(LZO_UNALIGNED_OK_4)
+    u.a[0] = u.a[1] = 0;
+    u.b[0] = 3; u.b[sizeof(lzo_uint32) + 1] = 4;
+    p = u2p(&u, 1);
+    r &= ((* (lzo_uint32p) p) == 0);
+#endif
+#if defined(LZO_UNALIGNED_OK_8)
+    u.c[0] = u.c[1] = 0;
+    u.b[0] = 5; u.b[sizeof(lzo_uint64) + 1] = 6;
+    p = u2p(&u, 1);
+    r &= ((* (lzo_uint64p) p) == 0);
+#endif
+#if defined(lzo_bitops_clz32)
+    { unsigned i; lzo_uint32 v = 1;
+    for (i = 0; i < 31; i++, v <<= 1)
+        r &= lzo_bitops_clz32(v) == 31 - i;
+    }
+#endif
+#if defined(lzo_bitops_clz64)
+    { unsigned i; lzo_uint64 v = 1;
+    for (i = 0; i < 63; i++, v <<= 1)
+        r &= lzo_bitops_clz64(v) == 63 - i;
+    }
+#endif
+#if defined(lzo_bitops_ctz32)
+    { unsigned i; lzo_uint32 v = 1;
+    for (i = 0; i < 31; i++, v <<= 1)
+        r &= lzo_bitops_ctz32(v) == i;
+    }
+#endif
+#if defined(lzo_bitops_ctz64)
+    { unsigned i; lzo_uint64 v = 1;
+    for (i = 0; i < 63; i++, v <<= 1)
+        r &= lzo_bitops_ctz64(v) == i;
+    }
+#endif
+#endif
+
+    return r == 1 ? LZO_E_OK : LZO_E_ERROR;
+}
+
+LZO_PUBLIC(int)
+__lzo_init_v2(unsigned v, int s1, int s2, int s3, int s4, int s5,
+                          int s6, int s7, int s8, int s9)
+{
+    int r;
+
+#if defined(__LZO_IN_MINILZO)
+#elif (LZO_CC_MSC && ((_MSC_VER) < 700))
+#else
+#define ACC_WANT_ACC_CHK_CH 1
+#undef ACCCHK_ASSERT
+#define ACCCHK_ASSERT(expr)  LZO_COMPILE_TIME_ASSERT(expr)
+#endif
+#undef ACCCHK_ASSERT
+
+    if (v == 0)
+        return LZO_E_ERROR;
+
+    r = (s1 == -1 || s1 == (int) sizeof(short)) &&
+        (s2 == -1 || s2 == (int) sizeof(int)) &&
+        (s3 == -1 || s3 == (int) sizeof(long)) &&
+        (s4 == -1 || s4 == (int) sizeof(lzo_uint32)) &&
+        (s5 == -1 || s5 == (int) sizeof(lzo_uint)) &&
+        (s6 == -1 || s6 == (int) lzo_sizeof_dict_t) &&
+        (s7 == -1 || s7 == (int) sizeof(char *)) &&
+        (s8 == -1 || s8 == (int) sizeof(lzo_voidp)) &&
+        (s9 == -1 || s9 == (int) sizeof(lzo_callback_t));
+    if (!r)
+        return LZO_E_ERROR;
+
+    r = _lzo_config_check();
+    if (r != LZO_E_OK)
+        return r;
+
+    return r;
+}
+
+#if !defined(__LZO_IN_MINILZO)
+
+#if (LZO_OS_WIN16 && LZO_CC_WATCOMC) && defined(__SW_BD)
+
+#if 0
+BOOL FAR PASCAL LibMain ( HANDLE hInstance, WORD wDataSegment,
+                          WORD wHeapSize, LPSTR lpszCmdLine )
+#else
+int __far __pascal LibMain ( int a, short b, short c, long d )
+#endif
+{
+    LZO_UNUSED(a); LZO_UNUSED(b); LZO_UNUSED(c); LZO_UNUSED(d);
+    return 1;
+}
+
+#endif
+
+#endif
+
+#endif
+
+#define LZO1X           1
+#define LZO_EOF_CODE    1
+#define M2_MAX_OFFSET   0x0800
+
+#if !defined(MINILZO_CFG_SKIP_LZO1X_1_COMPRESS)
+
+#if 1 && defined(UA_GET32)
+#undef  LZO_DICT_USE_PTR
+#define LZO_DICT_USE_PTR 0
+#undef  lzo_dict_t
+#define lzo_dict_t unsigned short
+#endif
+
+#define LZO_NEED_DICT_H 1
+#ifndef D_BITS
+#define D_BITS          14
+#endif
+#define D_INDEX1(d,p)       d = DM(DMUL(0x21,DX3(p,5,5,6)) >> 5)
+#define D_INDEX2(d,p)       d = (d & (D_MASK & 0x7ff)) ^ (D_HIGH | 0x1f)
+#if 1
+#define DINDEX(dv,p)        DM(((DMUL(0x1824429d,dv)) >> (32-D_BITS)))
+#else
+#define DINDEX(dv,p)        DM((dv) + ((dv) >> (32-D_BITS)))
+#endif
+
+#ifndef __LZO_CONFIG1X_H
+#define __LZO_CONFIG1X_H 1
+
+#if !defined(LZO1X) && !defined(LZO1Y) && !defined(LZO1Z)
+#  define LZO1X 1
+#endif
+
+#if !defined(__LZO_IN_MINILZO)
+#include "lzo/lzo1x.h"
+#endif
+
+#ifndef LZO_EOF_CODE
+#define LZO_EOF_CODE 1
+#endif
+#undef LZO_DETERMINISTIC
+
+#define M1_MAX_OFFSET   0x0400
+#ifndef M2_MAX_OFFSET
+#define M2_MAX_OFFSET   0x0800
+#endif
+#define M3_MAX_OFFSET   0x4000
+#define M4_MAX_OFFSET   0xbfff
+
+#define MX_MAX_OFFSET   (M1_MAX_OFFSET + M2_MAX_OFFSET)
+
+#define M1_MIN_LEN      2
+#define M1_MAX_LEN      2
+#define M2_MIN_LEN      3
+#ifndef M2_MAX_LEN
+#define M2_MAX_LEN      8
+#endif
+#define M3_MIN_LEN      3
+#define M3_MAX_LEN      33
+#define M4_MIN_LEN      3
+#define M4_MAX_LEN      9
+
+#define M1_MARKER       0
+#define M2_MARKER       64
+#define M3_MARKER       32
+#define M4_MARKER       16
+
+#ifndef MIN_LOOKAHEAD
+#define MIN_LOOKAHEAD       (M2_MAX_LEN + 1)
+#endif
+
+#if defined(LZO_NEED_DICT_H)
+
+#ifndef LZO_HASH
+#define LZO_HASH            LZO_HASH_LZO_INCREMENTAL_B
+#endif
+#define DL_MIN_LEN          M2_MIN_LEN
+
+#ifndef __LZO_DICT_H
+#define __LZO_DICT_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if !defined(D_BITS) && defined(DBITS)
+#  define D_BITS        DBITS
+#endif
+#if !defined(D_BITS)
+#  error "D_BITS is not defined"
+#endif
+#if (D_BITS < 16)
+#  define D_SIZE        LZO_SIZE(D_BITS)
+#  define D_MASK        LZO_MASK(D_BITS)
+#else
+#  define D_SIZE        LZO_USIZE(D_BITS)
+#  define D_MASK        LZO_UMASK(D_BITS)
+#endif
+#define D_HIGH          ((D_MASK >> 1) + 1)
+
+#if !defined(DD_BITS)
+#  define DD_BITS       0
+#endif
+#define DD_SIZE         LZO_SIZE(DD_BITS)
+#define DD_MASK         LZO_MASK(DD_BITS)
+
+#if !defined(DL_BITS)
+#  define DL_BITS       (D_BITS - DD_BITS)
+#endif
+#if (DL_BITS < 16)
+#  define DL_SIZE       LZO_SIZE(DL_BITS)
+#  define DL_MASK       LZO_MASK(DL_BITS)
+#else
+#  define DL_SIZE       LZO_USIZE(DL_BITS)
+#  define DL_MASK       LZO_UMASK(DL_BITS)
+#endif
+
+#if (D_BITS != DL_BITS + DD_BITS)
+#  error "D_BITS does not match"
+#endif
+#if (D_BITS < 6 || D_BITS > 18)
+#  error "invalid D_BITS"
+#endif
+#if (DL_BITS < 6 || DL_BITS > 20)
+#  error "invalid DL_BITS"
+#endif
+#if (DD_BITS < 0 || DD_BITS > 6)
+#  error "invalid DD_BITS"
+#endif
+
+#if !defined(DL_MIN_LEN)
+#  define DL_MIN_LEN    3
+#endif
+#if !defined(DL_SHIFT)
+#  define DL_SHIFT      ((DL_BITS + (DL_MIN_LEN - 1)) / DL_MIN_LEN)
+#endif
+
+#define LZO_HASH_GZIP                   1
+#define LZO_HASH_GZIP_INCREMENTAL       2
+#define LZO_HASH_LZO_INCREMENTAL_A      3
+#define LZO_HASH_LZO_INCREMENTAL_B      4
+
+#if !defined(LZO_HASH)
+#  error "choose a hashing strategy"
+#endif
+
+#undef DM
+#undef DX
+
+#if (DL_MIN_LEN == 3)
+#  define _DV2_A(p,shift1,shift2) \
+        (((( (lzo_xint)((p)[0]) << shift1) ^ (p)[1]) << shift2) ^ (p)[2])
+#  define _DV2_B(p,shift1,shift2) \
+        (((( (lzo_xint)((p)[2]) << shift1) ^ (p)[1]) << shift2) ^ (p)[0])
+#  define _DV3_B(p,shift1,shift2,shift3) \
+        ((_DV2_B((p)+1,shift1,shift2) << (shift3)) ^ (p)[0])
+#elif (DL_MIN_LEN == 2)
+#  define _DV2_A(p,shift1,shift2) \
+        (( (lzo_xint)(p[0]) << shift1) ^ p[1])
+#  define _DV2_B(p,shift1,shift2) \
+        (( (lzo_xint)(p[1]) << shift1) ^ p[2])
+#else
+#  error "invalid DL_MIN_LEN"
+#endif
+#define _DV_A(p,shift)      _DV2_A(p,shift,shift)
+#define _DV_B(p,shift)      _DV2_B(p,shift,shift)
+#define DA2(p,s1,s2) \
+        (((((lzo_xint)((p)[2]) << (s2)) + (p)[1]) << (s1)) + (p)[0])
+#define DS2(p,s1,s2) \
+        (((((lzo_xint)((p)[2]) << (s2)) - (p)[1]) << (s1)) - (p)[0])
+#define DX2(p,s1,s2) \
+        (((((lzo_xint)((p)[2]) << (s2)) ^ (p)[1]) << (s1)) ^ (p)[0])
+#define DA3(p,s1,s2,s3) ((DA2((p)+1,s2,s3) << (s1)) + (p)[0])
+#define DS3(p,s1,s2,s3) ((DS2((p)+1,s2,s3) << (s1)) - (p)[0])
+#define DX3(p,s1,s2,s3) ((DX2((p)+1,s2,s3) << (s1)) ^ (p)[0])
+#define DMS(v,s)        ((lzo_uint) (((v) & (D_MASK >> (s))) << (s)))
+#define DM(v)           DMS(v,0)
+
+#if (LZO_HASH == LZO_HASH_GZIP)
+#  define _DINDEX(dv,p)     (_DV_A((p),DL_SHIFT))
+
+#elif (LZO_HASH == LZO_HASH_GZIP_INCREMENTAL)
+#  define __LZO_HASH_INCREMENTAL 1
+#  define DVAL_FIRST(dv,p)  dv = _DV_A((p),DL_SHIFT)
+#  define DVAL_NEXT(dv,p)   dv = (((dv) << DL_SHIFT) ^ p[2])
+#  define _DINDEX(dv,p)     (dv)
+#  define DVAL_LOOKAHEAD    DL_MIN_LEN
+
+#elif (LZO_HASH == LZO_HASH_LZO_INCREMENTAL_A)
+#  define __LZO_HASH_INCREMENTAL 1
+#  define DVAL_FIRST(dv,p)  dv = _DV_A((p),5)
+#  define DVAL_NEXT(dv,p) \
+                dv ^= (lzo_xint)(p[-1]) << (2*5); dv = (((dv) << 5) ^ p[2])
+#  define _DINDEX(dv,p)     ((DMUL(0x9f5f,dv)) >> 5)
+#  define DVAL_LOOKAHEAD    DL_MIN_LEN
+
+#elif (LZO_HASH == LZO_HASH_LZO_INCREMENTAL_B)
+#  define __LZO_HASH_INCREMENTAL 1
+#  define DVAL_FIRST(dv,p)  dv = _DV_B((p),5)
+#  define DVAL_NEXT(dv,p) \
+                dv ^= p[-1]; dv = (((dv) >> 5) ^ ((lzo_xint)(p[2]) << (2*5)))
+#  define _DINDEX(dv,p)     ((DMUL(0x9f5f,dv)) >> 5)
+#  define DVAL_LOOKAHEAD    DL_MIN_LEN
+
+#else
+#  error "choose a hashing strategy"
+#endif
+
+#ifndef DINDEX
+#define DINDEX(dv,p)        ((lzo_uint)((_DINDEX(dv,p)) & DL_MASK) << DD_BITS)
+#endif
+#if !defined(DINDEX1) && defined(D_INDEX1)
+#define DINDEX1             D_INDEX1
+#endif
+#if !defined(DINDEX2) && defined(D_INDEX2)
+#define DINDEX2             D_INDEX2
+#endif
+
+#if !defined(__LZO_HASH_INCREMENTAL)
+#  define DVAL_FIRST(dv,p)  ((void) 0)
+#  define DVAL_NEXT(dv,p)   ((void) 0)
+#  define DVAL_LOOKAHEAD    0
+#endif
+
+#if !defined(DVAL_ASSERT)
+#if defined(__LZO_HASH_INCREMENTAL) && !defined(NDEBUG)
+#if (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x020700ul) || LZO_CC_LLVM)
+static void __attribute__((__unused__))
+#else
+static void
+#endif
+DVAL_ASSERT(lzo_xint dv, const lzo_bytep p)
+{
+    lzo_xint df;
+    DVAL_FIRST(df,(p));
+    assert(DINDEX(dv,p) == DINDEX(df,p));
+}
+#else
+#  define DVAL_ASSERT(dv,p) ((void) 0)
+#endif
+#endif
+
+#if (LZO_DICT_USE_PTR)
+#  define DENTRY(p,in)                          (p)
+#  define GINDEX(m_pos,m_off,dict,dindex,in)    m_pos = dict[dindex]
+#else
+#  define DENTRY(p,in)                          ((lzo_dict_t) pd(p, in))
+#  define GINDEX(m_pos,m_off,dict,dindex,in)    m_off = dict[dindex]
+#endif
+
+#if (DD_BITS == 0)
+
+#  define UPDATE_D(dict,drun,dv,p,in)       dict[ DINDEX(dv,p) ] = DENTRY(p,in)
+#  define UPDATE_I(dict,drun,index,p,in)    dict[index] = DENTRY(p,in)
+#  define UPDATE_P(ptr,drun,p,in)           (ptr)[0] = DENTRY(p,in)
+
+#else
+
+#  define UPDATE_D(dict,drun,dv,p,in)   \
+        dict[ DINDEX(dv,p) + drun++ ] = DENTRY(p,in); drun &= DD_MASK
+#  define UPDATE_I(dict,drun,index,p,in)    \
+        dict[ (index) + drun++ ] = DENTRY(p,in); drun &= DD_MASK
+#  define UPDATE_P(ptr,drun,p,in)   \
+        (ptr) [ drun++ ] = DENTRY(p,in); drun &= DD_MASK
+
+#endif
+
+#if (LZO_DICT_USE_PTR)
+
+#define LZO_CHECK_MPOS_DET(m_pos,m_off,in,ip,max_offset) \
+        (m_pos == NULL || (m_off = pd(ip, m_pos)) > max_offset)
+
+#define LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,max_offset) \
+    (BOUNDS_CHECKING_OFF_IN_EXPR(( \
+        m_pos = ip - (lzo_uint) PTR_DIFF(ip,m_pos), \
+        PTR_LT(m_pos,in) || \
+        (m_off = (lzo_uint) PTR_DIFF(ip,m_pos)) == 0 || \
+         m_off > max_offset )))
+
+#else
+
+#define LZO_CHECK_MPOS_DET(m_pos,m_off,in,ip,max_offset) \
+        (m_off == 0 || \
+         ((m_off = pd(ip, in) - m_off) > max_offset) || \
+         (m_pos = (ip) - (m_off), 0) )
+
+#define LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,max_offset) \
+        (pd(ip, in) <= m_off || \
+         ((m_off = pd(ip, in) - m_off) > max_offset) || \
+         (m_pos = (ip) - (m_off), 0) )
+
+#endif
+
+#if (LZO_DETERMINISTIC)
+#  define LZO_CHECK_MPOS    LZO_CHECK_MPOS_DET
+#else
+#  define LZO_CHECK_MPOS    LZO_CHECK_MPOS_NON_DET
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+#endif
+
+#endif
+
+#define LZO_DETERMINISTIC !(LZO_DICT_USE_PTR)
+
+#ifndef DO_COMPRESS
+#define DO_COMPRESS     lzo1x_1_compress
+#endif
+
+#if 1 && defined(DO_COMPRESS) && !defined(do_compress)
+#  define do_compress       LZO_CPP_ECONCAT2(DO_COMPRESS,_core)
+#endif
+
+#if defined(UA_GET64)
+#  define WANT_lzo_bitops_ctz64 1
+#elif defined(UA_GET32)
+#  define WANT_lzo_bitops_ctz32 1
+#endif
+
+#if (defined(_WIN32) || defined(_WIN64)) && ((LZO_CC_INTELC && (__INTEL_COMPILER >= 1000)) || (LZO_CC_MSC && (_MSC_VER >= 1400)))
+#include <intrin.h>
+#if !defined(lzo_bitops_clz32) && defined(WANT_lzo_bitops_clz32) && 0
+#pragma intrinsic(_BitScanReverse)
+static __lzo_inline unsigned lzo_bitops_clz32(lzo_uint32 v)
+{
+    unsigned long r;
+    (void) _BitScanReverse(&r, v);
+    return (unsigned) r;
+}
+#define lzo_bitops_clz32 lzo_bitops_clz32
+#endif
+#if !defined(lzo_bitops_clz64) && defined(WANT_lzo_bitops_clz64) && defined(LZO_UINT64_MAX) && 0
+#pragma intrinsic(_BitScanReverse64)
+static __lzo_inline unsigned lzo_bitops_clz64(lzo_uint64 v)
+{
+    unsigned long r;
+    (void) _BitScanReverse64(&r, v);
+    return (unsigned) r;
+}
+#define lzo_bitops_clz64 lzo_bitops_clz64
+#endif
+#if !defined(lzo_bitops_ctz32) && defined(WANT_lzo_bitops_ctz32)
+#pragma intrinsic(_BitScanForward)
+static __lzo_inline unsigned lzo_bitops_ctz32(lzo_uint32 v)
+{
+    unsigned long r;
+    (void) _BitScanForward(&r, v);
+    return (unsigned) r;
+}
+#define lzo_bitops_ctz32 lzo_bitops_ctz32
+#endif
+#if !defined(lzo_bitops_ctz64) && defined(WANT_lzo_bitops_ctz64) && defined(LZO_UINT64_MAX)
+#pragma intrinsic(_BitScanForward64)
+static __lzo_inline unsigned lzo_bitops_ctz64(lzo_uint64 v)
+{
+    unsigned long r;
+    (void) _BitScanForward64(&r, v);
+    return (unsigned) r;
+}
+#define lzo_bitops_ctz64 lzo_bitops_ctz64
+#endif
+
+#elif (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x030400ul) || (LZO_CC_INTELC && (__INTEL_COMPILER >= 1000)) || LZO_CC_LLVM)
+#if !defined(lzo_bitops_clz32) && defined(WANT_lzo_bitops_clz32)
+#define lzo_bitops_clz32(v) ((unsigned) __builtin_clz(v))
+#endif
+#if !defined(lzo_bitops_clz64) && defined(WANT_lzo_bitops_clz64) && defined(LZO_UINT64_MAX)
+#define lzo_bitops_clz64(v) ((unsigned) __builtin_clzll(v))
+#endif
+#if !defined(lzo_bitops_ctz32) && defined(WANT_lzo_bitops_ctz32)
+#define lzo_bitops_ctz32(v) ((unsigned) __builtin_ctz(v))
+#endif
+#if !defined(lzo_bitops_ctz64) && defined(WANT_lzo_bitops_ctz64) && defined(LZO_UINT64_MAX)
+#define lzo_bitops_ctz64(v) ((unsigned) __builtin_ctzll(v))
+#endif
+#if !defined(lzo_bitops_popcount32) && defined(WANT_lzo_bitops_popcount32)
+#define lzo_bitops_popcount32(v) ((unsigned) __builtin_popcount(v))
+#endif
+#if !defined(lzo_bitops_popcount32) && defined(WANT_lzo_bitops_popcount64) && defined(LZO_UINT64_MAX)
+#define lzo_bitops_popcount64(v) ((unsigned) __builtin_popcountll(v))
+#endif
+#endif
+
+static __lzo_noinline lzo_uint
+do_compress ( const lzo_bytep in , lzo_uint  in_len,
+                    lzo_bytep out, lzo_uintp out_len,
+                    lzo_uint  ti,  lzo_voidp wrkmem)
+{
+    register const lzo_bytep ip;
+    lzo_bytep op;
+    const lzo_bytep const in_end = in + in_len;
+    const lzo_bytep const ip_end = in + in_len - 20;
+    const lzo_bytep ii;
+    lzo_dict_p const dict = (lzo_dict_p) wrkmem;
+
+    op = out;
+    ip = in;
+    ii = ip - ti;
+
+    ip += ti < 4 ? 4 - ti : 0;
+    for (;;)
+    {
+        const lzo_bytep m_pos;
+#if !(LZO_DETERMINISTIC)
+        LZO_DEFINE_UNINITIALIZED_VAR(lzo_uint, m_off, 0);
+        lzo_uint m_len;
+        lzo_uint dindex;
+next:
+        if __lzo_unlikely(ip >= ip_end)
+            break;
+        DINDEX1(dindex,ip);
+        GINDEX(m_pos,m_off,dict,dindex,in);
+        if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET))
+            goto literal;
+#if 1
+        if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3])
+            goto try_match;
+        DINDEX2(dindex,ip);
+#endif
+        GINDEX(m_pos,m_off,dict,dindex,in);
+        if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET))
+            goto literal;
+        if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3])
+            goto try_match;
+        goto literal;
+
+try_match:
+#if defined(UA_GET32)
+        if (UA_GET32(m_pos) != UA_GET32(ip))
+#else
+        if (m_pos[0] != ip[0] || m_pos[1] != ip[1] || m_pos[2] != ip[2] || m_pos[3] != ip[3])
+#endif
+        {
+literal:
+            UPDATE_I(dict,0,dindex,ip,in);
+            ip += 1 + ((ip - ii) >> 5);
+            continue;
+        }
+        UPDATE_I(dict,0,dindex,ip,in);
+#else
+        lzo_uint m_off;
+        lzo_uint m_len;
+        {
+        lzo_uint32 dv;
+        lzo_uint dindex;
+literal:
+        ip += 1 + ((ip - ii) >> 5);
+next:
+        if __lzo_unlikely(ip >= ip_end)
+            break;
+        dv = UA_GET32(ip);
+        dindex = DINDEX(dv,ip);
+        GINDEX(m_off,m_pos,in+dict,dindex,in);
+        UPDATE_I(dict,0,dindex,ip,in);
+        if __lzo_unlikely(dv != UA_GET32(m_pos))
+            goto literal;
+        }
+#endif
+
+        {
+        register lzo_uint t = pd(ip,ii);
+        if (t != 0)
+        {
+            if (t <= 3)
+            {
+                op[-2] |= LZO_BYTE(t);
+#if defined(UA_COPY32)
+                UA_COPY32(op, ii);
+                op += t;
+#else
+                { do *op++ = *ii++; while (--t > 0); }
+#endif
+            }
+#if defined(UA_COPY32) || defined(UA_COPY64)
+            else if (t <= 16)
+            {
+                *op++ = LZO_BYTE(t - 3);
+#if defined(UA_COPY64)
+                UA_COPY64(op, ii);
+                UA_COPY64(op+8, ii+8);
+#else
+                UA_COPY32(op, ii);
+                UA_COPY32(op+4, ii+4);
+                UA_COPY32(op+8, ii+8);
+                UA_COPY32(op+12, ii+12);
+#endif
+                op += t;
+            }
+#endif
+            else
+            {
+                if (t <= 18)
+                    *op++ = LZO_BYTE(t - 3);
+                else
+                {
+                    register lzo_uint tt = t - 18;
+                    *op++ = 0;
+                    while __lzo_unlikely(tt > 255)
+                    {
+                        tt -= 255;
+#if 1 && (LZO_CC_MSC && (_MSC_VER >= 1400))
+                        * (volatile unsigned char *) op++ = 0;
+#else
+                        *op++ = 0;
+#endif
+                    }
+                    assert(tt > 0);
+                    *op++ = LZO_BYTE(tt);
+                }
+#if defined(UA_COPY32) || defined(UA_COPY64)
+                do {
+#if defined(UA_COPY64)
+                    UA_COPY64(op, ii);
+                    UA_COPY64(op+8, ii+8);
+#else
+                    UA_COPY32(op, ii);
+                    UA_COPY32(op+4, ii+4);
+                    UA_COPY32(op+8, ii+8);
+                    UA_COPY32(op+12, ii+12);
+#endif
+                    op += 16; ii += 16; t -= 16;
+                } while (t >= 16); if (t > 0)
+#endif
+                { do *op++ = *ii++; while (--t > 0); }
+            }
+        }
+        }
+        m_len = 4;
+        {
+#if defined(UA_GET64)
+        lzo_uint64 v;
+        v = UA_GET64(ip + m_len) ^ UA_GET64(m_pos + m_len);
+        if __lzo_unlikely(v == 0) {
+            do {
+                m_len += 8;
+                v = UA_GET64(ip + m_len) ^ UA_GET64(m_pos + m_len);
+                if __lzo_unlikely(ip + m_len >= ip_end)
+                    goto m_len_done;
+            } while (v == 0);
+        }
+#if (LZO_ABI_LITTLE_ENDIAN) && defined(lzo_bitops_ctz64)
+        m_len += lzo_bitops_ctz64(v) / CHAR_BIT;
+#elif (LZO_ABI_LITTLE_ENDIAN)
+        if ((v & UCHAR_MAX) == 0) do {
+            v >>= CHAR_BIT;
+            m_len += 1;
+        } while ((v & UCHAR_MAX) == 0);
+#else
+        if (ip[m_len] == m_pos[m_len]) do {
+            m_len += 1;
+        } while (ip[m_len] == m_pos[m_len]);
+#endif
+#elif defined(UA_GET32)
+        lzo_uint32 v;
+        v = UA_GET32(ip + m_len) ^ UA_GET32(m_pos + m_len);
+        if __lzo_unlikely(v == 0) {
+            do {
+                m_len += 4;
+                v = UA_GET32(ip + m_len) ^ UA_GET32(m_pos + m_len);
+                if __lzo_unlikely(ip + m_len >= ip_end)
+                    goto m_len_done;
+            } while (v == 0);
+        }
+#if (LZO_ABI_LITTLE_ENDIAN) && defined(lzo_bitops_ctz32)
+        m_len += lzo_bitops_ctz32(v) / CHAR_BIT;
+#elif (LZO_ABI_LITTLE_ENDIAN)
+        if ((v & UCHAR_MAX) == 0) do {
+            v >>= CHAR_BIT;
+            m_len += 1;
+        } while ((v & UCHAR_MAX) == 0);
+#else
+        if (ip[m_len] == m_pos[m_len]) do {
+            m_len += 1;
+        } while (ip[m_len] == m_pos[m_len]);
+#endif
+#else
+        if __lzo_unlikely(ip[m_len] == m_pos[m_len]) {
+            do {
+                m_len += 1;
+                if __lzo_unlikely(ip + m_len >= ip_end)
+                    goto m_len_done;
+            } while (ip[m_len] == m_pos[m_len]);
+        }
+#endif
+        }
+m_len_done:
+        m_off = pd(ip,m_pos);
+        ip += m_len;
+        ii = ip;
+        if (m_len <= M2_MAX_LEN && m_off <= M2_MAX_OFFSET)
+        {
+            m_off -= 1;
+#if defined(LZO1X)
+            *op++ = LZO_BYTE(((m_len - 1) << 5) | ((m_off & 7) << 2));
+            *op++ = LZO_BYTE(m_off >> 3);
+#elif defined(LZO1Y)
+            *op++ = LZO_BYTE(((m_len + 1) << 4) | ((m_off & 3) << 2));
+            *op++ = LZO_BYTE(m_off >> 2);
+#endif
+        }
+        else if (m_off <= M3_MAX_OFFSET)
+        {
+            m_off -= 1;
+            if (m_len <= M3_MAX_LEN)
+                *op++ = LZO_BYTE(M3_MARKER | (m_len - 2));
+            else
+            {
+                m_len -= M3_MAX_LEN;
+                *op++ = M3_MARKER | 0;
+                while __lzo_unlikely(m_len > 255)
+                {
+                    m_len -= 255;
+#if 1 && (LZO_CC_MSC && (_MSC_VER >= 1400))
+                    * (volatile unsigned char *) op++ = 0;
+#else
+                    *op++ = 0;
+#endif
+                }
+                *op++ = LZO_BYTE(m_len);
+            }
+            *op++ = LZO_BYTE(m_off << 2);
+            *op++ = LZO_BYTE(m_off >> 6);
+        }
+        else
+        {
+            m_off -= 0x4000;
+            if (m_len <= M4_MAX_LEN)
+                *op++ = LZO_BYTE(M4_MARKER | ((m_off >> 11) & 8) | (m_len - 2));
+            else
+            {
+                m_len -= M4_MAX_LEN;
+                *op++ = LZO_BYTE(M4_MARKER | ((m_off >> 11) & 8));
+                while __lzo_unlikely(m_len > 255)
+                {
+                    m_len -= 255;
+#if 1 && (LZO_CC_MSC && (_MSC_VER >= 1400))
+                    * (volatile unsigned char *) op++ = 0;
+#else
+                    *op++ = 0;
+#endif
+                }
+                *op++ = LZO_BYTE(m_len);
+            }
+            *op++ = LZO_BYTE(m_off << 2);
+            *op++ = LZO_BYTE(m_off >> 6);
+        }
+        goto next;
+    }
+
+    *out_len = pd(op, out);
+    return pd(in_end,ii);
+}
+
+LZO_PUBLIC(int)
+DO_COMPRESS      ( const lzo_bytep in , lzo_uint  in_len,
+                         lzo_bytep out, lzo_uintp out_len,
+                         lzo_voidp wrkmem )
+{
+    const lzo_bytep ip = in;
+    lzo_bytep op = out;
+    lzo_uint l = in_len;
+    lzo_uint t = 0;
+
+    while (l > 20)
+    {
+        lzo_uint ll = l;
+        lzo_uintptr_t ll_end;
+#if 0 || (LZO_DETERMINISTIC)
+        ll = LZO_MIN(ll, 49152);
+#endif
+        ll_end = (lzo_uintptr_t)ip + ll;
+        if ((ll_end + ((t + ll) >> 5)) <= ll_end || (const lzo_bytep)(ll_end + ((t + ll) >> 5)) <= ip + ll)
+            break;
+#if (LZO_DETERMINISTIC)
+        lzo_memset(wrkmem, 0, ((lzo_uint)1 << D_BITS) * sizeof(lzo_dict_t));
+#endif
+        t = do_compress(ip,ll,op,out_len,t,wrkmem);
+        ip += ll;
+        op += *out_len;
+        l  -= ll;
+    }
+    t += l;
+
+    if (t > 0)
+    {
+        const lzo_bytep ii = in + in_len - t;
+
+        if (op == out && t <= 238)
+            *op++ = LZO_BYTE(17 + t);
+        else if (t <= 3)
+            op[-2] |= LZO_BYTE(t);
+        else if (t <= 18)
+            *op++ = LZO_BYTE(t - 3);
+        else
+        {
+            lzo_uint tt = t - 18;
+
+            *op++ = 0;
+            while (tt > 255)
+            {
+                tt -= 255;
+#if 1 && (LZO_CC_MSC && (_MSC_VER >= 1400))
+
+                * (volatile unsigned char *) op++ = 0;
+#else
+                *op++ = 0;
+#endif
+            }
+            assert(tt > 0);
+            *op++ = LZO_BYTE(tt);
+        }
+        do *op++ = *ii++; while (--t > 0);
+    }
+
+    *op++ = M4_MARKER | 1;
+    *op++ = 0;
+    *op++ = 0;
+
+    *out_len = pd(op, out);
+    return LZO_E_OK;
+}
+
+#endif
+
+#undef do_compress
+#undef DO_COMPRESS
+#undef LZO_HASH
+
+#undef LZO_TEST_OVERRUN
+#undef DO_DECOMPRESS
+#define DO_DECOMPRESS       lzo1x_decompress
+
+#if !defined(MINILZO_CFG_SKIP_LZO1X_DECOMPRESS)
+
+#if defined(LZO_TEST_OVERRUN)
+#  if !defined(LZO_TEST_OVERRUN_INPUT)
+#    define LZO_TEST_OVERRUN_INPUT       2
+#  endif
+#  if !defined(LZO_TEST_OVERRUN_OUTPUT)
+#    define LZO_TEST_OVERRUN_OUTPUT      2
+#  endif
+#  if !defined(LZO_TEST_OVERRUN_LOOKBEHIND)
+#    define LZO_TEST_OVERRUN_LOOKBEHIND  1
+#  endif
+#endif
+
+#undef TEST_IP
+#undef TEST_OP
+#undef TEST_LB
+#undef TEST_LBO
+#undef NEED_IP
+#undef NEED_OP
+#undef HAVE_TEST_IP
+#undef HAVE_TEST_OP
+#undef HAVE_NEED_IP
+#undef HAVE_NEED_OP
+#undef HAVE_ANY_IP
+#undef HAVE_ANY_OP
+
+#if defined(LZO_TEST_OVERRUN_INPUT)
+#  if (LZO_TEST_OVERRUN_INPUT >= 1)
+#    define TEST_IP             (ip < ip_end)
+#  endif
+#  if (LZO_TEST_OVERRUN_INPUT >= 2)
+#    define NEED_IP(x) \
+            if ((lzo_uint)(ip_end - ip) < (lzo_uint)(x))  goto input_overrun
+#  endif
+#endif
+
+#if defined(LZO_TEST_OVERRUN_OUTPUT)
+#  if (LZO_TEST_OVERRUN_OUTPUT >= 1)
+#    define TEST_OP             (op <= op_end)
+#  endif
+#  if (LZO_TEST_OVERRUN_OUTPUT >= 2)
+#    undef TEST_OP
+#    define NEED_OP(x) \
+            if ((lzo_uint)(op_end - op) < (lzo_uint)(x))  goto output_overrun
+#  endif
+#endif
+
+#if defined(LZO_TEST_OVERRUN_LOOKBEHIND)
+#  define TEST_LB(m_pos)        if (m_pos < out || m_pos >= op) goto lookbehind_overrun
+#  define TEST_LBO(m_pos,o)     if (m_pos < out || m_pos >= op - (o)) goto lookbehind_overrun
+#else
+#  define TEST_LB(m_pos)        ((void) 0)
+#  define TEST_LBO(m_pos,o)     ((void) 0)
+#endif
+
+#if !defined(LZO_EOF_CODE) && !defined(TEST_IP)
+#  define TEST_IP               (ip < ip_end)
+#endif
+
+#if defined(TEST_IP)
+#  define HAVE_TEST_IP 1
+#else
+#  define TEST_IP               1
+#endif
+#if defined(TEST_OP)
+#  define HAVE_TEST_OP 1
+#else
+#  define TEST_OP               1
+#endif
+
+#if defined(NEED_IP)
+#  define HAVE_NEED_IP 1
+#else
+#  define NEED_IP(x)            ((void) 0)
+#endif
+#if defined(NEED_OP)
+#  define HAVE_NEED_OP 1
+#else
+#  define NEED_OP(x)            ((void) 0)
+#endif
+
+#if defined(HAVE_TEST_IP) || defined(HAVE_NEED_IP)
+#  define HAVE_ANY_IP 1
+#endif
+#if defined(HAVE_TEST_OP) || defined(HAVE_NEED_OP)
+#  define HAVE_ANY_OP 1
+#endif
+
+#if defined(DO_DECOMPRESS)
+LZO_PUBLIC(int)
+DO_DECOMPRESS  ( const lzo_bytep in , lzo_uint  in_len,
+                       lzo_bytep out, lzo_uintp out_len,
+                       lzo_voidp wrkmem )
+#endif
+{
+    register lzo_bytep op;
+    register const lzo_bytep ip;
+    register lzo_uint t;
+#if defined(COPY_DICT)
+    lzo_uint m_off;
+    const lzo_bytep dict_end;
+#else
+    register const lzo_bytep m_pos;
+#endif
+
+    const lzo_bytep const ip_end = in + in_len;
+#if defined(HAVE_ANY_OP)
+    lzo_bytep const op_end = out + *out_len;
+#endif
+#if defined(LZO1Z)
+    lzo_uint last_m_off = 0;
+#endif
+
+    LZO_UNUSED(wrkmem);
+
+#if defined(COPY_DICT)
+    if (dict)
+    {
+        if (dict_len > M4_MAX_OFFSET)
+        {
+            dict += dict_len - M4_MAX_OFFSET;
+            dict_len = M4_MAX_OFFSET;
+        }
+        dict_end = dict + dict_len;
+    }
+    else
+    {
+        dict_len = 0;
+        dict_end = NULL;
+    }
+#endif
+
+    *out_len = 0;
+
+    op = out;
+    ip = in;
+
+    if (*ip > 17)
+    {
+        t = *ip++ - 17;
+        if (t < 4)
+            goto match_next;
+        assert(t > 0); NEED_OP(t); NEED_IP(t+1);
+        do *op++ = *ip++; while (--t > 0);
+        goto first_literal_run;
+    }
+
+    while (TEST_IP && TEST_OP)
+    {
+        t = *ip++;
+        if (t >= 16)
+            goto match;
+        if (t == 0)
+        {
+            NEED_IP(1);
+            while (*ip == 0)
+            {
+                t += 255;
+                ip++;
+                NEED_IP(1);
+            }
+            t += 15 + *ip++;
+        }
+        assert(t > 0); NEED_OP(t+3); NEED_IP(t+4);
+#if defined(LZO_UNALIGNED_OK_8) && defined(LZO_UNALIGNED_OK_4)
+        t += 3;
+        if (t >= 8) do
+        {
+            UA_COPY64(op,ip);
+            op += 8; ip += 8; t -= 8;
+        } while (t >= 8);
+        if (t >= 4)
+        {
+            UA_COPY32(op,ip);
+            op += 4; ip += 4; t -= 4;
+        }
+        if (t > 0)
+        {
+            *op++ = *ip++;
+            if (t > 1) { *op++ = *ip++; if (t > 2) { *op++ = *ip++; } }
+        }
+#elif defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
+#if !defined(LZO_UNALIGNED_OK_4)
+        if (PTR_ALIGNED2_4(op,ip))
+        {
+#endif
+        UA_COPY32(op,ip);
+        op += 4; ip += 4;
+        if (--t > 0)
+        {
+            if (t >= 4)
+            {
+                do {
+                    UA_COPY32(op,ip);
+                    op += 4; ip += 4; t -= 4;
+                } while (t >= 4);
+                if (t > 0) do *op++ = *ip++; while (--t > 0);
+            }
+            else
+                do *op++ = *ip++; while (--t > 0);
+        }
+#if !defined(LZO_UNALIGNED_OK_4)
+        }
+        else
+#endif
+#endif
+#if !defined(LZO_UNALIGNED_OK_4) && !defined(LZO_UNALIGNED_OK_8)
+        {
+            *op++ = *ip++; *op++ = *ip++; *op++ = *ip++;
+            do *op++ = *ip++; while (--t > 0);
+        }
+#endif
+
+first_literal_run:
+
+        t = *ip++;
+        if (t >= 16)
+            goto match;
+#if defined(COPY_DICT)
+#if defined(LZO1Z)
+        m_off = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2);
+        last_m_off = m_off;
+#else
+        m_off = (1 + M2_MAX_OFFSET) + (t >> 2) + (*ip++ << 2);
+#endif
+        NEED_OP(3);
+        t = 3; COPY_DICT(t,m_off)
+#else
+#if defined(LZO1Z)
+        t = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2);
+        m_pos = op - t;
+        last_m_off = t;
+#else
+        m_pos = op - (1 + M2_MAX_OFFSET);
+        m_pos -= t >> 2;
+        m_pos -= *ip++ << 2;
+#endif
+        TEST_LB(m_pos); NEED_OP(3);
+        *op++ = *m_pos++; *op++ = *m_pos++; *op++ = *m_pos;
+#endif
+        goto match_done;
+
+        do {
+match:
+            if (t >= 64)
+            {
+#if defined(COPY_DICT)
+#if defined(LZO1X)
+                m_off = 1 + ((t >> 2) & 7) + (*ip++ << 3);
+                t = (t >> 5) - 1;
+#elif defined(LZO1Y)
+                m_off = 1 + ((t >> 2) & 3) + (*ip++ << 2);
+                t = (t >> 4) - 3;
+#elif defined(LZO1Z)
+                m_off = t & 0x1f;
+                if (m_off >= 0x1c)
+                    m_off = last_m_off;
+                else
+                {
+                    m_off = 1 + (m_off << 6) + (*ip++ >> 2);
+                    last_m_off = m_off;
+                }
+                t = (t >> 5) - 1;
+#endif
+#else
+#if defined(LZO1X)
+                m_pos = op - 1;
+                m_pos -= (t >> 2) & 7;
+                m_pos -= *ip++ << 3;
+                t = (t >> 5) - 1;
+#elif defined(LZO1Y)
+                m_pos = op - 1;
+                m_pos -= (t >> 2) & 3;
+                m_pos -= *ip++ << 2;
+                t = (t >> 4) - 3;
+#elif defined(LZO1Z)
+                {
+                    lzo_uint off = t & 0x1f;
+                    m_pos = op;
+                    if (off >= 0x1c)
+                    {
+                        assert(last_m_off > 0);
+                        m_pos -= last_m_off;
+                    }
+                    else
+                    {
+                        off = 1 + (off << 6) + (*ip++ >> 2);
+                        m_pos -= off;
+                        last_m_off = off;
+                    }
+                }
+                t = (t >> 5) - 1;
+#endif
+                TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1);
+                goto copy_match;
+#endif
+            }
+            else if (t >= 32)
+            {
+                t &= 31;
+                if (t == 0)
+                {
+                    NEED_IP(1);
+                    while (*ip == 0)
+                    {
+                        t += 255;
+                        ip++;
+                        NEED_IP(1);
+                    }
+                    t += 31 + *ip++;
+                }
+#if defined(COPY_DICT)
+#if defined(LZO1Z)
+                m_off = 1 + (ip[0] << 6) + (ip[1] >> 2);
+                last_m_off = m_off;
+#else
+                m_off = 1 + (ip[0] >> 2) + (ip[1] << 6);
+#endif
+#else
+#if defined(LZO1Z)
+                {
+                    lzo_uint off = 1 + (ip[0] << 6) + (ip[1] >> 2);
+                    m_pos = op - off;
+                    last_m_off = off;
+                }
+#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN)
+                m_pos = op - 1;
+                m_pos -= UA_GET16(ip) >> 2;
+#else
+                m_pos = op - 1;
+                m_pos -= (ip[0] >> 2) + (ip[1] << 6);
+#endif
+#endif
+                ip += 2;
+            }
+            else if (t >= 16)
+            {
+#if defined(COPY_DICT)
+                m_off = (t & 8) << 11;
+#else
+                m_pos = op;
+                m_pos -= (t & 8) << 11;
+#endif
+                t &= 7;
+                if (t == 0)
+                {
+                    NEED_IP(1);
+                    while (*ip == 0)
+                    {
+                        t += 255;
+                        ip++;
+                        NEED_IP(1);
+                    }
+                    t += 7 + *ip++;
+                }
+#if defined(COPY_DICT)
+#if defined(LZO1Z)
+                m_off += (ip[0] << 6) + (ip[1] >> 2);
+#else
+                m_off += (ip[0] >> 2) + (ip[1] << 6);
+#endif
+                ip += 2;
+                if (m_off == 0)
+                    goto eof_found;
+                m_off += 0x4000;
+#if defined(LZO1Z)
+                last_m_off = m_off;
+#endif
+#else
+#if defined(LZO1Z)
+                m_pos -= (ip[0] << 6) + (ip[1] >> 2);
+#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN)
+                m_pos -= UA_GET16(ip) >> 2;
+#else
+                m_pos -= (ip[0] >> 2) + (ip[1] << 6);
+#endif
+                ip += 2;
+                if (m_pos == op)
+                    goto eof_found;
+                m_pos -= 0x4000;
+#if defined(LZO1Z)
+                last_m_off = pd((const lzo_bytep)op, m_pos);
+#endif
+#endif
+            }
+            else
+            {
+#if defined(COPY_DICT)
+#if defined(LZO1Z)
+                m_off = 1 + (t << 6) + (*ip++ >> 2);
+                last_m_off = m_off;
+#else
+                m_off = 1 + (t >> 2) + (*ip++ << 2);
+#endif
+                NEED_OP(2);
+                t = 2; COPY_DICT(t,m_off)
+#else
+#if defined(LZO1Z)
+                t = 1 + (t << 6) + (*ip++ >> 2);
+                m_pos = op - t;
+                last_m_off = t;
+#else
+                m_pos = op - 1;
+                m_pos -= t >> 2;
+                m_pos -= *ip++ << 2;
+#endif
+                TEST_LB(m_pos); NEED_OP(2);
+                *op++ = *m_pos++; *op++ = *m_pos;
+#endif
+                goto match_done;
+            }
+
+#if defined(COPY_DICT)
+
+            NEED_OP(t+3-1);
+            t += 3-1; COPY_DICT(t,m_off)
+
+#else
+
+            TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1);
+#if defined(LZO_UNALIGNED_OK_8) && defined(LZO_UNALIGNED_OK_4)
+            if (op - m_pos >= 8)
+            {
+                t += (3 - 1);
+                if (t >= 8) do
+                {
+                    UA_COPY64(op,m_pos);
+                    op += 8; m_pos += 8; t -= 8;
+                } while (t >= 8);
+                if (t >= 4)
+                {
+                    UA_COPY32(op,m_pos);
+                    op += 4; m_pos += 4; t -= 4;
+                }
+                if (t > 0)
+                {
+                    *op++ = m_pos[0];
+                    if (t > 1) { *op++ = m_pos[1]; if (t > 2) { *op++ = m_pos[2]; } }
+                }
+            }
+            else
+#elif defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
+#if !defined(LZO_UNALIGNED_OK_4)
+            if (t >= 2 * 4 - (3 - 1) && PTR_ALIGNED2_4(op,m_pos))
+            {
+                assert((op - m_pos) >= 4);
+#else
+            if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4)
+            {
+#endif
+                UA_COPY32(op,m_pos);
+                op += 4; m_pos += 4; t -= 4 - (3 - 1);
+                do {
+                    UA_COPY32(op,m_pos);
+                    op += 4; m_pos += 4; t -= 4;
+                } while (t >= 4);
+                if (t > 0) do *op++ = *m_pos++; while (--t > 0);
+            }
+            else
+#endif
+            {
+copy_match:
+                *op++ = *m_pos++; *op++ = *m_pos++;
+                do *op++ = *m_pos++; while (--t > 0);
+            }
+
+#endif
+
+match_done:
+#if defined(LZO1Z)
+            t = ip[-1] & 3;
+#else
+            t = ip[-2] & 3;
+#endif
+            if (t == 0)
+                break;
+
+match_next:
+            assert(t > 0); assert(t < 4); NEED_OP(t); NEED_IP(t+1);
+#if 0
+            do *op++ = *ip++; while (--t > 0);
+#else
+            *op++ = *ip++;
+            if (t > 1) { *op++ = *ip++; if (t > 2) { *op++ = *ip++; } }
+#endif
+            t = *ip++;
+        } while (TEST_IP && TEST_OP);
+    }
+
+#if defined(HAVE_TEST_IP) || defined(HAVE_TEST_OP)
+    *out_len = pd(op, out);
+    return LZO_E_EOF_NOT_FOUND;
+#endif
+
+eof_found:
+    assert(t == 1);
+    *out_len = pd(op, out);
+    return (ip == ip_end ? LZO_E_OK :
+           (ip < ip_end  ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN));
+
+#if defined(HAVE_NEED_IP)
+input_overrun:
+    *out_len = pd(op, out);
+    return LZO_E_INPUT_OVERRUN;
+#endif
+
+#if defined(HAVE_NEED_OP)
+output_overrun:
+    *out_len = pd(op, out);
+    return LZO_E_OUTPUT_OVERRUN;
+#endif
+
+#if defined(LZO_TEST_OVERRUN_LOOKBEHIND)
+lookbehind_overrun:
+    *out_len = pd(op, out);
+    return LZO_E_LOOKBEHIND_OVERRUN;
+#endif
+}
+
+#endif
+
+#define LZO_TEST_OVERRUN 1
+#undef DO_DECOMPRESS
+#define DO_DECOMPRESS       lzo1x_decompress_safe
+
+#if !defined(MINILZO_CFG_SKIP_LZO1X_DECOMPRESS_SAFE)
+
+#if defined(LZO_TEST_OVERRUN)
+#  if !defined(LZO_TEST_OVERRUN_INPUT)
+#    define LZO_TEST_OVERRUN_INPUT       2
+#  endif
+#  if !defined(LZO_TEST_OVERRUN_OUTPUT)
+#    define LZO_TEST_OVERRUN_OUTPUT      2
+#  endif
+#  if !defined(LZO_TEST_OVERRUN_LOOKBEHIND)
+#    define LZO_TEST_OVERRUN_LOOKBEHIND  1
+#  endif
+#endif
+
+#undef TEST_IP
+#undef TEST_OP
+#undef TEST_LB
+#undef TEST_LBO
+#undef NEED_IP
+#undef NEED_OP
+#undef HAVE_TEST_IP
+#undef HAVE_TEST_OP
+#undef HAVE_NEED_IP
+#undef HAVE_NEED_OP
+#undef HAVE_ANY_IP
+#undef HAVE_ANY_OP
+
+#if defined(LZO_TEST_OVERRUN_INPUT)
+#  if (LZO_TEST_OVERRUN_INPUT >= 1)
+#    define TEST_IP             (ip < ip_end)
+#  endif
+#  if (LZO_TEST_OVERRUN_INPUT >= 2)
+#    define NEED_IP(x) \
+            if ((lzo_uint)(ip_end - ip) < (lzo_uint)(x))  goto input_overrun
+#  endif
+#endif
+
+#if defined(LZO_TEST_OVERRUN_OUTPUT)
+#  if (LZO_TEST_OVERRUN_OUTPUT >= 1)
+#    define TEST_OP             (op <= op_end)
+#  endif
+#  if (LZO_TEST_OVERRUN_OUTPUT >= 2)
+#    undef TEST_OP
+#    define NEED_OP(x) \
+            if ((lzo_uint)(op_end - op) < (lzo_uint)(x))  goto output_overrun
+#  endif
+#endif
+
+#if defined(LZO_TEST_OVERRUN_LOOKBEHIND)
+#  define TEST_LB(m_pos)        if (m_pos < out || m_pos >= op) goto lookbehind_overrun
+#  define TEST_LBO(m_pos,o)     if (m_pos < out || m_pos >= op - (o)) goto lookbehind_overrun
+#else
+#  define TEST_LB(m_pos)        ((void) 0)
+#  define TEST_LBO(m_pos,o)     ((void) 0)
+#endif
+
+#if !defined(LZO_EOF_CODE) && !defined(TEST_IP)
+#  define TEST_IP               (ip < ip_end)
+#endif
+
+#if defined(TEST_IP)
+#  define HAVE_TEST_IP 1
+#else
+#  define TEST_IP               1
+#endif
+#if defined(TEST_OP)
+#  define HAVE_TEST_OP 1
+#else
+#  define TEST_OP               1
+#endif
+
+#if defined(NEED_IP)
+#  define HAVE_NEED_IP 1
+#else
+#  define NEED_IP(x)            ((void) 0)
+#endif
+#if defined(NEED_OP)
+#  define HAVE_NEED_OP 1
+#else
+#  define NEED_OP(x)            ((void) 0)
+#endif
+
+#if defined(HAVE_TEST_IP) || defined(HAVE_NEED_IP)
+#  define HAVE_ANY_IP 1
+#endif
+#if defined(HAVE_TEST_OP) || defined(HAVE_NEED_OP)
+#  define HAVE_ANY_OP 1
+#endif
+
+#if defined(DO_DECOMPRESS)
+LZO_PUBLIC(int)
+DO_DECOMPRESS  ( const lzo_bytep in , lzo_uint  in_len,
+                       lzo_bytep out, lzo_uintp out_len,
+                       lzo_voidp wrkmem )
+#endif
+{
+    register lzo_bytep op;
+    register const lzo_bytep ip;
+    register lzo_uint t;
+#if defined(COPY_DICT)
+    lzo_uint m_off;
+    const lzo_bytep dict_end;
+#else
+    register const lzo_bytep m_pos;
+#endif
+
+    const lzo_bytep const ip_end = in + in_len;
+#if defined(HAVE_ANY_OP)
+    lzo_bytep const op_end = out + *out_len;
+#endif
+#if defined(LZO1Z)
+    lzo_uint last_m_off = 0;
+#endif
+
+    LZO_UNUSED(wrkmem);
+
+#if defined(COPY_DICT)
+    if (dict)
+    {
+        if (dict_len > M4_MAX_OFFSET)
+        {
+            dict += dict_len - M4_MAX_OFFSET;
+            dict_len = M4_MAX_OFFSET;
+        }
+        dict_end = dict + dict_len;
+    }
+    else
+    {
+        dict_len = 0;
+        dict_end = NULL;
+    }
+#endif
+
+    *out_len = 0;
+
+    op = out;
+    ip = in;
+
+    if (*ip > 17)
+    {
+        t = *ip++ - 17;
+        if (t < 4)
+            goto match_next;
+        assert(t > 0); NEED_OP(t); NEED_IP(t+1);
+        do *op++ = *ip++; while (--t > 0);
+        goto first_literal_run;
+    }
+
+    while (TEST_IP && TEST_OP)
+    {
+        t = *ip++;
+        if (t >= 16)
+            goto match;
+        if (t == 0)
+        {
+            NEED_IP(1);
+            while (*ip == 0)
+            {
+                t += 255;
+                ip++;
+                NEED_IP(1);
+            }
+            t += 15 + *ip++;
+        }
+        assert(t > 0); NEED_OP(t+3); NEED_IP(t+4);
+#if defined(LZO_UNALIGNED_OK_8) && defined(LZO_UNALIGNED_OK_4)
+        t += 3;
+        if (t >= 8) do
+        {
+            UA_COPY64(op,ip);
+            op += 8; ip += 8; t -= 8;
+        } while (t >= 8);
+        if (t >= 4)
+        {
+            UA_COPY32(op,ip);
+            op += 4; ip += 4; t -= 4;
+        }
+        if (t > 0)
+        {
+            *op++ = *ip++;
+            if (t > 1) { *op++ = *ip++; if (t > 2) { *op++ = *ip++; } }
+        }
+#elif defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
+#if !defined(LZO_UNALIGNED_OK_4)
+        if (PTR_ALIGNED2_4(op,ip))
+        {
+#endif
+        UA_COPY32(op,ip);
+        op += 4; ip += 4;
+        if (--t > 0)
+        {
+            if (t >= 4)
+            {
+                do {
+                    UA_COPY32(op,ip);
+                    op += 4; ip += 4; t -= 4;
+                } while (t >= 4);
+                if (t > 0) do *op++ = *ip++; while (--t > 0);
+            }
+            else
+                do *op++ = *ip++; while (--t > 0);
+        }
+#if !defined(LZO_UNALIGNED_OK_4)
+        }
+        else
+#endif
+#endif
+#if !defined(LZO_UNALIGNED_OK_4) && !defined(LZO_UNALIGNED_OK_8)
+        {
+            *op++ = *ip++; *op++ = *ip++; *op++ = *ip++;
+            do *op++ = *ip++; while (--t > 0);
+        }
+#endif
+
+first_literal_run:
+
+        t = *ip++;
+        if (t >= 16)
+            goto match;
+#if defined(COPY_DICT)
+#if defined(LZO1Z)
+        m_off = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2);
+        last_m_off = m_off;
+#else
+        m_off = (1 + M2_MAX_OFFSET) + (t >> 2) + (*ip++ << 2);
+#endif
+        NEED_OP(3);
+        t = 3; COPY_DICT(t,m_off)
+#else
+#if defined(LZO1Z)
+        t = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2);
+        m_pos = op - t;
+        last_m_off = t;
+#else
+        m_pos = op - (1 + M2_MAX_OFFSET);
+        m_pos -= t >> 2;
+        m_pos -= *ip++ << 2;
+#endif
+        TEST_LB(m_pos); NEED_OP(3);
+        *op++ = *m_pos++; *op++ = *m_pos++; *op++ = *m_pos;
+#endif
+        goto match_done;
+
+        do {
+match:
+            if (t >= 64)
+            {
+#if defined(COPY_DICT)
+#if defined(LZO1X)
+                m_off = 1 + ((t >> 2) & 7) + (*ip++ << 3);
+                t = (t >> 5) - 1;
+#elif defined(LZO1Y)
+                m_off = 1 + ((t >> 2) & 3) + (*ip++ << 2);
+                t = (t >> 4) - 3;
+#elif defined(LZO1Z)
+                m_off = t & 0x1f;
+                if (m_off >= 0x1c)
+                    m_off = last_m_off;
+                else
+                {
+                    m_off = 1 + (m_off << 6) + (*ip++ >> 2);
+                    last_m_off = m_off;
+                }
+                t = (t >> 5) - 1;
+#endif
+#else
+#if defined(LZO1X)
+                m_pos = op - 1;
+                m_pos -= (t >> 2) & 7;
+                m_pos -= *ip++ << 3;
+                t = (t >> 5) - 1;
+#elif defined(LZO1Y)
+                m_pos = op - 1;
+                m_pos -= (t >> 2) & 3;
+                m_pos -= *ip++ << 2;
+                t = (t >> 4) - 3;
+#elif defined(LZO1Z)
+                {
+                    lzo_uint off = t & 0x1f;
+                    m_pos = op;
+                    if (off >= 0x1c)
+                    {
+                        assert(last_m_off > 0);
+                        m_pos -= last_m_off;
+                    }
+                    else
+                    {
+                        off = 1 + (off << 6) + (*ip++ >> 2);
+                        m_pos -= off;
+                        last_m_off = off;
+                    }
+                }
+                t = (t >> 5) - 1;
+#endif
+                TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1);
+                goto copy_match;
+#endif
+            }
+            else if (t >= 32)
+            {
+                t &= 31;
+                if (t == 0)
+                {
+                    NEED_IP(1);
+                    while (*ip == 0)
+                    {
+                        t += 255;
+                        ip++;
+                        NEED_IP(1);
+                    }
+                    t += 31 + *ip++;
+                }
+#if defined(COPY_DICT)
+#if defined(LZO1Z)
+                m_off = 1 + (ip[0] << 6) + (ip[1] >> 2);
+                last_m_off = m_off;
+#else
+                m_off = 1 + (ip[0] >> 2) + (ip[1] << 6);
+#endif
+#else
+#if defined(LZO1Z)
+                {
+                    lzo_uint off = 1 + (ip[0] << 6) + (ip[1] >> 2);
+                    m_pos = op - off;
+                    last_m_off = off;
+                }
+#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN)
+                m_pos = op - 1;
+                m_pos -= UA_GET16(ip) >> 2;
+#else
+                m_pos = op - 1;
+                m_pos -= (ip[0] >> 2) + (ip[1] << 6);
+#endif
+#endif
+                ip += 2;
+            }
+            else if (t >= 16)
+            {
+#if defined(COPY_DICT)
+                m_off = (t & 8) << 11;
+#else
+                m_pos = op;
+                m_pos -= (t & 8) << 11;
+#endif
+                t &= 7;
+                if (t == 0)
+                {
+                    NEED_IP(1);
+                    while (*ip == 0)
+                    {
+                        t += 255;
+                        ip++;
+                        NEED_IP(1);
+                    }
+                    t += 7 + *ip++;
+                }
+#if defined(COPY_DICT)
+#if defined(LZO1Z)
+                m_off += (ip[0] << 6) + (ip[1] >> 2);
+#else
+                m_off += (ip[0] >> 2) + (ip[1] << 6);
+#endif
+                ip += 2;
+                if (m_off == 0)
+                    goto eof_found;
+                m_off += 0x4000;
+#if defined(LZO1Z)
+                last_m_off = m_off;
+#endif
+#else
+#if defined(LZO1Z)
+                m_pos -= (ip[0] << 6) + (ip[1] >> 2);
+#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN)
+                m_pos -= UA_GET16(ip) >> 2;
+#else
+                m_pos -= (ip[0] >> 2) + (ip[1] << 6);
+#endif
+                ip += 2;
+                if (m_pos == op)
+                    goto eof_found;
+                m_pos -= 0x4000;
+#if defined(LZO1Z)
+                last_m_off = pd((const lzo_bytep)op, m_pos);
+#endif
+#endif
+            }
+            else
+            {
+#if defined(COPY_DICT)
+#if defined(LZO1Z)
+                m_off = 1 + (t << 6) + (*ip++ >> 2);
+                last_m_off = m_off;
+#else
+                m_off = 1 + (t >> 2) + (*ip++ << 2);
+#endif
+                NEED_OP(2);
+                t = 2; COPY_DICT(t,m_off)
+#else
+#if defined(LZO1Z)
+                t = 1 + (t << 6) + (*ip++ >> 2);
+                m_pos = op - t;
+                last_m_off = t;
+#else
+                m_pos = op - 1;
+                m_pos -= t >> 2;
+                m_pos -= *ip++ << 2;
+#endif
+                TEST_LB(m_pos); NEED_OP(2);
+                *op++ = *m_pos++; *op++ = *m_pos;
+#endif
+                goto match_done;
+            }
+
+#if defined(COPY_DICT)
+
+            NEED_OP(t+3-1);
+            t += 3-1; COPY_DICT(t,m_off)
+
+#else
+
+            TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1);
+#if defined(LZO_UNALIGNED_OK_8) && defined(LZO_UNALIGNED_OK_4)
+            if (op - m_pos >= 8)
+            {
+                t += (3 - 1);
+                if (t >= 8) do
+                {
+                    UA_COPY64(op,m_pos);
+                    op += 8; m_pos += 8; t -= 8;
+                } while (t >= 8);
+                if (t >= 4)
+                {
+                    UA_COPY32(op,m_pos);
+                    op += 4; m_pos += 4; t -= 4;
+                }
+                if (t > 0)
+                {
+                    *op++ = m_pos[0];
+                    if (t > 1) { *op++ = m_pos[1]; if (t > 2) { *op++ = m_pos[2]; } }
+                }
+            }
+            else
+#elif defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
+#if !defined(LZO_UNALIGNED_OK_4)
+            if (t >= 2 * 4 - (3 - 1) && PTR_ALIGNED2_4(op,m_pos))
+            {
+                assert((op - m_pos) >= 4);
+#else
+            if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4)
+            {
+#endif
+                UA_COPY32(op,m_pos);
+                op += 4; m_pos += 4; t -= 4 - (3 - 1);
+                do {
+                    UA_COPY32(op,m_pos);
+                    op += 4; m_pos += 4; t -= 4;
+                } while (t >= 4);
+                if (t > 0) do *op++ = *m_pos++; while (--t > 0);
+            }
+            else
+#endif
+            {
+copy_match:
+                *op++ = *m_pos++; *op++ = *m_pos++;
+                do *op++ = *m_pos++; while (--t > 0);
+            }
+
+#endif
+
+match_done:
+#if defined(LZO1Z)
+            t = ip[-1] & 3;
+#else
+            t = ip[-2] & 3;
+#endif
+            if (t == 0)
+                break;
+
+match_next:
+            assert(t > 0); assert(t < 4); NEED_OP(t); NEED_IP(t+1);
+#if 0
+            do *op++ = *ip++; while (--t > 0);
+#else
+            *op++ = *ip++;
+            if (t > 1) { *op++ = *ip++; if (t > 2) { *op++ = *ip++; } }
+#endif
+            t = *ip++;
+        } while (TEST_IP && TEST_OP);
+    }
+
+#if defined(HAVE_TEST_IP) || defined(HAVE_TEST_OP)
+    *out_len = pd(op, out);
+    return LZO_E_EOF_NOT_FOUND;
+#endif
+
+eof_found:
+    assert(t == 1);
+    *out_len = pd(op, out);
+    return (ip == ip_end ? LZO_E_OK :
+           (ip < ip_end  ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN));
+
+#if defined(HAVE_NEED_IP)
+input_overrun:
+    *out_len = pd(op, out);
+    return LZO_E_INPUT_OVERRUN;
+#endif
+
+#if defined(HAVE_NEED_OP)
+output_overrun:
+    *out_len = pd(op, out);
+    return LZO_E_OUTPUT_OVERRUN;
+#endif
+
+#if defined(LZO_TEST_OVERRUN_LOOKBEHIND)
+lookbehind_overrun:
+    *out_len = pd(op, out);
+    return LZO_E_LOOKBEHIND_OVERRUN;
+#endif
+}
+
+#endif
+
+/***** End of minilzo.c *****/
+
diff --git a/filesystems/minilzo.h b/filesystems/minilzo.h
new file mode 100644 (file)
index 0000000..abeca18
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * this file take from grub 2.0
+ * for btrfs UEFI driver
+ */
+
+/* minilzo.h -- mini subset of the LZO real-time data compression library
+
+   This file is part of the LZO real-time data compression library.
+
+   Copyright (C) 2011 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2010 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2009 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
+   All Rights Reserved.
+
+   The LZO library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   The LZO library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with the LZO library; see the file COPYING.
+   If not, write to the Free Software Foundation, Inc.,
+   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+   Markus F.X.J. Oberhumer
+   <markus@oberhumer.com>
+   http://www.oberhumer.com/opensource/lzo/
+ */
+
+/*
+ * NOTE:
+ *   the full LZO package can be found at
+ *   http://www.oberhumer.com/opensource/lzo/
+ */
+
+
+#ifndef __MINILZO_H
+#define __MINILZO_H 1
+
+#define MINILZO_VERSION         0x2050
+
+#ifdef __LZOCONF_H
+#  error "you cannot use both LZO and miniLZO"
+#endif
+
+#undef LZO_HAVE_CONFIG_H
+#include "lzoconf.h"
+
+#if !defined(LZO_VERSION) || (LZO_VERSION != MINILZO_VERSION)
+#  error "version mismatch in header files"
+#endif
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/***********************************************************************
+//
+************************************************************************/
+
+/* Memory required for the wrkmem parameter.
+ * When the required size is 0, you can also pass a NULL pointer.
+ */
+
+#define LZO1X_MEM_COMPRESS      LZO1X_1_MEM_COMPRESS
+#define LZO1X_1_MEM_COMPRESS    ((lzo_uint32) (16384L * lzo_sizeof_dict_t))
+#define LZO1X_MEM_DECOMPRESS    (0)
+
+
+/* compression */
+LZO_EXTERN(int)
+lzo1x_1_compress        ( const lzo_bytep src, lzo_uint  src_len,
+                                lzo_bytep dst, lzo_uintp dst_len,
+                                lzo_voidp wrkmem );
+
+/* decompression */
+LZO_EXTERN(int)
+lzo1x_decompress        ( const lzo_bytep src, lzo_uint  src_len,
+                                lzo_bytep dst, lzo_uintp dst_len,
+                                lzo_voidp wrkmem /* NOT USED */ );
+
+/* safe decompression with overrun testing */
+LZO_EXTERN(int)
+lzo1x_decompress_safe   ( const lzo_bytep src, lzo_uint  src_len,
+                                lzo_bytep dst, lzo_uintp dst_len,
+                                lzo_voidp wrkmem /* NOT USED */ );
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* already included */
+
diff --git a/filesystems/scandisk.c b/filesystems/scandisk.c
new file mode 100644 (file)
index 0000000..d8b862a
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * scandisk.c
+ * Scanning disk for btrfs multi-devices
+ * by Samuel Liao
+ *
+ * Copyright (c) 2013 Tencent, Inc.
+ */
+/*
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "fsw_efi.h"
+#ifdef __MAKEWITH_GNUEFI
+#include "edk2/DriverBinding.h"
+#include "edk2/ComponentName.h"
+extern EFI_GUID gEfiDiskIoProtocolGuid;
+extern EFI_GUID gEfiBlockIoProtocolGuid;
+#endif
+#include "../include/refit_call_wrapper.h"
+
+extern struct fsw_host_table   fsw_efi_host_table;
+static void dummy_volume_free(struct fsw_volume *vol) { }
+static struct fsw_fstype_table   dummy_fstype = {
+    { FSW_STRING_TYPE_UTF8, 4, 4, "dummy" },
+    sizeof(struct fsw_volume),
+    sizeof(struct fsw_dnode),
+
+    NULL, //volume_mount,
+    dummy_volume_free, //volume_free,
+    NULL, //volume_stat,
+    NULL, //dnode_fill,
+    NULL, //dnode_free,
+    NULL, //dnode_stat,
+    NULL, //get_extent,
+    NULL, //dir_lookup,
+    NULL, //dir_read,
+    NULL, //readlink,
+};
+
+static struct fsw_volume *create_dummy_volume(EFI_DISK_IO *diskio, UINT32 mediaid)
+{
+    fsw_status_t err;
+    struct fsw_volume *vol;
+    FSW_VOLUME_DATA *Volume;
+
+    err = fsw_alloc_zero(sizeof(struct fsw_volume), (void **)&vol);
+    if(err)
+        return NULL;
+    err = fsw_alloc_zero(sizeof(FSW_VOLUME_DATA), (void **)&Volume);
+    if(err) {
+        fsw_free(vol);
+        return NULL;
+    }
+    /* fstype_table->volume_free for fsw_unmount */
+    vol->fstype_table = &dummy_fstype;
+    /* host_data needded to fsw_block_get()/fsw_efi_read_block() */
+    Volume->DiskIo = diskio;
+    Volume->MediaId = mediaid;
+
+    vol->host_data = Volume;
+    vol->host_table = &fsw_efi_host_table;
+    return vol;
+}
+
+static struct fsw_volume *clone_dummy_volume(struct fsw_volume *vol)
+{
+    FSW_VOLUME_DATA *Volume = (FSW_VOLUME_DATA *)vol->host_data;
+    return create_dummy_volume(Volume->DiskIo, Volume->MediaId);
+}
+
+static void free_dummy_volume(struct fsw_volume *vol)
+{
+    fsw_free(vol->host_data);
+    fsw_unmount(vol);
+}
+
+static int scan_disks(int (*hook)(struct fsw_volume *, struct fsw_volume *), struct fsw_volume *master)
+{
+    EFI_STATUS  Status;
+    EFI_HANDLE *Handles;
+    UINTN       HandleCount = 0;
+    UINTN       i;
+    UINTN       scanned = 0;
+
+    // Driver hangs if compiled with GNU-EFI unless there's a Print() statement somewhere.
+    // I'm still trying to track that down; in the meantime, work around it....
+#if defined(__MAKEWITH_GNUEFI)
+    Print(L" ");
+#endif
+    DPRINT(L"Scanning disks\n");
+    Status = refit_call5_wrapper(BS->LocateHandleBuffer, ByProtocol, &gEfiDiskIoProtocolGuid, NULL, &HandleCount, &Handles);
+    if (Status == EFI_NOT_FOUND)
+        return -1;  // no filesystems. strange, but true...
+    for (i = 0; i < HandleCount; i++) {
+        EFI_DISK_IO *diskio;
+        EFI_BLOCK_IO *blockio;
+        Status = refit_call3_wrapper(BS->HandleProtocol, Handles[i], &gEfiDiskIoProtocolGuid, (VOID **) &diskio);
+        if (Status != 0)
+            continue;
+        Status = refit_call3_wrapper(BS->HandleProtocol, Handles[i], &gEfiBlockIoProtocolGuid, (VOID **) &blockio);
+        if (Status != 0)
+            continue;
+        struct fsw_volume *vol = create_dummy_volume(diskio, blockio->Media->MediaId);
+        if(vol) {
+            DPRINT(L"Checking disk %d\n", i);
+            if(hook(master, vol) == FSW_SUCCESS)
+                scanned++;
+            free_dummy_volume(vol);
+        }
+    }
+    return scanned;
+}
+
diff --git a/filesystems/test/Makefile b/filesystems/test/Makefile
new file mode 100644 (file)
index 0000000..a15fd3a
--- /dev/null
@@ -0,0 +1,26 @@
+
+DRIVERNAME = xfs
+
+CC             = /usr/bin/gcc
+CFLAGS         = -Wall -g -D_REENTRANT -DVERSION=\"$(VERSION)\" -DHOST_POSIX -I ../ -DFSTYPE=$(DRIVERNAME)
+
+FSW_NAMES       = ../fsw_core ../fsw_lib
+FSW_OBJS       = $(FSW_NAMES:=.o)
+LSLR_OBJS      = $(FSW_OBJS) ../fsw_$(DRIVERNAME).o fsw_posix.o lslr.o
+LSLR_BIN       = lslr
+LSROOT_OBJS    = $(FSW_OBJS) ../fsw_xfs.o .fsw_posix.o lsroot.o
+LSROOT_BIN     = lsroot
+
+
+$(LSLR_BIN):   $(LSLR_OBJS)
+               $(CC) $(CFLAGS) -o $(LSLR_BIN) $(LSLR_OBJS) $(LDFLAGS)
+
+
+$(LSROOT_BIN): $(LSROOT_OBJS) 
+               $(CC) $(CFLAGS) -o $(LSROOT_BIN) $(LSROOT_OBJS) $(LDFLAGS)
+
+all:           $(LSLR_BIN) $(LSROOT_BIN)
+
+clean:         
+               @rm -f *.o ../*.o lslr lsroot
+
diff --git a/filesystems/test/README b/filesystems/test/README
new file mode 100644 (file)
index 0000000..c7c34e4
--- /dev/null
@@ -0,0 +1,2 @@
+This folder contains tests for VBoxFsDxe module, allowing up 
+and test filesystems without EFI environment and launching whole VBox. 
diff --git a/filesystems/test/fsw_posix.c b/filesystems/test/fsw_posix.c
new file mode 100644 (file)
index 0000000..eee8c5f
--- /dev/null
@@ -0,0 +1,479 @@
+/**
+ * \file fsw_posix.c
+ * POSIX user space host environment code.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsw_posix.h"
+
+
+#ifndef FSTYPE
+/** The file system type name to use. */
+#define FSTYPE ext2
+#endif
+
+
+// function prototypes
+
+fsw_status_t fsw_posix_open_dno(struct fsw_posix_volume *pvol, const char *path, int required_type,
+                                struct fsw_shandle *shand);
+
+void fsw_posix_change_blocksize(struct fsw_volume *vol,
+                              fsw_u32 old_phys_blocksize, fsw_u32 old_log_blocksize,
+                              fsw_u32 new_phys_blocksize, fsw_u32 new_log_blocksize);
+fsw_status_t fsw_posix_read_block(struct fsw_volume *vol, fsw_u32 phys_bno, void *buffer);
+
+/**
+ * Dispatch table for our FSW host driver.
+ */
+
+struct fsw_host_table   fsw_posix_host_table = {
+    FSW_STRING_TYPE_ISO88591,
+
+    fsw_posix_change_blocksize,
+    fsw_posix_read_block
+};
+
+extern struct fsw_fstype_table   FSW_FSTYPE_TABLE_NAME(FSTYPE);
+
+
+/**
+ * Mount function.
+ */
+
+struct fsw_posix_volume * fsw_posix_mount(const char *path, struct fsw_fstype_table *fstype_table)
+{
+    fsw_status_t        status;
+    struct fsw_posix_volume *pvol;
+
+    // allocate volume structure
+    status = fsw_alloc_zero(sizeof(struct fsw_posix_volume), (void **)&pvol);
+    if (status)
+        return NULL;
+    pvol->fd = -1;
+
+    // open underlying file/device
+    pvol->fd = open(path, O_RDONLY, 0);
+    if (pvol->fd < 0) {
+        fprintf(stderr, "fsw_posix_mount: %s: %s\n", path, strerror(errno));
+        fsw_free(pvol);
+        return NULL;
+    }
+
+    // mount the filesystem
+    if (fstype_table == NULL)
+        fstype_table = &FSW_FSTYPE_TABLE_NAME(FSTYPE);
+    status = fsw_mount(pvol, &fsw_posix_host_table, fstype_table, &pvol->vol);
+    if (status) {
+        fprintf(stderr, "fsw_posix_mount: fsw_mount returned %d\n", status);
+        fsw_free(pvol);
+        return NULL;
+    }
+
+    return pvol;
+}
+
+/**
+ * Unmount function.
+ */
+
+int fsw_posix_unmount(struct fsw_posix_volume *pvol)
+{
+    if (pvol->vol != NULL)
+        fsw_unmount(pvol->vol);
+    fsw_free(pvol);
+    return 0;
+}
+
+/**
+ * Open a named regular file.
+ */
+
+struct fsw_posix_file * fsw_posix_open(struct fsw_posix_volume *pvol, const char *path, int flags, mode_t mode)
+{
+    fsw_status_t        status;
+    struct fsw_posix_file *file;
+
+    // TODO: check flags for unwanted values
+
+    // allocate file structure
+    status = fsw_alloc(sizeof(struct fsw_posix_file), &file);
+    if (status)
+        return NULL;
+    file->pvol = pvol;
+
+    // open the file
+    status = fsw_posix_open_dno(pvol, path, FSW_DNODE_TYPE_FILE, &file->shand);
+    if (status) {
+        fprintf(stderr, "fsw_posix_open: open_dno returned %d\n", status);
+        fsw_free(file);
+        return NULL;
+    }
+
+    return file;
+}
+
+/**
+ * Read data from a regular file.
+ */
+
+ssize_t fsw_posix_read(struct fsw_posix_file *file, void *buf, size_t nbytes)
+{
+    fsw_status_t        status;
+    fsw_u32             buffer_size;
+
+    buffer_size = nbytes;
+    status = fsw_shandle_read(&file->shand, &buffer_size, buf);
+    if (status)
+        return -1;
+    return buffer_size;
+}
+
+/**
+ * Change position within a regular file.
+ */
+
+off_t fsw_posix_lseek(struct fsw_posix_file *file, off_t offset, int whence)
+{
+    fsw_u64             base_offset = 0;
+
+    // get base offset
+    base_offset = 0;
+    if (whence == SEEK_CUR)
+        base_offset = file->shand.pos;
+    else if (whence == SEEK_END)
+        base_offset = file->shand.dnode->size;
+
+    // calculate new offset, prevent seeks before the start of the file
+    if (offset < 0 && -offset > base_offset)
+        file->shand.pos = 0;
+    else
+        file->shand.pos = base_offset + offset;
+
+    return file->shand.pos;
+}
+
+/**
+ * Close a regular file.
+ */
+
+int fsw_posix_close(struct fsw_posix_file *file)
+{
+    fsw_shandle_close(&file->shand);
+    fsw_free(file);
+    return 0;
+}
+
+/**
+ * Open a directory for iteration.
+ */
+
+struct fsw_posix_dir * fsw_posix_opendir(struct fsw_posix_volume *pvol, const char *path)
+{
+    fsw_status_t        status;
+    struct fsw_posix_dir *dir;
+
+    // allocate file structure
+    status = fsw_alloc(sizeof(struct fsw_posix_dir), &dir);
+    if (status)
+        return NULL;
+    dir->pvol = pvol;
+
+    // open the directory
+    status = fsw_posix_open_dno(pvol, path, FSW_DNODE_TYPE_DIR, &dir->shand);
+    if (status) {
+        fprintf(stderr, "fsw_posix_opendir: open_dno returned %d\n", status);
+        fsw_free(dir);
+        return NULL;
+    }
+
+    return dir;
+}
+
+/**
+ * Read the next entry from a directory.
+ */
+
+struct dirent * fsw_posix_readdir(struct fsw_posix_dir *dir)
+{
+    fsw_status_t        status;
+    struct fsw_dnode    *dno;
+    static struct dirent dent;
+
+    // get next entry from file system
+    status = fsw_dnode_dir_read(&dir->shand, &dno);
+    if (status) {
+        if (status != 4)
+            fprintf(stderr, "fsw_posix_readdir: fsw_dnode_dir_read returned %d\n", status);
+        return NULL;
+    }
+    status = fsw_dnode_fill(dno);
+    if (status) {
+        fprintf(stderr, "fsw_posix_readdir: fsw_dnode_fill returned %d\n", status);
+        fsw_dnode_release(dno);
+        return NULL;
+    }
+
+    // fill dirent structure
+    dent.d_fileno = dno->dnode_id;
+    dent.d_reclen = 8 + dno->name.size + 1;
+    switch (dno->type) {
+        case FSW_DNODE_TYPE_FILE:
+            dent.d_type = DT_REG;
+            break;
+        case FSW_DNODE_TYPE_DIR:
+            dent.d_type = DT_DIR;
+            break;
+        case FSW_DNODE_TYPE_SYMLINK:
+            dent.d_type = DT_LNK;
+            break;
+        default:
+            dent.d_type = DT_UNKNOWN;
+            break;
+    }
+#if 0
+    dent.d_namlen = dno->name.size;
+#endif
+    memcpy(dent.d_name, dno->name.data, dno->name.size);
+    dent.d_name[dno->name.size] = 0;
+
+    return &dent;
+}
+
+/**
+ * Rewind a directory to the start.
+ */
+
+void fsw_posix_rewinddir(struct fsw_posix_dir *dir)
+{
+    dir->shand.pos = 0;
+}
+
+/**
+ * Close a directory.
+ */
+
+int fsw_posix_closedir(struct fsw_posix_dir *dir)
+{
+    fsw_shandle_close(&dir->shand);
+    fsw_free(dir);
+    return 0;
+}
+
+/**
+ * Open a shand of a required type by path.
+ */
+
+fsw_status_t fsw_posix_open_dno(struct fsw_posix_volume *pvol, const char *path, int required_type, struct fsw_shandle *shand)
+{
+    fsw_status_t        status;
+    struct fsw_dnode    *dno;
+    struct fsw_dnode    *target_dno;
+    struct fsw_string   lookup_path;
+
+    lookup_path.type = FSW_STRING_TYPE_ISO88591;
+    lookup_path.len  = strlen(path);
+    lookup_path.size = lookup_path.len;
+    lookup_path.data = (void *)path;
+
+    // resolve the path (symlinks along the way are automatically resolved)
+    status = fsw_dnode_lookup_path(pvol->vol->root, &lookup_path, '/', &dno);
+    if (status) {
+        fprintf(stderr, "fsw_posix_open_dno: fsw_dnode_lookup_path returned %d\n", status);
+        return status;
+    }
+
+    // if the final node is a symlink, also resolve it
+    status = fsw_dnode_resolve(dno, &target_dno);
+    fsw_dnode_release(dno);
+    if (status) {
+        fprintf(stderr, "fsw_posix_open_dno: fsw_dnode_resolve returned %d\n", status);
+        return status;
+    }
+    dno = target_dno;
+
+    // check that it is a regular file
+    status = fsw_dnode_fill(dno);
+    if (status) {
+        fprintf(stderr, "fsw_posix_open_dno: fsw_dnode_fill returned %d\n", status);
+        fsw_dnode_release(dno);
+        return status;
+    }
+    if (dno->type != required_type) {
+        fprintf(stderr, "fsw_posix_open_dno: dnode is not of the requested type\n");
+        fsw_dnode_release(dno);
+        return FSW_UNSUPPORTED;
+    }
+
+    // open shandle
+    status = fsw_shandle_open(dno, shand);
+    if (status) {
+        fprintf(stderr, "fsw_posix_open_dno: fsw_shandle_open returned %d\n", status);
+    }
+    fsw_dnode_release(dno);
+    return status;
+}
+
+/**
+ * FSW interface function for block size changes. This function is called by the FSW core
+ * when the file system driver changes the block sizes for the volume.
+ */
+
+void fsw_posix_change_blocksize(struct fsw_volume *vol,
+                                fsw_u32 old_phys_blocksize, fsw_u32 old_log_blocksize,
+                                fsw_u32 new_phys_blocksize, fsw_u32 new_log_blocksize)
+{
+    // nothing to do
+}
+
+/**
+ * FSW interface function to read data blocks. This function is called by the FSW core
+ * to read a block of data from the device. The buffer is allocated by the core code.
+ */
+
+fsw_status_t fsw_posix_read_block(struct fsw_volume *vol, fsw_u32 phys_bno, void *buffer)
+{
+    struct fsw_posix_volume *pvol = (struct fsw_posix_volume *)vol->host_data;
+    off_t           block_offset, seek_result;
+    ssize_t         read_result;
+
+    FSW_MSG_DEBUGV((FSW_MSGSTR("fsw_posix_read_block: %d  (%d)\n"), phys_bno, vol->phys_blocksize));
+
+    // read from disk
+    block_offset = (off_t)phys_bno * vol->phys_blocksize;
+    seek_result = lseek(pvol->fd, block_offset, SEEK_SET);
+    if (seek_result != block_offset)
+        return FSW_IO_ERROR;
+    read_result = read(pvol->fd, buffer, vol->phys_blocksize);
+    if (read_result != vol->phys_blocksize)
+        return FSW_IO_ERROR;
+
+    return FSW_SUCCESS;
+}
+
+
+/**
+ * Time mapping callback for the fsw_dnode_stat call. This function converts
+ * a Posix style timestamp into an EFI_TIME structure and writes it to the
+ * appropriate member of the EFI_FILE_INFO structure that we're filling.
+ */
+
+/*
+static void fsw_posix_store_time_posix(struct fsw_dnode_stat *sb, int which, fsw_u32 posix_time)
+{
+    EFI_FILE_INFO       *FileInfo = (EFI_FILE_INFO *)sb->host_data;
+
+    if (which == FSW_DNODE_STAT_CTIME)
+        fsw_posix_decode_time(&FileInfo->CreateTime,       posix_time);
+    else if (which == FSW_DNODE_STAT_MTIME)
+        fsw_posix_decode_time(&FileInfo->ModificationTime, posix_time);
+    else if (which == FSW_DNODE_STAT_ATIME)
+        fsw_posix_decode_time(&FileInfo->LastAccessTime,   posix_time);
+}
+*/
+
+/**
+ * Mode mapping callback for the fsw_dnode_stat call. This function looks at
+ * the Posix mode passed by the file system driver and makes appropriate
+ * adjustments to the EFI_FILE_INFO structure that we're filling.
+ */
+
+/*
+static void fsw_posix_store_attr_posix(struct fsw_dnode_stat *sb, fsw_u16 posix_mode)
+{
+    EFI_FILE_INFO       *FileInfo = (EFI_FILE_INFO *)sb->host_data;
+
+    if ((posix_mode & S_IWUSR) == 0)
+        FileInfo->Attribute |= EFI_FILE_READ_ONLY;
+}
+*/
+
+/**
+ * Common function to fill an EFI_FILE_INFO with information about a dnode.
+ */
+
+/*
+EFI_STATUS fsw_posix_dnode_fill_FileInfo(IN FSW_VOLUME_DATA *Volume,
+                                       IN struct fsw_dnode *dno,
+                                       IN OUT UINTN *BufferSize,
+                                       OUT VOID *Buffer)
+{
+    EFI_STATUS          Status;
+    EFI_FILE_INFO       *FileInfo;
+    UINTN               RequiredSize;
+    struct fsw_dnode_stat sb;
+
+    // make sure the dnode has complete info
+    Status = fsw_posix_map_status(fsw_dnode_fill(dno), Volume);
+    if (EFI_ERROR(Status))
+        return Status;
+
+    // TODO: check/assert that the dno's name is in UTF16
+
+    // check buffer size
+    RequiredSize = SIZE_OF_EFI_FILE_INFO + fsw_posix_strsize(&dno->name);
+    if (*BufferSize < RequiredSize) {
+        // TODO: wind back the directory in this case
+
+        *BufferSize = RequiredSize;
+        return EFI_BUFFER_TOO_SMALL;
+    }
+
+    // fill structure
+    ZeroMem(Buffer, RequiredSize);
+    FileInfo = (EFI_FILE_INFO *)Buffer;
+    FileInfo->Size = RequiredSize;
+    FileInfo->FileSize          = dno->size;
+    FileInfo->Attribute         = 0;
+    if (dno->type == FSW_DNODE_TYPE_DIR)
+        FileInfo->Attribute    |= EFI_FILE_DIRECTORY;
+    fsw_posix_strcpy(FileInfo->FileName, &dno->name);
+
+    // get the missing info from the fs driver
+    ZeroMem(&sb, sizeof(struct fsw_dnode_stat));
+    sb.store_time_posix = fsw_posix_store_time_posix;
+    sb.store_attr_posix = fsw_posix_store_attr_posix;
+    sb.host_data = FileInfo;
+    Status = fsw_posix_map_status(fsw_dnode_stat(dno, &sb), Volume);
+    if (EFI_ERROR(Status))
+        return Status;
+    FileInfo->PhysicalSize      = sb.used_bytes;
+
+    // prepare for return
+    *BufferSize = RequiredSize;
+    return EFI_SUCCESS;
+}
+*/
+
+// EOF
diff --git a/filesystems/test/fsw_posix.h b/filesystems/test/fsw_posix.h
new file mode 100644 (file)
index 0000000..8ab72f5
--- /dev/null
@@ -0,0 +1,98 @@
+/**
+ * \file fsw_posix.h
+ * POSIX user space host environment header.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _FSW_POSIX_H_
+#define _FSW_POSIX_H_
+
+#include "fsw_core.h"
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/dir.h>
+
+
+/**
+ * POSIX Host: Private per-volume structure.
+ */
+
+struct fsw_posix_volume {
+    struct fsw_volume           *vol;           //!< FSW volume structure
+
+    int                         fd;             //!< System file descriptor for data access
+
+};
+
+/**
+ * POSIX Host: Private structure for an open file.
+ */
+
+struct fsw_posix_file {
+    struct fsw_posix_volume     *pvol;          //!< POSIX host volume structure
+
+    struct fsw_shandle          shand;          //!< FSW handle for this file
+
+};
+
+/**
+ * POSIX Host: Private structure for an open directory.
+ */
+
+struct fsw_posix_dir {
+    struct fsw_posix_volume     *pvol;          //!< POSIX host volume structure
+
+    struct fsw_shandle          shand;          //!< FSW handle for this file
+
+};
+
+
+/* functions */
+
+struct fsw_posix_volume * fsw_posix_mount(const char *path, struct fsw_fstype_table *fstype_table);
+int fsw_posix_unmount(struct fsw_posix_volume *pvol);
+
+struct fsw_posix_file * fsw_posix_open(struct fsw_posix_volume *pvol, const char *path, int flags, mode_t mode);
+ssize_t fsw_posix_read(struct fsw_posix_file *file, void *buf, size_t nbytes);
+off_t fsw_posix_lseek(struct fsw_posix_file *file, off_t offset, int whence);
+int fsw_posix_close(struct fsw_posix_file *file);
+
+struct fsw_posix_dir * fsw_posix_opendir(struct fsw_posix_volume *pvol, const char *path);
+struct dirent * fsw_posix_readdir(struct fsw_posix_dir *dir);
+void fsw_posix_rewinddir(struct fsw_posix_dir *dir);
+int fsw_posix_closedir(struct fsw_posix_dir *dir);
+
+
+#endif
diff --git a/filesystems/test/fsw_posix_base.h b/filesystems/test/fsw_posix_base.h
new file mode 100644 (file)
index 0000000..0b7334b
--- /dev/null
@@ -0,0 +1,90 @@
+/**
+ * \file fsw_posix_base.h
+ * Base definitions for the POSIX user space host environment.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _FSW_POSIX_BASE_H_
+#define _FSW_POSIX_BASE_H_
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#define FSW_LITTLE_ENDIAN (1)
+// TODO: use info from the headers to define FSW_LITTLE_ENDIAN or FSW_BIG_ENDIAN
+
+
+// types
+
+typedef int8_t              fsw_s8;
+typedef uint8_t             fsw_u8;
+typedef int16_t             fsw_s16;
+typedef uint16_t            fsw_u16;
+typedef int32_t             fsw_s32;
+typedef uint32_t            fsw_u32;
+typedef int64_t             fsw_s64;
+typedef uint64_t            fsw_u64;
+
+
+// allocation functions
+
+#define fsw_alloc(size, ptrptr) (((*(ptrptr) = malloc(size)) == NULL) ? FSW_OUT_OF_MEMORY : FSW_SUCCESS)
+#define fsw_free(ptr) free(ptr)
+
+// memory functions
+
+#define fsw_memzero(dest,size) memset(dest,0,size)
+#define fsw_memcpy(dest,src,size) memcpy(dest,src,size)
+#define fsw_memeq(p1,p2,size) (memcmp(p1,p2,size) == 0)
+
+// message printing
+
+#define FSW_MSGSTR(s) s
+#define FSW_MSGFUNC(str, ...) (fprintf(stderr, str, ##__VA_ARGS__))
+
+// 64-bit hooks
+
+#define FSW_U64_SHR(val,shiftbits) ((val) >> (shiftbits))
+#define FSW_U64_DIV(val,divisor) ((val) / (divisor))
+#define DEBUG(x)
+
+#define RShiftU64(val, shift) ((val) >> (shift))
+#define LShiftU64(val, shift) ((val) << (shift))
+
+#endif
diff --git a/filesystems/test/lslr.c b/filesystems/test/lslr.c
new file mode 100644 (file)
index 0000000..0459b08
--- /dev/null
@@ -0,0 +1,138 @@
+/**
+ * \file lslr.c
+ * Test program for the POSIX user space environment.
+ */
+
+/*-
+ * Copyright (c) 2012 Stefan Agner
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define FSW_DEBUG_LEVEL 3
+
+#include "fsw_posix.h"
+
+
+//extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(ext2);
+//extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(reiserfs);
+extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(FSTYPE);
+
+static struct fsw_fstype_table *fstypes[] = {
+    //&FSW_FSTYPE_TABLE_NAME(ext2),
+    //&FSW_FSTYPE_TABLE_NAME(reiserfs),
+    &FSW_FSTYPE_TABLE_NAME(FSTYPE       ),
+    NULL
+};
+
+static int listdir(struct fsw_posix_volume *vol, char *path, int level)
+{
+    struct fsw_posix_dir *dir;
+    struct dirent *dent;
+    int i;
+    char subpath[4096];
+
+    dir = fsw_posix_opendir(vol, path);
+    if (dir == NULL) {
+        fprintf(stderr, "opendir(%s) call failed.\n", path);
+        return 1;
+    }
+    while ((dent = fsw_posix_readdir(dir)) != NULL) {
+        for (i = 0; i < level*2; i++)
+            fputc(' ', stderr);
+        fprintf(stderr, "%d  %s\n", dent->d_type, dent->d_name);
+
+        if (dent->d_type == DT_DIR) {
+            snprintf(subpath, 4095, "%s%s/", path, dent->d_name);
+            listdir(vol, subpath, level + 1);
+        }
+    }
+
+    fsw_posix_closedir(dir);
+
+    return 0;
+}
+
+static int catfile(struct fsw_posix_volume *vol, char *path)
+{
+    struct fsw_posix_file *file;
+    int r;
+    char buf[256];
+
+    file = fsw_posix_open(vol, path, 0, 0);
+    if (file == NULL) {
+        fprintf(stderr, "open(%s) call failed.\n", path);
+        return 1;
+    }
+
+    while ((r=fsw_posix_read(file, buf, sizeof(buf))) > 0)
+    {
+        int i;
+        for (i=0; i<r; i++)
+        {
+           printf("%c", buf[i]);
+        }
+    }
+    fsw_posix_close(file);
+
+    return 0;
+}
+
+int main(int argc, char **argv)
+{
+    struct fsw_posix_volume *vol;
+    int i;
+
+    if (argc != 2) {
+        fprintf(stderr, "Usage: lslr <file/device>\n");
+        return 1;
+    }
+
+    for (i = 0; fstypes[i]; i++) {
+        vol = fsw_posix_mount(argv[1], fstypes[i]);
+        if (vol != NULL) {
+            fprintf(stderr, "Mounted as '%s'.\n", fstypes[i]->name.data);
+            break;
+        }
+    }
+    if (vol == NULL) {
+        fprintf(stderr, "Mounting failed.\n");
+        return 1;
+    }
+
+    listdir(vol, "/boot/", 0);
+    catfile(vol, "/boot/testfile.txt");
+
+    fsw_posix_unmount(vol);
+
+    return 0;
+}
+
+// EOF
diff --git a/filesystems/test/lsroot.c b/filesystems/test/lsroot.c
new file mode 100644 (file)
index 0000000..abbebff
--- /dev/null
@@ -0,0 +1,80 @@
+/**
+ * \file lsroot.c
+ * Example program for the POSIX user space environment.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsw_posix.h"
+
+
+extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(reiserfs);
+extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(iso9660);
+extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(hfs);
+extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(ext2);
+extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(ext4);
+
+int main(int argc, char **argv)
+{
+    struct fsw_posix_volume *vol;
+    struct fsw_posix_dir *dir;
+    struct dirent *dent;
+
+    if (argc != 2) {
+        fprintf(stderr, "Usage: lsroot <file/device>\n");
+        return 1;
+    }
+
+    //vol = fsw_posix_mount(argv[1], &FSW_FSTYPE_TABLE_NAME(ext2));
+    //vol = fsw_posix_mount(argv[1], &FSW_FSTYPE_TABLE_NAME(reiserfs));
+    vol = fsw_posix_mount(argv[1], &FSW_FSTYPE_TABLE_NAME(FSTYPE));
+    if (vol == NULL) {
+        fprintf(stderr, "Mounting failed.\n");
+        return 1;
+    }
+    //dir = fsw_posix_opendir(vol, "/drivers/net/");
+    dir = fsw_posix_opendir(vol, "/");
+    if (dir == NULL) {
+        fprintf(stderr, "opendir call failed.\n");
+        return 1;
+    }
+    while ((dent = fsw_posix_readdir(dir)) != NULL) {
+        fprintf(stderr, "- %s\n", dent->d_name);
+    }
+    fsw_posix_closedir(dir);
+    fsw_posix_unmount(vol);
+
+    return 0;
+}
+
+// EOF
diff --git a/fonts/README.txt b/fonts/README.txt
new file mode 100644 (file)
index 0000000..4466fc6
--- /dev/null
@@ -0,0 +1,4 @@
+This directory contains PNGs built from a few open source fonts: the sans
+serif Liberation Mono Regular and Ubuntu mono and the serif Nimbus Mono,
+all in 12-, 14, and 24-point versions. All of these font files have
+anti-aliasing (aka font smoothing) applied.
diff --git a/fonts/liberation-mono-regular-12.png b/fonts/liberation-mono-regular-12.png
new file mode 100644 (file)
index 0000000..ed02b60
Binary files /dev/null and b/fonts/liberation-mono-regular-12.png differ
diff --git a/fonts/liberation-mono-regular-14.png b/fonts/liberation-mono-regular-14.png
new file mode 100644 (file)
index 0000000..47c1dba
Binary files /dev/null and b/fonts/liberation-mono-regular-14.png differ
diff --git a/fonts/liberation-mono-regular-24.png b/fonts/liberation-mono-regular-24.png
new file mode 100644 (file)
index 0000000..7abd266
Binary files /dev/null and b/fonts/liberation-mono-regular-24.png differ
diff --git a/fonts/mkfont.sh b/fonts/mkfont.sh
new file mode 100755 (executable)
index 0000000..0f87fa2
--- /dev/null
@@ -0,0 +1,53 @@
+#!/bin/bash
+#
+# copyright (c) 2013 by Roderick W. Smith
+#
+# This program is licensed under the terms of the GNU GPL, version 3,
+# or (at your option) any later version.
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Program to generate a PNG file suitable for use as a rEFInd font
+# To obtain a list of available font names, type:
+#
+# convert -list font | less
+#
+# The font used MUST be a monospaced font; searching for the string
+# "Mono" will turn up most suitable candidates.
+#
+# Usage:
+# ./mkfont.sh font-name font-size font-Y-offset bitmap-filename.png
+#
+# This script is part of the rEFInd package. Version numbers refer to
+# the rEFInd version with which the script was released.
+#
+# Version history:
+#
+#  0.6.6  -  Initial release
+
+if [[ $# != 4 ]] ; then
+   echo "Usage: $0 font-name font-size y-offset bitmap-filename.png"
+   echo "   font-name: Name of font (use 'convert -list font | less' to get list)"
+   echo "              NOTE: Font MUST be monospaced!"
+   echo "   font-size: Font size in points"
+   echo "   y-offset: pixels font is shifted (may be negative)"
+   echo "   bitmap-filename.png: output filename"
+   echo ""
+   exit 1
+fi
+
+Convert=`which convert 2> /dev/null`
+if [[ ! -x $Convert ]] ; then
+   echo "The 'convert' program is required but could not be found. It's part of the"
+   echo "ImagMagick program, usually installed in the 'imagemagick' package."
+   echo ""
+   exit 1
+fi
+
+Height=$2
+let CellWidth=(${Height}*6+5)/10
+#let CellWidth=(${Height}*5)/10
+let Width=${CellWidth}*96
+echo "Creating ${Width}x${Height} font bitmap...."
+$Convert -size ${Width}x${Height} xc:transparent -gravity NorthWest -font $1 -pointsize $2 \
+      -draw "text 0,$3 ' !\"#\$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_\`abcdefghijklmnopqrstuvwxyz{|}~?'" $4
diff --git a/fonts/nimbus-mono-12.png b/fonts/nimbus-mono-12.png
new file mode 100644 (file)
index 0000000..3b9e2eb
Binary files /dev/null and b/fonts/nimbus-mono-12.png differ
diff --git a/fonts/nimbus-mono-14.png b/fonts/nimbus-mono-14.png
new file mode 100644 (file)
index 0000000..c218f72
Binary files /dev/null and b/fonts/nimbus-mono-14.png differ
diff --git a/fonts/nimbus-mono-16.png b/fonts/nimbus-mono-16.png
new file mode 100644 (file)
index 0000000..2684231
Binary files /dev/null and b/fonts/nimbus-mono-16.png differ
diff --git a/fonts/nimbus-mono-24.png b/fonts/nimbus-mono-24.png
new file mode 100644 (file)
index 0000000..58cbb13
Binary files /dev/null and b/fonts/nimbus-mono-24.png differ
diff --git a/fonts/ubuntu-mono-12.png b/fonts/ubuntu-mono-12.png
new file mode 100644 (file)
index 0000000..f4eda3e
Binary files /dev/null and b/fonts/ubuntu-mono-12.png differ
diff --git a/fonts/ubuntu-mono-14.png b/fonts/ubuntu-mono-14.png
new file mode 100644 (file)
index 0000000..0f8dcea
Binary files /dev/null and b/fonts/ubuntu-mono-14.png differ
diff --git a/fonts/ubuntu-mono-16.png b/fonts/ubuntu-mono-16.png
new file mode 100644 (file)
index 0000000..6f37f2b
Binary files /dev/null and b/fonts/ubuntu-mono-16.png differ
diff --git a/fonts/ubuntu-mono-24.png b/fonts/ubuntu-mono-24.png
new file mode 100644 (file)
index 0000000..acabd23
Binary files /dev/null and b/fonts/ubuntu-mono-24.png differ
diff --git a/gptsync/AutoGen.c b/gptsync/AutoGen.c
new file mode 100644 (file)
index 0000000..6423efc
--- /dev/null
@@ -0,0 +1,287 @@
+/**
+  DO NOT EDIT
+  FILE auto-generated
+  Module name:
+    AutoGen.c
+  Abstract:       Auto-generated AutoGen.c for building module or library.
+**/
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiApplicationEntryPoint.h>
+#include "AutoGen.h"
+
+GLOBAL_REMOVE_IF_UNREFERENCED GUID gEfiCallerIdGuid = {0xB8448DD1, 0xB146, 0x41B7, {0x9D, 0x66, 0x98, 0xB3, 0xA0, 0xA4, 0x04, 0xD3}};
+
+// Guids
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiAcpiTableGuid = { 0x8868E871, 0xE4F1, 0x11D3, { 0xBC, 0x22, 0x00, 0x80, 0xC7, 0x3C, 0x88, 0x81 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiAcpi10TableGuid = { 0xEB9D2D30, 0x2D88, 0x11D3, { 0x9A, 0x16, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiAcpi20TableGuid = { 0x8868E871, 0xE4F1, 0x11D3, { 0xBC, 0x22, 0x00, 0x80, 0xC7, 0x3C, 0x88, 0x81 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDxeServicesTableGuid = { 0x05AD34BA, 0x6F02, 0x4214, { 0x95, 0x2E, 0x4D, 0xA0, 0x39, 0x8E, 0x2B, 0xB9 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiEventReadyToBootGuid = { 0x7CE88FB3, 0x4BD7, 0x4679, { 0x87, 0xA8, 0xA8, 0xD8, 0xDE, 0xE5, 0x0D, 0x2B }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiEventVirtualAddressChangeGuid = { 0x13FA7698, 0xC831, 0x49C7, { 0x87, 0xEA, 0x8F, 0x43, 0xFC, 0xC2, 0x51, 0x96 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiEventExitBootServicesGuid = { 0x27ABF055, 0xB1B8, 0x4C26, { 0x80, 0x48, 0x74, 0x8F, 0x37, 0xBA, 0xA2, 0xDF }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiFileInfoGuid = { 0x09576E92, 0x6D3F, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiFileSystemInfoGuid = { 0x09576E93, 0x6D3F, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiFileSystemVolumeLabelInfoIdGuid = { 0xDB47D7D3, 0xFE81, 0x11D3, { 0x9A, 0x35, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiGlobalVariableGuid = { 0x8BE4DF61, 0x93CA, 0x11D2, { 0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiPartTypeLegacyMbrGuid = { 0x024DEE41, 0x33E7, 0x11D3, { 0x9D, 0x69, 0x00, 0x08, 0xC7, 0x81, 0xF3, 0x9F }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiPartTypeSystemPartGuid = { 0xC12A7328, 0xF81F, 0x11D2, { 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSmbiosTableGuid = { 0xEB9D2D31, 0x2D88, 0x11D3, { 0x9A, 0x16, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSasDevicePathGuid = { 0xd487ddb4, 0x008b, 0x11d9, { 0xaf, 0xdc, 0x00, 0x10, 0x83, 0xff, 0xca, 0x4d }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiMdePkgTokenSpaceGuid = { 0x914AEBE7, 0x4635, 0x459b, { 0xAA, 0x1C, 0x11, 0xE2, 0x19, 0xB0, 0x3A, 0x10 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiEventLegacyBootGuid = { 0x2A571201, 0x4966, 0x47F6, { 0x8B, 0x86, 0xF3, 0x1E, 0x41, 0xF3, 0x2F, 0x10 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiHobListGuid = { 0x7739F24C, 0x93D7, 0x11D4, { 0x9A, 0x3A, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }};
+
+// Protocols
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiComponentName2ProtocolGuid = { 0x6A7A5CFF, 0xE8D9, 0x4F70, { 0xBA, 0xDA, 0x75, 0xAB, 0x30, 0x25, 0xCE, 0x14 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDevicePathToTextProtocolGuid = { 0x8B843E20, 0x8132, 0x4852, { 0x90, 0xCC, 0x55, 0x1A, 0x4E, 0x4A, 0x7F, 0x1C }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSimpleFileSystemProtocolGuid = { 0x964E5B22, 0x6459, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSimpleTextInProtocolGuid = { 0x387477C1, 0x69C7, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSimpleTextInputExProtocolGuid = {0xdd9e7534, 0x7762, 0x4698, { 0x8c, 0x14, 0xf5, 0x85, 0x17, 0xa6, 0x25, 0xaa } };
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSimpleTextOutProtocolGuid = { 0x387477C2, 0x69C7, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiUnicodeCollationProtocolGuid = { 0x1D85CD7F, 0xF43D, 0x11D2, { 0x9A, 0x0C, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiUnicodeCollation2ProtocolGuid = {0xa4c751fc, 0x23ae, 0x4c3e, { 0x92, 0xe9, 0x49, 0x64, 0xcf, 0x63, 0xf3, 0x49 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiAcpiS3SaveProtocolGuid = { 0x125F2DE1, 0xFB85, 0x440C, { 0xA5, 0x4C, 0x4D, 0x99, 0x35, 0x8A, 0x8D, 0x38 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiBlockIoProtocolGuid = { 0x964E5B21, 0x6459, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiCpuArchProtocolGuid = { 0x26BACCB1, 0x6F42, 0x11D4, { 0xBC, 0xE7, 0x00, 0x80, 0xC7, 0x3C, 0x88, 0x81 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDebugPortProtocolGuid = { 0xEBA4E8D2, 0x3858, 0x41EC, { 0xA2, 0x81, 0x26, 0x47, 0xBA, 0x96, 0x60, 0xD0 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDevicePathProtocolGuid = { 0x09576E91, 0x6D3F, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDiskIoProtocolGuid = { 0xCE345171, 0xBA0B, 0x11D2, { 0x8E, 0x4F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiExtScsiPassThruProtocolGuid = { 0x143b7632, 0xb81b, 0x4cb7, {0xab, 0xd3, 0xb6, 0x25, 0xa5, 0xb9, 0xbf, 0xfe }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiFirmwareVolume2ProtocolGuid = { 0x220e73b6, 0x6bdb, 0x4413, { 0x84, 0x5, 0xb9, 0x74, 0xb1, 0x8, 0x61, 0x9a } };
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiGraphicsOutputProtocolGuid = { 0x9042A9DE, 0x23DC, 0x4A38, { 0x96, 0xFB, 0x7A, 0xDE, 0xD0, 0x80, 0x51, 0x6A }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiHiiFontProtocolGuid = {0xe9ca4775, 0x8657, 0x47fc, {0x97, 0xe7, 0x7e, 0xd6, 0x5a, 0x08, 0x43, 0x24}};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiLegacy8259ProtocolGuid = { 0x38321dba, 0x4fe0, 0x4e17, { 0x8a, 0xec, 0x41, 0x30, 0x55, 0xea, 0xed, 0xc1 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiLoadedImageProtocolGuid = { 0x5B1B31A1, 0x9562, 0x11D2, { 0x8E, 0x3F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiOEMBadgingProtocolGuid = { 0x170E13C0, 0xBF1B, 0x4218, { 0x87, 0x1D, 0x2A, 0xBD, 0xC6, 0xF8, 0x87, 0xBC }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiPciIoProtocolGuid = { 0x4CF5B200, 0x68B8, 0x4CA5, { 0x9E, 0xEC, 0xB2, 0x3E, 0x3F, 0x50, 0x02, 0x9A }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiScsiIoProtocolGuid = { 0x932F47e6, 0x2362, 0x4002, { 0x80, 0x3E, 0x3C, 0xD5, 0x4B, 0x13, 0x8F, 0x85 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiScsiPassThruProtocolGuid = { 0xA59E8FCF, 0xBDA0, 0x43BB, { 0x90, 0xB1, 0xD3, 0x73, 0x2E, 0xCA, 0xA8, 0x77 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSimpleNetworkProtocolGuid = { 0xA19832B9, 0xAC25, 0x11D3, { 0x9A, 0x2D, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }};
+//GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiUgaDrawProtocolGuid = { 0x982C298B, 0xF4FA, 0x41CB, { 0xB8, 0x38, 0x77, 0xAA, 0x68, 0x8F, 0xB8, 0x39 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiAbsolutePointerProtocolGuid = { 0x8D59D32B, 0xC655, 0x4AE9, { 0x9B, 0x15, 0xF2, 0x59, 0x04, 0x99, 0x2A, 0x43 } };
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiAcpiTableProtocolGuid = { 0xFFE06BDD, 0x6107, 0x46A6, { 0x7B, 0xB2, 0x5A, 0x9C, 0x7E, 0xC5, 0x27, 0x5C }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiEdidActiveProtocolGuid = { 0xBD8C1056, 0x9F36, 0x44EC, { 0x92, 0xA8, 0xA6, 0x33, 0x7F, 0x81, 0x79, 0x86 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiEdidDiscoveredProtocolGuid = { 0x1C0C34F6, 0xD380, 0x41FA, { 0xA0, 0x49, 0x8A, 0xD0, 0x6C, 0x1A, 0x66, 0xAA }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiHiiDatabaseProtocolGuid = {0xef9fc172, 0xa1b2, 0x4693, {0xb3, 0x27, 0x6d, 0x32, 0xfc, 0x41, 0x60, 0x42}};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiHiiImageProtocolGuid = {0x31a6406a, 0x6bdf, 0x4e46, {0xb2, 0xa2, 0xeb, 0xaa, 0x89, 0xc4, 0x09, 0x20}};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiHiiProtocolGuid = { 0xd7ad636e, 0xb997, 0x459b, { 0xbf, 0x3f, 0x88, 0x46, 0x89, 0x79, 0x80, 0xe1 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSimplePointerProtocolGuid = { 0x31878C87, 0x0B75, 0x11D5, { 0x9A, 0x4F, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSmbiosProtocolGuid = {0x3583ff6, 0xcb36, 0x4940, { 0x94, 0x7e, 0xb9, 0xb3, 0x9f, 0x4a, 0xfa, 0xf7}};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSecurityArchProtocolGuid = { 0xA46423E3, 0x4617, 0x49F1, { 0xB9, 0xFF, 0xD1, 0xBF, 0xA9, 0x11, 0x58, 0x39 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiLegacyBiosProtocolGuid = { 0xdb9a1e3d, 0x45cb, 0x4abb, { 0x85, 0x3b, 0xe5, 0x38, 0x7f, 0xdb, 0x2e, 0x2d }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiLoadFile2ProtocolGuid = { 0x4006c0c1, 0xfcb3, 0x403e, {0x99, 0x6d, 0x4a, 0x6c, 0x87, 0x24, 0xe0, 0x6d }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiLoadFileProtocolGuid = { 0x56EC3091, 0x954C, 0x11D2, { 0x8E, 0x3F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiHiiPackageListProtocolGuid = { 0x6a1ee763, 0xd47a, 0x43b4, {0xaa, 0xbe, 0xef, 0x1d, 0xe2, 0xab, 0x56, 0xfc}};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverBindingProtocolGuid = { 0x18A031AB, 0xB443, 0x4D1A, { 0xA5, 0xC0, 0x0C, 0x09, 0x26, 0x1E, 0x9F, 0x71 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiComponentNameProtocolGuid = { 0x107A772C, 0xD5E1, 0x11D4, { 0x9A, 0x46, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverConfigurationProtocolGuid = { 0x107A772B, 0xD5E1, 0x11D4, { 0x9A, 0x46, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverConfiguration2ProtocolGuid = { 0xBFD7DC1D, 0x24F1, 0x40D9, { 0x82, 0xE7, 0x2E, 0x09, 0xBB, 0x6B, 0x4E, 0xBE }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverDiagnosticsProtocolGuid = { 0x0784924F, 0xE296, 0x11D4, { 0x9A, 0x49, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverDiagnostics2ProtocolGuid = { 0x4D330321, 0x025F, 0x4AAC, { 0x90, 0xD8, 0x5E, 0xD9, 0x00, 0x17, 0x3B, 0x63 }};
+
+// Definition of PCDs used in this module
+//GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdUgaConsumeSupport = _PCD_VALUE_PcdUgaConsumeSupport;
+
+// Definition of PCDs used in libraries
+
+#define _PCD_TOKEN_PcdMaximumLinkedListLength  2U
+#define _PCD_VALUE_PcdMaximumLinkedListLength  1000000U
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdMaximumLinkedListLength = _PCD_VALUE_PcdMaximumLinkedListLength;
+extern const  UINT32  _gPcd_FixedAtBuild_PcdMaximumLinkedListLength;
+#define _PCD_GET_MODE_32_PcdMaximumLinkedListLength  _gPcd_FixedAtBuild_PcdMaximumLinkedListLength
+#define _PCD_SET_MODE_32_PcdMaximumLinkedListLength  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdMaximumAsciiStringLength  3U
+#define _PCD_VALUE_PcdMaximumAsciiStringLength  1000000U
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdMaximumAsciiStringLength = _PCD_VALUE_PcdMaximumAsciiStringLength;
+extern const  UINT32  _gPcd_FixedAtBuild_PcdMaximumAsciiStringLength;
+#define _PCD_GET_MODE_32_PcdMaximumAsciiStringLength  _gPcd_FixedAtBuild_PcdMaximumAsciiStringLength
+#define _PCD_SET_MODE_32_PcdMaximumAsciiStringLength  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdMaximumUnicodeStringLength  4U
+#define _PCD_VALUE_PcdMaximumUnicodeStringLength  1000000U
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdMaximumUnicodeStringLength = _PCD_VALUE_PcdMaximumUnicodeStringLength;
+extern const  UINT32  _gPcd_FixedAtBuild_PcdMaximumUnicodeStringLength;
+#define _PCD_GET_MODE_32_PcdMaximumUnicodeStringLength  _gPcd_FixedAtBuild_PcdMaximumUnicodeStringLength
+#define _PCD_SET_MODE_32_PcdMaximumUnicodeStringLength  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdVerifyNodeInList  5U
+#define _PCD_VALUE_PcdVerifyNodeInList  ((BOOLEAN)0U)
+GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdVerifyNodeInList = _PCD_VALUE_PcdVerifyNodeInList;
+extern const  BOOLEAN  _gPcd_FixedAtBuild_PcdVerifyNodeInList;
+#define _PCD_GET_MODE_BOOL_PcdVerifyNodeInList  _gPcd_FixedAtBuild_PcdVerifyNodeInList
+#define _PCD_SET_MODE_BOOL_PcdVerifyNodeInList  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdDriverDiagnosticsDisable  6U
+#define _PCD_VALUE_PcdDriverDiagnosticsDisable  ((BOOLEAN)0U)
+GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdDriverDiagnosticsDisable = _PCD_VALUE_PcdDriverDiagnosticsDisable;
+extern const  BOOLEAN  _gPcd_FixedAtBuild_PcdDriverDiagnosticsDisable;
+#define _PCD_GET_MODE_BOOL_PcdDriverDiagnosticsDisable  _gPcd_FixedAtBuild_PcdDriverDiagnosticsDisable
+#define _PCD_SET_MODE_BOOL_PcdDriverDiagnosticsDisable  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdComponentNameDisable  7U
+#define _PCD_VALUE_PcdComponentNameDisable  ((BOOLEAN)0U)
+GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdComponentNameDisable = _PCD_VALUE_PcdComponentNameDisable;
+extern const  BOOLEAN  _gPcd_FixedAtBuild_PcdComponentNameDisable;
+#define _PCD_GET_MODE_BOOL_PcdComponentNameDisable  _gPcd_FixedAtBuild_PcdComponentNameDisable
+#define _PCD_SET_MODE_BOOL_PcdComponentNameDisable  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdDriverDiagnostics2Disable  8U
+#define _PCD_VALUE_PcdDriverDiagnostics2Disable  ((BOOLEAN)0U)
+GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdDriverDiagnostics2Disable = _PCD_VALUE_PcdDriverDiagnostics2Disable;
+extern const  BOOLEAN  _gPcd_FixedAtBuild_PcdDriverDiagnostics2Disable;
+#define _PCD_GET_MODE_BOOL_PcdDriverDiagnostics2Disable  _gPcd_FixedAtBuild_PcdDriverDiagnostics2Disable
+#define _PCD_SET_MODE_BOOL_PcdDriverDiagnostics2Disable  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdComponentName2Disable  9U
+#define _PCD_VALUE_PcdComponentName2Disable  ((BOOLEAN)0U)
+GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdComponentName2Disable = _PCD_VALUE_PcdComponentName2Disable;
+extern const  BOOLEAN  _gPcd_FixedAtBuild_PcdComponentName2Disable;
+#define _PCD_GET_MODE_BOOL_PcdComponentName2Disable  _gPcd_FixedAtBuild_PcdComponentName2Disable
+#define _PCD_SET_MODE_BOOL_PcdComponentName2Disable  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdUefiLibMaxPrintBufferSize  10U
+#define _PCD_VALUE_PcdUefiLibMaxPrintBufferSize  320U
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdUefiLibMaxPrintBufferSize = _PCD_VALUE_PcdUefiLibMaxPrintBufferSize;
+extern const  UINT32  _gPcd_FixedAtBuild_PcdUefiLibMaxPrintBufferSize;
+#define _PCD_GET_MODE_32_PcdUefiLibMaxPrintBufferSize  _gPcd_FixedAtBuild_PcdUefiLibMaxPrintBufferSize
+#define _PCD_SET_MODE_32_PcdUefiLibMaxPrintBufferSize  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+
+EFI_STATUS
+EFIAPI
+UefiBootServicesTableLibConstructor (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  );
+
+EFI_STATUS
+EFIAPI
+UefiRuntimeServicesTableLibConstructor (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  );
+
+EFI_STATUS
+EFIAPI
+UefiLibConstructor (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  );
+
+EFI_STATUS
+EFIAPI
+DxeServicesTableLibConstructor (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  );
+
+EFI_STATUS
+EFIAPI
+HobLibConstructor (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  );
+
+
+// VOID
+// EFIAPI
+// ProcessLibraryConstructorList (
+//   IN EFI_HANDLE        ImageHandle,
+//   IN EFI_SYSTEM_TABLE  *SystemTable
+//   )
+// {
+//   EFI_STATUS  Status;
+// 
+//   Status = UefiBootServicesTableLibConstructor (ImageHandle, SystemTable);
+//   ASSERT_EFI_ERROR (Status);
+// 
+//   Status = UefiRuntimeServicesTableLibConstructor (ImageHandle, SystemTable);
+//   ASSERT_EFI_ERROR (Status);
+// 
+//   Status = UefiLibConstructor (ImageHandle, SystemTable);
+//   ASSERT_EFI_ERROR (Status);
+// 
+//   Status = DxeServicesTableLibConstructor (ImageHandle, SystemTable);
+//   ASSERT_EFI_ERROR (Status);
+// 
+//   Status = HobLibConstructor (ImageHandle, SystemTable);
+//   ASSERT_EFI_ERROR (Status);
+// 
+// }
+
+
+
+// VOID
+// EFIAPI
+// ProcessLibraryDestructorList (
+//   IN EFI_HANDLE        ImageHandle,
+//   IN EFI_SYSTEM_TABLE  *SystemTable
+//   )
+// {
+//
+// }
+
+const UINT32 _gUefiDriverRevision = 0x00010000U;
+
+
+// EFI_STATUS
+// EFIAPI
+// ProcessModuleEntryPointList (
+//   IN EFI_HANDLE        ImageHandle,
+//   IN EFI_SYSTEM_TABLE  *SystemTable
+//   )
+// 
+// {
+//   return efi_main (ImageHandle, SystemTable);
+// }
+
+VOID
+EFIAPI
+ExitDriver (
+  IN EFI_STATUS  Status
+  )
+{
+  if (EFI_ERROR (Status)) {
+    ProcessLibraryDestructorList (gImageHandle, gST);
+  }
+  gBS->Exit (gImageHandle, Status, 0, NULL);
+}
+
+//GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gDriverUnloadImageCount = 0U;
+
+// EFI_STATUS
+// EFIAPI
+// ProcessModuleUnloadList (
+//   IN EFI_HANDLE        ImageHandle
+//   )
+// {
+//   return EFI_SUCCESS;
+// }
+
+// Stuff added in effort to get Secure Boot working....
+
+#define _PCD_TOKEN_PcdDebugPropertyMask  11U
+#define _PCD_VALUE_PcdDebugPropertyMask  0x0fU
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdDebugPropertyMask = _PCD_VALUE_PcdDebugPropertyMask;
+extern const  UINT8  _gPcd_FixedAtBuild_PcdDebugPropertyMask;
+#define _PCD_GET_MODE_8_PcdDebugPropertyMask  _gPcd_FixedAtBuild_PcdDebugPropertyMask
+//#define _PCD_SET_MODE_8_PcdDebugPropertyMask  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdDebugClearMemoryValue  10U
+#define _PCD_VALUE_PcdDebugClearMemoryValue  0xAFU
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdDebugClearMemoryValue = _PCD_VALUE_PcdDebugClearMemoryValue;
+extern const  UINT8  _gPcd_FixedAtBuild_PcdDebugClearMemoryValue;
+#define _PCD_GET_MODE_8_PcdDebugClearMemoryValue  _gPcd_FixedAtBuild_PcdDebugClearMemoryValue
+//#define _PCD_SET_MODE_8_PcdDebugClearMemoryValue  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdDebugPrintErrorLevel  5U
+#define _PCD_VALUE_PcdDebugPrintErrorLevel  0x80000000U
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdDebugPrintErrorLevel = _PCD_VALUE_PcdDebugPrintErrorLevel;
+extern const  UINT32  _gPcd_FixedAtBuild_PcdDebugPrintErrorLevel;
+#define _PCD_GET_MODE_32_PcdDebugPrintErrorLevel  _gPcd_FixedAtBuild_PcdDebugPrintErrorLevel
+//#define _PCD_SET_MODE_32_PcdDebugPrintErrorLevel  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
diff --git a/gptsync/AutoGen.h b/gptsync/AutoGen.h
new file mode 100644 (file)
index 0000000..a07912e
--- /dev/null
@@ -0,0 +1,51 @@
+/**
+  DO NOT EDIT
+  FILE auto-generated
+  Module name:
+    AutoGen.h
+  Abstract:       Auto-generated AutoGen.h for building module or library.
+**/
+
+#ifndef _AUTOGENH_B8448DD1_B146_41B7_9D66_98B3A0A404D3
+#define _AUTOGENH_B8448DD1_B146_41B7_9D66_98B3A0A404D3
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <Base.h>
+#include <Uefi.h>
+#include <Library/PcdLib.h>
+
+extern GUID  gEfiCallerIdGuid;
+
+#define EFI_CALLER_ID_GUID \
+  {0xB8448DD1, 0xB146, 0x41B7, {0x9D, 0x66, 0x98, 0xB3, 0xA0, 0xA4, 0x04, 0xD3}}
+
+// Definition of PCDs used in this module
+
+#define _PCD_TOKEN_PcdUgaConsumeSupport  16U
+#define _PCD_VALUE_PcdUgaConsumeSupport  ((BOOLEAN)1U)
+extern const  BOOLEAN  _gPcd_FixedAtBuild_PcdUgaConsumeSupport;
+#define _PCD_GET_MODE_BOOL_PcdUgaConsumeSupport  _gPcd_FixedAtBuild_PcdUgaConsumeSupport
+//#define _PCD_SET_MODE_BOOL_PcdUgaConsumeSupport  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+// Definition of PCDs used in libraries is in AutoGen.c
+
+
+EFI_STATUS
+EFIAPI
+efi_main (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  );
+
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/gptsync/Make.gnuefi b/gptsync/Make.gnuefi
new file mode 100644 (file)
index 0000000..ad92564
--- /dev/null
@@ -0,0 +1,42 @@
+#
+# gptsync/Make.gnuefi
+# Build control file for the gptsync tool, built with GNU-EFI
+#
+
+LOCAL_CPPFLAGS  = -I. -I../include
+LOCAL_LDFLAGS   = 
+LOCAL_LIBS      = 
+
+OBJS            = gptsync.o lib.o os_efi.o
+TARGET          = gptsync.efi
+
+include ../Make.common
+
+ifeq ($(ARCH),ia32)
+  ARCHNAME = gptsync_ia32.efi
+endif
+
+ifeq ($(ARCH),x86_64)
+  ARCHNAME = gptsync_x64.efi
+endif
+
+ifeq ($(ARCH),aarch64)
+  ARCHNAME = gptsync_aa64.efi
+endif
+
+all: $(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 .rel.* -j .rela.* -j .rel* -j .rela* \
+                  -j .reloc $(FORMAT) $< $@
+       chmod a-x $(TARGET)
+       mv $(TARGET) $(ARCHNAME)
+
+
+# EOF
diff --git a/gptsync/Make.tiano b/gptsync/Make.tiano
new file mode 100644 (file)
index 0000000..49e7787
--- /dev/null
@@ -0,0 +1,119 @@
+#
+# gptsync/Make.tiano
+# Build control file for gptsync utility, built with TianoCore EDK2
+#
+
+HOSTARCH        = $(shell uname -m | sed s,i[3456789]86,ia32,)
+ARCH            ?= $(HOSTARCH)
+
+# Note: IA64 options are untested; taken from Debian's rEFIt package.
+ifeq ($(ARCH),ia64)
+  # EFI specs allows only lower floating point partition to be used
+  ARCH_C_CFLAGS  = -frename-registers -mfixed-range=f32-f127
+  # TODO: Add ARCHDIR and FILENAME_CODE as appropriate
+endif
+
+ifeq ($(ARCH),ia32)
+  ARCH_C_FLAGS = -m32 -malign-double -DEFI32
+  ARCHDIR = Ia32
+  UC_ARCH = IA32
+  FILENAME_CODE = ia32
+  LD_CODE = elf_i386
+endif
+
+ifeq ($(ARCH),x86_64)
+  ARCH_C_FLAGS = "-DEFIAPI=__attribute__((ms_abi))" -mcmodel=large -m64 -mno-red-zone -DEFIX64
+  ARCHDIR = X64
+  UC_ARCH = X64
+  FILENAME_CODE = x64
+  LD_CODE = elf_x86_64
+endif
+
+ifeq ($(ARCH),aarch64)
+  ARCH_C_FLAGS = -DEFIAARCH64 -mcmodel=large
+  ARCHDIR = AArch64
+  UC_ARCH = AARCH64
+  FILENAME_CODE = aa64
+  LD_CODE = aarch64elf
+endif
+
+export EDK2BASE = /usr/local/UDK2014/MyWorkSpace
+#EDK2BASE = /usr/local/edk2
+
+# Below file defines TARGET (RELEASE or DEBUG) and TOOL_CHAIN_TAG (GCC44, GCC45, or GCC46)
+include $(EDK2BASE)/Conf/target.txt
+
+EFILIB          = $(EDK2BASE)/Build/Mde/$(TARGET)_$(TOOL_CHAIN_TAG)/$(UC_ARCH)/MdePkg/Library
+ALL_EFILIBS     = $(EFILIB)/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib/OUTPUT/BaseDebugPrintErrorLevelLib.lib \
+                 $(EFILIB)/BasePrintLib/BasePrintLib/OUTPUT/BasePrintLib.lib \
+                 $(EFILIB)/BasePcdLibNull/BasePcdLibNull/OUTPUT/BasePcdLibNull.lib \
+                 $(EFILIB)/UefiDebugLibConOut/UefiDebugLibConOut/OUTPUT/UefiDebugLibConOut.lib \
+                 $(EFILIB)/BaseLib/BaseLib/OUTPUT/BaseLib.lib \
+                 $(EFILIB)/BaseMemoryLib/BaseMemoryLib/OUTPUT/BaseMemoryLib.lib \
+                 $(EFILIB)/UefiBootServicesTableLib/UefiBootServicesTableLib/OUTPUT/UefiBootServicesTableLib.lib \
+                 $(EFILIB)/UefiMemoryAllocationLib/UefiMemoryAllocationLib/OUTPUT/UefiMemoryAllocationLib.lib \
+                 $(EFILIB)/UefiDevicePathLib/UefiDevicePathLib/OUTPUT/UefiDevicePathLib.lib \
+                 $(EFILIB)/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib/OUTPUT/UefiRuntimeServicesTableLib.lib \
+                 $(EFILIB)/UefiLib/UefiLib/OUTPUT/UefiLib.lib \
+                 $(EFILIB)/UefiApplicationEntryPoint/UefiApplicationEntryPoint/OUTPUT/UefiApplicationEntryPoint.lib
+
+ifeq ($(ARCH),aarch64)
+  ALL_EFILIBS +=  $(EFILIB)/BaseStackCheckLib/BaseStackCheckLib/OUTPUT/BaseStackCheckLib.lib
+endif
+
+INCLUDE_DIRS    = -I $(EDK2BASE)/MdePkg \
+                  -I $(EDK2BASE)/MdePkg/Include \
+                  -I $(EDK2BASE)/MdePkg/Include/$(ARCHDIR) \
+                 -I $(EDK2BASE)/EdkCompatibilityPkg/Foundation/Framework/Include \
+                 -I $(EDK2BASE)/EdkCompatibilityPkg/Foundation/Library/Dxe/Include \
+                 -I $(EDK2BASE)/MdeModulePkg/ \
+                  -I $(EDK2BASE)/MdeModulePkg/Include \
+                  -I $(EDK2BASE)/IntelFrameworkPkg/Include \
+                  -I $(EDK2BASE)/MdePkg/Include/$(ARCHDIR) \
+                 -I ../libeg \
+                 -I ../include \
+                 -I ..
+
+GPTSYNC_NAMES    = gptsync lib os_efi AutoGen ../EfiLib/BmLib
+OBJS             = $(GPTSYNC_NAMES:=.obj)
+BUILDME          = gptsync_$(FILENAME_CODE).efi
+
+OPTIMFLAGS      = -fno-strict-aliasing -Wno-address -Os
+DEBUGFLAGS      = -Wall -Wno-missing-braces -Wno-array-bounds -ffunction-sections -fdata-sections
+CFLAGS          = $(OPTIMFLAGS) -g -fshort-wchar -fno-stack-protector $(DEBUGFLAGS) -c -DHOST_EFI_EDK2 -D__MAKEWITH_TIANO
+#CFLAGS          = $(OPTIMFLAGS) -g -fshort-wchar -fno-stack-protector $(DEBUGFLAGS) -c -include AutoGen.h -DHOST_EFI_EDK2
+
+prefix          ?= /usr/bin/
+CC              ?= $(prefix)gcc
+AS              ?= $(prefix)as
+LD              ?= $(prefix)ld
+AR              ?= $(prefix)ar
+RANLIB          ?= $(prefix)ranlib
+OBJCOPY         ?= $(prefix)objcopy
+GENFW           ?= $(EDK2BASE)/BaseTools/Source/C/bin/GenFw
+
+
+LDSCRIPT = $(EDK2BASE)/BaseTools/Scripts/gcc4.4-ld-script
+
+LDFLAGS         = -nostdlib -n -q --gc-sections --script=$(EDK2BASE)/BaseTools/Scripts/gcc4.4-ld-script \
+                  --entry efi_main -u efi_main -m $(LD_CODE)
+
+%.obj: %.c
+       $(CC) $(ARCH_C_FLAGS) $(CFLAGS) $(INCLUDE_DIRS) -DNO_BUILTIN_VA_FUNCS -c $< -o $@
+       +make -C ../EfiLib -f Make.tiano
+
+ifneq (,$(filter %.efi,$(BUILDME)))
+
+DLL_TARGET = $(subst .efi,.dll,$(BUILDME))
+
+all: $(BUILDME)
+
+$(DLL_TARGET): $(OBJS)
+       $(LD) -o gptsync_$(FILENAME_CODE).dll $(LDFLAGS) --start-group $(ALL_EFILIBS) $(OBJS) --end-group
+
+$(BUILDME): $(DLL_TARGET)
+       $(OBJCOPY) --strip-unneeded -R .eh_frame $(DLL_TARGET)
+       $(GENFW) -e UEFI_APPLICATION -o $(BUILDME) $(DLL_TARGET)
+
+endif
+
diff --git a/gptsync/Make.unix b/gptsync/Make.unix
new file mode 100644 (file)
index 0000000..a1d7282
--- /dev/null
@@ -0,0 +1,74 @@
+#
+# Makefile for gptsync on Unix platforms
+#
+
+RM = rm -f
+CC = gcc
+
+GPTSYNC_TARGET = gptsync
+GPTSYNC_OBJS   = gptsync.unix.o lib.unix.o os_unix.gptsync.o
+
+SHOWPART_TARGET = showpart
+SHOWPART_OBJS   = showpart.unix.o lib.unix.o os_unix.showpart.o
+
+CPPFLAGS = -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -I../include
+CFLAGS   = -Wall
+LDFLAGS  =
+LIBS     =
+
+# system-dependent additions
+
+system = $(shell uname)
+ifeq ($(system),Darwin)
+  CC        = gcc-4.0
+  # TODO: re-enable this once the code is no longer little-endian specific
+  #CFLAGS   += -arch i386 -arch ppc
+  #LDFLAGS  += -arch i386 -arch ppc
+  ifeq (/Developer/SDKs/MacOSX10.4u.sdk,$(wildcard /Developer/SDKs/MacOSX10.4u.sdk))
+    CPPFLAGS += -isysroot /Developer/SDKs/MacOSX10.4u.sdk
+    LDFLAGS  += -Wl,-syslibroot,/Developer/SDKs/MacOSX10.4u.sdk
+  endif
+endif
+
+# real making
+
+all: $(GPTSYNC_TARGET) $(SHOWPART_TARGET)
+
+$(GPTSYNC_TARGET): $(GPTSYNC_OBJS)
+       $(CC) $(LDFLAGS) -o $@ $(GPTSYNC_OBJS) $(LIBS)
+
+gptsync.unix.o: gptsync.c
+       $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
+os_unix.gptsync.o: os_unix.c
+       $(CC) $(CPPFLAGS) -DPROGNAME=gptsync $(CFLAGS) -c $< -o $@
+
+$(SHOWPART_TARGET): $(SHOWPART_OBJS)
+       $(CC) $(LDFLAGS) -o $@ $(SHOWPART_OBJS) $(LIBS)
+
+showpart.unix.o: showpart.c
+       $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
+os_unix.showpart.o: os_unix.c
+       $(CC) $(CPPFLAGS) -DPROGNAME=showpart -DNOREADONLYWARN $(CFLAGS) -c $< -o $@
+
+lib.unix.o: lib.c
+       $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
+
+# additional dependencies
+
+gptsync.unix.o: gptsync.h ../include/syslinux_mbr.h
+os_unix.gptsync.o: gptsync.h
+
+showpart.unix.o: gptsync.h
+os_unix.showpart.o: gptsync.h
+
+lib.unix.o: gptsync.h
+
+# cleanup
+
+clean:
+       $(RM) *.o *~ *% $(GPTSYNC_TARGET) $(SHOWPART_TARGET)
+
+distclean: clean
+       $(RM) .depend
+
+# eof
diff --git a/gptsync/Makefile b/gptsync/Makefile
new file mode 100644 (file)
index 0000000..8987534
--- /dev/null
@@ -0,0 +1,29 @@
+# meta-Makefile for gptsync program; controls use of EFI build using
+# GNU-EFI vs. TianoCore EDK2 or build for Unix/Linux.
+#
+# Most of the functionality is in Make.tiano, Make.gnuefi, and
+# Make.unix; this Makefile just dispatches based on options
+# passed to it....
+
+TEXTFILES = gptsync.txt
+
+TARGET = tiano
+
+all:   $(TARGET)
+
+gnuefi:
+       +make -f Make.gnuefi gptsync.efi
+
+tiano:
+       +make -f Make.tiano
+
+unix:
+       +make -f Make.unix
+
+# utility rules
+
+clean:
+       rm -f *~ *.bak *.o *.obj *.so *.efi *.dll err.txt gptsync_*.txt gptsync showpart $(TEXTFILES)
+
+
+# DO NOT DELETE
diff --git a/gptsync/README.txt b/gptsync/README.txt
new file mode 100644 (file)
index 0000000..02a3c89
--- /dev/null
@@ -0,0 +1,45 @@
+This directory contains the source code for gptsync, which is a program for
+creating hybrid MBRs (http://www.rodsbooks.com/gdisk/hybrid.html).
+
+HYBRID MBRS ARE UGLY AND DANGEROUS HACKS, AND SHOULD NOT BE USED UNLESS
+ABSOLUTELY NECESSARY!
+
+Despite their dangers, hybrid MBRs are useful because Windows interprets
+hybrid MBR disks as having an MBR partition table, whereas OS X and Linux
+interpret such disks as having a GUID partition table (GPT). Since Windows
+ties its boot mode to the firmware type (MBR/BIOS and GPT/EFI), a hybrid
+MBR enables Windows to boot in BIOS mode from a disk that's primarily a GPT
+disk, such as a Macintosh OS X disk.
+
+Unfortunately, Apple uses hybrid MBRs as part of its workaround to enable
+Macs to boot Windows in BIOS mode while also supporting a standard EFI-mode
+boot of OS X. Many Linux distributions also install in BIOS mode on Macs,
+and so use hybrid MBRs; but it's usually possible to add an EFI-mode boot
+loader to get Macs to boot Linux in EFI mode, thus obviating the need for a
+hybrid MBR. Some Hackintosh installations rely on a hybrid MBR for reasons
+similar to those of OS X on a real Mac. Thus, you should use a hybrid MBR
+*ONLY* on a Mac that dual-boots with Windows or some other OS in BIOS mode
+or in very rare circumstances on other computers.
+
+The version of gptsync provided with rEFInd is heavily modified from the
+original rEFIt version of the program. Most notably, it's "smarter" about
+creating a hybrid MBR: It prioritizes placement of Windows (FAT and NTFS)
+partitions in the MBR side, followed by Linux partitions. Other partitions,
+such as OS X's HFS+ partitions, might not appear at all in the hybrid MBR,
+whereas they generally do appear in hybrid MBRs created by rEFIt's version
+of gptsync. In the rEFIt version of gptsync, OS X partitions can crowd out
+FAT or NTFS partitions, particularly on computers with shared FAT or NTFS
+partitions, multiple Windows installations, or triple-boots with OS X,
+Windows, and Linux. The rEFInd version of gptsync also checks the
+firmware's author and warns if you're trying to run the program on anything
+but Apple firmware, since in most such cases creating a hybrid MBR is *NOT*
+desirable.
+
+Although the Makefile supports building for both EFI (via the "gnuefi" and
+"tiano" targets) and Unix/Linux (via the "unix" target), the Unix build is
+currently broken; it returns a bogus error about an unknown GPT spec
+revision. If you want to create a hybrid MBR in an OS, you're better off
+using gdisk (http://www.rodsbooks.com/gdisk/), which provides much better
+control of the hybrid MBR creation process. gdisk may also be preferable if
+you have an unusual partition layout, many partitions, or specific
+requirements that you understand well.
diff --git a/gptsync/gptsync.8 b/gptsync/gptsync.8
new file mode 100644 (file)
index 0000000..0639e33
--- /dev/null
@@ -0,0 +1,16 @@
+.TH "gptsync" 8 "2006 Jul 2" "Debian" "rEFIt"
+.SH NAME
+gptsync \- GPT partition table to MBR partition table synchronisation
+.SH "SYNOPSIS"
+.BI "gptsync " "device"
+.SH "DESCRIPTION"
+Reads the GPT partition table on the device and synchronise content of
+MBR partition table on the device.  Useful for situations (as in
+mactel linux) where legacy operating systems require MBR partition
+table to function properly, while most other operating systems can
+work with GPT.
+
+.SH "Author"
+Written by Christoph Pfisterer. This manual page contributed for Debian by
+Junichi Uekawa <dancer@debian.org>, but may be used for others.
+
diff --git a/gptsync/gptsync.c b/gptsync/gptsync.c
new file mode 100644 (file)
index 0000000..2696e66
--- /dev/null
@@ -0,0 +1,530 @@
+/*
+ * gptsync/gptsync.c
+ * Platform-independent code for syncing GPT and MBR
+ *
+ * Copyright (c) 2006-2007 Christoph Pfisterer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/* Changes copyright (c) 2013 Roderick W. Smith */
+
+#include "gptsync.h"
+
+#include "syslinux_mbr.h"
+#define memcpy(a, b, c) CopyMem(a, b, c)
+
+//
+// MBR functions
+//
+
+static UINTN check_mbr(VOID)
+{
+    UINTN       i, k;
+    BOOLEAN     found = FALSE;
+
+    // check each entry
+    for (i = 0; i < mbr_part_count; i++) {
+        // check for overlap
+        for (k = 0; k < mbr_part_count; k++) {
+            if (k != i && !(mbr_parts[i].start_lba > mbr_parts[k].end_lba || mbr_parts[k].start_lba > mbr_parts[i].end_lba)) {
+                Print(L"Status: MBR partition table is invalid, partitions overlap.\n");
+                return EFI_UNSUPPORTED;
+            }
+        }
+
+        // check for extended partitions
+        if (mbr_parts[i].mbr_type == 0x05 || mbr_parts[i].mbr_type == 0x0f || mbr_parts[i].mbr_type == 0x85) {
+            Print(L"Status: Extended partition found in MBR table, will not touch this disk.\n",
+                  gpt_parts[i].gpt_parttype->name);
+            return EFI_UNSUPPORTED;
+        }
+
+        // Check for matching GPT partitition; if not found, flag error
+        if ((mbr_parts[i].mbr_type != 0xEE) && (mbr_parts[i].mbr_type != 0x00)) {
+            found = FALSE;
+            for (k = 0; (k < gpt_part_count) && !found; k++) {
+               if ((mbr_parts[i].start_lba == gpt_parts[k].start_lba) && (mbr_parts[i].end_lba == gpt_parts[k].end_lba)) {
+                  found = TRUE;
+               } // if
+            } // for
+            if (!found) {
+               Print(L"Status: Found MBR partition with no matching GPT partition. Re-syncing could\n");
+               Print(L"destroy data; will not touch this disk.\n");
+               return EFI_UNSUPPORTED;
+            } // if
+        } // if
+
+    } // for
+
+    return 0;
+} // UINTN check_mbr()
+
+static UINTN write_mbr(VOID)
+{
+    UINTN               status;
+    UINTN               i, k;
+    UINT8               active;
+    UINT64              lba;
+    MBR_PART_INFO       *table;
+    BOOLEAN             have_bootcode;
+
+    Print(L"\nWriting new MBR...\n");
+
+    // read MBR data
+    status = read_sector(0, sector);
+    if (status != 0)
+        return status;
+
+    // write partition table
+    *((UINT16 *)(sector + 510)) = 0xaa55;
+
+    table = (MBR_PART_INFO *)(sector + 446);
+    active = 0x80;
+    for (i = 0; i < 4; i++) {
+        for (k = 0; k < new_mbr_part_count; k++) {
+            if (new_mbr_parts[k].index == i)
+                break;
+        }
+        if (k >= new_mbr_part_count) {
+            // unused entry
+            table[i].flags        = 0;
+            table[i].start_chs[0] = 0;
+            table[i].start_chs[1] = 0;
+            table[i].start_chs[2] = 0;
+            table[i].type         = 0;
+            table[i].end_chs[0]   = 0;
+            table[i].end_chs[1]   = 0;
+            table[i].end_chs[2]   = 0;
+            table[i].start_lba    = 0;
+            table[i].size         = 0;
+        } else {
+            if (new_mbr_parts[k].active) {
+                table[i].flags        = active;
+                active = 0x00;
+            } else
+                table[i].flags        = 0x00;
+            table[i].start_chs[0] = 0xfe;
+            table[i].start_chs[1] = 0xff;
+            table[i].start_chs[2] = 0xff;
+            table[i].type         = new_mbr_parts[k].mbr_type;
+            table[i].end_chs[0]   = 0xfe;
+            table[i].end_chs[1]   = 0xff;
+            table[i].end_chs[2]   = 0xff;
+
+            lba = new_mbr_parts[k].start_lba;
+            if (lba > MAX_MBR_LBA) {
+                Print(L"Warning: Partition %d starts beyond 2 TiB limit\n", i+1);
+                lba = MAX_MBR_LBA;
+            }
+            table[i].start_lba    = (UINT32)lba;
+
+            lba = new_mbr_parts[k].end_lba + 1 - new_mbr_parts[k].start_lba;
+            if (lba > MAX_MBR_LBA) {
+                Print(L"Warning: Partition %d extends beyond 2 TiB limit\n", i+1);
+                lba = MAX_MBR_LBA;
+            }
+            table[i].size         = (UINT32)lba;
+        }
+    }
+
+    // add boot code if necessary
+    have_bootcode = FALSE;
+    for (i = 0; i < MBR_BOOTCODE_SIZE; i++) {
+        if (sector[i] != 0) {
+            have_bootcode = TRUE;
+            break;
+        }
+    }
+    if (!have_bootcode) {
+        // no boot code found in the MBR, add the syslinux MBR code
+        SetMem(sector, MBR_BOOTCODE_SIZE, 0);
+        CopyMem(sector, syslinux_mbr, SYSLINUX_MBR_SIZE);
+    }
+
+    // write MBR data
+    status = write_sector(0, sector);
+    if (status != 0)
+        return status;
+
+    Print(L"MBR updated successfully!\n");
+
+    return 0;
+}
+
+//
+// GPT functions
+//
+
+static UINTN check_gpt(VOID)
+{
+    UINTN       i, k;
+
+    if (gpt_part_count == 0) {
+        Print(L"Status: No GPT partition table, no need to sync.\n");
+        return EFI_UNSUPPORTED;
+    }
+
+    // check each entry
+    for (i = 0; i < gpt_part_count; i++) {
+        // check sanity
+        if (gpt_parts[i].end_lba < gpt_parts[i].start_lba) {
+            Print(L"Status: GPT partition table is invalid.\n");
+            return EFI_UNSUPPORTED;
+        }
+        // check for overlap
+        for (k = 0; k < gpt_part_count; k++) {
+            if (k != i && !(gpt_parts[i].start_lba > gpt_parts[k].end_lba || gpt_parts[k].start_lba > gpt_parts[i].end_lba)) {
+                Print(L"Status: GPT partition table is invalid, partitions overlap.\n");
+                return EFI_UNSUPPORTED;
+            }
+        }
+
+        // check for partitions kind
+        if (gpt_parts[i].gpt_parttype->kind == GPT_KIND_FATAL) {
+            Print(L"Status: GPT partition of type '%s' found, will not touch this disk.\n",
+                  gpt_parts[i].gpt_parttype->name);
+            return EFI_UNSUPPORTED;
+        }
+    }
+
+    return 0;
+} // VOID check_gpt()
+
+//
+// compare GPT and MBR tables
+//
+
+#define ACTION_NONE        (0)
+#define ACTION_NOP         (1)
+#define ACTION_REWRITE     (2)
+
+// Copy a single GPT entry to the new_mbr_parts array.
+static VOID copy_gpt_to_new_mbr(UINTN gpt_num, UINTN mbr_num) {
+   new_mbr_parts[mbr_num].index     = mbr_num;
+   new_mbr_parts[mbr_num].start_lba = gpt_parts[gpt_num].start_lba;
+   new_mbr_parts[mbr_num].end_lba   = gpt_parts[gpt_num].end_lba;
+   new_mbr_parts[mbr_num].mbr_type  = gpt_parts[gpt_num].mbr_type;
+   new_mbr_parts[mbr_num].active    = FALSE;
+} // VOID copy_gpt_to_new_mbr()
+
+// A simple bubble sort for the MBR partitions.
+static VOID sort_mbr(PARTITION_INFO *parts) {
+   PARTITION_INFO one_part;
+   int c, d;
+
+   if (parts == NULL)
+      return;
+
+   for (c = 0 ; c < 3; c++) {
+      for (d = 1 ; d < 3 - c; d++) {
+         if ((parts[d].start_lba > parts[d + 1].start_lba) && (parts[d].start_lba > 0) && (parts[d + 1].start_lba > 0)) {
+            one_part           = parts[d];
+            parts[d]           = parts[d + 1];
+            parts[d + 1]       = one_part;
+            parts[d].index     = d;
+            parts[d + 1].index = d + 1;
+         } // if
+      } // for
+   } // for
+} // VOID sort_mbr()
+
+// Generate a hybrid MBR based on the current GPT. Stores the result in the
+// new_mbr_parts[] array.
+static VOID generate_hybrid_mbr(VOID) {
+    UINTN i, k, iter, count_active;
+    UINT64 first_used_lba;
+
+    new_mbr_part_count = 1;
+    first_used_lba = (UINT64) MAX_MBR_LBA + (UINT64) 1;
+
+    // Copy partitions in three passes....
+    // First, do FAT and NTFS partitions....
+    i = 0;
+    do {
+        if ((gpt_parts[i].start_lba > 0) && (gpt_parts[i].end_lba > 0) &&
+            (gpt_parts[i].end_lba <= MAX_MBR_LBA) &&                    /* Within MBR limits */
+            (gpt_parts[i].gpt_parttype->kind == GPT_KIND_BASIC_DATA) && /* MS Basic Data GPT type code */
+            (gpt_parts[i].mbr_type != 0x83)) {                          /* Not containing Linux filesystem */
+           copy_gpt_to_new_mbr(i, new_mbr_part_count);
+           if (new_mbr_parts[new_mbr_part_count].start_lba < first_used_lba)
+              first_used_lba = new_mbr_parts[new_mbr_part_count].start_lba;
+
+           new_mbr_part_count++;
+        }
+        i++;
+    } while (i < gpt_part_count && new_mbr_part_count <= 3);
+
+    // Second, do Linux partitions. Note that we start from the END of the
+    // partition list, so as to maximize the space covered by the 0xEE
+    // partition if there are several Linux partitions before other hybridized
+    // partitions.
+    i = gpt_part_count - 1; // Note that gpt_part_count can't be 0; filtered by check_gpt()
+    while (i < gpt_part_count && new_mbr_part_count <= 3) { // if too few GPT partitions, i loops around to a huge value
+        if ((gpt_parts[i].start_lba > 0) && (gpt_parts[i].end_lba > 0) &&
+            (gpt_parts[i].end_lba <= MAX_MBR_LBA) &&
+            ((gpt_parts[i].gpt_parttype->kind == GPT_KIND_DATA) || (gpt_parts[i].gpt_parttype->kind == GPT_KIND_BASIC_DATA)) &&
+            (gpt_parts[i].mbr_type == 0x83)) {
+           copy_gpt_to_new_mbr(i, new_mbr_part_count);
+           if (new_mbr_parts[new_mbr_part_count].start_lba < first_used_lba)
+              first_used_lba = new_mbr_parts[new_mbr_part_count].start_lba;
+
+           new_mbr_part_count++;
+       }
+       i--;
+    } // while
+
+    // Third, do anything that's left to cover uncovered spaces; but this requires
+    // first creating the EFI protective entry, since we don't want to bother with
+    // anything already covered by this entry....
+    new_mbr_parts[0].index     = 0;
+    new_mbr_parts[0].start_lba = 1;
+    new_mbr_parts[0].end_lba   = (disk_size() > first_used_lba) ? (first_used_lba - 1) : disk_size() - 1;
+    if (new_mbr_parts[0].end_lba > MAX_MBR_LBA)
+       new_mbr_parts[0].end_lba = MAX_MBR_LBA;
+    new_mbr_parts[0].mbr_type  = 0xEE;
+    i = 0;
+    while (i < gpt_part_count && new_mbr_part_count <= 3) {
+       if ((gpt_parts[i].start_lba > new_mbr_parts[0].end_lba) && (gpt_parts[i].end_lba > 0) &&
+           (gpt_parts[i].end_lba <= MAX_MBR_LBA) &&
+           (gpt_parts[i].gpt_parttype->kind != GPT_KIND_BASIC_DATA) &&
+           (gpt_parts[i].mbr_type != 0x83)) {
+          copy_gpt_to_new_mbr(i, new_mbr_part_count);
+          new_mbr_part_count++;
+       }
+       i++;
+    } // while
+
+    // find matching partitions in the old MBR table, copy undetected details....
+    for (i = 1; i < new_mbr_part_count; i++) {
+       for (k = 0; k < mbr_part_count; k++) {
+           if (mbr_parts[k].start_lba == new_mbr_parts[i].start_lba) {
+               // keep type if not detected
+               if (new_mbr_parts[i].mbr_type == 0)
+                   new_mbr_parts[i].mbr_type = mbr_parts[k].mbr_type;
+               // keep active flag
+               new_mbr_parts[i].active = mbr_parts[k].active;
+               break;
+           } // if
+       } // for (k...)
+       if (new_mbr_parts[i].mbr_type == 0) {
+          // final fallback: set to a (hopefully) unused type
+          new_mbr_parts[i].mbr_type = 0xc0;
+       } // if
+    } // for (i...)
+
+    sort_mbr(new_mbr_parts);
+
+    // make sure there's exactly one active partition
+    for (iter = 0; iter < 3; iter++) {
+        // check
+        count_active = 0;
+        for (i = 0; i < new_mbr_part_count; i++)
+            if (new_mbr_parts[i].active)
+                count_active++;
+        if (count_active == 1)
+            break;
+
+        // set active on the first matching partition
+        if (count_active == 0) {
+            for (i = 0; i < new_mbr_part_count; i++) {
+                if (((new_mbr_parts[i].mbr_type == 0x07 ||    // NTFS
+                      new_mbr_parts[i].mbr_type == 0x0b ||    // FAT32
+                      new_mbr_parts[i].mbr_type == 0x0c)) ||  // FAT32 (LBA)
+                    (iter >= 1 && (new_mbr_parts[i].mbr_type == 0x83)) ||  // Linux
+                    (iter >= 2 && i > 0)) {
+                    new_mbr_parts[i].active = TRUE;
+                    break;
+                }
+            }
+        } else if (count_active > 1 && iter == 0) {
+            // too many active partitions, try deactivating the ESP / EFI Protective entry
+            if ((new_mbr_parts[0].mbr_type == 0xee || new_mbr_parts[0].mbr_type == 0xef) &&
+                new_mbr_parts[0].active) {
+                new_mbr_parts[0].active = FALSE;
+            }
+        } else if (count_active > 1 && iter > 0) {
+            // too many active partitions, deactivate all but the first one
+            count_active = 0;
+            for (i = 0; i < new_mbr_part_count; i++)
+                if (new_mbr_parts[i].active) {
+                    if (count_active > 0)
+                        new_mbr_parts[i].active = FALSE;
+                    count_active++;
+                }
+        }
+    } // for
+} // VOID generate_hybrid_mbr()
+
+// Examine partitions and decide whether a rewrite is in order.
+// Note that this function MAY ask user for advice.
+// Note that this function assumes the new hybrid MBR has already
+// been computed and stored in new_mbr_parts[].
+static BOOLEAN should_rewrite(VOID) {
+   BOOLEAN retval = TRUE, all_identical = TRUE, invalid;
+   UINTN i, num_existing_hybrid = 0, num_new_hybrid = 0;
+
+   // Check to see if the proposed table is identical to the current one;
+   // if so, synchronizing is pointless....
+   for (i = 0; i < 4; i++) {
+      if ((new_mbr_parts[i].mbr_type != 0xEE) && (mbr_parts[i].mbr_type != 0xEE) &&
+          ((new_mbr_parts[i].active != mbr_parts[i].active) ||
+           (new_mbr_parts[i].start_lba != mbr_parts[i].start_lba) ||
+           (new_mbr_parts[i].end_lba != mbr_parts[i].end_lba) ||
+           (new_mbr_parts[i].mbr_type != mbr_parts[i].mbr_type)))
+         all_identical = FALSE;
+
+      // while we're looping, count the number of old & new hybrid partitions....
+      if ((mbr_parts[i].mbr_type != 0x00) && (mbr_parts[i].mbr_type != 0xEE))
+         num_existing_hybrid++;
+      if ((new_mbr_parts[i].mbr_type != 0x00) && (new_mbr_parts[i].mbr_type != 0xEE))
+         num_new_hybrid++;
+   } // for
+
+   if (all_identical) {
+      Print(L"Tables are synchronized, no need to sync.\n");
+      return FALSE;
+   }
+
+   // If there's nothing to hybridize, but an existing hybrid MBR exists, offer to replace
+   // the hybrid MBR with a protective MBR.
+   if ((num_new_hybrid == 0) && (num_existing_hybrid > 0)) {
+      Print(L"Found no partitions that could be hybridized, but an existing hybrid MBR exists.\n");
+      Print(L"If you proceed, a fresh protective MBR will be created. Do you want to create\n");
+      invalid = input_boolean(STR("this new protective MBR, erasing the hybrid MBR? [y/N] "), &retval);
+      if (invalid)
+         retval = FALSE;
+   } // if
+
+   // If existing hybrid MBR that's NOT identical to the new one, ask the user
+   // before overwriting the old one.
+   if ((num_new_hybrid > 0) && (num_existing_hybrid > 0)) {
+      Print(L"Existing hybrid MBR detected, but it's not identical to what this program\n");
+      Print(L"would generate. Do you want to see the hybrid MBR that this program would\n");
+      invalid = input_boolean(STR("generate? [y/N] "), &retval);
+      if (invalid)
+         retval = FALSE;
+   } // if
+
+   return retval;
+} // BOOLEAN should_rewrite()
+
+static UINTN analyze(VOID)
+{
+    UINTN   i, detected_parttype;
+    CHARN   *fsname;
+    UINTN   status;
+
+    new_mbr_part_count = 0;
+
+    // determine correct MBR types for GPT partitions
+    if (gpt_part_count == 0) {
+        Print(L"Status: No GPT partitions defined, nothing to sync.\n");
+        return 0;
+    }
+    for (i = 0; i < gpt_part_count; i++) {
+        gpt_parts[i].mbr_type = gpt_parts[i].gpt_parttype->mbr_type;
+        if (gpt_parts[i].gpt_parttype->kind == GPT_KIND_BASIC_DATA) {
+            // Basic Data: need to look at data in the partition
+            status = detect_mbrtype_fs(gpt_parts[i].start_lba, &detected_parttype, &fsname);
+            if (status != 0)
+               Print(L"Warning: Error %d when detecting filesystem type!\n", status);
+            if (detected_parttype)
+                gpt_parts[i].mbr_type = detected_parttype;
+            else
+                gpt_parts[i].mbr_type = 0x0b;  // fallback: FAT32
+        }
+        // NOTE: mbr_type may still be 0 if content detection fails for exotic GPT types or file systems
+    } // for
+
+    // generate the new table
+    generate_hybrid_mbr();
+    if (!should_rewrite())
+       return EFI_ABORTED;
+
+    // display table
+    Print(L"\nProposed new MBR partition table:\n");
+    Print(L" # A    Start LBA      End LBA  Type\n");
+    for (i = 0; i < new_mbr_part_count; i++) {
+        Print(L" %d %s %12lld %12lld  %02x  %s\n",
+              new_mbr_parts[i].index + 1,
+              new_mbr_parts[i].active ? STR("*") : STR(" "),
+              new_mbr_parts[i].start_lba,
+              new_mbr_parts[i].end_lba,
+              new_mbr_parts[i].mbr_type,
+              mbr_parttype_name(new_mbr_parts[i].mbr_type));
+    }
+
+    return 0;
+} // UINTN analyze()
+
+//
+// sync algorithm entry point
+//
+
+UINTN gptsync(VOID)
+{
+    UINTN   status = 0;
+    UINTN   status_gpt, status_mbr;
+    BOOLEAN proceed = FALSE;
+
+    Print(L"gptsync version %s\ncopyright (c) 2006-2007 Christoph Pfisterer & 2013 Roderick W. Smith\n", VERSION);
+
+    // get full information from disk
+    status_gpt = read_gpt();
+    status_mbr = read_mbr();
+    if (status_gpt != 0 || status_mbr != 0)
+        return (status_gpt || status_mbr);
+
+    // cross-check current situation
+    Print(L"\n");
+    status = check_gpt();   // check GPT for consistency
+    if (status != 0)
+        return status;
+    status = check_mbr();   // check MBR for consistency
+    if (status != 0)
+        return status;
+    status = analyze();     // analyze the situation & compose new MBR table
+    if (status != 0)
+        return status;
+    if (new_mbr_part_count == 0)
+        return status;
+
+    // offer user the choice what to do
+    status = input_boolean(STR("\nMay I update the MBR as printed above? [y/N] "), &proceed);
+    if (status != 0 || proceed != TRUE)
+        return status;
+
+    // adjust the MBR and write it back
+    status = write_mbr();
+    if (status != 0)
+        return status;
+
+    return status;
+}
diff --git a/gptsync/gptsync.h b/gptsync/gptsync.h
new file mode 100644 (file)
index 0000000..1171472
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ * gptsync/gptsync.h
+ * Common header for gptsync and showpart
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/* Changes copyright (c) 2013 Roderick W. Smith */
+
+#define VERSION L"0.9.1"
+
+//
+// config
+//
+
+
+#if defined(EFI32) || defined(EFIX64) || defined(EFIAARCH64)
+#define CONFIG_EFI
+#endif
+
+//
+// platform-dependent types
+//
+
+#ifdef CONFIG_EFI
+
+#ifdef __MAKEWITH_GNUEFI
+#include "efi.h"
+#include "efilib.h"
+#else
+#include "../include/tiano_includes.h"
+#endif
+
+#define copy_guid(destguid, srcguid) (CopyMem(destguid, srcguid, 16))
+#define guids_are_equal(guid1, guid2) (CompareMem(guid1, guid2, 16) == 0)
+
+typedef CHAR16 CHARN;
+#define STR(x) L##x
+
+#endif
+
+
+#ifndef CONFIG_EFI
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <fcntl.h>
+
+/*
+typedef int                 INTN;
+typedef unsigned int        UINTN;
+typedef unsigned char       UINT8;
+typedef unsigned short      UINT16;
+typedef unsigned long       UINT32;
+typedef unsigned long long  UINT64;
+typedef void                VOID;
+*/
+
+typedef int                 BOOLEAN;
+#ifndef FALSE
+#define FALSE (0)
+#endif
+#ifndef TRUE
+#define TRUE  (1)
+#endif
+
+typedef unsigned short      CHAR16;
+typedef char                CHARN;
+#define STR(x) x
+
+void Print(wchar_t *format, ...);
+
+// FUTURE: use STR(),  #define Print printf
+
+#define copy_guid(destguid, srcguid) (CopyMem(destguid, srcguid, 16))
+#define guids_are_equal(guid1, guid2) (memcmp(guid1, guid2, 16) == 0)
+
+#define EFI_UNSUPPORTED 1
+#define EFI_ABORTED     2
+
+#endif
+
+#define GPT_KIND_SYSTEM     (0)
+#define GPT_KIND_DATA       (1)
+#define GPT_KIND_BASIC_DATA (2)
+#define GPT_KIND_FATAL      (3)
+
+#define MAX_MBR_LBA  0xFFFFFFFF
+
+//
+// platform-independent types
+//
+
+typedef struct {
+    UINT8   flags;
+    UINT8   start_chs[3];
+    UINT8   type;
+    UINT8   end_chs[3];
+    UINT32  start_lba;
+    UINT32  size;
+} MBR_PART_INFO;
+
+typedef struct {
+    UINT8   type;
+    CHARN   *name;
+} MBR_PARTTYPE;
+
+typedef struct {
+    UINT64  signature;
+    UINT32  spec_revision;
+    UINT32  header_size;
+    UINT32  header_crc32;
+    UINT32  reserved;
+    UINT64  header_lba;
+    UINT64  alternate_header_lba;
+    UINT64  first_usable_lba;
+    UINT64  last_usable_lba;
+    UINT8   disk_guid[16];
+    UINT64  entry_lba;
+    UINT32  entry_count;
+    UINT32  entry_size;
+    UINT32  entry_crc32;
+} GPT_HEADER;
+
+typedef struct {
+    UINT8   type_guid[16];
+    UINT8   partition_guid[16];
+    UINT64  start_lba;
+    UINT64  end_lba;
+    UINT64  attributes;
+    CHAR16  name[36];
+} GPT_ENTRY;
+
+typedef struct {
+    UINT8   guid[16];
+    UINT8   mbr_type;
+    CHARN   *name;
+    UINTN   kind;
+} GPT_PARTTYPE;
+
+typedef struct {
+    UINTN   index;
+    UINT64  start_lba;
+    UINT64  end_lba;
+    UINTN   mbr_type;
+    UINT8   gpt_type[16];
+    GPT_PARTTYPE *gpt_parttype;
+    BOOLEAN active;
+} PARTITION_INFO;
+
+//
+// functions provided by the OS-specific module
+//
+
+UINT64 disk_size(VOID);
+UINTN read_sector(UINT64 lba, UINT8 *buffer);
+UINTN write_sector(UINT64 lba, UINT8 *buffer);
+UINTN input_boolean(CHARN *prompt, BOOLEAN *bool_out);
+
+//
+// vars and functions provided by the common lib module
+//
+
+extern UINT8           empty_guid[16];
+
+extern PARTITION_INFO  mbr_parts[4];
+extern UINTN           mbr_part_count;
+extern PARTITION_INFO  gpt_parts[128];
+extern UINTN           gpt_part_count;
+
+extern PARTITION_INFO  new_mbr_parts[4];
+extern UINTN           new_mbr_part_count;
+
+extern UINT8           sector[512];
+
+extern MBR_PARTTYPE    mbr_types[];
+extern GPT_PARTTYPE    gpt_types[];
+extern GPT_PARTTYPE    gpt_dummy_type;
+
+CHARN * mbr_parttype_name(UINT8 type);
+UINTN read_mbr(VOID);
+
+GPT_PARTTYPE * gpt_parttype(UINT8 *type_guid);
+UINTN read_gpt(VOID);
+
+UINTN detect_mbrtype_fs(UINT64 partlba, UINTN *parttype, CHARN **fsname);
+
+//
+// actual platform-independent programs
+//
+
+UINTN gptsync(VOID);
+UINTN showpart(VOID);
+
+/* EOF */
diff --git a/gptsync/gptsync.mak b/gptsync/gptsync.mak
new file mode 100644 (file)
index 0000000..004f7f7
--- /dev/null
@@ -0,0 +1,71 @@
+#\r
+# gptsync/gptsync.mak\r
+# Build control file for the gptsync tool\r
+# \r
+\r
+#\r
+# Include sdk.env environment\r
+#\r
+\r
+!include $(SDK_INSTALL_DIR)\build\$(SDK_BUILD_ENV)\sdk.env\r
+\r
+#\r
+# Set the base output name and entry point\r
+#\r
+\r
+BASE_NAME         = gptsync\r
+IMAGE_ENTRY_POINT = efi_main\r
+\r
+#\r
+# Globals needed by master.mak\r
+#\r
+\r
+TARGET_APP = $(BASE_NAME)\r
+SOURCE_DIR = $(SDK_INSTALL_DIR)\refit\$(BASE_NAME)\r
+BUILD_DIR  = $(SDK_BUILD_DIR)\refit\$(BASE_NAME)\r
+\r
+#\r
+# Include paths\r
+#\r
+\r
+!include $(SDK_INSTALL_DIR)\include\$(EFI_INC_DIR)\makefile.hdr\r
+INC = -I $(SDK_INSTALL_DIR)\include\$(EFI_INC_DIR) \\r
+      -I $(SDK_INSTALL_DIR)\include\$(EFI_INC_DIR)\$(PROCESSOR) \\r
+      -I $(SDK_INSTALL_DIR)\refit\include $(INC)\r
+\r
+#\r
+# Libraries\r
+#\r
+\r
+LIBS = $(LIBS) $(SDK_BUILD_DIR)\lib\libefi\libefi.lib\r
+\r
+#\r
+# Default target\r
+#\r
+\r
+all : dirs $(LIBS) $(OBJECTS)\r
+       @echo Copying $(BASE_NAME).efi to current directory\r
+       @copy $(SDK_BIN_DIR)\$(BASE_NAME).efi $(BASE_NAME)_$(SDK_BUILD_ENV).efi\r
+\r
+#\r
+# Program object files\r
+#\r
+\r
+OBJECTS = $(OBJECTS) \\r
+    $(BUILD_DIR)\$(BASE_NAME).obj \\r
+    $(BUILD_DIR)\lib.obj \\r
+    $(BUILD_DIR)\os_efi.obj \\r
+\r
+#\r
+# Source file dependencies\r
+#\r
+\r
+$(BUILD_DIR)\$(BASE_NAME).obj : $(*B).c $(INC_DEPS)\r
+$(BUILD_DIR)\lib.obj         : $(*B).c $(INC_DEPS)\r
+$(BUILD_DIR)\os_efi.obj              : $(*B).c $(INC_DEPS)\r
+\r
+#\r
+# Handoff to master.mak\r
+#\r
+\r
+!include $(SDK_INSTALL_DIR)\build\master.mak\r
diff --git a/gptsync/lib.c b/gptsync/lib.c
new file mode 100644 (file)
index 0000000..9a3ad45
--- /dev/null
@@ -0,0 +1,506 @@
+/*
+ * gptsync/lib.c
+ * Platform-independent code common to gptsync and showpart
+ *
+ * Copyright (c) 2006-2007 Christoph Pfisterer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "gptsync.h"
+
+// variables
+
+UINT8           empty_guid[16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
+
+PARTITION_INFO  mbr_parts[4];
+UINTN           mbr_part_count = 0;
+PARTITION_INFO  gpt_parts[128];
+UINTN           gpt_part_count = 0;
+
+PARTITION_INFO  new_mbr_parts[4];
+UINTN           new_mbr_part_count = 0;
+
+UINT8           sector[512];
+
+MBR_PARTTYPE    mbr_types[] = {
+    { 0x01, STR("FAT12 (CHS)") },
+    { 0x04, STR("FAT16 <32M (CHS)") },
+    { 0x05, STR("Extended (CHS)") },
+    { 0x06, STR("FAT16 (CHS)") },
+    { 0x07, STR("NTFS/HPFS") },
+    { 0x0b, STR("FAT32 (CHS)") },
+    { 0x0c, STR("FAT32 (LBA)") },
+    { 0x0e, STR("FAT16 (LBA)") },
+    { 0x0f, STR("Extended (LBA)") },
+    { 0x11, STR("Hidden FAT12 (CHS)") },
+    { 0x14, STR("Hidden FAT16 <32M (CHS)") },
+    { 0x16, STR("Hidden FAT16 (CHS)") },
+    { 0x17, STR("Hidden NTFS/HPFS") },
+    { 0x1b, STR("Hidden FAT32 (CHS)") },
+    { 0x1c, STR("Hidden FAT32 (LBA)") },
+    { 0x1e, STR("Hidden FAT16 (LBA)") },
+    { 0x82, STR("Linux swap / Solaris") },
+    { 0x83, STR("Linux") },
+    { 0x85, STR("Linux Extended") },
+    { 0x86, STR("NT FAT volume set") },
+    { 0x87, STR("NTFS volume set") },
+    { 0x8e, STR("Linux LVM") },
+    { 0xa5, STR("FreeBSD") },
+    { 0xa6, STR("OpenBSD") },
+    { 0xa7, STR("NeXTSTEP") },
+    { 0xa8, STR("Mac OS X UFS") },
+    { 0xa9, STR("NetBSD") },
+    { 0xab, STR("Mac OS X Boot") },
+    { 0xac, STR("Apple RAID") },
+    { 0xaf, STR("Mac OS X HFS+") },
+    { 0xbe, STR("Solaris Boot") },
+    { 0xbf, STR("Solaris") },
+    { 0xeb, STR("BeOS") },
+    { 0xee, STR("EFI Protective") },
+    { 0xef, STR("EFI System (FAT)") },
+    { 0xfd, STR("Linux RAID") },
+    { 0, NULL },
+};
+
+GPT_PARTTYPE    gpt_types[] = {
+    // Sony uses this one
+    { "\x32\x97\x01\xF4\x6E\x06\x12\x4E\x82\x73\x34\x6C\x56\x41\x49\x4F", 0x00, STR("Sony System (FAT)"), GPT_KIND_FATAL },
+    // Defined by EFI/UEFI specification
+    { "\x28\x73\x2A\xC1\x1F\xF8\xD2\x11\xBA\x4B\x00\xA0\xC9\x3E\xC9\x3B", 0xef, STR("EFI System (FAT)"), GPT_KIND_SYSTEM },
+    { "\x41\xEE\x4D\x02\xE7\x33\xD3\x11\x9D\x69\x00\x08\xC7\x81\xF3\x9F", 0x00, STR("MBR partition scheme"), GPT_KIND_FATAL },
+    // Generally well-known
+    { "\x16\xE3\xC9\xE3\x5C\x0B\xB8\x4D\x81\x7D\xF9\x2D\xF0\x02\x15\xAE", 0x00, STR("MS Reserved"), GPT_KIND_SYSTEM },
+    { "\xA2\xA0\xD0\xEB\xE5\xB9\x33\x44\x87\xC0\x68\xB6\xB7\x26\x99\xC7", 0x00, STR("Basic Data"), GPT_KIND_BASIC_DATA },
+    // From Wikipedia
+    { "\xAA\xC8\x08\x58\x8F\x7E\xE0\x42\x85\xD2\xE1\xE9\x04\x34\xCF\xB3", 0x00, STR("MS LDM Metadata"), GPT_KIND_FATAL },
+    { "\xA0\x60\x9B\xAF\x31\x14\x62\x4F\xBC\x68\x33\x11\x71\x4A\x69\xAD", 0x00, STR("MS LDM Data"), GPT_KIND_FATAL },
+    { "\x1E\x4C\x89\x75\xEB\x3A\xD3\x11\xB7\xC1\x7B\x03\xA0\x00\x00\x00", 0x00, STR("HP/UX Data"), GPT_KIND_DATA },
+    { "\x28\xE7\xA1\xE2\xE3\x32\xD6\x11\xA6\x82\x7B\x03\xA0\x00\x00\x00", 0x00, STR("HP/UX Service"), GPT_KIND_SYSTEM },
+    // From Linux repository, fs/partitions/efi.h
+    { "\x0F\x88\x9D\xA1\xFC\x05\x3B\x4D\xA0\x06\x74\x3F\x0F\x84\x91\x1E", 0xfd, STR("Linux RAID"), GPT_KIND_DATA },
+    { "\x6D\xFD\x57\x06\xAB\xA4\xC4\x43\x84\xE5\x09\x33\xC8\x4B\x4F\x4F", 0x82, STR("Linux Swap"), GPT_KIND_SYSTEM },
+    { "\x79\xD3\xD6\xE6\x07\xF5\xC2\x44\xA2\x3C\x23\x8F\x2A\x3D\xF9\x28", 0x8e, STR("Linux LVM"), GPT_KIND_DATA },
+    { "\xAF\x3D\xC6\x0F\x83\x84\x72\x47\x8E\x79\x3D\x69\xD8\x47\x7D\xE4", 0x83, STR("Linux Filesystem"), GPT_KIND_DATA },
+    // From Wikipedia
+    { "\x39\x33\xA6\x8D\x07\x00\xC0\x60\xC4\x36\x08\x3A\xC8\x23\x09\x08", 0x00, STR("Linux Reserved"), GPT_KIND_SYSTEM },
+    // From grub2 repository, grub/include/grub/gpt_partition.h
+    { "\x48\x61\x68\x21\x49\x64\x6F\x6E\x74\x4E\x65\x65\x64\x45\x46\x49", 0x00, STR("GRUB2 BIOS Boot"), GPT_KIND_SYSTEM },
+    // From FreeBSD repository, sys/sys/gpt.h
+    { "\xB4\x7C\x6E\x51\xCF\x6E\xD6\x11\x8F\xF8\x00\x02\x2D\x09\x71\x2B", 0xa5, STR("FreeBSD Data"), GPT_KIND_DATA },
+    { "\xB5\x7C\x6E\x51\xCF\x6E\xD6\x11\x8F\xF8\x00\x02\x2D\x09\x71\x2B", 0x00, STR("FreeBSD Swap"), GPT_KIND_SYSTEM },
+    { "\xB6\x7C\x6E\x51\xCF\x6E\xD6\x11\x8F\xF8\x00\x02\x2D\x09\x71\x2B", 0xa5, STR("FreeBSD UFS"), GPT_KIND_DATA },
+    { "\xB8\x7C\x6E\x51\xCF\x6E\xD6\x11\x8F\xF8\x00\x02\x2D\x09\x71\x2B", 0x00, STR("FreeBSD Vinum"), GPT_KIND_DATA },
+    { "\xBA\x7C\x6E\x51\xCF\x6E\xD6\x11\x8F\xF8\x00\x02\x2D\x09\x71\x2B", 0xa5, STR("FreeBSD ZFS"), GPT_KIND_DATA },
+    { "\x9D\x6B\xBD\x83\x41\x7F\xDC\x11\xBE\x0B\x00\x15\x60\xB8\x4F\x0F", 0xa5, STR("FreeBSD Boot"), GPT_KIND_DATA },
+    // From NetBSD repository, sys/sys/disklabel_gpt.h
+    { "\x32\x8D\xF4\x49\x0E\xB1\xDC\x11\xB9\x9B\x00\x19\xD1\x87\x96\x48", 0x00, STR("NetBSD Swap"), GPT_KIND_SYSTEM },
+    { "\x5A\x8D\xF4\x49\x0E\xB1\xDC\x11\xB9\x9B\x00\x19\xD1\x87\x96\x48", 0xa9, STR("NetBSD FFS"), GPT_KIND_DATA },
+    { "\x82\x8D\xF4\x49\x0E\xB1\xDC\x11\xB9\x9B\x00\x19\xD1\x87\x96\x48", 0xa9, STR("NetBSD LFS"), GPT_KIND_DATA },
+    { "\xAA\x8D\xF4\x49\x0E\xB1\xDC\x11\xB9\x9B\x00\x19\xD1\x87\x96\x48", 0xa9, STR("NetBSD RAID"), GPT_KIND_DATA },
+    { "\xC4\x19\xB5\x2D\x0E\xB1\xDC\x11\xB9\x9B\x00\x19\xD1\x87\x96\x48", 0xa9, STR("NetBSD CCD"), GPT_KIND_DATA },
+    { "\xEC\x19\xB5\x2D\x0E\xB1\xDC\x11\xB9\x9B\x00\x19\xD1\x87\x96\x48", 0xa9, STR("NetBSD CGD"), GPT_KIND_DATA },
+    // From http://developer.apple.com/mac/library/technotes/tn2006/tn2166.html
+//    { "\x00\x53\x46\x48\x00\x00\xAA\x11\xAA\x11\x00\x30\x65\x43\xEC\xAC", 0x00, STR("Mac OS X HFS+"), GPT_KIND_SYSTEM },
+    { "\x00\x53\x46\x48\x00\x00\xAA\x11\xAA\x11\x00\x30\x65\x43\xEC\xAC", 0xaf, STR("Mac OS X HFS+"), GPT_KIND_DATA },
+    { "\x00\x53\x46\x55\x00\x00\xAA\x11\xAA\x11\x00\x30\x65\x43\xEC\xAC", 0xa8, STR("Mac OS X UFS"), GPT_KIND_DATA },
+    { "\x74\x6F\x6F\x42\x00\x00\xAA\x11\xAA\x11\x00\x30\x65\x43\xEC\xAC", 0xab, STR("Mac OS X Boot"), GPT_KIND_DATA },
+    { "\x44\x49\x41\x52\x00\x00\xAA\x11\xAA\x11\x00\x30\x65\x43\xEC\xAC", 0xac, STR("Apple RAID"), GPT_KIND_DATA },
+    { "\x44\x49\x41\x52\x4F\x5F\xAA\x11\xAA\x11\x00\x30\x65\x43\xEC\xAC", 0xac, STR("Apple RAID (Offline)"), GPT_KIND_DATA },
+    { "\x65\x62\x61\x4C\x00\x6C\xAA\x11\xAA\x11\x00\x30\x65\x43\xEC\xAC", 0x00, STR("Apple Label"), GPT_KIND_SYSTEM },
+    // From Wikipedia
+    { "\x6F\x63\x65\x52\x65\x76\xAA\x11\xAA\x11\x00\x30\x65\x43\xEC\xAC", 0x00, STR("Apple TV Recovery"), GPT_KIND_DATA },
+    // From OpenSolaris repository, usr/src/uts/common/sys/efi_partition.h
+    { "\x7f\x23\x96\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0x00, STR("Solaris Reserved"), GPT_KIND_SYSTEM },
+    { "\x45\xCB\x82\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0xbf, STR("Solaris Boot"), GPT_KIND_DATA },
+    { "\x4D\xCF\x85\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0xbf, STR("Solaris Root"), GPT_KIND_DATA },
+    { "\x6F\xC4\x87\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0x00, STR("Solaris Swap"), GPT_KIND_SYSTEM },
+    { "\xC3\x8C\x89\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0xbf, STR("Solaris Usr / Apple ZFS"), GPT_KIND_DATA },
+    { "\x2B\x64\x8B\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0x00, STR("Solaris Backup"), GPT_KIND_SYSTEM },
+    { "\xC7\x2A\x8D\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0x00, STR("Solaris Reserved (Stand)"), GPT_KIND_SYSTEM },
+    { "\xE9\xF2\x8E\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0xbf, STR("Solaris Var"), GPT_KIND_DATA },
+    { "\x39\xBA\x90\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0xbf, STR("Solaris Home"), GPT_KIND_DATA },
+    { "\xA5\x83\x92\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0x00, STR("Solaris Alternate Sector"), GPT_KIND_SYSTEM },
+    { "\x3B\x5A\x94\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0x00, STR("Solaris Reserved (Cache)"), GPT_KIND_SYSTEM },
+    { "\xD1\x30\x96\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0x00, STR("Solaris Reserved"), GPT_KIND_SYSTEM },
+    { "\x67\x07\x98\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0x00, STR("Solaris Reserved"), GPT_KIND_SYSTEM },
+    // List sentinel
+    { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, 0, NULL, 0 },
+};
+GPT_PARTTYPE    gpt_dummy_type =
+    { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, 0, STR("Unknown"), GPT_KIND_FATAL };
+
+//
+// MBR functions
+//
+
+CHARN * mbr_parttype_name(UINT8 type)
+{
+    int i;
+
+    for (i = 0; mbr_types[i].name; i++)
+        if (mbr_types[i].type == type)
+            return mbr_types[i].name;
+    return STR("Unknown");
+}
+
+UINTN read_mbr(VOID)
+{
+    UINTN               status;
+    UINTN               i;
+    BOOLEAN             used;
+    MBR_PART_INFO       *table;
+
+    Print(L"\nCurrent MBR partition table:\n");
+
+    // read MBR data
+    status = read_sector(0, sector);
+    if (status != 0)
+        return status;
+
+    // check for validity
+    if (*((UINT16 *)(sector + 510)) != 0xaa55) {
+        Print(L" No MBR partition table present!\n");
+        return 1;
+    }
+    table = (MBR_PART_INFO *)(sector + 446);
+    for (i = 0; i < 4; i++) {
+        if (table[i].flags != 0x00 && table[i].flags != 0x80) {
+            Print(L" MBR partition table is invalid!\n");
+            return 1;
+        }
+    }
+
+    // check if used
+    used = FALSE;
+    for (i = 0; i < 4; i++) {
+        if (table[i].start_lba > 0 && table[i].size > 0) {
+            used = TRUE;
+            break;
+        }
+    }
+    if (!used) {
+        Print(L" No partitions defined\n");
+        return 0;
+    }
+
+    // dump current state & fill internal structures
+    Print(L" # A    Start LBA      End LBA  Type\n");
+    for (i = 0; i < 4; i++) {
+        if (table[i].start_lba == 0 || table[i].size == 0)
+            continue;
+
+        mbr_parts[mbr_part_count].index     = i;
+        mbr_parts[mbr_part_count].start_lba = (UINT64)table[i].start_lba;
+        mbr_parts[mbr_part_count].end_lba   = (UINT64)table[i].start_lba + (UINT64)table[i].size - 1;
+        mbr_parts[mbr_part_count].mbr_type  = table[i].type;
+        mbr_parts[mbr_part_count].active    = (table[i].flags == 0x80) ? TRUE : FALSE;
+
+        Print(L" %d %s %12lld %12lld  %02x  %s\n",
+              mbr_parts[mbr_part_count].index + 1,
+              mbr_parts[mbr_part_count].active ? STR("*") : STR(" "),
+              mbr_parts[mbr_part_count].start_lba,
+              mbr_parts[mbr_part_count].end_lba,
+              mbr_parts[mbr_part_count].mbr_type,
+              mbr_parttype_name(mbr_parts[mbr_part_count].mbr_type));
+
+        mbr_part_count++;
+    }
+
+    return 0;
+}
+
+//
+// GPT functions
+//
+
+GPT_PARTTYPE * gpt_parttype(UINT8 *type_guid)
+{
+    int i;
+
+    for (i = 0; gpt_types[i].name; i++)
+        if (guids_are_equal(gpt_types[i].guid, type_guid))
+            return &(gpt_types[i]);
+    return &gpt_dummy_type;
+}
+
+UINTN read_gpt(VOID)
+{
+    UINTN       status;
+    GPT_HEADER  *header;
+    GPT_ENTRY   *entry;
+    UINT64      entry_lba;
+    UINTN       entry_count, entry_size, i;
+
+    Print(L"\nCurrent GUID partition table:\n");
+
+    // read GPT header
+    status = read_sector(1, sector);
+    if (status != 0)
+        return status;
+
+    // check signature
+    header = (GPT_HEADER *)sector;
+    if (header->signature != 0x5452415020494645ULL) {
+        Print(L" No GPT partition table present!\n");
+        return 0;
+    }
+    if (header->spec_revision != 0x00010000UL) {
+        Print(L" Warning: Unknown GPT spec revision 0x%08x\n", header->spec_revision);
+    }
+    if ((512 % header->entry_size) > 0 || header->entry_size > 512) {
+        Print(L" Error: Invalid GPT entry size (misaligned or more than 512 bytes)\n");
+        return 0;
+    }
+
+    // read entries
+    entry_lba   = header->entry_lba;
+    entry_size  = header->entry_size;
+    entry_count = header->entry_count;
+
+    for (i = 0; i < entry_count; i++) {
+        if (((i * entry_size) % 512) == 0) {
+            status = read_sector(entry_lba, sector);
+            if (status != 0)
+                return status;
+            entry_lba++;
+        }
+        entry = (GPT_ENTRY *)(sector + ((i * entry_size) % 512));
+
+        if (guids_are_equal(entry->type_guid, empty_guid))
+            continue;
+        if (gpt_part_count == 0) {
+            Print(L" #      Start LBA      End LBA  Type\n");
+        }
+
+        gpt_parts[gpt_part_count].index     = i;
+        gpt_parts[gpt_part_count].start_lba = entry->start_lba;
+        gpt_parts[gpt_part_count].end_lba   = entry->end_lba;
+        gpt_parts[gpt_part_count].mbr_type  = 0;
+        copy_guid(gpt_parts[gpt_part_count].gpt_type, entry->type_guid);
+        gpt_parts[gpt_part_count].gpt_parttype = gpt_parttype(gpt_parts[gpt_part_count].gpt_type);
+        gpt_parts[gpt_part_count].active    = FALSE;
+
+        Print(L" %d   %12lld %12lld  %s\n",
+              gpt_parts[gpt_part_count].index + 1,
+              gpt_parts[gpt_part_count].start_lba,
+              gpt_parts[gpt_part_count].end_lba,
+              gpt_parts[gpt_part_count].gpt_parttype->name);
+
+        gpt_part_count++;
+    }
+    if (gpt_part_count == 0) {
+        Print(L" No partitions defined\n");
+        return 0;
+    }
+
+    return 0;
+}
+
+//
+// detect file system type
+//
+
+UINTN detect_mbrtype_fs(UINT64 partlba, UINTN *parttype, CHARN **fsname)
+{
+    UINTN   status;
+    UINTN   signature, score;
+    UINTN   sectsize, clustersize, reserved, fatcount, dirsize, sectcount, fatsize, clustercount;
+
+    *fsname = STR("Unknown");
+    *parttype = 0;
+
+    // READ sector 0 / offset 0K
+    status = read_sector(partlba, sector);
+    if (status != 0)
+        return status;
+
+    // detect XFS
+    signature = *((UINT32 *)(sector));
+    if (signature == 0x42534658) {
+        *parttype = 0x83;
+        *fsname = STR("XFS");
+        return 0;
+    }
+
+    // detect FAT and NTFS
+    sectsize = *((UINT16 *)(sector + 11));
+    clustersize = sector[13];
+    if (sectsize >= 512 && (sectsize & (sectsize - 1)) == 0 &&
+        clustersize > 0 && (clustersize & (clustersize - 1)) == 0) {
+        // preconditions for both FAT and NTFS are now met
+
+        if (CompareMem(sector + 3, "NTFS    ", 8) == 0) {
+            *parttype = 0x07;
+            *fsname = STR("NTFS");
+            return 0;
+        }
+
+        score = 0;
+        // boot jump
+        if ((sector[0] == 0xEB && sector[2] == 0x90) || 
+            sector[0] == 0xE9)
+            score++;
+        // boot signature
+        if (sector[510] == 0x55 && sector[511] == 0xAA)
+            score++;
+        // reserved sectors
+        reserved = *((UINT16 *)(sector + 14));
+        if (reserved == 1 || reserved == 32)
+            score++;
+        // number of FATs
+        fatcount = sector[16];
+        if (fatcount == 2)
+            score++;
+        // number of root dir entries
+        dirsize = *((UINT16 *)(sector + 17));
+        // sector count (16-bit and 32-bit versions)
+        sectcount = *((UINT16 *)(sector + 19));
+        if (sectcount == 0)
+            sectcount = *((UINT32 *)(sector + 32));
+        // media byte
+        if (sector[21] == 0xF0 || sector[21] >= 0xF8)
+            score++;
+        // FAT size in sectors
+        fatsize = *((UINT16 *)(sector + 22));
+        if (fatsize == 0)
+            fatsize = *((UINT32 *)(sector + 36));
+
+        // determine FAT type
+        dirsize = ((dirsize * 32) + (sectsize - 1)) / sectsize;
+        clustercount = sectcount - (reserved + (fatcount * fatsize) + dirsize);
+        clustercount /= clustersize;
+
+        if (score >= 3) {
+            if (clustercount < 4085) {
+                *parttype = 0x01;
+                *fsname = STR("FAT12");
+            } else if (clustercount < 65525) {
+                *parttype = 0x0e;
+                *fsname = STR("FAT16");
+            } else {
+                *parttype = 0x0c;
+                *fsname = STR("FAT32");
+            }
+            // TODO: check if 0e and 0c are okay to use, maybe we should use 06 and 0b instead...
+            return 0;
+        }
+    }
+
+    // READ sector 2 / offset 1K
+    status = read_sector(partlba + 2, sector);
+    if (status != 0)
+        return status;
+
+    // detect HFS+
+    signature = *((UINT16 *)(sector));
+    if (signature == 0x4442) {
+        *parttype = 0xaf;
+        if (*((UINT16 *)(sector + 0x7c)) == 0x2B48)
+            *fsname = STR("HFS Extended (HFS+)");
+        else
+            *fsname = STR("HFS Standard");
+        return 0;
+    } else if (signature == 0x2B48) {
+        *parttype = 0xaf;
+        *fsname = STR("HFS Extended (HFS+)");
+        return 0;
+    }
+
+    // detect ext2/ext3/ext4
+    signature = *((UINT16 *)(sector + 56));
+    if (signature == 0xEF53) {
+        *parttype = 0x83;
+        if (*((UINT16 *)(sector + 96)) & 0x02C0 ||
+            *((UINT16 *)(sector + 100)) & 0x0078)
+            *fsname = STR("ext4");
+        else if (*((UINT16 *)(sector + 92)) & 0x0004)
+            *fsname = STR("ext3");
+        else
+            *fsname = STR("ext2");
+        return 0;
+    }
+
+    // READ sector 128 / offset 64K
+    status = read_sector(partlba + 128, sector);
+    if (status != 0)
+        return status;
+
+    // detect btrfs
+    if (CompareMem(sector + 64, "_BHRfS_M", 8) == 0) {
+        *parttype = 0x83;
+        *fsname = STR("btrfs");
+        return 0;
+    }
+
+    // detect ReiserFS
+    if (CompareMem(sector + 52, "ReIsErFs", 8) == 0 ||
+        CompareMem(sector + 52, "ReIsEr2Fs", 9) == 0 ||
+        CompareMem(sector + 52, "ReIsEr3Fs", 9) == 0) {
+        *parttype = 0x83;
+        *fsname = STR("ReiserFS");
+        return 0;
+    }
+
+    // detect Reiser4
+    if (CompareMem(sector, "ReIsEr4", 7) == 0) {
+        *parttype = 0x83;
+        *fsname = STR("Reiser4");
+        return 0;
+    }
+
+    // READ sector 64 / offset 32K
+    status = read_sector(partlba + 64, sector);
+    if (status != 0)
+        return status;
+
+    // detect JFS
+    if (CompareMem(sector, "JFS1", 4) == 0) {
+        *parttype = 0x83;
+        *fsname = STR("JFS");
+        return 0;
+    }
+
+    // READ sector 16 / offset 8K
+    status = read_sector(partlba + 16, sector);
+    if (status != 0)
+        return status;
+
+    // detect ReiserFS
+    if (CompareMem(sector + 52, "ReIsErFs", 8) == 0 ||
+        CompareMem(sector + 52, "ReIsEr2Fs", 9) == 0 ||
+        CompareMem(sector + 52, "ReIsEr3Fs", 9) == 0) {
+        *parttype = 0x83;
+        *fsname = STR("ReiserFS");
+        return 0;
+    }
+
+    return 0;
+}
diff --git a/gptsync/os_efi.c b/gptsync/os_efi.c
new file mode 100644 (file)
index 0000000..9559014
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+ * gptsync/os_efi.c
+ * EFI glue for gptsync
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "gptsync.h"
+#include "refit_call_wrapper.h"
+#ifdef __MAKEWITH_TIANO
+//#include "tiano_includes.h"
+#include "AutoGen.h"
+#endif
+
+// variables
+
+EFI_BLOCK_IO    *BlockIO = NULL;
+
+//
+// sector I/O functions
+//
+
+// Returns size of disk in blocks
+UINT64 disk_size(VOID) {
+   return (UINT64) (BlockIO->Media->LastBlock + 1);
+} // UINT64 disk_size()
+
+UINTN read_sector(UINT64 lba, UINT8 *buffer)
+{
+    EFI_STATUS          Status;
+
+    Status = refit_call5_wrapper(BlockIO->ReadBlocks, BlockIO, BlockIO->Media->MediaId, lba, 512, buffer);
+    if (EFI_ERROR(Status)) {
+        // TODO: report error
+        return 1;
+    }
+    return 0;
+}
+
+UINTN write_sector(UINT64 lba, UINT8 *buffer)
+{
+    EFI_STATUS          Status;
+
+    Status = refit_call5_wrapper(BlockIO->WriteBlocks, BlockIO, BlockIO->Media->MediaId, lba, 512, buffer);
+    if (EFI_ERROR(Status)) {
+        // TODO: report error
+        return 1;
+    }
+    return 0;
+}
+
+//
+// Keyboard input
+//
+
+static BOOLEAN ReadAllKeyStrokes(VOID)
+{
+    EFI_STATUS          Status;
+    BOOLEAN             GotKeyStrokes;
+    EFI_INPUT_KEY       Key;
+
+    GotKeyStrokes = FALSE;
+    for (;;) {
+        Status = refit_call2_wrapper(ST->ConIn->ReadKeyStroke, ST->ConIn, &Key);
+        if (Status == EFI_SUCCESS) {
+            GotKeyStrokes = TRUE;
+            continue;
+        }
+        break;
+    }
+    return GotKeyStrokes;
+}
+
+static VOID PauseForKey(VOID)
+{
+    UINTN               Index;
+
+    Print(L"\n* Hit any key to continue *");
+
+    if (ReadAllKeyStrokes()) {  // remove buffered key strokes
+        refit_call1_wrapper(BS->Stall, 5000000);     // 5 seconds delay
+        ReadAllKeyStrokes();    // empty the buffer again
+    }
+
+    refit_call3_wrapper(BS->WaitForEvent, 1, &ST->ConIn->WaitForKey, &Index);
+    ReadAllKeyStrokes();        // empty the buffer to protect the menu
+
+    Print(L"\n");
+}
+
+UINTN input_boolean(CHARN *prompt, BOOLEAN *bool_out)
+{
+    EFI_STATUS          Status;
+    UINTN               Index;
+    EFI_INPUT_KEY       Key;
+
+    Print(prompt);
+
+    if (ReadAllKeyStrokes()) {  // remove buffered key strokes
+        refit_call1_wrapper(BS->Stall, 500000);      // 0.5 seconds delay
+        ReadAllKeyStrokes();    // empty the buffer again
+    }
+
+    refit_call3_wrapper(BS->WaitForEvent, 1, &ST->ConIn->WaitForKey, &Index);
+    Status = refit_call2_wrapper(ST->ConIn->ReadKeyStroke, ST->ConIn, &Key);
+    if (EFI_ERROR(Status))
+        return 1;
+
+    if (Key.UnicodeChar == 'y' || Key.UnicodeChar == 'Y') {
+        Print(L"Yes\n");
+        *bool_out = TRUE;
+    } else {
+        Print(L"No\n");
+        *bool_out = FALSE;
+    }
+
+    ReadAllKeyStrokes();
+    return 0;
+}
+
+#ifdef __MAKEWITH_TIANO
+
+// EFI_GUID gEfiDxeServicesTableGuid = { 0x05AD34BA, 0x6F02, 0x4214, { 0x95, 0x2E, 0x4D, 0xA0, 0x39, 0x8E, 0x2B, 0xB9 }};
+
+// Minimal initialization function
+static VOID InitializeLib(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable) {
+   gST            = SystemTable;
+   //    gImageHandle   = ImageHandle;
+   gBS            = SystemTable->BootServices;
+   //    gRS            = SystemTable->RuntimeServices;
+   gRT = SystemTable->RuntimeServices; // Some BDS functions need gRT to be set
+
+//   InitializeConsoleSim();
+}
+
+// EFI_GUID gEfiBlockIoProtocolGuid = { 0x964E5B21, 0x6459, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
+
+#define LibLocateHandle gBS->LocateHandleBuffer
+#define BlockIoProtocol gEfiBlockIoProtocolGuid
+
+#endif
+
+// Performs a case-insensitive string comparison. This function is necesary
+// because some EFIs have buggy StriCmp() functions that actually perform
+// case-sensitive comparisons.
+// Returns TRUE if strings are identical, FALSE otherwise.
+static BOOLEAN MyStriCmp(IN CHAR16 *FirstString, IN CHAR16 *SecondString) {
+    if (FirstString && SecondString) {
+        while ((*FirstString != L'\0') && ((*FirstString & ~0x20) == (*SecondString & ~0x20))) {
+                FirstString++;
+                SecondString++;
+        }
+        return (*FirstString == *SecondString);
+    } else {
+        return FALSE;
+    }
+} // BOOLEAN MyStriCmp()
+
+// Check firmware vendor; get verification to continue if it's not Apple.
+// Returns TRUE if Apple firmware or if user assents to use, FALSE otherwise.
+static BOOLEAN VerifyGoOn(VOID) {
+   BOOLEAN GoOn = TRUE;
+   UINTN invalid;
+
+   if (MyStriCmp(L"Apple", ST->FirmwareVendor)) {
+      Print(L"Your firmware is made by %s.\n", ST->FirmwareVendor);
+      Print(L"Ordinarily, a hybrid MBR (which this program creates) should be used ONLY on\n");
+      Print(L"Apple Macs that dual-boot with Windows or some other BIOS-mode OS. Are you\n");
+      invalid = input_boolean(STR("SURE you want to continue? [y/N] "), &GoOn);
+      if (invalid)
+         GoOn = FALSE;
+   }
+   return GoOn;
+} // BOOLEAN VerifyGoOn()
+
+//
+// main entry point
+//
+
+EFI_STATUS
+EFIAPI
+efi_main    (IN EFI_HANDLE           ImageHandle,
+             IN EFI_SYSTEM_TABLE     *SystemTable)
+{
+    EFI_STATUS          Status;
+    UINTN               SyncStatus;
+    UINTN               Index;
+    UINTN               HandleCount;
+    EFI_HANDLE          *HandleBuffer;
+    EFI_HANDLE          DeviceHandle;
+    EFI_DEVICE_PATH     *DevicePath, *NextDevicePath;
+    BOOLEAN             Usable;
+
+    InitializeLib(ImageHandle, SystemTable);
+
+    Status = refit_call5_wrapper(BS->LocateHandleBuffer, ByProtocol, &BlockIoProtocol, NULL, &HandleCount, &HandleBuffer);
+    if (EFI_ERROR (Status)) {
+        Status = EFI_NOT_FOUND;
+        return Status;
+    }
+
+    if (!VerifyGoOn())
+       return EFI_ABORTED;
+
+    for (Index = 0; Index < HandleCount; Index++) {
+
+        DeviceHandle = HandleBuffer[Index];
+
+        // check device path
+        DevicePath = DevicePathFromHandle(DeviceHandle);
+        Usable = TRUE;
+        while (DevicePath != NULL && !IsDevicePathEndType(DevicePath)) {
+            NextDevicePath = NextDevicePathNode(DevicePath);
+
+            if (DevicePathType(DevicePath) == MESSAGING_DEVICE_PATH &&
+                (DevicePathSubType(DevicePath) == MSG_USB_DP ||
+                 DevicePathSubType(DevicePath) == MSG_USB_CLASS_DP ||
+                 DevicePathSubType(DevicePath) == MSG_1394_DP ||
+                 DevicePathSubType(DevicePath) == MSG_FIBRECHANNEL_DP))
+                Usable = FALSE;         // USB/FireWire/FC device
+            if (DevicePathType(DevicePath) == MEDIA_DEVICE_PATH)
+                Usable = FALSE;         // partition, El Torito entry, legacy BIOS device
+
+            DevicePath = NextDevicePath;
+        }
+        if (!Usable)
+            continue;
+
+        Status = refit_call3_wrapper(BS->HandleProtocol, DeviceHandle, &BlockIoProtocol, (VOID **) &BlockIO);
+        if (EFI_ERROR(Status)) {
+            // TODO: report error
+            BlockIO = NULL;
+        } else {
+            if (BlockIO->Media->BlockSize != 512)
+                BlockIO = NULL;    // optical media
+            else
+                break;
+        }
+
+    }
+
+    FreePool (HandleBuffer);
+
+    if (BlockIO == NULL) {
+        Print(L"Internal hard disk device not found!\n");
+        return EFI_NOT_FOUND;
+    }
+
+    SyncStatus = gptsync();
+
+    if (SyncStatus == 0)
+        PauseForKey();
+
+
+    if (SyncStatus)
+        return EFI_NOT_FOUND;
+    return EFI_SUCCESS;
+}
diff --git a/gptsync/os_unix.c b/gptsync/os_unix.c
new file mode 100644 (file)
index 0000000..a1df9bc
--- /dev/null
@@ -0,0 +1,272 @@
+/*
+ * gptsync/os_unix.c
+ * Unix OS glue for gptsync
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "gptsync.h"
+
+#include <stdarg.h>
+
+#define STRINGIFY(s) #s
+#define STRINGIFY2(s) STRINGIFY(s)
+#define PROGNAME_S STRINGIFY2(PROGNAME)
+
+// variables
+
+static int      fd;
+
+//
+// error functions
+//
+
+void error(const char *msg, ...)
+{
+    va_list par;
+    char buf[4096];
+
+    va_start(par, msg);
+    vsnprintf(buf, 4096, msg, par);
+    va_end(par);
+
+    fprintf(stderr, PROGNAME_S ": %s\n", buf);
+}
+
+void errore(const char *msg, ...)
+{
+    va_list par;
+    char buf[4096];
+
+    va_start(par, msg);
+    vsnprintf(buf, 4096, msg, par);
+    va_end(par);
+
+    fprintf(stderr, PROGNAME_S ": %s: %s\n", buf, strerror(errno));
+}
+
+//
+// sector I/O functions
+//
+
+// Returns size of disk in blocks (currently bogus)
+UINT64 disk_size(VOID) {
+   return (UINT64) 0xFFFFFFFF;
+} // UINT64 disk_size()
+
+UINTN read_sector(UINT64 lba, UINT8 *buffer)
+{
+    off_t   offset;
+    off_t   result_seek;
+    ssize_t result_read;
+
+    offset = lba * 512;
+    result_seek = lseek(fd, offset, SEEK_SET);
+    if (result_seek != offset) {
+        errore("Seek to %llu failed", offset);
+        return 1;
+    }
+
+    result_read = read(fd, buffer, 512);
+    if (result_read < 0) {
+        errore("Data read failed at position %llu", offset);
+        return 1;
+    }
+    if (result_read != 512) {
+        errore("Data read fell short at position %llu", offset);
+        return 1;
+    }
+    return 0;
+}
+
+UINTN write_sector(UINT64 lba, UINT8 *buffer)
+{
+    off_t   offset;
+    off_t   result_seek;
+    ssize_t result_write;
+
+    offset = lba * 512;
+    result_seek = lseek(fd, offset, SEEK_SET);
+    if (result_seek != offset) {
+        errore("Seek to %llu failed", offset);
+        return 1;
+    }
+
+    result_write = write(fd, buffer, 512);
+    if (result_write < 0) {
+        errore("Data write failed at position %llu", offset);
+        return 1;
+    }
+    if (result_write != 512) {
+        errore("Data write fell short at position %llu", offset);
+        return 1;
+    }
+    return 0;
+}
+
+//
+// keyboard input
+//
+
+UINTN input_boolean(CHARN *prompt, BOOLEAN *bool_out)
+{
+    int c;
+
+    printf("%s", prompt);
+    fflush(NULL);
+
+    c = getchar();
+    if (c == EOF)
+        return 1;
+
+    if (c == 'y' || c == 'Y') {
+        printf("Yes\n");
+        *bool_out = TRUE;
+    } else {
+        printf("No\n");
+        *bool_out = FALSE;
+    }
+
+    return 0;
+}
+
+//
+// EFI-style print function
+//
+
+void Print(wchar_t *format, ...)
+{
+    va_list par;
+    char formatbuf[256];
+    char buf[4096];
+    int i;
+
+    for (i = 0; format[i]; i++)
+        formatbuf[i] = (format[i] > 255) ? '?' : (char)(format[i] & 0xff);
+    formatbuf[i] = 0;
+
+    va_start(par, format);
+    vsnprintf(buf, 4096, formatbuf, par);
+    va_end(par);
+
+    printf("%s", buf);
+}
+
+//
+// main entry point
+//
+
+int main(int argc, char *argv[])
+{
+    char        *filename;
+    struct stat sb;
+    int         filekind;
+    UINT64      filesize;
+    char        *reason;
+    int         status;
+
+    // argument check
+    if (argc != 2) {
+        fprintf(stderr, "Usage: " PROGNAME_S " <device>\n");
+        return 1;
+    }
+    filename = argv[1];
+
+    // set input to unbuffered
+    fflush(NULL);
+    setvbuf(stdin, NULL, _IONBF, 0);
+
+    // stat check
+    if (stat(filename, &sb) < 0) {
+        errore("Can't stat %.300s", filename);
+        return 1;
+    }
+
+    filekind = 0;
+    filesize = 0;
+    reason = NULL;
+    if (S_ISREG(sb.st_mode))
+        filesize = sb.st_size;
+    else if (S_ISBLK(sb.st_mode))
+        filekind = 1;
+    else if (S_ISCHR(sb.st_mode))
+        filekind = 2;
+    else if (S_ISDIR(sb.st_mode))
+        reason = "Is a directory";
+    else if (S_ISFIFO(sb.st_mode))
+        reason = "Is a FIFO";
+#ifdef S_ISSOCK
+    else if (S_ISSOCK(sb.st_mode))
+        reason = "Is a socket";
+#endif
+    else
+        reason = "Is an unknown kind of special file";
+
+    if (reason != NULL) {
+        error("%.300s: %s", filename, reason);
+        return 1;
+    }
+
+    // open file
+    fd = open(filename, O_RDWR);
+    if (fd < 0 && errno == EBUSY) {
+        fd = open(filename, O_RDONLY);
+#ifndef NOREADONLYWARN
+        if (fd >= 0)
+            printf("Warning: %.300s opened read-only\n", filename);
+#endif
+    }
+    if (fd < 0) {
+        errore("Can't open %.300s", filename);
+        return 1;
+    }
+
+    // (try to) guard against TTY character devices
+    if (filekind == 2) {
+        if (isatty(fd)) {
+            error("%.300s: Is a TTY device", filename);
+            return 1;
+        }
+    }
+
+    // run sync algorithm
+    status = PROGNAME();
+    printf("\n");
+
+    // close file
+    if (close(fd) != 0) {
+        errore("Error while closing %.300s", filename);
+        return 1;
+    }
+
+    return status;
+}
diff --git a/gptsync/showpart.c b/gptsync/showpart.c
new file mode 100644 (file)
index 0000000..5d727ed
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+ * gptsync/showpart.c
+ * Platform-independent code for analyzing hard disk partitioning
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "gptsync.h"
+
+//
+// memory string search
+//
+
+static INTN FindMem(VOID *Buffer, UINTN BufferLength, VOID *SearchString, UINTN SearchStringLength)
+{
+    UINT8 *BufferPtr;
+    UINTN Offset;
+    
+    BufferPtr = Buffer;
+    BufferLength -= SearchStringLength;
+    for (Offset = 0; Offset < BufferLength; Offset++, BufferPtr++) {
+        if (CompareMem(BufferPtr, SearchString, SearchStringLength) == 0)
+            return (INTN)Offset;
+    }
+    
+    return -1;
+}
+
+//
+// detect boot code
+//
+
+static UINTN detect_bootcode(UINT64 partlba, CHARN **bootcodename)
+{
+    UINTN   status;
+    BOOLEAN bootable;
+    
+    // read MBR data
+    status = read_sector(partlba, sector);
+    if (status != 0)
+        return status;
+    
+    // check bootable signature
+    if (*((UINT16 *)(sector + 510)) == 0xaa55 && sector[0] != 0)
+        bootable = TRUE;
+    else
+        bootable = FALSE;
+    *bootcodename = NULL;
+    
+    // detect specific boot codes
+    if (CompareMem(sector + 2, "LILO", 4) == 0 ||
+        CompareMem(sector + 6, "LILO", 4) == 0) {
+        *bootcodename = STR("LILO");
+        
+    } else if (CompareMem(sector + 3, "SYSLINUX", 8) == 0) {
+        *bootcodename = STR("SYSLINUX");
+        
+    } else if (FindMem(sector, 512, "ISOLINUX", 8) >= 0) {
+        *bootcodename = STR("ISOLINUX");
+        
+    } else if (FindMem(sector, 512, "Geom\0Hard Disk\0Read\0 Error", 26) >= 0) {
+        *bootcodename = STR("GRUB");
+        
+    } else if ((*((UINT32 *)(sector + 502)) == 0 &&
+                *((UINT32 *)(sector + 506)) == 50000 &&
+                *((UINT16 *)(sector + 510)) == 0xaa55) ||
+               FindMem(sector, 512, "Starting the BTX loader", 23) >= 0) {
+        *bootcodename = STR("FreeBSD");
+        
+    } else if (FindMem(sector, 512, "!Loading", 8) >= 0 ||
+               FindMem(sector, 512, "/cdboot\0/CDBOOT\0", 16) >= 0) {
+        *bootcodename = STR("OpenBSD");
+        
+    } else if (FindMem(sector, 512, "Not a bootxx image", 18) >= 0) {
+        *bootcodename = STR("NetBSD");
+        
+    } else if (FindMem(sector, 512, "NTLDR", 5) >= 0) {
+        *bootcodename = STR("Windows NTLDR");
+        
+    } else if (FindMem(sector, 512, "BOOTMGR", 7) >= 0) {
+        *bootcodename = STR("Windows BOOTMGR (Vista)");
+        
+    } else if (FindMem(sector, 512, "CPUBOOT SYS", 11) >= 0 ||
+               FindMem(sector, 512, "KERNEL  SYS", 11) >= 0) {
+        *bootcodename = STR("FreeDOS");
+        
+    } else if (FindMem(sector, 512, "OS2LDR", 6) >= 0 ||
+               FindMem(sector, 512, "OS2BOOT", 7) >= 0) {
+        *bootcodename = STR("eComStation");
+        
+    } else if (FindMem(sector, 512, "Be Boot Loader", 14) >= 0) {
+        *bootcodename = STR("BeOS");
+        
+    } else if (FindMem(sector, 512, "yT Boot Loader", 14) >= 0) {
+        *bootcodename = STR("ZETA");
+        
+    } else if (FindMem(sector, 512, "\x04" "beos\x06" "system\x05" "zbeos", 18) >= 0) {
+        *bootcodename = STR("Haiku");
+        
+    }
+    
+    if (FindMem(sector, 512, "Non-system disk", 15) >= 0)   // dummy FAT boot sector
+        *bootcodename = STR("None (Non-system disk message)");
+    
+    // TODO: Add a note if a specific code was detected, but the sector is not bootable?
+    
+    if (*bootcodename == NULL) {
+        if (bootable)
+            *bootcodename = STR("Unknown, but bootable");
+        else
+            *bootcodename = STR("None");
+    }
+    
+    return 0;
+}
+
+//
+// check one partition
+//
+
+static UINTN analyze_part(UINT64 partlba)
+{
+    UINTN   status;
+    UINTN   i;
+    CHARN   *bootcodename;
+    UINTN   parttype;
+    CHARN   *fsname;
+    
+    if (partlba == 0)
+        Print(L"\nMBR contents:\n");
+    else
+        Print(L"\nPartition at LBA %lld:\n", partlba);
+    
+    // detect boot code
+    status = detect_bootcode(partlba, &bootcodename);
+    if (status)
+        return status;
+    Print(L" Boot Code: %s\n", bootcodename);
+    
+    if (partlba == 0)
+        return 0;   // short-circuit MBR analysis
+    
+    // detect file system
+    status = detect_mbrtype_fs(partlba, &parttype, &fsname);
+    if (status)
+        return status;
+    Print(L" File System: %s\n", fsname);
+    
+    // cross-reference with partition table
+    for (i = 0; i < gpt_part_count; i++) {
+        if (gpt_parts[i].start_lba == partlba) {
+            Print(L" Listed in GPT as partition %d, type %s\n", i+1,
+                  gpt_parts[i].gpt_parttype->name);
+        }
+    }
+    for (i = 0; i < mbr_part_count; i++) {
+        if (mbr_parts[i].start_lba == partlba) {
+            Print(L" Listed in MBR as partition %d, type %02x  %s%s\n", i+1,
+                  mbr_parts[i].mbr_type,
+                  mbr_parttype_name(mbr_parts[i].mbr_type),
+                  mbr_parts[i].active ? STR(", active") : STR(""));
+        }
+    }
+    
+    return 0;
+}
+
+//
+// check all partitions
+//
+
+static UINTN analyze_parts(VOID)
+{
+    UINTN   i, k;
+    UINTN   status;
+    BOOLEAN is_dupe;
+    
+    // check MBR (bootcode only)
+    status = analyze_part(0);
+    if (status)
+        return status;
+    
+    // check partitions listed in GPT
+    for (i = 0; i < gpt_part_count; i++) {
+        status = analyze_part(gpt_parts[i].start_lba);
+        if (status)
+            return status;
+    }
+    
+    // check partitions listed in MBR, but not in GPT
+    for (i = 0; i < mbr_part_count; i++) {
+        if (mbr_parts[i].start_lba == 1 && mbr_parts[i].mbr_type == 0xee)
+            continue;   // skip EFI Protective entry
+        
+        is_dupe = FALSE;
+        for (k = 0; k < gpt_part_count; k++)
+            if (gpt_parts[k].start_lba == mbr_parts[i].start_lba)
+                is_dupe = TRUE;
+        
+        if (!is_dupe) {
+            status = analyze_part(mbr_parts[i].start_lba);
+            if (status)
+                return status;
+        }
+    }
+    
+    return 0;
+}
+
+//
+// display algorithm entry point
+//
+
+UINTN showpart(VOID)
+{
+    UINTN   status = 0;
+    UINTN   status_gpt, status_mbr;
+    
+    // get full information from disk
+    status_gpt = read_gpt();
+    status_mbr = read_mbr();
+    if (status_gpt != 0 || status_mbr != 0)
+        return (status_gpt || status_mbr);
+    
+    // analyze all partitions
+    status = analyze_parts();
+    if (status != 0)
+        return status;
+    
+    return status;
+}
diff --git a/icons/README b/icons/README
new file mode 100644 (file)
index 0000000..e7950df
--- /dev/null
@@ -0,0 +1,135 @@
+This directory holds icons used by rEFInd. This file describes their
+sources, both in overview and in file-by-file detail, and provides pointers
+to the relevant licenses under which the icons are distributed.
+
+Icon Sources (Overview)
+-----------------------
+
+- The AwOken 2.5 icon set
+  - Source: http://alecive.deviantart.com/art/AwOken-163570862
+  - Copyright (c) 2013 by Alessandro Roncone (aka alecive on DeviantArt)
+  - License: Creative Commons Attribution-Share Alike 3.0 (CC-SA 3.0)
+
+- Original work for rEFInd
+  - Source: https://sourceforge.net/p/refind (this archive)
+  - Copyright (c) 2015 by Roderick W. Smith
+  - License: LGPLv3+ or CC-SA 3.0
+
+- Debian OS icon
+  - Source: https://commons.wikimedia.org/wiki/File:Debian-OpenLogo.svg
+  - Copyright (c) 1999 Debian Project
+  - License: LGPLv3+ or CC-SA 3.0
+
+- Elementary OS icon
+  - Source: https://commons.wikimedia.org/wiki/File:Elementary_logo.svg
+  - Copyright (c) 2008 Dan Rabbit
+  - License: GPLv2+
+
+Some icons have been altered from their original forms -- normally
+conversion from SVG to PNG format, resizing, changes in coloration, or
+addition of "drop shadow" effects. Details follow....
+
+The "svg" subdirectory holds SVG versions of some icons (notably absent are
+those based on the AwOken icon set).
+
+Icon Sources (Detail)
+---------------------
+
+Icons unchanged from AwOken 2.5:
+
+os_centos.png -- AwOken/clear/128x128/start-here/start-here-centos.png
+os_chakra.png -- AwOken/clear/128x128/start-here/start-here-chakra.png
+os_chrome.png -- AwOken/clear/128x128/apps/google-chrome1.png
+os_crunchbang.png -- AwOken/clear/128x128/start-here/start-here-crunchbang3.png
+os_fedora.png -- AwOken/clear/128x128/start-here/start-here-fedora5.png
+os_frugalware.png -- AwOken/clear/128x128/start-here/start-here-frugalware1.png
+os_kubuntu.png -- AwOken/clear/128x128/start-here/start-here-kubuntu.png
+os_lubuntu.png -- AwOken/clear/128x128/start-here/start-here-lubuntu.png
+os_mageia.png -- AwOken/clear/128x128/start-here/start-here-mageia.png
+os_mandriva.png -- AwOken/clear/128x128/start-here/start-here-mandriva5.png
+os_network.png -- AwOken/clear/128x128/places/network-workgroup1.png
+os_ubuntu.png -- AwOken/clear/128x128/start-here/start-here-ubuntu.png
+os_unknown.png -- AwOken/clear/128x128/actions/color-line1.png
+os_win8.png -- AwOken/clear/128x128/apps/live1.png
+
+
+Icons modified from AwOken 2.5:
+
+arrow_left.png -- AwOken/clear/128x128/actions/go-previous.png
+arrow_right.png -- AwOken/clear/128x128/actions/go-next.png
+boot_linux.png -- AwOken/clear/128x128/apps/supertux.png
+func_about.png -- AwOkenWhite/clear/128x128/actions/info2.png
+func_exit.png -- AwOkenWhite/clear/128x128/actions/application-exit2.png
+func_firmware.png -- AwOkenWhite/clear/128x128/status/indicator-cpufreq.png
+func_reset.png -- AwOkenWhite/clear/128x128/apps/gnome-session-reboot2.png
+func_shutdown.png -- AwOkenWhite/clear/128x128/apps/gnome-session-halt2.png
+os_arch.png -- AwOkenWhite/clear/128x128/start-here/start-here-arch3.png
+os_clover.png -- AwOkenWhite/clear/128x128/actions/tools-wizard.png
+os_gentoo.png -- AwOken/clear/128x128/start-here/start-here-gentoo.png
+os_hwtest.png -- AwOkenWhite/clear/128x128/apps/hw.png
+os_linux.png -- AwOkenWhite/clear/128x128/apps/supertux.png
+os_linuxmint.png -- AwOkenWhite/clear/128x128/start-here/start-here-mint3.png
+os_opensuse.png -- AwOkenWhite/clear/128x128/start-here/start-here-suse3.png
+os_slackware.png -- AwOkenWhite/clear/128x128/start-here/start-here-slackware1.png
+os_suse.png -- AwOkenWhite/clear/128x128/start-here/start-here-suse3.png
+os_xubuntu.png -- AwOkenWhite/clear/128x128/start-here/start-here-xubuntu1.png
+tool_mok_tool.png -- AwOkenWhite/clear/128x128/apps/gnome-keyring-manager.png
+tool_netboot.png -- AwOken/clear/128x128/places/network-workgroup1.png
+tool_shell.png -- AwOken/clear/128x128/apps/terminal3.png
+vol_external.png -- AwOkenWhite/clear/128x128/devices/drive-removable-media-usb2.png
+vol_internal.png -- AwOken/clear/128/128/drive-harddisk/Internal.png
+vol_net.png -- AwOken/clear/128/128/drive-harddisk/Server.png
+vol_optical.png - AwOken/clear/128x128/devices/media-optical-cd1.png
+
+
+Modified Elementary OS icon:
+
+os_elementary.png (GPLv2+)
+
+
+Modified Debian OS icon:
+
+os_debian.png (LGPLv3+ or CC-BY-SA 3.0)
+
+
+Icons created by me (Roderick W. Smith):
+
+boot_win.png
+func_csr_rotate.png
+os_clover.png
+os_freebsd.png
+os_gummiboot.png
+os_haiku.png
+os_legacy.png
+os_mac.png
+os_netbsd.png
+os_redhat.png
+os_refind.png
+os_refit.png
+os_win.png
+tool_apple_rescue.png
+tool_memtest.png
+tool_rescue.png
+transparent.png
+
+
+In addition, some icons are combinations of two other icons from different
+sources:
+
+tool_part.png -- vol_internal.png with AwOken's gparted2.png
+tool_windows_rescue.png: os_win8.png with AwOken's gnome_network_preferences.png
+
+
+Licneses
+--------
+
+The "licenses" subdirectory contains the text of the relevant licenses:
+
+CC-SA 3.0: Creative Commons Legal Code.html
+           (See also https://creativecommons.org/licenses/by-sa/3.0/us/)
+
+GPLv2: gpl-2.0.txt
+       (see also https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
+
+LGPLv3: lgpl-3.0.txt
+        (see also http://www.gnu.org/licenses/lgpl-3.0.en.html)
diff --git a/icons/arrow_left.png b/icons/arrow_left.png
new file mode 100644 (file)
index 0000000..0f75265
Binary files /dev/null and b/icons/arrow_left.png differ
diff --git a/icons/arrow_right.png b/icons/arrow_right.png
new file mode 100644 (file)
index 0000000..9942eff
Binary files /dev/null and b/icons/arrow_right.png differ
diff --git a/icons/boot_linux.png b/icons/boot_linux.png
new file mode 100644 (file)
index 0000000..4f52d7d
Binary files /dev/null and b/icons/boot_linux.png differ
diff --git a/icons/boot_win.png b/icons/boot_win.png
new file mode 100644 (file)
index 0000000..f86202c
Binary files /dev/null and b/icons/boot_win.png differ
diff --git a/icons/func_about.png b/icons/func_about.png
new file mode 100644 (file)
index 0000000..ad35390
Binary files /dev/null and b/icons/func_about.png differ
diff --git a/icons/func_csr_rotate.png b/icons/func_csr_rotate.png
new file mode 100644 (file)
index 0000000..a88ee75
Binary files /dev/null and b/icons/func_csr_rotate.png differ
diff --git a/icons/func_exit.png b/icons/func_exit.png
new file mode 100644 (file)
index 0000000..9306492
Binary files /dev/null and b/icons/func_exit.png differ
diff --git a/icons/func_firmware.png b/icons/func_firmware.png
new file mode 100644 (file)
index 0000000..ca86be4
Binary files /dev/null and b/icons/func_firmware.png differ
diff --git a/icons/func_reset.png b/icons/func_reset.png
new file mode 100644 (file)
index 0000000..872f624
Binary files /dev/null and b/icons/func_reset.png differ
diff --git a/icons/func_shutdown.png b/icons/func_shutdown.png
new file mode 100644 (file)
index 0000000..c18b989
Binary files /dev/null and b/icons/func_shutdown.png differ
diff --git a/icons/licenses/cc-3.0.txt b/icons/licenses/cc-3.0.txt
new file mode 100644 (file)
index 0000000..604209a
--- /dev/null
@@ -0,0 +1,359 @@
+Creative Commons Legal Code
+
+Attribution-ShareAlike 3.0 Unported
+
+    CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
+    LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN
+    ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
+    INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
+    REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR
+    DAMAGES RESULTING FROM ITS USE.
+
+License
+
+THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE
+COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY
+COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS
+AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.
+
+BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE
+TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY
+BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS
+CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND
+CONDITIONS.
+
+1. Definitions
+
+ a. "Adaptation" means a work based upon the Work, or upon the Work and
+    other pre-existing works, such as a translation, adaptation,
+    derivative work, arrangement of music or other alterations of a
+    literary or artistic work, or phonogram or performance and includes
+    cinematographic adaptations or any other form in which the Work may be
+    recast, transformed, or adapted including in any form recognizably
+    derived from the original, except that a work that constitutes a
+    Collection will not be considered an Adaptation for the purpose of
+    this License. For the avoidance of doubt, where the Work is a musical
+    work, performance or phonogram, the synchronization of the Work in
+    timed-relation with a moving image ("synching") will be considered an
+    Adaptation for the purpose of this License.
+ b. "Collection" means a collection of literary or artistic works, such as
+    encyclopedias and anthologies, or performances, phonograms or
+    broadcasts, or other works or subject matter other than works listed
+    in Section 1(f) below, which, by reason of the selection and
+    arrangement of their contents, constitute intellectual creations, in
+    which the Work is included in its entirety in unmodified form along
+    with one or more other contributions, each constituting separate and
+    independent works in themselves, which together are assembled into a
+    collective whole. A work that constitutes a Collection will not be
+    considered an Adaptation (as defined below) for the purposes of this
+    License.
+ c. "Creative Commons Compatible License" means a license that is listed
+    at https://creativecommons.org/compatiblelicenses that has been
+    approved by Creative Commons as being essentially equivalent to this
+    License, including, at a minimum, because that license: (i) contains
+    terms that have the same purpose, meaning and effect as the License
+    Elements of this License; and, (ii) explicitly permits the relicensing
+    of adaptations of works made available under that license under this
+    License or a Creative Commons jurisdiction license with the same
+    License Elements as this License.
+ d. "Distribute" means to make available to the public the original and
+    copies of the Work or Adaptation, as appropriate, through sale or
+    other transfer of ownership.
+ e. "License Elements" means the following high-level license attributes
+    as selected by Licensor and indicated in the title of this License:
+    Attribution, ShareAlike.
+ f. "Licensor" means the individual, individuals, entity or entities that
+    offer(s) the Work under the terms of this License.
+ g. "Original Author" means, in the case of a literary or artistic work,
+    the individual, individuals, entity or entities who created the Work
+    or if no individual or entity can be identified, the publisher; and in
+    addition (i) in the case of a performance the actors, singers,
+    musicians, dancers, and other persons who act, sing, deliver, declaim,
+    play in, interpret or otherwise perform literary or artistic works or
+    expressions of folklore; (ii) in the case of a phonogram the producer
+    being the person or legal entity who first fixes the sounds of a
+    performance or other sounds; and, (iii) in the case of broadcasts, the
+    organization that transmits the broadcast.
+ h. "Work" means the literary and/or artistic work offered under the terms
+    of this License including without limitation any production in the
+    literary, scientific and artistic domain, whatever may be the mode or
+    form of its expression including digital form, such as a book,
+    pamphlet and other writing; a lecture, address, sermon or other work
+    of the same nature; a dramatic or dramatico-musical work; a
+    choreographic work or entertainment in dumb show; a musical
+    composition with or without words; a cinematographic work to which are
+    assimilated works expressed by a process analogous to cinematography;
+    a work of drawing, painting, architecture, sculpture, engraving or
+    lithography; a photographic work to which are assimilated works
+    expressed by a process analogous to photography; a work of applied
+    art; an illustration, map, plan, sketch or three-dimensional work
+    relative to geography, topography, architecture or science; a
+    performance; a broadcast; a phonogram; a compilation of data to the
+    extent it is protected as a copyrightable work; or a work performed by
+    a variety or circus performer to the extent it is not otherwise
+    considered a literary or artistic work.
+ i. "You" means an individual or entity exercising rights under this
+    License who has not previously violated the terms of this License with
+    respect to the Work, or who has received express permission from the
+    Licensor to exercise rights under this License despite a previous
+    violation.
+ j. "Publicly Perform" means to perform public recitations of the Work and
+    to communicate to the public those public recitations, by any means or
+    process, including by wire or wireless means or public digital
+    performances; to make available to the public Works in such a way that
+    members of the public may access these Works from a place and at a
+    place individually chosen by them; to perform the Work to the public
+    by any means or process and the communication to the public of the
+    performances of the Work, including by public digital performance; to
+    broadcast and rebroadcast the Work by any means including signs,
+    sounds or images.
+ k. "Reproduce" means to make copies of the Work by any means including
+    without limitation by sound or visual recordings and the right of
+    fixation and reproducing fixations of the Work, including storage of a
+    protected performance or phonogram in digital form or other electronic
+    medium.
+
+2. Fair Dealing Rights. Nothing in this License is intended to reduce,
+limit, or restrict any uses free from copyright or rights arising from
+limitations or exceptions that are provided for in connection with the
+copyright protection under copyright law or other applicable laws.
+
+3. License Grant. Subject to the terms and conditions of this License,
+Licensor hereby grants You a worldwide, royalty-free, non-exclusive,
+perpetual (for the duration of the applicable copyright) license to
+exercise the rights in the Work as stated below:
+
+ a. to Reproduce the Work, to incorporate the Work into one or more
+    Collections, and to Reproduce the Work as incorporated in the
+    Collections;
+ b. to create and Reproduce Adaptations provided that any such Adaptation,
+    including any translation in any medium, takes reasonable steps to
+    clearly label, demarcate or otherwise identify that changes were made
+    to the original Work. For example, a translation could be marked "The
+    original work was translated from English to Spanish," or a
+    modification could indicate "The original work has been modified.";
+ c. to Distribute and Publicly Perform the Work including as incorporated
+    in Collections; and,
+ d. to Distribute and Publicly Perform Adaptations.
+ e. For the avoidance of doubt:
+
+     i. Non-waivable Compulsory License Schemes. In those jurisdictions in
+        which the right to collect royalties through any statutory or
+        compulsory licensing scheme cannot be waived, the Licensor
+        reserves the exclusive right to collect such royalties for any
+        exercise by You of the rights granted under this License;
+    ii. Waivable Compulsory License Schemes. In those jurisdictions in
+        which the right to collect royalties through any statutory or
+        compulsory licensing scheme can be waived, the Licensor waives the
+        exclusive right to collect such royalties for any exercise by You
+        of the rights granted under this License; and,
+   iii. Voluntary License Schemes. The Licensor waives the right to
+        collect royalties, whether individually or, in the event that the
+        Licensor is a member of a collecting society that administers
+        voluntary licensing schemes, via that society, from any exercise
+        by You of the rights granted under this License.
+
+The above rights may be exercised in all media and formats whether now
+known or hereafter devised. The above rights include the right to make
+such modifications as are technically necessary to exercise the rights in
+other media and formats. Subject to Section 8(f), all rights not expressly
+granted by Licensor are hereby reserved.
+
+4. Restrictions. The license granted in Section 3 above is expressly made
+subject to and limited by the following restrictions:
+
+ a. You may Distribute or Publicly Perform the Work only under the terms
+    of this License. You must include a copy of, or the Uniform Resource
+    Identifier (URI) for, this License with every copy of the Work You
+    Distribute or Publicly Perform. You may not offer or impose any terms
+    on the Work that restrict the terms of this License or the ability of
+    the recipient of the Work to exercise the rights granted to that
+    recipient under the terms of the License. You may not sublicense the
+    Work. You must keep intact all notices that refer to this License and
+    to the disclaimer of warranties with every copy of the Work You
+    Distribute or Publicly Perform. When You Distribute or Publicly
+    Perform the Work, You may not impose any effective technological
+    measures on the Work that restrict the ability of a recipient of the
+    Work from You to exercise the rights granted to that recipient under
+    the terms of the License. This Section 4(a) applies to the Work as
+    incorporated in a Collection, but this does not require the Collection
+    apart from the Work itself to be made subject to the terms of this
+    License. If You create a Collection, upon notice from any Licensor You
+    must, to the extent practicable, remove from the Collection any credit
+    as required by Section 4(c), as requested. If You create an
+    Adaptation, upon notice from any Licensor You must, to the extent
+    practicable, remove from the Adaptation any credit as required by
+    Section 4(c), as requested.
+ b. You may Distribute or Publicly Perform an Adaptation only under the
+    terms of: (i) this License; (ii) a later version of this License with
+    the same License Elements as this License; (iii) a Creative Commons
+    jurisdiction license (either this or a later license version) that
+    contains the same License Elements as this License (e.g.,
+    Attribution-ShareAlike 3.0 US)); (iv) a Creative Commons Compatible
+    License. If you license the Adaptation under one of the licenses
+    mentioned in (iv), you must comply with the terms of that license. If
+    you license the Adaptation under the terms of any of the licenses
+    mentioned in (i), (ii) or (iii) (the "Applicable License"), you must
+    comply with the terms of the Applicable License generally and the
+    following provisions: (I) You must include a copy of, or the URI for,
+    the Applicable License with every copy of each Adaptation You
+    Distribute or Publicly Perform; (II) You may not offer or impose any
+    terms on the Adaptation that restrict the terms of the Applicable
+    License or the ability of the recipient of the Adaptation to exercise
+    the rights granted to that recipient under the terms of the Applicable
+    License; (III) You must keep intact all notices that refer to the
+    Applicable License and to the disclaimer of warranties with every copy
+    of the Work as included in the Adaptation You Distribute or Publicly
+    Perform; (IV) when You Distribute or Publicly Perform the Adaptation,
+    You may not impose any effective technological measures on the
+    Adaptation that restrict the ability of a recipient of the Adaptation
+    from You to exercise the rights granted to that recipient under the
+    terms of the Applicable License. This Section 4(b) applies to the
+    Adaptation as incorporated in a Collection, but this does not require
+    the Collection apart from the Adaptation itself to be made subject to
+    the terms of the Applicable License.
+ c. If You Distribute, or Publicly Perform the Work or any Adaptations or
+    Collections, You must, unless a request has been made pursuant to
+    Section 4(a), keep intact all copyright notices for the Work and
+    provide, reasonable to the medium or means You are utilizing: (i) the
+    name of the Original Author (or pseudonym, if applicable) if supplied,
+    and/or if the Original Author and/or Licensor designate another party
+    or parties (e.g., a sponsor institute, publishing entity, journal) for
+    attribution ("Attribution Parties") in Licensor's copyright notice,
+    terms of service or by other reasonable means, the name of such party
+    or parties; (ii) the title of the Work if supplied; (iii) to the
+    extent reasonably practicable, the URI, if any, that Licensor
+    specifies to be associated with the Work, unless such URI does not
+    refer to the copyright notice or licensing information for the Work;
+    and (iv) , consistent with Ssection 3(b), in the case of an
+    Adaptation, a credit identifying the use of the Work in the Adaptation
+    (e.g., "French translation of the Work by Original Author," or
+    "Screenplay based on original Work by Original Author"). The credit
+    required by this Section 4(c) may be implemented in any reasonable
+    manner; provided, however, that in the case of a Adaptation or
+    Collection, at a minimum such credit will appear, if a credit for all
+    contributing authors of the Adaptation or Collection appears, then as
+    part of these credits and in a manner at least as prominent as the
+    credits for the other contributing authors. For the avoidance of
+    doubt, You may only use the credit required by this Section for the
+    purpose of attribution in the manner set out above and, by exercising
+    Your rights under this License, You may not implicitly or explicitly
+    assert or imply any connection with, sponsorship or endorsement by the
+    Original Author, Licensor and/or Attribution Parties, as appropriate,
+    of You or Your use of the Work, without the separate, express prior
+    written permission of the Original Author, Licensor and/or Attribution
+    Parties.
+ d. Except as otherwise agreed in writing by the Licensor or as may be
+    otherwise permitted by applicable law, if You Reproduce, Distribute or
+    Publicly Perform the Work either by itself or as part of any
+    Adaptations or Collections, You must not distort, mutilate, modify or
+    take other derogatory action in relation to the Work which would be
+    prejudicial to the Original Author's honor or reputation. Licensor
+    agrees that in those jurisdictions (e.g. Japan), in which any exercise
+    of the right granted in Section 3(b) of this License (the right to
+    make Adaptations) would be deemed to be a distortion, mutilation,
+    modification or other derogatory action prejudicial to the Original
+    Author's honor and reputation, the Licensor will waive or not assert,
+    as appropriate, this Section, to the fullest extent permitted by the
+    applicable national law, to enable You to reasonably exercise Your
+    right under Section 3(b) of this License (right to make Adaptations)
+    but not otherwise.
+
+5. Representations, Warranties and Disclaimer
+
+UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR
+OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY
+KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE,
+INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY,
+FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF
+LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS,
+WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION
+OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU.
+
+6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE
+LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR
+ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES
+ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS
+BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+7. Termination
+
+ a. This License and the rights granted hereunder will terminate
+    automatically upon any breach by You of the terms of this License.
+    Individuals or entities who have received Adaptations or Collections
+    from You under this License, however, will not have their licenses
+    terminated provided such individuals or entities remain in full
+    compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will
+    survive any termination of this License.
+ b. Subject to the above terms and conditions, the license granted here is
+    perpetual (for the duration of the applicable copyright in the Work).
+    Notwithstanding the above, Licensor reserves the right to release the
+    Work under different license terms or to stop distributing the Work at
+    any time; provided, however that any such election will not serve to
+    withdraw this License (or any other license that has been, or is
+    required to be, granted under the terms of this License), and this
+    License will continue in full force and effect unless terminated as
+    stated above.
+
+8. Miscellaneous
+
+ a. Each time You Distribute or Publicly Perform the Work or a Collection,
+    the Licensor offers to the recipient a license to the Work on the same
+    terms and conditions as the license granted to You under this License.
+ b. Each time You Distribute or Publicly Perform an Adaptation, Licensor
+    offers to the recipient a license to the original Work on the same
+    terms and conditions as the license granted to You under this License.
+ c. If any provision of this License is invalid or unenforceable under
+    applicable law, it shall not affect the validity or enforceability of
+    the remainder of the terms of this License, and without further action
+    by the parties to this agreement, such provision shall be reformed to
+    the minimum extent necessary to make such provision valid and
+    enforceable.
+ d. No term or provision of this License shall be deemed waived and no
+    breach consented to unless such waiver or consent shall be in writing
+    and signed by the party to be charged with such waiver or consent.
+ e. This License constitutes the entire agreement between the parties with
+    respect to the Work licensed here. There are no understandings,
+    agreements or representations with respect to the Work not specified
+    here. Licensor shall not be bound by any additional provisions that
+    may appear in any communication from You. This License may not be
+    modified without the mutual written agreement of the Licensor and You.
+ f. The rights granted under, and the subject matter referenced, in this
+    License were drafted utilizing the terminology of the Berne Convention
+    for the Protection of Literary and Artistic Works (as amended on
+    September 28, 1979), the Rome Convention of 1961, the WIPO Copyright
+    Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996
+    and the Universal Copyright Convention (as revised on July 24, 1971).
+    These rights and subject matter take effect in the relevant
+    jurisdiction in which the License terms are sought to be enforced
+    according to the corresponding provisions of the implementation of
+    those treaty provisions in the applicable national law. If the
+    standard suite of rights granted under applicable copyright law
+    includes additional rights not granted under this License, such
+    additional rights are deemed to be included in the License; this
+    License is not intended to restrict the license of any rights under
+    applicable law.
+
+
+Creative Commons Notice
+
+    Creative Commons is not a party to this License, and makes no warranty
+    whatsoever in connection with the Work. Creative Commons will not be
+    liable to You or any party on any legal theory for any damages
+    whatsoever, including without limitation any general, special,
+    incidental or consequential damages arising in connection to this
+    license. Notwithstanding the foregoing two (2) sentences, if Creative
+    Commons has expressly identified itself as the Licensor hereunder, it
+    shall have all rights and obligations of Licensor.
+
+    Except for the limited purpose of indicating to the public that the
+    Work is licensed under the CCPL, Creative Commons does not authorize
+    the use by either party of the trademark "Creative Commons" or any
+    related trademark or logo of Creative Commons without the prior
+    written consent of Creative Commons. Any permitted use will be in
+    compliance with Creative Commons' then-current trademark usage
+    guidelines, as may be published on its website or otherwise made
+    available upon request from time to time. For the avoidance of doubt,
+    this trademark restriction does not form part of the License.
+
+    Creative Commons may be contacted at https://creativecommons.org/.
diff --git a/icons/licenses/gpl-2.0.txt b/icons/licenses/gpl-2.0.txt
new file mode 100644 (file)
index 0000000..d159169
--- /dev/null
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/icons/licenses/lgpl-3.0.txt b/icons/licenses/lgpl-3.0.txt
new file mode 100644 (file)
index 0000000..65c5ca8
--- /dev/null
@@ -0,0 +1,165 @@
+                   GNU LESSER GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+  This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+  0. Additional Definitions.
+
+  As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+  "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+  An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+  A "Combined Work" is a work produced by combining or linking an
+Application with the Library.  The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+  The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+  The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+  1. Exception to Section 3 of the GNU GPL.
+
+  You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+  2. Conveying Modified Versions.
+
+  If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+   a) under this License, provided that you make a good faith effort to
+   ensure that, in the event an Application does not supply the
+   function or data, the facility still operates, and performs
+   whatever part of its purpose remains meaningful, or
+
+   b) under the GNU GPL, with none of the additional permissions of
+   this License applicable to that copy.
+
+  3. Object Code Incorporating Material from Library Header Files.
+
+  The object code form of an Application may incorporate material from
+a header file that is part of the Library.  You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+   a) Give prominent notice with each copy of the object code that the
+   Library is used in it and that the Library and its use are
+   covered by this License.
+
+   b) Accompany the object code with a copy of the GNU GPL and this license
+   document.
+
+  4. Combined Works.
+
+  You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+   a) Give prominent notice with each copy of the Combined Work that
+   the Library is used in it and that the Library and its use are
+   covered by this License.
+
+   b) Accompany the Combined Work with a copy of the GNU GPL and this license
+   document.
+
+   c) For a Combined Work that displays copyright notices during
+   execution, include the copyright notice for the Library among
+   these notices, as well as a reference directing the user to the
+   copies of the GNU GPL and this license document.
+
+   d) Do one of the following:
+
+       0) Convey the Minimal Corresponding Source under the terms of this
+       License, and the Corresponding Application Code in a form
+       suitable for, and under terms that permit, the user to
+       recombine or relink the Application with a modified version of
+       the Linked Version to produce a modified Combined Work, in the
+       manner specified by section 6 of the GNU GPL for conveying
+       Corresponding Source.
+
+       1) Use a suitable shared library mechanism for linking with the
+       Library.  A suitable mechanism is one that (a) uses at run time
+       a copy of the Library already present on the user's computer
+       system, and (b) will operate properly with a modified version
+       of the Library that is interface-compatible with the Linked
+       Version.
+
+   e) Provide Installation Information, but only if you would otherwise
+   be required to provide such information under section 6 of the
+   GNU GPL, and only to the extent that such information is
+   necessary to install and execute a modified version of the
+   Combined Work produced by recombining or relinking the
+   Application with a modified version of the Linked Version. (If
+   you use option 4d0, the Installation Information must accompany
+   the Minimal Corresponding Source and Corresponding Application
+   Code. If you use option 4d1, you must provide the Installation
+   Information in the manner specified by section 6 of the GNU GPL
+   for conveying Corresponding Source.)
+
+  5. Combined Libraries.
+
+  You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+   a) Accompany the combined library with a copy of the same work based
+   on the Library, uncombined with any other library facilities,
+   conveyed under the terms of this License.
+
+   b) Give prominent notice with the combined library that part of it
+   is a work based on the Library, and explaining where to find the
+   accompanying uncombined form of the same work.
+
+  6. Revised Versions of the GNU Lesser General Public License.
+
+  The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+  Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+  If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
diff --git a/icons/os_arch.png b/icons/os_arch.png
new file mode 100644 (file)
index 0000000..0d387b7
Binary files /dev/null and b/icons/os_arch.png differ
diff --git a/icons/os_centos.png b/icons/os_centos.png
new file mode 100644 (file)
index 0000000..d2a65b3
Binary files /dev/null and b/icons/os_centos.png differ
diff --git a/icons/os_chakra.png b/icons/os_chakra.png
new file mode 100644 (file)
index 0000000..365f3d5
Binary files /dev/null and b/icons/os_chakra.png differ
diff --git a/icons/os_chrome.png b/icons/os_chrome.png
new file mode 100644 (file)
index 0000000..158c829
Binary files /dev/null and b/icons/os_chrome.png differ
diff --git a/icons/os_clover.png b/icons/os_clover.png
new file mode 100644 (file)
index 0000000..b4c3b0f
Binary files /dev/null and b/icons/os_clover.png differ
diff --git a/icons/os_crunchbang.png b/icons/os_crunchbang.png
new file mode 100644 (file)
index 0000000..9e192d3
Binary files /dev/null and b/icons/os_crunchbang.png differ
diff --git a/icons/os_debian.png b/icons/os_debian.png
new file mode 100644 (file)
index 0000000..8645db1
Binary files /dev/null and b/icons/os_debian.png differ
diff --git a/icons/os_elementary.png b/icons/os_elementary.png
new file mode 100644 (file)
index 0000000..cec5fff
Binary files /dev/null and b/icons/os_elementary.png differ
diff --git a/icons/os_fedora.png b/icons/os_fedora.png
new file mode 100644 (file)
index 0000000..24c2bcc
Binary files /dev/null and b/icons/os_fedora.png differ
diff --git a/icons/os_freebsd.png b/icons/os_freebsd.png
new file mode 100644 (file)
index 0000000..ddfcec0
Binary files /dev/null and b/icons/os_freebsd.png differ
diff --git a/icons/os_frugalware.png b/icons/os_frugalware.png
new file mode 100644 (file)
index 0000000..b4cb4e1
Binary files /dev/null and b/icons/os_frugalware.png differ
diff --git a/icons/os_gentoo.png b/icons/os_gentoo.png
new file mode 100644 (file)
index 0000000..8f80c9d
Binary files /dev/null and b/icons/os_gentoo.png differ
diff --git a/icons/os_gummiboot.png b/icons/os_gummiboot.png
new file mode 100644 (file)
index 0000000..06713b3
Binary files /dev/null and b/icons/os_gummiboot.png differ
diff --git a/icons/os_haiku.png b/icons/os_haiku.png
new file mode 100644 (file)
index 0000000..1b1591e
Binary files /dev/null and b/icons/os_haiku.png differ
diff --git a/icons/os_hwtest.png b/icons/os_hwtest.png
new file mode 100644 (file)
index 0000000..907ad69
Binary files /dev/null and b/icons/os_hwtest.png differ
diff --git a/icons/os_kubuntu.png b/icons/os_kubuntu.png
new file mode 100644 (file)
index 0000000..2fb3262
Binary files /dev/null and b/icons/os_kubuntu.png differ
diff --git a/icons/os_legacy.png b/icons/os_legacy.png
new file mode 100644 (file)
index 0000000..56d1ef5
Binary files /dev/null and b/icons/os_legacy.png differ
diff --git a/icons/os_linux.png b/icons/os_linux.png
new file mode 100644 (file)
index 0000000..b08caa6
Binary files /dev/null and b/icons/os_linux.png differ
diff --git a/icons/os_linuxmint.png b/icons/os_linuxmint.png
new file mode 100644 (file)
index 0000000..94fac7c
Binary files /dev/null and b/icons/os_linuxmint.png differ
diff --git a/icons/os_lubuntu.png b/icons/os_lubuntu.png
new file mode 100644 (file)
index 0000000..3545e90
Binary files /dev/null and b/icons/os_lubuntu.png differ
diff --git a/icons/os_mac.png b/icons/os_mac.png
new file mode 100644 (file)
index 0000000..bb03018
Binary files /dev/null and b/icons/os_mac.png differ
diff --git a/icons/os_mageia.png b/icons/os_mageia.png
new file mode 100644 (file)
index 0000000..bb21a52
Binary files /dev/null and b/icons/os_mageia.png differ
diff --git a/icons/os_mandriva.png b/icons/os_mandriva.png
new file mode 100644 (file)
index 0000000..ccab520
Binary files /dev/null and b/icons/os_mandriva.png differ
diff --git a/icons/os_netbsd.png b/icons/os_netbsd.png
new file mode 100644 (file)
index 0000000..5fa8286
Binary files /dev/null and b/icons/os_netbsd.png differ
diff --git a/icons/os_network.png b/icons/os_network.png
new file mode 100644 (file)
index 0000000..2f19d30
Binary files /dev/null and b/icons/os_network.png differ
diff --git a/icons/os_opensuse.png b/icons/os_opensuse.png
new file mode 100644 (file)
index 0000000..3ac3673
Binary files /dev/null and b/icons/os_opensuse.png differ
diff --git a/icons/os_redhat.png b/icons/os_redhat.png
new file mode 100644 (file)
index 0000000..02f6547
Binary files /dev/null and b/icons/os_redhat.png differ
diff --git a/icons/os_refind.png b/icons/os_refind.png
new file mode 100644 (file)
index 0000000..bad3ee4
Binary files /dev/null and b/icons/os_refind.png differ
diff --git a/icons/os_refit.png b/icons/os_refit.png
new file mode 100644 (file)
index 0000000..deb4f73
Binary files /dev/null and b/icons/os_refit.png differ
diff --git a/icons/os_slackware.png b/icons/os_slackware.png
new file mode 100644 (file)
index 0000000..67f6d7e
Binary files /dev/null and b/icons/os_slackware.png differ
diff --git a/icons/os_suse.png b/icons/os_suse.png
new file mode 100644 (file)
index 0000000..3ac3673
Binary files /dev/null and b/icons/os_suse.png differ
diff --git a/icons/os_ubuntu.png b/icons/os_ubuntu.png
new file mode 100644 (file)
index 0000000..db748e0
Binary files /dev/null and b/icons/os_ubuntu.png differ
diff --git a/icons/os_unknown.png b/icons/os_unknown.png
new file mode 100644 (file)
index 0000000..e76e97d
Binary files /dev/null and b/icons/os_unknown.png differ
diff --git a/icons/os_win.png b/icons/os_win.png
new file mode 100644 (file)
index 0000000..ccacfaf
Binary files /dev/null and b/icons/os_win.png differ
diff --git a/icons/os_win8.png b/icons/os_win8.png
new file mode 100644 (file)
index 0000000..f01af72
Binary files /dev/null and b/icons/os_win8.png differ
diff --git a/icons/os_xubuntu.png b/icons/os_xubuntu.png
new file mode 100644 (file)
index 0000000..8ee623d
Binary files /dev/null and b/icons/os_xubuntu.png differ
diff --git a/icons/svg/boot_win.svg b/icons/svg/boot_win.svg
new file mode 100644 (file)
index 0000000..cf85b84
--- /dev/null
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="128"
+   height="128"
+   id="svg9607"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="os_win-02-white.svg"
+   inkscape:export-filename="/home/rodsmith/programming/refind/current/icons-build/svg/os_win-white.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90">
+  <defs
+     id="defs9609" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#bfbfbf"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="1"
+     inkscape:pageshadow="2"
+     inkscape:zoom="4.9497475"
+     inkscape:cx="64.652322"
+     inkscape:cy="66.261588"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:grid-bbox="true"
+     inkscape:document-units="px"
+     inkscape:window-width="1104"
+     inkscape:window-height="885"
+     inkscape:window-x="459"
+     inkscape:window-y="32"
+     inkscape:window-maximized="0" />
+  <metadata
+     id="metadata9612">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     transform="translate(0,80)">
+    <g
+       id="g9738"
+       transform="translate(-0.2020298,-0.90913682)"
+       style="fill:#737373;stroke:#737373;fill-opacity:1;stroke-opacity:1">
+      <path
+         sodipodi:nodetypes="ccccc"
+         inkscape:connector-curvature="0"
+         id="rect9615"
+         d="m 4.7203518,-11.741735 c 12.0209472,-14.272787 44.5029732,-16.021563 56.1714892,0 l 0,43.560551 c -13.716554,-12.936189 -38.510159,-14.30236 -56.1714892,0 z"
+         style="fill:#737373;fill-opacity:1;stroke:#737373;stroke-width:1.17263913000000009;stroke-opacity:1" />
+      <path
+         sodipodi:nodetypes="ccccc"
+         inkscape:connector-curvature="0"
+         id="rect9615-6"
+         d="m 4.6350396,-64.86804 c 12.0209444,-14.272787 44.5029724,-16.021562 56.1714884,0 l 0,43.560551 c -12.154227,-12.865477 -36.38669,-14.364515 -56.1714884,0 z"
+         style="fill:#737373;fill-opacity:1;stroke:#737373;stroke-width:1.17263913000000009;stroke-opacity:1" />
+      <path
+         sodipodi:nodetypes="ccccc"
+         inkscape:connector-curvature="0"
+         id="rect9615-6-7"
+         d="m 67.538565,-17.822259 c 12.020945,14.2727869 44.502975,16.0215625 56.171495,0 l 0,-43.56055 c -12.15423,12.865476 -36.386696,14.364514 -56.171495,0 z"
+         style="fill:#737373;fill-opacity:1;stroke:#737373;stroke-width:1.17263913000000009;stroke-opacity:1" />
+      <path
+         sodipodi:nodetypes="ccccc"
+         inkscape:connector-curvature="0"
+         id="rect9615-6-7-5"
+         d="m 67.597521,34.686314 c 12.020945,14.272786 44.502979,16.021562 56.171499,0 l 0,-43.5605509 c -12.15423,12.8654779 -36.386701,14.3645156 -56.171499,0 z"
+         style="fill:#737373;fill-opacity:1;stroke:#737373;stroke-width:1.17263913000000009;stroke-opacity:1" />
+    </g>
+  </g>
+</svg>
diff --git a/icons/svg/func_csr_rotate.svg b/icons/svg/func_csr_rotate.svg
new file mode 100644 (file)
index 0000000..ef1ee4e
--- /dev/null
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="48"
+   height="48"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="func_sip-01-basic.svg"
+   inkscape:export-filename="/home/rodsmith/programming/refind/current/icons-build/func_sip-color.png"
+   inkscape:export-xdpi="33.75"
+   inkscape:export-ydpi="33.75">
+  <defs
+     id="defs4">
+    <filter
+       id="filter3838"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood3840"
+         flood-opacity="0.7"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite3842"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur3844"
+         in="composite"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset3846"
+         dx="3"
+         dy="3"
+         result="offset" />
+      <feComposite
+         id="feComposite3848"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="7.9195959"
+     inkscape:cx="14.078998"
+     inkscape:cy="30.823184"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:window-width="1061"
+     inkscape:window-height="863"
+     inkscape:window-x="447"
+     inkscape:window-y="84"
+     inkscape:window-maximized="0" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(0,-1004.3622)">
+    <path
+       style="fill:#800000;fill-opacity:1;stroke:#800000;stroke-width:0.03846657;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;filter:url(#filter3838)"
+       d="m 21.57976,1047.861 c -0.544952,-0.2595 -1.77118,-0.9766 -2.724951,-1.5938 -8.114061,-5.2503 -13.8035913,-13.1805 -16.2965633,-22.7141 -0.4860218,-1.8587 -1.1295245,-5.9882 -1.1295245,-7.2487 l 0,-0.9563 0.8926568,0.1543 c 1.4854374,0.256 4.7318491,0.194 6.6192884,-0.1263 5.1768806,-0.8793 10.1276286,-3.82 13.5012376,-8.0194 l 0.5985,-0.745 0.598501,0.745 c 1.159672,1.4435 3.082847,3.246 4.590378,4.3025 4.149538,2.9078 8.617368,4.2016 13.712581,3.9712 l 2.356571,-0.1063 -0.116147,1.1115 c -0.547261,5.2373 -1.512962,9.0558 -3.358489,13.2801 -2.731316,6.2519 -7.907289,12.3599 -13.616767,16.069 -1.736654,1.1282 -4.061083,2.3759 -4.396844,2.36 -0.131774,0 -0.685472,-0.2236 -1.230425,-0.4829 l 0,0 z"
+       id="path3817"
+       inkscape:connector-curvature="0" />
+  </g>
+</svg>
diff --git a/icons/svg/os_clover.svg b/icons/svg/os_clover.svg
new file mode 100644 (file)
index 0000000..16aa594
--- /dev/null
@@ -0,0 +1,417 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="128"
+   height="128"
+   id="svg15332"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="os_clover-01-basic.svg">
+  <defs
+     id="defs15334">
+    <inkscape:path-effect
+       effect="skeletal"
+       id="path-effect15588"
+       is_visible="true"
+       pattern="m -48.597521,-31.744248 10,5 0,-10 z"
+       copytype="single_stretched"
+       prop_scale="1"
+       scale_y_rel="false"
+       spacing="0"
+       normal_offset="0"
+       tang_offset="0"
+       prop_units="false"
+       vertical_pattern="false"
+       fuse_tolerance="0" />
+    <inkscape:path-effect
+       effect="skeletal"
+       id="path-effect15584"
+       is_visible="true"
+       pattern="M 0,5 10,10 10,0 z"
+       copytype="single_stretched"
+       prop_scale="1"
+       scale_y_rel="false"
+       spacing="0"
+       normal_offset="0"
+       tang_offset="0"
+       prop_units="false"
+       vertical_pattern="false"
+       fuse_tolerance="0" />
+    <inkscape:path-effect
+       effect="skeletal"
+       id="path-effect15580"
+       is_visible="true"
+       pattern="M 0,5 10,10 10,0 z"
+       copytype="single_stretched"
+       prop_scale="1"
+       scale_y_rel="false"
+       spacing="0"
+       normal_offset="0"
+       tang_offset="0"
+       prop_units="false"
+       vertical_pattern="false"
+       fuse_tolerance="0" />
+    <inkscape:path-effect
+       effect="skeletal"
+       id="path-effect15576"
+       is_visible="true"
+       pattern="m -0.25712974,-58.74287 10.00000004,5 0,-10 z"
+       copytype="single_stretched"
+       prop_scale="1"
+       scale_y_rel="false"
+       spacing="0"
+       normal_offset="0"
+       tang_offset="0"
+       prop_units="false"
+       vertical_pattern="false"
+       fuse_tolerance="0" />
+    <inkscape:path-effect
+       effect="skeletal"
+       id="path-effect15572"
+       is_visible="true"
+       pattern="M 0,5 10,10 10,0 z"
+       copytype="single_stretched"
+       prop_scale="1"
+       scale_y_rel="false"
+       spacing="0"
+       normal_offset="0"
+       tang_offset="0"
+       prop_units="false"
+       vertical_pattern="false"
+       fuse_tolerance="0" />
+    <inkscape:path-effect
+       effect="skeletal"
+       id="path-effect15568"
+       is_visible="true"
+       pattern="M 0,5 10,10 10,0 z"
+       copytype="single_stretched"
+       prop_scale="1"
+       scale_y_rel="false"
+       spacing="0"
+       normal_offset="0"
+       tang_offset="0"
+       prop_units="false"
+       vertical_pattern="false"
+       fuse_tolerance="0" />
+    <inkscape:path-effect
+       effect="skeletal"
+       id="path-effect15564"
+       is_visible="true"
+       pattern="M 0,0 0,10 10,5 z"
+       copytype="single_stretched"
+       prop_scale="1"
+       scale_y_rel="false"
+       spacing="0"
+       normal_offset="0"
+       tang_offset="0"
+       prop_units="false"
+       vertical_pattern="false"
+       fuse_tolerance="0" />
+    <inkscape:path-effect
+       effect="skeletal"
+       id="path-effect15560"
+       is_visible="true"
+       pattern="M 0,5 10,10 10,0 z"
+       copytype="single_stretched"
+       prop_scale="1"
+       scale_y_rel="false"
+       spacing="0"
+       normal_offset="0"
+       tang_offset="0"
+       prop_units="false"
+       vertical_pattern="false"
+       fuse_tolerance="0" />
+    <inkscape:path-effect
+       effect="skeletal"
+       id="path-effect15556"
+       is_visible="true"
+       pattern="M 0,5 10,10 10,0 z"
+       copytype="single_stretched"
+       prop_scale="1"
+       scale_y_rel="false"
+       spacing="0"
+       normal_offset="0"
+       tang_offset="0"
+       prop_units="false"
+       vertical_pattern="false"
+       fuse_tolerance="0" />
+    <inkscape:path-effect
+       effect="skeletal"
+       id="path-effect15552"
+       is_visible="true"
+       pattern="M 0,5 10,10 10,0 z"
+       copytype="single_stretched"
+       prop_scale="1"
+       scale_y_rel="false"
+       spacing="0"
+       normal_offset="0"
+       tang_offset="0"
+       prop_units="false"
+       vertical_pattern="false"
+       fuse_tolerance="0" />
+    <inkscape:path-effect
+       effect="skeletal"
+       id="path-effect15548"
+       is_visible="true"
+       pattern="M 0,5 10,10 10,0 z"
+       copytype="single_stretched"
+       prop_scale="1"
+       scale_y_rel="false"
+       spacing="0"
+       normal_offset="0"
+       tang_offset="0"
+       prop_units="false"
+       vertical_pattern="false"
+       fuse_tolerance="0" />
+    <inkscape:path-effect
+       effect="skeletal"
+       id="path-effect15544"
+       is_visible="true"
+       pattern="M 0,5 10,10 10,0 z"
+       copytype="single_stretched"
+       prop_scale="1"
+       scale_y_rel="false"
+       spacing="0"
+       normal_offset="0"
+       tang_offset="0"
+       prop_units="false"
+       vertical_pattern="false"
+       fuse_tolerance="0" />
+    <inkscape:path-effect
+       effect="skeletal"
+       id="path-effect15540"
+       is_visible="true"
+       pattern="M 0,5 10,10 10,0 z"
+       copytype="single_stretched"
+       prop_scale="1"
+       scale_y_rel="false"
+       spacing="0"
+       normal_offset="0"
+       tang_offset="0"
+       prop_units="false"
+       vertical_pattern="false"
+       fuse_tolerance="0" />
+    <inkscape:path-effect
+       effect="skeletal"
+       id="path-effect15536"
+       is_visible="true"
+       pattern="M 0,5 10,10 10,0 z"
+       copytype="single_stretched"
+       prop_scale="1"
+       scale_y_rel="false"
+       spacing="0"
+       normal_offset="0"
+       tang_offset="0"
+       prop_units="false"
+       vertical_pattern="false"
+       fuse_tolerance="0" />
+    <inkscape:path-effect
+       effect="skeletal"
+       id="path-effect15532"
+       is_visible="true"
+       pattern="M 0,5 10,10 10,0 z"
+       copytype="single_stretched"
+       prop_scale="1"
+       scale_y_rel="false"
+       spacing="0"
+       normal_offset="0"
+       tang_offset="0"
+       prop_units="false"
+       vertical_pattern="false"
+       fuse_tolerance="0" />
+    <inkscape:path-effect
+       effect="skeletal"
+       id="path-effect15528"
+       is_visible="true"
+       pattern="M 0,5 10,10 10,0 z"
+       copytype="single_stretched"
+       prop_scale="1"
+       scale_y_rel="false"
+       spacing="0"
+       normal_offset="0"
+       tang_offset="0"
+       prop_units="false"
+       vertical_pattern="false"
+       fuse_tolerance="0" />
+    <inkscape:path-effect
+       effect="skeletal"
+       id="path-effect15524"
+       is_visible="true"
+       pattern="M 0,5 10,10 10,0 z"
+       copytype="single_stretched"
+       prop_scale="1"
+       scale_y_rel="false"
+       spacing="0"
+       normal_offset="0"
+       tang_offset="0"
+       prop_units="false"
+       vertical_pattern="false"
+       fuse_tolerance="0" />
+    <inkscape:path-effect
+       effect="skeletal"
+       id="path-effect15520"
+       is_visible="true"
+       pattern="M 0,5 10,10 10,0 z"
+       copytype="single_stretched"
+       prop_scale="1"
+       scale_y_rel="false"
+       spacing="0"
+       normal_offset="0"
+       tang_offset="0"
+       prop_units="false"
+       vertical_pattern="false"
+       fuse_tolerance="0" />
+    <inkscape:path-effect
+       effect="skeletal"
+       id="path-effect15516"
+       is_visible="true"
+       pattern="M 0,5 10,10 10,0 z"
+       copytype="single_stretched"
+       prop_scale="1"
+       scale_y_rel="false"
+       spacing="0"
+       normal_offset="0"
+       tang_offset="0"
+       prop_units="false"
+       vertical_pattern="false"
+       fuse_tolerance="0" />
+    <inkscape:path-effect
+       effect="skeletal"
+       id="path-effect15418"
+       is_visible="true"
+       pattern="m 29.055659,-73.596157 10,5 0,-10 z"
+       copytype="single_stretched"
+       prop_scale="1"
+       scale_y_rel="false"
+       spacing="0"
+       normal_offset="0"
+       tang_offset="0"
+       prop_units="false"
+       vertical_pattern="false"
+       fuse_tolerance="0" />
+    <filter
+       id="filter15645"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood15647"
+         flood-opacity="0.7"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite15649"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur15651"
+         in="composite"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset15653"
+         dx="3"
+         dy="3"
+         result="offset" />
+      <feComposite
+         id="feComposite15655"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="3.8890873"
+     inkscape:cx="76.499667"
+     inkscape:cy="64"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:document-units="px"
+     inkscape:grid-bbox="true"
+     showguides="true"
+     inkscape:guide-bbox="true"
+     inkscape:snap-bbox="true"
+     inkscape:window-width="1107"
+     inkscape:window-height="816"
+     inkscape:window-x="258"
+     inkscape:window-y="37"
+     inkscape:window-maximized="0" />
+  <metadata
+     id="metadata15337">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     transform="translate(0,64)">
+    <g
+       id="g15590"
+       transform="matrix(1.1495,0,0,1.1495,-1.9363173,13.844484)"
+       style="filter:url(#filter15645)">
+      <path
+         sodipodi:nodetypes="czczc"
+         inkscape:connector-curvature="0"
+         id="path15343"
+         d="m 55.052174,-14.387764 c 0,0 -46.2012364,4.5766947 -47.7332623,-9.116068 -1.5320244,-13.692764 20.4095553,-18.119841 20.4095553,-18.119841 0,0 4.356441,-21.955715 18.054064,-20.467766 13.697625,1.487948 9.269643,47.703675 9.269643,47.703675 z"
+         inkscape:transform-center-y="6.0425489"
+         style="fill:#008000;fill-opacity:1;stroke:#008000;stroke-width:1.29743457;stroke-opacity:1" />
+      <path
+         sodipodi:nodetypes="czczc"
+         inkscape:connector-curvature="0"
+         id="path15343-9"
+         d="m 60.364186,-9.9018411 c 0,0 46.201244,-4.5766959 47.733264,9.11606989 C 109.62947,12.90699 87.687893,17.334069 87.687893,17.334069 c 0,0 -4.356441,21.955714 -18.054064,20.467766 -13.697624,-1.48795 -9.269643,-47.7036761 -9.269643,-47.7036761 z"
+         inkscape:transform-center-y="-6.0425487"
+         style="fill:#008000;fill-opacity:1;stroke:#008000;stroke-width:1.29743457;stroke-opacity:1" />
+      <path
+         inkscape:transform-center-x="6.0425489"
+         sodipodi:nodetypes="czczc"
+         inkscape:connector-curvature="0"
+         id="path15343-7"
+         d="m 60.196664,-14.261099 c 0,0 -4.291826,-46.174813 9.410375,-47.791325 13.702199,-1.616513 17.993988,20.298621 17.993988,20.298621 0,0 21.928833,4.221239 20.356433,17.928567 -1.57241,13.707337 -47.760796,9.564137 -47.760796,9.564137 z"
+         style="fill:#008000;fill-opacity:1;stroke:#008000;stroke-width:1.29743457;stroke-opacity:1" />
+      <path
+         inkscape:transform-center-y="-2.0570379"
+         inkscape:transform-center-x="-24.81302"
+         sodipodi:nodetypes="czczc"
+         inkscape:connector-curvature="0"
+         id="path15343-7-0"
+         d="m 54.389123,-9.8005956 c 0,0 4.291824,46.1748136 -9.410375,47.7913256 C 31.27655,39.60724 26.984763,17.692104 26.984763,17.692104 c 0,0 -21.9288363,-4.221236 -20.3564342,-17.92856893 C 8.2007355,-13.943795 54.389123,-9.8005956 54.389123,-9.8005956 z"
+         style="fill:#008000;fill-opacity:1;stroke:#008000;stroke-width:1.29743457;stroke-opacity:1" />
+      <path
+         transform="matrix(0.91877547,-0.92173709,0.91607136,0.91312794,-55.308264,-90.153688)"
+         d="m 22.627418,104.85832 c 0,1.98813 -1.726814,3.59982 -3.856946,3.59982 -2.130133,0 -3.856946,-1.61169 -3.856946,-3.59982 0,-1.98812 1.726813,-3.59981 3.856946,-3.59981 2.130132,0 3.856946,1.61169 3.856946,3.59981 z"
+         sodipodi:ry="3.5998163"
+         sodipodi:rx="3.856946"
+         sodipodi:cy="104.85832"
+         sodipodi:cx="18.770472"
+         id="path15420"
+         style="fill:#008000;fill-opacity:1;stroke:#008000;stroke-opacity:1"
+         sodipodi:type="arc" />
+    </g>
+  </g>
+</svg>
diff --git a/icons/svg/os_debian.svg b/icons/svg/os_debian.svg
new file mode 100644 (file)
index 0000000..b4589f7
--- /dev/null
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   height="108.76"
+   viewBox="0 0 108.758 108.76226"
+   width="108.76"
+   id="svg11843"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="os_debian-02-bare.svg">
+  <metadata
+     id="metadata11887">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs11885">
+    <filter
+       id="filter11922"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood11924"
+         flood-opacity="0.7"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite11926"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur11928"
+         in="composite"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset11930"
+         dx="2"
+         dy="2"
+         result="offset" />
+      <feComposite
+         id="feComposite11932"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="955"
+     inkscape:window-height="882"
+     id="namedview11883"
+     showgrid="false"
+     inkscape:zoom="3.2748212"
+     inkscape:cx="54.380001"
+     inkscape:cy="72.065002"
+     inkscape:window-x="205"
+     inkscape:window-y="51"
+     inkscape:window-maximized="0"
+     inkscape:current-layer="svg11843" />
+  <g
+     id="g11889"
+     transform="translate(0.48298776,44.66387)"
+     style="filter:url(#filter11922)">
+    <path
+       style="fill:#d70751"
+       inkscape:connector-curvature="0"
+       id="path11845"
+       d="m 60.969,12.27426 c -1.494,0.02 0.281,0.768 2.232,1.069 0.541,-0.422 1.027,-0.846 1.463,-1.26 -1.213,0.297 -2.449,0.304 -3.695,0.191" />
+    <path
+       style="fill:#d70751"
+       inkscape:connector-curvature="0"
+       id="path11847"
+       d="m 68.986,10.27526 c 0.893,-1.2289999 1.541,-2.5729999 1.77,-3.9629999 -0.201,0.99 -0.736,1.845 -1.244,2.749 -2.793,1.7589999 -0.264,-1.044 -0.002,-2.111 -3.002,3.7829999 -0.414,2.268 -0.524,3.3249999" />
+    <path
+       style="fill:#d70751"
+       inkscape:connector-curvature="0"
+       id="path11849"
+       d="m 71.949,2.5712601 c 0.182,-2.69099999 -0.529,-1.83899999 -0.768,-0.814 0.278,0.146 0.499,1.898 0.768,0.814" />
+    <path
+       style="fill:#d70751"
+       inkscape:connector-curvature="0"
+       id="path11851"
+       d="m 55.301,-34.20774 c 0.798,0.142 1.724,0.252 1.591,0.443 0.876,-0.193 1.073,-0.367 -1.591,-0.443" />
+    <path
+       style="fill:#d70751"
+       inkscape:connector-curvature="0"
+       id="path11853"
+       d="m 56.893,-33.76474 -0.561,0.117 0.523,-0.048 0.038,-0.069" />
+    <path
+       style="fill:#d70751"
+       inkscape:connector-curvature="0"
+       id="path11855"
+       d="m 81.762,3.5912601 c 0.09,2.416 -0.705,3.59 -1.424,5.666 l -1.293,0.643 C 77.988,11.95426 79.15,11.20426 78.393,12.83726 c -1.652,1.467 -5.006,4.589 -6.08,4.875 -0.785,-0.017 0.531,-0.926 0.703,-1.281 -2.209,1.516 -1.773,2.276 -5.152,3.199 l -0.098,-0.221 c -8.33,3.92 -19.902,-3.847 -19.75,-14.4429999 -0.088,0.672 -0.253,0.504 -0.437,0.774 -0.43,-5.45099999 2.518,-10.926 7.49,-13.165 4.863,-2.406 10.564,-1.42 14.045,1.829 -1.912,-2.506 -5.721,-5.1630001 -10.232,-4.9170001 -4.421,0.072 -8.558,2.8810001 -9.938,5.9320001 -2.264,1.425 -2.528,5.49600001 -3.514,6.242 -1.329,9.7599999 2.497,13.9749999 8.97,18.9359999 1.016,0.686 0.286,0.791 0.422,1.313 -2.15,-1.006 -4.118,-2.526 -5.738,-4.387 0.86,1.257 1.787,2.479 2.986,3.439 -2.029,-0.685 -4.738,-4.913 -5.527,-5.085 3.495,6.258 14.178,10.975 19.775,8.634 -2.59,0.096 -5.879,0.053 -8.787,-1.022 -1.225,-0.629 -2.884,-1.93 -2.587,-2.173 7.636,2.851 15.522,2.158 22.128,-3.137 1.682,-1.31 3.518,-3.537 4.049,-3.567 -0.799,1.202 0.137,0.578 -0.477,1.639 1.672,-2.701 -0.729,-1.1 1.73,-4.664 l 0.908,1.25 c -0.34,-2.244 2.785,-4.9659999 2.467,-8.5119999 0.717,-1.084 0.799,1.168 0.039,3.662 1.055,-2.767 0.279,-3.212 0.549,-5.496 0.291,0.768 0.678,1.583 0.875,2.394 -0.688,-2.675 0.703,-4.50299999 1.049,-6.058 -0.342,-0.15 -1.061,1.18200001 -1.227,-1.976 0.025,-1.372 0.383,-0.719 0.52,-1.057 -0.268,-0.155 -0.975,-1.207 -1.404,-3.224 0.309,-0.475 0.832,1.229 1.256,1.298 -0.273,-1.603 -0.742,-2.826 -0.762,-4.0570001 -1.24,-2.59 -0.439,0.3460001 -1.443,-1.112 -1.32,-4.114 1.094,-0.955 1.258,-2.823 1.998,2.895 3.137,7.3850001 3.662,9.2440001 -0.4,-2.267 -1.045,-4.464 -1.834,-6.5890001 0.609,0.257 -0.979,-4.663 0.791,-1.405 -1.889,-6.945 -8.078,-13.435 -13.773,-16.479 0.695,0.637 1.574,1.437 1.26,1.563 -2.834,-1.685 -2.336,-1.818 -2.742,-2.53 -2.305,-0.939 -2.459,0.077 -3.984,0.002 -4.35,-2.308 -5.188,-2.063 -9.191,-3.507 l 0.182,0.852 c -2.881,-0.96 -3.357,0.362 -6.47,0.002 -0.189,-0.147 0.998,-0.536 1.976,-0.677 -2.786,0.368 -2.656,-0.55 -5.382,0.101 0.671,-0.471 1.383,-0.784 2.099,-1.184 -2.271,0.138 -5.424,1.322 -4.451,0.244 -3.705,1.654 -10.286,3.975 -13.979,7.438 l -0.116,-0.776 c -1.692,2.031 -7.379,6.066 -7.832,8.699 l -0.453,0.105 c -0.879,1.491 -1.45,3.18 -2.148,4.713 -1.151,1.963 -1.688,0.756 -1.524,1.064 -2.265,4.5920001 -3.392,8.4500001 -4.363,11.6160001 0.692,1.03500001 0.017,6.232 0.278,10.391 C 17.329,29.30726 32.883,49.25226 49.885,53.85626 c 2.492,0.893 6.197,0.861 9.349,0.949 -3.718,-1.064 -4.198,-0.563 -7.822,-1.826 -2.613,-1.232 -3.185,-2.637 -5.037,-4.244 l 0.733,1.295 c -3.63,-1.285 -2.111,-1.59 -5.065,-2.525 l 0.783,-1.021 c -1.177,-0.09 -3.117,-1.982 -3.647,-3.033 l -1.288,0.051 c -1.546,-1.906 -2.371,-3.283 -2.31,-4.35 l -0.416,0.742 c -0.471,-0.809 -5.691,-7.158 -2.983,-5.68 -0.503,-0.458 -1.172,-0.747 -1.897,-2.066 l 0.551,-0.629 c -1.301,-1.677 -2.398,-3.826 -2.314,-4.542 0.695,0.938 1.177,1.114 1.655,1.275 -3.291,-8.164 -3.476,-0.449 -5.967,-8.31 l 0.526,-0.042 c -0.403,-0.611 -0.65,-1.27 -0.974,-1.919 l 0.23,-2.285 C 21.624,12.96026 23.33,4.0512601 23.673,-0.83373989 23.908,-2.8197399 25.65,-4.9347399 26.973,-8.2517399 l -0.806,-0.138 C 27.709,-11.07774 34.969,-19.18874 38.333,-18.77274 c 1.629,-2.046 -0.324,-0.008 -0.643,-0.522 3.579,-3.703 4.704,-2.616 7.119,-3.283 2.603,-1.545 -2.235,0.604 -1.001,-0.589 4.503,-1.149 3.19,-2.614 9.063,-3.197 0.62,0.352 -1.437,0.544 -1.953,1.001 3.75,-1.836 11.869,-1.417 17.145,1.018 6.117,2.861 12.994,11.314 13.266,19.2670001 l 0.309,0.083 c -0.156,3.162 0.484,6.819 -0.627,10.177 l 0.751,-1.591" />
+    <path
+       style="fill:#d70751"
+       inkscape:connector-curvature="0"
+       id="path11857"
+       d="m 44.658,14.32426 -0.211,1.047 c 0.983,1.335 1.763,2.781 3.016,3.821 -0.902,-1.759 -1.571,-2.486 -2.805,-4.868" />
+    <path
+       style="fill:#d70751"
+       inkscape:connector-curvature="0"
+       id="path11859"
+       d="m 46.979,14.23426 c -0.52,-0.576 -0.826,-1.268 -1.172,-1.956 0.33,1.211 1.006,2.252 1.633,3.312 l -0.461,-1.356" />
+    <path
+       style="fill:#d70751"
+       inkscape:connector-curvature="0"
+       id="path11861"
+       d="m 88.063,5.3042601 -0.219,0.552 c -0.402,2.858 -1.273,5.6859999 -2.605,8.3089999 1.472,-2.767 2.421,-5.7939999 2.824,-8.8609999" />
+    <path
+       style="fill:#d70751"
+       inkscape:connector-curvature="0"
+       id="path11863"
+       d="m 55.598,-34.92474 c 1.009,-0.369 2.482,-0.203 3.556,-0.446 -1.398,0.117 -2.789,0.187 -4.162,0.362 l 0.606,0.084" />
+    <path
+       style="fill:#d70751"
+       inkscape:connector-curvature="0"
+       id="path11865"
+       d="m 20.127,-16.06274 c 0.233,2.154 -1.62,2.991 0.41,1.569 1.09,-2.454 -0.424,-0.677 -0.41,-1.569" />
+    <path
+       style="fill:#d70751"
+       inkscape:connector-curvature="0"
+       id="path11867"
+       d="m 17.739,-6.0887399 c 0.469,-1.437 0.553,-2.299 0.732,-3.132 -1.293,1.654 -0.596,2.007 -0.732,3.132" />
+  </g>
+</svg>
diff --git a/icons/svg/os_elementary.svg b/icons/svg/os_elementary.svg
new file mode 100644 (file)
index 0000000..fc97891
--- /dev/null
@@ -0,0 +1,188 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="128"
+   height="128"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="os_elementary-05-white.svg"
+   inkscape:export-filename="/home/rodsmith/programming/refind/current/icons-build/os_elementary-white.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90">
+  <defs
+     id="defs4">
+    <inkscape:path-effect
+       is_visible="true"
+       id="path-effect2991"
+       effect="spiro" />
+    <inkscape:path-effect
+       effect="spiro"
+       id="path-effect3177"
+       is_visible="true" />
+    <filter
+       id="filter13615"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood13617"
+         flood-opacity="0.7"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite13619"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur13621"
+         in="composite"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset13623"
+         dx="2"
+         dy="2"
+         result="offset" />
+      <feComposite
+         id="feComposite13625"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+    <filter
+       id="filter13646"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood13648"
+         flood-opacity="0.9"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite13650"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur13652"
+         in="composite"
+         stdDeviation="8"
+         result="blur" />
+      <feOffset
+         id="feOffset13654"
+         dx="5"
+         dy="5"
+         result="offset" />
+      <feComposite
+         id="feComposite13656"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#a0a0a0"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="5.6568542"
+     inkscape:cx="66.329121"
+     inkscape:cy="64"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     showguides="false"
+     inkscape:guide-bbox="true"
+     inkscape:window-width="1050"
+     inkscape:window-height="979"
+     inkscape:window-x="413"
+     inkscape:window-y="0"
+     inkscape:window-maximized="0"
+     fit-margin-top="4"
+     fit-margin-left="4"
+     fit-margin-right="4"
+     fit-margin-bottom="4"
+     showborder="true"
+     inkscape:showpageshadow="true">
+    <sodipodi:guide
+       orientation="1,0"
+       position="4,4"
+       id="guide2985" />
+    <sodipodi:guide
+       orientation="1,0"
+       position="604,459.18566"
+       id="guide2987" />
+    <sodipodi:guide
+       orientation="0,1"
+       position="-198.43278,4"
+       id="guide2989" />
+    <sodipodi:guide
+       orientation="0,1"
+       position="-265.01408,604"
+       id="guide2991" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-96,-828.36218)">
+    <g
+       id="g13609"
+       transform="matrix(0.19390511,0,0,0.19381243,80.257491,768.01645)"
+       style="filter:url(#filter13646);fill:#1e9eff;stroke:#1e9eff;fill-opacity:1;stroke-opacity:1"
+       inkscape:export-xdpi="18.947369"
+       inkscape:export-ydpi="18.947369">
+      <path
+         transform="translate(96,326.36218)"
+         inkscape:connector-curvature="0"
+         id="path13582"
+         d="M 299.80321,613.56476 C 197.92174,608.10118 106.15948,551.42291 55.073464,462.40395 35.899346,428.99245 23.807511,392.35152 17.969021,349.96927 16.20857,337.18996 16.197191,293.21958 17.950995,280.31498 27.700685,208.5762 56.958646,149.56573 106.85356,101.00716 153.12077,55.979107 207.62342,29.10103 273.17069,18.987558 c 19.8615,-3.064488 61.41591,-3.344894 80.40973,-0.5426 32.93296,4.858834 63.09581,13.804446 89.62868,26.581812 119.1285,57.3684 186.53393,183.77486 167.42463,313.974 -15.27514,104.07549 -85.55456,193.19 -183.81387,233.07653 -39.89944,16.19643 -84.61652,23.76124 -127.01665,21.48746 z m 41.12067,-18.81162 c 67.62471,-6.72428 127.15604,-35.33941 174.10572,-83.68799 30.33179,-31.23553 51.23408,-65.7593 64.9757,-107.31867 20.12404,-60.86197 18.98998,-127.94066 -3.16425,-187.16499 C 539.8057,117.57592 451.67832,48.226595 347.39861,36.028341 330.48807,34.050209 298.99376,34.030335 282.26467,35.987241 228.56724,42.268568 177.93154,64.18429 135.7678,99.3928 83.07679,143.39203 49.37961,203.97153 38.430918,274.3813 c -3.253303,20.92162 -3.264549,60.28311 -0.0232,81.22178 4.747139,30.66591 12.924742,56.77661 26.33267,84.07899 43.487742,88.55347 129.117712,147.08873 227.380372,155.43353 9.71469,0.825 39.05234,0.60712 48.80313,-0.36246 z"
+         style="fill:#1e9eff;fill-opacity:1;stroke:#1e9eff;stroke-width:1.02432775000000009;stroke-opacity:1" />
+      <path
+         transform="translate(96,326.36218)"
+         inkscape:connector-curvature="0"
+         id="path13584"
+         d="m 287.51128,450.33234 c -9.20847,-1.27511 -19.50895,-3.79831 -29.19334,-7.15122 -8.68995,-3.0086 -19.97439,-8.21666 -19.97439,-9.21868 0,-0.3296 4.26376,-3.07442 9.47503,-6.09959 36.28967,-21.06642 69.14244,-46.80272 99.62804,-78.04691 56.37988,-57.78278 81.43976,-110.16646 77.25639,-161.49219 -2.11,-25.88754 -11.38374,-48.06103 -26.97685,-64.50151 -14.60489,-15.39858 -32.60736,-25.179852 -55.41334,-30.107721 -9.59279,-2.07279 -38.10678,-1.779359 -48.14341,0.495433 -34.40754,7.798438 -66.19195,26.718698 -94.03303,55.974918 -61.99306,65.1441 -82.43198,154.12088 -52.51718,228.62312 5.83391,14.52923 15.58806,31.54563 24.32374,42.43347 3.78318,4.71522 6.55779,8.76145 6.16581,8.99163 -1.88699,1.10802 -29.82415,9.14461 -41.17366,11.84429 -13.10035,3.11614 -38.812063,7.75777 -39.34866,7.10345 C 94.508985,445.4282 85.898266,428.32507 79.353482,412.96543 59.776551,367.02128 54.746759,310.13177 65.820059,259.89553 74.502968,220.50377 94.661045,179.76729 120.86187,148.6642 c 27.28992,-32.39597 66.39302,-59.837427 106.33196,-74.620799 44.022,-16.294714 94.33533,-19.788334 141.23934,-9.807273 38.64375,8.223296 79.6708,28.321372 109.50848,53.645342 36.99027,31.39454 64.00158,71.19436 79.30321,116.84936 l 3.4326,10.2417 -5.64121,10.75702 c -29.20394,55.68797 -67.87007,103.19718 -114.70732,140.94125 -33.38873,26.90651 -68.66699,44.66197 -102.62559,51.65119 -12.15458,2.50161 -38.90622,3.57309 -50.19206,2.01035 z"
+         style="fill:#1e9eff;fill-opacity:1;stroke:#1e9eff;stroke-width:1.02432775000000009;stroke-opacity:1" />
+      <path
+         transform="translate(96,326.36218)"
+         inkscape:connector-curvature="0"
+         id="path13586"
+         d="m 205.4443,409.63637 c -16.68969,-17.16197 -26.89356,-34.99658 -33.13887,-57.92103 -11.24368,-41.2718 -5.35522,-87.33036 17.39037,-136.02454 21.12871,-45.23276 46.39326,-75.27545 77.32892,-91.95373 17.42412,-9.39383 30.47502,-12.70856 50.19207,-12.748 12.16974,-0.0243 14.92963,0.3069 23.00923,2.76157 17.66913,5.36809 30.61272,14.27397 41.20049,28.3481 32.14403,42.72852 22.46511,103.39567 -26.30019,164.84877 -33.24193,41.89082 -76.51857,76.61555 -127.1956,102.0604 -8.26227,4.14847 -15.18884,7.54267 -15.39239,7.54267 -0.20355,0 -3.39586,-3.1114 -7.09403,-6.91421 l 0,0 z"
+         style="fill:#1e9eff;fill-opacity:1;stroke:#1e9eff;stroke-width:1.02432775000000009;stroke-opacity:1" />
+      <path
+         transform="translate(96,326.36218)"
+         inkscape:connector-curvature="0"
+         id="path13588"
+         d="m 286.53883,570.04809 c -50.88733,-5.31382 -102.6056,-28.86652 -142.71422,-64.99262 -9.03301,-8.13609 -24.68554,-24.95555 -23.92858,-25.71251 0.22315,-0.22316 5.62412,-1.77484 12.00216,-3.44819 19.47581,-5.10969 44.10531,-13.46722 61.32021,-20.8078 l 8.65207,-3.68932 8.6498,5.7557 c 10.92175,7.26749 26.53996,14.72624 39.09088,18.66856 29.24187,9.18506 63.1077,10.10917 96.09885,2.62229 78.70775,-17.86162 163.90262,-91.67057 219.14718,-189.85916 l 3.12736,-5.55837 0.86452,6.07053 c 1.30024,9.13005 0.97135,46.79562 -0.50021,57.28693 -6.57196,46.85377 -23.13828,87.52488 -50.65713,124.36568 -9.41736,12.60748 -36.32693,39.52637 -48.87442,48.89137 -38.2086,28.51752 -81.32343,45.63855 -127.23236,50.52432 -11.67016,1.24198 -42.66103,1.17587 -55.04611,-0.11741 l 0,0 z"
+         style="fill:#1e9eff;fill-opacity:1;stroke:#1e9eff;stroke-width:1.02432775000000009;stroke-opacity:1" />
+    </g>
+  </g>
+</svg>
diff --git a/icons/svg/os_gummiboot.svg b/icons/svg/os_gummiboot.svg
new file mode 100644 (file)
index 0000000..80a3abc
--- /dev/null
@@ -0,0 +1,203 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="128"
+   height="128"
+   id="svg19221"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="os_gummiboot-01-basic.svg">
+  <defs
+     id="defs19223">
+    <inkscape:path-effect
+       effect="skeletal"
+       id="path-effect19257"
+       is_visible="true"
+       pattern="M 0,5 10,10 10,0 z"
+       copytype="single_stretched"
+       prop_scale="1"
+       scale_y_rel="false"
+       spacing="0"
+       normal_offset="0"
+       tang_offset="0"
+       prop_units="false"
+       vertical_pattern="false"
+       fuse_tolerance="0" />
+    <filter
+       id="filter19347"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood19349"
+         flood-opacity="0.65"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite19351"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur19353"
+         in="composite"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset19355"
+         dx="2"
+         dy="2"
+         result="offset" />
+      <feComposite
+         id="feComposite19357"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="3.8890873"
+     inkscape:cx="59.349784"
+     inkscape:cy="67.774903"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:document-units="px"
+     inkscape:grid-bbox="true"
+     inkscape:window-width="1093"
+     inkscape:window-height="861"
+     inkscape:window-x="246"
+     inkscape:window-y="45"
+     inkscape:window-maximized="0" />
+  <metadata
+     id="metadata19226">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     transform="translate(0,64)">
+    <g
+       id="g19315"
+       transform="matrix(1.2,0,0,1.2,-17.322915,5.7599999e-7)"
+       style="filter:url(#filter19347)">
+      <g
+         transform="matrix(0.54045343,0.84137393,-0.84137393,0.54045343,29.41098,-53.847932)"
+         id="g19311">
+        <rect
+           style="fill:#ff0000;fill-opacity:1;stroke:#ff0000;stroke-opacity:1"
+           id="rect19231"
+           width="96.166519"
+           height="57.854191"
+           x="15.91674"
+           y="-28.927095"
+           ry="23.655935" />
+        <rect
+           style="fill:#ff0000;fill-opacity:1;stroke:#000000;stroke-width:0.75067192;stroke-opacity:1"
+           id="rect19231-7"
+           width="74.816948"
+           height="41.904346"
+           x="26.591526"
+           y="-20.952173"
+           ry="17.13422" />
+      </g>
+      <g
+         transform="matrix(0.06205501,-0.99807273,0.99807273,0.06205501,122.12645,2.2880705)"
+         id="g19279">
+        <path
+           sodipodi:type="star"
+           style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-opacity:1"
+           id="path19259"
+           sodipodi:sides="3"
+           sodipodi:cx="62.996784"
+           sodipodi:cy="9.4631901"
+           sodipodi:r1="4.1140757"
+           sodipodi:r2="2.0570383"
+           sodipodi:arg1="-1.5707963"
+           sodipodi:arg2="-0.52359878"
+           inkscape:flatsided="false"
+           inkscape:rounded="0"
+           inkscape:randomized="0"
+           d="m 62.996784,5.3491144 1.781448,3.0855565 1.781446,3.0855571 -3.562894,0 -3.562894,0 1.781447,-3.0855571 z"
+           transform="matrix(0.99611394,0,0,1.0873392,-54.310432,-27.400102)"
+           inkscape:transform-center-y="-1.1183489" />
+        <rect
+           style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.3377991;stroke-opacity:1"
+           id="rect19261"
+           width="8.5378227"
+           height="5.4873924"
+           x="4.172637"
+           y="-15.159016"
+           ry="1.3157942" />
+        <rect
+           style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1.0407275;stroke-opacity:1"
+           id="rect19267"
+           width="0.45277908"
+           height="31.236288"
+           x="8.2636356"
+           y="-52.408901"
+           ry="0.24712254" />
+      </g>
+      <g
+         id="g19279-6"
+         transform="matrix(0.89800578,0.43998365,-0.43998365,0.89800578,20.695405,43.532597)">
+        <path
+           sodipodi:type="star"
+           style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-opacity:1"
+           id="path19259-0"
+           sodipodi:sides="3"
+           sodipodi:cx="62.996784"
+           sodipodi:cy="9.4631901"
+           sodipodi:r1="4.1140757"
+           sodipodi:r2="2.0570383"
+           sodipodi:arg1="-1.5707963"
+           sodipodi:arg2="-0.52359878"
+           inkscape:flatsided="false"
+           inkscape:rounded="0"
+           inkscape:randomized="0"
+           d="m 62.996784,5.3491144 1.781448,3.0855565 1.781446,3.0855571 -3.562894,0 -3.562894,0 1.781447,-3.0855571 z"
+           transform="matrix(0.99611394,0,0,1.0873392,-54.310432,-27.400102)"
+           inkscape:transform-center-y="-1.1183489" />
+        <rect
+           style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.3377991;stroke-opacity:1"
+           id="rect19261-9"
+           width="8.5378227"
+           height="5.4873924"
+           x="4.172637"
+           y="-15.159016"
+           ry="1.3157942" />
+        <rect
+           style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1.0407275;stroke-opacity:1"
+           id="rect19267-4"
+           width="0.45277908"
+           height="31.236288"
+           x="8.2636356"
+           y="-52.408901"
+           ry="0.24712254" />
+      </g>
+    </g>
+  </g>
+</svg>
diff --git a/icons/svg/os_haiku.svg b/icons/svg/os_haiku.svg
new file mode 100644 (file)
index 0000000..e36dded
--- /dev/null
@@ -0,0 +1,169 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="128"
+   height="128"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="os_haiku-01-basic.svg">
+  <defs
+     id="defs4">
+    <filter
+       id="filter5665"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood5667"
+         flood-opacity="0.7"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite5669"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur5671"
+         in="composite"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset5673"
+         dx="3"
+         dy="3"
+         result="offset" />
+      <feComposite
+         id="feComposite5675"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="3.959798"
+     inkscape:cx="58.819443"
+     inkscape:cy="72.789643"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:window-width="1046"
+     inkscape:window-height="839"
+     inkscape:window-x="385"
+     inkscape:window-y="93"
+     inkscape:window-maximized="0" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(0,-924.36218)">
+    <g
+       id="g5651"
+       style="filter:url(#filter5665)">
+      <rect
+         ry="0"
+         y="934.38153"
+         x="18.497774"
+         height="107.96134"
+         width="18.56284"
+         id="rect3013"
+         style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:2.13513446;stroke-opacity:1" />
+      <rect
+         ry="0"
+         y="934.38153"
+         x="90.449203"
+         height="107.96134"
+         width="18.56284"
+         id="rect3013-8"
+         style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:2.13513446;stroke-opacity:1" />
+      <g
+         id="g5595"
+         transform="matrix(1.5227283,0,0,1.4525208,-36.649015,996.88746)">
+        <path
+           style="fill:#008000;fill-opacity:1;stroke:#00ff00;stroke-width:0.18181819;stroke-opacity:1"
+           d="M 59.061107,5.390994 C 56.032698,5.04526 52.779267,3.974574 48.954696,2.065031 c -1.6,-0.798851 -3.236364,-1.640695 -3.636364,-1.870762 -0.4,-0.230068 -1.35219,-0.765373 -2.115977,-1.189566 -1.343771,-0.746307 -4.480725,-3.072643 -6.825044,-5.061392 -0.627174,-0.532048 -1.490197,-1.145274 -1.917829,-1.362724 -0.427632,-0.217451 -1.227513,-0.694631 -1.777513,-1.060401 -0.996154,-0.662478 -2.73167,-1.396504 -4.44841,-1.881428 l -0.902954,-0.255056 1.551288,-0.125871 c 0.858283,-0.06964 2.480011,-0.03535 3.630228,0.07676 1.321809,0.128836 2.514687,0.144118 3.275425,0.04196 1.1718,-0.157358 2.16715,-0.0093 2.16715,0.322391 0,0.08773 0.593182,0.60444 1.318182,1.148243 1.848965,1.386859 2.300325,1.858668 2.698216,2.820463 0.951305,2.299519 2.466262,5.277485 2.68921,5.286207 0.457696,0.01791 0.09994,-1.079084 -1.269142,-3.891595 -1.431701,-2.941144 -1.984086,-3.680898 -3.554633,-4.760365 l -1.021152,-0.701857 1.796933,-0.115007 c 2.696728,-0.172597 6.437152,-0.169271 7.193193,0.0064 1.19474,0.277598 3.387782,1.82652 4.717097,3.331633 1.423705,1.611989 2.216354,3.062064 2.692485,4.925646 0.183504,0.718232 0.496826,1.678018 0.696271,2.132856 0.199444,0.454838 0.419911,1.166038 0.489924,1.580442 0.142463,0.843231 0.541825,1.313262 0.852149,1.002938 0.204023,-0.204024 0.143569,-0.450404 -0.702953,-2.864904 -0.24542,-0.7 -0.601122,-1.873234 -0.790451,-2.607188 -0.189329,-0.733955 -0.646358,-1.831813 -1.015622,-2.439687 -1.023183,-1.684341 -2.854872,-3.677022 -4.068551,-4.426147 -0.596636,-0.368265 -1.084792,-0.705573 -1.084792,-0.749573 0,-0.044 0.838636,-0.06202 1.863636,-0.04006 1.025,0.02197 5.177273,-0.05609 9.227273,-0.173473 12.409778,-0.359667 20.650645,-0.07672 22.306218,0.765887 0.28158,0.143309 1.534691,0.476889 2.784691,0.741288 1.804682,0.381724 2.918631,0.495887 5.409091,0.55435 2.963467,0.06957 3.136363,0.05497 3.136363,-0.264746 0,-0.411604 -0.50965,-0.490386 -4,-0.618318 -2.136743,-0.07832 -5.258878,-0.576972 -5.571812,-0.889906 -0.04949,-0.04949 0.678087,-0.453814 1.616832,-0.898502 1.593913,-0.755044 5.779899,-3.341728 6.009775,-3.713674 0.05667,-0.09169 0.0337,-0.278894 -0.05105,-0.416012 -0.128726,-0.208283 -0.28894,-0.197801 -0.973682,0.0637 -0.450782,0.172155 -0.924773,0.439732 -1.053316,0.594617 -0.559493,0.674149 -4.095057,2.622234 -6.18786,3.409494 -0.946722,0.356133 -1.172633,0.372208 -2.816026,0.200381 -1.508634,-0.157737 -1.796809,-0.239142 -1.851478,-0.523018 -0.05817,-0.302075 -0.196816,-0.325265 -1.365793,-0.22845 -0.715574,0.05926 -2.814681,0.15555 -4.664681,0.213968 l -3.363637,0.106214 1.363637,-0.610257 c 3.210724,-1.436862 10.854088,-6.193882 11.845855,-7.37253 l 0.479833,-0.57025 1.428065,0.549318 c 3.455257,1.329095 8.889478,4.386869 11.207651,6.306415 3.437927,2.846752 4.091155,3.339032 5.201935,3.920232 0.66016,0.345424 1.97757,0.893615 2.92757,1.218204 0.95,0.324588 1.79369,0.648054 1.87487,0.718814 0.0812,0.07076 -0.57336,0.352386 -1.45454,0.625838 -2.45482,0.761791 -2.95591,0.961494 -4.32942,1.725453 -2.565695,1.42706 -5.666586,2.979405 -6.818182,3.413268 -0.65,0.244888 -2,0.801149 -3,1.236139 -1.696535,0.737974 -3.754109,1.497516 -9.363636,3.45653 C 78.61888,3.85284 74.121174,4.828149 70.146934,5.320549 66.64338,5.754631 62.478156,5.7811 59.061107,5.390999 l 0,0 z M 74.406696,0.736405 c -0.06488,-0.225 -0.499936,-0.963793 -0.966798,-1.641762 -0.46686,-0.677969 -1.356456,-2.027969 -1.976878,-3 -1.752188,-2.745198 -2.486298,-3.474953 -5.049958,-5.019986 -2.360724,-1.42273 -2.824197,-1.620138 -2.951402,-1.257102 -0.09582,0.273466 1.048154,1.110739 3.015351,2.206928 1.781698,0.992824 2.774507,2.014505 4.202794,4.325016 2.185398,3.535275 4.147171,5.844468 3.726891,4.386906 l 0,0 z m 13.002546,-1.311627 c 0,-1.112724 -1.564031,-4.26759 -3.224931,-6.505129 -1.707469,-2.300277 -2.432724,-3.04688 -2.959757,-3.04688 -0.516014,0 -0.460634,0.623401 0.07715,0.868431 0.240853,0.10974 0.704913,0.593328 1.031244,1.074639 0.326331,0.481312 0.908284,1.25673 1.293231,1.723153 0.98068,1.188247 1.853542,2.686741 2.510338,4.309648 0.308898,0.763271 0.638056,1.571856 0.731464,1.796856 0.253694,0.611105 0.541262,0.49384 0.541262,-0.220718 z m -46.074837,-9.505634 c -0.198618,-0.198618 -0.334814,0.117247 -0.192214,0.445783 0.135213,0.311521 0.145015,0.311237 0.220352,-0.0064 0.04336,-0.182827 0.0307,-0.380554 -0.02814,-0.439394 l 0,0 z"
+           id="path4170"
+           inkscape:connector-curvature="0" />
+        <path
+           style="fill:#008000;fill-opacity:1;stroke:#00ff00;stroke-width:0.18181819;stroke-opacity:1"
+           d="m 41.59106,-11.84972 c 0.65,-0.227648 1.662453,-0.628671 2.249896,-0.891163 0.587443,-0.262491 1.144432,-0.477257 1.237754,-0.477257 0.497801,0 5.540233,-2.320874 6.819612,-3.138855 3.51424,-2.246854 6.428603,-4.377528 6.5277,-4.772363 0.0851,-0.339073 0.331296,-0.454774 1.497081,-0.703569 2.709028,-0.578143 7.240819,-1.205369 9.486139,-1.312936 3.457158,-0.165623 8.480292,0.639879 12.046936,1.931827 l 1.592389,0.576812 -0.865116,0.687804 c -1.202948,0.956392 -4.642651,3.217234 -7.13312,4.688444 -1.754971,1.036726 -5.698313,2.942432 -6.641089,3.209452 -0.687202,0.194635 -2.538522,0.273313 -7.58498,0.322347 l -6.67589,0.06487 2.145691,-1.095097 c 2.242491,-1.144501 3.108279,-1.736851 6.115179,-4.183851 1,-0.813795 2.227272,-1.754891 2.727272,-2.091324 0.5,-0.336433 1.448269,-1.067638 2.107264,-1.6249 0.658994,-0.557262 1.43578,-1.185307 1.726191,-1.395654 0.457165,-0.331132 0.495213,-0.421978 0.283538,-0.67703 -0.220265,-0.265403 -0.29688,-0.267482 -0.77354,-0.02099 -0.290984,0.150473 -1.080482,0.744098 -1.754438,1.319167 -0.673958,0.575068 -1.839015,1.486999 -2.589015,2.026513 -0.75,0.539513 -2.018182,1.523536 -2.818182,2.186716 -2.155045,1.78648 -3.309515,2.609881 -4.727272,3.371627 -0.7,0.376103 -1.354546,0.746625 -1.454546,0.823383 -0.1,0.07676 -0.877272,0.448571 -1.727272,0.82625 l -1.545455,0.686689 -5.727273,0.0385 -5.727272,0.0385 1.181818,-0.413905 z"
+           id="path4172"
+           inkscape:connector-curvature="0" />
+        <path
+           style="fill:#008000;fill-opacity:1;stroke:#00ff00;stroke-width:0.18181819;stroke-opacity:1"
+           d="m 33.045605,-12.097808 c 0.65,-0.283815 1.960732,-1.005365 2.912737,-1.603447 0.952006,-0.598081 2.22897,-1.340511 2.837698,-1.649845 1.648048,-0.837477 6.539528,-2.524729 9.431383,-3.25323 1.4,-0.352681 3.922829,-1.050875 5.606286,-1.551542 1.683458,-0.500667 3.099238,-0.871897 3.146178,-0.824955 0.04694,0.04694 -0.512251,0.48015 -1.242649,0.962687 -0.730398,0.482537 -1.87362,1.264074 -2.540493,1.736749 -2.823289,2.001124 -6.379281,3.664004 -12.311293,5.7571 l -2.47621,0.873725 -3.272728,0.03439 -3.272727,0.03439 1.181818,-0.516025 z"
+           id="path4174"
+           inkscape:connector-curvature="0" />
+        <rect
+           style="fill:#00ff00;fill-opacity:1;stroke:#00ff00;stroke-width:0.08757018;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+           id="rect5503"
+           width="1.6991364"
+           height="0.2251936"
+           x="62.280296"
+           y="-5.7272224"
+           transform="matrix(0.96515405,-0.26168235,0.56031449,0.82827995,0,0)" />
+        <rect
+           style="fill:#00ff00;fill-opacity:1;stroke:#00ff00;stroke-width:0.06770154;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+           id="rect5505"
+           width="2.414537"
+           height="0.12001605"
+           x="31.512844"
+           y="1.2065728"
+           transform="matrix(0.92723443,-0.3744814,0.63994083,0.76842419,0,0)"
+           inkscape:transform-center-x="0.15096165"
+           inkscape:transform-center-y="-0.17817299" />
+        <rect
+           style="fill:#00ff00;fill-opacity:1;stroke:#00ff00;stroke-width:0.1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+           id="rect5507"
+           width="2.4772727"
+           height="0.13636364"
+           x="68.015884"
+           y="-50.667591"
+           transform="matrix(0.92504555,0.3798562,-0.3798562,0.92504555,0,0)" />
+        <path
+           style="fill:#00ff00;fill-opacity:1;stroke:#00ff00;stroke-width:0.00909091;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+           d="m 56.823725,2.178412 c -0.08288,-0.126493 -0.230548,-0.541705 -0.328148,-0.922695 -0.0976,-0.380989 -0.336518,-1.128899 -0.530928,-1.662021 -0.194411,-0.533122 -0.516852,-1.506514 -0.716536,-2.163093 -0.522149,-1.71687 -1.126028,-2.86106 -2.211731,-4.19065 -0.995737,-1.219412 -2.310157,-2.364181 -3.632188,-3.163384 -1.163956,-0.703641 -1.48942,-0.780821 -3.532272,-0.837637 -1.665786,-0.04633 -6.043356,0.101428 -6.981719,0.235656 l -0.425126,0.06081 0.998877,0.694997 c 1.111434,0.773312 1.952985,1.58766 2.442332,2.363383 0.830283,1.316181 2.625994,5.165336 2.739756,5.872738 l 0.05463,0.339684 -0.234536,-0.363636 c -0.370237,-0.574032 -1.339802,-2.512678 -1.989946,-3.978897 -0.860852,-1.941411 -0.888766,-1.974578 -3.213066,-3.817596 -0.60984,-0.483564 -1.151572,-0.959125 -1.203847,-1.056804 -0.17358,-0.324335 -0.611404,-0.382886 -2.654665,-0.355011 -1.067978,0.01457 -2.595832,-0.009 -3.395232,-0.05228 l -1.453453,-0.07877 0.675404,-0.268018 0.675405,-0.268019 3.278049,-0.05013 3.278049,-0.05013 1.181818,-0.408246 c 5.064949,-1.749634 8.948521,-3.394726 11.552352,-4.893608 0.784148,-0.451391 4.018752,-2.615749 5.356739,-3.584335 0.25,-0.180978 0.638636,-0.380754 0.863636,-0.443946 0.225,-0.06319 0.490588,-0.138643 0.590197,-0.167667 0.162505,-0.04735 0.16773,-0.03666 0.05087,0.104153 -0.348695,0.420152 -3.049181,2.368433 -5.363157,3.869281 -1.811101,1.174683 -6.023405,3.228747 -7.516952,3.665524 -0.256474,0.075 -1.279201,0.463218 -2.272728,0.862696 -0.993526,0.399479 -1.980274,0.777805 -2.192774,0.840725 -0.2125,0.06292 -0.386364,0.170716 -0.386364,0.239546 0,0.105223 0.929772,0.121022 5.840909,0.09925 l 5.840909,-0.0259 1.494316,-0.703777 c 3.000254,-1.41303 4.767103,-2.521937 7.505684,-4.710706 0.95,-0.759273 2.361364,-1.859666 3.136364,-2.445318 0.775,-0.585652 1.997561,-1.53925 2.716803,-2.119107 1.533343,-1.236192 2.012962,-1.525825 2.229333,-1.346253 0.07963,0.06608 0.144773,0.148982 0.144773,0.184221 0,0.08762 -3.157774,2.614189 -4.5,3.600493 -0.6,0.440897 -1.786364,1.358591 -2.636364,2.039321 -2.88965,2.314202 -3.713898,2.864982 -6.261222,4.183887 -0.981328,0.508093 -1.784232,0.958776 -1.784232,1.00152 0,0.04274 0.03916,0.101916 0.08702,0.131494 0.136939,0.08463 12.212196,-0.125558 13.276621,-0.231102 1.183466,-0.117348 1.817848,-0.357088 4.681818,-1.769304 3.011445,-1.484935 7.23438,-4.080244 9.930197,-6.102847 0.880213,-0.660402 1.046415,-0.752564 1.204545,-0.667936 0.100892,0.054 0.18344,0.132046 0.18344,0.173445 0,0.0414 -0.194318,0.256349 -0.431818,0.477668 -1.627329,1.516456 -7.318146,5.056694 -11.134161,6.926525 -1.073319,0.525921 -1.885109,0.976881 -1.886363,1.047901 -0.0024,0.137874 0.303646,0.131101 6.129563,-0.135637 2.915009,-0.133463 3.092693,-0.132581 3.201267,0.0159 0.06323,0.08647 0.127877,0.195973 0.143669,0.243351 0.09311,0.279338 3.065143,0.618265 3.883162,0.442832 1.420985,-0.304747 5.651842,-2.469773 6.958318,-3.56073 0.479673,-0.400546 1.256855,-0.789926 1.661331,-0.832353 0.299688,-0.03144 0.38919,0.244001 0.142111,0.437337 -0.969346,0.758498 -3.687131,2.405136 -5.803442,3.516159 -0.9,0.472483 -1.648779,0.922003 -1.663951,0.998934 -0.07901,0.400601 2.723189,0.889344 6.118496,1.067153 2.921607,0.153001 3.544989,0.252581 3.368532,0.538095 -0.142428,0.230454 -5.137873,0.04073 -7.038758,-0.267323 -1.298976,-0.210511 -3.390354,-0.716782 -4.073767,-0.986157 -1.097964,-0.432777 -3.674254,-0.690883 -8.346916,-0.836235 -3.445943,-0.107191 -6.848791,-0.07583 -16,0.147441 -2.95,0.07198 -6.253409,0.131123 -7.340909,0.131439 -1.0875,2.72e-4 -1.977273,0.03379 -1.977273,0.07439 0,0.08471 0.323772,0.332272 1.227273,0.938405 0.853901,0.572859 1.612925,1.273698 2.474383,2.284702 1.449081,1.700639 2.142621,2.939272 2.658818,4.748535 0.15692,0.55 0.547454,1.797727 0.867855,2.772727 0.320402,0.975 0.594419,1.891164 0.608928,2.035919 0.03433,0.342555 -0.148556,0.401197 -0.339999,0.109019 l 0,0 z"
+           id="path5519"
+           inkscape:connector-curvature="0" />
+        <path
+           style="fill:#00ff00;fill-opacity:1;stroke:#00ff00;stroke-width:0.00909091;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+           d="m 73.464083,0.105697 c -0.335165,-0.410279 -1.336375,-1.832378 -2.224911,-3.160223 -0.888536,-1.327845 -1.849176,-2.687972 -2.134754,-3.022505 -0.630321,-0.738371 -1.481224,-1.393255 -2.86886,-2.207974 -1.187547,-0.697241 -2.266903,-1.423952 -2.503902,-1.685833 -0.555526,-0.613849 1.358377,0.346641 3.566494,1.789841 1.767488,1.15521 2.311649,1.770133 4.564597,5.158178 1.675948,2.520336 2.372811,3.64398 2.372811,3.825998 0,0.170471 -0.238784,-0.04541 -0.771475,-0.697482 z"
+           id="path5521"
+           inkscape:connector-curvature="0" />
+        <path
+           style="fill:#00ff00;fill-opacity:1;stroke:#00ff00;stroke-width:0.00909091;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+           d="m 86.92808,-0.648344 c -0.141277,-0.3 -0.377098,-0.847527 -0.524047,-1.216727 -0.410225,-1.030658 -1.048036,-2.300017 -1.570891,-3.126358 -0.821394,-1.298162 -3.015115,-4.108259 -3.412365,-4.371147 -0.377106,-0.249557 -0.505424,-0.60395 -0.218677,-0.60395 0.429317,0 1.216467,0.789282 2.536268,2.543137 0.931619,1.238009 1.613551,2.329769 2.393141,3.831373 0.778218,1.498962 1.124737,2.478754 1.08347,3.063544 l -0.03003,0.425582 -0.256866,-0.545454 0,0 z"
+           id="path5523"
+           inkscape:connector-curvature="0" />
+      </g>
+    </g>
+  </g>
+</svg>
diff --git a/icons/svg/os_legacy.svg b/icons/svg/os_legacy.svg
new file mode 100644 (file)
index 0000000..6b6019a
--- /dev/null
@@ -0,0 +1,137 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="118"
+   height="118"
+   id="svg9364"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="os_legacy-03-color.svg">
+  <defs
+     id="defs9366">
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="0 : 64 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="104.75 : 54 : 1"
+       inkscape:persp3d-origin="64 : 42.666667 : 1"
+       id="perspective9372" />
+    <filter
+       id="filter3667"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood3669"
+         flood-opacity="0.7"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite3671"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur3673"
+         in="composite"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset3675"
+         dx="3"
+         dy="3"
+         result="offset" />
+      <feComposite
+         id="feComposite3677"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="5.6568542"
+     inkscape:cx="85.868388"
+     inkscape:cy="65.110614"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:document-units="px"
+     inkscape:grid-bbox="true"
+     inkscape:window-width="1112"
+     inkscape:window-height="983"
+     inkscape:window-x="127"
+     inkscape:window-y="0"
+     inkscape:window-maximized="0" />
+  <metadata
+     id="metadata9369">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     transform="translate(0,54)">
+    <g
+       id="g3661"
+       style="filter:url(#filter3667)">
+      <rect
+         inkscape:transform-center-x="27.5"
+         transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,0,0)"
+         y="-35.485481"
+         x="47.871014"
+         height="34.010544"
+         width="34.010544"
+         id="rect9388"
+         style="fill:#e6e6e6;fill-opacity:1;stroke:#e6e6e6;stroke-width:0.98945653000000000" />
+      <rect
+         inkscape:transform-center-x="27.5"
+         transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,0,0)"
+         y="-35.640812"
+         x="8.5925779"
+         height="34.010544"
+         width="34.010544"
+         id="rect9388-5"
+         style="fill:#999999;fill-opacity:1;stroke:#999999;stroke-width:0.98945653000000000" />
+      <rect
+         inkscape:transform-center-x="27.5"
+         transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,0,0)"
+         y="-74.810493"
+         x="8.5460062"
+         height="34.010544"
+         width="34.010544"
+         id="rect9388-1"
+         style="fill:#f2f2f2;fill-opacity:1;stroke:#f2f2f2;stroke-width:0.98945653000000000" />
+      <rect
+         inkscape:transform-center-x="27.5"
+         transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,0,0)"
+         y="-74.565689"
+         x="48.078125"
+         height="34.010544"
+         width="34.010544"
+         id="rect9388-4"
+         style="fill:#cccccc;fill-opacity:1;stroke:#cccccc;stroke-width:0.98945653000000000" />
+    </g>
+  </g>
+</svg>
diff --git a/icons/svg/os_mac.svg b/icons/svg/os_mac.svg
new file mode 100644 (file)
index 0000000..9ab3163
--- /dev/null
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="128"
+   height="128"
+   id="svg9329"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="os_mac.svg">
+  <defs
+     id="defs9331">
+    <filter
+       id="filter14665"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood14667"
+         flood-opacity="0.7"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite14669"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur14671"
+         in="composite"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset14673"
+         dx="3"
+         dy="3"
+         result="offset" />
+      <feComposite
+         id="feComposite14675"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="3.0989011"
+     inkscape:cx="45.916284"
+     inkscape:cy="64.4846"
+     inkscape:current-layer="layer1"
+     inkscape:document-units="px"
+     showgrid="false"
+     inkscape:snap-bbox="false"
+     inkscape:snap-bbox-edge-midpoints="false"
+     inkscape:bbox-nodes="false"
+     inkscape:window-width="1033"
+     inkscape:window-height="757"
+     inkscape:window-x="280"
+     inkscape:window-y="48"
+     inkscape:window-maximized="0" />
+  <metadata
+     id="metadata9334">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="X"
+     inkscape:groupmode="layer"
+     transform="translate(0,-352)">
+    <path
+       style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.32269504999999998;stroke-opacity:1;filter:url(#filter14665)"
+       d="M 55.535861,474.28314 C 31.903163,470.59273 13.250678,453.88702 7.1077726,430.90953 c -2.449046,-9.16065 -2.522865,-19.84749 -0.20101,-29.10065 4.7850114,-19.06943 19.1707534,-34.83217 37.7295884,-41.34105 10.5402,-3.69661 22.66072,-4.23179 33.72163,-1.48896 20.74249,5.1436 37.485929,21.9257 42.731359,42.83001 2.31728,9.23492 2.25409,19.96009 -0.1711,29.04064 -2.68918,10.06898 -7.44561,18.51511 -14.63835,25.99377 -9.141009,9.50437 -20.770919,15.44953 -34.154779,17.45975 -4.03276,0.60571 -12.64912,0.59537 -16.58925,-0.0199 l 0,10e-6 z m -2.61067,-31.91794 c 5.75541,-10.29397 10.65007,-19.0591 10.87702,-19.47807 0.38653,-0.71357 1.08731,0.47052 11.07691,18.71631 l 10.66428,19.47807 5.52343,0.0883 c 3.03788,0.0486 5.52342,-0.004 5.52342,-0.11631 0,-0.11253 -5.96131,-10.77421 -13.24737,-23.69262 l -13.24736,-23.48804 12.16117,-21.25027 c 6.68864,-11.68765 12.22289,-21.35919 12.29833,-21.4923 0.0754,-0.13311 -2.37634,-0.24122 -5.44838,-0.24024 l -5.58554,0.002 -9.5195,17.41583 c -5.23573,9.57872 -9.59927,17.41941 -9.69677,17.42376 -0.0975,0.004 -4.59909,-7.82862 -10.00355,-17.4066 l -9.82628,-17.41452 -5.56648,-0.011 c -3.06157,-0.006 -5.566495,0.0419 -5.566495,0.10654 0,0.0646 5.245075,9.10414 11.655715,20.08776 6.41064,10.98362 12.0743,20.70866 12.58591,21.61121 l 0.93019,1.64096 -13.43088,23.04518 c -7.38699,12.67485 -13.503164,23.2302 -13.591505,23.45633 -0.12713,0.32542 0.999733,0.39271 5.404365,0.32269 l 5.56498,-0.0885 10.46439,-18.71631 0,0 z"
+       id="path14663"
+       inkscape:connector-curvature="0" />
+  </g>
+</svg>
diff --git a/icons/svg/os_netbsd.svg b/icons/svg/os_netbsd.svg
new file mode 100644 (file)
index 0000000..3a7fbbc
--- /dev/null
@@ -0,0 +1,424 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="128"
+   height="128"
+   id="svg17054"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="os_netbsd-01-basic.svg">
+  <defs
+     id="defs17056">
+    <filter
+       id="filter17303"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood17305"
+         flood-opacity="0.65"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite17307"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur17309"
+         in="composite"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset17311"
+         dx="2"
+         dy="2"
+         result="offset" />
+      <feComposite
+         id="feComposite17313"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+    <filter
+       id="filter17315"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood17317"
+         flood-opacity="0.65"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite17319"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur17321"
+         in="composite"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset17323"
+         dx="2"
+         dy="2"
+         result="offset" />
+      <feComposite
+         id="feComposite17325"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+    <filter
+       id="filter17327"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood17329"
+         flood-opacity="0.65"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite17331"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur17333"
+         in="composite"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset17335"
+         dx="2"
+         dy="2"
+         result="offset" />
+      <feComposite
+         id="feComposite17337"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+    <filter
+       id="filter17339"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood17341"
+         flood-opacity="0.65"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite17343"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur17345"
+         in="composite"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset17347"
+         dx="2"
+         dy="2"
+         result="offset" />
+      <feComposite
+         id="feComposite17349"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+    <filter
+       id="filter17351"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood17353"
+         flood-opacity="0.65"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite17355"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur17357"
+         in="composite"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset17359"
+         dx="2"
+         dy="2"
+         result="offset" />
+      <feComposite
+         id="feComposite17361"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+    <filter
+       id="filter17363"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood17365"
+         flood-opacity="0.65"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite17367"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur17369"
+         in="composite"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset17371"
+         dx="2"
+         dy="2"
+         result="offset" />
+      <feComposite
+         id="feComposite17373"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+    <filter
+       id="filter17375"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood17377"
+         flood-opacity="0.65"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite17379"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur17381"
+         in="composite"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset17383"
+         dx="2"
+         dy="2"
+         result="offset" />
+      <feComposite
+         id="feComposite17385"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+    <filter
+       id="filter17387"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood17389"
+         flood-opacity="0.65"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite17391"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur17393"
+         in="composite"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset17395"
+         dx="2"
+         dy="2"
+         result="offset" />
+      <feComposite
+         id="feComposite17397"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+    <filter
+       id="filter17399"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood17401"
+         flood-opacity="0.65"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite17403"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur17405"
+         in="composite"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset17407"
+         dx="2"
+         dy="2"
+         result="offset" />
+      <feComposite
+         id="feComposite17409"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="3.8890873"
+     inkscape:cx="51.996"
+     inkscape:cy="61.59099"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:document-units="px"
+     inkscape:grid-bbox="true"
+     inkscape:window-width="1072"
+     inkscape:window-height="885"
+     inkscape:window-x="254"
+     inkscape:window-y="60"
+     inkscape:window-maximized="0" />
+  <metadata
+     id="metadata17059">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     transform="translate(0,64)">
+    <g
+       id="g17089"
+       transform="matrix(0.94150529,0,0,0.6223427,0.54982068,-21.484283)"
+       style="fill:#ff7f2a;filter:url(#filter17303)">
+      <path
+         sodipodi:nodetypes="czzcccaac"
+         inkscape:connector-curvature="0"
+         id="path17068"
+         d="m 58.362114,23.790621 c 0,0 -9.264427,8.564373 -14.47042,5.89488 -5.205993,-2.669494 -14.699991,9.894845 -18.726862,17.008461 -4.026871,7.113616 -9.173076,9.129031 -9.173076,9.129031 L 12.888151,31.067613 9.8994942,7.611697 c 0,0 5.9918358,7.235141 9.2880248,8.089462 7.657201,1.984628 15.253305,-9.4882938 22.897676,-7.2651745 5.830916,1.6957345 16.276919,15.3546365 16.276919,15.3546365 z"
+         inkscape:transform-center-x="-14.810821"
+         style="fill:#ff7f2a;fill-opacity:1;stroke:#ff7f2a;stroke-opacity:1"
+         transform="matrix(2.2369155,0,0,0.98936915,-12.001007,-63.675251)" />
+      <path
+         sodipodi:nodetypes="czzcccaac"
+         inkscape:connector-curvature="0"
+         id="path17068-9"
+         d="m 117.79667,-16.481994 c 0,0 -19.231387,7.2235816 -30.038153,4.972009 C 76.951754,-13.761557 57.243814,-3.1642213 48.884709,2.8357258 40.525604,8.8356732 29.84295,10.535565 29.84295,10.535565 l -6.442561,-20.879813 -6.203948,-19.783787 c 0,0 12.438042,6.102448 19.280374,6.823021 15.895058,1.673925 31.66329,-8.002859 47.531714,-6.127779 12.103997,1.43026 33.788141,12.950799 33.788141,12.950799 z"
+         inkscape:transform-center-x="-13.744268"
+         style="fill:#ff7f2a;fill-opacity:1;stroke:#ff7f2a;stroke-width:1.32319713000000005;stroke-opacity:1" />
+    </g>
+    <path
+       sodipodi:type="star"
+       style="fill:#999999;fill-opacity:1;stroke:#c8b7b7;stroke-opacity:1;filter:url(#filter17315)"
+       id="path17095"
+       sodipodi:sides="3"
+       sodipodi:cx="63.253918"
+       sodipodi:cy="74.517014"
+       sodipodi:r1="37.351135"
+       sodipodi:r2="18.67557"
+       sodipodi:arg1="0.53451638"
+       sodipodi:arg2="1.5817139"
+       inkscape:flatsided="false"
+       inkscape:rounded="0"
+       inkscape:randomized="0"
+       d="M 95.395134,93.544613 63.05003,93.19147 30.704925,92.838323 47.183308,65.003213 63.661695,37.168104 79.528415,65.356357 z"
+       transform="matrix(0.0807727,-0.04390913,0.29623078,0.78830475,-8.6315177,-83.602242)"
+       inkscape:transform-center-x="1.3991322"
+       inkscape:transform-center-y="-6.7941246" />
+    <path
+       inkscape:connector-curvature="0"
+       id="path17108"
+       style="font-size:36px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#ff7f2a;fill-opacity:1;stroke:none;font-family:FreeSerif;-inkscape-font-specification:FreeSerif;filter:url(#filter17327)"
+       d="m 30.591067,-8.5169089 c -0.672025,0.072023 -1.176024,0.156023 -1.512,0.252 -0.312024,0.072023 -0.648024,0.2520227 -1.008,0.54 -0.336023,0.2880221 -0.576023,0.7440216 -0.72,1.368 -0.120022,0.6000204 -0.180022,1.4160196 -0.18,2.448 l 0,18.9359999 -0.612,0 -15.912,-19.7999999 0,14.112 c -6e-6,1.8240039 0.215994,3.0360019 0.648,3.6359999 0.431993,0.576001 1.343992,0.900001 2.736,0.972 l 0,0.684 -8.4600001,0 0,-0.684 c 1.487998,-0.096 2.435997,-0.419999 2.844,-0.972 0.4319962,-0.575998 0.647996,-1.787996 0.648,-3.6359999 l 0,-15.876 c -0.7200033,-0.839978 -1.2960027,-1.3799774 -1.728,-1.62 -0.4080019,-0.239977 -0.9960013,-0.3599768 -1.764,-0.36 l 0,-0.684 6.1560001,0 13.86,17.424 0,-12.132 c -2.1e-5,-1.8239796 -0.22802,-3.0119784 -0.684,-3.564 -0.43202,-0.5759773 -1.356019,-0.923977 -2.772,-1.044 l 0,-0.684 8.46,0 0,0.684" />
+    <path
+       inkscape:connector-curvature="0"
+       id="path17110"
+       style="font-size:36px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#ff7f2a;fill-opacity:1;stroke:none;font-family:FreeSerif;-inkscape-font-specification:FreeSerif;filter:url(#filter17339)"
+       d="m 34.609004,4.6590911 c 0.048,1.5120085 0.251997,2.8200072 0.612,3.924 0.359996,1.080005 0.827995,1.8960039 1.404,2.4479999 0.575994,0.528003 1.151994,0.912003 1.728,1.152 0.599993,0.216002 1.223992,0.324002 1.872,0.324 1.15199,2e-6 2.147989,-0.287997 2.988,-0.864 0.863987,-0.575996 1.727987,-1.547995 2.592,-2.9159999 l 0.576,0.252 c -0.744014,1.9440039 -1.776013,3.4320019 -3.096,4.4639999 -1.32001,1.032 -2.832009,1.548 -4.536,1.548 -2.064005,0 -3.708004,-0.72 -4.932,-2.16 -1.200001,-1.463997 -1.800001,-3.4319947 -1.8,-5.9039999 -10e-7,-2.6639896 0.695999,-4.7999875 2.088,-6.40799998 1.415996,-1.63198422 3.227994,-2.44798342 5.436,-2.44800002 1.82399,1.66e-5 3.239989,0.552016 4.248,1.65600002 1.007987,1.08001382 1.643986,2.72401218 1.908,4.93199998 l -11.088,0 m 0.072,-1.152 7.344,0 c -0.24001,-1.5599873 -0.61201,-2.63998622 -1.116,-3.23999998 -0.504009,-0.59998504 -1.308008,-0.89998474 -2.412,-0.9 -2.160005,1.526e-5 -3.432004,1.38001388 -3.816,4.13999998" />
+    <path
+       inkscape:connector-curvature="0"
+       id="path17112"
+       style="font-size:36px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#ff7f2a;fill-opacity:1;stroke:none;font-family:FreeSerif;-inkscape-font-specification:FreeSerif;filter:url(#filter17351)"
+       d="m 56.050379,-1.5689089 0,1.15200002 -3.636,0 0,10.29599998 c -5e-6,1.1280039 0.143995,1.9560029 0.432,2.4839999 0.287994,0.504002 0.767994,0.756002 1.44,0.756 0.743992,2e-6 1.463991,-0.419998 2.16,-1.26 l 0.468,0.396 c -1.152009,1.824001 -2.592007,2.736 -4.32,2.736 -2.136003,0 -3.204002,-1.523999 -3.204,-4.572 l 0,-10.83599988 -1.908,0 c -0.096,-0.0719849 -0.144,-0.1559848 -0.144,-0.252 0,-0.11998458 0.036,-0.21598449 0.108,-0.288 0.072,-0.0719843 0.203999,-0.16798422 0.396,-0.28800002 0.215999,-0.143984 0.467999,-0.3239838 0.756,-0.54 0.287998,-0.2399833 0.683998,-0.6599829 1.188,-1.26 0.503997,-0.5999817 1.055996,-1.319981 1.656,-2.16 0.383995,-0.5519796 0.623995,-0.8879793 0.72,-1.008 0.167995,2.09e-5 0.251995,0.1560207 0.252,0.468 l 0,4.176 3.636,0" />
+    <path
+       inkscape:connector-curvature="0"
+       id="path17114"
+       style="font-size:36px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#999999;fill-opacity:1;stroke:none;font-family:FreeSerif;-inkscape-font-specification:FreeSerif;filter:url(#filter17363)"
+       d="m 78.197692,8.1510911 c -2.1e-5,0.7200058 -0.132021,1.4280051 -0.396,2.1239999 -0.264021,0.696004 -0.70802,1.392003 -1.332,2.088 -0.600019,0.672002 -1.500018,1.224001 -2.7,1.656 -1.200016,0.408 -2.628014,0.612 -4.284,0.612 l -12.024,0 0,-0.684 c 1.487998,-0.048 2.435997,-0.263999 2.844,-0.648 0.407996,-0.383998 0.611996,-1.247997 0.612,-2.592 l 0,-15.9839999 c -4e-6,-1.3199788 -0.204004,-2.1599779 -0.612,-2.52 -0.384003,-0.3839772 -1.332002,-0.6239769 -2.844,-0.72 l 0,-0.684 10.08,0 c 6.287983,2.38e-5 9.43198,2.0400218 9.432,6.12 -2e-5,0.7920169 -0.14402,1.5000162 -0.432,2.12400002 -0.288019,0.60001499 -0.588019,1.06801452 -0.9,1.404 -0.288019,0.31201387 -0.744018,0.61201358 -1.368,0.89999998 -0.624017,0.288013 -1.020016,0.4560128 -1.188,0.504 -0.168016,0.024013 -0.516016,0.1080127 -1.044,0.252 0.551984,0.1440124 0.959984,0.2520123 1.224,0.324 0.287983,0.072012 0.791983,0.2760119 1.512,0.612 0.743981,0.3360113 1.319981,0.6960109 1.728,1.08 0.40798,0.3840101 0.79198,0.9360096 1.152,1.656 0.359979,0.6960082 0.539979,1.4880074 0.54,2.376 m -11.34,5.1479999 c 1.079989,10e-7 2.015988,-0.072 2.808,-0.216 0.791986,-0.143998 1.535986,-0.383998 2.232,-0.72 0.695984,-0.359997 1.223984,-0.887997 1.584,-1.584 0.383983,-0.695995 0.575983,-1.5599945 0.576,-2.5919999 -1.7e-5,-0.9839926 -0.192017,-1.8119917 -0.576,-2.484 -0.360016,-0.6959904 -0.804016,-1.2239898 -1.332,-1.584 -0.528015,-0.3599891 -1.260014,-0.6359888 -2.196,-0.828 -0.936012,-0.1919885 -1.764011,-0.2999883 -2.484,-0.324 -0.72001,-0.047988 -1.680009,-0.071988 -2.88,-0.072 l 0,8.9279999 c -8e-6,0.576002 0.155992,0.972002 0.468,1.188 0.311991,0.192002 0.911991,0.288001 1.8,0.288 m -2.268,-11.8439999 3.42,0 c 1.679987,1.32e-5 2.975986,-0.3719864 3.888,-1.11599998 0.935984,-0.76798494 1.403984,-1.85998382 1.404,-3.27600002 -1.6e-5,-1.6079808 -0.540016,-2.8319796 -1.62,-3.672 -1.080014,-0.8399779 -2.652012,-1.2599775 -4.716,-1.26 l -1.584,0 c -0.528008,2.25e-5 -0.792008,0.3600222 -0.792,1.08 l 0,8.244" />
+    <path
+       inkscape:connector-curvature="0"
+       id="path17116"
+       style="font-size:36px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#999999;fill-opacity:1;stroke:none;font-family:FreeSerif;-inkscape-font-specification:FreeSerif;filter:url(#filter17375)"
+       d="m 93.240629,9.7710911 c -1.3e-5,-1.127994 -0.396013,-2.123993 -1.188,-2.988 -0.792011,-0.8879912 -1.75201,-1.6439905 -2.88,-2.268 -1.128008,-0.6239892 -2.256007,-1.2599886 -3.384,-1.908 -1.104005,-0.6719873 -2.052004,-1.5239864 -2.844,-2.55599998 -0.792002,-1.03198439 -1.188002,-2.23198322 -1.188,-3.60000002 -2e-6,-1.82398 0.611998,-3.2999785 1.836,-4.428 1.247995,-1.1519762 2.711994,-1.7279756 4.392,-1.728 1.007991,2.44e-5 2.09999,0.2040241 3.276,0.612 1.175988,0.4080233 1.883987,0.6120231 2.124,0.612 0.623986,2.31e-5 1.007986,-0.4079765 1.152,-1.224 l 0.756,0 0.792,7.668 -0.9,0 c -0.576015,-2.1119812 -1.464014,-3.6719796 -2.664,-4.68 -1.176011,-1.0079776 -2.48401,-1.5119771 -3.924,-1.512 -1.104007,2.29e-5 -2.004007,0.3120226 -2.7,0.936 -0.696005,0.6240213 -1.044005,1.4280205 -1.044,2.412 -5e-6,0.9600186 0.407995,1.8720177 1.224,2.736 0.815993,0.8640159 2.171992,1.82401497 4.068,2.88000002 2.375988,1.27201258 4.091986,2.53201138 5.148,3.77999998 1.055984,1.2240089 1.583983,2.5800076 1.584,4.068 -1.7e-5,1.8480039 -0.708016,3.4080029 -2.124,4.6799999 -1.416013,1.248 -3.156012,1.872 -5.22,1.872 -1.200008,0 -2.424007,-0.204 -3.672,-0.612 -1.224005,-0.407999 -1.980004,-0.611999 -2.268,-0.612 -0.264003,10e-7 -0.492003,0.120001 -0.684,0.36 -0.192003,0.216 -0.300003,0.492 -0.324,0.828 l -0.792,0 -1.08,-7.6319999 0.828,0 c 0.887998,2.184005 1.919997,3.7920029 3.096,4.8239999 1.175994,1.032001 2.567993,1.548001 4.176,1.548 1.31999,1e-6 2.387989,-0.371999 3.204,-1.116 0.815987,-0.767997 1.223987,-1.751996 1.224,-2.9519999" />
+    <path
+       inkscape:connector-curvature="0"
+       id="path17118"
+       style="font-size:36px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#999999;fill-opacity:1;stroke:none;font-family:FreeSerif;-inkscape-font-specification:FreeSerif;filter:url(#filter17387)"
+       d="m 123.31132,2.6070911 c -3e-5,1.080011 -0.12003,2.1360099 -0.36,3.168 -0.24003,1.0320078 -0.68403,2.1000068 -1.332,3.204 -0.64803,1.1040049 -1.47602,2.0640039 -2.484,2.8799999 -1.00802,0.792002 -2.35202,1.452001 -4.032,1.98 -1.65602,0.528 -3.54002,0.792 -5.652,0.792 l -10.224003,0 0,-0.684 c 1.367993,-0.096 2.231993,-0.335999 2.592003,-0.72 0.38399,-0.383998 0.57599,-1.223997 0.576,-2.52 l 0,-15.9839999 c -1e-5,-1.3199788 -0.18001,-2.1599779 -0.54,-2.52 -0.33601,-0.3599772 -1.21201,-0.599977 -2.628003,-0.72 l 0,-0.684 9.720003,0 c 2.18398,2.38e-5 4.12798,0.2520236 5.832,0.756 1.72798,0.4800226 3.10798,1.116022 4.14,1.908 1.05598,0.7680204 1.91997,1.6920195 2.592,2.772 0.69597,1.0560174 1.16397,2.1000163 1.404,3.13200002 0.26397,1.03201423 0.39597,2.11201318 0.396,3.23999998 m -3.924,0.252 c -2e-5,-1.0319872 -0.10802,-2.01598619 -0.324,-2.95199998 -0.19202,-0.95998432 -0.55202,-1.91998332 -1.08,-2.88000002 -0.52802,-0.9839814 -1.21202,-1.8239806 -2.052,-2.52 -0.84002,-0.6959792 -1.94402,-1.2599786 -3.312,-1.692 -1.36802,-0.4559777 -2.92801,-0.6839775 -4.68,-0.684 -0.74401,2.25e-5 -1.24801,0.096022 -1.512,0.288 -0.24001,0.192022 -0.36001,0.5640217 -0.36,1.116 l 0,18.2879999 c -10e-6,0.576002 0.13199,0.972002 0.396,1.188 0.26399,0.192002 0.75599,0.288001 1.476,0.288 7.63198,10e-7 11.44798,-3.4799951 11.448,-10.4399999" />
+    <rect
+       style="fill:#999999;fill-opacity:1;stroke:#999999;stroke-width:0.87290215000000004;stroke-opacity:1;filter:url(#filter17399)"
+       id="rect17105"
+       width="4.463408"
+       height="36.004753"
+       x="24.313543"
+       y="35.370052"
+       transform="matrix(0.8440288,-0.53629785,0.33448823,0.94239993,0,0)"
+       inkscape:transform-center-x="8.6102624"
+       inkscape:transform-center-y="-28.432038" />
+  </g>
+</svg>
diff --git a/icons/svg/os_redhat.svg b/icons/svg/os_redhat.svg
new file mode 100644 (file)
index 0000000..6f9b12b
--- /dev/null
@@ -0,0 +1,157 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="128"
+   height="128"
+   id="svg11068"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="os_redhat-02-color.svg"
+   inkscape:export-filename="/home/rodsmith/programming/refind/current/icons-build/os_redhat-color.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90">
+  <defs
+     id="defs11070">
+    <filter
+       id="filter11610"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood11612"
+         flood-opacity="0.6"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite11614"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur11616"
+         in="composite"
+         stdDeviation="2"
+         result="blur" />
+      <feOffset
+         id="feOffset11618"
+         dx="2"
+         dy="2"
+         result="offset" />
+      <feComposite
+         id="feComposite11620"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+    <filter
+       id="filter11756"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood11758"
+         flood-opacity="0.7"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite11760"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur11762"
+         in="composite"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset11764"
+         dx="2"
+         dy="2"
+         result="offset" />
+      <feComposite
+         id="feComposite11766"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="3.8890873"
+     inkscape:cx="107.72624"
+     inkscape:cy="64.342982"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:document-units="px"
+     inkscape:grid-bbox="true"
+     inkscape:window-width="1024"
+     inkscape:window-height="859"
+     inkscape:window-x="215"
+     inkscape:window-y="87"
+     inkscape:window-maximized="0" />
+  <metadata
+     id="metadata11073">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     transform="translate(0,64)">
+    <g
+       id="g11604"
+       transform="matrix(0.90471502,0.42601731,-0.42601731,0.90471502,20.872312,-30.760201)"
+       style="fill:#ff0000;stroke:#ffffff;filter:url(#filter11756)">
+      <path
+         transform="matrix(1.1342582,0,0,1.0785409,-27.300306,-62.412808)"
+         d="m 120.59385,91.101883 c 0,12.283767 -19.97348,22.241727 -44.612016,22.241727 -24.638533,0 -44.612011,-9.95796 -44.612011,-22.241727 0,-12.283764 19.973478,-22.241722 44.612011,-22.241722 24.638536,0 44.612016,9.957958 44.612016,22.241722 z"
+         sodipodi:ry="22.241722"
+         sodipodi:rx="44.612011"
+         sodipodi:cy="91.101883"
+         sodipodi:cx="75.981834"
+         id="path11076"
+         style="fill:#ff0000;fill-opacity:1;stroke:#ffffff;stroke-opacity:1;"
+         sodipodi:type="arc" />
+      <path
+         sodipodi:nodetypes="ccccc"
+         inkscape:connector-curvature="0"
+         d="m 30.855568,26.433754 c 2.026004,-19.2662261 54.580851,-18.0872467 56.054283,0 l 0,66.596603 c -10.237774,19.039053 -49.672825,17.895263 -56.054283,0 z"
+         style="fill:#ff0000;fill-opacity:1;stroke:#ffffff;stroke-opacity:1;"
+         transform="translate(0,-64)"
+         id="path11607" />
+      <path
+         transform="translate(-16.199174,-72.485281)"
+         d="m 102.59477,35.561859 c 0,8.591534 -12.317938,15.556349 -27.512884,15.556349 -15.194945,0 -27.512882,-6.964815 -27.512882,-15.556349 0,-8.591534 12.317937,-15.556349 27.512882,-15.556349 15.194946,0 27.512884,6.964815 27.512884,15.556349 z"
+         sodipodi:ry="15.556349"
+         sodipodi:rx="27.512882"
+         sodipodi:cy="35.561859"
+         sodipodi:cx="75.081886"
+         id="path11088"
+         style="fill:#ff0000;fill-opacity:1;stroke:#ffffff;stroke-opacity:1;"
+         sodipodi:type="arc" />
+    </g>
+  </g>
+</svg>
diff --git a/icons/svg/os_refind.svg b/icons/svg/os_refind.svg
new file mode 100644 (file)
index 0000000..5c55d6d
--- /dev/null
@@ -0,0 +1,154 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="128"
+   height="128"
+   id="svg12874"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   inkscape:export-filename="/home/rodsmith/programming/refind/current/icons-build/foo.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90"
+   sodipodi:docname="os_refind-03-basic.svg">
+  <defs
+     id="defs12876">
+    <filter
+       id="filter14441"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood14443"
+         flood-opacity="0.7"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite14445"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur14447"
+         in="composite"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset14449"
+         dx="3"
+         dy="3"
+         result="offset" />
+      <feComposite
+         id="feComposite14451"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#505050"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="5.46875"
+     inkscape:cx="65.187394"
+     inkscape:cy="62.318857"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:document-units="px"
+     inkscape:grid-bbox="true"
+     inkscape:window-width="1108"
+     inkscape:window-height="979"
+     inkscape:window-x="143"
+     inkscape:window-y="15"
+     inkscape:window-maximized="0" />
+  <metadata
+     id="metadata12879">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     transform="translate(0,64)">
+    <g
+       id="g14396"
+       transform="translate(-3.0027063,-3.0672157)"
+       style="filter:url(#filter14441)">
+      <path
+         sodipodi:end="6.3137247"
+         sodipodi:start="0.038057173"
+         transform="matrix(0.92479648,0,0,1.0146143,3.6793308,-74.868835)"
+         d="m 114.23105,62.798281 c -0.1474,3.24681 -3.40512,5.778652 -7.27631,5.655028 -3.8712,-0.123624 -6.88993,-2.855901 -6.74253,-6.10271 0.14739,-3.24681 3.40511,-5.778652 7.2763,-5.655028 3.85064,0.122968 6.86201,2.828112 6.74434,6.058508 l -7.01122,-0.179639 z"
+         sodipodi:ry="5.8831286"
+         sodipodi:rx="7.0144992"
+         sodipodi:cy="62.57444"
+         sodipodi:cx="107.22163"
+         id="path13770"
+         style="fill:#0000bc;fill-opacity:1;stroke:#0000bc;stroke-opacity:1"
+         sodipodi:type="arc" />
+      <path
+         inkscape:transform-center-y="-2.717824"
+         inkscape:transform-center-x="2.2822755"
+         transform="matrix(-0.36198059,-1.0983946,1.2009376,-0.52324781,92.632403,-15.195328)"
+         d="M 25.234285,15.542856 13.408625,14.102867 1.5350652,13.13418 8.6949622,3.6128532 15.47065,-6.1856079 20.136412,4.7757081 z"
+         inkscape:randomized="0"
+         inkscape:rounded="0"
+         inkscape:flatsided="false"
+         sodipodi:arg2="1.6720838"
+         sodipodi:arg1="0.62488624"
+         sodipodi:r2="6.6397543"
+         sodipodi:r1="13.753239"
+         sodipodi:cy="7.4971428"
+         sodipodi:cx="14.08"
+         sodipodi:sides="3"
+         id="path13768"
+         style="fill:#0000bc;fill-opacity:1;stroke:#0000bc;stroke-opacity:1"
+         sodipodi:type="star" />
+      <path
+         sodipodi:end="6.3137247"
+         sodipodi:start="0.038057173"
+         transform="matrix(1.0623728,0,0,1.0939231,-25.695042,-96.297006)"
+         d="m 128.90965,140.02735 c -0.13449,3.38069 -3.10681,6.01693 -6.63887,5.88821 -3.53207,-0.12872 -6.28635,-2.97366 -6.15186,-6.35435 0.13448,-3.38069 3.10681,-6.01693 6.63887,-5.88821 3.5133,0.12804 6.26086,2.94473 6.15351,6.30833 l -6.39702,-0.18705 z"
+         sodipodi:ry="6.1257143"
+         sodipodi:rx="6.4000001"
+         sodipodi:cy="139.79428"
+         sodipodi:cx="122.51428"
+         id="path13774"
+         style="fill:#0000bc;fill-opacity:1;stroke:#0000bc;stroke-opacity:1"
+         sodipodi:type="arc" />
+      <rect
+         transform="matrix(0.87626487,-0.48182972,0.50478347,0.86324599,0,0)"
+         y="62.893646"
+         x="54.812462"
+         height="36.635689"
+         width="13.590784"
+         id="rect13772"
+         style="fill:#0000bc;fill-opacity:1;stroke:#0000bc;stroke-width:0.97056359;stroke-opacity:1" />
+      <path
+         transform="translate(0,-64)"
+         inkscape:connector-curvature="0"
+         id="path14394"
+         d="M 62.24715,93.833652 C 44.041938,92.252582 28.546517,79.385025 23.734015,61.851955 22.501283,57.360822 22.301415,55.744916 22.29782,50.240526 22.294225,44.735665 22.524224,42.859657 23.75127,38.385327 28.007142,22.866603 41.06795,10.600982 56.852864,7.2990704 63.103797,5.9914908 69.776278,6.0487609 75.778578,7.4615104 83.004074,9.1621606 89.298831,12.39401 94.931372,17.294921 l 1.507079,1.311319 -4.873168,4.875923 -4.873169,4.875922 -1.296768,-1.097309 c -6.117882,-5.17688 -14.176954,-7.796403 -21.868196,-7.108048 -6.678051,0.597677 -12.12638,2.835457 -17.21195,7.069426 -8.343558,6.946394 -12.204448,18.453055 -9.850305,29.356991 1.730081,8.013399 6.921261,15.163838 14.115881,19.443507 4.268634,2.539167 8.875228,3.870069 14.059767,4.062041 7.738606,0.286543 14.749025,-2.096311 20.646607,-7.017823 5.644445,-4.710268 9.670531,-12.247325 10.415034,-19.497527 0.08051,-0.784007 0.193121,-1.47221 0.250249,-1.52934 0.13361,-0.133608 13.406277,0.33269 13.643537,0.479329 0.44025,0.27209 -0.49058,6.224421 -1.54774,9.897282 -2.3965,8.326113 -7.67389,16.284899 -14.40898,21.730061 -8.822615,7.132884 -20.238599,10.655628 -31.3921,9.686977 z"
+         style="fill:#0000bc;fill-opacity:1;stroke:#0000bc;stroke-width:0.18285714;stroke-opacity:1" />
+    </g>
+  </g>
+</svg>
diff --git a/icons/svg/os_refit.svg b/icons/svg/os_refit.svg
new file mode 100644 (file)
index 0000000..5f3acb3
--- /dev/null
@@ -0,0 +1,185 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="128"
+   height="128"
+   id="svg3838"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="os_refit-01-basic.svg"
+   inkscape:export-filename="/home/rodsmith/programming/refind/current/icons-build/os_refit-white.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90">
+  <defs
+     id="defs3840">
+    <filter
+       id="filter4018"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood4020"
+         flood-opacity="0.7"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite4022"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur4024"
+         in="composite"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset4026"
+         dx="3"
+         dy="3"
+         result="offset" />
+      <feComposite
+         id="feComposite4028"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+    <filter
+       id="filter4279"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood4281"
+         flood-opacity="0.7"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite4283"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur4285"
+         in="composite"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset4287"
+         dx="3"
+         dy="3"
+         result="offset" />
+      <feComposite
+         id="feComposite4289"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="3.8890873"
+     inkscape:cx="79.890469"
+     inkscape:cy="61.540294"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:document-units="px"
+     inkscape:grid-bbox="true"
+     inkscape:window-width="1149"
+     inkscape:window-height="913"
+     inkscape:window-x="419"
+     inkscape:window-y="39"
+     inkscape:window-maximized="0" />
+  <metadata
+     id="metadata3843">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     transform="translate(0,64)">
+    <g
+       id="g4238"
+       transform="translate(-1.0875019,1.1302528)"
+       style="filter:url(#filter4279)">
+      <g
+         id="g4199">
+        <path
+           style="fill:#ff7f2a;fill-opacity:1;stroke:#ff7f2a;stroke-width:0.02571297;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+           d="M 45.951523,45.677961 C 27.184494,40.714641 12.362921,25.664883 7.6037112,6.7397658 6.4660408,2.2157929 6.0560288,-1.1666201 6.0560288,-6.0279011 c 0,-5.4584779 0.533365,-9.8951559 1.6044734,-13.3464659 l 0.323999,-1.043983 12.4106888,0.05644 c 6.437899,0.02928 11.558356,-0.06862 11.627727,7.49e-4 0.06937,0.06937 -1.364536,7.106411 -1.519772,7.860089 -0.892047,4.3306369 -0.797329,9.7964989 0.239853,13.8411149 2.616556,10.2035681 10.427522,18.3046931 20.449236,21.2088731 1.250082,0.36226 2.295808,0.684994 2.323836,0.717186 0.04656,0.05348 -4.073393,21.15541 -4.391566,22.4931 -0.168132,0.70688 -0.195616,0.70618 -3.172981,-0.0812 l 0,0 z"
+           id="path3929"
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cssscsscsscsccc" />
+        <path
+           sodipodi:type="star"
+           style="fill:#ff7f2a;fill-opacity:1;stroke:#ff7f2a;stroke-width:0.1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+           id="path3937"
+           sodipodi:sides="3"
+           sodipodi:cx="43.969185"
+           sodipodi:cy="13.320137"
+           sodipodi:r1="29.920004"
+           sodipodi:r2="14.960005"
+           sodipodi:arg1="0.42520502"
+           sodipodi:arg2="1.4724026"
+           inkscape:flatsided="false"
+           inkscape:rounded="0"
+           inkscape:randomized="0"
+           d="M 71.224937,25.662365 45.438782,28.207784 19.652626,30.753197 30.341306,7.1490216 41.029991,-16.455151 56.127467,4.6036055 z"
+           transform="matrix(0.92066016,-0.27223138,0.26609375,0.95690224,20.413951,36.096524)"
+           inkscape:transform-center-x="-5.314509"
+           inkscape:transform-center-y="-2.1952162" />
+      </g>
+      <g
+         id="g4199-5"
+         transform="matrix(-1,0,0,-1,124.00389,-2.7747651)">
+        <path
+           style="fill:#ff7f2a;fill-opacity:1;stroke:#ff7f2a;stroke-width:0.02571297;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+           d="M 45.951523,45.677961 C 27.184494,40.714641 12.362921,25.664883 7.6037112,6.7397658 6.4660408,2.2157929 6.0560288,-1.1666201 6.0560288,-6.0279011 c 0,-5.4584779 0.533365,-9.8951559 1.6044734,-13.3464659 l 0.323999,-1.043983 12.4106888,0.05644 c 6.437899,0.02928 11.558356,-0.06862 11.627727,7.49e-4 0.06937,0.06937 -1.364536,7.106411 -1.519772,7.860089 -0.892047,4.3306369 -0.797329,9.7964989 0.239853,13.8411149 2.616556,10.2035681 10.427522,18.3046931 20.449236,21.2088731 1.250082,0.36226 2.295808,0.684994 2.323836,0.717186 0.04656,0.05348 -4.073393,21.15541 -4.391566,22.4931 -0.168132,0.70688 -0.195616,0.70618 -3.172981,-0.0812 l 0,0 z"
+           id="path3929-9"
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cssscsscsscsccc" />
+        <path
+           sodipodi:type="star"
+           style="fill:#ff7f2a;fill-opacity:1;stroke:#ff7f2a;stroke-width:0.1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+           id="path3937-8"
+           sodipodi:sides="3"
+           sodipodi:cx="43.969185"
+           sodipodi:cy="13.320137"
+           sodipodi:r1="29.920004"
+           sodipodi:r2="14.960005"
+           sodipodi:arg1="0.42520502"
+           sodipodi:arg2="1.4724026"
+           inkscape:flatsided="false"
+           inkscape:rounded="0"
+           inkscape:randomized="0"
+           d="M 71.224937,25.662365 45.438782,28.207784 19.652626,30.753197 30.341306,7.1490216 41.029991,-16.455151 56.127467,4.6036055 z"
+           transform="matrix(0.92066016,-0.27223138,0.26609375,0.95690224,20.413951,36.096524)"
+           inkscape:transform-center-x="-5.314509"
+           inkscape:transform-center-y="-2.1952162" />
+      </g>
+    </g>
+  </g>
+</svg>
diff --git a/icons/svg/os_win.svg b/icons/svg/os_win.svg
new file mode 100644 (file)
index 0000000..8afa10c
--- /dev/null
@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="135"
+   height="135"
+   id="svg9607"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="os_win-01-color.svg"
+   inkscape:export-filename="/home/rodsmith/programming/refind/current/icons-build/os_win-color.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90">
+  <defs
+     id="defs9609">
+    <filter
+       id="filter3815"
+       inkscape:label="Drop Shadow"
+       color-interpolation-filters="sRGB">
+      <feFlood
+         id="feFlood3817"
+         flood-opacity="0.7"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite3819"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur3821"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset3823"
+         dx="3"
+         dy="3"
+         result="offset" />
+      <feComposite
+         id="feComposite3825"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="4.9497475"
+     inkscape:cx="67.177703"
+     inkscape:cy="66.242938"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:grid-bbox="true"
+     inkscape:document-units="px"
+     inkscape:window-width="1143"
+     inkscape:window-height="936"
+     inkscape:window-x="354"
+     inkscape:window-y="81"
+     inkscape:window-maximized="0" />
+  <metadata
+     id="metadata9612">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     transform="translate(0,87)">
+    <g
+       id="g9738"
+       transform="translate(7.0761681e-7,-6.3639605)"
+       style="filter:url(#filter3815)">
+      <path
+         sodipodi:nodetypes="ccccc"
+         inkscape:connector-curvature="0"
+         id="rect9615"
+         d="m 4.7203518,-11.741735 c 12.0209472,-14.272787 44.5029732,-16.021563 56.1714892,0 l 0,43.560551 c -13.716554,-12.936189 -38.510159,-14.30236 -56.1714892,0 z"
+         style="fill:#0000ff;fill-opacity:1;stroke:#0000ff;stroke-width:1.17263913" />
+      <path
+         sodipodi:nodetypes="ccccc"
+         inkscape:connector-curvature="0"
+         id="rect9615-6"
+         d="m 4.6350396,-64.86804 c 12.0209444,-14.272787 44.5029724,-16.021562 56.1714884,0 l 0,43.560551 c -12.154227,-12.865477 -36.38669,-14.364515 -56.1714884,0 z"
+         style="fill:#ff0000;fill-opacity:1;stroke:#ff0000;stroke-width:1.17263913" />
+      <path
+         sodipodi:nodetypes="ccccc"
+         inkscape:connector-curvature="0"
+         id="rect9615-6-7"
+         d="m 67.538565,-17.822259 c 12.020945,14.2727869 44.502975,16.0215625 56.171495,0 l 0,-43.56055 c -12.15423,12.865476 -36.386696,14.364514 -56.171495,0 z"
+         style="fill:#00ff00;fill-opacity:1;stroke:#00ff00;stroke-width:1.17263913" />
+      <path
+         sodipodi:nodetypes="ccccc"
+         inkscape:connector-curvature="0"
+         id="rect9615-6-7-5"
+         d="m 67.597521,34.686314 c 12.020945,14.272786 44.502979,16.021562 56.171499,0 l 0,-43.5605509 c -12.15423,12.8654779 -36.386701,14.3645156 -56.171499,0 z"
+         style="fill:#ffff00;fill-opacity:1;stroke:#ffff00;stroke-width:1.17263913" />
+    </g>
+  </g>
+</svg>
diff --git a/icons/svg/tool_memtest.svg b/icons/svg/tool_memtest.svg
new file mode 100644 (file)
index 0000000..2e94527
--- /dev/null
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="128"
+   height="128"
+   id="svg9250"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="tool_memtest-01-basic.svg">
+  <defs
+     id="defs9252" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="4"
+     inkscape:cx="66.1575"
+     inkscape:cy="61.220758"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:document-units="px"
+     inkscape:grid-bbox="true"
+     inkscape:window-width="875"
+     inkscape:window-height="925"
+     inkscape:window-x="696"
+     inkscape:window-y="29"
+     inkscape:window-maximized="0" />
+  <metadata
+     id="metadata9255">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     transform="translate(0,64)">
+    <rect
+       style="fill:#808000;fill-opacity:1;stroke:#999999"
+       id="rect9258"
+       width="104.75"
+       height="41"
+       x="13.75"
+       y="19.25"
+       transform="translate(0,-64)" />
+    <rect
+       style="fill:#ffffff;fill-opacity:1;stroke:#999999"
+       id="rect9260"
+       width="59.5"
+       height="9"
+       x="13.75"
+       y="60.25"
+       transform="translate(0,-64)" />
+    <rect
+       style="fill:#ffffff;fill-opacity:1;stroke:#999999"
+       id="rect9262"
+       width="41"
+       height="9"
+       x="77.5"
+       y="60.5"
+       transform="translate(0,-64)" />
+    <rect
+       style="fill:#333333;fill-opacity:1;stroke:#999999"
+       id="rect9264"
+       width="19"
+       height="26.5"
+       x="22.5"
+       y="26.75"
+       transform="translate(0,-64)" />
+    <rect
+       style="fill:#333333;fill-opacity:1;stroke:#999999"
+       id="rect9264-2"
+       width="19"
+       height="26.5"
+       x="54.25"
+       y="-37.25" />
+    <rect
+       style="fill:#333333;fill-opacity:1;stroke:#999999"
+       id="rect9264-4"
+       width="19"
+       height="26.5"
+       x="87.5"
+       y="-37" />
+  </g>
+</svg>
diff --git a/icons/tool_apple_rescue.png b/icons/tool_apple_rescue.png
new file mode 100644 (file)
index 0000000..c1c637d
Binary files /dev/null and b/icons/tool_apple_rescue.png differ
diff --git a/icons/tool_memtest.png b/icons/tool_memtest.png
new file mode 100644 (file)
index 0000000..7892c55
Binary files /dev/null and b/icons/tool_memtest.png differ
diff --git a/icons/tool_mok_tool.png b/icons/tool_mok_tool.png
new file mode 100644 (file)
index 0000000..42bc488
Binary files /dev/null and b/icons/tool_mok_tool.png differ
diff --git a/icons/tool_netboot.png b/icons/tool_netboot.png
new file mode 100644 (file)
index 0000000..09d2294
Binary files /dev/null and b/icons/tool_netboot.png differ
diff --git a/icons/tool_part.png b/icons/tool_part.png
new file mode 100644 (file)
index 0000000..4b7a07b
Binary files /dev/null and b/icons/tool_part.png differ
diff --git a/icons/tool_rescue.png b/icons/tool_rescue.png
new file mode 100644 (file)
index 0000000..45de046
Binary files /dev/null and b/icons/tool_rescue.png differ
diff --git a/icons/tool_shell.png b/icons/tool_shell.png
new file mode 100644 (file)
index 0000000..b7fa2a7
Binary files /dev/null and b/icons/tool_shell.png differ
diff --git a/icons/tool_windows_rescue.png b/icons/tool_windows_rescue.png
new file mode 100644 (file)
index 0000000..19d1dd2
Binary files /dev/null and b/icons/tool_windows_rescue.png differ
diff --git a/icons/transparent.png b/icons/transparent.png
new file mode 100644 (file)
index 0000000..433cc88
Binary files /dev/null and b/icons/transparent.png differ
diff --git a/icons/vol_external.png b/icons/vol_external.png
new file mode 100644 (file)
index 0000000..4240d90
Binary files /dev/null and b/icons/vol_external.png differ
diff --git a/icons/vol_internal.png b/icons/vol_internal.png
new file mode 100644 (file)
index 0000000..ec5918a
Binary files /dev/null and b/icons/vol_internal.png differ
diff --git a/icons/vol_net.png b/icons/vol_net.png
new file mode 100644 (file)
index 0000000..31e1f37
Binary files /dev/null and b/icons/vol_net.png differ
diff --git a/icons/vol_optical.png b/icons/vol_optical.png
new file mode 100644 (file)
index 0000000..2a7488b
Binary files /dev/null and b/icons/vol_optical.png differ
diff --git a/images/back-normal-big.png b/images/back-normal-big.png
new file mode 100644 (file)
index 0000000..3484611
Binary files /dev/null and b/images/back-normal-big.png differ
diff --git a/images/back-normal-small.png b/images/back-normal-small.png
new file mode 100644 (file)
index 0000000..8109815
Binary files /dev/null and b/images/back-normal-small.png differ
diff --git a/images/back-selected-big.png b/images/back-selected-big.png
new file mode 100644 (file)
index 0000000..752d2d2
Binary files /dev/null and b/images/back-selected-big.png differ
diff --git a/images/back-selected-small.png b/images/back-selected-small.png
new file mode 100644 (file)
index 0000000..8d473da
Binary files /dev/null and b/images/back-selected-small.png differ
diff --git a/images/font.png b/images/font.png
new file mode 100644 (file)
index 0000000..49ba0a8
Binary files /dev/null and b/images/font.png differ
diff --git a/images/imgprepare.py b/images/imgprepare.py
new file mode 100755 (executable)
index 0000000..306f3cc
--- /dev/null
@@ -0,0 +1,114 @@
+#!/usr/bin/python
+
+import sys
+import Image
+
+def enc_backbuffer(backbuffer):
+    compdata = []
+    if len(backbuffer) == 0:
+        return compdata
+    while len(backbuffer) > 128:
+        compdata.append(127)
+        compdata.extend(backbuffer[0:128])
+        backbuffer = backbuffer[128:]
+    compdata.append(len(backbuffer)-1)
+    compdata.extend(backbuffer)
+    return compdata
+
+def packbits(rawdata):
+    compdata = []
+    backbuffer = []
+
+    while len(rawdata) >= 3:
+        c = rawdata[0]
+        if rawdata[1] == c and rawdata[2] == c:
+            runlength = 3
+            while runlength < 130 and len(rawdata) > runlength:
+                if rawdata[runlength] == c:
+                    runlength = runlength + 1
+                else:
+                    break
+            compdata.extend(enc_backbuffer(backbuffer))
+            backbuffer = []
+            compdata.append(runlength + 125)
+            compdata.append(c)
+            rawdata = rawdata[runlength:]
+
+        else:
+            backbuffer.append(c)
+            rawdata = rawdata[1:]
+
+    backbuffer.extend(rawdata)
+    compdata.extend(enc_backbuffer(backbuffer))
+
+    return compdata
+
+
+for filename in sys.argv[1:]:
+
+    origimage = Image.open(filename)
+
+    (width, height) = origimage.size
+    mode = origimage.mode
+    data = origimage.getdata()
+
+    print "%s: %d x %d %s" % (filename, width, height, mode)
+
+    basename = filename[:-4]
+    identname = basename.replace("-", "_")
+
+    planecount = 1
+    imgmode = 0
+    rawdata = []
+
+    if mode == "RGB" or mode == "RGBA":
+        planes = [ [], [], [] ]
+        for pixcount in range(0, width*height):
+            pixeldata = data[pixcount]
+            planes[0].append(pixeldata[2])
+            planes[1].append(pixeldata[1])
+            planes[2].append(pixeldata[0])
+
+        if planes[0] == planes[1] and planes[0] == planes[2]:
+            print " encoding as greyscale"
+            planecount = 1
+            rawdata.extend(planes[0])
+
+            if basename[0:4] == "font":
+                print " font detected, using alpha-only mode"
+                imgmode = 1
+                # invert all values
+                rawdata = map(lambda x: 255-x, rawdata)
+
+        else:
+            print " encoding as true color"
+            planecount = 3
+            rawdata.extend(planes[0])
+            rawdata.extend(planes[1])
+            rawdata.extend(planes[2])
+
+    else:
+        print " Mode not supported!"
+        continue
+
+    rawlen = len(rawdata)
+    compdata = packbits(rawdata)
+    complen = len(compdata)
+    print " compressed %d to %d" % (rawlen, complen)
+
+    output = """static UINT8 image_%s_compdata[] = {
+""" % identname
+    for i in range(0, len(compdata)):
+        output = output + " 0x%02x," % compdata[i]
+        if (i % 12) == 11:
+            output = output + "\n"
+    output = output + """
+};
+static BUILTIN_IMAGE image_%s = { NULL, %d, %d, %d, %d, image_%s_compdata, %d };
+""" % (identname, width, height, imgmode, planecount, identname, len(compdata))
+
+    f = file("image_%s.h" % identname, "w")
+    f.write(output)
+    f.close()
+
+print "Done!"
diff --git a/images/linux-bootlogo.png b/images/linux-bootlogo.png
new file mode 100644 (file)
index 0000000..203c5dc
Binary files /dev/null and b/images/linux-bootlogo.png differ
diff --git a/images/mkeei.py b/images/mkeei.py
new file mode 100755 (executable)
index 0000000..3aa1737
--- /dev/null
@@ -0,0 +1,179 @@
+#!/usr/bin/python
+
+import sys
+import Image
+
+def enc_backbuffer(backbuffer):
+    """Helper function for RLE compression, encodes a string of uncompressable data."""
+    compdata = []
+    if len(backbuffer) == 0:
+        return compdata
+    while len(backbuffer) > 128:
+        compdata.append(127)
+        compdata.extend(backbuffer[0:128])
+        backbuffer = backbuffer[128:]
+    compdata.append(len(backbuffer)-1)
+    compdata.extend(backbuffer)
+    return compdata
+
+def compress_rle(rawdata):
+    """Compresses the string using a RLE scheme."""
+    compdata = []
+    backbuffer = []
+
+    while len(rawdata) >= 3:
+        c = rawdata[0]
+        if rawdata[1] == c and rawdata[2] == c:
+            runlength = 3
+            while runlength < 130 and len(rawdata) > runlength:
+                if rawdata[runlength] == c:
+                    runlength = runlength + 1
+                else:
+                    break
+            compdata.extend(enc_backbuffer(backbuffer))
+            backbuffer = []
+            compdata.append(runlength + 125)
+            compdata.append(c)
+            rawdata = rawdata[runlength:]
+
+        else:
+            backbuffer.append(c)
+            rawdata = rawdata[1:]
+
+    backbuffer.extend(rawdata)
+    compdata.extend(enc_backbuffer(backbuffer))
+
+    return compdata
+
+def encode_plane(rawdata, identname, planename):
+    """Encodes the data of a single plane."""
+
+    rawlen = len(rawdata)
+    compdata = compress_rle(rawdata)
+    complen = len(compdata)
+    print "  plane %s: compressed %d to %d (%.1f%%)" % (planename, rawlen, complen, float(complen) / float(rawlen) * 100.0)
+
+    output = """static const UINT8 eei_%s_planedata_%s[%d] = {
+""" % (identname, planename, complen)
+    for i in range(0, len(compdata)):
+        output = output + " 0x%02x," % compdata[i]
+        if (i % 12) == 11:
+            output = output + "\n"
+    output = output + """
+};
+"""
+    return (output, "eei_%s_planedata_%s, %d" % (identname, planename, complen))
+
+
+### main loop
+
+print "mkeei 0.1, Copyright (c) 2006 Christoph Pfisterer"
+
+planenames = ( "blue", "green", "red", "alpha", "grey" )
+
+for filename in sys.argv[1:]:
+
+    origimage = Image.open(filename)
+
+    (width, height) = origimage.size
+    mode = origimage.mode
+    data = origimage.getdata()
+
+    print "%s: %d x %d %s" % (filename, width, height, mode)
+
+    basename = filename[:-4]   # TODO!!!!!!
+    identname = basename.replace("-", "_")
+
+    planes = [ [], [], [], [] ]
+
+    if mode == "RGB":
+        for pixcount in range(0, width*height):
+            pixeldata = data[pixcount]
+            planes[0].append(pixeldata[2])
+            planes[1].append(pixeldata[1])
+            planes[2].append(pixeldata[0])
+
+    elif mode == "RGBA":
+        for pixcount in range(0, width*height):
+            pixeldata = data[pixcount]
+            planes[0].append(pixeldata[2])
+            planes[1].append(pixeldata[1])
+            planes[2].append(pixeldata[0])
+            planes[3].append(pixeldata[3])
+
+    elif mode == "L":
+        for pixcount in range(0, width*height):
+            pixeldata = data[pixcount]
+            planes[0].append(pixeldata)
+            planes[1].append(pixeldata)
+            planes[2].append(pixeldata)
+
+    else:
+        print " Error: Mode not supported!"
+        continue
+
+    # special treatment for fonts
+
+    if basename[0:4] == "font":
+        if planes[0] != planes[1] or planes[0] != planes[2]:
+            print " Error: Font detected, but it is not greyscale!"
+            continue
+        print " font detected, encoding as alpha-only"
+        # invert greyscale values for use as alpha
+        planes[3] = map(lambda x: 255-x, planes[0])
+        planes[0] = []
+        planes[1] = []
+        planes[2] = []
+
+    # generate optimal output
+
+    output = ""
+    planeinfo = [ "NULL, 0", "NULL, 0", "NULL, 0", "NULL, 0" ]
+
+    if len(planes[0]) > 0 and planes[0] == planes[1] and planes[0] == planes[2]:
+        print " encoding as greyscale"
+        (output_part, planeinfo[0]) = encode_plane(planes[0], identname, planenames[4])
+        output = output + output_part
+        planeinfo[1] = planeinfo[0]
+        planeinfo[2] = planeinfo[0]
+
+    elif len(planes[0]) > 0:
+        print " encoding as true color"
+
+        (output_part, planeinfo[0]) = encode_plane(planes[0], identname, planenames[0])
+        output = output + output_part
+
+        if planes[1] == planes[0]:
+            print " encoding plane 1 is a copy of plane 0"
+            planeinfo[1] = planeinfo[0]
+        else:
+            (output_part, planeinfo[1]) = encode_plane(planes[1], identname, planenames[1])
+            output = output + output_part
+
+        if planes[2] == planes[0]:
+            print " encoding plane 2 is a copy of plane 0"
+            planeinfo[2] = planeinfo[0]
+        elif planes[2] == planes[1]:
+            print " encoding plane 2 is a copy of plane 1"
+            planeinfo[2] = planeinfo[1]
+        else:
+            (output_part, planeinfo[2]) = encode_plane(planes[2], identname, planenames[2])
+            output = output + output_part
+
+    if len(planes[3]) > 0:
+        if reduce(lambda x,y: x+y, planes[3]) == 0:
+            print " skipping alpha plane because it is empty"
+        else:
+            (output_part, planeinfo[3]) = encode_plane(planes[3], identname, planenames[3])
+            output = output + output_part
+
+    output = output + "static EEI_IMAGE eei_%s = { %d, %d, NULL, {\n" % (identname, width, height)
+    for i in range(0,4):
+        output = output + "    { %s },\n" % planeinfo[i]
+    output = output + "} };\n"
+
+    f = file("eei_%s.h" % identname, "w")
+    f.write(output)
+    f.close()
+
+print "Done!"
diff --git a/images/mkegemb.py b/images/mkegemb.py
new file mode 100755 (executable)
index 0000000..6a7c63d
--- /dev/null
@@ -0,0 +1,159 @@
+#!/usr/bin/env python
+
+import sys, os.path
+import Image
+
+def enc_backbuffer(backbuffer):
+    """Helper function for RLE compression, encodes a string of uncompressable data."""
+    compdata = []
+    if len(backbuffer) == 0:
+        return compdata
+    while len(backbuffer) > 128:
+        compdata.append(127)
+        compdata.extend(backbuffer[0:128])
+        backbuffer = backbuffer[128:]
+    compdata.append(len(backbuffer)-1)
+    compdata.extend(backbuffer)
+    return compdata
+
+def compress_rle(rawdata):
+    """Compresses the string using a RLE scheme."""
+    compdata = []
+    backbuffer = []
+    
+    while len(rawdata) >= 3:
+        c = rawdata[0]
+        if rawdata[1] == c and rawdata[2] == c:
+            runlength = 3
+            while runlength < 130 and len(rawdata) > runlength:
+                if rawdata[runlength] == c:
+                    runlength = runlength + 1
+                else:
+                    break
+            compdata.extend(enc_backbuffer(backbuffer))
+            backbuffer = []
+            compdata.append(runlength + 125)
+            compdata.append(c)
+            rawdata = rawdata[runlength:]
+        
+        else:
+            backbuffer.append(c)
+            rawdata = rawdata[1:]
+    
+    backbuffer.extend(rawdata)
+    compdata.extend(enc_backbuffer(backbuffer))
+    
+    return compdata
+
+def encode_plane(rawdata, planename):
+    """Encodes the data of a single plane."""
+    
+    rawlen = len(rawdata)
+    compdata = compress_rle(rawdata)
+    complen = len(compdata)
+    print "  plane %s: compressed %d to %d (%.1f%%)" % (planename, rawlen, complen, float(complen) / float(rawlen) * 100.0)
+    
+    return compdata
+
+
+### main loop
+
+print "mkegemb 0.1, Copyright (c) 2006 Christoph Pfisterer"
+
+planenames = ( "blue", "green", "red", "alpha", "grey" )
+
+for filename in sys.argv[1:]:
+    
+    origimage = Image.open(filename)
+    
+    (width, height) = origimage.size
+    mode = origimage.mode
+    data = origimage.getdata()
+    
+    print "%s: %d x %d %s" % (filename, width, height, mode)
+    
+    (basename, extension) = os.path.splitext(filename)
+    identname = basename.replace("-", "_")
+    
+    # extract image data from PIL object
+    
+    planes = [ [], [], [], [] ]
+    
+    if mode == "RGB":
+        for pixcount in range(0, width*height):
+            pixeldata = data[pixcount]
+            planes[0].append(pixeldata[0])
+            planes[1].append(pixeldata[1])
+            planes[2].append(pixeldata[2])
+    
+    elif mode == "RGBA":
+        for pixcount in range(0, width*height):
+            pixeldata = data[pixcount]
+            planes[0].append(pixeldata[0])
+            planes[1].append(pixeldata[1])
+            planes[2].append(pixeldata[2])
+            planes[3].append(pixeldata[3])
+    
+    elif mode == "L":
+        for pixcount in range(0, width*height):
+            pixeldata = data[pixcount]
+            planes[0].append(pixeldata)
+            planes[1].append(pixeldata)
+            planes[2].append(pixeldata)
+    
+    else:
+        print " Error: Mode not supported!"
+        continue
+    
+    # special treatment for fonts
+    
+    if basename[0:4] == "font":
+        if planes[0] != planes[1] or planes[0] != planes[2]:
+            print " Error: Font detected, but it is not greyscale!"
+            continue
+        print " font detected, encoding as alpha-only"
+        # invert greyscale values for use as alpha
+        planes[3] = map(lambda x: 255-x, planes[0])
+        planes[0] = []
+        planes[1] = []
+        planes[2] = []
+    
+    # encode planes
+    
+    imagedata = []
+    pixelformat = "EG_EIPIXELMODE"
+    
+    if len(planes[0]) > 0 and planes[0] == planes[1] and planes[0] == planes[2]:
+        print " encoding as greyscale"
+        imagedata.extend(encode_plane(planes[0], planenames[4]))
+        pixelformat = pixelformat + "_GRAY"
+    
+    elif len(planes[0]) > 0:
+        print " encoding as true color"
+        imagedata.extend(encode_plane(planes[0], planenames[0]))
+        imagedata.extend(encode_plane(planes[1], planenames[1]))
+        imagedata.extend(encode_plane(planes[2], planenames[2]))
+        pixelformat = pixelformat + "_COLOR"
+    
+    if len(planes[3]) > 0:
+        if reduce(lambda x,y: x+y, planes[3]) == 0:
+            print " skipping alpha plane because it is empty"
+        else:
+            imagedata.extend(encode_plane(planes[3], planenames[3]))
+            pixelformat = pixelformat + "_ALPHA"
+    
+    # generate compilable header file
+    
+    output = "static const UINT8 egemb_%s_data[%d] = {\n" % (identname, len(imagedata))
+    for i in range(0, len(imagedata)):
+        output = output + " 0x%02x," % imagedata[i]
+        if (i % 12) == 11:
+            output = output + "\n"
+    output = output + "\n};\n"
+    output = output + "static EG_EMBEDDED_IMAGE egemb_%s = { %d, %d, %s, EG_EICOMPMODE_RLE, egemb_%s_data, %d };\n" % (identname, width, height, pixelformat, identname, len(imagedata))
+    
+    f = file("egemb_%s.h" % identname, "w")
+    f.write(output)
+    f.close()
+
+print "Done!"
diff --git a/images/refind_banner.bmp b/images/refind_banner.bmp
new file mode 100644 (file)
index 0000000..de8150a
Binary files /dev/null and b/images/refind_banner.bmp differ
diff --git a/images/refind_banner.odt b/images/refind_banner.odt
new file mode 100644 (file)
index 0000000..35704ad
Binary files /dev/null and b/images/refind_banner.odt differ
diff --git a/images/txt.pl b/images/txt.pl
new file mode 100755 (executable)
index 0000000..b504fc2
--- /dev/null
@@ -0,0 +1,7 @@
+#!/usr/bin/perl
+
+foreach $i (32..126) {
+  print chr($i);
+}
+print "?\n";
+exit 0;
diff --git a/images/windows-bootlogo.png b/images/windows-bootlogo.png
new file mode 100644 (file)
index 0000000..2ff1dd9
Binary files /dev/null and b/images/windows-bootlogo.png differ
diff --git a/include/Bmp.h b/include/Bmp.h
new file mode 100644 (file)
index 0000000..c7d81b0
--- /dev/null
@@ -0,0 +1,52 @@
+/** @file\r
+  This file defines BMP file header data structures.\r
+\r
+Copyright (c) 2006 - 2008, Intel Corporation. <BR>\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _BMP_H__\r
+#define _BMP_H__\r
+\r
+#pragma pack(1)\r
+\r
+typedef struct {\r
+\r
+  UINT8   Blue;\r
+  UINT8   Green;\r
+  UINT8   Red;\r
+  UINT8   Reserved;\r
+\r
+} BMP_COLOR_MAP;\r
+\r
+typedef struct {\r
+\r
+  CHAR8         CharB;\r
+  CHAR8         CharM;\r
+  UINT32        Size;\r
+  UINT16        Reserved[2];\r
+  UINT32        ImageOffset;\r
+  UINT32        HeaderSize;\r
+  UINT32        PixelWidth;\r
+  UINT32        PixelHeight;\r
+  UINT16        Planes;          ///> Must be 1\r
+  UINT16        BitPerPixel;     ///> 1, 4, 8, or 24\r
+  UINT32        CompressionType;\r
+  UINT32        ImageSize;       ///> Compressed image size in bytes\r
+  UINT32        XPixelsPerMeter;\r
+  UINT32        YPixelsPerMeter;\r
+  UINT32        NumberOfColors;\r
+  UINT32        ImportantColors;\r
+\r
+} BMP_IMAGE_HEADER;\r
+\r
+#pragma pack()\r
+\r
+#endif\r
diff --git a/include/Handle.h b/include/Handle.h
new file mode 100644 (file)
index 0000000..9d3a082
--- /dev/null
@@ -0,0 +1,135 @@
+/*++
+
+Copyright (c) 2005, Intel Corporation                                                         
+All rights reserved. This program and the accompanying materials                          
+are licensed and made available under the terms and conditions of the BSD License         
+which accompanies this distribution. The full text of the license may be found at         
+http://opensource.org/licenses/bsd-license.php                                            
+                                                                                          
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             
+
+Module Name:
+
+  Handle.h
+
+Abstract:
+
+  Infomation about the handle function.
+Revision History
+
+--*/
+#ifndef _HANDLE_H
+#define _HANDLE_H
+
+#include "libeg.h"
+
+#define EFI_HANDLE_TYPE_UNKNOWN                     0x000
+#define EFI_HANDLE_TYPE_IMAGE_HANDLE                0x001
+#define EFI_HANDLE_TYPE_DRIVER_BINDING_HANDLE       0x002
+#define EFI_HANDLE_TYPE_DEVICE_DRIVER               0x004
+#define EFI_HANDLE_TYPE_BUS_DRIVER                  0x008
+#define EFI_HANDLE_TYPE_DRIVER_CONFIGURATION_HANDLE 0x010
+#define EFI_HANDLE_TYPE_DRIVER_DIAGNOSTICS_HANDLE   0x020
+#define EFI_HANDLE_TYPE_COMPONENT_NAME_HANDLE       0x040
+#define EFI_HANDLE_TYPE_DEVICE_HANDLE               0x080
+#define EFI_HANDLE_TYPE_PARENT_HANDLE               0x100
+#define EFI_HANDLE_TYPE_CONTROLLER_HANDLE           0x200
+#define EFI_HANDLE_TYPE_CHILD_HANDLE                0x400
+
+EFI_FILE_SYSTEM_INFO              *
+EfiLibFileSystemInfo (
+  IN EFI_FILE_HANDLE                FHand
+  );
+
+EFI_STATUS
+LibGetManagedChildControllerHandles (
+  EFI_HANDLE  DriverBindingHandle,
+  EFI_HANDLE  ControllerHandle,
+  UINTN       *ChildControllerHandleCount,
+  EFI_HANDLE  **ChildControllerHandleBuffer
+  );
+
+EFI_STATUS
+LibGetManagedControllerHandles (
+  EFI_HANDLE  DriverBindingHandle,
+  UINTN       *ControllerHandleCount,
+  EFI_HANDLE  **ControllerHandleBuffer
+  );
+
+EFI_STATUS
+LibGetChildControllerHandles (
+  EFI_HANDLE  ControllerHandle,
+  UINTN       *HandleCount,
+  EFI_HANDLE  **HandleBuffer
+  );
+
+EFI_STATUS
+LibInstallProtocolInterfaces (
+  IN OUT EFI_HANDLE                   *Handle,
+  ...
+  );
+
+VOID
+LibUninstallProtocolInterfaces (
+  IN EFI_HANDLE                       Handle,
+  ...
+  );
+
+EFI_STATUS
+LibReinstallProtocolInterfaces (
+  IN OUT EFI_HANDLE                   *Handle,
+  ...
+  );
+
+EFI_STATUS
+LibLocateHandleByDiskSignature (
+  IN UINT8                          MBRType,
+  IN UINT8                          SignatureType,
+  IN VOID                           *Signature,
+  IN OUT UINTN                      *NoHandles,
+  OUT EFI_HANDLE                    **Buffer
+  );
+
+EFI_STATUS
+LibLocateHandle (
+  IN EFI_LOCATE_SEARCH_TYPE         SearchType,
+  IN EFI_GUID                       * Protocol OPTIONAL,
+  IN VOID                           *SearchKey OPTIONAL,
+  IN OUT UINTN                      *NoHandles,
+  OUT EFI_HANDLE                    **Buffer
+  );
+
+EFI_STATUS
+LibLocateProtocol (
+  IN  EFI_GUID    *ProtocolGuid,
+  OUT VOID        **Interface
+  );
+
+EFI_HANDLE
+ShellHandleFromIndex (
+  IN UINTN        Value
+  );
+
+UINTN
+ShellHandleNoFromIndex (
+  IN UINTN        Value
+  );
+
+UINTN
+ShellHandleToIndex (
+  IN  EFI_HANDLE  Handle
+  );
+
+UINTN
+ShellHandleNoFromStr (
+  IN CHAR16       *Str
+  );
+
+UINTN
+ShellGetHandleNum (
+  VOID
+  );
+
+#endif
\ No newline at end of file
diff --git a/include/PeImage.h b/include/PeImage.h
new file mode 100644 (file)
index 0000000..be4043f
--- /dev/null
@@ -0,0 +1,776 @@
+/** @file
+  EFI image format for PE32, PE32+ and TE. Please note some data structures are 
+  different for PE32 and PE32+. EFI_IMAGE_NT_HEADERS32 is for PE32 and 
+  EFI_IMAGE_NT_HEADERS64 is for PE32+. 
+
+  This file is coded to the Visual Studio, Microsoft Portable Executable and 
+  Common Object File Format Specification, Revision 8.0 - May 16, 2006. 
+  This file also includes some definitions in PI Specification, Revision 1.0.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
+This program and the accompanying materials                          
+are licensed and made available under the terms and conditions of the BSD License         
+which accompanies this distribution.  The full text of the license may be found at        
+http://opensource.org/licenses/bsd-license.php.                                           
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             
+
+**/
+
+#ifndef __PE_IMAGE_H__
+#define __PE_IMAGE_H__
+
+#define SIGNATURE_16(A, B)        ((A) | (B << 8))
+#define SIGNATURE_32(A, B, C, D)  (SIGNATURE_16 (A, B) | (SIGNATURE_16 (C, D) << 16))
+#define SIGNATURE_64(A, B, C, D, E, F, G, H) \
+       (SIGNATURE_32 (A, B, C, D) | ((UINT64) (SIGNATURE_32 (E, F, G, H)) << 32))
+
+#define ALIGN_VALUE(Value, Alignment) ((Value) + (((Alignment) - (Value)) & ((Alignment) - 1)))
+#define ALIGN_POINTER(Pointer, Alignment) ((VOID *) (ALIGN_VALUE ((UINTN)(Pointer), (Alignment))))
+
+//
+// PE32+ Subsystem type for EFI images
+//
+#define EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION         10
+#define EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11
+#define EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER      12
+#define EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER      13 ///< defined PI Specification, 1.0
+
+
+//
+// PE32+ Machine type for EFI images
+//
+#define IMAGE_FILE_MACHINE_I386            0x014c
+#define IMAGE_FILE_MACHINE_IA64            0x0200
+#define IMAGE_FILE_MACHINE_EBC             0x0EBC
+#define IMAGE_FILE_MACHINE_X64             0x8664
+#define IMAGE_FILE_MACHINE_ARMTHUMB_MIXED  0x01c2
+
+//
+// EXE file formats
+//
+#define EFI_IMAGE_DOS_SIGNATURE     SIGNATURE_16('M', 'Z')
+#define EFI_IMAGE_OS2_SIGNATURE     SIGNATURE_16('N', 'E')
+#define EFI_IMAGE_OS2_SIGNATURE_LE  SIGNATURE_16('L', 'E')
+#define EFI_IMAGE_NT_SIGNATURE      SIGNATURE_32('P', 'E', '\0', '\0')
+
+///
+/// PE images can start with an optional DOS header, so if an image is run
+/// under DOS it can print an error message.
+///
+typedef struct {
+  UINT16  e_magic;    ///< Magic number.
+  UINT16  e_cblp;     ///< Bytes on last page of file.
+  UINT16  e_cp;       ///< Pages in file.
+  UINT16  e_crlc;     ///< Relocations.
+  UINT16  e_cparhdr;  ///< Size of header in paragraphs.
+  UINT16  e_minalloc; ///< Minimum extra paragraphs needed.
+  UINT16  e_maxalloc; ///< Maximum extra paragraphs needed.
+  UINT16  e_ss;       ///< Initial (relative) SS value.
+  UINT16  e_sp;       ///< Initial SP value.
+  UINT16  e_csum;     ///< Checksum.
+  UINT16  e_ip;       ///< Initial IP value.
+  UINT16  e_cs;       ///< Initial (relative) CS value.
+  UINT16  e_lfarlc;   ///< File address of relocation table.
+  UINT16  e_ovno;     ///< Overlay number.
+  UINT16  e_res[4];   ///< Reserved words.
+  UINT16  e_oemid;    ///< OEM identifier (for e_oeminfo).
+  UINT16  e_oeminfo;  ///< OEM information; e_oemid specific.
+  UINT16  e_res2[10]; ///< Reserved words.
+  UINT32  e_lfanew;   ///< File address of new exe header.
+} EFI_IMAGE_DOS_HEADER;
+
+///
+/// COFF File Header (Object and Image).
+///
+typedef struct {
+  UINT16  Machine;
+  UINT16  NumberOfSections;
+  UINT32  TimeDateStamp;
+  UINT32  PointerToSymbolTable;
+  UINT32  NumberOfSymbols;
+  UINT16  SizeOfOptionalHeader;
+  UINT16  Characteristics;
+} EFI_IMAGE_FILE_HEADER;
+
+///
+/// Size of EFI_IMAGE_FILE_HEADER.
+///
+#define EFI_IMAGE_SIZEOF_FILE_HEADER        20
+
+//
+// Characteristics
+//
+#define EFI_IMAGE_FILE_RELOCS_STRIPPED      (1 << 0)     ///< 0x0001  Relocation info stripped from file.
+#define EFI_IMAGE_FILE_EXECUTABLE_IMAGE     (1 << 1)     ///< 0x0002  File is executable  (i.e. no unresolved externel references).
+#define EFI_IMAGE_FILE_LINE_NUMS_STRIPPED   (1 << 2)     ///< 0x0004  Line nunbers stripped from file.
+#define EFI_IMAGE_FILE_LOCAL_SYMS_STRIPPED  (1 << 3)     ///< 0x0008  Local symbols stripped from file.
+#define EFI_IMAGE_FILE_BYTES_REVERSED_LO    (1 << 7)     ///< 0x0080  Bytes of machine word are reversed.
+#define EFI_IMAGE_FILE_32BIT_MACHINE        (1 << 8)     ///< 0x0100  32 bit word machine.
+#define EFI_IMAGE_FILE_DEBUG_STRIPPED       (1 << 9)     ///< 0x0200  Debugging info stripped from file in .DBG file.
+#define EFI_IMAGE_FILE_SYSTEM               (1 << 12)    ///< 0x1000  System File.
+#define EFI_IMAGE_FILE_DLL                  (1 << 13)    ///< 0x2000  File is a DLL.
+#define EFI_IMAGE_FILE_BYTES_REVERSED_HI    (1 << 15)    ///< 0x8000  Bytes of machine word are reversed.
+
+///
+/// Header Data Directories.
+///
+typedef struct {
+  UINT32  VirtualAddress;
+  UINT32  Size;
+} EFI_IMAGE_DATA_DIRECTORY;
+
+//
+// Directory Entries
+//
+#define EFI_IMAGE_DIRECTORY_ENTRY_EXPORT      0
+#define EFI_IMAGE_DIRECTORY_ENTRY_IMPORT      1
+#define EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE    2
+#define EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION   3
+#define EFI_IMAGE_DIRECTORY_ENTRY_SECURITY    4
+#define EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC   5
+#define EFI_IMAGE_DIRECTORY_ENTRY_DEBUG       6
+#define EFI_IMAGE_DIRECTORY_ENTRY_COPYRIGHT   7
+#define EFI_IMAGE_DIRECTORY_ENTRY_GLOBALPTR   8
+#define EFI_IMAGE_DIRECTORY_ENTRY_TLS         9
+#define EFI_IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10
+
+#define EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES 16
+
+///
+/// @attention
+/// EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC means PE32 and 
+/// EFI_IMAGE_OPTIONAL_HEADER32 must be used. The data structures only vary
+/// after NT additional fields.
+///
+#define EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b
+          
+///
+/// Optional Header Standard Fields for PE32.
+///
+typedef struct {
+  ///
+  /// Standard fields.
+  ///
+  UINT16                    Magic;
+  UINT8                     MajorLinkerVersion;
+  UINT8                     MinorLinkerVersion;
+  UINT32                    SizeOfCode;
+  UINT32                    SizeOfInitializedData;
+  UINT32                    SizeOfUninitializedData;
+  UINT32                    AddressOfEntryPoint;
+  UINT32                    BaseOfCode;
+  UINT32                    BaseOfData;  ///< PE32 contains this additional field, which is absent in PE32+.
+  ///
+  /// Optional Header Windows-Specific Fields.
+  ///
+  UINT32                    ImageBase;
+  UINT32                    SectionAlignment;
+  UINT32                    FileAlignment;
+  UINT16                    MajorOperatingSystemVersion;
+  UINT16                    MinorOperatingSystemVersion;
+  UINT16                    MajorImageVersion;
+  UINT16                    MinorImageVersion;
+  UINT16                    MajorSubsystemVersion;
+  UINT16                    MinorSubsystemVersion;
+  UINT32                    Win32VersionValue;
+  UINT32                    SizeOfImage;
+  UINT32                    SizeOfHeaders;
+  UINT32                    CheckSum;
+  UINT16                    Subsystem;
+  UINT16                    DllCharacteristics;
+  UINT32                    SizeOfStackReserve;
+  UINT32                    SizeOfStackCommit;
+  UINT32                    SizeOfHeapReserve;
+  UINT32                    SizeOfHeapCommit;
+  UINT32                    LoaderFlags;
+  UINT32                    NumberOfRvaAndSizes;
+  EFI_IMAGE_DATA_DIRECTORY  DataDirectory[EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES];
+} EFI_IMAGE_OPTIONAL_HEADER32;
+
+///
+/// @attention
+/// EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC means PE32+ and 
+/// EFI_IMAGE_OPTIONAL_HEADER64 must be used. The data structures only vary
+/// after NT additional fields.
+///
+#define EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b
+
+///
+/// Optional Header Standard Fields for PE32+.
+///
+typedef struct {
+  ///
+  /// Standard fields.
+  ///
+  UINT16                    Magic;
+  UINT8                     MajorLinkerVersion;
+  UINT8                     MinorLinkerVersion;
+  UINT32                    SizeOfCode;
+  UINT32                    SizeOfInitializedData;
+  UINT32                    SizeOfUninitializedData;
+  UINT32                    AddressOfEntryPoint;
+  UINT32                    BaseOfCode;
+  ///
+  /// Optional Header Windows-Specific Fields.
+  ///
+  UINT64                    ImageBase;
+  UINT32                    SectionAlignment;
+  UINT32                    FileAlignment;
+  UINT16                    MajorOperatingSystemVersion;
+  UINT16                    MinorOperatingSystemVersion;
+  UINT16                    MajorImageVersion;
+  UINT16                    MinorImageVersion;
+  UINT16                    MajorSubsystemVersion;
+  UINT16                    MinorSubsystemVersion;
+  UINT32                    Win32VersionValue;
+  UINT32                    SizeOfImage;
+  UINT32                    SizeOfHeaders;
+  UINT32                    CheckSum;
+  UINT16                    Subsystem;
+  UINT16                    DllCharacteristics;
+  UINT64                    SizeOfStackReserve;
+  UINT64                    SizeOfStackCommit;
+  UINT64                    SizeOfHeapReserve;
+  UINT64                    SizeOfHeapCommit;
+  UINT32                    LoaderFlags;
+  UINT32                    NumberOfRvaAndSizes;
+  EFI_IMAGE_DATA_DIRECTORY  DataDirectory[EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES];
+} EFI_IMAGE_OPTIONAL_HEADER64;
+
+///
+/// @attention
+/// EFI_IMAGE_NT_HEADERS32 is for use ONLY by tools.
+///
+typedef struct {
+  UINT32                      Signature;
+  EFI_IMAGE_FILE_HEADER       FileHeader;
+  EFI_IMAGE_OPTIONAL_HEADER32 OptionalHeader;
+} EFI_IMAGE_NT_HEADERS32;
+
+#define EFI_IMAGE_SIZEOF_NT_OPTIONAL32_HEADER sizeof (EFI_IMAGE_NT_HEADERS32)
+
+///
+/// @attention
+/// EFI_IMAGE_HEADERS64 is for use ONLY by tools.
+///
+typedef struct {
+  UINT32                      Signature;
+  EFI_IMAGE_FILE_HEADER       FileHeader;
+  EFI_IMAGE_OPTIONAL_HEADER64 OptionalHeader;
+} EFI_IMAGE_NT_HEADERS64;
+
+#define EFI_IMAGE_SIZEOF_NT_OPTIONAL64_HEADER sizeof (EFI_IMAGE_NT_HEADERS64)
+
+//
+// Other Windows Subsystem Values
+//
+#define EFI_IMAGE_SUBSYSTEM_UNKNOWN     0
+#define EFI_IMAGE_SUBSYSTEM_NATIVE      1
+#define EFI_IMAGE_SUBSYSTEM_WINDOWS_GUI 2
+#define EFI_IMAGE_SUBSYSTEM_WINDOWS_CUI 3
+#define EFI_IMAGE_SUBSYSTEM_OS2_CUI     5
+#define EFI_IMAGE_SUBSYSTEM_POSIX_CUI   7
+
+///
+/// Length of ShortName.
+///
+#define EFI_IMAGE_SIZEOF_SHORT_NAME 8
+
+///
+/// Section Table. This table immediately follows the optional header.
+///
+typedef struct {
+  UINT8 Name[EFI_IMAGE_SIZEOF_SHORT_NAME];
+  union {
+    UINT32  PhysicalAddress;
+    UINT32  VirtualSize;
+  } Misc;
+  UINT32  VirtualAddress;
+  UINT32  SizeOfRawData;
+  UINT32  PointerToRawData;
+  UINT32  PointerToRelocations;
+  UINT32  PointerToLinenumbers;
+  UINT16  NumberOfRelocations;
+  UINT16  NumberOfLinenumbers;
+  UINT32  Characteristics;
+} EFI_IMAGE_SECTION_HEADER;
+
+///
+/// Size of EFI_IMAGE_SECTION_HEADER.
+///
+#define EFI_IMAGE_SIZEOF_SECTION_HEADER       40
+         
+//
+// Section Flags Values
+//
+#define EFI_IMAGE_SCN_TYPE_NO_PAD                  BIT3   ///< 0x00000008  ///< Reserved.
+#define EFI_IMAGE_SCN_CNT_CODE                     BIT5   ///< 0x00000020
+#define EFI_IMAGE_SCN_CNT_INITIALIZED_DATA         BIT6   ///< 0x00000040
+#define EFI_IMAGE_SCN_CNT_UNINITIALIZED_DATA       BIT7   ///< 0x00000080
+                                                   
+#define EFI_IMAGE_SCN_LNK_OTHER                    BIT8   ///< 0x00000100  ///< Reserved.
+#define EFI_IMAGE_SCN_LNK_INFO                     BIT9   ///< 0x00000200  ///< Section contains comments or some other type of information.
+#define EFI_IMAGE_SCN_LNK_REMOVE                   BIT11  ///< 0x00000800  ///< Section contents will not become part of image.
+#define EFI_IMAGE_SCN_LNK_COMDAT                   BIT12  ///< 0x00001000
+                                                   
+#define EFI_IMAGE_SCN_ALIGN_1BYTES                 BIT20  ///< 0x00100000
+#define EFI_IMAGE_SCN_ALIGN_2BYTES                 BIT21  ///< 0x00200000
+#define EFI_IMAGE_SCN_ALIGN_4BYTES          (BIT20|BIT21) ///< 0x00300000
+#define EFI_IMAGE_SCN_ALIGN_8BYTES                 BIT22  ///< 0x00400000
+#define EFI_IMAGE_SCN_ALIGN_16BYTES         (BIT20|BIT22) ///< 0x00500000
+#define EFI_IMAGE_SCN_ALIGN_32BYTES         (BIT21|BIT22) ///< 0x00600000
+#define EFI_IMAGE_SCN_ALIGN_64BYTES   (BIT20|BIT21|BIT22) ///< 0x00700000
+                                              
+#define EFI_IMAGE_SCN_MEM_DISCARDABLE              BIT25  ///< 0x02000000
+#define EFI_IMAGE_SCN_MEM_NOT_CACHED               BIT26  ///< 0x04000000
+#define EFI_IMAGE_SCN_MEM_NOT_PAGED                BIT27  ///< 0x08000000
+#define EFI_IMAGE_SCN_MEM_SHARED                   BIT28  ///< 0x10000000
+#define EFI_IMAGE_SCN_MEM_EXECUTE                  BIT29  ///< 0x20000000
+#define EFI_IMAGE_SCN_MEM_READ                     BIT30  ///< 0x40000000
+#define EFI_IMAGE_SCN_MEM_WRITE                    BIT31  ///< 0x80000000
+
+///
+/// Size of a Symbol Table Record.
+///
+#define EFI_IMAGE_SIZEOF_SYMBOL 18
+
+//
+// Symbols have a section number of the section in which they are
+// defined. Otherwise, section numbers have the following meanings:
+//
+#define EFI_IMAGE_SYM_UNDEFINED (UINT16) 0  ///< Symbol is undefined or is common.
+#define EFI_IMAGE_SYM_ABSOLUTE  (UINT16) -1 ///< Symbol is an absolute value.
+#define EFI_IMAGE_SYM_DEBUG     (UINT16) -2 ///< Symbol is a special debug item.
+
+//
+// Symbol Type (fundamental) values.
+//
+#define EFI_IMAGE_SYM_TYPE_NULL   0   ///< no type.
+#define EFI_IMAGE_SYM_TYPE_VOID   1   ///< no valid type.
+#define EFI_IMAGE_SYM_TYPE_CHAR   2   ///< type character.
+#define EFI_IMAGE_SYM_TYPE_SHORT  3   ///< type short integer.
+#define EFI_IMAGE_SYM_TYPE_INT    4
+#define EFI_IMAGE_SYM_TYPE_LONG   5
+#define EFI_IMAGE_SYM_TYPE_FLOAT  6
+#define EFI_IMAGE_SYM_TYPE_DOUBLE 7
+#define EFI_IMAGE_SYM_TYPE_STRUCT 8
+#define EFI_IMAGE_SYM_TYPE_UNION  9
+#define EFI_IMAGE_SYM_TYPE_ENUM   10  ///< enumeration.
+#define EFI_IMAGE_SYM_TYPE_MOE    11  ///< member of enumeration.
+#define EFI_IMAGE_SYM_TYPE_BYTE   12
+#define EFI_IMAGE_SYM_TYPE_WORD   13
+#define EFI_IMAGE_SYM_TYPE_UINT   14
+#define EFI_IMAGE_SYM_TYPE_DWORD  15
+
+//
+// Symbol Type (derived) values.
+//
+#define EFI_IMAGE_SYM_DTYPE_NULL      0 ///< no derived type.
+#define EFI_IMAGE_SYM_DTYPE_POINTER   1
+#define EFI_IMAGE_SYM_DTYPE_FUNCTION  2
+#define EFI_IMAGE_SYM_DTYPE_ARRAY     3
+
+//
+// Storage classes.
+//
+#define EFI_IMAGE_SYM_CLASS_END_OF_FUNCTION   ((UINT8) -1)
+#define EFI_IMAGE_SYM_CLASS_NULL              0
+#define EFI_IMAGE_SYM_CLASS_AUTOMATIC         1
+#define EFI_IMAGE_SYM_CLASS_EXTERNAL          2
+#define EFI_IMAGE_SYM_CLASS_STATIC            3
+#define EFI_IMAGE_SYM_CLASS_REGISTER          4
+#define EFI_IMAGE_SYM_CLASS_EXTERNAL_DEF      5
+#define EFI_IMAGE_SYM_CLASS_LABEL             6
+#define EFI_IMAGE_SYM_CLASS_UNDEFINED_LABEL   7
+#define EFI_IMAGE_SYM_CLASS_MEMBER_OF_STRUCT  8
+#define EFI_IMAGE_SYM_CLASS_ARGUMENT          9
+#define EFI_IMAGE_SYM_CLASS_STRUCT_TAG        10
+#define EFI_IMAGE_SYM_CLASS_MEMBER_OF_UNION   11
+#define EFI_IMAGE_SYM_CLASS_UNION_TAG         12
+#define EFI_IMAGE_SYM_CLASS_TYPE_DEFINITION   13
+#define EFI_IMAGE_SYM_CLASS_UNDEFINED_STATIC  14
+#define EFI_IMAGE_SYM_CLASS_ENUM_TAG          15
+#define EFI_IMAGE_SYM_CLASS_MEMBER_OF_ENUM    16
+#define EFI_IMAGE_SYM_CLASS_REGISTER_PARAM    17
+#define EFI_IMAGE_SYM_CLASS_BIT_FIELD         18
+#define EFI_IMAGE_SYM_CLASS_BLOCK             100
+#define EFI_IMAGE_SYM_CLASS_FUNCTION          101
+#define EFI_IMAGE_SYM_CLASS_END_OF_STRUCT     102
+#define EFI_IMAGE_SYM_CLASS_FILE              103
+#define EFI_IMAGE_SYM_CLASS_SECTION           104
+#define EFI_IMAGE_SYM_CLASS_WEAK_EXTERNAL     105
+
+//
+// type packing constants
+//
+#define EFI_IMAGE_N_BTMASK  017
+#define EFI_IMAGE_N_TMASK   060
+#define EFI_IMAGE_N_TMASK1  0300
+#define EFI_IMAGE_N_TMASK2  0360
+#define EFI_IMAGE_N_BTSHFT  4
+#define EFI_IMAGE_N_TSHIFT  2
+
+//
+// Communal selection types.
+//
+#define EFI_IMAGE_COMDAT_SELECT_NODUPLICATES    1
+#define EFI_IMAGE_COMDAT_SELECT_ANY             2
+#define EFI_IMAGE_COMDAT_SELECT_SAME_SIZE       3
+#define EFI_IMAGE_COMDAT_SELECT_EXACT_MATCH     4
+#define EFI_IMAGE_COMDAT_SELECT_ASSOCIATIVE     5
+                                       
+//
+// the following values only be referred in PeCoff, not defined in PECOFF.
+//
+#define EFI_IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY  1
+#define EFI_IMAGE_WEAK_EXTERN_SEARCH_LIBRARY    2
+#define EFI_IMAGE_WEAK_EXTERN_SEARCH_ALIAS      3
+
+///
+/// Relocation format.
+///
+typedef struct {
+  UINT32  VirtualAddress;
+  UINT32  SymbolTableIndex;
+  UINT16  Type;
+} EFI_IMAGE_RELOCATION;
+
+///
+/// Size of EFI_IMAGE_RELOCATION
+///
+#define EFI_IMAGE_SIZEOF_RELOCATION 10
+
+//
+// I386 relocation types.
+//
+#define EFI_IMAGE_REL_I386_ABSOLUTE 0x0000  ///< Reference is absolute, no relocation is necessary.
+#define EFI_IMAGE_REL_I386_DIR16    0x0001  ///< Direct 16-bit reference to the symbols virtual address.
+#define EFI_IMAGE_REL_I386_REL16    0x0002  ///< PC-relative 16-bit reference to the symbols virtual address.
+#define EFI_IMAGE_REL_I386_DIR32    0x0006  ///< Direct 32-bit reference to the symbols virtual address.
+#define EFI_IMAGE_REL_I386_DIR32NB  0x0007  ///< Direct 32-bit reference to the symbols virtual address, base not included.
+#define EFI_IMAGE_REL_I386_SEG12    0x0009  ///< Direct 16-bit reference to the segment-selector bits of a 32-bit virtual address.
+#define EFI_IMAGE_REL_I386_SECTION  0x000A
+#define EFI_IMAGE_REL_I386_SECREL   0x000B
+#define EFI_IMAGE_REL_I386_REL32    0x0014  ///< PC-relative 32-bit reference to the symbols virtual address.
+
+// 
+// x64 processor relocation types.
+// 
+#define IMAGE_REL_AMD64_ABSOLUTE  0x0000
+#define IMAGE_REL_AMD64_ADDR64    0x0001
+#define IMAGE_REL_AMD64_ADDR32    0x0002
+#define IMAGE_REL_AMD64_ADDR32NB  0x0003
+#define IMAGE_REL_AMD64_REL32     0x0004
+#define IMAGE_REL_AMD64_REL32_1   0x0005
+#define IMAGE_REL_AMD64_REL32_2   0x0006
+#define IMAGE_REL_AMD64_REL32_3   0x0007
+#define IMAGE_REL_AMD64_REL32_4   0x0008
+#define IMAGE_REL_AMD64_REL32_5   0x0009
+#define IMAGE_REL_AMD64_SECTION   0x000A
+#define IMAGE_REL_AMD64_SECREL    0x000B
+#define IMAGE_REL_AMD64_SECREL7   0x000C
+#define IMAGE_REL_AMD64_TOKEN     0x000D
+#define IMAGE_REL_AMD64_SREL32    0x000E
+#define IMAGE_REL_AMD64_PAIR      0x000F
+#define IMAGE_REL_AMD64_SSPAN32   0x0010
+
+///
+/// Based relocation format.
+///
+typedef struct {
+  UINT32  VirtualAddress;
+  UINT32  SizeOfBlock;
+} EFI_IMAGE_BASE_RELOCATION;
+
+///
+/// Size of EFI_IMAGE_BASE_RELOCATION.
+///
+#define EFI_IMAGE_SIZEOF_BASE_RELOCATION  8
+
+//
+// Based relocation types.
+//
+#define EFI_IMAGE_REL_BASED_ABSOLUTE        0
+#define EFI_IMAGE_REL_BASED_HIGH            1
+#define EFI_IMAGE_REL_BASED_LOW             2
+#define EFI_IMAGE_REL_BASED_HIGHLOW         3
+#define EFI_IMAGE_REL_BASED_HIGHADJ         4
+#define EFI_IMAGE_REL_BASED_MIPS_JMPADDR    5
+#define EFI_IMAGE_REL_BASED_ARM_MOV32A      5
+#define EFI_IMAGE_REL_BASED_ARM_MOV32T      7
+#define EFI_IMAGE_REL_BASED_IA64_IMM64      9
+#define EFI_IMAGE_REL_BASED_MIPS_JMPADDR16  9
+#define EFI_IMAGE_REL_BASED_DIR64           10
+
+///
+/// Line number format.
+///
+typedef struct {
+  union {
+    UINT32  SymbolTableIndex; ///< Symbol table index of function name if Linenumber is 0.
+    UINT32  VirtualAddress;   ///< Virtual address of line number.
+  } Type;
+  UINT16  Linenumber;         ///< Line number.
+} EFI_IMAGE_LINENUMBER;
+
+///
+/// Size of EFI_IMAGE_LINENUMBER.
+///
+#define EFI_IMAGE_SIZEOF_LINENUMBER 6
+
+//
+// Archive format.
+//
+#define EFI_IMAGE_ARCHIVE_START_SIZE        8
+#define EFI_IMAGE_ARCHIVE_START             "!<arch>\n"
+#define EFI_IMAGE_ARCHIVE_END               "`\n"
+#define EFI_IMAGE_ARCHIVE_PAD               "\n"
+#define EFI_IMAGE_ARCHIVE_LINKER_MEMBER     "/               "
+#define EFI_IMAGE_ARCHIVE_LONGNAMES_MEMBER  "//              "
+
+///
+/// Archive Member Headers
+///
+typedef struct {
+  UINT8 Name[16];     ///< File member name - `/' terminated.
+  UINT8 Date[12];     ///< File member date - decimal.
+  UINT8 UserID[6];    ///< File member user id - decimal.
+  UINT8 GroupID[6];   ///< File member group id - decimal.
+  UINT8 Mode[8];      ///< File member mode - octal.
+  UINT8 Size[10];     ///< File member size - decimal.
+  UINT8 EndHeader[2]; ///< String to end header. (0x60 0x0A).
+} EFI_IMAGE_ARCHIVE_MEMBER_HEADER;
+
+///
+/// Size of EFI_IMAGE_ARCHIVE_MEMBER_HEADER.
+///
+#define EFI_IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR 60
+
+
+//
+// DLL Support
+//
+
+///
+/// Export Directory Table.
+///
+typedef struct {
+  UINT32  Characteristics;
+  UINT32  TimeDateStamp;
+  UINT16  MajorVersion;
+  UINT16  MinorVersion;
+  UINT32  Name;
+  UINT32  Base;
+  UINT32  NumberOfFunctions;
+  UINT32  NumberOfNames;
+  UINT32  AddressOfFunctions;
+  UINT32  AddressOfNames;
+  UINT32  AddressOfNameOrdinals;
+} EFI_IMAGE_EXPORT_DIRECTORY;
+
+///
+/// Hint/Name Table.
+///
+typedef struct {
+  UINT16  Hint;
+  UINT8   Name[1];
+} EFI_IMAGE_IMPORT_BY_NAME;
+
+///
+/// Import Address Table RVA (Thunk Table).
+///
+typedef struct {
+  union {
+    UINT32                    Function;
+    UINT32                    Ordinal;
+    EFI_IMAGE_IMPORT_BY_NAME  *AddressOfData;
+  } u1;
+} EFI_IMAGE_THUNK_DATA;
+
+#define EFI_IMAGE_ORDINAL_FLAG              BIT31    ///< Flag for PE32.
+#define EFI_IMAGE_SNAP_BY_ORDINAL(Ordinal)  ((Ordinal & EFI_IMAGE_ORDINAL_FLAG) != 0)
+#define EFI_IMAGE_ORDINAL(Ordinal)          (Ordinal & 0xffff)
+
+///
+/// Import Directory Table
+///
+typedef struct {
+  UINT32                Characteristics;
+  UINT32                TimeDateStamp;
+  UINT32                ForwarderChain;
+  UINT32                Name;
+  EFI_IMAGE_THUNK_DATA  *FirstThunk;
+} EFI_IMAGE_IMPORT_DESCRIPTOR;
+
+///
+/// Debug Directory Format.
+///
+typedef struct {
+  UINT32  Characteristics;
+  UINT32  TimeDateStamp;
+  UINT16  MajorVersion;
+  UINT16  MinorVersion;
+  UINT32  Type;
+  UINT32  SizeOfData;
+  UINT32  RVA;           ///< The address of the debug data when loaded, relative to the image base.
+  UINT32  FileOffset;    ///< The file pointer to the debug data.
+} EFI_IMAGE_DEBUG_DIRECTORY_ENTRY;
+
+#define EFI_IMAGE_DEBUG_TYPE_CODEVIEW 2     ///< The Visual C++ debug information.
+
+///
+/// Debug Data Structure defined in Microsoft C++.
+///
+#define CODEVIEW_SIGNATURE_NB10  SIGNATURE_32('N', 'B', '1', '0')
+typedef struct {
+  UINT32  Signature;                        ///< "NB10"
+  UINT32  Unknown;
+  UINT32  Unknown2;
+  UINT32  Unknown3;
+  //
+  // Filename of .PDB goes here
+  //
+} EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY;
+
+///
+/// Debug Data Structure defined in Microsoft C++.
+///
+#define CODEVIEW_SIGNATURE_RSDS  SIGNATURE_32('R', 'S', 'D', 'S')
+typedef struct {
+  UINT32  Signature;                        ///< "RSDS".
+  UINT32  Unknown;
+  UINT32  Unknown2;
+  UINT32  Unknown3;
+  UINT32  Unknown4;
+  UINT32  Unknown5;
+  //
+  // Filename of .PDB goes here
+  //
+} EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY;
+
+
+///
+/// Debug Data Structure defined by Apple Mach-O to Coff utility.
+///
+#define CODEVIEW_SIGNATURE_MTOC  SIGNATURE_32('M', 'T', 'O', 'C')
+typedef struct {
+  UINT32    Signature;                       ///< "MTOC".
+  EFI_GUID      MachOUuid;
+  //
+  //  Filename of .DLL (Mach-O with debug info) goes here
+  //
+} EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY;
+
+///
+/// Resource format.
+///
+typedef struct {
+  UINT32  Characteristics;
+  UINT32  TimeDateStamp;
+  UINT16  MajorVersion;
+  UINT16  MinorVersion;
+  UINT16  NumberOfNamedEntries;
+  UINT16  NumberOfIdEntries;
+  //
+  // Array of EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY entries goes here.
+  //
+} EFI_IMAGE_RESOURCE_DIRECTORY;
+
+///
+/// Resource directory entry format.
+///
+typedef struct {
+  union {
+    struct {
+      UINT32  NameOffset:31;
+      UINT32  NameIsString:1;
+    } s;
+    UINT32  Id;
+  } u1;
+  union {
+    UINT32  OffsetToData;
+    struct {
+      UINT32  OffsetToDirectory:31;
+      UINT32  DataIsDirectory:1;
+    } s;
+  } u2;
+} EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY;
+
+///
+/// Resource directory entry for string.
+///
+typedef struct {
+  UINT16  Length;
+  CHAR16  String[1];
+} EFI_IMAGE_RESOURCE_DIRECTORY_STRING;
+
+///
+/// Resource directory entry for data array.
+///
+typedef struct {
+  UINT32  OffsetToData;
+  UINT32  Size;
+  UINT32  CodePage;
+  UINT32  Reserved;
+} EFI_IMAGE_RESOURCE_DATA_ENTRY;
+
+///
+/// Header format for TE images, defined in the PI Specification, 1.0.
+///
+typedef struct {
+  UINT16                    Signature;            ///< The signature for TE format = "VZ".
+  UINT16                    Machine;              ///< From the original file header.
+  UINT8                     NumberOfSections;     ///< From the original file header.
+  UINT8                     Subsystem;            ///< From original optional header.
+  UINT16                    StrippedSize;         ///< Number of bytes we removed from the header.
+  UINT32                    AddressOfEntryPoint;  ///< Offset to entry point -- from original optional header.
+  UINT32                    BaseOfCode;           ///< From original image -- required for ITP debug.
+  UINT64                    ImageBase;            ///< From original file header.
+  EFI_IMAGE_DATA_DIRECTORY  DataDirectory[2];     ///< Only base relocation and debug directory.
+} EFI_TE_IMAGE_HEADER;
+
+
+#define EFI_TE_IMAGE_HEADER_SIGNATURE  SIGNATURE_16('V', 'Z')
+
+//
+// Data directory indexes in our TE image header
+//
+#define EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC  0
+#define EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG      1
+
+
+///
+/// Union of PE32, PE32+, and TE headers.
+///
+typedef union {
+  EFI_IMAGE_NT_HEADERS32   Pe32;
+  EFI_IMAGE_NT_HEADERS64   Pe32Plus;
+  EFI_TE_IMAGE_HEADER      Te;
+} EFI_IMAGE_OPTIONAL_HEADER_UNION;
+
+typedef union {
+  EFI_IMAGE_NT_HEADERS32            *Pe32;
+  EFI_IMAGE_NT_HEADERS64            *Pe32Plus;
+  EFI_TE_IMAGE_HEADER               *Te;
+  EFI_IMAGE_OPTIONAL_HEADER_UNION   *Union;
+} EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION;
+
+typedef struct _WIN_CERTIFICATE {
+       UINT32  dwLength;
+       UINT16  wRevision;
+       UINT16  wCertificateType;
+       //UINT8 bCertificate[ANYSIZE_ARRAY];
+} WIN_CERTIFICATE;
+
+typedef struct {
+       WIN_CERTIFICATE Hdr;
+       UINT8           CertData[1];
+} WIN_CERTIFICATE_EFI_PKCS;
+
+#define SHA256_DIGEST_SIZE  32
+#define WIN_CERT_TYPE_PKCS_SIGNED_DATA 0x0002
+
+#endif
diff --git a/include/PeImage2.h b/include/PeImage2.h
new file mode 100644 (file)
index 0000000..d5a19ce
--- /dev/null
@@ -0,0 +1,47 @@
+/** @file
+  EFI image format for PE32, PE32+ and TE. Please note some data structures are
+  different for PE32 and PE32+. EFI_IMAGE_NT_HEADERS32 is for PE32 and
+  EFI_IMAGE_NT_HEADERS64 is for PE32+.
+
+  This file is coded to the Visual Studio, Microsoft Portable Executable and
+  Common Object File Format Specification, Revision 8.0 - May 16, 2006.
+  This file also includes some definitions in PI Specification, Revision 1.0.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+/*
+ * Stripped down because the original file was flaking out on me and I just
+ * needed the one definition....
+ *
+ */
+
+#ifndef _PEIMAGE2_H_
+#define _PEIMAGE2_H_
+
+
+typedef struct _GNUEFI_PE_COFF_LOADER_IMAGE_CONTEXT {
+   UINT64                            ImageAddress;
+   UINT64                            ImageSize;
+   UINT64                            EntryPoint; 
+   UINTN                             SizeOfHeaders;
+   UINT16                            ImageType;
+   UINT16                            NumberOfSections;
+   EFI_IMAGE_SECTION_HEADER          *FirstSection;
+   EFI_IMAGE_DATA_DIRECTORY          *RelocDir;
+   EFI_IMAGE_DATA_DIRECTORY          *SecDir;
+   UINT64                            NumberOfRvaAndSizes;
+   EFI_IMAGE_OPTIONAL_HEADER_UNION   *PEHdr;
+} GNUEFI_PE_COFF_LOADER_IMAGE_CONTEXT;
+
+
+#endif
diff --git a/include/RemovableMedia.h b/include/RemovableMedia.h
new file mode 100644 (file)
index 0000000..75b2f62
--- /dev/null
@@ -0,0 +1,203 @@
+/*\r
+ * Copyright (c) 2005 Apple Computer, Inc.  All rights reserved.\r
+ *\r
+ * Module Name:\r
+ *\r
+ *     RemovableMedia.h\r
+ *\r
+ * Abstract:\r
+ *\r
+ *     Protocol interface for any device that supports removable media (i.e. optical drives).\r
+ *\r
+\r
+Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple\r
+Computer, Inc. ("Apple") in consideration of your agreement to the\r
+following terms, and your use, installation, modification or\r
+redistribution of this Apple software constitutes acceptance of these\r
+terms.  If you do not agree with these terms, please do not use,\r
+install, modify or redistribute this Apple software.\r
+\r
+In consideration of your agreement to abide by the following terms, and\r
+subject to these terms, Apple grants you a personal, non-exclusive\r
+license, under Apple's copyrights in this original Apple software (the\r
+"Apple Software"), to use, reproduce, modify and redistribute the Apple\r
+Software, with or without modifications, in source and/or binary forms;\r
+provided that if you redistribute the Apple Software in its entirety and\r
+without modifications, you must retain this notice and the following\r
+text and disclaimers in all such redistributions of the Apple Software. \r
+Neither the name, trademarks, service marks or logos of Apple Computer,\r
+Inc. may be used to endorse or promote products derived from the Apple\r
+Software without specific prior written permission from Apple.  Except\r
+as expressly stated in this notice, no other rights or licenses, express\r
+or implied, are granted by Apple herein, including but not limited to\r
+any patent rights that may be infringed by your derivative works or by\r
+other works in which the Apple Software may be incorporated.\r
+\r
+The Apple Software is provided by Apple on an "AS IS" basis.  APPLE\r
+MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION\r
+THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS\r
+FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND\r
+OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.\r
+\r
+IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL\r
+OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,\r
+MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED\r
+AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),\r
+STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE\r
+POSSIBILITY OF SUCH DAMAGE.\r
+\r
+Copyright Â© 2006 Apple Computer, Inc., All Rights Reserved\r
+\r
+ */\r
+\r
+#ifndef _APPLE_REMOVABLE_MEDIA_H\r
+#define _APPLE_REMOVABLE_MEDIA_H\r
+\r
+//\r
+// Global Id for Removable_Media Interface\r
+//\r
+// {2EA9743A-23D9-425e-872C-F615AA195788}\r
+#define APPLE_REMOVABLE_MEDIA_PROTOCOL_GUID \\r
+  { \\r
+    0x2ea9743a, 0x23d9, 0x425e, { 0x87, 0x2c, 0xf6, 0x15, 0xaa, 0x19, 0x57, 0x88 } \\r
+  }\r
+\r
+#define        APPLE_REMOVABLE_MEDIA_PROTOCOL_REVISION         0x00000001\r
+\r
+// EFI_FORWARD_DECLARATION (APPLE_REMOVABLE_MEDIA_PROTOCOL);\r
+typedef struct _APPLE_REMOVABLE_MEDIA_PROTOCOL APPLE_REMOVABLE_MEDIA_PROTOCOL;\r
+\r
+//\r
+// Eject\r
+//\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *APPLE_REMOVABLE_MEDIA_EJECT) (\r
+  IN APPLE_REMOVABLE_MEDIA_PROTOCOL                            * This\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+    Eject removable media from drive (such as a CD/DVD).\r
+\r
+  Arguments:\r
+    This                 - Protocol instance pointer.\r
+\r
+  Returns:\r
+    EFI_SUCCESS          - The media was ejected.\r
+\r
+--*/\r
+;\r
+\r
+//\r
+// Inject\r
+//\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *APPLE_REMOVABLE_MEDIA_INJECT) (\r
+  IN APPLE_REMOVABLE_MEDIA_PROTOCOL                            * This\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+    Inject removable media into drive (such as a CD/DVD).\r
+\r
+  Arguments:\r
+    This                 - Protocol instance pointer.\r
+\r
+  Returns:\r
+    EFI_SUCCESS          - The media was injected.\r
+\r
+--*/\r
+;\r
+\r
+//\r
+// Allow media to be ejected\r
+//\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *APPLE_REMOVABLE_MEDIA_ALLOW_REMOVAL) (\r
+  IN APPLE_REMOVABLE_MEDIA_PROTOCOL                            * This\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+    Allow the media to be removed from the drive.\r
+\r
+  Arguments:\r
+    This                 - Protocol instance pointer.\r
+\r
+  Returns:\r
+    EFI_SUCCESS          - The media can now be removed.\r
+       EFI_UNSUPPORTED      - The media cannot be removed.\r
+\r
+--*/\r
+;\r
+\r
+//\r
+// Prevent media from being ejected\r
+//\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *APPLE_REMOVABLE_MEDIA_PREVENT_REMOVAL) (\r
+  IN APPLE_REMOVABLE_MEDIA_PROTOCOL                            * This\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+    Prevent the media from being removed from the drive.\r
+\r
+  Arguments:\r
+    This                 - Protocol instance pointer.\r
+\r
+  Returns:\r
+    EFI_SUCCESS          - The drive is locked, and the media cannot be removed.\r
+       EFI_UNSUPPORTED      - The drive cannot be locked.\r
+\r
+--*/\r
+;\r
+\r
+//\r
+// Detect state of removable media tray\r
+//\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *APPLE_REMOVABLE_MEDIA_DETECT_TRAY_STATE) (\r
+  IN APPLE_REMOVABLE_MEDIA_PROTOCOL                            * This,\r
+  OUT BOOLEAN                                                                  * TrayOpen\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+    Get the status of the drive tray.\r
+\r
+  Arguments:\r
+    This                 - Protocol instance pointer.\r
+       TrayOpen             - Status of the drive tray.\r
+\r
+  Returns:\r
+    EFI_SUCCESS          - The status has been returned in TrayOpen.\r
+\r
+--*/\r
+;\r
+\r
+//\r
+// Protocol definition\r
+//\r
+struct _APPLE_REMOVABLE_MEDIA_PROTOCOL {\r
+  UINT32                                                                               Revision;\r
+  BOOLEAN                                                                              RemovalAllowed;\r
+  APPLE_REMOVABLE_MEDIA_EJECT                                  Eject;\r
+  APPLE_REMOVABLE_MEDIA_INJECT                                 Inject;\r
+  APPLE_REMOVABLE_MEDIA_ALLOW_REMOVAL                  AllowRemoval;\r
+  APPLE_REMOVABLE_MEDIA_PREVENT_REMOVAL                        PreventRemoval;\r
+  APPLE_REMOVABLE_MEDIA_DETECT_TRAY_STATE              DetectTrayState;\r
+\r
+};\r
+\r
+//extern EFI_GUID gAppleRemovableMediaProtocolGuid;\r
+\r
+#endif\r
+\r
diff --git a/include/egemb_arrow_left.h b/include/egemb_arrow_left.h
new file mode 100644 (file)
index 0000000..05234b0
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ * include/egemb_arrow_left.h
+ * An encoded left arrow icon
+ *
+ * Copyright (c) 2015 Roderick W. Smith
+ * All rights reserved.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+static const UINT8 egemb_arrow_left_data[2175] = {
+ 0xf9, 0xff, 0x8b, 0x00, 0x9d, 0xff, 0x8e, 0x00, 0x9a, 0xff, 0x90, 0x00,
+ 0x98, 0xff, 0x92, 0x00, 0x97, 0xff, 0x93, 0x00, 0x95, 0xff, 0x95, 0x00,
+ 0x93, 0xff, 0x97, 0x00, 0x91, 0xff, 0x99, 0x00, 0x90, 0xff, 0x9a, 0x00,
+ 0x8e, 0xff, 0x9c, 0x00, 0x8d, 0xff, 0x9d, 0x00, 0x8b, 0xff, 0x9f, 0x00,
+ 0x89, 0xff, 0xa1, 0x00, 0x87, 0xff, 0xa3, 0x00, 0x85, 0xff, 0xa5, 0x00,
+ 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00,
+ 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00,
+ 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00,
+ 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00,
+ 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00,
+ 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00,
+ 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x85, 0xff, 0xa5, 0x00,
+ 0x87, 0xff, 0xa3, 0x00, 0x89, 0xff, 0xa1, 0x00, 0x8b, 0xff, 0x9f, 0x00,
+ 0x8d, 0xff, 0x9d, 0x00, 0x8e, 0xff, 0x9c, 0x00, 0x90, 0xff, 0x9a, 0x00,
+ 0x91, 0xff, 0x99, 0x00, 0x93, 0xff, 0x96, 0x00, 0x96, 0xff, 0x94, 0x00,
+ 0x98, 0xff, 0x92, 0x00, 0x83, 0xff, 0xf9, 0xff, 0x8b, 0x00, 0x9d, 0xff,
+ 0x8b, 0x00, 0x02, 0x6b, 0x7e, 0x7a, 0x9a, 0xff, 0x8b, 0x00, 0x04, 0x37,
+ 0x72, 0x7e, 0x81, 0x83, 0x98, 0xff, 0x8b, 0x00, 0x06, 0x0f, 0x60, 0x7a,
+ 0x80, 0x86, 0x80, 0x80, 0x97, 0xff, 0x8b, 0x00, 0x07, 0x3e, 0x73, 0x7f,
+ 0x82, 0x80, 0x84, 0x80, 0x80, 0x95, 0xff, 0x8b, 0x00, 0x03, 0x24, 0x67,
+ 0x7d, 0x81, 0x80, 0x80, 0x02, 0x84, 0x80, 0x80, 0x93, 0xff, 0x8b, 0x00,
+ 0x04, 0x15, 0x55, 0x77, 0x80, 0x81, 0x81, 0x80, 0x02, 0x84, 0x80, 0x80,
+ 0x91, 0xff, 0x8b, 0x00, 0x04, 0x05, 0x44, 0x70, 0x7f, 0x82, 0x83, 0x80,
+ 0x02, 0x84, 0x80, 0x80, 0x90, 0xff, 0x8b, 0x00, 0x03, 0x2c, 0x69, 0x7d,
+ 0x81, 0x85, 0x80, 0x02, 0x84, 0x80, 0x80, 0x8e, 0xff, 0x8b, 0x00, 0x04,
+ 0x1e, 0x5e, 0x79, 0x81, 0x81, 0x86, 0x80, 0x02, 0x84, 0x80, 0x80, 0x8d,
+ 0xff, 0x8a, 0x00, 0x04, 0x11, 0x51, 0x76, 0x80, 0x81, 0x88, 0x80, 0x02,
+ 0x84, 0x80, 0x80, 0x8b, 0xff, 0x8b, 0x00, 0x03, 0x3e, 0x70, 0x7e, 0x82,
+ 0x8a, 0x80, 0x02, 0x84, 0x80, 0x80, 0x89, 0xff, 0x8b, 0x00, 0x03, 0x28,
+ 0x66, 0x7b, 0x82, 0x8c, 0x80, 0x02, 0x84, 0x80, 0x80, 0x87, 0xff, 0x8b,
+ 0x00, 0x04, 0x1b, 0x5e, 0x79, 0x81, 0x81, 0x8d, 0x80, 0x02, 0x84, 0x80,
+ 0x80, 0x85, 0xff, 0x8b, 0x00, 0x04, 0x0d, 0x4d, 0x75, 0x80, 0x81, 0x8f,
+ 0x80, 0x02, 0x84, 0x80, 0x80, 0x84, 0xff, 0x8b, 0x00, 0x03, 0x38, 0x6d,
+ 0x7e, 0x82, 0x91, 0x80, 0x02, 0x84, 0x80, 0x80, 0x84, 0xff, 0x89, 0x00,
+ 0x03, 0x26, 0x65, 0x7c, 0x81, 0x93, 0x80, 0x02, 0x84, 0x80, 0x80, 0x84,
+ 0xff, 0x87, 0x00, 0x04, 0x18, 0x5a, 0x79, 0x80, 0x81, 0x94, 0x80, 0x02,
+ 0x84, 0x80, 0x80, 0x84, 0xff, 0x85, 0x00, 0x04, 0x09, 0x49, 0x73, 0x80,
+ 0x81, 0x96, 0x80, 0x02, 0x84, 0x80, 0x80, 0x84, 0xff, 0x84, 0x00, 0x03,
+ 0x36, 0x6b, 0x7d, 0x82, 0x98, 0x80, 0x02, 0x84, 0x80, 0x80, 0x84, 0xff,
+ 0x82, 0x00, 0x03, 0x22, 0x62, 0x7a, 0x81, 0x9a, 0x80, 0x02, 0x84, 0x80,
+ 0x80, 0x84, 0xff, 0x80, 0x00, 0x04, 0x1a, 0x5b, 0x78, 0x80, 0x81, 0x9b,
+ 0x80, 0x02, 0x84, 0x80, 0x80, 0x84, 0xff, 0x80, 0x00, 0x04, 0x16, 0x56,
+ 0x77, 0x81, 0x81, 0x9b, 0x80, 0x02, 0x84, 0x80, 0x80, 0x84, 0xff, 0x82,
+ 0x00, 0x03, 0x18, 0x58, 0x78, 0x81, 0x9a, 0x80, 0x02, 0x84, 0x80, 0x80,
+ 0x84, 0xff, 0x84, 0x00, 0x03, 0x22, 0x5e, 0x7c, 0x82, 0x98, 0x80, 0x02,
+ 0x84, 0x80, 0x80, 0x84, 0xff, 0x85, 0x00, 0x04, 0x04, 0x2f, 0x67, 0x7f,
+ 0x81, 0x96, 0x80, 0x02, 0x84, 0x80, 0x80, 0x84, 0xff, 0x87, 0x00, 0x04,
+ 0x0a, 0x40, 0x71, 0x80, 0x81, 0x94, 0x80, 0x02, 0x84, 0x80, 0x80, 0x84,
+ 0xff, 0x89, 0x00, 0x03, 0x12, 0x4f, 0x78, 0x81, 0x93, 0x80, 0x02, 0x84,
+ 0x80, 0x80, 0x84, 0xff, 0x8b, 0x00, 0x03, 0x1e, 0x5c, 0x7d, 0x82, 0x91,
+ 0x80, 0x02, 0x84, 0x80, 0x80, 0x84, 0xff, 0x8c, 0x00, 0x04, 0x05, 0x30,
+ 0x69, 0x80, 0x81, 0x8f, 0x80, 0x02, 0x84, 0x80, 0x80, 0x84, 0xff, 0x8e,
+ 0x00, 0x04, 0x0b, 0x43, 0x72, 0x81, 0x81, 0x8d, 0x80, 0x02, 0x84, 0x80,
+ 0x80, 0x84, 0xff, 0x90, 0x00, 0x03, 0x13, 0x50, 0x78, 0x82, 0x8c, 0x80,
+ 0x02, 0x84, 0x80, 0x80, 0x84, 0xff, 0x92, 0x00, 0x03, 0x22, 0x5f, 0x7d,
+ 0x82, 0x8a, 0x80, 0x02, 0x84, 0x80, 0x80, 0x84, 0xff, 0x93, 0x00, 0x04,
+ 0x07, 0x35, 0x6b, 0x80, 0x81, 0x88, 0x80, 0x02, 0x84, 0x80, 0x80, 0x84,
+ 0xff, 0x95, 0x00, 0x04, 0x0d, 0x44, 0x73, 0x81, 0x81, 0x86, 0x80, 0x02,
+ 0x84, 0x80, 0x80, 0x85, 0xff, 0x96, 0x00, 0x03, 0x16, 0x55, 0x7a, 0x81,
+ 0x85, 0x80, 0x02, 0x84, 0x80, 0x80, 0x87, 0xff, 0x95, 0x00, 0x04, 0x02,
+ 0x28, 0x62, 0x7e, 0x82, 0x83, 0x80, 0x02, 0x84, 0x80, 0x80, 0x89, 0xff,
+ 0x95, 0x00, 0x04, 0x09, 0x39, 0x6e, 0x80, 0x81, 0x81, 0x80, 0x02, 0x84,
+ 0x80, 0x80, 0x8b, 0xff, 0x95, 0x00, 0x03, 0x10, 0x4d, 0x78, 0x81, 0x80,
+ 0x80, 0x02, 0x84, 0x80, 0x80, 0x8d, 0xff, 0x95, 0x00, 0x07, 0x1f, 0x60,
+ 0x7d, 0x82, 0x80, 0x84, 0x80, 0x80, 0x8e, 0xff, 0x95, 0x00, 0x06, 0x05,
+ 0x3b, 0x6f, 0x80, 0x86, 0x80, 0x80, 0x90, 0xff, 0x95, 0x00, 0x04, 0x12,
+ 0x59, 0x7a, 0x81, 0x83, 0x91, 0xff, 0x96, 0x00, 0x02, 0x3b, 0x71, 0x85,
+ 0x93, 0xff, 0x96, 0x00, 0x96, 0xff, 0x94, 0x00, 0x98, 0xff, 0x92, 0x00,
+ 0x83, 0xff, 0xf9, 0xff, 0x8b, 0x00, 0x9d, 0xff, 0x8e, 0x00, 0x9a, 0xff,
+ 0x90, 0x00, 0x98, 0xff, 0x92, 0x00, 0x97, 0xff, 0x93, 0x00, 0x95, 0xff,
+ 0x95, 0x00, 0x93, 0xff, 0x97, 0x00, 0x91, 0xff, 0x99, 0x00, 0x90, 0xff,
+ 0x9a, 0x00, 0x8e, 0xff, 0x9c, 0x00, 0x8d, 0xff, 0x9d, 0x00, 0x8b, 0xff,
+ 0x9f, 0x00, 0x89, 0xff, 0xa1, 0x00, 0x87, 0xff, 0xa3, 0x00, 0x85, 0xff,
+ 0xa5, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff,
+ 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff,
+ 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff,
+ 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff,
+ 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff,
+ 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff,
+ 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x85, 0xff,
+ 0xa5, 0x00, 0x87, 0xff, 0xa3, 0x00, 0x89, 0xff, 0xa1, 0x00, 0x8b, 0xff,
+ 0x9f, 0x00, 0x8d, 0xff, 0x9d, 0x00, 0x8e, 0xff, 0x9c, 0x00, 0x90, 0xff,
+ 0x9a, 0x00, 0x91, 0xff, 0x99, 0x00, 0x93, 0xff, 0x96, 0x00, 0x96, 0xff,
+ 0x94, 0x00, 0x98, 0xff, 0x92, 0x00, 0x83, 0xff, 0xf9, 0x00, 0x06, 0x01,
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x81, 0x07, 0x02, 0x06, 0x05, 0x03,
+ 0x9d, 0x00, 0x10, 0x01, 0x01, 0x02, 0x03, 0x05, 0x06, 0x08, 0x0a, 0x0b,
+ 0x0c, 0x0d, 0x0d, 0x0b, 0x06, 0x26, 0x57, 0x19, 0x9a, 0x00, 0x12, 0x01,
+ 0x01, 0x02, 0x03, 0x04, 0x06, 0x09, 0x0b, 0x0d, 0x10, 0x12, 0x14, 0x14,
+ 0x11, 0x1c, 0x67, 0xd9, 0xc6, 0x25, 0x98, 0x00, 0x80, 0x01, 0x11, 0x02,
+ 0x04, 0x06, 0x08, 0x0b, 0x0e, 0x11, 0x15, 0x18, 0x1b, 0x1c, 0x21, 0x52,
+ 0xba, 0xfb, 0xff, 0xc6, 0x24, 0x97, 0x00, 0x10, 0x01, 0x01, 0x02, 0x04,
+ 0x05, 0x07, 0x0a, 0x0d, 0x11, 0x16, 0x1b, 0x1f, 0x23, 0x26, 0x46, 0xa4,
+ 0xf3, 0x80, 0xff, 0x01, 0xc6, 0x24, 0x95, 0x00, 0x10, 0x01, 0x01, 0x02,
+ 0x03, 0x05, 0x07, 0x09, 0x0c, 0x10, 0x15, 0x1a, 0x20, 0x26, 0x2a, 0x40,
+ 0x90, 0xe6, 0x82, 0xff, 0x01, 0xc6, 0x24, 0x93, 0x00, 0x10, 0x01, 0x01,
+ 0x02, 0x03, 0x04, 0x06, 0x09, 0x0b, 0x0f, 0x14, 0x19, 0x1f, 0x26, 0x2c,
+ 0x3c, 0x7b, 0xd6, 0x84, 0xff, 0x01, 0xc6, 0x24, 0x91, 0x00, 0x80, 0x01,
+ 0x0e, 0x02, 0x04, 0x06, 0x08, 0x0b, 0x0e, 0x12, 0x17, 0x1d, 0x24, 0x2b,
+ 0x36, 0x66, 0xc1, 0xfb, 0x85, 0xff, 0x01, 0xc6, 0x24, 0x90, 0x00, 0x10,
+ 0x01, 0x01, 0x02, 0x03, 0x05, 0x07, 0x0a, 0x0d, 0x11, 0x16, 0x1b, 0x22,
+ 0x2a, 0x31, 0x52, 0xaa, 0xf3, 0x87, 0xff, 0x01, 0xc6, 0x24, 0x8e, 0x00,
+ 0x10, 0x01, 0x01, 0x02, 0x03, 0x05, 0x07, 0x09, 0x0c, 0x10, 0x15, 0x1a,
+ 0x20, 0x28, 0x2e, 0x44, 0x90, 0xe5, 0x89, 0xff, 0x01, 0xc6, 0x24, 0x8d,
+ 0x00, 0x10, 0x01, 0x01, 0x03, 0x04, 0x06, 0x08, 0x0b, 0x0f, 0x14, 0x19,
+ 0x1e, 0x25, 0x2c, 0x3c, 0x77, 0xd2, 0xfe, 0x8a, 0xff, 0x01, 0xc6, 0x24,
+ 0x8b, 0x00, 0x10, 0x01, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0d, 0x12,
+ 0x17, 0x1d, 0x23, 0x2b, 0x35, 0x5f, 0xbb, 0xfa, 0x8c, 0xff, 0x01, 0xc6,
+ 0x24, 0x89, 0x00, 0x10, 0x01, 0x01, 0x02, 0x03, 0x05, 0x07, 0x09, 0x0d,
+ 0x11, 0x16, 0x1b, 0x21, 0x29, 0x2f, 0x4d, 0xa3, 0xf0, 0x8e, 0xff, 0x01,
+ 0xc6, 0x24, 0x87, 0x00, 0x10, 0x01, 0x01, 0x02, 0x03, 0x04, 0x06, 0x09,
+ 0x0b, 0x0f, 0x14, 0x1a, 0x1f, 0x27, 0x2d, 0x43, 0x8b, 0xe1, 0x90, 0xff,
+ 0x01, 0xc6, 0x24, 0x85, 0x00, 0x11, 0x01, 0x01, 0x02, 0x03, 0x04, 0x06,
+ 0x08, 0x0b, 0x0e, 0x13, 0x18, 0x1e, 0x25, 0x2c, 0x3a, 0x71, 0xcd, 0xfd,
+ 0x91, 0xff, 0x01, 0xc6, 0x24, 0x84, 0x00, 0x10, 0x01, 0x01, 0x02, 0x04,
+ 0x06, 0x08, 0x0a, 0x0d, 0x12, 0x17, 0x1c, 0x23, 0x2a, 0x33, 0x5b, 0xb7,
+ 0xf8, 0x93, 0xff, 0x01, 0xc6, 0x24, 0x84, 0x00, 0x0e, 0x02, 0x03, 0x05,
+ 0x07, 0x09, 0x0c, 0x11, 0x16, 0x1b, 0x21, 0x29, 0x2e, 0x49, 0x9f, 0xed,
+ 0x95, 0xff, 0x01, 0xc6, 0x24, 0x84, 0x00, 0x0c, 0x04, 0x06, 0x08, 0x0b,
+ 0x0f, 0x14, 0x19, 0x1f, 0x27, 0x2d, 0x40, 0x85, 0xdd, 0x97, 0xff, 0x01,
+ 0xc6, 0x24, 0x84, 0x00, 0x0b, 0x06, 0x09, 0x0c, 0x11, 0x16, 0x1d, 0x24,
+ 0x2b, 0x38, 0x6d, 0xc8, 0xfc, 0x98, 0xff, 0x01, 0xc6, 0x24, 0x84, 0x00,
+ 0x09, 0x09, 0x0d, 0x12, 0x18, 0x20, 0x28, 0x30, 0x55, 0xb1, 0xf6, 0x9a,
+ 0xff, 0x01, 0xc6, 0x24, 0x84, 0x00, 0x07, 0x0d, 0x12, 0x19, 0x21, 0x28,
+ 0x43, 0x97, 0xea, 0x9c, 0xff, 0x01, 0xc6, 0x24, 0x84, 0x00, 0x05, 0x10,
+ 0x18, 0x1e, 0x32, 0x78, 0xd6, 0x9e, 0xff, 0x01, 0xc6, 0x24, 0x84, 0x00,
+ 0x06, 0x15, 0x1d, 0x25, 0x3a, 0x7f, 0xd9, 0xfe, 0x9d, 0xff, 0x01, 0xc6,
+ 0x24, 0x84, 0x00, 0x07, 0x17, 0x21, 0x2c, 0x39, 0x45, 0x60, 0xa9, 0xee,
+ 0x9c, 0xff, 0x01, 0xc6, 0x24, 0x84, 0x00, 0x09, 0x19, 0x23, 0x2f, 0x3d,
+ 0x4b, 0x59, 0x66, 0x87, 0xc9, 0xf9, 0x9a, 0xff, 0x01, 0xc6, 0x24, 0x84,
+ 0x00, 0x0b, 0x19, 0x23, 0x2f, 0x3d, 0x4b, 0x59, 0x67, 0x74, 0x82, 0xa7,
+ 0xdf, 0xfd, 0x98, 0xff, 0x01, 0xc6, 0x24, 0x84, 0x00, 0x0c, 0x17, 0x21,
+ 0x2c, 0x39, 0x47, 0x54, 0x62, 0x6f, 0x7b, 0x85, 0x94, 0xbc, 0xed, 0x97,
+ 0xff, 0x01, 0xc6, 0x24, 0x84, 0x00, 0x0e, 0x15, 0x1d, 0x27, 0x32, 0x3f,
+ 0x4c, 0x59, 0x65, 0x71, 0x7d, 0x86, 0x8d, 0x9e, 0xcc, 0xf5, 0x95, 0xff,
+ 0x01, 0xc6, 0x24, 0x84, 0x00, 0x10, 0x10, 0x18, 0x20, 0x2a, 0x35, 0x40,
+ 0x4c, 0x58, 0x64, 0x6f, 0x7a, 0x83, 0x8b, 0x93, 0xa9, 0xd9, 0xfb, 0x93,
+ 0xff, 0x01, 0xc6, 0x24, 0x84, 0x00, 0x12, 0x0d, 0x12, 0x19, 0x21, 0x2a,
+ 0x34, 0x3f, 0x4a, 0x55, 0x60, 0x6a, 0x74, 0x7d, 0x86, 0x8d, 0x97, 0xb5,
+ 0xe5, 0xfe, 0x91, 0xff, 0x01, 0xc6, 0x24, 0x84, 0x00, 0x13, 0x09, 0x0d,
+ 0x12, 0x18, 0x20, 0x28, 0x31, 0x3a, 0x45, 0x4e, 0x59, 0x64, 0x6e, 0x77,
+ 0x7f, 0x88, 0x8f, 0x9c, 0xc2, 0xf0, 0x90, 0xff, 0x01, 0xc6, 0x24, 0x84,
+ 0x00, 0x15, 0x06, 0x09, 0x0c, 0x11, 0x16, 0x1d, 0x24, 0x2c, 0x34, 0x3e,
+ 0x47, 0x52, 0x5c, 0x66, 0x70, 0x79, 0x82, 0x8a, 0x91, 0xa2, 0xd0, 0xf7,
+ 0x8e, 0xff, 0x01, 0xc6, 0x24, 0x84, 0x00, 0x17, 0x04, 0x06, 0x08, 0x0b,
+ 0x0f, 0x14, 0x19, 0x1f, 0x27, 0x2f, 0x37, 0x40, 0x4b, 0x55, 0x5f, 0x69,
+ 0x72, 0x7b, 0x84, 0x8c, 0x94, 0xac, 0xdc, 0xfc, 0x8c, 0xff, 0x01, 0xc6,
+ 0x24, 0x84, 0x00, 0x19, 0x02, 0x03, 0x05, 0x07, 0x09, 0x0c, 0x11, 0x16,
+ 0x1b, 0x21, 0x29, 0x31, 0x39, 0x43, 0x4c, 0x56, 0x61, 0x6b, 0x75, 0x7e,
+ 0x86, 0x8d, 0x98, 0xb8, 0xe7, 0xfe, 0x8a, 0xff, 0x01, 0xc6, 0x24, 0x84,
+ 0x00, 0x1a, 0x01, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0d, 0x12, 0x17,
+ 0x1c, 0x23, 0x2b, 0x33, 0x3c, 0x45, 0x50, 0x5a, 0x64, 0x6e, 0x77, 0x80,
+ 0x89, 0x90, 0x9d, 0xc6, 0xf2, 0x89, 0xff, 0x01, 0xc6, 0x24, 0x85, 0x00,
+ 0x1b, 0x01, 0x01, 0x02, 0x03, 0x04, 0x06, 0x08, 0x0b, 0x0e, 0x13, 0x18,
+ 0x1e, 0x25, 0x2d, 0x35, 0x3e, 0x49, 0x53, 0x5d, 0x67, 0x70, 0x7a, 0x83,
+ 0x8b, 0x91, 0xa4, 0xd2, 0xf8, 0x87, 0xff, 0x01, 0xc6, 0x24, 0x87, 0x00,
+ 0x1b, 0x01, 0x01, 0x02, 0x03, 0x04, 0x06, 0x09, 0x0b, 0x0f, 0x14, 0x1a,
+ 0x1f, 0x27, 0x2f, 0x38, 0x41, 0x4a, 0x54, 0x5f, 0x6a, 0x73, 0x7c, 0x85,
+ 0x8d, 0x95, 0xae, 0xde, 0xfd, 0x85, 0xff, 0x01, 0xc6, 0x24, 0x89, 0x00,
+ 0x1a, 0x01, 0x01, 0x02, 0x03, 0x05, 0x07, 0x09, 0x0d, 0x11, 0x16, 0x1b,
+ 0x21, 0x29, 0x31, 0x3a, 0x43, 0x4e, 0x58, 0x62, 0x6c, 0x76, 0x7f, 0x87,
+ 0x8d, 0x96, 0xb8, 0xe8, 0x84, 0xff, 0x01, 0xc6, 0x24, 0x8b, 0x00, 0x1a,
+ 0x01, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0d, 0x12, 0x17, 0x1d, 0x23,
+ 0x2b, 0x34, 0x3c, 0x47, 0x51, 0x5b, 0x65, 0x6f, 0x78, 0x80, 0x87, 0x8a,
+ 0x94, 0xbf, 0xf0, 0x82, 0xff, 0x01, 0xc6, 0x24, 0x8d, 0x00, 0x1a, 0x01,
+ 0x01, 0x03, 0x04, 0x06, 0x08, 0x0b, 0x0f, 0x14, 0x19, 0x1e, 0x25, 0x2d,
+ 0x36, 0x3f, 0x49, 0x54, 0x5e, 0x67, 0x70, 0x78, 0x7e, 0x81, 0x80, 0x8e,
+ 0xc4, 0xf6, 0x80, 0xff, 0x01, 0xc6, 0x24, 0x8e, 0x00, 0x1e, 0x01, 0x01,
+ 0x02, 0x03, 0x05, 0x07, 0x09, 0x0c, 0x10, 0x15, 0x1a, 0x20, 0x28, 0x30,
+ 0x38, 0x42, 0x4b, 0x56, 0x5f, 0x68, 0x6e, 0x72, 0x74, 0x70, 0x6c, 0x86,
+ 0xcc, 0xfc, 0xff, 0xc6, 0x24, 0x90, 0x00, 0x1c, 0x01, 0x01, 0x02, 0x03,
+ 0x05, 0x07, 0x0a, 0x0d, 0x11, 0x16, 0x1b, 0x22, 0x2a, 0x32, 0x3b, 0x44,
+ 0x4d, 0x56, 0x5d, 0x63, 0x65, 0x64, 0x5f, 0x55, 0x53, 0x84, 0xdf, 0xc6,
+ 0x25, 0x91, 0x00, 0x80, 0x01, 0x18, 0x02, 0x04, 0x06, 0x08, 0x0b, 0x0e,
+ 0x12, 0x17, 0x1d, 0x24, 0x2c, 0x34, 0x3d, 0x45, 0x4c, 0x52, 0x55, 0x56,
+ 0x52, 0x4b, 0x41, 0x32, 0x45, 0x61, 0x17, 0x93, 0x00, 0x18, 0x01, 0x01,
+ 0x02, 0x03, 0x04, 0x06, 0x09, 0x0b, 0x0f, 0x14, 0x19, 0x1f, 0x26, 0x2e,
+ 0x35, 0x3b, 0x41, 0x45, 0x46, 0x44, 0x3f, 0x37, 0x2e, 0x24, 0x13, 0x96,
+ 0x00, 0x16, 0x01, 0x01, 0x02, 0x03, 0x05, 0x07, 0x09, 0x0c, 0x10, 0x15,
+ 0x1a, 0x20, 0x26, 0x2c, 0x32, 0x35, 0x37, 0x36, 0x32, 0x2d, 0x25, 0x1e,
+ 0x10, 0x98, 0x00, 0x14, 0x01, 0x01, 0x02, 0x04, 0x05, 0x07, 0x0a, 0x0d,
+ 0x11, 0x16, 0x1b, 0x1f, 0x23, 0x27, 0x29, 0x29, 0x27, 0x22, 0x1d, 0x17,
+ 0x0c, 0x83, 0x00,
+};
+static EG_EMBEDDED_IMAGE egemb_arrow_left = { 48, 48, EG_EIPIXELMODE_COLOR_ALPHA, EG_EICOMPMODE_RLE, egemb_arrow_left_data, 2175 };
diff --git a/include/egemb_arrow_right.h b/include/egemb_arrow_right.h
new file mode 100644 (file)
index 0000000..60201c4
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * include/egemb_arrow_right.h
+ * An encoded right arrow icon
+ *
+ * Copyright (c) 2015 Roderick W. Smith
+ * All rights reserved.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+static const UINT8 egemb_arrow_right_data[2053] = {
+ 0xe2, 0xff, 0x8d, 0x00, 0x9d, 0xff, 0x8e, 0x00, 0x9c, 0xff, 0x90, 0x00,
+ 0x9a, 0xff, 0x92, 0x00, 0x98, 0xff, 0x94, 0x00, 0x96, 0xff, 0x95, 0x00,
+ 0x95, 0xff, 0x97, 0x00, 0x93, 0xff, 0x99, 0x00, 0x91, 0xff, 0x9a, 0x00,
+ 0x90, 0xff, 0x9c, 0x00, 0x8e, 0xff, 0x9e, 0x00, 0x8c, 0xff, 0x9f, 0x00,
+ 0x8b, 0xff, 0xa1, 0x00, 0x89, 0xff, 0xa3, 0x00, 0x87, 0xff, 0xa5, 0x00,
+ 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00,
+ 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00,
+ 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00,
+ 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00,
+ 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00,
+ 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00,
+ 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00,
+ 0x85, 0xff, 0xa3, 0x00, 0x87, 0xff, 0xa1, 0x00, 0x89, 0xff, 0x9f, 0x00,
+ 0x8b, 0xff, 0x9e, 0x00, 0x8c, 0xff, 0x9c, 0x00, 0x8e, 0xff, 0x9a, 0x00,
+ 0x90, 0xff, 0x99, 0x00, 0x91, 0xff, 0x97, 0x00, 0x93, 0xff, 0x95, 0x00,
+ 0x95, 0xff, 0x94, 0x00, 0x91, 0xff, 0xe2, 0xff, 0x8d, 0x00, 0x9d, 0xff,
+ 0x02, 0x00, 0x7d, 0x51, 0x8b, 0x00, 0x9c, 0xff, 0x03, 0x00, 0x7f, 0x7e,
+ 0x73, 0x8c, 0x00, 0x9a, 0xff, 0x05, 0x00, 0x7f, 0x80, 0x80, 0x7b, 0x5b,
+ 0x8c, 0x00, 0x98, 0xff, 0x01, 0x00, 0x7e, 0x80, 0x80, 0x02, 0x7f, 0x73,
+ 0x35, 0x8c, 0x00, 0x96, 0xff, 0x01, 0x00, 0x7e, 0x82, 0x80, 0x02, 0x7d,
+ 0x67, 0x0e, 0x8b, 0x00, 0x95, 0xff, 0x01, 0x00, 0x7e, 0x84, 0x80, 0x01,
+ 0x79, 0x55, 0x8c, 0x00, 0x93, 0xff, 0x01, 0x00, 0x7e, 0x86, 0x80, 0x01,
+ 0x72, 0x3d, 0x8c, 0x00, 0x91, 0xff, 0x01, 0x00, 0x7e, 0x87, 0x80, 0x02,
+ 0x7d, 0x6a, 0x22, 0x8b, 0x00, 0x90, 0xff, 0x01, 0x00, 0x7d, 0x89, 0x80,
+ 0x02, 0x7b, 0x5d, 0x09, 0x8b, 0x00, 0x8e, 0xff, 0x01, 0x00, 0x7d, 0x8b,
+ 0x80, 0x01, 0x77, 0x4d, 0x8c, 0x00, 0x8c, 0xff, 0x01, 0x00, 0x7d, 0x8d,
+ 0x80, 0x01, 0x71, 0x36, 0x8b, 0x00, 0x8b, 0xff, 0x01, 0x00, 0x7d, 0x8e,
+ 0x80, 0x02, 0x7d, 0x67, 0x1d, 0x8b, 0x00, 0x89, 0xff, 0x01, 0x00, 0x7d,
+ 0x90, 0x80, 0x02, 0x7b, 0x5c, 0x04, 0x8b, 0x00, 0x87, 0xff, 0x01, 0x00,
+ 0x7d, 0x92, 0x80, 0x01, 0x76, 0x49, 0x8c, 0x00, 0x85, 0xff, 0x01, 0x00,
+ 0x7d, 0x94, 0x80, 0x01, 0x6e, 0x31, 0x8a, 0x00, 0x85, 0xff, 0x01, 0x00,
+ 0x7d, 0x95, 0x80, 0x02, 0x7d, 0x65, 0x17, 0x88, 0x00, 0x85, 0xff, 0x01,
+ 0x00, 0x7d, 0x97, 0x80, 0x01, 0x7a, 0x5a, 0x87, 0x00, 0x85, 0xff, 0x01,
+ 0x00, 0x7d, 0x99, 0x80, 0x01, 0x74, 0x45, 0x85, 0x00, 0x85, 0xff, 0x01,
+ 0x00, 0x7d, 0x9a, 0x80, 0x02, 0x7e, 0x6c, 0x2b, 0x83, 0x00, 0x85, 0xff,
+ 0x01, 0x00, 0x7d, 0x9c, 0x80, 0x02, 0x7c, 0x63, 0x0d, 0x81, 0x00, 0x85,
+ 0xff, 0x01, 0x00, 0x7d, 0x9e, 0x80, 0x01, 0x79, 0x58, 0x80, 0x00, 0x85,
+ 0xff, 0x01, 0x00, 0x7d, 0x9e, 0x80, 0x01, 0x77, 0x54, 0x80, 0x00, 0x85,
+ 0xff, 0x01, 0x00, 0x7d, 0x9c, 0x80, 0x02, 0x7a, 0x58, 0x09, 0x81, 0x00,
+ 0x85, 0xff, 0x01, 0x00, 0x7d, 0x9a, 0x80, 0x02, 0x7d, 0x5f, 0x1a, 0x83,
+ 0x00, 0x85, 0xff, 0x01, 0x00, 0x7d, 0x99, 0x80, 0x01, 0x69, 0x2c, 0x85,
+ 0x00, 0x85, 0xff, 0x01, 0x00, 0x7d, 0x97, 0x80, 0x01, 0x73, 0x3e, 0x87,
+ 0x00, 0x85, 0xff, 0x01, 0x00, 0x7d, 0x95, 0x80, 0x02, 0x7a, 0x4e, 0x0a,
+ 0x88, 0x00, 0x85, 0xff, 0x01, 0x00, 0x7d, 0x93, 0x80, 0x02, 0x7e, 0x5e,
+ 0x19, 0x8a, 0x00, 0x85, 0xff, 0x01, 0x00, 0x7d, 0x92, 0x80, 0x01, 0x6b,
+ 0x2c, 0x8c, 0x00, 0x85, 0xff, 0x01, 0x00, 0x7d, 0x90, 0x80, 0x02, 0x75,
+ 0x42, 0x02, 0x8d, 0x00, 0x85, 0xff, 0x01, 0x00, 0x7d, 0x8e, 0x80, 0x02,
+ 0x7a, 0x51, 0x0d, 0x8f, 0x00, 0x85, 0xff, 0x01, 0x00, 0x7d, 0x8d, 0x80,
+ 0x01, 0x61, 0x1d, 0x91, 0x00, 0x85, 0xff, 0x01, 0x00, 0x7d, 0x8b, 0x80,
+ 0x01, 0x6d, 0x31, 0x93, 0x00, 0x85, 0xff, 0x01, 0x00, 0x7d, 0x89, 0x80,
+ 0x02, 0x76, 0x44, 0x03, 0x94, 0x00, 0x85, 0xff, 0x01, 0x00, 0x7d, 0x87,
+ 0x80, 0x02, 0x7c, 0x55, 0x10, 0x96, 0x00, 0x85, 0xff, 0x01, 0x00, 0x7d,
+ 0x85, 0x80, 0x02, 0x7f, 0x64, 0x22, 0x96, 0x00, 0x87, 0xff, 0x01, 0x00,
+ 0x7d, 0x84, 0x80, 0x01, 0x71, 0x38, 0x96, 0x00, 0x89, 0xff, 0x01, 0x00,
+ 0x7d, 0x82, 0x80, 0x02, 0x79, 0x4d, 0x05, 0x95, 0x00, 0x8b, 0xff, 0x01,
+ 0x00, 0x7d, 0x80, 0x80, 0x02, 0x7e, 0x61, 0x18, 0x96, 0x00, 0x8c, 0xff,
+ 0x05, 0x00, 0x7d, 0x80, 0x80, 0x71, 0x35, 0x96, 0x00, 0x8e, 0xff, 0x03,
+ 0x00, 0x7e, 0x7b, 0x5a, 0x96, 0x00, 0x90, 0xff, 0x02, 0x00, 0x71, 0x1f,
+ 0x96, 0x00, 0x91, 0xff, 0x97, 0x00, 0x93, 0xff, 0x95, 0x00, 0x95, 0xff,
+ 0x94, 0x00, 0x91, 0xff, 0xe2, 0xff, 0x8d, 0x00, 0x9d, 0xff, 0x8e, 0x00,
+ 0x9c, 0xff, 0x90, 0x00, 0x9a, 0xff, 0x92, 0x00, 0x98, 0xff, 0x94, 0x00,
+ 0x96, 0xff, 0x95, 0x00, 0x95, 0xff, 0x97, 0x00, 0x93, 0xff, 0x99, 0x00,
+ 0x91, 0xff, 0x9a, 0x00, 0x90, 0xff, 0x9c, 0x00, 0x8e, 0xff, 0x9e, 0x00,
+ 0x8c, 0xff, 0x9f, 0x00, 0x8b, 0xff, 0xa1, 0x00, 0x89, 0xff, 0xa3, 0x00,
+ 0x87, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00,
+ 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00,
+ 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00,
+ 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00,
+ 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00,
+ 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00,
+ 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00,
+ 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa3, 0x00, 0x87, 0xff, 0xa1, 0x00,
+ 0x89, 0xff, 0x9f, 0x00, 0x8b, 0xff, 0x9e, 0x00, 0x8c, 0xff, 0x9c, 0x00,
+ 0x8e, 0xff, 0x9a, 0x00, 0x90, 0xff, 0x99, 0x00, 0x91, 0xff, 0x97, 0x00,
+ 0x93, 0xff, 0x95, 0x00, 0x95, 0xff, 0x94, 0x00, 0x91, 0xff, 0xe2, 0x00,
+ 0x03, 0x02, 0x04, 0x05, 0x06, 0x81, 0x07, 0x07, 0x06, 0x05, 0x04, 0x03,
+ 0x02, 0x02, 0x01, 0x01, 0x9d, 0x00, 0x10, 0x04, 0x78, 0x13, 0x0a, 0x0b,
+ 0x0c, 0x0d, 0x0c, 0x0b, 0x0a, 0x08, 0x06, 0x05, 0x03, 0x02, 0x01, 0x01,
+ 0x9c, 0x00, 0x12, 0x06, 0xe5, 0xd8, 0x64, 0x11, 0x13, 0x14, 0x13, 0x12,
+ 0x10, 0x0d, 0x0b, 0x08, 0x06, 0x04, 0x03, 0x02, 0x01, 0x01, 0x9a, 0x00,
+ 0x14, 0x08, 0xe5, 0xff, 0xff, 0xbf, 0x4c, 0x1d, 0x1d, 0x1b, 0x18, 0x15,
+ 0x11, 0x0e, 0x0b, 0x08, 0x06, 0x04, 0x03, 0x02, 0x01, 0x01, 0x98, 0x00,
+ 0x01, 0x0b, 0xe6, 0x80, 0xff, 0x11, 0xf9, 0xa7, 0x3e, 0x27, 0x24, 0x1f,
+ 0x1b, 0x16, 0x11, 0x0d, 0x0a, 0x07, 0x05, 0x03, 0x02, 0x02, 0x01, 0x01,
+ 0x96, 0x00, 0x01, 0x0e, 0xe6, 0x82, 0xff, 0x10, 0xed, 0x90, 0x36, 0x2c,
+ 0x26, 0x20, 0x1a, 0x15, 0x10, 0x0c, 0x09, 0x07, 0x05, 0x03, 0x02, 0x01,
+ 0x01, 0x95, 0x00, 0x01, 0x11, 0xe7, 0x84, 0xff, 0x10, 0xdb, 0x78, 0x35,
+ 0x2d, 0x26, 0x1f, 0x19, 0x13, 0x0f, 0x0b, 0x08, 0x06, 0x04, 0x03, 0x02,
+ 0x01, 0x01, 0x93, 0x00, 0x01, 0x14, 0xe7, 0x85, 0xff, 0x11, 0xfe, 0xc5,
+ 0x60, 0x34, 0x2c, 0x24, 0x1d, 0x17, 0x12, 0x0e, 0x0a, 0x08, 0x05, 0x04,
+ 0x03, 0x02, 0x01, 0x01, 0x91, 0x00, 0x01, 0x16, 0xe7, 0x87, 0xff, 0x10,
+ 0xf8, 0xab, 0x4a, 0x32, 0x2a, 0x22, 0x1b, 0x16, 0x11, 0x0d, 0x0a, 0x07,
+ 0x05, 0x03, 0x02, 0x01, 0x01, 0x90, 0x00, 0x01, 0x18, 0xe8, 0x89, 0xff,
+ 0x10, 0xeb, 0x91, 0x3a, 0x2f, 0x27, 0x20, 0x1a, 0x14, 0x10, 0x0c, 0x09,
+ 0x06, 0x05, 0x03, 0x02, 0x01, 0x01, 0x8e, 0x00, 0x01, 0x19, 0xe8, 0x8b,
+ 0xff, 0x10, 0xd7, 0x74, 0x36, 0x2d, 0x25, 0x1e, 0x18, 0x13, 0x0f, 0x0b,
+ 0x08, 0x06, 0x04, 0x03, 0x02, 0x01, 0x01, 0x8c, 0x00, 0x01, 0x1a, 0xe8,
+ 0x8c, 0xff, 0x10, 0xfe, 0xbe, 0x59, 0x33, 0x2b, 0x23, 0x1d, 0x17, 0x12,
+ 0x0e, 0x0a, 0x07, 0x05, 0x04, 0x02, 0x01, 0x01, 0x8b, 0x00, 0x01, 0x1a,
+ 0xe8, 0x8e, 0xff, 0x10, 0xf5, 0xa4, 0x46, 0x31, 0x29, 0x22, 0x1b, 0x16,
+ 0x11, 0x0d, 0x09, 0x07, 0x05, 0x03, 0x02, 0x01, 0x01, 0x89, 0x00, 0x01,
+ 0x1b, 0xe8, 0x90, 0xff, 0x10, 0xe6, 0x8a, 0x39, 0x2f, 0x27, 0x20, 0x1a,
+ 0x14, 0x0f, 0x0c, 0x09, 0x06, 0x04, 0x03, 0x02, 0x01, 0x01, 0x87, 0x00,
+ 0x01, 0x1b, 0xe8, 0x92, 0xff, 0x10, 0xd2, 0x6d, 0x35, 0x2d, 0x25, 0x1e,
+ 0x18, 0x13, 0x0e, 0x0b, 0x08, 0x06, 0x04, 0x03, 0x02, 0x01, 0x01, 0x85,
+ 0x00, 0x01, 0x1b, 0xe8, 0x93, 0xff, 0x0f, 0xfc, 0xb9, 0x54, 0x33, 0x2a,
+ 0x23, 0x1c, 0x17, 0x12, 0x0d, 0x0a, 0x07, 0x05, 0x04, 0x03, 0x02, 0x85,
+ 0x00, 0x01, 0x1b, 0xe8, 0x95, 0xff, 0x0d, 0xf2, 0x9f, 0x42, 0x31, 0x28,
+ 0x21, 0x1b, 0x15, 0x10, 0x0d, 0x09, 0x07, 0x05, 0x03, 0x85, 0x00, 0x01,
+ 0x1b, 0xe8, 0x97, 0xff, 0x0b, 0xe2, 0x83, 0x37, 0x2e, 0x26, 0x1f, 0x19,
+ 0x14, 0x0f, 0x0b, 0x08, 0x05, 0x85, 0x00, 0x01, 0x1b, 0xe8, 0x99, 0xff,
+ 0x09, 0xcc, 0x68, 0x35, 0x2c, 0x24, 0x1d, 0x16, 0x11, 0x0d, 0x09, 0x85,
+ 0x00, 0x01, 0x1b, 0xe8, 0x9a, 0xff, 0x08, 0xfa, 0xb3, 0x4e, 0x31, 0x28,
+ 0x20, 0x18, 0x12, 0x0d, 0x85, 0x00, 0x01, 0x1b, 0xe8, 0x9c, 0xff, 0x06,
+ 0xef, 0x98, 0x39, 0x2a, 0x21, 0x19, 0x12, 0x85, 0x00, 0x01, 0x1b, 0xe8,
+ 0x9e, 0xff, 0x04, 0xdc, 0x77, 0x2a, 0x20, 0x17, 0x85, 0x00, 0x01, 0x1b,
+ 0xe8, 0x9e, 0xff, 0x04, 0xde, 0x7d, 0x32, 0x27, 0x1c, 0x85, 0x00, 0x01,
+ 0x1b, 0xe8, 0x9c, 0xff, 0x06, 0xf2, 0xab, 0x58, 0x46, 0x38, 0x2c, 0x20,
+ 0x85, 0x00, 0x01, 0x1b, 0xe8, 0x9a, 0xff, 0x08, 0xfc, 0xcc, 0x82, 0x67,
+ 0x59, 0x4a, 0x3c, 0x2f, 0x23, 0x85, 0x00, 0x01, 0x1b, 0xe8, 0x99, 0xff,
+ 0x09, 0xe2, 0xa4, 0x80, 0x74, 0x67, 0x59, 0x4a, 0x3c, 0x2f, 0x23, 0x85,
+ 0x00, 0x01, 0x1b, 0xe8, 0x97, 0xff, 0x0b, 0xef, 0xbc, 0x8f, 0x86, 0x7b,
+ 0x6f, 0x62, 0x54, 0x46, 0x38, 0x2c, 0x20, 0x85, 0x00, 0x01, 0x1b, 0xe8,
+ 0x95, 0xff, 0x0d, 0xf8, 0xcd, 0x9b, 0x8f, 0x86, 0x7c, 0x71, 0x65, 0x59,
+ 0x4c, 0x3f, 0x32, 0x27, 0x1c, 0x85, 0x00, 0x01, 0x1b, 0xe8, 0x93, 0xff,
+ 0x0f, 0xfe, 0xda, 0xa6, 0x93, 0x8b, 0x83, 0x79, 0x6f, 0x64, 0x58, 0x4c,
+ 0x40, 0x35, 0x2a, 0x20, 0x17, 0x85, 0x00, 0x01, 0x1b, 0xe8, 0x92, 0xff,
+ 0x10, 0xe8, 0xb3, 0x95, 0x8e, 0x86, 0x7d, 0x74, 0x6a, 0x5f, 0x54, 0x49,
+ 0x3f, 0x34, 0x2a, 0x21, 0x19, 0x12, 0x85, 0x00, 0x01, 0x1b, 0xe8, 0x90,
+ 0xff, 0x12, 0xf2, 0xc2, 0x96, 0x90, 0x88, 0x80, 0x77, 0x6d, 0x63, 0x59,
+ 0x4e, 0x44, 0x3a, 0x31, 0x28, 0x20, 0x18, 0x12, 0x0d, 0x85, 0x00, 0x01,
+ 0x1b, 0xe8, 0x8e, 0xff, 0x14, 0xfa, 0xd0, 0x9e, 0x91, 0x8a, 0x82, 0x79,
+ 0x70, 0x66, 0x5c, 0x52, 0x47, 0x3e, 0x35, 0x2c, 0x24, 0x1d, 0x16, 0x11,
+ 0x0d, 0x09, 0x85, 0x00, 0x01, 0x1b, 0xe8, 0x8c, 0xff, 0x16, 0xfe, 0xdd,
+ 0xa8, 0x93, 0x8c, 0x84, 0x7b, 0x72, 0x68, 0x5e, 0x54, 0x4a, 0x40, 0x37,
+ 0x2e, 0x26, 0x1f, 0x19, 0x14, 0x0f, 0x0b, 0x08, 0x05, 0x85, 0x00, 0x01,
+ 0x1b, 0xe8, 0x8b, 0xff, 0x17, 0xea, 0xb6, 0x95, 0x8e, 0x86, 0x7e, 0x75,
+ 0x6b, 0x61, 0x57, 0x4d, 0x43, 0x39, 0x31, 0x28, 0x21, 0x1b, 0x15, 0x10,
+ 0x0d, 0x09, 0x07, 0x05, 0x03, 0x85, 0x00, 0x01, 0x1b, 0xe8, 0x89, 0xff,
+ 0x19, 0xf4, 0xc6, 0x98, 0x90, 0x89, 0x80, 0x77, 0x6e, 0x64, 0x5a, 0x4f,
+ 0x45, 0x3c, 0x33, 0x2a, 0x23, 0x1c, 0x17, 0x12, 0x0d, 0x0a, 0x07, 0x05,
+ 0x04, 0x03, 0x02, 0x85, 0x00, 0x01, 0x1b, 0xe8, 0x87, 0xff, 0x1b, 0xfb,
+ 0xd4, 0xa1, 0x92, 0x8b, 0x83, 0x7a, 0x70, 0x66, 0x5c, 0x52, 0x48, 0x3e,
+ 0x35, 0x2d, 0x25, 0x1e, 0x18, 0x13, 0x0e, 0x0b, 0x08, 0x06, 0x04, 0x03,
+ 0x02, 0x01, 0x01, 0x85, 0x00, 0x01, 0x1b, 0xe8, 0x86, 0xff, 0x1a, 0xe0,
+ 0xab, 0x94, 0x8d, 0x85, 0x7c, 0x73, 0x69, 0x5f, 0x55, 0x4b, 0x41, 0x38,
+ 0x2f, 0x27, 0x20, 0x1a, 0x14, 0x0f, 0x0c, 0x09, 0x06, 0x04, 0x03, 0x02,
+ 0x01, 0x01, 0x87, 0x00, 0x01, 0x1a, 0xe8, 0x84, 0xff, 0x1a, 0xeb, 0xb7,
+ 0x93, 0x8e, 0x87, 0x7f, 0x76, 0x6c, 0x62, 0x58, 0x4d, 0x43, 0x3a, 0x31,
+ 0x29, 0x22, 0x1b, 0x16, 0x11, 0x0d, 0x09, 0x07, 0x05, 0x03, 0x02, 0x01,
+ 0x01, 0x89, 0x00, 0x01, 0x1a, 0xe8, 0x82, 0xff, 0x1a, 0xf4, 0xbf, 0x8f,
+ 0x8b, 0x87, 0x80, 0x78, 0x6f, 0x65, 0x5a, 0x50, 0x46, 0x3c, 0x33, 0x2b,
+ 0x23, 0x1d, 0x17, 0x12, 0x0e, 0x0a, 0x07, 0x05, 0x04, 0x02, 0x01, 0x01,
+ 0x8b, 0x00, 0x01, 0x19, 0xe8, 0x80, 0xff, 0x1b, 0xfb, 0xc5, 0x89, 0x80,
+ 0x80, 0x7e, 0x78, 0x70, 0x67, 0x5d, 0x53, 0x49, 0x3f, 0x36, 0x2d, 0x25,
+ 0x1e, 0x18, 0x13, 0x0f, 0x0b, 0x08, 0x06, 0x04, 0x03, 0x02, 0x01, 0x01,
+ 0x8c, 0x00, 0x1e, 0x18, 0xe8, 0xff, 0xff, 0xcf, 0x81, 0x6a, 0x71, 0x74,
+ 0x72, 0x6e, 0x68, 0x5f, 0x56, 0x4c, 0x42, 0x38, 0x2f, 0x27, 0x20, 0x1a,
+ 0x14, 0x10, 0x0c, 0x09, 0x06, 0x05, 0x03, 0x02, 0x01, 0x01, 0x8e, 0x00,
+ 0x1c, 0x16, 0xe7, 0xdd, 0x80, 0x4a, 0x56, 0x5f, 0x64, 0x65, 0x62, 0x5d,
+ 0x56, 0x4d, 0x44, 0x3b, 0x32, 0x2a, 0x22, 0x1b, 0x16, 0x11, 0x0d, 0x0a,
+ 0x07, 0x05, 0x03, 0x02, 0x01, 0x01, 0x90, 0x00, 0x1b, 0x14, 0x85, 0x31,
+ 0x35, 0x41, 0x4b, 0x52, 0x55, 0x55, 0x52, 0x4c, 0x45, 0x3d, 0x34, 0x2c,
+ 0x24, 0x1d, 0x17, 0x12, 0x0e, 0x0a, 0x08, 0x05, 0x04, 0x03, 0x02, 0x01,
+ 0x01, 0x91, 0x00, 0x19, 0x11, 0x19, 0x23, 0x2d, 0x37, 0x3f, 0x44, 0x46,
+ 0x44, 0x41, 0x3b, 0x35, 0x2d, 0x26, 0x1f, 0x19, 0x13, 0x0f, 0x0b, 0x08,
+ 0x06, 0x04, 0x03, 0x02, 0x01, 0x01, 0x93, 0x00, 0x17, 0x0e, 0x15, 0x1c,
+ 0x25, 0x2c, 0x32, 0x36, 0x36, 0x35, 0x31, 0x2c, 0x26, 0x20, 0x1a, 0x15,
+ 0x10, 0x0c, 0x09, 0x07, 0x05, 0x03, 0x02, 0x01, 0x01, 0x95, 0x00, 0x16,
+ 0x0b, 0x10, 0x16, 0x1c, 0x22, 0x26, 0x29, 0x29, 0x27, 0x24, 0x1f, 0x1b,
+ 0x16, 0x11, 0x0d, 0x0a, 0x07, 0x05, 0x03, 0x02, 0x02, 0x01, 0x01, 0x91,
+ 0x00,
+};
+static EG_EMBEDDED_IMAGE egemb_arrow_right = { 48, 48, EG_EIPIXELMODE_COLOR_ALPHA, EG_EICOMPMODE_RLE, egemb_arrow_right_data, 2053 };
diff --git a/include/egemb_back_selected_big.h b/include/egemb_back_selected_big.h
new file mode 100644 (file)
index 0000000..36116a4
--- /dev/null
@@ -0,0 +1,666 @@
+static const UINT8 egemb_back_selected_big_data[7951] = {
+ 0x83, 0x30, 0xff, 0xff, 0x01, 0xff, 0xff, 0x87, 0x30, 0xff, 0xff, 0x83,
+ 0xff, 0x84, 0x30, 0x85, 0xff, 0x03, 0x30, 0x20, 0x18, 0x13, 0xef, 0x10,
+ 0x03, 0x13, 0x18, 0x20, 0x30, 0x85, 0xff, 0x82, 0x30, 0x83, 0xff, 0x02,
+ 0x0d, 0x07, 0x05, 0xf7, 0x04, 0x02, 0x05, 0x07, 0x0d, 0x83, 0xff, 0x80,
+ 0x30, 0x82, 0xff, 0x03, 0x13, 0x06, 0x04, 0x03, 0xf9, 0x02, 0x03, 0x03,
+ 0x04, 0x06, 0x13, 0x82, 0xff, 0x01, 0x30, 0x60, 0x81, 0xff, 0x02, 0x0c,
+ 0x04, 0x03, 0x80, 0x02, 0xf7, 0x01, 0x80, 0x02, 0x02, 0x03, 0x04, 0x0c,
+ 0x81, 0xff, 0x00, 0x60, 0x81, 0xff, 0x03, 0x10, 0x04, 0x03, 0x02, 0xfd,
+ 0x01, 0x03, 0x02, 0x03, 0x04, 0x10, 0x85, 0xff, 0x02, 0x06, 0x03, 0x02,
+ 0xff, 0x01, 0x02, 0x02, 0x03, 0x06, 0x84, 0xff, 0x02, 0x0d, 0x04, 0x02,
+ 0xff, 0x01, 0x04, 0x01, 0x01, 0x02, 0x04, 0x0d, 0x83, 0xff, 0x02, 0x07,
+ 0x03, 0x02, 0xff, 0x01, 0x04, 0x01, 0x01, 0x02, 0x03, 0x07, 0x83, 0xff,
+ 0x02, 0x05, 0x02, 0x02, 0xff, 0x01, 0x04, 0x01, 0x01, 0x02, 0x02, 0x05,
+ 0x82, 0xff, 0x02, 0x30, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02,
+ 0x04, 0x30, 0x81, 0xff, 0x02, 0x20, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01,
+ 0x02, 0x02, 0x04, 0x20, 0x81, 0xff, 0x02, 0x13, 0x04, 0x02, 0xff, 0x01,
+ 0x81, 0x01, 0x02, 0x02, 0x04, 0x13, 0x81, 0xff, 0x02, 0x13, 0x04, 0x02,
+ 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x13, 0x81, 0xff, 0x02, 0x10,
+ 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff,
+ 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10,
+ 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02,
+ 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01,
+ 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01,
+ 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02,
+ 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10,
+ 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff,
+ 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10,
+ 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02,
+ 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01,
+ 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01,
+ 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02,
+ 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10,
+ 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff,
+ 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10,
+ 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02,
+ 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01,
+ 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01,
+ 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02,
+ 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10,
+ 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff,
+ 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10,
+ 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02,
+ 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01,
+ 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01,
+ 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02,
+ 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10,
+ 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff,
+ 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10,
+ 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02,
+ 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01,
+ 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01,
+ 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02,
+ 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10,
+ 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff,
+ 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10,
+ 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02,
+ 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01,
+ 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01,
+ 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02,
+ 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10,
+ 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff,
+ 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10,
+ 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02,
+ 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01,
+ 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01,
+ 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02,
+ 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10,
+ 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff,
+ 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10,
+ 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02,
+ 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01,
+ 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01,
+ 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02,
+ 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10,
+ 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff,
+ 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10,
+ 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02,
+ 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01,
+ 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01,
+ 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02,
+ 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10,
+ 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff,
+ 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10,
+ 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02,
+ 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01,
+ 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01,
+ 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02,
+ 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10,
+ 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff,
+ 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10,
+ 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02,
+ 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01,
+ 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01,
+ 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02,
+ 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10,
+ 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff,
+ 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10,
+ 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02,
+ 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01,
+ 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01,
+ 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02,
+ 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10,
+ 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff,
+ 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10,
+ 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02,
+ 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01,
+ 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01,
+ 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02,
+ 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10,
+ 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff,
+ 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10,
+ 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02,
+ 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01,
+ 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01,
+ 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02,
+ 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10,
+ 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff,
+ 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10,
+ 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02,
+ 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01,
+ 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01,
+ 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02,
+ 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10,
+ 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff,
+ 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10,
+ 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02,
+ 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01,
+ 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01,
+ 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02,
+ 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10,
+ 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff,
+ 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10,
+ 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02,
+ 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01,
+ 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01,
+ 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02,
+ 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10,
+ 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff,
+ 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10,
+ 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02,
+ 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01,
+ 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01,
+ 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02,
+ 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10,
+ 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff,
+ 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10,
+ 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02,
+ 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01,
+ 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01,
+ 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02,
+ 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x13,
+ 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x13, 0x81, 0xff,
+ 0x02, 0x13, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x13,
+ 0x81, 0xff, 0x02, 0x20, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02,
+ 0x04, 0x20, 0x81, 0xff, 0x02, 0x30, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01,
+ 0x02, 0x02, 0x04, 0x30, 0x82, 0xff, 0x02, 0x05, 0x02, 0x02, 0xff, 0x01,
+ 0x04, 0x01, 0x01, 0x02, 0x02, 0x05, 0x83, 0xff, 0x02, 0x07, 0x03, 0x02,
+ 0xff, 0x01, 0x04, 0x01, 0x01, 0x02, 0x03, 0x07, 0x83, 0xff, 0x02, 0x0d,
+ 0x04, 0x02, 0xff, 0x01, 0x04, 0x01, 0x01, 0x02, 0x04, 0x0d, 0x84, 0xff,
+ 0x02, 0x06, 0x03, 0x02, 0xff, 0x01, 0x02, 0x02, 0x03, 0x06, 0x85, 0xff,
+ 0x03, 0x10, 0x04, 0x03, 0x02, 0xfd, 0x01, 0x03, 0x02, 0x03, 0x04, 0x10,
+ 0x81, 0xff, 0x00, 0x60, 0x81, 0xff, 0x02, 0x0c, 0x04, 0x03, 0x80, 0x02,
+ 0xf7, 0x01, 0x80, 0x02, 0x02, 0x03, 0x04, 0x0c, 0x81, 0xff, 0x01, 0x60,
+ 0x30, 0x82, 0xff, 0x03, 0x10, 0x06, 0x04, 0x03, 0xf9, 0x02, 0x03, 0x03,
+ 0x04, 0x06, 0x10, 0x82, 0xff, 0x80, 0x30, 0x83, 0xff, 0x02, 0x0d, 0x07,
+ 0x05, 0xf7, 0x04, 0x02, 0x05, 0x07, 0x0d, 0x83, 0xff, 0x82, 0x30, 0x85,
+ 0xff, 0x03, 0x30, 0x20, 0x13, 0x13, 0xef, 0x10, 0x03, 0x13, 0x13, 0x20,
+ 0x30, 0x85, 0xff, 0x84, 0x30, 0xff, 0xff, 0x83, 0xff, 0x87, 0x30, 0xff,
+ 0xff, 0x01, 0xff, 0xff, 0x83, 0x30, 0x83, 0x00, 0x00, 0xfb, 0xff, 0xfe,
+ 0x00, 0xfb, 0x87, 0x00, 0x00, 0xf3, 0x86, 0xfe, 0xf1, 0xfd, 0x86, 0xfe,
+ 0x00, 0xf3, 0x84, 0x00, 0x00, 0xfd, 0x81, 0xfe, 0x02, 0xfd, 0xfb, 0xf3,
+ 0xf7, 0x00, 0x02, 0xf3, 0xfb, 0xfd, 0x81, 0xfe, 0x00, 0xfd, 0x82, 0x00,
+ 0x00, 0xfd, 0x80, 0xfe, 0x01, 0xfd, 0xf3, 0xfd, 0x00, 0x01, 0xf3, 0xfd,
+ 0x80, 0xfe, 0x00, 0xfd, 0x80, 0x00, 0x00, 0xfc, 0x80, 0xfe, 0x00, 0xfb,
+ 0xff, 0x00, 0x02, 0x00, 0x00, 0xfb, 0x80, 0xfe, 0x02, 0xfc, 0x00, 0x00,
+ 0x80, 0xfe, 0x00, 0xfb, 0xff, 0x00, 0x81, 0x00, 0x00, 0xfb, 0x80, 0xfe,
+ 0x04, 0x00, 0xfc, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x83, 0x00, 0x03, 0xfd,
+ 0xfe, 0xfe, 0xfc, 0x80, 0xfe, 0x00, 0xeb, 0xff, 0x00, 0x83, 0x00, 0x00,
+ 0xeb, 0x82, 0xfe, 0x00, 0xfd, 0xff, 0x00, 0x85, 0x00, 0x00, 0xfd, 0x81,
+ 0xfe, 0x00, 0xfa, 0xff, 0x00, 0x85, 0x00, 0x00, 0xfa, 0x81, 0xfe, 0x00,
+ 0xf3, 0xff, 0x00, 0x85, 0x00, 0x00, 0xeb, 0x81, 0xfe, 0xff, 0x00, 0x87,
+ 0x00, 0x81, 0xfe, 0xff, 0x00, 0x87, 0x00, 0x81, 0xfe, 0xff, 0x00, 0x87,
+ 0x00, 0x80, 0xfe, 0x00, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe,
+ 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff,
+ 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00,
+ 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe,
+ 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff,
+ 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00,
+ 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe,
+ 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff,
+ 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00,
+ 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe,
+ 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff,
+ 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00,
+ 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe,
+ 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff,
+ 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00,
+ 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe,
+ 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff,
+ 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00,
+ 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe,
+ 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff,
+ 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00,
+ 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe,
+ 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff,
+ 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00,
+ 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe,
+ 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff,
+ 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00,
+ 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe,
+ 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff,
+ 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00,
+ 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe,
+ 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff,
+ 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00,
+ 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe,
+ 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff,
+ 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00,
+ 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe,
+ 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff,
+ 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00,
+ 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe,
+ 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff,
+ 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00,
+ 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe,
+ 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff,
+ 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00,
+ 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe,
+ 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff,
+ 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00,
+ 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe,
+ 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff,
+ 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00,
+ 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe,
+ 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff,
+ 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00,
+ 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe,
+ 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff,
+ 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00,
+ 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe,
+ 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff,
+ 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00,
+ 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe,
+ 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff,
+ 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00,
+ 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe,
+ 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff,
+ 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00,
+ 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe,
+ 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff,
+ 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00,
+ 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe,
+ 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff,
+ 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00,
+ 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe,
+ 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff,
+ 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00,
+ 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe,
+ 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff,
+ 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00,
+ 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe,
+ 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff,
+ 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00,
+ 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe,
+ 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff,
+ 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00,
+ 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe,
+ 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff,
+ 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00,
+ 0x00, 0xfd, 0x80, 0xfe, 0xff, 0x00, 0x87, 0x00, 0x81, 0xfe, 0xff, 0x00,
+ 0x87, 0x00, 0x81, 0xfe, 0xff, 0x00, 0x87, 0x00, 0x81, 0xfe, 0x00, 0xeb,
+ 0xff, 0x00, 0x85, 0x00, 0x00, 0xeb, 0x81, 0xfe, 0x00, 0xfa, 0xff, 0x00,
+ 0x85, 0x00, 0x00, 0xfa, 0x81, 0xfe, 0x00, 0xfd, 0xff, 0x00, 0x85, 0x00,
+ 0x00, 0xfd, 0x82, 0xfe, 0x00, 0xeb, 0xff, 0x00, 0x83, 0x00, 0x00, 0xeb,
+ 0x80, 0xfe, 0x03, 0xfc, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x83, 0x00, 0x04,
+ 0xfd, 0xfe, 0xfe, 0xfc, 0x00, 0x80, 0xfe, 0x00, 0xfb, 0xff, 0x00, 0x81,
+ 0x00, 0x00, 0xfb, 0x80, 0xfe, 0x02, 0x00, 0x00, 0xfc, 0x80, 0xfe, 0x00,
+ 0xfb, 0xff, 0x00, 0x02, 0x00, 0x00, 0xfb, 0x80, 0xfe, 0x00, 0xfc, 0x80,
+ 0x00, 0x00, 0xfd, 0x80, 0xfe, 0x01, 0xfd, 0xeb, 0xfd, 0x00, 0x01, 0xeb,
+ 0xfd, 0x80, 0xfe, 0x00, 0xfd, 0x82, 0x00, 0x00, 0xfd, 0x81, 0xfe, 0x02,
+ 0xfd, 0xfb, 0xf3, 0xf7, 0x00, 0x02, 0xf3, 0xfb, 0xfd, 0x81, 0xfe, 0x00,
+ 0xfd, 0x84, 0x00, 0x00, 0xf3, 0x86, 0xfe, 0xf1, 0xfd, 0x86, 0xfe, 0x00,
+ 0xf7, 0x87, 0x00, 0x00, 0xfc, 0xff, 0xfe, 0x00, 0xfc, 0x83, 0x00, 0x83,
+ 0x00, 0x00, 0xfb, 0xff, 0xfe, 0x00, 0xfb, 0x87, 0x00, 0x00, 0xf3, 0x86,
+ 0xfe, 0xf1, 0xfd, 0x86, 0xfe, 0x00, 0xf3, 0x84, 0x00, 0x00, 0xfd, 0x81,
+ 0xfe, 0x02, 0xfd, 0xfb, 0xf3, 0xf7, 0x00, 0x02, 0xf3, 0xfb, 0xfd, 0x81,
+ 0xfe, 0x00, 0xfd, 0x82, 0x00, 0x00, 0xfd, 0x80, 0xfe, 0x01, 0xfd, 0xf3,
+ 0xfd, 0x00, 0x01, 0xf3, 0xfd, 0x80, 0xfe, 0x00, 0xfd, 0x80, 0x00, 0x00,
+ 0xfc, 0x80, 0xfe, 0x00, 0xfb, 0xff, 0x00, 0x02, 0x00, 0x00, 0xfb, 0x80,
+ 0xfe, 0x02, 0xfc, 0x00, 0x00, 0x80, 0xfe, 0x00, 0xfb, 0xff, 0x00, 0x81,
+ 0x00, 0x00, 0xfb, 0x80, 0xfe, 0x04, 0x00, 0xfc, 0xfe, 0xfe, 0xfd, 0xff,
+ 0x00, 0x83, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfc, 0x80, 0xfe, 0x00, 0xeb,
+ 0xff, 0x00, 0x83, 0x00, 0x00, 0xeb, 0x82, 0xfe, 0x00, 0xfd, 0xff, 0x00,
+ 0x85, 0x00, 0x00, 0xfd, 0x81, 0xfe, 0x00, 0xfa, 0xff, 0x00, 0x85, 0x00,
+ 0x00, 0xfa, 0x81, 0xfe, 0x00, 0xf3, 0xff, 0x00, 0x85, 0x00, 0x00, 0xeb,
+ 0x81, 0xfe, 0xff, 0x00, 0x87, 0x00, 0x81, 0xfe, 0xff, 0x00, 0x87, 0x00,
+ 0x81, 0xfe, 0xff, 0x00, 0x87, 0x00, 0x80, 0xfe, 0x00, 0xfd, 0xff, 0x00,
+ 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03,
+ 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe,
+ 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00,
+ 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03,
+ 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe,
+ 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00,
+ 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03,
+ 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe,
+ 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00,
+ 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03,
+ 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe,
+ 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00,
+ 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03,
+ 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe,
+ 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00,
+ 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03,
+ 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe,
+ 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00,
+ 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03,
+ 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe,
+ 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00,
+ 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03,
+ 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe,
+ 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00,
+ 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03,
+ 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe,
+ 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00,
+ 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03,
+ 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe,
+ 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00,
+ 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03,
+ 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe,
+ 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00,
+ 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03,
+ 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe,
+ 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00,
+ 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03,
+ 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe,
+ 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00,
+ 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03,
+ 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe,
+ 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00,
+ 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03,
+ 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe,
+ 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00,
+ 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03,
+ 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe,
+ 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00,
+ 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03,
+ 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe,
+ 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00,
+ 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03,
+ 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe,
+ 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00,
+ 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03,
+ 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe,
+ 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00,
+ 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03,
+ 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe,
+ 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00,
+ 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03,
+ 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe,
+ 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00,
+ 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03,
+ 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe,
+ 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00,
+ 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03,
+ 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe,
+ 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00,
+ 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03,
+ 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe,
+ 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00,
+ 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03,
+ 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe,
+ 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00,
+ 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03,
+ 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe,
+ 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00,
+ 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03,
+ 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe,
+ 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00,
+ 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03,
+ 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe,
+ 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00,
+ 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03,
+ 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe,
+ 0xfd, 0xff, 0x00, 0x87, 0x00, 0x00, 0xfd, 0x80, 0xfe, 0xff, 0x00, 0x87,
+ 0x00, 0x81, 0xfe, 0xff, 0x00, 0x87, 0x00, 0x81, 0xfe, 0xff, 0x00, 0x87,
+ 0x00, 0x81, 0xfe, 0x00, 0xeb, 0xff, 0x00, 0x85, 0x00, 0x00, 0xeb, 0x81,
+ 0xfe, 0x00, 0xfa, 0xff, 0x00, 0x85, 0x00, 0x00, 0xfa, 0x81, 0xfe, 0x00,
+ 0xfd, 0xff, 0x00, 0x85, 0x00, 0x00, 0xfd, 0x82, 0xfe, 0x00, 0xeb, 0xff,
+ 0x00, 0x83, 0x00, 0x00, 0xeb, 0x80, 0xfe, 0x03, 0xfc, 0xfe, 0xfe, 0xfd,
+ 0xff, 0x00, 0x83, 0x00, 0x04, 0xfd, 0xfe, 0xfe, 0xfc, 0x00, 0x80, 0xfe,
+ 0x00, 0xfb, 0xff, 0x00, 0x81, 0x00, 0x00, 0xfb, 0x80, 0xfe, 0x02, 0x00,
+ 0x00, 0xfc, 0x80, 0xfe, 0x00, 0xfb, 0xff, 0x00, 0x02, 0x00, 0x00, 0xfb,
+ 0x80, 0xfe, 0x00, 0xfc, 0x80, 0x00, 0x00, 0xfd, 0x80, 0xfe, 0x01, 0xfd,
+ 0xeb, 0xfd, 0x00, 0x01, 0xeb, 0xfd, 0x80, 0xfe, 0x00, 0xfd, 0x82, 0x00,
+ 0x00, 0xfd, 0x81, 0xfe, 0x02, 0xfd, 0xfb, 0xf3, 0xf7, 0x00, 0x02, 0xf3,
+ 0xfb, 0xfd, 0x81, 0xfe, 0x00, 0xfd, 0x84, 0x00, 0x00, 0xf3, 0x86, 0xfe,
+ 0xf1, 0xfd, 0x86, 0xfe, 0x00, 0xf7, 0x87, 0x00, 0x00, 0xfc, 0xff, 0xfe,
+ 0x00, 0xfc, 0x83, 0x00, 0x83, 0x03, 0x02, 0x1f, 0x47, 0x58, 0xfb, 0x70,
+ 0x02, 0x58, 0x47, 0x1f, 0x87, 0x03, 0x01, 0x0a, 0x58, 0x80, 0x70, 0x04,
+ 0x6c, 0x5c, 0x54, 0x4b, 0x43, 0xf1, 0x3f, 0x04, 0x43, 0x4b, 0x54, 0x5c,
+ 0x6c, 0x80, 0x70, 0x01, 0x58, 0x0a, 0x84, 0x03, 0x0b, 0x2f, 0x6c, 0x70,
+ 0x70, 0x54, 0x33, 0x1b, 0x0a, 0x03, 0x04, 0x05, 0x07, 0xef, 0x08, 0x0b,
+ 0x07, 0x05, 0x04, 0x03, 0x0a, 0x1b, 0x33, 0x54, 0x70, 0x70, 0x6c, 0x2f,
+ 0x82, 0x03, 0x0c, 0x3b, 0x70, 0x70, 0x5c, 0x2f, 0x0a, 0x09, 0x11, 0x16,
+ 0x1a, 0x1c, 0x1e, 0x1e, 0xef, 0x20, 0x0c, 0x1e, 0x1e, 0x1c, 0x1a, 0x16,
+ 0x11, 0x09, 0x0a, 0x2f, 0x5c, 0x70, 0x70, 0x3b, 0x80, 0x03, 0x0d, 0x23,
+ 0x70, 0x70, 0x54, 0x1f, 0x07, 0x14, 0x1e, 0x28, 0x2d, 0x30, 0x31, 0x32,
+ 0x34, 0xef, 0x35, 0x1c, 0x34, 0x32, 0x31, 0x30, 0x2d, 0x28, 0x1e, 0x14,
+ 0x07, 0x1f, 0x54, 0x70, 0x70, 0x23, 0x03, 0x01, 0x64, 0x70, 0x5c, 0x1f,
+ 0x0b, 0x1a, 0x28, 0x32, 0x39, 0x3e, 0x41, 0x43, 0x43, 0xf1, 0x45, 0x1b,
+ 0x43, 0x43, 0x41, 0x3e, 0x39, 0x32, 0x28, 0x1a, 0x0b, 0x1f, 0x5c, 0x70,
+ 0x60, 0x01, 0x23, 0x70, 0x70, 0x2b, 0x08, 0x1a, 0x2a, 0x37, 0x42, 0x49,
+ 0x4d, 0x4f, 0x51, 0x52, 0xf1, 0x53, 0x1a, 0x52, 0x51, 0x4f, 0x4d, 0x49,
+ 0x42, 0x37, 0x2a, 0x1a, 0x08, 0x2b, 0x70, 0x70, 0x23, 0x47, 0x70, 0x50,
+ 0x06, 0x14, 0x28, 0x37, 0x45, 0x4e, 0x55, 0x59, 0x5b, 0x5b, 0xf3, 0x5c,
+ 0x18, 0x5b, 0x5b, 0x59, 0x55, 0x4e, 0x45, 0x37, 0x28, 0x14, 0x06, 0x50,
+ 0x70, 0x47, 0x60, 0x70, 0x2f, 0x09, 0x20, 0x32, 0x42, 0x4e, 0x57, 0x5e,
+ 0x60, 0x62, 0x80, 0x63, 0xef, 0x64, 0x80, 0x63, 0x17, 0x62, 0x60, 0x5e,
+ 0x57, 0x4e, 0x42, 0x32, 0x20, 0x09, 0x2f, 0x70, 0x60, 0x68, 0x6c, 0x16,
+ 0x11, 0x28, 0x3a, 0x49, 0x55, 0x5e, 0x63, 0x66, 0x66, 0xf5, 0x67, 0x16,
+ 0x66, 0x66, 0x63, 0x5e, 0x56, 0x49, 0x3a, 0x28, 0x11, 0x16, 0x6c, 0x6c,
+ 0x70, 0x5c, 0x0a, 0x18, 0x2d, 0x3f, 0x4e, 0x5a, 0x60, 0x66, 0x66, 0xf7,
+ 0x67, 0x14, 0x66, 0x66, 0x60, 0x5a, 0x4e, 0x3f, 0x2d, 0x18, 0x06, 0x5c,
+ 0x70, 0x70, 0x50, 0x03, 0x1a, 0x30, 0x41, 0x4f, 0x5b, 0x62, 0x66, 0xf9,
+ 0x67, 0x12, 0x66, 0x62, 0x5b, 0x4f, 0x41, 0x30, 0x1a, 0x03, 0x50, 0x70,
+ 0x70, 0x4b, 0x04, 0x1c, 0x32, 0x43, 0x52, 0x5b, 0x63, 0xfb, 0x67, 0x11,
+ 0x63, 0x5b, 0x52, 0x43, 0x32, 0x1d, 0x04, 0x4b, 0x70, 0x70, 0x43, 0x07,
+ 0x1e, 0x32, 0x45, 0x52, 0x5c, 0x63, 0xfb, 0x67, 0x11, 0x63, 0x5c, 0x52,
+ 0x45, 0x32, 0x1e, 0x07, 0x43, 0x70, 0x70, 0x3f, 0x07, 0x1e, 0x34, 0x45,
+ 0x53, 0x5c, 0x63, 0xfb, 0x67, 0x11, 0x63, 0x5c, 0x53, 0x45, 0x34, 0x1e,
+ 0x07, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64,
+ 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70,
+ 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11,
+ 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08,
+ 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53,
+ 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45,
+ 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20,
+ 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64,
+ 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70,
+ 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11,
+ 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08,
+ 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53,
+ 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45,
+ 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20,
+ 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64,
+ 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70,
+ 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11,
+ 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08,
+ 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53,
+ 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45,
+ 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20,
+ 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64,
+ 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70,
+ 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11,
+ 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08,
+ 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53,
+ 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45,
+ 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20,
+ 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64,
+ 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70,
+ 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11,
+ 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08,
+ 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53,
+ 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45,
+ 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20,
+ 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64,
+ 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70,
+ 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11,
+ 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08,
+ 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53,
+ 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45,
+ 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20,
+ 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64,
+ 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70,
+ 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11,
+ 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08,
+ 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53,
+ 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45,
+ 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20,
+ 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64,
+ 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70,
+ 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11,
+ 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08,
+ 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53,
+ 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45,
+ 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20,
+ 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64,
+ 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70,
+ 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11,
+ 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08,
+ 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53,
+ 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45,
+ 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20,
+ 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64,
+ 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70,
+ 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11,
+ 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08,
+ 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53,
+ 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45,
+ 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20,
+ 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64,
+ 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70,
+ 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11,
+ 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08,
+ 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53,
+ 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45,
+ 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20,
+ 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64,
+ 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70,
+ 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11,
+ 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08,
+ 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53,
+ 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45,
+ 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20,
+ 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64,
+ 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70,
+ 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11,
+ 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08,
+ 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53,
+ 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45,
+ 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20,
+ 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64,
+ 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70,
+ 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11,
+ 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08,
+ 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53,
+ 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45,
+ 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20,
+ 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64,
+ 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70,
+ 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11,
+ 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08,
+ 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53,
+ 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45,
+ 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20,
+ 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64,
+ 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70,
+ 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11,
+ 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08,
+ 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53,
+ 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45,
+ 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20,
+ 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64,
+ 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70,
+ 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11,
+ 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08,
+ 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53,
+ 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45,
+ 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20,
+ 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64,
+ 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70,
+ 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11,
+ 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08,
+ 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53,
+ 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45,
+ 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20,
+ 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64,
+ 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70,
+ 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11,
+ 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08,
+ 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53,
+ 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45,
+ 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20,
+ 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64,
+ 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70,
+ 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11,
+ 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08,
+ 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53,
+ 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45,
+ 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20,
+ 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64,
+ 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70,
+ 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11,
+ 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08,
+ 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53,
+ 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45,
+ 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20,
+ 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64,
+ 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70,
+ 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11,
+ 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08,
+ 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53,
+ 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45,
+ 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20,
+ 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64,
+ 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70,
+ 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11,
+ 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08,
+ 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53,
+ 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45,
+ 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20,
+ 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64,
+ 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70,
+ 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11,
+ 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08,
+ 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53,
+ 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45,
+ 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20,
+ 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64,
+ 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70,
+ 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11,
+ 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08,
+ 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53,
+ 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45,
+ 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20,
+ 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64,
+ 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70,
+ 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11,
+ 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08,
+ 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53,
+ 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45,
+ 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20,
+ 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64,
+ 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70,
+ 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11,
+ 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08,
+ 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53,
+ 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45,
+ 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20,
+ 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64,
+ 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70,
+ 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11,
+ 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08,
+ 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53,
+ 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45,
+ 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20,
+ 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64,
+ 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70,
+ 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11,
+ 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x07,
+ 0x1e, 0x34, 0x45, 0x53, 0x5c, 0x63, 0xfb, 0x67, 0x11, 0x63, 0x5c, 0x53,
+ 0x45, 0x34, 0x1e, 0x07, 0x3f, 0x70, 0x70, 0x43, 0x07, 0x1e, 0x32, 0x45,
+ 0x52, 0x5c, 0x63, 0xfb, 0x67, 0x11, 0x63, 0x5c, 0x52, 0x45, 0x32, 0x1e,
+ 0x07, 0x43, 0x70, 0x70, 0x4b, 0x04, 0x1c, 0x32, 0x43, 0x52, 0x5b, 0x63,
+ 0xfb, 0x67, 0x12, 0x63, 0x5b, 0x52, 0x43, 0x32, 0x1d, 0x04, 0x4b, 0x70,
+ 0x70, 0x50, 0x03, 0x1a, 0x30, 0x41, 0x4f, 0x5b, 0x62, 0x66, 0xf9, 0x67,
+ 0x14, 0x66, 0x62, 0x5b, 0x4f, 0x41, 0x30, 0x1a, 0x03, 0x50, 0x70, 0x70,
+ 0x5c, 0x06, 0x18, 0x2d, 0x3f, 0x4e, 0x5a, 0x60, 0x66, 0x66, 0xf7, 0x67,
+ 0x16, 0x66, 0x66, 0x60, 0x5a, 0x4e, 0x3f, 0x2d, 0x18, 0x06, 0x5c, 0x70,
+ 0x68, 0x6c, 0x16, 0x11, 0x28, 0x3a, 0x49, 0x56, 0x5e, 0x63, 0x66, 0x66,
+ 0xf5, 0x67, 0x17, 0x66, 0x66, 0x63, 0x5e, 0x56, 0x49, 0x3a, 0x28, 0x11,
+ 0x16, 0x6c, 0x6c, 0x60, 0x70, 0x2f, 0x09, 0x20, 0x32, 0x42, 0x4e, 0x57,
+ 0x5e, 0x60, 0x62, 0x80, 0x63, 0xef, 0x64, 0x80, 0x63, 0x18, 0x62, 0x60,
+ 0x5e, 0x57, 0x4e, 0x42, 0x32, 0x20, 0x09, 0x2f, 0x70, 0x60, 0x47, 0x70,
+ 0x50, 0x06, 0x15, 0x28, 0x37, 0x45, 0x4e, 0x55, 0x59, 0x5b, 0x5b, 0xf3,
+ 0x5c, 0x1a, 0x5b, 0x5b, 0x59, 0x55, 0x4e, 0x45, 0x37, 0x28, 0x15, 0x06,
+ 0x50, 0x70, 0x47, 0x23, 0x70, 0x70, 0x2b, 0x08, 0x1a, 0x2a, 0x37, 0x42,
+ 0x49, 0x4d, 0x4f, 0x51, 0x52, 0xf1, 0x53, 0x1b, 0x52, 0x51, 0x4f, 0x4e,
+ 0x49, 0x42, 0x37, 0x2a, 0x1a, 0x08, 0x2b, 0x70, 0x70, 0x23, 0x01, 0x60,
+ 0x70, 0x58, 0x1f, 0x0b, 0x1a, 0x28, 0x32, 0x3a, 0x3e, 0x41, 0x43, 0x43,
+ 0xf1, 0x45, 0x1c, 0x43, 0x43, 0x41, 0x3e, 0x3a, 0x32, 0x28, 0x1a, 0x0b,
+ 0x1f, 0x58, 0x70, 0x60, 0x01, 0x03, 0x23, 0x70, 0x70, 0x54, 0x1f, 0x08,
+ 0x14, 0x20, 0x28, 0x2d, 0x30, 0x31, 0x32, 0x34, 0xef, 0x35, 0x0d, 0x34,
+ 0x32, 0x31, 0x30, 0x2d, 0x28, 0x20, 0x14, 0x08, 0x1f, 0x54, 0x70, 0x70,
+ 0x23, 0x80, 0x03, 0x0c, 0x3b, 0x70, 0x70, 0x5c, 0x2f, 0x06, 0x09, 0x11,
+ 0x16, 0x1a, 0x1c, 0x1e, 0x1e, 0xef, 0x20, 0x0c, 0x1e, 0x1e, 0x1c, 0x1a,
+ 0x16, 0x11, 0x09, 0x06, 0x2f, 0x5c, 0x70, 0x70, 0x3b, 0x82, 0x03, 0x0b,
+ 0x33, 0x6c, 0x70, 0x70, 0x54, 0x33, 0x1b, 0x0a, 0x03, 0x04, 0x07, 0x07,
+ 0xef, 0x08, 0x0b, 0x07, 0x07, 0x04, 0x03, 0x0a, 0x1b, 0x2f, 0x54, 0x70,
+ 0x70, 0x6c, 0x33, 0x84, 0x03, 0x01, 0x0a, 0x58, 0x80, 0x70, 0x04, 0x6c,
+ 0x5c, 0x54, 0x4b, 0x43, 0xf1, 0x3f, 0x04, 0x43, 0x4b, 0x54, 0x5c, 0x6c,
+ 0x80, 0x70, 0x01, 0x58, 0x0e, 0x87, 0x03, 0x02, 0x23, 0x47, 0x58, 0xfb,
+ 0x70, 0x02, 0x58, 0x47, 0x23, 0x83, 0x03,
+};
+static EG_EMBEDDED_IMAGE egemb_back_selected_big = { 144, 144, EG_EIPIXELMODE_COLOR_ALPHA, EG_EICOMPMODE_RLE, egemb_back_selected_big_data, 7951 };
diff --git a/include/egemb_back_selected_small.h b/include/egemb_back_selected_small.h
new file mode 100644 (file)
index 0000000..b2c433c
--- /dev/null
@@ -0,0 +1,154 @@
+static const UINT8 egemb_back_selected_small_data[1805] = {
+ 0x83, 0xbf, 0xb1, 0xff, 0x87, 0xbf, 0xb5, 0xff, 0x84, 0xbf, 0x85, 0xff,
+ 0x00, 0xbf, 0xa5, 0x00, 0x00, 0xbf, 0x85, 0xff, 0x82, 0xbf, 0x83, 0xff,
+ 0xad, 0x00, 0x83, 0xff, 0x80, 0xbf, 0x82, 0xff, 0xb1, 0x00, 0x82, 0xff,
+ 0x00, 0xbf, 0x82, 0xff, 0xb3, 0x00, 0x86, 0xff, 0xb5, 0x00, 0x85, 0xff,
+ 0xb5, 0x00, 0x84, 0xff, 0xb7, 0x00, 0x83, 0xff, 0xb7, 0x00, 0x83, 0xff,
+ 0xb7, 0x00, 0x82, 0xff, 0x00, 0xbf, 0xb7, 0x00, 0x00, 0xbf, 0x81, 0xff,
+ 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff,
+ 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff,
+ 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff,
+ 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff,
+ 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff,
+ 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff,
+ 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff,
+ 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff,
+ 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff,
+ 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff,
+ 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff,
+ 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff,
+ 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff,
+ 0xb9, 0x00, 0x81, 0xff, 0x00, 0xbf, 0xb7, 0x00, 0x00, 0xbf, 0x82, 0xff,
+ 0xb7, 0x00, 0x83, 0xff, 0xb7, 0x00, 0x83, 0xff, 0xb7, 0x00, 0x84, 0xff,
+ 0xb5, 0x00, 0x85, 0xff, 0xb5, 0x00, 0x86, 0xff, 0xb3, 0x00, 0x82, 0xff,
+ 0x00, 0xbf, 0x82, 0xff, 0xb1, 0x00, 0x82, 0xff, 0x80, 0xbf, 0x83, 0xff,
+ 0xad, 0x00, 0x83, 0xff, 0x82, 0xbf, 0x85, 0xff, 0x00, 0xbf, 0xa5, 0x00,
+ 0x00, 0xbf, 0x85, 0xff, 0x84, 0xbf, 0xb5, 0xff, 0x87, 0xbf, 0xb1, 0xff,
+ 0x83, 0xbf, 0x83, 0x00, 0x02, 0x23, 0x4b, 0x5b, 0xab, 0x73, 0x02, 0x5b,
+ 0x4b, 0x23, 0x87, 0x00, 0x01, 0x0f, 0x5b, 0x80, 0x73, 0x04, 0x6f, 0x5f,
+ 0x57, 0x4f, 0x47, 0xa1, 0x43, 0x04, 0x47, 0x4f, 0x57, 0x5f, 0x6f, 0x80,
+ 0x73, 0x01, 0x5b, 0x0f, 0x84, 0x00, 0x0b, 0x33, 0x6f, 0x73, 0x73, 0x57,
+ 0x37, 0x1f, 0x0f, 0x00, 0x02, 0x03, 0x04, 0x9f, 0x06, 0x0b, 0x04, 0x03,
+ 0x02, 0x00, 0x0f, 0x1f, 0x37, 0x57, 0x73, 0x73, 0x6f, 0x33, 0x82, 0x00,
+ 0x0c, 0x3f, 0x73, 0x73, 0x5f, 0x33, 0x0f, 0x07, 0x0f, 0x14, 0x18, 0x1a,
+ 0x1c, 0x1c, 0x9f, 0x1e, 0x0c, 0x1c, 0x1c, 0x1a, 0x18, 0x14, 0x0f, 0x07,
+ 0x0f, 0x33, 0x5f, 0x73, 0x73, 0x3f, 0x80, 0x00, 0x0d, 0x27, 0x73, 0x73,
+ 0x57, 0x23, 0x04, 0x12, 0x1c, 0x26, 0x2b, 0x2e, 0x2f, 0x30, 0x32, 0x9f,
+ 0x33, 0x1c, 0x32, 0x30, 0x2f, 0x2e, 0x2b, 0x26, 0x1c, 0x12, 0x04, 0x23,
+ 0x57, 0x73, 0x73, 0x27, 0x00, 0x03, 0x67, 0x73, 0x5f, 0x23, 0x08, 0x18,
+ 0x26, 0x30, 0x37, 0x3c, 0x3f, 0x42, 0x42, 0xa1, 0x43, 0x1b, 0x42, 0x42,
+ 0x3f, 0x3c, 0x37, 0x30, 0x26, 0x18, 0x08, 0x23, 0x5f, 0x73, 0x63, 0x03,
+ 0x27, 0x73, 0x73, 0x2f, 0x06, 0x18, 0x28, 0x36, 0x40, 0x47, 0x4b, 0x4e,
+ 0x4f, 0x50, 0xa1, 0x52, 0x1a, 0x50, 0x4f, 0x4e, 0x4b, 0x47, 0x40, 0x36,
+ 0x28, 0x18, 0x06, 0x2f, 0x73, 0x73, 0x27, 0x4b, 0x73, 0x53, 0x0b, 0x12,
+ 0x26, 0x36, 0x43, 0x4c, 0x53, 0x57, 0x5a, 0x5a, 0xa3, 0x5b, 0x18, 0x5a,
+ 0x5a, 0x57, 0x53, 0x4c, 0x43, 0x36, 0x26, 0x12, 0x0b, 0x53, 0x73, 0x4b,
+ 0x63, 0x73, 0x33, 0x07, 0x1e, 0x30, 0x40, 0x4c, 0x56, 0x5c, 0x5f, 0x60,
+ 0x80, 0x62, 0x9f, 0x63, 0x80, 0x62, 0x17, 0x60, 0x5f, 0x5c, 0x56, 0x4c,
+ 0x40, 0x30, 0x1e, 0x07, 0x33, 0x73, 0x63, 0x6b, 0x6f, 0x1b, 0x0f, 0x26,
+ 0x38, 0x47, 0x53, 0x5c, 0x62, 0x64, 0x64, 0xa5, 0x66, 0x16, 0x64, 0x64,
+ 0x62, 0x5c, 0x54, 0x47, 0x38, 0x26, 0x0f, 0x1b, 0x6f, 0x6f, 0x73, 0x5f,
+ 0x0f, 0x16, 0x2b, 0x3e, 0x4c, 0x58, 0x5f, 0x64, 0x64, 0xa7, 0x66, 0x14,
+ 0x64, 0x64, 0x5f, 0x58, 0x4c, 0x3e, 0x2b, 0x16, 0x0b, 0x5f, 0x73, 0x73,
+ 0x53, 0x00, 0x18, 0x2e, 0x3f, 0x4e, 0x5a, 0x60, 0x64, 0xa9, 0x66, 0x12,
+ 0x64, 0x60, 0x5a, 0x4e, 0x3f, 0x2e, 0x18, 0x00, 0x53, 0x73, 0x73, 0x4f,
+ 0x02, 0x1a, 0x30, 0x42, 0x50, 0x5a, 0x62, 0xab, 0x66, 0x11, 0x62, 0x5a,
+ 0x50, 0x42, 0x30, 0x1b, 0x02, 0x4f, 0x73, 0x73, 0x47, 0x04, 0x1c, 0x30,
+ 0x43, 0x50, 0x5b, 0x62, 0xab, 0x66, 0x11, 0x62, 0x5b, 0x50, 0x43, 0x30,
+ 0x1c, 0x04, 0x47, 0x73, 0x73, 0x43, 0x04, 0x1c, 0x32, 0x43, 0x52, 0x5b,
+ 0x62, 0xab, 0x66, 0x11, 0x62, 0x5b, 0x52, 0x43, 0x32, 0x1c, 0x04, 0x43,
+ 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66,
+ 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43,
+ 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b,
+ 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33,
+ 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33,
+ 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b,
+ 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43,
+ 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66,
+ 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43,
+ 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b,
+ 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33,
+ 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33,
+ 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b,
+ 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43,
+ 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66,
+ 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43,
+ 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b,
+ 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33,
+ 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33,
+ 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b,
+ 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43,
+ 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66,
+ 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43,
+ 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b,
+ 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33,
+ 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33,
+ 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b,
+ 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43,
+ 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66,
+ 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43,
+ 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b,
+ 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33,
+ 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33,
+ 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b,
+ 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43,
+ 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66,
+ 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43,
+ 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b,
+ 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33,
+ 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33,
+ 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b,
+ 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43,
+ 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66,
+ 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43,
+ 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b,
+ 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33,
+ 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33,
+ 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b,
+ 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43,
+ 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66,
+ 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43,
+ 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b,
+ 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33,
+ 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33,
+ 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b,
+ 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43,
+ 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66,
+ 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43,
+ 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b,
+ 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x04, 0x1c, 0x32,
+ 0x43, 0x52, 0x5b, 0x62, 0xab, 0x66, 0x11, 0x62, 0x5b, 0x52, 0x43, 0x32,
+ 0x1c, 0x04, 0x43, 0x73, 0x73, 0x47, 0x04, 0x1c, 0x30, 0x43, 0x50, 0x5b,
+ 0x62, 0xab, 0x66, 0x11, 0x62, 0x5b, 0x50, 0x43, 0x30, 0x1c, 0x04, 0x47,
+ 0x73, 0x73, 0x4f, 0x02, 0x1a, 0x30, 0x42, 0x50, 0x5a, 0x62, 0xab, 0x66,
+ 0x12, 0x62, 0x5a, 0x50, 0x42, 0x30, 0x1b, 0x02, 0x4f, 0x73, 0x73, 0x53,
+ 0x00, 0x18, 0x2e, 0x3f, 0x4e, 0x5a, 0x60, 0x64, 0xa9, 0x66, 0x14, 0x64,
+ 0x60, 0x5a, 0x4e, 0x3f, 0x2e, 0x18, 0x00, 0x53, 0x73, 0x73, 0x5f, 0x0b,
+ 0x16, 0x2b, 0x3e, 0x4c, 0x58, 0x5f, 0x64, 0x64, 0xa7, 0x66, 0x16, 0x64,
+ 0x64, 0x5f, 0x58, 0x4c, 0x3e, 0x2b, 0x16, 0x0b, 0x5f, 0x73, 0x6b, 0x6f,
+ 0x1b, 0x0f, 0x26, 0x38, 0x47, 0x54, 0x5c, 0x62, 0x64, 0x64, 0xa5, 0x66,
+ 0x17, 0x64, 0x64, 0x62, 0x5c, 0x54, 0x47, 0x38, 0x26, 0x0f, 0x1b, 0x6f,
+ 0x6f, 0x63, 0x73, 0x33, 0x07, 0x1e, 0x30, 0x40, 0x4c, 0x56, 0x5c, 0x5f,
+ 0x60, 0x80, 0x62, 0x9f, 0x63, 0x80, 0x62, 0x18, 0x60, 0x5f, 0x5c, 0x56,
+ 0x4c, 0x40, 0x30, 0x1e, 0x07, 0x33, 0x73, 0x63, 0x4b, 0x73, 0x53, 0x0b,
+ 0x13, 0x26, 0x36, 0x43, 0x4c, 0x53, 0x57, 0x5a, 0x5a, 0xa3, 0x5b, 0x1a,
+ 0x5a, 0x5a, 0x57, 0x53, 0x4c, 0x43, 0x36, 0x26, 0x13, 0x0b, 0x53, 0x73,
+ 0x4b, 0x27, 0x73, 0x73, 0x2f, 0x06, 0x18, 0x28, 0x36, 0x40, 0x47, 0x4b,
+ 0x4e, 0x4f, 0x50, 0xa1, 0x52, 0x1b, 0x50, 0x4f, 0x4e, 0x4c, 0x47, 0x40,
+ 0x36, 0x28, 0x18, 0x06, 0x2f, 0x73, 0x73, 0x27, 0x03, 0x63, 0x73, 0x5b,
+ 0x23, 0x08, 0x18, 0x26, 0x30, 0x38, 0x3c, 0x3f, 0x42, 0x42, 0xa1, 0x43,
+ 0x1c, 0x42, 0x42, 0x3f, 0x3c, 0x38, 0x30, 0x26, 0x18, 0x08, 0x23, 0x5b,
+ 0x73, 0x63, 0x03, 0x00, 0x27, 0x73, 0x73, 0x57, 0x23, 0x06, 0x12, 0x1e,
+ 0x26, 0x2b, 0x2e, 0x2f, 0x30, 0x32, 0x9f, 0x33, 0x0d, 0x32, 0x30, 0x2f,
+ 0x2e, 0x2b, 0x26, 0x1e, 0x12, 0x06, 0x23, 0x57, 0x73, 0x73, 0x27, 0x80,
+ 0x00, 0x0c, 0x3f, 0x73, 0x73, 0x5f, 0x33, 0x0b, 0x07, 0x0f, 0x14, 0x18,
+ 0x1a, 0x1c, 0x1c, 0x9f, 0x1e, 0x0c, 0x1c, 0x1c, 0x1a, 0x18, 0x14, 0x0f,
+ 0x07, 0x0b, 0x33, 0x5f, 0x73, 0x73, 0x3f, 0x82, 0x00, 0x0b, 0x37, 0x6f,
+ 0x73, 0x73, 0x57, 0x37, 0x1f, 0x0f, 0x00, 0x02, 0x04, 0x04, 0x9f, 0x06,
+ 0x0b, 0x04, 0x04, 0x02, 0x00, 0x0f, 0x1f, 0x33, 0x57, 0x73, 0x73, 0x6f,
+ 0x37, 0x84, 0x00, 0x01, 0x0f, 0x5b, 0x80, 0x73, 0x04, 0x6f, 0x5f, 0x57,
+ 0x4f, 0x47, 0xa1, 0x43, 0x04, 0x47, 0x4f, 0x57, 0x5f, 0x6f, 0x80, 0x73,
+ 0x01, 0x5b, 0x13, 0x87, 0x00, 0x02, 0x27, 0x4b, 0x5b, 0xab, 0x73, 0x02,
+ 0x5b, 0x4b, 0x27, 0x83, 0x00,
+};
+static EG_EMBEDDED_IMAGE egemb_back_selected_small = { 64, 64, EG_EIPIXELMODE_GRAY_ALPHA, EG_EICOMPMODE_RLE, egemb_back_selected_small_data, 1805 };
diff --git a/include/egemb_refind_banner.h b/include/egemb_refind_banner.h
new file mode 100644 (file)
index 0000000..4ab7e6a
--- /dev/null
@@ -0,0 +1,1932 @@
+/*
+ * include/egemb_refind_banner.h
+ * An encoded rEFInd banner graphic
+ *
+ * Copyright (c) 2015 Roderick W. Smith
+ * All rights reserved.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+static const UINT8 egemb_refind_banner_data[22887] = {
+ 0x94, 0xd0, 0x12, 0xcf, 0xce, 0xcd, 0xcc, 0xcb, 0xc9, 0xc7, 0xc6, 0xc5,
+ 0xc4, 0xc4, 0xc6, 0xc7, 0xc9, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xff, 0xd0,
+ 0xb7, 0xd0, 0x18, 0xcf, 0xcf, 0xcd, 0xcc, 0xc9, 0xc6, 0xc2, 0xbc, 0xa4,
+ 0x8b, 0x7a, 0x69, 0x73, 0x85, 0x9e, 0xb4, 0xba, 0xbe, 0xc2, 0xc6, 0xc9,
+ 0xcc, 0xcd, 0xcf, 0xcf, 0xff, 0xd0, 0xb3, 0xd0, 0x08, 0xcf, 0xcd, 0xcb,
+ 0xc7, 0xc2, 0xa9, 0x64, 0x2a, 0x0a, 0x83, 0x00, 0x0d, 0x01, 0x0b, 0x22,
+ 0x56, 0x95, 0xb4, 0xbb, 0xc2, 0xc7, 0xcb, 0xcd, 0xcf, 0xd0, 0xd0, 0x81,
+ 0xcf, 0xff, 0xd0, 0xaa, 0xd0, 0x07, 0xcf, 0xce, 0xcc, 0xc7, 0xb8, 0x73,
+ 0x37, 0x07, 0x8a, 0x00, 0x0f, 0x04, 0x2d, 0x65, 0xa4, 0xb8, 0xc1, 0xc7,
+ 0xcc, 0xce, 0xce, 0xcd, 0xcc, 0xcc, 0xcd, 0xce, 0xcf, 0xff, 0xd0, 0xa7,
+ 0xd0, 0x05, 0xcf, 0xcd, 0xca, 0xc3, 0x76, 0x12, 0x90, 0x00, 0x0c, 0x11,
+ 0x69, 0xac, 0xba, 0xc3, 0xc8, 0xca, 0xc7, 0x8f, 0xc4, 0xc7, 0xcc, 0xce,
+ 0xa3, 0xd0, 0x8b, 0xcf, 0x89, 0xd0, 0x89, 0xcf, 0xb9, 0xd0, 0x83, 0xcf,
+ 0x9a, 0xd0, 0x05, 0xcf, 0xcc, 0xc7, 0xb2, 0x45, 0x01, 0x92, 0x00, 0x0c,
+ 0x01, 0x37, 0x94, 0xb2, 0xbc, 0xbf, 0x64, 0x0a, 0xb3, 0xbd, 0xc6, 0xcc,
+ 0xcf, 0x9e, 0xd0, 0x04, 0xcf, 0xcf, 0xce, 0xcd, 0xcd, 0x89, 0xcc, 0x03,
+ 0xcd, 0xcd, 0xce, 0xcf, 0x82, 0xd0, 0x03, 0xcf, 0xcf, 0xce, 0xcd, 0x88,
+ 0xcc, 0x03, 0xcd, 0xcd, 0xce, 0xcf, 0x82, 0xd0, 0x06, 0xcf, 0xce, 0xce,
+ 0xcd, 0xce, 0xcf, 0xcf, 0xa9, 0xd0, 0x07, 0xcf, 0xcd, 0xcc, 0xcb, 0xcb,
+ 0xcc, 0xcd, 0xcf, 0x98, 0xd0, 0x04, 0xce, 0xcc, 0xc6, 0x8a, 0x1d, 0x96,
+ 0x00, 0x0a, 0x13, 0x69, 0xa4, 0x5d, 0x0d, 0x0a, 0x83, 0xad, 0xbf, 0xca,
+ 0xce, 0x9d, 0xd0, 0x05, 0xcf, 0xcd, 0xcb, 0xc8, 0xc6, 0xc4, 0x89, 0xc3,
+ 0x0d, 0xc5, 0xc6, 0xc9, 0xcc, 0xce, 0xcf, 0xd0, 0xd0, 0xcf, 0xcc, 0xcb,
+ 0xc7, 0xc6, 0xc4, 0x87, 0xc3, 0x10, 0xc5, 0xc6, 0xc9, 0xcc, 0xce, 0xcf,
+ 0xd0, 0xcf, 0xce, 0xcc, 0xca, 0xc7, 0xc6, 0xc8, 0xcc, 0xcd, 0xcf, 0xa7,
+ 0xd0, 0x09, 0xce, 0xcc, 0xc7, 0xbb, 0xb7, 0xbf, 0xc2, 0xc8, 0xcc, 0xcf,
+ 0x96, 0xd0, 0x04, 0xcf, 0xcc, 0xc5, 0x63, 0x06, 0x98, 0x00, 0x09, 0x01,
+ 0x29, 0x0a, 0x00, 0x00, 0x50, 0x9e, 0xb6, 0xc6, 0xcd, 0x9c, 0xd0, 0x06,
+ 0xcf, 0xcc, 0xc7, 0xad, 0x87, 0x76, 0x6e, 0x88, 0x6d, 0x0e, 0x6f, 0x8b,
+ 0xb3, 0xbc, 0xc4, 0xca, 0xce, 0xcf, 0xce, 0xcc, 0xc6, 0xa1, 0x83, 0x73,
+ 0x6e, 0x86, 0x6d, 0x12, 0x6e, 0x8a, 0xb2, 0xbc, 0xc3, 0xca, 0xcd, 0xcf,
+ 0xce, 0xcb, 0xc2, 0x8a, 0x69, 0x9e, 0xbb, 0xc2, 0xc9, 0xcd, 0xcf, 0xa5,
+ 0xd0, 0x0b, 0xcf, 0xcc, 0xb7, 0x41, 0x08, 0x06, 0x37, 0xae, 0xbc, 0xc6,
+ 0xcc, 0xcf, 0x94, 0xd0, 0x04, 0xcf, 0xcc, 0xc6, 0x79, 0x03, 0x88, 0x00,
+ 0x06, 0x04, 0x17, 0x24, 0x25, 0x23, 0x1a, 0x09, 0x87, 0x00, 0x01, 0x07,
+ 0x07, 0x80, 0x00, 0x05, 0x28, 0x90, 0xae, 0xc2, 0xcc, 0xcf, 0x9a, 0xd0,
+ 0x04, 0xcf, 0xcc, 0xc5, 0x4b, 0x03, 0x8d, 0x00, 0x08, 0x06, 0x81, 0xb4,
+ 0xc2, 0xcb, 0xcd, 0xcc, 0xba, 0x2e, 0x8c, 0x00, 0x08, 0x04, 0x77, 0xb4,
+ 0xc2, 0xcb, 0xcd, 0xcb, 0xa9, 0x11, 0x80, 0x00, 0x04, 0x6d, 0xb2, 0xc0,
+ 0xca, 0xce, 0xa4, 0xd0, 0x03, 0xcf, 0xcd, 0xc6, 0x56, 0x81, 0x00, 0x04,
+ 0x6a, 0xab, 0xc0, 0xca, 0xce, 0x93, 0xd0, 0x04, 0xcf, 0xcd, 0xc7, 0x95,
+ 0x0d, 0x86, 0x00, 0x0c, 0x12, 0x2d, 0x46, 0x66, 0x73, 0x7a, 0x7e, 0x80,
+ 0x7f, 0x7a, 0x5c, 0x35, 0x0d, 0x83, 0x00, 0x01, 0x04, 0x04, 0x81, 0x00,
+ 0x05, 0x17, 0x86, 0xa8, 0xc0, 0xcb, 0xcf, 0x9a, 0xd0, 0x02, 0xce, 0xc9,
+ 0x73, 0x90, 0x00, 0x06, 0x32, 0xa1, 0xb8, 0xc6, 0xcb, 0xc6, 0x48, 0x8e,
+ 0x00, 0x06, 0x2b, 0xa0, 0xb7, 0xc6, 0xcb, 0xc6, 0x4d, 0x81, 0x00, 0x05,
+ 0x25, 0x9e, 0xb5, 0xc6, 0xcd, 0xcf, 0xa3, 0xd0, 0x03, 0xcf, 0xcb, 0xb3,
+ 0x06, 0x81, 0x00, 0x05, 0x45, 0x9c, 0xb7, 0xc6, 0xce, 0xcf, 0x92, 0xd0,
+ 0x03, 0xce, 0xc9, 0xad, 0x1b, 0x85, 0x00, 0x10, 0x08, 0x35, 0x67, 0x76,
+ 0x84, 0x8e, 0x98, 0x9e, 0xa3, 0xa4, 0xa3, 0x9f, 0x99, 0x90, 0x81, 0x47,
+ 0x0b, 0x80, 0x00, 0x01, 0x04, 0x04, 0x82, 0x00, 0x05, 0x0e, 0x7e, 0xa2,
+ 0xbd, 0xca, 0xcf, 0x99, 0xd0, 0x03, 0xcf, 0xcc, 0xc4, 0x31, 0x90, 0x00,
+ 0x06, 0x1d, 0x93, 0xb0, 0xc2, 0xc8, 0xbe, 0x0d, 0x8e, 0x00, 0x06, 0x19,
+ 0x92, 0xaf, 0xc2, 0xc7, 0xb5, 0x06, 0x81, 0x00, 0x05, 0x17, 0x8d, 0xab,
+ 0xc2, 0xcc, 0xcf, 0xa3, 0xd0, 0x02, 0xce, 0xc8, 0x8a, 0x82, 0x00, 0x05,
+ 0x4d, 0x93, 0xb3, 0xc5, 0xcd, 0xcf, 0x91, 0xd0, 0x03, 0xcf, 0xcc, 0xbe,
+ 0x32, 0x84, 0x00, 0x16, 0x01, 0x21, 0x5a, 0x76, 0x88, 0x99, 0xa5, 0xaf,
+ 0xb6, 0xbb, 0xbd, 0xbf, 0xbe, 0xbb, 0xb7, 0xb0, 0xa5, 0x98, 0x77, 0x24,
+ 0x00, 0x04, 0x04, 0x83, 0x00, 0x05, 0x09, 0x6a, 0x9c, 0xb9, 0xc8, 0xce,
+ 0x99, 0xd0, 0x03, 0xcf, 0xcb, 0xbd, 0x07, 0x90, 0x00, 0x05, 0x42, 0x91,
+ 0xae, 0xc2, 0xc5, 0x98, 0x8f, 0x00, 0x05, 0x3f, 0x90, 0xad, 0xc1, 0xc5,
+ 0x8f, 0x82, 0x00, 0x05, 0x23, 0x85, 0xa7, 0xc0, 0xcb, 0xcf, 0xa2, 0xd0,
+ 0x03, 0xcf, 0xcd, 0xc5, 0x64, 0x82, 0x00, 0x05, 0x5d, 0x92, 0xb3, 0xc5,
+ 0xcd, 0xcf, 0x90, 0xd0, 0x03, 0xcf, 0xcd, 0xc6, 0x60, 0x84, 0x00, 0x0a,
+ 0x01, 0x37, 0x6a, 0x80, 0x95, 0xa7, 0xb4, 0xbe, 0xc3, 0xc6, 0xc9, 0x80,
+ 0xcb, 0x08, 0xca, 0xc7, 0xc4, 0xbe, 0xb3, 0xa3, 0x8c, 0x1e, 0x06, 0x84,
+ 0x00, 0x05, 0x01, 0x49, 0x95, 0xb4, 0xc6, 0xcd, 0x95, 0xd0, 0x00, 0xcf,
+ 0x80, 0xd0, 0x02, 0xce, 0xc8, 0xa0, 0x8d, 0x00, 0x09, 0x03, 0x15, 0x2b,
+ 0x4d, 0x82, 0x9b, 0xb4, 0xc3, 0xc3, 0x73, 0x8b, 0x00, 0x09, 0x03, 0x15,
+ 0x2b, 0x4d, 0x81, 0x9b, 0xb4, 0xc2, 0xc2, 0x6d, 0x82, 0x00, 0x05, 0x34,
+ 0x84, 0xa8, 0xc0, 0xcc, 0xcf, 0x89, 0xd0, 0x01, 0xcf, 0xcf, 0x94, 0xd0,
+ 0x03, 0xcf, 0xcc, 0xc2, 0x42, 0x81, 0x00, 0x05, 0x03, 0x6f, 0x95, 0xb4,
+ 0xc6, 0xcd, 0x91, 0xd0, 0x03, 0xcf, 0xcb, 0xbe, 0x1a, 0x84, 0x00, 0x0a,
+ 0x2f, 0x6d, 0x86, 0x9e, 0xb1, 0xbd, 0xc6, 0xca, 0xcc, 0xcd, 0xce, 0x80,
+ 0xcf, 0x07, 0xce, 0xce, 0xcc, 0xc8, 0xc1, 0xb2, 0x41, 0x08, 0x86, 0x00,
+ 0x05, 0x24, 0x8d, 0xae, 0xc2, 0xcc, 0xcf, 0x8a, 0xd0, 0x01, 0xcf, 0xcf,
+ 0x80, 0xce, 0x80, 0xcf, 0x00, 0xce, 0x80, 0xcd, 0x04, 0xce, 0xcf, 0xcd,
+ 0xc6, 0x7e, 0x82, 0x00, 0x04, 0x23, 0x5a, 0x66, 0x6f, 0x72, 0x83, 0x73,
+ 0x09, 0x76, 0x7a, 0x80, 0x8b, 0x9b, 0xae, 0xbf, 0xc6, 0xc2, 0x53, 0x82,
+ 0x00, 0x04, 0x35, 0x5d, 0x69, 0x70, 0x72, 0x81, 0x73, 0x09, 0x76, 0x7a,
+ 0x80, 0x8a, 0x9b, 0xae, 0xbf, 0xc6, 0xc1, 0x4c, 0x82, 0x00, 0x04, 0x46,
+ 0x88, 0xab, 0xc2, 0xcc, 0x80, 0xcf, 0x80, 0xce, 0x81, 0xcf, 0x01, 0xce,
+ 0xce, 0x81, 0xcd, 0x02, 0xce, 0xcf, 0xcf, 0x8c, 0xd0, 0x81, 0xcf, 0x03,
+ 0xcd, 0xc9, 0xbe, 0x21, 0x81, 0x00, 0x05, 0x11, 0x76, 0x9a, 0xb8, 0xc8,
+ 0xce, 0x91, 0xd0, 0x02, 0xcd, 0xc7, 0x74, 0x84, 0x00, 0x09, 0x25, 0x6c,
+ 0x86, 0xa1, 0xb4, 0xc2, 0xc9, 0xcc, 0xce, 0xcf, 0x83, 0xd0, 0x05, 0xcf,
+ 0xce, 0xcb, 0xc2, 0x42, 0x08, 0x87, 0x00, 0x05, 0x14, 0x84, 0xa7, 0xc0,
+ 0xcb, 0xcf, 0x89, 0xd0, 0x11, 0xcf, 0xcd, 0xcb, 0xc8, 0xc8, 0xc9, 0xcb,
+ 0xcc, 0xcb, 0xc8, 0xc6, 0xc5, 0xc6, 0xc9, 0xcc, 0xcb, 0xc3, 0x5c, 0x82,
+ 0x00, 0x05, 0x38, 0x6e, 0x83, 0x91, 0x97, 0x98, 0x82, 0x99, 0x09, 0x9b,
+ 0x9e, 0xa3, 0xab, 0xb4, 0xc0, 0xc7, 0xc9, 0xc0, 0x34, 0x82, 0x00, 0x05,
+ 0x4f, 0x73, 0x87, 0x93, 0x98, 0x98, 0x80, 0x99, 0x09, 0x9b, 0x9e, 0xa3,
+ 0xab, 0xb4, 0xc0, 0xc6, 0xc9, 0xc0, 0x2e, 0x82, 0x00, 0x0b, 0x5b, 0x8e,
+ 0xb0, 0xc4, 0xcc, 0xce, 0xcd, 0xcb, 0xc8, 0xc7, 0xc8, 0xcb, 0x80, 0xcc,
+ 0x09, 0xca, 0xc7, 0xc6, 0xc4, 0xc5, 0xc6, 0xc9, 0xcc, 0xcd, 0xcf, 0x88,
+ 0xd0, 0x0a, 0xcf, 0xcf, 0xce, 0xcd, 0xcc, 0xcb, 0xca, 0xc7, 0xc2, 0xb3,
+ 0x06, 0x81, 0x00, 0x05, 0x21, 0x7a, 0x9f, 0xbc, 0xca, 0xce, 0x90, 0xd0,
+ 0x03, 0xcf, 0xcc, 0xc2, 0x2e, 0x83, 0x00, 0x08, 0x11, 0x65, 0x82, 0x9e,
+ 0xb5, 0xc3, 0xcb, 0xce, 0xcf, 0x86, 0xd0, 0x03, 0xce, 0xc7, 0x3b, 0x06,
+ 0x88, 0x00, 0x05, 0x0b, 0x77, 0xa0, 0xbb, 0xc9, 0xce, 0x88, 0xd0, 0x12,
+ 0xcf, 0xcc, 0xc6, 0xa7, 0x79, 0xa9, 0xbc, 0xc0, 0xc2, 0xb4, 0x87, 0x5d,
+ 0x73, 0xa7, 0xbb, 0xc3, 0xc6, 0xc0, 0x3e, 0x82, 0x00, 0x05, 0x4e, 0x7e,
+ 0x98, 0xa9, 0xb0, 0xb2, 0x83, 0xb3, 0x08, 0xb5, 0xba, 0xbf, 0xc4, 0xc9,
+ 0xcc, 0xca, 0xbe, 0x17, 0x81, 0x00, 0x05, 0x03, 0x66, 0x84, 0x9e, 0xab,
+ 0xb1, 0x81, 0xb3, 0x09, 0xb4, 0xb5, 0xba, 0xbf, 0xc4, 0xc9, 0xcc, 0xca,
+ 0xbd, 0x11, 0x81, 0x00, 0x1b, 0x03, 0x6f, 0x94, 0xb4, 0xc6, 0xcc, 0xcc,
+ 0xc6, 0xa1, 0x71, 0x9b, 0xbb, 0xc0, 0xc4, 0xc5, 0xc2, 0xac, 0x86, 0x63,
+ 0x70, 0x8e, 0xac, 0xbb, 0xc1, 0xc6, 0xcc, 0xce, 0xcf, 0x84, 0xd0, 0x0b,
+ 0xcf, 0xcf, 0xcd, 0xcb, 0xc8, 0xc5, 0xc1, 0xbe, 0xbb, 0xab, 0x92, 0x69,
+ 0x82, 0x00, 0x05, 0x32, 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0x90, 0xd0, 0x03,
+ 0xce, 0xc8, 0x8e, 0x01, 0x83, 0x00, 0x07, 0x3b, 0x79, 0x98, 0xb2, 0xc2,
+ 0xcb, 0xce, 0xcf, 0x87, 0xd0, 0x08, 0xcd, 0xbc, 0x7a, 0x45, 0x23, 0x17,
+ 0x0d, 0x07, 0x01, 0x83, 0x00, 0x05, 0x03, 0x59, 0x9a, 0xb7, 0xc7, 0xce,
+ 0x87, 0xd0, 0x0a, 0xcf, 0xcc, 0xc6, 0x35, 0x00, 0x00, 0x03, 0x96, 0xa8,
+ 0x49, 0x01, 0x80, 0x00, 0x05, 0x03, 0x92, 0xb4, 0xbf, 0xbb, 0x1e, 0x81,
+ 0x00, 0x04, 0x01, 0x5c, 0x7c, 0x95, 0xa4, 0x83, 0xab, 0x0a, 0xac, 0xb1,
+ 0xb5, 0xbb, 0xc1, 0xc7, 0xcc, 0xcd, 0xc9, 0xb3, 0x01, 0x81, 0x00, 0x04,
+ 0x10, 0x65, 0x82, 0x9a, 0xa6, 0x81, 0xab, 0x09, 0xac, 0xb3, 0xb7, 0xbc,
+ 0xc2, 0xc8, 0xcc, 0xcd, 0xc9, 0xae, 0x82, 0x00, 0x07, 0x11, 0x76, 0x9b,
+ 0xb8, 0xc7, 0xcb, 0xc2, 0x25, 0x80, 0x00, 0x04, 0x60, 0xab, 0xb1, 0x6d,
+ 0x15, 0x82, 0x00, 0x06, 0x07, 0x53, 0xa7, 0xb8, 0xc3, 0xcb, 0xce, 0x83,
+ 0xd0, 0x09, 0xcf, 0xcd, 0xcb, 0xc6, 0xc0, 0x8d, 0x46, 0x29, 0x17, 0x04,
+ 0x85, 0x00, 0x05, 0x46, 0x87, 0xab, 0xc2, 0xcc, 0xcf, 0x8f, 0xd0, 0x03,
+ 0xcf, 0xcc, 0xc4, 0x46, 0x83, 0x00, 0x06, 0x11, 0x69, 0x8a, 0xa9, 0xbf,
+ 0xca, 0xce, 0x89, 0xd0, 0x15, 0xce, 0xc8, 0xbd, 0xab, 0x99, 0x8a, 0x7e,
+ 0x67, 0x4d, 0x2e, 0x19, 0x10, 0x09, 0x01, 0x00, 0x00, 0x32, 0x97, 0xb3,
+ 0xc6, 0xcd, 0xcf, 0x86, 0xd0, 0x02, 0xce, 0xc9, 0x89, 0x81, 0x00, 0x01,
+ 0x47, 0x22, 0x83, 0x00, 0x04, 0x47, 0xa3, 0xb4, 0xb2, 0x04, 0x8d, 0x00,
+ 0x08, 0x04, 0x25, 0x69, 0xb4, 0xc0, 0xc9, 0xcc, 0xc7, 0x92, 0x8c, 0x00,
+ 0x08, 0x0a, 0x2e, 0x82, 0xb6, 0xc2, 0xcb, 0xcc, 0xc7, 0x8d, 0x82, 0x00,
+ 0x06, 0x21, 0x7a, 0x9f, 0xbb, 0xc8, 0xc7, 0x7d, 0x81, 0x00, 0x02, 0x1b,
+ 0x6f, 0x1e, 0x86, 0x00, 0x05, 0x17, 0x98, 0xb4, 0xc2, 0xcb, 0xce, 0x80,
+ 0xd0, 0x06, 0xcf, 0xce, 0xcc, 0xc6, 0xb1, 0x64, 0x1a, 0x8a, 0x00, 0x05,
+ 0x5a, 0x8e, 0xaf, 0xc4, 0xcc, 0xcf, 0x8f, 0xd0, 0x03, 0xcf, 0xcb, 0xc0,
+ 0x1d, 0x83, 0x00, 0x06, 0x37, 0x7a, 0x9b, 0xb6, 0xc6, 0xcd, 0xcf, 0x89,
+ 0xd0, 0x15, 0xce, 0xcb, 0xc4, 0xbb, 0xb0, 0xa7, 0xa0, 0x9b, 0x95, 0x8e,
+ 0x86, 0x7f, 0x6f, 0x50, 0x2e, 0x1a, 0x27, 0x99, 0xb3, 0xc5, 0xcc, 0xcf,
+ 0x85, 0xd0, 0x03, 0xcf, 0xcd, 0xc4, 0x37, 0x89, 0x00, 0x03, 0x3a, 0x97,
+ 0xad, 0x94, 0x90, 0x00, 0x06, 0x09, 0x98, 0xb4, 0xc3, 0xca, 0xc5, 0x70,
+ 0x8e, 0x00, 0x06, 0x23, 0xa3, 0xb8, 0xc6, 0xcb, 0xc5, 0x6c, 0x82, 0x00,
+ 0x06, 0x34, 0x82, 0xa5, 0xbf, 0xc7, 0xc2, 0x2b, 0x81, 0x00, 0x01, 0x01,
+ 0x01, 0x88, 0x00, 0x0c, 0x35, 0x9f, 0xb6, 0xc6, 0xcc, 0xcf, 0xd0, 0xcf,
+ 0xce, 0xca, 0xc3, 0x60, 0x04, 0x8b, 0x00, 0x05, 0x03, 0x6f, 0x94, 0xb4,
+ 0xc6, 0xcd, 0x90, 0xd0, 0x03, 0xce, 0xc9, 0xa8, 0x03, 0x82, 0x00, 0x06,
+ 0x01, 0x5a, 0x87, 0xa9, 0xc0, 0xcb, 0xcf, 0x8a, 0xd0, 0x15, 0xcf, 0xce,
+ 0xcb, 0xc6, 0xc2, 0xbf, 0xbc, 0xb9, 0xb4, 0xaf, 0xa9, 0xa3, 0x9c, 0x96,
+ 0x8f, 0x8d, 0x94, 0xa5, 0xb9, 0xc6, 0xcd, 0xcf, 0x85, 0xd0, 0x03, 0xcf,
+ 0xcc, 0xc0, 0x13, 0x88, 0x00, 0x04, 0x04, 0x63, 0x95, 0xab, 0x74, 0x91,
+ 0x00, 0x05, 0x71, 0xa8, 0xbf, 0xc7, 0xc2, 0x4f, 0x8e, 0x00, 0x06, 0x04,
+ 0x91, 0xad, 0xc2, 0xc8, 0xc2, 0x4b, 0x82, 0x00, 0x06, 0x47, 0x88, 0xab,
+ 0xc1, 0xc6, 0xbd, 0x08, 0x8f, 0x00, 0x09, 0x71, 0xa8, 0xbf, 0xca, 0xce,
+ 0xcf, 0xce, 0xca, 0xbb, 0x3f, 0x8d, 0x00, 0x05, 0x11, 0x76, 0x9a, 0xb8,
+ 0xc8, 0xce, 0x90, 0xd0, 0x02, 0xce, 0xc7, 0x7f, 0x83, 0x00, 0x06, 0x0d,
+ 0x6f, 0x93, 0xb3, 0xc5, 0xcd, 0xcf, 0x8b, 0xd0, 0x13, 0xcf, 0xce, 0xcd,
+ 0xcc, 0xcb, 0xca, 0xc8, 0xc6, 0xc3, 0xc0, 0xbb, 0xb5, 0xaf, 0xa9, 0xa5,
+ 0xa9, 0xb4, 0xc0, 0xc9, 0xce, 0x86, 0xd0, 0x02, 0xce, 0xca, 0xb2, 0x87,
+ 0x00, 0x06, 0x07, 0x22, 0x57, 0x85, 0x9e, 0xae, 0x56, 0x90, 0x00, 0x06,
+ 0x09, 0x80, 0xa4, 0xbc, 0xc6, 0xc0, 0x31, 0x8e, 0x00, 0x06, 0x1e, 0x8a,
+ 0xab, 0xc0, 0xc6, 0xc0, 0x2d, 0x82, 0x00, 0x05, 0x5d, 0x8e, 0xaf, 0xc2,
+ 0xc6, 0xa2, 0x85, 0x00, 0x04, 0x12, 0x25, 0x35, 0x2e, 0x0d, 0x83, 0x00,
+ 0x08, 0x48, 0x9a, 0xb6, 0xc6, 0xcd, 0xce, 0xca, 0xb2, 0x24, 0x87, 0x00,
+ 0x01, 0x0a, 0x17, 0x82, 0x00, 0x05, 0x21, 0x7a, 0x9f, 0xbc, 0xca, 0xcf,
+ 0x8f, 0xd0, 0x03, 0xcf, 0xcd, 0xc5, 0x73, 0x83, 0x00, 0x05, 0x1d, 0x76,
+ 0x9b, 0xb9, 0xc8, 0xce, 0x8e, 0xd0, 0x81, 0xcf, 0x0d, 0xce, 0xcd, 0xcc,
+ 0xc8, 0xc3, 0xb7, 0x7a, 0x76, 0xab, 0xb0, 0xb9, 0xc3, 0xcb, 0xce, 0x86,
+ 0xd0, 0x02, 0xce, 0xc7, 0x8f, 0x83, 0x00, 0x0a, 0x14, 0x3c, 0x5c, 0x6c,
+ 0x74, 0x7e, 0x8a, 0x9e, 0xae, 0xb4, 0x39, 0x8e, 0x00, 0x08, 0x0d, 0x24,
+ 0x5a, 0x8d, 0xa9, 0xbf, 0xc5, 0xbd, 0x14, 0x8b, 0x00, 0x09, 0x01, 0x12,
+ 0x2a, 0x6c, 0x93, 0xaf, 0xc2, 0xc6, 0xbc, 0x11, 0x81, 0x00, 0x06, 0x03,
+ 0x6f, 0x95, 0xb4, 0xc4, 0xc4, 0x81, 0x83, 0x00, 0x07, 0x07, 0x3c, 0x69,
+ 0x76, 0x7e, 0x80, 0x76, 0x19, 0x82, 0x00, 0x07, 0x2d, 0x8e, 0xaf, 0xc3,
+ 0xcc, 0xcb, 0xc2, 0x32, 0x84, 0x00, 0x05, 0x0a, 0x34, 0x4c, 0x63, 0x6d,
+ 0x5b, 0x82, 0x00, 0x05, 0x32, 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0x8f, 0xd0,
+ 0x03, 0xcf, 0xcd, 0xc4, 0x6d, 0x83, 0x00, 0x05, 0x2b, 0x7e, 0xa1, 0xbd,
+ 0xca, 0xcf, 0x93, 0xd0, 0x0d, 0xcf, 0xcc, 0xc6, 0x5a, 0x1d, 0x03, 0x04,
+ 0x1e, 0x64, 0xaf, 0xbe, 0xc8, 0xcd, 0xcf, 0x85, 0xd0, 0x02, 0xcd, 0xc6,
+ 0x6f, 0x82, 0x00, 0x0b, 0x12, 0x5b, 0x72, 0x84, 0x91, 0x99, 0xa1, 0xab,
+ 0xb4, 0xbc, 0xb8, 0x1d, 0x81, 0x00, 0x04, 0x01, 0x44, 0x4f, 0x57, 0x5b,
+ 0x83, 0x5d, 0x0a, 0x5f, 0x69, 0x76, 0x7f, 0x8d, 0xa1, 0xb5, 0xc3, 0xc6,
+ 0xb0, 0x01, 0x81, 0x00, 0x04, 0x0e, 0x47, 0x50, 0x59, 0x5c, 0x81, 0x5d,
+ 0x09, 0x5f, 0x6e, 0x77, 0x82, 0x91, 0xa6, 0xba, 0xc6, 0xc6, 0xad, 0x82,
+ 0x00, 0x06, 0x12, 0x76, 0x9b, 0xb8, 0xc6, 0xc2, 0x60, 0x82, 0x00, 0x08,
+ 0x03, 0x4a, 0x70, 0x86, 0x97, 0xa0, 0xa2, 0x9b, 0x5f, 0x82, 0x00, 0x06,
+ 0x22, 0x88, 0xab, 0xc1, 0xc9, 0xc5, 0x5f, 0x83, 0x00, 0x07, 0x04, 0x30,
+ 0x64, 0x76, 0x83, 0x8c, 0x8e, 0x5d, 0x82, 0x00, 0x05, 0x46, 0x88, 0xab,
+ 0xc2, 0xcc, 0xcf, 0x8f, 0xd0, 0x03, 0xcf, 0xcc, 0xc3, 0x66, 0x83, 0x00,
+ 0x05, 0x2d, 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0x93, 0xd0, 0x03, 0xce, 0xc9,
+ 0x8d, 0x0a, 0x81, 0x00, 0x05, 0x11, 0x88, 0xb0, 0xc2, 0xcb, 0xcf, 0x84,
+ 0xd0, 0x03, 0xcf, 0xcc, 0xc3, 0x4f, 0x82, 0x00, 0x0b, 0x3b, 0x73, 0x8e,
+ 0xa3, 0xb0, 0xb7, 0xbc, 0xc1, 0xc5, 0xc4, 0xb5, 0x04, 0x81, 0x00, 0x05,
+ 0x0d, 0x60, 0x77, 0x89, 0x91, 0x93, 0x82, 0x94, 0x09, 0x95, 0x97, 0x9b,
+ 0xa1, 0xab, 0xb7, 0xc2, 0xc8, 0xc6, 0x8f, 0x82, 0x00, 0x05, 0x1e, 0x66,
+ 0x7c, 0x8a, 0x91, 0x93, 0x80, 0x94, 0x09, 0x95, 0x98, 0x9c, 0xa4, 0xad,
+ 0xba, 0xc4, 0xca, 0xc6, 0x8b, 0x82, 0x00, 0x06, 0x22, 0x7c, 0xa0, 0xbb,
+ 0xc6, 0xc1, 0x40, 0x82, 0x00, 0x08, 0x30, 0x6e, 0x8a, 0xa2, 0xb3, 0xbb,
+ 0xbb, 0xb3, 0x86, 0x82, 0x00, 0x06, 0x29, 0x85, 0xa8, 0xbf, 0xc5, 0x92,
+ 0x01, 0x82, 0x00, 0x08, 0x15, 0x57, 0x72, 0x86, 0x98, 0xa5, 0xab, 0xab,
+ 0x53, 0x82, 0x00, 0x05, 0x5b, 0x8e, 0xaf, 0xc4, 0xcc, 0xcf, 0x8f, 0xd0,
+ 0x03, 0xcf, 0xcc, 0xc2, 0x69, 0x83, 0x00, 0x05, 0x27, 0x82, 0xa6, 0xc0,
+ 0xcc, 0xcf, 0x92, 0xd0, 0x03, 0xcf, 0xcd, 0xc5, 0x2b, 0x83, 0x00, 0x04,
+ 0x44, 0xa0, 0xba, 0xc8, 0xce, 0x84, 0xd0, 0x03, 0xcf, 0xcc, 0xc0, 0x31,
+ 0x82, 0x00, 0x0a, 0x5d, 0x86, 0xa4, 0xb9, 0xc3, 0xc7, 0xca, 0xcc, 0xcc,
+ 0xc6, 0x9a, 0x82, 0x00, 0x04, 0x1b, 0x71, 0x8f, 0xa5, 0xb0, 0x84, 0xb4,
+ 0x08, 0xb6, 0xb9, 0xbc, 0xc1, 0xc6, 0xcb, 0xcc, 0xc5, 0x6e, 0x82, 0x00,
+ 0x04, 0x32, 0x77, 0x95, 0xa8, 0xb1, 0x81, 0xb4, 0x09, 0xb5, 0xb6, 0xba,
+ 0xbe, 0xc2, 0xc7, 0xcb, 0xcc, 0xc5, 0x6a, 0x82, 0x00, 0x06, 0x35, 0x82,
+ 0xa5, 0xbf, 0xc6, 0xbf, 0x22, 0x81, 0x00, 0x09, 0x03, 0x5f, 0x82, 0xa0,
+ 0xb7, 0xc3, 0xc8, 0xc7, 0xc0, 0x86, 0x82, 0x00, 0x05, 0x2f, 0x85, 0xa8,
+ 0xbd, 0xc0, 0x35, 0x82, 0x00, 0x09, 0x08, 0x59, 0x77, 0x90, 0xa4, 0xb4,
+ 0xbd, 0xc0, 0xb9, 0x3c, 0x81, 0x00, 0x05, 0x03, 0x6f, 0x94, 0xb4, 0xc6,
+ 0xcd, 0x90, 0xd0, 0x03, 0xcf, 0xcc, 0xc3, 0x70, 0x83, 0x00, 0x05, 0x20,
+ 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0x92, 0xd0, 0x03, 0xcf, 0xcc, 0xc0, 0x15,
+ 0x83, 0x00, 0x04, 0x3f, 0x96, 0xb4, 0xc6, 0xcd, 0x84, 0xd0, 0x03, 0xcf,
+ 0xcb, 0xbe, 0x15, 0x81, 0x00, 0x0b, 0x11, 0x70, 0x94, 0xb2, 0xc3, 0xcc,
+ 0xce, 0xcf, 0xcf, 0xcc, 0xc6, 0x79, 0x82, 0x00, 0x04, 0x2e, 0x7e, 0x9e,
+ 0xb7, 0xc2, 0x84, 0xc6, 0x08, 0xc7, 0xc8, 0xca, 0xcc, 0xcd, 0xce, 0xcc,
+ 0xc2, 0x4d, 0x82, 0x00, 0x04, 0x48, 0x86, 0xa5, 0xbb, 0xc3, 0x82, 0xc6,
+ 0x08, 0xc7, 0xc9, 0xca, 0xcc, 0xcd, 0xce, 0xcc, 0xc2, 0x4a, 0x82, 0x00,
+ 0x06, 0x48, 0x89, 0xab, 0xc1, 0xc6, 0xbb, 0x07, 0x81, 0x00, 0x09, 0x1a,
+ 0x71, 0x93, 0xb1, 0xc2, 0xcb, 0xcd, 0xcc, 0xc3, 0x77, 0x82, 0x00, 0x05,
+ 0x3f, 0x88, 0xa9, 0xbb, 0xa2, 0x01, 0x81, 0x00, 0x0a, 0x01, 0x46, 0x76,
+ 0x92, 0xab, 0xbb, 0xc4, 0xc9, 0xc7, 0xbd, 0x21, 0x81, 0x00, 0x05, 0x11,
+ 0x76, 0x9b, 0xb8, 0xc8, 0xce, 0x90, 0xd0, 0x03, 0xcf, 0xcc, 0xc4, 0x79,
+ 0x83, 0x00, 0x05, 0x18, 0x7e, 0xa2, 0xbd, 0xcb, 0xcf, 0x92, 0xd0, 0x03,
+ 0xce, 0xc9, 0xb8, 0x0d, 0x83, 0x00, 0x04, 0x63, 0x93, 0xb3, 0xc6, 0xcd,
+ 0x84, 0xd0, 0x03, 0xce, 0xc9, 0xb3, 0x01, 0x81, 0x00, 0x0b, 0x29, 0x7a,
+ 0x9e, 0xba, 0xc8, 0xce, 0xd0, 0xd0, 0xcf, 0xcc, 0xc3, 0x57, 0x82, 0x00,
+ 0x04, 0x41, 0x86, 0xa8, 0xc0, 0xca, 0x83, 0xcd, 0x80, 0xce, 0x81, 0xcf,
+ 0x02, 0xcc, 0xc0, 0x2e, 0x82, 0x00, 0x04, 0x5f, 0x8e, 0xaf, 0xc2, 0xcb,
+ 0x81, 0xcd, 0x80, 0xce, 0x06, 0xcf, 0xcf, 0xd0, 0xcf, 0xcc, 0xc0, 0x2b,
+ 0x82, 0x00, 0x05, 0x5f, 0x8f, 0xb0, 0xc2, 0xc6, 0xa1, 0x82, 0x00, 0x09,
+ 0x37, 0x7e, 0xa0, 0xbb, 0xc8, 0xce, 0xcf, 0xcc, 0xc3, 0x5d, 0x82, 0x00,
+ 0x04, 0x52, 0x8c, 0xab, 0xba, 0x52, 0x82, 0x00, 0x0a, 0x22, 0x6d, 0x8b,
+ 0xa8, 0xbc, 0xc7, 0xcc, 0xcd, 0xc9, 0xbb, 0x07, 0x81, 0x00, 0x05, 0x21,
+ 0x7a, 0xa0, 0xbc, 0xca, 0xcf, 0x90, 0xd0, 0x04, 0xcf, 0xcd, 0xc5, 0x9b,
+ 0x01, 0x82, 0x00, 0x05, 0x04, 0x6f, 0x9e, 0xba, 0xc9, 0xce, 0x92, 0xd0,
+ 0x02, 0xcd, 0xc7, 0x8b, 0x83, 0x00, 0x05, 0x0a, 0x71, 0x96, 0xb4, 0xc6,
+ 0xce, 0x84, 0xd0, 0x02, 0xce, 0xc7, 0x93, 0x82, 0x00, 0x0b, 0x42, 0x84,
+ 0xa7, 0xc0, 0xcb, 0xcf, 0xd0, 0xd0, 0xcf, 0xcc, 0xc1, 0x38, 0x82, 0x00,
+ 0x05, 0x56, 0x8d, 0xae, 0xc3, 0xcc, 0xcf, 0x88, 0xd0, 0x03, 0xcf, 0xcb,
+ 0xbe, 0x11, 0x81, 0x00, 0x06, 0x04, 0x70, 0x95, 0xb4, 0xc6, 0xcd, 0xcf,
+ 0x86, 0xd0, 0x03, 0xcf, 0xcb, 0xbd, 0x10, 0x81, 0x00, 0x06, 0x04, 0x70,
+ 0x95, 0xb4, 0xc4, 0xc4, 0x7f, 0x82, 0x00, 0x09, 0x4d, 0x87, 0xa9, 0xc1,
+ 0xcc, 0xcf, 0xcf, 0xcc, 0xc2, 0x40, 0x82, 0x00, 0x04, 0x67, 0x91, 0xae,
+ 0xb7, 0x21, 0x82, 0x00, 0x09, 0x3f, 0x7c, 0x9e, 0xb7, 0xc6, 0xcc, 0xcf,
+ 0xce, 0xc8, 0xa1, 0x82, 0x00, 0x05, 0x32, 0x82, 0xa5, 0xbf, 0xcb, 0xcf,
+ 0x91, 0xd0, 0x03, 0xce, 0xc6, 0xb5, 0x17, 0x83, 0x00, 0x05, 0x44, 0x94,
+ 0xb3, 0xc6, 0xcd, 0xcf, 0x90, 0xd0, 0x03, 0xcf, 0xcc, 0xc3, 0x53, 0x83,
+ 0x00, 0x05, 0x17, 0x76, 0x9b, 0xb9, 0xc8, 0xce, 0x84, 0xd0, 0x02, 0xcd,
+ 0xc6, 0x71, 0x82, 0x00, 0x0b, 0x59, 0x8c, 0xae, 0xc3, 0xcc, 0xcf, 0xd0,
+ 0xd0, 0xcf, 0xcb, 0xbf, 0x1a, 0x81, 0x00, 0x05, 0x01, 0x6a, 0x93, 0xb3,
+ 0xc6, 0xcd, 0x89, 0xd0, 0x02, 0xce, 0xc9, 0xaf, 0x82, 0x00, 0x05, 0x14,
+ 0x76, 0x9b, 0xb9, 0xc8, 0xce, 0x87, 0xd0, 0x02, 0xce, 0xc9, 0xac, 0x82,
+ 0x00, 0x06, 0x13, 0x76, 0x9b, 0xb8, 0xc6, 0xc2, 0x5f, 0x82, 0x00, 0x09,
+ 0x63, 0x8f, 0xb1, 0xc4, 0xcd, 0xcf, 0xcf, 0xcb, 0xc0, 0x24, 0x81, 0x00,
+ 0x05, 0x0a, 0x72, 0x97, 0xb2, 0xb5, 0x0a, 0x82, 0x00, 0x09, 0x5b, 0x89,
+ 0xab, 0xc0, 0xcb, 0xcf, 0xcf, 0xce, 0xc6, 0x80, 0x82, 0x00, 0x05, 0x47,
+ 0x88, 0xab, 0xc2, 0xcc, 0xcf, 0x91, 0xd0, 0x03, 0xce, 0xc9, 0xbb, 0x3a,
+ 0x83, 0x00, 0x05, 0x1e, 0x89, 0xab, 0xc0, 0xcb, 0xcf, 0x90, 0xd0, 0x03,
+ 0xce, 0xca, 0xb7, 0x14, 0x83, 0x00, 0x05, 0x25, 0x7e, 0xa2, 0xbd, 0xcb,
+ 0xcf, 0x83, 0xd0, 0x03, 0xcf, 0xcc, 0xc3, 0x52, 0x81, 0x00, 0x05, 0x03,
+ 0x6d, 0x93, 0xb4, 0xc6, 0xcd, 0x80, 0xd0, 0x03, 0xce, 0xca, 0xb7, 0x03,
+ 0x81, 0x00, 0x05, 0x0d, 0x73, 0x99, 0xb7, 0xc8, 0xce, 0x89, 0xd0, 0x02,
+ 0xce, 0xc7, 0x8c, 0x82, 0x00, 0x05, 0x24, 0x7c, 0xa1, 0xbc, 0xca, 0xcf,
+ 0x87, 0xd0, 0x02, 0xce, 0xc7, 0x8a, 0x82, 0x00, 0x06, 0x24, 0x7c, 0xa0,
+ 0xbb, 0xc6, 0xc1, 0x3f, 0x81, 0x00, 0x0a, 0x07, 0x71, 0x97, 0xb5, 0xc7,
+ 0xce, 0xd0, 0xcf, 0xca, 0xbc, 0x09, 0x81, 0x00, 0x04, 0x19, 0x79, 0x9c,
+ 0xb4, 0xa5, 0x82, 0x00, 0x0a, 0x08, 0x6d, 0x92, 0xb2, 0xc5, 0xcd, 0xcf,
+ 0xcf, 0xcd, 0xc4, 0x5f, 0x82, 0x00, 0x05, 0x5c, 0x8e, 0xb0, 0xc4, 0xcc,
+ 0xcf, 0x91, 0xd0, 0x03, 0xcf, 0xcb, 0xc0, 0x6e, 0x83, 0x00, 0x06, 0x01,
+ 0x58, 0x9e, 0xb8, 0xc6, 0xcd, 0xcf, 0x8e, 0xd0, 0x03, 0xcf, 0xcc, 0xc5,
+ 0x69, 0x84, 0x00, 0x05, 0x42, 0x86, 0xa9, 0xc1, 0xcc, 0xcf, 0x83, 0xd0,
+ 0x03, 0xcf, 0xcc, 0xc1, 0x34, 0x81, 0x00, 0x05, 0x11, 0x76, 0x9a, 0xb8,
+ 0xc8, 0xce, 0x80, 0xd0, 0x02, 0xce, 0xc8, 0x98, 0x82, 0x00, 0x05, 0x1d,
+ 0x7a, 0x9e, 0xbb, 0xc8, 0xcd, 0x86, 0xcf, 0x80, 0xd0, 0x02, 0xcd, 0xc5,
+ 0x6a, 0x82, 0x00, 0x05, 0x37, 0x82, 0xa6, 0xc0, 0xcc, 0xcf, 0x86, 0xd0,
+ 0x03, 0xcf, 0xcd, 0xc5, 0x69, 0x82, 0x00, 0x06, 0x35, 0x82, 0xa6, 0xbf,
+ 0xc6, 0xbf, 0x21, 0x81, 0x00, 0x09, 0x18, 0x77, 0x9c, 0xba, 0xc9, 0xce,
+ 0xd0, 0xce, 0xc8, 0xa5, 0x82, 0x00, 0x04, 0x2a, 0x7e, 0xa1, 0xb6, 0x95,
+ 0x82, 0x00, 0x0a, 0x06, 0x70, 0x95, 0xb4, 0xc6, 0xcd, 0xcf, 0xce, 0xcc,
+ 0xc1, 0x40, 0x81, 0x00, 0x05, 0x03, 0x6f, 0x95, 0xb4, 0xc6, 0xcd, 0x92,
+ 0xd0, 0x04, 0xcf, 0xcc, 0xc3, 0xab, 0x10, 0x83, 0x00, 0x05, 0x17, 0x8b,
+ 0xab, 0xc0, 0xca, 0xce, 0x8e, 0xd0, 0x03, 0xce, 0xc9, 0xa9, 0x12, 0x83,
+ 0x00, 0x06, 0x0b, 0x6d, 0x91, 0xb1, 0xc4, 0xcd, 0xcf, 0x83, 0xd0, 0x03,
+ 0xcf, 0xcb, 0xbe, 0x18, 0x81, 0x00, 0x05, 0x21, 0x7a, 0x9f, 0xbc, 0xca,
+ 0xce, 0x80, 0xd0, 0x02, 0xcd, 0xc6, 0x76, 0x82, 0x00, 0x05, 0x2d, 0x7d,
+ 0x9f, 0xba, 0xc6, 0xca, 0x83, 0xcb, 0x08, 0xcc, 0xcc, 0xcd, 0xce, 0xcf,
+ 0xcf, 0xcc, 0xc2, 0x4a, 0x82, 0x00, 0x05, 0x4a, 0x89, 0xab, 0xc2, 0xcc,
+ 0xcf, 0x86, 0xd0, 0x03, 0xcf, 0xcc, 0xc2, 0x49, 0x82, 0x00, 0x06, 0x4a,
+ 0x89, 0xab, 0xc1, 0xc6, 0xbb, 0x07, 0x81, 0x00, 0x09, 0x28, 0x7e, 0xa2,
+ 0xbd, 0xcb, 0xcf, 0xd0, 0xce, 0xc6, 0x84, 0x82, 0x00, 0x05, 0x3e, 0x85,
+ 0xa7, 0xb9, 0xb1, 0x04, 0x82, 0x00, 0x09, 0x5c, 0x91, 0xb0, 0xc2, 0xc9,
+ 0xcc, 0xcc, 0xc7, 0xbc, 0x23, 0x81, 0x00, 0x05, 0x11, 0x76, 0x9b, 0xb8,
+ 0xc8, 0xce, 0x93, 0xd0, 0x03, 0xcd, 0xc7, 0xb8, 0x42, 0x84, 0x00, 0x05,
+ 0x3c, 0x99, 0xb3, 0xc3, 0xcb, 0xce, 0x8b, 0xd0, 0x04, 0xcf, 0xce, 0xcb,
+ 0xc2, 0x3f, 0x84, 0x00, 0x05, 0x2a, 0x7a, 0x9c, 0xb9, 0xc8, 0xce, 0x84,
+ 0xd0, 0x03, 0xce, 0xc9, 0xb4, 0x01, 0x81, 0x00, 0x0b, 0x32, 0x82, 0xa5,
+ 0xbf, 0xcb, 0xcf, 0xd0, 0xd0, 0xcf, 0xcc, 0xc3, 0x55, 0x82, 0x00, 0x05,
+ 0x3c, 0x7c, 0x9b, 0xb1, 0xbb, 0xbe, 0x82, 0xbf, 0x09, 0xc0, 0xc0, 0xc2,
+ 0xc6, 0xca, 0xcd, 0xce, 0xcc, 0xc0, 0x2b, 0x82, 0x00, 0x05, 0x60, 0x8f,
+ 0xb1, 0xc4, 0xcd, 0xcf, 0x86, 0xd0, 0x03, 0xcf, 0xcc, 0xc0, 0x2a, 0x82,
+ 0x00, 0x05, 0x60, 0x8f, 0xb0, 0xc3, 0xc6, 0xa0, 0x82, 0x00, 0x09, 0x3b,
+ 0x84, 0xa8, 0xc0, 0xcc, 0xcf, 0xcf, 0xcd, 0xc5, 0x64, 0x82, 0x00, 0x05,
+ 0x52, 0x8b, 0xab, 0xbc, 0xb6, 0x24, 0x82, 0x00, 0x09, 0x10, 0x76, 0xa0,
+ 0xb4, 0xbd, 0xc1, 0xc2, 0xbe, 0xb3, 0x08, 0x81, 0x00, 0x05, 0x21, 0x7a,
+ 0xa0, 0xbc, 0xca, 0xcf, 0x93, 0xd0, 0x04, 0xcf, 0xcb, 0xc0, 0x97, 0x0a,
+ 0x83, 0x00, 0x07, 0x01, 0x4f, 0xa0, 0xb6, 0xc4, 0xcb, 0xce, 0xcf, 0x88,
+ 0xd0, 0x05, 0xcf, 0xce, 0xcb, 0xc2, 0x5d, 0x01, 0x83, 0x00, 0x06, 0x07,
+ 0x5d, 0x89, 0xa9, 0xc0, 0xcb, 0xcf, 0x84, 0xd0, 0x02, 0xce, 0xc7, 0x96,
+ 0x82, 0x00, 0x0b, 0x47, 0x88, 0xab, 0xc2, 0xcc, 0xcf, 0xd0, 0xd0, 0xcf,
+ 0xcc, 0xc1, 0x37, 0x82, 0x00, 0x04, 0x17, 0x28, 0x2f, 0x35, 0x37, 0x83,
+ 0x38, 0x09, 0x39, 0x52, 0x81, 0xb3, 0xc0, 0xc7, 0xcc, 0xca, 0xbd, 0x0e,
+ 0x81, 0x00, 0x05, 0x04, 0x71, 0x96, 0xb5, 0xc6, 0xce, 0x87, 0xd0, 0x03,
+ 0xcf, 0xcb, 0xbd, 0x0e, 0x81, 0x00, 0x06, 0x04, 0x71, 0x96, 0xb4, 0xc5,
+ 0xc4, 0x7e, 0x82, 0x00, 0x09, 0x4f, 0x8a, 0xac, 0xc2, 0xcc, 0xcf, 0xcf,
+ 0xcc, 0xc2, 0x46, 0x82, 0x00, 0x05, 0x69, 0x92, 0xb1, 0xc0, 0xbb, 0x48,
+ 0x83, 0x00, 0x07, 0x01, 0x25, 0x4d, 0x5f, 0x6d, 0x6d, 0x66, 0x53, 0x82,
+ 0x00, 0x05, 0x34, 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0x93, 0xd0, 0x04, 0xcf,
+ 0xcd, 0xc5, 0xb4, 0x4d, 0x84, 0x00, 0x08, 0x04, 0x59, 0xa2, 0xb6, 0xc2,
+ 0xca, 0xcd, 0xcf, 0xcf, 0x84, 0xd0, 0x06, 0xcf, 0xce, 0xcd, 0xc9, 0xc2,
+ 0x60, 0x01, 0x84, 0x00, 0x06, 0x31, 0x77, 0x99, 0xb4, 0xc6, 0xcd, 0xcf,
+ 0x84, 0xd0, 0x02, 0xcd, 0xc6, 0x76, 0x82, 0x00, 0x0b, 0x5d, 0x8e, 0xb0,
+ 0xc4, 0xcc, 0xcf, 0xd0, 0xd0, 0xcf, 0xcb, 0xbf, 0x19, 0x90, 0x00, 0x05,
+ 0x59, 0xae, 0xbf, 0xc8, 0xc7, 0xab, 0x82, 0x00, 0x05, 0x15, 0x76, 0x9c,
+ 0xba, 0xc8, 0xce, 0x87, 0xd0, 0x02, 0xce, 0xc9, 0xab, 0x82, 0x00, 0x06,
+ 0x15, 0x76, 0x9c, 0xb9, 0xc6, 0xc3, 0x5d, 0x82, 0x00, 0x09, 0x66, 0x91,
+ 0xb2, 0xc5, 0xcd, 0xcf, 0xcf, 0xcc, 0xc0, 0x29, 0x81, 0x00, 0x06, 0x0a,
+ 0x73, 0x98, 0xb5, 0xc3, 0xc0, 0x7c, 0x90, 0x00, 0x05, 0x48, 0x88, 0xab,
+ 0xc2, 0xcc, 0xcf, 0x94, 0xd0, 0x04, 0xce, 0xca, 0xbf, 0x9f, 0x19, 0x84,
+ 0x00, 0x08, 0x01, 0x3e, 0x9c, 0xb3, 0xbf, 0xc6, 0xcb, 0xcd, 0xce, 0x82,
+ 0xcf, 0x06, 0xce, 0xcc, 0xca, 0xc6, 0xb1, 0x42, 0x01, 0x84, 0x00, 0x06,
+ 0x10, 0x67, 0x8a, 0xa9, 0xbf, 0xca, 0xce, 0x84, 0xd0, 0x03, 0xcf, 0xcc,
+ 0xc4, 0x56, 0x81, 0x00, 0x05, 0x04, 0x71, 0x96, 0xb5, 0xc6, 0xcd, 0x80,
+ 0xd0, 0x03, 0xcf, 0xca, 0xbd, 0x07, 0x90, 0x00, 0x05, 0x18, 0x9b, 0xb4,
+ 0xc3, 0xc5, 0x8c, 0x82, 0x00, 0x05, 0x28, 0x7f, 0xa3, 0xbe, 0xca, 0xcf,
+ 0x87, 0xd0, 0x02, 0xce, 0xc8, 0x8c, 0x82, 0x00, 0x06, 0x29, 0x7f, 0xa3,
+ 0xbd, 0xc6, 0xc2, 0x3f, 0x81, 0x00, 0x0a, 0x09, 0x73, 0x98, 0xb7, 0xc7,
+ 0xce, 0xd0, 0xcf, 0xcb, 0xbe, 0x0e, 0x81, 0x00, 0x07, 0x1a, 0x7a, 0x9e,
+ 0xbb, 0xc6, 0xc3, 0xb3, 0x2f, 0x8f, 0x00, 0x05, 0x5d, 0x8f, 0xb1, 0xc4,
+ 0xcd, 0xcf, 0x94, 0xd0, 0x05, 0xcf, 0xcc, 0xc6, 0xb6, 0x83, 0x0e, 0x85,
+ 0x00, 0x07, 0x1e, 0x66, 0xa9, 0xb6, 0xc0, 0xc5, 0xc8, 0xca, 0x80, 0xcb,
+ 0x05, 0xca, 0xc7, 0xc4, 0xbe, 0x77, 0x19, 0x85, 0x00, 0x07, 0x04, 0x4e,
+ 0x7e, 0x9e, 0xb6, 0xc6, 0xcd, 0xcf, 0x84, 0xd0, 0x03, 0xcf, 0xcc, 0xc3,
+ 0x48, 0x81, 0x00, 0x05, 0x25, 0x7a, 0x9e, 0xbb, 0xc9, 0xce, 0x80, 0xd0,
+ 0x03, 0xcf, 0xca, 0xbd, 0x0e, 0x90, 0x00, 0x05, 0x21, 0x8f, 0xad, 0xc1,
+ 0xc3, 0x85, 0x82, 0x00, 0x05, 0x54, 0x89, 0xab, 0xc1, 0xcc, 0xcf, 0x87,
+ 0xd0, 0x02, 0xce, 0xc7, 0x82, 0x82, 0x00, 0x06, 0x55, 0x89, 0xab, 0xc1,
+ 0xc7, 0xc1, 0x37, 0x81, 0x00, 0x0a, 0x2b, 0x7e, 0xa0, 0xbc, 0xca, 0xcf,
+ 0xd0, 0xcf, 0xcb, 0xbd, 0x08, 0x81, 0x00, 0x08, 0x3f, 0x84, 0xa7, 0xbf,
+ 0xc9, 0xc8, 0xbd, 0x99, 0x1d, 0x8d, 0x00, 0x05, 0x0e, 0x74, 0x98, 0xb6,
+ 0xc6, 0xce, 0x96, 0xd0, 0x05, 0xce, 0xcb, 0xc2, 0xb0, 0x73, 0x08, 0x86,
+ 0x00, 0x0c, 0x1a, 0x57, 0x99, 0xb3, 0xb8, 0xbc, 0xbe, 0xbf, 0xbe, 0xbc,
+ 0x97, 0x63, 0x1d, 0x87, 0x00, 0x06, 0x37, 0x76, 0x93, 0xae, 0xc1, 0xcb,
+ 0xcf, 0x85, 0xd0, 0x03, 0xcf, 0xcc, 0xc3, 0x7c, 0x81, 0x00, 0x05, 0x58,
+ 0x89, 0xa9, 0xc0, 0xcb, 0xcf, 0x80, 0xd0, 0x03, 0xcf, 0xcb, 0xbf, 0x48,
+ 0x8f, 0x00, 0x07, 0x03, 0x5b, 0x91, 0xae, 0xc1, 0xc4, 0xb4, 0x0a, 0x80,
+ 0x00, 0x05, 0x15, 0x76, 0x96, 0xb3, 0xc5, 0xcd, 0x88, 0xd0, 0x03, 0xce,
+ 0xc7, 0xb0, 0x07, 0x80, 0x00, 0x07, 0x17, 0x76, 0x96, 0xb3, 0xc5, 0xc9,
+ 0xc2, 0x6d, 0x80, 0x00, 0x0b, 0x01, 0x5f, 0x8b, 0xab, 0xc1, 0xcc, 0xcf,
+ 0xd0, 0xcf, 0xcb, 0xbf, 0x3f, 0x80, 0x00, 0x0b, 0x09, 0x70, 0x92, 0xb0,
+ 0xc3, 0xcc, 0xcc, 0xc5, 0xb4, 0x98, 0x3f, 0x0d, 0x8b, 0x00, 0x05, 0x40,
+ 0x83, 0xa4, 0xbd, 0xca, 0xcf, 0x97, 0xd0, 0x05, 0xce, 0xc9, 0xbe, 0xab,
+ 0x63, 0x04, 0x87, 0x00, 0x07, 0x03, 0x13, 0x28, 0x3f, 0x44, 0x3e, 0x35,
+ 0x18, 0x89, 0x00, 0x06, 0x29, 0x70, 0x8c, 0xa8, 0xbd, 0xc8, 0xcd, 0x86,
+ 0xd0, 0x0d, 0xcf, 0xcd, 0xc6, 0xb3, 0x4a, 0x11, 0x1e, 0x4c, 0x81, 0x9b,
+ 0xb4, 0xc6, 0xcd, 0xcf, 0x80, 0xd0, 0x07, 0xcf, 0xcc, 0xc3, 0xaf, 0x63,
+ 0x3c, 0x21, 0x11, 0x89, 0x0e, 0x12, 0x17, 0x29, 0x5f, 0x83, 0x9e, 0xb6,
+ 0xc5, 0xc7, 0xbd, 0x76, 0x2b, 0x0d, 0x1e, 0x62, 0x8a, 0xa6, 0xbd, 0xc9,
+ 0xce, 0x88, 0xd0, 0x32, 0xce, 0xc9, 0xbd, 0x6e, 0x24, 0x0d, 0x21, 0x63,
+ 0x8a, 0xa6, 0xbd, 0xc9, 0xcc, 0xc5, 0xab, 0x46, 0x0e, 0x21, 0x4f, 0x82,
+ 0x9e, 0xb6, 0xc6, 0xcd, 0xd0, 0xd0, 0xcf, 0xcc, 0xc2, 0x9a, 0x3f, 0x13,
+ 0x2b, 0x5c, 0x87, 0xa3, 0xbb, 0xc8, 0xcd, 0xce, 0xcb, 0xc2, 0xb4, 0xa0,
+ 0x8c, 0x60, 0x35, 0x28, 0x1e, 0x19, 0x13, 0x83, 0x0e, 0x07, 0x1d, 0x44,
+ 0x7a, 0x96, 0xb1, 0xc3, 0xcc, 0xcf, 0x97, 0xd0, 0x06, 0xcf, 0xcd, 0xc7,
+ 0xbb, 0xa8, 0x55, 0x01, 0x99, 0x00, 0x07, 0x2a, 0x6d, 0x88, 0xa3, 0xb9,
+ 0xc6, 0xcc, 0xcf, 0x87, 0xd0, 0x0b, 0xce, 0xca, 0xbf, 0xac, 0x99, 0x8d,
+ 0x8e, 0x9b, 0xaf, 0xc0, 0xca, 0xce, 0x82, 0xd0, 0x07, 0xce, 0xc8, 0xbd,
+ 0xab, 0x9a, 0x8b, 0x82, 0x7e, 0x88, 0x7a, 0x12, 0x7d, 0x82, 0x8e, 0x9e,
+ 0xb2, 0xc1, 0xca, 0xcb, 0xc3, 0xb4, 0x9f, 0x8e, 0x89, 0x90, 0xa2, 0xb6,
+ 0xc5, 0xcc, 0xcf, 0x88, 0xd0, 0x17, 0xcf, 0xcc, 0xc3, 0xb3, 0x9e, 0x8e,
+ 0x88, 0x90, 0xa2, 0xb6, 0xc5, 0xcc, 0xcd, 0xc9, 0xbe, 0xab, 0x98, 0x8c,
+ 0x8e, 0x9e, 0xb1, 0xc1, 0xcb, 0xce, 0x80, 0xd0, 0x18, 0xcd, 0xc7, 0xbb,
+ 0xa7, 0x95, 0x8d, 0x92, 0xa0, 0xb4, 0xc3, 0xcc, 0xcf, 0xcf, 0xce, 0xca,
+ 0xc3, 0xb9, 0xab, 0x9e, 0x93, 0x8a, 0x85, 0x81, 0x7e, 0x7c, 0x82, 0x7a,
+ 0x06, 0x7f, 0x89, 0x98, 0xab, 0xbe, 0xc9, 0xce, 0x99, 0xd0, 0x06, 0xcf,
+ 0xcc, 0xc6, 0xba, 0xa5, 0x4f, 0x08, 0x96, 0x00, 0x08, 0x03, 0x2f, 0x69,
+ 0x85, 0xa0, 0xb6, 0xc4, 0xcc, 0xcf, 0x88, 0xd0, 0x0b, 0xcf, 0xcd, 0xc7,
+ 0xbe, 0xb3, 0xab, 0xac, 0xb4, 0xc0, 0xc8, 0xcd, 0xcf, 0x82, 0xd0, 0x08,
+ 0xcf, 0xcc, 0xc7, 0xbf, 0xb4, 0xab, 0xa6, 0xa2, 0xa0, 0x86, 0x9e, 0x12,
+ 0x9f, 0xa1, 0xa5, 0xac, 0xb7, 0xc2, 0xc9, 0xcd, 0xcd, 0xca, 0xc2, 0xb6,
+ 0xac, 0xa9, 0xae, 0xb8, 0xc3, 0xcb, 0xce, 0x89, 0xd0, 0x17, 0xcf, 0xce,
+ 0xca, 0xc1, 0xb5, 0xac, 0xa9, 0xae, 0xb8, 0xc3, 0xcb, 0xce, 0xcf, 0xcc,
+ 0xc6, 0xbd, 0xb3, 0xab, 0xad, 0xb5, 0xc0, 0xc9, 0xcd, 0xcf, 0x80, 0xd0,
+ 0x19, 0xcf, 0xcc, 0xc5, 0xbb, 0xb1, 0xab, 0xaf, 0xb8, 0xc2, 0xca, 0xce,
+ 0xd0, 0xd0, 0xcf, 0xce, 0xcc, 0xc6, 0xc1, 0xba, 0xb3, 0xac, 0xa8, 0xa4,
+ 0xa3, 0xa1, 0x9f, 0x80, 0x9e, 0x07, 0xa0, 0xa4, 0xa9, 0xb3, 0xbf, 0xc7,
+ 0xcc, 0xcf, 0x9a, 0xd0, 0x07, 0xcf, 0xcc, 0xc6, 0xb9, 0xa5, 0x7a, 0x29,
+ 0x01, 0x93, 0x00, 0x08, 0x04, 0x0b, 0x5d, 0x7a, 0x9a, 0xb3, 0xc3, 0xcb,
+ 0xce, 0x8a, 0xd0, 0x09, 0xcf, 0xcc, 0xc9, 0xc4, 0xc2, 0xc2, 0xc6, 0xca,
+ 0xcd, 0xcf, 0x84, 0xd0, 0x08, 0xcf, 0xcc, 0xca, 0xc6, 0xc2, 0xc0, 0xbd,
+ 0xbc, 0xbc, 0x84, 0xbb, 0x13, 0xbc, 0xbc, 0xbd, 0xbf, 0xc2, 0xc6, 0xcb,
+ 0xcd, 0xcf, 0xcf, 0xcd, 0xcb, 0xc6, 0xc2, 0xc1, 0xc2, 0xc6, 0xcb, 0xce,
+ 0xcf, 0x8a, 0xd0, 0x15, 0xcf, 0xcd, 0xca, 0xc6, 0xc2, 0xc0, 0xc2, 0xc6,
+ 0xcb, 0xce, 0xcf, 0xd0, 0xcf, 0xcc, 0xc8, 0xc4, 0xc2, 0xc2, 0xc6, 0xca,
+ 0xcd, 0xcf, 0x81, 0xd0, 0x0a, 0xcf, 0xce, 0xcc, 0xc7, 0xc3, 0xc2, 0xc3,
+ 0xc6, 0xcb, 0xce, 0xcf, 0x81, 0xd0, 0x09, 0xcf, 0xcd, 0xcc, 0xc8, 0xc5,
+ 0xc2, 0xc0, 0xbf, 0xbe, 0xbd, 0x82, 0xbc, 0x05, 0xbe, 0xc1, 0xc5, 0xc9,
+ 0xcd, 0xcf, 0x9c, 0xd0, 0x07, 0xcf, 0xcc, 0xc5, 0xba, 0xab, 0x96, 0x5a,
+ 0x15, 0x90, 0x00, 0x0a, 0x01, 0x03, 0x00, 0x01, 0x31, 0x84, 0xa4, 0xbc,
+ 0xc8, 0xcd, 0xcf, 0x8b, 0xd0, 0x09, 0xcf, 0xce, 0xcc, 0xcc, 0xca, 0xcb,
+ 0xcc, 0xcc, 0xce, 0xcf, 0x99, 0xd0, 0x0d, 0xcf, 0xce, 0xcd, 0xcd, 0xce,
+ 0xcf, 0xd0, 0xd0, 0xcf, 0xce, 0xcd, 0xcd, 0xce, 0xcf, 0xe8, 0xd0, 0x08,
+ 0xcf, 0xcc, 0xc6, 0xbf, 0xb2, 0xa1, 0x8a, 0x3f, 0x0a, 0x8c, 0x00, 0x01,
+ 0x04, 0x04, 0x81, 0x00, 0x05, 0x0d, 0x76, 0xa1, 0xbb, 0xc8, 0xce, 0x8b,
+ 0xd0, 0x0b, 0xcf, 0xce, 0xca, 0xc5, 0xc0, 0xbe, 0xbe, 0xc0, 0xc5, 0xca,
+ 0xcd, 0xcf, 0x8f, 0xd0, 0x01, 0xcf, 0xcf, 0x83, 0xd0, 0x0f, 0xcf, 0xcd,
+ 0xcb, 0xc7, 0xc6, 0xc9, 0xcc, 0xce, 0xce, 0xcc, 0xc9, 0xc6, 0xc6, 0xca,
+ 0xcd, 0xcf, 0xc7, 0xd0, 0x00, 0xcf, 0x9d, 0xd0, 0x0a, 0xcf, 0xcc, 0xc9,
+ 0xc3, 0xba, 0xab, 0x9b, 0x86, 0x50, 0x29, 0x0b, 0x85, 0x00, 0x03, 0x03,
+ 0x11, 0x22, 0x0e, 0x84, 0x00, 0x05, 0x25, 0x94, 0xb2, 0xc3, 0xcc, 0xcf,
+ 0x8a, 0xd0, 0x0c, 0xce, 0xcb, 0xda, 0xfd, 0xfd, 0xfb, 0xef, 0xc9, 0xb4,
+ 0xc0, 0xc8, 0xcd, 0xcf, 0x8c, 0xd0, 0x05, 0xcf, 0xce, 0xcd, 0xcd, 0xce,
+ 0xcf, 0x81, 0xd0, 0x0f, 0xce, 0xca, 0xd9, 0xfc, 0xbc, 0xbf, 0xc6, 0xcc,
+ 0xcc, 0xc7, 0xf4, 0xe9, 0xba, 0xc1, 0xc9, 0xce, 0xc4, 0xd0, 0x06, 0xcf,
+ 0xcf, 0xce, 0xcd, 0xce, 0xcf, 0xcf, 0x9b, 0xd0, 0x0c, 0xcf, 0xce, 0xcc,
+ 0xc7, 0xc0, 0xb6, 0xab, 0x9c, 0x8f, 0x84, 0x6d, 0x52, 0x3f, 0x80, 0x3a,
+ 0x06, 0x3c, 0x4a, 0x66, 0x72, 0x76, 0x4f, 0x06, 0x83, 0x00, 0x05, 0x08,
+ 0x66, 0xa3, 0xbb, 0xc8, 0xce, 0x89, 0xd0, 0x0d, 0xcf, 0xcd, 0xc6, 0xde,
+ 0xff, 0xf5, 0xf8, 0xff, 0xff, 0xb7, 0xb1, 0xc1, 0xca, 0xce, 0x8b, 0xd0,
+ 0x1b, 0xcf, 0xcc, 0xca, 0xc7, 0xc7, 0xcb, 0xcd, 0xcf, 0xd0, 0xd0, 0xcf,
+ 0xcc, 0xc4, 0xee, 0xff, 0xbf, 0xaf, 0xbe, 0xc7, 0xc6, 0xd3, 0xff, 0xf0,
+ 0xa6, 0xb5, 0xc4, 0xcc, 0xcf, 0xc2, 0xd0, 0x08, 0xcf, 0xce, 0xcc, 0xc9,
+ 0xc7, 0xc8, 0xcc, 0xce, 0xcf, 0x9c, 0xd0, 0x0b, 0xcf, 0xcd, 0xcb, 0xc6,
+ 0xc0, 0xb8, 0xaf, 0xa7, 0x9e, 0x98, 0x91, 0x8d, 0x80, 0x8a, 0x05, 0x8d,
+ 0x92, 0x97, 0x98, 0x92, 0x25, 0x84, 0x00, 0x05, 0x19, 0x90, 0xad, 0xc1,
+ 0xcb, 0xcf, 0x88, 0xd0, 0x0d, 0xcf, 0xcc, 0xc3, 0xe2, 0xff, 0x9d, 0x81,
+ 0xc1, 0xff, 0xd0, 0xa2, 0xb8, 0xc6, 0xcd, 0x81, 0xcf, 0x83, 0xd0, 0x81,
+ 0xcf, 0x1c, 0xcc, 0xc9, 0xf3, 0xe1, 0xbd, 0xc3, 0xcb, 0xce, 0xd0, 0xd0,
+ 0xce, 0xc9, 0xc6, 0xff, 0xff, 0xcb, 0x9e, 0xb4, 0xc1, 0xc0, 0xf0, 0xff,
+ 0xfb, 0x93, 0xa9, 0xbf, 0xcb, 0xcf, 0xd0, 0x82, 0xcf, 0x80, 0xd0, 0x81,
+ 0xcf, 0x83, 0xd0, 0x82, 0xcf, 0x82, 0xd0, 0x82, 0xcf, 0x81, 0xd0, 0x80,
+ 0xcf, 0x81, 0xd0, 0x85, 0xcf, 0x82, 0xd0, 0x80, 0xcf, 0x81, 0xd0, 0x81,
+ 0xcf, 0x08, 0xce, 0xcc, 0xd4, 0xf3, 0xd3, 0xbf, 0xc6, 0xcc, 0xcf, 0x9d,
+ 0xd0, 0x14, 0xcf, 0xcf, 0xcd, 0xcb, 0xc7, 0xc3, 0xc0, 0xbb, 0xb5, 0xb2,
+ 0xae, 0xac, 0xab, 0xac, 0xaf, 0xb3, 0xb5, 0xb5, 0xae, 0x88, 0x0e, 0x83,
+ 0x00, 0x06, 0x03, 0x48, 0x9e, 0xb7, 0xc6, 0xcd, 0xcf, 0x87, 0xd0, 0x0c,
+ 0xcf, 0xcb, 0xc0, 0xeb, 0xff, 0x8a, 0x7f, 0xa1, 0xff, 0xd2, 0x99, 0xb2,
+ 0xc3, 0x81, 0xcc, 0x01, 0xcd, 0xce, 0x80, 0xcf, 0x01, 0xce, 0xcd, 0x81,
+ 0xcc, 0x13, 0xc9, 0xca, 0xff, 0xdc, 0xac, 0xba, 0xc6, 0xcc, 0xcf, 0xcf,
+ 0xcd, 0xc5, 0xda, 0xff, 0xff, 0xe2, 0x8f, 0xa9, 0xb9, 0xca, 0x80, 0xff,
+ 0x03, 0x91, 0xa0, 0xbb, 0xc8, 0x80, 0xcd, 0x01, 0xcc, 0xcc, 0x80, 0xcd,
+ 0x0b, 0xce, 0xce, 0xcd, 0xcd, 0xcc, 0xcc, 0xcd, 0xce, 0xcf, 0xcf, 0xce,
+ 0xcd, 0x80, 0xcc, 0x06, 0xcd, 0xcd, 0xce, 0xce, 0xcf, 0xce, 0xcd, 0x80,
+ 0xcc, 0x01, 0xcd, 0xcd, 0x80, 0xce, 0x03, 0xcd, 0xcc, 0xcc, 0xcd, 0x81,
+ 0xce, 0x00, 0xcd, 0x83, 0xcc, 0x08, 0xcd, 0xcd, 0xce, 0xcf, 0xce, 0xce,
+ 0xcd, 0xcc, 0xcd, 0x80, 0xce, 0x01, 0xcd, 0xcd, 0x81, 0xcc, 0x08, 0xc6,
+ 0xd9, 0xff, 0xc5, 0xb1, 0xbe, 0xc8, 0xcd, 0xcf, 0x9e, 0xd0, 0x08, 0xcf,
+ 0xcf, 0xce, 0xcc, 0xcb, 0xc9, 0xc7, 0xc5, 0xc3, 0x80, 0xc2, 0x06, 0xc3,
+ 0xc5, 0xc6, 0xc6, 0xc0, 0xaf, 0x3f, 0x84, 0x00, 0x05, 0x11, 0x85, 0xa9,
+ 0xbf, 0xca, 0xce, 0x87, 0xd0, 0x65, 0xcf, 0xcb, 0xbf, 0xf4, 0xf9, 0x81,
+ 0x84, 0xd2, 0xff, 0xb5, 0x97, 0xaf, 0xc0, 0xc7, 0xc6, 0xc4, 0xc4, 0xc6,
+ 0xc9, 0xcc, 0xcd, 0xcc, 0xcb, 0xc7, 0xc5, 0xc3, 0xc5, 0xc6, 0xc2, 0xcb,
+ 0xff, 0xc8, 0x9e, 0xaf, 0xc0, 0xcb, 0xce, 0xcf, 0xcb, 0xc0, 0xf5, 0xf9,
+ 0xf0, 0xfc, 0x8a, 0x9f, 0xb0, 0xe9, 0xff, 0xea, 0xff, 0x9a, 0x9a, 0xb5,
+ 0xc5, 0xc9, 0xc7, 0xc5, 0xc4, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc8, 0xc6,
+ 0xc5, 0xc4, 0xc5, 0xc6, 0xc9, 0xcc, 0xcc, 0xca, 0xc7, 0xc5, 0xc4, 0xc4,
+ 0xc5, 0xc6, 0xc8, 0xca, 0xcb, 0xca, 0xc6, 0xc5, 0xc4, 0xc4, 0xc5, 0xc6,
+ 0xc7, 0xc9, 0xc9, 0xc6, 0xc5, 0xc4, 0xc6, 0xc8, 0xcb, 0xca, 0xc8, 0xc5,
+ 0x80, 0xc3, 0x1d, 0xc4, 0xc5, 0xc4, 0xc5, 0xc7, 0xca, 0xcc, 0xca, 0xc7,
+ 0xc5, 0xc4, 0xc5, 0xc8, 0xca, 0xca, 0xc7, 0xc6, 0xc4, 0xc4, 0xc5, 0xc4,
+ 0xbf, 0xdb, 0xff, 0xac, 0xa2, 0xb4, 0xc4, 0xcc, 0xcf, 0xa1, 0xd0, 0x04,
+ 0xcf, 0xcf, 0xce, 0xce, 0xcd, 0x82, 0xcc, 0x06, 0xcd, 0xcd, 0xcc, 0xc8,
+ 0xbc, 0xa1, 0x17, 0x84, 0x00, 0x05, 0x2f, 0x98, 0xb4, 0xc4, 0xcc, 0xcf,
+ 0x86, 0xd0, 0x7f, 0xcf, 0xca, 0xbd, 0xfe, 0xfb, 0xd6, 0xef, 0xff, 0xd3,
+ 0x83, 0x96, 0xad, 0xbb, 0xcc, 0xdd, 0xe1, 0xd2, 0xb8, 0xbc, 0xc3, 0xc7,
+ 0xc6, 0xcd, 0xdc, 0xe1, 0xd3, 0xb8, 0xb7, 0xc5, 0xe4, 0xff, 0xda, 0xc7,
+ 0xa7, 0xbb, 0xc8, 0xcd, 0xcd, 0xc8, 0xcc, 0xff, 0xd0, 0xca, 0xff, 0xa2,
+ 0x97, 0xb8, 0xff, 0xdc, 0xc0, 0xff, 0xaa, 0x96, 0xb1, 0xbe, 0xcb, 0xdb,
+ 0xdf, 0xd2, 0xb7, 0xcf, 0xdb, 0xba, 0xc2, 0xdd, 0xcc, 0xce, 0xdd, 0xcb,
+ 0xb8, 0xbe, 0xc3, 0xc3, 0xcf, 0xdb, 0xde, 0xd0, 0xb5, 0xd4, 0xd7, 0xbb,
+ 0xc0, 0xc2, 0xcf, 0xdc, 0xde, 0xd0, 0xb5, 0xd6, 0xd4, 0xbb, 0xbd, 0xc9,
+ 0xdc, 0xe1, 0xd2, 0xb8, 0xbc, 0xc1, 0xd1, 0xdd, 0xc9, 0xdd, 0xdb, 0xbe,
+ 0xb8, 0xd9, 0xdd, 0xc6, 0xba, 0xbf, 0xc2, 0xc7, 0xda, 0xe2, 0xd6, 0xbb,
+ 0xbb, 0xbf, 0xd4, 0xdd, 0xc1, 0xd9, 0xd8, 0xbc, 0xb4, 0xcc, 0xef, 0x06,
+ 0xff, 0xca, 0xbf, 0xab, 0xbf, 0xca, 0xce, 0xa5, 0xd0, 0x84, 0xcf, 0x06,
+ 0xd0, 0xcf, 0xcc, 0xc5, 0xb4, 0x5d, 0x04, 0x83, 0x00, 0x05, 0x0a, 0x70,
+ 0xa4, 0xbc, 0xc9, 0xce, 0x86, 0xd0, 0x02, 0xce, 0xc8, 0xc2, 0x82, 0xff,
+ 0x04, 0xf7, 0xb2, 0x93, 0xa7, 0xd5, 0x81, 0xff, 0x05, 0xf0, 0xae, 0xb4,
+ 0xbd, 0xd7, 0xfd, 0x80, 0xff, 0x02, 0xf3, 0xaa, 0xd2, 0x80, 0xff, 0x21,
+ 0xfb, 0x9c, 0xb4, 0xc6, 0xcc, 0xcc, 0xc4, 0xe3, 0xff, 0xa1, 0xa9, 0xff,
+ 0xc0, 0x8d, 0xde, 0xff, 0x9e, 0xae, 0xff, 0xbc, 0x93, 0xa9, 0xd9, 0xff,
+ 0xff, 0xf9, 0xff, 0xef, 0xf4, 0xf8, 0xa4, 0xbf, 0xff, 0xf7, 0x80, 0xff,
+ 0x24, 0xdb, 0xab, 0xb4, 0xe1, 0xff, 0xff, 0xf9, 0xff, 0xe9, 0xfa, 0xee,
+ 0xa7, 0xb0, 0xe2, 0xff, 0xff, 0xfd, 0xff, 0xe7, 0xfe, 0xe4, 0xa4, 0xca,
+ 0xfd, 0xff, 0xfc, 0xff, 0xee, 0xad, 0xb0, 0xe3, 0xff, 0xfe, 0xff, 0xff,
+ 0xfc, 0xf6, 0x80, 0xff, 0x11, 0xc3, 0xab, 0xc5, 0xfa, 0xff, 0xfd, 0xff,
+ 0xf5, 0xb3, 0xac, 0xed, 0xff, 0xf7, 0xff, 0xff, 0xfe, 0xa9, 0xeb, 0x80,
+ 0xff, 0x04, 0xdd, 0xa4, 0xbb, 0xc7, 0xce, 0xae, 0xd0, 0x04, 0xce, 0xca,
+ 0xc0, 0xab, 0x22, 0x84, 0x00, 0x05, 0x1d, 0x93, 0xb0, 0xc2, 0xcc, 0xcf,
+ 0x85, 0xd0, 0x7f, 0xce, 0xc7, 0xc9, 0xff, 0xd2, 0x8b, 0x92, 0xb1, 0xf0,
+ 0xff, 0xa2, 0xaf, 0xff, 0xf3, 0xba, 0xa2, 0xde, 0xff, 0xd0, 0xa2, 0xb9,
+ 0xfd, 0xf6, 0xbd, 0xa1, 0xd9, 0xff, 0xd4, 0x93, 0xd8, 0xff, 0x8d, 0x8a,
+ 0x9e, 0xb4, 0xc5, 0xcc, 0xca, 0xc2, 0xfb, 0xf0, 0x85, 0x91, 0xff, 0xe0,
+ 0x96, 0xff, 0xe0, 0x82, 0xa3, 0xff, 0xcf, 0x8e, 0xb8, 0xff, 0xe7, 0xaa,
+ 0x93, 0xaf, 0xfa, 0xff, 0xe7, 0x8e, 0xbe, 0xff, 0xef, 0xaa, 0xaa, 0xfb,
+ 0xf9, 0x9a, 0xc4, 0xff, 0xe1, 0xa6, 0x93, 0xb5, 0xfe, 0xff, 0xdb, 0x93,
+ 0xc7, 0xff, 0xe1, 0xa8, 0x96, 0xc0, 0xff, 0xff, 0xcd, 0x9b, 0xfb, 0xf8,
+ 0xa1, 0x89, 0xc4, 0xff, 0xcb, 0x9b, 0xe8, 0xff, 0xd3, 0x9e, 0xd9, 0xff,
+ 0xec, 0xa1, 0xa5, 0xfe, 0xe7, 0x99, 0xf2, 0xfe, 0xb0, 0x88, 0xb1, 0xff,
+ 0xde, 0x97, 0xf4, 0xff, 0xc6, 0xa0, 0xd9, 0xff, 0xc1, 0x91, 0xf5, 0x06,
+ 0xea, 0x81, 0x8e, 0xa4, 0xbb, 0xc7, 0xce, 0xae, 0xd0, 0x05, 0xcf, 0xcd,
+ 0xc6, 0xb8, 0x81, 0x0a, 0x83, 0x00, 0x06, 0x04, 0x54, 0x9f, 0xb9, 0xc7,
+ 0xcd, 0xcf, 0x83, 0xd0, 0x7f, 0xcf, 0xcd, 0xc6, 0xcf, 0xff, 0xbc, 0x7e,
+ 0x85, 0x88, 0xb6, 0xff, 0xc3, 0xc9, 0xff, 0xbb, 0x86, 0x89, 0x9c, 0xff,
+ 0xe7, 0x92, 0xcc, 0xff, 0xc5, 0x87, 0x89, 0x96, 0xff, 0xec, 0x83, 0xe2,
+ 0xfc, 0x7d, 0x8e, 0xa6, 0xbb, 0xc7, 0xcb, 0xc6, 0xd4, 0xff, 0xc7, 0x8a,
+ 0x8c, 0xf1, 0xfc, 0xd2, 0xff, 0xa2, 0x86, 0x9c, 0xff, 0xe2, 0x89, 0xd8,
+ 0xff, 0xa7, 0x8e, 0x93, 0x94, 0xd3, 0xff, 0xd4, 0x82, 0xc5, 0xff, 0xa6,
+ 0x84, 0x86, 0xdf, 0xff, 0x8e, 0xe3, 0xfe, 0x9a, 0x8e, 0x94, 0x93, 0xdf,
+ 0xff, 0xc6, 0x85, 0xe7, 0xfe, 0x99, 0x8e, 0x93, 0x92, 0xe5, 0xff, 0xb8,
+ 0xb5, 0xff, 0xe8, 0xc4, 0xc4, 0xc8, 0xff, 0xe5, 0x8c, 0xf2, 0xf0, 0x80,
+ 0x81, 0xb4, 0xff, 0xa9, 0x7f, 0x86, 0xf4, 0xeb, 0xa3, 0xff, 0xf2, 0xc5,
+ 0xc4, 0xc5, 0xf7, 0xfb, 0x89, 0xff, 0xe1, 0x80, 0x84, 0xa6, 0xff, 0xc4,
+ 0x85, 0x07, 0xff, 0xda, 0x7f, 0x93, 0xab, 0xc0, 0xca, 0xce, 0xaf, 0xd0,
+ 0x04, 0xcf, 0xcc, 0xc2, 0xaf, 0x35, 0x84, 0x00, 0x05, 0x15, 0x8a, 0xab,
+ 0xc0, 0xcb, 0xce, 0x83, 0xd0, 0x73, 0xcf, 0xcc, 0xc4, 0xd7, 0xff, 0xaf,
+ 0x8a, 0x94, 0x99, 0xc0, 0xff, 0xc4, 0xd5, 0xff, 0x9a, 0x86, 0x90, 0xa1,
+ 0xff, 0xe2, 0x89, 0xd6, 0xff, 0xa6, 0x88, 0x91, 0x9c, 0xfe, 0xe8, 0x7e,
+ 0xf1, 0xed, 0x86, 0x9a, 0xb2, 0xc2, 0xcb, 0xcb, 0xc2, 0xed, 0xff, 0x9e,
+ 0x92, 0x99, 0xd8, 0xff, 0xff, 0xe2, 0x80, 0x90, 0x9b, 0xfe, 0xf2, 0x83,
+ 0xe8, 0xf9, 0x8a, 0x90, 0x9c, 0x9e, 0xd2, 0xff, 0xc2, 0x7e, 0xd1, 0xff,
+ 0x96, 0x8b, 0x92, 0xe7, 0xfe, 0x80, 0xf4, 0xed, 0x86, 0x91, 0x9e, 0x9e,
+ 0xdd, 0xff, 0xb4, 0x80, 0xf5, 0xea, 0x88, 0x92, 0x9e, 0x9e, 0xdb, 0xff,
+ 0xa3, 0xc1, 0xff, 0xe6, 0xd8, 0xd9, 0xda, 0xda, 0xd2, 0x89, 0xfe, 0xdf,
+ 0x82, 0x8a, 0xc3, 0xff, 0x9f, 0x87, 0x90, 0xfd, 0xdf, 0xad, 0xff, 0xec,
+ 0xd6, 0xd9, 0x80, 0xda, 0x10, 0x97, 0xff, 0xce, 0x84, 0x8e, 0xb3, 0xff,
+ 0xbc, 0x93, 0xff, 0xcb, 0x89, 0x9f, 0xb6, 0xc5, 0xcc, 0xcf, 0xb0, 0xd0,
+ 0x04, 0xce, 0xc8, 0xbb, 0x99, 0x14, 0x83, 0x00, 0x06, 0x01, 0x38, 0x9a,
+ 0xb4, 0xc5, 0xcc, 0xcf, 0x82, 0xd0, 0x7f, 0xcf, 0xcc, 0xc2, 0xdf, 0xff,
+ 0xa0, 0x8b, 0x9a, 0xb4, 0xef, 0xff, 0xa6, 0xc3, 0xff, 0xc2, 0x86, 0x94,
+ 0xd4, 0xff, 0xc6, 0x88, 0xc6, 0xff, 0xcb, 0x89, 0x94, 0xce, 0xff, 0xcb,
+ 0x82, 0xfe, 0xde, 0x8d, 0xa3, 0xba, 0xc7, 0xcc, 0xc9, 0xc6, 0xff, 0xe5,
+ 0x90, 0x9b, 0xa5, 0xc4, 0xff, 0xff, 0x9f, 0x87, 0x9c, 0xa4, 0xf3, 0xff,
+ 0x84, 0xd9, 0xff, 0xa7, 0x90, 0x9e, 0xa6, 0xf9, 0xff, 0xb2, 0x80, 0xe0,
+ 0xfe, 0x8c, 0x96, 0x9e, 0xf1, 0xf4, 0x81, 0xe6, 0xff, 0x99, 0x92, 0x9f,
+ 0xac, 0xfe, 0xff, 0xa4, 0x82, 0xe4, 0xff, 0x97, 0x93, 0xa0, 0xa9, 0xfc,
+ 0xff, 0x92, 0xaf, 0xff, 0xd1, 0x70, 0x76, 0x99, 0x87, 0x85, 0x99, 0xff,
+ 0xd2, 0x8a, 0x94, 0xd3, 0xff, 0x97, 0x93, 0xa2, 0xff, 0xd4, 0x9a, 0xff,
+ 0xe8, 0x70, 0x74, 0x8f, 0x8d, 0x81, 0xa4, 0xff, 0xc0, 0x8c, 0x9a, 0xc2,
+ 0xff, 0xb3, 0xa3, 0x06, 0xff, 0xbe, 0x92, 0xa9, 0xbe, 0xca, 0xce, 0xb1,
+ 0xd0, 0x05, 0xcf, 0xcc, 0xc4, 0xb3, 0x4f, 0x01, 0x83, 0x00, 0x05, 0x08,
+ 0x7a, 0xa6, 0xbd, 0xc9, 0xce, 0x82, 0xd0, 0x7f, 0xcf, 0xcc, 0xc1, 0xe8,
+ 0xff, 0xee, 0xec, 0xf8, 0xff, 0xff, 0xd9, 0x81, 0x96, 0xfc, 0xff, 0xe8,
+ 0xf1, 0xff, 0xf4, 0x8f, 0x8f, 0xa3, 0xfb, 0xff, 0xea, 0xee, 0xff, 0xf7,
+ 0x8e, 0x95, 0xff, 0xd2, 0x93, 0xa9, 0xbf, 0xca, 0xcc, 0xc6, 0xdd, 0xff,
+ 0xbc, 0x96, 0xa5, 0xb0, 0xb5, 0xff, 0xe9, 0x81, 0x94, 0xa9, 0xaf, 0xe8,
+ 0xff, 0x97, 0xa9, 0xff, 0xfb, 0xd7, 0xd4, 0xf9, 0xff, 0xff, 0xa3, 0x83,
+ 0xee, 0xf2, 0x8f, 0x9e, 0xa8, 0xfd, 0xe4, 0x86, 0xb7, 0xff, 0xf8, 0xd2,
+ 0xd9, 0xfb, 0xff, 0xff, 0x95, 0x88, 0xb5, 0xff, 0xf3, 0xcc, 0xd3, 0xf8,
+ 0xff, 0xff, 0x82, 0x85, 0xf4, 0xff, 0xe8, 0xdc, 0xff, 0xec, 0x92, 0xae,
+ 0xff, 0xc5, 0x92, 0x9c, 0xe3, 0xfd, 0x92, 0x9b, 0xb5, 0xff, 0xc7, 0x83,
+ 0xe4, 0xff, 0xf0, 0xd7, 0xfe, 0xf7, 0x97, 0xb8, 0xff, 0xb5, 0x94, 0xa2,
+ 0xd3, 0xff, 0xa5, 0xb5, 0x06, 0xff, 0xb3, 0x98, 0xaf, 0xc2, 0xcc, 0xcf,
+ 0xb2, 0xd0, 0x04, 0xce, 0xca, 0xbf, 0xa7, 0x1d, 0x84, 0x00, 0x05, 0x0e,
+ 0x95, 0xb2, 0xc4, 0xcc, 0xcf, 0x81, 0xd0, 0x03, 0xcf, 0xcc, 0xc1, 0xf2,
+ 0x80, 0xff, 0x7f, 0xf8, 0xe7, 0xbb, 0x8c, 0x8f, 0x95, 0xb1, 0xf1, 0xff,
+ 0xfe, 0xe0, 0x97, 0x91, 0x9e, 0xa4, 0xb6, 0xef, 0xff, 0xfe, 0xe3, 0x98,
+ 0x8b, 0xad, 0xff, 0xc8, 0x9c, 0xb0, 0xc2, 0xcb, 0xcc, 0xc5, 0xf6, 0xfb,
+ 0x9d, 0x9f, 0xb0, 0xbb, 0xb4, 0xf5, 0xb7, 0x93, 0xa4, 0xb5, 0xb8, 0xde,
+ 0xff, 0xaf, 0x8e, 0xba, 0xf7, 0xff, 0xff, 0xe3, 0xd7, 0xff, 0x98, 0x8d,
+ 0xfc, 0xe6, 0x98, 0xa5, 0xb8, 0xff, 0xd8, 0x91, 0x93, 0xc5, 0xfb, 0xff,
+ 0xff, 0xdc, 0xdf, 0xff, 0x8c, 0x93, 0x9b, 0xc0, 0xf7, 0xff, 0xff, 0xe0,
+ 0xf2, 0xf9, 0x7a, 0x88, 0xa4, 0xe6, 0xff, 0xff, 0xea, 0xa5, 0x96, 0xc0,
+ 0xff, 0xbd, 0x9b, 0xa4, 0xf2, 0xf2, 0x9a, 0xa3, 0xc7, 0xff, 0xbd, 0x8f,
+ 0x9a, 0xdb, 0xfd, 0xff, 0xef, 0xb2, 0x91, 0xcb, 0xff, 0xaf, 0x9e, 0xab,
+ 0xe1, 0xff, 0x9c, 0xc8, 0xff, 0xab, 0xa1, 0xb5, 0xc5, 0xcd, 0xcf, 0xb2,
+ 0xd0, 0x05, 0xcf, 0xcd, 0xc6, 0xb6, 0x72, 0x08, 0x83, 0x00, 0x05, 0x07,
+ 0x73, 0xa5, 0xbe, 0xca, 0xcf, 0x81, 0xd0, 0x76, 0xcf, 0xcc, 0xc4, 0xb4,
+ 0x9e, 0x8f, 0x8a, 0x8a, 0x8e, 0x93, 0x9b, 0xa5, 0xab, 0xa9, 0x9e, 0x9c,
+ 0x92, 0x8f, 0x97, 0xa3, 0xb1, 0xb5, 0xae, 0xa0, 0x9c, 0x94, 0x8e, 0x95,
+ 0x9e, 0xa5, 0xa5, 0xa4, 0xab, 0xb9, 0xc6, 0xcc, 0xcc, 0xc6, 0xba, 0xab,
+ 0xa5, 0xad, 0xbb, 0xc2, 0xbf, 0xb2, 0xa7, 0xa9, 0xb4, 0xc0, 0xc1, 0xb5,
+ 0xa7, 0x9f, 0xa0, 0x9f, 0x9a, 0xa2, 0x97, 0x8f, 0x8e, 0x8e, 0x94, 0x9e,
+ 0xa3, 0xa2, 0xa6, 0xb1, 0xb6, 0xb0, 0xa6, 0xa4, 0xa5, 0xa3, 0x9c, 0xa2,
+ 0x96, 0x8f, 0x8e, 0x8e, 0x98, 0xa4, 0xa9, 0xa1, 0x93, 0x98, 0x8d, 0x8f,
+ 0xff, 0xd9, 0x81, 0x95, 0xa0, 0x9b, 0x98, 0x95, 0x8f, 0x98, 0xa4, 0xab,
+ 0xa8, 0xa5, 0xab, 0xb1, 0xaf, 0xa8, 0xa7, 0xae, 0xb3, 0xac, 0xa4, 0xa3,
+ 0xa3, 0x9e, 0x96, 0x98, 0x8e, 0x96, 0x9e, 0x80, 0xa4, 0x0b, 0xab, 0xb4,
+ 0xb3, 0xa9, 0x9f, 0x9e, 0x9e, 0xa3, 0xae, 0xbd, 0xc8, 0xce, 0xb4, 0xd0,
+ 0x04, 0xcf, 0xcb, 0xc1, 0xac, 0x2b, 0x82, 0x00, 0x06, 0x01, 0x01, 0x4a,
+ 0x9b, 0xb8, 0xc8, 0xce, 0x82, 0xd0, 0x4a, 0xce, 0xc8, 0xbf, 0xb3, 0xa8,
+ 0xa3, 0xa3, 0xa5, 0xab, 0xb3, 0xbb, 0xbf, 0xbc, 0xb4, 0xab, 0xa6, 0xa7,
+ 0xad, 0xb7, 0xc0, 0xc3, 0xbf, 0xb5, 0xab, 0xa6, 0xa7, 0xac, 0xb4, 0xb9,
+ 0xb8, 0xb7, 0xbb, 0xc2, 0xca, 0xce, 0xcd, 0xca, 0xc2, 0xba, 0xb7, 0xbd,
+ 0xc5, 0xc9, 0xc6, 0xc0, 0xbb, 0xbc, 0xc2, 0xc8, 0xc7, 0xc1, 0xb9, 0xb4,
+ 0xb5, 0xb4, 0xb0, 0xa9, 0xa6, 0xa4, 0xa5, 0xa8, 0xad, 0xb3, 0xb5, 0xb5,
+ 0xb8, 0xbe, 0xc1, 0xbd, 0xb8, 0xb7, 0xb9, 0xb7, 0xb1, 0xa9, 0x80, 0xa5,
+ 0x36, 0xa9, 0xae, 0xb4, 0xde, 0xf4, 0xce, 0x9c, 0x9d, 0xde, 0xff, 0xad,
+ 0x8d, 0xa4, 0xb2, 0xb3, 0xab, 0xa7, 0xa8, 0xad, 0xb4, 0xba, 0xb9, 0xb7,
+ 0xbb, 0xbe, 0xbd, 0xb8, 0xb8, 0xbc, 0xbf, 0xbb, 0xb7, 0xb7, 0xb8, 0xb4,
+ 0xac, 0xa7, 0xa7, 0xab, 0xb3, 0xb6, 0xb6, 0xb7, 0xbb, 0xc0, 0xbf, 0xb9,
+ 0xb4, 0xb3, 0xb3, 0xb5, 0xbd, 0xc5, 0xcc, 0xcf, 0xb4, 0xd0, 0x05, 0xcf,
+ 0xcd, 0xc7, 0xba, 0x90, 0x03, 0x82, 0x00, 0x05, 0x03, 0x53, 0x98, 0xb5,
+ 0xc6, 0xce, 0x82, 0xd0, 0x1b, 0xcf, 0xcc, 0xc8, 0xc2, 0xbf, 0xbc, 0xbc,
+ 0xbd, 0xc0, 0xc3, 0xc7, 0xca, 0xc8, 0xc4, 0xc0, 0xbd, 0xbe, 0xc1, 0xc6,
+ 0xca, 0xcc, 0xc9, 0xc5, 0xc0, 0xbd, 0xbe, 0xc1, 0xc4, 0x81, 0xc6, 0x24,
+ 0xcb, 0xcd, 0xcf, 0xcf, 0xcd, 0xc9, 0xc6, 0xc5, 0xc8, 0xcc, 0xcd, 0xcc,
+ 0xca, 0xc7, 0xc8, 0xcb, 0xcd, 0xcc, 0xca, 0xc6, 0xc4, 0xc5, 0xc5, 0xc2,
+ 0xbf, 0xbc, 0xbc, 0xbd, 0xbf, 0xc1, 0xc4, 0xc5, 0xc4, 0xc6, 0xc8, 0xc9,
+ 0xc7, 0x81, 0xc6, 0x09, 0xc2, 0xbf, 0xbc, 0xbc, 0xbd, 0xbf, 0xc1, 0xc0,
+ 0xc7, 0xfb, 0x81, 0xff, 0x0a, 0xd4, 0x88, 0x9b, 0xb1, 0xc0, 0xc2, 0xc0,
+ 0xbe, 0xbe, 0xc1, 0xc4, 0x81, 0xc6, 0x05, 0xc8, 0xc7, 0xc6, 0xc6, 0xc7,
+ 0xc8, 0x81, 0xc6, 0x05, 0xc5, 0xc1, 0xbe, 0xbe, 0xc0, 0xc3, 0x80, 0xc5,
+ 0x0b, 0xc7, 0xc9, 0xc8, 0xc6, 0xc4, 0xc3, 0xc3, 0xc5, 0xc7, 0xcc, 0xce,
+ 0xcf, 0xb5, 0xd0, 0x05, 0xcf, 0xcc, 0xc2, 0xb1, 0x34, 0x03, 0x81, 0x00,
+ 0x05, 0x10, 0x76, 0x9b, 0xb7, 0xc7, 0xce, 0x83, 0xd0, 0x03, 0xcf, 0xcd,
+ 0xcc, 0xcb, 0x80, 0xca, 0x20, 0xcb, 0xcc, 0xcd, 0xce, 0xce, 0xcc, 0xcb,
+ 0xca, 0xca, 0xcc, 0xcd, 0xce, 0xcf, 0xce, 0xcc, 0xcb, 0xca, 0xca, 0xcc,
+ 0xcc, 0xcd, 0xcd, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd0, 0xcf, 0xce, 0xcd,
+ 0xcc, 0xcd, 0x80, 0xcf, 0x07, 0xce, 0xcd, 0xcd, 0xce, 0xcf, 0xcf, 0xce,
+ 0xcd, 0x81, 0xcc, 0x04, 0xcb, 0xca, 0xc9, 0xca, 0xcb, 0x82, 0xcc, 0x03,
+ 0xcd, 0xce, 0xcd, 0xcc, 0x80, 0xcd, 0x1b, 0xcc, 0xca, 0xc9, 0xc9, 0xca,
+ 0xcb, 0xca, 0xc7, 0xbe, 0xb9, 0xc7, 0xdc, 0xd0, 0xae, 0x8c, 0x98, 0xab,
+ 0xbd, 0xc7, 0xcb, 0xcb, 0xca, 0xca, 0xcb, 0xcc, 0xcd, 0xcd, 0xcc, 0x80,
+ 0xcd, 0x01, 0xcc, 0xcc, 0x80, 0xcd, 0x07, 0xcc, 0xcd, 0xcd, 0xcc, 0xcc,
+ 0xca, 0xca, 0xcb, 0x81, 0xcc, 0x03, 0xcd, 0xce, 0xcd, 0xcd, 0x81, 0xcc,
+ 0x02, 0xcd, 0xcf, 0xcf, 0xb7, 0xd0, 0x0e, 0xce, 0xc9, 0xbd, 0xa5, 0x31,
+ 0x0a, 0x00, 0x03, 0x10, 0x55, 0x87, 0xa5, 0xbd, 0xca, 0xcf, 0x84, 0xd0,
+ 0x85, 0xcf, 0x80, 0xd0, 0x83, 0xcf, 0x80, 0xd0, 0x87, 0xcf, 0x83, 0xd0,
+ 0x80, 0xcf, 0x81, 0xd0, 0x00, 0xcf, 0x82, 0xd0, 0x83, 0xcf, 0x01, 0xce,
+ 0xce, 0x85, 0xcf, 0x00, 0xd0, 0x84, 0xcf, 0x11, 0xce, 0xce, 0xcf, 0xcf,
+ 0xce, 0xcb, 0xc4, 0xb8, 0xa9, 0x9e, 0x98, 0x99, 0xa0, 0xac, 0xbb, 0xc6,
+ 0xcc, 0xce, 0x9a, 0xcf, 0x01, 0xd0, 0xd0, 0x83, 0xcf, 0xb9, 0xd0, 0x0e,
+ 0xcf, 0xcc, 0xc6, 0xb8, 0xa4, 0x7c, 0x4d, 0x55, 0x76, 0x87, 0x9e, 0xb4,
+ 0xc4, 0xcc, 0xcf, 0xff, 0xd0, 0xbf, 0xd0, 0x0c, 0xcf, 0xcc, 0xc4, 0xb9,
+ 0xab, 0x9e, 0x98, 0x9b, 0xa5, 0xb4, 0xc1, 0xca, 0xce, 0xff, 0xd0, 0x93,
+ 0xd0, 0x94, 0xd0, 0x12, 0xcf, 0xce, 0xcd, 0xcc, 0xcb, 0xc9, 0xc7, 0xc6,
+ 0xc5, 0xc4, 0xc4, 0xc6, 0xc7, 0xc9, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xff,
+ 0xd0, 0xb7, 0xd0, 0x18, 0xcf, 0xcf, 0xcd, 0xcc, 0xc9, 0xc6, 0xc2, 0xbc,
+ 0xa4, 0x8b, 0x7a, 0x69, 0x73, 0x85, 0x9e, 0xb4, 0xba, 0xbe, 0xc2, 0xc6,
+ 0xc9, 0xcc, 0xcd, 0xcf, 0xcf, 0xff, 0xd0, 0xb3, 0xd0, 0x08, 0xcf, 0xcd,
+ 0xcb, 0xc7, 0xc2, 0xa9, 0x64, 0x2a, 0x0a, 0x83, 0x00, 0x0d, 0x01, 0x0b,
+ 0x22, 0x56, 0x95, 0xb4, 0xbb, 0xc2, 0xc7, 0xcb, 0xcd, 0xcf, 0xd0, 0xd0,
+ 0x81, 0xcf, 0xff, 0xd0, 0xaa, 0xd0, 0x07, 0xcf, 0xce, 0xcc, 0xc7, 0xb8,
+ 0x73, 0x37, 0x07, 0x8a, 0x00, 0x0f, 0x04, 0x2d, 0x65, 0xa4, 0xb8, 0xc1,
+ 0xc7, 0xcc, 0xce, 0xce, 0xcd, 0xcc, 0xcc, 0xcd, 0xce, 0xcf, 0xff, 0xd0,
+ 0xa7, 0xd0, 0x05, 0xcf, 0xcd, 0xca, 0xc3, 0x76, 0x12, 0x90, 0x00, 0x0c,
+ 0x11, 0x69, 0xac, 0xba, 0xc3, 0xc8, 0xca, 0xc7, 0x8f, 0xc4, 0xc7, 0xcc,
+ 0xce, 0xa3, 0xd0, 0x8b, 0xcf, 0x89, 0xd0, 0x89, 0xcf, 0xb9, 0xd0, 0x83,
+ 0xcf, 0x9a, 0xd0, 0x05, 0xcf, 0xcc, 0xc7, 0xb2, 0x45, 0x01, 0x92, 0x00,
+ 0x0c, 0x01, 0x37, 0x94, 0xb2, 0xbc, 0xbf, 0x64, 0x0a, 0xb3, 0xbd, 0xc6,
+ 0xcc, 0xcf, 0x9e, 0xd0, 0x04, 0xcf, 0xcf, 0xce, 0xcd, 0xcd, 0x89, 0xcc,
+ 0x03, 0xcd, 0xcd, 0xce, 0xcf, 0x82, 0xd0, 0x03, 0xcf, 0xcf, 0xce, 0xcd,
+ 0x88, 0xcc, 0x03, 0xcd, 0xcd, 0xce, 0xcf, 0x82, 0xd0, 0x06, 0xcf, 0xce,
+ 0xce, 0xcd, 0xce, 0xcf, 0xcf, 0xa9, 0xd0, 0x07, 0xcf, 0xcd, 0xcc, 0xcb,
+ 0xcb, 0xcc, 0xcd, 0xcf, 0x98, 0xd0, 0x04, 0xce, 0xcc, 0xc6, 0x8a, 0x1d,
+ 0x96, 0x00, 0x0a, 0x13, 0x69, 0xa4, 0x5d, 0x0d, 0x0a, 0x83, 0xad, 0xbf,
+ 0xca, 0xce, 0x9d, 0xd0, 0x05, 0xcf, 0xcd, 0xcb, 0xc8, 0xc6, 0xc4, 0x89,
+ 0xc3, 0x0d, 0xc5, 0xc6, 0xc9, 0xcc, 0xce, 0xcf, 0xd0, 0xd0, 0xcf, 0xcc,
+ 0xcb, 0xc7, 0xc6, 0xc4, 0x87, 0xc3, 0x10, 0xc5, 0xc6, 0xc9, 0xcc, 0xce,
+ 0xcf, 0xd0, 0xcf, 0xce, 0xcc, 0xca, 0xc7, 0xc6, 0xc8, 0xcc, 0xcd, 0xcf,
+ 0xa7, 0xd0, 0x09, 0xce, 0xcc, 0xc7, 0xbb, 0xb7, 0xbf, 0xc2, 0xc8, 0xcc,
+ 0xcf, 0x96, 0xd0, 0x04, 0xcf, 0xcc, 0xc5, 0x63, 0x06, 0x98, 0x00, 0x09,
+ 0x01, 0x29, 0x0a, 0x00, 0x00, 0x50, 0x9e, 0xb6, 0xc6, 0xcd, 0x9c, 0xd0,
+ 0x06, 0xcf, 0xcc, 0xc7, 0xad, 0x87, 0x76, 0x6e, 0x88, 0x6d, 0x0e, 0x6f,
+ 0x8b, 0xb3, 0xbc, 0xc4, 0xca, 0xce, 0xcf, 0xce, 0xcc, 0xc6, 0xa1, 0x83,
+ 0x73, 0x6e, 0x86, 0x6d, 0x12, 0x6e, 0x8a, 0xb2, 0xbc, 0xc3, 0xca, 0xcd,
+ 0xcf, 0xce, 0xcb, 0xc2, 0x8a, 0x69, 0x9e, 0xbb, 0xc2, 0xc9, 0xcd, 0xcf,
+ 0xa5, 0xd0, 0x0b, 0xcf, 0xcc, 0xb7, 0x41, 0x08, 0x06, 0x37, 0xae, 0xbc,
+ 0xc6, 0xcc, 0xcf, 0x94, 0xd0, 0x04, 0xcf, 0xcc, 0xc6, 0x79, 0x03, 0x88,
+ 0x00, 0x06, 0x04, 0x17, 0x24, 0x25, 0x23, 0x1a, 0x09, 0x87, 0x00, 0x01,
+ 0x07, 0x07, 0x80, 0x00, 0x05, 0x28, 0x90, 0xae, 0xc2, 0xcc, 0xcf, 0x9a,
+ 0xd0, 0x04, 0xcf, 0xcc, 0xc5, 0x4b, 0x03, 0x8d, 0x00, 0x08, 0x06, 0x81,
+ 0xb4, 0xc2, 0xcb, 0xcd, 0xcc, 0xba, 0x2e, 0x8c, 0x00, 0x08, 0x04, 0x77,
+ 0xb4, 0xc2, 0xcb, 0xcd, 0xcb, 0xa9, 0x11, 0x80, 0x00, 0x04, 0x6d, 0xb2,
+ 0xc0, 0xca, 0xce, 0xa4, 0xd0, 0x03, 0xcf, 0xcd, 0xc6, 0x56, 0x81, 0x00,
+ 0x04, 0x6a, 0xab, 0xc0, 0xca, 0xce, 0x93, 0xd0, 0x04, 0xcf, 0xcd, 0xc7,
+ 0x95, 0x0d, 0x86, 0x00, 0x0c, 0x12, 0x2d, 0x46, 0x66, 0x73, 0x7a, 0x7e,
+ 0x80, 0x7f, 0x7a, 0x5c, 0x35, 0x0d, 0x83, 0x00, 0x01, 0x04, 0x04, 0x81,
+ 0x00, 0x05, 0x17, 0x86, 0xa8, 0xc0, 0xcb, 0xcf, 0x9a, 0xd0, 0x02, 0xce,
+ 0xc9, 0x73, 0x90, 0x00, 0x06, 0x32, 0xa1, 0xb8, 0xc6, 0xcb, 0xc6, 0x48,
+ 0x8e, 0x00, 0x06, 0x2b, 0xa0, 0xb7, 0xc6, 0xcb, 0xc6, 0x4d, 0x81, 0x00,
+ 0x05, 0x25, 0x9e, 0xb5, 0xc6, 0xcd, 0xcf, 0xa3, 0xd0, 0x03, 0xcf, 0xcb,
+ 0xb3, 0x06, 0x81, 0x00, 0x05, 0x45, 0x9c, 0xb7, 0xc6, 0xce, 0xcf, 0x92,
+ 0xd0, 0x03, 0xce, 0xc9, 0xad, 0x1b, 0x85, 0x00, 0x10, 0x08, 0x35, 0x67,
+ 0x76, 0x84, 0x8e, 0x98, 0x9e, 0xa3, 0xa4, 0xa3, 0x9f, 0x99, 0x90, 0x81,
+ 0x47, 0x0b, 0x80, 0x00, 0x01, 0x04, 0x04, 0x82, 0x00, 0x05, 0x0e, 0x7e,
+ 0xa2, 0xbd, 0xca, 0xcf, 0x99, 0xd0, 0x03, 0xcf, 0xcc, 0xc4, 0x31, 0x90,
+ 0x00, 0x06, 0x1d, 0x93, 0xb0, 0xc2, 0xc8, 0xbe, 0x0d, 0x8e, 0x00, 0x06,
+ 0x19, 0x92, 0xaf, 0xc2, 0xc7, 0xb5, 0x06, 0x81, 0x00, 0x05, 0x17, 0x8d,
+ 0xab, 0xc2, 0xcc, 0xcf, 0xa3, 0xd0, 0x02, 0xce, 0xc8, 0x8a, 0x82, 0x00,
+ 0x05, 0x4d, 0x93, 0xb3, 0xc5, 0xcd, 0xcf, 0x91, 0xd0, 0x03, 0xcf, 0xcc,
+ 0xbe, 0x32, 0x84, 0x00, 0x16, 0x01, 0x21, 0x5a, 0x76, 0x88, 0x99, 0xa5,
+ 0xaf, 0xb6, 0xbb, 0xbd, 0xbf, 0xbe, 0xbb, 0xb7, 0xb0, 0xa5, 0x98, 0x77,
+ 0x24, 0x00, 0x04, 0x04, 0x83, 0x00, 0x05, 0x09, 0x6a, 0x9c, 0xb9, 0xc8,
+ 0xce, 0x99, 0xd0, 0x03, 0xcf, 0xcb, 0xbd, 0x07, 0x90, 0x00, 0x05, 0x42,
+ 0x91, 0xae, 0xc2, 0xc5, 0x98, 0x8f, 0x00, 0x05, 0x3f, 0x90, 0xad, 0xc1,
+ 0xc5, 0x8f, 0x82, 0x00, 0x05, 0x23, 0x85, 0xa7, 0xc0, 0xcb, 0xcf, 0xa2,
+ 0xd0, 0x03, 0xcf, 0xcd, 0xc5, 0x64, 0x82, 0x00, 0x05, 0x5d, 0x92, 0xb3,
+ 0xc5, 0xcd, 0xcf, 0x90, 0xd0, 0x03, 0xcf, 0xcd, 0xc6, 0x60, 0x84, 0x00,
+ 0x0a, 0x01, 0x37, 0x6a, 0x80, 0x95, 0xa7, 0xb4, 0xbe, 0xc3, 0xc6, 0xc9,
+ 0x80, 0xcb, 0x08, 0xca, 0xc7, 0xc4, 0xbe, 0xb3, 0xa3, 0x8c, 0x1e, 0x06,
+ 0x84, 0x00, 0x05, 0x01, 0x49, 0x95, 0xb4, 0xc6, 0xcd, 0x95, 0xd0, 0x00,
+ 0xcf, 0x80, 0xd0, 0x02, 0xce, 0xc8, 0xa0, 0x8d, 0x00, 0x09, 0x03, 0x15,
+ 0x2b, 0x4d, 0x82, 0x9b, 0xb4, 0xc3, 0xc3, 0x73, 0x8b, 0x00, 0x09, 0x03,
+ 0x15, 0x2b, 0x4d, 0x81, 0x9b, 0xb4, 0xc2, 0xc2, 0x6d, 0x82, 0x00, 0x05,
+ 0x34, 0x84, 0xa8, 0xc0, 0xcc, 0xcf, 0x89, 0xd0, 0x01, 0xcf, 0xcf, 0x94,
+ 0xd0, 0x03, 0xcf, 0xcc, 0xc2, 0x42, 0x81, 0x00, 0x05, 0x03, 0x6f, 0x95,
+ 0xb4, 0xc6, 0xcd, 0x91, 0xd0, 0x03, 0xcf, 0xcb, 0xbe, 0x1a, 0x84, 0x00,
+ 0x0a, 0x2f, 0x6d, 0x86, 0x9e, 0xb1, 0xbd, 0xc6, 0xca, 0xcc, 0xcd, 0xce,
+ 0x80, 0xcf, 0x07, 0xce, 0xce, 0xcc, 0xc8, 0xc1, 0xb2, 0x41, 0x08, 0x86,
+ 0x00, 0x05, 0x24, 0x8d, 0xae, 0xc2, 0xcc, 0xcf, 0x8a, 0xd0, 0x01, 0xcf,
+ 0xcf, 0x80, 0xce, 0x80, 0xcf, 0x00, 0xce, 0x80, 0xcd, 0x04, 0xce, 0xcf,
+ 0xcd, 0xc6, 0x7e, 0x82, 0x00, 0x04, 0x23, 0x5a, 0x66, 0x6f, 0x72, 0x83,
+ 0x73, 0x09, 0x76, 0x7a, 0x80, 0x8b, 0x9b, 0xae, 0xbf, 0xc6, 0xc2, 0x53,
+ 0x82, 0x00, 0x04, 0x35, 0x5d, 0x69, 0x70, 0x72, 0x81, 0x73, 0x09, 0x76,
+ 0x7a, 0x80, 0x8a, 0x9b, 0xae, 0xbf, 0xc6, 0xc1, 0x4c, 0x82, 0x00, 0x04,
+ 0x46, 0x88, 0xab, 0xc2, 0xcc, 0x80, 0xcf, 0x80, 0xce, 0x81, 0xcf, 0x01,
+ 0xce, 0xce, 0x81, 0xcd, 0x02, 0xce, 0xcf, 0xcf, 0x8c, 0xd0, 0x81, 0xcf,
+ 0x03, 0xcd, 0xc9, 0xbe, 0x21, 0x81, 0x00, 0x05, 0x11, 0x76, 0x9a, 0xb8,
+ 0xc8, 0xce, 0x91, 0xd0, 0x02, 0xcd, 0xc7, 0x74, 0x84, 0x00, 0x09, 0x25,
+ 0x6c, 0x86, 0xa1, 0xb4, 0xc2, 0xc9, 0xcc, 0xce, 0xcf, 0x83, 0xd0, 0x05,
+ 0xcf, 0xce, 0xcb, 0xc2, 0x42, 0x08, 0x87, 0x00, 0x05, 0x14, 0x84, 0xa7,
+ 0xc0, 0xcb, 0xcf, 0x89, 0xd0, 0x11, 0xcf, 0xcd, 0xcb, 0xc8, 0xc8, 0xc9,
+ 0xcb, 0xcc, 0xcb, 0xc8, 0xc6, 0xc5, 0xc6, 0xc9, 0xcc, 0xcb, 0xc3, 0x5c,
+ 0x82, 0x00, 0x05, 0x38, 0x6e, 0x83, 0x91, 0x97, 0x98, 0x82, 0x99, 0x09,
+ 0x9b, 0x9e, 0xa3, 0xab, 0xb4, 0xc0, 0xc7, 0xc9, 0xc0, 0x34, 0x82, 0x00,
+ 0x05, 0x4f, 0x73, 0x87, 0x93, 0x98, 0x98, 0x80, 0x99, 0x09, 0x9b, 0x9e,
+ 0xa3, 0xab, 0xb4, 0xc0, 0xc6, 0xc9, 0xc0, 0x2e, 0x82, 0x00, 0x0b, 0x5b,
+ 0x8e, 0xb0, 0xc4, 0xcc, 0xce, 0xcd, 0xcb, 0xc8, 0xc7, 0xc8, 0xcb, 0x80,
+ 0xcc, 0x09, 0xca, 0xc7, 0xc6, 0xc4, 0xc5, 0xc6, 0xc9, 0xcc, 0xcd, 0xcf,
+ 0x88, 0xd0, 0x0a, 0xcf, 0xcf, 0xce, 0xcd, 0xcc, 0xcb, 0xca, 0xc7, 0xc2,
+ 0xb3, 0x06, 0x81, 0x00, 0x05, 0x21, 0x7a, 0x9f, 0xbc, 0xca, 0xce, 0x90,
+ 0xd0, 0x03, 0xcf, 0xcc, 0xc2, 0x2e, 0x83, 0x00, 0x08, 0x11, 0x65, 0x82,
+ 0x9e, 0xb5, 0xc3, 0xcb, 0xce, 0xcf, 0x86, 0xd0, 0x03, 0xce, 0xc7, 0x3b,
+ 0x06, 0x88, 0x00, 0x05, 0x0b, 0x77, 0xa0, 0xbb, 0xc9, 0xce, 0x88, 0xd0,
+ 0x12, 0xcf, 0xcc, 0xc6, 0xa7, 0x79, 0xa9, 0xbc, 0xc0, 0xc2, 0xb4, 0x87,
+ 0x5d, 0x73, 0xa7, 0xbb, 0xc3, 0xc6, 0xc0, 0x3e, 0x82, 0x00, 0x05, 0x4e,
+ 0x7e, 0x98, 0xa9, 0xb0, 0xb2, 0x83, 0xb3, 0x08, 0xb5, 0xba, 0xbf, 0xc4,
+ 0xc9, 0xcc, 0xca, 0xbe, 0x17, 0x81, 0x00, 0x05, 0x03, 0x66, 0x84, 0x9e,
+ 0xab, 0xb1, 0x81, 0xb3, 0x09, 0xb4, 0xb5, 0xba, 0xbf, 0xc4, 0xc9, 0xcc,
+ 0xca, 0xbd, 0x11, 0x81, 0x00, 0x1b, 0x03, 0x6f, 0x94, 0xb4, 0xc6, 0xcc,
+ 0xcc, 0xc6, 0xa1, 0x71, 0x9b, 0xbb, 0xc0, 0xc4, 0xc5, 0xc2, 0xac, 0x86,
+ 0x63, 0x70, 0x8e, 0xac, 0xbb, 0xc1, 0xc6, 0xcc, 0xce, 0xcf, 0x84, 0xd0,
+ 0x0b, 0xcf, 0xcf, 0xcd, 0xcb, 0xc8, 0xc5, 0xc1, 0xbe, 0xbb, 0xab, 0x92,
+ 0x69, 0x82, 0x00, 0x05, 0x32, 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0x90, 0xd0,
+ 0x03, 0xce, 0xc8, 0x8e, 0x01, 0x83, 0x00, 0x07, 0x3b, 0x79, 0x98, 0xb2,
+ 0xc2, 0xcb, 0xce, 0xcf, 0x87, 0xd0, 0x08, 0xcd, 0xbc, 0x7a, 0x45, 0x23,
+ 0x17, 0x0d, 0x07, 0x01, 0x83, 0x00, 0x05, 0x03, 0x59, 0x9a, 0xb7, 0xc7,
+ 0xce, 0x87, 0xd0, 0x0a, 0xcf, 0xcc, 0xc6, 0x35, 0x00, 0x00, 0x03, 0x96,
+ 0xa8, 0x49, 0x01, 0x80, 0x00, 0x05, 0x03, 0x92, 0xb4, 0xbf, 0xbb, 0x1e,
+ 0x81, 0x00, 0x04, 0x01, 0x5c, 0x7c, 0x95, 0xa4, 0x83, 0xab, 0x0a, 0xac,
+ 0xb1, 0xb5, 0xbb, 0xc1, 0xc7, 0xcc, 0xcd, 0xc9, 0xb3, 0x01, 0x81, 0x00,
+ 0x04, 0x10, 0x65, 0x82, 0x9a, 0xa6, 0x81, 0xab, 0x09, 0xac, 0xb3, 0xb7,
+ 0xbc, 0xc2, 0xc8, 0xcc, 0xcd, 0xc9, 0xae, 0x82, 0x00, 0x07, 0x11, 0x76,
+ 0x9b, 0xb8, 0xc7, 0xcb, 0xc2, 0x25, 0x80, 0x00, 0x04, 0x60, 0xab, 0xb1,
+ 0x6d, 0x15, 0x82, 0x00, 0x06, 0x07, 0x53, 0xa7, 0xb8, 0xc3, 0xcb, 0xce,
+ 0x83, 0xd0, 0x09, 0xcf, 0xcd, 0xcb, 0xc6, 0xc0, 0x8d, 0x46, 0x29, 0x17,
+ 0x04, 0x85, 0x00, 0x05, 0x46, 0x87, 0xab, 0xc2, 0xcc, 0xcf, 0x8f, 0xd0,
+ 0x03, 0xcf, 0xcc, 0xc4, 0x46, 0x83, 0x00, 0x06, 0x11, 0x69, 0x8a, 0xa9,
+ 0xbf, 0xca, 0xce, 0x89, 0xd0, 0x15, 0xce, 0xc8, 0xbd, 0xab, 0x99, 0x8a,
+ 0x7e, 0x67, 0x4d, 0x2e, 0x19, 0x10, 0x09, 0x01, 0x00, 0x00, 0x32, 0x97,
+ 0xb3, 0xc6, 0xcd, 0xcf, 0x86, 0xd0, 0x02, 0xce, 0xc9, 0x89, 0x81, 0x00,
+ 0x01, 0x47, 0x22, 0x83, 0x00, 0x04, 0x47, 0xa3, 0xb4, 0xb2, 0x04, 0x8d,
+ 0x00, 0x08, 0x04, 0x25, 0x69, 0xb4, 0xc0, 0xc9, 0xcc, 0xc7, 0x92, 0x8c,
+ 0x00, 0x08, 0x0a, 0x2e, 0x82, 0xb6, 0xc2, 0xcb, 0xcc, 0xc7, 0x8d, 0x82,
+ 0x00, 0x06, 0x21, 0x7a, 0x9f, 0xbb, 0xc8, 0xc7, 0x7d, 0x81, 0x00, 0x02,
+ 0x1b, 0x6f, 0x1e, 0x86, 0x00, 0x05, 0x17, 0x98, 0xb4, 0xc2, 0xcb, 0xce,
+ 0x80, 0xd0, 0x06, 0xcf, 0xce, 0xcc, 0xc6, 0xb1, 0x64, 0x1a, 0x8a, 0x00,
+ 0x05, 0x5a, 0x8e, 0xaf, 0xc4, 0xcc, 0xcf, 0x8f, 0xd0, 0x03, 0xcf, 0xcb,
+ 0xc0, 0x1d, 0x83, 0x00, 0x06, 0x37, 0x7a, 0x9b, 0xb6, 0xc6, 0xcd, 0xcf,
+ 0x89, 0xd0, 0x15, 0xce, 0xcb, 0xc4, 0xbb, 0xb0, 0xa7, 0xa0, 0x9b, 0x95,
+ 0x8e, 0x86, 0x7f, 0x6f, 0x50, 0x2e, 0x1a, 0x27, 0x99, 0xb3, 0xc5, 0xcc,
+ 0xcf, 0x85, 0xd0, 0x03, 0xcf, 0xcd, 0xc4, 0x37, 0x89, 0x00, 0x03, 0x3a,
+ 0x97, 0xad, 0x94, 0x90, 0x00, 0x06, 0x09, 0x98, 0xb4, 0xc3, 0xca, 0xc5,
+ 0x70, 0x8e, 0x00, 0x06, 0x23, 0xa3, 0xb8, 0xc6, 0xcb, 0xc5, 0x6c, 0x82,
+ 0x00, 0x06, 0x34, 0x82, 0xa5, 0xbf, 0xc7, 0xc2, 0x2b, 0x81, 0x00, 0x01,
+ 0x01, 0x01, 0x88, 0x00, 0x0c, 0x35, 0x9f, 0xb6, 0xc6, 0xcc, 0xcf, 0xd0,
+ 0xcf, 0xce, 0xca, 0xc3, 0x60, 0x04, 0x8b, 0x00, 0x05, 0x03, 0x6f, 0x94,
+ 0xb4, 0xc6, 0xcd, 0x90, 0xd0, 0x03, 0xce, 0xc9, 0xa8, 0x03, 0x82, 0x00,
+ 0x06, 0x01, 0x5a, 0x87, 0xa9, 0xc0, 0xcb, 0xcf, 0x8a, 0xd0, 0x15, 0xcf,
+ 0xce, 0xcb, 0xc6, 0xc2, 0xbf, 0xbc, 0xb9, 0xb4, 0xaf, 0xa9, 0xa3, 0x9c,
+ 0x96, 0x8f, 0x8d, 0x94, 0xa5, 0xb9, 0xc6, 0xcd, 0xcf, 0x85, 0xd0, 0x03,
+ 0xcf, 0xcc, 0xc0, 0x13, 0x88, 0x00, 0x04, 0x04, 0x63, 0x95, 0xab, 0x74,
+ 0x91, 0x00, 0x05, 0x71, 0xa8, 0xbf, 0xc7, 0xc2, 0x4f, 0x8e, 0x00, 0x06,
+ 0x04, 0x91, 0xad, 0xc2, 0xc8, 0xc2, 0x4b, 0x82, 0x00, 0x06, 0x47, 0x88,
+ 0xab, 0xc1, 0xc6, 0xbd, 0x08, 0x8f, 0x00, 0x09, 0x71, 0xa8, 0xbf, 0xca,
+ 0xce, 0xcf, 0xce, 0xca, 0xbb, 0x3f, 0x8d, 0x00, 0x05, 0x11, 0x76, 0x9a,
+ 0xb8, 0xc8, 0xce, 0x90, 0xd0, 0x02, 0xce, 0xc7, 0x7f, 0x83, 0x00, 0x06,
+ 0x0d, 0x6f, 0x93, 0xb3, 0xc5, 0xcd, 0xcf, 0x8b, 0xd0, 0x13, 0xcf, 0xce,
+ 0xcd, 0xcc, 0xcb, 0xca, 0xc8, 0xc6, 0xc3, 0xc0, 0xbb, 0xb5, 0xaf, 0xa9,
+ 0xa5, 0xa9, 0xb4, 0xc0, 0xc9, 0xce, 0x86, 0xd0, 0x02, 0xce, 0xca, 0xb2,
+ 0x87, 0x00, 0x06, 0x07, 0x22, 0x57, 0x85, 0x9e, 0xae, 0x56, 0x90, 0x00,
+ 0x06, 0x09, 0x80, 0xa4, 0xbc, 0xc6, 0xc0, 0x31, 0x8e, 0x00, 0x06, 0x1e,
+ 0x8a, 0xab, 0xc0, 0xc6, 0xc0, 0x2d, 0x82, 0x00, 0x05, 0x5d, 0x8e, 0xaf,
+ 0xc2, 0xc6, 0xa2, 0x85, 0x00, 0x04, 0x12, 0x25, 0x35, 0x2e, 0x0d, 0x83,
+ 0x00, 0x08, 0x48, 0x9a, 0xb6, 0xc6, 0xcd, 0xce, 0xca, 0xb2, 0x24, 0x87,
+ 0x00, 0x01, 0x0a, 0x17, 0x82, 0x00, 0x05, 0x21, 0x7a, 0x9f, 0xbc, 0xca,
+ 0xcf, 0x8f, 0xd0, 0x03, 0xcf, 0xcd, 0xc5, 0x73, 0x83, 0x00, 0x05, 0x1d,
+ 0x76, 0x9b, 0xb9, 0xc8, 0xce, 0x8e, 0xd0, 0x81, 0xcf, 0x0d, 0xce, 0xcd,
+ 0xcc, 0xc8, 0xc3, 0xb7, 0x7a, 0x76, 0xab, 0xb0, 0xb9, 0xc3, 0xcb, 0xce,
+ 0x86, 0xd0, 0x02, 0xce, 0xc7, 0x8f, 0x83, 0x00, 0x0a, 0x14, 0x3c, 0x5c,
+ 0x6c, 0x74, 0x7e, 0x8a, 0x9e, 0xae, 0xb4, 0x39, 0x8e, 0x00, 0x08, 0x0d,
+ 0x24, 0x5a, 0x8d, 0xa9, 0xbf, 0xc5, 0xbd, 0x14, 0x8b, 0x00, 0x09, 0x01,
+ 0x12, 0x2a, 0x6c, 0x93, 0xaf, 0xc2, 0xc6, 0xbc, 0x11, 0x81, 0x00, 0x06,
+ 0x03, 0x6f, 0x95, 0xb4, 0xc4, 0xc4, 0x81, 0x83, 0x00, 0x07, 0x07, 0x3c,
+ 0x69, 0x76, 0x7e, 0x80, 0x76, 0x19, 0x82, 0x00, 0x07, 0x2d, 0x8e, 0xaf,
+ 0xc3, 0xcc, 0xcb, 0xc2, 0x32, 0x84, 0x00, 0x05, 0x0a, 0x34, 0x4c, 0x63,
+ 0x6d, 0x5b, 0x82, 0x00, 0x05, 0x32, 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0x8f,
+ 0xd0, 0x03, 0xcf, 0xcd, 0xc4, 0x6d, 0x83, 0x00, 0x05, 0x2b, 0x7e, 0xa1,
+ 0xbd, 0xca, 0xcf, 0x93, 0xd0, 0x0d, 0xcf, 0xcc, 0xc6, 0x5a, 0x1d, 0x03,
+ 0x04, 0x1e, 0x64, 0xaf, 0xbe, 0xc8, 0xcd, 0xcf, 0x85, 0xd0, 0x02, 0xcd,
+ 0xc6, 0x6f, 0x82, 0x00, 0x0b, 0x12, 0x5b, 0x72, 0x84, 0x91, 0x99, 0xa1,
+ 0xab, 0xb4, 0xbc, 0xb8, 0x1d, 0x81, 0x00, 0x04, 0x01, 0x44, 0x4f, 0x57,
+ 0x5b, 0x83, 0x5d, 0x0a, 0x5f, 0x69, 0x76, 0x7f, 0x8d, 0xa1, 0xb5, 0xc3,
+ 0xc6, 0xb0, 0x01, 0x81, 0x00, 0x04, 0x0e, 0x47, 0x50, 0x59, 0x5c, 0x81,
+ 0x5d, 0x09, 0x5f, 0x6e, 0x77, 0x82, 0x91, 0xa6, 0xba, 0xc6, 0xc6, 0xad,
+ 0x82, 0x00, 0x06, 0x12, 0x76, 0x9b, 0xb8, 0xc6, 0xc2, 0x60, 0x82, 0x00,
+ 0x08, 0x03, 0x4a, 0x70, 0x86, 0x97, 0xa0, 0xa2, 0x9b, 0x5f, 0x82, 0x00,
+ 0x06, 0x22, 0x88, 0xab, 0xc1, 0xc9, 0xc5, 0x5f, 0x83, 0x00, 0x07, 0x04,
+ 0x30, 0x64, 0x76, 0x83, 0x8c, 0x8e, 0x5d, 0x82, 0x00, 0x05, 0x46, 0x88,
+ 0xab, 0xc2, 0xcc, 0xcf, 0x8f, 0xd0, 0x03, 0xcf, 0xcc, 0xc3, 0x66, 0x83,
+ 0x00, 0x05, 0x2d, 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0x93, 0xd0, 0x03, 0xce,
+ 0xc9, 0x8d, 0x0a, 0x81, 0x00, 0x05, 0x11, 0x88, 0xb0, 0xc2, 0xcb, 0xcf,
+ 0x84, 0xd0, 0x03, 0xcf, 0xcc, 0xc3, 0x4f, 0x82, 0x00, 0x0b, 0x3b, 0x73,
+ 0x8e, 0xa3, 0xb0, 0xb7, 0xbc, 0xc1, 0xc5, 0xc4, 0xb5, 0x04, 0x81, 0x00,
+ 0x05, 0x0d, 0x60, 0x77, 0x89, 0x91, 0x93, 0x82, 0x94, 0x09, 0x95, 0x97,
+ 0x9b, 0xa1, 0xab, 0xb7, 0xc2, 0xc8, 0xc6, 0x8f, 0x82, 0x00, 0x05, 0x1e,
+ 0x66, 0x7c, 0x8a, 0x91, 0x93, 0x80, 0x94, 0x09, 0x95, 0x98, 0x9c, 0xa4,
+ 0xad, 0xba, 0xc4, 0xca, 0xc6, 0x8b, 0x82, 0x00, 0x06, 0x22, 0x7c, 0xa0,
+ 0xbb, 0xc6, 0xc1, 0x40, 0x82, 0x00, 0x08, 0x30, 0x6e, 0x8a, 0xa2, 0xb3,
+ 0xbb, 0xbb, 0xb3, 0x86, 0x82, 0x00, 0x06, 0x29, 0x85, 0xa8, 0xbf, 0xc5,
+ 0x92, 0x01, 0x82, 0x00, 0x08, 0x15, 0x57, 0x72, 0x86, 0x98, 0xa5, 0xab,
+ 0xab, 0x53, 0x82, 0x00, 0x05, 0x5b, 0x8e, 0xaf, 0xc4, 0xcc, 0xcf, 0x8f,
+ 0xd0, 0x03, 0xcf, 0xcc, 0xc2, 0x69, 0x83, 0x00, 0x05, 0x27, 0x82, 0xa6,
+ 0xc0, 0xcc, 0xcf, 0x92, 0xd0, 0x03, 0xcf, 0xcd, 0xc5, 0x2b, 0x83, 0x00,
+ 0x04, 0x44, 0xa0, 0xba, 0xc8, 0xce, 0x84, 0xd0, 0x03, 0xcf, 0xcc, 0xc0,
+ 0x31, 0x82, 0x00, 0x0a, 0x5d, 0x86, 0xa4, 0xb9, 0xc3, 0xc7, 0xca, 0xcc,
+ 0xcc, 0xc6, 0x9a, 0x82, 0x00, 0x04, 0x1b, 0x71, 0x8f, 0xa5, 0xb0, 0x84,
+ 0xb4, 0x08, 0xb6, 0xb9, 0xbc, 0xc1, 0xc6, 0xcb, 0xcc, 0xc5, 0x6e, 0x82,
+ 0x00, 0x04, 0x32, 0x77, 0x95, 0xa8, 0xb1, 0x81, 0xb4, 0x09, 0xb5, 0xb6,
+ 0xba, 0xbe, 0xc2, 0xc7, 0xcb, 0xcc, 0xc5, 0x6a, 0x82, 0x00, 0x06, 0x35,
+ 0x82, 0xa5, 0xbf, 0xc6, 0xbf, 0x22, 0x81, 0x00, 0x09, 0x03, 0x5f, 0x82,
+ 0xa0, 0xb7, 0xc3, 0xc8, 0xc7, 0xc0, 0x86, 0x82, 0x00, 0x05, 0x2f, 0x85,
+ 0xa8, 0xbd, 0xc0, 0x35, 0x82, 0x00, 0x09, 0x08, 0x59, 0x77, 0x90, 0xa4,
+ 0xb4, 0xbd, 0xc0, 0xb9, 0x3c, 0x81, 0x00, 0x05, 0x03, 0x6f, 0x94, 0xb4,
+ 0xc6, 0xcd, 0x90, 0xd0, 0x03, 0xcf, 0xcc, 0xc3, 0x70, 0x83, 0x00, 0x05,
+ 0x20, 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0x92, 0xd0, 0x03, 0xcf, 0xcc, 0xc0,
+ 0x15, 0x83, 0x00, 0x04, 0x3f, 0x96, 0xb4, 0xc6, 0xcd, 0x84, 0xd0, 0x03,
+ 0xcf, 0xcb, 0xbe, 0x15, 0x81, 0x00, 0x0b, 0x11, 0x70, 0x94, 0xb2, 0xc3,
+ 0xcc, 0xce, 0xcf, 0xcf, 0xcc, 0xc6, 0x79, 0x82, 0x00, 0x04, 0x2e, 0x7e,
+ 0x9e, 0xb7, 0xc2, 0x84, 0xc6, 0x08, 0xc7, 0xc8, 0xca, 0xcc, 0xcd, 0xce,
+ 0xcc, 0xc2, 0x4d, 0x82, 0x00, 0x04, 0x48, 0x86, 0xa5, 0xbb, 0xc3, 0x82,
+ 0xc6, 0x08, 0xc7, 0xc9, 0xca, 0xcc, 0xcd, 0xce, 0xcc, 0xc2, 0x4a, 0x82,
+ 0x00, 0x06, 0x48, 0x89, 0xab, 0xc1, 0xc6, 0xbb, 0x07, 0x81, 0x00, 0x09,
+ 0x1a, 0x71, 0x93, 0xb1, 0xc2, 0xcb, 0xcd, 0xcc, 0xc3, 0x77, 0x82, 0x00,
+ 0x05, 0x3f, 0x88, 0xa9, 0xbb, 0xa2, 0x01, 0x81, 0x00, 0x0a, 0x01, 0x46,
+ 0x76, 0x92, 0xab, 0xbb, 0xc4, 0xc9, 0xc7, 0xbd, 0x21, 0x81, 0x00, 0x05,
+ 0x11, 0x76, 0x9b, 0xb8, 0xc8, 0xce, 0x90, 0xd0, 0x03, 0xcf, 0xcc, 0xc4,
+ 0x79, 0x83, 0x00, 0x05, 0x18, 0x7e, 0xa2, 0xbd, 0xcb, 0xcf, 0x92, 0xd0,
+ 0x03, 0xce, 0xc9, 0xb8, 0x0d, 0x83, 0x00, 0x04, 0x63, 0x93, 0xb3, 0xc6,
+ 0xcd, 0x84, 0xd0, 0x03, 0xce, 0xc9, 0xb3, 0x01, 0x81, 0x00, 0x0b, 0x29,
+ 0x7a, 0x9e, 0xba, 0xc8, 0xce, 0xd0, 0xd0, 0xcf, 0xcc, 0xc3, 0x57, 0x82,
+ 0x00, 0x04, 0x41, 0x86, 0xa8, 0xc0, 0xca, 0x83, 0xcd, 0x80, 0xce, 0x81,
+ 0xcf, 0x02, 0xcc, 0xc0, 0x2e, 0x82, 0x00, 0x04, 0x5f, 0x8e, 0xaf, 0xc2,
+ 0xcb, 0x81, 0xcd, 0x80, 0xce, 0x06, 0xcf, 0xcf, 0xd0, 0xcf, 0xcc, 0xc0,
+ 0x2b, 0x82, 0x00, 0x05, 0x5f, 0x8f, 0xb0, 0xc2, 0xc6, 0xa1, 0x82, 0x00,
+ 0x09, 0x37, 0x7e, 0xa0, 0xbb, 0xc8, 0xce, 0xcf, 0xcc, 0xc3, 0x5d, 0x82,
+ 0x00, 0x04, 0x52, 0x8c, 0xab, 0xba, 0x52, 0x82, 0x00, 0x0a, 0x22, 0x6d,
+ 0x8b, 0xa8, 0xbc, 0xc7, 0xcc, 0xcd, 0xc9, 0xbb, 0x07, 0x81, 0x00, 0x05,
+ 0x21, 0x7a, 0xa0, 0xbc, 0xca, 0xcf, 0x90, 0xd0, 0x04, 0xcf, 0xcd, 0xc5,
+ 0x9b, 0x01, 0x82, 0x00, 0x05, 0x04, 0x6f, 0x9e, 0xba, 0xc9, 0xce, 0x92,
+ 0xd0, 0x02, 0xcd, 0xc7, 0x8b, 0x83, 0x00, 0x05, 0x0a, 0x71, 0x96, 0xb4,
+ 0xc6, 0xce, 0x84, 0xd0, 0x02, 0xce, 0xc7, 0x93, 0x82, 0x00, 0x0b, 0x42,
+ 0x84, 0xa7, 0xc0, 0xcb, 0xcf, 0xd0, 0xd0, 0xcf, 0xcc, 0xc1, 0x38, 0x82,
+ 0x00, 0x05, 0x56, 0x8d, 0xae, 0xc3, 0xcc, 0xcf, 0x88, 0xd0, 0x03, 0xcf,
+ 0xcb, 0xbe, 0x11, 0x81, 0x00, 0x06, 0x04, 0x70, 0x95, 0xb4, 0xc6, 0xcd,
+ 0xcf, 0x86, 0xd0, 0x03, 0xcf, 0xcb, 0xbd, 0x10, 0x81, 0x00, 0x06, 0x04,
+ 0x70, 0x95, 0xb4, 0xc4, 0xc4, 0x7f, 0x82, 0x00, 0x09, 0x4d, 0x87, 0xa9,
+ 0xc1, 0xcc, 0xcf, 0xcf, 0xcc, 0xc2, 0x40, 0x82, 0x00, 0x04, 0x67, 0x91,
+ 0xae, 0xb7, 0x21, 0x82, 0x00, 0x09, 0x3f, 0x7c, 0x9e, 0xb7, 0xc6, 0xcc,
+ 0xcf, 0xce, 0xc8, 0xa1, 0x82, 0x00, 0x05, 0x32, 0x82, 0xa5, 0xbf, 0xcb,
+ 0xcf, 0x91, 0xd0, 0x03, 0xce, 0xc6, 0xb5, 0x17, 0x83, 0x00, 0x05, 0x44,
+ 0x94, 0xb3, 0xc6, 0xcd, 0xcf, 0x90, 0xd0, 0x03, 0xcf, 0xcc, 0xc3, 0x53,
+ 0x83, 0x00, 0x05, 0x17, 0x76, 0x9b, 0xb9, 0xc8, 0xce, 0x84, 0xd0, 0x02,
+ 0xcd, 0xc6, 0x71, 0x82, 0x00, 0x0b, 0x59, 0x8c, 0xae, 0xc3, 0xcc, 0xcf,
+ 0xd0, 0xd0, 0xcf, 0xcb, 0xbf, 0x1a, 0x81, 0x00, 0x05, 0x01, 0x6a, 0x93,
+ 0xb3, 0xc6, 0xcd, 0x89, 0xd0, 0x02, 0xce, 0xc9, 0xaf, 0x82, 0x00, 0x05,
+ 0x14, 0x76, 0x9b, 0xb9, 0xc8, 0xce, 0x87, 0xd0, 0x02, 0xce, 0xc9, 0xac,
+ 0x82, 0x00, 0x06, 0x13, 0x76, 0x9b, 0xb8, 0xc6, 0xc2, 0x5f, 0x82, 0x00,
+ 0x09, 0x63, 0x8f, 0xb1, 0xc4, 0xcd, 0xcf, 0xcf, 0xcb, 0xc0, 0x24, 0x81,
+ 0x00, 0x05, 0x0a, 0x72, 0x97, 0xb2, 0xb5, 0x0a, 0x82, 0x00, 0x09, 0x5b,
+ 0x89, 0xab, 0xc0, 0xcb, 0xcf, 0xcf, 0xce, 0xc6, 0x80, 0x82, 0x00, 0x05,
+ 0x47, 0x88, 0xab, 0xc2, 0xcc, 0xcf, 0x91, 0xd0, 0x03, 0xce, 0xc9, 0xbb,
+ 0x3a, 0x83, 0x00, 0x05, 0x1e, 0x89, 0xab, 0xc0, 0xcb, 0xcf, 0x90, 0xd0,
+ 0x03, 0xce, 0xca, 0xb7, 0x14, 0x83, 0x00, 0x05, 0x25, 0x7e, 0xa2, 0xbd,
+ 0xcb, 0xcf, 0x83, 0xd0, 0x03, 0xcf, 0xcc, 0xc3, 0x52, 0x81, 0x00, 0x05,
+ 0x03, 0x6d, 0x93, 0xb4, 0xc6, 0xcd, 0x80, 0xd0, 0x03, 0xce, 0xca, 0xb7,
+ 0x03, 0x81, 0x00, 0x05, 0x0d, 0x73, 0x99, 0xb7, 0xc8, 0xce, 0x89, 0xd0,
+ 0x02, 0xce, 0xc7, 0x8c, 0x82, 0x00, 0x05, 0x24, 0x7c, 0xa1, 0xbc, 0xca,
+ 0xcf, 0x87, 0xd0, 0x02, 0xce, 0xc7, 0x8a, 0x82, 0x00, 0x06, 0x24, 0x7c,
+ 0xa0, 0xbb, 0xc6, 0xc1, 0x3f, 0x81, 0x00, 0x0a, 0x07, 0x71, 0x97, 0xb5,
+ 0xc7, 0xce, 0xd0, 0xcf, 0xca, 0xbc, 0x09, 0x81, 0x00, 0x04, 0x19, 0x79,
+ 0x9c, 0xb4, 0xa5, 0x82, 0x00, 0x0a, 0x08, 0x6d, 0x92, 0xb2, 0xc5, 0xcd,
+ 0xcf, 0xcf, 0xcd, 0xc4, 0x5f, 0x82, 0x00, 0x05, 0x5c, 0x8e, 0xb0, 0xc4,
+ 0xcc, 0xcf, 0x91, 0xd0, 0x03, 0xcf, 0xcb, 0xc0, 0x6e, 0x83, 0x00, 0x06,
+ 0x01, 0x58, 0x9e, 0xb8, 0xc6, 0xcd, 0xcf, 0x8e, 0xd0, 0x03, 0xcf, 0xcc,
+ 0xc5, 0x69, 0x84, 0x00, 0x05, 0x42, 0x86, 0xa9, 0xc1, 0xcc, 0xcf, 0x83,
+ 0xd0, 0x03, 0xcf, 0xcc, 0xc1, 0x34, 0x81, 0x00, 0x05, 0x11, 0x76, 0x9a,
+ 0xb8, 0xc8, 0xce, 0x80, 0xd0, 0x02, 0xce, 0xc8, 0x98, 0x82, 0x00, 0x05,
+ 0x1d, 0x7a, 0x9e, 0xbb, 0xc8, 0xcd, 0x86, 0xcf, 0x80, 0xd0, 0x02, 0xcd,
+ 0xc5, 0x6a, 0x82, 0x00, 0x05, 0x37, 0x82, 0xa6, 0xc0, 0xcc, 0xcf, 0x86,
+ 0xd0, 0x03, 0xcf, 0xcd, 0xc5, 0x69, 0x82, 0x00, 0x06, 0x35, 0x82, 0xa6,
+ 0xbf, 0xc6, 0xbf, 0x21, 0x81, 0x00, 0x09, 0x18, 0x77, 0x9c, 0xba, 0xc9,
+ 0xce, 0xd0, 0xce, 0xc8, 0xa5, 0x82, 0x00, 0x04, 0x2a, 0x7e, 0xa1, 0xb6,
+ 0x95, 0x82, 0x00, 0x0a, 0x06, 0x70, 0x95, 0xb4, 0xc6, 0xcd, 0xcf, 0xce,
+ 0xcc, 0xc1, 0x40, 0x81, 0x00, 0x05, 0x03, 0x6f, 0x95, 0xb4, 0xc6, 0xcd,
+ 0x92, 0xd0, 0x04, 0xcf, 0xcc, 0xc3, 0xab, 0x10, 0x83, 0x00, 0x05, 0x17,
+ 0x8b, 0xab, 0xc0, 0xca, 0xce, 0x8e, 0xd0, 0x03, 0xce, 0xc9, 0xa9, 0x12,
+ 0x83, 0x00, 0x06, 0x0b, 0x6d, 0x91, 0xb1, 0xc4, 0xcd, 0xcf, 0x83, 0xd0,
+ 0x03, 0xcf, 0xcb, 0xbe, 0x18, 0x81, 0x00, 0x05, 0x21, 0x7a, 0x9f, 0xbc,
+ 0xca, 0xce, 0x80, 0xd0, 0x02, 0xcd, 0xc6, 0x76, 0x82, 0x00, 0x05, 0x2d,
+ 0x7d, 0x9f, 0xba, 0xc6, 0xca, 0x83, 0xcb, 0x08, 0xcc, 0xcc, 0xcd, 0xce,
+ 0xcf, 0xcf, 0xcc, 0xc2, 0x4a, 0x82, 0x00, 0x05, 0x4a, 0x89, 0xab, 0xc2,
+ 0xcc, 0xcf, 0x86, 0xd0, 0x03, 0xcf, 0xcc, 0xc2, 0x49, 0x82, 0x00, 0x06,
+ 0x4a, 0x89, 0xab, 0xc1, 0xc6, 0xbb, 0x07, 0x81, 0x00, 0x09, 0x28, 0x7e,
+ 0xa2, 0xbd, 0xcb, 0xcf, 0xd0, 0xce, 0xc6, 0x84, 0x82, 0x00, 0x05, 0x3e,
+ 0x85, 0xa7, 0xb9, 0xb1, 0x04, 0x82, 0x00, 0x09, 0x5c, 0x91, 0xb0, 0xc2,
+ 0xc9, 0xcc, 0xcc, 0xc7, 0xbc, 0x23, 0x81, 0x00, 0x05, 0x11, 0x76, 0x9b,
+ 0xb8, 0xc8, 0xce, 0x93, 0xd0, 0x03, 0xcd, 0xc7, 0xb8, 0x42, 0x84, 0x00,
+ 0x05, 0x3c, 0x99, 0xb3, 0xc3, 0xcb, 0xce, 0x8b, 0xd0, 0x04, 0xcf, 0xce,
+ 0xcb, 0xc2, 0x3f, 0x84, 0x00, 0x05, 0x2a, 0x7a, 0x9c, 0xb9, 0xc8, 0xce,
+ 0x84, 0xd0, 0x03, 0xce, 0xc9, 0xb4, 0x01, 0x81, 0x00, 0x0b, 0x32, 0x82,
+ 0xa5, 0xbf, 0xcb, 0xcf, 0xd0, 0xd0, 0xcf, 0xcc, 0xc3, 0x55, 0x82, 0x00,
+ 0x05, 0x3c, 0x7c, 0x9b, 0xb1, 0xbb, 0xbe, 0x82, 0xbf, 0x09, 0xc0, 0xc0,
+ 0xc2, 0xc6, 0xca, 0xcd, 0xce, 0xcc, 0xc0, 0x2b, 0x82, 0x00, 0x05, 0x60,
+ 0x8f, 0xb1, 0xc4, 0xcd, 0xcf, 0x86, 0xd0, 0x03, 0xcf, 0xcc, 0xc0, 0x2a,
+ 0x82, 0x00, 0x05, 0x60, 0x8f, 0xb0, 0xc3, 0xc6, 0xa0, 0x82, 0x00, 0x09,
+ 0x3b, 0x84, 0xa8, 0xc0, 0xcc, 0xcf, 0xcf, 0xcd, 0xc5, 0x64, 0x82, 0x00,
+ 0x05, 0x52, 0x8b, 0xab, 0xbc, 0xb6, 0x24, 0x82, 0x00, 0x09, 0x10, 0x76,
+ 0xa0, 0xb4, 0xbd, 0xc1, 0xc2, 0xbe, 0xb3, 0x08, 0x81, 0x00, 0x05, 0x21,
+ 0x7a, 0xa0, 0xbc, 0xca, 0xcf, 0x93, 0xd0, 0x04, 0xcf, 0xcb, 0xc0, 0x97,
+ 0x0a, 0x83, 0x00, 0x07, 0x01, 0x4f, 0xa0, 0xb6, 0xc4, 0xcb, 0xce, 0xcf,
+ 0x88, 0xd0, 0x05, 0xcf, 0xce, 0xcb, 0xc2, 0x5d, 0x01, 0x83, 0x00, 0x06,
+ 0x07, 0x5d, 0x89, 0xa9, 0xc0, 0xcb, 0xcf, 0x84, 0xd0, 0x02, 0xce, 0xc7,
+ 0x96, 0x82, 0x00, 0x0b, 0x47, 0x88, 0xab, 0xc2, 0xcc, 0xcf, 0xd0, 0xd0,
+ 0xcf, 0xcc, 0xc1, 0x37, 0x82, 0x00, 0x04, 0x17, 0x28, 0x2f, 0x35, 0x37,
+ 0x83, 0x38, 0x09, 0x39, 0x52, 0x81, 0xb3, 0xc0, 0xc7, 0xcc, 0xca, 0xbd,
+ 0x0e, 0x81, 0x00, 0x05, 0x04, 0x71, 0x96, 0xb5, 0xc6, 0xce, 0x87, 0xd0,
+ 0x03, 0xcf, 0xcb, 0xbd, 0x0e, 0x81, 0x00, 0x06, 0x04, 0x71, 0x96, 0xb4,
+ 0xc5, 0xc4, 0x7e, 0x82, 0x00, 0x09, 0x4f, 0x8a, 0xac, 0xc2, 0xcc, 0xcf,
+ 0xcf, 0xcc, 0xc2, 0x46, 0x82, 0x00, 0x05, 0x69, 0x92, 0xb1, 0xc0, 0xbb,
+ 0x48, 0x83, 0x00, 0x07, 0x01, 0x25, 0x4d, 0x5f, 0x6d, 0x6d, 0x66, 0x53,
+ 0x82, 0x00, 0x05, 0x34, 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0x93, 0xd0, 0x04,
+ 0xcf, 0xcd, 0xc5, 0xb4, 0x4d, 0x84, 0x00, 0x08, 0x04, 0x59, 0xa2, 0xb6,
+ 0xc2, 0xca, 0xcd, 0xcf, 0xcf, 0x84, 0xd0, 0x06, 0xcf, 0xce, 0xcd, 0xc9,
+ 0xc2, 0x60, 0x01, 0x84, 0x00, 0x06, 0x31, 0x77, 0x99, 0xb4, 0xc6, 0xcd,
+ 0xcf, 0x84, 0xd0, 0x02, 0xcd, 0xc6, 0x76, 0x82, 0x00, 0x0b, 0x5d, 0x8e,
+ 0xb0, 0xc4, 0xcc, 0xcf, 0xd0, 0xd0, 0xcf, 0xcb, 0xbf, 0x19, 0x90, 0x00,
+ 0x05, 0x59, 0xae, 0xbf, 0xc8, 0xc7, 0xab, 0x82, 0x00, 0x05, 0x15, 0x76,
+ 0x9c, 0xba, 0xc8, 0xce, 0x87, 0xd0, 0x02, 0xce, 0xc9, 0xab, 0x82, 0x00,
+ 0x06, 0x15, 0x76, 0x9c, 0xb9, 0xc6, 0xc3, 0x5d, 0x82, 0x00, 0x09, 0x66,
+ 0x91, 0xb2, 0xc5, 0xcd, 0xcf, 0xcf, 0xcc, 0xc0, 0x29, 0x81, 0x00, 0x06,
+ 0x0a, 0x73, 0x98, 0xb5, 0xc3, 0xc0, 0x7c, 0x90, 0x00, 0x05, 0x48, 0x88,
+ 0xab, 0xc2, 0xcc, 0xcf, 0x94, 0xd0, 0x04, 0xce, 0xca, 0xbf, 0x9f, 0x19,
+ 0x84, 0x00, 0x08, 0x01, 0x3e, 0x9c, 0xb3, 0xbf, 0xc6, 0xcb, 0xcd, 0xce,
+ 0x82, 0xcf, 0x06, 0xce, 0xcc, 0xca, 0xc6, 0xb1, 0x42, 0x01, 0x84, 0x00,
+ 0x06, 0x10, 0x67, 0x8a, 0xa9, 0xbf, 0xca, 0xce, 0x84, 0xd0, 0x03, 0xcf,
+ 0xcc, 0xc4, 0x56, 0x81, 0x00, 0x05, 0x04, 0x71, 0x96, 0xb5, 0xc6, 0xcd,
+ 0x80, 0xd0, 0x03, 0xcf, 0xca, 0xbd, 0x07, 0x90, 0x00, 0x05, 0x18, 0x9b,
+ 0xb4, 0xc3, 0xc5, 0x8c, 0x82, 0x00, 0x05, 0x28, 0x7f, 0xa3, 0xbe, 0xca,
+ 0xcf, 0x87, 0xd0, 0x02, 0xce, 0xc8, 0x8c, 0x82, 0x00, 0x06, 0x29, 0x7f,
+ 0xa3, 0xbd, 0xc6, 0xc2, 0x3f, 0x81, 0x00, 0x0a, 0x09, 0x73, 0x98, 0xb7,
+ 0xc7, 0xce, 0xd0, 0xcf, 0xcb, 0xbe, 0x0e, 0x81, 0x00, 0x07, 0x1a, 0x7a,
+ 0x9e, 0xbb, 0xc6, 0xc3, 0xb3, 0x2f, 0x8f, 0x00, 0x05, 0x5d, 0x8f, 0xb1,
+ 0xc4, 0xcd, 0xcf, 0x94, 0xd0, 0x05, 0xcf, 0xcc, 0xc6, 0xb6, 0x83, 0x0e,
+ 0x85, 0x00, 0x07, 0x1e, 0x66, 0xa9, 0xb6, 0xc0, 0xc5, 0xc8, 0xca, 0x80,
+ 0xcb, 0x05, 0xca, 0xc7, 0xc4, 0xbe, 0x77, 0x19, 0x85, 0x00, 0x07, 0x04,
+ 0x4e, 0x7e, 0x9e, 0xb6, 0xc6, 0xcd, 0xcf, 0x84, 0xd0, 0x03, 0xcf, 0xcc,
+ 0xc3, 0x48, 0x81, 0x00, 0x05, 0x25, 0x7a, 0x9e, 0xbb, 0xc9, 0xce, 0x80,
+ 0xd0, 0x03, 0xcf, 0xca, 0xbd, 0x0e, 0x90, 0x00, 0x05, 0x21, 0x8f, 0xad,
+ 0xc1, 0xc3, 0x85, 0x82, 0x00, 0x05, 0x54, 0x89, 0xab, 0xc1, 0xcc, 0xcf,
+ 0x87, 0xd0, 0x02, 0xce, 0xc7, 0x82, 0x82, 0x00, 0x06, 0x55, 0x89, 0xab,
+ 0xc1, 0xc7, 0xc1, 0x37, 0x81, 0x00, 0x0a, 0x2b, 0x7e, 0xa0, 0xbc, 0xca,
+ 0xcf, 0xd0, 0xcf, 0xcb, 0xbd, 0x08, 0x81, 0x00, 0x08, 0x3f, 0x84, 0xa7,
+ 0xbf, 0xc9, 0xc8, 0xbd, 0x99, 0x1d, 0x8d, 0x00, 0x05, 0x0e, 0x74, 0x98,
+ 0xb6, 0xc6, 0xce, 0x96, 0xd0, 0x05, 0xce, 0xcb, 0xc2, 0xb0, 0x73, 0x08,
+ 0x86, 0x00, 0x0c, 0x1a, 0x57, 0x99, 0xb3, 0xb8, 0xbc, 0xbe, 0xbf, 0xbe,
+ 0xbc, 0x97, 0x63, 0x1d, 0x87, 0x00, 0x06, 0x37, 0x76, 0x93, 0xae, 0xc1,
+ 0xcb, 0xcf, 0x85, 0xd0, 0x03, 0xcf, 0xcc, 0xc3, 0x7c, 0x81, 0x00, 0x05,
+ 0x58, 0x89, 0xa9, 0xc0, 0xcb, 0xcf, 0x80, 0xd0, 0x03, 0xcf, 0xcb, 0xbf,
+ 0x48, 0x8f, 0x00, 0x07, 0x03, 0x5b, 0x91, 0xae, 0xc1, 0xc4, 0xb4, 0x0a,
+ 0x80, 0x00, 0x05, 0x15, 0x76, 0x96, 0xb3, 0xc5, 0xcd, 0x88, 0xd0, 0x03,
+ 0xce, 0xc7, 0xb0, 0x07, 0x80, 0x00, 0x07, 0x17, 0x76, 0x96, 0xb3, 0xc5,
+ 0xc9, 0xc2, 0x6d, 0x80, 0x00, 0x0b, 0x01, 0x5f, 0x8b, 0xab, 0xc1, 0xcc,
+ 0xcf, 0xd0, 0xcf, 0xcb, 0xbf, 0x3f, 0x80, 0x00, 0x0b, 0x09, 0x70, 0x92,
+ 0xb0, 0xc3, 0xcc, 0xcc, 0xc5, 0xb4, 0x98, 0x3f, 0x0d, 0x8b, 0x00, 0x05,
+ 0x40, 0x83, 0xa4, 0xbd, 0xca, 0xcf, 0x97, 0xd0, 0x05, 0xce, 0xc9, 0xbe,
+ 0xab, 0x63, 0x04, 0x87, 0x00, 0x07, 0x03, 0x13, 0x28, 0x3f, 0x44, 0x3e,
+ 0x35, 0x18, 0x89, 0x00, 0x06, 0x29, 0x70, 0x8c, 0xa8, 0xbd, 0xc8, 0xcd,
+ 0x86, 0xd0, 0x0d, 0xcf, 0xcd, 0xc6, 0xb3, 0x4a, 0x11, 0x1e, 0x4c, 0x81,
+ 0x9b, 0xb4, 0xc6, 0xcd, 0xcf, 0x80, 0xd0, 0x07, 0xcf, 0xcc, 0xc3, 0xaf,
+ 0x63, 0x3c, 0x21, 0x11, 0x89, 0x0e, 0x12, 0x17, 0x29, 0x5f, 0x83, 0x9e,
+ 0xb6, 0xc5, 0xc7, 0xbd, 0x76, 0x2b, 0x0d, 0x1e, 0x62, 0x8a, 0xa6, 0xbd,
+ 0xc9, 0xce, 0x88, 0xd0, 0x32, 0xce, 0xc9, 0xbd, 0x6e, 0x24, 0x0d, 0x21,
+ 0x63, 0x8a, 0xa6, 0xbd, 0xc9, 0xcc, 0xc5, 0xab, 0x46, 0x0e, 0x21, 0x4f,
+ 0x82, 0x9e, 0xb6, 0xc6, 0xcd, 0xd0, 0xd0, 0xcf, 0xcc, 0xc2, 0x9a, 0x3f,
+ 0x13, 0x2b, 0x5c, 0x87, 0xa3, 0xbb, 0xc8, 0xcd, 0xce, 0xcb, 0xc2, 0xb4,
+ 0xa0, 0x8c, 0x60, 0x35, 0x28, 0x1e, 0x19, 0x13, 0x83, 0x0e, 0x07, 0x1d,
+ 0x44, 0x7a, 0x96, 0xb1, 0xc3, 0xcc, 0xcf, 0x97, 0xd0, 0x06, 0xcf, 0xcd,
+ 0xc7, 0xbb, 0xa8, 0x55, 0x01, 0x99, 0x00, 0x07, 0x2a, 0x6d, 0x88, 0xa3,
+ 0xb9, 0xc6, 0xcc, 0xcf, 0x87, 0xd0, 0x0b, 0xce, 0xca, 0xbf, 0xac, 0x99,
+ 0x8d, 0x8e, 0x9b, 0xaf, 0xc0, 0xca, 0xce, 0x82, 0xd0, 0x07, 0xce, 0xc8,
+ 0xbd, 0xab, 0x9a, 0x8b, 0x82, 0x7e, 0x88, 0x7a, 0x12, 0x7d, 0x82, 0x8e,
+ 0x9e, 0xb2, 0xc1, 0xca, 0xcb, 0xc3, 0xb4, 0x9f, 0x8e, 0x89, 0x90, 0xa2,
+ 0xb6, 0xc5, 0xcc, 0xcf, 0x88, 0xd0, 0x17, 0xcf, 0xcc, 0xc3, 0xb3, 0x9e,
+ 0x8e, 0x88, 0x90, 0xa2, 0xb6, 0xc5, 0xcc, 0xcd, 0xc9, 0xbe, 0xab, 0x98,
+ 0x8c, 0x8e, 0x9e, 0xb1, 0xc1, 0xcb, 0xce, 0x80, 0xd0, 0x18, 0xcd, 0xc7,
+ 0xbb, 0xa7, 0x95, 0x8d, 0x92, 0xa0, 0xb4, 0xc3, 0xcc, 0xcf, 0xcf, 0xce,
+ 0xca, 0xc3, 0xb9, 0xab, 0x9e, 0x93, 0x8a, 0x85, 0x81, 0x7e, 0x7c, 0x82,
+ 0x7a, 0x06, 0x7f, 0x89, 0x98, 0xab, 0xbe, 0xc9, 0xce, 0x99, 0xd0, 0x06,
+ 0xcf, 0xcc, 0xc6, 0xba, 0xa5, 0x4f, 0x08, 0x96, 0x00, 0x08, 0x03, 0x2f,
+ 0x69, 0x85, 0xa0, 0xb6, 0xc4, 0xcc, 0xcf, 0x88, 0xd0, 0x0b, 0xcf, 0xcd,
+ 0xc7, 0xbe, 0xb3, 0xab, 0xac, 0xb4, 0xc0, 0xc8, 0xcd, 0xcf, 0x82, 0xd0,
+ 0x08, 0xcf, 0xcc, 0xc7, 0xbf, 0xb4, 0xab, 0xa6, 0xa2, 0xa0, 0x86, 0x9e,
+ 0x12, 0x9f, 0xa1, 0xa5, 0xac, 0xb7, 0xc2, 0xc9, 0xcd, 0xcd, 0xca, 0xc2,
+ 0xb6, 0xac, 0xa9, 0xae, 0xb8, 0xc3, 0xcb, 0xce, 0x89, 0xd0, 0x17, 0xcf,
+ 0xce, 0xca, 0xc1, 0xb5, 0xac, 0xa9, 0xae, 0xb8, 0xc3, 0xcb, 0xce, 0xcf,
+ 0xcc, 0xc6, 0xbd, 0xb3, 0xab, 0xad, 0xb5, 0xc0, 0xc9, 0xcd, 0xcf, 0x80,
+ 0xd0, 0x19, 0xcf, 0xcc, 0xc5, 0xbb, 0xb1, 0xab, 0xaf, 0xb8, 0xc2, 0xca,
+ 0xce, 0xd0, 0xd0, 0xcf, 0xce, 0xcc, 0xc6, 0xc1, 0xba, 0xb3, 0xac, 0xa8,
+ 0xa4, 0xa3, 0xa1, 0x9f, 0x80, 0x9e, 0x07, 0xa0, 0xa4, 0xa9, 0xb3, 0xbf,
+ 0xc7, 0xcc, 0xcf, 0x9a, 0xd0, 0x07, 0xcf, 0xcc, 0xc6, 0xb9, 0xa5, 0x7a,
+ 0x29, 0x01, 0x93, 0x00, 0x08, 0x04, 0x0b, 0x5d, 0x7a, 0x9a, 0xb3, 0xc3,
+ 0xcb, 0xce, 0x8a, 0xd0, 0x09, 0xcf, 0xcc, 0xc9, 0xc4, 0xc2, 0xc2, 0xc6,
+ 0xca, 0xcd, 0xcf, 0x84, 0xd0, 0x08, 0xcf, 0xcc, 0xca, 0xc6, 0xc2, 0xc0,
+ 0xbd, 0xbc, 0xbc, 0x84, 0xbb, 0x13, 0xbc, 0xbc, 0xbd, 0xbf, 0xc2, 0xc6,
+ 0xcb, 0xcd, 0xcf, 0xcf, 0xcd, 0xcb, 0xc6, 0xc2, 0xc1, 0xc2, 0xc6, 0xcb,
+ 0xce, 0xcf, 0x8a, 0xd0, 0x15, 0xcf, 0xcd, 0xca, 0xc6, 0xc2, 0xc0, 0xc2,
+ 0xc6, 0xcb, 0xce, 0xcf, 0xd0, 0xcf, 0xcc, 0xc8, 0xc4, 0xc2, 0xc2, 0xc6,
+ 0xca, 0xcd, 0xcf, 0x81, 0xd0, 0x0a, 0xcf, 0xce, 0xcc, 0xc7, 0xc3, 0xc2,
+ 0xc3, 0xc6, 0xcb, 0xce, 0xcf, 0x81, 0xd0, 0x09, 0xcf, 0xcd, 0xcc, 0xc8,
+ 0xc5, 0xc2, 0xc0, 0xbf, 0xbe, 0xbd, 0x82, 0xbc, 0x05, 0xbe, 0xc1, 0xc5,
+ 0xc9, 0xcd, 0xcf, 0x9c, 0xd0, 0x07, 0xcf, 0xcc, 0xc5, 0xba, 0xab, 0x96,
+ 0x5a, 0x15, 0x90, 0x00, 0x0a, 0x01, 0x03, 0x00, 0x01, 0x31, 0x84, 0xa4,
+ 0xbc, 0xc8, 0xcd, 0xcf, 0x8b, 0xd0, 0x09, 0xcf, 0xce, 0xcc, 0xcc, 0xca,
+ 0xcb, 0xcc, 0xcc, 0xce, 0xcf, 0x99, 0xd0, 0x0d, 0xcf, 0xce, 0xcd, 0xcd,
+ 0xce, 0xcf, 0xd0, 0xd0, 0xcf, 0xce, 0xcd, 0xcd, 0xce, 0xcf, 0xe8, 0xd0,
+ 0x08, 0xcf, 0xcc, 0xc6, 0xbf, 0xb2, 0xa1, 0x8a, 0x3f, 0x0a, 0x8c, 0x00,
+ 0x01, 0x04, 0x04, 0x81, 0x00, 0x05, 0x0d, 0x76, 0xa1, 0xbb, 0xc8, 0xce,
+ 0x8b, 0xd0, 0x0b, 0xcf, 0xce, 0xca, 0xc5, 0xc0, 0xbe, 0xbe, 0xc0, 0xc5,
+ 0xca, 0xcd, 0xcf, 0x8f, 0xd0, 0x01, 0xcf, 0xcf, 0x83, 0xd0, 0x0f, 0xcf,
+ 0xcd, 0xcb, 0xc7, 0xc6, 0xc9, 0xcc, 0xce, 0xce, 0xcc, 0xc9, 0xc6, 0xc6,
+ 0xca, 0xcd, 0xcf, 0xc7, 0xd0, 0x00, 0xcf, 0x9d, 0xd0, 0x0a, 0xcf, 0xcc,
+ 0xc9, 0xc3, 0xba, 0xab, 0x9b, 0x86, 0x50, 0x29, 0x0b, 0x85, 0x00, 0x03,
+ 0x03, 0x11, 0x22, 0x0e, 0x84, 0x00, 0x05, 0x25, 0x94, 0xb2, 0xc3, 0xcc,
+ 0xcf, 0x8a, 0xd0, 0x0c, 0xce, 0xcb, 0x76, 0x04, 0x04, 0x08, 0x1e, 0x6d,
+ 0xb4, 0xc0, 0xc8, 0xcd, 0xcf, 0x8c, 0xd0, 0x05, 0xcf, 0xce, 0xcd, 0xcd,
+ 0xce, 0xcf, 0x81, 0xd0, 0x0f, 0xce, 0xca, 0x7a, 0x08, 0xb0, 0xbf, 0xc6,
+ 0xcc, 0xcc, 0xc5, 0x1e, 0x3c, 0xba, 0xc1, 0xc9, 0xce, 0xc4, 0xd0, 0x06,
+ 0xcf, 0xcf, 0xce, 0xcd, 0xce, 0xcf, 0xcf, 0x9b, 0xd0, 0x0c, 0xcf, 0xce,
+ 0xcc, 0xc7, 0xc0, 0xb6, 0xab, 0x9c, 0x8f, 0x84, 0x6d, 0x52, 0x3f, 0x80,
+ 0x3a, 0x06, 0x3c, 0x4a, 0x66, 0x72, 0x76, 0x4f, 0x06, 0x83, 0x00, 0x05,
+ 0x08, 0x66, 0xa3, 0xbb, 0xc8, 0xce, 0x89, 0xd0, 0x0d, 0xcf, 0xcd, 0xc6,
+ 0x59, 0x00, 0x0d, 0x08, 0x00, 0x00, 0x76, 0xb1, 0xc1, 0xca, 0xce, 0x8b,
+ 0xd0, 0x1b, 0xcf, 0xcc, 0xca, 0xc7, 0xc7, 0xcb, 0xcd, 0xcf, 0xd0, 0xd0,
+ 0xcf, 0xcc, 0xc4, 0x2b, 0x00, 0x76, 0xaf, 0xbe, 0xc7, 0xc6, 0x7e, 0x00,
+ 0x1b, 0xa6, 0xb5, 0xc4, 0xcc, 0xcf, 0xc2, 0xd0, 0x08, 0xcf, 0xce, 0xcc,
+ 0xc9, 0xc7, 0xc8, 0xcc, 0xce, 0xcf, 0x9c, 0xd0, 0x0b, 0xcf, 0xcd, 0xcb,
+ 0xc6, 0xc0, 0xb8, 0xaf, 0xa7, 0x9e, 0x98, 0x91, 0x8d, 0x80, 0x8a, 0x05,
+ 0x8d, 0x92, 0x97, 0x98, 0x92, 0x25, 0x84, 0x00, 0x05, 0x19, 0x90, 0xad,
+ 0xc1, 0xcb, 0xcf, 0x88, 0xd0, 0x0d, 0xcf, 0xcc, 0xc3, 0x3f, 0x00, 0x6a,
+ 0x7d, 0x3e, 0x00, 0x3c, 0xa2, 0xb8, 0xc6, 0xcd, 0x81, 0xcf, 0x83, 0xd0,
+ 0x81, 0xcf, 0x1c, 0xcc, 0xc0, 0x24, 0x50, 0xbd, 0xc3, 0xcb, 0xce, 0xd0,
+ 0xd0, 0xce, 0xc9, 0xa3, 0x00, 0x00, 0x44, 0x9e, 0xb4, 0xc1, 0xc0, 0x22,
+ 0x00, 0x04, 0x93, 0xa9, 0xbf, 0xcb, 0xcf, 0xd0, 0x82, 0xcf, 0x80, 0xd0,
+ 0x81, 0xcf, 0x83, 0xd0, 0x82, 0xcf, 0x82, 0xd0, 0x82, 0xcf, 0x81, 0xd0,
+ 0x80, 0xcf, 0x81, 0xd0, 0x85, 0xcf, 0x82, 0xd0, 0x80, 0xcf, 0x81, 0xd0,
+ 0x81, 0xcf, 0x08, 0xce, 0xcc, 0x93, 0x23, 0x7a, 0xbf, 0xc6, 0xcc, 0xcf,
+ 0x9d, 0xd0, 0x14, 0xcf, 0xcf, 0xcd, 0xcb, 0xc7, 0xc3, 0xc0, 0xbb, 0xb5,
+ 0xb2, 0xae, 0xac, 0xab, 0xac, 0xaf, 0xb3, 0xb5, 0xb5, 0xae, 0x88, 0x0e,
+ 0x83, 0x00, 0x06, 0x03, 0x48, 0x9e, 0xb7, 0xc6, 0xcd, 0xcf, 0x87, 0xd0,
+ 0x0c, 0xcf, 0xcb, 0xc0, 0x29, 0x00, 0x77, 0x7f, 0x60, 0x00, 0x32, 0x99,
+ 0xb2, 0xc3, 0x81, 0xcc, 0x01, 0xcd, 0xce, 0x80, 0xcf, 0x01, 0xce, 0xcd,
+ 0x81, 0xcc, 0x13, 0xc9, 0xa1, 0x00, 0x46, 0xac, 0xba, 0xc6, 0xcc, 0xcf,
+ 0xcf, 0xcd, 0xc5, 0x58, 0x00, 0x00, 0x1b, 0x8f, 0xa9, 0xb9, 0x84, 0x80,
+ 0x00, 0x03, 0x79, 0xa0, 0xbb, 0xc8, 0x80, 0xcd, 0x01, 0xcc, 0xcc, 0x80,
+ 0xcd, 0x0b, 0xce, 0xce, 0xcd, 0xcd, 0xcc, 0xcc, 0xcd, 0xce, 0xcf, 0xcf,
+ 0xce, 0xcd, 0x80, 0xcc, 0x06, 0xcd, 0xcd, 0xce, 0xce, 0xcf, 0xce, 0xcd,
+ 0x80, 0xcc, 0x01, 0xcd, 0xcd, 0x80, 0xce, 0x03, 0xcd, 0xcc, 0xcc, 0xcd,
+ 0x81, 0xce, 0x00, 0xcd, 0x83, 0xcc, 0x08, 0xcd, 0xcd, 0xce, 0xcf, 0xce,
+ 0xce, 0xcd, 0xcc, 0xcd, 0x80, 0xce, 0x01, 0xcd, 0xcd, 0x81, 0xcc, 0x08,
+ 0xc6, 0x6c, 0x00, 0x73, 0xb1, 0xbe, 0xc8, 0xcd, 0xcf, 0x9e, 0xd0, 0x08,
+ 0xcf, 0xcf, 0xce, 0xcc, 0xcb, 0xc9, 0xc7, 0xc5, 0xc3, 0x80, 0xc2, 0x06,
+ 0xc3, 0xc5, 0xc6, 0xc6, 0xc0, 0xaf, 0x3f, 0x84, 0x00, 0x05, 0x11, 0x85,
+ 0xa9, 0xbf, 0xca, 0xce, 0x87, 0xd0, 0x65, 0xcf, 0xcb, 0xbf, 0x14, 0x07,
+ 0x81, 0x80, 0x31, 0x00, 0x50, 0x97, 0xaf, 0xc0, 0xc7, 0xc6, 0xc4, 0xc4,
+ 0xc6, 0xc9, 0xcc, 0xcd, 0xcc, 0xcb, 0xc7, 0xc5, 0xc3, 0xc5, 0xc6, 0xc2,
+ 0x82, 0x00, 0x50, 0x9e, 0xaf, 0xc0, 0xcb, 0xce, 0xcf, 0xcb, 0xc0, 0x15,
+ 0x07, 0x0d, 0x03, 0x7f, 0x9f, 0xb0, 0x2b, 0x00, 0x13, 0x00, 0x60, 0x9a,
+ 0xb5, 0xc5, 0xc9, 0xc7, 0xc5, 0xc4, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc8,
+ 0xc6, 0xc5, 0xc4, 0xc5, 0xc6, 0xc9, 0xcc, 0xcc, 0xca, 0xc7, 0xc5, 0xc4,
+ 0xc4, 0xc5, 0xc6, 0xc8, 0xca, 0xcb, 0xca, 0xc6, 0xc5, 0xc4, 0xc4, 0xc5,
+ 0xc6, 0xc7, 0xc9, 0xc9, 0xc6, 0xc5, 0xc4, 0xc6, 0xc8, 0xcb, 0xca, 0xc8,
+ 0xc5, 0x80, 0xc3, 0x1d, 0xc4, 0xc5, 0xc4, 0xc5, 0xc7, 0xca, 0xcc, 0xca,
+ 0xc7, 0xc5, 0xc4, 0xc5, 0xc8, 0xca, 0xca, 0xc7, 0xc6, 0xc4, 0xc4, 0xc5,
+ 0xc4, 0xbf, 0x4f, 0x00, 0x7a, 0xa2, 0xb4, 0xc4, 0xcc, 0xcf, 0xa1, 0xd0,
+ 0x04, 0xcf, 0xcf, 0xce, 0xce, 0xcd, 0x82, 0xcc, 0x06, 0xcd, 0xcd, 0xcc,
+ 0xc8, 0xbc, 0xa1, 0x17, 0x84, 0x00, 0x05, 0x2f, 0x98, 0xb4, 0xc4, 0xcc,
+ 0xcf, 0x86, 0xd0, 0x7f, 0xcf, 0xca, 0xb9, 0x01, 0x06, 0x27, 0x0e, 0x00,
+ 0x29, 0x82, 0x96, 0xad, 0xbb, 0x93, 0x59, 0x47, 0x66, 0xaf, 0xbc, 0xc3,
+ 0xc7, 0xc6, 0x9a, 0x5a, 0x46, 0x63, 0xab, 0xb7, 0x8e, 0x35, 0x00, 0x2a,
+ 0x47, 0x9f, 0xbb, 0xc8, 0xcd, 0xcd, 0xc8, 0x89, 0x00, 0x32, 0x2b, 0x00,
+ 0x5d, 0x97, 0x81, 0x00, 0x28, 0x35, 0x00, 0x4e, 0x96, 0xb1, 0xbe, 0x99,
+ 0x60, 0x4d, 0x69, 0xa9, 0x72, 0x5b, 0xb7, 0xac, 0x5d, 0x82, 0x76, 0x4e,
+ 0x7a, 0xb4, 0xbe, 0xc3, 0xc3, 0x92, 0x5d, 0x4d, 0x6f, 0xae, 0x69, 0x63,
+ 0xbb, 0xc0, 0xc2, 0x8e, 0x5c, 0x4e, 0x6f, 0xaf, 0x63, 0x6d, 0xbb, 0xbd,
+ 0x9a, 0x5c, 0x48, 0x69, 0xb1, 0xbc, 0xc1, 0x8a, 0x5d, 0x82, 0x4d, 0x50,
+ 0x8f, 0xa1, 0x57, 0x52, 0x88, 0xb7, 0xbf, 0xc2, 0xa9, 0x63, 0x47, 0x60,
+ 0xa7, 0xbb, 0xbf, 0x7d, 0x5d, 0x99, 0x5a, 0x5b, 0x9e, 0xb4, 0x73, 0x1d,
+ 0x06, 0x00, 0x3c, 0x59, 0xab, 0xbf, 0xca, 0xce, 0xa5, 0xd0, 0x84, 0xcf,
+ 0x06, 0xd0, 0xcf, 0xcc, 0xc5, 0xb4, 0x5d, 0x04, 0x83, 0x00, 0x05, 0x0a,
+ 0x70, 0xa4, 0xbc, 0xc9, 0xce, 0x86, 0xd0, 0x02, 0xce, 0xc8, 0xa3, 0x82,
+ 0x00, 0x05, 0x07, 0x4c, 0x93, 0xa7, 0x5d, 0x01, 0x80, 0x00, 0x05, 0x17,
+ 0x9e, 0xb4, 0xbd, 0x6a, 0x03, 0x80, 0x00, 0x02, 0x13, 0x92, 0x4d, 0x80,
+ 0x00, 0x21, 0x03, 0x9b, 0xb4, 0xc6, 0xcc, 0xcc, 0xc4, 0x40, 0x00, 0x63,
+ 0x49, 0x00, 0x3c, 0x8d, 0x2f, 0x00, 0x64, 0x46, 0x00, 0x3f, 0x93, 0xa9,
+ 0x59, 0x01, 0x00, 0x09, 0x00, 0x19, 0x11, 0x0b, 0xa4, 0x7e, 0x00, 0x0d,
+ 0x80, 0x00, 0x24, 0x3e, 0xab, 0xb4, 0x49, 0x00, 0x00, 0x09, 0x00, 0x21,
+ 0x08, 0x1b, 0xa7, 0xaf, 0x42, 0x00, 0x00, 0x03, 0x00, 0x25, 0x01, 0x2b,
+ 0xa4, 0x66, 0x03, 0x00, 0x03, 0x00, 0x1d, 0x9e, 0xb0, 0x3f, 0x00, 0x01,
+ 0x00, 0x00, 0x04, 0x0e, 0x80, 0x00, 0x11, 0x69, 0xab, 0x84, 0x0a, 0x00,
+ 0x04, 0x00, 0x11, 0x8c, 0xac, 0x27, 0x00, 0x0d, 0x00, 0x00, 0x01, 0x8e,
+ 0x21, 0x80, 0x00, 0x04, 0x28, 0xa4, 0xbb, 0xc7, 0xce, 0xae, 0xd0, 0x04,
+ 0xce, 0xca, 0xc0, 0xab, 0x22, 0x84, 0x00, 0x05, 0x1d, 0x93, 0xb0, 0xc2,
+ 0xcc, 0xcf, 0x85, 0xd0, 0x7f, 0xce, 0xc7, 0x8a, 0x00, 0x2e, 0x63, 0x5d,
+ 0x45, 0x0e, 0x00, 0x6e, 0x7a, 0x01, 0x11, 0x58, 0x6e, 0x27, 0x00, 0x40,
+ 0xa2, 0x8f, 0x03, 0x0e, 0x55, 0x70, 0x2b, 0x00, 0x35, 0x8a, 0x2d, 0x00,
+ 0x65, 0x7d, 0x9e, 0xb4, 0xc5, 0xcc, 0xca, 0xb4, 0x07, 0x13, 0x84, 0x70,
+ 0x00, 0x1d, 0x6d, 0x01, 0x21, 0x82, 0x5c, 0x00, 0x2f, 0x8e, 0x71, 0x00,
+ 0x25, 0x74, 0x90, 0x69, 0x06, 0x00, 0x1a, 0x8e, 0x5f, 0x00, 0x14, 0x60,
+ 0x5f, 0x04, 0x07, 0x91, 0x63, 0x00, 0x2e, 0x7a, 0x8f, 0x60, 0x01, 0x00,
+ 0x29, 0x93, 0x5b, 0x00, 0x2e, 0x76, 0x88, 0x4f, 0x00, 0x00, 0x35, 0x7c,
+ 0x04, 0x0a, 0x6e, 0x80, 0x40, 0x00, 0x46, 0x9b, 0x24, 0x00, 0x32, 0x69,
+ 0x28, 0x00, 0x13, 0x63, 0x66, 0x01, 0x1e, 0x91, 0x14, 0x01, 0x60, 0x83,
+ 0x55, 0x00, 0x2a, 0x97, 0x0e, 0x00, 0x41, 0x6a, 0x2b, 0x00, 0x4a, 0x84,
+ 0x0a, 0x06, 0x13, 0x71, 0x84, 0xa4, 0xbb, 0xc7, 0xce, 0xae, 0xd0, 0x05,
+ 0xcf, 0xcd, 0xc6, 0xb8, 0x81, 0x0a, 0x83, 0x00, 0x06, 0x04, 0x54, 0x9f,
+ 0xb9, 0xc7, 0xcd, 0xcf, 0x83, 0xd0, 0x71, 0xcf, 0xcd, 0xc6, 0x72, 0x00,
+ 0x48, 0x7e, 0x85, 0x88, 0x4d, 0x00, 0x3f, 0x3f, 0x00, 0x4d, 0x86, 0x89,
+ 0x73, 0x00, 0x1a, 0x92, 0x4f, 0x00, 0x48, 0x87, 0x89, 0x7a, 0x01, 0x14,
+ 0x83, 0x1e, 0x03, 0x7c, 0x8e, 0xa6, 0xbb, 0xc7, 0xcb, 0xc6, 0x70, 0x00,
+ 0x48, 0x8a, 0x8c, 0x11, 0x03, 0x29, 0x00, 0x5d, 0x86, 0x76, 0x00, 0x20,
+ 0x89, 0x32, 0x00, 0x6e, 0x8e, 0x93, 0x94, 0x34, 0x00, 0x28, 0x82, 0x46,
+ 0x00, 0x5f, 0x84, 0x86, 0x22, 0x00, 0x7e, 0x22, 0x01, 0x7a, 0x8e, 0x94,
+ 0x93, 0x25, 0x00, 0x35, 0x85, 0x1e, 0x01, 0x7d, 0x8e, 0x93, 0x92, 0x1e,
+ 0x00, 0x3f, 0x48, 0x00, 0x17, 0x35, 0x35, 0x32, 0x00, 0x1a, 0x8c, 0x10,
+ 0x10, 0x7f, 0x81, 0x4d, 0x00, 0x4f, 0x7f, 0x86, 0x0d, 0x15, 0x64, 0x00,
+ 0x0d, 0x80, 0x35, 0x12, 0x07, 0x04, 0x82, 0x01, 0x20, 0x80, 0x84, 0x63,
+ 0x00, 0x3b, 0x7d, 0x00, 0x22, 0x7f, 0x93, 0xab, 0xc0, 0xca, 0xce, 0xaf,
+ 0xd0, 0x04, 0xcf, 0xcc, 0xc2, 0xaf, 0x35, 0x84, 0x00, 0x05, 0x15, 0x8a,
+ 0xab, 0xc0, 0xcb, 0xce, 0x83, 0xd0, 0x7f, 0xcf, 0xcc, 0xc4, 0x5c, 0x00,
+ 0x5a, 0x8a, 0x94, 0x99, 0x50, 0x00, 0x38, 0x29, 0x00, 0x64, 0x86, 0x90,
+ 0x7e, 0x00, 0x1e, 0x89, 0x37, 0x00, 0x63, 0x88, 0x91, 0x83, 0x01, 0x17,
+ 0x7e, 0x0e, 0x11, 0x86, 0x9a, 0xb2, 0xc2, 0xcb, 0xcb, 0xc2, 0x29, 0x01,
+ 0x7c, 0x92, 0x99, 0x35, 0x00, 0x00, 0x19, 0x80, 0x90, 0x95, 0x01, 0x0e,
+ 0x83, 0x1a, 0x07, 0x87, 0x90, 0x9c, 0x9e, 0x3c, 0x00, 0x35, 0x7e, 0x34,
+ 0x00, 0x73, 0x8b, 0x92, 0x1e, 0x01, 0x7f, 0x0b, 0x13, 0x86, 0x91, 0x9e,
+ 0x9e, 0x2b, 0x00, 0x42, 0x80, 0x0b, 0x18, 0x88, 0x92, 0x9e, 0x9e, 0x2e,
+ 0x00, 0x4d, 0x35, 0x00, 0x15, 0x20, 0x21, 0x21, 0x22, 0x2e, 0x84, 0x01,
+ 0x21, 0x82, 0x8a, 0x47, 0x00, 0x63, 0x87, 0x8e, 0x03, 0x21, 0x4e, 0x00,
+ 0x0e, 0x1e, 0x21, 0x21, 0x22, 0x22, 0x69, 0x00, 0x31, 0x84, 0x8e, 0x64,
+ 0x00, 0x46, 0x6d, 0x07, 0x00, 0x34, 0x89, 0x9f, 0xb6, 0xc5, 0xcc, 0xcf,
+ 0xb0, 0xd0, 0x04, 0xce, 0xc8, 0xbb, 0x99, 0x14, 0x83, 0x00, 0x06, 0x01,
+ 0x38, 0x9a, 0xb4, 0xc5, 0xcc, 0xcf, 0x82, 0xd0, 0x7f, 0xcf, 0xcc, 0xc2,
+ 0x46, 0x00, 0x6a, 0x8b, 0x96, 0x79, 0x15, 0x00, 0x54, 0x37, 0x00, 0x3c,
+ 0x86, 0x90, 0x3e, 0x00, 0x3f, 0x88, 0x47, 0x00, 0x38, 0x89, 0x91, 0x45,
+ 0x00, 0x35, 0x7d, 0x01, 0x21, 0x8d, 0xa3, 0xba, 0xc7, 0xcc, 0xc9, 0xa2,
+ 0x00, 0x24, 0x90, 0x9b, 0xa5, 0x60, 0x00, 0x00, 0x52, 0x87, 0x9c, 0xa4,
+ 0x12, 0x01, 0x7d, 0x28, 0x00, 0x60, 0x90, 0x9e, 0x98, 0x08, 0x00, 0x46,
+ 0x80, 0x23, 0x01, 0x86, 0x96, 0x9e, 0x13, 0x0d, 0x81, 0x19, 0x00, 0x6d,
+ 0x92, 0x9f, 0x8d, 0x01, 0x00, 0x52, 0x82, 0x1e, 0x01, 0x76, 0x93, 0xa0,
+ 0x92, 0x03, 0x00, 0x5c, 0x46, 0x00, 0x25, 0x70, 0x76, 0x60, 0x79, 0x85,
+ 0x77, 0x00, 0x32, 0x8a, 0x94, 0x3f, 0x00, 0x7a, 0x93, 0x8d, 0x00, 0x2f,
+ 0x5f, 0x00, 0x11, 0x6d, 0x74, 0x67, 0x70, 0x81, 0x60, 0x00, 0x42, 0x8c,
+ 0x9a, 0x5d, 0x00, 0x52, 0x5d, 0x06, 0x00, 0x46, 0x92, 0xa9, 0xbe, 0xca,
+ 0xce, 0xb1, 0xd0, 0x05, 0xcf, 0xcc, 0xc4, 0xb3, 0x4f, 0x01, 0x83, 0x00,
+ 0x05, 0x08, 0x7a, 0xa6, 0xbd, 0xc9, 0xce, 0x82, 0xd0, 0x7f, 0xcf, 0xcc,
+ 0xc1, 0x2f, 0x00, 0x11, 0x15, 0x08, 0x00, 0x00, 0x29, 0x81, 0x6d, 0x03,
+ 0x00, 0x19, 0x11, 0x00, 0x0d, 0x7f, 0x8f, 0x83, 0x06, 0x00, 0x17, 0x14,
+ 0x00, 0x09, 0x76, 0x73, 0x00, 0x35, 0x93, 0xa9, 0xbf, 0xca, 0xcc, 0xc6,
+ 0x59, 0x00, 0x5a, 0x96, 0xa5, 0xb0, 0x92, 0x00, 0x17, 0x80, 0x94, 0xa9,
+ 0xaf, 0x29, 0x00, 0x6f, 0x5c, 0x00, 0x04, 0x30, 0x3c, 0x08, 0x00, 0x00,
+ 0x55, 0x83, 0x13, 0x0e, 0x8f, 0x9e, 0xa5, 0x03, 0x21, 0x86, 0x4f, 0x00,
+ 0x07, 0x37, 0x35, 0x04, 0x00, 0x00, 0x63, 0x88, 0x5f, 0x00, 0x0e, 0x41,
+ 0x3f, 0x0a, 0x00, 0x00, 0x6c, 0x73, 0x0a, 0x00, 0x12, 0x1e, 0x00, 0x14,
+ 0x89, 0x6e, 0x00, 0x46, 0x92, 0x9c, 0x2b, 0x03, 0x8f, 0x9b, 0x7e, 0x00,
+ 0x44, 0x80, 0x19, 0x00, 0x0d, 0x23, 0x01, 0x07, 0x77, 0x56, 0x00, 0x57,
+ 0x94, 0xa2, 0x4e, 0x00, 0x67, 0x4f, 0x06, 0x00, 0x59, 0x98, 0xaf, 0xc2,
+ 0xcc, 0xcf, 0xb2, 0xd0, 0x04, 0xce, 0xca, 0xbf, 0xa7, 0x1d, 0x84, 0x00,
+ 0x05, 0x0e, 0x95, 0xb2, 0xc4, 0xcc, 0xcf, 0x81, 0xd0, 0x03, 0xcf, 0xcc,
+ 0xc1, 0x1a, 0x80, 0x00, 0x7f, 0x07, 0x1a, 0x4c, 0x86, 0x8f, 0x95, 0x69,
+ 0x11, 0x00, 0x01, 0x21, 0x76, 0x91, 0x9e, 0xa4, 0x76, 0x14, 0x00, 0x01,
+ 0x1e, 0x72, 0x8b, 0x6d, 0x00, 0x49, 0x9c, 0xb0, 0xc2, 0xcb, 0xcc, 0xc3,
+ 0x15, 0x07, 0x90, 0x9f, 0xb0, 0xbb, 0xb4, 0x11, 0x5f, 0x93, 0xa4, 0xb5,
+ 0xb8, 0x41, 0x00, 0x65, 0x8e, 0x54, 0x09, 0x00, 0x00, 0x21, 0x29, 0x00,
+ 0x6a, 0x8c, 0x03, 0x22, 0x98, 0xa5, 0x97, 0x00, 0x39, 0x91, 0x92, 0x4b,
+ 0x06, 0x00, 0x01, 0x29, 0x21, 0x00, 0x7a, 0x93, 0x9b, 0x5a, 0x0a, 0x00,
+ 0x00, 0x22, 0x0d, 0x04, 0x7a, 0x88, 0x73, 0x1b, 0x01, 0x01, 0x17, 0x6d,
+ 0x96, 0x62, 0x00, 0x5d, 0x9b, 0xa4, 0x17, 0x13, 0x9a, 0xa3, 0x6c, 0x00,
+ 0x5c, 0x8f, 0x7e, 0x28, 0x01, 0x00, 0x11, 0x58, 0x91, 0x4a, 0x00, 0x71,
+ 0x9e, 0xab, 0x3a, 0x00, 0x82, 0x44, 0x00, 0x70, 0xa1, 0xb5, 0xc5, 0xcd,
+ 0xcf, 0xb2, 0xd0, 0x05, 0xcf, 0xcd, 0xc6, 0xb6, 0x72, 0x08, 0x83, 0x00,
+ 0x05, 0x07, 0x73, 0xa5, 0xbe, 0xca, 0xcf, 0x81, 0xd0, 0x76, 0xcf, 0xcc,
+ 0xc4, 0xb4, 0x9e, 0x8f, 0x8a, 0x8a, 0x8e, 0x93, 0x9b, 0xa5, 0xab, 0xa9,
+ 0x9e, 0x86, 0x87, 0x8f, 0x97, 0xa3, 0xb1, 0xb5, 0xae, 0xa0, 0x87, 0x88,
+ 0x8e, 0x95, 0x9e, 0xa5, 0xa5, 0xa4, 0xab, 0xb9, 0xc6, 0xcc, 0xcc, 0xc6,
+ 0xba, 0xab, 0xa5, 0xad, 0xbb, 0xc2, 0xbf, 0xb2, 0xa7, 0xa9, 0xb4, 0xc0,
+ 0xc1, 0xb5, 0xa7, 0x9f, 0xa0, 0x9f, 0x99, 0x81, 0x87, 0x8f, 0x8e, 0x8e,
+ 0x94, 0x9e, 0xa3, 0xa2, 0xa6, 0xb1, 0xb6, 0xb0, 0xa6, 0xa4, 0xa5, 0xa3,
+ 0x99, 0x7f, 0x8a, 0x8f, 0x8e, 0x8e, 0x98, 0xa4, 0xa9, 0xa1, 0x93, 0x79,
+ 0x7a, 0x6d, 0x00, 0x20, 0x81, 0x95, 0xa0, 0x9b, 0x8a, 0x85, 0x8f, 0x98,
+ 0xa4, 0xab, 0xa8, 0xa5, 0xab, 0xb1, 0xaf, 0xa8, 0xa7, 0xae, 0xb3, 0xac,
+ 0xa4, 0xa3, 0xa3, 0x9e, 0x8e, 0x82, 0x8e, 0x96, 0x9e, 0x80, 0xa4, 0x0b,
+ 0xab, 0xb4, 0xb3, 0xa9, 0x9f, 0x9e, 0x9e, 0xa3, 0xae, 0xbd, 0xc8, 0xce,
+ 0xb4, 0xd0, 0x04, 0xcf, 0xcb, 0xc1, 0xac, 0x2b, 0x82, 0x00, 0x06, 0x01,
+ 0x01, 0x4a, 0x9b, 0xb8, 0xc8, 0xce, 0x82, 0xd0, 0x4a, 0xce, 0xc8, 0xbf,
+ 0xb3, 0xa8, 0xa3, 0xa3, 0xa5, 0xab, 0xb3, 0xbb, 0xbf, 0xbc, 0xb4, 0xab,
+ 0xa6, 0xa7, 0xad, 0xb7, 0xc0, 0xc3, 0xbf, 0xb5, 0xab, 0xa6, 0xa7, 0xac,
+ 0xb4, 0xb9, 0xb8, 0xb7, 0xbb, 0xc2, 0xca, 0xce, 0xcd, 0xca, 0xc2, 0xba,
+ 0xb7, 0xbd, 0xc5, 0xc9, 0xc6, 0xc0, 0xbb, 0xbc, 0xc2, 0xc8, 0xc7, 0xc1,
+ 0xb9, 0xb4, 0xb5, 0xb4, 0xb0, 0xa9, 0xa6, 0xa4, 0xa5, 0xa8, 0xad, 0xb3,
+ 0xb5, 0xb5, 0xb8, 0xbe, 0xc1, 0xbd, 0xb8, 0xb7, 0xb9, 0xb7, 0xb1, 0xa9,
+ 0x80, 0xa5, 0x36, 0xa9, 0xae, 0xb4, 0x52, 0x15, 0x49, 0x7a, 0x6a, 0x21,
+ 0x00, 0x4d, 0x8d, 0xa4, 0xb2, 0xb3, 0xab, 0xa7, 0xa8, 0xad, 0xb4, 0xba,
+ 0xb9, 0xb7, 0xbb, 0xbe, 0xbd, 0xb8, 0xb8, 0xbc, 0xbf, 0xbb, 0xb7, 0xb7,
+ 0xb8, 0xb4, 0xac, 0xa7, 0xa7, 0xab, 0xb3, 0xb6, 0xb6, 0xb7, 0xbb, 0xc0,
+ 0xbf, 0xb9, 0xb4, 0xb3, 0xb3, 0xb5, 0xbd, 0xc5, 0xcc, 0xcf, 0xb4, 0xd0,
+ 0x05, 0xcf, 0xcd, 0xc7, 0xba, 0x90, 0x03, 0x82, 0x00, 0x05, 0x03, 0x53,
+ 0x98, 0xb5, 0xc6, 0xce, 0x82, 0xd0, 0x1b, 0xcf, 0xcc, 0xc8, 0xc2, 0xbf,
+ 0xbc, 0xbc, 0xbd, 0xc0, 0xc3, 0xc7, 0xca, 0xc8, 0xc4, 0xc0, 0xbd, 0xbe,
+ 0xc1, 0xc6, 0xca, 0xcc, 0xc9, 0xc5, 0xc0, 0xbd, 0xbe, 0xc1, 0xc4, 0x81,
+ 0xc6, 0x24, 0xcb, 0xcd, 0xcf, 0xcf, 0xcd, 0xc9, 0xc6, 0xc5, 0xc8, 0xcc,
+ 0xcd, 0xcc, 0xca, 0xc7, 0xc8, 0xcb, 0xcd, 0xcc, 0xca, 0xc6, 0xc4, 0xc5,
+ 0xc5, 0xc2, 0xbf, 0xbc, 0xbc, 0xbd, 0xbf, 0xc1, 0xc4, 0xc5, 0xc4, 0xc6,
+ 0xc8, 0xc9, 0xc7, 0x81, 0xc6, 0x09, 0xc2, 0xbf, 0xbc, 0xbc, 0xbd, 0xbf,
+ 0xc1, 0xc0, 0x95, 0x07, 0x81, 0x00, 0x0a, 0x2b, 0x88, 0x9b, 0xb1, 0xc0,
+ 0xc2, 0xc0, 0xbe, 0xbe, 0xc1, 0xc4, 0x81, 0xc6, 0x05, 0xc8, 0xc7, 0xc6,
+ 0xc6, 0xc7, 0xc8, 0x81, 0xc6, 0x05, 0xc5, 0xc1, 0xbe, 0xbe, 0xc0, 0xc3,
+ 0x80, 0xc5, 0x0b, 0xc7, 0xc9, 0xc8, 0xc6, 0xc4, 0xc3, 0xc3, 0xc5, 0xc7,
+ 0xcc, 0xce, 0xcf, 0xb5, 0xd0, 0x05, 0xcf, 0xcc, 0xc2, 0xb1, 0x34, 0x03,
+ 0x81, 0x00, 0x05, 0x10, 0x76, 0x9b, 0xb7, 0xc7, 0xce, 0x83, 0xd0, 0x03,
+ 0xcf, 0xcd, 0xcc, 0xcb, 0x80, 0xca, 0x20, 0xcb, 0xcc, 0xcd, 0xce, 0xce,
+ 0xcc, 0xcb, 0xca, 0xca, 0xcc, 0xcd, 0xce, 0xcf, 0xce, 0xcc, 0xcb, 0xca,
+ 0xca, 0xcc, 0xcc, 0xcd, 0xcd, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd0, 0xcf,
+ 0xce, 0xcd, 0xcc, 0xcd, 0x80, 0xcf, 0x07, 0xce, 0xcd, 0xcd, 0xce, 0xcf,
+ 0xcf, 0xce, 0xcd, 0x81, 0xcc, 0x04, 0xcb, 0xca, 0xc9, 0xca, 0xcb, 0x82,
+ 0xcc, 0x03, 0xcd, 0xce, 0xcd, 0xcc, 0x80, 0xcd, 0x1b, 0xcc, 0xca, 0xc9,
+ 0xc9, 0xca, 0xcb, 0xca, 0xc7, 0xbe, 0x96, 0x58, 0x2e, 0x37, 0x5c, 0x8c,
+ 0x98, 0xab, 0xbd, 0xc7, 0xcb, 0xcb, 0xca, 0xca, 0xcb, 0xcc, 0xcd, 0xcd,
+ 0xcc, 0x80, 0xcd, 0x01, 0xcc, 0xcc, 0x80, 0xcd, 0x07, 0xcc, 0xcd, 0xcd,
+ 0xcc, 0xcc, 0xca, 0xca, 0xcb, 0x81, 0xcc, 0x03, 0xcd, 0xce, 0xcd, 0xcd,
+ 0x81, 0xcc, 0x02, 0xcd, 0xcf, 0xcf, 0xb7, 0xd0, 0x0e, 0xce, 0xc9, 0xbd,
+ 0xa5, 0x31, 0x0a, 0x00, 0x03, 0x10, 0x55, 0x87, 0xa5, 0xbd, 0xca, 0xcf,
+ 0x84, 0xd0, 0x85, 0xcf, 0x80, 0xd0, 0x83, 0xcf, 0x80, 0xd0, 0x87, 0xcf,
+ 0x83, 0xd0, 0x80, 0xcf, 0x81, 0xd0, 0x00, 0xcf, 0x82, 0xd0, 0x83, 0xcf,
+ 0x01, 0xce, 0xce, 0x85, 0xcf, 0x00, 0xd0, 0x84, 0xcf, 0x11, 0xce, 0xce,
+ 0xcf, 0xcf, 0xce, 0xcb, 0xc4, 0xb8, 0xa9, 0x9e, 0x98, 0x99, 0xa0, 0xac,
+ 0xbb, 0xc6, 0xcc, 0xce, 0x9a, 0xcf, 0x01, 0xd0, 0xd0, 0x83, 0xcf, 0xb9,
+ 0xd0, 0x0e, 0xcf, 0xcc, 0xc6, 0xb8, 0xa4, 0x7c, 0x4d, 0x55, 0x76, 0x87,
+ 0x9e, 0xb4, 0xc4, 0xcc, 0xcf, 0xff, 0xd0, 0xbf, 0xd0, 0x0c, 0xcf, 0xcc,
+ 0xc4, 0xb9, 0xab, 0x9e, 0x98, 0x9b, 0xa5, 0xb4, 0xc1, 0xca, 0xce, 0xff,
+ 0xd0, 0x93, 0xd0, 0x94, 0xd0, 0x12, 0xcf, 0xce, 0xcd, 0xcc, 0xcb, 0xc9,
+ 0xc7, 0xc6, 0xc5, 0xc4, 0xc4, 0xc6, 0xc7, 0xc9, 0xcb, 0xcc, 0xcd, 0xce,
+ 0xcf, 0xff, 0xd0, 0xb7, 0xd0, 0x09, 0xcf, 0xcf, 0xcd, 0xcc, 0xc9, 0xc6,
+ 0xc2, 0xbd, 0xbb, 0xb8, 0x80, 0xb5, 0x0b, 0xb2, 0xb4, 0xb6, 0xba, 0xbe,
+ 0xc2, 0xc6, 0xc9, 0xcc, 0xcd, 0xcf, 0xcf, 0xff, 0xd0, 0xb3, 0xd0, 0x08,
+ 0xcf, 0xcd, 0xcb, 0xc7, 0xc2, 0xbc, 0xb8, 0xb9, 0xbb, 0x84, 0xbc, 0x0c,
+ 0xb9, 0xb5, 0xaf, 0xad, 0xb4, 0xbb, 0xc2, 0xc7, 0xcb, 0xcd, 0xcf, 0xd0,
+ 0xd0, 0x81, 0xcf, 0xff, 0xd0, 0xaa, 0xd0, 0x06, 0xcf, 0xce, 0xcc, 0xc7,
+ 0xc1, 0xba, 0xb8, 0x8b, 0xbc, 0x0f, 0xba, 0xb2, 0xac, 0xae, 0xb8, 0xc1,
+ 0xc7, 0xcc, 0xce, 0xce, 0xcd, 0xcc, 0xcc, 0xcd, 0xce, 0xcf, 0xff, 0xd0,
+ 0xa7, 0xd0, 0x05, 0xcf, 0xcd, 0xca, 0xc3, 0xbb, 0xb9, 0x90, 0xbc, 0x0c,
+ 0xb6, 0xa8, 0xac, 0xba, 0xc3, 0xc8, 0xca, 0xc7, 0xc3, 0xc4, 0xc7, 0xcc,
+ 0xce, 0xa3, 0xd0, 0x8b, 0xcf, 0x89, 0xd0, 0x89, 0xcf, 0xb9, 0xd0, 0x83,
+ 0xcf, 0x9a, 0xd0, 0x04, 0xcf, 0xcc, 0xc7, 0xbe, 0xb8, 0x94, 0xbc, 0x0b,
+ 0xac, 0xa3, 0xb2, 0xbc, 0xbf, 0xbb, 0xbc, 0xb5, 0xbd, 0xc6, 0xcc, 0xcf,
+ 0x9e, 0xd0, 0x04, 0xcf, 0xcf, 0xce, 0xcd, 0xcd, 0x89, 0xcc, 0x03, 0xcd,
+ 0xcd, 0xce, 0xcf, 0x82, 0xd0, 0x03, 0xcf, 0xcf, 0xce, 0xcd, 0x88, 0xcc,
+ 0x03, 0xcd, 0xcd, 0xce, 0xcf, 0x82, 0xd0, 0x06, 0xcf, 0xce, 0xce, 0xcd,
+ 0xce, 0xcf, 0xcf, 0xa9, 0xd0, 0x07, 0xcf, 0xcd, 0xcc, 0xcb, 0xcb, 0xcc,
+ 0xcd, 0xcf, 0x98, 0xd0, 0x04, 0xce, 0xcc, 0xc6, 0xbb, 0xba, 0x96, 0xbc,
+ 0x0a, 0xb5, 0xa1, 0xa4, 0xb2, 0xba, 0xba, 0xa4, 0xad, 0xbf, 0xca, 0xce,
+ 0x9d, 0xd0, 0x05, 0xcf, 0xcd, 0xcb, 0xc8, 0xc6, 0xc4, 0x89, 0xc3, 0x0d,
+ 0xc5, 0xc6, 0xc9, 0xcc, 0xce, 0xcf, 0xd0, 0xd0, 0xcf, 0xcc, 0xcb, 0xc7,
+ 0xc6, 0xc4, 0x87, 0xc3, 0x10, 0xc5, 0xc6, 0xc9, 0xcc, 0xce, 0xcf, 0xd0,
+ 0xcf, 0xce, 0xcc, 0xca, 0xc7, 0xc6, 0xc8, 0xcc, 0xcd, 0xcf, 0xa7, 0xd0,
+ 0x09, 0xce, 0xcc, 0xc7, 0xbb, 0xb7, 0xbf, 0xc2, 0xc8, 0xcc, 0xcf, 0x96,
+ 0xd0, 0x04, 0xcf, 0xcc, 0xc5, 0xbb, 0xbb, 0x98, 0xbc, 0x09, 0xba, 0xaa,
+ 0xb8, 0xbc, 0xbc, 0x9c, 0x9e, 0xb6, 0xc6, 0xcd, 0x9c, 0xd0, 0x06, 0xcf,
+ 0xcc, 0xc7, 0xc0, 0xba, 0xb7, 0xb5, 0x88, 0xb3, 0x0e, 0xb4, 0xb4, 0xb6,
+ 0xbc, 0xc4, 0xca, 0xce, 0xcf, 0xce, 0xcc, 0xc6, 0xbe, 0xb9, 0xb7, 0xb5,
+ 0x86, 0xb3, 0x12, 0xb4, 0xb4, 0xb6, 0xbc, 0xc3, 0xca, 0xcd, 0xcf, 0xce,
+ 0xcb, 0xc4, 0xbd, 0xb9, 0xb7, 0xbb, 0xc2, 0xc9, 0xcd, 0xcf, 0xa5, 0xd0,
+ 0x0b, 0xcf, 0xcc, 0xb7, 0x41, 0x08, 0x06, 0x37, 0xae, 0xbc, 0xc6, 0xcc,
+ 0xcf, 0x94, 0xd0, 0x04, 0xcf, 0xcc, 0xc6, 0xbb, 0xbb, 0x88, 0xbc, 0x06,
+ 0xb6, 0xa2, 0x94, 0x98, 0x9b, 0xa1, 0xb3, 0x87, 0xbc, 0x01, 0xb7, 0xb7,
+ 0x80, 0xbc, 0x05, 0xa4, 0x90, 0xae, 0xc2, 0xcc, 0xcf, 0x9a, 0xd0, 0x04,
+ 0xcf, 0xcc, 0xc6, 0xbc, 0xbb, 0x8d, 0xbc, 0x07, 0xbb, 0xaa, 0xb4, 0xc2,
+ 0xcb, 0xcd, 0xcc, 0xc4, 0x8d, 0xbc, 0x08, 0xba, 0xab, 0xb4, 0xc2, 0xcb,
+ 0xcd, 0xcb, 0xc1, 0xbb, 0x80, 0xbc, 0x04, 0xab, 0xb2, 0xc0, 0xca, 0xce,
+ 0xa4, 0xd0, 0x03, 0xcf, 0xcd, 0xc6, 0x56, 0x81, 0x00, 0x04, 0x6a, 0xab,
+ 0xc0, 0xca, 0xce, 0x93, 0xd0, 0x04, 0xcf, 0xcd, 0xc7, 0xbc, 0xbb, 0x86,
+ 0xbc, 0x0c, 0xa4, 0x8b, 0x7d, 0x6e, 0x73, 0x7a, 0x7e, 0x80, 0x7f, 0x7b,
+ 0x83, 0x96, 0xb1, 0x83, 0xbc, 0x01, 0xb4, 0xb3, 0x81, 0xbc, 0x05, 0xa9,
+ 0x86, 0xa8, 0xc0, 0xcb, 0xcf, 0x9a, 0xd0, 0x02, 0xce, 0xc9, 0xbd, 0x90,
+ 0xbc, 0x06, 0xa9, 0xa1, 0xb8, 0xc6, 0xcb, 0xc6, 0xba, 0x8e, 0xbc, 0x06,
+ 0xab, 0xa0, 0xb7, 0xc6, 0xcb, 0xc6, 0xbb, 0x81, 0xbc, 0x05, 0xad, 0x9e,
+ 0xb5, 0xc6, 0xcd, 0xcf, 0xa3, 0xd0, 0x03, 0xcf, 0xcb, 0xb3, 0x06, 0x81,
+ 0x00, 0x05, 0x45, 0x9c, 0xb7, 0xc6, 0xce, 0xcf, 0x92, 0xd0, 0x03, 0xce,
+ 0xc9, 0xc0, 0xb9, 0x85, 0xbc, 0x10, 0xb1, 0x85, 0x68, 0x76, 0x84, 0x8e,
+ 0x98, 0x9e, 0xa3, 0xa4, 0xa3, 0x9f, 0x99, 0x90, 0x86, 0x92, 0xb1, 0x80,
+ 0xbc, 0x01, 0xb4, 0xb3, 0x82, 0xbc, 0x05, 0xad, 0x7e, 0xa2, 0xbd, 0xca,
+ 0xcf, 0x99, 0xd0, 0x03, 0xcf, 0xcc, 0xc4, 0xb9, 0x90, 0xbc, 0x06, 0xab,
+ 0x93, 0xb0, 0xc2, 0xc8, 0xc0, 0xbb, 0x8e, 0xbc, 0x06, 0xad, 0x92, 0xaf,
+ 0xc2, 0xc7, 0xbf, 0xbb, 0x81, 0xbc, 0x05, 0xac, 0x8d, 0xab, 0xc2, 0xcc,
+ 0xcf, 0xa3, 0xd0, 0x02, 0xce, 0xc8, 0x8a, 0x82, 0x00, 0x05, 0x4d, 0x93,
+ 0xb3, 0xc5, 0xcd, 0xcf, 0x91, 0xd0, 0x03, 0xcf, 0xcc, 0xc3, 0xb9, 0x84,
+ 0xbc, 0x16, 0xba, 0x93, 0x6d, 0x76, 0x88, 0x99, 0xa5, 0xaf, 0xb6, 0xbb,
+ 0xbd, 0xbf, 0xbe, 0xbb, 0xb7, 0xb0, 0xa5, 0x98, 0x8d, 0xa4, 0xbc, 0xb5,
+ 0xb4, 0x83, 0xbc, 0x05, 0xb1, 0x7f, 0x9c, 0xb9, 0xc8, 0xce, 0x99, 0xd0,
+ 0x02, 0xcf, 0xcb, 0xbe, 0x91, 0xbc, 0x05, 0x8f, 0x91, 0xae, 0xc2, 0xc5,
+ 0xba, 0x8f, 0xbc, 0x05, 0x92, 0x90, 0xad, 0xc1, 0xc5, 0xb9, 0x82, 0xbc,
+ 0x05, 0x9d, 0x85, 0xa7, 0xc0, 0xcb, 0xcf, 0xa2, 0xd0, 0x03, 0xcf, 0xcd,
+ 0xc5, 0x64, 0x82, 0x00, 0x05, 0x5d, 0x92, 0xb3, 0xc5, 0xcd, 0xcf, 0x90,
+ 0xd0, 0x03, 0xcf, 0xcd, 0xc6, 0xba, 0x84, 0xbc, 0x0a, 0xba, 0x7d, 0x6a,
+ 0x80, 0x95, 0xa7, 0xb4, 0xbe, 0xc3, 0xc6, 0xc9, 0x80, 0xcb, 0x08, 0xca,
+ 0xc7, 0xc4, 0xbe, 0xb3, 0xa3, 0x8c, 0xa8, 0xb7, 0x84, 0xbc, 0x05, 0xba,
+ 0x8b, 0x95, 0xb4, 0xc6, 0xcd, 0x95, 0xd0, 0x00, 0xcf, 0x80, 0xd0, 0x02,
+ 0xce, 0xc8, 0xba, 0x8d, 0xbc, 0x09, 0xba, 0xa6, 0x92, 0x83, 0x82, 0x9b,
+ 0xb4, 0xc3, 0xc3, 0xb7, 0x8b, 0xbc, 0x09, 0xb9, 0xa5, 0x92, 0x83, 0x81,
+ 0x9b, 0xb4, 0xc2, 0xc2, 0xb6, 0x82, 0xbc, 0x05, 0x8e, 0x84, 0xa8, 0xc0,
+ 0xcc, 0xcf, 0x89, 0xd0, 0x01, 0xcf, 0xcf, 0x94, 0xd0, 0x03, 0xcf, 0xcc,
+ 0xc2, 0x42, 0x81, 0x00, 0x05, 0x03, 0x6f, 0x95, 0xb4, 0xc6, 0xcd, 0x91,
+ 0xd0, 0x03, 0xcf, 0xcb, 0xc0, 0xba, 0x84, 0xbc, 0x0a, 0x87, 0x6d, 0x86,
+ 0x9e, 0xb1, 0xbd, 0xc6, 0xca, 0xcc, 0xcd, 0xce, 0x80, 0xcf, 0x07, 0xce,
+ 0xce, 0xcc, 0xc8, 0xc1, 0xb2, 0xad, 0xb8, 0x86, 0xbc, 0x05, 0xa0, 0x8d,
+ 0xae, 0xc2, 0xcc, 0xcf, 0x8a, 0xd0, 0x01, 0xcf, 0xcf, 0x80, 0xce, 0x80,
+ 0xcf, 0x00, 0xce, 0x80, 0xcd, 0x04, 0xce, 0xcf, 0xcd, 0xc6, 0xb8, 0x82,
+ 0xbc, 0x04, 0x88, 0x5a, 0x66, 0x6f, 0x72, 0x83, 0x73, 0x09, 0x76, 0x7a,
+ 0x80, 0x8b, 0x9b, 0xae, 0xbf, 0xc6, 0xc2, 0xb6, 0x82, 0xbc, 0x04, 0x71,
+ 0x5d, 0x69, 0x70, 0x72, 0x81, 0x73, 0x09, 0x76, 0x7a, 0x80, 0x8a, 0x9b,
+ 0xae, 0xbf, 0xc6, 0xc1, 0xb4, 0x82, 0xbc, 0x04, 0x7f, 0x88, 0xab, 0xc2,
+ 0xcc, 0x80, 0xcf, 0x80, 0xce, 0x81, 0xcf, 0x01, 0xce, 0xce, 0x81, 0xcd,
+ 0x02, 0xce, 0xcf, 0xcf, 0x8c, 0xd0, 0x81, 0xcf, 0x03, 0xcd, 0xc9, 0xbe,
+ 0x21, 0x81, 0x00, 0x05, 0x11, 0x76, 0x9a, 0xb8, 0xc8, 0xce, 0x91, 0xd0,
+ 0x02, 0xcd, 0xc7, 0xb9, 0x84, 0xbc, 0x09, 0x8f, 0x6c, 0x86, 0xa1, 0xb4,
+ 0xc2, 0xc9, 0xcc, 0xce, 0xcf, 0x83, 0xd0, 0x05, 0xcf, 0xce, 0xcb, 0xc2,
+ 0xb8, 0xba, 0x87, 0xbc, 0x05, 0xaa, 0x84, 0xa7, 0xc0, 0xcb, 0xcf, 0x89,
+ 0xd0, 0x11, 0xcf, 0xcd, 0xcb, 0xc8, 0xc8, 0xc9, 0xcb, 0xcc, 0xcb, 0xc8,
+ 0xc6, 0xc5, 0xc6, 0xc9, 0xcc, 0xcb, 0xc3, 0xb5, 0x82, 0xbc, 0x05, 0x7d,
+ 0x6e, 0x83, 0x91, 0x97, 0x98, 0x82, 0x99, 0x09, 0x9b, 0x9e, 0xa3, 0xab,
+ 0xb4, 0xc0, 0xc7, 0xc9, 0xc0, 0xb7, 0x82, 0xbc, 0x05, 0x6a, 0x73, 0x87,
+ 0x93, 0x98, 0x98, 0x80, 0x99, 0x09, 0x9b, 0x9e, 0xa3, 0xab, 0xb4, 0xc0,
+ 0xc6, 0xc9, 0xc0, 0xb6, 0x82, 0xbc, 0x0b, 0x77, 0x8e, 0xb0, 0xc4, 0xcc,
+ 0xce, 0xcd, 0xcb, 0xc8, 0xc7, 0xc8, 0xcb, 0x80, 0xcc, 0x09, 0xca, 0xc7,
+ 0xc6, 0xc4, 0xc5, 0xc6, 0xc9, 0xcc, 0xcd, 0xcf, 0x88, 0xd0, 0x0a, 0xcf,
+ 0xcf, 0xce, 0xcd, 0xcc, 0xcb, 0xca, 0xc7, 0xc2, 0xb3, 0x06, 0x81, 0x00,
+ 0x05, 0x21, 0x7a, 0x9f, 0xbc, 0xca, 0xce, 0x90, 0xd0, 0x03, 0xcf, 0xcc,
+ 0xc2, 0xb9, 0x83, 0xbc, 0x08, 0xa5, 0x66, 0x82, 0x9e, 0xb5, 0xc3, 0xcb,
+ 0xce, 0xcf, 0x86, 0xd0, 0x03, 0xce, 0xc8, 0xbd, 0xbb, 0x88, 0xbc, 0x05,
+ 0xb0, 0x7e, 0xa0, 0xbb, 0xc9, 0xce, 0x88, 0xd0, 0x12, 0xcf, 0xcc, 0xc6,
+ 0xa7, 0x79, 0xa9, 0xbc, 0xc0, 0xc2, 0xb4, 0x87, 0x5d, 0x73, 0xa7, 0xbb,
+ 0xc3, 0xc6, 0xc0, 0xb6, 0x82, 0xbc, 0x05, 0x73, 0x7e, 0x98, 0xa9, 0xb0,
+ 0xb2, 0x83, 0xb3, 0x08, 0xb5, 0xba, 0xbf, 0xc4, 0xc9, 0xcc, 0xca, 0xbe,
+ 0xb9, 0x81, 0xbc, 0x05, 0xb7, 0x67, 0x84, 0x9e, 0xab, 0xb1, 0x81, 0xb3,
+ 0x09, 0xb4, 0xb5, 0xba, 0xbf, 0xc4, 0xc9, 0xcc, 0xca, 0xbd, 0xb9, 0x81,
+ 0xbc, 0x1b, 0xb8, 0x70, 0x94, 0xb4, 0xc6, 0xcc, 0xcc, 0xc6, 0xa1, 0x71,
+ 0x9b, 0xbb, 0xc0, 0xc4, 0xc5, 0xc2, 0xac, 0x86, 0x63, 0x70, 0x8e, 0xac,
+ 0xbb, 0xc1, 0xc6, 0xcc, 0xce, 0xcf, 0x84, 0xd0, 0x0b, 0xcf, 0xcf, 0xcd,
+ 0xcb, 0xc8, 0xc5, 0xc1, 0xbe, 0xbb, 0xab, 0x92, 0x69, 0x82, 0x00, 0x05,
+ 0x32, 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0x90, 0xd0, 0x02, 0xce, 0xc8, 0xba,
+ 0x84, 0xbc, 0x07, 0x7f, 0x79, 0x98, 0xb2, 0xc2, 0xcb, 0xce, 0xcf, 0x87,
+ 0xd0, 0x08, 0xcd, 0xc7, 0xbb, 0xb3, 0xb1, 0xaf, 0xb1, 0xb5, 0xbb, 0x83,
+ 0xbc, 0x05, 0xb7, 0x89, 0x9a, 0xb7, 0xc7, 0xce, 0x87, 0xd0, 0x0a, 0xcf,
+ 0xcc, 0xc6, 0x35, 0x00, 0x00, 0x03, 0x96, 0xa8, 0x49, 0x01, 0x80, 0x00,
+ 0x05, 0x03, 0x92, 0xb4, 0xbf, 0xbb, 0xb7, 0x82, 0xbc, 0x04, 0x68, 0x82,
+ 0x9b, 0xaa, 0xb0, 0x82, 0xb2, 0x09, 0xb3, 0xb3, 0xb5, 0xbb, 0xc1, 0xc7,
+ 0xcc, 0xcd, 0xc9, 0xba, 0x82, 0xbc, 0x05, 0xa9, 0x6b, 0x88, 0xa0, 0xac,
+ 0xb1, 0x80, 0xb2, 0x09, 0xb3, 0xb4, 0xb7, 0xbc, 0xc2, 0xc8, 0xcc, 0xcd,
+ 0xc9, 0xba, 0x82, 0xbc, 0x07, 0xa9, 0x76, 0x9b, 0xb8, 0xc7, 0xcb, 0xc2,
+ 0x25, 0x80, 0x00, 0x04, 0x60, 0xab, 0xb1, 0x6d, 0x15, 0x82, 0x00, 0x06,
+ 0x07, 0x53, 0xa7, 0xb8, 0xc3, 0xcb, 0xce, 0x83, 0xd0, 0x09, 0xcf, 0xcd,
+ 0xcb, 0xc6, 0xc0, 0x8d, 0x46, 0x29, 0x17, 0x04, 0x85, 0x00, 0x05, 0x46,
+ 0x87, 0xab, 0xc2, 0xcc, 0xcf, 0x8f, 0xd0, 0x03, 0xcf, 0xcc, 0xc4, 0xb7,
+ 0x83, 0xbc, 0x06, 0xa8, 0x6a, 0x8a, 0xa9, 0xbf, 0xca, 0xce, 0x89, 0xd0,
+ 0x15, 0xce, 0xc8, 0xbd, 0xab, 0x99, 0x8a, 0x7f, 0x81, 0x88, 0x97, 0xa7,
+ 0xae, 0xb2, 0xba, 0xbc, 0xbc, 0x9e, 0x97, 0xb3, 0xc6, 0xcd, 0xcf, 0x86,
+ 0xd0, 0x02, 0xce, 0xc9, 0x89, 0x81, 0x00, 0x01, 0x47, 0x22, 0x83, 0x00,
+ 0x04, 0x47, 0xa3, 0xb4, 0xb3, 0xba, 0x8d, 0xbc, 0x08, 0xbb, 0xb5, 0xaf,
+ 0xb4, 0xc0, 0xc9, 0xcc, 0xc7, 0xb8, 0x8c, 0xbc, 0x08, 0xba, 0xb3, 0xae,
+ 0xb6, 0xc2, 0xcb, 0xcc, 0xc7, 0xb8, 0x82, 0xbc, 0x06, 0x98, 0x7a, 0x9f,
+ 0xbb, 0xc8, 0xc7, 0x7d, 0x81, 0x00, 0x02, 0x1b, 0x6f, 0x1e, 0x86, 0x00,
+ 0x05, 0x17, 0x98, 0xb4, 0xc2, 0xcb, 0xce, 0x80, 0xd0, 0x06, 0xcf, 0xce,
+ 0xcc, 0xc6, 0xb1, 0x64, 0x1a, 0x8a, 0x00, 0x05, 0x5a, 0x8e, 0xaf, 0xc4,
+ 0xcc, 0xcf, 0x8f, 0xd0, 0x03, 0xcf, 0xcb, 0xc0, 0xba, 0x83, 0xbc, 0x06,
+ 0x80, 0x7a, 0x9b, 0xb6, 0xc6, 0xcd, 0xcf, 0x89, 0xd0, 0x15, 0xce, 0xcb,
+ 0xc4, 0xbb, 0xb0, 0xa7, 0xa0, 0x9b, 0x95, 0x8e, 0x86, 0x7f, 0x7e, 0x88,
+ 0x9d, 0xab, 0xa9, 0x99, 0xb3, 0xc5, 0xcc, 0xcf, 0x85, 0xd0, 0x03, 0xcf,
+ 0xcd, 0xc4, 0x37, 0x89, 0x00, 0x03, 0x3a, 0x97, 0xad, 0xb0, 0x90, 0xbc,
+ 0x06, 0xb8, 0x9e, 0xb4, 0xc3, 0xca, 0xc5, 0xb5, 0x8e, 0xbc, 0x06, 0xb1,
+ 0xa3, 0xb8, 0xc6, 0xcb, 0xc5, 0xb6, 0x82, 0xbc, 0x06, 0x8c, 0x82, 0xa5,
+ 0xbf, 0xc7, 0xc2, 0x2b, 0x81, 0x00, 0x01, 0x01, 0x01, 0x88, 0x00, 0x0c,
+ 0x35, 0x9f, 0xb6, 0xc6, 0xcc, 0xcf, 0xd0, 0xcf, 0xce, 0xca, 0xc3, 0x60,
+ 0x04, 0x8b, 0x00, 0x05, 0x03, 0x6f, 0x94, 0xb4, 0xc6, 0xcd, 0x90, 0xd0,
+ 0x03, 0xce, 0xc9, 0xbc, 0xbb, 0x82, 0xbc, 0x06, 0xbb, 0x6f, 0x87, 0xa9,
+ 0xc0, 0xcb, 0xcf, 0x8a, 0xd0, 0x15, 0xcf, 0xce, 0xcb, 0xc6, 0xc2, 0xbf,
+ 0xbc, 0xb9, 0xb4, 0xaf, 0xa9, 0xa3, 0x9c, 0x96, 0x8f, 0x8d, 0x94, 0xa5,
+ 0xb9, 0xc6, 0xcd, 0xcf, 0x85, 0xd0, 0x03, 0xcf, 0xcc, 0xc0, 0x13, 0x88,
+ 0x00, 0x04, 0x04, 0x63, 0x95, 0xab, 0xb0, 0x91, 0xbc, 0x05, 0x93, 0xa8,
+ 0xbf, 0xc7, 0xc2, 0xb6, 0x8e, 0xbc, 0x06, 0xb9, 0x91, 0xad, 0xc2, 0xc8,
+ 0xc2, 0xb5, 0x82, 0xbc, 0x06, 0x7f, 0x88, 0xab, 0xc1, 0xc6, 0xbd, 0x08,
+ 0x8f, 0x00, 0x09, 0x71, 0xa8, 0xbf, 0xca, 0xce, 0xcf, 0xce, 0xca, 0xbb,
+ 0x3f, 0x8d, 0x00, 0x05, 0x11, 0x76, 0x9a, 0xb8, 0xc8, 0xce, 0x90, 0xd0,
+ 0x02, 0xce, 0xc7, 0xb8, 0x83, 0xbc, 0x06, 0xac, 0x6f, 0x93, 0xb3, 0xc5,
+ 0xcd, 0xcf, 0x8b, 0xd0, 0x13, 0xcf, 0xce, 0xcd, 0xcc, 0xcb, 0xca, 0xc8,
+ 0xc6, 0xc3, 0xc0, 0xbb, 0xb5, 0xaf, 0xa9, 0xa5, 0xa9, 0xb4, 0xc0, 0xc9,
+ 0xce, 0x86, 0xd0, 0x02, 0xce, 0xca, 0xb2, 0x87, 0x00, 0x06, 0x07, 0x22,
+ 0x57, 0x85, 0x9e, 0xae, 0xb1, 0x90, 0xbc, 0x06, 0xb5, 0x84, 0xa4, 0xbc,
+ 0xc6, 0xc0, 0xb6, 0x8e, 0xbc, 0x06, 0xa6, 0x8a, 0xab, 0xc0, 0xc6, 0xc0,
+ 0xb7, 0x82, 0xbc, 0x05, 0x75, 0x8e, 0xaf, 0xc2, 0xc6, 0xa2, 0x85, 0x00,
+ 0x04, 0x12, 0x25, 0x35, 0x2e, 0x0d, 0x83, 0x00, 0x08, 0x48, 0x9a, 0xb6,
+ 0xc6, 0xcd, 0xce, 0xca, 0xb2, 0x24, 0x87, 0x00, 0x01, 0x0a, 0x17, 0x82,
+ 0x00, 0x05, 0x21, 0x7a, 0x9f, 0xbc, 0xca, 0xcf, 0x8f, 0xd0, 0x03, 0xcf,
+ 0xcd, 0xc5, 0xb6, 0x83, 0xbc, 0x05, 0x9d, 0x76, 0x9b, 0xb9, 0xc8, 0xce,
+ 0x8e, 0xd0, 0x81, 0xcf, 0x0d, 0xce, 0xcd, 0xcc, 0xc8, 0xc3, 0xbb, 0xb5,
+ 0xb2, 0xab, 0xb0, 0xb9, 0xc3, 0xcb, 0xce, 0x86, 0xd0, 0x02, 0xce, 0xc7,
+ 0x8f, 0x83, 0x00, 0x0a, 0x14, 0x3c, 0x5c, 0x6c, 0x74, 0x7e, 0x8a, 0x9e,
+ 0xae, 0xb4, 0xb4, 0x8e, 0xbc, 0x08, 0xad, 0x9b, 0x82, 0x8d, 0xa9, 0xbf,
+ 0xc5, 0xbd, 0xb9, 0x8b, 0xbc, 0x09, 0xba, 0xa9, 0x99, 0x7f, 0x93, 0xaf,
+ 0xc2, 0xc6, 0xbc, 0xba, 0x81, 0xbc, 0x06, 0xb7, 0x70, 0x95, 0xb4, 0xc4,
+ 0xc4, 0x81, 0x83, 0x00, 0x07, 0x07, 0x3c, 0x69, 0x76, 0x7e, 0x80, 0x76,
+ 0x19, 0x82, 0x00, 0x07, 0x2d, 0x8e, 0xaf, 0xc3, 0xcc, 0xcb, 0xc2, 0x32,
+ 0x84, 0x00, 0x05, 0x0a, 0x34, 0x4c, 0x63, 0x6d, 0x5b, 0x82, 0x00, 0x05,
+ 0x32, 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0x8f, 0xd0, 0x03, 0xcf, 0xcd, 0xc4,
+ 0xb5, 0x83, 0xbc, 0x05, 0x8f, 0x7e, 0xa1, 0xbd, 0xca, 0xcf, 0x93, 0xd0,
+ 0x0d, 0xcf, 0xcc, 0xc6, 0xbc, 0xba, 0xbb, 0xba, 0xb4, 0xab, 0xaf, 0xbe,
+ 0xc8, 0xcd, 0xcf, 0x85, 0xd0, 0x02, 0xcd, 0xc6, 0x6f, 0x82, 0x00, 0x0b,
+ 0x12, 0x5b, 0x72, 0x84, 0x91, 0x99, 0xa1, 0xab, 0xb4, 0xbc, 0xb8, 0xb9,
+ 0x81, 0xbc, 0x04, 0xba, 0x64, 0x6c, 0x74, 0x79, 0x83, 0x7a, 0x09, 0x7c,
+ 0x76, 0x76, 0x7f, 0x8d, 0xa1, 0xb5, 0xc3, 0xc6, 0xba, 0x82, 0xbc, 0x04,
+ 0xa5, 0x64, 0x6d, 0x76, 0x79, 0x81, 0x7a, 0x09, 0x7c, 0x75, 0x77, 0x82,
+ 0x91, 0xa6, 0xba, 0xc6, 0xc6, 0xbb, 0x82, 0xbc, 0x06, 0xa7, 0x76, 0x9b,
+ 0xb8, 0xc6, 0xc2, 0x60, 0x82, 0x00, 0x08, 0x03, 0x4a, 0x70, 0x86, 0x97,
+ 0xa0, 0xa2, 0x9b, 0x5f, 0x82, 0x00, 0x06, 0x22, 0x88, 0xab, 0xc1, 0xc9,
+ 0xc5, 0x5f, 0x83, 0x00, 0x07, 0x04, 0x30, 0x64, 0x76, 0x83, 0x8c, 0x8e,
+ 0x5d, 0x82, 0x00, 0x05, 0x46, 0x88, 0xab, 0xc2, 0xcc, 0xcf, 0x8f, 0xd0,
+ 0x03, 0xcf, 0xcc, 0xc3, 0xb5, 0x83, 0xbc, 0x05, 0x92, 0x82, 0xa5, 0xbf,
+ 0xcb, 0xcf, 0x93, 0xd0, 0x03, 0xce, 0xc9, 0xbe, 0xbb, 0x81, 0xbc, 0x05,
+ 0xb4, 0x9d, 0xb0, 0xc2, 0xcb, 0xcf, 0x84, 0xd0, 0x03, 0xcf, 0xcc, 0xc3,
+ 0x4f, 0x82, 0x00, 0x0a, 0x3b, 0x73, 0x8e, 0xa3, 0xb0, 0xb7, 0xbc, 0xc1,
+ 0xc5, 0xc4, 0xb8, 0x82, 0xbc, 0x05, 0xab, 0x60, 0x77, 0x89, 0x91, 0x93,
+ 0x82, 0x94, 0x09, 0x95, 0x97, 0x9b, 0xa1, 0xab, 0xb7, 0xc2, 0xc8, 0xc6,
+ 0xb8, 0x82, 0xbc, 0x05, 0x93, 0x66, 0x7c, 0x8a, 0x91, 0x93, 0x80, 0x94,
+ 0x09, 0x95, 0x98, 0x9c, 0xa4, 0xad, 0xba, 0xc4, 0xca, 0xc6, 0xb7, 0x82,
+ 0xbc, 0x06, 0x97, 0x7c, 0xa0, 0xbb, 0xc6, 0xc1, 0x40, 0x82, 0x00, 0x08,
+ 0x30, 0x6e, 0x8a, 0xa2, 0xb3, 0xbb, 0xbb, 0xb3, 0x86, 0x82, 0x00, 0x06,
+ 0x29, 0x85, 0xa8, 0xbf, 0xc5, 0x92, 0x01, 0x82, 0x00, 0x08, 0x15, 0x57,
+ 0x72, 0x86, 0x98, 0xa5, 0xab, 0xab, 0x53, 0x82, 0x00, 0x05, 0x5b, 0x8e,
+ 0xaf, 0xc4, 0xcc, 0xcf, 0x8f, 0xd0, 0x03, 0xcf, 0xcc, 0xc2, 0xb3, 0x83,
+ 0xbc, 0x05, 0x98, 0x82, 0xa6, 0xc0, 0xcc, 0xcf, 0x92, 0xd0, 0x03, 0xcf,
+ 0xcd, 0xc5, 0xb9, 0x83, 0xbc, 0x04, 0x9f, 0xa0, 0xba, 0xc8, 0xce, 0x84,
+ 0xd0, 0x03, 0xcf, 0xcc, 0xc0, 0x31, 0x82, 0x00, 0x0a, 0x5d, 0x86, 0xa4,
+ 0xb9, 0xc3, 0xc7, 0xca, 0xcc, 0xcc, 0xc6, 0xb8, 0x82, 0xbc, 0x04, 0x9b,
+ 0x71, 0x8f, 0xa5, 0xb0, 0x84, 0xb4, 0x08, 0xb6, 0xb9, 0xbc, 0xc1, 0xc6,
+ 0xcb, 0xcc, 0xc5, 0xb6, 0x82, 0xbc, 0x04, 0x87, 0x77, 0x95, 0xa8, 0xb1,
+ 0x81, 0xb4, 0x09, 0xb5, 0xb6, 0xba, 0xbe, 0xc2, 0xc7, 0xcb, 0xcc, 0xc5,
+ 0xb6, 0x82, 0xbc, 0x06, 0x8a, 0x82, 0xa5, 0xbf, 0xc6, 0xbf, 0x22, 0x81,
+ 0x00, 0x09, 0x03, 0x5f, 0x82, 0xa0, 0xb7, 0xc3, 0xc8, 0xc7, 0xc0, 0x86,
+ 0x82, 0x00, 0x05, 0x2f, 0x85, 0xa8, 0xbd, 0xc0, 0x35, 0x82, 0x00, 0x09,
+ 0x08, 0x59, 0x77, 0x90, 0xa4, 0xb4, 0xbd, 0xc0, 0xb9, 0x3c, 0x81, 0x00,
+ 0x05, 0x03, 0x6f, 0x94, 0xb4, 0xc6, 0xcd, 0x90, 0xd0, 0x03, 0xcf, 0xcc,
+ 0xc3, 0xb4, 0x83, 0xbc, 0x05, 0x9e, 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0x92,
+ 0xd0, 0x03, 0xcf, 0xcc, 0xc0, 0xb9, 0x83, 0xbc, 0x04, 0x95, 0x96, 0xb4,
+ 0xc6, 0xcd, 0x84, 0xd0, 0x03, 0xcf, 0xcb, 0xbe, 0x15, 0x81, 0x00, 0x0b,
+ 0x11, 0x70, 0x94, 0xb2, 0xc3, 0xcc, 0xce, 0xcf, 0xcf, 0xcc, 0xc6, 0xb6,
+ 0x82, 0xbc, 0x04, 0x8e, 0x7e, 0x9e, 0xb7, 0xc2, 0x84, 0xc6, 0x08, 0xc7,
+ 0xc8, 0xca, 0xcc, 0xcd, 0xce, 0xcc, 0xc2, 0xb5, 0x82, 0xbc, 0x04, 0x7c,
+ 0x86, 0xa5, 0xbb, 0xc3, 0x82, 0xc6, 0x08, 0xc7, 0xc9, 0xca, 0xcc, 0xcd,
+ 0xce, 0xcc, 0xc2, 0xb5, 0x82, 0xbc, 0x06, 0x7e, 0x89, 0xab, 0xc1, 0xc6,
+ 0xbb, 0x07, 0x81, 0x00, 0x09, 0x1a, 0x71, 0x93, 0xb1, 0xc2, 0xcb, 0xcd,
+ 0xcc, 0xc3, 0x77, 0x82, 0x00, 0x05, 0x3f, 0x88, 0xa9, 0xbb, 0xa2, 0x01,
+ 0x81, 0x00, 0x0a, 0x01, 0x46, 0x76, 0x92, 0xab, 0xbb, 0xc4, 0xc9, 0xc7,
+ 0xbd, 0x21, 0x81, 0x00, 0x05, 0x11, 0x76, 0x9b, 0xb8, 0xc8, 0xce, 0x90,
+ 0xd0, 0x03, 0xcf, 0xcc, 0xc4, 0xb4, 0x83, 0xbc, 0x05, 0xa4, 0x7e, 0xa2,
+ 0xbd, 0xcb, 0xcf, 0x92, 0xd0, 0x03, 0xce, 0xc9, 0xbb, 0xbb, 0x82, 0xbc,
+ 0x05, 0xbb, 0x76, 0x93, 0xb3, 0xc6, 0xcd, 0x84, 0xd0, 0x03, 0xce, 0xc9,
+ 0xb3, 0x01, 0x81, 0x00, 0x0b, 0x29, 0x7a, 0x9e, 0xba, 0xc8, 0xce, 0xd0,
+ 0xd0, 0xcf, 0xcc, 0xc3, 0xb5, 0x82, 0xbc, 0x04, 0x83, 0x86, 0xa8, 0xc0,
+ 0xca, 0x83, 0xcd, 0x80, 0xce, 0x81, 0xcf, 0x02, 0xcc, 0xc0, 0xb6, 0x82,
+ 0xbc, 0x04, 0x74, 0x8e, 0xaf, 0xc2, 0xcb, 0x81, 0xcd, 0x80, 0xce, 0x06,
+ 0xcf, 0xcf, 0xd0, 0xcf, 0xcc, 0xc0, 0xb7, 0x82, 0xbc, 0x05, 0x75, 0x8f,
+ 0xb0, 0xc2, 0xc6, 0xa1, 0x82, 0x00, 0x09, 0x37, 0x7e, 0xa0, 0xbb, 0xc8,
+ 0xce, 0xcf, 0xcc, 0xc3, 0x5d, 0x82, 0x00, 0x04, 0x52, 0x8c, 0xab, 0xba,
+ 0x52, 0x82, 0x00, 0x0a, 0x22, 0x6d, 0x8b, 0xa8, 0xbc, 0xc7, 0xcc, 0xcd,
+ 0xc9, 0xbb, 0x07, 0x81, 0x00, 0x05, 0x21, 0x7a, 0xa0, 0xbc, 0xca, 0xcf,
+ 0x90, 0xd0, 0x03, 0xcf, 0xcd, 0xc5, 0xb4, 0x83, 0xbc, 0x05, 0xb6, 0x7e,
+ 0x9e, 0xba, 0xc9, 0xce, 0x92, 0xd0, 0x02, 0xcd, 0xc7, 0xb7, 0x83, 0xbc,
+ 0x05, 0xb1, 0x71, 0x96, 0xb4, 0xc6, 0xce, 0x84, 0xd0, 0x02, 0xce, 0xc7,
+ 0x93, 0x82, 0x00, 0x0b, 0x42, 0x84, 0xa7, 0xc0, 0xcb, 0xcf, 0xd0, 0xd0,
+ 0xcf, 0xcc, 0xc1, 0xb5, 0x82, 0xbc, 0x05, 0x78, 0x8d, 0xae, 0xc3, 0xcc,
+ 0xcf, 0x88, 0xd0, 0x03, 0xcf, 0xcb, 0xbe, 0xb9, 0x81, 0xbc, 0x06, 0xb6,
+ 0x70, 0x95, 0xb4, 0xc6, 0xcd, 0xcf, 0x86, 0xd0, 0x03, 0xcf, 0xcb, 0xbd,
+ 0xb9, 0x81, 0xbc, 0x06, 0xb6, 0x70, 0x95, 0xb4, 0xc4, 0xc4, 0x7f, 0x82,
+ 0x00, 0x09, 0x4d, 0x87, 0xa9, 0xc1, 0xcc, 0xcf, 0xcf, 0xcc, 0xc2, 0x40,
+ 0x82, 0x00, 0x04, 0x67, 0x91, 0xae, 0xb7, 0x21, 0x82, 0x00, 0x09, 0x3f,
+ 0x7c, 0x9e, 0xb7, 0xc6, 0xcc, 0xcf, 0xce, 0xc8, 0xa1, 0x82, 0x00, 0x05,
+ 0x32, 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0x91, 0xd0, 0x03, 0xce, 0xc6, 0xb5,
+ 0xb6, 0x83, 0xbc, 0x05, 0x8f, 0x94, 0xb3, 0xc6, 0xcd, 0xcf, 0x90, 0xd0,
+ 0x03, 0xcf, 0xcc, 0xc3, 0xb6, 0x83, 0xbc, 0x05, 0xa2, 0x76, 0x9b, 0xb9,
+ 0xc8, 0xce, 0x84, 0xd0, 0x02, 0xcd, 0xc6, 0x71, 0x82, 0x00, 0x0b, 0x59,
+ 0x8c, 0xae, 0xc3, 0xcc, 0xcf, 0xd0, 0xd0, 0xcf, 0xcb, 0xbf, 0xb8, 0x81,
+ 0xbc, 0x05, 0xbb, 0x70, 0x93, 0xb3, 0xc6, 0xcd, 0x89, 0xd0, 0x02, 0xce,
+ 0xc9, 0xbb, 0x82, 0xbc, 0x05, 0xa5, 0x76, 0x9b, 0xb9, 0xc8, 0xce, 0x87,
+ 0xd0, 0x02, 0xce, 0xc9, 0xba, 0x82, 0xbc, 0x06, 0xa6, 0x76, 0x9b, 0xb8,
+ 0xc6, 0xc2, 0x5f, 0x82, 0x00, 0x09, 0x63, 0x8f, 0xb1, 0xc4, 0xcd, 0xcf,
+ 0xcf, 0xcb, 0xc0, 0x24, 0x81, 0x00, 0x05, 0x0a, 0x72, 0x97, 0xb2, 0xb5,
+ 0x0a, 0x82, 0x00, 0x09, 0x5b, 0x89, 0xab, 0xc0, 0xcb, 0xcf, 0xcf, 0xce,
+ 0xc6, 0x80, 0x82, 0x00, 0x05, 0x47, 0x88, 0xab, 0xc2, 0xcc, 0xcf, 0x91,
+ 0xd0, 0x03, 0xce, 0xc9, 0xbb, 0xb2, 0x83, 0xbc, 0x05, 0xa1, 0x89, 0xab,
+ 0xc0, 0xcb, 0xcf, 0x90, 0xd0, 0x03, 0xce, 0xca, 0xbd, 0xba, 0x83, 0xbc,
+ 0x05, 0x97, 0x7e, 0xa2, 0xbd, 0xcb, 0xcf, 0x83, 0xd0, 0x03, 0xcf, 0xcc,
+ 0xc3, 0x52, 0x81, 0x00, 0x05, 0x03, 0x6d, 0x93, 0xb4, 0xc6, 0xcd, 0x80,
+ 0xd0, 0x03, 0xce, 0xca, 0xbb, 0xbb, 0x81, 0xbc, 0x05, 0xad, 0x73, 0x99,
+ 0xb7, 0xc8, 0xce, 0x89, 0xd0, 0x02, 0xce, 0xc7, 0xb7, 0x82, 0xbc, 0x05,
+ 0x96, 0x7c, 0xa1, 0xbc, 0xca, 0xcf, 0x87, 0xd0, 0x02, 0xce, 0xc7, 0xb7,
+ 0x82, 0xbc, 0x06, 0x97, 0x7c, 0xa0, 0xbb, 0xc6, 0xc1, 0x3f, 0x81, 0x00,
+ 0x0a, 0x07, 0x71, 0x97, 0xb5, 0xc7, 0xce, 0xd0, 0xcf, 0xca, 0xbc, 0x09,
+ 0x81, 0x00, 0x04, 0x19, 0x79, 0x9c, 0xb4, 0xa5, 0x82, 0x00, 0x0a, 0x08,
+ 0x6d, 0x92, 0xb2, 0xc5, 0xcd, 0xcf, 0xcf, 0xcd, 0xc4, 0x5f, 0x82, 0x00,
+ 0x05, 0x5c, 0x8e, 0xb0, 0xc4, 0xcc, 0xcf, 0x91, 0xd0, 0x03, 0xcf, 0xcb,
+ 0xc0, 0xae, 0x84, 0xbc, 0x05, 0x8d, 0x9e, 0xb8, 0xc6, 0xcd, 0xcf, 0x8e,
+ 0xd0, 0x03, 0xcf, 0xcc, 0xc5, 0xb7, 0x84, 0xbc, 0x05, 0x81, 0x86, 0xa9,
+ 0xc1, 0xcc, 0xcf, 0x83, 0xd0, 0x03, 0xcf, 0xcc, 0xc1, 0x34, 0x81, 0x00,
+ 0x05, 0x11, 0x76, 0x9a, 0xb8, 0xc8, 0xce, 0x80, 0xd0, 0x02, 0xce, 0xc8,
+ 0xb8, 0x82, 0xbc, 0x05, 0x9e, 0x7a, 0x9e, 0xbb, 0xc8, 0xcd, 0x86, 0xcf,
+ 0x80, 0xd0, 0x02, 0xcd, 0xc5, 0xb6, 0x82, 0xbc, 0x05, 0x89, 0x82, 0xa6,
+ 0xc0, 0xcc, 0xcf, 0x86, 0xd0, 0x03, 0xcf, 0xcd, 0xc5, 0xb6, 0x82, 0xbc,
+ 0x06, 0x89, 0x82, 0xa6, 0xbf, 0xc6, 0xbf, 0x21, 0x81, 0x00, 0x09, 0x18,
+ 0x77, 0x9c, 0xba, 0xc9, 0xce, 0xd0, 0xce, 0xc8, 0xa5, 0x82, 0x00, 0x04,
+ 0x2a, 0x7e, 0xa1, 0xb6, 0x95, 0x82, 0x00, 0x0a, 0x06, 0x70, 0x95, 0xb4,
+ 0xc6, 0xcd, 0xcf, 0xce, 0xcc, 0xc1, 0x40, 0x81, 0x00, 0x05, 0x03, 0x6f,
+ 0x95, 0xb4, 0xc6, 0xcd, 0x92, 0xd0, 0x04, 0xcf, 0xcc, 0xc3, 0xb0, 0xb6,
+ 0x83, 0xbc, 0x05, 0xac, 0x8d, 0xab, 0xc0, 0xca, 0xce, 0x8e, 0xd0, 0x03,
+ 0xce, 0xc9, 0xbd, 0xb9, 0x83, 0xbc, 0x06, 0xae, 0x6e, 0x91, 0xb1, 0xc4,
+ 0xcd, 0xcf, 0x83, 0xd0, 0x03, 0xcf, 0xcb, 0xbe, 0x18, 0x81, 0x00, 0x05,
+ 0x21, 0x7a, 0x9f, 0xbc, 0xca, 0xce, 0x80, 0xd0, 0x02, 0xcd, 0xc6, 0xb6,
+ 0x82, 0xbc, 0x05, 0x8f, 0x7d, 0x9f, 0xba, 0xc6, 0xca, 0x83, 0xcb, 0x08,
+ 0xcc, 0xcc, 0xcd, 0xce, 0xcf, 0xcf, 0xcc, 0xc2, 0xb5, 0x82, 0xbc, 0x05,
+ 0x7d, 0x89, 0xab, 0xc2, 0xcc, 0xcf, 0x86, 0xd0, 0x03, 0xcf, 0xcc, 0xc2,
+ 0xb5, 0x82, 0xbc, 0x06, 0x7e, 0x89, 0xab, 0xc1, 0xc6, 0xbb, 0x07, 0x81,
+ 0x00, 0x09, 0x28, 0x7e, 0xa2, 0xbd, 0xcb, 0xcf, 0xd0, 0xce, 0xc6, 0x84,
+ 0x82, 0x00, 0x05, 0x3e, 0x85, 0xa7, 0xb9, 0xb1, 0x04, 0x82, 0x00, 0x09,
+ 0x5c, 0x91, 0xb0, 0xc2, 0xc9, 0xcc, 0xcc, 0xc7, 0xbc, 0x23, 0x81, 0x00,
+ 0x05, 0x11, 0x76, 0x9b, 0xb8, 0xc8, 0xce, 0x93, 0xd0, 0x03, 0xcd, 0xc7,
+ 0xb8, 0xae, 0x84, 0xbc, 0x05, 0x9c, 0x99, 0xb3, 0xc3, 0xcb, 0xce, 0x8b,
+ 0xd0, 0x04, 0xcf, 0xce, 0xcb, 0xc2, 0xb8, 0x84, 0xbc, 0x05, 0x8f, 0x7a,
+ 0x9c, 0xb9, 0xc8, 0xce, 0x84, 0xd0, 0x03, 0xce, 0xc9, 0xb4, 0x01, 0x81,
+ 0x00, 0x0b, 0x32, 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0xd0, 0xd0, 0xcf, 0xcc,
+ 0xc3, 0xb5, 0x82, 0xbc, 0x05, 0x7f, 0x7c, 0x9b, 0xb1, 0xbb, 0xbe, 0x82,
+ 0xbf, 0x09, 0xc0, 0xc0, 0xc2, 0xc6, 0xca, 0xcd, 0xce, 0xcc, 0xc0, 0xb7,
+ 0x82, 0xbc, 0x05, 0x74, 0x8f, 0xb1, 0xc4, 0xcd, 0xcf, 0x86, 0xd0, 0x03,
+ 0xcf, 0xcc, 0xc0, 0xb6, 0x82, 0xbc, 0x05, 0x73, 0x8f, 0xb0, 0xc3, 0xc6,
+ 0xa0, 0x82, 0x00, 0x09, 0x3b, 0x84, 0xa8, 0xc0, 0xcc, 0xcf, 0xcf, 0xcd,
+ 0xc5, 0x64, 0x82, 0x00, 0x05, 0x52, 0x8b, 0xab, 0xbc, 0xb6, 0x24, 0x82,
+ 0x00, 0x09, 0x10, 0x76, 0xa0, 0xb4, 0xbd, 0xc1, 0xc2, 0xbe, 0xb3, 0x08,
+ 0x81, 0x00, 0x05, 0x21, 0x7a, 0xa0, 0xbc, 0xca, 0xcf, 0x93, 0xd0, 0x04,
+ 0xcf, 0xcb, 0xc0, 0xab, 0xb9, 0x83, 0xbc, 0x07, 0xbb, 0x9b, 0xa0, 0xb6,
+ 0xc4, 0xcb, 0xce, 0xcf, 0x88, 0xd0, 0x04, 0xcf, 0xce, 0xcb, 0xc2, 0xb8,
+ 0x84, 0xbc, 0x06, 0xb3, 0x70, 0x89, 0xa9, 0xc0, 0xcb, 0xcf, 0x84, 0xd0,
+ 0x02, 0xce, 0xc7, 0x96, 0x82, 0x00, 0x0b, 0x47, 0x88, 0xab, 0xc2, 0xcc,
+ 0xcf, 0xd0, 0xd0, 0xcf, 0xcc, 0xc1, 0xb7, 0x82, 0xbc, 0x04, 0xa2, 0xa4,
+ 0xab, 0xb1, 0xb3, 0x84, 0xb4, 0x08, 0xb3, 0xb2, 0xb7, 0xc0, 0xc7, 0xcc,
+ 0xca, 0xbd, 0xb9, 0x81, 0xbc, 0x05, 0xb4, 0x71, 0x96, 0xb5, 0xc6, 0xce,
+ 0x87, 0xd0, 0x03, 0xcf, 0xcb, 0xbd, 0xb9, 0x81, 0xbc, 0x06, 0xb4, 0x71,
+ 0x96, 0xb4, 0xc5, 0xc4, 0x7e, 0x82, 0x00, 0x09, 0x4f, 0x8a, 0xac, 0xc2,
+ 0xcc, 0xcf, 0xcf, 0xcc, 0xc2, 0x46, 0x82, 0x00, 0x05, 0x69, 0x92, 0xb1,
+ 0xc0, 0xbb, 0x48, 0x83, 0x00, 0x07, 0x01, 0x25, 0x4d, 0x5f, 0x6d, 0x6d,
+ 0x66, 0x53, 0x82, 0x00, 0x05, 0x34, 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0x93,
+ 0xd0, 0x04, 0xcf, 0xcd, 0xc5, 0xb4, 0xa9, 0x84, 0xbc, 0x08, 0xb9, 0x9b,
+ 0xa2, 0xb6, 0xc2, 0xca, 0xcd, 0xcf, 0xcf, 0x84, 0xd0, 0x05, 0xcf, 0xce,
+ 0xcd, 0xc9, 0xc2, 0xb8, 0x85, 0xbc, 0x06, 0x87, 0x77, 0x99, 0xb4, 0xc6,
+ 0xcd, 0xcf, 0x84, 0xd0, 0x02, 0xcd, 0xc6, 0x76, 0x82, 0x00, 0x0b, 0x5d,
+ 0x8e, 0xb0, 0xc4, 0xcc, 0xcf, 0xd0, 0xd0, 0xcf, 0xcb, 0xbf, 0xb8, 0x90,
+ 0xbc, 0x05, 0xaa, 0xae, 0xbf, 0xc8, 0xc7, 0xba, 0x82, 0xbc, 0x05, 0xa5,
+ 0x76, 0x9c, 0xba, 0xc8, 0xce, 0x87, 0xd0, 0x02, 0xce, 0xc9, 0xba, 0x82,
+ 0xbc, 0x06, 0xa5, 0x76, 0x9c, 0xb9, 0xc6, 0xc3, 0x5d, 0x82, 0x00, 0x09,
+ 0x66, 0x91, 0xb2, 0xc5, 0xcd, 0xcf, 0xcf, 0xcc, 0xc0, 0x29, 0x81, 0x00,
+ 0x06, 0x0a, 0x73, 0x98, 0xb5, 0xc3, 0xc0, 0x7c, 0x90, 0x00, 0x05, 0x48,
+ 0x88, 0xab, 0xc2, 0xcc, 0xcf, 0x94, 0xd0, 0x04, 0xce, 0xca, 0xbf, 0xa8,
+ 0xb2, 0x84, 0xbc, 0x08, 0xba, 0xa5, 0xa1, 0xb3, 0xbf, 0xc6, 0xcb, 0xcd,
+ 0xce, 0x82, 0xcf, 0x05, 0xce, 0xcc, 0xca, 0xc6, 0xbe, 0xb8, 0x85, 0xbc,
+ 0x06, 0xa9, 0x6c, 0x8a, 0xa9, 0xbf, 0xca, 0xce, 0x84, 0xd0, 0x03, 0xcf,
+ 0xcc, 0xc4, 0x56, 0x81, 0x00, 0x05, 0x04, 0x71, 0x96, 0xb5, 0xc6, 0xcd,
+ 0x80, 0xd0, 0x02, 0xcf, 0xca, 0xbd, 0x91, 0xbc, 0x05, 0xb1, 0x9b, 0xb4,
+ 0xc3, 0xc5, 0xb8, 0x82, 0xbc, 0x05, 0x94, 0x7f, 0xa3, 0xbe, 0xca, 0xcf,
+ 0x87, 0xd0, 0x02, 0xce, 0xc8, 0xb8, 0x82, 0xbc, 0x06, 0x94, 0x7f, 0xa3,
+ 0xbd, 0xc6, 0xc2, 0x3f, 0x81, 0x00, 0x0a, 0x09, 0x73, 0x98, 0xb7, 0xc7,
+ 0xce, 0xd0, 0xcf, 0xcb, 0xbe, 0x0e, 0x81, 0x00, 0x07, 0x1a, 0x7a, 0x9e,
+ 0xbb, 0xc6, 0xc3, 0xb3, 0x2f, 0x8f, 0x00, 0x05, 0x5d, 0x8f, 0xb1, 0xc4,
+ 0xcd, 0xcf, 0x94, 0xd0, 0x05, 0xcf, 0xcc, 0xc6, 0xb6, 0xa2, 0xb4, 0x85,
+ 0xbc, 0x07, 0xaf, 0xa4, 0xa9, 0xb6, 0xc0, 0xc5, 0xc8, 0xca, 0x80, 0xcb,
+ 0x05, 0xca, 0xc7, 0xc4, 0xbf, 0xb8, 0xb8, 0x85, 0xbc, 0x07, 0xb4, 0x74,
+ 0x7e, 0x9e, 0xb6, 0xc6, 0xcd, 0xcf, 0x84, 0xd0, 0x03, 0xcf, 0xcc, 0xc3,
+ 0x48, 0x81, 0x00, 0x05, 0x25, 0x7a, 0x9e, 0xbb, 0xc9, 0xce, 0x80, 0xd0,
+ 0x03, 0xcf, 0xca, 0xbd, 0xb9, 0x90, 0xbc, 0x05, 0xa7, 0x8f, 0xad, 0xc1,
+ 0xc3, 0xb7, 0x82, 0xbc, 0x05, 0x78, 0x89, 0xab, 0xc1, 0xcc, 0xcf, 0x87,
+ 0xd0, 0x02, 0xce, 0xc7, 0xb7, 0x82, 0xbc, 0x06, 0x77, 0x89, 0xab, 0xc1,
+ 0xc7, 0xc1, 0x37, 0x81, 0x00, 0x0a, 0x2b, 0x7e, 0xa0, 0xbc, 0xca, 0xcf,
+ 0xd0, 0xcf, 0xcb, 0xbd, 0x08, 0x81, 0x00, 0x08, 0x3f, 0x84, 0xa7, 0xbf,
+ 0xc9, 0xc8, 0xbd, 0x99, 0x1d, 0x8d, 0x00, 0x05, 0x0e, 0x74, 0x98, 0xb6,
+ 0xc6, 0xce, 0x96, 0xd0, 0x05, 0xce, 0xcb, 0xc2, 0xb0, 0x9f, 0xb7, 0x86,
+ 0xbc, 0x0c, 0xb2, 0xa9, 0xaa, 0xb3, 0xb8, 0xbc, 0xbe, 0xbf, 0xbe, 0xbc,
+ 0xb8, 0xb6, 0xb9, 0x86, 0xbc, 0x07, 0xbb, 0x83, 0x76, 0x93, 0xae, 0xc1,
+ 0xcb, 0xcf, 0x85, 0xd0, 0x03, 0xcf, 0xcc, 0xc3, 0x7c, 0x81, 0x00, 0x05,
+ 0x58, 0x89, 0xa9, 0xc0, 0xcb, 0xcf, 0x80, 0xd0, 0x03, 0xcf, 0xcb, 0xbf,
+ 0xb2, 0x8f, 0xbc, 0x07, 0xb9, 0x81, 0x91, 0xae, 0xc1, 0xc4, 0xb8, 0xba,
+ 0x80, 0xbc, 0x05, 0xa7, 0x76, 0x96, 0xb3, 0xc5, 0xcd, 0x88, 0xd0, 0x03,
+ 0xce, 0xc7, 0xb7, 0xbb, 0x80, 0xbc, 0x07, 0xa7, 0x76, 0x96, 0xb3, 0xc5,
+ 0xc9, 0xc2, 0x6d, 0x80, 0x00, 0x0b, 0x01, 0x5f, 0x8b, 0xab, 0xc1, 0xcc,
+ 0xcf, 0xd0, 0xcf, 0xcb, 0xbf, 0x3f, 0x80, 0x00, 0x0b, 0x09, 0x70, 0x92,
+ 0xb0, 0xc3, 0xcc, 0xcc, 0xc5, 0xb4, 0x98, 0x3f, 0x0d, 0x8b, 0x00, 0x05,
+ 0x40, 0x83, 0xa4, 0xbd, 0xca, 0xcf, 0x97, 0xd0, 0x05, 0xce, 0xc9, 0xbe,
+ 0xab, 0x9e, 0xb9, 0x87, 0xbc, 0x07, 0xbb, 0xb7, 0xb3, 0xb1, 0xb3, 0xb3,
+ 0xb5, 0xb9, 0x89, 0xbc, 0x06, 0x8f, 0x70, 0x8c, 0xa8, 0xbd, 0xc8, 0xcd,
+ 0x86, 0xd0, 0x0d, 0xcf, 0xcd, 0xc6, 0xb3, 0x4a, 0x11, 0x1e, 0x4c, 0x81,
+ 0x9b, 0xb4, 0xc6, 0xcd, 0xcf, 0x80, 0xd0, 0x07, 0xcf, 0xcc, 0xc3, 0xb0,
+ 0xa2, 0x9d, 0xa3, 0xad, 0x89, 0xac, 0x12, 0xa6, 0x97, 0x7a, 0x83, 0x9e,
+ 0xb6, 0xc5, 0xc7, 0xbd, 0xad, 0xac, 0xb3, 0xa5, 0x7e, 0x8a, 0xa6, 0xbd,
+ 0xc9, 0xce, 0x88, 0xd0, 0x32, 0xce, 0xc9, 0xbd, 0xab, 0xae, 0xb3, 0xa3,
+ 0x7d, 0x8a, 0xa6, 0xbd, 0xc9, 0xcc, 0xc5, 0xab, 0x46, 0x0e, 0x21, 0x4f,
+ 0x82, 0x9e, 0xb6, 0xc6, 0xcd, 0xd0, 0xd0, 0xcf, 0xcc, 0xc2, 0x9a, 0x3f,
+ 0x13, 0x2b, 0x5c, 0x87, 0xa3, 0xbb, 0xc8, 0xcd, 0xce, 0xcb, 0xc2, 0xb4,
+ 0xa0, 0x8c, 0x60, 0x35, 0x28, 0x1e, 0x19, 0x13, 0x83, 0x0e, 0x07, 0x1d,
+ 0x44, 0x7a, 0x96, 0xb1, 0xc3, 0xcc, 0xcf, 0x97, 0xd0, 0x05, 0xcf, 0xcd,
+ 0xc7, 0xbb, 0xa8, 0xa1, 0x99, 0xbc, 0x08, 0xbb, 0x8a, 0x6d, 0x88, 0xa3,
+ 0xb9, 0xc6, 0xcc, 0xcf, 0x87, 0xd0, 0x0b, 0xce, 0xca, 0xbf, 0xac, 0x99,
+ 0x8d, 0x8e, 0x9b, 0xaf, 0xc0, 0xca, 0xce, 0x82, 0xd0, 0x07, 0xce, 0xc8,
+ 0xbd, 0xab, 0x9a, 0x8b, 0x82, 0x7e, 0x88, 0x7a, 0x12, 0x7d, 0x82, 0x8e,
+ 0x9e, 0xb2, 0xc1, 0xca, 0xcb, 0xc3, 0xb4, 0x9f, 0x8e, 0x89, 0x90, 0xa2,
+ 0xb6, 0xc5, 0xcc, 0xcf, 0x88, 0xd0, 0x17, 0xcf, 0xcc, 0xc3, 0xb3, 0x9e,
+ 0x8e, 0x88, 0x90, 0xa2, 0xb6, 0xc5, 0xcc, 0xcd, 0xc9, 0xbe, 0xab, 0x98,
+ 0x8c, 0x8e, 0x9e, 0xb1, 0xc1, 0xcb, 0xce, 0x80, 0xd0, 0x18, 0xcd, 0xc7,
+ 0xbb, 0xa7, 0x95, 0x8d, 0x92, 0xa0, 0xb4, 0xc3, 0xcc, 0xcf, 0xcf, 0xce,
+ 0xca, 0xc3, 0xb9, 0xab, 0x9e, 0x93, 0x8a, 0x85, 0x81, 0x7e, 0x7c, 0x82,
+ 0x7a, 0x06, 0x7f, 0x89, 0x98, 0xab, 0xbe, 0xc9, 0xce, 0x99, 0xd0, 0x06,
+ 0xcf, 0xcc, 0xc6, 0xba, 0xa5, 0xa0, 0xb7, 0x96, 0xbc, 0x08, 0xb6, 0x82,
+ 0x69, 0x85, 0xa0, 0xb6, 0xc4, 0xcc, 0xcf, 0x88, 0xd0, 0x0b, 0xcf, 0xcd,
+ 0xc7, 0xbe, 0xb3, 0xab, 0xac, 0xb4, 0xc0, 0xc8, 0xcd, 0xcf, 0x82, 0xd0,
+ 0x08, 0xcf, 0xcc, 0xc7, 0xbf, 0xb4, 0xab, 0xa6, 0xa2, 0xa0, 0x86, 0x9e,
+ 0x12, 0x9f, 0xa1, 0xa5, 0xac, 0xb7, 0xc2, 0xc9, 0xcd, 0xcd, 0xca, 0xc2,
+ 0xb6, 0xac, 0xa9, 0xae, 0xb8, 0xc3, 0xcb, 0xce, 0x89, 0xd0, 0x17, 0xcf,
+ 0xce, 0xca, 0xc1, 0xb5, 0xac, 0xa9, 0xae, 0xb8, 0xc3, 0xcb, 0xce, 0xcf,
+ 0xcc, 0xc6, 0xbd, 0xb3, 0xab, 0xad, 0xb5, 0xc0, 0xc9, 0xcd, 0xcf, 0x80,
+ 0xd0, 0x19, 0xcf, 0xcc, 0xc5, 0xbb, 0xb1, 0xab, 0xaf, 0xb8, 0xc2, 0xca,
+ 0xce, 0xd0, 0xd0, 0xcf, 0xce, 0xcc, 0xc6, 0xc1, 0xba, 0xb3, 0xac, 0xa8,
+ 0xa4, 0xa3, 0xa1, 0x9f, 0x80, 0x9e, 0x07, 0xa0, 0xa4, 0xa9, 0xb3, 0xbf,
+ 0xc7, 0xcc, 0xcf, 0x9a, 0xd0, 0x06, 0xcf, 0xcc, 0xc6, 0xb9, 0xa5, 0x94,
+ 0xa4, 0x94, 0xbc, 0x08, 0xb5, 0xab, 0x60, 0x7a, 0x9a, 0xb3, 0xc3, 0xcb,
+ 0xce, 0x8a, 0xd0, 0x09, 0xcf, 0xcc, 0xc9, 0xc4, 0xc2, 0xc2, 0xc6, 0xca,
+ 0xcd, 0xcf, 0x84, 0xd0, 0x08, 0xcf, 0xcc, 0xca, 0xc6, 0xc2, 0xc0, 0xbd,
+ 0xbc, 0xbc, 0x84, 0xbb, 0x13, 0xbc, 0xbc, 0xbd, 0xbf, 0xc2, 0xc6, 0xcb,
+ 0xcd, 0xcf, 0xcf, 0xcd, 0xcb, 0xc6, 0xc2, 0xc1, 0xc2, 0xc6, 0xcb, 0xce,
+ 0xcf, 0x8a, 0xd0, 0x15, 0xcf, 0xcd, 0xca, 0xc6, 0xc2, 0xc0, 0xc2, 0xc6,
+ 0xcb, 0xce, 0xcf, 0xd0, 0xcf, 0xcc, 0xc8, 0xc4, 0xc2, 0xc2, 0xc6, 0xca,
+ 0xcd, 0xcf, 0x81, 0xd0, 0x0a, 0xcf, 0xce, 0xcc, 0xc7, 0xc3, 0xc2, 0xc3,
+ 0xc6, 0xcb, 0xce, 0xcf, 0x81, 0xd0, 0x09, 0xcf, 0xcd, 0xcc, 0xc8, 0xc5,
+ 0xc2, 0xc0, 0xbf, 0xbe, 0xbd, 0x82, 0xbc, 0x05, 0xbe, 0xc1, 0xc5, 0xc9,
+ 0xcd, 0xcf, 0x9c, 0xd0, 0x07, 0xcf, 0xcc, 0xc5, 0xba, 0xab, 0x96, 0x93,
+ 0xae, 0x90, 0xbc, 0x0a, 0xb9, 0xb6, 0xbc, 0xba, 0x92, 0x84, 0xa4, 0xbc,
+ 0xc8, 0xcd, 0xcf, 0x8b, 0xd0, 0x09, 0xcf, 0xce, 0xcc, 0xcc, 0xca, 0xcb,
+ 0xcc, 0xcc, 0xce, 0xcf, 0x99, 0xd0, 0x0d, 0xcf, 0xce, 0xcd, 0xcd, 0xce,
+ 0xcf, 0xd0, 0xd0, 0xcf, 0xce, 0xcd, 0xcd, 0xce, 0xcf, 0xe8, 0xd0, 0x08,
+ 0xcf, 0xcc, 0xc6, 0xbf, 0xb2, 0xa1, 0x8f, 0x9b, 0xb5, 0x8c, 0xbc, 0x01,
+ 0xb3, 0xb4, 0x81, 0xbc, 0x05, 0xb0, 0x85, 0xa1, 0xbb, 0xc8, 0xce, 0x8b,
+ 0xd0, 0x0b, 0xcf, 0xce, 0xca, 0xc5, 0xc0, 0xbe, 0xbe, 0xc0, 0xc5, 0xca,
+ 0xcd, 0xcf, 0x8f, 0xd0, 0x01, 0xcf, 0xcf, 0x83, 0xd0, 0x0f, 0xcf, 0xcd,
+ 0xcb, 0xc7, 0xc6, 0xc9, 0xcc, 0xce, 0xce, 0xcc, 0xc9, 0xc6, 0xc6, 0xca,
+ 0xcd, 0xcf, 0xc7, 0xd0, 0x00, 0xcf, 0x9d, 0xd0, 0x0b, 0xcf, 0xcc, 0xc9,
+ 0xc3, 0xba, 0xab, 0x9b, 0x8c, 0x90, 0x9f, 0xb1, 0xbb, 0x84, 0xbc, 0x03,
+ 0xb7, 0xa7, 0x95, 0xac, 0x84, 0xbc, 0x05, 0xa4, 0x94, 0xb2, 0xc3, 0xcc,
+ 0xcf, 0x8a, 0xd0, 0x0c, 0xce, 0xcb, 0x76, 0x04, 0x04, 0x08, 0x1e, 0x6d,
+ 0xb4, 0xc0, 0xc8, 0xcd, 0xcf, 0x8c, 0xd0, 0x05, 0xcf, 0xce, 0xcd, 0xcd,
+ 0xce, 0xcf, 0x81, 0xd0, 0x0f, 0xce, 0xca, 0x7a, 0x08, 0xb0, 0xbf, 0xc6,
+ 0xcc, 0xcc, 0xc5, 0x1e, 0x3c, 0xba, 0xc1, 0xc9, 0xce, 0xc4, 0xd0, 0x06,
+ 0xcf, 0xcf, 0xce, 0xcd, 0xce, 0xcf, 0xcf, 0x9b, 0xd0, 0x16, 0xcf, 0xce,
+ 0xcc, 0xc7, 0xc0, 0xb6, 0xab, 0x9c, 0x8f, 0x84, 0x81, 0x88, 0x8e, 0x8e,
+ 0x8d, 0x8b, 0x8c, 0x82, 0x72, 0x72, 0x76, 0x87, 0xb8, 0x83, 0xbc, 0x05,
+ 0xb5, 0x8f, 0xa3, 0xbb, 0xc8, 0xce, 0x89, 0xd0, 0x0d, 0xcf, 0xcd, 0xc6,
+ 0x59, 0x00, 0x0d, 0x08, 0x00, 0x00, 0x76, 0xb1, 0xc1, 0xca, 0xce, 0x8b,
+ 0xd0, 0x1b, 0xcf, 0xcc, 0xca, 0xc7, 0xc7, 0xcb, 0xcd, 0xcf, 0xd0, 0xd0,
+ 0xcf, 0xcc, 0xc4, 0x2b, 0x00, 0x76, 0xaf, 0xbe, 0xc7, 0xc6, 0x7e, 0x00,
+ 0x1b, 0xa6, 0xb5, 0xc4, 0xcc, 0xcf, 0xc2, 0xd0, 0x08, 0xcf, 0xce, 0xcc,
+ 0xc9, 0xc7, 0xc8, 0xcc, 0xce, 0xcf, 0x9c, 0xd0, 0x0b, 0xcf, 0xcd, 0xcb,
+ 0xc6, 0xc0, 0xb8, 0xaf, 0xa7, 0x9e, 0x98, 0x91, 0x8d, 0x80, 0x8a, 0x05,
+ 0x8d, 0x92, 0x97, 0x98, 0x92, 0xac, 0x84, 0xbc, 0x05, 0xab, 0x91, 0xad,
+ 0xc1, 0xcb, 0xcf, 0x88, 0xd0, 0x0d, 0xcf, 0xcc, 0xc3, 0x3f, 0x00, 0x6a,
+ 0x7d, 0x3e, 0x00, 0x3c, 0xa2, 0xb8, 0xc6, 0xcd, 0x81, 0xcf, 0x83, 0xd0,
+ 0x81, 0xcf, 0x1c, 0xcc, 0xc0, 0x24, 0x50, 0xbd, 0xc3, 0xcb, 0xce, 0xd0,
+ 0xd0, 0xce, 0xc9, 0xa3, 0x00, 0x00, 0x44, 0x9e, 0xb4, 0xc1, 0xc0, 0x22,
+ 0x00, 0x04, 0x93, 0xa9, 0xbf, 0xcb, 0xcf, 0xd0, 0x82, 0xcf, 0x80, 0xd0,
+ 0x81, 0xcf, 0x83, 0xd0, 0x82, 0xcf, 0x82, 0xd0, 0x82, 0xcf, 0x81, 0xd0,
+ 0x80, 0xcf, 0x81, 0xd0, 0x85, 0xcf, 0x82, 0xd0, 0x80, 0xcf, 0x81, 0xd0,
+ 0x81, 0xcf, 0x08, 0xce, 0xcc, 0x93, 0x23, 0x7a, 0xbf, 0xc6, 0xcc, 0xcf,
+ 0x9d, 0xd0, 0x14, 0xcf, 0xcf, 0xcd, 0xcb, 0xc7, 0xc3, 0xc0, 0xbb, 0xb5,
+ 0xb2, 0xae, 0xac, 0xab, 0xac, 0xaf, 0xb3, 0xb5, 0xb5, 0xae, 0x9e, 0xb6,
+ 0x83, 0xbc, 0x06, 0xba, 0x99, 0x9e, 0xb7, 0xc6, 0xcd, 0xcf, 0x87, 0xd0,
+ 0x0c, 0xcf, 0xcb, 0xc0, 0x29, 0x00, 0x77, 0x7f, 0x60, 0x00, 0x32, 0x99,
+ 0xb2, 0xc3, 0x81, 0xcc, 0x01, 0xcd, 0xce, 0x80, 0xcf, 0x01, 0xce, 0xcd,
+ 0x81, 0xcc, 0x13, 0xc9, 0xa1, 0x00, 0x46, 0xac, 0xba, 0xc6, 0xcc, 0xcf,
+ 0xcf, 0xcd, 0xc5, 0x58, 0x00, 0x00, 0x1b, 0x8f, 0xa9, 0xb9, 0x84, 0x80,
+ 0x00, 0x03, 0x79, 0xa0, 0xbb, 0xc8, 0x80, 0xcd, 0x01, 0xcc, 0xcc, 0x80,
+ 0xcd, 0x0b, 0xce, 0xce, 0xcd, 0xcd, 0xcc, 0xcc, 0xcd, 0xce, 0xcf, 0xcf,
+ 0xce, 0xcd, 0x80, 0xcc, 0x06, 0xcd, 0xcd, 0xce, 0xce, 0xcf, 0xce, 0xcd,
+ 0x80, 0xcc, 0x01, 0xcd, 0xcd, 0x80, 0xce, 0x03, 0xcd, 0xcc, 0xcc, 0xcd,
+ 0x81, 0xce, 0x00, 0xcd, 0x83, 0xcc, 0x08, 0xcd, 0xcd, 0xce, 0xcf, 0xce,
+ 0xce, 0xcd, 0xcc, 0xcd, 0x80, 0xce, 0x01, 0xcd, 0xcd, 0x81, 0xcc, 0x08,
+ 0xc6, 0x6c, 0x00, 0x73, 0xb1, 0xbe, 0xc8, 0xcd, 0xcf, 0x9e, 0xd0, 0x08,
+ 0xcf, 0xcf, 0xce, 0xcc, 0xcb, 0xc9, 0xc7, 0xc5, 0xc3, 0x80, 0xc2, 0x06,
+ 0xc3, 0xc5, 0xc6, 0xc6, 0xc0, 0xaf, 0xaa, 0x84, 0xbc, 0x05, 0xaf, 0x8d,
+ 0xa9, 0xbf, 0xca, 0xce, 0x87, 0xd0, 0x65, 0xcf, 0xcb, 0xbf, 0x14, 0x07,
+ 0x81, 0x80, 0x31, 0x00, 0x50, 0x97, 0xaf, 0xc0, 0xc7, 0xc6, 0xc4, 0xc4,
+ 0xc6, 0xc9, 0xcc, 0xcd, 0xcc, 0xcb, 0xc7, 0xc5, 0xc3, 0xc5, 0xc6, 0xc2,
+ 0x82, 0x00, 0x50, 0x9e, 0xaf, 0xc0, 0xcb, 0xce, 0xcf, 0xcb, 0xc0, 0x15,
+ 0x07, 0x0d, 0x03, 0x7f, 0x9f, 0xb0, 0x2b, 0x00, 0x13, 0x00, 0x60, 0x9a,
+ 0xb5, 0xc5, 0xc9, 0xc7, 0xc5, 0xc4, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc8,
+ 0xc6, 0xc5, 0xc4, 0xc5, 0xc6, 0xc9, 0xcc, 0xcc, 0xca, 0xc7, 0xc5, 0xc4,
+ 0xc4, 0xc5, 0xc6, 0xc8, 0xca, 0xcb, 0xca, 0xc6, 0xc5, 0xc4, 0xc4, 0xc5,
+ 0xc6, 0xc7, 0xc9, 0xc9, 0xc6, 0xc5, 0xc4, 0xc6, 0xc8, 0xcb, 0xca, 0xc8,
+ 0xc5, 0x80, 0xc3, 0x1d, 0xc4, 0xc5, 0xc4, 0xc5, 0xc7, 0xca, 0xcc, 0xca,
+ 0xc7, 0xc5, 0xc4, 0xc5, 0xc8, 0xca, 0xca, 0xc7, 0xc6, 0xc4, 0xc4, 0xc5,
+ 0xc4, 0xbf, 0x4f, 0x00, 0x7a, 0xa2, 0xb4, 0xc4, 0xcc, 0xcf, 0xa1, 0xd0,
+ 0x04, 0xcf, 0xcf, 0xce, 0xce, 0xcd, 0x82, 0xcc, 0x06, 0xcd, 0xcd, 0xcc,
+ 0xc8, 0xbc, 0xa7, 0xb3, 0x84, 0xbc, 0x05, 0xa1, 0x98, 0xb4, 0xc4, 0xcc,
+ 0xcf, 0x86, 0xd0, 0x7f, 0xcf, 0xca, 0xb9, 0x01, 0x06, 0x27, 0x0e, 0x00,
+ 0x29, 0x82, 0x96, 0xad, 0xbb, 0x93, 0x59, 0x47, 0x66, 0xaf, 0xbc, 0xc3,
+ 0xc7, 0xc6, 0x9a, 0x5a, 0x46, 0x63, 0xab, 0xb7, 0x8e, 0x35, 0x00, 0x2a,
+ 0x47, 0x9f, 0xbb, 0xc8, 0xcd, 0xcd, 0xc8, 0x89, 0x00, 0x32, 0x2b, 0x00,
+ 0x5d, 0x97, 0x81, 0x00, 0x28, 0x35, 0x00, 0x4e, 0x96, 0xb1, 0xbe, 0x99,
+ 0x60, 0x4d, 0x69, 0xa9, 0x72, 0x5b, 0xb7, 0xac, 0x5d, 0x82, 0x76, 0x4e,
+ 0x7a, 0xb4, 0xbe, 0xc3, 0xc3, 0x92, 0x5d, 0x4d, 0x6f, 0xae, 0x69, 0x63,
+ 0xbb, 0xc0, 0xc2, 0x8e, 0x5c, 0x4e, 0x6f, 0xaf, 0x63, 0x6d, 0xbb, 0xbd,
+ 0x9a, 0x5c, 0x48, 0x69, 0xb1, 0xbc, 0xc1, 0x8a, 0x5d, 0x82, 0x4d, 0x50,
+ 0x8f, 0xa1, 0x57, 0x52, 0x88, 0xb7, 0xbf, 0xc2, 0xa9, 0x63, 0x47, 0x60,
+ 0xa7, 0xbb, 0xbf, 0x7d, 0x5d, 0x99, 0x5a, 0x5b, 0x9e, 0xb4, 0x73, 0x1d,
+ 0x06, 0x00, 0x3c, 0x59, 0xab, 0xbf, 0xca, 0xce, 0xa5, 0xd0, 0x84, 0xcf,
+ 0x06, 0xd0, 0xcf, 0xcc, 0xc5, 0xb4, 0xa7, 0xba, 0x83, 0xbc, 0x05, 0xb3,
+ 0x8d, 0xa4, 0xbc, 0xc9, 0xce, 0x86, 0xd0, 0x02, 0xce, 0xc8, 0xa3, 0x82,
+ 0x00, 0x05, 0x07, 0x4c, 0x93, 0xa7, 0x5d, 0x01, 0x80, 0x00, 0x05, 0x17,
+ 0x9e, 0xb4, 0xbd, 0x6a, 0x03, 0x80, 0x00, 0x02, 0x13, 0x92, 0x4d, 0x80,
+ 0x00, 0x21, 0x03, 0x9b, 0xb4, 0xc6, 0xcc, 0xcc, 0xc4, 0x40, 0x00, 0x63,
+ 0x49, 0x00, 0x3c, 0x8d, 0x2f, 0x00, 0x64, 0x46, 0x00, 0x3f, 0x93, 0xa9,
+ 0x59, 0x01, 0x00, 0x09, 0x00, 0x19, 0x11, 0x0b, 0xa4, 0x7e, 0x00, 0x0d,
+ 0x80, 0x00, 0x24, 0x3e, 0xab, 0xb4, 0x49, 0x00, 0x00, 0x09, 0x00, 0x21,
+ 0x08, 0x1b, 0xa7, 0xaf, 0x42, 0x00, 0x00, 0x03, 0x00, 0x25, 0x01, 0x2b,
+ 0xa4, 0x66, 0x03, 0x00, 0x03, 0x00, 0x1d, 0x9e, 0xb0, 0x3f, 0x00, 0x01,
+ 0x00, 0x00, 0x04, 0x0e, 0x80, 0x00, 0x11, 0x69, 0xab, 0x84, 0x0a, 0x00,
+ 0x04, 0x00, 0x11, 0x8c, 0xac, 0x27, 0x00, 0x0d, 0x00, 0x00, 0x01, 0x8e,
+ 0x21, 0x80, 0x00, 0x04, 0x28, 0xa4, 0xbb, 0xc7, 0xce, 0xae, 0xd0, 0x04,
+ 0xce, 0xca, 0xc0, 0xab, 0xb0, 0x84, 0xbc, 0x05, 0xa8, 0x93, 0xb0, 0xc2,
+ 0xcc, 0xcf, 0x85, 0xd0, 0x7f, 0xce, 0xc7, 0x8a, 0x00, 0x2e, 0x63, 0x5d,
+ 0x45, 0x0e, 0x00, 0x6e, 0x7a, 0x01, 0x11, 0x58, 0x6e, 0x27, 0x00, 0x40,
+ 0xa2, 0x8f, 0x03, 0x0e, 0x55, 0x70, 0x2b, 0x00, 0x35, 0x8a, 0x2d, 0x00,
+ 0x65, 0x7d, 0x9e, 0xb4, 0xc5, 0xcc, 0xca, 0xb4, 0x07, 0x13, 0x84, 0x70,
+ 0x00, 0x1d, 0x6d, 0x01, 0x21, 0x82, 0x5c, 0x00, 0x2f, 0x8e, 0x71, 0x00,
+ 0x25, 0x74, 0x90, 0x69, 0x06, 0x00, 0x1a, 0x8e, 0x5f, 0x00, 0x14, 0x60,
+ 0x5f, 0x04, 0x07, 0x91, 0x63, 0x00, 0x2e, 0x7a, 0x8f, 0x60, 0x01, 0x00,
+ 0x29, 0x93, 0x5b, 0x00, 0x2e, 0x76, 0x88, 0x4f, 0x00, 0x00, 0x35, 0x7c,
+ 0x04, 0x0a, 0x6e, 0x80, 0x40, 0x00, 0x46, 0x9b, 0x24, 0x00, 0x32, 0x69,
+ 0x28, 0x00, 0x13, 0x63, 0x66, 0x01, 0x1e, 0x91, 0x14, 0x01, 0x60, 0x83,
+ 0x55, 0x00, 0x2a, 0x97, 0x0e, 0x00, 0x41, 0x6a, 0x2b, 0x00, 0x4a, 0x84,
+ 0x0a, 0x06, 0x13, 0x71, 0x84, 0xa4, 0xbb, 0xc7, 0xce, 0xae, 0xd0, 0x05,
+ 0xcf, 0xcd, 0xc6, 0xb8, 0xa4, 0xb7, 0x83, 0xbc, 0x06, 0xb7, 0x94, 0x9f,
+ 0xb9, 0xc7, 0xcd, 0xcf, 0x83, 0xd0, 0x71, 0xcf, 0xcd, 0xc6, 0x72, 0x00,
+ 0x48, 0x7e, 0x85, 0x88, 0x4d, 0x00, 0x3f, 0x3f, 0x00, 0x4d, 0x86, 0x89,
+ 0x73, 0x00, 0x1a, 0x92, 0x4f, 0x00, 0x48, 0x87, 0x89, 0x7a, 0x01, 0x14,
+ 0x83, 0x1e, 0x03, 0x7c, 0x8e, 0xa6, 0xbb, 0xc7, 0xcb, 0xc6, 0x70, 0x00,
+ 0x48, 0x8a, 0x8c, 0x11, 0x03, 0x29, 0x00, 0x5d, 0x86, 0x76, 0x00, 0x20,
+ 0x89, 0x32, 0x00, 0x6e, 0x8e, 0x93, 0x94, 0x34, 0x00, 0x28, 0x82, 0x46,
+ 0x00, 0x5f, 0x84, 0x86, 0x22, 0x00, 0x7e, 0x22, 0x01, 0x7a, 0x8e, 0x94,
+ 0x93, 0x25, 0x00, 0x35, 0x85, 0x1e, 0x01, 0x7d, 0x8e, 0x93, 0x92, 0x1e,
+ 0x00, 0x3f, 0x48, 0x00, 0x17, 0x35, 0x35, 0x32, 0x00, 0x1a, 0x8c, 0x10,
+ 0x10, 0x7f, 0x81, 0x4d, 0x00, 0x4f, 0x7f, 0x86, 0x0d, 0x15, 0x64, 0x00,
+ 0x0d, 0x80, 0x35, 0x12, 0x07, 0x04, 0x82, 0x01, 0x20, 0x80, 0x84, 0x63,
+ 0x00, 0x3b, 0x7d, 0x00, 0x22, 0x7f, 0x93, 0xab, 0xc0, 0xca, 0xce, 0xaf,
+ 0xd0, 0x04, 0xcf, 0xcc, 0xc2, 0xaf, 0xad, 0x84, 0xbc, 0x05, 0xad, 0x8e,
+ 0xab, 0xc0, 0xcb, 0xce, 0x83, 0xd0, 0x7f, 0xcf, 0xcc, 0xc4, 0x5c, 0x00,
+ 0x5a, 0x8a, 0x94, 0x99, 0x50, 0x00, 0x38, 0x29, 0x00, 0x64, 0x86, 0x90,
+ 0x7e, 0x00, 0x1e, 0x89, 0x37, 0x00, 0x63, 0x88, 0x91, 0x83, 0x01, 0x17,
+ 0x7e, 0x0e, 0x11, 0x86, 0x9a, 0xb2, 0xc2, 0xcb, 0xcb, 0xc2, 0x29, 0x01,
+ 0x7c, 0x92, 0x99, 0x35, 0x00, 0x00, 0x19, 0x80, 0x90, 0x95, 0x01, 0x0e,
+ 0x83, 0x1a, 0x07, 0x87, 0x90, 0x9c, 0x9e, 0x3c, 0x00, 0x35, 0x7e, 0x34,
+ 0x00, 0x73, 0x8b, 0x92, 0x1e, 0x01, 0x7f, 0x0b, 0x13, 0x86, 0x91, 0x9e,
+ 0x9e, 0x2b, 0x00, 0x42, 0x80, 0x0b, 0x18, 0x88, 0x92, 0x9e, 0x9e, 0x2e,
+ 0x00, 0x4d, 0x35, 0x00, 0x15, 0x20, 0x21, 0x21, 0x22, 0x2e, 0x84, 0x01,
+ 0x21, 0x82, 0x8a, 0x47, 0x00, 0x63, 0x87, 0x8e, 0x03, 0x21, 0x4e, 0x00,
+ 0x0e, 0x1e, 0x21, 0x21, 0x22, 0x22, 0x69, 0x00, 0x31, 0x84, 0x8e, 0x64,
+ 0x00, 0x46, 0x6d, 0x07, 0x00, 0x34, 0x89, 0x9f, 0xb6, 0xc5, 0xcc, 0xcf,
+ 0xb0, 0xd0, 0x04, 0xce, 0xc8, 0xbb, 0xa5, 0xb5, 0x83, 0xbc, 0x06, 0xbb,
+ 0x9d, 0x9a, 0xb4, 0xc5, 0xcc, 0xcf, 0x82, 0xd0, 0x7f, 0xcf, 0xcc, 0xc2,
+ 0x46, 0x00, 0x6a, 0x8b, 0x96, 0x79, 0x15, 0x00, 0x54, 0x37, 0x00, 0x3c,
+ 0x86, 0x90, 0x3e, 0x00, 0x3f, 0x88, 0x47, 0x00, 0x38, 0x89, 0x91, 0x45,
+ 0x00, 0x35, 0x7d, 0x01, 0x21, 0x8d, 0xa3, 0xba, 0xc7, 0xcc, 0xc9, 0xa2,
+ 0x00, 0x24, 0x90, 0x9b, 0xa5, 0x60, 0x00, 0x00, 0x52, 0x87, 0x9c, 0xa4,
+ 0x12, 0x01, 0x7d, 0x28, 0x00, 0x60, 0x90, 0x9e, 0x98, 0x08, 0x00, 0x46,
+ 0x80, 0x23, 0x01, 0x86, 0x96, 0x9e, 0x13, 0x0d, 0x81, 0x19, 0x00, 0x6d,
+ 0x92, 0x9f, 0x8d, 0x01, 0x00, 0x52, 0x82, 0x1e, 0x01, 0x76, 0x93, 0xa0,
+ 0x92, 0x03, 0x00, 0x5c, 0x46, 0x00, 0x25, 0x70, 0x76, 0x60, 0x79, 0x85,
+ 0x77, 0x00, 0x32, 0x8a, 0x94, 0x3f, 0x00, 0x7a, 0x93, 0x8d, 0x00, 0x2f,
+ 0x5f, 0x00, 0x11, 0x6d, 0x74, 0x67, 0x70, 0x81, 0x60, 0x00, 0x42, 0x8c,
+ 0x9a, 0x5d, 0x00, 0x52, 0x5d, 0x06, 0x00, 0x46, 0x92, 0xa9, 0xbe, 0xca,
+ 0xce, 0xb1, 0xd0, 0x05, 0xcf, 0xcc, 0xc4, 0xb3, 0xa9, 0xba, 0x83, 0xbc,
+ 0x05, 0xb5, 0x8c, 0xa6, 0xbd, 0xc9, 0xce, 0x82, 0xd0, 0x7f, 0xcf, 0xcc,
+ 0xc1, 0x2f, 0x00, 0x11, 0x15, 0x08, 0x00, 0x00, 0x29, 0x81, 0x6d, 0x03,
+ 0x00, 0x19, 0x11, 0x00, 0x0d, 0x7f, 0x8f, 0x83, 0x06, 0x00, 0x17, 0x14,
+ 0x00, 0x09, 0x76, 0x73, 0x00, 0x35, 0x93, 0xa9, 0xbf, 0xca, 0xcc, 0xc6,
+ 0x59, 0x00, 0x5a, 0x96, 0xa5, 0xb0, 0x92, 0x00, 0x17, 0x80, 0x94, 0xa9,
+ 0xaf, 0x29, 0x00, 0x6f, 0x5c, 0x00, 0x04, 0x30, 0x3c, 0x08, 0x00, 0x00,
+ 0x55, 0x83, 0x13, 0x0e, 0x8f, 0x9e, 0xa5, 0x03, 0x21, 0x86, 0x4f, 0x00,
+ 0x07, 0x37, 0x35, 0x04, 0x00, 0x00, 0x63, 0x88, 0x5f, 0x00, 0x0e, 0x41,
+ 0x3f, 0x0a, 0x00, 0x00, 0x6c, 0x73, 0x0a, 0x00, 0x12, 0x1e, 0x00, 0x14,
+ 0x89, 0x6e, 0x00, 0x46, 0x92, 0x9c, 0x2b, 0x03, 0x8f, 0x9b, 0x7e, 0x00,
+ 0x44, 0x80, 0x19, 0x00, 0x0d, 0x23, 0x01, 0x07, 0x77, 0x56, 0x00, 0x57,
+ 0x94, 0xa2, 0x4e, 0x00, 0x67, 0x4f, 0x06, 0x00, 0x59, 0x98, 0xaf, 0xc2,
+ 0xcc, 0xcf, 0xb2, 0xd0, 0x04, 0xce, 0xca, 0xbf, 0xa8, 0xb1, 0x84, 0xbc,
+ 0x05, 0xb2, 0x95, 0xb2, 0xc4, 0xcc, 0xcf, 0x81, 0xd0, 0x03, 0xcf, 0xcc,
+ 0xc1, 0x1a, 0x80, 0x00, 0x7f, 0x07, 0x1a, 0x4c, 0x86, 0x8f, 0x95, 0x69,
+ 0x11, 0x00, 0x01, 0x21, 0x76, 0x91, 0x9e, 0xa4, 0x76, 0x14, 0x00, 0x01,
+ 0x1e, 0x72, 0x8b, 0x6d, 0x00, 0x49, 0x9c, 0xb0, 0xc2, 0xcb, 0xcc, 0xc3,
+ 0x15, 0x07, 0x90, 0x9f, 0xb0, 0xbb, 0xb4, 0x11, 0x5f, 0x93, 0xa4, 0xb5,
+ 0xb8, 0x41, 0x00, 0x65, 0x8e, 0x54, 0x09, 0x00, 0x00, 0x21, 0x29, 0x00,
+ 0x6a, 0x8c, 0x03, 0x22, 0x98, 0xa5, 0x97, 0x00, 0x39, 0x91, 0x92, 0x4b,
+ 0x06, 0x00, 0x01, 0x29, 0x21, 0x00, 0x7a, 0x93, 0x9b, 0x5a, 0x0a, 0x00,
+ 0x00, 0x22, 0x0d, 0x04, 0x7a, 0x88, 0x73, 0x1b, 0x01, 0x01, 0x17, 0x6d,
+ 0x96, 0x62, 0x00, 0x5d, 0x9b, 0xa4, 0x17, 0x13, 0x9a, 0xa3, 0x6c, 0x00,
+ 0x5c, 0x8f, 0x7e, 0x28, 0x01, 0x00, 0x11, 0x58, 0x91, 0x4a, 0x00, 0x71,
+ 0x9e, 0xab, 0x3a, 0x00, 0x82, 0x44, 0x00, 0x70, 0xa1, 0xb5, 0xc5, 0xcd,
+ 0xcf, 0xb2, 0xd0, 0x05, 0xcf, 0xcd, 0xc6, 0xb6, 0xa4, 0xb8, 0x83, 0xbc,
+ 0x05, 0xb7, 0x8b, 0xa5, 0xbe, 0xca, 0xcf, 0x81, 0xd0, 0x76, 0xcf, 0xcc,
+ 0xc4, 0xb4, 0x9e, 0x8f, 0x8a, 0x8a, 0x8e, 0x93, 0x9b, 0xa5, 0xab, 0xa9,
+ 0x9e, 0x86, 0x87, 0x8f, 0x97, 0xa3, 0xb1, 0xb5, 0xae, 0xa0, 0x87, 0x88,
+ 0x8e, 0x95, 0x9e, 0xa5, 0xa5, 0xa4, 0xab, 0xb9, 0xc6, 0xcc, 0xcc, 0xc6,
+ 0xba, 0xab, 0xa5, 0xad, 0xbb, 0xc2, 0xbf, 0xb2, 0xa7, 0xa9, 0xb4, 0xc0,
+ 0xc1, 0xb5, 0xa7, 0x9f, 0xa0, 0x9f, 0x99, 0x81, 0x87, 0x8f, 0x8e, 0x8e,
+ 0x94, 0x9e, 0xa3, 0xa2, 0xa6, 0xb1, 0xb6, 0xb0, 0xa6, 0xa4, 0xa5, 0xa3,
+ 0x99, 0x7f, 0x8a, 0x8f, 0x8e, 0x8e, 0x98, 0xa4, 0xa9, 0xa1, 0x93, 0x79,
+ 0x7a, 0x6d, 0x00, 0x20, 0x81, 0x95, 0xa0, 0x9b, 0x8a, 0x85, 0x8f, 0x98,
+ 0xa4, 0xab, 0xa8, 0xa5, 0xab, 0xb1, 0xaf, 0xa8, 0xa7, 0xae, 0xb3, 0xac,
+ 0xa4, 0xa3, 0xa3, 0x9e, 0x8e, 0x82, 0x8e, 0x96, 0x9e, 0x80, 0xa4, 0x0b,
+ 0xab, 0xb4, 0xb3, 0xa9, 0x9f, 0x9e, 0x9e, 0xa3, 0xae, 0xbd, 0xc8, 0xce,
+ 0xb4, 0xd0, 0x04, 0xcf, 0xcb, 0xc1, 0xac, 0xaf, 0x81, 0xbc, 0x80, 0xbb,
+ 0x04, 0x92, 0x9b, 0xb8, 0xc8, 0xce, 0x82, 0xd0, 0x4a, 0xce, 0xc8, 0xbf,
+ 0xb3, 0xa8, 0xa3, 0xa3, 0xa5, 0xab, 0xb3, 0xbb, 0xbf, 0xbc, 0xb4, 0xab,
+ 0xa6, 0xa7, 0xad, 0xb7, 0xc0, 0xc3, 0xbf, 0xb5, 0xab, 0xa6, 0xa7, 0xac,
+ 0xb4, 0xb9, 0xb8, 0xb7, 0xbb, 0xc2, 0xca, 0xce, 0xcd, 0xca, 0xc2, 0xba,
+ 0xb7, 0xbd, 0xc5, 0xc9, 0xc6, 0xc0, 0xbb, 0xbc, 0xc2, 0xc8, 0xc7, 0xc1,
+ 0xb9, 0xb4, 0xb5, 0xb4, 0xb0, 0xa9, 0xa6, 0xa4, 0xa5, 0xa8, 0xad, 0xb3,
+ 0xb5, 0xb5, 0xb8, 0xbe, 0xc1, 0xbd, 0xb8, 0xb7, 0xb9, 0xb7, 0xb1, 0xa9,
+ 0x80, 0xa5, 0x36, 0xa9, 0xae, 0xb4, 0x52, 0x15, 0x49, 0x7a, 0x6a, 0x21,
+ 0x00, 0x4d, 0x8d, 0xa4, 0xb2, 0xb3, 0xab, 0xa7, 0xa8, 0xad, 0xb4, 0xba,
+ 0xb9, 0xb7, 0xbb, 0xbe, 0xbd, 0xb8, 0xb8, 0xbc, 0xbf, 0xbb, 0xb7, 0xb7,
+ 0xb8, 0xb4, 0xac, 0xa7, 0xa7, 0xab, 0xb3, 0xb6, 0xb6, 0xb7, 0xbb, 0xc0,
+ 0xbf, 0xb9, 0xb4, 0xb3, 0xb3, 0xb5, 0xbd, 0xc5, 0xcc, 0xcf, 0xb4, 0xd0,
+ 0x05, 0xcf, 0xcd, 0xc7, 0xba, 0xa4, 0xba, 0x82, 0xbc, 0x05, 0xba, 0x87,
+ 0x98, 0xb5, 0xc6, 0xce, 0x82, 0xd0, 0x1b, 0xcf, 0xcc, 0xc8, 0xc2, 0xbf,
+ 0xbc, 0xbc, 0xbd, 0xc0, 0xc3, 0xc7, 0xca, 0xc8, 0xc4, 0xc0, 0xbd, 0xbe,
+ 0xc1, 0xc6, 0xca, 0xcc, 0xc9, 0xc5, 0xc0, 0xbd, 0xbe, 0xc1, 0xc4, 0x81,
+ 0xc6, 0x24, 0xcb, 0xcd, 0xcf, 0xcf, 0xcd, 0xc9, 0xc6, 0xc5, 0xc8, 0xcc,
+ 0xcd, 0xcc, 0xca, 0xc7, 0xc8, 0xcb, 0xcd, 0xcc, 0xca, 0xc6, 0xc4, 0xc5,
+ 0xc5, 0xc2, 0xbf, 0xbc, 0xbc, 0xbd, 0xbf, 0xc1, 0xc4, 0xc5, 0xc4, 0xc6,
+ 0xc8, 0xc9, 0xc7, 0x81, 0xc6, 0x09, 0xc2, 0xbf, 0xbc, 0xbc, 0xbd, 0xbf,
+ 0xc1, 0xc0, 0x95, 0x07, 0x81, 0x00, 0x0a, 0x2b, 0x88, 0x9b, 0xb1, 0xc0,
+ 0xc2, 0xc0, 0xbe, 0xbe, 0xc1, 0xc4, 0x81, 0xc6, 0x05, 0xc8, 0xc7, 0xc6,
+ 0xc6, 0xc7, 0xc8, 0x81, 0xc6, 0x05, 0xc5, 0xc1, 0xbe, 0xbe, 0xc0, 0xc3,
+ 0x80, 0xc5, 0x0b, 0xc7, 0xc9, 0xc8, 0xc6, 0xc4, 0xc3, 0xc3, 0xc5, 0xc7,
+ 0xcc, 0xce, 0xcf, 0xb5, 0xd0, 0x05, 0xcf, 0xcc, 0xc2, 0xb1, 0xae, 0xb8,
+ 0x81, 0xbc, 0x05, 0xad, 0x7b, 0x9b, 0xb7, 0xc7, 0xce, 0x83, 0xd0, 0x03,
+ 0xcf, 0xcd, 0xcc, 0xcb, 0x80, 0xca, 0x20, 0xcb, 0xcc, 0xcd, 0xce, 0xce,
+ 0xcc, 0xcb, 0xca, 0xca, 0xcc, 0xcd, 0xce, 0xcf, 0xce, 0xcc, 0xcb, 0xca,
+ 0xca, 0xcc, 0xcc, 0xcd, 0xcd, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd0, 0xcf,
+ 0xce, 0xcd, 0xcc, 0xcd, 0x80, 0xcf, 0x07, 0xce, 0xcd, 0xcd, 0xce, 0xcf,
+ 0xcf, 0xce, 0xcd, 0x81, 0xcc, 0x04, 0xcb, 0xca, 0xc9, 0xca, 0xcb, 0x82,
+ 0xcc, 0x03, 0xcd, 0xce, 0xcd, 0xcc, 0x80, 0xcd, 0x1b, 0xcc, 0xca, 0xc9,
+ 0xc9, 0xca, 0xcb, 0xca, 0xc7, 0xbe, 0x96, 0x58, 0x2e, 0x37, 0x5c, 0x8c,
+ 0x98, 0xab, 0xbd, 0xc7, 0xcb, 0xcb, 0xca, 0xca, 0xcb, 0xcc, 0xcd, 0xcd,
+ 0xcc, 0x80, 0xcd, 0x01, 0xcc, 0xcc, 0x80, 0xcd, 0x07, 0xcc, 0xcd, 0xcd,
+ 0xcc, 0xcc, 0xca, 0xca, 0xcb, 0x81, 0xcc, 0x03, 0xcd, 0xce, 0xcd, 0xcd,
+ 0x81, 0xcc, 0x02, 0xcd, 0xcf, 0xcf, 0xb7, 0xd0, 0x0e, 0xce, 0xc9, 0xbd,
+ 0xa7, 0xab, 0xb5, 0xbc, 0xba, 0xad, 0x7d, 0x87, 0xa5, 0xbd, 0xca, 0xcf,
+ 0x84, 0xd0, 0x85, 0xcf, 0x80, 0xd0, 0x83, 0xcf, 0x80, 0xd0, 0x87, 0xcf,
+ 0x83, 0xd0, 0x80, 0xcf, 0x81, 0xd0, 0x00, 0xcf, 0x82, 0xd0, 0x83, 0xcf,
+ 0x01, 0xce, 0xce, 0x85, 0xcf, 0x00, 0xd0, 0x84, 0xcf, 0x11, 0xce, 0xce,
+ 0xcf, 0xcf, 0xce, 0xcb, 0xc4, 0xb8, 0xa9, 0x9e, 0x98, 0x99, 0xa0, 0xac,
+ 0xbb, 0xc6, 0xcc, 0xce, 0x9a, 0xcf, 0x01, 0xd0, 0xd0, 0x83, 0xcf, 0xb9,
+ 0xd0, 0x0e, 0xcf, 0xcc, 0xc6, 0xb8, 0xa4, 0x94, 0x95, 0x88, 0x7b, 0x87,
+ 0x9e, 0xb4, 0xc4, 0xcc, 0xcf, 0xff, 0xd0, 0xbf, 0xd0, 0x0c, 0xcf, 0xcc,
+ 0xc4, 0xb9, 0xab, 0x9e, 0x98, 0x9b, 0xa5, 0xb4, 0xc1, 0xca, 0xce, 0xff,
+ 0xd0, 0x93, 0xd0,
+};
+static EG_EMBEDDED_IMAGE egemb_refind_banner = { 210, 64, EG_EIPIXELMODE_COLOR, EG_EICOMPMODE_RLE, egemb_refind_banner_data, 22887 };
diff --git a/include/refit_call_wrapper.h b/include/refit_call_wrapper.h
new file mode 100644 (file)
index 0000000..1bd4042
--- /dev/null
@@ -0,0 +1,67 @@
+#ifndef __REFIT_CALL_WRAPPER_H__
+#define __REFIT_CALL_WRAPPER_H__
+
+#ifdef __MAKEWITH_GNUEFI
+
+#if defined (EFIX64) | defined (AARCH64)
+# define refit_call1_wrapper(f, a1) \
+  uefi_call_wrapper(f, 1, (UINT64)(a1))
+# define refit_call2_wrapper(f, a1, a2) \
+  uefi_call_wrapper(f, 2, (UINT64)(a1), (UINT64)(a2))
+# define refit_call3_wrapper(f, a1, a2, a3) \
+  uefi_call_wrapper(f, 3, (UINT64)(a1), (UINT64)(a2), (UINT64)(a3))
+# define refit_call4_wrapper(f, a1, a2, a3, a4) \
+  uefi_call_wrapper(f, 4, (UINT64)(a1), (UINT64)(a2), (UINT64)(a3), (UINT64)(a4))
+# define refit_call5_wrapper(f, a1, a2, a3, a4, a5) \
+  uefi_call_wrapper(f, 5, (UINT64)(a1), (UINT64)(a2), (UINT64)(a3), (UINT64)(a4), (UINT64)(a5))
+# define refit_call6_wrapper(f, a1, a2, a3, a4, a5, a6) \
+  uefi_call_wrapper(f, 6, (UINT64)(a1), (UINT64)(a2), (UINT64)(a3), (UINT64)(a4), (UINT64)(a5), (UINT64)(a6))
+# define refit_call10_wrapper(f, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) \
+  uefi_call_wrapper(f, 10, (UINT64)(a1), (UINT64)(a2), (UINT64)(a3), (UINT64)(a4), (UINT64)(a5), (UINT64)(a6), (UINT64)(a7), (UINT64)(a8), (UINT64)(a9), (UINT64)(a10))
+#else
+# define refit_call1_wrapper(f, a1) \
+  uefi_call_wrapper(f, 1, a1)
+# define refit_call2_wrapper(f, a1, a2) \
+  uefi_call_wrapper(f, 2, a1, a2)
+# define refit_call3_wrapper(f, a1, a2, a3) \
+  uefi_call_wrapper(f, 3, a1, a2, a3)
+# define refit_call4_wrapper(f, a1, a2, a3, a4) \
+  uefi_call_wrapper(f, 4, a1, a2, a3, a4)
+# define refit_call5_wrapper(f, a1, a2, a3, a4, a5) \
+  uefi_call_wrapper(f, 5, a1, a2, a3, a4, a5)
+# define refit_call6_wrapper(f, a1, a2, a3, a4, a5, a6) \
+  uefi_call_wrapper(f, 6, a1, a2, a3, a4, a5, a6)
+# define refit_call10_wrapper(f, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) \
+  uefi_call_wrapper(f, 10, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)
+#endif
+
+#else /* not GNU EFI -- TianoCore EDK2 */
+
+#define refit_call1_wrapper(f, a1) \
+        f(a1)
+#define refit_call2_wrapper(f, a1, a2) \
+        f(a1, a2)
+#define refit_call3_wrapper(f, a1, a2, a3) \
+        f(a1, a2, a3)
+#define refit_call4_wrapper(f, a1, a2, a3, a4) \
+        f(a1, a2, a3, a4)
+#define refit_call5_wrapper(f, a1, a2, a3, a4, a5) \
+        f(a1, a2, a3, a4, a5)
+#define refit_call6_wrapper(f, a1, a2, a3, a4, a5, a6) \
+        f(a1, a2, a3, a4, a5, a6)
+#define refit_call7_wrapper(f, a1, a2, a3, a4, a5, a6, a7) \
+        f(a1, a2, a3, a4, a5, a6, a7)
+#define refit_call8_wrapper(f, a1, a2, a3, a4, a5, a6, a7, a8) \
+        f(a1, a2, a3, a4, a5, a6, a7, a8)
+#define refit_call9_wrapper(f, a1, a2, a3, a4, a5, a6, a7, a8, a9) \
+        f(a1, a2, a3, a4, a5, a6, a7, a8, a9)
+#define refit_call10_wrapper(f, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) \
+        f(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)
+
+#define uefi_call_wrapper(f, n, ...) \
+        f(__VA_ARGS__)
+
+#endif /* not GNU EFI -- TianoCore EDK2 */
+
+#endif /* !__REFIT_CALL_WRAPPER_H__ */
+
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/include/tiano_includes.h b/include/tiano_includes.h
new file mode 100644 (file)
index 0000000..a723c91
--- /dev/null
@@ -0,0 +1,151 @@
+// A boatload of #includes needed to build the software with TianoCore's EDK2/UDK2010
+// toolkit. Placed here to maintain my own sanity.
+
+#ifndef _REFIND_TIANO_INCLUDES_
+#define _REFIND_TIANO_INCLUDES_
+
+#define ST gST
+#define BS gBS
+#define RT gRT
+#define RS gRS
+#define StrDuplicate EfiStrDuplicate
+#define LoadedImageProtocol gEfiLoadedImageProtocolGuid
+#define LibFileInfo EfiLibFileInfo
+#define Atoi StrDecimalToUintn
+#define SPrint UnicodeSPrint
+#define StrDuplicate EfiStrDuplicate
+#define EFI_MAXIMUM_VARIABLE_SIZE           1024
+
+#include <PiDxe.h>
+#include <Base.h>
+#include <Uefi.h>
+#include <FrameworkDxe.h>
+// Protocol Includes
+#include <Protocol/AbsolutePointer.h>
+#include <Protocol/AcpiTable.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/BlockIo2.h>
+#include <Protocol/Cpu.h>
+#include <Protocol/DataHub.h>
+#include <Protocol/DebugPort.h>
+#include <Protocol/Decompress.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/DevicePathFromText.h>
+#include <Protocol/DevicePathToText.h>
+#include <Protocol/DiskIo.h>
+#include <Protocol/EdidActive.h>
+#include <Protocol/EdidDiscovered.h>
+#include <Protocol/FirmwareVolume2.h>
+#include <Protocol/FrameworkHii.h>
+#include <Protocol/GraphicsOutput.h>
+#include <Protocol/HiiDatabase.h>
+#include <Protocol/HiiImage.h>
+#include <Protocol/LegacyBios.h>
+#include <Protocol/LoadedImage.h>
+#include <Protocol/LoadedImage.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/ScsiIo.h>
+#include <Protocol/ScsiPassThru.h>
+#include <Protocol/ScsiPassThruExt.h>
+#include <Protocol/SimpleFileSystem.h>
+#include <Protocol/SimpleNetwork.h>
+#include <Protocol/SimplePointer.h>
+#include <Protocol/SimpleTextIn.h>
+#include <Protocol/SimpleTextOut.h>
+#include <Protocol/Smbios.h>
+#include <Protocol/SmbusHc.h>
+#include <Protocol/UgaDraw.h>
+#include <Protocol/UgaIo.h>
+#include <Protocol/UnicodeCollation.h>
+#include <Protocol/UsbIo.h>
+#include <Protocol/LegacyBios.h>
+
+// Guid Includes
+#include <Guid/Acpi.h>
+#include <Guid/ConsoleInDevice.h>
+#include <Guid/ConsoleOutDevice.h>
+#include <Guid/DataHubRecords.h>
+#include <Guid/DxeServices.h>
+#include <Guid/EventGroup.h>
+#include <Guid/FileInfo.h>
+#include <Guid/FileSystemInfo.h>
+#include <Guid/FileSystemVolumeLabelInfo.h>
+#include <Guid/GlobalVariable.h>
+#include <Guid/HobList.h>
+#include <Guid/MemoryTypeInformation.h>
+#include <Guid/MemoryAllocationHob.h>
+#include <Guid/SmBios.h>
+#include <Guid/StandardErrorDevice.h>
+
+// Library Includes
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/DxeServicesLib.h>
+#include <Library/DxeServicesTableLib.h>
+//#include <Library/EblCmdLib.h>
+//#include <Library/EblNetworkLib.h>
+//#include "EfiFileLib.h"
+#include <Library/HiiLib.h>
+#include <Library/HobLib.h>
+#include <Library/IoLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PrintLib.h>
+#include <Library/TimerLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiScsiLib.h>
+
+// IndustryStandard Includes
+#include <IndustryStandard/Pci.h>
+#include <IndustryStandard/SmBus.h>
+#include <IndustryStandard/Acpi.h>
+#include <IndustryStandard/HighPrecisionEventTimerTable.h>
+#include <IndustryStandard/Scsi.h>
+
+#include "../EfiLib/Platform.h"
+
+
+BOOLEAN CheckError(IN EFI_STATUS Status, IN CHAR16 *where);
+
+//
+// BmLib
+//
+extern EFI_STATUS
+EfiLibLocateProtocol (
+   IN  EFI_GUID    *ProtocolGuid,
+   OUT VOID        **Interface
+);
+
+
+extern EFI_FILE_HANDLE
+EfiLibOpenRoot (
+   IN EFI_HANDLE                   DeviceHandle
+);
+
+extern EFI_FILE_SYSTEM_VOLUME_LABEL *
+EfiLibFileSystemVolumeLabelInfo (
+   IN EFI_FILE_HANDLE      FHand
+);
+extern CHAR16 *
+EfiStrDuplicate (
+   IN CHAR16   *Src
+);
+
+extern EFI_FILE_INFO * EfiLibFileInfo (IN EFI_FILE_HANDLE      FHand);
+extern EFI_FILE_SYSTEM_INFO * EfiLibFileSystemInfo (IN EFI_FILE_HANDLE   Root);
+
+
+extern VOID *
+EfiReallocatePool (
+   IN VOID                 *OldPool,
+   IN UINTN                OldSize,
+   IN UINTN                NewSize
+);
+
+#define PoolPrint(...) CatSPrint(NULL, __VA_ARGS__)
+
+#endif
\ No newline at end of file
diff --git a/keys/README.txt b/keys/README.txt
new file mode 100644 (file)
index 0000000..9577afd
--- /dev/null
@@ -0,0 +1,68 @@
+This directory contains known public keys for Linux distributions and from
+other parties that sign boot loaders and kernels that should be verifiable
+by shim. I'm providing these keys as a convenience to enable easy
+installation of keys should you replace your distribution's version of shim
+with another one and therefore require adding its public key as a machine
+owner key (MOK).
+
+Files come with three extensions. A filename ending in .crt is a
+certificate file that can be used by sbverify to verify the authenticity of
+a key, as in:
+
+$ sbverify --cert keys/refind.crt refind/refind_x64.efi
+
+The .cer and .der filename extensions are equivalent, and are public key
+files similar to .crt files, but in a different form. The MokManager
+utility expects its input public keys in this form, so these are the files
+you would use to add a key to the MOK list maintained by MokManager and
+used by shim.
+
+The files in this directory are, in alphabetical order:
+
+- altlinux.cer -- The public key for ALT Linux (http://www.altlinux.com).
+  Taken from the alt-uefi-certs package
+  (http://www.sisyphus.ru/br/srpm/Sisyphus/alt-uefi-certs/spec).
+
+- canonical-uefi-ca.crt & canonical-uefi-ca.der -- Canonical's public key,
+  matched to the one used to sign Ubuntu boot loaders and kernels.
+
+- fedora-ca.cer & fedora-ca.crt -- Fedora's public key, matched to the one
+  used used to sign Fedora's shim 0.8 binary.
+
+- microsoft-kekca-public.der -- Microsoft's key exchange key (KEK), which
+  is present on most UEFI systems with Secure Boot. The purpose of
+  Microsoft's KEK is to enable Microsoft tools to update Secure Boot
+  variables. There is no reason to add it to your MOK list.
+
+- microsoft-pca-public.der -- A Microsoft public key, matched to the one
+  used to sign Microsoft's own boot loader. You might include this key in
+  your MOK list if you replace the keys that came with your computer with
+  your own key but still want to boot Windows. There's no reason to add it
+  to your MOK list if your computer came this key pre-installed and you did
+  not replace the default keys.
+
+- microsoft-uefica-public.der -- A Microsoft public key, matched to the one
+  Microsoft uses to sign third-party applications and drivers. If you
+  remove your default keys, adding this one to your MOK list will enable
+  you to launch third-party boot loaders and other tools signed by
+  Microsoft. There's no reason to add it to your MOK list if your computer
+  came this key pre-installed and you did not replace the default keys.
+
+- openSUSE-UEFI-CA-Certificate.cer, openSUSE-UEFI-CA-Certificate.crt,
+  openSUSE-UEFI-CA-Certificate-4096.cer, &
+  openSUSE-UEFI-CA-Certificate-4096.crt -- Public keys matched to the ones
+  used to sign OpenSUSE; taken from openSUSE's shim 0.7.318.81ee56d
+  package.
+
+- refind.cer & refind.crt -- My own (Roderick W. Smith's) public key,
+  matched to the one used to sign refind_x64.efi and the 64-bit rEFInd
+  drivers.
+
+- SLES-UEFI-CA-Certificate.cer & SLES-UEFI-CA-Certificate.crt -- The Public
+  key for SUSE Linux Enterprise Server; taken from openSUSE's shim
+  0.7.318.81ee56d package.
+
+The refind.cer and refind.crt files are my creations and are distributed
+under the terms of the BSD 2-clause license. The rest of the files are
+distributed on the assumption that doing so constitutes fair use. Certainly
+they're all easily obtained on the Internet from other sources.
diff --git a/keys/SLES-UEFI-CA-Certificate.cer b/keys/SLES-UEFI-CA-Certificate.cer
new file mode 100644 (file)
index 0000000..0c2c514
Binary files /dev/null and b/keys/SLES-UEFI-CA-Certificate.cer differ
diff --git a/keys/SLES-UEFI-CA-Certificate.crt b/keys/SLES-UEFI-CA-Certificate.crt
new file mode 100644 (file)
index 0000000..7efd6c8
--- /dev/null
@@ -0,0 +1,29 @@
+-----BEGIN CERTIFICATE-----
+MIIE5TCCA82gAwIBAgIBATANBgkqhkiG9w0BAQsFADCBpjEtMCsGA1UEAwwkU1VT
+RSBMaW51eCBFbnRlcnByaXNlIFNlY3VyZSBCb290IENBMQswCQYDVQQGEwJERTES
+MBAGA1UEBwwJTnVyZW1iZXJnMSEwHwYDVQQKDBhTVVNFIExpbnV4IFByb2R1Y3Rz
+IEdtYkgxEzARBgNVBAsMCkJ1aWxkIFRlYW0xHDAaBgkqhkiG9w0BCQEWDWJ1aWxk
+QHN1c2UuZGUwHhcNMTMwNDE4MTQzMzQxWhcNMzUwMzE0MTQzMzQxWjCBpjEtMCsG
+A1UEAwwkU1VTRSBMaW51eCBFbnRlcnByaXNlIFNlY3VyZSBCb290IENBMQswCQYD
+VQQGEwJERTESMBAGA1UEBwwJTnVyZW1iZXJnMSEwHwYDVQQKDBhTVVNFIExpbnV4
+IFByb2R1Y3RzIEdtYkgxEzARBgNVBAsMCkJ1aWxkIFRlYW0xHDAaBgkqhkiG9w0B
+CQEWDWJ1aWxkQHN1c2UuZGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
+AQDN/avXKoT4gcM2NVA1LMfsBPH01sxgS8gTs3SbvfbEP2M+ZlHyfj9ufHZ7cZ1p
+ISoVm6ql5VbIeZgSNc17Y4y4Nynud1C8t2SP/iZK5YMYHGxdtIfv1zPE+Bo/KZqE
+WgHg2YFtMXdiKfXBZRTfSh37t0pGO/OQi6K4JioKw55UtQNggePZWDXtsAviT2vv
+abqLR9+kxdrQ0iWqhWM+LwXbTGkCpg41s8KucLD/JYAxxw05dKPApFDNnz+Ft2L7
+e5JtyB4S0u4PlvQBMNHt4hDs0rK4oeHFLbOxHvjF+nloneWhkg9eT0VCfpAYVYz+
+whMxuCHerDCdmeFrRGEMQz11AgMBAAGjggEaMIIBFjAPBgNVHRMBAf8EBTADAQH/
+MB0GA1UdDgQWBBTsqw1CxFbPdwQ2uXOZOGKWXocmLzCB0wYDVR0jBIHLMIHIgBTs
+qw1CxFbPdwQ2uXOZOGKWXocmL6GBrKSBqTCBpjEtMCsGA1UEAwwkU1VTRSBMaW51
+eCBFbnRlcnByaXNlIFNlY3VyZSBCb290IENBMQswCQYDVQQGEwJERTESMBAGA1UE
+BwwJTnVyZW1iZXJnMSEwHwYDVQQKDBhTVVNFIExpbnV4IFByb2R1Y3RzIEdtYkgx
+EzARBgNVBAsMCkJ1aWxkIFRlYW0xHDAaBgkqhkiG9w0BCQEWDWJ1aWxkQHN1c2Uu
+ZGWCAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4IBAQASviyFhVqU
+Wc1JUQgXwdljJynTnp0/FQOZJBSe7XdBGPmy91+3ITqrXgyqo/218KISiQl53Qlw
+pq+cIiGRAia1D7p7wbg7wsg+Trt0zZFXes30wfYq5pjfWadEBAgNCffkBz10TSjL
+jQrVwW5N+yUJMoq+r843TzV56Huy6LBOVhI5yTz7X7i2rSJYfyQWM8oeHLj8Yl5M
+rOB9gyTumxB4mOLmSqwKzJiUB0ppGPohdLUSSEKDdo6KSH/GjR7M7uBicwnzwJD3
+SVfT9nx9HKF2nXZlHvs5ViQQru3qP1tc6i0eXEnPTYW2+zkZcN0e5iHyozEZHsO0
+rvc1p6G0YWtO
+-----END CERTIFICATE-----
diff --git a/keys/altlinux.cer b/keys/altlinux.cer
new file mode 100644 (file)
index 0000000..e1b9579
Binary files /dev/null and b/keys/altlinux.cer differ
diff --git a/keys/canonical-uefi-ca.crt b/keys/canonical-uefi-ca.crt
new file mode 100644 (file)
index 0000000..55c06d5
--- /dev/null
@@ -0,0 +1,25 @@
+-----BEGIN CERTIFICATE-----
+MIIENDCCAxygAwIBAgIJALlBJKAYLJJnMA0GCSqGSIb3DQEBCwUAMIGEMQswCQYD
+VQQGEwJHQjEUMBIGA1UECAwLSXNsZSBvZiBNYW4xEDAOBgNVBAcMB0RvdWdsYXMx
+FzAVBgNVBAoMDkNhbm9uaWNhbCBMdGQuMTQwMgYDVQQDDCtDYW5vbmljYWwgTHRk
+LiBNYXN0ZXIgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTEyMDQxMjExMTI1MVoX
+DTQyMDQxMTExMTI1MVowgYQxCzAJBgNVBAYTAkdCMRQwEgYDVQQIDAtJc2xlIG9m
+IE1hbjEQMA4GA1UEBwwHRG91Z2xhczEXMBUGA1UECgwOQ2Fub25pY2FsIEx0ZC4x
+NDAyBgNVBAMMK0Nhbm9uaWNhbCBMdGQuIE1hc3RlciBDZXJ0aWZpY2F0ZSBBdXRo
+b3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC/WzoWdO4hXa5h
+7Z1WrL3e3nLz3X4tTGIPrMBtSAgRz42L+2EfJ8wRbtlVPTlU60A7sbvihTR5yvd7
+v7p6yBAtGX2tWc+m1OlOD9quUupMnpDOxpkNTmdleF350dU4Skp6j5OcfxqjhdvO
++ov3wqIhLZtUQTUQVxONbLwpBlBKfuqZqWinO8cHGzKeoBmHDnm7aJktfpNS5fbr
+yZv5K+24aEm82ZVQQFvFsnGq61xX3nH5QArdW6wehC1QGlLW4fNrbpBkT1u06yDk
+YRDaWvDq5ELXAcT+IR/ZucBUlUKBUnIfSWR6yGwk8QhwC02loDLRoBxXqE3jr6WO
+BQU+EEOhAgMBAAGjgaYwgaMwHQYDVR0OBBYEFK2RmQvCKrH1FwSMI7ZlWiaONFpj
+MB8GA1UdIwQYMBaAFK2RmQvCKrH1FwSMI7ZlWiaONFpjMA8GA1UdEwEB/wQFMAMB
+Af8wCwYDVR0PBAQDAgGGMEMGA1UdHwQ8MDowOKA2oDSGMmh0dHA6Ly93d3cuY2Fu
+b25pY2FsLmNvbS9zZWN1cmUtYm9vdC1tYXN0ZXItY2EuY3JsMA0GCSqGSIb3DQEB
+CwUAA4IBAQA/ffZ2pbODtCt60G1SGgODxBKnUJxHkszAlHeC0q5Xs5kE9TI6xlUd
+B9sSqVb62NR2IOvkw1Hbmlyckj8Yc9qUaqGZOIykiG3B/Dlx0HR2FgM+ViM11VVH
+WxodQcLTEkzc/64KkpxiChcBnHPgXrH9vNa1GRF6fs0+A35m21uoyTlIUf9T4Zwx
+U5EbOxB1Axe65oECgJRwTEa3lLA9Fc0fjgLgaAKP+/lHHX2iAcYHUcSazO3dz6Nd
+7ZK7vtH95uwfM1FzBL48crB9CPgB/5h9y5zgaTl3JUdxiLGNJ6UuqPc/X4Bplz6p
+9JkU284DDgtmxBxtvbgnd8FClL38agq8
+-----END CERTIFICATE-----
diff --git a/keys/canonical-uefi-ca.der b/keys/canonical-uefi-ca.der
new file mode 100644 (file)
index 0000000..b4098d9
Binary files /dev/null and b/keys/canonical-uefi-ca.der differ
diff --git a/keys/fedora-ca.cer b/keys/fedora-ca.cer
new file mode 100644 (file)
index 0000000..b81707b
Binary files /dev/null and b/keys/fedora-ca.cer differ
diff --git a/keys/fedora-ca.crt b/keys/fedora-ca.crt
new file mode 100644 (file)
index 0000000..8776562
--- /dev/null
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDaDCCAlCgAwIBAgIFAJl28vQwDQYJKoZIhvcNAQELBQAwIDEeMBwGA1UEAxMV
+RmVkb3JhIFNlY3VyZSBCb290IENBMB4XDTEyMTIwNzE2MjU1NFoXDTIyMTIwNTE2
+MjU1NFowIDEeMBwGA1UEAxMVRmVkb3JhIFNlY3VyZSBCb290IENBMIIBIjANBgkq
+hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArvX3UoGpXD4r9x1V9FpohC28i3aWhQ0n
+uBilzcGDsownXSMK0RIKdZii5l0BivTZn/xwvMPEF3sCtRPEUZLgwAV0uS49JHig
+eXOUwMIrsoKn9KtnSiLzZM3D+QwmAb8b1T05v8n6+15SuaRI+xO/hykKZO8he7we
+FnuIT/FAK9kiFUdOhPYkHE1TFlqxKbtefX/A1OLVea9ZcwLct0i/ritwwfp0f3n1
+7iPQAwWxeRhP/U8v4mMZTXe6wSyLs9kFLtnYtlETv842Z5fkrVhWB6vQjGYSSdyR
+aLTI6t2cwIHGkVvbEnjb/8GvCBb8cBOXW1eta0SYfh/s7UZmlQ8FVQIDAQABo4Go
+MIGlME4GCCsGAQUFBwEBBEIwQDA+BggrBgEFBQcwAoYyaHR0cHM6Ly9mZWRvcmFw
+cm9qZWN0Lm9yZy93aWtpL0ZlYXR1cmVzL1NlY3VyZUJvb3QwHwYDVR0jBBgwFoAU
+/eMlmcLWHbG/WAczXXsg5M2WO0IwEwYDVR0lBAwwCgYIKwYBBQUHAwMwHQYDVR0O
+BBYEFP3jJZnC1h2xv1gHM117IOTNljtCMA0GCSqGSIb3DQEBCwUAA4IBAQA3d/A6
+QaIcn3E71puVtRXfSrb00VG6DQTanLIj8PM0WY241Jp1dGWAF2E6wZZ/p8Er0xrW
+YDxxOqTE4zkDAhUSCB9OzZdQ+P9QzLY+A31654J6wme+yQ4RDxYuHqnybv4Eveqe
+9Kmz2dRhVwiHxJjYoplk3hVUjVd5FB/6DU1rzZg19QwGvfMx1v4FH2CQth4Q9yTg
+PPYzUM1EwnEYUb0YMYEeMuHmn/mcAlO05WpB1mW0LvHPs7iCsKOW4iTYg64GW7Mk
+dE3RpAodCjIbdaKW0Q4+4TDDGOjLU8QLAK1+rchJQe+Xab0TX+/vPNpgBdiS/Npq
+6kg/Dj5zd/2miek/
+-----END CERTIFICATE-----
diff --git a/keys/microsoft-kekca-public.der b/keys/microsoft-kekca-public.der
new file mode 100644 (file)
index 0000000..2787083
Binary files /dev/null and b/keys/microsoft-kekca-public.der differ
diff --git a/keys/microsoft-pca-public.der b/keys/microsoft-pca-public.der
new file mode 100644 (file)
index 0000000..a6d001c
Binary files /dev/null and b/keys/microsoft-pca-public.der differ
diff --git a/keys/microsoft-uefica-public.der b/keys/microsoft-uefica-public.der
new file mode 100644 (file)
index 0000000..9aa6ac6
Binary files /dev/null and b/keys/microsoft-uefica-public.der differ
diff --git a/keys/openSUSE-UEFI-CA-Certificate-4096.cer b/keys/openSUSE-UEFI-CA-Certificate-4096.cer
new file mode 100644 (file)
index 0000000..1b530bc
Binary files /dev/null and b/keys/openSUSE-UEFI-CA-Certificate-4096.cer differ
diff --git a/keys/openSUSE-UEFI-CA-Certificate-4096.crt b/keys/openSUSE-UEFI-CA-Certificate-4096.crt
new file mode 100644 (file)
index 0000000..cff5536
--- /dev/null
@@ -0,0 +1,37 @@
+-----BEGIN CERTIFICATE-----
+MIIGdDCCBFygAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgTEgMB4GA1UEAwwXb3Bl
+blNVU0UgU2VjdXJlIEJvb3QgQ0ExCzAJBgNVBAYTAkRFMRIwEAYDVQQHDAlOdXJl
+bWJlcmcxGTAXBgNVBAoMEG9wZW5TVVNFIFByb2plY3QxITAfBgkqhkiG9w0BCQEW
+EmJ1aWxkQG9wZW5zdXNlLm9yZzAeFw0xMzAxMjgxNDUzMzBaFw0zNDEyMjQxNDUz
+MzBaMIGBMSAwHgYDVQQDDBdvcGVuU1VTRSBTZWN1cmUgQm9vdCBDQTELMAkGA1UE
+BhMCREUxEjAQBgNVBAcMCU51cmVtYmVyZzEZMBcGA1UECgwQb3BlblNVU0UgUHJv
+amVjdDEhMB8GCSqGSIb3DQEJARYSYnVpbGRAb3BlbnN1c2Uub3JnMIICIjANBgkq
+hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAuqmSgrdlO0B96sOK5mJj1k4OetzmP6l8
+YKdy+HdzN/3bS97vfqIIqb0YCgzmJROSLsXv6WQReuAtKbftgla6R/dOvKU/CxCN
+z0uCbzuM+gN5Q7pSWifnm81QNDowFpxZlJBFvIP92zh5yWNEGqVzMN0jDjOFxLfh
+O1sx6W8YBOYzScWrlTKysH6uK79gWenwvh3nmkx+68PV08azmizG6As4IAPDqtd/
+w92iLTzjLVGp32wFDhLuDleojjvJgnOGngKa8oRcLlvfh07wKO0urjt8/3HKxcUf
+RmbSyaLdfP8lOt/mFPpfN4kev9wjqdbIhLIZs6iKbu+hR40QfAR46V8vnPoeIYeM
+ibsl1mvr0U7O6w7kTQuzW7JmJkCYf7n4HoPBgxTzgjKlsBGY0I+dTvZXozsKuTKx
+ir/w6WWcdkIWoXJh00Nb9eWqFQr0exG0hwa1o0ESXjv7aJHwg39B6m8MZVppdpmg
+i0G8pOKtHQZ6OR87YeSUHJ400ocIfYMOAybuB/5rHfC58BvCcjaZwHKTkHlyx28i
+EXgFyzGMqbWlgmI5RJ8UzaM6rTaieIRSsyGbYrDa89BFMhGmY8xMIeeT8191bLbH
+CpX7CMW9npoEqslHL67FMI3LXC5fgYKoPwUnj/TlT0gkjVobEXmXZB6sCDQ6BFTg
+4dpPIFEjnxsCAwEAAaOB9DCB8TAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSZ
+DSa38E3ZzmTn0Y79aHtKXeKGpTCBrgYDVR0jBIGmMIGjgBSZDSa38E3ZzmTn0Y79
+aHtKXeKGpaGBh6SBhDCBgTEgMB4GA1UEAwwXb3BlblNVU0UgU2VjdXJlIEJvb3Qg
+Q0ExCzAJBgNVBAYTAkRFMRIwEAYDVQQHDAlOdXJlbWJlcmcxGTAXBgNVBAoMEG9w
+ZW5TVVNFIFByb2plY3QxITAfBgkqhkiG9w0BCQEWEmJ1aWxkQG9wZW5zdXNlLm9y
+Z4IBATAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIBAFsmHlxiAGKu
+Qyx1qb6l7bEWgXAePQfVaaCEH4Mn+oq80kJ67S7s6We8e5QJOgYznk5mDk+PTUC/
+phkP3aJRqZAf5UDrQkOHobpk7FFBxZKjZfULPls3H9+Hichw/XJ2/xJwG+Ja6pgD
+dNO2UaKOjZHCiyZ4ehO7syle/EgQALVwKH4cVq6zIh4xUH4r9WvfdR5vkhhTgM/0
+nzzoBnFRnCUpcsLPj10246wVuLQcliZBeKjiV4xqrMe6cXX8crHvZqqJPZ2jMTGD
+eVIpVES12ZpMT7SbQbcDR1XgjqrL3U9vfcabdqLU60000ALvnDFNN0Sm7xhB+d3c
+sDIyJMwSfIb9jWApsB/En5uRCM++ruqjyFiqTCORo9gzaocw6gut6WYs2TOrZ2NO
+Tq4JNAFfCL/z0p8jdz1dJZmqpgFAlltKNNDWV6KlBPUAdxDEbIiuGoYweB+Zxed3
+BKdlrKGcH0ewPmzt4vVLCl2yFoODxjVtndXieDt/BWIYltMjqYU1qrrOdISHdeAG
+A24L/uxiU4Ej2bKKWNYtvrGMNLMUWBTx5afHMQnK9MD8Z6cpjccNaR0Pe9ZCBRGI
+xyUitlfnU604q1GfYdymiq4mUvSEgy3vbbsVBvcAKElN+hWpAeZbiWc/KcBWKMtp
+4aQ0yoLWDFkQNGU0rGazsu3hpOWta6mL
+-----END CERTIFICATE-----
diff --git a/keys/openSUSE-UEFI-CA-Certificate.cer b/keys/openSUSE-UEFI-CA-Certificate.cer
new file mode 100644 (file)
index 0000000..73fcb44
Binary files /dev/null and b/keys/openSUSE-UEFI-CA-Certificate.cer differ
diff --git a/keys/openSUSE-UEFI-CA-Certificate.crt b/keys/openSUSE-UEFI-CA-Certificate.crt
new file mode 100644 (file)
index 0000000..e943169
--- /dev/null
@@ -0,0 +1,26 @@
+-----BEGIN CERTIFICATE-----
+MIIEdDCCA1ygAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgTEgMB4GA1UEAwwXb3Bl
+blNVU0UgU2VjdXJlIEJvb3QgQ0ExCzAJBgNVBAYTAkRFMRIwEAYDVQQHDAlOdXJl
+bWJlcmcxGTAXBgNVBAoMEG9wZW5TVVNFIFByb2plY3QxITAfBgkqhkiG9w0BCQEW
+EmJ1aWxkQG9wZW5zdXNlLm9yZzAeFw0xMzA4MjYxNjEyMDdaFw0zNTA3MjIxNjEy
+MDdaMIGBMSAwHgYDVQQDDBdvcGVuU1VTRSBTZWN1cmUgQm9vdCBDQTELMAkGA1UE
+BhMCREUxEjAQBgNVBAcMCU51cmVtYmVyZzEZMBcGA1UECgwQb3BlblNVU0UgUHJv
+amVjdDEhMB8GCSqGSIb3DQEJARYSYnVpbGRAb3BlbnN1c2Uub3JnMIIBIjANBgkq
+hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3t9hknqk/oPRfTtoDrGn8E6Sk/xHPnAt
+Tojcmp76M7Sm2w4jwQ2owdVlBIQE/zpIGE85MuTKTvkEnp8PzSBdYaunANil/yt/
+vuhHwy9bAsi73o4a6UbThu//iJmQ6xCJuIs/PqgHxlV6btNf/IM8PRbtJsUTc5Kx
+cB4ilcgAbCV2RvGi2dCwmGgPpy2xDWeJypRK6hLFkVV2f2x6LvkYiZ/49CRD1TVq
+ywAOLu1L4l0J2BuXcJmeWm+mgaidqVh2fWlxgtO6OpZDm/DaFcZO6cgVuenLx+Rx
+zuoQG2vEKnABqVK0F94AUs995P0PTQMYspAo1G/Erla8NmBJRotrCwIDAQABo4H0
+MIHxMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFGhCYA3iLExHfpW+I9/qlRPl
+lxdiMIGuBgNVHSMEgaYwgaOAFGhCYA3iLExHfpW+I9/qlRPllxdioYGHpIGEMIGB
+MSAwHgYDVQQDDBdvcGVuU1VTRSBTZWN1cmUgQm9vdCBDQTELMAkGA1UEBhMCREUx
+EjAQBgNVBAcMCU51cmVtYmVyZzEZMBcGA1UECgwQb3BlblNVU0UgUHJvamVjdDEh
+MB8GCSqGSIb3DQEJARYSYnVpbGRAb3BlbnN1c2Uub3JnggEBMA4GA1UdDwEB/wQE
+AwIBhjANBgkqhkiG9w0BAQsFAAOCAQEAiqOJwo7Z+YIL8zPO6RkXF6NlgM0zrgZR
+Vim2OId79J38KI6q4FMSDjpgxwbYOmF2O3cI9JSkjHxHOpnYhJsXzCBiLuJ25MY2
+DSbpLlM1Cvs6NZNFw5OCwQvzCOlXH1k3qdBsafto6n87r9P3WSeO1MeWc/QMCvc+
+5K9sjMd6bwl59EEf428R+z5ssaB75JK3yvky9d7DsHN947OCXc3sYdz+DD7Gteds
+LV2Sc//tqmqpm2aeXjptcLAxwM7fLyEQaAyH83egMzEKDxX27jKIxZpTcc0NGqEo
+idC/9lasSzs2BisBxevl3HKDPZSsKIMT+8FdJ5wT9jJf9h9Ktz5Tig==
+-----END CERTIFICATE-----
diff --git a/keys/refind.cer b/keys/refind.cer
new file mode 100644 (file)
index 0000000..9774f80
Binary files /dev/null and b/keys/refind.cer differ
diff --git a/keys/refind.crt b/keys/refind.crt
new file mode 100644 (file)
index 0000000..614f6d2
--- /dev/null
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDOzCCAiOgAwIBAgIJAODF7HQMFVJOMA0GCSqGSIb3DQEBBQUAMDQxMjAwBgNV
+BAMMKVJvZGVyaWNrIFcuIFNtaXRoLCByb2RzbWl0aEByb2RzYm9va3MuY29tMB4X
+DTEyMTIwNjIxMzgyOFoXDTMyMTIwMTIxMzgyOFowNDEyMDAGA1UEAwwpUm9kZXJp
+Y2sgVy4gU21pdGgsIHJvZHNtaXRoQHJvZHNib29rcy5jb20wggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQCqTnWTvfemH1XP4RqiCITm1Zuvwil1+XhccYx2
+YQ23IU/e1Dvdn5xtk6Qk0IQa8pYG8DrQdOQJkItv3PDYuOu0Zx/dHVm93okHBAS1
+X2JJcslswHv/hAATs0Xnv3fJt30mJ0ja+KDbSOZ3V0MH+pjBkc/6Pk7xHuOkWwjJ
+6iP5nePeD8oGvQcGuwZe9XhiK1NKa23j9WzVU8hl0buhyatBd/xASs9JnUsmEhsG
+dqasdmWp6QqTvj/QwWoJd7J5zmU0k5SGt5I0kKQGKo/epCU9XdAf5z198J0D6XyP
+fN3y2ZYTPGb/1rMNdceQXDxhl/ps3n4A/qIKiZW3Ks8cOj+HAgMBAAGjUDBOMB0G
+A1UdDgQWBBTTDAa9OVimbJh1fwmoCFXhdEpacDAfBgNVHSMEGDAWgBTTDAa9OVim
+bJh1fwmoCFXhdEpacDAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQCo
+9/vhRiG9oMEaJtihy4/pYTs9EiKCQ6ewzcbQaBz7mPXec7h5E4LuxhE7Rl/+1/xq
+39X8D7C0mbDyN0Drt3Ovf+hhzWdpkDIQ/7P6SdRTxAXE+/xUOj57jENPXZWV0jDt
+Uy1MGZN9IKAUXfnPfmv72FYN9XoUVv3d5yy9wSCc/9AlGHx8lGDJ/p7DJSXGmBKO
+BQV/1Y39GCxaSWdyrcjnV1swUBLO9tesfCRwfoo/rNh+wgK9P+emLbh+jSTL/zW/
+Ye1NS0VXD3pWTswA7M7XYOy6KON2vKupFyHhDj3NMzspq8/oDQHLvUzq1I8z99sd
+it92eWJ2JKoH6nSKDKXq
+-----END CERTIFICATE-----
diff --git a/libeg/Make.tiano b/libeg/Make.tiano
new file mode 100644 (file)
index 0000000..21dc026
--- /dev/null
@@ -0,0 +1,24 @@
+#
+# libeg/Make.tiano
+# Build control file for libeg components of rEFInd, using TianoCore EDK2
+#
+
+# This program is licensed under the terms of the GNU GPL, version 3,
+# or (at your option) any later version.
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+include ../Make.tiano
+
+SOURCE_NAMES     = image load_bmp load_icns lodepng lodepng_xtra screen text
+OBJS             = $(SOURCE_NAMES:=.obj)
+#DRIVERNAME      = ext2
+#BUILDME          = $(DRIVERNAME)_$(FILENAME_CODE).efi
+
+all: $(AR_TARGET)
+
+$(AR_TARGET): $(OBJS)
+       $(AR) -cr $(AR_TARGET).lib $(OBJS)
+
+clean:
+       make clean
diff --git a/libeg/Makefile b/libeg/Makefile
new file mode 100644 (file)
index 0000000..6b564d4
--- /dev/null
@@ -0,0 +1,24 @@
+#
+# libeg/Makefile
+# Build control file for the libeg library
+#
+
+# This program is licensed under the terms of the GNU GPL, version 3,
+# or (at your option) any later version.
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+SRCDIR = .
+
+VPATH = $(SRCDIR)
+
+LOCAL_CPPFLAGS  = -I$(SRCDIR) -I$(SRCDIR)/../include
+
+OBJS            = screen.o image.o text.o load_bmp.o load_icns.o lodepng.o lodepng_xtra.o
+TARGET          = libeg.a
+
+all: $(TARGET)
+
+include $(SRCDIR)/../Make.common
+
+# EOF
diff --git a/libeg/efiConsoleControl.h b/libeg/efiConsoleControl.h
new file mode 100644 (file)
index 0000000..187f562
--- /dev/null
@@ -0,0 +1,121 @@
+/*++ \r
+\r
+Copyright (c) 2004, Intel Corporation                                                         \r
+All rights reserved. This program and the accompanying materials                          \r
+are licensed and made available under the terms and conditions of the BSD License         \r
+which accompanies this distribution.  The full text of the license may be found at        \r
+http://opensource.org/licenses/bsd-license.php                                            \r
+                                                                                          \r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
+\r
+Module Name:\r
+\r
+  ConsoleControl.h\r
+\r
+Abstract:\r
+\r
+  Abstraction of a Text mode or UGA screen\r
+\r
+--*/\r
+\r
+#ifndef __CONSOLE_CONTROL_H__\r
+#define __CONSOLE_CONTROL_H__\r
+\r
+#define EFI_CONSOLE_CONTROL_PROTOCOL_GUID \\r
+  { 0xf42f7782, 0x12e, 0x4c12, { 0x99, 0x56, 0x49, 0xf9, 0x43, 0x4, 0xf7, 0x21 } }\r
+\r
+struct _EFI_CONSOLE_CONTROL_PROTOCOL;\r
+\r
+\r
+typedef enum {\r
+  EfiConsoleControlScreenText,\r
+  EfiConsoleControlScreenGraphics,\r
+  EfiConsoleControlScreenMaxValue\r
+} EFI_CONSOLE_CONTROL_SCREEN_MODE;\r
+\r
+\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *EFI_CONSOLE_CONTROL_PROTOCOL_GET_MODE) (\r
+  IN  struct _EFI_CONSOLE_CONTROL_PROTOCOL *This,\r
+  OUT EFI_CONSOLE_CONTROL_SCREEN_MODE   *Mode,\r
+  OUT BOOLEAN                           *UgaExists,   OPTIONAL  \r
+  OUT BOOLEAN                           *StdInLocked  OPTIONAL\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+    Return the current video mode information. Also returns info about existence\r
+    of UGA Draw devices in system, and if the Std In device is locked. All the\r
+    arguments are optional and only returned if a non NULL pointer is passed in.\r
+\r
+  Arguments:\r
+    This - Protocol instance pointer.\r
+    Mode        - Are we in text of grahics mode.\r
+    UgaExists   - TRUE if UGA Spliter has found a UGA device\r
+    StdInLocked - TRUE if StdIn device is keyboard locked\r
+\r
+  Returns:\r
+    EFI_SUCCESS     - Mode information returned.\r
+\r
+--*/\r
+;\r
+\r
+\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *EFI_CONSOLE_CONTROL_PROTOCOL_SET_MODE) (\r
+  IN  struct _EFI_CONSOLE_CONTROL_PROTOCOL *This,\r
+  OUT EFI_CONSOLE_CONTROL_SCREEN_MODE   Mode\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+    Set the current mode to either text or graphics. Graphics is\r
+    for Quiet Boot.\r
+\r
+  Arguments:\r
+    This  - Protocol instance pointer.\r
+    Mode  - Mode to set the \r
+\r
+  Returns:\r
+    EFI_SUCCESS     - Mode information returned.\r
+\r
+--*/\r
+;\r
+\r
+\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *EFI_CONSOLE_CONTROL_PROTOCOL_LOCK_STD_IN) (\r
+  IN struct _EFI_CONSOLE_CONTROL_PROTOCOL *This,\r
+  IN CHAR16                             *Password\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+    Lock Std In devices until Password is typed.\r
+\r
+  Arguments:\r
+    This     - Protocol instance pointer.\r
+    Password - Password needed to unlock screen. NULL means unlock keyboard\r
+\r
+  Returns:\r
+    EFI_SUCCESS      - Mode information returned.\r
+    EFI_DEVICE_ERROR - Std In not locked\r
+\r
+--*/\r
+;\r
+\r
+\r
+\r
+typedef struct _EFI_CONSOLE_CONTROL_PROTOCOL {\r
+  EFI_CONSOLE_CONTROL_PROTOCOL_GET_MODE           GetMode;\r
+  EFI_CONSOLE_CONTROL_PROTOCOL_SET_MODE           SetMode;\r
+  EFI_CONSOLE_CONTROL_PROTOCOL_LOCK_STD_IN        LockStdIn;\r
+} EFI_CONSOLE_CONTROL_PROTOCOL;\r
+\r
+//extern EFI_GUID gEfiConsoleControlProtocolGuid;\r
+\r
+#endif\r
diff --git a/libeg/efiUgaDraw.h b/libeg/efiUgaDraw.h
new file mode 100644 (file)
index 0000000..bce3f24
--- /dev/null
@@ -0,0 +1,182 @@
+/*++\r
+\r
+Copyright (c) 2004, Intel Corporation                                                         \r
+All rights reserved. This program and the accompanying materials                          \r
+are licensed and made available under the terms and conditions of the BSD License         \r
+which accompanies this distribution.  The full text of the license may be found at        \r
+http://opensource.org/licenses/bsd-license.php                                            \r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
+\r
+Module Name:\r
+\r
+UgaDraw.h\r
+\r
+Abstract:\r
+\r
+UGA Draw protocol from the EFI 1.1 specification.\r
+\r
+Abstraction of a very simple graphics device.\r
+\r
+--*/\r
+\r
+#ifndef __UGA_DRAW_H__\r
+#define __UGA_DRAW_H__\r
+\r
+#define EFI_UGA_DRAW_PROTOCOL_GUID \\r
+{ \\r
+    0x982c298b, 0xf4fa, 0x41cb, { 0xb8, 0x38, 0x77, 0xaa, 0x68, 0x8f, 0xb8, 0x39 } \\r
+}\r
+\r
+/* typedef struct _EFI_UGA_DRAW_PROTOCOL EFI_UGA_DRAW_PROTOCOL; */\r
+struct _EFI_UGA_DRAW_PROTOCOL;\r
+\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *EFI_UGA_DRAW_PROTOCOL_GET_MODE) (\r
+                                          IN  struct _EFI_UGA_DRAW_PROTOCOL * This,\r
+                                          OUT UINT32                *HorizontalResolution,\r
+                                          OUT UINT32                *VerticalResolution,\r
+                                          OUT UINT32                *ColorDepth,\r
+                                          OUT UINT32                *RefreshRate\r
+                                          )\r
+/*++\r
+\r
+Routine Description:\r
+Return the current video mode information.\r
+\r
+Arguments:\r
+This                  - Protocol instance pointer.\r
+HorizontalResolution  - Current video horizontal resolution in pixels\r
+VerticalResolution    - Current video vertical resolution in pixels\r
+ColorDepth            - Current video color depth in bits per pixel\r
+RefreshRate           - Current video refresh rate in Hz.\r
+\r
+Returns:\r
+EFI_SUCCESS     - Mode information returned.\r
+EFI_NOT_STARTED - Video display is not initialized. Call SetMode () \r
+EFI_INVALID_PARAMETER - One of the input args was NULL.\r
+\r
+--*/\r
+;\r
+\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *EFI_UGA_DRAW_PROTOCOL_SET_MODE) (\r
+                                          IN  struct _EFI_UGA_DRAW_PROTOCOL * This,\r
+                                          IN  UINT32                HorizontalResolution,\r
+                                          IN  UINT32                VerticalResolution,\r
+                                          IN  UINT32                ColorDepth,\r
+                                          IN  UINT32                RefreshRate\r
+                                          )\r
+/*++\r
+\r
+Routine Description:\r
+Return the current video mode information.\r
+\r
+Arguments:\r
+This                  - Protocol instance pointer.\r
+HorizontalResolution  - Current video horizontal resolution in pixels\r
+VerticalResolution    - Current video vertical resolution in pixels\r
+ColorDepth            - Current video color depth in bits per pixel\r
+RefreshRate           - Current video refresh rate in Hz.\r
+\r
+Returns:\r
+EFI_SUCCESS     - Mode information returned.\r
+EFI_NOT_STARTED - Video display is not initialized. Call SetMode () \r
+\r
+--*/\r
+;\r
+\r
+typedef struct {\r
+    UINT8 Blue;\r
+    UINT8 Green;\r
+    UINT8 Red;\r
+    UINT8 Reserved;\r
+} EFI_UGA_PIXEL;\r
+\r
+typedef union {\r
+    EFI_UGA_PIXEL Pixel;\r
+    UINT32        Raw;\r
+} EFI_UGA_PIXEL_UNION;\r
+\r
+typedef enum {\r
+    EfiUgaVideoFill,\r
+    EfiUgaVideoToBltBuffer,\r
+    EfiUgaBltBufferToVideo,\r
+    EfiUgaVideoToVideo,\r
+    EfiUgaBltMax\r
+} EFI_UGA_BLT_OPERATION;\r
+\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *EFI_UGA_DRAW_PROTOCOL_BLT) (\r
+                                     IN  struct _EFI_UGA_DRAW_PROTOCOL           * This,\r
+                                     IN  EFI_UGA_PIXEL                           * BltBuffer, OPTIONAL\r
+                                     IN  EFI_UGA_BLT_OPERATION                   BltOperation,\r
+                                     IN  UINTN                                   SourceX,\r
+                                     IN  UINTN                                   SourceY,\r
+                                     IN  UINTN                                   DestinationX,\r
+                                     IN  UINTN                                   DestinationY,\r
+                                     IN  UINTN                                   Width,\r
+                                     IN  UINTN                                   Height,\r
+                                     IN  UINTN                                   Delta         OPTIONAL\r
+                                     );\r
+\r
+/*++\r
+\r
+Routine Description:\r
+The following table defines actions for BltOperations:\r
+EfiUgaVideoFill - Write data from the  BltBuffer pixel (SourceX, SourceY) \r
+directly to every pixel of the video display rectangle \r
+(DestinationX, DestinationY) (DestinationX + Width, DestinationY + Height). \r
+Only one pixel will be used from the BltBuffer. Delta is NOT used.\r
+EfiUgaVideoToBltBuffer - Read data from the video display rectangle \r
+(SourceX, SourceY) (SourceX + Width, SourceY + Height) and place it in \r
+the BltBuffer rectangle (DestinationX, DestinationY ) \r
+(DestinationX + Width, DestinationY + Height). If DestinationX or \r
+DestinationY is not zero then Delta must be set to the length in bytes \r
+of a row in the BltBuffer.\r
+EfiUgaBltBufferToVideo - Write data from the  BltBuffer rectangle \r
+(SourceX, SourceY) (SourceX + Width, SourceY + Height) directly to the \r
+video display rectangle (DestinationX, DestinationY) \r
+(DestinationX + Width, DestinationY + Height). If SourceX or SourceY is \r
+not zero then Delta must be set to the length in bytes of a row in the \r
+BltBuffer.\r
+EfiUgaVideoToVideo - Copy from the video display rectangle (SourceX, SourceY)\r
+(SourceX + Width, SourceY + Height) .to the video display rectangle \r
+(DestinationX, DestinationY) (DestinationX + Width, DestinationY + Height). \r
+The BltBuffer and Delta  are not used in this mode.\r
+\r
+Arguments:\r
+This          - Protocol instance pointer.\r
+BltBuffer     - Buffer containing data to blit into video buffer. This \r
+buffer has a size of Width*Height*sizeof(EFI_UGA_PIXEL)\r
+BltOperation  - Operation to perform on BlitBuffer and video memory\r
+SourceX       - X coordinate of source for the BltBuffer.\r
+SourceY       - Y coordinate of source for the BltBuffer.\r
+DestinationX  - X coordinate of destination for the BltBuffer.\r
+DestinationY  - Y coordinate of destination for the BltBuffer.\r
+Width         - Width of rectangle in BltBuffer in pixels.\r
+Height        - Hight of rectangle in BltBuffer in pixels.\r
+Delta         -\r
+\r
+Returns:\r
+EFI_SUCCESS           - The Blt operation completed.\r
+EFI_INVALID_PARAMETER - BltOperation is not valid.\r
+EFI_DEVICE_ERROR      - A hardware error occured writting to the video \r
+buffer.\r
+\r
+--*/\r
+;\r
+\r
+typedef struct _EFI_UGA_DRAW_PROTOCOL {\r
+    EFI_UGA_DRAW_PROTOCOL_GET_MODE  GetMode;\r
+    EFI_UGA_DRAW_PROTOCOL_SET_MODE  SetMode;\r
+    EFI_UGA_DRAW_PROTOCOL_BLT       Blt;\r
+} EFI_UGA_DRAW_PROTOCOL;\r
+\r
+extern EFI_GUID gEfiUgaDrawProtocolGuid;\r
+\r
+#endif\r
diff --git a/libeg/egemb_font.h b/libeg/egemb_font.h
new file mode 100644 (file)
index 0000000..aaca740
--- /dev/null
@@ -0,0 +1,549 @@
+static const UINT8 egemb_liberation_mono_regular_14_data[6544] = {
+ 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
+ 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
+ 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
+ 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
+ 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
+ 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
+ 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
+ 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
+ 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
+ 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
+ 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
+ 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
+ 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
+ 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xd9, 0x00, 0x8e, 0x00,
+ 0x05, 0x14, 0xff, 0x64, 0x02, 0xfe, 0x77, 0x89, 0x00, 0x01, 0x30, 0xb0,
+ 0x93, 0x00, 0x01, 0x88, 0xef, 0x84, 0x00, 0x02, 0x89, 0xc1, 0x01, 0x80,
+ 0x00, 0x02, 0x5f, 0xe2, 0x0d, 0x83, 0x00, 0x01, 0x3b, 0xa7, 0xa5, 0x00,
+ 0x02, 0x03, 0xd9, 0x5b, 0xff, 0x00, 0x04, 0x38, 0xc2, 0xd8, 0xcc, 0x46,
+ 0xff, 0x00, 0xce, 0x00, 0x00, 0x34, 0x80, 0xff, 0x04, 0x8c, 0x00, 0x0c,
+ 0xeb, 0x41, 0x83, 0x00, 0x00, 0x28, 0x80, 0xff, 0x00, 0x94, 0x91, 0x00,
+ 0x02, 0x15, 0xd1, 0x83, 0x89, 0x00, 0x01, 0xbc, 0x80, 0x8f, 0x00, 0x02,
+ 0x18, 0xff, 0x20, 0x88, 0x00, 0x04, 0x5b, 0xd9, 0xf9, 0xf4, 0x74, 0x86,
+ 0x00, 0x01, 0xbc, 0x80, 0x85, 0x00, 0x02, 0x48, 0xff, 0x18, 0x83, 0x00,
+ 0x01, 0xa8, 0xb8, 0x80, 0x00, 0x01, 0x64, 0xd8, 0x83, 0x00, 0x00, 0x2c,
+ 0x80, 0xff, 0x00, 0x08, 0xf2, 0x00, 0x04, 0x10, 0xbb, 0xfb, 0xff, 0x40,
+ 0x80, 0x00, 0x01, 0x60, 0xc4, 0x81, 0x00, 0x03, 0xdc, 0xff, 0xe3, 0x48,
+ 0x9b, 0x00, 0x01, 0x75, 0xdc, 0x81, 0x00, 0x05, 0x05, 0xff, 0x54, 0x00,
+ 0xf2, 0x67, 0x80, 0x00, 0x1c, 0x03, 0xbd, 0x00, 0x00, 0xb9, 0x08, 0x00,
+ 0x36, 0xc5, 0xf4, 0xfd, 0xe5, 0x7c, 0x00, 0x56, 0xcb, 0xcb, 0x46, 0x00,
+ 0x00, 0x6e, 0x92, 0x00, 0x00, 0x66, 0xdf, 0xe5, 0x99, 0x02, 0x81, 0x00,
+ 0x01, 0x79, 0xdf, 0x83, 0x00, 0x02, 0x35, 0xf4, 0x23, 0x82, 0x00, 0x01,
+ 0xb7, 0x96, 0x81, 0x00, 0x05, 0x0f, 0x69, 0x3e, 0x9d, 0x3c, 0x44, 0xa3,
+ 0x00, 0x09, 0x60, 0xd6, 0x02, 0x00, 0x02, 0x88, 0xe9, 0xf7, 0xbc, 0x22,
+ 0x81, 0x00, 0x02, 0x2b, 0xf9, 0x50, 0x80, 0x00, 0x0d, 0x04, 0x8a, 0xe5,
+ 0xf3, 0xc3, 0x38, 0x00, 0x00, 0x0b, 0x97, 0xe7, 0xf4, 0xca, 0x44, 0x82,
+ 0x00, 0x05, 0x42, 0xff, 0x68, 0x00, 0x00, 0x8d, 0x81, 0xff, 0x00, 0xf4,
+ 0x80, 0x00, 0x07, 0x43, 0xd2, 0xf8, 0xd5, 0x4a, 0x00, 0x00, 0xec, 0x82,
+ 0xff, 0x0f, 0x50, 0x00, 0x10, 0xa1, 0xed, 0xf7, 0xc6, 0x3c, 0x00, 0x00,
+ 0x0c, 0x93, 0xe5, 0xf6, 0xb4, 0x1a, 0xa7, 0x00, 0x0e, 0x17, 0xa2, 0xe9,
+ 0xf0, 0xbe, 0x36, 0x00, 0x00, 0x33, 0xd2, 0x2b, 0x00, 0x1c, 0xcf, 0x31,
+ 0x80, 0x00, 0x02, 0xb1, 0xff, 0x23, 0x80, 0x00, 0x18, 0xe4, 0xff, 0xff,
+ 0xf0, 0xc9, 0x50, 0x00, 0x00, 0x01, 0x78, 0xe0, 0xf7, 0xcd, 0x43, 0x00,
+ 0x00, 0xe4, 0xff, 0xfa, 0xdc, 0x89, 0x0b, 0x00, 0x00, 0xe4, 0x82, 0xff,
+ 0x02, 0x64, 0x00, 0xac, 0x82, 0xff, 0x12, 0x6c, 0x00, 0x01, 0x7d, 0xe2,
+ 0xf7, 0xc9, 0x3c, 0x00, 0x00, 0xe4, 0x68, 0x00, 0x00, 0x04, 0xff, 0x48,
+ 0x00, 0xa0, 0x82, 0xff, 0x81, 0x00, 0x0f, 0xb0, 0xff, 0xff, 0xbc, 0x00,
+ 0x00, 0xe4, 0x68, 0x00, 0x00, 0x22, 0xee, 0x74, 0x00, 0x60, 0xec, 0x82,
+ 0x00, 0x0a, 0x20, 0xff, 0xac, 0x00, 0x00, 0x34, 0xff, 0x84, 0x00, 0xe4,
+ 0xd5, 0x80, 0x00, 0x2a, 0xe4, 0x48, 0x00, 0x04, 0x8c, 0xe9, 0xf7, 0xbc,
+ 0x27, 0x00, 0x00, 0xe4, 0xff, 0xff, 0xf5, 0xcf, 0x57, 0x00, 0x00, 0x03,
+ 0x88, 0xe8, 0xf6, 0xb9, 0x23, 0x00, 0x00, 0xe4, 0xff, 0xff, 0xf9, 0xd7,
+ 0x67, 0x00, 0x00, 0x1c, 0xa9, 0xe9, 0xf6, 0xd1, 0x52, 0x00, 0x7c, 0x83,
+ 0xff, 0x03, 0xe0, 0x08, 0xff, 0x48, 0x80, 0x00, 0x03, 0xe0, 0x6c, 0xc4,
+ 0x99, 0x81, 0x00, 0x03, 0x36, 0xff, 0xf1, 0x5b, 0x82, 0x00, 0x0b, 0xf2,
+ 0x70, 0xfa, 0x39, 0x00, 0x00, 0x03, 0xd0, 0x90, 0x75, 0xe2, 0x09, 0x80,
+ 0x00, 0x02, 0x88, 0xd7, 0x05, 0x83, 0xff, 0x0b, 0x94, 0x00, 0x00, 0x34,
+ 0xff, 0x0b, 0x04, 0x02, 0x00, 0x00, 0x75, 0xc3, 0x84, 0x00, 0x03, 0x04,
+ 0x04, 0xa5, 0x94, 0x82, 0x00, 0x02, 0xb3, 0xf4, 0x17, 0x8a, 0x00, 0x02,
+ 0x0e, 0xb8, 0x57, 0x88, 0x00, 0x01, 0xbc, 0x80, 0x8f, 0x00, 0x02, 0x18,
+ 0xff, 0x20, 0x87, 0x00, 0x05, 0x13, 0xf8, 0x83, 0x25, 0x20, 0x15, 0x86,
+ 0x00, 0x01, 0xbc, 0x80, 0x85, 0x00, 0x02, 0x1d, 0x68, 0x09, 0x83, 0x00,
+ 0x01, 0x44, 0x4a, 0x80, 0x00, 0x01, 0x64, 0xd8, 0x83, 0x00, 0x04, 0x01,
+ 0x08, 0x3a, 0xff, 0x08, 0xb9, 0x00, 0x01, 0x3d, 0xac, 0xb4, 0x00, 0x04,
+ 0x74, 0xd3, 0x14, 0x04, 0x01, 0x80, 0x00, 0x01, 0x60, 0xc4, 0x81, 0x00,
+ 0x03, 0x03, 0x07, 0x7c, 0xdb, 0x89, 0x00, 0x05, 0x17, 0xa2, 0xe9, 0xf0,
+ 0xbe, 0x36, 0x89, 0x00, 0x01, 0x6f, 0xd6, 0x82, 0x00, 0x04, 0xf5, 0x44,
+ 0x00, 0xe4, 0x56, 0x80, 0x00, 0x1c, 0x2c, 0x96, 0x00, 0x00, 0xc1, 0x00,
+ 0x00, 0xe4, 0x7a, 0x35, 0xb0, 0x32, 0xef, 0x50, 0xde, 0x1e, 0x34, 0xc9,
+ 0x00, 0x1d, 0xd5, 0x0c, 0x00, 0x17, 0xee, 0x1d, 0x07, 0xd2, 0x48, 0x81,
+ 0x00, 0x01, 0x69, 0xce, 0x83, 0x00, 0x01, 0xb5, 0x97, 0x83, 0x00, 0x02,
+ 0x36, 0xfa, 0x1c, 0x80, 0x00, 0x05, 0x18, 0x91, 0xd9, 0xf2, 0xad, 0x4a,
+ 0x81, 0x00, 0x01, 0x15, 0x2f, 0x9c, 0x00, 0x11, 0x04, 0xdd, 0x57, 0x00,
+ 0x00, 0x75, 0xe6, 0x41, 0x25, 0xa6, 0xd4, 0x02, 0x00, 0x11, 0x5e, 0xe1,
+ 0xf8, 0x50, 0x80, 0x00, 0x0e, 0x81, 0xe0, 0x3c, 0x21, 0x98, 0xec, 0x0c,
+ 0x00, 0x9c, 0xcf, 0x35, 0x1f, 0x8a, 0xf5, 0x11, 0x80, 0x00, 0x07, 0x06,
+ 0xd6, 0xf2, 0x68, 0x00, 0x00, 0x9e, 0x97, 0x80, 0x0c, 0x0b, 0x0b, 0x00,
+ 0x00, 0x25, 0xf0, 0x63, 0x1f, 0x74, 0xec, 0x0d, 0x00, 0x0b, 0x80, 0x0c,
+ 0x11, 0x36, 0xed, 0x15, 0x00, 0xa2, 0xc4, 0x1b, 0x08, 0x78, 0xf2, 0x10,
+ 0x00, 0x9c, 0xd3, 0x33, 0x24, 0xb3, 0xc5, 0x94, 0x00, 0x01, 0x2f, 0x51,
+ 0x85, 0x00, 0x02, 0x20, 0x5b, 0x05, 0x82, 0x00, 0x0a, 0x01, 0xc7, 0xbc,
+ 0x33, 0x26, 0x91, 0xee, 0x12, 0x00, 0xc5, 0x30, 0x80, 0x00, 0x07, 0x47,
+ 0xa9, 0x00, 0x00, 0x10, 0xf7, 0xbc, 0x7b, 0x80, 0x00, 0x19, 0xe4, 0x78,
+ 0x1c, 0x2a, 0x8b, 0xfb, 0x1f, 0x00, 0x74, 0xfa, 0x6c, 0x31, 0x89, 0xf7,
+ 0x2a, 0x00, 0xe4, 0x7d, 0x30, 0x60, 0xe4, 0xc0, 0x02, 0x00, 0xe4, 0x7d,
+ 0x81, 0x24, 0x03, 0x0e, 0x00, 0xac, 0xad, 0x81, 0x24, 0x17, 0x0f, 0x00,
+ 0x78, 0xf7, 0x67, 0x30, 0x90, 0xf3, 0x1d, 0x00, 0xe4, 0x68, 0x00, 0x00,
+ 0x04, 0xff, 0x48, 0x00, 0x16, 0x24, 0x87, 0xdd, 0x24, 0x24, 0x81, 0x00,
+ 0x0f, 0x18, 0x24, 0x9f, 0xbc, 0x00, 0x00, 0xe4, 0x68, 0x00, 0x09, 0xd0,
+ 0xa3, 0x00, 0x00, 0x60, 0xec, 0x82, 0x00, 0x42, 0x20, 0xf9, 0xee, 0x0d,
+ 0x00, 0x8d, 0xf2, 0x84, 0x00, 0xe4, 0xf9, 0x44, 0x00, 0x00, 0xe4, 0x48,
+ 0x00, 0x89, 0xf3, 0x5a, 0x3a, 0xbd, 0xe2, 0x0a, 0x00, 0xe4, 0x78, 0x1c,
+ 0x28, 0x75, 0xfd, 0x42, 0x00, 0x81, 0xf5, 0x5c, 0x3b, 0xc0, 0xdc, 0x07,
+ 0x00, 0xe4, 0x78, 0x1c, 0x25, 0x6c, 0xfd, 0x4b, 0x00, 0xbe, 0xb8, 0x26,
+ 0x16, 0x7a, 0xfb, 0x28, 0x11, 0x24, 0x24, 0x87, 0xdd, 0x24, 0x24, 0x1f,
+ 0x08, 0xff, 0x48, 0x80, 0x00, 0x04, 0xe0, 0x6c, 0x6c, 0xe9, 0x03, 0x80,
+ 0x00, 0x03, 0x89, 0xcf, 0xc9, 0x79, 0x81, 0x00, 0x12, 0x11, 0xff, 0x2c,
+ 0x8a, 0xce, 0x03, 0x00, 0x6d, 0xe4, 0x0d, 0x06, 0xd9, 0x7c, 0x00, 0x00,
+ 0x1f, 0xf7, 0x47, 0x00, 0x81, 0x24, 0x07, 0x54, 0xfb, 0x3e, 0x00, 0x00,
+ 0x34, 0xff, 0x08, 0x81, 0x00, 0x02, 0x0a, 0xe8, 0x46, 0x85, 0x00, 0x01,
+ 0xa4, 0x94, 0x81, 0x00, 0x03, 0x1d, 0xdc, 0x8a, 0x79, 0x98, 0x00, 0x01,
+ 0xbc, 0x80, 0x8f, 0x00, 0x02, 0x18, 0xff, 0x20, 0x87, 0x00, 0x02, 0x39,
+ 0xfd, 0x03, 0x89, 0x00, 0x01, 0xbc, 0x7f, 0x93, 0x00, 0x01, 0x64, 0xd8,
+ 0x85, 0x00, 0x02, 0x34, 0xff, 0x08, 0xad, 0x00, 0x00, 0x01, 0x88, 0x00,
+ 0x01, 0x6f, 0xac, 0xb4, 0x00, 0x01, 0x8f, 0xa1, 0x83, 0x00, 0x01, 0x60,
+ 0xc4, 0x83, 0x00, 0x01, 0x39, 0xf7, 0x88, 0x00, 0x06, 0x01, 0xc7, 0xbc,
+ 0x33, 0x26, 0x91, 0xee, 0x89, 0x00, 0x01, 0x68, 0xcf, 0x82, 0x00, 0x04,
+ 0xe6, 0x35, 0x00, 0xd5, 0x46, 0x80, 0x00, 0x1c, 0x5e, 0x65, 0x00, 0x22,
+ 0xa1, 0x00, 0x13, 0xff, 0x1c, 0x30, 0xb0, 0x00, 0x5e, 0x43, 0xf8, 0x04,
+ 0x19, 0xe4, 0x00, 0xb4, 0x4b, 0x00, 0x00, 0x2c, 0xd6, 0x00, 0x07, 0xd7,
+ 0x41, 0x81, 0x00, 0x01, 0x5a, 0xbe, 0x82, 0x00, 0x02, 0x21, 0xfe, 0x2b,
+ 0x84, 0x00, 0x01, 0xca, 0x81, 0x81, 0x00, 0x03, 0x06, 0xc8, 0xc5, 0x37,
+ 0x82, 0x00, 0x01, 0x50, 0xb4, 0x9c, 0x00, 0x11, 0x65, 0xd3, 0x01, 0x00,
+ 0x00, 0xdb, 0x64, 0x00, 0x00, 0x0b, 0xf7, 0x3e, 0x00, 0xfa, 0xc5, 0x3d,
+ 0xec, 0x50, 0x80, 0x00, 0x0e, 0x9a, 0x5c, 0x00, 0x00, 0x0e, 0xff, 0x36,
+ 0x00, 0x78, 0x35, 0x00, 0x00, 0x0f, 0xff, 0x32, 0x80, 0x00, 0x07, 0x7c,
+ 0x94, 0xd4, 0x68, 0x00, 0x00, 0xaf, 0x7f, 0x83, 0x00, 0x01, 0x93, 0x97,
+ 0x87, 0x00, 0x12, 0xbe, 0x72, 0x00, 0x00, 0xd1, 0x6f, 0x00, 0x00, 0x13,
+ 0xff, 0x31, 0x00, 0xef, 0x51, 0x00, 0x00, 0x14, 0xfe, 0x29, 0x80, 0x00,
+ 0x01, 0x9c, 0xff, 0x83, 0x00, 0x01, 0x9c, 0xff, 0x83, 0x00, 0x05, 0x01,
+ 0x4a, 0xbd, 0xe9, 0x59, 0x30, 0x83, 0xf0, 0x05, 0x8e, 0x1a, 0xc6, 0xe4,
+ 0x76, 0x10, 0x80, 0x00, 0x15, 0x35, 0xfc, 0x13, 0x00, 0x00, 0x01, 0xf5,
+ 0x45, 0x2e, 0xb8, 0x06, 0xa7, 0xc8, 0x7e, 0x9d, 0xd9, 0x01, 0x00, 0x63,
+ 0xc8, 0x58, 0xd2, 0x80, 0x00, 0x09, 0xe4, 0x68, 0x00, 0x00, 0x0c, 0xff,
+ 0x43, 0x01, 0xe6, 0x85, 0x80, 0x00, 0x0c, 0x99, 0x4c, 0x00, 0xe4, 0x68,
+ 0x00, 0x00, 0x21, 0xfb, 0x4c, 0x00, 0xe4, 0x68, 0x83, 0x00, 0x01, 0xac,
+ 0xa0, 0x82, 0x00, 0x02, 0x01, 0xe7, 0x7f, 0x80, 0x00, 0x09, 0xab, 0x42,
+ 0x00, 0xe4, 0x68, 0x00, 0x00, 0x04, 0xff, 0x48, 0x80, 0x00, 0x01, 0x74,
+ 0xd8, 0x85, 0x00, 0x0d, 0x90, 0xbc, 0x00, 0x00, 0xe4, 0x68, 0x00, 0xa3,
+ 0xcb, 0x08, 0x00, 0x00, 0x60, 0xec, 0x82, 0x00, 0x1a, 0x20, 0xf5, 0xb4,
+ 0x5f, 0x02, 0xe3, 0xb2, 0x84, 0x00, 0xe4, 0xb1, 0xb1, 0x00, 0x00, 0xe4,
+ 0x48, 0x06, 0xf2, 0x7a, 0x00, 0x00, 0x16, 0xfc, 0x5f, 0x00, 0xe4, 0x68,
+ 0x80, 0x00, 0x0c, 0xbf, 0x92, 0x04, 0xee, 0x7e, 0x00, 0x00, 0x19, 0xfd,
+ 0x59, 0x00, 0xe4, 0x68, 0x80, 0x00, 0x04, 0xbd, 0x94, 0x00, 0xf8, 0x51,
+ 0x80, 0x00, 0x01, 0x77, 0x2a, 0x80, 0x00, 0x01, 0x74, 0xd8, 0x80, 0x00,
+ 0x02, 0x08, 0xff, 0x48, 0x80, 0x00, 0x04, 0xe0, 0x6c, 0x17, 0xfc, 0x41,
+ 0x80, 0x00, 0x03, 0xdc, 0x76, 0xa4, 0x97, 0x81, 0x00, 0x10, 0x2f, 0xfe,
+ 0x09, 0x0a, 0xe0, 0x6c, 0x16, 0xef, 0x52, 0x00, 0x00, 0x4a, 0xf3, 0x19,
+ 0x00, 0xa8, 0xb1, 0x82, 0x00, 0x02, 0x0a, 0xd7, 0x85, 0x80, 0x00, 0x02,
+ 0x34, 0xff, 0x08, 0x82, 0x00, 0x01, 0x71, 0xc7, 0x85, 0x00, 0x01, 0xa4,
+ 0x94, 0x81, 0x00, 0x04, 0x80, 0x7e, 0x25, 0xdd, 0x01, 0x8f, 0x00, 0x27,
+ 0x13, 0xac, 0xee, 0xf0, 0xb1, 0x17, 0x00, 0x00, 0xbc, 0x88, 0xa8, 0xf5,
+ 0xd8, 0x47, 0x00, 0x00, 0x04, 0x87, 0xe6, 0xf6, 0xc7, 0x3b, 0x00, 0x00,
+ 0x10, 0xaf, 0xf2, 0xdb, 0x5d, 0xff, 0x20, 0x00, 0x05, 0x8e, 0xea, 0xf0,
+ 0xbf, 0x2e, 0x00, 0x10, 0x83, 0xff, 0x12, 0x54, 0x00, 0x0f, 0xac, 0xf0,
+ 0xd6, 0x3c, 0xfe, 0x2f, 0x00, 0xbc, 0x84, 0xa3, 0xf5, 0xde, 0x50, 0x00,
+ 0x00, 0x50, 0x80, 0xff, 0x00, 0x18, 0x80, 0x00, 0x00, 0x4c, 0x80, 0xff,
+ 0x00, 0xb8, 0x80, 0x00, 0x06, 0x64, 0xd8, 0x00, 0x00, 0x54, 0xed, 0x29,
+ 0x80, 0x00, 0x3e, 0x34, 0xff, 0x08, 0x00, 0x00, 0x4c, 0xbc, 0xb2, 0xec,
+ 0x4d, 0xc2, 0xe8, 0x33, 0x00, 0xc0, 0x75, 0xa7, 0xde, 0xe1, 0x55, 0x00,
+ 0x00, 0x05, 0x86, 0xdf, 0xef, 0xbe, 0x2c, 0x00, 0x00, 0xc1, 0x82, 0xb1,
+ 0xe1, 0xd8, 0x48, 0x00, 0x00, 0x11, 0xb1, 0xf2, 0xda, 0x54, 0xff, 0x27,
+ 0x00, 0x41, 0xea, 0x14, 0xb2, 0xf4, 0xff, 0x24, 0x00, 0x04, 0x91, 0xe7,
+ 0xf6, 0xca, 0x3a, 0x00, 0x00, 0xb4, 0x81, 0xff, 0x0c, 0xa0, 0x00, 0x00,
+ 0xbc, 0x80, 0x00, 0x00, 0x10, 0xff, 0x2c, 0x58, 0xf8, 0x0f, 0x80, 0x00,
+ 0x03, 0xa2, 0xbb, 0xc8, 0x6e, 0x81, 0x00, 0x0c, 0x07, 0xfc, 0x37, 0xd9,
+ 0x74, 0x00, 0x00, 0x25, 0xf4, 0x40, 0x57, 0xed, 0x07, 0x80, 0x00, 0x03,
+ 0x8c, 0xbd, 0x00, 0xb8, 0x82, 0xff, 0x00, 0x0c, 0x80, 0x00, 0x01, 0x90,
+ 0xa0, 0x83, 0x00, 0x01, 0x60, 0xc4, 0x83, 0x00, 0x01, 0x38, 0xf8, 0x88,
+ 0x00, 0x06, 0x35, 0xfc, 0x13, 0x00, 0x00, 0x01, 0xf5, 0x89, 0x00, 0x01,
+ 0x62, 0xc9, 0x82, 0x00, 0x12, 0x8b, 0x19, 0x00, 0x80, 0x24, 0x00, 0x38,
+ 0xc8, 0xe7, 0xd3, 0xc8, 0xda, 0xe0, 0xbe, 0x01, 0xe0, 0x90, 0x3b, 0xb0,
+ 0x80, 0x00, 0x05, 0xd5, 0x32, 0x48, 0xc0, 0x57, 0xa8, 0x80, 0x00, 0x04,
+ 0x08, 0xed, 0x5b, 0xca, 0x8d, 0x82, 0x00, 0x01, 0x31, 0x71, 0x82, 0x00,
+ 0x01, 0x61, 0xe6, 0x85, 0x00, 0x01, 0x85, 0xc4, 0x81, 0x00, 0x03, 0x71,
+ 0x88, 0x2e, 0xc8, 0x82, 0x00, 0x01, 0x50, 0xb4, 0x9b, 0x00, 0x07, 0x06,
+ 0xe1, 0x53, 0x00, 0x00, 0x0e, 0xff, 0x2e, 0x80, 0x00, 0x07, 0xcc, 0x71,
+ 0x00, 0x06, 0x00, 0x00, 0xec, 0x50, 0x84, 0x00, 0x02, 0x32, 0xfd, 0x1c,
+ 0x81, 0x00, 0x1a, 0x13, 0x8f, 0xd3, 0x06, 0x00, 0x00, 0x22, 0xdd, 0x0f,
+ 0xd4, 0x68, 0x00, 0x00, 0xc0, 0xaf, 0xc8, 0xe4, 0xb5, 0x29, 0x00, 0x00,
+ 0xd2, 0x78, 0xc0, 0xf6, 0xce, 0x3d, 0x82, 0x00, 0x0e, 0x52, 0xde, 0x05,
+ 0x00, 0x00, 0x7f, 0xc7, 0x1c, 0x07, 0x77, 0xda, 0x06, 0x01, 0xf4, 0x49,
+ 0x80, 0x00, 0x01, 0xf2, 0x59, 0x80, 0x00, 0x01, 0x9c, 0xff, 0x83, 0x00,
+ 0x01, 0x9c, 0xff, 0x81, 0x00, 0x07, 0x08, 0x66, 0xd7, 0xd9, 0x67, 0x08,
+ 0x00, 0x06, 0x83, 0x20, 0x0a, 0x13, 0x00, 0x00, 0x3a, 0xae, 0xf1, 0x92,
+ 0x22, 0x00, 0x04, 0x0a, 0x80, 0x00, 0x1d, 0x1f, 0xfe, 0x2b, 0x6d, 0x70,
+ 0x7d, 0x76, 0x00, 0xce, 0x6b, 0xc8, 0x11, 0x00, 0xbc, 0x78, 0x0e, 0xf8,
+ 0x29, 0x00, 0x00, 0xe4, 0x68, 0x00, 0x03, 0x71, 0xe6, 0x0e, 0x20, 0xff,
+ 0x40, 0x83, 0x00, 0x01, 0xe4, 0x68, 0x80, 0x00, 0x04, 0xc3, 0x8f, 0x00,
+ 0xe4, 0x68, 0x83, 0x00, 0x01, 0xac, 0xa0, 0x82, 0x00, 0x02, 0x20, 0xff,
+ 0x3e, 0x83, 0x00, 0x06, 0xe4, 0x68, 0x00, 0x00, 0x04, 0xff, 0x48, 0x80,
+ 0x00, 0x01, 0x74, 0xd8, 0x85, 0x00, 0x08, 0x90, 0xbc, 0x00, 0x00, 0xe4,
+ 0x68, 0x6d, 0xe7, 0x1c, 0x80, 0x00, 0x01, 0x60, 0xec, 0x82, 0x00, 0x12,
+ 0x20, 0xf7, 0x63, 0xb7, 0x3e, 0xca, 0x98, 0x84, 0x00, 0xe4, 0x57, 0xf5,
+ 0x21, 0x00, 0xe4, 0x48, 0x30, 0xff, 0x34, 0x80, 0x00, 0x04, 0xcc, 0x96,
+ 0x00, 0xe4, 0x68, 0x80, 0x00, 0x04, 0xbf, 0x97, 0x2c, 0xff, 0x37, 0x80,
+ 0x00, 0x04, 0xcf, 0x93, 0x00, 0xe4, 0x68, 0x80, 0x00, 0x05, 0xbc, 0x93,
+ 0x00, 0xd2, 0xb0, 0x11, 0x84, 0x00, 0x01, 0x74, 0xd8, 0x80, 0x00, 0x02,
+ 0x08, 0xff, 0x48, 0x80, 0x00, 0x17, 0xe0, 0x6c, 0x00, 0xbb, 0x95, 0x00,
+ 0x00, 0x30, 0xfe, 0x1f, 0x7f, 0xb6, 0x00, 0x75, 0xd5, 0x00, 0x4c, 0xe2,
+ 0x00, 0x00, 0x4c, 0xef, 0xaf, 0xb3, 0x81, 0x00, 0x04, 0xb5, 0x9e, 0x38,
+ 0xf7, 0x23, 0x82, 0x00, 0x02, 0x98, 0xca, 0x04, 0x80, 0x00, 0x02, 0x34,
+ 0xff, 0x08, 0x82, 0x00, 0x02, 0x08, 0xe6, 0x4b, 0x84, 0x00, 0x01, 0xa4,
+ 0x94, 0x80, 0x00, 0x05, 0x03, 0xe0, 0x1e, 0x00, 0xc1, 0x47, 0x8f, 0x00,
+ 0x2a, 0x9d, 0xc2, 0x15, 0x13, 0xbe, 0x9d, 0x00, 0x00, 0xbc, 0xe9, 0x55,
+ 0x12, 0x83, 0xf1, 0x0b, 0x00, 0x78, 0xdb, 0x31, 0x0e, 0x79, 0xf2, 0x16,
+ 0x00, 0x96, 0xcd, 0x16, 0x16, 0xb7, 0xff, 0x20, 0x00, 0x7d, 0xcd, 0x21,
+ 0x07, 0x78, 0xe6, 0x09, 0x00, 0x08, 0x49, 0xf8, 0x80, 0x08, 0x16, 0x02,
+ 0x00, 0x9a, 0xd2, 0x1c, 0x1e, 0xbb, 0xff, 0x2c, 0x00, 0xbc, 0xe6, 0x54,
+ 0x0c, 0x84, 0xed, 0x05, 0x00, 0x02, 0x08, 0x2a, 0xff, 0x18, 0x80, 0x00,
+ 0x04, 0x02, 0x08, 0x08, 0x87, 0xb8, 0x80, 0x00, 0x05, 0x64, 0xd8, 0x00,
+ 0x34, 0xef, 0x3f, 0x81, 0x00, 0x56, 0x34, 0xff, 0x08, 0x00, 0x00, 0x48,
+ 0xfa, 0x37, 0x89, 0xf3, 0x1b, 0xa1, 0x92, 0x00, 0xbc, 0xe7, 0x33, 0x00,
+ 0x69, 0xf0, 0x06, 0x00, 0x82, 0xd9, 0x27, 0x0a, 0x89, 0xec, 0x0e, 0x00,
+ 0xbc, 0xec, 0x32, 0x00, 0x5d, 0xf5, 0x12, 0x00, 0x97, 0xcb, 0x16, 0x16,
+ 0xb6, 0xff, 0x24, 0x00, 0x17, 0xff, 0xb9, 0x7a, 0x1f, 0x24, 0x07, 0x00,
+ 0x65, 0xcc, 0x18, 0x04, 0x5d, 0xdb, 0x02, 0x00, 0x05, 0x8f, 0xae, 0x08,
+ 0x08, 0x05, 0x00, 0x00, 0xbc, 0x80, 0x00, 0x00, 0x10, 0xff, 0x2c, 0x08,
+ 0xf0, 0x62, 0x00, 0x00, 0x0b, 0xf4, 0x5a, 0xa0, 0x92, 0x81, 0x00, 0x18,
+ 0x2d, 0xfc, 0x08, 0x35, 0xf2, 0x25, 0x01, 0xc3, 0x8a, 0x00, 0x05, 0xe8,
+ 0x57, 0x00, 0x00, 0x03, 0xe7, 0x57, 0x00, 0x02, 0x04, 0x04, 0x06, 0xb9,
+ 0xa7, 0x81, 0x00, 0x01, 0x96, 0x9e, 0x83, 0x00, 0x01, 0x60, 0xc4, 0x83,
+ 0x00, 0x02, 0x36, 0xfb, 0x02, 0x87, 0x00, 0x01, 0x04, 0x0a, 0x80, 0x00,
+ 0x01, 0x1f, 0xfe, 0x89, 0x00, 0x01, 0x5c, 0xc3, 0x8a, 0x00, 0x13, 0xbe,
+ 0x08, 0x00, 0x88, 0x3c, 0x00, 0x00, 0x34, 0xd4, 0xfc, 0xeb, 0x89, 0x20,
+ 0x00, 0x41, 0xcb, 0xc8, 0x46, 0xd7, 0x17, 0x80, 0x00, 0x06, 0x38, 0xe9,
+ 0xda, 0x35, 0x00, 0x46, 0x11, 0x87, 0x00, 0x01, 0x8c, 0xb9, 0x85, 0x00,
+ 0x01, 0x55, 0xef, 0x81, 0x00, 0x03, 0x03, 0x08, 0x00, 0x0c, 0x82, 0x00,
+ 0x01, 0x50, 0xb4, 0x9b, 0x00, 0x0c, 0x6a, 0xd0, 0x01, 0x00, 0x00, 0x22,
+ 0xff, 0x1b, 0x9c, 0xff, 0x00, 0xb8, 0x86, 0x81, 0x00, 0x01, 0xec, 0x50,
+ 0x83, 0x00, 0x02, 0x0a, 0xcb, 0x9e, 0x81, 0x00, 0x03, 0xc9, 0xff, 0xca,
+ 0x1b, 0x80, 0x00, 0x15, 0xb5, 0x58, 0x00, 0xd4, 0x68, 0x00, 0x00, 0xc3,
+ 0xc4, 0x43, 0x31, 0xac, 0xe8, 0x0f, 0x00, 0xef, 0xe3, 0x3d, 0x0e, 0x84,
+ 0xf1, 0x15, 0x81, 0x00, 0x01, 0xca, 0x71, 0x80, 0x00, 0x0e, 0x03, 0xb2,
+ 0xff, 0xff, 0xe7, 0x32, 0x00, 0x00, 0xb1, 0xbd, 0x10, 0x08, 0x7f, 0xfa,
+ 0x6b, 0x80, 0x00, 0x01, 0x1a, 0x2c, 0x83, 0x00, 0x01, 0x1a, 0x2c, 0x80,
+ 0x00, 0x04, 0x23, 0xeb, 0xc3, 0x4f, 0x01, 0x8c, 0x00, 0x03, 0x24, 0x96,
+ 0xf3, 0x75, 0x81, 0x00, 0x1e, 0x1a, 0xce, 0xa1, 0x00, 0x98, 0x43, 0xdd,
+ 0x0f, 0x00, 0xbb, 0x3a, 0xb9, 0x19, 0x18, 0xfc, 0x23, 0x00, 0xb5, 0x82,
+ 0x00, 0x00, 0xe4, 0xf6, 0xf0, 0xfb, 0xea, 0x43, 0x00, 0x36, 0xff, 0x28,
+ 0x83, 0x00, 0x01, 0xe4, 0x68, 0x80, 0x00, 0x04, 0xa5, 0xa9, 0x00, 0xe4,
+ 0xf8, 0x80, 0xf4, 0x04, 0xf0, 0x00, 0x00, 0xac, 0xa0, 0x82, 0x00, 0x02,
+ 0x36, 0xff, 0x28, 0x83, 0x00, 0x01, 0xe4, 0xfd, 0x80, 0xfc, 0x01, 0xff,
+ 0x48, 0x80, 0x00, 0x01, 0x74, 0xd8, 0x85, 0x00, 0x07, 0x90, 0xbc, 0x00,
+ 0x00, 0xe4, 0xa3, 0xfa, 0xa4, 0x81, 0x00, 0x01, 0x60, 0xec, 0x82, 0x00,
+ 0x12, 0x20, 0xf8, 0x11, 0xf3, 0x95, 0x73, 0x98, 0x84, 0x00, 0xe4, 0x44,
+ 0x9f, 0x8c, 0x00, 0xe4, 0x48, 0x46, 0xff, 0x1d, 0x80, 0x00, 0x0c, 0xb5,
+ 0xad, 0x00, 0xe4, 0x68, 0x00, 0x05, 0x5e, 0xfd, 0x43, 0x45, 0xff, 0x1f,
+ 0x80, 0x00, 0x10, 0xb8, 0xab, 0x00, 0xe4, 0x68, 0x00, 0x02, 0x4d, 0xfc,
+ 0x43, 0x00, 0x2e, 0xd2, 0xf8, 0xbe, 0x73, 0x12, 0x81, 0x00, 0x01, 0x74,
+ 0xd8, 0x80, 0x00, 0x02, 0x08, 0xff, 0x48, 0x80, 0x00, 0x11, 0xe0, 0x6c,
+ 0x00, 0x62, 0xe6, 0x02, 0x00, 0x83, 0xc6, 0x00, 0x5a, 0xd4, 0x00, 0xbf,
+ 0xeb, 0x29, 0x6a, 0xbe, 0x80, 0x00, 0x02, 0xb4, 0xfc, 0x1f, 0x81, 0x00,
+ 0x03, 0x25, 0xf7, 0xd9, 0x86, 0x82, 0x00, 0x02, 0x4f, 0xf3, 0x25, 0x81,
+ 0x00, 0x02, 0x34, 0xff, 0x08, 0x83, 0x00, 0x01, 0x6c, 0xcc, 0x84, 0x00,
+ 0x01, 0xa4, 0x94, 0x80, 0x00, 0x05, 0x4c, 0xb9, 0x00, 0x00, 0x5d, 0xae,
+ 0x8f, 0x00, 0x21, 0x0d, 0x0f, 0x00, 0x00, 0x6f, 0xd0, 0x00, 0x00, 0xbc,
+ 0xb5, 0x00, 0x00, 0x07, 0xf5, 0x4c, 0x00, 0xe6, 0x62, 0x00, 0x00, 0x02,
+ 0x5e, 0x1a, 0x00, 0xe7, 0x61, 0x00, 0x00, 0x44, 0xff, 0x20, 0x00, 0xe6,
+ 0x50, 0x80, 0x00, 0x05, 0xe8, 0x50, 0x00, 0x00, 0x44, 0xf8, 0x82, 0x00,
+ 0x0e, 0xe2, 0x69, 0x00, 0x00, 0x4e, 0xff, 0x2c, 0x00, 0xbc, 0xa9, 0x00,
+ 0x00, 0x1c, 0xff, 0x22, 0x80, 0x00, 0x02, 0x24, 0xff, 0x18, 0x83, 0x00,
+ 0x01, 0x84, 0xb8, 0x80, 0x00, 0x04, 0x64, 0xd8, 0x1b, 0xe4, 0x5a, 0x82,
+ 0x00, 0x30, 0x34, 0xff, 0x08, 0x00, 0x00, 0x48, 0xf2, 0x00, 0x65, 0xd7,
+ 0x00, 0x7d, 0xaa, 0x00, 0xbc, 0xa1, 0x00, 0x00, 0x19, 0xff, 0x22, 0x00,
+ 0xe9, 0x64, 0x00, 0x00, 0x09, 0xf4, 0x56, 0x00, 0xbc, 0xad, 0x00, 0x00,
+ 0x02, 0xf0, 0x52, 0x00, 0xe8, 0x60, 0x00, 0x00, 0x44, 0xff, 0x24, 0x00,
+ 0x03, 0xfe, 0xa2, 0x82, 0x00, 0x02, 0x84, 0xbe, 0x05, 0x83, 0x00, 0x01,
+ 0x8c, 0xac, 0x82, 0x00, 0x26, 0xbc, 0x80, 0x00, 0x00, 0x10, 0xff, 0x2c,
+ 0x00, 0x9a, 0xbc, 0x00, 0x00, 0x5c, 0xf0, 0x09, 0x78, 0xb7, 0x00, 0x7a,
+ 0xcb, 0x03, 0x55, 0xdb, 0x00, 0x00, 0x7d, 0xc3, 0x6f, 0xd0, 0x06, 0x00,
+ 0x00, 0x85, 0xb9, 0x00, 0x00, 0x4a, 0xeb, 0x06, 0x81, 0x00, 0x02, 0x80,
+ 0xd5, 0x0b, 0x80, 0x00, 0x02, 0x23, 0xe2, 0x65, 0x83, 0x00, 0x01, 0x60,
+ 0xc4, 0x83, 0x00, 0x0c, 0x0e, 0xed, 0x68, 0x01, 0x00, 0x16, 0xa9, 0xde,
+ 0xbd, 0x68, 0x16, 0x1c, 0x54, 0x81, 0x00, 0x02, 0x1a, 0xce, 0xa1, 0x89,
+ 0x00, 0x01, 0x55, 0xbc, 0x89, 0x00, 0x05, 0x03, 0xc1, 0x00, 0x00, 0xb9,
+ 0x0a, 0x81, 0x00, 0x04, 0x52, 0xd5, 0xb4, 0xf3, 0x3e, 0x80, 0x00, 0x0c,
+ 0x9e, 0x6a, 0xa1, 0xca, 0x91, 0x2a, 0xe9, 0x5e, 0xef, 0x21, 0x00, 0xe0,
+ 0x29, 0x87, 0x00, 0x01, 0x9f, 0xa5, 0x85, 0x00, 0x02, 0x42, 0xfe, 0x03,
+ 0x86, 0x00, 0x07, 0x2f, 0xec, 0xec, 0xf2, 0xfa, 0xec, 0xec, 0x8c, 0x87,
+ 0x00, 0x00, 0xb5, 0x80, 0xfc, 0x00, 0x1b, 0x88, 0x00, 0x02, 0x08, 0xe4,
+ 0x50, 0x80, 0x00, 0x07, 0x22, 0xff, 0x1c, 0x7e, 0xd0, 0x00, 0xbe, 0x85,
+ 0x81, 0x00, 0x01, 0xec, 0x50, 0x82, 0x00, 0x03, 0x10, 0xc4, 0xbe, 0x0a,
+ 0x81, 0x00, 0x0b, 0x20, 0x45, 0xaf, 0xd8, 0x0f, 0x00, 0x52, 0xb9, 0x00,
+ 0x00, 0xd4, 0x68, 0x83, 0x00, 0x0a, 0x09, 0xed, 0x5f, 0x00, 0xf4, 0x79,
+ 0x00, 0x00, 0x03, 0xe8, 0x5f, 0x80, 0x00, 0x02, 0x3c, 0xf4, 0x0e, 0x80,
+ 0x00, 0x0e, 0x96, 0xc0, 0x1e, 0x09, 0x6e, 0xea, 0x15, 0x00, 0x1c, 0xc2,
+ 0xfc, 0xf2, 0x88, 0xda, 0x66, 0x8d, 0x00, 0x03, 0x2f, 0xf7, 0x8a, 0x1b,
+ 0x8d, 0x00, 0x03, 0x05, 0x5d, 0xd7, 0x92, 0x80, 0x00, 0x1f, 0x23, 0xe4,
+ 0x87, 0x02, 0x00, 0xaa, 0x3e, 0xe6, 0x00, 0x00, 0xdb, 0x0c, 0xc6, 0x07,
+ 0x6f, 0xcf, 0x00, 0x00, 0x63, 0xd9, 0x00, 0x00, 0xe4, 0x7b, 0x20, 0x2b,
+ 0x66, 0xef, 0x4e, 0x35, 0xff, 0x2f, 0x83, 0x00, 0x01, 0xe4, 0x68, 0x80,
+ 0x00, 0x04, 0xb0, 0xa6, 0x00, 0xe4, 0x7d, 0x80, 0x24, 0x04, 0x23, 0x00,
+ 0x00, 0xac, 0xfe, 0x81, 0xfc, 0x10, 0x3f, 0x35, 0xff, 0x2f, 0x00, 0xbd,
+ 0xfc, 0xfc, 0x85, 0x00, 0xe4, 0x82, 0x2c, 0x2c, 0x2f, 0xff, 0x48, 0x80,
+ 0x00, 0x01, 0x74, 0xd8, 0x85, 0x00, 0x08, 0x90, 0xbc, 0x00, 0x00, 0xe4,
+ 0xfd, 0x94, 0xff, 0x4a, 0x80, 0x00, 0x01, 0x60, 0xec, 0x82, 0x00, 0x12,
+ 0x20, 0xf8, 0x00, 0xb3, 0xf6, 0x1c, 0x98, 0x84, 0x00, 0xe4, 0x44, 0x32,
+ 0xef, 0x0a, 0xe4, 0x48, 0x46, 0xff, 0x1e, 0x80, 0x00, 0x0c, 0xb7, 0xac,
+ 0x00, 0xe4, 0xf8, 0xf4, 0xfc, 0xed, 0x6a, 0x00, 0x47, 0xff, 0x1b, 0x80,
+ 0x00, 0x08, 0xb4, 0xaa, 0x00, 0xe4, 0xf8, 0xf4, 0xfa, 0xe6, 0x67, 0x81,
+ 0x00, 0x04, 0x2f, 0x78, 0xd7, 0xeb, 0x27, 0x80, 0x00, 0x01, 0x74, 0xd8,
+ 0x80, 0x00, 0x02, 0x08, 0xff, 0x48, 0x80, 0x00, 0x17, 0xe0, 0x6c, 0x00,
+ 0x10, 0xf9, 0x3d, 0x00, 0xd6, 0x6d, 0x00, 0x36, 0xf2, 0x07, 0xeb, 0x90,
+ 0x69, 0x88, 0x99, 0x00, 0x00, 0x0e, 0xe4, 0xf6, 0x5a, 0x82, 0x00, 0x02,
+ 0x91, 0xed, 0x0c, 0x81, 0x00, 0x02, 0x19, 0xeb, 0x62, 0x82, 0x00, 0x02,
+ 0x34, 0xff, 0x08, 0x83, 0x00, 0x02, 0x07, 0xe2, 0x50, 0x83, 0x00, 0x01,
+ 0xa4, 0x94, 0x80, 0x00, 0x06, 0xb2, 0x56, 0x00, 0x00, 0x09, 0xeb, 0x19,
+ 0x8e, 0x00, 0x09, 0x29, 0xaf, 0xdd, 0xe0, 0xed, 0xd8, 0x00, 0x00, 0xbc,
+ 0x8c, 0x80, 0x00, 0x04, 0xdb, 0x67, 0x0c, 0xff, 0x3b, 0x82, 0x00, 0x08,
+ 0x05, 0xfe, 0x40, 0x00, 0x00, 0x21, 0xff, 0x20, 0x0a, 0x83, 0xff, 0x04,
+ 0x70, 0x00, 0x00, 0x44, 0xf8, 0x82, 0x00, 0x0e, 0xfd, 0x49, 0x00, 0x00,
+ 0x1e, 0xff, 0x2c, 0x00, 0xbc, 0x83, 0x00, 0x00, 0x10, 0xff, 0x2c, 0x80,
+ 0x00, 0x02, 0x24, 0xff, 0x18, 0x83, 0x00, 0x01, 0x84, 0xb8, 0x80, 0x00,
+ 0x03, 0x64, 0xe0, 0xcd, 0xb9, 0x83, 0x00, 0x17, 0x34, 0xff, 0x08, 0x00,
+ 0x00, 0x48, 0xe1, 0x00, 0x60, 0xc8, 0x00, 0x78, 0xb0, 0x00, 0xbc, 0x81,
+ 0x00, 0x00, 0x10, 0xff, 0x2c, 0x0c, 0xff, 0x3b, 0x80, 0x00, 0x04, 0xd7,
+ 0x79, 0x00, 0xbc, 0x8a, 0x80, 0x00, 0x0d, 0xd8, 0x6e, 0x05, 0xfe, 0x40,
+ 0x00, 0x00, 0x21, 0xff, 0x24, 0x00, 0x00, 0xfc, 0x54, 0x82, 0x00, 0x05,
+ 0x20, 0xda, 0xec, 0xa5, 0x57, 0x05, 0x80, 0x00, 0x01, 0x8c, 0xac, 0x82,
+ 0x00, 0x1c, 0xbc, 0x80, 0x00, 0x00, 0x10, 0xff, 0x2c, 0x00, 0x3b, 0xfd,
+ 0x18, 0x00, 0xb9, 0x98, 0x00, 0x50, 0xdb, 0x00, 0xd7, 0xc1, 0x3c, 0x7d,
+ 0xb1, 0x00, 0x00, 0x03, 0xc8, 0xf8, 0x2b, 0x80, 0x00, 0x05, 0x1e, 0xfa,
+ 0x1d, 0x00, 0xa9, 0x8c, 0x81, 0x00, 0x02, 0x49, 0xf0, 0x27, 0x80, 0x00,
+ 0x02, 0x6e, 0xff, 0x92, 0x84, 0x00, 0x01, 0x60, 0xc4, 0x84, 0x00, 0x0b,
+ 0x39, 0xf1, 0xd1, 0x00, 0x2f, 0x59, 0x22, 0x4e, 0xaa, 0xee, 0xe7, 0x60,
+ 0x80, 0x00, 0x03, 0x23, 0xe4, 0x87, 0x02, 0x89, 0x00, 0x01, 0x46, 0xa2,
+ 0x88, 0x00, 0x07, 0x7d, 0xd1, 0xe8, 0xc8, 0xc8, 0xf2, 0xc8, 0x86, 0x80,
+ 0x00, 0x13, 0x30, 0xb0, 0x00, 0x92, 0xb9, 0x00, 0x00, 0x42, 0xbd, 0x5d,
+ 0xaa, 0x01, 0xc6, 0xae, 0x8f, 0x00, 0x7f, 0xba, 0x2a, 0xe3, 0x88, 0x00,
+ 0x01, 0x9f, 0xa5, 0x85, 0x00, 0x02, 0x42, 0xfe, 0x03, 0x86, 0x00, 0x07,
+ 0x05, 0x1c, 0x1c, 0x63, 0xbc, 0x1c, 0x1c, 0x10, 0x87, 0x00, 0x00, 0x1f,
+ 0x80, 0x2c, 0x00, 0x04, 0x88, 0x00, 0x01, 0x6f, 0xcd, 0x81, 0x00, 0x02,
+ 0x0d, 0xff, 0x30, 0x80, 0x00, 0x01, 0xd3, 0x6f, 0x81, 0x00, 0x01, 0xec,
+ 0x50, 0x81, 0x00, 0x03, 0x1a, 0xd4, 0xab, 0x08, 0x80, 0x00, 0x0d, 0x01,
+ 0x01, 0x00, 0x00, 0x01, 0xde, 0x6b, 0x0c, 0xda, 0x23, 0x00, 0x00, 0xd4,
+ 0x68, 0x84, 0x00, 0x04, 0xcd, 0x7c, 0x00, 0xe1, 0x6c, 0x80, 0x00, 0x01,
+ 0xcc, 0x76, 0x80, 0x00, 0x01, 0x93, 0xaf, 0x80, 0x00, 0x02, 0x07, 0xfc,
+ 0x42, 0x80, 0x00, 0x01, 0xdc, 0x68, 0x80, 0x00, 0x04, 0x0c, 0x07, 0x04,
+ 0xf4, 0x4a, 0x8e, 0x00, 0x07, 0x2c, 0x9e, 0xf2, 0xa2, 0x2e, 0x00, 0x00,
+ 0x31, 0x83, 0xf4, 0x08, 0x90, 0x00, 0x00, 0x0f, 0x75, 0xe3, 0xc9, 0x58,
+ 0x04, 0x80, 0x00, 0x01, 0xab, 0x9b, 0x80, 0x00, 0x12, 0xac, 0x46, 0xd5,
+ 0x00, 0x1a, 0xdc, 0x00, 0xcd, 0x00, 0xc8, 0xfa, 0xf0, 0xf0, 0xf3, 0xff,
+ 0x31, 0x00, 0xe4, 0x68, 0x80, 0x00, 0x04, 0x89, 0xc6, 0x1b, 0xff, 0x48,
+ 0x80, 0x00, 0x04, 0x07, 0x00, 0x00, 0xe4, 0x68, 0x80, 0x00, 0x04, 0xce,
+ 0x88, 0x00, 0xe4, 0x68, 0x83, 0x00, 0x01, 0xac, 0xb0, 0x81, 0x2c, 0x10,
+ 0x0b, 0x1a, 0xff, 0x48, 0x00, 0x21, 0x2c, 0xcb, 0x88, 0x00, 0xe4, 0x68,
+ 0x00, 0x00, 0x04, 0xff, 0x48, 0x80, 0x00, 0x01, 0x74, 0xd8, 0x85, 0x00,
+ 0x0d, 0x90, 0xbb, 0x00, 0x00, 0xe4, 0x86, 0x00, 0x9a, 0xe7, 0x13, 0x00,
+ 0x00, 0x60, 0xec, 0x82, 0x00, 0x12, 0x20, 0xf8, 0x00, 0x4c, 0x99, 0x00,
+ 0x98, 0x84, 0x00, 0xe4, 0x44, 0x00, 0xc5, 0x67, 0xe1, 0x48, 0x2e, 0xff,
+ 0x35, 0x80, 0x00, 0x0c, 0xce, 0x93, 0x00, 0xe4, 0x7d, 0x24, 0x1d, 0x04,
+ 0x00, 0x00, 0x35, 0xff, 0x2f, 0x80, 0x00, 0x07, 0xc7, 0x93, 0x00, 0xe4,
+ 0x7d, 0x24, 0xb8, 0xa9, 0x84, 0x00, 0x02, 0x07, 0xd1, 0x99, 0x80, 0x00,
+ 0x01, 0x74, 0xd8, 0x80, 0x00, 0x02, 0x04, 0xfe, 0x4d, 0x80, 0x00, 0x18,
+ 0xe8, 0x68, 0x00, 0x00, 0xb2, 0x90, 0x29, 0xfd, 0x18, 0x00, 0x11, 0xff,
+ 0x4d, 0xbc, 0x53, 0xa7, 0xa3, 0x74, 0x00, 0x00, 0x92, 0xbf, 0x5a, 0xe8,
+ 0x10, 0x81, 0x00, 0x01, 0x70, 0xd8, 0x81, 0x00, 0x02, 0x01, 0xba, 0xab,
+ 0x83, 0x00, 0x02, 0x34, 0xff, 0x08, 0x84, 0x00, 0x02, 0x68, 0xd0, 0x01,
+ 0x82, 0x00, 0x06, 0xa4, 0x94, 0x00, 0x00, 0x02, 0x7b, 0x07, 0x80, 0x00,
+ 0x01, 0x56, 0x31, 0x8e, 0x00, 0x09, 0xdb, 0xa4, 0x09, 0x00, 0x6a, 0xd8,
+ 0x00, 0x00, 0xbc, 0x88, 0x80, 0x00, 0x04, 0xd9, 0x6c, 0x0c, 0xff, 0x3c,
+ 0x82, 0x00, 0x0a, 0x05, 0xfe, 0x41, 0x00, 0x00, 0x26, 0xff, 0x20, 0x08,
+ 0xfe, 0x41, 0x84, 0x00, 0x01, 0x44, 0xf8, 0x81, 0x00, 0x0f, 0x01, 0xfe,
+ 0x44, 0x00, 0x00, 0x18, 0xff, 0x2c, 0x00, 0xbc, 0x80, 0x00, 0x00, 0x10,
+ 0xff, 0x2c, 0x80, 0x00, 0x02, 0x24, 0xff, 0x18, 0x83, 0x00, 0x01, 0x84,
+ 0xb8, 0x80, 0x00, 0x04, 0x64, 0xfe, 0x95, 0xf6, 0x44, 0x82, 0x00, 0x17,
+ 0x34, 0xff, 0x08, 0x00, 0x00, 0x48, 0xe0, 0x00, 0x60, 0xc8, 0x00, 0x78,
+ 0xb0, 0x00, 0xbc, 0x80, 0x00, 0x00, 0x10, 0xff, 0x2c, 0x0c, 0xff, 0x3b,
+ 0x80, 0x00, 0x04, 0xd8, 0x6f, 0x00, 0xbc, 0x89, 0x80, 0x00, 0x0d, 0xdc,
+ 0x66, 0x05, 0xfe, 0x41, 0x00, 0x00, 0x26, 0xff, 0x24, 0x00, 0x00, 0xfc,
+ 0x3c, 0x83, 0x00, 0x09, 0x04, 0x44, 0x8d, 0xe5, 0xbf, 0x04, 0x00, 0x00,
+ 0x8c, 0xac, 0x82, 0x00, 0x1c, 0xbc, 0x80, 0x00, 0x00, 0x11, 0xff, 0x2c,
+ 0x00, 0x00, 0xdb, 0x70, 0x18, 0xfc, 0x37, 0x00, 0x28, 0xfb, 0x28, 0xcd,
+ 0x68, 0x84, 0xa3, 0x87, 0x00, 0x00, 0x0e, 0xe1, 0xf2, 0x4f, 0x81, 0x00,
+ 0x04, 0xb2, 0x7d, 0x10, 0xf7, 0x28, 0x80, 0x00, 0x02, 0x20, 0xed, 0x53,
+ 0x81, 0x00, 0x03, 0x10, 0x59, 0xf2, 0x3e, 0x83, 0x00, 0x01, 0x60, 0xc4,
+ 0x83, 0x00, 0x03, 0x03, 0xce, 0x9f, 0x25, 0x89, 0x00, 0x01, 0xab, 0x9b,
+ 0x99, 0x00, 0x1d, 0x5d, 0x62, 0x00, 0x22, 0xa1, 0x00, 0x00, 0x54, 0xaf,
+ 0x00, 0x30, 0xb0, 0x00, 0x5e, 0xce, 0x00, 0x08, 0xd2, 0x24, 0x7c, 0x80,
+ 0x00, 0x9d, 0xc8, 0x7d, 0x00, 0x05, 0xc7, 0xde, 0x81, 0x88, 0x00, 0x01,
+ 0x8c, 0xb9, 0x85, 0x00, 0x01, 0x55, 0xef, 0x8a, 0x00, 0x01, 0x50, 0xb4,
+ 0x93, 0x00, 0x01, 0x1a, 0x2c, 0x81, 0x00, 0x02, 0x09, 0xe7, 0x4c, 0x82,
+ 0x00, 0x06, 0xd8, 0x69, 0x00, 0x00, 0x15, 0xfd, 0x38, 0x81, 0x00, 0x01,
+ 0xec, 0x50, 0x80, 0x00, 0x03, 0x12, 0xd8, 0x96, 0x01, 0x80, 0x00, 0x02,
+ 0x07, 0xf1, 0x49, 0x80, 0x00, 0x03, 0xdb, 0x6e, 0x4b, 0xfb, 0x80, 0xec,
+ 0x12, 0xfc, 0xf4, 0xa2, 0x06, 0xa7, 0x31, 0x00, 0x00, 0x09, 0xef, 0x5c,
+ 0x00, 0xac, 0xa5, 0x00, 0x00, 0x05, 0xec, 0x56, 0x80, 0x00, 0x01, 0xdc,
+ 0x67, 0x80, 0x00, 0x02, 0x06, 0xfb, 0x46, 0x80, 0x00, 0x09, 0xe2, 0x65,
+ 0x00, 0x56, 0x3e, 0x00, 0x00, 0x49, 0xfa, 0x11, 0x80, 0x00, 0x01, 0x1a,
+ 0x2c, 0x83, 0x00, 0x02, 0x1c, 0x3c, 0x13, 0x82, 0x00, 0x05, 0x16, 0x81,
+ 0xe9, 0xba, 0x37, 0x06, 0x83, 0x20, 0x05, 0x13, 0x0e, 0x8d, 0xef, 0xad,
+ 0x3b, 0x83, 0x00, 0x01, 0x57, 0x24, 0x80, 0x00, 0x0a, 0x99, 0x4c, 0xe1,
+ 0x0b, 0x84, 0xbf, 0x3d, 0x93, 0x22, 0xff, 0x3e, 0x80, 0x20, 0x04, 0xc4,
+ 0x88, 0x00, 0xe4, 0x68, 0x80, 0x00, 0x04, 0x8a, 0xcb, 0x00, 0xdb, 0x93,
+ 0x80, 0x00, 0x0c, 0x99, 0x93, 0x00, 0xe4, 0x68, 0x00, 0x00, 0x2b, 0xff,
+ 0x44, 0x00, 0xe4, 0x68, 0x83, 0x00, 0x01, 0xac, 0xa0, 0x83, 0x00, 0x01,
+ 0xdb, 0x95, 0x80, 0x00, 0x09, 0xc0, 0x88, 0x00, 0xe4, 0x68, 0x00, 0x00,
+ 0x04, 0xff, 0x48, 0x80, 0x00, 0x01, 0x74, 0xd8, 0x81, 0x00, 0x11, 0x8b,
+ 0x89, 0x00, 0x00, 0xa4, 0xa3, 0x00, 0x00, 0xe4, 0x68, 0x00, 0x0b, 0xda,
+ 0xaa, 0x00, 0x00, 0x60, 0xec, 0x82, 0x00, 0x01, 0x20, 0xf8, 0x81, 0x00,
+ 0x14, 0x98, 0x84, 0x00, 0xe4, 0x44, 0x00, 0x58, 0xd4, 0xd3, 0x48, 0x05,
+ 0xf0, 0x7b, 0x00, 0x00, 0x16, 0xfc, 0x59, 0x00, 0xe4, 0x68, 0x82, 0x00,
+ 0x12, 0x0b, 0xf9, 0x69, 0x00, 0x00, 0x0a, 0xf7, 0x5f, 0x00, 0xe4, 0x68,
+ 0x00, 0x1f, 0xf3, 0x58, 0x00, 0x38, 0xb9, 0x05, 0x80, 0x00, 0x01, 0xa5,
+ 0xa7, 0x80, 0x00, 0x01, 0x74, 0xd8, 0x81, 0x00, 0x0c, 0xe8, 0x6a, 0x00,
+ 0x00, 0x0e, 0xfc, 0x4f, 0x00, 0x00, 0x59, 0xde, 0x73, 0xbc, 0x80, 0x00,
+ 0x0d, 0xec, 0xa0, 0x7d, 0x16, 0xe1, 0xbb, 0x4f, 0x00, 0x34, 0xf8, 0x2a,
+ 0x00, 0xbf, 0x99, 0x81, 0x00, 0x01, 0x70, 0xd8, 0x81, 0x00, 0x02, 0x73,
+ 0xe3, 0x12, 0x83, 0x00, 0x02, 0x34, 0xff, 0x08, 0x84, 0x00, 0x02, 0x05,
+ 0xe0, 0x55, 0x82, 0x00, 0x01, 0xa4, 0x94, 0x97, 0x00, 0x22, 0x15, 0xff,
+ 0x34, 0x00, 0x00, 0x96, 0xd8, 0x00, 0x00, 0xbc, 0xa9, 0x00, 0x00, 0x07,
+ 0xf4, 0x4e, 0x00, 0xe7, 0x65, 0x00, 0x00, 0x02, 0x79, 0x28, 0x00, 0xea,
+ 0x63, 0x00, 0x00, 0x50, 0xff, 0x20, 0x00, 0xe1, 0x72, 0x80, 0x00, 0x00,
+ 0x20, 0x80, 0x00, 0x01, 0x44, 0xf8, 0x82, 0x00, 0x0e, 0xe7, 0x60, 0x00,
+ 0x00, 0x46, 0xff, 0x2c, 0x00, 0xbc, 0x80, 0x00, 0x00, 0x10, 0xff, 0x2c,
+ 0x80, 0x00, 0x02, 0x24, 0xff, 0x18, 0x83, 0x00, 0x01, 0x84, 0xb8, 0x80,
+ 0x00, 0x05, 0x64, 0xd8, 0x00, 0x72, 0xe3, 0x10, 0x81, 0x00, 0x30, 0x34,
+ 0xff, 0x08, 0x00, 0x00, 0x48, 0xe0, 0x00, 0x60, 0xc8, 0x00, 0x78, 0xb0,
+ 0x00, 0xbc, 0x80, 0x00, 0x00, 0x10, 0xff, 0x2c, 0x00, 0xe8, 0x64, 0x00,
+ 0x00, 0x0a, 0xf5, 0x4b, 0x00, 0xbc, 0xac, 0x00, 0x00, 0x06, 0xf5, 0x4b,
+ 0x00, 0xea, 0x63, 0x00, 0x00, 0x51, 0xff, 0x24, 0x00, 0x00, 0xfc, 0x3c,
+ 0x82, 0x00, 0x0a, 0x05, 0x07, 0x00, 0x00, 0x10, 0xf7, 0x35, 0x00, 0x00,
+ 0x8b, 0xac, 0x82, 0x00, 0x1d, 0xb3, 0x88, 0x00, 0x00, 0x2f, 0xff, 0x2c,
+ 0x00, 0x00, 0x7d, 0xc4, 0x6d, 0xd6, 0x00, 0x00, 0x05, 0xfb, 0x8a, 0x82,
+ 0x22, 0xca, 0xc3, 0x5d, 0x00, 0x00, 0xa1, 0xa5, 0x4e, 0xea, 0x17, 0x80,
+ 0x00, 0x03, 0x48, 0xdd, 0x68, 0xc2, 0x80, 0x00, 0x02, 0x08, 0xcd, 0x8b,
+ 0x84, 0x00, 0x01, 0xa2, 0x95, 0x83, 0x00, 0x01, 0x60, 0xc4, 0x83, 0x00,
+ 0x02, 0x2e, 0xfe, 0x0b, 0x8a, 0x00, 0x01, 0x57, 0x24, 0x8b, 0x00, 0x01,
+ 0x38, 0x61, 0x89, 0x00, 0x1f, 0x8d, 0x33, 0x00, 0x53, 0x6f, 0x00, 0x00,
+ 0x22, 0xf5, 0x70, 0x3c, 0xb1, 0x25, 0xca, 0x8c, 0x00, 0x87, 0x78, 0x00,
+ 0x60, 0x9c, 0x00, 0xba, 0x92, 0xdf, 0x31, 0x17, 0x8d, 0xff, 0x93, 0x16,
+ 0x03, 0x86, 0x00, 0x01, 0x60, 0xe5, 0x85, 0x00, 0x01, 0x85, 0xc3, 0x8a,
+ 0x00, 0x01, 0x50, 0xb4, 0x82, 0x00, 0x02, 0x32, 0xff, 0x85, 0x8b, 0x00,
+ 0x01, 0x9c, 0xff, 0x81, 0x00, 0x01, 0x74, 0xc9, 0x83, 0x00, 0x12, 0x6f,
+ 0xe9, 0x41, 0x26, 0xb0, 0xc9, 0x01, 0x00, 0x0b, 0x0c, 0x0c, 0xec, 0x58,
+ 0x0c, 0x08, 0x00, 0xa7, 0xc3, 0x11, 0x80, 0x10, 0x09, 0x06, 0x00, 0xa5,
+ 0xd5, 0x39, 0x20, 0x7f, 0xf8, 0x28, 0x08, 0x81, 0x1c, 0x17, 0xd8, 0x78,
+ 0x13, 0x00, 0xb5, 0xca, 0x2e, 0x23, 0xa4, 0xe5, 0x0e, 0x00, 0x40, 0xf9,
+ 0x5f, 0x1b, 0x91, 0xe5, 0x0a, 0x00, 0x00, 0x0d, 0xff, 0x39, 0x81, 0x00,
+ 0x0d, 0xb3, 0xc0, 0x1a, 0x06, 0x6b, 0xf5, 0x20, 0x00, 0x84, 0xd7, 0x28,
+ 0x2c, 0xd6, 0x94, 0x81, 0x00, 0x01, 0x9c, 0xff, 0x83, 0x00, 0x02, 0x9d,
+ 0xf8, 0x16, 0x84, 0x00, 0x02, 0x08, 0x64, 0x71, 0x85, 0x00, 0x02, 0x2b,
+ 0x90, 0x21, 0x85, 0x00, 0x01, 0x6c, 0x2d, 0x80, 0x00, 0x09, 0x68, 0x7d,
+ 0x61, 0xc6, 0x59, 0x9e, 0xb5, 0x16, 0x7a, 0xd4, 0x81, 0x00, 0x1c, 0x6d,
+ 0xdf, 0x00, 0xe4, 0x78, 0x1c, 0x24, 0x5a, 0xf1, 0x77, 0x00, 0x5f, 0xfb,
+ 0x70, 0x2d, 0x78, 0xf6, 0x31, 0x00, 0xe4, 0x7b, 0x25, 0x54, 0xe1, 0xbb,
+ 0x00, 0x00, 0xe4, 0x7b, 0x81, 0x20, 0x03, 0x15, 0x00, 0xac, 0xa0, 0x83,
+ 0x00, 0x29, 0x60, 0xfc, 0x6f, 0x2b, 0x4e, 0xe3, 0x85, 0x00, 0xe4, 0x68,
+ 0x00, 0x00, 0x04, 0xff, 0x48, 0x00, 0x14, 0x20, 0x85, 0xdd, 0x20, 0x20,
+ 0x00, 0x00, 0x67, 0xf3, 0x4a, 0x44, 0xf0, 0x5c, 0x00, 0x00, 0xe4, 0x68,
+ 0x00, 0x00, 0x36, 0xfb, 0x5b, 0x00, 0x60, 0xee, 0x81, 0x20, 0x02, 0x10,
+ 0x20, 0xf8, 0x81, 0x00, 0x14, 0x98, 0x84, 0x00, 0xe4, 0x44, 0x00, 0x05,
+ 0xe6, 0xf7, 0x48, 0x00, 0x83, 0xf3, 0x58, 0x36, 0xba, 0xdc, 0x07, 0x00,
+ 0xe4, 0x68, 0x83, 0x00, 0x16, 0xa4, 0xd6, 0x14, 0x00, 0x7d, 0xed, 0x0f,
+ 0x00, 0xe4, 0x68, 0x00, 0x00, 0x6d, 0xed, 0x18, 0x14, 0xec, 0xa5, 0x2c,
+ 0x1d, 0x5b, 0xf7, 0x5a, 0x80, 0x00, 0x01, 0x74, 0xd8, 0x81, 0x00, 0x0c,
+ 0x9b, 0xd8, 0x3e, 0x2f, 0xa1, 0xf0, 0x0e, 0x00, 0x00, 0x0b, 0xf5, 0xd9,
+ 0x64, 0x80, 0x00, 0x0e, 0xc7, 0xea, 0x3c, 0x00, 0xd6, 0xe9, 0x2a, 0x03,
+ 0xce, 0x8b, 0x00, 0x00, 0x2b, 0xf9, 0x39, 0x80, 0x00, 0x01, 0x70, 0xd8,
+ 0x80, 0x00, 0x02, 0x30, 0xf9, 0x62, 0x81, 0x20, 0x05, 0x1c, 0x00, 0x00,
+ 0x34, 0xff, 0x08, 0x85, 0x00, 0x02, 0x64, 0xd4, 0x02, 0x81, 0x00, 0x01,
+ 0xa4, 0x94, 0x97, 0x00, 0x2b, 0x05, 0xf4, 0x67, 0x00, 0x4f, 0xce, 0xe9,
+ 0x02, 0x00, 0xbc, 0xeb, 0x3f, 0x07, 0x7a, 0xf1, 0x0e, 0x00, 0x7a, 0xdc,
+ 0x2f, 0x0b, 0x7a, 0xf2, 0x17, 0x00, 0x9c, 0xd1, 0x20, 0x26, 0xbc, 0xff,
+ 0x20, 0x00, 0x76, 0xe6, 0x33, 0x04, 0x62, 0xf5, 0x16, 0x00, 0x00, 0x44,
+ 0xf8, 0x82, 0x00, 0x16, 0xa3, 0xc5, 0x0e, 0x15, 0xb1, 0xff, 0x2c, 0x00,
+ 0xbc, 0x80, 0x00, 0x00, 0x10, 0xff, 0x2c, 0x00, 0x08, 0x08, 0x2a, 0xff,
+ 0x1f, 0x08, 0x05, 0x81, 0x00, 0x01, 0x84, 0xb8, 0x80, 0x00, 0x3a, 0x64,
+ 0xd8, 0x00, 0x02, 0xc2, 0xa5, 0x00, 0x00, 0x08, 0x08, 0x3a, 0xff, 0x0f,
+ 0x08, 0x05, 0x48, 0xe0, 0x00, 0x60, 0xc8, 0x00, 0x78, 0xb0, 0x00, 0xbc,
+ 0x80, 0x00, 0x00, 0x10, 0xff, 0x2c, 0x00, 0x7f, 0xd9, 0x24, 0x0c, 0x8e,
+ 0xdc, 0x04, 0x00, 0xbc, 0xec, 0x44, 0x07, 0x79, 0xf0, 0x0a, 0x00, 0x9b,
+ 0xd1, 0x20, 0x26, 0xbb, 0xff, 0x24, 0x00, 0x00, 0xfc, 0x3c, 0x82, 0x00,
+ 0x1c, 0xaa, 0x99, 0x0c, 0x01, 0x44, 0xf4, 0x13, 0x00, 0x00, 0x75, 0xdd,
+ 0x27, 0x1d, 0x3b, 0x00, 0x00, 0x8c, 0xc7, 0x06, 0x04, 0x9b, 0xff, 0x2c,
+ 0x00, 0x00, 0x20, 0xf9, 0xc5, 0x75, 0x80, 0x00, 0x0d, 0xd8, 0xe2, 0x37,
+ 0x00, 0xd7, 0xe5, 0x33, 0x00, 0x52, 0xe6, 0x12, 0x00, 0xa2, 0xb3, 0x80,
+ 0x00, 0x03, 0x01, 0xdd, 0xe7, 0x5c, 0x80, 0x00, 0x02, 0x9c, 0xc3, 0x08,
+ 0x80, 0x04, 0x00, 0x01, 0x80, 0x00, 0x01, 0x90, 0xa0, 0x83, 0x00, 0x01,
+ 0x60, 0xc4, 0x83, 0x00, 0x01, 0x38, 0xf8, 0x8b, 0x00, 0x01, 0x6c, 0x2d,
+ 0x8b, 0x00, 0x01, 0x7c, 0xd8, 0x89, 0x00, 0x04, 0xb8, 0x07, 0x00, 0x84,
+ 0x3d, 0x80, 0x00, 0x17, 0x41, 0xc8, 0xf5, 0xfe, 0xe5, 0x92, 0x09, 0x2e,
+ 0xcc, 0x04, 0x00, 0x0b, 0xb7, 0xc0, 0xa7, 0x04, 0x8c, 0xe7, 0xee, 0xac,
+ 0x3e, 0xc7, 0xf2, 0x14, 0x86, 0x00, 0x02, 0x1e, 0xfe, 0x2a, 0x84, 0x00,
+ 0x01, 0xc9, 0x82, 0x91, 0x00, 0x02, 0x6d, 0xfb, 0x1c, 0x8b, 0x00, 0x01,
+ 0x9c, 0xff, 0x80, 0x00, 0x02, 0x0c, 0xea, 0x48, 0x83, 0x00, 0x08, 0x01,
+ 0x84, 0xe9, 0xf6, 0xb4, 0x1b, 0x00, 0x00, 0xec, 0x82, 0xff, 0x02, 0xb8,
+ 0x03, 0xfe, 0x82, 0xff, 0x07, 0x68, 0x00, 0x0d, 0x95, 0xe6, 0xf4, 0xcb,
+ 0x48, 0x83, 0x00, 0x09, 0xd4, 0x68, 0x00, 0x00, 0x13, 0xa3, 0xec, 0xf4,
+ 0xb9, 0x28, 0x80, 0x00, 0x04, 0x5d, 0xde, 0xf4, 0xc1, 0x2b, 0x80, 0x00,
+ 0x02, 0x27, 0xff, 0x20, 0x81, 0x00, 0x0d, 0x14, 0x9d, 0xe7, 0xf2, 0xc7,
+ 0x41, 0x00, 0x00, 0x08, 0xa3, 0xf0, 0xee, 0x94, 0x07, 0x81, 0x00, 0x01,
+ 0x9c, 0xff, 0x83, 0x00, 0x01, 0xd9, 0x9f, 0x9b, 0x00, 0x01, 0xf0, 0x64,
+ 0x80, 0x00, 0x02, 0x1b, 0xd6, 0x03, 0x80, 0x00, 0x03, 0x0a, 0x00, 0xd3,
+ 0x81, 0x81, 0x00, 0x1b, 0x1b, 0xfe, 0x38, 0xe4, 0xff, 0xff, 0xf8, 0xd7,
+ 0x75, 0x02, 0x00, 0x00, 0x66, 0xdb, 0xf8, 0xcd, 0x43, 0x00, 0x00, 0xe4,
+ 0xff, 0xfe, 0xe7, 0x92, 0x0c, 0x00, 0x00, 0xe4, 0x82, 0xff, 0x03, 0xac,
+ 0x00, 0xac, 0xa0, 0x84, 0x00, 0x0f, 0x6b, 0xdf, 0xfa, 0xd7, 0x7b, 0x0a,
+ 0x00, 0xe4, 0x68, 0x00, 0x00, 0x04, 0xff, 0x48, 0x00, 0xa0, 0x82, 0xff,
+ 0x0b, 0x00, 0x00, 0x02, 0x90, 0xec, 0xe9, 0x87, 0x02, 0x00, 0x00, 0xe4,
+ 0x68, 0x80, 0x00, 0x03, 0x7e, 0xef, 0x1c, 0x60, 0x82, 0xff, 0x02, 0x84,
+ 0x20, 0xf8, 0x81, 0x00, 0x14, 0x98, 0x84, 0x00, 0xe4, 0x44, 0x00, 0x00,
+ 0x7e, 0xff, 0x48, 0x00, 0x03, 0x89, 0xea, 0xf7, 0xba, 0x24, 0x00, 0x00,
+ 0xe4, 0x68, 0x83, 0x00, 0x15, 0x15, 0xca, 0xf7, 0xe9, 0xea, 0x45, 0x00,
+ 0x00, 0xe4, 0x68, 0x00, 0x00, 0x02, 0xc5, 0xb3, 0x00, 0x2f, 0xb5, 0xec,
+ 0xf5, 0xd2, 0x65, 0x81, 0x00, 0x01, 0x74, 0xd8, 0x81, 0x00, 0x05, 0x12,
+ 0xa1, 0xe8, 0xf1, 0xc2, 0x35, 0x81, 0x00, 0x02, 0xa8, 0xfa, 0x11, 0x80,
+ 0x00, 0x09, 0xa2, 0xf5, 0x06, 0x00, 0x97, 0xfe, 0x08, 0x70, 0xe4, 0x0c,
+ 0x80, 0x00, 0x06, 0x8d, 0xd3, 0x05, 0x00, 0x00, 0x70, 0xd8, 0x80, 0x00,
+ 0x00, 0x80, 0x83, 0xff, 0x05, 0xe4, 0x00, 0x00, 0x34, 0xff, 0x08, 0x85,
+ 0x00, 0x02, 0x04, 0xdc, 0x5a, 0x81, 0x00, 0x01, 0xa4, 0x94, 0x98, 0x00,
+ 0x25, 0x5f, 0xe7, 0xe0, 0x96, 0x1e, 0xe0, 0xd1, 0x00, 0xc1, 0x80, 0xb2,
+ 0xf5, 0xd6, 0x40, 0x00, 0x00, 0x04, 0x8a, 0xe8, 0xf9, 0xc8, 0x39, 0x00,
+ 0x00, 0x14, 0xb5, 0xf4, 0xd7, 0x47, 0xff, 0x25, 0x00, 0x04, 0x89, 0xe9,
+ 0xf5, 0xc8, 0x3e, 0x80, 0x00, 0x01, 0x44, 0xf8, 0x82, 0x00, 0x0f, 0x16,
+ 0xb8, 0xf2, 0xce, 0x43, 0xff, 0x2a, 0x00, 0xbc, 0x80, 0x00, 0x00, 0x10,
+ 0xff, 0x2c, 0x04, 0x83, 0xff, 0x00, 0xb0, 0x81, 0x00, 0x01, 0x84, 0xb8,
+ 0x80, 0x00, 0x07, 0x64, 0xd8, 0x00, 0x00, 0x22, 0xf4, 0x56, 0x14, 0x83,
+ 0xff, 0x2c, 0xa0, 0x48, 0xe0, 0x00, 0x60, 0xc8, 0x00, 0x78, 0xb0, 0x00,
+ 0xbc, 0x80, 0x00, 0x00, 0x10, 0xff, 0x2c, 0x00, 0x06, 0x93, 0xed, 0xf6,
+ 0xbf, 0x2b, 0x00, 0x00, 0xbc, 0x8e, 0xb1, 0xf5, 0xd8, 0x44, 0x00, 0x00,
+ 0x13, 0xb3, 0xf3, 0xd6, 0x4d, 0xff, 0x24, 0x00, 0x00, 0xfc, 0x3c, 0x82,
+ 0x00, 0x05, 0x17, 0xae, 0xed, 0xf3, 0xcc, 0x47, 0x80, 0x00, 0x0d, 0x15,
+ 0xc2, 0xf8, 0xf0, 0xbd, 0x00, 0x00, 0x1a, 0xc1, 0xe8, 0xcf, 0x46, 0xfa,
+ 0x30, 0x80, 0x00, 0x02, 0xbf, 0xfc, 0x18, 0x80, 0x00, 0x0e, 0xb0, 0xea,
+ 0x02, 0x00, 0x94, 0xfe, 0x0a, 0x17, 0xeb, 0x4d, 0x00, 0x00, 0x10, 0xe5,
+ 0x66, 0x80, 0x00, 0x02, 0x78, 0xee, 0x08, 0x80, 0x00, 0x83, 0xff, 0x00,
+ 0x4c, 0x80, 0x00, 0x01, 0x90, 0xa0, 0x83, 0x00, 0x01, 0x60, 0xc4, 0x83,
+ 0x00, 0x01, 0x38, 0xf8, 0x8b, 0x00, 0x01, 0xf0, 0x64, 0xa3, 0x00, 0x01,
+ 0x24, 0x84, 0x9b, 0x00, 0x01, 0xb3, 0x96, 0x83, 0x00, 0x02, 0x34, 0xfa,
+ 0x1d, 0x91, 0x00, 0x01, 0xa8, 0xab, 0xf3, 0x00, 0x02, 0x16, 0xff, 0x30,
+ 0xa1, 0x00, 0x06, 0x84, 0x9b, 0x0d, 0x02, 0x4f, 0xcc, 0x05, 0xff, 0x00,
+ 0x03, 0x01, 0x42, 0xff, 0x42, 0xc9, 0x00, 0x02, 0x34, 0xff, 0x08, 0x8c,
+ 0x00, 0x01, 0xa4, 0x94, 0xcc, 0x00, 0x02, 0x25, 0xff, 0x11, 0x91, 0x00,
+ 0x01, 0x95, 0xa7, 0xa8, 0x00, 0x01, 0xbc, 0x80, 0x87, 0x00, 0x02, 0x18,
+ 0xff, 0x24, 0xb8, 0x00, 0x01, 0x9a, 0x93, 0x8b, 0x00, 0x01, 0x8d, 0xa3,
+ 0x83, 0x00, 0x01, 0x60, 0xc4, 0x83, 0x00, 0x01, 0x3b, 0xf5, 0xd3, 0x00,
+ 0x02, 0x33, 0xf4, 0x23, 0x82, 0x00, 0x01, 0xb7, 0x97, 0x92, 0x00, 0x01,
+ 0xe3, 0x3e, 0xf3, 0x00, 0x01, 0x52, 0xc1, 0xa2, 0x00, 0x05, 0x01, 0x72,
+ 0xcf, 0xd6, 0x9c, 0x1a, 0xff, 0x00, 0x80, 0x00, 0x03, 0xb8, 0xcb, 0x27,
+ 0x12, 0xc7, 0x00, 0x04, 0x34, 0xff, 0x0b, 0x04, 0x02, 0x88, 0x00, 0x03,
+ 0x04, 0x04, 0xa5, 0x94, 0x86, 0x00, 0x00, 0x05, 0x85, 0xb0, 0x00, 0x4a,
+ 0xb5, 0x00, 0x05, 0x54, 0xe8, 0x28, 0x0a, 0x9b, 0xc9, 0x8e, 0x00, 0x05,
+ 0x10, 0x36, 0x1e, 0x4a, 0xef, 0x63, 0xa8, 0x00, 0x01, 0xbc, 0x80, 0x87,
+ 0x00, 0x02, 0x18, 0xff, 0x24, 0xb6, 0x00, 0x03, 0x0c, 0x55, 0xf4, 0x23,
+ 0x8b, 0x00, 0x04, 0x67, 0xd7, 0x15, 0x04, 0x01, 0x80, 0x00, 0x01, 0x60,
+ 0xc4, 0x81, 0x00, 0x03, 0x03, 0x07, 0x82, 0xcd, 0xd4, 0x00, 0x02, 0x89,
+ 0xc1, 0x01, 0x80, 0x00, 0x02, 0x5f, 0xe2, 0x0e, 0x91, 0x00, 0x01, 0x1e,
+ 0xd1, 0xf4, 0x00, 0x01, 0x58, 0x43, 0xff, 0x00, 0xab, 0x00, 0x03, 0x1c,
+ 0xbd, 0xf6, 0xaf, 0xc7, 0x00, 0x00, 0x34, 0x80, 0xff, 0x00, 0x8c, 0x87,
+ 0x00, 0x00, 0x28, 0x80, 0xff, 0x00, 0x94, 0xc8, 0x00, 0x05, 0x03, 0x8d,
+ 0xea, 0xf2, 0xbc, 0x25, 0x8e, 0x00, 0x05, 0x25, 0xdc, 0xf8, 0xe3, 0x83,
+ 0x02, 0xa8, 0x00, 0x01, 0xbc, 0x80, 0x87, 0x00, 0x02, 0x18, 0xff, 0x24,
+ 0xb6, 0x00, 0x02, 0xcf, 0xe4, 0x53, 0x8c, 0x00, 0x04, 0x09, 0xb3, 0xfb,
+ 0xff, 0x40, 0x80, 0x00, 0x01, 0x60, 0xc4, 0x81, 0x00, 0x03, 0xdc, 0xff,
+ 0xdf, 0x3c, 0x90, 0x00,
+};
+static EG_EMBEDDED_IMAGE egemb_font = { 768, 14, EG_EIPIXELMODE_GRAY_ALPHA, EG_EICOMPMODE_RLE, egemb_liberation_mono_regular_14_data, 6544 };
diff --git a/libeg/image.c b/libeg/image.c
new file mode 100644 (file)
index 0000000..5fcd288
--- /dev/null
@@ -0,0 +1,691 @@
+/*
+ * libeg/image.c
+ * Image handling functions
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Modifications copyright (c) 2012-2015 Roderick W. Smith
+ *
+ * Modifications distributed under the terms of the GNU General Public
+ * License (GPL) version 3 (GPLv3), or (at your option) any later version.
+ *
+ */
+/*
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "libegint.h"
+#include "../refind/global.h"
+#include "../refind/lib.h"
+#include "../refind/screen.h"
+#include "../refind/mystrings.h"
+#include "../include/refit_call_wrapper.h"
+#include "lodepng.h"
+
+#define MAX_FILE_SIZE (1024*1024*1024)
+
+// Multiplier for pseudo-floating-point operations in egScaleImage().
+// A value of 4096 should keep us within limits on 32-bit systems, but I've
+// seen some minor artifacts at this level, so give it a bit more precision
+// on 64-bit systems....
+#if defined(EFIX64) | defined(EFIAARCH64)
+#define FP_MULTIPLIER (UINTN) 65536
+#else
+#define FP_MULTIPLIER (UINTN) 4096
+#endif
+
+#ifndef __MAKEWITH_GNUEFI
+#define LibLocateHandle gBS->LocateHandleBuffer
+#define LibOpenRoot EfiLibOpenRoot
+#endif
+
+//
+// Basic image handling
+//
+
+EG_IMAGE * egCreateImage(IN UINTN Width, IN UINTN Height, IN BOOLEAN HasAlpha)
+{
+    EG_IMAGE        *NewImage;
+
+    NewImage = (EG_IMAGE *) AllocatePool(sizeof(EG_IMAGE));
+    if (NewImage == NULL)
+        return NULL;
+    NewImage->PixelData = (EG_PIXEL *) AllocatePool(Width * Height * sizeof(EG_PIXEL));
+    if (NewImage->PixelData == NULL) {
+        egFreeImage(NewImage);
+        return NULL;
+    }
+
+    NewImage->Width = Width;
+    NewImage->Height = Height;
+    NewImage->HasAlpha = HasAlpha;
+    return NewImage;
+}
+
+EG_IMAGE * egCreateFilledImage(IN UINTN Width, IN UINTN Height, IN BOOLEAN HasAlpha, IN EG_PIXEL *Color)
+{
+    EG_IMAGE        *NewImage;
+
+    NewImage = egCreateImage(Width, Height, HasAlpha);
+    if (NewImage == NULL)
+        return NULL;
+
+    egFillImage(NewImage, Color);
+    return NewImage;
+}
+
+EG_IMAGE * egCopyImage(IN EG_IMAGE *Image)
+{
+    EG_IMAGE        *NewImage = NULL;
+
+    if (Image != NULL)
+       NewImage = egCreateImage(Image->Width, Image->Height, Image->HasAlpha);
+    if (NewImage == NULL)
+        return NULL;
+
+    CopyMem(NewImage->PixelData, Image->PixelData, Image->Width * Image->Height * sizeof(EG_PIXEL));
+    return NewImage;
+}
+
+// Returns a smaller image composed of the specified crop area from the larger area.
+// If the specified area is larger than is in the original, returns NULL.
+EG_IMAGE * egCropImage(IN EG_IMAGE *Image, IN UINTN StartX, IN UINTN StartY, IN UINTN Width, IN UINTN Height) {
+   EG_IMAGE *NewImage = NULL;
+   UINTN x, y;
+
+   if (((StartX + Width) > Image->Width) || ((StartY + Height) > Image->Height))
+      return NULL;
+
+   NewImage = egCreateImage(Width, Height, Image->HasAlpha);
+   if (NewImage == NULL)
+      return NULL;
+
+   for (y = 0; y < Height; y++) {
+      for (x = 0; x < Width; x++) {
+         NewImage->PixelData[y * NewImage->Width + x] = Image->PixelData[(y + StartY) * Image->Width + x + StartX];
+      }
+   }
+   return NewImage;
+} // EG_IMAGE * egCropImage()
+
+// The following function implements a bilinear image scaling algorithm, based on
+// code presented at http://tech-algorithm.com/articles/bilinear-image-scaling/.
+// Resize an image; returns pointer to resized image if successful, NULL otherwise.
+// Calling function is responsible for freeing allocated memory.
+// NOTE: x_ratio, y_ratio, x_diff, and y_diff should really be float values;
+// however, I've found that my 32-bit Mac Mini has a buggy EFI (or buggy CPU?), which
+// causes this function to hang on float-to-UINT8 conversions on some (but not all!)
+// float values. Therefore, this function uses integer arithmetic but multiplies
+// all values by FP_MULTIPLIER to achieve something resembling the sort of precision
+// needed for good results.
+EG_IMAGE * egScaleImage(IN EG_IMAGE *Image, IN UINTN NewWidth, IN UINTN NewHeight) {
+   EG_IMAGE *NewImage = NULL;
+   EG_PIXEL a, b, c, d;
+   UINTN x, y, Index ;
+   UINTN i, j;
+   UINTN Offset = 0;
+   UINTN x_ratio, y_ratio, x_diff, y_diff;
+
+   if ((Image == NULL) || (Image->Height == 0) || (Image->Width == 0) || (NewWidth == 0) || (NewHeight == 0))
+      return NULL;
+
+   if ((Image->Width == NewWidth) && (Image->Height == NewHeight))
+      return (egCopyImage(Image));
+
+   NewImage = egCreateImage(NewWidth, NewHeight, Image->HasAlpha);
+   if (NewImage == NULL)
+      return NULL;
+
+   x_ratio = ((Image->Width - 1) * FP_MULTIPLIER) / NewWidth;
+   y_ratio = ((Image->Height - 1) * FP_MULTIPLIER) / NewHeight;
+
+   for (i = 0; i < NewHeight; i++) {
+      for (j = 0; j < NewWidth; j++) {
+         x = (j * (Image->Width - 1)) / NewWidth;
+         y = (i * (Image->Height - 1)) / NewHeight;
+         x_diff = (x_ratio * j) - x * FP_MULTIPLIER;
+         y_diff = (y_ratio * i) - y * FP_MULTIPLIER;
+         Index = ((y * Image->Width) + x);
+         a = Image->PixelData[Index];
+         b = Image->PixelData[Index + 1];
+         c = Image->PixelData[Index + Image->Width];
+         d = Image->PixelData[Index + Image->Width + 1];
+
+         // blue element
+         NewImage->PixelData[Offset].b = ((a.b) * (FP_MULTIPLIER - x_diff) * (FP_MULTIPLIER - y_diff) +
+                                          (b.b) * (x_diff) * (FP_MULTIPLIER - y_diff) +
+                                          (c.b) * (y_diff) * (FP_MULTIPLIER - x_diff) +
+                                          (d.b) * (x_diff * y_diff)) / (FP_MULTIPLIER * FP_MULTIPLIER);
+
+         // green element
+         NewImage->PixelData[Offset].g = ((a.g) * (FP_MULTIPLIER - x_diff) * (FP_MULTIPLIER - y_diff) +
+                                          (b.g) * (x_diff) * (FP_MULTIPLIER - y_diff) +
+                                          (c.g) * (y_diff) * (FP_MULTIPLIER - x_diff) +
+                                          (d.g) * (x_diff * y_diff)) / (FP_MULTIPLIER * FP_MULTIPLIER);
+
+         // red element
+         NewImage->PixelData[Offset].r = ((a.r) * (FP_MULTIPLIER - x_diff) * (FP_MULTIPLIER - y_diff) +
+                                          (b.r) * (x_diff) * (FP_MULTIPLIER - y_diff) +
+                                          (c.r) * (y_diff) * (FP_MULTIPLIER - x_diff) +
+                                          (d.r) * (x_diff * y_diff)) / (FP_MULTIPLIER * FP_MULTIPLIER);
+
+         // alpha element
+         NewImage->PixelData[Offset++].a = ((a.a) * (FP_MULTIPLIER - x_diff) * (FP_MULTIPLIER - y_diff) +
+                                            (b.a) * (x_diff) * (FP_MULTIPLIER - y_diff) +
+                                            (c.a) * (y_diff) * (FP_MULTIPLIER - x_diff) +
+                                            (d.a) * (x_diff * y_diff)) / (FP_MULTIPLIER * FP_MULTIPLIER);
+      } // for (j...)
+   } // for (i...)
+   return NewImage;
+} // EG_IMAGE * egScaleImage()
+
+VOID egFreeImage(IN EG_IMAGE *Image)
+{
+    if (Image != NULL) {
+        if (Image->PixelData != NULL)
+            FreePool(Image->PixelData);
+        FreePool(Image);
+    }
+}
+
+//
+// Basic file operations
+//
+
+EFI_STATUS egLoadFile(IN EFI_FILE *BaseDir, IN CHAR16 *FileName, OUT UINT8 **FileData, OUT UINTN *FileDataLength)
+{
+    EFI_STATUS          Status;
+    EFI_FILE_HANDLE     FileHandle;
+    EFI_FILE_INFO       *FileInfo;
+    UINT64              ReadSize;
+    UINTN               BufferSize;
+    UINT8               *Buffer;
+
+    if ((BaseDir == NULL) || (FileName == NULL))
+       return EFI_NOT_FOUND;
+
+    Status = refit_call5_wrapper(BaseDir->Open, BaseDir, &FileHandle, FileName, EFI_FILE_MODE_READ, 0);
+    if (EFI_ERROR(Status)) {
+        return Status;
+    }
+
+    FileInfo = LibFileInfo(FileHandle);
+    if (FileInfo == NULL) {
+        refit_call1_wrapper(FileHandle->Close, FileHandle);
+        return EFI_NOT_FOUND;
+    }
+    ReadSize = FileInfo->FileSize;
+    if (ReadSize > MAX_FILE_SIZE)
+        ReadSize = MAX_FILE_SIZE;
+    FreePool(FileInfo);
+
+    BufferSize = (UINTN)ReadSize;   // was limited to 1 GB above, so this is safe
+    Buffer = (UINT8 *) AllocatePool(BufferSize);
+    if (Buffer == NULL) {
+        refit_call1_wrapper(FileHandle->Close, FileHandle);
+        return EFI_OUT_OF_RESOURCES;
+    }
+
+    Status = refit_call3_wrapper(FileHandle->Read, FileHandle, &BufferSize, Buffer);
+    refit_call1_wrapper(FileHandle->Close, FileHandle);
+    if (EFI_ERROR(Status)) {
+        FreePool(Buffer);
+        return Status;
+    }
+
+    *FileData = Buffer;
+    *FileDataLength = BufferSize;
+    return EFI_SUCCESS;
+}
+
+static EFI_GUID ESPGuid = { 0xc12a7328, 0xf81f, 0x11d2, { 0xba, 0x4b, 0x00, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b } };
+
+EFI_STATUS egFindESP(OUT EFI_FILE_HANDLE *RootDir)
+{
+    EFI_STATUS          Status;
+    UINTN               HandleCount = 0;
+    EFI_HANDLE          *Handles;
+
+    Status = LibLocateHandle(ByProtocol, &ESPGuid, NULL, &HandleCount, &Handles);
+    if (!EFI_ERROR(Status) && HandleCount > 0) {
+        *RootDir = LibOpenRoot(Handles[0]);
+        if (*RootDir == NULL)
+            Status = EFI_NOT_FOUND;
+        FreePool(Handles);
+    }
+    return Status;
+}
+
+EFI_STATUS egSaveFile(IN EFI_FILE* BaseDir OPTIONAL, IN CHAR16 *FileName,
+                      IN UINT8 *FileData, IN UINTN FileDataLength)
+{
+    EFI_STATUS          Status;
+    EFI_FILE_HANDLE     FileHandle;
+    UINTN               BufferSize;
+
+    if (BaseDir == NULL) {
+        Status = egFindESP(&BaseDir);
+        if (EFI_ERROR(Status))
+            return Status;
+    }
+
+    Status = refit_call5_wrapper(BaseDir->Open, BaseDir, &FileHandle, FileName,
+                                 EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, 0);
+    if (EFI_ERROR(Status))
+        return Status;
+
+    BufferSize = FileDataLength;
+    Status = refit_call3_wrapper(FileHandle->Write, FileHandle, &BufferSize, FileData);
+    refit_call1_wrapper(FileHandle->Close, FileHandle);
+
+    return Status;
+}
+
+//
+// Loading images from files and embedded data
+//
+
+// Decode the specified image data. The IconSize parameter is relevant only
+// for ICNS, for which it selects which ICNS sub-image is decoded.
+// Returns a pointer to the resulting EG_IMAGE or NULL if decoding failed.
+static EG_IMAGE * egDecodeAny(IN UINT8 *FileData, IN UINTN FileDataLength, IN UINTN IconSize, IN BOOLEAN WantAlpha)
+{
+   EG_IMAGE        *NewImage = NULL;
+
+   NewImage = egDecodeICNS(FileData, FileDataLength, IconSize, WantAlpha);
+   if (NewImage == NULL)
+      NewImage = egDecodePNG(FileData, FileDataLength, IconSize, WantAlpha);
+   if (NewImage == NULL)
+      NewImage = egDecodeBMP(FileData, FileDataLength, IconSize, WantAlpha);
+
+   return NewImage;
+}
+
+EG_IMAGE * egLoadImage(IN EFI_FILE* BaseDir, IN CHAR16 *FileName, IN BOOLEAN WantAlpha)
+{
+    EFI_STATUS      Status;
+    UINT8           *FileData;
+    UINTN           FileDataLength;
+    EG_IMAGE        *NewImage;
+
+    if (BaseDir == NULL || FileName == NULL)
+        return NULL;
+
+    // load file
+    Status = egLoadFile(BaseDir, FileName, &FileData, &FileDataLength);
+    if (EFI_ERROR(Status))
+        return NULL;
+
+    // decode it
+    NewImage = egDecodeAny(FileData, FileDataLength, 128 /* arbitrary value */, WantAlpha);
+    FreePool(FileData);
+
+    return NewImage;
+}
+
+// Load an icon from (BaseDir)/Path, extracting the icon of size IconSize x IconSize.
+// Returns a pointer to the image data, or NULL if the icon could not be loaded.
+EG_IMAGE * egLoadIcon(IN EFI_FILE* BaseDir, IN CHAR16 *Path, IN UINTN IconSize)
+{
+    EFI_STATUS      Status;
+    UINT8           *FileData;
+    UINTN           FileDataLength;
+    EG_IMAGE        *Image, *NewImage;
+
+    if (BaseDir == NULL || Path == NULL)
+        return NULL;
+
+    // load file
+    Status = egLoadFile(BaseDir, Path, &FileData, &FileDataLength);
+    if (EFI_ERROR(Status))
+       return NULL;
+
+    // decode it
+    Image = egDecodeAny(FileData, FileDataLength, IconSize, TRUE);
+    FreePool(FileData);
+    if ((Image->Width != IconSize) || (Image->Height != IconSize)) {
+       NewImage = egScaleImage(Image, IconSize, IconSize);
+       if (!NewImage)
+          Print(L"Warning: Unable to scale icon of the wrong size from '%s'\n", Path);
+       egFreeImage(Image);
+       Image = NewImage;
+    }
+
+    return Image;
+} // EG_IMAGE *egLoadIcon()
+
+// Returns an icon of any type from the specified subdirectory using the specified
+// base name. All directory references are relative to BaseDir. For instance, if
+// SubdirName is "myicons" and BaseName is "os_linux", this function will return
+// an image based on "myicons/os_linux.icns" or "myicons/os_linux.png", in that
+// order of preference. Returns NULL if no such file is a valid icon file.
+EG_IMAGE * egLoadIconAnyType(IN EFI_FILE *BaseDir, IN CHAR16 *SubdirName, IN CHAR16 *BaseName, IN UINTN IconSize) {
+   EG_IMAGE *Image = NULL;
+   CHAR16 *Extension;
+   CHAR16 FileName[256];
+   UINTN i = 0;
+
+   while (((Extension = FindCommaDelimited(ICON_EXTENSIONS, i++)) != NULL) && (Image == NULL)) {
+      SPrint(FileName, 255, L"%s\\%s.%s", SubdirName, BaseName, Extension);
+      Image = egLoadIcon(BaseDir, FileName, IconSize);
+      MyFreePool(Extension);
+   } // while()
+
+   return Image;
+} // EG_IMAGE *egLoadIconAnyType()
+
+// Returns an icon with any extension in ICON_EXTENSIONS from either the directory
+// specified by GlobalConfig.IconsDir or DEFAULT_ICONS_DIR. The input BaseName
+// should be the icon name without an extension. For instance, if BaseName is
+// os_linux, GlobalConfig.IconsDir is myicons, DEFAULT_ICONS_DIR is icons, and
+// ICON_EXTENSIONS is "icns,png", this function will return myicons/os_linux.icns,
+// myicons/os_linux.png, icons/os_linux.icns, or icons/os_linux.png, in that
+// order of preference. Returns NULL if no such icon can be found. All file
+// references are relative to SelfDir.
+EG_IMAGE * egFindIcon(IN CHAR16 *BaseName, IN UINTN IconSize) {
+   EG_IMAGE *Image = NULL;
+
+   if (GlobalConfig.IconsDir != NULL) {
+      Image = egLoadIconAnyType(SelfDir, GlobalConfig.IconsDir, BaseName, IconSize);
+   }
+
+   if (Image == NULL) {
+      Image = egLoadIconAnyType(SelfDir, DEFAULT_ICONS_DIR, BaseName, IconSize);
+   }
+
+   return Image;
+} // EG_IMAGE * egFindIcon()
+
+EG_IMAGE * egPrepareEmbeddedImage(IN EG_EMBEDDED_IMAGE *EmbeddedImage, IN BOOLEAN WantAlpha)
+{
+    EG_IMAGE            *NewImage;
+    UINT8               *CompData;
+    UINTN               CompLen;
+    UINTN               PixelCount;
+
+    // sanity check
+    if (EmbeddedImage->PixelMode > EG_MAX_EIPIXELMODE ||
+        (EmbeddedImage->CompressMode != EG_EICOMPMODE_NONE && EmbeddedImage->CompressMode != EG_EICOMPMODE_RLE))
+        return NULL;
+
+    // allocate image structure and pixel buffer
+    NewImage = egCreateImage(EmbeddedImage->Width, EmbeddedImage->Height, WantAlpha);
+    if (NewImage == NULL)
+        return NULL;
+
+    CompData = (UINT8 *)EmbeddedImage->Data;   // drop const
+    CompLen  = EmbeddedImage->DataLength;
+    PixelCount = EmbeddedImage->Width * EmbeddedImage->Height;
+
+    // FUTURE: for EG_EICOMPMODE_EFICOMPRESS, decompress whole data block here
+
+    if (EmbeddedImage->PixelMode == EG_EIPIXELMODE_GRAY ||
+        EmbeddedImage->PixelMode == EG_EIPIXELMODE_GRAY_ALPHA) {
+
+        // copy grayscale plane and expand
+        if (EmbeddedImage->CompressMode == EG_EICOMPMODE_RLE) {
+            egDecompressIcnsRLE(&CompData, &CompLen, PLPTR(NewImage, r), PixelCount);
+        } else {
+            egInsertPlane(CompData, PLPTR(NewImage, r), PixelCount);
+            CompData += PixelCount;
+        }
+        egCopyPlane(PLPTR(NewImage, r), PLPTR(NewImage, g), PixelCount);
+        egCopyPlane(PLPTR(NewImage, r), PLPTR(NewImage, b), PixelCount);
+
+    } else if (EmbeddedImage->PixelMode == EG_EIPIXELMODE_COLOR ||
+               EmbeddedImage->PixelMode == EG_EIPIXELMODE_COLOR_ALPHA) {
+
+        // copy color planes
+        if (EmbeddedImage->CompressMode == EG_EICOMPMODE_RLE) {
+            egDecompressIcnsRLE(&CompData, &CompLen, PLPTR(NewImage, r), PixelCount);
+            egDecompressIcnsRLE(&CompData, &CompLen, PLPTR(NewImage, g), PixelCount);
+            egDecompressIcnsRLE(&CompData, &CompLen, PLPTR(NewImage, b), PixelCount);
+        } else {
+            egInsertPlane(CompData, PLPTR(NewImage, r), PixelCount);
+            CompData += PixelCount;
+            egInsertPlane(CompData, PLPTR(NewImage, g), PixelCount);
+            CompData += PixelCount;
+            egInsertPlane(CompData, PLPTR(NewImage, b), PixelCount);
+            CompData += PixelCount;
+        }
+
+    } else {
+
+        // set color planes to black
+        egSetPlane(PLPTR(NewImage, r), 0, PixelCount);
+        egSetPlane(PLPTR(NewImage, g), 0, PixelCount);
+        egSetPlane(PLPTR(NewImage, b), 0, PixelCount);
+
+    }
+
+    if (WantAlpha && (EmbeddedImage->PixelMode == EG_EIPIXELMODE_GRAY_ALPHA ||
+                      EmbeddedImage->PixelMode == EG_EIPIXELMODE_COLOR_ALPHA ||
+                      EmbeddedImage->PixelMode == EG_EIPIXELMODE_ALPHA)) {
+
+        // copy alpha plane
+        if (EmbeddedImage->CompressMode == EG_EICOMPMODE_RLE) {
+            egDecompressIcnsRLE(&CompData, &CompLen, PLPTR(NewImage, a), PixelCount);
+        } else {
+            egInsertPlane(CompData, PLPTR(NewImage, a), PixelCount);
+            CompData += PixelCount;
+        }
+
+    } else {
+        egSetPlane(PLPTR(NewImage, a), WantAlpha ? 255 : 0, PixelCount);
+    }
+
+    return NewImage;
+}
+
+//
+// Compositing
+//
+
+VOID egRestrictImageArea(IN EG_IMAGE *Image,
+                         IN UINTN AreaPosX, IN UINTN AreaPosY,
+                         IN OUT UINTN *AreaWidth, IN OUT UINTN *AreaHeight)
+{
+    if (AreaPosX >= Image->Width || AreaPosY >= Image->Height) {
+        // out of bounds, operation has no effect
+        *AreaWidth  = 0;
+        *AreaHeight = 0;
+    } else {
+        // calculate affected area
+        if (*AreaWidth > Image->Width - AreaPosX)
+            *AreaWidth = Image->Width - AreaPosX;
+        if (*AreaHeight > Image->Height - AreaPosY)
+            *AreaHeight = Image->Height - AreaPosY;
+    }
+}
+
+VOID egFillImage(IN OUT EG_IMAGE *CompImage, IN EG_PIXEL *Color)
+{
+    UINTN       i;
+    EG_PIXEL    FillColor;
+    EG_PIXEL    *PixelPtr;
+
+    FillColor = *Color;
+    if (!CompImage->HasAlpha)
+        FillColor.a = 0;
+
+    PixelPtr = CompImage->PixelData;
+    for (i = 0; i < CompImage->Width * CompImage->Height; i++, PixelPtr++)
+        *PixelPtr = FillColor;
+}
+
+VOID egFillImageArea(IN OUT EG_IMAGE *CompImage,
+                     IN UINTN AreaPosX, IN UINTN AreaPosY,
+                     IN UINTN AreaWidth, IN UINTN AreaHeight,
+                     IN EG_PIXEL *Color)
+{
+    UINTN       x, y;
+    EG_PIXEL    FillColor;
+    EG_PIXEL    *PixelPtr;
+    EG_PIXEL    *PixelBasePtr;
+
+    egRestrictImageArea(CompImage, AreaPosX, AreaPosY, &AreaWidth, &AreaHeight);
+
+    if (AreaWidth > 0) {
+        FillColor = *Color;
+        if (!CompImage->HasAlpha)
+            FillColor.a = 0;
+
+        PixelBasePtr = CompImage->PixelData + AreaPosY * CompImage->Width + AreaPosX;
+        for (y = 0; y < AreaHeight; y++) {
+            PixelPtr = PixelBasePtr;
+            for (x = 0; x < AreaWidth; x++, PixelPtr++)
+                *PixelPtr = FillColor;
+            PixelBasePtr += CompImage->Width;
+        }
+    }
+}
+
+VOID egRawCopy(IN OUT EG_PIXEL *CompBasePtr, IN EG_PIXEL *TopBasePtr,
+               IN UINTN Width, IN UINTN Height,
+               IN UINTN CompLineOffset, IN UINTN TopLineOffset)
+{
+    UINTN       x, y;
+    EG_PIXEL    *TopPtr, *CompPtr;
+
+    for (y = 0; y < Height; y++) {
+        TopPtr = TopBasePtr;
+        CompPtr = CompBasePtr;
+        for (x = 0; x < Width; x++) {
+            *CompPtr = *TopPtr;
+            TopPtr++, CompPtr++;
+        }
+        TopBasePtr += TopLineOffset;
+        CompBasePtr += CompLineOffset;
+    }
+}
+
+VOID egRawCompose(IN OUT EG_PIXEL *CompBasePtr, IN EG_PIXEL *TopBasePtr,
+                  IN UINTN Width, IN UINTN Height,
+                  IN UINTN CompLineOffset, IN UINTN TopLineOffset)
+{
+    UINTN       x, y;
+    EG_PIXEL    *TopPtr, *CompPtr;
+    UINTN       Alpha;
+    UINTN       RevAlpha;
+    UINTN       Temp;
+
+    for (y = 0; y < Height; y++) {
+        TopPtr = TopBasePtr;
+        CompPtr = CompBasePtr;
+        for (x = 0; x < Width; x++) {
+            Alpha = TopPtr->a;
+            RevAlpha = 255 - Alpha;
+            Temp = (UINTN)CompPtr->b * RevAlpha + (UINTN)TopPtr->b * Alpha + 0x80;
+            CompPtr->b = (Temp + (Temp >> 8)) >> 8;
+            Temp = (UINTN)CompPtr->g * RevAlpha + (UINTN)TopPtr->g * Alpha + 0x80;
+            CompPtr->g = (Temp + (Temp >> 8)) >> 8;
+            Temp = (UINTN)CompPtr->r * RevAlpha + (UINTN)TopPtr->r * Alpha + 0x80;
+            CompPtr->r = (Temp + (Temp >> 8)) >> 8;
+            /*
+            CompPtr->b = ((UINTN)CompPtr->b * RevAlpha + (UINTN)TopPtr->b * Alpha) / 255;
+            CompPtr->g = ((UINTN)CompPtr->g * RevAlpha + (UINTN)TopPtr->g * Alpha) / 255;
+            CompPtr->r = ((UINTN)CompPtr->r * RevAlpha + (UINTN)TopPtr->r * Alpha) / 255;
+            */
+            TopPtr++, CompPtr++;
+        }
+        TopBasePtr += TopLineOffset;
+        CompBasePtr += CompLineOffset;
+    }
+}
+
+VOID egComposeImage(IN OUT EG_IMAGE *CompImage, IN EG_IMAGE *TopImage, IN UINTN PosX, IN UINTN PosY)
+{
+    UINTN       CompWidth, CompHeight;
+
+    CompWidth  = TopImage->Width;
+    CompHeight = TopImage->Height;
+    egRestrictImageArea(CompImage, PosX, PosY, &CompWidth, &CompHeight);
+
+    // compose
+    if (CompWidth > 0) {
+        if (TopImage->HasAlpha) {
+            egRawCompose(CompImage->PixelData + PosY * CompImage->Width + PosX, TopImage->PixelData,
+                         CompWidth, CompHeight, CompImage->Width, TopImage->Width);
+        } else {
+            egRawCopy(CompImage->PixelData + PosY * CompImage->Width + PosX, TopImage->PixelData,
+                      CompWidth, CompHeight, CompImage->Width, TopImage->Width);
+        }
+    }
+} /* VOID egComposeImage() */
+
+//
+// misc internal functions
+//
+
+VOID egInsertPlane(IN UINT8 *SrcDataPtr, IN UINT8 *DestPlanePtr, IN UINTN PixelCount)
+{
+    UINTN i;
+
+    for (i = 0; i < PixelCount; i++) {
+        *DestPlanePtr = *SrcDataPtr++;
+        DestPlanePtr += 4;
+    }
+}
+
+VOID egSetPlane(IN UINT8 *DestPlanePtr, IN UINT8 Value, IN UINTN PixelCount)
+{
+    UINTN i;
+
+    for (i = 0; i < PixelCount; i++) {
+        *DestPlanePtr = Value;
+        DestPlanePtr += 4;
+    }
+}
+
+VOID egCopyPlane(IN UINT8 *SrcPlanePtr, IN UINT8 *DestPlanePtr, IN UINTN PixelCount)
+{
+    UINTN i;
+
+    for (i = 0; i < PixelCount; i++) {
+        *DestPlanePtr = *SrcPlanePtr;
+        DestPlanePtr += 4, SrcPlanePtr += 4;
+    }
+}
+
+/* EOF */
diff --git a/libeg/libeg.h b/libeg/libeg.h
new file mode 100644 (file)
index 0000000..5f55422
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * libeg/libeg.h
+ * EFI graphics library header for users
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __LIBEG_LIBEG_H__
+#define __LIBEG_LIBEG_H__
+
+#ifndef __MAKEWITH_GNUEFI
+#include "../include/tiano_includes.h"
+#endif
+
+/* types */
+
+typedef enum ColorTypes {
+   white,
+   black
+} Colors;
+
+/* This should be compatible with EFI_UGA_PIXEL */
+typedef struct {
+    UINT8 b, g, r, a;
+} EG_PIXEL;
+
+typedef struct {
+    UINTN       Width;
+    UINTN       Height;
+    BOOLEAN     HasAlpha;
+    EG_PIXEL    *PixelData;
+} EG_IMAGE;
+
+#define EG_EIPIXELMODE_GRAY         (0)
+#define EG_EIPIXELMODE_GRAY_ALPHA   (1)
+#define EG_EIPIXELMODE_COLOR        (2)
+#define EG_EIPIXELMODE_COLOR_ALPHA  (3)
+#define EG_EIPIXELMODE_ALPHA        (4)
+#define EG_MAX_EIPIXELMODE          EG_EIPIXELMODE_ALPHA
+
+#define EG_EICOMPMODE_NONE          (0)
+#define EG_EICOMPMODE_RLE           (1)
+#define EG_EICOMPMODE_EFICOMPRESS   (2)
+
+#define ICON_EXTENSIONS L"png,icns"
+
+typedef struct {
+    UINTN       Width;
+    UINTN       Height;
+    UINTN       PixelMode;
+    UINTN       CompressMode;
+    const UINT8 *Data;
+    UINTN       DataLength;
+} EG_EMBEDDED_IMAGE;
+
+/* functions */
+
+VOID egInitScreen(VOID);
+BOOLEAN egGetResFromMode(UINTN *ModeWidth, UINTN *Height);
+VOID egGetScreenSize(OUT UINTN *ScreenWidth, OUT UINTN *ScreenHeight);
+CHAR16 * egScreenDescription(VOID);
+BOOLEAN egHasGraphicsMode(VOID);
+BOOLEAN egIsGraphicsModeEnabled(VOID);
+VOID egSetGraphicsModeEnabled(IN BOOLEAN Enable);
+// NOTE: Even when egHasGraphicsMode() returns FALSE, you should
+//  call egSetGraphicsModeEnabled(FALSE) to ensure the system
+//  is running in text mode. egHasGraphicsMode() only determines
+//  if libeg can draw to the screen in graphics mode.
+
+EG_IMAGE * egCreateImage(IN UINTN Width, IN UINTN Height, IN BOOLEAN HasAlpha);
+EG_IMAGE * egCreateFilledImage(IN UINTN Width, IN UINTN Height, IN BOOLEAN HasAlpha, IN EG_PIXEL *Color);
+EG_IMAGE * egCopyImage(IN EG_IMAGE *Image);
+EG_IMAGE * egCropImage(IN EG_IMAGE *Image, IN UINTN StartX, IN UINTN StartY, IN UINTN Width, IN UINTN Height);
+EG_IMAGE * egScaleImage(EG_IMAGE *Image, UINTN NewWidth, UINTN NewHeight);
+VOID egFreeImage(IN EG_IMAGE *Image);
+
+EG_IMAGE * egLoadImage(IN EFI_FILE* BaseDir, IN CHAR16 *FileName, IN BOOLEAN WantAlpha);
+EG_IMAGE * egLoadIcon(IN EFI_FILE* BaseDir, IN CHAR16 *FileName, IN UINTN IconSize);
+EG_IMAGE * egLoadIconAnyType(IN EFI_FILE *BaseDir, IN CHAR16 *SubdirName, IN CHAR16 *BaseName, IN UINTN IconSize);
+EG_IMAGE * egFindIcon(IN CHAR16 *BaseName, IN UINTN IconSize);
+EG_IMAGE * egPrepareEmbeddedImage(IN EG_EMBEDDED_IMAGE *EmbeddedImage, IN BOOLEAN WantAlpha);
+
+EG_IMAGE * egEnsureImageSize(IN EG_IMAGE *Image, IN UINTN Width, IN UINTN Height, IN EG_PIXEL *Color);
+
+EFI_STATUS egLoadFile(IN EFI_FILE* BaseDir, IN CHAR16 *FileName,
+                      OUT UINT8 **FileData, OUT UINTN *FileDataLength);
+EFI_STATUS egFindESP(OUT EFI_FILE_HANDLE *RootDir);
+EFI_STATUS egSaveFile(IN EFI_FILE* BaseDir OPTIONAL, IN CHAR16 *FileName,
+                      IN UINT8 *FileData, IN UINTN FileDataLength);
+
+VOID egFillImage(IN OUT EG_IMAGE *CompImage, IN EG_PIXEL *Color);
+VOID egFillImageArea(IN OUT EG_IMAGE *CompImage,
+                     IN UINTN AreaPosX, IN UINTN AreaPosY,
+                     IN UINTN AreaWidth, IN UINTN AreaHeight,
+                     IN EG_PIXEL *Color);
+VOID egComposeImage(IN OUT EG_IMAGE *CompImage, IN EG_IMAGE *TopImage, IN UINTN PosX, IN UINTN PosY);
+
+UINTN egGetFontHeight(VOID);
+UINTN egGetFontCellWidth(VOID);
+UINTN egComputeTextWidth(IN CHAR16 *Text);
+VOID egMeasureText(IN CHAR16 *Text, OUT UINTN *Width, OUT UINTN *Height);
+VOID egRenderText(IN CHAR16 *Text, IN OUT EG_IMAGE *CompImage, IN UINTN PosX, IN UINTN PosY, IN UINT8 BGBrightness);
+VOID egLoadFont(IN CHAR16 *Filename);
+
+VOID egClearScreen(IN EG_PIXEL *Color);
+VOID egDrawImage(IN EG_IMAGE *Image, IN UINTN ScreenPosX, IN UINTN ScreenPosY);
+VOID egDrawImageWithTransparency(EG_IMAGE *Image, EG_IMAGE *BadgeImage, UINTN XPos, UINTN YPos, UINTN Width, UINTN Height);
+VOID egDrawImageArea(IN EG_IMAGE *Image,
+                     IN UINTN AreaPosX, IN UINTN AreaPosY,
+                     IN UINTN AreaWidth, IN UINTN AreaHeight,
+                     IN UINTN ScreenPosX, IN UINTN ScreenPosY);
+VOID egDisplayMessage(IN CHAR16 *Text, EG_PIXEL *BGColor);
+EG_IMAGE * egCopyScreen(VOID);
+VOID egScreenShot(VOID);
+BOOLEAN egSetTextMode(UINT32 RequestedMode);
+
+EG_IMAGE * egDecodePNG(IN UINT8 *FileData, IN UINTN FileDataLength, IN UINTN IconSize, IN BOOLEAN WantAlpha);
+
+#endif /* __LIBEG_LIBEG_H__ */
+
+/* EOF */
diff --git a/libeg/libegint.h b/libeg/libegint.h
new file mode 100644 (file)
index 0000000..400a65c
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * libeg/libegint.h
+ * EFI graphics library internal header
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __LIBEG_LIBEGINT_H__
+#define __LIBEG_LIBEGINT_H__
+
+#ifdef __MAKEWITH_GNUEFI
+#include <efi.h>
+#include <efilib.h>
+#else
+#include "../include/tiano_includes.h"
+#endif
+
+#include "libeg.h"
+
+/* types */
+
+typedef EG_IMAGE * (*EG_DECODE_FUNC)(IN UINT8 *FileData, IN UINTN FileDataLength, IN UINTN IconSize, IN BOOLEAN WantAlpha);
+
+/* functions */
+
+BOOLEAN egSetScreenSize(IN OUT UINTN *ScreenWidth, IN OUT UINTN *ScreenHeight);
+
+VOID egRestrictImageArea(IN EG_IMAGE *Image,
+                         IN UINTN AreaPosX, IN UINTN AreaPosY,
+                         IN OUT UINTN *AreaWidth, IN OUT UINTN *AreaHeight);
+VOID egRawCopy(IN OUT EG_PIXEL *CompBasePtr, IN EG_PIXEL *TopBasePtr,
+               IN UINTN Width, IN UINTN Height,
+               IN UINTN CompLineOffset, IN UINTN TopLineOffset);
+VOID egRawCompose(IN OUT EG_PIXEL *CompBasePtr, IN EG_PIXEL *TopBasePtr,
+                  IN UINTN Width, IN UINTN Height,
+                  IN UINTN CompLineOffset, IN UINTN TopLineOffset);
+
+#define PLPTR(imagevar, colorname) ((UINT8 *) &((imagevar)->PixelData->colorname))
+
+VOID egDecompressIcnsRLE(IN OUT UINT8 **CompData, IN OUT UINTN *CompLen, IN UINT8 *DestPlanePtr, IN UINTN PixelCount);
+VOID egInsertPlane(IN UINT8 *SrcDataPtr, IN UINT8 *DestPlanePtr, IN UINTN PixelCount);
+VOID egSetPlane(IN UINT8 *DestPlanePtr, IN UINT8 Value, IN UINTN PixelCount);
+VOID egCopyPlane(IN UINT8 *SrcPlanePtr, IN UINT8 *DestPlanePtr, IN UINTN PixelCount);
+
+EG_IMAGE * egDecodeBMP(IN UINT8 *FileData, IN UINTN FileDataLength, IN UINTN IconSize, IN BOOLEAN WantAlpha);
+EG_IMAGE * egDecodeICNS(IN UINT8 *FileData, IN UINTN FileDataLength, IN UINTN IconSize, IN BOOLEAN WantAlpha);
+
+VOID egEncodeBMP(IN EG_IMAGE *Image, OUT UINT8 **FileData, OUT UINTN *FileDataLength);
+
+
+#endif /* __LIBEG_LIBEGINT_H__ */
+
+/* EOF */
diff --git a/libeg/load_bmp.c b/libeg/load_bmp.c
new file mode 100644 (file)
index 0000000..a836e6e
--- /dev/null
@@ -0,0 +1,267 @@
+/*
+ * libeg/load_bmp.c
+ * Loading function for BMP images
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "libegint.h"
+
+// BMP structures
+
+#ifdef __MAKEWITH_GNUEFI
+#pragma pack(1)
+
+typedef struct {
+    UINT8   Blue;
+    UINT8   Green;
+    UINT8   Red;
+    UINT8   Reserved;
+} BMP_COLOR_MAP;
+
+typedef struct {
+    CHAR8         CharB;
+    CHAR8         CharM;
+    UINT32        Size;
+    UINT16        Reserved[2];
+    UINT32        ImageOffset;
+    UINT32        HeaderSize;
+    UINT32        PixelWidth;
+    UINT32        PixelHeight;
+    UINT16        Planes;       // Must be 1
+    UINT16        BitPerPixel;  // 1, 4, 8, or 24
+    UINT32        CompressionType;
+    UINT32        ImageSize;    // Compressed image size in bytes
+    UINT32        XPixelsPerMeter;
+    UINT32        YPixelsPerMeter;
+    UINT32        NumberOfColors;
+    UINT32        ImportantColors;
+} BMP_IMAGE_HEADER;
+
+#pragma pack()
+#endif
+
+//
+// Load BMP image
+//
+
+EG_IMAGE * egDecodeBMP(IN UINT8 *FileData, IN UINTN FileDataLength, IN UINTN IconSize, IN BOOLEAN WantAlpha)
+{
+    EG_IMAGE            *NewImage;
+    BMP_IMAGE_HEADER    *BmpHeader;
+    BMP_COLOR_MAP       *BmpColorMap;
+    UINTN               x, y;
+    UINT8               *ImagePtr;
+    UINT8               *ImagePtrBase;
+    UINTN               ImageLineOffset;
+    UINT8               ImageValue = 0, AlphaValue;
+    EG_PIXEL            *PixelPtr;
+    UINTN               Index, BitIndex;
+
+    // read and check header
+    if (FileDataLength < sizeof(BMP_IMAGE_HEADER) || FileData == NULL)
+        return NULL;
+    BmpHeader = (BMP_IMAGE_HEADER *) FileData;
+    if (BmpHeader->CharB != 'B' || BmpHeader->CharM != 'M')
+        return NULL;
+    if (BmpHeader->CompressionType != 0)
+        return NULL;
+    if (BmpHeader->BitPerPixel != 1 && BmpHeader->BitPerPixel != 4 &&
+        BmpHeader->BitPerPixel != 8 && BmpHeader->BitPerPixel != 24)
+        return NULL;
+
+    // calculate parameters
+    ImageLineOffset = BmpHeader->PixelWidth;
+    if (BmpHeader->BitPerPixel == 24)
+        ImageLineOffset *= 3;
+    else if (BmpHeader->BitPerPixel == 1)
+        ImageLineOffset = (ImageLineOffset + 7) >> 3;
+    else if (BmpHeader->BitPerPixel == 4)
+        ImageLineOffset = (ImageLineOffset + 1) >> 1;
+    if ((ImageLineOffset % 4) != 0)
+        ImageLineOffset = ImageLineOffset + (4 - (ImageLineOffset % 4));
+    // check bounds
+    if (BmpHeader->ImageOffset + ImageLineOffset * BmpHeader->PixelHeight > FileDataLength)
+        return NULL;
+
+    // allocate image structure and buffer
+    NewImage = egCreateImage(BmpHeader->PixelWidth, BmpHeader->PixelHeight, WantAlpha);
+    if (NewImage == NULL)
+        return NULL;
+    AlphaValue = WantAlpha ? 255 : 0;
+
+    // convert image
+    BmpColorMap = (BMP_COLOR_MAP *)(FileData + sizeof(BMP_IMAGE_HEADER));
+    ImagePtrBase = FileData + BmpHeader->ImageOffset;
+    for (y = 0; y < BmpHeader->PixelHeight; y++) {
+        ImagePtr = ImagePtrBase;
+        ImagePtrBase += ImageLineOffset;
+        PixelPtr = NewImage->PixelData + (BmpHeader->PixelHeight - 1 - y) * BmpHeader->PixelWidth;
+        
+        switch (BmpHeader->BitPerPixel) {
+            
+            case 1:
+                for (x = 0; x < BmpHeader->PixelWidth; x++) {
+                    BitIndex = x & 0x07;
+                    if (BitIndex == 0)
+                        ImageValue = *ImagePtr++;
+                    
+                    Index = (ImageValue >> (7 - BitIndex)) & 0x01;
+                    PixelPtr->b = BmpColorMap[Index].Blue;
+                    PixelPtr->g = BmpColorMap[Index].Green;
+                    PixelPtr->r = BmpColorMap[Index].Red;
+                    PixelPtr->a = AlphaValue;
+                    PixelPtr++;
+                }
+                break;
+            
+            case 4:
+                for (x = 0; x <= BmpHeader->PixelWidth - 2; x += 2) {
+                    ImageValue = *ImagePtr++;
+                    
+                    Index = ImageValue >> 4;
+                    PixelPtr->b = BmpColorMap[Index].Blue;
+                    PixelPtr->g = BmpColorMap[Index].Green;
+                    PixelPtr->r = BmpColorMap[Index].Red;
+                    PixelPtr->a = AlphaValue;
+                    PixelPtr++;
+                    
+                    Index = ImageValue & 0x0f;
+                    PixelPtr->b = BmpColorMap[Index].Blue;
+                    PixelPtr->g = BmpColorMap[Index].Green;
+                    PixelPtr->r = BmpColorMap[Index].Red;
+                    PixelPtr->a = AlphaValue;
+                    PixelPtr++;
+                }
+                if (x < BmpHeader->PixelWidth) {
+                    ImageValue = *ImagePtr++;
+                    
+                    Index = ImageValue >> 4;
+                    PixelPtr->b = BmpColorMap[Index].Blue;
+                    PixelPtr->g = BmpColorMap[Index].Green;
+                    PixelPtr->r = BmpColorMap[Index].Red;
+                    PixelPtr->a = AlphaValue;
+                    PixelPtr++;
+                }
+                break;
+            
+            case 8:
+                for (x = 0; x < BmpHeader->PixelWidth; x++) {
+                    Index = *ImagePtr++;
+                    PixelPtr->b = BmpColorMap[Index].Blue;
+                    PixelPtr->g = BmpColorMap[Index].Green;
+                    PixelPtr->r = BmpColorMap[Index].Red;
+                    PixelPtr->a = AlphaValue;
+                    PixelPtr++;
+                }
+                break;
+            
+            case 24:
+                for (x = 0; x < BmpHeader->PixelWidth; x++) {
+                    PixelPtr->b = *ImagePtr++;
+                    PixelPtr->g = *ImagePtr++;
+                    PixelPtr->r = *ImagePtr++;
+                    PixelPtr->a = AlphaValue;
+                    PixelPtr++;
+                }
+                break;
+            
+        }
+    }
+    
+    return NewImage;
+}
+
+//
+// Save BMP image
+//
+
+VOID egEncodeBMP(IN EG_IMAGE *Image, OUT UINT8 **FileDataReturn, OUT UINTN *FileDataLengthReturn)
+{
+    BMP_IMAGE_HEADER    *BmpHeader;
+    UINT8               *FileData;
+    UINTN               FileDataLength;
+    UINT8               *ImagePtr;
+    UINT8               *ImagePtrBase;
+    UINTN               ImageLineOffset;
+    EG_PIXEL            *PixelPtr;
+    UINTN               x, y;
+    
+    ImageLineOffset = Image->Width * 3;
+    if ((ImageLineOffset % 4) != 0)
+        ImageLineOffset = ImageLineOffset + (4 - (ImageLineOffset % 4));
+    
+    // allocate buffer for file data
+    FileDataLength = sizeof(BMP_IMAGE_HEADER) + Image->Height * ImageLineOffset;
+    FileData = AllocateZeroPool(FileDataLength);
+    if (FileData == NULL) {
+        Print(L"Error allocate %d bytes\n", FileDataLength);
+        *FileDataReturn = NULL;
+        *FileDataLengthReturn = 0;
+        return;
+    }
+    
+    // fill header
+    BmpHeader = (BMP_IMAGE_HEADER *)FileData;
+    BmpHeader->CharB = 'B';
+    BmpHeader->CharM = 'M';
+    BmpHeader->Size = FileDataLength;
+    BmpHeader->ImageOffset = sizeof(BMP_IMAGE_HEADER);
+    BmpHeader->HeaderSize = 40;
+    BmpHeader->PixelWidth = Image->Width;
+    BmpHeader->PixelHeight = Image->Height;
+    BmpHeader->Planes = 1;
+    BmpHeader->BitPerPixel = 24;
+    BmpHeader->CompressionType = 0;
+    BmpHeader->XPixelsPerMeter = 0xb13;
+    BmpHeader->YPixelsPerMeter = 0xb13;
+    
+    // fill pixel buffer
+    ImagePtrBase = FileData + BmpHeader->ImageOffset;
+    for (y = 0; y < Image->Height; y++) {
+        ImagePtr = ImagePtrBase;
+        ImagePtrBase += ImageLineOffset;
+        PixelPtr = Image->PixelData + (Image->Height - 1 - y) * Image->Width;
+        
+        for (x = 0; x < Image->Width; x++) {
+            *ImagePtr++ = PixelPtr->b;
+            *ImagePtr++ = PixelPtr->g;
+            *ImagePtr++ = PixelPtr->r;
+            PixelPtr++;
+        }
+    }
+    
+    *FileDataReturn = FileData;
+    *FileDataLengthReturn = FileDataLength;
+}
+
+/* EOF */
diff --git a/libeg/load_icns.c b/libeg/load_icns.c
new file mode 100644 (file)
index 0000000..41fca77
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * libeg/load_icns.c
+ * Loading function for .icns Apple icon images
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "libegint.h"
+
+#define MAX_ICNS_SIZES 4
+
+//
+// Decompress .icns RLE data
+//
+
+VOID egDecompressIcnsRLE(IN OUT UINT8 **CompData, IN OUT UINTN *CompLen, IN UINT8 *PixelData, IN UINTN PixelCount)
+{
+    UINT8 *cp;
+    UINT8 *cp_end;
+    UINT8 *pp;
+    UINTN pp_left;
+    UINTN len, i;
+    UINT8 value;
+
+    // setup variables
+    cp = *CompData;
+    cp_end = cp + *CompLen;
+    pp = PixelData;
+    pp_left = PixelCount;
+
+    // decode
+    while (cp + 1 < cp_end && pp_left > 0) {
+        len = *cp++;
+        if (len & 0x80) {   // compressed data: repeat next byte
+            len -= 125;
+            if (len > pp_left)
+                break;
+            value = *cp++;
+            for (i = 0; i < len; i++) {
+                *pp = value;
+                pp += 4;
+            }
+        } else {            // uncompressed data: copy bytes
+            len++;
+            if (len > pp_left || cp + len > cp_end)
+                break;
+            for (i = 0; i < len; i++) {
+                *pp = *cp++;
+                pp += 4;
+            }
+        }
+        pp_left -= len;
+    }
+
+    if (pp_left > 0) {
+        Print(L" egDecompressIcnsRLE: still need %d bytes of pixel data\n", pp_left);
+    }
+
+    // record what's left of the compressed data stream
+    *CompData = cp;
+    *CompLen = (UINTN)(cp_end - cp);
+}
+
+//
+// Load Apple .icns icons
+//
+
+EG_IMAGE * egDecodeICNS(IN UINT8 *FileData, IN UINTN FileDataLength, IN UINTN IconSize, IN BOOLEAN WantAlpha)
+{
+    EG_IMAGE            *NewImage;
+    UINT8               *Ptr, *BufferEnd, *DataPtr, *MaskPtr;
+    UINT32              BlockLen, DataLen, MaskLen;
+    UINTN               PixelCount, i;
+    UINT8               *CompData;
+    UINTN               CompLen;
+    UINT8               *SrcPtr;
+    EG_PIXEL            *DestPtr;
+    UINTN               SizesToTry[MAX_ICNS_SIZES + 1] = {IconSize, 128, 48, 32, 16};
+    UINTN               SizeToTry = 0;
+
+    if (FileDataLength < 8 || FileData == NULL ||
+        FileData[0] != 'i' || FileData[1] != 'c' || FileData[2] != 'n' || FileData[3] != 's') {
+        // not an icns file...
+        return NULL;
+    }
+
+    for (;;) {
+        DataPtr = NULL;
+        DataLen = 0;
+        MaskPtr = NULL;
+        MaskLen = 0;
+
+        do {
+           IconSize = SizesToTry[SizeToTry];
+           Ptr = FileData + 8;
+           BufferEnd = FileData + FileDataLength;
+           // iterate over tagged blocks in the file
+           while (Ptr + 8 <= BufferEnd) {
+               BlockLen = ((UINT32)Ptr[4] << 24) + ((UINT32)Ptr[5] << 16) + ((UINT32)Ptr[6] << 8) + (UINT32)Ptr[7];
+               if (Ptr + BlockLen > BufferEnd)   // block continues beyond end of file
+                   break;
+
+               // extract the appropriate blocks for each pixel size
+               if (IconSize == 128) {
+                   if (Ptr[0] == 'i' && Ptr[1] == 't' && Ptr[2] == '3' && Ptr[3] == '2') {
+                       if (Ptr[8] == 0 && Ptr[9] == 0 && Ptr[10] == 0 && Ptr[11] == 0) {
+                           DataPtr = Ptr + 12;
+                           DataLen = BlockLen - 12;
+                       }
+                   } else if (Ptr[0] == 't' && Ptr[1] == '8' && Ptr[2] == 'm' && Ptr[3] == 'k') {
+                       MaskPtr = Ptr + 8;
+                       MaskLen = BlockLen - 8;
+                   }
+
+               } else if (IconSize == 48) {
+                   if (Ptr[0] == 'i' && Ptr[1] == 'h' && Ptr[2] == '3' && Ptr[3] == '2') {
+                       DataPtr = Ptr + 8;
+                       DataLen = BlockLen - 8;
+                   } else if (Ptr[0] == 'h' && Ptr[1] == '8' && Ptr[2] == 'm' && Ptr[3] == 'k') {
+                       MaskPtr = Ptr + 8;
+                       MaskLen = BlockLen - 8;
+                   }
+
+               } else if (IconSize == 32) {
+                   if (Ptr[0] == 'i' && Ptr[1] == 'l' && Ptr[2] == '3' && Ptr[3] == '2') {
+                       DataPtr = Ptr + 8;
+                       DataLen = BlockLen - 8;
+                   } else if (Ptr[0] == 'l' && Ptr[1] == '8' && Ptr[2] == 'm' && Ptr[3] == 'k') {
+                       MaskPtr = Ptr + 8;
+                       MaskLen = BlockLen - 8;
+                   }
+
+               } else if (IconSize == 16) {
+                   if (Ptr[0] == 'i' && Ptr[1] == 's' && Ptr[2] == '3' && Ptr[3] == '2') {
+                       DataPtr = Ptr + 8;
+                       DataLen = BlockLen - 8;
+                   } else if (Ptr[0] == 's' && Ptr[1] == '8' && Ptr[2] == 'm' && Ptr[3] == 'k') {
+                       MaskPtr = Ptr + 8;
+                       MaskLen = BlockLen - 8;
+                   }
+
+               }
+
+               Ptr += BlockLen;
+           }
+        } while ((DataPtr == NULL) && (SizeToTry++ < MAX_ICNS_SIZES));
+
+        break;
+    }
+
+    if (DataPtr == NULL)
+        return NULL;   // no image found
+
+    // allocate image structure and buffer
+    NewImage = egCreateImage(IconSize, IconSize, WantAlpha);
+    if (NewImage == NULL)
+        return NULL;
+    PixelCount = IconSize * IconSize;
+
+    if (DataLen < PixelCount * 3) {
+
+        // pixel data is compressed, RGB planar
+        CompData = DataPtr;
+        CompLen  = DataLen;
+        egDecompressIcnsRLE(&CompData, &CompLen, PLPTR(NewImage, r), PixelCount);
+        egDecompressIcnsRLE(&CompData, &CompLen, PLPTR(NewImage, g), PixelCount);
+        egDecompressIcnsRLE(&CompData, &CompLen, PLPTR(NewImage, b), PixelCount);
+        // possible assertion: CompLen == 0
+        if (CompLen > 0) {
+            Print(L" egLoadICNSIcon: %d bytes of compressed data left\n", CompLen);
+        }
+
+    } else {
+
+        // pixel data is uncompressed, RGB interleaved
+        SrcPtr  = DataPtr;
+        DestPtr = NewImage->PixelData;
+        for (i = 0; i < PixelCount; i++, DestPtr++) {
+            DestPtr->r = *SrcPtr++;
+            DestPtr->g = *SrcPtr++;
+            DestPtr->b = *SrcPtr++;
+        }
+
+    }
+
+    // add/set alpha plane
+    if (MaskPtr != NULL && MaskLen >= PixelCount && WantAlpha)
+        egInsertPlane(MaskPtr, PLPTR(NewImage, a), PixelCount);
+    else
+        egSetPlane(PLPTR(NewImage, a), WantAlpha ? 255 : 0, PixelCount);
+
+    // FUTURE: scale to originally requested size if we had to load another size
+
+    return NewImage;
+} // EG_IMAGE * egDecodeICNS()
+
+/* EOF */
diff --git a/libeg/lodepng.c b/libeg/lodepng.c
new file mode 100644 (file)
index 0000000..2bbd07e
--- /dev/null
@@ -0,0 +1,6164 @@
+/*
+LodePNG version 20151024
+
+Copyright (c) 2005-2015 Lode Vandevenne
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+    1. The origin of this software must not be misrepresented; you must not
+    claim that you wrote the original software. If you use this software
+    in a product, an acknowledgment in the product documentation would be
+    appreciated but is not required.
+
+    2. Altered source versions must be plainly marked as such, and must not be
+    misrepresented as being the original software.
+
+    3. This notice may not be removed or altered from any source
+    distribution.
+*/
+
+/*
+The manual and changelog are in the header file "lodepng.h"
+Rename this file to lodepng.cpp to use it for C++, or to lodepng.c to use it for C.
+*/
+
+#include "lodepng.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef LODEPNG_COMPILE_CPP
+#include <fstream>
+#endif /*LODEPNG_COMPILE_CPP*/
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1310) /*Visual Studio: A few warning types are not desired here.*/
+#pragma warning( disable : 4244 ) /*implicit conversions: not warned by gcc -Wall -Wextra and requires too much casts*/
+#pragma warning( disable : 4996 ) /*VS does not like fopen, but fopen_s is not standard C so unusable here*/
+#endif /*_MSC_VER */
+
+const char* LODEPNG_VERSION_STRING = "20151024";
+
+/*
+This source file is built up in the following large parts. The code sections
+with the "LODEPNG_COMPILE_" #defines divide this up further in an intermixed way.
+-Tools for C and common code for PNG and Zlib
+-C Code for Zlib (huffman, deflate, ...)
+-C Code for PNG (file format chunks, adam7, PNG filters, color conversions, ...)
+-The C++ wrapper around all of the above
+*/
+
+/*The malloc, realloc and free functions defined here with "lodepng_" in front
+of the name, so that you can easily change them to others related to your
+platform if needed. Everything else in the code calls these. Pass
+-DLODEPNG_NO_COMPILE_ALLOCATORS to the compiler, or comment out
+#define LODEPNG_COMPILE_ALLOCATORS in the header, to disable the ones here and
+define them in your own project's source files without needing to change
+lodepng source code. Don't forget to remove "static" if you copypaste them
+from here.*/
+
+#ifdef LODEPNG_COMPILE_ALLOCATORS
+static void* lodepng_malloc(size_t size)
+{
+  return malloc(size);
+}
+
+static void* lodepng_realloc(void* ptr, size_t new_size)
+{
+  return realloc(ptr, new_size);
+}
+
+static void lodepng_free(void* ptr)
+{
+  free(ptr);
+}
+#else /*LODEPNG_COMPILE_ALLOCATORS*/
+void* lodepng_malloc(size_t size);
+void* lodepng_realloc(void* ptr, size_t new_size);
+void lodepng_free(void* ptr);
+#endif /*LODEPNG_COMPILE_ALLOCATORS*/
+
+/* ////////////////////////////////////////////////////////////////////////// */
+/* ////////////////////////////////////////////////////////////////////////// */
+/* // Tools for C, and common code for PNG and Zlib.                       // */
+/* ////////////////////////////////////////////////////////////////////////// */
+/* ////////////////////////////////////////////////////////////////////////// */
+
+/*
+Often in case of an error a value is assigned to a variable and then it breaks
+out of a loop (to go to the cleanup phase of a function). This macro does that.
+It makes the error handling code shorter and more readable.
+
+Example: if(!uivector_resizev(&frequencies_ll, 286, 0)) ERROR_BREAK(83);
+*/
+#define CERROR_BREAK(errorvar, code)\
+{\
+  errorvar = code;\
+  break;\
+}
+
+/*version of CERROR_BREAK that assumes the common case where the error variable is named "error"*/
+#define ERROR_BREAK(code) CERROR_BREAK(error, code)
+
+/*Set error var to the error code, and return it.*/
+#define CERROR_RETURN_ERROR(errorvar, code)\
+{\
+  errorvar = code;\
+  return code;\
+}
+
+/*Try the code, if it returns error, also return the error.*/
+#define CERROR_TRY_RETURN(call)\
+{\
+  unsigned error = call;\
+  if(error) return error;\
+}
+
+/*Set error var to the error code, and return from the void function.*/
+#define CERROR_RETURN(errorvar, code)\
+{\
+  errorvar = code;\
+  return;\
+}
+
+/*
+About uivector, ucvector and string:
+-All of them wrap dynamic arrays or text strings in a similar way.
+-LodePNG was originally written in C++. The vectors replace the std::vectors that were used in the C++ version.
+-The string tools are made to avoid problems with compilers that declare things like strncat as deprecated.
+-They're not used in the interface, only internally in this file as static functions.
+-As with many other structs in this file, the init and cleanup functions serve as ctor and dtor.
+*/
+
+#ifdef LODEPNG_COMPILE_ZLIB
+/*dynamic vector of unsigned ints*/
+typedef struct uivector
+{
+  unsigned* data;
+  size_t size; /*size in number of unsigned longs*/
+  size_t allocsize; /*allocated size in bytes*/
+} uivector;
+
+static void uivector_cleanup(void* p)
+{
+  ((uivector*)p)->size = ((uivector*)p)->allocsize = 0;
+  lodepng_free(((uivector*)p)->data);
+  ((uivector*)p)->data = NULL;
+}
+
+/*returns 1 if success, 0 if failure ==> nothing done*/
+static unsigned uivector_reserve(uivector* p, size_t allocsize)
+{
+  if(allocsize > p->allocsize)
+  {
+    size_t newsize = (allocsize > p->allocsize * 2) ? allocsize : (allocsize * 3 / 2);
+    void* data = lodepng_realloc(p->data, newsize);
+    if(data)
+    {
+      p->allocsize = newsize;
+      p->data = (unsigned*)data;
+    }
+    else return 0; /*error: not enough memory*/
+  }
+  return 1;
+}
+
+/*returns 1 if success, 0 if failure ==> nothing done*/
+static unsigned uivector_resize(uivector* p, size_t size)
+{
+  if(!uivector_reserve(p, size * sizeof(unsigned))) return 0;
+  p->size = size;
+  return 1; /*success*/
+}
+
+/*resize and give all new elements the value*/
+static unsigned uivector_resizev(uivector* p, size_t size, unsigned value)
+{
+  size_t oldsize = p->size, i;
+  if(!uivector_resize(p, size)) return 0;
+  for(i = oldsize; i < size; ++i) p->data[i] = value;
+  return 1;
+}
+
+static void uivector_init(uivector* p)
+{
+  p->data = NULL;
+  p->size = p->allocsize = 0;
+}
+
+#ifdef LODEPNG_COMPILE_ENCODER
+/*returns 1 if success, 0 if failure ==> nothing done*/
+static unsigned uivector_push_back(uivector* p, unsigned c)
+{
+  if(!uivector_resize(p, p->size + 1)) return 0;
+  p->data[p->size - 1] = c;
+  return 1;
+}
+#endif /*LODEPNG_COMPILE_ENCODER*/
+#endif /*LODEPNG_COMPILE_ZLIB*/
+
+/* /////////////////////////////////////////////////////////////////////////// */
+
+/*dynamic vector of unsigned chars*/
+typedef struct ucvector
+{
+  unsigned char* data;
+  size_t size; /*used size*/
+  size_t allocsize; /*allocated size*/
+} ucvector;
+
+/*returns 1 if success, 0 if failure ==> nothing done*/
+static unsigned ucvector_reserve(ucvector* p, size_t allocsize)
+{
+  if(allocsize > p->allocsize)
+  {
+    size_t newsize = (allocsize > p->allocsize * 2) ? allocsize : (allocsize * 3 / 2);
+    void* data = lodepng_realloc(p->data, newsize);
+    if(data)
+    {
+      p->allocsize = newsize;
+      p->data = (unsigned char*)data;
+    }
+    else return 0; /*error: not enough memory*/
+  }
+  return 1;
+}
+
+/*returns 1 if success, 0 if failure ==> nothing done*/
+static unsigned ucvector_resize(ucvector* p, size_t size)
+{
+  if(!ucvector_reserve(p, size * sizeof(unsigned char))) return 0;
+  p->size = size;
+  return 1; /*success*/
+}
+
+#ifdef LODEPNG_COMPILE_PNG
+
+static void ucvector_cleanup(void* p)
+{
+  ((ucvector*)p)->size = ((ucvector*)p)->allocsize = 0;
+  lodepng_free(((ucvector*)p)->data);
+  ((ucvector*)p)->data = NULL;
+}
+
+static void ucvector_init(ucvector* p)
+{
+  p->data = NULL;
+  p->size = p->allocsize = 0;
+}
+
+#ifdef LODEPNG_COMPILE_DECODER
+/*resize and give all new elements the value*/
+static unsigned ucvector_resizev(ucvector* p, size_t size, unsigned char value)
+{
+  size_t oldsize = p->size, i;
+  if(!ucvector_resize(p, size)) return 0;
+  for(i = oldsize; i < size; ++i) p->data[i] = value;
+  return 1;
+}
+#endif /*LODEPNG_COMPILE_DECODER*/
+#endif /*LODEPNG_COMPILE_PNG*/
+
+#ifdef LODEPNG_COMPILE_ZLIB
+/*you can both convert from vector to buffer&size and vica versa. If you use
+init_buffer to take over a buffer and size, it is not needed to use cleanup*/
+static void ucvector_init_buffer(ucvector* p, unsigned char* buffer, size_t size)
+{
+  p->data = buffer;
+  p->allocsize = p->size = size;
+}
+#endif /*LODEPNG_COMPILE_ZLIB*/
+
+#if (defined(LODEPNG_COMPILE_PNG) && defined(LODEPNG_COMPILE_ANCILLARY_CHUNKS)) || defined(LODEPNG_COMPILE_ENCODER)
+/*returns 1 if success, 0 if failure ==> nothing done*/
+static unsigned ucvector_push_back(ucvector* p, unsigned char c)
+{
+  if(!ucvector_resize(p, p->size + 1)) return 0;
+  p->data[p->size - 1] = c;
+  return 1;
+}
+#endif /*defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_ENCODER)*/
+
+
+/* ////////////////////////////////////////////////////////////////////////// */
+
+#ifdef LODEPNG_COMPILE_PNG
+#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
+/*returns 1 if success, 0 if failure ==> nothing done*/
+static unsigned string_resize(char** out, size_t size)
+{
+  char* data = (char*)lodepng_realloc(*out, size + 1);
+  if(data)
+  {
+    data[size] = 0; /*null termination char*/
+    *out = data;
+  }
+  return data != 0;
+}
+
+/*init a {char*, size_t} pair for use as string*/
+static void string_init(char** out)
+{
+  *out = NULL;
+  string_resize(out, 0);
+}
+
+/*free the above pair again*/
+static void string_cleanup(char** out)
+{
+  lodepng_free(*out);
+  *out = NULL;
+}
+
+static void string_set(char** out, const char* in)
+{
+  size_t insize = strlen(in), i;
+  if(string_resize(out, insize))
+  {
+    for(i = 0; i != insize; ++i)
+    {
+      (*out)[i] = in[i];
+    }
+  }
+}
+#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
+#endif /*LODEPNG_COMPILE_PNG*/
+
+/* ////////////////////////////////////////////////////////////////////////// */
+
+unsigned lodepng_read32bitInt(const unsigned char* buffer)
+{
+  return (unsigned)((buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]);
+}
+
+#if defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_ENCODER)
+/*buffer must have at least 4 allocated bytes available*/
+static void lodepng_set32bitInt(unsigned char* buffer, unsigned value)
+{
+  buffer[0] = (unsigned char)((value >> 24) & 0xff);
+  buffer[1] = (unsigned char)((value >> 16) & 0xff);
+  buffer[2] = (unsigned char)((value >>  8) & 0xff);
+  buffer[3] = (unsigned char)((value      ) & 0xff);
+}
+#endif /*defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_ENCODER)*/
+
+#ifdef LODEPNG_COMPILE_ENCODER
+static void lodepng_add32bitInt(ucvector* buffer, unsigned value)
+{
+  ucvector_resize(buffer, buffer->size + 4); /*todo: give error if resize failed*/
+  lodepng_set32bitInt(&buffer->data[buffer->size - 4], value);
+}
+#endif /*LODEPNG_COMPILE_ENCODER*/
+
+/* ////////////////////////////////////////////////////////////////////////// */
+/* / File IO                                                                / */
+/* ////////////////////////////////////////////////////////////////////////// */
+
+#ifdef LODEPNG_COMPILE_DISK
+
+unsigned lodepng_load_file(unsigned char** out, size_t* outsize, const char* filename)
+{
+  FILE* file;
+  long size;
+
+  /*provide some proper output values if error will happen*/
+  *out = 0;
+  *outsize = 0;
+
+  file = fopen(filename, "rb");
+  if(!file) return 78;
+
+  /*get filesize:*/
+  fseek(file , 0 , SEEK_END);
+  size = ftell(file);
+  rewind(file);
+
+  /*read contents of the file into the vector*/
+  *outsize = 0;
+  *out = (unsigned char*)lodepng_malloc((size_t)size);
+  if(size && (*out)) (*outsize) = fread(*out, 1, (size_t)size, file);
+
+  fclose(file);
+  if(!(*out) && size) return 83; /*the above malloc failed*/
+  return 0;
+}
+
+/*write given buffer to the file, overwriting the file, it doesn't append to it.*/
+unsigned lodepng_save_file(const unsigned char* buffer, size_t buffersize, const char* filename)
+{
+  FILE* file;
+  file = fopen(filename, "wb" );
+  if(!file) return 79;
+  fwrite((char*)buffer , 1 , buffersize, file);
+  fclose(file);
+  return 0;
+}
+
+#endif /*LODEPNG_COMPILE_DISK*/
+
+/* ////////////////////////////////////////////////////////////////////////// */
+/* ////////////////////////////////////////////////////////////////////////// */
+/* // End of common code and tools. Begin of Zlib related code.            // */
+/* ////////////////////////////////////////////////////////////////////////// */
+/* ////////////////////////////////////////////////////////////////////////// */
+
+#ifdef LODEPNG_COMPILE_ZLIB
+#ifdef LODEPNG_COMPILE_ENCODER
+/*TODO: this ignores potential out of memory errors*/
+#define addBitToStream(/*size_t**/ bitpointer, /*ucvector**/ bitstream, /*unsigned char*/ bit)\
+{\
+  /*add a new byte at the end*/\
+  if(((*bitpointer) & 7) == 0) ucvector_push_back(bitstream, (unsigned char)0);\
+  /*earlier bit of huffman code is in a lesser significant bit of an earlier byte*/\
+  (bitstream->data[bitstream->size - 1]) |= (bit << ((*bitpointer) & 0x7));\
+  ++(*bitpointer);\
+}
+
+static void addBitsToStream(size_t* bitpointer, ucvector* bitstream, unsigned value, size_t nbits)
+{
+  size_t i;
+  for(i = 0; i != nbits; ++i) addBitToStream(bitpointer, bitstream, (unsigned char)((value >> i) & 1));
+}
+
+static void addBitsToStreamReversed(size_t* bitpointer, ucvector* bitstream, unsigned value, size_t nbits)
+{
+  size_t i;
+  for(i = 0; i != nbits; ++i) addBitToStream(bitpointer, bitstream, (unsigned char)((value >> (nbits - 1 - i)) & 1));
+}
+#endif /*LODEPNG_COMPILE_ENCODER*/
+
+#ifdef LODEPNG_COMPILE_DECODER
+
+#define READBIT(bitpointer, bitstream) ((bitstream[bitpointer >> 3] >> (bitpointer & 0x7)) & (unsigned char)1)
+
+static unsigned char readBitFromStream(size_t* bitpointer, const unsigned char* bitstream)
+{
+  unsigned char result = (unsigned char)(READBIT(*bitpointer, bitstream));
+  ++(*bitpointer);
+  return result;
+}
+
+static unsigned readBitsFromStream(size_t* bitpointer, const unsigned char* bitstream, size_t nbits)
+{
+  unsigned result = 0, i;
+  for(i = 0; i != nbits; ++i)
+  {
+    result += ((unsigned)READBIT(*bitpointer, bitstream)) << i;
+    ++(*bitpointer);
+  }
+  return result;
+}
+#endif /*LODEPNG_COMPILE_DECODER*/
+
+/* ////////////////////////////////////////////////////////////////////////// */
+/* / Deflate - Huffman                                                      / */
+/* ////////////////////////////////////////////////////////////////////////// */
+
+#define FIRST_LENGTH_CODE_INDEX 257
+#define LAST_LENGTH_CODE_INDEX 285
+/*256 literals, the end code, some length codes, and 2 unused codes*/
+#define NUM_DEFLATE_CODE_SYMBOLS 288
+/*the distance codes have their own symbols, 30 used, 2 unused*/
+#define NUM_DISTANCE_SYMBOLS 32
+/*the code length codes. 0-15: code lengths, 16: copy previous 3-6 times, 17: 3-10 zeros, 18: 11-138 zeros*/
+#define NUM_CODE_LENGTH_CODES 19
+
+/*the base lengths represented by codes 257-285*/
+static const unsigned LENGTHBASE[29]
+  = {3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59,
+     67, 83, 99, 115, 131, 163, 195, 227, 258};
+
+/*the extra bits used by codes 257-285 (added to base length)*/
+static const unsigned LENGTHEXTRA[29]
+  = {0, 0, 0, 0, 0, 0, 0,  0,  1,  1,  1,  1,  2,  2,  2,  2,  3,  3,  3,  3,
+      4,  4,  4,   4,   5,   5,   5,   5,   0};
+
+/*the base backwards distances (the bits of distance codes appear after length codes and use their own huffman tree)*/
+static const unsigned DISTANCEBASE[30]
+  = {1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513,
+     769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577};
+
+/*the extra bits of backwards distances (added to base)*/
+static const unsigned DISTANCEEXTRA[30]
+  = {0, 0, 0, 0, 1, 1, 2,  2,  3,  3,  4,  4,  5,  5,   6,   6,   7,   7,   8,
+       8,    9,    9,   10,   10,   11,   11,   12,    12,    13,    13};
+
+/*the order in which "code length alphabet code lengths" are stored, out of this
+the huffman tree of the dynamic huffman tree lengths is generated*/
+static const unsigned CLCL_ORDER[NUM_CODE_LENGTH_CODES]
+  = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+/* ////////////////////////////////////////////////////////////////////////// */
+
+/*
+Huffman tree struct, containing multiple representations of the tree
+*/
+typedef struct HuffmanTree
+{
+  unsigned* tree2d;
+  unsigned* tree1d;
+  unsigned* lengths; /*the lengths of the codes of the 1d-tree*/
+  unsigned maxbitlen; /*maximum number of bits a single code can get*/
+  unsigned numcodes; /*number of symbols in the alphabet = number of codes*/
+} HuffmanTree;
+
+/*function used for debug purposes to draw the tree in ascii art with C++*/
+/*
+static void HuffmanTree_draw(HuffmanTree* tree)
+{
+  std::cout << "tree. length: " << tree->numcodes << " maxbitlen: " << tree->maxbitlen << std::endl;
+  for(size_t i = 0; i != tree->tree1d.size; ++i)
+  {
+    if(tree->lengths.data[i])
+      std::cout << i << " " << tree->tree1d.data[i] << " " << tree->lengths.data[i] << std::endl;
+  }
+  std::cout << std::endl;
+}*/
+
+static void HuffmanTree_init(HuffmanTree* tree)
+{
+  tree->tree2d = 0;
+  tree->tree1d = 0;
+  tree->lengths = 0;
+}
+
+static void HuffmanTree_cleanup(HuffmanTree* tree)
+{
+  lodepng_free(tree->tree2d);
+  lodepng_free(tree->tree1d);
+  lodepng_free(tree->lengths);
+}
+
+/*the tree representation used by the decoder. return value is error*/
+static unsigned HuffmanTree_make2DTree(HuffmanTree* tree)
+{
+  unsigned nodefilled = 0; /*up to which node it is filled*/
+  unsigned treepos = 0; /*position in the tree (1 of the numcodes columns)*/
+  unsigned n, i;
+
+  tree->tree2d = (unsigned*)lodepng_malloc(tree->numcodes * 2 * sizeof(unsigned));
+  if(!tree->tree2d) return 83; /*alloc fail*/
+
+  /*
+  convert tree1d[] to tree2d[][]. In the 2D array, a value of 32767 means
+  uninited, a value >= numcodes is an address to another bit, a value < numcodes
+  is a code. The 2 rows are the 2 possible bit values (0 or 1), there are as
+  many columns as codes - 1.
+  A good huffman tree has N * 2 - 1 nodes, of which N - 1 are internal nodes.
+  Here, the internal nodes are stored (what their 0 and 1 option point to).
+  There is only memory for such good tree currently, if there are more nodes
+  (due to too long length codes), error 55 will happen
+  */
+  for(n = 0; n < tree->numcodes * 2; ++n)
+  {
+    tree->tree2d[n] = 32767; /*32767 here means the tree2d isn't filled there yet*/
+  }
+
+  for(n = 0; n < tree->numcodes; ++n) /*the codes*/
+  {
+    for(i = 0; i != tree->lengths[n]; ++i) /*the bits for this code*/
+    {
+      unsigned char bit = (unsigned char)((tree->tree1d[n] >> (tree->lengths[n] - i - 1)) & 1);
+      /*oversubscribed, see comment in lodepng_error_text*/
+      if(treepos > 2147483647 || treepos + 2 > tree->numcodes) return 55;
+      if(tree->tree2d[2 * treepos + bit] == 32767) /*not yet filled in*/
+      {
+        if(i + 1 == tree->lengths[n]) /*last bit*/
+        {
+          tree->tree2d[2 * treepos + bit] = n; /*put the current code in it*/
+          treepos = 0;
+        }
+        else
+        {
+          /*put address of the next step in here, first that address has to be found of course
+          (it's just nodefilled + 1)...*/
+          ++nodefilled;
+          /*addresses encoded with numcodes added to it*/
+          tree->tree2d[2 * treepos + bit] = nodefilled + tree->numcodes;
+          treepos = nodefilled;
+        }
+      }
+      else treepos = tree->tree2d[2 * treepos + bit] - tree->numcodes;
+    }
+  }
+
+  for(n = 0; n < tree->numcodes * 2; ++n)
+  {
+    if(tree->tree2d[n] == 32767) tree->tree2d[n] = 0; /*remove possible remaining 32767's*/
+  }
+
+  return 0;
+}
+
+/*
+Second step for the ...makeFromLengths and ...makeFromFrequencies functions.
+numcodes, lengths and maxbitlen must already be filled in correctly. return
+value is error.
+*/
+static unsigned HuffmanTree_makeFromLengths2(HuffmanTree* tree)
+{
+  uivector blcount;
+  uivector nextcode;
+  unsigned error = 0;
+  unsigned bits, n;
+
+  uivector_init(&blcount);
+  uivector_init(&nextcode);
+
+  tree->tree1d = (unsigned*)lodepng_malloc(tree->numcodes * sizeof(unsigned));
+  if(!tree->tree1d) error = 83; /*alloc fail*/
+
+  if(!uivector_resizev(&blcount, tree->maxbitlen + 1, 0)
+  || !uivector_resizev(&nextcode, tree->maxbitlen + 1, 0))
+    error = 83; /*alloc fail*/
+
+  if(!error)
+  {
+    /*step 1: count number of instances of each code length*/
+    for(bits = 0; bits != tree->numcodes; ++bits) ++blcount.data[tree->lengths[bits]];
+    /*step 2: generate the nextcode values*/
+    for(bits = 1; bits <= tree->maxbitlen; ++bits)
+    {
+      nextcode.data[bits] = (nextcode.data[bits - 1] + blcount.data[bits - 1]) << 1;
+    }
+    /*step 3: generate all the codes*/
+    for(n = 0; n != tree->numcodes; ++n)
+    {
+      if(tree->lengths[n] != 0) tree->tree1d[n] = nextcode.data[tree->lengths[n]]++;
+    }
+  }
+
+  uivector_cleanup(&blcount);
+  uivector_cleanup(&nextcode);
+
+  if(!error) return HuffmanTree_make2DTree(tree);
+  else return error;
+}
+
+/*
+given the code lengths (as stored in the PNG file), generate the tree as defined
+by Deflate. maxbitlen is the maximum bits that a code in the tree can have.
+return value is error.
+*/
+static unsigned HuffmanTree_makeFromLengths(HuffmanTree* tree, const unsigned* bitlen,
+                                            size_t numcodes, unsigned maxbitlen)
+{
+  unsigned i;
+  tree->lengths = (unsigned*)lodepng_malloc(numcodes * sizeof(unsigned));
+  if(!tree->lengths) return 83; /*alloc fail*/
+  for(i = 0; i != numcodes; ++i) tree->lengths[i] = bitlen[i];
+  tree->numcodes = (unsigned)numcodes; /*number of symbols*/
+  tree->maxbitlen = maxbitlen;
+  return HuffmanTree_makeFromLengths2(tree);
+}
+
+#ifdef LODEPNG_COMPILE_ENCODER
+
+/*BPM: Boundary Package Merge, see "A Fast and Space-Economical Algorithm for Length-Limited Coding",
+Jyrki Katajainen, Alistair Moffat, Andrew Turpin, 1995.*/
+
+/*chain node for boundary package merge*/
+typedef struct BPMNode
+{
+  int weight; /*the sum of all weights in this chain*/
+  unsigned index; /*index of this leaf node (called "count" in the paper)*/
+  struct BPMNode* tail; /*the next nodes in this chain (null if last)*/
+  int in_use;
+} BPMNode;
+
+/*lists of chains*/
+typedef struct BPMLists
+{
+  /*memory pool*/
+  unsigned memsize;
+  BPMNode* memory;
+  unsigned numfree;
+  unsigned nextfree;
+  BPMNode** freelist;
+  /*two heads of lookahead chains per list*/
+  unsigned listsize;
+  BPMNode** chains0;
+  BPMNode** chains1;
+} BPMLists;
+
+/*creates a new chain node with the given parameters, from the memory in the lists */
+static BPMNode* bpmnode_create(BPMLists* lists, int weight, unsigned index, BPMNode* tail)
+{
+  unsigned i;
+  BPMNode* result;
+
+  /*memory full, so garbage collect*/
+  if(lists->nextfree >= lists->numfree)
+  {
+    /*mark only those that are in use*/
+    for(i = 0; i != lists->memsize; ++i) lists->memory[i].in_use = 0;
+    for(i = 0; i != lists->listsize; ++i)
+    {
+      BPMNode* node;
+      for(node = lists->chains0[i]; node != 0; node = node->tail) node->in_use = 1;
+      for(node = lists->chains1[i]; node != 0; node = node->tail) node->in_use = 1;
+    }
+    /*collect those that are free*/
+    lists->numfree = 0;
+    for(i = 0; i != lists->memsize; ++i)
+    {
+      if(!lists->memory[i].in_use) lists->freelist[lists->numfree++] = &lists->memory[i];
+    }
+    lists->nextfree = 0;
+  }
+
+  result = lists->freelist[lists->nextfree++];
+  result->weight = weight;
+  result->index = index;
+  result->tail = tail;
+  return result;
+}
+
+static int bpmnode_compare(const void* a, const void* b)
+{
+  int wa = ((const BPMNode*)a)->weight;
+  int wb = ((const BPMNode*)b)->weight;
+  if(wa < wb) return -1;
+  if(wa > wb) return 1;
+  /*make the qsort a stable sort*/
+  return ((const BPMNode*)a)->index < ((const BPMNode*)b)->index ? 1 : -1;
+}
+
+/*Boundary Package Merge step, numpresent is the amount of leaves, and c is the current chain.*/
+static void boundaryPM(BPMLists* lists, BPMNode* leaves, size_t numpresent, int c, int num)
+{
+  unsigned lastindex = lists->chains1[c]->index;
+
+  if(c == 0)
+  {
+    if(lastindex >= numpresent) return;
+    lists->chains0[c] = lists->chains1[c];
+    lists->chains1[c] = bpmnode_create(lists, leaves[lastindex].weight, lastindex + 1, 0);
+  }
+  else
+  {
+    /*sum of the weights of the head nodes of the previous lookahead chains.*/
+    int sum = lists->chains0[c - 1]->weight + lists->chains1[c - 1]->weight;
+    lists->chains0[c] = lists->chains1[c];
+    if(lastindex < numpresent && sum > leaves[lastindex].weight)
+    {
+      lists->chains1[c] = bpmnode_create(lists, leaves[lastindex].weight, lastindex + 1, lists->chains1[c]->tail);
+      return;
+    }
+    lists->chains1[c] = bpmnode_create(lists, sum, lastindex, lists->chains1[c - 1]);
+    /*in the end we are only interested in the chain of the last list, so no
+    need to recurse if we're at the last one (this gives measurable speedup)*/
+    if(num + 1 < (int)(2 * numpresent - 2))
+    {
+      boundaryPM(lists, leaves, numpresent, c - 1, num);
+      boundaryPM(lists, leaves, numpresent, c - 1, num);
+    }
+  }
+}
+
+unsigned lodepng_huffman_code_lengths(unsigned* lengths, const unsigned* frequencies,
+                                      size_t numcodes, unsigned maxbitlen)
+{
+  unsigned error = 0;
+  unsigned i;
+  size_t numpresent = 0; /*number of symbols with non-zero frequency*/
+  BPMNode* leaves; /*the symbols, only those with > 0 frequency*/
+
+  if(numcodes == 0) return 80; /*error: a tree of 0 symbols is not supposed to be made*/
+  if((1u << maxbitlen) < numcodes) return 80; /*error: represent all symbols*/
+
+  leaves = (BPMNode*)lodepng_malloc(numcodes * sizeof(*leaves));
+  if(!leaves) return 83; /*alloc fail*/
+
+  for(i = 0; i != numcodes; ++i)
+  {
+    if(frequencies[i] > 0)
+    {
+      leaves[numpresent].weight = (int)frequencies[i];
+      leaves[numpresent].index = i;
+      ++numpresent;
+    }
+  }
+
+  for(i = 0; i != numcodes; ++i) lengths[i] = 0;
+
+  /*ensure at least two present symbols. There should be at least one symbol
+  according to RFC 1951 section 3.2.7. Some decoders incorrectly require two. To
+  make these work as well ensure there are at least two symbols. The
+  Package-Merge code below also doesn't work correctly if there's only one
+  symbol, it'd give it the theoritical 0 bits but in practice zlib wants 1 bit*/
+  if(numpresent == 0)
+  {
+    lengths[0] = lengths[1] = 1; /*note that for RFC 1951 section 3.2.7, only lengths[0] = 1 is needed*/
+  }
+  else if(numpresent == 1)
+  {
+    lengths[leaves[0].index] = 1;
+    lengths[leaves[0].index == 0 ? 1 : 0] = 1;
+  }
+  else
+  {
+    BPMLists lists;
+    BPMNode* node;
+
+    qsort(leaves, numpresent, sizeof(BPMNode), bpmnode_compare);
+
+    lists.listsize = maxbitlen;
+    lists.memsize = 2 * maxbitlen * (maxbitlen + 1);
+    lists.nextfree = 0;
+    lists.numfree = lists.memsize;
+    lists.memory = (BPMNode*)lodepng_malloc(lists.memsize * sizeof(*lists.memory));
+    lists.freelist = (BPMNode**)lodepng_malloc(lists.memsize * sizeof(BPMNode*));
+    lists.chains0 = (BPMNode**)lodepng_malloc(lists.listsize * sizeof(BPMNode*));
+    lists.chains1 = (BPMNode**)lodepng_malloc(lists.listsize * sizeof(BPMNode*));
+    if(!lists.memory || !lists.freelist || !lists.chains0 || !lists.chains1) error = 83; /*alloc fail*/
+
+    if(!error)
+    {
+      for(i = 0; i != lists.memsize; ++i) lists.freelist[i] = &lists.memory[i];
+
+      bpmnode_create(&lists, leaves[0].weight, 1, 0);
+      bpmnode_create(&lists, leaves[1].weight, 2, 0);
+
+      for(i = 0; i != lists.listsize; ++i)
+      {
+        lists.chains0[i] = &lists.memory[0];
+        lists.chains1[i] = &lists.memory[1];
+      }
+
+      /*each boundaryPM call adds one chain to the last list, and we need 2 * numpresent - 2 chains.*/
+      for(i = 2; i != 2 * numpresent - 2; ++i) boundaryPM(&lists, leaves, numpresent, (int)maxbitlen - 1, (int)i);
+
+      for(node = lists.chains1[maxbitlen - 1]; node; node = node->tail)
+      {
+        for(i = 0; i != node->index; ++i) ++lengths[leaves[i].index];
+      }
+    }
+
+    lodepng_free(lists.memory);
+    lodepng_free(lists.freelist);
+    lodepng_free(lists.chains0);
+    lodepng_free(lists.chains1);
+  }
+
+  lodepng_free(leaves);
+  return error;
+}
+
+/*Create the Huffman tree given the symbol frequencies*/
+static unsigned HuffmanTree_makeFromFrequencies(HuffmanTree* tree, const unsigned* frequencies,
+                                                size_t mincodes, size_t numcodes, unsigned maxbitlen)
+{
+  unsigned error = 0;
+  while(!frequencies[numcodes - 1] && numcodes > mincodes) --numcodes; /*trim zeroes*/
+  tree->maxbitlen = maxbitlen;
+  tree->numcodes = (unsigned)numcodes; /*number of symbols*/
+  tree->lengths = (unsigned*)lodepng_realloc(tree->lengths, numcodes * sizeof(unsigned));
+  if(!tree->lengths) return 83; /*alloc fail*/
+  /*initialize all lengths to 0*/
+  memset(tree->lengths, 0, numcodes * sizeof(unsigned));
+
+  error = lodepng_huffman_code_lengths(tree->lengths, frequencies, numcodes, maxbitlen);
+  if(!error) error = HuffmanTree_makeFromLengths2(tree);
+  return error;
+}
+
+static unsigned HuffmanTree_getCode(const HuffmanTree* tree, unsigned index)
+{
+  return tree->tree1d[index];
+}
+
+static unsigned HuffmanTree_getLength(const HuffmanTree* tree, unsigned index)
+{
+  return tree->lengths[index];
+}
+#endif /*LODEPNG_COMPILE_ENCODER*/
+
+/*get the literal and length code tree of a deflated block with fixed tree, as per the deflate specification*/
+static unsigned generateFixedLitLenTree(HuffmanTree* tree)
+{
+  unsigned i, error = 0;
+  unsigned* bitlen = (unsigned*)lodepng_malloc(NUM_DEFLATE_CODE_SYMBOLS * sizeof(unsigned));
+  if(!bitlen) return 83; /*alloc fail*/
+
+  /*288 possible codes: 0-255=literals, 256=endcode, 257-285=lengthcodes, 286-287=unused*/
+  for(i =   0; i <= 143; ++i) bitlen[i] = 8;
+  for(i = 144; i <= 255; ++i) bitlen[i] = 9;
+  for(i = 256; i <= 279; ++i) bitlen[i] = 7;
+  for(i = 280; i <= 287; ++i) bitlen[i] = 8;
+
+  error = HuffmanTree_makeFromLengths(tree, bitlen, NUM_DEFLATE_CODE_SYMBOLS, 15);
+
+  lodepng_free(bitlen);
+  return error;
+}
+
+/*get the distance code tree of a deflated block with fixed tree, as specified in the deflate specification*/
+static unsigned generateFixedDistanceTree(HuffmanTree* tree)
+{
+  unsigned i, error = 0;
+  unsigned* bitlen = (unsigned*)lodepng_malloc(NUM_DISTANCE_SYMBOLS * sizeof(unsigned));
+  if(!bitlen) return 83; /*alloc fail*/
+
+  /*there are 32 distance codes, but 30-31 are unused*/
+  for(i = 0; i != NUM_DISTANCE_SYMBOLS; ++i) bitlen[i] = 5;
+  error = HuffmanTree_makeFromLengths(tree, bitlen, NUM_DISTANCE_SYMBOLS, 15);
+
+  lodepng_free(bitlen);
+  return error;
+}
+
+#ifdef LODEPNG_COMPILE_DECODER
+
+/*
+returns the code, or (unsigned)(-1) if error happened
+inbitlength is the length of the complete buffer, in bits (so its byte length times 8)
+*/
+static unsigned huffmanDecodeSymbol(const unsigned char* in, size_t* bp,
+                                    const HuffmanTree* codetree, size_t inbitlength)
+{
+  unsigned treepos = 0, ct;
+  for(;;)
+  {
+    if(*bp >= inbitlength) return (unsigned)(-1); /*error: end of input memory reached without endcode*/
+    /*
+    decode the symbol from the tree. The "readBitFromStream" code is inlined in
+    the expression below because this is the biggest bottleneck while decoding
+    */
+    ct = codetree->tree2d[(treepos << 1) + READBIT(*bp, in)];
+    ++(*bp);
+    if(ct < codetree->numcodes) return ct; /*the symbol is decoded, return it*/
+    else treepos = ct - codetree->numcodes; /*symbol not yet decoded, instead move tree position*/
+
+    if(treepos >= codetree->numcodes) return (unsigned)(-1); /*error: it appeared outside the codetree*/
+  }
+}
+#endif /*LODEPNG_COMPILE_DECODER*/
+
+#ifdef LODEPNG_COMPILE_DECODER
+
+/* ////////////////////////////////////////////////////////////////////////// */
+/* / Inflator (Decompressor)                                                / */
+/* ////////////////////////////////////////////////////////////////////////// */
+
+/*get the tree of a deflated block with fixed tree, as specified in the deflate specification*/
+static void getTreeInflateFixed(HuffmanTree* tree_ll, HuffmanTree* tree_d)
+{
+  /*TODO: check for out of memory errors*/
+  generateFixedLitLenTree(tree_ll);
+  generateFixedDistanceTree(tree_d);
+}
+
+/*get the tree of a deflated block with dynamic tree, the tree itself is also Huffman compressed with a known tree*/
+static unsigned getTreeInflateDynamic(HuffmanTree* tree_ll, HuffmanTree* tree_d,
+                                      const unsigned char* in, size_t* bp, size_t inlength)
+{
+  /*make sure that length values that aren't filled in will be 0, or a wrong tree will be generated*/
+  unsigned error = 0;
+  unsigned n, HLIT, HDIST, HCLEN, i;
+  size_t inbitlength = inlength * 8;
+
+  /*see comments in deflateDynamic for explanation of the context and these variables, it is analogous*/
+  unsigned* bitlen_ll = 0; /*lit,len code lengths*/
+  unsigned* bitlen_d = 0; /*dist code lengths*/
+  /*code length code lengths ("clcl"), the bit lengths of the huffman tree used to compress bitlen_ll and bitlen_d*/
+  unsigned* bitlen_cl = 0;
+  HuffmanTree tree_cl; /*the code tree for code length codes (the huffman tree for compressed huffman trees)*/
+
+  if((*bp) + 14 > (inlength << 3)) return 49; /*error: the bit pointer is or will go past the memory*/
+
+  /*number of literal/length codes + 257. Unlike the spec, the value 257 is added to it here already*/
+  HLIT =  readBitsFromStream(bp, in, 5) + 257;
+  /*number of distance codes. Unlike the spec, the value 1 is added to it here already*/
+  HDIST = readBitsFromStream(bp, in, 5) + 1;
+  /*number of code length codes. Unlike the spec, the value 4 is added to it here already*/
+  HCLEN = readBitsFromStream(bp, in, 4) + 4;
+
+  if((*bp) + HCLEN * 3 > (inlength << 3)) return 50; /*error: the bit pointer is or will go past the memory*/
+
+  HuffmanTree_init(&tree_cl);
+
+  while(!error)
+  {
+    /*read the code length codes out of 3 * (amount of code length codes) bits*/
+
+    bitlen_cl = (unsigned*)lodepng_malloc(NUM_CODE_LENGTH_CODES * sizeof(unsigned));
+    if(!bitlen_cl) ERROR_BREAK(83 /*alloc fail*/);
+
+    for(i = 0; i != NUM_CODE_LENGTH_CODES; ++i)
+    {
+      if(i < HCLEN) bitlen_cl[CLCL_ORDER[i]] = readBitsFromStream(bp, in, 3);
+      else bitlen_cl[CLCL_ORDER[i]] = 0; /*if not, it must stay 0*/
+    }
+
+    error = HuffmanTree_makeFromLengths(&tree_cl, bitlen_cl, NUM_CODE_LENGTH_CODES, 7);
+    if(error) break;
+
+    /*now we can use this tree to read the lengths for the tree that this function will return*/
+    bitlen_ll = (unsigned*)lodepng_malloc(NUM_DEFLATE_CODE_SYMBOLS * sizeof(unsigned));
+    bitlen_d = (unsigned*)lodepng_malloc(NUM_DISTANCE_SYMBOLS * sizeof(unsigned));
+    if(!bitlen_ll || !bitlen_d) ERROR_BREAK(83 /*alloc fail*/);
+    for(i = 0; i != NUM_DEFLATE_CODE_SYMBOLS; ++i) bitlen_ll[i] = 0;
+    for(i = 0; i != NUM_DISTANCE_SYMBOLS; ++i) bitlen_d[i] = 0;
+
+    /*i is the current symbol we're reading in the part that contains the code lengths of lit/len and dist codes*/
+    i = 0;
+    while(i < HLIT + HDIST)
+    {
+      unsigned code = huffmanDecodeSymbol(in, bp, &tree_cl, inbitlength);
+      if(code <= 15) /*a length code*/
+      {
+        if(i < HLIT) bitlen_ll[i] = code;
+        else bitlen_d[i - HLIT] = code;
+        ++i;
+      }
+      else if(code == 16) /*repeat previous*/
+      {
+        unsigned replength = 3; /*read in the 2 bits that indicate repeat length (3-6)*/
+        unsigned value; /*set value to the previous code*/
+
+        if(i == 0) ERROR_BREAK(54); /*can't repeat previous if i is 0*/
+
+        if((*bp + 2) > inbitlength) ERROR_BREAK(50); /*error, bit pointer jumps past memory*/
+        replength += readBitsFromStream(bp, in, 2);
+
+        if(i < HLIT + 1) value = bitlen_ll[i - 1];
+        else value = bitlen_d[i - HLIT - 1];
+        /*repeat this value in the next lengths*/
+        for(n = 0; n < replength; ++n)
+        {
+          if(i >= HLIT + HDIST) ERROR_BREAK(13); /*error: i is larger than the amount of codes*/
+          if(i < HLIT) bitlen_ll[i] = value;
+          else bitlen_d[i - HLIT] = value;
+          ++i;
+        }
+      }
+      else if(code == 17) /*repeat "0" 3-10 times*/
+      {
+        unsigned replength = 3; /*read in the bits that indicate repeat length*/
+        if((*bp + 3) > inbitlength) ERROR_BREAK(50); /*error, bit pointer jumps past memory*/
+        replength += readBitsFromStream(bp, in, 3);
+
+        /*repeat this value in the next lengths*/
+        for(n = 0; n < replength; ++n)
+        {
+          if(i >= HLIT + HDIST) ERROR_BREAK(14); /*error: i is larger than the amount of codes*/
+
+          if(i < HLIT) bitlen_ll[i] = 0;
+          else bitlen_d[i - HLIT] = 0;
+          ++i;
+        }
+      }
+      else if(code == 18) /*repeat "0" 11-138 times*/
+      {
+        unsigned replength = 11; /*read in the bits that indicate repeat length*/
+        if((*bp + 7) > inbitlength) ERROR_BREAK(50); /*error, bit pointer jumps past memory*/
+        replength += readBitsFromStream(bp, in, 7);
+
+        /*repeat this value in the next lengths*/
+        for(n = 0; n < replength; ++n)
+        {
+          if(i >= HLIT + HDIST) ERROR_BREAK(15); /*error: i is larger than the amount of codes*/
+
+          if(i < HLIT) bitlen_ll[i] = 0;
+          else bitlen_d[i - HLIT] = 0;
+          ++i;
+        }
+      }
+      else /*if(code == (unsigned)(-1))*/ /*huffmanDecodeSymbol returns (unsigned)(-1) in case of error*/
+      {
+        if(code == (unsigned)(-1))
+        {
+          /*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol
+          (10=no endcode, 11=wrong jump outside of tree)*/
+          error = (*bp) > inbitlength ? 10 : 11;
+        }
+        else error = 16; /*unexisting code, this can never happen*/
+        break;
+      }
+    }
+    if(error) break;
+
+    if(bitlen_ll[256] == 0) ERROR_BREAK(64); /*the length of the end code 256 must be larger than 0*/
+
+    /*now we've finally got HLIT and HDIST, so generate the code trees, and the function is done*/
+    error = HuffmanTree_makeFromLengths(tree_ll, bitlen_ll, NUM_DEFLATE_CODE_SYMBOLS, 15);
+    if(error) break;
+    error = HuffmanTree_makeFromLengths(tree_d, bitlen_d, NUM_DISTANCE_SYMBOLS, 15);
+
+    break; /*end of error-while*/
+  }
+
+  lodepng_free(bitlen_cl);
+  lodepng_free(bitlen_ll);
+  lodepng_free(bitlen_d);
+  HuffmanTree_cleanup(&tree_cl);
+
+  return error;
+}
+
+/*inflate a block with dynamic of fixed Huffman tree*/
+static unsigned inflateHuffmanBlock(ucvector* out, const unsigned char* in, size_t* bp,
+                                    size_t* pos, size_t inlength, unsigned btype)
+{
+  unsigned error = 0;
+  HuffmanTree tree_ll; /*the huffman tree for literal and length codes*/
+  HuffmanTree tree_d; /*the huffman tree for distance codes*/
+  size_t inbitlength = inlength * 8;
+
+  HuffmanTree_init(&tree_ll);
+  HuffmanTree_init(&tree_d);
+
+  if(btype == 1) getTreeInflateFixed(&tree_ll, &tree_d);
+  else if(btype == 2) error = getTreeInflateDynamic(&tree_ll, &tree_d, in, bp, inlength);
+
+  while(!error) /*decode all symbols until end reached, breaks at end code*/
+  {
+    /*code_ll is literal, length or end code*/
+    unsigned code_ll = huffmanDecodeSymbol(in, bp, &tree_ll, inbitlength);
+    if(code_ll <= 255) /*literal symbol*/
+    {
+      /*ucvector_push_back would do the same, but for some reason the two lines below run 10% faster*/
+      if(!ucvector_resize(out, (*pos) + 1)) ERROR_BREAK(83 /*alloc fail*/);
+      out->data[*pos] = (unsigned char)code_ll;
+      ++(*pos);
+    }
+    else if(code_ll >= FIRST_LENGTH_CODE_INDEX && code_ll <= LAST_LENGTH_CODE_INDEX) /*length code*/
+    {
+      unsigned code_d, distance;
+      unsigned numextrabits_l, numextrabits_d; /*extra bits for length and distance*/
+      size_t start, forward, backward, length;
+
+      /*part 1: get length base*/
+      length = LENGTHBASE[code_ll - FIRST_LENGTH_CODE_INDEX];
+
+      /*part 2: get extra bits and add the value of that to length*/
+      numextrabits_l = LENGTHEXTRA[code_ll - FIRST_LENGTH_CODE_INDEX];
+      if((*bp + numextrabits_l) > inbitlength) ERROR_BREAK(51); /*error, bit pointer will jump past memory*/
+      length += readBitsFromStream(bp, in, numextrabits_l);
+
+      /*part 3: get distance code*/
+      code_d = huffmanDecodeSymbol(in, bp, &tree_d, inbitlength);
+      if(code_d > 29)
+      {
+        if(code_ll == (unsigned)(-1)) /*huffmanDecodeSymbol returns (unsigned)(-1) in case of error*/
+        {
+          /*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol
+          (10=no endcode, 11=wrong jump outside of tree)*/
+          error = (*bp) > inlength * 8 ? 10 : 11;
+        }
+        else error = 18; /*error: invalid distance code (30-31 are never used)*/
+        break;
+      }
+      distance = DISTANCEBASE[code_d];
+
+      /*part 4: get extra bits from distance*/
+      numextrabits_d = DISTANCEEXTRA[code_d];
+      if((*bp + numextrabits_d) > inbitlength) ERROR_BREAK(51); /*error, bit pointer will jump past memory*/
+      distance += readBitsFromStream(bp, in, numextrabits_d);
+
+      /*part 5: fill in all the out[n] values based on the length and dist*/
+      start = (*pos);
+      if(distance > start) ERROR_BREAK(52); /*too long backward distance*/
+      backward = start - distance;
+
+      if(!ucvector_resize(out, (*pos) + length)) ERROR_BREAK(83 /*alloc fail*/);
+      if (distance < length) {
+        for(forward = 0; forward < length; ++forward)
+        {
+          out->data[(*pos)++] = out->data[backward++];
+        }
+      } else {
+        memcpy(out->data + *pos, out->data + backward, length);
+        *pos += length;
+      }
+    }
+    else if(code_ll == 256)
+    {
+      break; /*end code, break the loop*/
+    }
+    else /*if(code == (unsigned)(-1))*/ /*huffmanDecodeSymbol returns (unsigned)(-1) in case of error*/
+    {
+      /*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol
+      (10=no endcode, 11=wrong jump outside of tree)*/
+      error = ((*bp) > inlength * 8) ? 10 : 11;
+      break;
+    }
+  }
+
+  HuffmanTree_cleanup(&tree_ll);
+  HuffmanTree_cleanup(&tree_d);
+
+  return error;
+}
+
+static unsigned inflateNoCompression(ucvector* out, const unsigned char* in, size_t* bp, size_t* pos, size_t inlength)
+{
+  size_t p;
+  unsigned LEN, NLEN, n, error = 0;
+
+  /*go to first boundary of byte*/
+  while(((*bp) & 0x7) != 0) ++(*bp);
+  p = (*bp) / 8; /*byte position*/
+
+  /*read LEN (2 bytes) and NLEN (2 bytes)*/
+  if(p + 4 >= inlength) return 52; /*error, bit pointer will jump past memory*/
+  LEN = in[p] + 256u * in[p + 1]; p += 2;
+  NLEN = in[p] + 256u * in[p + 1]; p += 2;
+
+  /*check if 16-bit NLEN is really the one's complement of LEN*/
+  if(LEN + NLEN != 65535) return 21; /*error: NLEN is not one's complement of LEN*/
+
+  if(!ucvector_resize(out, (*pos) + LEN)) return 83; /*alloc fail*/
+
+  /*read the literal data: LEN bytes are now stored in the out buffer*/
+  if(p + LEN > inlength) return 23; /*error: reading outside of in buffer*/
+  for(n = 0; n < LEN; ++n) out->data[(*pos)++] = in[p++];
+
+  (*bp) = p * 8;
+
+  return error;
+}
+
+static unsigned lodepng_inflatev(ucvector* out,
+                                 const unsigned char* in, size_t insize,
+                                 const LodePNGDecompressSettings* settings)
+{
+  /*bit pointer in the "in" data, current byte is bp >> 3, current bit is bp & 0x7 (from lsb to msb of the byte)*/
+  size_t bp = 0;
+  unsigned BFINAL = 0;
+  size_t pos = 0; /*byte position in the out buffer*/
+  unsigned error = 0;
+
+  (void)settings;
+
+  while(!BFINAL)
+  {
+    unsigned BTYPE;
+    if(bp + 2 >= insize * 8) return 52; /*error, bit pointer will jump past memory*/
+    BFINAL = readBitFromStream(&bp, in);
+    BTYPE = 1u * readBitFromStream(&bp, in);
+    BTYPE += 2u * readBitFromStream(&bp, in);
+
+    if(BTYPE == 3) return 20; /*error: invalid BTYPE*/
+    else if(BTYPE == 0) error = inflateNoCompression(out, in, &bp, &pos, insize); /*no compression*/
+    else error = inflateHuffmanBlock(out, in, &bp, &pos, insize, BTYPE); /*compression, BTYPE 01 or 10*/
+
+    if(error) return error;
+  }
+
+  return error;
+}
+
+unsigned lodepng_inflate(unsigned char** out, size_t* outsize,
+                         const unsigned char* in, size_t insize,
+                         const LodePNGDecompressSettings* settings)
+{
+  unsigned error;
+  ucvector v;
+  ucvector_init_buffer(&v, *out, *outsize);
+  error = lodepng_inflatev(&v, in, insize, settings);
+  *out = v.data;
+  *outsize = v.size;
+  return error;
+}
+
+static unsigned inflate(unsigned char** out, size_t* outsize,
+                        const unsigned char* in, size_t insize,
+                        const LodePNGDecompressSettings* settings)
+{
+  if(settings->custom_inflate)
+  {
+    return settings->custom_inflate(out, outsize, in, insize, settings);
+  }
+  else
+  {
+    return lodepng_inflate(out, outsize, in, insize, settings);
+  }
+}
+
+#endif /*LODEPNG_COMPILE_DECODER*/
+
+#ifdef LODEPNG_COMPILE_ENCODER
+
+/* ////////////////////////////////////////////////////////////////////////// */
+/* / Deflator (Compressor)                                                  / */
+/* ////////////////////////////////////////////////////////////////////////// */
+
+static const size_t MAX_SUPPORTED_DEFLATE_LENGTH = 258;
+
+/*bitlen is the size in bits of the code*/
+static void addHuffmanSymbol(size_t* bp, ucvector* compressed, unsigned code, unsigned bitlen)
+{
+  addBitsToStreamReversed(bp, compressed, code, bitlen);
+}
+
+/*search the index in the array, that has the largest value smaller than or equal to the given value,
+given array must be sorted (if no value is smaller, it returns the size of the given array)*/
+static size_t searchCodeIndex(const unsigned* array, size_t array_size, size_t value)
+{
+  /*linear search implementation*/
+  /*for(size_t i = 1; i < array_size; ++i) if(array[i] > value) return i - 1;
+  return array_size - 1;*/
+
+  /*binary search implementation (not that much faster) (precondition: array_size > 0)*/
+  size_t left  = 1;
+  size_t right = array_size - 1;
+  while(left <= right)
+  {
+    size_t mid = (left + right) / 2;
+    if(array[mid] <= value) left = mid + 1; /*the value to find is more to the right*/
+    else if(array[mid - 1] > value) right = mid - 1; /*the value to find is more to the left*/
+    else return mid - 1;
+  }
+  return array_size - 1;
+}
+
+static void addLengthDistance(uivector* values, size_t length, size_t distance)
+{
+  /*values in encoded vector are those used by deflate:
+  0-255: literal bytes
+  256: end
+  257-285: length/distance pair (length code, followed by extra length bits, distance code, extra distance bits)
+  286-287: invalid*/
+
+  unsigned length_code = (unsigned)searchCodeIndex(LENGTHBASE, 29, length);
+  unsigned extra_length = (unsigned)(length - LENGTHBASE[length_code]);
+  unsigned dist_code = (unsigned)searchCodeIndex(DISTANCEBASE, 30, distance);
+  unsigned extra_distance = (unsigned)(distance - DISTANCEBASE[dist_code]);
+
+  uivector_push_back(values, length_code + FIRST_LENGTH_CODE_INDEX);
+  uivector_push_back(values, extra_length);
+  uivector_push_back(values, dist_code);
+  uivector_push_back(values, extra_distance);
+}
+
+/*3 bytes of data get encoded into two bytes. The hash cannot use more than 3
+bytes as input because 3 is the minimum match length for deflate*/
+static const unsigned HASH_NUM_VALUES = 65536;
+static const unsigned HASH_BIT_MASK = 65535; /*HASH_NUM_VALUES - 1, but C90 does not like that as initializer*/
+
+typedef struct Hash
+{
+  int* head; /*hash value to head circular pos - can be outdated if went around window*/
+  /*circular pos to prev circular pos*/
+  unsigned short* chain;
+  int* val; /*circular pos to hash value*/
+
+  /*TODO: do this not only for zeros but for any repeated byte. However for PNG
+  it's always going to be the zeros that dominate, so not important for PNG*/
+  int* headz; /*similar to head, but for chainz*/
+  unsigned short* chainz; /*those with same amount of zeros*/
+  unsigned short* zeros; /*length of zeros streak, used as a second hash chain*/
+} Hash;
+
+static unsigned hash_init(Hash* hash, unsigned windowsize)
+{
+  unsigned i;
+  hash->head = (int*)lodepng_malloc(sizeof(int) * HASH_NUM_VALUES);
+  hash->val = (int*)lodepng_malloc(sizeof(int) * windowsize);
+  hash->chain = (unsigned short*)lodepng_malloc(sizeof(unsigned short) * windowsize);
+
+  hash->zeros = (unsigned short*)lodepng_malloc(sizeof(unsigned short) * windowsize);
+  hash->headz = (int*)lodepng_malloc(sizeof(int) * (MAX_SUPPORTED_DEFLATE_LENGTH + 1));
+  hash->chainz = (unsigned short*)lodepng_malloc(sizeof(unsigned short) * windowsize);
+
+  if(!hash->head || !hash->chain || !hash->val  || !hash->headz|| !hash->chainz || !hash->zeros)
+  {
+    return 83; /*alloc fail*/
+  }
+
+  /*initialize hash table*/
+  for(i = 0; i != HASH_NUM_VALUES; ++i) hash->head[i] = -1;
+  for(i = 0; i != windowsize; ++i) hash->val[i] = -1;
+  for(i = 0; i != windowsize; ++i) hash->chain[i] = i; /*same value as index indicates uninitialized*/
+
+  for(i = 0; i <= MAX_SUPPORTED_DEFLATE_LENGTH; ++i) hash->headz[i] = -1;
+  for(i = 0; i != windowsize; ++i) hash->chainz[i] = i; /*same value as index indicates uninitialized*/
+
+  return 0;
+}
+
+static void hash_cleanup(Hash* hash)
+{
+  lodepng_free(hash->head);
+  lodepng_free(hash->val);
+  lodepng_free(hash->chain);
+
+  lodepng_free(hash->zeros);
+  lodepng_free(hash->headz);
+  lodepng_free(hash->chainz);
+}
+
+
+
+static unsigned getHash(const unsigned char* data, size_t size, size_t pos)
+{
+  unsigned result = 0;
+  if(pos + 2 < size)
+  {
+    /*A simple shift and xor hash is used. Since the data of PNGs is dominated
+    by zeroes due to the filters, a better hash does not have a significant
+    effect on speed in traversing the chain, and causes more time spend on
+    calculating the hash.*/
+    result ^= (unsigned)(data[pos + 0] << 0u);
+    result ^= (unsigned)(data[pos + 1] << 4u);
+    result ^= (unsigned)(data[pos + 2] << 8u);
+  } else {
+    size_t amount, i;
+    if(pos >= size) return 0;
+    amount = size - pos;
+    for(i = 0; i != amount; ++i) result ^= (unsigned)(data[pos + i] << (i * 8u));
+  }
+  return result & HASH_BIT_MASK;
+}
+
+static unsigned countZeros(const unsigned char* data, size_t size, size_t pos)
+{
+  const unsigned char* start = data + pos;
+  const unsigned char* end = start + MAX_SUPPORTED_DEFLATE_LENGTH;
+  if(end > data + size) end = data + size;
+  data = start;
+  while(data != end && *data == 0) ++data;
+  /*subtracting two addresses returned as 32-bit number (max value is MAX_SUPPORTED_DEFLATE_LENGTH)*/
+  return (unsigned)(data - start);
+}
+
+/*wpos = pos & (windowsize - 1)*/
+static void updateHashChain(Hash* hash, size_t wpos, unsigned hashval, unsigned short numzeros)
+{
+  hash->val[wpos] = (int)hashval;
+  if(hash->head[hashval] != -1) hash->chain[wpos] = hash->head[hashval];
+  hash->head[hashval] = wpos;
+
+  hash->zeros[wpos] = numzeros;
+  if(hash->headz[numzeros] != -1) hash->chainz[wpos] = hash->headz[numzeros];
+  hash->headz[numzeros] = wpos;
+}
+
+/*
+LZ77-encode the data. Return value is error code. The input are raw bytes, the output
+is in the form of unsigned integers with codes representing for example literal bytes, or
+length/distance pairs.
+It uses a hash table technique to let it encode faster. When doing LZ77 encoding, a
+sliding window (of windowsize) is used, and all past bytes in that window can be used as
+the "dictionary". A brute force search through all possible distances would be slow, and
+this hash technique is one out of several ways to speed this up.
+*/
+static unsigned encodeLZ77(uivector* out, Hash* hash,
+                           const unsigned char* in, size_t inpos, size_t insize, unsigned windowsize,
+                           unsigned minmatch, unsigned nicematch, unsigned lazymatching)
+{
+  size_t pos;
+  unsigned i, error = 0;
+  /*for large window lengths, assume the user wants no compression loss. Otherwise, max hash chain length speedup.*/
+  unsigned maxchainlength = windowsize >= 8192 ? windowsize : windowsize / 8;
+  unsigned maxlazymatch = windowsize >= 8192 ? MAX_SUPPORTED_DEFLATE_LENGTH : 64;
+
+  unsigned usezeros = 1; /*not sure if setting it to false for windowsize < 8192 is better or worse*/
+  unsigned numzeros = 0;
+
+  unsigned offset; /*the offset represents the distance in LZ77 terminology*/
+  unsigned length;
+  unsigned lazy = 0;
+  unsigned lazylength = 0, lazyoffset = 0;
+  unsigned hashval;
+  unsigned current_offset, current_length;
+  unsigned prev_offset;
+  const unsigned char *lastptr, *foreptr, *backptr;
+  unsigned hashpos;
+
+  if(windowsize == 0 || windowsize > 32768) return 60; /*error: windowsize smaller/larger than allowed*/
+  if((windowsize & (windowsize - 1)) != 0) return 90; /*error: must be power of two*/
+
+  if(nicematch > MAX_SUPPORTED_DEFLATE_LENGTH) nicematch = MAX_SUPPORTED_DEFLATE_LENGTH;
+
+  for(pos = inpos; pos < insize; ++pos)
+  {
+    size_t wpos = pos & (windowsize - 1); /*position for in 'circular' hash buffers*/
+    unsigned chainlength = 0;
+
+    hashval = getHash(in, insize, pos);
+
+    if(usezeros && hashval == 0)
+    {
+      if(numzeros == 0) numzeros = countZeros(in, insize, pos);
+      else if(pos + numzeros > insize || in[pos + numzeros - 1] != 0) --numzeros;
+    }
+    else
+    {
+      numzeros = 0;
+    }
+
+    updateHashChain(hash, wpos, hashval, numzeros);
+
+    /*the length and offset found for the current position*/
+    length = 0;
+    offset = 0;
+
+    hashpos = hash->chain[wpos];
+
+    lastptr = &in[insize < pos + MAX_SUPPORTED_DEFLATE_LENGTH ? insize : pos + MAX_SUPPORTED_DEFLATE_LENGTH];
+
+    /*search for the longest string*/
+    prev_offset = 0;
+    for(;;)
+    {
+      if(chainlength++ >= maxchainlength) break;
+      current_offset = hashpos <= wpos ? wpos - hashpos : wpos - hashpos + windowsize;
+
+      if(current_offset < prev_offset) break; /*stop when went completely around the circular buffer*/
+      prev_offset = current_offset;
+      if(current_offset > 0)
+      {
+        /*test the next characters*/
+        foreptr = &in[pos];
+        backptr = &in[pos - current_offset];
+
+        /*common case in PNGs is lots of zeros. Quickly skip over them as a speedup*/
+        if(numzeros >= 3)
+        {
+          unsigned skip = hash->zeros[hashpos];
+          if(skip > numzeros) skip = numzeros;
+          backptr += skip;
+          foreptr += skip;
+        }
+
+        while(foreptr != lastptr && *backptr == *foreptr) /*maximum supported length by deflate is max length*/
+        {
+          ++backptr;
+          ++foreptr;
+        }
+        current_length = (unsigned)(foreptr - &in[pos]);
+
+        if(current_length > length)
+        {
+          length = current_length; /*the longest length*/
+          offset = current_offset; /*the offset that is related to this longest length*/
+          /*jump out once a length of max length is found (speed gain). This also jumps
+          out if length is MAX_SUPPORTED_DEFLATE_LENGTH*/
+          if(current_length >= nicematch) break;
+        }
+      }
+
+      if(hashpos == hash->chain[hashpos]) break;
+
+      if(numzeros >= 3 && length > numzeros)
+      {
+        hashpos = hash->chainz[hashpos];
+        if(hash->zeros[hashpos] != numzeros) break;
+      }
+      else
+      {
+        hashpos = hash->chain[hashpos];
+        /*outdated hash value, happens if particular value was not encountered in whole last window*/
+        if(hash->val[hashpos] != (int)hashval) break;
+      }
+    }
+
+    if(lazymatching)
+    {
+      if(!lazy && length >= 3 && length <= maxlazymatch && length < MAX_SUPPORTED_DEFLATE_LENGTH)
+      {
+        lazy = 1;
+        lazylength = length;
+        lazyoffset = offset;
+        continue; /*try the next byte*/
+      }
+      if(lazy)
+      {
+        lazy = 0;
+        if(pos == 0) ERROR_BREAK(81);
+        if(length > lazylength + 1)
+        {
+          /*push the previous character as literal*/
+          if(!uivector_push_back(out, in[pos - 1])) ERROR_BREAK(83 /*alloc fail*/);
+        }
+        else
+        {
+          length = lazylength;
+          offset = lazyoffset;
+          hash->head[hashval] = -1; /*the same hashchain update will be done, this ensures no wrong alteration*/
+          hash->headz[numzeros] = -1; /*idem*/
+          --pos;
+        }
+      }
+    }
+    if(length >= 3 && offset > windowsize) ERROR_BREAK(86 /*too big (or overflown negative) offset*/);
+
+    /*encode it as length/distance pair or literal value*/
+    if(length < 3) /*only lengths of 3 or higher are supported as length/distance pair*/
+    {
+      if(!uivector_push_back(out, in[pos])) ERROR_BREAK(83 /*alloc fail*/);
+    }
+    else if(length < minmatch || (length == 3 && offset > 4096))
+    {
+      /*compensate for the fact that longer offsets have more extra bits, a
+      length of only 3 may be not worth it then*/
+      if(!uivector_push_back(out, in[pos])) ERROR_BREAK(83 /*alloc fail*/);
+    }
+    else
+    {
+      addLengthDistance(out, length, offset);
+      for(i = 1; i < length; ++i)
+      {
+        ++pos;
+        wpos = pos & (windowsize - 1);
+        hashval = getHash(in, insize, pos);
+        if(usezeros && hashval == 0)
+        {
+          if(numzeros == 0) numzeros = countZeros(in, insize, pos);
+          else if(pos + numzeros > insize || in[pos + numzeros - 1] != 0) --numzeros;
+        }
+        else
+        {
+          numzeros = 0;
+        }
+        updateHashChain(hash, wpos, hashval, numzeros);
+      }
+    }
+  } /*end of the loop through each character of input*/
+
+  return error;
+}
+
+/* /////////////////////////////////////////////////////////////////////////// */
+
+static unsigned deflateNoCompression(ucvector* out, const unsigned char* data, size_t datasize)
+{
+  /*non compressed deflate block data: 1 bit BFINAL,2 bits BTYPE,(5 bits): it jumps to start of next byte,
+  2 bytes LEN, 2 bytes NLEN, LEN bytes literal DATA*/
+
+  size_t i, j, numdeflateblocks = (datasize + 65534) / 65535;
+  unsigned datapos = 0;
+  for(i = 0; i != numdeflateblocks; ++i)
+  {
+    unsigned BFINAL, BTYPE, LEN, NLEN;
+    unsigned char firstbyte;
+
+    BFINAL = (i == numdeflateblocks - 1);
+    BTYPE = 0;
+
+    firstbyte = (unsigned char)(BFINAL + ((BTYPE & 1) << 1) + ((BTYPE & 2) << 1));
+    ucvector_push_back(out, firstbyte);
+
+    LEN = 65535;
+    if(datasize - datapos < 65535) LEN = (unsigned)datasize - datapos;
+    NLEN = 65535 - LEN;
+
+    ucvector_push_back(out, (unsigned char)(LEN % 256));
+    ucvector_push_back(out, (unsigned char)(LEN / 256));
+    ucvector_push_back(out, (unsigned char)(NLEN % 256));
+    ucvector_push_back(out, (unsigned char)(NLEN / 256));
+
+    /*Decompressed data*/
+    for(j = 0; j < 65535 && datapos < datasize; ++j)
+    {
+      ucvector_push_back(out, data[datapos++]);
+    }
+  }
+
+  return 0;
+}
+
+/*
+write the lz77-encoded data, which has lit, len and dist codes, to compressed stream using huffman trees.
+tree_ll: the tree for lit and len codes.
+tree_d: the tree for distance codes.
+*/
+static void writeLZ77data(size_t* bp, ucvector* out, const uivector* lz77_encoded,
+                          const HuffmanTree* tree_ll, const HuffmanTree* tree_d)
+{
+  size_t i = 0;
+  for(i = 0; i != lz77_encoded->size; ++i)
+  {
+    unsigned val = lz77_encoded->data[i];
+    addHuffmanSymbol(bp, out, HuffmanTree_getCode(tree_ll, val), HuffmanTree_getLength(tree_ll, val));
+    if(val > 256) /*for a length code, 3 more things have to be added*/
+    {
+      unsigned length_index = val - FIRST_LENGTH_CODE_INDEX;
+      unsigned n_length_extra_bits = LENGTHEXTRA[length_index];
+      unsigned length_extra_bits = lz77_encoded->data[++i];
+
+      unsigned distance_code = lz77_encoded->data[++i];
+
+      unsigned distance_index = distance_code;
+      unsigned n_distance_extra_bits = DISTANCEEXTRA[distance_index];
+      unsigned distance_extra_bits = lz77_encoded->data[++i];
+
+      addBitsToStream(bp, out, length_extra_bits, n_length_extra_bits);
+      addHuffmanSymbol(bp, out, HuffmanTree_getCode(tree_d, distance_code),
+                       HuffmanTree_getLength(tree_d, distance_code));
+      addBitsToStream(bp, out, distance_extra_bits, n_distance_extra_bits);
+    }
+  }
+}
+
+/*Deflate for a block of type "dynamic", that is, with freely, optimally, created huffman trees*/
+static unsigned deflateDynamic(ucvector* out, size_t* bp, Hash* hash,
+                               const unsigned char* data, size_t datapos, size_t dataend,
+                               const LodePNGCompressSettings* settings, unsigned final)
+{
+  unsigned error = 0;
+
+  /*
+  A block is compressed as follows: The PNG data is lz77 encoded, resulting in
+  literal bytes and length/distance pairs. This is then huffman compressed with
+  two huffman trees. One huffman tree is used for the lit and len values ("ll"),
+  another huffman tree is used for the dist values ("d"). These two trees are
+  stored using their code lengths, and to compress even more these code lengths
+  are also run-length encoded and huffman compressed. This gives a huffman tree
+  of code lengths "cl". The code lenghts used to describe this third tree are
+  the code length code lengths ("clcl").
+  */
+
+  /*The lz77 encoded data, represented with integers since there will also be length and distance codes in it*/
+  uivector lz77_encoded;
+  HuffmanTree tree_ll; /*tree for lit,len values*/
+  HuffmanTree tree_d; /*tree for distance codes*/
+  HuffmanTree tree_cl; /*tree for encoding the code lengths representing tree_ll and tree_d*/
+  uivector frequencies_ll; /*frequency of lit,len codes*/
+  uivector frequencies_d; /*frequency of dist codes*/
+  uivector frequencies_cl; /*frequency of code length codes*/
+  uivector bitlen_lld; /*lit,len,dist code lenghts (int bits), literally (without repeat codes).*/
+  uivector bitlen_lld_e; /*bitlen_lld encoded with repeat codes (this is a rudemtary run length compression)*/
+  /*bitlen_cl is the code length code lengths ("clcl"). The bit lengths of codes to represent tree_cl
+  (these are written as is in the file, it would be crazy to compress these using yet another huffman
+  tree that needs to be represented by yet another set of code lengths)*/
+  uivector bitlen_cl;
+  size_t datasize = dataend - datapos;
+
+  /*
+  Due to the huffman compression of huffman tree representations ("two levels"), there are some anologies:
+  bitlen_lld is to tree_cl what data is to tree_ll and tree_d.
+  bitlen_lld_e is to bitlen_lld what lz77_encoded is to data.
+  bitlen_cl is to bitlen_lld_e what bitlen_lld is to lz77_encoded.
+  */
+
+  unsigned BFINAL = final;
+  size_t numcodes_ll, numcodes_d, i;
+  unsigned HLIT, HDIST, HCLEN;
+
+  uivector_init(&lz77_encoded);
+  HuffmanTree_init(&tree_ll);
+  HuffmanTree_init(&tree_d);
+  HuffmanTree_init(&tree_cl);
+  uivector_init(&frequencies_ll);
+  uivector_init(&frequencies_d);
+  uivector_init(&frequencies_cl);
+  uivector_init(&bitlen_lld);
+  uivector_init(&bitlen_lld_e);
+  uivector_init(&bitlen_cl);
+
+  /*This while loop never loops due to a break at the end, it is here to
+  allow breaking out of it to the cleanup phase on error conditions.*/
+  while(!error)
+  {
+    if(settings->use_lz77)
+    {
+      error = encodeLZ77(&lz77_encoded, hash, data, datapos, dataend, settings->windowsize,
+                         settings->minmatch, settings->nicematch, settings->lazymatching);
+      if(error) break;
+    }
+    else
+    {
+      if(!uivector_resize(&lz77_encoded, datasize)) ERROR_BREAK(83 /*alloc fail*/);
+      for(i = datapos; i < dataend; ++i) lz77_encoded.data[i] = data[i]; /*no LZ77, but still will be Huffman compressed*/
+    }
+
+    if(!uivector_resizev(&frequencies_ll, 286, 0)) ERROR_BREAK(83 /*alloc fail*/);
+    if(!uivector_resizev(&frequencies_d, 30, 0)) ERROR_BREAK(83 /*alloc fail*/);
+
+    /*Count the frequencies of lit, len and dist codes*/
+    for(i = 0; i != lz77_encoded.size; ++i)
+    {
+      unsigned symbol = lz77_encoded.data[i];
+      ++frequencies_ll.data[symbol];
+      if(symbol > 256)
+      {
+        unsigned dist = lz77_encoded.data[i + 2];
+        ++frequencies_d.data[dist];
+        i += 3;
+      }
+    }
+    frequencies_ll.data[256] = 1; /*there will be exactly 1 end code, at the end of the block*/
+
+    /*Make both huffman trees, one for the lit and len codes, one for the dist codes*/
+    error = HuffmanTree_makeFromFrequencies(&tree_ll, frequencies_ll.data, 257, frequencies_ll.size, 15);
+    if(error) break;
+    /*2, not 1, is chosen for mincodes: some buggy PNG decoders require at least 2 symbols in the dist tree*/
+    error = HuffmanTree_makeFromFrequencies(&tree_d, frequencies_d.data, 2, frequencies_d.size, 15);
+    if(error) break;
+
+    numcodes_ll = tree_ll.numcodes; if(numcodes_ll > 286) numcodes_ll = 286;
+    numcodes_d = tree_d.numcodes; if(numcodes_d > 30) numcodes_d = 30;
+    /*store the code lengths of both generated trees in bitlen_lld*/
+    for(i = 0; i != numcodes_ll; ++i) uivector_push_back(&bitlen_lld, HuffmanTree_getLength(&tree_ll, (unsigned)i));
+    for(i = 0; i != numcodes_d; ++i) uivector_push_back(&bitlen_lld, HuffmanTree_getLength(&tree_d, (unsigned)i));
+
+    /*run-length compress bitlen_ldd into bitlen_lld_e by using repeat codes 16 (copy length 3-6 times),
+    17 (3-10 zeroes), 18 (11-138 zeroes)*/
+    for(i = 0; i != (unsigned)bitlen_lld.size; ++i)
+    {
+      unsigned j = 0; /*amount of repititions*/
+      while(i + j + 1 < (unsigned)bitlen_lld.size && bitlen_lld.data[i + j + 1] == bitlen_lld.data[i]) ++j;
+
+      if(bitlen_lld.data[i] == 0 && j >= 2) /*repeat code for zeroes*/
+      {
+        ++j; /*include the first zero*/
+        if(j <= 10) /*repeat code 17 supports max 10 zeroes*/
+        {
+          uivector_push_back(&bitlen_lld_e, 17);
+          uivector_push_back(&bitlen_lld_e, j - 3);
+        }
+        else /*repeat code 18 supports max 138 zeroes*/
+        {
+          if(j > 138) j = 138;
+          uivector_push_back(&bitlen_lld_e, 18);
+          uivector_push_back(&bitlen_lld_e, j - 11);
+        }
+        i += (j - 1);
+      }
+      else if(j >= 3) /*repeat code for value other than zero*/
+      {
+        size_t k;
+        unsigned num = j / 6, rest = j % 6;
+        uivector_push_back(&bitlen_lld_e, bitlen_lld.data[i]);
+        for(k = 0; k < num; ++k)
+        {
+          uivector_push_back(&bitlen_lld_e, 16);
+          uivector_push_back(&bitlen_lld_e, 6 - 3);
+        }
+        if(rest >= 3)
+        {
+          uivector_push_back(&bitlen_lld_e, 16);
+          uivector_push_back(&bitlen_lld_e, rest - 3);
+        }
+        else j -= rest;
+        i += j;
+      }
+      else /*too short to benefit from repeat code*/
+      {
+        uivector_push_back(&bitlen_lld_e, bitlen_lld.data[i]);
+      }
+    }
+
+    /*generate tree_cl, the huffmantree of huffmantrees*/
+
+    if(!uivector_resizev(&frequencies_cl, NUM_CODE_LENGTH_CODES, 0)) ERROR_BREAK(83 /*alloc fail*/);
+    for(i = 0; i != bitlen_lld_e.size; ++i)
+    {
+      ++frequencies_cl.data[bitlen_lld_e.data[i]];
+      /*after a repeat code come the bits that specify the number of repetitions,
+      those don't need to be in the frequencies_cl calculation*/
+      if(bitlen_lld_e.data[i] >= 16) ++i;
+    }
+
+    error = HuffmanTree_makeFromFrequencies(&tree_cl, frequencies_cl.data,
+                                            frequencies_cl.size, frequencies_cl.size, 7);
+    if(error) break;
+
+    if(!uivector_resize(&bitlen_cl, tree_cl.numcodes)) ERROR_BREAK(83 /*alloc fail*/);
+    for(i = 0; i != tree_cl.numcodes; ++i)
+    {
+      /*lenghts of code length tree is in the order as specified by deflate*/
+      bitlen_cl.data[i] = HuffmanTree_getLength(&tree_cl, CLCL_ORDER[i]);
+    }
+    while(bitlen_cl.data[bitlen_cl.size - 1] == 0 && bitlen_cl.size > 4)
+    {
+      /*remove zeros at the end, but minimum size must be 4*/
+      if(!uivector_resize(&bitlen_cl, bitlen_cl.size - 1)) ERROR_BREAK(83 /*alloc fail*/);
+    }
+    if(error) break;
+
+    /*
+    Write everything into the output
+
+    After the BFINAL and BTYPE, the dynamic block consists out of the following:
+    - 5 bits HLIT, 5 bits HDIST, 4 bits HCLEN
+    - (HCLEN+4)*3 bits code lengths of code length alphabet
+    - HLIT + 257 code lenghts of lit/length alphabet (encoded using the code length
+      alphabet, + possible repetition codes 16, 17, 18)
+    - HDIST + 1 code lengths of distance alphabet (encoded using the code length
+      alphabet, + possible repetition codes 16, 17, 18)
+    - compressed data
+    - 256 (end code)
+    */
+
+    /*Write block type*/
+    addBitToStream(bp, out, BFINAL);
+    addBitToStream(bp, out, 0); /*first bit of BTYPE "dynamic"*/
+    addBitToStream(bp, out, 1); /*second bit of BTYPE "dynamic"*/
+
+    /*write the HLIT, HDIST and HCLEN values*/
+    HLIT = (unsigned)(numcodes_ll - 257);
+    HDIST = (unsigned)(numcodes_d - 1);
+    HCLEN = (unsigned)bitlen_cl.size - 4;
+    /*trim zeroes for HCLEN. HLIT and HDIST were already trimmed at tree creation*/
+    while(!bitlen_cl.data[HCLEN + 4 - 1] && HCLEN > 0) --HCLEN;
+    addBitsToStream(bp, out, HLIT, 5);
+    addBitsToStream(bp, out, HDIST, 5);
+    addBitsToStream(bp, out, HCLEN, 4);
+
+    /*write the code lenghts of the code length alphabet*/
+    for(i = 0; i != HCLEN + 4; ++i) addBitsToStream(bp, out, bitlen_cl.data[i], 3);
+
+    /*write the lenghts of the lit/len AND the dist alphabet*/
+    for(i = 0; i != bitlen_lld_e.size; ++i)
+    {
+      addHuffmanSymbol(bp, out, HuffmanTree_getCode(&tree_cl, bitlen_lld_e.data[i]),
+                       HuffmanTree_getLength(&tree_cl, bitlen_lld_e.data[i]));
+      /*extra bits of repeat codes*/
+      if(bitlen_lld_e.data[i] == 16) addBitsToStream(bp, out, bitlen_lld_e.data[++i], 2);
+      else if(bitlen_lld_e.data[i] == 17) addBitsToStream(bp, out, bitlen_lld_e.data[++i], 3);
+      else if(bitlen_lld_e.data[i] == 18) addBitsToStream(bp, out, bitlen_lld_e.data[++i], 7);
+    }
+
+    /*write the compressed data symbols*/
+    writeLZ77data(bp, out, &lz77_encoded, &tree_ll, &tree_d);
+    /*error: the length of the end code 256 must be larger than 0*/
+    if(HuffmanTree_getLength(&tree_ll, 256) == 0) ERROR_BREAK(64);
+
+    /*write the end code*/
+    addHuffmanSymbol(bp, out, HuffmanTree_getCode(&tree_ll, 256), HuffmanTree_getLength(&tree_ll, 256));
+
+    break; /*end of error-while*/
+  }
+
+  /*cleanup*/
+  uivector_cleanup(&lz77_encoded);
+  HuffmanTree_cleanup(&tree_ll);
+  HuffmanTree_cleanup(&tree_d);
+  HuffmanTree_cleanup(&tree_cl);
+  uivector_cleanup(&frequencies_ll);
+  uivector_cleanup(&frequencies_d);
+  uivector_cleanup(&frequencies_cl);
+  uivector_cleanup(&bitlen_lld_e);
+  uivector_cleanup(&bitlen_lld);
+  uivector_cleanup(&bitlen_cl);
+
+  return error;
+}
+
+static unsigned deflateFixed(ucvector* out, size_t* bp, Hash* hash,
+                             const unsigned char* data,
+                             size_t datapos, size_t dataend,
+                             const LodePNGCompressSettings* settings, unsigned final)
+{
+  HuffmanTree tree_ll; /*tree for literal values and length codes*/
+  HuffmanTree tree_d; /*tree for distance codes*/
+
+  unsigned BFINAL = final;
+  unsigned error = 0;
+  size_t i;
+
+  HuffmanTree_init(&tree_ll);
+  HuffmanTree_init(&tree_d);
+
+  generateFixedLitLenTree(&tree_ll);
+  generateFixedDistanceTree(&tree_d);
+
+  addBitToStream(bp, out, BFINAL);
+  addBitToStream(bp, out, 1); /*first bit of BTYPE*/
+  addBitToStream(bp, out, 0); /*second bit of BTYPE*/
+
+  if(settings->use_lz77) /*LZ77 encoded*/
+  {
+    uivector lz77_encoded;
+    uivector_init(&lz77_encoded);
+    error = encodeLZ77(&lz77_encoded, hash, data, datapos, dataend, settings->windowsize,
+                       settings->minmatch, settings->nicematch, settings->lazymatching);
+    if(!error) writeLZ77data(bp, out, &lz77_encoded, &tree_ll, &tree_d);
+    uivector_cleanup(&lz77_encoded);
+  }
+  else /*no LZ77, but still will be Huffman compressed*/
+  {
+    for(i = datapos; i < dataend; ++i)
+    {
+      addHuffmanSymbol(bp, out, HuffmanTree_getCode(&tree_ll, data[i]), HuffmanTree_getLength(&tree_ll, data[i]));
+    }
+  }
+  /*add END code*/
+  if(!error) addHuffmanSymbol(bp, out, HuffmanTree_getCode(&tree_ll, 256), HuffmanTree_getLength(&tree_ll, 256));
+
+  /*cleanup*/
+  HuffmanTree_cleanup(&tree_ll);
+  HuffmanTree_cleanup(&tree_d);
+
+  return error;
+}
+
+static unsigned lodepng_deflatev(ucvector* out, const unsigned char* in, size_t insize,
+                                 const LodePNGCompressSettings* settings)
+{
+  unsigned error = 0;
+  size_t i, blocksize, numdeflateblocks;
+  size_t bp = 0; /*the bit pointer*/
+  Hash hash;
+
+  if(settings->btype > 2) return 61;
+  else if(settings->btype == 0) return deflateNoCompression(out, in, insize);
+  else if(settings->btype == 1) blocksize = insize;
+  else /*if(settings->btype == 2)*/
+  {
+    /*on PNGs, deflate blocks of 65-262k seem to give most dense encoding*/
+    blocksize = insize / 8 + 8;
+    if(blocksize < 65536) blocksize = 65536;
+    if(blocksize > 262144) blocksize = 262144;
+  }
+
+  numdeflateblocks = (insize + blocksize - 1) / blocksize;
+  if(numdeflateblocks == 0) numdeflateblocks = 1;
+
+  error = hash_init(&hash, settings->windowsize);
+  if(error) return error;
+
+  for(i = 0; i != numdeflateblocks && !error; ++i)
+  {
+    unsigned final = (i == numdeflateblocks - 1);
+    size_t start = i * blocksize;
+    size_t end = start + blocksize;
+    if(end > insize) end = insize;
+
+    if(settings->btype == 1) error = deflateFixed(out, &bp, &hash, in, start, end, settings, final);
+    else if(settings->btype == 2) error = deflateDynamic(out, &bp, &hash, in, start, end, settings, final);
+  }
+
+  hash_cleanup(&hash);
+
+  return error;
+}
+
+unsigned lodepng_deflate(unsigned char** out, size_t* outsize,
+                         const unsigned char* in, size_t insize,
+                         const LodePNGCompressSettings* settings)
+{
+  unsigned error;
+  ucvector v;
+  ucvector_init_buffer(&v, *out, *outsize);
+  error = lodepng_deflatev(&v, in, insize, settings);
+  *out = v.data;
+  *outsize = v.size;
+  return error;
+}
+
+static unsigned deflate(unsigned char** out, size_t* outsize,
+                        const unsigned char* in, size_t insize,
+                        const LodePNGCompressSettings* settings)
+{
+  if(settings->custom_deflate)
+  {
+    return settings->custom_deflate(out, outsize, in, insize, settings);
+  }
+  else
+  {
+    return lodepng_deflate(out, outsize, in, insize, settings);
+  }
+}
+
+#endif /*LODEPNG_COMPILE_DECODER*/
+
+/* ////////////////////////////////////////////////////////////////////////// */
+/* / Adler32                                                                  */
+/* ////////////////////////////////////////////////////////////////////////// */
+
+static unsigned update_adler32(unsigned adler, const unsigned char* data, unsigned len)
+{
+   unsigned s1 = adler & 0xffff;
+   unsigned s2 = (adler >> 16) & 0xffff;
+
+  while(len > 0)
+  {
+    /*at least 5550 sums can be done before the sums overflow, saving a lot of module divisions*/
+    unsigned amount = len > 5550 ? 5550 : len;
+    len -= amount;
+    while(amount > 0)
+    {
+      s1 += (*data++);
+      s2 += s1;
+      --amount;
+    }
+    s1 %= 65521;
+    s2 %= 65521;
+  }
+
+  return (s2 << 16) | s1;
+}
+
+/*Return the adler32 of the bytes data[0..len-1]*/
+static unsigned adler32(const unsigned char* data, unsigned len)
+{
+  return update_adler32(1L, data, len);
+}
+
+/* ////////////////////////////////////////////////////////////////////////// */
+/* / Zlib                                                                   / */
+/* ////////////////////////////////////////////////////////////////////////// */
+
+#ifdef LODEPNG_COMPILE_DECODER
+
+unsigned lodepng_zlib_decompress(unsigned char** out, size_t* outsize, const unsigned char* in,
+                                 size_t insize, const LodePNGDecompressSettings* settings)
+{
+  unsigned error = 0;
+  unsigned CM, CINFO, FDICT;
+
+  if(insize < 2) return 53; /*error, size of zlib data too small*/
+  /*read information from zlib header*/
+  if((in[0] * 256 + in[1]) % 31 != 0)
+  {
+    /*error: 256 * in[0] + in[1] must be a multiple of 31, the FCHECK value is supposed to be made that way*/
+    return 24;
+  }
+
+  CM = in[0] & 15;
+  CINFO = (in[0] >> 4) & 15;
+  /*FCHECK = in[1] & 31;*/ /*FCHECK is already tested above*/
+  FDICT = (in[1] >> 5) & 1;
+  /*FLEVEL = (in[1] >> 6) & 3;*/ /*FLEVEL is not used here*/
+
+  if(CM != 8 || CINFO > 7)
+  {
+    /*error: only compression method 8: inflate with sliding window of 32k is supported by the PNG spec*/
+    return 25;
+  }
+  if(FDICT != 0)
+  {
+    /*error: the specification of PNG says about the zlib stream:
+      "The additional flags shall not specify a preset dictionary."*/
+    return 26;
+  }
+
+  error = inflate(out, outsize, in + 2, insize - 2, settings);
+  if(error) return error;
+
+  if(!settings->ignore_adler32)
+  {
+    unsigned ADLER32 = lodepng_read32bitInt(&in[insize - 4]);
+    unsigned checksum = adler32(*out, (unsigned)(*outsize));
+    if(checksum != ADLER32) return 58; /*error, adler checksum not correct, data must be corrupted*/
+  }
+
+  return 0; /*no error*/
+}
+
+static unsigned zlib_decompress(unsigned char** out, size_t* outsize, const unsigned char* in,
+                                size_t insize, const LodePNGDecompressSettings* settings)
+{
+  if(settings->custom_zlib)
+  {
+    return settings->custom_zlib(out, outsize, in, insize, settings);
+  }
+  else
+  {
+    return lodepng_zlib_decompress(out, outsize, in, insize, settings);
+  }
+}
+
+#endif /*LODEPNG_COMPILE_DECODER*/
+
+#ifdef LODEPNG_COMPILE_ENCODER
+
+unsigned lodepng_zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in,
+                               size_t insize, const LodePNGCompressSettings* settings)
+{
+  /*initially, *out must be NULL and outsize 0, if you just give some random *out
+  that's pointing to a non allocated buffer, this'll crash*/
+  ucvector outv;
+  size_t i;
+  unsigned error;
+  unsigned char* deflatedata = 0;
+  size_t deflatesize = 0;
+
+  /*zlib data: 1 byte CMF (CM+CINFO), 1 byte FLG, deflate data, 4 byte ADLER32 checksum of the Decompressed data*/
+  unsigned CMF = 120; /*0b01111000: CM 8, CINFO 7. With CINFO 7, any window size up to 32768 can be used.*/
+  unsigned FLEVEL = 0;
+  unsigned FDICT = 0;
+  unsigned CMFFLG = 256 * CMF + FDICT * 32 + FLEVEL * 64;
+  unsigned FCHECK = 31 - CMFFLG % 31;
+  CMFFLG += FCHECK;
+
+  /*ucvector-controlled version of the output buffer, for dynamic array*/
+  ucvector_init_buffer(&outv, *out, *outsize);
+
+  ucvector_push_back(&outv, (unsigned char)(CMFFLG / 256));
+  ucvector_push_back(&outv, (unsigned char)(CMFFLG % 256));
+
+  error = deflate(&deflatedata, &deflatesize, in, insize, settings);
+
+  if(!error)
+  {
+    unsigned ADLER32 = adler32(in, (unsigned)insize);
+    for(i = 0; i != deflatesize; ++i) ucvector_push_back(&outv, deflatedata[i]);
+    lodepng_free(deflatedata);
+    lodepng_add32bitInt(&outv, ADLER32);
+  }
+
+  *out = outv.data;
+  *outsize = outv.size;
+
+  return error;
+}
+
+/* compress using the default or custom zlib function */
+static unsigned zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in,
+                              size_t insize, const LodePNGCompressSettings* settings)
+{
+  if(settings->custom_zlib)
+  {
+    return settings->custom_zlib(out, outsize, in, insize, settings);
+  }
+  else
+  {
+    return lodepng_zlib_compress(out, outsize, in, insize, settings);
+  }
+}
+
+#endif /*LODEPNG_COMPILE_ENCODER*/
+
+#else /*no LODEPNG_COMPILE_ZLIB*/
+
+#ifdef LODEPNG_COMPILE_DECODER
+static unsigned zlib_decompress(unsigned char** out, size_t* outsize, const unsigned char* in,
+                                size_t insize, const LodePNGDecompressSettings* settings)
+{
+  if(!settings->custom_zlib) return 87; /*no custom zlib function provided */
+  return settings->custom_zlib(out, outsize, in, insize, settings);
+}
+#endif /*LODEPNG_COMPILE_DECODER*/
+#ifdef LODEPNG_COMPILE_ENCODER
+static unsigned zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in,
+                              size_t insize, const LodePNGCompressSettings* settings)
+{
+  if(!settings->custom_zlib) return 87; /*no custom zlib function provided */
+  return settings->custom_zlib(out, outsize, in, insize, settings);
+}
+#endif /*LODEPNG_COMPILE_ENCODER*/
+
+#endif /*LODEPNG_COMPILE_ZLIB*/
+
+/* ////////////////////////////////////////////////////////////////////////// */
+
+#ifdef LODEPNG_COMPILE_ENCODER
+
+/*this is a good tradeoff between speed and compression ratio*/
+#define DEFAULT_WINDOWSIZE 2048
+
+void lodepng_compress_settings_init(LodePNGCompressSettings* settings)
+{
+  /*compress with dynamic huffman tree (not in the mathematical sense, just not the predefined one)*/
+  settings->btype = 2;
+  settings->use_lz77 = 1;
+  settings->windowsize = DEFAULT_WINDOWSIZE;
+  settings->minmatch = 3;
+  settings->nicematch = 128;
+  settings->lazymatching = 1;
+
+  settings->custom_zlib = 0;
+  settings->custom_deflate = 0;
+  settings->custom_context = 0;
+}
+
+const LodePNGCompressSettings lodepng_default_compress_settings = {2, 1, DEFAULT_WINDOWSIZE, 3, 128, 1, 0, 0, 0};
+
+
+#endif /*LODEPNG_COMPILE_ENCODER*/
+
+#ifdef LODEPNG_COMPILE_DECODER
+
+void lodepng_decompress_settings_init(LodePNGDecompressSettings* settings)
+{
+  settings->ignore_adler32 = 0;
+
+  settings->custom_zlib = 0;
+  settings->custom_inflate = 0;
+  settings->custom_context = 0;
+}
+
+const LodePNGDecompressSettings lodepng_default_decompress_settings = {0, 0, 0, 0};
+
+#endif /*LODEPNG_COMPILE_DECODER*/
+
+/* ////////////////////////////////////////////////////////////////////////// */
+/* ////////////////////////////////////////////////////////////////////////// */
+/* // End of Zlib related code. Begin of PNG related code.                 // */
+/* ////////////////////////////////////////////////////////////////////////// */
+/* ////////////////////////////////////////////////////////////////////////// */
+
+#ifdef LODEPNG_COMPILE_PNG
+
+/* ////////////////////////////////////////////////////////////////////////// */
+/* / CRC32                                                                  / */
+/* ////////////////////////////////////////////////////////////////////////// */
+
+
+#ifndef LODEPNG_NO_COMPILE_CRC
+/* CRC polynomial: 0xedb88320 */
+static unsigned lodepng_crc32_table[256] = {
+           0u, 1996959894u, 3993919788u, 2567524794u,  124634137u, 1886057615u, 3915621685u, 2657392035u,
+   249268274u, 2044508324u, 3772115230u, 2547177864u,  162941995u, 2125561021u, 3887607047u, 2428444049u,
+   498536548u, 1789927666u, 4089016648u, 2227061214u,  450548861u, 1843258603u, 4107580753u, 2211677639u,
+   325883990u, 1684777152u, 4251122042u, 2321926636u,  335633487u, 1661365465u, 4195302755u, 2366115317u,
+   997073096u, 1281953886u, 3579855332u, 2724688242u, 1006888145u, 1258607687u, 3524101629u, 2768942443u,
+   901097722u, 1119000684u, 3686517206u, 2898065728u,  853044451u, 1172266101u, 3705015759u, 2882616665u,
+   651767980u, 1373503546u, 3369554304u, 3218104598u,  565507253u, 1454621731u, 3485111705u, 3099436303u,
+   671266974u, 1594198024u, 3322730930u, 2970347812u,  795835527u, 1483230225u, 3244367275u, 3060149565u,
+  1994146192u,   31158534u, 2563907772u, 4023717930u, 1907459465u,  112637215u, 2680153253u, 3904427059u,
+  2013776290u,  251722036u, 2517215374u, 3775830040u, 2137656763u,  141376813u, 2439277719u, 3865271297u,
+  1802195444u,  476864866u, 2238001368u, 4066508878u, 1812370925u,  453092731u, 2181625025u, 4111451223u,
+  1706088902u,  314042704u, 2344532202u, 4240017532u, 1658658271u,  366619977u, 2362670323u, 4224994405u,
+  1303535960u,  984961486u, 2747007092u, 3569037538u, 1256170817u, 1037604311u, 2765210733u, 3554079995u,
+  1131014506u,  879679996u, 2909243462u, 3663771856u, 1141124467u,  855842277u, 2852801631u, 3708648649u,
+  1342533948u,  654459306u, 3188396048u, 3373015174u, 1466479909u,  544179635u, 3110523913u, 3462522015u,
+  1591671054u,  702138776u, 2966460450u, 3352799412u, 1504918807u,  783551873u, 3082640443u, 3233442989u,
+  3988292384u, 2596254646u,   62317068u, 1957810842u, 3939845945u, 2647816111u,   81470997u, 1943803523u,
+  3814918930u, 2489596804u,  225274430u, 2053790376u, 3826175755u, 2466906013u,  167816743u, 2097651377u,
+  4027552580u, 2265490386u,  503444072u, 1762050814u, 4150417245u, 2154129355u,  426522225u, 1852507879u,
+  4275313526u, 2312317920u,  282753626u, 1742555852u, 4189708143u, 2394877945u,  397917763u, 1622183637u,
+  3604390888u, 2714866558u,  953729732u, 1340076626u, 3518719985u, 2797360999u, 1068828381u, 1219638859u,
+  3624741850u, 2936675148u,  906185462u, 1090812512u, 3747672003u, 2825379669u,  829329135u, 1181335161u,
+  3412177804u, 3160834842u,  628085408u, 1382605366u, 3423369109u, 3138078467u,  570562233u, 1426400815u,
+  3317316542u, 2998733608u,  733239954u, 1555261956u, 3268935591u, 3050360625u,  752459403u, 1541320221u,
+  2607071920u, 3965973030u, 1969922972u,   40735498u, 2617837225u, 3943577151u, 1913087877u,   83908371u,
+  2512341634u, 3803740692u, 2075208622u,  213261112u, 2463272603u, 3855990285u, 2094854071u,  198958881u,
+  2262029012u, 4057260610u, 1759359992u,  534414190u, 2176718541u, 4139329115u, 1873836001u,  414664567u,
+  2282248934u, 4279200368u, 1711684554u,  285281116u, 2405801727u, 4167216745u, 1634467795u,  376229701u,
+  2685067896u, 3608007406u, 1308918612u,  956543938u, 2808555105u, 3495958263u, 1231636301u, 1047427035u,
+  2932959818u, 3654703836u, 1088359270u,  936918000u, 2847714899u, 3736837829u, 1202900863u,  817233897u,
+  3183342108u, 3401237130u, 1404277552u,  615818150u, 3134207493u, 3453421203u, 1423857449u,  601450431u,
+  3009837614u, 3294710456u, 1567103746u,  711928724u, 3020668471u, 3272380065u, 1510334235u,  755167117u
+};
+
+/*Return the CRC of the bytes buf[0..len-1].*/
+unsigned lodepng_crc32(const unsigned char* buf, size_t len)
+{
+  unsigned c = 0xffffffffL;
+  size_t n;
+
+  for(n = 0; n < len; ++n)
+  {
+    c = lodepng_crc32_table[(c ^ buf[n]) & 0xff] ^ (c >> 8);
+  }
+  return c ^ 0xffffffffL;
+}
+#endif /* !LODEPNG_NO_COMPILE_CRC */
+
+/* ////////////////////////////////////////////////////////////////////////// */
+/* / Reading and writing single bits and bytes from/to stream for LodePNG   / */
+/* ////////////////////////////////////////////////////////////////////////// */
+
+static unsigned char readBitFromReversedStream(size_t* bitpointer, const unsigned char* bitstream)
+{
+  unsigned char result = (unsigned char)((bitstream[(*bitpointer) >> 3] >> (7 - ((*bitpointer) & 0x7))) & 1);
+  ++(*bitpointer);
+  return result;
+}
+
+static unsigned readBitsFromReversedStream(size_t* bitpointer, const unsigned char* bitstream, size_t nbits)
+{
+  unsigned result = 0;
+  size_t i;
+  for(i = nbits - 1; i < nbits; --i)
+  {
+    result += (unsigned)readBitFromReversedStream(bitpointer, bitstream) << i;
+  }
+  return result;
+}
+
+#ifdef LODEPNG_COMPILE_DECODER
+static void setBitOfReversedStream0(size_t* bitpointer, unsigned char* bitstream, unsigned char bit)
+{
+  /*the current bit in bitstream must be 0 for this to work*/
+  if(bit)
+  {
+    /*earlier bit of huffman code is in a lesser significant bit of an earlier byte*/
+    bitstream[(*bitpointer) >> 3] |= (bit << (7 - ((*bitpointer) & 0x7)));
+  }
+  ++(*bitpointer);
+}
+#endif /*LODEPNG_COMPILE_DECODER*/
+
+static void setBitOfReversedStream(size_t* bitpointer, unsigned char* bitstream, unsigned char bit)
+{
+  /*the current bit in bitstream may be 0 or 1 for this to work*/
+  if(bit == 0) bitstream[(*bitpointer) >> 3] &=  (unsigned char)(~(1 << (7 - ((*bitpointer) & 0x7))));
+  else         bitstream[(*bitpointer) >> 3] |=  (1 << (7 - ((*bitpointer) & 0x7)));
+  ++(*bitpointer);
+}
+
+/* ////////////////////////////////////////////////////////////////////////// */
+/* / PNG chunks                                                             / */
+/* ////////////////////////////////////////////////////////////////////////// */
+
+unsigned lodepng_chunk_length(const unsigned char* chunk)
+{
+  return lodepng_read32bitInt(&chunk[0]);
+}
+
+void lodepng_chunk_type(char type[5], const unsigned char* chunk)
+{
+  unsigned i;
+  for(i = 0; i != 4; ++i) type[i] = (char)chunk[4 + i];
+  type[4] = 0; /*null termination char*/
+}
+
+unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type)
+{
+  if(strlen(type) != 4) return 0;
+  return (chunk[4] == type[0] && chunk[5] == type[1] && chunk[6] == type[2] && chunk[7] == type[3]);
+}
+
+unsigned char lodepng_chunk_ancillary(const unsigned char* chunk)
+{
+  return((chunk[4] & 32) != 0);
+}
+
+unsigned char lodepng_chunk_private(const unsigned char* chunk)
+{
+  return((chunk[6] & 32) != 0);
+}
+
+unsigned char lodepng_chunk_safetocopy(const unsigned char* chunk)
+{
+  return((chunk[7] & 32) != 0);
+}
+
+unsigned char* lodepng_chunk_data(unsigned char* chunk)
+{
+  return &chunk[8];
+}
+
+const unsigned char* lodepng_chunk_data_const(const unsigned char* chunk)
+{
+  return &chunk[8];
+}
+
+unsigned lodepng_chunk_check_crc(const unsigned char* chunk)
+{
+  unsigned length = lodepng_chunk_length(chunk);
+  unsigned CRC = lodepng_read32bitInt(&chunk[length + 8]);
+  /*the CRC is taken of the data and the 4 chunk type letters, not the length*/
+  unsigned checksum = lodepng_crc32(&chunk[4], length + 4);
+  if(CRC != checksum) return 1;
+  else return 0;
+}
+
+void lodepng_chunk_generate_crc(unsigned char* chunk)
+{
+  unsigned length = lodepng_chunk_length(chunk);
+  unsigned CRC = lodepng_crc32(&chunk[4], length + 4);
+  lodepng_set32bitInt(chunk + 8 + length, CRC);
+}
+
+unsigned char* lodepng_chunk_next(unsigned char* chunk)
+{
+  unsigned total_chunk_length = lodepng_chunk_length(chunk) + 12;
+  return &chunk[total_chunk_length];
+}
+
+const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk)
+{
+  unsigned total_chunk_length = lodepng_chunk_length(chunk) + 12;
+  return &chunk[total_chunk_length];
+}
+
+unsigned lodepng_chunk_append(unsigned char** out, size_t* outlength, const unsigned char* chunk)
+{
+  unsigned i;
+  unsigned total_chunk_length = lodepng_chunk_length(chunk) + 12;
+  unsigned char *chunk_start, *new_buffer;
+  size_t new_length = (*outlength) + total_chunk_length;
+  if(new_length < total_chunk_length || new_length < (*outlength)) return 77; /*integer overflow happened*/
+
+  new_buffer = (unsigned char*)lodepng_realloc(*out, new_length);
+  if(!new_buffer) return 83; /*alloc fail*/
+  (*out) = new_buffer;
+  (*outlength) = new_length;
+  chunk_start = &(*out)[new_length - total_chunk_length];
+
+  for(i = 0; i != total_chunk_length; ++i) chunk_start[i] = chunk[i];
+
+  return 0;
+}
+
+unsigned lodepng_chunk_create(unsigned char** out, size_t* outlength, unsigned length,
+                              const char* type, const unsigned char* data)
+{
+  unsigned i;
+  unsigned char *chunk, *new_buffer;
+  size_t new_length = (*outlength) + length + 12;
+  if(new_length < length + 12 || new_length < (*outlength)) return 77; /*integer overflow happened*/
+  new_buffer = (unsigned char*)lodepng_realloc(*out, new_length);
+  if(!new_buffer) return 83; /*alloc fail*/
+  (*out) = new_buffer;
+  (*outlength) = new_length;
+  chunk = &(*out)[(*outlength) - length - 12];
+
+  /*1: length*/
+  lodepng_set32bitInt(chunk, (unsigned)length);
+
+  /*2: chunk name (4 letters)*/
+  chunk[4] = (unsigned char)type[0];
+  chunk[5] = (unsigned char)type[1];
+  chunk[6] = (unsigned char)type[2];
+  chunk[7] = (unsigned char)type[3];
+
+  /*3: the data*/
+  for(i = 0; i != length; ++i) chunk[8 + i] = data[i];
+
+  /*4: CRC (of the chunkname characters and the data)*/
+  lodepng_chunk_generate_crc(chunk);
+
+  return 0;
+}
+
+/* ////////////////////////////////////////////////////////////////////////// */
+/* / Color types and such                                                   / */
+/* ////////////////////////////////////////////////////////////////////////// */
+
+/*return type is a LodePNG error code*/
+static unsigned checkColorValidity(LodePNGColorType colortype, unsigned bd) /*bd = bitdepth*/
+{
+  switch(colortype)
+  {
+    case 0: if(!(bd == 1 || bd == 2 || bd == 4 || bd == 8 || bd == 16)) return 37; break; /*grey*/
+    case 2: if(!(                                 bd == 8 || bd == 16)) return 37; break; /*RGB*/
+    case 3: if(!(bd == 1 || bd == 2 || bd == 4 || bd == 8            )) return 37; break; /*palette*/
+    case 4: if(!(                                 bd == 8 || bd == 16)) return 37; break; /*grey + alpha*/
+    case 6: if(!(                                 bd == 8 || bd == 16)) return 37; break; /*RGBA*/
+    default: return 31;
+  }
+  return 0; /*allowed color type / bits combination*/
+}
+
+static unsigned getNumColorChannels(LodePNGColorType colortype)
+{
+  switch(colortype)
+  {
+    case 0: return 1; /*grey*/
+    case 2: return 3; /*RGB*/
+    case 3: return 1; /*palette*/
+    case 4: return 2; /*grey + alpha*/
+    case 6: return 4; /*RGBA*/
+  }
+  return 0; /*unexisting color type*/
+}
+
+static unsigned lodepng_get_bpp_lct(LodePNGColorType colortype, unsigned bitdepth)
+{
+  /*bits per pixel is amount of channels * bits per channel*/
+  return getNumColorChannels(colortype) * bitdepth;
+}
+
+/* ////////////////////////////////////////////////////////////////////////// */
+
+void lodepng_color_mode_init(LodePNGColorMode* info)
+{
+  info->key_defined = 0;
+  info->key_r = info->key_g = info->key_b = 0;
+  info->colortype = LCT_RGBA;
+  info->bitdepth = 8;
+  info->palette = 0;
+  info->palettesize = 0;
+}
+
+void lodepng_color_mode_cleanup(LodePNGColorMode* info)
+{
+  lodepng_palette_clear(info);
+}
+
+unsigned lodepng_color_mode_copy(LodePNGColorMode* dest, const LodePNGColorMode* source)
+{
+  size_t i;
+  lodepng_color_mode_cleanup(dest);
+  *dest = *source;
+  if(source->palette)
+  {
+    dest->palette = (unsigned char*)lodepng_malloc(1024);
+    if(!dest->palette && source->palettesize) return 83; /*alloc fail*/
+    for(i = 0; i != source->palettesize * 4; ++i) dest->palette[i] = source->palette[i];
+  }
+  return 0;
+}
+
+static int lodepng_color_mode_equal(const LodePNGColorMode* a, const LodePNGColorMode* b)
+{
+  size_t i;
+  if(a->colortype != b->colortype) return 0;
+  if(a->bitdepth != b->bitdepth) return 0;
+  if(a->key_defined != b->key_defined) return 0;
+  if(a->key_defined)
+  {
+    if(a->key_r != b->key_r) return 0;
+    if(a->key_g != b->key_g) return 0;
+    if(a->key_b != b->key_b) return 0;
+  }
+  /*if one of the palette sizes is 0, then we consider it to be the same as the
+  other: it means that e.g. the palette was not given by the user and should be
+  considered the same as the palette inside the PNG.*/
+  if(1/*a->palettesize != 0 && b->palettesize != 0*/) {
+    if(a->palettesize != b->palettesize) return 0;
+    for(i = 0; i != a->palettesize * 4; ++i)
+    {
+      if(a->palette[i] != b->palette[i]) return 0;
+    }
+  }
+  return 1;
+}
+
+void lodepng_palette_clear(LodePNGColorMode* info)
+{
+  if(info->palette) lodepng_free(info->palette);
+  info->palette = 0;
+  info->palettesize = 0;
+}
+
+unsigned lodepng_palette_add(LodePNGColorMode* info,
+                             unsigned char r, unsigned char g, unsigned char b, unsigned char a)
+{
+  unsigned char* data;
+  /*the same resize technique as C++ std::vectors is used, and here it's made so that for a palette with
+  the max of 256 colors, it'll have the exact alloc size*/
+  if(!info->palette) /*allocate palette if empty*/
+  {
+    /*room for 256 colors with 4 bytes each*/
+    data = (unsigned char*)lodepng_realloc(info->palette, 1024);
+    if(!data) return 83; /*alloc fail*/
+    else info->palette = data;
+  }
+  info->palette[4 * info->palettesize + 0] = r;
+  info->palette[4 * info->palettesize + 1] = g;
+  info->palette[4 * info->palettesize + 2] = b;
+  info->palette[4 * info->palettesize + 3] = a;
+  ++info->palettesize;
+  return 0;
+}
+
+unsigned lodepng_get_bpp(const LodePNGColorMode* info)
+{
+  /*calculate bits per pixel out of colortype and bitdepth*/
+  return lodepng_get_bpp_lct(info->colortype, info->bitdepth);
+}
+
+unsigned lodepng_get_channels(const LodePNGColorMode* info)
+{
+  return getNumColorChannels(info->colortype);
+}
+
+unsigned lodepng_is_greyscale_type(const LodePNGColorMode* info)
+{
+  return info->colortype == LCT_GREY || info->colortype == LCT_GREY_ALPHA;
+}
+
+unsigned lodepng_is_alpha_type(const LodePNGColorMode* info)
+{
+  return (info->colortype & 4) != 0; /*4 or 6*/
+}
+
+unsigned lodepng_is_palette_type(const LodePNGColorMode* info)
+{
+  return info->colortype == LCT_PALETTE;
+}
+
+unsigned lodepng_has_palette_alpha(const LodePNGColorMode* info)
+{
+  size_t i;
+  for(i = 0; i != info->palettesize; ++i)
+  {
+    if(info->palette[i * 4 + 3] < 255) return 1;
+  }
+  return 0;
+}
+
+unsigned lodepng_can_have_alpha(const LodePNGColorMode* info)
+{
+  return info->key_defined
+      || lodepng_is_alpha_type(info)
+      || lodepng_has_palette_alpha(info);
+}
+
+size_t lodepng_get_raw_size(unsigned w, unsigned h, const LodePNGColorMode* color)
+{
+  return (w * h * lodepng_get_bpp(color) + 7) / 8;
+}
+
+size_t lodepng_get_raw_size_lct(unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth)
+{
+  return (w * h * lodepng_get_bpp_lct(colortype, bitdepth) + 7) / 8;
+}
+
+
+#ifdef LODEPNG_COMPILE_PNG
+#ifdef LODEPNG_COMPILE_DECODER
+/*in an idat chunk, each scanline is a multiple of 8 bits, unlike the lodepng output buffer*/
+static size_t lodepng_get_raw_size_idat(unsigned w, unsigned h, const LodePNGColorMode* color)
+{
+  return h * ((w * lodepng_get_bpp(color) + 7) / 8);
+}
+#endif /*LODEPNG_COMPILE_DECODER*/
+#endif /*LODEPNG_COMPILE_PNG*/
+
+#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
+
+static void LodePNGUnknownChunks_init(LodePNGInfo* info)
+{
+  unsigned i;
+  for(i = 0; i != 3; ++i) info->unknown_chunks_data[i] = 0;
+  for(i = 0; i != 3; ++i) info->unknown_chunks_size[i] = 0;
+}
+
+static void LodePNGUnknownChunks_cleanup(LodePNGInfo* info)
+{
+  unsigned i;
+  for(i = 0; i != 3; ++i) lodepng_free(info->unknown_chunks_data[i]);
+}
+
+static unsigned LodePNGUnknownChunks_copy(LodePNGInfo* dest, const LodePNGInfo* src)
+{
+  unsigned i;
+
+  LodePNGUnknownChunks_cleanup(dest);
+
+  for(i = 0; i != 3; ++i)
+  {
+    size_t j;
+    dest->unknown_chunks_size[i] = src->unknown_chunks_size[i];
+    dest->unknown_chunks_data[i] = (unsigned char*)lodepng_malloc(src->unknown_chunks_size[i]);
+    if(!dest->unknown_chunks_data[i] && dest->unknown_chunks_size[i]) return 83; /*alloc fail*/
+    for(j = 0; j < src->unknown_chunks_size[i]; ++j)
+    {
+      dest->unknown_chunks_data[i][j] = src->unknown_chunks_data[i][j];
+    }
+  }
+
+  return 0;
+}
+
+/******************************************************************************/
+
+static void LodePNGText_init(LodePNGInfo* info)
+{
+  info->text_num = 0;
+  info->text_keys = NULL;
+  info->text_strings = NULL;
+}
+
+static void LodePNGText_cleanup(LodePNGInfo* info)
+{
+  size_t i;
+  for(i = 0; i != info->text_num; ++i)
+  {
+    string_cleanup(&info->text_keys[i]);
+    string_cleanup(&info->text_strings[i]);
+  }
+  lodepng_free(info->text_keys);
+  lodepng_free(info->text_strings);
+}
+
+static unsigned LodePNGText_copy(LodePNGInfo* dest, const LodePNGInfo* source)
+{
+  size_t i = 0;
+  dest->text_keys = 0;
+  dest->text_strings = 0;
+  dest->text_num = 0;
+  for(i = 0; i != source->text_num; ++i)
+  {
+    CERROR_TRY_RETURN(lodepng_add_text(dest, source->text_keys[i], source->text_strings[i]));
+  }
+  return 0;
+}
+
+void lodepng_clear_text(LodePNGInfo* info)
+{
+  LodePNGText_cleanup(info);
+}
+
+unsigned lodepng_add_text(LodePNGInfo* info, const char* key, const char* str)
+{
+  char** new_keys = (char**)(lodepng_realloc(info->text_keys, sizeof(char*) * (info->text_num + 1)));
+  char** new_strings = (char**)(lodepng_realloc(info->text_strings, sizeof(char*) * (info->text_num + 1)));
+  if(!new_keys || !new_strings)
+  {
+    lodepng_free(new_keys);
+    lodepng_free(new_strings);
+    return 83; /*alloc fail*/
+  }
+
+  ++info->text_num;
+  info->text_keys = new_keys;
+  info->text_strings = new_strings;
+
+  string_init(&info->text_keys[info->text_num - 1]);
+  string_set(&info->text_keys[info->text_num - 1], key);
+
+  string_init(&info->text_strings[info->text_num - 1]);
+  string_set(&info->text_strings[info->text_num - 1], str);
+
+  return 0;
+}
+
+/******************************************************************************/
+
+static void LodePNGIText_init(LodePNGInfo* info)
+{
+  info->itext_num = 0;
+  info->itext_keys = NULL;
+  info->itext_langtags = NULL;
+  info->itext_transkeys = NULL;
+  info->itext_strings = NULL;
+}
+
+static void LodePNGIText_cleanup(LodePNGInfo* info)
+{
+  size_t i;
+  for(i = 0; i != info->itext_num; ++i)
+  {
+    string_cleanup(&info->itext_keys[i]);
+    string_cleanup(&info->itext_langtags[i]);
+    string_cleanup(&info->itext_transkeys[i]);
+    string_cleanup(&info->itext_strings[i]);
+  }
+  lodepng_free(info->itext_keys);
+  lodepng_free(info->itext_langtags);
+  lodepng_free(info->itext_transkeys);
+  lodepng_free(info->itext_strings);
+}
+
+static unsigned LodePNGIText_copy(LodePNGInfo* dest, const LodePNGInfo* source)
+{
+  size_t i = 0;
+  dest->itext_keys = 0;
+  dest->itext_langtags = 0;
+  dest->itext_transkeys = 0;
+  dest->itext_strings = 0;
+  dest->itext_num = 0;
+  for(i = 0; i != source->itext_num; ++i)
+  {
+    CERROR_TRY_RETURN(lodepng_add_itext(dest, source->itext_keys[i], source->itext_langtags[i],
+                                        source->itext_transkeys[i], source->itext_strings[i]));
+  }
+  return 0;
+}
+
+void lodepng_clear_itext(LodePNGInfo* info)
+{
+  LodePNGIText_cleanup(info);
+}
+
+unsigned lodepng_add_itext(LodePNGInfo* info, const char* key, const char* langtag,
+                           const char* transkey, const char* str)
+{
+  char** new_keys = (char**)(lodepng_realloc(info->itext_keys, sizeof(char*) * (info->itext_num + 1)));
+  char** new_langtags = (char**)(lodepng_realloc(info->itext_langtags, sizeof(char*) * (info->itext_num + 1)));
+  char** new_transkeys = (char**)(lodepng_realloc(info->itext_transkeys, sizeof(char*) * (info->itext_num + 1)));
+  char** new_strings = (char**)(lodepng_realloc(info->itext_strings, sizeof(char*) * (info->itext_num + 1)));
+  if(!new_keys || !new_langtags || !new_transkeys || !new_strings)
+  {
+    lodepng_free(new_keys);
+    lodepng_free(new_langtags);
+    lodepng_free(new_transkeys);
+    lodepng_free(new_strings);
+    return 83; /*alloc fail*/
+  }
+
+  ++info->itext_num;
+  info->itext_keys = new_keys;
+  info->itext_langtags = new_langtags;
+  info->itext_transkeys = new_transkeys;
+  info->itext_strings = new_strings;
+
+  string_init(&info->itext_keys[info->itext_num - 1]);
+  string_set(&info->itext_keys[info->itext_num - 1], key);
+
+  string_init(&info->itext_langtags[info->itext_num - 1]);
+  string_set(&info->itext_langtags[info->itext_num - 1], langtag);
+
+  string_init(&info->itext_transkeys[info->itext_num - 1]);
+  string_set(&info->itext_transkeys[info->itext_num - 1], transkey);
+
+  string_init(&info->itext_strings[info->itext_num - 1]);
+  string_set(&info->itext_strings[info->itext_num - 1], str);
+
+  return 0;
+}
+#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
+
+void lodepng_info_init(LodePNGInfo* info)
+{
+  lodepng_color_mode_init(&info->color);
+  info->interlace_method = 0;
+  info->compression_method = 0;
+  info->filter_method = 0;
+#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
+  info->background_defined = 0;
+  info->background_r = info->background_g = info->background_b = 0;
+
+  LodePNGText_init(info);
+  LodePNGIText_init(info);
+
+  info->time_defined = 0;
+  info->phys_defined = 0;
+
+  LodePNGUnknownChunks_init(info);
+#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
+}
+
+void lodepng_info_cleanup(LodePNGInfo* info)
+{
+  lodepng_color_mode_cleanup(&info->color);
+#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
+  LodePNGText_cleanup(info);
+  LodePNGIText_cleanup(info);
+
+  LodePNGUnknownChunks_cleanup(info);
+#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
+}
+
+unsigned lodepng_info_copy(LodePNGInfo* dest, const LodePNGInfo* source)
+{
+  lodepng_info_cleanup(dest);
+  *dest = *source;
+  lodepng_color_mode_init(&dest->color);
+  CERROR_TRY_RETURN(lodepng_color_mode_copy(&dest->color, &source->color));
+
+#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
+  CERROR_TRY_RETURN(LodePNGText_copy(dest, source));
+  CERROR_TRY_RETURN(LodePNGIText_copy(dest, source));
+
+  LodePNGUnknownChunks_init(dest);
+  CERROR_TRY_RETURN(LodePNGUnknownChunks_copy(dest, source));
+#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
+  return 0;
+}
+
+void lodepng_info_swap(LodePNGInfo* a, LodePNGInfo* b)
+{
+  LodePNGInfo temp = *a;
+  *a = *b;
+  *b = temp;
+}
+
+/* ////////////////////////////////////////////////////////////////////////// */
+
+/*index: bitgroup index, bits: bitgroup size(1, 2 or 4), in: bitgroup value, out: octet array to add bits to*/
+static void addColorBits(unsigned char* out, size_t index, unsigned bits, unsigned in)
+{
+  unsigned m = bits == 1 ? 7 : bits == 2 ? 3 : 1; /*8 / bits - 1*/
+  /*p = the partial index in the byte, e.g. with 4 palettebits it is 0 for first half or 1 for second half*/
+  unsigned p = index & m;
+  in &= (1u << bits) - 1u; /*filter out any other bits of the input value*/
+  in = in << (bits * (m - p));
+  if(p == 0) out[index * bits / 8] = in;
+  else out[index * bits / 8] |= in;
+}
+
+typedef struct ColorTree ColorTree;
+
+/*
+One node of a color tree
+This is the data structure used to count the number of unique colors and to get a palette
+index for a color. It's like an octree, but because the alpha channel is used too, each
+node has 16 instead of 8 children.
+*/
+struct ColorTree
+{
+  ColorTree* children[16]; /*up to 16 pointers to ColorTree of next level*/
+  int index; /*the payload. Only has a meaningful value if this is in the last level*/
+};
+
+static void color_tree_init(ColorTree* tree)
+{
+  int i;
+  for(i = 0; i != 16; ++i) tree->children[i] = 0;
+  tree->index = -1;
+}
+
+static void color_tree_cleanup(ColorTree* tree)
+{
+  int i;
+  for(i = 0; i != 16; ++i)
+  {
+    if(tree->children[i])
+    {
+      color_tree_cleanup(tree->children[i]);
+      lodepng_free(tree->children[i]);
+    }
+  }
+}
+
+/*returns -1 if color not present, its index otherwise*/
+static int color_tree_get(ColorTree* tree, unsigned char r, unsigned char g, unsigned char b, unsigned char a)
+{
+  int bit = 0;
+  for(bit = 0; bit < 8; ++bit)
+  {
+    int i = 8 * ((r >> bit) & 1) + 4 * ((g >> bit) & 1) + 2 * ((b >> bit) & 1) + 1 * ((a >> bit) & 1);
+    if(!tree->children[i]) return -1;
+    else tree = tree->children[i];
+  }
+  return tree ? tree->index : -1;
+}
+
+#ifdef LODEPNG_COMPILE_ENCODER
+static int color_tree_has(ColorTree* tree, unsigned char r, unsigned char g, unsigned char b, unsigned char a)
+{
+  return color_tree_get(tree, r, g, b, a) >= 0;
+}
+#endif /*LODEPNG_COMPILE_ENCODER*/
+
+/*color is not allowed to already exist.
+Index should be >= 0 (it's signed to be compatible with using -1 for "doesn't exist")*/
+static void color_tree_add(ColorTree* tree,
+                           unsigned char r, unsigned char g, unsigned char b, unsigned char a, unsigned index)
+{
+  int bit;
+  for(bit = 0; bit < 8; ++bit)
+  {
+    int i = 8 * ((r >> bit) & 1) + 4 * ((g >> bit) & 1) + 2 * ((b >> bit) & 1) + 1 * ((a >> bit) & 1);
+    if(!tree->children[i])
+    {
+      tree->children[i] = (ColorTree*)lodepng_malloc(sizeof(ColorTree));
+      color_tree_init(tree->children[i]);
+    }
+    tree = tree->children[i];
+  }
+  tree->index = (int)index;
+}
+
+/*put a pixel, given its RGBA color, into image of any color type*/
+static unsigned rgba8ToPixel(unsigned char* out, size_t i,
+                             const LodePNGColorMode* mode, ColorTree* tree /*for palette*/,
+                             unsigned char r, unsigned char g, unsigned char b, unsigned char a)
+{
+  if(mode->colortype == LCT_GREY)
+  {
+    unsigned char grey = r; /*((unsigned short)r + g + b) / 3*/;
+    if(mode->bitdepth == 8) out[i] = grey;
+    else if(mode->bitdepth == 16) out[i * 2 + 0] = out[i * 2 + 1] = grey;
+    else
+    {
+      /*take the most significant bits of grey*/
+      grey = (grey >> (8 - mode->bitdepth)) & ((1 << mode->bitdepth) - 1);
+      addColorBits(out, i, mode->bitdepth, grey);
+    }
+  }
+  else if(mode->colortype == LCT_RGB)
+  {
+    if(mode->bitdepth == 8)
+    {
+      out[i * 3 + 0] = r;
+      out[i * 3 + 1] = g;
+      out[i * 3 + 2] = b;
+    }
+    else
+    {
+      out[i * 6 + 0] = out[i * 6 + 1] = r;
+      out[i * 6 + 2] = out[i * 6 + 3] = g;
+      out[i * 6 + 4] = out[i * 6 + 5] = b;
+    }
+  }
+  else if(mode->colortype == LCT_PALETTE)
+  {
+    int index = color_tree_get(tree, r, g, b, a);
+    if(index < 0) return 82; /*color not in palette*/
+    if(mode->bitdepth == 8) out[i] = index;
+    else addColorBits(out, i, mode->bitdepth, (unsigned)index);
+  }
+  else if(mode->colortype == LCT_GREY_ALPHA)
+  {
+    unsigned char grey = r; /*((unsigned short)r + g + b) / 3*/;
+    if(mode->bitdepth == 8)
+    {
+      out[i * 2 + 0] = grey;
+      out[i * 2 + 1] = a;
+    }
+    else if(mode->bitdepth == 16)
+    {
+      out[i * 4 + 0] = out[i * 4 + 1] = grey;
+      out[i * 4 + 2] = out[i * 4 + 3] = a;
+    }
+  }
+  else if(mode->colortype == LCT_RGBA)
+  {
+    if(mode->bitdepth == 8)
+    {
+      out[i * 4 + 0] = r;
+      out[i * 4 + 1] = g;
+      out[i * 4 + 2] = b;
+      out[i * 4 + 3] = a;
+    }
+    else
+    {
+      out[i * 8 + 0] = out[i * 8 + 1] = r;
+      out[i * 8 + 2] = out[i * 8 + 3] = g;
+      out[i * 8 + 4] = out[i * 8 + 5] = b;
+      out[i * 8 + 6] = out[i * 8 + 7] = a;
+    }
+  }
+
+  return 0; /*no error*/
+}
+
+/*put a pixel, given its RGBA16 color, into image of any color 16-bitdepth type*/
+static void rgba16ToPixel(unsigned char* out, size_t i,
+                         const LodePNGColorMode* mode,
+                         unsigned short r, unsigned short g, unsigned short b, unsigned short a)
+{
+  if(mode->colortype == LCT_GREY)
+  {
+    unsigned short grey = r; /*((unsigned)r + g + b) / 3*/;
+    out[i * 2 + 0] = (grey >> 8) & 255;
+    out[i * 2 + 1] = grey & 255;
+  }
+  else if(mode->colortype == LCT_RGB)
+  {
+    out[i * 6 + 0] = (r >> 8) & 255;
+    out[i * 6 + 1] = r & 255;
+    out[i * 6 + 2] = (g >> 8) & 255;
+    out[i * 6 + 3] = g & 255;
+    out[i * 6 + 4] = (b >> 8) & 255;
+    out[i * 6 + 5] = b & 255;
+  }
+  else if(mode->colortype == LCT_GREY_ALPHA)
+  {
+    unsigned short grey = r; /*((unsigned)r + g + b) / 3*/;
+    out[i * 4 + 0] = (grey >> 8) & 255;
+    out[i * 4 + 1] = grey & 255;
+    out[i * 4 + 2] = (a >> 8) & 255;
+    out[i * 4 + 3] = a & 255;
+  }
+  else if(mode->colortype == LCT_RGBA)
+  {
+    out[i * 8 + 0] = (r >> 8) & 255;
+    out[i * 8 + 1] = r & 255;
+    out[i * 8 + 2] = (g >> 8) & 255;
+    out[i * 8 + 3] = g & 255;
+    out[i * 8 + 4] = (b >> 8) & 255;
+    out[i * 8 + 5] = b & 255;
+    out[i * 8 + 6] = (a >> 8) & 255;
+    out[i * 8 + 7] = a & 255;
+  }
+}
+
+/*Get RGBA8 color of pixel with index i (y * width + x) from the raw image with given color type.*/
+static void getPixelColorRGBA8(unsigned char* r, unsigned char* g,
+                               unsigned char* b, unsigned char* a,
+                               const unsigned char* in, size_t i,
+                               const LodePNGColorMode* mode)
+{
+  if(mode->colortype == LCT_GREY)
+  {
+    if(mode->bitdepth == 8)
+    {
+      *r = *g = *b = in[i];
+      if(mode->key_defined && *r == mode->key_r) *a = 0;
+      else *a = 255;
+    }
+    else if(mode->bitdepth == 16)
+    {
+      *r = *g = *b = in[i * 2 + 0];
+      if(mode->key_defined && 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r) *a = 0;
+      else *a = 255;
+    }
+    else
+    {
+      unsigned highest = ((1U << mode->bitdepth) - 1U); /*highest possible value for this bit depth*/
+      size_t j = i * mode->bitdepth;
+      unsigned value = readBitsFromReversedStream(&j, in, mode->bitdepth);
+      *r = *g = *b = (value * 255) / highest;
+      if(mode->key_defined && value == mode->key_r) *a = 0;
+      else *a = 255;
+    }
+  }
+  else if(mode->colortype == LCT_RGB)
+  {
+    if(mode->bitdepth == 8)
+    {
+      *r = in[i * 3 + 0]; *g = in[i * 3 + 1]; *b = in[i * 3 + 2];
+      if(mode->key_defined && *r == mode->key_r && *g == mode->key_g && *b == mode->key_b) *a = 0;
+      else *a = 255;
+    }
+    else
+    {
+      *r = in[i * 6 + 0];
+      *g = in[i * 6 + 2];
+      *b = in[i * 6 + 4];
+      if(mode->key_defined && 256U * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r
+         && 256U * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g
+         && 256U * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b) *a = 0;
+      else *a = 255;
+    }
+  }
+  else if(mode->colortype == LCT_PALETTE)
+  {
+    unsigned index;
+    if(mode->bitdepth == 8) index = in[i];
+    else
+    {
+      size_t j = i * mode->bitdepth;
+      index = readBitsFromReversedStream(&j, in, mode->bitdepth);
+    }
+
+    if(index >= mode->palettesize)
+    {
+      /*This is an error according to the PNG spec, but common PNG decoders make it black instead.
+      Done here too, slightly faster due to no error handling needed.*/
+      *r = *g = *b = 0;
+      *a = 255;
+    }
+    else
+    {
+      *r = mode->palette[index * 4 + 0];
+      *g = mode->palette[index * 4 + 1];
+      *b = mode->palette[index * 4 + 2];
+      *a = mode->palette[index * 4 + 3];
+    }
+  }
+  else if(mode->colortype == LCT_GREY_ALPHA)
+  {
+    if(mode->bitdepth == 8)
+    {
+      *r = *g = *b = in[i * 2 + 0];
+      *a = in[i * 2 + 1];
+    }
+    else
+    {
+      *r = *g = *b = in[i * 4 + 0];
+      *a = in[i * 4 + 2];
+    }
+  }
+  else if(mode->colortype == LCT_RGBA)
+  {
+    if(mode->bitdepth == 8)
+    {
+      *r = in[i * 4 + 0];
+      *g = in[i * 4 + 1];
+      *b = in[i * 4 + 2];
+      *a = in[i * 4 + 3];
+    }
+    else
+    {
+      *r = in[i * 8 + 0];
+      *g = in[i * 8 + 2];
+      *b = in[i * 8 + 4];
+      *a = in[i * 8 + 6];
+    }
+  }
+}
+
+/*Similar to getPixelColorRGBA8, but with all the for loops inside of the color
+mode test cases, optimized to convert the colors much faster, when converting
+to RGBA or RGB with 8 bit per cannel. buffer must be RGBA or RGB output with
+enough memory, if has_alpha is true the output is RGBA. mode has the color mode
+of the input buffer.*/
+static void getPixelColorsRGBA8(unsigned char* buffer, size_t numpixels,
+                                unsigned has_alpha, const unsigned char* in,
+                                const LodePNGColorMode* mode)
+{
+  unsigned num_channels = has_alpha ? 4 : 3;
+  size_t i;
+  if(mode->colortype == LCT_GREY)
+  {
+    if(mode->bitdepth == 8)
+    {
+      for(i = 0; i != numpixels; ++i, buffer += num_channels)
+      {
+        buffer[0] = buffer[1] = buffer[2] = in[i];
+        if(has_alpha) buffer[3] = mode->key_defined && in[i] == mode->key_r ? 0 : 255;
+      }
+    }
+    else if(mode->bitdepth == 16)
+    {
+      for(i = 0; i != numpixels; ++i, buffer += num_channels)
+      {
+        buffer[0] = buffer[1] = buffer[2] = in[i * 2];
+        if(has_alpha) buffer[3] = mode->key_defined && 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r ? 0 : 255;
+      }
+    }
+    else
+    {
+      unsigned highest = ((1U << mode->bitdepth) - 1U); /*highest possible value for this bit depth*/
+      size_t j = 0;
+      for(i = 0; i != numpixels; ++i, buffer += num_channels)
+      {
+        unsigned value = readBitsFromReversedStream(&j, in, mode->bitdepth);
+        buffer[0] = buffer[1] = buffer[2] = (value * 255) / highest;
+        if(has_alpha) buffer[3] = mode->key_defined && value == mode->key_r ? 0 : 255;
+      }
+    }
+  }
+  else if(mode->colortype == LCT_RGB)
+  {
+    if(mode->bitdepth == 8)
+    {
+      for(i = 0; i != numpixels; ++i, buffer += num_channels)
+      {
+        buffer[0] = in[i * 3 + 0];
+        buffer[1] = in[i * 3 + 1];
+        buffer[2] = in[i * 3 + 2];
+        if(has_alpha) buffer[3] = mode->key_defined && buffer[0] == mode->key_r
+           && buffer[1]== mode->key_g && buffer[2] == mode->key_b ? 0 : 255;
+      }
+    }
+    else
+    {
+      for(i = 0; i != numpixels; ++i, buffer += num_channels)
+      {
+        buffer[0] = in[i * 6 + 0];
+        buffer[1] = in[i * 6 + 2];
+        buffer[2] = in[i * 6 + 4];
+        if(has_alpha) buffer[3] = mode->key_defined
+           && 256U * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r
+           && 256U * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g
+           && 256U * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b ? 0 : 255;
+      }
+    }
+  }
+  else if(mode->colortype == LCT_PALETTE)
+  {
+    unsigned index;
+    size_t j = 0;
+    for(i = 0; i != numpixels; ++i, buffer += num_channels)
+    {
+      if(mode->bitdepth == 8) index = in[i];
+      else index = readBitsFromReversedStream(&j, in, mode->bitdepth);
+
+      if(index >= mode->palettesize)
+      {
+        /*This is an error according to the PNG spec, but most PNG decoders make it black instead.
+        Done here too, slightly faster due to no error handling needed.*/
+        buffer[0] = buffer[1] = buffer[2] = 0;
+        if(has_alpha) buffer[3] = 255;
+      }
+      else
+      {
+        buffer[0] = mode->palette[index * 4 + 0];
+        buffer[1] = mode->palette[index * 4 + 1];
+        buffer[2] = mode->palette[index * 4 + 2];
+        if(has_alpha) buffer[3] = mode->palette[index * 4 + 3];
+      }
+    }
+  }
+  else if(mode->colortype == LCT_GREY_ALPHA)
+  {
+    if(mode->bitdepth == 8)
+    {
+      for(i = 0; i != numpixels; ++i, buffer += num_channels)
+      {
+        buffer[0] = buffer[1] = buffer[2] = in[i * 2 + 0];
+        if(has_alpha) buffer[3] = in[i * 2 + 1];
+      }
+    }
+    else
+    {
+      for(i = 0; i != numpixels; ++i, buffer += num_channels)
+      {
+        buffer[0] = buffer[1] = buffer[2] = in[i * 4 + 0];
+        if(has_alpha) buffer[3] = in[i * 4 + 2];
+      }
+    }
+  }
+  else if(mode->colortype == LCT_RGBA)
+  {
+    if(mode->bitdepth == 8)
+    {
+      for(i = 0; i != numpixels; ++i, buffer += num_channels)
+      {
+        buffer[0] = in[i * 4 + 0];
+        buffer[1] = in[i * 4 + 1];
+        buffer[2] = in[i * 4 + 2];
+        if(has_alpha) buffer[3] = in[i * 4 + 3];
+      }
+    }
+    else
+    {
+      for(i = 0; i != numpixels; ++i, buffer += num_channels)
+      {
+        buffer[0] = in[i * 8 + 0];
+        buffer[1] = in[i * 8 + 2];
+        buffer[2] = in[i * 8 + 4];
+        if(has_alpha) buffer[3] = in[i * 8 + 6];
+      }
+    }
+  }
+}
+
+/*Get RGBA16 color of pixel with index i (y * width + x) from the raw image with
+given color type, but the given color type must be 16-bit itself.*/
+static void getPixelColorRGBA16(unsigned short* r, unsigned short* g, unsigned short* b, unsigned short* a,
+                                const unsigned char* in, size_t i, const LodePNGColorMode* mode)
+{
+  if(mode->colortype == LCT_GREY)
+  {
+    *r = *g = *b = 256 * in[i * 2 + 0] + in[i * 2 + 1];
+    if(mode->key_defined && 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r) *a = 0;
+    else *a = 65535;
+  }
+  else if(mode->colortype == LCT_RGB)
+  {
+    *r = 256 * in[i * 6 + 0] + in[i * 6 + 1];
+    *g = 256 * in[i * 6 + 2] + in[i * 6 + 3];
+    *b = 256 * in[i * 6 + 4] + in[i * 6 + 5];
+    if(mode->key_defined && 256U * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r
+       && 256U * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g
+       && 256U * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b) *a = 0;
+    else *a = 65535;
+  }
+  else if(mode->colortype == LCT_GREY_ALPHA)
+  {
+    *r = *g = *b = 256 * in[i * 4 + 0] + in[i * 4 + 1];
+    *a = 256 * in[i * 4 + 2] + in[i * 4 + 3];
+  }
+  else if(mode->colortype == LCT_RGBA)
+  {
+    *r = 256 * in[i * 8 + 0] + in[i * 8 + 1];
+    *g = 256 * in[i * 8 + 2] + in[i * 8 + 3];
+    *b = 256 * in[i * 8 + 4] + in[i * 8 + 5];
+    *a = 256 * in[i * 8 + 6] + in[i * 8 + 7];
+  }
+}
+
+unsigned lodepng_convert(unsigned char* out, const unsigned char* in,
+                         const LodePNGColorMode* mode_out, const LodePNGColorMode* mode_in,
+                         unsigned w, unsigned h)
+{
+  size_t i;
+  ColorTree tree;
+  size_t numpixels = w * h;
+
+  if(lodepng_color_mode_equal(mode_out, mode_in))
+  {
+    size_t numbytes = lodepng_get_raw_size(w, h, mode_in);
+    for(i = 0; i != numbytes; ++i) out[i] = in[i];
+    return 0;
+  }
+
+  if(mode_out->colortype == LCT_PALETTE)
+  {
+    size_t palettesize = mode_out->palettesize;
+    const unsigned char* palette = mode_out->palette;
+    size_t palsize = 1u << mode_out->bitdepth;
+    /*if the user specified output palette but did not give the values, assume
+    they want the values of the input color type (assuming that one is palette).
+    Note that we never create a new palette ourselves.*/
+    if(palettesize == 0) {
+      palettesize = mode_in->palettesize;
+      palette = mode_in->palette;
+    }
+    if(palettesize < palsize) palsize = palettesize;
+    color_tree_init(&tree);
+    for(i = 0; i != palsize; ++i)
+    {
+      const unsigned char* p = &palette[i * 4];
+      color_tree_add(&tree, p[0], p[1], p[2], p[3], i);
+    }
+  }
+
+  if(mode_in->bitdepth == 16 && mode_out->bitdepth == 16)
+  {
+    for(i = 0; i != numpixels; ++i)
+    {
+      unsigned short r = 0, g = 0, b = 0, a = 0;
+      getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode_in);
+      rgba16ToPixel(out, i, mode_out, r, g, b, a);
+    }
+  }
+  else if(mode_out->bitdepth == 8 && mode_out->colortype == LCT_RGBA)
+  {
+    getPixelColorsRGBA8(out, numpixels, 1, in, mode_in);
+  }
+  else if(mode_out->bitdepth == 8 && mode_out->colortype == LCT_RGB)
+  {
+    getPixelColorsRGBA8(out, numpixels, 0, in, mode_in);
+  }
+  else
+  {
+    unsigned char r = 0, g = 0, b = 0, a = 0;
+    for(i = 0; i != numpixels; ++i)
+    {
+      getPixelColorRGBA8(&r, &g, &b, &a, in, i, mode_in);
+      CERROR_TRY_RETURN(rgba8ToPixel(out, i, mode_out, &tree, r, g, b, a));
+    }
+  }
+
+  if(mode_out->colortype == LCT_PALETTE)
+  {
+    color_tree_cleanup(&tree);
+  }
+
+  return 0; /*no error*/
+}
+
+#ifdef LODEPNG_COMPILE_ENCODER
+
+void lodepng_color_profile_init(LodePNGColorProfile* profile)
+{
+  profile->colored = 0;
+  profile->key = 0;
+  profile->alpha = 0;
+  profile->key_r = profile->key_g = profile->key_b = 0;
+  profile->numcolors = 0;
+  profile->bits = 1;
+}
+
+/*function used for debug purposes with C++*/
+/*void printColorProfile(LodePNGColorProfile* p)
+{
+  std::cout << "colored: " << (int)p->colored << ", ";
+  std::cout << "key: " << (int)p->key << ", ";
+  std::cout << "key_r: " << (int)p->key_r << ", ";
+  std::cout << "key_g: " << (int)p->key_g << ", ";
+  std::cout << "key_b: " << (int)p->key_b << ", ";
+  std::cout << "alpha: " << (int)p->alpha << ", ";
+  std::cout << "numcolors: " << (int)p->numcolors << ", ";
+  std::cout << "bits: " << (int)p->bits << std::endl;
+}*/
+
+/*Returns how many bits needed to represent given value (max 8 bit)*/
+static unsigned getValueRequiredBits(unsigned char value)
+{
+  if(value == 0 || value == 255) return 1;
+  /*The scaling of 2-bit and 4-bit values uses multiples of 85 and 17*/
+  if(value % 17 == 0) return value % 85 == 0 ? 2 : 4;
+  return 8;
+}
+
+/*profile must already have been inited with mode.
+It's ok to set some parameters of profile to done already.*/
+unsigned lodepng_get_color_profile(LodePNGColorProfile* profile,
+                                   const unsigned char* in, unsigned w, unsigned h,
+                                   const LodePNGColorMode* mode)
+{
+  unsigned error = 0;
+  size_t i;
+  ColorTree tree;
+  size_t numpixels = w * h;
+
+  unsigned colored_done = lodepng_is_greyscale_type(mode) ? 1 : 0;
+  unsigned alpha_done = lodepng_can_have_alpha(mode) ? 0 : 1;
+  unsigned numcolors_done = 0;
+  unsigned bpp = lodepng_get_bpp(mode);
+  unsigned bits_done = bpp == 1 ? 1 : 0;
+  unsigned maxnumcolors = 257;
+  unsigned sixteen = 0;
+  if(bpp <= 8) maxnumcolors = bpp == 1 ? 2 : (bpp == 2 ? 4 : (bpp == 4 ? 16 : 256));
+
+  color_tree_init(&tree);
+
+  /*Check if the 16-bit input is truly 16-bit*/
+  if(mode->bitdepth == 16)
+  {
+    unsigned short r, g, b, a;
+    for(i = 0; i != numpixels; ++i)
+    {
+      getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode);
+      if((r & 255) != ((r >> 8) & 255) || (g & 255) != ((g >> 8) & 255) ||
+         (b & 255) != ((b >> 8) & 255) || (a & 255) != ((a >> 8) & 255)) /*first and second byte differ*/
+      {
+        sixteen = 1;
+        break;
+      }
+    }
+  }
+
+  if(sixteen)
+  {
+    unsigned short r = 0, g = 0, b = 0, a = 0;
+    profile->bits = 16;
+    bits_done = numcolors_done = 1; /*counting colors no longer useful, palette doesn't support 16-bit*/
+
+    for(i = 0; i != numpixels; ++i)
+    {
+      getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode);
+
+      if(!colored_done && (r != g || r != b))
+      {
+        profile->colored = 1;
+        colored_done = 1;
+      }
+
+      if(!alpha_done)
+      {
+        unsigned matchkey = (r == profile->key_r && g == profile->key_g && b == profile->key_b);
+        if(a != 65535 && (a != 0 || (profile->key && !matchkey)))
+        {
+          profile->alpha = 1;
+          alpha_done = 1;
+          if(profile->bits < 8) profile->bits = 8; /*PNG has no alphachannel modes with less than 8-bit per channel*/
+        }
+        else if(a == 0 && !profile->alpha && !profile->key)
+        {
+          profile->key = 1;
+          profile->key_r = r;
+          profile->key_g = g;
+          profile->key_b = b;
+        }
+        else if(a == 65535 && profile->key && matchkey)
+        {
+          /* Color key cannot be used if an opaque pixel also has that RGB color. */
+          profile->alpha = 1;
+          alpha_done = 1;
+        }
+      }
+
+      if(alpha_done && numcolors_done && colored_done && bits_done) break;
+    }
+  }
+  else /* < 16-bit */
+  {
+    for(i = 0; i != numpixels; ++i)
+    {
+      unsigned char r = 0, g = 0, b = 0, a = 0;
+      getPixelColorRGBA8(&r, &g, &b, &a, in, i, mode);
+
+      if(!bits_done && profile->bits < 8)
+      {
+        /*only r is checked, < 8 bits is only relevant for greyscale*/
+        unsigned bits = getValueRequiredBits(r);
+        if(bits > profile->bits) profile->bits = bits;
+      }
+      bits_done = (profile->bits >= bpp);
+
+      if(!colored_done && (r != g || r != b))
+      {
+        profile->colored = 1;
+        colored_done = 1;
+        if(profile->bits < 8) profile->bits = 8; /*PNG has no colored modes with less than 8-bit per channel*/
+      }
+
+      if(!alpha_done)
+      {
+        unsigned matchkey = (r == profile->key_r && g == profile->key_g && b == profile->key_b);
+        if(a != 255 && (a != 0 || (profile->key && !matchkey)))
+        {
+          profile->alpha = 1;
+          alpha_done = 1;
+          if(profile->bits < 8) profile->bits = 8; /*PNG has no alphachannel modes with less than 8-bit per channel*/
+        }
+        else if(a == 0 && !profile->alpha && !profile->key)
+        {
+          profile->key = 1;
+          profile->key_r = r;
+          profile->key_g = g;
+          profile->key_b = b;
+        }
+        else if(a == 255 && profile->key && matchkey)
+        {
+          /* Color key cannot be used if an opaque pixel also has that RGB color. */
+          profile->alpha = 1;
+          alpha_done = 1;
+          if(profile->bits < 8) profile->bits = 8; /*PNG has no alphachannel modes with less than 8-bit per channel*/
+        }
+      }
+
+      if(!numcolors_done)
+      {
+        if(!color_tree_has(&tree, r, g, b, a))
+        {
+          color_tree_add(&tree, r, g, b, a, profile->numcolors);
+          if(profile->numcolors < 256)
+          {
+            unsigned char* p = profile->palette;
+            unsigned n = profile->numcolors;
+            p[n * 4 + 0] = r;
+            p[n * 4 + 1] = g;
+            p[n * 4 + 2] = b;
+            p[n * 4 + 3] = a;
+          }
+          ++profile->numcolors;
+          numcolors_done = profile->numcolors >= maxnumcolors;
+        }
+      }
+
+      if(alpha_done && numcolors_done && colored_done && bits_done) break;
+    }
+
+    /*make the profile's key always 16-bit for consistency - repeat each byte twice*/
+    profile->key_r += (profile->key_r << 8);
+    profile->key_g += (profile->key_g << 8);
+    profile->key_b += (profile->key_b << 8);
+  }
+
+  color_tree_cleanup(&tree);
+  return error;
+}
+
+/*Automatically chooses color type that gives smallest amount of bits in the
+output image, e.g. grey if there are only greyscale pixels, palette if there
+are less than 256 colors, ...
+Updates values of mode with a potentially smaller color model. mode_out should
+contain the user chosen color model, but will be overwritten with the new chosen one.*/
+unsigned lodepng_auto_choose_color(LodePNGColorMode* mode_out,
+                                   const unsigned char* image, unsigned w, unsigned h,
+                                   const LodePNGColorMode* mode_in)
+{
+  LodePNGColorProfile prof;
+  unsigned error = 0;
+  unsigned i, n, palettebits, grey_ok, palette_ok;
+
+  lodepng_color_profile_init(&prof);
+  error = lodepng_get_color_profile(&prof, image, w, h, mode_in);
+  if(error) return error;
+  mode_out->key_defined = 0;
+
+  if(prof.key && w * h <= 16)
+  {
+    prof.alpha = 1; /*too few pixels to justify tRNS chunk overhead*/
+    if(prof.bits < 8) prof.bits = 8; /*PNG has no alphachannel modes with less than 8-bit per channel*/
+  }
+  grey_ok = !prof.colored && !prof.alpha; /*grey without alpha, with potentially low bits*/
+  n = prof.numcolors;
+  palettebits = n <= 2 ? 1 : (n <= 4 ? 2 : (n <= 16 ? 4 : 8));
+  palette_ok = n <= 256 && (n * 2 < w * h) && prof.bits <= 8;
+  if(w * h < n * 2) palette_ok = 0; /*don't add palette overhead if image has only a few pixels*/
+  if(grey_ok && prof.bits <= palettebits) palette_ok = 0; /*grey is less overhead*/
+
+  if(palette_ok)
+  {
+    unsigned char* p = prof.palette;
+    lodepng_palette_clear(mode_out); /*remove potential earlier palette*/
+    for(i = 0; i != prof.numcolors; ++i)
+    {
+      error = lodepng_palette_add(mode_out, p[i * 4 + 0], p[i * 4 + 1], p[i * 4 + 2], p[i * 4 + 3]);
+      if(error) break;
+    }
+
+    mode_out->colortype = LCT_PALETTE;
+    mode_out->bitdepth = palettebits;
+
+    if(mode_in->colortype == LCT_PALETTE && mode_in->palettesize >= mode_out->palettesize
+        && mode_in->bitdepth == mode_out->bitdepth)
+    {
+      /*If input should have same palette colors, keep original to preserve its order and prevent conversion*/
+      lodepng_color_mode_cleanup(mode_out);
+      lodepng_color_mode_copy(mode_out, mode_in);
+    }
+  }
+  else /*8-bit or 16-bit per channel*/
+  {
+    mode_out->bitdepth = prof.bits;
+    mode_out->colortype = prof.alpha ? (prof.colored ? LCT_RGBA : LCT_GREY_ALPHA)
+                                     : (prof.colored ? LCT_RGB : LCT_GREY);
+
+    if(prof.key && !prof.alpha)
+    {
+      unsigned mask = (1u << mode_out->bitdepth) - 1u; /*profile always uses 16-bit, mask converts it*/
+      mode_out->key_r = prof.key_r & mask;
+      mode_out->key_g = prof.key_g & mask;
+      mode_out->key_b = prof.key_b & mask;
+      mode_out->key_defined = 1;
+    }
+  }
+
+  return error;
+}
+
+#endif /* #ifdef LODEPNG_COMPILE_ENCODER */
+
+/*
+Paeth predicter, used by PNG filter type 4
+The parameters are of type short, but should come from unsigned chars, the shorts
+are only needed to make the paeth calculation correct.
+*/
+static unsigned char paethPredictor(short a, short b, short c)
+{
+  short pa = abs(b - c);
+  short pb = abs(a - c);
+  short pc = abs(a + b - c - c);
+
+  if(pc < pa && pc < pb) return (unsigned char)c;
+  else if(pb < pa) return (unsigned char)b;
+  else return (unsigned char)a;
+}
+
+/*shared values used by multiple Adam7 related functions*/
+
+static const unsigned ADAM7_IX[7] = { 0, 4, 0, 2, 0, 1, 0 }; /*x start values*/
+static const unsigned ADAM7_IY[7] = { 0, 0, 4, 0, 2, 0, 1 }; /*y start values*/
+static const unsigned ADAM7_DX[7] = { 8, 8, 4, 4, 2, 2, 1 }; /*x delta values*/
+static const unsigned ADAM7_DY[7] = { 8, 8, 8, 4, 4, 2, 2 }; /*y delta values*/
+
+/*
+Outputs various dimensions and positions in the image related to the Adam7 reduced images.
+passw: output containing the width of the 7 passes
+passh: output containing the height of the 7 passes
+filter_passstart: output containing the index of the start and end of each
+ reduced image with filter bytes
+padded_passstart output containing the index of the start and end of each
+ reduced image when without filter bytes but with padded scanlines
+passstart: output containing the index of the start and end of each reduced
+ image without padding between scanlines, but still padding between the images
+w, h: width and height of non-interlaced image
+bpp: bits per pixel
+"padded" is only relevant if bpp is less than 8 and a scanline or image does not
+ end at a full byte
+*/
+static void Adam7_getpassvalues(unsigned passw[7], unsigned passh[7], size_t filter_passstart[8],
+                                size_t padded_passstart[8], size_t passstart[8], unsigned w, unsigned h, unsigned bpp)
+{
+  /*the passstart values have 8 values: the 8th one indicates the byte after the end of the 7th (= last) pass*/
+  unsigned i;
+
+  /*calculate width and height in pixels of each pass*/
+  for(i = 0; i != 7; ++i)
+  {
+    passw[i] = (w + ADAM7_DX[i] - ADAM7_IX[i] - 1) / ADAM7_DX[i];
+    passh[i] = (h + ADAM7_DY[i] - ADAM7_IY[i] - 1) / ADAM7_DY[i];
+    if(passw[i] == 0) passh[i] = 0;
+    if(passh[i] == 0) passw[i] = 0;
+  }
+
+  filter_passstart[0] = padded_passstart[0] = passstart[0] = 0;
+  for(i = 0; i != 7; ++i)
+  {
+    /*if passw[i] is 0, it's 0 bytes, not 1 (no filtertype-byte)*/
+    filter_passstart[i + 1] = filter_passstart[i]
+                            + ((passw[i] && passh[i]) ? passh[i] * (1 + (passw[i] * bpp + 7) / 8) : 0);
+    /*bits padded if needed to fill full byte at end of each scanline*/
+    padded_passstart[i + 1] = padded_passstart[i] + passh[i] * ((passw[i] * bpp + 7) / 8);
+    /*only padded at end of reduced image*/
+    passstart[i + 1] = passstart[i] + (passh[i] * passw[i] * bpp + 7) / 8;
+  }
+}
+
+#ifdef LODEPNG_COMPILE_DECODER
+
+/* ////////////////////////////////////////////////////////////////////////// */
+/* / PNG Decoder                                                            / */
+/* ////////////////////////////////////////////////////////////////////////// */
+
+/*read the information from the header and store it in the LodePNGInfo. return value is error*/
+unsigned lodepng_inspect(unsigned* w, unsigned* h, LodePNGState* state,
+                         const unsigned char* in, size_t insize)
+{
+  LodePNGInfo* info = &state->info_png;
+  if(insize == 0 || in == 0)
+  {
+    CERROR_RETURN_ERROR(state->error, 48); /*error: the given data is empty*/
+  }
+  if(insize < 33)
+  {
+    CERROR_RETURN_ERROR(state->error, 27); /*error: the data length is smaller than the length of a PNG header*/
+  }
+
+  /*when decoding a new PNG image, make sure all parameters created after previous decoding are reset*/
+  lodepng_info_cleanup(info);
+  lodepng_info_init(info);
+
+  if(in[0] != 137 || in[1] != 80 || in[2] != 78 || in[3] != 71
+     || in[4] != 13 || in[5] != 10 || in[6] != 26 || in[7] != 10)
+  {
+    CERROR_RETURN_ERROR(state->error, 28); /*error: the first 8 bytes are not the correct PNG signature*/
+  }
+  if(in[12] != 'I' || in[13] != 'H' || in[14] != 'D' || in[15] != 'R')
+  {
+    CERROR_RETURN_ERROR(state->error, 29); /*error: it doesn't start with a IHDR chunk!*/
+  }
+
+  /*read the values given in the header*/
+  *w = lodepng_read32bitInt(&in[16]);
+  *h = lodepng_read32bitInt(&in[20]);
+  info->color.bitdepth = in[24];
+  info->color.colortype = (LodePNGColorType)in[25];
+  info->compression_method = in[26];
+  info->filter_method = in[27];
+  info->interlace_method = in[28];
+
+  if(*w == 0 || *h == 0)
+  {
+    CERROR_RETURN_ERROR(state->error, 93);
+  }
+
+  if(!state->decoder.ignore_crc)
+  {
+    unsigned CRC = lodepng_read32bitInt(&in[29]);
+    unsigned checksum = lodepng_crc32(&in[12], 17);
+    if(CRC != checksum)
+    {
+      CERROR_RETURN_ERROR(state->error, 57); /*invalid CRC*/
+    }
+  }
+
+  /*error: only compression method 0 is allowed in the specification*/
+  if(info->compression_method != 0) CERROR_RETURN_ERROR(state->error, 32);
+  /*error: only filter method 0 is allowed in the specification*/
+  if(info->filter_method != 0) CERROR_RETURN_ERROR(state->error, 33);
+  /*error: only interlace methods 0 and 1 exist in the specification*/
+  if(info->interlace_method > 1) CERROR_RETURN_ERROR(state->error, 34);
+
+  state->error = checkColorValidity(info->color.colortype, info->color.bitdepth);
+  return state->error;
+}
+
+static unsigned unfilterScanline(unsigned char* recon, const unsigned char* scanline, const unsigned char* precon,
+                                 size_t bytewidth, unsigned char filterType, size_t length)
+{
+  /*
+  For PNG filter method 0
+  unfilter a PNG image scanline by scanline. when the pixels are smaller than 1 byte,
+  the filter works byte per byte (bytewidth = 1)
+  precon is the previous unfiltered scanline, recon the result, scanline the current one
+  the incoming scanlines do NOT include the filtertype byte, that one is given in the parameter filterType instead
+  recon and scanline MAY be the same memory address! precon must be disjoint.
+  */
+
+  size_t i;
+  switch(filterType)
+  {
+    case 0:
+      for(i = 0; i != length; ++i) recon[i] = scanline[i];
+      break;
+    case 1:
+      for(i = 0; i != bytewidth; ++i) recon[i] = scanline[i];
+      for(i = bytewidth; i < length; ++i) recon[i] = scanline[i] + recon[i - bytewidth];
+      break;
+    case 2:
+      if(precon)
+      {
+        for(i = 0; i != length; ++i) recon[i] = scanline[i] + precon[i];
+      }
+      else
+      {
+        for(i = 0; i != length; ++i) recon[i] = scanline[i];
+      }
+      break;
+    case 3:
+      if(precon)
+      {
+        for(i = 0; i != bytewidth; ++i) recon[i] = scanline[i] + precon[i] / 2;
+        for(i = bytewidth; i < length; ++i) recon[i] = scanline[i] + ((recon[i - bytewidth] + precon[i]) / 2);
+      }
+      else
+      {
+        for(i = 0; i != bytewidth; ++i) recon[i] = scanline[i];
+        for(i = bytewidth; i < length; ++i) recon[i] = scanline[i] + recon[i - bytewidth] / 2;
+      }
+      break;
+    case 4:
+      if(precon)
+      {
+        for(i = 0; i != bytewidth; ++i)
+        {
+          recon[i] = (scanline[i] + precon[i]); /*paethPredictor(0, precon[i], 0) is always precon[i]*/
+        }
+        for(i = bytewidth; i < length; ++i)
+        {
+          recon[i] = (scanline[i] + paethPredictor(recon[i - bytewidth], precon[i], precon[i - bytewidth]));
+        }
+      }
+      else
+      {
+        for(i = 0; i != bytewidth; ++i)
+        {
+          recon[i] = scanline[i];
+        }
+        for(i = bytewidth; i < length; ++i)
+        {
+          /*paethPredictor(recon[i - bytewidth], 0, 0) is always recon[i - bytewidth]*/
+          recon[i] = (scanline[i] + recon[i - bytewidth]);
+        }
+      }
+      break;
+    default: return 36; /*error: unexisting filter type given*/
+  }
+  return 0;
+}
+
+static unsigned unfilter(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp)
+{
+  /*
+  For PNG filter method 0
+  this function unfilters a single image (e.g. without interlacing this is called once, with Adam7 seven times)
+  out must have enough bytes allocated already, in must have the scanlines + 1 filtertype byte per scanline
+  w and h are image dimensions or dimensions of reduced image, bpp is bits per pixel
+  in and out are allowed to be the same memory address (but aren't the same size since in has the extra filter bytes)
+  */
+
+  unsigned y;
+  unsigned char* prevline = 0;
+
+  /*bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per pixel otherwise*/
+  size_t bytewidth = (bpp + 7) / 8;
+  size_t linebytes = (w * bpp + 7) / 8;
+
+  for(y = 0; y < h; ++y)
+  {
+    size_t outindex = linebytes * y;
+    size_t inindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/
+    unsigned char filterType = in[inindex];
+
+    CERROR_TRY_RETURN(unfilterScanline(&out[outindex], &in[inindex + 1], prevline, bytewidth, filterType, linebytes));
+
+    prevline = &out[outindex];
+  }
+
+  return 0;
+}
+
+/*
+in: Adam7 interlaced image, with no padding bits between scanlines, but between
+ reduced images so that each reduced image starts at a byte.
+out: the same pixels, but re-ordered so that they're now a non-interlaced image with size w*h
+bpp: bits per pixel
+out has the following size in bits: w * h * bpp.
+in is possibly bigger due to padding bits between reduced images.
+out must be big enough AND must be 0 everywhere if bpp < 8 in the current implementation
+(because that's likely a little bit faster)
+NOTE: comments about padding bits are only relevant if bpp < 8
+*/
+static void Adam7_deinterlace(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp)
+{
+  unsigned passw[7], passh[7];
+  size_t filter_passstart[8], padded_passstart[8], passstart[8];
+  unsigned i;
+
+  Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp);
+
+  if(bpp >= 8)
+  {
+    for(i = 0; i != 7; ++i)
+    {
+      unsigned x, y, b;
+      size_t bytewidth = bpp / 8;
+      for(y = 0; y < passh[i]; ++y)
+      for(x = 0; x < passw[i]; ++x)
+      {
+        size_t pixelinstart = passstart[i] + (y * passw[i] + x) * bytewidth;
+        size_t pixeloutstart = ((ADAM7_IY[i] + y * ADAM7_DY[i]) * w + ADAM7_IX[i] + x * ADAM7_DX[i]) * bytewidth;
+        for(b = 0; b < bytewidth; ++b)
+        {
+          out[pixeloutstart + b] = in[pixelinstart + b];
+        }
+      }
+    }
+  }
+  else /*bpp < 8: Adam7 with pixels < 8 bit is a bit trickier: with bit pointers*/
+  {
+    for(i = 0; i != 7; ++i)
+    {
+      unsigned x, y, b;
+      unsigned ilinebits = bpp * passw[i];
+      unsigned olinebits = bpp * w;
+      size_t obp, ibp; /*bit pointers (for out and in buffer)*/
+      for(y = 0; y < passh[i]; ++y)
+      for(x = 0; x < passw[i]; ++x)
+      {
+        ibp = (8 * passstart[i]) + (y * ilinebits + x * bpp);
+        obp = (ADAM7_IY[i] + y * ADAM7_DY[i]) * olinebits + (ADAM7_IX[i] + x * ADAM7_DX[i]) * bpp;
+        for(b = 0; b < bpp; ++b)
+        {
+          unsigned char bit = readBitFromReversedStream(&ibp, in);
+          /*note that this function assumes the out buffer is completely 0, use setBitOfReversedStream otherwise*/
+          setBitOfReversedStream0(&obp, out, bit);
+        }
+      }
+    }
+  }
+}
+
+static void removePaddingBits(unsigned char* out, const unsigned char* in,
+                              size_t olinebits, size_t ilinebits, unsigned h)
+{
+  /*
+  After filtering there are still padding bits if scanlines have non multiple of 8 bit amounts. They need
+  to be removed (except at last scanline of (Adam7-reduced) image) before working with pure image buffers
+  for the Adam7 code, the color convert code and the output to the user.
+  in and out are allowed to be the same buffer, in may also be higher but still overlapping; in must
+  have >= ilinebits*h bits, out must have >= olinebits*h bits, olinebits must be <= ilinebits
+  also used to move bits after earlier such operations happened, e.g. in a sequence of reduced images from Adam7
+  only useful if (ilinebits - olinebits) is a value in the range 1..7
+  */
+  unsigned y;
+  size_t diff = ilinebits - olinebits;
+  size_t ibp = 0, obp = 0; /*input and output bit pointers*/
+  for(y = 0; y < h; ++y)
+  {
+    size_t x;
+    for(x = 0; x < olinebits; ++x)
+    {
+      unsigned char bit = readBitFromReversedStream(&ibp, in);
+      setBitOfReversedStream(&obp, out, bit);
+    }
+    ibp += diff;
+  }
+}
+
+/*out must be buffer big enough to contain full image, and in must contain the full decompressed data from
+the IDAT chunks (with filter index bytes and possible padding bits)
+return value is error*/
+static unsigned postProcessScanlines(unsigned char* out, unsigned char* in,
+                                     unsigned w, unsigned h, const LodePNGInfo* info_png)
+{
+  /*
+  This function converts the filtered-padded-interlaced data into pure 2D image buffer with the PNG's colortype.
+  Steps:
+  *) if no Adam7: 1) unfilter 2) remove padding bits (= posible extra bits per scanline if bpp < 8)
+  *) if adam7: 1) 7x unfilter 2) 7x remove padding bits 3) Adam7_deinterlace
+  NOTE: the in buffer will be overwritten with intermediate data!
+  */
+  unsigned bpp = lodepng_get_bpp(&info_png->color);
+  if(bpp == 0) return 31; /*error: invalid colortype*/
+
+  if(info_png->interlace_method == 0)
+  {
+    if(bpp < 8 && w * bpp != ((w * bpp + 7) / 8) * 8)
+    {
+      CERROR_TRY_RETURN(unfilter(in, in, w, h, bpp));
+      removePaddingBits(out, in, w * bpp, ((w * bpp + 7) / 8) * 8, h);
+    }
+    /*we can immediately filter into the out buffer, no other steps needed*/
+    else CERROR_TRY_RETURN(unfilter(out, in, w, h, bpp));
+  }
+  else /*interlace_method is 1 (Adam7)*/
+  {
+    unsigned passw[7], passh[7]; size_t filter_passstart[8], padded_passstart[8], passstart[8];
+    unsigned i;
+
+    Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp);
+
+    for(i = 0; i != 7; ++i)
+    {
+      CERROR_TRY_RETURN(unfilter(&in[padded_passstart[i]], &in[filter_passstart[i]], passw[i], passh[i], bpp));
+      /*TODO: possible efficiency improvement: if in this reduced image the bits fit nicely in 1 scanline,
+      move bytes instead of bits or move not at all*/
+      if(bpp < 8)
+      {
+        /*remove padding bits in scanlines; after this there still may be padding
+        bits between the different reduced images: each reduced image still starts nicely at a byte*/
+        removePaddingBits(&in[passstart[i]], &in[padded_passstart[i]], passw[i] * bpp,
+                          ((passw[i] * bpp + 7) / 8) * 8, passh[i]);
+      }
+    }
+
+    Adam7_deinterlace(out, in, w, h, bpp);
+  }
+
+  return 0;
+}
+
+static unsigned readChunk_PLTE(LodePNGColorMode* color, const unsigned char* data, size_t chunkLength)
+{
+  unsigned pos = 0, i;
+  if(color->palette) lodepng_free(color->palette);
+  color->palettesize = chunkLength / 3;
+  color->palette = (unsigned char*)lodepng_malloc(4 * color->palettesize);
+  if(!color->palette && color->palettesize)
+  {
+    color->palettesize = 0;
+    return 83; /*alloc fail*/
+  }
+  if(color->palettesize > 256) return 38; /*error: palette too big*/
+
+  for(i = 0; i != color->palettesize; ++i)
+  {
+    color->palette[4 * i + 0] = data[pos++]; /*R*/
+    color->palette[4 * i + 1] = data[pos++]; /*G*/
+    color->palette[4 * i + 2] = data[pos++]; /*B*/
+    color->palette[4 * i + 3] = 255; /*alpha*/
+  }
+
+  return 0; /* OK */
+}
+
+static unsigned readChunk_tRNS(LodePNGColorMode* color, const unsigned char* data, size_t chunkLength)
+{
+  unsigned i;
+  if(color->colortype == LCT_PALETTE)
+  {
+    /*error: more alpha values given than there are palette entries*/
+    if(chunkLength > color->palettesize) return 38;
+
+    for(i = 0; i != chunkLength; ++i) color->palette[4 * i + 3] = data[i];
+  }
+  else if(color->colortype == LCT_GREY)
+  {
+    /*error: this chunk must be 2 bytes for greyscale image*/
+    if(chunkLength != 2) return 30;
+
+    color->key_defined = 1;
+    color->key_r = color->key_g = color->key_b = 256u * data[0] + data[1];
+  }
+  else if(color->colortype == LCT_RGB)
+  {
+    /*error: this chunk must be 6 bytes for RGB image*/
+    if(chunkLength != 6) return 41;
+
+    color->key_defined = 1;
+    color->key_r = 256u * data[0] + data[1];
+    color->key_g = 256u * data[2] + data[3];
+    color->key_b = 256u * data[4] + data[5];
+  }
+  else return 42; /*error: tRNS chunk not allowed for other color models*/
+
+  return 0; /* OK */
+}
+
+
+#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
+/*background color chunk (bKGD)*/
+static unsigned readChunk_bKGD(LodePNGInfo* info, const unsigned char* data, size_t chunkLength)
+{
+  if(info->color.colortype == LCT_PALETTE)
+  {
+    /*error: this chunk must be 1 byte for indexed color image*/
+    if(chunkLength != 1) return 43;
+
+    info->background_defined = 1;
+    info->background_r = info->background_g = info->background_b = data[0];
+  }
+  else if(info->color.colortype == LCT_GREY || info->color.colortype == LCT_GREY_ALPHA)
+  {
+    /*error: this chunk must be 2 bytes for greyscale image*/
+    if(chunkLength != 2) return 44;
+
+    info->background_defined = 1;
+    info->background_r = info->background_g = info->background_b = 256u * data[0] + data[1];
+  }
+  else if(info->color.colortype == LCT_RGB || info->color.colortype == LCT_RGBA)
+  {
+    /*error: this chunk must be 6 bytes for greyscale image*/
+    if(chunkLength != 6) return 45;
+
+    info->background_defined = 1;
+    info->background_r = 256u * data[0] + data[1];
+    info->background_g = 256u * data[2] + data[3];
+    info->background_b = 256u * data[4] + data[5];
+  }
+
+  return 0; /* OK */
+}
+
+/*text chunk (tEXt)*/
+static unsigned readChunk_tEXt(LodePNGInfo* info, const unsigned char* data, size_t chunkLength)
+{
+  unsigned error = 0;
+  char *key = 0, *str = 0;
+  unsigned i;
+
+  while(!error) /*not really a while loop, only used to break on error*/
+  {
+    unsigned length, string2_begin;
+
+    length = 0;
+    while(length < chunkLength && data[length] != 0) ++length;
+    /*even though it's not allowed by the standard, no error is thrown if
+    there's no null termination char, if the text is empty*/
+    if(length < 1 || length > 79) CERROR_BREAK(error, 89); /*keyword too short or long*/
+
+    key = (char*)lodepng_malloc(length + 1);
+    if(!key) CERROR_BREAK(error, 83); /*alloc fail*/
+
+    key[length] = 0;
+    for(i = 0; i != length; ++i) key[i] = (char)data[i];
+
+    string2_begin = length + 1; /*skip keyword null terminator*/
+
+    length = chunkLength < string2_begin ? 0 : chunkLength - string2_begin;
+    str = (char*)lodepng_malloc(length + 1);
+    if(!str) CERROR_BREAK(error, 83); /*alloc fail*/
+
+    str[length] = 0;
+    for(i = 0; i != length; ++i) str[i] = (char)data[string2_begin + i];
+
+    error = lodepng_add_text(info, key, str);
+
+    break;
+  }
+
+  lodepng_free(key);
+  lodepng_free(str);
+
+  return error;
+}
+
+/*compressed text chunk (zTXt)*/
+static unsigned readChunk_zTXt(LodePNGInfo* info, const LodePNGDecompressSettings* zlibsettings,
+                               const unsigned char* data, size_t chunkLength)
+{
+  unsigned error = 0;
+  unsigned i;
+
+  unsigned length, string2_begin;
+  char *key = 0;
+  ucvector decoded;
+
+  ucvector_init(&decoded);
+
+  while(!error) /*not really a while loop, only used to break on error*/
+  {
+    for(length = 0; length < chunkLength && data[length] != 0; ++length) ;
+    if(length + 2 >= chunkLength) CERROR_BREAK(error, 75); /*no null termination, corrupt?*/
+    if(length < 1 || length > 79) CERROR_BREAK(error, 89); /*keyword too short or long*/
+
+    key = (char*)lodepng_malloc(length + 1);
+    if(!key) CERROR_BREAK(error, 83); /*alloc fail*/
+
+    key[length] = 0;
+    for(i = 0; i != length; ++i) key[i] = (char)data[i];
+
+    if(data[length + 1] != 0) CERROR_BREAK(error, 72); /*the 0 byte indicating compression must be 0*/
+
+    string2_begin = length + 2;
+    if(string2_begin > chunkLength) CERROR_BREAK(error, 75); /*no null termination, corrupt?*/
+
+    length = chunkLength - string2_begin;
+    /*will fail if zlib error, e.g. if length is too small*/
+    error = zlib_decompress(&decoded.data, &decoded.size,
+                            (unsigned char*)(&data[string2_begin]),
+                            length, zlibsettings);
+    if(error) break;
+    ucvector_push_back(&decoded, 0);
+
+    error = lodepng_add_text(info, key, (char*)decoded.data);
+
+    break;
+  }
+
+  lodepng_free(key);
+  ucvector_cleanup(&decoded);
+
+  return error;
+}
+
+/*international text chunk (iTXt)*/
+static unsigned readChunk_iTXt(LodePNGInfo* info, const LodePNGDecompressSettings* zlibsettings,
+                               const unsigned char* data, size_t chunkLength)
+{
+  unsigned error = 0;
+  unsigned i;
+
+  unsigned length, begin, compressed;
+  char *key = 0, *langtag = 0, *transkey = 0;
+  ucvector decoded;
+  ucvector_init(&decoded);
+
+  while(!error) /*not really a while loop, only used to break on error*/
+  {
+    /*Quick check if the chunk length isn't too small. Even without check
+    it'd still fail with other error checks below if it's too short. This just gives a different error code.*/
+    if(chunkLength < 5) CERROR_BREAK(error, 30); /*iTXt chunk too short*/
+
+    /*read the key*/
+    for(length = 0; length < chunkLength && data[length] != 0; ++length) ;
+    if(length + 3 >= chunkLength) CERROR_BREAK(error, 75); /*no null termination char, corrupt?*/
+    if(length < 1 || length > 79) CERROR_BREAK(error, 89); /*keyword too short or long*/
+
+    key = (char*)lodepng_malloc(length + 1);
+    if(!key) CERROR_BREAK(error, 83); /*alloc fail*/
+
+    key[length] = 0;
+    for(i = 0; i != length; ++i) key[i] = (char)data[i];
+
+    /*read the compression method*/
+    compressed = data[length + 1];
+    if(data[length + 2] != 0) CERROR_BREAK(error, 72); /*the 0 byte indicating compression must be 0*/
+
+    /*even though it's not allowed by the standard, no error is thrown if
+    there's no null termination char, if the text is empty for the next 3 texts*/
+
+    /*read the langtag*/
+    begin = length + 3;
+    length = 0;
+    for(i = begin; i < chunkLength && data[i] != 0; ++i) ++length;
+
+    langtag = (char*)lodepng_malloc(length + 1);
+    if(!langtag) CERROR_BREAK(error, 83); /*alloc fail*/
+
+    langtag[length] = 0;
+    for(i = 0; i != length; ++i) langtag[i] = (char)data[begin + i];
+
+    /*read the transkey*/
+    begin += length + 1;
+    length = 0;
+    for(i = begin; i < chunkLength && data[i] != 0; ++i) ++length;
+
+    transkey = (char*)lodepng_malloc(length + 1);
+    if(!transkey) CERROR_BREAK(error, 83); /*alloc fail*/
+
+    transkey[length] = 0;
+    for(i = 0; i != length; ++i) transkey[i] = (char)data[begin + i];
+
+    /*read the actual text*/
+    begin += length + 1;
+
+    length = chunkLength < begin ? 0 : chunkLength - begin;
+
+    if(compressed)
+    {
+      /*will fail if zlib error, e.g. if length is too small*/
+      error = zlib_decompress(&decoded.data, &decoded.size,
+                              (unsigned char*)(&data[begin]),
+                              length, zlibsettings);
+      if(error) break;
+      if(decoded.allocsize < decoded.size) decoded.allocsize = decoded.size;
+      ucvector_push_back(&decoded, 0);
+    }
+    else
+    {
+      if(!ucvector_resize(&decoded, length + 1)) CERROR_BREAK(error, 83 /*alloc fail*/);
+
+      decoded.data[length] = 0;
+      for(i = 0; i != length; ++i) decoded.data[i] = data[begin + i];
+    }
+
+    error = lodepng_add_itext(info, key, langtag, transkey, (char*)decoded.data);
+
+    break;
+  }
+
+  lodepng_free(key);
+  lodepng_free(langtag);
+  lodepng_free(transkey);
+  ucvector_cleanup(&decoded);
+
+  return error;
+}
+
+static unsigned readChunk_tIME(LodePNGInfo* info, const unsigned char* data, size_t chunkLength)
+{
+  if(chunkLength != 7) return 73; /*invalid tIME chunk size*/
+
+  info->time_defined = 1;
+  info->time.year = 256u * data[0] + data[1];
+  info->time.month = data[2];
+  info->time.day = data[3];
+  info->time.hour = data[4];
+  info->time.minute = data[5];
+  info->time.second = data[6];
+
+  return 0; /* OK */
+}
+
+static unsigned readChunk_pHYs(LodePNGInfo* info, const unsigned char* data, size_t chunkLength)
+{
+  if(chunkLength != 9) return 74; /*invalid pHYs chunk size*/
+
+  info->phys_defined = 1;
+  info->phys_x = 16777216u * data[0] + 65536u * data[1] + 256u * data[2] + data[3];
+  info->phys_y = 16777216u * data[4] + 65536u * data[5] + 256u * data[6] + data[7];
+  info->phys_unit = data[8];
+
+  return 0; /* OK */
+}
+#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
+
+/*read a PNG, the result will be in the same color type as the PNG (hence "generic")*/
+static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h,
+                          LodePNGState* state,
+                          const unsigned char* in, size_t insize)
+{
+  unsigned char IEND = 0;
+  const unsigned char* chunk;
+  size_t i;
+  ucvector idat; /*the data from idat chunks*/
+  ucvector scanlines;
+  size_t predict;
+  size_t numpixels;
+
+  /*for unknown chunk order*/
+  unsigned unknown = 0;
+#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
+  unsigned critical_pos = 1; /*1 = after IHDR, 2 = after PLTE, 3 = after IDAT*/
+#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
+
+  /*provide some proper output values if error will happen*/
+  *out = 0;
+
+  state->error = lodepng_inspect(w, h, state, in, insize); /*reads header and resets other parameters in state->info_png*/
+  if(state->error) return;
+
+  numpixels = *w * *h;
+
+  /*multiplication overflow*/
+  if(*h != 0 && numpixels / *h != *w) CERROR_RETURN(state->error, 92);
+  /*multiplication overflow possible further below. Allows up to 2^31-1 pixel
+  bytes with 16-bit RGBA, the rest is room for filter bytes.*/
+  if(numpixels > 268435455) CERROR_RETURN(state->error, 92);
+
+  ucvector_init(&idat);
+  chunk = &in[33]; /*first byte of the first chunk after the header*/
+
+  /*loop through the chunks, ignoring unknown chunks and stopping at IEND chunk.
+  IDAT data is put at the start of the in buffer*/
+  while(!IEND && !state->error)
+  {
+    unsigned chunkLength;
+    const unsigned char* data; /*the data in the chunk*/
+
+    /*error: size of the in buffer too small to contain next chunk*/
+    if((size_t)((chunk - in) + 12) > insize || chunk < in) CERROR_BREAK(state->error, 30);
+
+    /*length of the data of the chunk, excluding the length bytes, chunk type and CRC bytes*/
+    chunkLength = lodepng_chunk_length(chunk);
+    /*error: chunk length larger than the max PNG chunk size*/
+    if(chunkLength > 2147483647) CERROR_BREAK(state->error, 63);
+
+    if((size_t)((chunk - in) + chunkLength + 12) > insize || (chunk + chunkLength + 12) < in)
+    {
+      CERROR_BREAK(state->error, 64); /*error: size of the in buffer too small to contain next chunk*/
+    }
+
+    data = lodepng_chunk_data_const(chunk);
+
+    /*IDAT chunk, containing compressed image data*/
+    if(lodepng_chunk_type_equals(chunk, "IDAT"))
+    {
+      size_t oldsize = idat.size;
+      if(!ucvector_resize(&idat, oldsize + chunkLength)) CERROR_BREAK(state->error, 83 /*alloc fail*/);
+      for(i = 0; i != chunkLength; ++i) idat.data[oldsize + i] = data[i];
+#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
+      critical_pos = 3;
+#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
+    }
+    /*IEND chunk*/
+    else if(lodepng_chunk_type_equals(chunk, "IEND"))
+    {
+      IEND = 1;
+    }
+    /*palette chunk (PLTE)*/
+    else if(lodepng_chunk_type_equals(chunk, "PLTE"))
+    {
+      state->error = readChunk_PLTE(&state->info_png.color, data, chunkLength);
+      if(state->error) break;
+#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
+      critical_pos = 2;
+#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
+    }
+    /*palette transparency chunk (tRNS)*/
+    else if(lodepng_chunk_type_equals(chunk, "tRNS"))
+    {
+      state->error = readChunk_tRNS(&state->info_png.color, data, chunkLength);
+      if(state->error) break;
+    }
+#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
+    /*background color chunk (bKGD)*/
+    else if(lodepng_chunk_type_equals(chunk, "bKGD"))
+    {
+      state->error = readChunk_bKGD(&state->info_png, data, chunkLength);
+      if(state->error) break;
+    }
+    /*text chunk (tEXt)*/
+    else if(lodepng_chunk_type_equals(chunk, "tEXt"))
+    {
+      if(state->decoder.read_text_chunks)
+      {
+        state->error = readChunk_tEXt(&state->info_png, data, chunkLength);
+        if(state->error) break;
+      }
+    }
+    /*compressed text chunk (zTXt)*/
+    else if(lodepng_chunk_type_equals(chunk, "zTXt"))
+    {
+      if(state->decoder.read_text_chunks)
+      {
+        state->error = readChunk_zTXt(&state->info_png, &state->decoder.zlibsettings, data, chunkLength);
+        if(state->error) break;
+      }
+    }
+    /*international text chunk (iTXt)*/
+    else if(lodepng_chunk_type_equals(chunk, "iTXt"))
+    {
+      if(state->decoder.read_text_chunks)
+      {
+        state->error = readChunk_iTXt(&state->info_png, &state->decoder.zlibsettings, data, chunkLength);
+        if(state->error) break;
+      }
+    }
+    else if(lodepng_chunk_type_equals(chunk, "tIME"))
+    {
+      state->error = readChunk_tIME(&state->info_png, data, chunkLength);
+      if(state->error) break;
+    }
+    else if(lodepng_chunk_type_equals(chunk, "pHYs"))
+    {
+      state->error = readChunk_pHYs(&state->info_png, data, chunkLength);
+      if(state->error) break;
+    }
+#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
+    else /*it's not an implemented chunk type, so ignore it: skip over the data*/
+    {
+      /*error: unknown critical chunk (5th bit of first byte of chunk type is 0)*/
+      if(!lodepng_chunk_ancillary(chunk)) CERROR_BREAK(state->error, 69);
+
+      unknown = 1;
+#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
+      if(state->decoder.remember_unknown_chunks)
+      {
+        state->error = lodepng_chunk_append(&state->info_png.unknown_chunks_data[critical_pos - 1],
+                                            &state->info_png.unknown_chunks_size[critical_pos - 1], chunk);
+        if(state->error) break;
+      }
+#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
+    }
+
+    if(!state->decoder.ignore_crc && !unknown) /*check CRC if wanted, only on known chunk types*/
+    {
+      if(lodepng_chunk_check_crc(chunk)) CERROR_BREAK(state->error, 57); /*invalid CRC*/
+    }
+
+    if(!IEND) chunk = lodepng_chunk_next_const(chunk);
+  }
+
+  ucvector_init(&scanlines);
+  /*predict output size, to allocate exact size for output buffer to avoid more dynamic allocation.
+  If the decompressed size does not match the prediction, the image must be corrupt.*/
+  if(state->info_png.interlace_method == 0)
+  {
+    /*The extra *h is added because this are the filter bytes every scanline starts with*/
+    predict = lodepng_get_raw_size_idat(*w, *h, &state->info_png.color) + *h;
+  }
+  else
+  {
+    /*Adam-7 interlaced: predicted size is the sum of the 7 sub-images sizes*/
+    const LodePNGColorMode* color = &state->info_png.color;
+    predict = 0;
+    predict += lodepng_get_raw_size_idat((*w + 7) / 8, (*h + 7) / 8, color) + (*h + 7) / 8;
+    if(*w > 4) predict += lodepng_get_raw_size_idat((*w + 3) / 8, (*h + 7) / 8, color) + (*h + 7) / 8;
+    predict += lodepng_get_raw_size_idat((*w + 3) / 4, (*h + 3) / 8, color) + (*h + 3) / 8;
+    if(*w > 2) predict += lodepng_get_raw_size_idat((*w + 1) / 4, (*h + 3) / 4, color) + (*h + 3) / 4;
+    predict += lodepng_get_raw_size_idat((*w + 1) / 2, (*h + 1) / 4, color) + (*h + 1) / 4;
+    if(*w > 1) predict += lodepng_get_raw_size_idat((*w + 0) / 2, (*h + 1) / 2, color) + (*h + 1) / 2;
+    predict += lodepng_get_raw_size_idat((*w + 0) / 1, (*h + 0) / 2, color) + (*h + 0) / 2;
+  }
+  if(!state->error && !ucvector_reserve(&scanlines, predict)) state->error = 83; /*alloc fail*/
+  if(!state->error)
+  {
+    state->error = zlib_decompress(&scanlines.data, &scanlines.size, idat.data,
+                                   idat.size, &state->decoder.zlibsettings);
+    if(!state->error && scanlines.size != predict) state->error = 91; /*decompressed size doesn't match prediction*/
+  }
+  ucvector_cleanup(&idat);
+
+  if(!state->error)
+  {
+    size_t outsize = lodepng_get_raw_size(*w, *h, &state->info_png.color);
+    ucvector outv;
+    ucvector_init(&outv);
+    if(!ucvector_resizev(&outv, outsize, 0)) state->error = 83; /*alloc fail*/
+    if(!state->error) state->error = postProcessScanlines(outv.data, scanlines.data, *w, *h, &state->info_png);
+    *out = outv.data;
+  }
+  ucvector_cleanup(&scanlines);
+}
+
+unsigned lodepng_decode(unsigned char** out, unsigned* w, unsigned* h,
+                        LodePNGState* state,
+                        const unsigned char* in, size_t insize)
+{
+  *out = 0;
+  decodeGeneric(out, w, h, state, in, insize);
+  if(state->error) return state->error;
+  if(!state->decoder.color_convert || lodepng_color_mode_equal(&state->info_raw, &state->info_png.color))
+  {
+    /*same color type, no copying or converting of data needed*/
+    /*store the info_png color settings on the info_raw so that the info_raw still reflects what colortype
+    the raw image has to the end user*/
+    if(!state->decoder.color_convert)
+    {
+      state->error = lodepng_color_mode_copy(&state->info_raw, &state->info_png.color);
+      if(state->error) return state->error;
+    }
+  }
+  else
+  {
+    /*color conversion needed; sort of copy of the data*/
+    unsigned char* data = *out;
+    size_t outsize;
+
+    /*TODO: check if this works according to the statement in the documentation: "The converter can convert
+    from greyscale input color type, to 8-bit greyscale or greyscale with alpha"*/
+    if(!(state->info_raw.colortype == LCT_RGB || state->info_raw.colortype == LCT_RGBA)
+       && !(state->info_raw.bitdepth == 8))
+    {
+      return 56; /*unsupported color mode conversion*/
+    }
+
+    outsize = lodepng_get_raw_size(*w, *h, &state->info_raw);
+    *out = (unsigned char*)lodepng_malloc(outsize);
+    if(!(*out))
+    {
+      state->error = 83; /*alloc fail*/
+    }
+    else state->error = lodepng_convert(*out, data, &state->info_raw,
+                                        &state->info_png.color, *w, *h);
+    lodepng_free(data);
+  }
+  return state->error;
+}
+
+unsigned lodepng_decode_memory(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in,
+                               size_t insize, LodePNGColorType colortype, unsigned bitdepth)
+{
+  unsigned error;
+  LodePNGState state;
+  lodepng_state_init(&state);
+  state.info_raw.colortype = colortype;
+  state.info_raw.bitdepth = bitdepth;
+  error = lodepng_decode(out, w, h, &state, in, insize);
+  lodepng_state_cleanup(&state);
+  return error;
+}
+
+unsigned lodepng_decode32(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, size_t insize)
+{
+  return lodepng_decode_memory(out, w, h, in, insize, LCT_RGBA, 8);
+}
+
+unsigned lodepng_decode24(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, size_t insize)
+{
+  return lodepng_decode_memory(out, w, h, in, insize, LCT_RGB, 8);
+}
+
+#ifdef LODEPNG_COMPILE_DISK
+unsigned lodepng_decode_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename,
+                             LodePNGColorType colortype, unsigned bitdepth)
+{
+  unsigned char* buffer;
+  size_t buffersize;
+  unsigned error;
+  error = lodepng_load_file(&buffer, &buffersize, filename);
+  if(!error) error = lodepng_decode_memory(out, w, h, buffer, buffersize, colortype, bitdepth);
+  lodepng_free(buffer);
+  return error;
+}
+
+unsigned lodepng_decode32_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename)
+{
+  return lodepng_decode_file(out, w, h, filename, LCT_RGBA, 8);
+}
+
+unsigned lodepng_decode24_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename)
+{
+  return lodepng_decode_file(out, w, h, filename, LCT_RGB, 8);
+}
+#endif /*LODEPNG_COMPILE_DISK*/
+
+void lodepng_decoder_settings_init(LodePNGDecoderSettings* settings)
+{
+  settings->color_convert = 1;
+#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
+  settings->read_text_chunks = 1;
+  settings->remember_unknown_chunks = 0;
+#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
+  settings->ignore_crc = 0;
+  lodepng_decompress_settings_init(&settings->zlibsettings);
+}
+
+#endif /*LODEPNG_COMPILE_DECODER*/
+
+#if defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER)
+
+void lodepng_state_init(LodePNGState* state)
+{
+#ifdef LODEPNG_COMPILE_DECODER
+  lodepng_decoder_settings_init(&state->decoder);
+#endif /*LODEPNG_COMPILE_DECODER*/
+#ifdef LODEPNG_COMPILE_ENCODER
+  lodepng_encoder_settings_init(&state->encoder);
+#endif /*LODEPNG_COMPILE_ENCODER*/
+  lodepng_color_mode_init(&state->info_raw);
+  lodepng_info_init(&state->info_png);
+  state->error = 1;
+}
+
+void lodepng_state_cleanup(LodePNGState* state)
+{
+  lodepng_color_mode_cleanup(&state->info_raw);
+  lodepng_info_cleanup(&state->info_png);
+}
+
+void lodepng_state_copy(LodePNGState* dest, const LodePNGState* source)
+{
+  lodepng_state_cleanup(dest);
+  *dest = *source;
+  lodepng_color_mode_init(&dest->info_raw);
+  lodepng_info_init(&dest->info_png);
+  dest->error = lodepng_color_mode_copy(&dest->info_raw, &source->info_raw); if(dest->error) return;
+  dest->error = lodepng_info_copy(&dest->info_png, &source->info_png); if(dest->error) return;
+}
+
+#endif /* defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) */
+
+#ifdef LODEPNG_COMPILE_ENCODER
+
+/* ////////////////////////////////////////////////////////////////////////// */
+/* / PNG Encoder                                                            / */
+/* ////////////////////////////////////////////////////////////////////////// */
+
+/*chunkName must be string of 4 characters*/
+static unsigned addChunk(ucvector* out, const char* chunkName, const unsigned char* data, size_t length)
+{
+  CERROR_TRY_RETURN(lodepng_chunk_create(&out->data, &out->size, (unsigned)length, chunkName, data));
+  out->allocsize = out->size; /*fix the allocsize again*/
+  return 0;
+}
+
+static void writeSignature(ucvector* out)
+{
+  /*8 bytes PNG signature, aka the magic bytes*/
+  ucvector_push_back(out, 137);
+  ucvector_push_back(out, 80);
+  ucvector_push_back(out, 78);
+  ucvector_push_back(out, 71);
+  ucvector_push_back(out, 13);
+  ucvector_push_back(out, 10);
+  ucvector_push_back(out, 26);
+  ucvector_push_back(out, 10);
+}
+
+static unsigned addChunk_IHDR(ucvector* out, unsigned w, unsigned h,
+                              LodePNGColorType colortype, unsigned bitdepth, unsigned interlace_method)
+{
+  unsigned error = 0;
+  ucvector header;
+  ucvector_init(&header);
+
+  lodepng_add32bitInt(&header, w); /*width*/
+  lodepng_add32bitInt(&header, h); /*height*/
+  ucvector_push_back(&header, (unsigned char)bitdepth); /*bit depth*/
+  ucvector_push_back(&header, (unsigned char)colortype); /*color type*/
+  ucvector_push_back(&header, 0); /*compression method*/
+  ucvector_push_back(&header, 0); /*filter method*/
+  ucvector_push_back(&header, interlace_method); /*interlace method*/
+
+  error = addChunk(out, "IHDR", header.data, header.size);
+  ucvector_cleanup(&header);
+
+  return error;
+}
+
+static unsigned addChunk_PLTE(ucvector* out, const LodePNGColorMode* info)
+{
+  unsigned error = 0;
+  size_t i;
+  ucvector PLTE;
+  ucvector_init(&PLTE);
+  for(i = 0; i != info->palettesize * 4; ++i)
+  {
+    /*add all channels except alpha channel*/
+    if(i % 4 != 3) ucvector_push_back(&PLTE, info->palette[i]);
+  }
+  error = addChunk(out, "PLTE", PLTE.data, PLTE.size);
+  ucvector_cleanup(&PLTE);
+
+  return error;
+}
+
+static unsigned addChunk_tRNS(ucvector* out, const LodePNGColorMode* info)
+{
+  unsigned error = 0;
+  size_t i;
+  ucvector tRNS;
+  ucvector_init(&tRNS);
+  if(info->colortype == LCT_PALETTE)
+  {
+    size_t amount = info->palettesize;
+    /*the tail of palette values that all have 255 as alpha, does not have to be encoded*/
+    for(i = info->palettesize; i != 0; --i)
+    {
+      if(info->palette[4 * (i - 1) + 3] == 255) --amount;
+      else break;
+    }
+    /*add only alpha channel*/
+    for(i = 0; i != amount; ++i) ucvector_push_back(&tRNS, info->palette[4 * i + 3]);
+  }
+  else if(info->colortype == LCT_GREY)
+  {
+    if(info->key_defined)
+    {
+      ucvector_push_back(&tRNS, (unsigned char)(info->key_r / 256));
+      ucvector_push_back(&tRNS, (unsigned char)(info->key_r % 256));
+    }
+  }
+  else if(info->colortype == LCT_RGB)
+  {
+    if(info->key_defined)
+    {
+      ucvector_push_back(&tRNS, (unsigned char)(info->key_r / 256));
+      ucvector_push_back(&tRNS, (unsigned char)(info->key_r % 256));
+      ucvector_push_back(&tRNS, (unsigned char)(info->key_g / 256));
+      ucvector_push_back(&tRNS, (unsigned char)(info->key_g % 256));
+      ucvector_push_back(&tRNS, (unsigned char)(info->key_b / 256));
+      ucvector_push_back(&tRNS, (unsigned char)(info->key_b % 256));
+    }
+  }
+
+  error = addChunk(out, "tRNS", tRNS.data, tRNS.size);
+  ucvector_cleanup(&tRNS);
+
+  return error;
+}
+
+static unsigned addChunk_IDAT(ucvector* out, const unsigned char* data, size_t datasize,
+                              LodePNGCompressSettings* zlibsettings)
+{
+  ucvector zlibdata;
+  unsigned error = 0;
+
+  /*compress with the Zlib compressor*/
+  ucvector_init(&zlibdata);
+  error = zlib_compress(&zlibdata.data, &zlibdata.size, data, datasize, zlibsettings);
+  if(!error) error = addChunk(out, "IDAT", zlibdata.data, zlibdata.size);
+  ucvector_cleanup(&zlibdata);
+
+  return error;
+}
+
+static unsigned addChunk_IEND(ucvector* out)
+{
+  unsigned error = 0;
+  error = addChunk(out, "IEND", 0, 0);
+  return error;
+}
+
+#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
+
+static unsigned addChunk_tEXt(ucvector* out, const char* keyword, const char* textstring)
+{
+  unsigned error = 0;
+  size_t i;
+  ucvector text;
+  ucvector_init(&text);
+  for(i = 0; keyword[i] != 0; ++i) ucvector_push_back(&text, (unsigned char)keyword[i]);
+  if(i < 1 || i > 79) return 89; /*error: invalid keyword size*/
+  ucvector_push_back(&text, 0); /*0 termination char*/
+  for(i = 0; textstring[i] != 0; ++i) ucvector_push_back(&text, (unsigned char)textstring[i]);
+  error = addChunk(out, "tEXt", text.data, text.size);
+  ucvector_cleanup(&text);
+
+  return error;
+}
+
+static unsigned addChunk_zTXt(ucvector* out, const char* keyword, const char* textstring,
+                              LodePNGCompressSettings* zlibsettings)
+{
+  unsigned error = 0;
+  ucvector data, compressed;
+  size_t i, textsize = strlen(textstring);
+
+  ucvector_init(&data);
+  ucvector_init(&compressed);
+  for(i = 0; keyword[i] != 0; ++i) ucvector_push_back(&data, (unsigned char)keyword[i]);
+  if(i < 1 || i > 79) return 89; /*error: invalid keyword size*/
+  ucvector_push_back(&data, 0); /*0 termination char*/
+  ucvector_push_back(&data, 0); /*compression method: 0*/
+
+  error = zlib_compress(&compressed.data, &compressed.size,
+                        (unsigned char*)textstring, textsize, zlibsettings);
+  if(!error)
+  {
+    for(i = 0; i != compressed.size; ++i) ucvector_push_back(&data, compressed.data[i]);
+    error = addChunk(out, "zTXt", data.data, data.size);
+  }
+
+  ucvector_cleanup(&compressed);
+  ucvector_cleanup(&data);
+  return error;
+}
+
+static unsigned addChunk_iTXt(ucvector* out, unsigned compressed, const char* keyword, const char* langtag,
+                              const char* transkey, const char* textstring, LodePNGCompressSettings* zlibsettings)
+{
+  unsigned error = 0;
+  ucvector data;
+  size_t i, textsize = strlen(textstring);
+
+  ucvector_init(&data);
+
+  for(i = 0; keyword[i] != 0; ++i) ucvector_push_back(&data, (unsigned char)keyword[i]);
+  if(i < 1 || i > 79) return 89; /*error: invalid keyword size*/
+  ucvector_push_back(&data, 0); /*null termination char*/
+  ucvector_push_back(&data, compressed ? 1 : 0); /*compression flag*/
+  ucvector_push_back(&data, 0); /*compression method*/
+  for(i = 0; langtag[i] != 0; ++i) ucvector_push_back(&data, (unsigned char)langtag[i]);
+  ucvector_push_back(&data, 0); /*null termination char*/
+  for(i = 0; transkey[i] != 0; ++i) ucvector_push_back(&data, (unsigned char)transkey[i]);
+  ucvector_push_back(&data, 0); /*null termination char*/
+
+  if(compressed)
+  {
+    ucvector compressed_data;
+    ucvector_init(&compressed_data);
+    error = zlib_compress(&compressed_data.data, &compressed_data.size,
+                          (unsigned char*)textstring, textsize, zlibsettings);
+    if(!error)
+    {
+      for(i = 0; i != compressed_data.size; ++i) ucvector_push_back(&data, compressed_data.data[i]);
+    }
+    ucvector_cleanup(&compressed_data);
+  }
+  else /*not compressed*/
+  {
+    for(i = 0; textstring[i] != 0; ++i) ucvector_push_back(&data, (unsigned char)textstring[i]);
+  }
+
+  if(!error) error = addChunk(out, "iTXt", data.data, data.size);
+  ucvector_cleanup(&data);
+  return error;
+}
+
+static unsigned addChunk_bKGD(ucvector* out, const LodePNGInfo* info)
+{
+  unsigned error = 0;
+  ucvector bKGD;
+  ucvector_init(&bKGD);
+  if(info->color.colortype == LCT_GREY || info->color.colortype == LCT_GREY_ALPHA)
+  {
+    ucvector_push_back(&bKGD, (unsigned char)(info->background_r / 256));
+    ucvector_push_back(&bKGD, (unsigned char)(info->background_r % 256));
+  }
+  else if(info->color.colortype == LCT_RGB || info->color.colortype == LCT_RGBA)
+  {
+    ucvector_push_back(&bKGD, (unsigned char)(info->background_r / 256));
+    ucvector_push_back(&bKGD, (unsigned char)(info->background_r % 256));
+    ucvector_push_back(&bKGD, (unsigned char)(info->background_g / 256));
+    ucvector_push_back(&bKGD, (unsigned char)(info->background_g % 256));
+    ucvector_push_back(&bKGD, (unsigned char)(info->background_b / 256));
+    ucvector_push_back(&bKGD, (unsigned char)(info->background_b % 256));
+  }
+  else if(info->color.colortype == LCT_PALETTE)
+  {
+    ucvector_push_back(&bKGD, (unsigned char)(info->background_r % 256)); /*palette index*/
+  }
+
+  error = addChunk(out, "bKGD", bKGD.data, bKGD.size);
+  ucvector_cleanup(&bKGD);
+
+  return error;
+}
+
+static unsigned addChunk_tIME(ucvector* out, const LodePNGTime* time)
+{
+  unsigned error = 0;
+  unsigned char* data = (unsigned char*)lodepng_malloc(7);
+  if(!data) return 83; /*alloc fail*/
+  data[0] = (unsigned char)(time->year / 256);
+  data[1] = (unsigned char)(time->year % 256);
+  data[2] = (unsigned char)time->month;
+  data[3] = (unsigned char)time->day;
+  data[4] = (unsigned char)time->hour;
+  data[5] = (unsigned char)time->minute;
+  data[6] = (unsigned char)time->second;
+  error = addChunk(out, "tIME", data, 7);
+  lodepng_free(data);
+  return error;
+}
+
+static unsigned addChunk_pHYs(ucvector* out, const LodePNGInfo* info)
+{
+  unsigned error = 0;
+  ucvector data;
+  ucvector_init(&data);
+
+  lodepng_add32bitInt(&data, info->phys_x);
+  lodepng_add32bitInt(&data, info->phys_y);
+  ucvector_push_back(&data, info->phys_unit);
+
+  error = addChunk(out, "pHYs", data.data, data.size);
+  ucvector_cleanup(&data);
+
+  return error;
+}
+
+#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
+
+static void filterScanline(unsigned char* out, const unsigned char* scanline, const unsigned char* prevline,
+                           size_t length, size_t bytewidth, unsigned char filterType)
+{
+  size_t i;
+  switch(filterType)
+  {
+    case 0: /*None*/
+      for(i = 0; i != length; ++i) out[i] = scanline[i];
+      break;
+    case 1: /*Sub*/
+      for(i = 0; i != bytewidth; ++i) out[i] = scanline[i];
+      for(i = bytewidth; i < length; ++i) out[i] = scanline[i] - scanline[i - bytewidth];
+      break;
+    case 2: /*Up*/
+      if(prevline)
+      {
+        for(i = 0; i != length; ++i) out[i] = scanline[i] - prevline[i];
+      }
+      else
+      {
+        for(i = 0; i != length; ++i) out[i] = scanline[i];
+      }
+      break;
+    case 3: /*Average*/
+      if(prevline)
+      {
+        for(i = 0; i != bytewidth; ++i) out[i] = scanline[i] - prevline[i] / 2;
+        for(i = bytewidth; i < length; ++i) out[i] = scanline[i] - ((scanline[i - bytewidth] + prevline[i]) / 2);
+      }
+      else
+      {
+        for(i = 0; i != bytewidth; ++i) out[i] = scanline[i];
+        for(i = bytewidth; i < length; ++i) out[i] = scanline[i] - scanline[i - bytewidth] / 2;
+      }
+      break;
+    case 4: /*Paeth*/
+      if(prevline)
+      {
+        /*paethPredictor(0, prevline[i], 0) is always prevline[i]*/
+        for(i = 0; i != bytewidth; ++i) out[i] = (scanline[i] - prevline[i]);
+        for(i = bytewidth; i < length; ++i)
+        {
+          out[i] = (scanline[i] - paethPredictor(scanline[i - bytewidth], prevline[i], prevline[i - bytewidth]));
+        }
+      }
+      else
+      {
+        for(i = 0; i != bytewidth; ++i) out[i] = scanline[i];
+        /*paethPredictor(scanline[i - bytewidth], 0, 0) is always scanline[i - bytewidth]*/
+        for(i = bytewidth; i < length; ++i) out[i] = (scanline[i] - scanline[i - bytewidth]);
+      }
+      break;
+    default: return; /*unexisting filter type given*/
+  }
+}
+
+/* log2 approximation. A slight bit faster than std::log. */
+static float flog2(float f)
+{
+  float result = 0;
+  while(f > 32) { result += 4; f /= 16; }
+  while(f > 2) { ++result; f /= 2; }
+  return result + 1.442695f * (f * f * f / 3 - 3 * f * f / 2 + 3 * f - 1.83333f);
+}
+
+static unsigned filter(unsigned char* out, const unsigned char* in, unsigned w, unsigned h,
+                       const LodePNGColorMode* info, const LodePNGEncoderSettings* settings)
+{
+  /*
+  For PNG filter method 0
+  out must be a buffer with as size: h + (w * h * bpp + 7) / 8, because there are
+  the scanlines with 1 extra byte per scanline
+  */
+
+  unsigned bpp = lodepng_get_bpp(info);
+  /*the width of a scanline in bytes, not including the filter type*/
+  size_t linebytes = (w * bpp + 7) / 8;
+  /*bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per pixel otherwise*/
+  size_t bytewidth = (bpp + 7) / 8;
+  const unsigned char* prevline = 0;
+  unsigned x, y;
+  unsigned error = 0;
+  LodePNGFilterStrategy strategy = settings->filter_strategy;
+
+  /*
+  There is a heuristic called the minimum sum of absolute differences heuristic, suggested by the PNG standard:
+   *  If the image type is Palette, or the bit depth is smaller than 8, then do not filter the image (i.e.
+      use fixed filtering, with the filter None).
+   * (The other case) If the image type is Grayscale or RGB (with or without Alpha), and the bit depth is
+     not smaller than 8, then use adaptive filtering heuristic as follows: independently for each row, apply
+     all five filters and select the filter that produces the smallest sum of absolute values per row.
+  This heuristic is used if filter strategy is LFS_MINSUM and filter_palette_zero is true.
+
+  If filter_palette_zero is true and filter_strategy is not LFS_MINSUM, the above heuristic is followed,
+  but for "the other case", whatever strategy filter_strategy is set to instead of the minimum sum
+  heuristic is used.
+  */
+  if(settings->filter_palette_zero &&
+     (info->colortype == LCT_PALETTE || info->bitdepth < 8)) strategy = LFS_ZERO;
+
+  if(bpp == 0) return 31; /*error: invalid color type*/
+
+  if(strategy == LFS_ZERO)
+  {
+    for(y = 0; y != h; ++y)
+    {
+      size_t outindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/
+      size_t inindex = linebytes * y;
+      out[outindex] = 0; /*filter type byte*/
+      filterScanline(&out[outindex + 1], &in[inindex], prevline, linebytes, bytewidth, 0);
+      prevline = &in[inindex];
+    }
+  }
+  else if(strategy == LFS_MINSUM)
+  {
+    /*adaptive filtering*/
+    size_t sum[5];
+    ucvector attempt[5]; /*five filtering attempts, one for each filter type*/
+    size_t smallest = 0;
+    unsigned char type, bestType = 0;
+
+    for(type = 0; type != 5; ++type)
+    {
+      ucvector_init(&attempt[type]);
+      if(!ucvector_resize(&attempt[type], linebytes)) return 83; /*alloc fail*/
+    }
+
+    if(!error)
+    {
+      for(y = 0; y != h; ++y)
+      {
+        /*try the 5 filter types*/
+        for(type = 0; type != 5; ++type)
+        {
+          filterScanline(attempt[type].data, &in[y * linebytes], prevline, linebytes, bytewidth, type);
+
+          /*calculate the sum of the result*/
+          sum[type] = 0;
+          if(type == 0)
+          {
+            for(x = 0; x != linebytes; ++x) sum[type] += (unsigned char)(attempt[type].data[x]);
+          }
+          else
+          {
+            for(x = 0; x != linebytes; ++x)
+            {
+              /*For differences, each byte should be treated as signed, values above 127 are negative
+              (converted to signed char). Filtertype 0 isn't a difference though, so use unsigned there.
+              This means filtertype 0 is almost never chosen, but that is justified.*/
+              unsigned char s = attempt[type].data[x];
+              sum[type] += s < 128 ? s : (255U - s);
+            }
+          }
+
+          /*check if this is smallest sum (or if type == 0 it's the first case so always store the values)*/
+          if(type == 0 || sum[type] < smallest)
+          {
+            bestType = type;
+            smallest = sum[type];
+          }
+        }
+
+        prevline = &in[y * linebytes];
+
+        /*now fill the out values*/
+        out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/
+        for(x = 0; x != linebytes; ++x) out[y * (linebytes + 1) + 1 + x] = attempt[bestType].data[x];
+      }
+    }
+
+    for(type = 0; type != 5; ++type) ucvector_cleanup(&attempt[type]);
+  }
+  else if(strategy == LFS_ENTROPY)
+  {
+    float sum[5];
+    ucvector attempt[5]; /*five filtering attempts, one for each filter type*/
+    float smallest = 0;
+    unsigned type, bestType = 0;
+    unsigned count[256];
+
+    for(type = 0; type != 5; ++type)
+    {
+      ucvector_init(&attempt[type]);
+      if(!ucvector_resize(&attempt[type], linebytes)) return 83; /*alloc fail*/
+    }
+
+    for(y = 0; y != h; ++y)
+    {
+      /*try the 5 filter types*/
+      for(type = 0; type != 5; ++type)
+      {
+        filterScanline(attempt[type].data, &in[y * linebytes], prevline, linebytes, bytewidth, type);
+        for(x = 0; x != 256; ++x) count[x] = 0;
+        for(x = 0; x != linebytes; ++x) ++count[attempt[type].data[x]];
+        ++count[type]; /*the filter type itself is part of the scanline*/
+        sum[type] = 0;
+        for(x = 0; x != 256; ++x)
+        {
+          float p = count[x] / (float)(linebytes + 1);
+          sum[type] += count[x] == 0 ? 0 : flog2(1 / p) * p;
+        }
+        /*check if this is smallest sum (or if type == 0 it's the first case so always store the values)*/
+        if(type == 0 || sum[type] < smallest)
+        {
+          bestType = type;
+          smallest = sum[type];
+        }
+      }
+
+      prevline = &in[y * linebytes];
+
+      /*now fill the out values*/
+      out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/
+      for(x = 0; x != linebytes; ++x) out[y * (linebytes + 1) + 1 + x] = attempt[bestType].data[x];
+    }
+
+    for(type = 0; type != 5; ++type) ucvector_cleanup(&attempt[type]);
+  }
+  else if(strategy == LFS_PREDEFINED)
+  {
+    for(y = 0; y != h; ++y)
+    {
+      size_t outindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/
+      size_t inindex = linebytes * y;
+      unsigned char type = settings->predefined_filters[y];
+      out[outindex] = type; /*filter type byte*/
+      filterScanline(&out[outindex + 1], &in[inindex], prevline, linebytes, bytewidth, type);
+      prevline = &in[inindex];
+    }
+  }
+  else if(strategy == LFS_BRUTE_FORCE)
+  {
+    /*brute force filter chooser.
+    deflate the scanline after every filter attempt to see which one deflates best.
+    This is very slow and gives only slightly smaller, sometimes even larger, result*/
+    size_t size[5];
+    ucvector attempt[5]; /*five filtering attempts, one for each filter type*/
+    size_t smallest = 0;
+    unsigned type = 0, bestType = 0;
+    unsigned char* dummy;
+    LodePNGCompressSettings zlibsettings = settings->zlibsettings;
+    /*use fixed tree on the attempts so that the tree is not adapted to the filtertype on purpose,
+    to simulate the true case where the tree is the same for the whole image. Sometimes it gives
+    better result with dynamic tree anyway. Using the fixed tree sometimes gives worse, but in rare
+    cases better compression. It does make this a bit less slow, so it's worth doing this.*/
+    zlibsettings.btype = 1;
+    /*a custom encoder likely doesn't read the btype setting and is optimized for complete PNG
+    images only, so disable it*/
+    zlibsettings.custom_zlib = 0;
+    zlibsettings.custom_deflate = 0;
+    for(type = 0; type != 5; ++type)
+    {
+      ucvector_init(&attempt[type]);
+      ucvector_resize(&attempt[type], linebytes); /*todo: give error if resize failed*/
+    }
+    for(y = 0; y != h; ++y) /*try the 5 filter types*/
+    {
+      for(type = 0; type != 5; ++type)
+      {
+        unsigned testsize = attempt[type].size;
+        /*if(testsize > 8) testsize /= 8;*/ /*it already works good enough by testing a part of the row*/
+
+        filterScanline(attempt[type].data, &in[y * linebytes], prevline, linebytes, bytewidth, type);
+        size[type] = 0;
+        dummy = 0;
+        zlib_compress(&dummy, &size[type], attempt[type].data, testsize, &zlibsettings);
+        lodepng_free(dummy);
+        /*check if this is smallest size (or if type == 0 it's the first case so always store the values)*/
+        if(type == 0 || size[type] < smallest)
+        {
+          bestType = type;
+          smallest = size[type];
+        }
+      }
+      prevline = &in[y * linebytes];
+      out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/
+      for(x = 0; x != linebytes; ++x) out[y * (linebytes + 1) + 1 + x] = attempt[bestType].data[x];
+    }
+    for(type = 0; type != 5; ++type) ucvector_cleanup(&attempt[type]);
+  }
+  else return 88; /* unknown filter strategy */
+
+  return error;
+}
+
+static void addPaddingBits(unsigned char* out, const unsigned char* in,
+                           size_t olinebits, size_t ilinebits, unsigned h)
+{
+  /*The opposite of the removePaddingBits function
+  olinebits must be >= ilinebits*/
+  unsigned y;
+  size_t diff = olinebits - ilinebits;
+  size_t obp = 0, ibp = 0; /*bit pointers*/
+  for(y = 0; y != h; ++y)
+  {
+    size_t x;
+    for(x = 0; x < ilinebits; ++x)
+    {
+      unsigned char bit = readBitFromReversedStream(&ibp, in);
+      setBitOfReversedStream(&obp, out, bit);
+    }
+    /*obp += diff; --> no, fill in some value in the padding bits too, to avoid
+    "Use of uninitialised value of size ###" warning from valgrind*/
+    for(x = 0; x != diff; ++x) setBitOfReversedStream(&obp, out, 0);
+  }
+}
+
+/*
+in: non-interlaced image with size w*h
+out: the same pixels, but re-ordered according to PNG's Adam7 interlacing, with
+ no padding bits between scanlines, but between reduced images so that each
+ reduced image starts at a byte.
+bpp: bits per pixel
+there are no padding bits, not between scanlines, not between reduced images
+in has the following size in bits: w * h * bpp.
+out is possibly bigger due to padding bits between reduced images
+NOTE: comments about padding bits are only relevant if bpp < 8
+*/
+static void Adam7_interlace(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp)
+{
+  unsigned passw[7], passh[7];
+  size_t filter_passstart[8], padded_passstart[8], passstart[8];
+  unsigned i;
+
+  Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp);
+
+  if(bpp >= 8)
+  {
+    for(i = 0; i != 7; ++i)
+    {
+      unsigned x, y, b;
+      size_t bytewidth = bpp / 8;
+      for(y = 0; y < passh[i]; ++y)
+      for(x = 0; x < passw[i]; ++x)
+      {
+        size_t pixelinstart = ((ADAM7_IY[i] + y * ADAM7_DY[i]) * w + ADAM7_IX[i] + x * ADAM7_DX[i]) * bytewidth;
+        size_t pixeloutstart = passstart[i] + (y * passw[i] + x) * bytewidth;
+        for(b = 0; b < bytewidth; ++b)
+        {
+          out[pixeloutstart + b] = in[pixelinstart + b];
+        }
+      }
+    }
+  }
+  else /*bpp < 8: Adam7 with pixels < 8 bit is a bit trickier: with bit pointers*/
+  {
+    for(i = 0; i != 7; ++i)
+    {
+      unsigned x, y, b;
+      unsigned ilinebits = bpp * passw[i];
+      unsigned olinebits = bpp * w;
+      size_t obp, ibp; /*bit pointers (for out and in buffer)*/
+      for(y = 0; y < passh[i]; ++y)
+      for(x = 0; x < passw[i]; ++x)
+      {
+        ibp = (ADAM7_IY[i] + y * ADAM7_DY[i]) * olinebits + (ADAM7_IX[i] + x * ADAM7_DX[i]) * bpp;
+        obp = (8 * passstart[i]) + (y * ilinebits + x * bpp);
+        for(b = 0; b < bpp; ++b)
+        {
+          unsigned char bit = readBitFromReversedStream(&ibp, in);
+          setBitOfReversedStream(&obp, out, bit);
+        }
+      }
+    }
+  }
+}
+
+/*out must be buffer big enough to contain uncompressed IDAT chunk data, and in must contain the full image.
+return value is error**/
+static unsigned preProcessScanlines(unsigned char** out, size_t* outsize, const unsigned char* in,
+                                    unsigned w, unsigned h,
+                                    const LodePNGInfo* info_png, const LodePNGEncoderSettings* settings)
+{
+  /*
+  This function converts the pure 2D image with the PNG's colortype, into filtered-padded-interlaced data. Steps:
+  *) if no Adam7: 1) add padding bits (= posible extra bits per scanline if bpp < 8) 2) filter
+  *) if adam7: 1) Adam7_interlace 2) 7x add padding bits 3) 7x filter
+  */
+  unsigned bpp = lodepng_get_bpp(&info_png->color);
+  unsigned error = 0;
+
+  if(info_png->interlace_method == 0)
+  {
+    *outsize = h + (h * ((w * bpp + 7) / 8)); /*image size plus an extra byte per scanline + possible padding bits*/
+    *out = (unsigned char*)lodepng_malloc(*outsize);
+    if(!(*out) && (*outsize)) error = 83; /*alloc fail*/
+
+    if(!error)
+    {
+      /*non multiple of 8 bits per scanline, padding bits needed per scanline*/
+      if(bpp < 8 && w * bpp != ((w * bpp + 7) / 8) * 8)
+      {
+        unsigned char* padded = (unsigned char*)lodepng_malloc(h * ((w * bpp + 7) / 8));
+        if(!padded) error = 83; /*alloc fail*/
+        if(!error)
+        {
+          addPaddingBits(padded, in, ((w * bpp + 7) / 8) * 8, w * bpp, h);
+          error = filter(*out, padded, w, h, &info_png->color, settings);
+        }
+        lodepng_free(padded);
+      }
+      else
+      {
+        /*we can immediately filter into the out buffer, no other steps needed*/
+        error = filter(*out, in, w, h, &info_png->color, settings);
+      }
+    }
+  }
+  else /*interlace_method is 1 (Adam7)*/
+  {
+    unsigned passw[7], passh[7];
+    size_t filter_passstart[8], padded_passstart[8], passstart[8];
+    unsigned char* adam7;
+
+    Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp);
+
+    *outsize = filter_passstart[7]; /*image size plus an extra byte per scanline + possible padding bits*/
+    *out = (unsigned char*)lodepng_malloc(*outsize);
+    if(!(*out)) error = 83; /*alloc fail*/
+
+    adam7 = (unsigned char*)lodepng_malloc(passstart[7]);
+    if(!adam7 && passstart[7]) error = 83; /*alloc fail*/
+
+    if(!error)
+    {
+      unsigned i;
+
+      Adam7_interlace(adam7, in, w, h, bpp);
+      for(i = 0; i != 7; ++i)
+      {
+        if(bpp < 8)
+        {
+          unsigned char* padded = (unsigned char*)lodepng_malloc(padded_passstart[i + 1] - padded_passstart[i]);
+          if(!padded) ERROR_BREAK(83); /*alloc fail*/
+          addPaddingBits(padded, &adam7[passstart[i]],
+                         ((passw[i] * bpp + 7) / 8) * 8, passw[i] * bpp, passh[i]);
+          error = filter(&(*out)[filter_passstart[i]], padded,
+                         passw[i], passh[i], &info_png->color, settings);
+          lodepng_free(padded);
+        }
+        else
+        {
+          error = filter(&(*out)[filter_passstart[i]], &adam7[padded_passstart[i]],
+                         passw[i], passh[i], &info_png->color, settings);
+        }
+
+        if(error) break;
+      }
+    }
+
+    lodepng_free(adam7);
+  }
+
+  return error;
+}
+
+/*
+palette must have 4 * palettesize bytes allocated, and given in format RGBARGBARGBARGBA...
+returns 0 if the palette is opaque,
+returns 1 if the palette has a single color with alpha 0 ==> color key
+returns 2 if the palette is semi-translucent.
+*/
+static unsigned getPaletteTranslucency(const unsigned char* palette, size_t palettesize)
+{
+  size_t i;
+  unsigned key = 0;
+  unsigned r = 0, g = 0, b = 0; /*the value of the color with alpha 0, so long as color keying is possible*/
+  for(i = 0; i != palettesize; ++i)
+  {
+    if(!key && palette[4 * i + 3] == 0)
+    {
+      r = palette[4 * i + 0]; g = palette[4 * i + 1]; b = palette[4 * i + 2];
+      key = 1;
+      i = (size_t)(-1); /*restart from beginning, to detect earlier opaque colors with key's value*/
+    }
+    else if(palette[4 * i + 3] != 255) return 2;
+    /*when key, no opaque RGB may have key's RGB*/
+    else if(key && r == palette[i * 4 + 0] && g == palette[i * 4 + 1] && b == palette[i * 4 + 2]) return 2;
+  }
+  return key;
+}
+
+#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
+static unsigned addUnknownChunks(ucvector* out, unsigned char* data, size_t datasize)
+{
+  unsigned char* inchunk = data;
+  while((size_t)(inchunk - data) < datasize)
+  {
+    CERROR_TRY_RETURN(lodepng_chunk_append(&out->data, &out->size, inchunk));
+    out->allocsize = out->size; /*fix the allocsize again*/
+    inchunk = lodepng_chunk_next(inchunk);
+  }
+  return 0;
+}
+#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
+
+unsigned lodepng_encode(unsigned char** out, size_t* outsize,
+                        const unsigned char* image, unsigned w, unsigned h,
+                        LodePNGState* state)
+{
+  LodePNGInfo info;
+  ucvector outv;
+  unsigned char* data = 0; /*uncompressed version of the IDAT chunk data*/
+  size_t datasize = 0;
+
+  /*provide some proper output values if error will happen*/
+  *out = 0;
+  *outsize = 0;
+  state->error = 0;
+
+  lodepng_info_init(&info);
+  lodepng_info_copy(&info, &state->info_png);
+
+  if((info.color.colortype == LCT_PALETTE || state->encoder.force_palette)
+      && (info.color.palettesize == 0 || info.color.palettesize > 256))
+  {
+    state->error = 68; /*invalid palette size, it is only allowed to be 1-256*/
+    return state->error;
+  }
+
+  if(state->encoder.auto_convert)
+  {
+    state->error = lodepng_auto_choose_color(&info.color, image, w, h, &state->info_raw);
+  }
+  if(state->error) return state->error;
+
+  if(state->encoder.zlibsettings.btype > 2)
+  {
+    CERROR_RETURN_ERROR(state->error, 61); /*error: unexisting btype*/
+  }
+  if(state->info_png.interlace_method > 1)
+  {
+    CERROR_RETURN_ERROR(state->error, 71); /*error: unexisting interlace mode*/
+  }
+
+  state->error = checkColorValidity(info.color.colortype, info.color.bitdepth);
+  if(state->error) return state->error; /*error: unexisting color type given*/
+  state->error = checkColorValidity(state->info_raw.colortype, state->info_raw.bitdepth);
+  if(state->error) return state->error; /*error: unexisting color type given*/
+
+  if(!lodepng_color_mode_equal(&state->info_raw, &info.color))
+  {
+    unsigned char* converted;
+    size_t size = (w * h * lodepng_get_bpp(&info.color) + 7) / 8;
+
+    converted = (unsigned char*)lodepng_malloc(size);
+    if(!converted && size) state->error = 83; /*alloc fail*/
+    if(!state->error)
+    {
+      state->error = lodepng_convert(converted, image, &info.color, &state->info_raw, w, h);
+    }
+    if(!state->error) preProcessScanlines(&data, &datasize, converted, w, h, &info, &state->encoder);
+    lodepng_free(converted);
+  }
+  else preProcessScanlines(&data, &datasize, image, w, h, &info, &state->encoder);
+
+  ucvector_init(&outv);
+  while(!state->error) /*while only executed once, to break on error*/
+  {
+#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
+    size_t i;
+#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
+    /*write signature and chunks*/
+    writeSignature(&outv);
+    /*IHDR*/
+    addChunk_IHDR(&outv, w, h, info.color.colortype, info.color.bitdepth, info.interlace_method);
+#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
+    /*unknown chunks between IHDR and PLTE*/
+    if(info.unknown_chunks_data[0])
+    {
+      state->error = addUnknownChunks(&outv, info.unknown_chunks_data[0], info.unknown_chunks_size[0]);
+      if(state->error) break;
+    }
+#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
+    /*PLTE*/
+    if(info.color.colortype == LCT_PALETTE)
+    {
+      addChunk_PLTE(&outv, &info.color);
+    }
+    if(state->encoder.force_palette && (info.color.colortype == LCT_RGB || info.color.colortype == LCT_RGBA))
+    {
+      addChunk_PLTE(&outv, &info.color);
+    }
+    /*tRNS*/
+    if(info.color.colortype == LCT_PALETTE && getPaletteTranslucency(info.color.palette, info.color.palettesize) != 0)
+    {
+      addChunk_tRNS(&outv, &info.color);
+    }
+    if((info.color.colortype == LCT_GREY || info.color.colortype == LCT_RGB) && info.color.key_defined)
+    {
+      addChunk_tRNS(&outv, &info.color);
+    }
+#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
+    /*bKGD (must come between PLTE and the IDAt chunks*/
+    if(info.background_defined) addChunk_bKGD(&outv, &info);
+    /*pHYs (must come before the IDAT chunks)*/
+    if(info.phys_defined) addChunk_pHYs(&outv, &info);
+
+    /*unknown chunks between PLTE and IDAT*/
+    if(info.unknown_chunks_data[1])
+    {
+      state->error = addUnknownChunks(&outv, info.unknown_chunks_data[1], info.unknown_chunks_size[1]);
+      if(state->error) break;
+    }
+#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
+    /*IDAT (multiple IDAT chunks must be consecutive)*/
+    state->error = addChunk_IDAT(&outv, data, datasize, &state->encoder.zlibsettings);
+    if(state->error) break;
+#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
+    /*tIME*/
+    if(info.time_defined) addChunk_tIME(&outv, &info.time);
+    /*tEXt and/or zTXt*/
+    for(i = 0; i != info.text_num; ++i)
+    {
+      if(strlen(info.text_keys[i]) > 79)
+      {
+        state->error = 66; /*text chunk too large*/
+        break;
+      }
+      if(strlen(info.text_keys[i]) < 1)
+      {
+        state->error = 67; /*text chunk too small*/
+        break;
+      }
+      if(state->encoder.text_compression)
+      {
+        addChunk_zTXt(&outv, info.text_keys[i], info.text_strings[i], &state->encoder.zlibsettings);
+      }
+      else
+      {
+        addChunk_tEXt(&outv, info.text_keys[i], info.text_strings[i]);
+      }
+    }
+    /*LodePNG version id in text chunk*/
+    if(state->encoder.add_id)
+    {
+      unsigned alread_added_id_text = 0;
+      for(i = 0; i != info.text_num; ++i)
+      {
+        if(!strcmp(info.text_keys[i], "LodePNG"))
+        {
+          alread_added_id_text = 1;
+          break;
+        }
+      }
+      if(alread_added_id_text == 0)
+      {
+        addChunk_tEXt(&outv, "LodePNG", LODEPNG_VERSION_STRING); /*it's shorter as tEXt than as zTXt chunk*/
+      }
+    }
+    /*iTXt*/
+    for(i = 0; i != info.itext_num; ++i)
+    {
+      if(strlen(info.itext_keys[i]) > 79)
+      {
+        state->error = 66; /*text chunk too large*/
+        break;
+      }
+      if(strlen(info.itext_keys[i]) < 1)
+      {
+        state->error = 67; /*text chunk too small*/
+        break;
+      }
+      addChunk_iTXt(&outv, state->encoder.text_compression,
+                    info.itext_keys[i], info.itext_langtags[i], info.itext_transkeys[i], info.itext_strings[i],
+                    &state->encoder.zlibsettings);
+    }
+
+    /*unknown chunks between IDAT and IEND*/
+    if(info.unknown_chunks_data[2])
+    {
+      state->error = addUnknownChunks(&outv, info.unknown_chunks_data[2], info.unknown_chunks_size[2]);
+      if(state->error) break;
+    }
+#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
+    addChunk_IEND(&outv);
+
+    break; /*this isn't really a while loop; no error happened so break out now!*/
+  }
+
+  lodepng_info_cleanup(&info);
+  lodepng_free(data);
+  /*instead of cleaning the vector up, give it to the output*/
+  *out = outv.data;
+  *outsize = outv.size;
+
+  return state->error;
+}
+
+unsigned lodepng_encode_memory(unsigned char** out, size_t* outsize, const unsigned char* image,
+                               unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth)
+{
+  unsigned error;
+  LodePNGState state;
+  lodepng_state_init(&state);
+  state.info_raw.colortype = colortype;
+  state.info_raw.bitdepth = bitdepth;
+  state.info_png.color.colortype = colortype;
+  state.info_png.color.bitdepth = bitdepth;
+  lodepng_encode(out, outsize, image, w, h, &state);
+  error = state.error;
+  lodepng_state_cleanup(&state);
+  return error;
+}
+
+unsigned lodepng_encode32(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h)
+{
+  return lodepng_encode_memory(out, outsize, image, w, h, LCT_RGBA, 8);
+}
+
+unsigned lodepng_encode24(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h)
+{
+  return lodepng_encode_memory(out, outsize, image, w, h, LCT_RGB, 8);
+}
+
+#ifdef LODEPNG_COMPILE_DISK
+unsigned lodepng_encode_file(const char* filename, const unsigned char* image, unsigned w, unsigned h,
+                             LodePNGColorType colortype, unsigned bitdepth)
+{
+  unsigned char* buffer;
+  size_t buffersize;
+  unsigned error = lodepng_encode_memory(&buffer, &buffersize, image, w, h, colortype, bitdepth);
+  if(!error) error = lodepng_save_file(buffer, buffersize, filename);
+  lodepng_free(buffer);
+  return error;
+}
+
+unsigned lodepng_encode32_file(const char* filename, const unsigned char* image, unsigned w, unsigned h)
+{
+  return lodepng_encode_file(filename, image, w, h, LCT_RGBA, 8);
+}
+
+unsigned lodepng_encode24_file(const char* filename, const unsigned char* image, unsigned w, unsigned h)
+{
+  return lodepng_encode_file(filename, image, w, h, LCT_RGB, 8);
+}
+#endif /*LODEPNG_COMPILE_DISK*/
+
+void lodepng_encoder_settings_init(LodePNGEncoderSettings* settings)
+{
+  lodepng_compress_settings_init(&settings->zlibsettings);
+  settings->filter_palette_zero = 1;
+  settings->filter_strategy = LFS_MINSUM;
+  settings->auto_convert = 1;
+  settings->force_palette = 0;
+  settings->predefined_filters = 0;
+#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
+  settings->add_id = 0;
+  settings->text_compression = 1;
+#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
+}
+
+#endif /*LODEPNG_COMPILE_ENCODER*/
+#endif /*LODEPNG_COMPILE_PNG*/
+
+#ifdef LODEPNG_COMPILE_ERROR_TEXT
+/*
+This returns the description of a numerical error code in English. This is also
+the documentation of all the error codes.
+*/
+const char* lodepng_error_text(unsigned code)
+{
+  switch(code)
+  {
+    case 0: return "no error, everything went ok";
+    case 1: return "nothing done yet"; /*the Encoder/Decoder has done nothing yet, error checking makes no sense yet*/
+    case 10: return "end of input memory reached without huffman end code"; /*while huffman decoding*/
+    case 11: return "error in code tree made it jump outside of huffman tree"; /*while huffman decoding*/
+    case 13: return "problem while processing dynamic deflate block";
+    case 14: return "problem while processing dynamic deflate block";
+    case 15: return "problem while processing dynamic deflate block";
+    case 16: return "unexisting code while processing dynamic deflate block";
+    case 17: return "end of out buffer memory reached while inflating";
+    case 18: return "invalid distance code while inflating";
+    case 19: return "end of out buffer memory reached while inflating";
+    case 20: return "invalid deflate block BTYPE encountered while decoding";
+    case 21: return "NLEN is not ones complement of LEN in a deflate block";
+     /*end of out buffer memory reached while inflating:
+     This can happen if the inflated deflate data is longer than the amount of bytes required to fill up
+     all the pixels of the image, given the color depth and image dimensions. Something that doesn't
+     happen in a normal, well encoded, PNG image.*/
+    case 22: return "end of out buffer memory reached while inflating";
+    case 23: return "end of in buffer memory reached while inflating";
+    case 24: return "invalid FCHECK in zlib header";
+    case 25: return "invalid compression method in zlib header";
+    case 26: return "FDICT encountered in zlib header while it's not used for PNG";
+    case 27: return "PNG file is smaller than a PNG header";
+    /*Checks the magic file header, the first 8 bytes of the PNG file*/
+    case 28: return "incorrect PNG signature, it's no PNG or corrupted";
+    case 29: return "first chunk is not the header chunk";
+    case 30: return "chunk length too large, chunk broken off at end of file";
+    case 31: return "illegal PNG color type or bpp";
+    case 32: return "illegal PNG compression method";
+    case 33: return "illegal PNG filter method";
+    case 34: return "illegal PNG interlace method";
+    case 35: return "chunk length of a chunk is too large or the chunk too small";
+    case 36: return "illegal PNG filter type encountered";
+    case 37: return "illegal bit depth for this color type given";
+    case 38: return "the palette is too big"; /*more than 256 colors*/
+    case 39: return "more palette alpha values given in tRNS chunk than there are colors in the palette";
+    case 40: return "tRNS chunk has wrong size for greyscale image";
+    case 41: return "tRNS chunk has wrong size for RGB image";
+    case 42: return "tRNS chunk appeared while it was not allowed for this color type";
+    case 43: return "bKGD chunk has wrong size for palette image";
+    case 44: return "bKGD chunk has wrong size for greyscale image";
+    case 45: return "bKGD chunk has wrong size for RGB image";
+    /*the input data is empty, maybe a PNG file doesn't exist or is in the wrong path*/
+    case 48: return "empty input or file doesn't exist";
+    case 49: return "jumped past memory while generating dynamic huffman tree";
+    case 50: return "jumped past memory while generating dynamic huffman tree";
+    case 51: return "jumped past memory while inflating huffman block";
+    case 52: return "jumped past memory while inflating";
+    case 53: return "size of zlib data too small";
+    case 54: return "repeat symbol in tree while there was no value symbol yet";
+    /*jumped past tree while generating huffman tree, this could be when the
+    tree will have more leaves than symbols after generating it out of the
+    given lenghts. They call this an oversubscribed dynamic bit lengths tree in zlib.*/
+    case 55: return "jumped past tree while generating huffman tree";
+    case 56: return "given output image colortype or bitdepth not supported for color conversion";
+    case 57: return "invalid CRC encountered (checking CRC can be disabled)";
+    case 58: return "invalid ADLER32 encountered (checking ADLER32 can be disabled)";
+    case 59: return "requested color conversion not supported";
+    case 60: return "invalid window size given in the settings of the encoder (must be 0-32768)";
+    case 61: return "invalid BTYPE given in the settings of the encoder (only 0, 1 and 2 are allowed)";
+    /*LodePNG leaves the choice of RGB to greyscale conversion formula to the user.*/
+    case 62: return "conversion from color to greyscale not supported";
+    case 63: return "length of a chunk too long, max allowed for PNG is 2147483647 bytes per chunk"; /*(2^31-1)*/
+    /*this would result in the inability of a deflated block to ever contain an end code. It must be at least 1.*/
+    case 64: return "the length of the END symbol 256 in the Huffman tree is 0";
+    case 66: return "the length of a text chunk keyword given to the encoder is longer than the maximum of 79 bytes";
+    case 67: return "the length of a text chunk keyword given to the encoder is smaller than the minimum of 1 byte";
+    case 68: return "tried to encode a PLTE chunk with a palette that has less than 1 or more than 256 colors";
+    case 69: return "unknown chunk type with 'critical' flag encountered by the decoder";
+    case 71: return "unexisting interlace mode given to encoder (must be 0 or 1)";
+    case 72: return "while decoding, unexisting compression method encountering in zTXt or iTXt chunk (it must be 0)";
+    case 73: return "invalid tIME chunk size";
+    case 74: return "invalid pHYs chunk size";
+    /*length could be wrong, or data chopped off*/
+    case 75: return "no null termination char found while decoding text chunk";
+    case 76: return "iTXt chunk too short to contain required bytes";
+    case 77: return "integer overflow in buffer size";
+    case 78: return "failed to open file for reading"; /*file doesn't exist or couldn't be opened for reading*/
+    case 79: return "failed to open file for writing";
+    case 80: return "tried creating a tree of 0 symbols";
+    case 81: return "lazy matching at pos 0 is impossible";
+    case 82: return "color conversion to palette requested while a color isn't in palette";
+    case 83: return "memory allocation failed";
+    case 84: return "given image too small to contain all pixels to be encoded";
+    case 86: return "impossible offset in lz77 encoding (internal bug)";
+    case 87: return "must provide custom zlib function pointer if LODEPNG_COMPILE_ZLIB is not defined";
+    case 88: return "invalid filter strategy given for LodePNGEncoderSettings.filter_strategy";
+    case 89: return "text chunk keyword too short or long: must have size 1-79";
+    /*the windowsize in the LodePNGCompressSettings. Requiring POT(==> & instead of %) makes encoding 12% faster.*/
+    case 90: return "windowsize must be a power of two";
+    case 91: return "invalid decompressed idat size";
+    case 92: return "too many pixels, not supported";
+    case 93: return "zero width or height is invalid";
+  }
+  return "unknown error code";
+}
+#endif /*LODEPNG_COMPILE_ERROR_TEXT*/
+
+/* ////////////////////////////////////////////////////////////////////////// */
+/* ////////////////////////////////////////////////////////////////////////// */
+/* // C++ Wrapper                                                          // */
+/* ////////////////////////////////////////////////////////////////////////// */
+/* ////////////////////////////////////////////////////////////////////////// */
+
+#ifdef LODEPNG_COMPILE_CPP
+namespace lodepng
+{
+
+#ifdef LODEPNG_COMPILE_DISK
+void load_file(std::vector<unsigned char>& buffer, const std::string& filename)
+{
+  std::ifstream file(filename.c_str(), std::ios::in|std::ios::binary|std::ios::ate);
+
+  /*get filesize*/
+  std::streamsize size = 0;
+  if(file.seekg(0, std::ios::end).good()) size = file.tellg();
+  if(file.seekg(0, std::ios::beg).good()) size -= file.tellg();
+
+  /*read contents of the file into the vector*/
+  buffer.resize(size_t(size));
+  if(size > 0) file.read((char*)(&buffer[0]), size);
+}
+
+/*write given buffer to the file, overwriting the file, it doesn't append to it.*/
+unsigned save_file(const std::vector<unsigned char>& buffer, const std::string& filename)
+{
+  std::ofstream file(filename.c_str(), std::ios::out|std::ios::binary);
+  if(!file) return 79;
+  file.write(buffer.empty() ? 0 : (char*)&buffer[0], std::streamsize(buffer.size()));
+  return 0;
+}
+#endif /* LODEPNG_COMPILE_DISK */
+
+#ifdef LODEPNG_COMPILE_ZLIB
+#ifdef LODEPNG_COMPILE_DECODER
+unsigned decompress(std::vector<unsigned char>& out, const unsigned char* in, size_t insize,
+                    const LodePNGDecompressSettings& settings)
+{
+  unsigned char* buffer = 0;
+  size_t buffersize = 0;
+  unsigned error = zlib_decompress(&buffer, &buffersize, in, insize, &settings);
+  if(buffer)
+  {
+    out.insert(out.end(), &buffer[0], &buffer[buffersize]);
+    lodepng_free(buffer);
+  }
+  return error;
+}
+
+unsigned decompress(std::vector<unsigned char>& out, const std::vector<unsigned char>& in,
+                    const LodePNGDecompressSettings& settings)
+{
+  return decompress(out, in.empty() ? 0 : &in[0], in.size(), settings);
+}
+#endif /* LODEPNG_COMPILE_DECODER */
+
+#ifdef LODEPNG_COMPILE_ENCODER
+unsigned compress(std::vector<unsigned char>& out, const unsigned char* in, size_t insize,
+                  const LodePNGCompressSettings& settings)
+{
+  unsigned char* buffer = 0;
+  size_t buffersize = 0;
+  unsigned error = zlib_compress(&buffer, &buffersize, in, insize, &settings);
+  if(buffer)
+  {
+    out.insert(out.end(), &buffer[0], &buffer[buffersize]);
+    lodepng_free(buffer);
+  }
+  return error;
+}
+
+unsigned compress(std::vector<unsigned char>& out, const std::vector<unsigned char>& in,
+                  const LodePNGCompressSettings& settings)
+{
+  return compress(out, in.empty() ? 0 : &in[0], in.size(), settings);
+}
+#endif /* LODEPNG_COMPILE_ENCODER */
+#endif /* LODEPNG_COMPILE_ZLIB */
+
+
+#ifdef LODEPNG_COMPILE_PNG
+
+State::State()
+{
+  lodepng_state_init(this);
+}
+
+State::State(const State& other)
+{
+  lodepng_state_init(this);
+  lodepng_state_copy(this, &other);
+}
+
+State::~State()
+{
+  lodepng_state_cleanup(this);
+}
+
+State& State::operator=(const State& other)
+{
+  lodepng_state_copy(this, &other);
+  return *this;
+}
+
+#ifdef LODEPNG_COMPILE_DECODER
+
+unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h, const unsigned char* in,
+                size_t insize, LodePNGColorType colortype, unsigned bitdepth)
+{
+  unsigned char* buffer;
+  unsigned error = lodepng_decode_memory(&buffer, &w, &h, in, insize, colortype, bitdepth);
+  if(buffer && !error)
+  {
+    State state;
+    state.info_raw.colortype = colortype;
+    state.info_raw.bitdepth = bitdepth;
+    size_t buffersize = lodepng_get_raw_size(w, h, &state.info_raw);
+    out.insert(out.end(), &buffer[0], &buffer[buffersize]);
+    lodepng_free(buffer);
+  }
+  return error;
+}
+
+unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h,
+                const std::vector<unsigned char>& in, LodePNGColorType colortype, unsigned bitdepth)
+{
+  return decode(out, w, h, in.empty() ? 0 : &in[0], (unsigned)in.size(), colortype, bitdepth);
+}
+
+unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h,
+                State& state,
+                const unsigned char* in, size_t insize)
+{
+  unsigned char* buffer = NULL;
+  unsigned error = lodepng_decode(&buffer, &w, &h, &state, in, insize);
+  if(buffer && !error)
+  {
+    size_t buffersize = lodepng_get_raw_size(w, h, &state.info_raw);
+    out.insert(out.end(), &buffer[0], &buffer[buffersize]);
+  }
+  lodepng_free(buffer);
+  return error;
+}
+
+unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h,
+                State& state,
+                const std::vector<unsigned char>& in)
+{
+  return decode(out, w, h, state, in.empty() ? 0 : &in[0], in.size());
+}
+
+#ifdef LODEPNG_COMPILE_DISK
+unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h, const std::string& filename,
+                LodePNGColorType colortype, unsigned bitdepth)
+{
+  std::vector<unsigned char> buffer;
+  load_file(buffer, filename);
+  return decode(out, w, h, buffer, colortype, bitdepth);
+}
+#endif /* LODEPNG_COMPILE_DECODER */
+#endif /* LODEPNG_COMPILE_DISK */
+
+#ifdef LODEPNG_COMPILE_ENCODER
+unsigned encode(std::vector<unsigned char>& out, const unsigned char* in, unsigned w, unsigned h,
+                LodePNGColorType colortype, unsigned bitdepth)
+{
+  unsigned char* buffer;
+  size_t buffersize;
+  unsigned error = lodepng_encode_memory(&buffer, &buffersize, in, w, h, colortype, bitdepth);
+  if(buffer)
+  {
+    out.insert(out.end(), &buffer[0], &buffer[buffersize]);
+    lodepng_free(buffer);
+  }
+  return error;
+}
+
+unsigned encode(std::vector<unsigned char>& out,
+                const std::vector<unsigned char>& in, unsigned w, unsigned h,
+                LodePNGColorType colortype, unsigned bitdepth)
+{
+  if(lodepng_get_raw_size_lct(w, h, colortype, bitdepth) > in.size()) return 84;
+  return encode(out, in.empty() ? 0 : &in[0], w, h, colortype, bitdepth);
+}
+
+unsigned encode(std::vector<unsigned char>& out,
+                const unsigned char* in, unsigned w, unsigned h,
+                State& state)
+{
+  unsigned char* buffer;
+  size_t buffersize;
+  unsigned error = lodepng_encode(&buffer, &buffersize, in, w, h, &state);
+  if(buffer)
+  {
+    out.insert(out.end(), &buffer[0], &buffer[buffersize]);
+    lodepng_free(buffer);
+  }
+  return error;
+}
+
+unsigned encode(std::vector<unsigned char>& out,
+                const std::vector<unsigned char>& in, unsigned w, unsigned h,
+                State& state)
+{
+  if(lodepng_get_raw_size(w, h, &state.info_raw) > in.size()) return 84;
+  return encode(out, in.empty() ? 0 : &in[0], w, h, state);
+}
+
+#ifdef LODEPNG_COMPILE_DISK
+unsigned encode(const std::string& filename,
+                const unsigned char* in, unsigned w, unsigned h,
+                LodePNGColorType colortype, unsigned bitdepth)
+{
+  std::vector<unsigned char> buffer;
+  unsigned error = encode(buffer, in, w, h, colortype, bitdepth);
+  if(!error) error = save_file(buffer, filename);
+  return error;
+}
+
+unsigned encode(const std::string& filename,
+                const std::vector<unsigned char>& in, unsigned w, unsigned h,
+                LodePNGColorType colortype, unsigned bitdepth)
+{
+  if(lodepng_get_raw_size_lct(w, h, colortype, bitdepth) > in.size()) return 84;
+  return encode(filename, in.empty() ? 0 : &in[0], w, h, colortype, bitdepth);
+}
+#endif /* LODEPNG_COMPILE_DISK */
+#endif /* LODEPNG_COMPILE_ENCODER */
+#endif /* LODEPNG_COMPILE_PNG */
+} /* namespace lodepng */
+#endif /*LODEPNG_COMPILE_CPP*/
diff --git a/libeg/lodepng.h b/libeg/lodepng.h
new file mode 100644 (file)
index 0000000..4593949
--- /dev/null
@@ -0,0 +1,1732 @@
+/*
+LodePNG version 20151024
+
+Copyright (c) 2005-2015 Lode Vandevenne
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+    1. The origin of this software must not be misrepresented; you must not
+    claim that you wrote the original software. If you use this software
+    in a product, an acknowledgment in the product documentation would be
+    appreciated but is not required.
+
+    2. Altered source versions must be plainly marked as such, and must not be
+    misrepresented as being the original software.
+
+    3. This notice may not be removed or altered from any source
+    distribution.
+*/
+/*
+ * This version of lodepng.h is modified for use with rEFInd. Some options
+ * are commented out and several definitions (commented on shortly) are added
+ * for GNU-EFI compatibility. The associated lodepng.c file is unmodified
+ * from the original.
+ */
+
+#ifndef LODEPNG_H
+#define LODEPNG_H
+
+#include <string.h> /*for size_t*/
+
+// Below block of lines required for GNU-EFI and TianoCore (program hangs
+// when run without them, and associated function in lodepng_xtra.c)
+int MyStrlen(const char *InString);
+#define strlen(c) MyStrlen(c)
+#include <stdlib.h>
+#define abs(x) (((x) < 0) ? -(x) : (x))
+#ifdef __MAKEWITH_GNUEFI
+#include <efi.h>
+#include <efilib.h>
+#else
+#include "../include/tiano_includes.h"
+#endif
+#define memcpy(a, b, c) CopyMem(a, b, c)
+
+#ifdef __cplusplus
+#include <vector>
+#include <string>
+#endif /*__cplusplus*/
+
+extern const char* LODEPNG_VERSION_STRING;
+
+/*
+The following #defines are used to create code sections. They can be disabled
+to disable code sections, which can give faster compile time and smaller binary.
+The "NO_COMPILE" defines are designed to be used to pass as defines to the
+compiler command to disable them without modifying this header, e.g.
+-DLODEPNG_NO_COMPILE_ZLIB for gcc.
+In addition to those below, you can also define LODEPNG_NO_COMPILE_CRC to
+allow implementing a custom lodepng_crc32.
+*/
+/*deflate & zlib. If disabled, you must specify alternative zlib functions in
+the custom_zlib field of the compress and decompress settings*/
+#ifndef LODEPNG_NO_COMPILE_ZLIB
+#define LODEPNG_COMPILE_ZLIB
+#endif
+/*png encoder and png decoder*/
+#ifndef LODEPNG_NO_COMPILE_PNG
+#define LODEPNG_COMPILE_PNG
+#endif
+/*deflate&zlib decoder and png decoder*/
+#ifndef LODEPNG_NO_COMPILE_DECODER
+#define LODEPNG_COMPILE_DECODER
+#endif
+/*deflate&zlib encoder and png encoder*/
+// #ifndef LODEPNG_NO_COMPILE_ENCODER
+// #define LODEPNG_COMPILE_ENCODER
+// #endif
+/*the optional built in harddisk file loading and saving functions*/
+// #ifndef LODEPNG_NO_COMPILE_DISK
+// #define LODEPNG_COMPILE_DISK
+// #endif
+/*support for chunks other than IHDR, IDAT, PLTE, tRNS, IEND: ancillary and unknown chunks*/
+// #ifndef LODEPNG_NO_COMPILE_ANCILLARY_CHUNKS
+// #define LODEPNG_COMPILE_ANCILLARY_CHUNKS
+// #endif
+/*ability to convert error numerical codes to English text string*/
+// #ifndef LODEPNG_NO_COMPILE_ERROR_TEXT
+// #define LODEPNG_COMPILE_ERROR_TEXT
+// #endif
+/*Compile the default allocators (C's free, malloc and realloc). If you disable this,
+you can define the functions lodepng_free, lodepng_malloc and lodepng_realloc in your
+source files with custom allocators.*/
+// #ifndef LODEPNG_NO_COMPILE_ALLOCATORS
+// #define LODEPNG_COMPILE_ALLOCATORS
+// #endif
+/*compile the C++ version (you can disable the C++ wrapper here even when compiling for C++)*/
+#ifdef __cplusplus
+#ifndef LODEPNG_NO_COMPILE_CPP
+#define LODEPNG_COMPILE_CPP
+#endif
+#endif
+
+#ifdef LODEPNG_COMPILE_PNG
+/*The PNG color types (also used for raw).*/
+typedef enum LodePNGColorType
+{
+  LCT_GREY = 0, /*greyscale: 1,2,4,8,16 bit*/
+  LCT_RGB = 2, /*RGB: 8,16 bit*/
+  LCT_PALETTE = 3, /*palette: 1,2,4,8 bit*/
+  LCT_GREY_ALPHA = 4, /*greyscale with alpha: 8,16 bit*/
+  LCT_RGBA = 6 /*RGB with alpha: 8,16 bit*/
+} LodePNGColorType;
+
+#ifdef LODEPNG_COMPILE_DECODER
+/*
+Converts PNG data in memory to raw pixel data.
+out: Output parameter. Pointer to buffer that will contain the raw pixel data.
+     After decoding, its size is w * h * (bytes per pixel) bytes larger than
+     initially. Bytes per pixel depends on colortype and bitdepth.
+     Must be freed after usage with free(*out).
+     Note: for 16-bit per channel colors, uses big endian format like PNG does.
+w: Output parameter. Pointer to width of pixel data.
+h: Output parameter. Pointer to height of pixel data.
+in: Memory buffer with the PNG file.
+insize: size of the in buffer.
+colortype: the desired color type for the raw output image. See explanation on PNG color types.
+bitdepth: the desired bit depth for the raw output image. See explanation on PNG color types.
+Return value: LodePNG error code (0 means no error).
+*/
+unsigned lodepng_decode_memory(unsigned char** out, unsigned* w, unsigned* h,
+                               const unsigned char* in, size_t insize,
+                               LodePNGColorType colortype, unsigned bitdepth);
+
+/*Same as lodepng_decode_memory, but always decodes to 32-bit RGBA raw image*/
+unsigned lodepng_decode32(unsigned char** out, unsigned* w, unsigned* h,
+                          const unsigned char* in, size_t insize);
+
+/*Same as lodepng_decode_memory, but always decodes to 24-bit RGB raw image*/
+unsigned lodepng_decode24(unsigned char** out, unsigned* w, unsigned* h,
+                          const unsigned char* in, size_t insize);
+
+#ifdef LODEPNG_COMPILE_DISK
+/*
+Load PNG from disk, from file with given name.
+Same as the other decode functions, but instead takes a filename as input.
+*/
+unsigned lodepng_decode_file(unsigned char** out, unsigned* w, unsigned* h,
+                             const char* filename,
+                             LodePNGColorType colortype, unsigned bitdepth);
+
+/*Same as lodepng_decode_file, but always decodes to 32-bit RGBA raw image.*/
+unsigned lodepng_decode32_file(unsigned char** out, unsigned* w, unsigned* h,
+                               const char* filename);
+
+/*Same as lodepng_decode_file, but always decodes to 24-bit RGB raw image.*/
+unsigned lodepng_decode24_file(unsigned char** out, unsigned* w, unsigned* h,
+                               const char* filename);
+#endif /*LODEPNG_COMPILE_DISK*/
+#endif /*LODEPNG_COMPILE_DECODER*/
+
+
+#ifdef LODEPNG_COMPILE_ENCODER
+/*
+Converts raw pixel data into a PNG image in memory. The colortype and bitdepth
+  of the output PNG image cannot be chosen, they are automatically determined
+  by the colortype, bitdepth and content of the input pixel data.
+  Note: for 16-bit per channel colors, needs big endian format like PNG does.
+out: Output parameter. Pointer to buffer that will contain the PNG image data.
+     Must be freed after usage with free(*out).
+outsize: Output parameter. Pointer to the size in bytes of the out buffer.
+image: The raw pixel data to encode. The size of this buffer should be
+       w * h * (bytes per pixel), bytes per pixel depends on colortype and bitdepth.
+w: width of the raw pixel data in pixels.
+h: height of the raw pixel data in pixels.
+colortype: the color type of the raw input image. See explanation on PNG color types.
+bitdepth: the bit depth of the raw input image. See explanation on PNG color types.
+Return value: LodePNG error code (0 means no error).
+*/
+unsigned lodepng_encode_memory(unsigned char** out, size_t* outsize,
+                               const unsigned char* image, unsigned w, unsigned h,
+                               LodePNGColorType colortype, unsigned bitdepth);
+
+/*Same as lodepng_encode_memory, but always encodes from 32-bit RGBA raw image.*/
+unsigned lodepng_encode32(unsigned char** out, size_t* outsize,
+                          const unsigned char* image, unsigned w, unsigned h);
+
+/*Same as lodepng_encode_memory, but always encodes from 24-bit RGB raw image.*/
+unsigned lodepng_encode24(unsigned char** out, size_t* outsize,
+                          const unsigned char* image, unsigned w, unsigned h);
+
+#ifdef LODEPNG_COMPILE_DISK
+/*
+Converts raw pixel data into a PNG file on disk.
+Same as the other encode functions, but instead takes a filename as output.
+NOTE: This overwrites existing files without warning!
+*/
+unsigned lodepng_encode_file(const char* filename,
+                             const unsigned char* image, unsigned w, unsigned h,
+                             LodePNGColorType colortype, unsigned bitdepth);
+
+/*Same as lodepng_encode_file, but always encodes from 32-bit RGBA raw image.*/
+unsigned lodepng_encode32_file(const char* filename,
+                               const unsigned char* image, unsigned w, unsigned h);
+
+/*Same as lodepng_encode_file, but always encodes from 24-bit RGB raw image.*/
+unsigned lodepng_encode24_file(const char* filename,
+                               const unsigned char* image, unsigned w, unsigned h);
+#endif /*LODEPNG_COMPILE_DISK*/
+#endif /*LODEPNG_COMPILE_ENCODER*/
+
+
+#ifdef LODEPNG_COMPILE_CPP
+namespace lodepng
+{
+#ifdef LODEPNG_COMPILE_DECODER
+/*Same as lodepng_decode_memory, but decodes to an std::vector. The colortype
+is the format to output the pixels to. Default is RGBA 8-bit per channel.*/
+unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h,
+                const unsigned char* in, size_t insize,
+                LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8);
+unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h,
+                const std::vector<unsigned char>& in,
+                LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8);
+#ifdef LODEPNG_COMPILE_DISK
+/*
+Converts PNG file from disk to raw pixel data in memory.
+Same as the other decode functions, but instead takes a filename as input.
+*/
+unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h,
+                const std::string& filename,
+                LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8);
+#endif /* LODEPNG_COMPILE_DISK */
+#endif /* LODEPNG_COMPILE_DECODER */
+
+#ifdef LODEPNG_COMPILE_ENCODER
+/*Same as lodepng_encode_memory, but encodes to an std::vector. colortype
+is that of the raw input data. The output PNG color type will be auto chosen.*/
+unsigned encode(std::vector<unsigned char>& out,
+                const unsigned char* in, unsigned w, unsigned h,
+                LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8);
+unsigned encode(std::vector<unsigned char>& out,
+                const std::vector<unsigned char>& in, unsigned w, unsigned h,
+                LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8);
+#ifdef LODEPNG_COMPILE_DISK
+/*
+Converts 32-bit RGBA raw pixel data into a PNG file on disk.
+Same as the other encode functions, but instead takes a filename as output.
+NOTE: This overwrites existing files without warning!
+*/
+unsigned encode(const std::string& filename,
+                const unsigned char* in, unsigned w, unsigned h,
+                LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8);
+unsigned encode(const std::string& filename,
+                const std::vector<unsigned char>& in, unsigned w, unsigned h,
+                LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8);
+#endif /* LODEPNG_COMPILE_DISK */
+#endif /* LODEPNG_COMPILE_ENCODER */
+} /* namespace lodepng */
+#endif /*LODEPNG_COMPILE_CPP*/
+#endif /*LODEPNG_COMPILE_PNG*/
+
+#ifdef LODEPNG_COMPILE_ERROR_TEXT
+/*Returns an English description of the numerical error code.*/
+const char* lodepng_error_text(unsigned code);
+#endif /*LODEPNG_COMPILE_ERROR_TEXT*/
+
+#ifdef LODEPNG_COMPILE_DECODER
+/*Settings for zlib decompression*/
+typedef struct LodePNGDecompressSettings LodePNGDecompressSettings;
+struct LodePNGDecompressSettings
+{
+  unsigned ignore_adler32; /*if 1, continue and don't give an error message if the Adler32 checksum is corrupted*/
+
+  /*use custom zlib decoder instead of built in one (default: null)*/
+  unsigned (*custom_zlib)(unsigned char**, size_t*,
+                          const unsigned char*, size_t,
+                          const LodePNGDecompressSettings*);
+  /*use custom deflate decoder instead of built in one (default: null)
+  if custom_zlib is used, custom_deflate is ignored since only the built in
+  zlib function will call custom_deflate*/
+  unsigned (*custom_inflate)(unsigned char**, size_t*,
+                             const unsigned char*, size_t,
+                             const LodePNGDecompressSettings*);
+
+  const void* custom_context; /*optional custom settings for custom functions*/
+};
+
+extern const LodePNGDecompressSettings lodepng_default_decompress_settings;
+void lodepng_decompress_settings_init(LodePNGDecompressSettings* settings);
+#endif /*LODEPNG_COMPILE_DECODER*/
+
+#ifdef LODEPNG_COMPILE_ENCODER
+/*
+Settings for zlib compression. Tweaking these settings tweaks the balance
+between speed and compression ratio.
+*/
+typedef struct LodePNGCompressSettings LodePNGCompressSettings;
+struct LodePNGCompressSettings /*deflate = compress*/
+{
+  /*LZ77 related settings*/
+  unsigned btype; /*the block type for LZ (0, 1, 2 or 3, see zlib standard). Should be 2 for proper compression.*/
+  unsigned use_lz77; /*whether or not to use LZ77. Should be 1 for proper compression.*/
+  unsigned windowsize; /*must be a power of two <= 32768. higher compresses more but is slower. Default value: 2048.*/
+  unsigned minmatch; /*mininum lz77 length. 3 is normally best, 6 can be better for some PNGs. Default: 0*/
+  unsigned nicematch; /*stop searching if >= this length found. Set to 258 for best compression. Default: 128*/
+  unsigned lazymatching; /*use lazy matching: better compression but a bit slower. Default: true*/
+
+  /*use custom zlib encoder instead of built in one (default: null)*/
+  unsigned (*custom_zlib)(unsigned char**, size_t*,
+                          const unsigned char*, size_t,
+                          const LodePNGCompressSettings*);
+  /*use custom deflate encoder instead of built in one (default: null)
+  if custom_zlib is used, custom_deflate is ignored since only the built in
+  zlib function will call custom_deflate*/
+  unsigned (*custom_deflate)(unsigned char**, size_t*,
+                             const unsigned char*, size_t,
+                             const LodePNGCompressSettings*);
+
+  const void* custom_context; /*optional custom settings for custom functions*/
+};
+
+extern const LodePNGCompressSettings lodepng_default_compress_settings;
+void lodepng_compress_settings_init(LodePNGCompressSettings* settings);
+#endif /*LODEPNG_COMPILE_ENCODER*/
+
+#ifdef LODEPNG_COMPILE_PNG
+/*
+Color mode of an image. Contains all information required to decode the pixel
+bits to RGBA colors. This information is the same as used in the PNG file
+format, and is used both for PNG and raw image data in LodePNG.
+*/
+typedef struct LodePNGColorMode
+{
+  /*header (IHDR)*/
+  LodePNGColorType colortype; /*color type, see PNG standard or documentation further in this header file*/
+  unsigned bitdepth;  /*bits per sample, see PNG standard or documentation further in this header file*/
+
+  /*
+  palette (PLTE and tRNS)
+
+  Dynamically allocated with the colors of the palette, including alpha.
+  When encoding a PNG, to store your colors in the palette of the LodePNGColorMode, first use
+  lodepng_palette_clear, then for each color use lodepng_palette_add.
+  If you encode an image without alpha with palette, don't forget to put value 255 in each A byte of the palette.
+
+  When decoding, by default you can ignore this palette, since LodePNG already
+  fills the palette colors in the pixels of the raw RGBA output.
+
+  The palette is only supported for color type 3.
+  */
+  unsigned char* palette; /*palette in RGBARGBA... order. When allocated, must be either 0, or have size 1024*/
+  size_t palettesize; /*palette size in number of colors (amount of bytes is 4 * palettesize)*/
+
+  /*
+  transparent color key (tRNS)
+
+  This color uses the same bit depth as the bitdepth value in this struct, which can be 1-bit to 16-bit.
+  For greyscale PNGs, r, g and b will all 3 be set to the same.
+
+  When decoding, by default you can ignore this information, since LodePNG sets
+  pixels with this key to transparent already in the raw RGBA output.
+
+  The color key is only supported for color types 0 and 2.
+  */
+  unsigned key_defined; /*is a transparent color key given? 0 = false, 1 = true*/
+  unsigned key_r;       /*red/greyscale component of color key*/
+  unsigned key_g;       /*green component of color key*/
+  unsigned key_b;       /*blue component of color key*/
+} LodePNGColorMode;
+
+/*init, cleanup and copy functions to use with this struct*/
+void lodepng_color_mode_init(LodePNGColorMode* info);
+void lodepng_color_mode_cleanup(LodePNGColorMode* info);
+/*return value is error code (0 means no error)*/
+unsigned lodepng_color_mode_copy(LodePNGColorMode* dest, const LodePNGColorMode* source);
+
+void lodepng_palette_clear(LodePNGColorMode* info);
+/*add 1 color to the palette*/
+unsigned lodepng_palette_add(LodePNGColorMode* info,
+                             unsigned char r, unsigned char g, unsigned char b, unsigned char a);
+
+/*get the total amount of bits per pixel, based on colortype and bitdepth in the struct*/
+unsigned lodepng_get_bpp(const LodePNGColorMode* info);
+/*get the amount of color channels used, based on colortype in the struct.
+If a palette is used, it counts as 1 channel.*/
+unsigned lodepng_get_channels(const LodePNGColorMode* info);
+/*is it a greyscale type? (only colortype 0 or 4)*/
+unsigned lodepng_is_greyscale_type(const LodePNGColorMode* info);
+/*has it got an alpha channel? (only colortype 2 or 6)*/
+unsigned lodepng_is_alpha_type(const LodePNGColorMode* info);
+/*has it got a palette? (only colortype 3)*/
+unsigned lodepng_is_palette_type(const LodePNGColorMode* info);
+/*only returns true if there is a palette and there is a value in the palette with alpha < 255.
+Loops through the palette to check this.*/
+unsigned lodepng_has_palette_alpha(const LodePNGColorMode* info);
+/*
+Check if the given color info indicates the possibility of having non-opaque pixels in the PNG image.
+Returns true if the image can have translucent or invisible pixels (it still be opaque if it doesn't use such pixels).
+Returns false if the image can only have opaque pixels.
+In detail, it returns true only if it's a color type with alpha, or has a palette with non-opaque values,
+or if "key_defined" is true.
+*/
+unsigned lodepng_can_have_alpha(const LodePNGColorMode* info);
+/*Returns the byte size of a raw image buffer with given width, height and color mode*/
+size_t lodepng_get_raw_size(unsigned w, unsigned h, const LodePNGColorMode* color);
+
+#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
+/*The information of a Time chunk in PNG.*/
+typedef struct LodePNGTime
+{
+  unsigned year;    /*2 bytes used (0-65535)*/
+  unsigned month;   /*1-12*/
+  unsigned day;     /*1-31*/
+  unsigned hour;    /*0-23*/
+  unsigned minute;  /*0-59*/
+  unsigned second;  /*0-60 (to allow for leap seconds)*/
+} LodePNGTime;
+#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
+
+/*Information about the PNG image, except pixels, width and height.*/
+typedef struct LodePNGInfo
+{
+  /*header (IHDR), palette (PLTE) and transparency (tRNS) chunks*/
+  unsigned compression_method;/*compression method of the original file. Always 0.*/
+  unsigned filter_method;     /*filter method of the original file*/
+  unsigned interlace_method;  /*interlace method of the original file*/
+  LodePNGColorMode color;     /*color type and bits, palette and transparency of the PNG file*/
+
+#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
+  /*
+  suggested background color chunk (bKGD)
+  This color uses the same color mode as the PNG (except alpha channel), which can be 1-bit to 16-bit.
+
+  For greyscale PNGs, r, g and b will all 3 be set to the same. When encoding
+  the encoder writes the red one. For palette PNGs: When decoding, the RGB value
+  will be stored, not a palette index. But when encoding, specify the index of
+  the palette in background_r, the other two are then ignored.
+
+  The decoder does not use this background color to edit the color of pixels.
+  */
+  unsigned background_defined; /*is a suggested background color given?*/
+  unsigned background_r;       /*red component of suggested background color*/
+  unsigned background_g;       /*green component of suggested background color*/
+  unsigned background_b;       /*blue component of suggested background color*/
+
+  /*
+  non-international text chunks (tEXt and zTXt)
+
+  The char** arrays each contain num strings. The actual messages are in
+  text_strings, while text_keys are keywords that give a short description what
+  the actual text represents, e.g. Title, Author, Description, or anything else.
+
+  A keyword is minimum 1 character and maximum 79 characters long. It's
+  discouraged to use a single line length longer than 79 characters for texts.
+
+  Don't allocate these text buffers yourself. Use the init/cleanup functions
+  correctly and use lodepng_add_text and lodepng_clear_text.
+  */
+  size_t text_num; /*the amount of texts in these char** buffers (there may be more texts in itext)*/
+  char** text_keys; /*the keyword of a text chunk (e.g. "Comment")*/
+  char** text_strings; /*the actual text*/
+
+  /*
+  international text chunks (iTXt)
+  Similar to the non-international text chunks, but with additional strings
+  "langtags" and "transkeys".
+  */
+  size_t itext_num; /*the amount of international texts in this PNG*/
+  char** itext_keys; /*the English keyword of the text chunk (e.g. "Comment")*/
+  char** itext_langtags; /*language tag for this text's language, ISO/IEC 646 string, e.g. ISO 639 language tag*/
+  char** itext_transkeys; /*keyword translated to the international language - UTF-8 string*/
+  char** itext_strings; /*the actual international text - UTF-8 string*/
+
+  /*time chunk (tIME)*/
+  unsigned time_defined; /*set to 1 to make the encoder generate a tIME chunk*/
+  LodePNGTime time;
+
+  /*phys chunk (pHYs)*/
+  unsigned phys_defined; /*if 0, there is no pHYs chunk and the values below are undefined, if 1 else there is one*/
+  unsigned phys_x; /*pixels per unit in x direction*/
+  unsigned phys_y; /*pixels per unit in y direction*/
+  unsigned phys_unit; /*may be 0 (unknown unit) or 1 (metre)*/
+
+  /*
+  unknown chunks
+  There are 3 buffers, one for each position in the PNG where unknown chunks can appear
+  each buffer contains all unknown chunks for that position consecutively
+  The 3 buffers are the unknown chunks between certain critical chunks:
+  0: IHDR-PLTE, 1: PLTE-IDAT, 2: IDAT-IEND
+  Do not allocate or traverse this data yourself. Use the chunk traversing functions declared
+  later, such as lodepng_chunk_next and lodepng_chunk_append, to read/write this struct.
+  */
+  unsigned char* unknown_chunks_data[3];
+  size_t unknown_chunks_size[3]; /*size in bytes of the unknown chunks, given for protection*/
+#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
+} LodePNGInfo;
+
+/*init, cleanup and copy functions to use with this struct*/
+void lodepng_info_init(LodePNGInfo* info);
+void lodepng_info_cleanup(LodePNGInfo* info);
+/*return value is error code (0 means no error)*/
+unsigned lodepng_info_copy(LodePNGInfo* dest, const LodePNGInfo* source);
+
+#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
+void lodepng_clear_text(LodePNGInfo* info); /*use this to clear the texts again after you filled them in*/
+unsigned lodepng_add_text(LodePNGInfo* info, const char* key, const char* str); /*push back both texts at once*/
+
+void lodepng_clear_itext(LodePNGInfo* info); /*use this to clear the itexts again after you filled them in*/
+unsigned lodepng_add_itext(LodePNGInfo* info, const char* key, const char* langtag,
+                           const char* transkey, const char* str); /*push back the 4 texts of 1 chunk at once*/
+#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
+
+/*
+Converts raw buffer from one color type to another color type, based on
+LodePNGColorMode structs to describe the input and output color type.
+See the reference manual at the end of this header file to see which color conversions are supported.
+return value = LodePNG error code (0 if all went ok, an error if the conversion isn't supported)
+The out buffer must have size (w * h * bpp + 7) / 8, where bpp is the bits per pixel
+of the output color type (lodepng_get_bpp).
+For < 8 bpp images, there should not be padding bits at the end of scanlines.
+For 16-bit per channel colors, uses big endian format like PNG does.
+Return value is LodePNG error code
+*/
+unsigned lodepng_convert(unsigned char* out, const unsigned char* in,
+                         const LodePNGColorMode* mode_out, const LodePNGColorMode* mode_in,
+                         unsigned w, unsigned h);
+
+#ifdef LODEPNG_COMPILE_DECODER
+/*
+Settings for the decoder. This contains settings for the PNG and the Zlib
+decoder, but not the Info settings from the Info structs.
+*/
+typedef struct LodePNGDecoderSettings
+{
+  LodePNGDecompressSettings zlibsettings; /*in here is the setting to ignore Adler32 checksums*/
+
+  unsigned ignore_crc; /*ignore CRC checksums*/
+
+  unsigned color_convert; /*whether to convert the PNG to the color type you want. Default: yes*/
+
+#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
+  unsigned read_text_chunks; /*if false but remember_unknown_chunks is true, they're stored in the unknown chunks*/
+  /*store all bytes from unknown chunks in the LodePNGInfo (off by default, useful for a png editor)*/
+  unsigned remember_unknown_chunks;
+#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
+} LodePNGDecoderSettings;
+
+void lodepng_decoder_settings_init(LodePNGDecoderSettings* settings);
+#endif /*LODEPNG_COMPILE_DECODER*/
+
+#ifdef LODEPNG_COMPILE_ENCODER
+/*automatically use color type with less bits per pixel if losslessly possible. Default: AUTO*/
+typedef enum LodePNGFilterStrategy
+{
+  /*every filter at zero*/
+  LFS_ZERO,
+  /*Use filter that gives minimum sum, as described in the official PNG filter heuristic.*/
+  LFS_MINSUM,
+  /*Use the filter type that gives smallest Shannon entropy for this scanline. Depending
+  on the image, this is better or worse than minsum.*/
+  LFS_ENTROPY,
+  /*
+  Brute-force-search PNG filters by compressing each filter for each scanline.
+  Experimental, very slow, and only rarely gives better compression than MINSUM.
+  */
+  LFS_BRUTE_FORCE,
+  /*use predefined_filters buffer: you specify the filter type for each scanline*/
+  LFS_PREDEFINED
+} LodePNGFilterStrategy;
+
+/*Gives characteristics about the colors of the image, which helps decide which color model to use for encoding.
+Used internally by default if "auto_convert" is enabled. Public because it's useful for custom algorithms.*/
+typedef struct LodePNGColorProfile
+{
+  unsigned colored; /*not greyscale*/
+  unsigned key; /*if true, image is not opaque. Only if true and alpha is false, color key is possible.*/
+  unsigned short key_r; /*these values are always in 16-bit bitdepth in the profile*/
+  unsigned short key_g;
+  unsigned short key_b;
+  unsigned alpha; /*alpha channel or alpha palette required*/
+  unsigned numcolors; /*amount of colors, up to 257. Not valid if bits == 16.*/
+  unsigned char palette[1024]; /*Remembers up to the first 256 RGBA colors, in no particular order*/
+  unsigned bits; /*bits per channel (not for palette). 1,2 or 4 for greyscale only. 16 if 16-bit per channel required.*/
+} LodePNGColorProfile;
+
+void lodepng_color_profile_init(LodePNGColorProfile* profile);
+
+/*Get a LodePNGColorProfile of the image.*/
+unsigned lodepng_get_color_profile(LodePNGColorProfile* profile,
+                                   const unsigned char* image, unsigned w, unsigned h,
+                                   const LodePNGColorMode* mode_in);
+/*The function LodePNG uses internally to decide the PNG color with auto_convert.
+Chooses an optimal color model, e.g. grey if only grey pixels, palette if < 256 colors, ...*/
+unsigned lodepng_auto_choose_color(LodePNGColorMode* mode_out,
+                                   const unsigned char* image, unsigned w, unsigned h,
+                                   const LodePNGColorMode* mode_in);
+
+/*Settings for the encoder.*/
+typedef struct LodePNGEncoderSettings
+{
+  LodePNGCompressSettings zlibsettings; /*settings for the zlib encoder, such as window size, ...*/
+
+  unsigned auto_convert; /*automatically choose output PNG color type. Default: true*/
+
+  /*If true, follows the official PNG heuristic: if the PNG uses a palette or lower than
+  8 bit depth, set all filters to zero. Otherwise use the filter_strategy. Note that to
+  completely follow the official PNG heuristic, filter_palette_zero must be true and
+  filter_strategy must be LFS_MINSUM*/
+  unsigned filter_palette_zero;
+  /*Which filter strategy to use when not using zeroes due to filter_palette_zero.
+  Set filter_palette_zero to 0 to ensure always using your chosen strategy. Default: LFS_MINSUM*/
+  LodePNGFilterStrategy filter_strategy;
+  /*used if filter_strategy is LFS_PREDEFINED. In that case, this must point to a buffer with
+  the same length as the amount of scanlines in the image, and each value must <= 5. You
+  have to cleanup this buffer, LodePNG will never free it. Don't forget that filter_palette_zero
+  must be set to 0 to ensure this is also used on palette or low bitdepth images.*/
+  const unsigned char* predefined_filters;
+
+  /*force creating a PLTE chunk if colortype is 2 or 6 (= a suggested palette).
+  If colortype is 3, PLTE is _always_ created.*/
+  unsigned force_palette;
+#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
+  /*add LodePNG identifier and version as a text chunk, for debugging*/
+  unsigned add_id;
+  /*encode text chunks as zTXt chunks instead of tEXt chunks, and use compression in iTXt chunks*/
+  unsigned text_compression;
+#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
+} LodePNGEncoderSettings;
+
+void lodepng_encoder_settings_init(LodePNGEncoderSettings* settings);
+#endif /*LODEPNG_COMPILE_ENCODER*/
+
+
+#if defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER)
+/*The settings, state and information for extended encoding and decoding.*/
+typedef struct LodePNGState
+{
+#ifdef LODEPNG_COMPILE_DECODER
+  LodePNGDecoderSettings decoder; /*the decoding settings*/
+#endif /*LODEPNG_COMPILE_DECODER*/
+#ifdef LODEPNG_COMPILE_ENCODER
+  LodePNGEncoderSettings encoder; /*the encoding settings*/
+#endif /*LODEPNG_COMPILE_ENCODER*/
+  LodePNGColorMode info_raw; /*specifies the format in which you would like to get the raw pixel buffer*/
+  LodePNGInfo info_png; /*info of the PNG image obtained after decoding*/
+  unsigned error;
+#ifdef LODEPNG_COMPILE_CPP
+  /* For the lodepng::State subclass. */
+  virtual ~LodePNGState(){}
+#endif
+} LodePNGState;
+
+/*init, cleanup and copy functions to use with this struct*/
+void lodepng_state_init(LodePNGState* state);
+void lodepng_state_cleanup(LodePNGState* state);
+void lodepng_state_copy(LodePNGState* dest, const LodePNGState* source);
+#endif /* defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) */
+
+#ifdef LODEPNG_COMPILE_DECODER
+/*
+Same as lodepng_decode_memory, but uses a LodePNGState to allow custom settings and
+getting much more information about the PNG image and color mode.
+*/
+unsigned lodepng_decode(unsigned char** out, unsigned* w, unsigned* h,
+                        LodePNGState* state,
+                        const unsigned char* in, size_t insize);
+
+/*
+Read the PNG header, but not the actual data. This returns only the information
+that is in the header chunk of the PNG, such as width, height and color type. The
+information is placed in the info_png field of the LodePNGState.
+*/
+unsigned lodepng_inspect(unsigned* w, unsigned* h,
+                         LodePNGState* state,
+                         const unsigned char* in, size_t insize);
+#endif /*LODEPNG_COMPILE_DECODER*/
+
+
+#ifdef LODEPNG_COMPILE_ENCODER
+/*This function allocates the out buffer with standard malloc and stores the size in *outsize.*/
+unsigned lodepng_encode(unsigned char** out, size_t* outsize,
+                        const unsigned char* image, unsigned w, unsigned h,
+                        LodePNGState* state);
+#endif /*LODEPNG_COMPILE_ENCODER*/
+
+/*
+The lodepng_chunk functions are normally not needed, except to traverse the
+unknown chunks stored in the LodePNGInfo struct, or add new ones to it.
+It also allows traversing the chunks of an encoded PNG file yourself.
+
+PNG standard chunk naming conventions:
+First byte: uppercase = critical, lowercase = ancillary
+Second byte: uppercase = public, lowercase = private
+Third byte: must be uppercase
+Fourth byte: uppercase = unsafe to copy, lowercase = safe to copy
+*/
+
+/*
+Gets the length of the data of the chunk. Total chunk length has 12 bytes more.
+There must be at least 4 bytes to read from. If the result value is too large,
+it may be corrupt data.
+*/
+unsigned lodepng_chunk_length(const unsigned char* chunk);
+
+/*puts the 4-byte type in null terminated string*/
+void lodepng_chunk_type(char type[5], const unsigned char* chunk);
+
+/*check if the type is the given type*/
+unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type);
+
+/*0: it's one of the critical chunk types, 1: it's an ancillary chunk (see PNG standard)*/
+unsigned char lodepng_chunk_ancillary(const unsigned char* chunk);
+
+/*0: public, 1: private (see PNG standard)*/
+unsigned char lodepng_chunk_private(const unsigned char* chunk);
+
+/*0: the chunk is unsafe to copy, 1: the chunk is safe to copy (see PNG standard)*/
+unsigned char lodepng_chunk_safetocopy(const unsigned char* chunk);
+
+/*get pointer to the data of the chunk, where the input points to the header of the chunk*/
+unsigned char* lodepng_chunk_data(unsigned char* chunk);
+const unsigned char* lodepng_chunk_data_const(const unsigned char* chunk);
+
+/*returns 0 if the crc is correct, 1 if it's incorrect (0 for OK as usual!)*/
+unsigned lodepng_chunk_check_crc(const unsigned char* chunk);
+
+/*generates the correct CRC from the data and puts it in the last 4 bytes of the chunk*/
+void lodepng_chunk_generate_crc(unsigned char* chunk);
+
+/*iterate to next chunks. don't use on IEND chunk, as there is no next chunk then*/
+unsigned char* lodepng_chunk_next(unsigned char* chunk);
+const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk);
+
+/*
+Appends chunk to the data in out. The given chunk should already have its chunk header.
+The out variable and outlength are updated to reflect the new reallocated buffer.
+Returns error code (0 if it went ok)
+*/
+unsigned lodepng_chunk_append(unsigned char** out, size_t* outlength, const unsigned char* chunk);
+
+/*
+Appends new chunk to out. The chunk to append is given by giving its length, type
+and data separately. The type is a 4-letter string.
+The out variable and outlength are updated to reflect the new reallocated buffer.
+Returne error code (0 if it went ok)
+*/
+unsigned lodepng_chunk_create(unsigned char** out, size_t* outlength, unsigned length,
+                              const char* type, const unsigned char* data);
+
+
+/*Calculate CRC32 of buffer*/
+unsigned lodepng_crc32(const unsigned char* buf, size_t len);
+#endif /*LODEPNG_COMPILE_PNG*/
+
+
+#ifdef LODEPNG_COMPILE_ZLIB
+/*
+This zlib part can be used independently to zlib compress and decompress a
+buffer. It cannot be used to create gzip files however, and it only supports the
+part of zlib that is required for PNG, it does not support dictionaries.
+*/
+
+#ifdef LODEPNG_COMPILE_DECODER
+/*Inflate a buffer. Inflate is the decompression step of deflate. Out buffer must be freed after use.*/
+unsigned lodepng_inflate(unsigned char** out, size_t* outsize,
+                         const unsigned char* in, size_t insize,
+                         const LodePNGDecompressSettings* settings);
+
+/*
+Decompresses Zlib data. Reallocates the out buffer and appends the data. The
+data must be according to the zlib specification.
+Either, *out must be NULL and *outsize must be 0, or, *out must be a valid
+buffer and *outsize its size in bytes. out must be freed by user after usage.
+*/
+unsigned lodepng_zlib_decompress(unsigned char** out, size_t* outsize,
+                                 const unsigned char* in, size_t insize,
+                                 const LodePNGDecompressSettings* settings);
+#endif /*LODEPNG_COMPILE_DECODER*/
+
+#ifdef LODEPNG_COMPILE_ENCODER
+/*
+Compresses data with Zlib. Reallocates the out buffer and appends the data.
+Zlib adds a small header and trailer around the deflate data.
+The data is output in the format of the zlib specification.
+Either, *out must be NULL and *outsize must be 0, or, *out must be a valid
+buffer and *outsize its size in bytes. out must be freed by user after usage.
+*/
+unsigned lodepng_zlib_compress(unsigned char** out, size_t* outsize,
+                               const unsigned char* in, size_t insize,
+                               const LodePNGCompressSettings* settings);
+
+/*
+Find length-limited Huffman code for given frequencies. This function is in the
+public interface only for tests, it's used internally by lodepng_deflate.
+*/
+unsigned lodepng_huffman_code_lengths(unsigned* lengths, const unsigned* frequencies,
+                                      size_t numcodes, unsigned maxbitlen);
+
+/*Compress a buffer with deflate. See RFC 1951. Out buffer must be freed after use.*/
+unsigned lodepng_deflate(unsigned char** out, size_t* outsize,
+                         const unsigned char* in, size_t insize,
+                         const LodePNGCompressSettings* settings);
+
+#endif /*LODEPNG_COMPILE_ENCODER*/
+#endif /*LODEPNG_COMPILE_ZLIB*/
+
+#ifdef LODEPNG_COMPILE_DISK
+/*
+Load a file from disk into buffer. The function allocates the out buffer, and
+after usage you should free it.
+out: output parameter, contains pointer to loaded buffer.
+outsize: output parameter, size of the allocated out buffer
+filename: the path to the file to load
+return value: error code (0 means ok)
+*/
+unsigned lodepng_load_file(unsigned char** out, size_t* outsize, const char* filename);
+
+/*
+Save a file from buffer to disk. Warning, if it exists, this function overwrites
+the file without warning!
+buffer: the buffer to write
+buffersize: size of the buffer to write
+filename: the path to the file to save to
+return value: error code (0 means ok)
+*/
+unsigned lodepng_save_file(const unsigned char* buffer, size_t buffersize, const char* filename);
+#endif /*LODEPNG_COMPILE_DISK*/
+
+#ifdef LODEPNG_COMPILE_CPP
+/* The LodePNG C++ wrapper uses std::vectors instead of manually allocated memory buffers. */
+namespace lodepng
+{
+#ifdef LODEPNG_COMPILE_PNG
+class State : public LodePNGState
+{
+  public:
+    State();
+    State(const State& other);
+    virtual ~State();
+    State& operator=(const State& other);
+};
+
+#ifdef LODEPNG_COMPILE_DECODER
+/* Same as other lodepng::decode, but using a State for more settings and information. */
+unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h,
+                State& state,
+                const unsigned char* in, size_t insize);
+unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h,
+                State& state,
+                const std::vector<unsigned char>& in);
+#endif /*LODEPNG_COMPILE_DECODER*/
+
+#ifdef LODEPNG_COMPILE_ENCODER
+/* Same as other lodepng::encode, but using a State for more settings and information. */
+unsigned encode(std::vector<unsigned char>& out,
+                const unsigned char* in, unsigned w, unsigned h,
+                State& state);
+unsigned encode(std::vector<unsigned char>& out,
+                const std::vector<unsigned char>& in, unsigned w, unsigned h,
+                State& state);
+#endif /*LODEPNG_COMPILE_ENCODER*/
+
+#ifdef LODEPNG_COMPILE_DISK
+/*
+Load a file from disk into an std::vector. If the vector is empty, then either
+the file doesn't exist or is an empty file.
+*/
+void load_file(std::vector<unsigned char>& buffer, const std::string& filename);
+
+/*
+Save the binary data in an std::vector to a file on disk. The file is overwritten
+without warning.
+*/
+unsigned save_file(const std::vector<unsigned char>& buffer, const std::string& filename);
+#endif /* LODEPNG_COMPILE_DISK */
+#endif /* LODEPNG_COMPILE_PNG */
+
+#ifdef LODEPNG_COMPILE_ZLIB
+#ifdef LODEPNG_COMPILE_DECODER
+/* Zlib-decompress an unsigned char buffer */
+unsigned decompress(std::vector<unsigned char>& out, const unsigned char* in, size_t insize,
+                    const LodePNGDecompressSettings& settings = lodepng_default_decompress_settings);
+
+/* Zlib-decompress an std::vector */
+unsigned decompress(std::vector<unsigned char>& out, const std::vector<unsigned char>& in,
+                    const LodePNGDecompressSettings& settings = lodepng_default_decompress_settings);
+#endif /* LODEPNG_COMPILE_DECODER */
+
+#ifdef LODEPNG_COMPILE_ENCODER
+/* Zlib-compress an unsigned char buffer */
+unsigned compress(std::vector<unsigned char>& out, const unsigned char* in, size_t insize,
+                  const LodePNGCompressSettings& settings = lodepng_default_compress_settings);
+
+/* Zlib-compress an std::vector */
+unsigned compress(std::vector<unsigned char>& out, const std::vector<unsigned char>& in,
+                  const LodePNGCompressSettings& settings = lodepng_default_compress_settings);
+#endif /* LODEPNG_COMPILE_ENCODER */
+#endif /* LODEPNG_COMPILE_ZLIB */
+} /* namespace lodepng */
+#endif /*LODEPNG_COMPILE_CPP*/
+
+/*
+TODO:
+[.] test if there are no memory leaks or security exploits - done a lot but needs to be checked often
+[.] check compatibility with various compilers  - done but needs to be redone for every newer version
+[X] converting color to 16-bit per channel types
+[ ] read all public PNG chunk types (but never let the color profile and gamma ones touch RGB values)
+[ ] make sure encoder generates no chunks with size > (2^31)-1
+[ ] partial decoding (stream processing)
+[X] let the "isFullyOpaque" function check color keys and transparent palettes too
+[X] better name for the variables "codes", "codesD", "codelengthcodes", "clcl" and "lldl"
+[ ] don't stop decoding on errors like 69, 57, 58 (make warnings)
+[ ] let the C++ wrapper catch exceptions coming from the standard library and return LodePNG error codes
+[ ] allow user to provide custom color conversion functions, e.g. for premultiplied alpha, padding bits or not, ...
+*/
+
+#endif /*LODEPNG_H inclusion guard*/
+
+/*
+LodePNG Documentation
+---------------------
+
+0. table of contents
+--------------------
+
+  1. about
+   1.1. supported features
+   1.2. features not supported
+  2. C and C++ version
+  3. security
+  4. decoding
+  5. encoding
+  6. color conversions
+    6.1. PNG color types
+    6.2. color conversions
+    6.3. padding bits
+    6.4. A note about 16-bits per channel and endianness
+  7. error values
+  8. chunks and PNG editing
+  9. compiler support
+  10. examples
+   10.1. decoder C++ example
+   10.2. decoder C example
+  11. changes
+  12. contact information
+
+
+1. about
+--------
+
+PNG is a file format to store raster images losslessly with good compression,
+supporting different color types and alpha channel.
+
+LodePNG is a PNG codec according to the Portable Network Graphics (PNG)
+Specification (Second Edition) - W3C Recommendation 10 November 2003.
+
+The specifications used are:
+
+*) Portable Network Graphics (PNG) Specification (Second Edition):
+     http://www.w3.org/TR/2003/REC-PNG-20031110
+*) RFC 1950 ZLIB Compressed Data Format version 3.3:
+     http://www.gzip.org/zlib/rfc-zlib.html
+*) RFC 1951 DEFLATE Compressed Data Format Specification ver 1.3:
+     http://www.gzip.org/zlib/rfc-deflate.html
+
+The most recent version of LodePNG can currently be found at
+http://lodev.org/lodepng/
+
+LodePNG works both in C (ISO C90) and C++, with a C++ wrapper that adds
+extra functionality.
+
+LodePNG exists out of two files:
+-lodepng.h: the header file for both C and C++
+-lodepng.c(pp): give it the name lodepng.c or lodepng.cpp (or .cc) depending on your usage
+
+If you want to start using LodePNG right away without reading this doc, get the
+examples from the LodePNG website to see how to use it in code, or check the
+smaller examples in chapter 13 here.
+
+LodePNG is simple but only supports the basic requirements. To achieve
+simplicity, the following design choices were made: There are no dependencies
+on any external library. There are functions to decode and encode a PNG with
+a single function call, and extended versions of these functions taking a
+LodePNGState struct allowing to specify or get more information. By default
+the colors of the raw image are always RGB or RGBA, no matter what color type
+the PNG file uses. To read and write files, there are simple functions to
+convert the files to/from buffers in memory.
+
+This all makes LodePNG suitable for loading textures in games, demos and small
+programs, ... It's less suitable for full fledged image editors, loading PNGs
+over network (it requires all the image data to be available before decoding can
+begin), life-critical systems, ...
+
+1.1. supported features
+-----------------------
+
+The following features are supported by the decoder:
+
+*) decoding of PNGs with any color type, bit depth and interlace mode, to a 24- or 32-bit color raw image,
+   or the same color type as the PNG
+*) encoding of PNGs, from any raw image to 24- or 32-bit color, or the same color type as the raw image
+*) Adam7 interlace and deinterlace for any color type
+*) loading the image from harddisk or decoding it from a buffer from other sources than harddisk
+*) support for alpha channels, including RGBA color model, translucent palettes and color keying
+*) zlib decompression (inflate)
+*) zlib compression (deflate)
+*) CRC32 and ADLER32 checksums
+*) handling of unknown chunks, allowing making a PNG editor that stores custom and unknown chunks.
+*) the following chunks are supported (generated/interpreted) by both encoder and decoder:
+    IHDR: header information
+    PLTE: color palette
+    IDAT: pixel data
+    IEND: the final chunk
+    tRNS: transparency for palettized images
+    tEXt: textual information
+    zTXt: compressed textual information
+    iTXt: international textual information
+    bKGD: suggested background color
+    pHYs: physical dimensions
+    tIME: modification time
+
+1.2. features not supported
+---------------------------
+
+The following features are _not_ supported:
+
+*) some features needed to make a conformant PNG-Editor might be still missing.
+*) partial loading/stream processing. All data must be available and is processed in one call.
+*) The following public chunks are not supported but treated as unknown chunks by LodePNG
+    cHRM, gAMA, iCCP, sRGB, sBIT, hIST, sPLT
+   Some of these are not supported on purpose: LodePNG wants to provide the RGB values
+   stored in the pixels, not values modified by system dependent gamma or color models.
+
+
+2. C and C++ version
+--------------------
+
+The C version uses buffers allocated with alloc that you need to free()
+yourself. You need to use init and cleanup functions for each struct whenever
+using a struct from the C version to avoid exploits and memory leaks.
+
+The C++ version has extra functions with std::vectors in the interface and the
+lodepng::State class which is a LodePNGState with constructor and destructor.
+
+These files work without modification for both C and C++ compilers because all
+the additional C++ code is in "#ifdef __cplusplus" blocks that make C-compilers
+ignore it, and the C code is made to compile both with strict ISO C90 and C++.
+
+To use the C++ version, you need to rename the source file to lodepng.cpp
+(instead of lodepng.c), and compile it with a C++ compiler.
+
+To use the C version, you need to rename the source file to lodepng.c (instead
+of lodepng.cpp), and compile it with a C compiler.
+
+
+3. Security
+-----------
+
+Even if carefully designed, it's always possible that LodePNG contains possible
+exploits. If you discover one, please let me know, and it will be fixed.
+
+When using LodePNG, care has to be taken with the C version of LodePNG, as well
+as the C-style structs when working with C++. The following conventions are used
+for all C-style structs:
+
+-if a struct has a corresponding init function, always call the init function when making a new one
+-if a struct has a corresponding cleanup function, call it before the struct disappears to avoid memory leaks
+-if a struct has a corresponding copy function, use the copy function instead of "=".
+ The destination must also be inited already.
+
+
+4. Decoding
+-----------
+
+Decoding converts a PNG compressed image to a raw pixel buffer.
+
+Most documentation on using the decoder is at its declarations in the header
+above. For C, simple decoding can be done with functions such as
+lodepng_decode32, and more advanced decoding can be done with the struct
+LodePNGState and lodepng_decode. For C++, all decoding can be done with the
+various lodepng::decode functions, and lodepng::State can be used for advanced
+features.
+
+When using the LodePNGState, it uses the following fields for decoding:
+*) LodePNGInfo info_png: it stores extra information about the PNG (the input) in here
+*) LodePNGColorMode info_raw: here you can say what color mode of the raw image (the output) you want to get
+*) LodePNGDecoderSettings decoder: you can specify a few extra settings for the decoder to use
+
+LodePNGInfo info_png
+--------------------
+
+After decoding, this contains extra information of the PNG image, except the actual
+pixels, width and height because these are already gotten directly from the decoder
+functions.
+
+It contains for example the original color type of the PNG image, text comments,
+suggested background color, etc... More details about the LodePNGInfo struct are
+at its declaration documentation.
+
+LodePNGColorMode info_raw
+-------------------------
+
+When decoding, here you can specify which color type you want
+the resulting raw image to be. If this is different from the colortype of the
+PNG, then the decoder will automatically convert the result. This conversion
+always works, except if you want it to convert a color PNG to greyscale or to
+a palette with missing colors.
+
+By default, 32-bit color is used for the result.
+
+LodePNGDecoderSettings decoder
+------------------------------
+
+The settings can be used to ignore the errors created by invalid CRC and Adler32
+chunks, and to disable the decoding of tEXt chunks.
+
+There's also a setting color_convert, true by default. If false, no conversion
+is done, the resulting data will be as it was in the PNG (after decompression)
+and you'll have to puzzle the colors of the pixels together yourself using the
+color type information in the LodePNGInfo.
+
+
+5. Encoding
+-----------
+
+Encoding converts a raw pixel buffer to a PNG compressed image.
+
+Most documentation on using the encoder is at its declarations in the header
+above. For C, simple encoding can be done with functions such as
+lodepng_encode32, and more advanced decoding can be done with the struct
+LodePNGState and lodepng_encode. For C++, all encoding can be done with the
+various lodepng::encode functions, and lodepng::State can be used for advanced
+features.
+
+Like the decoder, the encoder can also give errors. However it gives less errors
+since the encoder input is trusted, the decoder input (a PNG image that could
+be forged by anyone) is not trusted.
+
+When using the LodePNGState, it uses the following fields for encoding:
+*) LodePNGInfo info_png: here you specify how you want the PNG (the output) to be.
+*) LodePNGColorMode info_raw: here you say what color type of the raw image (the input) has
+*) LodePNGEncoderSettings encoder: you can specify a few settings for the encoder to use
+
+LodePNGInfo info_png
+--------------------
+
+When encoding, you use this the opposite way as when decoding: for encoding,
+you fill in the values you want the PNG to have before encoding. By default it's
+not needed to specify a color type for the PNG since it's automatically chosen,
+but it's possible to choose it yourself given the right settings.
+
+The encoder will not always exactly match the LodePNGInfo struct you give,
+it tries as close as possible. Some things are ignored by the encoder. The
+encoder uses, for example, the following settings from it when applicable:
+colortype and bitdepth, text chunks, time chunk, the color key, the palette, the
+background color, the interlace method, unknown chunks, ...
+
+When encoding to a PNG with colortype 3, the encoder will generate a PLTE chunk.
+If the palette contains any colors for which the alpha channel is not 255 (so
+there are translucent colors in the palette), it'll add a tRNS chunk.
+
+LodePNGColorMode info_raw
+-------------------------
+
+You specify the color type of the raw image that you give to the input here,
+including a possible transparent color key and palette you happen to be using in
+your raw image data.
+
+By default, 32-bit color is assumed, meaning your input has to be in RGBA
+format with 4 bytes (unsigned chars) per pixel.
+
+LodePNGEncoderSettings encoder
+------------------------------
+
+The following settings are supported (some are in sub-structs):
+*) auto_convert: when this option is enabled, the encoder will
+automatically choose the smallest possible color mode (including color key) that
+can encode the colors of all pixels without information loss.
+*) btype: the block type for LZ77. 0 = uncompressed, 1 = fixed huffman tree,
+   2 = dynamic huffman tree (best compression). Should be 2 for proper
+   compression.
+*) use_lz77: whether or not to use LZ77 for compressed block types. Should be
+   true for proper compression.
+*) windowsize: the window size used by the LZ77 encoder (1 - 32768). Has value
+   2048 by default, but can be set to 32768 for better, but slow, compression.
+*) force_palette: if colortype is 2 or 6, you can make the encoder write a PLTE
+   chunk if force_palette is true. This can used as suggested palette to convert
+   to by viewers that don't support more than 256 colors (if those still exist)
+*) add_id: add text chunk "Encoder: LodePNG <version>" to the image.
+*) text_compression: default 1. If 1, it'll store texts as zTXt instead of tEXt chunks.
+  zTXt chunks use zlib compression on the text. This gives a smaller result on
+  large texts but a larger result on small texts (such as a single program name).
+  It's all tEXt or all zTXt though, there's no separate setting per text yet.
+
+
+6. color conversions
+--------------------
+
+An important thing to note about LodePNG, is that the color type of the PNG, and
+the color type of the raw image, are completely independent. By default, when
+you decode a PNG, you get the result as a raw image in the color type you want,
+no matter whether the PNG was encoded with a palette, greyscale or RGBA color.
+And if you encode an image, by default LodePNG will automatically choose the PNG
+color type that gives good compression based on the values of colors and amount
+of colors in the image. It can be configured to let you control it instead as
+well, though.
+
+To be able to do this, LodePNG does conversions from one color mode to another.
+It can convert from almost any color type to any other color type, except the
+following conversions: RGB to greyscale is not supported, and converting to a
+palette when the palette doesn't have a required color is not supported. This is
+not supported on purpose: this is information loss which requires a color
+reduction algorithm that is beyong the scope of a PNG encoder (yes, RGB to grey
+is easy, but there are multiple ways if you want to give some channels more
+weight).
+
+By default, when decoding, you get the raw image in 32-bit RGBA or 24-bit RGB
+color, no matter what color type the PNG has. And by default when encoding,
+LodePNG automatically picks the best color model for the output PNG, and expects
+the input image to be 32-bit RGBA or 24-bit RGB. So, unless you want to control
+the color format of the images yourself, you can skip this chapter.
+
+6.1. PNG color types
+--------------------
+
+A PNG image can have many color types, ranging from 1-bit color to 64-bit color,
+as well as palettized color modes. After the zlib decompression and unfiltering
+in the PNG image is done, the raw pixel data will have that color type and thus
+a certain amount of bits per pixel. If you want the output raw image after
+decoding to have another color type, a conversion is done by LodePNG.
+
+The PNG specification gives the following color types:
+
+0: greyscale, bit depths 1, 2, 4, 8, 16
+2: RGB, bit depths 8 and 16
+3: palette, bit depths 1, 2, 4 and 8
+4: greyscale with alpha, bit depths 8 and 16
+6: RGBA, bit depths 8 and 16
+
+Bit depth is the amount of bits per pixel per color channel. So the total amount
+of bits per pixel is: amount of channels * bitdepth.
+
+6.2. color conversions
+----------------------
+
+As explained in the sections about the encoder and decoder, you can specify
+color types and bit depths in info_png and info_raw to change the default
+behaviour.
+
+If, when decoding, you want the raw image to be something else than the default,
+you need to set the color type and bit depth you want in the LodePNGColorMode,
+or the parameters colortype and bitdepth of the simple decoding function.
+
+If, when encoding, you use another color type than the default in the raw input
+image, you need to specify its color type and bit depth in the LodePNGColorMode
+of the raw image, or use the parameters colortype and bitdepth of the simple
+encoding function.
+
+If, when encoding, you don't want LodePNG to choose the output PNG color type
+but control it yourself, you need to set auto_convert in the encoder settings
+to false, and specify the color type you want in the LodePNGInfo of the
+encoder (including palette: it can generate a palette if auto_convert is true,
+otherwise not).
+
+If the input and output color type differ (whether user chosen or auto chosen),
+LodePNG will do a color conversion, which follows the rules below, and may
+sometimes result in an error.
+
+To avoid some confusion:
+-the decoder converts from PNG to raw image
+-the encoder converts from raw image to PNG
+-the colortype and bitdepth in LodePNGColorMode info_raw, are those of the raw image
+-the colortype and bitdepth in the color field of LodePNGInfo info_png, are those of the PNG
+-when encoding, the color type in LodePNGInfo is ignored if auto_convert
+ is enabled, it is automatically generated instead
+-when decoding, the color type in LodePNGInfo is set by the decoder to that of the original
+ PNG image, but it can be ignored since the raw image has the color type you requested instead
+-if the color type of the LodePNGColorMode and PNG image aren't the same, a conversion
+ between the color types is done if the color types are supported. If it is not
+ supported, an error is returned. If the types are the same, no conversion is done.
+-even though some conversions aren't supported, LodePNG supports loading PNGs from any
+ colortype and saving PNGs to any colortype, sometimes it just requires preparing
+ the raw image correctly before encoding.
+-both encoder and decoder use the same color converter.
+
+Non supported color conversions:
+-color to greyscale: no error is thrown, but the result will look ugly because
+only the red channel is taken
+-anything to palette when that palette does not have that color in it: in this
+case an error is thrown
+
+Supported color conversions:
+-anything to 8-bit RGB, 8-bit RGBA, 16-bit RGB, 16-bit RGBA
+-any grey or grey+alpha, to grey or grey+alpha
+-anything to a palette, as long as the palette has the requested colors in it
+-removing alpha channel
+-higher to smaller bitdepth, and vice versa
+
+If you want no color conversion to be done (e.g. for speed or control):
+-In the encoder, you can make it save a PNG with any color type by giving the
+raw color mode and LodePNGInfo the same color mode, and setting auto_convert to
+false.
+-In the decoder, you can make it store the pixel data in the same color type
+as the PNG has, by setting the color_convert setting to false. Settings in
+info_raw are then ignored.
+
+The function lodepng_convert does the color conversion. It is available in the
+interface but normally isn't needed since the encoder and decoder already call
+it.
+
+6.3. padding bits
+-----------------
+
+In the PNG file format, if a less than 8-bit per pixel color type is used and the scanlines
+have a bit amount that isn't a multiple of 8, then padding bits are used so that each
+scanline starts at a fresh byte. But that is NOT true for the LodePNG raw input and output.
+The raw input image you give to the encoder, and the raw output image you get from the decoder
+will NOT have these padding bits, e.g. in the case of a 1-bit image with a width
+of 7 pixels, the first pixel of the second scanline will the the 8th bit of the first byte,
+not the first bit of a new byte.
+
+6.4. A note about 16-bits per channel and endianness
+----------------------------------------------------
+
+LodePNG uses unsigned char arrays for 16-bit per channel colors too, just like
+for any other color format. The 16-bit values are stored in big endian (most
+significant byte first) in these arrays. This is the opposite order of the
+little endian used by x86 CPU's.
+
+LodePNG always uses big endian because the PNG file format does so internally.
+Conversions to other formats than PNG uses internally are not supported by
+LodePNG on purpose, there are myriads of formats, including endianness of 16-bit
+colors, the order in which you store R, G, B and A, and so on. Supporting and
+converting to/from all that is outside the scope of LodePNG.
+
+This may mean that, depending on your use case, you may want to convert the big
+endian output of LodePNG to little endian with a for loop. This is certainly not
+always needed, many applications and libraries support big endian 16-bit colors
+anyway, but it means you cannot simply cast the unsigned char* buffer to an
+unsigned short* buffer on x86 CPUs.
+
+
+7. error values
+---------------
+
+All functions in LodePNG that return an error code, return 0 if everything went
+OK, or a non-zero code if there was an error.
+
+The meaning of the LodePNG error values can be retrieved with the function
+lodepng_error_text: given the numerical error code, it returns a description
+of the error in English as a string.
+
+Check the implementation of lodepng_error_text to see the meaning of each code.
+
+
+8. chunks and PNG editing
+-------------------------
+
+If you want to add extra chunks to a PNG you encode, or use LodePNG for a PNG
+editor that should follow the rules about handling of unknown chunks, or if your
+program is able to read other types of chunks than the ones handled by LodePNG,
+then that's possible with the chunk functions of LodePNG.
+
+A PNG chunk has the following layout:
+
+4 bytes length
+4 bytes type name
+length bytes data
+4 bytes CRC
+
+8.1. iterating through chunks
+-----------------------------
+
+If you have a buffer containing the PNG image data, then the first chunk (the
+IHDR chunk) starts at byte number 8 of that buffer. The first 8 bytes are the
+signature of the PNG and are not part of a chunk. But if you start at byte 8
+then you have a chunk, and can check the following things of it.
+
+NOTE: none of these functions check for memory buffer boundaries. To avoid
+exploits, always make sure the buffer contains all the data of the chunks.
+When using lodepng_chunk_next, make sure the returned value is within the
+allocated memory.
+
+unsigned lodepng_chunk_length(const unsigned char* chunk):
+
+Get the length of the chunk's data. The total chunk length is this length + 12.
+
+void lodepng_chunk_type(char type[5], const unsigned char* chunk):
+unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type):
+
+Get the type of the chunk or compare if it's a certain type
+
+unsigned char lodepng_chunk_critical(const unsigned char* chunk):
+unsigned char lodepng_chunk_private(const unsigned char* chunk):
+unsigned char lodepng_chunk_safetocopy(const unsigned char* chunk):
+
+Check if the chunk is critical in the PNG standard (only IHDR, PLTE, IDAT and IEND are).
+Check if the chunk is private (public chunks are part of the standard, private ones not).
+Check if the chunk is safe to copy. If it's not, then, when modifying data in a critical
+chunk, unsafe to copy chunks of the old image may NOT be saved in the new one if your
+program doesn't handle that type of unknown chunk.
+
+unsigned char* lodepng_chunk_data(unsigned char* chunk):
+const unsigned char* lodepng_chunk_data_const(const unsigned char* chunk):
+
+Get a pointer to the start of the data of the chunk.
+
+unsigned lodepng_chunk_check_crc(const unsigned char* chunk):
+void lodepng_chunk_generate_crc(unsigned char* chunk):
+
+Check if the crc is correct or generate a correct one.
+
+unsigned char* lodepng_chunk_next(unsigned char* chunk):
+const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk):
+
+Iterate to the next chunk. This works if you have a buffer with consecutive chunks. Note that these
+functions do no boundary checking of the allocated data whatsoever, so make sure there is enough
+data available in the buffer to be able to go to the next chunk.
+
+unsigned lodepng_chunk_append(unsigned char** out, size_t* outlength, const unsigned char* chunk):
+unsigned lodepng_chunk_create(unsigned char** out, size_t* outlength, unsigned length,
+                              const char* type, const unsigned char* data):
+
+These functions are used to create new chunks that are appended to the data in *out that has
+length *outlength. The append function appends an existing chunk to the new data. The create
+function creates a new chunk with the given parameters and appends it. Type is the 4-letter
+name of the chunk.
+
+8.2. chunks in info_png
+-----------------------
+
+The LodePNGInfo struct contains fields with the unknown chunk in it. It has 3
+buffers (each with size) to contain 3 types of unknown chunks:
+the ones that come before the PLTE chunk, the ones that come between the PLTE
+and the IDAT chunks, and the ones that come after the IDAT chunks.
+It's necessary to make the distionction between these 3 cases because the PNG
+standard forces to keep the ordering of unknown chunks compared to the critical
+chunks, but does not force any other ordering rules.
+
+info_png.unknown_chunks_data[0] is the chunks before PLTE
+info_png.unknown_chunks_data[1] is the chunks after PLTE, before IDAT
+info_png.unknown_chunks_data[2] is the chunks after IDAT
+
+The chunks in these 3 buffers can be iterated through and read by using the same
+way described in the previous subchapter.
+
+When using the decoder to decode a PNG, you can make it store all unknown chunks
+if you set the option settings.remember_unknown_chunks to 1. By default, this
+option is off (0).
+
+The encoder will always encode unknown chunks that are stored in the info_png.
+If you need it to add a particular chunk that isn't known by LodePNG, you can
+use lodepng_chunk_append or lodepng_chunk_create to the chunk data in
+info_png.unknown_chunks_data[x].
+
+Chunks that are known by LodePNG should not be added in that way. E.g. to make
+LodePNG add a bKGD chunk, set background_defined to true and add the correct
+parameters there instead.
+
+
+9. compiler support
+-------------------
+
+No libraries other than the current standard C library are needed to compile
+LodePNG. For the C++ version, only the standard C++ library is needed on top.
+Add the files lodepng.c(pp) and lodepng.h to your project, include
+lodepng.h where needed, and your program can read/write PNG files.
+
+It is compatible with C90 and up, and C++03 and up.
+
+If performance is important, use optimization when compiling! For both the
+encoder and decoder, this makes a large difference.
+
+Make sure that LodePNG is compiled with the same compiler of the same version
+and with the same settings as the rest of the program, or the interfaces with
+std::vectors and std::strings in C++ can be incompatible.
+
+CHAR_BITS must be 8 or higher, because LodePNG uses unsigned chars for octets.
+
+*) gcc and g++
+
+LodePNG is developed in gcc so this compiler is natively supported. It gives no
+warnings with compiler options "-Wall -Wextra -pedantic -ansi", with gcc and g++
+version 4.7.1 on Linux, 32-bit and 64-bit.
+
+*) Clang
+
+Fully supported and warning-free.
+
+*) Mingw
+
+The Mingw compiler (a port of gcc for Windows) should be fully supported by
+LodePNG.
+
+*) Visual Studio and Visual C++ Express Edition
+
+LodePNG should be warning-free with warning level W4. Two warnings were disabled
+with pragmas though: warning 4244 about implicit conversions, and warning 4996
+where it wants to use a non-standard function fopen_s instead of the standard C
+fopen.
+
+Visual Studio may want "stdafx.h" files to be included in each source file and
+give an error "unexpected end of file while looking for precompiled header".
+This is not standard C++ and will not be added to the stock LodePNG. You can
+disable it for lodepng.cpp only by right clicking it, Properties, C/C++,
+Precompiled Headers, and set it to Not Using Precompiled Headers there.
+
+NOTE: Modern versions of VS should be fully supported, but old versions, e.g.
+VS6, are not guaranteed to work.
+
+*) Compilers on Macintosh
+
+LodePNG has been reported to work both with gcc and LLVM for Macintosh, both for
+C and C++.
+
+*) Other Compilers
+
+If you encounter problems on any compilers, feel free to let me know and I may
+try to fix it if the compiler is modern and standards complient.
+
+
+10. examples
+------------
+
+This decoder example shows the most basic usage of LodePNG. More complex
+examples can be found on the LodePNG website.
+
+10.1. decoder C++ example
+-------------------------
+
+#include "lodepng.h"
+#include <iostream>
+
+int main(int argc, char *argv[])
+{
+  const char* filename = argc > 1 ? argv[1] : "test.png";
+
+  //load and decode
+  std::vector<unsigned char> image;
+  unsigned width, height;
+  unsigned error = lodepng::decode(image, width, height, filename);
+
+  //if there's an error, display it
+  if(error) std::cout << "decoder error " << error << ": " << lodepng_error_text(error) << std::endl;
+
+  //the pixels are now in the vector "image", 4 bytes per pixel, ordered RGBARGBA..., use it as texture, draw it, ...
+}
+
+10.2. decoder C example
+-----------------------
+
+#include "lodepng.h"
+
+int main(int argc, char *argv[])
+{
+  unsigned error;
+  unsigned char* image;
+  size_t width, height;
+  const char* filename = argc > 1 ? argv[1] : "test.png";
+
+  error = lodepng_decode32_file(&image, &width, &height, filename);
+
+  if(error) printf("decoder error %u: %s\n", error, lodepng_error_text(error));
+
+  / * use image here * /
+
+  free(image);
+  return 0;
+}
+
+
+11. changes
+-----------
+
+The version number of LodePNG is the date of the change given in the format
+yyyymmdd.
+
+Some changes aren't backwards compatible. Those are indicated with a (!)
+symbol.
+
+*) 24 okt 2015: Bugfix with decoding to palette output.
+*) 18 apr 2015: Boundary PM instead of just package-merge for faster encoding.
+*) 23 aug 2014: Reduced needless memory usage of decoder.
+*) 28 jun 2014: Removed fix_png setting, always support palette OOB for
+    simplicity. Made ColorProfile public.
+*) 09 jun 2014: Faster encoder by fixing hash bug and more zeros optimization.
+*) 22 dec 2013: Power of two windowsize required for optimization.
+*) 15 apr 2013: Fixed bug with LAC_ALPHA and color key.
+*) 25 mar 2013: Added an optional feature to ignore some PNG errors (fix_png).
+*) 11 mar 2013 (!): Bugfix with custom free. Changed from "my" to "lodepng_"
+    prefix for the custom allocators and made it possible with a new #define to
+    use custom ones in your project without needing to change lodepng's code.
+*) 28 jan 2013: Bugfix with color key.
+*) 27 okt 2012: Tweaks in text chunk keyword length error handling.
+*) 8 okt 2012 (!): Added new filter strategy (entropy) and new auto color mode.
+    (no palette). Better deflate tree encoding. New compression tweak settings.
+    Faster color conversions while decoding. Some internal cleanups.
+*) 23 sep 2012: Reduced warnings in Visual Studio a little bit.
+*) 1 sep 2012 (!): Removed #define's for giving custom (de)compression functions
+    and made it work with function pointers instead.
+*) 23 jun 2012: Added more filter strategies. Made it easier to use custom alloc
+    and free functions and toggle #defines from compiler flags. Small fixes.
+*) 6 may 2012 (!): Made plugging in custom zlib/deflate functions more flexible.
+*) 22 apr 2012 (!): Made interface more consistent, renaming a lot. Removed
+    redundant C++ codec classes. Reduced amount of structs. Everything changed,
+    but it is cleaner now imho and functionality remains the same. Also fixed
+    several bugs and shrunk the implementation code. Made new samples.
+*) 6 nov 2011 (!): By default, the encoder now automatically chooses the best
+    PNG color model and bit depth, based on the amount and type of colors of the
+    raw image. For this, autoLeaveOutAlphaChannel replaced by auto_choose_color.
+*) 9 okt 2011: simpler hash chain implementation for the encoder.
+*) 8 sep 2011: lz77 encoder lazy matching instead of greedy matching.
+*) 23 aug 2011: tweaked the zlib compression parameters after benchmarking.
+    A bug with the PNG filtertype heuristic was fixed, so that it chooses much
+    better ones (it's quite significant). A setting to do an experimental, slow,
+    brute force search for PNG filter types is added.
+*) 17 aug 2011 (!): changed some C zlib related function names.
+*) 16 aug 2011: made the code less wide (max 120 characters per line).
+*) 17 apr 2011: code cleanup. Bugfixes. Convert low to 16-bit per sample colors.
+*) 21 feb 2011: fixed compiling for C90. Fixed compiling with sections disabled.
+*) 11 dec 2010: encoding is made faster, based on suggestion by Peter Eastman
+    to optimize long sequences of zeros.
+*) 13 nov 2010: added LodePNG_InfoColor_hasPaletteAlpha and
+    LodePNG_InfoColor_canHaveAlpha functions for convenience.
+*) 7 nov 2010: added LodePNG_error_text function to get error code description.
+*) 30 okt 2010: made decoding slightly faster
+*) 26 okt 2010: (!) changed some C function and struct names (more consistent).
+     Reorganized the documentation and the declaration order in the header.
+*) 08 aug 2010: only changed some comments and external samples.
+*) 05 jul 2010: fixed bug thanks to warnings in the new gcc version.
+*) 14 mar 2010: fixed bug where too much memory was allocated for char buffers.
+*) 02 sep 2008: fixed bug where it could create empty tree that linux apps could
+    read by ignoring the problem but windows apps couldn't.
+*) 06 jun 2008: added more error checks for out of memory cases.
+*) 26 apr 2008: added a few more checks here and there to ensure more safety.
+*) 06 mar 2008: crash with encoding of strings fixed
+*) 02 feb 2008: support for international text chunks added (iTXt)
+*) 23 jan 2008: small cleanups, and #defines to divide code in sections
+*) 20 jan 2008: support for unknown chunks allowing using LodePNG for an editor.
+*) 18 jan 2008: support for tIME and pHYs chunks added to encoder and decoder.
+*) 17 jan 2008: ability to encode and decode compressed zTXt chunks added
+    Also various fixes, such as in the deflate and the padding bits code.
+*) 13 jan 2008: Added ability to encode Adam7-interlaced images. Improved
+    filtering code of encoder.
+*) 07 jan 2008: (!) changed LodePNG to use ISO C90 instead of C++. A
+    C++ wrapper around this provides an interface almost identical to before.
+    Having LodePNG be pure ISO C90 makes it more portable. The C and C++ code
+    are together in these files but it works both for C and C++ compilers.
+*) 29 dec 2007: (!) changed most integer types to unsigned int + other tweaks
+*) 30 aug 2007: bug fixed which makes this Borland C++ compatible
+*) 09 aug 2007: some VS2005 warnings removed again
+*) 21 jul 2007: deflate code placed in new namespace separate from zlib code
+*) 08 jun 2007: fixed bug with 2- and 4-bit color, and small interlaced images
+*) 04 jun 2007: improved support for Visual Studio 2005: crash with accessing
+    invalid std::vector element [0] fixed, and level 3 and 4 warnings removed
+*) 02 jun 2007: made the encoder add a tag with version by default
+*) 27 may 2007: zlib and png code separated (but still in the same file),
+    simple encoder/decoder functions added for more simple usage cases
+*) 19 may 2007: minor fixes, some code cleaning, new error added (error 69),
+    moved some examples from here to lodepng_examples.cpp
+*) 12 may 2007: palette decoding bug fixed
+*) 24 apr 2007: changed the license from BSD to the zlib license
+*) 11 mar 2007: very simple addition: ability to encode bKGD chunks.
+*) 04 mar 2007: (!) tEXt chunk related fixes, and support for encoding
+    palettized PNG images. Plus little interface change with palette and texts.
+*) 03 mar 2007: Made it encode dynamic Huffman shorter with repeat codes.
+    Fixed a bug where the end code of a block had length 0 in the Huffman tree.
+*) 26 feb 2007: Huffman compression with dynamic trees (BTYPE 2) now implemented
+    and supported by the encoder, resulting in smaller PNGs at the output.
+*) 27 jan 2007: Made the Adler-32 test faster so that a timewaste is gone.
+*) 24 jan 2007: gave encoder an error interface. Added color conversion from any
+    greyscale type to 8-bit greyscale with or without alpha.
+*) 21 jan 2007: (!) Totally changed the interface. It allows more color types
+    to convert to and is more uniform. See the manual for how it works now.
+*) 07 jan 2007: Some cleanup & fixes, and a few changes over the last days:
+    encode/decode custom tEXt chunks, separate classes for zlib & deflate, and
+    at last made the decoder give errors for incorrect Adler32 or Crc.
+*) 01 jan 2007: Fixed bug with encoding PNGs with less than 8 bits per channel.
+*) 29 dec 2006: Added support for encoding images without alpha channel, and
+    cleaned out code as well as making certain parts faster.
+*) 28 dec 2006: Added "Settings" to the encoder.
+*) 26 dec 2006: The encoder now does LZ77 encoding and produces much smaller files now.
+    Removed some code duplication in the decoder. Fixed little bug in an example.
+*) 09 dec 2006: (!) Placed output parameters of public functions as first parameter.
+    Fixed a bug of the decoder with 16-bit per color.
+*) 15 okt 2006: Changed documentation structure
+*) 09 okt 2006: Encoder class added. It encodes a valid PNG image from the
+    given image buffer, however for now it's not compressed.
+*) 08 sep 2006: (!) Changed to interface with a Decoder class
+*) 30 jul 2006: (!) LodePNG_InfoPng , width and height are now retrieved in different
+    way. Renamed decodePNG to decodePNGGeneric.
+*) 29 jul 2006: (!) Changed the interface: image info is now returned as a
+    struct of type LodePNG::LodePNG_Info, instead of a vector, which was a bit clumsy.
+*) 28 jul 2006: Cleaned the code and added new error checks.
+    Corrected terminology "deflate" into "inflate".
+*) 23 jun 2006: Added SDL example in the documentation in the header, this
+    example allows easy debugging by displaying the PNG and its transparency.
+*) 22 jun 2006: (!) Changed way to obtain error value. Added
+    loadFile function for convenience. Made decodePNG32 faster.
+*) 21 jun 2006: (!) Changed type of info vector to unsigned.
+    Changed position of palette in info vector. Fixed an important bug that
+    happened on PNGs with an uncompressed block.
+*) 16 jun 2006: Internally changed unsigned into unsigned where
+    needed, and performed some optimizations.
+*) 07 jun 2006: (!) Renamed functions to decodePNG and placed them
+    in LodePNG namespace. Changed the order of the parameters. Rewrote the
+    documentation in the header. Renamed files to lodepng.cpp and lodepng.h
+*) 22 apr 2006: Optimized and improved some code
+*) 07 sep 2005: (!) Changed to std::vector interface
+*) 12 aug 2005: Initial release (C++, decoder only)
+
+
+12. contact information
+-----------------------
+
+Feel free to contact me with suggestions, problems, comments, ... concerning
+LodePNG. If you encounter a PNG image that doesn't work properly with this
+decoder, feel free to send it and I'll use it to find and fix the problem.
+
+My email address is (puzzle the account and domain together with an @ symbol):
+Domain: gmail dot com.
+Account: lode dot vandevenne.
+
+
+Copyright (c) 2005-2015 Lode Vandevenne
+*/
diff --git a/libeg/lodepng_xtra.c b/libeg/lodepng_xtra.c
new file mode 100644 (file)
index 0000000..343fbff
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * Additional functions to support LodePNG for use in rEFInd
+ *
+ * copyright (c) 2013 by by Roderick W. Smith, and distributed
+ * under the terms of the GNU GPL v3, or (at your option) any
+ * later version.
+ *
+ * See http://lodev.org/lodepng/ for the original LodePNG.
+ *
+ */
+/*
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "global.h"
+#include "../refind/screen.h"
+#include "lodepng.h"
+
+// EFI's equivalent of realloc requires the original buffer's size as an
+// input parameter, which the standard libc realloc does not require. Thus,
+// I've modified lodepng_malloc() to allocate more memory to store this data,
+// and lodepng_realloc() can then read it when required. Because the size is
+// stored at the start of the allocated area, these functions are NOT
+// interchangeable with the standard EFI functions; memory allocated via
+// lodepng_malloc() should be freed via lodepng_free(), and myfree() should
+// NOT be used with memory allocated via AllocatePool() or AllocateZeroPool()!
+
+void* lodepng_malloc(size_t size) {
+   void *ptr;
+
+   ptr = AllocateZeroPool(size + sizeof(size_t));
+   if (ptr) {
+      *(size_t *) ptr = size;
+      return ((size_t *) ptr) + 1;
+   } else {
+      return NULL;
+   }
+} // void* lodepng_malloc()
+
+void lodepng_free (void *ptr) {
+   if (ptr) {
+      ptr = (void *) (((size_t *) ptr) - 1);
+      FreePool(ptr);
+   }
+} // void lodepng_free()
+
+static size_t report_size(void *ptr) {
+   if (ptr)
+      return * (((size_t *) ptr) - 1);
+   else
+      return 0;
+} // size_t report_size()
+
+void* lodepng_realloc(void *ptr, size_t new_size) {
+   size_t *new_pool;
+   size_t old_size;
+
+   new_pool = lodepng_malloc(new_size);
+   if (new_pool && ptr) {
+      old_size = report_size(ptr);
+      CopyMem(new_pool, ptr, (old_size < new_size) ? old_size : new_size);
+   }
+   return new_pool;
+} // lodepng_realloc()
+
+// Finds length of ASCII string, which MUST be NULL-terminated.
+int MyStrlen(const char *InString) {
+   int Length = 0;
+
+   if (InString) {
+      while (InString[Length] != '\0')
+         Length++;
+   }
+   return Length;
+} // int MyStrlen()
+
+typedef struct _lode_color {
+   UINT8 red;
+   UINT8 green;
+   UINT8 blue;
+   UINT8 alpha;
+} lode_color;
+
+EG_IMAGE * egDecodePNG(IN UINT8 *FileData, IN UINTN FileDataLength, IN UINTN IconSize, IN BOOLEAN WantAlpha) {
+   EG_IMAGE *NewImage = NULL;
+   unsigned Error, Width, Height;
+   EG_PIXEL *PixelData;
+   lode_color *LodeData;
+   UINTN i;
+
+   Error = lodepng_decode_memory((unsigned char **) &PixelData, &Width, &Height, (unsigned char*) FileData,
+                                 (size_t) FileDataLength, LCT_RGBA, 8);
+
+   if (Error) {
+      return NULL;
+   }
+
+   // allocate image structure and buffer
+   NewImage = egCreateImage(Width, Height, WantAlpha);
+   if ((NewImage == NULL) || (NewImage->Width != Width) || (NewImage->Height != Height))
+      return NULL;
+
+   LodeData = (lode_color *) PixelData;
+
+   // Annoyingly, EFI and LodePNG use different ordering of RGB values in
+   // their pixel data representations, so we've got to adjust them....
+   for (i = 0; i < (NewImage->Height * NewImage->Width); i++) {
+      NewImage->PixelData[i].r = LodeData[i].red;
+      NewImage->PixelData[i].g = LodeData[i].green;
+      NewImage->PixelData[i].b = LodeData[i].blue;
+      if (WantAlpha)
+         NewImage->PixelData[i].a = LodeData[i].alpha;
+   }
+   lodepng_free(PixelData);
+
+   return NewImage;
+} // EG_IMAGE * egDecodePNG()
diff --git a/libeg/screen.c b/libeg/screen.c
new file mode 100644 (file)
index 0000000..506355e
--- /dev/null
@@ -0,0 +1,539 @@
+/*
+ * libeg/screen.c
+ * Screen handling functions
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Modifications copyright (c) 2012-2014 Roderick W. Smith
+ *
+ * Modifications distributed under the terms of the GNU General Public
+ * License (GPL) version 3 (GPLv3), or (at your option) any later version.
+ *
+ */
+/*
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "libegint.h"
+#include "../refind/screen.h"
+#include "../refind/lib.h"
+#include "../refind/mystrings.h"
+#include "../include/refit_call_wrapper.h"
+#include "libeg.h"
+#include "../include/Handle.h"
+
+#include <efiUgaDraw.h>
+#include <efiConsoleControl.h>
+
+#ifndef __MAKEWITH_GNUEFI
+#define LibLocateProtocol EfiLibLocateProtocol
+#endif
+
+// Console defines and variables
+
+static EFI_GUID ConsoleControlProtocolGuid = EFI_CONSOLE_CONTROL_PROTOCOL_GUID;
+static EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL;
+
+static EFI_GUID UgaDrawProtocolGuid = EFI_UGA_DRAW_PROTOCOL_GUID;
+static EFI_UGA_DRAW_PROTOCOL *UgaDraw = NULL;
+
+static EFI_GUID GraphicsOutputProtocolGuid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
+static EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput = NULL;
+
+static BOOLEAN egHasGraphics = FALSE;
+static UINTN egScreenWidth  = 800;
+static UINTN egScreenHeight = 600;
+
+//
+// Screen handling
+//
+
+// Make the necessary system calls to identify the current graphics mode.
+// Stores the results in the file-global variables egScreenWidth,
+// egScreenHeight, and egHasGraphics. The first two of these will be
+// unchanged if neither GraphicsOutput nor UgaDraw is a valid pointer.
+static VOID egDetermineScreenSize(VOID) {
+    EFI_STATUS Status = EFI_SUCCESS;
+    UINT32 UGAWidth, UGAHeight, UGADepth, UGARefreshRate;
+
+    // get screen size
+    egHasGraphics = FALSE;
+    if (GraphicsOutput != NULL) {
+        egScreenWidth = GraphicsOutput->Mode->Info->HorizontalResolution;
+        egScreenHeight = GraphicsOutput->Mode->Info->VerticalResolution;
+        egHasGraphics = TRUE;
+    } else if (UgaDraw != NULL) {
+        Status = refit_call5_wrapper(UgaDraw->GetMode, UgaDraw, &UGAWidth, &UGAHeight, &UGADepth, &UGARefreshRate);
+        if (EFI_ERROR(Status)) {
+            UgaDraw = NULL;   // graphics not available
+        } else {
+            egScreenWidth  = UGAWidth;
+            egScreenHeight = UGAHeight;
+            egHasGraphics = TRUE;
+        }
+    }
+} // static VOID egDetermineScreenSize()
+
+VOID egGetScreenSize(OUT UINTN *ScreenWidth, OUT UINTN *ScreenHeight)
+{
+    egDetermineScreenSize();
+
+    if (ScreenWidth != NULL)
+        *ScreenWidth = egScreenWidth;
+    if (ScreenHeight != NULL)
+        *ScreenHeight = egScreenHeight;
+}
+
+VOID egInitScreen(VOID)
+{
+    EFI_STATUS Status = EFI_SUCCESS;
+
+    // get protocols
+    Status = LibLocateProtocol(&ConsoleControlProtocolGuid, (VOID **) &ConsoleControl);
+    if (EFI_ERROR(Status))
+        ConsoleControl = NULL;
+
+    Status = LibLocateProtocol(&UgaDrawProtocolGuid, (VOID **) &UgaDraw);
+    if (EFI_ERROR(Status))
+        UgaDraw = NULL;
+
+    Status = LibLocateProtocol(&GraphicsOutputProtocolGuid, (VOID **) &GraphicsOutput);
+    if (EFI_ERROR(Status))
+        GraphicsOutput = NULL;
+
+    egDetermineScreenSize();
+}
+
+// Convert a graphics mode (in *ModeWidth) to a width and height (returned in
+// *ModeWidth and *Height, respectively).
+// Returns TRUE if successful, FALSE if not (invalid mode, typically)
+BOOLEAN egGetResFromMode(UINTN *ModeWidth, UINTN *Height) {
+   UINTN                                 Size;
+   EFI_STATUS                            Status;
+   EFI_GRAPHICS_OUTPUT_MODE_INFORMATION  *Info = NULL;
+
+   if ((ModeWidth != NULL) && (Height != NULL)) {
+      Status = refit_call4_wrapper(GraphicsOutput->QueryMode, GraphicsOutput, *ModeWidth, &Size, &Info);
+      if ((Status == EFI_SUCCESS) && (Info != NULL)) {
+         *ModeWidth = Info->HorizontalResolution;
+         *Height = Info->VerticalResolution;
+         return TRUE;
+      }
+   }
+   return FALSE;
+} // BOOLEAN egGetResFromMode()
+
+// Sets the screen resolution to the specified value, if possible. If *ScreenHeight
+// is 0 and GOP mode is detected, assume that *ScreenWidth contains a GOP mode
+// number rather than a horizontal resolution. If the specified resolution is not
+// valid, displays a warning with the valid modes on GOP (UEFI) systems, or silently
+// fails on UGA (EFI 1.x) systems. Note that this function attempts to set ANY screen
+// resolution, even 0x0 or ridiculously large values.
+// Upon success, returns actual screen resolution in *ScreenWidth and *ScreenHeight.
+// These values are unchanged upon failure.
+// Returns TRUE if successful, FALSE if not.
+BOOLEAN egSetScreenSize(IN OUT UINTN *ScreenWidth, IN OUT UINTN *ScreenHeight) {
+   EFI_STATUS                            Status = EFI_SUCCESS;
+   EFI_GRAPHICS_OUTPUT_MODE_INFORMATION  *Info;
+   UINTN                                 Size;
+   UINT32                                ModeNum = 0;
+   UINT32                                UGAWidth, UGAHeight, UGADepth, UGARefreshRate;
+   BOOLEAN                               ModeSet = FALSE;
+
+   if ((ScreenWidth == NULL) || (ScreenHeight == NULL))
+      return FALSE;
+
+   if (GraphicsOutput != NULL) { // GOP mode (UEFI)
+      if (*ScreenHeight == 0) { // User specified a mode number (stored in *ScreenWidth); use it directly
+         ModeNum = (UINT32) *ScreenWidth;
+         if (egGetResFromMode(ScreenWidth, ScreenHeight) &&
+             (refit_call2_wrapper(GraphicsOutput->SetMode, GraphicsOutput, ModeNum) == EFI_SUCCESS)) {
+            ModeSet = TRUE;
+         }
+
+      // User specified width & height; must find mode...
+      } else {
+         // Do a loop through the modes to see if the specified one is available;
+         // and if so, switch to it....
+         do {
+            Status = refit_call4_wrapper(GraphicsOutput->QueryMode, GraphicsOutput, ModeNum, &Size, &Info);
+            if ((Status == EFI_SUCCESS) && (Size >= sizeof(*Info) && (Info != NULL)) &&
+                (Info->HorizontalResolution == *ScreenWidth) && (Info->VerticalResolution == *ScreenHeight)) {
+               Status = refit_call2_wrapper(GraphicsOutput->SetMode, GraphicsOutput, ModeNum);
+               ModeSet = (Status == EFI_SUCCESS);
+            } // if
+         } while ((++ModeNum < GraphicsOutput->Mode->MaxMode) && !ModeSet);
+      } // if/else
+
+      if (ModeSet) {
+         egScreenWidth = *ScreenWidth;
+         egScreenHeight = *ScreenHeight;
+      } else {// If unsuccessful, display an error message for the user....
+         SwitchToText(FALSE);
+         Print(L"Error setting graphics mode %d x %d; using default mode!\nAvailable modes are:\n", *ScreenWidth, *ScreenHeight);
+         ModeNum = 0;
+         do {
+            Status = refit_call4_wrapper(GraphicsOutput->QueryMode, GraphicsOutput, ModeNum, &Size, &Info);
+            if ((Status == EFI_SUCCESS) && (Info != NULL)) {
+               Print(L"Mode %d: %d x %d\n", ModeNum, Info->HorizontalResolution, Info->VerticalResolution);
+            } // else
+         } while (++ModeNum < GraphicsOutput->Mode->MaxMode);
+         PauseForKey();
+         SwitchToGraphics();
+      } // if GOP mode (UEFI)
+
+   } else if (UgaDraw != NULL) { // UGA mode (EFI 1.x)
+      // Try to use current color depth & refresh rate for new mode. Maybe not the best choice
+      // in all cases, but I don't know how to probe for alternatives....
+      Status = refit_call5_wrapper(UgaDraw->GetMode, UgaDraw, &UGAWidth, &UGAHeight, &UGADepth, &UGARefreshRate);
+      Status = refit_call5_wrapper(UgaDraw->SetMode, UgaDraw, *ScreenWidth, *ScreenHeight, UGADepth, UGARefreshRate);
+      if (Status == EFI_SUCCESS) {
+         egScreenWidth = *ScreenWidth;
+         egScreenHeight = *ScreenHeight;
+         ModeSet = TRUE;
+      } else {
+         // TODO: Find a list of supported modes and display it.
+         // NOTE: Below doesn't actually appear unless we explicitly switch to text mode.
+         // This is just a placeholder until something better can be done....
+         Print(L"Error setting graphics mode %d x %d; unsupported mode!\n");
+      } // if/else
+   } // if/else if UGA mode (EFI 1.x)
+   return (ModeSet);
+} // BOOLEAN egSetScreenSize()
+
+// Set a text mode.
+// Returns TRUE if the mode actually changed, FALSE otherwise.
+// Note that a FALSE return value can mean either an error or no change
+// necessary.
+BOOLEAN egSetTextMode(UINT32 RequestedMode) {
+   UINTN         i = 0, Width, Height;
+   EFI_STATUS    Status;
+   BOOLEAN       ChangedIt = FALSE;
+
+   if ((RequestedMode != DONT_CHANGE_TEXT_MODE) && (RequestedMode != ST->ConOut->Mode->Mode)) {
+      Status = refit_call2_wrapper(ST->ConOut->SetMode, ST->ConOut, RequestedMode);
+      if (Status == EFI_SUCCESS) {
+         ChangedIt = TRUE;
+      } else {
+         SwitchToText(FALSE);
+         Print(L"\nError setting text mode %d; available modes are:\n", RequestedMode);
+         do {
+            Status = refit_call4_wrapper(ST->ConOut->QueryMode, ST->ConOut, i, &Width, &Height);
+            if (Status == EFI_SUCCESS)
+               Print(L"Mode %d: %d x %d\n", i, Width, Height);
+         } while (++i < ST->ConOut->Mode->MaxMode);
+         Print(L"Mode %d: Use default mode\n", DONT_CHANGE_TEXT_MODE);
+
+         PauseForKey();
+         SwitchToGraphics();
+      } // if/else successful change
+   } // if need to change mode
+   return ChangedIt;
+} // BOOLEAN egSetTextMode()
+
+CHAR16 * egScreenDescription(VOID)
+{
+    CHAR16 *GraphicsInfo, *TextInfo = NULL;
+
+    GraphicsInfo = AllocateZeroPool(256 * sizeof(CHAR16));
+    if (GraphicsInfo == NULL)
+       return L"memory allocation error";
+
+    if (egHasGraphics) {
+        if (GraphicsOutput != NULL) {
+            SPrint(GraphicsInfo, 255, L"Graphics Output (UEFI), %dx%d", egScreenWidth, egScreenHeight);
+        } else if (UgaDraw != NULL) {
+            GraphicsInfo = AllocateZeroPool(256 * sizeof(CHAR16));
+            SPrint(GraphicsInfo, 255, L"UGA Draw (EFI 1.10), %dx%d", egScreenWidth, egScreenHeight);
+        } else {
+            MyFreePool(GraphicsInfo);
+            MyFreePool(TextInfo);
+            return L"Internal Error";
+        }
+        if (!AllowGraphicsMode) { // graphics-capable HW, but in text mode
+           TextInfo = AllocateZeroPool(256 * sizeof(CHAR16));
+           SPrint(TextInfo, 255, L"(in %dx%d text mode)", ConWidth, ConHeight);
+           MergeStrings(&GraphicsInfo, TextInfo, L' ');
+        }
+    } else {
+        SPrint(GraphicsInfo, 255, L"Text-foo console, %dx%d", ConWidth, ConHeight);
+    }
+    MyFreePool(TextInfo);
+    return GraphicsInfo;
+}
+
+BOOLEAN egHasGraphicsMode(VOID)
+{
+    return egHasGraphics;
+}
+
+BOOLEAN egIsGraphicsModeEnabled(VOID)
+{
+    EFI_CONSOLE_CONTROL_SCREEN_MODE CurrentMode;
+
+    if (ConsoleControl != NULL) {
+        refit_call4_wrapper(ConsoleControl->GetMode, ConsoleControl, &CurrentMode, NULL, NULL);
+        return (CurrentMode == EfiConsoleControlScreenGraphics) ? TRUE : FALSE;
+    }
+
+    return FALSE;
+}
+
+VOID egSetGraphicsModeEnabled(IN BOOLEAN Enable)
+{
+    EFI_CONSOLE_CONTROL_SCREEN_MODE CurrentMode;
+    EFI_CONSOLE_CONTROL_SCREEN_MODE NewMode;
+
+    if (ConsoleControl != NULL) {
+        refit_call4_wrapper(ConsoleControl->GetMode, ConsoleControl, &CurrentMode, NULL, NULL);
+
+        NewMode = Enable ? EfiConsoleControlScreenGraphics
+                         : EfiConsoleControlScreenText;
+        if (CurrentMode != NewMode)
+           refit_call2_wrapper(ConsoleControl->SetMode, ConsoleControl, NewMode);
+    }
+}
+
+//
+// Drawing to the screen
+//
+
+VOID egClearScreen(IN EG_PIXEL *Color)
+{
+    EFI_UGA_PIXEL FillColor;
+
+    if (!egHasGraphics)
+        return;
+
+    if (Color != NULL) {
+       FillColor.Red   = Color->r;
+       FillColor.Green = Color->g;
+       FillColor.Blue  = Color->b;
+    } else {
+       FillColor.Red   = 0x0;
+       FillColor.Green = 0x0;
+       FillColor.Blue  = 0x0;
+    }
+    FillColor.Reserved = 0;
+
+    if (GraphicsOutput != NULL) {
+        // EFI_GRAPHICS_OUTPUT_BLT_PIXEL and EFI_UGA_PIXEL have the same
+        // layout, and the header from TianoCore actually defines them
+        // to be the same type.
+        refit_call10_wrapper(GraphicsOutput->Blt, GraphicsOutput, (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)&FillColor, EfiBltVideoFill,
+                             0, 0, 0, 0, egScreenWidth, egScreenHeight, 0);
+    } else if (UgaDraw != NULL) {
+        refit_call10_wrapper(UgaDraw->Blt, UgaDraw, &FillColor, EfiUgaVideoFill, 0, 0, 0, 0, egScreenWidth, egScreenHeight, 0);
+    }
+}
+
+VOID egDrawImage(IN EG_IMAGE *Image, IN UINTN ScreenPosX, IN UINTN ScreenPosY)
+{
+    EG_IMAGE *CompImage = NULL;
+
+    // NOTE: Weird seemingly redundant tests because some placement code can "wrap around" and
+    // send "negative" values, which of course become very large unsigned ints that can then
+    // wrap around AGAIN if values are added to them.....
+    if (!egHasGraphics || ((ScreenPosX + Image->Width) > egScreenWidth) || ((ScreenPosY + Image->Height) > egScreenHeight) ||
+        (ScreenPosX > egScreenWidth) || (ScreenPosY > egScreenHeight))
+        return;
+
+    if ((GlobalConfig.ScreenBackground == NULL) || ((Image->Width == egScreenWidth) && (Image->Height == egScreenHeight))) {
+       CompImage = Image;
+    } else if (GlobalConfig.ScreenBackground == Image) {
+       CompImage = GlobalConfig.ScreenBackground;
+    } else {
+       CompImage = egCropImage(GlobalConfig.ScreenBackground, ScreenPosX, ScreenPosY, Image->Width, Image->Height);
+       if (CompImage == NULL) {
+          Print(L"Error! Can't crop image in egDrawImage()!\n");
+          return;
+       }
+       egComposeImage(CompImage, Image, 0, 0);
+    }
+
+    if (GraphicsOutput != NULL) {
+       refit_call10_wrapper(GraphicsOutput->Blt, GraphicsOutput, (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)CompImage->PixelData,
+                            EfiBltBufferToVideo, 0, 0, ScreenPosX, ScreenPosY, CompImage->Width, CompImage->Height, 0);
+    } else if (UgaDraw != NULL) {
+       refit_call10_wrapper(UgaDraw->Blt, UgaDraw, (EFI_UGA_PIXEL *)CompImage->PixelData, EfiUgaBltBufferToVideo,
+                            0, 0, ScreenPosX, ScreenPosY, CompImage->Width, CompImage->Height, 0);
+    }
+    if ((CompImage != GlobalConfig.ScreenBackground) && (CompImage != Image))
+       egFreeImage(CompImage);
+} /* VOID egDrawImage() */
+
+// Display an unselected icon on the screen, so that the background image shows
+// through the transparency areas. The BadgeImage may be NULL, in which case
+// it's not composited in.
+VOID egDrawImageWithTransparency(EG_IMAGE *Image, EG_IMAGE *BadgeImage, UINTN XPos, UINTN YPos, UINTN Width, UINTN Height) {
+   EG_IMAGE *Background;
+
+   Background = egCropImage(GlobalConfig.ScreenBackground, XPos, YPos, Width, Height);
+   if (Background != NULL) {
+      BltImageCompositeBadge(Background, Image, BadgeImage, XPos, YPos);
+      egFreeImage(Background);
+   }
+} // VOID DrawImageWithTransparency()
+
+VOID egDrawImageArea(IN EG_IMAGE *Image,
+                     IN UINTN AreaPosX, IN UINTN AreaPosY,
+                     IN UINTN AreaWidth, IN UINTN AreaHeight,
+                     IN UINTN ScreenPosX, IN UINTN ScreenPosY)
+{
+    if (!egHasGraphics)
+        return;
+
+    egRestrictImageArea(Image, AreaPosX, AreaPosY, &AreaWidth, &AreaHeight);
+    if (AreaWidth == 0)
+        return;
+
+    if (GraphicsOutput != NULL) {
+        refit_call10_wrapper(GraphicsOutput->Blt, GraphicsOutput, (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)Image->PixelData,
+                             EfiBltBufferToVideo, AreaPosX, AreaPosY, ScreenPosX, ScreenPosY, AreaWidth, AreaHeight,
+                             Image->Width * 4);
+    } else if (UgaDraw != NULL) {
+        refit_call10_wrapper(UgaDraw->Blt, UgaDraw, (EFI_UGA_PIXEL *)Image->PixelData, EfiUgaBltBufferToVideo,
+                             AreaPosX, AreaPosY, ScreenPosX, ScreenPosY, AreaWidth, AreaHeight, Image->Width * 4);
+    }
+}
+
+// Display a message in the center of the screen, surrounded by a box of the
+// specified color. For the moment, uses graphics calls only. (It still works
+// in text mode on GOP/UEFI systems, but not on UGA/EFI 1.x systems.)
+VOID egDisplayMessage(IN CHAR16 *Text, EG_PIXEL *BGColor) {
+   UINTN BoxWidth, BoxHeight;
+   EG_IMAGE *Box;
+
+   if ((Text != NULL) && (BGColor != NULL)) {
+      egMeasureText(Text, &BoxWidth, &BoxHeight);
+      BoxWidth += 14;
+      BoxHeight *= 2;
+      if (BoxWidth > egScreenWidth)
+         BoxWidth = egScreenWidth;
+      Box = egCreateFilledImage(BoxWidth, BoxHeight, FALSE, BGColor);
+      egRenderText(Text, Box, 7, BoxHeight / 4, (BGColor->r + BGColor->g + BGColor->b) / 3);
+      egDrawImage(Box, (egScreenWidth - BoxWidth) / 2, (egScreenHeight - BoxHeight) / 2);
+   } // if non-NULL inputs
+} // VOID egDisplayMessage()
+
+// Copy the current contents of the display into an EG_IMAGE....
+// Returns pointer if successful, NULL if not.
+EG_IMAGE * egCopyScreen(VOID) {
+   EG_IMAGE *Image = NULL;
+
+   if (!egHasGraphics)
+      return NULL;
+
+   // allocate a buffer for the whole screen
+   Image = egCreateImage(egScreenWidth, egScreenHeight, FALSE);
+   if (Image == NULL) {
+      return NULL;
+   }
+
+   // get full screen image
+   if (GraphicsOutput != NULL) {
+      refit_call10_wrapper(GraphicsOutput->Blt, GraphicsOutput, (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)Image->PixelData,
+                           EfiBltVideoToBltBuffer, 0, 0, 0, 0, Image->Width, Image->Height, 0);
+   } else if (UgaDraw != NULL) {
+      refit_call10_wrapper(UgaDraw->Blt, UgaDraw, (EFI_UGA_PIXEL *)Image->PixelData, EfiUgaVideoToBltBuffer,
+                           0, 0, 0, 0, Image->Width, Image->Height, 0);
+   }
+   return Image;
+} // EG_IMAGE * egCopyScreen()
+
+//
+// Make a screenshot
+//
+
+VOID egScreenShot(VOID)
+{
+    EFI_STATUS      Status;
+    EG_IMAGE        *Image;
+    UINT8           *FileData;
+    UINTN           FileDataLength;
+    UINTN           Index;
+    UINTN           ssNum;
+    CHAR16          Filename[80];
+    EFI_FILE*       BaseDir;
+
+    Image = egCopyScreen();
+    if (Image == NULL) {
+       Print(L"Error: Unable to take screen shot\n");
+       goto bailout_wait;
+    }
+
+    // encode as BMP
+    egEncodeBMP(Image, &FileData, &FileDataLength);
+    egFreeImage(Image);
+    if (FileData == NULL) {
+        Print(L"Error egEncodeBMP returned NULL\n");
+        goto bailout_wait;
+    }
+
+    Status = egFindESP(&BaseDir);
+    if (EFI_ERROR(Status))
+        return;
+
+    // Search for existing screen shot files; increment number to an unused value...
+    ssNum = 001;
+    do {
+       SPrint(Filename, 80, L"screenshot_%03d.bmp", ssNum++);
+    } while (FileExists(BaseDir, Filename));
+
+    // save to file on the ESP
+    Status = egSaveFile(BaseDir, Filename, FileData, FileDataLength);
+    FreePool(FileData);
+    if (CheckError(Status, L"in egSaveFile()")) {
+        goto bailout_wait;
+    }
+
+    return;
+
+    // DEBUG: switch to text mode
+bailout_wait:
+    egSetGraphicsModeEnabled(FALSE);
+    refit_call3_wrapper(BS->WaitForEvent, 1, &ST->ConIn->WaitForKey, &Index);
+}
+
+/* EOF */
diff --git a/libeg/text.c b/libeg/text.c
new file mode 100644 (file)
index 0000000..bcb2133
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * libeg/text.c
+ * Text drawing functions
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "libegint.h"
+#include "../refind/global.h"
+
+#include "egemb_font.h"
+#define FONT_NUM_CHARS 96
+
+static EG_IMAGE *BaseFontImage = NULL;
+static EG_IMAGE *DarkFontImage = NULL;
+static EG_IMAGE *LightFontImage = NULL;
+
+static UINTN FontCellWidth = 7;
+
+//
+// Text rendering
+//
+
+static VOID egPrepareFont() {
+   if (BaseFontImage == NULL) {
+      BaseFontImage = egPrepareEmbeddedImage(&egemb_font, TRUE);
+   }
+   if (BaseFontImage != NULL)
+      FontCellWidth = BaseFontImage->Width / FONT_NUM_CHARS;
+} // VOID egPrepareFont();
+
+UINTN egGetFontHeight(VOID) {
+   egPrepareFont();
+   return BaseFontImage->Height;
+} // UINTN egGetFontHeight()
+
+UINTN egGetFontCellWidth(VOID) {
+   return FontCellWidth;
+}
+
+UINTN egComputeTextWidth(IN CHAR16 *Text) {
+   UINTN Width = 0;
+
+   egPrepareFont();
+   if (Text != NULL)
+      Width = FontCellWidth * StrLen(Text);
+   return Width;
+} // UINTN egComputeTextWidth()
+
+VOID egMeasureText(IN CHAR16 *Text, OUT UINTN *Width, OUT UINTN *Height)
+{
+    egPrepareFont();
+
+    if (Width != NULL)
+        *Width = StrLen(Text) * FontCellWidth;
+    if (Height != NULL)
+        *Height = BaseFontImage->Height;
+}
+
+VOID egRenderText(IN CHAR16 *Text, IN OUT EG_IMAGE *CompImage, IN UINTN PosX, IN UINTN PosY, IN UINT8 BGBrightness)
+{
+    EG_IMAGE        *FontImage;
+    EG_PIXEL        *BufferPtr;
+    EG_PIXEL        *FontPixelData;
+    UINTN           BufferLineOffset, FontLineOffset;
+    UINTN           TextLength;
+    UINTN           i, c;
+
+    egPrepareFont();
+
+    // clip the text
+    if (Text)
+       TextLength = StrLen(Text);
+    else
+       TextLength = 0;
+
+    if (TextLength * FontCellWidth + PosX > CompImage->Width)
+        TextLength = (CompImage->Width - PosX) / FontCellWidth;
+
+    if (BGBrightness < 128) {
+       if (LightFontImage == NULL) {
+          LightFontImage = egCopyImage(BaseFontImage);
+          if (LightFontImage == NULL)
+             return;
+          for (i = 0; i < (LightFontImage->Width * LightFontImage->Height); i++) {
+             LightFontImage->PixelData[i].r = 255 - LightFontImage->PixelData[i].r;
+             LightFontImage->PixelData[i].g = 255 - LightFontImage->PixelData[i].g;
+             LightFontImage->PixelData[i].b = 255 - LightFontImage->PixelData[i].b;
+          } // for
+       } // if
+       FontImage = LightFontImage;
+    } else {
+       if (DarkFontImage == NULL)
+          DarkFontImage = egCopyImage(BaseFontImage);
+       if (DarkFontImage == NULL)
+          return;
+       FontImage = DarkFontImage;
+    } // if/else
+
+    // render it
+    BufferPtr = CompImage->PixelData;
+    BufferLineOffset = CompImage->Width;
+    BufferPtr += PosX + PosY * BufferLineOffset;
+    FontPixelData = FontImage->PixelData;
+    FontLineOffset = FontImage->Width;
+    for (i = 0; i < TextLength; i++) {
+        c = Text[i];
+        if (c < 32 || c >= 127)
+            c = 95;
+        else
+            c -= 32;
+        egRawCompose(BufferPtr, FontPixelData + c * FontCellWidth,
+                     FontCellWidth, FontImage->Height,
+                     BufferLineOffset, FontLineOffset);
+        BufferPtr += FontCellWidth;
+    }
+}
+
+// Load a font bitmap from the specified file
+VOID egLoadFont(IN CHAR16 *Filename) {
+   if (BaseFontImage)
+      egFreeImage(BaseFontImage);
+
+   BaseFontImage = egLoadImage(SelfDir, Filename, TRUE);
+   if (BaseFontImage == NULL)
+      Print(L"Note: Font image file %s is invalid! Using default font!\n");
+    egPrepareFont();
+} // BOOLEAN egLoadFont()
+
+/* EOF */
diff --git a/mkcdimage b/mkcdimage
new file mode 100755 (executable)
index 0000000..a794812
--- /dev/null
+++ b/mkcdimage
@@ -0,0 +1,108 @@
+#!/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
+cp $StartDir/SHELLS.txt ./refind-bin-$Version
+
+# Create a boot directory and (temporarily) copy the EFI shell
+# files to it....
+mkdir -p refind-bin-$Version/EFI/boot
+cd refind-bin-$Version/EFI/boot
+cp $StartDir/shell*.efi ./
+
+# Create hard links to the rEFInd files so that they'll be suitable for an
+# EFI-boot CD...
+ln ../../refind/refind_ia32.efi ./bootia32.efi
+ln ../../refind/refind_x64.efi ./bootx64.efi
+ln ../../refind/refind_aa64.efi ./bootaa64.efi
+cp ../../refind/refind.conf-sample ./refind.conf
+sed -i '/#showtools/a showtools shell,memtest,gdisk,apple_recovery,csr_rotate,windows_recovery,mok_tool,about,shutdown,reboot,firmware' refind.conf
+sed -i '/#csr_values/a csr_values 10,77' refind.conf
+mkdir icons
+cd icons
+ln ../../../refind/icons/* ./
+cd ../
+mkdir drivers_x64
+cd drivers_x64
+ln ../../../refind/drivers_x64/* ./
+cd ..
+mkdir drivers_ia32
+cd drivers_ia32
+ln ../../../refind/drivers_ia32/* ./
+cd ..
+mkdir drivers_aa64
+cd drivers_aa64
+ln ../../../refind/drivers_aa64/* ./
+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
+
+# Move the EFI shell files back to the root where they belong
+# (They were in EFI/boot just so they'd get counted in ToritoSize)
+mv EFI/boot/shell*.efi ./
+
+# 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 "ElTorito" refind-bin-$Version.img
+mcopy -irefind-bin-$Version.img -s EFI shell*.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 \
+    -eltorito-alt-boot -efi-boot refind-bin-$Version.img \
+    -no-emul-boot ./
+
+# Create a bootable USB flash drive image, using the FAT filesystem
+# created above and a stored partition table image (plus some empty
+# sectors)....
+#
+rm -f ../../refind-flashdrive-$Version.*
+let FatSize=`du -s refind-bin-$Version.img | cut -f 1`
+let FatSize=($FatSize)+2048
+dd if=/dev/zero of=../../refind-flashdrive-$Version.img bs=1024 count=$FatSize
+sgdisk -n 1:2048:0 -t 1:EF00 -g ../../refind-flashdrive-$Version.img
+if [[ $? != 0 ]] ; then
+   echo "sgdisk failed! Exiting!"
+   exit 1
+fi
+dd if=refind-bin-$Version.img of=../../refind-flashdrive-$Version.img bs=512 seek=2048 conv=notrunc
+
+cd ..
+mkdir refind-flashdrive-$Version
+ln ../refind-flashdrive-$Version.img refind-flashdrive-$Version
+cp $StartDir/README-flashdrive.txt $StartDir/COPYING.txt $StartDir/NEWS.txt \
+   $StartDir/CREDITS.txt $StartDir/LICENSE.txt $StartDir/SHELLS.txt refind-flashdrive-$Version
+zip -9r ../refind-flashdrive-$Version.zip refind-flashdrive-$Version
+
+cd ../
+
+# Zip up the optical disc image....
+rm -f refind-cd-$Version.zip
+zip -9 refind-cd-$Version.zip refind-cd-$Version.iso
+
+rm -r temp/
diff --git a/mkdistrib b/mkdistrib
new file mode 100755 (executable)
index 0000000..78fbe95
--- /dev/null
+++ b/mkdistrib
@@ -0,0 +1,157 @@
+#!/bin/bash
+#
+# Script to prepare source code and binary distribution files of rEFInd.
+# By Rod Smith, 3/11/2012
+# Updated 11/8/2012 to do more things automatically
+# Updated 12/6/2012 to sign binaries with the rEFInd MOK
+#
+# Usage: ./mkdistrib version [--nosign]
+# where "version" is a version number
+# MUST be run from an x86-64 system, on which the TianoCore build
+# includes both X64 and IA32 build support ("TARGET_ARCH = IA32 X64"
+# in Conf/target.txt). The MOK files must be available from a disk
+# partition to be mounted via /etc/fstab at /mnt/refind.
+
+
+if [[ $2 == "--nosign" ]] ; then
+   SignIt=0
+else
+   SignIt=1
+fi
+
+StartDir=`pwd`
+SBSign=`which sbsign 2> /dev/null`
+KeysDir=/mnt/refind
+
+KeysInfo=`df $KeysDir 2> /dev/null | grep $KeysDir`
+
+if [[ ! -n $SBSign && $SignIt == 1 ]] ; then
+   echo "Can't find sbsign binary! Aborting!"
+   exit 1
+fi
+
+if [[ ! -n $KeysInfo && $SignIt == 1 ]] ; then
+   mount /mnt/refind
+   if [[ $? -ne 0 ]] ; then
+      echo "Error mounting $KeysDir! Aborting!"
+      echo ""
+      exit 1
+   fi
+fi
+
+# From here on, if there's an error, abort immediately.
+set -e
+
+make clean
+
+# Remove temporary files from the "debian" subdirectory
+rm -rf debian/refind debian/*.log
+
+# Convert man pages to HTML form
+man2html docs/man/mkrlconf.8 > docs/refind/mkrlconf.html
+man2html docs/man/mvrefind.8 > docs/refind/mvrefind.html
+man2html docs/man/refind-install.8 > docs/refind/refind-install.html
+
+# Prepare a place and copy files there....
+mkdir -p ../snapshots/$1/refind-$1/icons/licenses ../snapshots/$1/refind-$1/icons/svg
+cp --preserve=timestamps icons/*png icons/README ../snapshots/$1/refind-$1/icons/
+cp --preserve=timestamps -r icons/licenses/* ../snapshots/$1/refind-$1/icons/licenses/
+cp --preserve=timestamps -r icons/svg/* ../snapshots/$1/refind-$1/icons/svg/
+cp -a debian docs images keys fonts banners include EfiLib libeg mok net refind filesystems gptsync refind.spec refind-install mkrlconf mvrefind mountesp CREDITS.txt NEWS.txt BUILDING.txt COPYING.txt LICENSE.txt README.txt refind.inf Make.tiano Make.common Make.aarch64 Makefile refind.conf-sample ../snapshots/$1/refind-$1
+
+# Go there and prepare a souce code tarball....
+cd ../snapshots/$1/
+rm -f refind-src-$1.tar.gz
+tar cvf refind-src-$1.tar refind-$1
+gzip -9 refind-src-$1.tar
+
+# Remove SVG files, since they aren't needed for binary packages....
+rm -rf refind-$1/icons/svg
+
+# Build the ARM64 binaries
+cd refind-$1
+ARCH=aarch64 make -j1
+ARCH=aarch64 make fs
+mkdir -p refind-bin-$1/refind/drivers_aa64
+cp --preserve=timestamps drivers_aa64/*_aa64.efi refind-bin-$1/refind/drivers_aa64/
+cp --preserve=timestamps filesystems/LICENSE*txt refind-bin-$1/refind/drivers_aa64/
+cp refind/refind_aa64.efi refind-bin-$1/refind/refind_aa64.efi
+cp refind/refind_aa64.efi $StartDir/
+mkdir -p refind-bin-$1/refind/tools_aa64
+# Don't copy gptsync_aa64.efi because it won't build in cross-compile environment
+# and because it's likely to be useless on ARM64.
+
+# Build the IA32 binaries
+make clean
+ARCH=ia32 make -j1
+ARCH=ia32 make fs
+mkdir -p refind-bin-$1/refind/drivers_ia32
+cp --preserve=timestamps drivers_ia32/*_ia32.efi refind-bin-$1/refind/drivers_ia32/
+cp --preserve=timestamps filesystems/LICENSE*txt refind-bin-$1/refind/drivers_ia32/
+cp refind/refind_ia32.efi refind-bin-$1/refind/refind_ia32.efi
+cp refind/refind_ia32.efi $StartDir/
+mkdir -p refind-bin-$1/refind/tools_ia32
+cp --preserve=timestamps gptsync/gptsync_ia32.efi refind-bin-$1/refind/tools_ia32/
+
+# Build the X64 binaries
+make clean
+make -j1
+make fs
+mkdir -p refind-bin-$1/refind/drivers_x64
+cp -a icons refind-bin-$1/refind/
+if [[ $SignIt == 1 ]] ; then
+   for File in `ls drivers_x64/*_x64.efi` ; do
+      $SBSign --key $KeysDir/refind.key --cert $KeysDir/refind.crt --output refind-bin-$1/refind/$File $File
+   done
+else
+   cp --preserve=timestamps drivers_x64/*_x64.efi refind-bin-$1/refind/drivers_x64/
+fi
+cp --preserve=timestamps filesystems/LICENSE*txt refind-bin-$1/refind/drivers_x64/
+cp --preserve=timestamps refind.conf-sample refind-bin-$1/refind/
+if [[ $SignIt == 1 ]] ; then
+   $SBSign --key $KeysDir/refind.key --cert $KeysDir/refind.crt --output refind-bin-$1/refind/refind_x64.efi refind/refind_x64.efi
+else
+   cp refind/refind_x64.efi refind-bin-$1/refind/refind_x64.efi
+fi
+mkdir -p refind-bin-$1/refind/tools_x64
+if [[ $SignIt == 1 ]] ; then
+   $SBSign --key $KeysDir/refind.key --cert $KeysDir/refind.crt --output refind-bin-$1/refind/tools_x64/gptsync_x64.efi gptsync/gptsync_x64.efi
+else
+   cp --preserve=timestamps gptsync/gptsync_x64.efi refind-bin-$1/refind/tools_x64/
+fi
+cp refind-bin-$1/refind/refind_x64.efi $StartDir
+cp -a docs keys banners fonts COPYING.txt LICENSE.txt README.txt CREDITS.txt NEWS.txt refind-install mkrlconf mvrefind mountesp refind-bin-$1
+
+# Prepare the final .zip file
+zip -9r ../refind-bin-$1.zip refind-bin-$1
+
+# Prepare a variant with the x86-64 version built with GNU-EFI....
+make clean
+make -j1 gnuefi
+if [[ $SignIt == 1 ]] ; then
+   $SBSign --key $KeysDir/refind.key --cert $KeysDir/refind.crt --output refind-bin-$1/refind/refind_x64.efi refind/refind_x64.efi
+else
+   cp refind/refind_x64.efi refind-bin-$1/refind/refind_x64.efi
+fi
+zip -9r ../refind-bin-gnuefi-$1.zip refind-bin-$1
+
+# Clean up....
+cd ..
+rm -r refind-$1
+
+# Prepare the RPM & Debian package files
+cp refind-src-$1.tar.gz ~/rpmbuild/SOURCES/
+rpmbuild -ba $StartDir/refind.spec
+mv ~/rpmbuild/RPMS/*/refind-$1* ./
+mv ~/rpmbuild/SRPMS/refind-$1* ./
+sudo alien --to-deb -k -c refind-$1*x86_64.rpm
+sudo chown rodsmith: refind*deb
+rm ~/rpmbuild/SOURCES/refind-src-*
+
+# Clean up
+if [[ $SignIt == 1 ]] ; then
+   umount $KeysDir
+fi
+
+# Finish
+cd $StartDir
diff --git a/mkrlconf b/mkrlconf
new file mode 100755 (executable)
index 0000000..bbc4037
--- /dev/null
+++ b/mkrlconf
@@ -0,0 +1,64 @@
+#!/bin/bash
+
+# Script to create a refind_linux.conf file for the current Linux
+# installation.
+
+# copyright (c) 2012-2015 by Roderick W. Smith
+#
+# This program is licensed under the terms of the GNU GPL, version 3,
+# or (at your option) any later version.
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Usage:
+#
+# ./mkrlconf [--force]
+#
+# Options:
+#
+#   --force  -- Overwrite an existing file (default is to not replace existing file)
+
+# Revision history:
+#
+# 0.10.1  -- Improve extraction of kernel options from /proc/cmdline
+# 0.10.0  -- Renamed from mkrlconf.sh to mkrlconf; changed to get $DefaultOptions
+#            from /proc/cmdline rather than from GRUB
+# 0.9.0   -- Added check for OS type, to keep from running pointlessly on OS X
+# 0.7.7   -- Fixed bug that caused stray PARTUUID= and line breaks in generated file
+# 0.5.1   -- Initial release
+#
+# Note: mkrlconf version numbers match those of the rEFInd package
+# with which they first appeared.
+
+RLConfFile="/boot/refind_linux.conf"
+
+if [[ `uname -s` != "Linux" ]] ; then
+    echo "This script is intended to be run from Linux. Aborting!"
+    echo ""
+    exit 1
+fi
+
+if [[ ! -f $RLConfFile || $1 == "--force" ]] ; then
+    RootFS=`df / | grep dev | cut -f 1 -d " "`
+    StartOfDevname=`echo $RootFS | cut -b 1-7`
+    if [[ $StartOfDevname == "/dev/sd" || $StartOfDevName == "/dev/hd" ]] ; then
+        # Identify root filesystem by UUID rather than by device node, if possible
+        Uuid=`blkid -o export -s UUID $RootFS 2> /dev/null | grep UUID=`
+        if [[ -n $Uuid ]] ; then
+            RootFS=$Uuid
+        fi
+    fi
+    FirstCmdlineOption=`cat /proc/cmdline | cut -d ' ' -f 1`
+    if [[ "$FirstCmdlineOption" =~ (vmlinuz|bzImage|kernel) ]] ; then
+        DefaultOptions=`cat /proc/cmdline | cut -d ' ' -f 2- | sed 's/\S*initrd=\S*//g' | sed 's/ *$//' | sed 's/^ *//'`
+    else
+        DefaultOptions=`cat /proc/cmdline | sed 's/\S*initrd=\S*//g' | sed 's/ *$//' | sed 's/^ *//'`
+    fi
+    echo "\"Boot with standard options\"  \"$DefaultOptions\"" > $RLConfFile
+    echo "\"Boot to single-user mode\"    \"$DefaultOptions single\"" >> $RLConfFile
+    echo "\"Boot with minimal options\"   \"ro root=$RootFS\"" >> $RLConfFile
+else
+    echo "Existing $RLConfFile found! Not overwriting!"
+    echo "To force overwriting, pass the --force option."
+    echo ""
+fi
diff --git a/mok/COPYING b/mok/COPYING
new file mode 100644 (file)
index 0000000..e2aa3e6
--- /dev/null
@@ -0,0 +1,356 @@
+Below file was part of the efitools package by James Bottomley, from which
+most of the source files in this directory were taken. The files in this
+directory originated in the "lib" directory of the efitools package, and so
+fall under the LGPLv2.1. The mok.c and mok.h files, however, are based on
+Matthew J. Garrett's shim program; see the copyright notices in those files
+for details....
+
+------------------------------------------------------------------------
+
+efitools - useful tools for manipulating UEFI secure boot platforms
+
+(c) 2012 James Bottomley
+
+All of these programs are made available under version 2 of the GNU General
+Public Licence.
+
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/mok/Make.tiano b/mok/Make.tiano
new file mode 100644 (file)
index 0000000..ee2c52c
--- /dev/null
@@ -0,0 +1,21 @@
+#
+# mok/Make.tiano
+# Build control file for Secure Boot components of rEFInd, using TianoCore EDK2
+#
+# This program is licensed under the terms of the GNU GPL, version 3,
+# or (at your option) any later version.
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+include ../Make.tiano
+
+SOURCE_NAMES     = guid mok security_policy simple_file
+OBJS             = $(SOURCE_NAMES:=.obj)
+
+all: $(AR_TARGET)
+
+$(AR_TARGET): $(OBJS)
+       $(AR) -cr $(AR_TARGET).lib $(OBJS)
+
+clean:
+       make clean
diff --git a/mok/Makefile b/mok/Makefile
new file mode 100644 (file)
index 0000000..a30b0e1
--- /dev/null
@@ -0,0 +1,24 @@
+#
+# mok/Makefile
+# Build control file for the libeg library
+#
+
+# This program is licensed under the terms of the GNU GPL, version 3,
+# or (at your option) any later version.
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+SRCDIR = .
+
+VPATH = $(SRCDIR)
+
+LOCAL_CPPFLAGS  = -I$(SRCDIR) -I$(SRCDIR)/../include
+
+OBJS            = guid.o mok.o security_policy.o simple_file.o
+TARGET          = libmok.a
+
+all: $(TARGET)
+
+include $(SRCDIR)/../Make.common
+
+# EOF
diff --git a/mok/guid.c b/mok/guid.c
new file mode 100644 (file)
index 0000000..155b8ed
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2012 <James.Bottomley@HansenPartnership.com>
+ *
+ * see COPYING file
+ */
+
+#include "global.h"
+#include "guid.h"
+
+// #ifndef BUILD_EFI
+// /* EFI has %g for this, so it's only needed in platform c */
+// const char *guid_to_str(EFI_GUID *guid)
+// {
+//    static char str[256];
+// 
+//    sprintf(str, "%08x-%04hx-%04hx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx",
+//       guid->Data1, guid->Data2, guid->Data3,
+//       guid->Data4[0], guid->Data4[1], guid->Data4[2],
+//       guid->Data4[3], guid->Data4[4], guid->Data4[5],
+//       guid->Data4[6], guid->Data4[7]);
+// 
+//    return str;
+// }
+// 
+// void str_to_guid(const char *str, EFI_GUID *guid)
+// {
+//   sscanf(str, "%8x-%4hx-%4hx-%2hhx%2hhx-%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx",
+//           &guid->Data1, &guid->Data2, &guid->Data3,
+//           guid->Data4, guid->Data4 + 1, guid->Data4 + 2,
+//           guid->Data4 + 3, guid->Data4 + 4, guid->Data4 + 5,
+//           guid->Data4 + 6, guid->Data4 + 7);
+// }
+// #endif
+
+/* all the necessary guids */
+EFI_GUID GV_GUID = EFI_GLOBAL_VARIABLE;
+EFI_GUID SIG_DB = { 0xd719b2cb, 0x3d3a, 0x4596, {0xa3, 0xbc, 0xda, 0xd0,  0xe, 0x67, 0x65, 0x6f }};
+
+EFI_GUID X509_GUID =   { 0xa5c059a1, 0x94e4, 0x4aa7, {0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72} };
+EFI_GUID RSA2048_GUID = { 0x3c5766e8, 0x269c, 0x4e34, {0xaa, 0x14, 0xed, 0x77, 0x6e, 0x85, 0xb3, 0xb6} };
+EFI_GUID PKCS7_GUID = { 0x4aafd29d, 0x68df, 0x49ee, {0x8a, 0xa9, 0x34, 0x7d, 0x37, 0x56, 0x65, 0xa7} };
+EFI_GUID IMAGE_PROTOCOL = LOADED_IMAGE_PROTOCOL;
+EFI_GUID SIMPLE_FS_PROTOCOL = SIMPLE_FILE_SYSTEM_PROTOCOL;
+EFI_GUID EFI_CERT_SHA256_GUID  = { 0xc1c41626, 0x504c, 0x4092, { 0xac, 0xa9, 0x41, 0xf9, 0x36, 0x93, 0x43, 0x28 } };
+EFI_GUID MOK_OWNER = { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} };
+EFI_GUID SECURITY_PROTOCOL_GUID = { 0xA46423E3, 0x4617, 0x49f1, {0xB9, 0xFF, 0xD1, 0xBF, 0xA9, 0x11, 0x58, 0x39 } };
+EFI_GUID SECURITY2_PROTOCOL_GUID = { 0x94ab2f58, 0x1438, 0x4ef1, {0x91, 0x52, 0x18, 0x94, 0x1a, 0x3a, 0x0e, 0x68 } };
diff --git a/mok/guid.h b/mok/guid.h
new file mode 100644 (file)
index 0000000..3d8925f
--- /dev/null
@@ -0,0 +1,18 @@
+//#include <efi.h>
+
+// #ifndef BUILD_EFI
+// const char *guid_to_str(EFI_GUID *guid);
+// void str_to_guid(const char *str, EFI_GUID *guid);
+// #endif
+
+extern EFI_GUID GV_GUID;
+extern EFI_GUID SIG_DB;
+extern EFI_GUID X509_GUID;
+extern EFI_GUID RSA2048_GUID;
+extern EFI_GUID PKCS7_GUID;
+extern EFI_GUID IMAGE_PROTOCOL;
+extern EFI_GUID SIMPLE_FS_PROTOCOL;
+extern EFI_GUID EFI_CERT_SHA256_GUID;
+extern EFI_GUID MOK_OWNER;
+extern EFI_GUID SECURITY_PROTOCOL_GUID;
+extern EFI_GUID SECURITY2_PROTOCOL_GUID;
diff --git a/mok/mok.c b/mok/mok.c
new file mode 100644 (file)
index 0000000..6b47522
--- /dev/null
+++ b/mok/mok.c
@@ -0,0 +1,104 @@
+/* mok/mok.c
+ *
+ * Based mostly on shim.c by Matthew J. Garrett/Red Hat (see below
+ * copyright notice).
+ *
+ * Code to perform Secure Boot verification of boot loader programs
+ * using the Shim program and its Machine Owner Keys (MOKs), to
+ * supplement standard Secure Boot checks performed by the firmware.
+ *
+ */
+
+/*
+ * shim - trivial UEFI first-stage bootloader
+ *
+ * Copyright 2012 Red Hat, Inc <mjg@redhat.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Significant portions of this code are derived from Tianocore
+ * (http://tianocore.sf.net) and are Copyright 2009-2012 Intel
+ * Corporation.
+ */
+
+#include "global.h"
+#include "mok.h"
+#include "../include/refit_call_wrapper.h"
+#include "../refind/lib.h"
+#include "../refind/screen.h"
+
+
+/*
+ * Check whether we're in Secure Boot and user mode
+ */
+BOOLEAN secure_mode (VOID)
+{
+   EFI_STATUS status;
+   EFI_GUID global_var = EFI_GLOBAL_VARIABLE;
+   UINTN charsize = sizeof(char);
+   UINT8 *sb = NULL, *setupmode = NULL;
+
+   status = EfivarGetRaw(&global_var, L"SecureBoot", (CHAR8 **) &sb, &charsize);
+   /* FIXME - more paranoia here? */
+   if (status != EFI_SUCCESS || charsize != sizeof(CHAR8) || *sb != 1) {
+      return FALSE;
+   }
+
+   status = EfivarGetRaw(&global_var, L"SetupMode", (CHAR8 **) &setupmode, &charsize);
+   if (status == EFI_SUCCESS && charsize == sizeof(CHAR8) && *setupmode == 1) {
+      return FALSE;
+   }
+
+   return TRUE;
+} // secure_mode()
+
+// Returns TRUE if the shim program is available to verify binaries,
+// FALSE if not
+BOOLEAN ShimLoaded(void) {
+   SHIM_LOCK   *shim_lock;
+   EFI_GUID    ShimLockGuid = SHIM_LOCK_GUID;
+
+   return (refit_call3_wrapper(BS->LocateProtocol, &ShimLockGuid, NULL, (VOID**) &shim_lock) == EFI_SUCCESS);
+} // ShimLoaded()
+
+// The following is based on the grub_linuxefi_secure_validate() function in Fedora's
+// version of GRUB 2.
+// Returns TRUE if the specified data is validated by Shim's MOK, FALSE otherwise
+BOOLEAN ShimValidate (VOID *data, UINT32 size)
+{
+   SHIM_LOCK   *shim_lock;
+   EFI_GUID    ShimLockGuid = SHIM_LOCK_GUID;
+
+   if ((data != NULL) && (refit_call3_wrapper(BS->LocateProtocol, &ShimLockGuid, NULL, (VOID**) &shim_lock) == EFI_SUCCESS)) {
+      if (!shim_lock)
+         return FALSE;
+
+      if (shim_lock->shim_verify(data, size) == EFI_SUCCESS)
+         return TRUE;
+   }
+
+   return FALSE;
+} // BOOLEAN ShimValidate()
\ No newline at end of file
diff --git a/mok/mok.h b/mok/mok.h
new file mode 100644 (file)
index 0000000..d24e2b4
--- /dev/null
+++ b/mok/mok.h
@@ -0,0 +1,30 @@
+#include "../include/PeImage.h"
+#include "../include/PeImage2.h"
+
+#define SHIM_LOCK_GUID \
+   { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} }
+
+#if defined (EFIX64)
+typedef struct _SHIM_LOCK
+{
+   EFI_STATUS __attribute__((sysv_abi)) (*shim_verify) (VOID *buffer, UINT32 size);
+   EFI_STATUS __attribute__((sysv_abi)) (*generate_hash) (char *data, int datasize,
+                                                          GNUEFI_PE_COFF_LOADER_IMAGE_CONTEXT *context, UINT8 *sha256hash,
+                                                          UINT8 *sha1hash);
+   EFI_STATUS __attribute__((sysv_abi)) (*read_header) (void *data, unsigned int datasize,
+                                                        GNUEFI_PE_COFF_LOADER_IMAGE_CONTEXT *context);
+} SHIM_LOCK;
+#else
+typedef struct _SHIM_LOCK
+{
+   EFI_STATUS (*shim_verify) (VOID *buffer, UINT32 size);
+   EFI_STATUS (*generate_hash) (char *data, int datasize, GNUEFI_PE_COFF_LOADER_IMAGE_CONTEXT *context,
+                                UINT8 *sha256hash, UINT8 *sha1hash);
+   EFI_STATUS (*read_header) (void *data, unsigned int datasize, GNUEFI_PE_COFF_LOADER_IMAGE_CONTEXT *context);
+} SHIM_LOCK;
+#endif
+
+//EFI_STATUS get_variable (CHAR16 *name, EFI_GUID guid, UINT32 *attributes, UINTN *size, VOID **buffer);
+BOOLEAN ShimLoaded(void);
+BOOLEAN ShimValidate (VOID *data, UINT32 size);
+BOOLEAN secure_mode (VOID);
diff --git a/mok/security_policy.c b/mok/security_policy.c
new file mode 100644 (file)
index 0000000..33d3be7
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * Copyright 2012 <James.Bottomley@HansenPartnership.com>
+ *
+ * see COPYING file
+ *
+ * Install and remove a platform security2 override policy
+ */
+
+#include <global.h>
+
+#include "guid.h"
+#include "../refind/lib.h"
+#include "simple_file.h"
+#include "../include/refit_call_wrapper.h"
+#include "mok.h"
+
+#include <security_policy.h>
+
+/*
+ * See the UEFI Platform Initialization manual (Vol2: DXE) for this
+ */
+struct _EFI_SECURITY2_PROTOCOL;
+struct _EFI_SECURITY_PROTOCOL;
+struct _EFI_DEVICE_PATH_PROTOCOL;
+typedef struct _EFI_SECURITY2_PROTOCOL EFI_SECURITY2_PROTOCOL;
+typedef struct _EFI_SECURITY_PROTOCOL EFI_SECURITY_PROTOCOL;
+
+#if defined(EFIX64)
+#define MSABI __attribute__((ms_abi))
+#else
+#define MSABI
+#endif
+
+typedef EFI_STATUS (MSABI *EFI_SECURITY_FILE_AUTHENTICATION_STATE) (
+         const EFI_SECURITY_PROTOCOL *This,
+         UINT32 AuthenticationStatus,
+         const EFI_DEVICE_PATH_PROTOCOL *File
+                             );
+typedef EFI_STATUS (MSABI *EFI_SECURITY2_FILE_AUTHENTICATION) (
+         const EFI_SECURITY2_PROTOCOL *This,
+         const EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+         VOID *FileBuffer,
+         UINTN FileSize,
+         BOOLEAN  BootPolicy
+                             );
+
+struct _EFI_SECURITY2_PROTOCOL {
+   EFI_SECURITY2_FILE_AUTHENTICATION FileAuthentication;
+};
+
+struct _EFI_SECURITY_PROTOCOL {
+   EFI_SECURITY_FILE_AUTHENTICATION_STATE  FileAuthenticationState;
+};
+
+
+static EFI_SECURITY_FILE_AUTHENTICATION_STATE esfas = NULL;
+static EFI_SECURITY2_FILE_AUTHENTICATION es2fa = NULL;
+
+// Perform shim/MOK and Secure Boot authentication on a binary that's already been
+// loaded into memory. This function does the platform SB authentication first
+// but preserves its return value in case of its failure, so that it can be
+// returned in case of a shim/MOK authentication failure. This is done because
+// the SB failure code seems to vary from one implementation to another, and I
+// don't want to interfere with that at this time.
+static MSABI EFI_STATUS
+security2_policy_authentication (
+   const EFI_SECURITY2_PROTOCOL *This,
+   const EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+   VOID *FileBuffer,
+   UINTN FileSize,
+   BOOLEAN  BootPolicy
+             )
+{
+   EFI_STATUS Status;
+
+   /* Chain original security policy */
+   Status = uefi_call_wrapper(es2fa, 5, This, DevicePath, FileBuffer, FileSize, BootPolicy);
+
+   /* if OK, don't bother with MOK check */
+   if (Status == EFI_SUCCESS)
+      return Status;
+
+   if (ShimValidate(FileBuffer, FileSize)) {
+      return EFI_SUCCESS;
+   } else {
+      return Status;
+   }
+} // EFI_STATUS security2_policy_authentication()
+
+// Perform both shim/MOK and platform Secure Boot authentication. This function loads
+// the file and performs shim/MOK authentication first simply to avoid double loads
+// of Linux kernels, which are much more likely to be shim/MOK-signed than platform-signed,
+// since kernels are big and can take several seconds to load on some computers and
+// filesystems. This also has the effect of returning whatever the platform code is for
+// authentication failure, be it EFI_ACCESS_DENIED, EFI_SECURITY_VIOLATION, or something
+// else. (This seems to vary between implementations.)
+static MSABI EFI_STATUS
+security_policy_authentication (
+   const EFI_SECURITY_PROTOCOL *This,
+   UINT32 AuthenticationStatus,
+   const EFI_DEVICE_PATH_PROTOCOL *DevicePathConst
+   )
+{
+   EFI_STATUS        Status;
+   EFI_DEVICE_PATH   *DevPath, *OrigDevPath;
+   EFI_HANDLE        h;
+   EFI_FILE          *f;
+   VOID              *FileBuffer;
+   UINTN             FileSize;
+   CHAR16            *DevPathStr;
+
+   if (DevicePathConst == NULL) {
+      return EFI_INVALID_PARAMETER;
+   } else {
+      DevPath = OrigDevPath = DuplicateDevicePath((EFI_DEVICE_PATH *)DevicePathConst);
+   }
+
+   Status = refit_call3_wrapper(BS->LocateDevicePath, &SIMPLE_FS_PROTOCOL, &DevPath, &h);
+   if (Status != EFI_SUCCESS)
+      goto out;
+
+   DevPathStr = DevicePathToStr(DevPath);
+
+   Status = simple_file_open_by_handle(h, DevPathStr, &f, EFI_FILE_MODE_READ);
+   MyFreePool(DevPathStr);
+   if (Status != EFI_SUCCESS)
+      goto out;
+
+   Status = simple_file_read_all(f, &FileSize, &FileBuffer);
+   simple_file_close(f);
+   if (Status != EFI_SUCCESS)
+      goto out;
+
+   if (ShimValidate(FileBuffer, FileSize)) {
+      Status = EFI_SUCCESS;
+   } else {
+      // Try using the platform's native policy....
+      Status = uefi_call_wrapper(esfas, 3, This, AuthenticationStatus, DevicePathConst);
+   }
+   FreePool(FileBuffer);
+
+ out:
+   MyFreePool(OrigDevPath);
+   return Status;
+} // EFI_STATUS security_policy_authentication()
+
+EFI_STATUS
+security_policy_install(void)
+{
+   EFI_SECURITY_PROTOCOL *security_protocol;
+   EFI_SECURITY2_PROTOCOL *security2_protocol = NULL;
+   EFI_STATUS status;
+
+   if (esfas) {
+      /* Already Installed */
+      return EFI_ALREADY_STARTED;
+   }
+
+   /* Don't bother with status here.  The call is allowed
+    * to fail, since SECURITY2 was introduced in PI 1.2.1
+    * If it fails, use security2_protocol == NULL as indicator */
+   uefi_call_wrapper(BS->LocateProtocol, 3, &SECURITY2_PROTOCOL_GUID, NULL, (VOID**) &security2_protocol);
+
+   status = uefi_call_wrapper(BS->LocateProtocol, 3, &SECURITY_PROTOCOL_GUID, NULL, (VOID**) &security_protocol);
+   if (status != EFI_SUCCESS)
+      /* This one is mandatory, so there's a serious problem */
+      return status;
+
+   if (security2_protocol) {
+      es2fa = security2_protocol->FileAuthentication;
+      security2_protocol->FileAuthentication = security2_policy_authentication;
+   }
+
+   esfas = security_protocol->FileAuthenticationState;
+   security_protocol->FileAuthenticationState = security_policy_authentication;
+   return EFI_SUCCESS;
+}
+
+EFI_STATUS
+security_policy_uninstall(void)
+{
+   EFI_STATUS status;
+
+   if (esfas) {
+      EFI_SECURITY_PROTOCOL *security_protocol;
+
+      status = uefi_call_wrapper(BS->LocateProtocol, 3, &SECURITY_PROTOCOL_GUID, NULL, (VOID**) &security_protocol);
+
+      if (status != EFI_SUCCESS)
+         return status;
+
+      security_protocol->FileAuthenticationState = esfas;
+      esfas = NULL;
+   } else {
+      /* nothing installed */
+      return EFI_NOT_STARTED;
+   }
+
+   if (es2fa) {
+      EFI_SECURITY2_PROTOCOL *security2_protocol;
+
+      status = uefi_call_wrapper(BS->LocateProtocol, 3, &SECURITY2_PROTOCOL_GUID, NULL, (VOID**) &security2_protocol);
+
+      if (status != EFI_SUCCESS)
+         return status;
+
+      security2_protocol->FileAuthentication = es2fa;
+      es2fa = NULL;
+   }
+
+   return EFI_SUCCESS;
+}
diff --git a/mok/security_policy.h b/mok/security_policy.h
new file mode 100644 (file)
index 0000000..8bbcf48
--- /dev/null
@@ -0,0 +1,6 @@
+EFI_STATUS
+security_policy_install(void);
+EFI_STATUS
+security_policy_uninstall(void);
+// void
+// security_protocol_set_hashes(unsigned char *esl, int len);
diff --git a/mok/simple_file.c b/mok/simple_file.c
new file mode 100644 (file)
index 0000000..263593f
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2012 <James.Bottomley@HansenPartnership.com>
+ *
+ * see COPYING file
+ */
+
+#include <global.h>
+#include "../include/refit_call_wrapper.h"
+
+#include "simple_file.h"
+//#include "execute.h"    /* for generate_path() */
+
+static EFI_GUID IMAGE_PROTOCOL = LOADED_IMAGE_PROTOCOL;
+static EFI_GUID SIMPLE_FS_PROTOCOL = SIMPLE_FILE_SYSTEM_PROTOCOL;
+static EFI_GUID FILE_INFO = EFI_FILE_INFO_ID;
+
+EFI_STATUS
+simple_file_open_by_handle(EFI_HANDLE device, CHAR16 *name, EFI_FILE **file, UINT64 mode)
+{
+   EFI_STATUS efi_status;
+   EFI_FILE_IO_INTERFACE *drive;
+   EFI_FILE *root;
+
+   efi_status = uefi_call_wrapper(BS->HandleProtocol, 3, device,
+                   &SIMPLE_FS_PROTOCOL, (VOID**) &drive);
+
+   if (efi_status != EFI_SUCCESS) {
+      Print(L"Unable to find simple file protocol\n");
+      goto error;
+   }
+
+   efi_status = uefi_call_wrapper(drive->OpenVolume, 2, drive, &root);
+
+   if (efi_status != EFI_SUCCESS) {
+      Print(L"Failed to open drive volume\n");
+      goto error;
+   }
+
+   efi_status = uefi_call_wrapper(root->Open, 5, root, file, name,
+                   mode, 0);
+
+ error:
+   return efi_status;
+}
+
+// generate_path() from shim by Matthew J. Garrett
+static
+EFI_STATUS
+generate_path(CHAR16* name, EFI_LOADED_IMAGE *li, EFI_DEVICE_PATH **path, CHAR16 **PathName)
+{
+        unsigned int pathlen;
+        EFI_STATUS efi_status = EFI_SUCCESS;
+        CHAR16 *devpathstr = DevicePathToStr(li->FilePath),
+                *found = NULL;
+        int i;
+
+        for (i = 0; i < StrLen(devpathstr); i++) {
+                if (devpathstr[i] == '/')
+                        devpathstr[i] = '\\';
+                if (devpathstr[i] == '\\')
+                        found = &devpathstr[i];
+        }
+        if (!found) {
+                pathlen = 0;
+        } else {
+                while (*(found - 1) == '\\')
+                        --found;
+                *found = '\0';
+                pathlen = StrLen(devpathstr);
+        }
+
+        if (name[0] != '\\')
+                pathlen++;
+
+        *PathName = AllocatePool((pathlen + 1 + StrLen(name))*sizeof(CHAR16));
+
+        if (!*PathName) {
+                Print(L"Failed to allocate path buffer\n");
+                efi_status = EFI_OUT_OF_RESOURCES;
+                goto error;
+        }
+
+        StrCpy(*PathName, devpathstr);
+
+        if (name[0] != '\\')
+                StrCat(*PathName, L"\\");
+        StrCat(*PathName, name);
+
+        *path = FileDevicePath(li->DeviceHandle, *PathName);
+
+error:
+        FreePool(devpathstr);
+
+        return efi_status;
+} // generate_path()
+
+EFI_STATUS
+simple_file_open(EFI_HANDLE image, CHAR16 *name, EFI_FILE **file, UINT64 mode)
+{
+   EFI_STATUS efi_status;
+   EFI_HANDLE device;
+   EFI_LOADED_IMAGE *li;
+   EFI_DEVICE_PATH *loadpath = NULL;
+   CHAR16 *PathName = NULL;
+
+   efi_status = uefi_call_wrapper(BS->HandleProtocol, 3, image,
+                   &IMAGE_PROTOCOL, (VOID**) &li);
+
+   if (efi_status != EFI_SUCCESS)
+      return simple_file_open_by_handle(image, name, file, mode);
+
+   efi_status = generate_path(name, li, &loadpath, &PathName);
+
+   if (efi_status != EFI_SUCCESS) {
+      Print(L"Unable to generate load path for %s\n", name);
+      return efi_status;
+   }
+
+   device = li->DeviceHandle;
+
+   efi_status = simple_file_open_by_handle(device, PathName, file, mode);
+
+   FreePool(PathName);
+   FreePool(loadpath);
+
+   return efi_status;
+}
+
+EFI_STATUS
+simple_file_read_all(EFI_FILE *file, UINTN *size, void **buffer)
+{
+   EFI_STATUS efi_status;
+   EFI_FILE_INFO *fi;
+   char buf[1024];
+
+   *size = sizeof(buf);
+   fi = (void *)buf;
+
+
+   efi_status = uefi_call_wrapper(file->GetInfo, 4, file, &FILE_INFO,
+                   size, fi);
+   if (efi_status != EFI_SUCCESS) {
+      Print(L"Failed to get file info\n");
+      return efi_status;
+   }
+
+   *size = fi->FileSize;
+
+   *buffer = AllocatePool(*size);
+   if (!*buffer) {
+      Print(L"Failed to allocate buffer of size %d\n", *size);
+      return EFI_OUT_OF_RESOURCES;
+   }
+   efi_status = uefi_call_wrapper(file->Read, 3, file, size, *buffer);
+
+   return efi_status;
+}
+
+void
+simple_file_close(EFI_FILE *file)
+{
+   uefi_call_wrapper(file->Close, 1, file);
+}
diff --git a/mok/simple_file.h b/mok/simple_file.h
new file mode 100644 (file)
index 0000000..e0cbf16
--- /dev/null
@@ -0,0 +1,9 @@
+EFI_STATUS
+simple_file_open (EFI_HANDLE image, CHAR16 *name, EFI_FILE **file, UINT64 mode);
+EFI_STATUS
+simple_file_open_by_handle(EFI_HANDLE device, CHAR16 *name, EFI_FILE **file, UINT64 mode);
+EFI_STATUS
+simple_file_read_all(EFI_FILE *file, UINTN *size, void **buffer);
+void
+simple_file_close(EFI_FILE *file);
+
diff --git a/mountesp b/mountesp
new file mode 100755 (executable)
index 0000000..77bdc0a
--- /dev/null
+++ b/mountesp
@@ -0,0 +1,82 @@
+#!/bin/bash
+#
+# Mac OS X script to locate and mount an EFI System Partition (ESP)
+#
+# Usage:
+#
+# ./mountesp
+#
+# This program is copyright (c) 2015 by Roderick W. Smith
+#
+# This program is licensed under the terms of the GNU GPL, version 3,
+# or (at your option) any later version.
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# Revision history:
+#
+# 0.9.3   -- Initial release (with rEFInd 0.9.3)
+
+# Mount the ESP at /Volumes/ESP or determine its current mount
+# point.
+MountOSXESP() {
+    # Identify the ESP. Note: This returns the FIRST ESP found;
+    # if the system has multiple disks, this could be wrong!
+    Temp=$(mount | sed -n -E "/^(\/dev\/disk[0-9]+s[0-9]+) on \/ \(.*$/s//\1/p")
+    if [ $Temp ]; then
+        Temp=$(diskutil list | grep " EFI " | grep -o 'disk.*' | head -n 1)
+        if [ -z $Temp ]; then
+            echo "Warning: root device doesn't have an EFI partition"
+        fi
+    else
+        echo "Warning: root device could not be found"
+    fi
+    if [ -z $Temp ]; then
+        Temp=$(diskutil list | sed -n -E '/^ *[0-9]+:[ ]+EFI EFI[ ]+[0-9.]+ [A-Z]+[ ]+(disk[0-9]+s[0-9]+)$/ { s//\1/p
+                q
+            }' )
+
+        if [ -z $Temp ]; then
+            echo "Could not find an EFI partition. Aborting!"
+            exit 1
+        fi
+    fi
+    Esp=/dev/`echo $Temp`
+    echo "The ESP has been identified as $Esp; attempting to mount it...."
+    # If the ESP is mounted, use its current mount point....
+    Temp=`df -P | grep "$Esp "`
+    MountPoint=`echo $Temp | cut -f 6- -d ' '`
+    if [[ "$MountPoint" == '' ]] ; then
+        if [[ $UID != 0 ]] ; then
+            echo "You must run this program as root or using sudo! Exiting!"
+            exit 1
+        fi
+        MountPoint="/Volumes/ESP"
+        mkdir /Volumes/ESP &> /dev/null
+        mount -t msdos "$Esp" $MountPoint
+        # Some systems have HFS+ "ESPs." They shouldn't, but they do. If this is
+        # detected, mount it as such and set appropriate options.
+        if [[ $? != 0 ]] ; then
+            mount -t hfs "$Esp" $MountPoint
+            if [[ $? != 0 ]] ; then
+                echo "Unable to mount ESP!\n"
+                exit 1
+            fi
+        fi
+    fi
+    echo "The ESP is mounted at $MountPoint"
+} # MountOSXESP()
+
+#
+# Main part of script....
+#
+
+case "$OSTYPE" in
+    darwin*)
+            MountOSXESP
+            ;;
+    *)
+            echo "This script is meant to be run under OS X *ONLY*! Exiting!"
+            exit
+            ;;
+esac
diff --git a/mvrefind b/mvrefind
new file mode 100755 (executable)
index 0000000..1bb5d45
--- /dev/null
+++ b/mvrefind
@@ -0,0 +1,283 @@
+#!/bin/bash
+#
+# Linux script to move an existing rEFInd installation from one directory to
+# another
+#
+# copyright (c) 2013-2015 by Roderick W. Smith
+#
+# This program is licensed under the terms of the GNU GPL, version 3,
+# or (at your option) any later version.
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Usage:
+#
+# ./mvrefind /path/to/source /path/to/destination
+#
+# Typically used to "hijack" or "unhijack" a Windows boot loader location or
+# to help convert a rEFInd installation made in BIOS mode to one that works
+# in EFI mode.
+#
+# Revision history:
+#
+# 0.10.1  -- Generalized to support ARM64 (aka AARCH64, aa64)
+# 0.10.0  -- Renamed from mvrefind.sh to mvrefind
+# 0.6.3   -- Initial release
+#
+# Note: mvrefind version numbers match those of the rEFInd package
+# with which they first appeared.
+
+RootDir="/"
+SourceShim="shim.efi"
+TargetShim=$SourceShim
+SourceDir=`readlink -f ${1}`
+TargetDir=`readlink -f ${2}`
+
+# Identifies the ESP's location (/boot or /boot/efi); aborts if the ESP isn't
+# mounted at either location. Also splits the ESP location from SourceDir and
+# TargetDir, leaving them intact but creating new EspSourceDir and EspTargetDir
+# variables containing only the ESP components thereof. These new variables
+# are also converted to all-lowercase and any trailing slash is stripped, to
+# assist in comparisons. (This is reasonable because FAT is case-insensitive.)
+# Sets InstallDir to the ESP mount point.
+FindLinuxESP() {
+   EspLine=`df $RootDir/boot/efi 2> /dev/null | grep boot/efi`
+   if [[ ! -n $EspLine ]] ; then
+      EspLine=`df $RootDir/boot | grep boot`
+   fi
+   InstallDir=`echo $EspLine | cut -d " " -f 6`
+   if [[ -n $InstallDir ]] ; then
+      EspFilesystem=`grep $InstallDir /etc/mtab | cut -d " " -f 3`
+   fi
+   if [[ $EspFilesystem != 'vfat' ]] ; then
+      echo "$RootDir/boot/efi doesn't seem to be on a VFAT filesystem. The ESP must be"
+      echo "mounted at $RootDir/boot or $RootDir/boot/efi and it must be VFAT! Aborting!"
+      exit 1
+   fi
+
+   # Sanity check on source & target....
+   EspPathLength=`expr length $InstallDir`
+   Temp=`echo $SourceDir | cut -c 1-$EspPathLength`
+   if [[ $Temp != $InstallDir ]] ; then
+      echo "$SourceDir isn't on the ESP ($InstallDir)! Aborting!"
+      exit 1
+   fi
+   Temp=`echo $TargetDir | cut -c 1-$EspPathLength`
+   if [[ $Temp != $InstallDir ]] ; then
+      echo "$TargetDir isn't on the ESP ($InstallDir)! Aborting!"
+      exit 1
+   fi
+
+   # Temporarily replace "/" in pathnames with ",", so as to enable sed to
+   # work on them
+   TempInstallDir=`echo $InstallDir | tr '/' ','`
+   Temp=`echo $SourceDir | tr '/' ',' | sed s/${TempInstallDir}//g | tr ',' '/' | tr '[A-Z]' '[a-z]'`
+   EspSourceDir=`dirname $Temp`/`basename $Temp`
+   Temp=`echo $TargetDir | tr '/' ',' | sed s/${TempInstallDir}//g | tr ',' '/' | tr '[A-Z]' '[a-z]'`
+   EspTargetDir=`dirname $Temp`/`basename $Temp`
+   if [[ $EspSourceDir == $EspTargetDir ]] ; then
+      echo "$SourceDir is the same as $TargetDir! Aborting!"
+      exit 1
+   fi
+} # FindLinuxESP
+
+DeterminePlatform() {
+    CpuType=`uname -m`
+    case "$CpuType" in
+    aarch64)
+        Platform="aa64"
+        ;;
+    x86_64)
+        Platform="x64"
+        ;;
+    i?86)
+        Platform="ia32"
+        ;;
+    *)
+        echo "Unsupported CPU type; aborting!"
+        exit 1
+    esac
+    Source="refind_$Platform.efi"
+    Target=$Source
+}
+
+# Adjust filename variables appropriately for their locations and detected
+# presence (or lack thereof) of shim installation
+AdjustFilenames() {
+   if [[ -f $SourceDir/grub$Platform.efi ]] ; then
+      Source="grub$Platform.efi"
+      Target=$Source
+      if [[ $EspSourceDir == "/efi/boot" ]] ; then
+         SourceShim="boot$Platform.efi"
+      elif [[ $EspSourceDir == "/efi/microsoft/boot" ]] ; then
+         SourceShim="bootmgfw.efi"
+      fi
+   else
+      SourceShim="none"
+      TargetShim="none"
+      if [[ $EspSourceDir == "/efi/boot" ]] ; then
+         Source="boot$Platform.efi"
+      elif [[ $EspSourceDir == "/efi/microsoft/boot" ]] ; then
+         Source="bootmgfw.efi"
+      fi
+   fi
+
+   if [[ $EspTargetDir == "/efi/boot" ]] ; then
+      if [[ $TargetShim == "none" ]] ; then
+         Target="boot$Platform.efi"
+      else
+         TargetShim="boot$Platform.efi"
+      fi
+   elif [[ $EspTargetDir == "/efi/microsoft/boot" ]] ; then
+      if [[ $TargetShim == "none" ]] ; then
+         Target="bootmgfw.efi"
+      else
+         TargetShim="bootmgfw.efi"
+      fi
+   fi
+} # AdjustFilenames()
+
+# Checks for the presence of necessary files, including both boot loaders
+# and support utilities (efibootmgr, etc.)
+CheckForFiles() {
+   if [[ (! -f $SourceDir/$Source) ||
+         ($SourceShim != "none" && ! -f $SourceDir/SourceShim) ||
+         ! -f $SourceDir/refind.conf ]] ; then
+      echo "There doesn't seem to be a rEFInd installation at $SourceDir!"
+      echo "Aborting!"
+      exit 1
+   fi
+   if [[ $EspTargetDir != "/efi/boot" && $EspTargetDir != "/efi/microsoft/boot" ]] ; then
+      Efibootmgr=`which efibootmgr 2> /dev/null`
+      if [[ ! -f $Efibootmgr ]] ; then
+         echo "Moving to a non-default directory requires a working efibootmgr utility, but"
+         echo "one can't be found! Aborting!"
+         exit 1
+      elif [[ ! -d "/sys/firmware/efi" ]] ; then
+         echo "Moving to a non-default directory requires a boot into EFI mode, but we seem"
+         echo "to be running in BIOS mode. (Perhaps typing 'modprobe efivars' will fix this."
+         echo "Aborting!"
+      fi
+   fi
+} # CheckForFiles()
+
+# Do final checks & then move the files!
+MoveFiles() {
+   ExistingFiles=`find $TargetDir -name "*.efi" 2> /dev/null`
+   if [[ -n $ExistingFiles && $EspTargetDir != "/efi/boot" && $EspTargetDir != "/efi/microsoft/boot" ]] ; then
+      echo "$TargetDir isn't empty! Aborting!"
+      exit 1
+   fi
+
+   if [[ $EspTargetDir == "/efi/boot" && -d $TargetDir ]] ; then
+      if [[ -d $InstallDir/EFI/BOOT-rEFIndBackup ]] ; then
+         echo ""
+         echo "Caution: An existing backup of a default boot loader exists! If the current"
+         echo "default boot loader and the backup are different boot loaders, the current"
+         echo "one will become inaccessible."
+         echo ""
+         echo -n "Do you want to proceed with moving (Y/N)? "
+         read YesNo
+         if [[ $YesNo == "Y" || $YesNo == "y" ]] ; then
+            echo "OK; continuing with the move..."
+         else
+            exit 0
+         fi
+      else
+         mv $TargetDir $InstallDir/EFI/BOOT-refindBackup &> /dev/null
+      fi
+   fi
+
+   if [[ $EspTargetDir == "/efi/microsoft/boot" && -d $TargetDir ]] ; then
+      mv -n $EspTargetDir/bootmgfw.efi $InstallDir/EFI/Microsoft/
+   fi
+
+   mkdir -p $TargetDir
+   mv $SourceDir/icons $TargetDir/ 2> /dev/null
+   mv $SourceDir/icons-backup $TargetDir/ 2> /dev/null
+   mv $SourceDir/drivers_* $TargetDir/ 2> /dev/null
+   mv $SourceDir/keys $TargetDir 2> /dev/null
+   mv $SourceDir/$Source $TargetDir/$Target 2> /dev/null
+   mv $SourceDir/$SourceShim $TargetDir/$TargetShim 2> /dev/null
+   mv $SourceDir/refind.conf* $TargetDir/ 2> /dev/null
+   rmdir $SourceDir 2> /dev/null
+} # MoveFiles()
+
+# Clean up after moving files -- mainly restoring old backed-up files, if present
+PostMoveCleanup() {
+   if [[ $EfiSourceDir == "/efi/boot" && -d $InstallDir/EFI/BOOT-rEFIndBackup && ! -d $SourceDir ]] ; then
+      mv $InstallDir/EFI/BOOT-rEFIndBackup $SourceDir 2> /dev/null
+   fi
+   if [[ $EfiSourceDir == "/efi/microsoft/boot" && -f $InstallDir/EFI/Microsoft/bootmgfw.efi ]] ; then
+      mv -n $InstallDir/EFI/Microsoft/bootmgfw.efi $SourceDir/bootmgfw.efi
+   fi
+} # PostMoveCleanup()
+
+# If necessary, create a new NVRAM entry for the new location
+AddNvramEntry() {
+   InstallIt="0"
+   Efibootmgr=`which efibootmgr 2> /dev/null`
+   InstallDisk=`grep $InstallDir /etc/mtab | cut -d " " -f 1 | cut -c 1-8`
+   PartNum=`grep $InstallDir /etc/mtab | cut -d " " -f 1 | cut -c 9-10`
+
+   if [[ $TargetShim != "none" ]] ; then
+      EntryFilename=$EspTargetDir/$TargetShim
+   else
+      EntryFilename=$EspTargetDir/$Target
+   fi # if/else
+
+   EfiEntryFilename=`echo ${EntryFilename//\//\\\}`
+   EfiEntryFilename2=`echo ${EfiEntryFilename} | sed s/\\\\\\\\/\\\\\\\\\\\\\\\\/g`
+   ExistingEntry=`$Efibootmgr -v | grep -i $EfiEntryFilename2`
+
+   if [[ $ExistingEntry ]] ; then
+      ExistingEntryBootNum=`echo $ExistingEntry | cut -c 5-8`
+      FirstBoot=`$Efibootmgr | grep BootOrder | cut -c 12-15`
+      if [[ $ExistingEntryBootNum != $FirstBoot ]] ; then
+         $Efibootmgr -b $ExistingEntryBootNum -B &> /dev/null
+         InstallIt="1"
+      fi
+   else
+      InstallIt="1"
+   fi
+
+   if [[ $InstallIt == "1" ]] ; then
+      if [[ $EfiTargetDir == "/efi/microsoft/boot" ]] ; then
+         # Name it the way some firmware expects -- see http://mjg59.dreamwidth.org/20187.html
+         $Efibootmgr -c -l $EfiEntryFilename -L "Windows Boot Manager" -d $InstallDisk -p $PartNum &> /dev/null
+      else
+         $Efibootmgr -c -l $EfiEntryFilename -L "rEFInd Boot Manager" -d $InstallDisk -p $PartNum &> /dev/null
+      fi
+      if [[ $? != 0 ]] ; then
+         EfibootmgrProblems=1
+      fi
+   fi
+
+   if [[ $EfibootmgrProblems ]] ; then
+      echo
+      echo "ALERT: There were problems running the efibootmgr program! Your moved rEFInd"
+      echo "might not run!"
+      echo
+   fi
+} # AddNvramEntry
+
+#
+# Main body of script
+#
+
+if [[ $# != 2 ]] ; then
+   echo "Usage: $0 {source-directory} {target-directory}"
+   exit 1
+fi
+if [[ `whoami` != "root" ]] ; then
+   echo "Not running as root! Aborting!"
+   exit 1
+fi
+
+FindLinuxESP
+DeterminePlatform
+AdjustFilenames
+CheckForFiles
+MoveFiles
+PostMoveCleanup
+AddNvramEntry
diff --git a/net/Makefile b/net/Makefile
new file mode 100644 (file)
index 0000000..8be6a61
--- /dev/null
@@ -0,0 +1,24 @@
+IPXE_GIT=git://git.ipxe.org/ipxe.git
+EFI_PREFIX=efi_discovery_prefix.c
+EFI_DISCOVERY_BINARY=ipxe_discovery.efi
+EFI_DISCOVERY_ENTRY=_efi_discovery_start
+IPXE_SRC = ipxe
+
+source:
+       rm -rf $(IPXE_SRC)/
+       git clone $(IPXE_GIT)
+       cp discovery/$(EFI_PREFIX) ipxe/src/arch/x86/prefix/
+       cp discovery/Makefile.housekeeping ipxe/src/Makefile.housekeeping
+netboot:
+       mkdir -p bin
+       cp discovery/console.h ipxe/src/config/local/console.h;\
+       cd ipxe/src;\
+       make bin-x86_64-efi/ipxe.efi TGT_LD_ENTRY=$(EFI_DISCOVERY_ENTRY);\
+       cp bin-x86_64-efi/ipxe.efi ../../bin/$(EFI_DISCOVERY_BINARY);\
+       rm -r bin-x86_64-efi/;\
+       rm config/local/console.h;\
+       make bin-x86_64-efi/ipxe.efi;\
+       cp bin-x86_64-efi/ipxe.efi ../../bin/ipxe.efi;\
+       cd ../../
+clean:
+       rm -r bin/
diff --git a/net/discovery/Makefile.housekeeping b/net/discovery/Makefile.housekeeping
new file mode 100644 (file)
index 0000000..8dad3a1
--- /dev/null
@@ -0,0 +1,1461 @@
+# -*- makefile -*- : Force emacs to use Makefile mode
+#
+# This file contains various boring housekeeping functions that would
+# otherwise seriously clutter up the main Makefile.
+
+###############################################################################
+#
+# Find a usable "echo -e" substitute.
+#
+TAB                    := $(shell $(PRINTF) '\t')
+ECHO_E_ECHO            := $(ECHO)
+ECHO_E_ECHO_E          := $(ECHO) -e
+ECHO_E_BIN_ECHO        := /bin/echo
+ECHO_E_BIN_ECHO_E      := /bin/echo -e
+ECHO_E_ECHO_TAB                := $(shell $(ECHO_E_ECHO) '\t' | cat)
+ECHO_E_ECHO_E_TAB      := $(shell $(ECHO_E_ECHO_E) '\t' | cat)
+ECHO_E_BIN_ECHO_TAB    := $(shell $(ECHO_E_BIN_ECHO) '\t')
+ECHO_E_BIN_ECHO_E_TAB  := $(shell $(ECHO_E_BIN_ECHO_E) '\t')
+
+ifeq ($(ECHO_E_ECHO_TAB),$(TAB))
+ECHO_E         := $(ECHO_E_ECHO)
+endif
+ifeq ($(ECHO_E_ECHO_E_TAB),$(TAB))
+ECHO_E         := $(ECHO_E_ECHO_E)
+endif
+ifeq ($(ECHO_E_BIN_ECHO_TAB),$(TAB))
+ECHO_E         := $(ECHO_E_BIN_ECHO)
+endif
+ifeq ($(ECHO_E_BIN_ECHO_E_TAB),$(TAB))
+ECHO_E         := $(ECHO_E_BIN_ECHO_E)
+endif
+
+.echocheck :
+ifdef ECHO_E
+       @$(TOUCH) $@
+else
+       @$(PRINTF) '%24s : x%sx\n' 'tab' '$(TAB)'
+       @$(PRINTF) '%24s : x%sx\n' '"$(ECHO_E_ECHO) \t"' \
+                                   '$(ECHO_E_ECHO_TAB)'
+       @$(PRINTF) '%24s : x%sx\n' '"$(ECHO_E_ECHO_E) \t"' \
+                                   '$(ECHO_E_ECHO_E_TAB)'
+       @$(PRINTF) '%24s : x%sx\n' '"$(ECHO_E_BIN_ECHO) \t"' \
+                                   '$(ECHO_E_BIN_ECHO_TAB)'
+       @$(PRINTF) '%24s : x%sx\n' '"$(ECHO_E_BIN_ECHO_E) \t"' \
+                                   '$(ECHO_E_BIN_ECHO_E_TAB)'
+       @$(ECHO) "No usable \"echo -e\" substitute found"
+       @exit 1
+endif
+MAKEDEPS       += .echocheck
+VERYCLEANUP    += .echocheck
+
+echo :
+       @$(ECHO) "Using \"$(ECHO_E)\" for \"echo -e\""
+
+###############################################################################
+#
+# Generate a usable "seq" substitute
+#
+define seq
+       $(shell awk 'BEGIN { for ( i = $(1) ; i <= $(2) ; i++ ) print i }')
+endef
+
+###############################################################################
+#
+# Determine host OS
+#
+HOST_OS                := $(shell uname -s)
+hostos :
+       @$(ECHO) $(HOST_OS)
+
+###############################################################################
+#
+# Determine compiler
+
+CCDEFS         := $(shell $(CC) -E -x c -c /dev/null -dM | cut -d" " -f2)
+ccdefs:
+       @$(ECHO) $(CCDEFS)
+
+ifeq ($(filter __ICC,$(CCDEFS)),__ICC)
+CCTYPE         := icc
+else
+CCTYPE         := gcc
+endif
+cctype:
+       @$(ECHO) $(CCTYPE)
+
+###############################################################################
+#
+# Check for tools that can cause failed builds
+#
+
+ifeq ($(CCTYPE),gcc)
+GCC_2_96_BANNER := $(shell $(CC) -v 2>&1 | grep -is 'gcc version 2\.96')
+ifneq ($(GCC_2_96_BANNER),)
+$(warning gcc 2.96 is unsuitable for compiling iPXE)
+$(warning Use gcc 2.95 or a newer version instead)
+$(error Unsuitable build environment found)
+endif
+endif
+
+PERL_UNICODE_CHECK := $(shell $(PERL) -e 'use bytes; print chr(255)' | wc -c)
+ifeq ($(PERL_UNICODE_CHECK),2)
+$(warning Your Perl version has a Unicode handling bug)
+$(warning Execute this command before building iPXE:)
+$(warning export LANG=$${LANG%.UTF-8})
+$(error Unsuitable build environment found)
+endif
+
+LD_GOLD_BANNER := $(shell $(LD) -v 2>&1 | grep 'GNU gold')
+ifneq ($(LD_GOLD_BANNER),)
+$(warning GNU gold is unsuitable for building iPXE)
+$(warning Use GNU ld instead)
+$(error Unsuitable build environment found)
+endif
+
+###############################################################################
+#
+# Check if $(eval ...) is available to use
+#
+
+HAVE_EVAL :=
+ifndef NO_EVAL
+$(eval HAVE_EVAL := yes)
+endif
+eval :
+       @$(ECHO) $(HAVE_EVAL)
+
+###############################################################################
+#
+# Check for various tool workarounds
+#
+
+WORKAROUND_CFLAGS :=
+WORKAROUND_ASFLAGS :=
+WORKAROUND_LDFLAGS :=
+
+# Make syntax does not allow use of comma or space in certain places.
+# This ugly workaround is suggested in the manual.
+#
+COMMA  := ,
+EMPTY  :=
+SPACE  := $(EMPTY) $(EMPTY)
+HASH   := \#
+define NEWLINE
+
+
+endef
+
+# Some widespread patched versions of gcc include -fstack-protector by
+# default, even when -ffreestanding is specified.  We therefore need
+# to disable -fstack-protector if the compiler supports it.
+#
+ifeq ($(CCTYPE),gcc)
+SP_TEST = $(CC) -fno-stack-protector -x c -c /dev/null \
+               -o /dev/null >/dev/null 2>&1
+SP_FLAGS := $(shell $(SP_TEST) && $(ECHO) '-fno-stack-protector')
+WORKAROUND_CFLAGS += $(SP_FLAGS)
+endif
+
+# Some widespread patched versions of gcc include -fPIE -Wl,-pie by
+# default.  Note that gcc will exit *successfully* if it fails to
+# recognise an option that starts with "no", so we have to test for
+# output on stderr instead of checking the exit status.
+#
+ifeq ($(CCTYPE),gcc)
+PIE_TEST = [ -z "`$(CC) -fno-PIE -nopie -x c -c /dev/null -o /dev/null 2>&1`" ]
+PIE_FLAGS := $(shell $(PIE_TEST) && $(ECHO) '-fno-PIE -nopie')
+WORKAROUND_CFLAGS += $(PIE_FLAGS)
+endif
+
+# gcc 4.4 generates .eh_frame sections by default, which distort the
+# output of "size".  Inhibit this.
+#
+ifeq ($(CCTYPE),gcc)
+CFI_TEST = $(CC) -fno-dwarf2-cfi-asm -fno-exceptions -fno-unwind-tables \
+                -fno-asynchronous-unwind-tables -x c -c /dev/null \
+                -o /dev/null >/dev/null 2>&1
+CFI_FLAGS := $(shell $(CFI_TEST) && \
+              $(ECHO) '-fno-dwarf2-cfi-asm -fno-exceptions ' \
+                      '-fno-unwind-tables -fno-asynchronous-unwind-tables')
+WORKAROUND_CFLAGS += $(CFI_FLAGS)
+endif
+
+# gcc 4.6 generates spurious warnings if -Waddress is in force.
+# Inhibit this.
+#
+ifeq ($(CCTYPE),gcc)
+WNA_TEST = $(CC) -Wno-address -x c -c /dev/null -o /dev/null >/dev/null 2>&1
+WNA_FLAGS := $(shell $(WNA_TEST) && $(ECHO) '-Wno-address')
+WORKAROUND_CFLAGS += $(WNA_FLAGS)
+endif
+
+# Some versions of gas choke on division operators, treating them as
+# comment markers.  Specifying --divide will work around this problem,
+# but isn't available on older gas versions.
+#
+DIVIDE_TEST = $(AS) --divide /dev/null -o /dev/null 2>/dev/null
+DIVIDE_FLAGS := $(shell $(DIVIDE_TEST) && $(ECHO) '--divide')
+WORKAROUND_ASFLAGS += $(DIVIDE_FLAGS)
+
+###############################################################################
+#
+# Build verbosity
+#
+ifeq ($(V),1)
+Q :=
+QM := @\#
+else
+Q := @
+QM := @
+endif
+
+###############################################################################
+#
+# Checker
+#
+ifeq ($(C),1)
+export REAL_CC := $(CC)
+CC := cgcc
+CFLAGS += -Wno-decl
+endif
+
+###############################################################################
+#
+# Set BIN according to whatever was specified on the command line as
+# the build target.
+#
+
+# Determine how many different BIN directories are mentioned in the
+# make goals.
+#
+BIN_GOALS      := $(filter bin bin/% bin-%,$(MAKECMDGOALS))
+BIN_GOALS_BINS := $(sort $(foreach BG,$(BIN_GOALS),\
+                                   $(firstword $(subst /, ,$(BG)))))
+NUM_BINS       := $(words $(BIN_GOALS_BINS))
+
+ifeq ($(NUM_BINS),0)
+
+# No BIN directory was specified.  Set BIN to "bin" as a sensible
+# default.
+
+BIN            := bin
+
+else # NUM_BINS == 0
+
+ifeq ($(NUM_BINS),1)
+
+# If exactly one BIN directory was specified, set BIN to match this
+# directory.
+#
+BIN            := $(firstword $(BIN_GOALS_BINS))
+
+else # NUM_BINS == 1
+
+# More than one BIN directory was specified.  We cannot handle the
+# latter case within a single make invocation, so set up recursive
+# targets for each BIN directory.  Use exactly one target for each BIN
+# directory since running multiple make invocations within the same
+# BIN directory is likely to cause problems.
+#
+# Leave $(BIN) undefined.  This has implications for any target that
+# depends on $(BIN); such targets should be made conditional upon the
+# existence of $(BIN).
+#
+BIN_GOALS_FIRST        := $(foreach BGB,$(BIN_GOALS_BINS),\
+                            $(firstword $(filter $(BGB)/%,$(BIN_GOALS))))
+BIN_GOALS_OTHER        := $(filter-out $(BIN_GOALS_FIRST),$(BIN_GOALS))
+
+$(BIN_GOALS_FIRST) : % : BIN_RECURSE
+       $(Q)$(MAKE) --no-print-directory BIN=$(firstword $(subst /, ,$@)) \
+           $(filter $(firstword $(subst /, ,$@))/%, $(BIN_GOALS))
+$(BIN_GOALS_OTHER) : % : BIN_RECURSE
+       $(Q)$(TRUE)
+.PHONY : BIN_RECURSE
+
+endif # NUM_BINS == 1
+endif # NUM_BINS == 0
+
+ifdef BIN
+
+# Create $(BIN) directory if it doesn't exist yet
+#
+ifeq ($(wildcard $(BIN)),)
+$(shell $(MKDIR) -p $(BIN))
+endif
+
+# Target to allow e.g. "make bin-efi arch"
+#
+$(BIN) :
+       @# Do nothing, silently
+.PHONY : $(BIN)
+
+# Remove everything in $(BIN) for a "make clean"
+#
+CLEANUP        += $(BIN)/*.* # Avoid picking up directories
+
+endif # defined(BIN)
+
+# Determine whether or not we need to include the dependency files
+#
+NO_DEP_TARGETS := $(BIN) clean veryclean
+ifeq ($(MAKECMDGOALS),)
+NEED_DEPS      := 1
+endif
+ifneq ($(strip $(filter-out $(NO_DEP_TARGETS),$(MAKECMDGOALS))),)
+NEED_DEPS      := 1
+endif
+
+###############################################################################
+#
+# Select build architecture and platform based on $(BIN)
+#
+# BIN has the form bin[-[arch-]platform]
+
+ARCHS          := $(patsubst arch/%,%,$(wildcard arch/*))
+PLATFORMS      := $(patsubst config/defaults/%.h,%,\
+                    $(wildcard config/defaults/*.h))
+archs :
+       @$(ECHO) $(ARCHS)
+
+platforms :
+       @$(ECHO) $(PLATFORMS)
+
+ifdef BIN
+
+# Determine architecture portion of $(BIN), if present
+BIN_ARCH       := $(strip $(foreach A,$(ARCHS),\
+                            $(patsubst bin-$(A)-%,$(A),\
+                              $(filter bin-$(A)-%,$(BIN)))))
+
+# Determine platform portion of $(BIN), if present
+ifeq ($(BIN_ARCH),)
+BIN_PLATFORM   := $(patsubst bin-%,%,$(filter bin-%,$(BIN)))
+else
+BIN_PLATFORM   := $(patsubst bin-$(BIN_ARCH)-%,%,$(BIN))
+endif
+
+# Determine build architecture
+DEFAULT_ARCH   := i386
+ARCH           := $(firstword $(BIN_ARCH) $(DEFAULT_ARCH))
+CFLAGS         += -DARCH=$(ARCH)
+arch :
+       @$(ECHO) $(ARCH)
+.PHONY : arch
+
+# Determine build platform
+DEFAULT_PLATFORM := pcbios
+PLATFORM       := $(firstword $(BIN_PLATFORM) $(DEFAULT_PLATFORM))
+CFLAGS         += -DPLATFORM=$(PLATFORM)
+platform :
+       @$(ECHO) $(PLATFORM)
+
+endif # defined(BIN)
+
+# Include architecture-specific Makefile
+ifdef ARCH
+MAKEDEPS       += arch/$(ARCH)/Makefile
+include arch/$(ARCH)/Makefile
+endif
+
+# Include architecture-specific include path
+ifdef ARCH
+INCDIRS                += arch/$(ARCH)/include
+INCDIRS                += arch/$(ARCH)/include/$(PLATFORM)
+endif
+
+###############################################################################
+#
+# Source file handling
+
+# SRCDIRS lists all directories containing source files.
+srcdirs :
+       @$(ECHO) $(SRCDIRS)
+
+# SRCS lists all .c or .S files found in any SRCDIR
+#
+SRCS   += $(wildcard $(patsubst %,%/*.c,$(SRCDIRS)))
+SRCS   += $(wildcard $(patsubst %,%/*.S,$(SRCDIRS)))
+srcs :
+       @$(ECHO) $(SRCS)
+
+# AUTO_SRCS lists all files in SRCS that are not mentioned in
+# NON_AUTO_SRCS.  Files should be added to NON_AUTO_SRCS if they
+# cannot be built using the standard build template.
+#
+AUTO_SRCS = $(filter-out $(NON_AUTO_SRCS),$(SRCS))
+autosrcs :
+       @$(ECHO) $(AUTO_SRCS)
+
+# Just about everything else in this section depends upon having
+# $(BIN) set
+
+ifdef BIN
+
+# INCDIRS lists the include path
+incdirs :
+       @$(ECHO) $(INCDIRS)
+
+# Common flags
+#
+CFLAGS         += $(foreach INC,$(INCDIRS),-I$(INC))
+CFLAGS         += -Os
+CFLAGS         += -g
+ifeq ($(CCTYPE),gcc)
+CFLAGS         += -ffreestanding
+CFLAGS         += -Wall -W -Wformat-nonliteral
+HOST_CFLAGS    += -Wall -W -Wformat-nonliteral
+endif
+ifeq ($(CCTYPE),icc)
+CFLAGS         += -fno-builtin
+CFLAGS         += -no-ip
+CFLAGS         += -no-gcc
+CFLAGS         += -diag-disable 111 # Unreachable code
+CFLAGS         += -diag-disable 128 # Unreachable loop
+CFLAGS         += -diag-disable 170 # Array boundary checks
+CFLAGS         += -diag-disable 177 # Unused functions
+CFLAGS         += -diag-disable 181 # printf() format checks
+CFLAGS         += -diag-disable 188 # enum strictness
+CFLAGS         += -diag-disable 193 # Undefined preprocessor identifiers
+CFLAGS         += -diag-disable 280 # switch ( constant )
+CFLAGS         += -diag-disable 310 # K&R parameter lists
+CFLAGS         += -diag-disable 424 # Extra semicolon
+CFLAGS         += -diag-disable 589 # Declarations mid-code
+CFLAGS         += -diag-disable 593 # Unused variables
+CFLAGS         += -diag-disable 810 # Casting ints to smaller ints
+CFLAGS         += -diag-disable 981 # Sequence point violations
+CFLAGS         += -diag-disable 1292 # Ignored attributes
+CFLAGS         += -diag-disable 1338 # void pointer arithmetic
+CFLAGS         += -diag-disable 1361 # Variable-length arrays
+CFLAGS         += -diag-disable 1418 # Missing prototypes
+CFLAGS         += -diag-disable 1419 # Missing prototypes
+CFLAGS         += -diag-disable 1599 # Hidden variables
+CFLAGS         += -Wall -Wmissing-declarations
+endif
+CFLAGS         += $(WORKAROUND_CFLAGS) $(EXTRA_CFLAGS)
+ASFLAGS                += $(WORKAROUND_ASFLAGS) $(EXTRA_ASFLAGS)
+LDFLAGS                += $(WORKAROUND_LDFLAGS) $(EXTRA_LDFLAGS)
+HOST_CFLAGS    += -O2 -g
+
+# Inhibit -Werror if NO_WERROR is specified on make command line
+#
+ifneq ($(NO_WERROR),1)
+CFLAGS         += -Werror
+ASFLAGS                += --fatal-warnings
+HOST_CFLAGS    += -Werror
+endif
+
+# Function trace recorder state in the last build.  This is needed
+# in order to correctly rebuild whenever the function recorder is
+# enabled/disabled.
+#
+FNREC_STATE    := $(BIN)/.fnrec.state
+ifeq ($(wildcard $(FNREC_STATE)),)
+FNREC_OLD      := <invalid>
+else
+FNREC_OLD      := $(shell cat $(FNREC_STATE))
+endif
+ifeq ($(FNREC_OLD),$(FNREC))
+$(FNREC_STATE) :
+else
+$(FNREC_STATE) : clean
+$(shell $(ECHO) "$(FNREC)" > $(FNREC_STATE))
+endif
+
+VERYCLEANUP    += $(FNREC_STATE)
+MAKEDEPS       += $(FNREC_STATE)
+
+ifeq ($(FNREC),1)
+# Enabling -finstrument-functions affects gcc's analysis and leads to spurious
+# warnings about use of uninitialised variables.
+#
+CFLAGS         += -Wno-uninitialized
+CFLAGS         += -finstrument-functions
+CFLAGS         += -finstrument-functions-exclude-file-list=core/fnrec.c
+endif
+
+# Enable per-item sections and section garbage collection.  Note that
+# some older versions of gcc support -fdata-sections but treat it as
+# implying -fno-common, which would break our build.  Some other older
+# versions issue a spurious and uninhibitable warning if
+# -ffunction-sections is used with -g, which would also break our
+# build since we use -Werror.
+#
+ifeq ($(CCTYPE),gcc)
+DS_TEST                = $(ECHO) 'char x;' | \
+                 $(CC) -fdata-sections -S -x c - -o - 2>/dev/null | \
+                 grep -E '\.comm' > /dev/null
+DS_FLAGS       := $(shell $(DS_TEST) && $(ECHO) '-fdata-sections')
+FS_TEST                = $(CC) -ffunction-sections -g -c -x c /dev/null \
+                 -o /dev/null 2>/dev/null
+FS_FLAGS       := $(shell $(FS_TEST) && $(ECHO) '-ffunction-sections')
+CFLAGS         += $(FS_FLAGS) $(DS_FLAGS)
+endif
+LDFLAGS                += --gc-sections
+
+# Force creation of static binaries (required for OpenBSD, does no
+# harm on other platforms).
+#
+LDFLAGS                += -static
+
+# compiler.h is needed for our linking and debugging system
+#
+CFLAGS         += -include include/compiler.h
+
+# CFLAGS for specific object types
+#
+CFLAGS_c       +=
+CFLAGS_S       += -DASSEMBLY
+
+# Base object name of the current target
+#
+OBJECT         = $(firstword $(subst ., ,$(@F)))
+
+# CFLAGS for specific object files.  You can define
+# e.g. CFLAGS_rtl8139, and have those flags automatically used when
+# compiling bin/rtl8139.o.
+#
+OBJ_CFLAGS     = $(CFLAGS_$(OBJECT)) -DOBJECT=$(subst -,_,$(OBJECT))
+$(BIN)/%.flags :
+       @$(ECHO) $(OBJ_CFLAGS)
+
+# ICC requires postprocessing objects to fix up table alignments
+#
+ifeq ($(CCTYPE),icc)
+POST_O         = && $(ICCFIX) $@
+POST_O_DEPS    := $(ICCFIX)
+else
+POST_O         :=
+POST_O_DEPS    :=
+endif
+
+# Rules for specific object types.
+#
+COMPILE_c      = $(CC) $(CFLAGS) $(CFLAGS_c) $(OBJ_CFLAGS)
+RULE_c         = $(Q)$(COMPILE_c) -c $< -o $@ $(POST_O)
+RULE_c_to_dbg%.o = $(Q)$(COMPILE_c) -DDBGLVL_MAX=$* -c $< -o $@ $(POST_O)
+RULE_c_to_c    = $(Q)$(COMPILE_c) -E -c $< > $@
+RULE_c_to_s    = $(Q)$(COMPILE_c) -S -g0 -c $< -o $@
+
+PREPROCESS_S   = $(CPP) $(CFLAGS) $(CFLAGS_S) $(OBJ_CFLAGS)
+ASSEMBLE_S     = $(AS) $(ASFLAGS)
+RULE_S         = $(Q)$(PREPROCESS_S) $< | $(ASSEMBLE_S) -o $@
+RULE_S_to_dbg%.o = $(Q)$(PREPROCESS_S) -DDBGLVL_MAX=$* $< | $(ASSEMBLE_S) -o $@
+RULE_S_to_s    = $(Q)$(PREPROCESS_S) $< > $@
+
+DEBUG_TARGETS  += dbg%.o c s
+
+# List of embedded images included in the last build of embedded.o.
+# This is needed in order to correctly rebuild embedded.o whenever the
+# list of objects changes.
+#
+EMBED          := $(EMBEDDED_IMAGE) # Maintain backwards compatibility
+EMBEDDED_LIST  := $(BIN)/.embedded.list
+ifeq ($(wildcard $(EMBEDDED_LIST)),)
+EMBED_OLD := <invalid>
+else
+EMBED_OLD := $(shell cat $(EMBEDDED_LIST))
+endif
+ifneq ($(EMBED_OLD),$(EMBED))
+$(shell $(ECHO) "$(EMBED)" > $(EMBEDDED_LIST))
+endif
+
+$(EMBEDDED_LIST) : $(MAKEDEPS)
+
+VERYCLEANUP    += $(EMBEDDED_LIST)
+
+EMBEDDED_FILES := $(subst $(COMMA), ,$(EMBED))
+EMBED_ALL      := $(foreach i,$(call seq,1,$(words $(EMBEDDED_FILES))),\
+                    EMBED ( $(i), \"$(word $(i), $(EMBEDDED_FILES))\",\
+                            \"$(notdir $(word $(i),$(EMBEDDED_FILES)))\" ))
+
+embedded_DEPS += $(EMBEDDED_FILES) $(EMBEDDED_LIST)
+
+CFLAGS_embedded = -DEMBED_ALL="$(EMBED_ALL)"
+
+# List of trusted root certificates
+#
+TRUSTED_LIST   := $(BIN)/.trusted.list
+ifeq ($(wildcard $(TRUSTED_LIST)),)
+TRUST_OLD := <invalid>
+else
+TRUST_OLD := $(shell cat $(TRUSTED_LIST))
+endif
+ifneq ($(TRUST_OLD),$(TRUST))
+$(shell $(ECHO) "$(TRUST)" > $(TRUSTED_LIST))
+endif
+
+$(TRUSTED_LIST) : $(MAKEDEPS)
+
+VERYCLEANUP    += $(TRUSTED_LIST)
+
+# Trusted root certificate fingerprints
+#
+TRUSTED_CERTS  := $(subst $(COMMA), ,$(TRUST))
+TRUSTED_FPS    := $(foreach CERT,$(TRUSTED_CERTS),\
+                    0x$(subst :,$(COMMA) 0x,$(lastword $(subst =, ,\
+                        $(shell $(OPENSSL) x509 -in $(CERT) -noout -sha256 \
+                                -fingerprint))))$(COMMA))
+
+rootcert_DEPS += $(TRUSTED_FILES) $(TRUSTED_LIST)
+
+CFLAGS_rootcert = $(if $(TRUSTED_FPS),-DTRUSTED="$(TRUSTED_FPS)")
+
+# List of embedded certificates
+#
+CERT_LIST := $(BIN)/.certificate.list
+ifeq ($(wildcard $(CERT_LIST)),)
+CERT_OLD := <invalid>
+else
+CERT_OLD := $(shell cat $(CERT_LIST))
+endif
+ifneq ($(CERT_OLD),$(CERT))
+$(shell $(ECHO) "$(CERT)" > $(CERT_LIST))
+endif
+
+$(CERT_LIST) : $(MAKEDEPS)
+
+VERYCLEANUP += $(CERT_LIST)
+
+# Embedded certificates concatenated and then split into one file per
+# certificate (even if original files contained certificate chains)
+#
+CERT_FILES := $(subst $(COMMA), ,$(CERT))
+CERT_CONCAT := $(BIN)/.certificates.pem
+
+ifneq ($(CERT),)
+
+CERT_COUNT := $(shell grep "BEGIN CERTIFICATE" $(CERT_FILES) | wc -l)
+
+$(CERT_CONCAT) : $(CERT_FILES) $(CERT_LIST)
+       $(Q)cat $(CERT_FILES) > $@
+
+# We must use an (otherwise unnecessary) pattern rule here to encode
+# the fact that one "csplit" command generates multiple targets
+CERT_PEMS := $(foreach i,$(call seq,1,$(CERT_COUNT)),\
+              $(BIN)/.certificate.pem.$(i))
+$(subst .pem.,.%.,$(CERT_PEMS)) : $(BIN)/.certificates.%
+       $(Q)$(CSPLIT) -q -n 1 -f $(BIN)/.certificate.pem. $< \
+               '/BEGIN CERTIFICATE/' '{*}'
+
+CERT_DERS := $(subst .certificate.pem.,.certificate.der.,$(CERT_PEMS))
+$(BIN)/.certificate.der.% : $(BIN)/.certificate.pem.%
+       $(Q)$(OPENSSL) x509 -in $< -outform DER -out $@
+
+CERT_ALL := $(foreach i,$(call seq,1,$(CERT_COUNT)),\
+             CERT ( $(i), \"$(word $(i),$(CERT_DERS))\" ))
+
+endif
+
+certstore_DEPS += $(CERT_LIST) $(CERT_FILES) $(CERT_PEMS) $(CERT_DERS)
+
+CFLAGS_certstore += -DCERT_ALL="$(CERT_ALL)"
+
+CLEANUP += $(BIN)/.certificate.* $(BIN)/.certificates.*
+
+# (Single-element) list of private keys
+#
+ifdef KEY
+PRIVKEY        := $(KEY) # Maintain backwards compatibility
+endif
+PRIVKEY_LIST := $(BIN)/.private_key.list
+ifeq ($(wildcard $(PRIVKEY_LIST)),)
+PRIVKEY_OLD := <invalid>
+else
+PRIVKEY_OLD := $(shell cat $(PRIVKEY_LIST))
+endif
+ifneq ($(PRIVKEY_OLD),$(PRIVKEY))
+$(shell $(ECHO) "$(PRIVKEY)" > $(PRIVKEY_LIST))
+endif
+
+$(PRIVKEY_LIST) : $(MAKEDEPS)
+
+VERYCLEANUP += $(PRIVKEY_LIST)
+
+# Embedded private key
+#
+PRIVKEY_INC := $(BIN)/.private_key.der
+
+ifdef PRIVKEY
+$(PRIVKEY_INC) : $(PRIVKEY) $(PRIVKEY_LIST)
+       $(Q)$(OPENSSL) rsa -in $< -outform DER -out $@
+
+privkey_DEPS += $(PRIVKEY_INC)
+endif
+
+CLEANUP += $(BIN)/.private_key.*
+
+privkey_DEPS += $(PRIVKEY_LIST)
+
+CFLAGS_privkey += $(if $(PRIVKEY),-DPRIVATE_KEY="\"$(PRIVKEY_INC)\"")
+
+# (Single-element) list of named configurations
+#
+CONFIG_LIST := $(BIN)/.config.list
+ifeq ($(wildcard $(CONFIG_LIST)),)
+CONFIG_OLD := <invalid>
+else
+CONFIG_OLD := $(shell cat $(CONFIG_LIST))
+endif
+ifneq ($(CONFIG_OLD),$(CONFIG))
+$(shell $(ECHO) "$(CONFIG)" > $(CONFIG_LIST))
+endif
+
+$(CONFIG_LIST) : $(MAKEDEPS)
+
+VERYCLEANUP += $(CONFIG_LIST)
+
+# Named configurations
+#
+ifneq ($(CONFIG),)
+ifneq ($(wildcard config/$(CONFIG)),)
+CFLAGS += -DCONFIG=$(CONFIG)
+endif
+CFLAGS += -DLOCAL_CONFIG=$(CONFIG)
+endif
+
+config/named.h : $(CONFIG_LIST)
+       $(Q)$(TOUCH) $@
+
+.PRECIOUS : config/named.h
+
+# These files use .incbin inline assembly to include a binary file.
+# Unfortunately ccache does not detect this dependency and caches
+# builds even when the binary file has changed.
+#
+$(BIN)/embedded.% : override CC := env CCACHE_DISABLE=1 $(CC)
+$(BIN)/certstore.% : override CC := env CCACHE_DISABLE=1 $(CC)
+$(BIN)/privkey.% : override CC := env CCACHE_DISABLE=1 $(CC)
+
+# Debug message autocolourisation range
+#
+DBGCOL_LIST    := $(BIN)/.dbgcol.list
+ifeq ($(wildcard $(DBGCOL_LIST)),)
+DBGCOL_OLD := <invalid>
+else
+DBGCOL_OLD := $(shell cat $(DBGCOL_LIST))
+endif
+ifneq ($(DBGCOL_OLD),$(DBGCOL))
+$(shell $(ECHO) "$(DBGCOL)" > $(DBGCOL_LIST))
+endif
+
+$(DBGCOL_LIST) : $(MAKEDEPS)
+
+VERYCLEANUP += $(DBGCOL_LIST)
+
+DBGCOL_COLOURS := $(subst -, ,$(DBGCOL))
+DBGCOL_MIN := $(word 1,$(DBGCOL_COLOURS))
+DBGCOL_MAX := $(word 2,$(DBGCOL_COLOURS))
+
+debug_DEPS += $(DBGCOL_LIST)
+
+CFLAGS_debug += $(if $(DBGCOL_MIN),-DDBGCOL_MIN=$(DBGCOL_MIN))
+CFLAGS_debug += $(if $(DBGCOL_MAX),-DDBGCOL_MAX=$(DBGCOL_MAX))
+
+# We automatically generate rules for any file mentioned in AUTO_SRCS
+# using the following set of templates.  We use $(eval ...) if
+# available, otherwise we generate separate Makefile fragments and
+# include them.
+
+# deps_template : generate dependency list for a given source file
+#
+# $(1) is the full path to the source file (e.g. "drivers/net/rtl8139.c")
+#
+define deps_template_file
+$(call deps_template_parts,$(1),$(subst .,,$(suffix $(1))),$(basename $(notdir $(1))))
+endef
+#
+# $(1) is the full path to the source file (e.g. "drivers/net/rtl8139.c")
+# $(2) is the source type (e.g. "c")
+# $(3) is the source base name (e.g. "rtl8139")
+#
+define deps_template_parts
+       @$(ECHO) "  [DEPS] $(1)"
+       @$(MKDIR) -p $(BIN)/deps/$(dir $(1))
+       $(Q)$(CPP) $(CFLAGS) $(CFLAGS_$(2)) $(CFLAGS_$(3)) -DOBJECT=$(3) \
+               -Wno-error -M $(1) -MG -MP | \
+               sed 's/\.o\s*:/_DEPS +=/' > $(BIN)/deps/$(1).d
+       $(Q)$(if $(findstring drivers/,$(1)),\
+          $(PERL) $(PARSEROM) $(1) >> $(BIN)/deps/$(1).d)
+endef
+
+# rules_template : generate rules for a given source file
+#
+# $(1) is the full path to the source file (e.g. "drivers/net/rtl8139.c")
+#
+define rules_template
+$(call rules_template_parts,$(1),$(subst .,,$(suffix $(1))),$(basename $(notdir $(1))))
+endef
+#
+# $(1) is the full path to the source file (e.g. "drivers/net/rtl8139.c")
+# $(2) is the source type (e.g. "c")
+# $(3) is the source base name (e.g. "rtl8139")
+#
+define rules_template_parts
+$$(BIN)/$(3).o : $(1) $$(MAKEDEPS) $$(POST_O_DEPS) $$($(3)_DEPS)
+       $$(QM)$(ECHO) "  [BUILD] $$@"
+       $$(RULE_$(2))
+BOBJS += $$(BIN)/$(3).o
+$(foreach TGT,$(DEBUG_TARGETS),$(if $(RULE_$(2)_to_$(TGT)),$(NEWLINE)$(call rules_template_target,$(1),$(2),$(3),$(TGT))))
+$$(BIN)/deps/$(1).d : $$($(3)_DEPS)
+TAGS : $$($(3)_DEPS)
+endef
+#
+# $(1) is the full path to the source file (e.g. "drivers/net/rtl8139.c")
+# $(2) is the source type (e.g. "c")
+# $(3) is the source base name (e.g. "rtl8139")
+# $(4) is the destination type (e.g. "dbg%.o")
+#
+define rules_template_target
+$$(BIN)/$(3).$(4) : $(1) $$(MAKEDEPS) $$(POST_O_DEPS) $$($(3)_DEPS)
+       $$(QM)$(ECHO) "  [BUILD] $$@"
+       $$(RULE_$(2)_to_$(4))
+$(TGT)_OBJS += $$(BIN)/$(3).$(4)
+endef
+#
+# $(1) is the full path to the source file (e.g. "drivers/net/rtl8139.c")
+#
+define rules_template_file
+       @$(ECHO) "  [RULES] $(1)"
+       @$(MKDIR) -p $(BIN)/rules/$(dir $(1))
+       @$(ECHO_E) '$(subst $(NEWLINE),\n,$(call rules_template,$(1)))' \
+                > $(BIN)/rules/$(1).r
+endef
+
+# Generate the dependency files
+#
+$(BIN)/deps/%.d : % $(MAKEDEPS) $(PARSEROM)
+       $(call deps_template_file,$<)
+
+# Calculate list of dependency files
+#
+AUTO_DEPS      = $(patsubst %,$(BIN)/deps/%.d,$(AUTO_SRCS))
+autodeps :
+       @$(ECHO) $(AUTO_DEPS)
+VERYCLEANUP    += $(BIN)/deps
+
+# Include dependency files
+#
+ifdef NEED_DEPS
+ifneq ($(AUTO_DEPS),)
+-include $(AUTO_DEPS)
+endif
+endif
+
+# Generate the rules files
+#
+$(BIN)/rules/%.r : % $(MAKEDEPS)
+       $(call rules_template_file,$<)
+
+# Calculate list of rules files
+#
+AUTO_RULES     = $(patsubst %,$(BIN)/rules/%.r,$(AUTO_SRCS))
+autorules :
+       @$(ECHO) $(AUTO_RULES)
+VERYCLEANUP    += $(BIN)/rules
+
+# Evaluate rules (or include rules files)
+#
+ifdef NEED_DEPS
+ifneq ($(AUTO_RULES),)
+ifneq ($(HAVE_EVAL),)
+$(foreach SRC,$(AUTO_SRCS),$(eval $(call rules_template,$(SRC))))
+else
+-include $(AUTO_RULES)
+endif
+endif
+endif
+
+# The following variables are created by the rules files
+#
+bobjs :
+       @$(ECHO) $(BOBJS)
+drivers :
+       @$(ECHO) $(DRIVERS)
+.PHONY : drivers
+roms :
+       @$(ECHO) $(ROMS)
+
+# Generate error usage information
+#
+$(BIN)/%.einfo : $(BIN)/%.o
+       $(QM)$(ECHO) "  [EINFO] $@"
+       $(Q)$(OBJCOPY) -O binary -j .einfo --set-section-flags .einfo=alloc \
+               $< $@
+
+EINFOS         := $(patsubst $(BIN)/%.o,$(BIN)/%.einfo,$(BOBJS))
+$(BIN)/errors : $(EINFOS) $(EINFO)
+       $(QM)$(ECHO) "  [EINFO] $@"
+       $(Q)$(EINFO) $(EINFOS) | sort > $@
+CLEANUP                += $(BIN)/errors        # Doesn't match the $(BIN)/*.* pattern
+
+# Generate the NIC file from the parsed source files.  The NIC file is
+# only for rom-o-matic.
+#
+$(BIN)/NIC : $(AUTO_DEPS)
+       @$(ECHO) '# This is an automatically generated file, do not edit' > $@
+       @$(ECHO) '# It does not affect anything in the build, ' \
+            'it is only for rom-o-matic' >> $@
+       @$(ECHO) >> $@
+       @perl -ne 'chomp; print "$$1\n" if /\# NIC\t(.*)$$/' $^ >> $@
+CLEANUP                += $(BIN)/NIC   # Doesn't match the $(BIN)/*.* pattern
+
+# Analyse a target name (e.g. "bin/dfe538--prism2_pci.rom.tmp") and
+# derive the variables:
+# 
+# TGT_ELEMENTS : the elements of the target (e.g. "dfe538 prism2_pci")
+# TGT_PREFIX   : the prefix type (e.g. "pcirom")
+# TGT_DRIVERS  : the driver for each element (e.g. "rtl8139 prism2_pci")
+# TGT_ROM_NAME : the ROM name (e.g. "dfe538")
+#
+DRIVERS_ipxe   = $(DRIVERS)
+CARD_DRIVER    = $(firstword $(DRIVER_$(1)) $(1))
+TGT_ELEMENTS   = $(subst --, ,$(firstword $(subst ., ,$(notdir $@))))
+TGT_ROM_NAME   = $(firstword $(TGT_ELEMENTS))
+TGT_DRIVERS    = $(strip $(if $(DRIVERS_$(TGT_ROM_NAME)), \
+                              $(DRIVERS_$(TGT_ROM_NAME)), \
+                              $(foreach TGT_ELEMENT,$(TGT_ELEMENTS), \
+                                $(call CARD_DRIVER,$(TGT_ELEMENT))) ))
+TGT_PREFIX_NAME        = $(word 2,$(subst ., ,$(notdir $@)))
+TGT_PREFIX     = $(strip $(if $(filter rom,$(TGT_PREFIX_NAME)), \
+                              $(ROM_TYPE_$(TGT_ROM_NAME))rom, \
+                              $(TGT_PREFIX_NAME)))
+
+# Look up ROM IDs for the current target
+# (e.g. "bin/dfe538--prism2_pci.rom.tmp") and derive the variables:
+#
+# TGT_PCI_VENDOR : the PCI vendor ID (e.g. "0x1186")
+# TGT_PCI_DEVICE : the PCI device ID (e.g. "0x1300")
+#
+TGT_PCI_VENDOR = $(PCI_VENDOR_$(TGT_ROM_NAME))
+TGT_PCI_DEVICE = $(PCI_DEVICE_$(TGT_ROM_NAME))
+
+# Calculate link-time options for the current target
+# (e.g. "bin/dfe538--prism2_pci.rom.tmp") and derive the variables:
+#
+# TGT_LD_DRIVERS : symbols to require in order to drag in the relevant drivers
+#                 (e.g. "obj_rtl8139 obj_prism2_pci")
+# TGT_LD_IDS :     symbols to define in order to fill in ID structures in the
+#                 ROM header (e.g."pci_vendor_id=0x1186 pci_device_id=0x1300")
+#
+TGT_LD_DRIVERS = $(subst -,_,$(patsubst %,obj_%,$(TGT_DRIVERS)))
+TGT_LD_IDS     = pci_vendor_id=$(firstword $(TGT_PCI_VENDOR) 0) \
+                 pci_device_id=$(firstword $(TGT_PCI_DEVICE) 0)
+
+ifndef TGT_LD_ENTRY
+TGT_LD_ENTRY   = _$(TGT_PREFIX)_start
+endif
+
+# Calculate linker flags based on link-time options for the current
+# target type (e.g. "bin/dfe538--prism2_pci.rom.tmp") and derive the
+# variables:
+#
+# TGT_LD_FLAGS : target-specific flags to pass to linker (e.g.
+#               "-u obj_zpciprefix -u obj_rtl8139 -u obj_prism2_pci
+#                --defsym pci_vendor=0x1186 --defsym pci_device=0x1300")
+#
+TGT_LD_FLAGS   = $(foreach SYM,$(TGT_LD_ENTRY) $(TGT_LD_DRIVERS) obj_config,\
+                   -u $(SYM) --defsym check_$(SYM)=$(SYM) ) \
+                 $(patsubst %,--defsym %,$(TGT_LD_IDS)) \
+                 -e $(TGT_LD_ENTRY)
+
+# Calculate list of debugging versions of objects to be included in
+# the target.
+#
+DEBUG_LIST     = $(subst $(COMMA), ,$(DEBUG))
+DEBUG_OBJ_LEVEL        = $(firstword $(word 2,$(subst :, ,$(1))) 1)
+DEBUG_OBJ_BASE = $(word 1,$(subst :, ,$(1))).dbg$(call DEBUG_OBJ_LEVEL,$(1))
+DEBUG_OBJ      = $(BIN)/$(call DEBUG_OBJ_BASE,$(1)).o
+DEBUG_ORIG_OBJ = $(BIN)/$(word 1,$(subst :, ,$(1))).o
+DEBUG_OBJS     = $(foreach D,$(DEBUG_LIST),$(call DEBUG_OBJ,$(D)))
+DEBUG_ORIG_OBJS        = $(foreach D,$(DEBUG_LIST),$(call DEBUG_ORIG_OBJ,$(D)))
+BLIB_OBJS      = $(DEBUG_OBJS) $(filter-out $(DEBUG_ORIG_OBJS),$(BOBJS))
+
+# Print out all derived information for a given target.
+#
+$(BIN)/%.info :
+       @$(ECHO) 'Elements             : $(TGT_ELEMENTS)'
+       @$(ECHO) 'Prefix               : $(TGT_PREFIX)'
+       @$(ECHO) 'Drivers              : $(TGT_DRIVERS)'
+       @$(ECHO) 'ROM name             : $(TGT_ROM_NAME)'
+       @$(ECHO)
+       @$(ECHO) 'PCI vendor           : $(TGT_PCI_VENDOR)'
+       @$(ECHO) 'PCI device           : $(TGT_PCI_DEVICE)'
+       @$(ECHO)
+       @$(ECHO) 'LD driver symbols    : $(TGT_LD_DRIVERS)'
+       @$(ECHO) 'LD ID symbols        : $(TGT_LD_IDS)'
+       @$(ECHO) 'LD entry point       : $(TGT_LD_ENTRY)'
+       @$(ECHO)
+       @$(ECHO) 'LD target flags      : $(TGT_LD_FLAGS)'
+       @$(ECHO)
+       @$(ECHO) 'Debugging objects    : $(DEBUG_OBJS)'
+       @$(ECHO) 'Replaced objects     : $(DEBUG_ORIG_OBJS)'
+
+# List of objects included in the last build of blib.  This is needed
+# in order to correctly rebuild blib whenever the list of objects
+# changes.
+#
+BLIB_LIST      := $(BIN)/.blib.list
+ifeq ($(wildcard $(BLIB_LIST)),)
+BLIB_OBJS_OLD  := <invalid>
+else
+BLIB_OBJS_OLD  := $(shell cat $(BLIB_LIST))
+endif
+ifneq ($(BLIB_OBJS_OLD),$(BLIB_OBJS))
+$(shell $(ECHO) "$(BLIB_OBJS)" > $(BLIB_LIST))
+endif
+
+$(BLIB_LIST) : $(MAKEDEPS)
+
+VERYCLEANUP    += $(BLIB_LIST)
+
+# Library of all objects
+#
+BLIB           = $(BIN)/blib.a
+$(BLIB) : $(BLIB_OBJS) $(BLIB_LIST) $(MAKEDEPS)
+       $(Q)$(RM) $(BLIB)
+       $(QM)$(ECHO) "  [AR] $@"
+       $(Q)$(AR) r $@ $(BLIB_OBJS)
+       $(Q)$(RANLIB) $@
+blib : $(BLIB)
+
+# Command to generate build ID.  Must be unique for each $(BIN)/%.tmp,
+# even within the same build run.
+#
+BUILD_ID_CMD   := perl -e 'printf "0x%08x", int ( rand ( 0xffffffff ) );'
+
+# Build timestamp
+#
+BUILD_TIMESTAMP := $(shell date +%s)
+
+# Build version
+#
+GIT_INDEX := $(if $(GITVERSION),$(if $(wildcard ../.git/index),../.git/index))
+$(BIN)/version.%.o : core/version.c $(MAKEDEPS) $(GIT_INDEX)
+       $(QM)$(ECHO) "  [VERSION] $@"
+       $(Q)$(COMPILE_c) -DBUILD_NAME="\"$*\"" \
+               -DVERSION_MAJOR=$(VERSION_MAJOR) \
+               -DVERSION_MINOR=$(VERSION_MINOR) \
+               -DVERSION_PATCH=$(VERSION_PATCH) \
+               -DVERSION="\"$(VERSION)\"" \
+               -c $< -o $@
+
+# Build an intermediate object file from the objects required for the
+# specified target.
+#
+$(BIN)/%.tmp : $(BIN)/version.%.o $(BLIB) $(MAKEDEPS) $(LDSCRIPT)
+       $(QM)$(ECHO) "  [LD] $@"
+       $(Q)$(LD) $(LDFLAGS) -T $(LDSCRIPT) $(TGT_LD_FLAGS) $< $(BLIB) -o $@ \
+               --defsym _build_id=`$(BUILD_ID_CMD)` \
+               --defsym _build_timestamp=$(BUILD_TIMESTAMP) \
+               -Map $(BIN)/$*.tmp.map
+       $(Q)$(OBJDUMP) -ht $@ | $(PERL) $(SORTOBJDUMP) >> $(BIN)/$*.tmp.map
+
+# Keep intermediate object file (useful for debugging)
+.PRECIOUS : $(BIN)/%.tmp
+
+# Show a linker map for the specified target
+#
+$(BIN)/%.map : $(BIN)/%.tmp
+       @less $(BIN)/$*.tmp.map
+
+# Get objects list for the specified target
+#
+define objs_list
+       $(sort $(foreach OBJ_SYMBOL,\
+                $(filter obj_%,$(shell $(NM) $(1) | cut -d" " -f3)),\
+                $(patsubst obj_%,%,$(OBJ_SYMBOL))))
+endef
+$(BIN)/%.objs : $(BIN)/%.tmp
+       $(Q)$(ECHO) $(call objs_list,$<)
+$(BIN)/%.sizes : $(BIN)/%.tmp
+       $(Q)$(SIZE) -t $(foreach OBJ,$(call objs_list,$<),$(wildcard $(BIN)/$(subst _,?,$(OBJ)).o)) | \
+               sort -g
+
+# Get dependency list for the specified target
+#
+define deps_list
+       $(sort $(foreach OBJ,$(call objs_list,$(1)),$($(OBJ)_DEPS)))
+endef
+$(BIN)/%.deps : $(BIN)/%.tmp
+       $(Q)$(ECHO) $(call deps_list,$<)
+
+# Get unneeded source files for the specified target
+#
+define nodeps_list
+       $(sort $(filter-out $(call deps_list,$(1)),\
+                $(foreach BOBJ,$(BOBJS),\
+                  $($(basename $(notdir $(BOBJ)))_DEPS))))
+endef
+$(BIN)/%.nodeps : $(BIN)/%.tmp
+       $(Q)$(ECHO) $(call nodeps_list,$<)
+
+# Get licensing verdict for the specified target
+#
+define licensable_deps_list
+       $(filter-out config/local/%.h,\
+         $(filter-out $(BIN)/.%.list,\
+           $(call deps_list,$(1))))
+endef
+define unlicensed_deps_list
+       $(shell grep -L FILE_LICENCE $(call licensable_deps_list,$(1)))
+endef
+define licence_list
+       $(sort $(foreach LICENCE,\
+                $(filter __licence__%,$(shell $(NM) $(1) | cut -d" " -f3)),\
+                $(word 2,$(subst __, ,$(LICENCE)))))
+endef
+$(BIN)/%.licence_list : $(BIN)/%.tmp
+       $(Q)$(ECHO) $(call licence_list,$<)
+$(BIN)/%.licence : $(BIN)/%.tmp
+       $(QM)$(ECHO) "  [LICENCE] $@"
+       $(Q)$(if $(strip $(call unlicensed_deps_list,$<)),\
+               echo -n "Unable to determine licence because the following " ;\
+               echo "files are missing a licence declaration:" ;\
+               echo $(call unlicensed_deps_list,$<);\
+               exit 1,\
+               $(PERL) $(LICENCE) $(call licence_list,$<))
+
+# Extract compression information from intermediate object file
+#
+$(BIN)/%.zinfo : $(BIN)/%.tmp
+       $(QM)$(ECHO) "  [ZINFO] $@"
+       $(Q)$(OBJCOPY) -O binary -j .zinfo $< $@
+
+# Build raw binary file from intermediate object file
+#
+$(BIN)/%.bin : $(BIN)/%.tmp
+       $(QM)$(ECHO) "  [BIN] $@"
+       $(Q)$(OBJCOPY) -O binary -R .zinfo $< $@
+
+# Compress raw binary file
+#
+$(BIN)/%.zbin : $(BIN)/%.bin $(BIN)/%.zinfo $(ZBIN)
+       $(QM)$(ECHO) "  [ZBIN] $@"
+       $(Q)$(ZBIN) $(BIN)/$*.bin $(BIN)/$*.zinfo > $@
+
+# Rules for each media format.  These are generated and placed in an
+# external Makefile fragment.  We could do this via $(eval ...), but
+# that would require make >= 3.80.
+# 
+# Note that there's an alternative way to generate most .rom images:
+# they can be copied from their 'master' ROM image using cp and
+# reprocessed with makerom to add the PCI IDs and ident string.  The
+# relevant rule would look something like:
+#
+#   $(BIN)/dfe538%rom : $(BIN)/rtl8139%rom
+#      cat $< $@
+#      $(FINALISE_rom)
+# 
+# You can derive the ROM/driver relationships using the variables
+# DRIVER_<rom> and/or ROMS_<driver>.
+# 
+# We don't currently do this, because (a) it would require generating
+# yet more Makefile fragments (since you need a rule for each ROM in
+# ROMS), and (b) the linker is so fast that it probably wouldn't make
+# much difference to the overall build time.
+
+# Add NON_AUTO_MEDIA to the media list, so that they show up in the
+# output of "make"
+#
+MEDIA          += $(NON_AUTO_MEDIA)
+
+media :
+       @$(ECHO) $(MEDIA)
+
+AUTO_MEDIA     = $(filter-out $(NON_AUTO_MEDIA),$(MEDIA))
+automedia :
+       @$(ECHO) $(AUTO_MEDIA)
+
+# media_template : create media rules
+#
+# $(1) is the media name (e.g. "rom")
+#
+define media_template
+$(if $(filter $(1),$(AUTO_MEDIA)),$(call auto_media_template,$(1)))
+LIST_$(1) := $$(if $$(LIST_NAME_$(1)),$$($$(LIST_NAME_$(1))),$$(DRIVERS))
+ALL_$(1) = $$(foreach ITEM,$$(LIST_$(1)),$$(BIN)/$$(ITEM).$(1))
+$$(BIN)/all$(1)s : $$(ALL_$(1))
+$$(BIN)/allall : $$(BIN)/all$(1)s
+all$(1)s : $$(BIN)/all$(1)s
+allall : $$(BIN)/allall
+endef
+#
+# $(1) is the media name (e.g. "rom")
+#
+define auto_media_template
+$$(BIN)/%.$(1) : $$(BIN)/%.$(1).zbin
+       $$(QM)echo "  [FINISH] $$@"
+       $$(Q)$$(CP) $$< $$@
+       $$(Q)$$(if $$(PAD_$(1)),$$(PAD_$(1)) $$@)
+       $$(Q)$$(if $$(FINALISE_$(1)),$$(FINALISE_$(1)) $$@)
+endef
+#
+# $(1) is the media name (e.g. "rom")
+#
+define media_template_file
+       @$(ECHO) "  [MEDIARULES] $(1)"
+       @$(MKDIR) -p $(BIN)/rules/$(dir $(1))
+       @$(ECHO_E) '$(subst $(NEWLINE),\n,$(call media_template,$(1)))' \
+               > $(BIN)/rules/$(1).media.r
+endef
+
+# Generate media rules files
+#
+$(BIN)/rules/%.media.r : $(MAKEDEPS)
+       $(call media_template_file,$*)
+
+# Calculate list of media rules files
+#
+MEDIA_RULES            = $(patsubst %,$(BIN)/rules/%.media.r,$(MEDIA))
+mediarules :
+       @$(ECHO) $(MEDIA_RULES)
+
+# Evaluate media rules (or include media rules files)
+#
+ifdef NEED_DEPS
+ifneq ($(MEDIA_RULES),)
+ifneq ($(HAVE_EVAL),)
+$(foreach MEDIUM,$(MEDIA),$(eval $(call media_template,$(MEDIUM))))
+else
+-include $(MEDIA_RULES)
+endif
+endif
+endif
+
+# Alias for ipxe.%
+#
+$(BIN)/etherboot.% : $(BIN)/ipxe.%
+       ln -sf $(notdir $<) $@
+
+endif # defined(BIN)
+
+###############################################################################
+#
+# The compression utilities
+#
+$(NRV2B) : util/nrv2b.c $(MAKEDEPS)
+       $(QM)$(ECHO) "  [HOSTCC] $@"
+       $(Q)$(HOST_CC) $(HOST_CFLAGS) -DENCODE -DDECODE -DMAIN -DVERBOSE \
+                      -DNDEBUG -DBITSIZE=32 -DENDIAN=0 -o $@ $<
+CLEANUP        += $(NRV2B)
+
+$(ZBIN) : util/zbin.c util/nrv2b.c $(MAKEDEPS)
+       $(QM)$(ECHO) "  [HOSTCC] $@"
+       $(Q)$(HOST_CC) $(HOST_CFLAGS) -o $@ $<
+CLEANUP += $(ZBIN)
+
+###############################################################################
+#
+# The EFI image converter
+#
+ELF2EFI_CFLAGS := -I$(BINUTILS_DIR)/include -I$(BFD_DIR)/include \
+                  -I$(ZLIB_DIR)/include -idirafter include
+ELF2EFI_LDFLAGS        := -L$(BINUTILS_DIR)/lib -L$(BFD_DIR)/lib -L$(ZLIB_DIR)/lib \
+                  -lbfd -ldl -liberty -lz -Wl,--no-warn-search-mismatch
+
+$(ELF2EFI32) : util/elf2efi.c $(MAKEDEPS)
+       $(QM)$(ECHO) "  [HOSTCC] $@"
+       $(Q)$(HOST_CC) $(HOST_CFLAGS) $(ELF2EFI_CFLAGS) -DEFI_TARGET_IA32 $< \
+               $(ELF2EFI_LDFLAGS) -o $@
+CLEANUP += $(ELF2EFI32)
+
+$(ELF2EFI64) : util/elf2efi.c $(MAKEDEPS)
+       $(QM)$(ECHO) "  [HOSTCC] $@"
+       $(Q)$(HOST_CC) $(HOST_CFLAGS) $(ELF2EFI_CFLAGS) -DEFI_TARGET_X64 $< \
+               $(ELF2EFI_LDFLAGS) -o $@
+CLEANUP += $(ELF2EFI64)
+
+$(EFIROM) : util/efirom.c $(MAKEDEPS)
+       $(QM)$(ECHO) "  [HOSTCC] $@"
+       $(Q)$(HOST_CC) $(HOST_CFLAGS) -idirafter include -o $@ $<
+CLEANUP += $(EFIROM)
+
+$(EFIFATBIN) : util/efifatbin.c $(MAKEDEPS)
+       $(QM)$(ECHO) "  [HOSTCC] $@"
+       $(Q)$(HOST_CC) $(HOST_CFLAGS) -idirafter include -o $@ $<
+CLEANUP += $(EFIFATBIN)
+
+###############################################################################
+#
+# The ICC fixup utility
+#
+$(ICCFIX) : util/iccfix.c $(MAKEDEPS)
+       $(QM)$(ECHO) "  [HOSTCC] $@"
+       $(Q)$(HOST_CC) $(HOST_CFLAGS) -idirafter include -o $@ $<
+CLEANUP += $(ICCFIX)
+
+###############################################################################
+#
+# The error usage information utility
+#
+$(EINFO) : util/einfo.c $(MAKEDEPS)
+       $(QM)$(ECHO) "  [HOSTCC] $@"
+       $(Q)$(HOST_CC) $(HOST_CFLAGS) -idirafter include -o $@ $<
+CLEANUP += $(EINFO)
+
+###############################################################################
+#
+# Local configs
+#
+CONFIG_HEADERS := $(patsubst config/%,%,$(wildcard config/*.h))
+CONFIG_LOCAL_HEADERS := $(foreach HEADER,$(CONFIG_HEADERS),\
+                                 config/local/$(HEADER))
+
+$(CONFIG_LOCAL_HEADERS) :
+       $(Q)$(TOUCH) $@
+
+.PRECIOUS : $(CONFIG_LOCAL_HEADERS)
+
+ifneq ($(CONFIG),)
+
+CONFIG_LOCAL_NAMED_HEADERS := $(foreach HEADER,$(CONFIG_HEADERS),\
+                                       config/local/$(CONFIG)/$(HEADER))
+
+$(CONFIG_LOCAL_NAMED_HEADERS) :
+       $(Q)$(MKDIR) -p $(dir $@)
+       $(Q)$(TOUCH) $@
+
+.PRECIOUS : $(CONFIG_LOCAL_NAMED_HEADERS)
+
+endif
+
+###############################################################################
+#
+# Auto-incrementing build serial number.  Append "bs" to your list of
+# build targets to get a serial number printed at the end of the
+# build.  Enable -DBUILD_SERIAL in order to see it when the code runs.
+#
+BUILDSERIAL_H          = config/.buildserial.h
+BUILDSERIAL_NOW                = config/.buildserial.now
+BUILDSERIAL_NEXT       = config/.buildserial.next
+
+$(BUILDSERIAL_NOW) $(BUILDSERIAL_NEXT) :
+       $(ECHO) 1 > $@
+
+$(BUILDSERIAL_H) : $(BUILDSERIAL_NOW) $(BUILDSERIAL_NEXT)
+       $(ECHO) '#define BUILD_SERIAL_NUM $(shell cat $<)' > $@
+
+ifeq ($(filter bs,$(MAKECMDGOALS)),bs)
+$(shell diff -q $(BUILDSERIAL_NOW) $(BUILDSERIAL_NEXT) > /dev/null || \
+       cp -f $(BUILDSERIAL_NEXT) $(BUILDSERIAL_NOW))
+endif
+
+bs : $(BUILDSERIAL_NOW)
+       @$(ECHO) $$(( $(shell cat $<) + 1 )) > $(BUILDSERIAL_NEXT)
+       @$(ECHO) "Build serial number is $(shell cat $<)"
+
+###############################################################################
+#
+# Build the TAGS file(s) for emacs
+#
+TAGS :
+       ctags -e -R -f $@ --exclude=bin
+
+CLEANUP        += TAGS
+
+###############################################################################
+#
+# Force rebuild for any given target
+#
+%.rebuild :
+       rm -f $*
+       $(Q)$(MAKE) $*
+
+###############################################################################
+#
+# Symbol table checks
+#
+
+ifdef BIN
+
+SYMTAB = $(BIN)/symtab
+$(SYMTAB) : $(BLIB)
+       $(OBJDUMP) -w -t $< > $@
+
+CLEANUP        += $(BIN)/symtab
+
+symcheck : $(SYMTAB)
+       $(PERL) $(SYMCHECK) $<
+
+endif # defined(BIN)
+
+###############################################################################
+#
+# Build bochs symbol table
+#
+
+ifdef BIN
+
+$(BIN)/%.bxs : $(BIN)/%.tmp
+       $(NM) $< | cut -d" " -f1,3 > $@
+
+endif # defined(BIN)
+
+###############################################################################
+#
+# Documentation
+#
+
+ifdef BIN
+
+$(BIN)/doxygen.cfg : doxygen.cfg $(MAKEDEPS)
+       $(Q)$(PERL) -pe 's{\@SRCDIRS\@}{$(SRCDIRS)}; ' \
+               -e  's{\@INCDIRS\@}{$(filter-out .,$(INCDIRS))}; ' \
+               -e  's{\@BIN\@}{$(BIN)}; ' \
+               -e  's{\@ARCH\@}{$(ARCH)}; ' \
+               $< > $@
+
+$(BIN)/doc : $(BIN)/doxygen.cfg
+       $(Q)$(DOXYGEN) $<
+
+.PHONY : $(BIN)/doc
+
+doc : $(BIN)/doc
+
+doc-clean :
+       $(Q)$(RM) -r $(BIN)/doc
+
+VERYCLEANUP    += $(BIN)/doc
+
+docview :
+       @[ -f $(BIN)/doc/html/index.html ] || $(MAKE) $(BIN)/doc
+       @if [ -n "$$BROWSER" ] ; then \
+               ( $$BROWSER $(BIN)/doc/html/index.html & ) ; \
+       else \
+               $(ECHO) "Documentation index in $(BIN)/doc/html/index.html" ; \
+       fi
+
+endif # defined(BIN)
+
+###############################################################################
+#
+# Keyboard maps
+#
+
+hci/keymap/keymap_%.c :
+       $(Q)$(PERL) $(GENKEYMAP) $* > $@
+
+###############################################################################
+#
+# Force deletion of incomplete targets
+#
+
+.DELETE_ON_ERROR :
+
+###############################################################################
+#
+# Clean-up
+#
+
+ifeq ($(NUM_BINS),0)
+ALLBINS                := bin{,-*}
+CLEANUP                := $(patsubst $(BIN)/%,$(ALLBINS)/%,$(CLEANUP))
+VERYCLEANUP    := $(patsubst $(BIN)/%,$(ALLBINS)/%,$(VERYCLEANUP))
+endif
+
+clean :
+       $(RM) $(CLEANUP)
+
+veryclean : clean
+       $(RM) -r $(VERYCLEANUP)
diff --git a/net/discovery/console.h b/net/discovery/console.h
new file mode 100644 (file)
index 0000000..426ac93
--- /dev/null
@@ -0,0 +1 @@
+#undef CONSOLE_EFI
diff --git a/net/discovery/efi_discovery_prefix.c b/net/discovery/efi_discovery_prefix.c
new file mode 100644 (file)
index 0000000..c799072
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2009 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdlib.h>
+#include <ipxe/efi/efi_driver.h>
+#include <ipxe/efi/efi_snp.h>
+#include <ipxe/efi/efi_strings.h>
+#include <ipxe/umalloc.h>
+#include <ipxe/uri.h>
+#include <ipxe/init.h>
+#include <usr/ifmgmt.h>
+#include <usr/route.h>
+#include <usr/autoboot.h>
+
+#define MAX_EXIT_BUFFER_SIZE 256
+
+/**
+ * Close all open net devices
+ *
+ * Called before a fresh boot attempt in order to free up memory.  We
+ * don't just close the device immediately after the boot fails,
+ * because there may still be TCP connections in the process of
+ * closing.
+ */
+static void close_all_netdevs ( void ) {
+       struct net_device *netdev;
+
+       for_each_netdev ( netdev ) {
+               ifclose ( netdev );
+       }
+}
+
+static struct uri* try_getting_next_server ( struct net_device *netdev ) {
+       struct uri *filename;
+
+       /* Close all other network devices */
+       close_all_netdevs();
+
+       /* Open device and display device status */
+       if ( ifopen ( netdev ) != 0 )
+               goto err_ifopen;
+       ifstat ( netdev );
+
+       /* Configure device */
+       if (ifconf ( netdev, NULL )!= 0 )
+               goto err_dhcp;
+       route();
+
+  /* Fetch next server and filename */
+       filename = fetch_next_server_and_filename ( NULL );
+       if ( ! filename )
+               goto err_filename;
+       if ( ! uri_has_path ( filename ) ) {
+               /* Ignore empty filename */
+               uri_put ( filename );
+               filename = NULL;
+       }
+       return filename;
+  err_filename:
+  err_dhcp:
+  err_ifopen:
+    return NULL;
+}
+
+
+static struct uri* efi_discover ( void ) {
+       struct net_device *netdev;
+  
+  struct uri* filename = NULL;
+
+       for_each_netdev ( netdev ) {
+               filename = try_getting_next_server ( netdev );
+       }
+
+       return filename;
+}
+
+/**
+ * EFI entry point
+ *
+ * @v image_handle     Image handle
+ * @v systab           System table
+ * @ret efirc          EFI return status code
+ */
+EFI_STATUS EFIAPI _efi_discovery_start ( EFI_HANDLE image_handle,
+                              EFI_SYSTEM_TABLE *systab ) {
+       EFI_STATUS efirc;
+  struct uri* filename;
+  userptr_t user_buf;
+  wchar_t* exit_buf;
+
+       /* Initialise EFI environment */
+       if ( ( efirc = efi_init ( image_handle, systab ) ) != 0 )
+               goto err_init;
+
+  if ( ( user_buf = umalloc(MAX_EXIT_BUFFER_SIZE*2) ) == 0)
+  {
+     efirc = EFI_OUT_OF_RESOURCES;
+     goto err_init;
+  }
+  
+  exit_buf = (wchar_t *)user_to_phys(user_buf,0);
+
+  initialise();
+  startup();
+
+  if ( ( filename = efi_discover() ) == NULL)
+  {
+     efirc = EFI_NOT_FOUND;
+     goto err_filename;
+  }
+  
+       efi_snp_release();
+       efi_loaded_image->Unload ( image_handle );
+       efi_driver_reconnect_all();
+  efi_snprintf(exit_buf,MAX_EXIT_BUFFER_SIZE,"%s - %s", filename->host, filename->path);
+  uri_put(filename);
+
+  systab->BootServices->Exit(image_handle, efirc, MAX_EXIT_BUFFER_SIZE, (CHAR16 *) exit_buf);
+
+ err_filename:
+ err_init:
+       systab->BootServices->Exit(image_handle, efirc, 0, NULL);
+       return efirc;
+}
+
+/**
+ * Probe EFI root bus
+ *
+ * @v rootdev          EFI root device
+ */
+static int efi_probe ( struct root_device *rootdev __unused ) {
+
+       return efi_driver_connect_all();
+}
+
+/**
+ * Remove EFI root bus
+ *
+ * @v rootdev          EFI root device
+ */
+static void efi_remove ( struct root_device *rootdev __unused ) {
+
+       efi_driver_disconnect_all();
+}
+
+/** EFI root device driver */
+static struct root_driver efi_root_driver = {
+       .probe = efi_probe,
+       .remove = efi_remove,
+};
+
+/** EFI root device */
+struct root_device efi_root_device __root_device = {
+       .dev = { .name = "EFI" },
+       .driver = &efi_root_driver,
+};
diff --git a/old-banners/refind.svg b/old-banners/refind.svg
new file mode 100644 (file)
index 0000000..562d5df
--- /dev/null
@@ -0,0 +1,260 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="744.09448819"
+   height="1052.3622047"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.2 r9819"
+   sodipodi:docname="refind.svg"
+   inkscape:export-filename="/Users/erikkemperman/refind.png"
+   inkscape:export-xdpi="149.96837"
+   inkscape:export-ydpi="149.96837">
+  <defs
+     id="defs4">
+    <linearGradient
+       id="linearGradient5189">
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="0"
+         id="stop5191" />
+      <stop
+         style="stop-color:#000000;stop-opacity:0;"
+         offset="1"
+         id="stop5193" />
+    </linearGradient>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="Arrow1Send"
+       style="overflow:visible;">
+      <path
+         id="path4038"
+         d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;"
+         transform="scale(0.2) rotate(180) translate(6,0)" />
+    </marker>
+    <marker
+       style="overflow:visible"
+       inkscape:stockid="InfiniteLineStart"
+       id="InfiniteLineStart"
+       refX="0"
+       refY="0"
+       orient="auto">
+      <g
+         id="g4268"
+         transform="translate(-13,0)">
+        <circle
+           d="M 3.8,0 C 3.8,0.44182781 3.4418278,0.80000001 3,0.80000001 2.5581722,0.80000001 2.2,0.44182781 2.2,0 c 0,-0.44182781 0.3581722,-0.80000001 0.8,-0.80000001 0.4418278,0 0.8,0.3581722 0.8,0.80000001 z"
+           id="circle4270"
+           r="0.8"
+           cy="0"
+           cx="3" />
+        <circle
+           d="M 7.3,0 C 7.3,0.44182781 6.9418278,0.80000001 6.5,0.80000001 6.0581722,0.80000001 5.7,0.44182781 5.7,0 c 0,-0.44182781 0.3581722,-0.80000001 0.8,-0.80000001 0.4418278,0 0.8,0.3581722 0.8,0.80000001 z"
+           id="circle4272"
+           r="0.8"
+           cy="0"
+           cx="6.5" />
+        <circle
+           d="M 10.8,0 C 10.8,0.44182781 10.441828,0.80000001 10,0.80000001 9.5581722,0.80000001 9.2,0.44182781 9.2,0 c 0,-0.44182781 0.3581722,-0.80000001 0.8,-0.80000001 0.441828,0 0.8,0.3581722 0.8,0.80000001 z"
+           id="circle4274"
+           r="0.8"
+           cy="0"
+           cx="10" />
+      </g>
+    </marker>
+    <marker
+       inkscape:stockid="TriangleOutS"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="TriangleOutS"
+       style="overflow:visible">
+      <path
+         id="path3908"
+         d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none"
+         transform="scale(0.2)" />
+    </marker>
+    <filter
+       id="filter5203"
+       inkscape:label="Relief print"
+       inkscape:menu="Bumps"
+       inkscape:menu-tooltip="Bumps effect with a bevel, color flood and complex lighting"
+       color-interpolation-filters="sRGB">
+      <feGaussianBlur
+         id="feGaussianBlur5205"
+         stdDeviation="5"
+         result="result8" />
+      <feComposite
+         id="feComposite5207"
+         in2="result8"
+         result="result6"
+         in="SourceGraphic"
+         operator="in" />
+      <feComposite
+         id="feComposite5209"
+         in2="result6"
+         operator="in"
+         result="result11" />
+      <feFlood
+         id="feFlood5211"
+         result="result10"
+         in="result11"
+         flood-opacity="1"
+         flood-color="rgb(255,255,255)" />
+      <feBlend
+         id="feBlend5213"
+         in2="result11"
+         mode="multiply"
+         in="result10"
+         result="result12" />
+      <feComposite
+         id="feComposite5215"
+         in2="SourceGraphic"
+         result="fbSourceGraphic"
+         operator="in"
+         in="result12" />
+      <feFlood
+         id="feFlood5217"
+         result="result6"
+         flood-color="rgb(75,101,154)"
+         in="fbSourceGraphic" />
+      <feComposite
+         id="feComposite5219"
+         in2="result6"
+         k3="0.3"
+         k2="0.3"
+         k1="0.5"
+         operator="arithmetic"
+         result="result2"
+         in="fbSourceGraphic" />
+      <feColorMatrix
+         id="feColorMatrix5221"
+         result="fbSourceGraphicAlpha"
+         in="result2"
+         values="1 0 0 -1 0 1 0 1 -1 0 1 0 0 -1 0 -0.8 -1 0 3.9 -2.7 "
+         type="matrix" />
+      <feGaussianBlur
+         id="feGaussianBlur5223"
+         result="result0"
+         in="fbSourceGraphicAlpha"
+         stdDeviation="0.5" />
+      <feDiffuseLighting
+         id="feDiffuseLighting5225"
+         lighting-color="rgb(255,255,255)"
+         diffuseConstant="0.7"
+         surfaceScale="50"
+         result="result13"
+         in="result0">
+        <feDistantLight
+           id="feDistantLight5227"
+           elevation="20"
+           azimuth="225" />
+      </feDiffuseLighting>
+      <feSpecularLighting
+         id="feSpecularLighting5229"
+         specularExponent="20"
+         specularConstant="0.7"
+         surfaceScale="10"
+         lighting-color="rgb(255,255,255)"
+         result="result1"
+         in="result0">
+        <feDistantLight
+           id="feDistantLight5231"
+           elevation="45"
+           azimuth="225" />
+      </feSpecularLighting>
+      <feBlend
+         id="feBlend5233"
+         in2="SourceGraphic"
+         mode="screen"
+         result="result5"
+         in="result13" />
+      <feComposite
+         id="feComposite5235"
+         in2="result5"
+         in="result1"
+         k3="1"
+         k2="1"
+         operator="arithmetic"
+         result="result9" />
+      <feComposite
+         id="feComposite5237"
+         in2="SourceGraphic"
+         operator="in" />
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="0.49497475"
+     inkscape:cx="363.92167"
+     inkscape:cy="579.31792"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:window-width="1235"
+     inkscape:window-height="825"
+     inkscape:window-x="79"
+     inkscape:window-y="4"
+     inkscape:window-maximized="0" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <g
+       id="g5197"
+       style="filter:url(#filter5203)">
+      <g
+         style="stroke:#000000;stroke-opacity:1"
+         id="g5185">
+        <path
+           style="fill:none;stroke:#000000;stroke-width:122.41708374000002379;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:none"
+           d="m 639.08453,440.52756 c -3.56478,17.42062 -8.82227,34.22465 -15.59312,50.23273 -6.77084,16.00808 -15.05504,31.2202 -24.67325,45.45703 -9.61822,14.23683 -20.57044,27.49836 -32.67731,39.60523 -12.10687,12.10687 -25.3684,23.05909 -39.60523,32.6773 -14.23683,9.61822 -29.44895,17.90242 -45.45703,24.67326 -16.00808,6.77085 -32.81211,12.02834 -50.23273,15.59312 -17.42062,3.56477 -35.45784,5.43684 -53.93231,5.43684 -18.47447,0 -36.51169,-1.87207 -53.93231,-5.43684 -17.42062,-3.56478 -34.22465,-8.82227 -50.23273,-15.59312 -16.00807,-6.77084 -31.2202,-15.05504 -45.45703,-24.67326 -14.23683,-9.61821 -27.49835,-20.57043 -39.60522,-32.6773 -12.10688,-12.10687 -23.05909,-25.3684 -32.67731,-39.60523 -9.6182,-14.23683 -17.90241,-29.44895 -24.67326,-45.45703 -6.77085,-16.00808 -12.02833,-32.81211 -15.5931,-50.23273 -3.56478,-17.42062 -5.43685,-35.45785 -5.43685,-53.93231 0,-18.47446 1.87207,-36.51169 5.43685,-53.93231 3.56477,-17.42062 8.82225,-34.22465 15.5931,-50.23273 6.77085,-16.00807 15.05506,-31.2202 24.67326,-45.45703 9.61822,-14.23683 20.57043,-27.49835 32.67731,-39.60522 12.10687,-12.10688 25.36839,-23.0591 39.60522,-32.6773 14.23683,-9.61821 29.44896,-17.90242 45.45703,-24.67327 16.00808,-6.77084 32.81211,-12.02833 50.23273,-15.59311 17.42062,-3.56477 35.45784,-5.43684 53.93231,-5.43684 18.47447,0 36.51169,1.87207 53.93231,5.43684 17.42062,3.56478 34.22465,8.82227 50.23273,15.59311 16.00808,6.77085 31.2202,15.05506 45.45703,24.67327 14.23683,9.6182 27.49836,20.57042 39.60523,32.6773 12.10687,12.10687 1.5e-4,0.002 12.09811,12.08757"
+           id="path2985"
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="csssssssssssssssssssssssssssc" />
+        <path
+           style="fill:none;stroke:#000000;stroke-width:122.41708374000002379;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:none"
+           d="M 481.09422,633.19723 617.47075,936.30224"
+           id="path4570"
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cc" />
+      </g>
+      <path
+         sodipodi:nodetypes="cccc"
+         inkscape:connector-curvature="0"
+         id="rect4852"
+         d="m 472.35714,280.54413 201.30255,-151.28104 -0.0205,209.54514 z"
+         style="fill:#000000;fill-opacity:1;stroke:none" />
+    </g>
+  </g>
+</svg>
diff --git a/old-banners/refind_blue.png b/old-banners/refind_blue.png
new file mode 100644 (file)
index 0000000..293e4dc
Binary files /dev/null and b/old-banners/refind_blue.png differ
diff --git a/old-banners/refind_lighter.png b/old-banners/refind_lighter.png
new file mode 100644 (file)
index 0000000..461df94
Binary files /dev/null and b/old-banners/refind_lighter.png differ
diff --git a/old-banners/refind_metal.png b/old-banners/refind_metal.png
new file mode 100644 (file)
index 0000000..9f7fed4
Binary files /dev/null and b/old-banners/refind_metal.png differ
diff --git a/old-banners/refind_original.png b/old-banners/refind_original.png
new file mode 100644 (file)
index 0000000..a1dc253
Binary files /dev/null and b/old-banners/refind_original.png differ
diff --git a/refind-alt.spec b/refind-alt.spec
new file mode 100644 (file)
index 0000000..0104030
--- /dev/null
@@ -0,0 +1,94 @@
+Name: refind
+Version: 0.6.4
+Release: alt1
+
+Summary: EFI boot manager software
+License: GPLv3
+Group: System/Base
+
+Url: http://www.rodsbooks.com/refind/
+Source0: refind-src-%version.zip
+Source1: os_altlinux.icns
+Packager: Michael Shigorin <mike@altlinux.org>
+
+BuildRequires: gnu-efi unzip
+BuildRequires: rpm-macros-uefi sbsigntools alt-uefi-keys-private
+Requires: efibootmgr
+Provides: refind-signed
+
+%define refind_lib %_efi_bindir
+%define refind_data %_datadir/%name
+
+%ifarch x86_64
+%define _efi_arch x64
+%endif
+%ifarch %ix86
+%define _efi_arch ia32
+%endif
+
+%description
+A graphical boot manager for EFI- and UEFI-based computers, such as all
+Intel-based Macs and recent (most 2011 and later) PCs. rEFInd presents a
+boot menu showing all the EFI boot loaders on the EFI-accessible
+partitions, and optionally BIOS-bootable partitions on Macs. EFI-compatbile
+OSes, including Linux, provide boot loaders that rEFInd can detect and
+launch. rEFInd can launch Linux EFI boot loaders such as ELILO, GRUB
+Legacy, GRUB 2, and 3.3.0 and later kernels with EFI stub support. EFI
+filesystem drivers for ext2/3/4fs, ReiserFS, HFS+, and ISO-9660 enable
+rEFInd to read boot loaders from these filesystems, too. rEFInd's ability
+to detect boot loaders at runtime makes it very easy to use, particularly
+when paired with Linux kernels that provide EFI stub support.
+
+%prep
+%setup
+
+%build
+make gnuefi
+make fs_gnuefi
+
+%install
+mkdir -p %buildroot{%refind_lib{,/drivers_%_efi_arch},%refind_data}
+
+%ifarch x86_64
+for file in refind/refind*.efi; do
+       sbsign --key %_efi_keydir/altlinux.key --cert %_efi_keydir/altlinux.crt \
+               --output %buildroot%_efi_bindir/"`basename "$file"`" "$file"
+done
+for file in drivers_%_efi_arch/*_x64.efi; do
+       sbsign --key %_efi_keydir/altlinux.key --cert %_efi_keydir/altlinux.crt \
+               --output %buildroot%refind_lib/"$file" "$file"
+done
+%endif
+
+%ifarch %ix86
+install -pm644 refind/refind*.efi %buildroot%refind_lib/
+cp -a drivers_%_efi_arch/*.efi %buildroot%refind_lib/drivers_%_efi_arch/
+%endif
+
+cp -a icons/ %buildroot%refind_data/
+cp -a %SOURCE1 %buildroot%refind_data/icons/
+
+%files
+%doc docs/*
+%doc NEWS.txt COPYING.txt LICENSE.txt README.txt CREDITS.txt
+%doc install.sh mkrlconf.sh mvrefind.sh
+%refind_lib
+%refind_data
+
+# TODO:
+# - create separate signing helper
+# - move off hardwired sbsign to that
+# NB:
+# - macros get expanded too early for shell loops
+
+%changelog
+* Sat Jan 12 2013 Michael Shigorin <mike@altlinux.org> 0.6.4-alt1
+- initial build for ALT Linux Sisyphus
+- stripped upstream installation helpers (too smart for a package)
+- added os_altlinux icon
+
+* Sun Jan 6 2013 R Smith <rodsmith@rodsbooks.com> - 0.6.3-2
+- Fixed accidental inclusion of "env" as part of installation script
+
+* Sun Jan 6 2013 R Smith <rodsmith@rodsbooks.com> - 0.6.3
+- Created spec file for 0.6.3 release
diff --git a/refind-install b/refind-install
new file mode 100755 (executable)
index 0000000..495892f
--- /dev/null
@@ -0,0 +1,1288 @@
+#!/bin/bash
+#
+# Linux/MacOS X script to install rEFInd
+#
+# Usage:
+#
+# ./refind-install [options]
+#
+# options include:
+#    "--notesp" to install to the OS X root filesystem rather than to the ESP.
+#           This option may not be used under Linux.
+#    "--usedefault {devicefile}" to install as default
+#           (/EFI/BOOT/BOOTX64.EFI and similar) to the specified device
+#           (/dev/sdd1 or whatever) without registering with the NVRAM.
+#    "--ownhfs {devicefile}" to install to an HFS+ volume that's NOT currently
+#           an OS X boot volume.
+#    "--root {dir}" to specify installation using the specified directory
+#           as the system's root
+#    "--alldrivers" to install all drivers along with regular files
+#    "--nodrivers" to suppress driver installation (default in Linux is
+#           driver used on /boot; --nodrivers is OS X default)
+#    "--shim {shimfile}" to install a shim.efi file for Secure Boot
+#    "--preloader" is synonymous with "--shim"
+#    "--localkeys" to re-sign x86-64 binaries with a locally-generated key
+#    "--keepname" to keep refind_x64.efi name as such even when using shim
+#    "--yes" to assume a "yes" response to all prompts
+#
+# The "esp" option is valid only on Mac OS X; it causes
+# installation to the EFI System Partition (ESP) rather than
+# to the current OS X boot partition. Under Linux, this script
+# installs to the ESP by default.
+#
+# This program is copyright (c) 2012-2015 by Roderick W. Smith
+#
+# This program is licensed under the terms of the GNU GPL, version 3,
+# or (at your option) any later version.
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Revision history:
+#
+# 0.10.1  -- Improve extraction of default kernel options from /proc/cmdline.
+#            Add support for AMD64 (aka AARCH64, aa64) platform.
+# 0.10.0  -- Enable running under OS X's recovery system & add warning about
+#            SIP & brief instructions on how to deal with it if SIP is
+#            detected to be enabled. Also change way refind_linux.conf default
+#            options are found; use /proc/cmdline as base.
+# 0.9.2   -- Added --keepname option.
+# 0.8.7   -- Better detection of Secure Boot mode & fixed errors when copying
+#            Shim & MokManager files over themselves; fixed bug that caused
+#            inappropriate installation to EFI/BOOT/bootx64.efi
+# 0.8.6   -- Fixed bugs that caused misidentification of ESP on disks with
+#            partition numbers over 10 on OS X and misidentification of mount
+#            point if already-mounted ESP had space in path.
+# 0.8.5   -- Refinement/cleanup of new OS X ESP-as-default policy
+# 0.8.4   -- OS X default changed to install to ESP under /EFI/BOOT
+# 0.7.9   -- Fixed bug that caused errors if dmraid utility not installed
+# 0.7.7   -- Fixed bug that created mangled refind_linux.conf file; added ability
+#            to locate and mount ESP on Linux, if it's not mounted
+# 0.7.6   -- Added --ownhfs {device-filename} option
+# 0.7.5   -- Fixed bug when installing to ESP on recent versions of OS X
+# 0.7.2   -- Fixed code that could be confused by use of autofs to mount the ESP
+# 0.7.0   -- Added support for the new Btrfs driver
+# 0.6.12  -- Added support for PreLoader as well as for shim
+# 0.6.11  -- Improvements in script's ability to handle directories with spaces
+#            in their names
+# 0.6.9   -- Install gptsync on Macs
+# 0.6.8   -- Bug fix: ESP scan now uses "uniq".
+# 0.6.6   -- Bug fix: Upgrade drivers when installed to EFI/BOOT. Also enable
+#            copying shim.efi and MokManager.efi over themselves.
+# 0.6.4   -- Copies ext2 driver rather than ext4 driver for ext2/3fs
+# 0.6.3   -- Support for detecting rEFInd in EFI/BOOT and EFI/Microsoft/Boot
+#            directories & for installing to EFI/BOOT in BIOS mode
+# 0.6.2-1 -- Added --yes option & tweaked key-copying for use with RPM install script
+# 0.6.1   -- Added --root option; minor bug fixes
+# 0.6.0   -- Changed --drivers to --alldrivers and added --nodrivers option;
+#            changed default driver installation behavior in Linux to install
+#            the driver needed to read /boot (if available)
+# 0.5.1.2 -- Fixed bug that caused failure to generate refind_linux.conf file
+# 0.5.1.1 -- Fixed bug that caused script failure under OS X
+# 0.5.1   -- Added --shim & --localkeys options & create sample refind_linux.conf
+#            in /boot
+# 0.5.0   -- Added --usedefault & --drivers options & changed "esp" option to "--esp"
+# 0.4.5   -- Fixed check for rEFItBlesser in OS X
+# 0.4.2   -- Added notice about BIOS-based OSes & made NVRAM changes in Linux smarter
+# 0.4.1   -- Added check for rEFItBlesser in OS X
+# 0.3.3.1 -- Fixed OS X 10.7 bug; also works as make target
+# 0.3.2.1 -- Check for presence of source files; aborts if not present
+# 0.3.2   -- Initial version
+#
+# Note: install.sh version numbers match those of the rEFInd package
+# with which they first appeared.
+
+RootDir="/"
+TargetDir=/EFI/refind
+LocalKeysBase="refind_local"
+ShimSource="none"
+ShimType="none"
+KeepName=0
+TargetShim="default"
+TargetX64="refind_x64.efi"
+TargetIA32="refind_ia32.efi"
+LocalKeys=0
+DeleteRefindDir=0
+AlwaysYes=0
+
+#
+# Functions used by both OS X and Linux....
+#
+
+GetParams() {
+   InstallToEspOnMac=1
+   # Install the driver required to read Linux /boot, if it's available
+   # Note: Under OS X, this will be installed only if a Linux partition
+   # is detected, in which case the ext4fs driver will be installed.
+   InstallDrivers="boot"
+   while [[ $# -gt 0 ]]; do
+      case $1 in
+         --notesp) InstallToEspOnMac=0
+              ;;
+         --ownhfs) OwnHfs=1
+              InstallToEspOnMac=0
+              TargetPart="$2"
+              TargetDir=/System/Library/CoreServices
+              shift
+              ;;
+         --usedefault) TargetDir=/EFI/BOOT
+              TargetPart="$2"
+              TargetX64="bootx64.efi"
+              TargetIA32="bootia32.efi"
+              shift
+              ;;
+         --root) RootDir="$2"
+              InstallToEspOnMac=0
+              shift
+              ;;
+         --localkeys) LocalKeys=1
+              ;;
+         --shim | --preloader) ShimSource="$2"
+              ShimType=`basename $ShimSource`
+              shift
+              ;;
+         --keepname) KeepName=1
+              ;;
+         --drivers | --alldrivers) InstallDrivers="all"
+              ;;
+         --nodrivers) InstallDrivers="none"
+              ;;
+         --yes) AlwaysYes=1
+              ;;
+         * ) echo "Usage: $0 [--notesp | --usedefault {device-file} | --root {dir} |"
+             echo "                     --ownhfs {device-file} ] [--keepname]"
+             echo "                  [--nodrivers | --alldrivers]"
+             echo "                  [--localkeys] [--keepname] [--yes]"
+             exit 1
+      esac
+      shift
+   done
+   if [[ "$InstallToEspOnMac" == 0 && "$RootDir" == '/' && "$TargetDir" == '/EFI/BOOT' ]] ; then
+      echo "You may use --notesp OR --usedefault, but not both! Aborting!"
+      exit 1
+   fi
+   if [[ "$RootDir" != '/' && "$TargetDir" == '/EFI/BOOT' ]] ; then
+      echo "You may use --root OR --usedefault, but not both! Aborting!"
+      exit 1
+   fi
+   if [[ "$TargetDir" != '/System/Library/CoreServices' && "$OwnHfs" == '1' ]] ; then
+      echo "If you use --ownhfs, you may NOT use --usedefault! Aborting!"
+      exit 1
+   fi
+   if [[ "$KeepName" == 1 && "$ShimSource" == "none" ]] ; then
+      echo "The --keepname option is meaningful only in conjunction with --shim"
+      echo "or --preloader! Aborting!"
+      exit 1
+   fi
+   if [[ "$KeepName" == 1 && "$OSTYPE" != "linux" && "$OSTYPE" != "linux-gnu" ]] ; then
+      echo "The --keepname option is valid only under Linux! Aborting!"
+      exit 1
+   fi
+   if [[ "$KeepName" == 1 && "$TargetDir" == "/EFI/BOOT" ]] ; then
+      echo "The --keepname option is incompatible with --usedefault! Aborting!"
+      exit 1
+   fi
+   RLConfFile="$RootDir/boot/refind_linux.conf"
+   EtcKeysDir="$RootDir/etc/refind.d/keys"
+} # GetParams()
+
+# Get a yes/no response from the user and place it in the YesNo variable.
+# If the AlwaysYes variable is set to 1, skip the user input and set "Y"
+# in the YesNo variable.
+ReadYesNo() {
+   if [[ $AlwaysYes == 1 ]] ; then
+      YesNo="Y"
+      echo "Y"
+   else
+      read YesNo
+   fi
+}
+
+# Determine what CPU type and EFI bit depth we're using.
+# Sets Platform global variable to lowercase EFI platform code (currently
+# "x64", "ia32", or "aa64") -- the same code used in filenames.
+DeterminePlatform() {
+   local CpuType
+   case "$OSTYPE" in
+   darwin*)
+      CpuType=`ioreg -l -p IODeviceTree | grep firmware-abi | cut -d "\"" -f 4`
+      if [[ "$CpuType" == EFI32 ]] ; then
+         Platform="ia32"
+      else
+         Platform="x64"
+      fi
+      ;;
+   linux*)
+      CpuType=`uname -m`
+      case "$CpuType" in
+      aarch64)
+         Platform="aa64"
+         ;;
+      x86_64)
+         Platform="x64"
+         ;;
+      i?86)
+         Platform="ia32"
+         # If we're in EFI mode, do some sanity checks, and alert the user or even
+         # abort. Not in BIOS mode, though, since that could be used on an emergency
+         # disc to try to recover a troubled Linux installation.
+         if [[ -d /sys/firmware/efi ]] ; then
+            if [[ "$ShimSource" != "none" && "$TargetDir" != "/BOOT/EFI" ]] ; then
+               echo ""
+               echo "CAUTION: shim does not currently supports 32-bit systems, so you should not"
+               echo "use the --shim option to install on such systems. Aborting!"
+               echo ""
+               exit 1
+            fi
+            echo
+            echo "CAUTION: This Linux installation uses a 32-bit kernel. 32-bit EFI-based"
+            echo "computers are VERY RARE. If you've installed a 32-bit version of Linux"
+            echo "on a 64-bit computer, you should manually install the 64-bit version of"
+            echo "rEFInd. If you're positive you want to continue with this installation,"
+            echo "answer 'Y' to the following question..."
+            echo
+            echo -n "Are you sure you want to continue (Y/N)? "
+            ReadYesNo
+            if [[ $YesNo == "Y" || $YesNo == "y" ]] ; then
+               echo "OK; continuing with the installation..."
+            else
+               exit 0
+            fi
+         fi # In EFI mode
+         ;;
+      *)
+         echo "Unknown CPU type '$CpuType'; aborting!"
+         exit 1
+         ;;
+      esac # case "$CpuType"....
+      ;;
+   *)
+      echo "Unknown OS; aborting!"
+      exit 1
+      ;;
+   esac # case "$OSTYPE"....
+} # DeterminePlatform()
+
+# Abort if the rEFInd files can't be found.
+# Also sets $ConfFile to point to the configuration file,
+# $IconsDir to point to the icons directory,
+# $ShimSource to the source of the shim.efi file (if necessary),
+# $ThisDir to point to the directory in which this script resides,
+# and $RefindDir to point to where the rEFInd binaries live
+CheckForFiles() {
+   # Note: $ThisDir points to real (not symlinked) script home on Linux,
+   # enabling creating a symlink in /usr/sbin (or wherever); but on OS X,
+   # "readlink" doesn't do the same thing as under Linux, so the script
+   # must not be a symlink under OS X.
+   case "$OSTYPE" in
+      darwin*)
+           ThisDir="$( cd -P "${BASH_SOURCE%/*}" && pwd )"
+           ;;
+      linux*)
+           ThisDir="$(dirname "$(readlink -f "$0")")"
+           ;;
+   esac
+   RefindDir="$ThisDir/refind"
+
+   if [[ ! -f "$RefindDir/refind_$Platform.efi" ]] ; then
+      echo "The rEFInd binary file is missing! Aborting installation!"
+      exit 1
+   fi
+
+   if [[ -f "$RefindDir/refind.conf-sample" ]] ; then
+      ConfFile="$RefindDir/refind.conf-sample"
+   elif [[ -f "$ThisDir/refind.conf-sample" ]] ; then
+      ConfFile="$ThisDir/refind.conf-sample"
+   else
+      echo "The sample configuration file is missing! Aborting installation!"
+      exit 1
+   fi
+
+   if [[ -d "$RefindDir/icons" ]] ; then
+      IconsDir="$RefindDir/icons"
+   elif [[ -d "$ThisDir/icons" ]] ; then
+      IconsDir="$ThisDir/icons"
+   else
+      echo "The icons directory is missing! Aborting installation!"
+      exit 1
+   fi
+
+   echo "ShimSource is $ShimSource"
+   if [[ "$ShimSource" != "none" ]] ; then
+      if [[ -f "$ShimSource" ]] ; then
+         if [[ $ShimType == "shimx64.efi" || $ShimType == "shim.efi" ]] ; then
+            TargetX64="grubx64.efi"
+            TargetAARCH64="grubaa64.efi"
+            MokManagerSource=`dirname "$ShimSource"`/MokManager.efi
+         elif [[ $ShimType == "preloader.efi" || $ShimType == "PreLoader.efi" ]] ; then
+            TargetX64="loader.efi"
+            MokManagerSource=`dirname "$ShimSource"`/HashTool.efi
+         else
+            echo "Unknown shim/PreBootloader filename: $ShimType!"
+            echo "Known filenames are shimx64.efi, shim.efi, and PreLoader.efi. Aborting!"
+            exit 1
+         fi
+      else
+         echo "The specified shim/PreBootloader file, $ShimSource, doesn't exist!"
+         echo "Aborting installation!"
+         exit 1
+      fi
+   fi
+} # CheckForFiles()
+
+# Helper for CopyRefindFiles; copies shim files (including MokManager, if it's
+# available) to target.
+CopyShimFiles() {
+   local inode1=`ls -i "$ShimSource" 2> /dev/null | cut -f 1 -d " "`
+   local inode2=`ls -i "$InstallDir/$TargetDir/$TargetShim" 2> /dev/null | cut -f 1 -d " "`
+   if [[ $inode1 != $inode2 ]] ; then
+      cp -fb "$ShimSource" "$InstallDir/$TargetDir/$TargetShim"
+      if [[ $? != 0 ]] ; then
+         Problems=1
+      fi
+   fi
+   inode1=`ls -i "$MokManagerSource" 2> /dev/null | cut -f 1 -d " "`
+   local TargetMMName=`basename $MokManagerSource`
+   inode2=`ls -i "$InstallDir/$TargetDir/$TargetMMName" 2> /dev/null | cut -f 1 -d " "`
+   if [[ $inode1 != $inode2 ]] ; then
+      if [[ -f "$MokManagerSource" ]] ; then
+         cp -fb "$MokManagerSource" "$InstallDir/$TargetDir/"
+      fi
+      if [[ $? != 0 ]] ; then
+         Problems=1
+      fi
+   fi
+} # CopyShimFiles()
+
+# Copy the public keys to the installation medium
+CopyKeys() {
+   if [[ $LocalKeys == 1 ]] ; then
+      mkdir -p "$InstallDir/$TargetDir/keys/"
+      cp "$EtcKeysDir/$LocalKeysBase.cer" "$InstallDir/$TargetDir/keys/"
+      cp "$EtcKeysDir/$LocalKeysBase.crt" "$InstallDir/$TargetDir/keys/"
+   fi
+} # CopyKeys()
+
+# Set varaibles for installation in EFI/BOOT directory
+SetVarsForBoot() {
+   TargetDir="/EFI/BOOT"
+   if [[ $ShimSource == "none" ]] ; then
+      TargetX64="bootx64.efi"
+      TargetIA32="bootia32.efi"
+      TargetAARCH64="bootaa64.efi"
+   else
+      if [[ $ShimType == "shim.efi" || $ShimType == "shimx64.efi" || $ShimType = "shimaa64.efi" ]] ; then
+         TargetX64="grubx64.efi"
+         TargetAARCH64="grubaa64.efi"
+      elif [[ $ShimType == "preloader.efi" || $ShimType == "PreLoader.efi" ]] ; then
+         TargetX64="loader.efi"
+      else
+         echo "Unknown shim/PreBootloader type: $ShimType"
+         echo "Aborting!"
+         exit 1
+      fi
+      TargetIA32="bootia32.efi"
+      TargetShim="boot$Platform.efi"
+   fi
+   if [[ $KeepName == 1 ]] ; then
+      echo "Installation is to /EFI/BOOT, which is incompatible with --keepname! Aborting!"
+      exit 1
+   fi
+} # SetVarsForBoot()
+
+# Set variables for installation in EFI/Microsoft/Boot directory
+SetVarsForMsBoot() {
+   TargetDir="/EFI/Microsoft/Boot"
+   if [[ $ShimSource == "none" ]] ; then
+      TargetX64="bootmgfw.efi"
+      TargetIA32="bootmgfw.efi"
+      TargetAARCH64="bootmgfw.efi"
+   else
+      if [[ $ShimType == "shim.efi" || $ShimType == "shimx64.efi" || $ShimType == "shimaa64.efi" ]] ; then
+         TargetX64="grubx64.efi"
+         TargetAARCH64="grubaa64.efi"
+      elif [[ $ShimType == "preloader.efi" || $ShimType == "PreLoader.efi" ]] ; then
+         TargetX64="loader.efi"
+      else
+         echo "Unknown shim/PreBootloader type: $ShimType"
+         echo "Aborting!"
+         exit 1
+      fi
+      TargetShim="bootmgfw.efi"
+   fi
+   if [[ $KeepName == 1 ]] ; then
+      echo "Installation is to /EFI/Microsoft/Boot, which is incompatible with --keepname!"
+      echo "Aborting!"
+      exit 1
+   fi
+} # SetVarsForMsBoot()
+
+# TargetDir defaults to /EFI/refind; however, this function adjusts it as follows:
+# - If an existing refind.conf is available in /EFI/BOOT or /EFI/Microsoft/Boot,
+#   install to that directory under the suitable name; but DO NOT do this if
+#   refind.conf is also in /EFI/refind.
+# - If booted in BIOS mode and the ESP lacks any other EFI files, install to
+#   /EFI/BOOT
+# - If booted in BIOS mode and there's no refind.conf file and there is a
+#   /EFI/Microsoft/Boot/bootmgfw.efi file, move it down one level and
+#   install under that name, "hijacking" the Windows boot loader filename
+DetermineTargetDir() {
+   Upgrade=0
+
+   if [[ -f $InstallDir/EFI/BOOT/refind.conf && ! -f $InstallDir/EFI/refind/refind.conf ]] ; then
+      SetVarsForBoot
+      Upgrade=1
+   fi
+   if [[ -f $InstallDir/EFI/Microsoft/Boot/refind.conf && ! -f $InstallDir/EFI/refind/refind.conf ]] ; then
+      SetVarsForMsBoot
+      Upgrade=1
+   fi
+   if [[ -f $InstallDir/EFI/refind/refind.conf ]] ; then
+      TargetDir="/EFI/refind"
+      if [[ $ShimSource == "none" || $KeepName == 1 ]] ; then
+         TargetX64="refind_x64.efi"
+         TargetIA32="refind_ia32.efi"
+         TargetAARCH64="refind_aa64.efi"
+      fi
+      Upgrade=1
+   fi
+   if [[ $Upgrade == 1 ]] ; then
+      echo "Found rEFInd installation in $InstallDir$TargetDir; upgrading it."
+   fi
+
+   if [[ ! -d /sys/firmware/efi && ! $OSTYPE == darwin* && $Upgrade == 0 ]] ; then     # BIOS-mode
+      FoundEfiFiles=`find "$InstallDir/EFI/BOOT" -name "*.efi" 2> /dev/null`
+      FoundConfFiles=`find "$InstallDir" -name "refind\.conf" 2> /dev/null`
+      if [[ ! -n "$FoundConfFiles" && -f "$InstallDir/EFI/Microsoft/Boot/bootmgfw.efi" ]] ; then
+         mv -n "$InstallDir/EFI/Microsoft/Boot/bootmgfw.efi" "$InstallDir/EFI/Microsoft" &> /dev/null
+         SetVarsForMsBoot
+         echo "Running in BIOS mode with a suspected Windows installation; moving boot loader"
+         echo "files so as to install to $InstallDir$TargetDir."
+      elif [[ ! -n "$FoundEfiFiles" ]] ; then  # In BIOS mode and no default loader; install as default loader
+         SetVarsForBoot
+         echo "Running in BIOS mode with no existing default boot loader; installing to"
+         echo $InstallDir$TargetDir
+      else
+         echo "Running in BIOS mode with an existing default boot loader; backing it up and"
+         echo "installing rEFInd in its place."
+         if [[ -d "$InstallDir/EFI/BOOT-rEFIndBackup" ]] ; then
+            echo ""
+            echo "Caution: An existing backup of a default boot loader exists! If the current"
+            echo "default boot loader and the backup are different boot loaders, the current"
+            echo "one will become inaccessible."
+            echo ""
+            echo -n "Do you want to proceed with installation (Y/N)? "
+            ReadYesNo
+            if [[ $YesNo == "Y" || $YesNo == "y" ]] ; then
+               echo "OK; continuing with the installation..."
+            else
+               exit 0
+            fi
+         fi
+         mv -n "$InstallDir/EFI/BOOT" "$InstallDir/EFI/BOOT-rEFIndBackup"
+         SetVarsForBoot
+      fi
+   fi # BIOS-mode
+} # DetermineTargetDir()
+
+# Determine (or guess) the filesystem used on the Linux /boot filesystem.
+# Store the result in the BootFS global variable.
+SetBootFS() {
+   BootFS=""
+   case "$OSTYPE" in
+      linux*)
+           if command -v blkid &>/dev/null; then
+              BootPart=`df $RootDir/boot | grep dev | cut -f 1 -d " "`
+              BootFS=`blkid -o export $BootPart 2> /dev/null | grep TYPE= | cut -f 2 -d =`
+           fi
+           ;;
+      darwin*)
+           # 0FC63DAF-8483-4772-8E79-3D69D8477DE4 = Linux filesystem
+           # BC13C2FF-59E6-4262-A352-B275FD6F7172 = Freedesktop $boot partition
+           # 933AC7E1-2EB4-4F13-B844-0E14E2AEF915 = Freedesktop Linux /home
+           # E6D6D379-F507-44C2-A23C-238F2A3DF928 = Linux LVM
+           # A19D880F-05FC-4D3B-A006-743F0F84911E = Linux RAID
+           # 0657FD6D-A4AB-43C4-84E5-0933C84B4F4F = Linux swap
+           Temp=$(diskutil list | grep -i '0FC63DAF-8483-4772-8E79-3D69D8477DE4\|BC13C2FF-59E6-4262-A352-B275FD6F7172\|933AC7E1-2EB4-4F13-B844-0E14E2AEF915\|E6D6D379-F507-44C2-A23C-238F2A3DF928\|A19D880F-05FC-4D3B-A006-743F0F84911E\|0657FD6D-A4AB-43C4-84E5-0933C84B4F4F\|Linux')
+           BootFS=""
+           if [[ -n $Temp ]] ; then
+              echo "Found suspected Linux partition(s); installing ext4fs driver."
+              BootFS="ext4"
+           fi
+           ;;
+   esac
+} # SetBootFS()
+
+# Copy drivers from $RefindDir/drivers_$1 to $InstallDir/$TargetDir/drivers_$1,
+# honoring the $InstallDrivers condition. Must be passed a suitable
+# architecture code (ia32 or x64).
+CopyDrivers() {
+   if [[ $InstallDrivers == "all" ]] ; then
+      mkdir -p "$InstallDir/$TargetDir/drivers_$1"
+      cp "$ThisDir"/drivers_$1/*_$1.efi "$InstallDir/$TargetDir/drivers_$1/" 2> /dev/null
+      cp "$RefindDir"/drivers_$1/*_$1.efi "$InstallDir/$TargetDir/drivers_$1/" 2> /dev/null
+   elif [[ "$InstallDrivers" == "boot" ]] ; then
+      SetBootFS
+      DriverType=""
+      case $BootFS in
+         ext2 | ext3) DriverType="ext2"
+              # Could use ext4, but that can create unwanted entries from symbolic
+              # links in / to /boot/vmlinuz if a separate /boot partition is used.
+              ;;
+         ext4) DriverType="ext4"
+              ;;
+         reiserfs) DriverType="reiserfs"
+              ;;
+         btrfs) DriverType="btrfs"
+              ;;
+         hfsplus) DriverType="hfs"
+              ;;
+         ntfs) DriverType="ntfs"
+              ;;
+         *) BootFS=""
+      esac
+      if [[ -n $BootFS ]] ; then
+         echo "Installing driver for $BootFS (${DriverType}_$1.efi)"
+         mkdir -p "$InstallDir/$TargetDir/drivers_$1"
+         cp "$ThisDir/drivers_$1/${DriverType}_$1.efi" "$InstallDir/$TargetDir/drivers_$1/" 2> /dev/null
+         cp "$RefindDir/drivers_$1/${DriverType}_$1.efi" "$InstallDir/$TargetDir/drivers_$1"/ 2> /dev/null
+      fi
+   fi
+} # CopyDrivers()
+
+# Copy tools (currently only gptsync, and that only on Macs) to the EFI/tools
+# directory on the ESP. Must be passed a suitable architecture code (ia32
+# or x64).
+CopyTools() {
+   mkdir -p "$InstallDir/EFI/tools"
+   if [[ $OSTYPE == darwin* ]] ; then
+      cp -f "$RefindDir/tools_$1/gptsync_$1.efi" "$InstallDir/EFI/tools/"
+      if [[ -f "$InstallDir/EFI/tools/gptsync.efi" ]] ; then
+         mv "$InstallDir/EFI/tools/gptsync.efi" "$InstallDir/EFI/tools/gptsync.efi-disabled"
+         echo "Found old gptsync.efi; disabling it by renaming it to gptsync.efi-disabled"
+      fi
+   fi
+} # CopyTools()
+
+# Copy the rEFInd files to the ESP or OS X root partition.
+# Sets Problems=1 if any critical commands fail.
+CopyRefindFiles() {
+   mkdir -p "$InstallDir/$TargetDir"
+   if [[ "$TargetDir" == '/EFI/BOOT' ]] ; then
+      cp "$RefindDir/refind_ia32.efi" "$InstallDir/$TargetDir/$TargetIA32" 2> /dev/null
+      if [[ $? != 0 ]] ; then
+         echo "Note: IA32 (x86) binary not installed!"
+      fi
+      cp "$RefindDir/refind_x64.efi" "$InstallDir/$TargetDir/$TargetX64" 2> /dev/null
+      if [[ $? != 0 ]] ; then
+         Problems=1
+      fi
+      cp "$RefindDir/refind_aa64.efi" "$InstallDir/$TargetDir/$TargetAARCH64" 2> /dev/null
+      if [[ $? != 0 && $Platform == "aa64" ]] ; then
+         Problems=1
+      fi
+      if [[ "$ShimSource" != "none" ]] ; then
+         TargetShim="bootx64.efi"
+         CopyShimFiles
+      fi
+      if [[ $InstallDrivers == "all" ]] ; then
+         cp -r "$RefindDir"/drivers_* "$InstallDir/$TargetDir/" 2> /dev/null
+         cp -r "$ThisDir"/drivers_* "$InstallDir/$TargetDir/" 2> /dev/null
+      elif [[ $Upgrade == 1 || $InstallToEspOnMac == 1 ]] ; then
+         CopyDrivers "$Platform"
+         CopyTools "$Platform"
+      fi
+      Refind="boot$Platform.efi"
+      CopyKeys
+   elif [[ $Platform == 'x64' || $TargetDir == "/EFI/Microsoft/Boot" ]] ; then
+      cp "$RefindDir/refind_x64.efi" "$InstallDir/$TargetDir/$TargetX64"
+      if [[ $? != 0 ]] ; then
+         Problems=1
+      fi
+      CopyDrivers x64
+      CopyTools x64
+      Refind="refind_x64.efi"
+      CopyKeys
+      if [[ "$ShimSource" != "none" ]] ; then
+         if [[ "$TargetShim" == "default" ]] ; then
+            TargetShim=`basename "$ShimSource"`
+         fi
+         CopyShimFiles
+         Refind="$TargetShim"
+         if [[ $LocalKeys == 0 ]] ; then
+            echo "Storing copies of rEFInd Secure Boot public keys in $EtcKeysDir"
+            mkdir -p "$EtcKeysDir"
+            cp "$ThisDir/keys/refind.cer" "$EtcKeysDir" 2> /dev/null
+            cp "$ThisDir/keys/refind.crt" "$EtcKeysDir" 2> /dev/null
+         fi
+      fi
+      if [[ "$TargetDir" == '/System/Library/CoreServices' ]] ; then
+         SetupMacHfs $TargetX64
+      fi
+   elif [[ $Platform == 'ia32' || $Platform == 'aa64' ]] ; then
+      if [[ $Platform == 'ia32' ]] ; then
+         cp "$RefindDir/refind_ia32.efi" "$InstallDir/$TargetDir/$TargetIA32"
+         if [[ $? != 0 ]] ; then
+            Problems=1
+         fi
+      else
+         cp "$RefindDir/refind_aa64.efi" "$InstallDir/$TargetDir/$TargetAARCH64"
+         if [[ $? != 0 ]] ; then
+            Problems=1
+         fi
+      fi
+      CopyDrivers $Platform
+      CopyTools $Platform
+      Refind="refind_$Platform.efi"
+      if [[ "$TargetDir" == '/System/Library/CoreServices' ]] ; then
+         SetupMacHfs $TargetIA32
+      fi
+   else
+      echo "Unknown platform! Aborting!"
+      exit 1
+   fi
+   echo "Copied rEFInd binary files"
+   echo ""
+   if [[ -d "$InstallDir/$TargetDir/icons" ]] ; then
+      rm -rf "$InstallDir/$TargetDir/icons-backup" &> /dev/null
+      mv -f "$InstallDir/$TargetDir/icons" "$InstallDir/$TargetDir/icons-backup"
+      echo "Notice: Backed up existing icons directory as icons-backup."
+   fi
+   cp -r "$IconsDir" "$InstallDir/$TargetDir"
+   if [[ $? != 0 ]] ; then
+      Problems=1
+   fi
+   mkdir -p "$InstallDir/$TargetDir/keys"
+   cp -rf "$ThisDir"/keys/*.[cd]er "$InstallDir/$TargetDir/keys/" 2> /dev/null
+   cp -rf "$EtcKeysDir"/*.[cd]er "$InstallDir/$TargetDir/keys/" 2> /dev/null
+   if [[ -f "$InstallDir/$TargetDir/refind.conf" ]] ; then
+      echo "Existing refind.conf file found; copying sample file as refind.conf-sample"
+      echo "to avoid overwriting your customizations."
+      echo ""
+      cp -f "$ConfFile" "$InstallDir/$TargetDir"
+      if [[ $? != 0 ]] ; then
+         Problems=1
+      fi
+   else
+      echo "Copying sample configuration file as refind.conf; edit this file to configure"
+      echo "rEFInd."
+      echo ""
+      cp -f "$ConfFile" "$InstallDir/$TargetDir/refind.conf"
+      if [[ $? != 0 ]] ; then
+         Problems=1
+      fi
+   fi
+   if [[ $DeleteRefindDir == 1 ]] ; then
+      echo "Deleting the temporary directory $RefindDir"
+      rm -r "$RefindDir"
+   fi
+} # CopyRefindFiles()
+
+# Mount the partition the user specified with the --usedefault or --ownhfs option
+MountDefaultTarget() {
+   InstallDir=/tmp/refind_install
+   mkdir -p "$InstallDir"
+   UnmountEsp=1
+   if [[ $OSTYPE == darwin* ]] ; then
+      if [[ $OwnHfs == '1' ]] ; then
+         Temp=`diskutil info "$TargetPart" | grep "Mount Point"`
+         InstallDir=`echo $Temp | cut -f 3-30 -d ' '`
+         if [[ $InstallDir == '' ]] ; then
+            InstallDir=/tmp/refind_install
+            mount -t hfs "$TargetPart" "$InstallDir"
+         else
+            UnmountEsp=0
+         fi
+      else
+         mount -t msdos "$TargetPart" "$InstallDir"
+      fi
+   elif [[ $OSTYPE == linux* ]] ; then
+      mount -t vfat "$TargetPart" "$InstallDir"
+   fi
+   if [[ $? != 0 ]] ; then
+      echo "Couldn't mount $TargetPart ! Aborting!"
+      rmdir "$InstallDir"
+      exit 1
+   fi
+} # MountDefaultTarget()
+
+#
+# A series of OS X support functions....
+#
+
+# Mount the ESP at /Volumes/ESP or determine its current mount
+# point.
+# Sets InstallDir to the ESP mount point
+# Sets UnmountEsp if we mounted it
+MountOSXESP() {
+   # Identify the ESP. Note: This returns the FIRST ESP found;
+   # if the system has multiple disks, this could be wrong!
+   Temp=$(mount | sed -n -E "/^(\/dev\/disk[0-9]+s[0-9]+) on \/ \(.*$/s//\1/p")
+   if [ $Temp ]; then
+      Temp=$(diskutil list | grep " EFI " | grep -o 'disk.*' | head -n 1)
+      if [ -z $Temp ]; then
+         echo "Warning: root device doesn't have an EFI partition"
+      fi
+   else
+      echo "Warning: root device could not be found"
+   fi
+   if [ -z $Temp ]; then
+      Temp=$(diskutil list | sed -n -E '/^ *[0-9]+:[ ]+EFI EFI[ ]+[0-9.]+ [A-Z]+[ ]+(disk[0-9]+s[0-9]+)$/ { s//\1/p
+             q
+         }' )
+
+      if [ -z $Temp ]; then
+         echo "Could not find an EFI partition. Aborting!"
+         exit 1
+      fi
+   fi
+   Esp=/dev/`echo $Temp`
+   # If the ESP is mounted, use its current mount point....
+   Temp=`df -P | grep "$Esp "`
+   InstallDir=`echo $Temp | cut -f 6- -d ' '`
+   if [[ "$InstallDir" == '' ]] ; then
+      mkdir /Volumes/ESP &> /dev/null
+      mount -t msdos "$Esp" /Volumes/ESP
+      # Some systems have HFS+ "ESPs." They shouldn't, but they do. If this is
+      # detected, mount it as such and set appropriate options.
+      if [[ $? != 0 ]] ; then
+         mount -t hfs "$Esp" /Volumes/Esp
+         OwnHfs=1
+         InstallToEspOnMac=0
+         if [[ $? != 0 ]] ; then
+            echo "Unable to mount ESP! Aborting!\n"
+            exit 1
+         fi
+      fi
+      UnmountEsp=1
+      InstallDir="/Volumes/ESP"
+   fi
+} # MountOSXESP()
+
+# Set up for booting from Mac HFS+ volume that boots rEFInd in MJG's way
+# (http://mjg59.dreamwidth.org/7468.html)
+# Must be passed the original rEFInd binary filename (without a path).
+SetupMacHfs() {
+   if [[ -s "$InstallDir/mach_kernel" ]] ; then
+      echo "Attempt to install rEFInd to a partition with a /mach_kernel file! Aborting!"
+      exit 1
+   fi
+   cp -n "$InstallDir/$TargetDir/boot.efi" "$InstallDir/$TargetDir/boot.efi-backup" &> /dev/null
+   ln -f "$InstallDir/$TargetDir/$1" "$InstallDir/$TargetDir/boot.efi"
+   touch "$InstallDir/mach_kernel"
+   rm "$InstallDir/$TargetDir/SystemVersion.plist" &> /dev/null
+   cat - << ENDOFHERE >> "$InstallDir/$TargetDir/SystemVersion.plist"
+<xml version="1.0" encoding="UTF-8"?>
+<plist version="1.0">
+<dict>
+        <key>ProductBuildVersion</key>
+        <string></string>
+        <key>ProductName</key>
+        <string>rEFInd</string>
+        <key>ProductVersion</key>
+        <string>0.10.0</string>
+</dict>
+</plist>
+ENDOFHERE
+} # SetupMacHfs()
+
+CheckForSIP() {
+   if [[ -x "/usr/bin/csrutil" ]] ; then
+      local OKToInstall=`/usr/bin/csrutil status | \
+                         grep "Protection status: disabled\|enabled (Apple Internal)\|NVRAM Protections: disabled"`
+      if [[ -z "$OKToInstall" ]] ; then
+         echo
+         echo "**** ALERT: SIP ENABLED! ****"
+         echo
+         if [[ "$Upgrade" == "1" ]] ; then
+            echo "You are attempting to upgrade an existing installation, but it appears that"
+            echo "System Integrity Protection (SIP) is enabled. If rEFInd is working now, then"
+            echo "this is fine; you can upgrade your existing rEFInd. If rEFInd is not working,"
+            echo "though, re-installing from this boot will not help. To re-enable rEFInd, you"
+            echo "must re-install it from a Recovery system or from another OS. To enter the"
+            echo "Recovery system and re-install rEFInd:"
+         else
+            echo "rEFInd cannot be installed because System Integrity Protection (SIP) seems"
+            echo "to be enabled! You must install rEFInd from your Recovery installation or"
+            echo "from another OS. To install from the Recovery system:"
+         fi
+         echo
+         echo "  1. Reboot"
+         echo "  2. Hold down Command+R as the chime sounds"
+         echo "  3. When the OS has booted, select Utilities->Terminal"
+         echo "  4. Change to this directory with the 'cd' command; it will probably be under"
+         if [[ "`pwd | cut -b 1-8`" == "/Volumes" ]] ; then
+            echo "     `pwd`"
+         else
+            local RootName=`diskutil info -plist / | grep -A 1 VolumeName | grep string | cut -d \> -f 2 | cut -d \< -f 1`
+            echo "     /Volumes/$RootName`pwd`"
+         fi
+         echo "  5. Re-run this script."
+         echo
+         if [[ "$Upgrade" != "1" ]] ; then
+            echo "If you believe SIP is NOT enabled, you may attempt an installation anyhow,"
+            echo "but it may fail."
+            echo
+         fi
+         echo "For more on this subject, see http://www.rodsbooks.com/refind/sip.html"
+         echo
+         echo -n "Do you want to attempt installation (Y/N)? "
+         ReadYesNo
+         if [[ $YesNo == "N" || $YesNo == "n" ]] ; then
+            echo "Exiting!"
+            exit
+         fi
+      fi # csrutil status suggests OK to install
+   fi # csrutil exists
+} # CheckForSIP()
+
+# Control the OS X installation.
+# Sets Problems=1 if problems found during the installation.
+InstallOnOSX() {
+   echo "Installing rEFInd on OS X...."
+   if [[ "$InstallToEspOnMac" == "1" ]] ; then
+      MountOSXESP
+   elif [[ "$TargetDir" == "/EFI/BOOT" || "$OwnHfs" == '1' ]] ; then
+      MountDefaultTarget
+   else
+      InstallDir="$RootDir/"
+   fi
+   echo "Installing rEFInd to the partition mounted at $InstallDir"
+   DetermineTargetDir
+   CheckForSIP
+   CopyRefindFiles
+   cp "$ThisDir/mountesp" /usr/local/bin &> /dev/null
+   if [[ $InstallToEspOnMac == "1" ]] ; then
+      bless --mount "$InstallDir" --setBoot --file "$InstallDir/$TargetDir/$Refind" --shortform
+   elif [[ "$TargetDir" != "/EFI/BOOT" ]] ; then
+      bless --setBoot --folder "$InstallDir/$TargetDir" --file "$InstallDir/$TargetDir/$Refind"
+   fi
+   if [[ $? != 0 ]] ; then
+      Problems=1
+   fi
+   if [[ -f /Library/StartupItems/rEFItBlesser || -d /Library/StartupItems/rEFItBlesser ]] ; then
+      echo
+      echo "/Library/StartupItems/rEFItBlesser found!"
+      echo "This program is part of rEFIt, and will cause rEFInd to fail to work after"
+      echo -n "its first boot. Do you want to remove rEFItBlesser (Y/N)? "
+      ReadYesNo
+      if [[ $YesNo == "Y" || $YesNo == "y" ]] ; then
+         echo "Deleting /Library/StartupItems/rEFItBlesser..."
+         rm -r /Library/StartupItems/rEFItBlesser
+      else
+         echo "Not deleting rEFItBlesser."
+      fi
+   fi
+} # InstallOnOSX()
+
+
+#
+# Now a series of Linux support functions....
+#
+
+# Check for evidence that we're running in Secure Boot mode. If so, and if
+# appropriate options haven't been set, warn the user and offer to abort.
+# If we're NOT in Secure Boot mode but the user HAS specified the --shim
+# or --localkeys option, warn the user and offer to abort.
+CheckSecureBoot() {
+   local IsSecureBoot
+   if [[ -f /sys/firmware/efi/vars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c/data ]] ; then
+      IsSecureBoot=`od -An -t u1 /sys/firmware/efi/vars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c/data | tr -d '[[:space:]]'`
+   else
+      IsSecureBoot="0"
+   fi
+   if [[ $IsSecureBoot == "1" && "$TargetDir" != '/EFI/BOOT' && "$ShimSource" == "none" ]] ; then
+      echo ""
+      echo "CAUTION: Your computer appears to be booted with Secure Boot, but you haven't"
+      echo "specified a valid shim.efi file source. Chances are you should re-run with"
+      echo "the --shim option. You can read more about this topic at"
+      echo "http://www.rodsbooks.com/refind/secureboot.html."
+      echo ""
+      echo -n "Do you want to proceed with installation (Y/N)? "
+      ReadYesNo
+      if [[ $YesNo == "Y" || $YesNo == "y" ]] ; then
+         echo "OK; continuing with the installation..."
+      else
+         exit 0
+      fi
+   fi
+
+   if [[ "$ShimSource" != "none" && ! $IsSecureBoot == "1" ]] ; then
+      echo ""
+      echo "You've specified installing using a shim.efi file, but your computer does not"
+      echo "appear to be running in Secure Boot mode. Although installing in this way"
+      echo "should work, it's unnecessarily complex. You may continue, but unless you"
+      echo "plan to enable Secure Boot, you should consider stopping and omitting the"
+      echo "--shim option. You can read more about this topic at"
+      echo "http://www.rodsbooks.com/refind/secureboot.html."
+      echo ""
+      echo -n "Do you want to proceed with installation (Y/N)? "
+      ReadYesNo
+      if [[ $YesNo == "Y" || $YesNo == "y" ]] ; then
+         echo "OK; continuing with the installation..."
+      else
+         exit 0
+      fi
+   fi
+
+   if [[ $LocalKeys != 0 && ! $IsSecureBoot == "1" ]] ; then
+      echo ""
+      echo "You've specified re-signing your rEFInd binaries with locally-generated keys,"
+      echo "but your computer does not appear to be running in Secure Boot mode. The"
+      echo "keys you generate will be useless unless you enable Secure Boot. You may"
+      echo "proceed with this installation, but before you do so, you may want to read"
+      echo "more about it at http://www.rodsbooks.com/refind/secureboot.html."
+      echo ""
+      echo -n "Do you want to proceed with installation (Y/N)? "
+      ReadYesNo
+      if [[ $YesNo == "Y" || $YesNo == "y" ]] ; then
+         echo "OK; continuing with the installation..."
+      else
+         exit 0
+      fi
+   fi
+
+} # CheckSecureBoot()
+
+# Check for the presence of locally-generated keys from a previous installation in
+# $EtcKeysDir (/etc/refind.d/keys). If they're not present, generate them using
+# openssl.
+GenerateKeys() {
+   PrivateKey="$EtcKeysDir/$LocalKeysBase.key"
+   CertKey="$EtcKeysDir/$LocalKeysBase.crt"
+   DerKey="$EtcKeysDir/$LocalKeysBase.cer"
+   OpenSSL=`which openssl 2> /dev/null`
+
+   # Do the work only if one or more of the necessary keys is missing
+   # TODO: Technically, we don't need the DerKey; but if it's missing and openssl
+   # is also missing, this will fail. This could be improved.
+   if [[ ! -f "$PrivateKey" || ! -f "$CertKey" || ! -f "$DerKey" ]] ; then
+      echo "Generating a fresh set of local keys...."
+      mkdir -p "$EtcKeysDir"
+      chmod 0700 "$EtcKeysDir"
+      if [[ ! -x "$OpenSSL" ]] ; then
+         echo "Can't find openssl, which is required to create your private signing keys!"
+         echo "Aborting!"
+         exit 1
+      fi
+      if [[ -f "$PrivateKey" ]] ; then
+         echo "Backing up existing $PrivateKey"
+         cp -f "$PrivateKey" "$PrivateKey.backup" 2> /dev/null
+      fi
+      if [[ -f "$CertKey" ]] ; then
+         echo "Backing up existing $CertKey"
+         cp -f "$CertKey" "$CertKey.backup" 2> /dev/null
+      fi
+      if [[ -f "$DerKey" ]] ; then
+         echo "Backing up existing $DerKey"
+         cp -f "$DerKey" "$DerKey.backup" 2> /dev/null
+      fi
+      "$OpenSSL" req -new -x509 -newkey rsa:2048 -keyout "$PrivateKey" -out "$CertKey" \
+                     -nodes -days 3650 -subj "/CN=Locally-generated rEFInd key/"
+      "$OpenSSL" x509 -in "$CertKey" -out "$DerKey" -outform DER
+      chmod 0600 "$PrivateKey"
+   else
+      echo "Using existing local keys...."
+   fi
+}
+
+# Sign a single binary. Requires parameters:
+#   $1 = source file
+#   $2 = destination file
+# Also assumes that the SBSign, PESign, UseSBSign, UsePESign, and various key variables are set
+# appropriately.
+# Aborts script on error
+SignOneBinary() {
+   $SBSign --key "$PrivateKey" --cert "$CertKey" --output "$2" "$1"
+   if [[ $? != 0 ]] ; then
+      echo "Problem signing the binary $1! Aborting!"
+      exit 1
+   fi
+}
+
+# Re-sign the x86-64 binaries with a locally-generated key, First look for appropriate
+# key files in $EtcKeysDir. If they're present, use them to re-sign the binaries. If
+# not, try to generate new keys and store them in $EtcKeysDir.
+ReSignBinaries() {
+   SBSign=`which sbsign 2> /dev/null`
+   echo "Found sbsign at $SBSign"
+   TempDir="/tmp/refind_local"
+   if [[ ! -x "$SBSign" ]] ; then
+      echo "Can't find sbsign, which is required to sign rEFInd with your own keys!"
+      echo "Aborting!"
+      exit 1
+   fi
+   GenerateKeys
+   mkdir -p "$TempDir/drivers_$Platform"
+   cp "$RefindDir/refind.conf-sample $TempDir" 2> /dev/null
+   cp "$ThisDir/refind.conf-sample $TempDir" 2> /dev/null
+   cp "$RefindDir/refind_ia32.efi $TempDir" 2> /dev/null
+   cp -a "$RefindDir/drivers_ia32 $TempDir" 2> /dev/null
+   cp -a "$ThisDir/drivers_ia32 $TempDir" 2> /dev/null
+   SignOneBinary "$RefindDir/refind_$Platform.efi" "$TempDir/refind_$Platform.efi"
+   SaveIFS=$IFS
+   IFS=$(echo -en "\n\b")
+   for Driver in `ls "$RefindDir"/drivers_$Platform/*.efi "$ThisDir"/drivers_$Platform/*.efi 2> /dev/null` ; do
+      TempName=`basename "$Driver"`
+      SignOneBinary "$Driver" "$TempDir/drivers_$Platform/$TempName"
+   done
+   IFS=$SaveIFS
+   RefindDir="$TempDir"
+   DeleteRefindDir=1
+} # ReSignBinaries()
+
+# Locate and mount an ESP, if possible, based on parted output.
+# Should be called only if /boot/efi is NOT an acceptable ESP.
+# Sets InstallDir to the mounted ESP's path ($RootDir/boot/efi)
+# and EspFilesystem the filesystem (always "vfat")
+FindLinuxESP() {
+   echo "The ESP doesn't seem to be mounted! Trying to find it...."
+   local Drive
+   local PartNum
+   local TableType
+   local DmStatus
+   local SkipIt
+   local Dmraid
+   for Drive in `ls /dev/[sh]d?` ; do
+      SkipIt=0
+      Dmraid=`which dmraid 2> /dev/null`
+      if [ -x "$Dmraid" ] ; then
+         DmStatus=`dmraid -r | grep $Drive`
+         if [ -n "$DmStatus" ] ; then
+            echo "$Drive seems to be part of a RAID array; skipping!"
+            SkipIt=1
+         fi
+      fi
+      TableType=`parted $Drive print -m -s 2>/dev/null | awk -F: '$1 == "'$Drive'" { print $6 }'`
+      if [[ $TableType == 'gpt' && $SkipIt == 0 ]] ; then # read only GPT disks that aren't part of dmraid array
+         PartNum=`LANG=C parted $Drive print -m -s 2>/dev/null | awk -F: '$7 ~ "(^boot| boot)" { print $1 }' | head -n 1`
+         if [ "$PartNum" -eq "$PartNum" ] 2> /dev/null ; then
+            InstallDir="$RootDir/boot/efi"
+            mkdir -p $InstallDir
+            mount $Drive$PartNum $InstallDir
+            EspFilesystem=`grep "$Drive$PartNum.*/boot/efi" /etc/mtab | uniq | grep -v autofs | cut -d " " -f 3`
+            if [[ $EspFilesystem != 'vfat' ]] ; then
+               umount $InstallDir
+            else
+               echo "Mounting ESP at $InstallDir"
+               break;
+            fi
+         fi # $PartNum -eq $PartNum
+      fi # TableType
+   done
+} # FindLinuxESP()
+
+# Identifies the ESP's location (/boot or /boot/efi, or these locations under
+# the directory specified by --root); aborts if the ESP isn't mounted at
+# either location.
+# Sets InstallDir to the ESP mount point.
+FindMountedESP() {
+   mount /boot &> /dev/null
+   mount /boot/efi &> /dev/null
+   EspLine=`df "$RootDir/boot/efi" 2> /dev/null | grep boot/efi`
+   if [[ ! -n "$EspLine" ]] ; then
+      EspLine=`df "$RootDir"/boot | grep boot`
+   fi
+   InstallDir=`echo $EspLine | cut -d " " -f 6`
+
+   if [[ -n "$InstallDir" ]] ; then
+      EspFilesystem=`grep -w "$InstallDir" /etc/mtab | uniq | grep -v autofs | cut -d " " -f 3`
+   fi
+   if [[ $EspFilesystem != 'vfat' ]] ; then
+      FindLinuxESP
+   fi
+   if [[ $EspFilesystem != 'vfat' ]] ; then
+      echo "$RootDir/$InstallDir doesn't seem to be on a VFAT filesystem. The ESP must be"
+      echo "mounted at $RootDir/boot or $RootDir/boot/efi and it must be VFAT! Aborting!"
+      exit 1
+   fi
+   echo "ESP was found at $InstallDir using $EspFilesystem"
+} # FindMountedESP
+
+# Uses efibootmgr to add an entry for rEFInd to the EFI's NVRAM.
+# If this fails, sets Problems=1
+AddBootEntry() {
+   local PartNum
+   Efibootmgr=`which efibootmgr 2> /dev/null`
+   if [[ "$Efibootmgr" ]] ; then
+      InstallDisk=`grep "$InstallDir" /etc/mtab | cut -d " " -f 1 | cut -c 1-8`
+      PartNum=`grep "$InstallDir" /etc/mtab | cut -d " " -f 1 | cut -c 9-10`
+      EntryFilename="$TargetDir/$Refind"
+      EfiEntryFilename=`echo ${EntryFilename//\//\\\}`
+      EfiEntryFilename2=`echo ${EfiEntryFilename} | sed s/\\\\\\\\/\\\\\\\\\\\\\\\\/g`
+      ExistingEntry=`"$Efibootmgr" -v | grep -i "$EfiEntryFilename2"`
+
+      if [[ "$ExistingEntry" ]] ; then
+         ExistingEntryBootNum=`echo "$ExistingEntry" | cut -c 5-8`
+         FirstBoot=`"$Efibootmgr" | grep BootOrder | cut -c 12-15`
+         if [[ "$ExistingEntryBootNum" != "$FirstBoot" ]] ; then
+            echo "An existing rEFInd boot entry exists, but isn't set as the default boot"
+            echo "manager. The boot order is being adjusted to make rEFInd the default boot"
+            echo "manager. If this is NOT what you want, you should use efibootmgr to"
+            echo "manually adjust your EFI's boot order."
+         fi
+         "$Efibootmgr" -b $ExistingEntryBootNum -B &> /dev/null
+      fi
+
+      echo "Installing it!"
+      if [[ "$KeepName" == 0 ]] ; then
+         "$Efibootmgr" -c -l "$EfiEntryFilename" -L "rEFInd Boot Manager" -d $InstallDisk -p $PartNum &> /dev/null
+      else
+         "$Efibootmgr" -c -l "$EfiEntryFilename" -L "rEFInd Boot Manager" -d $InstallDisk -p $PartNum \
+                       -u "$TargetShim $TargetX64" &> /dev/null
+      fi
+      if [[ $? != 0 ]] ; then
+         EfibootmgrProblems=1
+         Problems=1
+      fi
+
+   else # efibootmgr not found
+      EfibootmgrProblems=1
+      Problems=1
+   fi
+
+   if [[ $EfibootmgrProblems ]] ; then
+      echo
+      echo "ALERT: There were problems running the efibootmgr program! You may need to"
+      echo "rename the $Refind binary to the default name (EFI/BOOT/bootx64.efi"
+      echo "on x86-64 systems, EFI/BOOT/bootia32.efi on x86 systems, or"
+      echo "EFI/BOOT/bootaa64.efi on ARM64 systems) to have it run!"
+      echo
+   else
+      echo "rEFInd has been set as the default boot manager."
+   fi
+} # AddBootEntry()
+
+# Create a minimal/sample refind_linux.conf file in /boot.
+GenerateRefindLinuxConf() {
+   if [[ -f "$RLConfFile" ]] ; then
+      echo "Existing $RLConfFile found; not overwriting."
+   else
+      echo "Creating $RLConfFile; edit it to adjust kernel options."
+      RootFS=`df "$RootDir" | grep dev | cut -f 1 -d " "`
+      StartOfDevname=`echo "$RootFS" | cut -b 1-7`
+      if [[ "$StartOfDevname" == "/dev/sd" || "$StartOfDevName" == "/dev/hd" ]] ; then
+         # Identify root filesystem by UUID rather than by device node, if possible
+         Uuid=`blkid -o export -s UUID "$RootFS" 2> /dev/null | grep UUID=`
+         if [[ -n $Uuid ]] ; then
+            RootFS="$Uuid"
+         fi
+      fi
+      if [[ $RootDir == "/" ]] ; then
+         local FirstCmdlineOption=`cat /proc/cmdline | cut -d ' ' -f 1`
+         if [[ "$FirstCmdlineOption" =~ (vmlinuz|bzImage|kernel) ]] ; then
+            DefaultOptions=`cat /proc/cmdline | cut -d ' ' -f 2- | sed 's/\S*initrd=\S*//g' | sed 's/ *$//' | sed 's/^ *//'`
+         else
+            DefaultOptions=`cat /proc/cmdline | sed 's/\S*initrd=\S*//g' | sed 's/ *$//' | sed 's/^ *//'`
+         fi
+      else
+         if [[ -f "$RootDir/etc/default/grub" ]] ; then
+            # We want the default options used by the distribution, stored here....
+            source "$RootDir/etc/default/grub"
+            echo "Setting default boot options based on $RootDir/etc/default/grub"
+         fi
+         DefaultOptions="ro root=$RootFS $GRUB_CMDLINE_LINUX $GRUB_CMDLINE_LINUX_DEFAULT"
+      fi
+      echo "\"Boot with standard options\"  \"$DefaultOptions\"" > $RLConfFile
+      echo "\"Boot to single-user mode\"    \"$DefaultOptions single\"" >> $RLConfFile
+      echo "\"Boot with minimal options\"   \"ro root=$RootFS\"" >> $RLConfFile
+   fi
+}
+
+# Controls rEFInd installation under Linux.
+# Sets Problems=1 if something goes wrong.
+InstallOnLinux() {
+   if [[ "$TargetDir" == "/System/Library/CoreServices" ]] ; then
+      echo "You may not use the --ownhfs option under Linux! Aborting!"
+      exit 1
+   fi
+   echo "Installing rEFInd on Linux...."
+   modprobe efivars &> /dev/null
+   if [[ $TargetDir == "/EFI/BOOT" ]] ; then
+      MountDefaultTarget
+   else
+      FindMountedESP
+      DetermineTargetDir
+   fi
+
+   if [[ $LocalKeys == 1 ]] ; then
+      ReSignBinaries
+   fi
+
+   CheckSecureBoot
+   CopyRefindFiles
+   if [[ "$TargetDir" != "/EFI/BOOT" && "$TargetDir" != "/EFI/Microsoft/Boot" ]] ; then
+      AddBootEntry
+      GenerateRefindLinuxConf
+   fi
+} # InstallOnLinux()
+
+#
+# The main part of the script. Sets a few environment variables,
+# performs a few startup checks, and then calls functions to
+# install under OS X or Linux, depending on the detected platform.
+#
+GetParams "$@"
+if [[ $UID != 0 ]] ; then
+   echo "Not running as root; attempting to elevate privileges via sudo...."
+   sudo "$BASH_SOURCE" "$@"
+   if [[ $? != 0 ]] ; then
+      echo "This script must be run as root (or using sudo). Exiting!"
+      exit 1
+   else
+      exit 0
+   fi
+fi
+DeterminePlatform
+CheckForFiles
+case "$OSTYPE" in
+   darwin*)
+        if [[ "$ShimSource" != "none" ]] ; then
+           echo "The --shim option is not supported on OS X! Exiting!"
+           exit 1
+        fi
+        if [[ "$LocalKeys" != 0 ]] ; then
+           echo "The --localkeys option is not supported on OS X! Exiting!"
+           exit 1
+        fi
+        InstallOnOSX $1
+        ;;
+   linux*)
+        InstallOnLinux
+        ;;
+   *)
+        echo "Running on unknown OS; aborting!"
+        if [[ "$InstallToEspOnMac" == 0 ]] ; then
+           echo "The --notesp option is not supported on Linux! Exiting!"
+           exit 1
+        fi
+esac
+
+if [[ $Problems ]] ; then
+   echo
+   echo "ALERT:"
+   echo "Installation has completed, but problems were detected. Review the output for"
+   echo "error messages and take corrective measures as necessary. You may need to"
+   echo "re-run this script or install manually before rEFInd will work."
+   echo
+else
+   echo
+   echo "Installation has completed successfully."
+   echo
+fi
+
+if [[ $UnmountEsp == '1' ]] ; then
+   echo "Unmounting install dir"
+   case "$OSTYPE" in
+   darwin*)
+      diskutil unmount $InstallDir
+      ;;
+   *)
+      umount $InstallDir
+      ;;
+   esac
+fi
+
+if [[ "$InstallDir" == /tmp/refind_install ]] ; then
+#   sleep 5
+   rmdir "$InstallDir"
+fi
diff --git a/refind.conf-sample b/refind.conf-sample
new file mode 100644 (file)
index 0000000..a1c57b5
--- /dev/null
@@ -0,0 +1,516 @@
+#
+# refind.conf
+# Configuration file for the rEFInd boot menu
+#
+
+# Timeout in seconds for the main menu screen. Setting the timeout to 0
+# disables automatic booting (i.e., no timeout). Setting it to -1 causes
+# an immediate boot to the default OS *UNLESS* a keypress is in the buffer
+# when rEFInd launches, in which case that keypress is interpreted as a
+# shortcut key. If no matching shortcut is found, rEFInd displays its
+# menu with no timeout.
+#
+timeout 20
+
+# Screen saver timeout; the screen blanks after the specified number of
+# seconds with no keyboard input. The screen returns after most keypresses
+# (unfortunately, not including modifier keys such as Shift, Control, Alt,
+# or Option). Setting a value of "-1" causes rEFInd to start up with its
+# screen saver active. The default is 0, which disables the screen saver.
+#screensaver 300
+
+# Hide user interface elements for personal preference or to increase
+# security:
+#  banner      - the rEFInd title banner (built-in or loaded via "banner")
+#  label       - boot option text label in the menu
+#  singleuser  - remove the submenu options to boot Mac OS X in single-user
+#                or verbose modes; affects ONLY MacOS X
+#  safemode    - remove the submenu option to boot Mac OS X in "safe mode"
+#  hwtest      - the submenu option to run Apple's hardware test
+#  arrows      - scroll arrows on the OS selection tag line
+#  hints       - brief command summary in the menu
+#  editor      - the options editor (+, F2, or Insert on boot options menu)
+#  badges      - device-type badges for boot options
+#  all         - all of the above
+# Default is none of these (all elements active)
+#
+#hideui singleuser
+#hideui all
+
+# Set the name of a subdirectory in which icons are stored. Icons must
+# have the same names they have in the standard directory. The directory
+# name is specified relative to the main rEFInd binary's directory. If
+# an icon can't be found in the specified directory, an attempt is made
+# to load it from the default directory; thus, you can replace just some
+# icons in your own directory and rely on the default for others.
+# Default is "icons".
+#
+#icons_dir myicons
+#icons_dir icons/snowy
+
+# Use a custom title banner instead of the rEFInd icon and name. The file
+# path is relative to the directory where refind.efi is located. The color
+# in the top left corner of the image is used as the background color
+# for the menu screens. Currently uncompressed BMP images with color
+# depths of 24, 8, 4 or 1 bits are supported, as well as PNG images.
+#
+#banner hostname.bmp
+#banner mybanner.png
+#banner icons/snowy/banner-snowy.png
+
+# Specify how to handle banners that aren't exactly the same as the screen
+# size:
+#  noscale     - Crop if too big, show with border if too small
+#  fillscreen  - Fill the screen
+# Default is noscale
+#
+#banner_scale fillscreen
+
+# Icon sizes. All icons are square, so just one value is specified. The
+# big icons are used for OS selectors in the first row and the small
+# icons are used for tools on the second row. Drive-type badges are 1/4
+# the size of the big icons. Legal values are 32 and above. If the icon
+# files do not hold icons of the proper size, the icons are scaled to
+# the specified size. The default values are 48 and 128 for small and
+# big icons, respectively.
+#
+#small_icon_size 96
+#big_icon_size 256
+
+# Custom images for the selection background. There is a big one (144 x 144)
+# for the OS icons, and a small one (64 x 64) for the function icons in the
+# second row. If only a small image is given, that one is also used for
+# the big icons by stretching it in the middle. If only a big one is given,
+# the built-in default will be used for the small icons.
+#
+# Like the banner option above, these options take a filename of an
+# uncompressed BMP image file with a color depth of 24, 8, 4, or 1 bits,
+# or a PNG image. The PNG format is required if you need transparency
+# support (to let you "see through" to a full-screen banner).
+#
+#selection_big   selection-big.bmp
+#selection_small selection-small.bmp
+
+# Set the font to be used for all textual displays in graphics mode.
+# The font must be a PNG file with alpha channel transparency. It must
+# contain ASCII characters 32-126 (space through tilde), inclusive, plus
+# a glyph to be displayed in place of characters outside of this range,
+# for a total of 96 glyphs. Only monospaced fonts are supported. Fonts
+# may be of any size, although large fonts can produce display
+# irregularities.
+# The default is rEFInd's built-in font, Luxi Mono Regular 12 point.
+#
+#font myfont.png
+
+# Use text mode only. When enabled, this option forces rEFInd into text mode.
+# Passing this option a "0" value causes graphics mode to be used. Pasing
+# it no value or any non-0 value causes text mode to be used.
+# Default is to use graphics mode.
+#
+#textonly
+
+# Set the EFI text mode to be used for textual displays. This option
+# takes a single digit that refers to a mode number. Mode 0 is normally
+# 80x25, 1 is sometimes 80x50, and higher numbers are system-specific
+# modes. Mode 1024 is a special code that tells rEFInd to not set the
+# text mode; it uses whatever was in use when the program was launched.
+# If you specify an invalid mode, rEFInd pauses during boot to inform
+# you of valid modes.
+# CAUTION: On VirtualBox, and perhaps on some real computers, specifying
+# a text mode and uncommenting the "textonly" option while NOT specifying
+# a resolution can result in an unusable display in the booted OS.
+# Default is 1024 (no change)
+#
+#textmode 2
+
+# Set the screen's video resolution. Pass this option either:
+#  * two values, corresponding to the X and Y resolutions
+#  * one value, corresponding to a GOP (UEFI) video mode
+# Note that not all resolutions are supported. On UEFI systems, passing
+# an incorrect value results in a message being shown on the screen to
+# that effect, along with a list of supported modes. On EFI 1.x systems
+# (e.g., Macintoshes), setting an incorrect mode silently fails. On both
+# types of systems, setting an incorrect resolution results in the default
+# resolution being used. A resolution of 1024x768 usually works, but higher
+# values often don't.
+# Default is "0 0" (use the system default resolution, usually 800x600).
+#
+#resolution 1024 768
+#resolution 1440 900
+#resolution 3
+
+# Launch specified OSes in graphics mode. By default, rEFInd switches
+# to text mode and displays basic pre-launch information when launching
+# all OSes except OS X. Using graphics mode can produce a more seamless
+# transition, but displays no information, which can make matters
+# difficult if you must debug a problem. Also, on at least one known
+# computer, using graphics mode prevents a crash when using the Linux
+# kernel's EFI stub loader. You can specify an empty list to boot all
+# OSes in text mode.
+# Valid options:
+#   osx     - Mac OS X
+#   linux   - A Linux kernel with EFI stub loader
+#   elilo   - The ELILO boot loader
+#   grub    - The GRUB (Legacy or 2) boot loader
+#   windows - Microsoft Windows
+# Default value: osx
+#
+#use_graphics_for osx,linux
+
+# Which non-bootloader tools to show on the tools line, and in what
+# order to display them:
+#  shell            - the EFI shell (requires external program; see rEFInd
+#                     documentation for details)
+#  memtest          - the memtest86 program, in EFI/tools, EFI/memtest86,
+#                     EFI/memtest, EFI/tools/memtest86, or EFI/tools/memtest
+#  gptsync          - the (dangerous) gptsync.efi utility (requires external
+#                     program; see rEFInd documentation for details)
+#  gdisk            - the gdisk partitioning program
+#  apple_recovery   - boots the Apple Recovery HD partition, if present
+#  windows_recovery - boots an OEM Windows recovery tool, if present
+#                     (see also the windows_recovery_files option)
+#  mok_tool         - makes available the Machine Owner Key (MOK) maintenance
+#                     tool, MokManager.efi, used on Secure Boot systems
+#  csr_rotate       - adjusts Apple System Integrity Protection (SIP)
+#                     policy. Requires "csr_values" to be set.
+#  about            - an "about this program" option
+#  exit             - a tag to exit from rEFInd
+#  shutdown         - shuts down the computer (a bug causes this to reboot
+#                     many UEFI systems)
+#  reboot           - a tag to reboot the computer
+#  firmware         - a tag to reboot the computer into the firmware's
+#                     user interface (ignored on older computers)
+#  netboot          - launch the ipxe.efi tool for network (PXE) booting
+# Default is shell,memtest,gdisk,apple_recovery,windows_recovery,mok_tool,about,shutdown,reboot,firmware
+#
+#showtools shell, gdisk, memtest, mok_tool, apple_recovery, windows_recovery, about, reboot, exit, firmware
+
+# Boot loaders that can launch a Windows restore or emergency system.
+# These tend to be OEM-specific.
+# Default is LRS_ESP:/EFI/Microsoft/Boot/LrsBootmgr.efi
+#
+#windows_recovery_files LRS_ESP:/EFI/Microsoft/Boot/LrsBootmgr.efi
+
+# Directories in which to search for EFI drivers. These drivers can
+# provide filesystem support, give access to hard disks on plug-in
+# controllers, etc. In most cases none are needed, but if you add
+# EFI drivers and you want rEFInd to automatically load them, you
+# should specify one or more paths here. rEFInd always scans the
+# "drivers" and "drivers_{arch}" subdirectories of its own installation
+# directory (where "{arch}" is your architecture code); this option
+# specifies ADDITIONAL directories to scan.
+# Default is to scan no additional directories for EFI drivers
+#
+#scan_driver_dirs EFI/tools/drivers,drivers
+
+# Which types of boot loaders to search, and in what order to display them:
+#  internal      - internal EFI disk-based boot loaders
+#  external      - external EFI disk-based boot loaders
+#  optical       - EFI optical discs (CD, DVD, etc.)
+#  netboot       - EFI network (PXE) boot options
+#  hdbios        - BIOS disk-based boot loaders
+#  biosexternal  - BIOS external boot loaders (USB, eSATA, etc.)
+#  cd            - BIOS optical-disc boot loaders
+#  manual        - use stanzas later in this configuration file
+# Note that the legacy BIOS options require firmware support, which is
+# not present on all computers.
+# The netboot option is experimental and relies on the ipxe.efi and
+# ipxe_discover.efi program files.
+# On UEFI PCs, default is internal,external,optical,manual
+# On Macs, default is internal,hdbios,external,biosexternal,optical,cd,manual
+#
+#scanfor internal,external,optical,manual
+
+# By default, rEFInd relies on the UEFI firmware to detect BIOS-mode boot
+# devices. This sometimes doesn't detect all the available devices, though.
+# For these cases, uefi_deep_legacy_scan results in a forced scan and
+# modification of NVRAM variables on each boot. Adding "0", "off", or
+# "false" resets to the default value. This token has no effect on Macs or
+# when no BIOS-mode options are set via scanfor.
+# Default is unset (or "uefi_deep_legacy_scan false")
+#
+#uefi_deep_legacy_scan
+
+# Delay for the specified number of seconds before scanning disks.
+# This can help some users who find that some of their disks
+# (usually external or optical discs) aren't detected initially,
+# but are detected after pressing Esc.
+# The default is 0.
+#
+#scan_delay 5
+
+# When scanning volumes for EFI boot loaders, rEFInd always looks for
+# Mac OS X's and Microsoft Windows' boot loaders in their normal locations,
+# and scans the root directory and every subdirectory of the /EFI directory
+# for additional boot loaders, but it doesn't recurse into these directories.
+# The also_scan_dirs token adds more directories to the scan list.
+# Directories are specified relative to the volume's root directory. This
+# option applies to ALL the volumes that rEFInd scans UNLESS you include
+# a volume name and colon before the directory name, as in "myvol:/somedir"
+# to scan the somedir directory only on the filesystem named myvol. If a
+# specified directory doesn't exist, it's ignored (no error condition
+# results). The default is to scan the "boot" directory in addition to
+# various hard-coded directories.
+#
+#also_scan_dirs boot,ESP2:EFI/linux/kernels
+
+# Partitions (or whole disks, for legacy-mode boots) to omit from scans.
+# For EFI-mode scans, you must specify a volume by its label, which you
+# can obtain in an EFI shell by typing "vol", from Linux by typing
+# "blkid /dev/{devicename}", or by examining the disk's label in various
+# OSes' file browsers.
+# For legacy-mode scans, you can specify any subset of the boot loader
+# description shown when you highlight the option in rEFInd.
+# The default is "LRS_ESP".
+#
+#dont_scan_volumes "Recovery HD"
+
+# Directories that should NOT be scanned for boot loaders. By default,
+# rEFInd doesn't scan its own directory, the EFI/tools directory, the
+# EFI/memtest directory, the EFI/memtest86 directory, or the
+# com.apple.recovery.boot directory. Using the dont_scan_dirs option
+# enables you to "blacklist" other directories; but be sure to use "+"
+# as the first element if you want to continue blacklisting existing
+# directories. You might use this token to keep EFI/boot/bootx64.efi out
+# of the menu if that's a duplicate of another boot loader or to exclude
+# a directory that holds drivers or non-bootloader utilities provided by
+# a hardware manufacturer. If a directory is listed both here and in
+# also_scan_dirs, dont_scan_dirs takes precedence. Note that this
+# blacklist applies to ALL the filesystems that rEFInd scans, not just
+# the ESP, unless you precede the directory name by a filesystem name,
+# as in "myvol:EFI/somedir" to exclude EFI/somedir from the scan on the
+# myvol volume but not on other volumes.
+#
+#dont_scan_dirs ESP:/EFI/boot,EFI/Dell,EFI/memtest86
+
+# Files that should NOT be included as EFI boot loaders (on the
+# first line of the display). If you're using a boot loader that
+# relies on support programs or drivers that are installed alongside
+# the main binary or if you want to "blacklist" certain loaders by
+# name rather than location, use this option. Note that this will
+# NOT prevent certain binaries from showing up in the second-row
+# set of tools. Most notably, various Secure Boot and recovery
+# tools are present in this list, but may appear as second-row
+# items.
+# The file may be specified as a bare name (e.g., "notme.efi"), as
+# a complete filename (e.g., "/EFI/somedir/notme.efi"), or as a
+# complete filename with volume (e.g., "SOMEDISK:/EFI/somedir/notme.efi").
+# The default is shim.efi,shim-fedora.efi,shimx64.efi,PreLoader.efi,
+# TextMode.efi,ebounce.efi,GraphicsConsole.efi,MokManager.efi,HashTool.efi,
+# HashTool-signed.efi,bootmgr.efi
+#
+#dont_scan_files shim.efi,MokManager.efi
+
+# Scan for Linux kernels that lack a ".efi" filename extension. This is
+# useful for better integration with Linux distributions that provide
+# kernels with EFI stub loaders but that don't give those kernels filenames
+# that end in ".efi", particularly if the kernels are stored on a
+# filesystem that the EFI can read. When set to "1", "true", or "on", this
+# option causes all files in scanned directories with names that begin with
+# "vmlinuz" or "bzImage" to be included as loaders, even if they lack ".efi"
+# extensions. Passing this option a "0", "false", or "off" value causes
+# kernels without ".efi" extensions to NOT be scanned.
+# Default is "true" -- to scan for kernels without ".efi" extensions.
+#
+#scan_all_linux_kernels false
+
+# Combine all Linux kernels in a given directory into a single entry.
+# When so set, the kernel with the most recent time stamp will be launched
+# by default, and its filename will appear in the entry's description.
+# To launch other kernels, the user must press F2 or Insert; alternate
+# kernels then appear as options on the sub-menu.
+# Default is "true" -- kernels are "folded" into a single menu entry.
+#
+#fold_linux_kernels false
+
+# Set the maximum number of tags that can be displayed on the screen at
+# any time. If more loaders are discovered than this value, rEFInd shows
+# a subset in a scrolling list. If this value is set too high for the
+# screen to handle, it's reduced to the value that the screen can manage.
+# If this value is set to 0 (the default), it's adjusted to the number
+# that the screen can handle.
+#
+#max_tags 0
+
+# Set the default menu selection.  The available arguments match the
+# keyboard accelerators available within rEFInd.  You may select the
+# default loader using:
+#  - A digit between 1 and 9, in which case the Nth loader in the menu
+#    will be the default. 
+#  - A "+" symbol at the start of the string, which refers to the most
+#    recently booted loader.
+#  - Any substring that corresponds to a portion of the loader's title
+#    (usually the OS's name, boot loader's path, or a volume or
+#    filesystem title).
+# You may also specify multiple selectors by separating them with commas
+# and enclosing the list in quotes. (The "+" option is only meaningful in
+# this context.)
+# If you follow the selector(s) with two times, in 24-hour format, the
+# default will apply only between those times. The times are in the
+# motherboard's time standard, whether that's UTC or local time, so if
+# you use UTC, you'll need to adjust this from local time manually.
+# Times may span midnight as in "23:30 00:30", which applies to 11:30 PM
+# to 12:30 AM. You may specify multiple default_selection lines, in which
+# case the last one to match takes precedence. Thus, you can set a main
+# option without a time followed by one or more that include times to
+# set different defaults for different times of day.
+# The default behavior is to boot the previously-booted OS.
+#
+#default_selection 1
+#default_selection Microsoft
+#default_selection "+,bzImage,vmlinuz"
+#default_selection Maintenance 23:30 2:00
+#default_selection "Maintenance,OS X" 1:00 2:30
+
+# Enable VMX bit and lock the CPU MSR if unlocked.
+# On some Intel Apple computers, the firmware does not lock the MSR 0x3A.
+# The symptom on Windows is Hyper-V not working even if the CPU
+# meets the minimum requirements (HW assisted virtualization and SLAT)
+# DO NOT SET THIS EXCEPT ON INTEL CPUs THAT SUPPORT VMX! See
+# http://www.thomas-krenn.com/en/wiki/Activating_the_Intel_VT_Virtualization_Feature!
+# for more on this subject.
+# The default is false: Don't try to enable and lock the MSR.
+#
+#enable_and_lock_vmx false
+
+# Tell a Mac's EFI that OS X is about to be launched, even when it's not.
+# This option causes some Macs to initialize their hardware differently than
+# when a third-party OS is launched normally. In some cases (particularly on
+# Macs with multiple video cards), using this option can cause hardware to
+# work that would not otherwise work. On the other hand, using this option
+# when it is not necessary can cause hardware (such as keyboards and mice) to
+# become inaccessible. Therefore, you should not enable this option if your
+# non-Apple OSes work correctly; enable it only if you have problems with
+# some hardware devices. When needed, a value of "10.9" usually works, but
+# you can experiment with other values. This feature has no effect on
+# non-Apple computers.
+# The default is inactive (no OS X spoofing is done).
+#
+#spoof_osx_version 10.9
+
+# Set the CSR values for Apple's System Integrity Protection (SIP) feature.
+# Values are one-byte (two-character) hexadecimal numbers. These values
+# define which specific security features are enabled. Below are the codes
+# for what the values mean. Add them up (in hexadecimal!) to set new values.
+# Apple's "csrutil enable" and "csrutil disable" commands set values of 10
+# and 77, respectively.
+#   CSR_ALLOW_UNTRUSTED_KEXTS       0x01
+#   CSR_ALLOW_UNRESTRICTED_FS       0x02
+#   CSR_ALLOW_TASK_FOR_PID          0x04
+#   CSR_ALLOW_KERNEL_DEBUGGER       0x08
+#   CSR_ALLOW_APPLE_INTERNAL        0x10
+#   CSR_ALLOW_UNRESTRICTED_DTRACE   0x20
+#   CSR_ALLOW_UNRESTRICTED_NVRAM    0x40
+#
+#csr_values 10,77
+
+# Include a secondary configuration file within this one. This secondary
+# file is loaded as if its options appeared at the point of the "include"
+# token itself, so if you want to override a setting in the main file,
+# the secondary file must be referenced AFTER the setting you want to
+# override. Note that the secondary file may NOT load a tertiary file.
+#
+#include manual.conf
+
+# Sample manual configuration stanzas. Each begins with the "menuentry"
+# keyword followed by a name that's to appear in the menu (use quotes
+# if you want the name to contain a space) and an open curly brace
+# ("{"). Each entry ends with a close curly brace ("}"). Common
+# keywords within each stanza include:
+#
+#  volume    - identifies the filesystem from which subsequent files
+#              are loaded. You can specify the volume by filesystem
+#              label, by partition label, or by partition GUID number
+#              (but NOT yet by filesystem UUID number).
+#  loader    - identifies the boot loader file
+#  initrd    - Specifies an initial RAM disk file
+#  icon      - specifies a custom boot loader icon
+#  ostype    - OS type code to determine boot options available by
+#              pressing Insert. Valid values are "MacOS", "Linux",
+#              "Windows", and "XOM". Case-sensitive.
+#  graphics  - set to "on" to enable graphics-mode boot (useful
+#              mainly for MacOS) or "off" for text-mode boot.
+#              Default is auto-detected from loader filename.
+#  options   - sets options to be passed to the boot loader; use
+#              quotes if more than one option should be passed or
+#              if any options use characters that might be changed
+#              by rEFInd parsing procedures (=, /, #, or tab).
+#  disabled  - use alone or set to "yes" to disable this entry.
+#
+# Note that you can use either DOS/Windows/EFI-style backslashes (\)
+# or Unix-style forward slashes (/) as directory separators. Either
+# way, all file references are on the ESP from which rEFInd was
+# launched.
+# Use of quotes around parameters causes them to be interpreted as
+# one keyword, and for parsing of special characters (spaces, =, /,
+# and #) to be disabled. This is useful mainly with the "options"
+# keyword. Use of quotes around parameters that specify filenames is
+# permissible, but you must then use backslashes instead of slashes,
+# except when you must pass a forward slash to the loader, as when
+# passing a root= option to a Linux kernel.
+
+# Below are several sample boot stanzas. All are disabled by default.
+# Find one similar to what you need, copy it, remove the "disabled" line,
+# and adjust the entries to suit your needs.
+
+# A sample entry for a Linux 3.13 kernel with EFI boot stub support
+# on a partition with a GUID of 904404F8-B481-440C-A1E3-11A5A954E601.
+# This entry includes Linux-specific boot options and specification
+# of an initial RAM disk. Note uses of Linux-style forward slashes.
+# Also note that a leading slash is optional in file specifications.
+menuentry Linux {
+    icon EFI/refind/icons/os_linux.png
+    volume 904404F8-B481-440C-A1E3-11A5A954E601
+    loader bzImage-3.3.0-rc7
+    initrd initrd-3.3.0.img
+    options "ro root=UUID=5f96cafa-e0a7-4057-b18f-fa709db5b837"
+    disabled
+}
+
+# A sample entry for loading Ubuntu using its standard name for
+# its GRUB 2 boot loader. Note uses of Linux-style forward slashes
+menuentry Ubuntu {
+    loader /EFI/ubuntu/grubx64.efi
+    icon /EFI/refind/icons/os_linux.png
+    disabled
+}
+
+# A minimal ELILO entry, which probably offers nothing that
+# auto-detection can't accomplish.
+menuentry "ELILO" {
+    loader \EFI\elilo\elilo.efi
+    disabled
+}
+
+# Like the ELILO entry, this one offers nothing that auto-detection
+# can't do; but you might use it if you want to disable auto-detection
+# but still boot Windows....
+menuentry "Windows 7" {
+    loader \EFI\Microsoft\Boot\bootmgfw.efi
+    disabled
+}
+
+# EFI shells are programs just like boot loaders, and can be
+# launched in the same way. You can pass a shell the name of a
+# script that it's to run on the "options" line. The script
+# could initialize hardware and then launch an OS, or it could
+# do something entirely different.
+menuentry "Windows via shell script" {
+    icon \EFI\refind\icons\os_win.png
+    loader \EFI\tools\shell.efi
+    options "fs0:\EFI\tools\launch_windows.nsh"
+    disabled
+}
+
+# Mac OS is normally detected and run automatically; however,
+# if you want to do something unusual, a manual boot stanza may
+# be the way to do it. This one does nothing very unusual, but
+# it may serve as a starting point. Note that you'll almost
+# certainly need to change the "volume" line for this example
+# to work.
+menuentry "My Mac OS X" {
+    icon \EFI\refind\icons\os_mac.png
+    volume "OS X boot"
+    loader \System\Library\CoreServices\boot.efi
+    disabled
+}
diff --git a/refind.inf b/refind.inf
new file mode 100644 (file)
index 0000000..3f6096f
--- /dev/null
@@ -0,0 +1,165 @@
+## @file\r
+#\r
+# refind.inf file to build rEFInd using the EDK2/UDK2010/UDK2014 development\r
+# kit.\r
+#\r
+# Copyright (c) 2012-2014 by Roderick W. Smith\r
+# Released under the terms of the GPLv3, a copy of which should come\r
+# with this file.\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                   = 0x00010005\r
+  BASE_NAME                     = REFIND\r
+  FILE_GUID                     = B8448DD1-B146-41B7-9D66-98B3A0A404D3\r
+  MODULE_TYPE                   = UEFI_APPLICATION\r
+  EDK_RELEASE_VERSION                  = 0x00020000\r
+  EFI_SPECIFICATION_VERSION            = 0x00010000\r
+  VERSION_STRING                = 1.0\r
+  ENTRY_POINT                   = efi_main\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources]\r
+  EfiLib/GenericBdsLib.h\r
+  EfiLib/BmLib.c\r
+  EfiLib/DevicePath.c #included into GenericBdsLib\r
+  EfiLib/BdsConnect.c #included into GenericBdsLib\r
+  EfiLib/BdsHelper.c\r
+  EfiLib/BdsTianoCore.c\r
+  EfiLib/legacy.c\r
+  mok/mok.c\r
+  mok/guid.c\r
+  mok/security_policy.c\r
+  mok/simple_file.c\r
+  refind/apple.c\r
+  refind/main.c\r
+  refind/config.c\r
+  refind/icns.c\r
+  refind/legacy.c\r
+  refind/lib.c\r
+  refind/line_edit.c\r
+  refind/menu.c\r
+  refind/mystrings.c\r
+  refind/screen.c\r
+  refind/driver_support.c\r
+  refind/gpt.c\r
+  refind/crc32.c\r
+  libeg/image.c\r
+  libeg/load_bmp.c\r
+  libeg/load_icns.c\r
+  libeg/lodepng.c\r
+  libeg/lodepng_xtra.c\r
+  libeg/screen.c\r
+  libeg/text.c\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+  IntelFrameworkPkg/IntelFrameworkPkg.dec\r
+  IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec\r
+\r
+[LibraryClasses]\r
+  UefiApplicationEntryPoint\r
+  UefiBootServicesTableLib\r
+  UefiLib\r
+   MemoryAllocationLib\r
+   BaseMemoryLib\r
+   BaseLib\r
+  DevicePathLib\r
+  DebugLib\r
+  DxeServicesLib\r
+  DxeServicesTableLib\r
+  HobLib\r
+  MemoryAllocationLib\r
+  IoLib\r
+  PerformanceLib\r
+\r
+[Guids]\r
+  gEfiAcpiTableGuid\r
+  gEfiAcpi10TableGuid\r
+  gEfiAcpi20TableGuid\r
+  gEfiDxeServicesTableGuid\r
+  gEfiEventReadyToBootGuid\r
+  gEfiEventVirtualAddressChangeGuid\r
+  gEfiEventExitBootServicesGuid\r
+  gEfiFileInfoGuid                              ## CONSUMES ## GUID\r
+  gEfiFileSystemInfoGuid                        ## CONSUMES ## GUID\r
+  gEfiFileSystemVolumeLabelInfoIdGuid\r
+  gEfiGlobalVariableGuid\r
+  gEfiPartTypeLegacyMbrGuid\r
+  gEfiPartTypeSystemPartGuid\r
+  gEfiSmbiosTableGuid\r
+  gEfiSasDevicePathGuid\r
+  \r
+       \r
+\r
+[Ppis]\r
+\r
+[Protocols]\r
+  gEfiComponentName2ProtocolGuid                          # ALWAYS_CONSUMED\r
+  gEfiDevicePathToTextProtocolGuid                        # ALWAYS_CONSUMED\r
+  gEfiSimpleFileSystemProtocolGuid                        # ALWAYS_CONSUMED\r
+  gEfiSimpleTextInProtocolGuid                            # ALWAYS_CONSUMED\r
+  gEfiSimpleTextInputExProtocolGuid                       # ALWAYS_CONSUMED\r
+  gEfiSimpleTextOutProtocolGuid                           # ALWAYS_CONSUMED\r
+  gEfiUnicodeCollationProtocolGuid                       # ALWAYS_CONSUMED  \r
+  gEfiUnicodeCollation2ProtocolGuid                       # ALWAYS_CONSUMED  \r
+  \r
+  gEfiAcpiS3SaveProtocolGuid                    # PROTOCOL CONSUMES\r
+  gEfiBlockIoProtocolGuid                       # PROTOCOL CONSUMES\r
+  gEfiCpuArchProtocolGuid                       # PROTOCOL CONSUMES\r
+  gEfiDebugPortProtocolGuid                     # PROTOCOL CONSUMES\r
+  gEfiDevicePathProtocolGuid                    # PROTOCOL CONSUMES\r
+  gEfiDiskIoProtocolGuid                        # PROTOCOL CONSUMES\r
+  gEfiExtScsiPassThruProtocolGuid               ## PROTOCOL SOMETIMES_CONSUMES\r
+  gEfiFirmwareVolume2ProtocolGuid               # PROTOCOL CONSUMES\r
+  gEfiGraphicsOutputProtocolGuid                # PROTOCOL SOMETIMES_CONSUMES\r
+  gEfiHiiFontProtocolGuid                       # PROTOCOL CONSUMES\r
+  gEfiLegacy8259ProtocolGuid                                   ## PROTOCOL SOMETIMES_CONSUMES\r
+  gEfiLoadedImageProtocolGuid                   # PROTOCOL CONSUMES\r
+  gEfiOEMBadgingProtocolGuid                    # PROTOCOL CONSUMES\r
+  gEfiPciIoProtocolGuid                         # PROTOCOL CONSUMES \r
+  gEfiScsiIoProtocolGuid                        ## PROTOCOL SOMETIMES_CONSUMES\r
+  gEfiScsiPassThruProtocolGuid                  ## PROTOCOL SOMETIMES_CONSUMES\r
+  gEfiSimpleNetworkProtocolGuid                 # PROTOCOL CONSUMES\r
+  gEfiUgaDrawProtocolGuid |PcdUgaConsumeSupport # PROTOCOL SOMETIMES_CONSUMES\r
+  \r
+  gEfiAbsolutePointerProtocolGuid\r
+  gEfiAcpiTableProtocolGuid\r
+  gEfiEdidActiveProtocolGuid\r
+  gEfiEdidDiscoveredProtocolGuid\r
+  gEfiHiiDatabaseProtocolGuid\r
+  gEfiHiiImageProtocolGuid\r
+  gEfiHiiProtocolGuid\r
+  gEfiSimplePointerProtocolGuid\r
+  gEfiSmbiosProtocolGuid\r
+  gEfiSecurityArchProtocolGuid  \r
+  gEfiScsiIoProtocolGuid                        ## PROTOCOL SOMETIMES_CONSUMES\r
+  gEfiScsiPassThruProtocolGuid                  ## PROTOCOL SOMETIMES_CONSUMES\r
+  gEfiExtScsiPassThruProtocolGuid               ## PROTOCOL SOMETIMES_CONSUMES\r
+\r
+  gEfiLegacyBiosProtocolGuid                    # PROTOCOL TO_START\r
+\r
+  gEfiLoadFile2ProtocolGuid\r
+  gEfiLoadFileProtocolGuid\r
+  gEfiHiiPackageListProtocolGuid\r
+\r
+[FeaturePcd]\r
+  gEfiMdePkgTokenSpaceGuid.PcdUgaConsumeSupport\r
+\r
+[Pcd]\r
+\r
+\r
+[BuildOptions.IA32]\r
+  XCODE:*_*_*_CC_FLAGS = -Os \r
+  GCC:*_*_*_CC_FLAGS = -Os -DEFI32 -D__MAKEWITH_TIANO\r
+\r
+[BuildOptions.X64]\r
+  XCODE:*_*_*_CC_FLAGS = -Os \r
+  GCC:*_*_*_CC_FLAGS = -Os -DEFIX64 -D__MAKEWITH_TIANO\r
diff --git a/refind.spec b/refind.spec
new file mode 100644 (file)
index 0000000..12acf19
--- /dev/null
@@ -0,0 +1,210 @@
+Summary: EFI boot manager software
+Name: refind
+Version: 0.10.0
+Release: 1%{?dist}
+Summary: EFI boot manager software
+License: GPLv3
+URL: http://www.rodsbooks.com/refind/
+Group: System Environment/Base
+Source: refind-src-%version.tar.gz
+Requires: efibootmgr
+BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)
+
+%define efiarch unknown
+%ifarch i386
+%define efiarch ia32
+%endif
+%ifarch i486
+%define efiarch ia32
+%endif
+%ifarch i586
+%define efiarch ia32
+%endif
+%ifarch i686
+%define efiarch ia32
+%endif
+%ifarch x86_64
+%define efiarch x64
+%endif
+
+# Directory in which refind.key and refind.crt files are found for
+# signing of binaries. If absent, binaries are copied unsigned.
+%define keydir /mnt/refind
+
+%description
+
+A graphical boot manager for EFI- and UEFI-based computers, such as all
+Intel-based Macs and recent (most 2011 and later) PCs. rEFInd presents a
+boot menu showing all the EFI boot loaders on the EFI-accessible
+partitions, and optionally BIOS-bootable partitions on Macs and BIOS boot
+entries on UEFI PCs with CSMs. EFI-compatbile OSes, including Linux,
+provide boot loaders that rEFInd can detect and launch. rEFInd can launch
+Linux EFI boot loaders such as ELILO, GRUB Legacy, GRUB 2, and 3.3.0 and
+later kernels with EFI stub support. EFI filesystem drivers for ext2/3/4fs,
+ReiserFS, Btrfs, NTFS, HFS+, and ISO-9660 enable rEFInd to read boot
+loaders from these filesystems, too. rEFInd's ability to detect boot
+loaders at runtime makes it very easy to use, particularly when paired with
+Linux kernels that provide EFI stub support.
+
+%prep
+%setup -q
+
+%build
+if [[ -d /usr/local/UDK2014 ]] ; then
+   make
+   make fs
+else
+   make gnuefi
+   make fs_gnuefi
+fi
+
+%install
+rm -rf $RPM_BUILD_ROOT
+mkdir -p $RPM_BUILD_ROOT/usr/share/refind-%{version}/refind/
+
+# Copy the rEFInd binaries (rEFInd proper and drivers) to /usr/share/refind-%{version},
+# including signing the binaries if sbsign is installed and a %{keydir}/refind.key file
+# is available
+declare SBSign=`which sbsign 2> /dev/null`
+if [[ -f %{keydir}/refind.key && -x $SBSign ]] ; then
+   $SBSign --key %{keydir}/refind.key --cert %{keydir}/refind.crt --output $RPM_BUILD_ROOT/usr/share/refind-%{version}/refind/refind_%{efiarch}.efi refind/refind_%{efiarch}.efi
+   mkdir -p $RPM_BUILD_ROOT/usr/share/refind-%{version}/refind/drivers_%{efiarch}
+   for File in `ls drivers_%{efiarch}/*_x64.efi` ; do
+      $SBSign --key %{keydir}/refind.key --cert %{keydir}/refind.crt --output $RPM_BUILD_ROOT/usr/share/refind-%{version}/refind/$File $File
+   done
+   mkdir -p $RPM_BUILD_ROOT/usr/share/refind-%{version}/refind/tools_%{efiarch}
+   $SBSign --key %{keydir}/refind.key --cert %{keydir}/refind.crt --output $RPM_BUILD_ROOT/usr/share/refind-%{version}/refind/tools_%{efiarch}/gptsync_%{efiarch}.efi gptsync/gptsync_%{efiarch}.efi
+else
+   install -Dp -m0644 refind/refind*.efi $RPM_BUILD_ROOT/usr/share/refind-%{version}/refind/
+   mkdir -p $RPM_BUILD_ROOT/usr/share/refind-%{version}/refind/drivers_%{efiarch}
+   cp -a drivers_%{efiarch}/* $RPM_BUILD_ROOT/usr/share/refind-%{version}/refind/drivers_%{efiarch}/
+   mkdir -p $RPM_BUILD_ROOT/usr/share/refind-%{version}/refind/tools_%{efiarch}
+   install -Dp -m0644 gptsync/gptsync_%{efiarch}.efi $RPM_BUILD_ROOT/usr/share/refind-%{version}/refind/tools_%{efiarch}/gptsync_%{efiarch}.efi
+fi
+
+# Copy configuration and support files to /usr/share/refind-%{version}
+install -Dp -m0644 refind.conf-sample $RPM_BUILD_ROOT/usr/share/refind-%{version}/refind/
+cp -a icons $RPM_BUILD_ROOT/usr/share/refind-%{version}/refind/
+rm -rf $RPM_BUILD_ROOT/usr/share/refind-%{version}/refind/icons/svg
+install -Dp -m0755 refind-install $RPM_BUILD_ROOT/usr/share/refind-%{version}/
+
+# Copy documentation to /usr/share/doc/refind-%{version}
+mkdir -p $RPM_BUILD_ROOT/usr/share/doc/refind-%{version}
+cp -a docs/Styles $RPM_BUILD_ROOT/usr/share/doc/refind-%{version}/
+cp -a docs/refind $RPM_BUILD_ROOT/usr/share/doc/refind-%{version}/
+install -Dp -m0644 NEWS.txt COPYING.txt LICENSE.txt README.txt CREDITS.txt $RPM_BUILD_ROOT/usr/share/doc/refind-%{version}
+
+# Copy man pages to /usr/share/man/man8
+mkdir -p $RPM_BUILD_ROOT/usr/share/man/man8
+install -Dp -m0644 docs/man/mvrefind.8 $RPM_BUILD_ROOT/usr/share/man/man8
+install -Dp -m0644 docs/man/mkrlconf.8 $RPM_BUILD_ROOT/usr/share/man/man8
+install -Dp -m0644 docs/man/refind-install.8 $RPM_BUILD_ROOT/usr/share/man/man8
+
+# Copy keys to /etc/refind.d/keys
+mkdir -p $RPM_BUILD_ROOT/etc/refind.d/keys
+install -Dp -m0644 keys/* $RPM_BUILD_ROOT/etc/refind.d/keys
+
+# Copy scripts to /usr/sbin
+mkdir -p $RPM_BUILD_ROOT/usr/sbin
+install -Dp -m0755 mkrlconf $RPM_BUILD_ROOT/usr/sbin/
+install -Dp -m0755 mvrefind $RPM_BUILD_ROOT/usr/sbin/
+ln -sr $RPM_BUILD_ROOT/usr/share/refind-%{version}/refind-install $RPM_BUILD_ROOT/usr/sbin
+
+# Copy banners and fonts to /usr/share/refind-%{version}
+cp -a banners $RPM_BUILD_ROOT/usr/share/refind-%{version}/
+cp -a fonts $RPM_BUILD_ROOT/usr/share/refind-%{version}/
+
+%clean
+#rm -rf $RPM_BUILD_ROOT
+
+%files
+%defattr(-,root,root -)
+%doc /usr/share/doc/refind-%{version}
+%doc /usr/share/man/man8
+/usr/sbin/mkrlconf
+/usr/sbin/mvrefind
+/usr/sbin/refind-install
+/usr/share/refind-%{version}
+/etc/refind.d/
+
+%post
+PATH=$PATH:/usr/local/bin
+# Remove any existing NVRAM entry for rEFInd, to avoid creating a duplicate.
+ExistingEntry=`efibootmgr | grep "rEFInd Boot Manager" | cut -c 5-8`
+if [[ -n $ExistingEntry ]] ; then
+   efibootmgr --bootnum $ExistingEntry --delete-bootnum &> /dev/null
+fi
+
+cd /usr/share/refind-%{version}
+
+if [[ -f /sys/firmware/efi/vars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c/data ]] ; then
+   IsSecureBoot=`od -An -t u1 /sys/firmware/efi/vars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c/data | tr -d '[[:space:]]'`
+else
+   IsSecureBoot="0"
+fi
+# Note: Two find operations for ShimFile favors shim over PreLoader -- if both are
+# present, the script uses shim rather than PreLoader.
+declare ShimFile=`find /boot -name shim\.efi -o -name shimx64\.efi -o -name PreLoader\.efi 2> /dev/null | head -n 1`
+if [[ ! -n $ShimFile ]] ; then
+   declare ShimFile=`find /boot -name PreLoader\.efi 2> /dev/null | head -n 1`
+fi
+declare SBSign=`which sbsign 2> /dev/null`
+declare OpenSSL=`which openssl 2> /dev/null`
+
+# Run the rEFInd installation script. Do so with the --shim option
+# if Secure Boot mode is suspected and if a shim program can be
+# found, or without it if not. If the sbsign and openssl programs
+# can be found, do the install using a local signing key. Note that
+# this option is undesirable for a distribution, since it would
+# then require the user to enroll an extra MOK. I'm including it
+# here because I'm NOT a distribution maintainer, and I want to
+# encourage users to use their own local keys.
+if [[ $IsSecureBoot == "1" && -n $ShimFile ]] ; then
+   if [[ -n $SBSign && -n $OpenSSL ]] ; then
+      ./refind-install --shim $ShimFile --localkeys --yes
+   else
+      ./refind-install --shim $ShimFile --yes
+   fi
+else
+   if [[ -n $SBSign && -n $OpenSSL ]] ; then
+      ./refind-install --localkeys --yes
+   else
+      ./refind-install --yes
+   fi
+fi
+
+# CAUTION: Don't create a %preun or a %postun script that deletes the files
+# installed by refind-install, since that script will run after an update,
+# thus wiping out the just-updated files.
+
+%changelog
+* Sun Nov 8 2015 R Smith <rodsmith@rodsbooks.com> - 0.10.0
+- Updated spec file for 0.10.0
+* Sat Sep 19 2015 R Smith <rodsmith@rodsbooks.com> - 0.9.2
+- Updated spec file for 0.9.2
+* Sun Sep 13 2015 R Smith <rodsmith@rodsbooks.com> - 0.9.1
+- Updated spec file for 0.9.1
+* Sun Jul 26 2015 R Smith <rodsmith@rodsbooks.com> - 0.9.0
+- Updated spec file for 0.9.0
+* Sun Mar 1 2015 R Smith <rodsmith@rodsbooks.com> - 0.8.7
+- Updated spec file for 0.8.7
+* Sun Feb 8 2015 R Smith <rodsmith@rodsbooks.com> - 0.8.6
+- Updated spec file for 0.8.6
+* Sun Feb 1 2015 R Smith <rodsmith@rodsbooks.com> - 0.8.5
+- Updated spec file for 0.8.5
+* Mon Dec 8 2014 R Smith <rodsmith@rodsbooks.com> - 0.8.4
+- Updated spec file for 0.8.4
+* Sun Jul 6 2014 R Smith <rodsmith@rodsbooks.com> - 0.8.3
+- Updated spec file for 0.8.3
+* Sun Jun 8 2014 R Smith <rodsmith@rodsbooks.com> - 0.8.2
+- Updated spec file for 0.8.2
+* Thu May 15 2014 R Smith <rodsmith@rodsbooks.com> - 0.8.1
+- Updated spec file for 0.8.1
+* Sun May 4 2014 R Smith <rodsmith@rodsbooks.com> - 0.8.0
+- Updated spec file for 0.8.0
+* Sun Apr 20 2014 R Smith <rodsmith@rodsbooks.com> - 0.7.9
+- Updated spec file for 0.7.9
+* Sun Mar 9 2014 R Smith <rodsmith@rodsbooks.com> - 0.7.8
+- Updated spec file for 0.7.8
+* Fri Jan 3 2014 R Smith <rodsmith@rodsbooks.com> - 0.7.7
+- Created spec file for 0.7.7 release
diff --git a/refind/AutoGen.c b/refind/AutoGen.c
new file mode 100644 (file)
index 0000000..22f7f3a
--- /dev/null
@@ -0,0 +1,293 @@
+/**
+  DO NOT EDIT
+  FILE auto-generated
+  Module name:
+    AutoGen.c
+  Abstract:       Auto-generated AutoGen.c for building module or library.
+**/
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiApplicationEntryPoint.h>
+#include "AutoGen.h"
+
+GLOBAL_REMOVE_IF_UNREFERENCED GUID gEfiCallerIdGuid = {0xB8448DD1, 0xB146, 0x41B7, {0x9D, 0x66, 0x98, 0xB3, 0xA0, 0xA4, 0x04, 0xD3}};
+
+// Guids
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiAcpiTableGuid = { 0x8868E871, 0xE4F1, 0x11D3, { 0xBC, 0x22, 0x00, 0x80, 0xC7, 0x3C, 0x88, 0x81 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiAcpi10TableGuid = { 0xEB9D2D30, 0x2D88, 0x11D3, { 0x9A, 0x16, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiAcpi20TableGuid = { 0x8868E871, 0xE4F1, 0x11D3, { 0xBC, 0x22, 0x00, 0x80, 0xC7, 0x3C, 0x88, 0x81 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDxeServicesTableGuid = { 0x05AD34BA, 0x6F02, 0x4214, { 0x95, 0x2E, 0x4D, 0xA0, 0x39, 0x8E, 0x2B, 0xB9 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiEventReadyToBootGuid = { 0x7CE88FB3, 0x4BD7, 0x4679, { 0x87, 0xA8, 0xA8, 0xD8, 0xDE, 0xE5, 0x0D, 0x2B }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiEventVirtualAddressChangeGuid = { 0x13FA7698, 0xC831, 0x49C7, { 0x87, 0xEA, 0x8F, 0x43, 0xFC, 0xC2, 0x51, 0x96 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiEventExitBootServicesGuid = { 0x27ABF055, 0xB1B8, 0x4C26, { 0x80, 0x48, 0x74, 0x8F, 0x37, 0xBA, 0xA2, 0xDF }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiFileInfoGuid = { 0x09576E92, 0x6D3F, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiFileSystemInfoGuid = { 0x09576E93, 0x6D3F, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiFileSystemVolumeLabelInfoIdGuid = { 0xDB47D7D3, 0xFE81, 0x11D3, { 0x9A, 0x35, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiGlobalVariableGuid = { 0x8BE4DF61, 0x93CA, 0x11D2, { 0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiPartTypeLegacyMbrGuid = { 0x024DEE41, 0x33E7, 0x11D3, { 0x9D, 0x69, 0x00, 0x08, 0xC7, 0x81, 0xF3, 0x9F }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiPartTypeSystemPartGuid = { 0xC12A7328, 0xF81F, 0x11D2, { 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSmbiosTableGuid = { 0xEB9D2D31, 0x2D88, 0x11D3, { 0x9A, 0x16, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSasDevicePathGuid = { 0xd487ddb4, 0x008b, 0x11d9, { 0xaf, 0xdc, 0x00, 0x10, 0x83, 0xff, 0xca, 0x4d }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiMdePkgTokenSpaceGuid = { 0x914AEBE7, 0x4635, 0x459b, { 0xAA, 0x1C, 0x11, 0xE2, 0x19, 0xB0, 0x3A, 0x10 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiEventLegacyBootGuid = { 0x2A571201, 0x4966, 0x47F6, { 0x8B, 0x86, 0xF3, 0x1E, 0x41, 0xF3, 0x2F, 0x10 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiHobListGuid = { 0x7739F24C, 0x93D7, 0x11D4, { 0x9A, 0x3A, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }};
+
+// Protocols
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiComponentName2ProtocolGuid = { 0x6A7A5CFF, 0xE8D9, 0x4F70, { 0xBA, 0xDA, 0x75, 0xAB, 0x30, 0x25, 0xCE, 0x14 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDevicePathToTextProtocolGuid = { 0x8B843E20, 0x8132, 0x4852, { 0x90, 0xCC, 0x55, 0x1A, 0x4E, 0x4A, 0x7F, 0x1C }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSimpleFileSystemProtocolGuid = { 0x964E5B22, 0x6459, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSimpleTextInProtocolGuid = { 0x387477C1, 0x69C7, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSimpleTextInputExProtocolGuid = {0xdd9e7534, 0x7762, 0x4698, { 0x8c, 0x14, 0xf5, 0x85, 0x17, 0xa6, 0x25, 0xaa } };
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSimpleTextOutProtocolGuid = { 0x387477C2, 0x69C7, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiUnicodeCollationProtocolGuid = { 0x1D85CD7F, 0xF43D, 0x11D2, { 0x9A, 0x0C, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiUnicodeCollation2ProtocolGuid = {0xa4c751fc, 0x23ae, 0x4c3e, { 0x92, 0xe9, 0x49, 0x64, 0xcf, 0x63, 0xf3, 0x49 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiAcpiS3SaveProtocolGuid = { 0x125F2DE1, 0xFB85, 0x440C, { 0xA5, 0x4C, 0x4D, 0x99, 0x35, 0x8A, 0x8D, 0x38 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiBlockIoProtocolGuid = { 0x964E5B21, 0x6459, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiCpuArchProtocolGuid = { 0x26BACCB1, 0x6F42, 0x11D4, { 0xBC, 0xE7, 0x00, 0x80, 0xC7, 0x3C, 0x88, 0x81 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDebugPortProtocolGuid = { 0xEBA4E8D2, 0x3858, 0x41EC, { 0xA2, 0x81, 0x26, 0x47, 0xBA, 0x96, 0x60, 0xD0 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDevicePathProtocolGuid = { 0x09576E91, 0x6D3F, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDiskIoProtocolGuid = { 0xCE345171, 0xBA0B, 0x11D2, { 0x8E, 0x4F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiExtScsiPassThruProtocolGuid = { 0x143b7632, 0xb81b, 0x4cb7, {0xab, 0xd3, 0xb6, 0x25, 0xa5, 0xb9, 0xbf, 0xfe }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiFirmwareVolume2ProtocolGuid = { 0x220e73b6, 0x6bdb, 0x4413, { 0x84, 0x5, 0xb9, 0x74, 0xb1, 0x8, 0x61, 0x9a } };
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiGraphicsOutputProtocolGuid = { 0x9042A9DE, 0x23DC, 0x4A38, { 0x96, 0xFB, 0x7A, 0xDE, 0xD0, 0x80, 0x51, 0x6A }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiHiiFontProtocolGuid = {0xe9ca4775, 0x8657, 0x47fc, {0x97, 0xe7, 0x7e, 0xd6, 0x5a, 0x08, 0x43, 0x24}};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiLegacy8259ProtocolGuid = { 0x38321dba, 0x4fe0, 0x4e17, { 0x8a, 0xec, 0x41, 0x30, 0x55, 0xea, 0xed, 0xc1 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiLoadedImageProtocolGuid = { 0x5B1B31A1, 0x9562, 0x11D2, { 0x8E, 0x3F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiOEMBadgingProtocolGuid = { 0x170E13C0, 0xBF1B, 0x4218, { 0x87, 0x1D, 0x2A, 0xBD, 0xC6, 0xF8, 0x87, 0xBC }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiPciIoProtocolGuid = { 0x4CF5B200, 0x68B8, 0x4CA5, { 0x9E, 0xEC, 0xB2, 0x3E, 0x3F, 0x50, 0x02, 0x9A }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiScsiIoProtocolGuid = { 0x932F47e6, 0x2362, 0x4002, { 0x80, 0x3E, 0x3C, 0xD5, 0x4B, 0x13, 0x8F, 0x85 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiScsiPassThruProtocolGuid = { 0xA59E8FCF, 0xBDA0, 0x43BB, { 0x90, 0xB1, 0xD3, 0x73, 0x2E, 0xCA, 0xA8, 0x77 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSimpleNetworkProtocolGuid = { 0xA19832B9, 0xAC25, 0x11D3, { 0x9A, 0x2D, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }};
+//GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiUgaDrawProtocolGuid = { 0x982C298B, 0xF4FA, 0x41CB, { 0xB8, 0x38, 0x77, 0xAA, 0x68, 0x8F, 0xB8, 0x39 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiAbsolutePointerProtocolGuid = { 0x8D59D32B, 0xC655, 0x4AE9, { 0x9B, 0x15, 0xF2, 0x59, 0x04, 0x99, 0x2A, 0x43 } };
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiAcpiTableProtocolGuid = { 0xFFE06BDD, 0x6107, 0x46A6, { 0x7B, 0xB2, 0x5A, 0x9C, 0x7E, 0xC5, 0x27, 0x5C }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiEdidActiveProtocolGuid = { 0xBD8C1056, 0x9F36, 0x44EC, { 0x92, 0xA8, 0xA6, 0x33, 0x7F, 0x81, 0x79, 0x86 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiEdidDiscoveredProtocolGuid = { 0x1C0C34F6, 0xD380, 0x41FA, { 0xA0, 0x49, 0x8A, 0xD0, 0x6C, 0x1A, 0x66, 0xAA }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiHiiDatabaseProtocolGuid = {0xef9fc172, 0xa1b2, 0x4693, {0xb3, 0x27, 0x6d, 0x32, 0xfc, 0x41, 0x60, 0x42}};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiHiiImageProtocolGuid = {0x31a6406a, 0x6bdf, 0x4e46, {0xb2, 0xa2, 0xeb, 0xaa, 0x89, 0xc4, 0x09, 0x20}};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiHiiProtocolGuid = { 0xd7ad636e, 0xb997, 0x459b, { 0xbf, 0x3f, 0x88, 0x46, 0x89, 0x79, 0x80, 0xe1 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSimplePointerProtocolGuid = { 0x31878C87, 0x0B75, 0x11D5, { 0x9A, 0x4F, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSmbiosProtocolGuid = {0x3583ff6, 0xcb36, 0x4940, { 0x94, 0x7e, 0xb9, 0xb3, 0x9f, 0x4a, 0xfa, 0xf7}};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSecurityArchProtocolGuid = { 0xA46423E3, 0x4617, 0x49F1, { 0xB9, 0xFF, 0xD1, 0xBF, 0xA9, 0x11, 0x58, 0x39 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiLegacyBiosProtocolGuid = { 0xdb9a1e3d, 0x45cb, 0x4abb, { 0x85, 0x3b, 0xe5, 0x38, 0x7f, 0xdb, 0x2e, 0x2d }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiLoadFile2ProtocolGuid = { 0x4006c0c1, 0xfcb3, 0x403e, {0x99, 0x6d, 0x4a, 0x6c, 0x87, 0x24, 0xe0, 0x6d }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiLoadFileProtocolGuid = { 0x56EC3091, 0x954C, 0x11D2, { 0x8E, 0x3F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiHiiPackageListProtocolGuid = { 0x6a1ee763, 0xd47a, 0x43b4, {0xaa, 0xbe, 0xef, 0x1d, 0xe2, 0xab, 0x56, 0xfc}};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverBindingProtocolGuid = { 0x18A031AB, 0xB443, 0x4D1A, { 0xA5, 0xC0, 0x0C, 0x09, 0x26, 0x1E, 0x9F, 0x71 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiComponentNameProtocolGuid = { 0x107A772C, 0xD5E1, 0x11D4, { 0x9A, 0x46, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverConfigurationProtocolGuid = { 0x107A772B, 0xD5E1, 0x11D4, { 0x9A, 0x46, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverConfiguration2ProtocolGuid = { 0xBFD7DC1D, 0x24F1, 0x40D9, { 0x82, 0xE7, 0x2E, 0x09, 0xBB, 0x6B, 0x4E, 0xBE }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverDiagnosticsProtocolGuid = { 0x0784924F, 0xE296, 0x11D4, { 0x9A, 0x49, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverDiagnostics2ProtocolGuid = { 0x4D330321, 0x025F, 0x4AAC, { 0x90, 0xD8, 0x5E, 0xD9, 0x00, 0x17, 0x3B, 0x63 }};
+
+// Definition of PCDs used in this module
+//GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdUgaConsumeSupport = _PCD_VALUE_PcdUgaConsumeSupport;
+
+// Definition of PCDs used in libraries
+
+#define _PCD_TOKEN_PcdMaximumLinkedListLength  2U
+#define _PCD_VALUE_PcdMaximumLinkedListLength  1000000U
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdMaximumLinkedListLength = _PCD_VALUE_PcdMaximumLinkedListLength;
+extern const  UINT32  _gPcd_FixedAtBuild_PcdMaximumLinkedListLength;
+#define _PCD_GET_MODE_32_PcdMaximumLinkedListLength  _gPcd_FixedAtBuild_PcdMaximumLinkedListLength
+#define _PCD_SET_MODE_32_PcdMaximumLinkedListLength  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdMaximumAsciiStringLength  3U
+#define _PCD_VALUE_PcdMaximumAsciiStringLength  1000000U
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdMaximumAsciiStringLength = _PCD_VALUE_PcdMaximumAsciiStringLength;
+extern const  UINT32  _gPcd_FixedAtBuild_PcdMaximumAsciiStringLength;
+#define _PCD_GET_MODE_32_PcdMaximumAsciiStringLength  _gPcd_FixedAtBuild_PcdMaximumAsciiStringLength
+#define _PCD_SET_MODE_32_PcdMaximumAsciiStringLength  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdMaximumUnicodeStringLength  4U
+#define _PCD_VALUE_PcdMaximumUnicodeStringLength  1000000U
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdMaximumUnicodeStringLength = _PCD_VALUE_PcdMaximumUnicodeStringLength;
+extern const  UINT32  _gPcd_FixedAtBuild_PcdMaximumUnicodeStringLength;
+#define _PCD_GET_MODE_32_PcdMaximumUnicodeStringLength  _gPcd_FixedAtBuild_PcdMaximumUnicodeStringLength
+#define _PCD_SET_MODE_32_PcdMaximumUnicodeStringLength  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdVerifyNodeInList  5U
+#define _PCD_VALUE_PcdVerifyNodeInList  ((BOOLEAN)0U)
+GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdVerifyNodeInList = _PCD_VALUE_PcdVerifyNodeInList;
+extern const  BOOLEAN  _gPcd_FixedAtBuild_PcdVerifyNodeInList;
+#define _PCD_GET_MODE_BOOL_PcdVerifyNodeInList  _gPcd_FixedAtBuild_PcdVerifyNodeInList
+#define _PCD_SET_MODE_BOOL_PcdVerifyNodeInList  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdMaximumDevicePathNodeCount  6U
+#define _PCD_VALUE_PcdMaximumDevicePathNodeCount  0U
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdMaximumDevicePathNodeCount = _PCD_VALUE_PcdMaximumDevicePathNodeCount;
+extern const  UINT32  _gPcd_FixedAtBuild_PcdMaximumDevicePathNodeCount;
+#define _PCD_GET_MODE_32_PcdMaximumDevicePathNodeCount  _gPcd_FixedAtBuild_PcdMaximumDevicePathNodeCount
+//#define _PCD_SET_MODE_32_PcdMaximumDevicePathNodeCount  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdDriverDiagnosticsDisable  6U
+#define _PCD_VALUE_PcdDriverDiagnosticsDisable  ((BOOLEAN)0U)
+GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdDriverDiagnosticsDisable = _PCD_VALUE_PcdDriverDiagnosticsDisable;
+extern const  BOOLEAN  _gPcd_FixedAtBuild_PcdDriverDiagnosticsDisable;
+#define _PCD_GET_MODE_BOOL_PcdDriverDiagnosticsDisable  _gPcd_FixedAtBuild_PcdDriverDiagnosticsDisable
+#define _PCD_SET_MODE_BOOL_PcdDriverDiagnosticsDisable  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdComponentNameDisable  7U
+#define _PCD_VALUE_PcdComponentNameDisable  ((BOOLEAN)0U)
+GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdComponentNameDisable = _PCD_VALUE_PcdComponentNameDisable;
+extern const  BOOLEAN  _gPcd_FixedAtBuild_PcdComponentNameDisable;
+#define _PCD_GET_MODE_BOOL_PcdComponentNameDisable  _gPcd_FixedAtBuild_PcdComponentNameDisable
+#define _PCD_SET_MODE_BOOL_PcdComponentNameDisable  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdDriverDiagnostics2Disable  8U
+#define _PCD_VALUE_PcdDriverDiagnostics2Disable  ((BOOLEAN)0U)
+GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdDriverDiagnostics2Disable = _PCD_VALUE_PcdDriverDiagnostics2Disable;
+extern const  BOOLEAN  _gPcd_FixedAtBuild_PcdDriverDiagnostics2Disable;
+#define _PCD_GET_MODE_BOOL_PcdDriverDiagnostics2Disable  _gPcd_FixedAtBuild_PcdDriverDiagnostics2Disable
+#define _PCD_SET_MODE_BOOL_PcdDriverDiagnostics2Disable  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdComponentName2Disable  9U
+#define _PCD_VALUE_PcdComponentName2Disable  ((BOOLEAN)0U)
+GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdComponentName2Disable = _PCD_VALUE_PcdComponentName2Disable;
+extern const  BOOLEAN  _gPcd_FixedAtBuild_PcdComponentName2Disable;
+#define _PCD_GET_MODE_BOOL_PcdComponentName2Disable  _gPcd_FixedAtBuild_PcdComponentName2Disable
+#define _PCD_SET_MODE_BOOL_PcdComponentName2Disable  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdUefiLibMaxPrintBufferSize  10U
+#define _PCD_VALUE_PcdUefiLibMaxPrintBufferSize  320U
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdUefiLibMaxPrintBufferSize = _PCD_VALUE_PcdUefiLibMaxPrintBufferSize;
+extern const  UINT32  _gPcd_FixedAtBuild_PcdUefiLibMaxPrintBufferSize;
+#define _PCD_GET_MODE_32_PcdUefiLibMaxPrintBufferSize  _gPcd_FixedAtBuild_PcdUefiLibMaxPrintBufferSize
+#define _PCD_SET_MODE_32_PcdUefiLibMaxPrintBufferSize  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+EFI_STATUS
+EFIAPI
+UefiBootServicesTableLibConstructor (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  );
+
+EFI_STATUS
+EFIAPI
+UefiRuntimeServicesTableLibConstructor (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  );
+
+EFI_STATUS
+EFIAPI
+UefiLibConstructor (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  );
+
+EFI_STATUS
+EFIAPI
+DxeServicesTableLibConstructor (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  );
+
+EFI_STATUS
+EFIAPI
+HobLibConstructor (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  );
+
+
+// VOID
+// EFIAPI
+// ProcessLibraryConstructorList (
+//   IN EFI_HANDLE        ImageHandle,
+//   IN EFI_SYSTEM_TABLE  *SystemTable
+//   )
+// {
+//   EFI_STATUS  Status;
+// 
+//   Status = UefiBootServicesTableLibConstructor (ImageHandle, SystemTable);
+//   ASSERT_EFI_ERROR (Status);
+// 
+//   Status = UefiRuntimeServicesTableLibConstructor (ImageHandle, SystemTable);
+//   ASSERT_EFI_ERROR (Status);
+// 
+//   Status = UefiLibConstructor (ImageHandle, SystemTable);
+//   ASSERT_EFI_ERROR (Status);
+// 
+//   Status = DxeServicesTableLibConstructor (ImageHandle, SystemTable);
+//   ASSERT_EFI_ERROR (Status);
+// 
+//   Status = HobLibConstructor (ImageHandle, SystemTable);
+//   ASSERT_EFI_ERROR (Status);
+// 
+// }
+
+
+
+// VOID
+// EFIAPI
+// ProcessLibraryDestructorList (
+//   IN EFI_HANDLE        ImageHandle,
+//   IN EFI_SYSTEM_TABLE  *SystemTable
+//   )
+// {
+//
+// }
+
+const UINT32 _gUefiDriverRevision = 0x00010000U;
+
+
+// EFI_STATUS
+// EFIAPI
+// ProcessModuleEntryPointList (
+//   IN EFI_HANDLE        ImageHandle,
+//   IN EFI_SYSTEM_TABLE  *SystemTable
+//   )
+// 
+// {
+//   return efi_main (ImageHandle, SystemTable);
+// }
+
+VOID
+EFIAPI
+ExitDriver (
+  IN EFI_STATUS  Status
+  )
+{
+  if (EFI_ERROR (Status)) {
+    ProcessLibraryDestructorList (gImageHandle, gST);
+  }
+  gBS->Exit (gImageHandle, Status, 0, NULL);
+}
+
+//GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gDriverUnloadImageCount = 0U;
+
+// EFI_STATUS
+// EFIAPI
+// ProcessModuleUnloadList (
+//   IN EFI_HANDLE        ImageHandle
+//   )
+// {
+//   return EFI_SUCCESS;
+// }
+
+// Stuff added in effort to get Secure Boot working....
+
+#define _PCD_TOKEN_PcdDebugPropertyMask  11U
+#define _PCD_VALUE_PcdDebugPropertyMask  0x0fU
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdDebugPropertyMask = _PCD_VALUE_PcdDebugPropertyMask;
+extern const  UINT8  _gPcd_FixedAtBuild_PcdDebugPropertyMask;
+#define _PCD_GET_MODE_8_PcdDebugPropertyMask  _gPcd_FixedAtBuild_PcdDebugPropertyMask
+//#define _PCD_SET_MODE_8_PcdDebugPropertyMask  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdDebugClearMemoryValue  10U
+#define _PCD_VALUE_PcdDebugClearMemoryValue  0xAFU
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdDebugClearMemoryValue = _PCD_VALUE_PcdDebugClearMemoryValue;
+extern const  UINT8  _gPcd_FixedAtBuild_PcdDebugClearMemoryValue;
+#define _PCD_GET_MODE_8_PcdDebugClearMemoryValue  _gPcd_FixedAtBuild_PcdDebugClearMemoryValue
+//#define _PCD_SET_MODE_8_PcdDebugClearMemoryValue  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdDebugPrintErrorLevel  5U
+#define _PCD_VALUE_PcdDebugPrintErrorLevel  0x80000000U
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdDebugPrintErrorLevel = _PCD_VALUE_PcdDebugPrintErrorLevel;
+extern const  UINT32  _gPcd_FixedAtBuild_PcdDebugPrintErrorLevel;
+#define _PCD_GET_MODE_32_PcdDebugPrintErrorLevel  _gPcd_FixedAtBuild_PcdDebugPrintErrorLevel
+//#define _PCD_SET_MODE_32_PcdDebugPrintErrorLevel  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
diff --git a/refind/AutoGen.h b/refind/AutoGen.h
new file mode 100644 (file)
index 0000000..a07912e
--- /dev/null
@@ -0,0 +1,51 @@
+/**
+  DO NOT EDIT
+  FILE auto-generated
+  Module name:
+    AutoGen.h
+  Abstract:       Auto-generated AutoGen.h for building module or library.
+**/
+
+#ifndef _AUTOGENH_B8448DD1_B146_41B7_9D66_98B3A0A404D3
+#define _AUTOGENH_B8448DD1_B146_41B7_9D66_98B3A0A404D3
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <Base.h>
+#include <Uefi.h>
+#include <Library/PcdLib.h>
+
+extern GUID  gEfiCallerIdGuid;
+
+#define EFI_CALLER_ID_GUID \
+  {0xB8448DD1, 0xB146, 0x41B7, {0x9D, 0x66, 0x98, 0xB3, 0xA0, 0xA4, 0x04, 0xD3}}
+
+// Definition of PCDs used in this module
+
+#define _PCD_TOKEN_PcdUgaConsumeSupport  16U
+#define _PCD_VALUE_PcdUgaConsumeSupport  ((BOOLEAN)1U)
+extern const  BOOLEAN  _gPcd_FixedAtBuild_PcdUgaConsumeSupport;
+#define _PCD_GET_MODE_BOOL_PcdUgaConsumeSupport  _gPcd_FixedAtBuild_PcdUgaConsumeSupport
+//#define _PCD_SET_MODE_BOOL_PcdUgaConsumeSupport  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+// Definition of PCDs used in libraries is in AutoGen.c
+
+
+EFI_STATUS
+EFIAPI
+efi_main (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  );
+
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/refind/Make.tiano b/refind/Make.tiano
new file mode 100644 (file)
index 0000000..075c4a7
--- /dev/null
@@ -0,0 +1,61 @@
+#
+# refind/Make.tiano
+# Build control file for rEFInd, using TianoCore EDK2
+# Requires that EfiLib, mok, and libeg subdirectories be built before this
+# file is used.
+#
+# This program is licensed under the terms of the GNU GPL, version 3,
+# or (at your option) any later version.
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+
+include ../Make.tiano
+
+EFILIB          = $(EDK2BASE)/Build/Mde/$(TARGET)_$(TOOL_CHAIN_TAG)/$(UC_ARCH)/MdePkg/Library
+ALL_EFILIBS     = $(EFILIB)/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib/OUTPUT/BaseDebugPrintErrorLevelLib.lib \
+                  $(EFILIB)/BasePrintLib/BasePrintLib/OUTPUT/BasePrintLib.lib \
+                  $(EFILIB)/BasePcdLibNull/BasePcdLibNull/OUTPUT/BasePcdLibNull.lib \
+                  $(EFILIB)/UefiDebugLibStdErr/UefiDebugLibStdErr/OUTPUT/UefiDebugLibStdErr.lib \
+                  $(EFILIB)/BaseLib/BaseLib/OUTPUT/BaseLib.lib \
+                  $(EFILIB)/BaseMemoryLib/BaseMemoryLib/OUTPUT/BaseMemoryLib.lib \
+                  $(EFILIB)/UefiBootServicesTableLib/UefiBootServicesTableLib/OUTPUT/UefiBootServicesTableLib.lib \
+                  $(EFILIB)/UefiMemoryAllocationLib/UefiMemoryAllocationLib/OUTPUT/UefiMemoryAllocationLib.lib \
+                  $(EFILIB)/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib/OUTPUT/UefiRuntimeServicesTableLib.lib \
+                  $(EFILIB)/UefiDevicePathLib/UefiDevicePathLib/OUTPUT/UefiDevicePathLib.lib \
+                  $(EFILIB)/UefiLib/UefiLib/OUTPUT/UefiLib.lib \
+                  $(EFILIB)/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull/OUTPUT/PeCoffExtraActionLibNull.lib \
+                  $(EFILIB)/UefiApplicationEntryPoint/UefiApplicationEntryPoint/OUTPUT/UefiApplicationEntryPoint.lib \
+                  $(EFILIB)/DxeServicesLib/DxeServicesLib/OUTPUT/DxeServicesLib.lib \
+                  $(EFILIB)/DxeServicesTableLib/DxeServicesTableLib/OUTPUT/DxeServicesTableLib.lib \
+                  $(EFILIB)/DxeHobLib/DxeHobLib/OUTPUT/DxeHobLib.lib \
+                  $(EFILIB)/BasePeCoffLib/BasePeCoffLib/OUTPUT/BasePeCoffLib.lib
+#                $(EFILIB)/BasePerformanceLibNull/BasePerformanceLibNull/OUTPUT/BasePerformanceLibNull.lib \
+#                /usr/local/UDK2010/MyWorkSpace/Build/Mde/RELEASE_GCC46/X64/MdePkg/Library/SecPeiDxeTimerLibCpu/SecPeiDxeTimerLibCpu/OUTPUT/SecPeiDxeTimerLibCpu.lib \
+#                /usr/local/UDK2010/MyWorkSpace/Build/MdeModule/RELEASE_GCC46/X64/MdeModulePkg/Core/Dxe/DxeMain/OUTPUT/DxeCore.lib \
+#                /usr/local/UDK2010/MyWorkSpace/Build/Mde/RELEASE_GCC46/X64/MdePkg/Library/BaseCacheMaintenanceLib/BaseCacheMaintenanceLib/OUTPUT/BaseCacheMaintenanceLib.lib \
+#                /usr/local/UDK2010/MyWorkSpace/Build/Mde/RELEASE_GCC46/X64/MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull/OUTPUT/BasePerformanceLibNull.lib
+#                  $(EFILIB)/../../MdeModulePkg/Core/Dxe/DxeMain/OUTPUT/DxeCore.lib
+#                /usr/local/UDK2010/MyWorkSpace/Build/MdeModule/RELEASE_GCC46/X64/MdeModulePkg/Core/Dxe/DxeMain/OUTPUT/DxeMain/DxeMain.obj
+
+ifeq ($(ARCH),aarch64)
+  ALL_EFILIBS +=    $(EFILIB)/BaseStackCheckLib/BaseStackCheckLib/OUTPUT/BaseStackCheckLib.lib
+endif
+
+SOURCE_NAMES     = apple config mystrings line_edit driver_support icns lib main menu screen gpt crc32 legacy AutoGen
+OBJS             = $(SOURCE_NAMES:=.obj)
+
+all: $(BUILDME)
+
+$(AR_TARGET): $(OBJS)
+       $(AR) -cr $(AR_TARGET).lib $(OBJS)
+
+$(DLL_TARGET)_$(FILENAME_CODE).dll: $(OBJS) ../libeg/libeg.lib ../EfiLib/EfiLib.lib ../mok/mok.lib
+       $(LD) -o $(DLL_TARGET)_$(FILENAME_CODE).dll $(LDFLAGS) --start-group $(ALL_EFILIBS) $(OBJS) ../libeg/libeg.lib ../EfiLib/EfiLib.lib ../mok/mok.lib --end-group
+
+$(BUILDME): $(DLL_TARGET)_$(FILENAME_CODE).dll
+       $(OBJCOPY) --strip-unneeded -R .eh_frame $(DLL_TARGET)_$(FILENAME_CODE).dll
+       $(GENFW) -e UEFI_APPLICATION -o $(BUILDME)_$(FILENAME_CODE).efi $(DLL_TARGET)_$(FILENAME_CODE).dll
+
+clean:
+       make clean
diff --git a/refind/Makefile b/refind/Makefile
new file mode 100644 (file)
index 0000000..6fe0b5b
--- /dev/null
@@ -0,0 +1,53 @@
+#
+# refind/Makefile
+# Build control file for the rEFInd boot menu
+#
+# This program is licensed under the terms of the GNU GPL, version 3,
+# or (at your option) any later version.
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+SRCDIR = .
+
+VPATH = $(SRCDIR)
+
+ARCH            = $(shell uname -m | sed s,i[3456789]86,ia32,)
+
+TARGET = refind.efi
+
+ifeq ($(ARCH),ia32)
+  LIBEG = build32
+  TARGET = refind_ia32.efi
+endif
+
+ifeq ($(ARCH),x86_64)
+  LIBEG = build64
+  TARGET = refind_x64.efi
+endif
+
+ifeq ($(ARCH),aarch64)
+  LIBEG = build
+  TARGET = refind_aa64.efi
+endif
+
+LOCAL_CPPFLAGS  = -I$(SRCDIR) -I$(SRCDIR)/../include -I$(SRCDIR)/../libeg -I$(SRCDIR)/../mok
+LOCAL_LDFLAGS   = -L$(SRCDIR)/../libeg/ -L$(SRCDIR)/../mok/ -L$(SRCDIR)/../EfiLib/
+LOCAL_LIBS      = -leg -lmok -lEfiLib
+
+OBJS            = main.o mystrings.o apple.o line_edit.o config.o menu.o screen.o icns.o gpt.o crc32.o lib.o driver_support.o legacy.o
+
+all: $(TARGET)
+
+include $(SRCDIR)/../Make.common
+
+$(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 .rel.* -j .rela.* -j .rel* -j .rela* \
+                  -j .reloc $(FORMAT) $< $@
+       chmod a-x $(TARGET)
+
+# EOF
+# DO NOT DELETE
diff --git a/refind/apple.c b/refind/apple.c
new file mode 100644 (file)
index 0000000..9f9b1f3
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * refind/apple.c
+ * Functions specific to Apple computers
+ * 
+ * Copyright (c) 2015 Roderick W. Smith
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * 
+ */
+
+#include "global.h"
+#include "config.h"
+#include "lib.h"
+#include "screen.h"
+#include "apple.h"
+#include "mystrings.h"
+#include "refit_call_wrapper.h"
+
+CHAR16 gCsrStatus[256];
+
+// Get CSR (Apple's System Integrity Protection [SIP], or "rootless") status
+// information.
+EFI_STATUS GetCsrStatus(UINT32 *CsrStatus) {
+    UINT32     *ReturnValue = NULL;
+    UINTN      CsrLength;
+    EFI_GUID   CsrGuid = CSR_GUID;
+    EFI_STATUS Status = EFI_INVALID_PARAMETER;
+
+    if (CsrStatus) {
+        Status = EfivarGetRaw(&CsrGuid, L"csr-active-config", (CHAR8**) &ReturnValue, &CsrLength);
+        if (Status == EFI_SUCCESS) {
+            if (CsrLength == 4) {
+                *CsrStatus = *ReturnValue;
+            } else {
+                Status = EFI_BAD_BUFFER_SIZE;
+                SPrint(gCsrStatus, 255, L" Unknown System Integrity Protection version");
+            }
+            MyFreePool(ReturnValue);
+        } // if (Status == EFI_SUCCESS)
+    } // if (CsrStatus)
+    return Status;
+} // INTN GetCsrStatus()
+
+// Store string describing CSR status value in gCsrStatus variable, which appears
+// on the Info page. If DisplayMessage is TRUE, displays the new value of
+// gCsrStatus on the screen for three seconds.
+VOID RecordgCsrStatus(UINT32 CsrStatus, BOOLEAN DisplayMessage) {
+    EG_PIXEL    BGColor;
+
+    BGColor.b = 255;
+    BGColor.g = 175;
+    BGColor.r = 100;
+    BGColor.a = 0;
+
+    switch (CsrStatus) {
+        case SIP_ENABLED:
+            SPrint(gCsrStatus, 255, L" System Integrity Protection is enabled (0x%02x)", CsrStatus);
+            break;
+        case SIP_DISABLED:
+            SPrint(gCsrStatus, 255, L" System Integrity Protection is disabled (0x%02x)", CsrStatus);
+            break;
+        default:
+            SPrint(gCsrStatus, 255, L" System Integrity Protection status: 0x%02x", CsrStatus);
+    } // switch
+    if (DisplayMessage) {
+        egDisplayMessage(gCsrStatus, &BGColor);
+        PauseSeconds(3);
+    } // if
+} // VOID RecordgCsrStatus
+
+// Find the current CSR status and reset it to the next one in the
+// GlobalConfig.CsrValues list, or to the first value if the current
+// value is not on the list.
+VOID RotateCsrValue(VOID) {
+    UINT32       CurrentValue, TargetCsr;
+    UINT32_LIST  *ListItem;
+    EFI_GUID     CsrGuid = CSR_GUID;
+    EFI_STATUS   Status;
+
+    Status = GetCsrStatus(&CurrentValue);
+    if ((Status == EFI_SUCCESS) && GlobalConfig.CsrValues) {
+        ListItem = GlobalConfig.CsrValues;
+        while ((ListItem != NULL) && (ListItem->Value != CurrentValue))
+            ListItem = ListItem->Next;
+        if (ListItem == NULL || ListItem->Next == NULL) {
+            TargetCsr = GlobalConfig.CsrValues->Value;
+        } else {
+            TargetCsr = ListItem->Next->Value;
+        }
+        Status = EfivarSetRaw(&CsrGuid, L"csr-active-config", (CHAR8 *) &TargetCsr, 4, TRUE);
+        if (Status == EFI_SUCCESS)
+            RecordgCsrStatus(TargetCsr, TRUE);
+        else
+            SPrint(gCsrStatus, 255, L" Error setting System Integrity Protection code.");
+    } // if
+} // VOID RotateCsrValue()
+
+
+/*
+ * The below definitions and SetAppleOSInfo() function are based on a GRUB patch
+ * by Andreas Heider:
+ * https://lists.gnu.org/archive/html/grub-devel/2013-12/msg00442.html
+ */
+
+#define EFI_APPLE_SET_OS_PROTOCOL_GUID  \
+  { 0xc5c5da95, 0x7d5c, 0x45e6, \
+    { 0xb2, 0xf1, 0x3f, 0xd5, 0x2b, 0xb1, 0x00, 0x77 } \
+  }
+
+typedef struct EfiAppleSetOsInterface {
+    UINT64 Version;
+    EFI_STATUS EFIAPI (*SetOsVersion) (IN CHAR8 *Version);
+    EFI_STATUS EFIAPI (*SetOsVendor) (IN CHAR8 *Vendor);
+} EfiAppleSetOsInterface;
+
+// Function to tell the firmware that OS X is being launched. This is
+// required to work around problems on some Macs that don't fully
+// initialize some hardware (especially video displays) when third-party
+// OSes are launched in EFI mode.
+EFI_STATUS SetAppleOSInfo() {
+    CHAR16 *AppleOSVersion = NULL;
+    CHAR8 *AppleOSVersion8 = NULL;
+    EFI_STATUS Status;
+    EFI_GUID apple_set_os_guid = EFI_APPLE_SET_OS_PROTOCOL_GUID;
+    EfiAppleSetOsInterface *SetOs = NULL;
+
+    Status = refit_call3_wrapper(BS->LocateProtocol, &apple_set_os_guid, NULL, (VOID**) &SetOs);
+
+    // If not a Mac, ignore the call....
+    if ((Status != EFI_SUCCESS) || (!SetOs))
+        return EFI_SUCCESS;
+
+    if ((SetOs->Version != 0) && GlobalConfig.SpoofOSXVersion) {
+        AppleOSVersion = StrDuplicate(L"Mac OS X");
+        MergeStrings(&AppleOSVersion, GlobalConfig.SpoofOSXVersion, ' ');
+        if (AppleOSVersion) {
+            AppleOSVersion8 = AllocateZeroPool((StrLen(AppleOSVersion) + 1) * sizeof(CHAR8));
+            UnicodeStrToAsciiStr(AppleOSVersion, AppleOSVersion8);
+            if (AppleOSVersion8) {
+                Status = refit_call1_wrapper (SetOs->SetOsVersion, AppleOSVersion8);
+                if (!EFI_ERROR(Status))
+                    Status = EFI_SUCCESS;
+                MyFreePool(AppleOSVersion8);
+            } else {
+                Status = EFI_OUT_OF_RESOURCES;
+                Print(L"Out of resources in SetAppleOSInfo!\n");
+            }
+            if ((Status == EFI_SUCCESS) && (SetOs->Version == 2))
+                Status = refit_call1_wrapper (SetOs->SetOsVendor, (CHAR8 *) "Apple Inc.");
+            MyFreePool(AppleOSVersion);
+        } // if (AppleOSVersion)
+    } // if
+    if (Status != EFI_SUCCESS)
+        Print(L"Unable to set firmware boot type!\n");
+
+    return (Status);
+} // EFI_STATUS SetAppleOSInfo()
\ No newline at end of file
diff --git a/refind/apple.h b/refind/apple.h
new file mode 100644 (file)
index 0000000..94062b1
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * refind/apple.h
+ * 
+ * Copyright (c) 2015 Roderick W. Smith
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef __APPLE_H_
+#define __APPLE_H_
+
+// The constants related to Apple's System Integrity Protection (SIP)....
+#define CSR_GUID { 0x7c436110, 0xab2a, 0x4bbb, { 0xa8, 0x80, 0xfe, 0x41, 0x99, 0x5c, 0x9f, 0x82 } };
+// These codes are returned in the first byte of the csr-active-config variable
+#define CSR_ALLOW_UNTRUSTED_KEXTS       0x01
+#define CSR_ALLOW_UNRESTRICTED_FS       0x02
+#define CSR_ALLOW_TASK_FOR_PID          0x04
+#define CSR_ALLOW_KERNEL_DEBUGGER       0x08
+#define CSR_ALLOW_APPLE_INTERNAL        0x10
+#define CSR_ALLOW_UNRESTRICTED_DTRACE   0x20
+#define CSR_ALLOW_UNRESTRICTED_NVRAM    0x40
+#define CSR_END_OF_LIST                 0xFFFFFFFF
+// Some summaries....
+#define SIP_ENABLED  CSR_ALLOW_APPLE_INTERNAL
+#define SIP_DISABLED (CSR_ALLOW_UNRESTRICTED_NVRAM | \
+                      CSR_ALLOW_UNRESTRICTED_DTRACE | \
+                      CSR_ALLOW_APPLE_INTERNAL | \
+                      CSR_ALLOW_TASK_FOR_PID | \
+                      CSR_ALLOW_UNRESTRICTED_FS | \
+                      CSR_ALLOW_UNTRUSTED_KEXTS)
+#define CSR_MAX_LEGAL_VALUE (CSR_ALLOW_UNTRUSTED_KEXTS | \
+                             CSR_ALLOW_UNRESTRICTED_FS | \
+                             CSR_ALLOW_TASK_FOR_PID | \
+                             CSR_ALLOW_KERNEL_DEBUGGER | \
+                             CSR_ALLOW_APPLE_INTERNAL | \
+                             CSR_ALLOW_UNRESTRICTED_DTRACE | \
+                             CSR_ALLOW_UNRESTRICTED_NVRAM)
+
+extern CHAR16 gCsrStatus[256];
+
+EFI_STATUS GetCsrStatus(UINT32 *CsrValue);
+VOID RecordgCsrStatus(UINT32 CsrStatus, BOOLEAN DisplayMessage);
+VOID RotateCsrValue(VOID);
+EFI_STATUS SetAppleOSInfo();
+
+#endif
\ No newline at end of file
diff --git a/refind/config.c b/refind/config.c
new file mode 100644 (file)
index 0000000..8aa2850
--- /dev/null
@@ -0,0 +1,1206 @@
+/*
+ * refind/config.c
+ * Configuration file functions
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Modifications copyright (c) 2012-2015 Roderick W. Smith
+ * 
+ * Modifications distributed under the terms of the GNU General Public
+ * License (GPL) version 3 (GPLv3) or (at your option) any later version.
+ * 
+ */
+/*
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "global.h"
+#include "lib.h"
+#include "icns.h"
+#include "menu.h"
+#include "config.h"
+#include "screen.h"
+#include "apple.h"
+#include "mystrings.h"
+#include "../include/refit_call_wrapper.h"
+#include "../mok/mok.h"
+
+// constants
+
+#define LINUX_OPTIONS_FILENAMES  L"refind_linux.conf,refind-linux.conf"
+#define MAXCONFIGFILESIZE        (128*1024)
+
+#define ENCODING_ISO8859_1  (0)
+#define ENCODING_UTF8       (1)
+#define ENCODING_UTF16_LE   (2)
+
+#define GetTime ST->RuntimeServices->GetTime
+#define LAST_MINUTE 1439 /* Last minute of a day */
+
+extern REFIT_MENU_ENTRY MenuEntryReturn;
+//static REFIT_MENU_ENTRY MenuEntryReturn   = { L"Return to Main Menu", TAG_RETURN, 0, 0, 0, NULL, NULL, NULL };
+
+//
+// read a file into a buffer
+//
+
+EFI_STATUS ReadFile(IN EFI_FILE_HANDLE BaseDir, IN CHAR16 *FileName, IN OUT REFIT_FILE *File, OUT UINTN *size)
+{
+    EFI_STATUS      Status;
+    EFI_FILE_HANDLE FileHandle;
+    EFI_FILE_INFO   *FileInfo;
+    UINT64          ReadSize;
+    CHAR16          Message[256];
+
+    File->Buffer = NULL;
+    File->BufferSize = 0;
+
+    // read the file, allocating a buffer on the way
+    Status = refit_call5_wrapper(BaseDir->Open, BaseDir, &FileHandle, FileName, EFI_FILE_MODE_READ, 0);
+    SPrint(Message, 255, L"while loading the file '%s'", FileName);
+    if (CheckError(Status, Message))
+        return Status;
+
+    FileInfo = LibFileInfo(FileHandle);
+    if (FileInfo == NULL) {
+        // TODO: print and register the error
+        refit_call1_wrapper(FileHandle->Close, FileHandle);
+        return EFI_LOAD_ERROR;
+    }
+    ReadSize = FileInfo->FileSize;
+    FreePool(FileInfo);
+
+    File->BufferSize = (UINTN)ReadSize;
+    File->Buffer = AllocatePool(File->BufferSize);
+    if (File->Buffer == NULL) {
+       size = 0;
+       return EFI_OUT_OF_RESOURCES;
+    } else {
+       *size = File->BufferSize;
+    } // if/else
+    Status = refit_call3_wrapper(FileHandle->Read, FileHandle, &File->BufferSize, File->Buffer);
+    if (CheckError(Status, Message)) {
+        MyFreePool(File->Buffer);
+        File->Buffer = NULL;
+        refit_call1_wrapper(FileHandle->Close, FileHandle);
+        return Status;
+    }
+    Status = refit_call1_wrapper(FileHandle->Close, FileHandle);
+
+    // setup for reading
+    File->Current8Ptr  = (CHAR8 *)File->Buffer;
+    File->End8Ptr      = File->Current8Ptr + File->BufferSize;
+    File->Current16Ptr = (CHAR16 *)File->Buffer;
+    File->End16Ptr     = File->Current16Ptr + (File->BufferSize >> 1);
+
+    // detect encoding
+    File->Encoding = ENCODING_ISO8859_1;   // default: 1:1 translation of CHAR8 to CHAR16
+    if (File->BufferSize >= 4) {
+        if (File->Buffer[0] == 0xFF && File->Buffer[1] == 0xFE) {
+            // BOM in UTF-16 little endian (or UTF-32 little endian)
+            File->Encoding = ENCODING_UTF16_LE;   // use CHAR16 as is
+            File->Current16Ptr++;
+        } else if (File->Buffer[0] == 0xEF && File->Buffer[1] == 0xBB && File->Buffer[2] == 0xBF) {
+            // BOM in UTF-8
+            File->Encoding = ENCODING_UTF8;       // translate from UTF-8 to UTF-16
+            File->Current8Ptr += 3;
+        } else if (File->Buffer[1] == 0 && File->Buffer[3] == 0) {
+            File->Encoding = ENCODING_UTF16_LE;   // use CHAR16 as is
+        }
+        // TODO: detect other encodings as they are implemented
+    }
+
+    return EFI_SUCCESS;
+}
+
+//
+// get a single line of text from a file
+//
+
+static CHAR16 *ReadLine(REFIT_FILE *File)
+{
+    CHAR16  *Line, *q;
+    UINTN   LineLength;
+
+    if (File->Buffer == NULL)
+        return NULL;
+
+    if (File->Encoding == ENCODING_ISO8859_1 || File->Encoding == ENCODING_UTF8) {
+
+        CHAR8 *p, *LineStart, *LineEnd;
+
+        p = File->Current8Ptr;
+        if (p >= File->End8Ptr)
+            return NULL;
+
+        LineStart = p;
+        for (; p < File->End8Ptr; p++)
+            if (*p == 13 || *p == 10)
+                break;
+        LineEnd = p;
+        for (; p < File->End8Ptr; p++)
+            if (*p != 13 && *p != 10)
+                break;
+        File->Current8Ptr = p;
+
+        LineLength = (UINTN)(LineEnd - LineStart) + 1;
+        Line = AllocatePool(LineLength * sizeof(CHAR16));
+        if (Line == NULL)
+            return NULL;
+
+        q = Line;
+        if (File->Encoding == ENCODING_ISO8859_1) {
+            for (p = LineStart; p < LineEnd; )
+                *q++ = *p++;
+        } else if (File->Encoding == ENCODING_UTF8) {
+            // TODO: actually handle UTF-8
+            for (p = LineStart; p < LineEnd; )
+                *q++ = *p++;
+        }
+        *q = 0;
+
+    } else if (File->Encoding == ENCODING_UTF16_LE) {
+
+        CHAR16 *p, *LineStart, *LineEnd;
+
+        p = File->Current16Ptr;
+        if (p >= File->End16Ptr)
+            return NULL;
+
+        LineStart = p;
+        for (; p < File->End16Ptr; p++)
+            if (*p == 13 || *p == 10)
+                break;
+        LineEnd = p;
+        for (; p < File->End16Ptr; p++)
+            if (*p != 13 && *p != 10)
+                break;
+        File->Current16Ptr = p;
+
+        LineLength = (UINTN)(LineEnd - LineStart) + 1;
+        Line = AllocatePool(LineLength * sizeof(CHAR16));
+        if (Line == NULL)
+            return NULL;
+
+        for (p = LineStart, q = Line; p < LineEnd; )
+            *q++ = *p++;
+        *q = 0;
+
+    } else
+        return NULL;   // unsupported encoding
+
+    return Line;
+}
+
+// Returns FALSE if *p points to the end of a token, TRUE otherwise.
+// Also modifies *p **IF** the first and second characters are both
+// quotes ('"'); it deletes one of them.
+static BOOLEAN KeepReading(IN OUT CHAR16 *p, IN OUT BOOLEAN *IsQuoted) {
+   BOOLEAN MoreToRead = FALSE;
+   CHAR16  *Temp = NULL;
+
+   if ((p == NULL) || (IsQuoted == NULL))
+      return FALSE;
+
+   if (*p == L'\0')
+      return FALSE;
+
+   if ((*p != ' ' && *p != '\t' && *p != '=' && *p != '#' && *p != ',') || *IsQuoted) {
+      MoreToRead = TRUE;
+   }
+   if (*p == L'"') {
+      if (p[1] == L'"') {
+         Temp = StrDuplicate(&p[1]);
+         if (Temp != NULL) {
+            StrCpy(p, Temp);
+            FreePool(Temp);
+         }
+         MoreToRead = TRUE;
+      } else {
+         *IsQuoted = !(*IsQuoted);
+         MoreToRead = FALSE;
+      } // if/else second character is a quote
+   } // if first character is a quote
+
+   return MoreToRead;
+} // BOOLEAN KeepReading()
+
+//
+// get a line of tokens from a file
+//
+UINTN ReadTokenLine(IN REFIT_FILE *File, OUT CHAR16 ***TokenList)
+{
+    BOOLEAN         LineFinished, IsQuoted = FALSE;
+    CHAR16          *Line, *Token, *p;
+    UINTN           TokenCount = 0;
+
+    *TokenList = NULL;
+
+    while (TokenCount == 0) {
+        Line = ReadLine(File);
+        if (Line == NULL)
+            return(0);
+        if (Line[0] == L'\0') {
+            MyFreePool(Line);
+            return(0);
+        } // if
+
+        p = Line;
+        LineFinished = FALSE;
+        while (!LineFinished) {
+            // skip whitespace & find start of token
+            while ((*p == ' ' || *p == '\t' || *p == '=' || *p == ',') && !IsQuoted)
+                p++;
+            if (*p == 0 || *p == '#')
+                break;
+
+            if (*p == '"') {
+               IsQuoted = !IsQuoted;
+               p++;
+            } // if
+            Token = p;
+
+            // find end of token
+            while (KeepReading(p, &IsQuoted)) {
+               if ((*p == L'/') && !IsQuoted) // Switch Unix-style to DOS-style directory separators
+                  *p = L'\\';
+               p++;
+            } // while
+            if (*p == L'\0' || *p == L'#')
+                LineFinished = TRUE;
+            *p++ = 0;
+
+            AddListElement((VOID ***)TokenList, &TokenCount, (VOID *)StrDuplicate(Token));
+        }
+
+        FreePool(Line);
+    }
+    return (TokenCount);
+} /* ReadTokenLine() */
+
+VOID FreeTokenLine(IN OUT CHAR16 ***TokenList, IN OUT UINTN *TokenCount)
+{
+    // TODO: also free the items
+    FreeList((VOID ***)TokenList, TokenCount);
+}
+
+// handle a parameter with a single integer argument
+static VOID HandleInt(IN CHAR16 **TokenList, IN UINTN TokenCount, OUT UINTN *Value)
+{
+    if (TokenCount == 2) {
+       if (StrCmp(TokenList[1], L"-1") == 0)
+          *Value = -1;
+       else
+          *Value = Atoi(TokenList[1]);
+    }
+}
+
+// handle a parameter with a single string argument
+static VOID HandleString(IN CHAR16 **TokenList, IN UINTN TokenCount, OUT CHAR16 **Target) {
+   if ((TokenCount == 2) && Target) {
+      if ((StrLen(TokenList[1]) > 1) && (TokenList[1][0] == L'+') &&
+          ((TokenList[1][1] == L',') || (TokenList[1][1] == L' '))) {
+         if (*Target) {
+            MergeStrings(Target, TokenList[1] + 2, L',');
+         } else {
+            *Target = StrDuplicate(TokenList[1] + 2);
+         } // if/else
+      } else {
+         MyFreePool(*Target);
+         *Target = StrDuplicate(TokenList[1]);
+      } // if/else
+   } // if
+} // static VOID HandleString()
+
+// Handle a parameter with a series of string arguments, to replace or be added to a
+// comma-delimited list. Passes each token through the CleanUpPathNameSlashes() function
+// to ensure consistency in subsequent comparisons of filenames. If the first
+// non-keyword token is "+", the list is added to the existing target string; otherwise,
+// the tokens replace the current string.
+static VOID HandleStrings(IN CHAR16 **TokenList, IN UINTN TokenCount, OUT CHAR16 **Target) {
+   UINTN i;
+   BOOLEAN AddMode = FALSE;
+
+   if ((TokenCount > 2) && (StrCmp(TokenList[1], L"+") == 0)) {
+      AddMode = TRUE;
+   }
+
+   if ((*Target != NULL) && !AddMode) {
+      FreePool(*Target);
+      *Target = NULL;
+   } // if
+   for (i = 1; i < TokenCount; i++) {
+      if ((i != 1) || !AddMode) {
+         CleanUpPathNameSlashes(TokenList[i]);
+         MergeStrings(Target, TokenList[i], L',');
+      } // if
+   } // for
+} // static VOID HandleStrings()
+
+// Handle a parameter with a series of hexadecimal arguments, to replace or be added to a
+// linked list of UINT32 values. Any item with a non-hexadecimal value is discarded, as is
+// any value that exceeds MaxValue. If the first non-keyword token is "+", the new list is
+// added to the existing Target; otherwise, the interpreted tokens replace the current
+// Target.
+static VOID HandleHexes(IN CHAR16 **TokenList, IN UINTN TokenCount, IN UINTN MaxValue, OUT UINT32_LIST **Target) {
+    UINTN       InputIndex = 1, i;
+    UINT32      Value;
+    UINT32_LIST *EndOfList = NULL;
+    UINT32_LIST *NewEntry;
+
+    if ((TokenCount > 2) && (StrCmp(TokenList[1], L"+") == 0)) {
+        InputIndex = 2;
+        EndOfList = *Target;
+        while (EndOfList && (EndOfList->Next != NULL)) {
+            EndOfList = EndOfList->Next;
+        }
+    } else {
+        EraseUint32List(Target);
+    }
+
+    for (i = InputIndex; i < TokenCount; i++) {
+        if (IsValidHex(TokenList[i])) {
+            Value = (UINT32) StrToHex(TokenList[i], 0, 8);
+            if (Value <= MaxValue) {
+                NewEntry = AllocatePool(sizeof(UINT32_LIST));
+                if (NewEntry) {
+                    NewEntry->Value = Value;
+                    NewEntry->Next = NULL;
+                    if (EndOfList == NULL) {
+                        EndOfList = NewEntry;
+                        *Target = NewEntry;
+                    } else {
+                        EndOfList->Next = NewEntry;
+                        EndOfList = NewEntry;
+                    } // if/else
+                } // if allocated memory for NewEntry
+            } // if (Value < MaxValue)
+        } // if is valid hex value
+    } // for
+} // static VOID HandleHexes()
+
+// Convert TimeString (in "HH:MM" format) to a pure-minute format. Values should be
+// in the range from 0 (for 00:00, or midnight) to 1439 (for 23:59; aka LAST_MINUTE).
+// Any value outside that range denotes an error in the specification. Note that if
+// the input is a number that includes no colon, this function will return the original
+// number in UINTN form.
+static UINTN HandleTime(IN CHAR16 *TimeString) {
+   UINTN Hour = 0, Minute = 0, TimeLength, i = 0;
+
+   TimeLength = StrLen(TimeString);
+   while (i < TimeLength) {
+      if (TimeString[i] == L':') {
+         Hour = Minute;
+         Minute = 0;
+      } // if
+      if ((TimeString[i] >= L'0') && (TimeString[i] <= '9')) {
+         Minute *= 10;
+         Minute += (TimeString[i] - L'0');
+      } // if
+      i++;
+   } // while
+   return (Hour * 60 + Minute);
+} // BOOLEAN HandleTime()
+
+static BOOLEAN HandleBoolean(IN CHAR16 **TokenList, IN UINTN TokenCount) {
+   BOOLEAN TruthValue = TRUE;
+
+   if ((TokenCount >= 2) && ((StrCmp(TokenList[1], L"0") == 0) ||
+                             MyStriCmp(TokenList[1], L"false") ||
+                             MyStriCmp(TokenList[1], L"off"))) {
+      TruthValue = FALSE;
+   } // if
+
+   return TruthValue;
+} // BOOLEAN HandleBoolean
+
+// Sets the default boot loader IF the current time is within the bounds
+// defined by the third and fourth tokens in the TokenList.
+static VOID SetDefaultByTime(IN CHAR16 **TokenList, OUT CHAR16 **Default) {
+   EFI_STATUS            Status;
+   EFI_TIME              CurrentTime;
+   UINTN                 StartTime, EndTime, Now;
+   BOOLEAN               SetIt = FALSE;
+
+   StartTime = HandleTime(TokenList[2]);
+   EndTime = HandleTime(TokenList[3]);
+
+   if ((StartTime <= LAST_MINUTE) && (EndTime <= LAST_MINUTE)) {
+      Status = refit_call2_wrapper(GetTime, &CurrentTime, NULL);
+      if (Status != EFI_SUCCESS)
+         return;
+      Now = CurrentTime.Hour * 60 + CurrentTime.Minute;
+
+      if (Now > LAST_MINUTE) { // Shouldn't happen; just being paranoid
+         Print(L"Warning: Impossible system time: %d:%d\n", CurrentTime.Hour, CurrentTime.Minute);
+         return;
+      } // if impossible time
+
+      if (StartTime < EndTime) { // Time range does NOT cross midnight
+         if ((Now >= StartTime) && (Now <= EndTime))
+            SetIt = TRUE;
+      } else { // Time range DOES cross midnight
+         if ((Now >= StartTime) && (Now <= EndTime))
+            SetIt = TRUE;
+      } // if/else time range crosses midnight
+
+      if (SetIt) {
+         MyFreePool(*Default);
+         *Default = StrDuplicate(TokenList[1]);
+      } // if (SetIt)
+   } // if ((StartTime <= LAST_MINUTE) && (EndTime <= LAST_MINUTE))
+} // VOID SetDefaultByTime()
+
+// read config file
+VOID ReadConfig(CHAR16 *FileName)
+{
+    EFI_STATUS      Status;
+    REFIT_FILE      File;
+    CHAR16          **TokenList;
+    CHAR16          *FlagName;
+    CHAR16          *TempStr = NULL;
+    UINTN           TokenCount, i;
+    EFI_GUID        RefindGuid = REFIND_GUID_VALUE;
+
+    // Set a few defaults only if we're loading the default file.
+    if (MyStriCmp(FileName, GlobalConfig.ConfigFilename)) {
+       MyFreePool(GlobalConfig.AlsoScan);
+       GlobalConfig.AlsoScan = StrDuplicate(ALSO_SCAN_DIRS);
+       MyFreePool(GlobalConfig.DontScanDirs);
+       if (SelfVolume) {
+          if (SelfVolume->VolName) {
+             TempStr = SelfVolume->VolName ? StrDuplicate(SelfVolume->VolName) : NULL;
+          } else {
+             TempStr = AllocateZeroPool(256 * sizeof(CHAR16));
+             if (TempStr != NULL)
+                SPrint(TempStr, 255, L"fs%d", SelfVolume->VolNumber);
+          } // if/else
+       }
+       MergeStrings(&TempStr, SelfDirPath, L':');
+       MergeStrings(&TempStr, MEMTEST_LOCATIONS, L',');
+       GlobalConfig.DontScanDirs = TempStr;
+       MyFreePool(GlobalConfig.DontScanFiles);
+       GlobalConfig.DontScanFiles = StrDuplicate(DONT_SCAN_FILES);
+       MergeStrings(&(GlobalConfig.DontScanFiles), MOK_NAMES, L',');
+       MyFreePool(GlobalConfig.DontScanVolumes);
+       GlobalConfig.DontScanVolumes = StrDuplicate(DONT_SCAN_VOLUMES);
+       GlobalConfig.WindowsRecoveryFiles = StrDuplicate(WINDOWS_RECOVERY_FILES);
+       if (GlobalConfig.DefaultSelection != NULL) {
+          MyFreePool(GlobalConfig.DefaultSelection);
+          GlobalConfig.DefaultSelection = NULL;
+       }
+       Status = EfivarGetRaw(&RefindGuid, L"PreviousBoot", (CHAR8**) &(GlobalConfig.DefaultSelection), &i);
+       if (Status != EFI_SUCCESS)
+          GlobalConfig.DefaultSelection = NULL;
+    } // if
+
+    if (!FileExists(SelfDir, FileName)) {
+       Print(L"Configuration file '%s' missing!\n", FileName);
+       if (!FileExists(SelfDir, L"icons")) {
+          Print(L"Icons directory doesn't exist; setting textonly = TRUE!\n");
+          GlobalConfig.TextOnly = TRUE;
+       }
+       return;
+    }
+
+    Status = ReadFile(SelfDir, FileName, &File, &i);
+    if (EFI_ERROR(Status))
+        return;
+
+    for (;;) {
+        TokenCount = ReadTokenLine(&File, &TokenList);
+        if (TokenCount == 0)
+            break;
+
+        if (MyStriCmp(TokenList[0], L"timeout")) {
+            HandleInt(TokenList, TokenCount, &(GlobalConfig.Timeout));
+
+        } else if (MyStriCmp(TokenList[0], L"hideui")) {
+            for (i = 1; i < TokenCount; i++) {
+                FlagName = TokenList[i];
+                if (MyStriCmp(FlagName, L"banner")) {
+                   GlobalConfig.HideUIFlags |= HIDEUI_FLAG_BANNER;
+                } else if (MyStriCmp(FlagName, L"label")) {
+                   GlobalConfig.HideUIFlags |= HIDEUI_FLAG_LABEL;
+                } else if (MyStriCmp(FlagName, L"singleuser")) {
+                   GlobalConfig.HideUIFlags |= HIDEUI_FLAG_SINGLEUSER;
+                } else if (MyStriCmp(FlagName, L"hwtest")) {
+                   GlobalConfig.HideUIFlags |= HIDEUI_FLAG_HWTEST;
+                } else if (MyStriCmp(FlagName, L"arrows")) {
+                   GlobalConfig.HideUIFlags |= HIDEUI_FLAG_ARROWS;
+                } else if (MyStriCmp(FlagName, L"hints")) {
+                   GlobalConfig.HideUIFlags |= HIDEUI_FLAG_HINTS;
+                } else if (MyStriCmp(FlagName, L"editor")) {
+                   GlobalConfig.HideUIFlags |= HIDEUI_FLAG_EDITOR;
+                } else if (MyStriCmp(FlagName, L"safemode")) {
+                   GlobalConfig.HideUIFlags |= HIDEUI_FLAG_SAFEMODE;
+                } else if (MyStriCmp(FlagName, L"badges")) {
+                   GlobalConfig.HideUIFlags |= HIDEUI_FLAG_BADGES;
+                } else if (MyStriCmp(FlagName, L"all")) {
+                   GlobalConfig.HideUIFlags = HIDEUI_FLAG_ALL;
+                } else {
+                    Print(L" unknown hideui flag: '%s'\n", FlagName);
+                }
+            }
+
+        } else if (MyStriCmp(TokenList[0], L"icons_dir")) {
+           HandleString(TokenList, TokenCount, &(GlobalConfig.IconsDir));
+
+        } else if (MyStriCmp(TokenList[0], L"scanfor")) {
+           for (i = 0; i < NUM_SCAN_OPTIONS; i++) {
+              if (i < TokenCount)
+                 GlobalConfig.ScanFor[i] = TokenList[i][0];
+              else
+                 GlobalConfig.ScanFor[i] = ' ';
+           }
+
+        } else if (MyStriCmp(TokenList[0], L"uefi_deep_legacy_scan")) {
+           GlobalConfig.DeepLegacyScan = HandleBoolean(TokenList, TokenCount);
+
+        } else if (MyStriCmp(TokenList[0], L"scan_delay") && (TokenCount == 2)) {
+           HandleInt(TokenList, TokenCount, &(GlobalConfig.ScanDelay));
+
+        } else if (MyStriCmp(TokenList[0], L"also_scan_dirs")) {
+            HandleStrings(TokenList, TokenCount, &(GlobalConfig.AlsoScan));
+
+        } else if (MyStriCmp(TokenList[0], L"don't_scan_volumes") || MyStriCmp(TokenList[0], L"dont_scan_volumes")) {
+           // Note: Don't use HandleStrings() because it modifies slashes, which might be present in volume name
+           MyFreePool(GlobalConfig.DontScanVolumes);
+           GlobalConfig.DontScanVolumes = NULL;
+           for (i = 1; i < TokenCount; i++) {
+              MergeStrings(&GlobalConfig.DontScanVolumes, TokenList[i], L',');
+           }
+
+        } else if (MyStriCmp(TokenList[0], L"don't_scan_dirs") || MyStriCmp(TokenList[0], L"dont_scan_dirs")) {
+            HandleStrings(TokenList, TokenCount, &(GlobalConfig.DontScanDirs));
+
+        } else if (MyStriCmp(TokenList[0], L"don't_scan_files") || MyStriCmp(TokenList[0], L"dont_scan_files")) {
+           HandleStrings(TokenList, TokenCount, &(GlobalConfig.DontScanFiles));
+
+        } else if (MyStriCmp(TokenList[0], L"windows_recovery_files")) {
+           HandleStrings(TokenList, TokenCount, &(GlobalConfig.WindowsRecoveryFiles));
+
+        } else if (MyStriCmp(TokenList[0], L"scan_driver_dirs")) {
+            HandleStrings(TokenList, TokenCount, &(GlobalConfig.DriverDirs));
+
+        } else if (MyStriCmp(TokenList[0], L"showtools")) {
+            SetMem(GlobalConfig.ShowTools, NUM_TOOLS * sizeof(UINTN), 0);
+            for (i = 1; (i < TokenCount) && (i < NUM_TOOLS); i++) {
+                FlagName = TokenList[i];
+                if (MyStriCmp(FlagName, L"shell")) {
+                    GlobalConfig.ShowTools[i - 1] = TAG_SHELL;
+                } else if (MyStriCmp(FlagName, L"gptsync")) {
+                    GlobalConfig.ShowTools[i - 1] = TAG_GPTSYNC;
+                } else if (MyStriCmp(FlagName, L"gdisk")) {
+                   GlobalConfig.ShowTools[i - 1] = TAG_GDISK;
+                } else if (MyStriCmp(FlagName, L"about")) {
+                   GlobalConfig.ShowTools[i - 1] = TAG_ABOUT;
+                } else if (MyStriCmp(FlagName, L"exit")) {
+                   GlobalConfig.ShowTools[i - 1] = TAG_EXIT;
+                } else if (MyStriCmp(FlagName, L"reboot")) {
+                   GlobalConfig.ShowTools[i - 1] = TAG_REBOOT;
+                } else if (MyStriCmp(FlagName, L"shutdown")) {
+                   GlobalConfig.ShowTools[i - 1] = TAG_SHUTDOWN;
+                } else if (MyStriCmp(FlagName, L"apple_recovery")) {
+                   GlobalConfig.ShowTools[i - 1] = TAG_APPLE_RECOVERY;
+                } else if (MyStriCmp(FlagName, L"windows_recovery")) {
+                   GlobalConfig.ShowTools[i - 1] = TAG_WINDOWS_RECOVERY;
+                } else if (MyStriCmp(FlagName, L"mok_tool")) {
+                   GlobalConfig.ShowTools[i - 1] = TAG_MOK_TOOL;
+                } else if (MyStriCmp(FlagName, L"csr_rotate")) {
+                   GlobalConfig.ShowTools[i - 1] = TAG_CSR_ROTATE;
+                } else if (MyStriCmp(FlagName, L"firmware")) {
+                   GlobalConfig.ShowTools[i - 1] = TAG_FIRMWARE;
+                } else if (MyStriCmp(FlagName, L"memtest86") || MyStriCmp(FlagName, L"memtest")) {
+                   GlobalConfig.ShowTools[i - 1] = TAG_MEMTEST;
+                } else if (MyStriCmp(FlagName, L"netboot")) {
+                   GlobalConfig.ShowTools[i - 1] = TAG_NETBOOT;
+                } else {
+                   Print(L" unknown showtools flag: '%s'\n", FlagName);
+                }
+            } // showtools options
+
+        } else if (MyStriCmp(TokenList[0], L"banner")) {
+           HandleString(TokenList, TokenCount, &(GlobalConfig.BannerFileName));
+
+        } else if (MyStriCmp(TokenList[0], L"banner_scale") && (TokenCount == 2)) {
+           if (MyStriCmp(TokenList[1], L"noscale")) {
+              GlobalConfig.BannerScale = BANNER_NOSCALE;
+           } else if (MyStriCmp(TokenList[1], L"fillscreen") || MyStriCmp(TokenList[1], L"fullscreen")) {
+              GlobalConfig.BannerScale = BANNER_FILLSCREEN;
+           } else {
+              Print(L" unknown banner_type flag: '%s'\n", TokenList[1]);
+           } // if/else
+
+        } else if (MyStriCmp(TokenList[0], L"small_icon_size") && (TokenCount == 2)) {
+           HandleInt(TokenList, TokenCount, &i);
+           if (i >= 32)
+              GlobalConfig.IconSizes[ICON_SIZE_SMALL] = i;
+
+        } else if (MyStriCmp(TokenList[0], L"big_icon_size") && (TokenCount == 2)) {
+           HandleInt(TokenList, TokenCount, &i);
+           if (i >= 32) {
+              GlobalConfig.IconSizes[ICON_SIZE_BIG] = i;
+              GlobalConfig.IconSizes[ICON_SIZE_BADGE] = i / 4;
+           }
+
+        } else if (MyStriCmp(TokenList[0], L"selection_small")) {
+           HandleString(TokenList, TokenCount, &(GlobalConfig.SelectionSmallFileName));
+
+        } else if (MyStriCmp(TokenList[0], L"selection_big")) {
+           HandleString(TokenList, TokenCount, &(GlobalConfig.SelectionBigFileName));
+
+        } else if (MyStriCmp(TokenList[0], L"default_selection")) {
+           if (TokenCount == 4) {
+              SetDefaultByTime(TokenList, &(GlobalConfig.DefaultSelection));
+           } else {
+              HandleString(TokenList, TokenCount, &(GlobalConfig.DefaultSelection));
+           }
+
+        } else if (MyStriCmp(TokenList[0], L"textonly")) {
+           GlobalConfig.TextOnly = HandleBoolean(TokenList, TokenCount);
+
+        } else if (MyStriCmp(TokenList[0], L"textmode")) {
+           HandleInt(TokenList, TokenCount, &(GlobalConfig.RequestedTextMode));
+
+        } else if (MyStriCmp(TokenList[0], L"resolution") && ((TokenCount == 2) || (TokenCount == 3))) {
+           GlobalConfig.RequestedScreenWidth = Atoi(TokenList[1]);
+           if (TokenCount == 3)
+              GlobalConfig.RequestedScreenHeight = Atoi(TokenList[2]);
+           else
+              GlobalConfig.RequestedScreenHeight = 0;
+
+        } else if (MyStriCmp(TokenList[0], L"screensaver")) {
+           HandleInt(TokenList, TokenCount, &(GlobalConfig.ScreensaverTime));
+
+        } else if (MyStriCmp(TokenList[0], L"use_graphics_for")) {
+           if ((TokenCount == 2) || ((TokenCount > 2) && (!MyStriCmp(TokenList[1], L"+"))))
+              GlobalConfig.GraphicsFor = 0;
+           for (i = 1; i < TokenCount; i++) {
+              if (MyStriCmp(TokenList[i], L"osx")) {
+                 GlobalConfig.GraphicsFor |= GRAPHICS_FOR_OSX;
+              } else if (MyStriCmp(TokenList[i], L"linux")) {
+                 GlobalConfig.GraphicsFor |= GRAPHICS_FOR_LINUX;
+              } else if (MyStriCmp(TokenList[i], L"elilo")) {
+                 GlobalConfig.GraphicsFor |= GRAPHICS_FOR_ELILO;
+              } else if (MyStriCmp(TokenList[i], L"grub")) {
+                 GlobalConfig.GraphicsFor |= GRAPHICS_FOR_GRUB;
+              } else if (MyStriCmp(TokenList[i], L"windows")) {
+                 GlobalConfig.GraphicsFor |= GRAPHICS_FOR_WINDOWS;
+              }
+           } // for (graphics_on tokens)
+
+        } else if (MyStriCmp(TokenList[0], L"font") && (TokenCount == 2)) {
+           egLoadFont(TokenList[1]);
+
+        } else if (MyStriCmp(TokenList[0], L"scan_all_linux_kernels")) {
+           GlobalConfig.ScanAllLinux = HandleBoolean(TokenList, TokenCount);
+
+        } else if (MyStriCmp(TokenList[0], L"fold_linux_kernels")) {
+            GlobalConfig.FoldLinuxKernels = HandleBoolean(TokenList, TokenCount);
+
+        } else if (MyStriCmp(TokenList[0], L"max_tags")) {
+           HandleInt(TokenList, TokenCount, &(GlobalConfig.MaxTags));
+
+        } else if (MyStriCmp(TokenList[0], L"enable_and_lock_vmx")) {
+           GlobalConfig.EnableAndLockVMX = HandleBoolean(TokenList, TokenCount);
+
+        } else if (MyStriCmp(TokenList[0], L"spoof_osx_version")) {
+            HandleString(TokenList, TokenCount, &(GlobalConfig.SpoofOSXVersion));
+
+        } else if (MyStriCmp(TokenList[0], L"csr_values")) {
+            HandleHexes(TokenList, TokenCount, CSR_MAX_LEGAL_VALUE, &(GlobalConfig.CsrValues));
+
+        } else if (MyStriCmp(TokenList[0], L"include") && (TokenCount == 2) && MyStriCmp(FileName, GlobalConfig.ConfigFilename)) {
+           if (!MyStriCmp(TokenList[1], FileName)) {
+              ReadConfig(TokenList[1]);
+           }
+
+        }
+
+        FreeTokenLine(&TokenList, &TokenCount);
+    }
+    if ((GlobalConfig.DontScanFiles) && (GlobalConfig.WindowsRecoveryFiles))
+       MergeStrings(&(GlobalConfig.DontScanFiles), GlobalConfig.WindowsRecoveryFiles, L',');
+    MyFreePool(File.Buffer);
+
+    if (!FileExists(SelfDir, L"icons") && !FileExists(SelfDir, GlobalConfig.IconsDir)) {
+       Print(L"Icons directory doesn't exist; setting textonly = TRUE!\n");
+       GlobalConfig.TextOnly = TRUE;
+    }
+} /* VOID ReadConfig() */
+
+// Finds a volume with the specified Identifier (a filesystem label, a
+// partition name, a partition GUID, or a number followed by a colon). If
+// found, sets *Volume to point to that volume. If not, leaves it unchanged.
+// Returns TRUE if a match was found, FALSE if not.
+static BOOLEAN FindVolume(REFIT_VOLUME **Volume, CHAR16 *Identifier) {
+   UINTN     i = 0, CountedVolumes = 0, Length;
+   INTN      Number = -1;
+   BOOLEAN   Found = FALSE, IdIsGuid = FALSE;
+   EFI_GUID  VolGuid, NullGuid = NULL_GUID_VALUE;
+
+   VolGuid = StringAsGuid(Identifier);
+   Length = StrLen(Identifier);
+   if ((Length >= 2) && (Identifier[Length - 1] == L':') &&
+       (Identifier[0] >= L'0') && (Identifier[0] <= L'9')) {
+      Number = (INTN) Atoi(Identifier);
+   } else if (IsGuid(Identifier)) {
+      IdIsGuid = TRUE;
+   }
+   while ((i < VolumesCount) && (!Found)) {
+      if (Number >= 0) { // User specified a volume by number
+         if (Volumes[i]->IsReadable) {
+            if (CountedVolumes == Number) {
+               *Volume = Volumes[i];
+               Found = TRUE;
+            }
+            CountedVolumes++;
+         } // if
+      } else { // User specified a volume by label or GUID
+         if (MyStriCmp(Identifier, Volumes[i]->VolName) || MyStriCmp(Identifier, Volumes[i]->PartName)) {
+            *Volume = Volumes[i];
+            Found = TRUE;
+         } // if
+         if (IdIsGuid && !Found) {
+            if (GuidsAreEqual(&VolGuid, &(Volumes[i]->PartGuid)) && !GuidsAreEqual(&NullGuid, &(Volumes[i]->PartGuid))) {
+               *Volume = Volumes[i];
+               Found = TRUE;
+            } // if
+         } // if
+      } // if/else
+      i++;
+   } // while()
+   return (Found);
+} // static VOID FindVolume()
+
+static VOID AddSubmenu(LOADER_ENTRY *Entry, REFIT_FILE *File, REFIT_VOLUME *Volume, CHAR16 *Title) {
+   REFIT_MENU_SCREEN  *SubScreen;
+   LOADER_ENTRY       *SubEntry;
+   UINTN              TokenCount;
+   CHAR16             **TokenList;
+
+   SubScreen = InitializeSubScreen(Entry);
+
+   // Set defaults for the new entry; will be modified based on lines read from the config. file....
+   SubEntry = InitializeLoaderEntry(Entry);
+
+   if ((SubEntry == NULL) || (SubScreen == NULL))
+      return;
+   SubEntry->me.Title        = StrDuplicate(Title);
+
+   while (((TokenCount = ReadTokenLine(File, &TokenList)) > 0) && (StrCmp(TokenList[0], L"}") != 0)) {
+
+      if (MyStriCmp(TokenList[0], L"loader") && (TokenCount > 1)) { // set the boot loader filename
+         MyFreePool(SubEntry->LoaderPath);
+         SubEntry->LoaderPath = StrDuplicate(TokenList[1]);
+         SubEntry->DevicePath = FileDevicePath(Volume->DeviceHandle, SubEntry->LoaderPath);
+
+      } else if (MyStriCmp(TokenList[0], L"volume") && (TokenCount > 1)) {
+         if (FindVolume(&Volume, TokenList[1])) {
+            if ((Volume != NULL) && (Volume->IsReadable) && (Volume->RootDir)) {
+               MyFreePool(SubEntry->me.Title);
+               SubEntry->me.Title        = AllocateZeroPool(256 * sizeof(CHAR16));
+               SPrint(SubEntry->me.Title, 255, L"Boot %s from %s", (Title != NULL) ? Title : L"Unknown", Volume->VolName);
+               SubEntry->me.BadgeImage   = Volume->VolBadgeImage;
+               SubEntry->VolName         = Volume->VolName;
+            } // if volume is readable
+         } // if match found
+
+      } else if (MyStriCmp(TokenList[0], L"initrd")) {
+         MyFreePool(SubEntry->InitrdPath);
+         SubEntry->InitrdPath = NULL;
+         if (TokenCount > 1) {
+            SubEntry->InitrdPath = StrDuplicate(TokenList[1]);
+         }
+
+      } else if (MyStriCmp(TokenList[0], L"options")) {
+         MyFreePool(SubEntry->LoadOptions);
+         SubEntry->LoadOptions = NULL;
+         if (TokenCount > 1) {
+            SubEntry->LoadOptions = StrDuplicate(TokenList[1]);
+         } // if/else
+
+      } else if (MyStriCmp(TokenList[0], L"add_options") && (TokenCount > 1)) {
+         MergeStrings(&SubEntry->LoadOptions, TokenList[1], L' ');
+
+      } else if (MyStriCmp(TokenList[0], L"graphics") && (TokenCount > 1)) {
+         SubEntry->UseGraphicsMode = MyStriCmp(TokenList[1], L"on");
+
+      } else if (MyStriCmp(TokenList[0], L"disabled")) {
+         SubEntry->Enabled = FALSE;
+      } // ief/elseif
+
+      FreeTokenLine(&TokenList, &TokenCount);
+   } // while()
+
+   if (SubEntry->InitrdPath != NULL) {
+      MergeStrings(&SubEntry->LoadOptions, L"initrd=", L' ');
+      MergeStrings(&SubEntry->LoadOptions, SubEntry->InitrdPath, 0);
+      MyFreePool(SubEntry->InitrdPath);
+      SubEntry->InitrdPath = NULL;
+   } // if
+   if (SubEntry->Enabled == TRUE) {
+      AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry);
+   }
+   Entry->me.SubScreen = SubScreen;
+} // VOID AddSubmenu()
+
+// Adds the options from a SINGLE refind.conf stanza to a new loader entry and returns
+// that entry. The calling function is then responsible for adding the entry to the
+// list of entries.
+static LOADER_ENTRY * AddStanzaEntries(REFIT_FILE *File, REFIT_VOLUME *Volume, CHAR16 *Title) {
+   CHAR16       **TokenList;
+   UINTN        TokenCount;
+   LOADER_ENTRY *Entry;
+   BOOLEAN      DefaultsSet = FALSE, AddedSubmenu = FALSE;
+   REFIT_VOLUME *CurrentVolume = Volume;
+
+   // prepare the menu entry
+   Entry = InitializeLoaderEntry(NULL);
+   if (Entry == NULL)
+      return NULL;
+
+   Entry->Title           = StrDuplicate(Title);
+   Entry->me.Title        = AllocateZeroPool(256 * sizeof(CHAR16));
+   SPrint(Entry->me.Title, 255, L"Boot %s from %s", (Title != NULL) ? Title : L"Unknown", CurrentVolume->VolName);
+   Entry->me.Row          = 0;
+   Entry->me.BadgeImage   = CurrentVolume->VolBadgeImage;
+   Entry->VolName         = CurrentVolume->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) && (StrCmp(TokenList[0], L"}") != 0)) {
+      if (MyStriCmp(TokenList[0], L"loader") && (TokenCount > 1)) { // set the boot loader filename
+         Entry->LoaderPath = StrDuplicate(TokenList[1]);
+         Entry->DevicePath = FileDevicePath(CurrentVolume->DeviceHandle, Entry->LoaderPath);
+         SetLoaderDefaults(Entry, TokenList[1], CurrentVolume);
+         MyFreePool(Entry->LoadOptions);
+         Entry->LoadOptions = NULL; // Discard default options, if any
+         DefaultsSet = TRUE;
+
+      } else if (MyStriCmp(TokenList[0], L"volume") && (TokenCount > 1)) {
+         if (FindVolume(&CurrentVolume, TokenList[1])) {
+            if ((CurrentVolume != NULL) && (CurrentVolume->IsReadable) && (CurrentVolume->RootDir)) {
+               MyFreePool(Entry->me.Title);
+               Entry->me.Title        = AllocateZeroPool(256 * sizeof(CHAR16));
+               SPrint(Entry->me.Title, 255, L"Boot %s from %s", (Title != NULL) ? Title : L"Unknown", CurrentVolume->VolName);
+               Entry->me.BadgeImage   = CurrentVolume->VolBadgeImage;
+               Entry->VolName         = CurrentVolume->VolName;
+            } // if volume is readable
+         } // if match found
+
+      } else if (MyStriCmp(TokenList[0], L"icon") && (TokenCount > 1)) {
+         MyFreePool(Entry->me.Image);
+         Entry->me.Image = egLoadIcon(CurrentVolume->RootDir, TokenList[1], GlobalConfig.IconSizes[ICON_SIZE_BIG]);
+         if (Entry->me.Image == NULL) {
+            Entry->me.Image = DummyImage(GlobalConfig.IconSizes[ICON_SIZE_BIG]);
+         }
+
+      } else if (MyStriCmp(TokenList[0], L"initrd") && (TokenCount > 1)) {
+         MyFreePool(Entry->InitrdPath);
+         Entry->InitrdPath = StrDuplicate(TokenList[1]);
+
+      } else if (MyStriCmp(TokenList[0], L"options") && (TokenCount > 1)) {
+         MyFreePool(Entry->LoadOptions);
+         Entry->LoadOptions = StrDuplicate(TokenList[1]);
+
+      } else if (MyStriCmp(TokenList[0], L"ostype") && (TokenCount > 1)) {
+         if (TokenCount > 1) {
+            Entry->OSType = TokenList[1][0];
+         }
+
+      } else if (MyStriCmp(TokenList[0], L"graphics") && (TokenCount > 1)) {
+         Entry->UseGraphicsMode = MyStriCmp(TokenList[1], L"on");
+
+      } else if (MyStriCmp(TokenList[0], L"disabled")) {
+         Entry->Enabled = FALSE;
+
+      } else if (MyStriCmp(TokenList[0], L"submenuentry") && (TokenCount > 1)) {
+         AddSubmenu(Entry, File, CurrentVolume, TokenList[1]);
+         AddedSubmenu = TRUE;
+
+      } // set options to pass to the loader program
+      FreeTokenLine(&TokenList, &TokenCount);
+   } // while()
+
+   if (AddedSubmenu)
+       AddMenuEntry(Entry->me.SubScreen, &MenuEntryReturn);
+
+   if (Entry->InitrdPath) {
+      MergeStrings(&Entry->LoadOptions, L"initrd=", L' ');
+      MergeStrings(&Entry->LoadOptions, Entry->InitrdPath, 0);
+      MyFreePool(Entry->InitrdPath);
+      Entry->InitrdPath = NULL;
+   } // if
+
+   if (!DefaultsSet)
+      SetLoaderDefaults(Entry, L"\\EFI\\BOOT\\nemo.efi", CurrentVolume); // user included no "loader" line; use bogus one
+
+   return(Entry);
+} // static VOID AddStanzaEntries()
+
+// Read the user-configured menu entries from refind.conf and add or delete
+// entries based on the contents of that file....
+VOID ScanUserConfigured(CHAR16 *FileName)
+{
+   EFI_STATUS        Status;
+   REFIT_FILE        File;
+   REFIT_VOLUME      *Volume;
+   CHAR16            **TokenList;
+   CHAR16            *Title = NULL;
+   UINTN             TokenCount, size;
+   LOADER_ENTRY      *Entry;
+
+   if (FileExists(SelfDir, FileName)) {
+      Status = ReadFile(SelfDir, FileName, &File, &size);
+      if (EFI_ERROR(Status))
+         return;
+
+      Volume = SelfVolume;
+
+      while ((TokenCount = ReadTokenLine(&File, &TokenList)) > 0) {
+         if (MyStriCmp(TokenList[0], L"menuentry") && (TokenCount > 1)) {
+            Title = StrDuplicate(TokenList[1]);
+            Entry = AddStanzaEntries(&File, Volume, TokenList[1]);
+            if (Entry->Enabled) {
+               if (Entry->me.SubScreen == NULL)
+                  GenerateSubScreen(Entry, Volume, TRUE);
+               AddPreparedLoaderEntry(Entry);
+            } else {
+               MyFreePool(Entry);
+            } // if/else
+            MyFreePool(Title);
+
+         } else if (MyStriCmp(TokenList[0], L"include") && (TokenCount == 2) &&
+                    MyStriCmp(FileName, GlobalConfig.ConfigFilename)) {
+            if (!MyStriCmp(TokenList[1], FileName)) {
+               ScanUserConfigured(TokenList[1]);
+            }
+
+         } // if/else if...
+         FreeTokenLine(&TokenList, &TokenCount);
+      } // while()
+   } // if()
+} // VOID ScanUserConfigured()
+
+// Create an options file based on /etc/fstab. The resulting file has two options
+// lines, one of which boots the system with "ro root={rootfs}" and the other of
+// which boots the system with "ro root={rootfs} single", where "{rootfs}" is the
+// filesystem identifier associated with the "/" line in /etc/fstab.
+static REFIT_FILE * GenerateOptionsFromEtcFstab(REFIT_VOLUME *Volume) {
+   UINTN        TokenCount, i;
+   REFIT_FILE   *Options = NULL, *Fstab = NULL;
+   EFI_STATUS   Status;
+   CHAR16       **TokenList, *Line, Root[100];
+
+   if (FileExists(Volume->RootDir, L"\\etc\\fstab")) {
+      Options = AllocateZeroPool(sizeof(REFIT_FILE));
+      Fstab = AllocateZeroPool(sizeof(REFIT_FILE));
+      Status = ReadFile(Volume->RootDir, L"\\etc\\fstab", Fstab, &i);
+      if (CheckError(Status, L"while reading /etc/fstab")) {
+         if (Options != NULL)
+            FreePool(Options);
+         if (Fstab != NULL)
+            FreePool(Fstab);
+         Options = NULL;
+         Fstab = NULL;
+      } else { // File read; locate root fs and create entries
+         Options->Encoding = ENCODING_UTF16_LE;
+         while ((TokenCount = ReadTokenLine(Fstab, &TokenList)) > 0) {
+            if (TokenCount > 2) {
+               Root[0] = '\0';
+               if (StrCmp(TokenList[1], L"\\") == 0) {
+                  SPrint(Root, 99, L"%s", TokenList[0]);
+               } else if (StrCmp(TokenList[2], L"\\") == 0) {
+                  SPrint(Root, 99, L"%s=%s", TokenList[0], TokenList[1]);
+               } // if/elseif/elseif
+               if (Root[0] != L'\0') {
+                  for (i = 0; i < StrLen(Root); i++)
+                     if (Root[i] == '\\')
+                        Root[i] = '/';
+                  Line = PoolPrint(L"\"Boot with normal options\"    \"ro root=%s\"\n", Root);
+                  MergeStrings((CHAR16 **) &(Options->Buffer), Line, 0);
+                  MyFreePool(Line);
+                  Line = PoolPrint(L"\"Boot into single-user mode\"  \"ro root=%s single\"\n", Root);
+                  MergeStrings((CHAR16**) &(Options->Buffer), Line, 0);
+                  Options->BufferSize = StrLen((CHAR16*) Options->Buffer) * sizeof(CHAR16);
+               } // if
+            } // if
+            FreeTokenLine(&TokenList, &TokenCount);
+         } // while
+
+         if (Options->Buffer) {
+            Options->Current8Ptr  = (CHAR8 *)Options->Buffer;
+            Options->End8Ptr      = Options->Current8Ptr + Options->BufferSize;
+            Options->Current16Ptr = (CHAR16 *)Options->Buffer;
+            Options->End16Ptr     = Options->Current16Ptr + (Options->BufferSize >> 1);
+         } else {
+             MyFreePool(Options);
+             Options = NULL;
+         }
+
+         MyFreePool(Fstab->Buffer);
+         MyFreePool(Fstab);
+      } // if/else file read error
+   } // if /etc/fstab exists
+   return Options;
+} // GenerateOptionsFromEtcFstab()
+
+// Create options from partition type codes. Specifically, if the earlier
+// partition scan found a partition with a type code corresponding to a root
+// filesystem according to the Freedesktop.org Discoverable Partitions Spec
+// (http://www.freedesktop.org/wiki/Specifications/DiscoverablePartitionsSpec/),
+// this function returns an appropriate file with two lines, one with
+// "ro root=/dev/disk/by-partuuid/{GUID}" and the other with that plus "single".
+// Note that this function returns the LAST partition found with the
+// appropriate type code, so this will work poorly on dual-boot systems or
+// if the type code is set incorrectly.
+static REFIT_FILE * GenerateOptionsFromPartTypes(VOID) {
+    REFIT_FILE   *Options = NULL;
+    CHAR16       *Line, *GuidString, *WriteStatus;
+
+    if (GlobalConfig.DiscoveredRoot) {
+        Options = AllocateZeroPool(sizeof(REFIT_FILE));
+        if (Options) {
+            Options->Encoding = ENCODING_UTF16_LE;
+            GuidString = GuidAsString(&(GlobalConfig.DiscoveredRoot->PartGuid));
+            WriteStatus = GlobalConfig.DiscoveredRoot->IsMarkedReadOnly ? L"ro" : L"rw";
+            ToLower(GuidString);
+            if (GuidString) {
+                Line = PoolPrint(L"\"Boot with normal options\"    \"%s root=/dev/disk/by-partuuid/%s\"\n", WriteStatus, GuidString);
+                MergeStrings((CHAR16 **) &(Options->Buffer), Line, 0);
+                MyFreePool(Line);
+                Line = PoolPrint(L"\"Boot into single-user mode\"  \"%s root=/dev/disk/by-partuuid/%s single\"\n", WriteStatus, GuidString);
+                MergeStrings((CHAR16**) &(Options->Buffer), Line, 0);
+                MyFreePool(Line);
+                MyFreePool(GuidString);
+            } // if (GuidString)
+            Options->BufferSize = StrLen((CHAR16*) Options->Buffer) * sizeof(CHAR16);
+
+            Options->Current8Ptr  = (CHAR8 *)Options->Buffer;
+            Options->End8Ptr      = Options->Current8Ptr + Options->BufferSize;
+            Options->Current16Ptr = (CHAR16 *)Options->Buffer;
+            Options->End16Ptr     = Options->Current16Ptr + (Options->BufferSize >> 1);
+        } // if (Options allocated OK)
+    } // if (partition has root GUID)
+    return Options;
+} // REFIT_FILE * GenerateOptionsFromPartTypes()
+
+// Read a Linux kernel options file for a Linux boot loader into memory. The LoaderPath
+// and Volume variables identify the location of the options file, but not its name --
+// you pass this function the filename of the Linux kernel, initial RAM disk, or other
+// file in the target directory, and this function finds the file with a name in the
+// comma-delimited list of names specified by LINUX_OPTIONS_FILENAMES within that
+// directory and loads it. This function tries multiple files because I originally
+// used the filename linux.conf, but close on the heels of that decision, the Linux
+// kernel developers decided to use that name for a similar purpose, but with a
+// different file format. Thus, I'm migrating rEFInd to use the name refind_linux.conf,
+// but I want a migration period in which both names are used.
+// If a rEFInd options file can't be found, try to generate minimal options from
+// /etc/fstab on the same volume as the kernel. This typically works only if the
+// kernel is being read from the Linux root filesystem.
+//
+// The return value is a pointer to the REFIT_FILE handle for the file, or NULL if
+// it wasn't found.
+REFIT_FILE * ReadLinuxOptionsFile(IN CHAR16 *LoaderPath, IN REFIT_VOLUME *Volume) {
+   CHAR16       *OptionsFilename, *FullFilename;
+   BOOLEAN      GoOn = TRUE, FileFound = FALSE;
+   UINTN        i = 0, size;
+   REFIT_FILE   *File = NULL;
+   EFI_STATUS   Status;
+
+   do {
+      OptionsFilename = FindCommaDelimited(LINUX_OPTIONS_FILENAMES, i++);
+      FullFilename = FindPath(LoaderPath);
+      if ((OptionsFilename != NULL) && (FullFilename != NULL)) {
+         MergeStrings(&FullFilename, OptionsFilename, '\\');
+         if (FileExists(Volume->RootDir, FullFilename)) {
+            File = AllocateZeroPool(sizeof(REFIT_FILE));
+            Status = ReadFile(Volume->RootDir, FullFilename, File, &size);
+            if (CheckError(Status, L"while loading the Linux options file")) {
+               if (File != NULL)
+                  FreePool(File);
+               File = NULL;
+            } else {
+               GoOn = FALSE;
+               FileFound = TRUE;
+            } // if/else error
+         } // if file exists
+      } else { // a filename string is NULL
+         GoOn = FALSE;
+      } // if/else
+      MyFreePool(OptionsFilename);
+      MyFreePool(FullFilename);
+      OptionsFilename = FullFilename = NULL;
+   } while (GoOn);
+   if (!FileFound) {
+      // No refind_linux.conf file; look for /etc/fstab and try to pull values from there....
+      File = GenerateOptionsFromEtcFstab(Volume);
+      // If still no joy, try to use Freedesktop.org Discoverable Partitions Spec....
+      if (!File)
+         File = GenerateOptionsFromPartTypes();
+   } // if
+   return (File);
+} // static REFIT_FILE * ReadLinuxOptionsFile()
+
+// Retrieve a single line of options from a Linux kernel options file
+CHAR16 * GetFirstOptionsFromFile(IN CHAR16 *LoaderPath, IN REFIT_VOLUME *Volume) {
+   UINTN        TokenCount;
+   CHAR16       *Options = NULL;
+   CHAR16       **TokenList;
+   REFIT_FILE   *File;
+
+   File = ReadLinuxOptionsFile(LoaderPath, Volume);
+   if (File != NULL) {
+      TokenCount = ReadTokenLine(File, &TokenList);
+      if (TokenCount > 1)
+         Options = StrDuplicate(TokenList[1]);
+      FreeTokenLine(&TokenList, &TokenCount);
+      FreePool(File);
+   } // if
+   return Options;
+} // static CHAR16 * GetOptionsFile()
+
diff --git a/refind/config.h b/refind/config.h
new file mode 100644 (file)
index 0000000..b69b0a3
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * refit/config.h
+ * General header file
+ *
+ * Copyright (c) 2006-2009 Christoph Pfisterer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Modifications copyright (c) 2012-2015 Roderick W. Smith
+ * 
+ * Modifications distributed under the terms of the GNU General Public
+ * License (GPL) version 3 (GPLv3), a copy of which must be distributed
+ * with this source code or binaries made from it.
+ * 
+ */
+
+#ifndef __CONFIG_H_
+#define __CONFIG_H_
+
+#ifdef __MAKEWITH_GNUEFI
+#include "efi.h"
+#else
+#include "../include/tiano_includes.h"
+#endif
+#include "global.h"
+
+
+//
+// config module
+//
+
+typedef struct {
+    UINT8   *Buffer;
+    UINTN   BufferSize;
+    UINTN   Encoding;
+    CHAR8   *Current8Ptr;
+    CHAR8   *End8Ptr;
+    CHAR16  *Current16Ptr;
+    CHAR16  *End16Ptr;
+} REFIT_FILE;
+
+#define CONFIG_FILE_NAME         L"refind.conf"
+// Note: Below is combined with MOK_NAMES to make default
+#define DONT_SCAN_FILES L"shim.efi,shim-fedora.efi,shimx64.efi,PreLoader.efi,TextMode.efi,ebounce.efi,GraphicsConsole.efi,bootmgr.efi"
+#define DONT_SCAN_VOLUMES L"LRS_ESP"
+#define ALSO_SCAN_DIRS L"boot,@/boot"
+
+EFI_STATUS ReadFile(IN EFI_FILE_HANDLE BaseDir, CHAR16 *FileName, REFIT_FILE *File, UINTN *size);
+VOID ReadConfig(CHAR16 *FileName);
+VOID ScanUserConfigured(CHAR16 *FileName);
+UINTN ReadTokenLine(IN REFIT_FILE *File, OUT CHAR16 ***TokenList);
+VOID FreeTokenLine(IN OUT CHAR16 ***TokenList, IN OUT UINTN *TokenCount);
+REFIT_FILE * ReadLinuxOptionsFile(IN CHAR16 *LoaderPath, IN REFIT_VOLUME *Volume);
+CHAR16 * GetFirstOptionsFromFile(IN CHAR16 *LoaderPath, IN REFIT_VOLUME *Volume);
+
+#endif
+
+/* EOF */
diff --git a/refind/crc32.c b/refind/crc32.c
new file mode 100644 (file)
index 0000000..5beccc0
--- /dev/null
@@ -0,0 +1,106 @@
+/*-\r
+ *  COPYRIGHT (C) 1986 Gary S. Brown.  You may use this program, or\r
+ *  code or tables extracted from it, as desired without restriction.\r
+ *\r
+ *  First, the polynomial itself and its table of feedback terms.  The\r
+ *  polynomial is\r
+ *  X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0\r
+ *\r
+ *  Note that we take it "backwards" and put the highest-order term in\r
+ *  the lowest-order bit.  The X^32 term is "implied"; the LSB is the\r
+ *  X^31 term, etc.  The X^0 term (usually shown as "+1") results in\r
+ *  the MSB being 1\r
+ *\r
+ *  Note that the usual hardware shift register implementation, which\r
+ *  is what we're using (we're merely optimizing it by doing eight-bit\r
+ *  chunks at a time) shifts bits into the lowest-order term.  In our\r
+ *  implementation, that means shifting towards the right.  Why do we\r
+ *  do it this way?  Because the calculated CRC must be transmitted in\r
+ *  order from highest-order term to lowest-order term.  UARTs transmit\r
+ *  characters in order from LSB to MSB.  By storing the CRC this way\r
+ *  we hand it to the UART in the order low-byte to high-byte; the UART\r
+ *  sends each low-bit to hight-bit; and the result is transmission bit\r
+ *  by bit from highest- to lowest-order term without requiring any bit\r
+ *  shuffling on our part.  Reception works similarly\r
+ *\r
+ *  The feedback terms table consists of 256, 32-bit entries.  Notes\r
+ *\r
+ *      The table can be generated at runtime if desired; code to do so\r
+ *      is shown later.  It might not be obvious, but the feedback\r
+ *      terms simply represent the results of eight shift/xor opera\r
+ *      tions for all combinations of data and CRC register values\r
+ *\r
+ *      The values must be right-shifted by eight bits by the "updcrc\r
+ *      logic; the shift must be unsigned (bring in zeroes).  On some\r
+ *      hardware you could probably optimize the shift in assembler by\r
+ *      using byte-swap instructions\r
+ *      polynomial $edb88320\r
+ *\r
+ *\r
+ * CRC32 code derived from work by Gary S. Brown.\r
+ */\r
+/*\r
+ * Modified slightly for use on EFI by Rod Smith\r
+ */\r
+\r
+#include "crc32.h"\r
+\r
+static UINT32 crc32_tab[] = {\r
+   0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,\r
+   0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,\r
+   0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,\r
+   0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,\r
+   0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,\r
+   0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,\r
+   0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,\r
+   0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,\r
+   0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,\r
+   0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,\r
+   0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,\r
+   0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,\r
+   0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,\r
+   0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,\r
+   0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,\r
+   0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,\r
+   0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,\r
+   0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,\r
+   0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,\r
+   0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,\r
+   0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,\r
+   0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,\r
+   0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,\r
+   0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,\r
+   0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,\r
+   0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,\r
+   0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,\r
+   0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,\r
+   0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,\r
+   0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,\r
+   0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,\r
+   0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,\r
+   0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,\r
+   0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,\r
+   0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,\r
+   0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,\r
+   0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,\r
+   0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,\r
+   0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,\r
+   0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,\r
+   0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,\r
+   0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,\r
+   0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d\r
+};\r
+\r
+UINT32 crc32(UINT32 crc, const VOID *buf, UINTN size)\r
+{\r
+   const UINT8 *p;\r
+\r
+   p = buf;\r
+   crc = crc ^ ~0U;\r
+\r
+   while (size--)\r
+      crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);\r
+\r
+   return crc ^ ~0U;\r
+}\r
+\r
diff --git a/refind/crc32.h b/refind/crc32.h
new file mode 100644 (file)
index 0000000..f7c7639
--- /dev/null
@@ -0,0 +1,58 @@
+/*-\r
+ *  COPYRIGHT (C) 1986 Gary S. Brown.  You may use this program, or\r
+ *  code or tables extracted from it, as desired without restriction.\r
+ *\r
+ *  First, the polynomial itself and its table of feedback terms.  The\r
+ *  polynomial is\r
+ *  X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0\r
+ *\r
+ *  Note that we take it "backwards" and put the highest-order term in\r
+ *  the lowest-order bit.  The X^32 term is "implied"; the LSB is the\r
+ *  X^31 term, etc.  The X^0 term (usually shown as "+1") results in\r
+ *  the MSB being 1\r
+ *\r
+ *  Note that the usual hardware shift register implementation, which\r
+ *  is what we're using (we're merely optimizing it by doing eight-bit\r
+ *  chunks at a time) shifts bits into the lowest-order term.  In our\r
+ *  implementation, that means shifting towards the right.  Why do we\r
+ *  do it this way?  Because the calculated CRC must be transmitted in\r
+ *  order from highest-order term to lowest-order term.  UARTs transmit\r
+ *  characters in order from LSB to MSB.  By storing the CRC this way\r
+ *  we hand it to the UART in the order low-byte to high-byte; the UART\r
+ *  sends each low-bit to hight-bit; and the result is transmission bit\r
+ *  by bit from highest- to lowest-order term without requiring any bit\r
+ *  shuffling on our part.  Reception works similarly\r
+ *\r
+ *  The feedback terms table consists of 256, 32-bit entries.  Notes\r
+ *\r
+ *      The table can be generated at runtime if desired; code to do so\r
+ *      is shown later.  It might not be obvious, but the feedback\r
+ *      terms simply represent the results of eight shift/xor opera\r
+ *      tions for all combinations of data and CRC register values\r
+ *\r
+ *      The values must be right-shifted by eight bits by the "updcrc\r
+ *      logic; the shift must be unsigned (bring in zeroes).  On some\r
+ *      hardware you could probably optimize the shift in assembler by\r
+ *      using byte-swap instructions\r
+ *      polynomial $edb88320\r
+ *\r
+ *\r
+ * CRC32 code derived from work by Gary S. Brown.\r
+ */\r
+/*\r
+ * Modified slightly for use on EFI by Rod Smith\r
+ */\r
+\r
+#ifndef __CRC32_H_\r
+#define __CRC32_H_\r
+\r
+#ifdef __MAKEWITH_GNUEFI\r
+#include "efi.h"\r
+#include "efilib.h"\r
+#else\r
+#include "../include/tiano_includes.h"\r
+#endif\r
+\r
+UINT32 crc32(UINT32 crc, const VOID *buf, UINTN size);\r
+\r
+#endif
\ No newline at end of file
diff --git a/refind/driver_support.c b/refind/driver_support.c
new file mode 100644 (file)
index 0000000..a547d65
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ * File to implement LibScanHandleDatabase(), which is used by rEFInd's
+ * driver-loading code (inherited from rEFIt), but which has not been
+ * implemented in GNU-EFI and seems to have been dropped from current
+ * versions of the Tianocore library. This function was taken from a git
+ * site with EFI code, but some of the constants it uses were taken from
+ * a more recent EDK2 package (see below for details). The original files
+ * bore the following copyright notice:
+ *
+ * Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+ * This program and the accompanying materials are licensed and made available under
+ * the terms and conditions of the BSD License that accompanies this distribution.
+ * The full text of the license may be found at
+ * http://opensource.org/licenses/bsd-license.php.
+ *
+ * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ *
+ */
+
+#include "driver_support.h"
+#include "lib.h"
+#include "../include/refit_call_wrapper.h"
+
+#ifdef __MAKEWITH_GNUEFI
+// Following "global" constants are from EDK2's AutoGen.c....
+EFI_GUID gEfiLoadedImageProtocolGuid = { 0x5B1B31A1, 0x9562, 0x11D2, { 0x8E, 0x3F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
+EFI_GUID gEfiDriverBindingProtocolGuid = { 0x18A031AB, 0xB443, 0x4D1A, { 0xA5, 0xC0, 0x0C, 0x09, 0x26, 0x1E, 0x9F, 0x71 }};
+EFI_GUID gEfiDriverConfiguration2ProtocolGuid = { 0xBFD7DC1D, 0x24F1, 0x40D9, { 0x82, 0xE7, 0x2E, 0x09, 0xBB, 0x6B, 0x4E, 0xBE }};
+EFI_GUID gEfiDriverConfigurationProtocolGuid = { 0x107A772B, 0xD5E1, 0x11D4, { 0x9A, 0x46, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }};
+EFI_GUID gEfiDriverDiagnosticsProtocolGuid = { 0x0784924F, 0xE296, 0x11D4, { 0x9A, 0x49, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }};
+EFI_GUID gEfiDriverDiagnostics2ProtocolGuid = { 0x4D330321, 0x025F, 0x4AAC, { 0x90, 0xD8, 0x5E, 0xD9, 0x00, 0x17, 0x3B, 0x63 }};
+EFI_GUID gEfiComponentNameProtocolGuid = { 0x107A772C, 0xD5E1, 0x11D4, { 0x9A, 0x46, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }};
+EFI_GUID gEfiComponentName2ProtocolGuid = { 0x6A7A5CFF, 0xE8D9, 0x4F70, { 0xBA, 0xDA, 0x75, 0xAB, 0x30, 0x25, 0xCE, 0x14 }};
+EFI_GUID gEfiDevicePathProtocolGuid = { 0x09576E91, 0x6D3F, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
+#endif
+
+// Below is from http://git.etherboot.org/?p=mirror/efi/shell/.git;a=commitdiff;h=b1b0c63423cac54dc964c2930e04aebb46a946ec;
+// Seems to have been replaced by ParseHandleDatabaseByRelationshipWithType(), but the latter isn't working for me....
+EFI_STATUS
+LibScanHandleDatabase (
+  EFI_HANDLE  DriverBindingHandle, OPTIONAL
+  UINT32      *DriverBindingHandleIndex, OPTIONAL
+  EFI_HANDLE  ControllerHandle, OPTIONAL
+  UINT32      *ControllerHandleIndex, OPTIONAL
+  UINTN       *HandleCount,
+  EFI_HANDLE  **HandleBuffer,
+  UINT32      **HandleType
+  )
+
+{
+  EFI_STATUS                          Status;
+  UINTN                               HandleIndex;
+  EFI_GUID                            **ProtocolGuidArray;
+  UINTN                               ArrayCount;
+  UINTN                               ProtocolIndex;
+  EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfo;
+  UINTN                               OpenInfoCount;
+  UINTN                               OpenInfoIndex;
+  UINTN                               ChildIndex;
+  BOOLEAN                             DriverBindingHandleIndexValid;
+//  BOOLEAN                             ControllerHandleIndexValid;
+
+  DriverBindingHandleIndexValid = FALSE;
+  if (DriverBindingHandleIndex != NULL) {
+    *DriverBindingHandleIndex = 0xffffffff;
+  }
+
+//  ControllerHandleIndexValid = FALSE;
+  if (ControllerHandleIndex != NULL) {
+    *ControllerHandleIndex = 0xffffffff;
+  }
+
+  *HandleCount  = 0;
+  *HandleBuffer = NULL;
+  *HandleType   = NULL;
+
+  //
+  // Retrieve the list of all handles from the handle database
+  //
+
+  Status = refit_call5_wrapper(BS->LocateHandleBuffer,
+     AllHandles,
+     NULL,
+     NULL,
+     HandleCount,
+     HandleBuffer
+  );
+  if (EFI_ERROR (Status)) {
+    goto Error;
+  }
+
+  *HandleType = AllocatePool (*HandleCount * sizeof (UINT32));
+  if (*HandleType == NULL) {
+    goto Error;
+  }
+
+  for (HandleIndex = 0; HandleIndex < *HandleCount; HandleIndex++) {
+    //
+    // Assume that the handle type is unknown
+    //
+    (*HandleType)[HandleIndex] = EFI_HANDLE_TYPE_UNKNOWN;
+
+    if (DriverBindingHandle != NULL &&
+        DriverBindingHandleIndex != NULL &&
+        (*HandleBuffer)[HandleIndex] == DriverBindingHandle
+        ) {
+      *DriverBindingHandleIndex     = (UINT32) HandleIndex;
+      DriverBindingHandleIndexValid = TRUE;
+    }
+
+    if (ControllerHandle != NULL && ControllerHandleIndex != NULL && (*HandleBuffer)[HandleIndex] == ControllerHandle) {
+      *ControllerHandleIndex      = (UINT32) HandleIndex;
+//      ControllerHandleIndexValid  = TRUE;
+    }
+
+  }
+
+  for (HandleIndex = 0; HandleIndex < *HandleCount; HandleIndex++) {
+    //
+    // Retrieve the list of all the protocols on each handle
+    //
+
+    Status = refit_call3_wrapper(BS->ProtocolsPerHandle,
+                  (*HandleBuffer)[HandleIndex],
+                  &ProtocolGuidArray,
+                  &ArrayCount
+                  );
+    if (!EFI_ERROR (Status)) {
+
+      for (ProtocolIndex = 0; ProtocolIndex < ArrayCount; ProtocolIndex++) {
+
+        if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiLoadedImageProtocolGuid) == 0) {
+          (*HandleType)[HandleIndex] |= EFI_HANDLE_TYPE_IMAGE_HANDLE;
+        }
+
+        if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiDriverBindingProtocolGuid) == 0) {
+          (*HandleType)[HandleIndex] |= EFI_HANDLE_TYPE_DRIVER_BINDING_HANDLE;
+        }
+
+        if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiDriverConfigurationProtocolGuid) == 0) {
+          (*HandleType)[HandleIndex] |= EFI_HANDLE_TYPE_DRIVER_CONFIGURATION_HANDLE;
+        }
+
+        if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiDriverDiagnosticsProtocolGuid) == 0) {
+          (*HandleType)[HandleIndex] |= EFI_HANDLE_TYPE_DRIVER_DIAGNOSTICS_HANDLE;
+        }
+
+        if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiComponentNameProtocolGuid) == 0) {
+          (*HandleType)[HandleIndex] |= EFI_HANDLE_TYPE_COMPONENT_NAME_HANDLE;
+        }
+
+        if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiDevicePathProtocolGuid) == 0) {
+          (*HandleType)[HandleIndex] |= EFI_HANDLE_TYPE_DEVICE_HANDLE;
+        }
+        //
+        // Retrieve the list of agents that have opened each protocol
+        //
+
+        Status = refit_call4_wrapper(BS->OpenProtocolInformation,
+                      (*HandleBuffer)[HandleIndex],
+                      ProtocolGuidArray[ProtocolIndex],
+                      &OpenInfo,
+                      &OpenInfoCount
+                      );
+        if (!EFI_ERROR (Status)) {
+
+          for (OpenInfoIndex = 0; OpenInfoIndex < OpenInfoCount; OpenInfoIndex++) {
+            if (DriverBindingHandle != NULL && OpenInfo[OpenInfoIndex].AgentHandle == DriverBindingHandle) {
+              if ((OpenInfo[OpenInfoIndex].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) == EFI_OPEN_PROTOCOL_BY_DRIVER) {
+                //
+                // Mark the device handle as being managed by the driver specified by DriverBindingHandle
+                //
+                (*HandleType)[HandleIndex] |= (EFI_HANDLE_TYPE_DEVICE_HANDLE | EFI_HANDLE_TYPE_CONTROLLER_HANDLE);
+                //
+                // Mark the DriverBindingHandle as being a driver that is managing at least one controller
+                //
+                if (DriverBindingHandleIndexValid) {
+                  (*HandleType)[*DriverBindingHandleIndex] |= EFI_HANDLE_TYPE_DEVICE_DRIVER;
+                }
+              }
+
+              if ((
+                    OpenInfo[OpenInfoIndex].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+                ) == EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+                  ) {
+                //
+                // Mark the DriverBindingHandle as being a driver that is managing at least one child controller
+                //
+                if (DriverBindingHandleIndexValid) {
+                  (*HandleType)[*DriverBindingHandleIndex] |= EFI_HANDLE_TYPE_BUS_DRIVER;
+                }
+              }
+
+              if (ControllerHandle != NULL && (*HandleBuffer)[HandleIndex] == ControllerHandle) {
+                if ((
+                      OpenInfo[OpenInfoIndex].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+                  ) == EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+                    ) {
+                  for (ChildIndex = 0; ChildIndex < *HandleCount; ChildIndex++) {
+                    if ((*HandleBuffer)[ChildIndex] == OpenInfo[OpenInfoIndex].ControllerHandle) {
+                      (*HandleType)[ChildIndex] |= (EFI_HANDLE_TYPE_DEVICE_HANDLE | EFI_HANDLE_TYPE_CHILD_HANDLE);
+                    }
+                  }
+                }
+              }
+            }
+
+            if (DriverBindingHandle == NULL && OpenInfo[OpenInfoIndex].ControllerHandle == ControllerHandle) {
+              if ((OpenInfo[OpenInfoIndex].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) == EFI_OPEN_PROTOCOL_BY_DRIVER) {
+                for (ChildIndex = 0; ChildIndex < *HandleCount; ChildIndex++) {
+                  if ((*HandleBuffer)[ChildIndex] == OpenInfo[OpenInfoIndex].AgentHandle) {
+                    (*HandleType)[ChildIndex] |= EFI_HANDLE_TYPE_DEVICE_DRIVER;
+                  }
+                }
+              }
+
+              if ((
+                    OpenInfo[OpenInfoIndex].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+                ) == EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+                  ) {
+                (*HandleType)[HandleIndex] |= EFI_HANDLE_TYPE_PARENT_HANDLE;
+                for (ChildIndex = 0; ChildIndex < *HandleCount; ChildIndex++) {
+                  if ((*HandleBuffer)[ChildIndex] == OpenInfo[OpenInfoIndex].AgentHandle) {
+                    (*HandleType)[ChildIndex] |= EFI_HANDLE_TYPE_BUS_DRIVER;
+                  }
+                }
+              }
+            }
+          }
+
+          MyFreePool (OpenInfo);
+        }
+      }
+
+      MyFreePool (ProtocolGuidArray);
+    }
+  }
+
+  return EFI_SUCCESS;
+
+Error:
+  MyFreePool (*HandleType);
+  MyFreePool (*HandleBuffer);
+
+  *HandleCount  = 0;
+  *HandleBuffer = NULL;
+  *HandleType   = NULL;
+
+  return Status;
+} /* EFI_STATUS LibScanHandleDatabase() */
diff --git a/refind/driver_support.h b/refind/driver_support.h
new file mode 100644 (file)
index 0000000..08405eb
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * File to implement LibScanHandleDatabase(), which is used by rEFInd's
+ * driver-loading code (inherited from rEFIt), but which has not been
+ * implemented in GNU-EFI and seems to have been dropped from current
+ * versions of the Tianocore library. This function was taken from a git
+ * site with EFI code. The original file bore the following copyright
+ * notice:
+ *
+ * Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+ * This program and the accompanying materials are licensed and made available under
+ * the terms and conditions of the BSD License that accompanies this distribution.
+ * The full text of the license may be found at
+ * http://opensource.org/licenses/bsd-license.php.
+ *
+ * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ *
+ */
+
+#ifdef __MAKEWITH_GNUEFI
+#include <efi.h>
+#include <efi/efilib.h>
+#else
+#include "../include/tiano_includes.h"
+#endif
+#include "global.h"
+
+#ifndef _DRIVER_SUPPORT
+#define _DRIVER_SUPPORT
+
+// Below is from http://git.etherboot.org/?p=mirror/efi/shell/.git;a=commitdiff;h=b1b0c63423cac54dc964c2930e04aebb46a946ec;
+// Seems to have been replaced by ParseHandleDatabaseByRelationshipWithType(), but the latter isn't working for me....
+EFI_STATUS
+LibScanHandleDatabase (
+  EFI_HANDLE  DriverBindingHandle, OPTIONAL
+  UINT32      *DriverBindingHandleIndex, OPTIONAL
+  EFI_HANDLE  ControllerHandle, OPTIONAL
+  UINT32      *ControllerHandleIndex, OPTIONAL
+  UINTN       *HandleCount,
+  EFI_HANDLE  **HandleBuffer,
+  UINT32      **HandleType
+  );
+
+
+#define EFI_HANDLE_TYPE_UNKNOWN                     0x000
+#define EFI_HANDLE_TYPE_IMAGE_HANDLE                0x001
+#define EFI_HANDLE_TYPE_DRIVER_BINDING_HANDLE       0x002
+#define EFI_HANDLE_TYPE_DEVICE_DRIVER               0x004
+#define EFI_HANDLE_TYPE_BUS_DRIVER                  0x008
+#define EFI_HANDLE_TYPE_DRIVER_CONFIGURATION_HANDLE 0x010
+#define EFI_HANDLE_TYPE_DRIVER_DIAGNOSTICS_HANDLE   0x020
+#define EFI_HANDLE_TYPE_COMPONENT_NAME_HANDLE       0x040
+#define EFI_HANDLE_TYPE_DEVICE_HANDLE               0x080
+#define EFI_HANDLE_TYPE_PARENT_HANDLE               0x100
+#define EFI_HANDLE_TYPE_CONTROLLER_HANDLE           0x200
+#define EFI_HANDLE_TYPE_CHILD_HANDLE                0x400
+
+#endif
diff --git a/refind/global.h b/refind/global.h
new file mode 100644 (file)
index 0000000..8acbf7d
--- /dev/null
@@ -0,0 +1,354 @@
+/*
+ * refit/global.h
+ * Global header file
+ *
+ * Copyright (c) 2006-2009 Christoph Pfisterer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Modifications copyright (c) 2012-2015 Roderick W. Smith
+ *
+ * Modifications distributed under the terms of the GNU General Public
+ * License (GPL) version 3 (GPLv3), a copy of which must be distributed
+ * with this source code or binaries made from it.
+ *
+ */
+
+#ifndef __GLOBAL_H_
+#define __GLOBAL_H_
+
+#ifdef __MAKEWITH_GNUEFI
+#include <efi.h>
+#include <efilib.h>
+#else
+#include "../include/tiano_includes.h"
+#endif
+#include "../EfiLib/GenericBdsLib.h"
+
+#include "libeg.h"
+
+#define REFIT_DEBUG (0)
+
+// Tag classifications; used in various ways.
+#define TAG_ABOUT            (1)
+#define TAG_REBOOT           (2)
+#define TAG_SHUTDOWN         (3)
+#define TAG_TOOL             (4)
+#define TAG_LOADER           (5)
+#define TAG_LEGACY           (6)
+#define TAG_EXIT             (7)
+#define TAG_SHELL            (8)
+#define TAG_GPTSYNC          (9)
+#define TAG_LEGACY_UEFI      (10)
+#define TAG_APPLE_RECOVERY   (11)
+#define TAG_WINDOWS_RECOVERY (12)
+#define TAG_MOK_TOOL         (13)
+#define TAG_FIRMWARE         (14)
+#define TAG_MEMTEST          (15)
+#define TAG_GDISK            (16)
+#define TAG_NETBOOT          (17)
+#define TAG_CSR_ROTATE       (18)
+#define NUM_TOOLS            (19)
+
+#define NUM_SCAN_OPTIONS 10
+
+#define DEFAULT_ICONS_DIR L"icons"
+
+// OS bit codes; used in GlobalConfig.GraphicsOn
+#define GRAPHICS_FOR_OSX        1
+#define GRAPHICS_FOR_LINUX      2
+#define GRAPHICS_FOR_ELILO      4
+#define GRAPHICS_FOR_GRUB       8
+#define GRAPHICS_FOR_WINDOWS   16
+
+// Load types
+#define TYPE_EFI    1
+#define TYPE_LEGACY 2
+
+// Type of legacy (BIOS) boot support detected
+#define LEGACY_TYPE_NONE 0
+#define LEGACY_TYPE_MAC  1
+#define LEGACY_TYPE_UEFI 2
+
+#ifdef __MAKEWITH_GNUEFI
+//
+// define BBS Device Types
+//
+#define BBS_FLOPPY        0x01
+#define BBS_HARDDISK      0x02
+#define BBS_CDROM         0x03
+#define BBS_PCMCIA        0x04
+#define BBS_USB           0x05
+#define BBS_EMBED_NETWORK 0x06
+#define BBS_BEV_DEVICE    0x80
+#define BBS_UNKNOWN       0xff
+#endif
+
+// BIOS Boot Specification (BBS) device types, as returned in DevicePath->Type field
+#define DEVICE_TYPE_HW         0x01
+#define DEVICE_TYPE_ACPI       0x02 /* returned by UEFI boot loader on USB */
+#define DEVICE_TYPE_MESSAGING  0x03
+#define DEVICE_TYPE_MEDIA      0x04 /* returned by EFI boot loaders on hard disk */
+#define DEVICE_TYPE_BIOS       0x05 /* returned by legacy (BIOS) boot loaders */
+#define DEVICE_TYPE_END        0x75 /* end of path */
+
+// Filesystem type identifiers. Not all are yet used....
+#define FS_TYPE_UNKNOWN        0
+#define FS_TYPE_WHOLEDISK      1
+#define FS_TYPE_FAT            2
+#define FS_TYPE_EXFAT          3
+#define FS_TYPE_NTFS           4
+#define FS_TYPE_EXT2           5
+#define FS_TYPE_EXT3           6
+#define FS_TYPE_EXT4           7
+#define FS_TYPE_HFSPLUS        8
+#define FS_TYPE_REISERFS       9
+#define FS_TYPE_BTRFS          10
+#define FS_TYPE_XFS            11
+#define FS_TYPE_ISO9660        12
+
+// How to scale banner images
+#define BANNER_NOSCALE         0
+#define BANNER_FILLSCREEN      1
+
+// Sizes of the default icons; badges are 1/4 the big icon size
+#define DEFAULT_SMALL_ICON_SIZE 48
+#define DEFAULT_BIG_ICON_SIZE   128
+
+// Codes for types of icon sizes; used for indexing into GlobalConfig.IconSizes[]
+#define ICON_SIZE_BADGE 0
+#define ICON_SIZE_SMALL 1
+#define ICON_SIZE_BIG   2
+
+// Names of binaries that can manage MOKs....
+#define MOK_NAMES               L"MokManager.efi,HashTool.efi,HashTool-signed.efi,KeyTool.efi,KeyTool-signed.efi"
+// Directories to search for these MOK-managing programs. Note that SelfDir is
+// searched in addition to these locations....
+#define MOK_LOCATIONS           L"\\,EFI\\tools,EFI\\fedora,EFI\\redhat,EFI\\ubuntu,EFI\\suse,EFI\\opensuse,EFI\\altlinux"
+// Directories to search for memtest86....
+#define MEMTEST_LOCATIONS       L"EFI\\tools,EFI\\tools\\memtest86,EFI\\tools\\memtest,EFI\\memtest86,EFI\\memtest"
+// Files that may be Windows recovery files
+#define WINDOWS_RECOVERY_FILES  L"EFI\\Microsoft\\Boot\\LrsBootmgr.efi,Recovery:\\EFI\\BOOT\\bootx64.efi,Recovery:\\EFI\\BOOT\\bootia32.efi"
+
+// Definitions for the "hideui" option in refind.conf
+#define HIDEUI_FLAG_NONE       (0x0000)
+#define HIDEUI_FLAG_BANNER     (0x0001)
+#define HIDEUI_FLAG_LABEL      (0x0002)
+#define HIDEUI_FLAG_SINGLEUSER (0x0004)
+#define HIDEUI_FLAG_HWTEST     (0x0008)
+#define HIDEUI_FLAG_ARROWS     (0x0010)
+#define HIDEUI_FLAG_HINTS      (0x0020)
+#define HIDEUI_FLAG_EDITOR     (0x0040)
+#define HIDEUI_FLAG_SAFEMODE   (0x0080)
+#define HIDEUI_FLAG_BADGES     (0x0100)
+#define HIDEUI_FLAG_ALL       ((0xffff))
+
+// Default hint text for program-launch submenus
+#define SUBSCREEN_HINT1            L"Use arrow keys to move cursor; Enter to boot;"
+#define SUBSCREEN_HINT2            L"Insert or F2 to edit options; Esc to return to main menu"
+#define SUBSCREEN_HINT2_NO_EDITOR  L"Esc to return to main menu"
+
+#define NULL_GUID_VALUE { 0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} };
+#define REFIND_GUID_VALUE { 0x36D08FA7, 0xCF0B, 0x42F5, {0x8F, 0x14, 0x68, 0xDF, 0x73, 0xED, 0x37, 0x40} };
+
+//
+// global definitions
+//
+
+// global types
+
+typedef struct _uint32_list {
+    UINT32               Value;
+    struct _uint32_list  *Next;
+} UINT32_LIST;
+
+typedef struct {
+   UINT8 Flags;
+   UINT8 StartCHS1;
+   UINT8 StartCHS2;
+   UINT8 StartCHS3;
+   UINT8 Type;
+   UINT8 EndCHS1;
+   UINT8 EndCHS2;
+   UINT8 EndCHS3;
+   UINT32 StartLBA;
+   UINT32 Size;
+} MBR_PARTITION_INFO;
+
+typedef struct {
+   EFI_DEVICE_PATH     *DevicePath;
+   EFI_HANDLE          DeviceHandle;
+   EFI_FILE            *RootDir;
+   CHAR16              *VolName;
+   CHAR16              *PartName;
+   EFI_GUID            VolUuid;
+   EFI_GUID            PartGuid;
+   EFI_GUID            PartTypeGuid;
+   BOOLEAN             IsMarkedReadOnly;
+   UINTN               VolNumber;
+   EG_IMAGE            *VolIconImage;
+   EG_IMAGE            *VolBadgeImage;
+   UINTN               DiskKind;
+   BOOLEAN             IsAppleLegacy;
+   BOOLEAN             HasBootCode;
+   CHAR16              *OSIconName;
+   CHAR16              *OSName;
+   BOOLEAN             IsMbrPartition;
+   UINTN               MbrPartitionIndex;
+   EFI_BLOCK_IO        *BlockIO;
+   UINT64              BlockIOOffset;
+   EFI_BLOCK_IO        *WholeDiskBlockIO;
+   EFI_DEVICE_PATH     *WholeDiskDevicePath;
+   MBR_PARTITION_INFO  *MbrPartitionTable;
+   BOOLEAN             IsReadable;
+   UINT32              FSType;
+} REFIT_VOLUME;
+
+typedef struct _refit_menu_entry {
+   CHAR16      *Title;
+   UINTN       Tag;
+   UINTN       Row;
+   CHAR16      ShortcutDigit;
+   CHAR16      ShortcutLetter;
+   EG_IMAGE    *Image;
+   EG_IMAGE    *BadgeImage;
+   struct _refit_menu_screen *SubScreen;
+} REFIT_MENU_ENTRY;
+
+typedef struct _refit_menu_screen {
+   CHAR16      *Title;
+   EG_IMAGE    *TitleImage;
+   UINTN       InfoLineCount;
+   CHAR16      **InfoLines;
+   UINTN       EntryCount;     // total number of entries registered
+   REFIT_MENU_ENTRY **Entries;
+   UINTN       TimeoutSeconds;
+   CHAR16      *TimeoutText;
+   CHAR16      *Hint1;
+   CHAR16      *Hint2;
+} REFIT_MENU_SCREEN;
+
+typedef struct {
+   REFIT_MENU_ENTRY me;
+   CHAR16           *Title;
+   CHAR16           *LoaderPath;
+   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;
+   BDS_COMMON_OPTION *BdsOption;
+   CHAR16            *LoadOptions;
+   BOOLEAN           Enabled;
+} LEGACY_ENTRY;
+
+typedef struct {
+   BOOLEAN          TextOnly;
+   BOOLEAN          ScanAllLinux;
+   BOOLEAN          DeepLegacyScan;
+   BOOLEAN          EnableAndLockVMX;
+   BOOLEAN          FoldLinuxKernels;
+   UINTN            RequestedScreenWidth;
+   UINTN            RequestedScreenHeight;
+   UINTN            BannerBottomEdge;
+   UINTN            RequestedTextMode;
+   UINTN            Timeout;
+   UINTN            HideUIFlags;
+   UINTN            MaxTags;     // max. number of OS entries to show simultaneously in graphics mode
+   UINTN            GraphicsFor;
+   UINTN            LegacyType;
+   UINTN            ScanDelay;
+   UINTN            ScreensaverTime;
+   UINTN            IconSizes[3];
+   UINTN            BannerScale;
+   REFIT_VOLUME     *DiscoveredRoot;
+   EFI_DEVICE_PATH  *SelfDevicePath;
+   CHAR16           *BannerFileName;
+   EG_IMAGE         *ScreenBackground;
+   CHAR16           *ConfigFilename;
+   CHAR16           *SelectionSmallFileName;
+   CHAR16           *SelectionBigFileName;
+   CHAR16           *DefaultSelection;
+   CHAR16           *AlsoScan;
+   CHAR16           *DontScanVolumes;
+   CHAR16           *DontScanDirs;
+   CHAR16           *DontScanFiles;
+   CHAR16           *WindowsRecoveryFiles;
+   CHAR16           *DriverDirs;
+   CHAR16           *IconsDir;
+   CHAR16           *SpoofOSXVersion;
+   UINT32_LIST      *CsrValues;
+   UINTN            ShowTools[NUM_TOOLS];
+   CHAR8            ScanFor[NUM_SCAN_OPTIONS]; // codes of types of loaders for which to scan
+} REFIT_CONFIG;
+
+// Global variables
+
+extern EFI_HANDLE       SelfImageHandle;
+extern EFI_LOADED_IMAGE *SelfLoadedImage;
+extern EFI_FILE         *SelfRootDir;
+extern EFI_FILE         *SelfDir;
+extern CHAR16           *SelfDirPath;
+
+extern REFIT_VOLUME     *SelfVolume;
+extern REFIT_VOLUME     **Volumes;
+extern UINTN            VolumesCount;
+
+extern REFIT_CONFIG     GlobalConfig;
+
+extern EFI_GUID gEfiLegacyBootProtocolGuid;
+extern EFI_GUID gEfiGlobalVariableGuid;
+
+EFI_STATUS StartEFIImageList(IN EFI_DEVICE_PATH **DevicePaths,
+                             IN CHAR16 *LoadOptions, IN UINTN LoaderType,
+                             IN CHAR16 *ImageTitle, IN CHAR8 OSType,
+                             OUT UINTN *ErrorInStep,
+                             IN BOOLEAN Verbose,
+                             IN BOOLEAN IsDriver);
+LOADER_ENTRY *InitializeLoaderEntry(IN LOADER_ENTRY *Entry);
+REFIT_MENU_SCREEN *InitializeSubScreen(IN LOADER_ENTRY *Entry);
+VOID GenerateSubScreen(LOADER_ENTRY *Entry, IN REFIT_VOLUME *Volume, IN BOOLEAN GenerateReturn);
+EG_IMAGE * GetDiskBadge(IN UINTN DiskType);
+LOADER_ENTRY * MakeGenericLoaderEntry(VOID);
+VOID SetLoaderDefaults(LOADER_ENTRY *Entry, CHAR16 *LoaderPath, IN REFIT_VOLUME *Volume);
+LOADER_ENTRY * AddPreparedLoaderEntry(LOADER_ENTRY *Entry);
+VOID StoreLoaderName(IN CHAR16 *Name);
+
+#endif
+
+/* EOF */
diff --git a/refind/gpt.c b/refind/gpt.c
new file mode 100644 (file)
index 0000000..6ce2ba0
--- /dev/null
@@ -0,0 +1,259 @@
+/*
+ * refind/gpt.c
+ * Functions related to GPT data structures
+ *
+ * Copyright (c) 2014-2015 Roderick W. Smith
+ * All rights reserved.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "gpt.h"
+#include "lib.h"
+#include "screen.h"
+#include "crc32.h"
+#include "../include/refit_call_wrapper.h"
+
+#ifdef __MAKEWITH_TIANO
+#define BlockIoProtocol gEfiBlockIoProtocolGuid
+#endif
+
+extern GPT_DATA *gPartitions;
+
+// Allocate data for the main GPT_DATA structure, as well as the ProtectiveMBR
+// and Header structures it contains. This function does *NOT*, however,
+// allocate memory for the Entries data structure, since its size is variable
+// and is determined by the contents of Header.
+GPT_DATA * AllocateGptData(VOID) {
+   GPT_DATA *GptData;
+
+   GptData = AllocateZeroPool(sizeof(GPT_DATA));
+   if (GptData != NULL) {
+      GptData->ProtectiveMBR = AllocateZeroPool(sizeof(MBR_RECORD));
+      GptData->Header = AllocateZeroPool(sizeof(GPT_HEADER));
+      if ((GptData->ProtectiveMBR == NULL) || (GptData->Header == NULL)) {
+         MyFreePool(GptData->ProtectiveMBR);
+         MyFreePool(GptData->Header);
+         MyFreePool(GptData);
+         GptData = NULL;
+      } // if
+   } // if
+   return GptData;
+} // GPT_DATA * AllocateGptData()
+
+// Unallocate a single GPT_DATA structure. This does NOT follow the
+// linked list, though.
+VOID ClearGptData(GPT_DATA *Data) {
+   if (Data) {
+      if (Data->ProtectiveMBR)
+         MyFreePool(Data->ProtectiveMBR);
+      if (Data->Header)
+         MyFreePool(Data->Header);
+      if (Data->Entries)
+         MyFreePool(Data->Entries);
+      MyFreePool(Data);
+   } // if
+} // VOID ClearGptData()
+
+// TODO: Make this work on big-endian systems; at the moment, it contains
+// little-endian assumptions!
+// Returns TRUE if the GPT protective MBR and header data appear valid,
+// FALSE otherwise.
+static BOOLEAN GptHeaderValid(GPT_DATA *GptData) {
+   BOOLEAN IsValid;
+   UINT32 CrcValue, StoredCrcValue;
+   UINTN HeaderSize = sizeof(GPT_HEADER);
+
+   if ((GptData == NULL) || (GptData->ProtectiveMBR == NULL) || (GptData->Header == NULL))
+      return FALSE;
+
+   IsValid = (GptData->ProtectiveMBR->MBRSignature == 0xAA55);
+   IsValid = IsValid && ((GptData->ProtectiveMBR->partitions[0].type == 0xEE) ||
+                         (GptData->ProtectiveMBR->partitions[1].type == 0xEE) ||
+                         (GptData->ProtectiveMBR->partitions[2].type == 0xEE) ||
+                         (GptData->ProtectiveMBR->partitions[3].type == 0xEE));
+
+   IsValid = IsValid && ((GptData->Header->signature == 0x5452415020494645ULL) &&
+                         (GptData->Header->spec_revision == 0x00010000) &&
+                         (GptData->Header->entry_size == 128));
+
+   // Looks good so far; check CRC value....
+   if (IsValid) {
+      if (GptData->Header->header_size < HeaderSize)
+         HeaderSize = GptData->Header->header_size;
+      StoredCrcValue = GptData->Header->header_crc32;
+      GptData->Header->header_crc32 = 0;
+      CrcValue = crc32(0x0, GptData->Header, HeaderSize);
+      if (CrcValue != StoredCrcValue)
+         IsValid = FALSE;
+      GptData->Header->header_crc32 = StoredCrcValue;
+   } // if
+
+   return IsValid;
+} // BOOLEAN GptHeaderValid()
+
+// Read GPT data from Volume and store it in *Data. Note that this function
+// may be called on a Volume that is not in fact a GPT disk (an MBR disk,
+// a partition, etc.), in which case it will return EFI_LOAD_ERROR or some
+// other error condition. In this case, *Data will be left alone.
+// Note also that this function checks CRCs and does other sanity checks
+// on the input data, but does NOT resort to using the backup data if the
+// primary data structures are damaged. The intent is that the function
+// be very conservative about reading GPT data. Currently (version 0.7.10),
+// rEFInd uses the data only to provide access to partition names. This is
+// non-critical data, so it's OK to return nothing, but having the program
+// hang on reading garbage or return nonsense could be very bad.
+EFI_STATUS ReadGptData(REFIT_VOLUME *Volume, GPT_DATA **Data) {
+   EFI_STATUS Status = EFI_SUCCESS;
+   UINT64     BufferSize;
+   UINTN      i;
+   GPT_DATA   *GptData; // Temporary holding storage; transferred to *Data later
+
+   if ((Volume == NULL) || (Data == NULL))
+      return EFI_INVALID_PARAMETER;
+
+   // get block i/o
+   if ((Status == EFI_SUCCESS) && (Volume->BlockIO == NULL)) {
+      Status = refit_call3_wrapper(BS->HandleProtocol, Volume->DeviceHandle, &BlockIoProtocol, (VOID **) &(Volume->BlockIO));
+      if (EFI_ERROR(Status)) {
+         Volume->BlockIO = NULL;
+         Print(L"Warning: Can't get BlockIO protocol in ReadGptData().\n");
+         Status = EFI_NOT_READY;
+      }
+   } // if
+
+   if ((Status == EFI_SUCCESS) && ((!Volume->BlockIO->Media->MediaPresent) || (Volume->BlockIO->Media->LogicalPartition)))
+      Status = EFI_NO_MEDIA;
+
+   if (Status == EFI_SUCCESS) {
+      GptData = AllocateGptData(); // Note: All but GptData->Entries
+      if (GptData == NULL) {
+         Status = EFI_OUT_OF_RESOURCES;
+      } // if
+   } // if
+
+   // Read the MBR and store it in GptData->ProtectiveMBR.
+   if (Status == EFI_SUCCESS) {
+      Status = refit_call5_wrapper(Volume->BlockIO->ReadBlocks, Volume->BlockIO, Volume->BlockIO->Media->MediaId,
+                                   0, sizeof(MBR_RECORD), (VOID*) GptData->ProtectiveMBR);
+   }
+
+   // Read the GPT header and store it in GptData->Header.
+   if (Status == EFI_SUCCESS) {
+      Status = refit_call5_wrapper(Volume->BlockIO->ReadBlocks, Volume->BlockIO, Volume->BlockIO->Media->MediaId,
+                                   1, sizeof(GPT_HEADER), GptData->Header);
+   }
+
+   // If it looks like a valid protective MBR & GPT header, try to do more with it....
+   if (Status == EFI_SUCCESS) {
+      if (GptHeaderValid(GptData)) {
+         // Load actual GPT table....
+         BufferSize = GptData->Header->entry_count * 128;
+         GptData->Entries = AllocatePool(BufferSize);
+         if (GptData->Entries == NULL)
+            Status = EFI_OUT_OF_RESOURCES;
+
+         if (Status == EFI_SUCCESS)
+            Status = refit_call5_wrapper(Volume->BlockIO->ReadBlocks, Volume->BlockIO, Volume->BlockIO->Media->MediaId,
+                                         GptData->Header->entry_lba, BufferSize, GptData->Entries);
+
+         // Check CRC status of table
+         if ((Status == EFI_SUCCESS) && (crc32(0x0, GptData->Entries, BufferSize) != GptData->Header->entry_crc32))
+            Status = EFI_CRC_ERROR;
+
+         // Now, ensure that every name is null-terminated....
+         if (Status == EFI_SUCCESS) {
+            for (i = 0; i < GptData->Header->entry_count; i++)
+               GptData->Entries[i].name[35] = '\0';
+         } // if
+      } else {
+         Status = EFI_UNSUPPORTED;
+      } // if/else valid header
+   } // if header read OK
+
+   if (Status == EFI_SUCCESS) {
+      // Everything looks OK, so copy it over
+      ClearGptData(*Data);
+      *Data = GptData;
+   } else {
+      ClearGptData(GptData);
+   } // if/else
+
+   return Status;
+} // EFI_STATUS ReadGptData()
+
+// Look in gPartitions for a partition with the specified Guid. If found, return
+// a pointer to that partition's data. If not found, return a NULL pointer.
+// The calling function is responsible for freeing the returned memory.
+GPT_ENTRY * FindPartWithGuid(EFI_GUID *Guid) {
+   UINTN     i;
+   GPT_ENTRY *Found = NULL;
+   GPT_DATA  *GptData;
+
+   if ((Guid == NULL) || (gPartitions == NULL))
+      return NULL;
+
+   GptData = gPartitions;
+   while ((GptData != NULL) && (!Found)) {
+      i = 0;
+      while ((i < GptData->Header->entry_count) && (!Found)) {
+         if (GuidsAreEqual((EFI_GUID*) &(GptData->Entries[i].partition_guid), Guid)) {
+            Found = AllocateZeroPool(sizeof(GPT_ENTRY));
+            CopyMem(Found, &GptData->Entries[i], sizeof(GPT_ENTRY));
+         } else {
+            i++;
+         } // if/else
+      } // while(scanning entries)
+      GptData = GptData->NextEntry;
+   } // while(scanning GPTs)
+   return Found;
+} // GPT_ENTRY * FindPartWithGuid()
+
+// Erase the gPartitions linked-list data structure
+VOID ForgetPartitionTables(VOID) {
+   GPT_DATA  *Next;
+
+   while (gPartitions != NULL) {
+      Next = gPartitions->NextEntry;
+      ClearGptData(gPartitions);
+      gPartitions = Next;
+   } // while
+} // VOID ForgetPartitionTables()
+
+// If Volume points to a whole disk with a GPT, add it to the gPartitions
+// linked list of GPTs.
+VOID AddPartitionTable(REFIT_VOLUME *Volume) {
+   GPT_DATA    *GptData = NULL, *GptList;
+   EFI_STATUS  Status;
+   UINTN       NumTables = 1;
+
+   Status = ReadGptData(Volume, &GptData);
+   if (Status == EFI_SUCCESS) {
+      if (gPartitions == NULL) {
+         gPartitions = GptData;
+      } else {
+         GptList = gPartitions;
+         while (GptList->NextEntry != NULL) {
+            GptList = GptList->NextEntry;
+            NumTables++;
+         } // while
+         GptList->NextEntry = GptData;
+         NumTables++;
+      } // if/else
+   } else if (GptData != NULL) {
+      ClearGptData(GptData);
+      NumTables = 0;
+   } // if/else
+} // VOID AddPartitionTable()
+
diff --git a/refind/gpt.h b/refind/gpt.h
new file mode 100644 (file)
index 0000000..28a495b
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * refind/gpt.h
+ * Functions related to GPT data structures
+ *
+ * Copyright (c) 2014-2015 Roderick W. Smith
+ * All rights reserved.
+ *
+ * This program is distributed under the terms of the GNU General Public
+ * License (GPL) version 3 (GPLv3), a copy of which must be distributed
+ * with this source code or binaries made from it.
+ *
+ */
+
+#include "global.h"
+
+#ifndef __GPT_H_
+#define __GPT_H_
+
+#ifdef __MAKEWITH_GNUEFI
+#include "efi.h"
+#include "efilib.h"
+#else
+#include "../include/tiano_includes.h"
+#endif
+
+#pragma pack(1)
+typedef struct {
+   UINT8   flags;
+   UINT8   start_chs[3];
+   UINT8   type;
+   UINT8   end_chs[3];
+   UINT32  start_lba;
+   UINT32  size;
+} MBR_PART_INFO;
+
+// A 512-byte data structure into which the MBR can be loaded in one
+// go. Also used when loading logical partitions.
+
+typedef struct {
+   UINT8            code[440];
+   UINT32           diskSignature;
+   UINT16           nulls;
+   MBR_PART_INFO    partitions[4];
+   UINT16           MBRSignature;
+} MBR_RECORD;
+
+typedef struct {
+   UINT64  signature;
+   UINT32  spec_revision;
+   UINT32  header_size;
+   UINT32  header_crc32;
+   UINT32  reserved;
+   UINT64  header_lba;
+   UINT64  alternate_header_lba;
+   UINT64  first_usable_lba;
+   UINT64  last_usable_lba;
+   UINT8   disk_guid[16];
+   UINT64  entry_lba;
+   UINT32  entry_count;
+   UINT32  entry_size;
+   UINT32  entry_crc32;
+   UINT8   reserved2[420];
+} GPT_HEADER;
+
+typedef struct {
+   UINT8   type_guid[16];
+   UINT8   partition_guid[16];
+   UINT64  start_lba;
+   UINT64  end_lba;
+   UINT64  attributes;
+   CHAR16  name[36];
+} GPT_ENTRY;
+
+typedef struct _gpt_data {
+   MBR_RECORD         *ProtectiveMBR;
+   GPT_HEADER         *Header;
+   GPT_ENTRY          *Entries;
+   struct _gpt_data   *NextEntry;
+} GPT_DATA;
+
+#pragma pack(0)
+
+VOID ClearGptData(GPT_DATA *Data);
+EFI_STATUS ReadGptData(REFIT_VOLUME *Volume, GPT_DATA **Data);
+// CHAR16 * PartNameFromGuid(EFI_GUID *Guid);
+GPT_ENTRY * FindPartWithGuid(EFI_GUID *Guid);
+VOID ForgetPartitionTables(VOID);
+VOID AddPartitionTable(REFIT_VOLUME *Volume);
+
+#endif
\ No newline at end of file
diff --git a/refind/icns.c b/refind/icns.c
new file mode 100644 (file)
index 0000000..5e74bb2
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * refit/icns.c
+ * Loader for .icns icon files
+ *
+ * Copyright (c) 2006-2007 Christoph Pfisterer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "global.h"
+#include "lib.h"
+#include "icns.h"
+#include "config.h"
+#include "mystrings.h"
+#include "../refind/screen.h"
+
+//
+// well-known icons
+//
+
+typedef struct {
+    EG_IMAGE    *Image;
+    CHAR16      *FileName;
+    UINTN       IconSize;
+} BUILTIN_ICON;
+
+BUILTIN_ICON BuiltinIconTable[BUILTIN_ICON_COUNT] = {
+   { NULL, L"func_about", ICON_SIZE_SMALL },
+   { NULL, L"func_reset", ICON_SIZE_SMALL },
+   { NULL, L"func_shutdown", ICON_SIZE_SMALL },
+   { NULL, L"func_exit", ICON_SIZE_SMALL },
+   { NULL, L"func_firmware", ICON_SIZE_SMALL },
+   { NULL, L"func_csr_rotate", ICON_SIZE_SMALL },
+   { NULL, L"tool_shell", ICON_SIZE_SMALL },
+   { NULL, L"tool_part", ICON_SIZE_SMALL },
+   { NULL, L"tool_rescue", ICON_SIZE_SMALL },
+   { NULL, L"tool_apple_rescue", ICON_SIZE_SMALL },
+   { NULL, L"tool_windows_rescue", ICON_SIZE_SMALL },
+   { NULL, L"tool_mok_tool", ICON_SIZE_SMALL },
+   { NULL, L"tool_memtest", ICON_SIZE_SMALL },
+   { NULL, L"tool_netboot", ICON_SIZE_SMALL },
+   { NULL, L"vol_internal", ICON_SIZE_BADGE },
+   { NULL, L"vol_external", ICON_SIZE_BADGE },
+   { NULL, L"vol_optical", ICON_SIZE_BADGE },
+   { NULL, L"vol_net", ICON_SIZE_BADGE },
+};
+
+EG_IMAGE * BuiltinIcon(IN UINTN Id)
+{
+    if (Id >= BUILTIN_ICON_COUNT)
+        return NULL;
+
+    if (BuiltinIconTable[Id].Image == NULL) {
+       BuiltinIconTable[Id].Image = egFindIcon(BuiltinIconTable[Id].FileName, GlobalConfig.IconSizes[BuiltinIconTable[Id].IconSize]);
+       if (BuiltinIconTable[Id].Image == NULL)
+          BuiltinIconTable[Id].Image = DummyImage(GlobalConfig.IconSizes[BuiltinIconTable[Id].IconSize]);
+    } // if
+
+    return BuiltinIconTable[Id].Image;
+}
+
+//
+// Load an icon for an operating system
+//
+
+// Load an OS icon from among the comma-delimited list provided in OSIconName.
+// Searches for icons with extensions in the ICON_EXTENSIONS list (via
+// egFindIcon()).
+// Returns image data. On failure, returns an ugly "dummy" icon.
+EG_IMAGE * LoadOSIcon(IN CHAR16 *OSIconName OPTIONAL, IN CHAR16 *FallbackIconName, BOOLEAN BootLogo)
+{
+    EG_IMAGE        *Image = NULL;
+    CHAR16          *CutoutName, BaseName[256];
+    UINTN           Index = 0;
+
+    if (GlobalConfig.TextOnly)      // skip loading if it's not used anyway
+        return NULL;
+
+    // First, try to find an icon from the OSIconName list....
+    while (((CutoutName = FindCommaDelimited(OSIconName, Index++)) != NULL) && (Image == NULL)) {
+       SPrint(BaseName, 255, L"%s_%s", BootLogo ? L"boot" : L"os", CutoutName);
+       Image = egFindIcon(BaseName, GlobalConfig.IconSizes[ICON_SIZE_BIG]);
+    }
+
+    // If that fails, try again using the FallbackIconName....
+    if (Image == NULL) {
+       SPrint(BaseName, 255, L"%s_%s", BootLogo ? L"boot" : L"os", FallbackIconName);
+       Image = egFindIcon(BaseName, GlobalConfig.IconSizes[ICON_SIZE_BIG]);
+    }
+
+    // If that fails and if BootLogo was set, try again using the "os_" start of the name....
+    if (BootLogo && (Image == NULL)) {
+       SPrint(BaseName, 255, L"os_%s", FallbackIconName);
+       Image = egFindIcon(BaseName, GlobalConfig.IconSizes[ICON_SIZE_BIG]);
+    }
+
+    // If all of these fail, return the dummy image....
+    if (Image == NULL)
+       Image = DummyImage(GlobalConfig.IconSizes[ICON_SIZE_BIG]);
+
+    return Image;
+} /* EG_IMAGE * LoadOSIcon() */
+
+
+static EG_PIXEL BlackPixel  = { 0x00, 0x00, 0x00, 0 };
+//static EG_PIXEL YellowPixel = { 0x00, 0xff, 0xff, 0 };
+
+EG_IMAGE * DummyImage(IN UINTN PixelSize)
+{
+    EG_IMAGE        *Image;
+    UINTN           x, y, LineOffset;
+    CHAR8           *Ptr, *YPtr;
+
+    Image = egCreateFilledImage(PixelSize, PixelSize, TRUE, &BlackPixel);
+
+    LineOffset = PixelSize * 4;
+
+    YPtr = (CHAR8 *)Image->PixelData + ((PixelSize - 32) >> 1) * (LineOffset + 4);
+    for (y = 0; y < 32; y++) {
+        Ptr = YPtr;
+        for (x = 0; x < 32; x++) {
+            if (((x + y) % 12) < 6) {
+                *Ptr++ = 0;
+                *Ptr++ = 0;
+                *Ptr++ = 0;
+            } else {
+                *Ptr++ = 0;
+                *Ptr++ = 255;
+                *Ptr++ = 255;
+            }
+            *Ptr++ = 144;
+        }
+        YPtr += LineOffset;
+    }
+
+    return Image;
+}
diff --git a/refind/icns.h b/refind/icns.h
new file mode 100644 (file)
index 0000000..2a6f92b
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * refit/icns.h
+ * Icon management header file
+ *
+ * Copyright (c) 2006-2009 Christoph Pfisterer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Modifications copyright (c) 2012-2015 Roderick W. Smith
+ * 
+ * Modifications distributed under the terms of the GNU General Public
+ * License (GPL) version 3 (GPLv3), a copy of which must be distributed
+ * with this source code or binaries made from it.
+ * 
+ */
+
+#ifndef __ICNS_H_
+#define __ICNS_H_
+
+//
+// icns loader module
+//
+
+EG_IMAGE * LoadOSIcon(IN CHAR16 *OSIconName OPTIONAL, IN CHAR16 *FallbackIconName, BOOLEAN BootLogo);
+
+EG_IMAGE * DummyImage(IN UINTN PixelSize);
+
+EG_IMAGE * BuiltinIcon(IN UINTN Id);
+
+#define BUILTIN_ICON_FUNC_ABOUT            (0)
+#define BUILTIN_ICON_FUNC_RESET            (1)
+#define BUILTIN_ICON_FUNC_SHUTDOWN         (2)
+#define BUILTIN_ICON_FUNC_EXIT             (3)
+#define BUILTIN_ICON_FUNC_FIRMWARE         (4)
+#define BUILTIN_ICON_FUNC_CSR_ROTATE       (5)
+#define BUILTIN_ICON_TOOL_SHELL            (6)
+#define BUILTIN_ICON_TOOL_PART             (7)
+#define BUILTIN_ICON_TOOL_RESCUE           (8)
+#define BUILTIN_ICON_TOOL_APPLE_RESCUE     (9)
+#define BUILTIN_ICON_TOOL_WINDOWS_RESCUE   (10)
+#define BUILTIN_ICON_TOOL_MOK_TOOL         (11)
+#define BUILTIN_ICON_TOOL_MEMTEST          (12)
+#define BUILTIN_ICON_TOOL_NETBOOT          (13)
+#define BUILTIN_ICON_VOL_INTERNAL          (14)
+#define BUILTIN_ICON_VOL_EXTERNAL          (15)
+#define BUILTIN_ICON_VOL_OPTICAL           (16)
+#define BUILTIN_ICON_VOL_NET               (17)
+#define BUILTIN_ICON_COUNT                 (18)
+
+#endif
+
+/* EOF */
diff --git a/refind/legacy.c b/refind/legacy.c
new file mode 100644 (file)
index 0000000..9ac7ce2
--- /dev/null
@@ -0,0 +1,710 @@
+/*
+ * refind/legacy.c
+ * Functions related to BIOS/CSM/legacy booting
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Modifications copyright (c) 2012-2015 Roderick W. Smith
+ *
+ * Modifications distributed under the terms of the GNU General Public
+ * License (GPL) version 3 (GPLv3), or (at your option) any later version.
+ *
+ */
+/*
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "global.h"
+#include "icns.h"
+#include "legacy.h"
+#include "lib.h"
+#include "menu.h"
+#include "refit_call_wrapper.h"
+#include "screen.h"
+#include "syslinux_mbr.h"
+#include "mystrings.h"
+#include "../EfiLib/BdsHelper.h"
+#include "../EfiLib/legacy.h"
+#include "Handle.h"
+
+extern REFIT_MENU_ENTRY MenuEntryReturn;
+extern REFIT_MENU_SCREEN MainMenu;
+
+#ifndef __MAKEWITH_GNUEFI
+#define LibLocateHandle gBS->LocateHandleBuffer
+#define DevicePathProtocol gEfiDevicePathProtocolGuid
+#endif
+
+static EFI_STATUS ActivateMbrPartition(IN EFI_BLOCK_IO *BlockIO, IN UINTN PartitionIndex)
+{
+    EFI_STATUS          Status;
+    UINT8               SectorBuffer[512];
+    MBR_PARTITION_INFO  *MbrTable, *EMbrTable;
+    UINT32              ExtBase, ExtCurrent, NextExtCurrent;
+    UINTN               LogicalPartitionIndex = 4;
+    UINTN               i;
+    BOOLEAN             HaveBootCode;
+
+    // read MBR
+    Status = refit_call5_wrapper(BlockIO->ReadBlocks, BlockIO, BlockIO->Media->MediaId, 0, 512, SectorBuffer);
+    if (EFI_ERROR(Status))
+        return Status;
+    if (*((UINT16 *)(SectorBuffer + 510)) != 0xaa55)
+        return EFI_NOT_FOUND;  // safety measure #1
+
+    // add boot code if necessary
+    HaveBootCode = FALSE;
+    for (i = 0; i < MBR_BOOTCODE_SIZE; i++) {
+        if (SectorBuffer[i] != 0) {
+            HaveBootCode = TRUE;
+            break;
+        }
+    }
+    if (!HaveBootCode) {
+        // no boot code found in the MBR, add the syslinux MBR code
+        SetMem(SectorBuffer, MBR_BOOTCODE_SIZE, 0);
+        CopyMem(SectorBuffer, syslinux_mbr, SYSLINUX_MBR_SIZE);
+    }
+
+    // set the partition active
+    MbrTable = (MBR_PARTITION_INFO *)(SectorBuffer + 446);
+    ExtBase = 0;
+    for (i = 0; i < 4; i++) {
+        if (MbrTable[i].Flags != 0x00 && MbrTable[i].Flags != 0x80)
+            return EFI_NOT_FOUND;   // safety measure #2
+        if (i == PartitionIndex)
+            MbrTable[i].Flags = 0x80;
+        else if (PartitionIndex >= 4 && IS_EXTENDED_PART_TYPE(MbrTable[i].Type)) {
+            MbrTable[i].Flags = 0x80;
+            ExtBase = MbrTable[i].StartLBA;
+        } else
+            MbrTable[i].Flags = 0x00;
+    }
+
+    // write MBR
+    Status = refit_call5_wrapper(BlockIO->WriteBlocks, BlockIO, BlockIO->Media->MediaId, 0, 512, SectorBuffer);
+    if (EFI_ERROR(Status))
+        return Status;
+
+    if (PartitionIndex >= 4) {
+        // we have to activate a logical partition, so walk the EMBR chain
+
+        // NOTE: ExtBase was set above while looking at the MBR table
+        for (ExtCurrent = ExtBase; ExtCurrent; ExtCurrent = NextExtCurrent) {
+            // read current EMBR
+            Status = refit_call5_wrapper(BlockIO->ReadBlocks, BlockIO, BlockIO->Media->MediaId, ExtCurrent, 512, SectorBuffer);
+            if (EFI_ERROR(Status))
+                return Status;
+            if (*((UINT16 *)(SectorBuffer + 510)) != 0xaa55)
+                return EFI_NOT_FOUND;  // safety measure #3
+
+            // scan EMBR, set appropriate partition active
+            EMbrTable = (MBR_PARTITION_INFO *)(SectorBuffer + 446);
+            NextExtCurrent = 0;
+            for (i = 0; i < 4; i++) {
+                if (EMbrTable[i].Flags != 0x00 && EMbrTable[i].Flags != 0x80)
+                    return EFI_NOT_FOUND;   // safety measure #4
+                if (EMbrTable[i].StartLBA == 0 || EMbrTable[i].Size == 0)
+                    break;
+                if (IS_EXTENDED_PART_TYPE(EMbrTable[i].Type)) {
+                    // link to next EMBR
+                    NextExtCurrent = ExtBase + EMbrTable[i].StartLBA;
+                    EMbrTable[i].Flags = (PartitionIndex >= LogicalPartitionIndex) ? 0x80 : 0x00;
+                    break;
+                } else {
+                    // logical partition
+                    EMbrTable[i].Flags = (PartitionIndex == LogicalPartitionIndex) ? 0x80 : 0x00;
+                    LogicalPartitionIndex++;
+                }
+            }
+
+            // write current EMBR
+            Status = refit_call5_wrapper(BlockIO->WriteBlocks, BlockIO, BlockIO->Media->MediaId, ExtCurrent, 512, SectorBuffer);
+            if (EFI_ERROR(Status))
+                return Status;
+
+            if (PartitionIndex < LogicalPartitionIndex)
+                break;  // stop the loop, no need to touch further EMBRs
+        }
+
+    }
+
+    return EFI_SUCCESS;
+} /* static EFI_STATUS ActivateMbrPartition() */
+
+static EFI_GUID AppleVariableVendorID = { 0x7C436110, 0xAB2A, 0x4BBB, 0xA8, 0x80, 0xFE, 0x41, 0x99, 0x5C, 0x9F, 0x82 };
+
+static EFI_STATUS WriteBootDiskHint(IN EFI_DEVICE_PATH *WholeDiskDevicePath)
+{
+   EFI_STATUS          Status;
+
+   Status = refit_call5_wrapper(RT->SetVariable, L"BootCampHD", &AppleVariableVendorID,
+                                EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+                                GetDevicePathSize(WholeDiskDevicePath), WholeDiskDevicePath);
+   if (EFI_ERROR(Status))
+      return Status;
+
+   return EFI_SUCCESS;
+}
+
+//
+// firmware device path discovery
+//
+
+static UINT8 LegacyLoaderMediaPathData[] = {
+    0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B,
+    0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B,
+    0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00,
+};
+static EFI_DEVICE_PATH *LegacyLoaderMediaPath = (EFI_DEVICE_PATH *)LegacyLoaderMediaPathData;
+
+static VOID ExtractLegacyLoaderPaths(EFI_DEVICE_PATH **PathList, UINTN MaxPaths, EFI_DEVICE_PATH **HardcodedPathList)
+{
+    EFI_STATUS          Status;
+    UINTN               HandleCount = 0;
+    UINTN               HandleIndex, HardcodedIndex;
+    EFI_HANDLE          *Handles;
+    EFI_HANDLE          Handle;
+    UINTN               PathCount = 0;
+    UINTN               PathIndex;
+    EFI_LOADED_IMAGE    *LoadedImage;
+    EFI_DEVICE_PATH     *DevicePath;
+    BOOLEAN             Seen;
+
+    MaxPaths--;  // leave space for the terminating NULL pointer
+
+    // get all LoadedImage handles
+    Status = LibLocateHandle(ByProtocol, &LoadedImageProtocol, NULL, &HandleCount, &Handles);
+    if (CheckError(Status, L"while listing LoadedImage handles")) {
+        if (HardcodedPathList) {
+            for (HardcodedIndex = 0; HardcodedPathList[HardcodedIndex] && PathCount < MaxPaths; HardcodedIndex++)
+                PathList[PathCount++] = HardcodedPathList[HardcodedIndex];
+        }
+        PathList[PathCount] = NULL;
+        return;
+    }
+    for (HandleIndex = 0; HandleIndex < HandleCount && PathCount < MaxPaths; HandleIndex++) {
+        Handle = Handles[HandleIndex];
+
+        Status = refit_call3_wrapper(BS->HandleProtocol, Handle, &LoadedImageProtocol, (VOID **) &LoadedImage);
+        if (EFI_ERROR(Status))
+            continue;  // This can only happen if the firmware scewed up, ignore it.
+
+        Status = refit_call3_wrapper(BS->HandleProtocol, LoadedImage->DeviceHandle, &DevicePathProtocol, (VOID **) &DevicePath);
+        if (EFI_ERROR(Status))
+            continue;  // This happens, ignore it.
+
+        // Only grab memory range nodes
+        if (DevicePathType(DevicePath) != HARDWARE_DEVICE_PATH || DevicePathSubType(DevicePath) != HW_MEMMAP_DP)
+            continue;
+
+        // Check if we have this device path in the list already
+        // WARNING: This assumes the first node in the device path is unique!
+        Seen = FALSE;
+        for (PathIndex = 0; PathIndex < PathCount; PathIndex++) {
+            if (DevicePathNodeLength(DevicePath) != DevicePathNodeLength(PathList[PathIndex]))
+                continue;
+            if (CompareMem(DevicePath, PathList[PathIndex], DevicePathNodeLength(DevicePath)) == 0) {
+                Seen = TRUE;
+                break;
+            }
+        }
+        if (Seen)
+            continue;
+
+        PathList[PathCount++] = AppendDevicePath(DevicePath, LegacyLoaderMediaPath);
+    }
+    MyFreePool(Handles);
+
+    if (HardcodedPathList) {
+        for (HardcodedIndex = 0; HardcodedPathList[HardcodedIndex] && PathCount < MaxPaths; HardcodedIndex++)
+            PathList[PathCount++] = HardcodedPathList[HardcodedIndex];
+    }
+    PathList[PathCount] = NULL;
+} /* VOID ExtractLegacyLoaderPaths() */
+
+// early 2006 Core Duo / Core Solo models
+static UINT8 LegacyLoaderDevicePath1Data[] = {
+    0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0x00, 0x00,
+    0xFF, 0xFF, 0xF9, 0xFF, 0x00, 0x00, 0x00, 0x00,
+    0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B,
+    0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B,
+    0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00,
+};
+// mid-2006 Mac Pro (and probably other Core 2 models)
+static UINT8 LegacyLoaderDevicePath2Data[] = {
+    0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0x00, 0x00,
+    0xFF, 0xFF, 0xF7, 0xFF, 0x00, 0x00, 0x00, 0x00,
+    0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B,
+    0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B,
+    0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00,
+};
+// mid-2007 MBP ("Santa Rosa" based models)
+static UINT8 LegacyLoaderDevicePath3Data[] = {
+    0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0x00, 0x00,
+    0xFF, 0xFF, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0x00,
+    0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B,
+    0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B,
+    0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00,
+};
+// early-2008 MBA
+static UINT8 LegacyLoaderDevicePath4Data[] = {
+    0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0xC0, 0xFF, 0x00, 0x00, 0x00, 0x00,
+    0xFF, 0xFF, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0x00,
+    0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B,
+    0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B,
+    0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00,
+};
+// late-2008 MB/MBP (NVidia chipset)
+static UINT8 LegacyLoaderDevicePath5Data[] = {
+    0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00,
+    0x00, 0x40, 0xCB, 0xFF, 0x00, 0x00, 0x00, 0x00,
+    0xFF, 0xBF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
+    0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B,
+    0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B,
+    0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00,
+};
+
+static EFI_DEVICE_PATH *LegacyLoaderList[] = {
+    (EFI_DEVICE_PATH *)LegacyLoaderDevicePath1Data,
+    (EFI_DEVICE_PATH *)LegacyLoaderDevicePath2Data,
+    (EFI_DEVICE_PATH *)LegacyLoaderDevicePath3Data,
+    (EFI_DEVICE_PATH *)LegacyLoaderDevicePath4Data,
+    (EFI_DEVICE_PATH *)LegacyLoaderDevicePath5Data,
+    NULL
+};
+
+#define MAX_DISCOVERED_PATHS (16)
+
+VOID StartLegacy(IN LEGACY_ENTRY *Entry, IN CHAR16 *SelectionName)
+{
+    EFI_STATUS          Status;
+    EG_IMAGE            *BootLogoImage;
+    UINTN               ErrorInStep = 0;
+    EFI_DEVICE_PATH     *DiscoveredPathList[MAX_DISCOVERED_PATHS];
+
+    BeginExternalScreen(TRUE, L"Booting Legacy OS (Mac mode)");
+
+    BootLogoImage = LoadOSIcon(Entry->Volume->OSIconName, L"legacy", TRUE);
+    if (BootLogoImage != NULL)
+        BltImageAlpha(BootLogoImage,
+                      (UGAWidth  - BootLogoImage->Width ) >> 1,
+                      (UGAHeight - BootLogoImage->Height) >> 1,
+                      &StdBackgroundPixel);
+
+    if (Entry->Volume->IsMbrPartition)
+        ActivateMbrPartition(Entry->Volume->WholeDiskBlockIO, Entry->Volume->MbrPartitionIndex);
+
+    if (Entry->Volume->DiskKind != DISK_KIND_OPTICAL && Entry->Volume->WholeDiskDevicePath != NULL)
+       WriteBootDiskHint(Entry->Volume->WholeDiskDevicePath);
+
+    ExtractLegacyLoaderPaths(DiscoveredPathList, MAX_DISCOVERED_PATHS, LegacyLoaderList);
+
+    StoreLoaderName(SelectionName);
+    Status = StartEFIImageList(DiscoveredPathList, Entry->LoadOptions, TYPE_LEGACY, L"legacy loader", 0, &ErrorInStep, TRUE, FALSE);
+    if (Status == EFI_NOT_FOUND) {
+        if (ErrorInStep == 1) {
+            Print(L"\nPlease make sure that you have the latest firmware update installed.\n");
+        } else if (ErrorInStep == 3) {
+            Print(L"\nThe firmware refused to boot from the selected volume. Note that external\n"
+                  L"hard drives are not well-supported by Apple's firmware for legacy OS booting.\n");
+        }
+    }
+    FinishExternalScreen();
+} /* static VOID StartLegacy() */
+
+// Start a device on a non-Mac using the EFI_LEGACY_BIOS_PROTOCOL
+VOID StartLegacyUEFI(LEGACY_ENTRY *Entry, CHAR16 *SelectionName)
+{
+    BeginExternalScreen(TRUE, L"Booting Legacy OS (UEFI mode)");
+    StoreLoaderName(SelectionName);
+
+    BdsLibConnectDevicePath (Entry->BdsOption->DevicePath);
+    BdsLibDoLegacyBoot(Entry->BdsOption);
+
+    // If we get here, it means that there was a failure....
+    Print(L"Failure booting legacy (BIOS) OS.");
+    PauseForKey();
+    FinishExternalScreen();
+} // static VOID StartLegacyUEFI()
+
+static LEGACY_ENTRY * AddLegacyEntry(IN CHAR16 *LoaderTitle, IN REFIT_VOLUME *Volume)
+{
+    LEGACY_ENTRY            *Entry, *SubEntry;
+    REFIT_MENU_SCREEN       *SubScreen;
+    CHAR16                  *VolDesc, *LegacyTitle;
+    CHAR16                  ShortcutLetter = 0;
+
+    if (LoaderTitle == NULL) {
+        if (Volume->OSName != NULL) {
+            LoaderTitle = Volume->OSName;
+            if (LoaderTitle[0] == 'W' || LoaderTitle[0] == 'L')
+                ShortcutLetter = LoaderTitle[0];
+        } else
+            LoaderTitle = L"Legacy OS";
+    }
+    if (Volume->VolName != NULL)
+        VolDesc = Volume->VolName;
+    else
+        VolDesc = (Volume->DiskKind == DISK_KIND_OPTICAL) ? L"CD" : L"HD";
+
+    LegacyTitle = AllocateZeroPool(256 * sizeof(CHAR16));
+    if (LegacyTitle != NULL)
+       SPrint(LegacyTitle, 255, L"Boot %s from %s", LoaderTitle, VolDesc);
+    if (IsInSubstring(LegacyTitle, GlobalConfig.DontScanVolumes)) {
+       MyFreePool(LegacyTitle);
+       return NULL;
+    } // if
+
+    // prepare the menu entry
+    Entry = AllocateZeroPool(sizeof(LEGACY_ENTRY));
+    Entry->me.Title = LegacyTitle;
+    Entry->me.Tag          = TAG_LEGACY;
+    Entry->me.Row          = 0;
+    Entry->me.ShortcutLetter = ShortcutLetter;
+    Entry->me.Image        = LoadOSIcon(Volume->OSIconName, L"legacy", FALSE);
+    Entry->me.BadgeImage   = Volume->VolBadgeImage;
+    Entry->Volume          = Volume;
+    Entry->LoadOptions     = (Volume->DiskKind == DISK_KIND_OPTICAL) ? L"CD" :
+                              ((Volume->DiskKind == DISK_KIND_EXTERNAL) ? L"USB" : L"HD");
+    Entry->Enabled         = TRUE;
+
+    // create the submenu
+    SubScreen = AllocateZeroPool(sizeof(REFIT_MENU_SCREEN));
+    SubScreen->Title = AllocateZeroPool(256 * sizeof(CHAR16));
+    SPrint(SubScreen->Title, 255, L"Boot Options for %s on %s", LoaderTitle, VolDesc);
+    SubScreen->TitleImage = Entry->me.Image;
+    SubScreen->Hint1 = StrDuplicate(SUBSCREEN_HINT1);
+    if (GlobalConfig.HideUIFlags & HIDEUI_FLAG_EDITOR) {
+       SubScreen->Hint2 = StrDuplicate(SUBSCREEN_HINT2_NO_EDITOR);
+    } else {
+       SubScreen->Hint2 = StrDuplicate(SUBSCREEN_HINT2);
+    } // if/else
+
+    // default entry
+    SubEntry = AllocateZeroPool(sizeof(LEGACY_ENTRY));
+    SubEntry->me.Title = AllocateZeroPool(256 * sizeof(CHAR16));
+    SPrint(SubEntry->me.Title, 255, L"Boot %s", LoaderTitle);
+    SubEntry->me.Tag          = TAG_LEGACY;
+    SubEntry->Volume          = Entry->Volume;
+    SubEntry->LoadOptions     = Entry->LoadOptions;
+    AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry);
+
+    AddMenuEntry(SubScreen, &MenuEntryReturn);
+    Entry->me.SubScreen = SubScreen;
+    AddMenuEntry(&MainMenu, (REFIT_MENU_ENTRY *)Entry);
+    return Entry;
+} /* static LEGACY_ENTRY * AddLegacyEntry() */
+
+
+/**
+    Create a rEFInd boot option from a Legacy BIOS protocol option.
+*/
+static LEGACY_ENTRY * AddLegacyEntryUEFI(BDS_COMMON_OPTION *BdsOption, IN UINT16 DiskType)
+{
+    LEGACY_ENTRY            *Entry, *SubEntry;
+    REFIT_MENU_SCREEN       *SubScreen;
+    CHAR16                  ShortcutLetter = 0;
+    CHAR16 *LegacyDescription = StrDuplicate(BdsOption->Description);
+
+    if (IsInSubstring(LegacyDescription, GlobalConfig.DontScanVolumes))
+       return NULL;
+
+    // Remove stray spaces, since many EFIs produce descriptions with lots of
+    // extra spaces, especially at the end; this throws off centering of the
+    // description on the screen....
+    LimitStringLength(LegacyDescription, 100);
+
+    // prepare the menu entry
+    Entry = AllocateZeroPool(sizeof(LEGACY_ENTRY));
+    Entry->me.Title = AllocateZeroPool(256 * sizeof(CHAR16));
+    SPrint(Entry->me.Title, 255, L"Boot legacy target %s", LegacyDescription);
+    Entry->me.Tag          = TAG_LEGACY_UEFI;
+    Entry->me.Row          = 0;
+    Entry->me.ShortcutLetter = ShortcutLetter;
+    Entry->me.Image        = LoadOSIcon(L"legacy", L"legacy", TRUE);
+    Entry->LoadOptions     = (DiskType == BBS_CDROM) ? L"CD" :
+                             ((DiskType == BBS_USB) ? L"USB" : L"HD");
+    Entry->me.BadgeImage   = GetDiskBadge(DiskType);
+    Entry->BdsOption       = BdsOption;
+    Entry->Enabled         = TRUE;
+
+    // create the submenu
+    SubScreen = AllocateZeroPool(sizeof(REFIT_MENU_SCREEN));
+    SubScreen->Title = AllocateZeroPool(256 * sizeof(CHAR16));
+    SPrint(SubScreen->Title, 255, L"No boot options for legacy target");
+    SubScreen->TitleImage = Entry->me.Image;
+    SubScreen->Hint1 = StrDuplicate(SUBSCREEN_HINT1);
+    if (GlobalConfig.HideUIFlags & HIDEUI_FLAG_EDITOR) {
+       SubScreen->Hint2 = StrDuplicate(SUBSCREEN_HINT2_NO_EDITOR);
+    } else {
+       SubScreen->Hint2 = StrDuplicate(SUBSCREEN_HINT2);
+    } // if/else
+
+    // default entry
+    SubEntry = AllocateZeroPool(sizeof(LEGACY_ENTRY));
+    SubEntry->me.Title = AllocateZeroPool(256 * sizeof(CHAR16));
+    SPrint(SubEntry->me.Title, 255, L"Boot %s", LegacyDescription);
+    SubEntry->me.Tag          = TAG_LEGACY_UEFI;
+    Entry->BdsOption          = BdsOption; 
+    AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry);
+
+    AddMenuEntry(SubScreen, &MenuEntryReturn);
+    Entry->me.SubScreen = SubScreen;
+    AddMenuEntry(&MainMenu, (REFIT_MENU_ENTRY *)Entry);
+    return Entry;
+} /* static LEGACY_ENTRY * AddLegacyEntryUEFI() */
+
+/**
+    Scan for legacy BIOS targets on machines that implement EFI_LEGACY_BIOS_PROTOCOL.
+    In testing, protocol has not been implemented on Macs but has been
+    implemented on most UEFI PCs.
+    Restricts output to disks of the specified DiskType.
+*/
+static VOID ScanLegacyUEFI(IN UINTN DiskType)
+{
+    EFI_STATUS                Status;
+    EFI_LEGACY_BIOS_PROTOCOL  *LegacyBios;
+    UINT16                    *BootOrder = NULL;
+    UINTN                     Index = 0;
+    CHAR16                    BootOption[10];
+    UINTN                     BootOrderSize = 0;
+    CHAR16                    Buffer[20];
+    BDS_COMMON_OPTION         *BdsOption;
+    LIST_ENTRY                TempList;
+    BBS_BBS_DEVICE_PATH       *BbsDevicePath = NULL;
+    BOOLEAN                   SearchingForUsb = FALSE;
+
+    InitializeListHead (&TempList);
+    ZeroMem (Buffer, sizeof (Buffer));
+
+    // If LegacyBios protocol is not implemented on this platform, then
+    //we do not support this type of legacy boot on this machine.
+    Status = refit_call3_wrapper(gBS->LocateProtocol, &gEfiLegacyBootProtocolGuid, NULL, (VOID **) &LegacyBios);
+    if (EFI_ERROR (Status))
+       return;
+
+    // EFI calls USB drives BBS_HARDDRIVE, but we want to distinguish them,
+    // so we set DiskType inappropriately elsewhere in the program and
+    // "translate" it here.
+    if (DiskType == BBS_USB) {
+       DiskType = BBS_HARDDISK;
+       SearchingForUsb = TRUE;
+    } // if
+
+    // Grab the boot order
+    BootOrder = BdsLibGetVariableAndSize(L"BootOrder", &gEfiGlobalVariableGuid, &BootOrderSize);
+    if (BootOrder == NULL) {
+        BootOrderSize = 0;
+    }
+
+    Index = 0;
+    while (Index < BootOrderSize / sizeof (UINT16))
+    {
+        // Grab each boot option variable from the boot order, and convert
+        // the variable into a BDS boot option
+        UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);
+        BdsOption = BdsLibVariableToOption (&TempList, BootOption);
+
+        if (BdsOption != NULL) {
+           BbsDevicePath = (BBS_BBS_DEVICE_PATH *)BdsOption->DevicePath;
+           // Only add the entry if it is of a requested type (e.g. USB, HD)
+           // Two checks necessary because some systems return EFI boot loaders
+           // with a DeviceType value that would inappropriately include them
+           // as legacy loaders....
+           if ((BbsDevicePath->DeviceType == DiskType) && (BdsOption->DevicePath->Type == DEVICE_TYPE_BIOS)) {
+              // USB flash drives appear as hard disks with certain media flags set.
+              // Look for this, and if present, pass it on with the (technically
+              // incorrect, but internally useful) BBS_TYPE_USB flag set.
+              if (DiskType == BBS_HARDDISK) {
+                 if (SearchingForUsb && (BbsDevicePath->StatusFlag & (BBS_MEDIA_PRESENT | BBS_MEDIA_MAYBE_PRESENT))) {
+                    AddLegacyEntryUEFI(BdsOption, BBS_USB);
+                 } else if (!SearchingForUsb && !(BbsDevicePath->StatusFlag & (BBS_MEDIA_PRESENT | BBS_MEDIA_MAYBE_PRESENT))) {
+                    AddLegacyEntryUEFI(BdsOption, DiskType);
+                 }
+              } else {
+                 AddLegacyEntryUEFI(BdsOption, DiskType);
+              } // if/else
+           } // if
+        } // if (BdsOption != NULL)
+        Index++;
+    } // while
+} /* static VOID ScanLegacyUEFI() */
+
+static VOID ScanLegacyVolume(REFIT_VOLUME *Volume, UINTN VolumeIndex) {
+   UINTN VolumeIndex2;
+   BOOLEAN ShowVolume, HideIfOthersFound;
+
+   ShowVolume = FALSE;
+   HideIfOthersFound = FALSE;
+   if (Volume->IsAppleLegacy) {
+      ShowVolume = TRUE;
+      HideIfOthersFound = TRUE;
+   } else if (Volume->HasBootCode) {
+      ShowVolume = TRUE;
+      if (Volume->BlockIO == Volume->WholeDiskBlockIO &&
+         Volume->BlockIOOffset == 0 &&
+         Volume->OSName == NULL)
+         // this is a whole disk (MBR) entry; hide if we have entries for partitions
+         HideIfOthersFound = TRUE;
+   }
+   if (HideIfOthersFound) {
+      // check for other bootable entries on the same disk
+      for (VolumeIndex2 = 0; VolumeIndex2 < VolumesCount; VolumeIndex2++) {
+         if (VolumeIndex2 != VolumeIndex && Volumes[VolumeIndex2]->HasBootCode &&
+             Volumes[VolumeIndex2]->WholeDiskBlockIO == Volume->WholeDiskBlockIO)
+            ShowVolume = FALSE;
+      }
+   }
+
+   if (ShowVolume)
+      AddLegacyEntry(NULL, Volume);
+} // static VOID ScanLegacyVolume()
+
+// Scan attached optical discs for legacy (BIOS) boot code
+// and add anything found to the list....
+VOID ScanLegacyDisc(VOID)
+{
+   UINTN                   VolumeIndex;
+   REFIT_VOLUME            *Volume;
+
+   if (GlobalConfig.LegacyType == LEGACY_TYPE_MAC) {
+      for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) {
+         Volume = Volumes[VolumeIndex];
+         if (Volume->DiskKind == DISK_KIND_OPTICAL)
+            ScanLegacyVolume(Volume, VolumeIndex);
+      } // for
+   } else if (GlobalConfig.LegacyType == LEGACY_TYPE_UEFI) {
+      ScanLegacyUEFI(BBS_CDROM);
+   }
+} /* VOID ScanLegacyDisc() */
+
+// Scan internal hard disks for legacy (BIOS) boot code
+// and add anything found to the list....
+VOID ScanLegacyInternal(VOID)
+{
+    UINTN                   VolumeIndex;
+    REFIT_VOLUME            *Volume;
+
+    if (GlobalConfig.LegacyType == LEGACY_TYPE_MAC) {
+       for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) {
+           Volume = Volumes[VolumeIndex];
+           if (Volume->DiskKind == DISK_KIND_INTERNAL)
+               ScanLegacyVolume(Volume, VolumeIndex);
+       } // for
+    } else if (GlobalConfig.LegacyType == LEGACY_TYPE_UEFI) {
+       // TODO: This actually picks up USB flash drives, too; try to find
+       // a way to differentiate the two....
+       ScanLegacyUEFI(BBS_HARDDISK);
+    }
+} /* VOID ScanLegacyInternal() */
+
+// Scan external disks for legacy (BIOS) boot code
+// and add anything found to the list....
+VOID ScanLegacyExternal(VOID)
+{
+   UINTN                   VolumeIndex;
+   REFIT_VOLUME            *Volume;
+
+   if (GlobalConfig.LegacyType == LEGACY_TYPE_MAC) {
+      for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) {
+         Volume = Volumes[VolumeIndex];
+         if (Volume->DiskKind == DISK_KIND_EXTERNAL)
+            ScanLegacyVolume(Volume, VolumeIndex);
+      } // for
+   } else if (GlobalConfig.LegacyType == LEGACY_TYPE_UEFI) {
+      // TODO: This actually doesn't do anything useful; leaving in hopes of
+      // fixing it later....
+      ScanLegacyUEFI(BBS_USB);
+   }
+} /* VOID ScanLegacyExternal() */
+
+// Determine what (if any) type of legacy (BIOS) boot support is available
+VOID FindLegacyBootType(VOID) {
+   EFI_STATUS                Status;
+   EFI_LEGACY_BIOS_PROTOCOL  *LegacyBios;
+
+   GlobalConfig.LegacyType = LEGACY_TYPE_NONE;
+
+   // UEFI-style legacy BIOS support is available only with some EFI implementations....
+   Status = refit_call3_wrapper(gBS->LocateProtocol, &gEfiLegacyBootProtocolGuid, NULL, (VOID **) &LegacyBios);
+   if (!EFI_ERROR (Status))
+      GlobalConfig.LegacyType = LEGACY_TYPE_UEFI;
+
+   // Macs have their own system. If the firmware vendor code contains the
+   // string "Apple", assume it's available. Note that this overrides the
+   // UEFI type, and might yield false positives if the vendor string
+   // contains "Apple" as part of something bigger, so this isn't 100%
+   // perfect.
+   if (StriSubCmp(L"Apple", ST->FirmwareVendor))
+      GlobalConfig.LegacyType = LEGACY_TYPE_MAC;
+} // VOID FindLegacyBootType
+
+// Warn the user if legacy OS scans are enabled but the firmware can't support them....
+VOID WarnIfLegacyProblems(VOID) {
+   BOOLEAN  found = FALSE;
+   UINTN    i = 0;
+
+   if (GlobalConfig.LegacyType == LEGACY_TYPE_NONE) {
+      do {
+         if (GlobalConfig.ScanFor[i] == 'h' || GlobalConfig.ScanFor[i] == 'b' || GlobalConfig.ScanFor[i] == 'c' ||
+             GlobalConfig.ScanFor[i] == 'H' || GlobalConfig.ScanFor[i] == 'B' || GlobalConfig.ScanFor[i] == 'C')
+            found = TRUE;
+         i++;
+      } while ((i < NUM_SCAN_OPTIONS) && (!found));
+
+      if (found) {
+         Print(L"NOTE: refind.conf's 'scanfor' line specifies scanning for one or more legacy\n");
+         Print(L"(BIOS) boot options; however, this is not possible because your computer lacks\n");
+         Print(L"the necessary Compatibility Support Module (CSM) support or that support is\n");
+         Print(L"disabled in your firmware.\n");
+         PauseForKey();
+      } // if (found)
+   } // if no legacy support
+} // VOID WarnIfLegacyProblems()
+
diff --git a/refind/legacy.h b/refind/legacy.h
new file mode 100644 (file)
index 0000000..3da42f2
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * refind/legacy.h
+ * Functions related to BIOS/CSM/legacy booting
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Modifications copyright (c) 2012-2015 Roderick W. Smith
+ *
+ * Modifications distributed under the terms of the GNU General Public
+ * License (GPL) version 3 (GPLv3), a copy of which must be distributed
+ * with this source code or binaries made from it.
+ *
+ */
+
+#include "global.h"
+
+VOID StartLegacy(IN LEGACY_ENTRY *Entry, IN CHAR16 *SelectionName);
+VOID StartLegacyUEFI(LEGACY_ENTRY *Entry, CHAR16 *SelectionName);
+VOID ScanLegacyDisc(VOID);
+VOID ScanLegacyInternal(VOID);
+VOID ScanLegacyExternal(VOID);
+VOID FindLegacyBootType(VOID);
+VOID WarnIfLegacyProblems(VOID);
diff --git a/refind/lib.c b/refind/lib.c
new file mode 100644 (file)
index 0000000..5bc1828
--- /dev/null
@@ -0,0 +1,1741 @@
+/*
+ * refind/lib.c
+ * General library functions
+ *
+ * Copyright (c) 2006-2009 Christoph Pfisterer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Modifications copyright (c) 2012-2015 Roderick W. Smith
+ *
+ * Modifications distributed under the terms of the GNU General Public
+ * License (GPL) version 3 (GPLv3), or (at your option) any later version.
+ *
+ */
+/*
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "global.h"
+#include "lib.h"
+#include "icns.h"
+#include "screen.h"
+#include "../include/refit_call_wrapper.h"
+#include "../include/RemovableMedia.h"
+#include "gpt.h"
+#include "config.h"
+#include "mystrings.h"
+
+#ifdef __MAKEWITH_GNUEFI
+#define EfiReallocatePool ReallocatePool
+#else
+#define LibLocateHandle gBS->LocateHandleBuffer
+#define DevicePathProtocol gEfiDevicePathProtocolGuid
+#define BlockIoProtocol gEfiBlockIoProtocolGuid
+#define LibFileSystemInfo EfiLibFileSystemInfo
+#define LibOpenRoot EfiLibOpenRoot
+EFI_DEVICE_PATH EndDevicePath[] = {
+   {END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, {END_DEVICE_PATH_LENGTH, 0}}
+};
+#endif
+
+// "Magic" signatures for various filesystems
+#define FAT_MAGIC                        0xAA55
+#define EXT2_SUPER_MAGIC                 0xEF53
+#define HFSPLUS_MAGIC1                   0x2B48
+#define HFSPLUS_MAGIC2                   0x5848
+#define REISERFS_SUPER_MAGIC_STRING      "ReIsErFs"
+#define REISER2FS_SUPER_MAGIC_STRING     "ReIsEr2Fs"
+#define REISER2FS_JR_SUPER_MAGIC_STRING  "ReIsEr3Fs"
+#define BTRFS_SIGNATURE                  "_BHRfS_M"
+#define XFS_SIGNATURE                    "XFSB"
+#define NTFS_SIGNATURE                   "NTFS    "
+
+// variables
+
+EFI_HANDLE       SelfImageHandle;
+EFI_LOADED_IMAGE *SelfLoadedImage;
+EFI_FILE         *SelfRootDir;
+EFI_FILE         *SelfDir;
+CHAR16           *SelfDirPath;
+
+REFIT_VOLUME     *SelfVolume = NULL;
+REFIT_VOLUME     **Volumes = NULL;
+UINTN            VolumesCount = 0;
+extern GPT_DATA *gPartitions;
+
+// Maximum size for disk sectors
+#define SECTOR_SIZE 4096
+
+// Number of bytes to read from a partition to determine its filesystem type
+// and identify its boot loader, and hence probable BIOS-mode OS installation
+#define SAMPLE_SIZE 69632 /* 68 KiB -- ReiserFS superblock begins at 64 KiB */
+
+//
+// Pathname manipulations
+//
+
+// Converts forward slashes to backslashes, removes duplicate slashes, and
+// removes slashes from both the start and end of the pathname.
+// Necessary because some (buggy?) EFI implementations produce "\/" strings
+// in pathnames, because some user inputs can produce duplicate directory
+// separators, and because we want consistent start and end slashes for
+// directory comparisons. A special case: If the PathName refers to root,
+// return "/", since some firmware implementations flake out if this
+// isn't present.
+VOID CleanUpPathNameSlashes(IN OUT CHAR16 *PathName) {
+    CHAR16   *NewName;
+    UINTN    i, Length, FinalChar = 0;
+    BOOLEAN  LastWasSlash = FALSE;
+
+    Length = StrLen(PathName);
+    NewName = AllocateZeroPool(sizeof(CHAR16) * (Length + 2));
+    if (NewName != NULL) {
+        for (i = 0; i < Length; i++) {
+            if ((PathName[i] == L'/') || (PathName[i] == L'\\')) {
+                if ((!LastWasSlash) && (FinalChar != 0))
+                    NewName[FinalChar++] = L'\\';
+                LastWasSlash = TRUE;
+            } else {
+                NewName[FinalChar++] = PathName[i];
+                LastWasSlash = FALSE;
+            } // if/else
+        } // for
+        NewName[FinalChar] = 0;
+        if ((FinalChar > 0) && (NewName[FinalChar - 1] == L'\\'))
+            NewName[--FinalChar] = 0;
+        if (FinalChar == 0) {
+            NewName[0] = L'\\';
+            NewName[1] = 0;
+        }
+        // Copy the transformed name back....
+        StrCpy(PathName, NewName);
+        FreePool(NewName);
+    } // if allocation OK
+} // CleanUpPathNameSlashes()
+
+// Splits an EFI device path into device and filename components. For instance, if InString is
+// PciRoot(0x0)/Pci(0x1f,0x2)/Ata(Secondary,Master,0x0)/HD(2,GPT,8314ae90-ada3-48e9-9c3b-09a88f80d921,0x96028,0xfa000)/\bzImage-3.5.1.efi,
+// this function will truncate that input to
+// PciRoot(0x0)/Pci(0x1f,0x2)/Ata(Secondary,Master,0x0)/HD(2,GPT,8314ae90-ada3-48e9-9c3b-09a88f80d921,0x96028,0xfa000)
+// and return bzImage-3.5.1.efi as its return value.
+// It does this by searching for the last ")" character in InString, copying everything
+// after that string (after some cleanup) as the return value, and truncating the original
+// input value.
+// If InString contains no ")" character, this function leaves the original input string
+// unmodified and also returns that string. If InString is NULL, this function returns NULL.
+static CHAR16* SplitDeviceString(IN OUT CHAR16 *InString) {
+    INTN i;
+    CHAR16 *FileName = NULL;
+    BOOLEAN Found = FALSE;
+
+    if (InString != NULL) {
+        i = StrLen(InString) - 1;
+        while ((i >= 0) && (!Found)) {
+            if (InString[i] == L')') {
+                Found = TRUE;
+                FileName = StrDuplicate(&InString[i + 1]);
+                CleanUpPathNameSlashes(FileName);
+                InString[i + 1] = '\0';
+            } // if
+            i--;
+        } // while
+        if (FileName == NULL)
+            FileName = StrDuplicate(InString);
+    } // if
+    return FileName;
+} // static CHAR16* SplitDeviceString()
+
+//
+// Library initialization and de-initialization
+//
+
+static EFI_STATUS FinishInitRefitLib(VOID)
+{
+    EFI_STATUS  Status;
+
+    if (SelfRootDir == NULL) {
+        SelfRootDir = LibOpenRoot(SelfLoadedImage->DeviceHandle);
+        if (SelfRootDir == NULL) {
+            CheckError(EFI_LOAD_ERROR, L"while (re)opening our installation volume");
+            return EFI_LOAD_ERROR;
+        }
+    }
+
+    Status = refit_call5_wrapper(SelfRootDir->Open, SelfRootDir, &SelfDir, SelfDirPath, EFI_FILE_MODE_READ, 0);
+    if (CheckFatalError(Status, L"while opening our installation directory"))
+        return EFI_LOAD_ERROR;
+
+    return EFI_SUCCESS;
+}
+
+EFI_STATUS InitRefitLib(IN EFI_HANDLE ImageHandle)
+{
+    EFI_STATUS  Status;
+    CHAR16      *DevicePathAsString, *Temp;
+
+    SelfImageHandle = ImageHandle;
+    Status = refit_call3_wrapper(BS->HandleProtocol, SelfImageHandle, &LoadedImageProtocol, (VOID **) &SelfLoadedImage);
+    if (CheckFatalError(Status, L"while getting a LoadedImageProtocol handle"))
+        return EFI_LOAD_ERROR;
+
+    // find the current directory
+    DevicePathAsString = DevicePathToStr(SelfLoadedImage->FilePath);
+    GlobalConfig.SelfDevicePath = FileDevicePath(SelfLoadedImage->DeviceHandle, DevicePathAsString);
+    CleanUpPathNameSlashes(DevicePathAsString);
+    MyFreePool(SelfDirPath);
+    Temp = FindPath(DevicePathAsString);
+    SelfDirPath = SplitDeviceString(Temp);
+    MyFreePool(DevicePathAsString);
+    MyFreePool(Temp);
+
+    return FinishInitRefitLib();
+}
+
+static VOID UninitVolumes(VOID)
+{
+    REFIT_VOLUME            *Volume;
+    UINTN                   VolumeIndex;
+
+    for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) {
+        Volume = Volumes[VolumeIndex];
+
+        if (Volume->RootDir != NULL) {
+            refit_call1_wrapper(Volume->RootDir->Close, Volume->RootDir);
+            Volume->RootDir = NULL;
+        }
+
+        Volume->DeviceHandle = NULL;
+        Volume->BlockIO = NULL;
+        Volume->WholeDiskBlockIO = NULL;
+    }
+} /* VOID UninitVolumes() */
+
+VOID ReinitVolumes(VOID)
+{
+    EFI_STATUS              Status;
+    REFIT_VOLUME            *Volume;
+    UINTN                   VolumeIndex;
+    EFI_DEVICE_PATH         *RemainingDevicePath;
+    EFI_HANDLE              DeviceHandle, WholeDiskHandle;
+
+    for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) {
+        Volume = Volumes[VolumeIndex];
+
+        if (Volume->DevicePath != NULL) {
+            // get the handle for that path
+            RemainingDevicePath = Volume->DevicePath;
+            Status = refit_call3_wrapper(BS->LocateDevicePath, &BlockIoProtocol, &RemainingDevicePath, &DeviceHandle);
+
+            if (!EFI_ERROR(Status)) {
+                Volume->DeviceHandle = DeviceHandle;
+
+                // get the root directory
+                Volume->RootDir = LibOpenRoot(Volume->DeviceHandle);
+
+            } else
+                CheckError(Status, L"from LocateDevicePath");
+        }
+
+        if (Volume->WholeDiskDevicePath != NULL) {
+            // get the handle for that path
+            RemainingDevicePath = Volume->WholeDiskDevicePath;
+            Status = refit_call3_wrapper(BS->LocateDevicePath, &BlockIoProtocol, &RemainingDevicePath, &WholeDiskHandle);
+
+            if (!EFI_ERROR(Status)) {
+                // get the BlockIO protocol
+                Status = refit_call3_wrapper(BS->HandleProtocol, WholeDiskHandle, &BlockIoProtocol,
+                                             (VOID **) &Volume->WholeDiskBlockIO);
+                if (EFI_ERROR(Status)) {
+                    Volume->WholeDiskBlockIO = NULL;
+                    CheckError(Status, L"from HandleProtocol");
+                }
+            } else
+                CheckError(Status, L"from LocateDevicePath");
+        }
+    }
+} /* VOID ReinitVolumes(VOID) */
+
+// called before running external programs to close open file handles
+VOID UninitRefitLib(VOID)
+{
+    // This piece of code was made to correspond to weirdness in ReinitRefitLib().
+    // See the comment on it there.
+    if(SelfRootDir == SelfVolume->RootDir)
+        SelfRootDir=0;
+
+    UninitVolumes();
+
+    if (SelfDir != NULL) {
+        refit_call1_wrapper(SelfDir->Close, SelfDir);
+        SelfDir = NULL;
+    }
+
+    if (SelfRootDir != NULL) {
+       refit_call1_wrapper(SelfRootDir->Close, SelfRootDir);
+       SelfRootDir = NULL;
+    }
+} /* VOID UninitRefitLib() */
+
+// called after running external programs to re-open file handles
+EFI_STATUS ReinitRefitLib(VOID)
+{
+    ReinitVolumes();
+
+    if ((ST->Hdr.Revision >> 16) == 1) {
+       // Below two lines were in rEFIt, but seem to cause system crashes or
+       // reboots when launching OSes after returning from programs on most
+       // systems. OTOH, my Mac Mini produces errors about "(re)opening our
+       // installation volume" (see the next function) when returning from
+       // programs when these two lines are removed, and it often crashes
+       // when returning from a program or when launching a second program
+       // with these lines removed. Therefore, the preceding if() statement
+       // executes these lines only on EFIs with a major version number of 1
+       // (which Macs have) and not with 2 (which UEFI PCs have). My selection
+       // of hardware on which to test is limited, though, so this may be the
+       // wrong test, or there may be a better way to fix this problem.
+       // TODO: Figure out cause of above weirdness and fix it more
+       // reliably!
+       if (SelfVolume != NULL && SelfVolume->RootDir != NULL)
+          SelfRootDir = SelfVolume->RootDir;
+    } // if
+
+    return FinishInitRefitLib();
+}
+
+//
+// EFI variable read and write functions
+//
+
+// From gummiboot: Retrieve a raw EFI variable.
+// Returns EFI status
+EFI_STATUS EfivarGetRaw(EFI_GUID *vendor, CHAR16 *name, CHAR8 **buffer, UINTN *size) {
+   CHAR8 *buf;
+   UINTN l;
+   EFI_STATUS err;
+
+   l = sizeof(CHAR16 *) * EFI_MAXIMUM_VARIABLE_SIZE;
+   buf = AllocatePool(l);
+   if (!buf)
+      return EFI_OUT_OF_RESOURCES;
+
+   err = refit_call5_wrapper(RT->GetVariable, name, vendor, NULL, &l, buf);
+   if (EFI_ERROR(err) == EFI_SUCCESS) {
+      *buffer = buf;
+      if (size)
+         *size = l;
+   } else
+      MyFreePool(buf);
+   return err;
+} // EFI_STATUS EfivarGetRaw()
+
+// From gummiboot: Set an EFI variable
+EFI_STATUS EfivarSetRaw(EFI_GUID *vendor, CHAR16 *name, CHAR8 *buf, UINTN size, BOOLEAN persistent) {
+   UINT32 flags;
+
+   flags = EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS;
+   if (persistent)
+      flags |= EFI_VARIABLE_NON_VOLATILE;
+
+   return refit_call5_wrapper(RT->SetVariable, name, vendor, flags, size, buf);
+} // EFI_STATUS EfivarSetRaw()
+
+//
+// list functions
+//
+
+VOID AddListElement(IN OUT VOID ***ListPtr, IN OUT UINTN *ElementCount, IN VOID *NewElement)
+{
+    UINTN AllocateCount;
+
+    if ((*ElementCount & 15) == 0) {
+        AllocateCount = *ElementCount + 16;
+        if (*ElementCount == 0)
+            *ListPtr = AllocatePool(sizeof(VOID *) * AllocateCount);
+        else
+            *ListPtr = EfiReallocatePool(*ListPtr, sizeof(VOID *) * (*ElementCount), sizeof(VOID *) * AllocateCount);
+    }
+    (*ListPtr)[*ElementCount] = NewElement;
+    (*ElementCount)++;
+} /* VOID AddListElement() */
+
+VOID FreeList(IN OUT VOID ***ListPtr, IN OUT UINTN *ElementCount)
+{
+    UINTN i;
+
+    if ((*ElementCount > 0) && (**ListPtr != NULL)) {
+        for (i = 0; i < *ElementCount; i++) {
+            // TODO: call a user-provided routine for each element here
+            MyFreePool((*ListPtr)[i]);
+        }
+        MyFreePool(*ListPtr);
+    }
+} // VOID FreeList()
+
+//
+// volume functions
+//
+
+// Return a pointer to a string containing a filesystem type name. If the
+// filesystem type is unknown, a blank (but non-null) string is returned.
+// The returned variable is a constant that should NOT be freed.
+static CHAR16 *FSTypeName(IN UINT32 TypeCode) {
+   CHAR16 *retval = NULL;
+
+   switch (TypeCode) {
+      case FS_TYPE_WHOLEDISK:
+         retval = L" whole disk";
+         break;
+      case FS_TYPE_FAT:
+         retval = L" FAT";
+         break;
+      case FS_TYPE_HFSPLUS:
+         retval = L" HFS+";
+         break;
+      case FS_TYPE_EXT2:
+         retval = L" ext2";
+         break;
+      case FS_TYPE_EXT3:
+         retval = L" ext3";
+         break;
+      case FS_TYPE_EXT4:
+         retval = L" ext4";
+         break;
+      case FS_TYPE_REISERFS:
+         retval = L" ReiserFS";
+         break;
+      case FS_TYPE_BTRFS:
+         retval = L" Btrfs";
+         break;
+      case FS_TYPE_XFS:
+         retval = L" XFS";
+         break;
+      case FS_TYPE_ISO9660:
+         retval = L" ISO-9660";
+         break;
+      case FS_TYPE_NTFS:
+         retval = L" NTFS";
+         break;
+      default:
+         retval = L"";
+         break;
+   } // switch
+   return retval;
+} // CHAR16 *FSTypeName()
+
+// Identify the filesystem type and record the filesystem's UUID/serial number,
+// if possible. Expects a Buffer containing the first few (normally at least
+// 4096) bytes of the filesystem. Sets the filesystem type code in Volume->FSType
+// and the UUID/serial number in Volume->VolUuid. Note that the UUID value is
+// recognized differently for each filesystem, and is currently supported only
+// for NTFS, ext2/3/4fs, and ReiserFS (and for NTFS it's really a 64-bit serial
+// number not a UUID or GUID). If the UUID can't be determined, it's set to 0.
+// Also, the UUID is just read directly into memory; it is *NOT* valid when
+// displayed by GuidAsString() or used in other GUID/UUID-manipulating
+// functions. (As I write, it's being used merely to detect partitions that are
+// part of a RAID 1 array.)
+static VOID SetFilesystemData(IN UINT8 *Buffer, IN UINTN BufferSize, IN OUT REFIT_VOLUME *Volume) {
+   UINT32       *Ext2Incompat, *Ext2Compat;
+   UINT16       *Magic16;
+   char         *MagicString;
+   EFI_FILE     *RootDir;
+
+   if ((Buffer != NULL) && (Volume != NULL)) {
+      SetMem(&(Volume->VolUuid), sizeof(EFI_GUID), 0);
+      Volume->FSType = FS_TYPE_UNKNOWN;
+
+      if (BufferSize >= (1024 + 100)) {
+         Magic16 = (UINT16*) (Buffer + 1024 + 56);
+         if (*Magic16 == EXT2_SUPER_MAGIC) { // ext2/3/4
+            Ext2Compat = (UINT32*) (Buffer + 1024 + 92);
+            Ext2Incompat = (UINT32*) (Buffer + 1024 + 96);
+            if ((*Ext2Incompat & 0x0040) || (*Ext2Incompat & 0x0200)) { // check for extents or flex_bg
+               Volume->FSType = FS_TYPE_EXT4;
+            } else if (*Ext2Compat & 0x0004) { // check for journal
+               Volume->FSType = FS_TYPE_EXT3;
+            } else { // none of these features; presume it's ext2...
+               Volume->FSType = FS_TYPE_EXT2;
+            }
+            CopyMem(&(Volume->VolUuid), Buffer + 1024 + 104, sizeof(EFI_GUID));
+            return;
+         }
+      } // search for ext2/3/4 magic
+
+      if (BufferSize >= (65536 + 100)) {
+         MagicString = (char*) (Buffer + 65536 + 52);
+         if ((CompareMem(MagicString, REISERFS_SUPER_MAGIC_STRING, 8) == 0) ||
+             (CompareMem(MagicString, REISER2FS_SUPER_MAGIC_STRING, 9) == 0) ||
+             (CompareMem(MagicString, REISER2FS_JR_SUPER_MAGIC_STRING, 9) == 0)) {
+            Volume->FSType = FS_TYPE_REISERFS;
+            CopyMem(&(Volume->VolUuid), Buffer + 65536 + 84, sizeof(EFI_GUID));
+            return;
+         } // if
+      } // search for ReiserFS magic
+
+      if (BufferSize >= (65536 + 64 + 8)) {
+         MagicString = (char*) (Buffer + 65536 + 64);
+         if (CompareMem(MagicString, BTRFS_SIGNATURE, 8) == 0) {
+            Volume->FSType = FS_TYPE_BTRFS;
+            return;
+         } // if
+      } // search for Btrfs magic
+
+      if (BufferSize >= 512) {
+         MagicString = (char*) Buffer;
+         if (CompareMem(MagicString, XFS_SIGNATURE, 4) == 0) {
+            Volume->FSType = FS_TYPE_XFS;
+            return;
+         }
+      } // search for XFS magic
+
+      if (BufferSize >= (1024 + 2)) {
+         Magic16 = (UINT16*) (Buffer + 1024);
+         if ((*Magic16 == HFSPLUS_MAGIC1) || (*Magic16 == HFSPLUS_MAGIC2)) {
+            Volume->FSType = FS_TYPE_HFSPLUS;
+            return;
+         }
+      } // search for HFS+ magic
+
+      if (BufferSize >= 512) {
+         // Search for NTFS, FAT, and MBR/EBR.
+         // These all have 0xAA55 at the end of the first sector, but FAT and
+         // MBR/EBR are not easily distinguished. Thus, we first look for NTFS
+         // "magic"; then check to see if the volume can be mounted, thus
+         // relying on the EFI's built-in FAT driver to identify FAT; and then
+         // check to see if the "volume" is in fact a whole-disk device.
+         Magic16 = (UINT16*) (Buffer + 510);
+         if (*Magic16 == FAT_MAGIC) {
+            MagicString = (char*) (Buffer + 3);
+            if (CompareMem(MagicString, NTFS_SIGNATURE, 8) == 0) {
+               Volume->FSType = FS_TYPE_NTFS;
+               CopyMem(&(Volume->VolUuid), Buffer + 0x48, sizeof(UINT64));
+            } else {
+               RootDir = LibOpenRoot(Volume->DeviceHandle);
+               if (RootDir != NULL) {
+                  Volume->FSType = FS_TYPE_FAT;
+               } else if (!Volume->BlockIO->Media->LogicalPartition) {
+                  Volume->FSType = FS_TYPE_WHOLEDISK;
+               } // if/elseif/else
+            } // if/else
+            return;
+         } // if
+      } // search for FAT and NTFS magic
+
+      // If no other filesystem is identified and block size is right, assume
+      // it's ISO-9660....
+      if (Volume->BlockIO->Media->BlockSize == 2048) {
+          Volume->FSType = FS_TYPE_ISO9660;
+          return;
+      }
+   } // if ((Buffer != NULL) && (Volume != NULL))
+} // UINT32 SetFilesystemData()
+
+static VOID ScanVolumeBootcode(REFIT_VOLUME *Volume, BOOLEAN *Bootable)
+{
+    EFI_STATUS              Status;
+    UINT8                   Buffer[SAMPLE_SIZE];
+    UINTN                   i;
+    MBR_PARTITION_INFO      *MbrTable;
+    BOOLEAN                 MbrTableFound = FALSE;
+
+    Volume->HasBootCode = FALSE;
+    Volume->OSIconName = NULL;
+    Volume->OSName = NULL;
+    *Bootable = FALSE;
+
+    if (Volume->BlockIO == NULL)
+        return;
+    if (Volume->BlockIO->Media->BlockSize > SAMPLE_SIZE)
+        return;   // our buffer is too small...
+
+    // look at the boot sector (this is used for both hard disks and El Torito images!)
+    Status = refit_call5_wrapper(Volume->BlockIO->ReadBlocks,
+                                 Volume->BlockIO, Volume->BlockIO->Media->MediaId,
+                                 Volume->BlockIOOffset, SAMPLE_SIZE, Buffer);
+    if (!EFI_ERROR(Status)) {
+        SetFilesystemData(Buffer, SAMPLE_SIZE, Volume);
+    }
+    if ((Status == EFI_SUCCESS) && (GlobalConfig.LegacyType == LEGACY_TYPE_MAC)) {
+        if ((*((UINT16 *)(Buffer + 510)) == 0xaa55 && Buffer[0] != 0) && (FindMem(Buffer, 512, "EXFAT", 5) == -1)) {
+            *Bootable = TRUE;
+            Volume->HasBootCode = TRUE;
+        }
+
+        // detect specific boot codes
+        if (CompareMem(Buffer + 2, "LILO", 4) == 0 ||
+            CompareMem(Buffer + 6, "LILO", 4) == 0 ||
+            CompareMem(Buffer + 3, "SYSLINUX", 8) == 0 ||
+            FindMem(Buffer, SECTOR_SIZE, "ISOLINUX", 8) >= 0) {
+            Volume->HasBootCode = TRUE;
+            Volume->OSIconName = L"linux";
+            Volume->OSName = L"Linux";
+
+        } else if (FindMem(Buffer, 512, "Geom\0Hard Disk\0Read\0 Error", 26) >= 0) {   // GRUB
+            Volume->HasBootCode = TRUE;
+            Volume->OSIconName = L"grub,linux";
+            Volume->OSName = L"Linux";
+
+        } else if ((*((UINT32 *)(Buffer + 502)) == 0 &&
+                    *((UINT32 *)(Buffer + 506)) == 50000 &&
+                    *((UINT16 *)(Buffer + 510)) == 0xaa55) ||
+                    FindMem(Buffer, SECTOR_SIZE, "Starting the BTX loader", 23) >= 0) {
+            Volume->HasBootCode = TRUE;
+            Volume->OSIconName = L"freebsd";
+            Volume->OSName = L"FreeBSD";
+
+        // If more differentiation needed, also search for
+        // "Invalid partition table" &/or "Missing boot loader".
+        } else if ((*((UINT16 *)(Buffer + 510)) == 0xaa55) &&
+                   (FindMem(Buffer, SECTOR_SIZE, "Boot loader too large", 21) >= 0) &&
+                   (FindMem(Buffer, SECTOR_SIZE, "I/O error loading boot loader", 29) >= 0))  {
+            Volume->HasBootCode = TRUE;
+            Volume->OSIconName = L"freebsd";
+            Volume->OSName = L"FreeBSD";
+
+        } else if (FindMem(Buffer, 512, "!Loading", 8) >= 0 ||
+                   FindMem(Buffer, SECTOR_SIZE, "/cdboot\0/CDBOOT\0", 16) >= 0) {
+            Volume->HasBootCode = TRUE;
+            Volume->OSIconName = L"openbsd";
+            Volume->OSName = L"OpenBSD";
+
+        } else if (FindMem(Buffer, 512, "Not a bootxx image", 18) >= 0 ||
+                   *((UINT32 *)(Buffer + 1028)) == 0x7886b6d1) {
+            Volume->HasBootCode = TRUE;
+            Volume->OSIconName = L"netbsd";
+            Volume->OSName = L"NetBSD";
+
+        // Windows NT/200x/XP
+        } else if (FindMem(Buffer, SECTOR_SIZE, "NTLDR", 5) >= 0) {
+            Volume->HasBootCode = TRUE;
+            Volume->OSIconName = L"win";
+            Volume->OSName = L"Windows";
+
+        // Windows Vista/7/8
+        } else if (FindMem(Buffer, SECTOR_SIZE, "BOOTMGR", 7) >= 0) {
+            Volume->HasBootCode = TRUE;
+            Volume->OSIconName = L"win8,win";
+            Volume->OSName = L"Windows";
+
+        } else if (FindMem(Buffer, 512, "CPUBOOT SYS", 11) >= 0 ||
+                   FindMem(Buffer, 512, "KERNEL  SYS", 11) >= 0) {
+            Volume->HasBootCode = TRUE;
+            Volume->OSIconName = L"freedos";
+            Volume->OSName = L"FreeDOS";
+
+        } else if (FindMem(Buffer, 512, "OS2LDR", 6) >= 0 ||
+                   FindMem(Buffer, 512, "OS2BOOT", 7) >= 0) {
+            Volume->HasBootCode = TRUE;
+            Volume->OSIconName = L"ecomstation";
+            Volume->OSName = L"eComStation";
+
+        } else if (FindMem(Buffer, 512, "Be Boot Loader", 14) >= 0) {
+            Volume->HasBootCode = TRUE;
+            Volume->OSIconName = L"beos";
+            Volume->OSName = L"BeOS";
+
+        } else if (FindMem(Buffer, 512, "yT Boot Loader", 14) >= 0) {
+            Volume->HasBootCode = TRUE;
+            Volume->OSIconName = L"zeta,beos";
+            Volume->OSName = L"ZETA";
+
+        } else if (FindMem(Buffer, 512, "\x04" "beos\x06" "system\x05" "zbeos", 18) >= 0 ||
+                   FindMem(Buffer, 512, "\x06" "system\x0c" "haiku_loader", 20) >= 0) {
+            Volume->HasBootCode = TRUE;
+            Volume->OSIconName = L"haiku,beos";
+            Volume->OSName = L"Haiku";
+
+        }
+
+        // NOTE: If you add an operating system with a name that starts with 'W' or 'L', you
+        //  need to fix AddLegacyEntry in refind/legacy.c.
+
+#if REFIT_DEBUG > 0
+        Print(L"  Result of bootcode detection: %s %s (%s)\n",
+              Volume->HasBootCode ? L"bootable" : L"non-bootable",
+              Volume->OSName, Volume->OSIconName);
+#endif
+
+        // dummy FAT boot sector (created by OS X's newfs_msdos)
+        if (FindMem(Buffer, 512, "Non-system disk", 15) >= 0)
+            Volume->HasBootCode = FALSE;
+
+        // dummy FAT boot sector (created by Linux's mkdosfs)
+        if (FindMem(Buffer, 512, "This is not a bootable disk", 27) >= 0)
+            Volume->HasBootCode = FALSE;
+
+        // dummy FAT boot sector (created by Windows)
+        if (FindMem(Buffer, 512, "Press any key to restart", 24) >= 0)
+            Volume->HasBootCode = FALSE;
+
+        // check for MBR partition table
+        if (*((UINT16 *)(Buffer + 510)) == 0xaa55) {
+            MbrTable = (MBR_PARTITION_INFO *)(Buffer + 446);
+            for (i = 0; i < 4; i++)
+                if (MbrTable[i].StartLBA && MbrTable[i].Size)
+                    MbrTableFound = TRUE;
+            for (i = 0; i < 4; i++)
+                if (MbrTable[i].Flags != 0x00 && MbrTable[i].Flags != 0x80)
+                    MbrTableFound = FALSE;
+            if (MbrTableFound) {
+                Volume->MbrPartitionTable = AllocatePool(4 * 16);
+                CopyMem(Volume->MbrPartitionTable, MbrTable, 4 * 16);
+            }
+        }
+
+    } else {
+#if REFIT_DEBUG > 0
+        CheckError(Status, L"while reading boot sector");
+#endif
+    }
+} /* VOID ScanVolumeBootcode() */
+
+// Set default volume badge icon based on /.VolumeBadge.{icns|png} file or disk kind
+VOID SetVolumeBadgeIcon(REFIT_VOLUME *Volume)
+{
+   if (GlobalConfig.HideUIFlags & HIDEUI_FLAG_BADGES)
+      return;
+
+   if (Volume->VolBadgeImage == NULL) {
+      Volume->VolBadgeImage = egLoadIconAnyType(Volume->RootDir, L"", L".VolumeBadge", GlobalConfig.IconSizes[ICON_SIZE_BADGE]);
+   }
+
+   if (Volume->VolBadgeImage == NULL) {
+      switch (Volume->DiskKind) {
+          case DISK_KIND_INTERNAL:
+             Volume->VolBadgeImage = BuiltinIcon(BUILTIN_ICON_VOL_INTERNAL);
+             break;
+          case DISK_KIND_EXTERNAL:
+             Volume->VolBadgeImage = BuiltinIcon(BUILTIN_ICON_VOL_EXTERNAL);
+             break;
+          case DISK_KIND_OPTICAL:
+             Volume->VolBadgeImage = BuiltinIcon(BUILTIN_ICON_VOL_OPTICAL);
+             break;
+          case DISK_KIND_NET:
+             Volume->VolBadgeImage = BuiltinIcon(BUILTIN_ICON_VOL_NET);
+             break;
+      } // switch()
+   }
+} // VOID SetVolumeBadgeIcon()
+
+// Return a string representing the input size in IEEE-1541 units.
+// The calling function is responsible for freeing the allocated memory.
+static CHAR16 *SizeInIEEEUnits(UINT64 SizeInBytes) {
+    UINT64 SizeInIeee;
+    UINTN Index = 0, NumPrefixes;
+    CHAR16 *Units, *Prefixes = L" KMGTPEZ";
+    CHAR16 *TheValue;
+
+    TheValue = AllocateZeroPool(sizeof(CHAR16) * 256);
+    if (TheValue != NULL) {
+        NumPrefixes = StrLen(Prefixes);
+        SizeInIeee = SizeInBytes;
+        while ((SizeInIeee > 1024) && (Index < (NumPrefixes - 1))) {
+            Index++;
+            SizeInIeee /= 1024;
+        } // while
+        if (Prefixes[Index] == ' ') {
+            Units = StrDuplicate(L"-byte");
+        } else {
+            Units = StrDuplicate(L"  iB");
+            Units[1] = Prefixes[Index];
+        } // if/else
+        SPrint(TheValue, 255, L"%ld%s", SizeInIeee, Units);
+    } // if
+    return TheValue;
+} // CHAR16 *SizeInIEEEUnits()
+
+// Return a name for the volume. Ideally this should be the label for the
+// filesystem or volume, but this function falls back to describing the
+// filesystem by size (200 MiB, etc.) and/or type (ext2, HFS+, etc.), if
+// this information can be extracted.
+// The calling function is responsible for freeing the memory allocated
+// for the name string.
+static CHAR16 *GetVolumeName(REFIT_VOLUME *Volume) {
+    EFI_FILE_SYSTEM_INFO    *FileSystemInfoPtr = NULL;
+    CHAR16                  *FoundName = NULL;
+    CHAR16                  *SISize, *TypeName;
+
+    if (Volume->RootDir != NULL) {
+        FileSystemInfoPtr = LibFileSystemInfo(Volume->RootDir);
+     }
+
+    if ((FileSystemInfoPtr != NULL) && (FileSystemInfoPtr->VolumeLabel != NULL) &&
+        (StrLen(FileSystemInfoPtr->VolumeLabel) > 0)) {
+        FoundName = StrDuplicate(FileSystemInfoPtr->VolumeLabel);
+    }
+
+    // If no filesystem name, try to use the partition name....
+    if ((FoundName == NULL) && (Volume->PartName != NULL) && (StrLen(Volume->PartName) > 0) &&
+        !IsIn(Volume->PartName, IGNORE_PARTITION_NAMES)) {
+        FoundName = StrDuplicate(Volume->PartName);
+    } // if use partition name
+
+    // No filesystem or acceptable partition name, so use fs type and size
+    if ((FoundName == NULL) && (FileSystemInfoPtr != NULL)) {
+        FoundName = AllocateZeroPool(sizeof(CHAR16) * 256);
+        if (FoundName != NULL) {
+            SISize = SizeInIEEEUnits(FileSystemInfoPtr->VolumeSize);
+            SPrint(FoundName, 255, L"%s%s volume", SISize, FSTypeName(Volume->FSType));
+            MyFreePool(SISize);
+        } // if allocated memory OK
+    } // if (FoundName == NULL)
+
+    MyFreePool(FileSystemInfoPtr);
+
+    if (FoundName == NULL) {
+        FoundName = AllocateZeroPool(sizeof(CHAR16) * 256);
+        if (FoundName != NULL) {
+            TypeName = FSTypeName(Volume->FSType); // NOTE: Don't free TypeName; function returns constant
+            if (StrLen(TypeName) > 0)
+                SPrint(FoundName, 255, L"%s volume", TypeName);
+            else
+                SPrint(FoundName, 255, L"unknown volume");
+        } // if allocated memory OK
+    } // if
+
+    // TODO: Above could be improved/extended, in case filesystem name is not found,
+    // such as:
+    //  - use or add disk/partition number (e.g., "(hd0,2)")
+
+    // Desperate fallback name....
+    if (FoundName == NULL) {
+        FoundName = StrDuplicate(L"unknown volume");
+    }
+    return FoundName;
+} // static CHAR16 *GetVolumeName()
+
+// Determine the unique GUID, type code GUID, and name of the volume and store them.
+static VOID SetPartGuidAndName(REFIT_VOLUME *Volume, EFI_DEVICE_PATH_PROTOCOL *DevicePath) {
+    HARDDRIVE_DEVICE_PATH    *HdDevicePath;
+    GPT_ENTRY                *PartInfo;
+
+    if ((Volume == NULL) || (DevicePath == NULL))
+        return;
+
+    if ((DevicePath->Type == MEDIA_DEVICE_PATH) && (DevicePath->SubType == MEDIA_HARDDRIVE_DP)) {
+        HdDevicePath = (HARDDRIVE_DEVICE_PATH*) DevicePath;
+        if (HdDevicePath->SignatureType == SIGNATURE_TYPE_GUID) {
+            Volume->PartGuid = *((EFI_GUID*) HdDevicePath->Signature);
+            PartInfo = FindPartWithGuid(&(Volume->PartGuid));
+            if (PartInfo) {
+                Volume->PartName = StrDuplicate(PartInfo->name);
+                CopyMem(&(Volume->PartTypeGuid), PartInfo->type_guid, sizeof(EFI_GUID));
+                if (GuidsAreEqual(&(Volume->PartTypeGuid), &gFreedesktopRootGuid) &&
+                        ((PartInfo->attributes & GPT_NO_AUTOMOUNT) == 0)) {
+                    GlobalConfig.DiscoveredRoot = Volume;
+                } // if (GUIDs match && automounting OK)
+                Volume->IsMarkedReadOnly = ((PartInfo->attributes & GPT_READ_ONLY) > 0);
+            } // if (PartInfo exists)
+        } // if (GPT disk)
+    } // if (disk device)
+} // VOID SetPartGuid()
+
+// Return TRUE if NTFS boot files are found or if Volume is unreadable,
+// FALSE otherwise. The idea is to weed out non-boot NTFS volumes from
+// BIOS/legacy boot list on Macs. We can't assume NTFS will be readable,
+// so return TRUE if it's unreadable; but if it IS readable, return
+// TRUE only if Windows boot files are found.
+static BOOLEAN HasWindowsBiosBootFiles(REFIT_VOLUME *Volume) {
+    BOOLEAN FilesFound = TRUE;
+
+    if (Volume->RootDir != NULL) {
+        FilesFound = FileExists(Volume->RootDir, L"NTLDR") ||  // Windows NT/200x/XP boot file
+                     FileExists(Volume->RootDir, L"bootmgr");  // Windows Vista/7/8 boot file
+    } // if
+    return FilesFound;
+} // static VOID HasWindowsBiosBootFiles()
+
+VOID ScanVolume(REFIT_VOLUME *Volume)
+{
+    EFI_STATUS              Status;
+    EFI_DEVICE_PATH         *DevicePath, *NextDevicePath;
+    EFI_DEVICE_PATH         *DiskDevicePath, *RemainingDevicePath;
+    EFI_HANDLE              WholeDiskHandle;
+    UINTN                   PartialLength;
+    BOOLEAN                 Bootable;
+
+    // get device path
+    Volume->DevicePath = DuplicateDevicePath(DevicePathFromHandle(Volume->DeviceHandle));
+#if REFIT_DEBUG > 0
+    if (Volume->DevicePath != NULL) {
+        Print(L"* %s\n", DevicePathToStr(Volume->DevicePath));
+#if REFIT_DEBUG >= 2
+        DumpHex(1, 0, DevicePathSize(Volume->DevicePath), Volume->DevicePath);
+#endif
+    }
+#endif
+
+    Volume->DiskKind = DISK_KIND_INTERNAL;  // default
+
+    // get block i/o
+    Status = refit_call3_wrapper(BS->HandleProtocol, Volume->DeviceHandle, &BlockIoProtocol, (VOID **) &(Volume->BlockIO));
+    if (EFI_ERROR(Status)) {
+        Volume->BlockIO = NULL;
+        Print(L"Warning: Can't get BlockIO protocol.\n");
+    } else {
+        if (Volume->BlockIO->Media->BlockSize == 2048)
+            Volume->DiskKind = DISK_KIND_OPTICAL;
+    }
+
+    // scan for bootcode and MBR table
+    Bootable = FALSE;
+    ScanVolumeBootcode(Volume, &Bootable);
+
+    // detect device type
+    DevicePath = Volume->DevicePath;
+    while (DevicePath != NULL && !IsDevicePathEndType(DevicePath)) {
+        NextDevicePath = NextDevicePathNode(DevicePath);
+
+        if (DevicePathType(DevicePath) == MEDIA_DEVICE_PATH) {
+           SetPartGuidAndName(Volume, DevicePath);
+        }
+        if (DevicePathType(DevicePath) == MESSAGING_DEVICE_PATH &&
+            (DevicePathSubType(DevicePath) == MSG_USB_DP ||
+             DevicePathSubType(DevicePath) == MSG_USB_CLASS_DP ||
+             DevicePathSubType(DevicePath) == MSG_1394_DP ||
+             DevicePathSubType(DevicePath) == MSG_FIBRECHANNEL_DP))
+            Volume->DiskKind = DISK_KIND_EXTERNAL;    // USB/FireWire/FC device -> external
+        if (DevicePathType(DevicePath) == MEDIA_DEVICE_PATH &&
+            DevicePathSubType(DevicePath) == MEDIA_CDROM_DP) {
+            Volume->DiskKind = DISK_KIND_OPTICAL;     // El Torito entry -> optical disk
+            Bootable = TRUE;
+        }
+
+        if (DevicePathType(DevicePath) == MEDIA_DEVICE_PATH && DevicePathSubType(DevicePath) == MEDIA_VENDOR_DP) {
+            Volume->IsAppleLegacy = TRUE;             // legacy BIOS device entry
+            // TODO: also check for Boot Camp GUID
+            Bootable = FALSE;   // this handle's BlockIO is just an alias for the whole device
+        }
+
+        if (DevicePathType(DevicePath) == MESSAGING_DEVICE_PATH) {
+            // make a device path for the whole device
+            PartialLength = (UINT8 *)NextDevicePath - (UINT8 *)(Volume->DevicePath);
+            DiskDevicePath = (EFI_DEVICE_PATH *)AllocatePool(PartialLength + sizeof(EFI_DEVICE_PATH));
+            CopyMem(DiskDevicePath, Volume->DevicePath, PartialLength);
+            CopyMem((UINT8 *)DiskDevicePath + PartialLength, EndDevicePath, sizeof(EFI_DEVICE_PATH));
+
+            // get the handle for that path
+            RemainingDevicePath = DiskDevicePath;
+            Status = refit_call3_wrapper(BS->LocateDevicePath, &BlockIoProtocol, &RemainingDevicePath, &WholeDiskHandle);
+            FreePool(DiskDevicePath);
+
+            if (!EFI_ERROR(Status)) {
+                //Print(L"  - original handle: %08x - disk handle: %08x\n", (UINT32)DeviceHandle, (UINT32)WholeDiskHandle);
+
+                // get the device path for later
+                Status = refit_call3_wrapper(BS->HandleProtocol, WholeDiskHandle, &DevicePathProtocol, (VOID **) &DiskDevicePath);
+                if (!EFI_ERROR(Status)) {
+                    Volume->WholeDiskDevicePath = DuplicateDevicePath(DiskDevicePath);
+                }
+
+                // look at the BlockIO protocol
+                Status = refit_call3_wrapper(BS->HandleProtocol, WholeDiskHandle, &BlockIoProtocol,
+                                             (VOID **) &Volume->WholeDiskBlockIO);
+                if (!EFI_ERROR(Status)) {
+
+                    // check the media block size
+                    if (Volume->WholeDiskBlockIO->Media->BlockSize == 2048)
+                        Volume->DiskKind = DISK_KIND_OPTICAL;
+
+                } else {
+                    Volume->WholeDiskBlockIO = NULL;
+                    //CheckError(Status, L"from HandleProtocol");
+                }
+            } //else
+              //  CheckError(Status, L"from LocateDevicePath");
+        }
+
+        DevicePath = NextDevicePath;
+    } // while
+
+   if (!Bootable) {
+#if REFIT_DEBUG > 0
+      if (Volume->HasBootCode)
+         Print(L"  Volume considered non-bootable, but boot code is present\n");
+#endif
+      Volume->HasBootCode = FALSE;
+   }
+
+   // open the root directory of the volume
+   Volume->RootDir = LibOpenRoot(Volume->DeviceHandle);
+
+   // Set volume icon based on .VolumeBadge icon or disk kind
+   SetVolumeBadgeIcon(Volume);
+
+   Volume->VolName = GetVolumeName(Volume);
+
+   if (Volume->RootDir == NULL) {
+      Volume->IsReadable = FALSE;
+      return;
+   } else {
+      Volume->IsReadable = TRUE;
+      if ((GlobalConfig.LegacyType == LEGACY_TYPE_MAC) && (Volume->FSType == FS_TYPE_NTFS) && Volume->HasBootCode) {
+         // VBR boot code found on NTFS, but volume is not actually bootable
+         // unless there are actual boot file, so check for them....
+         Volume->HasBootCode = HasWindowsBiosBootFiles(Volume);
+      }
+   } // if/else
+
+   // get custom volume icons if present
+   if (!Volume->VolIconImage) {
+      Volume->VolIconImage = egLoadIconAnyType(Volume->RootDir, L"", L".VolumeIcon", GlobalConfig.IconSizes[ICON_SIZE_BIG]);
+   }
+} // ScanVolume()
+
+static VOID ScanExtendedPartition(REFIT_VOLUME *WholeDiskVolume, MBR_PARTITION_INFO *MbrEntry)
+{
+    EFI_STATUS              Status;
+    REFIT_VOLUME            *Volume;
+    UINT32                  ExtBase, ExtCurrent, NextExtCurrent;
+    UINTN                   i;
+    UINTN                   LogicalPartitionIndex = 4;
+    UINT8                   SectorBuffer[512];
+    BOOLEAN                 Bootable;
+    MBR_PARTITION_INFO      *EMbrTable;
+
+    ExtBase = MbrEntry->StartLBA;
+
+    for (ExtCurrent = ExtBase; ExtCurrent; ExtCurrent = NextExtCurrent) {
+        // read current EMBR
+      Status = refit_call5_wrapper(WholeDiskVolume->BlockIO->ReadBlocks,
+                                   WholeDiskVolume->BlockIO,
+                                   WholeDiskVolume->BlockIO->Media->MediaId,
+                                   ExtCurrent, 512, SectorBuffer);
+        if (EFI_ERROR(Status))
+            break;
+        if (*((UINT16 *)(SectorBuffer + 510)) != 0xaa55)
+            break;
+        EMbrTable = (MBR_PARTITION_INFO *)(SectorBuffer + 446);
+
+        // scan logical partitions in this EMBR
+        NextExtCurrent = 0;
+        for (i = 0; i < 4; i++) {
+            if ((EMbrTable[i].Flags != 0x00 && EMbrTable[i].Flags != 0x80) ||
+                EMbrTable[i].StartLBA == 0 || EMbrTable[i].Size == 0)
+                break;
+            if (IS_EXTENDED_PART_TYPE(EMbrTable[i].Type)) {
+                // set next ExtCurrent
+                NextExtCurrent = ExtBase + EMbrTable[i].StartLBA;
+                break;
+            } else {
+                // found a logical partition
+                Volume = AllocateZeroPool(sizeof(REFIT_VOLUME));
+                Volume->DiskKind = WholeDiskVolume->DiskKind;
+                Volume->IsMbrPartition = TRUE;
+                Volume->MbrPartitionIndex = LogicalPartitionIndex++;
+                Volume->VolName = AllocateZeroPool(256 * sizeof(UINT16));
+                SPrint(Volume->VolName, 255, L"Partition %d", Volume->MbrPartitionIndex + 1);
+                Volume->BlockIO = WholeDiskVolume->BlockIO;
+                Volume->BlockIOOffset = ExtCurrent + EMbrTable[i].StartLBA;
+                Volume->WholeDiskBlockIO = WholeDiskVolume->BlockIO;
+
+                Bootable = FALSE;
+                ScanVolumeBootcode(Volume, &Bootable);
+                if (!Bootable)
+                    Volume->HasBootCode = FALSE;
+                SetVolumeBadgeIcon(Volume);
+                AddListElement((VOID ***) &Volumes, &VolumesCount, Volume);
+            } // if/else
+        } // for
+    } // for
+} /* VOID ScanExtendedPartition() */
+
+VOID ScanVolumes(VOID)
+{
+    EFI_STATUS              Status;
+    EFI_HANDLE              *Handles;
+    REFIT_VOLUME            *Volume, *WholeDiskVolume;
+    MBR_PARTITION_INFO      *MbrTable;
+    UINTN                   HandleCount = 0;
+    UINTN                   HandleIndex;
+    UINTN                   VolumeIndex, VolumeIndex2;
+    UINTN                   PartitionIndex;
+    UINTN                   SectorSum, i, VolNumber = 0;
+    UINT8                   *SectorBuffer1, *SectorBuffer2;
+    EFI_GUID                *UuidList;
+    EFI_GUID                NullUuid = NULL_GUID_VALUE;
+
+    MyFreePool(Volumes);
+    Volumes = NULL;
+    VolumesCount = 0;
+    ForgetPartitionTables();
+
+    // get all filesystem handles
+    Status = LibLocateHandle(ByProtocol, &BlockIoProtocol, NULL, &HandleCount, &Handles);
+    UuidList = AllocateZeroPool(sizeof(EFI_GUID) * HandleCount);
+    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];
+        AddPartitionTable(Volume);
+        ScanVolume(Volume);
+        if (UuidList) {
+           UuidList[HandleIndex] = Volume->VolUuid;
+           for (i = 0; i < HandleIndex; i++) {
+              if ((CompareMem(&(Volume->VolUuid), &(UuidList[i]), sizeof(EFI_GUID)) == 0) &&
+                  (CompareMem(&(Volume->VolUuid), &NullUuid, sizeof(EFI_GUID)) != 0)) { // Duplicate filesystem UUID
+                 Volume->IsReadable = FALSE;
+              } // if
+           } // for
+        } // if
+        if (Volume->IsReadable)
+           Volume->VolNumber = VolNumber++;
+        else
+           Volume->VolNumber = VOL_UNREADABLE;
+
+        AddListElement((VOID ***) &Volumes, &VolumesCount, Volume);
+
+        if (Volume->DeviceHandle == SelfLoadedImage->DeviceHandle)
+            SelfVolume = Volume;
+    }
+    MyFreePool(Handles);
+
+    if (SelfVolume == NULL)
+        Print(L"WARNING: SelfVolume not found");
+
+    // second pass: relate partitions and whole disk devices
+    for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) {
+        Volume = Volumes[VolumeIndex];
+        // check MBR partition table for extended partitions
+        if (Volume->BlockIO != NULL && Volume->WholeDiskBlockIO != NULL &&
+            Volume->BlockIO == Volume->WholeDiskBlockIO && Volume->BlockIOOffset == 0 &&
+            Volume->MbrPartitionTable != NULL) {
+            MbrTable = Volume->MbrPartitionTable;
+            for (PartitionIndex = 0; PartitionIndex < 4; PartitionIndex++) {
+                if (IS_EXTENDED_PART_TYPE(MbrTable[PartitionIndex].Type)) {
+                   ScanExtendedPartition(Volume, MbrTable + PartitionIndex);
+                }
+            }
+        }
+
+        // search for corresponding whole disk volume entry
+        WholeDiskVolume = NULL;
+        if (Volume->BlockIO != NULL && Volume->WholeDiskBlockIO != NULL &&
+            Volume->BlockIO != Volume->WholeDiskBlockIO) {
+            for (VolumeIndex2 = 0; VolumeIndex2 < VolumesCount; VolumeIndex2++) {
+                if (Volumes[VolumeIndex2]->BlockIO == Volume->WholeDiskBlockIO &&
+                    Volumes[VolumeIndex2]->BlockIOOffset == 0) {
+                    WholeDiskVolume = Volumes[VolumeIndex2];
+                }
+            }
+        }
+
+        if (WholeDiskVolume != NULL && WholeDiskVolume->MbrPartitionTable != NULL) {
+            // check if this volume is one of the partitions in the table
+            MbrTable = WholeDiskVolume->MbrPartitionTable;
+            SectorBuffer1 = AllocatePool(512);
+            SectorBuffer2 = AllocatePool(512);
+            for (PartitionIndex = 0; PartitionIndex < 4; PartitionIndex++) {
+                // check size
+                if ((UINT64)(MbrTable[PartitionIndex].Size) != Volume->BlockIO->Media->LastBlock + 1)
+                    continue;
+
+                // compare boot sector read through offset vs. directly
+                Status = refit_call5_wrapper(Volume->BlockIO->ReadBlocks,
+                                             Volume->BlockIO, Volume->BlockIO->Media->MediaId,
+                                             Volume->BlockIOOffset, 512, SectorBuffer1);
+                if (EFI_ERROR(Status))
+                    break;
+                Status = refit_call5_wrapper(Volume->WholeDiskBlockIO->ReadBlocks,
+                                             Volume->WholeDiskBlockIO, Volume->WholeDiskBlockIO->Media->MediaId,
+                                             MbrTable[PartitionIndex].StartLBA, 512, SectorBuffer2);
+                if (EFI_ERROR(Status))
+                    break;
+                if (CompareMem(SectorBuffer1, SectorBuffer2, 512) != 0)
+                    continue;
+                SectorSum = 0;
+                for (i = 0; i < 512; i++)
+                    SectorSum += SectorBuffer1[i];
+                if (SectorSum < 1000)
+                    continue;
+
+                // TODO: mark entry as non-bootable if it is an extended partition
+
+                // now we're reasonably sure the association is correct...
+                Volume->IsMbrPartition = TRUE;
+                Volume->MbrPartitionIndex = PartitionIndex;
+                if (Volume->VolName == NULL) {
+                    Volume->VolName = AllocateZeroPool(sizeof(CHAR16) * 256);
+                    SPrint(Volume->VolName, 255, L"Partition %d", PartitionIndex + 1);
+                }
+                break;
+            }
+
+            MyFreePool(SectorBuffer1);
+            MyFreePool(SectorBuffer2);
+        }
+    } // for
+} /* VOID ScanVolumes() */
+
+//
+// file and dir functions
+//
+
+BOOLEAN FileExists(IN EFI_FILE *BaseDir, IN CHAR16 *RelativePath)
+{
+    EFI_STATUS         Status;
+    EFI_FILE_HANDLE    TestFile;
+
+    if (BaseDir != NULL) {
+        Status = refit_call5_wrapper(BaseDir->Open, BaseDir, &TestFile, RelativePath, EFI_FILE_MODE_READ, 0);
+        if (Status == EFI_SUCCESS) {
+            refit_call1_wrapper(TestFile->Close, TestFile);
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
+
+EFI_STATUS DirNextEntry(IN EFI_FILE *Directory, IN OUT EFI_FILE_INFO **DirEntry, IN UINTN FilterMode)
+{
+    EFI_STATUS Status;
+    VOID *Buffer;
+    UINTN LastBufferSize, BufferSize;
+    INTN IterCount;
+
+    for (;;) {
+
+        // free pointer from last call
+        if (*DirEntry != NULL) {
+           FreePool(*DirEntry);
+           *DirEntry = NULL;
+        }
+
+        // read next directory entry
+        LastBufferSize = BufferSize = 256;
+        Buffer = AllocatePool(BufferSize);
+        for (IterCount = 0; ; IterCount++) {
+            Status = refit_call3_wrapper(Directory->Read, Directory, &BufferSize, Buffer);
+            if (Status != EFI_BUFFER_TOO_SMALL || IterCount >= 4)
+                break;
+            if (BufferSize <= LastBufferSize) {
+                Print(L"FS Driver requests bad buffer size %d (was %d), using %d instead\n", BufferSize, LastBufferSize, LastBufferSize * 2);
+                BufferSize = LastBufferSize * 2;
+#if REFIT_DEBUG > 0
+            } else {
+                Print(L"Reallocating buffer from %d to %d\n", LastBufferSize, BufferSize);
+#endif
+            }
+            Buffer = EfiReallocatePool(Buffer, LastBufferSize, BufferSize);
+            LastBufferSize = BufferSize;
+        }
+        if (EFI_ERROR(Status)) {
+            MyFreePool(Buffer);
+            Buffer = NULL;
+            break;
+        }
+
+        // check for end of listing
+        if (BufferSize == 0) {    // end of directory listing
+            MyFreePool(Buffer);
+            Buffer = NULL;
+            break;
+        }
+
+        // entry is ready to be returned
+        *DirEntry = (EFI_FILE_INFO *)Buffer;
+
+        // filter results
+        if (FilterMode == 1) {   // only return directories
+            if (((*DirEntry)->Attribute & EFI_FILE_DIRECTORY))
+                break;
+        } else if (FilterMode == 2) {   // only return files
+            if (((*DirEntry)->Attribute & EFI_FILE_DIRECTORY) == 0)
+                break;
+        } else                   // no filter or unknown filter -> return everything
+            break;
+
+    }
+    return Status;
+}
+
+VOID DirIterOpen(IN EFI_FILE *BaseDir, IN CHAR16 *RelativePath OPTIONAL, OUT REFIT_DIR_ITER *DirIter)
+{
+    if (RelativePath == NULL) {
+        DirIter->LastStatus = EFI_SUCCESS;
+        DirIter->DirHandle = BaseDir;
+        DirIter->CloseDirHandle = FALSE;
+    } else {
+        DirIter->LastStatus = refit_call5_wrapper(BaseDir->Open, BaseDir, &(DirIter->DirHandle), RelativePath, EFI_FILE_MODE_READ, 0);
+        DirIter->CloseDirHandle = EFI_ERROR(DirIter->LastStatus) ? FALSE : TRUE;
+    }
+    DirIter->LastFileInfo = NULL;
+}
+
+#ifndef __MAKEWITH_GNUEFI
+EFI_UNICODE_COLLATION_PROTOCOL *mUnicodeCollation = NULL;
+
+static EFI_STATUS
+InitializeUnicodeCollationProtocol (VOID)
+{
+   EFI_STATUS  Status;
+
+   if (mUnicodeCollation != NULL) {
+      return EFI_SUCCESS;
+   }
+
+   //
+   // BUGBUG: Proper impelmentation is to locate all Unicode Collation Protocol
+   // instances first and then select one which support English language.
+   // Current implementation just pick the first instance.
+   //
+   Status = gBS->LocateProtocol (
+                          &gEfiUnicodeCollation2ProtocolGuid,
+                          NULL,
+                          (VOID **) &mUnicodeCollation
+                          );
+  if (EFI_ERROR(Status)) {
+    Status = gBS->LocateProtocol (
+                  &gEfiUnicodeCollationProtocolGuid,
+                  NULL,
+                  (VOID **) &mUnicodeCollation
+                  );
+
+  }
+   return Status;
+}
+
+static BOOLEAN
+MetaiMatch (IN CHAR16 *String, IN CHAR16 *Pattern)
+{
+   if (!mUnicodeCollation) {
+      InitializeUnicodeCollationProtocol();
+   }
+   if (mUnicodeCollation)
+      return mUnicodeCollation->MetaiMatch (mUnicodeCollation, String, Pattern);
+   return FALSE; // Shouldn't happen
+}
+
+#endif
+
+BOOLEAN DirIterNext(IN OUT REFIT_DIR_ITER *DirIter, IN UINTN FilterMode, IN CHAR16 *FilePattern OPTIONAL,
+                    OUT EFI_FILE_INFO **DirEntry)
+{
+    BOOLEAN KeepGoing = TRUE;
+    UINTN   i;
+    CHAR16  *OnePattern;
+
+    if (DirIter->LastFileInfo != NULL) {
+       FreePool(DirIter->LastFileInfo);
+       DirIter->LastFileInfo = NULL;
+    }
+
+    if (EFI_ERROR(DirIter->LastStatus))
+        return FALSE;   // stop iteration
+
+    do {
+        DirIter->LastStatus = DirNextEntry(DirIter->DirHandle, &(DirIter->LastFileInfo), FilterMode);
+        if (EFI_ERROR(DirIter->LastStatus))
+           return FALSE;
+        if (DirIter->LastFileInfo == NULL)  // end of listing
+            return FALSE;
+        if (FilePattern != NULL) {
+            if ((DirIter->LastFileInfo->Attribute & EFI_FILE_DIRECTORY))
+                KeepGoing = FALSE;
+            i = 0;
+            while (KeepGoing && (OnePattern = FindCommaDelimited(FilePattern, i++)) != NULL) {
+               if (MetaiMatch(DirIter->LastFileInfo->FileName, OnePattern))
+                   KeepGoing = FALSE;
+            } // while
+            // else continue loop
+        } else
+            break;
+   } while (KeepGoing && FilePattern);
+
+    *DirEntry = DirIter->LastFileInfo;
+    return TRUE;
+}
+
+EFI_STATUS DirIterClose(IN OUT REFIT_DIR_ITER *DirIter)
+{
+   if (DirIter->LastFileInfo != NULL) {
+      FreePool(DirIter->LastFileInfo);
+      DirIter->LastFileInfo = NULL;
+   }
+   if (DirIter->CloseDirHandle)
+      refit_call1_wrapper(DirIter->DirHandle->Close, DirIter->DirHandle);
+   return DirIter->LastStatus;
+}
+
+//
+// file name manipulation
+//
+
+// Returns the filename portion (minus path name) of the
+// specified file
+CHAR16 * Basename(IN CHAR16 *Path)
+{
+    CHAR16  *FileName;
+    UINTN   i;
+
+    FileName = Path;
+
+    if (Path != NULL) {
+        for (i = StrLen(Path); i > 0; i--) {
+            if (Path[i-1] == '\\' || Path[i-1] == '/') {
+                FileName = Path + i;
+                break;
+            }
+        }
+    }
+
+    return FileName;
+}
+
+// Remove the .efi extension from FileName -- for instance, if FileName is
+// "fred.efi", returns "fred". If the filename contains no .efi extension,
+// returns a copy of the original input.
+CHAR16 * StripEfiExtension(IN CHAR16 *FileName) {
+    UINTN  Length;
+    CHAR16 *Copy = NULL;
+
+    if ((FileName != NULL) && ((Copy = StrDuplicate(FileName)) != NULL)) {
+        Length = StrLen(Copy);
+        if ((Length >= 4) && MyStriCmp(&Copy[Length - 4], L".efi")) {
+            Copy[Length - 4] = 0;
+        } // if
+    } // if
+    return Copy;
+} // CHAR16 * StripExtension()
+
+//
+// memory string search
+//
+
+INTN FindMem(IN VOID *Buffer, IN UINTN BufferLength, IN VOID *SearchString, IN UINTN SearchStringLength)
+{
+    UINT8 *BufferPtr;
+    UINTN Offset;
+
+    BufferPtr = Buffer;
+    BufferLength -= SearchStringLength;
+    for (Offset = 0; Offset < BufferLength; Offset++, BufferPtr++) {
+        if (CompareMem(BufferPtr, SearchString, SearchStringLength) == 0)
+            return (INTN)Offset;
+    }
+
+    return -1;
+}
+
+// Takes an input pathname (*Path) and returns the part of the filename from
+// the final dot onwards, converted to lowercase. If the filename includes
+// no dots, or if the input is NULL, returns an empty (but allocated) string.
+// The calling function is responsible for freeing the memory associated with
+// the return value.
+CHAR16 *FindExtension(IN CHAR16 *Path) {
+    CHAR16     *Extension;
+    BOOLEAN    Found = FALSE, FoundSlash = FALSE;
+    INTN       i;
+
+    Extension = AllocateZeroPool(sizeof(CHAR16));
+    if (Path) {
+        i = StrLen(Path);
+        while ((!Found) && (!FoundSlash) && (i >= 0)) {
+            if (Path[i] == L'.')
+                Found = TRUE;
+            else if ((Path[i] == L'/') || (Path[i] == L'\\'))
+                FoundSlash = TRUE;
+            if (!Found)
+                i--;
+        } // while
+        if (Found) {
+            MergeStrings(&Extension, &Path[i], 0);
+            ToLower(Extension);
+        } // if (Found)
+    } // if
+    return (Extension);
+} // CHAR16 *FindExtension()
+
+// Takes an input pathname (*Path) and locates the final directory component
+// of that name. For instance, if the input path is 'EFI\foo\bar.efi', this
+// function returns the string 'foo'.
+// Assumes the pathname is separated with backslashes.
+CHAR16 *FindLastDirName(IN CHAR16 *Path) {
+    UINTN i, StartOfElement = 0, EndOfElement = 0, PathLength, CopyLength;
+    CHAR16 *Found = NULL;
+
+    if (Path == NULL)
+        return NULL;
+
+    PathLength = StrLen(Path);
+    // Find start & end of target element
+    for (i = 0; i < PathLength; i++) {
+        if (Path[i] == '\\') {
+            StartOfElement = EndOfElement;
+            EndOfElement = i;
+        } // if
+    } // for
+    // Extract the target element
+    if (EndOfElement > 0) {
+        while ((StartOfElement < PathLength) && (Path[StartOfElement] == '\\')) {
+            StartOfElement++;
+        } // while
+        EndOfElement--;
+        if (EndOfElement >= StartOfElement) {
+            CopyLength = EndOfElement - StartOfElement + 1;
+            Found = StrDuplicate(&Path[StartOfElement]);
+            if (Found != NULL)
+                Found[CopyLength] = 0;
+        } // if (EndOfElement >= StartOfElement)
+    } // if (EndOfElement > 0)
+    return (Found);
+} // CHAR16 *FindLastDirName()
+
+// Returns the directory portion of a pathname. For instance,
+// if FullPath is 'EFI\foo\bar.efi', this function returns the
+// string 'EFI\foo'. The calling function is responsible for
+// freeing the returned string's memory.
+CHAR16 *FindPath(IN CHAR16* FullPath) {
+   UINTN i, LastBackslash = 0;
+   CHAR16 *PathOnly = NULL;
+
+   if (FullPath != NULL) {
+      for (i = 0; i < StrLen(FullPath); i++) {
+         if (FullPath[i] == '\\')
+            LastBackslash = i;
+      } // for
+      PathOnly = StrDuplicate(FullPath);
+      if (PathOnly != NULL)
+         PathOnly[LastBackslash] = 0;
+   } // if
+   return (PathOnly);
+}
+
+// Takes an input loadpath, splits it into disk and filename components, finds a matching
+// DeviceVolume, and returns that and the filename (*loader).
+VOID FindVolumeAndFilename(IN EFI_DEVICE_PATH *loadpath, OUT REFIT_VOLUME **DeviceVolume, OUT CHAR16 **loader) {
+    CHAR16 *DeviceString, *VolumeDeviceString, *Temp;
+    UINTN i = 0;
+    BOOLEAN Found = FALSE;
+
+    MyFreePool(*loader);
+    MyFreePool(*DeviceVolume);
+    *DeviceVolume = NULL;
+    DeviceString = DevicePathToStr(loadpath);
+    *loader = SplitDeviceString(DeviceString);
+
+    while ((i < VolumesCount) && (!Found)) {
+        VolumeDeviceString = DevicePathToStr(Volumes[i]->DevicePath);
+        Temp = SplitDeviceString(VolumeDeviceString);
+        if (MyStriCmp(DeviceString, VolumeDeviceString)) {
+            Found = TRUE;
+            *DeviceVolume = Volumes[i];
+        }
+        MyFreePool(Temp);
+        MyFreePool(VolumeDeviceString);
+        i++;
+    } // while
+
+    MyFreePool(DeviceString);
+} // VOID FindVolumeAndFilename()
+
+// Splits a volume/filename string (e.g., "fs0:\EFI\BOOT") into separate
+// volume and filename components (e.g., "fs0" and "\EFI\BOOT"), returning
+// the filename component in the original *Path variable and the split-off
+// volume component in the *VolName variable.
+// Returns TRUE if both components are found, FALSE otherwise.
+BOOLEAN SplitVolumeAndFilename(IN OUT CHAR16 **Path, OUT CHAR16 **VolName) {
+    UINTN i = 0, Length;
+    CHAR16 *Filename;
+
+    if (*Path == NULL)
+        return FALSE;
+
+    if (*VolName != NULL) {
+        MyFreePool(*VolName);
+        *VolName = NULL;
+    }
+
+    Length = StrLen(*Path);
+    while ((i < Length) && ((*Path)[i] != L':')) {
+        i++;
+    } // while
+
+    if (i < Length) {
+        Filename = StrDuplicate((*Path) + i + 1);
+        (*Path)[i] = 0;
+        *VolName = *Path;
+        *Path = Filename;
+        return TRUE;
+    } else {
+        return FALSE;
+    }
+} // BOOLEAN SplitVolumeAndFilename()
+
+// Take an input path name, which may include a volume specification and/or
+// a path, and return separate volume, path, and file names. For instance,
+// "BIGVOL:\EFI\ubuntu\grubx64.efi" will return a VolName of "BIGVOL", a Path
+// of "EFI\ubuntu", and a Filename of "grubx64.efi". If an element is missing,
+// the returned pointer is NULL. The calling function is responsible for
+// freeing the allocated memory.
+VOID SplitPathName(CHAR16 *InPath, CHAR16 **VolName, CHAR16 **Path, CHAR16 **Filename) {
+    CHAR16 *Temp = NULL;
+
+    MyFreePool(*VolName);
+    MyFreePool(*Path);
+    MyFreePool(*Filename);
+    *VolName = *Path = *Filename = NULL;
+    Temp = StrDuplicate(InPath);
+    SplitVolumeAndFilename(&Temp, VolName); // VolName is NULL or has volume; Temp has rest of path
+    CleanUpPathNameSlashes(Temp);
+    *Path = FindPath(Temp); // *Path has path (may be 0-length); Temp unchanged.
+    *Filename = StrDuplicate(Temp + StrLen(*Path));
+    CleanUpPathNameSlashes(*Filename);
+    if (StrLen(*Path) == 0) {
+        MyFreePool(*Path);
+        *Path = NULL;
+    }
+    if (StrLen(*Filename) == 0) {
+        MyFreePool(*Filename);
+        *Filename = NULL;
+    }
+    MyFreePool(Temp);
+} // VOID SplitPathName()
+
+// Returns TRUE if specified Volume, Directory, and Filename correspond to an
+// element in the comma-delimited List, FALSE otherwise. Note that Directory and
+// Filename must *NOT* include a volume or path specification (that's part of
+// the Volume variable), but the List elements may. Performs comparison
+// case-insensitively.
+BOOLEAN FilenameIn(REFIT_VOLUME *Volume, CHAR16 *Directory, CHAR16 *Filename, CHAR16 *List) {
+    UINTN     i = 0;
+    BOOLEAN   Found = FALSE;
+    CHAR16    *OneElement;
+    CHAR16    *TargetVolName = NULL, *TargetPath = NULL, *TargetFilename = NULL;
+
+    if (Filename && List) {
+        while (!Found && (OneElement = FindCommaDelimited(List, i++))) {
+            Found = TRUE;
+            SplitPathName(OneElement, &TargetVolName, &TargetPath, &TargetFilename);
+            VolumeNumberToName(Volume, &TargetVolName);
+            if (((TargetVolName != NULL) && ((Volume == NULL) || (!MyStriCmp(TargetVolName, Volume->VolName)))) ||
+                 ((TargetPath != NULL) && (!MyStriCmp(TargetPath, Directory))) ||
+                 ((TargetFilename != NULL) && (!MyStriCmp(TargetFilename, Filename)))) {
+                Found = FALSE;
+            } // if
+            MyFreePool(OneElement);
+        } // while
+    } // if
+
+    MyFreePool(TargetVolName);
+    MyFreePool(TargetPath);
+    MyFreePool(TargetFilename);
+    return Found;
+} // BOOLEAN FilenameIn()
+
+// If *VolName is of the form "fs#", where "#" is a number, and if Volume points
+// to this volume number, returns with *VolName changed to the volume name, as
+// stored in the Volume data structure.
+// Returns TRUE if this substitution was made, FALSE otherwise.
+BOOLEAN VolumeNumberToName(REFIT_VOLUME *Volume, CHAR16 **VolName) {
+   BOOLEAN MadeSubstitution = FALSE;
+   UINTN VolNum;
+
+   if ((VolName == NULL) || (*VolName == NULL))
+      return FALSE;
+
+   if ((StrLen(*VolName) > 2) && (*VolName[0] == L'f') && (*VolName[1] == L's') && (*VolName[2] >= L'0') && (*VolName[2] <= L'9')) {
+      VolNum = Atoi(*VolName + 2);
+      if (VolNum == Volume->VolNumber) {
+         MyFreePool(*VolName);
+         *VolName = StrDuplicate(Volume->VolName);
+         MadeSubstitution = TRUE;
+      } // if
+   } // if
+   return MadeSubstitution;
+} // BOOLEAN VolumeMatchesNumber()
+
+// Implement FreePool the way it should have been done to begin with, so that
+// it doesn't throw an ASSERT message if fed a NULL pointer....
+VOID MyFreePool(IN VOID *Pointer) {
+    if (Pointer != NULL)
+        FreePool(Pointer);
+}
+
+static EFI_GUID AppleRemovableMediaGuid = APPLE_REMOVABLE_MEDIA_PROTOCOL_GUID;
+
+// Eject all removable media.
+// Returns TRUE if any media were ejected, FALSE otherwise.
+BOOLEAN EjectMedia(VOID) {
+    EFI_STATUS                      Status;
+    UINTN                           HandleIndex, HandleCount = 0, Ejected = 0;
+    EFI_HANDLE                      *Handles, Handle;
+    APPLE_REMOVABLE_MEDIA_PROTOCOL  *Ejectable;
+
+    Status = LibLocateHandle(ByProtocol, &AppleRemovableMediaGuid, NULL, &HandleCount, &Handles);
+    if (EFI_ERROR(Status) || HandleCount == 0)
+        return (FALSE); // probably not an Apple system
+
+    for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
+        Handle = Handles[HandleIndex];
+        Status = refit_call3_wrapper(BS->HandleProtocol, Handle, &AppleRemovableMediaGuid, (VOID **) &Ejectable);
+        if (EFI_ERROR(Status))
+            continue;
+        Status = refit_call1_wrapper(Ejectable->Eject, Ejectable);
+        if (!EFI_ERROR(Status))
+            Ejected++;
+    }
+    MyFreePool(Handles);
+    return (Ejected > 0);
+} // VOID EjectMedia()
+
+// Returns TRUE if the two GUIDs are equal, FALSE otherwise
+BOOLEAN GuidsAreEqual(EFI_GUID *Guid1, EFI_GUID *Guid2) {
+    return (CompareMem(Guid1, Guid2, 16) == 0);
+} // BOOLEAN GuidsAreEqual()
+
+// Erase linked-list of UINT32 values....
+VOID EraseUint32List(UINT32_LIST **TheList) {
+    UINT32_LIST *NextItem;
+
+    while (*TheList) {
+        NextItem = (*TheList)->Next;
+        FreePool(*TheList);
+        *TheList = NextItem;
+    } // while
+} // EraseUin32List()
diff --git a/refind/lib.h b/refind/lib.h
new file mode 100644 (file)
index 0000000..7f379b3
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * refit/lib.h
+ * General header file
+ *
+ * Copyright (c) 2006-2009 Christoph Pfisterer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Modifications copyright (c) 2012-2015 Roderick W. Smith
+ *
+ * Modifications distributed under the terms of the GNU General Public
+ * License (GPL) version 3 (GPLv3), a copy of which must be distributed
+ * with this source code or binaries made from it.
+ *
+ */
+
+#ifndef __LIB_H_
+#define __LIB_H_
+
+#ifdef __MAKEWITH_GNUEFI
+#include "efi.h"
+#include "efilib.h"
+#define EFI_DEVICE_PATH_PROTOCOL EFI_DEVICE_PATH
+#else
+#include "../include/tiano_includes.h"
+#endif
+
+#include "global.h"
+
+#include "libeg.h"
+
+//
+// lib module
+//
+
+// types
+
+typedef struct {
+    EFI_STATUS          LastStatus;
+    EFI_FILE_HANDLE     DirHandle;
+    BOOLEAN             CloseDirHandle;
+    EFI_FILE_INFO       *LastFileInfo;
+} REFIT_DIR_ITER;
+
+#define DISK_KIND_INTERNAL  (0)
+#define DISK_KIND_EXTERNAL  (1)
+#define DISK_KIND_OPTICAL   (2)
+#define DISK_KIND_NET       (3)
+
+#define VOL_UNREADABLE 999
+
+#define IS_EXTENDED_PART_TYPE(type) ((type) == 0x05 || (type) == 0x0f || (type) == 0x85)
+
+// GPT attributes of interest to us for Freedesktop.org Discoverable
+// Partitions Specification....
+#define GPT_READ_ONLY     0x1000000000000000
+#define GPT_NO_AUTOMOUNT  0x8000000000000000
+
+// Partition names to be ignored when setting volume name
+#define IGNORE_PARTITION_NAMES L"Microsoft basic data,Linux filesystem,Apple HFS/HFS+"
+
+extern EFI_GUID gFreedesktopRootGuid;
+
+EFI_STATUS InitRefitLib(IN EFI_HANDLE ImageHandle);
+VOID UninitRefitLib(VOID);
+EFI_STATUS ReinitRefitLib(VOID);
+
+EFI_STATUS EfivarGetRaw(EFI_GUID *vendor, CHAR16 *name, CHAR8 **buffer, UINTN *size);
+EFI_STATUS EfivarSetRaw(EFI_GUID *vendor, CHAR16 *name, CHAR8 *buf, UINTN size, BOOLEAN persistent);
+
+VOID CleanUpPathNameSlashes(IN OUT CHAR16 *PathName);
+VOID CreateList(OUT VOID ***ListPtr, OUT UINTN *ElementCount, IN UINTN InitialElementCount);
+VOID AddListElement(IN OUT VOID ***ListPtr, IN OUT UINTN *ElementCount, IN VOID *NewElement);
+VOID FreeList(IN OUT VOID ***ListPtr, IN OUT UINTN *ElementCount);
+
+VOID SetVolumeBadgeIcon(REFIT_VOLUME *Volume);
+VOID ScanVolumes(VOID);
+
+BOOLEAN FileExists(IN EFI_FILE *BaseDir, IN CHAR16 *RelativePath);
+
+EFI_STATUS DirNextEntry(IN EFI_FILE *Directory, IN OUT EFI_FILE_INFO **DirEntry, IN UINTN FilterMode);
+
+VOID DirIterOpen(IN EFI_FILE *BaseDir, IN CHAR16 *RelativePath OPTIONAL, OUT REFIT_DIR_ITER *DirIter);
+BOOLEAN DirIterNext(IN OUT REFIT_DIR_ITER *DirIter, IN UINTN FilterMode, IN CHAR16 *FilePattern OPTIONAL, OUT EFI_FILE_INFO **DirEntry);
+EFI_STATUS DirIterClose(IN OUT REFIT_DIR_ITER *DirIter);
+
+CHAR16 * Basename(IN CHAR16 *Path);
+CHAR16 * StripEfiExtension(CHAR16 *FileName);
+
+INTN FindMem(IN VOID *Buffer, IN UINTN BufferLength, IN VOID *SearchString, IN UINTN SearchStringLength);
+VOID ReinitVolumes(VOID);
+
+CHAR16 *FindExtension(IN CHAR16 *Path);
+CHAR16 *FindLastDirName(IN CHAR16 *Path);
+CHAR16 *FindPath(IN CHAR16* FullPath);
+VOID FindVolumeAndFilename(IN EFI_DEVICE_PATH *loadpath, OUT REFIT_VOLUME **DeviceVolume, OUT CHAR16 **loader);
+BOOLEAN SplitVolumeAndFilename(IN OUT CHAR16 **Path, OUT CHAR16 **VolName);
+VOID SplitPathName(CHAR16 *InPath, CHAR16 **VolName, CHAR16 **Path, CHAR16 **Filename);
+BOOLEAN FilenameIn(IN REFIT_VOLUME *Volume, IN CHAR16 *Directory, IN CHAR16 *Filename, IN CHAR16 *List);
+BOOLEAN VolumeNumberToName(REFIT_VOLUME *Volume, CHAR16 **VolName);
+VOID MyFreePool(IN OUT VOID *Pointer);
+
+BOOLEAN EjectMedia(VOID);
+
+BOOLEAN GuidsAreEqual(EFI_GUID *Guid1, EFI_GUID *Guid2);
+
+VOID EraseUint32List(UINT32_LIST **TheList);
+
+#endif
\ No newline at end of file
diff --git a/refind/line_edit.c b/refind/line_edit.c
new file mode 100644 (file)
index 0000000..8bb9fb4
--- /dev/null
@@ -0,0 +1,217 @@
+// Line-editing functions borrowed from gummiboot (cursor_left(),
+// cursor_right(), & line_edit()).
+
+/*
+ * Simple UEFI boot loader which executes configured EFI images, where the
+ * default entry is selected by a configured pattern (glob) or an on-screen
+ * menu.
+ *
+ * All gummiboot code is LGPL not GPL, to stay out of politics and to give
+ * the freedom of copying code from programs to possible future libraries.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * Copyright (C) 2012-2013 Kay Sievers <kay@vrfy.org>
+ * Copyright (C) 2012 Harald Hoyer <harald@redhat.com>
+ *
+ * "Any intelligent fool can make things bigger, more complex, and more violent.
+"
+ *   -- Albert Einstein
+ */
+
+#include "global.h"
+#include "screen.h"
+#include "lib.h"
+#include "../include/refit_call_wrapper.h"
+
+static void cursor_left(UINTN *cursor, UINTN *first)
+{
+   if ((*cursor) > 0)
+      (*cursor)--;
+   else if ((*first) > 0)
+      (*first)--;
+}
+
+static void cursor_right(UINTN *cursor, UINTN *first, UINTN x_max, UINTN len)
+{
+   if ((*cursor)+2 < x_max)
+      (*cursor)++;
+   else if ((*first) + (*cursor) < len)
+      (*first)++;
+}
+
+BOOLEAN line_edit(CHAR16 *line_in, CHAR16 **line_out, UINTN x_max) {
+   CHAR16 *line;
+   UINTN size;
+   UINTN len;
+   UINTN first;
+   UINTN y_pos = 3;
+   CHAR16 *print;
+   UINTN cursor;
+   BOOLEAN exit;
+   BOOLEAN enter;
+
+   DrawScreenHeader(L"Line Editor");
+   refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, (ConWidth - 71) / 2, ConHeight - 1);
+   refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut,
+                       L"Use cursor keys to edit, Esc to exit, Enter to boot with edited options");
+
+   if (!line_in)
+      line_in = L"";
+   size = StrLen(line_in) + 1024;
+   line = AllocatePool(size * sizeof(CHAR16));
+   StrCpy(line, line_in);
+   len = StrLen(line);
+   print = AllocatePool(x_max * sizeof(CHAR16));
+
+   refit_call2_wrapper(ST->ConOut->EnableCursor, ST->ConOut, TRUE);
+
+   first = 0;
+   cursor = 0;
+   enter = FALSE;
+   exit = FALSE;
+   while (!exit) {
+      UINTN index;
+      EFI_STATUS err;
+      EFI_INPUT_KEY key;
+      UINTN i;
+
+      i = len - first;
+      if (i >= x_max-2)
+         i = x_max-2;
+      CopyMem(print, line + first, i * sizeof(CHAR16));
+      print[i++] = ' ';
+      print[i] = '\0';
+
+      refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 0, y_pos);
+      refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, print);
+      refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, cursor, y_pos);
+
+      refit_call3_wrapper(BS->WaitForEvent, 1, &ST->ConIn->WaitForKey, &index);
+      err = refit_call2_wrapper(ST->ConIn->ReadKeyStroke, ST->ConIn, &key);
+      if (EFI_ERROR(err))
+         continue;
+
+      switch (key.ScanCode) {
+      case SCAN_ESC:
+         exit = TRUE;
+         break;
+      case SCAN_HOME:
+         cursor = 0;
+         first = 0;
+         continue;
+      case SCAN_END:
+         cursor = len;
+         if (cursor >= x_max) {
+            cursor = x_max-2;
+            first = len - (x_max-2);
+         }
+         continue;
+      case SCAN_UP:
+         while((first + cursor) && line[first + cursor] == ' ')
+            cursor_left(&cursor, &first);
+         while((first + cursor) && line[first + cursor] != ' ')
+            cursor_left(&cursor, &first);
+         while((first + cursor) && line[first + cursor] == ' ')
+            cursor_left(&cursor, &first);
+         if (first + cursor != len && first + cursor)
+            cursor_right(&cursor, &first, x_max, len);
+         refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, cursor, y_pos);
+         continue;
+      case SCAN_DOWN:
+         while(line[first + cursor] && line[first + cursor] == ' ')
+            cursor_right(&cursor, &first, x_max, len);
+         while(line[first + cursor] && line[first + cursor] != ' ')
+            cursor_right(&cursor, &first, x_max, len);
+         while(line[first + cursor] && line[first + cursor] == ' ')
+              cursor_right(&cursor, &first, x_max, len);
+         refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, cursor, y_pos);
+         continue;
+      case SCAN_RIGHT:
+         if (first + cursor == len)
+            continue;
+         cursor_right(&cursor, &first, x_max, len);
+         refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, cursor, y_pos);
+         continue;
+      case SCAN_LEFT:
+         cursor_left(&cursor, &first);
+         refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, cursor, y_pos);
+         continue;
+      case SCAN_DELETE:
+         if (len == 0)
+            continue;
+         if (first + cursor == len)
+            continue;
+         for (i = first + cursor; i < len; i++)
+            line[i] = line[i+1];
+         line[len-1] = ' ';
+         len--;
+         continue;
+      }
+
+      switch (key.UnicodeChar) {
+      case CHAR_LINEFEED:
+      case CHAR_CARRIAGE_RETURN:
+         *line_out = line;
+         line = NULL;
+         enter = TRUE;
+         exit = TRUE;
+         break;
+      case CHAR_BACKSPACE:
+         if (len == 0)
+            continue;
+         if (first == 0 && cursor == 0)
+            continue;
+         for (i = first + cursor-1; i < len; i++)
+            line[i] = line[i+1];
+         len--;
+         if (cursor > 0)
+            cursor--;
+         if (cursor > 0 || first == 0)
+            continue;
+         /* show full line if it fits */
+         if (len < x_max-2) {
+            cursor = first;
+            first = 0;
+            continue;
+         }
+         /* jump left to see what we delete */
+         if (first > 10) {
+            first -= 10;
+            cursor = 10;
+         } else {
+            cursor = first;
+            first = 0;
+         }
+         continue;
+      case '\t':
+      case ' ' ... '~':
+      case 0x80 ... 0xffff:
+         if (len+1 == size)
+            continue;
+         for (i = len; i > first + cursor; i--)
+            line[i] = line[i-1];
+         line[first + cursor] = key.UnicodeChar;
+         len++;
+         line[len] = '\0';
+         if (cursor+2 < x_max)
+            cursor++;
+         else if (first + cursor < len)
+            first++;
+         continue;
+      }
+   }
+
+   refit_call2_wrapper(ST->ConOut->EnableCursor, ST->ConOut, FALSE);
+   FreePool(print);
+   FreePool(line);
+   return enter;
+} /* BOOLEAN line_edit() */
diff --git a/refind/line_edit.h b/refind/line_edit.h
new file mode 100644 (file)
index 0000000..83338de
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * refind/screen_edit.h
+ *
+ * Line-editing functions borrowed from gummiboot
+ *
+ */
+/*
+ * Simple UEFI boot loader which executes configured EFI images, where the
+ * default entry is selected by a configured pattern (glob) or an on-screen
+ * menu.
+ *
+ * All gummiboot code is LGPL not GPL, to stay out of politics and to give
+ * the freedom of copying code from programs to possible future libraries.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * Copyright (C) 2012-2013 Kay Sievers <kay@vrfy.org>
+ * Copyright (C) 2012 Harald Hoyer <harald@redhat.com>
+ *
+ * "Any intelligent fool can make things bigger, more complex, and more violent.
+"
+ *   -- Albert Einstein
+ */
+
+#ifndef __LINE_EDIT_H_
+#define __LINE_EDIT_H_
+
+BOOLEAN line_edit(CHAR16 *line_in, CHAR16 **line_out, UINTN x_max);
+
+#endif
diff --git a/refind/main.c b/refind/main.c
new file mode 100644 (file)
index 0000000..e96f35b
--- /dev/null
@@ -0,0 +1,2314 @@
+/*
+ * 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-2015 Roderick W. Smith
+ *
+ * Modifications distributed under the terms of the GNU General Public
+ * License (GPL) version 3 (GPLv3), or (at your option) any later version.
+ *
+ */
+/*
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "global.h"
+#include "config.h"
+#include "screen.h"
+#include "legacy.h"
+#include "lib.h"
+#include "icns.h"
+#include "menu.h"
+#include "mok.h"
+#include "gpt.h"
+#include "apple.h"
+#include "mystrings.h"
+#include "security_policy.h"
+#include "driver_support.h"
+#include "../include/Handle.h"
+#include "../include/refit_call_wrapper.h"
+#include "../EfiLib/BdsHelper.h"
+#include "../EfiLib/legacy.h"
+
+#ifdef __MAKEWITH_GNUEFI
+#ifndef EFI_SECURITY_VIOLATION
+#define EFI_SECURITY_VIOLATION    EFIERR (26)
+#endif
+#endif
+
+#ifndef EFI_OS_INDICATIONS_BOOT_TO_FW_UI
+#define EFI_OS_INDICATIONS_BOOT_TO_FW_UI 0x0000000000000001ULL
+#endif
+
+#ifdef __MAKEWITH_TIANO
+#define LibLocateHandle gBS->LocateHandleBuffer
+#endif
+
+//
+// constants
+
+#define MACOSX_LOADER_DIR      L"System\\Library\\CoreServices"
+#define MACOSX_LOADER_PATH      ( MACOSX_LOADER_DIR L"\\boot.efi" )
+#if defined (EFIX64)
+#define SHELL_NAMES             L"\\EFI\\tools\\shell.efi,\\EFI\\tools\\shellx64.efi,\\shell.efi,\\shellx64.efi"
+#define GPTSYNC_NAMES           L"\\EFI\\tools\\gptsync.efi,\\EFI\\tools\\gptsync_x64.efi"
+#define GDISK_NAMES             L"\\EFI\\tools\\gdisk.efi,\\EFI\\tools\\gdisk_x64.efi"
+#define NETBOOT_NAMES           L"\\EFI\\tools\\ipxe.efi"
+#define MEMTEST_NAMES           L"memtest86.efi,memtest86_x64.efi,memtest86x64.efi,bootx64.efi"
+#define DRIVER_DIRS             L"drivers,drivers_x64"
+#define FALLBACK_FULLNAME       L"EFI\\BOOT\\bootx64.efi"
+#define FALLBACK_BASENAME       L"bootx64.efi"
+#define EFI_STUB_ARCH           0x8664
+EFI_GUID gFreedesktopRootGuid = { 0x4f68bce3, 0xe8cd, 0x4db1, { 0x96, 0xe7, 0xfb, 0xca, 0xf9, 0x84, 0xb7, 0x09 }};
+#elif defined (EFI32)
+#define SHELL_NAMES             L"\\EFI\\tools\\shell.efi,\\EFI\\tools\\shellia32.efi,\\shell.efi,\\shellia32.efi"
+#define GPTSYNC_NAMES           L"\\EFI\\tools\\gptsync.efi,\\EFI\\tools\\gptsync_ia32.efi"
+#define GDISK_NAMES             L"\\EFI\\tools\\gdisk.efi,\\EFI\\tools\\gdisk_ia32.efi"
+#define NETBOOT_NAMES           L"\\EFI\\tools\\ipxe.efi"
+#define MEMTEST_NAMES           L"memtest86.efi,memtest86_ia32.efi,memtest86ia32.efi,bootia32.efi"
+#define DRIVER_DIRS             L"drivers,drivers_ia32"
+#define FALLBACK_FULLNAME       L"EFI\\BOOT\\bootia32.efi"
+#define FALLBACK_BASENAME       L"bootia32.efi"
+#define EFI_STUB_ARCH           0x014c
+EFI_GUID gFreedesktopRootGuid = { 0x44479540, 0xf297, 0x41b2, { 0x9a, 0xf7, 0xd1, 0x31, 0xd5, 0xf0, 0x45, 0x8a }};
+#elif defined (EFIAARCH64)
+#define SHELL_NAMES             L"\\EFI\\tools\\shell.efi,\\EFI\\tools\\shellaa64.efi,\\shell.efi,\\shellaa64.efi"
+#define GPTSYNC_NAMES           L"\\EFI\\tools\\gptsync.efi,\\EFI\\tools\\gptsync_aa64.efi"
+#define GDISK_NAMES             L"\\EFI\\tools\\gdisk.efi,\\EFI\\tools\\gdisk_aa64.efi"
+#define NETBOOT_NAMES           L"\\EFI\\tools\\ipxe.efi"
+#define MEMTEST_NAMES           L"memtest86.efi,memtest86_aa64.efi,memtest86aa64.efi,bootaa64.efi"
+#define DRIVER_DIRS             L"drivers,drivers_aa64"
+#define FALLBACK_FULLNAME       L"EFI\\BOOT\\bootaa64.efi"
+#define FALLBACK_BASENAME       L"bootaa64.efi"
+#define EFI_STUB_ARCH           0xaa64
+EFI_GUID gFreedesktopRootGuid = { 0xb921b045, 0x1df0, 0x41c3, { 0xaf, 0x44, 0x4c, 0x6f, 0x28, 0x0d, 0x3f, 0xae }};
+#else
+#define SHELL_NAMES             L"\\EFI\\tools\\shell.efi,\\shell.efi"
+#define GPTSYNC_NAMES           L"\\EFI\\tools\\gptsync.efi"
+#define GDISK_NAMES             L"\\EFI\\tools\\gdisk.efi"
+#define NETBOOT_NAMES           L"\\EFI\\tools\\ipxe.efi"
+#define MEMTEST_NAMES           L"memtest86.efi"
+#define DRIVER_DIRS             L"drivers"
+#define FALLBACK_FULLNAME       L"EFI\\BOOT\\boot.efi" /* Not really correct */
+#define FALLBACK_BASENAME       L"boot.efi"            /* Not really correct */
+// Below is GUID for ARM32
+EFI_GUID gFreedesktopRootGuid = { 0x69dad710, 0x2ce4, 0x4e3c, { 0xb1, 0x6c, 0x21, 0xa1, 0xd4, 0x9a, 0xbe, 0xd3 }};
+#endif
+#define FAT_ARCH                0x0ef1fab9 /* ID for Apple "fat" binary */
+
+#define IPXE_DISCOVER_NAME      L"\\efi\\tools\\ipxe_discover.efi"
+#define IPXE_NAME               L"\\efi\\tools\\ipxe.efi"
+
+// Filename patterns that identify EFI boot loaders. Note that a single case (either L"*.efi" or
+// L"*.EFI") is fine for most systems; but Gigabyte's buggy Hybrid EFI does a case-sensitive
+// comparison when it should do a case-insensitive comparison, so I'm doubling this up. It does
+// no harm on other computers, AFAIK. In theory, every case variation should be done for
+// completeness, but that's ridiculous....
+#define LOADER_MATCH_PATTERNS   L"*.efi,*.EFI"
+
+// Patterns that identify Linux kernels. Added to the loader match pattern when the
+// scan_all_linux_kernels option is set in the configuration file. Causes kernels WITHOUT
+// a ".efi" extension to be found when scanning for boot loaders.
+#define LINUX_MATCH_PATTERNS    L"vmlinuz*,bzImage*,kernel*"
+
+// Maximum length of a text string in certain menus
+#define MAX_LINE_LENGTH 65
+
+static REFIT_MENU_ENTRY MenuEntryAbout    = { L"About rEFInd", TAG_ABOUT, 1, 0, 'A', NULL, NULL, NULL };
+static REFIT_MENU_ENTRY MenuEntryReset    = { L"Reboot Computer", TAG_REBOOT, 1, 0, 'R', NULL, NULL, NULL };
+static REFIT_MENU_ENTRY MenuEntryShutdown = { L"Shut Down Computer", TAG_SHUTDOWN, 1, 0, 'U', NULL, NULL, NULL };
+REFIT_MENU_ENTRY MenuEntryReturn   = { L"Return to Main Menu", TAG_RETURN, 1, 0, 0, NULL, NULL, NULL };
+static REFIT_MENU_ENTRY MenuEntryExit     = { L"Exit rEFInd", TAG_EXIT, 1, 0, 0, NULL, NULL, NULL };
+static REFIT_MENU_ENTRY MenuEntryFirmware = { L"Reboot to Computer Setup Utility", TAG_FIRMWARE, 1, 0, 0, NULL, NULL, NULL };
+static REFIT_MENU_ENTRY MenuEntryRotateCsr = { L"Change SIP Policy", TAG_CSR_ROTATE, 1, 0, 0, NULL, NULL, NULL };
+
+REFIT_MENU_SCREEN MainMenu       = { L"Main Menu", NULL, 0, NULL, 0, NULL, 0, L"Automatic boot",
+                                     L"Use arrow keys to move cursor; Enter to boot;",
+                                     L"Insert or F2 for more options; Esc to refresh" };
+static REFIT_MENU_SCREEN AboutMenu      = { L"About", NULL, 0, NULL, 0, NULL, 0, NULL, L"Press Enter to return to main menu", L"" };
+
+REFIT_CONFIG GlobalConfig = { FALSE, TRUE, FALSE, FALSE, TRUE, 0, 0, 0, DONT_CHANGE_TEXT_MODE,
+                              20, 0, 0, GRAPHICS_FOR_OSX, LEGACY_TYPE_MAC,
+                              0, 0, { DEFAULT_BIG_ICON_SIZE / 4, DEFAULT_SMALL_ICON_SIZE, DEFAULT_BIG_ICON_SIZE },
+                              BANNER_NOSCALE, NULL, NULL, NULL, NULL, CONFIG_FILE_NAME, NULL, NULL, NULL, NULL,
+                              NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+                              { TAG_SHELL, TAG_MEMTEST, TAG_GDISK, TAG_APPLE_RECOVERY, TAG_WINDOWS_RECOVERY,
+                                TAG_MOK_TOOL, TAG_ABOUT, TAG_SHUTDOWN, TAG_REBOOT, TAG_FIRMWARE,
+                                0, 0, 0, 0, 0, 0, 0, 0 }
+                            };
+
+EFI_GUID GlobalGuid = EFI_GLOBAL_VARIABLE;
+EFI_GUID RefindGuid = REFIND_GUID_VALUE;
+
+GPT_DATA *gPartitions = NULL;
+
+// Structure used to hold boot loader filenames and time stamps in
+// a linked list; used to sort entries within a directory.
+struct LOADER_LIST {
+    CHAR16              *FileName;
+    EFI_TIME            TimeStamp;
+    struct LOADER_LIST  *NextEntry;
+};
+
+//
+// misc functions
+//
+
+static VOID AboutrEFInd(VOID)
+{
+    CHAR16     *FirmwareVendor;
+    UINT32     CsrStatus;
+
+    if (AboutMenu.EntryCount == 0) {
+        AboutMenu.TitleImage = BuiltinIcon(BUILTIN_ICON_FUNC_ABOUT);
+        AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.10.0.6");
+        AddMenuInfoLine(&AboutMenu, L"");
+        AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2006-2010 Christoph Pfisterer");
+        AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2012-2015 Roderick W. Smith");
+        AddMenuInfoLine(&AboutMenu, L"Portions Copyright (c) Intel Corporation and others");
+        AddMenuInfoLine(&AboutMenu, L"Distributed under the terms of the GNU GPLv3 license");
+        AddMenuInfoLine(&AboutMenu, L"");
+        AddMenuInfoLine(&AboutMenu, L"Running on:");
+        AddMenuInfoLine(&AboutMenu, PoolPrint(L" EFI Revision %d.%02d", ST->Hdr.Revision >> 16, ST->Hdr.Revision & ((1 << 16) - 1)));
+#if defined(EFI32)
+        AddMenuInfoLine(&AboutMenu, PoolPrint(L" Platform: x86 (32 bit); Secure Boot %s",
+                                              secure_mode() ? L"active" : L"inactive"));
+#elif defined(EFIX64)
+        AddMenuInfoLine(&AboutMenu, PoolPrint(L" Platform: x86_64 (64 bit); Secure Boot %s",
+                                              secure_mode() ? L"active" : L"inactive"));
+#elif defined(EFIAARCH64)
+        AddMenuInfoLine(&AboutMenu, PoolPrint(L" Platform: ARM (64 bit); Secure Boot %s",
+                                              secure_mode() ? L"active" : L"inactive"));
+#else
+        AddMenuInfoLine(&AboutMenu, L" Platform: unknown");
+#endif
+        if (GetCsrStatus(&CsrStatus) == EFI_SUCCESS) {
+            RecordgCsrStatus(CsrStatus, FALSE);
+            AddMenuInfoLine(&AboutMenu, gCsrStatus);
+        }
+        FirmwareVendor = StrDuplicate(ST->FirmwareVendor);
+        LimitStringLength(FirmwareVendor, MAX_LINE_LENGTH); // More than ~65 causes empty info page on 800x600 display
+        AddMenuInfoLine(&AboutMenu, PoolPrint(L" Firmware: %s %d.%02d", FirmwareVendor, ST->FirmwareRevision >> 16,
+                                              ST->FirmwareRevision & ((1 << 16) - 1)));
+        AddMenuInfoLine(&AboutMenu, PoolPrint(L" Screen Output: %s", egScreenDescription()));
+        AddMenuInfoLine(&AboutMenu, L"");
+#if defined(__MAKEWITH_GNUEFI)
+        AddMenuInfoLine(&AboutMenu, L"Built with GNU-EFI");
+#else
+        AddMenuInfoLine(&AboutMenu, L"Built with TianoCore EDK2");
+#endif
+        AddMenuInfoLine(&AboutMenu, L"");
+        AddMenuInfoLine(&AboutMenu, L"For more information, see the rEFInd Web site:");
+        AddMenuInfoLine(&AboutMenu, L"http://www.rodsbooks.com/refind/");
+        AddMenuEntry(&AboutMenu, &MenuEntryReturn);
+    }
+
+    RunMenu(&AboutMenu, NULL);
+} /* VOID AboutrEFInd() */
+
+static VOID WarnSecureBootError(CHAR16 *Name, BOOLEAN Verbose) {
+    if (Name == NULL)
+        Name = L"the loader";
+
+    refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_ERROR);
+    Print(L"Secure Boot validation failure loading %s!\n", Name);
+    refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BASIC);
+    if (Verbose && secure_mode()) {
+        Print(L"\nThis computer is configured with Secure Boot active, but\n%s has failed validation.\n", Name);
+        Print(L"\nYou can:\n * Launch another boot loader\n");
+        Print(L" * Disable Secure Boot in your firmware\n");
+        Print(L" * Sign %s with a machine owner key (MOK)\n", Name);
+        Print(L" * Use a MOK utility (often present on the second row) to add a MOK with which\n");
+        Print(L"   %s has already been signed.\n", Name);
+        Print(L" * Use a MOK utility to register %s (\"enroll its hash\") without\n", Name);
+        Print(L"   signing it.\n");
+        Print(L"\nSee http://www.rodsbooks.com/refind/secureboot.html for more information\n");
+        PauseForKey();
+    } // if
+} // VOID WarnSecureBootError()
+
+// Returns TRUE if this file is a valid EFI loader file, and is proper ARCH
+static BOOLEAN IsValidLoader(EFI_FILE *RootDir, CHAR16 *FileName) {
+    BOOLEAN         IsValid = TRUE;
+#if defined (EFIX64) | defined (EFI32) | defined (EFIAARCH64)
+    EFI_STATUS      Status;
+    EFI_FILE_HANDLE FileHandle;
+    CHAR8           Header[512];
+    UINTN           Size = sizeof(Header);
+
+    if ((RootDir == NULL) || (FileName == NULL)) {
+        // Assume valid here, because Macs produce NULL RootDir (& maybe FileName)
+        // when launching from a Firewire drive. This should be handled better, but
+        // fix would have to be in StartEFIImageList() and/or in FindVolumeAndFilename().
+        return TRUE;
+    } // if
+
+    Status = refit_call5_wrapper(RootDir->Open, RootDir, &FileHandle, FileName, EFI_FILE_MODE_READ, 0);
+    if (EFI_ERROR(Status))
+        return FALSE;
+
+    Status = refit_call3_wrapper(FileHandle->Read, FileHandle, &Size, Header);
+    refit_call1_wrapper(FileHandle->Close, FileHandle);
+
+    IsValid = !EFI_ERROR(Status) &&
+              Size == sizeof(Header) &&
+              ((Header[0] == 'M' && Header[1] == 'Z' &&
+               (Size = *(UINT32 *)&Header[0x3c]) < 0x180 &&
+               Header[Size] == 'P' && Header[Size+1] == 'E' &&
+               Header[Size+2] == 0 && Header[Size+3] == 0 &&
+               *(UINT16 *)&Header[Size+4] == EFI_STUB_ARCH) ||
+              (*(UINT32 *)&Header == FAT_ARCH));
+#endif
+    return IsValid;
+} // BOOLEAN IsValidLoader()
+
+// Launch an EFI binary.
+EFI_STATUS StartEFIImageList(IN EFI_DEVICE_PATH **DevicePaths,
+                             IN CHAR16 *LoadOptions, IN UINTN LoaderType,
+                             IN CHAR16 *ImageTitle, IN CHAR8 OSType,
+                             OUT UINTN *ErrorInStep,
+                             IN BOOLEAN Verbose,
+                             IN BOOLEAN IsDriver)
+{
+    EFI_STATUS              Status, ReturnStatus;
+    EFI_HANDLE              ChildImageHandle, ChildImageHandle2;
+    EFI_LOADED_IMAGE        *ChildLoadedImage = NULL;
+    REFIT_VOLUME            *Volume = NULL;
+    UINTN                   DevicePathIndex;
+    CHAR16                  ErrorInfo[256];
+    CHAR16                  *FullLoadOptions = NULL;
+    CHAR16                  *Filename = NULL;
+    CHAR16                  *Temp;
+
+    if (ErrorInStep != NULL)
+        *ErrorInStep = 0;
+
+    // set load options
+    if (LoadOptions != NULL) {
+        FullLoadOptions = StrDuplicate(LoadOptions);
+        if ((LoaderType == TYPE_EFI) && (OSType == 'M')) {
+            MergeStrings(&FullLoadOptions, L" ", 0);
+            // NOTE: That last space is also added by the EFI shell and seems to be significant
+            // when passing options to Apple's boot.efi...
+        } // if
+    } // if (LoadOptions != NULL)
+    if (Verbose)
+    Print(L"Starting %s\nUsing load options '%s'\n", ImageTitle, FullLoadOptions ? FullLoadOptions : L"");
+
+    // load the image into memory
+    ReturnStatus = Status = EFI_NOT_FOUND;  // in case the list is empty
+    for (DevicePathIndex = 0; DevicePaths[DevicePathIndex] != NULL; DevicePathIndex++) {
+        FindVolumeAndFilename(DevicePaths[DevicePathIndex], &Volume, &Filename);
+        // Some EFIs crash if attempting to load driver for invalid architecture, so
+        // protect for this condition; but sometimes Volume comes back NULL, so provide
+        // an exception. (TODO: Handle this special condition better.)
+        if ((LoaderType == TYPE_LEGACY) || (Volume == NULL) || IsValidLoader(Volume->RootDir, Filename)) {
+            if (Filename && (LoaderType != TYPE_LEGACY)) {
+                Temp = PoolPrint(L"\\%s %s", Filename, FullLoadOptions ? FullLoadOptions : L"");
+                if (Temp != NULL) {
+                    MyFreePool(FullLoadOptions);
+                    FullLoadOptions = Temp;
+                }
+            } // if (Filename)
+
+            // NOTE: Below commented-out line could be more efficient if file were read ahead of
+            // time and passed as a pre-loaded image to LoadImage(), but it doesn't work on my
+            // 32-bit Mac Mini or my 64-bit Intel box when launching a Linux kernel; the
+            // kernel returns a "Failed to handle fs_proto" error message.
+            // TODO: Track down the cause of this error and fix it, if possible.
+            // ReturnStatus = Status = refit_call6_wrapper(BS->LoadImage, FALSE, SelfImageHandle, DevicePaths[DevicePathIndex],
+            //                                            ImageData, ImageSize, &ChildImageHandle);
+            ReturnStatus = Status = refit_call6_wrapper(BS->LoadImage, FALSE, SelfImageHandle, DevicePaths[DevicePathIndex],
+                                                        NULL, 0, &ChildImageHandle);
+            if (secure_mode() && ShimLoaded()) {
+                // Load ourself into memory. This is a trick to work around a bug in Shim 0.8,
+                // which ties itself into the BS->LoadImage() and BS->StartImage() functions and
+                // then unregisters itself from the EFI system table when its replacement
+                // StartImage() function is called *IF* the previous LoadImage() was for the same
+                // program. The result is that rEFInd can validate only the first program it
+                // launches (often a filesystem driver). Loading a second program (rEFInd itself,
+                // here, to keep it smaller than a kernel) works around this problem. See the
+                // replacements.c file in Shim, and especially its start_image() function, for
+                // the source of the problem.
+                // NOTE: This doesn't check the return status or handle errors. It could
+                // conceivably do weird things if, say, rEFInd were on a USB drive that the
+                // user pulls before launching a program.
+                refit_call6_wrapper(BS->LoadImage, FALSE, SelfImageHandle, GlobalConfig.SelfDevicePath,
+                                    NULL, 0, &ChildImageHandle2);
+            }
+        } else {
+            Print(L"Invalid loader file!\n");
+            ReturnStatus = EFI_LOAD_ERROR;
+        }
+        if (ReturnStatus != EFI_NOT_FOUND) {
+            break;
+        }
+    } // for
+    if ((Status == EFI_ACCESS_DENIED) || (Status == EFI_SECURITY_VIOLATION)) {
+        WarnSecureBootError(ImageTitle, Verbose);
+        goto bailout;
+    }
+    SPrint(ErrorInfo, 255, L"while loading %s", ImageTitle);
+    if (CheckError(Status, ErrorInfo)) {
+        if (ErrorInStep != NULL)
+            *ErrorInStep = 1;
+        goto bailout;
+    }
+
+    ReturnStatus = Status = refit_call3_wrapper(BS->HandleProtocol, ChildImageHandle, &LoadedImageProtocol,
+                                                (VOID **) &ChildLoadedImage);
+    if (CheckError(Status, L"while getting a LoadedImageProtocol handle")) {
+        if (ErrorInStep != NULL)
+            *ErrorInStep = 2;
+        goto bailout_unload;
+    }
+    ChildLoadedImage->LoadOptions = (VOID *)FullLoadOptions;
+    ChildLoadedImage->LoadOptionsSize = FullLoadOptions ? ((UINT32)StrLen(FullLoadOptions) + 1) * sizeof(CHAR16) : 0;
+    // turn control over to the image
+    // TODO: (optionally) re-enable the EFI watchdog timer!
+
+    // close open file handles
+    UninitRefitLib();
+    ReturnStatus = Status = refit_call3_wrapper(BS->StartImage, ChildImageHandle, NULL, NULL);
+
+    // control returns here when the child image calls Exit()
+    SPrint(ErrorInfo, 255, L"returned from %s", ImageTitle);
+    if (CheckError(Status, ErrorInfo)) {
+        if (ErrorInStep != NULL)
+            *ErrorInStep = 3;
+    }
+
+    // re-open file handles
+    ReinitRefitLib();
+
+bailout_unload:
+    // unload the image, we don't care if it works or not...
+    if (!IsDriver)
+        Status = refit_call1_wrapper(BS->UnloadImage, ChildImageHandle);
+
+bailout:
+    MyFreePool(FullLoadOptions);
+    return ReturnStatus;
+} /* EFI_STATUS StartEFIImageList() */
+
+static EFI_STATUS StartEFIImage(IN EFI_DEVICE_PATH *DevicePath,
+                                IN CHAR16 *LoadOptions, IN UINTN LoaderType,
+                                IN CHAR16 *ImageTitle, IN CHAR8 OSType,
+                                OUT UINTN *ErrorInStep,
+                                IN BOOLEAN Verbose,
+                                IN BOOLEAN IsDriver
+                               )
+{
+    EFI_DEVICE_PATH *DevicePaths[2];
+
+    DevicePaths[0] = DevicePath;
+    DevicePaths[1] = NULL;
+    return StartEFIImageList(DevicePaths, LoadOptions, LoaderType, ImageTitle, OSType, ErrorInStep, Verbose, IsDriver);
+} /* static EFI_STATUS StartEFIImage() */
+
+// From gummiboot: Reboot the computer into its built-in user interface
+static EFI_STATUS RebootIntoFirmware(VOID) {
+    CHAR8 *b;
+    UINTN size;
+    UINT64 osind;
+    EFI_STATUS err;
+
+    osind = EFI_OS_INDICATIONS_BOOT_TO_FW_UI;
+
+    err = EfivarGetRaw(&GlobalGuid, L"OsIndications", &b, &size);
+    if (err == EFI_SUCCESS)
+        osind |= (UINT64)*b;
+    MyFreePool(b);
+
+    err = EfivarSetRaw(&GlobalGuid, L"OsIndications", (CHAR8 *)&osind, sizeof(UINT64), TRUE);
+    if (err != EFI_SUCCESS)
+        return err;
+
+    refit_call4_wrapper(RT->ResetSystem, EfiResetCold, EFI_SUCCESS, 0, NULL);
+    Print(L"Error calling ResetSystem: %r", err);
+    PauseForKey();
+    return err;
+}
+
+// Record the value of the loader's name/description in rEFInd's "PreviousBoot" EFI variable,
+// if it's different from what's already stored there.
+VOID StoreLoaderName(IN CHAR16 *Name) {
+    EFI_STATUS   Status;
+    CHAR16       *OldName = NULL;
+    UINTN        Length;
+
+    if (Name) {
+        Status = EfivarGetRaw(&RefindGuid, L"PreviousBoot", (CHAR8**) &OldName, &Length);
+        if ((Status != EFI_SUCCESS) || (StrCmp(OldName, Name) != 0)) {
+            EfivarSetRaw(&RefindGuid, L"PreviousBoot", (CHAR8*) Name, StrLen(Name) * 2 + 2, TRUE);
+        } // if
+        MyFreePool(OldName);
+    } // if
+} // VOID StoreLoaderName()
+
+//
+// EFI OS loader functions
+//
+
+// See http://www.thomas-krenn.com/en/wiki/Activating_the_Intel_VT_Virtualization_Feature
+// for information on Intel VMX features
+static VOID DoEnableAndLockVMX(VOID)
+{
+#if defined (EFIX64) | defined (EFI32)
+    UINT32 msr = 0x3a;
+    UINT32 low_bits = 0, high_bits = 0;
+
+    // is VMX active ?
+    __asm__ volatile ("rdmsr" : "=a" (low_bits), "=d" (high_bits) : "c" (msr));
+
+    // enable and lock vmx if not locked
+    if ((low_bits & 1) == 0) {
+        high_bits = 0;
+        low_bits = 0x05;
+        msr = 0x3a;
+        __asm__ volatile ("wrmsr" : : "c" (msr), "a" (low_bits), "d" (high_bits));
+    }
+#endif
+} // VOID DoEnableAndLockVMX()
+
+static VOID StartLoader(LOADER_ENTRY *Entry, CHAR16 *SelectionName)
+{
+    UINTN ErrorInStep = 0;
+
+    if (GlobalConfig.EnableAndLockVMX) {
+        DoEnableAndLockVMX();
+    }
+
+    BeginExternalScreen(Entry->UseGraphicsMode, L"Booting OS");
+    StoreLoaderName(SelectionName);
+    StartEFIImage(Entry->DevicePath, Entry->LoadOptions, TYPE_EFI,
+                  Basename(Entry->LoaderPath), Entry->OSType, &ErrorInStep, !Entry->UseGraphicsMode, FALSE);
+    FinishExternalScreen();
+}
+
+// Locate an initrd or initramfs file that matches the kernel specified by LoaderPath.
+// The matching file has a name that begins with "init" and includes the same version
+// number string as is found in LoaderPath -- but not a longer version number string.
+// For instance, if LoaderPath is \EFI\kernels\bzImage-3.3.0.efi, and if \EFI\kernels
+// has a file called initramfs-3.3.0.img, this function will return the string
+// '\EFI\kernels\initramfs-3.3.0.img'. If the directory ALSO contains the file
+// initramfs-3.3.0-rc7.img or initramfs-13.3.0.img, those files will NOT match;
+// 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);
+
+    // Add trailing backslash for root directory; necessary on some systems, but must
+    // NOT be added to all directories, since on other systems, a trailing backslash on
+    // anything but the root directory causes them to flake out!
+    if (StrLen(Path) == 0) {
+        MergeStrings(&Path, L"\\", 0);
+    } // if
+    DirIterOpen(Volume->RootDir, Path, &DirIter);
+    // Now add a trailing backslash if it was NOT added earlier, for consistency in
+    // building the InitrdName later....
+    if ((StrLen(Path) > 0) && (Path[StrLen(Path) - 1] != L'\\'))
+        MergeStrings(&Path, L"\\", 0);
+    while ((DirIterNext(&DirIter, 2, L"init*", &DirEntry)) && (InitrdName == NULL)) {
+        InitrdVersion = FindNumbers(DirEntry->FileName);
+        if (KernelVersion != NULL) {
+            if (MyStriCmp(InitrdVersion, KernelVersion)) {
+                InitrdName = PoolPrint(L"%s%s", Path, DirEntry->FileName);
+            } // if
+        } else {
+            if (InitrdVersion == NULL) {
+                InitrdName = PoolPrint(L"%s%s", Path, DirEntry->FileName);
+            } // if
+        } // if/else
+        MyFreePool(InitrdVersion);
+    } // while
+    DirIterClose(&DirIter);
+
+    // Note: Don't FreePool(FileName), since Basename returns a pointer WITHIN the string it's passed.
+    MyFreePool(KernelVersion);
+    MyFreePool(Path);
+    return (InitrdName);
+} // static CHAR16 * FindInitrd()
+
+LOADER_ENTRY * AddPreparedLoaderEntry(LOADER_ENTRY *Entry) {
+    AddMenuEntry(&MainMenu, (REFIT_MENU_ENTRY *)Entry);
+
+    return(Entry);
+} // LOADER_ENTRY * AddPreparedLoaderEntry()
+
+// Creates a copy of a menu screen.
+// Returns a pointer to the copy of the menu screen.
+static REFIT_MENU_SCREEN* CopyMenuScreen(REFIT_MENU_SCREEN *Entry) {
+    REFIT_MENU_SCREEN *NewEntry;
+    UINTN i;
+
+    NewEntry = AllocateZeroPool(sizeof(REFIT_MENU_SCREEN));
+    if ((Entry != NULL) && (NewEntry != NULL)) {
+        CopyMem(NewEntry, Entry, sizeof(REFIT_MENU_SCREEN));
+        NewEntry->Title = (Entry->Title) ? StrDuplicate(Entry->Title) : NULL;
+        NewEntry->TimeoutText = (Entry->TimeoutText) ? StrDuplicate(Entry->TimeoutText) : NULL;
+        if (Entry->TitleImage != NULL) {
+            NewEntry->TitleImage = AllocatePool(sizeof(EG_IMAGE));
+            if (NewEntry->TitleImage != NULL)
+                CopyMem(NewEntry->TitleImage, Entry->TitleImage, sizeof(EG_IMAGE));
+        } // if
+        NewEntry->InfoLines = (CHAR16**) AllocateZeroPool(Entry->InfoLineCount * (sizeof(CHAR16*)));
+        for (i = 0; i < Entry->InfoLineCount && NewEntry->InfoLines; i++) {
+            NewEntry->InfoLines[i] = (Entry->InfoLines[i]) ? StrDuplicate(Entry->InfoLines[i]) : NULL;
+        } // for
+        NewEntry->Entries = (REFIT_MENU_ENTRY**) AllocateZeroPool(Entry->EntryCount * (sizeof (REFIT_MENU_ENTRY*)));
+        for (i = 0; i < Entry->EntryCount && NewEntry->Entries; i++) {
+            AddMenuEntry(NewEntry, Entry->Entries[i]);
+        } // for
+        NewEntry->Hint1 = (Entry->Hint1) ? StrDuplicate(Entry->Hint1) : NULL;
+        NewEntry->Hint2 = (Entry->Hint2) ? StrDuplicate(Entry->Hint2) : NULL;
+    } // if
+    return (NewEntry);
+} // static REFIT_MENU_SCREEN* CopyMenuScreen()
+
+// Creates a copy of a menu entry. Intended to enable moving a stack-based
+// menu entry (such as the ones for the "reboot" and "exit" functions) to
+// to the heap. This enables easier deletion of the whole set of menu
+// entries when re-scanning.
+// Returns a pointer to the copy of the menu entry.
+static REFIT_MENU_ENTRY* CopyMenuEntry(REFIT_MENU_ENTRY *Entry) {
+    REFIT_MENU_ENTRY *NewEntry;
+
+    NewEntry = AllocateZeroPool(sizeof(REFIT_MENU_ENTRY));
+    if ((Entry != NULL) && (NewEntry != NULL)) {
+        CopyMem(NewEntry, Entry, sizeof(REFIT_MENU_ENTRY));
+        NewEntry->Title = (Entry->Title) ? StrDuplicate(Entry->Title) : NULL;
+        if (Entry->BadgeImage != NULL) {
+            NewEntry->BadgeImage = AllocatePool(sizeof(EG_IMAGE));
+            if (NewEntry->BadgeImage != NULL)
+                CopyMem(NewEntry->BadgeImage, Entry->BadgeImage, sizeof(EG_IMAGE));
+        }
+        if (Entry->Image != NULL) {
+            NewEntry->Image = AllocatePool(sizeof(EG_IMAGE));
+            if (NewEntry->Image != NULL)
+                CopyMem(NewEntry->Image, Entry->Image, sizeof(EG_IMAGE));
+        }
+        if (Entry->SubScreen != NULL) {
+            NewEntry->SubScreen = CopyMenuScreen(Entry->SubScreen);
+        }
+    } // if
+    return (NewEntry);
+} // REFIT_MENU_ENTRY* CopyMenuEntry()
+
+// Creates a new LOADER_ENTRY data structure and populates it with
+// default values from the specified Entry, or NULL values if Entry
+// is unspecified (NULL).
+// Returns a pointer to the new data structure, or NULL if it
+// couldn't be allocated
+LOADER_ENTRY *InitializeLoaderEntry(IN LOADER_ENTRY *Entry) {
+    LOADER_ENTRY *NewEntry = NULL;
+
+    NewEntry = AllocateZeroPool(sizeof(LOADER_ENTRY));
+    if (NewEntry != NULL) {
+        NewEntry->me.Title        = NULL;
+        NewEntry->me.Tag          = TAG_LOADER;
+        NewEntry->Enabled         = TRUE;
+        NewEntry->UseGraphicsMode = FALSE;
+        NewEntry->OSType          = 0;
+        if (Entry != NULL) {
+            NewEntry->LoaderPath      = (Entry->LoaderPath) ? StrDuplicate(Entry->LoaderPath) : NULL;
+            NewEntry->VolName         = (Entry->VolName) ? StrDuplicate(Entry->VolName) : NULL;
+            NewEntry->DevicePath      = Entry->DevicePath;
+            NewEntry->UseGraphicsMode = Entry->UseGraphicsMode;
+            NewEntry->LoadOptions     = (Entry->LoadOptions) ? StrDuplicate(Entry->LoadOptions) : NULL;
+            NewEntry->InitrdPath      = (Entry->InitrdPath) ? StrDuplicate(Entry->InitrdPath) : NULL;
+        }
+    } // if
+    return (NewEntry);
+} // LOADER_ENTRY *InitializeLoaderEntry()
+
+// Adds InitrdPath to Options, but only if Options doesn't already include an
+// initrd= line. Done to enable overriding the default initrd selection in a
+// refind_linux.conf file's options list.
+// Returns a pointer to a new string. The calling function is responsible for
+// freeing its memory.
+static CHAR16 *AddInitrdToOptions(CHAR16 *Options, CHAR16 *InitrdPath) {
+    CHAR16 *NewOptions = NULL;
+
+    if (Options != NULL)
+        NewOptions = StrDuplicate(Options);
+    if ((InitrdPath != NULL) && !StriSubCmp(L"initrd=", Options)) {
+        MergeStrings(&NewOptions, L"initrd=", L' ');
+        MergeStrings(&NewOptions, InitrdPath, 0);
+    }
+    return NewOptions;
+} // CHAR16 *AddInitrdToOptions()
+
+// Prepare a REFIT_MENU_SCREEN data structure for a subscreen entry. This sets up
+// the default entry that launches the boot loader using the same options as the
+// main Entry does. Subsequent options can be added by the calling function.
+// If a subscreen already exists in the Entry that's passed to this function,
+// it's left unchanged and a pointer to it is returned.
+// Returns a pointer to the new subscreen data structure, or NULL if there
+// were problems allocating memory.
+REFIT_MENU_SCREEN *InitializeSubScreen(IN LOADER_ENTRY *Entry) {
+    CHAR16              *FileName, *MainOptions = NULL;
+    REFIT_MENU_SCREEN   *SubScreen = NULL;
+    LOADER_ENTRY        *SubEntry;
+
+    FileName = Basename(Entry->LoaderPath);
+    if (Entry->me.SubScreen == NULL) { // No subscreen yet; initialize default entry....
+        SubScreen = AllocateZeroPool(sizeof(REFIT_MENU_SCREEN));
+        if (SubScreen != NULL) {
+            SubScreen->Title = AllocateZeroPool(sizeof(CHAR16) * 256);
+            SPrint(SubScreen->Title, 255, L"Boot Options for %s on %s",
+                   (Entry->Title != NULL) ? Entry->Title : FileName, Entry->VolName);
+            SubScreen->TitleImage = Entry->me.Image;
+            // default entry
+            SubEntry = InitializeLoaderEntry(Entry);
+            if (SubEntry != NULL) {
+                SubEntry->me.Title = StrDuplicate(L"Boot using default options");
+                MainOptions = SubEntry->LoadOptions;
+                SubEntry->LoadOptions = AddInitrdToOptions(MainOptions, SubEntry->InitrdPath);
+                MyFreePool(MainOptions);
+                AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry);
+            } // if (SubEntry != NULL)
+            SubScreen->Hint1 = StrDuplicate(SUBSCREEN_HINT1);
+            if (GlobalConfig.HideUIFlags & HIDEUI_FLAG_EDITOR) {
+                SubScreen->Hint2 = StrDuplicate(SUBSCREEN_HINT2_NO_EDITOR);
+            } else {
+                SubScreen->Hint2 = StrDuplicate(SUBSCREEN_HINT2);
+            } // if/else
+        } // if (SubScreen != NULL)
+    } else { // existing subscreen; less initialization, and just add new entry later....
+        SubScreen = Entry->me.SubScreen;
+    } // if/else
+    return SubScreen;
+} // REFIT_MENU_SCREEN *InitializeSubScreen()
+
+VOID GenerateSubScreen(LOADER_ENTRY *Entry, IN REFIT_VOLUME *Volume, IN BOOLEAN GenerateReturn) {
+    REFIT_MENU_SCREEN  *SubScreen;
+    LOADER_ENTRY       *SubEntry;
+    CHAR16             *InitrdName;
+    CHAR16             DiagsFileName[256];
+    REFIT_FILE         *File;
+    UINTN              TokenCount;
+    CHAR16             **TokenList;
+
+    // create the submenu
+    if (StrLen(Entry->Title) == 0) {
+        MyFreePool(Entry->Title);
+        Entry->Title = NULL;
+    }
+    SubScreen = InitializeSubScreen(Entry);
+
+    // loader-specific submenu entries
+    if (Entry->OSType == 'M') {          // entries for 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";
+            SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_OSX;
+            AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry);
+        } // if
+
+        SubEntry = InitializeLoaderEntry(Entry);
+        if (SubEntry != NULL) {
+            SubEntry->me.Title        = L"Boot Mac OS X with a 32-bit kernel";
+            SubEntry->LoadOptions     = L"arch=i386";
+            SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_OSX;
+            AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry);
+        } // if
+#endif
+
+        if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_SINGLEUSER)) {
+            SubEntry = InitializeLoaderEntry(Entry);
+            if (SubEntry != NULL) {
+                SubEntry->me.Title        = L"Boot 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
+        } // single-user mode allowed
+
+        if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_SAFEMODE)) {
+            SubEntry = InitializeLoaderEntry(Entry);
+            if (SubEntry != NULL) {
+                SubEntry->me.Title        = L"Boot Mac OS X in safe mode";
+                SubEntry->UseGraphicsMode = FALSE;
+                SubEntry->LoadOptions     = L"-v -x";
+                AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry);
+            } // if
+        } // safe mode allowed
+
+        // check for Apple hardware diagnostics
+        StrCpy(DiagsFileName, L"System\\Library\\CoreServices\\.diagnostics\\diags.efi");
+        if (FileExists(Volume->RootDir, DiagsFileName) && !(GlobalConfig.HideUIFlags & HIDEUI_FLAG_HWTEST)) {
+            SubEntry = InitializeLoaderEntry(Entry);
+            if (SubEntry != NULL) {
+                SubEntry->me.Title        = L"Run Apple Hardware Test";
+                MyFreePool(SubEntry->LoaderPath);
+                SubEntry->LoaderPath      = StrDuplicate(DiagsFileName);
+                SubEntry->DevicePath      = FileDevicePath(Volume->DeviceHandle, SubEntry->LoaderPath);
+                SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_OSX;
+                AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry);
+            } // if
+        } // if diagnostics entry found
+
+    } else if (Entry->OSType == 'L') {   // entries for Linux kernels with EFI stub loaders
+        File = ReadLinuxOptionsFile(Entry->LoaderPath, Volume);
+        if (File != NULL) {
+            InitrdName =  FindInitrd(Entry->LoaderPath, Volume);
+            TokenCount = ReadTokenLine(File, &TokenList);
+            // first entry requires special processing, since it was initially set
+            // up with a default title but correct options by InitializeSubScreen(),
+            // earlier....
+            if ((TokenCount > 1) && (SubScreen->Entries != NULL) && (SubScreen->Entries[0] != NULL)) {
+                MyFreePool(SubScreen->Entries[0]->Title);
+                SubScreen->Entries[0]->Title = TokenList[0] ? StrDuplicate(TokenList[0]) : StrDuplicate(L"Boot Linux");
+            } // if
+            FreeTokenLine(&TokenList, &TokenCount);
+            while ((TokenCount = ReadTokenLine(File, &TokenList)) > 1) {
+                SubEntry = InitializeLoaderEntry(Entry);
+                SubEntry->me.Title = TokenList[0] ? StrDuplicate(TokenList[0]) : StrDuplicate(L"Boot Linux");
+                MyFreePool(SubEntry->LoadOptions);
+                SubEntry->LoadOptions = AddInitrdToOptions(TokenList[1], InitrdName);
+                FreeTokenLine(&TokenList, &TokenCount);
+                SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_LINUX;
+                AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry);
+            } // while
+            MyFreePool(InitrdName);
+            MyFreePool(File);
+        } // if
+
+    } else if (Entry->OSType == 'E') {   // entries for ELILO
+        SubEntry = InitializeLoaderEntry(Entry);
+        if (SubEntry != NULL) {
+            SubEntry->me.Title        = L"Run ELILO in interactive mode";
+            SubEntry->LoadOptions     = L"-p";
+            SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_ELILO;
+            AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry);
+        }
+
+        SubEntry = InitializeLoaderEntry(Entry);
+        if (SubEntry != NULL) {
+            SubEntry->me.Title        = L"Boot Linux for a 17\" iMac or a 15\" MacBook Pro (*)";
+            SubEntry->LoadOptions     = L"-d 0 i17";
+            SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_ELILO;
+            AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry);
+        }
+
+        SubEntry = InitializeLoaderEntry(Entry);
+        if (SubEntry != NULL) {
+            SubEntry->me.Title        = L"Boot Linux for a 20\" iMac (*)";
+            SubEntry->LoadOptions     = L"-d 0 i20";
+            SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_ELILO;
+            AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry);
+        }
+
+        SubEntry = InitializeLoaderEntry(Entry);
+        if (SubEntry != NULL) {
+            SubEntry->me.Title        = L"Boot Linux for a Mac Mini (*)";
+            SubEntry->LoadOptions     = L"-d 0 mini";
+            SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_ELILO;
+            AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry);
+        }
+
+        AddMenuInfoLine(SubScreen, L"NOTE: This is an example. Entries");
+        AddMenuInfoLine(SubScreen, L"marked with (*) may not work.");
+
+    } else if (Entry->OSType == 'X') {   // entries for xom.efi
+        // by default, skip the built-in selection and boot from hard disk only
+        Entry->LoadOptions = L"-s -h";
+
+        SubEntry = InitializeLoaderEntry(Entry);
+        if (SubEntry != NULL) {
+            SubEntry->me.Title        = L"Boot Windows from Hard Disk";
+            SubEntry->LoadOptions     = L"-s -h";
+            SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_WINDOWS;
+            AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry);
+        }
+
+        SubEntry = InitializeLoaderEntry(Entry);
+        if (SubEntry != NULL) {
+            SubEntry->me.Title        = L"Boot Windows from CD-ROM";
+            SubEntry->LoadOptions     = L"-s -c";
+            SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_WINDOWS;
+            AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry);
+        }
+
+        SubEntry = InitializeLoaderEntry(Entry);
+        if (SubEntry != NULL) {
+            SubEntry->me.Title        = L"Run XOM in text mode";
+            SubEntry->LoadOptions     = L"-v";
+            SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_WINDOWS;
+            AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry);
+        }
+    } // entries for xom.efi
+    if (GenerateReturn)
+        AddMenuEntry(SubScreen, &MenuEntryReturn);
+    Entry->me.SubScreen = SubScreen;
+} // VOID GenerateSubScreen()
+
+// Returns options for a Linux kernel. Reads them from an options file in the
+// kernel's directory; and if present, adds an initrd= option for an initial
+// RAM disk file with the same version number as the kernel file.
+static CHAR16 * GetMainLinuxOptions(IN CHAR16 * LoaderPath, IN REFIT_VOLUME *Volume) {
+    CHAR16 *Options = NULL, *InitrdName, *FullOptions = NULL;
+
+    Options = GetFirstOptionsFromFile(LoaderPath, Volume);
+    InitrdName = FindInitrd(LoaderPath, Volume);
+    FullOptions = AddInitrdToOptions(Options, InitrdName);
+
+    MyFreePool(Options);
+    MyFreePool(InitrdName);
+    return (FullOptions);
+} // static CHAR16 * GetMainLinuxOptions()
+
+// Read the specified file and add values of "ID", "NAME", or "DISTRIB_ID" tokens to
+// OSIconName list. Intended for adding Linux distribution clues gleaned from
+// /etc/lsb-release and /etc/os-release files.
+static VOID ParseReleaseFile(CHAR16 **OSIconName, REFIT_VOLUME *Volume, CHAR16 *FileName) {
+    UINTN       FileSize = 0;
+    REFIT_FILE  File;
+    CHAR16      **TokenList;
+    UINTN       TokenCount = 0;
+
+    if ((Volume == NULL) || (FileName == NULL) || (OSIconName == NULL) || (*OSIconName == NULL))
+        return;
+
+    if (FileExists(Volume->RootDir, FileName) &&
+        (ReadFile(Volume->RootDir, FileName, &File, &FileSize) == EFI_SUCCESS)) {
+        do {
+            TokenCount = ReadTokenLine(&File, &TokenList);
+            if ((TokenCount > 1) && (MyStriCmp(TokenList[0], L"ID") ||
+                                     MyStriCmp(TokenList[0], L"NAME") ||
+                                     MyStriCmp(TokenList[0], L"DISTRIB_ID"))) {
+                MergeWords(OSIconName, TokenList[1], L',');
+            } // if
+            FreeTokenLine(&TokenList, &TokenCount);
+        } while (TokenCount > 0);
+        MyFreePool(File.Buffer);
+    } // if
+} // VOID ParseReleaseFile()
+
+// Try to guess the name of the Linux distribution & add that name to
+// OSIconName list.
+static VOID GuessLinuxDistribution(CHAR16 **OSIconName, REFIT_VOLUME *Volume, CHAR16 *LoaderPath) {
+    // If on Linux root fs, /etc/os-release or /etc/lsb-release file probably has clues....
+    ParseReleaseFile(OSIconName, Volume, L"etc\\lsb-release");
+    ParseReleaseFile(OSIconName, Volume, L"etc\\os-release");
+
+    // Search for clues in the kernel's filename....
+    if (StriSubCmp(L".fc", LoaderPath))
+        MergeStrings(OSIconName, L"fedora", L',');
+    if (StriSubCmp(L".el", LoaderPath))
+        MergeStrings(OSIconName, L"redhat", L',');
+} // VOID GuessLinuxDistribution()
+
+// Sets a few defaults for a loader entry -- mainly the icon, but also the OS type
+// code and shortcut letter. For Linux EFI stub loaders, also sets kernel options
+// that will (with luck) work fairly automatically.
+VOID SetLoaderDefaults(LOADER_ENTRY *Entry, CHAR16 *LoaderPath, REFIT_VOLUME *Volume) {
+    CHAR16      *NameClues, *PathOnly, *NoExtension, *OSIconName = NULL, *Temp;
+    CHAR16      ShortcutLetter = 0;
+
+    NameClues = Basename(LoaderPath);
+    PathOnly = FindPath(LoaderPath);
+    NoExtension = StripEfiExtension(NameClues);
+
+    if (Volume->DiskKind == DISK_KIND_NET) {
+        MergeStrings(&NameClues, Entry->me.Title, L' ');
+    } else {
+        // locate a custom icon for the loader
+        // Anything found here takes precedence over the "hints" in the OSIconName variable
+        if (!Entry->me.Image) {
+            Entry->me.Image = egLoadIconAnyType(Volume->RootDir, PathOnly, NoExtension, GlobalConfig.IconSizes[ICON_SIZE_BIG]);
+        }
+        if (!Entry->me.Image) {
+            Entry->me.Image = egCopyImage(Volume->VolIconImage);
+        }
+
+        // Begin creating icon "hints" by using last part of directory path leading
+        // to the loader
+        Temp = FindLastDirName(LoaderPath);
+        MergeStrings(&OSIconName, Temp, L',');
+        MyFreePool(Temp);
+        Temp = NULL;
+        if (OSIconName != NULL) {
+            ShortcutLetter = OSIconName[0];
+        }
+
+        // Add every "word" in the volume label, delimited by spaces, dashes (-), or
+        // underscores (_), to the list of hints to be used in searching for OS
+        // icons.
+        MergeWords(&OSIconName, Volume->VolName, L',');
+    } // if/else network boot
+
+    // detect specific loaders
+    if (StriSubCmp(L"bzImage", NameClues) || StriSubCmp(L"vmlinuz", NameClues) || StriSubCmp(L"kernel", NameClues)) {
+        if (Volume->DiskKind != DISK_KIND_NET) {
+            GuessLinuxDistribution(&OSIconName, Volume, LoaderPath);
+            Entry->LoadOptions = GetMainLinuxOptions(LoaderPath, Volume);
+        }
+        MergeStrings(&OSIconName, L"linux", L',');
+        Entry->OSType = 'L';
+        if (ShortcutLetter == 0)
+            ShortcutLetter = 'L';
+        Entry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_LINUX;
+    } else if (StriSubCmp(L"refit", LoaderPath)) {
+        MergeStrings(&OSIconName, L"refit", L',');
+        Entry->OSType = 'R';
+        ShortcutLetter = 'R';
+    } else if (StriSubCmp(L"refind", LoaderPath)) {
+        MergeStrings(&OSIconName, L"refind", L',');
+        Entry->OSType = 'R';
+        ShortcutLetter = 'R';
+    } else if (MyStriCmp(LoaderPath, MACOSX_LOADER_PATH)) {
+        MergeStrings(&OSIconName, L"mac", L',');
+        Entry->OSType = 'M';
+        ShortcutLetter = 'M';
+        Entry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_OSX;
+    } else if (MyStriCmp(NameClues, L"diags.efi")) {
+        MergeStrings(&OSIconName, L"hwtest", L',');
+    } else if (MyStriCmp(NameClues, L"e.efi") || MyStriCmp(NameClues, L"elilo.efi") || StriSubCmp(L"elilo", NameClues)) {
+        MergeStrings(&OSIconName, L"elilo,linux", L',');
+        Entry->OSType = 'E';
+        if (ShortcutLetter == 0)
+            ShortcutLetter = 'L';
+        Entry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_ELILO;
+    } else if (StriSubCmp(L"grub", NameClues)) {
+        MergeStrings(&OSIconName, L"grub,linux", L',');
+        Entry->OSType = 'G';
+        ShortcutLetter = 'G';
+        Entry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_GRUB;
+    } else if (MyStriCmp(NameClues, L"cdboot.efi") ||
+               MyStriCmp(NameClues, L"bootmgr.efi") ||
+               MyStriCmp(NameClues, L"bootmgfw.efi") ||
+               MyStriCmp(NameClues, L"bkpbootmgfw.efi")) {
+        MergeStrings(&OSIconName, L"win8", L',');
+        Entry->OSType = 'W';
+        ShortcutLetter = 'W';
+        Entry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_WINDOWS;
+    } else if (MyStriCmp(NameClues, L"xom.efi")) {
+        MergeStrings(&OSIconName, L"xom,win,win8", L',');
+        Entry->OSType = 'X';
+        ShortcutLetter = 'W';
+        Entry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_WINDOWS;
+    }
+    else if (StriSubCmp(L"ipxe", NameClues)) {
+        Entry->OSType = 'N';
+        ShortcutLetter = 'N';
+        MergeStrings(&OSIconName, L"network", L',');
+    } 
+
+    if ((ShortcutLetter >= 'a') && (ShortcutLetter <= 'z'))
+        ShortcutLetter = ShortcutLetter - 'a' + 'A'; // convert lowercase to uppercase
+    Entry->me.ShortcutLetter = ShortcutLetter;
+    if (Entry->me.Image == NULL)
+        Entry->me.Image = LoadOSIcon(OSIconName, L"unknown", FALSE);
+    MyFreePool(PathOnly);
+} // VOID SetLoaderDefaults()
+
+// Add a specified EFI boot loader to the list, using automatic settings
+// for icons, options, etc.
+static LOADER_ENTRY * AddLoaderEntry(IN CHAR16 *LoaderPath, IN CHAR16 *LoaderTitle, IN REFIT_VOLUME *Volume, IN BOOLEAN SubScreenReturn) {
+    LOADER_ENTRY  *Entry;
+
+    CleanUpPathNameSlashes(LoaderPath);
+    Entry = InitializeLoaderEntry(NULL);
+    if (Entry != NULL) {
+        Entry->Title = StrDuplicate((LoaderTitle != NULL) ? LoaderTitle : LoaderPath);
+        Entry->me.Title = AllocateZeroPool(sizeof(CHAR16) * 256);
+        // Extra space at end of Entry->me.Title enables searching on Volume->VolName even if another volume
+        // name is identical except for something added to the end (e.g., VolB1 vs. VolB12).
+        // Note: Volume->VolName will be NULL for network boot programs.
+        if (Volume->VolName)
+            SPrint(Entry->me.Title, 255, L"Boot %s from %s ", (LoaderTitle != NULL) ? LoaderTitle : LoaderPath, Volume->VolName);
+        else
+            SPrint(Entry->me.Title, 255, L"Boot %s ", (LoaderTitle != NULL) ? LoaderTitle : LoaderPath);
+        Entry->me.Row = 0;
+        Entry->me.BadgeImage = Volume->VolBadgeImage;
+        if ((LoaderPath != NULL) && (LoaderPath[0] != L'\\')) {
+            Entry->LoaderPath = StrDuplicate(L"\\");
+        } else {
+            Entry->LoaderPath = NULL;
+        }
+        MergeStrings(&(Entry->LoaderPath), LoaderPath, 0);
+        Entry->VolName = Volume->VolName;
+        Entry->DevicePath = FileDevicePath(Volume->DeviceHandle, Entry->LoaderPath);
+        SetLoaderDefaults(Entry, LoaderPath, Volume);
+        GenerateSubScreen(Entry, Volume, SubScreenReturn);
+        AddMenuEntry(&MainMenu, (REFIT_MENU_ENTRY *)Entry);
+    }
+
+    return(Entry);
+} // LOADER_ENTRY * AddLoaderEntry()
+
+// Add a Linux kernel as a submenu entry for another (pre-existing) Linux kernel entry.
+static VOID AddKernelToSubmenu(LOADER_ENTRY * TargetLoader, CHAR16 *FileName, REFIT_VOLUME *Volume) {
+    REFIT_FILE          *File;
+    CHAR16              **TokenList = NULL, *InitrdName, *SubmenuName = NULL, *VolName = NULL, *Path = NULL, *Title;
+    REFIT_MENU_SCREEN   *SubScreen;
+    LOADER_ENTRY        *SubEntry;
+    UINTN               TokenCount;
+
+    File = ReadLinuxOptionsFile(TargetLoader->LoaderPath, Volume);
+    if (File != NULL) {
+        SubScreen = TargetLoader->me.SubScreen;
+        InitrdName = FindInitrd(FileName, Volume);
+        while ((TokenCount = ReadTokenLine(File, &TokenList)) > 1) {
+            SubEntry = InitializeLoaderEntry(TargetLoader);
+            SplitPathName(FileName, &VolName, &Path, &SubmenuName);
+            MergeStrings(&SubmenuName, L": ", '\0');
+            MergeStrings(&SubmenuName, TokenList[0] ? StrDuplicate(TokenList[0]) : StrDuplicate(L"Boot Linux"), '\0');
+            Title = StrDuplicate(SubmenuName);
+            LimitStringLength(Title, MAX_LINE_LENGTH);
+            SubEntry->me.Title = Title;
+            MyFreePool(SubEntry->LoadOptions);
+            SubEntry->LoadOptions = AddInitrdToOptions(TokenList[1], InitrdName);
+            MyFreePool(SubEntry->LoaderPath);
+            SubEntry->LoaderPath = StrDuplicate(FileName);
+            CleanUpPathNameSlashes(SubEntry->LoaderPath);
+            SubEntry->DevicePath = FileDevicePath(Volume->DeviceHandle, SubEntry->LoaderPath);
+            FreeTokenLine(&TokenList, &TokenCount);
+            SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_LINUX;
+            AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry);
+        } // while
+        MyFreePool(VolName);
+        MyFreePool(Path);
+        MyFreePool(SubmenuName);
+        MyFreePool(InitrdName);
+        MyFreePool(File);
+    } // if
+} // static VOID AddKernelToSubmenu()
+
+// Returns -1 if (Time1 < Time2), +1 if (Time1 > Time2), or 0 if
+// (Time1 == Time2). Precision is only to the nearest second; since
+// this is used for sorting boot loader entries, differences smaller
+// than this are likely to be meaningless (and unlikely!).
+INTN TimeComp(IN EFI_TIME *Time1, IN EFI_TIME *Time2) {
+    INT64 Time1InSeconds, Time2InSeconds;
+
+    // Following values are overestimates; I'm assuming 31 days in every month.
+    // This is fine for the purpose of this function, which is limited
+    Time1InSeconds = Time1->Second + (Time1->Minute * 60) + (Time1->Hour * 3600) + (Time1->Day * 86400) +
+                        (Time1->Month * 2678400) + ((Time1->Year - 1998) * 32140800);
+    Time2InSeconds = Time2->Second + (Time2->Minute * 60) + (Time2->Hour * 3600) + (Time2->Day * 86400) +
+                        (Time2->Month * 2678400) + ((Time2->Year - 1998) * 32140800);
+    if (Time1InSeconds < Time2InSeconds)
+        return (-1);
+    else if (Time1InSeconds > Time2InSeconds)
+        return (1);
+
+    return 0;
+} // INTN TimeComp()
+
+// Adds a loader list element, keeping it sorted by date. Returns the new
+// first element (the one with the most recent date).
+static struct LOADER_LIST * AddLoaderListEntry(struct LOADER_LIST *LoaderList, struct LOADER_LIST *NewEntry) {
+    struct LOADER_LIST *LatestEntry, *CurrentEntry, *PrevEntry = NULL;
+
+    LatestEntry = CurrentEntry = LoaderList;
+    if (LoaderList == NULL) {
+        LatestEntry = NewEntry;
+    } else {
+        while ((CurrentEntry != NULL) && (TimeComp(&(NewEntry->TimeStamp), &(CurrentEntry->TimeStamp)) < 0)) {
+            PrevEntry = CurrentEntry;
+            CurrentEntry = CurrentEntry->NextEntry;
+        } // while
+        NewEntry->NextEntry = CurrentEntry;
+        if (PrevEntry == NULL) {
+            LatestEntry = NewEntry;
+        } else {
+            PrevEntry->NextEntry = NewEntry;
+        } // if/else
+    } // if/else
+    return (LatestEntry);
+} // static VOID AddLoaderListEntry()
+
+// Delete the LOADER_LIST linked list
+static VOID CleanUpLoaderList(struct LOADER_LIST *LoaderList) {
+    struct LOADER_LIST *Temp;
+
+    while (LoaderList != NULL) {
+        Temp = LoaderList;
+        LoaderList = LoaderList->NextEntry;
+        MyFreePool(Temp->FileName);
+        MyFreePool(Temp);
+    } // while
+} // static VOID CleanUpLoaderList()
+
+// Returns FALSE if the specified file/volume matches the GlobalConfig.DontScanDirs
+// or GlobalConfig.DontScanVolumes specification, or if Path points to a volume
+// other than the one specified by Volume, or if the specified path is SelfDir.
+// Returns TRUE if none of these conditions is met -- that is, if the path is
+// eligible for scanning.
+static BOOLEAN ShouldScan(REFIT_VOLUME *Volume, CHAR16 *Path) {
+    CHAR16   *VolName = NULL, *DontScanDir, *PathCopy = NULL;
+    UINTN    i = 0;
+    BOOLEAN  ScanIt = TRUE;
+
+    if ((IsIn(Volume->VolName, GlobalConfig.DontScanVolumes)) || (IsIn(Volume->PartName, GlobalConfig.DontScanVolumes)))
+        return FALSE;
+
+    if (MyStriCmp(Path, SelfDirPath) && (Volume->DeviceHandle == SelfVolume->DeviceHandle))
+        return FALSE;
+
+    // See if Path includes an explicit volume declaration that's NOT Volume....
+    PathCopy = StrDuplicate(Path);
+    if (SplitVolumeAndFilename(&PathCopy, &VolName)) {
+        VolumeNumberToName(Volume, &VolName);
+        if (VolName && !MyStriCmp(VolName, Volume->VolName)) {
+            ScanIt = FALSE;
+        } // if
+    } // if Path includes volume specification
+    MyFreePool(PathCopy);
+    MyFreePool(VolName);
+    VolName = NULL;
+
+    // See if Volume is in GlobalConfig.DontScanDirs....
+    while (ScanIt && (DontScanDir = FindCommaDelimited(GlobalConfig.DontScanDirs, i++))) {
+        SplitVolumeAndFilename(&DontScanDir, &VolName);
+        CleanUpPathNameSlashes(DontScanDir);
+        VolumeNumberToName(Volume, &VolName);
+        if (VolName != NULL) {
+            if (MyStriCmp(VolName, Volume->VolName) && MyStriCmp(DontScanDir, Path))
+                ScanIt = FALSE;
+        } else {
+            if (MyStriCmp(DontScanDir, Path))
+                ScanIt = FALSE;
+        }
+        MyFreePool(DontScanDir);
+        MyFreePool(VolName);
+        DontScanDir = NULL;
+        VolName = NULL;
+    } // while()
+
+    return ScanIt;
+} // BOOLEAN ShouldScan()
+
+// Returns TRUE if the file is byte-for-byte identical with the fallback file
+// on the volume AND if the file is not itself the fallback file; returns
+// FALSE if the file is not identical to the fallback file OR if the file
+// IS the fallback file. Intended for use in excluding the fallback boot
+// loader when it's a duplicate of another boot loader.
+static BOOLEAN DuplicatesFallback(IN REFIT_VOLUME *Volume, IN CHAR16 *FileName) {
+    CHAR8           *FileContents, *FallbackContents;
+    EFI_FILE_HANDLE FileHandle, FallbackHandle;
+    EFI_FILE_INFO   *FileInfo, *FallbackInfo;
+    UINTN           FileSize = 0, FallbackSize = 0;
+    EFI_STATUS      Status;
+    BOOLEAN         AreIdentical = FALSE;
+
+    if (!FileExists(Volume->RootDir, FileName) || !FileExists(Volume->RootDir, FALLBACK_FULLNAME))
+        return FALSE;
+
+    CleanUpPathNameSlashes(FileName);
+
+    if (MyStriCmp(FileName, FALLBACK_FULLNAME))
+        return FALSE; // identical filenames, so not a duplicate....
+
+    Status = refit_call5_wrapper(Volume->RootDir->Open, Volume->RootDir, &FileHandle, FileName, EFI_FILE_MODE_READ, 0);
+    if (Status == EFI_SUCCESS) {
+        FileInfo = LibFileInfo(FileHandle);
+        FileSize = FileInfo->FileSize;
+    } else {
+        return FALSE;
+    }
+
+    Status = refit_call5_wrapper(Volume->RootDir->Open, Volume->RootDir, &FallbackHandle, FALLBACK_FULLNAME, EFI_FILE_MODE_READ, 0);
+    if (Status == EFI_SUCCESS) {
+        FallbackInfo = LibFileInfo(FallbackHandle);
+        FallbackSize = FallbackInfo->FileSize;
+    } else {
+        refit_call1_wrapper(FileHandle->Close, FileHandle);
+        return FALSE;
+    }
+
+    if (FallbackSize != FileSize) { // not same size, so can't be identical
+        AreIdentical = FALSE;
+    } else { // could be identical; do full check....
+        FileContents = AllocatePool(FileSize);
+        FallbackContents = AllocatePool(FallbackSize);
+        if (FileContents && FallbackContents) {
+            Status = refit_call3_wrapper(FileHandle->Read, FileHandle, &FileSize, FileContents);
+            if (Status == EFI_SUCCESS) {
+                Status = refit_call3_wrapper(FallbackHandle->Read, FallbackHandle, &FallbackSize, FallbackContents);
+            }
+            if (Status == EFI_SUCCESS) {
+                AreIdentical = (CompareMem(FileContents, FallbackContents, FileSize) == 0);
+            } // if
+        } // if
+        MyFreePool(FileContents);
+        MyFreePool(FallbackContents);
+    } // if/else
+
+    // BUG ALERT: Some systems (e.g., DUET, some Macs with large displays) crash if the
+    // following two calls are reversed. Go figure....
+    refit_call1_wrapper(FileHandle->Close, FallbackHandle);
+    refit_call1_wrapper(FileHandle->Close, FileHandle);
+    return AreIdentical;
+} // BOOLEAN DuplicatesFallback()
+
+// Returns FALSE if two measures of file size are identical for a single file,
+// TRUE if not or if the file can't be opened and the other measure is non-0.
+// Despite the function's name, this isn't really a direct test of symbolic
+// link status, since EFI doesn't officially support symlinks. It does seem
+// to be a reliable indicator, though. (OTOH, some disk errors might cause a
+// file to fail to open, which would return a false positive -- but as I use
+// this function to exclude symbolic links from the list of boot loaders,
+// that would be fine, since such boot loaders wouldn't work.)
+static BOOLEAN IsSymbolicLink(REFIT_VOLUME *Volume, CHAR16 *Path, EFI_FILE_INFO *DirEntry) {
+    EFI_FILE_HANDLE FileHandle;
+    EFI_FILE_INFO   *FileInfo = NULL;
+    EFI_STATUS      Status;
+    UINTN           FileSize2 = 0;
+    CHAR16          *FileName;
+
+    FileName = StrDuplicate(Path);
+    MergeStrings(&FileName, DirEntry->FileName, L'\\');
+    CleanUpPathNameSlashes(FileName);
+
+    Status = refit_call5_wrapper(Volume->RootDir->Open, Volume->RootDir, &FileHandle, FileName, EFI_FILE_MODE_READ, 0);
+    if (Status == EFI_SUCCESS) {
+        FileInfo = LibFileInfo(FileHandle);
+        if (FileInfo != NULL)
+            FileSize2 = FileInfo->FileSize;
+    }
+
+    MyFreePool(FileName);
+    MyFreePool(FileInfo);
+
+    return (DirEntry->FileSize != FileSize2);
+} // BOOLEAN IsSymbolicLink()
+
+// Returns TRUE if a file with the same name as the original but with
+// ".efi.signed" is also present in the same directory. Ubuntu is using
+// this filename as a signed version of the original unsigned kernel, and
+// there's no point in cluttering the display with two kernels that will
+// behave identically on non-SB systems, or when one will fail when SB
+// is active.
+static BOOLEAN HasSignedCounterpart(IN REFIT_VOLUME *Volume, IN CHAR16 *Path, IN CHAR16 *Filename) {
+    CHAR16 *NewFile = NULL;
+    BOOLEAN retval = FALSE;
+
+    MergeStrings(&NewFile, Path, 0);
+    MergeStrings(&NewFile, Filename, L'\\');
+    MergeStrings(&NewFile, L".efi.signed", 0);
+    if (NewFile != NULL) {
+        CleanUpPathNameSlashes(NewFile);
+        if (FileExists(Volume->RootDir, NewFile))
+            retval = TRUE;
+        MyFreePool(NewFile);
+    } // if
+
+    return retval;
+} // BOOLEAN HasSignedCounterpart()
+
+// Scan an individual directory for EFI boot loader files and, if found,
+// add them to the list. Exception: Ignores FALLBACK_FULLNAME, which is picked
+// up in ScanEfiFiles(). Sorts the entries within the loader directory so that
+// the most recent one appears first in the list.
+// Returns TRUE if a duplicate for FALLBACK_FILENAME was found, FALSE if not.
+static BOOLEAN ScanLoaderDir(IN REFIT_VOLUME *Volume, IN CHAR16 *Path, IN CHAR16 *Pattern)
+{
+    EFI_STATUS              Status;
+    REFIT_DIR_ITER          DirIter;
+    EFI_FILE_INFO           *DirEntry;
+    CHAR16                  FileName[256], *Extension;
+    struct LOADER_LIST      *LoaderList = NULL, *NewLoader;
+    LOADER_ENTRY            *FirstKernel = NULL, *LatestEntry = NULL;
+    BOOLEAN                 FoundFallbackDuplicate = FALSE, IsLinux = FALSE, InSelfPath;
+
+    InSelfPath = MyStriCmp(Path, SelfDirPath);
+    if ((!SelfDirPath || !Path || (InSelfPath && (Volume->DeviceHandle != SelfVolume->DeviceHandle)) ||
+           (!InSelfPath)) && (ShouldScan(Volume, Path))) {
+       // look through contents of the directory
+       DirIterOpen(Volume->RootDir, Path, &DirIter);
+       while (DirIterNext(&DirIter, 2, Pattern, &DirEntry)) {
+          Extension = FindExtension(DirEntry->FileName);
+          if (DirEntry->FileName[0] == '.' ||
+              MyStriCmp(Extension, L".icns") ||
+              MyStriCmp(Extension, L".png") ||
+              (MyStriCmp(DirEntry->FileName, FALLBACK_BASENAME) && (MyStriCmp(Path, L"EFI\\BOOT"))) ||
+              StriSubCmp(L"shell", DirEntry->FileName) ||
+              IsSymbolicLink(Volume, Path, DirEntry) || /* is symbolic link */
+              HasSignedCounterpart(Volume, Path, DirEntry->FileName) || /* a file with same name plus ".efi.signed" is present */
+              FilenameIn(Volume, Path, DirEntry->FileName, GlobalConfig.DontScanFiles))
+                continue;   // skip this
+
+          if (Path)
+             SPrint(FileName, 255, L"\\%s\\%s", Path, DirEntry->FileName);
+          else
+             SPrint(FileName, 255, L"\\%s", DirEntry->FileName);
+          CleanUpPathNameSlashes(FileName);
+
+          if(!IsValidLoader(Volume->RootDir, FileName))
+             continue;
+
+          NewLoader = AllocateZeroPool(sizeof(struct LOADER_LIST));
+          if (NewLoader != NULL) {
+             NewLoader->FileName = StrDuplicate(FileName);
+             NewLoader->TimeStamp = DirEntry->ModificationTime;
+             LoaderList = AddLoaderListEntry(LoaderList, NewLoader);
+             if (DuplicatesFallback(Volume, FileName))
+                FoundFallbackDuplicate = TRUE;
+          } // if
+          MyFreePool(Extension);
+       } // while
+
+       NewLoader = LoaderList;
+       while (NewLoader != NULL) {
+           IsLinux = (StriSubCmp(L"bzImage", NewLoader->FileName) ||
+                      StriSubCmp(L"vmlinuz", NewLoader->FileName) ||
+                      StriSubCmp(L"kernel", NewLoader->FileName));
+           if ((FirstKernel != NULL) && IsLinux && GlobalConfig.FoldLinuxKernels) {
+               AddKernelToSubmenu(FirstKernel, NewLoader->FileName, Volume);
+           } else {
+               LatestEntry = AddLoaderEntry(NewLoader->FileName, NULL, Volume, !(IsLinux && GlobalConfig.FoldLinuxKernels));
+               if (IsLinux && (FirstKernel == NULL))
+                   FirstKernel = LatestEntry;
+           }
+           NewLoader = NewLoader->NextEntry;
+       } // while
+       if ((NewLoader != NULL) && (FirstKernel != NULL) && IsLinux && GlobalConfig.FoldLinuxKernels)
+           AddMenuEntry(FirstKernel->me.SubScreen, &MenuEntryReturn);
+
+       CleanUpLoaderList(LoaderList);
+       Status = DirIterClose(&DirIter);
+       // NOTE: EFI_INVALID_PARAMETER really is an error that should be reported;
+       // but I've gotten reports from users who are getting this error occasionally
+       // and I can't find anything wrong or reproduce the problem, so I'm putting
+       // it down to buggy EFI implementations and ignoring that particular error....
+       if ((Status != EFI_NOT_FOUND) && (Status != EFI_INVALID_PARAMETER)) {
+          if (Path)
+             SPrint(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 a blacklisted directory
+
+    return FoundFallbackDuplicate;
+} /* static VOID ScanLoaderDir() */
+
+// Run the IPXE_DISCOVER_NAME program, which obtains the IP address of the boot
+// server and the name of the boot file it delivers.
+CHAR16* RuniPXEDiscover(EFI_HANDLE Volume)
+{
+    EFI_STATUS       Status;
+    EFI_DEVICE_PATH  *FilePath;
+    EFI_HANDLE       iPXEHandle;
+    CHAR16           *boot_info = NULL;
+    UINTN            boot_info_size = 0;
+
+    FilePath = FileDevicePath (Volume, IPXE_DISCOVER_NAME);
+    Status = refit_call6_wrapper(BS->LoadImage, FALSE, SelfImageHandle, FilePath, NULL, 0, &iPXEHandle);
+    if (Status != 0)
+        return NULL;
+
+    Status = refit_call3_wrapper(BS->StartImage, iPXEHandle, &boot_info_size, &boot_info);
+
+    return boot_info;
+} // RuniPXEDiscover()
+
+// Scan for network (PXE) boot servers. This function relies on the presence
+// of the IPXE_DISCOVER_NAME and IPXE_NAME program files on the volume from
+// which rEFInd launched. As of December 6, 2014, these tools aren't entirely
+// reliable. See BUILDING.txt for information on building them.
+static VOID ScanNetboot() {
+    CHAR16        *iPXEFileName = IPXE_NAME;
+    CHAR16        *Location;
+    REFIT_VOLUME  *NetVolume;
+
+    if (FileExists(SelfVolume->RootDir, IPXE_DISCOVER_NAME) &&
+        FileExists(SelfVolume->RootDir, IPXE_NAME) &&
+        IsValidLoader(SelfVolume->RootDir, IPXE_DISCOVER_NAME) &&
+        IsValidLoader(SelfVolume->RootDir, IPXE_NAME)) {
+            Location = RuniPXEDiscover(SelfVolume->DeviceHandle);
+            if (Location != NULL && FileExists(SelfVolume->RootDir, iPXEFileName)) {
+                NetVolume = AllocatePool(sizeof(REFIT_VOLUME));
+                CopyMem(NetVolume, SelfVolume, sizeof(REFIT_VOLUME));
+                NetVolume->DiskKind = DISK_KIND_NET;
+                NetVolume->VolBadgeImage = BuiltinIcon(BUILTIN_ICON_VOL_NET);
+                NetVolume->PartName = NetVolume->VolName = NULL;
+                AddLoaderEntry(iPXEFileName, Location, NetVolume, TRUE);
+                MyFreePool(NetVolume);
+            } // if support files exist and are valid
+    } 
+} // VOID ScanNetBoot()
+
+static VOID ScanEfiFiles(REFIT_VOLUME *Volume) {
+    EFI_STATUS              Status;
+    REFIT_DIR_ITER          EfiDirIter;
+    EFI_FILE_INFO           *EfiDirEntry;
+    CHAR16                  FileName[256], *Directory = NULL, *MatchPatterns, *VolName = NULL, *SelfPath;
+    UINTN                   i, Length;
+    BOOLEAN                 ScanFallbackLoader = TRUE;
+    BOOLEAN                 FoundBRBackup = FALSE;
+
+    if (Volume && (Volume->RootDir != NULL) && (Volume->VolName != NULL) && (Volume->IsReadable)) {
+        MatchPatterns = StrDuplicate(LOADER_MATCH_PATTERNS);
+        if (GlobalConfig.ScanAllLinux)
+            MergeStrings(&MatchPatterns, LINUX_MATCH_PATTERNS, L',');
+
+        // check for Mac OS X boot loader
+        if (ShouldScan(Volume, MACOSX_LOADER_DIR)) {
+            StrCpy(FileName, MACOSX_LOADER_PATH);
+            if (FileExists(Volume->RootDir, FileName) && !FilenameIn(Volume, MACOSX_LOADER_DIR, L"boot.efi", GlobalConfig.DontScanFiles)) {
+                AddLoaderEntry(FileName, L"Mac OS X", Volume, TRUE);
+                if (DuplicatesFallback(Volume, FileName))
+                    ScanFallbackLoader = FALSE;
+            }
+
+            // check for XOM
+            StrCpy(FileName, L"System\\Library\\CoreServices\\xom.efi");
+            if (FileExists(Volume->RootDir, FileName) && !FilenameIn(Volume, MACOSX_LOADER_DIR, L"xom.efi", GlobalConfig.DontScanFiles)) {
+                AddLoaderEntry(FileName, L"Windows XP (XoM)", Volume, TRUE);
+                if (DuplicatesFallback(Volume, FileName))
+                    ScanFallbackLoader = FALSE;
+            }
+        } // if should scan Mac directory
+
+        // check for Microsoft boot loader/menu
+        if (ShouldScan(Volume, L"EFI\\Microsoft\\Boot")) {
+            StrCpy(FileName, L"EFI\\Microsoft\\Boot\\bkpbootmgfw.efi");
+            if (FileExists(Volume->RootDir, FileName) &&  !FilenameIn(Volume, L"EFI\\Microsoft\\Boot", L"bkpbootmgfw.efi",
+                GlobalConfig.DontScanFiles)) {
+                    AddLoaderEntry(FileName, L"Microsoft EFI boot (Boot Repair backup)", Volume, TRUE);
+                    FoundBRBackup = TRUE;
+                    if (DuplicatesFallback(Volume, FileName))
+                        ScanFallbackLoader = FALSE;
+            }
+            StrCpy(FileName, L"EFI\\Microsoft\\Boot\\bootmgfw.efi");
+            if (FileExists(Volume->RootDir, FileName) &&
+                !FilenameIn(Volume, L"EFI\\Microsoft\\Boot", L"bootmgfw.efi", GlobalConfig.DontScanFiles)) {
+                    if (FoundBRBackup)
+                        AddLoaderEntry(FileName, L"Supposed Microsoft EFI boot (probably GRUB)", Volume, TRUE);
+                    else
+                        AddLoaderEntry(FileName, L"Microsoft EFI boot", Volume, TRUE);
+                    if (DuplicatesFallback(Volume, FileName))
+                        ScanFallbackLoader = FALSE;
+            }
+        } // if
+
+        // scan the root directory for EFI executables
+        if (ScanLoaderDir(Volume, L"\\", MatchPatterns))
+            ScanFallbackLoader = FALSE;
+
+        // scan subdirectories of the EFI directory (as per the standard)
+        DirIterOpen(Volume->RootDir, L"EFI", &EfiDirIter);
+        while (DirIterNext(&EfiDirIter, 1, NULL, &EfiDirEntry)) {
+            if (MyStriCmp(EfiDirEntry->FileName, L"tools") || EfiDirEntry->FileName[0] == '.')
+                continue;   // skip this, doesn't contain boot loaders or is scanned later
+            SPrint(FileName, 255, L"EFI\\%s", EfiDirEntry->FileName);
+            if (ScanLoaderDir(Volume, FileName, MatchPatterns))
+                ScanFallbackLoader = FALSE;
+        } // while()
+        Status = DirIterClose(&EfiDirIter);
+        if ((Status != EFI_NOT_FOUND) && (Status != EFI_INVALID_PARAMETER))
+            CheckError(Status, L"while scanning the EFI directory");
+
+        // Scan user-specified (or additional default) directories....
+        i = 0;
+        while ((Directory = FindCommaDelimited(GlobalConfig.AlsoScan, i++)) != NULL) {
+            if (ShouldScan(Volume, Directory)) {
+                SplitVolumeAndFilename(&Directory, &VolName);
+                CleanUpPathNameSlashes(Directory);
+                Length = StrLen(Directory);
+                if ((Length > 0) && ScanLoaderDir(Volume, Directory, MatchPatterns))
+                    ScanFallbackLoader = FALSE;
+                MyFreePool(VolName);
+            } // if should scan dir
+            MyFreePool(Directory);
+        } // while
+
+        // Don't scan the fallback loader if it's on the same volume and a duplicate of rEFInd itself....
+        SelfPath = DevicePathToStr(SelfLoadedImage->FilePath);
+        CleanUpPathNameSlashes(SelfPath);
+        if ((Volume->DeviceHandle == SelfLoadedImage->DeviceHandle) && DuplicatesFallback(Volume, SelfPath))
+            ScanFallbackLoader = FALSE;
+
+        // If not a duplicate & if it exists & if it's not us, create an entry
+        // for the fallback boot loader
+        if (ScanFallbackLoader && FileExists(Volume->RootDir, FALLBACK_FULLNAME) && ShouldScan(Volume, L"EFI\\BOOT")) {
+            AddLoaderEntry(FALLBACK_FULLNAME, L"Fallback boot loader", Volume, TRUE);
+        }
+    } // if
+} // static VOID ScanEfiFiles()
+
+// Scan internal disks for valid EFI boot loaders....
+static VOID ScanInternal(VOID) {
+    UINTN                   VolumeIndex;
+
+    for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) {
+        if (Volumes[VolumeIndex]->DiskKind == DISK_KIND_INTERNAL) {
+            ScanEfiFiles(Volumes[VolumeIndex]);
+        }
+    } // for
+} // static VOID ScanInternal()
+
+// Scan external disks for valid EFI boot loaders....
+static VOID ScanExternal(VOID) {
+    UINTN                   VolumeIndex;
+
+    for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) {
+        if (Volumes[VolumeIndex]->DiskKind == DISK_KIND_EXTERNAL) {
+            ScanEfiFiles(Volumes[VolumeIndex]);
+        }
+    } // for
+} // static VOID ScanExternal()
+
+// Scan internal disks for valid EFI boot loaders....
+static VOID ScanOptical(VOID) {
+    UINTN                   VolumeIndex;
+
+    for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) {
+        if (Volumes[VolumeIndex]->DiskKind == DISK_KIND_OPTICAL) {
+            ScanEfiFiles(Volumes[VolumeIndex]);
+        }
+    } // for
+} // static VOID ScanOptical()
+
+// default volume badge icon based on disk kind
+EG_IMAGE * GetDiskBadge(IN UINTN DiskType) {
+    EG_IMAGE * Badge = NULL;
+
+    switch (DiskType) {
+        case BBS_HARDDISK:
+            Badge = BuiltinIcon(BUILTIN_ICON_VOL_INTERNAL);
+            break;
+        case BBS_USB:
+            Badge = BuiltinIcon(BUILTIN_ICON_VOL_EXTERNAL);
+            break;
+        case BBS_CDROM:
+            Badge = BuiltinIcon(BUILTIN_ICON_VOL_OPTICAL);
+            break;
+    } // switch()
+    return Badge;
+} // EG_IMAGE * GetDiskBadge()
+
+//
+// pre-boot tool functions
+//
+
+static VOID StartTool(IN LOADER_ENTRY *Entry)
+{
+    BeginExternalScreen(Entry->UseGraphicsMode, Entry->me.Title + 6);  // assumes "Start <title>" as assigned below
+    StoreLoaderName(Entry->me.Title);
+    StartEFIImage(Entry->DevicePath, Entry->LoadOptions, TYPE_EFI,
+                  Basename(Entry->LoaderPath), Entry->OSType, NULL, TRUE, FALSE);
+    FinishExternalScreen();
+} /* static VOID StartTool() */
+
+static LOADER_ENTRY * AddToolEntry(EFI_HANDLE DeviceHandle, IN CHAR16 *LoaderPath, IN CHAR16 *LoaderTitle, IN EG_IMAGE *Image,
+                                   IN CHAR16 ShortcutLetter, IN BOOLEAN UseGraphicsMode)
+{
+    LOADER_ENTRY *Entry;
+    CHAR16       *TitleStr = NULL;
+
+    Entry = AllocateZeroPool(sizeof(LOADER_ENTRY));
+
+    TitleStr = PoolPrint(L"Start %s", LoaderTitle);
+    Entry->me.Title = TitleStr;
+    Entry->me.Tag = TAG_TOOL;
+    Entry->me.Row = 1;
+    Entry->me.ShortcutLetter = ShortcutLetter;
+    Entry->me.Image = Image;
+    Entry->LoaderPath = (LoaderPath) ? StrDuplicate(LoaderPath) : NULL;
+    Entry->DevicePath = FileDevicePath(DeviceHandle, Entry->LoaderPath);
+    Entry->UseGraphicsMode = UseGraphicsMode;
+
+    AddMenuEntry(&MainMenu, (REFIT_MENU_ENTRY *)Entry);
+    return Entry;
+} /* static LOADER_ENTRY * AddToolEntry() */
+
+//
+// pre-boot driver functions
+//
+
+static UINTN ScanDriverDir(IN CHAR16 *Path)
+{
+    EFI_STATUS              Status;
+    REFIT_DIR_ITER          DirIter;
+    UINTN                   NumFound = 0;
+    EFI_FILE_INFO           *DirEntry;
+    CHAR16                  FileName[256];
+
+    CleanUpPathNameSlashes(Path);
+    // look through contents of the directory
+    DirIterOpen(SelfRootDir, Path, &DirIter);
+    while (DirIterNext(&DirIter, 2, LOADER_MATCH_PATTERNS, &DirEntry)) {
+        if (DirEntry->FileName[0] == '.')
+            continue;   // skip this
+
+        SPrint(FileName, 255, L"%s\\%s", Path, DirEntry->FileName);
+        NumFound++;
+        Status = StartEFIImage(FileDevicePath(SelfLoadedImage->DeviceHandle, FileName),
+                               L"", TYPE_EFI, DirEntry->FileName, 0, NULL, FALSE, TRUE);
+    }
+    Status = DirIterClose(&DirIter);
+    if ((Status != EFI_NOT_FOUND) && (Status != EFI_INVALID_PARAMETER)) {
+        SPrint(FileName, 255, L"while scanning the %s directory", Path);
+        CheckError(Status, FileName);
+    }
+    return (NumFound);
+}
+
+#ifdef __MAKEWITH_GNUEFI
+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;
+            } // for
+
+            if (!Parent) {
+                if (HandleType[Index] & EFI_HANDLE_TYPE_DEVICE_HANDLE) {
+                   Status = refit_call4_wrapper(BS->ConnectController,
+                                                AllHandleBuffer[Index],
+                                                NULL,
+                                                NULL,
+                                                TRUE);
+                }
+            }
+        }
+
+        MyFreePool (HandleBuffer);
+        MyFreePool (HandleType);
+    }
+
+Done:
+    MyFreePool (AllHandleBuffer);
+    return Status;
+} /* EFI_STATUS ConnectAllDriversToAllControllers() */
+#else
+static EFI_STATUS ConnectAllDriversToAllControllers(VOID) {
+    BdsLibConnectAllDriversToAllControllers();
+    return 0;
+}
+#endif
+
+// Load all EFI drivers from rEFInd's "drivers" subdirectory and from the
+// directories specified by the user in the "scan_driver_dirs" configuration
+// file line.
+static VOID LoadDrivers(VOID)
+{
+    CHAR16        *Directory, *SelfDirectory;
+    UINTN         i = 0, Length, NumFound = 0;
+
+    // load drivers from the subdirectories of rEFInd's home directory specified
+    // in the DRIVER_DIRS constant.
+    while ((Directory = FindCommaDelimited(DRIVER_DIRS, i++)) != NULL) {
+       SelfDirectory = SelfDirPath ? StrDuplicate(SelfDirPath) : NULL;
+       CleanUpPathNameSlashes(SelfDirectory);
+       MergeStrings(&SelfDirectory, Directory, L'\\');
+       NumFound += ScanDriverDir(SelfDirectory);
+       MyFreePool(Directory);
+       MyFreePool(SelfDirectory);
+    }
+
+    // Scan additional user-specified driver directories....
+    i = 0;
+    while ((Directory = FindCommaDelimited(GlobalConfig.DriverDirs, i++)) != NULL) {
+       CleanUpPathNameSlashes(Directory);
+       Length = StrLen(Directory);
+       if (Length > 0) {
+          NumFound += ScanDriverDir(Directory);
+       } // if
+       MyFreePool(Directory);
+    } // while
+
+    // connect all devices
+    if (NumFound > 0) {
+       ConnectAllDriversToAllControllers();
+    }
+} /* static VOID LoadDrivers() */
+
+// Locates boot loaders. NOTE: This assumes that GlobalConfig.LegacyType is set correctly.
+static VOID ScanForBootloaders(VOID) {
+    UINTN    i;
+    CHAR8    s;
+    BOOLEAN  ScanForLegacy = FALSE;
+
+    // Determine up-front if we'll be scanning for legacy loaders....
+    for (i = 0; i < NUM_SCAN_OPTIONS; i++) {
+        s = GlobalConfig.ScanFor[i];
+        if ((s == 'c') || (s == 'C') || (s == 'h') || (s == 'H') || (s == 'b') || (s == 'B'))
+            ScanForLegacy = TRUE;
+    } // for
+
+    // If UEFI & scanning for legacy loaders & deep legacy scan, update NVRAM boot manager list
+    if ((GlobalConfig.LegacyType == LEGACY_TYPE_UEFI) && ScanForLegacy && GlobalConfig.DeepLegacyScan) {
+        BdsDeleteAllInvalidLegacyBootOptions();
+        BdsAddNonExistingLegacyBootOptions();
+    } // if
+
+    // scan for loaders and tools, add them to the menu
+    for (i = 0; i < NUM_SCAN_OPTIONS; i++) {
+        switch(GlobalConfig.ScanFor[i]) {
+            case 'c': case 'C':
+                ScanLegacyDisc();
+                break;
+            case 'h': case 'H':
+                ScanLegacyInternal();
+                break;
+            case 'b': case 'B':
+                ScanLegacyExternal();
+                break;
+            case 'm': case 'M':
+                ScanUserConfigured(GlobalConfig.ConfigFilename);
+                break;
+            case 'e': case 'E':
+                ScanExternal();
+                break;
+            case 'i': case 'I':
+                ScanInternal();
+                break;
+            case 'o': case 'O':
+                ScanOptical();
+                break;
+            case 'n': case 'N':
+                ScanNetboot();
+                break;
+        } // switch()
+    } // for
+
+    // assign shortcut keys
+    for (i = 0; i < MainMenu.EntryCount && MainMenu.Entries[i]->Row == 0 && i < 9; i++)
+        MainMenu.Entries[i]->ShortcutDigit = (CHAR16)('1' + i);
+
+    // wait for user ACK when there were errors
+    FinishTextScreen(FALSE);
+} // static VOID ScanForBootloaders()
+
+// Locate a single tool from the specified Locations using one of the
+// specified Names and add it to the menu.
+static VOID FindTool(CHAR16 *Locations, CHAR16 *Names, CHAR16 *Description, UINTN Icon) {
+    UINTN j = 0, k, VolumeIndex;
+    CHAR16 *DirName, *FileName, *PathName, FullDescription[256];
+
+    while ((DirName = FindCommaDelimited(Locations, j++)) != NULL) {
+        k = 0;
+        while ((FileName = FindCommaDelimited(Names, k++)) != NULL) {
+            PathName = StrDuplicate(DirName);
+            MergeStrings(&PathName, FileName, MyStriCmp(PathName, L"\\") ? 0 : L'\\');
+            for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) {
+                if ((Volumes[VolumeIndex]->RootDir != NULL) &&
+                    (FileExists(Volumes[VolumeIndex]->RootDir, PathName)) &&
+                    IsValidLoader(Volumes[VolumeIndex]->RootDir, PathName)) {
+                        SPrint(FullDescription, 255, L"%s at %s on %s", Description, PathName, Volumes[VolumeIndex]->VolName);
+                        AddToolEntry(Volumes[VolumeIndex]->DeviceHandle, PathName, FullDescription, BuiltinIcon(Icon), 'S', FALSE);
+                } // if
+            } // for
+            MyFreePool(PathName);
+            MyFreePool(FileName);
+        } // while Names
+        MyFreePool(DirName);
+    } // while Locations
+} // VOID FindTool()
+
+// Add the second-row tags containing built-in and external tools (EFI shell,
+// reboot, etc.)
+static VOID ScanForTools(VOID) {
+    CHAR16 *FileName = NULL, *VolName = NULL, *MokLocations, Description[256];
+    REFIT_MENU_ENTRY *TempMenuEntry;
+    UINTN i, j, VolumeIndex;
+    UINT64 osind;
+    CHAR8 *b = 0;
+    UINT32 CsrValue;
+
+    MokLocations = StrDuplicate(MOK_LOCATIONS);
+    if (MokLocations != NULL)
+        MergeStrings(&MokLocations, SelfDirPath, L',');
+
+    for (i = 0; i < NUM_TOOLS; i++) {
+        switch(GlobalConfig.ShowTools[i]) {
+            // NOTE: Be sure that FileName is NULL at the end of each case.
+            case TAG_SHUTDOWN:
+                TempMenuEntry = CopyMenuEntry(&MenuEntryShutdown);
+                TempMenuEntry->Image = BuiltinIcon(BUILTIN_ICON_FUNC_SHUTDOWN);
+                AddMenuEntry(&MainMenu, TempMenuEntry);
+                break;
+
+            case TAG_REBOOT:
+                TempMenuEntry = CopyMenuEntry(&MenuEntryReset);
+                TempMenuEntry->Image = BuiltinIcon(BUILTIN_ICON_FUNC_RESET);
+                AddMenuEntry(&MainMenu, TempMenuEntry);
+                break;
+
+            case TAG_ABOUT:
+                TempMenuEntry = CopyMenuEntry(&MenuEntryAbout);
+                TempMenuEntry->Image = BuiltinIcon(BUILTIN_ICON_FUNC_ABOUT);
+                AddMenuEntry(&MainMenu, TempMenuEntry);
+                break;
+
+            case TAG_EXIT:
+                TempMenuEntry = CopyMenuEntry(&MenuEntryExit);
+                TempMenuEntry->Image = BuiltinIcon(BUILTIN_ICON_FUNC_EXIT);
+                AddMenuEntry(&MainMenu, TempMenuEntry);
+                break;
+
+            case TAG_FIRMWARE:
+                if (EfivarGetRaw(&GlobalGuid, L"OsIndicationsSupported", &b, &j) == EFI_SUCCESS) {
+                    osind = (UINT64)*b;
+                    if (osind & EFI_OS_INDICATIONS_BOOT_TO_FW_UI) {
+                        TempMenuEntry = CopyMenuEntry(&MenuEntryFirmware);
+                        TempMenuEntry->Image = BuiltinIcon(BUILTIN_ICON_FUNC_FIRMWARE);
+                        AddMenuEntry(&MainMenu, TempMenuEntry);
+                    } // if
+                } // if
+                break;
+
+            case TAG_SHELL:
+                j = 0;
+                while ((FileName = FindCommaDelimited(SHELL_NAMES, j++)) != NULL) {
+                    if (FileExists(SelfRootDir, FileName) && IsValidLoader(SelfRootDir, FileName)) {
+                        AddToolEntry(SelfLoadedImage->DeviceHandle, FileName, L"EFI Shell", BuiltinIcon(BUILTIN_ICON_TOOL_SHELL),
+                                     'S', FALSE);
+                    }
+                MyFreePool(FileName);
+                } // while
+                break;
+
+            case TAG_GPTSYNC:
+                j = 0;
+                while ((FileName = FindCommaDelimited(GPTSYNC_NAMES, j++)) != NULL) {
+                    if (FileExists(SelfRootDir, FileName) && IsValidLoader(SelfRootDir, FileName)) {
+                        AddToolEntry(SelfLoadedImage->DeviceHandle, FileName, L"Hybrid MBR tool", BuiltinIcon(BUILTIN_ICON_TOOL_PART),
+                                     'P', FALSE);
+                    } // if
+                    MyFreePool(FileName);
+                } // while
+                FileName = NULL;
+                break;
+
+            case TAG_GDISK:
+                j = 0;
+                while ((FileName = FindCommaDelimited(GDISK_NAMES, j++)) != NULL) {
+                    if (FileExists(SelfRootDir, FileName) && IsValidLoader(SelfRootDir, FileName)) {
+                        AddToolEntry(SelfLoadedImage->DeviceHandle, FileName, L"disk partitioning tool",
+                                     BuiltinIcon(BUILTIN_ICON_TOOL_PART), 'G', FALSE);
+                    } // if
+                    MyFreePool(FileName);
+                } // while
+                FileName = NULL;
+                break;
+            
+            case TAG_NETBOOT:
+                j = 0;
+                while ((FileName = FindCommaDelimited(NETBOOT_NAMES, j++)) != NULL) {
+                    if (FileExists(SelfRootDir, FileName) && IsValidLoader(SelfRootDir, FileName)) {
+                        AddToolEntry(SelfLoadedImage->DeviceHandle, FileName, L"Netboot",
+                                     BuiltinIcon(BUILTIN_ICON_TOOL_NETBOOT), 'N', FALSE);
+                    } // if
+                    MyFreePool(FileName);
+                } // while
+                FileName = NULL;
+                break;
+
+            case TAG_APPLE_RECOVERY:
+                FileName = StrDuplicate(L"\\com.apple.recovery.boot\\boot.efi");
+                for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) {
+                    if ((Volumes[VolumeIndex]->RootDir != NULL) &&
+                        (FileExists(Volumes[VolumeIndex]->RootDir, FileName)) &&
+                        IsValidLoader(Volumes[VolumeIndex]->RootDir, FileName)) {
+                            SPrint(Description, 255, L"Apple Recovery on %s", Volumes[VolumeIndex]->VolName);
+                            AddToolEntry(Volumes[VolumeIndex]->DeviceHandle, FileName, Description,
+                                         BuiltinIcon(BUILTIN_ICON_TOOL_APPLE_RESCUE), 'R', TRUE);
+                    } // if
+                } // for
+                MyFreePool(FileName);
+                FileName = NULL;
+                break;
+
+            case TAG_WINDOWS_RECOVERY:
+                j = 0;
+                while ((FileName = FindCommaDelimited(GlobalConfig.WindowsRecoveryFiles, j++)) != NULL) {
+                    SplitVolumeAndFilename(&FileName, &VolName);
+                    for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) {
+                        if ((Volumes[VolumeIndex]->RootDir != NULL) &&
+                            (FileExists(Volumes[VolumeIndex]->RootDir, FileName)) &&
+                            IsValidLoader(Volumes[VolumeIndex]->RootDir, FileName) &&
+                            ((VolName == NULL) || MyStriCmp(VolName, Volumes[VolumeIndex]->VolName))) {
+                                SPrint(Description, 255, L"Microsoft Recovery on %s", Volumes[VolumeIndex]->VolName);
+                                AddToolEntry(Volumes[VolumeIndex]->DeviceHandle, FileName, Description,
+                                             BuiltinIcon(BUILTIN_ICON_TOOL_WINDOWS_RESCUE), 'R', TRUE);
+                        } // if
+                    } // for
+                } // while
+                MyFreePool(FileName);
+                FileName = NULL;
+                MyFreePool(VolName);
+                VolName = NULL;
+                break;
+
+            case TAG_MOK_TOOL:
+                FindTool(MokLocations, MOK_NAMES, L"MOK utility", BUILTIN_ICON_TOOL_MOK_TOOL);
+                break;
+
+            case TAG_CSR_ROTATE:
+                if ((GetCsrStatus(&CsrValue) == EFI_SUCCESS) && (GlobalConfig.CsrValues)) {
+                    TempMenuEntry = CopyMenuEntry(&MenuEntryRotateCsr);
+                    TempMenuEntry->Image = BuiltinIcon(BUILTIN_ICON_FUNC_CSR_ROTATE);
+                    AddMenuEntry(&MainMenu, TempMenuEntry);
+                } // if
+                break;
+
+            case TAG_MEMTEST:
+                FindTool(MEMTEST_LOCATIONS, MEMTEST_NAMES, L"Memory test utility", BUILTIN_ICON_TOOL_MEMTEST);
+                break;
+
+        } // switch()
+    } // for
+} // static VOID ScanForTools
+
+// Rescan for boot loaders
+static VOID RescanAll(BOOLEAN DisplayMessage) {
+    EG_PIXEL           BGColor;
+
+    BGColor.b = 255;
+    BGColor.g = 175;
+    BGColor.r = 100;
+    BGColor.a = 0;
+    if (DisplayMessage)
+        egDisplayMessage(L"Scanning for new boot loaders; please wait....", &BGColor);
+    FreeList((VOID ***) &(MainMenu.Entries), &MainMenu.EntryCount);
+    MainMenu.Entries = NULL;
+    MainMenu.EntryCount = 0;
+    ConnectAllDriversToAllControllers();
+    ScanVolumes();
+    ReadConfig(GlobalConfig.ConfigFilename);
+    ScanForBootloaders();
+    ScanForTools();
+    SetupScreen();
+} // VOID RescanAll()
+
+#ifdef __MAKEWITH_TIANO
+
+// Minimal initialization function
+static VOID InitializeLib(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable) {
+    gST            = SystemTable;
+    //    gImageHandle   = ImageHandle;
+    gBS            = SystemTable->BootServices;
+    //    gRS            = SystemTable->RuntimeServices;
+    gRT = SystemTable->RuntimeServices; // Some BDS functions need gRT to be set
+    EfiGetSystemConfigurationTable (&gEfiDxeServicesTableGuid, (VOID **) &gDS);
+}
+
+#endif
+
+// Set up our own Secure Boot extensions....
+// Returns TRUE on success, FALSE otherwise
+static BOOLEAN SecureBootSetup(VOID) {
+    EFI_STATUS Status;
+    BOOLEAN    Success = FALSE;
+
+    if (secure_mode() && ShimLoaded()) {
+        Status = security_policy_install();
+        if (Status == EFI_SUCCESS) {
+            Success = TRUE;
+        } else {
+            Print(L"Failed to install MOK Secure Boot extensions");
+            PauseForKey();
+        }
+    }
+    return Success;
+} // VOID SecureBootSetup()
+
+// Remove our own Secure Boot extensions....
+// Returns TRUE on success, FALSE otherwise
+static BOOLEAN SecureBootUninstall(VOID) {
+    EFI_STATUS Status;
+    BOOLEAN    Success = TRUE;
+
+    if (secure_mode()) {
+        Status = security_policy_uninstall();
+        if (Status != EFI_SUCCESS) {
+            Success = FALSE;
+            BeginTextScreen(L"Secure Boot Policy Failure");
+            Print(L"Failed to uninstall MOK Secure Boot extensions; forcing a reboot.");
+            PauseForKey();
+            refit_call4_wrapper(RT->ResetSystem, EfiResetCold, EFI_SUCCESS, 0, NULL);
+        }
+    }
+    return Success;
+} // VOID SecureBootUninstall
+
+// Sets the global configuration filename; will be CONFIG_FILE_NAME unless the
+// "-c" command-line option is set, in which case that takes precedence.
+// If an error is encountered, leaves the value alone (it should be set to
+// CONFIG_FILE_NAME when GlobalConfig is initialized).
+static VOID SetConfigFilename(EFI_HANDLE ImageHandle) {
+    EFI_LOADED_IMAGE *Info;
+    CHAR16 *Options, *FileName, *SubString;
+    EFI_STATUS Status;
+
+    Status = refit_call3_wrapper(BS->HandleProtocol, ImageHandle, &LoadedImageProtocol, (VOID **) &Info);
+    if ((Status == EFI_SUCCESS) && (Info->LoadOptionsSize > 0)) {
+        Options = (CHAR16 *) Info->LoadOptions;
+        SubString = MyStrStr(Options, L" -c ");
+        if (SubString) {
+            FileName = StrDuplicate(&SubString[4]);
+            if (FileName) {
+                LimitStringLength(FileName, 256);
+            }
+
+            if (FileExists(SelfDir, FileName)) {
+                GlobalConfig.ConfigFilename = FileName;
+            } else {
+                Print(L"Specified configuration file (%s) doesn't exist; using\n'refind.conf' default\n", FileName);
+                MyFreePool(FileName);
+            } // if/else
+        } // if
+    } // if
+} // VOID SetConfigFilename()
+
+//
+// main entry point
+//
+EFI_STATUS
+EFIAPI
+efi_main (EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
+{
+    EFI_STATUS         Status;
+    BOOLEAN            MainLoopRunning = TRUE;
+    BOOLEAN            MokProtocol;
+    REFIT_MENU_ENTRY   *ChosenEntry;
+    UINTN              MenuExit, i;
+    CHAR16             *SelectionName = NULL;
+    EG_PIXEL           BGColor;
+
+    // bootstrap
+    InitializeLib(ImageHandle, SystemTable);
+    Status = InitRefitLib(ImageHandle);
+    if (EFI_ERROR(Status))
+        return Status;
+
+    // read configuration
+    CopyMem(GlobalConfig.ScanFor, "ieom      ", NUM_SCAN_OPTIONS);
+    FindLegacyBootType();
+    if (GlobalConfig.LegacyType == LEGACY_TYPE_MAC)
+       CopyMem(GlobalConfig.ScanFor, "ihebocm   ", NUM_SCAN_OPTIONS);
+    SetConfigFilename(ImageHandle);
+    MokProtocol = SecureBootSetup();
+    LoadDrivers();
+    ScanVolumes(); // Do before ReadConfig() because it needs SelfVolume->VolName
+    ReadConfig(GlobalConfig.ConfigFilename);
+
+    if (GlobalConfig.SpoofOSXVersion && GlobalConfig.SpoofOSXVersion[0] != L'\0')
+        SetAppleOSInfo();
+
+    InitScreen();
+    WarnIfLegacyProblems();
+    MainMenu.TimeoutSeconds = GlobalConfig.Timeout;
+
+    // disable EFI watchdog timer
+    refit_call4_wrapper(BS->SetWatchdogTimer, 0x0000, 0x0000, 0x0000, NULL);
+
+    // further bootstrap (now with config available)
+    ScanForBootloaders();
+    ScanForTools();
+    SetupScreen();
+
+    if (GlobalConfig.ScanDelay > 0) {
+       BGColor.b = 255;
+       BGColor.g = 175;
+       BGColor.r = 100;
+       BGColor.a = 0;
+       if (GlobalConfig.ScanDelay > 1)
+          egDisplayMessage(L"Pausing before disk scan; please wait....", &BGColor);
+       for (i = 0; i < GlobalConfig.ScanDelay; i++)
+          refit_call1_wrapper(BS->Stall, 1000000);
+       RescanAll(GlobalConfig.ScanDelay > 1);
+    } // if
+
+    if (GlobalConfig.DefaultSelection)
+       SelectionName = StrDuplicate(GlobalConfig.DefaultSelection);
+
+    while (MainLoopRunning) {
+        MenuExit = RunMainMenu(&MainMenu, &SelectionName, &ChosenEntry);
+
+        // The Escape key triggers a re-scan operation....
+        if (MenuExit == MENU_EXIT_ESCAPE) {
+            MenuExit = 0;
+            RescanAll(TRUE);
+            continue;
+        }
+
+        switch (ChosenEntry->Tag) {
+
+            case TAG_REBOOT:    // Reboot
+                TerminateScreen();
+                refit_call4_wrapper(RT->ResetSystem, EfiResetCold, EFI_SUCCESS, 0, NULL);
+                MainLoopRunning = FALSE;   // just in case we get this far
+                break;
+
+            case TAG_SHUTDOWN: // Shut Down
+                TerminateScreen();
+                refit_call4_wrapper(RT->ResetSystem, EfiResetShutdown, EFI_SUCCESS, 0, NULL);
+                MainLoopRunning = FALSE;   // just in case we get this far
+                break;
+
+            case TAG_ABOUT:    // About rEFInd
+                AboutrEFInd();
+                break;
+
+            case TAG_LOADER:   // Boot OS via .EFI loader
+                StartLoader((LOADER_ENTRY *)ChosenEntry, SelectionName);
+                break;
+
+            case TAG_LEGACY:   // Boot legacy OS
+                StartLegacy((LEGACY_ENTRY *)ChosenEntry, SelectionName);
+                break;
+
+            case TAG_LEGACY_UEFI: // Boot a legacy OS on a non-Mac
+                StartLegacyUEFI((LEGACY_ENTRY *)ChosenEntry, SelectionName);
+                break;
+
+            case TAG_TOOL:     // Start a EFI tool
+                StartTool((LOADER_ENTRY *)ChosenEntry);
+                break;
+
+            case TAG_EXIT:    // Terminate rEFInd
+                if ((MokProtocol) && !SecureBootUninstall()) {
+                   MainLoopRunning = FALSE;   // just in case we get this far
+                } else {
+                   BeginTextScreen(L" ");
+                   return EFI_SUCCESS;
+                }
+                break;
+
+            case TAG_FIRMWARE: // Reboot into firmware's user interface
+                RebootIntoFirmware();
+                break;
+
+            case TAG_CSR_ROTATE:
+                RotateCsrValue();
+                break;
+
+        } // switch()
+    } // while()
+
+    // If we end up here, things have gone wrong. Try to reboot, and if that
+    // fails, go into an endless loop.
+    refit_call4_wrapper(RT->ResetSystem, EfiResetCold, EFI_SUCCESS, 0, NULL);
+    EndlessIdleLoop();
+
+    return EFI_SUCCESS;
+} /* efi_main() */
diff --git a/refind/menu.c b/refind/menu.c
new file mode 100644 (file)
index 0000000..35a8f26
--- /dev/null
@@ -0,0 +1,1278 @@
+/*
+ * 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-2015 Roderick W. Smith
+ *
+ * Modifications distributed under the terms of the GNU General Public
+ * License (GPL) version 3 (GPLv3), or (at your option) any later version.
+ *
+ */
+/*
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "global.h"
+#include "screen.h"
+#include "lib.h"
+#include "menu.h"
+#include "config.h"
+#include "libeg.h"
+#include "libegint.h"
+#include "line_edit.h"
+#include "mystrings.h"
+#include "../include/refit_call_wrapper.h"
+
+#include "../include/egemb_back_selected_small.h"
+#include "../include/egemb_back_selected_big.h"
+#include "../include/egemb_arrow_left.h"
+#include "../include/egemb_arrow_right.h"
+
+// other menu definitions
+
+#define MENU_FUNCTION_INIT            (0)
+#define MENU_FUNCTION_CLEANUP         (1)
+#define MENU_FUNCTION_PAINT_ALL       (2)
+#define MENU_FUNCTION_PAINT_SELECTION (3)
+#define MENU_FUNCTION_PAINT_TIMEOUT   (4)
+#define MENU_FUNCTION_PAINT_HINTS     (5)
+
+typedef VOID (*MENU_STYLE_FUNC)(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, IN UINTN Function, IN CHAR16 *ParamText);
+
+static CHAR16 ArrowUp[2] = { ARROW_UP, 0 };
+static CHAR16 ArrowDown[2] = { ARROW_DOWN, 0 };
+static UINTN TileSizes[2] = { 144, 64 };
+
+// Text and icon spacing constants....
+#define TEXT_YMARGIN (2)
+#define TITLEICON_SPACING (16)
+
+#define TILE_XSPACING (8)
+#define TILE_YSPACING (16)
+
+// Alignment values for PaintIcon()
+#define ALIGN_RIGHT 1
+#define ALIGN_LEFT 0
+
+static EG_IMAGE *SelectionImages[2] = { NULL, NULL };
+static EG_PIXEL SelectionBackgroundPixel = { 0xff, 0xff, 0xff, 0 };
+
+//
+// Graphics helper functions
+//
+
+static VOID InitSelection(VOID)
+{
+    EG_IMAGE    *TempSmallImage = NULL, *TempBigImage = NULL;
+    BOOLEAN     LoadedSmallImage = FALSE;
+
+    if (!AllowGraphicsMode)
+        return;
+    if (SelectionImages[0] != NULL)
+        return;
+
+    // load small selection image
+    if (GlobalConfig.SelectionSmallFileName != NULL) {
+        TempSmallImage = egLoadImage(SelfDir, GlobalConfig.SelectionSmallFileName, TRUE);
+    }
+    if (TempSmallImage == NULL)
+        TempSmallImage = egPrepareEmbeddedImage(&egemb_back_selected_small, TRUE);
+    else
+       LoadedSmallImage = TRUE;
+    SelectionImages[1] = egScaleImage(TempSmallImage, TileSizes[1], TileSizes[1]);
+
+    // load big selection image
+    if (GlobalConfig.SelectionBigFileName != NULL) {
+        TempBigImage = egLoadImage(SelfDir, GlobalConfig.SelectionBigFileName, TRUE);
+    }
+    if (TempBigImage == NULL) {
+        if (LoadedSmallImage) {
+           // calculate big selection image from small one
+           TempBigImage = egCopyImage(TempSmallImage);
+        } else {
+           TempBigImage = egPrepareEmbeddedImage(&egemb_back_selected_big, TRUE);
+        }
+    }
+    SelectionImages[0] = egScaleImage(TempBigImage, TileSizes[0], TileSizes[0]);
+
+    if (TempSmallImage)
+       egFreeImage(TempSmallImage);
+    if (TempBigImage)
+       egFreeImage(TempBigImage);
+} // VOID InitSelection()
+
+//
+// Scrolling functions
+//
+
+static VOID InitScroll(OUT SCROLL_STATE *State, IN UINTN ItemCount, IN UINTN VisibleSpace)
+{
+    State->PreviousSelection = State->CurrentSelection = 0;
+    State->MaxIndex = (INTN)ItemCount - 1;
+    State->FirstVisible = 0;
+    if (AllowGraphicsMode) {
+       State->MaxVisible = UGAWidth / (TileSizes[0] + TILE_XSPACING) - 1;
+    } else
+       State->MaxVisible = ConHeight - 4;
+    if ((VisibleSpace > 0) && (VisibleSpace < State->MaxVisible))
+        State->MaxVisible = (INTN)VisibleSpace;
+    State->PaintAll = TRUE;
+    State->PaintSelection = FALSE;
+
+    State->LastVisible = State->FirstVisible + State->MaxVisible - 1;
+}
+
+// Adjust variables relating to the scrolling of tags, for when a selected icon isn't
+// visible given the current scrolling condition....
+static VOID AdjustScrollState(IN SCROLL_STATE *State) {
+   if (State->CurrentSelection > State->LastVisible) {
+      State->LastVisible = State->CurrentSelection;
+      State->FirstVisible = 1 + State->CurrentSelection - State->MaxVisible;
+      if (State->FirstVisible < 0) // shouldn't happen, but just in case....
+         State->FirstVisible = 0;
+      State->PaintAll = TRUE;
+   } // Scroll forward
+   if (State->CurrentSelection < State->FirstVisible) {
+      State->FirstVisible = State->CurrentSelection;
+      State->LastVisible = State->CurrentSelection + State->MaxVisible - 1;
+      State->PaintAll = TRUE;
+   } // Scroll backward
+} // static VOID AdjustScrollState
+
+static VOID UpdateScroll(IN OUT SCROLL_STATE *State, IN UINTN Movement)
+{
+    State->PreviousSelection = State->CurrentSelection;
+
+    switch (Movement) {
+        case SCROLL_LINE_LEFT:
+            if (State->CurrentSelection > 0) {
+                State->CurrentSelection --;
+            }
+            break;
+
+        case SCROLL_LINE_RIGHT:
+            if (State->CurrentSelection < State->MaxIndex) {
+                State->CurrentSelection ++;
+            }
+            break;
+
+        case SCROLL_LINE_UP:
+            if (State->ScrollMode == SCROLL_MODE_ICONS) {
+               if (State->CurrentSelection >= State->InitialRow1) {
+                  if (State->MaxIndex > State->InitialRow1) { // avoid division by 0!
+                     State->CurrentSelection = State->FirstVisible + (State->LastVisible - State->FirstVisible) *
+                                               (State->CurrentSelection - State->InitialRow1) /
+                                               (State->MaxIndex - State->InitialRow1);
+                  } else {
+                     State->CurrentSelection = State->FirstVisible;
+                  } // if/else
+               } // if in second row
+            } else {
+               if (State->CurrentSelection > 0)
+                  State->CurrentSelection--;
+            } // if/else
+            break;
+
+        case SCROLL_LINE_DOWN:
+           if (State->ScrollMode == SCROLL_MODE_ICONS) {
+               if (State->CurrentSelection <= State->FinalRow0) {
+                  if (State->LastVisible > State->FirstVisible) { // avoid division by 0!
+                     State->CurrentSelection = State->InitialRow1 + (State->MaxIndex - State->InitialRow1) *
+                                               (State->CurrentSelection - State->FirstVisible) /
+                                               (State->LastVisible - State->FirstVisible);
+                  } else {
+                     State->CurrentSelection = State->InitialRow1;
+                  } // if/else
+               } // if in first row
+            } else {
+               if (State->CurrentSelection < State->MaxIndex)
+                  State->CurrentSelection++;
+            } // if/else
+            break;
+
+        case SCROLL_PAGE_UP:
+           if (State->CurrentSelection <= State->FinalRow0)
+              State->CurrentSelection -= State->MaxVisible;
+           else if (State->CurrentSelection == State->InitialRow1)
+              State->CurrentSelection = State->FinalRow0;
+           else
+              State->CurrentSelection = State->InitialRow1;
+           if (State->CurrentSelection < 0)
+              State->CurrentSelection = 0;
+           break;
+
+        case SCROLL_FIRST:
+           if (State->CurrentSelection > 0) {
+              State->PaintAll = TRUE;
+              State->CurrentSelection = 0;
+           }
+           break;
+
+        case SCROLL_PAGE_DOWN:
+           if (State->CurrentSelection < State->FinalRow0) {
+              State->CurrentSelection += State->MaxVisible;
+              if (State->CurrentSelection > State->FinalRow0)
+                 State->CurrentSelection = State->FinalRow0;
+           } else if (State->CurrentSelection == State->FinalRow0) {
+              State->CurrentSelection++;
+           } else {
+              State->CurrentSelection = State->MaxIndex;
+           }
+           if (State->CurrentSelection > State->MaxIndex)
+              State->CurrentSelection = State->MaxIndex;
+           break;
+
+        case SCROLL_LAST:
+           if (State->CurrentSelection < State->MaxIndex) {
+              State->PaintAll = TRUE;
+              State->CurrentSelection = State->MaxIndex;
+           }
+           break;
+
+        case SCROLL_NONE:
+            break;
+
+    }
+    if (State->ScrollMode == SCROLL_MODE_TEXT)
+       AdjustScrollState(State);
+
+    if (!State->PaintAll && State->CurrentSelection != State->PreviousSelection)
+        State->PaintSelection = TRUE;
+    State->LastVisible = State->FirstVisible + State->MaxVisible - 1;
+} // static VOID UpdateScroll()
+
+//
+// menu helper functions
+//
+
+VOID AddMenuInfoLine(IN REFIT_MENU_SCREEN *Screen, IN CHAR16 *InfoLine)
+{
+    AddListElement((VOID ***) &(Screen->InfoLines), &(Screen->InfoLineCount), InfoLine);
+}
+
+VOID AddMenuEntry(IN REFIT_MENU_SCREEN *Screen, IN REFIT_MENU_ENTRY *Entry)
+{
+    AddListElement((VOID ***) &(Screen->Entries), &(Screen->EntryCount), Entry);
+}
+
+
+static INTN FindMenuShortcutEntry(IN REFIT_MENU_SCREEN *Screen, IN CHAR16 *Defaults)
+{
+    UINTN i, j = 0;
+    CHAR16 *Shortcut;
+
+    while ((Shortcut = FindCommaDelimited(Defaults, j)) != NULL) {
+       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]) {
+                     MyFreePool(Shortcut);
+                     return i;
+                  } // if
+            } // for
+         } // if
+       } else if (StrLen(Shortcut) > 1) {
+          for (i = 0; i < Screen->EntryCount; i++) {
+             if (StriSubCmp(Shortcut, Screen->Entries[i]->Title)) {
+                MyFreePool(Shortcut);
+                return i;
+             } // if
+          } // for
+       }
+       MyFreePool(Shortcut);
+       j++;
+    } // while()
+    return -1;
+}
+
+// Identify the end of row 0 and the beginning of row 1; store the results in the
+// appropriate fields in State. Also reduce MaxVisible if that value is greater
+// than the total number of row-0 tags and if we're in an icon-based screen
+static VOID IdentifyRows(IN SCROLL_STATE *State, IN REFIT_MENU_SCREEN *Screen) {
+   UINTN i;
+
+   State->FinalRow0 = 0;
+   State->InitialRow1 = State->MaxIndex;
+   for (i = 0; i <= State->MaxIndex; i++) {
+      if (Screen->Entries[i]->Row == 0) {
+         State->FinalRow0 = i;
+      } else if ((Screen->Entries[i]->Row == 1) && (State->InitialRow1 > i)) {
+         State->InitialRow1 = i;
+      } // if/else
+   } // for
+   if ((State->ScrollMode == SCROLL_MODE_ICONS) && (State->MaxVisible > (State->FinalRow0 + 1)))
+      State->MaxVisible = State->FinalRow0 + 1;
+} // static VOID IdentifyRows()
+
+// Blank the screen, wait for a keypress, and restore banner/background.
+// Screen may still require redrawing of text and icons on return.
+// TODO: Support more sophisticated screen savers, such as power-saving
+// mode and dynamic images.
+static VOID SaveScreen(VOID) {
+   UINTN index;
+   EG_PIXEL Black = { 0x0, 0x0, 0x0, 0 };
+
+   egClearScreen(&Black);
+   refit_call3_wrapper(BS->WaitForEvent, 1, &ST->ConIn->WaitForKey, &index);
+   if (AllowGraphicsMode)
+      SwitchToGraphicsAndClear();
+   ReadAllKeyStrokes();
+} // VOID SaveScreen()
+
+//
+// generic menu function
+//
+static UINTN RunGenericMenu(IN REFIT_MENU_SCREEN *Screen, IN MENU_STYLE_FUNC StyleFunc, IN OUT INTN *DefaultEntryIndex,
+                            OUT REFIT_MENU_ENTRY **ChosenEntry)
+{
+    SCROLL_STATE State;
+    EFI_STATUS Status;
+    EFI_INPUT_KEY key;
+    UINTN index;
+    INTN ShortcutEntry;
+    BOOLEAN HaveTimeout = FALSE;
+    BOOLEAN WaitForRelease = FALSE;
+    UINTN TimeoutCountdown = 0;
+    INTN PreviousTime = -1, CurrentTime, TimeSinceKeystroke = 0;
+    CHAR16 TimeoutMessage[256];
+    CHAR16 KeyAsString[2];
+    UINTN MenuExit;
+
+    if (Screen->TimeoutSeconds > 0) {
+        HaveTimeout = TRUE;
+        TimeoutCountdown = Screen->TimeoutSeconds * 10;
+    }
+    MenuExit = 0;
+
+    StyleFunc(Screen, &State, MENU_FUNCTION_INIT, NULL);
+    IdentifyRows(&State, Screen);
+    // override the starting selection with the default index, if any
+    if (*DefaultEntryIndex >= 0 && *DefaultEntryIndex <= State.MaxIndex) {
+        State.CurrentSelection = *DefaultEntryIndex;
+        if (GlobalConfig.ScreensaverTime != -1)
+           UpdateScroll(&State, SCROLL_NONE);
+    }
+
+    if (Screen->TimeoutSeconds == -1) {
+        Status = refit_call2_wrapper(ST->ConIn->ReadKeyStroke, ST->ConIn, &key);
+        if (Status == EFI_NOT_READY) {
+            MenuExit = MENU_EXIT_TIMEOUT;
+        } else {
+            KeyAsString[0] = key.UnicodeChar;
+            KeyAsString[1] = 0;
+            ShortcutEntry = FindMenuShortcutEntry(Screen, KeyAsString);
+            if (ShortcutEntry >= 0) {
+                State.CurrentSelection = ShortcutEntry;
+                MenuExit = MENU_EXIT_ENTER;
+            } else {
+                WaitForRelease = TRUE;
+                HaveTimeout = FALSE;
+            }
+        }
+    }
+
+    if (GlobalConfig.ScreensaverTime != -1)
+        State.PaintAll = TRUE;
+
+    while (!MenuExit) {
+        // update the screen
+        if (State.PaintAll && (GlobalConfig.ScreensaverTime != -1)) {
+            StyleFunc(Screen, &State, MENU_FUNCTION_PAINT_ALL, NULL);
+            State.PaintAll = FALSE;
+        } else if (State.PaintSelection) {
+            StyleFunc(Screen, &State, MENU_FUNCTION_PAINT_SELECTION, NULL);
+            State.PaintSelection = FALSE;
+        }
+
+        if (WaitForRelease) {
+            Status = refit_call2_wrapper(ST->ConIn->ReadKeyStroke, ST->ConIn, &key);
+            if (Status == EFI_SUCCESS) {
+                // reset, because otherwise the buffer gets queued with keystrokes
+                refit_call2_wrapper(ST->ConIn->Reset, ST->ConIn, FALSE);
+                refit_call1_wrapper(BS->Stall, 100000);
+            } else {
+                WaitForRelease = FALSE;
+                refit_call2_wrapper(ST->ConIn->Reset, ST->ConIn, TRUE);
+            }
+            continue;
+        }
+
+        if (HaveTimeout) {
+            CurrentTime = (TimeoutCountdown + 5) / 10;
+            if (CurrentTime != PreviousTime) {
+               SPrint(TimeoutMessage, 255, L"%s in %d seconds", Screen->TimeoutText, CurrentTime);
+               if (GlobalConfig.ScreensaverTime != -1)
+                  StyleFunc(Screen, &State, MENU_FUNCTION_PAINT_TIMEOUT, TimeoutMessage);
+               PreviousTime = CurrentTime;
+            }
+        }
+
+        // read key press (and wait for it if applicable)
+        Status = refit_call2_wrapper(ST->ConIn->ReadKeyStroke, ST->ConIn, &key);
+        if (Status != EFI_SUCCESS) {
+            if (HaveTimeout && TimeoutCountdown == 0) {
+                // timeout expired
+                MenuExit = MENU_EXIT_TIMEOUT;
+                break;
+            } else if (HaveTimeout || GlobalConfig.ScreensaverTime > 0) {
+                EFI_EVENT           TimerEvent;
+                UINTN               ElapsCount = 1;
+
+                Status = refit_call5_wrapper(BS->CreateEvent, EVT_TIMER, 0, NULL, NULL, &TimerEvent);
+                if (EFI_ERROR(Status)) {
+                    refit_call1_wrapper(BS->Stall, 100000); // Pause for 100 ms
+                } else {
+                    EFI_EVENT           WaitList[2];
+                    UINTN               Index;
+
+                    refit_call3_wrapper(BS->SetTimer, TimerEvent, TimerRelative, 10000000); // 1s Timeout
+                    WaitList[0] = ST->ConIn->WaitForKey;
+                    WaitList[1] = TimerEvent;
+                    Status = refit_call3_wrapper(BS->WaitForEvent, 2, WaitList, &Index);
+                    refit_call1_wrapper(BS->CloseEvent, TimerEvent);
+                    if (EFI_ERROR(Status))
+                        refit_call1_wrapper(BS->Stall, 100000); // Pause for 100 ms
+                    else if(Index == 0)
+                        continue;
+                    else
+                        ElapsCount = 10; // always counted as 1s to end of the timeout
+                }
+                TimeSinceKeystroke += ElapsCount;
+                if(HaveTimeout) {
+                    TimeoutCountdown = TimeoutCountdown <= ElapsCount ? 0 : TimeoutCountdown - ElapsCount;
+                } else if (GlobalConfig.ScreensaverTime > 0 &&
+                        TimeSinceKeystroke > (GlobalConfig.ScreensaverTime * 10))
+                {
+                        SaveScreen();
+                        State.PaintAll = TRUE;
+                        TimeSinceKeystroke = 0;
+                } // if
+            } else {
+                refit_call3_wrapper(BS->WaitForEvent, 1, &ST->ConIn->WaitForKey, &index);
+            }
+            continue;
+        } else {
+           TimeSinceKeystroke = 0;
+        } // if/else !read keystroke
+
+        if (HaveTimeout) {
+            // the user pressed a key, cancel the timeout
+            StyleFunc(Screen, &State, MENU_FUNCTION_PAINT_TIMEOUT, L"");
+            HaveTimeout = FALSE;
+            if (GlobalConfig.ScreensaverTime == -1) { // cancel start-with-blank-screen coding
+               GlobalConfig.ScreensaverTime = 0;
+               if (!GlobalConfig.TextOnly)
+                 BltClearScreen(TRUE);
+            }
+        }
+
+        // react to key press
+        switch (key.ScanCode) {
+            case SCAN_UP:
+                UpdateScroll(&State, SCROLL_LINE_UP);
+                break;
+            case SCAN_LEFT:
+                UpdateScroll(&State, SCROLL_LINE_LEFT);
+                break;
+            case SCAN_DOWN:
+                UpdateScroll(&State, SCROLL_LINE_DOWN);
+                break;
+            case SCAN_RIGHT:
+                UpdateScroll(&State, SCROLL_LINE_RIGHT);
+                break;
+            case SCAN_HOME:
+                UpdateScroll(&State, SCROLL_FIRST);
+                break;
+            case SCAN_END:
+                UpdateScroll(&State, SCROLL_LAST);
+                break;
+            case SCAN_PAGE_UP:
+                UpdateScroll(&State, SCROLL_PAGE_UP);
+                break;
+            case SCAN_PAGE_DOWN:
+                UpdateScroll(&State, SCROLL_PAGE_DOWN);
+                break;
+            case SCAN_ESC:
+                MenuExit = MENU_EXIT_ESCAPE;
+                break;
+            case SCAN_INSERT:
+            case SCAN_F2:
+                MenuExit = MENU_EXIT_DETAILS;
+                break;
+            case SCAN_F10:
+                egScreenShot();
+                break;
+            case 0x0016: // F12
+               if (EjectMedia())
+                  MenuExit = MENU_EXIT_ESCAPE;
+               break;
+        }
+        switch (key.UnicodeChar) {
+            case CHAR_LINEFEED:
+            case CHAR_CARRIAGE_RETURN:
+            case ' ':
+                MenuExit = MENU_EXIT_ENTER;
+                break;
+            case '+':
+                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];
+    *DefaultEntryIndex = State.CurrentSelection;
+    return MenuExit;
+} /* static UINTN RunGenericMenu() */
+
+//
+// text-mode generic style
+//
+
+// Show information lines in text mode.
+static VOID ShowTextInfoLines(IN REFIT_MENU_SCREEN *Screen) {
+   INTN i;
+
+   BeginTextScreen(Screen->Title);
+   if (Screen->InfoLineCount > 0) {
+      refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BASIC);
+      for (i = 0; i < (INTN)Screen->InfoLineCount; i++) {
+         refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 3, 4 + i);
+         refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, Screen->InfoLines[i]);
+      }
+   }
+} // VOID ShowTextInfoLines()
+
+// Do most of the work for text-based menus....
+static VOID TextMenuStyle(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, IN UINTN Function, IN CHAR16 *ParamText)
+{
+    INTN i;
+    UINTN MenuWidth, ItemWidth, MenuHeight;
+    static UINTN MenuPosY;
+    static CHAR16 **DisplayStrings;
+    CHAR16 TimeoutMessage[256];
+
+    State->ScrollMode = SCROLL_MODE_TEXT;
+    switch (Function) {
+
+        case MENU_FUNCTION_INIT:
+            // vertical layout
+            MenuPosY = 4;
+            if (Screen->InfoLineCount > 0)
+                MenuPosY += Screen->InfoLineCount + 1;
+            MenuHeight = ConHeight - MenuPosY - 3;
+            if (Screen->TimeoutSeconds > 0)
+                MenuHeight -= 2;
+            InitScroll(State, Screen->EntryCount, MenuHeight);
+
+            // determine width of the menu
+            MenuWidth = 20;  // minimum
+            for (i = 0; i <= State->MaxIndex; i++) {
+                ItemWidth = StrLen(Screen->Entries[i]->Title);
+                if (MenuWidth < ItemWidth)
+                    MenuWidth = ItemWidth;
+            }
+            MenuWidth += 2;
+            if (MenuWidth > ConWidth - 3)
+                MenuWidth = ConWidth - 3;
+
+            // prepare strings for display
+            DisplayStrings = AllocatePool(sizeof(CHAR16 *) * Screen->EntryCount);
+            for (i = 0; i <= State->MaxIndex; i++) {
+                // Note: Theoretically, SPrint() is a cleaner way to do this; but the
+                // description of the StrSize parameter to SPrint implies it's measured
+                // in characters, but in practice both TianoCore and GNU-EFI seem to
+                // use bytes instead, resulting in truncated displays. I could just
+                // double the size of the StrSize parameter, but that seems unsafe in
+                // case a future library change starts treating this as characters, so
+                // I'm doing it the hard way in this instance.
+                // TODO: Review the above and possibly change other uses of SPrint()
+                DisplayStrings[i] = AllocateZeroPool(2 * sizeof(CHAR16));
+                DisplayStrings[i][0] = L' ';
+                MergeStrings(&DisplayStrings[i], Screen->Entries[i]->Title, 0);
+                if (StrLen(DisplayStrings[i]) > MenuWidth)
+                   DisplayStrings[i][MenuWidth - 1] = 0;
+                // TODO: use more elaborate techniques for shortening too long strings (ellipses in the middle)
+                // TODO: account for double-width characters
+            } // for
+
+            break;
+
+        case MENU_FUNCTION_CLEANUP:
+            // release temporary memory
+            for (i = 0; i <= State->MaxIndex; i++)
+                MyFreePool(DisplayStrings[i]);
+            MyFreePool(DisplayStrings);
+            break;
+
+        case MENU_FUNCTION_PAINT_ALL:
+            // paint the whole screen (initially and after scrolling)
+
+            ShowTextInfoLines(Screen);
+            for (i = 0; i <= State->MaxIndex; i++) {
+                if (i >= State->FirstVisible && i <= State->LastVisible) {
+                    refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 2, MenuPosY + (i - State->FirstVisible));
+                    if (i == State->CurrentSelection)
+                       refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_CHOICE_CURRENT);
+                    else
+                       refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_CHOICE_BASIC);
+                    refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, DisplayStrings[i]);
+                }
+            }
+            // scrolling indicators
+            refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_SCROLLARROW);
+            refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 0, MenuPosY);
+            if (State->FirstVisible > 0)
+                refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, ArrowUp);
+            else
+               refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, L" ");
+            refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 0, MenuPosY + State->MaxVisible);
+            if (State->LastVisible < State->MaxIndex)
+               refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, ArrowDown);
+            else
+               refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, L" ");
+            if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_HINTS)) {
+               if (Screen->Hint1 != NULL) {
+                  refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 0, ConHeight - 2);
+                  refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, Screen->Hint1);
+               }
+               if (Screen->Hint2 != NULL) {
+                  refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 0, ConHeight - 1);
+                  refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, Screen->Hint2);
+               }
+            }
+            break;
+
+        case MENU_FUNCTION_PAINT_SELECTION:
+            // redraw selection cursor
+            refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 2,
+                                MenuPosY + (State->PreviousSelection - State->FirstVisible));
+            refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_CHOICE_BASIC);
+            refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, DisplayStrings[State->PreviousSelection]);
+            refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 2,
+                                MenuPosY + (State->CurrentSelection - State->FirstVisible));
+            refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_CHOICE_CURRENT);
+            refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, DisplayStrings[State->CurrentSelection]);
+            break;
+
+        case MENU_FUNCTION_PAINT_TIMEOUT:
+            if (ParamText[0] == 0) {
+                // clear message
+                refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BASIC);
+                refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 0, ConHeight - 3);
+                refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, BlankLine + 1);
+            } else {
+                // paint or update message
+                refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_ERROR);
+                refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 3, ConHeight - 3);
+                SPrint(TimeoutMessage, 255, L"%s  ", ParamText);
+                refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, TimeoutMessage);
+            }
+            break;
+
+    }
+}
+
+//
+// graphical generic style
+//
+
+inline static UINTN TextLineHeight(VOID) {
+   return egGetFontHeight() + TEXT_YMARGIN * 2;
+} // UINTN TextLineHeight()
+
+//
+// Display a submenu
+//
+
+// Display text with a solid background (MenuBackgroundPixel or SelectionBackgroundPixel).
+// Indents text by one character and placed TEXT_YMARGIN pixels down from the
+// specified XPos and YPos locations.
+static VOID DrawText(IN CHAR16 *Text, IN BOOLEAN Selected, IN UINTN FieldWidth, IN UINTN XPos, IN UINTN YPos)
+{
+   EG_IMAGE *TextBuffer;
+   EG_PIXEL Bg;
+
+   TextBuffer = egCreateImage(FieldWidth, TextLineHeight(), FALSE);
+
+   egFillImage(TextBuffer, &MenuBackgroundPixel);
+   Bg = MenuBackgroundPixel;
+   if (Selected) {
+       // draw selection bar background
+       egFillImageArea(TextBuffer, 0, 0, FieldWidth, TextBuffer->Height, &SelectionBackgroundPixel);
+       Bg = SelectionBackgroundPixel;
+   }
+
+   // render the text
+   egRenderText(Text, TextBuffer, egGetFontCellWidth(), TEXT_YMARGIN, (Bg.r + Bg.g + Bg.b) / 3);
+   egDrawImageWithTransparency(TextBuffer, NULL, XPos, YPos, TextBuffer->Width, TextBuffer->Height);
+//    BltImage(TextBuffer, XPos, YPos);
+}
+
+// Finds the average brightness of the input Image.
+// NOTE: Passing an Image that covers the whole screen can strain the
+// capacity of a UINTN on a 32-bit system with a very large display.
+// Using UINT64 instead is unworkable, since the code won't compile
+// on a 32-bit system. As the intended use for this function is to handle
+// a single text string's background, this shouldn't be a problem, but it
+// may need addressing if it's applied more broadly....
+static UINT8 AverageBrightness(EG_IMAGE *Image) {
+   UINTN i;
+   UINTN Sum = 0;
+
+   if ((Image != NULL) && ((Image->Width * Image->Height) != 0)) {
+      for (i = 0; i < (Image->Width * Image->Height); i++) {
+         Sum += (Image->PixelData[i].r + Image->PixelData[i].g + Image->PixelData[i].b);
+      }
+      Sum /= (Image->Width * Image->Height * 3);
+   } // if
+   return (UINT8) Sum;
+} // UINT8 AverageBrightness()
+
+// Display text against the screen's background image. Special case: If Text is NULL
+// or 0-length, clear the line. Does NOT indent the text or reposition it relative
+// to the specified XPos and YPos values.
+static VOID DrawTextWithTransparency(IN CHAR16 *Text, IN UINTN XPos, IN UINTN YPos)
+{
+    UINTN TextWidth;
+    EG_IMAGE *TextBuffer = NULL;
+
+    if (Text == NULL)
+       Text = L"";
+
+    egMeasureText(Text, &TextWidth, NULL);
+    if (TextWidth == 0) {
+       TextWidth = UGAWidth;
+       XPos = 0;
+    }
+
+    TextBuffer = egCropImage(GlobalConfig.ScreenBackground, XPos, YPos, TextWidth, TextLineHeight());
+    if (TextBuffer == NULL)
+       return;
+
+    // render the text
+    egRenderText(Text, TextBuffer, 0, 0, AverageBrightness(TextBuffer));
+    egDrawImageWithTransparency(TextBuffer, NULL, XPos, YPos, TextBuffer->Width, TextBuffer->Height);
+    egFreeImage(TextBuffer);
+}
+
+// Compute the size & position of the window that will hold a subscreen's information.
+static VOID ComputeSubScreenWindowSize(REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, UINTN *XPos, UINTN *YPos,
+                                       UINTN *Width, UINTN *Height, UINTN *LineWidth) {
+   UINTN i, ItemWidth, HintTop, BannerBottomEdge, TitleWidth;
+   UINTN FontCellWidth = egGetFontCellWidth();
+   UINTN FontCellHeight = egGetFontHeight();
+
+   *Width = 20;
+   *Height = 5;
+   TitleWidth = egComputeTextWidth(Screen->Title);
+
+   for (i = 0; i < Screen->InfoLineCount; i++) {
+       ItemWidth = StrLen(Screen->InfoLines[i]);
+       if (*Width < ItemWidth) {
+           *Width = ItemWidth;
+       }
+       (*Height)++;
+   }
+   for (i = 0; i <= State->MaxIndex; i++) {
+       ItemWidth = StrLen(Screen->Entries[i]->Title);
+       if (*Width < ItemWidth) {
+           *Width = ItemWidth;
+       }
+       (*Height)++;
+   }
+   *Width = (*Width + 2) * FontCellWidth;
+   *LineWidth = *Width;
+   if (Screen->TitleImage)
+      *Width += (Screen->TitleImage->Width + TITLEICON_SPACING * 2 + FontCellWidth);
+   else
+      *Width += FontCellWidth;
+
+   if (*Width < TitleWidth)
+      *Width = TitleWidth + 2 * FontCellWidth;
+
+   // Keep it within the bounds of the screen, or 2/3 of the screen's width
+   // for screens over 800 pixels wide
+   if (*Width > UGAWidth)
+      *Width = UGAWidth;
+
+   *XPos = (UGAWidth - *Width) / 2;
+
+   HintTop = UGAHeight - (FontCellHeight * 3); // top of hint text
+   *Height *= TextLineHeight();
+   if (Screen->TitleImage && (*Height < (Screen->TitleImage->Height + TextLineHeight() * 4)))
+      *Height = Screen->TitleImage->Height + TextLineHeight() * 4;
+
+   if (GlobalConfig.BannerBottomEdge >= HintTop) { // probably a full-screen image; treat it as an empty banner
+      BannerBottomEdge = 0;
+   } else {
+      BannerBottomEdge = GlobalConfig.BannerBottomEdge;
+   }
+   if (*Height > (HintTop - BannerBottomEdge - FontCellHeight * 2)) {
+      BannerBottomEdge = 0;
+   }
+   if (*Height > (HintTop - BannerBottomEdge - FontCellHeight * 2)) {
+      // TODO: Implement scrolling in text screen.
+      *Height = (HintTop - BannerBottomEdge - FontCellHeight * 2);
+   }
+
+   *YPos = ((UGAHeight - *Height) / 2);
+   if (*YPos < BannerBottomEdge)
+      *YPos = BannerBottomEdge + FontCellHeight + (HintTop - BannerBottomEdge - *Height) / 2;
+} // VOID ComputeSubScreenWindowSize()
+
+// Displays sub-menus
+static VOID GraphicsMenuStyle(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, IN UINTN Function, IN CHAR16 *ParamText)
+{
+    INTN i;
+    UINTN ItemWidth;
+    static UINTN LineWidth, MenuWidth, MenuHeight, EntriesPosX, TitlePosX, EntriesPosY, TimeoutPosY, CharWidth;
+    EG_IMAGE *Window;
+    EG_PIXEL *BackgroundPixel = &(GlobalConfig.ScreenBackground->PixelData[0]);
+
+    CharWidth = egGetFontCellWidth();
+    State->ScrollMode = SCROLL_MODE_TEXT;
+    switch (Function) {
+
+        case MENU_FUNCTION_INIT:
+            InitScroll(State, Screen->EntryCount, 0);
+            ComputeSubScreenWindowSize(Screen, State, &EntriesPosX, &EntriesPosY, &MenuWidth, &MenuHeight, &LineWidth);
+            TimeoutPosY = EntriesPosY + (Screen->EntryCount + 1) * TextLineHeight();
+
+            // initial painting
+            SwitchToGraphicsAndClear();
+            Window = egCreateFilledImage(MenuWidth, MenuHeight, FALSE, BackgroundPixel);
+            egDrawImage(Window, EntriesPosX, EntriesPosY);
+            ItemWidth = egComputeTextWidth(Screen->Title);
+            if (MenuWidth > ItemWidth) {
+               TitlePosX = EntriesPosX + (MenuWidth - ItemWidth) / 2 - CharWidth;
+            } else {
+               TitlePosX = EntriesPosX;
+               if (CharWidth > 0) {
+                  i = MenuWidth / CharWidth - 2;
+                  if (i > 0)
+                     Screen->Title[i] = 0;
+               } // if
+            } // if/else
+            break;
+
+        case MENU_FUNCTION_CLEANUP:
+            // nothing to do
+            break;
+
+        case MENU_FUNCTION_PAINT_ALL:
+           ComputeSubScreenWindowSize(Screen, State, &EntriesPosX, &EntriesPosY, &MenuWidth, &MenuHeight, &LineWidth);
+           DrawText(Screen->Title, FALSE, (StrLen(Screen->Title) + 2) * CharWidth, TitlePosX, EntriesPosY += TextLineHeight());
+           if (Screen->TitleImage) {
+              BltImageAlpha(Screen->TitleImage, EntriesPosX + TITLEICON_SPACING, EntriesPosY + TextLineHeight() * 2,
+                            BackgroundPixel);
+              EntriesPosX += (Screen->TitleImage->Width + TITLEICON_SPACING * 2);
+           }
+           EntriesPosY += (TextLineHeight() * 2);
+           if (Screen->InfoLineCount > 0) {
+               for (i = 0; i < (INTN)Screen->InfoLineCount; i++) {
+                   DrawText(Screen->InfoLines[i], FALSE, LineWidth, EntriesPosX, EntriesPosY);
+                   EntriesPosY += TextLineHeight();
+               }
+               EntriesPosY += TextLineHeight();  // also add a blank line
+           }
+
+           for (i = 0; i <= State->MaxIndex; i++) {
+              DrawText(Screen->Entries[i]->Title, (i == State->CurrentSelection), LineWidth, EntriesPosX,
+                       EntriesPosY + i * TextLineHeight());
+           }
+           if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_HINTS)) {
+              if ((Screen->Hint1 != NULL) && (StrLen(Screen->Hint1) > 0))
+                 DrawTextWithTransparency(Screen->Hint1, (UGAWidth - egComputeTextWidth(Screen->Hint1)) / 2,
+                                          UGAHeight - (egGetFontHeight() * 3));
+              if ((Screen->Hint2 != NULL) && (StrLen(Screen->Hint2) > 0))
+                 DrawTextWithTransparency(Screen->Hint2, (UGAWidth - egComputeTextWidth(Screen->Hint2)) / 2,
+                                           UGAHeight - (egGetFontHeight() * 2));
+           } // if
+           break;
+
+        case MENU_FUNCTION_PAINT_SELECTION:
+            // redraw selection cursor
+            DrawText(Screen->Entries[State->PreviousSelection]->Title, FALSE, LineWidth,
+                     EntriesPosX, EntriesPosY + State->PreviousSelection * TextLineHeight());
+            DrawText(Screen->Entries[State->CurrentSelection]->Title, TRUE, LineWidth,
+                     EntriesPosX, EntriesPosY + State->CurrentSelection * TextLineHeight());
+            break;
+
+        case MENU_FUNCTION_PAINT_TIMEOUT:
+            DrawText(ParamText, FALSE, LineWidth, EntriesPosX, TimeoutPosY);
+            break;
+
+    }
+} // static VOID GraphicsMenuStyle()
+
+//
+// graphical main menu style
+//
+
+static VOID DrawMainMenuEntry(REFIT_MENU_ENTRY *Entry, BOOLEAN selected, UINTN XPos, UINTN YPos)
+{
+   EG_IMAGE *Background;
+
+   if (SelectionImages != NULL) {
+      if (selected) {
+         Background = egCropImage(GlobalConfig.ScreenBackground, XPos, YPos,
+                                  SelectionImages[Entry->Row]->Width, SelectionImages[Entry->Row]->Height);
+         egComposeImage(Background, SelectionImages[Entry->Row], 0, 0);
+         BltImageCompositeBadge(Background, Entry->Image, Entry->BadgeImage, XPos, YPos);
+      } else { // Image not selected; copy background
+         egDrawImageWithTransparency(Entry->Image, Entry->BadgeImage, XPos, YPos,
+                                     SelectionImages[Entry->Row]->Width, SelectionImages[Entry->Row]->Height);
+      } // if/else
+   } // if
+} // VOID DrawMainMenuEntry()
+
+static VOID PaintAll(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, UINTN *itemPosX,
+                     UINTN row0PosY, UINTN row1PosY, UINTN textPosY) {
+   INTN i;
+
+   if (Screen->Entries[State->CurrentSelection]->Row == 0)
+      AdjustScrollState(State);
+   for (i = State->FirstVisible; i <= State->MaxIndex; i++) {
+      if (Screen->Entries[i]->Row == 0) {
+         if (i <= State->LastVisible) {
+            DrawMainMenuEntry(Screen->Entries[i], (i == State->CurrentSelection) ? TRUE : FALSE,
+                              itemPosX[i - State->FirstVisible], row0PosY);
+         } // if
+      } else {
+         DrawMainMenuEntry(Screen->Entries[i], (i == State->CurrentSelection) ? TRUE : FALSE, itemPosX[i], row1PosY);
+      }
+   }
+   if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_LABEL)) {
+      DrawTextWithTransparency(L"", 0, textPosY);
+      DrawTextWithTransparency(Screen->Entries[State->CurrentSelection]->Title,
+                               (UGAWidth - egComputeTextWidth(Screen->Entries[State->CurrentSelection]->Title)) >> 1,
+                               textPosY);
+   }
+
+   if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_HINTS)) {
+      DrawTextWithTransparency(Screen->Hint1, (UGAWidth - egComputeTextWidth(Screen->Hint1)) / 2,
+                               UGAHeight - (egGetFontHeight() * 3));
+      DrawTextWithTransparency(Screen->Hint2, (UGAWidth - egComputeTextWidth(Screen->Hint2)) / 2,
+                               UGAHeight - (egGetFontHeight() * 2));
+   } // if
+} // static VOID PaintAll()
+
+// Move the selection to State->CurrentSelection, adjusting icon row if necessary...
+static VOID PaintSelection(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, UINTN *itemPosX,
+                           UINTN row0PosY, UINTN row1PosY, UINTN textPosY) {
+   UINTN XSelectPrev, XSelectCur, YPosPrev, YPosCur;
+
+   if (((State->CurrentSelection <= State->LastVisible) && (State->CurrentSelection >= State->FirstVisible)) ||
+       (State->CurrentSelection >= State->InitialRow1) ) {
+      if (Screen->Entries[State->PreviousSelection]->Row == 0) {
+         XSelectPrev = State->PreviousSelection - State->FirstVisible;
+         YPosPrev = row0PosY;
+      } else {
+         XSelectPrev = State->PreviousSelection;
+         YPosPrev = row1PosY;
+      } // if/else
+      if (Screen->Entries[State->CurrentSelection]->Row == 0) {
+         XSelectCur = State->CurrentSelection - State->FirstVisible;
+         YPosCur = row0PosY;
+      } else {
+         XSelectCur = State->CurrentSelection;
+         YPosCur = row1PosY;
+      } // if/else
+      DrawMainMenuEntry(Screen->Entries[State->PreviousSelection], FALSE, itemPosX[XSelectPrev], YPosPrev);
+      DrawMainMenuEntry(Screen->Entries[State->CurrentSelection], TRUE, itemPosX[XSelectCur], YPosCur);
+      if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_LABEL)) {
+         DrawTextWithTransparency(L"", 0, textPosY);
+         DrawTextWithTransparency(Screen->Entries[State->CurrentSelection]->Title,
+                                  (UGAWidth - egComputeTextWidth(Screen->Entries[State->CurrentSelection]->Title)) >> 1,
+                                  textPosY);
+      }
+   } else { // Current selection not visible; must redraw the menu....
+      MainMenuStyle(Screen, State, MENU_FUNCTION_PAINT_ALL, NULL);
+   }
+} // static VOID MoveSelection(VOID)
+
+// Display a 48x48 icon at the specified location. Uses the image specified by
+// ExternalFilename if it's available, or BuiltInImage if it's not. The
+// Y position is specified as the center value, and so is adjusted by half
+// the icon's height. The X position is set along the icon's left
+// edge if Alignment == ALIGN_LEFT, and along the right edge if
+// Alignment == ALIGN_RIGHT
+static VOID PaintIcon(IN EG_EMBEDDED_IMAGE *BuiltInIcon, IN CHAR16 *ExternalFilename, UINTN PosX, UINTN PosY, UINTN Alignment) {
+   EG_IMAGE *Icon = NULL;
+
+   Icon = egFindIcon(ExternalFilename, GlobalConfig.IconSizes[ICON_SIZE_SMALL]);
+   if (Icon == NULL)
+      Icon = egPrepareEmbeddedImage(BuiltInIcon, TRUE);
+   if (Icon != NULL) {
+      if (Alignment == ALIGN_RIGHT)
+         PosX -= Icon->Width;
+      egDrawImageWithTransparency(Icon, NULL, PosX, PosY - (Icon->Height / 2), Icon->Width, Icon->Height);
+   }
+} // static VOID ()
+
+UINTN ComputeRow0PosY(VOID) {
+   return ((UGAHeight / 2) - TileSizes[0] / 2);
+} // UINTN ComputeRow0PosY()
+
+// Display (or erase) the arrow icons to the left and right of an icon's row,
+// as appropriate.
+static VOID PaintArrows(SCROLL_STATE *State, UINTN PosX, UINTN PosY, UINTN row0Loaders) {
+   EG_IMAGE *TempImage;
+   UINTN Width, Height, RightX, AdjPosY;
+
+   // NOTE: Assume that left and right arrows are of the same size....
+   Width = egemb_arrow_left.Width;
+   Height = egemb_arrow_left.Height;
+   RightX = (UGAWidth + (TileSizes[0] + TILE_XSPACING) * State->MaxVisible) / 2 + TILE_XSPACING;
+   AdjPosY = PosY - (Height / 2);
+
+   // For PaintIcon() calls, the starting Y position is moved to the midpoint
+   // of the surrounding row; PaintIcon() adjusts this back up by half the
+   // icon's height to properly center it.
+   if ((State->FirstVisible > 0) && (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_ARROWS))) {
+      PaintIcon(&egemb_arrow_left, L"arrow_left", PosX, PosY, ALIGN_RIGHT);
+   } else {
+      TempImage = egCropImage(GlobalConfig.ScreenBackground, PosX - Width, AdjPosY, Width, Height);
+      BltImage(TempImage, PosX - Width, AdjPosY);
+      egFreeImage(TempImage);
+   } // if/else
+
+   if ((State->LastVisible < (row0Loaders - 1)) && (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_ARROWS))) {
+      PaintIcon(&egemb_arrow_right, L"arrow_right", RightX, PosY, ALIGN_LEFT);
+   } else {
+      TempImage = egCropImage(GlobalConfig.ScreenBackground, RightX, AdjPosY, Width, Height);
+      BltImage(TempImage, RightX, AdjPosY);
+      egFreeImage(TempImage);
+   } // if/else
+} // VOID PaintArrows()
+
+// Display main menu in graphics mode
+VOID MainMenuStyle(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, IN UINTN Function, IN CHAR16 *ParamText)
+{
+    INTN i;
+    static UINTN row0PosX, row0PosXRunning, row1PosY, row0Loaders;
+    UINTN row0Count, row1Count, row1PosX, row1PosXRunning;
+    static UINTN *itemPosX;
+    static UINTN row0PosY, textPosY;
+
+    State->ScrollMode = SCROLL_MODE_ICONS;
+    switch (Function) {
+
+        case MENU_FUNCTION_INIT:
+            InitScroll(State, Screen->EntryCount, GlobalConfig.MaxTags);
+
+            // layout
+            row0Count = 0;
+            row1Count = 0;
+            row0Loaders = 0;
+            for (i = 0; i <= State->MaxIndex; i++) {
+               if (Screen->Entries[i]->Row == 1) {
+                  row1Count++;
+               } else {
+                  row0Loaders++;
+                  if (row0Count < State->MaxVisible)
+                     row0Count++;
+               }
+            }
+            row0PosX = (UGAWidth + TILE_XSPACING - (TileSizes[0] + TILE_XSPACING) * row0Count) >> 1;
+            row0PosY = ComputeRow0PosY();
+            row1PosX = (UGAWidth + TILE_XSPACING - (TileSizes[1] + TILE_XSPACING) * row1Count) >> 1;
+            row1PosY = row0PosY + TileSizes[0] + TILE_YSPACING;
+            if (row1Count > 0)
+                textPosY = row1PosY + TileSizes[1] + TILE_YSPACING;
+            else
+                textPosY = row1PosY;
+
+            itemPosX = AllocatePool(sizeof(UINTN) * Screen->EntryCount);
+            row0PosXRunning = row0PosX;
+            row1PosXRunning = row1PosX;
+            for (i = 0; i <= State->MaxIndex; i++) {
+                if (Screen->Entries[i]->Row == 0) {
+                    itemPosX[i] = row0PosXRunning;
+                    row0PosXRunning += TileSizes[0] + TILE_XSPACING;
+                } else {
+                    itemPosX[i] = row1PosXRunning;
+                    row1PosXRunning += TileSizes[1] + TILE_XSPACING;
+                }
+            }
+            // initial painting
+            InitSelection();
+            SwitchToGraphicsAndClear();
+            break;
+
+        case MENU_FUNCTION_CLEANUP:
+            MyFreePool(itemPosX);
+            break;
+
+        case MENU_FUNCTION_PAINT_ALL:
+            PaintAll(Screen, State, itemPosX, row0PosY, row1PosY, textPosY);
+            // For PaintArrows(), the starting Y position is moved to the midpoint
+            // of the surrounding row; PaintIcon() adjusts this back up by half the
+            // icon's height to properly center it.
+            PaintArrows(State, row0PosX - TILE_XSPACING, row0PosY + (TileSizes[0] / 2), row0Loaders);
+            break;
+
+        case MENU_FUNCTION_PAINT_SELECTION:
+            PaintSelection(Screen, State, itemPosX, row0PosY, row1PosY, textPosY);
+            break;
+
+        case MENU_FUNCTION_PAINT_TIMEOUT:
+            if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_LABEL)) {
+               DrawTextWithTransparency(L"", 0, textPosY + TextLineHeight());
+               DrawTextWithTransparency(ParamText, (UGAWidth - egComputeTextWidth(ParamText)) >> 1, textPosY + TextLineHeight());
+            }
+            break;
+
+    }
+} // VOID MainMenuStyle()
+
+// Enable the user to edit boot loader options.
+// Returns TRUE if the user exited with edited options; FALSE if the user
+// pressed Esc to terminate the edit.
+static BOOLEAN EditOptions(LOADER_ENTRY *MenuEntry) {
+   UINTN x_max, y_max;
+   CHAR16 *EditedOptions;
+   BOOLEAN retval = FALSE;
+
+   if (GlobalConfig.HideUIFlags & HIDEUI_FLAG_EDITOR) {
+      return FALSE;
+   }
+
+   refit_call4_wrapper(ST->ConOut->QueryMode, ST->ConOut, ST->ConOut->Mode->Mode, &x_max, &y_max);
+
+   if (!GlobalConfig.TextOnly)
+      SwitchToText(TRUE);
+
+   if (line_edit(MenuEntry->LoadOptions, &EditedOptions, x_max)) {
+      MyFreePool(MenuEntry->LoadOptions);
+      MenuEntry->LoadOptions = EditedOptions;
+      retval = TRUE;
+   } // if
+   if (!GlobalConfig.TextOnly)
+      SwitchToGraphics();
+   return retval;
+} // VOID EditOptions()
+
+//
+// user-callable dispatcher functions
+//
+
+UINTN RunMenu(IN REFIT_MENU_SCREEN *Screen, OUT REFIT_MENU_ENTRY **ChosenEntry)
+{
+    INTN            DefaultEntry = -1;
+    MENU_STYLE_FUNC Style = TextMenuStyle;
+
+    if (AllowGraphicsMode)
+        Style = GraphicsMenuStyle;
+
+    return RunGenericMenu(Screen, Style, &DefaultEntry, ChosenEntry);
+}
+
+UINTN RunMainMenu(REFIT_MENU_SCREEN *Screen, CHAR16** DefaultSelection, REFIT_MENU_ENTRY **ChosenEntry)
+{
+    MENU_STYLE_FUNC Style = TextMenuStyle;
+    MENU_STYLE_FUNC MainStyle = TextMenuStyle;
+    REFIT_MENU_ENTRY *TempChosenEntry;
+    CHAR16 *MenuTitle;
+    UINTN MenuExit = 0;
+    INTN DefaultEntryIndex = -1;
+    INTN DefaultSubmenuIndex = -1;
+
+    TileSizes[0] = (GlobalConfig.IconSizes[ICON_SIZE_BIG] * 9) / 8;
+    TileSizes[1] = (GlobalConfig.IconSizes[ICON_SIZE_SMALL] * 4) / 3;
+
+    if ((DefaultSelection != NULL) && (*DefaultSelection != NULL)) {
+        // Find a menu entry that includes *DefaultSelection as a substring
+        DefaultEntryIndex = FindMenuShortcutEntry(Screen, *DefaultSelection);
+    }
+
+    if (AllowGraphicsMode) {
+        Style = GraphicsMenuStyle;
+        MainStyle = MainMenuStyle;
+    }
+
+    while (!MenuExit) {
+        MenuExit = RunGenericMenu(Screen, MainStyle, &DefaultEntryIndex, &TempChosenEntry);
+        Screen->TimeoutSeconds = 0;
+
+        MenuTitle = StrDuplicate(TempChosenEntry->Title);
+        if (MenuExit == MENU_EXIT_DETAILS) {
+            if (TempChosenEntry->SubScreen != NULL) {
+               MenuExit = RunGenericMenu(TempChosenEntry->SubScreen, Style, &DefaultSubmenuIndex, &TempChosenEntry);
+               if (MenuExit == MENU_EXIT_ESCAPE || TempChosenEntry->Tag == TAG_RETURN)
+                   MenuExit = 0;
+               if (MenuExit == MENU_EXIT_DETAILS) {
+                  if (!EditOptions((LOADER_ENTRY *) TempChosenEntry))
+                     MenuExit = 0;
+               } // if
+            } else { // no sub-screen; ignore keypress
+               MenuExit = 0;
+            }
+        } // Enter sub-screen
+    }
+
+    if (ChosenEntry)
+        *ChosenEntry = TempChosenEntry;
+    if (DefaultSelection) {
+       MyFreePool(*DefaultSelection);
+       *DefaultSelection = MenuTitle;
+    } // if
+    return MenuExit;
+} /* UINTN RunMainMenu() */
diff --git a/refind/menu.h b/refind/menu.h
new file mode 100644 (file)
index 0000000..0b2db1f
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * refind/menu.h
+ * menu functions header file
+ *
+ * Copyright (c) 2006-2009 Christoph Pfisterer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Modifications copyright (c) 2012 Roderick W. Smith
+ * 
+ * Modifications distributed under the terms of the GNU General Public
+ * License (GPL) version 3 (GPLv3), a copy of which must be distributed
+ * with this source code or binaries made from it.
+ * 
+ */
+
+#ifndef __REFIND_MENU_H_
+#define __REFIND_MENU_H_
+
+#ifdef __MAKEWITH_GNUEFI
+#include "efi.h"
+#include "efilib.h"
+#else
+#include "../include/tiano_includes.h"
+#endif
+#include "global.h"
+
+#include "libeg.h"
+
+//
+// menu module
+//
+
+#define MENU_EXIT_ENTER   (1)
+#define MENU_EXIT_ESCAPE  (2)
+#define MENU_EXIT_DETAILS (3)
+#define MENU_EXIT_TIMEOUT (4)
+#define MENU_EXIT_EJECT   (5)
+
+#define TAG_RETURN       (99)
+
+// scrolling definitions
+
+typedef struct {
+   INTN CurrentSelection, PreviousSelection, MaxIndex;
+   INTN FirstVisible, LastVisible, MaxVisible;
+   INTN FinalRow0, InitialRow1;
+   INTN ScrollMode;
+   BOOLEAN PaintAll, PaintSelection;
+} SCROLL_STATE;
+
+#define SCROLL_LINE_UP    (0)
+#define SCROLL_LINE_DOWN  (1)
+#define SCROLL_PAGE_UP    (2)
+#define SCROLL_PAGE_DOWN  (3)
+#define SCROLL_FIRST      (4)
+#define SCROLL_LAST       (5)
+#define SCROLL_NONE       (6)
+#define SCROLL_LINE_RIGHT (7)
+#define SCROLL_LINE_LEFT  (8)
+
+#define SCROLL_MODE_TEXT  (0) /* Used in text mode & for GUI submenus */
+#define SCROLL_MODE_ICONS (1) /* Used for main GUI menu */
+
+struct _refit_menu_screen;
+
+VOID AddMenuInfoLine(IN REFIT_MENU_SCREEN *Screen, IN CHAR16 *InfoLine);
+VOID AddMenuEntry(IN REFIT_MENU_SCREEN *Screen, IN REFIT_MENU_ENTRY *Entry);
+UINTN ComputeRow0PosY(VOID);
+VOID MainMenuStyle(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, IN UINTN Function, IN CHAR16 *ParamText);
+UINTN RunMenu(IN REFIT_MENU_SCREEN *Screen, OUT REFIT_MENU_ENTRY **ChosenEntry);
+UINTN RunMainMenu(IN REFIT_MENU_SCREEN *Screen, IN CHAR16** DefaultSelection, OUT REFIT_MENU_ENTRY **ChosenEntry);
+
+#endif
+
+/* EOF */
diff --git a/refind/mystrings.c b/refind/mystrings.c
new file mode 100644 (file)
index 0000000..a5c5823
--- /dev/null
@@ -0,0 +1,458 @@
+/*
+ * refind/mystrings.c
+ * String-manipulation functions
+ *
+ * Copyright (c) 2012-2015 Roderick W. Smith
+ *
+ * Distributed under the terms of the GNU General Public License (GPL)
+ * version 3 (GPLv3), or (at your option) any later version.
+ *
+ */
+/*
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "mystrings.h"
+#include "lib.h"
+
+BOOLEAN StriSubCmp(IN CHAR16 *SmallStr, IN CHAR16 *BigStr) {
+    BOOLEAN Found = 0, Terminate = 0;
+    UINTN BigIndex = 0, SmallIndex = 0, BigStart = 0;
+
+    if (SmallStr && BigStr) {
+        while (!Terminate) {
+            if (BigStr[BigIndex] == '\0') {
+                Terminate = 1;
+            }
+            if (SmallStr[SmallIndex] == '\0') {
+                Found = 1;
+                Terminate = 1;
+            }
+            if ((SmallStr[SmallIndex] & ~0x20) == (BigStr[BigIndex] & ~0x20)) {
+                SmallIndex++;
+                BigIndex++;
+            } else {
+                SmallIndex = 0;
+                BigStart++;
+                BigIndex = BigStart;
+            }
+        } // while
+    } // if
+    return Found;
+} // BOOLEAN StriSubCmp()
+
+// Performs a case-insensitive string comparison. This function is necesary
+// because some EFIs have buggy StriCmp() functions that actually perform
+// case-sensitive comparisons.
+// Returns TRUE if strings are identical, FALSE otherwise.
+BOOLEAN MyStriCmp(IN CONST CHAR16 *FirstString, IN CONST CHAR16 *SecondString) {
+    if (FirstString && SecondString) {
+        while ((*FirstString != L'\0') && ((*FirstString & ~0x20) == (*SecondString & ~0x20))) {
+                FirstString++;
+                SecondString++;
+        }
+        return (*FirstString == *SecondString);
+    } else {
+        return FALSE;
+    }
+} // BOOLEAN MyStriCmp()
+
+/*++
+ * 
+ * Routine Description:
+ *
+ *  Find a substring.
+ *
+ * Arguments: 
+ *
+ *  String      - Null-terminated string to search.
+ *  StrCharSet  - Null-terminated string to search for.
+ *
+ * Returns:
+ *  The address of the first occurrence of the matching substring if successful, or NULL otherwise.
+ * --*/
+CHAR16* MyStrStr (IN CHAR16  *String, IN CHAR16  *StrCharSet)
+{
+    CHAR16 *Src;
+    CHAR16 *Sub;
+
+    if ((String == NULL) || (StrCharSet == NULL))
+        return NULL;
+
+    Src = String;
+    Sub = StrCharSet;
+
+    while ((*String != L'\0') && (*StrCharSet != L'\0')) {
+        if (*String++ != *StrCharSet) {
+            String = ++Src;
+            StrCharSet = Sub;
+        } else {
+            StrCharSet++;
+        }
+    }
+    if (*StrCharSet == L'\0') {
+        return Src;
+    } else {
+        return NULL;
+    }
+} // CHAR16 *MyStrStr()
+
+// Convert input string to all-lowercase.
+// DO NOT USE the standard StrLwr() function, since it's broken on some EFIs!
+VOID ToLower(CHAR16 * MyString) {
+    UINTN i = 0;
+
+    if (MyString) {
+        while (MyString[i] != L'\0') {
+            if ((MyString[i] >= L'A') && (MyString[i] <= L'Z'))
+                MyString[i] = MyString[i] - L'A' + L'a';
+            i++;
+        } // while
+    } // if
+} // VOID ToLower()
+
+// Merges two strings, creating a new one and returning a pointer to it.
+// If AddChar != 0, the specified character is placed between the two original
+// strings (unless the first string is NULL or empty). The original input
+// string *First is de-allocated and replaced by the new merged string.
+// This is similar to StrCat, but safer and more flexible because
+// MergeStrings allocates memory that's the correct size for the
+// new merged string, so it can take a NULL *First and it cleans
+// up the old memory. It should *NOT* be used with a constant
+// *First, though....
+VOID MergeStrings(IN OUT CHAR16 **First, IN CHAR16 *Second, CHAR16 AddChar) {
+    UINTN Length1 = 0, Length2 = 0;
+    CHAR16* NewString;
+
+    if (*First != NULL)
+        Length1 = StrLen(*First);
+    if (Second != NULL)
+        Length2 = StrLen(Second);
+    NewString = AllocatePool(sizeof(CHAR16) * (Length1 + Length2 + 2));
+    if (NewString != NULL) {
+        if ((*First != NULL) && (Length1 == 0)) {
+            MyFreePool(*First);
+            *First = NULL;
+        }
+        NewString[0] = L'\0';
+        if (*First != NULL) {
+            StrCat(NewString, *First);
+            if (AddChar) {
+                NewString[Length1] = AddChar;
+                NewString[Length1 + 1] = '\0';
+            } // if (AddChar)
+        } // if (*First != NULL)
+        if (Second != NULL)
+            StrCat(NewString, Second);
+        MyFreePool(*First);
+        *First = NewString;
+    } else {
+        Print(L"Error! Unable to allocate memory in MergeStrings()!\n");
+    } // if/else
+} // VOID MergeStrings()
+
+// Similar to MergeStrings, but breaks the input string into word chunks and
+// merges each word separately. Words are defined as string fragments separated
+// by ' ', '_', or '-'.
+VOID MergeWords(CHAR16 **MergeTo, CHAR16 *SourceString, CHAR16 AddChar) {
+    CHAR16 *Temp, *Word, *p;
+    BOOLEAN LineFinished = FALSE;
+
+    if (SourceString) {
+        Temp = Word = p = StrDuplicate(SourceString);
+        if (Temp) {
+            while (!LineFinished) {
+                if ((*p == L' ') || (*p == L'_') || (*p == L'-') || (*p == L'\0')) {
+                    if (*p == L'\0')
+                        LineFinished = TRUE;
+                    *p = L'\0';
+                    if (*Word != L'\0')
+                        MergeStrings(MergeTo, Word, AddChar);
+                    Word = p + 1;
+                } // if
+                p++;
+            } // while
+            MyFreePool(Temp);
+        } else {
+            Print(L"Error! Unable to allocate memory in MergeWords()!\n");
+        } // if/else
+    } // if
+} // VOID MergeWords()
+
+// Restrict TheString to at most Limit characters.
+// Does this in two ways:
+// - Locates stretches of two or more spaces and compresses
+//   them down to one space.
+// - Truncates TheString
+// Returns TRUE if changes were made, FALSE otherwise
+BOOLEAN LimitStringLength(CHAR16 *TheString, UINTN Limit) {
+    CHAR16    *SubString, *TempString;
+    UINTN     i;
+    BOOLEAN   HasChanged = FALSE;
+
+    // SubString will be NULL or point WITHIN TheString
+    SubString = MyStrStr(TheString, L"  ");
+    while (SubString != NULL) {
+        i = 0;
+        while (SubString[i] == L' ')
+            i++;
+        if (i >= StrLen(SubString)) {
+            SubString[0] = '\0';
+            HasChanged = TRUE;
+        } else {
+            TempString = StrDuplicate(&SubString[i]);
+            if (TempString != NULL) {
+                StrCpy(&SubString[1], TempString);
+                MyFreePool(TempString);
+                HasChanged = TRUE;
+            } else {
+                // memory allocation problem; abort to avoid potentially infinite loop!
+                break;
+            } // if/else
+        } // if/else
+        SubString = MyStrStr(TheString, L"  ");
+    } // while
+
+    // If the string is still too long, truncate it....
+    if (StrLen(TheString) > Limit) {
+        TheString[Limit] = '\0';
+        HasChanged = TRUE;
+    } // if
+
+    return HasChanged;
+} // BOOLEAN LimitStringLength()
+
+// Returns all the digits in the input string, including intervening
+// non-digit characters. For instance, if InString is "foo-3.3.4-7.img",
+// this function returns "3.3.4-7". If InString contains no digits,
+// the return value is NULL.
+CHAR16 *FindNumbers(IN CHAR16 *InString) {
+    UINTN i, StartOfElement, EndOfElement = 0, CopyLength;
+    CHAR16 *Found = NULL;
+
+    if (InString == NULL)
+        return NULL;
+
+    StartOfElement = StrLen(InString);
+    // Find start & end of target element
+    for (i = 0; InString[i] != L'\0'; i++) {
+        if ((InString[i] >= L'0') && (InString[i] <= L'9')) {
+            if (StartOfElement > i)
+                StartOfElement = i;
+            if (EndOfElement < i)
+                EndOfElement = i;
+        } // if
+    } // for
+    // Extract the target element
+    if (EndOfElement > 0) {
+        if (EndOfElement >= StartOfElement) {
+            CopyLength = EndOfElement - StartOfElement + 1;
+            Found = StrDuplicate(&InString[StartOfElement]);
+            if (Found != NULL)
+                Found[CopyLength] = 0;
+        } // if (EndOfElement >= StartOfElement)
+    } // if (EndOfElement > 0)
+    return (Found);
+} // CHAR16 *FindNumbers()
+
+// Find the #Index element (numbered from 0) in a comma-delimited string
+// of elements.
+// Returns the found element, or NULL if Index is out of range or InString
+// is NULL. Note that the calling function is responsible for freeing the
+// memory associated with the returned string pointer.
+CHAR16 *FindCommaDelimited(IN CHAR16 *InString, IN UINTN Index) {
+    UINTN    StartPos = 0, CurPos = 0, InLength;
+    BOOLEAN  Found = FALSE;
+    CHAR16   *FoundString = NULL;
+
+    if (InString != NULL) {
+        InLength = StrLen(InString);
+        // After while() loop, StartPos marks start of item #Index
+        while ((Index > 0) && (CurPos < InLength)) {
+            if (InString[CurPos] == L',') {
+                Index--;
+                StartPos = CurPos + 1;
+            } // if
+            CurPos++;
+        } // while
+        // After while() loop, CurPos is one past the end of the element
+        while ((CurPos < InLength) && (!Found)) {
+            if (InString[CurPos] == L',')
+                Found = TRUE;
+            else
+                CurPos++;
+        } // while
+        if (Index == 0)
+            FoundString = StrDuplicate(&InString[StartPos]);
+        if (FoundString != NULL)
+            FoundString[CurPos - StartPos] = 0;
+    } // if
+    return (FoundString);
+} // CHAR16 *FindCommaDelimited()
+
+// Returns TRUE if SmallString is an element in the comma-delimited List,
+// FALSE otherwise. Performs comparison case-insensitively.
+BOOLEAN IsIn(IN CHAR16 *SmallString, IN CHAR16 *List) {
+   UINTN     i = 0;
+   BOOLEAN   Found = FALSE;
+   CHAR16    *OneElement;
+
+   if (SmallString && List) {
+      while (!Found && (OneElement = FindCommaDelimited(List, i++))) {
+         if (MyStriCmp(OneElement, SmallString))
+            Found = TRUE;
+      } // while
+   } // if
+   return Found;
+} // BOOLEAN IsIn()
+
+// Returns TRUE if any element of List can be found as a substring of
+// BigString, FALSE otherwise. Performs comparisons case-insensitively.
+BOOLEAN IsInSubstring(IN CHAR16 *BigString, IN CHAR16 *List) {
+   UINTN   i = 0, ElementLength;
+   BOOLEAN Found = FALSE;
+   CHAR16  *OneElement;
+
+   if (BigString && List) {
+      while (!Found && (OneElement = FindCommaDelimited(List, i++))) {
+         ElementLength = StrLen(OneElement);
+         if ((ElementLength <= StrLen(BigString)) && (StriSubCmp(OneElement, BigString)))
+            Found = TRUE;
+      } // while
+   } // if
+   return Found;
+} // BOOLEAN IsSubstringIn()
+
+// Returns TRUE if *Input contains nothing but valid hexadecimal characters,
+// FALSE otherwise. Note that a leading "0x" is NOT acceptable in the input!
+BOOLEAN IsValidHex(CHAR16 *Input) {
+    BOOLEAN IsHex = TRUE;
+    UINTN i = 0;
+
+    while ((Input[i] != L'\0') && IsHex) {
+        if (!(((Input[i] >= L'0') && (Input[i] <= L'9')) ||
+              ((Input[i] >= L'A') && (Input[i] <= L'F')) ||
+              ((Input[i] >= L'a') && (Input[i] <= L'f')))) {
+                IsHex = FALSE;
+        }
+        i++;
+    } // while
+    return IsHex;
+} // BOOLEAN IsValidHex()
+
+// Converts consecutive characters in the input string into a
+// number, interpreting the string as a hexadecimal number, starting
+// at the specified position and continuing for the specified number
+// of characters or until the end of the string, whichever is first.
+// NumChars must be between 1 and 16. Ignores invalid characters.
+UINT64 StrToHex(CHAR16 *Input, UINTN Pos, UINTN NumChars) {
+    UINT64 retval = 0x00;
+    UINTN  NumDone = 0, InputLength;
+    CHAR16 a;
+
+    if ((Input == NULL) || (NumChars == 0) || (NumChars > 16)) {
+        return 0;
+    }
+
+    InputLength = StrLen(Input);
+    while ((Pos <= InputLength) && (NumDone < NumChars)) {
+        a = Input[Pos];
+        if ((a >= '0') && (a <= '9')) {
+            retval *= 0x10;
+            retval += (a - '0');
+            NumDone++;
+        }
+        if ((a >= 'a') && (a <= 'f')) {
+            retval *= 0x10;
+            retval += (a - 'a' + 0x0a);
+            NumDone++;
+        }
+        if ((a >= 'A') && (a <= 'F')) {
+            retval *= 0x10;
+            retval += (a - 'A' + 0x0a);
+            NumDone++;
+        }
+        Pos++;
+    } // while()
+    return retval;
+} // StrToHex()
+
+// Returns TRUE if UnknownString can be interpreted as a GUID, FALSE otherwise.
+// Note that the input string must have no extraneous spaces and must be
+// conventionally formatted as a 36-character GUID, complete with dashes in
+// appropriate places.
+BOOLEAN IsGuid(CHAR16 *UnknownString) {
+    UINTN   Length, i;
+    BOOLEAN retval = TRUE;
+    CHAR16  a;
+
+    if (UnknownString == NULL)
+        return FALSE;
+
+    Length = StrLen(UnknownString);
+    if (Length != 36)
+        return FALSE;
+
+    for (i = 0; i < Length; i++) {
+        a = UnknownString[i];
+        if ((i == 8) || (i == 13) || (i == 18) || (i == 23)) {
+            if (a != L'-')
+                retval = FALSE;
+        } else if (((a < L'a') || (a > L'f')) &&
+                   ((a < L'A') || (a > L'F')) &&
+                   ((a < L'0') && (a > L'9'))) {
+            retval = FALSE;
+        } // if/else if
+    } // for
+    return retval;
+} // BOOLEAN IsGuid()
+
+// Return the GUID as a string, suitable for display to the user. Note that the calling
+// function is responsible for freeing the allocated memory.
+CHAR16 * GuidAsString(EFI_GUID *GuidData) {
+   CHAR16 *TheString;
+
+   TheString = AllocateZeroPool(42 * sizeof(CHAR16));
+   if (TheString != 0) {
+      SPrint (TheString, 82, L"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+              (UINTN)GuidData->Data1, (UINTN)GuidData->Data2, (UINTN)GuidData->Data3,
+              (UINTN)GuidData->Data4[0], (UINTN)GuidData->Data4[1], (UINTN)GuidData->Data4[2],
+              (UINTN)GuidData->Data4[3], (UINTN)GuidData->Data4[4], (UINTN)GuidData->Data4[5],
+              (UINTN)GuidData->Data4[6], (UINTN)GuidData->Data4[7]);
+   }
+   return TheString;
+} // GuidAsString(EFI_GUID *GuidData)
+
+EFI_GUID StringAsGuid(CHAR16 * InString) {
+    EFI_GUID  Guid = NULL_GUID_VALUE;
+
+    if (!IsGuid(InString)) {
+        return Guid;
+    }
+
+    Guid.Data1 = (UINT32) StrToHex(InString, 0, 8);
+    Guid.Data2 = (UINT16) StrToHex(InString, 9, 4);
+    Guid.Data3 = (UINT16) StrToHex(InString, 14, 4);
+    Guid.Data4[0] = (UINT8) StrToHex(InString, 19, 2);
+    Guid.Data4[1] = (UINT8) StrToHex(InString, 21, 2);
+    Guid.Data4[2] = (UINT8) StrToHex(InString, 23, 2);
+    Guid.Data4[3] = (UINT8) StrToHex(InString, 26, 2);
+    Guid.Data4[4] = (UINT8) StrToHex(InString, 28, 2);
+    Guid.Data4[5] = (UINT8) StrToHex(InString, 30, 2);
+    Guid.Data4[6] = (UINT8) StrToHex(InString, 32, 2);
+    Guid.Data4[7] = (UINT8) StrToHex(InString, 34, 2);
+
+    return Guid;
+} // EFI_GUID StringAsGuid()
diff --git a/refind/mystrings.h b/refind/mystrings.h
new file mode 100644 (file)
index 0000000..9b4faec
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * refit/mystrings.h
+ * String functions header file
+ *
+ * Copyright (c) 2012-2015 Roderick W. Smith
+ *
+ * Distributed under the terms of the GNU General Public License (GPL)
+ * version 3 (GPLv3), or (at your option) any later version.
+ *
+ */
+/*
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __MYSTRINGS_H_
+#define __MYSTRINGS_H_
+
+#ifdef __MAKEWITH_GNUEFI
+#include <efi.h>
+#include <efilib.h>
+#else
+#include "../include/tiano_includes.h"
+#endif
+#include "../EfiLib/GenericBdsLib.h"
+
+BOOLEAN StriSubCmp(IN CHAR16 *TargetStr, IN CHAR16 *BigStr);
+BOOLEAN MyStriCmp(IN CONST CHAR16 *String1, IN CONST CHAR16 *String2);
+CHAR16* MyStrStr (IN CHAR16  *String, IN CHAR16  *StrCharSet);
+VOID ToLower(CHAR16 * MyString);
+VOID MergeStrings(IN OUT CHAR16 **First, IN CHAR16 *Second, CHAR16 AddChar);
+VOID MergeWords(CHAR16 **MergeTo, CHAR16 *InString, CHAR16 AddChar);
+BOOLEAN LimitStringLength(CHAR16 *TheString, UINTN Limit);
+CHAR16 *FindNumbers(IN CHAR16 *InString);
+CHAR16 *FindCommaDelimited(IN CHAR16 *InString, IN UINTN Index);
+BOOLEAN IsIn(IN CHAR16 *SmallString, IN CHAR16 *List);
+BOOLEAN IsInSubstring(IN CHAR16 *BigString, IN CHAR16 *List);
+
+BOOLEAN IsValidHex(CHAR16 *Input);
+UINT64 StrToHex(CHAR16 *Input, UINTN Position, UINTN NumChars);
+BOOLEAN IsGuid(CHAR16 *UnknownString);
+CHAR16 * GuidAsString(EFI_GUID *GuidData);
+EFI_GUID StringAsGuid(CHAR16 * InString);
+
+
+#endif
\ No newline at end of file
diff --git a/refind/screen.c b/refind/screen.c
new file mode 100644 (file)
index 0000000..a408430
--- /dev/null
@@ -0,0 +1,599 @@
+/*
+ * refind/screen.c
+ * Screen handling functions
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Modifications copyright (c) 2012-2015 Roderick W. Smith
+ *
+ * Modifications distributed under the terms of the GNU General Public
+ * License (GPL) version 3 (GPLv3), or (at your option) any later version.
+ *
+ */
+/*
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "global.h"
+#include "screen.h"
+#include "config.h"
+#include "libegint.h"
+#include "lib.h"
+#include "menu.h"
+#include "../include/refit_call_wrapper.h"
+
+#include "../include/egemb_refind_banner.h"
+
+// Console defines and variables
+
+UINTN ConWidth;
+UINTN ConHeight;
+CHAR16 *BlankLine = NULL;
+
+// UGA defines and variables
+
+UINTN UGAWidth;
+UINTN UGAHeight;
+BOOLEAN AllowGraphicsMode;
+
+EG_PIXEL StdBackgroundPixel  = { 0xbf, 0xbf, 0xbf, 0 };
+EG_PIXEL MenuBackgroundPixel = { 0xbf, 0xbf, 0xbf, 0 };
+EG_PIXEL DarkBackgroundPixel = { 0x0, 0x0, 0x0, 0 };
+
+static BOOLEAN GraphicsScreenDirty;
+
+// general defines and variables
+
+static BOOLEAN haveError = FALSE;
+
+static VOID PrepareBlankLine(VOID) {
+    UINTN i;
+
+    MyFreePool(BlankLine);
+    // make a buffer for a whole text line
+    BlankLine = AllocatePool((ConWidth + 1) * sizeof(CHAR16));
+    for (i = 0; i < ConWidth; i++)
+        BlankLine[i] = ' ';
+    BlankLine[i] = 0;
+}
+
+//
+// Screen initialization and switching
+//
+
+VOID InitScreen(VOID)
+{
+    // initialize libeg
+    egInitScreen();
+
+    if (egHasGraphicsMode()) {
+        egGetScreenSize(&UGAWidth, &UGAHeight);
+        AllowGraphicsMode = TRUE;
+    } else {
+        AllowGraphicsMode = FALSE;
+        egSetTextMode(GlobalConfig.RequestedTextMode);
+        egSetGraphicsModeEnabled(FALSE);   // just to be sure we are in text mode
+    }
+    GraphicsScreenDirty = TRUE;
+
+    // disable cursor
+    refit_call2_wrapper(ST->ConOut->EnableCursor, ST->ConOut, FALSE);
+
+    // get size of text console
+    if (refit_call4_wrapper(ST->ConOut->QueryMode, ST->ConOut, ST->ConOut->Mode->Mode, &ConWidth, &ConHeight) != EFI_SUCCESS) {
+        // use default values on error
+        ConWidth = 80;
+        ConHeight = 25;
+    }
+
+    PrepareBlankLine();
+
+    // show the banner if in text mode
+    if (GlobalConfig.TextOnly && (GlobalConfig.ScreensaverTime != -1))
+       DrawScreenHeader(L"Initializing...");
+}
+
+// Set the screen resolution and mode (text vs. graphics).
+VOID SetupScreen(VOID)
+{
+    UINTN NewWidth, NewHeight;
+
+    // Convert mode number to horizontal & vertical resolution values
+    if ((GlobalConfig.RequestedScreenWidth > 0) && (GlobalConfig.RequestedScreenHeight == 0))
+       egGetResFromMode(&(GlobalConfig.RequestedScreenWidth), &(GlobalConfig.RequestedScreenHeight));
+
+    // Set the believed-to-be current resolution to the LOWER of the current
+    // believed-to-be resolution and the requested resolution. This is done to
+    // enable setting a lower-than-default resolution.
+    if ((GlobalConfig.RequestedScreenWidth > 0) && (GlobalConfig.RequestedScreenHeight > 0)) {
+       UGAWidth = (UGAWidth < GlobalConfig.RequestedScreenWidth) ? UGAWidth : GlobalConfig.RequestedScreenWidth;
+       UGAHeight = (UGAHeight < GlobalConfig.RequestedScreenHeight) ? UGAHeight : GlobalConfig.RequestedScreenHeight;
+    }
+
+    // Set text mode. If this requires increasing the size of the graphics mode, do so.
+    if (egSetTextMode(GlobalConfig.RequestedTextMode)) {
+       egGetScreenSize(&NewWidth, &NewHeight);
+       if ((NewWidth > UGAWidth) || (NewHeight > UGAHeight)) {
+          UGAWidth = NewWidth;
+          UGAHeight = NewHeight;
+       }
+       if ((UGAWidth > GlobalConfig.RequestedScreenWidth) || (UGAHeight > GlobalConfig.RequestedScreenHeight)) {
+           // Requested text mode forces us to use a bigger graphics mode
+           GlobalConfig.RequestedScreenWidth = UGAWidth;
+           GlobalConfig.RequestedScreenHeight = UGAHeight;
+       } // if
+    }
+
+    if (GlobalConfig.RequestedScreenWidth > 0) {
+       egSetScreenSize(&(GlobalConfig.RequestedScreenWidth), &(GlobalConfig.RequestedScreenHeight));
+       egGetScreenSize(&UGAWidth, &UGAHeight);
+    } // if user requested a particular screen resolution
+
+    if (GlobalConfig.TextOnly) {
+        // switch to text mode if requested
+        AllowGraphicsMode = FALSE;
+        SwitchToText(FALSE);
+
+    } else if (AllowGraphicsMode) {
+        // clear screen and show banner
+        // (now we know we'll stay in graphics mode)
+        SwitchToGraphics();
+        if (GlobalConfig.ScreensaverTime != -1) {
+           BltClearScreen(TRUE);
+        } else { // start with screen blanked
+           GraphicsScreenDirty = TRUE;
+        }
+    }
+} // VOID SetupScreen()
+
+VOID SwitchToText(IN BOOLEAN CursorEnabled)
+{
+    egSetGraphicsModeEnabled(FALSE);
+    refit_call2_wrapper(ST->ConOut->EnableCursor, ST->ConOut, CursorEnabled);
+    // get size of text console
+    if (refit_call4_wrapper(ST->ConOut->QueryMode, ST->ConOut, ST->ConOut->Mode->Mode, &ConWidth, &ConHeight) != EFI_SUCCESS) {
+        // use default values on error
+        ConWidth = 80;
+        ConHeight = 25;
+    }
+    PrepareBlankLine();
+}
+
+VOID SwitchToGraphics(VOID)
+{
+    if (AllowGraphicsMode && !egIsGraphicsModeEnabled()) {
+        egSetGraphicsModeEnabled(TRUE);
+        GraphicsScreenDirty = TRUE;
+    }
+}
+
+//
+// Screen control for running tools
+//
+
+VOID BeginTextScreen(IN CHAR16 *Title)
+{
+    DrawScreenHeader(Title);
+    SwitchToText(FALSE);
+
+    // reset error flag
+    haveError = FALSE;
+}
+
+VOID FinishTextScreen(IN BOOLEAN WaitAlways)
+{
+    if (haveError || WaitAlways) {
+       PauseForKey();
+       SwitchToText(FALSE);
+    }
+
+    // reset error flag
+    haveError = FALSE;
+}
+
+VOID BeginExternalScreen(IN BOOLEAN UseGraphicsMode, IN CHAR16 *Title)
+{
+    if (!AllowGraphicsMode)
+        UseGraphicsMode = FALSE;
+
+    if (UseGraphicsMode) {
+        SwitchToGraphics();
+        BltClearScreen(FALSE);
+    } else {
+        egClearScreen(&DarkBackgroundPixel);
+        DrawScreenHeader(Title);
+        SwitchToText(TRUE);
+    }
+
+    // reset error flag
+    haveError = FALSE;
+}
+
+VOID FinishExternalScreen(VOID)
+{
+    // make sure we clean up later
+    GraphicsScreenDirty = TRUE;
+
+    if (haveError) {
+        SwitchToText(FALSE);
+        PauseForKey();
+    }
+
+    // Reset the screen resolution, in case external program changed it....
+    SetupScreen();
+
+    // reset error flag
+    haveError = FALSE;
+}
+
+VOID TerminateScreen(VOID)
+{
+    // clear text screen
+    refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BASIC);
+    refit_call1_wrapper(ST->ConOut->ClearScreen, ST->ConOut);
+
+    // enable cursor
+    refit_call2_wrapper(ST->ConOut->EnableCursor, ST->ConOut, TRUE);
+}
+
+VOID DrawScreenHeader(IN CHAR16 *Title)
+{
+    UINTN y;
+
+    // clear to black background
+    egClearScreen(&DarkBackgroundPixel); // first clear in graphics mode
+    refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BASIC);
+    refit_call1_wrapper(ST->ConOut->ClearScreen, ST->ConOut); // then clear in text mode
+
+    // paint header background
+    refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BANNER);
+    for (y = 0; y < 3; y++) {
+        refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 0, y);
+        Print(BlankLine);
+    }
+
+    // print header text
+    refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 3, 1);
+    Print(L"rEFInd - %s", Title);
+
+    // reposition cursor
+    refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BASIC);
+    refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 0, 4);
+}
+
+//
+// Keyboard input
+//
+
+BOOLEAN ReadAllKeyStrokes(VOID)
+{
+    BOOLEAN       GotKeyStrokes;
+    EFI_STATUS    Status;
+    EFI_INPUT_KEY key;
+
+    GotKeyStrokes = FALSE;
+    for (;;) {
+        Status = refit_call2_wrapper(ST->ConIn->ReadKeyStroke, ST->ConIn, &key);
+        if (Status == EFI_SUCCESS) {
+            GotKeyStrokes = TRUE;
+            continue;
+        }
+        break;
+    }
+    return GotKeyStrokes;
+}
+
+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");
+}
+
+// Pause a specified number of seconds
+VOID PauseSeconds(UINTN Seconds) {
+     refit_call1_wrapper(BS->Stall, 1000000 * Seconds);
+} // VOID PauseSeconds()
+
+#if REFIT_DEBUG > 0
+VOID DebugPause(VOID)
+{
+    // show console and wait for key
+    SwitchToText(FALSE);
+    PauseForKey();
+
+    // reset error flag
+    haveError = FALSE;
+}
+#endif
+
+VOID EndlessIdleLoop(VOID)
+{
+    UINTN index;
+
+    for (;;) {
+        ReadAllKeyStrokes();
+        refit_call3_wrapper(BS->WaitForEvent, 1, &ST->ConIn->WaitForKey, &index);
+    }
+}
+
+//
+// Error handling
+//
+
+#ifdef __MAKEWITH_GNUEFI
+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;
+}
+#else
+BOOLEAN CheckFatalError(IN EFI_STATUS Status, IN CHAR16 *where)
+{
+//    CHAR16 ErrorName[64];
+
+    if (!EFI_ERROR(Status))
+        return FALSE;
+
+    gST->ConOut->SetAttribute (gST->ConOut, ATTR_ERROR);
+    Print(L"Fatal Error: %r %s\n", Status, where);
+    gST->ConOut->SetAttribute (gST->ConOut, ATTR_BASIC);
+    haveError = TRUE;
+
+    //gBS->Exit(ImageHandle, ExitStatus, ExitDataSize, ExitData);
+
+    return TRUE;
+}
+
+BOOLEAN CheckError(IN EFI_STATUS Status, IN CHAR16 *where)
+{
+    if (!EFI_ERROR(Status))
+        return FALSE;
+
+    gST->ConOut->SetAttribute (gST->ConOut, ATTR_ERROR);
+    Print(L"Error: %r %s\n", Status, where);
+    gST->ConOut->SetAttribute (gST->ConOut, ATTR_BASIC);
+    haveError = TRUE;
+
+    return TRUE;
+}
+#endif
+
+//
+// Graphics functions
+//
+
+VOID SwitchToGraphicsAndClear(VOID)
+{
+    SwitchToGraphics();
+    if (GraphicsScreenDirty)
+        BltClearScreen(TRUE);
+}
+
+VOID BltClearScreen(BOOLEAN ShowBanner)
+{
+    static EG_IMAGE *Banner = NULL;
+    EG_IMAGE *NewBanner = NULL;
+    INTN BannerPosX, BannerPosY;
+    EG_PIXEL Black = { 0x0, 0x0, 0x0, 0 };
+
+    if (ShowBanner && !(GlobalConfig.HideUIFlags & HIDEUI_FLAG_BANNER)) {
+        // load banner on first call
+        if (Banner == NULL) {
+            if (GlobalConfig.BannerFileName)
+                Banner = egLoadImage(SelfDir, GlobalConfig.BannerFileName, FALSE);
+            if (Banner == NULL)
+                Banner = egPrepareEmbeddedImage(&egemb_refind_banner, FALSE);
+        }
+
+        if (Banner) {
+           if (GlobalConfig.BannerScale == BANNER_FILLSCREEN) {
+              if ((Banner->Height != UGAHeight) || (Banner->Width != UGAWidth)) {
+                 NewBanner = egScaleImage(Banner, UGAWidth, UGAHeight);
+              } // if
+           } else if ((Banner->Width > UGAWidth) || (Banner->Height > UGAHeight)) {
+              NewBanner = egCropImage(Banner, 0, 0, (Banner->Width > UGAWidth) ? UGAWidth : Banner->Width,
+                                      (Banner->Height > UGAHeight) ? UGAHeight : Banner->Height);
+           } // if/elseif
+           if (NewBanner) {
+              MyFreePool(Banner);
+              Banner = NewBanner;
+           }
+           MenuBackgroundPixel = Banner->PixelData[0];
+        } // if Banner exists
+
+        // clear and draw banner
+        if (GlobalConfig.ScreensaverTime != -1)
+           egClearScreen(&MenuBackgroundPixel);
+        else
+           egClearScreen(&Black);
+
+        if (Banner != NULL) {
+            BannerPosX = (Banner->Width < UGAWidth) ? ((UGAWidth - Banner->Width) / 2) : 0;
+            BannerPosY = (INTN) (ComputeRow0PosY() / 2) - (INTN) Banner->Height;
+            if (BannerPosY < 0)
+               BannerPosY = 0;
+            GlobalConfig.BannerBottomEdge = BannerPosY + Banner->Height;
+            if (GlobalConfig.ScreensaverTime != -1)
+               BltImage(Banner, (UINTN) BannerPosX, (UINTN) BannerPosY);
+        }
+
+    } else { // not showing banner
+        // clear to menu background color
+        egClearScreen(&MenuBackgroundPixel);
+    }
+
+    GraphicsScreenDirty = FALSE;
+    egFreeImage(GlobalConfig.ScreenBackground);
+    GlobalConfig.ScreenBackground = egCopyScreen();
+} // VOID BltClearScreen()
+
+
+VOID BltImage(IN EG_IMAGE *Image, IN UINTN XPos, IN UINTN YPos)
+{
+    egDrawImage(Image, XPos, YPos);
+    GraphicsScreenDirty = TRUE;
+}
+
+VOID BltImageAlpha(IN EG_IMAGE *Image, IN UINTN XPos, IN UINTN YPos, IN EG_PIXEL *BackgroundPixel)
+{
+    EG_IMAGE *CompImage;
+
+    // compose on background
+    CompImage = egCreateFilledImage(Image->Width, Image->Height, FALSE, BackgroundPixel);
+    egComposeImage(CompImage, Image, 0, 0);
+
+    // blit to screen and clean up
+    egDrawImage(CompImage, XPos, YPos);
+    egFreeImage(CompImage);
+    GraphicsScreenDirty = TRUE;
+}
+
+// VOID BltImageComposite(IN EG_IMAGE *BaseImage, IN EG_IMAGE *TopImage, IN UINTN XPos, IN UINTN YPos)
+// {
+//     UINTN TotalWidth, TotalHeight, CompWidth, CompHeight, OffsetX, OffsetY;
+//     EG_IMAGE *CompImage;
+//     
+//     // initialize buffer with base image
+//     CompImage = egCopyImage(BaseImage);
+//     TotalWidth  = BaseImage->Width;
+//     TotalHeight = BaseImage->Height;
+//     
+//     // place the top image
+//     CompWidth = TopImage->Width;
+//     if (CompWidth > TotalWidth)
+//         CompWidth = TotalWidth;
+//     OffsetX = (TotalWidth - CompWidth) >> 1;
+//     CompHeight = TopImage->Height;
+//     if (CompHeight > TotalHeight)
+//         CompHeight = TotalHeight;
+//     OffsetY = (TotalHeight - CompHeight) >> 1;
+//     egComposeImage(CompImage, TopImage, OffsetX, OffsetY);
+//
+//     // blit to screen and clean up
+//     egDrawImage(CompImage, XPos, YPos);
+//     egFreeImage(CompImage);
+//     GraphicsScreenDirty = TRUE;
+// }
+
+VOID BltImageCompositeBadge(IN EG_IMAGE *BaseImage, IN EG_IMAGE *TopImage, IN EG_IMAGE *BadgeImage, IN UINTN XPos, IN UINTN YPos)
+{
+     UINTN TotalWidth = 0, TotalHeight = 0, CompWidth = 0, CompHeight = 0, OffsetX = 0, OffsetY = 0;
+     EG_IMAGE *CompImage = NULL;
+
+     // initialize buffer with base image
+     if (BaseImage != NULL) {
+         CompImage = egCopyImage(BaseImage);
+         TotalWidth  = BaseImage->Width;
+         TotalHeight = BaseImage->Height;
+     }
+
+     // place the top image
+     if ((TopImage != NULL) && (CompImage != NULL)) {
+         CompWidth = TopImage->Width;
+         if (CompWidth > TotalWidth)
+               CompWidth = TotalWidth;
+         OffsetX = (TotalWidth - CompWidth) >> 1;
+         CompHeight = TopImage->Height;
+         if (CompHeight > TotalHeight)
+               CompHeight = TotalHeight;
+         OffsetY = (TotalHeight - CompHeight) >> 1;
+         egComposeImage(CompImage, TopImage, OffsetX, OffsetY);
+     }
+
+     // place the badge image
+     if (BadgeImage != NULL && CompImage != NULL && (BadgeImage->Width + 8) < CompWidth && (BadgeImage->Height + 8) < CompHeight) {
+         OffsetX += CompWidth  - 8 - BadgeImage->Width;
+         OffsetY += CompHeight - 8 - BadgeImage->Height;
+         egComposeImage(CompImage, BadgeImage, OffsetX, OffsetY);
+     }
+
+     // blit to screen and clean up
+     if (CompImage != NULL) {
+         if (CompImage->HasAlpha)
+             egDrawImageWithTransparency(CompImage, NULL, XPos, YPos, CompImage->Width, CompImage->Height);
+         else
+             egDrawImage(CompImage, XPos, YPos);
+         egFreeImage(CompImage);
+         GraphicsScreenDirty = TRUE;
+     }
+}
diff --git a/refind/screen.h b/refind/screen.h
new file mode 100644 (file)
index 0000000..abe9bab
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * refit/screen.h
+ * Screen management header file
+ *
+ * Copyright (c) 2006-2009 Christoph Pfisterer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __SCREEN_H_
+#define __SCREEN_H_
+
+#ifdef __MAKEWITH_GNUEFI
+#include "efi.h"
+#include "efilib.h"
+#else
+#include "../include/tiano_includes.h"
+#endif
+
+#include "libeg.h"
+
+//
+// screen module
+//
+
+#define DONT_CHANGE_TEXT_MODE 1024 /* textmode # that's a code to not change the text mode */
+
+#define ATTR_BASIC (EFI_LIGHTGRAY | EFI_BACKGROUND_BLACK)
+#define ATTR_ERROR (EFI_YELLOW | EFI_BACKGROUND_BLACK)
+#define ATTR_BANNER (EFI_WHITE | EFI_BACKGROUND_BLUE)
+#define ATTR_CHOICE_BASIC ATTR_BASIC
+#define ATTR_CHOICE_CURRENT (EFI_WHITE | EFI_BACKGROUND_GREEN)
+#define ATTR_SCROLLARROW (EFI_LIGHTGREEN | EFI_BACKGROUND_BLACK)
+
+//#define LAYOUT_TEXT_WIDTH (512)
+//#define LAYOUT_TEXT_WIDTH (425)
+#define LAYOUT_BANNER_YGAP 32
+
+//#define FONT_CELL_WIDTH (7)
+//#define FONT_CELL_HEIGHT (12)
+
+extern UINTN ConWidth;
+extern UINTN ConHeight;
+extern CHAR16 *BlankLine;
+
+extern UINTN UGAWidth;
+extern UINTN UGAHeight;
+extern BOOLEAN AllowGraphicsMode;
+
+extern EG_PIXEL StdBackgroundPixel;
+extern EG_PIXEL MenuBackgroundPixel;
+
+VOID InitScreen(VOID);
+VOID SetupScreen(VOID);
+VOID BeginTextScreen(IN CHAR16 *Title);
+VOID FinishTextScreen(IN BOOLEAN WaitAlways);
+VOID BeginExternalScreen(IN BOOLEAN UseGraphicsMode, IN CHAR16 *Title);
+VOID FinishExternalScreen(VOID);
+VOID TerminateScreen(VOID);
+VOID DrawScreenHeader(IN CHAR16 *Title);
+
+#if REFIT_DEBUG > 0
+VOID DebugPause(VOID);
+#else
+#define DebugPause()
+#endif
+VOID EndlessIdleLoop(VOID);
+BOOLEAN ReadAllKeyStrokes(VOID);
+VOID PauseForKey(VOID);
+VOID PauseSeconds(UINTN Seconds);
+
+BOOLEAN CheckFatalError(IN EFI_STATUS Status, IN CHAR16 *where);
+BOOLEAN CheckError(IN EFI_STATUS Status, IN CHAR16 *where);
+
+VOID SwitchToText(IN BOOLEAN CursorEnabled);
+VOID SwitchToGraphics(VOID);
+
+VOID SwitchToGraphicsAndClear(VOID);
+VOID BltClearScreen(IN BOOLEAN ShowBanner);
+VOID BltImage(IN EG_IMAGE *Image, IN UINTN XPos, IN UINTN YPos);
+VOID BltImageAlpha(IN EG_IMAGE *Image, IN UINTN XPos, IN UINTN YPos, IN EG_PIXEL *BackgroundPixel);
+//VOID BltImageComposite(IN EG_IMAGE *BaseImage, IN EG_IMAGE *TopImage, IN UINTN XPos, IN UINTN YPos);
+VOID BltImageCompositeBadge(IN EG_IMAGE *BaseImage, IN EG_IMAGE *TopImage, IN EG_IMAGE *BadgeImage, IN UINTN XPos, IN UINTN YPos);
+
+#endif
diff --git a/themes/snowy/README.txt b/themes/snowy/README.txt
new file mode 100644 (file)
index 0000000..0271a16
--- /dev/null
@@ -0,0 +1,37 @@
+This is the Snowy theme for rEFInd (http://www.rodsbooks.com/refind/). To
+use it:
+
+1) Unpack the .zip file (which you've presumably already done).
+
+2) Copy the "snowy" subdirectory to your rEFInd installation. rEFInd can be
+   located various places, depending on your OS:
+   * On most Linux systems, the ESP is mounted at /boot/efi, so rEFInd is
+     at /boot/efi/EFI/refind.
+   * On OS X, if you haven't configured the ESP to auto-mount, you should
+     run the "mountesp" script that comes with rEFInd 0.10.0 and later.
+     This will mount the ESP, typically at /Volumes/ESP, so rEFInd will
+     probably be at /Volumes/ESP/EFI/refind.
+   * On Windows, the ESP is not mounted by default. In an Administrator
+     Command Prompt window, you can type "mountvol S: /S" to mount the ESP
+     as S:. (You can change the device letter, if necessary.) rEFInd should
+     then normally be S:\EFI\refind.
+
+3) Open the refind.conf file in the rEFInd directory in your favorite
+   text editor.
+
+4) Locate and change the following lines in refind.conf:
+   * icons_dir: Uncomment the sample or add a new line that reads "icons_dir
+     snowy".
+   * banner: Uncomment the sample or add a new line that reads
+     "banner-snowy.png".
+   * banner_scale: Uncomment the sample or add a new line that reads
+     "banner_scale fillscreen"
+
+You can swap out any element, including the banner/background image, as you
+see fit. The banner-snowy.png image is 1920x1080. If your display is
+another size, the image will be scaled to fit. If you see artifacts, or if
+your display does not use a 16:9 aspect ratio, you may want to load the
+file into a graphics editor to scale it or to crop it.
+
+This theme is derived from icons from several sources; see snowy/README for
+details.
diff --git a/themes/snowy/snowy/README b/themes/snowy/snowy/README
new file mode 100644 (file)
index 0000000..9c44a3e
--- /dev/null
@@ -0,0 +1,135 @@
+This directory holds icons used by rEFInd. This file describes their
+sources, both in overview and in file-by-file detail, and provides pointers
+to the relevant licenses under which the icons are distributed.
+
+Icon Sources (Overview)
+-----------------------
+
+- The AwOken 2.5 icon set
+  - Source: http://alecive.deviantart.com/art/AwOken-163570862
+  - Copyright (c) 2013 by Alessandro Roncone (aka alecive on DeviantArt)
+  - License: Creative Commons Attribution-Share Alike 3.0 (CC-SA 3.0)
+
+- Original work for rEFInd
+  - Source: https://sourceforge.net/p/refind (this archive)
+  - Copyright (c) 2015 by Roderick W. Smith
+  - License: LGPLv3+ or CC-SA 3.0
+
+- Debian OS icon
+  - Source: https://commons.wikimedia.org/wiki/File:Debian-OpenLogo.svg
+  - Copyright (c) 1999 Debian Project
+  - License: LGPLv3+ or CC-SA 3.0
+
+- Elementary OS icon
+  - Source: https://commons.wikimedia.org/wiki/File:Elementary_logo.svg
+  - Copyright (c) 2008 Dan Rabbit
+  - License: GPLv2+
+
+Some icons have been altered from their original forms -- normally
+conversion from SVG to PNG format, resizing, changes in coloration, or
+addition of "drop shadow" effects. Details follow....
+
+The "svg" subdirectory holds SVG versions of some icons (notably absent are
+those based on the AwOken icon set).
+
+Icon Sources (Detail)
+---------------------
+
+Icons unchanged from AwOken 2.5:
+
+arrow_left.png -- Aw0kenWhite/clear/128x128/actions/go-previous.png
+arrow_right.png -- Aw0kenWhite/clear/128x128/actions/go-next.png
+func_about.png -- Aw0kenWhite/clear/128x128/actions/info2.png
+func_exit.png -- Aw0kenWhite/clear/128x128/actions/application-exit2.png
+func_reset.png -- Aw0kenWhite/clear/128x128/apps/gnome-session-reboot2.png
+func_shutdown.png -- Aw0kenWhite/clear/128x128/apps/gnome-session-halt2.png
+os_arch.png -- Aw0kenWhite/clear/128x128/start-here/start-here-arch3.png
+os_centos.png -- Aw0kenWhite/clear/128x128/start-here/start-here-centos3.png
+os_chakra.png -- Aw0kenWhite/clear/128x128/start-here/start-here-chakra.png
+os_chrome.png -- Aw0kenWhite/clear/128x128/apps/google-chrome1.png
+os_crunchbang.png -- Aw0kenWhite/clear/128x128/start-here/start-here-crunchbang3.png
+os_fedora.png -- Aw0kenWhite/clear/128x128/start-here/start-here-fedora3.png
+os_frugalware.png -- Aw0kenWhite/clear/128x128/start-here/start-here-frugalware3.png
+os_gentoo.png -- Aw0kenWhite/clear/128x128/start-here/start-here-gentoo3.png
+os_hwtest.png -- AwOkenWhite/clear/128x128/apps/hw.png
+os_kubuntu.png -- Aw0kenWhite/clear/128x128/start-here/start-here-kubuntu1.png
+os_linuxmint.png -- Aw0kenWhite/clear/128x128/start-here/start-here-mint3.png
+os_linux.png -- Aw0kenWhite/clear/128x128/apps/supertux.png
+os_lubuntu.png -- Aw0kenWhite/clear/128x128/start-here/start-here-lubuntu1.png
+os_mageia.png -- Aw0kenWhite/clear/128x128/start-here/start-here-mageia1.png
+os_mandriva.png -- Aw0kenWhite/clear/128x128/start-here/start-here-mandriva3.png
+os_network.png -- Aw0kenWhite/clear/128x128/places/network-workgroup2.png
+os_opensuse.png -- Aw0kenWhite/clear/128x128/start-here/start-here-suse3.png
+os_slackware.png -- Aw0kenWhite/clear/128x128/start-here/start-here-slackware1.png
+os_suse.png -- Aw0kenWhite/clear/128x128/start-here/start-here-suse3.png
+os_ubuntu.png -- Aw0kenWhite/clear/128x128/start-here/start-here-ubuntu.png
+os_unknown.png -- AwOkenWhite/clear/128x128/actions/color-line2.png
+os_win8.png -- Aw0kenWhite/clear/128x128/apps/live1.png
+os_xubuntu.png -- Aw0kenWhite/clear/128x128/start-here/start-here-xubuntu1.png
+tool_mok_tool.png -- Aw0kenWhite/clear/128x128/apps/gnome-keyring-manager.png
+tool_netboot.png -- Aw0kenWhite/clear/128x128/places/network-workgroup2.png
+tool_shell.png -- Aw0kenWhite/clear/128x128/apps/terminal2.png
+vol_optical.png - Aw0kenWhite/clear/128x128/devices/media-optical-cd1.png
+
+
+Icons modified from AwOken 2.5:
+
+boot_linux.png -- Aw0ken/clear/128x128/apps/supertux.png
+func_firmware.png -- AwOkenWhite/clear/128x128/status/indicator-cpufreq.png
+vol_external.png -- AwOkenWhite/clear/128x128/devices/drive-removable-media-usb2.png
+vol_internal.png -- Aw0kenWhite/clear/128/128/drive-harddisk/Internal.png
+vol_net.png -- Aw0kenWhite/clear/128/128/drive-harddisk/Server.png
+
+
+Modified Elementary OS icon:
+
+os_elementary.png (GPLv2+)
+
+
+Modified Debian OS icon:
+
+os_debian.png (LGPLv3+ or CC-BY-SA 3.0)
+
+
+Banner and icons created by me (Roderick W. Smith):
+
+banner-snowy.png
+boot_win.png
+func_csr_rotate.png
+os_clover.png
+os_freebsd.png
+os_gummiboot.png
+os_haiku.png
+os_legacy.png
+os_mac.png
+os_netbsd.png
+os_redhat.png
+os_refind.png
+os_refit.png
+os_win.png
+tool_apple_rescue.png
+tool_memtest.png
+tool_rescue.png
+transparent.png
+
+
+In addition, some icons are combinations of two other icons from different
+sources:
+
+tool_part.png -- vol_internal.png with AwOken's gparted2.png
+tool_windows_rescue.png: os_win8.png with tool_rescue.png
+
+
+Licneses
+--------
+
+The "licenses" subdirectory contains the text of the relevant licenses:
+
+CC-SA 3.0: Creative Commons Legal Code.html
+           (See also https://creativecommons.org/licenses/by-sa/3.0/us/)
+
+GPLv2: gpl-2.0.txt
+       (see also https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
+
+LGPLv3: lgpl-3.0.txt
+        (see also http://www.gnu.org/licenses/lgpl-3.0.en.html)
diff --git a/themes/snowy/snowy/arrow_left.png b/themes/snowy/snowy/arrow_left.png
new file mode 100644 (file)
index 0000000..16aab53
Binary files /dev/null and b/themes/snowy/snowy/arrow_left.png differ
diff --git a/themes/snowy/snowy/arrow_right.png b/themes/snowy/snowy/arrow_right.png
new file mode 100644 (file)
index 0000000..b59f9ea
Binary files /dev/null and b/themes/snowy/snowy/arrow_right.png differ
diff --git a/themes/snowy/snowy/banner-snowy.png b/themes/snowy/snowy/banner-snowy.png
new file mode 100644 (file)
index 0000000..fbb4dc9
Binary files /dev/null and b/themes/snowy/snowy/banner-snowy.png differ
diff --git a/themes/snowy/snowy/boot_linux.png b/themes/snowy/snowy/boot_linux.png
new file mode 100644 (file)
index 0000000..4f52d7d
Binary files /dev/null and b/themes/snowy/snowy/boot_linux.png differ
diff --git a/themes/snowy/snowy/boot_win.png b/themes/snowy/snowy/boot_win.png
new file mode 100644 (file)
index 0000000..f86202c
Binary files /dev/null and b/themes/snowy/snowy/boot_win.png differ
diff --git a/themes/snowy/snowy/func_about.png b/themes/snowy/snowy/func_about.png
new file mode 100644 (file)
index 0000000..d2fea00
Binary files /dev/null and b/themes/snowy/snowy/func_about.png differ
diff --git a/themes/snowy/snowy/func_csr_rotate.png b/themes/snowy/snowy/func_csr_rotate.png
new file mode 100644 (file)
index 0000000..4d9c051
Binary files /dev/null and b/themes/snowy/snowy/func_csr_rotate.png differ
diff --git a/themes/snowy/snowy/func_exit.png b/themes/snowy/snowy/func_exit.png
new file mode 100644 (file)
index 0000000..708718a
Binary files /dev/null and b/themes/snowy/snowy/func_exit.png differ
diff --git a/themes/snowy/snowy/func_firmware.png b/themes/snowy/snowy/func_firmware.png
new file mode 100644 (file)
index 0000000..6960f50
Binary files /dev/null and b/themes/snowy/snowy/func_firmware.png differ
diff --git a/themes/snowy/snowy/func_reset.png b/themes/snowy/snowy/func_reset.png
new file mode 100644 (file)
index 0000000..3be378c
Binary files /dev/null and b/themes/snowy/snowy/func_reset.png differ
diff --git a/themes/snowy/snowy/func_shutdown.png b/themes/snowy/snowy/func_shutdown.png
new file mode 100644 (file)
index 0000000..0930dcb
Binary files /dev/null and b/themes/snowy/snowy/func_shutdown.png differ
diff --git a/themes/snowy/snowy/licenses/cc-3.0.txt b/themes/snowy/snowy/licenses/cc-3.0.txt
new file mode 100644 (file)
index 0000000..604209a
--- /dev/null
@@ -0,0 +1,359 @@
+Creative Commons Legal Code
+
+Attribution-ShareAlike 3.0 Unported
+
+    CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
+    LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN
+    ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
+    INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
+    REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR
+    DAMAGES RESULTING FROM ITS USE.
+
+License
+
+THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE
+COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY
+COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS
+AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.
+
+BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE
+TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY
+BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS
+CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND
+CONDITIONS.
+
+1. Definitions
+
+ a. "Adaptation" means a work based upon the Work, or upon the Work and
+    other pre-existing works, such as a translation, adaptation,
+    derivative work, arrangement of music or other alterations of a
+    literary or artistic work, or phonogram or performance and includes
+    cinematographic adaptations or any other form in which the Work may be
+    recast, transformed, or adapted including in any form recognizably
+    derived from the original, except that a work that constitutes a
+    Collection will not be considered an Adaptation for the purpose of
+    this License. For the avoidance of doubt, where the Work is a musical
+    work, performance or phonogram, the synchronization of the Work in
+    timed-relation with a moving image ("synching") will be considered an
+    Adaptation for the purpose of this License.
+ b. "Collection" means a collection of literary or artistic works, such as
+    encyclopedias and anthologies, or performances, phonograms or
+    broadcasts, or other works or subject matter other than works listed
+    in Section 1(f) below, which, by reason of the selection and
+    arrangement of their contents, constitute intellectual creations, in
+    which the Work is included in its entirety in unmodified form along
+    with one or more other contributions, each constituting separate and
+    independent works in themselves, which together are assembled into a
+    collective whole. A work that constitutes a Collection will not be
+    considered an Adaptation (as defined below) for the purposes of this
+    License.
+ c. "Creative Commons Compatible License" means a license that is listed
+    at https://creativecommons.org/compatiblelicenses that has been
+    approved by Creative Commons as being essentially equivalent to this
+    License, including, at a minimum, because that license: (i) contains
+    terms that have the same purpose, meaning and effect as the License
+    Elements of this License; and, (ii) explicitly permits the relicensing
+    of adaptations of works made available under that license under this
+    License or a Creative Commons jurisdiction license with the same
+    License Elements as this License.
+ d. "Distribute" means to make available to the public the original and
+    copies of the Work or Adaptation, as appropriate, through sale or
+    other transfer of ownership.
+ e. "License Elements" means the following high-level license attributes
+    as selected by Licensor and indicated in the title of this License:
+    Attribution, ShareAlike.
+ f. "Licensor" means the individual, individuals, entity or entities that
+    offer(s) the Work under the terms of this License.
+ g. "Original Author" means, in the case of a literary or artistic work,
+    the individual, individuals, entity or entities who created the Work
+    or if no individual or entity can be identified, the publisher; and in
+    addition (i) in the case of a performance the actors, singers,
+    musicians, dancers, and other persons who act, sing, deliver, declaim,
+    play in, interpret or otherwise perform literary or artistic works or
+    expressions of folklore; (ii) in the case of a phonogram the producer
+    being the person or legal entity who first fixes the sounds of a
+    performance or other sounds; and, (iii) in the case of broadcasts, the
+    organization that transmits the broadcast.
+ h. "Work" means the literary and/or artistic work offered under the terms
+    of this License including without limitation any production in the
+    literary, scientific and artistic domain, whatever may be the mode or
+    form of its expression including digital form, such as a book,
+    pamphlet and other writing; a lecture, address, sermon or other work
+    of the same nature; a dramatic or dramatico-musical work; a
+    choreographic work or entertainment in dumb show; a musical
+    composition with or without words; a cinematographic work to which are
+    assimilated works expressed by a process analogous to cinematography;
+    a work of drawing, painting, architecture, sculpture, engraving or
+    lithography; a photographic work to which are assimilated works
+    expressed by a process analogous to photography; a work of applied
+    art; an illustration, map, plan, sketch or three-dimensional work
+    relative to geography, topography, architecture or science; a
+    performance; a broadcast; a phonogram; a compilation of data to the
+    extent it is protected as a copyrightable work; or a work performed by
+    a variety or circus performer to the extent it is not otherwise
+    considered a literary or artistic work.
+ i. "You" means an individual or entity exercising rights under this
+    License who has not previously violated the terms of this License with
+    respect to the Work, or who has received express permission from the
+    Licensor to exercise rights under this License despite a previous
+    violation.
+ j. "Publicly Perform" means to perform public recitations of the Work and
+    to communicate to the public those public recitations, by any means or
+    process, including by wire or wireless means or public digital
+    performances; to make available to the public Works in such a way that
+    members of the public may access these Works from a place and at a
+    place individually chosen by them; to perform the Work to the public
+    by any means or process and the communication to the public of the
+    performances of the Work, including by public digital performance; to
+    broadcast and rebroadcast the Work by any means including signs,
+    sounds or images.
+ k. "Reproduce" means to make copies of the Work by any means including
+    without limitation by sound or visual recordings and the right of
+    fixation and reproducing fixations of the Work, including storage of a
+    protected performance or phonogram in digital form or other electronic
+    medium.
+
+2. Fair Dealing Rights. Nothing in this License is intended to reduce,
+limit, or restrict any uses free from copyright or rights arising from
+limitations or exceptions that are provided for in connection with the
+copyright protection under copyright law or other applicable laws.
+
+3. License Grant. Subject to the terms and conditions of this License,
+Licensor hereby grants You a worldwide, royalty-free, non-exclusive,
+perpetual (for the duration of the applicable copyright) license to
+exercise the rights in the Work as stated below:
+
+ a. to Reproduce the Work, to incorporate the Work into one or more
+    Collections, and to Reproduce the Work as incorporated in the
+    Collections;
+ b. to create and Reproduce Adaptations provided that any such Adaptation,
+    including any translation in any medium, takes reasonable steps to
+    clearly label, demarcate or otherwise identify that changes were made
+    to the original Work. For example, a translation could be marked "The
+    original work was translated from English to Spanish," or a
+    modification could indicate "The original work has been modified.";
+ c. to Distribute and Publicly Perform the Work including as incorporated
+    in Collections; and,
+ d. to Distribute and Publicly Perform Adaptations.
+ e. For the avoidance of doubt:
+
+     i. Non-waivable Compulsory License Schemes. In those jurisdictions in
+        which the right to collect royalties through any statutory or
+        compulsory licensing scheme cannot be waived, the Licensor
+        reserves the exclusive right to collect such royalties for any
+        exercise by You of the rights granted under this License;
+    ii. Waivable Compulsory License Schemes. In those jurisdictions in
+        which the right to collect royalties through any statutory or
+        compulsory licensing scheme can be waived, the Licensor waives the
+        exclusive right to collect such royalties for any exercise by You
+        of the rights granted under this License; and,
+   iii. Voluntary License Schemes. The Licensor waives the right to
+        collect royalties, whether individually or, in the event that the
+        Licensor is a member of a collecting society that administers
+        voluntary licensing schemes, via that society, from any exercise
+        by You of the rights granted under this License.
+
+The above rights may be exercised in all media and formats whether now
+known or hereafter devised. The above rights include the right to make
+such modifications as are technically necessary to exercise the rights in
+other media and formats. Subject to Section 8(f), all rights not expressly
+granted by Licensor are hereby reserved.
+
+4. Restrictions. The license granted in Section 3 above is expressly made
+subject to and limited by the following restrictions:
+
+ a. You may Distribute or Publicly Perform the Work only under the terms
+    of this License. You must include a copy of, or the Uniform Resource
+    Identifier (URI) for, this License with every copy of the Work You
+    Distribute or Publicly Perform. You may not offer or impose any terms
+    on the Work that restrict the terms of this License or the ability of
+    the recipient of the Work to exercise the rights granted to that
+    recipient under the terms of the License. You may not sublicense the
+    Work. You must keep intact all notices that refer to this License and
+    to the disclaimer of warranties with every copy of the Work You
+    Distribute or Publicly Perform. When You Distribute or Publicly
+    Perform the Work, You may not impose any effective technological
+    measures on the Work that restrict the ability of a recipient of the
+    Work from You to exercise the rights granted to that recipient under
+    the terms of the License. This Section 4(a) applies to the Work as
+    incorporated in a Collection, but this does not require the Collection
+    apart from the Work itself to be made subject to the terms of this
+    License. If You create a Collection, upon notice from any Licensor You
+    must, to the extent practicable, remove from the Collection any credit
+    as required by Section 4(c), as requested. If You create an
+    Adaptation, upon notice from any Licensor You must, to the extent
+    practicable, remove from the Adaptation any credit as required by
+    Section 4(c), as requested.
+ b. You may Distribute or Publicly Perform an Adaptation only under the
+    terms of: (i) this License; (ii) a later version of this License with
+    the same License Elements as this License; (iii) a Creative Commons
+    jurisdiction license (either this or a later license version) that
+    contains the same License Elements as this License (e.g.,
+    Attribution-ShareAlike 3.0 US)); (iv) a Creative Commons Compatible
+    License. If you license the Adaptation under one of the licenses
+    mentioned in (iv), you must comply with the terms of that license. If
+    you license the Adaptation under the terms of any of the licenses
+    mentioned in (i), (ii) or (iii) (the "Applicable License"), you must
+    comply with the terms of the Applicable License generally and the
+    following provisions: (I) You must include a copy of, or the URI for,
+    the Applicable License with every copy of each Adaptation You
+    Distribute or Publicly Perform; (II) You may not offer or impose any
+    terms on the Adaptation that restrict the terms of the Applicable
+    License or the ability of the recipient of the Adaptation to exercise
+    the rights granted to that recipient under the terms of the Applicable
+    License; (III) You must keep intact all notices that refer to the
+    Applicable License and to the disclaimer of warranties with every copy
+    of the Work as included in the Adaptation You Distribute or Publicly
+    Perform; (IV) when You Distribute or Publicly Perform the Adaptation,
+    You may not impose any effective technological measures on the
+    Adaptation that restrict the ability of a recipient of the Adaptation
+    from You to exercise the rights granted to that recipient under the
+    terms of the Applicable License. This Section 4(b) applies to the
+    Adaptation as incorporated in a Collection, but this does not require
+    the Collection apart from the Adaptation itself to be made subject to
+    the terms of the Applicable License.
+ c. If You Distribute, or Publicly Perform the Work or any Adaptations or
+    Collections, You must, unless a request has been made pursuant to
+    Section 4(a), keep intact all copyright notices for the Work and
+    provide, reasonable to the medium or means You are utilizing: (i) the
+    name of the Original Author (or pseudonym, if applicable) if supplied,
+    and/or if the Original Author and/or Licensor designate another party
+    or parties (e.g., a sponsor institute, publishing entity, journal) for
+    attribution ("Attribution Parties") in Licensor's copyright notice,
+    terms of service or by other reasonable means, the name of such party
+    or parties; (ii) the title of the Work if supplied; (iii) to the
+    extent reasonably practicable, the URI, if any, that Licensor
+    specifies to be associated with the Work, unless such URI does not
+    refer to the copyright notice or licensing information for the Work;
+    and (iv) , consistent with Ssection 3(b), in the case of an
+    Adaptation, a credit identifying the use of the Work in the Adaptation
+    (e.g., "French translation of the Work by Original Author," or
+    "Screenplay based on original Work by Original Author"). The credit
+    required by this Section 4(c) may be implemented in any reasonable
+    manner; provided, however, that in the case of a Adaptation or
+    Collection, at a minimum such credit will appear, if a credit for all
+    contributing authors of the Adaptation or Collection appears, then as
+    part of these credits and in a manner at least as prominent as the
+    credits for the other contributing authors. For the avoidance of
+    doubt, You may only use the credit required by this Section for the
+    purpose of attribution in the manner set out above and, by exercising
+    Your rights under this License, You may not implicitly or explicitly
+    assert or imply any connection with, sponsorship or endorsement by the
+    Original Author, Licensor and/or Attribution Parties, as appropriate,
+    of You or Your use of the Work, without the separate, express prior
+    written permission of the Original Author, Licensor and/or Attribution
+    Parties.
+ d. Except as otherwise agreed in writing by the Licensor or as may be
+    otherwise permitted by applicable law, if You Reproduce, Distribute or
+    Publicly Perform the Work either by itself or as part of any
+    Adaptations or Collections, You must not distort, mutilate, modify or
+    take other derogatory action in relation to the Work which would be
+    prejudicial to the Original Author's honor or reputation. Licensor
+    agrees that in those jurisdictions (e.g. Japan), in which any exercise
+    of the right granted in Section 3(b) of this License (the right to
+    make Adaptations) would be deemed to be a distortion, mutilation,
+    modification or other derogatory action prejudicial to the Original
+    Author's honor and reputation, the Licensor will waive or not assert,
+    as appropriate, this Section, to the fullest extent permitted by the
+    applicable national law, to enable You to reasonably exercise Your
+    right under Section 3(b) of this License (right to make Adaptations)
+    but not otherwise.
+
+5. Representations, Warranties and Disclaimer
+
+UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR
+OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY
+KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE,
+INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY,
+FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF
+LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS,
+WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION
+OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU.
+
+6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE
+LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR
+ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES
+ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS
+BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+7. Termination
+
+ a. This License and the rights granted hereunder will terminate
+    automatically upon any breach by You of the terms of this License.
+    Individuals or entities who have received Adaptations or Collections
+    from You under this License, however, will not have their licenses
+    terminated provided such individuals or entities remain in full
+    compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will
+    survive any termination of this License.
+ b. Subject to the above terms and conditions, the license granted here is
+    perpetual (for the duration of the applicable copyright in the Work).
+    Notwithstanding the above, Licensor reserves the right to release the
+    Work under different license terms or to stop distributing the Work at
+    any time; provided, however that any such election will not serve to
+    withdraw this License (or any other license that has been, or is
+    required to be, granted under the terms of this License), and this
+    License will continue in full force and effect unless terminated as
+    stated above.
+
+8. Miscellaneous
+
+ a. Each time You Distribute or Publicly Perform the Work or a Collection,
+    the Licensor offers to the recipient a license to the Work on the same
+    terms and conditions as the license granted to You under this License.
+ b. Each time You Distribute or Publicly Perform an Adaptation, Licensor
+    offers to the recipient a license to the original Work on the same
+    terms and conditions as the license granted to You under this License.
+ c. If any provision of this License is invalid or unenforceable under
+    applicable law, it shall not affect the validity or enforceability of
+    the remainder of the terms of this License, and without further action
+    by the parties to this agreement, such provision shall be reformed to
+    the minimum extent necessary to make such provision valid and
+    enforceable.
+ d. No term or provision of this License shall be deemed waived and no
+    breach consented to unless such waiver or consent shall be in writing
+    and signed by the party to be charged with such waiver or consent.
+ e. This License constitutes the entire agreement between the parties with
+    respect to the Work licensed here. There are no understandings,
+    agreements or representations with respect to the Work not specified
+    here. Licensor shall not be bound by any additional provisions that
+    may appear in any communication from You. This License may not be
+    modified without the mutual written agreement of the Licensor and You.
+ f. The rights granted under, and the subject matter referenced, in this
+    License were drafted utilizing the terminology of the Berne Convention
+    for the Protection of Literary and Artistic Works (as amended on
+    September 28, 1979), the Rome Convention of 1961, the WIPO Copyright
+    Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996
+    and the Universal Copyright Convention (as revised on July 24, 1971).
+    These rights and subject matter take effect in the relevant
+    jurisdiction in which the License terms are sought to be enforced
+    according to the corresponding provisions of the implementation of
+    those treaty provisions in the applicable national law. If the
+    standard suite of rights granted under applicable copyright law
+    includes additional rights not granted under this License, such
+    additional rights are deemed to be included in the License; this
+    License is not intended to restrict the license of any rights under
+    applicable law.
+
+
+Creative Commons Notice
+
+    Creative Commons is not a party to this License, and makes no warranty
+    whatsoever in connection with the Work. Creative Commons will not be
+    liable to You or any party on any legal theory for any damages
+    whatsoever, including without limitation any general, special,
+    incidental or consequential damages arising in connection to this
+    license. Notwithstanding the foregoing two (2) sentences, if Creative
+    Commons has expressly identified itself as the Licensor hereunder, it
+    shall have all rights and obligations of Licensor.
+
+    Except for the limited purpose of indicating to the public that the
+    Work is licensed under the CCPL, Creative Commons does not authorize
+    the use by either party of the trademark "Creative Commons" or any
+    related trademark or logo of Creative Commons without the prior
+    written consent of Creative Commons. Any permitted use will be in
+    compliance with Creative Commons' then-current trademark usage
+    guidelines, as may be published on its website or otherwise made
+    available upon request from time to time. For the avoidance of doubt,
+    this trademark restriction does not form part of the License.
+
+    Creative Commons may be contacted at https://creativecommons.org/.
diff --git a/themes/snowy/snowy/licenses/lgpl-3.0.txt b/themes/snowy/snowy/licenses/lgpl-3.0.txt
new file mode 100644 (file)
index 0000000..65c5ca8
--- /dev/null
@@ -0,0 +1,165 @@
+                   GNU LESSER GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+  This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+  0. Additional Definitions.
+
+  As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+  "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+  An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+  A "Combined Work" is a work produced by combining or linking an
+Application with the Library.  The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+  The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+  The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+  1. Exception to Section 3 of the GNU GPL.
+
+  You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+  2. Conveying Modified Versions.
+
+  If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+   a) under this License, provided that you make a good faith effort to
+   ensure that, in the event an Application does not supply the
+   function or data, the facility still operates, and performs
+   whatever part of its purpose remains meaningful, or
+
+   b) under the GNU GPL, with none of the additional permissions of
+   this License applicable to that copy.
+
+  3. Object Code Incorporating Material from Library Header Files.
+
+  The object code form of an Application may incorporate material from
+a header file that is part of the Library.  You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+   a) Give prominent notice with each copy of the object code that the
+   Library is used in it and that the Library and its use are
+   covered by this License.
+
+   b) Accompany the object code with a copy of the GNU GPL and this license
+   document.
+
+  4. Combined Works.
+
+  You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+   a) Give prominent notice with each copy of the Combined Work that
+   the Library is used in it and that the Library and its use are
+   covered by this License.
+
+   b) Accompany the Combined Work with a copy of the GNU GPL and this license
+   document.
+
+   c) For a Combined Work that displays copyright notices during
+   execution, include the copyright notice for the Library among
+   these notices, as well as a reference directing the user to the
+   copies of the GNU GPL and this license document.
+
+   d) Do one of the following:
+
+       0) Convey the Minimal Corresponding Source under the terms of this
+       License, and the Corresponding Application Code in a form
+       suitable for, and under terms that permit, the user to
+       recombine or relink the Application with a modified version of
+       the Linked Version to produce a modified Combined Work, in the
+       manner specified by section 6 of the GNU GPL for conveying
+       Corresponding Source.
+
+       1) Use a suitable shared library mechanism for linking with the
+       Library.  A suitable mechanism is one that (a) uses at run time
+       a copy of the Library already present on the user's computer
+       system, and (b) will operate properly with a modified version
+       of the Library that is interface-compatible with the Linked
+       Version.
+
+   e) Provide Installation Information, but only if you would otherwise
+   be required to provide such information under section 6 of the
+   GNU GPL, and only to the extent that such information is
+   necessary to install and execute a modified version of the
+   Combined Work produced by recombining or relinking the
+   Application with a modified version of the Linked Version. (If
+   you use option 4d0, the Installation Information must accompany
+   the Minimal Corresponding Source and Corresponding Application
+   Code. If you use option 4d1, you must provide the Installation
+   Information in the manner specified by section 6 of the GNU GPL
+   for conveying Corresponding Source.)
+
+  5. Combined Libraries.
+
+  You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+   a) Accompany the combined library with a copy of the same work based
+   on the Library, uncombined with any other library facilities,
+   conveyed under the terms of this License.
+
+   b) Give prominent notice with the combined library that part of it
+   is a work based on the Library, and explaining where to find the
+   accompanying uncombined form of the same work.
+
+  6. Revised Versions of the GNU Lesser General Public License.
+
+  The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+  Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+  If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
diff --git a/themes/snowy/snowy/os_arch.png b/themes/snowy/snowy/os_arch.png
new file mode 100644 (file)
index 0000000..797a76a
Binary files /dev/null and b/themes/snowy/snowy/os_arch.png differ
diff --git a/themes/snowy/snowy/os_centos.png b/themes/snowy/snowy/os_centos.png
new file mode 100644 (file)
index 0000000..be7ee19
Binary files /dev/null and b/themes/snowy/snowy/os_centos.png differ
diff --git a/themes/snowy/snowy/os_chakra.png b/themes/snowy/snowy/os_chakra.png
new file mode 100644 (file)
index 0000000..f3619df
Binary files /dev/null and b/themes/snowy/snowy/os_chakra.png differ
diff --git a/themes/snowy/snowy/os_chrome.png b/themes/snowy/snowy/os_chrome.png
new file mode 100644 (file)
index 0000000..8ba3f6f
Binary files /dev/null and b/themes/snowy/snowy/os_chrome.png differ
diff --git a/themes/snowy/snowy/os_clover.png b/themes/snowy/snowy/os_clover.png
new file mode 100644 (file)
index 0000000..3ada7fc
Binary files /dev/null and b/themes/snowy/snowy/os_clover.png differ
diff --git a/themes/snowy/snowy/os_crunchbang.png b/themes/snowy/snowy/os_crunchbang.png
new file mode 100644 (file)
index 0000000..36d0f75
Binary files /dev/null and b/themes/snowy/snowy/os_crunchbang.png differ
diff --git a/themes/snowy/snowy/os_debian.png b/themes/snowy/snowy/os_debian.png
new file mode 100644 (file)
index 0000000..8a4823c
Binary files /dev/null and b/themes/snowy/snowy/os_debian.png differ
diff --git a/themes/snowy/snowy/os_elementary.png b/themes/snowy/snowy/os_elementary.png
new file mode 100644 (file)
index 0000000..ea4fed2
Binary files /dev/null and b/themes/snowy/snowy/os_elementary.png differ
diff --git a/themes/snowy/snowy/os_fedora.png b/themes/snowy/snowy/os_fedora.png
new file mode 100644 (file)
index 0000000..1887b66
Binary files /dev/null and b/themes/snowy/snowy/os_fedora.png differ
diff --git a/themes/snowy/snowy/os_freebsd.png b/themes/snowy/snowy/os_freebsd.png
new file mode 100644 (file)
index 0000000..641b6c8
Binary files /dev/null and b/themes/snowy/snowy/os_freebsd.png differ
diff --git a/themes/snowy/snowy/os_frugalware.png b/themes/snowy/snowy/os_frugalware.png
new file mode 100644 (file)
index 0000000..3c2d0a9
Binary files /dev/null and b/themes/snowy/snowy/os_frugalware.png differ
diff --git a/themes/snowy/snowy/os_gentoo.png b/themes/snowy/snowy/os_gentoo.png
new file mode 100644 (file)
index 0000000..e006b49
Binary files /dev/null and b/themes/snowy/snowy/os_gentoo.png differ
diff --git a/themes/snowy/snowy/os_gummiboot.png b/themes/snowy/snowy/os_gummiboot.png
new file mode 100644 (file)
index 0000000..eb18931
Binary files /dev/null and b/themes/snowy/snowy/os_gummiboot.png differ
diff --git a/themes/snowy/snowy/os_haiku.png b/themes/snowy/snowy/os_haiku.png
new file mode 100644 (file)
index 0000000..67ee5df
Binary files /dev/null and b/themes/snowy/snowy/os_haiku.png differ
diff --git a/themes/snowy/snowy/os_hwtest.png b/themes/snowy/snowy/os_hwtest.png
new file mode 100644 (file)
index 0000000..f26d900
Binary files /dev/null and b/themes/snowy/snowy/os_hwtest.png differ
diff --git a/themes/snowy/snowy/os_kubuntu.png b/themes/snowy/snowy/os_kubuntu.png
new file mode 100644 (file)
index 0000000..8a78b9a
Binary files /dev/null and b/themes/snowy/snowy/os_kubuntu.png differ
diff --git a/themes/snowy/snowy/os_legacy.png b/themes/snowy/snowy/os_legacy.png
new file mode 100644 (file)
index 0000000..0033a95
Binary files /dev/null and b/themes/snowy/snowy/os_legacy.png differ
diff --git a/themes/snowy/snowy/os_linux.png b/themes/snowy/snowy/os_linux.png
new file mode 100644 (file)
index 0000000..5aae3a3
Binary files /dev/null and b/themes/snowy/snowy/os_linux.png differ
diff --git a/themes/snowy/snowy/os_linuxmint.png b/themes/snowy/snowy/os_linuxmint.png
new file mode 100644 (file)
index 0000000..c9d83cd
Binary files /dev/null and b/themes/snowy/snowy/os_linuxmint.png differ
diff --git a/themes/snowy/snowy/os_lubuntu.png b/themes/snowy/snowy/os_lubuntu.png
new file mode 100644 (file)
index 0000000..dddee2a
Binary files /dev/null and b/themes/snowy/snowy/os_lubuntu.png differ
diff --git a/themes/snowy/snowy/os_mac.png b/themes/snowy/snowy/os_mac.png
new file mode 100644 (file)
index 0000000..bb03018
Binary files /dev/null and b/themes/snowy/snowy/os_mac.png differ
diff --git a/themes/snowy/snowy/os_mageia.png b/themes/snowy/snowy/os_mageia.png
new file mode 100644 (file)
index 0000000..caf9517
Binary files /dev/null and b/themes/snowy/snowy/os_mageia.png differ
diff --git a/themes/snowy/snowy/os_mandriva.png b/themes/snowy/snowy/os_mandriva.png
new file mode 100644 (file)
index 0000000..f6e14ec
Binary files /dev/null and b/themes/snowy/snowy/os_mandriva.png differ
diff --git a/themes/snowy/snowy/os_netbsd.png b/themes/snowy/snowy/os_netbsd.png
new file mode 100644 (file)
index 0000000..16d1b59
Binary files /dev/null and b/themes/snowy/snowy/os_netbsd.png differ
diff --git a/themes/snowy/snowy/os_network.png b/themes/snowy/snowy/os_network.png
new file mode 100644 (file)
index 0000000..c63c278
Binary files /dev/null and b/themes/snowy/snowy/os_network.png differ
diff --git a/themes/snowy/snowy/os_opensuse.png b/themes/snowy/snowy/os_opensuse.png
new file mode 100644 (file)
index 0000000..2deea58
Binary files /dev/null and b/themes/snowy/snowy/os_opensuse.png differ
diff --git a/themes/snowy/snowy/os_redhat.png b/themes/snowy/snowy/os_redhat.png
new file mode 100644 (file)
index 0000000..a3206ac
Binary files /dev/null and b/themes/snowy/snowy/os_redhat.png differ
diff --git a/themes/snowy/snowy/os_refind.png b/themes/snowy/snowy/os_refind.png
new file mode 100644 (file)
index 0000000..3d97fb2
Binary files /dev/null and b/themes/snowy/snowy/os_refind.png differ
diff --git a/themes/snowy/snowy/os_refit.png b/themes/snowy/snowy/os_refit.png
new file mode 100644 (file)
index 0000000..6e20ae0
Binary files /dev/null and b/themes/snowy/snowy/os_refit.png differ
diff --git a/themes/snowy/snowy/os_slackware.png b/themes/snowy/snowy/os_slackware.png
new file mode 100644 (file)
index 0000000..51b88a2
Binary files /dev/null and b/themes/snowy/snowy/os_slackware.png differ
diff --git a/themes/snowy/snowy/os_suse.png b/themes/snowy/snowy/os_suse.png
new file mode 100644 (file)
index 0000000..2deea58
Binary files /dev/null and b/themes/snowy/snowy/os_suse.png differ
diff --git a/themes/snowy/snowy/os_ubuntu.png b/themes/snowy/snowy/os_ubuntu.png
new file mode 100644 (file)
index 0000000..164d604
Binary files /dev/null and b/themes/snowy/snowy/os_ubuntu.png differ
diff --git a/themes/snowy/snowy/os_unknown.png b/themes/snowy/snowy/os_unknown.png
new file mode 100644 (file)
index 0000000..39b319d
Binary files /dev/null and b/themes/snowy/snowy/os_unknown.png differ
diff --git a/themes/snowy/snowy/os_win.png b/themes/snowy/snowy/os_win.png
new file mode 100644 (file)
index 0000000..f6aa4f2
Binary files /dev/null and b/themes/snowy/snowy/os_win.png differ
diff --git a/themes/snowy/snowy/os_win8.png b/themes/snowy/snowy/os_win8.png
new file mode 100644 (file)
index 0000000..564305e
Binary files /dev/null and b/themes/snowy/snowy/os_win8.png differ
diff --git a/themes/snowy/snowy/os_xubuntu.png b/themes/snowy/snowy/os_xubuntu.png
new file mode 100644 (file)
index 0000000..6286597
Binary files /dev/null and b/themes/snowy/snowy/os_xubuntu.png differ
diff --git a/themes/snowy/snowy/svg/arrow_left.svg b/themes/snowy/snowy/svg/arrow_left.svg
new file mode 100644 (file)
index 0000000..5e2218f
--- /dev/null
@@ -0,0 +1,109 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="48px"
+   height="48px"
+   id="svg3613"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="arrow_left-02-color.svg"
+   inkscape:export-filename="/home/rodsmith/programming/refind/current/icons-build/arrow_left-color.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90">
+  <defs
+     id="defs3615">
+    <filter
+       id="filter3720"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood3722"
+         flood-opacity="0.7"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite3724"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur3726"
+         in="composite"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset3728"
+         dx="3"
+         dy="3"
+         result="offset" />
+      <feComposite
+         id="feComposite3730"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="7"
+     inkscape:cx="1.2142857"
+     inkscape:cy="24"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:grid-bbox="true"
+     inkscape:document-units="px"
+     inkscape:window-width="1160"
+     inkscape:window-height="866"
+     inkscape:window-x="252"
+     inkscape:window-y="92"
+     inkscape:window-maximized="0" />
+  <metadata
+     id="metadata3618">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer">
+    <path
+       sodipodi:type="star"
+       style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.10000000000000001;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;filter:url(#filter3720)"
+       id="path3625"
+       sodipodi:sides="3"
+       sodipodi:cx="11.857143"
+       sodipodi:cy="12"
+       sodipodi:r1="20.380564"
+       sodipodi:r2="10.190284"
+       sodipodi:arg1="2.0943951"
+       sodipodi:arg2="3.1415927"
+       inkscape:flatsided="false"
+       inkscape:rounded="0"
+       inkscape:randomized="0"
+       d="M 1.6668616,29.650086 1.6668596,12 1.6668615,-5.6500859 16.952286,3.1749556 32.237707,12 16.952285,20.825045 z"
+       inkscape:transform-center-x="5.9581092"
+       transform="matrix(-1.1693711,0,0,1.1693711,43.82351,9.9675468)" />
+  </g>
+</svg>
diff --git a/themes/snowy/snowy/svg/arrow_right.svg b/themes/snowy/snowy/svg/arrow_right.svg
new file mode 100644 (file)
index 0000000..8f90cba
--- /dev/null
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="48px"
+   height="48px"
+   id="svg3613"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="arrow_right-02-color.svg">
+  <defs
+     id="defs3615">
+    <filter
+       id="filter3670"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood3672"
+         flood-opacity="0.7"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite3674"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur3676"
+         in="composite"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset3678"
+         dx="3"
+         dy="3"
+         result="offset" />
+      <feComposite
+         id="feComposite3680"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="7"
+     inkscape:cx="1.2142857"
+     inkscape:cy="24"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:grid-bbox="true"
+     inkscape:document-units="px"
+     inkscape:window-width="1160"
+     inkscape:window-height="866"
+     inkscape:window-x="553"
+     inkscape:window-y="89"
+     inkscape:window-maximized="0" />
+  <metadata
+     id="metadata3618">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer">
+    <path
+       sodipodi:type="star"
+       style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.10000000000000001;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;filter:url(#filter3670)"
+       id="path3625"
+       sodipodi:sides="3"
+       sodipodi:cx="11.857143"
+       sodipodi:cy="12"
+       sodipodi:r1="20.380564"
+       sodipodi:r2="10.190284"
+       sodipodi:arg1="2.0943951"
+       sodipodi:arg2="3.1415927"
+       inkscape:flatsided="false"
+       inkscape:rounded="0"
+       inkscape:randomized="0"
+       d="M 1.6668616,29.650086 1.6668596,12 1.6668615,-5.6500859 16.952286,3.1749556 32.237707,12 16.952285,20.825045 z"
+       inkscape:transform-center-x="-5.9581089"
+       transform="matrix(1.1693711,0,0,1.1693711,4.1764897,9.9675468)" />
+  </g>
+</svg>
diff --git a/themes/snowy/snowy/svg/boot_win.svg b/themes/snowy/snowy/svg/boot_win.svg
new file mode 100644 (file)
index 0000000..cf85b84
--- /dev/null
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="128"
+   height="128"
+   id="svg9607"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="os_win-02-white.svg"
+   inkscape:export-filename="/home/rodsmith/programming/refind/current/icons-build/svg/os_win-white.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90">
+  <defs
+     id="defs9609" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#bfbfbf"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="1"
+     inkscape:pageshadow="2"
+     inkscape:zoom="4.9497475"
+     inkscape:cx="64.652322"
+     inkscape:cy="66.261588"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:grid-bbox="true"
+     inkscape:document-units="px"
+     inkscape:window-width="1104"
+     inkscape:window-height="885"
+     inkscape:window-x="459"
+     inkscape:window-y="32"
+     inkscape:window-maximized="0" />
+  <metadata
+     id="metadata9612">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     transform="translate(0,80)">
+    <g
+       id="g9738"
+       transform="translate(-0.2020298,-0.90913682)"
+       style="fill:#737373;stroke:#737373;fill-opacity:1;stroke-opacity:1">
+      <path
+         sodipodi:nodetypes="ccccc"
+         inkscape:connector-curvature="0"
+         id="rect9615"
+         d="m 4.7203518,-11.741735 c 12.0209472,-14.272787 44.5029732,-16.021563 56.1714892,0 l 0,43.560551 c -13.716554,-12.936189 -38.510159,-14.30236 -56.1714892,0 z"
+         style="fill:#737373;fill-opacity:1;stroke:#737373;stroke-width:1.17263913000000009;stroke-opacity:1" />
+      <path
+         sodipodi:nodetypes="ccccc"
+         inkscape:connector-curvature="0"
+         id="rect9615-6"
+         d="m 4.6350396,-64.86804 c 12.0209444,-14.272787 44.5029724,-16.021562 56.1714884,0 l 0,43.560551 c -12.154227,-12.865477 -36.38669,-14.364515 -56.1714884,0 z"
+         style="fill:#737373;fill-opacity:1;stroke:#737373;stroke-width:1.17263913000000009;stroke-opacity:1" />
+      <path
+         sodipodi:nodetypes="ccccc"
+         inkscape:connector-curvature="0"
+         id="rect9615-6-7"
+         d="m 67.538565,-17.822259 c 12.020945,14.2727869 44.502975,16.0215625 56.171495,0 l 0,-43.56055 c -12.15423,12.865476 -36.386696,14.364514 -56.171495,0 z"
+         style="fill:#737373;fill-opacity:1;stroke:#737373;stroke-width:1.17263913000000009;stroke-opacity:1" />
+      <path
+         sodipodi:nodetypes="ccccc"
+         inkscape:connector-curvature="0"
+         id="rect9615-6-7-5"
+         d="m 67.597521,34.686314 c 12.020945,14.272786 44.502979,16.021562 56.171499,0 l 0,-43.5605509 c -12.15423,12.8654779 -36.386701,14.3645156 -56.171499,0 z"
+         style="fill:#737373;fill-opacity:1;stroke:#737373;stroke-width:1.17263913000000009;stroke-opacity:1" />
+    </g>
+  </g>
+</svg>
diff --git a/themes/snowy/snowy/svg/func_csr_rotate.svg b/themes/snowy/snowy/svg/func_csr_rotate.svg
new file mode 100644 (file)
index 0000000..4b2a114
--- /dev/null
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="48"
+   height="48"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="func_sip-02-color.svg"
+   inkscape:export-filename="/home/rodsmith/programming/refind/current/icons-build/func_sip-white.png"
+   inkscape:export-xdpi="33.75"
+   inkscape:export-ydpi="33.75">
+  <defs
+     id="defs4">
+    <filter
+       id="filter3838"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood3840"
+         flood-opacity="0.7"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite3842"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur3844"
+         in="composite"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset3846"
+         dx="3"
+         dy="3"
+         result="offset" />
+      <feComposite
+         id="feComposite3848"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="7.9195959"
+     inkscape:cx="14.078998"
+     inkscape:cy="30.823184"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:window-width="1061"
+     inkscape:window-height="863"
+     inkscape:window-x="447"
+     inkscape:window-y="84"
+     inkscape:window-maximized="0" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(0,-1004.3622)">
+    <path
+       style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.03846657000000000;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;filter:url(#filter3838)"
+       d="m 21.57976,1047.861 c -0.544952,-0.2595 -1.77118,-0.9766 -2.724951,-1.5938 -8.114061,-5.2503 -13.8035913,-13.1805 -16.2965633,-22.7141 -0.4860218,-1.8587 -1.1295245,-5.9882 -1.1295245,-7.2487 l 0,-0.9563 0.8926568,0.1543 c 1.4854374,0.256 4.7318491,0.194 6.6192884,-0.1263 5.1768806,-0.8793 10.1276286,-3.82 13.5012376,-8.0194 l 0.5985,-0.745 0.598501,0.745 c 1.159672,1.4435 3.082847,3.246 4.590378,4.3025 4.149538,2.9078 8.617368,4.2016 13.712581,3.9712 l 2.356571,-0.1063 -0.116147,1.1115 c -0.547261,5.2373 -1.512962,9.0558 -3.358489,13.2801 -2.731316,6.2519 -7.907289,12.3599 -13.616767,16.069 -1.736654,1.1282 -4.061083,2.3759 -4.396844,2.36 -0.131774,0 -0.685472,-0.2236 -1.230425,-0.4829 l 0,0 z"
+       id="path3817"
+       inkscape:connector-curvature="0" />
+  </g>
+</svg>
diff --git a/themes/snowy/snowy/svg/os_clover.svg b/themes/snowy/snowy/svg/os_clover.svg
new file mode 100644 (file)
index 0000000..6493909
--- /dev/null
@@ -0,0 +1,420 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="128"
+   height="128"
+   id="svg15332"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="os_clover-02-color.svg"
+   inkscape:export-filename="/home/rodsmith/programming/refind/current/icons-build/os_clover-color.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90">
+  <defs
+     id="defs15334">
+    <inkscape:path-effect
+       effect="skeletal"
+       id="path-effect15588"
+       is_visible="true"
+       pattern="m -48.597521,-31.744248 10,5 0,-10 z"
+       copytype="single_stretched"
+       prop_scale="1"
+       scale_y_rel="false"
+       spacing="0"
+       normal_offset="0"
+       tang_offset="0"
+       prop_units="false"
+       vertical_pattern="false"
+       fuse_tolerance="0" />
+    <inkscape:path-effect
+       effect="skeletal"
+       id="path-effect15584"
+       is_visible="true"
+       pattern="M 0,5 10,10 10,0 z"
+       copytype="single_stretched"
+       prop_scale="1"
+       scale_y_rel="false"
+       spacing="0"
+       normal_offset="0"
+       tang_offset="0"
+       prop_units="false"
+       vertical_pattern="false"
+       fuse_tolerance="0" />
+    <inkscape:path-effect
+       effect="skeletal"
+       id="path-effect15580"
+       is_visible="true"
+       pattern="M 0,5 10,10 10,0 z"
+       copytype="single_stretched"
+       prop_scale="1"
+       scale_y_rel="false"
+       spacing="0"
+       normal_offset="0"
+       tang_offset="0"
+       prop_units="false"
+       vertical_pattern="false"
+       fuse_tolerance="0" />
+    <inkscape:path-effect
+       effect="skeletal"
+       id="path-effect15576"
+       is_visible="true"
+       pattern="m -0.25712974,-58.74287 10.00000004,5 0,-10 z"
+       copytype="single_stretched"
+       prop_scale="1"
+       scale_y_rel="false"
+       spacing="0"
+       normal_offset="0"
+       tang_offset="0"
+       prop_units="false"
+       vertical_pattern="false"
+       fuse_tolerance="0" />
+    <inkscape:path-effect
+       effect="skeletal"
+       id="path-effect15572"
+       is_visible="true"
+       pattern="M 0,5 10,10 10,0 z"
+       copytype="single_stretched"
+       prop_scale="1"
+       scale_y_rel="false"
+       spacing="0"
+       normal_offset="0"
+       tang_offset="0"
+       prop_units="false"
+       vertical_pattern="false"
+       fuse_tolerance="0" />
+    <inkscape:path-effect
+       effect="skeletal"
+       id="path-effect15568"
+       is_visible="true"
+       pattern="M 0,5 10,10 10,0 z"
+       copytype="single_stretched"
+       prop_scale="1"
+       scale_y_rel="false"
+       spacing="0"
+       normal_offset="0"
+       tang_offset="0"
+       prop_units="false"
+       vertical_pattern="false"
+       fuse_tolerance="0" />
+    <inkscape:path-effect
+       effect="skeletal"
+       id="path-effect15564"
+       is_visible="true"
+       pattern="M 0,0 0,10 10,5 z"
+       copytype="single_stretched"
+       prop_scale="1"
+       scale_y_rel="false"
+       spacing="0"
+       normal_offset="0"
+       tang_offset="0"
+       prop_units="false"
+       vertical_pattern="false"
+       fuse_tolerance="0" />
+    <inkscape:path-effect
+       effect="skeletal"
+       id="path-effect15560"
+       is_visible="true"
+       pattern="M 0,5 10,10 10,0 z"
+       copytype="single_stretched"
+       prop_scale="1"
+       scale_y_rel="false"
+       spacing="0"
+       normal_offset="0"
+       tang_offset="0"
+       prop_units="false"
+       vertical_pattern="false"
+       fuse_tolerance="0" />
+    <inkscape:path-effect
+       effect="skeletal"
+       id="path-effect15556"
+       is_visible="true"
+       pattern="M 0,5 10,10 10,0 z"
+       copytype="single_stretched"
+       prop_scale="1"
+       scale_y_rel="false"
+       spacing="0"
+       normal_offset="0"
+       tang_offset="0"
+       prop_units="false"
+       vertical_pattern="false"
+       fuse_tolerance="0" />
+    <inkscape:path-effect
+       effect="skeletal"
+       id="path-effect15552"
+       is_visible="true"
+       pattern="M 0,5 10,10 10,0 z"
+       copytype="single_stretched"
+       prop_scale="1"
+       scale_y_rel="false"
+       spacing="0"
+       normal_offset="0"
+       tang_offset="0"
+       prop_units="false"
+       vertical_pattern="false"
+       fuse_tolerance="0" />
+    <inkscape:path-effect
+       effect="skeletal"
+       id="path-effect15548"
+       is_visible="true"
+       pattern="M 0,5 10,10 10,0 z"
+       copytype="single_stretched"
+       prop_scale="1"
+       scale_y_rel="false"
+       spacing="0"
+       normal_offset="0"
+       tang_offset="0"
+       prop_units="false"
+       vertical_pattern="false"
+       fuse_tolerance="0" />
+    <inkscape:path-effect
+       effect="skeletal"
+       id="path-effect15544"
+       is_visible="true"
+       pattern="M 0,5 10,10 10,0 z"
+       copytype="single_stretched"
+       prop_scale="1"
+       scale_y_rel="false"
+       spacing="0"
+       normal_offset="0"
+       tang_offset="0"
+       prop_units="false"
+       vertical_pattern="false"
+       fuse_tolerance="0" />
+    <inkscape:path-effect
+       effect="skeletal"
+       id="path-effect15540"
+       is_visible="true"
+       pattern="M 0,5 10,10 10,0 z"
+       copytype="single_stretched"
+       prop_scale="1"
+       scale_y_rel="false"
+       spacing="0"
+       normal_offset="0"
+       tang_offset="0"
+       prop_units="false"
+       vertical_pattern="false"
+       fuse_tolerance="0" />
+    <inkscape:path-effect
+       effect="skeletal"
+       id="path-effect15536"
+       is_visible="true"
+       pattern="M 0,5 10,10 10,0 z"
+       copytype="single_stretched"
+       prop_scale="1"
+       scale_y_rel="false"
+       spacing="0"
+       normal_offset="0"
+       tang_offset="0"
+       prop_units="false"
+       vertical_pattern="false"
+       fuse_tolerance="0" />
+    <inkscape:path-effect
+       effect="skeletal"
+       id="path-effect15532"
+       is_visible="true"
+       pattern="M 0,5 10,10 10,0 z"
+       copytype="single_stretched"
+       prop_scale="1"
+       scale_y_rel="false"
+       spacing="0"
+       normal_offset="0"
+       tang_offset="0"
+       prop_units="false"
+       vertical_pattern="false"
+       fuse_tolerance="0" />
+    <inkscape:path-effect
+       effect="skeletal"
+       id="path-effect15528"
+       is_visible="true"
+       pattern="M 0,5 10,10 10,0 z"
+       copytype="single_stretched"
+       prop_scale="1"
+       scale_y_rel="false"
+       spacing="0"
+       normal_offset="0"
+       tang_offset="0"
+       prop_units="false"
+       vertical_pattern="false"
+       fuse_tolerance="0" />
+    <inkscape:path-effect
+       effect="skeletal"
+       id="path-effect15524"
+       is_visible="true"
+       pattern="M 0,5 10,10 10,0 z"
+       copytype="single_stretched"
+       prop_scale="1"
+       scale_y_rel="false"
+       spacing="0"
+       normal_offset="0"
+       tang_offset="0"
+       prop_units="false"
+       vertical_pattern="false"
+       fuse_tolerance="0" />
+    <inkscape:path-effect
+       effect="skeletal"
+       id="path-effect15520"
+       is_visible="true"
+       pattern="M 0,5 10,10 10,0 z"
+       copytype="single_stretched"
+       prop_scale="1"
+       scale_y_rel="false"
+       spacing="0"
+       normal_offset="0"
+       tang_offset="0"
+       prop_units="false"
+       vertical_pattern="false"
+       fuse_tolerance="0" />
+    <inkscape:path-effect
+       effect="skeletal"
+       id="path-effect15516"
+       is_visible="true"
+       pattern="M 0,5 10,10 10,0 z"
+       copytype="single_stretched"
+       prop_scale="1"
+       scale_y_rel="false"
+       spacing="0"
+       normal_offset="0"
+       tang_offset="0"
+       prop_units="false"
+       vertical_pattern="false"
+       fuse_tolerance="0" />
+    <inkscape:path-effect
+       effect="skeletal"
+       id="path-effect15418"
+       is_visible="true"
+       pattern="m 29.055659,-73.596157 10,5 0,-10 z"
+       copytype="single_stretched"
+       prop_scale="1"
+       scale_y_rel="false"
+       spacing="0"
+       normal_offset="0"
+       tang_offset="0"
+       prop_units="false"
+       vertical_pattern="false"
+       fuse_tolerance="0" />
+    <filter
+       id="filter15645"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood15647"
+         flood-opacity="0.7"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite15649"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur15651"
+         in="composite"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset15653"
+         dx="3"
+         dy="3"
+         result="offset" />
+      <feComposite
+         id="feComposite15655"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="3.8890873"
+     inkscape:cx="76.499667"
+     inkscape:cy="64"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:document-units="px"
+     inkscape:grid-bbox="true"
+     showguides="true"
+     inkscape:guide-bbox="true"
+     inkscape:snap-bbox="true"
+     inkscape:window-width="1107"
+     inkscape:window-height="816"
+     inkscape:window-x="400"
+     inkscape:window-y="34"
+     inkscape:window-maximized="0" />
+  <metadata
+     id="metadata15337">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     transform="translate(0,64)">
+    <g
+       id="g15590"
+       transform="matrix(1.1495,0,0,1.1495,-1.9363173,13.844484)"
+       style="filter:url(#filter15645);fill:#ffffff;stroke:#ffffff">
+      <path
+         sodipodi:nodetypes="czczc"
+         inkscape:connector-curvature="0"
+         id="path15343"
+         d="m 55.052174,-14.387764 c 0,0 -46.2012364,4.5766947 -47.7332623,-9.116068 -1.5320244,-13.692764 20.4095553,-18.119841 20.4095553,-18.119841 0,0 4.356441,-21.955715 18.054064,-20.467766 13.697625,1.487948 9.269643,47.703675 9.269643,47.703675 z"
+         inkscape:transform-center-y="6.0425489"
+         style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1.29743457000000006;stroke-opacity:1" />
+      <path
+         sodipodi:nodetypes="czczc"
+         inkscape:connector-curvature="0"
+         id="path15343-9"
+         d="m 60.364186,-9.9018411 c 0,0 46.201244,-4.5766959 47.733264,9.11606989 C 109.62947,12.90699 87.687893,17.334069 87.687893,17.334069 c 0,0 -4.356441,21.955714 -18.054064,20.467766 -13.697624,-1.48795 -9.269643,-47.7036761 -9.269643,-47.7036761 z"
+         inkscape:transform-center-y="-6.0425487"
+         style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1.29743457000000006;stroke-opacity:1" />
+      <path
+         inkscape:transform-center-x="6.0425489"
+         sodipodi:nodetypes="czczc"
+         inkscape:connector-curvature="0"
+         id="path15343-7"
+         d="m 60.196664,-14.261099 c 0,0 -4.291826,-46.174813 9.410375,-47.791325 13.702199,-1.616513 17.993988,20.298621 17.993988,20.298621 0,0 21.928833,4.221239 20.356433,17.928567 -1.57241,13.707337 -47.760796,9.564137 -47.760796,9.564137 z"
+         style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1.29743457000000006;stroke-opacity:1" />
+      <path
+         inkscape:transform-center-y="-2.0570379"
+         inkscape:transform-center-x="-24.81302"
+         sodipodi:nodetypes="czczc"
+         inkscape:connector-curvature="0"
+         id="path15343-7-0"
+         d="m 54.389123,-9.8005956 c 0,0 4.291824,46.1748136 -9.410375,47.7913256 C 31.27655,39.60724 26.984763,17.692104 26.984763,17.692104 c 0,0 -21.9288363,-4.221236 -20.3564342,-17.92856893 C 8.2007355,-13.943795 54.389123,-9.8005956 54.389123,-9.8005956 z"
+         style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1.29743457000000006;stroke-opacity:1" />
+      <path
+         transform="matrix(0.91877547,-0.92173709,0.91607136,0.91312794,-55.308264,-90.153688)"
+         d="m 22.627418,104.85832 c 0,1.98813 -1.726814,3.59982 -3.856946,3.59982 -2.130133,0 -3.856946,-1.61169 -3.856946,-3.59982 0,-1.98812 1.726813,-3.59981 3.856946,-3.59981 2.130132,0 3.856946,1.61169 3.856946,3.59981 z"
+         sodipodi:ry="3.5998163"
+         sodipodi:rx="3.856946"
+         sodipodi:cy="104.85832"
+         sodipodi:cx="18.770472"
+         id="path15420"
+         style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-opacity:1"
+         sodipodi:type="arc" />
+    </g>
+  </g>
+</svg>
diff --git a/themes/snowy/snowy/svg/os_debian.svg b/themes/snowy/snowy/svg/os_debian.svg
new file mode 100644 (file)
index 0000000..55eaedb
--- /dev/null
@@ -0,0 +1,152 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   height="108.76"
+   viewBox="0 0 108.758 108.76226"
+   width="108.76"
+   id="svg11843"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="os_debian-04-white.svg"
+   inkscape:export-filename="/home/rodsmith/programming/refind/current/icons-build/os_debian-white.png"
+   inkscape:export-xdpi="105.9213"
+   inkscape:export-ydpi="105.9213">
+  <metadata
+     id="metadata11887">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs11885">
+    <filter
+       id="filter11922"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood11924"
+         flood-opacity="0.7"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite11926"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur11928"
+         in="composite"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset11930"
+         dx="2"
+         dy="2"
+         result="offset" />
+      <feComposite
+         id="feComposite11932"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="955"
+     inkscape:window-height="882"
+     id="namedview11883"
+     showgrid="false"
+     inkscape:zoom="4.6312966"
+     inkscape:cx="54.380001"
+     inkscape:cy="55.78192"
+     inkscape:window-x="205"
+     inkscape:window-y="51"
+     inkscape:window-maximized="0"
+     inkscape:current-layer="svg11843" />
+  <g
+     id="g11889"
+     transform="translate(0.48298776,44.66387)"
+     style="filter:url(#filter11922);fill:#ffffff">
+    <path
+       style="fill:#ffffff"
+       inkscape:connector-curvature="0"
+       id="path11845"
+       d="m 60.969,12.27426 c -1.494,0.02 0.281,0.768 2.232,1.069 0.541,-0.422 1.027,-0.846 1.463,-1.26 -1.213,0.297 -2.449,0.304 -3.695,0.191" />
+    <path
+       style="fill:#ffffff"
+       inkscape:connector-curvature="0"
+       id="path11847"
+       d="m 68.986,10.27526 c 0.893,-1.2289999 1.541,-2.5729999 1.77,-3.9629999 -0.201,0.99 -0.736,1.845 -1.244,2.749 -2.793,1.7589999 -0.264,-1.044 -0.002,-2.111 -3.002,3.7829999 -0.414,2.268 -0.524,3.3249999" />
+    <path
+       style="fill:#ffffff"
+       inkscape:connector-curvature="0"
+       id="path11849"
+       d="m 71.949,2.5712601 c 0.182,-2.69099999 -0.529,-1.83899999 -0.768,-0.814 0.278,0.146 0.499,1.898 0.768,0.814" />
+    <path
+       style="fill:#ffffff"
+       inkscape:connector-curvature="0"
+       id="path11851"
+       d="m 55.301,-34.20774 c 0.798,0.142 1.724,0.252 1.591,0.443 0.876,-0.193 1.073,-0.367 -1.591,-0.443" />
+    <path
+       style="fill:#ffffff"
+       inkscape:connector-curvature="0"
+       id="path11853"
+       d="m 56.893,-33.76474 -0.561,0.117 0.523,-0.048 0.038,-0.069" />
+    <path
+       style="fill:#ffffff"
+       inkscape:connector-curvature="0"
+       id="path11855"
+       d="m 81.762,3.5912601 c 0.09,2.416 -0.705,3.59 -1.424,5.666 l -1.293,0.643 C 77.988,11.95426 79.15,11.20426 78.393,12.83726 c -1.652,1.467 -5.006,4.589 -6.08,4.875 -0.785,-0.017 0.531,-0.926 0.703,-1.281 -2.209,1.516 -1.773,2.276 -5.152,3.199 l -0.098,-0.221 c -8.33,3.92 -19.902,-3.847 -19.75,-14.4429999 -0.088,0.672 -0.253,0.504 -0.437,0.774 -0.43,-5.45099999 2.518,-10.926 7.49,-13.165 4.863,-2.406 10.564,-1.42 14.045,1.829 -1.912,-2.506 -5.721,-5.1630001 -10.232,-4.9170001 -4.421,0.072 -8.558,2.8810001 -9.938,5.9320001 -2.264,1.425 -2.528,5.49600001 -3.514,6.242 -1.329,9.7599999 2.497,13.9749999 8.97,18.9359999 1.016,0.686 0.286,0.791 0.422,1.313 -2.15,-1.006 -4.118,-2.526 -5.738,-4.387 0.86,1.257 1.787,2.479 2.986,3.439 -2.029,-0.685 -4.738,-4.913 -5.527,-5.085 3.495,6.258 14.178,10.975 19.775,8.634 -2.59,0.096 -5.879,0.053 -8.787,-1.022 -1.225,-0.629 -2.884,-1.93 -2.587,-2.173 7.636,2.851 15.522,2.158 22.128,-3.137 1.682,-1.31 3.518,-3.537 4.049,-3.567 -0.799,1.202 0.137,0.578 -0.477,1.639 1.672,-2.701 -0.729,-1.1 1.73,-4.664 l 0.908,1.25 c -0.34,-2.244 2.785,-4.9659999 2.467,-8.5119999 0.717,-1.084 0.799,1.168 0.039,3.662 1.055,-2.767 0.279,-3.212 0.549,-5.496 0.291,0.768 0.678,1.583 0.875,2.394 -0.688,-2.675 0.703,-4.50299999 1.049,-6.058 -0.342,-0.15 -1.061,1.18200001 -1.227,-1.976 0.025,-1.372 0.383,-0.719 0.52,-1.057 -0.268,-0.155 -0.975,-1.207 -1.404,-3.224 0.309,-0.475 0.832,1.229 1.256,1.298 -0.273,-1.603 -0.742,-2.826 -0.762,-4.0570001 -1.24,-2.59 -0.439,0.3460001 -1.443,-1.112 -1.32,-4.114 1.094,-0.955 1.258,-2.823 1.998,2.895 3.137,7.3850001 3.662,9.2440001 -0.4,-2.267 -1.045,-4.464 -1.834,-6.5890001 0.609,0.257 -0.979,-4.663 0.791,-1.405 -1.889,-6.945 -8.078,-13.435 -13.773,-16.479 0.695,0.637 1.574,1.437 1.26,1.563 -2.834,-1.685 -2.336,-1.818 -2.742,-2.53 -2.305,-0.939 -2.459,0.077 -3.984,0.002 -4.35,-2.308 -5.188,-2.063 -9.191,-3.507 l 0.182,0.852 c -2.881,-0.96 -3.357,0.362 -6.47,0.002 -0.189,-0.147 0.998,-0.536 1.976,-0.677 -2.786,0.368 -2.656,-0.55 -5.382,0.101 0.671,-0.471 1.383,-0.784 2.099,-1.184 -2.271,0.138 -5.424,1.322 -4.451,0.244 -3.705,1.654 -10.286,3.975 -13.979,7.438 l -0.116,-0.776 c -1.692,2.031 -7.379,6.066 -7.832,8.699 l -0.453,0.105 c -0.879,1.491 -1.45,3.18 -2.148,4.713 -1.151,1.963 -1.688,0.756 -1.524,1.064 -2.265,4.5920001 -3.392,8.4500001 -4.363,11.6160001 0.692,1.03500001 0.017,6.232 0.278,10.391 C 17.329,29.30726 32.883,49.25226 49.885,53.85626 c 2.492,0.893 6.197,0.861 9.349,0.949 -3.718,-1.064 -4.198,-0.563 -7.822,-1.826 -2.613,-1.232 -3.185,-2.637 -5.037,-4.244 l 0.733,1.295 c -3.63,-1.285 -2.111,-1.59 -5.065,-2.525 l 0.783,-1.021 c -1.177,-0.09 -3.117,-1.982 -3.647,-3.033 l -1.288,0.051 c -1.546,-1.906 -2.371,-3.283 -2.31,-4.35 l -0.416,0.742 c -0.471,-0.809 -5.691,-7.158 -2.983,-5.68 -0.503,-0.458 -1.172,-0.747 -1.897,-2.066 l 0.551,-0.629 c -1.301,-1.677 -2.398,-3.826 -2.314,-4.542 0.695,0.938 1.177,1.114 1.655,1.275 -3.291,-8.164 -3.476,-0.449 -5.967,-8.31 l 0.526,-0.042 c -0.403,-0.611 -0.65,-1.27 -0.974,-1.919 l 0.23,-2.285 C 21.624,12.96026 23.33,4.0512601 23.673,-0.83373989 23.908,-2.8197399 25.65,-4.9347399 26.973,-8.2517399 l -0.806,-0.138 C 27.709,-11.07774 34.969,-19.18874 38.333,-18.77274 c 1.629,-2.046 -0.324,-0.008 -0.643,-0.522 3.579,-3.703 4.704,-2.616 7.119,-3.283 2.603,-1.545 -2.235,0.604 -1.001,-0.589 4.503,-1.149 3.19,-2.614 9.063,-3.197 0.62,0.352 -1.437,0.544 -1.953,1.001 3.75,-1.836 11.869,-1.417 17.145,1.018 6.117,2.861 12.994,11.314 13.266,19.2670001 l 0.309,0.083 c -0.156,3.162 0.484,6.819 -0.627,10.177 l 0.751,-1.591" />
+    <path
+       style="fill:#ffffff"
+       inkscape:connector-curvature="0"
+       id="path11857"
+       d="m 44.658,14.32426 -0.211,1.047 c 0.983,1.335 1.763,2.781 3.016,3.821 -0.902,-1.759 -1.571,-2.486 -2.805,-4.868" />
+    <path
+       style="fill:#ffffff"
+       inkscape:connector-curvature="0"
+       id="path11859"
+       d="m 46.979,14.23426 c -0.52,-0.576 -0.826,-1.268 -1.172,-1.956 0.33,1.211 1.006,2.252 1.633,3.312 l -0.461,-1.356" />
+    <path
+       style="fill:#ffffff"
+       inkscape:connector-curvature="0"
+       id="path11861"
+       d="m 88.063,5.3042601 -0.219,0.552 c -0.402,2.858 -1.273,5.6859999 -2.605,8.3089999 1.472,-2.767 2.421,-5.7939999 2.824,-8.8609999" />
+    <path
+       style="fill:#ffffff"
+       inkscape:connector-curvature="0"
+       id="path11863"
+       d="m 55.598,-34.92474 c 1.009,-0.369 2.482,-0.203 3.556,-0.446 -1.398,0.117 -2.789,0.187 -4.162,0.362 l 0.606,0.084" />
+    <path
+       style="fill:#ffffff"
+       inkscape:connector-curvature="0"
+       id="path11865"
+       d="m 20.127,-16.06274 c 0.233,2.154 -1.62,2.991 0.41,1.569 1.09,-2.454 -0.424,-0.677 -0.41,-1.569" />
+    <path
+       style="fill:#ffffff"
+       inkscape:connector-curvature="0"
+       id="path11867"
+       d="m 17.739,-6.0887399 c 0.469,-1.437 0.553,-2.299 0.732,-3.132 -1.293,1.654 -0.596,2.007 -0.732,3.132" />
+  </g>
+</svg>
diff --git a/themes/snowy/snowy/svg/os_elementary.svg b/themes/snowy/snowy/svg/os_elementary.svg
new file mode 100644 (file)
index 0000000..6cd19e3
--- /dev/null
@@ -0,0 +1,188 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="128"
+   height="128"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="os_elementary-05-white.svg"
+   inkscape:export-filename="/home/rodsmith/programming/refind/current/icons-build/os_elementary-white.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90">
+  <defs
+     id="defs4">
+    <inkscape:path-effect
+       is_visible="true"
+       id="path-effect2991"
+       effect="spiro" />
+    <inkscape:path-effect
+       effect="spiro"
+       id="path-effect3177"
+       is_visible="true" />
+    <filter
+       id="filter13615"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood13617"
+         flood-opacity="0.7"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite13619"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur13621"
+         in="composite"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset13623"
+         dx="2"
+         dy="2"
+         result="offset" />
+      <feComposite
+         id="feComposite13625"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+    <filter
+       id="filter13646"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood13648"
+         flood-opacity="0.9"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite13650"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur13652"
+         in="composite"
+         stdDeviation="8"
+         result="blur" />
+      <feOffset
+         id="feOffset13654"
+         dx="5"
+         dy="5"
+         result="offset" />
+      <feComposite
+         id="feComposite13656"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#a0a0a0"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="5.6568542"
+     inkscape:cx="68.53883"
+     inkscape:cy="64"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     showguides="false"
+     inkscape:guide-bbox="true"
+     inkscape:window-width="1050"
+     inkscape:window-height="979"
+     inkscape:window-x="306"
+     inkscape:window-y="19"
+     inkscape:window-maximized="0"
+     fit-margin-top="4"
+     fit-margin-left="4"
+     fit-margin-right="4"
+     fit-margin-bottom="4"
+     showborder="true"
+     inkscape:showpageshadow="true">
+    <sodipodi:guide
+       orientation="1,0"
+       position="4,4"
+       id="guide2985" />
+    <sodipodi:guide
+       orientation="1,0"
+       position="604,459.18566"
+       id="guide2987" />
+    <sodipodi:guide
+       orientation="0,1"
+       position="-198.43278,4"
+       id="guide2989" />
+    <sodipodi:guide
+       orientation="0,1"
+       position="-265.01408,604"
+       id="guide2991" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-96,-828.36218)">
+    <g
+       id="g13609"
+       transform="matrix(0.19390511,0,0,0.19381243,80.257491,768.01645)"
+       style="filter:url(#filter13646)"
+       inkscape:export-xdpi="18.947369"
+       inkscape:export-ydpi="18.947369">
+      <path
+         transform="translate(96,326.36218)"
+         inkscape:connector-curvature="0"
+         id="path13582"
+         d="M 299.80321,613.56476 C 197.92174,608.10118 106.15948,551.42291 55.073464,462.40395 35.899346,428.99245 23.807511,392.35152 17.969021,349.96927 16.20857,337.18996 16.197191,293.21958 17.950995,280.31498 27.700685,208.5762 56.958646,149.56573 106.85356,101.00716 153.12077,55.979107 207.62342,29.10103 273.17069,18.987558 c 19.8615,-3.064488 61.41591,-3.344894 80.40973,-0.5426 32.93296,4.858834 63.09581,13.804446 89.62868,26.581812 119.1285,57.3684 186.53393,183.77486 167.42463,313.974 -15.27514,104.07549 -85.55456,193.19 -183.81387,233.07653 -39.89944,16.19643 -84.61652,23.76124 -127.01665,21.48746 z m 41.12067,-18.81162 c 67.62471,-6.72428 127.15604,-35.33941 174.10572,-83.68799 30.33179,-31.23553 51.23408,-65.7593 64.9757,-107.31867 20.12404,-60.86197 18.98998,-127.94066 -3.16425,-187.16499 C 539.8057,117.57592 451.67832,48.226595 347.39861,36.028341 330.48807,34.050209 298.99376,34.030335 282.26467,35.987241 228.56724,42.268568 177.93154,64.18429 135.7678,99.3928 83.07679,143.39203 49.37961,203.97153 38.430918,274.3813 c -3.253303,20.92162 -3.264549,60.28311 -0.0232,81.22178 4.747139,30.66591 12.924742,56.77661 26.33267,84.07899 43.487742,88.55347 129.117712,147.08873 227.380372,155.43353 9.71469,0.825 39.05234,0.60712 48.80313,-0.36246 z"
+         style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1.02432775000000009;stroke-opacity:1;" />
+      <path
+         transform="translate(96,326.36218)"
+         inkscape:connector-curvature="0"
+         id="path13584"
+         d="m 287.51128,450.33234 c -9.20847,-1.27511 -19.50895,-3.79831 -29.19334,-7.15122 -8.68995,-3.0086 -19.97439,-8.21666 -19.97439,-9.21868 0,-0.3296 4.26376,-3.07442 9.47503,-6.09959 36.28967,-21.06642 69.14244,-46.80272 99.62804,-78.04691 56.37988,-57.78278 81.43976,-110.16646 77.25639,-161.49219 -2.11,-25.88754 -11.38374,-48.06103 -26.97685,-64.50151 -14.60489,-15.39858 -32.60736,-25.179852 -55.41334,-30.107721 -9.59279,-2.07279 -38.10678,-1.779359 -48.14341,0.495433 -34.40754,7.798438 -66.19195,26.718698 -94.03303,55.974918 -61.99306,65.1441 -82.43198,154.12088 -52.51718,228.62312 5.83391,14.52923 15.58806,31.54563 24.32374,42.43347 3.78318,4.71522 6.55779,8.76145 6.16581,8.99163 -1.88699,1.10802 -29.82415,9.14461 -41.17366,11.84429 -13.10035,3.11614 -38.812063,7.75777 -39.34866,7.10345 C 94.508985,445.4282 85.898266,428.32507 79.353482,412.96543 59.776551,367.02128 54.746759,310.13177 65.820059,259.89553 74.502968,220.50377 94.661045,179.76729 120.86187,148.6642 c 27.28992,-32.39597 66.39302,-59.837427 106.33196,-74.620799 44.022,-16.294714 94.33533,-19.788334 141.23934,-9.807273 38.64375,8.223296 79.6708,28.321372 109.50848,53.645342 36.99027,31.39454 64.00158,71.19436 79.30321,116.84936 l 3.4326,10.2417 -5.64121,10.75702 c -29.20394,55.68797 -67.87007,103.19718 -114.70732,140.94125 -33.38873,26.90651 -68.66699,44.66197 -102.62559,51.65119 -12.15458,2.50161 -38.90622,3.57309 -50.19206,2.01035 z"
+         style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1.02432775000000009;stroke-opacity:1;" />
+      <path
+         transform="translate(96,326.36218)"
+         inkscape:connector-curvature="0"
+         id="path13586"
+         d="m 205.4443,409.63637 c -16.68969,-17.16197 -26.89356,-34.99658 -33.13887,-57.92103 -11.24368,-41.2718 -5.35522,-87.33036 17.39037,-136.02454 21.12871,-45.23276 46.39326,-75.27545 77.32892,-91.95373 17.42412,-9.39383 30.47502,-12.70856 50.19207,-12.748 12.16974,-0.0243 14.92963,0.3069 23.00923,2.76157 17.66913,5.36809 30.61272,14.27397 41.20049,28.3481 32.14403,42.72852 22.46511,103.39567 -26.30019,164.84877 -33.24193,41.89082 -76.51857,76.61555 -127.1956,102.0604 -8.26227,4.14847 -15.18884,7.54267 -15.39239,7.54267 -0.20355,0 -3.39586,-3.1114 -7.09403,-6.91421 l 0,0 z"
+         style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1.02432775000000009;stroke-opacity:1;" />
+      <path
+         transform="translate(96,326.36218)"
+         inkscape:connector-curvature="0"
+         id="path13588"
+         d="m 286.53883,570.04809 c -50.88733,-5.31382 -102.6056,-28.86652 -142.71422,-64.99262 -9.03301,-8.13609 -24.68554,-24.95555 -23.92858,-25.71251 0.22315,-0.22316 5.62412,-1.77484 12.00216,-3.44819 19.47581,-5.10969 44.10531,-13.46722 61.32021,-20.8078 l 8.65207,-3.68932 8.6498,5.7557 c 10.92175,7.26749 26.53996,14.72624 39.09088,18.66856 29.24187,9.18506 63.1077,10.10917 96.09885,2.62229 78.70775,-17.86162 163.90262,-91.67057 219.14718,-189.85916 l 3.12736,-5.55837 0.86452,6.07053 c 1.30024,9.13005 0.97135,46.79562 -0.50021,57.28693 -6.57196,46.85377 -23.13828,87.52488 -50.65713,124.36568 -9.41736,12.60748 -36.32693,39.52637 -48.87442,48.89137 -38.2086,28.51752 -81.32343,45.63855 -127.23236,50.52432 -11.67016,1.24198 -42.66103,1.17587 -55.04611,-0.11741 l 0,0 z"
+         style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1.02432775000000009;stroke-opacity:1;" />
+    </g>
+  </g>
+</svg>
diff --git a/themes/snowy/snowy/svg/os_gummiboot.svg b/themes/snowy/snowy/svg/os_gummiboot.svg
new file mode 100644 (file)
index 0000000..038f92f
--- /dev/null
@@ -0,0 +1,203 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="128"
+   height="128"
+   id="svg19221"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="os_gummiboot-02-color.svg"
+   inkscape:export-filename="/home/rodsmith/programming/refind/current/icons-build/os_gummiboot-white.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90">
+  <defs
+     id="defs19223">
+    <inkscape:path-effect
+       effect="skeletal"
+       id="path-effect19257"
+       is_visible="true"
+       pattern="M 0,5 10,10 10,0 z"
+       copytype="single_stretched"
+       prop_scale="1"
+       scale_y_rel="false"
+       spacing="0"
+       normal_offset="0"
+       tang_offset="0"
+       prop_units="false"
+       vertical_pattern="false"
+       fuse_tolerance="0" />
+    <filter
+       id="filter19416"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood19418"
+         flood-opacity="0.65"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite19420"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur19422"
+         in="composite"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset19424"
+         dx="2"
+         dy="2"
+         result="offset" />
+      <feComposite
+         id="feComposite19426"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="3.8890873"
+     inkscape:cx="59.349784"
+     inkscape:cy="67.774903"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:document-units="px"
+     inkscape:grid-bbox="true"
+     inkscape:window-width="1093"
+     inkscape:window-height="861"
+     inkscape:window-x="246"
+     inkscape:window-y="45"
+     inkscape:window-maximized="0" />
+  <metadata
+     id="metadata19226">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     transform="translate(0,64)">
+    <g
+       id="g19404"
+       style="filter:url(#filter19416)">
+      <rect
+         transform="matrix(0.54045344,0.84137392,-0.84137392,0.54045344,0,0)"
+         ry="28.387121"
+         y="-84.754982"
+         x="-25.555317"
+         height="69.425026"
+         width="115.39982"
+         id="rect19231"
+         style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1.20000005000000010;stroke-opacity:1" />
+      <rect
+         transform="matrix(0.54045344,0.84137392,-0.84137392,0.54045344,0,0)"
+         ry="20.561064"
+         y="-75.185074"
+         x="-12.745574"
+         height="50.285213"
+         width="89.780334"
+         id="rect19231-7"
+         style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.90080631;stroke-opacity:1" />
+      <g
+         transform="matrix(0.07446601,-1.1976873,1.1976873,0.07446601,129.22882,2.7456852)"
+         id="g19279">
+        <path
+           sodipodi:type="star"
+           style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-opacity:1"
+           id="path19259"
+           sodipodi:sides="3"
+           sodipodi:cx="62.996784"
+           sodipodi:cy="9.4631901"
+           sodipodi:r1="4.1140757"
+           sodipodi:r2="2.0570383"
+           sodipodi:arg1="-1.5707963"
+           sodipodi:arg2="-0.52359878"
+           inkscape:flatsided="false"
+           inkscape:rounded="0"
+           inkscape:randomized="0"
+           d="m 62.996784,5.3491144 1.781448,3.0855565 1.781446,3.0855571 -3.562894,0 -3.562894,0 1.781447,-3.0855571 z"
+           transform="matrix(0.99611394,0,0,1.0873392,-54.310432,-27.400102)"
+           inkscape:transform-center-y="-1.1183489" />
+        <rect
+           style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.3377991;stroke-opacity:1"
+           id="rect19261"
+           width="8.5378227"
+           height="5.4873924"
+           x="4.172637"
+           y="-15.159016"
+           ry="1.3157942" />
+        <rect
+           style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1.0407275;stroke-opacity:1"
+           id="rect19267"
+           width="0.45277908"
+           height="31.236288"
+           x="8.2636356"
+           y="-52.408901"
+           ry="0.24712254" />
+      </g>
+      <g
+         id="g19279-6"
+         transform="matrix(1.0776069,0.52798038,-0.52798038,1.0776069,7.511571,52.239117)">
+        <path
+           sodipodi:type="star"
+           style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-opacity:1"
+           id="path19259-0"
+           sodipodi:sides="3"
+           sodipodi:cx="62.996784"
+           sodipodi:cy="9.4631901"
+           sodipodi:r1="4.1140757"
+           sodipodi:r2="2.0570383"
+           sodipodi:arg1="-1.5707963"
+           sodipodi:arg2="-0.52359878"
+           inkscape:flatsided="false"
+           inkscape:rounded="0"
+           inkscape:randomized="0"
+           d="m 62.996784,5.3491144 1.781448,3.0855565 1.781446,3.0855571 -3.562894,0 -3.562894,0 1.781447,-3.0855571 z"
+           transform="matrix(0.99611394,0,0,1.0873392,-54.310432,-27.400102)"
+           inkscape:transform-center-y="-1.1183489" />
+        <rect
+           style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.3377991;stroke-opacity:1"
+           id="rect19261-9"
+           width="8.5378227"
+           height="5.4873924"
+           x="4.172637"
+           y="-15.159016"
+           ry="1.3157942" />
+        <rect
+           style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1.0407275;stroke-opacity:1"
+           id="rect19267-4"
+           width="0.45277908"
+           height="31.236288"
+           x="8.2636356"
+           y="-52.408901"
+           ry="0.24712254" />
+      </g>
+    </g>
+  </g>
+</svg>
diff --git a/themes/snowy/snowy/svg/os_haiku.svg b/themes/snowy/snowy/svg/os_haiku.svg
new file mode 100644 (file)
index 0000000..3ddbac1
--- /dev/null
@@ -0,0 +1,202 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="128"
+   height="128"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="os_haiku-02-color.svg">
+  <defs
+     id="defs4">
+    <filter
+       id="filter5665"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood5667"
+         flood-opacity="0.7"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite5669"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur5671"
+         in="composite"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset5673"
+         dx="3"
+         dy="3"
+         result="offset" />
+      <feComposite
+         id="feComposite5675"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+    <filter
+       id="filter5843"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood5845"
+         flood-opacity="0.7"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite5847"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur5849"
+         in="composite"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset5851"
+         dx="3"
+         dy="3"
+         result="offset" />
+      <feComposite
+         id="feComposite5853"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="3.959798"
+     inkscape:cx="58.819443"
+     inkscape:cy="72.789643"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:window-width="1046"
+     inkscape:window-height="839"
+     inkscape:window-x="385"
+     inkscape:window-y="93"
+     inkscape:window-maximized="0" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(0,-924.36218)">
+    <g
+       id="g5829"
+       style="filter:url(#filter5843)">
+      <rect
+         ry="0"
+         y="934.38153"
+         x="18.497774"
+         height="107.96134"
+         width="18.56284"
+         id="rect3013"
+         style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:2.13513446000000018;stroke-opacity:1" />
+      <rect
+         ry="0"
+         y="934.38153"
+         x="90.449203"
+         height="107.96134"
+         width="18.56284"
+         id="rect3013-8"
+         style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:2.13513446000000018;stroke-opacity:1" />
+      <g
+         id="g5595"
+         transform="matrix(1.5227283,0,0,1.4525208,-36.649015,996.88746)"
+         style="fill:#ffffff;stroke:#e6e6e6">
+        <path
+           style="fill:#ffffff;fill-opacity:1;stroke:#e6e6e6;stroke-width:0.18181818999999999;stroke-opacity:1"
+           d="M 59.061107,5.390994 C 56.032698,5.04526 52.779267,3.974574 48.954696,2.065031 c -1.6,-0.798851 -3.236364,-1.640695 -3.636364,-1.870762 -0.4,-0.230068 -1.35219,-0.765373 -2.115977,-1.189566 -1.343771,-0.746307 -4.480725,-3.072643 -6.825044,-5.061392 -0.627174,-0.532048 -1.490197,-1.145274 -1.917829,-1.362724 -0.427632,-0.217451 -1.227513,-0.694631 -1.777513,-1.060401 -0.996154,-0.662478 -2.73167,-1.396504 -4.44841,-1.881428 l -0.902954,-0.255056 1.551288,-0.125871 c 0.858283,-0.06964 2.480011,-0.03535 3.630228,0.07676 1.321809,0.128836 2.514687,0.144118 3.275425,0.04196 1.1718,-0.157358 2.16715,-0.0093 2.16715,0.322391 0,0.08773 0.593182,0.60444 1.318182,1.148243 1.848965,1.386859 2.300325,1.858668 2.698216,2.820463 0.951305,2.299519 2.466262,5.277485 2.68921,5.286207 0.457696,0.01791 0.09994,-1.079084 -1.269142,-3.891595 -1.431701,-2.941144 -1.984086,-3.680898 -3.554633,-4.760365 l -1.021152,-0.701857 1.796933,-0.115007 c 2.696728,-0.172597 6.437152,-0.169271 7.193193,0.0064 1.19474,0.277598 3.387782,1.82652 4.717097,3.331633 1.423705,1.611989 2.216354,3.062064 2.692485,4.925646 0.183504,0.718232 0.496826,1.678018 0.696271,2.132856 0.199444,0.454838 0.419911,1.166038 0.489924,1.580442 0.142463,0.843231 0.541825,1.313262 0.852149,1.002938 0.204023,-0.204024 0.143569,-0.450404 -0.702953,-2.864904 -0.24542,-0.7 -0.601122,-1.873234 -0.790451,-2.607188 -0.189329,-0.733955 -0.646358,-1.831813 -1.015622,-2.439687 -1.023183,-1.684341 -2.854872,-3.677022 -4.068551,-4.426147 -0.596636,-0.368265 -1.084792,-0.705573 -1.084792,-0.749573 0,-0.044 0.838636,-0.06202 1.863636,-0.04006 1.025,0.02197 5.177273,-0.05609 9.227273,-0.173473 12.409778,-0.359667 20.650645,-0.07672 22.306218,0.765887 0.28158,0.143309 1.534691,0.476889 2.784691,0.741288 1.804682,0.381724 2.918631,0.495887 5.409091,0.55435 2.963467,0.06957 3.136363,0.05497 3.136363,-0.264746 0,-0.411604 -0.50965,-0.490386 -4,-0.618318 -2.136743,-0.07832 -5.258878,-0.576972 -5.571812,-0.889906 -0.04949,-0.04949 0.678087,-0.453814 1.616832,-0.898502 1.593913,-0.755044 5.779899,-3.341728 6.009775,-3.713674 0.05667,-0.09169 0.0337,-0.278894 -0.05105,-0.416012 -0.128726,-0.208283 -0.28894,-0.197801 -0.973682,0.0637 -0.450782,0.172155 -0.924773,0.439732 -1.053316,0.594617 -0.559493,0.674149 -4.095057,2.622234 -6.18786,3.409494 -0.946722,0.356133 -1.172633,0.372208 -2.816026,0.200381 -1.508634,-0.157737 -1.796809,-0.239142 -1.851478,-0.523018 -0.05817,-0.302075 -0.196816,-0.325265 -1.365793,-0.22845 -0.715574,0.05926 -2.814681,0.15555 -4.664681,0.213968 l -3.363637,0.106214 1.363637,-0.610257 c 3.210724,-1.436862 10.854088,-6.193882 11.845855,-7.37253 l 0.479833,-0.57025 1.428065,0.549318 c 3.455257,1.329095 8.889478,4.386869 11.207651,6.306415 3.437927,2.846752 4.091155,3.339032 5.201935,3.920232 0.66016,0.345424 1.97757,0.893615 2.92757,1.218204 0.95,0.324588 1.79369,0.648054 1.87487,0.718814 0.0812,0.07076 -0.57336,0.352386 -1.45454,0.625838 -2.45482,0.761791 -2.95591,0.961494 -4.32942,1.725453 -2.565695,1.42706 -5.666586,2.979405 -6.818182,3.413268 -0.65,0.244888 -2,0.801149 -3,1.236139 -1.696535,0.737974 -3.754109,1.497516 -9.363636,3.45653 C 78.61888,3.85284 74.121174,4.828149 70.146934,5.320549 66.64338,5.754631 62.478156,5.7811 59.061107,5.390999 l 0,0 z M 74.406696,0.736405 c -0.06488,-0.225 -0.499936,-0.963793 -0.966798,-1.641762 -0.46686,-0.677969 -1.356456,-2.027969 -1.976878,-3 -1.752188,-2.745198 -2.486298,-3.474953 -5.049958,-5.019986 -2.360724,-1.42273 -2.824197,-1.620138 -2.951402,-1.257102 -0.09582,0.273466 1.048154,1.110739 3.015351,2.206928 1.781698,0.992824 2.774507,2.014505 4.202794,4.325016 2.185398,3.535275 4.147171,5.844468 3.726891,4.386906 l 0,0 z m 13.002546,-1.311627 c 0,-1.112724 -1.564031,-4.26759 -3.224931,-6.505129 -1.707469,-2.300277 -2.432724,-3.04688 -2.959757,-3.04688 -0.516014,0 -0.460634,0.623401 0.07715,0.868431 0.240853,0.10974 0.704913,0.593328 1.031244,1.074639 0.326331,0.481312 0.908284,1.25673 1.293231,1.723153 0.98068,1.188247 1.853542,2.686741 2.510338,4.309648 0.308898,0.763271 0.638056,1.571856 0.731464,1.796856 0.253694,0.611105 0.541262,0.49384 0.541262,-0.220718 z m -46.074837,-9.505634 c -0.198618,-0.198618 -0.334814,0.117247 -0.192214,0.445783 0.135213,0.311521 0.145015,0.311237 0.220352,-0.0064 0.04336,-0.182827 0.0307,-0.380554 -0.02814,-0.439394 l 0,0 z"
+           id="path4170"
+           inkscape:connector-curvature="0" />
+        <path
+           style="fill:#ffffff;fill-opacity:1;stroke:#e6e6e6;stroke-width:0.18181818999999999;stroke-opacity:1"
+           d="m 41.59106,-11.84972 c 0.65,-0.227648 1.662453,-0.628671 2.249896,-0.891163 0.587443,-0.262491 1.144432,-0.477257 1.237754,-0.477257 0.497801,0 5.540233,-2.320874 6.819612,-3.138855 3.51424,-2.246854 6.428603,-4.377528 6.5277,-4.772363 0.0851,-0.339073 0.331296,-0.454774 1.497081,-0.703569 2.709028,-0.578143 7.240819,-1.205369 9.486139,-1.312936 3.457158,-0.165623 8.480292,0.639879 12.046936,1.931827 l 1.592389,0.576812 -0.865116,0.687804 c -1.202948,0.956392 -4.642651,3.217234 -7.13312,4.688444 -1.754971,1.036726 -5.698313,2.942432 -6.641089,3.209452 -0.687202,0.194635 -2.538522,0.273313 -7.58498,0.322347 l -6.67589,0.06487 2.145691,-1.095097 c 2.242491,-1.144501 3.108279,-1.736851 6.115179,-4.183851 1,-0.813795 2.227272,-1.754891 2.727272,-2.091324 0.5,-0.336433 1.448269,-1.067638 2.107264,-1.6249 0.658994,-0.557262 1.43578,-1.185307 1.726191,-1.395654 0.457165,-0.331132 0.495213,-0.421978 0.283538,-0.67703 -0.220265,-0.265403 -0.29688,-0.267482 -0.77354,-0.02099 -0.290984,0.150473 -1.080482,0.744098 -1.754438,1.319167 -0.673958,0.575068 -1.839015,1.486999 -2.589015,2.026513 -0.75,0.539513 -2.018182,1.523536 -2.818182,2.186716 -2.155045,1.78648 -3.309515,2.609881 -4.727272,3.371627 -0.7,0.376103 -1.354546,0.746625 -1.454546,0.823383 -0.1,0.07676 -0.877272,0.448571 -1.727272,0.82625 l -1.545455,0.686689 -5.727273,0.0385 -5.727272,0.0385 1.181818,-0.413905 z"
+           id="path4172"
+           inkscape:connector-curvature="0" />
+        <path
+           style="fill:#ffffff;fill-opacity:1;stroke:#e6e6e6;stroke-width:0.18181818999999999;stroke-opacity:1"
+           d="m 33.045605,-12.097808 c 0.65,-0.283815 1.960732,-1.005365 2.912737,-1.603447 0.952006,-0.598081 2.22897,-1.340511 2.837698,-1.649845 1.648048,-0.837477 6.539528,-2.524729 9.431383,-3.25323 1.4,-0.352681 3.922829,-1.050875 5.606286,-1.551542 1.683458,-0.500667 3.099238,-0.871897 3.146178,-0.824955 0.04694,0.04694 -0.512251,0.48015 -1.242649,0.962687 -0.730398,0.482537 -1.87362,1.264074 -2.540493,1.736749 -2.823289,2.001124 -6.379281,3.664004 -12.311293,5.7571 l -2.47621,0.873725 -3.272728,0.03439 -3.272727,0.03439 1.181818,-0.516025 z"
+           id="path4174"
+           inkscape:connector-curvature="0" />
+        <rect
+           style="fill:#ffffff;fill-opacity:1;stroke:#e6e6e6;stroke-width:0.08757018000000000;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+           id="rect5503"
+           width="1.6991364"
+           height="0.2251936"
+           x="62.280296"
+           y="-5.7272224"
+           transform="matrix(0.96515405,-0.26168235,0.56031449,0.82827995,0,0)" />
+        <rect
+           style="fill:#ffffff;fill-opacity:1;stroke:#e6e6e6;stroke-width:0.06770154000000000;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+           id="rect5505"
+           width="2.414537"
+           height="0.12001605"
+           x="31.512844"
+           y="1.2065728"
+           transform="matrix(0.92723443,-0.3744814,0.63994083,0.76842419,0,0)"
+           inkscape:transform-center-x="0.15096165"
+           inkscape:transform-center-y="-0.17817299" />
+        <rect
+           style="fill:#ffffff;fill-opacity:1;stroke:#e6e6e6;stroke-width:0.10000000000000001;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+           id="rect5507"
+           width="2.4772727"
+           height="0.13636364"
+           x="68.015884"
+           y="-50.667591"
+           transform="matrix(0.92504555,0.3798562,-0.3798562,0.92504555,0,0)" />
+        <path
+           style="fill:#ffffff;fill-opacity:1;stroke:#e6e6e6;stroke-width:0.00909091000000000;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+           d="m 56.823725,2.178412 c -0.08288,-0.126493 -0.230548,-0.541705 -0.328148,-0.922695 -0.0976,-0.380989 -0.336518,-1.128899 -0.530928,-1.662021 -0.194411,-0.533122 -0.516852,-1.506514 -0.716536,-2.163093 -0.522149,-1.71687 -1.126028,-2.86106 -2.211731,-4.19065 -0.995737,-1.219412 -2.310157,-2.364181 -3.632188,-3.163384 -1.163956,-0.703641 -1.48942,-0.780821 -3.532272,-0.837637 -1.665786,-0.04633 -6.043356,0.101428 -6.981719,0.235656 l -0.425126,0.06081 0.998877,0.694997 c 1.111434,0.773312 1.952985,1.58766 2.442332,2.363383 0.830283,1.316181 2.625994,5.165336 2.739756,5.872738 l 0.05463,0.339684 -0.234536,-0.363636 c -0.370237,-0.574032 -1.339802,-2.512678 -1.989946,-3.978897 -0.860852,-1.941411 -0.888766,-1.974578 -3.213066,-3.817596 -0.60984,-0.483564 -1.151572,-0.959125 -1.203847,-1.056804 -0.17358,-0.324335 -0.611404,-0.382886 -2.654665,-0.355011 -1.067978,0.01457 -2.595832,-0.009 -3.395232,-0.05228 l -1.453453,-0.07877 0.675404,-0.268018 0.675405,-0.268019 3.278049,-0.05013 3.278049,-0.05013 1.181818,-0.408246 c 5.064949,-1.749634 8.948521,-3.394726 11.552352,-4.893608 0.784148,-0.451391 4.018752,-2.615749 5.356739,-3.584335 0.25,-0.180978 0.638636,-0.380754 0.863636,-0.443946 0.225,-0.06319 0.490588,-0.138643 0.590197,-0.167667 0.162505,-0.04735 0.16773,-0.03666 0.05087,0.104153 -0.348695,0.420152 -3.049181,2.368433 -5.363157,3.869281 -1.811101,1.174683 -6.023405,3.228747 -7.516952,3.665524 -0.256474,0.075 -1.279201,0.463218 -2.272728,0.862696 -0.993526,0.399479 -1.980274,0.777805 -2.192774,0.840725 -0.2125,0.06292 -0.386364,0.170716 -0.386364,0.239546 0,0.105223 0.929772,0.121022 5.840909,0.09925 l 5.840909,-0.0259 1.494316,-0.703777 c 3.000254,-1.41303 4.767103,-2.521937 7.505684,-4.710706 0.95,-0.759273 2.361364,-1.859666 3.136364,-2.445318 0.775,-0.585652 1.997561,-1.53925 2.716803,-2.119107 1.533343,-1.236192 2.012962,-1.525825 2.229333,-1.346253 0.07963,0.06608 0.144773,0.148982 0.144773,0.184221 0,0.08762 -3.157774,2.614189 -4.5,3.600493 -0.6,0.440897 -1.786364,1.358591 -2.636364,2.039321 -2.88965,2.314202 -3.713898,2.864982 -6.261222,4.183887 -0.981328,0.508093 -1.784232,0.958776 -1.784232,1.00152 0,0.04274 0.03916,0.101916 0.08702,0.131494 0.136939,0.08463 12.212196,-0.125558 13.276621,-0.231102 1.183466,-0.117348 1.817848,-0.357088 4.681818,-1.769304 3.011445,-1.484935 7.23438,-4.080244 9.930197,-6.102847 0.880213,-0.660402 1.046415,-0.752564 1.204545,-0.667936 0.100892,0.054 0.18344,0.132046 0.18344,0.173445 0,0.0414 -0.194318,0.256349 -0.431818,0.477668 -1.627329,1.516456 -7.318146,5.056694 -11.134161,6.926525 -1.073319,0.525921 -1.885109,0.976881 -1.886363,1.047901 -0.0024,0.137874 0.303646,0.131101 6.129563,-0.135637 2.915009,-0.133463 3.092693,-0.132581 3.201267,0.0159 0.06323,0.08647 0.127877,0.195973 0.143669,0.243351 0.09311,0.279338 3.065143,0.618265 3.883162,0.442832 1.420985,-0.304747 5.651842,-2.469773 6.958318,-3.56073 0.479673,-0.400546 1.256855,-0.789926 1.661331,-0.832353 0.299688,-0.03144 0.38919,0.244001 0.142111,0.437337 -0.969346,0.758498 -3.687131,2.405136 -5.803442,3.516159 -0.9,0.472483 -1.648779,0.922003 -1.663951,0.998934 -0.07901,0.400601 2.723189,0.889344 6.118496,1.067153 2.921607,0.153001 3.544989,0.252581 3.368532,0.538095 -0.142428,0.230454 -5.137873,0.04073 -7.038758,-0.267323 -1.298976,-0.210511 -3.390354,-0.716782 -4.073767,-0.986157 -1.097964,-0.432777 -3.674254,-0.690883 -8.346916,-0.836235 -3.445943,-0.107191 -6.848791,-0.07583 -16,0.147441 -2.95,0.07198 -6.253409,0.131123 -7.340909,0.131439 -1.0875,2.72e-4 -1.977273,0.03379 -1.977273,0.07439 0,0.08471 0.323772,0.332272 1.227273,0.938405 0.853901,0.572859 1.612925,1.273698 2.474383,2.284702 1.449081,1.700639 2.142621,2.939272 2.658818,4.748535 0.15692,0.55 0.547454,1.797727 0.867855,2.772727 0.320402,0.975 0.594419,1.891164 0.608928,2.035919 0.03433,0.342555 -0.148556,0.401197 -0.339999,0.109019 l 0,0 z"
+           id="path5519"
+           inkscape:connector-curvature="0" />
+        <path
+           style="fill:#ffffff;fill-opacity:1;stroke:#e6e6e6;stroke-width:0.00909091000000000;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+           d="m 73.464083,0.105697 c -0.335165,-0.410279 -1.336375,-1.832378 -2.224911,-3.160223 -0.888536,-1.327845 -1.849176,-2.687972 -2.134754,-3.022505 -0.630321,-0.738371 -1.481224,-1.393255 -2.86886,-2.207974 -1.187547,-0.697241 -2.266903,-1.423952 -2.503902,-1.685833 -0.555526,-0.613849 1.358377,0.346641 3.566494,1.789841 1.767488,1.15521 2.311649,1.770133 4.564597,5.158178 1.675948,2.520336 2.372811,3.64398 2.372811,3.825998 0,0.170471 -0.238784,-0.04541 -0.771475,-0.697482 z"
+           id="path5521"
+           inkscape:connector-curvature="0" />
+        <path
+           style="fill:#ffffff;fill-opacity:1;stroke:#e6e6e6;stroke-width:0.00909091000000000;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+           d="m 86.92808,-0.648344 c -0.141277,-0.3 -0.377098,-0.847527 -0.524047,-1.216727 -0.410225,-1.030658 -1.048036,-2.300017 -1.570891,-3.126358 -0.821394,-1.298162 -3.015115,-4.108259 -3.412365,-4.371147 -0.377106,-0.249557 -0.505424,-0.60395 -0.218677,-0.60395 0.429317,0 1.216467,0.789282 2.536268,2.543137 0.931619,1.238009 1.613551,2.329769 2.393141,3.831373 0.778218,1.498962 1.124737,2.478754 1.08347,3.063544 l -0.03003,0.425582 -0.256866,-0.545454 0,0 z"
+           id="path5523"
+           inkscape:connector-curvature="0" />
+      </g>
+    </g>
+  </g>
+</svg>
diff --git a/themes/snowy/snowy/svg/os_legacy.svg b/themes/snowy/snowy/svg/os_legacy.svg
new file mode 100644 (file)
index 0000000..9763ef5
--- /dev/null
@@ -0,0 +1,137 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="118"
+   height="118"
+   id="svg9364"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="os_legacy-02-white.svg">
+  <defs
+     id="defs9366">
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="0 : 64 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="104.75 : 54 : 1"
+       inkscape:persp3d-origin="64 : 42.666667 : 1"
+       id="perspective9372" />
+    <filter
+       id="filter3734"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood3736"
+         flood-opacity="0.7"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite3738"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur3740"
+         in="composite"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset3742"
+         dx="3"
+         dy="3"
+         result="offset" />
+      <feComposite
+         id="feComposite3744"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="5.6568542"
+     inkscape:cx="85.868388"
+     inkscape:cy="65.110614"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:document-units="px"
+     inkscape:grid-bbox="true"
+     inkscape:window-width="1112"
+     inkscape:window-height="983"
+     inkscape:window-x="279"
+     inkscape:window-y="23"
+     inkscape:window-maximized="0" />
+  <metadata
+     id="metadata9369">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     transform="translate(0,54)">
+    <g
+       id="g3728"
+       style="filter:url(#filter3734)">
+      <rect
+         inkscape:transform-center-x="27.5"
+         transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,0,0)"
+         y="-35.485481"
+         x="47.871014"
+         height="34.010544"
+         width="34.010544"
+         id="rect9388"
+         style="fill:#f9f9f9;fill-opacity:1;stroke:#f9f9f9;stroke-width:0.98945653000000000" />
+      <rect
+         inkscape:transform-center-x="27.5"
+         transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,0,0)"
+         y="-35.640812"
+         x="8.5925779"
+         height="34.010544"
+         width="34.010544"
+         id="rect9388-5"
+         style="fill:#ececec;fill-opacity:1;stroke:#ececec;stroke-width:0.98945653000000000" />
+      <rect
+         inkscape:transform-center-x="27.5"
+         transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,0,0)"
+         y="-74.810493"
+         x="8.5460062"
+         height="34.010544"
+         width="34.010544"
+         id="rect9388-1"
+         style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.98945653000000000" />
+      <rect
+         inkscape:transform-center-x="27.5"
+         transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,0,0)"
+         y="-74.565689"
+         x="48.078125"
+         height="34.010544"
+         width="34.010544"
+         id="rect9388-4"
+         style="fill:#f2f2f2;fill-opacity:1;stroke:#f2f2f2;stroke-width:0.98945653000000000" />
+    </g>
+  </g>
+</svg>
diff --git a/themes/snowy/snowy/svg/os_mac.svg b/themes/snowy/snowy/svg/os_mac.svg
new file mode 100644 (file)
index 0000000..9ab3163
--- /dev/null
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="128"
+   height="128"
+   id="svg9329"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="os_mac.svg">
+  <defs
+     id="defs9331">
+    <filter
+       id="filter14665"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood14667"
+         flood-opacity="0.7"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite14669"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur14671"
+         in="composite"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset14673"
+         dx="3"
+         dy="3"
+         result="offset" />
+      <feComposite
+         id="feComposite14675"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="3.0989011"
+     inkscape:cx="45.916284"
+     inkscape:cy="64.4846"
+     inkscape:current-layer="layer1"
+     inkscape:document-units="px"
+     showgrid="false"
+     inkscape:snap-bbox="false"
+     inkscape:snap-bbox-edge-midpoints="false"
+     inkscape:bbox-nodes="false"
+     inkscape:window-width="1033"
+     inkscape:window-height="757"
+     inkscape:window-x="280"
+     inkscape:window-y="48"
+     inkscape:window-maximized="0" />
+  <metadata
+     id="metadata9334">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="X"
+     inkscape:groupmode="layer"
+     transform="translate(0,-352)">
+    <path
+       style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.32269504999999998;stroke-opacity:1;filter:url(#filter14665)"
+       d="M 55.535861,474.28314 C 31.903163,470.59273 13.250678,453.88702 7.1077726,430.90953 c -2.449046,-9.16065 -2.522865,-19.84749 -0.20101,-29.10065 4.7850114,-19.06943 19.1707534,-34.83217 37.7295884,-41.34105 10.5402,-3.69661 22.66072,-4.23179 33.72163,-1.48896 20.74249,5.1436 37.485929,21.9257 42.731359,42.83001 2.31728,9.23492 2.25409,19.96009 -0.1711,29.04064 -2.68918,10.06898 -7.44561,18.51511 -14.63835,25.99377 -9.141009,9.50437 -20.770919,15.44953 -34.154779,17.45975 -4.03276,0.60571 -12.64912,0.59537 -16.58925,-0.0199 l 0,10e-6 z m -2.61067,-31.91794 c 5.75541,-10.29397 10.65007,-19.0591 10.87702,-19.47807 0.38653,-0.71357 1.08731,0.47052 11.07691,18.71631 l 10.66428,19.47807 5.52343,0.0883 c 3.03788,0.0486 5.52342,-0.004 5.52342,-0.11631 0,-0.11253 -5.96131,-10.77421 -13.24737,-23.69262 l -13.24736,-23.48804 12.16117,-21.25027 c 6.68864,-11.68765 12.22289,-21.35919 12.29833,-21.4923 0.0754,-0.13311 -2.37634,-0.24122 -5.44838,-0.24024 l -5.58554,0.002 -9.5195,17.41583 c -5.23573,9.57872 -9.59927,17.41941 -9.69677,17.42376 -0.0975,0.004 -4.59909,-7.82862 -10.00355,-17.4066 l -9.82628,-17.41452 -5.56648,-0.011 c -3.06157,-0.006 -5.566495,0.0419 -5.566495,0.10654 0,0.0646 5.245075,9.10414 11.655715,20.08776 6.41064,10.98362 12.0743,20.70866 12.58591,21.61121 l 0.93019,1.64096 -13.43088,23.04518 c -7.38699,12.67485 -13.503164,23.2302 -13.591505,23.45633 -0.12713,0.32542 0.999733,0.39271 5.404365,0.32269 l 5.56498,-0.0885 10.46439,-18.71631 0,0 z"
+       id="path14663"
+       inkscape:connector-curvature="0" />
+  </g>
+</svg>
diff --git a/themes/snowy/snowy/svg/os_netbsd.svg b/themes/snowy/snowy/svg/os_netbsd.svg
new file mode 100644 (file)
index 0000000..d932b13
--- /dev/null
@@ -0,0 +1,424 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="128"
+   height="128"
+   id="svg17054"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="os_netbsd-02-color.svg">
+  <defs
+     id="defs17056">
+    <filter
+       id="filter17303"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood17305"
+         flood-opacity="0.65"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite17307"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur17309"
+         in="composite"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset17311"
+         dx="2"
+         dy="2"
+         result="offset" />
+      <feComposite
+         id="feComposite17313"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+    <filter
+       id="filter17315"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood17317"
+         flood-opacity="0.65"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite17319"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur17321"
+         in="composite"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset17323"
+         dx="2"
+         dy="2"
+         result="offset" />
+      <feComposite
+         id="feComposite17325"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+    <filter
+       id="filter17327"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood17329"
+         flood-opacity="0.65"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite17331"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur17333"
+         in="composite"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset17335"
+         dx="2"
+         dy="2"
+         result="offset" />
+      <feComposite
+         id="feComposite17337"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+    <filter
+       id="filter17339"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood17341"
+         flood-opacity="0.65"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite17343"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur17345"
+         in="composite"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset17347"
+         dx="2"
+         dy="2"
+         result="offset" />
+      <feComposite
+         id="feComposite17349"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+    <filter
+       id="filter17351"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood17353"
+         flood-opacity="0.65"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite17355"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur17357"
+         in="composite"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset17359"
+         dx="2"
+         dy="2"
+         result="offset" />
+      <feComposite
+         id="feComposite17361"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+    <filter
+       id="filter17363"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood17365"
+         flood-opacity="0.65"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite17367"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur17369"
+         in="composite"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset17371"
+         dx="2"
+         dy="2"
+         result="offset" />
+      <feComposite
+         id="feComposite17373"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+    <filter
+       id="filter17375"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood17377"
+         flood-opacity="0.65"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite17379"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur17381"
+         in="composite"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset17383"
+         dx="2"
+         dy="2"
+         result="offset" />
+      <feComposite
+         id="feComposite17385"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+    <filter
+       id="filter17387"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood17389"
+         flood-opacity="0.65"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite17391"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur17393"
+         in="composite"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset17395"
+         dx="2"
+         dy="2"
+         result="offset" />
+      <feComposite
+         id="feComposite17397"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+    <filter
+       id="filter17399"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood17401"
+         flood-opacity="0.65"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite17403"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur17405"
+         in="composite"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset17407"
+         dx="2"
+         dy="2"
+         result="offset" />
+      <feComposite
+         id="feComposite17409"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="3.8890873"
+     inkscape:cx="51.996"
+     inkscape:cy="61.59099"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:document-units="px"
+     inkscape:grid-bbox="true"
+     inkscape:window-width="1072"
+     inkscape:window-height="885"
+     inkscape:window-x="254"
+     inkscape:window-y="60"
+     inkscape:window-maximized="0" />
+  <metadata
+     id="metadata17059">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     transform="translate(0,64)">
+    <g
+       id="g17089"
+       transform="matrix(0.94150529,0,0,0.6223427,0.54982068,-21.484283)"
+       style="fill:#ffffff;filter:url(#filter17303);stroke:#ffffff">
+      <path
+         sodipodi:nodetypes="czzcccaac"
+         inkscape:connector-curvature="0"
+         id="path17068"
+         d="m 58.362114,23.790621 c 0,0 -9.264427,8.564373 -14.47042,5.89488 -5.205993,-2.669494 -14.699991,9.894845 -18.726862,17.008461 -4.026871,7.113616 -9.173076,9.129031 -9.173076,9.129031 L 12.888151,31.067613 9.8994942,7.611697 c 0,0 5.9918358,7.235141 9.2880248,8.089462 7.657201,1.984628 15.253305,-9.4882938 22.897676,-7.2651745 5.830916,1.6957345 16.276919,15.3546365 16.276919,15.3546365 z"
+         inkscape:transform-center-x="-14.810821"
+         style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-opacity:1"
+         transform="matrix(2.2369155,0,0,0.98936915,-12.001007,-63.675251)" />
+      <path
+         sodipodi:nodetypes="czzcccaac"
+         inkscape:connector-curvature="0"
+         id="path17068-9"
+         d="m 117.79667,-16.481994 c 0,0 -19.231387,7.2235816 -30.038153,4.972009 C 76.951754,-13.761557 57.243814,-3.1642213 48.884709,2.8357258 40.525604,8.8356732 29.84295,10.535565 29.84295,10.535565 l -6.442561,-20.879813 -6.203948,-19.783787 c 0,0 12.438042,6.102448 19.280374,6.823021 15.895058,1.673925 31.66329,-8.002859 47.531714,-6.127779 12.103997,1.43026 33.788141,12.950799 33.788141,12.950799 z"
+         inkscape:transform-center-x="-13.744268"
+         style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1.32319713000000005;stroke-opacity:1" />
+    </g>
+    <path
+       sodipodi:type="star"
+       style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-opacity:1;filter:url(#filter17315)"
+       id="path17095"
+       sodipodi:sides="3"
+       sodipodi:cx="63.253918"
+       sodipodi:cy="74.517014"
+       sodipodi:r1="37.351135"
+       sodipodi:r2="18.67557"
+       sodipodi:arg1="0.53451638"
+       sodipodi:arg2="1.5817139"
+       inkscape:flatsided="false"
+       inkscape:rounded="0"
+       inkscape:randomized="0"
+       d="M 95.395134,93.544613 63.05003,93.19147 30.704925,92.838323 47.183308,65.003213 63.661695,37.168104 79.528415,65.356357 z"
+       transform="matrix(0.0807727,-0.04390913,0.29623078,0.78830475,-8.6315177,-83.602242)"
+       inkscape:transform-center-x="1.3991322"
+       inkscape:transform-center-y="-6.7941246" />
+    <path
+       inkscape:connector-curvature="0"
+       id="path17108"
+       style="font-size:36px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke:#ffffff;font-family:FreeSerif;-inkscape-font-specification:FreeSerif;filter:url(#filter17327)"
+       d="m 30.591067,-8.5169089 c -0.672025,0.072023 -1.176024,0.156023 -1.512,0.252 -0.312024,0.072023 -0.648024,0.2520227 -1.008,0.54 -0.336023,0.2880221 -0.576023,0.7440216 -0.72,1.368 -0.120022,0.6000204 -0.180022,1.4160196 -0.18,2.448 l 0,18.9359999 -0.612,0 -15.912,-19.7999999 0,14.112 c -6e-6,1.8240039 0.215994,3.0360019 0.648,3.6359999 0.431993,0.576001 1.343992,0.900001 2.736,0.972 l 0,0.684 -8.4600001,0 0,-0.684 c 1.487998,-0.096 2.435997,-0.419999 2.844,-0.972 0.4319962,-0.575998 0.647996,-1.787996 0.648,-3.6359999 l 0,-15.876 c -0.7200033,-0.839978 -1.2960027,-1.3799774 -1.728,-1.62 -0.4080019,-0.239977 -0.9960013,-0.3599768 -1.764,-0.36 l 0,-0.684 6.1560001,0 13.86,17.424 0,-12.132 c -2.1e-5,-1.8239796 -0.22802,-3.0119784 -0.684,-3.564 -0.43202,-0.5759773 -1.356019,-0.923977 -2.772,-1.044 l 0,-0.684 8.46,0 0,0.684" />
+    <path
+       inkscape:connector-curvature="0"
+       id="path17110"
+       style="font-size:36px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke:#ffffff;font-family:FreeSerif;-inkscape-font-specification:FreeSerif;filter:url(#filter17339)"
+       d="m 34.609004,4.6590911 c 0.048,1.5120085 0.251997,2.8200072 0.612,3.924 0.359996,1.080005 0.827995,1.8960039 1.404,2.4479999 0.575994,0.528003 1.151994,0.912003 1.728,1.152 0.599993,0.216002 1.223992,0.324002 1.872,0.324 1.15199,2e-6 2.147989,-0.287997 2.988,-0.864 0.863987,-0.575996 1.727987,-1.547995 2.592,-2.9159999 l 0.576,0.252 c -0.744014,1.9440039 -1.776013,3.4320019 -3.096,4.4639999 -1.32001,1.032 -2.832009,1.548 -4.536,1.548 -2.064005,0 -3.708004,-0.72 -4.932,-2.16 -1.200001,-1.463997 -1.800001,-3.4319947 -1.8,-5.9039999 -10e-7,-2.6639896 0.695999,-4.7999875 2.088,-6.40799998 1.415996,-1.63198422 3.227994,-2.44798342 5.436,-2.44800002 1.82399,1.66e-5 3.239989,0.552016 4.248,1.65600002 1.007987,1.08001382 1.643986,2.72401218 1.908,4.93199998 l -11.088,0 m 0.072,-1.152 7.344,0 c -0.24001,-1.5599873 -0.61201,-2.63998622 -1.116,-3.23999998 -0.504009,-0.59998504 -1.308008,-0.89998474 -2.412,-0.9 -2.160005,1.526e-5 -3.432004,1.38001388 -3.816,4.13999998" />
+    <path
+       inkscape:connector-curvature="0"
+       id="path17112"
+       style="font-size:36px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke:#ffffff;font-family:FreeSerif;-inkscape-font-specification:FreeSerif;filter:url(#filter17351)"
+       d="m 56.050379,-1.5689089 0,1.15200002 -3.636,0 0,10.29599998 c -5e-6,1.1280039 0.143995,1.9560029 0.432,2.4839999 0.287994,0.504002 0.767994,0.756002 1.44,0.756 0.743992,2e-6 1.463991,-0.419998 2.16,-1.26 l 0.468,0.396 c -1.152009,1.824001 -2.592007,2.736 -4.32,2.736 -2.136003,0 -3.204002,-1.523999 -3.204,-4.572 l 0,-10.83599988 -1.908,0 c -0.096,-0.0719849 -0.144,-0.1559848 -0.144,-0.252 0,-0.11998458 0.036,-0.21598449 0.108,-0.288 0.072,-0.0719843 0.203999,-0.16798422 0.396,-0.28800002 0.215999,-0.143984 0.467999,-0.3239838 0.756,-0.54 0.287998,-0.2399833 0.683998,-0.6599829 1.188,-1.26 0.503997,-0.5999817 1.055996,-1.319981 1.656,-2.16 0.383995,-0.5519796 0.623995,-0.8879793 0.72,-1.008 0.167995,2.09e-5 0.251995,0.1560207 0.252,0.468 l 0,4.176 3.636,0" />
+    <path
+       inkscape:connector-curvature="0"
+       id="path17114"
+       style="font-size:36px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke:#ffffff;font-family:FreeSerif;-inkscape-font-specification:FreeSerif;filter:url(#filter17363)"
+       d="m 78.197692,8.1510911 c -2.1e-5,0.7200058 -0.132021,1.4280051 -0.396,2.1239999 -0.264021,0.696004 -0.70802,1.392003 -1.332,2.088 -0.600019,0.672002 -1.500018,1.224001 -2.7,1.656 -1.200016,0.408 -2.628014,0.612 -4.284,0.612 l -12.024,0 0,-0.684 c 1.487998,-0.048 2.435997,-0.263999 2.844,-0.648 0.407996,-0.383998 0.611996,-1.247997 0.612,-2.592 l 0,-15.9839999 c -4e-6,-1.3199788 -0.204004,-2.1599779 -0.612,-2.52 -0.384003,-0.3839772 -1.332002,-0.6239769 -2.844,-0.72 l 0,-0.684 10.08,0 c 6.287983,2.38e-5 9.43198,2.0400218 9.432,6.12 -2e-5,0.7920169 -0.14402,1.5000162 -0.432,2.12400002 -0.288019,0.60001499 -0.588019,1.06801452 -0.9,1.404 -0.288019,0.31201387 -0.744018,0.61201358 -1.368,0.89999998 -0.624017,0.288013 -1.020016,0.4560128 -1.188,0.504 -0.168016,0.024013 -0.516016,0.1080127 -1.044,0.252 0.551984,0.1440124 0.959984,0.2520123 1.224,0.324 0.287983,0.072012 0.791983,0.2760119 1.512,0.612 0.743981,0.3360113 1.319981,0.6960109 1.728,1.08 0.40798,0.3840101 0.79198,0.9360096 1.152,1.656 0.359979,0.6960082 0.539979,1.4880074 0.54,2.376 m -11.34,5.1479999 c 1.079989,10e-7 2.015988,-0.072 2.808,-0.216 0.791986,-0.143998 1.535986,-0.383998 2.232,-0.72 0.695984,-0.359997 1.223984,-0.887997 1.584,-1.584 0.383983,-0.695995 0.575983,-1.5599945 0.576,-2.5919999 -1.7e-5,-0.9839926 -0.192017,-1.8119917 -0.576,-2.484 -0.360016,-0.6959904 -0.804016,-1.2239898 -1.332,-1.584 -0.528015,-0.3599891 -1.260014,-0.6359888 -2.196,-0.828 -0.936012,-0.1919885 -1.764011,-0.2999883 -2.484,-0.324 -0.72001,-0.047988 -1.680009,-0.071988 -2.88,-0.072 l 0,8.9279999 c -8e-6,0.576002 0.155992,0.972002 0.468,1.188 0.311991,0.192002 0.911991,0.288001 1.8,0.288 m -2.268,-11.8439999 3.42,0 c 1.679987,1.32e-5 2.975986,-0.3719864 3.888,-1.11599998 0.935984,-0.76798494 1.403984,-1.85998382 1.404,-3.27600002 -1.6e-5,-1.6079808 -0.540016,-2.8319796 -1.62,-3.672 -1.080014,-0.8399779 -2.652012,-1.2599775 -4.716,-1.26 l -1.584,0 c -0.528008,2.25e-5 -0.792008,0.3600222 -0.792,1.08 l 0,8.244" />
+    <path
+       inkscape:connector-curvature="0"
+       id="path17116"
+       style="font-size:36px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke:#ffffff;font-family:FreeSerif;-inkscape-font-specification:FreeSerif;filter:url(#filter17375)"
+       d="m 93.240629,9.7710911 c -1.3e-5,-1.127994 -0.396013,-2.123993 -1.188,-2.988 -0.792011,-0.8879912 -1.75201,-1.6439905 -2.88,-2.268 -1.128008,-0.6239892 -2.256007,-1.2599886 -3.384,-1.908 -1.104005,-0.6719873 -2.052004,-1.5239864 -2.844,-2.55599998 -0.792002,-1.03198439 -1.188002,-2.23198322 -1.188,-3.60000002 -2e-6,-1.82398 0.611998,-3.2999785 1.836,-4.428 1.247995,-1.1519762 2.711994,-1.7279756 4.392,-1.728 1.007991,2.44e-5 2.09999,0.2040241 3.276,0.612 1.175988,0.4080233 1.883987,0.6120231 2.124,0.612 0.623986,2.31e-5 1.007986,-0.4079765 1.152,-1.224 l 0.756,0 0.792,7.668 -0.9,0 c -0.576015,-2.1119812 -1.464014,-3.6719796 -2.664,-4.68 -1.176011,-1.0079776 -2.48401,-1.5119771 -3.924,-1.512 -1.104007,2.29e-5 -2.004007,0.3120226 -2.7,0.936 -0.696005,0.6240213 -1.044005,1.4280205 -1.044,2.412 -5e-6,0.9600186 0.407995,1.8720177 1.224,2.736 0.815993,0.8640159 2.171992,1.82401497 4.068,2.88000002 2.375988,1.27201258 4.091986,2.53201138 5.148,3.77999998 1.055984,1.2240089 1.583983,2.5800076 1.584,4.068 -1.7e-5,1.8480039 -0.708016,3.4080029 -2.124,4.6799999 -1.416013,1.248 -3.156012,1.872 -5.22,1.872 -1.200008,0 -2.424007,-0.204 -3.672,-0.612 -1.224005,-0.407999 -1.980004,-0.611999 -2.268,-0.612 -0.264003,10e-7 -0.492003,0.120001 -0.684,0.36 -0.192003,0.216 -0.300003,0.492 -0.324,0.828 l -0.792,0 -1.08,-7.6319999 0.828,0 c 0.887998,2.184005 1.919997,3.7920029 3.096,4.8239999 1.175994,1.032001 2.567993,1.548001 4.176,1.548 1.31999,1e-6 2.387989,-0.371999 3.204,-1.116 0.815987,-0.767997 1.223987,-1.751996 1.224,-2.9519999" />
+    <path
+       inkscape:connector-curvature="0"
+       id="path17118"
+       style="font-size:36px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke:#ffffff;font-family:FreeSerif;-inkscape-font-specification:FreeSerif;filter:url(#filter17387)"
+       d="m 123.31132,2.6070911 c -3e-5,1.080011 -0.12003,2.1360099 -0.36,3.168 -0.24003,1.0320078 -0.68403,2.1000068 -1.332,3.204 -0.64803,1.1040049 -1.47602,2.0640039 -2.484,2.8799999 -1.00802,0.792002 -2.35202,1.452001 -4.032,1.98 -1.65602,0.528 -3.54002,0.792 -5.652,0.792 l -10.224003,0 0,-0.684 c 1.367993,-0.096 2.231993,-0.335999 2.592003,-0.72 0.38399,-0.383998 0.57599,-1.223997 0.576,-2.52 l 0,-15.9839999 c -1e-5,-1.3199788 -0.18001,-2.1599779 -0.54,-2.52 -0.33601,-0.3599772 -1.21201,-0.599977 -2.628003,-0.72 l 0,-0.684 9.720003,0 c 2.18398,2.38e-5 4.12798,0.2520236 5.832,0.756 1.72798,0.4800226 3.10798,1.116022 4.14,1.908 1.05598,0.7680204 1.91997,1.6920195 2.592,2.772 0.69597,1.0560174 1.16397,2.1000163 1.404,3.13200002 0.26397,1.03201423 0.39597,2.11201318 0.396,3.23999998 m -3.924,0.252 c -2e-5,-1.0319872 -0.10802,-2.01598619 -0.324,-2.95199998 -0.19202,-0.95998432 -0.55202,-1.91998332 -1.08,-2.88000002 -0.52802,-0.9839814 -1.21202,-1.8239806 -2.052,-2.52 -0.84002,-0.6959792 -1.94402,-1.2599786 -3.312,-1.692 -1.36802,-0.4559777 -2.92801,-0.6839775 -4.68,-0.684 -0.74401,2.25e-5 -1.24801,0.096022 -1.512,0.288 -0.24001,0.192022 -0.36001,0.5640217 -0.36,1.116 l 0,18.2879999 c -10e-6,0.576002 0.13199,0.972002 0.396,1.188 0.26399,0.192002 0.75599,0.288001 1.476,0.288 7.63198,10e-7 11.44798,-3.4799951 11.448,-10.4399999" />
+    <rect
+       style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.87290215000000004;stroke-opacity:1;filter:url(#filter17399)"
+       id="rect17105"
+       width="4.463408"
+       height="36.004753"
+       x="24.313543"
+       y="35.370052"
+       transform="matrix(0.8440288,-0.53629785,0.33448823,0.94239993,0,0)"
+       inkscape:transform-center-x="8.6102624"
+       inkscape:transform-center-y="-28.432038" />
+  </g>
+</svg>
diff --git a/themes/snowy/snowy/svg/os_redhat.svg b/themes/snowy/snowy/svg/os_redhat.svg
new file mode 100644 (file)
index 0000000..47e2353
--- /dev/null
@@ -0,0 +1,157 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="128"
+   height="128"
+   id="svg11068"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="os_redhat-02-color.svg"
+   inkscape:export-filename="/home/rodsmith/programming/refind/current/icons-build/os_redhat-color.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90">
+  <defs
+     id="defs11070">
+    <filter
+       id="filter11610"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood11612"
+         flood-opacity="0.6"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite11614"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur11616"
+         in="composite"
+         stdDeviation="2"
+         result="blur" />
+      <feOffset
+         id="feOffset11618"
+         dx="2"
+         dy="2"
+         result="offset" />
+      <feComposite
+         id="feComposite11620"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+    <filter
+       id="filter11756"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood11758"
+         flood-opacity="0.7"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite11760"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur11762"
+         in="composite"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset11764"
+         dx="2"
+         dy="2"
+         result="offset" />
+      <feComposite
+         id="feComposite11766"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="3.8890873"
+     inkscape:cx="107.72624"
+     inkscape:cy="64.342982"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:document-units="px"
+     inkscape:grid-bbox="true"
+     inkscape:window-width="1024"
+     inkscape:window-height="859"
+     inkscape:window-x="215"
+     inkscape:window-y="87"
+     inkscape:window-maximized="0" />
+  <metadata
+     id="metadata11073">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     transform="translate(0,64)">
+    <g
+       id="g11604"
+       transform="matrix(0.90471502,0.42601731,-0.42601731,0.90471502,20.872312,-30.760201)"
+       style="fill:#ffffff;stroke:#ffaaaa;filter:url(#filter11756)">
+      <path
+         transform="matrix(1.1342582,0,0,1.0785409,-27.300306,-62.412808)"
+         d="m 120.59385,91.101883 c 0,12.283767 -19.97348,22.241727 -44.612016,22.241727 -24.638533,0 -44.612011,-9.95796 -44.612011,-22.241727 0,-12.283764 19.973478,-22.241722 44.612011,-22.241722 24.638536,0 44.612016,9.957958 44.612016,22.241722 z"
+         sodipodi:ry="22.241722"
+         sodipodi:rx="44.612011"
+         sodipodi:cy="91.101883"
+         sodipodi:cx="75.981834"
+         id="path11076"
+         style="fill:#ffffff;fill-opacity:1;stroke:#ffaaaa;stroke-opacity:1"
+         sodipodi:type="arc" />
+      <path
+         sodipodi:nodetypes="ccccc"
+         inkscape:connector-curvature="0"
+         d="m 30.855568,26.433754 c 2.026004,-19.2662261 54.580851,-18.0872467 56.054283,0 l 0,66.596603 c -10.237774,19.039053 -49.672825,17.895263 -56.054283,0 z"
+         style="fill:#ffffff;fill-opacity:1;stroke:#ffaaaa;stroke-opacity:1"
+         transform="translate(0,-64)"
+         id="path11607" />
+      <path
+         transform="translate(-16.199174,-72.485281)"
+         d="m 102.59477,35.561859 c 0,8.591534 -12.317938,15.556349 -27.512884,15.556349 -15.194945,0 -27.512882,-6.964815 -27.512882,-15.556349 0,-8.591534 12.317937,-15.556349 27.512882,-15.556349 15.194946,0 27.512884,6.964815 27.512884,15.556349 z"
+         sodipodi:ry="15.556349"
+         sodipodi:rx="27.512882"
+         sodipodi:cy="35.561859"
+         sodipodi:cx="75.081886"
+         id="path11088"
+         style="fill:#ffffff;fill-opacity:1;stroke:#ffaaaa;stroke-opacity:1"
+         sodipodi:type="arc" />
+    </g>
+  </g>
+</svg>
diff --git a/themes/snowy/snowy/svg/os_refind.svg b/themes/snowy/snowy/svg/os_refind.svg
new file mode 100644 (file)
index 0000000..ca92c6d
--- /dev/null
@@ -0,0 +1,154 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="128"
+   height="128"
+   id="svg12874"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   inkscape:export-filename="/home/rodsmith/programming/refind/current/icons-build/os_refind-white.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90"
+   sodipodi:docname="os_refind-04-color.svg">
+  <defs
+     id="defs12876">
+    <filter
+       id="filter14441"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood14443"
+         flood-opacity="0.7"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite14445"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur14447"
+         in="composite"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset14449"
+         dx="3"
+         dy="3"
+         result="offset" />
+      <feComposite
+         id="feComposite14451"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#505050"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="5.46875"
+     inkscape:cx="65.187394"
+     inkscape:cy="62.318857"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:document-units="px"
+     inkscape:grid-bbox="true"
+     inkscape:window-width="1108"
+     inkscape:window-height="979"
+     inkscape:window-x="173"
+     inkscape:window-y="12"
+     inkscape:window-maximized="0" />
+  <metadata
+     id="metadata12879">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     transform="translate(0,64)">
+    <g
+       id="g14396"
+       transform="translate(-3.0027063,-3.0672157)"
+       style="filter:url(#filter14441);fill:#ffffff;stroke:#ffffff">
+      <path
+         sodipodi:end="6.3137247"
+         sodipodi:start="0.038057173"
+         transform="matrix(0.92479648,0,0,1.0146143,3.6793308,-74.868835)"
+         d="m 114.23105,62.798281 c -0.1474,3.24681 -3.40512,5.778652 -7.27631,5.655028 -3.8712,-0.123624 -6.88993,-2.855901 -6.74253,-6.10271 0.14739,-3.24681 3.40511,-5.778652 7.2763,-5.655028 3.85064,0.122968 6.86201,2.828112 6.74434,6.058508 l -7.01122,-0.179639 z"
+         sodipodi:ry="5.8831286"
+         sodipodi:rx="7.0144992"
+         sodipodi:cy="62.57444"
+         sodipodi:cx="107.22163"
+         id="path13770"
+         style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-opacity:1"
+         sodipodi:type="arc" />
+      <path
+         inkscape:transform-center-y="-2.717824"
+         inkscape:transform-center-x="2.2822755"
+         transform="matrix(-0.36198059,-1.0983946,1.2009376,-0.52324781,92.632403,-15.195328)"
+         d="M 25.234285,15.542856 13.408625,14.102867 1.5350652,13.13418 8.6949622,3.6128532 15.47065,-6.1856079 20.136412,4.7757081 z"
+         inkscape:randomized="0"
+         inkscape:rounded="0"
+         inkscape:flatsided="false"
+         sodipodi:arg2="1.6720838"
+         sodipodi:arg1="0.62488624"
+         sodipodi:r2="6.6397543"
+         sodipodi:r1="13.753239"
+         sodipodi:cy="7.4971428"
+         sodipodi:cx="14.08"
+         sodipodi:sides="3"
+         id="path13768"
+         style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-opacity:1"
+         sodipodi:type="star" />
+      <path
+         sodipodi:end="6.3137247"
+         sodipodi:start="0.038057173"
+         transform="matrix(1.0623728,0,0,1.0939231,-25.695042,-96.297006)"
+         d="m 128.90965,140.02735 c -0.13449,3.38069 -3.10681,6.01693 -6.63887,5.88821 -3.53207,-0.12872 -6.28635,-2.97366 -6.15186,-6.35435 0.13448,-3.38069 3.10681,-6.01693 6.63887,-5.88821 3.5133,0.12804 6.26086,2.94473 6.15351,6.30833 l -6.39702,-0.18705 z"
+         sodipodi:ry="6.1257143"
+         sodipodi:rx="6.4000001"
+         sodipodi:cy="139.79428"
+         sodipodi:cx="122.51428"
+         id="path13774"
+         style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-opacity:1"
+         sodipodi:type="arc" />
+      <rect
+         transform="matrix(0.87626487,-0.48182972,0.50478347,0.86324599,0,0)"
+         y="62.893646"
+         x="54.812462"
+         height="36.635689"
+         width="13.590784"
+         id="rect13772"
+         style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.97056359000000003;stroke-opacity:1" />
+      <path
+         transform="translate(0,-64)"
+         inkscape:connector-curvature="0"
+         id="path14394"
+         d="M 62.24715,93.833652 C 44.041938,92.252582 28.546517,79.385025 23.734015,61.851955 22.501283,57.360822 22.301415,55.744916 22.29782,50.240526 22.294225,44.735665 22.524224,42.859657 23.75127,38.385327 28.007142,22.866603 41.06795,10.600982 56.852864,7.2990704 63.103797,5.9914908 69.776278,6.0487609 75.778578,7.4615104 83.004074,9.1621606 89.298831,12.39401 94.931372,17.294921 l 1.507079,1.311319 -4.873168,4.875923 -4.873169,4.875922 -1.296768,-1.097309 c -6.117882,-5.17688 -14.176954,-7.796403 -21.868196,-7.108048 -6.678051,0.597677 -12.12638,2.835457 -17.21195,7.069426 -8.343558,6.946394 -12.204448,18.453055 -9.850305,29.356991 1.730081,8.013399 6.921261,15.163838 14.115881,19.443507 4.268634,2.539167 8.875228,3.870069 14.059767,4.062041 7.738606,0.286543 14.749025,-2.096311 20.646607,-7.017823 5.644445,-4.710268 9.670531,-12.247325 10.415034,-19.497527 0.08051,-0.784007 0.193121,-1.47221 0.250249,-1.52934 0.13361,-0.133608 13.406277,0.33269 13.643537,0.479329 0.44025,0.27209 -0.49058,6.224421 -1.54774,9.897282 -2.3965,8.326113 -7.67389,16.284899 -14.40898,21.730061 -8.822615,7.132884 -20.238599,10.655628 -31.3921,9.686977 z"
+         style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.18285714000000000;stroke-opacity:1" />
+    </g>
+  </g>
+</svg>
diff --git a/themes/snowy/snowy/svg/os_refit.svg b/themes/snowy/snowy/svg/os_refit.svg
new file mode 100644 (file)
index 0000000..66324e6
--- /dev/null
@@ -0,0 +1,187 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="128"
+   height="128"
+   id="svg3838"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="os_refit-02-color.svg"
+   inkscape:export-filename="/home/rodsmith/programming/refind/current/icons-build/os_refit-white.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90">
+  <defs
+     id="defs3840">
+    <filter
+       id="filter4018"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood4020"
+         flood-opacity="0.7"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite4022"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur4024"
+         in="composite"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset4026"
+         dx="3"
+         dy="3"
+         result="offset" />
+      <feComposite
+         id="feComposite4028"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+    <filter
+       id="filter4279"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood4281"
+         flood-opacity="0.7"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite4283"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur4285"
+         in="composite"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset4287"
+         dx="3"
+         dy="3"
+         result="offset" />
+      <feComposite
+         id="feComposite4289"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="3.8890873"
+     inkscape:cx="79.890469"
+     inkscape:cy="61.540294"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:document-units="px"
+     inkscape:grid-bbox="true"
+     inkscape:window-width="1149"
+     inkscape:window-height="913"
+     inkscape:window-x="419"
+     inkscape:window-y="39"
+     inkscape:window-maximized="0" />
+  <metadata
+     id="metadata3843">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     transform="translate(0,64)">
+    <g
+       id="g4238"
+       transform="translate(-1.0875019,1.1302528)"
+       style="filter:url(#filter4279);fill:#ffffff;stroke:#ffffff">
+      <g
+         id="g4199"
+         style="fill:#ffffff;stroke:#ffffff">
+        <path
+           style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.02571297000000000;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+           d="M 45.951523,45.677961 C 27.184494,40.714641 12.362921,25.664883 7.6037112,6.7397658 6.4660408,2.2157929 6.0560288,-1.1666201 6.0560288,-6.0279011 c 0,-5.4584779 0.533365,-9.8951559 1.6044734,-13.3464659 l 0.323999,-1.043983 12.4106888,0.05644 c 6.437899,0.02928 11.558356,-0.06862 11.627727,7.49e-4 0.06937,0.06937 -1.364536,7.106411 -1.519772,7.860089 -0.892047,4.3306369 -0.797329,9.7964989 0.239853,13.8411149 2.616556,10.2035681 10.427522,18.3046931 20.449236,21.2088731 1.250082,0.36226 2.295808,0.684994 2.323836,0.717186 0.04656,0.05348 -4.073393,21.15541 -4.391566,22.4931 -0.168132,0.70688 -0.195616,0.70618 -3.172981,-0.0812 l 0,0 z"
+           id="path3929"
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cssscsscsscsccc" />
+        <path
+           sodipodi:type="star"
+           style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.10000000000000001;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+           id="path3937"
+           sodipodi:sides="3"
+           sodipodi:cx="43.969185"
+           sodipodi:cy="13.320137"
+           sodipodi:r1="29.920004"
+           sodipodi:r2="14.960005"
+           sodipodi:arg1="0.42520502"
+           sodipodi:arg2="1.4724026"
+           inkscape:flatsided="false"
+           inkscape:rounded="0"
+           inkscape:randomized="0"
+           d="M 71.224937,25.662365 45.438782,28.207784 19.652626,30.753197 30.341306,7.1490216 41.029991,-16.455151 56.127467,4.6036055 z"
+           transform="matrix(0.92066016,-0.27223138,0.26609375,0.95690224,20.413951,36.096524)"
+           inkscape:transform-center-x="-5.314509"
+           inkscape:transform-center-y="-2.1952162" />
+      </g>
+      <g
+         id="g4199-5"
+         transform="matrix(-1,0,0,-1,124.00389,-2.7747651)"
+         style="fill:#ffffff;stroke:#ffffff">
+        <path
+           style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.02571297000000000;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+           d="M 45.951523,45.677961 C 27.184494,40.714641 12.362921,25.664883 7.6037112,6.7397658 6.4660408,2.2157929 6.0560288,-1.1666201 6.0560288,-6.0279011 c 0,-5.4584779 0.533365,-9.8951559 1.6044734,-13.3464659 l 0.323999,-1.043983 12.4106888,0.05644 c 6.437899,0.02928 11.558356,-0.06862 11.627727,7.49e-4 0.06937,0.06937 -1.364536,7.106411 -1.519772,7.860089 -0.892047,4.3306369 -0.797329,9.7964989 0.239853,13.8411149 2.616556,10.2035681 10.427522,18.3046931 20.449236,21.2088731 1.250082,0.36226 2.295808,0.684994 2.323836,0.717186 0.04656,0.05348 -4.073393,21.15541 -4.391566,22.4931 -0.168132,0.70688 -0.195616,0.70618 -3.172981,-0.0812 l 0,0 z"
+           id="path3929-9"
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cssscsscsscsccc" />
+        <path
+           sodipodi:type="star"
+           style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.10000000000000001;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+           id="path3937-8"
+           sodipodi:sides="3"
+           sodipodi:cx="43.969185"
+           sodipodi:cy="13.320137"
+           sodipodi:r1="29.920004"
+           sodipodi:r2="14.960005"
+           sodipodi:arg1="0.42520502"
+           sodipodi:arg2="1.4724026"
+           inkscape:flatsided="false"
+           inkscape:rounded="0"
+           inkscape:randomized="0"
+           d="M 71.224937,25.662365 45.438782,28.207784 19.652626,30.753197 30.341306,7.1490216 41.029991,-16.455151 56.127467,4.6036055 z"
+           transform="matrix(0.92066016,-0.27223138,0.26609375,0.95690224,20.413951,36.096524)"
+           inkscape:transform-center-x="-5.314509"
+           inkscape:transform-center-y="-2.1952162" />
+      </g>
+    </g>
+  </g>
+</svg>
diff --git a/themes/snowy/snowy/svg/os_win.svg b/themes/snowy/snowy/svg/os_win.svg
new file mode 100644 (file)
index 0000000..84d9221
--- /dev/null
@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="135"
+   height="135"
+   id="svg9607"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="os_win-02-white.svg"
+   inkscape:export-filename="/home/rodsmith/programming/refind/current/icons-build/os_win-white.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90">
+  <defs
+     id="defs9609">
+    <filter
+       id="filter3876"
+       inkscape:label="Drop Shadow"
+       color-interpolation-filters="sRGB">
+      <feFlood
+         id="feFlood3878"
+         flood-opacity="0.7"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite3880"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur3882"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset3884"
+         dx="3"
+         dy="3"
+         result="offset" />
+      <feComposite
+         id="feComposite3886"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="4.9497475"
+     inkscape:cx="67.177703"
+     inkscape:cy="66.261588"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:grid-bbox="true"
+     inkscape:document-units="px"
+     inkscape:window-width="1158"
+     inkscape:window-height="942"
+     inkscape:window-x="315"
+     inkscape:window-y="38"
+     inkscape:window-maximized="0" />
+  <metadata
+     id="metadata9612">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     transform="translate(0,87)">
+    <g
+       id="g9738"
+       transform="translate(0.40406172,-7.3741131)"
+       style="fill:#ffffff;stroke:#ffffff;filter:url(#filter3876)">
+      <path
+         sodipodi:nodetypes="ccccc"
+         inkscape:connector-curvature="0"
+         id="rect9615"
+         d="m 4.7203518,-11.741735 c 12.0209472,-14.272787 44.5029732,-16.021563 56.1714892,0 l 0,43.560551 c -13.716554,-12.936189 -38.510159,-14.30236 -56.1714892,0 z"
+         style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1.17263913" />
+      <path
+         sodipodi:nodetypes="ccccc"
+         inkscape:connector-curvature="0"
+         id="rect9615-6"
+         d="m 4.6350396,-64.86804 c 12.0209444,-14.272787 44.5029724,-16.021562 56.1714884,0 l 0,43.560551 c -12.154227,-12.865477 -36.38669,-14.364515 -56.1714884,0 z"
+         style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1.17263913" />
+      <path
+         sodipodi:nodetypes="ccccc"
+         inkscape:connector-curvature="0"
+         id="rect9615-6-7"
+         d="m 67.538565,-17.822259 c 12.020945,14.2727869 44.502975,16.0215625 56.171495,0 l 0,-43.56055 c -12.15423,12.865476 -36.386696,14.364514 -56.171495,0 z"
+         style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1.17263913" />
+      <path
+         sodipodi:nodetypes="ccccc"
+         inkscape:connector-curvature="0"
+         id="rect9615-6-7-5"
+         d="m 67.597521,34.686314 c 12.020945,14.272786 44.502979,16.021562 56.171499,0 l 0,-43.5605509 c -12.15423,12.8654779 -36.386701,14.3645156 -56.171499,0 z"
+         style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1.17263913" />
+    </g>
+  </g>
+</svg>
diff --git a/themes/snowy/snowy/svg/tool_apple_rescue.svg b/themes/snowy/snowy/svg/tool_apple_rescue.svg
new file mode 100644 (file)
index 0000000..4eea01c
--- /dev/null
@@ -0,0 +1,285 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="128"
+   height="128"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="tool_rescue-03-white.svg"
+   inkscape:export-filename="/home/rodsmith/programming/refind/current/icons-build/tool_apple_rescue-color.png"
+   inkscape:export-xdpi="33.75"
+   inkscape:export-ydpi="33.75">
+  <defs
+     id="defs4">
+    <filter
+       id="filter4020"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood4022"
+         flood-opacity="0.7"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite4024"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur4026"
+         in="composite"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset4028"
+         dx="3"
+         dy="3"
+         result="offset" />
+      <feComposite
+         id="feComposite4030"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+    <filter
+       color-interpolation-filters="sRGB"
+       id="filter14665"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood14667"
+         flood-opacity="0.7"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite14669"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur14671"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset14673"
+         dx="3"
+         dy="3"
+         result="offset" />
+      <feComposite
+         id="feComposite14675"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+    <filter
+       id="filter4265"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood4267"
+         flood-opacity="0.7"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite4269"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur4271"
+         in="composite"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset4273"
+         dx="3"
+         dy="3"
+         result="offset" />
+      <feComposite
+         id="feComposite4275"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+    <filter
+       color-interpolation-filters="sRGB"
+       id="filter14665-6"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood14667-0"
+         flood-opacity="0.7"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite14669-8"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur14671-8"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset14673-4"
+         dx="3"
+         dy="3"
+         result="offset" />
+      <feComposite
+         id="feComposite14675-8"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="5.6568542"
+     inkscape:cx="58.736442"
+     inkscape:cy="62.010384"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:window-width="1258"
+     inkscape:window-height="864"
+     inkscape:window-x="56"
+     inkscape:window-y="55"
+     inkscape:window-maximized="0" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(0,-924.36218)">
+    <g
+       id="g4230"
+       style="filter:url(#filter4265)">
+      <path
+         transform="matrix(1.2248505,0,0,1.4364973,92.650547,1024.9643)"
+         d="m 94.449261,47.440334 a 40.279831,34.345188 0 1 1 -80.559662,0 40.279831,34.345188 0 1 1 80.559662,0 z"
+         sodipodi:ry="34.345188"
+         sodipodi:rx="40.279831"
+         sodipodi:cy="47.440334"
+         sodipodi:cx="54.16943"
+         id="path2985-3"
+         style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+         sodipodi:type="arc" />
+      <path
+         sodipodi:end="0.57850209"
+         sodipodi:start="0"
+         transform="matrix(0.99677979,0,0,1.1202746,69.370944,858.30292)"
+         d="m 124,70.125 a 47.625,42.375 0 0 1 -7.74942,23.169395 L 76.375,70.125 z"
+         sodipodi:ry="42.375"
+         sodipodi:rx="47.625"
+         sodipodi:cy="70.125"
+         sodipodi:cx="76.375"
+         id="path3821"
+         style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+         sodipodi:type="arc" />
+      <path
+         sodipodi:end="0.59507843"
+         sodipodi:start="0"
+         transform="matrix(1.0556593,0,0,1.0160721,83.499721,975.2974)"
+         d="M 98.5,66.25 A 28.875,30 0 0 1 93.536518,83.067211 L 69.625,66.25 z"
+         sodipodi:ry="30"
+         sodipodi:rx="28.875"
+         sodipodi:cy="66.25"
+         sodipodi:cx="69.625"
+         id="path3823"
+         style="fill:#00ff00;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+         sodipodi:type="arc" />
+      <path
+         inkscape:connector-curvature="0"
+         id="path3908"
+         d="m 98.024003,1032.7108 c 0.02026,-0.018 0.445928,-0.3578 0.945938,-0.7545 3.827129,-3.0364 7.724779,-7.1691 10.636079,-11.2773 5.25842,-7.4205 8.62213,-15.9968 9.79337,-24.96976 0.61138,-4.68375 0.61236,-10.00319 0.003,-14.67246 -1.54864,-11.86114 -6.8758,-22.88873 -15.23228,-31.53185 l -0.96206,-0.99506 0.82236,0 0.82236,0 0.76686,0.81759 c 8.28714,8.8354 13.56701,20.0914 15.01907,32.01868 0.31201,2.56291 0.39435,4.03 0.39435,7.02687 0,3.12286 -0.0854,4.55096 -0.43576,7.29204 -1.7731,13.86985 -8.60863,26.60495 -19.22163,35.81145 l -1.458403,1.2651 -0.964906,10e-4 c -0.530699,6e-4 -0.948333,-0.014 -0.928078,-0.032 l 0,0 z"
+         style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.01767767;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+      <path
+         inkscape:connector-curvature="0"
+         id="path3910"
+         d="m 59.746269,1045.227 c -15.476753,-1.1683 -30.40188,-9.055 -40.124705,-21.2027 C 7.3819223,1008.7321 3.820095,988.87984 9.9916105,970.35055 14.061235,958.13195 22.21588,947.5803 32.996269,940.5838 c 12.68992,-8.23579 28.16082,-11.08922 43,-7.93088 12.091587,2.57356 23.598875,9.49688 31.549751,18.9818 12.84135,15.31898 16.79155,36.00361 10.45855,54.76458 -2.12403,6.2923 -4.65565,11.0863 -8.69274,16.4613 -11.342426,15.1011 -30.613336,23.7971 -49.565561,22.3664 z m 12.25,-1.4763 c 16.067732,-2.3739 30.057411,-11.3359 38.988471,-24.9764 1.96034,-2.994 4.78551,-8.8718 5.95333,-12.3859 2.15687,-6.49035 2.91056,-11.15083 2.90918,-17.98909 -0.002,-9.04369 -1.74171,-16.67528 -5.61411,-24.625 -5.395,-11.07551 -14.529599,-20.23123 -25.571481,-25.63059 -25.275035,-12.35922 -55.662768,-4.15116 -71.28779,19.25559 -4.476254,6.70557 -7.4833007,14.58394 -8.7920995,23.03505 -0.6087404,3.93073 -0.6067995,12.01119 0.00383,15.95604 4.0944105,26.451 24.9673735,45.7401 51.7856665,47.8562 2.296075,0.1812 8.969227,-0.1035 11.625,-0.4959 z"
+         style="fill:#000000;fill-opacity:1;stroke:#ffffff;stroke-width:0.05;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+      <path
+         inkscape:connector-curvature="0"
+         id="path3950"
+         d="m 79.017061,944.17252 c -2.039604,-0.23009 -3.855702,-1.49266 -4.810619,-3.34441 -0.552641,-1.07167 -0.6666,-1.56349 -0.667115,-2.87913 -4.01e-4,-1.02664 0.02561,-1.22438 0.244139,-1.85616 0.768074,-2.22051 2.514105,-3.76829 4.786376,-4.24292 1.089731,-0.22762 2.291346,-0.11521 3.465826,0.32422 1.71642,0.64219 3.262053,2.41201 3.740611,4.28315 0.212671,0.83153 0.228725,2.13143 0.03643,2.95011 -0.175827,0.7486 -0.722039,1.85836 -1.228619,2.49625 -1.277915,1.60915 -3.475574,2.50483 -5.567034,2.26889 z m 1.76249,-1.27419 c 1.805073,-0.37898 3.291066,-1.7583 3.808524,-3.53514 0.22681,-0.77882 0.213524,-2.04318 -0.02972,-2.82843 -0.644003,-2.07897 -2.374741,-3.43643 -4.530102,-3.55308 -2.263397,-0.1225 -4.152797,1.08745 -4.996231,3.19953 -0.324107,0.81161 -0.403728,2.17628 -0.177504,3.04233 0.691821,2.64848 3.251597,4.23609 5.925036,3.67479 z"
+         style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.01767767;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+      <path
+         inkscape:connector-curvature="0"
+         id="path3950-8"
+         d="m 113.64843,1009.7718 c -2.03961,-0.2301 -3.85571,-1.4926 -4.81062,-3.3444 -0.55264,-1.0717 -0.6666,-1.5635 -0.66712,-2.8791 -4e-4,-1.0267 0.0256,-1.2244 0.24414,-1.8562 0.76807,-2.2205 2.51411,-3.76828 4.78638,-4.24291 1.08973,-0.22762 2.29134,-0.11521 3.46582,0.32422 1.71642,0.64219 3.26205,2.41199 3.74061,4.28319 0.21267,0.8315 0.22873,2.1314 0.0364,2.9501 -0.17582,0.7486 -0.72204,1.8583 -1.22862,2.4962 -1.27791,1.6092 -3.47557,2.5049 -5.56703,2.2689 z m 1.76249,-1.2742 c 1.80507,-0.379 3.29106,-1.7583 3.80852,-3.5351 0.22681,-0.7788 0.21352,-2.0432 -0.0297,-2.8284 -0.644,-2.079 -2.37474,-3.43648 -4.5301,-3.55313 -2.2634,-0.1225 -4.1528,1.08745 -4.99623,3.19953 -0.32411,0.8116 -0.40373,2.1763 -0.17751,3.0423 0.69182,2.6485 3.2516,4.2361 5.92504,3.6748 z"
+         style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.01767767;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+      <path
+         inkscape:connector-curvature="0"
+         id="path3950-3"
+         d="m 13.416039,977.2449 c -2.039604,-0.23009 -3.8557017,-1.49266 -4.8106187,-3.34441 -0.552641,-1.07167 -0.6666,-1.56349 -0.667115,-2.87913 -4.01e-4,-1.02664 0.02561,-1.22438 0.244139,-1.85616 0.768074,-2.22051 2.5141047,-3.76829 4.7863757,-4.24292 1.089731,-0.22762 2.291346,-0.11521 3.465826,0.32422 1.716419,0.64219 3.262052,2.41201 3.74061,4.28315 0.212671,0.83153 0.228725,2.13143 0.03643,2.95011 -0.175827,0.7486 -0.722039,1.85836 -1.228619,2.49625 -1.277914,1.60915 -3.475573,2.50483 -5.567033,2.26889 z m 1.76249,-1.27419 c 1.805073,-0.37898 3.291065,-1.7583 3.808523,-3.53514 0.22681,-0.77882 0.213524,-2.04318 -0.02972,-2.82843 -0.644003,-2.07897 -2.37474,-3.43643 -4.530101,-3.55308 -2.263397,-0.1225 -4.152797,1.08745 -4.9962307,3.19953 -0.324107,0.81161 -0.403728,2.17628 -0.177504,3.04233 0.691821,2.64848 3.2515967,4.23609 5.9250357,3.67479 z"
+         style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.01767767;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+      <path
+         inkscape:connector-curvature="0"
+         id="path3950-9"
+         d="m 47.180387,1044.42 c -2.039604,-0.23 -3.855702,-1.4926 -4.810619,-3.3444 -0.552641,-1.0716 -0.6666,-1.5635 -0.667115,-2.8791 -4.01e-4,-1.0266 0.02561,-1.2244 0.244139,-1.8562 0.768074,-2.2205 2.514105,-3.7682 4.786376,-4.2429 1.089731,-0.2276 2.291346,-0.1152 3.465826,0.3242 1.71642,0.6422 3.262053,2.4121 3.740611,4.2832 0.212671,0.8315 0.228725,2.1314 0.03643,2.9501 -0.175827,0.7486 -0.722039,1.8584 -1.228619,2.4963 -1.277915,1.6091 -3.475574,2.5048 -5.567034,2.2688 z m 1.76249,-1.2741 c 1.805073,-0.379 3.291066,-1.7583 3.808524,-3.5352 0.22681,-0.7788 0.213524,-2.0432 -0.02972,-2.8284 -0.644003,-2.079 -2.374741,-3.4364 -4.530102,-3.5531 -2.263397,-0.1225 -4.152797,1.0875 -4.996231,3.1995 -0.324107,0.8116 -0.403728,2.1763 -0.177504,3.0424 0.691821,2.6484 3.251597,4.2361 5.925036,3.6748 z"
+         style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.01767767;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+      <path
+         inkscape:connector-curvature="0"
+         id="path3819"
+         d="m 58.825796,1036.3558 c -7.13374,-0.8237 -15.31012,-3.8196 -21.32741,-7.8145 -13.93838,-9.2537 -22.34958,-25.4869 -21.66992,-41.82188 0.82898,-19.92334 13.2809,-36.87427 32.16992,-43.79321 5.02534,-1.84075 10.01175,-2.68527 15.875,-2.68865 7.51891,-0.004 13.68968,1.34402 20.5,4.47936 12.69528,5.84466 22.888104,18.14664 26.353914,31.80724 4.17405,16.45216 -0.58961,33.60534 -12.728644,45.83374 -8.84111,8.9063 -20.3463,13.8055 -33.12527,14.1056 -2.3375,0.055 -5.05891,0.01 -6.04759,-0.1077 l 0,0 z m 11.54759,-18.3567 c 11.61583,-2.5315 20.6114,-11.4981 23.29842,-23.22328 0.58133,-2.5368 0.58133,-10.326 0,-12.86268 -2.4358,-10.62899 -10.25593,-19.24828 -20.33165,-22.40937 -3.77762,-1.18517 -4.52096,-1.2849 -9.46677,-1.27003 -5.30152,0.0159 -7.17681,0.35065 -11.3178,2.02007 -9.75903,3.9343 -16.87875,12.94281 -18.44607,23.33961 -0.94935,6.2976 0.0844,13.0011 2.8279,18.33828 3.17118,6.1692 7.54734,10.5177 13.68597,13.5993 3.05142,1.5319 6.38944,2.4712 10.375,2.9196 1.78781,0.2012 7.68316,-0.083 9.375,-0.4515 l 0,0 z"
+         style="fill:#e6e6e6;fill-opacity:1;stroke:#e6e6e6;stroke-width:0.25000000000000000;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+      <path
+         inkscape:connector-curvature="0"
+         id="path3827"
+         d="m 100.87127,1012.1422 c -1.375,-0.9095 -4.27177,-2.8071 -6.43726,-4.217 l -3.93727,-2.5634 1.22464,-2.4359 c 1.91042,-3.79993 3.27489,-8.83867 3.27489,-12.0936 l 0,-1.21726 7.91258,0 7.91258,0 -0.16005,2.44222 c -0.39094,5.96543 -2.08431,12.07724 -4.91389,17.73554 -0.96743,1.9346 -1.89786,3.6267 -2.0676,3.7603 -0.21726,0.1709 -1.04866,-0.2467 -2.80862,-1.4109 z"
+         style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.25;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+      <path
+         inkscape:connector-curvature="0"
+         id="path3827-9"
+         d="m 40.71027,1025.3243 c 0.9095,-1.375 2.8071,-4.2717 4.217,-6.4372 l 2.5634,-3.9373 2.4359,1.2247 c 3.7999,1.9104 8.83864,3.2748 12.09357,3.2748 l 1.21726,0 0,7.9126 0,7.9126 -2.44222,-0.16 c -5.96541,-0.391 -12.07721,-2.0844 -17.73551,-4.9139 -1.9346,-0.9675 -3.6267,-1.8979 -3.7603,-2.0676 -0.1709,-0.2173 0.2467,-1.0487 1.4109,-2.8087 z"
+         style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.25;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+      <path
+         inkscape:connector-curvature="0"
+         id="path3827-9-4"
+         d="m 26.53785,965.8224 c 1.375,0.9095 4.2717,2.8071 6.4372,4.217 l 3.9373,2.5634 -1.2247,2.4359 c -1.9104,3.7999 -3.2748,8.8387 -3.2748,12.0936 l 0,1.2172 -7.9126,0 -7.9126,0 0.16,-2.4422 c 0.391,-5.9654 2.0844,-12.0772 4.9139,-17.7355 0.9675,-1.9346 1.8979,-3.6267 2.0676,-3.7603 0.2173,-0.1709 1.0487,0.2467 2.8087,1.4109 z"
+         style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.25;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+      <path
+         inkscape:connector-curvature="0"
+         id="path3827-9-4-1"
+         d="m 87.039724,951.40003 c -0.9095,1.375 -2.8071,4.2717 -4.217,6.4372 l -2.5634,3.9373 -2.4359,-1.2247 c -3.7999,-1.9104 -8.8387,-3.2748 -12.0936,-3.2748 l -1.2172,0 0,-7.9126 0,-7.9126 2.4422,0.16 c 5.9654,0.391 12.0772,2.0844 17.7355,4.9139 1.9346,0.9675 3.6267,1.8979 3.7603,2.0676 0.1709,0.2173 -0.2467,1.0487 -1.4109,2.8087 z"
+         style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.25;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+    </g>
+    <path
+       style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.32269505;stroke-opacity:1;filter:url(#filter14665-6)"
+       d="m 50.272305,1048.635 c -23.632698,-3.6904 -42.2851829,-20.3961 -48.4280879,-43.3736 -2.44904595,-9.16075 -2.52286495,-19.84757 -0.20101,-29.10073 4.785011,-19.06943 19.1707529,-34.83217 37.7295879,-41.34105 10.5402,-3.69661 22.66072,-4.23179 33.72163,-1.48896 20.742487,5.1436 37.485925,21.9257 42.731355,42.83001 2.31728,9.23492 2.25409,19.96008 -0.1711,29.04073 -2.68918,10.0689 -7.44561,18.5151 -14.63835,25.9937 -9.141008,9.5044 -20.770915,15.4496 -34.154775,17.4598 -4.03276,0.6057 -12.64912,0.5954 -16.58925,-0.02 l 0,0 z m -2.61067,-31.918 c 5.75541,-10.2939 10.65007,-19.05915 10.87702,-19.47805 0.38653,-0.7136 1.08731,0.4705 11.07691,18.71635 l 10.66428,19.4781 5.52343,0.088 c 3.037877,0.049 5.523417,0 5.523417,-0.1164 0,-0.1125 -5.961307,-10.7742 -13.247367,-23.6926 l -13.24736,-23.48807 12.16117,-21.25027 c 6.68864,-11.68765 12.222887,-21.35919 12.298327,-21.4923 0.0754,-0.13311 -2.376337,-0.24122 -5.448377,-0.24024 l -5.58554,0.002 -9.5195,17.41583 c -5.23573,9.57872 -9.59927,17.41941 -9.69677,17.42376 -0.0975,0.004 -4.59909,-7.82862 -10.00355,-17.4066 l -9.82628,-17.41452 -5.56648,-0.011 c -3.06157,-0.006 -5.566495,0.0419 -5.566495,0.10654 0,0.0646 5.245075,9.10414 11.655715,20.08776 6.41064,10.98362 12.0743,20.70866 12.58591,21.61121 l 0.93019,1.64096 -13.43088,23.04524 c -7.38699,12.6748 -13.503164,23.2302 -13.591505,23.4563 -0.12713,0.3254 0.999733,0.3927 5.404365,0.3227 l 5.56498,-0.089 10.46439,-18.7163 0,0 z"
+       id="path14663"
+       inkscape:connector-curvature="0"
+       transform="matrix(0.5,0,0,0.5,34.63178,493.18627)" />
+  </g>
+</svg>
diff --git a/themes/snowy/snowy/svg/tool_memtest.svg b/themes/snowy/snowy/svg/tool_memtest.svg
new file mode 100644 (file)
index 0000000..e73d5a8
--- /dev/null
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="128"
+   height="128"
+   id="svg9250"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="New document 51">
+  <defs
+     id="defs9252" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="4"
+     inkscape:cx="66.1575"
+     inkscape:cy="61.220758"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:document-units="px"
+     inkscape:grid-bbox="true"
+     inkscape:window-width="875"
+     inkscape:window-height="925"
+     inkscape:window-x="696"
+     inkscape:window-y="29"
+     inkscape:window-maximized="0" />
+  <metadata
+     id="metadata9255">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     transform="translate(0,64)">
+    <rect
+       style="fill:#ffffff;fill-opacity:1;stroke:#999999"
+       id="rect9258"
+       width="104.75"
+       height="41"
+       x="13.75"
+       y="19.25"
+       transform="translate(0,-64)" />
+    <rect
+       style="fill:#ffffff;fill-opacity:1;stroke:#999999"
+       id="rect9260"
+       width="59.5"
+       height="9"
+       x="13.75"
+       y="60.25"
+       transform="translate(0,-64)" />
+    <rect
+       style="fill:#ffffff;fill-opacity:1;stroke:#999999"
+       id="rect9262"
+       width="41"
+       height="9"
+       x="77.5"
+       y="60.5"
+       transform="translate(0,-64)" />
+    <rect
+       style="fill:#ffffff;fill-opacity:1;stroke:#999999"
+       id="rect9264"
+       width="19"
+       height="26.5"
+       x="22.5"
+       y="26.75"
+       transform="translate(0,-64)" />
+    <rect
+       style="fill:#ffffff;fill-opacity:1;stroke:#999999"
+       id="rect9264-2"
+       width="19"
+       height="26.5"
+       x="54.25"
+       y="-37.25" />
+    <rect
+       style="fill:#ffffff;fill-opacity:1;stroke:#999999"
+       id="rect9264-4"
+       width="19"
+       height="26.5"
+       x="87.5"
+       y="-37" />
+  </g>
+</svg>
diff --git a/themes/snowy/snowy/svg/tool_rescue.png b/themes/snowy/snowy/svg/tool_rescue.png
new file mode 100644 (file)
index 0000000..4a251b4
--- /dev/null
@@ -0,0 +1,248 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="128"
+   height="128"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="tool_apple_rescue-color.svg"
+   inkscape:export-filename="/home/rodsmith/programming/refind/current/icons-build/tool_apple_rescue-color.png"
+   inkscape:export-xdpi="33.75"
+   inkscape:export-ydpi="33.75">
+  <defs
+     id="defs4">
+    <filter
+       id="filter4020"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood4022"
+         flood-opacity="0.7"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite4024"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur4026"
+         in="composite"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset4028"
+         dx="3"
+         dy="3"
+         result="offset" />
+      <feComposite
+         id="feComposite4030"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+    <filter
+       color-interpolation-filters="sRGB"
+       id="filter14665"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood14667"
+         flood-opacity="0.7"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite14669"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur14671"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset14673"
+         dx="3"
+         dy="3"
+         result="offset" />
+      <feComposite
+         id="feComposite14675"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+    <filter
+       id="filter4265"
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood4267"
+         flood-opacity="0.7"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite4269"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur4271"
+         in="composite"
+         stdDeviation="3"
+         result="blur" />
+      <feOffset
+         id="feOffset4273"
+         dx="3"
+         dy="3"
+         result="offset" />
+      <feComposite
+         id="feComposite4275"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="5.6568542"
+     inkscape:cx="58.736442"
+     inkscape:cy="62.010384"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:window-width="1258"
+     inkscape:window-height="864"
+     inkscape:window-x="56"
+     inkscape:window-y="55"
+     inkscape:window-maximized="0" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(0,-924.36218)">
+    <g
+       id="g4230"
+       style="filter:url(#filter4265)">
+      <path
+         transform="matrix(1.2248505,0,0,1.4364973,92.650547,1024.9643)"
+         d="m 94.449261,47.440334 a 40.279831,34.345188 0 1 1 -80.559662,0 40.279831,34.345188 0 1 1 80.559662,0 z"
+         sodipodi:ry="34.345188"
+         sodipodi:rx="40.279831"
+         sodipodi:cy="47.440334"
+         sodipodi:cx="54.16943"
+         id="path2985-3"
+         style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+         sodipodi:type="arc" />
+      <path
+         sodipodi:end="0.57850209"
+         sodipodi:start="0"
+         transform="matrix(0.99677979,0,0,1.1202746,69.370944,858.30292)"
+         d="m 124,70.125 a 47.625,42.375 0 0 1 -7.74942,23.169395 L 76.375,70.125 z"
+         sodipodi:ry="42.375"
+         sodipodi:rx="47.625"
+         sodipodi:cy="70.125"
+         sodipodi:cx="76.375"
+         id="path3821"
+         style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+         sodipodi:type="arc" />
+      <path
+         sodipodi:end="0.59507843"
+         sodipodi:start="0"
+         transform="matrix(1.0556593,0,0,1.0160721,83.499721,975.2974)"
+         d="M 98.5,66.25 A 28.875,30 0 0 1 93.536518,83.067211 L 69.625,66.25 z"
+         sodipodi:ry="30"
+         sodipodi:rx="28.875"
+         sodipodi:cy="66.25"
+         sodipodi:cx="69.625"
+         id="path3823"
+         style="fill:#00ff00;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+         sodipodi:type="arc" />
+      <path
+         inkscape:connector-curvature="0"
+         id="path3908"
+         d="m 98.024003,1032.7108 c 0.02026,-0.018 0.445928,-0.3578 0.945938,-0.7545 3.827129,-3.0364 7.724779,-7.1691 10.636079,-11.2773 5.25842,-7.4205 8.62213,-15.9968 9.79337,-24.96976 0.61138,-4.68375 0.61236,-10.00319 0.003,-14.67246 -1.54864,-11.86114 -6.8758,-22.88873 -15.23228,-31.53185 l -0.96206,-0.99506 0.82236,0 0.82236,0 0.76686,0.81759 c 8.28714,8.8354 13.56701,20.0914 15.01907,32.01868 0.31201,2.56291 0.39435,4.03 0.39435,7.02687 0,3.12286 -0.0854,4.55096 -0.43576,7.29204 -1.7731,13.86985 -8.60863,26.60495 -19.22163,35.81145 l -1.458403,1.2651 -0.964906,10e-4 c -0.530699,6e-4 -0.948333,-0.014 -0.928078,-0.032 l 0,0 z"
+         style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.01767767;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+      <path
+         inkscape:connector-curvature="0"
+         id="path3910"
+         d="m 59.746269,1045.227 c -15.476753,-1.1683 -30.40188,-9.055 -40.124705,-21.2027 C 7.3819223,1008.7321 3.820095,988.87984 9.9916105,970.35055 14.061235,958.13195 22.21588,947.5803 32.996269,940.5838 c 12.68992,-8.23579 28.16082,-11.08922 43,-7.93088 12.091587,2.57356 23.598875,9.49688 31.549751,18.9818 12.84135,15.31898 16.79155,36.00361 10.45855,54.76458 -2.12403,6.2923 -4.65565,11.0863 -8.69274,16.4613 -11.342426,15.1011 -30.613336,23.7971 -49.565561,22.3664 z m 12.25,-1.4763 c 16.067732,-2.3739 30.057411,-11.3359 38.988471,-24.9764 1.96034,-2.994 4.78551,-8.8718 5.95333,-12.3859 2.15687,-6.49035 2.91056,-11.15083 2.90918,-17.98909 -0.002,-9.04369 -1.74171,-16.67528 -5.61411,-24.625 -5.395,-11.07551 -14.529599,-20.23123 -25.571481,-25.63059 -25.275035,-12.35922 -55.662768,-4.15116 -71.28779,19.25559 -4.476254,6.70557 -7.4833007,14.58394 -8.7920995,23.03505 -0.6087404,3.93073 -0.6067995,12.01119 0.00383,15.95604 4.0944105,26.451 24.9673735,45.7401 51.7856665,47.8562 2.296075,0.1812 8.969227,-0.1035 11.625,-0.4959 z"
+         style="fill:#000000;fill-opacity:1;stroke:#ffffff;stroke-width:0.05;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+      <path
+         inkscape:connector-curvature="0"
+         id="path3950"
+         d="m 79.017061,944.17252 c -2.039604,-0.23009 -3.855702,-1.49266 -4.810619,-3.34441 -0.552641,-1.07167 -0.6666,-1.56349 -0.667115,-2.87913 -4.01e-4,-1.02664 0.02561,-1.22438 0.244139,-1.85616 0.768074,-2.22051 2.514105,-3.76829 4.786376,-4.24292 1.089731,-0.22762 2.291346,-0.11521 3.465826,0.32422 1.71642,0.64219 3.262053,2.41201 3.740611,4.28315 0.212671,0.83153 0.228725,2.13143 0.03643,2.95011 -0.175827,0.7486 -0.722039,1.85836 -1.228619,2.49625 -1.277915,1.60915 -3.475574,2.50483 -5.567034,2.26889 z m 1.76249,-1.27419 c 1.805073,-0.37898 3.291066,-1.7583 3.808524,-3.53514 0.22681,-0.77882 0.213524,-2.04318 -0.02972,-2.82843 -0.644003,-2.07897 -2.374741,-3.43643 -4.530102,-3.55308 -2.263397,-0.1225 -4.152797,1.08745 -4.996231,3.19953 -0.324107,0.81161 -0.403728,2.17628 -0.177504,3.04233 0.691821,2.64848 3.251597,4.23609 5.925036,3.67479 z"
+         style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.01767767;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+      <path
+         inkscape:connector-curvature="0"
+         id="path3950-8"
+         d="m 113.64843,1009.7718 c -2.03961,-0.2301 -3.85571,-1.4926 -4.81062,-3.3444 -0.55264,-1.0717 -0.6666,-1.5635 -0.66712,-2.8791 -4e-4,-1.0267 0.0256,-1.2244 0.24414,-1.8562 0.76807,-2.2205 2.51411,-3.76828 4.78638,-4.24291 1.08973,-0.22762 2.29134,-0.11521 3.46582,0.32422 1.71642,0.64219 3.26205,2.41199 3.74061,4.28319 0.21267,0.8315 0.22873,2.1314 0.0364,2.9501 -0.17582,0.7486 -0.72204,1.8583 -1.22862,2.4962 -1.27791,1.6092 -3.47557,2.5049 -5.56703,2.2689 z m 1.76249,-1.2742 c 1.80507,-0.379 3.29106,-1.7583 3.80852,-3.5351 0.22681,-0.7788 0.21352,-2.0432 -0.0297,-2.8284 -0.644,-2.079 -2.37474,-3.43648 -4.5301,-3.55313 -2.2634,-0.1225 -4.1528,1.08745 -4.99623,3.19953 -0.32411,0.8116 -0.40373,2.1763 -0.17751,3.0423 0.69182,2.6485 3.2516,4.2361 5.92504,3.6748 z"
+         style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.01767767;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+      <path
+         inkscape:connector-curvature="0"
+         id="path3950-3"
+         d="m 13.416039,977.2449 c -2.039604,-0.23009 -3.8557017,-1.49266 -4.8106187,-3.34441 -0.552641,-1.07167 -0.6666,-1.56349 -0.667115,-2.87913 -4.01e-4,-1.02664 0.02561,-1.22438 0.244139,-1.85616 0.768074,-2.22051 2.5141047,-3.76829 4.7863757,-4.24292 1.089731,-0.22762 2.291346,-0.11521 3.465826,0.32422 1.716419,0.64219 3.262052,2.41201 3.74061,4.28315 0.212671,0.83153 0.228725,2.13143 0.03643,2.95011 -0.175827,0.7486 -0.722039,1.85836 -1.228619,2.49625 -1.277914,1.60915 -3.475573,2.50483 -5.567033,2.26889 z m 1.76249,-1.27419 c 1.805073,-0.37898 3.291065,-1.7583 3.808523,-3.53514 0.22681,-0.77882 0.213524,-2.04318 -0.02972,-2.82843 -0.644003,-2.07897 -2.37474,-3.43643 -4.530101,-3.55308 -2.263397,-0.1225 -4.152797,1.08745 -4.9962307,3.19953 -0.324107,0.81161 -0.403728,2.17628 -0.177504,3.04233 0.691821,2.64848 3.2515967,4.23609 5.9250357,3.67479 z"
+         style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.01767767;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+      <path
+         inkscape:connector-curvature="0"
+         id="path3950-9"
+         d="m 47.180387,1044.42 c -2.039604,-0.23 -3.855702,-1.4926 -4.810619,-3.3444 -0.552641,-1.0716 -0.6666,-1.5635 -0.667115,-2.8791 -4.01e-4,-1.0266 0.02561,-1.2244 0.244139,-1.8562 0.768074,-2.2205 2.514105,-3.7682 4.786376,-4.2429 1.089731,-0.2276 2.291346,-0.1152 3.465826,0.3242 1.71642,0.6422 3.262053,2.4121 3.740611,4.2832 0.212671,0.8315 0.228725,2.1314 0.03643,2.9501 -0.175827,0.7486 -0.722039,1.8584 -1.228619,2.4963 -1.277915,1.6091 -3.475574,2.5048 -5.567034,2.2688 z m 1.76249,-1.2741 c 1.805073,-0.379 3.291066,-1.7583 3.808524,-3.5352 0.22681,-0.7788 0.213524,-2.0432 -0.02972,-2.8284 -0.644003,-2.079 -2.374741,-3.4364 -4.530102,-3.5531 -2.263397,-0.1225 -4.152797,1.0875 -4.996231,3.1995 -0.324107,0.8116 -0.403728,2.1763 -0.177504,3.0424 0.691821,2.6484 3.251597,4.2361 5.925036,3.6748 z"
+         style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.01767767;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+      <path
+         inkscape:connector-curvature="0"
+         id="path3819"
+         d="m 58.825796,1036.3558 c -7.13374,-0.8237 -15.31012,-3.8196 -21.32741,-7.8145 -13.93838,-9.2537 -22.34958,-25.4869 -21.66992,-41.82188 0.82898,-19.92334 13.2809,-36.87427 32.16992,-43.79321 5.02534,-1.84075 10.01175,-2.68527 15.875,-2.68865 7.51891,-0.004 13.68968,1.34402 20.5,4.47936 12.69528,5.84466 22.888104,18.14664 26.353914,31.80724 4.17405,16.45216 -0.58961,33.60534 -12.728644,45.83374 -8.84111,8.9063 -20.3463,13.8055 -33.12527,14.1056 -2.3375,0.055 -5.05891,0.01 -6.04759,-0.1077 l 0,0 z m 11.54759,-18.3567 c 11.61583,-2.5315 20.6114,-11.4981 23.29842,-23.22328 0.58133,-2.5368 0.58133,-10.326 0,-12.86268 -2.4358,-10.62899 -10.25593,-19.24828 -20.33165,-22.40937 -3.77762,-1.18517 -4.52096,-1.2849 -9.46677,-1.27003 -5.30152,0.0159 -7.17681,0.35065 -11.3178,2.02007 -9.75903,3.9343 -16.87875,12.94281 -18.44607,23.33961 -0.94935,6.2976 0.0844,13.0011 2.8279,18.33828 3.17118,6.1692 7.54734,10.5177 13.68597,13.5993 3.05142,1.5319 6.38944,2.4712 10.375,2.9196 1.78781,0.2012 7.68316,-0.083 9.375,-0.4515 l 0,0 z"
+         style="fill:#e6e6e6;fill-opacity:1;stroke:#e6e6e6;stroke-width:0.25000000000000000;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+      <path
+         inkscape:connector-curvature="0"
+         id="path3827"
+         d="m 100.87127,1012.1422 c -1.375,-0.9095 -4.27177,-2.8071 -6.43726,-4.217 l -3.93727,-2.5634 1.22464,-2.4359 c 1.91042,-3.79993 3.27489,-8.83867 3.27489,-12.0936 l 0,-1.21726 7.91258,0 7.91258,0 -0.16005,2.44222 c -0.39094,5.96543 -2.08431,12.07724 -4.91389,17.73554 -0.96743,1.9346 -1.89786,3.6267 -2.0676,3.7603 -0.21726,0.1709 -1.04866,-0.2467 -2.80862,-1.4109 z"
+         style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.25;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+      <path
+         inkscape:connector-curvature="0"
+         id="path3827-9"
+         d="m 40.71027,1025.3243 c 0.9095,-1.375 2.8071,-4.2717 4.217,-6.4372 l 2.5634,-3.9373 2.4359,1.2247 c 3.7999,1.9104 8.83864,3.2748 12.09357,3.2748 l 1.21726,0 0,7.9126 0,7.9126 -2.44222,-0.16 c -5.96541,-0.391 -12.07721,-2.0844 -17.73551,-4.9139 -1.9346,-0.9675 -3.6267,-1.8979 -3.7603,-2.0676 -0.1709,-0.2173 0.2467,-1.0487 1.4109,-2.8087 z"
+         style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.25;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+      <path
+         inkscape:connector-curvature="0"
+         id="path3827-9-4"
+         d="m 26.53785,965.8224 c 1.375,0.9095 4.2717,2.8071 6.4372,4.217 l 3.9373,2.5634 -1.2247,2.4359 c -1.9104,3.7999 -3.2748,8.8387 -3.2748,12.0936 l 0,1.2172 -7.9126,0 -7.9126,0 0.16,-2.4422 c 0.391,-5.9654 2.0844,-12.0772 4.9139,-17.7355 0.9675,-1.9346 1.8979,-3.6267 2.0676,-3.7603 0.2173,-0.1709 1.0487,0.2467 2.8087,1.4109 z"
+         style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.25;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+      <path
+         inkscape:connector-curvature="0"
+         id="path3827-9-4-1"
+         d="m 87.039724,951.40003 c -0.9095,1.375 -2.8071,4.2717 -4.217,6.4372 l -2.5634,3.9373 -2.4359,-1.2247 c -3.7999,-1.9104 -8.8387,-3.2748 -12.0936,-3.2748 l -1.2172,0 0,-7.9126 0,-7.9126 2.4422,0.16 c 5.9654,0.391 12.0772,2.0844 17.7355,4.9139 1.9346,0.9675 3.6267,1.8979 3.7603,2.0676 0.1709,0.2173 -0.2467,1.0487 -1.4109,2.8087 z"
+         style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.25;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+    </g>
+  </g>
+</svg>
diff --git a/themes/snowy/snowy/tool_apple_rescue.png b/themes/snowy/snowy/tool_apple_rescue.png
new file mode 100644 (file)
index 0000000..5869748
Binary files /dev/null and b/themes/snowy/snowy/tool_apple_rescue.png differ
diff --git a/themes/snowy/snowy/tool_memtest.png b/themes/snowy/snowy/tool_memtest.png
new file mode 100644 (file)
index 0000000..46e0d6b
Binary files /dev/null and b/themes/snowy/snowy/tool_memtest.png differ
diff --git a/themes/snowy/snowy/tool_mok_tool.png b/themes/snowy/snowy/tool_mok_tool.png
new file mode 100644 (file)
index 0000000..16b0232
Binary files /dev/null and b/themes/snowy/snowy/tool_mok_tool.png differ
diff --git a/themes/snowy/snowy/tool_netboot.png b/themes/snowy/snowy/tool_netboot.png
new file mode 100644 (file)
index 0000000..c63c278
Binary files /dev/null and b/themes/snowy/snowy/tool_netboot.png differ
diff --git a/themes/snowy/snowy/tool_part.png b/themes/snowy/snowy/tool_part.png
new file mode 100644 (file)
index 0000000..9a4a400
Binary files /dev/null and b/themes/snowy/snowy/tool_part.png differ
diff --git a/themes/snowy/snowy/tool_rescue.png b/themes/snowy/snowy/tool_rescue.png
new file mode 100644 (file)
index 0000000..f1213c1
Binary files /dev/null and b/themes/snowy/snowy/tool_rescue.png differ
diff --git a/themes/snowy/snowy/tool_shell.png b/themes/snowy/snowy/tool_shell.png
new file mode 100644 (file)
index 0000000..f2d9ddc
Binary files /dev/null and b/themes/snowy/snowy/tool_shell.png differ
diff --git a/themes/snowy/snowy/tool_windows_rescue.png b/themes/snowy/snowy/tool_windows_rescue.png
new file mode 100644 (file)
index 0000000..6984d72
Binary files /dev/null and b/themes/snowy/snowy/tool_windows_rescue.png differ
diff --git a/themes/snowy/snowy/transparent.png b/themes/snowy/snowy/transparent.png
new file mode 100644 (file)
index 0000000..433cc88
Binary files /dev/null and b/themes/snowy/snowy/transparent.png differ
diff --git a/themes/snowy/snowy/vol_external.png b/themes/snowy/snowy/vol_external.png
new file mode 100644 (file)
index 0000000..2de389d
Binary files /dev/null and b/themes/snowy/snowy/vol_external.png differ
diff --git a/themes/snowy/snowy/vol_internal.png b/themes/snowy/snowy/vol_internal.png
new file mode 100644 (file)
index 0000000..96264ac
Binary files /dev/null and b/themes/snowy/snowy/vol_internal.png differ
diff --git a/themes/snowy/snowy/vol_net.png b/themes/snowy/snowy/vol_net.png
new file mode 100644 (file)
index 0000000..c16ee27
Binary files /dev/null and b/themes/snowy/snowy/vol_net.png differ
diff --git a/themes/snowy/snowy/vol_optical.png b/themes/snowy/snowy/vol_optical.png
new file mode 100644 (file)
index 0000000..f9bcf23
Binary files /dev/null and b/themes/snowy/snowy/vol_optical.png differ