From e44e3482bdb4d0ebde2d8b41830ac2cdb07948fb Mon Sep 17 00:00:00 2001 From: Yang Zhang Date: Fri, 28 Aug 2015 09:58:54 +0800 Subject: Add qemu 2.4.0 Change-Id: Ic99cbad4b61f8b127b7dc74d04576c0bcbaaf4f5 Signed-off-by: Yang Zhang --- qemu/roms/openbios/fs/hfsplus/build.xml | 11 + qemu/roms/openbios/fs/hfsplus/hfsp_blockiter.c | 141 ++++ qemu/roms/openbios/fs/hfsplus/hfsp_btree.c | 372 +++++++++++ qemu/roms/openbios/fs/hfsplus/hfsp_fs.c | 632 ++++++++++++++++++ qemu/roms/openbios/fs/hfsplus/hfsp_record.c | 759 ++++++++++++++++++++++ qemu/roms/openbios/fs/hfsplus/hfsp_unicode.c | 511 +++++++++++++++ qemu/roms/openbios/fs/hfsplus/hfsp_volume.c | 323 +++++++++ qemu/roms/openbios/fs/hfsplus/include/apple.h | 111 ++++ qemu/roms/openbios/fs/hfsplus/include/blockiter.h | 59 ++ qemu/roms/openbios/fs/hfsplus/include/btree.h | 50 ++ qemu/roms/openbios/fs/hfsplus/include/hfs.h | 32 + qemu/roms/openbios/fs/hfsplus/include/hfsp.h | 305 +++++++++ qemu/roms/openbios/fs/hfsplus/include/hfstime.h | 34 + qemu/roms/openbios/fs/hfsplus/include/libhfsp.h | 201 ++++++ qemu/roms/openbios/fs/hfsplus/include/record.h | 80 +++ qemu/roms/openbios/fs/hfsplus/include/swab.h | 64 ++ qemu/roms/openbios/fs/hfsplus/include/unicode.h | 28 + qemu/roms/openbios/fs/hfsplus/include/volume.h | 87 +++ qemu/roms/openbios/fs/hfsplus/libhfsp.c | 29 + 19 files changed, 3829 insertions(+) create mode 100644 qemu/roms/openbios/fs/hfsplus/build.xml create mode 100644 qemu/roms/openbios/fs/hfsplus/hfsp_blockiter.c create mode 100644 qemu/roms/openbios/fs/hfsplus/hfsp_btree.c create mode 100644 qemu/roms/openbios/fs/hfsplus/hfsp_fs.c create mode 100644 qemu/roms/openbios/fs/hfsplus/hfsp_record.c create mode 100644 qemu/roms/openbios/fs/hfsplus/hfsp_unicode.c create mode 100644 qemu/roms/openbios/fs/hfsplus/hfsp_volume.c create mode 100644 qemu/roms/openbios/fs/hfsplus/include/apple.h create mode 100644 qemu/roms/openbios/fs/hfsplus/include/blockiter.h create mode 100644 qemu/roms/openbios/fs/hfsplus/include/btree.h create mode 100644 qemu/roms/openbios/fs/hfsplus/include/hfs.h create mode 100644 qemu/roms/openbios/fs/hfsplus/include/hfsp.h create mode 100644 qemu/roms/openbios/fs/hfsplus/include/hfstime.h create mode 100644 qemu/roms/openbios/fs/hfsplus/include/libhfsp.h create mode 100644 qemu/roms/openbios/fs/hfsplus/include/record.h create mode 100644 qemu/roms/openbios/fs/hfsplus/include/swab.h create mode 100644 qemu/roms/openbios/fs/hfsplus/include/unicode.h create mode 100644 qemu/roms/openbios/fs/hfsplus/include/volume.h create mode 100644 qemu/roms/openbios/fs/hfsplus/libhfsp.c (limited to 'qemu/roms/openbios/fs/hfsplus') diff --git a/qemu/roms/openbios/fs/hfsplus/build.xml b/qemu/roms/openbios/fs/hfsplus/build.xml new file mode 100644 index 000000000..5f4c28869 --- /dev/null +++ b/qemu/roms/openbios/fs/hfsplus/build.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/qemu/roms/openbios/fs/hfsplus/hfsp_blockiter.c b/qemu/roms/openbios/fs/hfsplus/hfsp_blockiter.c new file mode 100644 index 000000000..e91009229 --- /dev/null +++ b/qemu/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 + * Original work by 1996-1998 Robert Leslie + * 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/qemu/roms/openbios/fs/hfsplus/hfsp_btree.c b/qemu/roms/openbios/fs/hfsplus/hfsp_btree.c new file mode 100644 index 000000000..24eca924c --- /dev/null +++ b/qemu/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 + * Original 1996-1998 Robert Leslie + * 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/qemu/roms/openbios/fs/hfsplus/hfsp_fs.c b/qemu/roms/openbios/fs/hfsplus/hfsp_fs.c new file mode 100644 index 000000000..df234bb04 --- /dev/null +++ b/qemu/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/qemu/roms/openbios/fs/hfsplus/hfsp_record.c b/qemu/roms/openbios/fs/hfsplus/hfsp_record.c new file mode 100644 index 000000000..d4e7af1bf --- /dev/null +++ b/qemu/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 + * Original 1996-1998 Robert Leslie + * 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/qemu/roms/openbios/fs/hfsplus/hfsp_unicode.c b/qemu/roms/openbios/fs/hfsplus/hfsp_unicode.c new file mode 100644 index 000000000..7a34affa1 --- /dev/null +++ b/qemu/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/qemu/roms/openbios/fs/hfsplus/hfsp_volume.c b/qemu/roms/openbios/fs/hfsplus/hfsp_volume.c new file mode 100644 index 000000000..2d624e23e --- /dev/null +++ b/qemu/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 + * Original work by 1996-1998 Robert Leslie + * 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/qemu/roms/openbios/fs/hfsplus/include/apple.h b/qemu/roms/openbios/fs/hfsplus/include/apple.h new file mode 100644 index 000000000..7ba836db6 --- /dev/null +++ b/qemu/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 + * Original code 1996-1998 by Robert Leslie + * 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/qemu/roms/openbios/fs/hfsplus/include/blockiter.h b/qemu/roms/openbios/fs/hfsplus/include/blockiter.h new file mode 100644 index 000000000..da3e480fd --- /dev/null +++ b/qemu/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 + * Original work by 1996-1998 Robert Leslie + * 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/qemu/roms/openbios/fs/hfsplus/include/btree.h b/qemu/roms/openbios/fs/hfsplus/include/btree.h new file mode 100644 index 000000000..46ac8501f --- /dev/null +++ b/qemu/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 + * Original 1996-1998 Robert Leslie + * 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/qemu/roms/openbios/fs/hfsplus/include/hfs.h b/qemu/roms/openbios/fs/hfsplus/include/hfs.h new file mode 100644 index 000000000..5b0cbb490 --- /dev/null +++ b/qemu/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 + * Original code 1996-1998 by Robert Leslie + * 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/qemu/roms/openbios/fs/hfsplus/include/hfsp.h b/qemu/roms/openbios/fs/hfsplus/include/hfsp.h new file mode 100644 index 000000000..e916473c6 --- /dev/null +++ b/qemu/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 + * Original code 1996-1998 by Robert Leslie + * 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/qemu/roms/openbios/fs/hfsplus/include/hfstime.h b/qemu/roms/openbios/fs/hfsplus/include/hfstime.h new file mode 100644 index 000000000..bb6bd4a6e --- /dev/null +++ b/qemu/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 ^ + * Original 1996-1998 Robert Leslie + * 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/qemu/roms/openbios/fs/hfsplus/include/libhfsp.h b/qemu/roms/openbios/fs/hfsplus/include/libhfsp.h new file mode 100644 index 000000000..912cfbd05 --- /dev/null +++ b/qemu/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/qemu/roms/openbios/fs/hfsplus/include/record.h b/qemu/roms/openbios/fs/hfsplus/include/record.h new file mode 100644 index 000000000..6454f552a --- /dev/null +++ b/qemu/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 + * Original 1996-1998 Robert Leslie + * 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/qemu/roms/openbios/fs/hfsplus/include/swab.h b/qemu/roms/openbios/fs/hfsplus/include/swab.h new file mode 100644 index 000000000..c424008ee --- /dev/null +++ b/qemu/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 + * Original work 1996-1998 Robert Leslie + * + * 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/qemu/roms/openbios/fs/hfsplus/include/unicode.h b/qemu/roms/openbios/fs/hfsplus/include/unicode.h new file mode 100644 index 000000000..e7c86f78a --- /dev/null +++ b/qemu/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/qemu/roms/openbios/fs/hfsplus/include/volume.h b/qemu/roms/openbios/fs/hfsplus/include/volume.h new file mode 100644 index 000000000..19be05500 --- /dev/null +++ b/qemu/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 ^ + * Original 1996-1998 Robert Leslie + * + * 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/qemu/roms/openbios/fs/hfsplus/libhfsp.c b/qemu/roms/openbios/fs/hfsplus/libhfsp.c new file mode 100644 index 000000000..af1cde6a9 --- /dev/null +++ b/qemu/roms/openbios/fs/hfsplus/libhfsp.c @@ -0,0 +1,29 @@ +/* + * libhfsp - library for reading and writing Macintosh HFS volumes + * Copyright (C) 1996-1998 Robert Leslie + * + * Thi file contains utitlity fucntions to manage the features of + * the hfs+ library. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * $Id: libhfsp.c,v 1.1.1.1 2000/07/25 10:33:40 kkaempf Exp $ + */ + +#include "config.h" +#include "libhfsp.h" + +const char *hfsp_error = "no error"; /* static error string */ -- cgit 1.2.3-korg