/*
 * atari.c
 * Detection of ATARI ST partition map
 *
 * Copyright (c) 2003 Christoph Pfisterer
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use, copy,
 * modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE. 
 */

#include "global.h"

/*
 * ATARI ST partition map
 */

static char * get_name_for_type(char *type)
{
  if (memcmp(type, "GEM", 3) == 0)
    return "Standard GEMDOS";
  else if (memcmp(type, "BGM", 3) == 0)
    return "Big GEMDOS";
  else if (memcmp(type, "XGM", 3) == 0)
    return "Extended";
  return "Unknown";
}

static void detect_atari_partmap_ext(SECTION *section, u8 extbase, int level);

void detect_atari_partmap(SECTION *section, int level)
{
  unsigned char *buf;
  int i, off, used, flag, flags[4];
  u4 start, size, starts[4], sizes[4];
  char types[4][4], *type;
  u2 atari_csum;
  char s[256], append[64];

  /* partition maps only occur at the start of a device */
  if (section->pos != 0)
    return;

  if (get_buffer(section, 0, 512, (void **)&buf) < 512)
    return;

  /* check checksum */
  atari_csum = 0;
  for (i = 0; i < 512; i += 2)
    atari_csum += get_be_short(buf + i);
  if (atari_csum != 0x1234)
    return;

  /* get data and check if it's actually used */
  used = 0;
  for (off = 0x1c6, i = 0; i < 4; i++, off += 12) {
    flags[i] = buf[off];
    get_string(buf + off + 1, 3, types[i]);
    starts[i] = get_be_long(buf + off + 4);
    sizes[i] = get_be_long(buf + off + 8);
    if ((flags[i] & 1) && starts[i] != 0 && sizes[i] != 0)
      used = 1;
  }
  if (!used)
    return;

  /* print data and handle each partition */
  print_line(level, "ATARI ST partition map");
  for (i = 0; i < 4; i++) {
    start = starts[i];
    size = sizes[i];
    flag = flags[i];
    type = types[i];
    if ((flag & 1) == 0)
      continue;

    sprintf(append, " from %lu", start);
    if (flag & 0x80)
      strcat(append, ", bootable");
    format_blocky_size(s, size, 512, "sectors", append);
    print_line(level, "Partition %d: %s",
	       i+1, s);

    print_line(level + 1, "Type \"%s\" (%s)", type,
	       get_name_for_type(type));

    if (memcmp(type, "XGM", 3) == 0) {
      /* extended partition */
      detect_atari_partmap_ext(section, start, level + 1);
    } else {
      /* recurse for content detection */
      analyze_recursive(section, level + 1,
			(u8)start * 512, (u8)size * 512, 0);
    }
  }
}

static void detect_atari_partmap_ext(SECTION *section, u8 extbase, int level)
{
  unsigned char *buf;
  int extpartnum = 5;
  u8 tablebase, nexttablebase;
  int i, off, flags[4];
  u4 start, size, starts[4], sizes[4];
  char types[4][4], *type;
  char s[256], append[64];

  for (tablebase = extbase; tablebase; tablebase = nexttablebase) {
    /* read sector from linked list */
    if (get_buffer(section, tablebase << 9, 512, (void **)&buf) < 512)
      return;

    /* get data */
    for (off = 0x1c6, i = 0; i < 4; i++, off += 12) {
      flags[i] = buf[off];
      get_string(buf + off + 1, 3, types[i]);
      starts[i] = get_be_long(buf + off + 4);
      sizes[i] = get_be_long(buf + off + 8);
    }

    /* print data and handle each partition */
    nexttablebase = 0;
    for (i = 0; i < 4; i++) {
      start = starts[i];
      size = sizes[i];
      type = types[i];
      if ((flags[i] & 1) == 0)
	continue;

      if (memcmp(type, "XGM", 3) == 0) {
	/* link to next table */

	nexttablebase = extbase + start;

      } else {
	/* real partition */

	sprintf(append, " from %lu", start);
	format_blocky_size(s, size, 512, "sectors", append);
	print_line(level, "Partition %d: %s",
		   extpartnum, s);
	extpartnum++;

	print_line(level + 1, "Type \"%s\" (%s)", type,
		   get_name_for_type(type));

	/* recurse for content detection */
	analyze_recursive(section, level + 1,
			  (tablebase + start) * 512, (u8)size * 512, 0);
      }
    }
  }
}

/* EOF */


syntax highlighted by Code2HTML, v. 0.9.1