]> git.sur5r.net Git - cc65/commitdiff
Added inital version of a CONVERT tool for Apple GEOS. It converts the output of...
authorol.sc <ol.sc@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Sat, 21 Jan 2012 13:31:00 +0000 (13:31 +0000)
committerol.sc <ol.sc@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Sat, 21 Jan 2012 13:31:00 +0000 (13:31 +0000)
- VLIR support
- support to "unCONVERT"
- nicer UI

git-svn-id: svn://svn.cc65.org/cc65/trunk@5418 b7a2c559-68d2-44c3-8de9-860c34a00d81

targetutil/geos-apple/convert.c [new file with mode: 0644]

diff --git a/targetutil/geos-apple/convert.c b/targetutil/geos-apple/convert.c
new file mode 100644 (file)
index 0000000..cafccca
--- /dev/null
@@ -0,0 +1,220 @@
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <dirent.h>
+#include <dio.h>
+
+dhandle_t dhandle;
+
+struct dir_entry_t {
+    struct {
+        unsigned name_length  :4;
+        unsigned storage_type :4;
+    }             storage_length;
+    char          file_name[15];
+    unsigned char file_type;
+    unsigned      key_pointer;
+    unsigned      blocks_used;
+    unsigned char size[3];
+    unsigned long creation;
+    unsigned char version;
+    unsigned char min_version;
+    unsigned char access;
+    unsigned      aux_type;
+    unsigned long last_mod;
+    unsigned      header_pointer;
+}* dir_entry;
+
+union {
+    unsigned char bytes[512];
+    struct {
+        unsigned      prev_block;
+        unsigned      next_block;
+        unsigned char entries[1];
+    } content;
+} dir_block;
+
+union {
+    unsigned char bytes[512];
+    struct {
+        unsigned char addr_lo[254];
+        unsigned char size_lo[2];
+        unsigned char addr_hi[254];
+        unsigned char size_hi[2];
+    } content;
+} index_block;
+
+union {
+    unsigned char bytes[512];
+    struct {
+        unsigned char      info_block[256];
+        unsigned char      vlir_records[128];
+        struct dir_entry_t dir_entry;
+    } content;
+} header_block;
+
+
+static void err_exit(char *operation)
+{
+    fprintf(stderr, "%s - err:%02x - %s",
+            operation, (int)_oserror, _stroserror(_oserror));
+    getchar();
+    exit(EXIT_FAILURE);
+}
+
+
+static unsigned get_dir_entry(char* p_name)
+{
+    char*          d_name;
+    char*          f_name;
+    size_t         f_namelen;
+    DIR*           dir;
+    struct dirent* dirent;
+    unsigned       cur_addr;
+    unsigned char  entry_length;
+    unsigned char  entries_per_block;
+    unsigned char  cur_entry;
+
+    /* Split path name into directory name and file name */
+    f_name = strrchr(p_name, '/');
+    if (f_name) {
+        d_name = p_name;
+        *f_name++ = '\0';
+    } else {
+        d_name = ".";
+        f_name = p_name;
+    }
+    f_namelen = strlen(f_name);
+
+    /* Start with high level functions to get handling
+       of relative path and current drive for free */
+    dir = opendir(d_name);
+    if (!dir) {
+        err_exit("opendir");
+    }
+    dirent = readdir(dir);
+    if (!dirent) {
+        err_exit("readdir");
+    }
+
+    /* Field header_pointer directly follows field last_mod */
+    cur_addr = *(unsigned*)(&dirent->d_mtime.hour + 1);
+
+    /* DEV_NUM is set to the drive accessed above */
+    dhandle = dio_open(*(driveid_t*)0xBF30);
+    if (!dhandle) {
+        err_exit("dio_open");
+    }
+
+    if (dio_read(dhandle, cur_addr, &dir_block)) {
+        err_exit("dio_read.1");
+    }
+
+    /* Get directory entry infos from directory header */
+    entry_length      = dir_block.bytes[0x23];
+    entries_per_block = dir_block.bytes[0x24];
+
+    /* Skip directory header entry */
+    cur_entry = 1;
+
+    do {
+
+        /* Search for next active directory entry */
+        do {
+
+            /* Check if next directory block is necessary */
+            if (cur_entry == entries_per_block) {
+
+                /* Check if another directory block is present */
+                cur_addr = dir_block.content.next_block;
+                if (!cur_addr) {
+                    _mappederrno(0x46);
+                    err_exit("dio_read.2");
+                }
+
+                /* Read next directory block */
+                if (dio_read(dhandle, cur_addr, &dir_block)) {
+                    err_exit("dio_read.3");
+                }
+
+                /* Start with first entry in next block */
+                cur_entry = 0;
+            }
+
+            /* Compute pointer to current entry */
+            dir_entry = (struct dir_entry_t*)(dir_block.content.entries +
+                                              cur_entry * entry_length);
+
+            /* Switch to next entry */
+            ++cur_entry;
+        } while (!dir_entry->storage_length.storage_type);
+
+    } while (dir_entry->storage_length.name_length != f_namelen ||
+             strncasecmp(dir_entry->file_name, f_name, f_namelen));
+
+    return cur_addr;
+}
+
+
+int main(int argc, char* argv[])
+{
+    char     input[80];
+    char*    p_name;
+    unsigned dir_addr;
+    unsigned header_addr;
+
+    if (argc > 1) {
+        p_name = argv[1];
+    } else {
+        printf("Apple GEOS Convert\nPathname:");
+        p_name = gets(input);
+    }
+
+    dir_addr = get_dir_entry(p_name);
+
+    if (dio_read(dhandle, dir_entry->key_pointer, &index_block)) {
+        err_exit("dio_read.4");
+    }
+
+    header_addr = index_block.content.addr_lo[0] |
+                  index_block.content.addr_hi[0] << 8;
+
+    if (dio_read(dhandle, header_addr, &header_block)) {
+        err_exit("dio_read.5");
+    }
+
+    dir_entry->storage_length  = header_block.content.dir_entry.storage_length;
+    memcpy(dir_entry->file_name, header_block.content.dir_entry.file_name, 15);
+    dir_entry->file_type       = header_block.content.dir_entry.file_type;
+    memcpy(dir_entry->size,      header_block.content.dir_entry.size, 3);
+    dir_entry->creation        = header_block.content.dir_entry.creation;
+    dir_entry->version         = header_block.content.dir_entry.version;
+    dir_entry->min_version     = header_block.content.dir_entry.min_version;
+    dir_entry->aux_type        = header_addr;
+    dir_entry->last_mod        = header_block.content.dir_entry.last_mod;
+
+    memmove(&index_block.content.addr_lo[0],
+            &index_block.content.addr_lo[1], sizeof(index_block.content.addr_lo) - 1);
+    memmove(&index_block.content.addr_hi[0],
+            &index_block.content.addr_hi[1], sizeof(index_block.content.addr_hi) - 1);
+
+    index_block.content.size_lo[1] = dir_entry->size[0];
+    index_block.content.size_hi[1] = dir_entry->size[1];
+    index_block.content.size_lo[0] = dir_entry->size[2];
+    index_block.content.size_hi[0] = 0;
+
+    if (dio_write(dhandle, dir_addr, &dir_block)) {
+        err_exit("dio_write.1");
+    }
+
+    if (dio_write(dhandle, dir_entry->key_pointer, &index_block)) {
+        err_exit("dio_write.2");
+    }
+
+    if (dio_close(dhandle)) {
+        err_exit("dio_close");
+    }
+
+    return EXIT_SUCCESS;
+}
\ No newline at end of file