Logo Search packages:      
Sourcecode: cbmconvert version File versions  Download package

enum RdStatus ReadCpmImage ( FILE *  file,
const char *  filename,
write_file_t  writeCallback,
log_t  log 
)

Read and convert a disk image in C128 CP/M format

Parameters:
file the file input stream
filename host system name of the file
writeCallback function for writing the contained files
log Call-back function for diagnostic output
Returns:
status of the operation

Definition at line 2079 of file image.c.

References CpmDirEnt::area, CpmDirEnt::block, CpmDirEnt::blocks, Image::buf, CPMBLOCK, CpmConvertName(), CpmTransTable(), Image::dirtrack, elementsof, Errors, CpmDirEnt::extent, Image::name, RdFail, RdNoSpace, RdOK, Image::type, Warnings, WrFail, WrNoSpace, and WrOK.

{
  struct Image image;
  byte_t** trans;
  unsigned au; /* allocation unit size */
  unsigned sectors; /* number of disk sectors */

  /* determine disk image type from its length */
  {
    const struct DiskGeometry* geom = 0;
    size_t length, blocks;
    unsigned i;

    if (fseek (file, 0, SEEK_END)) {
    seekError:
      (*log) (Errors, 0, "fseek: %s", strerror(errno));
      return RdFail;
    }

    length = ftell (file);

    if (fseek (file, 0, SEEK_SET))
      goto seekError;

    if (length % 256) {
    unknownImage:
      (*log) (Errors, 0, "Unknown CP/M disk image type");
      return RdFail;
    }

    for (i = 0, blocks = length / 256; i < elementsof(diskGeometry); i++)
      if (diskGeometry[i].blocks == blocks) {
      geom = &diskGeometry[i];
      break;
      }

    if (!geom)
      goto unknownImage;

    /* Initialize the disk image structure. */

    if (!(image.buf = malloc (length))) {
      (*log) (Errors, 0, "Out of memory");
      return RdFail;
    }

    image.type = geom->type;
    image.dirtrack = geom->dirtrack;
    image.name = 0;

    if (1 != fread (image.buf, length, 1, file)) {
      (*log) (Errors, 0, "fread: %s", strerror(errno));
      free (image.buf);
      return RdFail;
    }

    /* Get the CP/M sector translations. */

    if (!(trans = CpmTransTable (&image, &au, &sectors))) {
      free (image.buf);
      goto unknownImage;
    }
  }

  /* Traverse through the directory and extract the files */
  {
    struct CpmDirEnt* directory;
    unsigned d;
    struct Filename name;

    for (d = 0; d < au * 8; d++) {
      unsigned i, j, length;

      directory = ((struct CpmDirEnt*) trans[d / 8]) + (d % 8);

      if (directory->area == 0xE5) continue; /* unused entry */

      CpmConvertName (directory, &name);

      if (directory->extent) {
      (*log) (Warnings, &name,
            "starting with non-zero extent 0x%02x, file ignored",
            directory->extent);
      continue;
      }

      /* search for following extents */
      for (i = d, j = length = 0; i < au * 8; i++) {
      struct CpmDirEnt* dir = ((struct CpmDirEnt*) trans[i / 8]) + (i % 8);

      if (memcmp (dir, directory, 12) ||
          dir->extent != j || dir->blocks > 128)
        break;

      j++;
      length += dir->blocks;

      if (dir->blocks < 128)
        break;
      }

      /* j holds the number of directory extents */

      if (!j) {
      (*log) (Warnings, &name, "error in directory entry, file skipped");
      continue;
      }

      if (directory->area)
      (*log) (Warnings, &name, "user area code 0x%02x ignored",
            directory->area);

      length *= 128;

      /* Read the file */
      {
      byte_t* curr, *buf = malloc (length);

      if (!buf) {
        (*log) (Warnings, &name, "out of memory");
        d += j - 1;
        continue;
      }

      for (curr = buf, j += d; d < j; d++) {
        directory = ((struct CpmDirEnt*) trans[d / 8]) + (d % 8);

        for (i = 0; i < directory->blocks; i++) {
          unsigned sect = (au / 2) * CPMBLOCK (directory->block, i / au) +
            ((i / 2) % (au / 2));

          if (sect >= sectors) {
            (*log) (Errors, &name,
                  "Illegal block address in block %u of extent 0x%02x",
                  i, directory->extent);
            free (buf);
            goto FileDone;
          }

          memcpy (curr, trans[sect] + 128 * (i % 2), 128);
          curr += 128;
        }
      }

      /* Remove trailing EOF characters (only when they are at end of the
         last block). */
      while (buf[length - 1] == 0x1A) length--;

      switch ((*writeCallback) (&name, buf, length)) {
      case WrOK:
        break;
      case WrNoSpace:
        free (buf);
        free (image.buf);
        free (trans);
        return RdNoSpace;
      case WrFail:
      default:
        free (buf);
        free (image.buf);
        free (trans);
        return RdFail;
      }

      free (buf);
      }

    FileDone:
      d--;
    }
  }

  free (image.buf);
  free (trans);

  return RdOK;
}


Generated by  Doxygen 1.6.0   Back to index