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

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

Read and convert a Commodore C2N tape archive

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

name of the file being processed

tape header

start address of the file being processed

end address of the file being processed

number of bytes read so far

the data buffer

Definition at line 107 of file c2n.c.

References DEL, c2n_header::endAddrHigh, c2n_header::endAddrLow, Errors, Everything, header2name(), PRG, RdFail, RdNoSpace, RdOK, Filename::recordLength, SEQ, c2n_header::startAddrHigh, c2n_header::startAddrLow, c2n_header::tag, tBasic, tDataBlock, tDataHeader, tEnd, tML, Filename::type, Warnings, WrFail, WrNoSpace, and WrOK.

{
  /** name of the file being processed */
  struct Filename name;
  /* clear the file type code (to denote uninitialized file name) */
  name.type = 0;
  /* clear the record length (no relative files on tapes) */
  name.recordLength = 0;

  while (!feof (file)) {
    /** tape header */
    struct c2n_header header;
    /** start address of the file being processed */
    unsigned start;
    /** end address of the file being processed */
    unsigned end;

    if (1 != fread (&header, sizeof header, 1, file)) {
      if (feof (file))
      break;
      (*log) (Errors, name.type ? &name : 0, "fread: %s", strerror (errno));
      return RdFail;
    }

  nextHeader:
    start = (unsigned) header.startAddrLow | header.startAddrHigh << 8;
    end = (unsigned) header.endAddrLow | header.endAddrHigh << 8;

    switch (header.tag) {
    case tBasic:
    case tML:
      header2name (&header, &name);
      name.type = PRG;
      if ((header.tag == tBasic && header.startAddrLow != 1) ||
        start >= end)
      (*log) (Warnings, &name, "Suspicious addresses 0x%04x..0x%04x",
            start, end);
      break;
    case tDataHeader:
      header2name (&header, &name);
      name.type = SEQ;
      if (start != 0x33c || end != 0x3fc)
      (*log) (Warnings, &name,
            "Suspicious addresses 0x%04x..0x%04x (expected 0x33c..0x3fc)",
            start, end);
      if ((byte_t) (end - start) != 192)
      (*log) (Warnings, name.type ? &name : 0,
            "Block length differs from 192");
      break;
    case tEnd:
      header2name (&header, &name);
      name.type = DEL;
      (*log) (Everything, &name, "Ignoring end-of-tape marker");
      continue;
    default:
      (*log) (Errors, name.type ? &name : 0,
            "Unknown C2N header code 0x%02x", header.tag);
      return RdFail;
    }

    if (name.type == SEQ) {
      /** number of bytes read so far */
      size_t length = 0;
      /** the data buffer */
      byte_t* buf = 0;

    nextBlock:
      if (1 != fread (&header, sizeof header, 1, file)) {
      if (feof (file))
        goto writeData;
      (*log) (Errors, &name, "fread: %s", strerror (errno));
      free (buf);
      return RdFail;
      }

      if (header.tag == tDataBlock) {
      byte_t* b = realloc (buf, length + (sizeof header) - 1);
      if (!b) {
        (*log) (Errors, &name, "Out of memory.");
        free (buf);
        return RdFail;
      }
      buf = b;
      memcpy (buf + length, ((byte_t*) &header) + 1, (sizeof header) - 1);
      length += (sizeof header) - 1;
      goto nextBlock;
      }
      else {
      enum WrStatus status;
      writeData:
      if (!length)
        (*log) (Warnings, &name, "no data");
      status = (*writeCallback) (&name, buf, length);
      free (buf);
      switch (status) {
      case WrOK:
        break;
      case WrNoSpace:
        return RdNoSpace;
      case WrFail:
      default:
        return RdFail;
      }

      if (!feof (file))
        goto nextHeader;
      }
    }
    else {
      byte_t* buf;
      enum WrStatus status;
      size_t readlength, length = (end - start) & 0xffff;

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

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

      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