From af1a266670d040d2f4083ff309d732d648afba2a Mon Sep 17 00:00:00 2001
From: Angelos Mouzakitis <a.mouzakitis@virtualopensystems.com>
Date: Tue, 10 Oct 2023 14:33:42 +0000
Subject: Add submodule dependency files

Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec
---
 roms/openbios/fs/hfsplus/build.xml           |  11 +
 roms/openbios/fs/hfsplus/hfsp_blockiter.c    | 141 +++++
 roms/openbios/fs/hfsplus/hfsp_btree.c        | 372 +++++++++++++
 roms/openbios/fs/hfsplus/hfsp_fs.c           | 630 ++++++++++++++++++++++
 roms/openbios/fs/hfsplus/hfsp_record.c       | 759 +++++++++++++++++++++++++++
 roms/openbios/fs/hfsplus/hfsp_unicode.c      | 511 ++++++++++++++++++
 roms/openbios/fs/hfsplus/hfsp_volume.c       | 323 ++++++++++++
 roms/openbios/fs/hfsplus/include/apple.h     | 111 ++++
 roms/openbios/fs/hfsplus/include/blockiter.h |  59 +++
 roms/openbios/fs/hfsplus/include/btree.h     |  50 ++
 roms/openbios/fs/hfsplus/include/hfs.h       |  32 ++
 roms/openbios/fs/hfsplus/include/hfsp.h      | 305 +++++++++++
 roms/openbios/fs/hfsplus/include/hfstime.h   |  34 ++
 roms/openbios/fs/hfsplus/include/libhfsp.h   | 201 +++++++
 roms/openbios/fs/hfsplus/include/record.h    |  80 +++
 roms/openbios/fs/hfsplus/include/swab.h      |  64 +++
 roms/openbios/fs/hfsplus/include/unicode.h   |  28 +
 roms/openbios/fs/hfsplus/include/volume.h    |  87 +++
 roms/openbios/fs/hfsplus/libhfsp.c           |  29 +
 19 files changed, 3827 insertions(+)
 create mode 100644 roms/openbios/fs/hfsplus/build.xml
 create mode 100644 roms/openbios/fs/hfsplus/hfsp_blockiter.c
 create mode 100644 roms/openbios/fs/hfsplus/hfsp_btree.c
 create mode 100644 roms/openbios/fs/hfsplus/hfsp_fs.c
 create mode 100644 roms/openbios/fs/hfsplus/hfsp_record.c
 create mode 100644 roms/openbios/fs/hfsplus/hfsp_unicode.c
 create mode 100644 roms/openbios/fs/hfsplus/hfsp_volume.c
 create mode 100644 roms/openbios/fs/hfsplus/include/apple.h
 create mode 100644 roms/openbios/fs/hfsplus/include/blockiter.h
 create mode 100644 roms/openbios/fs/hfsplus/include/btree.h
 create mode 100644 roms/openbios/fs/hfsplus/include/hfs.h
 create mode 100644 roms/openbios/fs/hfsplus/include/hfsp.h
 create mode 100644 roms/openbios/fs/hfsplus/include/hfstime.h
 create mode 100644 roms/openbios/fs/hfsplus/include/libhfsp.h
 create mode 100644 roms/openbios/fs/hfsplus/include/record.h
 create mode 100644 roms/openbios/fs/hfsplus/include/swab.h
 create mode 100644 roms/openbios/fs/hfsplus/include/unicode.h
 create mode 100644 roms/openbios/fs/hfsplus/include/volume.h
 create mode 100644 roms/openbios/fs/hfsplus/libhfsp.c

(limited to 'roms/openbios/fs/hfsplus')

