diff options
Diffstat (limited to 'roms/openbios/fs/hfsplus')
| -rw-r--r-- | roms/openbios/fs/hfsplus/build.xml | 11 | ||||
| -rw-r--r-- | roms/openbios/fs/hfsplus/hfsp_blockiter.c | 141 | ||||
| -rw-r--r-- | roms/openbios/fs/hfsplus/hfsp_btree.c | 372 | ||||
| -rw-r--r-- | roms/openbios/fs/hfsplus/hfsp_fs.c | 632 | ||||
| -rw-r--r-- | roms/openbios/fs/hfsplus/hfsp_record.c | 759 | ||||
| -rw-r--r-- | roms/openbios/fs/hfsplus/hfsp_unicode.c | 511 | ||||
| -rw-r--r-- | roms/openbios/fs/hfsplus/hfsp_volume.c | 323 | ||||
| -rw-r--r-- | roms/openbios/fs/hfsplus/include/apple.h | 111 | ||||
| -rw-r--r-- | roms/openbios/fs/hfsplus/include/blockiter.h | 59 | ||||
| -rw-r--r-- | roms/openbios/fs/hfsplus/include/btree.h | 50 | ||||
| -rw-r--r-- | roms/openbios/fs/hfsplus/include/hfs.h | 32 | ||||
| -rw-r--r-- | roms/openbios/fs/hfsplus/include/hfsp.h | 305 | ||||
| -rw-r--r-- | roms/openbios/fs/hfsplus/include/hfstime.h | 34 | ||||
| -rw-r--r-- | roms/openbios/fs/hfsplus/include/libhfsp.h | 201 | ||||
| -rw-r--r-- | roms/openbios/fs/hfsplus/include/record.h | 80 | ||||
| -rw-r--r-- | roms/openbios/fs/hfsplus/include/swab.h | 64 | ||||
| -rw-r--r-- | roms/openbios/fs/hfsplus/include/unicode.h | 28 | ||||
| -rw-r--r-- | roms/openbios/fs/hfsplus/include/volume.h | 87 | ||||
| -rw-r--r-- | roms/openbios/fs/hfsplus/libhfsp.c | 29 | 
19 files changed, 3829 insertions, 0 deletions
| diff --git a/roms/openbios/fs/hfsplus/build.xml b/roms/openbios/fs/hfsplus/build.xml new file mode 100644 index 00000000..5f4c2886 --- /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 00000000..e9100922 --- /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 00000000..24eca924 --- /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 00000000..df234bb0 --- /dev/null +++ b/roms/openbios/fs/hfsplus/hfsp_fs.c @@ -0,0 +1,632 @@ +/* + *   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( p[0] == p[5] && p[3] ) +			cnid = p[3]; +		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 00000000..d4e7af1b --- /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 00000000..7a34affa --- /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 00000000..2d624e23 --- /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 00000000..7ba836db --- /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 00000000..da3e480f --- /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 00000000..46ac8501 --- /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 00000000..5b0cbb49 --- /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 00000000..e916473c --- /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 00000000..bb6bd4a6 --- /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 00000000..912cfbd0 --- /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 00000000..6454f552 --- /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 00000000..c424008e --- /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 00000000..e7c86f78 --- /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 00000000..19be0550 --- /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 00000000..af1cde6a --- /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 */ | 
