Example #1
0
int decrunch_xfd (FILE *f1, FILE *f2)
{
    struct xfdBufferInfo *xfdobj;
    uint8 *packed;
    int plen,ret=-1;
    struct stat st;
    struct local_data data;

    if (f2 == NULL)
	return -1;

    fstat(fileno(f1), &st);
    plen = st.st_size;

    packed = AllocVec(plen,MEMF_CLEAR);
    if (!packed) return -1;

    fread(packed,plen,1,f1);

	if(xfdobj=open_xfd(&data))
	{
		xfdobj->xfdbi_SourceBufLen = plen;
		xfdobj->xfdbi_SourceBuffer = packed;
		xfdobj->xfdbi_Flags = XFDFB_RECOGEXTERN | XFDFB_RECOGTARGETLEN;
		xfdobj->xfdbi_PackerFlags = XFDPFB_RECOGLEN;
		if(xfdRecogBuffer(xfdobj))
		{
			xfdobj->xfdbi_TargetBufMemType = MEMF_ANY;
			if(xfdDecrunchBuffer(xfdobj))
			{
				if(fwrite(xfdobj->xfdbi_TargetBuffer,1,xfdobj->xfdbi_TargetBufSaveLen,f2) == xfdobj->xfdbi_TargetBufSaveLen) ret=0;
				FreeMem(xfdobj->xfdbi_TargetBuffer,xfdobj->xfdbi_TargetBufLen);
			}
			else
			{
				ret=-1;
			}
		}
		close_xfd(xfdobj, &data);
	}
	FreeVec(packed);
	return(ret);
}
Example #2
0
char *test_xfd	(unsigned char *buffer, int length)
{
	char *ret = NULL;
	struct xfdBufferInfo *xfdobj;
	struct local_data data;

	if(xfdobj=open_xfd(&data))
	{
		xfdobj->xfdbi_SourceBuffer = buffer;
		xfdobj->xfdbi_SourceBufLen = length;
		xfdobj->xfdbi_Flags = XFDFB_RECOGTARGETLEN | XFDFB_RECOGEXTERN;

		if(xfdRecogBuffer(xfdobj))
		{
			ret = xfdobj->xfdbi_PackerName;
		}
		close_xfd(xfdobj, &data);
	}
	return(ret);
}
Example #3
0
/* Identify a file without attempting to decompress it */
libspectrum_error
libspectrum_identify_file_raw( libspectrum_id_t *type, const char *filename,
			       const unsigned char *buffer, size_t length )
{
  struct type {

    int type;

    const char *extension; int extension_score;

    const char *signature; size_t offset, length; int sig_score;
  };

  struct type *ptr,
    types[] = {
      
      { LIBSPECTRUM_ID_RECORDING_RZX, "rzx", 3, "RZX!",		    0, 4, 4 },

      { LIBSPECTRUM_ID_SNAPSHOT_SNA,  "sna", 3, NULL,		    0, 0, 0 },
      /* Peter McGavin's Spectrum Emulator on the Amiga used .snapshot for sna
         snaps */
      { LIBSPECTRUM_ID_SNAPSHOT_SNA,  "snapshot", 3, NULL,	    0, 0, 0 },
      { LIBSPECTRUM_ID_SNAPSHOT_SNP,  "snp", 3, NULL,		    0, 0, 0 },
      { LIBSPECTRUM_ID_SNAPSHOT_SP,   "sp",  3, "\x53\x50\0",	    0, 3, 1 },
      { LIBSPECTRUM_ID_SNAPSHOT_SZX,  "szx", 3, "ZXST",		    0, 4, 4 },
      { LIBSPECTRUM_ID_SNAPSHOT_Z80,  "z80", 3, "\0\0",		    6, 2, 1 },
      /* .slt files also dealt with by the .z80 loading code */
      { LIBSPECTRUM_ID_SNAPSHOT_Z80,  "slt", 3, "\0\0",		    6, 2, 1 },
      { LIBSPECTRUM_ID_SNAPSHOT_ZXS,  "zxs", 3, "SNAP",		    8, 4, 4 },
      { LIBSPECTRUM_ID_SNAPSHOT_PLUSD,"mgtsnp", 3, NULL,	    0, 0, 0 },

      { LIBSPECTRUM_ID_CARTRIDGE_DCK, "dck", 3, NULL,		    0, 0, 0 },
      { LIBSPECTRUM_ID_CARTRIDGE_IF2, "rom", 3, NULL,		    0, 0, 0 },

      { LIBSPECTRUM_ID_MICRODRIVE_MDR, "mdr", 3, NULL,		    0, 0, 0 },

      { LIBSPECTRUM_ID_TAPE_TAP,      "tap", 3, "\x13\0\0",	    0, 3, 1 },
      { LIBSPECTRUM_ID_TAPE_SPC,      "spc", 3, "\x11\0\0",	    0, 3, 1 },
      { LIBSPECTRUM_ID_TAPE_STA,      "sta", 3, "\x11\0\0",	    0, 3, 1 },
      { LIBSPECTRUM_ID_TAPE_LTP,      "ltp", 3, "\x11\0\0",	    0, 3, 1 },
      { LIBSPECTRUM_ID_TAPE_TZX,      "tzx", 3, "ZXTape!",	    0, 7, 4 },
      { LIBSPECTRUM_ID_TAPE_WARAJEVO, "tap", 2, "\xff\xff\xff\xff", 8, 4, 2 },

      { LIBSPECTRUM_ID_DISK_DSK,      "dsk", 3, NULL,		    0, 0, 0 },
      { LIBSPECTRUM_ID_DISK_SCL,      "scl", 3, "SINCLAIR",         0, 8, 4 },
      { LIBSPECTRUM_ID_DISK_TRD,      "trd", 3, NULL,		    0, 0, 0 },

      { LIBSPECTRUM_ID_HARDDISK_HDF,  "hdf", 3, "RS-IDE\x1a",	    0, 7, 4 },

      { LIBSPECTRUM_ID_COMPRESSED_BZ2,"bz2", 3, "BZh",		    0, 3, 4 },
      { LIBSPECTRUM_ID_COMPRESSED_GZ, "gz",  3, "\x1f\x8b",	    0, 2, 4 },

      { LIBSPECTRUM_ID_TAPE_Z80EM,    "raw", 1, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0Raw tape sample",  0, 64, 0 },
      { LIBSPECTRUM_ID_TAPE_CSW,      "csw", 2, "Compressed Square Wave\x1a",  0, 23, 4 },

      { LIBSPECTRUM_ID_TAPE_WAV,      "wav", 3, NULL,		    0, 0, 0 },

      { LIBSPECTRUM_ID_DISK_MGT,      "mgt", 3, NULL,		    0, 0, 0 },
      { LIBSPECTRUM_ID_DISK_IMG,      "img", 3, NULL,		    0, 0, 0 },

      { -1, NULL, 0, NULL, 0, 0, 0 }, /* End marker */

    };

  const char *extension = NULL;
  int score, best_score, best_guess, duplicate_best;

  /* Get the filename extension, if it exists */
  if( filename ) {
    extension = strrchr( filename, '.' ); if( extension ) extension++;
  }

  best_guess = LIBSPECTRUM_ID_UNKNOWN; best_score = 0; duplicate_best = 0;

  /* Compare against known extensions and signatures */
  for( ptr = types; ptr->type != -1; ptr++ ) {

    score = 0;

    if( extension && ptr->extension &&
	!strcasecmp( extension, ptr->extension ) )
      score += ptr->extension_score;

    if( ptr->signature && length >= ptr->offset + ptr->length &&
	!memcmp( &buffer[ ptr->offset ], ptr->signature, ptr->length ) )
      score += ptr->sig_score;

    if( score > best_score ) {
      best_guess = ptr->type; best_score = score; duplicate_best = 0;
    } else if( score == best_score && ptr->type != best_guess ) {
      duplicate_best = 1;
    }
  }

#if defined AMIGA || defined __MORPHOS__
  /* Compressed file check through xfdmaster.library */

  /* this prevents most good matches and gz/bz2 from being run through xfd (xfd
     supports gz, but we want to use the internal code) */
  if( best_score <= 3 ) {
#ifndef __MORPHOS__
    struct ExecIFace *IExec =
      (struct ExecIFace *)(*(struct ExecBase **)4)->MainInterface;
#endif				/* #ifndef __MORPHOS__ */
    struct xfdBufferInfo *xfdobj;

#ifndef __MORPHOS__
    if( xfdMasterBase = IExec->OpenLibrary("xfdmaster.library",38 ) ) {
      if( IxfdMaster =
         (struct xfdMasterIFace *)IExec->GetInterface(xfdMasterBase,"main",1,NULL)){
        if( xfdobj = (struct xfdBufferInfo *)IxfdMaster->xfdAllocObject(XFDOBJ_BUFFERINFO) ) {
#else				/* #ifndef __MORPHOS__ */
    if( xfdMasterBase = OpenLibrary("xfdmaster.library",38 ) ) {
        if( xfdobj = (struct xfdBufferInfo *)xfdAllocObject(XFDOBJ_BUFFERINFO) ) {
#endif				/* #ifndef __MORPHOS__ */
          xfdobj->xfdbi_SourceBuffer = buffer;
          xfdobj->xfdbi_SourceBufLen = length;
          xfdobj->xfdbi_Flags = XFDFB_RECOGTARGETLEN | XFDFB_RECOGEXTERN;

#ifndef __MORPHOS__
          if( IxfdMaster->xfdRecogBuffer( xfdobj ) ) {
#else				/* #ifndef __MORPHOS__ */
          if( xfdRecogBuffer( xfdobj ) ) {
#endif				/* #ifndef __MORPHOS__ */
            best_guess = LIBSPECTRUM_ID_COMPRESSED_XFD;
            duplicate_best=0;
          }
#ifndef __MORPHOS__
          IxfdMaster->xfdFreeObject( (APTR)xfdobj );
#else				/* #ifndef __MORPHOS__ */
          xfdFreeObject( (APTR)xfdobj );
#endif				/* #ifndef __MORPHOS__ */
        }
#ifndef __MORPHOS__
        IExec->DropInterface( (struct Interface *)IxfdMaster );
      }
      IExec->CloseLibrary( xfdMasterBase );
#else				/* #ifndef __MORPHOS__ */
      CloseLibrary( xfdMasterBase );
#endif				/* #ifndef __MORPHOS__ */
    }
  }
#endif /* #ifdef AMIGA */

  /* If two things were equally good, we can't identify this. Otherwise,
     return our best guess */
  if( duplicate_best ) {
    *type = LIBSPECTRUM_ID_UNKNOWN;
  } else {
    *type = best_guess;
  }

  return LIBSPECTRUM_ERROR_NONE;
}

/* What generic 'class' of file is this file */
libspectrum_error
libspectrum_identify_class( libspectrum_class_t *libspectrum_class,
			    libspectrum_id_t type )
{
  switch( type ) {

  case LIBSPECTRUM_ID_UNKNOWN:
    *libspectrum_class = LIBSPECTRUM_CLASS_UNKNOWN; return 0;
  
  case LIBSPECTRUM_ID_CARTRIDGE_DCK:
    *libspectrum_class = LIBSPECTRUM_CLASS_CARTRIDGE_TIMEX; return 0;

  case LIBSPECTRUM_ID_COMPRESSED_BZ2:
  case LIBSPECTRUM_ID_COMPRESSED_GZ:
  case LIBSPECTRUM_ID_COMPRESSED_XFD:
    *libspectrum_class = LIBSPECTRUM_CLASS_COMPRESSED; return 0;

  case LIBSPECTRUM_ID_DISK_DSK:
    *libspectrum_class = LIBSPECTRUM_CLASS_DISK_PLUS3; return 0;

  case LIBSPECTRUM_ID_DISK_IMG:
  case LIBSPECTRUM_ID_DISK_MGT:
    *libspectrum_class = LIBSPECTRUM_CLASS_DISK_PLUSD; return 0;

  case LIBSPECTRUM_ID_DISK_SCL:
  case LIBSPECTRUM_ID_DISK_TRD:
    *libspectrum_class = LIBSPECTRUM_CLASS_DISK_TRDOS; return 0;

  case LIBSPECTRUM_ID_HARDDISK_HDF:
    *libspectrum_class = LIBSPECTRUM_CLASS_HARDDISK; return 0;

  case LIBSPECTRUM_ID_MICRODRIVE_MDR:
    *libspectrum_class = LIBSPECTRUM_CLASS_MICRODRIVE; return 0;

  case LIBSPECTRUM_ID_RECORDING_RZX:
    *libspectrum_class = LIBSPECTRUM_CLASS_RECORDING; return 0;

  case LIBSPECTRUM_ID_SNAPSHOT_PLUSD:
  case LIBSPECTRUM_ID_SNAPSHOT_SNA:
  case LIBSPECTRUM_ID_SNAPSHOT_SNP:
  case LIBSPECTRUM_ID_SNAPSHOT_SP:
  case LIBSPECTRUM_ID_SNAPSHOT_SZX:
  case LIBSPECTRUM_ID_SNAPSHOT_Z80:
  case LIBSPECTRUM_ID_SNAPSHOT_ZXS:
    *libspectrum_class = LIBSPECTRUM_CLASS_SNAPSHOT; return 0;

  case LIBSPECTRUM_ID_TAPE_TAP:
  case LIBSPECTRUM_ID_TAPE_SPC:
  case LIBSPECTRUM_ID_TAPE_STA:
  case LIBSPECTRUM_ID_TAPE_LTP:
  case LIBSPECTRUM_ID_TAPE_TZX:
  case LIBSPECTRUM_ID_TAPE_WARAJEVO:
  case LIBSPECTRUM_ID_TAPE_Z80EM:
  case LIBSPECTRUM_ID_TAPE_CSW:
  case LIBSPECTRUM_ID_TAPE_WAV:
    *libspectrum_class = LIBSPECTRUM_CLASS_TAPE; return 0;

  case LIBSPECTRUM_ID_CARTRIDGE_IF2:
    *libspectrum_class = LIBSPECTRUM_CLASS_CARTRIDGE_IF2; return 0;

  }

  libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
			   "Unknown file type %d", type );
  return LIBSPECTRUM_ERROR_UNKNOWN;
}

libspectrum_error
libspectrum_uncompress_file( unsigned char **new_buffer, size_t *new_length,
			     char **new_filename, libspectrum_id_t type,
			     const unsigned char *old_buffer,
			     size_t old_length, const char *old_filename )
{
  libspectrum_class_t class;
  libspectrum_error error;

  error = libspectrum_identify_class( &class, type );
  if( error ) return error;

  if( class != LIBSPECTRUM_CLASS_COMPRESSED ) {
    libspectrum_print_error( LIBSPECTRUM_ERROR_LOGIC,
			     "file type %d is not a compressed type", type );
    return LIBSPECTRUM_ERROR_LOGIC;
  }

  if( new_filename && old_filename ) {
    *new_filename = strdup( old_filename );
    if( !*new_filename ) {
      libspectrum_print_error( LIBSPECTRUM_ERROR_MEMORY,
			       "out of memory at %s:%d", __FILE__, __LINE__ );
      return LIBSPECTRUM_ERROR_MEMORY;
    }
  }

  /* Tells the inflation routines to allocate memory for us */
  *new_length = 0;
  
  switch( type ) {

  case LIBSPECTRUM_ID_COMPRESSED_BZ2:

#ifdef HAVE_LIBBZ2

    if( new_filename && *new_filename ) {
      if( strlen( *new_filename ) >= 4 &&
	  !strcasecmp( &(*new_filename)[ strlen( *new_filename ) - 4 ],
		       ".bz2" ) )
	(*new_filename)[ strlen( *new_filename ) - 4 ] = '\0';
    }

    error = libspectrum_bzip2_inflate( old_buffer, old_length,
				       new_buffer, new_length );
    if( error ) {
      if( new_filename ) free( *new_filename );
      return error;
    }

#else				/* #ifdef HAVE_LIBBZ2 */

    libspectrum_print_error(
      LIBSPECTRUM_ERROR_UNKNOWN,
      "libbz2 not available to decompress bzipped file"
    );
    if( new_filename ) free( *new_filename );
    return LIBSPECTRUM_ERROR_UNKNOWN;

#endif				/* #ifdef HAVE_LIBBZ2 */

    break;

  case LIBSPECTRUM_ID_COMPRESSED_GZ:

#ifdef HAVE_ZLIB_H

    if( new_filename && *new_filename ) {
      if( strlen( *new_filename ) >= 3 &&
	  !strcasecmp( &(*new_filename)[ strlen( *new_filename ) - 3 ],
		       ".gz" ) )
	(*new_filename)[ strlen( *new_filename ) - 3 ] = '\0';
    }
      
    error = libspectrum_gzip_inflate( old_buffer, old_length,
				      new_buffer, new_length );
    if( error ) {
      if( new_filename ) free( *new_filename );
      return error;
    }

#else				/* #ifdef HAVE_ZLIB_H */

    libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
			     "zlib not available to decompress gzipped file" );
    if( new_filename ) free( *new_filename );
    return LIBSPECTRUM_ERROR_UNKNOWN;

#endif				/* #ifdef HAVE_ZLIB_H */

    break;

#if defined AMIGA || defined __MORPHOS__
  case LIBSPECTRUM_ID_COMPRESSED_XFD:
    {
#ifndef __MORPHOS__
      struct ExecIFace *IExec =
        (struct ExecIFace *)(*(struct ExecBase **)4)->MainInterface;
#endif				/* #ifndef __MORPHOS__ */
      struct xfdBufferInfo *xfdobj;

#ifndef __MORPHOS__
      if( xfdMasterBase = IExec->OpenLibrary( "xfdmaster.library", 38 ) ) {
        if( IxfdMaster =
            (struct xfdMasterIFace *)IExec->GetInterface(xfdMasterBase,"main",1,NULL)) {
          if( xfdobj =
              (struct xfdBufferInfo *)IxfdMaster->xfdAllocObject(XFDOBJ_BUFFERINFO) ) {
#else				/* #ifndef __MORPHOS__ */
      if( xfdMasterBase = OpenLibrary( "xfdmaster.library", 38 ) ) {
          if( xfdobj = (struct xfdBufferInfo *)xfdAllocObject(XFDOBJ_BUFFERINFO) ) {
#endif				/* #ifndef __MORPHOS__ */
            xfdobj->xfdbi_SourceBufLen = old_length;
            xfdobj->xfdbi_SourceBuffer = old_buffer;
            xfdobj->xfdbi_Flags = XFDFB_RECOGEXTERN | XFDFB_RECOGTARGETLEN;
            xfdobj->xfdbi_PackerFlags = XFDPFB_RECOGLEN;
#ifndef __MORPHOS__
            if( IxfdMaster->xfdRecogBuffer( xfdobj ) ) {
#else				/* #ifndef __MORPHOS__ */
            if( xfdRecogBuffer( xfdobj ) ) {
#endif				/* #ifndef __MORPHOS__ */
              xfdobj->xfdbi_TargetBufMemType = MEMF_ANY;
#ifndef __MORPHOS__
              if( IxfdMaster->xfdDecrunchBuffer( xfdobj ) ) {
#else				/* #ifndef __MORPHOS__ */
              if( xfdDecrunchBuffer( xfdobj ) ) {
#endif				/* #ifndef __MORPHOS__ */
                *new_buffer = malloc( xfdobj->xfdbi_TargetBufSaveLen );
                *new_length = xfdobj->xfdbi_TargetBufSaveLen;
                memcpy( *new_buffer, xfdobj->xfdbi_TargetBuffer, *new_length );
#ifndef __MORPHOS__
                IExec->FreeMem( xfdobj->xfdbi_TargetBuffer,xfdobj->xfdbi_TargetBufLen );
#else				/* #ifndef __MORPHOS__ */
                FreeMem( xfdobj->xfdbi_TargetBuffer,xfdobj->xfdbi_TargetBufLen );
#endif				/* #ifndef __MORPHOS__ */
              } else {
                libspectrum_print_error(
                             LIBSPECTRUM_ERROR_UNKNOWN,
                             "xfdmaster.library not able to decrunch %s file",
                             xfdobj->xfdbi_PackerName );
                return LIBSPECTRUM_ERROR_UNKNOWN;
              }
            } else {
              libspectrum_print_error(
                                 LIBSPECTRUM_ERROR_UNKNOWN,
                                 "xfdmaster.library does not recognise file" );
              return LIBSPECTRUM_ERROR_UNKNOWN;
            }
#ifndef __MORPHOS__
            IxfdMaster->xfdFreeObject( xfdobj );
#else				/* #ifndef __MORPHOS__ */
            xfdFreeObject( xfdobj );
#endif				/* #ifndef __MORPHOS__ */
          }
#ifndef __MORPHOS__
          IExec->DropInterface( (struct Interface *)IxfdMaster );
        }
        IExec->CloseLibrary( xfdMasterBase );
#else				/* #ifndef __MORPHOS__ */
        CloseLibrary( xfdMasterBase );
#endif				/* #ifndef __MORPHOS__ */
      }
    }
    break;
#endif /* #ifdef AMIGA */

  default:
    libspectrum_print_error( LIBSPECTRUM_ERROR_LOGIC,
			     "unknown compressed type %d", type );
    if( new_filename ) free( *new_filename );
    return LIBSPECTRUM_ERROR_LOGIC;
  }

  return LIBSPECTRUM_ERROR_NONE;
}

/* Ensure there is room for `requested' characters after the current
   position `ptr' in `buffer'. If not, realloc() and update the
   pointers as necessary */
int
libspectrum_make_room( libspectrum_byte **dest, size_t requested,
		       libspectrum_byte **ptr, size_t *allocated )
{
  size_t current_length;

  current_length = *ptr - *dest;

  if( *allocated == 0 ) {

    (*allocated) = requested;

    *dest = (libspectrum_byte*)malloc( requested * sizeof(libspectrum_byte) );
    if( *dest == NULL ) return 1;

  } else {

    /* If there's already enough room here, just return */
    if( current_length + requested <= (*allocated) ) return 0;

    /* Make the new size the maximum of the new needed size and the
     old allocated size * 2 */
    (*allocated) =
      current_length + requested > 2 * (*allocated) ?
      current_length + requested :
      2 * (*allocated);

    *dest = (libspectrum_byte*)
      realloc( *dest, (*allocated) * sizeof( libspectrum_byte ) );
    if( *dest == NULL ) return 1;

  }

  /* Update the secondary pointer to the block */
  *ptr = *dest + current_length;

  return 0;

}

/* Read an LSB word from 'buffer' */
libspectrum_word
libspectrum_read_word( const libspectrum_byte **buffer )
{
  libspectrum_word value;

  value = (*buffer)[0] + (*buffer)[1] * 0x100;

  (*buffer) += 2;

  return value;
}

/* Read an LSB dword from buffer */
libspectrum_dword
libspectrum_read_dword( const libspectrum_byte **buffer )
{
  libspectrum_dword value;

  value = (*buffer)[0]             +
          (*buffer)[1] *     0x100 +
	  (*buffer)[2] *   0x10000 +
          (*buffer)[3] * 0x1000000 ;

  (*buffer) += 4;

  return value;
}

/* Write an (LSB) word to buffer */
int
libspectrum_write_word( libspectrum_byte **buffer, libspectrum_word w )
{
  *(*buffer)++ = w & 0xff;
  *(*buffer)++ = w >> 8;
  return LIBSPECTRUM_ERROR_NONE;
}

/* Write an LSB dword to buffer */
int libspectrum_write_dword( libspectrum_byte **buffer, libspectrum_dword d )
{
  *(*buffer)++ = ( d & 0x000000ff )      ;
  *(*buffer)++ = ( d & 0x0000ff00 ) >>  8;
  *(*buffer)++ = ( d & 0x00ff0000 ) >> 16;
  *(*buffer)++ = ( d & 0xff000000 ) >> 24;
  return LIBSPECTRUM_ERROR_NONE;
}