diff --git a/roms/openbios/fs/hfsplus/build.xml b/roms/openbios/fs/hfsplus/build.xml
new file mode 100644
index 000000000..5f4c28869
--- /dev/null
+++ b/roms/openbios/fs/hfsplus/build.xml
@@ -0,0 +1,11 @@
+<build>
+ <library name="fs" type="static" target="target">
+  <object source="hfsp_blockiter.c" flags="-I$(SRCDIR)/fs/hfsplus/include -I$(SRCDIR)/fs/ -fno-strict-aliasing" condition="HFSP"/>
+  <object source="hfsp_btree.c" flags="-I$(SRCDIR)/fs/hfsplus/include -I$(SRCDIR)/fs/ -fno-strict-aliasing" condition="HFSP"/>
+  <object source="libhfsp.c" flags="-I$(SRCDIR)/fs/hfsplus/include -I$(SRCDIR)/fs/ -fno-strict-aliasing" condition="HFSP"/>
+  <object source="hfsp_record.c" flags="-I$(SRCDIR)/fs/hfsplus/include -I$(SRCDIR)/fs/ -fno-strict-aliasing" condition="HFSP"/>
+  <object source="hfsp_unicode.c" flags="-I$(SRCDIR)/fs/hfsplus/include -I$(SRCDIR)/fs/ -fno-strict-aliasing" condition="HFSP"/>
+  <object source="hfsp_volume.c" flags="-I$(SRCDIR)/fs/hfsplus/include -I$(SRCDIR)/fs/ -fno-strict-aliasing" condition="HFSP"/>
+  <object source="hfsp_fs.c" flags="-I$(SRCDIR)/fs/hfsplus/include -I$(SRCDIR)/fs/ -fno-strict-aliasing" condition="HFSP"/>
+ </library>
+</build>
diff --git a/roms/openbios/fs/hfsplus/hfsp_blockiter.c b/roms/openbios/fs/hfsplus/hfsp_blockiter.c
new file mode 100644
index 000000000..e91009229
--- /dev/null
+++ b/roms/openbios/fs/hfsplus/hfsp_blockiter.c
@@ -0,0 +1,141 @@
+/*
+ * libhfs - library for reading and writing Macintosh HFS volumes
+ *
+ * The iterator shown here iterates over the blocks of a fork.
+ *
+ * Copyright (C) 2000 Klaus Halfmann <khalfmann@libra.de>
+ * Original work by 1996-1998 Robert Leslie <rob@mars.org>
+ * other work 2000 from Brad Boyer (flar@pants.nu)
+ *
+ * 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.
+ *
+ * $Id: blockiter.c,v 1.2 2000/10/17 05:58:46 hasi Exp $
+ */
+
+#include "config.h"
+#include "libhfsp.h"
+#include "blockiter.h"
+#include "volume.h"
+#include "record.h"
+#include "btree.h"
+#include "os.h"
+#include "swab.h"
+#include "hfstime.h"
+
+/* Initialize iterator for a given fork */
+void
+blockiter_init(blockiter* b, volume* vol, hfsp_fork_raw* f,
+		    UInt8 forktype, UInt32 fileId)
+{
+    b->vol	    = vol;
+    b->curr_block   = 0;
+    b->block	    = 0;
+    b->max_block    = f->total_blocks;
+    b->fileId	    = fileId;
+    b->index	    = 0;
+    b->file	    = f->extents;
+    b->e	    = f->extents;
+    b->forktype	    = forktype;
+    b->in_extent    = 0;
+}
+
+/* get next extent record when needed */
+static int
+blockiter_next_extent(blockiter *b)
+{
+    btree*  extents_tree = volume_get_extents_tree(b->vol);
+    int	    err;
+
+    b->index = 0;
+    if (b->in_extent) // already using extents record ?
+    {
+	err = record_next_extent(&b->er);
+	// Hope there is no need to check this ...
+	// if (b->er.key.start_block != b->curr_block)
+	//     HFSP_ERROR(ENOENT,
+	//	"Extents record inconistent");
+    }
+    else
+    {
+	err = record_init_file(&b->er, extents_tree, b->forktype,
+		b->fileId, b->curr_block);
+	b->in_extent = -1;  // true
+    }
+    b->e = b->er.extent;
+    return err;
+}
+
+/* find next block of the fork iterating over */
+int
+blockiter_next(blockiter *b)
+{
+    b->curr_block ++;
+    b->block ++;
+    if (b->curr_block >= b->max_block)
+	return -1; // end of Blocks, but no error
+    // in current part of extent ?
+    if (b->block >= b->e->block_count)
+    {
+	b->index++;
+	b->block = 0;		// reset relative position
+	b->e++;
+	if (b -> index >= 8)	// need to fetch another extent
+	{
+	    if (blockiter_next_extent(b))
+		HFSP_ERROR(ENOENT, "Extends record not found.");
+	}
+    }
+    return 0;
+
+  fail:
+    return -1;
+}
+
+/* skip the indicated number of blocks */
+int
+blockiter_skip(blockiter *b, UInt32 skip)
+{
+    while (skip > 0)
+    {
+	// Skip to skip or end of current extent
+	UInt32 diff = b->e->block_count - b->block;
+	if (skip < diff)
+	{
+	    diff = skip;
+	    skip = 0;
+	}
+	else
+	    skip -= diff;
+	b->curr_block += diff;
+	b->block      += diff;
+	if (b->curr_block >= b->max_block)
+	    return -1;	// end of Blocks, but no error
+	if (b->block >= b->e->block_count)
+	{
+	    b->index++;
+	    b->block = 0;		// reset relative position
+	    b->e++;
+	    if (b -> index >= 8)	// need to fetch another extent
+	    {
+		if (blockiter_next_extent(b))
+		    HFSP_ERROR(ENOENT, "Extends record not found.");
+	    }
+	}
+    } // we are here when skip was null, thats ok
+    return 0;
+  fail:
+    return -1;
+}
diff --git a/roms/openbios/fs/hfsplus/hfsp_btree.c b/roms/openbios/fs/hfsplus/hfsp_btree.c
new file mode 100644
index 000000000..24eca924c
--- /dev/null
+++ b/roms/openbios/fs/hfsplus/hfsp_btree.c
@@ -0,0 +1,372 @@
+/*
+ * libhfs - library for reading and writing Macintosh HFS volumes
+ * The fucntions are used to handle the various forms of btrees
+ * found on HFS+ volumes.
+ *
+ * The fucntions are used to handle the various forms of btrees
+ * found on HFS+ volumes.
+ *
+ * Copyright (C) 2000 Klaus Halfmann <khalfmann@libra.de>
+ * Original 1996-1998 Robert Leslie <rob@mars.org>
+ * Additional work by  Brad Boyer (flar@pants.nu)
+ *
+ * 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.
+ *
+ * $Id: btree.c,v 1.14 2000/10/25 05:43:04 hasi Exp $
+ */
+
+#include "config.h"
+#include "libhfsp.h"
+#include "volume.h"
+#include "btree.h"
+#include "record.h"
+#include "swab.h"
+
+/* Read the node from the given buffer and swap the bytes.
+ *
+ * return pointer after reading the structure
+ */
+static void* btree_readnode(btree_node_desc* node, void *p)
+{
+    node->next	    = bswabU32_inc(p);
+    node->prev	    = bswabU32_inc(p);
+    node->kind	    = bswabU8_inc(p);
+    node->height    = bswabU8_inc(p);
+    node->num_rec   = bswabU16_inc(p);
+    node->reserved  = bswabU16_inc(p);
+    return p;
+}
+
+/* read a btree header from the given buffer and swap the bytes.
+ *
+ * return pointer after reading the structure
+ */
+static void* btree_readhead(btree_head* head, void *p)
+{
+	UInt32 *q;
+        head->depth	    = bswabU16_inc(p);
+        head->root	    = bswabU32_inc(p);
+        head->leaf_count    = bswabU32_inc(p);
+        head->leaf_head	    = bswabU32_inc(p);
+        head->leaf_tail	    = bswabU32_inc(p);
+        head->node_size	    = bswabU16_inc(p);
+        head->max_key_len   = bswabU16_inc(p);
+        head->node_count    = bswabU32_inc(p);
+        head->free_nodes    = bswabU32_inc(p);
+        head->reserved1	    = bswabU16_inc(p);
+        head->clump_size    = bswabU32_inc(p);
+        head->btree_type    = bswabU8_inc(p);
+        head->reserved2	    = bswabU8_inc(p);
+        head->attributes    = bswabU32_inc(p);
+	    // skip reserved bytes
+	q=((UInt32*) p);
+	// ((UInt32*) p) += 16;
+	q+=16;
+	return q;
+}
+
+/* Priority of the depth of the node compared to LRU value.
+ * Should be the average number of keys per node but these vary. */
+#define DEPTH_FACTOR	1000
+
+/* Cache size is height of tree + this value
+ * Really big numbers wont help in case of ls -R
+ */
+#define EXTRA_CACHESIZE	3
+
+/* Not in use by now ... */
+#define CACHE_DIRTY 0x0001
+
+/* Intialize cache with default cache Size,
+ * must call node_cache_close to deallocate memory */
+static int node_cache_init(node_cache* cache, btree* tree, int size)
+{
+    int nodebufsize;
+    char * buf;
+
+    cache->size		= size;
+    cache->currindex	= 0;
+    nodebufsize = tree->head.node_size + sizeof(node_buf);
+    buf = malloc(size *(sizeof(node_entry) + nodebufsize));
+    if (!buf)
+	return -1;
+    cache -> nodebufsize = nodebufsize;
+    cache -> entries = (node_entry*) buf;
+    cache -> buffers = (char*) &cache->entries[size];
+    bzero(cache->entries, size*sizeof(node_entry));
+    return 0;
+}
+
+/* Like cache->buffers[i], since size of node_buf is variable */
+static inline node_buf* node_buf_get(node_cache* cache, int i)
+{
+    return (node_buf*) (cache->buffers + (i * cache->nodebufsize));
+}
+
+/* flush the node at index */
+static void node_cache_flush_node(node_cache* cache, int index)
+{
+    // NYI
+    cache -> entries[index].index = 0;	// invalidate entry
+}
+
+static void node_cache_close(node_cache* cache)
+{
+    if (!cache->entries) // not (fully) intialized ?
+	return;
+    free(cache->entries);
+}
+
+/* Load the cach node indentified by index with
+ * the node identified by node_index */
+
+static node_buf* node_cache_load_buf
+    (btree* bt, node_cache* cache, int index, UInt16 node_index)
+{
+    node_buf	*result	    = node_buf_get(cache ,index);
+    UInt32	blkpernode  = bt->blkpernode;
+    UInt32	block	    = node_index * blkpernode;
+    void*	p	    = volume_readfromfork(bt->vol, result->node, bt->fork,
+			     block, blkpernode, HFSP_EXTENT_DATA, bt->cnid);
+    node_entry	*e	    = &cache->entries[index];
+
+    if (!p)
+	return NULL;	// evil ...
+
+    result->index   = node_index;
+    btree_readnode(&result->desc, p);
+
+    e -> priority   = result->desc.height * DEPTH_FACTOR;
+    e -> index	    = node_index;
+    return result;
+}
+
+/* Read node at given index, using cache.
+ */
+node_buf* btree_node_by_index(btree* bt, UInt16 index)
+{
+    node_cache*	cache = &bt->cache;
+    int		oldindex, lruindex;
+    int		currindex = cache->currindex;
+    UInt32	prio;
+    node_entry	*e;
+
+    // Shortcut acces to current node, will not change priorities
+    if (cache->entries[currindex].index == index)
+	return node_buf_get(cache ,currindex);
+    oldindex = currindex;
+    if (currindex == 0)
+	currindex = cache->size;
+    currindex--;
+    lruindex = oldindex;	    // entry to be flushed when needed
+    prio     = 0;		    // current priority
+    while (currindex != oldindex)   // round robin
+    {
+	e = &cache->entries[currindex];
+	if (e->index == index)	    // got it
+	{
+	    if (e->priority != 0)   // already top, uuh
+		e->priority--;
+	    cache->currindex = currindex;
+	    return node_buf_get(cache ,currindex);
+	}
+	else
+	{
+	    if (!e->index)
+	    {
+		lruindex = currindex;
+		break;	// empty entry, load it
+	    }
+	    if (e->priority != UINT_MAX) // already least, uuh
+		e->priority++;
+	}
+	if (prio < e->priority)
+	{
+	    lruindex = currindex;
+	    prio = e->priority;
+	}
+	if (currindex == 0)
+	    currindex = cache->size;
+	currindex--;
+    }
+    e = &cache->entries[lruindex];
+    cache->currindex = lruindex;
+    if (e->flags & CACHE_DIRTY)
+           node_cache_flush_node(    cache, lruindex);
+    return node_cache_load_buf  (bt, cache, lruindex, index);
+}
+
+/** intialize the btree with the first entry in the fork */
+static int btree_init(btree* bt, volume* vol, hfsp_fork_raw* fork)
+{
+    void	    *p;
+    char	    buf[vol->blksize];
+    UInt16	    node_size;
+    btree_node_desc node;
+
+    bt->vol	= vol;
+    bt->fork	= fork;
+    p	= volume_readfromfork(vol, buf, fork, 0, 1,
+		 HFSP_EXTENT_DATA, bt->cnid);
+    if (!p)
+	return -1;
+    p = btree_readnode(&node, p);
+    if (node.kind != HFSP_NODE_HEAD)
+	return -1;   // should not happen ?
+    btree_readhead(&bt->head, p);
+
+    node_size = bt->head.node_size;
+    bt->blkpernode = node_size / vol->blksize;
+
+    if (bt->blkpernode == 0 || vol->blksize *
+	    bt->blkpernode != node_size)
+	return -1;  // should never happen ...
+
+    node_cache_init(&bt->cache, bt, bt->head.depth + EXTRA_CACHESIZE);
+
+    // Allocate buffer
+    // bt->buf = malloc(node_size);
+    // if (!bt->buf)
+    //	return ENOMEM;
+
+    return 0;
+}
+
+/** Intialize catalog btree, so that btree_close can safely be called. */
+void btree_reset(btree* bt)
+{
+    bt->cache.entries = NULL;
+}
+
+/** Intialize catalog btree */
+int btree_init_cat(btree* bt, volume* vol, hfsp_fork_raw* fork)
+{
+    int result = btree_init(bt,vol,fork);	// super (...)
+    bt->cnid  = HFSP_CAT_CNID;
+    bt->kcomp = record_key_compare;
+    bt->kread = record_readkey;
+    return result;
+}
+
+/** Intialize catalog btree */
+int btree_init_extent(btree* bt, volume* vol, hfsp_fork_raw* fork)
+{
+    int result = btree_init(bt,vol,fork);	// super (...)
+    bt->cnid  = HFSP_EXT_CNID;
+    bt->kcomp = record_extent_key_compare;
+    bt->kread = record_extent_readkey;
+    return result;
+}
+
+/** close the btree and free any resources */
+void btree_close(btree* bt)
+{
+    node_cache_close(&bt->cache);
+    // free(bt->buf);
+}
+
+/* returns pointer to key given by index in current node.
+ *
+ * Assumes that current node is not NODE_HEAD ...
+ */
+void* btree_key_by_index(btree* bt, node_buf* buf, UInt16 index)
+{
+    UInt16  node_size	    = bt->head.node_size;
+	// The offsets are found at the end of the node ...
+    UInt16  off_pos	    = node_size - (index +1) * sizeof(btree_record_offset);
+	// position of offset at end of node
+    btree_record_offset* offset =
+	(btree_record_offset*) (buf->node + off_pos);
+
+    // now we have the offset and can read the key ...
+#ifdef CONFIG_LITTLE_ENDIAN
+    return buf->node + bswabU16(*offset);
+#else
+    return buf->node + *offset;
+#endif
+}
+
+
+#ifdef DEBUG
+
+/* print btree header node information */
+void btree_printhead(btree_head* head)
+{
+    UInt32 attr;
+    printf("  depth       : %#X\n",  head->depth);
+    printf("  root        : %#lX\n", head->root);
+    printf("  leaf_count  : %#lX\n", head->leaf_count);
+    printf("  leaf_head   : %#lX\n", head->leaf_head);
+    printf("  leaf_tail   : %#lX\n", head->leaf_tail);
+    printf("  node_size   : %#X\n",  head->node_size);
+    printf("  max_key_len : %#X\n",  head->max_key_len);
+    printf("  node_count  : %#lX\n", head->node_count);
+    printf("  free_nodes  : %#lX\n", head->free_nodes);
+    printf("  reserved1   : %#X\n",  head->reserved1);
+    printf("  clump_size  : %#lX\n", head->clump_size);
+    printf("  btree_type  : %#X\n",  head->btree_type);
+    attr = head->attributes;
+    printf("  reserved2   : %#X\n",  head->reserved2);
+    if (attr & HFSPLUS_BAD_CLOSE)
+        printf(" HFSPLUS_BAD_CLOSE *** ");
+    else
+        printf(" !HFSPLUS_BAD_CLOSE");
+    if (attr & HFSPLUS_TREE_BIGKEYS)
+        printf(" HFSPLUS_TREE_BIGKEYS ");
+    else
+        printf("  !HFSPLUS_TREE_BIGKEYS");
+    if (attr & HFSPLUS_TREE_VAR_NDXKEY_SIZE)
+        printf(" HFSPLUS_TREE_VAR_NDXKEY_SIZE");
+    else
+        printf(" !HFSPLUS_TREE_VAR_NDXKEY_SIZE");
+    if (attr & HFSPLUS_TREE_UNUSED)
+        printf(" HFSPLUS_TREE_UNUSED ***\n");
+    printf("\n");
+}
+
+/* Dump all the node information to stdout */
+void btree_print(btree* bt)
+{
+    btree_node_desc* node;
+
+    btree_printhead(&bt->head);
+
+    node = &bt->node;
+    printf("next     : %#lX\n", node->next);
+    printf("prev     : %#lX\n", node->prev);
+    printf("height   : %#X\n",  node->height);
+    printf("num_rec  : %#X\n",  node->num_rec);
+    printf("reserved : %#X\n",  node->reserved);
+    printf("height   : %#X\n",  node->height);                                      switch(node->kind)
+    {
+	case HFSP_NODE_NDX  :
+	    printf("HFSP_NODE_NDX\n");
+	    break;
+	case HFSP_NODE_HEAD :
+	    printf("HFSP_NODE_HEAD\n");
+	    break;
+	case HFSP_NODE_MAP  :
+	    printf("HFSP_NODE_MAP\n");
+	    break;
+	case HFSP_NODE_LEAF :
+	    printf("HFSP_NODE_LEAF\n");
+	    break;
+	default:
+	    printf("*** Unknown Node type ***\n");
+    }
+}
+
+#endif
diff --git a/roms/openbios/fs/hfsplus/hfsp_fs.c b/roms/openbios/fs/hfsplus/hfsp_fs.c
new file mode 100644
index 000000000..4d52478b7
--- /dev/null
+++ b/roms/openbios/fs/hfsplus/hfsp_fs.c
@@ -0,0 +1,630 @@
+/*
+ *   Creation Date: <2001/05/05 23:33:49 samuel>
+ *   Time-stamp: <2004/01/12 10:25:39 samuel>
+ *
+ *	/package/hfsplus-files
+ *
+ *	HFS+ file system interface (and ROM lookup support)
+ *
+ *   Copyright (C) 2001, 2002, 2003, 2004 Samuel Rydh (samuel@ibrium.se)
+ *   Copyright (C) 2010 Mark Cave-Ayland (mark.cave-ayland@siriusit.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
+ *
+ */
+
+#include "config.h"
+#include "libopenbios/bindings.h"
+#include "fs/fs.h"
+#include "libhfsp.h"
+#include "volume.h"
+#include "record.h"
+#include "unicode.h"
+#include "blockiter.h"
+#include "libc/diskio.h"
+#include "libc/vsprintf.h"
+
+#define MAC_OS_ROM_CREATOR	0x63687270	/* 'chrp' */
+#define MAC_OS_ROM_TYPE		0x74627869	/* 'tbxi' */
+#define MAC_OS_ROM_NAME		"Mac OS ROM"
+
+#define FINDER_TYPE		0x464E4452	/* 'FNDR' */
+#define FINDER_CREATOR		0x4D414353	/* 'MACS' */
+#define SYSTEM_TYPE		0x7A737973	/* 'zsys' */
+#define SYSTEM_CREATOR		0x4D414353	/* 'MACS' */
+
+#define VOLNAME_SIZE	64
+
+extern void     hfsp_init( void );
+
+typedef struct {
+	record		rec;
+	char		*path;
+	off_t		pos;
+} hfsp_file_t;
+
+typedef struct {
+	volume *vol;
+	hfsp_file_t *hfspfile;
+} hfsp_info_t;
+
+DECLARE_NODE( hfsp, 0, sizeof(hfsp_info_t), "+/packages/hfsplus-files" );
+
+
+/************************************************************************/
+/*	Search implementation						*/
+/************************************************************************/
+
+typedef int (*match_proc_t)( record *r, record *parent, const void *match_data, hfsp_file_t *pt );
+
+static int
+search_files( record *par, int recursive, match_proc_t proc, const void *match_data, hfsp_file_t *pt )
+{
+	hfsp_file_t t;
+	record r;
+	int ret = 1;
+
+	t.path = NULL;
+
+	record_init_parent( &r, par );
+	do{
+		if( r.record.type == HFSP_FOLDER || r.record.type == HFSP_FILE )
+			ret = (*proc)( &r, par, match_data, &t );
+
+		if( ret && r.record.type == HFSP_FOLDER && recursive )
+			ret = search_files( &r, 1, proc, match_data, &t );
+
+	} while( ret && !record_next(&r) );
+
+	if( !ret && pt ) {
+                char name[256];
+                const char *s2 = t.path ? t.path : "";
+
+		unicode_uni2asc( name, &r.key.name, sizeof(name));
+
+		pt->rec = t.rec;
+		pt->path = malloc( strlen(name) + strlen(s2) + 2 );
+		strcpy( pt->path, name );
+		if( strlen(s2) ) {
+			strcat( pt->path, "\\" );
+			strcat( pt->path, s2 );
+		}
+	}
+
+	if( t.path )
+		free( t.path );
+
+	return ret;
+}
+
+static int
+root_search_files( volume *vol, int recursive, match_proc_t proc, const void *match_data, hfsp_file_t *pt )
+{
+	record r;
+
+	record_init_root( &r, &vol->catalog );
+	return search_files( &r, recursive, proc, match_data, pt );
+}
+
+static int
+match_file( record *r, record *parent, const void *match_data, hfsp_file_t *pt )
+{
+        const char *p = (const char*)match_data;
+	char name[256];
+	int ret=1;
+
+	if( r->record.type != HFSP_FILE )
+		return 1;
+
+	(void) unicode_uni2asc(name, &r->key.name, sizeof(name));
+	if( !(ret=strcasecmp(p, name)) && pt )
+		pt->rec = *r;
+
+	return ret;
+}
+
+static int
+match_rom( record *r, record *par, const void *match_data, hfsp_file_t *pt )
+{
+	hfsp_cat_file *file = &r->record.u.file;
+	FInfo *fi = &file->user_info;
+	int ret = 1;
+	char buf[256];
+
+	if( r->record.type == HFSP_FILE && fi->fdCreator == MAC_OS_ROM_CREATOR && fi->fdType == MAC_OS_ROM_TYPE ) {
+		ret = search_files( par, 0, match_file, "System", NULL )
+			|| search_files( par, 0, match_file, "Finder", NULL );
+
+		(void) unicode_uni2asc(buf, &r->key.name, sizeof(buf));
+		if( !strcasecmp("BootX", buf) )
+			return 1;
+
+		if( !ret && pt )
+			pt->rec = *r;
+	}
+	return ret;
+}
+
+static int
+match_path( record *r, record *par, const void *match_data, hfsp_file_t *pt )
+{
+	char name[256], *s, *next, *org;
+	int ret=1;
+
+ 	next = org = strdup( (char*)match_data );
+	while( (s=strsep( &next, "\\/" )) && !strlen(s) )
+		;
+	if( !s ) {
+		free( org );
+		return 1;
+	}
+
+	if( *s == ':' && strlen(s) == 5 ) {
+		if( r->record.type == HFSP_FILE && !next ) {
+			/* match type */
+			hfsp_cat_file *file = &r->record.u.file;
+			FInfo *fi = &file->user_info;
+			int i, type=0;
+			for( i=1; s[i] && i<=4; i++ )
+				type = (type << 8) | s[i];
+			/* printk("fi->fdType: %s / %s\n", s+1, b ); */
+			if( fi->fdType == type ) {
+				if( pt )
+					pt->rec = *r;
+				ret = 0;
+			}
+		}
+	} else {
+		(void) unicode_uni2asc(name, &r->key.name, sizeof(name));
+
+		if( !strcasecmp(s, name) ) {
+			if( r->record.type == HFSP_FILE && !next ) {
+				if( pt )
+					pt->rec = *r;
+				ret = 0;
+			} else /* must be a directory */
+				ret = search_files( r, 0, match_path, next, pt );
+		}
+	}
+	free( org );
+	return ret;
+}
+
+
+/************************************************************************/
+/*	Standard package methods						*/
+/************************************************************************/
+
+/* ( -- success? ) */
+static void
+hfsp_files_open( hfsp_info_t *mi )
+{
+	int fd;
+	char *path = my_args_copy();
+
+	if ( ! path )
+		RET( 0 );
+
+	fd = open_ih( my_parent() );
+	if ( fd == -1 ) {
+		free( path );
+		RET( 0 );
+	}
+
+	mi->vol = malloc( sizeof(volume) );
+	if (volume_open(mi->vol, fd)) {
+		free( path );
+		close_io( fd );
+		RET( 0 );
+	}
+
+	mi->hfspfile = malloc( sizeof(hfsp_file_t) );
+	
+	/* Leading \\ means system folder. The finder info block has
+	 * the following meaning.
+	 *
+	 *  [0] Prefered boot directory ID
+	 *  [3] MacOS 9 boot directory ID
+	 *  [5] MacOS X boot directory ID
+	 */
+	if( !strncmp(path, "\\\\", 2) ) {
+		int *p = (int*)&(mi->vol)->vol.finder_info[0];
+		int cnid = p[0];
+		/* printk(" p[0] = %x, p[3] = %x, p[5] = %x\n", p[0], p[3], p[5] ); */
+		if( record_init_cnid(&(mi->hfspfile->rec), &(mi->vol)->catalog, cnid) )
+			RET ( 0 );
+		path += 2;
+	} else {
+		record_init_root( &(mi->hfspfile->rec), &(mi->vol)->catalog );
+	}
+
+	if( !search_files(&(mi->hfspfile->rec), 0, match_path, path, mi->hfspfile ) )
+		RET ( -1 );
+	
+	RET ( -1 );
+}
+
+/* ( -- ) */
+static void
+hfsp_files_close( hfsp_info_t *mi )
+{
+	volume_close(mi->vol);
+
+	if( mi->hfspfile->path )
+		free( mi->hfspfile->path );
+	free( mi->hfspfile );
+}
+
+/* ( buf len -- actlen ) */
+static void
+hfsp_files_read( hfsp_info_t *mi )
+{
+	int count = POP();
+	char *buf = (char *)cell2pointer(POP());
+
+	hfsp_file_t *t = mi->hfspfile;
+	volume *vol = t->rec.tree->vol;
+	UInt32 blksize = vol->blksize;
+	hfsp_cat_file *file = &t->rec.record.u.file;
+	blockiter iter;
+	char buf2[blksize];
+	int act_count, curpos=0;
+
+	blockiter_init( &iter, vol, &file->data_fork, HFSP_EXTENT_DATA, file->id );
+	while( curpos + blksize < t->pos ) {
+		if( blockiter_next( &iter ) ) {
+			RET ( -1 );
+			return;
+		}
+		curpos += blksize;
+	}
+	act_count = 0;
+
+	while( act_count < count ){
+		UInt32 block = blockiter_curr(&iter);
+		int max = blksize, add = 0, size;
+
+		if( volume_readinbuf( vol, buf2, block ) )
+			break;
+
+		if( curpos < t->pos ){
+			add += t->pos - curpos;
+			max -= t->pos - curpos;
+		}
+		size = (count-act_count > max)? max : count-act_count;
+		memcpy( (char *)buf + act_count, &buf2[add], size );
+
+		curpos += blksize;
+		act_count += size;
+
+		if( blockiter_next( &iter ) )
+			break;
+	}
+
+	t->pos += act_count;
+
+	RET ( act_count );
+}
+
+/* ( pos.d -- status ) */
+static void
+hfsp_files_seek( hfsp_info_t *mi )
+{
+	long long pos = DPOP();
+	int offs = (int)pos;
+	int whence = SEEK_SET;
+
+	hfsp_file_t *t = mi->hfspfile;
+	hfsp_cat_file *file = &t->rec.record.u.file;
+	int total = file->data_fork.total_size;
+
+	if( offs == -1 ) {
+		offs = 0;
+		whence = SEEK_END;
+	}
+
+	switch( whence ){
+	case SEEK_END:
+		t->pos = total + offs;
+		break;
+	default:
+	case SEEK_SET:
+		t->pos = offs;
+		break;
+	}
+
+	if( t->pos < 0 )
+		t->pos = 0;
+
+	if( t->pos > total )
+		t->pos = total;
+
+	RET ( 0 );
+}
+
+/* ( addr -- size ) */
+static void
+hfsp_files_load( hfsp_info_t *mi )
+{
+	char *buf = (char *)cell2pointer(POP());
+
+	hfsp_file_t *t = mi->hfspfile;
+	volume *vol = t->rec.tree->vol;
+	UInt32 blksize = vol->blksize;
+	hfsp_cat_file *file = &t->rec.record.u.file;
+	int total = file->data_fork.total_size;
+	blockiter iter;
+	char buf2[blksize];
+	int act_count;
+
+	blockiter_init( &iter, vol, &file->data_fork, HFSP_EXTENT_DATA, file->id );
+
+	act_count = 0;
+
+	while( act_count < total ){
+		UInt32 block = blockiter_curr(&iter);
+		int max = blksize, size;
+
+		if( volume_readinbuf( vol, buf2, block ) )
+			break;
+
+		size = (total-act_count > max)? max : total-act_count;
+		memcpy( (char *)buf + act_count, &buf2, size );
+
+		act_count += size;
+
+		if( blockiter_next( &iter ) )
+			break;
+	}
+
+	RET ( act_count );
+}
+
+/* ( -- cstr ) */
+static void
+hfsp_files_get_fstype( hfsp_info_t *mi )
+{
+	PUSH( pointer2cell(strdup("HFS+")) );
+}
+
+/* ( -- cstr ) */
+static void
+hfsp_files_get_path( hfsp_info_t *mi )
+{
+	char *buf;
+	hfsp_file_t *t = mi->hfspfile;
+
+	if( !t->path )
+		RET ( 0 );
+
+	buf = malloc(strlen(t->path) + 1);
+	strncpy( buf, t->path, strlen(t->path) );
+	buf[strlen(t->path)] = 0;
+
+	PUSH(pointer2cell(buf));
+}
+
+/* ( -- success? ) */
+static void
+hfsp_files_open_nwrom( hfsp_info_t *mi )
+{
+	/* Switch to an existing ROM image file on the fs! */
+	if( !root_search_files(mi->vol, 1, match_rom, NULL, mi->hfspfile) )
+		RET ( -1 );
+
+	RET ( 0 );
+}
+
+/* ( -- cstr|0 ) */
+static void
+hfsp_files_volume_name( hfsp_info_t *mi )
+{
+	int fd;
+	char *volname = malloc(VOLNAME_SIZE);
+
+	fd = open_ih(my_self());
+        if (fd >= 0) {
+                get_hfs_vol_name(fd, volname, VOLNAME_SIZE);
+                close_io(fd);
+        } else {
+                volname[0] = '\0';
+        }
+
+	PUSH(pointer2cell(volname));
+}
+
+static const int days_month[12] =
+	{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+static const int days_month_leap[12] =
+	{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+
+static inline int is_leap(int year)
+{
+	return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
+}
+
+static void
+print_date(uint32_t sec)
+{
+	unsigned int second, minute, hour, month, day, year;
+	int current;
+	const int *days;
+
+	second = sec % 60;
+	sec /= 60;
+
+	minute = sec % 60;
+	sec /= 60;
+
+	hour = sec % 24;
+	sec /= 24;
+
+	year = sec * 100 / 36525;
+	sec -= year * 36525 / 100;
+	year += 1904;
+
+	days = is_leap(year) ?  days_month_leap : days_month;
+
+	current = 0;
+	month = 0;
+	while (month < 12) {
+		if (sec <= current + days[month]) {
+			break;
+		}
+		current += days[month];
+		month++;
+	}
+	month++;
+
+	day = sec - current + 1;
+
+	forth_printf("%d-%02d-%02d %02d:%02d:%02d ",
+		     year, month, day, hour, minute, second);
+}
+
+/* static method, ( pathstr len ihandle -- ) */
+static void
+hfsp_files_dir( hfsp_info_t *dummy )
+{
+	ihandle_t ih = POP_ih();
+	char *path = pop_fstr_copy();
+	int fd, found;
+	volume *vol;
+	record rec, r, folrec;
+	char name[256], *curfol, *tmppath;
+	
+	fd = open_ih(ih);
+	if ( fd == -1 ) {
+		free( path );
+		RET( 0 );
+	}
+
+	vol = malloc( sizeof(volume) );
+	if (volume_open(vol, fd)) {
+		free( path );
+		close_io( fd );
+		RET( 0 );
+	}
+	
+	/* First move to the specified folder */
+	tmppath = strdup(path);
+	record_init_root( &rec, &vol->catalog );
+	record_init_parent( &r, &rec );
+	
+	/* Remove initial \ or / */
+	curfol = strsep(&tmppath, "\\//");
+	curfol = strsep(&tmppath, "\\//");
+	forth_printf("\n");
+	
+	while (curfol && strlen(curfol)) {	    
+	    found = 0;
+	    do {
+		if (r.record.type == HFSP_FOLDER) {
+		    unicode_uni2asc(name, &r.key.name, sizeof(name));
+		    
+		    if (!strcmp(name, curfol)) {
+			folrec = r;
+			found = -1;
+		    }
+		}
+	    } while ( !record_next(&r) );
+	    
+	    if (!found) {
+		forth_printf("Unable to locate path %s on filesystem\n", path);
+		goto done;
+	    } else {
+		record_init_parent( &r, &folrec );
+	    }
+	    
+	    curfol = strsep(&tmppath, "\\//");
+	}
+	
+	/* Output the directory contents */
+	found = 0;
+	do {
+	    unicode_uni2asc(name, &r.key.name, sizeof(name));
+	    
+	    if (r.record.type == HFSP_FILE) {
+		/* Grab the file entry */
+		hfsp_cat_file *file = &r.record.u.file;
+		forth_printf("% 10lld ", file->data_fork.total_size);
+		print_date(file->create_date);
+		forth_printf(" %s\n", name);
+		found = -1;
+	    }
+	    
+	    if (r.record.type == HFSP_FOLDER) {
+		/* Grab the directory entry */
+		hfsp_cat_folder *folder = &r.record.u.folder;
+		forth_printf("         0 ");
+		print_date(folder->create_date);
+		forth_printf(" %s\\\n", name);
+		found = -1;
+	    }
+	    
+	} while ( !record_next(&r) );
+	
+	if (!found) {
+	    forth_printf("  (Empty folder)\n");
+	}
+	
+done:
+	volume_close(vol);
+	free(vol);
+	free(path);
+	if (tmppath)
+	    free(tmppath);
+}
+
+/* static method, ( pos.d ih -- flag? ) */
+static void
+hfsp_files_probe( hfsp_info_t *dummy )
+{
+	ihandle_t ih = POP_ih();
+	long long offs = DPOP();
+	int fd, ret = 0;
+
+	fd = open_ih(ih);
+        if (fd >= 0) {
+                if (volume_probe(fd, offs)) {
+                        ret = -1;
+                }
+                close_io(fd);
+        } else {
+                ret = -1;
+        }
+
+	RET (ret);
+}
+
+static void
+hfsp_initializer( hfsp_info_t *dummy )
+{
+	fword("register-fs-package");
+}
+
+NODE_METHODS( hfsp ) = {
+	{ "probe",	hfsp_files_probe	},
+	{ "open",	hfsp_files_open		},
+	{ "close",	hfsp_files_close	},
+	{ "read",	hfsp_files_read		},
+	{ "seek",	hfsp_files_seek		},
+	{ "load",	hfsp_files_load		},
+	{ "dir",	hfsp_files_dir		},
+
+	/* special */
+	{ "open-nwrom",	 	hfsp_files_open_nwrom 	},
+	{ "get-path",		hfsp_files_get_path	},
+	{ "get-fstype",		hfsp_files_get_fstype	},
+	{ "volume-name",	hfsp_files_volume_name	},
+
+	{ NULL,		hfsp_initializer	},
+};
+
+void
+hfsp_init( void )
+{
+	REGISTER_NODE( hfsp );
+}
diff --git a/roms/openbios/fs/hfsplus/hfsp_record.c b/roms/openbios/fs/hfsplus/hfsp_record.c
new file mode 100644
index 000000000..d4e7af1bf
--- /dev/null
+++ b/roms/openbios/fs/hfsplus/hfsp_record.c
@@ -0,0 +1,759 @@
+/*
+ * libhfsp - library for reading and writing Macintosh HFS+ volumes.
+ *
+ * a record contains a key and a folder or file and is part
+ * of a btree.
+ *
+ * Copyright (C) 2000 Klaus Halfmann <khalfmann@libra.de>
+ * Original 1996-1998 Robert Leslie <rob@mars.org>
+ * Additional work by  Brad Boyer (flar@pants.nu)
+ *
+ * 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.
+ *
+ * $Id: record.c,v 1.24 2000/10/17 05:58:46 hasi Exp $
+ */
+
+#include "config.h"
+#include "libhfsp.h"
+#include "hfstime.h"
+#include "record.h"
+#include "volume.h"
+#include "btree.h"
+#include "unicode.h"
+#include "swab.h"
+
+/* read a hfsp_cat_key from memory */
+void* record_readkey(void* p, void* buf)
+{
+    hfsp_cat_key*   key = (hfsp_cat_key*) buf;
+    const void*	    check;
+    UInt16	    key_length, len,i;
+    UInt16*	    cp;
+
+    key->key_length = key_length    = bswabU16_inc(p);
+    check = p;
+    key->parent_cnid		    = bswabU32_inc(p);
+    key->name.strlen = len	    = bswabU16_inc(p);
+    cp = key->name.name;
+    for (i=0; i < len; i++, cp++)
+	*cp			    = bswabU16_inc(p);
+	/* check if keylenght was correct */
+    if (key_length != ((char*) p) - ((char*) check))
+	 HFSP_ERROR(EINVAL, "Invalid key length in record_readkey");
+    return p;
+  fail:
+    return NULL;
+}
+
+/* read a hfsp_extent_key from memory */
+void* record_extent_readkey(void* p, void* buf)
+{
+    hfsp_extent_key* key = (hfsp_extent_key*) buf;
+    UInt16  key_length;
+
+    key->key_length = key_length    = bswabU16_inc(p);
+    key->fork_type		    = bswabU8_inc(p);
+    key->filler			    = bswabU8_inc(p);
+    if (key_length != 10)
+	HFSP_ERROR(-1, "Invalid key length in record_extent_readkey");
+    key->file_id		    = bswabU32_inc(p);
+    key->start_block		    = bswabU32_inc(p);
+    return p;
+  fail:
+    return NULL;
+}
+
+
+/* read posix permission from memory */
+static inline void* record_readperm(void *p, hfsp_perm* perm)
+{
+    perm->owner= bswabU32_inc(p);
+    perm->group= bswabU32_inc(p);
+    perm->mode = bswabU32_inc(p);
+    perm->dev  = bswabU32_inc(p);
+    return p;
+}
+
+/* read directory info */
+static inline void* record_readDInfo(void *p, DInfo* info)
+{
+    info->frRect.top	= bswabU16_inc(p);
+    info->frRect.left	= bswabU16_inc(p);
+    info->frRect.bottom	= bswabU16_inc(p);
+    info->frRect.right	= bswabU16_inc(p);
+    info->frFlags	= bswabU16_inc(p);
+    info->frLocation.v	= bswabU16_inc(p);
+    info->frLocation.h	= bswabU16_inc(p);
+    info->frView	= bswabU16_inc(p);
+    return p;
+}
+
+/* read extra Directory info */
+static inline void* record_readDXInfo(void *p, DXInfo* xinfo)
+{
+    xinfo->frScroll.v  = bswabU16_inc(p);
+    xinfo->frScroll.h  = bswabU16_inc(p);
+    xinfo->frOpenChain = bswabU32_inc(p);
+    xinfo->frUnused    = bswabU16_inc(p);
+    xinfo->frComment   = bswabU16_inc(p);
+    xinfo->frPutAway   = bswabU32_inc(p);
+    return p;
+}
+
+/* read a hfsp_cat_folder from memory */
+static void* record_readfolder(void *p, hfsp_cat_folder* folder)
+{
+    folder->flags		= bswabU16_inc(p);
+    folder->valence		= bswabU32_inc(p);
+    folder->id			= bswabU32_inc(p);
+    folder->create_date		= bswabU32_inc(p);
+    folder->content_mod_date    = bswabU32_inc(p);
+    folder->attribute_mod_date	= bswabU32_inc(p);
+    folder->access_date		= bswabU32_inc(p);
+    folder->backup_date		= bswabU32_inc(p);
+    p = record_readperm	    (p, &folder->permissions);
+    p = record_readDInfo    (p, &folder->user_info);
+    p = record_readDXInfo   (p, &folder->finder_info);
+    folder->text_encoding	= bswabU32_inc(p);
+    folder->reserved		= bswabU32_inc(p);
+    return p;
+}
+
+/* read file info */
+static inline void* record_readFInfo(void *p, FInfo* info)
+{
+    info->fdType	= bswabU32_inc(p);
+    info->fdCreator	= bswabU32_inc(p);
+    info->fdFlags	= bswabU16_inc(p);
+    info->fdLocation.v	= bswabU16_inc(p);
+    info->fdLocation.h	= bswabU16_inc(p);
+    info->fdFldr	= bswabU16_inc(p);
+    return p;
+}
+
+/* read extra File info */
+static inline void* record_readFXInfo(void *p, FXInfo* xinfo)
+{
+    SInt16 *q;
+    xinfo->fdIconID	= bswabU16_inc(p);
+    q=(SInt16*) p;
+    q+=4; // skip unused
+    p=(void *)q;
+    xinfo->fdComment	= bswabU16_inc(p);
+    xinfo->fdPutAway	= bswabU32_inc(p);
+    return p;
+}
+
+/* read a hfsp_cat_file from memory */
+static void* record_readfile(void *p, hfsp_cat_file* file)
+{
+    file->flags			= bswabU16_inc(p);
+    file->reserved1		= bswabU32_inc(p);
+    file->id			= bswabU32_inc(p);
+    file->create_date		= bswabU32_inc(p);
+    file->content_mod_date	= bswabU32_inc(p);
+    file->attribute_mod_date	= bswabU32_inc(p);
+    file->access_date		= bswabU32_inc(p);
+    file->backup_date		= bswabU32_inc(p);
+    p = record_readperm	    (p, &file->permissions);
+    p = record_readFInfo    (p, &file->user_info);
+    p = record_readFXInfo   (p, &file->finder_info);
+    file->text_encoding		= bswabU32_inc(p);
+    file->reserved2		= bswabU32_inc(p);
+    p =	    volume_readfork (p, &file->data_fork);
+    return  volume_readfork (p, &file->res_fork);
+}
+
+/* read a hfsp_cat_thread from memory */
+static void* record_readthread(void *p, hfsp_cat_thread* entry)
+{
+    int	    i;
+    UInt16  len;
+    UInt16* cp;
+
+    entry->         reserved	= bswabU16_inc(p);
+    entry->	    parentID	= bswabU32_inc(p);
+    entry->nodeName.strlen = len= bswabU16_inc(p);
+    cp = entry->nodeName.name;
+    if (len > 255)
+        HFSP_ERROR(-1, "Invalid key length in record thread");
+    for (i=0; i < len; i++, cp++)
+	*cp			 = bswabU16_inc(p);
+    return p;
+ fail:
+    return NULL;
+}
+
+/* read a hfsp_cat_entry from memory */
+static void* record_readentry(void *p, hfsp_cat_entry* entry)
+{
+    UInt16 type = bswabU16_inc(p);
+    entry->type = type;
+    switch (type)
+    {
+	case HFSP_FOLDER:
+	    return record_readfolder(p, &entry->u.folder);
+	case HFSP_FILE:
+	    return record_readfile  (p, &entry->u.file);
+	case HFSP_FOLDER_THREAD:
+	case HFSP_FILE_THREAD:
+	    return record_readthread(p, &entry->u.thread);
+	default:
+	    HFSP_ERROR(-1, "Unexpected record type in record_readentry");
+    } ;
+  fail:
+    return NULL;
+}
+
+
+/* Most of the functions here will not change the node in the btree,
+   But this must be changed in the future ... */
+
+
+/* intialize the record with the given index entry in the btree. */
+static int record_init(record* r, btree* bt, node_buf* buf, UInt16 index)
+{
+    void *p;
+    r-> tree   = bt;
+    p = btree_key_by_index(bt,buf,index);
+    if (!p)
+	return -1;
+    p = record_readkey  (p, &r->key);
+    if (!p)
+	return -1;
+    p = record_readentry(p, &r->record);
+    if (!p)
+	return -1;
+    r->node_index = buf->index;
+    r-> keyind    = index;
+
+    return 0;
+}
+
+/* intialize the record with the given index entry in the btree. */
+static int record_init_extent(extent_record* r, btree* bt, node_buf* buf, UInt16 index)
+{
+    void *p;
+    r-> tree   = bt;
+    p = btree_key_by_index(bt, buf,index);
+    if (!p)
+	return -1;
+    p = record_extent_readkey(p, &r->key);
+    if (!p)
+	return -1;
+    p = volume_readextent(p, r->extent);
+    if (!p)
+	return -1;
+    r->node_index = buf->index;
+    r-> keyind    = index;
+
+    return 0;
+}
+
+/* intialize the record to the first record of the tree
+ * which is (per design) the root node.
+ */
+int record_init_root(record* r, btree* tree)
+{
+    // Position to first leaf node ...
+    UInt32 leaf_head = tree->head.leaf_head;
+    node_buf* buf = btree_node_by_index(tree, leaf_head);
+    if (!buf)
+	return -1;
+    return record_init(r, tree, buf, 0);
+}
+
+/* Compare two cat_keys ... */
+int record_key_compare(void* k1, void* k2)
+{
+    hfsp_cat_key* key1 = (hfsp_cat_key*) k1;
+    hfsp_cat_key* key2 = (hfsp_cat_key*) k2;
+    int diff = key2->parent_cnid - key1->parent_cnid;
+    if (!diff) // same parent
+	diff = fast_unicode_compare(&key1->name, &key2->name);
+    return diff;
+}
+
+/* Compare two extent_keys ... */
+int record_extent_key_compare(void* k1, void* k2)
+{
+    hfsp_extent_key* key1 = (hfsp_extent_key*) k1;
+    hfsp_extent_key* key2 = (hfsp_extent_key*) k2;
+    int diff = key2->fork_type - key1->fork_type;
+    if (!diff) // same type
+    {
+	diff = key2->file_id - key1->file_id;
+	if (!diff) // same file
+	    diff = key2->start_block - key1->start_block;
+    }
+    return diff;
+}
+
+/* Position node in btree so that key might be inside */
+static node_buf* record_find_node(btree* tree, void *key)
+{
+    int			start, end, mid, comp;  // components of a binary search
+    void		*p = NULL;
+    char		curr_key[tree->head.max_key_len];
+		    // The current key under examination
+    hfsp_key_read	readkey	    = tree->kread;
+    hfsp_key_compare	key_compare = tree->kcomp;
+    UInt32		index;
+    node_buf*		node = btree_node_by_index(tree, tree->head.root);
+    if (!node)
+	HFSP_ERROR(-1, "record_find_node: Cant position to root node");
+    while (node->desc.kind == HFSP_NODE_NDX)
+    {
+	mid = start = 0;
+	end  = node->desc.num_rec;
+	comp = -1;
+	while (start < end)
+	{
+	    mid = (start + end) >> 1;
+	    p = btree_key_by_index(tree, node, mid);
+	    if (!p)
+		HFSP_ERROR(-1, "record_find_node: unexpected error");
+	    p = readkey  (p, curr_key);
+	    if (!p)
+		HFSP_ERROR(-1, "record_find_node: unexpected error");
+	    comp = key_compare(curr_key, key);
+	    if (comp > 0)
+		start = mid + 1;
+	    else if (comp < 0)
+		end = mid;
+	    else
+		break;
+	}
+	if (!p) // Empty tree, fascinating ...
+	    HFSP_ERROR(-1, "record_find_node: unexpected empty node");
+	if (comp < 0)	// mmh interesting key is before this key ...
+	{
+	    if (mid == 0)
+		return NULL;  // nothing before this key ..
+	    p = btree_key_by_index(tree, node, mid-1);
+	    if (!p)
+		HFSP_ERROR(-1, "record_find_node: unexpected error");
+	    p = readkey  (p, curr_key);
+	    if (!p)
+		HFSP_ERROR(-1, "record_find_node: unexpected error");
+	}
+
+	index = bswabU32_inc(p);
+	node = btree_node_by_index(tree, index);
+    }
+    return node;	// go on and use the found node
+  fail:
+    return NULL;
+}
+
+/* search for the given key in the btree.
+ *
+ * returns pointer to memory just after key or NULL
+ * In any case *keyind recives the index where the
+ * key was found (or could be inserted.)
+ */
+static void *
+record_find_key(btree* tree, void* key, int* keyind, UInt16* node_index)
+{
+    node_buf* buf = record_find_node(tree, key);
+    if (buf)
+    {
+	int		    comp  = -1;
+	int		    start = 0; // components of a binary search
+	int		    end   = buf->desc.num_rec;
+	int		    mid   = -1;
+	void		    *p    = NULL;
+	char		    curr_key[tree->head.max_key_len];
+	hfsp_key_read	    readkey	= tree->kread;
+	hfsp_key_compare    key_compare = tree->kcomp;
+	while (start < end)
+	{
+	    mid = (start + end) >> 1;
+	    p = btree_key_by_index(tree, buf, mid);
+	    if (!p)
+		HFSP_ERROR(-1, "record_init_key: unexpected error");
+	    p = readkey  (p, curr_key);
+	    if (!p)
+		HFSP_ERROR(-1, "record_init_cat_key: unexpected error");
+	    comp = key_compare(curr_key, key);
+	    if (comp > 0)
+		start = mid + 1;
+	    else if (comp < 0)
+		end = mid;
+	    else
+		break;
+	}
+	if (!p) // Empty tree, fascinating ...
+	    HFSP_ERROR(ENOENT, "record_init_key: unexpected empty node");
+	*keyind = mid;
+	*node_index = buf->index;
+	if (!comp)	// found something ...
+	    return p;
+    }
+    HFSP_ERROR(ENOENT, NULL);
+  fail:
+    return NULL;
+}
+
+/* intialize the record by searching for the given key in the btree.
+ *
+ * r is umodified on error.
+ */
+static int
+record_init_key(record* r, btree* tree, hfsp_cat_key* key)
+{
+    int	    keyind;
+    UInt16  node_index;
+    void    *p = record_find_key(tree, key, &keyind, &node_index);
+
+    if (p)
+    {
+	r -> tree      = tree;
+	r -> node_index= node_index;
+	r -> keyind    = keyind;
+	r -> key       = *key; // Better use a record_key_copy ...
+	p = record_readentry(p, &r->record);
+	if (!p)
+	    HFSP_ERROR(-1, "record_init_key: unexpected error");
+	return 0;
+    }
+  fail:
+    return -1;
+}
+
+/* intialize the extent_record to the extent identified by the
+ * (first) blockindex.
+ *
+ * forktype: either HFSP_EXTEND_DATA or HFSP_EXTEND_RSRC
+ */
+int record_init_file(extent_record* r, btree* tree,
+		    UInt8 forktype, UInt32 fileId, UInt32 blockindex)
+{
+    int		    keyind;
+    UInt16	    node_index;
+    hfsp_extent_key key = { 10, forktype, 0, fileId, blockindex };
+    void	    *p = record_find_key(tree, &key, &keyind, &node_index);
+
+    if (p)
+    {
+	r -> tree      = tree;
+	r -> node_index= node_index;
+	r -> keyind    = keyind;
+	r -> key       = key; // Better use a record_key_copy ...
+	p =  volume_readextent(p, r->extent);
+	if (!p)
+	    HFSP_ERROR(-1, "record_init_file: unexpected error");
+	return 0;
+    }
+  fail:
+    return -1;
+}
+
+/* intialize the record to the folder identified by cnid
+ */
+int record_init_cnid(record* r, btree* tree, UInt32 cnid)
+{
+    hfsp_cat_key    thread_key;	    // the thread is the first record
+
+    thread_key.key_length = 6;	    // null name (like '.' in unix )
+    thread_key.parent_cnid = cnid;
+    thread_key.name.strlen = 0;
+
+    return record_init_key(r, tree, &thread_key);
+}
+
+/* intialize the record to the first record of the parent.
+ */
+int record_init_parent(record* r, record* parent)
+{
+    if (parent->record.type == HFSP_FOLDER)
+	return record_init_cnid(r, parent->tree, parent->record.u.folder.id);
+    else if(parent->record.type == HFSP_FOLDER_THREAD)
+    {
+	if (r != parent)
+	    *r = *parent; // The folder thread is in fact the first entry, like '.'
+	return 0;
+    }
+    HFSP_ERROR(EINVAL,
+	"record_init_parent: parent is neither folder nor folder thread.");
+
+  fail:
+    return EINVAL;
+}
+
+
+/* find correct node record for given node and *pindex.
+ *
+ * index of record in this (or next) node
+ * */
+static node_buf* prepare_next(btree* tree, UInt16 node_index, UInt16* pindex)
+{
+    node_buf*	     buf    = btree_node_by_index(tree, node_index);
+    btree_node_desc* desc   = &buf->desc;
+    UInt32	     numrec = desc->num_rec;
+    if (*pindex >= numrec) // move on to next node
+    {
+	UInt16 next = desc->next;
+	*pindex = 0;
+	if (!next   /* is there a next node ? */
+	||  !( buf = btree_node_by_index(tree, next)))
+	    return NULL;
+    }
+    return buf;
+}
+/* move record foreward to next entry.
+ *
+ * In case of an error the value of *r is undefined !
+ */
+int record_next(record* r)
+{
+    btree*	tree	= r->tree;
+    UInt16	index	= r->keyind +1;
+    UInt32	parent;
+    node_buf*	buf	= prepare_next(tree, r->node_index, &index);
+
+    if (!buf)
+	return ENOENT;	// No (more) such file or directory
+
+    parent = r->key.parent_cnid;
+
+    if (record_init(r, tree, buf, index))
+	return -1;
+
+    if (r->key.parent_cnid != parent || // end of current directory
+	index != r->keyind)		// internal error ?
+	return ENOENT;	// No (more) such file or directory
+
+    return 0;
+}
+
+/* move record foreward to next extent record.
+ *
+ * In case of an error the value of *r is undefined !
+ */
+int record_next_extent(extent_record* r)
+{
+    btree*	tree   = r->tree;
+    UInt16	index  = r->keyind +1;
+    UInt32	file_id;
+    UInt8	fork_type;
+    node_buf*	buf	= prepare_next(tree, r->node_index, &index);
+
+    if (!buf)
+	return ENOENT;	// No (more) such file or directory
+
+    file_id	= r->key.file_id;
+    fork_type	= r->key.fork_type;
+
+    if (record_init_extent(r, tree, buf, index))
+	return -1;
+
+    if (r->key.file_id	 != file_id ||	    // end of current file
+	r->key.fork_type != fork_type ||    // end of current fork
+	index != r->keyind)		    // internal error ?
+	return ENOENT;	// No (more) such file or directory
+
+    return 0;
+}
+
+/* intialize the record by searching for the given string in the given folder.
+ *
+ * parent and r may be the same.
+ */
+int record_init_string_parent(record* r, record* parent, char* name)
+{
+    hfsp_cat_key key;
+
+    if (parent->record.type == HFSP_FOLDER)
+	key.parent_cnid = parent->record.u.folder.id;
+    else if(parent->record.type == HFSP_FOLDER_THREAD)
+	key.parent_cnid = parent->key.parent_cnid;
+    else
+	HFSP_ERROR(-1, "record_init_string_parent: parent is not a folder.");
+
+    key.key_length = 6 + unicode_asc2uni(&key.name,name); // 6 for minumum size
+    return record_init_key(r, parent->tree, &key);
+
+  fail:
+    return -1;
+}
+
+/* move record up in folder hierarchy (if possible) */
+int record_up(record* r)
+{
+    if (r->record.type == HFSP_FOLDER)
+    {
+	// locate folder thread
+	if (record_init_cnid(r, r->tree, r->record.u.folder.id))
+	    return -1;
+    }
+    else if(r->record.type == HFSP_FOLDER_THREAD)
+    {
+	// do nothing were are already where we want to be
+    }
+    else
+	HFSP_ERROR(-1, "record_up: record is neither folder nor folder thread.");
+
+    if(r->record.type != HFSP_FOLDER_THREAD)
+	HFSP_ERROR(-1, "record_up: unable to locate parent");
+    return record_init_cnid(r, r->tree, r->record.u.thread.parentID);
+
+  fail:
+    return -1;
+}
+
+#ifdef DEBUG
+
+/* print Quickdraw Point */
+static void record_print_Point(Point* p)
+{
+    printf("[ v=%d, h=%d ]", p->v, p->h);
+}
+
+/* print Quickdraw Rect */
+static void record_print_Rect(Rect* r)
+{
+    printf("[ top=%d, left=%d, bottom=%d, right=%d  ]",
+	     r->top, r->left, r->bottom, r->right);
+}
+
+/* print the key of a record */
+static void record_print_key(hfsp_cat_key* key)
+{
+    char buf[255]; // mh this _might_ overflow
+    unicode_uni2asc(buf, &key->name, 255);
+    printf("parent cnid :    %ld\n",   key->parent_cnid);
+    printf("name        :    %s\n", buf);
+}
+
+/* print permissions */
+static void record_print_perm(hfsp_perm* perm)
+{
+    printf("owner               :\t%ld\n",  perm->owner);
+    printf("group               :\t%ld\n",  perm->group);
+    printf("perm                :\t0x%lX\n",perm->mode);
+    printf("dev                 :\t%ld\n",  perm->dev);
+}
+
+/* print Directory info */
+static void record_print_DInfo(DInfo* dinfo)
+{
+    printf(  "frRect              :\t");    record_print_Rect(&dinfo->frRect);
+    printf("\nfrFlags             :\t0X%X\n",    dinfo->frFlags);
+    printf(  "frLocation          :\t");    record_print_Point(&dinfo->frLocation);
+    printf("\nfrView              :\t0X%X\n",    dinfo->frView);
+}
+
+/* print extended Directory info */
+static void record_print_DXInfo(DXInfo* xinfo)
+{
+    printf(  "frScroll            :\t");    record_print_Point(&xinfo->frScroll);
+    printf("\nfrOpenChain         :\t%ld\n",  xinfo->frOpenChain);
+    printf(  "frUnused            :\t%d\n",   xinfo->frUnused);
+    printf(  "frComment           :\t%d\n",   xinfo->frComment);
+    printf(  "frPutAway           :\t%ld\n",  xinfo->frPutAway);
+}
+
+static void record_print_folder(hfsp_cat_folder* folder)
+{
+    printf("flags               :\t0x%X\n",	folder->flags);
+    printf("valence             :\t0x%lX\n",	folder->valence);
+    printf("id                  :\t%ld\n",	folder->id);
+    record_print_perm	(&folder->permissions);
+    record_print_DInfo	(&folder->user_info);
+    record_print_DXInfo	(&folder->finder_info);
+    printf("text_encoding       :\t0x%lX\n",	folder->text_encoding);
+    printf("reserved            :\t0x%lX\n",	folder->reserved);
+}
+
+/* print File info */
+static void record_print_FInfo(FInfo* finfo)
+{
+    printf(  "fdType              :\t%4.4s\n", (char*) &finfo->fdType);
+    printf(  "fdCreator           :\t%4.4s\n", (char*) &finfo->fdCreator);
+    printf(  "fdFlags             :\t0X%X\n", finfo->fdFlags);
+    printf(  "fdLocation          :\t");     record_print_Point(&finfo->fdLocation);
+    printf("\nfdFldr              :\t%d\n",  finfo->fdFldr);
+}
+
+/* print extended File info */
+static void record_print_FXInfo(FXInfo* xinfo)
+{
+    printf(  "fdIconID            :\t%d\n",   xinfo->fdIconID);
+    // xinfo -> fdUnused;
+    printf(  "fdComment           :\t%d\n",   xinfo->fdComment);
+    printf(  "fdPutAway           :\t%ld\n",  xinfo->fdPutAway);
+}
+
+/* print folder entry */
+
+/* print file entry */
+static void record_print_file(hfsp_cat_file* file)
+{
+    printf("flags               :\t0x%X\n",	file->flags);
+    printf("reserved1           :\t0x%lX\n",	file->reserved1);
+    printf("id                  :\t%ld\n",	file->id);
+    record_print_perm	(&file->permissions);
+    record_print_FInfo	(&file->user_info);
+    record_print_FXInfo	(&file->finder_info);
+    printf("text_encoding       :\t0x%lX\n",	file->text_encoding);
+    printf("reserved            :\t0x%lX\n",	file->reserved2);
+    printf("Datafork:\n");
+    volume_print_fork (&file->data_fork);
+    printf("Rsrcfork:\n");
+    volume_print_fork (&file->res_fork);
+}
+
+/* print info for a file or folder thread */
+static void record_print_thread(hfsp_cat_thread* entry)
+{
+    char buf[255]; // mh this _might_ overflow
+    unicode_uni2asc(buf, &entry->nodeName, 255);
+    printf("parent cnid :\t%ld\n", entry->parentID);
+    printf("name        :\t%s\n" , buf);
+}
+
+/* print the information for a record */
+static void record_print_entry(hfsp_cat_entry* entry)
+{
+    switch (entry->type)
+    {
+	case HFSP_FOLDER:
+	    printf("=== Folder ===\n");
+	    return record_print_folder(&entry->u.folder);
+	case HFSP_FILE:
+	    printf("=== File ===\n");
+	    return record_print_file  (&entry->u.file);
+	case HFSP_FOLDER_THREAD:
+	    printf("=== Folder Thread ===\n");
+	    return record_print_thread(&entry->u.thread);
+	case HFSP_FILE_THREAD:
+	    printf("=== File Thread ==\n");
+	    return record_print_thread(&entry->u.thread);
+	default:
+	    printf("=== Unknown Record Type ===\n");
+    } ;
+}
+
+    /* Dump all the record information to stdout */
+void record_print(record* r)
+{
+    printf ("keyind      :    %u\n", r->keyind);
+    record_print_key  (&r->key);
+    record_print_entry(&r->record);
+}
+
+#endif
diff --git a/roms/openbios/fs/hfsplus/hfsp_unicode.c b/roms/openbios/fs/hfsplus/hfsp_unicode.c
new file mode 100644
index 000000000..7a34affa1
--- /dev/null
+++ b/roms/openbios/fs/hfsplus/hfsp_unicode.c
@@ -0,0 +1,511 @@
+/*
+ *  linux/fs/hfsplus/unicode.c
+ *
+ * Copyright (C) 1999-2000  Brad Boyer (flar@pants.nu)
+ * This file may be distributed under the terms of the GNU Public License.
+ *
+ * The routines found here convert hfs-unicode string into ascii Strings
+ * and vice versa.  And the correct comparison between Strings.
+ */
+
+
+#include "config.h"
+#include "libhfsp.h"
+#include "unicode.h"
+
+/* ISO-8859-1 -> unicode */
+static int
+asc2uni( unsigned char *ustr, const char *astr, int maxlen )
+{
+	int len;
+
+	if( maxlen <= 0 )
+		return 0;
+
+	for( len=0; *astr && len < maxlen-1 ; astr++, len++ ) {
+		*ustr++ = 0;
+		*ustr++ = *astr;
+	}
+	ustr[0] = ustr[1] = 0;
+	return len;
+}
+
+/* unicode -> ISO-8859-1 */
+static int
+uni2asc( char *astr, const unsigned char *ustr, int ustrlen, int maxlen )
+{
+	int len;
+
+	if( maxlen <= 0 )
+		return 0;
+
+	for( len=0; ustrlen-- > 0 && len < maxlen-1 ; ustr += 2 ) {
+		/* might be unrepresentable (or too complicated for us) */
+		if( ustr[0] || !ustr[1] )
+			continue;
+		if( ustr[1] < 0x20 || ustr[1] >= 0x7f )
+		    *astr++ = '?';
+		else
+		    *astr++ = ustr[1];
+		len++;
+	}
+	*astr = 0;
+	return len;
+}
+
+int
+unicode_asc2uni( hfsp_unistr255 *ustr, const char* astr )
+{
+	return ustr->strlen = asc2uni( (u8*)ustr->name, astr, 255 );
+}
+
+int
+unicode_uni2asc(char *astr, const hfsp_unistr255 *ustr, int maxlen)
+{
+	return uni2asc( astr, (u8*)ustr->name, ustr->strlen, maxlen );
+}
+
+/* The following code is almost as published by Apple, only
+   small modifications where made to match some linux styles ...
+
+fastUnicodeCompare - Compare two Unicode strings; produce a relative ordering
+*/
+
+static const UInt16 gLowerCaseTable[];
+
+SInt32 fast_unicode_compare ( const hfsp_unistr255 *ustr1,
+			      const hfsp_unistr255 *ustr2)
+{
+    register UInt16     c1,c2;
+    register SInt32	diff;
+    register UInt16     temp;
+    register UInt16	length1 = ustr1->strlen;
+    register UInt16	length2 = ustr2->strlen;
+    register const UInt16* lowerCaseTable = gLowerCaseTable;
+    register const UInt16* str1 = ustr1->name;
+    register const UInt16* str2 = ustr2->name;
+
+    while (1) {
+        //  Set default values for c1, c2 in case there are no more valid chars
+        c1 = c2 = 0;
+        //  Find next non-ignorable char from str1, or zero if no more
+        while (length1 && c1 == 0) {
+            c1 = *(str1++);
+            --length1;
+            if ((temp = lowerCaseTable[c1>>8]) != 0)        //  is there a subtable
+                                                            //  for this upper byte?
+                c1 = lowerCaseTable[temp + (c1 & 0x00FF)];  //  yes, so fold the char
+        }
+        //  Find next non-ignorable char from str2, or zero if no more
+        while (length2 && c2 == 0) {
+            c2 = *(str2++);
+            --length2;
+            if ((temp = lowerCaseTable[c2>>8]) != 0)        //  is there a subtable
+                                                            //  for this upper byte?
+                c2 = lowerCaseTable[temp + (c2 & 0x00FF)];  //  yes, so fold the char
+        }
+	diff = c2-c1;
+        if (diff)       //  found a difference, so stop looping
+            break;
+        if (c1 == 0)        //  did we reach the end of both strings at the same time?
+            return 0;       //  yes, so strings are equal
+    }
+    return diff;
+}
+
+
+/*  The lower case table consists of a 256-entry high-byte table followed by
+    some number of 256-entry subtables. The high-byte table contains either an
+    offset to the subtable for characters with that high byte or zero, which
+    means that there are no case mappings or ignored characters in that block.
+    Ignored characters are mapped to zero.
+ */
+
+static const UInt16 gLowerCaseTable[] = {
+
+    // High-byte indices ( == 0 iff no case mapping and no ignorables )
+
+
+    /* 0 */ 0x0100, 0x0200, 0x0000, 0x0300, 0x0400, 0x0500, 0x0000, 0x0000,
+            0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 1 */ 0x0600, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+            0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 2 */ 0x0700, 0x0800, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+            0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 3 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+            0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 4 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+            0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 5 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+            0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 6 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+            0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 7 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+            0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 8 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+            0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 9 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+            0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* A */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+            0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* B */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+            0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* C */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+            0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* D */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+            0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* E */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+            0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* F */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+            0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0900, 0x0A00,
+
+    // Table 1 (for high byte 0x00)
+
+    /* 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,
+
+    // Table 2 (for high byte 0x01)
+
+    /* 0 */ 0x0100, 0x0101, 0x0102, 0x0103, 0x0104, 0x0105, 0x0106, 0x0107,
+            0x0108, 0x0109, 0x010A, 0x010B, 0x010C, 0x010D, 0x010E, 0x010F,
+    /* 1 */ 0x0111, 0x0111, 0x0112, 0x0113, 0x0114, 0x0115, 0x0116, 0x0117,
+            0x0118, 0x0119, 0x011A, 0x011B, 0x011C, 0x011D, 0x011E, 0x011F,
+    /* 2 */ 0x0120, 0x0121, 0x0122, 0x0123, 0x0124, 0x0125, 0x0127, 0x0127,
+            0x0128, 0x0129, 0x012A, 0x012B, 0x012C, 0x012D, 0x012E, 0x012F,
+    /* 3 */ 0x0130, 0x0131, 0x0133, 0x0133, 0x0134, 0x0135, 0x0136, 0x0137,
+            0x0138, 0x0139, 0x013A, 0x013B, 0x013C, 0x013D, 0x013E, 0x0140,
+    /* 4 */ 0x0140, 0x0142, 0x0142, 0x0143, 0x0144, 0x0145, 0x0146, 0x0147,
+            0x0148, 0x0149, 0x014B, 0x014B, 0x014C, 0x014D, 0x014E, 0x014F,
+    /* 5 */ 0x0150, 0x0151, 0x0153, 0x0153, 0x0154, 0x0155, 0x0156, 0x0157,
+            0x0158, 0x0159, 0x015A, 0x015B, 0x015C, 0x015D, 0x015E, 0x015F,
+    /* 6 */ 0x0160, 0x0161, 0x0162, 0x0163, 0x0164, 0x0165, 0x0167, 0x0167,
+            0x0168, 0x0169, 0x016A, 0x016B, 0x016C, 0x016D, 0x016E, 0x016F,
+    /* 7 */ 0x0170, 0x0171, 0x0172, 0x0173, 0x0174, 0x0175, 0x0176, 0x0177,
+            0x0178, 0x0179, 0x017A, 0x017B, 0x017C, 0x017D, 0x017E, 0x017F,
+    /* 8 */ 0x0180, 0x0253, 0x0183, 0x0183, 0x0185, 0x0185, 0x0254, 0x0188,
+            0x0188, 0x0256, 0x0257, 0x018C, 0x018C, 0x018D, 0x01DD, 0x0259,
+    /* 9 */ 0x025B, 0x0192, 0x0192, 0x0260, 0x0263, 0x0195, 0x0269, 0x0268,
+            0x0199, 0x0199, 0x019A, 0x019B, 0x026F, 0x0272, 0x019E, 0x0275,
+    /* A */ 0x01A0, 0x01A1, 0x01A3, 0x01A3, 0x01A5, 0x01A5, 0x01A6, 0x01A8,
+            0x01A8, 0x0283, 0x01AA, 0x01AB, 0x01AD, 0x01AD, 0x0288, 0x01AF,
+    /* B */ 0x01B0, 0x028A, 0x028B, 0x01B4, 0x01B4, 0x01B6, 0x01B6, 0x0292,
+            0x01B9, 0x01B9, 0x01BA, 0x01BB, 0x01BD, 0x01BD, 0x01BE, 0x01BF,
+    /* C */ 0x01C0, 0x01C1, 0x01C2, 0x01C3, 0x01C6, 0x01C6, 0x01C6, 0x01C9,
+            0x01C9, 0x01C9, 0x01CC, 0x01CC, 0x01CC, 0x01CD, 0x01CE, 0x01CF,
+    /* D */ 0x01D0, 0x01D1, 0x01D2, 0x01D3, 0x01D4, 0x01D5, 0x01D6, 0x01D7,
+            0x01D8, 0x01D9, 0x01DA, 0x01DB, 0x01DC, 0x01DD, 0x01DE, 0x01DF,
+    /* E */ 0x01E0, 0x01E1, 0x01E2, 0x01E3, 0x01E5, 0x01E5, 0x01E6, 0x01E7,
+            0x01E8, 0x01E9, 0x01EA, 0x01EB, 0x01EC, 0x01ED, 0x01EE, 0x01EF,
+    /* F */ 0x01F0, 0x01F3, 0x01F3, 0x01F3, 0x01F4, 0x01F5, 0x01F6, 0x01F7,
+            0x01F8, 0x01F9, 0x01FA, 0x01FB, 0x01FC, 0x01FD, 0x01FE, 0x01FF,
+
+    // Table 3 (for high byte 0x03)
+
+    /* 0 */ 0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0305, 0x0306, 0x0307,
+            0x0308, 0x0309, 0x030A, 0x030B, 0x030C, 0x030D, 0x030E, 0x030F,
+    /* 1 */ 0x0310, 0x0311, 0x0312, 0x0313, 0x0314, 0x0315, 0x0316, 0x0317,
+            0x0318, 0x0319, 0x031A, 0x031B, 0x031C, 0x031D, 0x031E, 0x031F,
+    /* 2 */ 0x0320, 0x0321, 0x0322, 0x0323, 0x0324, 0x0325, 0x0326, 0x0327,
+            0x0328, 0x0329, 0x032A, 0x032B, 0x032C, 0x032D, 0x032E, 0x032F,
+    /* 3 */ 0x0330, 0x0331, 0x0332, 0x0333, 0x0334, 0x0335, 0x0336, 0x0337,
+            0x0338, 0x0339, 0x033A, 0x033B, 0x033C, 0x033D, 0x033E, 0x033F,
+    /* 4 */ 0x0340, 0x0341, 0x0342, 0x0343, 0x0344, 0x0345, 0x0346, 0x0347,
+            0x0348, 0x0349, 0x034A, 0x034B, 0x034C, 0x034D, 0x034E, 0x034F,
+    /* 5 */ 0x0350, 0x0351, 0x0352, 0x0353, 0x0354, 0x0355, 0x0356, 0x0357,
+            0x0358, 0x0359, 0x035A, 0x035B, 0x035C, 0x035D, 0x035E, 0x035F,
+    /* 6 */ 0x0360, 0x0361, 0x0362, 0x0363, 0x0364, 0x0365, 0x0366, 0x0367,
+            0x0368, 0x0369, 0x036A, 0x036B, 0x036C, 0x036D, 0x036E, 0x036F,
+    /* 7 */ 0x0370, 0x0371, 0x0372, 0x0373, 0x0374, 0x0375, 0x0376, 0x0377,
+            0x0378, 0x0379, 0x037A, 0x037B, 0x037C, 0x037D, 0x037E, 0x037F,
+    /* 8 */ 0x0380, 0x0381, 0x0382, 0x0383, 0x0384, 0x0385, 0x0386, 0x0387,
+            0x0388, 0x0389, 0x038A, 0x038B, 0x038C, 0x038D, 0x038E, 0x038F,
+    /* 9 */ 0x0390, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7,
+            0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
+    /* A */ 0x03C0, 0x03C1, 0x03A2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7,
+            0x03C8, 0x03C9, 0x03AA, 0x03AB, 0x03AC, 0x03AD, 0x03AE, 0x03AF,
+    /* B */ 0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7,
+            0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
+    /* C */ 0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7,
+            0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0x03CF,
+    /* D */ 0x03D0, 0x03D1, 0x03D2, 0x03D3, 0x03D4, 0x03D5, 0x03D6, 0x03D7,
+            0x03D8, 0x03D9, 0x03DA, 0x03DB, 0x03DC, 0x03DD, 0x03DE, 0x03DF,
+    /* E */ 0x03E0, 0x03E1, 0x03E3, 0x03E3, 0x03E5, 0x03E5, 0x03E7, 0x03E7,
+            0x03E9, 0x03E9, 0x03EB, 0x03EB, 0x03ED, 0x03ED, 0x03EF, 0x03EF,
+    /* F */ 0x03F0, 0x03F1, 0x03F2, 0x03F3, 0x03F4, 0x03F5, 0x03F6, 0x03F7,
+            0x03F8, 0x03F9, 0x03FA, 0x03FB, 0x03FC, 0x03FD, 0x03FE, 0x03FF,
+
+    // Table 4 (for high byte 0x04)
+
+    /* 0 */ 0x0400, 0x0401, 0x0452, 0x0403, 0x0454, 0x0455, 0x0456, 0x0407,
+            0x0458, 0x0459, 0x045A, 0x045B, 0x040C, 0x040D, 0x040E, 0x045F,
+    /* 1 */ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
+            0x0438, 0x0419, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
+    /* 2 */ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
+            0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
+    /* 3 */ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
+            0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
+    /* 4 */ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
+            0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
+    /* 5 */ 0x0450, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457,
+            0x0458, 0x0459, 0x045A, 0x045B, 0x045C, 0x045D, 0x045E, 0x045F,
+    /* 6 */ 0x0461, 0x0461, 0x0463, 0x0463, 0x0465, 0x0465, 0x0467, 0x0467,
+            0x0469, 0x0469, 0x046B, 0x046B, 0x046D, 0x046D, 0x046F, 0x046F,
+    /* 7 */ 0x0471, 0x0471, 0x0473, 0x0473, 0x0475, 0x0475, 0x0476, 0x0477,
+            0x0479, 0x0479, 0x047B, 0x047B, 0x047D, 0x047D, 0x047F, 0x047F,
+    /* 8 */ 0x0481, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487,
+            0x0488, 0x0489, 0x048A, 0x048B, 0x048C, 0x048D, 0x048E, 0x048F,
+    /* 9 */ 0x0491, 0x0491, 0x0493, 0x0493, 0x0495, 0x0495, 0x0497, 0x0497,
+            0x0499, 0x0499, 0x049B, 0x049B, 0x049D, 0x049D, 0x049F, 0x049F,
+    /* A */ 0x04A1, 0x04A1, 0x04A3, 0x04A3, 0x04A5, 0x04A5, 0x04A7, 0x04A7,
+            0x04A9, 0x04A9, 0x04AB, 0x04AB, 0x04AD, 0x04AD, 0x04AF, 0x04AF,
+    /* B */ 0x04B1, 0x04B1, 0x04B3, 0x04B3, 0x04B5, 0x04B5, 0x04B7, 0x04B7,
+            0x04B9, 0x04B9, 0x04BB, 0x04BB, 0x04BD, 0x04BD, 0x04BF, 0x04BF,
+    /* C */ 0x04C0, 0x04C1, 0x04C2, 0x04C4, 0x04C4, 0x04C5, 0x04C6, 0x04C8,
+            0x04C8, 0x04C9, 0x04CA, 0x04CC, 0x04CC, 0x04CD, 0x04CE, 0x04CF,
+    /* D */ 0x04D0, 0x04D1, 0x04D2, 0x04D3, 0x04D4, 0x04D5, 0x04D6, 0x04D7,
+            0x04D8, 0x04D9, 0x04DA, 0x04DB, 0x04DC, 0x04DD, 0x04DE, 0x04DF,
+    /* E */ 0x04E0, 0x04E1, 0x04E2, 0x04E3, 0x04E4, 0x04E5, 0x04E6, 0x04E7,
+            0x04E8, 0x04E9, 0x04EA, 0x04EB, 0x04EC, 0x04ED, 0x04EE, 0x04EF,
+    /* F */ 0x04F0, 0x04F1, 0x04F2, 0x04F3, 0x04F4, 0x04F5, 0x04F6, 0x04F7,
+            0x04F8, 0x04F9, 0x04FA, 0x04FB, 0x04FC, 0x04FD, 0x04FE, 0x04FF,
+
+    // Table 5 (for high byte 0x05)
+
+    /* 0 */ 0x0500, 0x0501, 0x0502, 0x0503, 0x0504, 0x0505, 0x0506, 0x0507,
+            0x0508, 0x0509, 0x050A, 0x050B, 0x050C, 0x050D, 0x050E, 0x050F,
+    /* 1 */ 0x0510, 0x0511, 0x0512, 0x0513, 0x0514, 0x0515, 0x0516, 0x0517,
+            0x0518, 0x0519, 0x051A, 0x051B, 0x051C, 0x051D, 0x051E, 0x051F,
+    /* 2 */ 0x0520, 0x0521, 0x0522, 0x0523, 0x0524, 0x0525, 0x0526, 0x0527,
+            0x0528, 0x0529, 0x052A, 0x052B, 0x052C, 0x052D, 0x052E, 0x052F,
+    /* 3 */ 0x0530, 0x0561, 0x0562, 0x0563, 0x0564, 0x0565, 0x0566, 0x0567,
+            0x0568, 0x0569, 0x056A, 0x056B, 0x056C, 0x056D, 0x056E, 0x056F,
+    /* 4 */ 0x0570, 0x0571, 0x0572, 0x0573, 0x0574, 0x0575, 0x0576, 0x0577,
+            0x0578, 0x0579, 0x057A, 0x057B, 0x057C, 0x057D, 0x057E, 0x057F,
+    /* 5 */ 0x0580, 0x0581, 0x0582, 0x0583, 0x0584, 0x0585, 0x0586, 0x0557,
+            0x0558, 0x0559, 0x055A, 0x055B, 0x055C, 0x055D, 0x055E, 0x055F,
+    /* 6 */ 0x0560, 0x0561, 0x0562, 0x0563, 0x0564, 0x0565, 0x0566, 0x0567,
+            0x0568, 0x0569, 0x056A, 0x056B, 0x056C, 0x056D, 0x056E, 0x056F,
+    /* 7 */ 0x0570, 0x0571, 0x0572, 0x0573, 0x0574, 0x0575, 0x0576, 0x0577,
+            0x0578, 0x0579, 0x057A, 0x057B, 0x057C, 0x057D, 0x057E, 0x057F,
+    /* 8 */ 0x0580, 0x0581, 0x0582, 0x0583, 0x0584, 0x0585, 0x0586, 0x0587,
+            0x0588, 0x0589, 0x058A, 0x058B, 0x058C, 0x058D, 0x058E, 0x058F,
+    /* 9 */ 0x0590, 0x0591, 0x0592, 0x0593, 0x0594, 0x0595, 0x0596, 0x0597,
+            0x0598, 0x0599, 0x059A, 0x059B, 0x059C, 0x059D, 0x059E, 0x059F,
+    /* A */ 0x05A0, 0x05A1, 0x05A2, 0x05A3, 0x05A4, 0x05A5, 0x05A6, 0x05A7,
+            0x05A8, 0x05A9, 0x05AA, 0x05AB, 0x05AC, 0x05AD, 0x05AE, 0x05AF,
+    /* B */ 0x05B0, 0x05B1, 0x05B2, 0x05B3, 0x05B4, 0x05B5, 0x05B6, 0x05B7,
+            0x05B8, 0x05B9, 0x05BA, 0x05BB, 0x05BC, 0x05BD, 0x05BE, 0x05BF,
+    /* C */ 0x05C0, 0x05C1, 0x05C2, 0x05C3, 0x05C4, 0x05C5, 0x05C6, 0x05C7,
+            0x05C8, 0x05C9, 0x05CA, 0x05CB, 0x05CC, 0x05CD, 0x05CE, 0x05CF,
+    /* D */ 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7,
+            0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,
+    /* E */ 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7,
+            0x05E8, 0x05E9, 0x05EA, 0x05EB, 0x05EC, 0x05ED, 0x05EE, 0x05EF,
+    /* F */ 0x05F0, 0x05F1, 0x05F2, 0x05F3, 0x05F4, 0x05F5, 0x05F6, 0x05F7,
+            0x05F8, 0x05F9, 0x05FA, 0x05FB, 0x05FC, 0x05FD, 0x05FE, 0x05FF,
+
+    // Table 6 (for high byte 0x10)
+
+    /* 0 */ 0x1000, 0x1001, 0x1002, 0x1003, 0x1004, 0x1005, 0x1006, 0x1007,
+            0x1008, 0x1009, 0x100A, 0x100B, 0x100C, 0x100D, 0x100E, 0x100F,
+    /* 1 */ 0x1010, 0x1011, 0x1012, 0x1013, 0x1014, 0x1015, 0x1016, 0x1017,
+            0x1018, 0x1019, 0x101A, 0x101B, 0x101C, 0x101D, 0x101E, 0x101F,
+    /* 2 */ 0x1020, 0x1021, 0x1022, 0x1023, 0x1024, 0x1025, 0x1026, 0x1027,
+            0x1028, 0x1029, 0x102A, 0x102B, 0x102C, 0x102D, 0x102E, 0x102F,
+    /* 3 */ 0x1030, 0x1031, 0x1032, 0x1033, 0x1034, 0x1035, 0x1036, 0x1037,
+            0x1038, 0x1039, 0x103A, 0x103B, 0x103C, 0x103D, 0x103E, 0x103F,
+    /* 4 */ 0x1040, 0x1041, 0x1042, 0x1043, 0x1044, 0x1045, 0x1046, 0x1047,
+            0x1048, 0x1049, 0x104A, 0x104B, 0x104C, 0x104D, 0x104E, 0x104F,
+    /* 5 */ 0x1050, 0x1051, 0x1052, 0x1053, 0x1054, 0x1055, 0x1056, 0x1057,
+            0x1058, 0x1059, 0x105A, 0x105B, 0x105C, 0x105D, 0x105E, 0x105F,
+    /* 6 */ 0x1060, 0x1061, 0x1062, 0x1063, 0x1064, 0x1065, 0x1066, 0x1067,
+            0x1068, 0x1069, 0x106A, 0x106B, 0x106C, 0x106D, 0x106E, 0x106F,
+    /* 7 */ 0x1070, 0x1071, 0x1072, 0x1073, 0x1074, 0x1075, 0x1076, 0x1077,
+            0x1078, 0x1079, 0x107A, 0x107B, 0x107C, 0x107D, 0x107E, 0x107F,
+    /* 8 */ 0x1080, 0x1081, 0x1082, 0x1083, 0x1084, 0x1085, 0x1086, 0x1087,
+            0x1088, 0x1089, 0x108A, 0x108B, 0x108C, 0x108D, 0x108E, 0x108F,
+    /* 9 */ 0x1090, 0x1091, 0x1092, 0x1093, 0x1094, 0x1095, 0x1096, 0x1097,
+            0x1098, 0x1099, 0x109A, 0x109B, 0x109C, 0x109D, 0x109E, 0x109F,
+    /* A */ 0x10D0, 0x10D1, 0x10D2, 0x10D3, 0x10D4, 0x10D5, 0x10D6, 0x10D7,
+            0x10D8, 0x10D9, 0x10DA, 0x10DB, 0x10DC, 0x10DD, 0x10DE, 0x10DF,
+    /* B */ 0x10E0, 0x10E1, 0x10E2, 0x10E3, 0x10E4, 0x10E5, 0x10E6, 0x10E7,
+            0x10E8, 0x10E9, 0x10EA, 0x10EB, 0x10EC, 0x10ED, 0x10EE, 0x10EF,
+    /* C */ 0x10F0, 0x10F1, 0x10F2, 0x10F3, 0x10F4, 0x10F5, 0x10C6, 0x10C7,
+            0x10C8, 0x10C9, 0x10CA, 0x10CB, 0x10CC, 0x10CD, 0x10CE, 0x10CF,
+    /* D */ 0x10D0, 0x10D1, 0x10D2, 0x10D3, 0x10D4, 0x10D5, 0x10D6, 0x10D7,
+            0x10D8, 0x10D9, 0x10DA, 0x10DB, 0x10DC, 0x10DD, 0x10DE, 0x10DF,
+    /* E */ 0x10E0, 0x10E1, 0x10E2, 0x10E3, 0x10E4, 0x10E5, 0x10E6, 0x10E7,
+            0x10E8, 0x10E9, 0x10EA, 0x10EB, 0x10EC, 0x10ED, 0x10EE, 0x10EF,
+    /* F */ 0x10F0, 0x10F1, 0x10F2, 0x10F3, 0x10F4, 0x10F5, 0x10F6, 0x10F7,
+            0x10F8, 0x10F9, 0x10FA, 0x10FB, 0x10FC, 0x10FD, 0x10FE, 0x10FF,
+
+    // Table 7 (for high byte 0x20)
+
+    /* 0 */ 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007,
+            0x2008, 0x2009, 0x200A, 0x200B, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 1 */ 0x2010, 0x2011, 0x2012, 0x2013, 0x2014, 0x2015, 0x2016, 0x2017,
+            0x2018, 0x2019, 0x201A, 0x201B, 0x201C, 0x201D, 0x201E, 0x201F,
+    /* 2 */ 0x2020, 0x2021, 0x2022, 0x2023, 0x2024, 0x2025, 0x2026, 0x2027,
+            0x2028, 0x2029, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x202F,
+    /* 3 */ 0x2030, 0x2031, 0x2032, 0x2033, 0x2034, 0x2035, 0x2036, 0x2037,
+            0x2038, 0x2039, 0x203A, 0x203B, 0x203C, 0x203D, 0x203E, 0x203F,
+    /* 4 */ 0x2040, 0x2041, 0x2042, 0x2043, 0x2044, 0x2045, 0x2046, 0x2047,
+            0x2048, 0x2049, 0x204A, 0x204B, 0x204C, 0x204D, 0x204E, 0x204F,
+    /* 5 */ 0x2050, 0x2051, 0x2052, 0x2053, 0x2054, 0x2055, 0x2056, 0x2057,
+            0x2058, 0x2059, 0x205A, 0x205B, 0x205C, 0x205D, 0x205E, 0x205F,
+    /* 6 */ 0x2060, 0x2061, 0x2062, 0x2063, 0x2064, 0x2065, 0x2066, 0x2067,
+            0x2068, 0x2069, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 7 */ 0x2070, 0x2071, 0x2072, 0x2073, 0x2074, 0x2075, 0x2076, 0x2077,
+            0x2078, 0x2079, 0x207A, 0x207B, 0x207C, 0x207D, 0x207E, 0x207F,
+    /* 8 */ 0x2080, 0x2081, 0x2082, 0x2083, 0x2084, 0x2085, 0x2086, 0x2087,
+            0x2088, 0x2089, 0x208A, 0x208B, 0x208C, 0x208D, 0x208E, 0x208F,
+    /* 9 */ 0x2090, 0x2091, 0x2092, 0x2093, 0x2094, 0x2095, 0x2096, 0x2097,
+            0x2098, 0x2099, 0x209A, 0x209B, 0x209C, 0x209D, 0x209E, 0x209F,
+    /* A */ 0x20A0, 0x20A1, 0x20A2, 0x20A3, 0x20A4, 0x20A5, 0x20A6, 0x20A7,
+            0x20A8, 0x20A9, 0x20AA, 0x20AB, 0x20AC, 0x20AD, 0x20AE, 0x20AF,
+    /* B */ 0x20B0, 0x20B1, 0x20B2, 0x20B3, 0x20B4, 0x20B5, 0x20B6, 0x20B7,
+            0x20B8, 0x20B9, 0x20BA, 0x20BB, 0x20BC, 0x20BD, 0x20BE, 0x20BF,
+    /* C */ 0x20C0, 0x20C1, 0x20C2, 0x20C3, 0x20C4, 0x20C5, 0x20C6, 0x20C7,
+            0x20C8, 0x20C9, 0x20CA, 0x20CB, 0x20CC, 0x20CD, 0x20CE, 0x20CF,
+    /* D */ 0x20D0, 0x20D1, 0x20D2, 0x20D3, 0x20D4, 0x20D5, 0x20D6, 0x20D7,
+            0x20D8, 0x20D9, 0x20DA, 0x20DB, 0x20DC, 0x20DD, 0x20DE, 0x20DF,
+    /* E */ 0x20E0, 0x20E1, 0x20E2, 0x20E3, 0x20E4, 0x20E5, 0x20E6, 0x20E7,
+            0x20E8, 0x20E9, 0x20EA, 0x20EB, 0x20EC, 0x20ED, 0x20EE, 0x20EF,
+    /* F */ 0x20F0, 0x20F1, 0x20F2, 0x20F3, 0x20F4, 0x20F5, 0x20F6, 0x20F7,
+            0x20F8, 0x20F9, 0x20FA, 0x20FB, 0x20FC, 0x20FD, 0x20FE, 0x20FF,
+
+    // Table 8 (for high byte 0x21)
+
+    /* 0 */ 0x2100, 0x2101, 0x2102, 0x2103, 0x2104, 0x2105, 0x2106, 0x2107,
+            0x2108, 0x2109, 0x210A, 0x210B, 0x210C, 0x210D, 0x210E, 0x210F,
+    /* 1 */ 0x2110, 0x2111, 0x2112, 0x2113, 0x2114, 0x2115, 0x2116, 0x2117,
+            0x2118, 0x2119, 0x211A, 0x211B, 0x211C, 0x211D, 0x211E, 0x211F,
+    /* 2 */ 0x2120, 0x2121, 0x2122, 0x2123, 0x2124, 0x2125, 0x2126, 0x2127,
+            0x2128, 0x2129, 0x212A, 0x212B, 0x212C, 0x212D, 0x212E, 0x212F,
+    /* 3 */ 0x2130, 0x2131, 0x2132, 0x2133, 0x2134, 0x2135, 0x2136, 0x2137,
+            0x2138, 0x2139, 0x213A, 0x213B, 0x213C, 0x213D, 0x213E, 0x213F,
+    /* 4 */ 0x2140, 0x2141, 0x2142, 0x2143, 0x2144, 0x2145, 0x2146, 0x2147,
+            0x2148, 0x2149, 0x214A, 0x214B, 0x214C, 0x214D, 0x214E, 0x214F,
+    /* 5 */ 0x2150, 0x2151, 0x2152, 0x2153, 0x2154, 0x2155, 0x2156, 0x2157,
+            0x2158, 0x2159, 0x215A, 0x215B, 0x215C, 0x215D, 0x215E, 0x215F,
+    /* 6 */ 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177,
+            0x2178, 0x2179, 0x217A, 0x217B, 0x217C, 0x217D, 0x217E, 0x217F,
+    /* 7 */ 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177,
+            0x2178, 0x2179, 0x217A, 0x217B, 0x217C, 0x217D, 0x217E, 0x217F,
+    /* 8 */ 0x2180, 0x2181, 0x2182, 0x2183, 0x2184, 0x2185, 0x2186, 0x2187,
+            0x2188, 0x2189, 0x218A, 0x218B, 0x218C, 0x218D, 0x218E, 0x218F,
+    /* 9 */ 0x2190, 0x2191, 0x2192, 0x2193, 0x2194, 0x2195, 0x2196, 0x2197,
+            0x2198, 0x2199, 0x219A, 0x219B, 0x219C, 0x219D, 0x219E, 0x219F,
+    /* A */ 0x21A0, 0x21A1, 0x21A2, 0x21A3, 0x21A4, 0x21A5, 0x21A6, 0x21A7,
+            0x21A8, 0x21A9, 0x21AA, 0x21AB, 0x21AC, 0x21AD, 0x21AE, 0x21AF,
+    /* B */ 0x21B0, 0x21B1, 0x21B2, 0x21B3, 0x21B4, 0x21B5, 0x21B6, 0x21B7,
+            0x21B8, 0x21B9, 0x21BA, 0x21BB, 0x21BC, 0x21BD, 0x21BE, 0x21BF,
+    /* C */ 0x21C0, 0x21C1, 0x21C2, 0x21C3, 0x21C4, 0x21C5, 0x21C6, 0x21C7,
+            0x21C8, 0x21C9, 0x21CA, 0x21CB, 0x21CC, 0x21CD, 0x21CE, 0x21CF,
+    /* D */ 0x21D0, 0x21D1, 0x21D2, 0x21D3, 0x21D4, 0x21D5, 0x21D6, 0x21D7,
+            0x21D8, 0x21D9, 0x21DA, 0x21DB, 0x21DC, 0x21DD, 0x21DE, 0x21DF,
+    /* E */ 0x21E0, 0x21E1, 0x21E2, 0x21E3, 0x21E4, 0x21E5, 0x21E6, 0x21E7,
+            0x21E8, 0x21E9, 0x21EA, 0x21EB, 0x21EC, 0x21ED, 0x21EE, 0x21EF,
+    /* F */ 0x21F0, 0x21F1, 0x21F2, 0x21F3, 0x21F4, 0x21F5, 0x21F6, 0x21F7,
+            0x21F8, 0x21F9, 0x21FA, 0x21FB, 0x21FC, 0x21FD, 0x21FE, 0x21FF,
+
+    // Table 9 (for high byte 0xFE)
+
+    /* 0 */ 0xFE00, 0xFE01, 0xFE02, 0xFE03, 0xFE04, 0xFE05, 0xFE06, 0xFE07,
+            0xFE08, 0xFE09, 0xFE0A, 0xFE0B, 0xFE0C, 0xFE0D, 0xFE0E, 0xFE0F,
+    /* 1 */ 0xFE10, 0xFE11, 0xFE12, 0xFE13, 0xFE14, 0xFE15, 0xFE16, 0xFE17,
+            0xFE18, 0xFE19, 0xFE1A, 0xFE1B, 0xFE1C, 0xFE1D, 0xFE1E, 0xFE1F,
+    /* 2 */ 0xFE20, 0xFE21, 0xFE22, 0xFE23, 0xFE24, 0xFE25, 0xFE26, 0xFE27,
+            0xFE28, 0xFE29, 0xFE2A, 0xFE2B, 0xFE2C, 0xFE2D, 0xFE2E, 0xFE2F,
+    /* 3 */ 0xFE30, 0xFE31, 0xFE32, 0xFE33, 0xFE34, 0xFE35, 0xFE36, 0xFE37,
+            0xFE38, 0xFE39, 0xFE3A, 0xFE3B, 0xFE3C, 0xFE3D, 0xFE3E, 0xFE3F,
+    /* 4 */ 0xFE40, 0xFE41, 0xFE42, 0xFE43, 0xFE44, 0xFE45, 0xFE46, 0xFE47,
+            0xFE48, 0xFE49, 0xFE4A, 0xFE4B, 0xFE4C, 0xFE4D, 0xFE4E, 0xFE4F,
+    /* 5 */ 0xFE50, 0xFE51, 0xFE52, 0xFE53, 0xFE54, 0xFE55, 0xFE56, 0xFE57,
+            0xFE58, 0xFE59, 0xFE5A, 0xFE5B, 0xFE5C, 0xFE5D, 0xFE5E, 0xFE5F,
+    /* 6 */ 0xFE60, 0xFE61, 0xFE62, 0xFE63, 0xFE64, 0xFE65, 0xFE66, 0xFE67,
+            0xFE68, 0xFE69, 0xFE6A, 0xFE6B, 0xFE6C, 0xFE6D, 0xFE6E, 0xFE6F,
+    /* 7 */ 0xFE70, 0xFE71, 0xFE72, 0xFE73, 0xFE74, 0xFE75, 0xFE76, 0xFE77,
+            0xFE78, 0xFE79, 0xFE7A, 0xFE7B, 0xFE7C, 0xFE7D, 0xFE7E, 0xFE7F,
+    /* 8 */ 0xFE80, 0xFE81, 0xFE82, 0xFE83, 0xFE84, 0xFE85, 0xFE86, 0xFE87,
+            0xFE88, 0xFE89, 0xFE8A, 0xFE8B, 0xFE8C, 0xFE8D, 0xFE8E, 0xFE8F,
+    /* 9 */ 0xFE90, 0xFE91, 0xFE92, 0xFE93, 0xFE94, 0xFE95, 0xFE96, 0xFE97,
+            0xFE98, 0xFE99, 0xFE9A, 0xFE9B, 0xFE9C, 0xFE9D, 0xFE9E, 0xFE9F,
+    /* A */ 0xFEA0, 0xFEA1, 0xFEA2, 0xFEA3, 0xFEA4, 0xFEA5, 0xFEA6, 0xFEA7,
+            0xFEA8, 0xFEA9, 0xFEAA, 0xFEAB, 0xFEAC, 0xFEAD, 0xFEAE, 0xFEAF,
+    /* B */ 0xFEB0, 0xFEB1, 0xFEB2, 0xFEB3, 0xFEB4, 0xFEB5, 0xFEB6, 0xFEB7,
+            0xFEB8, 0xFEB9, 0xFEBA, 0xFEBB, 0xFEBC, 0xFEBD, 0xFEBE, 0xFEBF,
+    /* C */ 0xFEC0, 0xFEC1, 0xFEC2, 0xFEC3, 0xFEC4, 0xFEC5, 0xFEC6, 0xFEC7,
+            0xFEC8, 0xFEC9, 0xFECA, 0xFECB, 0xFECC, 0xFECD, 0xFECE, 0xFECF,
+    /* D */ 0xFED0, 0xFED1, 0xFED2, 0xFED3, 0xFED4, 0xFED5, 0xFED6, 0xFED7,
+            0xFED8, 0xFED9, 0xFEDA, 0xFEDB, 0xFEDC, 0xFEDD, 0xFEDE, 0xFEDF,
+    /* E */ 0xFEE0, 0xFEE1, 0xFEE2, 0xFEE3, 0xFEE4, 0xFEE5, 0xFEE6, 0xFEE7,
+            0xFEE8, 0xFEE9, 0xFEEA, 0xFEEB, 0xFEEC, 0xFEED, 0xFEEE, 0xFEEF,
+    /* F */ 0xFEF0, 0xFEF1, 0xFEF2, 0xFEF3, 0xFEF4, 0xFEF5, 0xFEF6, 0xFEF7,
+            0xFEF8, 0xFEF9, 0xFEFA, 0xFEFB, 0xFEFC, 0xFEFD, 0xFEFE, 0x0000,
+
+    // Table 10 (for high byte 0xFF)
+
+    /* 0 */ 0xFF00, 0xFF01, 0xFF02, 0xFF03, 0xFF04, 0xFF05, 0xFF06, 0xFF07,
+            0xFF08, 0xFF09, 0xFF0A, 0xFF0B, 0xFF0C, 0xFF0D, 0xFF0E, 0xFF0F,
+    /* 1 */ 0xFF10, 0xFF11, 0xFF12, 0xFF13, 0xFF14, 0xFF15, 0xFF16, 0xFF17,
+            0xFF18, 0xFF19, 0xFF1A, 0xFF1B, 0xFF1C, 0xFF1D, 0xFF1E, 0xFF1F,
+    /* 2 */ 0xFF20, 0xFF41, 0xFF42, 0xFF43, 0xFF44, 0xFF45, 0xFF46, 0xFF47,
+            0xFF48, 0xFF49, 0xFF4A, 0xFF4B, 0xFF4C, 0xFF4D, 0xFF4E, 0xFF4F,
+    /* 3 */ 0xFF50, 0xFF51, 0xFF52, 0xFF53, 0xFF54, 0xFF55, 0xFF56, 0xFF57,
+            0xFF58, 0xFF59, 0xFF5A, 0xFF3B, 0xFF3C, 0xFF3D, 0xFF3E, 0xFF3F,
+    /* 4 */ 0xFF40, 0xFF41, 0xFF42, 0xFF43, 0xFF44, 0xFF45, 0xFF46, 0xFF47,
+            0xFF48, 0xFF49, 0xFF4A, 0xFF4B, 0xFF4C, 0xFF4D, 0xFF4E, 0xFF4F,
+    /* 5 */ 0xFF50, 0xFF51, 0xFF52, 0xFF53, 0xFF54, 0xFF55, 0xFF56, 0xFF57,
+            0xFF58, 0xFF59, 0xFF5A, 0xFF5B, 0xFF5C, 0xFF5D, 0xFF5E, 0xFF5F,
+    /* 6 */ 0xFF60, 0xFF61, 0xFF62, 0xFF63, 0xFF64, 0xFF65, 0xFF66, 0xFF67,
+            0xFF68, 0xFF69, 0xFF6A, 0xFF6B, 0xFF6C, 0xFF6D, 0xFF6E, 0xFF6F,
+    /* 7 */ 0xFF70, 0xFF71, 0xFF72, 0xFF73, 0xFF74, 0xFF75, 0xFF76, 0xFF77,
+            0xFF78, 0xFF79, 0xFF7A, 0xFF7B, 0xFF7C, 0xFF7D, 0xFF7E, 0xFF7F,
+    /* 8 */ 0xFF80, 0xFF81, 0xFF82, 0xFF83, 0xFF84, 0xFF85, 0xFF86, 0xFF87,
+            0xFF88, 0xFF89, 0xFF8A, 0xFF8B, 0xFF8C, 0xFF8D, 0xFF8E, 0xFF8F,
+    /* 9 */ 0xFF90, 0xFF91, 0xFF92, 0xFF93, 0xFF94, 0xFF95, 0xFF96, 0xFF97,
+            0xFF98, 0xFF99, 0xFF9A, 0xFF9B, 0xFF9C, 0xFF9D, 0xFF9E, 0xFF9F,
+    /* A */ 0xFFA0, 0xFFA1, 0xFFA2, 0xFFA3, 0xFFA4, 0xFFA5, 0xFFA6, 0xFFA7,
+            0xFFA8, 0xFFA9, 0xFFAA, 0xFFAB, 0xFFAC, 0xFFAD, 0xFFAE, 0xFFAF,
+    /* B */ 0xFFB0, 0xFFB1, 0xFFB2, 0xFFB3, 0xFFB4, 0xFFB5, 0xFFB6, 0xFFB7,
+            0xFFB8, 0xFFB9, 0xFFBA, 0xFFBB, 0xFFBC, 0xFFBD, 0xFFBE, 0xFFBF,
+    /* C */ 0xFFC0, 0xFFC1, 0xFFC2, 0xFFC3, 0xFFC4, 0xFFC5, 0xFFC6, 0xFFC7,
+            0xFFC8, 0xFFC9, 0xFFCA, 0xFFCB, 0xFFCC, 0xFFCD, 0xFFCE, 0xFFCF,
+    /* D */ 0xFFD0, 0xFFD1, 0xFFD2, 0xFFD3, 0xFFD4, 0xFFD5, 0xFFD6, 0xFFD7,
+            0xFFD8, 0xFFD9, 0xFFDA, 0xFFDB, 0xFFDC, 0xFFDD, 0xFFDE, 0xFFDF,
+    /* E */ 0xFFE0, 0xFFE1, 0xFFE2, 0xFFE3, 0xFFE4, 0xFFE5, 0xFFE6, 0xFFE7,
+            0xFFE8, 0xFFE9, 0xFFEA, 0xFFEB, 0xFFEC, 0xFFED, 0xFFEE, 0xFFEF,
+    /* F */ 0xFFF0, 0xFFF1, 0xFFF2, 0xFFF3, 0xFFF4, 0xFFF5, 0xFFF6, 0xFFF7,
+            0xFFF8, 0xFFF9, 0xFFFA, 0xFFFB, 0xFFFC, 0xFFFD, 0xFFFE, 0xFFFF,
+};
diff --git a/roms/openbios/fs/hfsplus/hfsp_volume.c b/roms/openbios/fs/hfsplus/hfsp_volume.c
new file mode 100644
index 000000000..2d624e23e
--- /dev/null
+++ b/roms/openbios/fs/hfsplus/hfsp_volume.c
@@ -0,0 +1,323 @@
+/*
+ * libhfs - library for reading and writing Macintosh HFS volumes
+ *
+ * Code to acces the basic volume information of a HFS+ volume.
+ *
+ * Copyright (C) 2000 Klaus Halfmann <khalfmann@libra.de>
+ * Original work by 1996-1998 Robert Leslie <rob@mars.org>
+ * other work 2000 from Brad Boyer (flar@pants.nu)
+ *
+ * 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.
+ *
+ * $Id: volume.c,v 1.21 2000/10/25 05:43:04 hasi Exp $
+ */
+
+#include "config.h"
+#include "libhfsp.h"
+#include "volume.h"
+#include "record.h"
+#include "btree.h"
+#include "blockiter.h"
+#include "os.h"
+#include "swab.h"
+#include "hfstime.h"
+
+
+/* Fill a given buffer with the given block in volume.
+ */
+int
+volume_readinbuf(volume * vol,void* buf, long block)
+{
+	UInt16 blksize_bits;
+	ASSERT( block < vol->maxblocks);
+
+	blksize_bits = vol->blksize_bits;
+	block	+= vol->startblock;
+	if( os_seek(vol->os_fd, block, blksize_bits) == block)
+		if( 1 == os_read(vol->os_fd, buf, 1, blksize_bits))
+			return 0;
+	return -1;
+}
+
+/* read multiple blocks into given memory.
+ *
+ * returns given pinter or NULL on failure.
+ */
+void*
+volume_readfromfork(volume* vol, void* buf,
+		hfsp_fork_raw* f, UInt32 block,
+		UInt32 count, UInt8 forktype, UInt32 fileId)
+{
+	blockiter iter;
+	char *cbuf = buf;
+
+	blockiter_init(&iter, vol, f, forktype, fileId);
+	if( blockiter_skip(&iter, block))
+		return NULL;
+
+	while( count > 0) {
+		--count;
+		if( volume_readinbuf(vol, cbuf, blockiter_curr(&iter)))
+			return NULL;
+		cbuf += vol->blksize;
+		if( count > 0 && blockiter_next(&iter))
+			return NULL;
+	}
+	return buf;
+}
+
+
+/* Read a raw hfsp_extent_rec from memory.
+ *
+ * return pointer right after the structure.
+ */
+void*
+volume_readextent(void *p, hfsp_extent_rec er)
+{
+	int 		i;
+	hfsp_extent	*e;
+
+	for( i=0; i < 8; i++) {
+		e = &er[i];
+		e->start_block = bswabU32_inc(p);
+		e->block_count = bswabU32_inc(p);
+	}
+	return p;
+}
+
+/* Read a raw hfsp_fork from memory.
+ *
+ * return pointer right after the structure.
+ */
+void*
+volume_readfork(void *p, hfsp_fork_raw* f)
+{
+	f->total_size   = bswabU64_inc(p);
+	f->clump_size   = bswabU32_inc(p);
+	f->total_blocks = bswabU32_inc(p);
+
+	return volume_readextent(p, f->extents);
+}
+
+/* Read the volume from the given buffer and swap the bytes.
+ *
+ * ToDo: add more consitency checks.
+ */
+static int
+volume_readbuf(hfsp_vh* vh, char * p)
+{
+	if(  (vh->signature = bswabU16_inc(p)) != HFSP_VOLHEAD_SIG)
+		HFSP_ERROR(-1, "This is not a HFS+ volume");
+
+	vh->version		= bswabU16_inc(p);
+	vh->attributes   	= bswabU32_inc(p);
+	vh->last_mount_vers	= bswabU32_inc(p);
+	vh->reserved		= bswabU32_inc(p);
+	vh->create_date		= bswabU32_inc(p);
+	vh->modify_date		= bswabU32_inc(p);
+	vh->backup_date		= bswabU32_inc(p);
+	vh->checked_date	= bswabU32_inc(p);
+	vh->file_count		= bswabU32_inc(p);
+	vh->folder_count	= bswabU32_inc(p);
+	vh->blocksize		= bswabU32_inc(p);
+	vh->total_blocks	= bswabU32_inc(p);
+	vh->free_blocks		= bswabU32_inc(p);
+	vh->next_alloc		= bswabU32_inc(p);
+	vh->rsrc_clump_sz	= bswabU32_inc(p);
+	vh->data_clump_sz	= bswabU32_inc(p);
+	vh->next_cnid		= bswabU32_inc(p);
+	vh->write_count		= bswabU32_inc(p);
+	vh->encodings_bmp	= bswabU64_inc(p);
+	memcpy(vh->finder_info, p, 32);
+	p += 32; // So finderinfo must be swapped later, ***
+	p = volume_readfork(p, &vh->alloc_file );
+	p = volume_readfork(p, &vh->ext_file   );
+	p = volume_readfork(p, &vh->cat_file   );
+	p = volume_readfork(p, &vh->attr_file  );
+        volume_readfork(p, &vh->start_file );
+	return 0;
+  fail:
+	return -1;
+}
+
+/* Read the volume from the given block */
+static int
+volume_read(volume * vol, hfsp_vh* vh, UInt32 block)
+{
+	char buf[vol->blksize];
+
+	if( volume_readinbuf(vol, buf, block))
+		return -1;
+        return volume_readbuf(vh, buf);
+}
+
+/* Find out wether the volume is wrapped and unwrap it eventually */
+static int
+volume_read_wrapper(volume * vol, hfsp_vh* vh)
+{
+	UInt16  signature;
+	char	buf[vol->blksize];
+        char    *p = buf;
+	int	ret;
+	UInt64	vol_size;
+	
+	if( volume_readinbuf(vol, buf, 2) ) // Wrapper or volume header starts here
+		return -1;
+
+	signature = bswabU16_inc(p);
+	if( signature == HFS_VOLHEAD_SIG) {		/* Wrapper */
+		UInt32  drAlBlkSiz;			/* size (in bytes) of allocation blocks */
+		UInt32	sect_per_block;			/* how may block build an hfs sector */
+		UInt16  drAlBlSt;			/* first allocation block in volume */
+		UInt16	embeds, embedl;			/* Start/lenght of embedded area in blocks */
+
+		p += 0x12;			/* skip unneded HFS vol fields */
+		drAlBlkSiz = bswabU32_inc(p);		/* offset 0x14 */
+		p += 0x4;			/* skip unneded HFS vol fields */
+		drAlBlSt = bswabU16_inc(p);		/* offset 0x1C */
+
+		p += 0x5E;			/* skip unneded HFS vol fields */
+		signature = bswabU16_inc(p);		/* offset 0x7C, drEmbedSigWord */
+		if( signature != HFSP_VOLHEAD_SIG)
+			HFSP_ERROR(-1, "This looks like a normal HFS volume");
+		embeds = bswabU16_inc(p);
+		embedl = bswabU16_inc(p);
+		sect_per_block =  (drAlBlkSiz / HFSP_BLOCKSZ);
+		// end is absolute (not relative to HFS+ start)
+		vol->maxblocks = embedl * sect_per_block;
+		vol->startblock = drAlBlSt + embeds * sect_per_block;
+		/* Now we can try to read the embedded HFS+ volume header */
+		return volume_read(vol,vh,2);
+	}
+	else if( signature == HFSP_VOLHEAD_SIG) { /* Native HFS+ volume */
+		p = buf; // Restore to begin of block
+                ret = volume_readbuf(vh, p);
+		if( !ret ) {
+		    /* When reading the initial partition we must use 512 byte blocks */
+		    vol_size = (uint64_t)vh->blocksize * vh->total_blocks;
+		    vol->maxblocks = vol_size / HFSP_BLOCKSZ;
+		}
+		
+		return ret;
+	} else
+		 HFSP_ERROR(-1, "Neither Wrapper nor native HFS+ volume header found");
+fail:
+	return -1;
+}
+
+
+/* Open the device, read and verify the volume header
+   (and its backup) */
+int
+volume_open( volume* vol, int os_fd )
+{
+	hfsp_vh backup;	/* backup volume found at second to last block */
+	long	sect_per_block;
+	int	shift;
+
+	vol->blksize_bits	= HFSP_BLOCKSZ_BITS;
+	vol->blksize		= HFSP_BLOCKSZ;
+	vol->startblock		= 0;
+	vol->maxblocks		= 3;
+		/* this should be enough until we find the volume descriptor */
+	vol->extents		= NULL; /* Thanks to Jeremias Sauceda */
+
+	btree_reset(&vol->catalog);
+	vol->os_fd = os_fd;
+
+	// vol->maxblocks = os_seek(vol->os_fd, -1, HFSP_BLOCKSZ_BITS);
+	// This wont work for /dev/... but we do not really need it
+
+	if( volume_read_wrapper(vol, &vol->vol))
+		return -1;
+	if( volume_read(vol, &backup, vol->maxblocks - 2))
+		return -1;
+
+	/* Now switch blksize from HFSP_BLOCKSZ (512) to value given in header
+	   and adjust depend values accordingly, after that a block always
+	   means a HFS+ allocation size */
+
+	/* Usually 4096 / 512  == 8 */
+	sect_per_block = vol->vol.blocksize / HFSP_BLOCKSZ;
+	shift = 0;
+	if( sect_per_block > 1) {
+		shift = 1;
+		while( sect_per_block > 2) {
+			sect_per_block >>=1;
+			shift++;
+		}		/* shift = 3 */
+	}
+	vol -> blksize_bits += shift;
+	vol -> blksize = 1 << vol->blksize_bits;
+	vol -> startblock >>= shift;
+	vol -> maxblocks = vol->vol.total_blocks;	/* cant calculate via shift ? */
+
+	if( btree_init_cat(&vol->catalog, vol, &vol->vol.cat_file))
+		return -1;
+
+	return 0;
+}
+
+/* Write back all data eventually cached and close the device */
+int
+volume_close(volume* vol)
+{
+	btree_close(&vol->catalog);
+	if( vol->extents) {
+		btree_close(vol->extents);
+		FREE(vol->extents);
+	}
+	return 0;
+}
+
+/* internal fucntion used to create the extents btree,
+   is called by inline function when needed */
+void
+volume_create_extents_tree(volume* vol)
+{
+	btree* result = (btree*) ALLOC(btree*, sizeof(btree));
+	if( !result)
+		HFSP_ERROR(ENOMEM, "No memory for extents btree");
+	if( !btree_init_extent(result, vol, &vol->vol.ext_file)) {
+		vol->extents = result;
+		return;
+	}
+  fail:
+	vol->extents = NULL;
+}
+
+/* Determine whether the volume is a HFS-plus volume */
+int
+volume_probe(int fd, long long offset)
+{
+	UInt16 *vol;
+	int ret = 0;
+
+	vol = (UInt16 *)malloc(2 * 1 << HFSP_BLOCKSZ_BITS);
+	os_seek_offset( fd, 2 * (1 << HFSP_BLOCKSZ_BITS) + offset );
+	os_read(fd, vol, 2, HFSP_BLOCKSZ_BITS);
+
+	if (__be16_to_cpu(vol[0]) == HFS_VOLHEAD_SIG &&
+		__be16_to_cpu(vol[0x3e]) == HFSP_VOLHEAD_SIG) {
+		ret = -1;
+	} else if (__be16_to_cpu(vol[0]) == HFSP_VOLHEAD_SIG) {
+		ret = -1;
+	}
+
+	free(vol);
+	return ret;
+}
+
diff --git a/roms/openbios/fs/hfsplus/include/apple.h b/roms/openbios/fs/hfsplus/include/apple.h
new file mode 100644
index 000000000..7ba836db6
--- /dev/null
+++ b/roms/openbios/fs/hfsplus/include/apple.h
@@ -0,0 +1,111 @@
+/*
+ * libhfsp - library for reading and writing Macintosh HFS+ volumes
+ *
+ * This file contains defintions that are special for Apple.
+ * The names match the defintions found in Apple Header files.
+ *
+ * Copyright (C) 2000 Klaus Halfmann <khalfmann@libra.de>
+ * Original code 1996-1998 by Robert Leslie <rob@mars.rog>
+ * other work 2000 from Brad Boyer (flar@pants.nu)
+ *
+ * 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.
+ *
+ * $Id: apple.h,v 1.2 2000/09/08 14:55:08 hasi Exp $
+ */
+
+typedef signed char	    Char;
+typedef unsigned char	    UChar;
+typedef signed char	    SInt8;
+typedef unsigned char	    UInt8;
+typedef signed short	    SInt16;
+typedef unsigned short	    UInt16;
+typedef signed long	    SInt32;
+typedef unsigned long	    UInt32;
+typedef unsigned long	    OSType;
+typedef unsigned long long  UInt64;
+
+/* A point, normally used by Quickdraw,
+ * but found in Finderinformation, too
+ */
+typedef struct {
+  SInt16	v;		/* vertical coordinate */
+  SInt16	h;		/* horizontal coordinate */
+} Point;
+
+/* A rectancle, normally used by Quickdraw,
+ * but found in Finderinformation, too.
+ */
+typedef struct {
+  SInt16	top;		/* top edge of rectangle */
+  SInt16	left;		/* left edge */
+  SInt16	bottom;		/* bottom edge */
+  SInt16	right;		/* right edge */
+} Rect;
+
+/* Information about the location and size of a folder
+ * used by the Finder.
+ */
+typedef struct {
+  Rect		frRect;		/* folder's rectangle */
+  SInt16	frFlags;	/* flags */
+  Point		frLocation;	/* folder's location */
+  SInt16	frView;		/* folder's view */
+} DInfo;
+
+/* Extended folder information used by the Finder ...
+ */
+typedef struct {
+  Point		frScroll;	/* scroll position */
+  SInt32	frOpenChain;	/* directory ID chain of open folders */
+  SInt16	frUnused;	/* reserved */
+  SInt16	frComment;	/* comment ID */
+  SInt32	frPutAway;	/* directory ID */
+} DXInfo;
+
+/* Finder information for a File
+ */
+typedef struct {
+  OSType	fdType;		/* file type */
+  OSType	fdCreator;	/* file's creator */
+  SInt16	fdFlags;	/* flags */
+  Point		fdLocation;	/* file's location */
+  SInt16	fdFldr;		/* file's window */
+} FInfo;
+
+/* Extendend Finder Information for a file
+ */
+typedef struct {
+  SInt16	fdIconID;	/* icon ID */
+  SInt16	fdUnused[4];	/* reserved */
+  SInt16	fdComment;	/* comment ID */
+  SInt32	fdPutAway;	/* home directory ID */
+} FXInfo;
+
+/* Flagvalues for FInfo and DInfo */
+# define HFS_FNDR_ISONDESK              (1 <<  0)
+# define HFS_FNDR_COLOR                 0x0e
+# define HFS_FNDR_COLORRESERVED         (1 <<  4)
+# define HFS_FNDR_REQUIRESSWITCHLAUNCH  (1 <<  5)
+# define HFS_FNDR_ISSHARED              (1 <<  6)
+# define HFS_FNDR_HASNOINITS            (1 <<  7)
+# define HFS_FNDR_HASBEENINITED         (1 <<  8)
+# define HFS_FNDR_RESERVED              (1 <<  9)
+# define HFS_FNDR_HASCUSTOMICON         (1 << 10)
+# define HFS_FNDR_ISSTATIONERY          (1 << 11)
+# define HFS_FNDR_NAMELOCKED            (1 << 12)
+# define HFS_FNDR_HASBUNDLE             (1 << 13)
+# define HFS_FNDR_ISINVISIBLE           (1 << 14)
+# define HFS_FNDR_ISALIAS               (1 << 15)
diff --git a/roms/openbios/fs/hfsplus/include/blockiter.h b/roms/openbios/fs/hfsplus/include/blockiter.h
new file mode 100644
index 000000000..da3e480fd
--- /dev/null
+++ b/roms/openbios/fs/hfsplus/include/blockiter.h
@@ -0,0 +1,59 @@
+/*
+ * libhfs - library for reading and writing Macintosh HFS volumes
+ *
+ * The iterator shown here iterates over the blocks of a fork.
+ *
+ * Copyright (C) 2000 Klaus Halfmann <khalfmann@libra.de>
+ * Original work by 1996-1998 Robert Leslie <rob@mars.org>
+ * other work 2000 from Brad Boyer (flar@pants.nu)
+ *
+ * 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.
+ *
+ * $Id: blockiter.h,v 1.1 2000/10/10 11:14:05 hasi Exp $
+ */
+
+/*  Structure of the blockiterator */
+typedef struct
+{
+    volume*	    vol;	// volume we iterate over
+    UInt32	    curr_block;	// current, absolute block
+    UInt32	    block;	// relative block in current extent
+    UInt32	    max_block;	// Maximum allowed block
+    UInt32	    fileId;	// id of file we iterate over
+    int		    index;	// 0 .. 7 in current extent
+    hfsp_extent*    file;	// original extent record from file
+    hfsp_extent*    e;		// current extentent under examination
+    UInt8	    forktype;	// type of fork we iterate over
+    UInt8	    in_extent;	// boolean  0 - in file extent
+				//	    1 - in extents file
+    extent_record   er;		// record to iterate in extents file.
+} blockiter;
+
+/* Initialize iterator for a given fork */
+extern void blockiter_init(blockiter* b, volume* vol, hfsp_fork_raw* f,
+			    UInt8 forktype, UInt32 fileId);
+
+/* find next block of the fork iterating over */
+extern int blockiter_next(blockiter *b);
+
+/* skip the indicated number of blocks */
+extern int blockiter_skip(blockiter *b, UInt32 skip);
+
+/* return current block */
+static inline UInt32 blockiter_curr(blockiter *b)
+{
+    return b->e->start_block + b->block;
+}
diff --git a/roms/openbios/fs/hfsplus/include/btree.h b/roms/openbios/fs/hfsplus/include/btree.h
new file mode 100644
index 000000000..46ac8501f
--- /dev/null
+++ b/roms/openbios/fs/hfsplus/include/btree.h
@@ -0,0 +1,50 @@
+/*
+ * libhfs - library for reading and writing Macintosh HFS volumes.
+ *
+ * The fucntions are used to handle the various forms of btrees
+ * found on HFS+ volumes.
+ *
+ * Copyright (C) 2000 Klaus Halfmann <khalfmann@libra.de>
+ * Original 1996-1998 Robert Leslie <rob@mars.org>
+ * Additional work by  Brad Boyer (flar@pants.nu)
+ *
+ * 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.
+ *
+ * $Id: btree.h,v 1.10 2000/10/25 05:43:04 hasi Exp $
+ */
+
+/** Intialize catalog btree, so that btree_close can safely be called. */
+extern void btree_reset(btree* bt);
+
+/** Intialize catalog btree */
+extern int btree_init_cat(btree* bt, volume* vol, hfsp_fork_raw* fork);
+
+/** Intialize extents btree */
+extern int btree_init_extent(btree* bt, volume* vol, hfsp_fork_raw* fork);
+
+/** close the btree and free any resources */
+extern void btree_close(btree* bt);
+
+/* Read node at given index */
+extern node_buf* btree_node_by_index(btree* bt, UInt16 index);
+
+/* returns pointer to key given by index in current node */
+extern void* btree_key_by_index(btree* bt, node_buf* buf, UInt16 index);
+
+#ifdef DEBUG
+    /* Dump all the btree information to stdout */
+  extern void btree_print(btree* bt);
+#endif
diff --git a/roms/openbios/fs/hfsplus/include/hfs.h b/roms/openbios/fs/hfsplus/include/hfs.h
new file mode 100644
index 000000000..5b0cbb490
--- /dev/null
+++ b/roms/openbios/fs/hfsplus/include/hfs.h
@@ -0,0 +1,32 @@
+/*
+ * libhfsp - library for reading and writing Macintosh HFS+ volumes
+ *
+ * This file includes definitions for access to old HFS structures.
+ *
+ * Copyright (C) 2000 Klaus Halfmann <khalfmann@libra.de>
+ * Original code 1996-1998 by Robert Leslie <rob@mars.rog>
+ * other work 2000 from Brad Boyer (flar@pants.nu)
+ *
+ * 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.
+ *
+ * $Id: hfs.h,v 1.1.1.1 2000/07/25 10:33:40 kkaempf Exp $
+ */
+
+
+#define HFS_BLOCKSZ		512
+	/* A sector for Apple is always 512 bytes */
+#define HFS_BLOCKSZ_BITS	9	/* 1<<9 == 512  */
+#define	HFS_VOLHEAD_SIG		0x4244	/* 'BD'	*/
diff --git a/roms/openbios/fs/hfsplus/include/hfsp.h b/roms/openbios/fs/hfsplus/include/hfsp.h
new file mode 100644
index 000000000..e916473c6
--- /dev/null
+++ b/roms/openbios/fs/hfsplus/include/hfsp.h
@@ -0,0 +1,305 @@
+/*
+ * libhfsp - library for reading and writing Macintosh HFS+ volumes
+ *
+ * This file includes definitions for the structures found on
+ * HFS+ Volumes. The structures are further wrapped by struct
+ * found in libhfsp.h. fucntions on those enhanced structures
+ * are found in files mentioned in comments below.
+ *
+ * Copyright (C) 2000 Klaus Halfmann <khalfmann@libra.de>
+ * Original code 1996-1998 by Robert Leslie <rob@mars.rog>
+ * other work 2000 from Brad Boyer (flar@pants.nu)
+ *
+ * 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.
+ *
+ * $Id: hfsp.h,v 1.17 2000/10/20 06:16:52 hasi Exp $
+ */
+
+#define HFSP_BLOCKSZ            512	/* A sector for Apple is always 512 bytes */
+#define HFSP_BLOCKSZ_BITS       9	/* 1<<9 == 512  */
+#define	HFSP_VOLHEAD_SIG	0x482B	/* 'H+'	*/
+
+/* HFS+ includes POSIX permissions , although marked as reserved they will be
+ * used as such. Is ignored by MacOS 8-9 but probably not by MacOS X.
+ */
+typedef struct {
+        UInt32         owner;
+        UInt32         group;
+        UInt32         mode;
+        UInt32         dev;
+} hfsp_perm;
+
+/* A single contiguous area (fragment) of a file */
+typedef struct {
+        UInt32         start_block;
+        UInt32         block_count;
+} hfsp_extent;
+
+/* A file may contain up to 8 normale extents, all other
+   are found in some extra extent area */
+typedef hfsp_extent hfsp_extent_rec[8];
+
+/* Information for a "Fork" in a file
+ * Forks are the "usual" DATA and RSRC forks or special files
+ * (e.g. the Volume Bitmap)
+ */
+typedef struct {
+        UInt64		total_size;  // logical size
+        UInt32		clump_size;  // number of bytes to preallocate
+        UInt32		total_blocks;
+        hfsp_extent_rec extents;     // initial (8) extents
+} hfsp_fork_raw;
+
+/* HFS+ Volume Header
+ * Always found at block 2 of the disk, a copy is stored
+ * at the second to last block of the disk.
+ */
+typedef struct hfsp_vh {
+        UInt16         signature;   // must be HFSPLUS_VOLHEAD_SIG 'H+'
+        UInt16         version;     // currently 4, ignored
+        UInt32         attributes;  // See bit constants below
+        UInt32         last_mount_vers;
+                // Use a registered creator code here (what do we use ?)
+		// Mac OS uses '8.10' well
+        UInt32         reserved;
+
+        UInt32         create_date; // local time !
+        UInt32         modify_date; // GMT (?)
+        UInt32         backup_date; // GMT (?)
+        UInt32         checked_date; // GMT (?) fsck ?
+
+        UInt32         file_count;
+         // not including special files but including DATA and RSRC forks
+        UInt32         folder_count; // excluding the root folder
+
+        UInt32         blocksize;
+         // must be multiple of HFSPLUS_SECTOR_SIZE,
+         // should be a multiple of 4k for harddisk
+        UInt32         total_blocks;
+        UInt32         free_blocks;
+         // The total number of unused allocation blocks on the disk.
+
+        UInt32         next_alloc;
+         // hint wher to search for next allocation blocks
+        UInt32         rsrc_clump_sz;
+         // default clump size for rsrc forks
+        UInt32         data_clump_sz;
+         // default clump size for data forks
+        UInt32	       next_cnid;
+         // next unused catalog id
+        UInt32         write_count;
+         // increment on every mount (and write ?)
+        UInt64        encodings_bmp;
+                // for every encoding used on the disk a bit is set
+                // ignored but eventually must be cared for
+        Char          finder_info[32];
+	hfsp_fork_raw   alloc_file;
+         // stores bitmap of use/free blocks
+        hfsp_fork_raw   ext_file;
+         // stores oferflow extents
+        hfsp_fork_raw   cat_file;
+	 // This contains the root directory
+        hfsp_fork_raw   attr_file;
+        hfsp_fork_raw   start_file;
+         // a special startup file may be described here (used by ?)
+} hfsp_vh;
+
+/* HFS+ volume attributes */
+/* 0-6 reserved, may be used in memory only */
+#define HFSPLUS_VOL_RESERVED1 0x000000FF
+#define HFSPLUS_VOL_HARDLOCK  0x00000080 // Used in Memory by finder only
+#define HFSPLUS_VOL_UNMNT     0x00000100
+        // clear this bit when mounting, set as last step of unmounting
+        // This is checked by (slower) ROM code
+#define HFSPLUS_VOL_SPARE_BLK 0x00000200
+#define HFSPLUS_VOL_NOCACHE   0x00000400
+        // in case of RAM or ROM disk (try a HFS+ Ramdisk :)
+#define HFSPLUS_VOL_INCNSTNT  0x00000800
+        // Reverse meaning as of HFSPLUS_VOL_UNMNT
+        // This is checked by (faster) Mac OS code
+/* 12-14 reserved */
+#define HFSPLUS_VOL_RESERVED2 0x00007000
+#define HFSPLUS_VOL_SOFTLOCK  0x00008000
+#define HFSPLUS_VOL_RESERVED3 0xFFFF0000
+
+/* HFS+ Btree node descriptor */
+typedef struct {
+	UInt32	    next;   /* pointer to next node of this kind, or 0 */
+	UInt32	    prev;   /* pointer to previous node of this kind, or 0 */
+	UInt8	    kind;   /* see below */
+	UInt8	    height; /* root node starts with 0 */
+	UInt16	    num_rec;	/* number of records in this node */
+	UInt16	    reserved;	/* fill up to 4 byte alignment */
+} btree_node_desc;
+
+/* HFS+ Btree Node types */
+#define HFSP_NODE_NDX	0x00
+#define HFSP_NODE_HEAD	0x01
+#define HFSP_NODE_MAP	0x02
+#define HFSP_NODE_LEAF	0xFF
+
+#define HFSP_CATALOG_MIN_NODE_SIZE  0x1000
+#define HFSP_ATTRMIN_DOE_SIZE	    0x1000
+
+/* The record offsets are found at the end of the fork
+ * containing the Btree */
+
+typedef UInt16	btree_record_offset;
+
+typedef struct {
+        UInt16         depth;
+	    // equal to height of btree_node_desc
+        UInt32         root;
+	    // root node of the hierarchy
+        UInt32         leaf_count;
+        UInt32         leaf_head;
+        UInt32         leaf_tail;
+        UInt16         node_size;
+	    // node size of _all_ nodes in this fork
+        UInt16         max_key_len;
+        UInt32         node_count;
+	    // count of all (free and used) nodes in tree
+        UInt32         free_nodes;
+        UInt16         reserved1;
+        UInt32         clump_size;
+         // ignored my MacOS used by ?
+        UInt8	       btree_type;
+         // always 0 for HFS+
+        UInt8	       reserved2;
+        UInt32         attributes;
+	 // see below
+        UInt32         reserved3[16];
+} btree_head;
+
+/* BTree attributes */
+#define HFSPLUS_BAD_CLOSE            0x01
+  // Btree was not properly closed and should be checked
+  // not used for HFS+ but reserved
+#define HFSPLUS_TREE_BIGKEYS         0x02
+  // always set for HFS+
+#define HFSPLUS_TREE_VAR_NDXKEY_SIZE 0x04
+  // use variable length index nodes, always set for catalog btree,
+  // always cleared for extents btree.
+
+#define HFSPLUS_TREE_UNUSED          0xFFFFFFF8
+
+/* Some special File ID numbers */
+#define HFSP_POR_CNID             1  /* Parent Of the Root */
+#define HFSP_ROOT_CNID            2  /* ROOT directory */
+#define HFSP_EXT_CNID             3  /* EXTents B-tree */
+#define HFSP_CAT_CNID             4  /* CATalog B-tree */
+#define HFSP_BAD_CNID             5  /* BAD blocks file */
+#define HFSP_ALLOC_CNID           6  /* ALLOCation file */
+#define HFSP_START_CNID           7  /* STARTup file */
+#define HFSP_ATTR_CNID            8  /* ATTRibutes file  */
+#define HFSP_EXCH_CNID           15  /* ExchangeFiles temp id */
+#define HFPS_MIN_CNID		 15  /* Minimum expected value */
+
+/* Unicode String */
+typedef struct {
+    UInt16		strlen;
+    UInt16		name[255];	// unicode charcters
+} hfsp_unistr255;
+
+/* HFS+ catalog entry key */
+typedef struct {
+    UInt16		key_length;	/* excluding length */
+    UInt32		parent_cnid;
+    hfsp_unistr255	name;
+} hfsp_cat_key;
+
+/* HFS+ exnteds entry key */
+typedef struct {
+    UInt16		key_length;	/* excluding length */
+    UInt8		fork_type;	/* Seee below */
+    UInt8		filler;
+    UInt32		file_id;
+    UInt32		start_block;
+} hfsp_extent_key;
+
+#define HFSP_EXTENT_DATA    0x00
+#define HFSP_EXTENT_RSRC    0xFF
+
+/* The key is followed by a record, an index or some other data */
+
+/* The types of these records are defined as follows */
+
+#define HFSP_FOLDER         0x0001  // entry fo a Folder
+#define HFSP_FILE           0x0002  // entry for a File
+#define HFSP_FOLDER_THREAD  0x0003
+    // Like '.' in unix, identifies the folder by its id, only
+#define HFSP_FILE_THREAD    0x0004
+    // Im unsure if this is used by HFS+, too
+
+/* HFS+ folder data (part of an hfsp_cat_entry) */
+typedef struct {
+    UInt16          flags;		/* no flags defined yet */
+    UInt32	    valence;		/* Numer of files and folders contained in folder */
+    UInt32	    id;
+    UInt32	    create_date;	// GMT
+    UInt32	    content_mod_date;	// GMT
+    UInt32	    attribute_mod_date;	// GMT
+    UInt32	    access_date;	// GMT
+    UInt32	    backup_date;	// GMT
+    hfsp_perm	    permissions;
+    DInfo	    user_info;
+    DXInfo	    finder_info;
+    UInt32	    text_encoding;
+	 // hint fo the finder what encoding to use, unused here
+    UInt32         reserved;
+} hfsp_cat_folder;
+
+/* HFS+ file data (part of a cat_entry) */
+typedef struct {
+    UInt16          flags;		/* See below */
+    UInt32	    reserved1;
+    UInt32	    id;
+    UInt32	    create_date;
+    UInt32	    content_mod_date;
+    UInt32	    attribute_mod_date;
+    UInt32	    access_date;
+    UInt32	    backup_date;
+    hfsp_perm	    permissions;
+    FInfo           user_info;
+    FXInfo	    finder_info;
+    UInt32	    text_encoding;
+    UInt32	    reserved2;
+
+    hfsp_fork_raw   data_fork;
+    hfsp_fork_raw   res_fork;
+} hfsp_cat_file;
+
+/* File attribute bits */
+#define HFSP_FILE_LOCKED      0x0001
+#define HFSP_THREAD_EXISTS    0x0002 /* Always set in HFS+ */
+
+/* HFS+ catalog thread (part of a cat_entry) */
+typedef struct {
+    UInt16          reserved;
+    UInt32	    parentID;
+    hfsp_unistr255   nodeName;
+} hfsp_cat_thread;
+
+
+/* A data record in the catalog tree */
+typedef struct {
+    UInt16	    type;
+    union {
+	hfsp_cat_folder folder;
+	hfsp_cat_file   file;
+	hfsp_cat_thread thread;
+    } u;
+} hfsp_cat_entry;
diff --git a/roms/openbios/fs/hfsplus/include/hfstime.h b/roms/openbios/fs/hfsplus/include/hfstime.h
new file mode 100644
index 000000000..bb6bd4a6e
--- /dev/null
+++ b/roms/openbios/fs/hfsplus/include/hfstime.h
@@ -0,0 +1,34 @@
+/*
+ * libhfs - library for reading and writing Macintosh HFS volumes
+ * Copyright (C) 2000 Klaus Halfmann <khalfmann@libra.de>^
+ * Original 1996-1998 Robert Leslie <rob@mars.org>
+ * other work 2000 from Brad Boyer (flar@pants.nu)
+ *
+ * The HFS+ dates are stored as UInt32 containing the number of seconds since
+ * midnight, January 1, 1904, GMT. This is slightly different from HFS,
+ * where the value represents local time. A notable exception is the
+ * creationdate !. Linux uses times in GMT starting at  January 1, 1970
+ *
+ * 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.
+ *
+ * $Id: hfstime.h,v 1.2 2000/10/19 13:33:38 hasi Exp $
+ */
+
+    /* The number of seconds between 1.1.1904 and 1.1.1970 */
+#define HFSPTIMEDIFF 2082844800U
+
+   /* return the given apple time as UNIX time */
+extern char* get_atime(UInt32 atime);
diff --git a/roms/openbios/fs/hfsplus/include/libhfsp.h b/roms/openbios/fs/hfsplus/include/libhfsp.h
new file mode 100644
index 000000000..912cfbd05
--- /dev/null
+++ b/roms/openbios/fs/hfsplus/include/libhfsp.h
@@ -0,0 +1,201 @@
+/*
+ * libhfs - library for reading and writing Macintosh HFS volumes
+ * Copyright (C) 2000 Klaus Halfmann (khalfmann@libra.de)
+ * Original work by 1996-1998 Robert Leslie (rob@mars.org)
+ *
+ * This file defines constants,structs etc needed for this library.
+ * Everything found here is usually not related to Apple defintions.
+ *
+ * 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.
+ *
+ * $Id: libhfsp.h,v 1.17 2000/10/20 06:16:52 hasi Exp $
+ */
+
+# include "apple.h"
+# include "hfs.h"
+# include "hfsp.h"
+
+/* Last error is eventually found here */
+extern const char *hfsp_error;
+
+# define HFSP_ERROR(code, str)  \
+    do { hfsp_error = (str), errno = (code); goto fail; } while (0)
+
+# ifdef DEBUG
+#  define ASSERT(cond)	do { if (! (cond)) abort(); } while (0)
+# else
+#  define ASSERT(cond)	/* nothing */
+# endif
+
+# define SIZE(type, n)		((size_t) (sizeof(type) * (n)))
+# define ALLOC(type, n)		((type *) malloc(SIZE(type, n)))
+# define ALLOCX(type, n)	((n) ? ALLOC(type, n) : (type *) 0)
+# define FREE(ptr)		((ptr) ? (void) free((void *) ptr) : (void) 0)
+
+# define REALLOC(ptr, type, n)  \
+    ((type *) ((ptr) ? realloc(ptr, SIZE(type, n)) : malloc(SIZE(type, n))))
+# define REALLOCX(ptr, type, n)  \
+    ((n) ? REALLOC(ptr, type, n) : (FREE(ptr), (type *) 0))
+
+# define BMTST(bm, num)  \
+    (((const byte *) (bm))[(num) >> 3]  &  (0x80 >> ((num) & 0x07)))
+# define BMSET(bm, num)  \
+          (((byte *) (bm))[(num) >> 3] |=  (0x80 >> ((num) & 0x07)))
+# define BMCLR(bm, num)  \
+          (((byte *) (bm))[(num) >> 3] &= ~(0x80 >> ((num) & 0x07)))
+
+# define STRINGIZE(x)		#x
+# define STR(x)			STRINGIZE(x)
+
+/* used by internal routines to specify the open modes */
+# define HFSP_MODE_RDONLY        0
+# define HFSP_MODE_RDWR          1
+# define HFSP_MODE_ANY           2
+
+/* Signatures registered with Apple to identify this driver */
+    /* Identifies the userland implementation */
+# define HPLS_SIGNATURE 0x482B4C58	// 'H+LX'
+    /* Identifies the kernel module by Brad Boyer (flar@pants.nu) */
+# define HPLS_SIGRES1	0x482B4C78	// 'H+Lx'
+    /* not jet in use ... */
+# define HPLS_SIGRES2	0x482B6C78	// 'H+lx'
+    /* Signature used by Apple */
+# define HPAPPLE_SIGNATURE  0x382e3130	// '8.10'
+
+/* Version used for this implementation of HFS+. This is not related
+ * to the VERSION file found at the top-level of this package,
+ * but designates the version of the low level code */
+#define HPLS_VERSION	1   /* must fit in a short */
+
+
+/* Othe Signatures may follow for informational purpos */
+
+/* prototype for key comparing functions. */
+typedef int (*hfsp_key_compare) (void* key1, void* key2);
+
+/* prototype for key reading (necessary for byte swapping) */
+typedef void* (*hfsp_key_read) (void* p, void* key);
+
+struct volume; /* foreward declaration for btree needed */
+
+/* Structures for a node cache. The cache is an array
+ * with linear search. (So making it to big may make
+ * things slower). It is searched in a round robin
+ * fashion.
+ */
+
+typedef struct
+{
+    UInt32		priority;
+	// as lower this number as higher the priority.
+	// decremetned on any sucessfull usage
+	// incremented else, intial value height*DEPTHFACTOR
+    UInt16		index;	// of node in fork
+	// 0 means empty, since first node is node header
+	// contents of node in original byte order
+    UInt16		flags;	// like DIRTY etc.
+} node_entry;
+
+typedef struct
+{
+    UInt32		index;	    // duplicate of above
+    btree_node_desc	desc;	    // header of node
+    char		node[0];    // actual node_size
+	// contents of node in original byte order
+} node_buf;
+
+typedef struct
+{
+    int		size;	     // number of nodes in the cache
+    int		currindex;   // round robin index
+    int		nodebufsize; // size of complete node_buf, including node
+    node_entry	*entries;
+    char	*buffers;   // actually *node_buf
+} node_cache;
+
+typedef struct
+{
+    struct volume*	vol;	/* pointer to volume this tree is part of */
+    hfsp_fork_raw*	fork;	/* pointer to fork this tree is part of */
+    UInt32		cnid;	/* (pseudo) file id for the fork */
+    hfsp_key_compare	kcomp;
+	/* function used for key compare in _this_ btree */
+    hfsp_key_read	kread;
+	/* fucntion used to read a key int _this_ btree */
+    btree_head		head;
+
+    UInt16		blkpernode;
+	 /* Number of volume blocks per node (usually 1-4) */
+    node_cache		cache;
+    /* Warning all functions of btrees and records may modify
+       the following values ! */
+    // UInt16		node_index; /* index of node in fork */
+    // btree_node_desc	node;	/* current node under examination */
+    // char*		buf;	/* buf with size of a node */
+} btree;
+
+/* Function on btrees are defined in btree.h */
+
+/* A Wrapper around the raw hfs+ volume header for additional information
+ * needed by this library.
+ */
+
+typedef struct volume
+{
+    int		os_fd;		/* OS dependend reference to device */
+    UInt16	blksize_bits;   /* blocksize of device = 1 << blksize_bits */
+    UInt16	filler;
+    UInt32	blksize;	/* always 1 << blksize_bits */
+    UInt32	startblock;
+	/* Offset from physical to logical blocks,
+	   eventually intodruced by HFS wrapper */
+    UInt32  	maxblocks;	/* maximum number of blocks in device */
+    // UInt32	currblock;	/* value of current block, to cache blocks */
+    hfsp_vh	vol;		/* raw volume data */
+    // void*	blockbuf;	/* (single) buffer for fetching one block */
+     /* Buffer has double size of blksize to allow cross block reading */
+
+    btree*	extents;	/* is NULL by default and intialized when needed */
+    btree	catalog;	/* This is always neeeded */
+} volume;
+
+/* Functions on volumes are defined in volume.h */
+
+typedef struct {    // may not be used as found here
+    btree*		tree;	// tree where this record is contained in.
+    UInt16		node_index; /* index of record in btree */
+    UInt16		keyind;	/* index of current key in btree */
+    hfsp_cat_key	key;	/* current key */
+    UInt32		child;	/* child node belonging to this key */
+} index_record;
+
+typedef struct {
+    btree*		tree;	// tree where this record is contained in.
+    UInt16		node_index; /* index of record in btree */
+    UInt16		keyind;	/* index of current key in btree */
+    hfsp_extent_key	key;	/* current key */
+    hfsp_extent_rec	extent; /* The payload carried around */
+} extent_record;
+
+typedef struct {
+    btree*		tree;	// tree where this record is contained in.
+    UInt16		node_index; /* index of record in btree */
+    UInt16		keyind;	/* index of current key in btree */
+    hfsp_cat_key	key;	/* current key */
+    hfsp_cat_entry	record;	/* current record */
+} record;
+
+/* Functions on records are defined in record.h */
diff --git a/roms/openbios/fs/hfsplus/include/record.h b/roms/openbios/fs/hfsplus/include/record.h
new file mode 100644
index 000000000..6454f552a
--- /dev/null
+++ b/roms/openbios/fs/hfsplus/include/record.h
@@ -0,0 +1,80 @@
+/*
+ * libhfs - library for reading and writing Macintosh HFS volumes.
+ *
+ * a record contains a key and a folder or file and is part
+ * of a btree.
+ *
+ * Copyright (C) 2000 Klaus Halfmann <khalfmann@libra.de>
+ * Original 1996-1998 Robert Leslie <rob@mars.org>
+ * Additional work by  Brad Boyer (flar@pants.nu)
+ *
+ * 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.
+ *
+ * $Id: record.h,v 1.10 2000/10/01 17:08:05 hasi Exp $
+ */
+
+/* Compare two cat_keys ... */
+extern int record_key_compare(void* k1, void* k2);
+
+/* Compare two extent_keys ... */
+extern int record_extent_key_compare(void* k1, void* k2);
+
+/* read a catalog key into a given buffer */
+extern void* record_readkey(void* p, void* buf);
+
+/* read an extent key into a given buffer */
+extern void* record_extent_readkey(void* p, void* buf);
+
+/* intialize the record to the first record of the tree
+ * which is (per design) the root node.
+ */
+extern int record_init_root(record* r, btree* tree);
+
+/* intialize the record to the folder given by cnid.
+ */
+extern int record_init_cnid(record* r, btree* tree, UInt32 cnid);
+
+/* intialize the record to the first record of the parent.
+ */
+extern int record_init_parent(record* r, record* parent);
+
+/* intialize the record by searching for the given string in the given folder.
+ *
+ * parent and r may be the same.
+ */
+extern int record_init_string_parent(record* r, record* parent, char* key);
+
+/* move record up in folder hierarchy (if possible) */
+extern int record_up(record* r);
+
+/* move record foreward to next entry.
+ *
+ * In case of an error the value of *r is undefined !
+ */
+extern int record_next(record* r);
+
+/* intialize the extent_record to the extent identified by
+ * a given file */
+extern int record_init_file(extent_record* r, btree* tree,
+		    UInt8 forktype, UInt32 fileId, UInt32 blockindex);
+
+/* move foreward to next entent record. */
+extern int record_next_extent(extent_record *r);
+
+#ifdef DEBUG
+    /* Dump all the record information to stdout */
+  extern void record_print(record* r);
+#endif
diff --git a/roms/openbios/fs/hfsplus/include/swab.h b/roms/openbios/fs/hfsplus/include/swab.h
new file mode 100644
index 000000000..c424008ee
--- /dev/null
+++ b/roms/openbios/fs/hfsplus/include/swab.h
@@ -0,0 +1,64 @@
+/*
+ * libhfs - library for reading and writing Macintosh HFS volumes
+ *
+ * Copyright (C) 2000 Klaus Halfmann <klaus.halfmann@feri.de>
+ * Original work 1996-1998 Robert Leslie <rob@mars.org>
+ *
+ * This file defines some byte swapping function. I did not find this
+ * in any standard or linux way.
+ *
+ * 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.
+ *
+ * $Id: swab.h,v 1.1.1.1 2002/03/05 19:50:29 klaus Exp $
+ */
+
+#include "config.h"
+#include "libc/byteorder.h"
+
+ /* basic fuction:
+    value = swab_inc(ptr);
+	ptr is afterwards incremented by sizeof(value)
+ */
+
+#ifndef CONFIG_BIG_ENDIAN
+
+#define bswabU16(val) __bswap16(val)
+
+#define bswabU16_inc(ptr) (__extension__ ({ UInt16 v=__bswap16(*((UInt16*) (ptr))); ptr+=sizeof(UInt16);v;}))
+#define bswabU32_inc(ptr) (__extension__ ({ UInt32 v=__bswap32(*((UInt32*) (ptr))); ptr+=sizeof(UInt32);v;}))
+#define bswabU64_inc(ptr) (__extension__ ({ UInt64 v=__bswap64(*((UInt64*) (ptr))); ptr+=sizeof(UInt64);v;}))
+
+#define bstoreU16_inc(ptr, val) do {(*((UInt16*) (ptr))) = __bswap16(val); ptr+=sizeof(UInt16);} while (0)
+#define bstoreU32_inc(ptr, val) do {(*((UInt32*) (ptr))) = __bswap32(val); ptr+=sizeof(UInt32);} while (0)
+#define bstoreU64_inc(ptr, val) do {(*((UInt64*) (ptr))) = __bswap64(val); ptr+=sizeof(UInt64);} while (0)
+
+#else // BYTE_ORDER == BIG_ENDIAN
+
+#define bswabU16(val) val
+
+#define bswabU16_inc(ptr) (__extension__ ({ UInt16 v=(*((UInt16*) (ptr))); ptr+=sizeof(UInt16);v;}))
+#define bswabU32_inc(ptr) (__extension__ ({ UInt32 v=(*((UInt32*) (ptr))); ptr+=sizeof(UInt32);v;}))
+#define bswabU64_inc(ptr) (__extension__ ({ UInt64 v=(*((UInt64*) (ptr))); ptr+=sizeof(UInt64);v;}))
+
+#define bstoreU16_inc(ptr, val) do {(*((UInt16*) (ptr))) = val; ptr+=sizeof(UInt16);} while (0)
+#define bstoreU32_inc(ptr, val) do {(*((UInt32*) (ptr))) = val; ptr+=sizeof(UInt32);} while (0)
+#define bstoreU64_inc(ptr, val) do {(*((UInt64*) (ptr))) = val; ptr+=sizeof(UInt64);} while (0)
+
+#endif
+
+/* for the sake of compleetness and readability */
+#define bswabU8_inc(ptr)	(__extension__ ({ UInt8 v=(*((UInt8*) (ptr))); ptr+=sizeof(UInt8);v;}))
+#define bstoreU8_inc(ptr,val)	do {(*((UInt8*) (ptr))) = val; ptr+=sizeof(UInt8);} while (0)
diff --git a/roms/openbios/fs/hfsplus/include/unicode.h b/roms/openbios/fs/hfsplus/include/unicode.h
new file mode 100644
index 000000000..e7c86f78a
--- /dev/null
+++ b/roms/openbios/fs/hfsplus/include/unicode.h
@@ -0,0 +1,28 @@
+/*
+ *  linux/fs/hfsplus/unicode.c
+ *
+ * Copyright (C) 1999-2000  Brad Boyer (flar@pants.nu)
+ * This file may be distributed under the terms of the GNU Public License.
+ *
+ * The routines found here convert hfs-unicode string into ascii Strings
+ * and vice versa.  And the correct comparison between Strings.
+ */
+
+/* convert the asci string astr into a unicode string given by ustr.
+ *
+ * returns actual length of convertet string.
+ */
+
+int unicode_asc2uni(hfsp_unistr255 *ustr, const char *astr);
+
+/* Convert an unicode string ustr to a ascii string astr of given maximum len
+ *
+ * returns actual length of convertet string.
+ */
+
+int unicode_uni2asc(char *astr, const hfsp_unistr255 *ustr, int maxlen);
+
+/* similar to strcmp for unicode, pascal strings */
+
+SInt32 fast_unicode_compare (const hfsp_unistr255 *ustr1,
+			     const hfsp_unistr255 *ustr2);
diff --git a/roms/openbios/fs/hfsplus/include/volume.h b/roms/openbios/fs/hfsplus/include/volume.h
new file mode 100644
index 000000000..19be05500
--- /dev/null
+++ b/roms/openbios/fs/hfsplus/include/volume.h
@@ -0,0 +1,87 @@
+/*
+ * libhfs - library for reading and writing Macintosh HFS volumes
+ * Copyright (C) 2000 Klaus Halfmann <khalfmann@libra.de>^
+ * Original 1996-1998 Robert Leslie <rob@mars.org>
+ *
+ * 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.
+ *
+ * $Id: volume.h,v 1.11 2000/10/17 05:58:46 hasi Exp $
+ */
+
+#ifndef _H_VOLUME
+#define _H_VOLUME
+
+/* Open the device, read and verify the volume header
+   (and its backup) */
+extern int volume_open(volume* vol, int os_fd);
+
+/* Write back all data eventually cached and close the device. */
+extern int volume_close(volume* vol);
+
+/* read multiple blocks into given memory.
+ *
+ * returns given pointer or NULL on failure.
+ */
+extern void* volume_readfromfork(volume* vol, void* buf,
+	hfsp_fork_raw* f, UInt32 block,
+	UInt32 count, UInt8 forktype, UInt32 fileId);
+
+/* Fill a given buffer with the given block in volume.
+ */
+int volume_readinbuf(volume * vol,void* buf, long block);
+
+/* invalidat cache hold in volume, will be removed when
+ * caching strategy is clear to me. */
+/*
+extern inline void volume_invalidate_cache(volume* vol)
+{
+    vol -> currblock = (UInt32) -1;
+}
+*/
+
+/* Check in Allocation file if given block is allocated. */
+extern int volume_allocated(volume* v, UInt32 block);
+
+/* Read a raw hfsp_extent_rec from memory. */
+extern void* volume_readextent(void *p, hfsp_extent_rec er);
+
+/* Read fork information from raw memory */
+extern void* volume_readfork(void *p, hfsp_fork_raw* f);
+
+/* internal function used to create the extents btree,
+   is called by following inline fucntion when needed */
+extern void volume_create_extents_tree(volume* vol);
+
+/* accessor for entends btree, is created on demand */
+static inline btree* volume_get_extents_tree(volume* vol) {
+    if (!vol->extents)
+	volume_create_extents_tree(vol);
+    return vol->extents;
+}
+
+/* Determine whether the volume is a HFS-plus volume */
+int volume_probe(int fd, long long offset);
+
+#ifdef DEBUG
+    /* Print raw fork information to stdout */
+  void volume_print_fork(hfsp_fork_raw* f);
+    /* Dump all the volume information to stdout */
+  void volume_print(hfsp_vh* vol);
+#endif
+
+
+
+#endif   /* _H_VOLUME */
diff --git a/roms/openbios/fs/hfsplus/libhfsp.c b/roms/openbios/fs/hfsplus/libhfsp.c
new file mode 100644
index 000000000..af1cde6a9
--- /dev/null
+++ b/roms/openbios/fs/hfsplus/libhfsp.c
@@ -0,0 +1,29 @@
+/*
+ * libhfsp - library for reading and writing Macintosh HFS volumes
+ * Copyright (C) 1996-1998 Robert Leslie
+ *
+ * Thi file contains utitlity fucntions to manage the features of
+ * the hfs+ library.
+ *
+ * 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.
+ *
+ * $Id: libhfsp.c,v 1.1.1.1 2000/07/25 10:33:40 kkaempf Exp $
+ */
+
+#include "config.h"
+#include "libhfsp.h"
+
+const char *hfsp_error = "no error";       /* static error string */
-- 
cgit