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

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

Read and convert a tape archive of the C64S emulator

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 93 of file t64.c.

References DEL, Errors, Everything, t64header::headerblock, t64header::majorVersion, t64header::maxEntriesHigh, t64header::maxEntriesLow, t64header::minorVersion, entry::name, Filename::name, t64header::numEntriesHigh, t64header::numEntriesLow, PRG, RdFail, RdNoSpace, RdOK, Filename::recordLength, Filename::type, USR, Warnings, WrFail, WrNoSpace, and WrOK.

{
  unsigned numEntries, entry;

  /* Check the header. */

  {
    struct t64header t64header;
    unsigned maxEntries;

    static const char T64Header1[] = "C64 tape image file";
    static const char T64Header2[] = "C64S tape file";
    static const char T64Header3[] = "C64S tape image file";

    if (1 != fread (&t64header, sizeof t64header, 1, file)) {
    freadFail:
      (*log) (Errors, 0, "fread: %s", strerror (errno));
      return RdFail;
    }

    if (memcmp (t64header.headerblock, T64Header1, sizeof T64Header1 - 1) &&
      memcmp (t64header.headerblock, T64Header2, sizeof T64Header2 - 1) &&
      memcmp (t64header.headerblock, T64Header3, sizeof T64Header3 - 1)) {
      (*log) (Errors, 0, "Unknown T64 header");
      return RdFail;
    }

    if (t64header.majorVersion != 1 || t64header.minorVersion != 0)
      (*log) (Errors, 0, "Unknown T64 version, trying anyway");

    maxEntries = ((unsigned) t64header.maxEntriesLow |
              (t64header.maxEntriesHigh << 8));
    numEntries = ((unsigned) t64header.numEntriesLow |
              (t64header.numEntriesHigh << 8));

    if (!numEntries) {
      (*log) (Warnings, 0,
            "Number of entries set to zero; trying to read the first entry");
      numEntries = 1;
    }
    else if (numEntries > maxEntries) {
      (*log) (Errors, 0, "Error in the number of entries");
      return RdFail;
    }

    (*log) (Everything, 0, "T64 version %u.%u, %u/%u files",
          t64header.majorVersion, t64header.minorVersion,
          numEntries, maxEntries);
  }

  /* Process the files */

  for (entry = 0; entry < numEntries; entry++) {
    struct t64entry t64entry;
    struct Filename name;
    long fileoffset;
    size_t length;

    name.type = PRG;
    name.recordLength = 0;

    if (fseek (file,
             sizeof (struct t64header) + entry * sizeof t64entry,
             SEEK_SET)) {
      (*log) (Errors, 0, "fseek: %s", strerror (errno));
      return RdFail;
    }

    if (1 != fread (&t64entry, sizeof t64entry, 1, file))
      goto freadFail;

    /* Convert the header. */
    memcpy (name.name, t64entry.name, 16);
    {
      int i;
      /* Convert trailing spaces to shifted spaces. */
      for (i = 16; --i && name.name[i] == ' '; name.name[i] = 0xA0);
    }
    fileoffset =
      (long) t64entry.fileOffsetLowest |
      t64entry.fileOffsetLower << 8 |
      t64entry.fileOffsetHigher << 16 |
      t64entry.fileOffsetHighest << 24;

    length =
      (((size_t) t64entry.endAddrLow | t64entry.endAddrHigh << 8) -
       ((size_t) t64entry.startAddrLow | t64entry.startAddrHigh << 8)) &
      0xFFFF;

    if (t64entry.entryType != 1) {
    unknown:
      (*log) (Errors, &name,
            "Unknown entry type 0x%02x 0x%02x, assuming PRG",
            t64entry.entryType, t64entry.fileType);
    }
    else if (t64entry.fileType != 1) {
      unsigned filetype = t64entry.fileType & 0x8F;
      if (filetype >= DEL && filetype <= USR)
      name.type = filetype;
      else
      goto unknown;
    }

    /* Read the file */
    {
      byte_t* buf;
      enum WrStatus status;
      size_t readlength;

      if (!(buf = malloc (length + 2))) {
      (*log) (Errors, &name, "Out of memory.");
      return RdFail;
      }

      buf[0] = t64entry.startAddrLow;
      buf[1] = t64entry.startAddrHigh;

      if (fseek (file, fileoffset, SEEK_SET)) {
      (*log) (Errors, &name, "fseek: %s", strerror(errno));
      free (buf);
      return RdFail;
      }

      if (length != (readlength = fread (&buf[2], 1, length, file))) {
      if (feof (file))
        (*log) (Warnings, &name, "Truncated file, proceeding anyway");
      if (ferror (file)) {
        (*log) (Errors, &name, "fread: %s", strerror(errno));
        free (buf);
        return RdFail;
      }
      }

      status = (*writeCallback) (&name, buf, readlength + 2);
      free (buf);

      switch (status) {
      case WrOK:
      break;
      case WrNoSpace:
      return RdNoSpace;
      case WrFail:
      default:
      return RdFail;
      }
    }
  }

  return RdOK;
}


Generated by  Doxygen 1.6.0   Back to index