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

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

Read and convert an Arkive 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

Definition at line 63 of file unark.c.

References DEL, Errors, Filename::name, PRG, RdFail, RdNoSpace, RdOK, Filename::recordLength, REL, rounddiv, SEQ, ArkiveEntry::sidesectCount, ArkiveEntry::sidesectLastLength, Filename::type, Warnings, WrFail, WrNoSpace, and WrOK.

{
  struct Filename name;
  struct ArkiveEntry entry;
  int f, fcount;

  /* File positions */
  long headerPos; /* current header position */
  long archivePos; /* current archive position */

  if (EOF == (fcount = fgetc (file))) {
  hdrError:
    (*log) (Errors, 0, "File header read failed: %s", strerror(errno));
    return RdFail;
  }

  headerPos = ftell (file);
  archivePos = 254 * rounddiv (headerPos + fcount * sizeof entry, 254);

  /* start extracting files */

  for (f = 0; f++ < fcount;) {
    size_t length;
    unsigned blocks;

    if (fseek (file, headerPos, SEEK_SET) ||
      1 != fread (&entry, sizeof entry, 1, file))
      goto hdrError;

    headerPos += sizeof entry;

    /* copy file name */
    memcpy (name.name, entry.name, 16);

    /* copy the record length */
    name.recordLength = entry.recordLength;

    /* determine file length */
    blocks = entry.blocksLow + (entry.blocksHigh << 8);
    length = 254 * blocks + entry.lastSectorLength - 255;

    /* determine file type */

    switch (entry.filetype & ~0x38) {
    case DEL:
    case SEQ:
    case PRG:
      name.type = entry.filetype & ~0x38;
      break;

    case REL:
      name.type = REL;

      if (!name.recordLength)
      (*log) (Warnings, &name, "zero record length");

      {
      unsigned sidesectCount, sidesectLastLength;

      sidesectCount = (blocks + 119) / 121;
      sidesectLastLength = 15 + 2 * ((blocks - sidesectCount) % 120);

      if (entry.sidesectCount != sidesectCount ||
          entry.sidesectLastLength != sidesectLastLength) {
        (*log) (Errors, &name, "improper side sector length");
        (*log) (Errors, &name, "Following files may be totally wrong!");
      }

      length = (blocks - sidesectCount) * 254 - 255 +
        entry.lastSectorLength;
      }

      break;

    default:
      name.type = 0;
      (*log) (Errors, &name, "Unknown type, defaulting to DEL");
      name.type = DEL;
      break;
    }

    /* read the file */

    {
      byte_t* buf;

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

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

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

      archivePos += 254 * blocks;

      if (name.type == REL)
      /* Arkive stores the last side sector, */
      /* wasting 254 bytes */
      /* for each relative file. */
      archivePos -= 254 * (entry.sidesectCount - 1);

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

      free (buf);
    }
  }

  return RdOK;
}


Generated by  Doxygen 1.6.0   Back to index